Page MenuHomeFreeBSD

Clean up unionfs thread arguments and implement VOP_VPUT_PAIR
ClosedPublic

Authored by jah on Nov 16 2021, 6:16 AM.
Tags
None
Referenced Files
Unknown Object (File)
Wed, May 8, 7:03 AM
Unknown Object (File)
Mon, May 6, 7:29 AM
Unknown Object (File)
Mar 18 2024, 12:38 AM
Unknown Object (File)
Mar 7 2024, 4:49 PM
Unknown Object (File)
Jan 27 2024, 2:26 PM
Unknown Object (File)
Jan 6 2024, 3:58 PM
Unknown Object (File)
Dec 28 2023, 3:46 AM
Unknown Object (File)
Dec 23 2023, 12:18 AM
Subscribers

Details

Summary

This review contains 2 commits:

  1. Remove unnecessary thread argument from unionfs_nodeget() and _noderem()

No functional change intended.

  1. unionfs: implement VOP_VPUT_PAIR

unionfs must pass VOP_VPUT_PAIR directly to the underlying FS so that
it can have a chance to manage any special locking considerations that
may be necessary.

The unionfs implementation is based heavily on the corresponding nullfs
implementation.

Diff Detail

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

Event Timeline

jah requested review of this revision.Nov 16 2021, 6:16 AM

The thread arg removal patch looks fine.

sys/fs/unionfs/union_vnops.c
2610

I suspect it is not safe to do VOP_VPUT_PAIR() on one pair while another one is locked. This note is true for other call to VOP_VPUT_PAIR() in this function as well.

Is it really needed to call both VOP_VPUT_PAIR()? If yes, there is a fundamental brokeness in unionfs design. It should be so that you need to do either upper, or lower call, not both.

sys/fs/unionfs/union_vnops.c
2610

The behavior here is based on the fact that currently unionfs_lock()/unionfs_unlock() operate on both lower and upper vnodes, if present.

I already have plenty of concerns about that behavior, and at some point I'd like to sit down and see if I can rethink the whole locking scheme. I haven't yet seen a failure that I can attribute to unionfs_lock()'s behavior, but it seems dangerous to lock two vnodes without any assistance from vn_lock_pair() or something like it. I'm also skeptical that the lower vnode lock is needed at all once the upper vnode is present, although propagating the lower vnode lock state to the upper vnode during e.g. unionfs_copyfile() would still be problematic.

Is your specific concern here about the possibility for an underlying FS implementation to relock the vnodes, leading to LOR? Does that concern still hold even though unlock_vp is set in the calls to the lower FS?

sys/fs/unionfs/union_vnops.c
2610

If you own a vnode lock on some mp, you generally cannot safely lock any vnode on other mp.

At very least, lookup() establishes the order between locks by following the path: containing directory lock is before any vnode lock having a name in this directory. Through vp_crossmp, this order also crosses mount points.

If you own one vnode lock, you cannot know where is another vnode' lock in this order.

But there are more isolated and corner cases. One big can of worms is the UFS quota support. First, quota file locks are essentially after any other vnode locks due to the code organization, but they can be reached by normal lookups. But, quota files can be put on other filesystem (not the one which they serve). This adds even more LOR violations.

sys/fs/unionfs/union_vnops.c
2610

Then that's really the fundamental brokenness, that unionfs_lock() always tries to independently lock both vnodes, right?
As long as that remains true, then I don't think unionfs_vput_pair() has any choice but to call VOP_VPUT_PAIR() on both vnodes.

I could be missing something, but given that I'm setting unlock_vp on both vnodes, it doesn't seem that I'm making the problem worse with this change. This change also fixes a panic that's easy to reproduce during stress testing, so what I'd like to do is commit this change along with a TODO comment that it should be revisited once the unionfs locking scheme has been reworked.

Then, I'll see if I can fix the fundamental issue with unionfs_lock(). Ultimately, most unionfs operations other than lookup() don't care about the lower vnode once the upper vnode is present. I wonder if I could take the approach of changing unionfs_lock() to only lock one vnode or the other, while using vn_lock_pair() for the small number of cases in which both vnode locks need to overlap?

sys/fs/unionfs/union_vnops.c
2610

I do not intend to block this change in any way.

Yes, my belief is that reasonable unionfs implementation should be fine with only locking upper or lower vnode (or dvp/vp pair), almost never it needs to lock both upper and lower symultaneously. Open question is how to detect whether we have or not the upper vnode, in safe manner. Another open question is how to lock all four safely.

Both UFS and msdosfs rename handle safe locking of three or four vnodes, fdvp/fvp and tdvp/(tvp or NULL). But since locks are dropped, VOPs have to do sleep-less relookup to ensure that names did not change.

Remove some write-only variables, add locking commentary

All of the unions tests in stress2 runs without any issues when D33008.98931.diff is added.

In D33008#752188, @jah wrote:

ping

You should take responsibility for unionfs commits on yourself. I already stated my opinion, including the note that I do not object against the change in any way. Commit it with 'Discussed with: kib' tagline.

This revision was not accepted when it landed; it landed in state Needs Review.Dec 8 2021, 12:12 AM
This revision was automatically updated to reflect the committed changes.