📄 super.c
字号:
s->s_flags = flags; spin_lock(&sb_lock); insert_super(s, type); lock_super(s); if (!type->read_super(s, data, flags & MS_VERBOSE ? 1 : 0)) goto out_fail; s->s_flags |= MS_ACTIVE; unlock_super(s); /* tell bdcache that we are going to keep this one */ if (bdev) atomic_inc(&bdev->bd_count);out: return s;out_fail: unlock_super(s); deactivate_super(s); remove_super(s); return NULL;}/* * Unnamed block devices are dummy devices used by virtual * filesystems which don't use real block-devices. -- jrs */static unsigned long unnamed_dev_in_use[256/(8*sizeof(unsigned long))];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));}static struct super_block *get_sb_bdev(struct file_system_type *fs_type, char *dev_name, int flags, void * data){ struct inode *inode; struct block_device *bdev; struct block_device_operations *bdops; devfs_handle_t de; struct super_block * s; struct nameidata nd; struct list_head *p; kdev_t dev; int error = 0; mode_t mode = FMODE_READ; /* we always need it ;-) */ /* What device it is? */ if (!dev_name || !*dev_name) return ERR_PTR(-EINVAL); if (path_init(dev_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd)) error = path_walk(dev_name, &nd); if (error) return ERR_PTR(error); inode = nd.dentry->d_inode; error = -ENOTBLK; if (!S_ISBLK(inode->i_mode)) goto out; error = -EACCES; if (nd.mnt->mnt_flags & MNT_NODEV) goto out; bd_acquire(inode); bdev = inode->i_bdev; de = devfs_get_handle_from_inode (inode); bdops = devfs_get_ops (de); /* Increments module use count */ if (bdops) bdev->bd_op = bdops; /* Done with lookups, semaphore down */ dev = to_kdev_t(bdev->bd_dev); if (!(flags & MS_RDONLY)) mode |= FMODE_WRITE; error = blkdev_get(bdev, mode, 0, BDEV_FS); devfs_put_ops (de); /* Decrement module use count now we're safe */ if (error) goto out; check_disk_change(dev); error = -EACCES; if (!(flags & MS_RDONLY) && is_read_only(dev)) { blkdev_put(bdev, BDEV_FS); goto out; } error = -ENOMEM; s = alloc_super(); if (!s) { blkdev_put(bdev, BDEV_FS); goto out; } error = -EBUSY;restart: spin_lock(&sb_lock); list_for_each(p, &super_blocks) { struct super_block *old = sb_entry(p); if (old->s_dev != dev) continue; if (old->s_type != fs_type || ((flags ^ old->s_flags) & MS_RDONLY)) { spin_unlock(&sb_lock); destroy_super(s); blkdev_put(bdev, BDEV_FS); goto out; } if (!grab_super(old)) goto restart; destroy_super(s); blkdev_put(bdev, BDEV_FS); path_release(&nd); return old; } s->s_dev = dev; s->s_bdev = bdev; s->s_flags = flags; insert_super(s, fs_type); error = -EINVAL; lock_super(s); if (!fs_type->read_super(s, data, flags & MS_VERBOSE ? 1 : 0)) goto out_fail; s->s_flags |= MS_ACTIVE; unlock_super(s); path_release(&nd); return s;out_fail: unlock_super(s); deactivate_super(s); remove_super(s);out: path_release(&nd); return ERR_PTR(error);}static struct super_block *get_sb_nodev(struct file_system_type *fs_type, int flags, void * data){ kdev_t dev; int error = -EMFILE; dev = get_unnamed_dev(); if (dev) { struct super_block * sb; error = -EINVAL; sb = read_super(dev, NULL, fs_type, flags, data); if (sb) return sb; } return ERR_PTR(error);}static struct super_block *get_sb_single(struct file_system_type *fs_type, int flags, void *data){ struct super_block * s = alloc_super(); if (!s) return ERR_PTR(-ENOMEM); /* * Get the superblock of kernel-wide instance, but * keep the reference to fs_type. */retry: spin_lock(&sb_lock); if (!list_empty(&fs_type->fs_supers)) { struct super_block *old; old = list_entry(fs_type->fs_supers.next, struct super_block, s_instances); if (!grab_super(old)) goto retry; destroy_super(s); do_remount_sb(old, flags, data); return old; } else { kdev_t dev = get_unnamed_dev(); if (!dev) { spin_unlock(&sb_lock); destroy_super(s); return ERR_PTR(-EMFILE); } s->s_dev = dev; s->s_flags = flags; insert_super(s, fs_type); lock_super(s); if (!fs_type->read_super(s, data, flags & MS_VERBOSE ? 1 : 0)) goto out_fail; s->s_flags |= MS_ACTIVE; unlock_super(s); return s; out_fail: unlock_super(s); deactivate_super(s); remove_super(s); return ERR_PTR(-EINVAL); }}void kill_super(struct super_block *sb){ struct dentry *root = sb->s_root; struct file_system_type *fs = sb->s_type; struct super_operations *sop = sb->s_op; if (!deactivate_super(sb)) return; down_write(&sb->s_umount); lock_kernel(); sb->s_root = NULL; /* Need to clean after the sucker */ if (fs->fs_flags & FS_LITTER) d_genocide(root); shrink_dcache_parent(root); dput(root); fsync_super(sb); lock_super(sb); sb->s_flags &= ~MS_ACTIVE; invalidate_inodes(sb); /* bad name - it should be evict_inodes() */ if (sop) { if (sop->write_super && sb->s_dirt) sop->write_super(sb); if (sop->put_super) sop->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"); } unlock_kernel(); unlock_super(sb); remove_super(sb);}/* * 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. */int do_remount_sb(struct super_block *sb, int flags, void *data){ int retval; if (!(flags & MS_RDONLY) && sb->s_dev && is_read_only(sb->s_dev)) return -EACCES; /*flags |= MS_RDONLY;*/ if (flags & MS_RDONLY) acct_auto_close(sb->s_dev); shrink_dcache_sb(sb); fsync_super(sb); /* 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)) return -EBUSY; if (sb->s_op && sb->s_op->remount_fs) { lock_super(sb); retval = sb->s_op->remount_fs(sb, &flags, data); unlock_super(sb); if (retval) return retval; } sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK); /* * We can't invalidate inodes as we can loose data when remounting * (someone might manage to alter data while we are waiting in lock_super() * or in foo_remount_fs())) */ return 0;}struct vfsmount *do_kern_mount(char *type, int flags, char *name, void *data){ struct file_system_type * fstype; struct vfsmount *mnt = NULL; struct super_block *sb; if (!type || !memchr(type, 0, PAGE_SIZE)) return ERR_PTR(-EINVAL); /* we need capabilities... */ if (!capable(CAP_SYS_ADMIN)) return ERR_PTR(-EPERM); /* ... filesystem driver... */ fstype = get_fs_type(type); if (!fstype) return ERR_PTR(-ENODEV); /* ... allocated vfsmount... */ mnt = alloc_vfsmnt(); if (!mnt) { mnt = ERR_PTR(-ENOMEM); goto fs_out; } set_devname(mnt, name); /* get locked superblock */ if (fstype->fs_flags & FS_REQUIRES_DEV) sb = get_sb_bdev(fstype, name, flags, data); else if (fstype->fs_flags & FS_SINGLE) sb = get_sb_single(fstype, flags, data); else sb = get_sb_nodev(fstype, flags, data); if (IS_ERR(sb)) { free_vfsmnt(mnt); mnt = (struct vfsmount *)sb; goto fs_out; } if (fstype->fs_flags & FS_NOMOUNT) sb->s_flags |= MS_NOUSER; mnt->mnt_sb = sb; mnt->mnt_root = dget(sb->s_root); mnt->mnt_mountpoint = mnt->mnt_root; mnt->mnt_parent = mnt; up_write(&sb->s_umount);fs_out: put_filesystem(fstype); return mnt;}struct vfsmount *kern_mount(struct file_system_type *type){ return do_kern_mount((char *)type->name, 0, (char *)type->name, NULL);}static char * __initdata root_mount_data;static int __init root_data_setup(char *str){ root_mount_data = str; return 1;}static char * __initdata root_fs_names;static int __init fs_names_setup(char *str){ root_fs_names = str; return 1;}__setup("rootflags=", root_data_setup);__setup("rootfstype=", fs_names_setup);static void __init get_fs_names(char *page){ char *s = page; if (root_fs_names) { strcpy(page, root_fs_names); while (*s++) { if (s[-1] == ',') s[-1] = '\0'; } } else { int len = get_filesystem_list(page); char *p, *next; page[len] = '\0'; for (p = page-1; p; p = next) { next = strchr(++p, '\n'); if (*p++ != '\t') continue; while ((*s++ = *p++) != '\n') ; s[-1] = '\0'; } } *s = '\0';}void __init mount_root(void){ struct nameidata root_nd; struct super_block * sb; struct vfsmount *vfsmnt; struct block_device *bdev = NULL; mode_t mode; int retval; void *handle; char path[64]; int path_start = -1; char *name = "/dev/root"; char *fs_names, *p;#ifdef CONFIG_ROOT_NFS void *data;#endif root_mountflags |= MS_VERBOSE;#ifdef CONFIG_ROOT_NFS if (MAJOR(ROOT_DEV) != UNNAMED_MAJOR) goto skip_nfs; data = nfs_root_data(); if (!data) goto no_nfs; vfsmnt = do_kern_mount("nfs", root_mountflags, "/dev/root", data); if (!IS_ERR(vfsmnt)) { printk ("VFS: Mounted root (%s filesystem).\n", "nfs"); ROOT_DEV = vfsmnt->mnt_sb->s_dev; goto attach_it; }no_nfs: printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n"); ROOT_DEV = MKDEV(FLOPPY_MAJOR, 0);skip_nfs:#endif#ifdef CONFIG_BLK_DEV_FD if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {#ifdef CONFIG_BLK_DEV_RAM extern int rd_doload; extern void rd_load_secondary(void);#endif floppy_eject();#ifndef CONFIG_BLK_DEV_RAM printk(KERN_NOTICE "(Warning, this kernel has no ramdisk support)\n");#else /* 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 fs_names = __getname(); get_fs_names(fs_names); devfs_make_root (root_device_name); handle = devfs_find_handle (NULL, ROOT_DEVICE_NAME, MAJOR (ROOT_DEV), MINOR (ROOT_DEV), DEVFS_SPECIAL_BLK, 1); if (handle) /* Sigh: bd*() functions only paper over the cracks */ { unsigned major, minor; devfs_get_maj_min (handle, &major, &minor); ROOT_DEV = MKDEV (major, minor); } /* * Probably pure paranoia, but I'm less than happy about delving into * devfs crap and checking it right now. Later. */ if (!ROOT_DEV) panic("I have no root and I want to scream");retry: bdev = bdget(kdev_t_to_nr(ROOT_DEV)); if (!bdev) panic("%s: unable to allocate root device", __FUNCTION__); bdev->bd_op = devfs_get_ops (handle); /* Increments module use count */ path_start = devfs_generate_path (handle, path + 5, sizeof (path) - 5); mode = FMODE_READ; if (!(root_mountflags & MS_RDONLY)) mode |= FMODE_WRITE; retval = blkdev_get(bdev, mode, 0, BDEV_FS); devfs_put_ops (handle); /* Decrement module use count now we're safe */ if (retval == -EROFS) { root_mountflags |= MS_RDONLY; goto retry; } if (retval) { /* * Allow the user to distinguish between failed open * and bad superblock on root device. */Eio: printk ("VFS: Cannot open root device \"%s\" or %s\n", root_device_name, kdevname (ROOT_DEV)); printk ("Please append a correct \"root=\" boot option\n"); panic("VFS: Unable to mount root fs on %s", kdevname(ROOT_DEV)); } check_disk_change(ROOT_DEV); sb = get_super(ROOT_DEV); if (sb) { /* FIXME */ p = (char *)sb->s_type->name; atomic_inc(&sb->s_active); up_read(&sb->s_umount); down_write(&sb->s_umount); goto mount_it; } for (p = fs_names; *p; p += strlen(p)+1) { struct file_system_type * fs_type = get_fs_type(p); if (!fs_type) continue; atomic_inc(&bdev->bd_count); retval = blkdev_get(bdev, mode, 0, BDEV_FS); if (retval) goto Eio; sb = read_super(ROOT_DEV, bdev, fs_type, root_mountflags, root_mount_data); put_filesystem(fs_type); if (sb) { blkdev_put(bdev, BDEV_FS); goto mount_it; } } panic("VFS: Unable to mount root fs on %s", kdevname(ROOT_DEV));mount_it: /* FIXME */ up_write(&sb->s_umount); printk ("VFS: Mounted root (%s filesystem)%s.\n", p, (sb->s_flags & MS_RDONLY) ? " readonly" : ""); putname(fs_names); if (path_start >= 0) { name = path + path_start; devfs_unregister (devfs_find_handle(NULL, "root", 0, 0, 0, 0)); devfs_mk_symlink (NULL, "root", DEVFS_FL_DEFAULT, name + 5, NULL, NULL); memcpy (name, "/dev/", 5); } vfsmnt = alloc_vfsmnt(); if (!vfsmnt) panic("VFS: alloc_vfsmnt failed for root fs"); set_devname(vfsmnt, name); vfsmnt->mnt_sb = sb; vfsmnt->mnt_root = dget(sb->s_root); bdput(bdev); /* sb holds a reference */#ifdef CONFIG_ROOT_NFSattach_it:#endif root_nd.mnt = root_vfsmnt; root_nd.dentry = root_vfsmnt->mnt_sb->s_root; graft_tree(vfsmnt, &root_nd); set_fs_root(current->fs, vfsmnt, vfsmnt->mnt_root); set_fs_pwd(current->fs, vfsmnt, vfsmnt->mnt_root); mntput(vfsmnt);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -