Messages in this thread Patch in this message |  | | Date | Fri, 14 Sep 2001 15:02:31 -0400 (EDT) | From | Alexander Viro <> | Subject | [PATCH] lazy umount (2/4) |
| |
Part 2/4: Added minimal rootfs (read-only root directory - absolute minimum, just to have something to go with root vfsmount), Now we have a fixed root vfsmount and that allows to kill a lot of special-casing,
diff -urN S10-pre9-move_vfsmnt/fs/super.c S10-pre9-root_vfsmnt/fs/super.c --- S10-pre9-move_vfsmnt/fs/super.c Fri Sep 14 14:02:32 2001 +++ S10-pre9-root_vfsmnt/fs/super.c Fri Sep 14 14:03:34 2001 @@ -280,6 +280,7 @@ } static LIST_HEAD(vfsmntlist); +static struct vfsmount *root_vfsmnt; static struct list_head *mount_hashtable; static int hash_mask, hash_bits; @@ -346,52 +347,6 @@ nd->dentry->d_mounted++; } -/** - * add_vfsmnt - add a new mount node - * @nd: location of mountpoint or %NULL if we want a root node - * @root: root of (sub)tree to be mounted - * @dev_name: device name to show in /proc/mounts or %NULL (for "none"). - * - * This is VFS idea of mount. New node is allocated, bound to a tree - * we are mounting and optionally (OK, usually) registered as mounted - * on a given mountpoint. Returns a pointer to new node or %NULL in - * case of failure. - * - * Potential reason for failure (aside of trivial lack of memory) is a - * deleted mountpoint. Caller must hold ->i_zombie on mountpoint - * dentry (if any). - */ - -static struct vfsmount *add_vfsmnt(struct dentry *root, const char *dev_name) -{ - struct vfsmount *mnt; - struct super_block *sb = root->d_inode->i_sb; - char *name; - - mnt = alloc_vfsmnt(); - if (!mnt) - goto out; - - /* It may be NULL, but who cares? */ - if (dev_name) { - name = kmalloc(strlen(dev_name)+1, GFP_KERNEL); - if (name) { - strcpy(name, dev_name); - mnt->mnt_devname = name; - } - } - mnt->mnt_sb = sb; - mnt->mnt_root = dget(root); - mnt->mnt_mountpoint = mnt->mnt_root; - mnt->mnt_parent = mnt; - - spin_lock(&dcache_lock); - list_add(&mnt->mnt_list, vfsmntlist.prev); - spin_unlock(&dcache_lock); -out: - return mnt; -} - static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root) { char *name = old->mnt_devname; @@ -1200,8 +1155,7 @@ list_del(&mnt->mnt_list); spin_unlock(&dcache_lock); mntput(mnt); - if (parent_nd.mnt != mnt) - path_release(&parent_nd); + path_release(&parent_nd); return 0; } spin_unlock(&dcache_lock); @@ -1241,8 +1195,7 @@ list_del(&mnt->mnt_list); spin_unlock(&dcache_lock); mntput(mnt); - if (parent_nd.mnt != mnt) - path_release(&parent_nd); + path_release(&parent_nd); return 0; } @@ -1601,6 +1554,7 @@ void __init mount_root(void) { + struct nameidata root_nd; struct file_system_type * fs_type; struct super_block * sb; struct vfsmount *vfsmnt; @@ -1610,6 +1564,7 @@ void *handle; char path[64]; int path_start = -1; + char *name = "/dev/root"; #ifdef CONFIG_ROOT_NFS void *data; @@ -1746,13 +1701,26 @@ fs_type->name, (sb->s_flags & MS_RDONLY) ? " readonly" : ""); if (path_start >= 0) { + name = path + path_start; devfs_mk_symlink (NULL, "root", DEVFS_FL_DEFAULT, - path + 5 + path_start, NULL, NULL); - memcpy (path + path_start, "/dev/", 5); - vfsmnt = add_vfsmnt(sb->s_root, path + path_start); + name + 5, NULL, NULL); + memcpy (name, "/dev/", 5); } - else - vfsmnt = add_vfsmnt(sb->s_root, "/dev/root"); + vfsmnt = alloc_vfsmnt(); + if (!vfsmnt) + panic("VFS: alloc_vfsmnt failed for root fs"); + + vfsmnt->mnt_devname = kmalloc(strlen(name)+1, GFP_KERNEL); + if (vfsmnt->mnt_devname) + strcpy(vfsmnt->mnt_devname, name); + vfsmnt->mnt_sb = sb; + vfsmnt->mnt_root = dget(sb->s_root); + + root_nd.mnt = root_vfsmnt; + root_nd.dentry = root_vfsmnt->mnt_sb->s_root; + graft_tree(vfsmnt, &root_nd); + mntput(vfsmnt); + /* FIXME: if something will try to umount us right now... */ if (vfsmnt) { set_fs_root(current->fs, vfsmnt, sb->s_root); @@ -1761,10 +1729,8 @@ bdput(bdev); /* sb holds a reference */ return; } - panic("VFS: add_vfsmnt failed for root fs"); } - static void chroot_fs_refs(struct dentry *old_root, struct vfsmount *old_rootmnt, struct dentry *new_root, @@ -1878,15 +1844,12 @@ detach_mnt(new_nd.mnt, &parent_nd); detach_mnt(root_mnt, &root_parent); attach_mnt(root_mnt, &old_nd); - if (root_parent.mnt != root_mnt) - attach_mnt(new_nd.mnt, &root_parent); + attach_mnt(new_nd.mnt, &root_parent); spin_unlock(&dcache_lock); chroot_fs_refs(root,root_mnt,new_nd.dentry,new_nd.mnt); error = 0; - if (root_parent.mnt != root_mnt) - path_release(&root_parent); - if (parent_nd.mnt != new_nd.mnt) - path_release(&parent_nd); + path_release(&root_parent); + path_release(&parent_nd); out2: up(&old_nd.dentry->d_inode->i_zombie); up(&mount_sem); @@ -1959,24 +1922,19 @@ if (!blivet) { spin_lock(&dcache_lock); list_del(&old_rootmnt->mnt_list); - if (atomic_read(&old_rootmnt->mnt_count) > 2) { - spin_unlock(&dcache_lock); - mntput(old_rootmnt); - blivet = -EBUSY; - } else { - spin_unlock(&dcache_lock); - mntput(old_rootmnt); - if (parent_nd.mnt != old_rootmnt) - path_release(&parent_nd); - mntput(old_rootmnt); - ioctl_by_bdev(ramdisk, BLKFLSBUF, 0); - printk("okay\n"); - error = 0; - } + spin_unlock(&dcache_lock); + mntput(old_rootmnt); + mntput(old_rootmnt); + blivet = ioctl_by_bdev(ramdisk, BLKFLSBUF, 0); + path_release(&parent_nd); blkdev_put(ramdisk, BDEV_FS); } - if (blivet) + if (blivet) { printk(KERN_ERR "error %d\n", blivet); + } else { + printk("okay\n"); + error = 0; + } kfree(new_devname); return error; } @@ -1991,8 +1949,7 @@ spin_unlock(&dcache_lock); /* put the old stuff */ - if (parent_nd.mnt != old_rootmnt) - path_release(&parent_nd); + path_release(&parent_nd); mntput(old_rootmnt); path_release(&nd); return 0; @@ -2000,6 +1957,54 @@ #endif +/* + * Absolutely minimal fake fs - only empty root directory and nothing else. + * In 2.5 we'll use ramfs or tmpfs, but for now it's all we need - just + * something to go with root vfsmount. + */ +static struct dentry *rootfs_lookup(struct inode *dir, struct dentry *dentry) +{ + d_add(dentry, NULL); + return NULL; +} +static struct file_operations rootfs_dir_operations = { + read: generic_read_dir, + readdir: dcache_readdir, +}; +static struct inode_operations rootfs_dir_inode_operations = { + lookup: rootfs_lookup, +}; +static struct super_block *rootfs_read_super(struct super_block * sb, void * data, int silent) +{ + struct inode * inode; + struct dentry * root; + static struct super_operations s_ops = {}; + sb->s_op = &s_ops; + inode = new_inode(sb); + if (!inode) + return NULL; + inode->i_mode = S_IFDIR|0555; + inode->i_uid = inode->i_gid = 0; + inode->i_op = &rootfs_dir_inode_operations; + inode->i_fop = &rootfs_dir_operations; + root = d_alloc_root(inode); + if (!root) { + iput(inode); + return NULL; + } + sb->s_root = root; + return sb; +} +static DECLARE_FSTYPE(root_fs_type, "rootfs", rootfs_read_super, FS_NOMOUNT); + +static void __init init_mount_tree(void) +{ + register_filesystem(&root_fs_type); + root_vfsmnt = do_kern_mount("rootfs", 0, "rootfs", NULL); + if (IS_ERR(root_vfsmnt)) + panic("can't allocate root vfsmount"); +} + void __init mnt_init(unsigned long mempages) { struct list_head *d; @@ -2055,4 +2060,5 @@ d++; i--; } while (i); + init_mount_tree(); }
- 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/
|  |