tech-kern archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: Add a mountlist iterator
> 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.
> 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);
> > 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.
> > 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);
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);
(Meanwhile, vfs_release would be a better name than vfs_destroy, in a
subsequent change.)
Home |
Main Index |
Thread Index |
Old Index