static int proc_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, struct vfsmount *mnt) { int err; struct super_block *sb; struct pid_namespace *ns; struct proc_inode *ei; char *options; if (proc_mnt) { /* Seed the root directory with a pid so it doesn't need * to be special in base.c. I would do this earlier but * the only task alive when /proc is mounted the first time * is the init_task and it doesn't have any pids. */ ei = PROC_I(proc_mnt->mnt_sb->s_root->d_inode); if (!ei->pid) ei->pid = find_get_pid(1); } if (flags & MS_KERNMOUNT) { ns = (struct pid_namespace *)data; options = NULL; } else { ns = task_active_pid_ns(current); options = data; } sb = sget(fs_type, proc_test_super, proc_set_super, ns); if (IS_ERR(sb)) return PTR_ERR(sb); if (!sb->s_root) { sb->s_flags = flags; if (!proc_parse_options(options, ns)) { deactivate_locked_super(sb); return -EINVAL; } err = proc_fill_super(sb); if (err) { deactivate_locked_super(sb); return err; } ei = PROC_I(sb->s_root->d_inode); if (!ei->pid) { rcu_read_lock(); ei->pid = get_pid(find_pid_ns(1, ns)); rcu_read_unlock(); } sb->s_flags |= MS_ACTIVE; ns->proc_mnt = mnt; } simple_set_mnt(mnt, sb); return 0; }
/** * kernfs_mount_ns - kernfs mount helper * @fs_type: file_system_type of the fs being mounted * @flags: mount flags specified for the mount * @root: kernfs_root of the hierarchy being mounted * @new_sb_created: tell the caller if we allocated a new superblock * @ns: optional namespace tag of the mount * * This is to be called from each kernfs user's file_system_type->mount() * implementation, which should pass through the specified @fs_type and * @flags, and specify the hierarchy and namespace tag to mount via @root * and @ns, respectively. * * The return value can be passed to the vfs layer verbatim. */ struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags, struct kernfs_root *root, bool *new_sb_created, const void *ns) { struct super_block *sb; struct kernfs_super_info *info; int error; info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) return ERR_PTR(-ENOMEM); info->root = root; info->ns = ns; sb = sget(fs_type, kernfs_test_super, kernfs_set_super, flags, info); if (IS_ERR(sb) || sb->s_fs_info != info) kfree(info); if (IS_ERR(sb)) return ERR_CAST(sb); if (new_sb_created) *new_sb_created = !sb->s_root; if (!sb->s_root) { error = kernfs_fill_super(sb); if (error) { deactivate_locked_super(sb); return ERR_PTR(error); } sb->s_flags |= MS_ACTIVE; } return dget(sb->s_root); }
static struct dentry *sysfs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { struct sysfs_super_info *info; enum kobj_ns_type type; struct super_block *sb; int error; info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) return ERR_PTR(-ENOMEM); for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) info->ns[type] = kobj_ns_grab_current(type); sb = sget(fs_type, sysfs_test_super, sysfs_set_super, info); if (IS_ERR(sb) || sb->s_fs_info != info) free_sysfs_super_info(info); if (IS_ERR(sb)) return ERR_CAST(sb); if (!sb->s_root) { sb->s_flags = flags; error = sysfs_fill_super(sb, data, flags & MS_SILENT ? 1 : 0); if (error) { deactivate_locked_super(sb); return ERR_PTR(error); } sb->s_flags |= MS_ACTIVE; } return dget(sb->s_root); }
struct dentry * vnlayer_mount( struct file_system_type *fs_type, int flags, const char *dev_name, void *data ) { SUPER_T *sb; int err; #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0) sb = sget(fs_type, NULL, vnlayer_set_sb, flags, data); #else sb = sget(fs_type, NULL, vnlayer_set_sb, data); #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0) */ if (IS_ERR(sb)) { return (struct dentry *)(sb); } sb->s_flags = flags; if (sb->s_root == NULL) { err = vnlayer_fill_super(sb, data, 0); if (err != 0) { deactivate_locked_super(sb); return ERR_PTR(err); } sb->s_flags |= MS_ACTIVE; } /* return a dget dentry */ return dget(sb->s_root); }
void fc_drop_locked(struct fs_context *fc) { struct super_block *sb = fc->root->d_sb; dput(fc->root); fc->root = NULL; deactivate_locked_super(sb); }
static struct dentry *proc_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { int err; struct super_block *sb; struct pid_namespace *ns; struct proc_inode *ei; char *options; if (flags & MS_KERNMOUNT) { ns = (struct pid_namespace *)data; options = NULL; } else { ns = current->nsproxy->pid_ns; options = data; } sb = sget(fs_type, proc_test_super, proc_set_super, ns); if (IS_ERR(sb)) return ERR_CAST(sb); if (!proc_parse_options(options, ns)) { deactivate_locked_super(sb); return ERR_PTR(-EINVAL); } if (!sb->s_root) { sb->s_flags = flags; err = proc_fill_super(sb); if (err) { deactivate_locked_super(sb); return ERR_PTR(err); } sb->s_flags |= MS_ACTIVE; } ei = PROC_I(sb->s_root->d_inode); if (!ei->pid) { rcu_read_lock(); ei->pid = get_pid(find_pid_ns(1, ns)); rcu_read_unlock(); } return dget(sb->s_root); }
static struct dentry *proc_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { int err; struct super_block *sb; struct pid_namespace *ns; char *options; if (flags & MS_KERNMOUNT) { ns = (struct pid_namespace *)data; options = NULL; } else { ns = task_active_pid_ns(current); options = data; if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type)) return ERR_PTR(-EPERM); /* Does the mounter have privilege over the pid namespace? */ if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN)) return ERR_PTR(-EPERM); } sb = sget(fs_type, proc_test_super, proc_set_super, flags, ns); if (IS_ERR(sb)) return ERR_CAST(sb); if (!proc_parse_options(options, ns)) { deactivate_locked_super(sb); return ERR_PTR(-EINVAL); } if (!sb->s_root) { err = proc_fill_super(sb); if (err) { deactivate_locked_super(sb); return ERR_PTR(err); } sb->s_flags |= MS_ACTIVE; } return dget(sb->s_root); }
static struct dentry *plgfs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data_page) { struct super_block *sb; struct plgfs_mnt_cfg *cfg; int rv; cfg = plgfs_get_cfg(fs_type, flags, dev_name, data_page); if (IS_ERR(cfg)) return ERR_CAST(cfg); sb = sget(fs_type, plgfs_test_super, set_anon_super, flags, cfg); if (IS_ERR(sb)) { plgfs_put_cfg(cfg); return ERR_CAST(sb); } if (cfg->flags & PLGFS_OPT_DIFF_PLGS) { pr_err("pluginfs: \"%s\" already mounted with different set of " "plugins\n", dev_name); deactivate_locked_super(sb); plgfs_put_cfg(cfg); return ERR_PTR(-EINVAL); } if (sb->s_root) { plgfs_put_cfg(cfg); return dget(sb->s_root); } rv = plgfs_fill_super(sb, flags, cfg); if (rv) { deactivate_locked_super(sb); plgfs_put_cfg(cfg); return ERR_PTR(rv); } plgfs_put_cfg(cfg); return dget(sb->s_root); }
static struct dentry *proc_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { int err; struct super_block *sb; struct pid_namespace *ns; char *options; if (flags & MS_KERNMOUNT) { ns = (struct pid_namespace *)data; options = NULL; } else { ns = task_active_pid_ns(current); options = data; if (!current_user_ns()->may_mount_proc) return ERR_PTR(-EPERM); } sb = sget(fs_type, proc_test_super, proc_set_super, flags, ns); if (IS_ERR(sb)) return ERR_CAST(sb); if (!proc_parse_options(options, ns)) { deactivate_locked_super(sb); return ERR_PTR(-EINVAL); } if (!sb->s_root) { err = proc_fill_super(sb); if (err) { deactivate_locked_super(sb); return ERR_PTR(err); } sb->s_flags |= MS_ACTIVE; } return dget(sb->s_root); }
/* * Get an AFS superblock and root directory. */ static int afs_get_tree(struct fs_context *fc) { struct afs_fs_context *ctx = fc->fs_private; struct super_block *sb; struct afs_super_info *as; int ret; ret = afs_validate_fc(fc); if (ret) goto error; _enter(""); /* allocate a superblock info record */ ret = -ENOMEM; as = afs_alloc_sbi(fc); if (!as) goto error; fc->s_fs_info = as; /* allocate a deviceless superblock */ sb = sget_fc(fc, as->dyn_root ? afs_dynroot_test_super : afs_test_super, afs_set_super); if (IS_ERR(sb)) { ret = PTR_ERR(sb); goto error; } if (!sb->s_root) { /* initial superblock/root creation */ _debug("create"); ret = afs_fill_super(sb, ctx); if (ret < 0) goto error_sb; sb->s_flags |= SB_ACTIVE; } else { _debug("reuse"); ASSERTCMP(sb->s_flags, &, SB_ACTIVE); } fc->root = dget(sb->s_root); trace_afs_get_tree(as->cell, as->volume); _leave(" = 0 [%p]", sb); return 0; error_sb: deactivate_locked_super(sb); error: _leave(" = %d", ret); return ret; }
/* * get a superblock on an MTD-backed filesystem */ static int get_sb_mtd_aux(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, struct mtd_info *mtd, int (*fill_super)(struct super_block *, void *, int), struct vfsmount *mnt) { struct super_block *sb; int ret; sb = sget(fs_type, get_sb_mtd_compare, get_sb_mtd_set, mtd); if (IS_ERR(sb)) goto out_error; if (sb->s_root) goto already_mounted; /* fresh new superblock */ DEBUG(1, "MTDSB: New superblock for device %d (\"%s\")\n", mtd->index, mtd->name); sb->s_flags = flags; ret = fill_super(sb, data, flags & MS_SILENT ? 1 : 0); if (ret < 0) { deactivate_locked_super(sb); return ret; } /* go */ sb->s_flags |= MS_ACTIVE; simple_set_mnt(mnt, sb); return 0; /* new mountpoint for an already mounted superblock */ already_mounted: DEBUG(1, "MTDSB: Device %d (\"%s\") is already mounted\n", mtd->index, mtd->name); simple_set_mnt(mnt, sb); ret = 0; goto out_put; out_error: ret = PTR_ERR(sb); out_put: put_mtd_device(mtd); return ret; }
static struct dentry *anon_inodefs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { struct dentry *root; root = mount_pseudo(fs_type, "anon_inode:", NULL, &anon_inodefs_dentry_operations, ANON_INODE_FS_MAGIC); if (!IS_ERR(root)) { struct super_block *s = root->d_sb; anon_inode_inode = anon_inode_mkinode(s); if (IS_ERR(anon_inode_inode)) { dput(root); deactivate_locked_super(s); root = ERR_CAST(anon_inode_inode); } } return root; }
/* * devpts_mount() * * If the '-o newinstance' mount option was specified, mount a new * (private) instance of devpts. PTYs created in this instance are * independent of the PTYs in other devpts instances. * * If the '-o newinstance' option was not specified, mount/remount the * initial kernel mount of devpts. This type of mount gives the * legacy, single-instance semantics. * * The 'newinstance' option is needed to support multiple namespace * semantics in devpts while preserving backward compatibility of the * current 'single-namespace' semantics. i.e all mounts of devpts * without the 'newinstance' mount option should bind to the initial * kernel mount, like mount_single(). * * Mounts with 'newinstance' option create a new, private namespace. * * NOTE: * * For single-mount semantics, devpts cannot use mount_single(), * because mount_single()/sget() find and use the super-block from * the most recent mount of devpts. But that recent mount may be a * 'newinstance' mount and mount_single() would pick the newinstance * super-block instead of the initial super-block. */ static struct dentry *devpts_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { int error; struct pts_mount_opts opts; struct super_block *s; error = parse_mount_options(data, PARSE_MOUNT, &opts); if (error) return ERR_PTR(error); /* Require newinstance for all user namespace mounts to ensure * the mount options are not changed. */ if ((current_user_ns() != &init_user_ns) && !opts.newinstance) return ERR_PTR(-EINVAL); if (opts.newinstance) s = sget(fs_type, NULL, set_anon_super, flags, NULL); else s = sget(fs_type, compare_init_pts_sb, set_anon_super, flags, NULL); if (IS_ERR(s)) return ERR_CAST(s); if (!s->s_root) { error = devpts_fill_super(s, data, flags & MS_SILENT ? 1 : 0); if (error) goto out_undo_sget; s->s_flags |= MS_ACTIVE; } memcpy(&(DEVPTS_SB(s))->mount_opts, &opts, sizeof(opts)); error = mknod_ptmx(s); if (error) goto out_undo_sget; return dget(s->s_root); out_undo_sget: deactivate_locked_super(s); return ERR_PTR(error); }
/* * devpts_get_sb() * * If the '-o newinstance' mount option was specified, mount a new * (private) instance of devpts. PTYs created in this instance are * independent of the PTYs in other devpts instances. * * If the '-o newinstance' option was not specified, mount/remount the * initial kernel mount of devpts. This type of mount gives the * legacy, single-instance semantics. * * The 'newinstance' option is needed to support multiple namespace * semantics in devpts while preserving backward compatibility of the * current 'single-namespace' semantics. i.e all mounts of devpts * without the 'newinstance' mount option should bind to the initial * kernel mount, like get_sb_single(). * * Mounts with 'newinstance' option create a new, private namespace. * * NOTE: * * For single-mount semantics, devpts cannot use get_sb_single(), * because get_sb_single()/sget() find and use the super-block from * the most recent mount of devpts. But that recent mount may be a * 'newinstance' mount and get_sb_single() would pick the newinstance * super-block instead of the initial super-block. */ static int devpts_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, struct vfsmount *mnt) { int error; struct pts_mount_opts opts; struct super_block *s; error = parse_mount_options(data, PARSE_MOUNT, &opts); if (error) return error; if (opts.newinstance) s = sget(fs_type, NULL, set_anon_super, NULL); else s = sget(fs_type, compare_init_pts_sb, set_anon_super, NULL); if (IS_ERR(s)) return PTR_ERR(s); if (!s->s_root) { s->s_flags = flags; error = devpts_fill_super(s, data, flags & MS_SILENT ? 1 : 0); if (error) goto out_undo_sget; s->s_flags |= MS_ACTIVE; } simple_set_mnt(mnt, s); memcpy(&(DEVPTS_SB(s))->mount_opts, &opts, sizeof(opts)); error = mknod_ptmx(s); if (error) goto out_dput; return 0; out_dput: dput(s->s_root); /* undo dget() in simple_set_mnt() */ out_undo_sget: deactivate_locked_super(s); return error; }
/* * Based on mount_nodev() in fs/super.c (need to pass mount options). */ struct dentry *esdfs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *raw_data) { int error; struct super_block *s = sget(fs_type, NULL, set_anon_super, flags, NULL); if (IS_ERR(s)) return ERR_CAST(s); s->s_flags = flags; error = esdfs_read_super(s, dev_name, raw_data, flags & MS_SILENT ? 1 : 0); if (error) { deactivate_locked_super(s); return ERR_PTR(error); } s->s_flags |= MS_ACTIVE; return dget(s->s_root); }
/* A feature which supports mount_nodev() with options */ static struct dentry *mount_nodev_with_options(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, int (*fill_super)(struct super_block *, const char *, void *, int)) { int error; struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL); if (IS_ERR(s)) return ERR_CAST(s); s->s_flags = flags; error = fill_super(s, dev_name, data, flags & MS_SILENT ? 1 : 0); if (error) { deactivate_locked_super(s); return ERR_PTR(error); } s->s_flags |= MS_ACTIVE; return dget(s->s_root); }
static struct dentry *phuang_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { int err; struct super_block *sb; printk(KERN_DEBUG "%s", __func__); sb = sget(fs_type, phuang_test_super, phuang_set_super, data); if (IS_ERR(sb)) return ERR_CAST(sb); if (sb->s_root == NULL) { sb->s_flags = flags; err = phuang_fill_super(sb); if (err) { deactivate_locked_super(sb); return ERR_PTR(err); } sb->s_flags |= MS_ACTIVE; } return dget(sb->s_root); }
static int cifs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, struct vfsmount *mnt) { int rc; struct super_block *sb = sget(fs_type, NULL, set_anon_super, NULL); cFYI(1, "Devname: %s flags: %d ", dev_name, flags); if (IS_ERR(sb)) return PTR_ERR(sb); sb->s_flags = flags; rc = cifs_read_super(sb, data, dev_name, flags & MS_SILENT ? 1 : 0); if (rc) { deactivate_locked_super(sb); return rc; } sb->s_flags |= MS_ACTIVE; simple_set_mnt(mnt, sb); return 0; }
static struct dentry * cifs_do_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { int rc; struct super_block *sb; sb = sget(fs_type, NULL, set_anon_super, NULL); cFYI(1, "Devname: %s flags: %d ", dev_name, flags); if (IS_ERR(sb)) return ERR_CAST(sb); sb->s_flags = flags; rc = cifs_read_super(sb, data, dev_name, flags & MS_SILENT ? 1 : 0); if (rc) { deactivate_locked_super(sb); return ERR_PTR(rc); } sb->s_flags |= MS_ACTIVE; return dget(sb->s_root); }
static struct dentry * cifs_do_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { int rc; struct super_block *sb; struct cifs_sb_info *cifs_sb; struct smb_vol *volume_info; struct cifs_mnt_data mnt_data; struct dentry *root; cFYI(1, "Devname: %s flags: %d ", dev_name, flags); rc = cifs_setup_volume_info(&volume_info, (char *)data, dev_name); if (rc) return ERR_PTR(rc); cifs_sb = kzalloc(sizeof(struct cifs_sb_info), GFP_KERNEL); if (cifs_sb == NULL) { root = ERR_PTR(-ENOMEM); goto out; } cifs_setup_cifs_sb(volume_info, cifs_sb); mnt_data.vol = volume_info; mnt_data.cifs_sb = cifs_sb; mnt_data.flags = flags; sb = sget(fs_type, cifs_match_super, set_anon_super, &mnt_data); if (IS_ERR(sb)) { root = ERR_CAST(sb); goto out_cifs_sb; } if (sb->s_fs_info) { cFYI(1, "Use existing superblock"); goto out_shared; } /* * Copy mount params for use in submounts. Better to do * the copy here and deal with the error before cleanup gets * complicated post-mount. */ cifs_sb->mountdata = kstrndup(data, PAGE_SIZE, GFP_KERNEL); if (cifs_sb->mountdata == NULL) { root = ERR_PTR(-ENOMEM); goto out_super; } sb->s_flags = flags; /* BB should we make this contingent on mount parm? */ sb->s_flags |= MS_NODIRATIME | MS_NOATIME; sb->s_fs_info = cifs_sb; rc = cifs_read_super(sb, volume_info, dev_name, flags & MS_SILENT ? 1 : 0); if (rc) { root = ERR_PTR(rc); goto out_super; } sb->s_flags |= MS_ACTIVE; root = cifs_get_root(volume_info, sb); if (root == NULL) goto out_super; cFYI(1, "dentry root is: %p", root); goto out; out_shared: root = cifs_get_root(volume_info, sb); if (root) cFYI(1, "dentry root is: %p", root); goto out; out_super: kfree(cifs_sb->mountdata); deactivate_locked_super(sb); out_cifs_sb: unload_nls(cifs_sb->local_nls); kfree(cifs_sb); out: cifs_cleanup_volume_info(&volume_info); return root; }
static struct dentry * nilfs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { struct nilfs_super_data sd; struct super_block *s; fmode_t mode = FMODE_READ | FMODE_EXCL; struct dentry *root_dentry; int err, s_new = false; if (!(flags & MS_RDONLY)) mode |= FMODE_WRITE; sd.bdev = blkdev_get_by_path(dev_name, mode, fs_type); if (IS_ERR(sd.bdev)) return ERR_CAST(sd.bdev); sd.cno = 0; sd.flags = flags; if (nilfs_identify((char *)data, &sd)) { err = -EINVAL; goto failed; } /* * once the super is inserted into the list by sget, s_umount * will protect the lockfs code from trying to start a snapshot * while we are mounting */ mutex_lock(&sd.bdev->bd_fsfreeze_mutex); if (sd.bdev->bd_fsfreeze_count > 0) { mutex_unlock(&sd.bdev->bd_fsfreeze_mutex); err = -EBUSY; goto failed; } s = sget(fs_type, nilfs_test_bdev_super, nilfs_set_bdev_super, sd.bdev); mutex_unlock(&sd.bdev->bd_fsfreeze_mutex); if (IS_ERR(s)) { err = PTR_ERR(s); goto failed; } if (!s->s_root) { char b[BDEVNAME_SIZE]; s_new = true; /* New superblock instance created */ s->s_flags = flags; s->s_mode = mode; strlcpy(s->s_id, bdevname(sd.bdev, b), sizeof(s->s_id)); sb_set_blocksize(s, block_size(sd.bdev)); err = nilfs_fill_super(s, data, flags & MS_SILENT ? 1 : 0); if (err) goto failed_super; s->s_flags |= MS_ACTIVE; } else if (!sd.cno) { int busy = false; if (nilfs_tree_was_touched(s->s_root)) { busy = nilfs_try_to_shrink_tree(s->s_root); if (busy && (flags ^ s->s_flags) & MS_RDONLY) { printk(KERN_ERR "NILFS: the device already " "has a %s mount.\n", (s->s_flags & MS_RDONLY) ? "read-only" : "read/write"); err = -EBUSY; goto failed_super; } } if (!busy) { /* * Try remount to setup mount states if the current * tree is not mounted and only snapshots use this sb. */ err = nilfs_remount(s, &flags, data); if (err) goto failed_super; } } if (sd.cno) { err = nilfs_attach_snapshot(s, sd.cno, &root_dentry); if (err) goto failed_super; } else { root_dentry = dget(s->s_root); } if (!s_new) blkdev_put(sd.bdev, mode); return root_dentry; failed_super: deactivate_locked_super(s); failed: if (!s_new) blkdev_put(sd.bdev, mode); return ERR_PTR(err); }
static struct dentry *lofs_mount( struct file_system_type *fs_type, int flags, const char *dev_name, void *raw_data) { static const struct qstr slash = { .name = "/", .len = 1 }; struct super_block *s; struct lofs_sb_info *sbi; struct lofs_dentry_info *root_info; struct inode *inode; const char *err = "Getting sb failed"; struct path path; int rc; sbi = kmem_cache_zalloc(lofs_sb_info_cache, GFP_KERNEL); if (!sbi) { rc = -ENOMEM; goto out; } s = sget(fs_type, NULL, set_anon_super, NULL); if (IS_ERR(s)) { rc = PTR_ERR(s); goto out; } s->s_flags = flags; #if defined(HAVE_BACKING_DEV) rc = bdi_setup_and_register(&sbi->bdi, "lofs", BDI_CAP_MAP_COPY); if (rc) goto out1; s->s_bdi = &sbi->bdi; #endif lofs_set_superblock_private(s, sbi); /* ->kill_sb() will take care of sbi after that point */ sbi = NULL; s->s_op = &lofs_sops; s->s_d_op = &lofs_dops; err = "Reading sb failed"; rc = kern_path(slash.name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path); if (rc) { lofs_printk(KERN_WARNING, "kern_path() failed\n"); goto out1; } lofs_set_superblock_lower(s, path.dentry->d_sb); s->s_maxbytes = path.dentry->d_sb->s_maxbytes; s->s_blocksize = path.dentry->d_sb->s_blocksize; s->s_magic = 0x10f5; inode = lofs_get_inode(path.dentry->d_inode, s); rc = PTR_ERR(inode); if (IS_ERR(inode)) { goto out_free; } #ifdef HAVE_D_MAKE_ROOT s->s_root = d_make_root(inode); #else s->s_root = d_alloc_root(inode); if (!s->s_root) { iput(inode); } #endif if (!s->s_root) { rc = -ENOMEM; goto out_free; } rc = -ENOMEM; root_info = kmem_cache_zalloc(lofs_dentry_info_cache, GFP_KERNEL); if (!root_info) goto out_free; /* ->kill_sb() will take care of root_info */ lofs_set_dentry_private(s->s_root, root_info); lofs_set_dentry_lower(s->s_root, path.dentry); lofs_set_dentry_lower_mnt(s->s_root, path.mnt); s->s_flags |= MS_ACTIVE; return dget(s->s_root); out_free: path_put(&path); out1: deactivate_locked_super(s); out: if (sbi) { kmem_cache_free(lofs_sb_info_cache, sbi); } printk(KERN_ERR "%s; rc = [%d]\n", err, rc); return ERR_PTR(rc); } /** * lofs_kill_block_super * @sb: The lofs super block * * Used to bring the superblock down and free the private data. */ static void lofs_kill_block_super(struct super_block *sb) { struct lofs_sb_info *sb_info = lofs_superblock_to_private(sb); kill_anon_super(sb); #if defined(HAVE_BACKING_DEV) if (sb_info) { bdi_destroy(&sb_info->bdi); } #endif kmem_cache_free(lofs_sb_info_cache, sb_info); } #else /* !HAVE_MOUNT_IN_FS_TYPE */ /** * lofs_fill_super * @sb: The lofs super block * @raw_data: The options passed to mount * @silent: Not used but required by function prototype * * Sets up what we can of the sb, rest is done in lofs_read_super * * Returns zero on success; non-zero otherwise */ static int lofs_fill_super(struct super_block *sb, void *raw_data, int silent) { int rc = 0; struct inode *inode; struct nameidata nd; /* Released in lofs_put_super() */ struct lofs_sb_info *sbi; sbi = kmem_cache_zalloc(lofs_sb_info_cache, GFP_KERNEL); if (!sbi) { lofs_printk(KERN_WARNING, "Out of memory\n"); return -ENOMEM; } lofs_set_superblock_private(sb, sbi); sb->s_op = (struct super_operations *) &lofs_sops; /* Released through deactivate_super(sb) from get_sb_nodev */ #if defined(HAVE_S_D_OP) sb->s_d_op = &lofs_dops; #endif rc = path_lookup("/", LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &nd); if (rc) { lofs_printk(KERN_WARNING, "path_lookup() failed\n"); return rc; } lofs_set_superblock_lower(sb, NAMEIDATA_TO_DENTRY(&nd)->d_sb); sb->s_maxbytes = NAMEIDATA_TO_DENTRY(&nd)->d_sb->s_maxbytes; sb->s_blocksize = NAMEIDATA_TO_DENTRY(&nd)->d_sb->s_blocksize; #ifdef HAVE_ADDRESS_SPACE_OPS_EXT sb->s_flags |= MS_HAS_NEW_AOPS; #endif /* Get the root inode and dentry. We have to bootstrap this one, * since it doesn't get created via the regular lookup mechanism. */ inode = lofs_get_inode(NAMEIDATA_TO_DENTRY(&nd)->d_inode, sb); if (IS_ERR(inode)) { dput(NAMEIDATA_TO_DENTRY(&nd)); mntput(NAMEIDATA_TO_VFSMNT(&nd)); return PTR_ERR(inode); } sb->s_root = d_alloc_root(inode); if (!sb->s_root) { iput(inode); dput(NAMEIDATA_TO_DENTRY(&nd)); mntput(NAMEIDATA_TO_VFSMNT(&nd)); return -ENOMEM; } lofs_set_dentry_private(sb->s_root, kmem_cache_zalloc(lofs_dentry_info_cache, GFP_KERNEL)); lofs_set_dentry_lower(sb->s_root, NAMEIDATA_TO_DENTRY(&nd)); lofs_set_dentry_lower_mnt(sb->s_root, NAMEIDATA_TO_VFSMNT(&nd)); #if !defined(HAVE_S_D_OP) sb->s_root->d_op = (struct dentry_operations *) &lofs_dops; #endif return 0; }
static int v9fs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, struct vfsmount *mnt) { struct super_block *sb = NULL; struct inode *inode = NULL; struct dentry *root = NULL; struct v9fs_session_info *v9ses = NULL; int mode = S_IRWXUGO | S_ISVTX; struct p9_fid *fid; int retval = 0; P9_DPRINTK(P9_DEBUG_VFS, " \n"); v9ses = kzalloc(sizeof(struct v9fs_session_info), GFP_KERNEL); if (!v9ses) return -ENOMEM; fid = v9fs_session_init(v9ses, dev_name, data); if (IS_ERR(fid)) { retval = PTR_ERR(fid); /* * we need to call session_close to tear down some * of the data structure setup by session_init */ goto close_session; } sb = sget(fs_type, NULL, v9fs_set_super, v9ses); if (IS_ERR(sb)) { retval = PTR_ERR(sb); goto clunk_fid; } v9fs_fill_super(sb, v9ses, flags, data); inode = v9fs_get_inode(sb, S_IFDIR | mode); if (IS_ERR(inode)) { retval = PTR_ERR(inode); goto release_sb; } root = d_alloc_root(inode); if (!root) { iput(inode); retval = -ENOMEM; goto release_sb; } sb->s_root = root; if (v9fs_proto_dotl(v9ses)) { struct p9_stat_dotl *st = NULL; st = p9_client_getattr_dotl(fid, P9_STATS_BASIC); if (IS_ERR(st)) { retval = PTR_ERR(st); goto release_sb; } v9fs_stat2inode_dotl(st, root->d_inode); kfree(st); } else { struct p9_wstat *st = NULL; st = p9_client_stat(fid); if (IS_ERR(st)) { retval = PTR_ERR(st); goto release_sb; } root->d_inode->i_ino = v9fs_qid2ino(&st->qid); v9fs_stat2inode(st, root->d_inode, sb); p9stat_free(st); kfree(st); } retval = v9fs_get_acl(inode, fid); if (retval) goto release_sb; v9fs_fid_add(root, fid); P9_DPRINTK(P9_DEBUG_VFS, " simple set mount, return 0\n"); simple_set_mnt(mnt, sb); return 0; clunk_fid: p9_client_clunk(fid); close_session: v9fs_session_close(v9ses); kfree(v9ses); return retval; release_sb: /* * we will do the session_close and root dentry release * in the below call. But we need to clunk fid, because we haven't * attached the fid to dentry so it won't get clunked * automatically. */ p9_client_clunk(fid); deactivate_locked_super(sb); return retval; }
static struct dentry * cifs_do_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { int rc; struct super_block *sb; struct cifs_sb_info *cifs_sb; struct smb_vol *volume_info; struct cifs_mnt_data mnt_data; struct dentry *root; cifs_dbg(FYI, "Devname: %s flags: %d\n", dev_name, flags); volume_info = cifs_get_volume_info((char *)data, dev_name); if (IS_ERR(volume_info)) return ERR_CAST(volume_info); cifs_sb = kzalloc(sizeof(struct cifs_sb_info), GFP_KERNEL); if (cifs_sb == NULL) { root = ERR_PTR(-ENOMEM); goto out_nls; } cifs_sb->mountdata = kstrndup(data, PAGE_SIZE, GFP_KERNEL); if (cifs_sb->mountdata == NULL) { root = ERR_PTR(-ENOMEM); goto out_cifs_sb; } cifs_setup_cifs_sb(volume_info, cifs_sb); rc = cifs_mount(cifs_sb, volume_info); if (rc) { if (!(flags & MS_SILENT)) cifs_dbg(VFS, "cifs_mount failed w/return code = %d\n", rc); root = ERR_PTR(rc); goto out_mountdata; } mnt_data.vol = volume_info; mnt_data.cifs_sb = cifs_sb; mnt_data.flags = flags; /* BB should we make this contingent on mount parm? */ flags |= MS_NODIRATIME | MS_NOATIME; sb = sget(fs_type, cifs_match_super, cifs_set_super, flags, &mnt_data); if (IS_ERR(sb)) { root = ERR_CAST(sb); cifs_umount(cifs_sb); goto out; } if (sb->s_root) { cifs_dbg(FYI, "Use existing superblock\n"); cifs_umount(cifs_sb); } else { rc = cifs_read_super(sb); if (rc) { root = ERR_PTR(rc); goto out_super; } sb->s_flags |= MS_ACTIVE; } root = cifs_get_root(volume_info, sb); if (IS_ERR(root)) goto out_super; cifs_dbg(FYI, "dentry root is: %p\n", root); goto out; out_super: deactivate_locked_super(sb); out: cifs_cleanup_volume_info(volume_info); return root; out_mountdata: kfree(cifs_sb->mountdata); out_cifs_sb: kfree(cifs_sb); out_nls: unload_nls(volume_info->local_nls); goto out; }
static int nilfs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, struct vfsmount *mnt) { struct nilfs_super_data sd; struct super_block *s; fmode_t mode = FMODE_READ; struct the_nilfs *nilfs; int err, need_to_close = 1; if (!(flags & MS_RDONLY)) mode |= FMODE_WRITE; sd.bdev = open_bdev_exclusive(dev_name, mode, fs_type); if (IS_ERR(sd.bdev)) return PTR_ERR(sd.bdev); /* * To get mount instance using sget() vfs-routine, NILFS needs * much more information than normal filesystems to identify mount * instance. For snapshot mounts, not only a mount type (ro-mount * or rw-mount) but also a checkpoint number is required. */ sd.cno = 0; sd.flags = flags; if (nilfs_identify((char *)data, &sd)) { err = -EINVAL; goto failed; } nilfs = find_or_create_nilfs(sd.bdev); if (!nilfs) { err = -ENOMEM; goto failed; } mutex_lock(&nilfs->ns_mount_mutex); if (!sd.cno) { /* * Check if an exclusive mount exists or not. * Snapshot mounts coexist with a current mount * (i.e. rw-mount or ro-mount), whereas rw-mount and * ro-mount are mutually exclusive. */ down_read(&nilfs->ns_super_sem); if (nilfs->ns_current && ((nilfs->ns_current->s_super->s_flags ^ flags) & MS_RDONLY)) { up_read(&nilfs->ns_super_sem); err = -EBUSY; goto failed_unlock; } up_read(&nilfs->ns_super_sem); } /* * Find existing nilfs_sb_info struct */ sd.sbi = nilfs_find_sbinfo(nilfs, !(flags & MS_RDONLY), sd.cno); /* * Get super block instance holding the nilfs_sb_info struct. * A new instance is allocated if no existing mount is present or * existing instance has been unmounted. */ s = sget(fs_type, nilfs_test_bdev_super, nilfs_set_bdev_super, &sd); if (sd.sbi) nilfs_put_sbinfo(sd.sbi); if (IS_ERR(s)) { err = PTR_ERR(s); goto failed_unlock; } if (!s->s_root) { char b[BDEVNAME_SIZE]; /* New superblock instance created */ s->s_flags = flags; s->s_mode = mode; strlcpy(s->s_id, bdevname(sd.bdev, b), sizeof(s->s_id)); sb_set_blocksize(s, block_size(sd.bdev)); err = nilfs_fill_super(s, data, flags & MS_SILENT ? 1 : 0, nilfs); if (err) goto cancel_new; s->s_flags |= MS_ACTIVE; need_to_close = 0; } mutex_unlock(&nilfs->ns_mount_mutex); put_nilfs(nilfs); if (need_to_close) close_bdev_exclusive(sd.bdev, mode); simple_set_mnt(mnt, s); return 0; failed_unlock: mutex_unlock(&nilfs->ns_mount_mutex); put_nilfs(nilfs); failed: close_bdev_exclusive(sd.bdev, mode); return err; cancel_new: /* Abandoning the newly allocated superblock */ mutex_unlock(&nilfs->ns_mount_mutex); put_nilfs(nilfs); deactivate_locked_super(s); /* * deactivate_locked_super() invokes close_bdev_exclusive(). * We must finish all post-cleaning before this call; * put_nilfs() needs the block device. */ return err; }
struct dentry *orangefs_mount(struct file_system_type *fst, int flags, const char *devname, void *data) { int ret = -EINVAL; struct super_block *sb = ERR_PTR(-EINVAL); struct orangefs_kernel_op_s *new_op; struct dentry *d = ERR_PTR(-EINVAL); gossip_debug(GOSSIP_SUPER_DEBUG, "orangefs_mount: called with devname %s\n", devname); if (!devname) { gossip_err("ERROR: device name not specified.\n"); return ERR_PTR(-EINVAL); } new_op = op_alloc(ORANGEFS_VFS_OP_FS_MOUNT); if (!new_op) return ERR_PTR(-ENOMEM); strncpy(new_op->upcall.req.fs_mount.orangefs_config_server, devname, ORANGEFS_MAX_SERVER_ADDR_LEN - 1); gossip_debug(GOSSIP_SUPER_DEBUG, "Attempting ORANGEFS Mount via host %s\n", new_op->upcall.req.fs_mount.orangefs_config_server); ret = service_operation(new_op, "orangefs_mount", 0); gossip_debug(GOSSIP_SUPER_DEBUG, "orangefs_mount: mount got return value of %d\n", ret); if (ret) goto free_op; if (new_op->downcall.resp.fs_mount.fs_id == ORANGEFS_FS_ID_NULL) { gossip_err("ERROR: Retrieved null fs_id\n"); ret = -EINVAL; goto free_op; } sb = sget(fst, NULL, set_anon_super, flags, NULL); if (IS_ERR(sb)) { d = ERR_CAST(sb); orangefs_unmount(new_op->downcall.resp.fs_mount.id, new_op->downcall.resp.fs_mount.fs_id, devname); goto free_op; } ret = orangefs_fill_sb(sb, &new_op->downcall.resp.fs_mount, data, flags & SB_SILENT ? 1 : 0); if (ret) { d = ERR_PTR(ret); goto free_sb_and_op; } /* * on successful mount, store the devname and data * used */ strncpy(ORANGEFS_SB(sb)->devname, devname, ORANGEFS_MAX_SERVER_ADDR_LEN - 1); /* mount_pending must be cleared */ ORANGEFS_SB(sb)->mount_pending = 0; /* * finally, add this sb to our list of known orangefs * sb's */ gossip_debug(GOSSIP_SUPER_DEBUG, "Adding SB %p to orangefs superblocks\n", ORANGEFS_SB(sb)); spin_lock(&orangefs_superblocks_lock); list_add_tail(&ORANGEFS_SB(sb)->list, &orangefs_superblocks); spin_unlock(&orangefs_superblocks_lock); op_release(new_op); /* Must be removed from the list now. */ ORANGEFS_SB(sb)->no_list = 0; if (orangefs_userspace_version >= 20906) { new_op = op_alloc(ORANGEFS_VFS_OP_FEATURES); if (!new_op) return ERR_PTR(-ENOMEM); new_op->upcall.req.features.features = 0; ret = service_operation(new_op, "orangefs_features", 0); orangefs_features = new_op->downcall.resp.features.features; op_release(new_op); } else { orangefs_features = 0; } return dget(sb->s_root); free_sb_and_op: /* Will call orangefs_kill_sb with sb not in list. */ ORANGEFS_SB(sb)->no_list = 1; /* ORANGEFS_VFS_OP_FS_UMOUNT is done by orangefs_kill_sb. */ deactivate_locked_super(sb); free_op: gossip_err("orangefs_mount: mount request failed with %d\n", ret); if (ret == -EINVAL) { gossip_err("Ensure that all orangefs-servers have the same FS configuration files\n"); gossip_err("Look at pvfs2-client-core log file (typically /tmp/pvfs2-client.log) for more details\n"); } op_release(new_op); return d; }
static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { struct super_block *sb = NULL; struct inode *inode = NULL; struct dentry *root = NULL; struct v9fs_session_info *v9ses = NULL; umode_t mode = S_IRWXUGO | S_ISVTX; struct p9_fid *fid; int retval = 0; p9_debug(P9_DEBUG_VFS, "\n"); v9ses = kzalloc(sizeof(struct v9fs_session_info), GFP_KERNEL); if (!v9ses) return ERR_PTR(-ENOMEM); fid = v9fs_session_init(v9ses, dev_name, data); if (IS_ERR(fid)) { retval = PTR_ERR(fid); goto free_session; } sb = sget(fs_type, NULL, v9fs_set_super, flags, v9ses); if (IS_ERR(sb)) { retval = PTR_ERR(sb); goto clunk_fid; } v9fs_fill_super(sb, v9ses, flags, data); if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) sb->s_d_op = &v9fs_cached_dentry_operations; else sb->s_d_op = &v9fs_dentry_operations; inode = v9fs_get_inode(sb, S_IFDIR | mode, 0); if (IS_ERR(inode)) { retval = PTR_ERR(inode); goto release_sb; } root = d_make_root(inode); if (!root) { retval = -ENOMEM; goto release_sb; } sb->s_root = root; if (v9fs_proto_dotl(v9ses)) { struct p9_stat_dotl *st = NULL; st = p9_client_getattr_dotl(fid, P9_STATS_BASIC); if (IS_ERR(st)) { retval = PTR_ERR(st); goto release_sb; } d_inode(root)->i_ino = v9fs_qid2ino(&st->qid); v9fs_stat2inode_dotl(st, d_inode(root)); kfree(st); } else { struct p9_wstat *st = NULL; st = p9_client_stat(fid); if (IS_ERR(st)) { retval = PTR_ERR(st); goto release_sb; } d_inode(root)->i_ino = v9fs_qid2ino(&st->qid); v9fs_stat2inode(st, d_inode(root), sb); p9stat_free(st); kfree(st); } retval = v9fs_get_acl(inode, fid); if (retval) goto release_sb; v9fs_fid_add(root, fid); p9_debug(P9_DEBUG_VFS, " simple set mount, return 0\n"); return dget(sb->s_root); clunk_fid: p9_client_clunk(fid); v9fs_session_close(v9ses); free_session: kfree(v9ses); return ERR_PTR(retval); release_sb: /* * we will do the session_close and root dentry release * in the below call. But we need to clunk fid, because we haven't * attached the fid to dentry so it won't get clunked * automatically. */ p9_client_clunk(fid); deactivate_locked_super(sb); return ERR_PTR(retval); }