Page MenuHomeFreeBSD

unionfs: accommodate underlying FS calls that may re-lock
ClosedPublic

Authored by jah on Feb 24 2024, 11:56 PM.
Tags
None
Referenced Files
Unknown Object (File)
Sat, May 11, 12:40 PM
Unknown Object (File)
Sat, May 11, 12:39 PM
Unknown Object (File)
Sat, May 11, 12:39 PM
Unknown Object (File)
Sat, May 11, 8:41 AM
Unknown Object (File)
Sat, May 11, 8:09 AM
Unknown Object (File)
Apr 26 2024, 3:42 AM
Unknown Object (File)
Apr 22 2024, 4:40 AM
Unknown Object (File)
Apr 19 2024, 5:36 PM

Details

Summary

Since non-doomed unionfs vnodes always share their primary lock with
either the lower or upper vnode, any forwarded call to the base FS
which transiently drops that upper or lower vnode lock may result in
the unionfs vnode becoming completely unlocked during that transient
window. The unionfs vnode may then become doomed by a concurrent
forced unmount, which can lead to either or both of the following:

--Complete loss of the unionfs lock: in the process of being

doomed, the unionfs vnode switches back to the default vnode lock,
so even if the base FS VOP reacquires the upper/lower vnode lock,
that no longer translates into the unionfs vnode being relocked.
This will then violate that caller's locking assumptions as well
as various assertions that are enabled with DEBUG_VFS_LOCKS.

--Complete less of reference on the upper/lower vnode: the caller

normally holds a reference on the unionfs vnode, while the unionfs
vnode in turn holds references on the upper/lower vnodes.  But in
the course of being doomed, the unionfs vnode will drop the latter
set of references, which can effectively lead to the base FS VOP
executing with no references at all on its vnode, violating the
assumption that vnodes can't be recycled during these calls and
(if lucky) violating various assertions in the base FS.

Fix this by adding two new functions, unionfs_forward_vop_start()
and unionfs_forward_vop_finish(), which are intended to bookend
any forwarded VOP which may transiently unlock the relevant vnode(s).
These functions are currently only applied to VOPs that modify file
state (and require vnode reference and lock state to be identical at
call entry and exit), as the common reason for transiently dropping
locks is to update filesystem metadata.

MFC after: 2 weeks

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Not Applicable
Unit
Tests Not Applicable

Event Timeline

jah requested review of this revision.Feb 24 2024, 11:56 PM

This basically amounts to a generalized version of the mkdir()-specific fix I made last year in commit 93fe61afde72e6841251ea43551631c30556032d (of course in that commit I also inadvertently added a potential v_usecount ref leak on the new vnode). Or I guess it can be thought of as a tailored version of null_bypass().

I ran the unionfs specific tests with the D44076.134963.patch added.
I did not observe any problems during an 8 hour test.

I agree with your reasoning. Overall looks fine. Thanks! I have a couple of suggestions.

sys/fs/unionfs/union.h
158–161

Since most calls pass NULL for the second vnode, I'd suggest renaming these and adding two helpers for the frequent case.

I'd add a _pair suffix for those with two vnodes. The single vnode variant can just call the two vnode variants with additional NULL/0 parameters.

sys/fs/unionfs/union_subr.c
1007–1008

Assuming a vnode is locked by the caller, VOP_ISLOCKED() can only return LK_EXCLUSIVE and LK_SHARED.

1012–1013

Same here.

1042

I'd suggest renaming these into vp1_doomed and vp2_doomed instead, since this is what is really tested, and clearer I think particularly for the return statement.

1059–1067

Suggestions: Extract the unionvp2 != NULL test, making the code inside the same as the previous block (with substitution of 1 with 2), allowing to factorize this code in a small helper function.

sys/fs/unionfs/union_vnops.c
378–382

Suggested simplification.

461–464

Same here.

1470–1472

Same.

1600–1602

Same.

Incorporate code review feedback from olce@

This revision is now accepted and ready to land.Feb 29 2024, 9:21 AM

Tests with D44076.135202.patch showed no issues.