Messages in this thread Patch in this message | | | Date | Sun, 13 Jan 2002 07:56:20 -0500 (EST) | From | Alexander Viro <> | Subject | Re: binfmt_misc module gets stuck |
| |
On Tue, 8 Jan 2002, Pavel Roskin wrote:
> I believe that kern_mount() and kern_umount() are remnants from the time > when the binfmt_misc filesystem was mounted automatically by the kernel. > Removing them preserves all functionality (I did check it) while allows > unloading binfmt_misc if and only if the binfmt_misc filesystem is not > used for any mounts.
That's wrong - you are using that tree to store information (entries you've defined), so the lifetime should be "there are mounts or there are entries". Which is actually pretty easy to implement - see if the following (completely untested) patch works for you. It should give the following rules: if you had defined some entries - they stay alive until you remove them, mounted or not (i.e. umount /proc/sys/binfmt_misc && mount ... will not destroy any state) if there is no entries and fs is not mounted - you can rmmod.
diff -urN C2-pre11-grow_page_buffers/fs/binfmt_misc.c C2-pre11-current/fs/binfmt_misc.c --- C2-pre11-grow_page_buffers/fs/binfmt_misc.c Sat Oct 20 22:14:42 2001 +++ C2-pre11-current/fs/binfmt_misc.c Sun Jan 13 06:53:30 2002 @@ -49,6 +49,8 @@ } Node; static rwlock_t entries_lock __attribute__((unused)) = RW_LOCK_UNLOCKED; +static struct vfsmount *bm_mnt; +static int entry_count = 0; /* * Check if we support the binfmt @@ -390,10 +392,15 @@ Node *e = inode->u.generic_ip; if (e) { + struct vfsmount *mnt; write_lock(&entries_lock); list_del(&e->list); + mnt = bm_mnt; + if (!--entry_count) + bm_mnt = NULL; write_unlock(&entries_lock); kfree(e); + mntput(mnt); } } @@ -404,8 +411,7 @@ write_lock(&entries_lock); dentry = e->dentry; if (dentry) { - list_del(&e->list); - INIT_LIST_HEAD(&e->list); + list_del_init(&e->list); e->dentry = NULL; } write_unlock(&entries_lock); @@ -484,12 +490,16 @@ write: bm_entry_write, }; +static struct file_system_type bm_fs_type; + /* /register */ static ssize_t bm_register_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) { Node *e; + struct inode *inode; + struct vfsmount *mnt = NULL; struct dentry *root, *dentry; struct super_block *sb = file->f_vfsmnt->mnt_sb; int err = 0; @@ -503,31 +513,52 @@ down(&root->d_inode->i_sem); dentry = lookup_one_len(e->name, root, strlen(e->name)); err = PTR_ERR(dentry); - if (!IS_ERR(dentry)) { - down(&root->d_inode->i_zombie); - if (dentry->d_inode) { - err = -EEXIST; - } else { - struct inode * inode = bm_get_inode(sb, S_IFREG | 0644); - err = -ENOMEM; + if (IS_ERR(dentry)) + goto out; - if (inode) { - write_lock(&entries_lock); + down(&root->d_inode->i_zombie); - e->dentry = dget(dentry); - inode->u.generic_ip = e; - inode->i_fop = &bm_entry_operations; - d_instantiate(dentry, inode); + err = -EEXIST; + if (dentry->d_inode) + goto out2; - list_add(&e->list, &entries); - write_unlock(&entries_lock); + inode = bm_get_inode(sb, S_IFREG | 0644); - err = 0; - } + err = -ENOMEM; + if (!inode) + goto out2; + + write_lock(&entries_lock); + if (!bm_mnt) { + write_unlock(&entries_lock); + mnt = kern_mount(&bm_fs_type); + if (IS_ERR(mnt)) { + err = PTR_ERR(mnt); + iput(inode); + inode = NULL; + goto out2; } - up(&root->d_inode->i_zombie); - dput(dentry); + write_lock(&entries_lock); + if (!bm_mnt) + bm_mnt = mnt; } + mntget(bm_mnt); + entry_count++; + + e->dentry = dget(dentry); + inode->u.generic_ip = e; + inode->i_fop = &bm_entry_operations; + d_instantiate(dentry, inode); + + list_add(&e->list, &entries); + write_unlock(&entries_lock); + + mntput(mnt); + err = 0; +out2: + up(&root->d_inode->i_zombie); + dput(dentry); +out: up(&root->d_inode->i_sem); dput(root); @@ -687,23 +718,13 @@ static DECLARE_FSTYPE(bm_fs_type, "binfmt_misc", bm_read_super, FS_SINGLE|FS_LITTER); -static struct vfsmount *bm_mnt; - static int __init init_misc_binfmt(void) { int err = register_filesystem(&bm_fs_type); if (!err) { - bm_mnt = kern_mount(&bm_fs_type); - err = PTR_ERR(bm_mnt); - if (IS_ERR(bm_mnt)) + err = register_binfmt(&misc_format); + if (err) unregister_filesystem(&bm_fs_type); - else { - err = register_binfmt(&misc_format); - if (err) { - unregister_filesystem(&bm_fs_type); - kern_umount(bm_mnt); - } - } } return err; } @@ -712,7 +733,6 @@ { unregister_binfmt(&misc_format); unregister_filesystem(&bm_fs_type); - kern_umount(bm_mnt); } EXPORT_NO_SYMBOLS; - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |