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 ----