super.c

来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 1,342 行 · 第 1/3 页

C
1,342
字号
 */void sync_supers(kdev_t dev){	struct super_block * sb;	for (sb = sb_entry(super_blocks.next);	     sb != sb_entry(&super_blocks); 	     sb = sb_entry(sb->s_list.next)) {		if (!sb->s_dev)			continue;		if (dev && sb->s_dev != dev)			continue;		if (!sb->s_dirt)			continue;		/* N.B. Should lock the superblock while writing */		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);	}}struct super_block * get_super(kdev_t dev){	struct super_block * s;	if (!dev)		return NULL;restart:	s = sb_entry(super_blocks.next);	while (s != sb_entry(&super_blocks))		if (s->s_dev == dev) {			wait_on_super(s);			if (s->s_dev == dev)				return s;			goto restart;		} else			s = sb_entry(s->s_list.next);	return NULL;}#ifndef OSKITasmlinkage int sys_ustat(dev_t dev, struct ustat * ubuf){        struct super_block *s;        struct ustat tmp;        struct statfs sbuf;        mm_segment_t old_fs;	int err = -EINVAL;	lock_kernel();        s = get_super(to_kdev_t(dev));        if (s == NULL)                goto out;	err = -ENOSYS;        if (!(s->s_op->statfs))                goto out;        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;        err = copy_to_user(ubuf,&tmp,sizeof(struct ustat)) ? -EFAULT : 0;out:	unlock_kernel();	return err;}#endif /* OSKIT *//* * Find a super_block with no device assigned. */static struct super_block *get_empty_super(void){	struct super_block *s;	for (s  = sb_entry(super_blocks.next);	     s != sb_entry(&super_blocks); 	     s  = sb_entry(s->s_list.next)) {		if (s->s_dev)			continue;		if (!s->s_lock)			return s;		printk("VFS: empty superblock %p locked!\n", s);	}	/* Need a new one... */	if (nr_super_blocks >= max_super_blocks)		return NULL;	s = kmalloc(sizeof(struct super_block),  GFP_USER);	if (s) {		nr_super_blocks++;		memset(s, 0, sizeof(struct super_block));		INIT_LIST_HEAD(&s->s_dirty);		list_add (&s->s_list, super_blocks.prev);	}	return s;}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)		goto out_null;	check_disk_change(dev);	s = get_super(dev);	if (s)		goto out;	type = get_fs_type(name);	if (!type) {		printk("VFS: on device %s: get_fs_type(%s) failed\n",		       kdevname(dev), name);		goto out;	}	s = get_empty_super();	if (!s)		goto out;	s->s_dev = dev;	s->s_flags = flags;	s->s_dirt = 0;	sema_init(&s->s_vfs_rename_sem,1);	/* N.B. Should lock superblock now ... */	if (!type->read_super(s, data, silent))		goto out_fail;	s->s_dev = dev; /* N.B. why do this again?? */	s->s_rd_only = 0;	s->s_type = type;out:	return s;	/* N.B. s_dev should be cleared in type->read_super */out_fail:	s->s_dev = 0;out_null:	s = NULL;	goto out;}#ifndef OSKIT/* * 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 (!test_and_set_bit(i,unnamed_dev_in_use))			return MKDEV(UNNAMED_MAJOR, i);	}	return 0;}void put_unnamed_dev(kdev_t dev){	if (!dev || MAJOR(dev) != UNNAMED_MAJOR)		return;	if (test_and_clear_bit(MINOR(dev), unnamed_dev_in_use))		return;	printk("VFS: put_unnamed_dev: freeing unused device %s\n",			kdevname(dev));}#endif /* OSKIT */#ifdef OSKIT       int d_umount(struct super_block * sb)#elsestatic int d_umount(struct super_block * sb)#endif{	struct dentry * root = sb->s_root;	struct dentry * covered = root->d_covers;	if (root->d_count != 1)		return -EBUSY;	if (root->d_inode->i_state)		return -EBUSY;	sb->s_root = NULL;	if (covered != root) {		root->d_covers = root;		covered->d_mounts = covered;		dput(covered);	}	dput(root);	return 0;}#ifndef OSKITstatic void d_mount(struct dentry *covered, struct dentry *dentry){	if (covered->d_mounts != covered) {		printk("VFS: mount - already mounted\n");		return;	}	covered->d_mounts = dentry;	dentry->d_covers = covered;}static int do_umount(kdev_t dev, int unmount_root, int flags){	struct super_block * sb;	int retval;		retval = -ENOENT;	sb = get_super(dev);	if (!sb || !sb->s_root)		goto out;	/*	 * Before checking whether the filesystem is still busy,	 * make sure the kernel doesn't hold any quota files open	 * on the device. If the umount fails, too bad -- there	 * are no quotas running any more. Just turn them on again.	 */	DQUOT_OFF(dev);	acct_auto_close(dev);	/*	 * If we may have to abort operations to get out of this	 * mount, and they will themselves hold resources we must	 * allow the fs to do things. In the Unix tradition of	 * 'Gee thats tricky lets do it in userspace' the umount_begin	 * might fail to complete on the first run through as other tasks	 * must return, and the like. Thats for the mount program to worry	 * about for the moment.	 */	 	if( (flags&MNT_FORCE) && sb->s_op->umount_begin)		sb->s_op->umount_begin(sb);	/*	 * Shrink dcache, then fsync. This guarantees that if the	 * filesystem is quiescent at this point, then (a) only the	 * root entry should be in use and (b) that root entry is	 * clean.	 */	shrink_dcache_sb(sb);	fsync_dev(dev);	if (dev==ROOT_DEV && !unmount_root) {		/*		 * Special case for "unmounting" root ...		 * we just try to remount it readonly.		 */		retval = 0;		if (!(sb->s_flags & MS_RDONLY))			retval = do_remount_sb(sb, MS_RDONLY, 0);		return retval;	}	retval = d_umount(sb);	if (retval)		goto out;	if (sb->s_op) {		if (sb->s_op->write_super && sb->s_dirt)			sb->s_op->write_super(sb);	}	lock_super(sb);	if (sb->s_op) {		if (sb->s_op->put_super)			sb->s_op->put_super(sb);	}	/* Forget any remaining inodes */	if (invalidate_inodes(sb)) {		printk("VFS: Busy inodes after unmount. "			"Self-destruct in 5 seconds.  Have a nice day...\n");	}	sb->s_dev = 0;		/* Free the superblock */	unlock_super(sb);	remove_vfsmnt(dev);out:	return retval;}static int umount_dev(kdev_t dev, int flags){	int retval;	struct inode * inode = get_empty_inode();	retval = -ENOMEM;	if (!inode)		goto out;	inode->i_rdev = dev;	retval = -ENXIO;	if (MAJOR(dev) >= MAX_BLKDEV)		goto out_iput;	fsync_dev(dev);	down(&mount_sem);	retval = do_umount(dev, 0, flags);	if (!retval) {		fsync_dev(dev);		if (dev != ROOT_DEV) {			blkdev_release(inode);			put_unnamed_dev(dev);		}	}	up(&mount_sem);out_iput:	iput(inode);out:	return retval;}/* * Now umount can handle mount points as well as block devices. * This is important for filesystems which use unnamed block devices. * * There is a little kludge here with the dummy_inode.  The current * vfs release functions only use the r_dev field in the inode so * we give them the info they need without using a real inode. * If any other fields are ever needed by any block device release * functions, they should be faked here.  -- jrs * * We now support a flag for forced unmount like the other 'big iron' * unixes. Our API is identical to OSF/1 to avoid making a mess of AMD */asmlinkage int sys_umount(char * name, int flags){	struct dentry * dentry;	int retval;	if (!capable(CAP_SYS_ADMIN))		return -EPERM;	lock_kernel();	dentry = namei(name);	retval = PTR_ERR(dentry);	if (!IS_ERR(dentry)) {		struct inode * inode = dentry->d_inode;		kdev_t dev = inode->i_rdev;		retval = 0;				if (S_ISBLK(inode->i_mode)) {			if (IS_NODEV(inode))				retval = -EACCES;		} else {			struct super_block *sb = inode->i_sb;			retval = -EINVAL;			if (sb && inode == sb->s_root->d_inode) {				dev = sb->s_dev;				retval = 0;			}		}		dput(dentry);		if (!retval)			retval = umount_dev(dev, flags);	}	unlock_kernel();	return retval;}/* *	The 2.0 compatible umount. No flags.  */ asmlinkage int sys_oldumount(char * name){	return sys_umount(name,0);}/* * Check whether we can mount the specified device. */int fs_may_mount(kdev_t dev){	struct super_block * sb = get_super(dev);	int busy;	busy = sb && sb->s_root &&	       (sb->s_root->d_count != 1 || sb->s_root->d_covers != sb->s_root);	return !busy;}/* * do_mount() does the actual mounting after sys_mount has done the ugly * parameter parsing. When enough time has gone by, and everything uses the * new mount() parameters, sys_mount() can then be cleaned up. * * We cannot mount a filesystem if it has active, used, or dirty inodes. * We also have to flush all inode-data for this device, as the new mount * might need new info. * * [21-Mar-97] T.Schoebel-Theuer: Now this can be overridden when * supplying a leading "!" before the dir_name, allowing "stacks" of * mounted filesystems. The stacking will only influence any pathname lookups * _after_ the mount, but open file descriptors or working directories that * are now covered remain valid. For example, when you overmount /home, any * process with old cwd /home/joe will continue to use the old versions, * as long as relative paths are used, but absolute paths like /home/joe/xxx * will go to the new "top of stack" version. In general, crossing a * mount point will always go to the top of stack element. * Anyone using this new feature must know what he/she is doing. */int do_mount(kdev_t dev, const char * dev_name, const char * dir_name, const char * type, int flags, void * data){	struct dentry * dir_d;	struct super_block * sb;	struct vfsmount *vfsmnt;	int error;	error = -EACCES;	if (!(flags & MS_RDONLY) && dev && is_read_only(dev))		goto out;	/*	 * Do the lookup first to force automounting.	 */	dir_d = namei(dir_name);	error = PTR_ERR(dir_d);	if (IS_ERR(dir_d))		goto out;	down(&mount_sem);	error = -ENOTDIR;	if (!S_ISDIR(dir_d->d_inode->i_mode))		goto dput_and_out;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?