super.c

来自「elinux jffs初始版本 具体了解JFFS的文件系统!」· C语言 代码 · 共 1,110 行 · 第 1/2 页

C
1,110
字号
			return MKDEV(UNNAMED_MAJOR, i);	}	printk("VFS: Sorry, out of unnamed devices\n");	return 0;}void put_unnamed_dev(kdev_t dev){	if (!dev)		return;	if (MAJOR(dev) == UNNAMED_MAJOR &&	    clear_bit(MINOR(dev), unnamed_dev_in_use))		return;	printk("VFS: put_unnamed_dev: freeing unused device %s\n",			kdevname(dev));}static int do_umount(kdev_t dev,int unmount_root){	struct super_block * sb;	int retval;		if (dev==ROOT_DEV && !unmount_root) {		/*		 * 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)) {			/*			 * Make sure all quotas are turned off on this device we need to mount			 * it readonly so no more writes by the quotasystem.			 * If later on the remount fails too bad there are no quotas running			 * anymore. Turn them on again by hand.			 */			quota_off(dev, -1);			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(%s): mounted inode has i_mount=NULL\n",		       kdevname(dev));	/*	 * Before checking if the filesystem is still busy make sure the kernel	 * doesn't hold any quotafiles open on that device. If the umount fails	 * too bad there are no quotas running anymore. Turn them on again by hand.	 */	quota_off(dev, -1);	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);	remove_vfsmnt(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;	kdev_t dev;	int retval;	struct inode dummy_inode;	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->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;	}	retval = do_umount(dev,0);	if (!retval) {		fsync_dev(dev);		if (dev != ROOT_DEV) {			blkdev_release (inode);			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. */int do_mount(kdev_t dev, const char * dev_name, const char * dir_name, const char * type, int flags, void * data){	struct inode * dir_i;	struct super_block * sb;	struct vfsmount *vfsmnt;	int error;	if (!(flags & MS_RDONLY) && dev && is_read_only(dev))		return -EACCES;		/*flags |= MS_RDONLY;*/	error = namei(dir_name, &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 -ENOTDIR;	}	if (!fs_may_mount(dev)) {		iput(dir_i);		return -EBUSY;	}	sb = read_super(dev,type,flags,data,0);	if (!sb) {		iput(dir_i);		return -EINVAL;	}	if (sb->s_covered) {		iput(dir_i);		return -EBUSY;	}	vfsmnt = add_vfsmnt(dev, dev_name, dir_name);	if (vfsmnt) {		vfsmnt->mnt_sb = sb;		vfsmnt->mnt_flags = flags;	}	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;	struct vfsmount *vfsmnt;		if (!(flags & MS_RDONLY) && sb->s_dev && is_read_only(sb->s_dev))		return -EACCES;		/*flags |= MS_RDONLY;*/	/* 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);	vfsmnt = lookup_vfsmnt(sb->s_dev);	if (vfsmnt)		vfsmnt->mnt_flags = sb->s_flags;	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;#ifndef NO_MM	struct vm_area_struct * vma;#endif	*where = 0;	if (!data)		return 0;#ifndef NO_MM	vma = find_vma(current->mm, (unsigned long) data);	if (!vma || (unsigned long) data < vma->vm_start)		return -EFAULT;	if (!(vma->vm_flags & VM_READ))		return -EFAULT;	i = vma->vm_end - (unsigned long) data;	if (PAGE_SIZE <= (unsigned long) i)		i = PAGE_SIZE-1;#else	i = PAGE_SIZE-1;#endif	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;	kdev_t dev;	int retval;	const 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;	fops = NULL;	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;		}		fops = get_blkfops(MAJOR(dev));		if (!fops) {			iput(inode);			return -ENOTBLK;		}		if (fops->open) {			struct file dummy;	/* allows read-write or read-only flag */			memset(&dummy, 0, sizeof(dummy));			dummy.f_inode = inode;			dummy.f_mode = (new_flags & MS_RDONLY) ? 1 : 3;			retval = fops->open(inode, &dummy);			if (retval) {				iput(inode);				return retval;			}		}	} else {		if (!(dev = get_unnamed_dev()))			return -EMFILE;		inode = NULL;	}	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,dev_name,dir_name,t,flags,(void *) page);	free_page(page);	if (retval && !fstype->requires_dev) 		put_unnamed_dev(dev);	if (retval && fops && fops->release)		fops->release(inode, NULL);	iput(inode);	return retval;}static void do_mount_root(void){	struct file_system_type * fs_type;	struct super_block * sb;	struct vfsmount *vfsmnt;	struct inode * inode, d_inode;	struct file filp;	int retval;  #ifdef CONFIG_ROOT_NFS	if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR)		if (nfs_root_init(nfs_root_name, nfs_root_addrs) < 0) {			printk(KERN_ERR "Root-NFS: Unable to contact NFS "			    "server for root fs, using /dev/fd0 instead\n");			ROOT_DEV = MKDEV(FLOPPY_MAJOR, 0);		}	if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) {		ROOT_DEV = 0;		if ((fs_type = get_fs_type("nfs"))) {			sb = &super_blocks[0];			while (sb->s_dev) sb++;			sb->s_dev = get_unnamed_dev();			sb->s_flags = root_mountflags & ~MS_RDONLY;			if (nfs_root_mount(sb) >= 0) {				inode = sb->s_mounted;				inode->i_count += 3 ;				sb->s_covered = inode;				sb->s_rd_only = 0;				sb->s_dirt = 0;				sb->s_type = fs_type;				current->fs->pwd = inode;				current->fs->root = inode;				ROOT_DEV = sb->s_dev;				printk (KERN_NOTICE "VFS: Mounted root (nfs filesystem).\n");				vfsmnt = add_vfsmnt(ROOT_DEV, "/dev/root", "/");				if (!vfsmnt)					panic("VFS: add_vfsmnt failed for NFS root.\n");				vfsmnt->mnt_sb = sb;				vfsmnt->mnt_flags = sb->s_flags;				return;			}			sb->s_dev = 0;		}		if (!ROOT_DEV) {			printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n");			ROOT_DEV = MKDEV(FLOPPY_MAJOR, 0);		}	}#endif#ifdef CONFIG_BLK_DEV_FD	if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {		extern int rd_doload;		floppy_eject();#ifndef CONFIG_BLK_DEV_RAM		printk(KERN_NOTICE "(Warning, this kernel has no ramdisk support)\n");#endif#ifdef CONFIG_BLK_DEV_INITRD		/* rd_doload is 2 for a dual initrd/ramload setup */		if(rd_doload==2)			rd_load_secondary();		else#endif				{			printk(KERN_NOTICE "VFS: Insert root floppy and press ENTER\n");			wait_for_keypress();		}	}#endif	memset(&filp, 0, sizeof(filp));	memset(&d_inode, 0, sizeof(d_inode));	d_inode.i_rdev = ROOT_DEV;	filp.f_inode = &d_inode;	if ( root_mountflags & MS_RDONLY)		filp.f_mode = 1; /* read only */	else		filp.f_mode = 3; /* read write */	retval = blkdev_open(&d_inode, &filp);	if (retval == -EROFS) {		root_mountflags |= MS_RDONLY;		filp.f_mode = 1;		retval = blkdev_open(&d_inode, &filp);	}	if (retval)	        /*		 * Allow the user to distinguish between failed open		 * and bad superblock on root device.		 */		printk("VFS: Cannot open root device %s\n",		       kdevname(ROOT_DEV));	else for (fs_type = file_systems ; fs_type ; fs_type = fs_type->next) {  		if (!fs_type->requires_dev)  			continue;  		sb = read_super(ROOT_DEV,fs_type->name,root_mountflags,NULL,0);		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->fs->pwd = inode;			current->fs->root = inode;			printk ("VFS: Mounted root (%s filesystem)%s.\n",				fs_type->name,				(sb->s_flags & MS_RDONLY) ? " readonly" : "");			vfsmnt = add_vfsmnt(ROOT_DEV, "/dev/root", "/");			if (!vfsmnt)				panic("VFS: add_vfsmnt failed for root fs");			vfsmnt->mnt_sb = sb;			vfsmnt->mnt_flags = root_mountflags;			return;		}	}	panic("VFS: Unable to mount root fs on %s",		kdevname(ROOT_DEV));}void mount_root(void){	memset(super_blocks, 0, sizeof(super_blocks));	do_mount_root();}#ifdef CONFIG_BLK_DEV_INITRDint change_root(kdev_t new_root_dev,const char *put_old){	kdev_t old_root_dev;	struct vfsmount *vfsmnt;	struct inode *old_root,*old_pwd,*inode;	unsigned long old_fs;	int error;	old_root = current->fs->root;	old_pwd = current->fs->pwd;	old_root_dev = ROOT_DEV;	if (!fs_may_mount(new_root_dev)) {		printk(KERN_CRIT "New root is busy. Staying in initrd.\n");		return -EBUSY;	}	ROOT_DEV = new_root_dev;	do_mount_root();	old_fs = get_fs();	set_fs(get_ds());        error = namei(put_old,&inode);	if (error) inode = NULL;	set_fs(old_fs);	if (!error && (inode->i_count != 1 || inode->i_mount)) error = -EBUSY;	if (!error && !S_ISDIR(inode->i_mode)) error = -ENOTDIR;	iput(old_root); /* current->fs->root */	iput(old_pwd); /* current->fs->pwd */	if (error) {		int umount_error;		if (inode) iput(inode);		printk(KERN_NOTICE "Trying to unmount old root ... ");		old_root->i_mount = old_root;			/* does this belong into do_mount_root ? */		umount_error = do_umount(old_root_dev,1);		if (umount_error) printk(KERN_ERR "error %d\n",umount_error);		else {			printk("okay\n");			invalidate_buffers(old_root_dev);		}		return umount_error ? error : 0;	}	iput(old_root); /* sb->s_covered */	remove_vfsmnt(old_root_dev);	vfsmnt = add_vfsmnt(old_root_dev,"/dev/root.old",put_old);	if (!vfsmnt) printk(KERN_CRIT "Trouble: add_vfsmnt failed\n");	else {		vfsmnt->mnt_sb = old_root->i_sb;		vfsmnt->mnt_sb->s_covered = inode;		vfsmnt->mnt_flags = vfsmnt->mnt_sb->s_flags;	}	inode->i_mount = old_root;	return 0;}#endif

⌨️ 快捷键说明

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