patch-1.3.46 linux/fs/super.c
Next file: linux/include/asm-alpha/mman.h
Previous file: linux/fs/smbfs/proc.c
Back to the patch index
Back to the overall index
- Lines: 314
- Date:
Mon Dec 11 07:46:21 1995
- Orig file:
v1.3.45/linux/fs/super.c
- Orig date:
Fri Nov 17 08:42:28 1995
diff -u --recursive --new-file v1.3.45/linux/fs/super.c linux/fs/super.c
@@ -2,18 +2,22 @@
* linux/fs/super.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
- */
-
-/*
- * super.c contains code to handle the super-block tables.
+ *
+ * super.c contains code to handle: - mount structures
+ * - super-block tables.
+ * - mount systemcall
+ * - umount systemcall
*
* GK 2/5/95 - Changed to support mounting the root fs via NFS
*/
+
#include <stdarg.h>
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/kernel.h>
+#include <linux/mount.h>
+#include <linux/malloc.h>
#include <linux/major.h>
#include <linux/stat.h>
#include <linux/errno.h>
@@ -32,8 +36,6 @@
extern int root_mountflags;
-struct super_block super_blocks[NR_SUPER];
-
static int do_remount_sb(struct super_block *sb, int flags, char * data);
#ifdef CONFIG_ROOT_NFS
@@ -43,24 +45,118 @@
/* this is initialized in init/main.c */
kdev_t ROOT_DEV;
-static struct file_system_type * file_systems = NULL;
+struct super_block super_blocks[NR_SUPER];
+static struct file_system_type *file_systems = (struct file_system_type *) NULL;
+static struct vfsmount *vfsmntlist = (struct vfsmount *) NULL,
+ *vfsmnttail = (struct vfsmount *) NULL,
+ *mru_vfsmnt = (struct vfsmount *) NULL;
-int register_filesystem(struct file_system_type * fs)
+/*
+ * This part handles the management of the list of mounted filesystems.
+ */
+struct vfsmount *lookup_vfsmnt(kdev_t dev)
{
- struct file_system_type ** tmp;
+ struct vfsmount *lptr;
- if (!fs)
- return -EINVAL;
- if (fs->next)
- return -EBUSY;
- tmp = &file_systems;
- while (*tmp) {
- if (strcmp((*tmp)->name, fs->name) == 0)
- return -EBUSY;
- tmp = &(*tmp)->next;
+ if (vfsmntlist == (struct vfsmount *)NULL)
+ return ((struct vfsmount *)NULL);
+
+ if (mru_vfsmnt != (struct vfsmount *)NULL &&
+ mru_vfsmnt->mnt_dev == dev)
+ return (mru_vfsmnt);
+
+ for (lptr = vfsmntlist;
+ lptr != (struct vfsmount *)NULL;
+ lptr = lptr->mnt_next)
+ if (lptr->mnt_dev == dev) {
+ mru_vfsmnt = lptr;
+ return (lptr);
+ }
+
+ return ((struct vfsmount *)NULL);
+ /* NOTREACHED */
+}
+
+struct vfsmount *add_vfsmnt(kdev_t dev, const char *dev_name, const char *dir_name)
+{
+ struct vfsmount *lptr;
+ char *tmp;
+
+ if ((lptr = (struct vfsmount *)
+ kmalloc(sizeof(struct vfsmount), GFP_KERNEL)) == (struct vfsmount *)NULL)
+ return ((struct vfsmount *)NULL);
+ memset(lptr, 0, sizeof(struct vfsmount));
+
+ lptr->mnt_dev = dev;
+ lptr->mnt_sem.count = 1;
+ if (dev_name && !getname(dev_name, &tmp)) {
+ if ((lptr->mnt_devname =
+ (char *) kmalloc(strlen(tmp), GFP_KERNEL)) != (char *)NULL)
+ strcpy(lptr->mnt_devname, tmp);
+ putname(tmp);
}
- *tmp = fs;
- return 0;
+ if (dir_name && !getname(dir_name, &tmp)) {
+ if ((lptr->mnt_dirname =
+ (char *) kmalloc(strlen(tmp), GFP_KERNEL)) != (char *)NULL)
+ strcpy(lptr->mnt_dirname, tmp);
+ putname(tmp);
+ }
+
+ if (vfsmntlist == (struct vfsmount *)NULL) {
+ vfsmntlist = vfsmnttail = lptr;
+ } else {
+ vfsmnttail->mnt_next = lptr;
+ vfsmnttail = lptr;
+ }
+ return (lptr);
+}
+
+void remove_vfsmnt(kdev_t dev)
+{
+ struct vfsmount *lptr, *tofree;
+
+ if (vfsmntlist == (struct vfsmount *)NULL)
+ return;
+ lptr = vfsmntlist;
+ if (lptr->mnt_dev == dev) {
+ tofree = lptr;
+ vfsmntlist = lptr->mnt_next;
+ if (vfsmnttail->mnt_dev == dev)
+ vfsmnttail = vfsmntlist;
+ } else {
+ while (lptr->mnt_next != (struct vfsmount *)NULL) {
+ if (lptr->mnt_next->mnt_dev == dev)
+ break;
+ lptr = lptr->mnt_next;
+ }
+ tofree = lptr->mnt_next;
+ if (tofree == (struct vfsmount *)NULL)
+ return;
+ lptr->mnt_next = lptr->mnt_next->mnt_next;
+ if (vfsmnttail->mnt_dev == dev)
+ vfsmnttail = lptr;
+ }
+ kfree(tofree->mnt_devname);
+ kfree(tofree->mnt_dirname);
+ kfree_s(tofree, sizeof(struct vfsmount));
+}
+
+int register_filesystem(struct file_system_type * fs)
+{
+ struct file_system_type ** tmp;
+
+ if (!fs)
+ return -EINVAL;
+ if (fs->next)
+ return -EBUSY;
+ tmp = &file_systems;
+ while (*tmp) {
+ if (strcmp((*tmp)->name, fs->name) == 0)
+ return -EBUSY;
+ tmp = &(*tmp)->next;
+ }
+ *tmp = fs;
+ return 0;
}
int unregister_filesystem(struct file_system_type * fs)
@@ -364,11 +460,20 @@
int retval;
if (dev==ROOT_DEV) {
- /* Special case for "unmounting" root. We just try to remount
- it readonly, and sync() the device. */
+ /*
+ * Special case for "unmounting" root. We just try to remount
+ * it readonly, and sync() the device.
+ */
if (!(sb=get_super(dev)))
return -ENOENT;
if (!(sb->s_flags & MS_RDONLY)) {
+ /*
+ * Make sure all quotas are turned off on this device we need to mount
+ * it readonly so no more writes by the quotasystem.
+ * If later on the remount fails to bad there are no quotas running
+ * anymore. Turn them on again by hand.
+ */
+ quota_off(dev, -1);
fsync_dev(dev);
retval = do_remount_sb(sb, MS_RDONLY, 0);
if (retval)
@@ -381,6 +486,12 @@
if (!sb->s_covered->i_mount)
printk("VFS: umount(%s): mounted inode has i_mount=NULL\n",
kdevname(dev));
+ /*
+ * Before checking if the filesystem is still busy make sure the kernel
+ * doesn't hold any quotafiles open on that device. If the umount fails
+ * to bad there are no quotas running anymore. Turn them on again by hand.
+ */
+ quota_off(dev, -1);
if (!fs_may_umount(dev, sb->s_mounted))
return -EBUSY;
sb->s_covered->i_mount = NULL;
@@ -391,6 +502,7 @@
if (sb->s_op && sb->s_op->write_super && sb->s_dirt)
sb->s_op->write_super(sb);
put_super(dev);
+ remove_vfsmnt(dev);
return 0;
}
@@ -415,9 +527,9 @@
if (!suser())
return -EPERM;
- retval = namei(name,&inode);
+ retval = namei(name, &inode);
if (retval) {
- retval = lnamei(name,&inode);
+ retval = lnamei(name, &inode);
if (retval)
return retval;
}
@@ -466,13 +578,15 @@
* We also have to flush all inode-data for this device, as the new mount
* might need new info.
*/
-int do_mount(kdev_t dev, const char * dir, const char * type, int flags, void * data)
+
+int do_mount(kdev_t dev, const char * dev_name, const char * dir_name, const char * type, int flags, void * data)
{
struct inode * dir_i;
struct super_block * sb;
+ struct vfsmount *vfsmnt;
int error;
- error = namei(dir,&dir_i);
+ error = namei(dir_name, &dir_i);
if (error)
return error;
if (dir_i->i_count != 1 || dir_i->i_mount) {
@@ -496,6 +610,8 @@
iput(dir_i);
return -EBUSY;
}
+ vfsmnt = add_vfsmnt(dev, dev_name, dir_name);
+ vfsmnt->mnt_sb = sb;
sb->s_covered = dir_i;
dir_i->i_mount = sb->s_mounted;
return 0; /* we don't iput(dir_i) - see umount */
@@ -534,7 +650,7 @@
struct inode *dir_i;
int retval;
- retval = namei(dir,&dir_i);
+ retval = namei(dir, &dir_i);
if (retval)
return retval;
if (dir_i != dir_i->i_sb->s_mounted) {
@@ -619,7 +735,7 @@
t = fstype->name;
fops = NULL;
if (fstype->requires_dev) {
- retval = namei(dev_name,&inode);
+ retval = namei(dev_name, &inode);
if (retval)
return retval;
if (!S_ISBLK(inode->i_mode)) {
@@ -666,7 +782,7 @@
return retval;
}
}
- retval = do_mount(dev,dir_name,t,flags,(void *) page);
+ retval = do_mount(dev,dev_name,dir_name,t,flags,(void *) page);
free_page(page);
if (retval && fops && fops->release)
fops->release(inode, NULL);
@@ -678,10 +794,11 @@
{
struct file_system_type * fs_type;
struct super_block * sb;
+ struct vfsmount *vfsmnt;
struct inode * inode, d_inode;
struct file filp;
int retval;
-
+
memset(super_blocks, 0, sizeof(super_blocks));
#ifdef CONFIG_ROOT_NFS
if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) {
@@ -737,9 +854,9 @@
for (fs_type = file_systems ; fs_type ; fs_type = fs_type->next) {
if(retval)
break;
- if (!fs_type->requires_dev)
- continue;
- sb = read_super(ROOT_DEV,fs_type->name,root_mountflags,NULL,1);
+ if (!fs_type->requires_dev)
+ continue;
+ sb = read_super(ROOT_DEV,fs_type->name,root_mountflags,NULL,1);
if (sb) {
inode = sb->s_mounted;
inode->i_count += 3 ; /* NOTE! it is logically used 4 times, not 1 */
@@ -750,6 +867,8 @@
printk ("VFS: Mounted root (%s filesystem)%s.\n",
fs_type->name,
(sb->s_flags & MS_RDONLY) ? " readonly" : "");
+ vfsmnt = add_vfsmnt(ROOT_DEV, "rootfs", "/");
+ vfsmnt->mnt_sb = sb;
return;
}
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this