super.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 1,342 行 · 第 1/3 页
C
1,342 行
/* * linux/fs/super.c * * Copyright (C) 1991, 1992 Linus Torvalds * * super.c contains code to handle: - mount structures * - super-block tables. * - mount system call * - umount system call * * Added options to /proc/mounts * Torbj鰎n Lindh (torbjorn.lindh@gopta.se), April 14, 1996. * * GK 2/5/95 - Changed to support mounting the root fs via NFS * * Added kerneld support: Jacques Gelinas and Bjorn Ekwall * Added change_root: Werner Almesberger & Hans Lermen, Feb '96 * * OSKit support added by the University of Utah, 1997 */#include <linux/config.h>#include <linux/malloc.h>#include <linux/locks.h>#include <linux/smp_lock.h>#ifndef OSKIT#include <linux/fd.h>#endif /* OSKIT */#include <linux/init.h>#include <linux/quotaops.h>#include <linux/acct.h>#include <asm/uaccess.h>#ifndef OSKIT#include <linux/nfs_fs.h>#include <linux/nfs_fs_sb.h>#include <linux/nfs_mount.h>#endif /* OSKIT */#ifdef CONFIG_KMOD#include <linux/kmod.h>#endif/* * We use a semaphore to synchronize all mount/umount * activity - imagine the mess if we have a race between * unmounting a filesystem and re-mounting it (or something * else). */static struct semaphore mount_sem = MUTEX;extern void wait_for_keypress(void);extern struct file_operations * get_blkfops(unsigned int major);extern int root_mountflags;extern void rd_load_secondary(void);#ifndef OSKITstatic int do_remount_sb(struct super_block *sb, int flags, char * data);#endif/* this is initialized in init/main.c */kdev_t ROOT_DEV;int nr_super_blocks = 0;int max_super_blocks = NR_SUPER;LIST_HEAD(super_blocks);static struct file_system_type *file_systems = (struct file_system_type *) NULL;#ifndef OSKITstruct vfsmount *vfsmntlist = (struct vfsmount *) NULL;static struct vfsmount *vfsmnttail = (struct vfsmount *) NULL, *mru_vfsmnt = (struct vfsmount *) NULL;#endif /* OSKIT */#ifndef OSKIT/* * This part handles the management of the list of mounted filesystems. */struct vfsmount *lookup_vfsmnt(kdev_t dev){ struct vfsmount *lptr; 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 */}static struct vfsmount *add_vfsmnt(struct super_block *sb, const char *dev_name, const char *dir_name){ struct vfsmount *lptr; char *tmp, *name; lptr = (struct vfsmount *)kmalloc(sizeof(struct vfsmount), GFP_KERNEL); if (!lptr) goto out; memset(lptr, 0, sizeof(struct vfsmount)); lptr->mnt_sb = sb; lptr->mnt_dev = sb->s_dev; lptr->mnt_flags = sb->s_flags; sema_init(&lptr->mnt_dquot.dqio_sem, 1); sema_init(&lptr->mnt_dquot.dqoff_sem, 1); lptr->mnt_dquot.flags = 0; /* 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 (name) { strcpy(name, tmp); lptr->mnt_devname = name; } putname(tmp); } if (dir_name && !IS_ERR(tmp = getname(dir_name))) { name = (char *) kmalloc(strlen(tmp)+1, GFP_KERNEL); if (name) { strcpy(name, tmp); lptr->mnt_dirname = name; } putname(tmp); } if (vfsmntlist == (struct vfsmount *)NULL) { vfsmntlist = vfsmnttail = lptr; } else { vfsmnttail->mnt_next = lptr; vfsmnttail = lptr; }out: return lptr;}static 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; } if (tofree == mru_vfsmnt) mru_vfsmnt = NULL; kfree(tofree->mnt_devname); kfree(tofree->mnt_dirname); kfree_s(tofree, sizeof(struct vfsmount));}#endif /* OSKIT */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;}#ifndef OSKIT#ifdef CONFIG_MODULESint unregister_filesystem(struct file_system_type * fs){ struct file_system_type ** tmp; tmp = &file_systems; while (*tmp) { if (fs == *tmp) { *tmp = fs->next; fs->next = NULL; return 0; } tmp = &(*tmp)->next; } return -EINVAL;}#endifstatic int fs_index(const char * __name){ struct file_system_type * tmp; char * name; int err, index; name = getname(__name); err = PTR_ERR(name); if (IS_ERR(name)) return err; index = 0; for (tmp = file_systems ; tmp ; tmp = tmp->next) { if (strcmp(tmp->name, name) == 0) { putname(name); return index; } index++; } putname(name); return -EINVAL;}static int fs_name(unsigned int index, char * buf){ struct file_system_type * tmp; int len; tmp = file_systems; while (tmp && index > 0) { tmp = tmp->next; index--; } if (!tmp) return -EINVAL; len = strlen(tmp->name) + 1; return copy_to_user(buf, tmp->name, len) ? -EFAULT : 0;}static int fs_maxindex(void){ struct file_system_type * tmp; int index; index = 0; for (tmp = file_systems ; tmp ; tmp = tmp->next) index++; return index;}/* * Whee.. Weird sysv syscall. */asmlinkage int sys_sysfs(int option, unsigned long arg1, unsigned long arg2){ int retval = -EINVAL; lock_kernel(); switch (option) { case 1: retval = fs_index((const char *) arg1); break; case 2: retval = fs_name(arg1, (char *) arg2); break; case 3: retval = fs_maxindex(); break; } unlock_kernel(); return retval;}static struct proc_fs_info { int flag; char *str;} fs_info[] = { { MS_NOEXEC, ",noexec" }, { MS_NOSUID, ",nosuid" }, { MS_NODEV, ",nodev" }, { MS_SYNCHRONOUS, ",sync" }, { MS_MANDLOCK, ",mand" }, { MS_NOATIME, ",noatime" }, { MS_NODIRATIME, ",nodiratime" },#ifdef MS_NOSUB /* Can't find this except in mount.c */ { MS_NOSUB, ",nosub" },#endif { 0, NULL }};static struct proc_nfs_info { int flag; char *str;} nfs_info[] = { { NFS_MOUNT_SOFT, ",soft" }, { NFS_MOUNT_INTR, ",intr" }, { NFS_MOUNT_POSIX, ",posix" }, { NFS_MOUNT_NOCTO, ",nocto" }, { NFS_MOUNT_NOAC, ",noac" }, { 0, NULL }};int get_filesystem_info( char *buf ){ struct vfsmount *tmp = vfsmntlist; struct proc_fs_info *fs_infop; struct proc_nfs_info *nfs_infop; struct nfs_server *nfss; int len = 0; while ( tmp && len < PAGE_SIZE - 160) { len += sprintf( buf + len, "%s %s %s %s", tmp->mnt_devname, tmp->mnt_dirname, tmp->mnt_sb->s_type->name, tmp->mnt_flags & MS_RDONLY ? "ro" : "rw" ); for (fs_infop = fs_info; fs_infop->flag; fs_infop++) { if (tmp->mnt_flags & fs_infop->flag) { strcpy(buf + len, fs_infop->str); len += strlen(fs_infop->str); } } 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); }#if 0 if (nfss->timeo != 7*HZ/10) { len += sprintf(buf+len, ",timeo=%d", nfss->timeo*10/HZ); } if (nfss->retrans != 3) { len += sprintf(buf+len, ",retrans=%d", nfss->retrans); }#endif if (nfss->acregmin != 3*HZ) { len += sprintf(buf+len, ",acregmin=%d", nfss->acregmin/HZ); } if (nfss->acregmax != 60*HZ) { len += sprintf(buf+len, ",acregmax=%d", nfss->acregmax/HZ); } if (nfss->acdirmin != 30*HZ) { len += sprintf(buf+len, ",acdirmin=%d", nfss->acdirmin/HZ); } if (nfss->acdirmax != 60*HZ) { len += sprintf(buf+len, ",acdirmax=%d", 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); } } len += sprintf(buf+len, ",addr=%s", nfss->hostname); } len += sprintf( buf + len, " 0 0\n" ); tmp = tmp->mnt_next; } return len;}int get_filesystem_list(char * buf){ int len = 0; struct file_system_type * tmp; tmp = file_systems; while (tmp && len < PAGE_SIZE - 80) { len += sprintf(buf+len, "%s\t%s\n", (tmp->fs_flags & FS_REQUIRES_DEV) ? "" : "nodev", tmp->name); tmp = tmp->next; } return len;}#endif /* OSKIT */struct file_system_type *get_fs_type(const char *name){ struct file_system_type * fs = file_systems; if (!name) return fs; for (fs = file_systems; fs && strcmp(fs->name, name); fs = fs->next) ;#ifdef CONFIG_KMOD if (!fs && (request_module(name) == 0)) { for (fs = file_systems; fs && strcmp(fs->name, name); fs = fs->next) ; }#endif return fs;}void __wait_on_super(struct super_block * sb){ struct wait_queue wait = { current, NULL }; add_wait_queue(&sb->s_wait, &wait);repeat: current->state = TASK_UNINTERRUPTIBLE; if (sb->s_lock) { schedule(); goto repeat; } remove_wait_queue(&sb->s_wait, &wait); current->state = TASK_RUNNING;}/* * Note: check the dirty flag before waiting, so we don't * hold up the sync while mounting a device. (The newly * mounted device won't need syncing.)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?