tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: Add a mountlist iterator



> On 2. Apr 2017, at 16:34, Taylor R Campbell <campbell+netbsd-tech-kern%mumble.net@localhost> wrote:
> 
>> Date: Sun, 2 Apr 2017 11:09:49 +0200
>> From: "J. Hannken-Illjes" <hannken%eis.cs.tu-bs.de@localhost>
>> 
>>> On 1. Apr 2017, at 23:03, Taylor R Campbell <campbell+netbsd-tech-kern%mumble.net@localhost> wrote:
>>> 
>>> Any particular reason to use a pointer-to-opaque-pointer here instead
>>> of a caller-allocated struct mountlist_iterator object?
>> 
>> Just to make it opaque to the caller.  I see no reason to make the
>> mountlist internals part of the kernel API and expose them down to
>> the file system implementations.
> 
> The caller-allocated struct mountlist_iterator could be made to
> contain just a single pointer as the current API uses.
> 
> *shrug* Not a big deal either way.
> 
>> As _mountlist_next() exists for DDB only (no locks, no allocs) I see
>> no problems here.
> 
> One might be concerned in ddb with having to chase many pointers in a
> possibly corrupt kernel memory state, so there is some small advantage
> to avoiding list traversal.

Not from the DDB prompt but from operations like "printlockedvnodes()"
or "fstrans_dump()".  If the mountlist is corrupt you're lost.

> 
>>                   Embedding the mountlist_entry in "struct mount"
>> forces us to use a "struct mount" as a marker and this struct
>> has a size of ~2.5 kBytes.
> 
> By `embed' I didn't mean that the marker has to be a whole struct
> mount.  Rather, something more like:
> 
> 	struct mountlist_entry {
> 		TAILQ_ENTRY(mountlist_entry)		mle_tqe;
> 		enum { MNTENT_MARKER, MNTENT_MOUNT }	mle_tag;
> 	};
> 
> 	struct mount {
> 		...
> 		struct mountlist_entry mnt_entry;
> 		...
> 	};
> 
> 	TAILQ_HEAD(, mountlist_entry) mount_list;
> 
> To recover the struct mount from a struct mountlist_entry that is
> tagged as a mount, simply do
> 
> 	struct mountlist_entry *mle = ...;
> 	struct mount *mp = container_of(mle, struct mount, mnt_entry);

Any reason you want "mle_tqe" and "mle_tag" public?

>>> Candidate for cacheline-aligned struct?  Why do we need a new lock
>>> mount_list_lock for this instead of using the existing mountlist_lock?
>> 
>> For the transition it is better to use a separate lock.  After the
>> transition "mountlist_lock" gets removed.
> 
> OK, fair enough.  Can you add a comment over the declaration stating
> that plan?
> 
>>> Beware: TAILQ_PREV (and TAILQ_LAST) violates strict aliasing rules, so
>>> we should probably try to phase it out rather than add new users.
>>> Maybe we should add a new kind of queue(3) that doesn't violate strict
>>> aliasing but supports *_PREV and *_LAST.
>>> 
>>> All that said, it is not clear to me why you need reverse iteration
>>> here.  None of your patches seem to use it.  Are you planning to use
>>> it for some future purpose?
>> 
>> Historical the mountlist gets traversed in mount order.  Some syscalls
>> return in this order so it should be kept.
>> 
>> Unmounting all file system on shutdown has to be done in reverse mount
>> order so here (vfs_unmount_forceone / vfs_unmountall1) we need it.
> 
> I see -- your patch just hasn't addressed those yet.  Maybe Someone^TM
> should just write a replacement for TAILQ so we can use it here now.

File 002_ml_iterator_switch around line 453 and 487.

>>> Why do we need a new refcnt dance here?  Why isn't it enough to just
>>> use vfs_busy like all the existing callers?
>> 
>> Because vfs_busy() expects the caller to already hold a reference and
>> one of the goals here is to drop the mount_list_lock as early as possible.
> 
> I suppose you want to avoid setting down a lock order for
> mount_list_lock and mp->mnt_unmounting.  I guess this doesn't matter
> much since it's limited to vfs internals.
> 
>>> Can you make another separate commit to drop the keepref parameter to
>>> vfs_unbusy, and change all the callers with keepref=true to just use
>>> vfs_destroy themselves?
>> 
>> You mean the opposite (keepref=false -> caller does vfs_destroy), yes?
>> 
>> Of the 81 usages of vfs_unbusy() only 6 have keepref=true, all others
>> would have to be changed to "vfs_unbusy(mp); vfs_destroy(mp);".
> 
> Heh.  This confusion on my part suggest two things:
> 
> 1. Perhaps in this change, we ought to add a different function for
> use with mount iteration, say mountlist_iterator_next_done, so that
> any legacy confusion about the vfs_busy/unbusy API is hidden:
> 
> 	mountlist_iterator_init(&it);
> 	while ((mp = mountlist_iterator_next(&it)) != NULL) {
> 		...
> 		mountlist_iterator_next_done(&it, mp);
> 	}
> 	mountlist_iterator_destroy(&it);

Will think about it -- looks ok so far.

> 2. Perhaps in another change, we ought to replace vfs_unbusy(mp,
> false) by vfs_unbusy(mp), and vfs_unbusy(mp, true) by
> 
> vfs_acquire(mp);
> vfs_unbusy(mp);
> 
> so that there is less confusing boolean-flagged asymmetry between
> vfs_busy/vfs_unbusy.
> 
> Thus, the busy count (determining whether a mount can be unmounted
> from the file system namespace) and the reference count (determining
> whether the struct mount kernel data structures can be freed) would be
> maintained in parallel:
> 
> 	/* file system mount point busy count (implies reference count too) */
> 	error = vfs_busy(mp);
> 	if (error)
> 		goto fail;
> 	...
> 	vfs_unbusy(mp);
> 
> 	/* data structure reference count */
> 	vfs_acquire(mp);
> 	...
> 	vfs_destroy(mp);

dito.

> (Meanwhile, vfs_release would be a better name than vfs_destroy, in a
> subsequent change.)

--
J. Hannken-Illjes - hannken%eis.cs.tu-bs.de@localhost - TU Braunschweig (Germany)



Home | Main Index | Thread Index | Old Index