[PATCH v3 0/2] f2fs: pack same-inode blocks by inode during FG_GC

Daejun Park posted 2 patches 1 week, 2 days ago
Only 1 patches received!
Documentation/ABI/testing/sysfs-fs-f2fs |  20 ++
fs/f2fs/f2fs.h                          |   9 +-
fs/f2fs/gc.c                            | 302 +++++++++++++++++++-----
fs/f2fs/gc.h                            |   5 +
fs/f2fs/super.c                         |   2 +
fs/f2fs/sysfs.c                         |  16 ++
6 files changed, 297 insertions(+), 57 deletions(-)
[PATCH v3 0/2] f2fs: pack same-inode blocks by inode during FG_GC
Posted by Daejun Park 1 week, 2 days ago
Hi,

FG_GC migrates a victim section's valid blocks in source segment-offset
order, so blocks from several inodes stay interleaved in the destination
curseg and post-GC files stay fragmented.  This series migrates them in
inode order instead, producing inode-contiguous runs across the section.

Patch 1 is a pure refactor (extract do_migrate_one_data_block()).
Patch 2 records each valid block on a per-inode list in phase 3 and
drains it in inode order via pack_gc_section() once the section has been
scanned.  It is gated on a sysfs knob (gc_inode_local_packing) and FG_GC
only; on slab alloc failure a block falls back to immediate migration.

Changes since v2 (all in patch 2; the first three address Chao Yu's
review):
  - default gc_inode_local_packing to 0: the feature is now opt-in
    rather than enabled on large sections, since a new GC behaviour
    should not be on by default.
  - drop the section's queued gc_blocks on the freezing 'goto stop' path
    (new drop_gc_blocks() helper).  f2fs_gc() reuses one gc_list across
    the sections it collects in a single call, so leftover records could
    otherwise leak into the next section's pack pass.
  - expose the packing-queue drain threshold as a sysfs knob
    gc_pack_max_blocks (default 4096, minimum 64) instead of a fixed
    constant.  The ABI doc describes it as a drain threshold checked at
    segment boundaries, since the queue can transiently overshoot the
    value by up to one segment's blocks.
  - pack_gc_section() skips a queued block invalidated since phase 3
    (check_valid_map), matching the legacy phase-4 skip, so a stale block
    is neither migrated nor stat-counted.
  - queued records are freed in one place: pack_gc_section() and
    put_gc_inode() release them via drop_gc_blocks() instead of three
    copies of the same walk, and the normal-completion pack_gc_section()
    call is guarded by nr_gc_blocks so a queue already emptied by an
    early drain does not trigger a useless walk of the inode list.
  - gc_inode_local_packing's sysfs store assigns the bool directly
    (!!t), like iostat_enable/readdir_ra, instead of falling through to
    the generic unsigned-int write over a bool field.
  - drop the '+45 %' hot-rewrite iteration figure from patch 2's
    measurements: it is a wall-clock number and QEMU virtio
    bandwidth/latency is not reliable; the structural counters stand.
  - patch 1: unchanged.

Rebased onto current f2fs/dev (now includes "f2fs: embed f2fs_gc_kthread
in f2fs_sb_info"); no code change, the diff is identical to the c0b65f612
base it was developed on.

The seg_freed recompute Chao asked about is unchanged from v2: it runs
after the pack pass on all exit paths and counts already-empty segments
exactly as the legacy 'goto freed' path does (required so a fully
reclaimed section reaches seg_freed == f2fs_usable_segs_in_sec();
excluding them would re-introduce the -EAGAIN this series fixes).  Any
already-empty segment it counts feeds only the total_freed tracepoint,
not the sec_freed/-EAGAIN decision.

Changes since v1:
  - patch 2: fix seg_freed accounting (recompute after the deferred pack
    pass); without it a sync F2FS_IOC_GC returned -EAGAIN despite freeing
    space.  Clear next_victim_seg on the freezing path; bound the packing
    queue and drain in batches.  Rebased onto f2fs/dev.

Results (QEMU guest):
  - large section (-s 32, 64 x 4 MiB): post-GC extents 65536 -> 49170
    (-24 %).
  - natural FG_GC, 90 % full, 300 s hot/cold rewrite: cold-file extents
    -63 %, move_blks -18 %, skipped_gc_rwsem -59 %.
  - seg_freed regression test: packing matches the legacy path
    (seg_freed 152, sec_freed 38, 24/24 sync ioctls succeed).
  - gc_pack_max_blocks partial-drain test (cap=64, large section): the
    drain fires ~1.5k times in one section yet seg_freed still matches
    the legacy path (384 == 384), integrity preserved.
  - regression suite on this tree: clean dmesg, sha256 preserved;
    gc_pack_max_blocks validates its bounds and gc_inode_local_packing
    defaults to 0.

Daejun Park (2):
  f2fs: extract do_migrate_one_data_block() helper for GC migration
  f2fs: pack same-inode blocks by inode during FG_GC

 Documentation/ABI/testing/sysfs-fs-f2fs |  20 ++
 fs/f2fs/f2fs.h                          |   9 +-
 fs/f2fs/gc.c                            | 302 +++++++++++++++++++-----
 fs/f2fs/gc.h                            |   5 +
 fs/f2fs/super.c                         |   2 +
 fs/f2fs/sysfs.c                         |  16 ++
 6 files changed, 297 insertions(+), 57 deletions(-)


base-commit: 6429f3bf6dc33cba42055260f905559c43976eeb
-- 
2.43.0