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