Print this page
NEX-15279 support NFS server in zone
NEX-15520 online NFS shares cause zoneadm halt to hang in nfs_export_zone_fini
Portions contributed by: Dan Kruchinin dan.kruchinin@nexenta.com
Portions contributed by: Stepan Zastupov stepan.zastupov@gmail.com
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
OS-20 share_nfs(1m) charset handling is unreliable
OS-22 Page fault at nfscmd_dropped_entrysize+0x1e()
OS-23 NFSv2/3/4: READDIR responses are inconsistent when charset conversion fails
OS-24 rfs3_readdir(): Issues related to nfscmd_convdirent()
Reviewed by: Jan Kryl <jan.kryl@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>

*** 16,30 **** --- 16,35 ---- * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ + /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ + /* + * Copyright 2018 Nexenta Systems, Inc. + */ + #include <sys/param.h> #include <sys/types.h> #include <sys/pathname.h> #include <sys/errno.h> #include <sys/cmn_err.h>
*** 43,80 **** #ifdef nextdp #undef nextdp #endif #define nextdp(dp) ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen)) ! kmutex_t nfscmd_lock; ! door_handle_t nfscmd_dh; static struct charset_cache *nfscmd_charmap(exportinfo_t *exi, struct sockaddr *sp); - void nfscmd_args(uint_t did) { ! mutex_enter(&nfscmd_lock); ! if (nfscmd_dh) ! door_ki_rele(nfscmd_dh); ! nfscmd_dh = door_ki_lookup(did); ! mutex_exit(&nfscmd_lock); } void nfscmd_init(void) { ! mutex_init(&nfscmd_lock, NULL, MUTEX_DEFAULT, NULL); } void nfscmd_fini(void) { } /* * nfscmd_send(arg, result) * * Send a command to the daemon listening on the door. The result is * returned in the result pointer if the function return value is --- 48,118 ---- #ifdef nextdp #undef nextdp #endif #define nextdp(dp) ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen)) ! typedef struct nfscmd_globals { ! kmutex_t nfscmd_lock; ! door_handle_t nfscmd_dh; ! } nfscmd_globals_t; + static zone_key_t nfscmd_zone_key; + static struct charset_cache *nfscmd_charmap(exportinfo_t *exi, struct sockaddr *sp); + static void *nfscmd_zone_init(zoneid_t); + static void nfscmd_zone_fini(zoneid_t, void *); void nfscmd_args(uint_t did) { ! nfscmd_globals_t *ncg = zone_getspecific(nfscmd_zone_key, curzone); ! ! mutex_enter(&ncg->nfscmd_lock); ! if (ncg->nfscmd_dh != NULL) ! door_ki_rele(ncg->nfscmd_dh); ! ncg->nfscmd_dh = door_ki_lookup(did); ! mutex_exit(&ncg->nfscmd_lock); } void nfscmd_init(void) { ! zone_key_create(&nfscmd_zone_key, nfscmd_zone_init, ! NULL, nfscmd_zone_fini); } void nfscmd_fini(void) { + (void) zone_key_delete(nfscmd_zone_key); } + /*ARGSUSED*/ + static void * + nfscmd_zone_init(zoneid_t zoneid) + { + nfscmd_globals_t *ncg; + + ncg = kmem_zalloc(sizeof (*ncg), KM_SLEEP); + mutex_init(&ncg->nfscmd_lock, NULL, MUTEX_DEFAULT, NULL); + + return (ncg); + } + + /*ARGSUSED*/ + static void + nfscmd_zone_fini(zoneid_t zoneid, void *data) + { + nfscmd_globals_t *ncg = data; + + mutex_destroy(&ncg->nfscmd_lock); + if (ncg->nfscmd_dh) + door_ki_rele(ncg->nfscmd_dh); + kmem_free(ncg, sizeof (*ncg)); + } + /* * nfscmd_send(arg, result) * * Send a command to the daemon listening on the door. The result is * returned in the result pointer if the function return value is
*** 86,102 **** door_handle_t dh; door_arg_t da; door_info_t di; int ntries = 0; int last = 0; retry: ! mutex_enter(&nfscmd_lock); ! dh = nfscmd_dh; if (dh != NULL) door_ki_hold(dh); ! mutex_exit(&nfscmd_lock); if (dh == NULL) { /* * The rendezvous point has not been established yet ! * This could mean that either mountd(1m) has not yet --- 124,141 ---- door_handle_t dh; door_arg_t da; door_info_t di; int ntries = 0; int last = 0; + nfscmd_globals_t *ncg = zone_getspecific(nfscmd_zone_key, curzone); retry: ! mutex_enter(&ncg->nfscmd_lock); ! dh = ncg->nfscmd_dh; if (dh != NULL) door_ki_hold(dh); ! mutex_exit(&ncg->nfscmd_lock); if (dh == NULL) { /* * The rendezvous point has not been established yet ! * This could mean that either mountd(1m) has not yet
*** 139,152 **** * the (existing) door on us; we * want to wait to give smf(5) a * chance to restart mountd(1m) * and establish a new door handle. */ ! mutex_enter(&nfscmd_lock); ! if (dh == nfscmd_dh) ! nfscmd_dh = NULL; ! mutex_exit(&nfscmd_lock); door_ki_rele(dh); delay(hz); goto retry; } /* --- 178,191 ---- * the (existing) door on us; we * want to wait to give smf(5) a * chance to restart mountd(1m) * and establish a new door handle. */ ! mutex_enter(&ncg->nfscmd_lock); ! if (dh == ncg->nfscmd_dh) ! ncg->nfscmd_dh = NULL; ! mutex_exit(&ncg->nfscmd_lock); door_ki_rele(dh); delay(hz); goto retry; } /*
*** 254,267 **** charset = (struct charset_cache *) kmem_zalloc(sizeof (struct charset_cache), KM_SLEEP); if (charset == NULL) return (NULL); ! if (name != NULL) { charset->inbound = kiconv_open("UTF-8", name); charset->outbound = kiconv_open(name, "UTF-8"); ! } charset->client_addr = *sp; mutex_enter(&exi->exi_lock); charset->next = exi->exi_charset; exi->exi_charset = charset; mutex_exit(&exi->exi_lock); --- 293,306 ---- charset = (struct charset_cache *) kmem_zalloc(sizeof (struct charset_cache), KM_SLEEP); if (charset == NULL) return (NULL); ! charset->inbound = kiconv_open("UTF-8", name); charset->outbound = kiconv_open(name, "UTF-8"); ! charset->client_addr = *sp; mutex_enter(&exi->exi_lock); charset->next = exi->exi_charset; exi->exi_charset = charset; mutex_exit(&exi->exi_lock);
*** 332,343 **** size_t osize; struct charset_cache *charset = NULL; charset = nfscmd_findmap(exi, ca); if (charset == NULL || ! (charset->inbound == NULL && inbound) || ! (charset->outbound == NULL && !inbound)) return (name); /* make sure we have more than enough space */ newname = kmem_zalloc(size, KM_SLEEP); nsize = strlen(name); --- 371,382 ---- size_t osize; struct charset_cache *charset = NULL; charset = nfscmd_findmap(exi, ca); if (charset == NULL || ! (charset->inbound == (kiconv_t)-1 && inbound) || ! (charset->outbound == (kiconv_t)-1 && !inbound)) return (name); /* make sure we have more than enough space */ newname = kmem_zalloc(size, KM_SLEEP); nsize = strlen(name);
*** 353,534 **** kmem_free(newname, size); newname = NULL; } return (newname); - } - - /* - * nfscmd_convdirent() - * - * There is only one entry in the data. Convert to new charset, if - * required and only return a success if it fits. - */ - char * - nfscmd_convdirent(struct sockaddr *ca, struct exportinfo *exi, char *data, - size_t size, enum nfsstat3 *error) - { - char *newdata; - size_t ret; - size_t nsize; - size_t count; - int err = 0; - char *iname; - char *oname; - struct charset_cache *charset; - - charset = nfscmd_findmap(exi, ca); - if (charset == NULL || charset->outbound == (void *)~0) - return (data); - - newdata = kmem_zalloc(size, KM_SLEEP); - - nsize = strlen(((struct dirent64 *)data)->d_name); - count = size; - bcopy(data, newdata, sizeof (struct dirent64)); - - iname = ((struct dirent64 *)data)->d_name; - oname = ((struct dirent64 *)newdata)->d_name; - - ret = kiconv(charset->outbound, &iname, &nsize, &oname, &count, &err); - if (ret == (size_t)-1) { - kmem_free(newdata, size); - newdata = NULL; - if (err == E2BIG) { - if (error != NULL) - *error = NFS3ERR_NAMETOOLONG; - } else { - newdata = data; - } - } else { - ret = strlen(((struct dirent64 *)newdata)->d_name); - ((struct dirent64 *)newdata)->d_reclen = - DIRENT64_RECLEN(ret + 1); - } - return (newdata); - } - - /* - * nfscmd_convdirplus(addr, export, data, nents, maxsize, ndata) - * - * Convert the dirents in data into a new list of dirents in ndata. - */ - - size_t - nfscmd_convdirplus(struct sockaddr *ca, struct exportinfo *exi, char *data, - size_t nents, size_t maxsize, char **ndata) - { - char *newdata; - size_t nsize; - struct dirent64 *dp; - struct dirent64 *ndp; - size_t i; - size_t ret; - char *iname; - char *oname; - size_t ilen; - size_t olen; - int err; - size_t skipped; - struct charset_cache *charset; - *ndata = data; /* return the data if no changes to make */ - - charset = nfscmd_findmap(exi, ca); - - if (charset == NULL || charset->outbound == (void *)~0) - return (0); - - newdata = kmem_zalloc(maxsize, KM_SLEEP); - nsize = 0; - - dp = (struct dirent64 *)data; - ndp = (struct dirent64 *)newdata; - - for (skipped = 0, i = 0; i < nents; i++) { - /* - * Copy the dp information if it fits. Then copy and - * convert the name in the entry. - */ - if ((maxsize - nsize) < dp->d_reclen) - /* doesn't fit */ - break; - *ndp = *dp; - iname = dp->d_name; - ilen = strlen(iname); - oname = ndp->d_name; - olen = MIN(MAXNAMELEN, maxsize - nsize); - ret = kiconv(charset->outbound, &iname, &ilen, &oname, - &olen, &err); - - if (ret == (size_t)-1) { - switch (err) { - default: - case E2BIG: - break; - case EILSEQ: - skipped++; - dp = nextdp(dp); - continue; - } - } - ilen = MIN(MAXNAMELEN, maxsize - nsize) - olen; - ndp->d_name[ilen] = '\0'; - /* - * What to do with other errors? - * For now, we return the unconverted string. - */ - ndp->d_reclen = DIRENT64_RECLEN(strlen(ndp->d_name) + 1); - nsize += ndp->d_reclen; - dp = nextdp(dp); - ndp = nextdp(ndp); - } - - *ndata = newdata; - return (nents - (i + skipped)); - } - - /* - * nfscmd_countents(data, len) - * - * How many dirents are there in the data buffer? - */ - - size_t - nfscmd_countents(char *data, size_t len) - { - struct dirent64 *dp = (struct dirent64 *)data; - size_t curlen; - size_t reclen; - size_t nents; - - for (nents = 0, curlen = 0; curlen < len; curlen += reclen, nents++) { - reclen = dp->d_reclen; - dp = nextdp(dp); - } - return (nents); - } - - /* - * nfscmd_dropped_entrysize(dir, drop, nents) - * - * We need to drop "drop" entries from dir in order to fit in the - * buffer. How much do we reduce the overall size by? - */ - - size_t - nfscmd_dropped_entrysize(struct dirent64 *dir, size_t drop, size_t nents) - { - size_t size; - size_t i; - - for (i = nents - drop; i > 0 && dir != NULL; i--) - dir = nextdp(dir); - - if (dir == NULL) - return (0); - - for (size = 0, i = 0; i < drop && dir != NULL; i++) { - size += dir->d_reclen; - dir = nextdp(dir); - } - return (size); } --- 392,397 ----