* [PATCH] intrinsic automount and mountpoint degradation support
@ 2004-06-30 19:35 David Howells
0 siblings, 0 replies; 3+ messages in thread
From: David Howells @ 2004-06-30 19:35 UTC (permalink / raw)
To: torvalds, akpm; +Cc: linux-kernel, viro
Hi Linus, Andrew,
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.
David
diff -uNr linux-2.6.7/fs/namei.c linux-2.6.7-auto/fs/namei.c
--- linux-2.6.7/fs/namei.c 2004-06-18 13:44:02.000000000 +0100
+++ linux-2.6.7-auto/fs/namei.c 2004-06-25 13:48:28.000000000 +0100
@@ -278,6 +278,12 @@
mntput(nd->mnt);
}
+void path_release_on_umount(struct nameidata *nd)
+{
+ dput(nd->dentry);
+ _mntput(nd->mnt);
+}
+
/*
* Internal lookup() using the new generic dcache.
* SMP-safe
diff -uNr linux-2.6.7/fs/namespace.c linux-2.6.7-auto/fs/namespace.c
--- linux-2.6.7/fs/namespace.c 2004-06-18 13:44:02.000000000 +0100
+++ linux-2.6.7-auto/fs/namespace.c 2004-06-30 19:43:14.565098078 +0100
@@ -60,6 +60,7 @@
INIT_LIST_HEAD(&mnt->mnt_child);
INIT_LIST_HEAD(&mnt->mnt_mounts);
INIT_LIST_HEAD(&mnt->mnt_list);
+ INIT_LIST_HEAD(&mnt->mnt_fslink);
if (name) {
int size = strlen(name)+1;
char *newname = kmalloc(size, GFP_KERNEL);
@@ -106,13 +107,9 @@
EXPORT_SYMBOL(lookup_mnt);
-static int check_mnt(struct vfsmount *mnt)
+static inline int check_mnt(struct vfsmount *mnt)
{
- spin_lock(&vfsmount_lock);
- while (mnt->mnt_parent != mnt)
- mnt = mnt->mnt_parent;
- spin_unlock(&vfsmount_lock);
- return mnt == current->namespace->root;
+ return mnt->mnt_namespace == current->namespace;
}
static void detach_mnt(struct vfsmount *mnt, struct nameidata *old_nd)
@@ -164,6 +161,11 @@
mnt->mnt_root = dget(root);
mnt->mnt_mountpoint = mnt->mnt_root;
mnt->mnt_parent = mnt;
+ mnt->mnt_namespace = old->mnt_namespace;
+ spin_lock(&vfsmount_lock);
+ if (!list_empty(&old->mnt_fslink))
+ list_add(&mnt->mnt_fslink, &old->mnt_fslink);
+ spin_unlock(&vfsmount_lock);
}
return mnt;
}
@@ -346,6 +348,7 @@
while (!list_empty(&kill)) {
mnt = list_entry(kill.next, struct vfsmount, mnt_list);
list_del_init(&mnt->mnt_list);
+ list_del_init(&mnt->mnt_fslink);
if (mnt->mnt_parent == mnt) {
spin_unlock(&vfsmount_lock);
} else {
@@ -369,6 +372,24 @@
return retval;
/*
+ * If we've been asked to mark for expiry, we only _actually_ effect
+ * the unmount if:
+ * (1) the mark is already set (the mark is cleared by mntput())
+ * (2) the usage count == 1 [parent vfsmount] + 1 [sys_umount]
+ */
+ if (flags & MNT_EXPIRE) {
+ if (mnt == current->fs->rootmnt ||
+ flags & (MNT_FORCE | MNT_DETACH))
+ return -EINVAL;
+
+ if (atomic_read(&mnt->mnt_count) != 2)
+ return -EBUSY;
+
+ if (!xchg(&mnt->mnt_expiry_mark, 1))
+ return -EAGAIN;
+ }
+
+ /*
* If we may have to abort operations to get out of this
* mount, and they will themselves hold resources we must
* allow the fs to do things. In the Unix tradition of
@@ -461,7 +482,7 @@
retval = do_umount(nd.mnt, flags);
dput_and_out:
- path_release(&nd);
+ path_release_on_umount(&nd);
out:
return retval;
}
@@ -618,6 +639,10 @@
}
if (mnt) {
+ spin_lock(&vfsmount_lock);
+ list_del_init(&mnt->mnt_fslink);
+ spin_unlock(&vfsmount_lock);
+
err = graft_tree(mnt, nd);
if (err) {
spin_lock(&vfsmount_lock);
@@ -638,7 +663,8 @@
* on it - tough luck.
*/
-static int do_remount(struct nameidata *nd,int flags,int mnt_flags,void *data)
+static int do_remount(struct nameidata *nd, int flags, int mnt_flags,
+ void *data)
{
int err;
struct super_block * sb = nd->mnt->mnt_sb;
@@ -710,6 +736,7 @@
detach_mnt(old_nd.mnt, &parent_nd);
attach_mnt(old_nd.mnt, nd);
+ list_del_init(&old_nd.mnt->mnt_fslink);
out2:
spin_unlock(&vfsmount_lock);
out1:
@@ -722,11 +749,10 @@
return err;
}
-static int do_add_mount(struct nameidata *nd, char *type, int flags,
+static int do_new_mount(struct nameidata *nd, char *type, int flags,
int mnt_flags, char *name, void *data)
{
struct vfsmount *mnt;
- int err;
if (!type || !memchr(type, 0, PAGE_SIZE))
return -EINVAL;
@@ -736,9 +762,16 @@
return -EPERM;
mnt = do_kern_mount(type, flags, name, data);
- err = PTR_ERR(mnt);
if (IS_ERR(mnt))
- goto out;
+ return PTR_ERR(mnt);
+
+ return do_add_mount(mnt, nd, mnt_flags, NULL);
+}
+
+int do_add_mount(struct vfsmount *newmnt, struct nameidata *nd,
+ int mnt_flags, struct list_head *fslist)
+{
+ int err;
down_write(¤t->namespace->sem);
/* Something was mounted here while we slept */
@@ -750,22 +783,111 @@
/* Refuse the same filesystem on the same mount point */
err = -EBUSY;
- if (nd->mnt->mnt_sb == mnt->mnt_sb && nd->mnt->mnt_root == nd->dentry)
+ if (nd->mnt->mnt_sb == newmnt->mnt_sb &&
+ nd->mnt->mnt_root == nd->dentry)
goto unlock;
err = -EINVAL;
- if (S_ISLNK(mnt->mnt_root->d_inode->i_mode))
+ if (S_ISLNK(newmnt->mnt_root->d_inode->i_mode))
goto unlock;
- mnt->mnt_flags = mnt_flags;
- err = graft_tree(mnt, nd);
+ newmnt->mnt_flags = mnt_flags;
+ err = graft_tree(newmnt, nd);
+
+ if (err == 0 && fslist) {
+ spin_lock(&vfsmount_lock);
+ list_add_tail(&newmnt->mnt_fslink, fslist);
+ spin_unlock(&vfsmount_lock);
+ }
+
unlock:
up_write(¤t->namespace->sem);
- mntput(mnt);
-out:
+ mntput(newmnt);
return err;
}
+EXPORT_SYMBOL_GPL(do_add_mount);
+
+void mark_mounts_for_expiry(struct list_head *mounts)
+{
+ struct namespace *namespace;
+ struct list_head graveyard, *_p, *_n;
+ struct vfsmount *mnt;
+
+ INIT_LIST_HEAD(&graveyard);
+
+ spin_lock(&vfsmount_lock);
+
+ list_for_each_safe(_p, _n, mounts) {
+ mnt = list_entry(_p, struct vfsmount, mnt_fslink);
+
+ if (!xchg(&mnt->mnt_expiry_mark, 1) ||
+ atomic_read(&mnt->mnt_count) != 1)
+ continue;
+
+ mntget(mnt);
+ list_move(&mnt->mnt_fslink, &graveyard);
+ }
+
+ while (!list_empty(&graveyard)) {
+ mnt = list_entry(graveyard.next, struct vfsmount, mnt_fslink);
+ list_del_init(&mnt->mnt_fslink);
+
+ namespace = mnt->mnt_namespace;
+ if (!namespace || atomic_read(&namespace->count) <= 0)
+ continue;
+ get_namespace(namespace);
+
+ spin_unlock(&vfsmount_lock);
+ down_write(&namespace->sem);
+ spin_lock(&vfsmount_lock);
+
+ if (atomic_read(&mnt->mnt_count) == 2) {
+ struct vfsmount *xdmnt;
+ struct dentry *xdentry;
+
+ list_del_init(&mnt->mnt_list);
+ list_del_init(&mnt->mnt_child);
+ list_del_init(&mnt->mnt_hash);
+ mnt->mnt_mountpoint->d_mounted--;
+
+ xdentry = mnt->mnt_mountpoint;
+ mnt->mnt_mountpoint = mnt->mnt_root;
+ xdmnt = mnt->mnt_parent;
+ mnt->mnt_parent = mnt;
+ spin_unlock(&vfsmount_lock);
+
+ mntput(xdmnt);
+ dput(xdentry);
+
+ if (atomic_read(&mnt->mnt_sb->s_active) == 1) {
+ /* last instance - try to be smart */
+ lock_kernel();
+ DQUOT_OFF(mnt->mnt_sb);
+ acct_auto_close(mnt->mnt_sb);
+ unlock_kernel();
+ }
+
+ mntput(mnt);
+ }
+ else {
+ list_add_tail(&mnt->mnt_fslink, mounts);
+ spin_unlock(&vfsmount_lock);
+ }
+
+ up_write(&namespace->sem);
+
+ mntput(mnt);
+ put_namespace(namespace);
+
+ spin_lock(&vfsmount_lock);
+ }
+
+ spin_unlock(&vfsmount_lock);
+}
+
+EXPORT_SYMBOL_GPL(mark_mounts_for_expiry);
+
int copy_mount_options (const void __user *data, unsigned long *where)
{
int i;
@@ -860,7 +982,7 @@
else if (flags & MS_MOVE)
retval = do_move_mount(&nd, dev_name);
else
- retval = do_add_mount(&nd, type_page, flags, mnt_flags,
+ retval = do_new_mount(&nd, type_page, flags, mnt_flags,
dev_name, data_page);
dput_out:
path_release(&nd);
@@ -1185,6 +1307,7 @@
init_rwsem(&namespace->sem);
list_add(&mnt->mnt_list, &namespace->list);
namespace->root = mnt;
+ mnt->mnt_namespace = namespace;
init_task.namespace = namespace;
read_lock(&tasklist_lock);
@@ -1252,8 +1375,15 @@
void __put_namespace(struct namespace *namespace)
{
+ struct vfsmount *mnt;
+
down_write(&namespace->sem);
spin_lock(&vfsmount_lock);
+
+ list_for_each_entry(mnt, &namespace->list, mnt_list) {
+ mnt->mnt_namespace = NULL;
+ }
+
umount_tree(namespace->root);
spin_unlock(&vfsmount_lock);
up_write(&namespace->sem);
diff -uNr linux-2.6.7/fs/super.c linux-2.6.7-auto/fs/super.c
--- linux-2.6.7/fs/super.c 2004-06-18 13:44:04.000000000 +0100
+++ linux-2.6.7-auto/fs/super.c 2004-06-25 13:50:04.000000000 +0100
@@ -788,6 +788,7 @@
mnt->mnt_root = dget(sb->s_root);
mnt->mnt_mountpoint = sb->s_root;
mnt->mnt_parent = mnt;
+ mnt->mnt_namespace = current->namespace;
up_write(&sb->s_umount);
put_filesystem(type);
return mnt;
@@ -804,6 +805,8 @@
return (struct vfsmount *)sb;
}
+EXPORT_SYMBOL_GPL(do_kern_mount);
+
struct vfsmount *kern_mount(struct file_system_type *type)
{
return do_kern_mount(type->name, 0, type->name, NULL);
diff -uNr linux-2.6.7/include/linux/fs.h linux-2.6.7-auto/include/linux/fs.h
--- linux-2.6.7/include/linux/fs.h 2004-06-18 13:44:05.000000000 +0100
+++ linux-2.6.7-auto/include/linux/fs.h 2004-06-25 13:48:35.000000000 +0100
@@ -714,6 +714,7 @@
#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 -uNr linux-2.6.7/include/linux/mount.h linux-2.6.7-auto/include/linux/mount.h
--- linux-2.6.7/include/linux/mount.h 2004-06-18 13:42:15.000000000 +0100
+++ linux-2.6.7-auto/include/linux/mount.h 2004-06-25 13:48:35.000000000 +0100
@@ -29,8 +29,11 @@
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 @@
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)
+{
+ 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 -uNr linux-2.6.7/include/linux/namei.h linux-2.6.7-auto/include/linux/namei.h
--- linux-2.6.7/include/linux/namei.h 2004-06-18 13:42:16.000000000 +0100
+++ linux-2.6.7-auto/include/linux/namei.h 2004-06-25 13:48:35.000000000 +0100
@@ -57,6 +57,7 @@
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 -uNr linux-2.6.7/include/linux/namespace.h linux-2.6.7-auto/include/linux/namespace.h
--- linux-2.6.7/include/linux/namespace.h 2004-06-18 13:42:16.000000000 +0100
+++ linux-2.6.7-auto/include/linux/namespace.h 2004-06-25 13:48:35.000000000 +0100
@@ -14,7 +14,7 @@
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)
{
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH] intrinsic automount and mountpoint degradation support
@ 2004-06-30 19:41 David Howells
2004-06-30 19:57 ` Andrew Morton
0 siblings, 1 reply; 3+ messages in thread
From: David Howells @ 2004-06-30 19:41 UTC (permalink / raw)
To: torvalds, akpm; +Cc: linux-kernel, viro
Hi Linus, Andrew,
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.
David
diff -uNr linux-2.6.7/fs/namei.c linux-2.6.7-auto/fs/namei.c
--- linux-2.6.7/fs/namei.c 2004-06-18 13:44:02.000000000 +0100
+++ linux-2.6.7-auto/fs/namei.c 2004-06-25 13:48:28.000000000 +0100
@@ -278,6 +278,12 @@
mntput(nd->mnt);
}
+void path_release_on_umount(struct nameidata *nd)
+{
+ dput(nd->dentry);
+ _mntput(nd->mnt);
+}
+
/*
* Internal lookup() using the new generic dcache.
* SMP-safe
diff -uNr linux-2.6.7/fs/namespace.c linux-2.6.7-auto/fs/namespace.c
--- linux-2.6.7/fs/namespace.c 2004-06-18 13:44:02.000000000 +0100
+++ linux-2.6.7-auto/fs/namespace.c 2004-06-30 19:43:14.565098078 +0100
@@ -60,6 +60,7 @@
INIT_LIST_HEAD(&mnt->mnt_child);
INIT_LIST_HEAD(&mnt->mnt_mounts);
INIT_LIST_HEAD(&mnt->mnt_list);
+ INIT_LIST_HEAD(&mnt->mnt_fslink);
if (name) {
int size = strlen(name)+1;
char *newname = kmalloc(size, GFP_KERNEL);
@@ -106,13 +107,9 @@
EXPORT_SYMBOL(lookup_mnt);
-static int check_mnt(struct vfsmount *mnt)
+static inline int check_mnt(struct vfsmount *mnt)
{
- spin_lock(&vfsmount_lock);
- while (mnt->mnt_parent != mnt)
- mnt = mnt->mnt_parent;
- spin_unlock(&vfsmount_lock);
- return mnt == current->namespace->root;
+ return mnt->mnt_namespace == current->namespace;
}
static void detach_mnt(struct vfsmount *mnt, struct nameidata *old_nd)
@@ -164,6 +161,11 @@
mnt->mnt_root = dget(root);
mnt->mnt_mountpoint = mnt->mnt_root;
mnt->mnt_parent = mnt;
+ mnt->mnt_namespace = old->mnt_namespace;
+ spin_lock(&vfsmount_lock);
+ if (!list_empty(&old->mnt_fslink))
+ list_add(&mnt->mnt_fslink, &old->mnt_fslink);
+ spin_unlock(&vfsmount_lock);
}
return mnt;
}
@@ -346,6 +348,7 @@
while (!list_empty(&kill)) {
mnt = list_entry(kill.next, struct vfsmount, mnt_list);
list_del_init(&mnt->mnt_list);
+ list_del_init(&mnt->mnt_fslink);
if (mnt->mnt_parent == mnt) {
spin_unlock(&vfsmount_lock);
} else {
@@ -369,6 +372,24 @@
return retval;
/*
+ * If we've been asked to mark for expiry, we only _actually_ effect
+ * the unmount if:
+ * (1) the mark is already set (the mark is cleared by mntput())
+ * (2) the usage count == 1 [parent vfsmount] + 1 [sys_umount]
+ */
+ if (flags & MNT_EXPIRE) {
+ if (mnt == current->fs->rootmnt ||
+ flags & (MNT_FORCE | MNT_DETACH))
+ return -EINVAL;
+
+ if (atomic_read(&mnt->mnt_count) != 2)
+ return -EBUSY;
+
+ if (!xchg(&mnt->mnt_expiry_mark, 1))
+ return -EAGAIN;
+ }
+
+ /*
* If we may have to abort operations to get out of this
* mount, and they will themselves hold resources we must
* allow the fs to do things. In the Unix tradition of
@@ -461,7 +482,7 @@
retval = do_umount(nd.mnt, flags);
dput_and_out:
- path_release(&nd);
+ path_release_on_umount(&nd);
out:
return retval;
}
@@ -618,6 +639,10 @@
}
if (mnt) {
+ spin_lock(&vfsmount_lock);
+ list_del_init(&mnt->mnt_fslink);
+ spin_unlock(&vfsmount_lock);
+
err = graft_tree(mnt, nd);
if (err) {
spin_lock(&vfsmount_lock);
@@ -638,7 +663,8 @@
* on it - tough luck.
*/
-static int do_remount(struct nameidata *nd,int flags,int mnt_flags,void *data)
+static int do_remount(struct nameidata *nd, int flags, int mnt_flags,
+ void *data)
{
int err;
struct super_block * sb = nd->mnt->mnt_sb;
@@ -710,6 +736,7 @@
detach_mnt(old_nd.mnt, &parent_nd);
attach_mnt(old_nd.mnt, nd);
+ list_del_init(&old_nd.mnt->mnt_fslink);
out2:
spin_unlock(&vfsmount_lock);
out1:
@@ -722,11 +749,10 @@
return err;
}
-static int do_add_mount(struct nameidata *nd, char *type, int flags,
+static int do_new_mount(struct nameidata *nd, char *type, int flags,
int mnt_flags, char *name, void *data)
{
struct vfsmount *mnt;
- int err;
if (!type || !memchr(type, 0, PAGE_SIZE))
return -EINVAL;
@@ -736,9 +762,16 @@
return -EPERM;
mnt = do_kern_mount(type, flags, name, data);
- err = PTR_ERR(mnt);
if (IS_ERR(mnt))
- goto out;
+ return PTR_ERR(mnt);
+
+ return do_add_mount(mnt, nd, mnt_flags, NULL);
+}
+
+int do_add_mount(struct vfsmount *newmnt, struct nameidata *nd,
+ int mnt_flags, struct list_head *fslist)
+{
+ int err;
down_write(¤t->namespace->sem);
/* Something was mounted here while we slept */
@@ -750,22 +783,111 @@
/* Refuse the same filesystem on the same mount point */
err = -EBUSY;
- if (nd->mnt->mnt_sb == mnt->mnt_sb && nd->mnt->mnt_root == nd->dentry)
+ if (nd->mnt->mnt_sb == newmnt->mnt_sb &&
+ nd->mnt->mnt_root == nd->dentry)
goto unlock;
err = -EINVAL;
- if (S_ISLNK(mnt->mnt_root->d_inode->i_mode))
+ if (S_ISLNK(newmnt->mnt_root->d_inode->i_mode))
goto unlock;
- mnt->mnt_flags = mnt_flags;
- err = graft_tree(mnt, nd);
+ newmnt->mnt_flags = mnt_flags;
+ err = graft_tree(newmnt, nd);
+
+ if (err == 0 && fslist) {
+ spin_lock(&vfsmount_lock);
+ list_add_tail(&newmnt->mnt_fslink, fslist);
+ spin_unlock(&vfsmount_lock);
+ }
+
unlock:
up_write(¤t->namespace->sem);
- mntput(mnt);
-out:
+ mntput(newmnt);
return err;
}
+EXPORT_SYMBOL_GPL(do_add_mount);
+
+void mark_mounts_for_expiry(struct list_head *mounts)
+{
+ struct namespace *namespace;
+ struct list_head graveyard, *_p, *_n;
+ struct vfsmount *mnt;
+
+ INIT_LIST_HEAD(&graveyard);
+
+ spin_lock(&vfsmount_lock);
+
+ list_for_each_safe(_p, _n, mounts) {
+ mnt = list_entry(_p, struct vfsmount, mnt_fslink);
+
+ if (!xchg(&mnt->mnt_expiry_mark, 1) ||
+ atomic_read(&mnt->mnt_count) != 1)
+ continue;
+
+ mntget(mnt);
+ list_move(&mnt->mnt_fslink, &graveyard);
+ }
+
+ while (!list_empty(&graveyard)) {
+ mnt = list_entry(graveyard.next, struct vfsmount, mnt_fslink);
+ list_del_init(&mnt->mnt_fslink);
+
+ namespace = mnt->mnt_namespace;
+ if (!namespace || atomic_read(&namespace->count) <= 0)
+ continue;
+ get_namespace(namespace);
+
+ spin_unlock(&vfsmount_lock);
+ down_write(&namespace->sem);
+ spin_lock(&vfsmount_lock);
+
+ if (atomic_read(&mnt->mnt_count) == 2) {
+ struct vfsmount *xdmnt;
+ struct dentry *xdentry;
+
+ list_del_init(&mnt->mnt_list);
+ list_del_init(&mnt->mnt_child);
+ list_del_init(&mnt->mnt_hash);
+ mnt->mnt_mountpoint->d_mounted--;
+
+ xdentry = mnt->mnt_mountpoint;
+ mnt->mnt_mountpoint = mnt->mnt_root;
+ xdmnt = mnt->mnt_parent;
+ mnt->mnt_parent = mnt;
+ spin_unlock(&vfsmount_lock);
+
+ mntput(xdmnt);
+ dput(xdentry);
+
+ if (atomic_read(&mnt->mnt_sb->s_active) == 1) {
+ /* last instance - try to be smart */
+ lock_kernel();
+ DQUOT_OFF(mnt->mnt_sb);
+ acct_auto_close(mnt->mnt_sb);
+ unlock_kernel();
+ }
+
+ mntput(mnt);
+ }
+ else {
+ list_add_tail(&mnt->mnt_fslink, mounts);
+ spin_unlock(&vfsmount_lock);
+ }
+
+ up_write(&namespace->sem);
+
+ mntput(mnt);
+ put_namespace(namespace);
+
+ spin_lock(&vfsmount_lock);
+ }
+
+ spin_unlock(&vfsmount_lock);
+}
+
+EXPORT_SYMBOL_GPL(mark_mounts_for_expiry);
+
int copy_mount_options (const void __user *data, unsigned long *where)
{
int i;
@@ -860,7 +982,7 @@
else if (flags & MS_MOVE)
retval = do_move_mount(&nd, dev_name);
else
- retval = do_add_mount(&nd, type_page, flags, mnt_flags,
+ retval = do_new_mount(&nd, type_page, flags, mnt_flags,
dev_name, data_page);
dput_out:
path_release(&nd);
@@ -1185,6 +1307,7 @@
init_rwsem(&namespace->sem);
list_add(&mnt->mnt_list, &namespace->list);
namespace->root = mnt;
+ mnt->mnt_namespace = namespace;
init_task.namespace = namespace;
read_lock(&tasklist_lock);
@@ -1252,8 +1375,15 @@
void __put_namespace(struct namespace *namespace)
{
+ struct vfsmount *mnt;
+
down_write(&namespace->sem);
spin_lock(&vfsmount_lock);
+
+ list_for_each_entry(mnt, &namespace->list, mnt_list) {
+ mnt->mnt_namespace = NULL;
+ }
+
umount_tree(namespace->root);
spin_unlock(&vfsmount_lock);
up_write(&namespace->sem);
diff -uNr linux-2.6.7/fs/super.c linux-2.6.7-auto/fs/super.c
--- linux-2.6.7/fs/super.c 2004-06-18 13:44:04.000000000 +0100
+++ linux-2.6.7-auto/fs/super.c 2004-06-25 13:50:04.000000000 +0100
@@ -788,6 +788,7 @@
mnt->mnt_root = dget(sb->s_root);
mnt->mnt_mountpoint = sb->s_root;
mnt->mnt_parent = mnt;
+ mnt->mnt_namespace = current->namespace;
up_write(&sb->s_umount);
put_filesystem(type);
return mnt;
@@ -804,6 +805,8 @@
return (struct vfsmount *)sb;
}
+EXPORT_SYMBOL_GPL(do_kern_mount);
+
struct vfsmount *kern_mount(struct file_system_type *type)
{
return do_kern_mount(type->name, 0, type->name, NULL);
diff -uNr linux-2.6.7/include/linux/fs.h linux-2.6.7-auto/include/linux/fs.h
--- linux-2.6.7/include/linux/fs.h 2004-06-18 13:44:05.000000000 +0100
+++ linux-2.6.7-auto/include/linux/fs.h 2004-06-25 13:48:35.000000000 +0100
@@ -714,6 +714,7 @@
#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 -uNr linux-2.6.7/include/linux/mount.h linux-2.6.7-auto/include/linux/mount.h
--- linux-2.6.7/include/linux/mount.h 2004-06-18 13:42:15.000000000 +0100
+++ linux-2.6.7-auto/include/linux/mount.h 2004-06-25 13:48:35.000000000 +0100
@@ -29,8 +29,11 @@
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 @@
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)
+{
+ 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 -uNr linux-2.6.7/include/linux/namei.h linux-2.6.7-auto/include/linux/namei.h
--- linux-2.6.7/include/linux/namei.h 2004-06-18 13:42:16.000000000 +0100
+++ linux-2.6.7-auto/include/linux/namei.h 2004-06-25 13:48:35.000000000 +0100
@@ -57,6 +57,7 @@
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 -uNr linux-2.6.7/include/linux/namespace.h linux-2.6.7-auto/include/linux/namespace.h
--- linux-2.6.7/include/linux/namespace.h 2004-06-18 13:42:16.000000000 +0100
+++ linux-2.6.7-auto/include/linux/namespace.h 2004-06-25 13:48:35.000000000 +0100
@@ -14,7 +14,7 @@
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)
{
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] intrinsic automount and mountpoint degradation support
2004-06-30 19:41 David Howells
@ 2004-06-30 19:57 ` Andrew Morton
0 siblings, 0 replies; 3+ messages in thread
From: Andrew Morton @ 2004-06-30 19:57 UTC (permalink / raw)
To: David Howells; +Cc: torvalds, linux-kernel, viro
David Howells <dhowells@redhat.com> wrote:
>
> 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.
Please don't try to add uncommented code to the kernel.
How does this work?
Why is autofs unsuitable?
Apart from documenting the major functions and data structures, comments
are also needed which describe the interpretation of ->mnt_count. This:
+ if (atomic_read(&mnt->mnt_count) == 2) {
is otherwise incomprehensible.
Apart from making the code maintainable, tasteful commentary and covering
documentation makes the patch review process much more fruitful. Please
have a think about that, and resend?
Thanks.
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2004-06-30 19:59 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-06-30 19:35 [PATCH] intrinsic automount and mountpoint degradation support David Howells
-- strict thread matches above, loose matches on Subject: below --
2004-06-30 19:41 David Howells
2004-06-30 19:57 ` Andrew Morton
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox