[RFC][PATCH] /proc/dead_mounts support (Was: [RFC][PATCH] rbind across ...)

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

 



> I have a better idea:
> 
>  - create a "dead_mounts" namespace.
>  - chain each detached mount's ->mnt_list on dead_mounts->list
>  - set mnt_namespace to dead_mounts
>  - export the list via proc through the usual mount list interface
> 
> The last would be a nice bonus: I've always wanted to see the list of
> detached, but not-yet destroyed mounts.

Here's a patch that does this.  It needs all the other namespace
patches, so I made a diff against 2.6.12-rc4-mm2 in case anybody wants
to try it:

  http://www.inf.bme.hu/~mszeredi/patches/patch-2.6.12-rc4-mm2-szm1

It works for me(TM).

Miklos

Index: linux/include/linux/proc_fs.h
===================================================================
--- linux.orig/include/linux/proc_fs.h	2005-05-22 16:09:37.000000000 +0200
+++ linux/include/linux/proc_fs.h	2005-05-22 16:09:45.000000000 +0200
@@ -127,6 +127,7 @@ extern struct dentry *proc_lookup(struct
 extern struct file_operations proc_kcore_operations;
 extern struct file_operations proc_kmsg_operations;
 extern struct file_operations ppc_htab_operations;
+extern struct file_operations proc_dead_mounts_operations;
 
 /*
  * proc_tty.c
Index: linux/fs/proc/proc_misc.c
===================================================================
--- linux.orig/fs/proc/proc_misc.c	2005-05-22 16:09:37.000000000 +0200
+++ linux/fs/proc/proc_misc.c	2005-05-22 16:09:45.000000000 +0200
@@ -652,6 +652,9 @@ void __init proc_misc_init(void)
 		create_proc_read_entry(p->name, 0, NULL, p->read_proc, NULL);
 
 	proc_symlink("mounts", NULL, "self/mounts");
+	entry = create_proc_entry("dead_mounts", S_IRUSR, &proc_root);
+	if (entry)
+		entry->proc_fops = &proc_dead_mounts_operations;
 
 	/* And now for trickier ones */
 	entry = create_proc_entry("kmsg", S_IRUSR, &proc_root);
Index: linux/fs/namespace.c
===================================================================
--- linux.orig/fs/namespace.c	2005-05-22 16:09:45.000000000 +0200
+++ linux/fs/namespace.c	2005-05-22 16:12:23.000000000 +0200
@@ -42,6 +42,7 @@ static inline int sysfs_init(void)
 static struct list_head *mount_hashtable;
 static int hash_mask, hash_bits;
 static kmem_cache_t *mnt_cache; 
+static struct namespace *dead_mounts;
 
 static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry)
 {
@@ -175,6 +176,8 @@ clone_mnt(struct vfsmount *old, struct d
 void __mntput(struct vfsmount *mnt)
 {
 	struct super_block *sb = mnt->mnt_sb;
+	list_del(&mnt->mnt_list);
+	spin_unlock(&vfsmount_lock);
 	dput(mnt->mnt_root);
 	free_vfsmnt(mnt);
 	deactivate_super(sb);
@@ -240,7 +243,10 @@ static int show_vfsmnt(struct seq_file *
 
 	mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none");
 	seq_putc(m, ' ');
-	seq_path(m, mnt, mnt->mnt_root, " \t\n\\");
+	if (mnt->mnt_namespace != dead_mounts)
+		seq_path(m, mnt, mnt->mnt_root, " \t\n\\");
+	else
+		seq_puts(m, "(detached)");
 	seq_putc(m, ' ');
 	mangle(m, mnt->mnt_sb->s_type->name);
 	seq_puts(m, mnt->mnt_sb->s_flags & MS_RDONLY ? " ro" : " rw");
@@ -265,6 +271,71 @@ struct seq_operations mounts_op = {
 	.show	= show_vfsmnt
 };
 
+/* /proc/dead_mounts needs slightly different handling than above */
+static void *dead_m_start(struct seq_file *m, loff_t *pos)
+{
+	struct namespace *n = m->private;
+	struct vfsmount *res = NULL;
+	struct list_head *p;
+	loff_t l = *pos;
+
+	spin_lock(&vfsmount_lock);
+	list_for_each(p, &n->list)
+		if (!l--) {
+			res = mntget(list_entry(p, struct vfsmount, mnt_list));
+			break;
+		}
+	spin_unlock(&vfsmount_lock);
+	return res;
+}
+
+static void *dead_m_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	struct namespace *n = m->private;
+	struct vfsmount *curr = v;
+	struct vfsmount *res = NULL;
+	struct list_head *p;
+
+	(*pos)++;
+	spin_lock(&vfsmount_lock);
+	p = curr->mnt_list.next;
+	if (p != &n->list)
+		res = mntget(list_entry(p, struct vfsmount, mnt_list));
+	spin_unlock(&vfsmount_lock);
+	mntput(curr);
+	return res;
+}
+
+static void dead_m_stop(struct seq_file *m, void *v)
+{
+	struct vfsmount *curr = v;
+	mntput(curr);
+}
+
+static struct seq_operations dead_mounts_op = {
+	.start	= dead_m_start,
+	.next	= dead_m_next,
+	.stop	= dead_m_stop,
+	.show	= show_vfsmnt
+};
+
+static int dead_mounts_open(struct inode *inode, struct file *file)
+{
+	int ret = seq_open(file, &dead_mounts_op);
+	if (!ret) {
+		struct seq_file *m = file->private_data;
+		m->private = dead_mounts;
+	}
+	return ret;
+}
+
+struct file_operations proc_dead_mounts_operations = {
+	.open		= dead_mounts_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
+};
+
 /**
  * may_umount_tree - check if a mount tree is busy
  * @mnt: root of mount tree
@@ -343,14 +414,13 @@ static void umount_tree(struct vfsmount 
 	LIST_HEAD(kill);
 
 	for (p = mnt; p; p = next_mnt(p, mnt)) {
-		list_del(&p->mnt_list);
-		list_add(&p->mnt_list, &kill);
-		p->mnt_namespace = NULL;
+		list_move(&p->mnt_list, &kill);
+		p->mnt_namespace = dead_mounts;
 	}
 
 	while (!list_empty(&kill)) {
 		mnt = list_entry(kill.next, struct vfsmount, mnt_list);
-		list_del_init(&mnt->mnt_list);
+		list_move_tail(&mnt->mnt_list, &dead_mounts->list);
 		list_del_init(&mnt->mnt_fslink);
 		if (mnt->mnt_parent == mnt) {
 			spin_unlock(&vfsmount_lock);
@@ -447,7 +517,7 @@ static int do_umount(struct vfsmount *mn
 	}
 	retval = -EBUSY;
 	if (atomic_read(&mnt->mnt_count) == 2 || flags & MNT_DETACH) {
-		if (!list_empty(&mnt->mnt_list))
+		if (mnt->mnt_namespace != dead_mounts)
 			umount_tree(mnt);
 		retval = 0;
 	}
@@ -842,8 +912,8 @@ static void expire_mount(struct vfsmount
 		struct nameidata old_nd;
 
 		/* delete from the namespace */
-		list_del_init(&mnt->mnt_list);
-		mnt->mnt_namespace = NULL;
+		list_move_tail(&mnt->mnt_list, &dead_mounts->list);
+		mnt->mnt_namespace = dead_mounts;
 		detach_mnt(mnt, &old_nd);
 		spin_unlock(&vfsmount_lock);
 		path_release(&old_nd);
@@ -1387,6 +1457,14 @@ static void __init init_mount_tree(void)
 	namespace->root = mnt;
 	mnt->mnt_namespace = namespace;
 
+	dead_mounts = kmalloc(sizeof(struct namespace), GFP_KERNEL);
+	if (!dead_mounts)
+		panic("Can't allocate dead_mounts namespace");
+	atomic_set(&dead_mounts->count, 1);
+	INIT_LIST_HEAD(&dead_mounts->list);
+	init_rwsem(&dead_mounts->sem);
+	dead_mounts->root = NULL;
+
 	init_task.namespace = namespace;
 	read_lock(&tasklist_lock);
 	do_each_thread(g, p) {
Index: linux/include/linux/mount.h
===================================================================
--- linux.orig/include/linux/mount.h	2005-05-22 16:09:37.000000000 +0200
+++ linux/include/linux/mount.h	2005-05-22 16:09:45.000000000 +0200
@@ -46,11 +46,12 @@ static inline struct vfsmount *mntget(st
 }
 
 extern void __mntput(struct vfsmount *mnt);
+extern spinlock_t vfsmount_lock;
 
 static inline void _mntput(struct vfsmount *mnt)
 {
 	if (mnt) {
-		if (atomic_dec_and_test(&mnt->mnt_count))
+		if (atomic_dec_and_lock(&mnt->mnt_count, &vfsmount_lock))
 			__mntput(mnt);
 	}
 }
@@ -75,7 +76,5 @@ extern int do_add_mount(struct vfsmount 
 
 extern void mark_mounts_for_expiry(struct list_head *mounts);
 
-extern spinlock_t vfsmount_lock;
-
 #endif
 #endif /* _LINUX_MOUNT_H */
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux