Print this page
2988 nfssrv: need ability to go to submounts for v3 and v2 protocols
Portions contributed by: Marcel Telka <marcel.telka@nexenta.com>
Portions contributed by: Jean McCormack <jean.mccormack@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Dan McDonald <danmcd@joyent.com>
Change-Id: I6fdf110cc17e789353c4442b83a46cb80643456e

*** 16,28 **** * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved. ! * Copyright 2014 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2016 by Delphix. All rights reserved. */ /* * Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T. --- 16,29 ---- * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ + /* * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved. ! * Copyright 2015 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2016 by Delphix. All rights reserved. */ /* * Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T.
*** 327,337 **** --- 328,412 ---- rfs_setattr_getfh(struct nfssaargs *args) { return (&args->saa_fh); } + /* Change and release @exip and @vpp only in success */ + int + rfs_cross_mnt(vnode_t **vpp, struct exportinfo **exip) + { + struct exportinfo *exi; + vnode_t *vp = *vpp; + fid_t fid; + int error; + + VN_HOLD(vp); + + if ((error = traverse(&vp)) != 0) { + VN_RELE(vp); + return (error); + } + + bzero(&fid, sizeof (fid)); + fid.fid_len = MAXFIDSZ; + error = VOP_FID(vp, &fid, NULL); + if (error) { + VN_RELE(vp); + return (error); + } + + exi = checkexport(&vp->v_vfsp->vfs_fsid, &fid); + if (exi == NULL || + (exi->exi_export.ex_flags & EX_NOHIDE) == 0) { + /* + * It is not error, just subdir is not exported + * or "nohide" is not set + */ + if (exi != NULL) + exi_rele(exi); + VN_RELE(vp); + } else { + /* go to submount */ + exi_rele(*exip); + *exip = exi; + + VN_RELE(*vpp); + *vpp = vp; + } + + return (0); + } + /* + * Given mounted "dvp" and "exi", go upper mountpoint + * with dvp/exi correction + * Return 0 in success + */ + int + rfs_climb_crossmnt(vnode_t **dvpp, struct exportinfo **exip, cred_t *cr) + { + struct exportinfo *exi; + vnode_t *dvp = *dvpp; + + ASSERT(dvp->v_flag & VROOT); + + VN_HOLD(dvp); + dvp = untraverse(dvp); + exi = nfs_vptoexi(NULL, dvp, cr, NULL, NULL, FALSE); + if (exi == NULL) { + VN_RELE(dvp); + return (-1); + } + + exi_rele(*exip); + *exip = exi; + VN_RELE(*dvpp); + *dvpp = dvp; + + return (0); + } + /* * Directory lookup. * Returns an fhandle and file attributes for file name in a directory. */ /* ARGSUSED */ void
*** 379,407 **** dr->dr_status = NFSERR_STALE; return; } } /* * Not allow lookup beyond root. * If the filehandle matches a filehandle of the exi, * then the ".." refers beyond the root of an exported filesystem. */ if (strcmp(da->da_name, "..") == 0 && EQFID(&exi->exi_fid, (fid_t *)&fhp->fh_len)) { ! VN_RELE(dvp); ! dr->dr_status = NFSERR_NOENT; ! return; } ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; name = nfscmd_convname(ca, exi, da->da_name, NFSCMD_CONV_INBOUND, MAXPATHLEN); if (name == NULL) { ! dr->dr_status = NFSERR_ACCES; ! return; } /* * If the public filehandle is used then allow * a multi-component lookup, i.e. evaluate --- 454,494 ---- dr->dr_status = NFSERR_STALE; return; } } + exi_hold(exi); + /* * Not allow lookup beyond root. * If the filehandle matches a filehandle of the exi, * then the ".." refers beyond the root of an exported filesystem. */ if (strcmp(da->da_name, "..") == 0 && EQFID(&exi->exi_fid, (fid_t *)&fhp->fh_len)) { ! if ((exi->exi_export.ex_flags & EX_NOHIDE) && ! (dvp->v_flag & VROOT)) { ! /* ! * special case for ".." and 'nohide'exported root ! */ ! if (rfs_climb_crossmnt(&dvp, &exi, cr) != 0) { ! error = NFSERR_ACCES; ! goto out; } + } else { + error = NFSERR_NOENT; + goto out; + } + } ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; name = nfscmd_convname(ca, exi, da->da_name, NFSCMD_CONV_INBOUND, MAXPATHLEN); if (name == NULL) { ! error = NFSERR_ACCES; ! goto out; } /* * If the public filehandle is used then allow * a multi-component lookup, i.e. evaluate
*** 411,420 **** --- 498,510 ---- * This may result in a vnode in another filesystem * which is OK as long as the filesystem is exported. */ if (PUBLIC_FH2(fhp)) { publicfh_flag = TRUE; + + exi_rele(exi); + error = rfs_publicfh_mclookup(name, dvp, cr, &vp, &exi, &sec); } else { /* * Do a normal single component lookup.
*** 424,433 **** --- 514,528 ---- } if (name != da->da_name) kmem_free(name, MAXPATHLEN); + if (error == 0 && vn_ismntpt(vp)) { + error = rfs_cross_mnt(&vp, &exi); + if (error) + VN_RELE(vp); + } if (!error) { va.va_mask = AT_ALL; /* we want everything */ error = rfs4_delegated_getattr(vp, &va, 0, cr);
*** 450,468 **** } } VN_RELE(vp); } VN_RELE(dvp); ! /* ! * If publicfh_flag is true then we have called rfs_publicfh_mclookup ! * and have obtained a new exportinfo in exi which needs to be ! * released. Note the the original exportinfo pointed to by exi ! * will be released by the caller, comon_dispatch. ! */ ! if (publicfh_flag && exi != NULL) exi_rele(exi); /* * If it's public fh, no 0x81, and client's flavor is * invalid, set WebNFS status to WNFSERR_CLNT_FLAVOR now. --- 545,558 ---- } } VN_RELE(vp); } + out: VN_RELE(dvp); ! if (exi != NULL) exi_rele(exi); /* * If it's public fh, no 0x81, and client's flavor is * invalid, set WebNFS status to WNFSERR_CLNT_FLAVOR now.