diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-02-05 06:47:02 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-02-05 06:47:02 +0000 |
commit | 99a7e12f34b3661a0d1354eef83a0eef4df5e34c (patch) | |
tree | 3560aca9ca86792f9ab7bd87861ea143a1b3c7a3 /fs/super.c | |
parent | e73a04659c0b8cdee4dd40e58630e2cf63afb316 (diff) |
Merge with Linux 2.3.38.
Diffstat (limited to 'fs/super.c')
-rw-r--r-- | fs/super.c | 186 |
1 files changed, 90 insertions, 96 deletions
diff --git a/fs/super.c b/fs/super.c index 9f901236b..4c67729aa 100644 --- a/fs/super.c +++ b/fs/super.c @@ -45,7 +45,6 @@ static DECLARE_MUTEX(mount_sem); extern void wait_for_keypress(void); -extern struct file_operations * get_blkfops(unsigned int major); extern int root_mountflags; @@ -181,7 +180,6 @@ int register_filesystem(struct file_system_type * fs) return 0; } -#ifdef CONFIG_MODULES int unregister_filesystem(struct file_system_type * fs) { struct file_system_type ** tmp; @@ -197,7 +195,6 @@ int unregister_filesystem(struct file_system_type * fs) } return -EINVAL; } -#endif static int fs_index(const char * __name) { @@ -532,7 +529,8 @@ struct super_block *get_empty_super(void) return s; } -static struct super_block * read_super(kdev_t dev,const char *name,int flags, +static struct super_block * read_super(kdev_t dev, struct block_device *bdev, + const char *name, int flags, void *data, int silent) { struct super_block * s; @@ -543,7 +541,7 @@ static struct super_block * read_super(kdev_t dev,const char *name,int flags, check_disk_change(dev); s = get_super(dev); if (s) - goto out; + goto found; /* ought to set ->s_bdev */ type = get_fs_type(name); if (!type) { @@ -555,23 +553,30 @@ static struct super_block * read_super(kdev_t dev,const char *name,int flags, if (!s) goto out; s->s_dev = dev; + s->s_bdev = bdev; s->s_flags = flags; s->s_dirt = 0; sema_init(&s->s_vfs_rename_sem,1); /* N.B. Should lock superblock now ... */ if (!type->read_super(s, data, silent)) goto out_fail; - s->s_dev = dev; /* N.B. why do this again?? */ s->s_type = type; +bd_get: + /* tell bdcache that we are going to keep this one */ + if (bdev) + atomic_inc(&bdev->bd_count); out: return s; - /* N.B. s_dev should be cleared in type->read_super */ out_fail: s->s_dev = 0; + s->s_bdev = 0; out_null: s = NULL; goto out; +found: + s->s_bdev = bdev; + goto bd_get; } /* @@ -634,9 +639,10 @@ static void d_mount(struct dentry *covered, struct dentry *dentry) dentry->d_covers = covered; } -static int do_umount(kdev_t dev, int unmount_root, int flags) +static struct block_device *do_umount(kdev_t dev, int unmount_root, int flags) { struct super_block * sb; + struct block_device *bdev; int retval; retval = -ENOENT; @@ -683,7 +689,7 @@ static int do_umount(kdev_t dev, int unmount_root, int flags) retval = 0; if (!(sb->s_flags & MS_RDONLY)) retval = do_remount_sb(sb, MS_RDONLY, 0); - return retval; + return ERR_PTR(retval); } retval = d_umount(sb); @@ -708,43 +714,44 @@ static int do_umount(kdev_t dev, int unmount_root, int flags) } sb->s_dev = 0; /* Free the superblock */ + bdev = sb->s_bdev; + sb->s_bdev = NULL; unlock_super(sb); remove_vfsmnt(dev); + + return bdev; + out: - return retval; + return ERR_PTR(retval); } static int umount_dev(kdev_t dev, int flags) { int retval; - struct inode * inode = get_empty_inode(); + struct block_device *bdev; - retval = -ENOMEM; - if (!inode) - goto out; - - inode->i_rdev = dev; retval = -ENXIO; if (MAJOR(dev) >= MAX_BLKDEV) - goto out_iput; + goto out; fsync_dev(dev); down(&mount_sem); - retval = do_umount(dev, 0, flags); - if (!retval) { - fsync_dev(dev); - if (dev != ROOT_DEV) { - blkdev_release(inode); + bdev = do_umount(dev, 0, flags); + if (IS_ERR(bdev)) + retval = PTR_ERR(bdev); + else { + retval = 0; + if (bdev) { + blkdev_put(bdev, BDEV_FS); + bdput(bdev); + } else { put_unnamed_dev(dev); } } - up(&mount_sem); -out_iput: - iput(inode); out: return retval; } @@ -753,12 +760,6 @@ out: * Now umount can handle mount points as well as block devices. * This is important for filesystems which use unnamed block devices. * - * There is a little kludge here with the dummy_inode. The current - * vfs release functions only use the r_dev field in the inode so - * we give them the info they need without using a real inode. - * If any other fields are ever needed by any block device release - * functions, they should be faked here. -- jrs - * * We now support a flag for forced unmount like the other 'big iron' * unixes. Our API is identical to OSF/1 to avoid making a mess of AMD */ @@ -842,14 +843,29 @@ int fs_may_mount(kdev_t dev) * Anyone using this new feature must know what he/she is doing. */ -int do_mount(kdev_t dev, const char * dev_name, const char * dir_name, - const char * type, int flags, void * data) +int do_mount(struct block_device *bdev, const char *dev_name, + const char *dir_name, const char * type, int flags, void * data) { + kdev_t dev; struct dentry * dir_d; struct super_block * sb; struct vfsmount *vfsmnt; int error; + if (bdev) { + mode_t mode = FMODE_READ; /* we always need it ;-) */ + if (!(flags & MS_RDONLY)) + mode |= FMODE_WRITE; + dev = to_kdev_t(bdev->bd_dev); + error = blkdev_get(bdev, mode, 0, BDEV_FS); + if (error) + return error; + } else { + dev = get_unnamed_dev(); + if (!dev) + return -EMFILE; /* huh? */ + } + error = -EACCES; if (!(flags & MS_RDONLY) && dev && is_read_only(dev)) goto out; @@ -876,7 +892,7 @@ int do_mount(kdev_t dev, const char * dev_name, const char * dir_name, * read_super just does a get_super(). */ error = -EINVAL; - sb = read_super(dev, type, flags, data, 0); + sb = read_super(dev, bdev, type, flags, data, 0); if (!sb) goto dput_and_out; @@ -886,20 +902,30 @@ int do_mount(kdev_t dev, const char * dev_name, const char * dir_name, */ error = -EBUSY; if (!fs_may_mount(dev)) - goto dput_and_out; + goto bdput_and_out; error = -ENOMEM; vfsmnt = add_vfsmnt(sb, dev_name, dir_name); if (vfsmnt) { d_mount(dget(dir_d), sb->s_root); - error = 0; + dput(dir_d); + up(&mount_sem); + return 0; } +bdput_and_out: + sb->s_bdev = NULL; + if (bdev) + bdput(bdev); dput_and_out: dput(dir_d); up(&mount_sem); out: - return error; + if (bdev) + blkdev_put(bdev, BDEV_FS); + else + put_unnamed_dev(dev); + return error; } @@ -1019,11 +1045,10 @@ asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type, struct file_system_type * fstype; struct dentry * dentry = NULL; struct inode * inode = NULL; - kdev_t dev; + struct block_device *bdev = NULL; int retval; unsigned long flags = 0; unsigned long page = 0; - struct file dummy; /* allows read-write or read-only flag */ if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -1049,7 +1074,6 @@ asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type, if (!fstype) goto out; - memset(&dummy, 0, sizeof(dummy)); if (fstype->fs_flags & FS_REQUIRES_DEV) { dentry = namei(dev_name); retval = PTR_ERR(dentry); @@ -1065,28 +1089,7 @@ asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type, if (IS_NODEV(inode)) goto dput_and_out; - dev = inode->i_rdev; - retval = -ENXIO; - if (MAJOR(dev) >= MAX_BLKDEV) - goto dput_and_out; - - retval = -ENOTBLK; - dummy.f_op = get_blkfops(MAJOR(dev)); - if (!dummy.f_op) - goto dput_and_out; - - if (dummy.f_op->open) { - dummy.f_dentry = dentry; - dummy.f_mode = (new_flags & MS_RDONLY) ? 1 : 3; - retval = dummy.f_op->open(inode, &dummy); - if (retval) - goto dput_and_out; - } - - } else { - retval = -EMFILE; - if (!(dev = get_unnamed_dev())) - goto out; + bdev = inode->i_bdev; } page = 0; @@ -1094,27 +1097,17 @@ asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type, flags = new_flags & ~MS_MGC_MSK; retval = copy_mount_options(data, &page); if (retval < 0) - goto clean_up; + goto dput_and_out; } - retval = do_mount(dev, dev_name, dir_name, fstype->name, flags, + retval = do_mount(bdev, dev_name, dir_name, fstype->name, flags, (void *) page); free_page(page); - if (retval) - goto clean_up; dput_and_out: dput(dentry); out: unlock_kernel(); return retval; - -clean_up: - if (dummy.f_op) { - if (dummy.f_op->release) - dummy.f_op->release(inode, NULL); - } else - put_unnamed_dev(dev); - goto dput_and_out; } void __init mount_root(void) @@ -1122,8 +1115,8 @@ void __init mount_root(void) struct file_system_type * fs_type; struct super_block * sb; struct vfsmount *vfsmnt; - struct inode * d_inode = NULL; - struct file filp; + struct block_device *bdev = NULL; + mode_t mode; int retval; #ifdef CONFIG_ROOT_NFS @@ -1132,6 +1125,7 @@ void __init mount_root(void) if ((fs_type = get_fs_type("nfs"))) { sb = get_empty_super(); /* "can't fail" */ sb->s_dev = get_unnamed_dev(); + sb->s_bdev = NULL; sb->s_flags = root_mountflags; sema_init(&sb->s_vfs_rename_sem,1); vfsmnt = add_vfsmnt(sb, "/dev/root", "/"); @@ -1179,23 +1173,17 @@ void __init mount_root(void) } #endif - memset(&filp, 0, sizeof(filp)); - d_inode = get_empty_inode(); - if (!d_inode) - panic(__FUNCTION__ ": unable to allocate root inode"); - d_inode->i_rdev = ROOT_DEV; - filp.f_dentry = NULL; - if ( root_mountflags & MS_RDONLY) - filp.f_mode = 1; /* read only */ - else - filp.f_mode = 3; /* read write */ - retval = blkdev_open(d_inode, &filp); + bdev = bdget(kdev_t_to_nr(ROOT_DEV)); + if (!bdget) + panic(__FUNCTION__ ": unable to allocate root device"); + mode = FMODE_READ; + if (!(root_mountflags & MS_RDONLY)) + mode |= FMODE_WRITE; + retval = blkdev_get(bdev, mode, 0, BDEV_FS); if (retval == -EROFS) { root_mountflags |= MS_RDONLY; - filp.f_mode = 1; - retval = blkdev_open(d_inode, &filp); + retval = blkdev_get(bdev, FMODE_READ, 0, BDEV_FS); } - iput(d_inode); if (retval) /* * Allow the user to distinguish between failed open @@ -1206,7 +1194,7 @@ void __init mount_root(void) else for (fs_type = file_systems ; fs_type ; fs_type = fs_type->next) { if (!(fs_type->fs_flags & FS_REQUIRES_DEV)) continue; - sb = read_super(ROOT_DEV,fs_type->name,root_mountflags,NULL,1); + sb = read_super(ROOT_DEV,bdev,fs_type->name,root_mountflags,NULL,1); if (sb) { sb->s_flags = root_mountflags; current->fs->root = dget(sb->s_root); @@ -1215,8 +1203,10 @@ void __init mount_root(void) fs_type->name, (sb->s_flags & MS_RDONLY) ? " readonly" : ""); vfsmnt = add_vfsmnt(sb, "/dev/root", "/"); - if (vfsmnt) + if (vfsmnt) { + bdput(bdev); /* sb holds a reference */ return; + } panic("VFS: add_vfsmnt failed for root fs"); } } @@ -1270,16 +1260,20 @@ int __init change_root(kdev_t new_root_dev,const char *put_old) error = -ENOTDIR; } if (error) { - int umount_error; + struct block_device *bdev; printk(KERN_NOTICE "Trying to unmount old root ... "); - umount_error = do_umount(old_root_dev,1, 0); - if (!umount_error) { + bdev = do_umount(old_root_dev,1, 0); + if (!IS_ERR(bdev)) { printk("okay\n"); invalidate_buffers(old_root_dev); + if (bdev) { + blkdev_put(bdev, BDEV_FS); + bdput(bdev); + } return 0; } - printk(KERN_ERR "error %d\n",umount_error); + printk(KERN_ERR "error %d\n",PTR_ERR(bdev)); return error; } remove_vfsmnt(old_root_dev); |