1f7b422b1SDavid Howells /* 2f7b422b1SDavid Howells * linux/fs/nfs/nfs4namespace.c 3f7b422b1SDavid Howells * 4f7b422b1SDavid Howells * Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com> 554ceac45SDavid Howells * - Modified by David Howells <dhowells@redhat.com> 6f7b422b1SDavid Howells * 7f7b422b1SDavid Howells * NFSv4 namespace 8f7b422b1SDavid Howells */ 9f7b422b1SDavid Howells 10f7b422b1SDavid Howells #include <linux/dcache.h> 11f7b422b1SDavid Howells #include <linux/mount.h> 12f7b422b1SDavid Howells #include <linux/namei.h> 13f7b422b1SDavid Howells #include <linux/nfs_fs.h> 145a0e3ad6STejun Heo #include <linux/slab.h> 15f7b422b1SDavid Howells #include <linux/string.h> 16f7b422b1SDavid Howells #include <linux/sunrpc/clnt.h> 175976687aSJeff Layton #include <linux/sunrpc/addr.h> 18f7b422b1SDavid Howells #include <linux/vfs.h> 19f7b422b1SDavid Howells #include <linux/inet.h> 20f7b422b1SDavid Howells #include "internal.h" 21c228fd3aSTrond Myklebust #include "nfs4_fs.h" 227d7ea882STrond Myklebust #include "dns_resolve.h" 23f7b422b1SDavid Howells 24f7b422b1SDavid Howells #define NFSDBG_FACILITY NFSDBG_VFS 25f7b422b1SDavid Howells 26f7b422b1SDavid Howells /* 27ef95d31eSTrond Myklebust * Convert the NFSv4 pathname components into a standard posix path. 28ef95d31eSTrond Myklebust * 29ef95d31eSTrond Myklebust * Note that the resulting string will be placed at the end of the buffer 30f7b422b1SDavid Howells */ 31509de811SDavid Howells static inline char *nfs4_pathname_string(const struct nfs4_pathname *pathname, 32f7b422b1SDavid Howells char *buffer, ssize_t buflen) 33f7b422b1SDavid Howells { 34f7b422b1SDavid Howells char *end = buffer + buflen; 35f7b422b1SDavid Howells int n; 36f7b422b1SDavid Howells 37f7b422b1SDavid Howells *--end = '\0'; 38f7b422b1SDavid Howells buflen--; 39f7b422b1SDavid Howells 40f7b422b1SDavid Howells n = pathname->ncomponents; 41f7b422b1SDavid Howells while (--n >= 0) { 42509de811SDavid Howells const struct nfs4_string *component = &pathname->components[n]; 43f7b422b1SDavid Howells buflen -= component->len + 1; 44f7b422b1SDavid Howells if (buflen < 0) 45f7b422b1SDavid Howells goto Elong; 46f7b422b1SDavid Howells end -= component->len; 47f7b422b1SDavid Howells memcpy(end, component->data, component->len); 48f7b422b1SDavid Howells *--end = '/'; 49f7b422b1SDavid Howells } 50f7b422b1SDavid Howells return end; 51f7b422b1SDavid Howells Elong: 52f7b422b1SDavid Howells return ERR_PTR(-ENAMETOOLONG); 53f7b422b1SDavid Howells } 54f7b422b1SDavid Howells 5554ceac45SDavid Howells /* 561aba1567SWeston Andros Adamson * return the path component of "<server>:<path>" 571aba1567SWeston Andros Adamson * nfspath - the "<server>:<path>" string 581aba1567SWeston Andros Adamson * end - one past the last char that could contain "<server>:" 591aba1567SWeston Andros Adamson * returns NULL on failure 601aba1567SWeston Andros Adamson */ 611aba1567SWeston Andros Adamson static char *nfs_path_component(const char *nfspath, const char *end) 621aba1567SWeston Andros Adamson { 631aba1567SWeston Andros Adamson char *p; 641aba1567SWeston Andros Adamson 651aba1567SWeston Andros Adamson if (*nfspath == '[') { 661aba1567SWeston Andros Adamson /* parse [] escaped IPv6 addrs */ 671aba1567SWeston Andros Adamson p = strchr(nfspath, ']'); 681aba1567SWeston Andros Adamson if (p != NULL && ++p < end && *p == ':') 691aba1567SWeston Andros Adamson return p + 1; 701aba1567SWeston Andros Adamson } else { 711aba1567SWeston Andros Adamson /* otherwise split on first colon */ 721aba1567SWeston Andros Adamson p = strchr(nfspath, ':'); 731aba1567SWeston Andros Adamson if (p != NULL && p < end) 741aba1567SWeston Andros Adamson return p + 1; 751aba1567SWeston Andros Adamson } 761aba1567SWeston Andros Adamson return NULL; 771aba1567SWeston Andros Adamson } 781aba1567SWeston Andros Adamson 791aba1567SWeston Andros Adamson /* 8054ceac45SDavid Howells * Determine the mount path as a string 8154ceac45SDavid Howells */ 82b514f872SAl Viro static char *nfs4_path(struct dentry *dentry, char *buffer, ssize_t buflen) 8354ceac45SDavid Howells { 84b514f872SAl Viro char *limit; 8597a54868SBen Hutchings char *path = nfs_path(&limit, dentry, buffer, buflen, 8697a54868SBen Hutchings NFS_PATH_CANONICAL); 87b514f872SAl Viro if (!IS_ERR(path)) { 881aba1567SWeston Andros Adamson char *path_component = nfs_path_component(path, limit); 891aba1567SWeston Andros Adamson if (path_component) 901aba1567SWeston Andros Adamson return path_component; 91b514f872SAl Viro } 92b514f872SAl Viro return path; 9354ceac45SDavid Howells } 9454ceac45SDavid Howells 9554ceac45SDavid Howells /* 9654ceac45SDavid Howells * Check that fs_locations::fs_root [RFC3530 6.3] is a prefix for what we 9754ceac45SDavid Howells * believe to be the server path to this dentry 9854ceac45SDavid Howells */ 99b514f872SAl Viro static int nfs4_validate_fspath(struct dentry *dentry, 10054ceac45SDavid Howells const struct nfs4_fs_locations *locations, 10154ceac45SDavid Howells char *page, char *page2) 10254ceac45SDavid Howells { 10354ceac45SDavid Howells const char *path, *fs_path; 10454ceac45SDavid Howells 105b514f872SAl Viro path = nfs4_path(dentry, page, PAGE_SIZE); 10654ceac45SDavid Howells if (IS_ERR(path)) 10754ceac45SDavid Howells return PTR_ERR(path); 10854ceac45SDavid Howells 10954ceac45SDavid Howells fs_path = nfs4_pathname_string(&locations->fs_path, page2, PAGE_SIZE); 11054ceac45SDavid Howells if (IS_ERR(fs_path)) 11154ceac45SDavid Howells return PTR_ERR(fs_path); 11254ceac45SDavid Howells 11354ceac45SDavid Howells if (strncmp(path, fs_path, strlen(fs_path)) != 0) { 11454ceac45SDavid Howells dprintk("%s: path %s does not begin with fsroot %s\n", 1153110ff80SHarvey Harrison __func__, path, fs_path); 11654ceac45SDavid Howells return -ENOENT; 11754ceac45SDavid Howells } 11854ceac45SDavid Howells 11954ceac45SDavid Howells return 0; 12054ceac45SDavid Howells } 12154ceac45SDavid Howells 1227d7ea882STrond Myklebust static size_t nfs_parse_server_name(char *string, size_t len, 1231b340d01SStanislav Kinsbursky struct sockaddr *sa, size_t salen, struct nfs_server *server) 1247d7ea882STrond Myklebust { 1252446ab60STrond Myklebust struct net *net = rpc_net_ns(server->client); 1267d7ea882STrond Myklebust ssize_t ret; 1277d7ea882STrond Myklebust 12833faaa38SStanislav Kinsbursky ret = rpc_pton(net, string, len, sa, salen); 1297d7ea882STrond Myklebust if (ret == 0) { 13033faaa38SStanislav Kinsbursky ret = nfs_dns_resolve_name(net, string, len, sa, salen); 1317d7ea882STrond Myklebust if (ret < 0) 1327d7ea882STrond Myklebust ret = 0; 1337d7ea882STrond Myklebust } 1347d7ea882STrond Myklebust return ret; 1357d7ea882STrond Myklebust } 1367d7ea882STrond Myklebust 1372671bfc3SBryan Schumaker rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors) 1382671bfc3SBryan Schumaker { 1392671bfc3SBryan Schumaker struct gss_api_mech *mech; 1402671bfc3SBryan Schumaker struct xdr_netobj oid; 141fb15b26fSChuck Lever unsigned int i; 1422671bfc3SBryan Schumaker rpc_authflavor_t pseudoflavor = RPC_AUTH_UNIX; 1432671bfc3SBryan Schumaker 1442671bfc3SBryan Schumaker for (i = 0; i < flavors->num_flavors; i++) { 145fb15b26fSChuck Lever struct nfs4_secinfo4 *flavor = &flavors->flavors[i]; 1462671bfc3SBryan Schumaker 1472671bfc3SBryan Schumaker if (flavor->flavor == RPC_AUTH_NULL || flavor->flavor == RPC_AUTH_UNIX) { 1482671bfc3SBryan Schumaker pseudoflavor = flavor->flavor; 1492671bfc3SBryan Schumaker break; 1502671bfc3SBryan Schumaker } else if (flavor->flavor == RPC_AUTH_GSS) { 151fb15b26fSChuck Lever oid.len = flavor->flavor_info.oid.len; 152fb15b26fSChuck Lever oid.data = flavor->flavor_info.oid.data; 1532671bfc3SBryan Schumaker mech = gss_mech_get_by_OID(&oid); 1542671bfc3SBryan Schumaker if (!mech) 1552671bfc3SBryan Schumaker continue; 156fb15b26fSChuck Lever pseudoflavor = gss_svc_to_pseudoflavor(mech, 157fb15b26fSChuck Lever flavor->flavor_info.service); 1582671bfc3SBryan Schumaker gss_mech_put(mech); 1592671bfc3SBryan Schumaker break; 1602671bfc3SBryan Schumaker } 1612671bfc3SBryan Schumaker } 1622671bfc3SBryan Schumaker 1632671bfc3SBryan Schumaker return pseudoflavor; 1642671bfc3SBryan Schumaker } 1652671bfc3SBryan Schumaker 16672de53ecSBryan Schumaker static rpc_authflavor_t nfs4_negotiate_security(struct inode *inode, struct qstr *name) 16772de53ecSBryan Schumaker { 16872de53ecSBryan Schumaker struct page *page; 16972de53ecSBryan Schumaker struct nfs4_secinfo_flavors *flavors; 17072de53ecSBryan Schumaker rpc_authflavor_t flavor; 17172de53ecSBryan Schumaker int err; 17272de53ecSBryan Schumaker 17372de53ecSBryan Schumaker page = alloc_page(GFP_KERNEL); 17472de53ecSBryan Schumaker if (!page) 17572de53ecSBryan Schumaker return -ENOMEM; 17672de53ecSBryan Schumaker flavors = page_address(page); 17772de53ecSBryan Schumaker 17872de53ecSBryan Schumaker err = nfs4_proc_secinfo(inode, name, flavors); 17972de53ecSBryan Schumaker if (err < 0) { 18072de53ecSBryan Schumaker flavor = err; 18172de53ecSBryan Schumaker goto out; 18272de53ecSBryan Schumaker } 18372de53ecSBryan Schumaker 18472de53ecSBryan Schumaker flavor = nfs_find_best_sec(flavors); 18572de53ecSBryan Schumaker 18672de53ecSBryan Schumaker out: 18772de53ecSBryan Schumaker put_page(page); 18872de53ecSBryan Schumaker return flavor; 18972de53ecSBryan Schumaker } 19072de53ecSBryan Schumaker 19172de53ecSBryan Schumaker /* 19272de53ecSBryan Schumaker * Please call rpc_shutdown_client() when you are done with this client. 19372de53ecSBryan Schumaker */ 19472de53ecSBryan Schumaker struct rpc_clnt *nfs4_create_sec_client(struct rpc_clnt *clnt, struct inode *inode, 19572de53ecSBryan Schumaker struct qstr *name) 19672de53ecSBryan Schumaker { 19772de53ecSBryan Schumaker rpc_authflavor_t flavor; 19872de53ecSBryan Schumaker 19972de53ecSBryan Schumaker flavor = nfs4_negotiate_security(inode, name); 2005f23eff3SBenny Halevy if ((int)flavor < 0) 20162d98c93SNeilBrown return ERR_PTR((int)flavor); 20272de53ecSBryan Schumaker 203ba9b584cSChuck Lever return rpc_clone_client_set_auth(clnt, flavor); 20472de53ecSBryan Schumaker } 20572de53ecSBryan Schumaker 2064ada29d5SJ. Bruce Fields static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, 2074ada29d5SJ. Bruce Fields char *page, char *page2, 2084ada29d5SJ. Bruce Fields const struct nfs4_fs_location *location) 2094ada29d5SJ. Bruce Fields { 210364d015eSTrond Myklebust const size_t addr_bufsize = sizeof(struct sockaddr_storage); 2114ada29d5SJ. Bruce Fields struct vfsmount *mnt = ERR_PTR(-ENOENT); 2124ada29d5SJ. Bruce Fields char *mnt_path; 213ef95d31eSTrond Myklebust unsigned int maxbuflen; 214460cdbc8SJ. Bruce Fields unsigned int s; 2154ada29d5SJ. Bruce Fields 2164ada29d5SJ. Bruce Fields mnt_path = nfs4_pathname_string(&location->rootpath, page2, PAGE_SIZE); 2174ada29d5SJ. Bruce Fields if (IS_ERR(mnt_path)) 218517be09dSTrond Myklebust return ERR_CAST(mnt_path); 2194ada29d5SJ. Bruce Fields mountdata->mnt_path = mnt_path; 220ef95d31eSTrond Myklebust maxbuflen = mnt_path - 1 - page2; 2214ada29d5SJ. Bruce Fields 222364d015eSTrond Myklebust mountdata->addr = kmalloc(addr_bufsize, GFP_KERNEL); 223364d015eSTrond Myklebust if (mountdata->addr == NULL) 224364d015eSTrond Myklebust return ERR_PTR(-ENOMEM); 225364d015eSTrond Myklebust 226460cdbc8SJ. Bruce Fields for (s = 0; s < location->nservers; s++) { 227ea31a443SJ. Bruce Fields const struct nfs4_string *buf = &location->servers[s]; 2284ada29d5SJ. Bruce Fields 229ef95d31eSTrond Myklebust if (buf->len <= 0 || buf->len >= maxbuflen) 2304ada29d5SJ. Bruce Fields continue; 2314ada29d5SJ. Bruce Fields 232ea31a443SJ. Bruce Fields if (memchr(buf->data, IPV6_SCOPE_DELIMITER, buf->len)) 233ea31a443SJ. Bruce Fields continue; 234517be09dSTrond Myklebust 235517be09dSTrond Myklebust mountdata->addrlen = nfs_parse_server_name(buf->data, buf->len, 2361b340d01SStanislav Kinsbursky mountdata->addr, addr_bufsize, 2371b340d01SStanislav Kinsbursky NFS_SB(mountdata->sb)); 23853a0b9c4SChuck Lever if (mountdata->addrlen == 0) 239ea31a443SJ. Bruce Fields continue; 240517be09dSTrond Myklebust 241ec6ee612SChuck Lever rpc_set_port(mountdata->addr, NFS_PORT); 242ea31a443SJ. Bruce Fields 243ef95d31eSTrond Myklebust memcpy(page2, buf->data, buf->len); 244ef95d31eSTrond Myklebust page2[buf->len] = '\0'; 245ea31a443SJ. Bruce Fields mountdata->hostname = page2; 2464ada29d5SJ. Bruce Fields 2474ada29d5SJ. Bruce Fields snprintf(page, PAGE_SIZE, "%s:%s", 2484ada29d5SJ. Bruce Fields mountdata->hostname, 2494ada29d5SJ. Bruce Fields mountdata->mnt_path); 2504ada29d5SJ. Bruce Fields 2514ada29d5SJ. Bruce Fields mnt = vfs_kern_mount(&nfs4_referral_fs_type, 0, page, mountdata); 2524ada29d5SJ. Bruce Fields if (!IS_ERR(mnt)) 2534ada29d5SJ. Bruce Fields break; 2544ada29d5SJ. Bruce Fields } 255364d015eSTrond Myklebust kfree(mountdata->addr); 2564ada29d5SJ. Bruce Fields return mnt; 2574ada29d5SJ. Bruce Fields } 2584ada29d5SJ. Bruce Fields 259f7b422b1SDavid Howells /** 260f7b422b1SDavid Howells * nfs_follow_referral - set up mountpoint when hitting a referral on moved error 261f7b422b1SDavid Howells * @dentry - parent directory 2623f43c666SChuck Lever * @locations - array of NFSv4 server location information 263f7b422b1SDavid Howells * 264f7b422b1SDavid Howells */ 265f8ad9c4bSAl Viro static struct vfsmount *nfs_follow_referral(struct dentry *dentry, 266509de811SDavid Howells const struct nfs4_fs_locations *locations) 267f7b422b1SDavid Howells { 268f7b422b1SDavid Howells struct vfsmount *mnt = ERR_PTR(-ENOENT); 269f7b422b1SDavid Howells struct nfs_clone_mount mountdata = { 270f8ad9c4bSAl Viro .sb = dentry->d_sb, 271f7b422b1SDavid Howells .dentry = dentry, 272f8ad9c4bSAl Viro .authflavor = NFS_SB(dentry->d_sb)->client->cl_auth->au_flavor, 273f7b422b1SDavid Howells }; 27454ceac45SDavid Howells char *page = NULL, *page2 = NULL; 2753f43c666SChuck Lever int loc, error; 276f7b422b1SDavid Howells 277f7b422b1SDavid Howells if (locations == NULL || locations->nlocations <= 0) 278f7b422b1SDavid Howells goto out; 279f7b422b1SDavid Howells 2803110ff80SHarvey Harrison dprintk("%s: referral at %s/%s\n", __func__, 281f7b422b1SDavid Howells dentry->d_parent->d_name.name, dentry->d_name.name); 282f7b422b1SDavid Howells 283f7b422b1SDavid Howells page = (char *) __get_free_page(GFP_USER); 28454ceac45SDavid Howells if (!page) 285f7b422b1SDavid Howells goto out; 28654ceac45SDavid Howells 287f7b422b1SDavid Howells page2 = (char *) __get_free_page(GFP_USER); 28854ceac45SDavid Howells if (!page2) 289f7b422b1SDavid Howells goto out; 290f7b422b1SDavid Howells 29154ceac45SDavid Howells /* Ensure fs path is a prefix of current dentry path */ 292b514f872SAl Viro error = nfs4_validate_fspath(dentry, locations, page, page2); 29354ceac45SDavid Howells if (error < 0) { 29454ceac45SDavid Howells mnt = ERR_PTR(error); 29554ceac45SDavid Howells goto out; 296f7b422b1SDavid Howells } 297f7b422b1SDavid Howells 298460cdbc8SJ. Bruce Fields for (loc = 0; loc < locations->nlocations; loc++) { 299509de811SDavid Howells const struct nfs4_fs_location *location = &locations->locations[loc]; 300f7b422b1SDavid Howells 301f7b422b1SDavid Howells if (location == NULL || location->nservers <= 0 || 302460cdbc8SJ. Bruce Fields location->rootpath.ncomponents == 0) 303f7b422b1SDavid Howells continue; 304f7b422b1SDavid Howells 3054ada29d5SJ. Bruce Fields mnt = try_location(&mountdata, page, page2, location); 3064ada29d5SJ. Bruce Fields if (!IS_ERR(mnt)) 307f7b422b1SDavid Howells break; 308f7b422b1SDavid Howells } 309f7b422b1SDavid Howells 31054ceac45SDavid Howells out: 311f7b422b1SDavid Howells free_page((unsigned long) page); 312f7b422b1SDavid Howells free_page((unsigned long) page2); 3133110ff80SHarvey Harrison dprintk("%s: done\n", __func__); 314f7b422b1SDavid Howells return mnt; 315f7b422b1SDavid Howells } 316f7b422b1SDavid Howells 317f7b422b1SDavid Howells /* 318f7b422b1SDavid Howells * nfs_do_refmount - handle crossing a referral on server 319f7b422b1SDavid Howells * @dentry - dentry of referral 320f7b422b1SDavid Howells * 321f7b422b1SDavid Howells */ 322281cad46SBryan Schumaker static struct vfsmount *nfs_do_refmount(struct rpc_clnt *client, struct dentry *dentry) 323f7b422b1SDavid Howells { 32454ceac45SDavid Howells struct vfsmount *mnt = ERR_PTR(-ENOMEM); 325f7b422b1SDavid Howells struct dentry *parent; 326f7b422b1SDavid Howells struct nfs4_fs_locations *fs_locations = NULL; 327f7b422b1SDavid Howells struct page *page; 328f7b422b1SDavid Howells int err; 329f7b422b1SDavid Howells 330f7b422b1SDavid Howells /* BUG_ON(IS_ROOT(dentry)); */ 3313110ff80SHarvey Harrison dprintk("%s: enter\n", __func__); 332f7b422b1SDavid Howells 333f7b422b1SDavid Howells page = alloc_page(GFP_KERNEL); 334f7b422b1SDavid Howells if (page == NULL) 335f7b422b1SDavid Howells goto out; 336f7b422b1SDavid Howells 337f7b422b1SDavid Howells fs_locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL); 338f7b422b1SDavid Howells if (fs_locations == NULL) 339f7b422b1SDavid Howells goto out_free; 340f7b422b1SDavid Howells 341f7b422b1SDavid Howells /* Get locations */ 34254ceac45SDavid Howells mnt = ERR_PTR(-ENOENT); 34354ceac45SDavid Howells 344f7b422b1SDavid Howells parent = dget_parent(dentry); 34554ceac45SDavid Howells dprintk("%s: getting locations for %s/%s\n", 3463110ff80SHarvey Harrison __func__, parent->d_name.name, dentry->d_name.name); 34754ceac45SDavid Howells 348f05d147fSBryan Schumaker err = nfs4_proc_fs_locations(client, parent->d_inode, &dentry->d_name, fs_locations, page); 349f7b422b1SDavid Howells dput(parent); 35054ceac45SDavid Howells if (err != 0 || 35154ceac45SDavid Howells fs_locations->nlocations <= 0 || 352f7b422b1SDavid Howells fs_locations->fs_path.ncomponents <= 0) 353f7b422b1SDavid Howells goto out_free; 354f7b422b1SDavid Howells 355f8ad9c4bSAl Viro mnt = nfs_follow_referral(dentry, fs_locations); 356f7b422b1SDavid Howells out_free: 357f7b422b1SDavid Howells __free_page(page); 358f7b422b1SDavid Howells kfree(fs_locations); 359f7b422b1SDavid Howells out: 3603110ff80SHarvey Harrison dprintk("%s: done\n", __func__); 361f7b422b1SDavid Howells return mnt; 362f7b422b1SDavid Howells } 363281cad46SBryan Schumaker 364281cad46SBryan Schumaker struct vfsmount *nfs4_submount(struct nfs_server *server, struct dentry *dentry, 365281cad46SBryan Schumaker struct nfs_fh *fh, struct nfs_fattr *fattr) 366281cad46SBryan Schumaker { 367281cad46SBryan Schumaker struct dentry *parent = dget_parent(dentry); 368281cad46SBryan Schumaker struct rpc_clnt *client; 369281cad46SBryan Schumaker struct vfsmount *mnt; 370281cad46SBryan Schumaker 371281cad46SBryan Schumaker /* Look it up again to get its attributes and sec flavor */ 372281cad46SBryan Schumaker client = nfs4_proc_lookup_mountpoint(parent->d_inode, &dentry->d_name, fh, fattr); 373281cad46SBryan Schumaker dput(parent); 374281cad46SBryan Schumaker if (IS_ERR(client)) 375281cad46SBryan Schumaker return ERR_CAST(client); 376281cad46SBryan Schumaker 377281cad46SBryan Schumaker if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) 378281cad46SBryan Schumaker mnt = nfs_do_refmount(client, dentry); 379281cad46SBryan Schumaker else 380281cad46SBryan Schumaker mnt = nfs_do_submount(dentry, fh, fattr, client->cl_auth->au_flavor); 381281cad46SBryan Schumaker 382281cad46SBryan Schumaker rpc_shutdown_client(client); 383281cad46SBryan Schumaker return mnt; 384281cad46SBryan Schumaker } 385