Skip to content

Commit 8d547cf

Browse files
dgchinnerdchinner
authored andcommitted
xfs: reserve space and initialise xlog_op_header in item formatting
Current xlog_write() adds op headers to the log manually for every log item region that is in the vector passed to it. While xlog_write() needs to stamp the transaction ID into the ophdr, we already know it's length, flags, clientid, etc at CIL commit time. This means the only time that xlog write really needs to format and reserve space for a new ophdr is when a region is split across two iclogs. Adding the opheader and accounting for it as part of the normal formatted item region means we simplify the accounting of space used by a transaction and we don't have to special case reserving of space in for the ophdrs in xlog_write(). It also means we can largely initialise the ophdr in transaction commit instead of xlog_write, making the xlog_write formatting inner loop much tighter. xlog_prepare_iovec() is now too large to stay as an inline function, so we move it out of line and into xfs_log.c. Object sizes: text data bss dec hex filename 1125934 305951 484 1432369 15db31 fs/xfs/built-in.a.before 1123360 305951 484 1429795 15d123 fs/xfs/built-in.a.after So the code is a roughly 2.5kB smaller with xlog_prepare_iovec() now out of line, even though it grew in size itself. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Chandan Babu R <chandan.babu@oracle.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
1 parent 3c352be commit 8d547cf

3 files changed

Lines changed: 99 additions & 83 deletions

File tree

fs/xfs/xfs_log.c

Lines changed: 77 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,62 @@ xlog_iclogs_empty(
9090
static int
9191
xfs_log_cover(struct xfs_mount *);
9292

93+
/*
94+
* We need to make sure the buffer pointer returned is naturally aligned for the
95+
* biggest basic data type we put into it. We have already accounted for this
96+
* padding when sizing the buffer.
97+
*
98+
* However, this padding does not get written into the log, and hence we have to
99+
* track the space used by the log vectors separately to prevent log space hangs
100+
* due to inaccurate accounting (i.e. a leak) of the used log space through the
101+
* CIL context ticket.
102+
*
103+
* We also add space for the xlog_op_header that describes this region in the
104+
* log. This prepends the data region we return to the caller to copy their data
105+
* into, so do all the static initialisation of the ophdr now. Because the ophdr
106+
* is not 8 byte aligned, we have to be careful to ensure that we align the
107+
* start of the buffer such that the region we return to the call is 8 byte
108+
* aligned and packed against the tail of the ophdr.
109+
*/
110+
void *
111+
xlog_prepare_iovec(
112+
struct xfs_log_vec *lv,
113+
struct xfs_log_iovec **vecp,
114+
uint type)
115+
{
116+
struct xfs_log_iovec *vec = *vecp;
117+
struct xlog_op_header *oph;
118+
uint32_t len;
119+
void *buf;
120+
121+
if (vec) {
122+
ASSERT(vec - lv->lv_iovecp < lv->lv_niovecs);
123+
vec++;
124+
} else {
125+
vec = &lv->lv_iovecp[0];
126+
}
127+
128+
len = lv->lv_buf_len + sizeof(struct xlog_op_header);
129+
if (!IS_ALIGNED(len, sizeof(uint64_t))) {
130+
lv->lv_buf_len = round_up(len, sizeof(uint64_t)) -
131+
sizeof(struct xlog_op_header);
132+
}
133+
134+
vec->i_type = type;
135+
vec->i_addr = lv->lv_buf + lv->lv_buf_len;
136+
137+
oph = vec->i_addr;
138+
oph->oh_clientid = XFS_TRANSACTION;
139+
oph->oh_res2 = 0;
140+
oph->oh_flags = 0;
141+
142+
buf = vec->i_addr + sizeof(struct xlog_op_header);
143+
ASSERT(IS_ALIGNED((unsigned long)buf, sizeof(uint64_t)));
144+
145+
*vecp = vec;
146+
return buf;
147+
}
148+
93149
static void
94150
xlog_grant_sub_space(
95151
struct xlog *log,
@@ -2232,9 +2288,9 @@ xlog_print_trans(
22322288
}
22332289

22342290
/*
2235-
* Calculate the potential space needed by the log vector. If this is a start
2236-
* transaction, the caller has already accounted for both opheaders in the start
2237-
* transaction, so we don't need to account for them here.
2291+
* Calculate the potential space needed by the log vector. All regions contain
2292+
* their own opheaders and they are accounted for in region space so we don't
2293+
* need to add them to the vector length here.
22382294
*/
22392295
static int
22402296
xlog_write_calc_vec_length(
@@ -2261,18 +2317,7 @@ xlog_write_calc_vec_length(
22612317
xlog_tic_add_region(ticket, vecp->i_len, vecp->i_type);
22622318
}
22632319
}
2264-
2265-
/* Don't account for regions with embedded ophdrs */
2266-
if (optype && headers > 0) {
2267-
headers--;
2268-
if (optype & XLOG_START_TRANS) {
2269-
ASSERT(headers >= 1);
2270-
headers--;
2271-
}
2272-
}
2273-
22742320
ticket->t_res_num_ophdrs += headers;
2275-
len += headers * sizeof(struct xlog_op_header);
22762321

22772322
return len;
22782323
}
@@ -2282,7 +2327,6 @@ xlog_write_setup_ophdr(
22822327
struct xlog_op_header *ophdr,
22832328
struct xlog_ticket *ticket)
22842329
{
2285-
ophdr->oh_tid = cpu_to_be32(ticket->t_tid);
22862330
ophdr->oh_clientid = XFS_TRANSACTION;
22872331
ophdr->oh_res2 = 0;
22882332
ophdr->oh_flags = 0;
@@ -2500,21 +2544,25 @@ xlog_write(
25002544
ASSERT((unsigned long)ptr % sizeof(int32_t) == 0);
25012545

25022546
/*
2503-
* The XLOG_START_TRANS has embedded ophdrs for the
2504-
* start record and transaction header. They will always
2505-
* be the first two regions in the lv chain. Commit and
2506-
* unmount records also have embedded ophdrs.
2547+
* Regions always have their ophdr at the start of the
2548+
* region, except for:
2549+
* - a transaction start which has a start record ophdr
2550+
* before the first region ophdr; and
2551+
* - the previous region didn't fully fit into an iclog
2552+
* so needs a continuation ophdr to prepend the region
2553+
* in this new iclog.
25072554
*/
2508-
if (optype) {
2509-
ophdr = reg->i_addr;
2510-
if (index)
2511-
optype &= ~XLOG_START_TRANS;
2512-
} else {
2555+
ophdr = reg->i_addr;
2556+
if (optype && index) {
2557+
optype &= ~XLOG_START_TRANS;
2558+
} else if (partial_copy) {
25132559
ophdr = xlog_write_setup_ophdr(ptr, ticket);
25142560
xlog_write_adv_cnt(&ptr, &len, &log_offset,
25152561
sizeof(struct xlog_op_header));
25162562
added_ophdr = true;
25172563
}
2564+
ophdr->oh_tid = cpu_to_be32(ticket->t_tid);
2565+
25182566
len += xlog_write_setup_copy(ticket, ophdr,
25192567
iclog->ic_size-log_offset,
25202568
reg->i_len,
@@ -2532,20 +2580,11 @@ xlog_write(
25322580
ophdr->oh_len = cpu_to_be32(copy_len -
25332581
sizeof(struct xlog_op_header));
25342582
}
2535-
/*
2536-
* Copy region.
2537-
*
2538-
* Commit records just log an opheader, so
2539-
* we can have empty payloads with no data region to
2540-
* copy. Hence we only copy the payload if the vector
2541-
* says it has data to copy.
2542-
*/
2543-
ASSERT(copy_len >= 0);
2544-
if (copy_len > 0) {
2545-
memcpy(ptr, reg->i_addr + copy_off, copy_len);
2546-
xlog_write_adv_cnt(&ptr, &len, &log_offset,
2547-
copy_len);
2548-
}
2583+
2584+
ASSERT(copy_len > 0);
2585+
memcpy(ptr, reg->i_addr + copy_off, copy_len);
2586+
xlog_write_adv_cnt(&ptr, &len, &log_offset, copy_len);
2587+
25492588
if (added_ophdr)
25502589
copy_len += sizeof(struct xlog_op_header);
25512590
record_cnt++;

fs/xfs/xfs_log.h

Lines changed: 8 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -21,44 +21,18 @@ struct xfs_log_vec {
2121

2222
#define XFS_LOG_VEC_ORDERED (-1)
2323

24-
/*
25-
* We need to make sure the buffer pointer returned is naturally aligned for the
26-
* biggest basic data type we put into it. We have already accounted for this
27-
* padding when sizing the buffer.
28-
*
29-
* However, this padding does not get written into the log, and hence we have to
30-
* track the space used by the log vectors separately to prevent log space hangs
31-
* due to inaccurate accounting (i.e. a leak) of the used log space through the
32-
* CIL context ticket.
33-
*/
34-
static inline void *
35-
xlog_prepare_iovec(struct xfs_log_vec *lv, struct xfs_log_iovec **vecp,
36-
uint type)
37-
{
38-
struct xfs_log_iovec *vec = *vecp;
39-
40-
if (vec) {
41-
ASSERT(vec - lv->lv_iovecp < lv->lv_niovecs);
42-
vec++;
43-
} else {
44-
vec = &lv->lv_iovecp[0];
45-
}
46-
47-
if (!IS_ALIGNED(lv->lv_buf_len, sizeof(uint64_t)))
48-
lv->lv_buf_len = round_up(lv->lv_buf_len, sizeof(uint64_t));
49-
50-
vec->i_type = type;
51-
vec->i_addr = lv->lv_buf + lv->lv_buf_len;
52-
53-
ASSERT(IS_ALIGNED((unsigned long)vec->i_addr, sizeof(uint64_t)));
54-
55-
*vecp = vec;
56-
return vec->i_addr;
57-
}
24+
void *xlog_prepare_iovec(struct xfs_log_vec *lv, struct xfs_log_iovec **vecp,
25+
uint type);
5826

5927
static inline void
6028
xlog_finish_iovec(struct xfs_log_vec *lv, struct xfs_log_iovec *vec, int len)
6129
{
30+
struct xlog_op_header *oph = vec->i_addr;
31+
32+
/* opheader tracks payload length, logvec tracks region length */
33+
oph->oh_len = cpu_to_be32(len);
34+
35+
len += sizeof(struct xlog_op_header);
6236
lv->lv_buf_len += len;
6337
lv->lv_bytes += len;
6438
vec->i_len = len;

fs/xfs/xfs_log_cil.c

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -214,13 +214,20 @@ xlog_cil_alloc_shadow_bufs(
214214
}
215215

216216
/*
217-
* We 64-bit align the length of each iovec so that the start
218-
* of the next one is naturally aligned. We'll need to
219-
* account for that slack space here. Then round nbytes up
220-
* to 64-bit alignment so that the initial buffer alignment is
221-
* easy to calculate and verify.
217+
* We 64-bit align the length of each iovec so that the start of
218+
* the next one is naturally aligned. We'll need to account for
219+
* that slack space here.
220+
*
221+
* We also add the xlog_op_header to each region when
222+
* formatting, but that's not accounted to the size of the item
223+
* at this point. Hence we'll need an addition number of bytes
224+
* for each vector to hold an opheader.
225+
*
226+
* Then round nbytes up to 64-bit alignment so that the initial
227+
* buffer alignment is easy to calculate and verify.
222228
*/
223-
nbytes += niovecs * sizeof(uint64_t);
229+
nbytes += niovecs *
230+
(sizeof(uint64_t) + sizeof(struct xlog_op_header));
224231
nbytes = round_up(nbytes, sizeof(uint64_t));
225232

226233
/*
@@ -465,11 +472,6 @@ xlog_cil_insert_items(
465472

466473
spin_lock(&cil->xc_cil_lock);
467474

468-
/* account for space used by new iovec headers */
469-
iovhdr_res = diff_iovecs * sizeof(xlog_op_header_t);
470-
len += iovhdr_res;
471-
ctx->nvecs += diff_iovecs;
472-
473475
/* attach the transaction to the CIL if it has any busy extents */
474476
if (!list_empty(&tp->t_busy))
475477
list_splice_init(&tp->t_busy, &ctx->busy_extents);
@@ -501,6 +503,7 @@ xlog_cil_insert_items(
501503
}
502504
tp->t_ticket->t_curr_res -= len;
503505
ctx->space_used += len;
506+
ctx->nvecs += diff_iovecs;
504507

505508
/*
506509
* If we've overrun the reservation, dump the tx details before we move

0 commit comments

Comments
 (0)