Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
Kernel
提交
463260d7
K
Kernel
项目概览
openeuler
/
Kernel
大约 2 年 前同步成功
通知
8
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
Kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
463260d7
编写于
4月 21, 2022
作者:
D
Dave Chinner
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'guilt/xlog-write-rework' into xfs-5.19-for-next
上级
898a768f
593e3439
变更
6
显示空白变更内容
内联
并排
Showing
6 changed file
with
454 addition
and
588 deletion
+454
-588
fs/xfs/libxfs/xfs_log_format.h
fs/xfs/libxfs/xfs_log_format.h
+0
-1
fs/xfs/xfs_log.c
fs/xfs/xfs_log.c
+323
-441
fs/xfs/xfs_log.h
fs/xfs/xfs_log.h
+14
-41
fs/xfs/xfs_log_cil.c
fs/xfs/xfs_log_cil.c
+111
-58
fs/xfs/xfs_log_priv.h
fs/xfs/xfs_log_priv.h
+4
-43
fs/xfs/xfs_trans.c
fs/xfs/xfs_trans.c
+2
-4
未找到文件。
fs/xfs/libxfs/xfs_log_format.h
浏览文件 @
463260d7
...
@@ -69,7 +69,6 @@ static inline uint xlog_get_cycle(char *ptr)
...
@@ -69,7 +69,6 @@ static inline uint xlog_get_cycle(char *ptr)
/* Log Clients */
/* Log Clients */
#define XFS_TRANSACTION 0x69
#define XFS_TRANSACTION 0x69
#define XFS_VOLUME 0x2
#define XFS_LOG 0xaa
#define XFS_LOG 0xaa
#define XLOG_UNMOUNT_TYPE 0x556e
/* Un for Unmount */
#define XLOG_UNMOUNT_TYPE 0x556e
/* Un for Unmount */
...
...
fs/xfs/xfs_log.c
浏览文件 @
463260d7
...
@@ -49,7 +49,6 @@ xlog_state_get_iclog_space(
...
@@ -49,7 +49,6 @@ xlog_state_get_iclog_space(
int
len
,
int
len
,
struct
xlog_in_core
**
iclog
,
struct
xlog_in_core
**
iclog
,
struct
xlog_ticket
*
ticket
,
struct
xlog_ticket
*
ticket
,
int
*
continued_write
,
int
*
logoffsetp
);
int
*
logoffsetp
);
STATIC
void
STATIC
void
xlog_grant_push_ail
(
xlog_grant_push_ail
(
...
@@ -61,10 +60,6 @@ xlog_sync(
...
@@ -61,10 +60,6 @@ xlog_sync(
struct
xlog_in_core
*
iclog
);
struct
xlog_in_core
*
iclog
);
#if defined(DEBUG)
#if defined(DEBUG)
STATIC
void
STATIC
void
xlog_verify_dest_ptr
(
struct
xlog
*
log
,
void
*
ptr
);
STATIC
void
xlog_verify_grant_tail
(
xlog_verify_grant_tail
(
struct
xlog
*
log
);
struct
xlog
*
log
);
STATIC
void
STATIC
void
...
@@ -77,7 +72,6 @@ xlog_verify_tail_lsn(
...
@@ -77,7 +72,6 @@ xlog_verify_tail_lsn(
struct
xlog
*
log
,
struct
xlog
*
log
,
struct
xlog_in_core
*
iclog
);
struct
xlog_in_core
*
iclog
);
#else
#else
#define xlog_verify_dest_ptr(a,b)
#define xlog_verify_grant_tail(a)
#define xlog_verify_grant_tail(a)
#define xlog_verify_iclog(a,b,c)
#define xlog_verify_iclog(a,b,c)
#define xlog_verify_tail_lsn(a,b)
#define xlog_verify_tail_lsn(a,b)
...
@@ -90,6 +84,62 @@ xlog_iclogs_empty(
...
@@ -90,6 +84,62 @@ xlog_iclogs_empty(
static
int
static
int
xfs_log_cover
(
struct
xfs_mount
*
);
xfs_log_cover
(
struct
xfs_mount
*
);
/*
* We need to make sure the buffer pointer returned is naturally aligned for the
* biggest basic data type we put into it. We have already accounted for this
* padding when sizing the buffer.
*
* However, this padding does not get written into the log, and hence we have to
* track the space used by the log vectors separately to prevent log space hangs
* due to inaccurate accounting (i.e. a leak) of the used log space through the
* CIL context ticket.
*
* We also add space for the xlog_op_header that describes this region in the
* log. This prepends the data region we return to the caller to copy their data
* into, so do all the static initialisation of the ophdr now. Because the ophdr
* is not 8 byte aligned, we have to be careful to ensure that we align the
* start of the buffer such that the region we return to the call is 8 byte
* aligned and packed against the tail of the ophdr.
*/
void
*
xlog_prepare_iovec
(
struct
xfs_log_vec
*
lv
,
struct
xfs_log_iovec
**
vecp
,
uint
type
)
{
struct
xfs_log_iovec
*
vec
=
*
vecp
;
struct
xlog_op_header
*
oph
;
uint32_t
len
;
void
*
buf
;
if
(
vec
)
{
ASSERT
(
vec
-
lv
->
lv_iovecp
<
lv
->
lv_niovecs
);
vec
++
;
}
else
{
vec
=
&
lv
->
lv_iovecp
[
0
];
}
len
=
lv
->
lv_buf_len
+
sizeof
(
struct
xlog_op_header
);
if
(
!
IS_ALIGNED
(
len
,
sizeof
(
uint64_t
)))
{
lv
->
lv_buf_len
=
round_up
(
len
,
sizeof
(
uint64_t
))
-
sizeof
(
struct
xlog_op_header
);
}
vec
->
i_type
=
type
;
vec
->
i_addr
=
lv
->
lv_buf
+
lv
->
lv_buf_len
;
oph
=
vec
->
i_addr
;
oph
->
oh_clientid
=
XFS_TRANSACTION
;
oph
->
oh_res2
=
0
;
oph
->
oh_flags
=
0
;
buf
=
vec
->
i_addr
+
sizeof
(
struct
xlog_op_header
);
ASSERT
(
IS_ALIGNED
((
unsigned
long
)
buf
,
sizeof
(
uint64_t
)));
*
vecp
=
vec
;
return
buf
;
}
static
void
static
void
xlog_grant_sub_space
(
xlog_grant_sub_space
(
struct
xlog
*
log
,
struct
xlog
*
log
,
...
@@ -322,30 +372,6 @@ xlog_grant_head_check(
...
@@ -322,30 +372,6 @@ xlog_grant_head_check(
return
error
;
return
error
;
}
}
static
void
xlog_tic_reset_res
(
xlog_ticket_t
*
tic
)
{
tic
->
t_res_num
=
0
;
tic
->
t_res_arr_sum
=
0
;
tic
->
t_res_num_ophdrs
=
0
;
}
static
void
xlog_tic_add_region
(
xlog_ticket_t
*
tic
,
uint
len
,
uint
type
)
{
if
(
tic
->
t_res_num
==
XLOG_TIC_LEN_MAX
)
{
/* add to overflow and start again */
tic
->
t_res_o_flow
+=
tic
->
t_res_arr_sum
;
tic
->
t_res_num
=
0
;
tic
->
t_res_arr_sum
=
0
;
}
tic
->
t_res_arr
[
tic
->
t_res_num
].
r_len
=
len
;
tic
->
t_res_arr
[
tic
->
t_res_num
].
r_type
=
type
;
tic
->
t_res_arr_sum
+=
len
;
tic
->
t_res_num
++
;
}
bool
bool
xfs_log_writable
(
xfs_log_writable
(
struct
xfs_mount
*
mp
)
struct
xfs_mount
*
mp
)
...
@@ -395,8 +421,6 @@ xfs_log_regrant(
...
@@ -395,8 +421,6 @@ xfs_log_regrant(
xlog_grant_push_ail
(
log
,
tic
->
t_unit_res
);
xlog_grant_push_ail
(
log
,
tic
->
t_unit_res
);
tic
->
t_curr_res
=
tic
->
t_unit_res
;
tic
->
t_curr_res
=
tic
->
t_unit_res
;
xlog_tic_reset_res
(
tic
);
if
(
tic
->
t_cnt
>
0
)
if
(
tic
->
t_cnt
>
0
)
return
0
;
return
0
;
...
@@ -437,7 +461,6 @@ xfs_log_reserve(
...
@@ -437,7 +461,6 @@ xfs_log_reserve(
int
unit_bytes
,
int
unit_bytes
,
int
cnt
,
int
cnt
,
struct
xlog_ticket
**
ticp
,
struct
xlog_ticket
**
ticp
,
uint8_t
client
,
bool
permanent
)
bool
permanent
)
{
{
struct
xlog
*
log
=
mp
->
m_log
;
struct
xlog
*
log
=
mp
->
m_log
;
...
@@ -445,15 +468,13 @@ xfs_log_reserve(
...
@@ -445,15 +468,13 @@ xfs_log_reserve(
int
need_bytes
;
int
need_bytes
;
int
error
=
0
;
int
error
=
0
;
ASSERT
(
client
==
XFS_TRANSACTION
||
client
==
XFS_LOG
);
if
(
xlog_is_shutdown
(
log
))
if
(
xlog_is_shutdown
(
log
))
return
-
EIO
;
return
-
EIO
;
XFS_STATS_INC
(
mp
,
xs_try_logspace
);
XFS_STATS_INC
(
mp
,
xs_try_logspace
);
ASSERT
(
*
ticp
==
NULL
);
ASSERT
(
*
ticp
==
NULL
);
tic
=
xlog_ticket_alloc
(
log
,
unit_bytes
,
cnt
,
client
,
permanent
);
tic
=
xlog_ticket_alloc
(
log
,
unit_bytes
,
cnt
,
permanent
);
*
ticp
=
tic
;
*
ticp
=
tic
;
xlog_grant_push_ail
(
log
,
tic
->
t_cnt
?
tic
->
t_unit_res
*
tic
->
t_cnt
xlog_grant_push_ail
(
log
,
tic
->
t_cnt
?
tic
->
t_unit_res
*
tic
->
t_cnt
...
@@ -901,12 +922,22 @@ xlog_write_unmount_record(
...
@@ -901,12 +922,22 @@ xlog_write_unmount_record(
struct
xlog
*
log
,
struct
xlog
*
log
,
struct
xlog_ticket
*
ticket
)
struct
xlog_ticket
*
ticket
)
{
{
struct
xfs_unmount_log_format
ulf
=
{
struct
{
struct
xlog_op_header
ophdr
;
struct
xfs_unmount_log_format
ulf
;
}
unmount_rec
=
{
.
ophdr
=
{
.
oh_clientid
=
XFS_LOG
,
.
oh_tid
=
cpu_to_be32
(
ticket
->
t_tid
),
.
oh_flags
=
XLOG_UNMOUNT_TRANS
,
},
.
ulf
=
{
.
magic
=
XLOG_UNMOUNT_TYPE
,
.
magic
=
XLOG_UNMOUNT_TYPE
,
},
};
};
struct
xfs_log_iovec
reg
=
{
struct
xfs_log_iovec
reg
=
{
.
i_addr
=
&
u
lf
,
.
i_addr
=
&
u
nmount_rec
,
.
i_len
=
sizeof
(
u
lf
),
.
i_len
=
sizeof
(
u
nmount_rec
),
.
i_type
=
XLOG_REG_TYPE_UNMOUNT
,
.
i_type
=
XLOG_REG_TYPE_UNMOUNT
,
};
};
struct
xfs_log_vec
vec
=
{
struct
xfs_log_vec
vec
=
{
...
@@ -914,10 +945,14 @@ xlog_write_unmount_record(
...
@@ -914,10 +945,14 @@ xlog_write_unmount_record(
.
lv_iovecp
=
&
reg
,
.
lv_iovecp
=
&
reg
,
};
};
BUILD_BUG_ON
((
sizeof
(
struct
xlog_op_header
)
+
sizeof
(
struct
xfs_unmount_log_format
))
!=
sizeof
(
unmount_rec
));
/* account for space used by record data */
/* account for space used by record data */
ticket
->
t_curr_res
-=
sizeof
(
u
lf
);
ticket
->
t_curr_res
-=
sizeof
(
u
nmount_rec
);
return
xlog_write
(
log
,
NULL
,
&
vec
,
ticket
,
XLOG_UNMOUNT_TRANS
);
return
xlog_write
(
log
,
NULL
,
&
vec
,
ticket
,
reg
.
i_len
);
}
}
/*
/*
...
@@ -933,7 +968,7 @@ xlog_unmount_write(
...
@@ -933,7 +968,7 @@ xlog_unmount_write(
struct
xlog_ticket
*
tic
=
NULL
;
struct
xlog_ticket
*
tic
=
NULL
;
int
error
;
int
error
;
error
=
xfs_log_reserve
(
mp
,
600
,
1
,
&
tic
,
XFS_LOG
,
0
);
error
=
xfs_log_reserve
(
mp
,
600
,
1
,
&
tic
,
0
);
if
(
error
)
if
(
error
)
goto
out_err
;
goto
out_err
;
...
@@ -1584,9 +1619,6 @@ xlog_alloc_log(
...
@@ -1584,9 +1619,6 @@ xlog_alloc_log(
GFP_KERNEL
|
__GFP_RETRY_MAYFAIL
);
GFP_KERNEL
|
__GFP_RETRY_MAYFAIL
);
if
(
!
iclog
->
ic_data
)
if
(
!
iclog
->
ic_data
)
goto
out_free_iclog
;
goto
out_free_iclog
;
#ifdef DEBUG
log
->
l_iclog_bak
[
i
]
=
&
iclog
->
ic_header
;
#endif
head
=
&
iclog
->
ic_header
;
head
=
&
iclog
->
ic_header
;
memset
(
head
,
0
,
sizeof
(
xlog_rec_header_t
));
memset
(
head
,
0
,
sizeof
(
xlog_rec_header_t
));
head
->
h_magicno
=
cpu_to_be32
(
XLOG_HEADER_MAGIC_NUM
);
head
->
h_magicno
=
cpu_to_be32
(
XLOG_HEADER_MAGIC_NUM
);
...
@@ -1602,7 +1634,7 @@ xlog_alloc_log(
...
@@ -1602,7 +1634,7 @@ xlog_alloc_log(
iclog
->
ic_log
=
log
;
iclog
->
ic_log
=
log
;
atomic_set
(
&
iclog
->
ic_refcnt
,
0
);
atomic_set
(
&
iclog
->
ic_refcnt
,
0
);
INIT_LIST_HEAD
(
&
iclog
->
ic_callbacks
);
INIT_LIST_HEAD
(
&
iclog
->
ic_callbacks
);
iclog
->
ic_datap
=
(
char
*
)
iclog
->
ic_data
+
log
->
l_iclog_hsize
;
iclog
->
ic_datap
=
(
void
*
)
iclog
->
ic_data
+
log
->
l_iclog_hsize
;
init_waitqueue_head
(
&
iclog
->
ic_force_wait
);
init_waitqueue_head
(
&
iclog
->
ic_force_wait
);
init_waitqueue_head
(
&
iclog
->
ic_write_wait
);
init_waitqueue_head
(
&
iclog
->
ic_write_wait
);
...
@@ -2111,63 +2143,11 @@ xlog_print_tic_res(
...
@@ -2111,63 +2143,11 @@ xlog_print_tic_res(
struct
xfs_mount
*
mp
,
struct
xfs_mount
*
mp
,
struct
xlog_ticket
*
ticket
)
struct
xlog_ticket
*
ticket
)
{
{
uint
i
;
uint
ophdr_spc
=
ticket
->
t_res_num_ophdrs
*
(
uint
)
sizeof
(
xlog_op_header_t
);
/* match with XLOG_REG_TYPE_* in xfs_log.h */
#define REG_TYPE_STR(type, str) [XLOG_REG_TYPE_##type] = str
static
char
*
res_type_str
[]
=
{
REG_TYPE_STR
(
BFORMAT
,
"bformat"
),
REG_TYPE_STR
(
BCHUNK
,
"bchunk"
),
REG_TYPE_STR
(
EFI_FORMAT
,
"efi_format"
),
REG_TYPE_STR
(
EFD_FORMAT
,
"efd_format"
),
REG_TYPE_STR
(
IFORMAT
,
"iformat"
),
REG_TYPE_STR
(
ICORE
,
"icore"
),
REG_TYPE_STR
(
IEXT
,
"iext"
),
REG_TYPE_STR
(
IBROOT
,
"ibroot"
),
REG_TYPE_STR
(
ILOCAL
,
"ilocal"
),
REG_TYPE_STR
(
IATTR_EXT
,
"iattr_ext"
),
REG_TYPE_STR
(
IATTR_BROOT
,
"iattr_broot"
),
REG_TYPE_STR
(
IATTR_LOCAL
,
"iattr_local"
),
REG_TYPE_STR
(
QFORMAT
,
"qformat"
),
REG_TYPE_STR
(
DQUOT
,
"dquot"
),
REG_TYPE_STR
(
QUOTAOFF
,
"quotaoff"
),
REG_TYPE_STR
(
LRHEADER
,
"LR header"
),
REG_TYPE_STR
(
UNMOUNT
,
"unmount"
),
REG_TYPE_STR
(
COMMIT
,
"commit"
),
REG_TYPE_STR
(
TRANSHDR
,
"trans header"
),
REG_TYPE_STR
(
ICREATE
,
"inode create"
),
REG_TYPE_STR
(
RUI_FORMAT
,
"rui_format"
),
REG_TYPE_STR
(
RUD_FORMAT
,
"rud_format"
),
REG_TYPE_STR
(
CUI_FORMAT
,
"cui_format"
),
REG_TYPE_STR
(
CUD_FORMAT
,
"cud_format"
),
REG_TYPE_STR
(
BUI_FORMAT
,
"bui_format"
),
REG_TYPE_STR
(
BUD_FORMAT
,
"bud_format"
),
};
BUILD_BUG_ON
(
ARRAY_SIZE
(
res_type_str
)
!=
XLOG_REG_TYPE_MAX
+
1
);
#undef REG_TYPE_STR
xfs_warn
(
mp
,
"ticket reservation summary:"
);
xfs_warn
(
mp
,
"ticket reservation summary:"
);
xfs_warn
(
mp
,
" unit res = %d bytes"
,
xfs_warn
(
mp
,
" unit res = %d bytes"
,
ticket
->
t_unit_res
);
ticket
->
t_unit_res
);
xfs_warn
(
mp
,
" current res = %d bytes"
,
ticket
->
t_curr_res
);
xfs_warn
(
mp
,
" current res = %d bytes"
,
xfs_warn
(
mp
,
" original count = %d"
,
ticket
->
t_ocnt
);
ticket
->
t_curr_res
);
xfs_warn
(
mp
,
" remaining count = %d"
,
ticket
->
t_cnt
);
xfs_warn
(
mp
,
" total reg = %u bytes (o/flow = %u bytes)"
,
ticket
->
t_res_arr_sum
,
ticket
->
t_res_o_flow
);
xfs_warn
(
mp
,
" ophdrs = %u (ophdr space = %u bytes)"
,
ticket
->
t_res_num_ophdrs
,
ophdr_spc
);
xfs_warn
(
mp
,
" ophdr + reg = %u bytes"
,
ticket
->
t_res_arr_sum
+
ticket
->
t_res_o_flow
+
ophdr_spc
);
xfs_warn
(
mp
,
" num regions = %u"
,
ticket
->
t_res_num
);
for
(
i
=
0
;
i
<
ticket
->
t_res_num
;
i
++
)
{
uint
r_type
=
ticket
->
t_res_arr
[
i
].
r_type
;
xfs_warn
(
mp
,
"region[%u]: %s - %u bytes"
,
i
,
((
r_type
<=
0
||
r_type
>
XLOG_REG_TYPE_MAX
)
?
"bad-rtype"
:
res_type_str
[
r_type
]),
ticket
->
t_res_arr
[
i
].
r_len
);
}
}
}
/*
/*
...
@@ -2220,187 +2200,226 @@ xlog_print_trans(
...
@@ -2220,187 +2200,226 @@ xlog_print_trans(
}
}
}
}
static
inline
void
xlog_write_iovec
(
struct
xlog_in_core
*
iclog
,
uint32_t
*
log_offset
,
void
*
data
,
uint32_t
write_len
,
int
*
bytes_left
,
uint32_t
*
record_cnt
,
uint32_t
*
data_cnt
)
{
ASSERT
(
*
log_offset
<
iclog
->
ic_log
->
l_iclog_size
);
ASSERT
(
*
log_offset
%
sizeof
(
int32_t
)
==
0
);
ASSERT
(
write_len
%
sizeof
(
int32_t
)
==
0
);
memcpy
(
iclog
->
ic_datap
+
*
log_offset
,
data
,
write_len
);
*
log_offset
+=
write_len
;
*
bytes_left
-=
write_len
;
(
*
record_cnt
)
++
;
*
data_cnt
+=
write_len
;
}
/*
/*
* Calculate the potential space needed by the log vector. We may need a start
* Write log vectors into a single iclog which is guaranteed by the caller
* record, and each region gets its own struct xlog_op_header and may need to be
* to have enough space to write the entire log vector into.
* double word aligned.
*/
*/
static
int
static
void
xlog_write_calc_vec_length
(
xlog_write_full
(
struct
xfs_log_vec
*
lv
,
struct
xlog_ticket
*
ticket
,
struct
xlog_ticket
*
ticket
,
struct
xfs_log_vec
*
log_vector
,
struct
xlog_in_core
*
iclog
,
uint
optype
)
uint32_t
*
log_offset
,
uint32_t
*
len
,
uint32_t
*
record_cnt
,
uint32_t
*
data_cnt
)
{
{
struct
xfs_log_vec
*
lv
;
int
index
;
int
headers
=
0
;
int
len
=
0
;
int
i
;
if
(
optype
&
XLOG_START_TRANS
)
ASSERT
(
*
log_offset
+
*
len
<=
iclog
->
ic_size
||
headers
++
;
iclog
->
ic_state
==
XLOG_STATE_WANT_SYNC
)
;
for
(
lv
=
log_vector
;
lv
;
lv
=
lv
->
lv_next
)
{
/*
/* we don't write ordered log vectors */
* Ordered log vectors have no regions to write so this
if
(
lv
->
lv_buf_len
==
XFS_LOG_VEC_ORDERED
)
* loop will naturally skip them.
continue
;
*/
for
(
index
=
0
;
index
<
lv
->
lv_niovecs
;
index
++
)
{
headers
+=
lv
->
lv_niovecs
;
struct
xfs_log_iovec
*
reg
=
&
lv
->
lv_iovecp
[
index
];
struct
xlog_op_header
*
ophdr
=
reg
->
i_addr
;
for
(
i
=
0
;
i
<
lv
->
lv_niovecs
;
i
++
)
{
struct
xfs_log_iovec
*
vecp
=
&
lv
->
lv_iovecp
[
i
];
len
+=
vecp
->
i_len
;
xlog_tic_add_region
(
ticket
,
vecp
->
i_len
,
vecp
->
i_type
);
}
}
ticket
->
t_res_num_ophdrs
+=
headers
;
len
+=
headers
*
sizeof
(
struct
xlog_op_header
);
return
len
;
}
static
void
xlog_write_start_rec
(
struct
xlog_op_header
*
ophdr
,
struct
xlog_ticket
*
ticket
)
{
ophdr
->
oh_tid
=
cpu_to_be32
(
ticket
->
t_tid
);
ophdr
->
oh_tid
=
cpu_to_be32
(
ticket
->
t_tid
);
ophdr
->
oh_clientid
=
ticket
->
t_clientid
;
xlog_write_iovec
(
iclog
,
log_offset
,
reg
->
i_addr
,
ophdr
->
oh_len
=
0
;
reg
->
i_len
,
len
,
record_cnt
,
data_cnt
);
ophdr
->
oh_flags
=
XLOG_START_TRANS
;
}
ophdr
->
oh_res2
=
0
;
}
}
static
xlog_op_header_t
*
static
int
xlog_write_setup_ophdr
(
xlog_write_get_more_iclog_space
(
struct
xlog
*
log
,
struct
xlog_op_header
*
ophdr
,
struct
xlog_ticket
*
ticket
,
struct
xlog_ticket
*
ticket
,
uint
flags
)
struct
xlog_in_core
**
iclogp
,
uint32_t
*
log_offset
,
uint32_t
len
,
uint32_t
*
record_cnt
,
uint32_t
*
data_cnt
)
{
{
ophdr
->
oh_tid
=
cpu_to_be32
(
ticket
->
t_tid
);
struct
xlog_in_core
*
iclog
=
*
iclogp
;
ophdr
->
oh_clientid
=
ticket
->
t_clientid
;
struct
xlog
*
log
=
iclog
->
ic_log
;
ophdr
->
oh_res2
=
0
;
int
error
;
/* are we copying a commit or unmount record? */
ophdr
->
oh_flags
=
flags
;
/*
spin_lock
(
&
log
->
l_icloglock
);
* We've seen logs corrupted with bad transaction client ids. This
ASSERT
(
iclog
->
ic_state
==
XLOG_STATE_WANT_SYNC
);
* makes sure that XFS doesn't generate them on. Turn this into an EIO
xlog_state_finish_copy
(
log
,
iclog
,
*
record_cnt
,
*
data_cnt
);
* and shut down the filesystem.
error
=
xlog_state_release_iclog
(
log
,
iclog
);
*/
spin_unlock
(
&
log
->
l_icloglock
);
switch
(
ophdr
->
oh_clientid
)
{
if
(
error
)
case
XFS_TRANSACTION
:
return
error
;
case
XFS_VOLUME
:
case
XFS_LOG
:
break
;
default:
xfs_warn
(
log
->
l_mp
,
"Bad XFS transaction clientid 0x%x in ticket "
PTR_FMT
,
ophdr
->
oh_clientid
,
ticket
);
return
NULL
;
}
return
ophdr
;
error
=
xlog_state_get_iclog_space
(
log
,
len
,
&
iclog
,
ticket
,
log_offset
);
if
(
error
)
return
error
;
*
record_cnt
=
0
;
*
data_cnt
=
0
;
*
iclogp
=
iclog
;
return
0
;
}
}
/*
/*
*
Set up the parameters of the region copy into the log. This has
*
Write log vectors into a single iclog which is smaller than the current chain
*
to handle region write split across multiple log buffers - this
*
length. We write until we cannot fit a full record into the remaining space
*
state is kept external to this function so that this code can
*
and then stop. We return the log vector that is to be written that cannot
*
be written in an obvious, self documenting manner
.
*
wholly fit in the iclog
.
*/
*/
static
int
static
int
xlog_write_setup_copy
(
xlog_write_partial
(
struct
xfs_log_vec
*
lv
,
struct
xlog_ticket
*
ticket
,
struct
xlog_ticket
*
ticket
,
struct
xlog_op_header
*
ophdr
,
struct
xlog_in_core
**
iclogp
,
int
space_available
,
uint32_t
*
log_offset
,
int
space_required
,
uint32_t
*
len
,
int
*
copy_off
,
uint32_t
*
record_cnt
,
int
*
copy_len
,
uint32_t
*
data_cnt
)
int
*
last_was_partial_copy
,
{
int
*
bytes_consumed
)
struct
xlog_in_core
*
iclog
=
*
iclogp
;
{
struct
xlog_op_header
*
ophdr
;
int
still_to_copy
;
int
index
=
0
;
uint32_t
rlen
;
still_to_copy
=
space_required
-
*
bytes_consumed
;
int
error
;
*
copy_off
=
*
bytes_consumed
;
/* walk the logvec, copying until we run out of space in the iclog */
if
(
still_to_copy
<=
space_available
)
{
for
(
index
=
0
;
index
<
lv
->
lv_niovecs
;
index
++
)
{
/* write of region completes here */
struct
xfs_log_iovec
*
reg
=
&
lv
->
lv_iovecp
[
index
];
*
copy_len
=
still_to_copy
;
uint32_t
reg_offset
=
0
;
ophdr
->
oh_len
=
cpu_to_be32
(
*
copy_len
);
if
(
*
last_was_partial_copy
)
/*
ophdr
->
oh_flags
|=
(
XLOG_END_TRANS
|
XLOG_WAS_CONT_TRANS
);
* The first region of a continuation must have a non-zero
*
last_was_partial_copy
=
0
;
* length otherwise log recovery will just skip over it and
*
bytes_consumed
=
0
;
* start recovering from the next opheader it finds. Because we
return
0
;
* mark the next opheader as a continuation, recovery will then
* incorrectly add the continuation to the previous region and
* that breaks stuff.
*
* Hence if there isn't space for region data after the
* opheader, then we need to start afresh with a new iclog.
*/
if
(
iclog
->
ic_size
-
*
log_offset
<=
sizeof
(
struct
xlog_op_header
))
{
error
=
xlog_write_get_more_iclog_space
(
ticket
,
&
iclog
,
log_offset
,
*
len
,
record_cnt
,
data_cnt
);
if
(
error
)
return
error
;
}
}
/* partial write of region, needs extra log op header reservation */
ophdr
=
reg
->
i_addr
;
*
copy_len
=
space_available
;
rlen
=
min_t
(
uint32_t
,
reg
->
i_len
,
iclog
->
ic_size
-
*
log_offset
);
ophdr
->
oh_len
=
cpu_to_be32
(
*
copy_len
);
ophdr
->
oh_tid
=
cpu_to_be32
(
ticket
->
t_tid
);
ophdr
->
oh_len
=
cpu_to_be32
(
rlen
-
sizeof
(
struct
xlog_op_header
));
if
(
rlen
!=
reg
->
i_len
)
ophdr
->
oh_flags
|=
XLOG_CONTINUE_TRANS
;
ophdr
->
oh_flags
|=
XLOG_CONTINUE_TRANS
;
if
(
*
last_was_partial_copy
)
ophdr
->
oh_flags
|=
XLOG_WAS_CONT_TRANS
;
*
bytes_consumed
+=
*
copy_len
;
(
*
last_was_partial_copy
)
++
;
/* account for new log op header */
xlog_write_iovec
(
iclog
,
log_offset
,
reg
->
i_addr
,
ticket
->
t_curr_res
-=
sizeof
(
struct
xlog_op_header
);
rlen
,
len
,
record_cnt
,
data_cnt
);
ticket
->
t_res_num_ophdrs
++
;
return
sizeof
(
struct
xlog_op_header
);
/* If we wrote the whole region, move to the next. */
}
if
(
rlen
==
reg
->
i_len
)
continue
;
static
int
/*
xlog_write_copy_finish
(
* We now have a partially written iovec, but it can span
struct
xlog
*
log
,
* multiple iclogs so we loop here. First we release the iclog
struct
xlog_in_core
*
iclog
,
* we currently have, then we get a new iclog and add a new
uint
flags
,
* opheader. Then we continue copying from where we were until
int
*
record_cnt
,
* we either complete the iovec or fill the iclog. If we
int
*
data_cnt
,
* complete the iovec, then we increment the index and go right
int
*
partial_copy
,
* back to the top of the outer loop. if we fill the iclog, we
int
*
partial_copy_len
,
* run the inner loop again.
int
log_offset
)
*
{
* This is complicated by the tail of a region using all the
int
error
;
* space in an iclog and hence requiring us to release the iclog
* and get a new one before returning to the outer loop. We must
* always guarantee that we exit this inner loop with at least
* space for log transaction opheaders left in the current
* iclog, hence we cannot just terminate the loop at the end
* of the of the continuation. So we loop while there is no
* space left in the current iclog, and check for the end of the
* continuation after getting a new iclog.
*/
do
{
/*
* Ensure we include the continuation opheader in the
* space we need in the new iclog by adding that size
* to the length we require. This continuation opheader
* needs to be accounted to the ticket as the space it
* consumes hasn't been accounted to the lv we are
* writing.
*/
error
=
xlog_write_get_more_iclog_space
(
ticket
,
&
iclog
,
log_offset
,
*
len
+
sizeof
(
struct
xlog_op_header
),
record_cnt
,
data_cnt
);
if
(
error
)
return
error
;
ophdr
=
iclog
->
ic_datap
+
*
log_offset
;
ophdr
->
oh_tid
=
cpu_to_be32
(
ticket
->
t_tid
);
ophdr
->
oh_clientid
=
XFS_TRANSACTION
;
ophdr
->
oh_res2
=
0
;
ophdr
->
oh_flags
=
XLOG_WAS_CONT_TRANS
;
ticket
->
t_curr_res
-=
sizeof
(
struct
xlog_op_header
);
*
log_offset
+=
sizeof
(
struct
xlog_op_header
);
*
data_cnt
+=
sizeof
(
struct
xlog_op_header
);
if
(
*
partial_copy
)
{
/*
/*
* This iclog has already been marked WANT_SYNC by
* If rlen fits in the iclog, then end the region
* xlog_state_get_iclog_space
.
* continuation. Otherwise we're going around again
.
*/
*/
spin_lock
(
&
log
->
l_icloglock
)
;
reg_offset
+=
rlen
;
xlog_state_finish_copy
(
log
,
iclog
,
*
record_cnt
,
*
data_cnt
)
;
rlen
=
reg
->
i_len
-
reg_offset
;
*
record_cnt
=
0
;
if
(
rlen
<=
iclog
->
ic_size
-
*
log_offset
)
*
data_cnt
=
0
;
ophdr
->
oh_flags
|=
XLOG_END_TRANS
;
goto
release_iclog
;
else
}
ophdr
->
oh_flags
|=
XLOG_CONTINUE_TRANS
;
*
partial_copy
=
0
;
rlen
=
min_t
(
uint32_t
,
rlen
,
iclog
->
ic_size
-
*
log_offset
)
;
*
partial_copy_len
=
0
;
ophdr
->
oh_len
=
cpu_to_be32
(
rlen
)
;
if
(
iclog
->
ic_size
-
log_offset
>
sizeof
(
xlog_op_header_t
))
xlog_write_iovec
(
iclog
,
log_offset
,
return
0
;
reg
->
i_addr
+
reg_offset
,
rlen
,
len
,
record_cnt
,
data_cnt
);
/* no more space in this iclog - push it. */
}
while
(
ophdr
->
oh_flags
&
XLOG_CONTINUE_TRANS
);
spin_lock
(
&
log
->
l_icloglock
);
}
xlog_state_finish_copy
(
log
,
iclog
,
*
record_cnt
,
*
data_cnt
);
*
record_cnt
=
0
;
*
data_cnt
=
0
;
if
(
iclog
->
ic_state
==
XLOG_STATE_ACTIVE
)
/*
xlog_state_switch_iclogs
(
log
,
iclog
,
0
);
* No more iovecs remain in this logvec so return the next log vec to
else
* the caller so it can go back to fast path copying.
ASSERT
(
iclog
->
ic_state
==
XLOG_STATE_WANT_SYNC
||
*/
xlog_is_shutdown
(
log
));
*
iclogp
=
iclog
;
release_iclog:
return
0
;
error
=
xlog_state_release_iclog
(
log
,
iclog
);
spin_unlock
(
&
log
->
l_icloglock
);
return
error
;
}
}
/*
/*
...
@@ -2449,27 +2468,16 @@ xlog_write(
...
@@ -2449,27 +2468,16 @@ xlog_write(
struct
xfs_cil_ctx
*
ctx
,
struct
xfs_cil_ctx
*
ctx
,
struct
xfs_log_vec
*
log_vector
,
struct
xfs_log_vec
*
log_vector
,
struct
xlog_ticket
*
ticket
,
struct
xlog_ticket
*
ticket
,
uint
optype
)
uint32_t
len
)
{
{
struct
xlog_in_core
*
iclog
=
NULL
;
struct
xlog_in_core
*
iclog
=
NULL
;
struct
xfs_log_vec
*
lv
=
log_vector
;
struct
xfs_log_vec
*
lv
=
log_vector
;
struct
xfs_log_iovec
*
vecp
=
lv
->
lv_iovecp
;
uint32_t
record_cnt
=
0
;
int
index
=
0
;
uint32_t
data_cnt
=
0
;
int
len
;
int
partial_copy
=
0
;
int
partial_copy_len
=
0
;
int
contwr
=
0
;
int
record_cnt
=
0
;
int
data_cnt
=
0
;
int
error
=
0
;
int
error
=
0
;
int
log_offset
;
/*
* If this is a commit or unmount transaction, we don't need a start
* record to be written. We do, however, have to account for the
* commit or unmount header that gets written. Hence we always have
* to account for an extra xlog_op_header here.
*/
ticket
->
t_curr_res
-=
sizeof
(
struct
xlog_op_header
);
if
(
ticket
->
t_curr_res
<
0
)
{
if
(
ticket
->
t_curr_res
<
0
)
{
xfs_alert_tag
(
log
->
l_mp
,
XFS_PTAG_LOGRES
,
xfs_alert_tag
(
log
->
l_mp
,
XFS_PTAG_LOGRES
,
"ctx ticket reservation ran out. Need to up reservation"
);
"ctx ticket reservation ran out. Need to up reservation"
);
...
@@ -2477,144 +2485,54 @@ xlog_write(
...
@@ -2477,144 +2485,54 @@ xlog_write(
xlog_force_shutdown
(
log
,
SHUTDOWN_LOG_IO_ERROR
);
xlog_force_shutdown
(
log
,
SHUTDOWN_LOG_IO_ERROR
);
}
}
len
=
xlog_write_calc_vec_length
(
ticket
,
log_vector
,
optype
);
while
(
lv
&&
(
!
lv
->
lv_niovecs
||
index
<
lv
->
lv_niovecs
))
{
void
*
ptr
;
int
log_offset
;
error
=
xlog_state_get_iclog_space
(
log
,
len
,
&
iclog
,
ticket
,
error
=
xlog_state_get_iclog_space
(
log
,
len
,
&
iclog
,
ticket
,
&
contwr
,
&
log_offset
);
&
log_offset
);
if
(
error
)
if
(
error
)
return
error
;
return
error
;
ASSERT
(
log_offset
<=
iclog
->
ic_size
-
1
);
ASSERT
(
log_offset
<=
iclog
->
ic_size
-
1
);
ptr
=
iclog
->
ic_datap
+
log_offset
;
/*
/*
* If we have a context pointer, pass it the first iclog we are
* If we have a context pointer, pass it the first iclog we are
* writing to so it can record state needed for iclog write
* writing to so it can record state needed for iclog write
* ordering.
* ordering.
*/
*/
if
(
ctx
)
{
if
(
ctx
)
xlog_cil_set_ctx_write_state
(
ctx
,
iclog
);
xlog_cil_set_ctx_write_state
(
ctx
,
iclog
);
ctx
=
NULL
;
}
while
(
lv
)
{
/*
/*
*
This loop writes out as many regions as can fit in the amount
*
If the entire log vec does not fit in the iclog, punt it to
*
of space which was allocated by xlog_state_get_iclog_space()
.
*
the partial copy loop which can handle this case
.
*/
*/
while
(
lv
&&
(
!
lv
->
lv_niovecs
||
index
<
lv
->
lv_niovecs
))
{
if
(
lv
->
lv_niovecs
&&
struct
xfs_log_iovec
*
reg
;
lv
->
lv_bytes
>
iclog
->
ic_size
-
log_offset
)
{
struct
xlog_op_header
*
ophdr
;
error
=
xlog_write_partial
(
lv
,
ticket
,
&
iclog
,
int
copy_len
;
&
log_offset
,
&
len
,
&
record_cnt
,
int
copy_off
;
&
data_cnt
);
bool
ordered
=
false
;
if
(
error
)
{
bool
wrote_start_rec
=
false
;
/* ordered log vectors have no regions to write */
if
(
lv
->
lv_buf_len
==
XFS_LOG_VEC_ORDERED
)
{
ASSERT
(
lv
->
lv_niovecs
==
0
);
ordered
=
true
;
goto
next_lv
;
}
reg
=
&
vecp
[
index
];
ASSERT
(
reg
->
i_len
%
sizeof
(
int32_t
)
==
0
);
ASSERT
((
unsigned
long
)
ptr
%
sizeof
(
int32_t
)
==
0
);
/*
/*
* Before we start formatting log vectors, we need to
* We have no iclog to release, so just return
* write a start record. Only do this for the first
* the error immediately.
* iclog we write to.
*/
*/
if
(
optype
&
XLOG_START_TRANS
)
{
xlog_write_start_rec
(
ptr
,
ticket
);
xlog_write_adv_cnt
(
&
ptr
,
&
len
,
&
log_offset
,
sizeof
(
struct
xlog_op_header
));
optype
&=
~
XLOG_START_TRANS
;
wrote_start_rec
=
true
;
}
ophdr
=
xlog_write_setup_ophdr
(
log
,
ptr
,
ticket
,
optype
);
if
(
!
ophdr
)
return
-
EIO
;
xlog_write_adv_cnt
(
&
ptr
,
&
len
,
&
log_offset
,
sizeof
(
struct
xlog_op_header
));
len
+=
xlog_write_setup_copy
(
ticket
,
ophdr
,
iclog
->
ic_size
-
log_offset
,
reg
->
i_len
,
&
copy_off
,
&
copy_len
,
&
partial_copy
,
&
partial_copy_len
);
xlog_verify_dest_ptr
(
log
,
ptr
);
/*
* Copy region.
*
* Unmount records just log an opheader, so can have
* empty payloads with no data region to copy. Hence we
* only copy the payload if the vector says it has data
* to copy.
*/
ASSERT
(
copy_len
>=
0
);
if
(
copy_len
>
0
)
{
memcpy
(
ptr
,
reg
->
i_addr
+
copy_off
,
copy_len
);
xlog_write_adv_cnt
(
&
ptr
,
&
len
,
&
log_offset
,
copy_len
);
}
copy_len
+=
sizeof
(
struct
xlog_op_header
);
record_cnt
++
;
if
(
wrote_start_rec
)
{
copy_len
+=
sizeof
(
struct
xlog_op_header
);
record_cnt
++
;
}
data_cnt
+=
contwr
?
copy_len
:
0
;
error
=
xlog_write_copy_finish
(
log
,
iclog
,
optype
,
&
record_cnt
,
&
data_cnt
,
&
partial_copy
,
&
partial_copy_len
,
log_offset
);
if
(
error
)
return
error
;
return
error
;
/*
* if we had a partial copy, we need to get more iclog
* space but we don't want to increment the region
* index because there is still more is this region to
* write.
*
* If we completed writing this region, and we flushed
* the iclog (indicated by resetting of the record
* count), then we also need to get more log space. If
* this was the last record, though, we are done and
* can just return.
*/
if
(
partial_copy
)
break
;
if
(
++
index
==
lv
->
lv_niovecs
)
{
next_lv:
lv
=
lv
->
lv_next
;
index
=
0
;
if
(
lv
)
vecp
=
lv
->
lv_iovecp
;
}
if
(
record_cnt
==
0
&&
!
ordered
)
{
if
(
!
lv
)
return
0
;
break
;
}
}
}
else
{
xlog_write_full
(
lv
,
ticket
,
iclog
,
&
log_offset
,
&
len
,
&
record_cnt
,
&
data_cnt
);
}
}
lv
=
lv
->
lv_next
;
}
}
ASSERT
(
len
==
0
);
ASSERT
(
len
==
0
);
/*
* We've already been guaranteed that the last writes will fit inside
* the current iclog, and hence it will already have the space used by
* those writes accounted to it. Hence we do not need to update the
* iclog with the number of bytes written here.
*/
spin_lock
(
&
log
->
l_icloglock
);
spin_lock
(
&
log
->
l_icloglock
);
xlog_state_finish_copy
(
log
,
iclog
,
record_cnt
,
data_cnt
);
xlog_state_finish_copy
(
log
,
iclog
,
record_cnt
,
0
);
error
=
xlog_state_release_iclog
(
log
,
iclog
);
error
=
xlog_state_release_iclog
(
log
,
iclog
);
spin_unlock
(
&
log
->
l_icloglock
);
spin_unlock
(
&
log
->
l_icloglock
);
...
@@ -2971,7 +2889,6 @@ xlog_state_get_iclog_space(
...
@@ -2971,7 +2889,6 @@ xlog_state_get_iclog_space(
int
len
,
int
len
,
struct
xlog_in_core
**
iclogp
,
struct
xlog_in_core
**
iclogp
,
struct
xlog_ticket
*
ticket
,
struct
xlog_ticket
*
ticket
,
int
*
continued_write
,
int
*
logoffsetp
)
int
*
logoffsetp
)
{
{
int
log_offset
;
int
log_offset
;
...
@@ -3008,9 +2925,6 @@ xlog_state_get_iclog_space(
...
@@ -3008,9 +2925,6 @@ xlog_state_get_iclog_space(
*/
*/
if
(
log_offset
==
0
)
{
if
(
log_offset
==
0
)
{
ticket
->
t_curr_res
-=
log
->
l_iclog_hsize
;
ticket
->
t_curr_res
-=
log
->
l_iclog_hsize
;
xlog_tic_add_region
(
ticket
,
log
->
l_iclog_hsize
,
XLOG_REG_TYPE_LRHEADER
);
head
->
h_cycle
=
cpu_to_be32
(
log
->
l_curr_cycle
);
head
->
h_cycle
=
cpu_to_be32
(
log
->
l_curr_cycle
);
head
->
h_lsn
=
cpu_to_be64
(
head
->
h_lsn
=
cpu_to_be64
(
xlog_assign_lsn
(
log
->
l_curr_cycle
,
log
->
l_curr_block
));
xlog_assign_lsn
(
log
->
l_curr_cycle
,
log
->
l_curr_block
));
...
@@ -3052,13 +2966,10 @@ xlog_state_get_iclog_space(
...
@@ -3052,13 +2966,10 @@ xlog_state_get_iclog_space(
* iclogs (to mark it taken), this particular iclog will release/sync
* iclogs (to mark it taken), this particular iclog will release/sync
* to disk in xlog_write().
* to disk in xlog_write().
*/
*/
if
(
len
<=
iclog
->
ic_size
-
iclog
->
ic_offset
)
{
if
(
len
<=
iclog
->
ic_size
-
iclog
->
ic_offset
)
*
continued_write
=
0
;
iclog
->
ic_offset
+=
len
;
iclog
->
ic_offset
+=
len
;
}
else
{
else
*
continued_write
=
1
;
xlog_state_switch_iclogs
(
log
,
iclog
,
iclog
->
ic_size
);
xlog_state_switch_iclogs
(
log
,
iclog
,
iclog
->
ic_size
);
}
*
iclogp
=
iclog
;
*
iclogp
=
iclog
;
ASSERT
(
iclog
->
ic_offset
<=
iclog
->
ic_size
);
ASSERT
(
iclog
->
ic_offset
<=
iclog
->
ic_size
);
...
@@ -3090,7 +3001,6 @@ xfs_log_ticket_regrant(
...
@@ -3090,7 +3001,6 @@ xfs_log_ticket_regrant(
xlog_grant_sub_space
(
log
,
&
log
->
l_write_head
.
grant
,
xlog_grant_sub_space
(
log
,
&
log
->
l_write_head
.
grant
,
ticket
->
t_curr_res
);
ticket
->
t_curr_res
);
ticket
->
t_curr_res
=
ticket
->
t_unit_res
;
ticket
->
t_curr_res
=
ticket
->
t_unit_res
;
xlog_tic_reset_res
(
ticket
);
trace_xfs_log_ticket_regrant_sub
(
log
,
ticket
);
trace_xfs_log_ticket_regrant_sub
(
log
,
ticket
);
...
@@ -3101,7 +3011,6 @@ xfs_log_ticket_regrant(
...
@@ -3101,7 +3011,6 @@ xfs_log_ticket_regrant(
trace_xfs_log_ticket_regrant_exit
(
log
,
ticket
);
trace_xfs_log_ticket_regrant_exit
(
log
,
ticket
);
ticket
->
t_curr_res
=
ticket
->
t_unit_res
;
ticket
->
t_curr_res
=
ticket
->
t_unit_res
;
xlog_tic_reset_res
(
ticket
);
}
}
xfs_log_ticket_put
(
ticket
);
xfs_log_ticket_put
(
ticket
);
...
@@ -3591,7 +3500,6 @@ xlog_ticket_alloc(
...
@@ -3591,7 +3500,6 @@ xlog_ticket_alloc(
struct
xlog
*
log
,
struct
xlog
*
log
,
int
unit_bytes
,
int
unit_bytes
,
int
cnt
,
int
cnt
,
char
client
,
bool
permanent
)
bool
permanent
)
{
{
struct
xlog_ticket
*
tic
;
struct
xlog_ticket
*
tic
;
...
@@ -3609,39 +3517,13 @@ xlog_ticket_alloc(
...
@@ -3609,39 +3517,13 @@ xlog_ticket_alloc(
tic
->
t_cnt
=
cnt
;
tic
->
t_cnt
=
cnt
;
tic
->
t_ocnt
=
cnt
;
tic
->
t_ocnt
=
cnt
;
tic
->
t_tid
=
prandom_u32
();
tic
->
t_tid
=
prandom_u32
();
tic
->
t_clientid
=
client
;
if
(
permanent
)
if
(
permanent
)
tic
->
t_flags
|=
XLOG_TIC_PERM_RESERV
;
tic
->
t_flags
|=
XLOG_TIC_PERM_RESERV
;
xlog_tic_reset_res
(
tic
);
return
tic
;
return
tic
;
}
}
#if defined(DEBUG)
#if defined(DEBUG)
/*
* Make sure that the destination ptr is within the valid data region of
* one of the iclogs. This uses backup pointers stored in a different
* part of the log in case we trash the log structure.
*/
STATIC
void
xlog_verify_dest_ptr
(
struct
xlog
*
log
,
void
*
ptr
)
{
int
i
;
int
good_ptr
=
0
;
for
(
i
=
0
;
i
<
log
->
l_iclog_bufs
;
i
++
)
{
if
(
ptr
>=
log
->
l_iclog_bak
[
i
]
&&
ptr
<=
log
->
l_iclog_bak
[
i
]
+
log
->
l_iclog_size
)
good_ptr
++
;
}
if
(
!
good_ptr
)
xfs_emerg
(
log
->
l_mp
,
"%s: invalid ptr"
,
__func__
);
}
/*
/*
* Check to make sure the grant write head didn't just over lap the tail. If
* Check to make sure the grant write head didn't just over lap the tail. If
* the cycles are the same, we can't be overlapping. Otherwise, make sure that
* the cycles are the same, we can't be overlapping. Otherwise, make sure that
...
@@ -3769,7 +3651,7 @@ xlog_verify_iclog(
...
@@ -3769,7 +3651,7 @@ xlog_verify_iclog(
if
(
field_offset
&
0x1ff
)
{
if
(
field_offset
&
0x1ff
)
{
clientid
=
ophead
->
oh_clientid
;
clientid
=
ophead
->
oh_clientid
;
}
else
{
}
else
{
idx
=
BTOBBT
((
char
*
)
&
ophead
->
oh_clientid
-
iclog
->
ic_datap
);
idx
=
BTOBBT
((
void
*
)
&
ophead
->
oh_clientid
-
iclog
->
ic_datap
);
if
(
idx
>=
(
XLOG_HEADER_CYCLE_SIZE
/
BBSIZE
))
{
if
(
idx
>=
(
XLOG_HEADER_CYCLE_SIZE
/
BBSIZE
))
{
j
=
idx
/
(
XLOG_HEADER_CYCLE_SIZE
/
BBSIZE
);
j
=
idx
/
(
XLOG_HEADER_CYCLE_SIZE
/
BBSIZE
);
k
=
idx
%
(
XLOG_HEADER_CYCLE_SIZE
/
BBSIZE
);
k
=
idx
%
(
XLOG_HEADER_CYCLE_SIZE
/
BBSIZE
);
...
@@ -3780,11 +3662,12 @@ xlog_verify_iclog(
...
@@ -3780,11 +3662,12 @@ xlog_verify_iclog(
iclog
->
ic_header
.
h_cycle_data
[
idx
]);
iclog
->
ic_header
.
h_cycle_data
[
idx
]);
}
}
}
}
if
(
clientid
!=
XFS_TRANSACTION
&&
clientid
!=
XFS_LOG
)
if
(
clientid
!=
XFS_TRANSACTION
&&
clientid
!=
XFS_LOG
)
{
xfs_warn
(
log
->
l_mp
,
xfs_warn
(
log
->
l_mp
,
"%s: invalid clientid %d op "
PTR_FMT
" offset 0x%lx"
,
"%s:
op %d
invalid clientid %d op "
PTR_FMT
" offset 0x%lx"
,
__func__
,
clientid
,
ophead
,
__func__
,
i
,
clientid
,
ophead
,
(
unsigned
long
)
field_offset
);
(
unsigned
long
)
field_offset
);
}
/* check length */
/* check length */
p
=
&
ophead
->
oh_len
;
p
=
&
ophead
->
oh_len
;
...
@@ -3792,8 +3675,7 @@ xlog_verify_iclog(
...
@@ -3792,8 +3675,7 @@ xlog_verify_iclog(
if
(
field_offset
&
0x1ff
)
{
if
(
field_offset
&
0x1ff
)
{
op_len
=
be32_to_cpu
(
ophead
->
oh_len
);
op_len
=
be32_to_cpu
(
ophead
->
oh_len
);
}
else
{
}
else
{
idx
=
BTOBBT
((
uintptr_t
)
&
ophead
->
oh_len
-
idx
=
BTOBBT
((
void
*
)
&
ophead
->
oh_len
-
iclog
->
ic_datap
);
(
uintptr_t
)
iclog
->
ic_datap
);
if
(
idx
>=
(
XLOG_HEADER_CYCLE_SIZE
/
BBSIZE
))
{
if
(
idx
>=
(
XLOG_HEADER_CYCLE_SIZE
/
BBSIZE
))
{
j
=
idx
/
(
XLOG_HEADER_CYCLE_SIZE
/
BBSIZE
);
j
=
idx
/
(
XLOG_HEADER_CYCLE_SIZE
/
BBSIZE
);
k
=
idx
%
(
XLOG_HEADER_CYCLE_SIZE
/
BBSIZE
);
k
=
idx
%
(
XLOG_HEADER_CYCLE_SIZE
/
BBSIZE
);
...
...
fs/xfs/xfs_log.h
浏览文件 @
463260d7
...
@@ -21,42 +21,19 @@ struct xfs_log_vec {
...
@@ -21,42 +21,19 @@ struct xfs_log_vec {
#define XFS_LOG_VEC_ORDERED (-1)
#define XFS_LOG_VEC_ORDERED (-1)
static
inline
void
*
void
*
xlog_prepare_iovec
(
struct
xfs_log_vec
*
lv
,
struct
xfs_log_iovec
**
vecp
,
xlog_prepare_iovec
(
struct
xfs_log_vec
*
lv
,
struct
xfs_log_iovec
**
vecp
,
uint
type
);
uint
type
)
{
struct
xfs_log_iovec
*
vec
=
*
vecp
;
if
(
vec
)
{
ASSERT
(
vec
-
lv
->
lv_iovecp
<
lv
->
lv_niovecs
);
vec
++
;
}
else
{
vec
=
&
lv
->
lv_iovecp
[
0
];
}
vec
->
i_type
=
type
;
vec
->
i_addr
=
lv
->
lv_buf
+
lv
->
lv_buf_len
;
ASSERT
(
IS_ALIGNED
((
unsigned
long
)
vec
->
i_addr
,
sizeof
(
uint64_t
)));
*
vecp
=
vec
;
return
vec
->
i_addr
;
}
/*
* We need to make sure the next buffer is naturally aligned for the biggest
* basic data type we put into it. We already accounted for this padding when
* sizing the buffer.
*
* However, this padding does not get written into the log, and hence we have to
* track the space used by the log vectors separately to prevent log space hangs
* due to inaccurate accounting (i.e. a leak) of the used log space through the
* CIL context ticket.
*/
static
inline
void
static
inline
void
xlog_finish_iovec
(
struct
xfs_log_vec
*
lv
,
struct
xfs_log_iovec
*
vec
,
int
len
)
xlog_finish_iovec
(
struct
xfs_log_vec
*
lv
,
struct
xfs_log_iovec
*
vec
,
int
len
)
{
{
lv
->
lv_buf_len
+=
round_up
(
len
,
sizeof
(
uint64_t
));
struct
xlog_op_header
*
oph
=
vec
->
i_addr
;
/* opheader tracks payload length, logvec tracks region length */
oph
->
oh_len
=
cpu_to_be32
(
len
);
len
+=
sizeof
(
struct
xlog_op_header
);
lv
->
lv_buf_len
+=
len
;
lv
->
lv_bytes
+=
len
;
lv
->
lv_bytes
+=
len
;
vec
->
i_len
=
len
;
vec
->
i_len
=
len
;
}
}
...
@@ -118,12 +95,8 @@ void xfs_log_mount_cancel(struct xfs_mount *);
...
@@ -118,12 +95,8 @@ void xfs_log_mount_cancel(struct xfs_mount *);
xfs_lsn_t
xlog_assign_tail_lsn
(
struct
xfs_mount
*
mp
);
xfs_lsn_t
xlog_assign_tail_lsn
(
struct
xfs_mount
*
mp
);
xfs_lsn_t
xlog_assign_tail_lsn_locked
(
struct
xfs_mount
*
mp
);
xfs_lsn_t
xlog_assign_tail_lsn_locked
(
struct
xfs_mount
*
mp
);
void
xfs_log_space_wake
(
struct
xfs_mount
*
mp
);
void
xfs_log_space_wake
(
struct
xfs_mount
*
mp
);
int
xfs_log_reserve
(
struct
xfs_mount
*
mp
,
int
xfs_log_reserve
(
struct
xfs_mount
*
mp
,
int
length
,
int
count
,
int
length
,
struct
xlog_ticket
**
ticket
,
bool
permanent
);
int
count
,
struct
xlog_ticket
**
ticket
,
uint8_t
clientid
,
bool
permanent
);
int
xfs_log_regrant
(
struct
xfs_mount
*
mp
,
struct
xlog_ticket
*
tic
);
int
xfs_log_regrant
(
struct
xfs_mount
*
mp
,
struct
xlog_ticket
*
tic
);
void
xfs_log_unmount
(
struct
xfs_mount
*
mp
);
void
xfs_log_unmount
(
struct
xfs_mount
*
mp
);
bool
xfs_log_writable
(
struct
xfs_mount
*
mp
);
bool
xfs_log_writable
(
struct
xfs_mount
*
mp
);
...
...
fs/xfs/xfs_log_cil.c
浏览文件 @
463260d7
...
@@ -37,7 +37,7 @@ xlog_cil_ticket_alloc(
...
@@ -37,7 +37,7 @@ xlog_cil_ticket_alloc(
{
{
struct
xlog_ticket
*
tic
;
struct
xlog_ticket
*
tic
;
tic
=
xlog_ticket_alloc
(
log
,
0
,
1
,
XFS_TRANSACTION
,
0
);
tic
=
xlog_ticket_alloc
(
log
,
0
,
1
,
0
);
/*
/*
* set the current reservation to zero so we know to steal the basic
* set the current reservation to zero so we know to steal the basic
...
@@ -214,13 +214,20 @@ xlog_cil_alloc_shadow_bufs(
...
@@ -214,13 +214,20 @@ xlog_cil_alloc_shadow_bufs(
}
}
/*
/*
* We 64-bit align the length of each iovec so that the start
* We 64-bit align the length of each iovec so that the start of
* of the next one is naturally aligned. We'll need to
* the next one is naturally aligned. We'll need to account for
* account for that slack space here. Then round nbytes up
* that slack space here.
* to 64-bit alignment so that the initial buffer alignment is
*
* easy to calculate and verify.
* We also add the xlog_op_header to each region when
* formatting, but that's not accounted to the size of the item
* at this point. Hence we'll need an addition number of bytes
* for each vector to hold an opheader.
*
* Then round nbytes up to 64-bit alignment so that the initial
* buffer alignment is easy to calculate and verify.
*/
*/
nbytes
+=
niovecs
*
sizeof
(
uint64_t
);
nbytes
+=
niovecs
*
(
sizeof
(
uint64_t
)
+
sizeof
(
struct
xlog_op_header
));
nbytes
=
round_up
(
nbytes
,
sizeof
(
uint64_t
));
nbytes
=
round_up
(
nbytes
,
sizeof
(
uint64_t
));
/*
/*
...
@@ -277,22 +284,18 @@ xlog_cil_alloc_shadow_bufs(
...
@@ -277,22 +284,18 @@ xlog_cil_alloc_shadow_bufs(
/*
/*
* Prepare the log item for insertion into the CIL. Calculate the difference in
* Prepare the log item for insertion into the CIL. Calculate the difference in
* log space and vectors it will consume, and if it is a new item pin it as
* log space it will consume, and if it is a new item pin it as well.
* well.
*/
*/
STATIC
void
STATIC
void
xfs_cil_prepare_item
(
xfs_cil_prepare_item
(
struct
xlog
*
log
,
struct
xlog
*
log
,
struct
xfs_log_vec
*
lv
,
struct
xfs_log_vec
*
lv
,
struct
xfs_log_vec
*
old_lv
,
struct
xfs_log_vec
*
old_lv
,
int
*
diff_len
,
int
*
diff_len
)
int
*
diff_iovecs
)
{
{
/* Account for the new LV being passed in */
/* Account for the new LV being passed in */
if
(
lv
->
lv_buf_len
!=
XFS_LOG_VEC_ORDERED
)
{
if
(
lv
->
lv_buf_len
!=
XFS_LOG_VEC_ORDERED
)
*
diff_len
+=
lv
->
lv_bytes
;
*
diff_len
+=
lv
->
lv_bytes
;
*
diff_iovecs
+=
lv
->
lv_niovecs
;
}
/*
/*
* If there is no old LV, this is the first time we've seen the item in
* If there is no old LV, this is the first time we've seen the item in
...
@@ -309,7 +312,6 @@ xfs_cil_prepare_item(
...
@@ -309,7 +312,6 @@ xfs_cil_prepare_item(
ASSERT
(
lv
->
lv_buf_len
!=
XFS_LOG_VEC_ORDERED
);
ASSERT
(
lv
->
lv_buf_len
!=
XFS_LOG_VEC_ORDERED
);
*
diff_len
-=
old_lv
->
lv_bytes
;
*
diff_len
-=
old_lv
->
lv_bytes
;
*
diff_iovecs
-=
old_lv
->
lv_niovecs
;
lv
->
lv_item
->
li_lv_shadow
=
old_lv
;
lv
->
lv_item
->
li_lv_shadow
=
old_lv
;
}
}
...
@@ -358,12 +360,10 @@ static void
...
@@ -358,12 +360,10 @@ static void
xlog_cil_insert_format_items
(
xlog_cil_insert_format_items
(
struct
xlog
*
log
,
struct
xlog
*
log
,
struct
xfs_trans
*
tp
,
struct
xfs_trans
*
tp
,
int
*
diff_len
,
int
*
diff_len
)
int
*
diff_iovecs
)
{
{
struct
xfs_log_item
*
lip
;
struct
xfs_log_item
*
lip
;
/* Bail out if we didn't find a log item. */
/* Bail out if we didn't find a log item. */
if
(
list_empty
(
&
tp
->
t_items
))
{
if
(
list_empty
(
&
tp
->
t_items
))
{
ASSERT
(
0
);
ASSERT
(
0
);
...
@@ -406,7 +406,6 @@ xlog_cil_insert_format_items(
...
@@ -406,7 +406,6 @@ xlog_cil_insert_format_items(
* set the item up as though it is a new insertion so
* set the item up as though it is a new insertion so
* that the space reservation accounting is correct.
* that the space reservation accounting is correct.
*/
*/
*
diff_iovecs
-=
lv
->
lv_niovecs
;
*
diff_len
-=
lv
->
lv_bytes
;
*
diff_len
-=
lv
->
lv_bytes
;
/* Ensure the lv is set up according to ->iop_size */
/* Ensure the lv is set up according to ->iop_size */
...
@@ -431,7 +430,7 @@ xlog_cil_insert_format_items(
...
@@ -431,7 +430,7 @@ xlog_cil_insert_format_items(
ASSERT
(
IS_ALIGNED
((
unsigned
long
)
lv
->
lv_buf
,
sizeof
(
uint64_t
)));
ASSERT
(
IS_ALIGNED
((
unsigned
long
)
lv
->
lv_buf
,
sizeof
(
uint64_t
)));
lip
->
li_ops
->
iop_format
(
lip
,
lv
);
lip
->
li_ops
->
iop_format
(
lip
,
lv
);
insert:
insert:
xfs_cil_prepare_item
(
log
,
lv
,
old_lv
,
diff_len
,
diff_iovecs
);
xfs_cil_prepare_item
(
log
,
lv
,
old_lv
,
diff_len
);
}
}
}
}
...
@@ -451,7 +450,6 @@ xlog_cil_insert_items(
...
@@ -451,7 +450,6 @@ xlog_cil_insert_items(
struct
xfs_cil_ctx
*
ctx
=
cil
->
xc_ctx
;
struct
xfs_cil_ctx
*
ctx
=
cil
->
xc_ctx
;
struct
xfs_log_item
*
lip
;
struct
xfs_log_item
*
lip
;
int
len
=
0
;
int
len
=
0
;
int
diff_iovecs
=
0
;
int
iclog_space
;
int
iclog_space
;
int
iovhdr_res
=
0
,
split_res
=
0
,
ctx_res
=
0
;
int
iovhdr_res
=
0
,
split_res
=
0
,
ctx_res
=
0
;
...
@@ -461,15 +459,10 @@ xlog_cil_insert_items(
...
@@ -461,15 +459,10 @@ xlog_cil_insert_items(
* We can do this safely because the context can't checkpoint until we
* We can do this safely because the context can't checkpoint until we
* are done so it doesn't matter exactly how we update the CIL.
* are done so it doesn't matter exactly how we update the CIL.
*/
*/
xlog_cil_insert_format_items
(
log
,
tp
,
&
len
,
&
diff_iovecs
);
xlog_cil_insert_format_items
(
log
,
tp
,
&
len
);
spin_lock
(
&
cil
->
xc_cil_lock
);
spin_lock
(
&
cil
->
xc_cil_lock
);
/* account for space used by new iovec headers */
iovhdr_res
=
diff_iovecs
*
sizeof
(
xlog_op_header_t
);
len
+=
iovhdr_res
;
ctx
->
nvecs
+=
diff_iovecs
;
/* attach the transaction to the CIL if it has any busy extents */
/* attach the transaction to the CIL if it has any busy extents */
if
(
!
list_empty
(
&
tp
->
t_busy
))
if
(
!
list_empty
(
&
tp
->
t_busy
))
list_splice_init
(
&
tp
->
t_busy
,
&
ctx
->
busy_extents
);
list_splice_init
(
&
tp
->
t_busy
,
&
ctx
->
busy_extents
);
...
@@ -822,7 +815,8 @@ xlog_cil_order_write(
...
@@ -822,7 +815,8 @@ xlog_cil_order_write(
static
int
static
int
xlog_cil_write_chain
(
xlog_cil_write_chain
(
struct
xfs_cil_ctx
*
ctx
,
struct
xfs_cil_ctx
*
ctx
,
struct
xfs_log_vec
*
chain
)
struct
xfs_log_vec
*
chain
,
uint32_t
chain_len
)
{
{
struct
xlog
*
log
=
ctx
->
cil
->
xc_log
;
struct
xlog
*
log
=
ctx
->
cil
->
xc_log
;
int
error
;
int
error
;
...
@@ -830,7 +824,7 @@ xlog_cil_write_chain(
...
@@ -830,7 +824,7 @@ xlog_cil_write_chain(
error
=
xlog_cil_order_write
(
ctx
->
cil
,
ctx
->
sequence
,
_START_RECORD
);
error
=
xlog_cil_order_write
(
ctx
->
cil
,
ctx
->
sequence
,
_START_RECORD
);
if
(
error
)
if
(
error
)
return
error
;
return
error
;
return
xlog_write
(
log
,
ctx
,
chain
,
ctx
->
ticket
,
XLOG_START_TRANS
);
return
xlog_write
(
log
,
ctx
,
chain
,
ctx
->
ticket
,
chain_len
);
}
}
/*
/*
...
@@ -844,9 +838,14 @@ xlog_cil_write_commit_record(
...
@@ -844,9 +838,14 @@ xlog_cil_write_commit_record(
struct
xfs_cil_ctx
*
ctx
)
struct
xfs_cil_ctx
*
ctx
)
{
{
struct
xlog
*
log
=
ctx
->
cil
->
xc_log
;
struct
xlog
*
log
=
ctx
->
cil
->
xc_log
;
struct
xlog_op_header
ophdr
=
{
.
oh_clientid
=
XFS_TRANSACTION
,
.
oh_tid
=
cpu_to_be32
(
ctx
->
ticket
->
t_tid
),
.
oh_flags
=
XLOG_COMMIT_TRANS
,
};
struct
xfs_log_iovec
reg
=
{
struct
xfs_log_iovec
reg
=
{
.
i_addr
=
NULL
,
.
i_addr
=
&
ophdr
,
.
i_len
=
0
,
.
i_len
=
sizeof
(
struct
xlog_op_header
)
,
.
i_type
=
XLOG_REG_TYPE_COMMIT
,
.
i_type
=
XLOG_REG_TYPE_COMMIT
,
};
};
struct
xfs_log_vec
vec
=
{
struct
xfs_log_vec
vec
=
{
...
@@ -862,12 +861,79 @@ xlog_cil_write_commit_record(
...
@@ -862,12 +861,79 @@ xlog_cil_write_commit_record(
if
(
error
)
if
(
error
)
return
error
;
return
error
;
error
=
xlog_write
(
log
,
ctx
,
&
vec
,
ctx
->
ticket
,
XLOG_COMMIT_TRANS
);
/* account for space used by record data */
ctx
->
ticket
->
t_curr_res
-=
reg
.
i_len
;
error
=
xlog_write
(
log
,
ctx
,
&
vec
,
ctx
->
ticket
,
reg
.
i_len
);
if
(
error
)
if
(
error
)
xlog_force_shutdown
(
log
,
SHUTDOWN_LOG_IO_ERROR
);
xlog_force_shutdown
(
log
,
SHUTDOWN_LOG_IO_ERROR
);
return
error
;
return
error
;
}
}
struct
xlog_cil_trans_hdr
{
struct
xlog_op_header
oph
[
2
];
struct
xfs_trans_header
thdr
;
struct
xfs_log_iovec
lhdr
[
2
];
};
/*
* Build a checkpoint transaction header to begin the journal transaction. We
* need to account for the space used by the transaction header here as it is
* not accounted for in xlog_write().
*
* This is the only place we write a transaction header, so we also build the
* log opheaders that indicate the start of a log transaction and wrap the
* transaction header. We keep the start record in it's own log vector rather
* than compacting them into a single region as this ends up making the logic
* in xlog_write() for handling empty opheaders for start, commit and unmount
* records much simpler.
*/
static
void
xlog_cil_build_trans_hdr
(
struct
xfs_cil_ctx
*
ctx
,
struct
xlog_cil_trans_hdr
*
hdr
,
struct
xfs_log_vec
*
lvhdr
,
int
num_iovecs
)
{
struct
xlog_ticket
*
tic
=
ctx
->
ticket
;
__be32
tid
=
cpu_to_be32
(
tic
->
t_tid
);
memset
(
hdr
,
0
,
sizeof
(
*
hdr
));
/* Log start record */
hdr
->
oph
[
0
].
oh_tid
=
tid
;
hdr
->
oph
[
0
].
oh_clientid
=
XFS_TRANSACTION
;
hdr
->
oph
[
0
].
oh_flags
=
XLOG_START_TRANS
;
/* log iovec region pointer */
hdr
->
lhdr
[
0
].
i_addr
=
&
hdr
->
oph
[
0
];
hdr
->
lhdr
[
0
].
i_len
=
sizeof
(
struct
xlog_op_header
);
hdr
->
lhdr
[
0
].
i_type
=
XLOG_REG_TYPE_LRHEADER
;
/* log opheader */
hdr
->
oph
[
1
].
oh_tid
=
tid
;
hdr
->
oph
[
1
].
oh_clientid
=
XFS_TRANSACTION
;
hdr
->
oph
[
1
].
oh_len
=
cpu_to_be32
(
sizeof
(
struct
xfs_trans_header
));
/* transaction header in host byte order format */
hdr
->
thdr
.
th_magic
=
XFS_TRANS_HEADER_MAGIC
;
hdr
->
thdr
.
th_type
=
XFS_TRANS_CHECKPOINT
;
hdr
->
thdr
.
th_tid
=
tic
->
t_tid
;
hdr
->
thdr
.
th_num_items
=
num_iovecs
;
/* log iovec region pointer */
hdr
->
lhdr
[
1
].
i_addr
=
&
hdr
->
oph
[
1
];
hdr
->
lhdr
[
1
].
i_len
=
sizeof
(
struct
xlog_op_header
)
+
sizeof
(
struct
xfs_trans_header
);
hdr
->
lhdr
[
1
].
i_type
=
XLOG_REG_TYPE_TRANSHDR
;
lvhdr
->
lv_niovecs
=
2
;
lvhdr
->
lv_iovecp
=
&
hdr
->
lhdr
[
0
];
lvhdr
->
lv_bytes
=
hdr
->
lhdr
[
0
].
i_len
+
hdr
->
lhdr
[
1
].
i_len
;
lvhdr
->
lv_next
=
ctx
->
lv_chain
;
tic
->
t_curr_res
-=
lvhdr
->
lv_bytes
;
}
/*
/*
* Push the Committed Item List to the log.
* Push the Committed Item List to the log.
*
*
...
@@ -892,11 +958,10 @@ xlog_cil_push_work(
...
@@ -892,11 +958,10 @@ xlog_cil_push_work(
struct
xlog
*
log
=
cil
->
xc_log
;
struct
xlog
*
log
=
cil
->
xc_log
;
struct
xfs_log_vec
*
lv
;
struct
xfs_log_vec
*
lv
;
struct
xfs_cil_ctx
*
new_ctx
;
struct
xfs_cil_ctx
*
new_ctx
;
struct
xlog_ticket
*
tic
;
int
num_iovecs
=
0
;
int
num_
iovecs
;
int
num_
bytes
=
0
;
int
error
=
0
;
int
error
=
0
;
struct
xfs_trans_header
thdr
;
struct
xlog_cil_trans_hdr
thdr
;
struct
xfs_log_iovec
lhdr
;
struct
xfs_log_vec
lvhdr
=
{
NULL
};
struct
xfs_log_vec
lvhdr
=
{
NULL
};
xfs_csn_t
push_seq
;
xfs_csn_t
push_seq
;
bool
push_commit_stable
;
bool
push_commit_stable
;
...
@@ -975,7 +1040,6 @@ xlog_cil_push_work(
...
@@ -975,7 +1040,6 @@ xlog_cil_push_work(
* by the flush lock.
* by the flush lock.
*/
*/
lv
=
NULL
;
lv
=
NULL
;
num_iovecs
=
0
;
while
(
!
list_empty
(
&
cil
->
xc_cil
))
{
while
(
!
list_empty
(
&
cil
->
xc_cil
))
{
struct
xfs_log_item
*
item
;
struct
xfs_log_item
*
item
;
...
@@ -989,6 +1053,10 @@ xlog_cil_push_work(
...
@@ -989,6 +1053,10 @@ xlog_cil_push_work(
lv
=
item
->
li_lv
;
lv
=
item
->
li_lv
;
item
->
li_lv
=
NULL
;
item
->
li_lv
=
NULL
;
num_iovecs
+=
lv
->
lv_niovecs
;
num_iovecs
+=
lv
->
lv_niovecs
;
/* we don't write ordered log vectors */
if
(
lv
->
lv_buf_len
!=
XFS_LOG_VEC_ORDERED
)
num_bytes
+=
lv
->
lv_bytes
;
}
}
/*
/*
...
@@ -1025,26 +1093,11 @@ xlog_cil_push_work(
...
@@ -1025,26 +1093,11 @@ xlog_cil_push_work(
* Build a checkpoint transaction header and write it to the log to
* Build a checkpoint transaction header and write it to the log to
* begin the transaction. We need to account for the space used by the
* begin the transaction. We need to account for the space used by the
* transaction header here as it is not accounted for in xlog_write().
* transaction header here as it is not accounted for in xlog_write().
*
*/
* The LSN we need to pass to the log items on transaction commit is
xlog_cil_build_trans_hdr
(
ctx
,
&
thdr
,
&
lvhdr
,
num_iovecs
);
* the LSN reported by the first log vector write. If we use the commit
num_bytes
+=
lvhdr
.
lv_bytes
;
* record lsn then we can move the tail beyond the grant write head.
*/
error
=
xlog_cil_write_chain
(
ctx
,
&
lvhdr
,
num_bytes
);
tic
=
ctx
->
ticket
;
thdr
.
th_magic
=
XFS_TRANS_HEADER_MAGIC
;
thdr
.
th_type
=
XFS_TRANS_CHECKPOINT
;
thdr
.
th_tid
=
tic
->
t_tid
;
thdr
.
th_num_items
=
num_iovecs
;
lhdr
.
i_addr
=
&
thdr
;
lhdr
.
i_len
=
sizeof
(
xfs_trans_header_t
);
lhdr
.
i_type
=
XLOG_REG_TYPE_TRANSHDR
;
tic
->
t_curr_res
-=
lhdr
.
i_len
+
sizeof
(
xlog_op_header_t
);
lvhdr
.
lv_niovecs
=
1
;
lvhdr
.
lv_iovecp
=
&
lhdr
;
lvhdr
.
lv_next
=
ctx
->
lv_chain
;
error
=
xlog_cil_write_chain
(
ctx
,
&
lvhdr
);
if
(
error
)
if
(
error
)
goto
out_abort_free_ticket
;
goto
out_abort_free_ticket
;
...
@@ -1052,7 +1105,7 @@ xlog_cil_push_work(
...
@@ -1052,7 +1105,7 @@ xlog_cil_push_work(
if
(
error
)
if
(
error
)
goto
out_abort_free_ticket
;
goto
out_abort_free_ticket
;
xfs_log_ticket_ungrant
(
log
,
tic
);
xfs_log_ticket_ungrant
(
log
,
ctx
->
ticket
);
/*
/*
* If the checkpoint spans multiple iclogs, wait for all previous iclogs
* If the checkpoint spans multiple iclogs, wait for all previous iclogs
...
@@ -1116,7 +1169,7 @@ xlog_cil_push_work(
...
@@ -1116,7 +1169,7 @@ xlog_cil_push_work(
return
;
return
;
out_abort_free_ticket:
out_abort_free_ticket:
xfs_log_ticket_ungrant
(
log
,
tic
);
xfs_log_ticket_ungrant
(
log
,
ctx
->
ticket
);
ASSERT
(
xlog_is_shutdown
(
log
));
ASSERT
(
xlog_is_shutdown
(
log
));
if
(
!
ctx
->
commit_iclog
)
{
if
(
!
ctx
->
commit_iclog
)
{
xlog_cil_committed
(
ctx
);
xlog_cil_committed
(
ctx
);
...
...
fs/xfs/xfs_log_priv.h
浏览文件 @
463260d7
...
@@ -142,19 +142,6 @@ enum xlog_iclog_state {
...
@@ -142,19 +142,6 @@ enum xlog_iclog_state {
#define XLOG_COVER_OPS 5
#define XLOG_COVER_OPS 5
/* Ticket reservation region accounting */
#define XLOG_TIC_LEN_MAX 15
/*
* Reservation region
* As would be stored in xfs_log_iovec but without the i_addr which
* we don't care about.
*/
typedef
struct
xlog_res
{
uint
r_len
;
/* region length :4 */
uint
r_type
;
/* region's transaction type :4 */
}
xlog_res_t
;
typedef
struct
xlog_ticket
{
typedef
struct
xlog_ticket
{
struct
list_head
t_queue
;
/* reserve/write queue */
struct
list_head
t_queue
;
/* reserve/write queue */
struct
task_struct
*
t_task
;
/* task that owns this ticket */
struct
task_struct
*
t_task
;
/* task that owns this ticket */
...
@@ -164,15 +151,7 @@ typedef struct xlog_ticket {
...
@@ -164,15 +151,7 @@ typedef struct xlog_ticket {
int
t_unit_res
;
/* unit reservation in bytes : 4 */
int
t_unit_res
;
/* unit reservation in bytes : 4 */
char
t_ocnt
;
/* original count : 1 */
char
t_ocnt
;
/* original count : 1 */
char
t_cnt
;
/* current count : 1 */
char
t_cnt
;
/* current count : 1 */
char
t_clientid
;
/* who does this belong to; : 1 */
uint8_t
t_flags
;
/* properties of reservation : 1 */
uint8_t
t_flags
;
/* properties of reservation : 1 */
/* reservation array fields */
uint
t_res_num
;
/* num in array : 4 */
uint
t_res_num_ophdrs
;
/* num op hdrs : 4 */
uint
t_res_arr_sum
;
/* array sum : 4 */
uint
t_res_o_flow
;
/* sum overflow : 4 */
xlog_res_t
t_res_arr
[
XLOG_TIC_LEN_MAX
];
/* array of res : 8 * 15 */
}
xlog_ticket_t
;
}
xlog_ticket_t
;
/*
/*
...
@@ -211,7 +190,7 @@ typedef struct xlog_in_core {
...
@@ -211,7 +190,7 @@ typedef struct xlog_in_core {
u32
ic_offset
;
u32
ic_offset
;
enum
xlog_iclog_state
ic_state
;
enum
xlog_iclog_state
ic_state
;
unsigned
int
ic_flags
;
unsigned
int
ic_flags
;
char
*
ic_datap
;
/* pointer to iclog data */
void
*
ic_datap
;
/* pointer to iclog data */
struct
list_head
ic_callbacks
;
struct
list_head
ic_callbacks
;
/* reference counts need their own cacheline */
/* reference counts need their own cacheline */
...
@@ -242,7 +221,6 @@ struct xfs_cil_ctx {
...
@@ -242,7 +221,6 @@ struct xfs_cil_ctx {
xfs_lsn_t
commit_lsn
;
/* chkpt commit record lsn */
xfs_lsn_t
commit_lsn
;
/* chkpt commit record lsn */
struct
xlog_in_core
*
commit_iclog
;
struct
xlog_in_core
*
commit_iclog
;
struct
xlog_ticket
*
ticket
;
/* chkpt ticket */
struct
xlog_ticket
*
ticket
;
/* chkpt ticket */
int
nvecs
;
/* number of regions */
int
space_used
;
/* aggregate size of regions */
int
space_used
;
/* aggregate size of regions */
struct
list_head
busy_extents
;
/* busy extents in chkpt */
struct
list_head
busy_extents
;
/* busy extents in chkpt */
struct
xfs_log_vec
*
lv_chain
;
/* logvecs being pushed */
struct
xfs_log_vec
*
lv_chain
;
/* logvecs being pushed */
...
@@ -441,10 +419,6 @@ struct xlog {
...
@@ -441,10 +419,6 @@ struct xlog {
struct
xfs_kobj
l_kobj
;
struct
xfs_kobj
l_kobj
;
/* The following field are used for debugging; need to hold icloglock */
#ifdef DEBUG
void
*
l_iclog_bak
[
XLOG_MAX_ICLOGS
];
#endif
/* log recovery lsn tracking (for buffer submission */
/* log recovery lsn tracking (for buffer submission */
xfs_lsn_t
l_recovery_lsn
;
xfs_lsn_t
l_recovery_lsn
;
...
@@ -509,27 +483,14 @@ extern __le32 xlog_cksum(struct xlog *log, struct xlog_rec_header *rhead,
...
@@ -509,27 +483,14 @@ extern __le32 xlog_cksum(struct xlog *log, struct xlog_rec_header *rhead,
char
*
dp
,
int
size
);
char
*
dp
,
int
size
);
extern
struct
kmem_cache
*
xfs_log_ticket_cache
;
extern
struct
kmem_cache
*
xfs_log_ticket_cache
;
struct
xlog_ticket
*
struct
xlog_ticket
*
xlog_ticket_alloc
(
struct
xlog
*
log
,
int
unit_bytes
,
xlog_ticket_alloc
(
int
count
,
bool
permanent
);
struct
xlog
*
log
,
int
unit_bytes
,
int
count
,
char
client
,
bool
permanent
);
static
inline
void
xlog_write_adv_cnt
(
void
**
ptr
,
int
*
len
,
int
*
off
,
size_t
bytes
)
{
*
ptr
+=
bytes
;
*
len
-=
bytes
;
*
off
+=
bytes
;
}
void
xlog_print_tic_res
(
struct
xfs_mount
*
mp
,
struct
xlog_ticket
*
ticket
);
void
xlog_print_tic_res
(
struct
xfs_mount
*
mp
,
struct
xlog_ticket
*
ticket
);
void
xlog_print_trans
(
struct
xfs_trans
*
);
void
xlog_print_trans
(
struct
xfs_trans
*
);
int
xlog_write
(
struct
xlog
*
log
,
struct
xfs_cil_ctx
*
ctx
,
int
xlog_write
(
struct
xlog
*
log
,
struct
xfs_cil_ctx
*
ctx
,
struct
xfs_log_vec
*
log_vector
,
struct
xlog_ticket
*
tic
,
struct
xfs_log_vec
*
log_vector
,
struct
xlog_ticket
*
tic
,
uint
optype
);
uint
32_t
len
);
void
xfs_log_ticket_ungrant
(
struct
xlog
*
log
,
struct
xlog_ticket
*
ticket
);
void
xfs_log_ticket_ungrant
(
struct
xlog
*
log
,
struct
xlog_ticket
*
ticket
);
void
xfs_log_ticket_regrant
(
struct
xlog
*
log
,
struct
xlog_ticket
*
ticket
);
void
xfs_log_ticket_regrant
(
struct
xlog
*
log
,
struct
xlog_ticket
*
ticket
);
...
...
fs/xfs/xfs_trans.c
浏览文件 @
463260d7
...
@@ -194,11 +194,9 @@ xfs_trans_reserve(
...
@@ -194,11 +194,9 @@ xfs_trans_reserve(
ASSERT
(
resp
->
tr_logflags
&
XFS_TRANS_PERM_LOG_RES
);
ASSERT
(
resp
->
tr_logflags
&
XFS_TRANS_PERM_LOG_RES
);
error
=
xfs_log_regrant
(
mp
,
tp
->
t_ticket
);
error
=
xfs_log_regrant
(
mp
,
tp
->
t_ticket
);
}
else
{
}
else
{
error
=
xfs_log_reserve
(
mp
,
error
=
xfs_log_reserve
(
mp
,
resp
->
tr_logres
,
resp
->
tr_logres
,
resp
->
tr_logcount
,
resp
->
tr_logcount
,
&
tp
->
t_ticket
,
XFS_TRANSACTION
,
&
tp
->
t_ticket
,
permanent
);
permanent
);
}
}
if
(
error
)
if
(
error
)
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录