The rsrc_alloc debugfs reader writes rows directly to userspace without respecting the caller's read count. It also uses the current row length as the userspace stride, which can corrupt output when rows have different widths. Use seq_file to handle userspace buffer sizes, offsets, and partial reads. The LF list formatter is used both to determine the widest column and skip PF/VF rows with no resources, and to emit the final table. Let it measure the formatted length when no seq_file is supplied, and write directly to the seq_file during rendering. This preserves the pre-scan behavior while removing the temporary string buffers. Fixes: 23205e6d06d4 ("octeontx2-af: Dump current resource provisioning status") Assisted-by: LLM Codex Signed-off-by: Heyang Tan Changes in v3: - Format LF lists directly in the seq_file buffer and remove temporary buffers. - Measure, rather than emit, LF lists during width calculation and row scans. - Explain the two formatter modes in a code comment. - Preserve column alignment with seq_setwidth() and seq_pad(). - Reorder local declarations in reverse Christmas tree order. Link: https://lore.kernel.org/netdev/20260906141129.1730-1-thy15333007817@163.com/ --- .../marvell/octeontx2/af/rvu_debugfs.c | 114 +++++++++++------- 1 file changed, 69 insertions(+), 45 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c index fcbf4ba0e10a..1f177851e76d 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c @@ -646,10 +646,29 @@ static ssize_t rvu_dbg_lmtst_map_table_display(struct file *filp, RVU_DEBUG_FOPS(lmtst_map_table, lmtst_map_table_display, NULL); -static void get_lf_str_list(const struct rvu_block *block, int pcifunc, - char *lfs) +static int get_num_digits(int number) { - int lf = 0, seq = 0, len = 0, prev_lf = block->lf.max; + int width = 1; + + while (number >= 10) { + number /= 10; + width++; + } + + return width; +} + +/* + * Pre-scan callers need the formatted length to size columns and skip empty + * PF/VF rows. Passing NULL keeps those scans from emitting output before the + * final rendering pass. + */ +static int format_lf_str_list(struct seq_file *filp, + const struct rvu_block *block, int pcifunc) +{ + int prev_lf = block->lf.max; + int lf = 0, len = 0; + bool seq = false; for_each_set_bit(lf, block->lf.bmap, block->lf.max) { if (lf >= block->lf.max) @@ -664,32 +683,40 @@ static void get_lf_str_list(const struct rvu_block *block, int pcifunc, continue; } - if (seq) - len += sprintf(lfs + len, "-%d,%d", prev_lf, lf); - else - len += (len ? sprintf(lfs + len, ",%d", lf) : - sprintf(lfs + len, "%d", lf)); + if (seq) { + if (filp) + seq_printf(filp, "-%d,%d", prev_lf, lf); + len += get_num_digits(prev_lf) + get_num_digits(lf) + 2; + } else if (len) { + if (filp) + seq_printf(filp, ",%d", lf); + len += get_num_digits(lf) + 1; + } else { + if (filp) + seq_printf(filp, "%d", lf); + len += get_num_digits(lf); + } prev_lf = lf; - seq = 0; + seq = false; } - if (seq) - len += sprintf(lfs + len, "-%d", prev_lf); + if (seq) { + if (filp) + seq_printf(filp, "-%d", prev_lf); + len += get_num_digits(prev_lf) + 1; + } - lfs[len] = '\0'; + return len; } static int get_max_column_width(struct rvu *rvu) { - int index, pf, vf, lf_str_size = 12, buf_size = 256; struct rvu_block block; + int lf_str_size = 12; + int index, pf, vf; u16 pcifunc; - char *buf; - - buf = kzalloc(buf_size, GFP_KERNEL); - if (!buf) - return -ENOMEM; + int len; for (pf = 0; pf < rvu->hw->total_pfs; pf++) { for (vf = 0; vf <= rvu->hw->total_vfs; vf++) { @@ -702,39 +729,38 @@ static int get_max_column_width(struct rvu *rvu) if (!strlen(block.name)) continue; - get_lf_str_list(&block, pcifunc, buf); - if (lf_str_size <= strlen(buf)) - lf_str_size = strlen(buf) + 1; + len = format_lf_str_list(NULL, &block, pcifunc); + if (lf_str_size <= len) + lf_str_size = len + 1; } } } - kfree(buf); return lf_str_size; } /* Dumps current provisioning status of all RVU block LFs */ static int rvu_dbg_rsrc_attach_status(struct seq_file *filp, void *unused) { - int index, pf, vf, pcifunc; struct rvu *rvu = filp->private; + int index, pf, vf, pcifunc; struct rvu_block block; int lf_str_size; - char *lfs; + int len; lf_str_size = get_max_column_width(rvu); - if (lf_str_size < 0) - return lf_str_size; - lfs = kzalloc(lf_str_size, GFP_KERNEL); - if (!lfs) - return -ENOMEM; + seq_setwidth(filp, lf_str_size); + seq_puts(filp, "pcifunc"); + seq_pad(filp, ' '); + for (index = 0; index < BLK_COUNT; index++) { + if (!strlen(rvu->hw->block[index].name)) + continue; - seq_printf(filp, "%-*s", lf_str_size, "pcifunc"); - for (index = 0; index < BLK_COUNT; index++) - if (strlen(rvu->hw->block[index].name)) - seq_printf(filp, "%-*s", lf_str_size, - rvu->hw->block[index].name); + seq_setwidth(filp, lf_str_size); + seq_puts(filp, rvu->hw->block[index].name); + seq_pad(filp, ' '); + } seq_putc(filp, '\n'); for (pf = 0; pf < rvu->hw->total_pfs; pf++) { @@ -747,35 +773,33 @@ static int rvu_dbg_rsrc_attach_status(struct seq_file *filp, void *unused) block = rvu->hw->block[index]; if (!strlen(block.name)) continue; - lfs[0] = '\0'; - get_lf_str_list(&block, pcifunc, lfs); - if (strlen(lfs)) + len = format_lf_str_list(NULL, &block, pcifunc); + if (len) break; } if (index == BLK_COUNT) continue; + seq_setwidth(filp, lf_str_size); if (vf) - sprintf(lfs, "PF%d:VF%d", pf, vf - 1); + seq_printf(filp, "PF%d:VF%d", pf, vf - 1); else - sprintf(lfs, "PF%d", pf); - seq_printf(filp, "%-*s", lf_str_size, lfs); + seq_printf(filp, "PF%d", pf); + seq_pad(filp, ' '); for (index = 0; index < BLK_COUNT; index++) { block = rvu->hw->block[index]; if (!strlen(block.name)) continue; - lfs[0] = '\0'; - get_lf_str_list(&block, pcifunc, lfs); - seq_printf(filp, "%-*s", lf_str_size, lfs); + seq_setwidth(filp, lf_str_size); + format_lf_str_list(filp, &block, pcifunc); + seq_pad(filp, ' '); } seq_putc(filp, '\n'); } } - kfree(lfs); - return 0; } -- 2.34.1