diff options
author | jasmith <none@none> | 2007-08-15 15:11:46 -0700 |
---|---|---|
committer | jasmith <none@none> | 2007-08-15 15:11:46 -0700 |
commit | af9f976974e1de7e139c213e6a8ab6e40196328c (patch) | |
tree | eb7b8ca15fe1d714007e5303d910bf7238db4f00 | |
parent | 1aef0e1149d6c985ac9c3c60ce727f4dbe5a560a (diff) | |
download | illumos-gate-af9f976974e1de7e139c213e6a8ab6e40196328c.tar.gz |
6216103 assertion failed: curdata->ex_seccnt > 0 seen again
-rw-r--r-- | usr/src/uts/common/fs/nfs/nfs4_srv_ns.c | 55 | ||||
-rw-r--r-- | usr/src/uts/common/fs/nfs/nfs_export.c | 863 | ||||
-rw-r--r-- | usr/src/uts/common/nfs/export.h | 10 |
3 files changed, 614 insertions, 314 deletions
diff --git a/usr/src/uts/common/fs/nfs/nfs4_srv_ns.c b/usr/src/uts/common/fs/nfs/nfs4_srv_ns.c index 5402f8e5a8..2d3cd81fba 100644 --- a/usr/src/uts/common/fs/nfs/nfs4_srv_ns.c +++ b/usr/src/uts/common/fs/nfs/nfs4_srv_ns.c @@ -18,7 +18,7 @@ * * CDDL HEADER END * - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -30,6 +30,8 @@ #include <nfs/export.h> #include <sys/cmn_err.h> +#define PSEUDOFS_SUFFIX " (pseudo)" + /* * A version of VOP_FID that deals with a remote VOP_FID for nfs. * If vp is an nfs node, nfs4_fid() returns EREMOTE, nfs3_fid() and nfs_fid() @@ -42,8 +44,8 @@ * nfs filesystem is also part of it. Thus, need to be able to setup a pseudo * exportinfo for an nfs node. * - * e.g. mount an ufs filesystem on an nfs filesystem, then share the ufs - * filesystem. (like exporting a local disk from a "diskless" client) + * e.g. mount a filesystem on top of a nfs dir, and then share the new mount + * (like exporting a local disk from a "diskless" client) */ int vop_fid_pseudo(vnode_t *vp, fid_t *fidp) @@ -124,20 +126,19 @@ nfs4_vget_pseudo(struct exportinfo *exi, vnode_t **vpp, fid_t *fidp) * a real export, the pathname to the export is * checked to see if all the directory components * are accessible via an NFSv4 client, i.e. are - * exported. If tree_climb() finds an unexported + * exported. If treeclimb_export() finds an unexported * mountpoint along the path, then it calls this * function to export it. * - * This pseudo export differs from a real export - * in restriction on simple. read-only access, - * and the addition of a "visible" list of directories. - * A real export may have a visible list if it is a root of - * a file system and at least one of its subtree resides in - * a different file system is shared. + * This pseudo export differs from a real export in that + * it only allows read-only access. A "visible" list of + * directories is added to filter lookup and readdir results + * to only contain dirnames which lead to descendant shares. * - * A visible list is per file system. It resides in the exportinfo - * for the pseudo node (VROOT) and it could reside in a real export - * of a VROOT node. + * A visible list has a per-file-system scope. Any exportinfo + * struct (real or pseudo) can have a visible list as long as + * a) its export root is VROOT + * b) a descendant of the export root is shared */ int pseudo_exportfs(vnode_t *vp, struct exp_visible *vis_head, @@ -147,8 +148,7 @@ pseudo_exportfs(vnode_t *vp, struct exp_visible *vis_head, struct exportdata *kex; fid_t fid; fsid_t fsid; - int error; - char *pseudo; + int error, vpathlen; ASSERT(RW_WRITE_HELD(&exported_lock)); @@ -177,7 +177,7 @@ pseudo_exportfs(vnode_t *vp, struct exp_visible *vis_head, exi->exi_visible = vis_head; exi->exi_count = 1; exi->exi_volatile_dev = (vfssw[vp->v_vfsp->vfs_fstype].vsw_flag & - VSW_VOLATILEDEV) ? 1 : 0; + VSW_VOLATILEDEV) ? 1 : 0; mutex_init(&exi->exi_lock, NULL, MUTEX_DEFAULT, NULL); /* @@ -193,12 +193,13 @@ pseudo_exportfs(vnode_t *vp, struct exp_visible *vis_head, kex = &exi->exi_export; kex->ex_flags = EX_PSEUDO; - /* Set up a generic pathname */ - - pseudo = "(pseudo)"; - kex->ex_pathlen = strlen(pseudo); + vpathlen = vp->v_path ? strlen(vp->v_path) : 0; + kex->ex_pathlen = vpathlen + strlen(PSEUDOFS_SUFFIX); kex->ex_path = kmem_alloc(kex->ex_pathlen + 1, KM_SLEEP); - (void) strcpy(kex->ex_path, pseudo); + + if (vpathlen) + (void) strcpy(kex->ex_path, vp->v_path); + (void) strcpy(kex->ex_path + vpathlen, PSEUDOFS_SUFFIX); /* Transfer the secinfo data from exdata to this new pseudo node */ if (exdata) @@ -228,7 +229,9 @@ free_visible(struct exp_visible *head) for (visp = head; visp; visp = next) { if (visp->vis_vp != NULL) VN_RELE(visp->vis_vp); + next = visp->vis_next; + srv_secinfo_list_free(visp->vis_secinfo, visp->vis_seccnt); kmem_free(visp, sizeof (*visp)); } } @@ -297,7 +300,7 @@ more_visible(struct exportinfo *exi, struct exp_visible *vis_head) * set to 1. * * For example, if /export/home was shared - * (and a UFS mountpoint), then "export" and + * (and a mountpoint), then "export" and * "home" would each have visible structs in * the root pseudo exportinfo. The vis_exported * for home would be 1, and vis_exported for @@ -383,6 +386,8 @@ less_visible(struct exportinfo *exi, struct exp_visible *vis_head) prev->vis_next = next; VN_RELE(vp2->vis_vp); + srv_secinfo_list_free(vp2->vis_secinfo, + vp2->vis_seccnt); kmem_free(vp2, sizeof (*vp1)); } else { /* @@ -566,6 +571,8 @@ treeclimb_export(struct exportinfo *exip) visp->vis_ino = va.va_nodeid; visp->vis_count = 1; visp->vis_exported = exportdir; + visp->vis_secinfo = NULL; + visp->vis_seccnt = 0; visp->vis_next = vis_head; vis_head = visp; @@ -660,7 +667,7 @@ treeclimb_unexport(struct exportinfo *exip) * the parent export. */ error = export_unlink(&vp->v_vfsp->vfs_fsid, - &fid, vp, NULL); + &fid, vp, NULL); if (error) break; @@ -694,6 +701,8 @@ treeclimb_unexport(struct exportinfo *exip) visp->vis_ino = 0; visp->vis_count = 1; visp->vis_exported = exportdir; + visp->vis_secinfo = NULL; + visp->vis_seccnt = 0; visp->vis_next = vis_head; vis_head = visp; diff --git a/usr/src/uts/common/fs/nfs/nfs_export.c b/usr/src/uts/common/fs/nfs/nfs_export.c index 52f380a7ac..1eb16d4173 100644 --- a/usr/src/uts/common/fs/nfs/nfs_export.c +++ b/usr/src/uts/common/fs/nfs/nfs_export.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -50,6 +50,7 @@ #include <sys/cmn_err.h> #include <sys/acl.h> #include <sys/utsname.h> +#include <sys/sdt.h> #include <netinet/in.h> #include <rpc/types.h> @@ -69,17 +70,25 @@ struct exportinfo *exptable[EXPTABLESIZE]; static int unexport(fsid_t *, fid_t *, vnode_t *); -static void exportfree(struct exportinfo *); -static int loadindex(struct exportdata *); +static void exportfree(exportinfo_t *); +static int loadindex(exportdata_t *); -extern void nfsauth_cache_free(struct exportinfo *); +extern void nfsauth_cache_free(exportinfo_t *); extern int sec_svc_loadrootnames(int, int, caddr_t **, model_t); extern void sec_svc_freerootnames(int, int, caddr_t *); +static int build_seclist_nodups(exportdata_t *, secinfo_t *, int); +static void srv_secinfo_add(secinfo_t **, int *, secinfo_t *, int, int); +static void srv_secinfo_remove(secinfo_t **, int *, secinfo_t *, int); +static void pseudo_secinfo_add(exportinfo_t *, exp_visible_t *, exportinfo_t *); +static void pseudo_secinfo_remove(exportinfo_t *, exp_visible_t *); +static void free_pseudoanc(struct exp_visible *); +static int srv_secinfo_treeclimb(exportinfo_t *, secinfo_t *, int, int); + #ifdef VOLATILE_FH_TEST -static struct ex_vol_rename *find_volrnm_fh(struct exportinfo *, nfs_fh4 *); -static uint32_t find_volrnm_fh_id(struct exportinfo *, nfs_fh4 *); -static void free_volrnm_list(struct exportinfo *); +static struct ex_vol_rename *find_volrnm_fh(exportinfo_t *, nfs_fh4 *); +static uint32_t find_volrnm_fh_id(exportinfo_t *, nfs_fh4 *); +static void free_volrnm_list(exportinfo_t *); #endif /* VOLATILE_FH_TEST */ /* @@ -98,6 +107,14 @@ fid_t exi_rootfid; /* for checking the default public file handle */ fhandle_t nullfh2; /* for comparing V2 filehandles */ +/* + * macro for static dtrace probes to trace server namespace ref count mods. + */ +#define SECREF_TRACE(seclist, tag, flav, aftcnt) \ + DTRACE_PROBE4(nfss__d__nmspc__secref, struct secinfo *, (seclist), \ + char *, (tag), int, (int)(flav), int, (int)(aftcnt)) + + #define exptablehash(fsid, fid) (nfs_fhhash((fsid), (fid)) & (EXPTABLESIZE - 1)) /* @@ -165,16 +182,16 @@ srv_secinfo_entry_free(struct secinfo *secp) { if (secp->s_rootcnt > 0 && secp->s_rootnames != NULL) { sec_svc_freerootnames(secp->s_secinfo.sc_rpcnum, - secp->s_rootcnt, secp->s_rootnames); + secp->s_rootcnt, secp->s_rootnames); secp->s_rootcnt = 0; } if ((secp->s_secinfo.sc_rpcnum == RPCSEC_GSS) && (secp->s_secinfo.sc_gss_mech_type)) { kmem_free(secp->s_secinfo.sc_gss_mech_type->elements, - secp->s_secinfo.sc_gss_mech_type->length); + secp->s_secinfo.sc_gss_mech_type->length); kmem_free(secp->s_secinfo.sc_gss_mech_type, - sizeof (rpc_gss_OID_desc)); + sizeof (rpc_gss_OID_desc)); secp->s_secinfo.sc_gss_mech_type = NULL; } @@ -219,21 +236,21 @@ srv_secinfo_copy(struct secinfo *from, struct secinfo *to) if (from->s_secinfo.sc_rpcnum == RPCSEC_GSS) { to->s_secinfo.sc_service = from->s_secinfo.sc_service; bcopy(from->s_secinfo.sc_name, to->s_secinfo.sc_name, - strlen(from->s_secinfo.sc_name)); + strlen(from->s_secinfo.sc_name)); bcopy(from->s_secinfo.sc_gss_mech, to->s_secinfo.sc_gss_mech, - strlen(from->s_secinfo.sc_gss_mech)); + strlen(from->s_secinfo.sc_gss_mech)); /* copy mechanism oid */ to->s_secinfo.sc_gss_mech_type = - kmem_alloc(sizeof (rpc_gss_OID_desc), KM_SLEEP); + kmem_alloc(sizeof (rpc_gss_OID_desc), KM_SLEEP); to->s_secinfo.sc_gss_mech_type->length = - from->s_secinfo.sc_gss_mech_type->length; + from->s_secinfo.sc_gss_mech_type->length; to->s_secinfo.sc_gss_mech_type->elements = - kmem_alloc(from->s_secinfo.sc_gss_mech_type->length, - KM_SLEEP); + kmem_alloc(from->s_secinfo.sc_gss_mech_type->length, + KM_SLEEP); bcopy(from->s_secinfo.sc_gss_mech_type->elements, - to->s_secinfo.sc_gss_mech_type->elements, - from->s_secinfo.sc_gss_mech_type->length); + to->s_secinfo.sc_gss_mech_type->elements, + from->s_secinfo.sc_gss_mech_type->length); } to->s_refcnt = from->s_refcnt; @@ -242,31 +259,43 @@ srv_secinfo_copy(struct secinfo *from, struct secinfo *to) } /* - * Create an secinfo array without duplicates to facilitate - * flavor merging. + * Create a secinfo array without duplicates. The condensed + * flavor list is used to propagate flavor ref counts to an + * export's ancestor pseudonodes. */ -int32_t -build_seclist_nodups(struct exportdata *data, struct secinfo *nsec) +static int +build_seclist_nodups(exportdata_t *exd, secinfo_t *nodups, int exponly) { - int i, j, dup; /* counters */ - int tcnt; /* total sec count */ - int32_t ncnt; - - tcnt = data->ex_seccnt; - - /* Populate exportdata structure only with non duplicate flavors */ - for (i = 0, ncnt = 0; i < tcnt; i++) { - /* see if previous dup copied */ - for (j = 0, dup = 0; j < i; j++) { - if (data->ex_secinfo[i].s_secinfo.sc_nfsnum == - data->ex_secinfo[j].s_secinfo.sc_nfsnum) { - dup = 1; + int ccnt, c; + int ncnt, n; + struct secinfo *cursec; + + ncnt = 0; + ccnt = exd->ex_seccnt; + cursec = exd->ex_secinfo; + + for (c = 0; c < ccnt; c++) { + + if (exponly && ! SEC_REF_EXPORTED(&cursec[c])) + continue; + + for (n = 0; n < ncnt; n++) { + if (nodups[n].s_secinfo.sc_nfsnum == + cursec[c].s_secinfo.sc_nfsnum) break; - } } - if (dup == 0) { - bcopy(&data->ex_secinfo[i], &nsec[ncnt], - sizeof (struct secinfo)); + + /* + * The structure copy below also copys ptrs embedded + * within struct secinfo. The ptrs are copied but + * they are never freed from the nodups array. If + * an ancestor's secinfo array doesn't contain one + * of the nodups flavors, then the entry is properly + * copied into the ancestor's secinfo array. + * (see srv_secinfo_copy) + */ + if (n == ncnt) { + nodups[n] = cursec[c]; ncnt++; } } @@ -274,42 +303,41 @@ build_seclist_nodups(struct exportdata *data, struct secinfo *nsec) } /* - * Add the new security flavors from newdata to the current list, curdata. - * Upon return, curdata has the newly merged secinfo list. + * Add the new security flavors from newdata to the current list, pcursec. + * Upon return, *pcursec has the newly merged secinfo list. * - * There should be at least 1 secinfo entry in newdata. + * There should be at least 1 secinfo entry in newsec. * * This routine is used under the protection of exported_lock (RW_WRITER). */ -void -srv_secinfo_add(struct exportdata *curdata, struct secinfo *newsecinfo, - int ncnt) +static void +srv_secinfo_add(secinfo_t **pcursec, int *pcurcnt, secinfo_t *newsec, + int newcnt, int is_pseudo) { int ccnt, c; /* sec count in current data - curdata */ - int n; /* sec count in new data - newsecinfo */ - int tcnt, mcnt; /* total sec count after merge */ + int n; /* index for newsec - newsecinfo */ + int tcnt; /* total sec count after merge */ + int mcnt; /* total sec count after merge */ struct secinfo *msec; /* merged secinfo list */ + struct secinfo *cursec; - ccnt = curdata->ex_seccnt; + cursec = *pcursec; + ccnt = *pcurcnt; - ASSERT(ncnt > 0); - tcnt = ccnt + ncnt; + ASSERT(newcnt > 0); + tcnt = ccnt + newcnt; - for (n = 0; n < ncnt; n++) { + for (n = 0; n < newcnt; n++) { for (c = 0; c < ccnt; c++) { - if (newsecinfo[n].s_secinfo.sc_nfsnum == - curdata->ex_secinfo[c].s_secinfo.sc_nfsnum) { - - /* - * add the reference count of the newsecinfo - * to the curdata for this nfs flavor. - */ - curdata->ex_secinfo[c].s_refcnt += - newsecinfo[n].s_refcnt; - - tcnt--; - break; - } + if (newsec[n].s_secinfo.sc_nfsnum == + cursec[c].s_secinfo.sc_nfsnum) { + cursec[c].s_refcnt++; + SECREF_TRACE(cursec, "add_ref", + cursec[c].s_secinfo.sc_nfsnum, + cursec[c].s_refcnt); + tcnt--; + break; + } } } @@ -319,65 +347,73 @@ srv_secinfo_add(struct exportdata *curdata, struct secinfo *newsecinfo, msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP); /* move current secinfo list data to the new list */ - for (c = 0; c < ccnt; c++) { - - bcopy(&curdata->ex_secinfo[c], &msec[c], - sizeof (struct secinfo)); - } + for (c = 0; c < ccnt; c++) + msec[c] = cursec[c]; /* Add the flavor that's not in the current data */ mcnt = ccnt; - for (n = 0; n < ncnt; n++) { + for (n = 0; n < newcnt; n++) { for (c = 0; c < ccnt; c++) { - if (newsecinfo[n].s_secinfo.sc_nfsnum == - curdata->ex_secinfo[c].s_secinfo.sc_nfsnum) + if (newsec[n].s_secinfo.sc_nfsnum == + cursec[c].s_secinfo.sc_nfsnum) break; } /* This is the one. Add it. */ if (c == ccnt) { - srv_secinfo_copy(&newsecinfo[n], &msec[mcnt]); - if (curdata->ex_flags & EX_PSEUDO) - msec[mcnt].s_flags = M_RO; - mcnt++; + srv_secinfo_copy(&newsec[n], &msec[mcnt]); + + if (is_pseudo) + msec[mcnt].s_flags = M_RO; + + SECREF_TRACE(msec, "new_ref", + msec[mcnt].s_secinfo.sc_nfsnum, + msec[mcnt].s_refcnt); + mcnt++; } } ASSERT(mcnt == tcnt); + /* - * Done. Update curdata. - * Free up the existing secinfo list in curdata and - * set the new value. + * Done. Update curdata. Free the old secinfo list in + * curdata and return the new sec array info */ if (ccnt > 0) - kmem_free(curdata->ex_secinfo, ccnt * sizeof (struct secinfo)); - curdata->ex_seccnt = tcnt; - curdata->ex_secinfo = msec; + kmem_free(cursec, ccnt * sizeof (struct secinfo)); + *pcurcnt = tcnt; + *pcursec = msec; } /* * For NFS V4. * Remove the security data of the unexported node from its ancestors. - * Assume there is at least one flavor entry in the current data, curdata. + * Assume there is at least one flavor entry in the current sec list + * (pcursec). * * This routine is used under the protection of exported_lock (RW_WRITER). + * + * Every element of remsec is an explicitly exported flavor. If + * srv_secinfo_remove() is called fom an exportfs error path, then + * the flavor list was derived from the user's share cmdline, + * and all flavors are explicit. If it was called from the unshare path, + * build_seclist_nodups() was called with the exponly flag. */ -void -srv_secinfo_remove(struct exportdata *curdata, - struct secinfo *remsecinfo, int rcnt) +static void +srv_secinfo_remove(secinfo_t **pcursec, int *pcurcnt, secinfo_t *remsec, + int remcnt) { int ccnt, c; /* sec count in current data - curdata */ int r; /* sec count in removal data - remsecinfo */ int tcnt, mcnt; /* total sec count after removing */ struct secinfo *msec; /* final secinfo list after removing */ + struct secinfo *cursec; - ASSERT(curdata->ex_seccnt > 0); - ccnt = curdata->ex_seccnt; + cursec = *pcursec; + ccnt = *pcurcnt; tcnt = ccnt; - for (r = 0; r < rcnt; r++) { - - if (SEC_REF_EXPORTED(&remsecinfo[r])) { + for (r = 0; r < remcnt; r++) { /* * Remove a flavor only if the flavor was a shared flavor for * the remsecinfo exported node that's being unshared. @@ -385,25 +421,28 @@ srv_secinfo_remove(struct exportdata *curdata, * need to keep it. */ for (c = 0; c < ccnt; c++) { - if (remsecinfo[r].s_secinfo.sc_nfsnum == - curdata->ex_secinfo[c].s_secinfo.sc_nfsnum) { + if (remsec[r].s_secinfo.sc_nfsnum == + cursec[c].s_secinfo.sc_nfsnum) { - /* - * Decrement secinfo reference count by 1. - * If this entry is invalid after decrementing - * the count (i.e. count < 1), this entry will - * be removed. - */ - curdata->ex_secinfo[c].s_refcnt--; - ASSERT(curdata->ex_secinfo[c].s_refcnt >= 0); + /* + * Decrement secinfo reference count by 1. + * If this entry is invalid after decrementing + * the count (i.e. count < 1), this entry will + * be removed. + */ + cursec[c].s_refcnt--; - if (SEC_REF_INVALID(&curdata->ex_secinfo[c])) - tcnt--; + SECREF_TRACE(cursec, "del_ref", + cursec[c].s_secinfo.sc_nfsnum, + cursec[c].s_refcnt); - break; - } + ASSERT(cursec[c].s_refcnt >= 0); + + if (SEC_REF_INVALID(&cursec[c])) + tcnt--; + break; + } } - } } ASSERT(tcnt >= 0); @@ -411,9 +450,9 @@ srv_secinfo_remove(struct exportdata *curdata, return; /* no change; no flavors to remove */ if (tcnt == 0) { - srv_secinfo_list_free(curdata->ex_secinfo, ccnt); - curdata->ex_seccnt = 0; - curdata->ex_secinfo = NULL; + srv_secinfo_list_free(cursec, ccnt); + *pcurcnt = 0; + *pcursec = NULL; return; } @@ -422,12 +461,10 @@ srv_secinfo_remove(struct exportdata *curdata, /* walk thru the given secinfo list to remove the flavors */ mcnt = 0; for (c = 0; c < ccnt; c++) { - - if (SEC_REF_INVALID(&curdata->ex_secinfo[c])) { - srv_secinfo_entry_free(&curdata->ex_secinfo[c]); + if (SEC_REF_INVALID(&cursec[c])) { + srv_secinfo_entry_free(&cursec[c]); } else { - bcopy(&curdata->ex_secinfo[c], &msec[mcnt], - sizeof (struct secinfo)); + msec[mcnt] = cursec[c]; mcnt++; } } @@ -439,25 +476,158 @@ srv_secinfo_remove(struct exportdata *curdata, * within the list have either been moved to msec or freed * if it's invalid. */ - kmem_free(curdata->ex_secinfo, ccnt * sizeof (struct secinfo)); - curdata->ex_seccnt = tcnt; - curdata->ex_secinfo = msec; + kmem_free(*pcursec, ccnt * sizeof (struct secinfo)); + *pcursec = msec; + *pcurcnt = tcnt; +} + + +/* + * pseudo_secinfo_add + * ancexi: ancestor exportinfo + * ancpseudo: linked list of ancestor pseudnodes + * newexi: new export that needs to inherit implicitly allowed flavors + * + * Increment secflavor ref counts in ancestor pseudonodes. If newexi + * is non-NULL, then also set newexi's implicitly allowed flavors by + * copy the flavors in its pseudonode. + * + * There's no work to do if either the ancexi's pseudonode list + * or ancpseudo is empty. + * + * ancexi->exi_visible could be NULL because sec flavor refs are + * propagated after the namespace has been changed for the new + * share/unshare. In the unshare case, the pseudnodes leading to + * this export have already been dereferenced and possibly destroyed. + * If the parent export had no other shared descendants, then its + * pseudonode list would be empty. + */ +static void +pseudo_secinfo_add(exportinfo_t *ancexi, exp_visible_t *ancpseudo, + exportinfo_t *newexi) +{ + exp_visible_t *av, *v; + fid_t *nxfid = NULL; + secinfo_t **pnewsec = NULL; + int *pnewcnt = NULL; + int is_pseudo; + + + if (ancexi->exi_visible == NULL || ancpseudo == NULL) + return; + + is_pseudo = PSEUDO(ancexi); + + /* + * Prepare to set newexi's implicitly allowed flavors by + * inheriting flavors from newexi's pseudnode. + * nxfid : used to find the newexi's pseudonode + * pnewsec: newexi's secinfo array + * pnewcnt: newexi's secinfo count + */ + if (newexi) { + nxfid = &newexi->exi_fid; + pnewsec = &newexi->exi_export.ex_secinfo; + pnewcnt = &newexi->exi_export.ex_seccnt; + } + + /* + * find the pseudonodes which correspond to the ones in ancvis. + */ + for (av = ancpseudo; av != NULL; av = av->vis_next) { + for (v = ancexi->exi_visible; v != NULL; v = v->vis_next) { + + if (EQFID(&av->vis_fid, &v->vis_fid)) { + /* + * It's a match. First check to see if newexi + * needs to get implicitly allowed flavors from + * its pseudonode. + * + * ancpseudo is built [by srv_secinfo_treeclimb] + * such that vis_exported is only set for the + * pseudonode corresponding to newexi's root. + */ + if (nxfid && av->vis_exported && + v->vis_seccnt > 0) { + + srv_secinfo_add(pnewsec, pnewcnt, + v->vis_secinfo, v->vis_seccnt, + is_pseudo); + + nxfid = NULL; + } + + /* + * Apply flavor refs for the new export to + * each of the parexi's pseudonodes + */ + srv_secinfo_add(&v->vis_secinfo, &v->vis_seccnt, + av->vis_secinfo, av->vis_seccnt, is_pseudo); + + break; + } + } + } +} + + +/* + * pseudo_secinfo_remove + * ancexi: ancestor exportinfo + * ancpseudo: linked list of ancestor pseudnodes + * + * Decrement secflavor ref counts in ancestor pseudonodes. + */ +static void +pseudo_secinfo_remove(exportinfo_t *ancexi, exp_visible_t *ancpseudo) +{ + exp_visible_t *av, *v; + if (ancexi->exi_visible == NULL || ancpseudo == NULL) + return; + + /* + * find the pseudonodes which correspond to the ones in ancvis. + */ + for (av = ancpseudo; av != NULL; av = av->vis_next) { + for (v = ancexi->exi_visible; v != NULL; v = v->vis_next) { + if (EQFID(&av->vis_fid, &v->vis_fid)) { + + srv_secinfo_remove(&v->vis_secinfo, + &v->vis_seccnt, av->vis_secinfo, + av->vis_seccnt); + + break; + } + } + } } + + /* - * Upon re-sharing an export node, if there is more than 1 export reference - * to an old flavor (i.e. some of its children shared with this flavor), this - * flavor information needs to be transfered to the new shared node. + * For the reshare case, sec flavor accounting happens in 3 steps: + * 1) propagate addition of new flavor refs up the ancestor tree + * 2) transfer flavor refs of descendants to new/reshared exportdata + * 3) propagate removal of old flavor refs up the ancestor tree + * + * srv_secinfo_exp2exp() implements step 2 of a reshare. At this point, + * the new flavor list has already been propagated up through the + * ancestor tree via srv_secinfo_treeclimb(). * - * Expect at least 1 secinfo entry in the old shared node - olddata. - * Expect both curdata and olddata are not pseudo nodes. + * If there is more than 1 export reference to an old flavor (i.e. some + * of its children shared with this flavor), this flavor information + * needs to be transfered to the new exportdata struct. A flavor in + * the old exportdata has descendant refs when s_refcnt > 1. + * + * Transferring descendant flavor refcnts happens in 2 passes: + * a) flavors used before (oldsecinfo) and after (curdata->ex_secinfo) reshare + * b) flavors used before but not after reshare * * This routine is used under the protection of exported_lock (RW_WRITER). */ void -srv_secinfo_exp2exp(struct exportdata *curdata, struct secinfo *oldsecinfo, - int ocnt) +srv_secinfo_exp2exp(exportdata_t *curdata, secinfo_t *oldsecinfo, int ocnt) { int ccnt, c; /* sec count in current data - curdata */ int o; /* sec count in old data - oldsecinfo */ @@ -470,85 +640,104 @@ srv_secinfo_exp2exp(struct exportdata *curdata, struct secinfo *oldsecinfo, ASSERT(!(curdata->ex_flags & EX_PSEUDO)); /* - * If the oldsecinfo has flavors with more than 1 reference count, - * transfer the information to the curdata. + * If the oldsecinfo has flavors with more than 1 reference count + * and the flavor is specified in the reshare, transfer the flavor + * refs to the new seclist (curdata.ex_secinfo). */ tcnt = ccnt + ocnt; for (o = 0; o < ocnt; o++) { - if (SEC_REF_SELF(&oldsecinfo[o])) { - tcnt--; - } else { + if (SEC_REF_SELF(&oldsecinfo[o])) { + tcnt--; + continue; + } + for (c = 0; c < ccnt; c++) { - if (oldsecinfo[o].s_secinfo.sc_nfsnum == - curdata->ex_secinfo[c].s_secinfo.sc_nfsnum) { + if (oldsecinfo[o].s_secinfo.sc_nfsnum == + curdata->ex_secinfo[c].s_secinfo.sc_nfsnum) { + + /* + * add old reference to the current + * secinfo count + */ + curdata->ex_secinfo[c].s_refcnt += + oldsecinfo[o].s_refcnt; - /* add old reference to the current secinfo count */ - curdata->ex_secinfo[c].s_refcnt += - oldsecinfo[o].s_refcnt; + /* + * Delete the old export flavor + * reference. The initial reference + * was created during srv_secinfo_add, + * and the count is decremented below + * to account for the initial reference. + */ + if (SEC_REF_EXPORTED(&oldsecinfo[o])) + curdata->ex_secinfo[c].s_refcnt--; - /* delete the old export flavor reference */ - if (SEC_REF_EXPORTED(&oldsecinfo[o])) - curdata->ex_secinfo[c].s_refcnt--; + SECREF_TRACE(curdata->ex_path, + "reshare_xfer_common_child_refs", + curdata->ex_secinfo[c].s_secinfo.sc_nfsnum, + curdata->ex_secinfo[c].s_refcnt); - ASSERT(curdata->ex_secinfo[c].s_refcnt >= 0); + ASSERT(curdata->ex_secinfo[c].s_refcnt >= 0); - tcnt--; - break; - } + tcnt--; + break; + } } - } } if (tcnt == ccnt) return; /* no more transfer to do */ /* - * oldsecinfo has flavors refered by its children that are not - * in the current (new) export flavor list. Add these flavors. + * oldsecinfo has flavors referenced by its children that are not + * in the current (new) export flavor list. Add these flavors. */ msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP); /* move current secinfo list data to the new list */ - for (c = 0; c < ccnt; c++) { - bcopy(&curdata->ex_secinfo[c], &msec[c], - sizeof (struct secinfo)); - } + for (c = 0; c < ccnt; c++) + msec[c] = curdata->ex_secinfo[c]; /* * Add the flavor that's not in the new export, but still - * referred by its children. + * referenced by its children. */ mcnt = ccnt; for (o = 0; o < ocnt; o++) { - if (! SEC_REF_SELF(&oldsecinfo[o])) { - for (c = 0; c < ccnt; c++) { - if (oldsecinfo[o].s_secinfo.sc_nfsnum == - curdata->ex_secinfo[c].s_secinfo.sc_nfsnum) - break; - } + if (! SEC_REF_SELF(&oldsecinfo[o])) { + for (c = 0; c < ccnt; c++) { + if (oldsecinfo[o].s_secinfo.sc_nfsnum == + curdata->ex_secinfo[c].s_secinfo.sc_nfsnum) + break; + } - /* - * This is the one. Add it. Decrement the reference count - * by 1 if the flavor is an explicitly shared flavor for - * the oldsecinfo export node. - */ - if (c == ccnt) { - srv_secinfo_copy(&oldsecinfo[o], &msec[mcnt]); - if (SEC_REF_EXPORTED(&oldsecinfo[o])) - msec[mcnt].s_refcnt--; - ASSERT(msec[mcnt].s_refcnt >= 0); - mcnt++; + /* + * This is the one. Add it. Decrement the ref count + * by 1 if the flavor is an explicitly shared flavor + * for the oldsecinfo export node. + */ + if (c == ccnt) { + srv_secinfo_copy(&oldsecinfo[o], &msec[mcnt]); + if (SEC_REF_EXPORTED(&oldsecinfo[o])) + msec[mcnt].s_refcnt--; + + SECREF_TRACE(curdata, + "reshare_xfer_implicit_child_refs", + msec[mcnt].s_secinfo.sc_nfsnum, + msec[mcnt].s_refcnt); + + ASSERT(msec[mcnt].s_refcnt >= 0); + mcnt++; + } } - } } ASSERT(mcnt == tcnt); /* - * Done. Update curdata. - * Free up the existing secinfo list in curdata and - * set the new value. + * Done. Update curdata, free the existing secinfo list in + * curdata and set the new value. */ if (ccnt > 0) kmem_free(curdata->ex_secinfo, ccnt * sizeof (struct secinfo)); @@ -565,7 +754,7 @@ srv_secinfo_exp2exp(struct exportdata *curdata, struct secinfo *oldsecinfo, * This routine is used under the protection of exported_lock (RW_WRITER). */ void -srv_secinfo_exp2pseu(struct exportdata *curdata, struct exportdata *olddata) +srv_secinfo_exp2pseu(exportdata_t *curdata, exportdata_t *olddata) { int ocnt, o; /* sec count in transfer data - trandata */ int tcnt, mcnt; /* total sec count after transfer */ @@ -583,8 +772,8 @@ srv_secinfo_exp2pseu(struct exportdata *curdata, struct exportdata *olddata) tcnt = ocnt; for (o = 0; o < ocnt; o++) { - if (SEC_REF_SELF(&olddata->ex_secinfo[o])) - tcnt--; + if (SEC_REF_SELF(&olddata->ex_secinfo[o])) + tcnt--; } if (tcnt == 0) @@ -594,19 +783,25 @@ srv_secinfo_exp2pseu(struct exportdata *curdata, struct exportdata *olddata) mcnt = 0; for (o = 0; o < ocnt; o++) { - if (! SEC_REF_SELF(&olddata->ex_secinfo[o])) { + if (! SEC_REF_SELF(&olddata->ex_secinfo[o])) { - /* - * Decrement the reference count by 1 if the flavor is - * an explicitly shared flavor for the olddata export node. - */ - srv_secinfo_copy(&olddata->ex_secinfo[o], &msec[mcnt]); - msec[mcnt].s_flags = M_RO; /* for a pseudo node */ - if (SEC_REF_EXPORTED(&olddata->ex_secinfo[o])) - msec[mcnt].s_refcnt--; - ASSERT(msec[mcnt].s_refcnt >= 0); - mcnt++; - } + /* + * Decrement the reference count by 1 if the flavor is + * an explicitly shared flavor for the olddata export + * node. + */ + srv_secinfo_copy(&olddata->ex_secinfo[o], &msec[mcnt]); + msec[mcnt].s_flags = M_RO; + if (SEC_REF_EXPORTED(&olddata->ex_secinfo[o])) + msec[mcnt].s_refcnt--; + + SECREF_TRACE(curdata, "unshare_morph_pseudo", + msec[mcnt].s_secinfo.sc_nfsnum, + msec[mcnt].s_refcnt); + + ASSERT(msec[mcnt].s_refcnt >= 0); + mcnt++; + } } ASSERT(mcnt == tcnt); @@ -619,32 +814,41 @@ srv_secinfo_exp2pseu(struct exportdata *curdata, struct exportdata *olddata) curdata->ex_secinfo = msec; } + /* * For NFS V4. * Add or remove the newly exported or unexported security flavors of the * given exportinfo from its ancestors upto the system root. */ int -srv_secinfo_treeclimb(struct exportinfo *exip, bool_t isadd, - struct secinfo *exsecinfo, int exseccnt) +srv_secinfo_treeclimb(exportinfo_t *exip, secinfo_t *sec, int seccnt, int isadd) { vnode_t *dvp, *vp; fid_t fid; int error = 0; - int exportdir; - struct exportinfo *exi; + int exportdir, set_implicit_flav; + struct exportinfo *exi = NULL; + exp_visible_t *anc_head = NULL, *anc; ASSERT(RW_WRITE_HELD(&exported_lock)); - if (exseccnt == 0) + if (seccnt == 0) return (0); vp = exip->exi_vp; VN_HOLD(vp); exportdir = 1; - for (;;) { + /* + * If flavors are being added and the new export root isn't + * also VROOT, its implicitly allowed flavors are inherited from + * from its pseudonode. + */ + set_implicit_flav = (isadd && !(vp->v_flag & VROOT)) ? 1 : 0; + anc_head = NULL; + anc = NULL; + for (;;) { bzero(&fid, sizeof (fid)); fid.fid_len = MAXFIDSZ; error = vop_fid_pseudo(vp, &fid); @@ -656,32 +860,43 @@ srv_secinfo_treeclimb(struct exportinfo *exip, bool_t isadd, exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp); if (exi != NULL) { - - if (isadd) { - /* - * Add the new security flavors to the - * export entry of the current directory. - */ - srv_secinfo_add(&exi->exi_export, exsecinfo, - exseccnt); - } else { - /* - * Remove the unexported secinfo entries. - */ - srv_secinfo_remove(&exi->exi_export, exsecinfo, - exseccnt); - } + secinfo_t **pxsec = &exi->exi_export.ex_secinfo; + int *pxcnt = &exi->exi_export.ex_seccnt; + + if (isadd) + srv_secinfo_add(pxsec, pxcnt, sec, + seccnt, PSEUDO(exi)); + else + srv_secinfo_remove(pxsec, pxcnt, sec, + seccnt); } } /* - * If at the root of the filesystem, need - * to traverse across the mountpoint - * and continue the climb on the mounted-on - * filesystem. + * If we're at the root of the filesystem: + * - manage pseudnode sec flavors + * - traverse mountpoint and continue treeclimb from the stub */ if (vp->v_flag & VROOT) { + if (exi != NULL) { + if (isadd) { + if (set_implicit_flav) { + pseudo_secinfo_add(exi, + anc_head, exip); + set_implicit_flav = 0; + } else + pseudo_secinfo_add(exi, + anc_head, NULL); + } else + pseudo_secinfo_remove(exi, anc_head); + } + + if (anc_head) { + free_pseudoanc(anc_head); + anc_head = NULL; + } + if (VN_CMP(vp, rootdir)) { /* at system root */ break; @@ -693,6 +908,24 @@ srv_secinfo_treeclimb(struct exportinfo *exip, bool_t isadd, } /* + * Build a temporary list of ancestor pseudonodes leading to + * the ancestor VROOT export. vis_exported identifies the + * pseudonode that corresponds to root of export being + * shared/unshared. + */ + anc = kmem_alloc(sizeof (exp_visible_t), KM_SLEEP); + anc->vis_next = anc_head; + VN_HOLD(vp); + anc->vis_vp = vp; + anc->vis_fid = fid; + anc->vis_ino = 0; + anc->vis_count = 1; + anc->vis_seccnt = seccnt; + anc->vis_secinfo = sec; + anc->vis_exported = exportdir; + anc_head = anc; + + /* * Now, do a ".." to find parent dir of vp. */ error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, CRED()); @@ -713,11 +946,38 @@ srv_secinfo_treeclimb(struct exportinfo *exip, bool_t isadd, } VN_RELE(vp); + + if (anc_head) + free_pseudoanc(anc_head); + return (error); } +/* + * Free a list of visible directories + */ +static void +free_pseudoanc(struct exp_visible *head) +{ + struct exp_visible *visp, *next; + + for (visp = head; visp; visp = next) { + if (visp->vis_vp != NULL) + VN_RELE(visp->vis_vp); + /* + * we don't free vis_secinfo from the temporary pseudonode + * ancestor list because it was never kmem_alloc'd. + * srv_secinfo_treeclimb set it to point to the nodups + * secinfo array (which is a stack var). + */ + next = visp->vis_next; + kmem_free(visp, sizeof (*visp)); + } +} + + void -export_link(struct exportinfo *exi) { +export_link(exportinfo_t *exi) { int exporthash; exporthash = exptablehash(&exi->exi_fsid, &exi->exi_fid); @@ -743,9 +1003,9 @@ nfs_exportinit(void) exi_public = exi_root; exi_root->exi_export.ex_flags = EX_PUBLIC; - exi_root->exi_export.ex_pathlen = 2; /* length of "/" */ + exi_root->exi_export.ex_pathlen = 1; /* length of "/" */ exi_root->exi_export.ex_path = - kmem_alloc(exi_root->exi_export.ex_pathlen, KM_SLEEP); + kmem_alloc(exi_root->exi_export.ex_pathlen + 1, KM_SLEEP); exi_root->exi_export.ex_path[0] = '/'; exi_root->exi_export.ex_path[1] = '\0'; @@ -765,7 +1025,7 @@ nfs_exportinit(void) exi_root->exi_fh.fh_fsid = rootdir->v_vfsp->vfs_fsid; exi_root->exi_fh.fh_xlen = exi_rootfid.fid_len; bcopy(exi_rootfid.fid_data, exi_root->exi_fh.fh_xdata, - exi_rootfid.fid_len); + exi_rootfid.fid_len); exi_root->exi_fh.fh_len = sizeof (exi_root->exi_fh.fh_data); /* @@ -789,7 +1049,7 @@ nfs_exportfini(void) * Deallocate the place holder for the public file handle. */ srv_secinfo_list_free(exi_root->exi_export.ex_secinfo, - exi_root->exi_export.ex_seccnt); + exi_root->exi_export.ex_seccnt); mutex_destroy(&exi_root->exi_lock); kmem_free(exi_root, sizeof (*exi_root)); @@ -844,33 +1104,44 @@ rfs_gsscallback(struct svc_req *req, gss_cred_id_t deleg, void *gss_context, rw_enter(&exported_lock, RW_READER); for (i = 0; i < EXPTABLESIZE; i++) { - exi = exptable[i]; - while (exi) { - if (exi->exi_export.ex_seccnt > 0) { - struct secinfo *secp; - - secp = exi->exi_export.ex_secinfo; - for (j = 0; j < exi->exi_export.ex_seccnt; j++) { - /* - * If there is a map of the triplet - * (mechanism, service, qop) between raw_cred and - * the exported flavor, get the psudo flavor number. - * Also qop should not be NULL, it should be "default" - * or something else. - */ - if ((secp[j].s_secinfo.sc_rpcnum == RPCSEC_GSS) && - (nfs_mech_equal(secp[j].s_secinfo.sc_gss_mech_type, - raw_cred->mechanism)) && - (secp[j].s_secinfo.sc_service == raw_cred->service) && - (raw_cred->qop == secp[j].s_secinfo.sc_qop)) { - *cookie = (void *)(uintptr_t) - secp[j].s_secinfo.sc_nfsnum; - goto done; + exi = exptable[i]; + while (exi) { + if (exi->exi_export.ex_seccnt > 0) { + struct secinfo *secp; + seconfig_t *se; + int seccnt; + + secp = exi->exi_export.ex_secinfo; + seccnt = exi->exi_export.ex_seccnt; + for (j = 0; j < seccnt; j++) { + /* + * If there is a map of the triplet + * (mechanism, service, qop) between + * raw_cred and the exported flavor, + * get the psudo flavor number. + * Also qop should not be NULL, it + * should be "default" or something + * else. + */ + se = &secp[j].s_secinfo; + if ((se->sc_rpcnum == RPCSEC_GSS) && + + (nfs_mech_equal( + se->sc_gss_mech_type, + raw_cred->mechanism)) && + + (se->sc_service == + raw_cred->service) && + (raw_cred->qop == se->sc_qop)) { + + *cookie = (void *)(uintptr_t) + se->sc_nfsnum; + goto done; + } + } } - } + exi = exi->exi_hash; } - exi = exi->exi_hash; - } } done: rw_exit(&exported_lock); @@ -917,7 +1188,7 @@ exportfs(struct exportfs_args *args, model_t model, cred_t *cr) { vnode_t *vp; vnode_t *dvp; - struct exportdata *kex; /* kernel space exportdata */ + struct exportdata *kex; struct exportinfo *exi; struct exportinfo *ex, *prev; fid_t fid; @@ -934,10 +1205,10 @@ exportfs(struct exportfs_args *args, model_t model, cred_t *cr) int allocd_seccnt; STRUCT_HANDLE(exportfs_args, uap); STRUCT_DECL(exportdata, uexi); - struct secinfo suniq[MAX_FLAVORS]; /* no duplicate flavors */ - int32_t suniqcnt; /* ex_seccnt for suniq */ - struct secinfo suniqex[MAX_FLAVORS]; /* no duplicate flavors */ - int32_t suniqcntex; /* ex_seccnt for suniq */ + struct secinfo newsec[MAX_FLAVORS]; + int newcnt; + struct secinfo oldsec[MAX_FLAVORS]; + int oldcnt; int i; STRUCT_SET_HANDLE(uap, model, args); @@ -1024,7 +1295,7 @@ exportfs(struct exportfs_args *args, model_t model, cred_t *cr) exi->exi_vp = vp; exi->exi_count = 1; exi->exi_volatile_dev = (vfssw[vp->v_vfsp->vfs_fstype].vsw_flag & - VSW_VOLATILEDEV) ? 1 : 0; + VSW_VOLATILEDEV) ? 1 : 0; mutex_init(&exi->exi_lock, NULL, MUTEX_DEFAULT, NULL); exi->exi_dvp = dvp; @@ -1063,8 +1334,8 @@ exportfs(struct exportfs_args *args, model_t model, cred_t *cr) if (kex->ex_version != EX_CURRENT_VERSION) { error = EINVAL; cmn_err(CE_WARN, - "NFS: exportfs requires export struct version 2 - got %d\n", - kex->ex_version); + "NFS: exportfs requires export struct version 2 - got %d\n", + kex->ex_version); goto out1; } @@ -1115,7 +1386,7 @@ exportfs(struct exportfs_args *args, model_t model, cred_t *cr) goto out2; } kex->ex_log_buffer = - kmem_alloc(kex->ex_log_bufferlen + 1, KM_SLEEP); + kmem_alloc(kex->ex_log_bufferlen + 1, KM_SLEEP); bcopy(log_buffer, kex->ex_log_buffer, kex->ex_log_bufferlen); kex->ex_log_buffer[kex->ex_log_bufferlen] = '\0'; kmem_free(log_buffer, MAXPATHLEN); @@ -1345,26 +1616,40 @@ exportfs(struct exportfs_args *args, model_t model, cred_t *cr) error = treeclimb_export(exi); /* - * By this time all the kernel memory is allocated and we can - * build a unique flavor list. + * build a unique flavor list from the flavors specified + * in the share cmd. unique means that each flavor only + * appears once in the secinfo list -- no duplicates allowed. */ - suniqcnt = build_seclist_nodups(&exi->exi_export, suniq); + newcnt = build_seclist_nodups(&exi->exi_export, newsec, FALSE); if (!error) - error = srv_secinfo_treeclimb(exi, TRUE, suniq, suniqcnt); + error = srv_secinfo_treeclimb(exi, newsec, newcnt, TRUE); /* * If re-sharing an old export entry, update the secinfo data * depending on if the old entry is a pseudo node or not. */ if (!error && ex != NULL) { - suniqcntex = build_seclist_nodups(&ex->exi_export, suniqex); + oldcnt = build_seclist_nodups(&ex->exi_export, oldsec, FALSE); if (PSEUDO(ex)) { - srv_secinfo_add(&exi->exi_export, suniqex, suniqcntex); + /* + * The dir being shared is a pseudo export root (which + * will be transformed into a real export root). The + * flavor(s) of the new share were propagated to the + * ancestors by srv_secinfo_treeclimb() above. Now + * transfer the implicit flavor refs from the old + * pseudo exprot root to the new (real) export root. + */ + srv_secinfo_add(&exi->exi_export.ex_secinfo, + &exi->exi_export.ex_seccnt, oldsec, oldcnt, TRUE); } else { - srv_secinfo_exp2exp(&exi->exi_export, suniqex, suniqcntex); - error = srv_secinfo_treeclimb(ex, FALSE, suniqex, - suniqcntex); + /* + * First transfer implicit flavor refs to new export. + * Remove old flavor refs last. + */ + srv_secinfo_exp2exp(&exi->exi_export, oldsec, oldcnt); + error = srv_secinfo_treeclimb(ex, oldsec, oldcnt, + FALSE); } } @@ -1372,10 +1657,8 @@ exportfs(struct exportfs_args *args, model_t model, cred_t *cr) goto out7; /* - * If it's a re-export and the old entry has a visible list, - * then transfer its visible list to the new export. - * Note: only VROOT node may have a visible list either - * it is a PSEUDO node or a real export node. + * If it's a re-export and the old entry has a pseudnode list, + * transfer it to the new export. */ if (ex != NULL && (ex->exi_visible != NULL)) { exi->exi_visible = ex->exi_visible; @@ -1402,7 +1685,7 @@ out7: * will fail at the same place in the tree. */ (void) treeclimb_unexport(exi); - (void) srv_secinfo_treeclimb(exi, FALSE, suniq, suniqcnt); + (void) srv_secinfo_treeclimb(exi, newsec, newcnt, FALSE); /* * Unlink and re-link the new and old export in exptable. @@ -1424,7 +1707,7 @@ out5: if (kex->ex_secinfo) { kmem_free(kex->ex_secinfo, - kex->ex_seccnt * sizeof (struct secinfo)); + kex->ex_seccnt * sizeof (struct secinfo)); } out4: @@ -1490,8 +1773,8 @@ unexport(fsid_t *fsid, fid_t *fid, vnode_t *vp) { struct exportinfo *exi = NULL; int error; - struct secinfo suniq[MAX_FLAVORS]; - int32_t suniqcnt; + struct secinfo cursec[MAX_FLAVORS]; + int curcnt; rw_enter(&exported_lock, RW_WRITER); @@ -1520,7 +1803,7 @@ unexport(fsid_t *fsid, fid_t *fid, vnode_t *vp) */ if (exi->exi_visible) { error = pseudo_exportfs(exi->exi_vp, exi->exi_visible, - &exi->exi_export); + &exi->exi_export); if (error) goto done; @@ -1531,9 +1814,9 @@ unexport(fsid_t *fsid, fid_t *fid, vnode_t *vp) goto done; } - suniqcnt = build_seclist_nodups(&exi->exi_export, suniq); + curcnt = build_seclist_nodups(&exi->exi_export, cursec, TRUE); - error = srv_secinfo_treeclimb(exi, FALSE, suniq, suniqcnt); + error = srv_secinfo_treeclimb(exi, cursec, curcnt, FALSE); if (error) goto done; @@ -1829,7 +2112,7 @@ nfs_vptoexi(vnode_t *dvp, vnode_t *vp, cred_t *cr, int *walk, } bool_t -chk_clnt_sec(struct exportinfo *exi, struct svc_req *req) +chk_clnt_sec(exportinfo_t *exi, struct svc_req *req) { int i, nfsflavor; struct secinfo *sp; @@ -1854,7 +2137,7 @@ chk_clnt_sec(struct exportinfo *exi, struct svc_req *req) * Make an fhandle from a vnode */ int -makefh(fhandle_t *fh, vnode_t *vp, struct exportinfo *exi) +makefh(fhandle_t *fh, vnode_t *vp, exportinfo_t *exi) { int error; @@ -1894,16 +2177,16 @@ makefh(fhandle_t *fh, vnode_t *vp, struct exportinfo *exi) * of security flavors sent in the current overloaded filehandle.) */ int -makefh_ol(fhandle_t *fh, struct exportinfo *exi, uint_t sec_index) +makefh_ol(fhandle_t *fh, exportinfo_t *exi, uint_t sec_index) { static int max_cnt = (NFS_FHSIZE/sizeof (int)) - 1; int totalcnt, i, *ipt, cnt; char *c; if (fh == (fhandle_t *)NULL || - exi == (struct exportinfo *)NULL || - sec_index > exi->exi_export.ex_seccnt || - sec_index < 1) + exi == (struct exportinfo *)NULL || + sec_index > exi->exi_export.ex_seccnt || + sec_index < 1) return (EREMOTE); totalcnt = exi->exi_export.ex_seccnt-sec_index+1; @@ -1928,7 +2211,7 @@ makefh_ol(fhandle_t *fh, struct exportinfo *exi, uint_t sec_index) ipt = (int *)(c + sizeof (int32_t)); for (i = 0; i < cnt; i++) { *ipt++ = htonl(exi->exi_export.ex_secinfo[i+sec_index-1]. - s_secinfo.sc_nfsnum); + s_secinfo.sc_nfsnum); } return (0); } @@ -1955,8 +2238,8 @@ makefh3(nfs_fh3 *fh, vnode_t *vp, struct exportinfo *exi) fh->fh3_xlen = exi->exi_fid.fid_len; bcopy(exi->exi_fid.fid_data, fh->fh3_xdata, fh->fh3_xlen); fh->fh3_length = sizeof (fsid_t) - + sizeof (ushort_t) + fh->fh3_len - + sizeof (ushort_t) + fh->fh3_xlen; + + sizeof (ushort_t) + fh->fh3_len + + sizeof (ushort_t) + fh->fh3_xlen; fh->fh3_flags = 0; return (0); } @@ -1988,12 +2271,13 @@ makefh3_ol(nfs_fh3 *fh, struct exportinfo *exi, uint_t sec_index) { static int max_cnt = NFS3_FHSIZE/sizeof (int) - 1; int totalcnt, cnt, *ipt, i; + secinfo_t *sec = exi->exi_export.ex_secinfo; char *c; if (fh == (nfs_fh3 *)NULL || - exi == (struct exportinfo *)NULL || - sec_index > exi->exi_export.ex_seccnt || - sec_index < 1) { + exi == (struct exportinfo *)NULL || + sec_index > exi->exi_export.ex_seccnt || + sec_index < 1) { return (EREMOTE); } @@ -2019,8 +2303,7 @@ makefh3_ol(nfs_fh3 *fh, struct exportinfo *exi, uint_t sec_index) */ ipt = (int *)(c + sizeof (int32_t)); for (i = 0; i < cnt; i++) { - *(ipt+i) = htonl( - exi->exi_export.ex_secinfo[i+sec_index-1].s_secinfo.sc_nfsnum); + *(ipt+i) = htonl(sec[i+sec_index-1].s_secinfo.sc_nfsnum); } return (0); } @@ -2053,7 +2336,7 @@ makefh4(nfs_fh4 *fh, vnode_t *vp, struct exportinfo *exi) bzero(fh_fmtp->fh4_i.fhx_data, sizeof (fh_fmtp->fh4_i.fhx_data)); bzero(fh_fmtp->fh4_i.fhx_xdata, sizeof (fh_fmtp->fh4_i.fhx_xdata)); bcopy(exi->exi_fh.fh_xdata, fh_fmtp->fh4_i.fhx_xdata, - exi->exi_fh.fh_xlen); + exi->exi_fh.fh_xlen); fh_fmtp->fh4_len = fid.fid_len; ASSERT(fid.fid_len <= sizeof (fh_fmtp->fh4_data)); @@ -2102,11 +2385,11 @@ nfs_fhtovp(fhandle_t *fh, struct exportinfo *exi) fid_t *fidp; TRACE_0(TR_FAC_NFS, TR_FHTOVP_START, - "fhtovp_start"); + "fhtovp_start"); if (exi == NULL) { TRACE_1(TR_FAC_NFS, TR_FHTOVP_END, - "fhtovp_end:(%S)", "exi NULL"); + "fhtovp_end:(%S)", "exi NULL"); return (NULL); /* not exported */ } @@ -2115,7 +2398,7 @@ nfs_fhtovp(fhandle_t *fh, struct exportinfo *exi) if (PUBLIC_FH2(fh)) { if (exi->exi_export.ex_flags & EX_PUBLIC) { TRACE_1(TR_FAC_NFS, TR_FHTOVP_END, - "fhtovp_end:(%S)", "root not exported"); + "fhtovp_end:(%S)", "root not exported"); return (NULL); } vp = exi->exi_vp; @@ -2130,11 +2413,11 @@ nfs_fhtovp(fhandle_t *fh, struct exportinfo *exi) error = VFS_VGET(vfsp, &vp, fidp); if (error || vp == NULL) { TRACE_1(TR_FAC_NFS, TR_FHTOVP_END, - "fhtovp_end:(%S)", "VFS_GET failed or vp NULL"); + "fhtovp_end:(%S)", "VFS_GET failed or vp NULL"); return (NULL); } TRACE_1(TR_FAC_NFS, TR_FHTOVP_END, - "fhtovp_end:(%S)", "end"); + "fhtovp_end:(%S)", "end"); return (vp); } @@ -2531,7 +2814,7 @@ find_volrnm_fh_id(struct exportinfo *exi, nfs_fh4 *fh4p) mutex_enter(&exi->exi_vol_rename_lock); p = find_volrnm_fh(exi, fh4p); volatile_id = (p ? p->vrn_fh_fmt.fh4_volatile_id : - exi->exi_volatile_id); + exi->exi_volatile_id); mutex_exit(&exi->exi_vol_rename_lock); return (volatile_id); } diff --git a/usr/src/uts/common/nfs/export.h b/usr/src/uts/common/nfs/export.h index e3e39334e4..ccb43683b4 100644 --- a/usr/src/uts/common/nfs/export.h +++ b/usr/src/uts/common/nfs/export.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -317,6 +317,10 @@ struct exportinfo { #endif /* VOLATILE_FH_TEST */ }; +typedef struct exportinfo exportinfo_t; +typedef struct exportdata exportdata_t; +typedef struct secinfo secinfo_t; + /* * exp_visible is a visible list per filesystem. It is for filesystems * that may need a limited view of its contents. A pseudo export and @@ -343,7 +347,10 @@ struct exp_visible { int vis_count; int vis_exported; struct exp_visible *vis_next; + struct secinfo *vis_secinfo; + int vis_seccnt; }; +typedef struct exp_visible exp_visible_t; #define PSEUDO(exi) ((exi)->exi_export.ex_flags & EX_PSEUDO) @@ -418,6 +425,7 @@ extern int nfs4_vget_pseudo(struct exportinfo *, vnode_t **, fid_t *); * information. */ extern void srv_secinfo_exp2pseu(struct exportdata *, struct exportdata *); +extern void srv_secinfo_list_free(struct secinfo *, int); /* * "public" and default (root) location for public filehandle |