#!/usr/bin/env python """Hand the archive's file handles back to the host. The archive is on a virtiofs share whose daemon holds a host file descriptor per inode the guest has looked up. Anything that reads a lot of the archive leaves those inodes cached, and the handles with them, until something forces the guest to evict them -- at which point the daemon can run out and the mount starts refusing *every* open, which surfaces across the whole machine as "too many open files in system". The pipeline's own bulk jobs now reclaim as they go and again when they finish, so this should rarely be needed. It exists for when something else has loaded the cache, or to check where things stand: reclaim.py # report, then reclaim if needed reclaim.py --check # report only, change nothing sudo reclaim.py # uses drop_caches: instant, and far gentler Without root the only lever available is memory pressure, which means briefly allocating several GiB. Running under sudo avoids that entirely. """ import argparse import os import sys sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from suvi import vfs #: Roughly the slab size at which the daemon is likely near a 1M descriptor limit. #: A cached dentry plus inode is on the order of a kilobyte, so a gigabyte of #: reclaimable slab is on the order of a million inodes. CONCERN_GIB = 1.0 def report(prefix): slab = vfs.reclaimable_kb() / (1024 * 1024) print(f"{prefix:>8}: {slab:.2f} GiB reclaimable slab " f"(~{slab:.1f}M cached inodes), {vfs.available_gib():.1f} GiB available") return slab def main(argv=None): parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument("--check", action="store_true", help="report only, reclaim nothing") parser.add_argument("--force", action="store_true", help="reclaim even if it looks fine") args = parser.parse_args(argv) before = report("before") if args.check: print(" (check only; nothing reclaimed)") return 0 if before < CONCERN_GIB else 1 if before < CONCERN_GIB and not args.force: print(f" below {CONCERN_GIB} GiB; nothing to do. Use --force to reclaim anyway.") return 0 if os.geteuid() != 0: print(" not root, so using memory pressure; run under sudo for the direct path") freed = vfs.release_handles() after = report("after") print(f" {'reclaimed' if freed else 'no change'}: " f"{before - after:+.2f} GiB") return 0 if __name__ == "__main__": sys.exit(main())