Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

xfs: grant heads track byte counts, not LSNs

The grant heads in the log track the space reserved in the log for
running transactions. They do this by tracking how far ahead of the
tail that the reservation has reached, and the units for doing this
are {cycle,bytes} for the reserve head rather than {cycle,blocks}
which are normal used by LSNs.

This is annoyingly complex because we have to split, crack and
combined these tuples for any calculation we do to determine log
space and targets. This is computationally expensive as well as
difficult to do atomically and locklessly, as well as limiting the
size of the log to 2^32 bytes.

Really, though, all the grant heads are tracking is how much space
is currently available for use in the log. We can track this as a
simply byte count - we just don't care what the actual physical
location in the log the head and tail are at, just how much space we
have remaining before the head and tail overlap.

So, convert the grant heads to track the byte reservations that are
active rather than the current (cycle, offset) tuples. This means an
empty log has zero bytes consumed, and a full log is when the
reservations reach the size of the log minus the space consumed by
the AIL.

This greatly simplifies the accounting and checks for whether there
is space available. We no longer need to crack or combine LSNs to
determine how much space the log has left, nor do we need to look at
the head or tail of the log to determine how close to full we are.

There is, however, a complexity that needs to be handled. We know
how much space is being tracked in the AIL now via log->l_tail_space
and the log tickets track active reservations and return the unused
portions to the grant heads when ungranted. Unfortunately, we don't
track the used portion of the grant, so when we transfer log items
from the CIL to the AIL, the space accounted to the grant heads is
transferred to the log tail space. Hence when we move the AIL head
forwards on item insert, we have to remove that space from the grant
heads.

We also remove the xlog_verify_grant_tail() debug function as it is
no longer useful. The check it performs has been racy since delayed
logging was introduced, but now it is clearly only detecting false
positives so remove it.

The result of this substantially simpler accounting algorithm is an
increase in sustained transaction rate from ~1.3 million
transactions/s to ~1.9 million transactions/s with no increase in
CPU usage. We also remove the 32 bit space limitation on the grant
heads, which will allow us to increase the journal size beyond 2GB
in future.

Note that this renames the sysfs files exposing the log grant space
now that the values are exported in bytes. This allows xfstests
to auto-detect the old or new ABI.

[hch: move xlog_grant_sub_space out of line,
update the xlog_grant_{add,sub}_space prototypes,
rename the sysfs files to allow auto-detection in xfstests]

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Chandan Babu R <chandanbabu@kernel.org>

authored by

Dave Chinner and committed by
Chandan Babu R
c1220522 de302cea

+139 -239
+8 -10
Documentation/ABI/testing/sysfs-fs-xfs
··· 15 15 The log sequence number (LSN) of the current tail of the 16 16 log. The LSN is exported in "cycle:basic block" format. 17 17 18 - What: /sys/fs/xfs/<disk>/log/reserve_grant_head 19 - Date: July 2014 20 - KernelVersion: 3.17 18 + What: /sys/fs/xfs/<disk>/log/reserve_grant_head_bytes 19 + Date: June 2024 20 + KernelVersion: 6.11 21 21 Contact: linux-xfs@vger.kernel.org 22 22 Description: 23 23 The current state of the log reserve grant head. It 24 24 represents the total log reservation of all currently 25 - outstanding transactions. The grant head is exported in 26 - "cycle:bytes" format. 25 + outstanding transactions in bytes. 27 26 Users: xfstests 28 27 29 - What: /sys/fs/xfs/<disk>/log/write_grant_head 30 - Date: July 2014 31 - KernelVersion: 3.17 28 + What: /sys/fs/xfs/<disk>/log/write_grant_head_bytes 29 + Date: June 2024 30 + KernelVersion: 6.11 32 31 Contact: linux-xfs@vger.kernel.org 33 32 Description: 34 33 The current state of the log write grant head. It 35 34 represents the total log reservation of all currently 36 35 outstanding transactions, including regrants due to 37 - rolling transactions. The grant head is exported in 38 - "cycle:bytes" format. 36 + rolling transactions in bytes. 39 37 Users: xfstests
+89 -159
fs/xfs/xfs_log.c
··· 53 53 struct xlog_ticket *ticket); 54 54 #if defined(DEBUG) 55 55 STATIC void 56 - xlog_verify_grant_tail( 57 - struct xlog *log); 58 - STATIC void 59 56 xlog_verify_iclog( 60 57 struct xlog *log, 61 58 struct xlog_in_core *iclog, ··· 62 65 struct xlog *log, 63 66 struct xlog_in_core *iclog); 64 67 #else 65 - #define xlog_verify_grant_tail(a) 66 68 #define xlog_verify_iclog(a,b,c) 67 69 #define xlog_verify_tail_lsn(a,b) 68 70 #endif ··· 129 133 return buf; 130 134 } 131 135 132 - static void 136 + static inline void 133 137 xlog_grant_sub_space( 134 - struct xlog *log, 135 138 struct xlog_grant_head *head, 136 - int bytes) 139 + int64_t bytes) 137 140 { 138 - int64_t head_val = atomic64_read(&head->grant); 139 - int64_t new, old; 141 + atomic64_sub(bytes, &head->grant); 142 + } 140 143 141 - do { 142 - int cycle, space; 143 - 144 - xlog_crack_grant_head_val(head_val, &cycle, &space); 145 - 146 - space -= bytes; 147 - if (space < 0) { 148 - space += log->l_logsize; 149 - cycle--; 150 - } 151 - 152 - old = head_val; 153 - new = xlog_assign_grant_head_val(cycle, space); 154 - head_val = atomic64_cmpxchg(&head->grant, old, new); 155 - } while (head_val != old); 144 + static inline void 145 + xlog_grant_add_space( 146 + struct xlog_grant_head *head, 147 + int64_t bytes) 148 + { 149 + atomic64_add(bytes, &head->grant); 156 150 } 157 151 158 152 static void 159 - xlog_grant_add_space( 160 - struct xlog *log, 161 - struct xlog_grant_head *head, 162 - int bytes) 163 - { 164 - int64_t head_val = atomic64_read(&head->grant); 165 - int64_t new, old; 166 - 167 - do { 168 - int tmp; 169 - int cycle, space; 170 - 171 - xlog_crack_grant_head_val(head_val, &cycle, &space); 172 - 173 - tmp = log->l_logsize - space; 174 - if (tmp > bytes) 175 - space += bytes; 176 - else { 177 - space = bytes - tmp; 178 - cycle++; 179 - } 180 - 181 - old = head_val; 182 - new = xlog_assign_grant_head_val(cycle, space); 183 - head_val = atomic64_cmpxchg(&head->grant, old, new); 184 - } while (head_val != old); 185 - } 186 - 187 - STATIC void 188 153 xlog_grant_head_init( 189 154 struct xlog_grant_head *head) 190 155 { 191 - xlog_assign_grant_head(&head->grant, 1, 0); 156 + atomic64_set(&head->grant, 0); 192 157 INIT_LIST_HEAD(&head->waiters); 193 158 spin_lock_init(&head->lock); 194 159 } 195 160 161 + void 162 + xlog_grant_return_space( 163 + struct xlog *log, 164 + xfs_lsn_t old_head, 165 + xfs_lsn_t new_head) 166 + { 167 + int64_t diff = xlog_lsn_sub(log, new_head, old_head); 168 + 169 + xlog_grant_sub_space(&log->l_reserve_head, diff); 170 + xlog_grant_sub_space(&log->l_write_head, diff); 171 + } 172 + 196 173 /* 197 - * Return the space in the log between the tail and the head. The head 198 - * is passed in the cycle/bytes formal parms. In the special case where 199 - * the reserve head has wrapped passed the tail, this calculation is no 200 - * longer valid. In this case, just return 0 which means there is no space 201 - * in the log. This works for all places where this function is called 202 - * with the reserve head. Of course, if the write head were to ever 203 - * wrap the tail, we should blow up. Rather than catch this case here, 204 - * we depend on other ASSERTions in other parts of the code. XXXmiken 205 - * 206 - * If reservation head is behind the tail, we have a problem. Warn about it, 207 - * but then treat it as if the log is empty. 208 - * 209 - * If the log is shut down, the head and tail may be invalid or out of whack, so 210 - * shortcut invalidity asserts in this case so that we don't trigger them 211 - * falsely. 174 + * Return the space in the log between the tail and the head. In the case where 175 + * we have overrun available reservation space, return 0. The memory barrier 176 + * pairs with the smp_wmb() in xlog_cil_ail_insert() to ensure that grant head 177 + * vs tail space updates are seen in the correct order and hence avoid 178 + * transients as space is transferred from the grant heads to the AIL on commit 179 + * completion. 212 180 */ 213 - static int 181 + static uint64_t 214 182 xlog_grant_space_left( 215 183 struct xlog *log, 216 184 struct xlog_grant_head *head) 217 185 { 218 - int tail_bytes; 219 - int tail_cycle; 220 - int head_cycle; 221 - int head_bytes; 186 + int64_t free_bytes; 222 187 223 - xlog_crack_grant_head(&head->grant, &head_cycle, &head_bytes); 224 - xlog_crack_atomic_lsn(&log->l_tail_lsn, &tail_cycle, &tail_bytes); 225 - tail_bytes = BBTOB(tail_bytes); 226 - if (tail_cycle == head_cycle && head_bytes >= tail_bytes) 227 - return log->l_logsize - (head_bytes - tail_bytes); 228 - if (tail_cycle + 1 < head_cycle) 229 - return 0; 230 - 231 - /* Ignore potential inconsistency when shutdown. */ 232 - if (xlog_is_shutdown(log)) 233 - return log->l_logsize; 234 - 235 - if (tail_cycle < head_cycle) { 236 - ASSERT(tail_cycle == (head_cycle - 1)); 237 - return tail_bytes - head_bytes; 238 - } 239 - 240 - /* 241 - * The reservation head is behind the tail. In this case we just want to 242 - * return the size of the log as the amount of space left. 243 - */ 244 - xfs_alert(log->l_mp, "xlog_grant_space_left: head behind tail"); 245 - xfs_alert(log->l_mp, " tail_cycle = %d, tail_bytes = %d", 246 - tail_cycle, tail_bytes); 247 - xfs_alert(log->l_mp, " GH cycle = %d, GH bytes = %d", 248 - head_cycle, head_bytes); 249 - ASSERT(0); 250 - return log->l_logsize; 188 + smp_rmb(); /* paired with smp_wmb in xlog_cil_ail_insert() */ 189 + free_bytes = log->l_logsize - READ_ONCE(log->l_tail_space) - 190 + atomic64_read(&head->grant); 191 + if (free_bytes > 0) 192 + return free_bytes; 193 + return 0; 251 194 } 252 195 253 196 STATIC void ··· 388 453 if (error) 389 454 goto out_error; 390 455 391 - xlog_grant_add_space(log, &log->l_write_head, need_bytes); 456 + xlog_grant_add_space(&log->l_write_head, need_bytes); 392 457 trace_xfs_log_regrant_exit(log, tic); 393 - xlog_verify_grant_tail(log); 394 458 return 0; 395 459 396 460 out_error: ··· 438 504 if (error) 439 505 goto out_error; 440 506 441 - xlog_grant_add_space(log, &log->l_reserve_head, need_bytes); 442 - xlog_grant_add_space(log, &log->l_write_head, need_bytes); 507 + xlog_grant_add_space(&log->l_reserve_head, need_bytes); 508 + xlog_grant_add_space(&log->l_write_head, need_bytes); 443 509 trace_xfs_log_reserve_exit(log, tic); 444 - xlog_verify_grant_tail(log); 445 510 return 0; 446 511 447 512 out_error: ··· 1813 1880 if (ticket) { 1814 1881 ticket->t_curr_res -= roundoff; 1815 1882 } else { 1816 - xlog_grant_add_space(log, &log->l_reserve_head, roundoff); 1817 - xlog_grant_add_space(log, &log->l_write_head, roundoff); 1883 + xlog_grant_add_space(&log->l_reserve_head, roundoff); 1884 + xlog_grant_add_space(&log->l_write_head, roundoff); 1818 1885 } 1819 1886 1820 1887 /* put cycle number in every block */ ··· 2734 2801 if (ticket->t_cnt > 0) 2735 2802 ticket->t_cnt--; 2736 2803 2737 - xlog_grant_sub_space(log, &log->l_reserve_head, ticket->t_curr_res); 2738 - xlog_grant_sub_space(log, &log->l_write_head, ticket->t_curr_res); 2804 + xlog_grant_sub_space(&log->l_reserve_head, ticket->t_curr_res); 2805 + xlog_grant_sub_space(&log->l_write_head, ticket->t_curr_res); 2739 2806 ticket->t_curr_res = ticket->t_unit_res; 2740 2807 2741 2808 trace_xfs_log_ticket_regrant_sub(log, ticket); 2742 2809 2743 2810 /* just return if we still have some of the pre-reserved space */ 2744 2811 if (!ticket->t_cnt) { 2745 - xlog_grant_add_space(log, &log->l_reserve_head, 2746 - ticket->t_unit_res); 2812 + xlog_grant_add_space(&log->l_reserve_head, ticket->t_unit_res); 2747 2813 trace_xfs_log_ticket_regrant_exit(log, ticket); 2748 2814 2749 2815 ticket->t_curr_res = ticket->t_unit_res; ··· 2789 2857 bytes += ticket->t_unit_res*ticket->t_cnt; 2790 2858 } 2791 2859 2792 - xlog_grant_sub_space(log, &log->l_reserve_head, bytes); 2793 - xlog_grant_sub_space(log, &log->l_write_head, bytes); 2860 + xlog_grant_sub_space(&log->l_reserve_head, bytes); 2861 + xlog_grant_sub_space(&log->l_write_head, bytes); 2794 2862 2795 2863 trace_xfs_log_ticket_ungrant_exit(log, ticket); 2796 2864 ··· 3263 3331 } 3264 3332 3265 3333 #if defined(DEBUG) 3266 - /* 3267 - * Check to make sure the grant write head didn't just over lap the tail. If 3268 - * the cycles are the same, we can't be overlapping. Otherwise, make sure that 3269 - * the cycles differ by exactly one and check the byte count. 3270 - * 3271 - * This check is run unlocked, so can give false positives. Rather than assert 3272 - * on failures, use a warn-once flag and a panic tag to allow the admin to 3273 - * determine if they want to panic the machine when such an error occurs. For 3274 - * debug kernels this will have the same effect as using an assert but, unlinke 3275 - * an assert, it can be turned off at runtime. 3276 - */ 3277 - STATIC void 3278 - xlog_verify_grant_tail( 3279 - struct xlog *log) 3334 + static void 3335 + xlog_verify_dump_tail( 3336 + struct xlog *log, 3337 + struct xlog_in_core *iclog) 3280 3338 { 3281 - int tail_cycle, tail_blocks; 3282 - int cycle, space; 3283 - 3284 - xlog_crack_grant_head(&log->l_write_head.grant, &cycle, &space); 3285 - xlog_crack_atomic_lsn(&log->l_tail_lsn, &tail_cycle, &tail_blocks); 3286 - if (tail_cycle != cycle) { 3287 - if (cycle - 1 != tail_cycle && 3288 - !test_and_set_bit(XLOG_TAIL_WARN, &log->l_opstate)) { 3289 - xfs_alert_tag(log->l_mp, XFS_PTAG_LOGRES, 3290 - "%s: cycle - 1 != tail_cycle", __func__); 3291 - } 3292 - 3293 - if (space > BBTOB(tail_blocks) && 3294 - !test_and_set_bit(XLOG_TAIL_WARN, &log->l_opstate)) { 3295 - xfs_alert_tag(log->l_mp, XFS_PTAG_LOGRES, 3296 - "%s: space > BBTOB(tail_blocks)", __func__); 3297 - } 3298 - } 3339 + xfs_alert(log->l_mp, 3340 + "ran out of log space tail 0x%llx/0x%llx, head lsn 0x%llx, head 0x%x/0x%x, prev head 0x%x/0x%x", 3341 + iclog ? be64_to_cpu(iclog->ic_header.h_tail_lsn) : -1, 3342 + atomic64_read(&log->l_tail_lsn), 3343 + log->l_ailp->ail_head_lsn, 3344 + log->l_curr_cycle, log->l_curr_block, 3345 + log->l_prev_cycle, log->l_prev_block); 3346 + xfs_alert(log->l_mp, 3347 + "write grant 0x%llx, reserve grant 0x%llx, tail_space 0x%llx, size 0x%x, iclog flags 0x%x", 3348 + atomic64_read(&log->l_write_head.grant), 3349 + atomic64_read(&log->l_reserve_head.grant), 3350 + log->l_tail_space, log->l_logsize, 3351 + iclog ? iclog->ic_flags : -1); 3299 3352 } 3300 3353 3301 - /* check if it will fit */ 3354 + /* Check if the new iclog will fit in the log. */ 3302 3355 STATIC void 3303 3356 xlog_verify_tail_lsn( 3304 3357 struct xlog *log, ··· 3292 3375 xfs_lsn_t tail_lsn = be64_to_cpu(iclog->ic_header.h_tail_lsn); 3293 3376 int blocks; 3294 3377 3295 - if (CYCLE_LSN(tail_lsn) == log->l_prev_cycle) { 3296 - blocks = 3297 - log->l_logBBsize - (log->l_prev_block - BLOCK_LSN(tail_lsn)); 3298 - if (blocks < BTOBB(iclog->ic_offset)+BTOBB(log->l_iclog_hsize)) 3299 - xfs_emerg(log->l_mp, "%s: ran out of log space", __func__); 3300 - } else { 3301 - ASSERT(CYCLE_LSN(tail_lsn)+1 == log->l_prev_cycle); 3378 + if (CYCLE_LSN(tail_lsn) == log->l_prev_cycle) { 3379 + blocks = log->l_logBBsize - 3380 + (log->l_prev_block - BLOCK_LSN(tail_lsn)); 3381 + if (blocks < BTOBB(iclog->ic_offset) + 3382 + BTOBB(log->l_iclog_hsize)) { 3383 + xfs_emerg(log->l_mp, 3384 + "%s: ran out of log space", __func__); 3385 + xlog_verify_dump_tail(log, iclog); 3386 + } 3387 + return; 3388 + } 3302 3389 3303 - if (BLOCK_LSN(tail_lsn) == log->l_prev_block) 3390 + if (CYCLE_LSN(tail_lsn) + 1 != log->l_prev_cycle) { 3391 + xfs_emerg(log->l_mp, "%s: head has wrapped tail.", __func__); 3392 + xlog_verify_dump_tail(log, iclog); 3393 + return; 3394 + } 3395 + if (BLOCK_LSN(tail_lsn) == log->l_prev_block) { 3304 3396 xfs_emerg(log->l_mp, "%s: tail wrapped", __func__); 3397 + xlog_verify_dump_tail(log, iclog); 3398 + return; 3399 + } 3305 3400 3306 3401 blocks = BLOCK_LSN(tail_lsn) - log->l_prev_block; 3307 - if (blocks < BTOBB(iclog->ic_offset) + 1) 3308 - xfs_emerg(log->l_mp, "%s: ran out of log space", __func__); 3309 - } 3402 + if (blocks < BTOBB(iclog->ic_offset) + 1) { 3403 + xfs_emerg(log->l_mp, "%s: ran out of iclog space", __func__); 3404 + xlog_verify_dump_tail(log, iclog); 3405 + } 3310 3406 } 3311 3407 3312 3408 /*
+12
fs/xfs/xfs_log_cil.c
··· 764 764 struct xfs_log_item *log_items[LOG_ITEM_BATCH_SIZE]; 765 765 struct xfs_log_vec *lv; 766 766 struct xfs_ail_cursor cur; 767 + xfs_lsn_t old_head; 767 768 int i = 0; 768 769 769 770 /* ··· 781 780 aborted); 782 781 spin_lock(&ailp->ail_lock); 783 782 xfs_trans_ail_cursor_last(ailp, &cur, ctx->start_lsn); 783 + old_head = ailp->ail_head_lsn; 784 784 ailp->ail_head_lsn = ctx->commit_lsn; 785 785 /* xfs_ail_update_finish() drops the ail_lock */ 786 786 xfs_ail_update_finish(ailp, NULLCOMMITLSN); 787 + 788 + /* 789 + * We move the AIL head forwards to account for the space used in the 790 + * log before we remove that space from the grant heads. This prevents a 791 + * transient condition where reservation space appears to become 792 + * available on return, only for it to disappear again immediately as 793 + * the AIL head update accounts in the log tail space. 794 + */ 795 + smp_wmb(); /* paired with smp_rmb in xlog_grant_space_left */ 796 + xlog_grant_return_space(ailp->ail_log, old_head, ailp->ail_head_lsn); 787 797 788 798 /* unpin all the log items */ 789 799 list_for_each_entry(lv, &ctx->lv_chain, lv_list) {
+3 -30
fs/xfs/xfs_log_priv.h
··· 544 544 } 545 545 546 546 /* 547 - * When we crack the grant head, we sample it first so that the value will not 548 - * change while we are cracking it into the component values. This means we 549 - * will always get consistent component values to work from. 550 - */ 551 - static inline void 552 - xlog_crack_grant_head_val(int64_t val, int *cycle, int *space) 553 - { 554 - *cycle = val >> 32; 555 - *space = val & 0xffffffff; 556 - } 557 - 558 - static inline void 559 - xlog_crack_grant_head(atomic64_t *head, int *cycle, int *space) 560 - { 561 - xlog_crack_grant_head_val(atomic64_read(head), cycle, space); 562 - } 563 - 564 - static inline int64_t 565 - xlog_assign_grant_head_val(int cycle, int space) 566 - { 567 - return ((int64_t)cycle << 32) | space; 568 - } 569 - 570 - static inline void 571 - xlog_assign_grant_head(atomic64_t *head, int cycle, int space) 572 - { 573 - atomic64_set(head, xlog_assign_grant_head_val(cycle, space)); 574 - } 575 - 576 - /* 577 547 * Committed Item List interfaces 578 548 */ 579 549 int xlog_cil_init(struct xlog *log); ··· 608 638 ASSERT((hi_cycle == lo_cycle + 1) || xlog_is_shutdown(log)); 609 639 return (uint64_t)log->l_logsize - BBTOB(lo_block - hi_block); 610 640 } 641 + 642 + void xlog_grant_return_space(struct xlog *log, xfs_lsn_t old_head, 643 + xfs_lsn_t new_head); 611 644 612 645 /* 613 646 * The LSN is valid so long as it is behind the current LSN. If it isn't, this
-4
fs/xfs/xfs_log_recover.c
··· 1213 1213 log->l_curr_cycle++; 1214 1214 atomic64_set(&log->l_tail_lsn, be64_to_cpu(rhead->h_tail_lsn)); 1215 1215 log->l_ailp->ail_head_lsn = be64_to_cpu(rhead->h_lsn); 1216 - xlog_assign_grant_head(&log->l_reserve_head.grant, log->l_curr_cycle, 1217 - BBTOB(log->l_curr_block)); 1218 - xlog_assign_grant_head(&log->l_write_head.grant, log->l_curr_cycle, 1219 - BBTOB(log->l_curr_block)); 1220 1216 } 1221 1217 1222 1218 /*
+10 -19
fs/xfs/xfs_sysfs.c
··· 432 432 XFS_SYSFS_ATTR_RO(log_tail_lsn); 433 433 434 434 STATIC ssize_t 435 - reserve_grant_head_show( 435 + reserve_grant_head_bytes_show( 436 436 struct kobject *kobject, 437 437 char *buf) 438 - 439 438 { 440 - int cycle; 441 - int bytes; 442 - struct xlog *log = to_xlog(kobject); 443 - 444 - xlog_crack_grant_head(&log->l_reserve_head.grant, &cycle, &bytes); 445 - return sysfs_emit(buf, "%d:%d\n", cycle, bytes); 439 + return sysfs_emit(buf, "%lld\n", 440 + atomic64_read(&to_xlog(kobject)->l_reserve_head.grant)); 446 441 } 447 - XFS_SYSFS_ATTR_RO(reserve_grant_head); 442 + XFS_SYSFS_ATTR_RO(reserve_grant_head_bytes); 448 443 449 444 STATIC ssize_t 450 - write_grant_head_show( 445 + write_grant_head_bytes_show( 451 446 struct kobject *kobject, 452 447 char *buf) 453 448 { 454 - int cycle; 455 - int bytes; 456 - struct xlog *log = to_xlog(kobject); 457 - 458 - xlog_crack_grant_head(&log->l_write_head.grant, &cycle, &bytes); 459 - return sysfs_emit(buf, "%d:%d\n", cycle, bytes); 449 + return sysfs_emit(buf, "%lld\n", 450 + atomic64_read(&to_xlog(kobject)->l_write_head.grant)); 460 451 } 461 - XFS_SYSFS_ATTR_RO(write_grant_head); 452 + XFS_SYSFS_ATTR_RO(write_grant_head_bytes); 462 453 463 454 static struct attribute *xfs_log_attrs[] = { 464 455 ATTR_LIST(log_head_lsn), 465 456 ATTR_LIST(log_tail_lsn), 466 - ATTR_LIST(reserve_grant_head), 467 - ATTR_LIST(write_grant_head), 457 + ATTR_LIST(reserve_grant_head_bytes), 458 + ATTR_LIST(write_grant_head_bytes), 468 459 NULL, 469 460 }; 470 461 ATTRIBUTE_GROUPS(xfs_log);
+17 -17
fs/xfs/xfs_trace.h
··· 1230 1230 TP_ARGS(log, tic), 1231 1231 TP_STRUCT__entry( 1232 1232 __field(dev_t, dev) 1233 + __field(unsigned long, tic) 1233 1234 __field(char, ocnt) 1234 1235 __field(char, cnt) 1235 1236 __field(int, curr_res) ··· 1238 1237 __field(unsigned int, flags) 1239 1238 __field(int, reserveq) 1240 1239 __field(int, writeq) 1241 - __field(int, grant_reserve_cycle) 1242 - __field(int, grant_reserve_bytes) 1243 - __field(int, grant_write_cycle) 1244 - __field(int, grant_write_bytes) 1240 + __field(uint64_t, grant_reserve_bytes) 1241 + __field(uint64_t, grant_write_bytes) 1242 + __field(uint64_t, tail_space) 1245 1243 __field(int, curr_cycle) 1246 1244 __field(int, curr_block) 1247 1245 __field(xfs_lsn_t, tail_lsn) 1248 1246 ), 1249 1247 TP_fast_assign( 1250 1248 __entry->dev = log->l_mp->m_super->s_dev; 1249 + __entry->tic = (unsigned long)tic; 1251 1250 __entry->ocnt = tic->t_ocnt; 1252 1251 __entry->cnt = tic->t_cnt; 1253 1252 __entry->curr_res = tic->t_curr_res; ··· 1255 1254 __entry->flags = tic->t_flags; 1256 1255 __entry->reserveq = list_empty(&log->l_reserve_head.waiters); 1257 1256 __entry->writeq = list_empty(&log->l_write_head.waiters); 1258 - xlog_crack_grant_head(&log->l_reserve_head.grant, 1259 - &__entry->grant_reserve_cycle, 1260 - &__entry->grant_reserve_bytes); 1261 - xlog_crack_grant_head(&log->l_write_head.grant, 1262 - &__entry->grant_write_cycle, 1263 - &__entry->grant_write_bytes); 1257 + __entry->tail_space = READ_ONCE(log->l_tail_space); 1258 + __entry->grant_reserve_bytes = __entry->tail_space + 1259 + atomic64_read(&log->l_reserve_head.grant); 1260 + __entry->grant_write_bytes = __entry->tail_space + 1261 + atomic64_read(&log->l_write_head.grant); 1264 1262 __entry->curr_cycle = log->l_curr_cycle; 1265 1263 __entry->curr_block = log->l_curr_block; 1266 1264 __entry->tail_lsn = atomic64_read(&log->l_tail_lsn); 1267 1265 ), 1268 - TP_printk("dev %d:%d t_ocnt %u t_cnt %u t_curr_res %u " 1269 - "t_unit_res %u t_flags %s reserveq %s " 1270 - "writeq %s grant_reserve_cycle %d " 1271 - "grant_reserve_bytes %d grant_write_cycle %d " 1272 - "grant_write_bytes %d curr_cycle %d curr_block %d " 1266 + TP_printk("dev %d:%d tic 0x%lx t_ocnt %u t_cnt %u t_curr_res %u " 1267 + "t_unit_res %u t_flags %s reserveq %s writeq %s " 1268 + "tail space %llu grant_reserve_bytes %llu " 1269 + "grant_write_bytes %llu curr_cycle %d curr_block %d " 1273 1270 "tail_cycle %d tail_block %d", 1274 1271 MAJOR(__entry->dev), MINOR(__entry->dev), 1272 + __entry->tic, 1275 1273 __entry->ocnt, 1276 1274 __entry->cnt, 1277 1275 __entry->curr_res, ··· 1278 1278 __print_flags(__entry->flags, "|", XLOG_TIC_FLAGS), 1279 1279 __entry->reserveq ? "empty" : "active", 1280 1280 __entry->writeq ? "empty" : "active", 1281 - __entry->grant_reserve_cycle, 1281 + __entry->tail_space, 1282 1282 __entry->grant_reserve_bytes, 1283 - __entry->grant_write_cycle, 1284 1283 __entry->grant_write_bytes, 1285 1284 __entry->curr_cycle, 1286 1285 __entry->curr_block, ··· 1307 1308 DEFINE_LOGGRANT_EVENT(xfs_log_ticket_ungrant_sub); 1308 1309 DEFINE_LOGGRANT_EVENT(xfs_log_ticket_ungrant_exit); 1309 1310 DEFINE_LOGGRANT_EVENT(xfs_log_cil_wait); 1311 + DEFINE_LOGGRANT_EVENT(xfs_log_cil_return); 1310 1312 1311 1313 DECLARE_EVENT_CLASS(xfs_log_item_class, 1312 1314 TP_PROTO(struct xfs_log_item *lip),