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