diff options
| author | David Howells <dhowells@redhat.com> | 2004-07-10 19:30:11 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2004-07-10 19:30:11 -0700 |
| commit | c8a6ba011918486195870aab9a8e3d61c76c1b02 (patch) | |
| tree | 896c5960db3db754d7364802486044fa907eed50 /include/linux | |
| parent | 694effe72032db1384b5a084977b8bbb2c3cdaa6 (diff) | |
[PATCH] intrinsic automount and mountpoint degradation support
Here's a patch that I worked out with Al Viro that adds support for a
filesystem (such as kAFS) to perform automounting intrinsically without the
need for a userspace daemon. It also adds support for such mountpoints to be
degraded at the filesystem's behest until they've been untouched long enough
that they'll be removed.
I've a patch (to follow) that removes some #ifdef's from fs/afs/* thus
allowing it to make use of this facility.
There are five pieces to this:
(1) Any interested filesystem needs to have at least one list to which
expirable mountpoints can be added.
Access to this list is governed by the vfsmount_lock.
(2) When a filesystem wants to create an expirable mount, it calls
do_kern_mount() to get a handle on the filesystem it wants mounting, and
then calls do_add_mount() to mount that filesystem on the designated
mountpoint, supplying the list mentioned in (1) to which the vfsmount
will be added.
In kAFS's case, the mountpoint is a directory with a follow_link() method
defined (fs/afs/mntpt.c). This uses the struct nameidata supplied as an
argument as a determination of where the new filesystem should be
mounted.
(3) When something using a vfsmount finishes dealing with it, it calls
mntput(). This unmarks the vfsmount for immediate expiry.
There are two criteria for determining if a vfsmount may be expired - it
mustn't be marked as in use for anything other than being a child of
another vfsmount, and it must have an expiry mark against it already.
(4) The filesystem then determines the policy on expiring the mounts created
in (2). When it feels the need to, it passes the list mentioned in (1) to
mark_mounts_for_expiry() to request everything on the list be expired.
This function examines each mount listed. If the vfsmount meets the
criteria mentioned in (3), then the vfsmount is deleted from the
namespace and disposed of as for unmounting; otherwise the vfsmount is
left untouched apart from now bearing an expiration mark if it didn't
before.
kAFS's expiration policy is simply to invoke this process at regular
intervals for all the mounts on its list.
(5) An expiration facility is also provided to userspace: by calling umount()
with a MNT_EXPIRE flag, it can make a request to unmount only if the
mountpoint hasn't been used since the last request and isn't in use now.
This allows expiration to be driven by userspace instead of by the
kernel if that is desirable.
This also means that do_umount() has to use a different version of
path_release() to everyone else... it can't call mntput() as that clears
the expiration flag, thus rendering this unachievable; so it's version of
path_release() calls _mntput(), which doesn't do the clear.
My original idea was to give the kernel more knowledge of automounted
things. This avoids a certain problem with stat() on a mountpoint causing it
to mount (for example, do "ls -l /afs" on a machine with kAFS), but Al wanted
it done this way.
> Why is autofs unsuitable?
Because:
(1) Autofs is flat; AFS requires a tree - mounts on mounts on mounts on
mounts...
(2) AFS holds the data as to what the mountpoints are and where they go, and
these may be cross-links to subtrees beyond your control. It's also not
trivial to extract a list of mountpoints as is required for autofs.
(3) Autofs is not namespace safe.
(4) Ducking back to userspace to get that to do the mount is pretty tricky if
namespaces are involved.
In fact, autofs may well want to make use of this facility.
Signed-Off-By: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'include/linux')
| -rw-r--r-- | include/linux/fs.h | 1 | ||||
| -rw-r--r-- | include/linux/mount.h | 21 | ||||
| -rw-r--r-- | include/linux/namei.h | 1 | ||||
| -rw-r--r-- | include/linux/namespace.h | 2 |
4 files changed, 23 insertions, 2 deletions
diff --git a/include/linux/fs.h b/include/linux/fs.h index de1cd53ca7d3..e847ef6d20fb 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -716,6 +716,7 @@ extern int send_sigurg(struct fown_struct *fown); #define MNT_FORCE 0x00000001 /* Attempt to forcibily umount */ #define MNT_DETACH 0x00000002 /* Just detach from the tree */ +#define MNT_EXPIRE 0x00000004 /* Mark for expiry */ extern struct list_head super_blocks; extern spinlock_t sb_lock; diff --git a/include/linux/mount.h b/include/linux/mount.h index 61554dda78a8..42e2c9460088 100644 --- a/include/linux/mount.h +++ b/include/linux/mount.h @@ -29,8 +29,11 @@ struct vfsmount struct list_head mnt_child; /* and going through their mnt_child */ atomic_t mnt_count; int mnt_flags; + int mnt_expiry_mark; /* true if marked for expiry */ char *mnt_devname; /* Name of device e.g. /dev/dsk/hda1 */ struct list_head mnt_list; + struct list_head mnt_fslink; /* link in fs-specific expiry list */ + struct namespace *mnt_namespace; /* containing namespace */ }; static inline struct vfsmount *mntget(struct vfsmount *mnt) @@ -42,7 +45,7 @@ static inline struct vfsmount *mntget(struct vfsmount *mnt) extern void __mntput(struct vfsmount *mnt); -static inline void mntput(struct vfsmount *mnt) +static inline void _mntput(struct vfsmount *mnt) { if (mnt) { if (atomic_dec_and_test(&mnt->mnt_count)) @@ -50,10 +53,26 @@ static inline void mntput(struct vfsmount *mnt) } } +static inline void mntput(struct vfsmount *mnt) +{ + if (mnt) { + mnt->mnt_expiry_mark = 0; + _mntput(mnt); + } +} + extern void free_vfsmnt(struct vfsmount *mnt); extern struct vfsmount *alloc_vfsmnt(const char *name); extern struct vfsmount *do_kern_mount(const char *fstype, int flags, const char *name, void *data); + +struct nameidata; + +extern int do_add_mount(struct vfsmount *newmnt, struct nameidata *nd, + int mnt_flags, struct list_head *fslist); + +extern void mark_mounts_for_expiry(struct list_head *mounts); + extern spinlock_t vfsmount_lock; #endif diff --git a/include/linux/namei.h b/include/linux/namei.h index adcafdec8ee7..1bbfa296e11f 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h @@ -61,6 +61,7 @@ extern int FASTCALL(path_lookup(const char *, unsigned, struct nameidata *)); extern int FASTCALL(path_walk(const char *, struct nameidata *)); extern int FASTCALL(link_path_walk(const char *, struct nameidata *)); extern void path_release(struct nameidata *); +extern void path_release_on_umount(struct nameidata *); extern struct dentry * lookup_one_len(const char *, struct dentry *, int); extern struct dentry * lookup_hash(struct qstr *, struct dentry *); diff --git a/include/linux/namespace.h b/include/linux/namespace.h index fdd8abb07386..9eca1558d72f 100644 --- a/include/linux/namespace.h +++ b/include/linux/namespace.h @@ -14,7 +14,7 @@ struct namespace { extern void umount_tree(struct vfsmount *); extern int copy_namespace(int, struct task_struct *); -void __put_namespace(struct namespace *namespace); +extern void __put_namespace(struct namespace *namespace); static inline void put_namespace(struct namespace *namespace) { |
