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 + -
显示快捷键?