patch-2.3.99-pre4 linux/fs/super.c
Next file: linux/fs/udf/file.c
Previous file: linux/fs/read_write.c
Back to the patch index
Back to the overall index
- Lines: 469
- Date:
Fri Apr 7 13:38:00 2000
- Orig file:
v2.3.99-pre3/linux/fs/super.c
- Orig date:
Mon Mar 27 08:08:30 2000
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/super.c linux/fs/super.c
@@ -91,6 +91,19 @@
return p;
}
+/**
+ * register_filesystem - register a new filesystem
+ * @fs: the file system structure
+ *
+ * Adds the file system passed to the list of file systems the kernel
+ * is aware of for by mount and other syscalls. Returns 0 on success,
+ * or a negative errno code on an error.
+ *
+ * The file_system_type that is passed is linked into the kernel
+ * structures and must not be freed until the file system has been
+ * unregistered.
+ */
+
int register_filesystem(struct file_system_type * fs)
{
int res = 0;
@@ -110,6 +123,18 @@
return res;
}
+/**
+ * unregister_filesystem - unregister a file system
+ * @fs: filesystem to unregister
+ *
+ * Remove a file system that was previously successfully registered
+ * with the kernel. An error is returned if the file system is not found.
+ * Zero is returned on a success.
+ *
+ * Once this function has returned the file_system_type structure may be
+ * freed or reused.
+ */
+
int unregister_filesystem(struct file_system_type * fs)
{
struct file_system_type ** tmp;
@@ -192,7 +217,6 @@
{
int retval = -EINVAL;
- lock_kernel();
switch (option) {
case 1:
retval = fs_index((const char *) arg1);
@@ -206,7 +230,6 @@
retval = fs_maxindex();
break;
}
- unlock_kernel();
return retval;
}
@@ -253,7 +276,7 @@
const char *dev_name, const char *dir_name)
{
struct vfsmount *lptr;
- char *tmp, *name;
+ char *name;
lptr = (struct vfsmount *)kmalloc(sizeof(struct vfsmount), GFP_KERNEL);
if (!lptr)
@@ -264,21 +287,19 @@
lptr->mnt_dev = sb->s_dev;
/* N.B. Is it really OK to have a vfsmount without names? */
- if (dev_name && !IS_ERR(tmp = getname(dev_name))) {
- name = (char *) kmalloc(strlen(tmp)+1, GFP_KERNEL);
+ if (dev_name) {
+ name = (char *) kmalloc(strlen(dev_name)+1, GFP_KERNEL);
if (name) {
- strcpy(name, tmp);
+ strcpy(name, dev_name);
lptr->mnt_devname = name;
}
- putname(tmp);
}
- if (dir_name && !IS_ERR(tmp = getname(dir_name))) {
- name = (char *) kmalloc(strlen(tmp)+1, GFP_KERNEL);
+ if (dir_name) {
+ name = (char *) kmalloc(strlen(dir_name)+1, GFP_KERNEL);
if (name) {
- strcpy(name, tmp);
+ strcpy(name, dir_name);
lptr->mnt_dirname = name;
}
- putname(tmp);
}
if (vfsmntlist == (struct vfsmount *)NULL) {
@@ -343,13 +364,16 @@
static struct proc_nfs_info {
int flag;
char *str;
+ char *nostr;
} nfs_info[] = {
- { NFS_MOUNT_SOFT, ",soft" },
- { NFS_MOUNT_INTR, ",intr" },
- { NFS_MOUNT_POSIX, ",posix" },
- { NFS_MOUNT_NOCTO, ",nocto" },
- { NFS_MOUNT_NOAC, ",noac" },
- { 0, NULL }
+ { NFS_MOUNT_SOFT, ",soft", ",hard" },
+ { NFS_MOUNT_INTR, ",intr", "" },
+ { NFS_MOUNT_POSIX, ",posix", "" },
+ { NFS_MOUNT_TCP, ",tcp", ",udp" },
+ { NFS_MOUNT_NOCTO, ",nocto", "" },
+ { NFS_MOUNT_NOAC, ",noac", "" },
+ { NFS_MOUNT_NONLM, ",nolock", ",lock" },
+ { 0, NULL, NULL }
};
int get_filesystem_info( char *buf )
@@ -362,9 +386,10 @@
char *path,*buffer = (char *) __get_free_page(GFP_KERNEL);
if (!buffer) return 0;
- for (tmp = vfsmntlist; tmp && len < PAGE_SIZE - 160;
- tmp = tmp->mnt_next) {
- path = d_path(tmp->mnt_sb->s_root, buffer, PAGE_SIZE);
+ for (tmp = vfsmntlist; tmp && len < PAGE_SIZE - 160; tmp = tmp->mnt_next) {
+ if (!tmp->mnt_sb || !tmp->mnt_sb->s_root)
+ continue;
+ path = d_path(tmp->mnt_sb->s_root, tmp, buffer, PAGE_SIZE);
if (!path)
continue;
len += sprintf( buf + len, "%s %s %s %s",
@@ -379,14 +404,11 @@
}
if (!strcmp("nfs", tmp->mnt_sb->s_type->name)) {
nfss = &tmp->mnt_sb->u.nfs_sb.s_server;
- if (nfss->rsize != NFS_DEF_FILE_IO_BUFFER_SIZE) {
- len += sprintf(buf+len, ",rsize=%d",
- nfss->rsize);
- }
- if (nfss->wsize != NFS_DEF_FILE_IO_BUFFER_SIZE) {
- len += sprintf(buf+len, ",wsize=%d",
- nfss->wsize);
- }
+ len += sprintf(buf+len, ",v%d", nfss->rpc_ops->version);
+
+ len += sprintf(buf+len, ",rsize=%d", nfss->rsize);
+
+ len += sprintf(buf+len, ",wsize=%d", nfss->wsize);
#if 0
if (nfss->timeo != 7*HZ/10) {
len += sprintf(buf+len, ",timeo=%d",
@@ -414,10 +436,13 @@
nfss->acdirmax/HZ);
}
for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) {
- if (nfss->flags & nfs_infop->flag) {
- strcpy(buf + len, nfs_infop->str);
- len += strlen(nfs_infop->str);
- }
+ char *str;
+ if (nfss->flags & nfs_infop->flag)
+ str = nfs_infop->str;
+ else
+ str = nfs_infop->nostr;
+ strcpy(buf + len, str);
+ len += strlen(str);
}
len += sprintf(buf+len, ",addr=%s",
nfss->hostname);
@@ -429,6 +454,14 @@
return len;
}
+/**
+ * __wait_on_super - wait on a superblock
+ * @sb: superblock to wait on
+ *
+ * Waits for a superblock to become unlocked and then returns. It does
+ * not take the lock. This is an internal function. See wait_on_super.
+ */
+
void __wait_on_super(struct super_block * sb)
{
DECLARE_WAITQUEUE(wait, current);
@@ -473,6 +506,14 @@
}
}
+/**
+ * get_super - get the superblock of a device
+ * @dev: device to get the super block for
+ *
+ * Scans the superblock list and finds the superblock of the file system
+ * mounted on the device given. NULL is returned if no match is found.
+ */
+
struct super_block * get_super(kdev_t dev)
{
struct super_block * s;
@@ -517,9 +558,15 @@
return err;
}
-/*
- * Find a super_block with no device assigned.
+/**
+ * get_empty_super - find empty superblocks
+ *
+ * Find a super_block with no device assigned. A free superblock is
+ * found and returned. If neccessary new superblocks are allocated.
+ * NULL is returned if there are insufficient resources to complete
+ * the request
*/
+
struct super_block *get_empty_super(void)
{
struct super_block *s;
@@ -850,7 +897,7 @@
* Anyone using this new feature must know what he/she is doing.
*/
-int do_mount(struct block_device *bdev, const char *dev_name,
+static 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;
@@ -881,7 +928,7 @@
/*
* Do the lookup first to force automounting.
*/
- dir_d = namei(dir_name);
+ dir_d = lookup_dentry(dir_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE);
error = PTR_ERR(dir_d);
if (IS_ERR(dir_d))
goto out;
@@ -981,11 +1028,10 @@
sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK);
/*
- * Invalidate the inodes, as some mount options may be changed.
- * N.B. If we are changing media, we should check the return
- * from invalidate_inodes ... can't allow _any_ open files.
+ * We can't invalidate inodes as we can loose data when remounting
+ * (someone might manage to alter data while we are waiting in lock_super()
+ * or in foo_remount_fs()))
*/
- invalidate_inodes(sb);
return 0;
}
@@ -995,11 +1041,10 @@
struct dentry *dentry;
int retval;
- dentry = namei(dir);
+ dentry = lookup_dentry(dir, LOOKUP_FOLLOW|LOOKUP_POSITIVE);
retval = PTR_ERR(dentry);
if (!IS_ERR(dentry)) {
struct super_block * sb = dentry->d_inode->i_sb;
-
retval = -ENODEV;
if (sb) {
retval = -EINVAL;
@@ -1062,8 +1107,8 @@
* aren't used, as the syscall assumes we are talking to an older
* version that didn't understand them.
*/
-long do_sys_mount(char * dev_name, char * dir_name, unsigned long type_page,
- unsigned long new_flags, unsigned long data_page)
+long do_sys_mount(char * dev_name, char * dir_name, char *type_page,
+ unsigned long new_flags, void *data_page)
{
struct file_system_type * fstype;
struct dentry * dentry = NULL;
@@ -1071,6 +1116,15 @@
struct block_device *bdev = NULL;
int retval;
unsigned long flags = 0;
+
+ /* Basic sanity checks */
+
+ if (!dir_name || !*dir_name || !memchr(dir_name, 0, PAGE_SIZE))
+ return -EINVAL;
+ if (!type_page || !memchr(type_page, 0, PAGE_SIZE))
+ return -EINVAL;
+ if (dev_name && !memchr(dev_name, 0, PAGE_SIZE))
+ return -EINVAL;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
@@ -1083,7 +1137,7 @@
goto out;
}
- fstype = get_fs_type((char *) type_page);
+ fstype = get_fs_type(type_page);
retval = -ENODEV;
if (!fstype)
goto out;
@@ -1091,7 +1145,10 @@
if (fstype->fs_flags & FS_REQUIRES_DEV) {
struct block_device_operations *bdops;
- dentry = namei(dev_name);
+ retval = -EINVAL;
+ if (!dev_name || !*dev_name)
+ goto fs_out;
+ dentry = lookup_dentry(dev_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE);
retval = PTR_ERR(dentry);
if (IS_ERR(dentry))
goto fs_out;
@@ -1114,7 +1171,7 @@
flags = new_flags & ~MS_MGC_MSK;
retval = do_mount(bdev, dev_name, dir_name, fstype->name, flags,
- (void *) data_page);
+ data_page);
dput_and_out:
dput(dentry);
@@ -1130,6 +1187,8 @@
int retval;
unsigned long data_page = 0;
unsigned long type_page = 0;
+ unsigned long dev_page = 0;
+ char *dir_page;
lock_kernel();
retval = copy_mount_options (type, &type_page);
@@ -1146,12 +1205,24 @@
goto out;
}
+ dir_page = getname(dir_name);
+ retval = PTR_ERR(dir_page);
+ if (IS_ERR(dir_page))
+ goto out1;
+
+ retval = copy_mount_options (dev_name, &dev_page);
+ if (retval < 0)
+ goto out2;
retval = copy_mount_options (data, &data_page);
if (retval >= 0) {
- retval = do_sys_mount(dev_name, dir_name, type_page,
- new_flags, data_page);
+ retval = do_sys_mount((char*)dev_page,dir_page,(char*)type_page,
+ new_flags, (void*)data_page);
free_page(data_page);
}
+ free_page(dev_page);
+out2:
+ putname(dir_page);
+out1:
free_page(type_page);
out:
unlock_kernel();
@@ -1162,7 +1233,7 @@
{
struct file_system_type * fs_type;
struct super_block * sb;
- struct vfsmount *vfsmnt;
+ struct vfsmount *vfsmnt = NULL;
struct block_device *bdev = NULL;
mode_t mode;
int retval;
@@ -1186,7 +1257,9 @@
sb->s_dirt = 0;
sb->s_type = fs_type;
current->fs->root = dget(sb->s_root);
+ current->fs->rootmnt = mntget(vfsmnt);
current->fs->pwd = dget(sb->s_root);
+ current->fs->pwdmnt = mntget(vfsmnt);
ROOT_DEV = sb->s_dev;
printk (KERN_NOTICE "VFS: Mounted root (NFS filesystem)%s.\n", (sb->s_flags & MS_RDONLY) ? " readonly" : "");
return;
@@ -1298,7 +1371,9 @@
mount_it:
sb->s_flags = root_mountflags;
current->fs->root = dget(sb->s_root);
+ current->fs->rootmnt = mntget(vfsmnt);
current->fs->pwd = dget(sb->s_root);
+ current->fs->pwdmnt = mntget(vfsmnt);
printk ("VFS: Mounted root (%s filesystem)%s.\n",
fs_type->name,
(sb->s_flags & MS_RDONLY) ? " readonly" : "");
@@ -1321,22 +1396,28 @@
static void chroot_fs_refs(struct dentry *old_root,
- struct dentry *new_root)
+ struct vfsmount *old_rootmnt,
+ struct dentry *new_root,
+ struct vfsmount *new_rootmnt)
{
struct task_struct *p;
read_lock(&tasklist_lock);
for_each_task(p) {
if (!p->fs) continue;
- if (p->fs->root == old_root) {
- dput(old_root);
+ if (p->fs->root == old_root && p->fs->rootmnt == old_rootmnt) {
p->fs->root = dget(new_root);
+ p->fs->rootmnt = mntget(new_rootmnt);
+ mntput(old_rootmnt);
+ dput(old_root);
printk(KERN_DEBUG "chroot_fs_refs: changed root of "
"process %d\n",p->pid);
}
- if (p->fs->pwd == old_root) {
- dput(old_root);
+ if (p->fs->pwd == old_root && p->fs->pwdmnt == old_rootmnt) {
p->fs->pwd = dget(new_root);
+ p->fs->pwdmnt = mntget(new_rootmnt);
+ mntput(old_rootmnt);
+ dput(old_root);
printk(KERN_DEBUG "chroot_fs_refs: changed cwd of "
"process %d\n",p->pid);
}
@@ -1344,7 +1425,6 @@
read_unlock(&tasklist_lock);
}
-
/*
* Moves the current root to put_root, and sets root/cwd of all processes
* which had them on the old root to new_root.
@@ -1360,9 +1440,11 @@
asmlinkage long sys_pivot_root(const char *new_root, const char *put_old)
{
struct dentry *root = current->fs->root;
+ struct vfsmount *root_mnt = current->fs->rootmnt;
struct dentry *d_new_root, *d_put_old, *covered;
struct dentry *root_dev_root, *new_root_dev_root;
struct dentry *walk, *next;
+ struct vfsmount *new_root_mnt = NULL;
int error;
if (!capable(CAP_SYS_ADMIN))
@@ -1414,7 +1496,7 @@
root_dev_root = root->d_sb->s_root;
root_dev_root->d_covers = dget(d_put_old);
d_put_old->d_mounts = root_dev_root;
- chroot_fs_refs(root,d_new_root);
+ chroot_fs_refs(root,root_mnt,d_new_root,new_root_mnt);
error = 0;
out2:
up(&mount_sem);
@@ -1444,7 +1526,7 @@
return -EBUSY;
}
/* First unmount devfs if mounted */
- dir_d = lookup_dentry ("/dev", NULL, 1);
+ dir_d = lookup_dentry ("/dev", LOOKUP_FOLLOW|LOOKUP_POSITIVE);
if (!IS_ERR(dir_d)) {
struct super_block *sb = dir_d->d_inode->i_sb;
@@ -1467,12 +1549,9 @@
/*
* Get the new mount directory
*/
- dir_d = lookup_dentry(put_old, NULL, 1);
+ dir_d = lookup_dentry(put_old, LOOKUP_FOLLOW|LOOKUP_POSITIVE);
if (IS_ERR(dir_d)) {
error = PTR_ERR(dir_d);
- } else if (!dir_d->d_inode) {
- dput(dir_d);
- error = -ENOENT;
} else {
error = 0;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)