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