The balloon holds filesystem space that never carries data, but its blocks are allocated, so FITRIM walks past them, and inflating the balloon is a plain fallocate() that does not discard either. Once the balloon is inflated over the blocks of removed files, e.g. on an online shrink of a Container disk, the ploop or qcow2 image keeps those clusters mapped for good, and compaction, which is FITRIM, does not give them back (VSTOR-153590).
This series makes FITRIM discard the unwritten extents of the balloon after the free space, on ext4 (patch 2) and xfs (patch 3). The walk holds the inode locks of the balloon exclusively, after waiting for direct I/O and flushing its page cache, as punch hole does, so no block can be freed, reused or written under the discard. Physically adjacent extents are merged, so that the device below gets whole clusters, and a long run is discarded in interruptible chunks. A balloon inflated before this series is released by the next FITRIM, no userspace change is needed. Patch 1 fixes an inode reference leak in xfs_balloon_get() that FITRIM would now hit too. The ploop side is openvz/ploop.ovz PR 519: tests for this, and fixes of the ploop-balloon discard options found on the way: https://bitbucket.org/openvz/ploop.ovz/pull-requests/519 Changes since v1 (https://lore.virtuozzo.com/kernel/[email protected]/): - take the balloon inode locks exclusively, wait for direct I/O and flush the page cache before the walk; v1 held the shared lock, which did not keep writeback and direct I/O from converting an extent the walk had seen unwritten (Sashiko); - walk to the end of the file instead of i_size, as fallocate() with FALLOC_FL_KEEP_SIZE can leave unwritten extents past it (Sashiko); - discard a merged run in chunks aligned to the discard granularity, checking for fatal signals and freezing between them; - drop the read-only mount skip: ploop does not set balloon_ino on a read-only mount, and the free space pass does not skip one either; - ext4: do not count the balloon in the trimmed length, so fstrim -v no longer reports it as freed on every call; no 64-bit division on i_size any more (Sashiko); - xfs: fail FITRIM on an error reading the balloon inode, use GFP_KERNEL, and fix the xfs_balloon_get() leak in patch 1 (Sashiko); - every FITRIM still discards the balloon again: neither filesystem bumps a counter on fallocate() of the balloon that a skip could rely on, and a wrong skip would leave clusters mapped for good, while a repeated discard of unmapped clusters is cheap. Tested on 6.12.0-211.52.1.22.19.vz10 rebuilt with this series and the VSTOR-154159 max_discard_segments fixes: - ploop and qcow2 images with ext4 and xfs: write 2G, remove it without a trim, inflate the balloon over the free space, ploop-balloon discard. Stock: the image keeps mapping the removed 2G. Patched: the image maps about as much as when it was created, a kept file is intact, fsck and ploop check / qemu-img check are clean; - 16G removed under a balloon of about 38G: a full fstrim takes under 3 seconds, a SIGKILL one second into it ends fstrim at once, a repeated fstrim takes a fraction of a second, fsck is clean; - test_ploop_balloon.py from PR 519: green on ploop and qcow2. On the stock kernel only the tests for the space under the balloon fail. Not covered: ext4 bigalloc, a realtime xfs balloon (skipped). On ploop1 discard works on whole clusters, so up to two clusters at the ends of each contiguous piece of the balloon stay mapped, as do pieces shorter than the FITRIM minimum length. Denis V. Lunev (3): xfs: release the balloon inode when xfs_balloon_get() refuses it ext4: discard the balloon on FITRIM xfs: discard the balloon on FITRIM fs/ext4/mballoc.c | 126 +++++++++++++++++++++++++++++++++++++ fs/xfs/xfs_discard.c | 144 +++++++++++++++++++++++++++++++++++++++++++ fs/xfs/xfs_super.c | 4 +- 3 files changed, 273 insertions(+), 1 deletion(-) -- 2.53.0 _______________________________________________ Devel mailing list [email protected] https://lists.openvz.org/mailman/listinfo/devel
