Mercurial > illumos > illumos-gate
changeset 12679:30c794f87c0d
6930814 share/unshare issues
6931194 exportfs() uses exportinfo_t after dropping exported_lock and without doing exi_count++
6836258 exportinfo 16-way hash is too small
6953045 Put implementation of the Pearson's hashing algorithm into a separate file
author | Pavel Filipensky <Pavel.Filipensky@Sun.COM> |
---|---|
date | Wed, 23 Jun 2010 15:54:15 +0200 |
parents | 79fad257c978 |
children | 84a6540d6278 |
files | usr/src/lib/libshare/common/libshare.c usr/src/lib/libshare/common/libshare.h usr/src/lib/libshare/nfs/libshare_nfs.c usr/src/pkg/manifests/system-header.mf usr/src/uts/common/Makefile.files usr/src/uts/common/fs/nfs/nfs4_idmap.c usr/src/uts/common/fs/nfs/nfs4_srv_ns.c usr/src/uts/common/fs/nfs/nfs_auth.c usr/src/uts/common/fs/nfs/nfs_export.c usr/src/uts/common/fs/pkp_hash.c usr/src/uts/common/fs/sharefs/sharetab.c usr/src/uts/common/nfs/export.h usr/src/uts/common/nfs/nfs4_idmap_impl.h usr/src/uts/common/sharefs/sharetab.h usr/src/uts/common/sys/Makefile usr/src/uts/common/sys/pkp_hash.h |
diffstat | 16 files changed, 320 insertions(+), 405 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/lib/libshare/common/libshare.c Wed Jun 23 10:37:46 2010 +0100 +++ b/usr/src/lib/libshare/common/libshare.c Wed Jun 23 15:54:15 2010 +0200 @@ -221,6 +221,9 @@ case SA_PASSWORD_ENC: ret = dgettext(TEXT_DOMAIN, "passwords must be encrypted"); break; + case SA_SHARE_EXISTS: + ret = dgettext(TEXT_DOMAIN, "path or file is already shared"); + break; default: (void) snprintf(errstr, sizeof (errstr), dgettext(TEXT_DOMAIN, "unknown %d"), err);
--- a/usr/src/lib/libshare/common/libshare.h Wed Jun 23 10:37:46 2010 +0100 +++ b/usr/src/lib/libshare/common/libshare.h Wed Jun 23 15:54:15 2010 +0200 @@ -87,6 +87,7 @@ #define SA_NO_SUCH_SECTION 30 /* no section found */ #define SA_NO_PROPERTIES 31 /* no properties found */ #define SA_PASSWORD_ENC 32 /* passwords must be encrypted */ +#define SA_SHARE_EXISTS 33 /* path or file is already shared */ /* API Initialization */ #define SA_INIT_SHARE_API 0x0001 /* init share specific interface */
--- a/usr/src/lib/libshare/nfs/libshare_nfs.c Wed Jun 23 10:37:46 2010 +0100 +++ b/usr/src/lib/libshare/nfs/libshare_nfs.c Wed Jun 23 15:54:15 2010 +0200 @@ -20,8 +20,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -1952,7 +1951,10 @@ break; } err = SA_NO_PERMISSION; - /* FALLTHROUGH */ + break; + case EEXIST: + err = SA_SHARE_EXISTS; + break; default: break; }
--- a/usr/src/pkg/manifests/system-header.mf Wed Jun 23 10:37:46 2010 +0100 +++ b/usr/src/pkg/manifests/system-header.mf Wed Jun 23 15:54:15 2010 +0200 @@ -1283,6 +1283,7 @@ file path=usr/include/sys/physmem.h $(i386_ONLY)file path=usr/include/sys/pic.h $(i386_ONLY)file path=usr/include/sys/pit.h +file path=usr/include/sys/pkp_hash.h file path=usr/include/sys/pm.h $(i386_ONLY)file path=usr/include/sys/pmem.h file path=usr/include/sys/policy.h
--- a/usr/src/uts/common/Makefile.files Wed Jun 23 10:37:46 2010 +0100 +++ b/usr/src/uts/common/Makefile.files Wed Jun 23 15:54:15 2010 +0200 @@ -255,6 +255,7 @@ pgrp.o \ pgrpsys.o \ pid.o \ + pkp_hash.o \ policy.o \ poll.o \ pool.o \
--- a/usr/src/uts/common/fs/nfs/nfs4_idmap.c Wed Jun 23 10:37:46 2010 +0100 +++ b/usr/src/uts/common/fs/nfs/nfs4_idmap.c Wed Jun 23 15:54:15 2010 +0200 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. */ @@ -124,6 +123,7 @@ #include <sys/sunddi.h> #include <sys/dnlc.h> #include <sys/sdt.h> +#include <sys/pkp_hash.h> #include <nfs/nfs4.h> #include <nfs/rnode4.h> #include <nfs/nfsid_map.h> @@ -137,7 +137,6 @@ static list_t nfsidmap_globals_list; static kmutex_t nfsidmap_globals_lock; static kmem_cache_t *nfsidmap_cache; -static uint_t pkp_tab[NFSID_CACHE_ANCHORS]; static int nfs4_idcache_tout; /* @@ -147,31 +146,11 @@ #define _CACHE_TOUT (60*60) /* secs in 1 hour */ #define TIMEOUT(x) (gethrestime_sec() > \ ((x) + nfs4_idcache_tout)) - /* * Max length of valid id string including the trailing null */ #define _MAXIDSTRLEN 11 -/* - * Pearson's string hash - * - * See: Communications of the ACM, June 1990 Vol 33 pp 677-680 - * http://www.acm.org/pubs/citations/journals/cacm/1990-33-6/p677-pearson - */ -#define PS_HASH(msg, hash, len) \ -{ \ - uint_t key = 0x12345678; /* arbitrary value */ \ - int i; \ - \ - (hash) = MOD2((key + (len)), NFSID_CACHE_ANCHORS); \ - \ - for (i = 0; i < (len); i++) { \ - (hash) = MOD2(((hash) + (msg)[i]), NFSID_CACHE_ANCHORS); \ - (hash) = pkp_tab[(hash)]; \ - } \ -} - #define ID_HASH(id, hash) \ { \ (hash) = MOD2(((id) ^ NFSID_CACHE_ANCHORS), NFSID_CACHE_ANCHORS); \ @@ -185,7 +164,6 @@ static void nfs_idmap_fini_zone(zoneid_t, void *); static int is_stringified_id(utf8string *); -static void init_pkp_tab(void); static void nfs_idmap_i2s_literal(uid_t, utf8string *); static int nfs_idmap_s2i_literal(utf8string *, uid_t *, int); static void nfs_idmap_reclaim(void *); @@ -215,10 +193,6 @@ nfs_idmap_init(void) { /* - * Initialize Pearson's Table - */ - init_pkp_tab(); - /* * Initialize the kmem cache */ nfsidmap_cache = kmem_cache_create("NFS_idmap_cache", @@ -1303,7 +1277,6 @@ nfsidmap_t *p; nfsidmap_t *pnext; nfsidhq_t *hq; - uint_t hash; char *rqst_c_str; uint_t rqst_len; uint_t found_stat = 0; @@ -1318,9 +1291,8 @@ /* * Compute hash queue */ - PS_HASH(rqst_c_str, hash, rqst_len - 1); - *hashno = hash; - hq = &cip->table[hash]; + *hashno = pkp_tab_hash(rqst_c_str, rqst_len - 1); + hq = &cip->table[*hashno]; /* * Look for the entry in the HQ @@ -1407,7 +1379,7 @@ case HQ_HASH_FIND: default: - PS_HASH(c_str, hashno, c_len - 1); + hashno = pkp_tab_hash(c_str, c_len - 1); break; } hq = &cip->table[hashno]; @@ -1704,33 +1676,6 @@ /* -- Utility functions -- */ -/* - * Initialize table in pseudo-random fashion - * for use in Pearson's string hash algorithm. - * - * See: Communications of the ACM, June 1990 Vol 33 pp 677-680 - * http://www.acm.org/pubs/citations/journals/cacm/1990-33-6/p677-pearson - */ -static void -init_pkp_tab(void) -{ - int i; - int j; - int k = 7; - uint_t s; - - for (i = 0; i < NFSID_CACHE_ANCHORS; i++) - pkp_tab[i] = i; - - for (j = 0; j < 4; j++) - for (i = 0; i < NFSID_CACHE_ANCHORS; i++) { - s = pkp_tab[i]; - k = MOD2((k + s), NFSID_CACHE_ANCHORS); - pkp_tab[i] = pkp_tab[k]; - pkp_tab[k] = s; - } -} - char * utf8_strchr(utf8string *u8s, const char c) {
--- a/usr/src/uts/common/fs/nfs/nfs4_srv_ns.c Wed Jun 23 10:37:46 2010 +0100 +++ b/usr/src/uts/common/fs/nfs/nfs4_srv_ns.c Wed Jun 23 15:54:15 2010 +0200 @@ -137,38 +137,21 @@ * 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, - struct exportdata *exdata, struct exportinfo **exi_retp) +struct exportinfo * +pseudo_exportfs(vnode_t *vp, fid_t *fid, struct exp_visible *vis_head, + struct exportdata *exdata) { struct exportinfo *exi; struct exportdata *kex; - fid_t fid; fsid_t fsid; - int error, vpathlen; + int vpathlen; ASSERT(RW_WRITE_HELD(&exported_lock)); - /* - * Get the vfs id - */ - bzero(&fid, sizeof (fid)); - fid.fid_len = MAXFIDSZ; - error = vop_fid_pseudo(vp, &fid); - if (error) { - /* - * If VOP_FID returns ENOSPC then the fid supplied - * is too small. For now we simply return EREMOTE. - */ - if (error == ENOSPC) - error = EREMOTE; - return (error); - } - fsid = vp->v_vfsp->vfs_fsid; exi = kmem_zalloc(sizeof (*exi), KM_SLEEP); exi->exi_fsid = fsid; - exi->exi_fid = fid; + exi->exi_fid = *fid; exi->exi_vp = vp; VN_HOLD(exi->exi_vp); exi->exi_visible = vis_head; @@ -212,14 +195,7 @@ */ export_link(exi); - /* - * If exi_retp is non-NULL return a pointer to the new - * exportinfo structure. - */ - if (exi_retp) - *exi_retp = exi; - - return (0); + return (exi); } /* @@ -339,7 +315,7 @@ * share /x/y/a/b * * When more_visible() is called during the second share, - * the existing namespace is folowing: + * the existing namespace is following: * exp_visible_t * treenode_t exportinfo_t v0 v1 * ns_root+---+ +------------+ +---+ +---+ @@ -381,7 +357,7 @@ * - add t4, t5, t6 as a child of t1 (t4 will become sibling of t2) * - add v3 to the end of E0->exi_visible * - * Note that v4 and v5 were already proccesed in pseudo_exportfs() and + * Note that v4 and v5 were already processed in pseudo_exportfs() and * added to E2. The outer loop of more_visible() will loop only over v2 * and v3. The inner loop of more_visible() always loops over v0 and v1. * @@ -681,10 +657,8 @@ * this as a pseudo export so that an NFS v4 * client can do lookups in it. */ - error = pseudo_exportfs(vp, vis_head, NULL, - &new_exi); - if (error) - break; + new_exi = pseudo_exportfs(vp, &fid, vis_head, + NULL); vis_head = NULL; } @@ -765,9 +739,8 @@ /* * We can have set error due to error in: * 1. vop_fid_pseudo() - * 2. pseudo_exportfs() which can fail only in vop_fid_pseudo() - * 3. VOP_GETATTR() - * 4. VOP_LOOKUP() + * 2. VOP_GETATTR() + * 3. VOP_LOOKUP() * We must free pseudo exportinfos, visibles and treenodes. * Visibles are referenced from treenode_t::tree_vis and * exportinfo_t::exi_visible. To avoid double freeing, only @@ -787,8 +760,7 @@ exportinfo_t *e = tree_head->tree_exi; /* exip will be freed in exportfs() */ if (e && e != exip) { - (void) export_unlink(&e->exi_fsid, &e->exi_fid, - e->exi_vp, NULL); + export_unlink(e); exi_rele(e); } tree_head = tree_head->tree_child_first; @@ -814,7 +786,6 @@ void treeclimb_unexport(struct exportinfo *exip) { - struct exportinfo *exi; treenode_t *tnode, *old_nd; ASSERT(RW_WRITE_HELD(&exported_lock)); @@ -839,17 +810,13 @@ /* Release pseudo export if it has no child */ if (TREE_ROOT(tnode) && !TREE_EXPORTED(tnode) && tnode->tree_child_first == 0) { - exi = tnode->tree_exi; - (void) export_unlink(&exi->exi_fsid, &exi->exi_fid, - exi->exi_vp, NULL); + export_unlink(tnode->tree_exi); exi_rele(tnode->tree_exi); } /* Release visible in parent's exportinfo */ - if (tnode->tree_vis) { - exi = vis2exi(tnode); - less_visible(exi, tnode->tree_vis); - } + if (tnode->tree_vis) + less_visible(vis2exi(tnode), tnode->tree_vis); /* Continue with parent */ old_nd = tnode;
--- a/usr/src/uts/common/fs/nfs/nfs_auth.c Wed Jun 23 10:37:46 2010 +0100 +++ b/usr/src/uts/common/fs/nfs/nfs_auth.c Wed Jun 23 15:54:15 2010 +0200 @@ -1145,7 +1145,7 @@ rw_enter(&exported_lock, RW_READER); for (i = 0; i < EXPTABLESIZE; i++) { - for (exi = exptable[i]; exi; exi = exi->exi_hash) { + for (exi = exptable[i]; exi; exi = exi->fid_hash.next) { exi_cache_trim(exi); } }
--- a/usr/src/uts/common/fs/nfs/nfs_export.c Wed Jun 23 10:37:46 2010 +0100 +++ b/usr/src/uts/common/fs/nfs/nfs_export.c Wed Jun 23 15:54:15 2010 +0200 @@ -62,12 +62,14 @@ #include <nfs/nfs_log.h> #include <nfs/lm.h> #include <sys/sunddi.h> +#include <sys/pkp_hash.h> treenode_t *ns_root; +struct exportinfo *exptable_path_hash[PKP_HASH_SIZE]; struct exportinfo *exptable[EXPTABLESIZE]; -static int unexport(fsid_t *, fid_t *, vnode_t *); +static int unexport(exportinfo_t *); static void exportfree(exportinfo_t *); static int loadindex(exportdata_t *); @@ -112,61 +114,36 @@ #define exptablehash(fsid, fid) (nfs_fhhash((fsid), (fid)) & (EXPTABLESIZE - 1)) +static uint8_t +xor_hash(uint8_t *data, int len) +{ + uint8_t h = 0; + + while (len--) + h ^= *data++; + + return (h); +} + /* - * File handle hash function, good for producing hash values 16 bits wide. + * File handle hash function, XOR over all bytes in fsid and fid. */ -int +static unsigned nfs_fhhash(fsid_t *fsid, fid_t *fid) { - short *data; - int i, len; - short h; - - ASSERT(fid != NULL); - - data = (short *)fid->fid_data; - - /* fid_data must be aligned on a short */ - ASSERT((((uintptr_t)data) & (sizeof (short) - 1)) == 0); + int len; + uint8_t h; - if (fid->fid_len == 10) { - /* - * probably ufs: hash on bytes 4,5 and 8,9 - */ - return (fsid->val[0] ^ data[2] ^ data[4]); - } - - if (fid->fid_len == 6) { - /* - * probably hsfs: hash on bytes 0,1 and 4,5 - */ - return ((fsid->val[0] ^ data[0] ^ data[2])); - } - - /* - * Some other file system. Assume that every byte is - * worth hashing. - */ - h = (short)fsid->val[0]; + h = xor_hash((uint8_t *)fsid, sizeof (fsid_t)); /* * Sanity check the length before using it * blindly in case the client trashed it. */ - if (fid->fid_len > NFS_FHMAXDATA) - len = 0; - else - len = fid->fid_len / sizeof (short); + len = fid->fid_len > NFS_FH4MAXDATA ? 0 : fid->fid_len; + h ^= xor_hash((uint8_t *)fid->fid_data, len); - /* - * This will ignore one byte if len is not a multiple of - * of sizeof (short). No big deal since we at least get some - * variation with fsid->val[0]; - */ - for (i = 0; i < len; i++) - h ^= data[i]; - - return ((int)h); + return ((unsigned)h); } /* @@ -189,7 +166,6 @@ sizeof (rpc_gss_OID_desc)); secp->s_secinfo.sc_gss_mech_type = NULL; } - } /* @@ -783,13 +759,35 @@ } } -void -export_link(exportinfo_t *exi) { - int exporthash; +/* hash_name is a text substitution for either fid_hash or path_hash */ +#define exp_hash_unlink(exi, hash_name) \ + if (*(exi)->hash_name.bckt == (exi)) \ + *(exi)->hash_name.bckt = (exi)->hash_name.next; \ + if ((exi)->hash_name.prev) \ + (exi)->hash_name.prev->hash_name.next = (exi)->hash_name.next; \ + if ((exi)->hash_name.next) \ + (exi)->hash_name.next->hash_name.prev = (exi)->hash_name.prev; \ + (exi)->hash_name.bckt = NULL; - exporthash = exptablehash(&exi->exi_fsid, &exi->exi_fid); - exi->exi_hash = exptable[exporthash]; - exptable[exporthash] = exi; +#define exp_hash_link(exi, hash_name, bucket) \ + (exi)->hash_name.bckt = (bucket); \ + (exi)->hash_name.prev = NULL; \ + (exi)->hash_name.next = *(bucket); \ + if ((exi)->hash_name.next) \ + (exi)->hash_name.next->hash_name.prev = (exi); \ + *(bucket) = (exi); + +void +export_link(exportinfo_t *exi) +{ + exportinfo_t **bckt; + + bckt = &exptable[exptablehash(&exi->exi_fsid, &exi->exi_fid)]; + exp_hash_link(exi, fid_hash, bckt); + + bckt = &exptable_path_hash[pkp_tab_hash(exi->exi_export.ex_path, + strlen(exi->exi_export.ex_path))]; + exp_hash_link(exi, path_hash, bckt); } /* @@ -948,7 +946,7 @@ } } } - exi = exi->exi_hash; + exi = exi->fid_hash.next; } } done: @@ -998,7 +996,7 @@ vnode_t *dvp; struct exportdata *kex; struct exportinfo *exi = NULL; - struct exportinfo *ex, *prev; + struct exportinfo *ex, *ex1, *ex2; fid_t fid; fsid_t fsid; int error; @@ -1018,9 +1016,39 @@ struct secinfo oldsec[MAX_FLAVORS]; int oldcnt; int i; + struct pathname lookpn; STRUCT_SET_HANDLE(uap, model, args); + /* Read in pathname from userspace */ + if (error = pn_get(STRUCT_FGETP(uap, dname), UIO_USERSPACE, &lookpn)) + return (error); + + /* Walk the export list looking for that pathname */ + rw_enter(&exported_lock, RW_READER); + DTRACE_PROBE(nfss__i__exported_lock1_start); + for (ex1 = exptable_path_hash[pkp_tab_hash(lookpn.pn_path, + strlen(lookpn.pn_path))]; ex1; ex1 = ex1->path_hash.next) { + if (ex1 != exi_root && 0 == + strcmp(ex1->exi_export.ex_path, lookpn.pn_path)) { + exi_hold(ex1); + break; + } + } + DTRACE_PROBE(nfss__i__exported_lock1_stop); + rw_exit(&exported_lock); + + /* Is this an unshare? */ + if (STRUCT_FGETP(uap, uex) == NULL) { + pn_free(&lookpn); + if (ex1 == NULL) + return (EINVAL); + error = unexport(ex1); + exi_rele(ex1); + return (error); + } + + /* It is a share or a re-share */ error = lookupname(STRUCT_FGETP(uap, dname), UIO_USERSPACE, FOLLOW, &dvp, &vp); if (error == EINVAL) { @@ -1034,87 +1062,18 @@ dvp = NULL; } if (!error && vp == NULL) { - /* - * Last component of fname not found - */ - if (dvp != NULL) { + /* Last component of fname not found */ + if (dvp != NULL) VN_RELE(dvp); - } error = ENOENT; } - if (error) { - /* - * If this is a request to unexport, indicated by the - * uex pointer being NULL, it is possible that the - * directory has already been removed or shared filesystem - * could have been forcibly unmounted. In which case - * we scan the export list which records the pathname - * originally exported. - */ - if (STRUCT_FGETP(uap, uex) == NULL) { - char namebuf[TYPICALMAXPATHLEN]; - struct pathname lookpn; - int i; - - /* Read in pathname from userspace */ - error = pn_get_buf(STRUCT_FGETP(uap, dname), - UIO_USERSPACE, &lookpn, namebuf, sizeof (namebuf)); - if (error == ENAMETOOLONG) { - /* - * pathname > TYPICALMAXPATHLEN, use - * pn_get() instead. Remember to - * pn_free() afterwards. - */ - error = pn_get(STRUCT_FGETP(uap, dname), - UIO_USERSPACE, &lookpn); - } - - if (error) - return (error); - - /* Walk the export list looking for that pathname */ - rw_enter(&exported_lock, RW_READER); - for (i = 0; i < EXPTABLESIZE; i++) { - exi = exptable[i]; - while (exi) { - if (strcmp(exi->exi_export.ex_path, - lookpn.pn_path) == 0) { - goto exi_scan_end; - } - exi = exi->exi_hash; - } - } -exi_scan_end: - rw_exit(&exported_lock); - if (exi) { - /* Found a match, use it. */ - vp = exi->exi_vp; - dvp = exi->exi_dvp; - DTRACE_PROBE2(nfss__i__nmspc__tree, - char *, - "unsharing removed dir/unmounted fs", - char *, lookpn.pn_path); - VN_HOLD(vp); - VN_HOLD(dvp); - error = 0; - } else { - /* Still no match, set error */ - error = ENOENT; - } - if (lookpn.pn_buf != namebuf) { - /* - * We didn't use namebuf, so make - * sure we free the allocated memory - */ - pn_free(&lookpn); - } - } + pn_free(&lookpn); + if (ex1) + exi_rele(ex1); + return (error); } - if (error) - return (error); - /* * 'vp' may be an AUTOFS node, so we perform a * VOP_ACCESS() to trigger the mount of the @@ -1135,10 +1094,22 @@ VN_RELE(vp); if (dvp != NULL) VN_RELE(dvp); + pn_free(&lookpn); + if (ex1) + exi_rele(ex1); return (error); } } + /* Do not allow sharing another vnode for already shared path */ + if (ex1 && !PSEUDO(ex1) && !VN_CMP(ex1->exi_vp, vp)) { + pn_free(&lookpn); + exi_rele(ex1); + return (EEXIST); + } + if (ex1) + exi_rele(ex1); + /* * Get the vfs id */ @@ -1147,13 +1118,7 @@ error = VOP_FID(vp, &fid, NULL); fsid = vp->v_vfsp->vfs_fsid; - /* - * Allow unshare request for forcibly unmounted shared filesystem. - */ - if (error == EIO && exi) { - fid = exi->exi_fid; - fsid = exi->exi_fsid; - } else if (error) { + if (error) { VN_RELE(vp); if (dvp != NULL) VN_RELE(dvp); @@ -1163,16 +1128,30 @@ */ if (error == ENOSPC) error = EREMOTE; + pn_free(&lookpn); return (error); } - if (STRUCT_FGETP(uap, uex) == NULL) { - error = unexport(&fsid, &fid, vp); - VN_RELE(vp); - if (dvp != NULL) - VN_RELE(dvp); - return (error); + /* + * Do not allow re-sharing a shared vnode under a different path + * PSEUDO export has ex_path fabricated, e.g. "/tmp (pseudo)", skip it. + */ + rw_enter(&exported_lock, RW_READER); + DTRACE_PROBE(nfss__i__exported_lock2_start); + for (ex2 = exptable[exptablehash(&fsid, &fid)]; ex2; + ex2 = ex2->fid_hash.next) { + if (ex2 != exi_root && !PSEUDO(ex2) && + VN_CMP(ex2->exi_vp, vp) && + strcmp(ex2->exi_export.ex_path, lookpn.pn_path) != 0) { + DTRACE_PROBE(nfss__i__exported_lock2_stop); + rw_exit(&exported_lock); + pn_free(&lookpn); + return (EEXIST); + } } + DTRACE_PROBE(nfss__i__exported_lock2_stop); + rw_exit(&exported_lock); + pn_free(&lookpn); exi = kmem_zalloc(sizeof (*exi), KM_SLEEP); exi->exi_fsid = fsid; @@ -1447,6 +1426,7 @@ * Insert the new entry at the front of the export list */ rw_enter(&exported_lock, RW_WRITER); + DTRACE_PROBE(nfss__i__exported_lock3_start); export_link(exi); @@ -1455,10 +1435,9 @@ * If one is found then unlink it, wait until this is the * only reference and then free it. */ - prev = exi; - for (ex = prev->exi_hash; ex != NULL; prev = ex, ex = ex->exi_hash) { + for (ex = exi->fid_hash.next; ex != NULL; ex = ex->fid_hash.next) { if (ex != exi_root && VN_CMP(ex->exi_vp, vp)) { - prev->exi_hash = ex->exi_hash; + export_unlink(ex); break; } } @@ -1553,6 +1532,7 @@ ex->exi_visible = NULL; } + DTRACE_PROBE(nfss__i__exported_lock3_stop); rw_exit(&exported_lock); if (exi_public == exi || kex->ex_flags & EX_LOG) { @@ -1569,7 +1549,8 @@ out7: /* Unlink the new export in exptable. */ - (void) export_unlink(&exi->exi_fsid, &exi->exi_fid, exi->exi_vp, NULL); + export_unlink(exi); + DTRACE_PROBE(nfss__i__exported_lock3_stop); rw_exit(&exported_lock); out6: if (kex->ex_flags & EX_INDEX) @@ -1607,71 +1588,34 @@ /* * Remove the exportinfo from the export list */ -int -export_unlink(fsid_t *fsid, fid_t *fid, vnode_t *vp, struct exportinfo **exip) +void +export_unlink(struct exportinfo *exi) { - struct exportinfo **tail; - ASSERT(RW_WRITE_HELD(&exported_lock)); - tail = &exptable[exptablehash(fsid, fid)]; - while (*tail != NULL) { - if (exportmatch(*tail, fsid, fid)) { - /* - * If vp is given, check if vp is the - * same vnode as the exported node. - * - * Since VOP_FID of a lofs node returns the - * fid of its real node (ufs), the exported - * node for lofs and (pseudo) ufs may have - * the same fsid and fid. - */ - if (vp == NULL || vp == (*tail)->exi_vp) { - - if (exip != NULL) - *exip = *tail; - *tail = (*tail)->exi_hash; - - return (0); - } - } - tail = &(*tail)->exi_hash; - } - - return (EINVAL); + exp_hash_unlink(exi, fid_hash); + exp_hash_unlink(exi, path_hash); } /* * Unexport an exported filesystem */ -int -unexport(fsid_t *fsid, fid_t *fid, vnode_t *vp) +static int +unexport(struct exportinfo *exi) { - struct exportinfo *exi = NULL; - int error; struct secinfo cursec[MAX_FLAVORS]; int curcnt; rw_enter(&exported_lock, RW_WRITER); - error = export_unlink(fsid, fid, vp, &exi); - - if (error) { - rw_exit(&exported_lock); - return (error); - } - - /* pseudo node is not a real exported filesystem */ - if (PSEUDO(exi)) { - /* - * Put the pseudo node back into the export table - * before erroring out. - */ - export_link(exi); + /* Check if exi is still linked in the export table */ + if (!EXP_LINKED(exi) || PSEUDO(exi)) { rw_exit(&exported_lock); return (EINVAL); } + export_unlink(exi); + /* * Remove security flavors before treeclimb_unexport() is called * because srv_secinfo_treeclimb needs the namespace tree @@ -1688,19 +1632,13 @@ if (exi->exi_visible) { struct exportinfo *newexi; - error = pseudo_exportfs(exi->exi_vp, exi->exi_visible, - &exi->exi_export, &newexi); - if (error) - goto done; + newexi = pseudo_exportfs(exi->exi_vp, &exi->exi_fid, + exi->exi_visible, &exi->exi_export); + exi->exi_visible = NULL; - exi->exi_visible = NULL; - /* - * pseudo_exportfs() has allocated new exportinfo, - * update the treenode. - */ + /* interconnect the existing treenode with the new exportinfo */ newexi->exi_tree = exi->exi_tree; newexi->exi_tree->tree_exi = newexi; - } else { treeclimb_unexport(exi); } @@ -1736,12 +1674,7 @@ } exi_rele(exi); - return (error); - -done: - rw_exit(&exported_lock); - exi_rele(exi); - return (error); + return (0); } /* @@ -2525,7 +2458,7 @@ rw_enter(&exported_lock, RW_READER); for (exi = exptable[exptablehash(fsid, fid)]; exi != NULL; - exi = exi->exi_hash) { + exi = exi->fid_hash.next) { if (exportmatch(exi, fsid, fid)) { /* * If this is the place holder for the @@ -2563,7 +2496,7 @@ for (exi = exptable[exptablehash(fsid, fid)]; exi != NULL; - exi = exi->exi_hash) { + exi = exi->fid_hash.next) { if (exportmatch(exi, fsid, fid)) { /* * If this is the place holder for the
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/fs/pkp_hash.c Wed Jun 23 15:54:15 2010 +0200 @@ -0,0 +1,70 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#include <sys/pkp_hash.h> + +/* + * Pearson's string hash + * + * See: Communications of the ACM, June 1990 Vol 33 pp 677-680 + * http://portal.acm.org/citation.cfm?doid=78973.78978 + */ + +#define MOD2(a, pow_of_2) ((a) & ((pow_of_2) - 1)) + +static uint_t pkp_tab[PKP_HASH_SIZE] = { +1, 87, 49, 12, 176, 178, 102, 166, 121, 193, 6, 84, 249, 230, 44, 163, +14, 197, 213, 181, 161, 85, 218, 80, 64, 239, 24, 226, 236, 142, 38, 200, +110, 177, 104, 103, 141, 253, 255, 50, 77, 101, 81, 18, 45, 96, 31, 222, +25, 107, 190, 70, 86, 237, 240, 34, 72, 242, 20, 214, 244, 227, 149, 235, +97, 234, 57, 22, 60, 250, 82, 175, 208, 5, 127, 199, 111, 62, 135, 248, +174, 169, 211, 58, 66, 154, 106, 195, 245, 171, 17, 187, 182, 179, 0, 243, +132, 56, 148, 75, 128, 133, 158, 100, 130, 126, 91, 13, 153, 246, 216, 219, +119, 68, 223, 78, 83, 88, 201, 99, 122, 11, 92, 32, 136, 114, 52, 10, +138, 30, 48, 183, 156, 35, 61, 26, 143, 74, 251, 94, 129, 162, 63, 152, +170, 7, 115, 167, 241, 206, 3, 150, 55, 59, 151, 220, 90, 53, 23, 131, +125, 173, 15, 238, 79, 95, 89, 16, 105, 137, 225, 224, 217, 160, 37, 123, +118, 73, 2, 157, 46, 116, 9, 145, 134, 228, 207, 212, 202, 215, 69, 229, +27, 188, 67, 124, 168, 252, 42, 4, 29, 108, 21, 247, 19, 205, 39, 203, +233, 40, 186, 147, 198, 192, 155, 33, 164, 191, 98, 204, 165, 180, 117, 76, +140, 36, 210, 172, 41, 54, 159, 8, 185, 232, 113, 196, 231, 47, 146, 120, +51, 65, 28, 144, 254, 221, 93, 189, 194, 139, 112, 43, 71, 109, 184, 209 +}; + +uint_t +pkp_tab_hash(char *str, int len) +{ + uint_t key = 0x12345678; /* arbitrary value */ + uint_t hash; + int i; + + hash = MOD2((key + len), PKP_HASH_SIZE); + + for (i = 0; i < len; i++) { + hash = MOD2((hash + str[i]), PKP_HASH_SIZE); + hash = pkp_tab[hash]; + } + + return (hash); +}
--- a/usr/src/uts/common/fs/sharefs/sharetab.c Wed Jun 23 10:37:46 2010 +0100 +++ b/usr/src/uts/common/fs/sharefs/sharetab.c Wed Jun 23 15:54:15 2010 +0200 @@ -20,12 +20,9 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/types.h> #include <sys/types32.h> #include <sys/param.h> @@ -86,36 +83,6 @@ uint_t sharetab_generation; /* Only increments and wraps! */ -static uint_t pkp_tab[SHARETAB_HASHES]; - -/* - * Initialize table in pseudo-random fashion - * for use in Pearson's string hash algorithm. - * - * See: Communications of the ACM, June 1990 Vol 33 pp 677-680 - * http://www.acm.org/pubs/citations/journals/cacm/1990-33-6/p677-pearson - */ -static void -init_pkp_tab(void) -{ - int i; - int j; - int k = 7; - uint_t s; - - for (i = 0; i < SHARETAB_HASHES; i++) - pkp_tab[i] = i; - - for (j = 0; j < 4; j++) { - for (i = 0; i < SHARETAB_HASHES; i++) { - s = pkp_tab[i]; - k = MOD2((k + s), SHARETAB_HASHES); - pkp_tab[i] = pkp_tab[k]; - pkp_tab[k] = s; - } - } -} - /* * Take care of cleaning up a share. * If passed in a length array, use it to determine how much @@ -168,7 +135,7 @@ } iPath = shl ? shl->shl_path : strlen(sh->sh_path); - SHARETAB_HASH_IT(iHash, sh->sh_path); + iHash = pkp_tab_hash(sh->sh_path, strlen(sh->sh_path)); /* * Now walk down the hash table and find the entry to free! @@ -263,7 +230,7 @@ /* * Now we need to find where we have to add the entry. */ - SHARETAB_HASH_IT(iHash, sh->sh_path); + iHash = pkp_tab_hash(sh->sh_path, strlen(sh->sh_path)); iPath = shl ? shl->shl_path : strlen(sh->sh_path); @@ -347,8 +314,6 @@ void sharefs_sharetab_init(void) { - init_pkp_tab(); - rw_init(&sharetab_lock, NULL, RW_DEFAULT, NULL); rw_init(&sharefs_lock, NULL, RW_DEFAULT, NULL);
--- a/usr/src/uts/common/nfs/export.h Wed Jun 23 10:37:46 2010 +0100 +++ b/usr/src/uts/common/nfs/export.h Wed Jun 23 15:54:15 2010 +0200 @@ -419,7 +419,13 @@ /* Root of nfs pseudo namespace */ extern treenode_t *ns_root; -#define EXPTABLESIZE 16 +#define EXPTABLESIZE 256 + +struct exp_hash { + struct exportinfo *prev; /* ptr to the previous exportinfo */ + struct exportinfo *next; /* ptr to the next exportinfo */ + struct exportinfo **bckt; /* backpointer to the hash bucket */ +}; /* * A node associated with an export entry on the @@ -441,7 +447,8 @@ struct exportdata exi_export; fsid_t exi_fsid; struct fid exi_fid; - struct exportinfo *exi_hash; + struct exp_hash fid_hash; + struct exp_hash path_hash; struct treenode *exi_tree; fhandle_t exi_fh; krwlock_t exi_cache_lock; @@ -505,6 +512,7 @@ typedef struct exp_visible exp_visible_t; #define PSEUDO(exi) ((exi)->exi_export.ex_flags & EX_PSEUDO) +#define EXP_LINKED(exi) ((exi)->fid_hash.bckt != NULL) #define EQFSID(fsidp1, fsidp2) \ (((fsidp1)->val[0] == (fsidp2)->val[0]) && \ @@ -533,7 +541,6 @@ struct svc_req *); extern int nfsauth4_secinfo_access(struct exportinfo *, struct svc_req *, int, int); -extern int nfs_fhhash(fsid_t *, fid_t *); extern int nfs_fhbcmp(char *, char *, int); extern int nfs_exportinit(void); extern void nfs_exportfini(void); @@ -555,8 +562,7 @@ extern int nfs_check_vpexi(vnode_t *, vnode_t *, cred_t *, struct exportinfo **); extern void export_link(struct exportinfo *); -extern int export_unlink(fsid_t *, fid_t *, vnode_t *, - struct exportinfo **); +extern void export_unlink(struct exportinfo *); extern vnode_t *untraverse(vnode_t *); extern int vn_is_nfs_reparse(vnode_t *, cred_t *); extern int client_is_downrev(struct svc_req *); @@ -573,8 +579,8 @@ extern int has_visible(struct exportinfo *, vnode_t *); extern void free_visible(struct exp_visible *); extern int nfs_exported(struct exportinfo *, vnode_t *); -extern int pseudo_exportfs(vnode_t *, struct exp_visible *, - struct exportdata *, struct exportinfo **); +extern struct exportinfo *pseudo_exportfs(vnode_t *, fid_t *, + struct exp_visible *, struct exportdata *); extern int vop_fid_pseudo(vnode_t *, fid_t *fidp); extern int nfs4_vget_pseudo(struct exportinfo *, vnode_t **, fid_t *); /*
--- a/usr/src/uts/common/nfs/nfs4_idmap_impl.h Wed Jun 23 10:37:46 2010 +0100 +++ b/usr/src/uts/common/nfs/nfs4_idmap_impl.h Wed Jun 23 15:54:15 2010 +0200 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,17 +19,15 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _NFS4_IDMAP_IMPL_H #define _NFS4_IDMAP_IMPL_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/list.h> #include <sys/door.h> +#include <sys/pkp_hash.h> /* * This is a private header file. Applications should not directly include @@ -44,7 +41,7 @@ /* * Cache Entry Definitions */ -#define NFSID_CACHE_ANCHORS 256 +#define NFSID_CACHE_ANCHORS PKP_HASH_SIZE typedef struct nfsidmap { struct nfsidmap *id_chain[2]; /* must be first */
--- a/usr/src/uts/common/sharefs/sharetab.h Wed Jun 23 10:37:46 2010 +0100 +++ b/usr/src/uts/common/sharefs/sharetab.h Wed Jun 23 15:54:15 2010 +0200 @@ -18,16 +18,14 @@ * * CDDL HEADER END */ - /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _SHAREFS_SHARETAB_H #define _SHAREFS_SHARETAB_H -#pragma ident "%Z%%M% %I% %E% SMI" +#include <sys/pkp_hash.h> /* * This header defines the glue to keeping a sharetab in memory. @@ -54,7 +52,7 @@ uint_t ssh_count; } sharefs_hash_head_t; -#define SHARETAB_HASHES 256 +#define SHARETAB_HASHES PKP_HASH_SIZE typedef struct sharetab { sharefs_hash_head_t s_buckets[SHARETAB_HASHES]; @@ -63,29 +61,6 @@ uint_t s_count; } sharetab_t; -#define MOD2(a, pow_of_2) (a) & ((pow_of_2) - 1) - -/* - * Pearson's string hash - * - * See: Communications of the ACM, June 1990 Vol 33 pp 677-680 - * http://www.acm.org/pubs/citations/journals/cacm/1990-33-6/p677-pearson - */ -#define SHARETAB_HASH_IT(hash, path) \ -{ \ - uint_t key = 0x12345678; /* arbitrary value */ \ - int i, len; \ - \ - len = strlen((path)); \ - \ - (hash) = MOD2((key + len), SHARETAB_HASHES); \ - \ - for (i = 0; i < len; i++) { \ - (hash) = MOD2(((hash) + (path)[i]), SHARETAB_HASHES); \ - (hash) = pkp_tab[(hash)]; \ - } \ -} - #ifdef __cplusplus } #endif
--- a/usr/src/uts/common/sys/Makefile Wed Jun 23 10:37:46 2010 +0100 +++ b/usr/src/uts/common/sys/Makefile Wed Jun 23 15:54:15 2010 +0200 @@ -431,6 +431,7 @@ pg.h \ pghw.h \ physmem.h \ + pkp_hash.h \ pm.h \ policy.h \ poll.h \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/sys/pkp_hash.h Wed Jun 23 15:54:15 2010 +0200 @@ -0,0 +1,48 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#ifndef _PKP_HASH_H_ +#define _PKP_HASH_H_ + +#include <sys/types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Pearson's string hash + * + * See: Communications of the ACM, June 1990 Vol 33 pp 677-680 + * http://portal.acm.org/citation.cfm?doid=78973.78978 + */ +#define PKP_HASH_SIZE 256 + +extern uint_t pkp_tab_hash(char *, int); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKP_HASH_H_ */