⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 super.c

📁 linux1.1源代码
💻 C
字号:
/* *  linux/fs/super.c * *  Copyright (C) 1991, 1992  Linus Torvalds *//* * super.c contains code to handle the super-block tables. */#include <linux/config.h>#include <linux/sched.h>#include <linux/kernel.h>#include <linux/major.h>#include <linux/stat.h>#include <linux/errno.h>#include <linux/string.h>#include <linux/locks.h>#include <asm/system.h>#include <asm/segment.h> /* * The definition of file_systems that used to be here is now in * filesystems.c.  Now super.c contains no fs specific code.  -- jrs */extern struct file_system_type file_systems[];extern struct file_operations * get_blkfops(unsigned int);extern struct file_operations * get_chrfops(unsigned int);extern void wait_for_keypress(void);extern void fcntl_init_locks(void);extern int root_mountflags;struct super_block super_blocks[NR_SUPER];static int do_remount_sb(struct super_block *sb, int flags, char * data);/* this is initialized in init/main.c */dev_t ROOT_DEV = 0;struct file_system_type *get_fs_type(char *name){	int a;		if (!name)		return &file_systems[0];	for(a = 0 ; file_systems[a].read_super ; a++)		if (!strcmp(name,file_systems[a].name))			return(&file_systems[a]);	return NULL;}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(dev_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(dev_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(dev_t dev){	struct super_block * sb;	if (dev == ROOT_DEV) {		printk("VFS: Root device %d/%d: prepare for armageddon\n",							MAJOR(dev), MINOR(dev));		return;	}	if (!(sb = get_super(dev)))		return;	if (sb->s_covered) {		printk("VFS: Mounted device %d/%d - tssk, tssk\n",						MAJOR(dev), MINOR(dev));		return;	}	if (sb->s_op && sb->s_op->put_super)		sb->s_op->put_super(sb);}static struct super_block * read_super(dev_t dev,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 %d/%d: get_fs_type(%s) failed\n",						MAJOR(dev), MINOR(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;	return s;}/* * Unnamed block devices are dummy devices used by virtual * filesystems which don't use real block-devices.  -- jrs */static char unnamed_dev_in_use[256];static dev_t get_unnamed_dev(void){	static int first_use = 0;	int i;	if (first_use == 0) {		first_use = 1;		memset(unnamed_dev_in_use, 0, sizeof(unnamed_dev_in_use));		unnamed_dev_in_use[0] = 1; /* minor 0 (nodev) is special */	}	for (i = 0; i < sizeof unnamed_dev_in_use/sizeof unnamed_dev_in_use[0]; i++) {		if (!unnamed_dev_in_use[i]) {			unnamed_dev_in_use[i] = 1;			return (UNNAMED_MAJOR << 8) | i;		}	}	return 0;}static void put_unnamed_dev(dev_t dev){	if (!dev)		return;	if (!unnamed_dev_in_use[dev]) {		printk("VFS: put_unnamed_dev: freeing unused device %d/%d\n",							MAJOR(dev), MINOR(dev));		return;	}	unnamed_dev_in_use[dev] = 0;}static int do_umount(dev_t dev){	struct super_block * sb;	int retval;		if (dev==ROOT_DEV) {		/* Special case for "unmounting" root.  We just try to remount		   it readonly, and sync() the device. */		if (!(sb=get_super(dev)))			return -ENOENT;		if (!(sb->s_flags & MS_RDONLY)) {			fsync_dev(dev);			retval = do_remount_sb(sb, MS_RDONLY, 0);			if (retval)				return retval;		}		return 0;	}	if (!(sb=get_super(dev)) || !(sb->s_covered))		return -ENOENT;	if (!sb->s_covered->i_mount)		printk("VFS: umount(%d/%d): mounted inode has i_mount=NULL\n",							MAJOR(dev), MINOR(dev));	if (!fs_may_umount(dev, sb->s_mounted))		return -EBUSY;	sb->s_covered->i_mount = NULL;	iput(sb->s_covered);	sb->s_covered = NULL;	iput(sb->s_mounted);	sb->s_mounted = NULL;	if (sb->s_op && sb->s_op->write_super && sb->s_dirt)		sb->s_op->write_super(sb);	put_super(dev);	return 0;}/* * 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 */asmlinkage int sys_umount(char * name){	struct inode * inode;	dev_t dev;	int retval;	struct inode dummy_inode;	struct file_operations * fops;	if (!suser())		return -EPERM;	retval = namei(name,&inode);	if (retval) {		retval = lnamei(name,&inode);		if (retval)			return retval;	}	if (S_ISBLK(inode->i_mode)) {		dev = inode->i_rdev;		if (IS_NODEV(inode)) {			iput(inode);			return -EACCES;		}	} else {		if (!inode || !inode->i_sb || inode != inode->i_sb->s_mounted) {			iput(inode);			return -EINVAL;		}		dev = inode->i_sb->s_dev;		iput(inode);		memset(&dummy_inode, 0, sizeof(dummy_inode));		dummy_inode.i_rdev = dev;		inode = &dummy_inode;	}	if (MAJOR(dev) >= MAX_BLKDEV) {		iput(inode);		return -ENXIO;	}	if (!(retval = do_umount(dev)) && dev != ROOT_DEV) {		fops = get_blkfops(MAJOR(dev));		if (fops && fops->release)			fops->release(inode,NULL);		if (MAJOR(dev) == UNNAMED_MAJOR)			put_unnamed_dev(dev);	}	if (inode != &dummy_inode)		iput(inode);	if (retval)		return retval;	fsync_dev(dev);	return 0;}/* * 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. */static int do_mount(dev_t dev, const char * dir, char * type, int flags, void * data){	struct inode * dir_i;	struct super_block * sb;	int error;	error = namei(dir,&dir_i);	if (error)		return error;	if (dir_i->i_count != 1 || dir_i->i_mount) {		iput(dir_i);		return -EBUSY;	}	if (!S_ISDIR(dir_i->i_mode)) {		iput(dir_i);		return -EPERM;	}	if (!fs_may_mount(dev)) {		iput(dir_i);		return -EBUSY;	}	sb = read_super(dev,type,flags,data,0);	if (!sb || sb->s_covered) {		iput(dir_i);		return -EBUSY;	}	sb->s_covered = dir_i;	dir_i->i_mount = sb->s_mounted;	return 0;		/* we don't iput(dir_i) - see umount */}/* * Alters the mount flags of a mounted file system. Only the mount point * is used as a reference - file system type and the device are ignored. * FS-specific mount options can't be altered by remounting. */static int do_remount_sb(struct super_block *sb, int flags, char *data){	int retval;		/* If we are remounting RDONLY, make sure there are no rw files open */	if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY))		if (!fs_may_remount_ro(sb->s_dev))			return -EBUSY;	if (sb->s_op && sb->s_op->remount_fs) {		retval = sb->s_op->remount_fs(sb, &flags, data);		if (retval)			return retval;	}	sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) |		(flags & MS_RMT_MASK);	return 0;}static int do_remount(const char *dir,int flags,char *data){	struct inode *dir_i;	int retval;	retval = namei(dir,&dir_i);	if (retval)		return retval;	if (dir_i != dir_i->i_sb->s_mounted) {		iput(dir_i);		return -EINVAL;	}	retval = do_remount_sb(dir_i->i_sb, flags, data);	iput(dir_i);	return retval;}static int copy_mount_options (const void * data, unsigned long *where){	int i;	unsigned long page;	struct vm_area_struct * vma;	*where = 0;	if (!data)		return 0;	for (vma = current->mmap ; ; ) {		if (!vma ||		    (unsigned long) data < vma->vm_start) {			return -EFAULT;		}		if ((unsigned long) data < vma->vm_end)			break;		vma = vma->vm_next;	}	i = vma->vm_end - (unsigned long) data;	if (PAGE_SIZE <= (unsigned long) i)		i = PAGE_SIZE-1;	if (!(page = __get_free_page(GFP_KERNEL))) {		return -ENOMEM;	}	memcpy_fromfs((void *) page,data,i);	*where = page;	return 0;}/* * Flags is a 16-bit value that allows up to 16 non-fs dependent flags to * be given to the mount() call (ie: read-only, no-dev, no-suid etc). * * data is a (void *) that can point to any structure up to * PAGE_SIZE-1 bytes, which can contain arbitrary fs-dependent * information (or be NULL). * * NOTE! As old versions of mount() didn't use this setup, the flags * has to have a special 16-bit magic number in the hight word: * 0xC0ED. If this magic word isn't present, the flags and data info * isn't used, as the syscall assumes we are talking to an older * version that didn't understand them. */asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,	unsigned long new_flags, void * data){	struct file_system_type * fstype;	struct inode * inode;	struct file_operations * fops;	dev_t dev;	int retval;	char * t;	unsigned long flags = 0;	unsigned long page = 0;	if (!suser())		return -EPERM;	if ((new_flags &	     (MS_MGC_MSK | MS_REMOUNT)) == (MS_MGC_VAL | MS_REMOUNT)) {		retval = copy_mount_options (data, &page);		if (retval < 0)			return retval;		retval = do_remount(dir_name,				    new_flags & ~MS_MGC_MSK & ~MS_REMOUNT,				    (char *) page);		free_page(page);		return retval;	}	retval = copy_mount_options (type, &page);	if (retval < 0)		return retval;	fstype = get_fs_type((char *) page);	free_page(page);	if (!fstype)				return -ENODEV;	t = fstype->name;	if (fstype->requires_dev) {		retval = namei(dev_name,&inode);		if (retval)			return retval;		if (!S_ISBLK(inode->i_mode)) {			iput(inode);			return -ENOTBLK;		}		if (IS_NODEV(inode)) {			iput(inode);			return -EACCES;		}		dev = inode->i_rdev;		if (MAJOR(dev) >= MAX_BLKDEV) {			iput(inode);			return -ENXIO;		}	} else {		if (!(dev = get_unnamed_dev()))			return -EMFILE;		inode = NULL;	}	fops = get_blkfops(MAJOR(dev));	if (fops && fops->open) {		retval = fops->open(inode,NULL);		if (retval) {			iput(inode);			return retval;		}	}	page = 0;	if ((new_flags & MS_MGC_MSK) == MS_MGC_VAL) {		flags = new_flags & ~MS_MGC_MSK;		retval = copy_mount_options(data, &page);		if (retval < 0) {			iput(inode);			return retval;		}	}	retval = do_mount(dev,dir_name,t,flags,(void *) page);	free_page(page);	if (retval && fops && fops->release)		fops->release(inode,NULL);	iput(inode);	return retval;}void mount_root(void){	struct file_system_type * fs_type;	struct super_block * sb;	struct inode * inode;	memset(super_blocks, 0, sizeof(super_blocks));	fcntl_init_locks();	if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {		printk(KERN_NOTICE "VFS: Insert root floppy and press ENTER\n");		wait_for_keypress();	}	for (fs_type = file_systems; fs_type->read_super; fs_type++) {		if (!fs_type->requires_dev)			continue;		sb = read_super(ROOT_DEV,fs_type->name,root_mountflags,NULL,1);		if (sb) {			inode = sb->s_mounted;			inode->i_count += 3 ;	/* NOTE! it is logically used 4 times, not 1 */			sb->s_covered = inode;			sb->s_flags = root_mountflags;			current->pwd = inode;			current->root = inode;			printk ("VFS: Mounted root (%s filesystem)%s.\n",				fs_type->name,				(sb->s_flags & MS_RDONLY) ? " readonly" : "");			return;		}	}	panic("VFS: Unable to mount root");}

⌨️ 快捷键说明

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