21541: Fix KeyError, segfaults, and memory use issues
authorPeter Amstutz <peter.amstutz@curii.com>
Wed, 6 Mar 2024 20:03:38 +0000 (15:03 -0500)
committerPeter Amstutz <peter.amstutz@curii.com>
Fri, 15 Mar 2024 17:05:13 +0000 (13:05 -0400)
commitb9fde93b6e24b0575ce81a964be6884231647ee4
tree0b769b0ffec79c9efbd2c48169c9a2fb12c12dbb
parentcac999f47113207f1b05405ee24daab19ac97de4
21541: Fix KeyError, segfaults, and memory use issues

* Fixes a segfault on startup due to multiple threads fetching the
cluster config using the same http2 object, which is not threadafe.
Now fetches the relevant configuration
item once (ForwardSlashNameSubstitution), and stores it where all the
threads can access it.  (bug #21568)

* Fixes KeyError thrown where a parent inode is removed from the
inodes table before its children.

* In the process of testing, re-discovered a bug where, if the llfuse
_notify_queue fills up, the entire mount process deadlocks.

The previous fix worked by monkey-patching llfuse to replace a
limited-length queue with an unlimited length queue, however changes
in subsequent llfuse versions caused that variable to be hidden from
Python (so the monkey patch didn't fail but it no longer had any
effect either).  The solution is to introduce an additional
unlimited-size queue in between the operation handlers and the
limited-size kernel notification queue.

* Because cache management and inode cleanup interact with kernel
notifications (which were moved into a separate thread), I decided
they should also be asynchronous from the operation handlers, so they
are now part of the same thread that processes kernel notifications.

* Attempting to remove an inode that is in use will now at minimum
send a kernel invalidation, which will sometimes nudge the kernel to
forget the inode, enabling us to remove it.

* Filter groups now check if the filter group contains itself so it
doesn't create an infinite path loop that breaks filesystem traversal
tools.

* In the process of testing, found that llfuse didn't wait for the
_notify_queue to drain before closing the FUSE channel, resulting in a
segfault if the _notify_loop thread tried to process any events after
shutdown started.  This bug cannot be worked around on the Arvados
side, so I have prepared an arvados-llfuse fork with a bug fix.

* Testing with arv-mount-stress-test (which creates 8 subprocesses that all
traverse the filesystem at the same time) now passes with no
filesystem errors, no deadlocks, no segfaults, and modest memory
usage.

Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz@curii.com>
sdk/python/arvados/safeapi.py
services/fuse/arvados_fuse/__init__.py
services/fuse/arvados_fuse/command.py
services/fuse/arvados_fuse/fresh.py
services/fuse/arvados_fuse/fusedir.py
services/fuse/tests/integration_test.py
services/fuse/tests/mount_test_base.py
services/fuse/tests/test_inodes.py
services/fuse/tests/test_mount.py
services/fuse/tests/test_unmount.py