static struct vfsmount *cifs_dfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry, const struct dfs_info3_param *ref) { struct cifs_sb_info *cifs_sb; struct vfsmount *mnt; char *mountdata; char *devname = NULL; char *fullpath; cifs_sb = CIFS_SB(dentry->d_inode->i_sb); /* * this function gives us a path with a double backslash prefix. We * require a single backslash for DFS. */ fullpath = build_path_from_dentry(dentry); if (!fullpath) return ERR_PTR(-ENOMEM); mountdata = cifs_compose_mount_options(cifs_sb->mountdata, fullpath + 1, ref, &devname); kfree(fullpath); if (IS_ERR(mountdata)) return (struct vfsmount *)mountdata; mnt = vfs_kern_mount(&cifs_fs_type, 0, devname, mountdata); kfree(mountdata); kfree(devname); return mnt; }
/* * Clone a mountpoint of the appropriate type */ static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server, const char *devname, struct nfs_clone_mount *mountdata) { #ifdef CONFIG_NFS_V4 struct vfsmount *mnt = ERR_PTR(-EINVAL); switch (server->nfs_client->rpc_ops->version) { case 2: case 3: mnt = vfs_kern_mount(&nfs_xdev_fs_type, 0, devname, mountdata); break; case 4: mnt = vfs_kern_mount(&nfs4_xdev_fs_type, 0, devname, mountdata); } return mnt; #else return vfs_kern_mount(&nfs_xdev_fs_type, 0, devname, mountdata); #endif }
static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, char *page, char *page2, const struct nfs4_fs_location *location) { const size_t addr_bufsize = sizeof(struct sockaddr_storage); struct vfsmount *mnt = ERR_PTR(-ENOENT); char *mnt_path; unsigned int maxbuflen; unsigned int s; mnt_path = nfs4_pathname_string(&location->rootpath, page2, PAGE_SIZE); if (IS_ERR(mnt_path)) return ERR_CAST(mnt_path); mountdata->mnt_path = mnt_path; maxbuflen = mnt_path - 1 - page2; mountdata->addr = kmalloc(addr_bufsize, GFP_KERNEL); if (mountdata->addr == NULL) return ERR_PTR(-ENOMEM); for (s = 0; s < location->nservers; s++) { const struct nfs4_string *buf = &location->servers[s]; if (buf->len <= 0 || buf->len >= maxbuflen) continue; if (memchr(buf->data, IPV6_SCOPE_DELIMITER, buf->len)) continue; mountdata->addrlen = nfs_parse_server_name(buf->data, buf->len, mountdata->addr, addr_bufsize, NFS_SB(mountdata->sb)); if (mountdata->addrlen == 0) continue; rpc_set_port(mountdata->addr, NFS_PORT); memcpy(page2, buf->data, buf->len); page2[buf->len] = '\0'; mountdata->hostname = page2; snprintf(page, PAGE_SIZE, "%s:%s", mountdata->hostname, mountdata->mnt_path); mnt = vfs_kern_mount(&nfs4_referral_fs_type, 0, page, mountdata); if (!IS_ERR(mnt)) break; } kfree(mountdata->addr); return mnt; }
/* mount our hidden southbound filesystem */ int ftfs_private_mount(const char *dev_name, const char *fs_type, void *data) { int err; struct vfsmount *vfs_mount; struct file_system_type *type; BUG_ON(ftfs_vfs); if (!dev_name || !*dev_name) { err = -EINVAL; goto err_out; } if (!fs_type || !*fs_type) { err = -EINVAL; goto err_out; } type = get_fs_type(fs_type); vfs_mount = vfs_kern_mount(type, FTFS_MS_FLAGS, dev_name, data); if (!IS_ERR(vfs_mount) && (type->fs_flags & FS_HAS_SUBTYPE) && !vfs_mount->mnt_sb->s_subtype) //mnt = ftfs_fs_set_subtype(mnt, fstype); BUG(); /* this causes problems during unmount. only for internal mounts */ //real_mount(vfs_mount)->mnt_ns = ERR_PTR(-EINVAL); ftfs_put_filesystem(type); if (IS_ERR(vfs_mount)) { err = PTR_ERR(vfs_mount); goto err_out; } mutex_lock(&ftfs_southbound_lock); ftfs_vfs = mntget(vfs_mount); mutex_unlock(&ftfs_southbound_lock); pr_devel("%s mnt_ns=%p\n", __func__, real_mount(vfs_mount)->mnt_ns); return 0; err_out: mutex_lock(&ftfs_southbound_lock); ftfs_vfs = NULL; mutex_unlock(&ftfs_southbound_lock); return err; }
/** * cifs_dfs_do_refmount - mounts specified path using provided refferal * @cifs_sb: parent/root superblock * @fullpath: full path in UNC format * @ref: server's referral */ static struct vfsmount *cifs_dfs_do_refmount(struct cifs_sb_info *cifs_sb, const char *fullpath, const struct dfs_info3_param *ref) { struct vfsmount *mnt; char *mountdata; char *devname = NULL; /* strip first '\' from fullpath */ mountdata = cifs_compose_mount_options(cifs_sb->mountdata, fullpath + 1, ref, &devname); if (IS_ERR(mountdata)) return (struct vfsmount *)mountdata; mnt = vfs_kern_mount(&cifs_fs_type, 0, devname, mountdata); kfree(mountdata); kfree(devname); return mnt; }
static struct vfsmount *nfs_do_root_mount(struct file_system_type *fs_type, int flags, void *data, const char *hostname) { struct vfsmount *root_mnt; char *root_devname; size_t len; len = strlen(hostname) + 5; root_devname = kmalloc(len, GFP_KERNEL); if (root_devname == NULL) return ERR_PTR(-ENOMEM); /* Does hostname needs to be enclosed in brackets? */ if (strchr(hostname, ':')) snprintf(root_devname, len, "[%s]:/", hostname); else snprintf(root_devname, len, "%s:/", hostname); root_mnt = vfs_kern_mount(fs_type, flags, root_devname, data); kfree(root_devname); return root_mnt; }
static int __init myfs_init(void) { int retval; retval = register_filesystem(&my_fs_type); if (!retval) { myfs_mount = vfs_kern_mount(&my_fs_type,MS_KERNMOUNT,(&my_fs_type)->name,NULL); if (IS_ERR(myfs_mount)) { printk(KERN_ERR "myfs: could not mount!\n"); retval= PTR_ERR(myfs_mount); myfs_mount = NULL; unregister_filesystem(&my_fs_type); return retval; } } return 0; }
static struct vfsmount *plgfs_mount_hidden_known(int flags, const char *dev_name, char *fstype, void *data) { struct file_system_type *type; struct vfsmount *mnt; type = get_fs_type(fstype); if (!type) return ERR_PTR(-ENODEV); mnt = vfs_kern_mount(type, flags | MS_KERNMOUNT, dev_name, data); module_put(type->owner); if (!IS_ERR(mnt)) return mnt; return ERR_PTR(-ENODEV); }
static struct vfsmount *cifs_dfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry, const struct dfs_info3_param *ref) { struct cifs_sb_info *cifs_sb; struct vfsmount *mnt; char *mountdata; char *devname = NULL; cifs_sb = CIFS_SB(dentry->d_inode->i_sb); mountdata = compose_mount_options(cifs_sb->mountdata, dentry, ref, &devname); if (IS_ERR(mountdata)) return (struct vfsmount *)mountdata; mnt = vfs_kern_mount(&cifs_fs_type, 0, devname, mountdata); kfree(mountdata); kfree(devname); return mnt; }
static struct vfsmount *plgfs_mount_hidden_unknown(int flags, const char *dev_name, void *data) { struct file_system_type *type; struct vfsmount *mnt; const char **name; for (name = plgfs_supported_fs_names; *name; name++) { type = get_fs_type(*name); if (!type) continue; mnt = vfs_kern_mount(type, flags | MS_KERNMOUNT, dev_name, data); module_put(type->owner); if (!IS_ERR(mnt)) return mnt; } return ERR_PTR(-ENODEV); }
/* * Clone a mountpoint of the appropriate type */ static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server, const char *devname, struct nfs_clone_mount *mountdata) { return vfs_kern_mount(&nfs_xdev_fs_type, 0, devname, mountdata); }
/** * nfs_follow_referral - set up mountpoint when hitting a referral on moved error * @mnt_parent - mountpoint of parent directory * @dentry - parent directory * @locations - array of NFSv4 server location information * */ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, const struct dentry *dentry, const struct nfs4_fs_locations *locations) { struct vfsmount *mnt = ERR_PTR(-ENOENT); struct nfs_clone_mount mountdata = { .sb = mnt_parent->mnt_sb, .dentry = dentry, .authflavor = NFS_SB(mnt_parent->mnt_sb)->client->cl_auth->au_flavor, }; char *page = NULL, *page2 = NULL; unsigned int s; int loc, error; if (locations == NULL || locations->nlocations <= 0) goto out; dprintk("%s: referral at %s/%s\n", __func__, dentry->d_parent->d_name.name, dentry->d_name.name); page = (char *) __get_free_page(GFP_USER); if (!page) goto out; page2 = (char *) __get_free_page(GFP_USER); if (!page2) goto out; /* Ensure fs path is a prefix of current dentry path */ error = nfs4_validate_fspath(mnt_parent, dentry, locations, page, page2); if (error < 0) { mnt = ERR_PTR(error); goto out; } loc = 0; while (loc < locations->nlocations && IS_ERR(mnt)) { const struct nfs4_fs_location *location = &locations->locations[loc]; char *mnt_path; if (location == NULL || location->nservers <= 0 || location->rootpath.ncomponents == 0) { loc++; continue; } mnt_path = nfs4_pathname_string(&location->rootpath, page2, PAGE_SIZE); if (IS_ERR(mnt_path)) { loc++; continue; } mountdata.mnt_path = mnt_path; s = 0; while (s < location->nservers) { struct sockaddr_in addr = { .sin_family = AF_INET, .sin_port = htons(NFS_PORT), }; if (location->servers[s].len <= 0 || valid_ipaddr4(location->servers[s].data) < 0) { s++; continue; } mountdata.hostname = location->servers[s].data; addr.sin_addr.s_addr = in_aton(mountdata.hostname), mountdata.addr = (struct sockaddr *)&addr; mountdata.addrlen = sizeof(addr); snprintf(page, PAGE_SIZE, "%s:%s", mountdata.hostname, mountdata.mnt_path); mnt = vfs_kern_mount(&nfs4_referral_fs_type, 0, page, &mountdata); if (!IS_ERR(mnt)) { break; } s++; } loc++; } out: free_page((unsigned long) page); free_page((unsigned long) page2); dprintk("%s: done\n", __func__); return mnt; } /* * nfs_do_refmount - handle crossing a referral on server * @dentry - dentry of referral * @nd - nameidata info * */ struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry) { struct vfsmount *mnt = ERR_PTR(-ENOMEM); struct dentry *parent; struct nfs4_fs_locations *fs_locations = NULL; struct page *page; int err; /* BUG_ON(IS_ROOT(dentry)); */ dprintk("%s: enter\n", __func__); page = alloc_page(GFP_KERNEL); if (page == NULL) goto out; fs_locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL); if (fs_locations == NULL) goto out_free; /* Get locations */ mnt = ERR_PTR(-ENOENT); parent = dget_parent(dentry); dprintk("%s: getting locations for %s/%s\n", __func__, parent->d_name.name, dentry->d_name.name); err = nfs4_proc_fs_locations(parent->d_inode, &dentry->d_name, fs_locations, page); dput(parent); if (err != 0 || fs_locations->nlocations <= 0 || fs_locations->fs_path.ncomponents <= 0) goto out_free; mnt = nfs_follow_referral(mnt_parent, dentry, fs_locations); out_free: __free_page(page); kfree(fs_locations); out: dprintk("%s: done\n", __func__); return mnt; }
/* * create a vfsmount to be automounted */ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt) { struct afs_super_info *super; struct vfsmount *mnt; struct page *page = NULL; size_t size; char *buf, *devname = NULL, *options = NULL; int ret; kenter("{%s}", mntpt->d_name.name); BUG_ON(!mntpt->d_inode); ret = -EINVAL; size = mntpt->d_inode->i_size; if (size > PAGE_SIZE - 1) goto error; ret = -ENOMEM; devname = (char *) get_zeroed_page(GFP_KERNEL); if (!devname) goto error; options = (char *) get_zeroed_page(GFP_KERNEL); if (!options) goto error; /* read the contents of the AFS special symlink */ page = read_mapping_page(mntpt->d_inode->i_mapping, 0, NULL); if (IS_ERR(page)) { ret = PTR_ERR(page); goto error; } ret = -EIO; wait_on_page_locked(page); if (!PageUptodate(page) || PageError(page)) goto error; buf = kmap(page); memcpy(devname, buf, size); kunmap(page); page_cache_release(page); page = NULL; /* work out what options we want */ super = AFS_FS_S(mntpt->d_sb); memcpy(options, "cell=", 5); strcpy(options + 5, super->volume->cell->name); if (super->volume->type == AFSVL_RWVOL) strcat(options, ",rwpath"); /* try and do the mount */ kdebug("--- attempting mount %s -o %s ---", devname, options); mnt = vfs_kern_mount(&afs_fs_type, 0, devname, options); kdebug("--- mount result %p ---", mnt); free_page((unsigned long) devname); free_page((unsigned long) options); kleave(" = %p", mnt); return mnt; error: if (page) page_cache_release(page); if (devname) free_page((unsigned long) devname); if (options) free_page((unsigned long) options); kleave(" = %d", ret); return ERR_PTR(ret); } /* end afs_mntpt_do_automount() */
/* * create a vfsmount to be automounted */ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt) { struct afs_super_info *super; struct vfsmount *mnt; struct afs_vnode *vnode; struct page *page; char *devname, *options; bool rwpath = false; int ret; _enter("{%s}", mntpt->d_name.name); BUG_ON(!mntpt->d_inode); ret = -ENOMEM; devname = (char *) get_zeroed_page(GFP_KERNEL); if (!devname) goto error_no_devname; options = (char *) get_zeroed_page(GFP_KERNEL); if (!options) goto error_no_options; vnode = AFS_FS_I(mntpt->d_inode); if (test_bit(AFS_VNODE_PSEUDODIR, &vnode->flags)) { /* if the directory is a pseudo directory, use the d_name */ static const char afs_root_cell[] = ":root.cell."; unsigned size = mntpt->d_name.len; ret = -ENOENT; if (size < 2 || size > AFS_MAXCELLNAME) goto error_no_page; if (mntpt->d_name.name[0] == '.') { devname[0] = '#'; memcpy(devname + 1, mntpt->d_name.name, size - 1); memcpy(devname + size, afs_root_cell, sizeof(afs_root_cell)); rwpath = true; } else { devname[0] = '%'; memcpy(devname + 1, mntpt->d_name.name, size); memcpy(devname + size + 1, afs_root_cell, sizeof(afs_root_cell)); } } else { /* read the contents of the AFS special symlink */ loff_t size = i_size_read(mntpt->d_inode); char *buf; ret = -EINVAL; if (size > PAGE_SIZE - 1) goto error_no_page; page = read_mapping_page(mntpt->d_inode->i_mapping, 0, NULL); if (IS_ERR(page)) { ret = PTR_ERR(page); goto error_no_page; } ret = -EIO; if (PageError(page)) goto error; buf = kmap_atomic(page, KM_USER0); memcpy(devname, buf, size); kunmap_atomic(buf, KM_USER0); page_cache_release(page); page = NULL; } /* work out what options we want */ super = AFS_FS_S(mntpt->d_sb); memcpy(options, "cell=", 5); strcpy(options + 5, super->volume->cell->name); if (super->volume->type == AFSVL_RWVOL || rwpath) strcat(options, ",rwpath"); /* try and do the mount */ _debug("--- attempting mount %s -o %s ---", devname, options); mnt = vfs_kern_mount(&afs_fs_type, 0, devname, options); _debug("--- mount result %p ---", mnt); free_page((unsigned long) devname); free_page((unsigned long) options); _leave(" = %p", mnt); return mnt; error: page_cache_release(page); error_no_page: free_page((unsigned long) options); error_no_options: free_page((unsigned long) devname); error_no_devname: _leave(" = %d", ret); return ERR_PTR(ret); }
struct vfsmount *cifs_dfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry, char *ref_unc) { int rc; struct cifs_sb_info *cifs_sb; struct sockaddr_in sin_server; struct vfsmount *mnt = ERR_PTR(-ENOENT); char *mountdata; int md_len; char *devname; char *tkn_e; char srvIP[16]; char sep = ','; int off, noff; cFYI(1, ("in %s", __FUNCTION__ )); cifs_sb = CIFS_SB(dentry->d_inode->i_sb); if ( cifs_sb->mountdata == NULL ) { return ERR_PTR(-EINVAL); } devname = cifs_get_share_name(ref_unc); rc = cifs_resolve_server_name_to_ip( devname, &(sin_server.sin_addr)); snprintf(srvIP, sizeof(srvIP), "%u.%u.%u.%u", NIPQUAD(sin_server.sin_addr)); if (rc != 0) { if (devname) kfree(devname); cERROR(1, ("%s: failed to resolve server part of %s to IP", __FUNCTION__, devname )); rc = -EINVAL; return ERR_PTR(rc); } srvIP[sizeof(srvIP)-1] = '\0'; md_len = strlen(cifs_sb->mountdata) + sizeof(srvIP) + strlen(ref_unc) + 3; mountdata = kzalloc(md_len+1, GFP_KERNEL); /* copy all options except unc,ip,prefixpath */ off = 0; if (strncmp(cifs_sb->mountdata, "sep=", 4) == 0) { sep = cifs_sb->mountdata[4]; strncpy(mountdata, cifs_sb->mountdata, 5); off += 5; } while ( (tkn_e = strchr(cifs_sb->mountdata+off, sep)) ) { noff = (tkn_e - (cifs_sb->mountdata+off)) + 1; if (strnicmp(cifs_sb->mountdata+off, "unc=", 4) == 0) { off += noff; continue; } if (strnicmp(cifs_sb->mountdata+off, "ip=", 3) == 0) { off += noff; continue; } if (strnicmp(cifs_sb->mountdata+off, "prefixpath=", 3) == 0) { off += noff; continue; } strncat(mountdata, cifs_sb->mountdata+off, noff); off += noff; } strcat(mountdata, cifs_sb->mountdata+off); mountdata[md_len] = '\0'; strcat(mountdata, ", ip="); strcat(mountdata, srvIP); strcat(mountdata, ", unc="); strcat(mountdata, devname); /* find prefixpath */ tkn_e = strchr(ref_unc+2, '\\'); if ( tkn_e ) { tkn_e = strchr(tkn_e+1, '\\'); if ( tkn_e ) { strcat(mountdata, ",prefixpath="); strcat(mountdata, tkn_e); } } /*cFYI(1,("%s: old mountdata: %s", __FUNCTION__,cifs_sb->mountdata));*/ /*cFYI(1, ("%s: new mountdata: %s", __FUNCTION__, mountdata ));*/ mnt = vfs_kern_mount(&cifs_fs_type, 0, devname, mountdata); if (devname) kfree(devname); if (mountdata) kfree(mountdata); cFYI(1, ("leaving %s", __FUNCTION__ )); return mnt; }
static void* snap_mountpoint_follow_link(struct dentry *dentry, struct nameidata *nd) { struct vfsmount *mnt = ERR_PTR(-ENOENT); vnode_t *dir_vp = NULL; char *snapname = NULL; char *zfs_fs_name = NULL; int rc = 0; vfs_t *vfsp = NULL; ASSERT(dentry->d_parent); dir_vp = LZFS_ITOV(dentry->d_parent->d_inode); vfsp = dir_vp->v_vfsp; ASSERT(vfsp); zfs_fs_name = kzalloc(MAXNAMELEN, KM_SLEEP); dput(nd->path.dentry); nd->path.dentry = dget(dentry); zfs_fs_name_fn(vfsp->vfs_data, zfs_fs_name); snapname = kzalloc(strlen(zfs_fs_name) + strlen(dentry->d_name.name) + 2, KM_SLEEP); snapname = strncpy(snapname, zfs_fs_name, strlen(zfs_fs_name) + 1); snapname = strcat(snapname, "@"); snapname = strcat(snapname, dentry->d_name.name); mnt = vfs_kern_mount(&lzfs_fs_type, 0, snapname, NULL); ((vfs_t *)mnt->mnt_sb->s_fs_info)->vfs_mntpt = dentry; mntget(mnt); rc = PTR_ERR(mnt); if (IS_ERR(mnt)) { goto out_err; } mnt->mnt_mountpoint = dentry; ASSERT(nd); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) rc = do_add_mount(mnt, nd, nd->path.mnt->mnt_flags | MNT_READONLY, NULL); #else rc = do_add_mount(mnt, &nd->path, nd->path.mnt->mnt_flags | MNT_READONLY, NULL); #endif switch (rc) { case 0: path_put(&nd->path); nd->path.mnt = mnt; nd->path.dentry = dget(mnt->mnt_root); break; case -EBUSY: nd->path.dentry = dget(mnt->mnt_root); /* someone else made a mount here whilst we were busy */ #ifdef HAVE_2ARGS_FOLLOW_DOWN /* for kernel version < 2.6.31 */ while (d_mountpoint(nd->path.dentry) && follow_down(&mnt, &nd->path.dentry)) { ; } #else while (d_mountpoint(nd->path.dentry) && follow_down(&nd->path)) { ; } #endif rc = 0; default: mntput(mnt); break; } kfree(zfs_fs_name); kfree(snapname); return ERR_PTR(rc); out_err: path_put(&nd->path); kfree(zfs_fs_name); kfree(snapname); return ERR_PTR(rc); }