From bfbb13c994c87d0453ca6bb826470ec99a909992 Mon Sep 17 00:00:00 2001 From: jmcp Date: Thu, 10 Jun 2010 16:27:13 -0700 Subject: backout 6930814: causes 6960023 --- usr/src/lib/libshare/common/libshare.c | 3 - usr/src/lib/libshare/common/libshare.h | 1 - usr/src/lib/libshare/nfs/libshare_nfs.c | 8 +- usr/src/pkg/manifests/system-header.mf | 1 - usr/src/uts/common/Makefile.files | 1 - usr/src/uts/common/fs/nfs/nfs4_idmap.c | 65 +++++- usr/src/uts/common/fs/nfs/nfs4_srv_ns.c | 65 ++++-- usr/src/uts/common/fs/nfs/nfs_auth.c | 2 +- usr/src/uts/common/fs/nfs/nfs_export.c | 363 ++++++++++++++++++------------- usr/src/uts/common/fs/pkp_hash.c | 70 ------ usr/src/uts/common/fs/sharefs/sharetab.c | 41 +++- usr/src/uts/common/nfs/export.h | 20 +- usr/src/uts/common/nfs/nfs4_idmap_impl.h | 13 +- usr/src/uts/common/sharefs/sharetab.h | 31 ++- usr/src/uts/common/sys/Makefile | 1 - usr/src/uts/common/sys/pkp_hash.h | 48 ---- 16 files changed, 410 insertions(+), 323 deletions(-) delete mode 100644 usr/src/uts/common/fs/pkp_hash.c delete mode 100644 usr/src/uts/common/sys/pkp_hash.h diff --git a/usr/src/lib/libshare/common/libshare.c b/usr/src/lib/libshare/common/libshare.c index 1d17d5fea7..30c2c486f1 100644 --- a/usr/src/lib/libshare/common/libshare.c +++ b/usr/src/lib/libshare/common/libshare.c @@ -221,9 +221,6 @@ sa_errorstr(int err) 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); diff --git a/usr/src/lib/libshare/common/libshare.h b/usr/src/lib/libshare/common/libshare.h index 283a499a8e..5d32f60e8f 100644 --- a/usr/src/lib/libshare/common/libshare.h +++ b/usr/src/lib/libshare/common/libshare.h @@ -87,7 +87,6 @@ typedef void *sa_handle_t; /* opaque handle to access core functions */ #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 */ diff --git a/usr/src/lib/libshare/nfs/libshare_nfs.c b/usr/src/lib/libshare/nfs/libshare_nfs.c index 3173e47d7f..6a9f7fafba 100644 --- a/usr/src/lib/libshare/nfs/libshare_nfs.c +++ b/usr/src/lib/libshare/nfs/libshare_nfs.c @@ -20,7 +20,8 @@ */ /* - * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ /* @@ -1951,10 +1952,7 @@ nfs_enable_share(sa_share_t share) break; } err = SA_NO_PERMISSION; - break; - case EEXIST: - err = SA_SHARE_EXISTS; - break; + /* FALLTHROUGH */ default: break; } diff --git a/usr/src/pkg/manifests/system-header.mf b/usr/src/pkg/manifests/system-header.mf index 3d72a44f27..25b41f849d 100644 --- a/usr/src/pkg/manifests/system-header.mf +++ b/usr/src/pkg/manifests/system-header.mf @@ -1284,7 +1284,6 @@ file path=usr/include/sys/pghw.h 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 diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files index fd94035afe..d72125bf54 100644 --- a/usr/src/uts/common/Makefile.files +++ b/usr/src/uts/common/Makefile.files @@ -255,7 +255,6 @@ GENUNIX_OBJS += \ pgrp.o \ pgrpsys.o \ pid.o \ - pkp_hash.o \ policy.o \ poll.o \ pool.o \ diff --git a/usr/src/uts/common/fs/nfs/nfs4_idmap.c b/usr/src/uts/common/fs/nfs/nfs4_idmap.c index 35afec00d2..a5f05a5d34 100644 --- a/usr/src/uts/common/fs/nfs/nfs4_idmap.c +++ b/usr/src/uts/common/fs/nfs/nfs4_idmap.c @@ -19,7 +19,8 @@ * CDDL HEADER END */ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ @@ -123,7 +124,6 @@ #include #include #include -#include #include #include #include @@ -137,6 +137,7 @@ zone_key_t nfsidmap_zone_key; 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; /* @@ -146,11 +147,31 @@ static int nfs4_idcache_tout; #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); \ @@ -164,6 +185,7 @@ static void *nfs_idmap_init_zone(zoneid_t); 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 *); @@ -192,6 +214,10 @@ static void nfs_idmap_cache_rment(nfsidmap_t *); void nfs_idmap_init(void) { + /* + * Initialize Pearson's Table + */ + init_pkp_tab(); /* * Initialize the kmem cache */ @@ -1277,6 +1303,7 @@ nfs_idmap_cache_s2i_lkup(idmap_cache_info_t *cip, /* cache info ptr */ 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; @@ -1291,8 +1318,9 @@ nfs_idmap_cache_s2i_lkup(idmap_cache_info_t *cip, /* cache info ptr */ /* * Compute hash queue */ - *hashno = pkp_tab_hash(rqst_c_str, rqst_len - 1); - hq = &cip->table[*hashno]; + PS_HASH(rqst_c_str, hash, rqst_len - 1); + *hashno = hash; + hq = &cip->table[hash]; /* * Look for the entry in the HQ @@ -1379,7 +1407,7 @@ nfs_idmap_cache_s2i_insert(idmap_cache_info_t *cip, /* cache info ptr */ case HQ_HASH_FIND: default: - hashno = pkp_tab_hash(c_str, c_len - 1); + PS_HASH(c_str, hashno, c_len - 1); break; } hq = &cip->table[hashno]; @@ -1676,6 +1704,33 @@ nfs_idmap_i2s_literal(uid_t id, utf8string *u8s) /* -- 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) { 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 8e5aefc829..bc15ca0552 100644 --- a/usr/src/uts/common/fs/nfs/nfs4_srv_ns.c +++ b/usr/src/uts/common/fs/nfs/nfs4_srv_ns.c @@ -137,21 +137,38 @@ nfs4_vget_pseudo(struct exportinfo *exi, vnode_t **vpp, fid_t *fidp) * a) its export root is VROOT * b) a descendant of the export root is shared */ -struct exportinfo * -pseudo_exportfs(vnode_t *vp, fid_t *fid, struct exp_visible *vis_head, - struct exportdata *exdata) +int +pseudo_exportfs(vnode_t *vp, struct exp_visible *vis_head, + struct exportdata *exdata, struct exportinfo **exi_retp) { struct exportinfo *exi; struct exportdata *kex; + fid_t fid; fsid_t fsid; - int vpathlen; + int error, 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; @@ -195,7 +212,14 @@ pseudo_exportfs(vnode_t *vp, fid_t *fid, struct exp_visible *vis_head, */ export_link(exi); - return (exi); + /* + * If exi_retp is non-NULL return a pointer to the new + * exportinfo structure. + */ + if (exi_retp) + *exi_retp = exi; + + return (0); } /* @@ -315,7 +339,7 @@ tree_remove_node(treenode_t *node) * share /x/y/a/b * * When more_visible() is called during the second share, - * the existing namespace is following: + * the existing namespace is folowing: * exp_visible_t * treenode_t exportinfo_t v0 v1 * ns_root+---+ +------------+ +---+ +---+ @@ -357,7 +381,7 @@ tree_remove_node(treenode_t *node) * - 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 processed in pseudo_exportfs() and + * Note that v4 and v5 were already proccesed 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. * @@ -655,8 +679,10 @@ treeclimb_export(struct exportinfo *exip) * this as a pseudo export so that an NFS v4 * client can do lookups in it. */ - new_exi = pseudo_exportfs(vp, &fid, vis_head, - NULL); + error = pseudo_exportfs(vp, vis_head, NULL, + &new_exi); + if (error) + break; vis_head = NULL; } @@ -737,8 +763,9 @@ treeclimb_export(struct exportinfo *exip) /* * We can have set error due to error in: * 1. vop_fid_pseudo() - * 2. VOP_GETATTR() - * 3. VOP_LOOKUP() + * 2. pseudo_exportfs() which can fail only in vop_fid_pseudo() + * 3. VOP_GETATTR() + * 4. 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 @@ -758,7 +785,8 @@ treeclimb_export(struct exportinfo *exip) exportinfo_t *e = tree_head->tree_exi; /* exip will be freed in exportfs() */ if (e && e != exip) { - export_unlink(e); + (void) export_unlink(&e->exi_fsid, &e->exi_fid, + e->exi_vp, NULL); exi_rele(e); } tree_head = tree_head->tree_child_first; @@ -784,6 +812,7 @@ treeclimb_export(struct exportinfo *exip) void treeclimb_unexport(struct exportinfo *exip) { + struct exportinfo *exi; treenode_t *tnode, *old_nd; ASSERT(RW_WRITE_HELD(&exported_lock)); @@ -808,13 +837,17 @@ treeclimb_unexport(struct exportinfo *exip) /* Release pseudo export if it has no child */ if (TREE_ROOT(tnode) && !TREE_EXPORTED(tnode) && tnode->tree_child_first == 0) { - export_unlink(tnode->tree_exi); + exi = tnode->tree_exi; + (void) export_unlink(&exi->exi_fsid, &exi->exi_fid, + exi->exi_vp, NULL); exi_rele(tnode->tree_exi); } /* Release visible in parent's exportinfo */ - if (tnode->tree_vis) - less_visible(vis2exi(tnode), tnode->tree_vis); + if (tnode->tree_vis) { + exi = vis2exi(tnode); + less_visible(exi, tnode->tree_vis); + } /* Continue with parent */ old_nd = tnode; diff --git a/usr/src/uts/common/fs/nfs/nfs_auth.c b/usr/src/uts/common/fs/nfs/nfs_auth.c index 00a25566e4..d803531e09 100644 --- a/usr/src/uts/common/fs/nfs/nfs_auth.c +++ b/usr/src/uts/common/fs/nfs/nfs_auth.c @@ -1145,7 +1145,7 @@ exi_cache_reclaim(void *cdrarg) rw_enter(&exported_lock, RW_READER); for (i = 0; i < EXPTABLESIZE; i++) { - for (exi = exptable[i]; exi; exi = exi->fid_hash.next) { + for (exi = exptable[i]; exi; exi = exi->exi_hash) { exi_cache_trim(exi); } } diff --git a/usr/src/uts/common/fs/nfs/nfs_export.c b/usr/src/uts/common/fs/nfs/nfs_export.c index 138cced588..315fdb8385 100644 --- a/usr/src/uts/common/fs/nfs/nfs_export.c +++ b/usr/src/uts/common/fs/nfs/nfs_export.c @@ -62,14 +62,12 @@ #include #include #include -#include treenode_t *ns_root; -struct exportinfo *exptable_path_hash[PKP_HASH_SIZE]; struct exportinfo *exptable[EXPTABLESIZE]; -static void unexport(exportinfo_t *); +static int unexport(fsid_t *, fid_t *, vnode_t *); static void exportfree(exportinfo_t *); static int loadindex(exportdata_t *); @@ -114,36 +112,61 @@ fhandle_t nullfh2; /* for comparing V2 filehandles */ #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, XOR over all bytes in fsid and fid. + * File handle hash function, good for producing hash values 16 bits wide. */ -static unsigned +int nfs_fhhash(fsid_t *fsid, fid_t *fid) { - int len; - uint8_t h; + short *data; + int i, len; + short h; + + ASSERT(fid != NULL); - h = xor_hash((uint8_t *)fsid, sizeof (fsid_t)); + data = (short *)fid->fid_data; + + /* fid_data must be aligned on a short */ + ASSERT((((uintptr_t)data) & (sizeof (short) - 1)) == 0); + + 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]; /* * Sanity check the length before using it * blindly in case the client trashed it. */ - len = fid->fid_len > NFS_FH4MAXDATA ? 0 : fid->fid_len; - h ^= xor_hash((uint8_t *)fid->fid_data, len); + if (fid->fid_len > NFS_FHMAXDATA) + len = 0; + else + len = fid->fid_len / sizeof (short); + + /* + * 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 ((unsigned)h); + return ((int)h); } /* @@ -166,6 +189,7 @@ srv_secinfo_entry_free(struct secinfo *secp) sizeof (rpc_gss_OID_desc)); secp->s_secinfo.sc_gss_mech_type = NULL; } + } /* @@ -759,35 +783,13 @@ srv_secinfo_treeclimb(exportinfo_t *exip, secinfo_t *sec, int seccnt, int isadd) } } -/* 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; - -#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; +export_link(exportinfo_t *exi) { + int exporthash; - 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); + exporthash = exptablehash(&exi->exi_fsid, &exi->exi_fid); + exi->exi_hash = exptable[exporthash]; + exptable[exporthash] = exi; } /* @@ -946,7 +948,7 @@ rfs_gsscallback(struct svc_req *req, gss_cred_id_t deleg, void *gss_context, } } } - exi = exi->fid_hash.next; + exi = exi->exi_hash; } } done: @@ -996,7 +998,7 @@ exportfs(struct exportfs_args *args, model_t model, cred_t *cr) vnode_t *dvp; struct exportdata *kex; struct exportinfo *exi = NULL; - struct exportinfo *ex, *ex1, *ex2; + struct exportinfo *ex, *prev; fid_t fid; fsid_t fsid; int error; @@ -1016,46 +1018,9 @@ exportfs(struct exportfs_args *args, model_t model, cred_t *cr) 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); - rw_enter(&exported_lock, RW_WRITER); - /* Check if ex1 is still linked in the export table */ - if (ex1 == NULL || !EXP_LINKED(ex1) || PSEUDO(ex1)) { - rw_exit(&exported_lock); - if (ex1) - exi_rele(ex1); - return (EINVAL); - } - unexport(ex1); - rw_exit(&exported_lock); - exi_rele(ex1); - return (0); - } - - /* It is a share or a re-share */ error = lookupname(STRUCT_FGETP(uap, dname), UIO_USERSPACE, FOLLOW, &dvp, &vp); if (error == EINVAL) { @@ -1069,18 +1034,87 @@ exportfs(struct exportfs_args *args, model_t model, cred_t *cr) 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) { - pn_free(&lookpn); - if (ex1) - exi_rele(ex1); - return (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); + } + } } + if (error) + return (error); + /* * 'vp' may be an AUTOFS node, so we perform a * VOP_ACCESS() to trigger the mount of the @@ -1101,22 +1135,10 @@ exportfs(struct exportfs_args *args, model_t model, cred_t *cr) 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 */ @@ -1125,7 +1147,13 @@ exportfs(struct exportfs_args *args, model_t model, cred_t *cr) error = VOP_FID(vp, &fid, NULL); fsid = vp->v_vfsp->vfs_fsid; - if (error) { + /* + * Allow unshare request for forcibly unmounted shared filesystem. + */ + if (error == EIO && exi) { + fid = exi->exi_fid; + fsid = exi->exi_fsid; + } else if (error) { VN_RELE(vp); if (dvp != NULL) VN_RELE(dvp); @@ -1135,30 +1163,16 @@ exportfs(struct exportfs_args *args, model_t model, cred_t *cr) */ if (error == ENOSPC) error = EREMOTE; - pn_free(&lookpn); 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); - } + if (STRUCT_FGETP(uap, uex) == NULL) { + error = unexport(&fsid, &fid, vp); + VN_RELE(vp); + if (dvp != NULL) + VN_RELE(dvp); + return (error); } - 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; @@ -1433,7 +1447,6 @@ exportfs(struct exportfs_args *args, model_t model, cred_t *cr) * 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); @@ -1442,9 +1455,10 @@ exportfs(struct exportfs_args *args, model_t model, cred_t *cr) * If one is found then unlink it, wait until this is the * only reference and then free it. */ - for (ex = exi->fid_hash.next; ex != NULL; ex = ex->fid_hash.next) { + prev = exi; + for (ex = prev->exi_hash; ex != NULL; prev = ex, ex = ex->exi_hash) { if (ex != exi_root && VN_CMP(ex->exi_vp, vp)) { - export_unlink(ex); + prev->exi_hash = ex->exi_hash; break; } } @@ -1539,7 +1553,6 @@ exportfs(struct exportfs_args *args, model_t model, cred_t *cr) ex->exi_visible = NULL; } - DTRACE_PROBE(nfss__i__exported_lock3_stop); rw_exit(&exported_lock); if (exi_public == exi || kex->ex_flags & EX_LOG) { @@ -1556,8 +1569,7 @@ exportfs(struct exportfs_args *args, model_t model, cred_t *cr) out7: /* Unlink the new export in exptable. */ - export_unlink(exi); - DTRACE_PROBE(nfss__i__exported_lock3_stop); + (void) export_unlink(&exi->exi_fsid, &exi->exi_fid, exi->exi_vp, NULL); rw_exit(&exported_lock); out6: if (kex->ex_flags & EX_INDEX) @@ -1595,27 +1607,70 @@ out1: /* * Remove the exportinfo from the export list */ -void -export_unlink(struct exportinfo *exi) +int +export_unlink(fsid_t *fsid, fid_t *fid, vnode_t *vp, struct exportinfo **exip) { + struct exportinfo **tail; + ASSERT(RW_WRITE_HELD(&exported_lock)); - exp_hash_unlink(exi, fid_hash); - exp_hash_unlink(exi, path_hash); + 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); } /* * Unexport an exported filesystem */ -void -unexport(struct exportinfo *exi) +int +unexport(fsid_t *fsid, fid_t *fid, vnode_t *vp) { + struct exportinfo *exi = NULL; + int error; struct secinfo cursec[MAX_FLAVORS]; int curcnt; - ASSERT(RW_WRITE_HELD(&exported_lock)); + rw_enter(&exported_lock, RW_WRITER); - export_unlink(exi); + 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); + rw_exit(&exported_lock); + return (EINVAL); + } /* * Remove security flavors before treeclimb_unexport() is called @@ -1633,17 +1688,25 @@ unexport(struct exportinfo *exi) if (exi->exi_visible) { struct exportinfo *newexi; - newexi = pseudo_exportfs(exi->exi_vp, &exi->exi_fid, - exi->exi_visible, &exi->exi_export); - exi->exi_visible = NULL; + error = pseudo_exportfs(exi->exi_vp, exi->exi_visible, + &exi->exi_export, &newexi); + if (error) + goto done; - /* interconnect the existing treenode with the new exportinfo */ + exi->exi_visible = NULL; + /* + * pseudo_exportfs() has allocated new exportinfo, + * update the treenode. + */ newexi->exi_tree = exi->exi_tree; newexi->exi_tree->tree_exi = newexi; + } else { treeclimb_unexport(exi); } + rw_exit(&exported_lock); + /* * Need to call into the NFSv4 server and release all data * held on this particular export. This is important since @@ -1673,6 +1736,12 @@ unexport(struct exportinfo *exi) } exi_rele(exi); + return (error); + +done: + rw_exit(&exported_lock); + exi_rele(exi); + return (error); } /* @@ -2456,7 +2525,7 @@ checkexport(fsid_t *fsid, fid_t *fid) rw_enter(&exported_lock, RW_READER); for (exi = exptable[exptablehash(fsid, fid)]; exi != NULL; - exi = exi->fid_hash.next) { + exi = exi->exi_hash) { if (exportmatch(exi, fsid, fid)) { /* * If this is the place holder for the @@ -2494,7 +2563,7 @@ checkexport4(fsid_t *fsid, fid_t *fid, vnode_t *vp) for (exi = exptable[exptablehash(fsid, fid)]; exi != NULL; - exi = exi->fid_hash.next) { + exi = exi->exi_hash) { if (exportmatch(exi, fsid, fid)) { /* * If this is the place holder for the diff --git a/usr/src/uts/common/fs/pkp_hash.c b/usr/src/uts/common/fs/pkp_hash.c deleted file mode 100644 index ee74adf008..0000000000 --- a/usr/src/uts/common/fs/pkp_hash.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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 - -/* - * 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); -} diff --git a/usr/src/uts/common/fs/sharefs/sharetab.c b/usr/src/uts/common/fs/sharefs/sharetab.c index 5036cd3f17..53d4ae4a2b 100644 --- a/usr/src/uts/common/fs/sharefs/sharetab.c +++ b/usr/src/uts/common/fs/sharefs/sharetab.c @@ -20,9 +20,12 @@ */ /* - * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ +#pragma ident "%Z%%M% %I% %E% SMI" + #include #include #include @@ -83,6 +86,36 @@ timestruc_t sharetab_snap_time; 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 @@ -135,7 +168,7 @@ sharefs_remove(share_t *sh, sharefs_lens_t *shl) } iPath = shl ? shl->shl_path : strlen(sh->sh_path); - iHash = pkp_tab_hash(sh->sh_path, strlen(sh->sh_path)); + SHARETAB_HASH_IT(iHash, sh->sh_path); /* * Now walk down the hash table and find the entry to free! @@ -230,7 +263,7 @@ sharefs_add(share_t *sh, sharefs_lens_t *shl) /* * Now we need to find where we have to add the entry. */ - iHash = pkp_tab_hash(sh->sh_path, strlen(sh->sh_path)); + SHARETAB_HASH_IT(iHash, sh->sh_path); iPath = shl ? shl->shl_path : strlen(sh->sh_path); @@ -314,6 +347,8 @@ sharefs_add(share_t *sh, sharefs_lens_t *shl) void sharefs_sharetab_init(void) { + init_pkp_tab(); + rw_init(&sharetab_lock, NULL, RW_DEFAULT, NULL); rw_init(&sharefs_lock, NULL, RW_DEFAULT, NULL); diff --git a/usr/src/uts/common/nfs/export.h b/usr/src/uts/common/nfs/export.h index 56d8e2b0de..5d6072c2f7 100644 --- a/usr/src/uts/common/nfs/export.h +++ b/usr/src/uts/common/nfs/export.h @@ -419,13 +419,7 @@ typedef struct treenode { /* Root of nfs pseudo namespace */ extern treenode_t *ns_root; -#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 */ -}; +#define EXPTABLESIZE 16 /* * A node associated with an export entry on the @@ -447,8 +441,7 @@ struct exportinfo { struct exportdata exi_export; fsid_t exi_fsid; struct fid exi_fid; - struct exp_hash fid_hash; - struct exp_hash path_hash; + struct exportinfo *exi_hash; struct treenode *exi_tree; fhandle_t exi_fh; krwlock_t exi_cache_lock; @@ -512,7 +505,6 @@ struct exp_visible { 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]) && \ @@ -541,6 +533,7 @@ extern int nfsauth4_access(struct exportinfo *, vnode_t *, 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); @@ -562,7 +555,8 @@ extern struct exportinfo *nfs_vptoexi(vnode_t *, vnode_t *, cred_t *, int *, extern int nfs_check_vpexi(vnode_t *, vnode_t *, cred_t *, struct exportinfo **); extern void export_link(struct exportinfo *); -extern void export_unlink(struct exportinfo *); +extern int export_unlink(fsid_t *, fid_t *, vnode_t *, + 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 *); @@ -579,8 +573,8 @@ extern int nfs_visible_inode(struct exportinfo *, ino64_t, int *); extern int has_visible(struct exportinfo *, vnode_t *); extern void free_visible(struct exp_visible *); extern int nfs_exported(struct exportinfo *, vnode_t *); -extern struct exportinfo *pseudo_exportfs(vnode_t *, fid_t *, - struct exp_visible *, struct exportdata *); +extern int pseudo_exportfs(vnode_t *, struct exp_visible *, + struct exportdata *, struct exportinfo **); extern int vop_fid_pseudo(vnode_t *, fid_t *fidp); extern int nfs4_vget_pseudo(struct exportinfo *, vnode_t **, fid_t *); /* diff --git a/usr/src/uts/common/nfs/nfs4_idmap_impl.h b/usr/src/uts/common/nfs/nfs4_idmap_impl.h index f0f166688d..344e98213a 100644 --- a/usr/src/uts/common/nfs/nfs4_idmap_impl.h +++ b/usr/src/uts/common/nfs/nfs4_idmap_impl.h @@ -2,8 +2,9 @@ * 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. + * Common Development and Distribution License, Version 1.0 only + * (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. @@ -19,15 +20,17 @@ * CDDL HEADER END */ /* - * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #ifndef _NFS4_IDMAP_IMPL_H #define _NFS4_IDMAP_IMPL_H +#pragma ident "%Z%%M% %I% %E% SMI" + #include #include -#include /* * This is a private header file. Applications should not directly include @@ -41,7 +44,7 @@ extern "C" { /* * Cache Entry Definitions */ -#define NFSID_CACHE_ANCHORS PKP_HASH_SIZE +#define NFSID_CACHE_ANCHORS 256 typedef struct nfsidmap { struct nfsidmap *id_chain[2]; /* must be first */ diff --git a/usr/src/uts/common/sharefs/sharetab.h b/usr/src/uts/common/sharefs/sharetab.h index f1a3fd620c..9271c07a8d 100644 --- a/usr/src/uts/common/sharefs/sharetab.h +++ b/usr/src/uts/common/sharefs/sharetab.h @@ -18,14 +18,16 @@ * * CDDL HEADER END */ + /* - * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #ifndef _SHAREFS_SHARETAB_H #define _SHAREFS_SHARETAB_H -#include +#pragma ident "%Z%%M% %I% %E% SMI" /* * This header defines the glue to keeping a sharetab in memory. @@ -52,7 +54,7 @@ typedef struct sharefs_hash_head { uint_t ssh_count; } sharefs_hash_head_t; -#define SHARETAB_HASHES PKP_HASH_SIZE +#define SHARETAB_HASHES 256 typedef struct sharetab { sharefs_hash_head_t s_buckets[SHARETAB_HASHES]; @@ -61,6 +63,29 @@ typedef struct sharetab { 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 diff --git a/usr/src/uts/common/sys/Makefile b/usr/src/uts/common/sys/Makefile index fbcbd7fc5c..63883cfcbb 100644 --- a/usr/src/uts/common/sys/Makefile +++ b/usr/src/uts/common/sys/Makefile @@ -431,7 +431,6 @@ CHKHDRS= \ pg.h \ pghw.h \ physmem.h \ - pkp_hash.h \ pm.h \ policy.h \ poll.h \ diff --git a/usr/src/uts/common/sys/pkp_hash.h b/usr/src/uts/common/sys/pkp_hash.h deleted file mode 100644 index e7602304bf..0000000000 --- a/usr/src/uts/common/sys/pkp_hash.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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 - -#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_ */ -- cgit v1.2.3