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

Configure Feed

Select the types of activity you want to include in your feed.

netfs: Add a tracepoint to log the lifespan of folio_queue structs

Add a tracepoint to log the lifespan of folio_queue structs. For tracing
illustrative purposes, folio_queues are tagged with the debug ID of
whatever they're related to (typically a netfs_io_request) and a debug ID
of their own.

Signed-off-by: David Howells <dhowells@redhat.com>
Link: https://lore.kernel.org/r/20241216204124.3752367-5-dhowells@redhat.com
cc: Jeff Layton <jlayton@kernel.org>
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>

authored by

David Howells and committed by
Christian Brauner
aabcabf2 eb118159

+91 -28
+7 -3
fs/netfs/buffered_read.c
··· 131 131 struct folio_queue *tail = rreq->buffer_tail, *new; 132 132 size_t added; 133 133 134 - new = netfs_folioq_alloc(GFP_NOFS); 134 + new = netfs_folioq_alloc(rreq->debug_id, GFP_NOFS, 135 + netfs_trace_folioq_alloc_read_prep); 135 136 if (!new) 136 137 return -ENOMEM; 137 138 new->prev = tail; ··· 362 361 struct folio_batch put_batch; 363 362 size_t added; 364 363 365 - folioq = netfs_folioq_alloc(GFP_KERNEL); 364 + folioq = netfs_folioq_alloc(rreq->debug_id, GFP_KERNEL, 365 + netfs_trace_folioq_alloc_read_prime); 366 366 if (!folioq) 367 367 return -ENOMEM; 368 + 368 369 rreq->buffer = folioq; 369 370 rreq->buffer_tail = folioq; 370 371 rreq->submitted = rreq->start; ··· 439 436 { 440 437 struct folio_queue *folioq; 441 438 442 - folioq = netfs_folioq_alloc(GFP_KERNEL); 439 + folioq = netfs_folioq_alloc(rreq->debug_id, GFP_KERNEL, 440 + netfs_trace_folioq_alloc_read_sing); 443 441 if (!folioq) 444 442 return -ENOMEM; 445 443
+2 -1
fs/netfs/internal.h
··· 58 58 /* 59 59 * misc.c 60 60 */ 61 - struct folio_queue *netfs_buffer_make_space(struct netfs_io_request *rreq); 61 + struct folio_queue *netfs_buffer_make_space(struct netfs_io_request *rreq, 62 + enum netfs_folioq_trace trace); 62 63 int netfs_buffer_append_folio(struct netfs_io_request *rreq, struct folio *folio, 63 64 bool needs_put); 64 65 struct folio_queue *netfs_delete_buffer_head(struct netfs_io_request *wreq);
+20 -11
fs/netfs/misc.c
··· 10 10 11 11 /** 12 12 * netfs_folioq_alloc - Allocate a folio_queue struct 13 + * @rreq_id: Associated debugging ID for tracing purposes 13 14 * @gfp: Allocation constraints 15 + * @trace: Trace tag to indicate the purpose of the allocation 14 16 * 15 - * Allocate, initialise and account the folio_queue struct. 17 + * Allocate, initialise and account the folio_queue struct and log a trace line 18 + * to mark the allocation. 16 19 */ 17 - struct folio_queue *netfs_folioq_alloc(gfp_t gfp) 20 + struct folio_queue *netfs_folioq_alloc(unsigned int rreq_id, gfp_t gfp, 21 + unsigned int /*enum netfs_folioq_trace*/ trace) 18 22 { 23 + static atomic_t debug_ids; 19 24 struct folio_queue *fq; 20 25 21 26 fq = kmalloc(sizeof(*fq), gfp); 22 27 if (fq) { 23 28 netfs_stat(&netfs_n_folioq); 24 - folioq_init(fq); 29 + folioq_init(fq, rreq_id); 30 + fq->debug_id = atomic_inc_return(&debug_ids); 31 + trace_netfs_folioq(fq, trace); 25 32 } 26 33 return fq; 27 34 } ··· 37 30 /** 38 31 * netfs_folioq_free - Free a folio_queue struct 39 32 * @folioq: The object to free 33 + * @trace: Trace tag to indicate which free 40 34 * 41 35 * Free and unaccount the folio_queue struct. 42 36 */ 43 - void netfs_folioq_free(struct folio_queue *folioq) 37 + void netfs_folioq_free(struct folio_queue *folioq, 38 + unsigned int /*enum netfs_trace_folioq*/ trace) 44 39 { 40 + trace_netfs_folioq(folioq, trace); 45 41 netfs_stat_d(&netfs_n_folioq); 46 42 kfree(folioq); 47 43 } ··· 53 43 /* 54 44 * Make sure there's space in the rolling queue. 55 45 */ 56 - struct folio_queue *netfs_buffer_make_space(struct netfs_io_request *rreq) 46 + struct folio_queue *netfs_buffer_make_space(struct netfs_io_request *rreq, 47 + enum netfs_folioq_trace trace) 57 48 { 58 49 struct folio_queue *tail = rreq->buffer_tail, *prev; 59 50 unsigned int prev_nr_slots = 0; ··· 70 59 prev_nr_slots = folioq_nr_slots(tail); 71 60 } 72 61 73 - tail = kmalloc(sizeof(*tail), GFP_NOFS); 62 + tail = netfs_folioq_alloc(rreq->debug_id, GFP_NOFS, trace); 74 63 if (!tail) 75 64 return ERR_PTR(-ENOMEM); 76 - netfs_stat(&netfs_n_folioq); 77 - folioq_init(tail); 78 65 tail->prev = prev; 79 66 if (prev) 80 67 /* [!] NOTE: After we set prev->next, the consumer is entirely ··· 107 98 struct folio_queue *tail; 108 99 unsigned int slot, order = folio_order(folio); 109 100 110 - tail = netfs_buffer_make_space(rreq); 101 + tail = netfs_buffer_make_space(rreq, netfs_trace_folioq_alloc_append_folio); 111 102 if (IS_ERR(tail)) 112 103 return PTR_ERR(tail); 113 104 ··· 128 119 129 120 if (next) 130 121 next->prev = NULL; 131 - netfs_folioq_free(head); 122 + netfs_folioq_free(head, netfs_trace_folioq_delete); 132 123 wreq->buffer = next; 133 124 return next; 134 125 } ··· 151 142 folio_put(folio); 152 143 } 153 144 } 154 - netfs_folioq_free(p); 145 + netfs_folioq_free(p, netfs_trace_folioq_clear); 155 146 } 156 147 } 157 148
+6 -2
fs/netfs/read_collect.c
··· 103 103 subreq->transferred, subreq->len)) 104 104 subreq->transferred = subreq->len; 105 105 106 + trace_netfs_folioq(folioq, netfs_trace_folioq_read_progress); 106 107 next_folio: 107 108 fsize = PAGE_SIZE << subreq->curr_folio_order; 108 109 fpos = round_down(subreq->start + subreq->consumed, fsize); ··· 120 119 if (folioq) { 121 120 struct folio *folio = folioq_folio(folioq, slot); 122 121 123 - pr_err("folioq: orders=%02x%02x%02x%02x\n", 122 + pr_err("folioq: fq=%x orders=%02x%02x%02x%02x %px\n", 123 + folioq->debug_id, 124 124 folioq->orders[0], folioq->orders[1], 125 - folioq->orders[2], folioq->orders[3]); 125 + folioq->orders[2], folioq->orders[3], 126 + folioq); 126 127 if (folio) 127 128 pr_err("folio: %llx-%llx ix=%llx o=%u qo=%u\n", 128 129 fpos, fend - 1, folio_pos(folio), folio_order(folio), ··· 225 222 slot = 0; 226 223 folioq = folioq->next; 227 224 subreq->curr_folioq = folioq; 225 + trace_netfs_folioq(folioq, netfs_trace_folioq_read_progress); 228 226 } 229 227 subreq->curr_folioq_slot = slot; 230 228 if (folioq && folioq_folio(folioq, slot))
+1 -1
fs/netfs/write_issue.c
··· 161 161 */ 162 162 if (iov_iter_is_folioq(wreq_iter) && 163 163 wreq_iter->folioq_slot >= folioq_nr_slots(wreq_iter->folioq)) { 164 - netfs_buffer_make_space(wreq); 164 + netfs_buffer_make_space(wreq, netfs_trace_folioq_prep_write); 165 165 } 166 166 167 167 subreq = netfs_alloc_subrequest(wreq);
+1 -1
fs/smb/client/smb2ops.c
··· 4388 4388 p = kmalloc(sizeof(*p), GFP_NOFS); 4389 4389 if (!p) 4390 4390 goto nomem; 4391 - folioq_init(p); 4391 + folioq_init(p, 0); 4392 4392 if (tail) { 4393 4393 tail->next = p; 4394 4394 p->prev = tail;
+9 -3
include/linux/folio_queue.h
··· 37 37 #if PAGEVEC_SIZE > BITS_PER_LONG 38 38 #error marks is not big enough 39 39 #endif 40 + unsigned int rreq_id; 41 + unsigned int debug_id; 40 42 }; 41 43 42 44 /** 43 45 * folioq_init - Initialise a folio queue segment 44 46 * @folioq: The segment to initialise 47 + * @rreq_id: The request identifier to use in tracelines. 45 48 * 46 - * Initialise a folio queue segment. Note that the folio pointers are 47 - * left uninitialised. 49 + * Initialise a folio queue segment and set an identifier to be used in traces. 50 + * 51 + * Note that the folio pointers are left uninitialised. 48 52 */ 49 - static inline void folioq_init(struct folio_queue *folioq) 53 + static inline void folioq_init(struct folio_queue *folioq, unsigned int rreq_id) 50 54 { 51 55 folio_batch_init(&folioq->vec); 52 56 folioq->next = NULL; ··· 58 54 folioq->marks = 0; 59 55 folioq->marks2 = 0; 60 56 folioq->marks3 = 0; 57 + folioq->rreq_id = rreq_id; 58 + folioq->debug_id = 0; 61 59 } 62 60 63 61 /**
+4 -2
include/linux/netfs.h
··· 455 455 void netfs_end_io_direct(struct inode *inode); 456 456 457 457 /* Miscellaneous APIs. */ 458 - struct folio_queue *netfs_folioq_alloc(gfp_t gfp); 459 - void netfs_folioq_free(struct folio_queue *folioq); 458 + struct folio_queue *netfs_folioq_alloc(unsigned int rreq_id, gfp_t gfp, 459 + unsigned int trace /*enum netfs_folioq_trace*/); 460 + void netfs_folioq_free(struct folio_queue *folioq, 461 + unsigned int trace /*enum netfs_trace_folioq*/); 460 462 461 463 /** 462 464 * netfs_inode - Get the netfs inode context from the inode
+39 -2
include/trace/events/netfs.h
··· 191 191 EM(netfs_trace_donate_to_next, "to-next") \ 192 192 E_(netfs_trace_donate_to_deferred_next, "defer-next") 193 193 194 + #define netfs_folioq_traces \ 195 + EM(netfs_trace_folioq_alloc_append_folio, "alloc-apf") \ 196 + EM(netfs_trace_folioq_alloc_read_prep, "alloc-r-prep") \ 197 + EM(netfs_trace_folioq_alloc_read_prime, "alloc-r-prime") \ 198 + EM(netfs_trace_folioq_alloc_read_sing, "alloc-r-sing") \ 199 + EM(netfs_trace_folioq_clear, "clear") \ 200 + EM(netfs_trace_folioq_delete, "delete") \ 201 + EM(netfs_trace_folioq_prep_write, "prep-wr") \ 202 + E_(netfs_trace_folioq_read_progress, "r-progress") 203 + 194 204 #ifndef __NETFS_DECLARE_TRACE_ENUMS_ONCE_ONLY 195 205 #define __NETFS_DECLARE_TRACE_ENUMS_ONCE_ONLY 196 206 ··· 219 209 enum netfs_folio_trace { netfs_folio_traces } __mode(byte); 220 210 enum netfs_collect_contig_trace { netfs_collect_contig_traces } __mode(byte); 221 211 enum netfs_donate_trace { netfs_donate_traces } __mode(byte); 212 + enum netfs_folioq_trace { netfs_folioq_traces } __mode(byte); 222 213 223 214 #endif 224 215 ··· 243 232 netfs_folio_traces; 244 233 netfs_collect_contig_traces; 245 234 netfs_donate_traces; 235 + netfs_folioq_traces; 246 236 247 237 /* 248 238 * Now redefine the EM() and E_() macros to map the enums to the strings that ··· 329 317 __field(unsigned short, flags) 330 318 __field(enum netfs_io_source, source) 331 319 __field(enum netfs_sreq_trace, what) 320 + __field(u8, slot) 332 321 __field(size_t, len) 333 322 __field(size_t, transferred) 334 323 __field(loff_t, start) ··· 345 332 __entry->len = sreq->len; 346 333 __entry->transferred = sreq->transferred; 347 334 __entry->start = sreq->start; 335 + __entry->slot = sreq->curr_folioq_slot; 348 336 ), 349 337 350 - TP_printk("R=%08x[%x] %s %s f=%02x s=%llx %zx/%zx e=%d", 338 + TP_printk("R=%08x[%x] %s %s f=%02x s=%llx %zx/%zx s=%u e=%d", 351 339 __entry->rreq, __entry->index, 352 340 __print_symbolic(__entry->source, netfs_sreq_sources), 353 341 __print_symbolic(__entry->what, netfs_sreq_traces), 354 342 __entry->flags, 355 343 __entry->start, __entry->transferred, __entry->len, 356 - __entry->error) 344 + __entry->slot, __entry->error) 357 345 ); 358 346 359 347 TRACE_EVENT(netfs_failure, ··· 757 743 __entry->rreq, __entry->from, __entry->to, 758 744 __print_symbolic(__entry->trace, netfs_donate_traces), 759 745 __entry->amount) 746 + ); 747 + 748 + TRACE_EVENT(netfs_folioq, 749 + TP_PROTO(const struct folio_queue *fq, 750 + enum netfs_folioq_trace trace), 751 + 752 + TP_ARGS(fq, trace), 753 + 754 + TP_STRUCT__entry( 755 + __field(unsigned int, rreq) 756 + __field(unsigned int, id) 757 + __field(enum netfs_folioq_trace, trace) 758 + ), 759 + 760 + TP_fast_assign( 761 + __entry->rreq = fq ? fq->rreq_id : 0; 762 + __entry->id = fq ? fq->debug_id : 0; 763 + __entry->trace = trace; 764 + ), 765 + 766 + TP_printk("R=%08x fq=%x %s", 767 + __entry->rreq, __entry->id, 768 + __print_symbolic(__entry->trace, netfs_folioq_traces)) 760 769 ); 761 770 762 771 #undef EM
+2 -2
lib/kunit_iov_iter.c
··· 392 392 if (folioq_full(p)) { 393 393 p->next = kzalloc(sizeof(struct folio_queue), GFP_KERNEL); 394 394 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, p->next); 395 - folioq_init(p->next); 395 + folioq_init(p->next, 0); 396 396 p->next->prev = p; 397 397 p = p->next; 398 398 } ··· 409 409 folioq = kzalloc(sizeof(struct folio_queue), GFP_KERNEL); 410 410 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, folioq); 411 411 kunit_add_action_or_reset(test, iov_kunit_destroy_folioq, folioq); 412 - folioq_init(folioq); 412 + folioq_init(folioq, 0); 413 413 return folioq; 414 414 } 415 415