super.c
来自「elinux jffs初始版本 具体了解JFFS的文件系统!」· C语言 代码 · 共 1,110 行 · 第 1/2 页
C
1,110 行
/* * linux/fs/super.c * * Copyright (C) 1991, 1992 Linus Torvalds * * super.c contains code to handle: - mount structures * - super-block tables. * - mount systemcall * - umount systemcall * * 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 */#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>#include <linux/string.h>#include <linux/locks.h>#include <linux/mm.h>#include <linux/fd.h>#include <asm/system.h>#include <asm/segment.h>#include <asm/bitops.h>#ifdef CONFIG_KERNELD#include <linux/kerneld.h>#endif #include <linux/nfs_fs.h>#include <linux/nfs_fs_sb.h>#include <linux/nfs_mount.h>extern void wait_for_keypress(void);extern struct file_operations * get_blkfops(unsigned int major);extern void blkdev_release (struct inode *);extern int root_mountflags;static int do_remount_sb(struct super_block *sb, int flags, char * data);/* this is initialized in init/main.c */kdev_t ROOT_DEV;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;/* * 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 */}struct vfsmount *add_vfsmnt(kdev_t dev, const char *dev_name, const char *dir_name){ struct vfsmount *lptr; char *tmp; lptr = (struct vfsmount *)kmalloc(sizeof(struct vfsmount), GFP_KERNEL); if (!lptr) return 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)+1, GFP_KERNEL)) != (char *)NULL) strcpy(lptr->mnt_devname, tmp); putname(tmp); } if (dir_name && !getname(dir_name, &tmp)) { if ((lptr->mnt_dirname = (char *) kmalloc(strlen(tmp)+1, 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; } if (tofree == mru_vfsmnt) mru_vfsmnt = NULL; 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;}#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; err = getname(__name, &name); if (err) 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 err, len; tmp = file_systems; while (tmp && index > 0) { tmp = tmp->next; index--; } if (!tmp) return -EINVAL; len = strlen(tmp->name) + 1; err = verify_area(VERIFY_WRITE, buf, len); if (err) return err; memcpy_tofs(buf, tmp->name, len); return 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, ...){ va_list args; int retval = -EINVAL; unsigned int index; va_start(args, option); switch (option) { case 1: retval = fs_index(va_arg(args, const char *)); break; case 2: index = va_arg(args, unsigned int); retval = fs_name(index, va_arg(args, char *)); break; case 3: retval = fs_maxindex(); break; } va_end(args); 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" },#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 (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); } 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->requires_dev ? "" : "nodev", tmp->name); tmp = tmp->next; } return len;}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_KERNELD 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;}void sync_supers(kdev_t dev){ struct super_block * sb; for (sb = super_blocks + 0 ; sb < super_blocks + NR_SUPER ; sb++) { if (!sb->s_dev) continue; if (dev && sb->s_dev != dev) continue; wait_on_super(sb); if (!sb->s_dev || !sb->s_dirt) continue; if (dev && (dev != sb->s_dev)) continue; if (sb->s_op && sb->s_op->write_super) sb->s_op->write_super(sb); }}static struct super_block * get_super(kdev_t dev){ struct super_block * s; if (!dev) return NULL; s = 0+super_blocks; while (s < NR_SUPER+super_blocks) if (s->s_dev == dev) { wait_on_super(s); if (s->s_dev == dev) return s; s = 0+super_blocks; } else s++; return NULL;}void put_super(kdev_t dev){ struct super_block * sb; if (dev == ROOT_DEV) { printk("VFS: Root device %s: prepare for armageddon\n", kdevname(dev)); return; } if (!(sb = get_super(dev))) return; if (sb->s_covered) { printk("VFS: Mounted device %s - tssk, tssk\n", kdevname(dev)); return; } if (sb->s_op && sb->s_op->put_super) sb->s_op->put_super(sb);}asmlinkage int sys_ustat(dev_t dev, struct ustat * ubuf){ struct super_block *s; struct ustat tmp; struct statfs sbuf; unsigned long old_fs; int error; s = get_super(to_kdev_t(dev)); if (s == NULL) return -EINVAL; if (!(s->s_op->statfs)) return -ENOSYS; error = verify_area(VERIFY_WRITE,ubuf,sizeof(struct ustat)); if (error) return error; old_fs = get_fs(); set_fs(get_ds()); s->s_op->statfs(s,&sbuf,sizeof(struct statfs)); set_fs(old_fs); memset(&tmp,0,sizeof(struct ustat)); tmp.f_tfree = sbuf.f_bfree; tmp.f_tinode = sbuf.f_ffree; memcpy_tofs(ubuf,&tmp,sizeof(struct ustat)); return 0;}static struct super_block * read_super(kdev_t dev,const char *name,int flags, void *data, int silent){ struct super_block * s; struct file_system_type *type; if (!dev) return NULL; check_disk_change(dev); s = get_super(dev); if (s) return s; if (!(type = get_fs_type(name))) { printk("VFS: on device %s: get_fs_type(%s) failed\n", kdevname(dev), name); return NULL; } for (s = 0+super_blocks ;; s++) { if (s >= NR_SUPER+super_blocks) return NULL; if (!(s->s_dev)) break; } s->s_dev = dev; s->s_flags = flags; if (!type->read_super(s,data, silent)) { s->s_dev = 0; return NULL; } s->s_dev = dev; s->s_covered = NULL; s->s_rd_only = 0; s->s_dirt = 0; s->s_type = type; return s;}/* * Unnamed block devices are dummy devices used by virtual * filesystems which don't use real block-devices. -- jrs */static unsigned int unnamed_dev_in_use[256/(8*sizeof(unsigned int))] = { 0, };kdev_t get_unnamed_dev(void){ int i; for (i = 1; i < 256; i++) { if (!set_bit(i,unnamed_dev_in_use))
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?