diff options
author | th199096 <none@none> | 2007-10-22 15:49:36 -0700 |
---|---|---|
committer | th199096 <none@none> | 2007-10-22 15:49:36 -0700 |
commit | b9238976491622ad75a67ab0c12edf99e36212b9 (patch) | |
tree | 9b05921ffcef7973ffdbbb12b4e5b867fdaf70c1 | |
parent | 90c85bf889e3af34323084f00e344a82f120b409 (diff) | |
download | illumos-gate-b9238976491622ad75a67ab0c12edf99e36212b9.tar.gz |
PSARC 2007/416 NFSv4 Mirror-mounts
PSARC 2007/563 Add _AT_TRIGGER to fstatat(2)
5035401 allow clients to cross server filesystem boundaries if the fs is visible
6613892 nftw(3C) has potential security issues
31 files changed, 4819 insertions, 1937 deletions
diff --git a/usr/src/cmd/fs.d/autofs/autod_nfs.c b/usr/src/cmd/fs.d/autofs/autod_nfs.c index d750376974..903f3b8f18 100644 --- a/usr/src/cmd/fs.d/autofs/autod_nfs.c +++ b/usr/src/cmd/fs.d/autofs/autod_nfs.c @@ -85,6 +85,8 @@ #include <tsol/label.h> #include <zone.h> +extern void set_nfsv4_ephemeral_mount_to(void); + extern char *nfs_get_qop_name(); extern AUTH *nfs_create_ah(); extern enum snego_stat nfs_sec_nego(); @@ -2378,6 +2380,12 @@ try_mnt_slash: } /* + * About to do a nfs mount, make sure the mount_to is set for + * potential ephemeral mounts with NFSv4. + */ + set_nfsv4_ephemeral_mount_to(); + + /* * If no action list pointer then do the mount, otherwise * build the actions list pointer with the mount information. * so the mount can be done in the kernel. diff --git a/usr/src/cmd/fs.d/nfs/lib/nfs_subr.c b/usr/src/cmd/fs.d/nfs/lib/nfs_subr.c index b78d4e124f..0dbdbbe6a3 100644 --- a/usr/src/cmd/fs.d/nfs/lib/nfs_subr.c +++ b/usr/src/cmd/fs.d/nfs/lib/nfs_subr.c @@ -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,10 +19,8 @@ * CDDL HEADER END */ /* - * nfs_subr.c - * - * Copyright (c) 1996 Sun Microsystems Inc - * All Rights Reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -35,6 +32,11 @@ #include <sys/utsname.h> #include <nfs/nfs.h> #include "nfs_subr.h" +#include <errno.h> +#include <deflt.h> + +#include <nfs/nfssys.h> +extern int _nfssys(enum nfssys_op, void *); /* * This function is added to detect compatibility problem with SunOS4.x. @@ -75,8 +77,8 @@ remote_lock(char *fshost, caddr_t fh) return (0); rpc_stat = clnt_call(cl, NLM_GRANTED, - xdr_nlm_testargs, (caddr_t)&rlm_args, - xdr_nlm_res, (caddr_t)&rlm_res, timeout); + xdr_nlm_testargs, (caddr_t)&rlm_args, + xdr_nlm_res, (caddr_t)&rlm_res, timeout); clnt_destroy(cl); return (rpc_stat == RPC_CANTDECODEARGS); @@ -242,3 +244,34 @@ convert_special(char **specialp, char *host, char *oldpath, char *newpath, free(url); return (0); } + +/* + * Solaris autofs configuration file location + */ +#define AUTOFSADMIN "/etc/default/autofs" +#define AUTOFS_MOUNT_TIMEOUT 600 /* default min time mount will */ + +void +set_nfsv4_ephemeral_mount_to(void) +{ + char *defval; + + uint_t mount_to = AUTOFS_MOUNT_TIMEOUT; + + /* + * Get the value from /etc/default/autofs + */ + if ((defopen(AUTOFSADMIN)) == 0) { + if ((defval = defread("AUTOMOUNT_TIMEOUT=")) != NULL) { + errno = 0; + mount_to = strtoul(defval, (char **)NULL, 10); + if (errno != 0) + mount_to = AUTOFS_MOUNT_TIMEOUT; + } + + /* close defaults file */ + defopen(NULL); + } + + (void) _nfssys(NFS4_EPHEMERAL_MOUNT_TO, &mount_to); +} diff --git a/usr/src/cmd/fs.d/nfs/mount/mount.c b/usr/src/cmd/fs.d/nfs/mount/mount.c index a6bba0b601..318ee6ae8c 100644 --- a/usr/src/cmd/fs.d/nfs/mount/mount.c +++ b/usr/src/cmd/fs.d/nfs/mount/mount.c @@ -82,6 +82,9 @@ #include "webnfs.h" #include <rpcsvc/nfs4_prot.h> +#include <nfs/nfssys.h> +extern int _nfssys(enum nfssys_op, void *); + #ifndef NFS_VERSMAX #define NFS_VERSMAX 4 #endif @@ -176,6 +179,8 @@ static int sec_opt = 0; /* any security option ? */ static bool_t snego_done; static void sigusr1(int); +extern void set_nfsv4_ephemeral_mount_to(void); + /* * list of support services needed */ @@ -320,13 +325,13 @@ main(int argc, char *argv[]) */ read_default(); if (vers_min_default > vers_max_default || - vers_min_default < NFS_VERSMIN || - vers_max_default > NFS_VERSMAX) { + vers_min_default < NFS_VERSMIN || + vers_max_default > NFS_VERSMAX) { pr_err("%s %s\n%s %s\n", - gettext("Incorrect configuration of client\'s"), - NFSADMIN, - gettext("NFS_CLIENT_VERSMIN or NFS_CLIENT_VERSMAX"), - gettext("is either out of range or overlaps.")); + gettext("Incorrect configuration of client\'s"), + NFSADMIN, + gettext("NFS_CLIENT_VERSMIN or NFS_CLIENT_VERSMAX"), + gettext("is either out of range or overlaps.")); } SET_ERR_RET(&retry_error, ERR_PROTO_NONE, 0); @@ -482,7 +487,7 @@ mount_nfs(struct mnttab *mntp, int ro, err_ret_t *retry_error) cb = strchr(host, ']'); if (cb == NULL) { pr_err(gettext( - "illegal nfs url syntax\n")); + "illegal nfs url syntax\n")); last_error = RET_ERR; goto out; } else { @@ -491,7 +496,7 @@ mount_nfs(struct mnttab *mntp, int ro, err_ret_t *retry_error) cb++; if (*cb == ':') port = htons((ushort_t) - atoi(cb+1)); + atoi(cb+1)); } } else { sport = strchr(host, ':'); @@ -534,14 +539,14 @@ mount_nfs(struct mnttab *mntp, int ro, err_ret_t *retry_error) if (replicated && !(mntflags & MS_RDONLY)) { pr_err(gettext( - "replicated mounts must be read-only\n")); + "replicated mounts must be read-only\n")); last_error = RET_ERR; goto out; } if (replicated && (argp->flags & NFSMNT_SOFT)) { pr_err(gettext( - "replicated mounts must not be soft\n")); + "replicated mounts must not be soft\n")); last_error = RET_ERR; goto out; } @@ -557,7 +562,7 @@ mount_nfs(struct mnttab *mntp, int ro, err_ret_t *retry_error) */ if ((use_pubfh == TRUE) || (url == TRUE)) { r = get_fh_via_pub(argp, host, path, url, use_pubfh, - &vers, &nconf, port); + &vers, &nconf, port); if (r != RET_OK) { /* @@ -597,7 +602,7 @@ mount_nfs(struct mnttab *mntp, int ro, err_ret_t *retry_error) loud_on_mnt_err = TRUE; r = get_fh(argp, host, path, &vers, - loud_on_mnt_err, &nconf, port); + loud_on_mnt_err, &nconf, port); if (r != RET_OK) { @@ -622,7 +627,7 @@ mount_nfs(struct mnttab *mntp, int ro, err_ret_t *retry_error) strcat(newpath, path); r = get_fh(argp, host, newpath, &vers, - TRUE, &nconf, port); + TRUE, &nconf, port); if (r == RET_OK) path = newpath; @@ -669,7 +674,7 @@ mount_nfs(struct mnttab *mntp, int ro, err_ret_t *retry_error) host, path); (void) fprintf(stderr, gettext( " contact admin to install server change\n")); - argp->flags |= NFSMNT_LLOCK; + argp->flags |= NFSMNT_LLOCK; } if (self_check(host)) @@ -684,8 +689,8 @@ mount_nfs(struct mnttab *mntp, int ro, err_ret_t *retry_error) if (!(argp->flags & NFSMNT_KNCONF)) { nconf = NULL; if (r = getaddr_nfs(argp, host, &nconf, - FALSE, path, port, retry_error, - TRUE)) { + FALSE, path, port, retry_error, + TRUE)) { last_error = r; goto out; } @@ -760,19 +765,25 @@ cont: if (!qflg) saveopts = strdup(mntp->mnt_mntopts); + /* + * And make sure that we have the ephemeral mount_to + * set for this zone. + */ + set_nfsv4_ephemeral_mount_to(); + if (mount(mntp->mnt_special, mntp->mnt_mountp, mntflags, fstype, args, - sizeof (*args), mntp->mnt_mntopts, MAX_MNTOPT_STR) < 0) { + sizeof (*args), mntp->mnt_mntopts, MAX_MNTOPT_STR) < 0) { if (errno != ENOENT) { pr_err(gettext("mount: %s: %s\n"), - mntp->mnt_mountp, strerror(errno)); + mntp->mnt_mountp, strerror(errno)); } else { struct stat sb; if (stat(mntp->mnt_mountp, &sb) < 0 && errno == ENOENT) pr_err(gettext("mount: %s: %s\n"), - mntp->mnt_mountp, strerror(ENOENT)); + mntp->mnt_mountp, strerror(ENOENT)); else pr_err("%s: %s\n", mntp->mnt_special, - strerror(ENOENT)); + strerror(ENOENT)); } last_error = RET_ERR; @@ -1027,9 +1038,9 @@ set_args(int *mntflags, struct nfs_args *args, char *fshost, struct mnttab *mnt) case OPT_SECURE: if (nfs_getseconfig_byname("dh", &nfs_sec)) { - pr_err(gettext("can not get \"dh\" from %s\n"), - NFSSEC_CONF); - goto badopt; + pr_err(gettext("can not get \"dh\" from %s\n"), + NFSSEC_CONF); + goto badopt; } sec_opt++; break; @@ -1070,7 +1081,7 @@ set_args(int *mntflags, struct nfs_args *args, char *fshost, struct mnttab *mnt) if (bad(val)) goto badopt; args->acdirmin = args->acregmin = args->acdirmax - = args->acregmax = atoi(val); + = args->acregmax = atoi(val); break; case OPT_ACREGMIN: args->flags |= NFSMNT_ACREGMIN; @@ -1130,12 +1141,15 @@ set_args(int *mntflags, struct nfs_args *args, char *fshost, struct mnttab *mnt) (void) strncpy(nfs_proto, val, strlen(val)+1); break; + case OPT_NOPRINT: args->flags |= NFSMNT_NOPRINT; break; + case OPT_LARGEFILES: largefiles = 1; break; + case OPT_NOLARGEFILES: pr_err(gettext("NFS can't support \"nolargefiles\"\n")); free(optstr); @@ -1143,9 +1157,9 @@ set_args(int *mntflags, struct nfs_args *args, char *fshost, struct mnttab *mnt) case OPT_SEC: if (nfs_getseconfig_byname(val, &nfs_sec)) { - pr_err(gettext("can not get \"%s\" from %s\n"), - val, NFSSEC_CONF); - return (RET_ERR); + pr_err(gettext("can not get \"%s\" from %s\n"), + val, NFSSEC_CONF); + return (RET_ERR); } sec_opt++; break; @@ -1244,18 +1258,18 @@ make_secure(struct nfs_args *args, char *hostname, struct netconfig *nconf, */ if (!snego_done && !sec_opt) { /* - * Get default security mode. - * AUTH_UNIX has been the default choice for a long time. - * The better NFS security service becomes, the better chance - * we will set stronger security service as the default NFS - * security mode. - * + * Get default security mode. + * AUTH_UNIX has been the default choice for a long time. + * The better NFS security service becomes, the better chance + * we will set stronger security service as the default NFS + * security mode. */ - if (nfs_getseconfig_default(&nfs_sec)) { - pr_err(gettext("error getting default security entry\n")); - return (-1); - } - args->flags |= NFSMNT_SECDEFAULT; + if (nfs_getseconfig_default(&nfs_sec)) { + pr_err(gettext("error getting default" + " security entry\n")); + return (-1); + } + args->flags |= NFSMNT_SECDEFAULT; } /* @@ -1280,10 +1294,9 @@ make_secure(struct nfs_args *args, char *hostname, struct netconfig *nconf, * If using the public fh or nfsv4, we will not contact the * remote RPCBINDer, since it is possibly behind a firewall. */ - if (use_pubfh == FALSE && vers != NFS_V4) { + if (use_pubfh == FALSE && vers != NFS_V4) syncaddr = get_the_addr(hostname, RPCBPROG, RPCBVERS, - nconf, 0, NULL, NULL, FALSE, NULL, NULL); - } + nconf, 0, NULL, NULL, FALSE, NULL, NULL); if (syncaddr != NULL) { /* for flags in sec_data */ @@ -1298,9 +1311,9 @@ make_secure(struct nfs_args *args, char *hostname, struct netconfig *nconf, error = netdir_getbyname(nconf, &hs, &retaddrs); if (error != ND_OK && (nfs_sec.sc_rpcnum == AUTH_DH)) { - pr_err(gettext("%s: secure: no time service\n"), - hostname); - return (-1); + pr_err(gettext("%s: secure: no time service\n"), + hostname); + return (-1); } if (error == ND_OK) @@ -1312,15 +1325,15 @@ make_secure(struct nfs_args *args, char *hostname, struct netconfig *nconf, * and netname data. */ if (vers == NFS_V4 && syncaddr && - host2netname(netname, hostname, NULL)) { - args->syncaddr = malloc(sizeof (struct netbuf)); - args->syncaddr->buf = malloc(syncaddr->len); - (void) memcpy(args->syncaddr->buf, syncaddr->buf, - syncaddr->len); - args->syncaddr->len = syncaddr->len; - args->syncaddr->maxlen = syncaddr->maxlen; - args->netname = strdup(netname); - args->flags |= NFSMNT_SECURE; + host2netname(netname, hostname, NULL)) { + args->syncaddr = malloc(sizeof (struct netbuf)); + args->syncaddr->buf = malloc(syncaddr->len); + (void) memcpy(args->syncaddr->buf, + syncaddr->buf, syncaddr->len); + args->syncaddr->len = syncaddr->len; + args->syncaddr->maxlen = syncaddr->maxlen; + args->netname = strdup(netname); + args->flags |= NFSMNT_SECURE; } } } @@ -1332,7 +1345,7 @@ make_secure(struct nfs_args *args, char *hostname, struct netconfig *nconf, * extended data structure. */ if (!(secdata = nfs_clnt_secdata(&nfs_sec, hostname, args->knconf, - syncaddr, flags))) { + syncaddr, flags))) { pr_err(gettext("errors constructing security related data\n")); if (flags & AUTH_F_RPCTIMESYNC) { free(syncaddr->buf); @@ -1382,11 +1395,11 @@ get_the_addr(char *hostname, ulong_t prog, ulong_t vers, return (NULL); if ((fd = t_open(nconf->nc_device, O_RDWR, tinfo)) == -1) - goto done; + goto done; /* LINTED pointer alignment */ if ((tbind = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR)) - == NULL) + == NULL) goto done; /* @@ -1402,7 +1415,7 @@ get_the_addr(char *hostname, ulong_t prog, ulong_t vers, /* NFS where vers==4 does not support UDP */ if (vers == NFS_V4 && strncasecmp(nconf->nc_proto, NC_UDP, - strlen(NC_UDP)) == 0) { + strlen(NC_UDP)) == 0) { SET_ERR_RET(error, ERR_PROTO_UNSUPP, 0); goto done; } @@ -1425,7 +1438,7 @@ get_the_addr(char *hostname, ulong_t prog, ulong_t vers, goto done; } memcpy(tbind->addr.buf, retaddrs->n_addrs->buf, - retaddrs->n_addrs->len); + retaddrs->n_addrs->len); tbind->addr.len = retaddrs->n_addrs->len; netdir_free((void *)retaddrs, ND_ADDRLIST); (void) netdir_options(nconf, ND_SET_RESERVEDPORT, fd, NULL); @@ -1441,10 +1454,10 @@ get_the_addr(char *hostname, ulong_t prog, ulong_t vers, /* LINTED pointer alignment */ if (strcmp(nconf->nc_protofmly, NC_INET) == 0) ((struct sockaddr_in *)tbind->addr.buf)->sin_port - = port; + = port; else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) ((struct sockaddr_in6 *)tbind->addr.buf)->sin6_port - = port; + = port; } @@ -1476,139 +1489,145 @@ get_the_addr(char *hostname, ulong_t prog, ulong_t vers, (void) clnt_control(cl, CLSET_TIMEOUT, (char *)&tv); if ((get_pubfh == TRUE) && (vers != NFS_V4)) { - enum snego_stat sec; + enum snego_stat sec; - if (!snego_done) { - /* - * negotiate sec flavor. - */ - snego.cnt = 0; - if ((sec = nfs_sec_nego(vers, cl, fspath, &snego)) == - SNEGO_SUCCESS) { - int jj; - - /* - * check if server supports the one - * specified in the sec= option. - */ - if (sec_opt) { - for (jj = 0; jj < snego.cnt; jj++) { - if (snego.array[jj] == nfs_sec.sc_nfsnum) { - snego_done = TRUE; - break; - } - } - } + if (!snego_done) { + /* + * negotiate sec flavor. + */ + snego.cnt = 0; + if ((sec = nfs_sec_nego(vers, cl, fspath, &snego)) == + SNEGO_SUCCESS) { + int jj; - /* - * find a common sec flavor - */ - if (!snego_done) { - if (sec_opt) { - pr_err(gettext( - "Server does not support the security" - " flavor specified.\n")); - } - for (jj = 0; jj < snego.cnt; jj++) { - if (!nfs_getseconfig_bynumber(snego.array[jj], - &nfs_sec)) { - snego_done = TRUE; + /* + * check if server supports the one + * specified in the sec= option. + */ if (sec_opt) { - pr_err(gettext( - "Security flavor %d was negotiated and" - " will be used.\n"), - nfs_sec.sc_nfsnum); + for (jj = 0; jj < snego.cnt; jj++) { + if (snego.array[jj] == + nfs_sec.sc_nfsnum) { + snego_done = TRUE; + break; + } + } } - break; - } - } - } - if (!snego_done) - return (NULL); - /* - * Now that the flavor has been - * negotiated, get the fh. - * - * First, create an auth handle using the negotiated - * sec flavor in the next lookup to - * fetch the filehandle. - */ - new_ah = nfs_create_ah(cl, hostname, &nfs_sec); - if (new_ah == NULL) - goto done; - cl->cl_auth = new_ah; - } else if (sec == SNEGO_ARRAY_TOO_SMALL || sec == - SNEGO_FAILURE) { - goto done; - } - /* - * Note that if sec == SNEGO_DEF_VALID - * default sec flavor is acceptable. - * Use it to get the filehandle. - */ - } + /* + * find a common sec flavor + */ + if (!snego_done) { + if (sec_opt) { + pr_err(gettext( + "Server does not support" + " the security flavor" + " specified.\n")); + } - if (vers == NFS_VERSION) { - wnl_diropargs arg; - wnl_diropres *res; + for (jj = 0; jj < snego.cnt; jj++) { + if (!nfs_getseconfig_bynumber( + snego.array[jj], + &nfs_sec)) { + snego_done = TRUE; +#define EMSG80SUX "Security flavor %d was negotiated and will be used.\n" + if (sec_opt) + pr_err(gettext( + EMSG80SUX), + nfs_sec. + sc_nfsnum); + break; + } + } + } - memset((char *)&arg.dir, 0, sizeof (wnl_fh)); - arg.name = fspath; - res = wnlproc_lookup_2(&arg, cl); + if (!snego_done) + return (NULL); - if (res == NULL || res->status != NFS_OK) - goto done; - *fhp = malloc(sizeof (wnl_fh)); + /* + * Now that the flavor has been + * negotiated, get the fh. + * + * First, create an auth handle using the + * negotiated sec flavor in the next lookup to + * fetch the filehandle. + */ + new_ah = nfs_create_ah(cl, hostname, &nfs_sec); + if (new_ah == NULL) + goto done; + cl->cl_auth = new_ah; + } else if (sec == SNEGO_ARRAY_TOO_SMALL || sec == + SNEGO_FAILURE) { + goto done; + } - if (*fhp == NULL) { - pr_err(gettext("no memory\n")); - goto done; + /* + * Note that if sec == SNEGO_DEF_VALID + * default sec flavor is acceptable. + * Use it to get the filehandle. + */ } - memcpy((char *)*fhp, - (char *)&res->wnl_diropres_u.wnl_diropres.file, - sizeof (wnl_fh)); - } else { - WNL_LOOKUP3args arg; - WNL_LOOKUP3res *res; - nfs_fh3 *fh3p; + if (vers == NFS_VERSION) { + wnl_diropargs arg; + wnl_diropres *res; - memset((char *)&arg.what.dir, 0, sizeof (wnl_fh3)); - arg.what.name = fspath; - res = wnlproc3_lookup_3(&arg, cl); + memset((char *)&arg.dir, 0, sizeof (wnl_fh)); + arg.name = fspath; + res = wnlproc_lookup_2(&arg, cl); - if (res == NULL || res->status != NFS3_OK) - goto done; + if (res == NULL || res->status != NFS_OK) + goto done; + *fhp = malloc(sizeof (wnl_fh)); - fh3p = (nfs_fh3 *)malloc(sizeof (*fh3p)); + if (*fhp == NULL) { + pr_err(gettext("no memory\n")); + goto done; + } - if (fh3p == NULL) { - pr_err(gettext("no memory\n")); - CLNT_FREERES(cl, xdr_WNL_LOOKUP3res, (char *)res); - goto done; - } + memcpy((char *)*fhp, + (char *)&res->wnl_diropres_u.wnl_diropres.file, + sizeof (wnl_fh)); + } else { + WNL_LOOKUP3args arg; + WNL_LOOKUP3res *res; + nfs_fh3 *fh3p; - fh3p->fh3_length = - res->WNL_LOOKUP3res_u.res_ok.object.data.data_len; - memcpy(fh3p->fh3_u.data, - res->WNL_LOOKUP3res_u.res_ok.object.data.data_val, - fh3p->fh3_length); + memset((char *)&arg.what.dir, 0, sizeof (wnl_fh3)); + arg.what.name = fspath; + res = wnlproc3_lookup_3(&arg, cl); - *fhp = (caddr_t)fh3p; + if (res == NULL || res->status != NFS3_OK) + goto done; - CLNT_FREERES(cl, xdr_WNL_LOOKUP3res, (char *)res); - } + fh3p = (nfs_fh3 *)malloc(sizeof (*fh3p)); + + if (fh3p == NULL) { + pr_err(gettext("no memory\n")); + CLNT_FREERES(cl, xdr_WNL_LOOKUP3res, + (char *)res); + goto done; + } + + fh3p->fh3_length = + res->WNL_LOOKUP3res_u.res_ok.object.data.data_len; + memcpy(fh3p->fh3_u.data, + res->WNL_LOOKUP3res_u.res_ok.object.data.data_val, + fh3p->fh3_length); + + *fhp = (caddr_t)fh3p; + CLNT_FREERES(cl, xdr_WNL_LOOKUP3res, (char *)res); + } } else { void *res; struct rpc_err r_err; if (vers == NFS_VERSION) - res = wnlproc_null_2(NULL, cl); + res = wnlproc_null_2(NULL, cl); else if (vers == NFS_V3) - res = wnlproc3_null_3(NULL, cl); + res = wnlproc3_null_3(NULL, cl); else - res = wnlproc4_null_4(NULL, cl); + res = wnlproc4_null_4(NULL, cl); if (res == NULL) { clnt_geterr(cl, &r_err); @@ -1645,14 +1664,14 @@ get_the_addr(char *hostname, ulong_t prog, ulong_t vers, done: if (cl) { - if (ah != NULL) { - if (new_ah != NULL) - AUTH_DESTROY(ah); - AUTH_DESTROY(cl->cl_auth); - cl->cl_auth = NULL; - } - clnt_destroy(cl); - cl = NULL; + if (ah != NULL) { + if (new_ah != NULL) + AUTH_DESTROY(ah); + AUTH_DESTROY(cl->cl_auth); + cl->cl_auth = NULL; + } + clnt_destroy(cl); + cl = NULL; } if (tbind) { t_free((char *)tbind, T_BIND); @@ -1663,6 +1682,34 @@ done: return (nb); } +static int +check_nconf(struct netconfig *nconf, int nthtry, int *valid_proto) +{ + int try_test = 0; + int valid_family; + char *proto = NULL; + + + if (nthtry == FIRST_TRY) { + try_test = ((nconf->nc_semantics == NC_TPI_COTS_ORD) || + (nconf->nc_semantics == NC_TPI_COTS)); + proto = NC_TCP; + } else if (nthtry == SECOND_TRY) { + try_test = (nconf->nc_semantics == NC_TPI_CLTS); + proto = NC_UDP; + } + + if (proto && + (strcmp(nconf->nc_protofmly, NC_INET) == 0 || + strcmp(nconf->nc_protofmly, NC_INET6) == 0) && + (strcmp(nconf->nc_proto, proto) == 0)) + *valid_proto = TRUE; + else + *valid_proto = FALSE; + + return (try_test); +} + /* * Get a network address on "hostname" for program "prog" * with version "vers". If the port number is specified (non zero) @@ -1704,7 +1751,7 @@ get_addr(char *hostname, ulong_t prog, ulong_t vers, struct netconfig **nconfp, if (nconfp && *nconfp) return (get_the_addr(hostname, prog, vers, *nconfp, port, - tinfo, fhp, get_pubfh, fspath, error)); + tinfo, fhp, get_pubfh, fspath, error)); /* * No nconf passed in. * @@ -1739,17 +1786,15 @@ get_addr(char *hostname, ulong_t prog, ulong_t vers, struct netconfig **nconfp, SET_ERR_RET(error, ERR_PROTO_UNSUPP, 0); if ((port != 0) && - ((strcmp(nconf->nc_protofmly, NC_INET) == 0 || - strcmp(nconf->nc_protofmly, NC_INET6) == 0) && - (strcmp(nconf->nc_proto, NC_TCP) != 0 && - strcmp(nconf->nc_proto, NC_UDP) != 0))) - + ((strcmp(nconf->nc_protofmly, NC_INET) == 0 || + strcmp(nconf->nc_protofmly, NC_INET6) == 0) && + (strcmp(nconf->nc_proto, NC_TCP) != 0 && + strcmp(nconf->nc_proto, NC_UDP) != 0))) { continue; - - else { + } else { nb = get_the_addr(hostname, prog, - vers, nconf, port, tinfo, - fhp, get_pubfh, fspath, error); + vers, nconf, port, tinfo, + fhp, get_pubfh, fspath, error); if (nb != NULL) break; @@ -1758,12 +1803,12 @@ get_addr(char *hostname, ulong_t prog, ulong_t vers, struct netconfig **nconfp, if (error) { if (error->error_type == ERR_NOHOST) SET_ERR_RET(&errsave_nohost, - error->error_type, - error->error_value); + error->error_type, + error->error_value); if (error->error_type == ERR_RPCERROR) SET_ERR_RET(&errsave_rpcerr, - error->error_type, - error->error_value); + error->error_type, + error->error_value); } /* * continue with same protocol @@ -1777,51 +1822,24 @@ get_addr(char *hostname, ulong_t prog, ulong_t vers, struct netconfig **nconfp, goto done; if ((nb = get_the_addr(hostname, prog, vers, nconf, port, - tinfo, fhp, get_pubfh, fspath, error)) == NULL) + tinfo, fhp, get_pubfh, fspath, error)) == NULL) goto done; - - } else { retry: SET_ERR_RET(error, ERR_NETPATH, 0); while (nconf = getnetpath(nc)) { SET_ERR_RET(error, ERR_PROTO_NONE, 0); - if (nconf->nc_flag & NC_VISIBLE) { - if (nthtry == FIRST_TRY) { - if ((nconf->nc_semantics == - NC_TPI_COTS_ORD) || - (nconf->nc_semantics == - NC_TPI_COTS)) { - if (port == 0) - break; + if (nconf->nc_flag & NC_VISIBLE) { + int valid_proto; - if ((strcmp(nconf->nc_protofmly, - NC_INET) == 0 || - strcmp(nconf-> - nc_protofmly, - NC_INET6) == 0) && - (strcmp(nconf->nc_proto, - NC_TCP) == 0)) + if (check_nconf(nconf, + nthtry, &valid_proto)) { + if (port == 0) + break; - break; - } - } - if (nthtry == SECOND_TRY) { - if (nconf->nc_semantics == - NC_TPI_CLTS) { - if (port == 0) - break; - if ((strcmp(nconf->nc_protofmly, - NC_INET) == 0 || - strcmp(nconf-> - nc_protofmly, NC_INET6) - == 0) && - (strcmp( - nconf->nc_proto, - NC_UDP) == 0)) - break; - } + if (valid_proto == TRUE) + break; } } } /* while */ @@ -1835,18 +1853,18 @@ retry: goto done; } else { if ((nb = get_the_addr(hostname, prog, vers, nconf, - port, tinfo, fhp, get_pubfh, fspath, error)) - == NULL) { + port, tinfo, fhp, get_pubfh, fspath, error)) + == NULL) { /* nb is NULL - deal with errors */ if (error) { if (error->error_type == ERR_NOHOST) SET_ERR_RET(&errsave_nohost, - error->error_type, - error->error_value); + error->error_type, + error->error_value); if (error->error_type == ERR_RPCERROR) SET_ERR_RET(&errsave_rpcerr, - error->error_type, - error->error_value); + error->error_type, + error->error_value); } /* * Continue the same search path in the @@ -1880,11 +1898,11 @@ done: */ if (errsave_nohost.error_type != ERR_PROTO_NONE) SET_ERR_RET(error, errsave_nohost.error_type, - errsave_nohost.error_value); + errsave_nohost.error_value); if (errsave_rpcerr.error_type != ERR_PROTO_NONE) SET_ERR_RET(error, errsave_rpcerr.error_type, - errsave_rpcerr.error_value); + errsave_rpcerr.error_value); } return (nb); @@ -1913,9 +1931,8 @@ get_fh_via_pub(struct nfs_args *args, char *fshost, char *fspath, bool_t url, if (url == FALSE) { path = malloc(strlen(fspath) + 2); if (path == NULL) { - if (loud == TRUE) { + if (loud == TRUE) pr_err(gettext("no memory\n")); - } return (RET_ERR); } @@ -1932,7 +1949,7 @@ get_fh_via_pub(struct nfs_args *args, char *fshost, char *fspath, bool_t url, * getaddr_nfs will also fill in the fh for us. */ r = getaddr_nfs(args, fshost, nconfp, - TRUE, path, port, NULL, FALSE); + TRUE, path, port, NULL, FALSE); if (r == RET_OK) { /* @@ -1959,13 +1976,12 @@ get_fh_via_pub(struct nfs_args *args, char *fshost, char *fspath, bool_t url, } } - if (fspath != path) { + if (fspath != path) free(path); - } if (loud == TRUE) { pr_err(gettext("Could not use public filehandle in request to" - " server %s\n"), fshost); + " server %s\n"), fshost); } return (r); @@ -2041,9 +2057,8 @@ get_fh(struct nfs_args *args, char *fshost, char *fspath, int *versp, /* Let's hope for the best */ nfsvers_to_use = NFS_V4; - retval = - getaddr_nfs(args, fshost, nconfp, FALSE, - fspath, port, &error, vers_min == NFS_V4); + retval = getaddr_nfs(args, fshost, nconfp, FALSE, + fspath, port, &error, vers_min == NFS_V4); if (retval == RET_OK) { *versp = nfsvers_to_use = NFS_V4; @@ -2060,9 +2075,8 @@ get_fh(struct nfs_args *args, char *fshost, char *fspath, int *versp, vers_to_try--; /* If no more versions to try, let the user know. */ - if (vers_to_try < vers_min) { + if (vers_to_try < vers_min) return (retval); - } /* * If we are here, there are more versions to try but @@ -2076,7 +2090,7 @@ get_fh(struct nfs_args *args, char *fshost, char *fspath, int *versp, } while ((cl = clnt_create_vers(fshost, MOUNTPROG, &outvers, - vers_min, vers_to_try, "datagram_v")) == NULL) { + vers_min, vers_to_try, "datagram_v")) == NULL) { if (rpc_createerr.cf_stat == RPC_UNKNOWNHOST) { pr_err(gettext("%s: %s\n"), fshost, clnt_spcreateerror("")); @@ -2087,7 +2101,7 @@ get_fh(struct nfs_args *args, char *fshost, char *fspath, int *versp, * We don't want to downgrade version on lost packets */ if ((rpc_createerr.cf_stat == RPC_TIMEDOUT) || - (rpc_createerr.cf_stat == RPC_PMAPFAILURE)) { + (rpc_createerr.cf_stat == RPC_PMAPFAILURE)) { pr_err(gettext("%s: %s\n"), fshost, clnt_spcreateerror("")); return (RET_RETRY); @@ -2148,7 +2162,7 @@ get_fh(struct nfs_args *args, char *fshost, char *fspath, int *versp, case MOUNTVERS_POSIX: *versp = nfsvers_to_use = NFS_VERSION; rpc_stat = clnt_call(cl, MOUNTPROC_MNT, xdr_dirpath, - (caddr_t)&fspath, xdr_fhstatus, (caddr_t)&fhs, timeout); + (caddr_t)&fspath, xdr_fhstatus, (caddr_t)&fhs, timeout); if (rpc_stat != RPC_SUCCESS) { pr_err(gettext("%s:%s: server not responding %s\n"), fshost, fspath, clnt_sperror(cl, "")); @@ -2158,13 +2172,14 @@ get_fh(struct nfs_args *args, char *fshost, char *fspath, int *versp, if ((errno = fhs.fhs_status) != MNT_OK) { if (loud_on_mnt_err) { - if (errno == EACCES) { - pr_err(gettext("%s:%s: access denied\n"), - fshost, fspath); - } else { - pr_err(gettext("%s:%s: %s\n"), fshost, fspath, - strerror(errno)); - } + if (errno == EACCES) { + pr_err(gettext( + "%s:%s: access denied\n"), + fshost, fspath); + } else { + pr_err(gettext("%s:%s: %s\n"), fshost, + fspath, strerror(errno)); + } } clnt_destroy(cl); return (RET_MNTERR); @@ -2175,11 +2190,11 @@ get_fh(struct nfs_args *args, char *fshost, char *fspath, int *versp, return (RET_ERR); } memcpy((caddr_t)args->fh, (caddr_t)&fhs.fhstatus_u.fhs_fhandle, - sizeof (fhs.fhstatus_u.fhs_fhandle)); + sizeof (fhs.fhstatus_u.fhs_fhandle)); if (!errno && posix) { rpc_stat = clnt_call(cl, MOUNTPROC_PATHCONF, - xdr_dirpath, (caddr_t)&fspath, xdr_ppathcnf, - (caddr_t)&p, timeout); + xdr_dirpath, (caddr_t)&fspath, xdr_ppathcnf, + (caddr_t)&p, timeout); if (rpc_stat != RPC_SUCCESS) { pr_err(gettext( "%s:%s: server not responding %s\n"), @@ -2205,15 +2220,15 @@ get_fh(struct nfs_args *args, char *fshost, char *fspath, int *versp, return (RET_ERR); } memcpy((caddr_t)args->pathconf, (caddr_t)&p, - sizeof (p)); + sizeof (p)); } break; case MOUNTVERS3: *versp = nfsvers_to_use = NFS_V3; rpc_stat = clnt_call(cl, MOUNTPROC_MNT, xdr_dirpath, - (caddr_t)&fspath, - xdr_mountres3, (caddr_t)&mountres3, timeout); + (caddr_t)&fspath, xdr_mountres3, (caddr_t)&mountres3, + timeout); if (rpc_stat != RPC_SUCCESS) { pr_err(gettext("%s:%s: server not responding %s\n"), fshost, fspath, clnt_sperror(cl, "")); @@ -2226,25 +2241,26 @@ get_fh(struct nfs_args *args, char *fshost, char *fspath, int *versp, * codes map into E* errors. */ if ((errno = mountres3.fhs_status) != MNT_OK) { - if (loud_on_mnt_err) { - switch (errno) { - case MNT3ERR_NAMETOOLONG: - msg = "path name is too long"; - break; - case MNT3ERR_NOTSUPP: - msg = "operation not supported"; - break; - case MNT3ERR_SERVERFAULT: - msg = "server fault"; - break; - default: - msg = strerror(errno); - break; + if (loud_on_mnt_err) { + switch (errno) { + case MNT3ERR_NAMETOOLONG: + msg = "path name is too long"; + break; + case MNT3ERR_NOTSUPP: + msg = "operation not supported"; + break; + case MNT3ERR_SERVERFAULT: + msg = "server fault"; + break; + default: + msg = strerror(errno); + break; + } + pr_err(gettext("%s:%s: %s\n"), fshost, + fspath, msg); } - pr_err(gettext("%s:%s: %s\n"), fshost, fspath, msg); - } - clnt_destroy(cl); - return (RET_MNTERR); + clnt_destroy(cl); + return (RET_MNTERR); } fh3p = (nfs_fh3 *)malloc(sizeof (*fh3p)); @@ -2253,10 +2269,10 @@ get_fh(struct nfs_args *args, char *fshost, char *fspath, int *versp, return (RET_ERR); } fh3p->fh3_length = - mountres3.mountres3_u.mountinfo.fhandle.fhandle3_len; + mountres3.mountres3_u.mountinfo.fhandle.fhandle3_len; (void) memcpy(fh3p->fh3_u.data, - mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val, - fh3p->fh3_length); + mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val, + fh3p->fh3_length); args->fh = (caddr_t)fh3p; fstype = MNTTYPE_NFS3; @@ -2274,30 +2290,33 @@ get_fh(struct nfs_args *args, char *fshost, char *fspath, int *versp, * */ auths = - mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_val; + mountres3.mountres3_u.mountinfo.auth_flavors + .auth_flavors_val; count = - mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_len; + mountres3.mountres3_u.mountinfo.auth_flavors + .auth_flavors_len; if (sec_opt) { for (i = 0; i < count; i++) { if (auths[i] == nfs_sec.sc_nfsnum) - break; + break; } - if (i >= count) { + if (i >= count) goto autherr; - } } else { - if (count > 0) { - for (i = 0; i < count; i++) { - if (!nfs_getseconfig_bynumber(auths[i], &nfs_sec)) { - sec_opt++; + if (count < 0) break; - } - } - if (i >= count) { - goto autherr; + + for (i = 0; i < count; i++) { + if (!nfs_getseconfig_bynumber(auths[i], + &nfs_sec)) { + sec_opt++; + break; + } } - } + + if (i >= count) + goto autherr; } break; default: @@ -2312,8 +2331,8 @@ get_fh(struct nfs_args *args, char *fshost, char *fspath, int *versp, autherr: pr_err(gettext( - "security mode does not match the server exporting %s:%s\n"), - fshost, fspath); + "security mode does not match the server exporting %s:%s\n"), + fshost, fspath); clnt_destroy(cl); return (RET_ERR); } @@ -2388,19 +2407,19 @@ getaddr_nfs(struct nfs_args *args, char *fshost, struct netconfig **nconfp, /* no error print at this time */ break; pr_err(gettext("%s NFS service not" - " available %s\n"), fshost, + " available %s\n"), fshost, clnt_sperrno(addr_error.error_value)); printed = 1; break; case ERR_NETPATH: pr_err(gettext("%s: Error in NETPATH.\n"), - fshost); + fshost); printed = 1; break; case ERR_PROTO_INVALID: pr_err(gettext("%s: NFS service does not" - " recognize protocol: %s.\n"), fshost, - nfs_proto); + " recognize protocol: %s.\n"), fshost, + nfs_proto); printed = 1; break; case ERR_PROTO_UNSUPP: @@ -2423,8 +2442,8 @@ getaddr_nfs(struct nfs_args *args, char *fshost, struct netconfig **nconfp, * and retry below. */ pr_err(gettext("%s: NFS service does" - " not support protocol: %s.\n"), - fshost, nfs_proto); + " not support protocol: %s.\n"), + fshost, nfs_proto); } break; case ERR_NOHOST: @@ -2434,20 +2453,20 @@ getaddr_nfs(struct nfs_args *args, char *fshost, struct netconfig **nconfp, default: /* case ERR_PROTO_NONE falls through */ pr_err(gettext("%s: NFS service not responding" - "\n"), fshost); + "\n"), fshost); printed = 1; break; } } SET_ERR_RET(error, - addr_error.error_type, addr_error.error_value); + addr_error.error_type, addr_error.error_value); if (addr_error.error_type == ERR_PROTO_NONE) return (RET_RETRY); else if (addr_error.error_type == ERR_RPCERROR && - ! IS_UNRECOVERABLE_RPC(addr_error.error_value)) { + !IS_UNRECOVERABLE_RPC(addr_error.error_value)) { return (RET_RETRY); } else if (nfsvers == 0 && addr_error.error_type == - ERR_PROTO_UNSUPP && nfsvers_to_use != NFS_VERSMIN) { + ERR_PROTO_UNSUPP && nfsvers_to_use != NFS_VERSMIN) { /* * If no version is specified, and the error is due * to an unsupported transport, then decrement the @@ -2520,10 +2539,10 @@ retry(struct mnttab *mntp, int ro) break; if (count > 0) { - (void) sleep(delay); - delay *= 2; - if (delay > 120) - delay = 120; + (void) sleep(delay); + delay *= 2; + if (delay > 120) + delay = 120; } } diff --git a/usr/src/cmd/fs.d/nfs/nfsstat/nfsstat.c b/usr/src/cmd/fs.d/nfs/nfsstat/nfsstat.c index 5680d59174..e97dc9cbff 100644 --- a/usr/src/cmd/fs.d/nfs/nfsstat/nfsstat.c +++ b/usr/src/cmd/fs.d/nfs/nfsstat/nfsstat.c @@ -116,6 +116,13 @@ static int count; /* number of iterations the stat is printed */ #define MAX_COLUMNS 80 #define MAX_PATHS 50 /* max paths that can be taken by -m */ +/* + * MI4_MIRRORMOUNT is canonically defined in nfs4_clnt.h, but we cannot + * include that file here. + */ +#define MI4_MIRRORMOUNT 0x4000 +#define NFS_V4 4 + static int req_width(kstat_t *, int); static int stat_width(kstat_t *, int); static char *path [MAX_PATHS] = {NULL}; /* array to store the multiple paths */ @@ -157,7 +164,7 @@ main(int argc, char *argv[]) int vflag = 0; /* version specified, 0 specifies all */ int zflag = 0; /* zero stats after printing */ char *split_line = "*******************************************" - "*************************************"; + "*************************************"; interval = 0; count = 0; @@ -226,7 +233,8 @@ main(int argc, char *argv[]) } else if (mflag) { if (cflag || rflag || sflag || zflag || nflag || aflag || vflag) - fail(0, "The -m flag may not be used with any other flags"); + fail(0, + "The -m flag may not be used with any other flags"); for (j = 0; (argc - optind > 0) && (j < (MAX_PATHS - 1)); j++) { path[j] = argv[optind]; @@ -238,8 +246,7 @@ main(int argc, char *argv[]) path[j] = NULL; if (argc - optind > 0) fprintf(stderr, "Only the first 50 paths " - "will be searched for\n"); - + "will be searched for\n"); } setup(); @@ -270,8 +277,8 @@ main(int argc, char *argv[]) (rpc_clts_client_kstat == NULL || nfs_client_kstat == NULL)) { fprintf(stderr, - "nfsstat: kernel is not configured with" - " the client nfs and rpc code.\n"); + "nfsstat: kernel is not configured with" + " the client nfs and rpc code.\n"); } if (cflag || (!sflag && !cflag)) { if (rflag || (!rflag && !nflag && !aflag)) @@ -537,7 +544,7 @@ req_width(kstat_t *req, int field_width) else per = 0; (void) sprintf(fixlen, "%" PRIu64 " %d%%", - knp[i].value.ui64, per); + knp[i].value.ui64, per); len = strlen(fixlen) + 1; if (field_width < len) field_width = len; @@ -577,15 +584,12 @@ cr_print(int zflag) return; stat_print("\nClient rpc:\nConnection oriented:", - rpc_cots_client_kstat, - &old_rpc_cots_client_kstat.kst, field_width, - zflag); + rpc_cots_client_kstat, + &old_rpc_cots_client_kstat.kst, field_width, zflag); stat_print("Connectionless:", rpc_clts_client_kstat, - &old_rpc_clts_client_kstat.kst, field_width, - zflag); + &old_rpc_clts_client_kstat.kst, field_width, zflag); stat_print("RDMA based:", rpc_rdma_client_kstat, - &old_rpc_rdma_client_kstat.kst, field_width, - zflag); + &old_rpc_rdma_client_kstat.kst, field_width, zflag); } static void @@ -598,14 +602,11 @@ sr_print(int zflag) return; stat_print("\nServer rpc:\nConnection oriented:", rpc_cots_server_kstat, - &old_rpc_cots_server_kstat.kst, field_width, - zflag); + &old_rpc_cots_server_kstat.kst, field_width, zflag); stat_print("Connectionless:", rpc_clts_server_kstat, - &old_rpc_clts_server_kstat.kst, field_width, - zflag); + &old_rpc_clts_server_kstat.kst, field_width, zflag); stat_print("RDMA based:", rpc_rdma_server_kstat, - &old_rpc_rdma_server_kstat.kst, field_width, - zflag); + &old_rpc_rdma_server_kstat.kst, field_width, zflag); } static void @@ -620,37 +621,35 @@ cn_print(int zflag, int vflag) if (vflag == 0) { kstat_sum(nfs_client_kstat, nfs4_client_kstat, ksum_kstat); stat_print("\nClient nfs:", ksum_kstat, &old_ksum_kstat.kst, - field_width, zflag); + field_width, zflag); } if (vflag == 2 || vflag == 3) { stat_print("\nClient nfs:", nfs_client_kstat, - &old_nfs_client_kstat.kst, - field_width, zflag); + &old_nfs_client_kstat.kst, field_width, zflag); } if (vflag == 4) { stat_print("\nClient nfs:", nfs4_client_kstat, - &old_nfs4_client_kstat.kst, - field_width, zflag); + &old_nfs4_client_kstat.kst, field_width, zflag); } if (vflag == 2 || vflag == 0) { field_width = getstats_rfsreq(2); req_print(rfsreqcnt_v2_kstat, &old_rfsreqcnt_v2_kstat.kst, - 2, field_width, zflag); + 2, field_width, zflag); } if (vflag == 3 || vflag == 0) { field_width = getstats_rfsreq(3); req_print(rfsreqcnt_v3_kstat, &old_rfsreqcnt_v3_kstat.kst, 3, - field_width, zflag); + field_width, zflag); } if (vflag == 4 || vflag == 0) { field_width = getstats_rfsreq(4); req_print_v4(rfsreqcnt_v4_kstat, &old_rfsreqcnt_v4_kstat.kst, - field_width, zflag); + field_width, zflag); } } @@ -665,39 +664,35 @@ sn_print(int zflag, int vflag) if (vflag == 2 || vflag == 0) { stat_print("\nServer NFSv2:", nfs_server_v2_kstat, - &old_nfs_server_v2_kstat.kst, - field_width, zflag); + &old_nfs_server_v2_kstat.kst, field_width, zflag); } if (vflag == 3 || vflag == 0) { stat_print("\nServer NFSv3:", nfs_server_v3_kstat, - &old_nfs_server_v3_kstat.kst, - field_width, zflag); + &old_nfs_server_v3_kstat.kst, field_width, zflag); } if (vflag == 4 || vflag == 0) { stat_print("\nServer NFSv4:", nfs_server_v4_kstat, - &old_nfs_server_v4_kstat.kst, - field_width, zflag); + &old_nfs_server_v4_kstat.kst, field_width, zflag); } if (vflag == 2 || vflag == 0) { field_width = getstats_rfsproc(2); req_print(rfsproccnt_v2_kstat, &old_rfsproccnt_v2_kstat.kst, - 2, field_width, zflag); + 2, field_width, zflag); } if (vflag == 3 || vflag == 0) { field_width = getstats_rfsproc(3); req_print(rfsproccnt_v3_kstat, &old_rfsproccnt_v3_kstat.kst, - 3, field_width, zflag); - + 3, field_width, zflag); } if (vflag == 4 || vflag == 0) { field_width = getstats_rfsproc(4); req_print_v4(rfsproccnt_v4_kstat, &old_rfsproccnt_v4_kstat.kst, - field_width, zflag); + field_width, zflag); } } @@ -714,12 +709,12 @@ ca_print(int zflag, int vflag) if (vflag == 2 || vflag == 0) { req_print(aclreqcnt_v2_kstat, &old_aclreqcnt_v2_kstat.kst, 2, - field_width, zflag); + field_width, zflag); } if (vflag == 3 || vflag == 0) { req_print(aclreqcnt_v3_kstat, &old_aclreqcnt_v3_kstat.kst, - 3, field_width, zflag); + 3, field_width, zflag); } } @@ -736,12 +731,12 @@ sa_print(int zflag, int vflag) if (vflag == 2 || vflag == 0) { req_print(aclproccnt_v2_kstat, &old_aclproccnt_v2_kstat.kst, - 2, field_width, zflag); + 2, field_width, zflag); } if (vflag == 3 || vflag == 0) { req_print(aclproccnt_v3_kstat, &old_aclproccnt_v3_kstat.kst, - 3, field_width, zflag); + 3, field_width, zflag); } } @@ -749,7 +744,7 @@ sa_print(int zflag, int vflag) static void req_print(kstat_t *req, kstat_t *req_old, int ver, int field_width, - int zflag) + int zflag) { int i, j, nreq, per, ncolumns; uint64_t tot, old_tot; @@ -803,9 +798,9 @@ req_print(kstat_t *req, kstat_t *req_old, int ver, int field_width, else per = 0; (void) sprintf(fixlen, "%" PRIu64 " %d%% ", - ((interval && knp_old != NULL) ? - (knp[j].value.ui64 - knp_old[j].value.ui64) - : knp[j].value.ui64), per); + ((interval && knp_old != NULL) ? + (knp[j].value.ui64 - knp_old[j].value.ui64) + : knp[j].value.ui64), per); printf("%-*s", field_width, fixlen); } if (zflag) { @@ -889,9 +884,9 @@ req_print_v4(kstat_t *req, kstat_t *req_old, int field_width, int zflag) else per = 0; (void) sprintf(fixlen, "%" PRIu64 " %d%% ", - ((interval && kptr_old != NULL) ? - (knp[j].value.ui64 - kptr_old[j].value.ui64) - : knp[j].value.ui64), per); + ((interval && kptr_old != NULL) ? + (knp[j].value.ui64 - kptr_old[j].value.ui64) + : knp[j].value.ui64), per); printf("%-*s", field_width, fixlen); } printf("\n"); @@ -912,9 +907,9 @@ req_print_v4(kstat_t *req, kstat_t *req_old, int field_width, int zflag) else per = 0; (void) sprintf(fixlen, "%" PRIu64 " %d%% ", - ((interval && kptr_old != NULL) ? - (knp[j].value.ui64 - kptr_old[j].value.ui64) - : knp[j].value.ui64), per); + ((interval && kptr_old != NULL) ? + (knp[j].value.ui64 - kptr_old[j].value.ui64) + : knp[j].value.ui64), per); printf("%-*s", field_width, fixlen); } printf("\n"); @@ -931,7 +926,7 @@ req_print_v4(kstat_t *req, kstat_t *req_old, int field_width, int zflag) static void stat_print(const char *title_string, kstat_t *req, kstat_t *req_old, - int field_width, int zflag) + int field_width, int zflag) { int i, j, nreq, ncolumns; char fixlen[128]; @@ -961,9 +956,9 @@ stat_print(const char *title_string, kstat_t *req, kstat_t *req_old, /* prints out the stat numbers */ for (j = i; j < MIN(i + ncolumns, nreq); j++) { (void) sprintf(fixlen, "%" PRIu64 " ", - (interval && knp_old != NULL) ? - (knp[j].value.ui64 - knp_old[j].value.ui64) - : knp[j].value.ui64); + (interval && knp_old != NULL) ? + (knp[j].value.ui64 - knp_old[j].value.ui64) + : knp[j].value.ui64); printf("%-*s", field_width, fixlen); } printf("\n"); @@ -1050,7 +1045,7 @@ mi_print(void) * Check to see here if user gave a path(s) to * only show the mount point they wanted * Iterate through the list of paths the user gave and see - * if any of them match the our current nfs mount + * if any of them match our current nfs mount */ if (path[0] != NULL) { found = 0; @@ -1081,7 +1076,7 @@ mi_print(void) * So save the mount point now */ if ((mrp->ig_path = malloc( - strlen(m.mnt_mountp) + 1)) == 0) { + strlen(m.mnt_mountp) + 1)) == 0) { fprintf(stderr, "nfsstat: not enough memory\n"); exit(1); } @@ -1122,7 +1117,7 @@ mi_print(void) if (strcmp(mrp->ig_path, m.mnt_special) == 0) { mrp->ig_path = 0; (void) strcpy(mrp->my_dir, - m.mnt_mountp); + m.mnt_mountp); } } } @@ -1221,13 +1216,18 @@ mi_print(void) if (mik.mik_flags & MI_ACL) printf(",acl"); + if (mik.mik_vers >= NFS_V4) { + if (mik.mik_flags & MI4_MIRRORMOUNT) + printf(",mirrormount"); + } + printf(",rsize=%d,wsize=%d,retrans=%d,timeo=%d", - mik.mik_curread, mik.mik_curwrite, mik.mik_retrans, - mik.mik_timeo); + mik.mik_curread, mik.mik_curwrite, mik.mik_retrans, + mik.mik_timeo); printf("\n"); printf(" Attr cache: acregmin=%d,acregmax=%d" - ",acdirmin=%d,acdirmax=%d\n", mik.mik_acregmin, - mik.mik_acregmax, mik.mik_acdirmin, mik.mik_acdirmax); + ",acdirmin=%d,acdirmax=%d\n", mik.mik_acregmin, + mik.mik_acregmax, mik.mik_acdirmin, mik.mik_acdirmax); if (transport_flag) { printf(" Transport: proto=rdma, plugin=%s\n", @@ -1243,13 +1243,13 @@ mi_print(void) j = (i == NFS_CALLTYPES ? i - 1 : i); if (mik.mik_timers[j].srtt || mik.mik_timers[j].rtxcur) { - printf( - " %s: srtt=%d (%dms), dev=%d (%dms), cur=%u (%ums)\n", - timer_name[i], - srtt_to_ms(mik.mik_timers[i].srtt), - dev_to_ms(mik.mik_timers[i].deviate), - mik.mik_timers[i].rtxcur, - mik.mik_timers[i].rtxcur * 20); + printf(" %s: srtt=%d (%dms), " + "dev=%d (%dms), cur=%u (%ums)\n", + timer_name[i], + srtt_to_ms(mik.mik_timers[i].srtt), + dev_to_ms(mik.mik_timers[i].deviate), + mik.mik_timers[i].rtxcur, + mik.mik_timers[i].rtxcur * 20); } } @@ -1297,7 +1297,6 @@ ignore(char *opts) void usage(void) { - fprintf(stderr, "Usage: nfsstat [-cnrsza [-v version] " "[interval [count]]\n"); fprintf(stderr, "Usage: nfsstat -m [pathname..]\n"); diff --git a/usr/src/cmd/rexd/Makefile b/usr/src/cmd/rexd/Makefile index a60d269936..5817b4add5 100644 --- a/usr/src/cmd/rexd/Makefile +++ b/usr/src/cmd/rexd/Makefile @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -40,7 +40,8 @@ ROOTMANIFESTDIR= $(ROOTSVCNETWORKRPC) SRCS= $(PROG:%=%.c) #OBJS= errprintf.o mount_nfs.o rex_xdr.o unix_login.o mntent.o -OBJS= errprintf.o mount_nfs.o rex.o unix_login.o mntent.o +TYPEOBJS= nfs_subr.o +OBJS= errprintf.o mount_nfs.o rex.o unix_login.o mntent.o $(TYPEOBJS) REXDOBJS= rpc.rexd.o errprintf.o mount_nfs.o rex.o unix_login.o mntent.o ONOBJS= on.o sharetab.o where.o rex.o mntent.o #WHEREOBJS= sharetab.o where.o where_main.o mntent.o @@ -58,6 +59,8 @@ CPPFLAGS = -I. $(CPPFLAGS.master) LDLIBS += -lsocket -lnsl rpc.rexd := LDLIBS += -lrpcsvc -lbsm -lpam +TYPESRCS= ../nfs/lib/nfs_subr.c + # install rule # don't re-install directories created by Targetdirs #$(ROOTREXD)/%: % @@ -113,3 +116,6 @@ rpc.rexd.o: rex.h unix_login.o: rex.h rex.o: rex.h + +nfs_subr.o: ../fs.d/nfs/lib/nfs_subr.c + $(COMPILE.c) ../fs.d/nfs/lib/nfs_subr.c diff --git a/usr/src/cmd/rexd/mount_nfs.c b/usr/src/cmd/rexd/mount_nfs.c index 3a276b7afc..8f94b04d72 100644 --- a/usr/src/cmd/rexd/mount_nfs.c +++ b/usr/src/cmd/rexd/mount_nfs.c @@ -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. @@ -18,10 +17,12 @@ * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END - * - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ + /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ @@ -32,32 +33,34 @@ #pragma ident "%Z%%M% %I% %E% SMI" #define NFSCLIENT -#include <sys/types.h> -#include <memory.h> -#include <netconfig.h> -#include <netdb.h> -#include <netdir.h> -#include <netinet/in.h> -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <syslog.h> - -#include <rpc/rpc.h> -#include <rpc/clnt_soc.h> -#include <rpc/pmap_prot.h> -#include <nfs/nfs.h> -#include <nfs/mount.h> -#include <rpcsvc/mount.h> -#include <errno.h> -#include <sys/mntent.h> -#include <sys/mnttab.h> -#include <sys/mount.h> -#include <sys/param.h> -#include <sys/socket.h> -#include <sys/stat.h> +#include <sys/types.h> +#include <memory.h> +#include <netconfig.h> +#include <netdb.h> +#include <netdir.h> +#include <netinet/in.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <syslog.h> + +#include <rpc/rpc.h> +#include <rpc/clnt_soc.h> +#include <rpc/pmap_prot.h> +#include <nfs/nfs.h> +#include <nfs/mount.h> +#include <rpcsvc/mount.h> +#include <errno.h> +#include <sys/mntent.h> +#include <sys/mnttab.h> +#include <sys/mount.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/stat.h> + +#include <deflt.h> static struct knetconfig *get_knconf(struct netconfig *nconf); static int bindudp_resvport(CLIENT *client); @@ -68,6 +71,8 @@ static void netbuf_free(struct netbuf *nb); static struct netbuf *get_addr(char *hostname, int prog, int vers, struct netconfig **nconfp); +extern void set_nfsv4_ephemeral_mount_to(void); + #define TIME_MAX 16 extern int Debug; @@ -91,10 +96,7 @@ void free_knconf(struct knetconfig *); * The "error" string returns the error message. */ int -mount_nfs(fsname, dir, error) - char *fsname; - char *dir; - char *error; +mount_nfs(char *fsname, char *dir, char *error) { struct sockaddr_in sin; struct hostent *hp; @@ -156,7 +158,7 @@ mount_nfs(fsname, dir, error) */ if ((hp = gethostbyname(host)) == NULL) { errprintf(error, "mount %s: %s not in hosts database\n", - fsname, host); + fsname, host); return (1); } @@ -171,11 +173,11 @@ mount_nfs(fsname, dir, error) fprintf(stderr, "h_aliases %s\n\t", "<none>"); if (hp->h_addrtype == AF_INET) fprintf(stderr, - "h_addrtype AF_INET\n\th_adth_length %u\n\t", - hp->h_length); + "h_addrtype AF_INET\n\th_adth_length %u\n\t", + hp->h_length); else fprintf(stderr, "h_addrtype %u\n\th_adth_length %u\n\t", - hp->h_addrtype, hp->h_length); + hp->h_addrtype, hp->h_length); if (hp->h_addr_list[0] && *hp->h_addr_list[0]) fprintf(stderr, "h_addr_list <apparent list>\n"); else @@ -196,19 +198,19 @@ mount_nfs(fsname, dir, error) printf("clnt_create for mountproc (%d)\n", errno); client = clnt_create_vers(host, MOUNTPROG, &vers, MOUNTVERS, vers, - "udp"); + "udp"); if (client == NULL) { errprintf(error, "%s %s\n", host, - clnt_spcreateerror("mount server not responding")); + clnt_spcreateerror("mount server not responding")); return (1); } if (Debug) printf("call bindudp_resvport for mountproc (%d)\n", errno); - if (bindudp_resvport(client) < 0) { + if (bindudp_resvport(client) < 0) { errprintf(error, "mount %s:%s: %s\n", host, path, - "Couldn't bind to reserved port"); + "Couldn't bind to reserved port"); if (Debug) printf("could not bind to reserved port\n"); clnt_destroy(client); @@ -219,7 +221,7 @@ mount_nfs(fsname, dir, error) auth_destroy(client->cl_auth); if ((client->cl_auth = authsys_create_default()) == NULL) { errprintf(error, "mount %s:%s: %s\n", host, path, - "Couldn't create authsys structure"); + "Couldn't create authsys structure"); if (Debug) printf("could not create authsys structure\n"); clnt_destroy(client); @@ -234,7 +236,7 @@ mount_nfs(fsname, dir, error) */ /* set mount args */ - memset(&args, 0, sizeof(args)); + memset(&args, 0, sizeof (args)); /* Get fhandle of remote path from server's mountd */ @@ -245,14 +247,16 @@ mount_nfs(fsname, dir, error) case MOUNTVERS: case MOUNTVERS_POSIX: rpc_stat = clnt_call(client, MOUNTPROC_MNT, - xdr_dirpath, (caddr_t)&path, - xdr_fhstatus, (caddr_t)&fhs, timeout); + xdr_dirpath, (caddr_t)&path, + xdr_fhstatus, (caddr_t)&fhs, timeout); if (rpc_stat != RPC_SUCCESS) { - /* Given the way "clnt_sperror" works, the "%s" */ - /* following the "not responding" is correct. */ + /* + * Given the way "clnt_sperror" works, the "%s" + * following the "not responding" is correct. + */ errprintf(error, "mount server %s not responding %s\n", - host, clnt_sperror(client, "")); + host, clnt_sperror(client, "")); clnt_destroy(client); return (1); } @@ -262,11 +266,11 @@ mount_nfs(fsname, dir, error) if ((errno = fhs.fhs_status) != MNT_OK) { if (errno == EACCES) { errprintf(error, - "rexd mount: not in EXPORT list for %s\n", - fsname); + "rexd mount: not in EXPORT list for %s\n", + fsname); } else { errprintf(error, "rexd mount: error %d %s\n", - errno, strerror(errno)); + errno, strerror(errno)); } return (1); } @@ -277,14 +281,16 @@ mount_nfs(fsname, dir, error) case MOUNTVERS3: memset((char *)&res3, '\0', sizeof (res3)); rpc_stat = clnt_call(client, MOUNTPROC_MNT, - xdr_dirpath, (char *)&path, - xdr_mountres3, (char *)&res3, timeout); + xdr_dirpath, (char *)&path, + xdr_mountres3, (char *)&res3, timeout); if (rpc_stat != RPC_SUCCESS) { - /* Given the way "clnt_sperror" works, the "%s" */ - /* following the "not responding" is correct. */ + /* + * Given the way "clnt_sperror" works, the "%s" + * following the "not responding" is correct. + */ errprintf(error, "mount server %s not responding %s\n", - host, clnt_sperror(client, "")); + host, clnt_sperror(client, "")); clnt_destroy(client); return (1); } @@ -294,11 +300,11 @@ mount_nfs(fsname, dir, error) if ((errno = res3.fhs_status) != MNT_OK) { if (errno == EACCES) { errprintf(error, - "rexd mount: not in EXPORT list for %s\n", - fsname); + "rexd mount: not in EXPORT list for %s\n", + fsname); } else { errprintf(error, "rexd mount: error %d %s\n", - errno, strerror(errno)); + errno, strerror(errno)); } return (1); } @@ -322,7 +328,7 @@ mount_nfs(fsname, dir, error) break; default: errprintf(error, "rexd mount: unknown MOUNT version %ld\n", - vers); + vers); return (1); } @@ -353,12 +359,18 @@ mount_nfs(fsname, dir, error) flags = MS_NOSUID | MS_DATA; + /* + * And make sure that we have the ephemeral mount_to + * set for this zone. + */ + set_nfsv4_ephemeral_mount_to(); + /* Provide the mounted resource name when mounting. */ - if (mount(fsname, dir, flags, fstype, &args, sizeof(args)) < 0) { + if (mount(fsname, dir, flags, fstype, &args, sizeof (args)) < 0) { netbuf_free(args.addr); free_knconf(args.knconf); errprintf(error, "unable to mount %s on %s: %s\n", - fsname, dir, strerror(errno)); + fsname, dir, strerror(errno)); return (1); } @@ -397,8 +409,7 @@ mount_nfs(fsname, dir, error) * umount_nfs - unmount a file system when finished */ int -umount_nfs(fsname, dir) -char *fsname, *dir; +umount_nfs(char *fsname, char *dir) { char *p; char *hostname; @@ -443,7 +454,7 @@ char *fsname, *dir; } if (bindudp_resvport(client) < 0) { errprintf(NULL, "umount %s:%s:%s", hostname, p, - "Could not bind to reserved port\n"); + "Could not bind to reserved port\n"); clnt_destroy(client); return (1); } @@ -456,8 +467,8 @@ char *fsname, *dir; timeout.tv_usec = 0; timeout.tv_sec = 25; - rpc_stat = clnt_call(client, MOUNTPROC_UMNT, xdr_dirpath, (caddr_t) &p, - xdr_void, (char *)NULL, timeout); + rpc_stat = clnt_call(client, MOUNTPROC_UMNT, xdr_dirpath, (caddr_t)&p, + xdr_void, (char *)NULL, timeout); clnt_destroy(client); @@ -470,12 +481,8 @@ char *fsname, *dir; return (0); } - - - static struct mnttab * -dupmnttab(mnt) -struct mnttab *mnt; +dupmnttab(struct mnttab *mnt) { struct mnttab *new; void freemnttab(); @@ -502,7 +509,8 @@ struct mnttab *mnt; return (new); - alloc_failed: +alloc_failed: + errprintf(NULL, "dupmnttab: memory allocation failed\n"); freemnttab(new); return (NULL); @@ -514,8 +522,7 @@ struct mnttab *mnt; * Free a single mnttab structure */ static void -freemnttab(mnt) -struct mnttab *mnt; +freemnttab(struct mnttab *mnt) { if (mnt) { if (mnt->mnt_special) @@ -545,8 +552,7 @@ struct mntlist { * Free a list of mnttab structures */ static void -freemntlist(mntl) -struct mntlist *mntl; +freemntlist(struct mntlist *mntl) { struct mntlist *mntl_tmp; @@ -568,25 +574,20 @@ struct mntlist *mntl; * Returns NULL on errors. */ char * -parsefs(fullname, error) -char *fullname; -char *error; +parsefs(char *fullname, char *error) { - char *dir, - *subdir; + char *dir, *subdir; struct exportnode *ex = NULL; int err; int bestlen = 0; - int len, - dirlen; + int len, dirlen; if (Debug && errno) printf("parsefs of %s entered with errno %d %s\n", - fullname, errno, strerror(errno)); + fullname, errno, strerror(errno)); dir = strchr(fullname, ':'); if (dir == NULL) { - errprintf(error, "No host name in %s\n", fullname); return (NULL); } @@ -596,20 +597,18 @@ char *error; printf("parsefs before rpc_call: ERRNO:%d\n", errno); if (err = rpc_call(fullname, MOUNTPROG, MOUNTVERS, MOUNTPROC_EXPORT, - xdr_void, 0, xdr_exports, (char *)&ex, "udp")) { + xdr_void, 0, xdr_exports, (char *)&ex, "udp")) { if (err == (int)RPC_TIMEDOUT) errprintf(error, "Host %s is not running mountd\n", - fullname); + fullname); else errprintf(error, "RPC error %d with host %s (%s)\n", - err, fullname, clnt_sperrno(err)); + err, fullname, clnt_sperrno(err)); if (Debug && errno) { printf("parsefs: mount call to %s returned %d %s\n", - fullname, - err, - clnt_sperrno(err)); + fullname, err, clnt_sperrno(err)); printf("with errno %d:\t%s\n", errno, strerror(errno)); } return (NULL); @@ -622,9 +621,7 @@ char *error; if (Debug && errno) { printf("parsefs: mount call to %s returned %d %s\n", - fullname, - err, - clnt_sperrno(err)); + fullname, err, clnt_sperrno(err)); printf("with errno %d:\t%s\n", errno, strerror(errno)); } @@ -644,7 +641,7 @@ char *error; if (bestlen == 0) { errprintf(error, "%s not exported by %s\n", - dir, fullname); + dir, fullname); return (NULL); } @@ -659,7 +656,6 @@ char *error; return (subdir); } - /* * Get the network address for the service identified by "prog" * and "vers" on "hostname". The netconfig address is returned @@ -667,13 +663,8 @@ char *error; * If the hostname is the same as the last call, then the same * transport is used as last time (same netconfig entry). */ - - static struct netbuf * -get_addr(hostname, prog, vers, nconfp) -char *hostname; -int prog, vers; -struct netconfig **nconfp; +get_addr(char *hostname, int prog, int vers, struct netconfig **nconfp) { static char prevhost[MAXHOSTNAMELEN+1]; static struct netconfig *nconf; @@ -712,12 +703,12 @@ struct netconfig **nconfp; if (fd < 0) goto done; - tbind = (struct t_bind *) t_alloc(fd, T_BIND, T_ADDR); + tbind = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR); if (tbind == NULL) goto done; if (rpcb_getaddr(prog, vers, nconf, &tbind->addr, hostname) == 0) { - t_free((char *) tbind, T_BIND); + t_free((char *)tbind, T_BIND); tbind = NULL; goto retry; } @@ -726,7 +717,7 @@ struct netconfig **nconfp; /* * Make a copy of the netbuf to return */ - nb = (struct netbuf *) malloc(sizeof (struct netbuf)); + nb = (struct netbuf *)malloc(sizeof (struct netbuf)); if (nb == NULL) { errprintf(NULL, "no memory"); goto done; @@ -743,15 +734,14 @@ struct netconfig **nconfp; done: if (tbind) - t_free((char *) tbind, T_BIND); + t_free((char *)tbind, T_BIND); if (fd >= 0) (void) t_close(fd); return (nb); } static struct knetconfig * -get_knconf(nconf) -struct netconfig *nconf; +get_knconf(struct netconfig *nconf) { struct stat stbuf; struct knetconfig *k; @@ -760,7 +750,7 @@ struct netconfig *nconf; errprintf(NULL, "get_knconf: stat %s: %m", nconf->nc_device); return (NULL); } - k = (struct knetconfig *) malloc(sizeof (*k)); + k = (struct knetconfig *)malloc(sizeof (*k)); if (k == NULL) goto nomem; k->knc_semantics = nconf->nc_semantics; @@ -781,8 +771,7 @@ nomem: } static void -free_knconf(k) -struct knetconfig *k; +free_knconf(struct knetconfig *k) { if (k == NULL) return; @@ -794,8 +783,7 @@ struct knetconfig *k; } static void -netbuf_free(nb) -struct netbuf *nb; +netbuf_free(struct netbuf *nb) { if (nb == NULL) return; @@ -806,9 +794,7 @@ struct netbuf *nb; static enum clnt_stat -pingnfs(hostname, versp) -char *hostname; -rpcvers_t *versp; +pingnfs(char *hostname, rpcvers_t *versp) { CLIENT *cl; enum clnt_stat clnt_stat; @@ -828,10 +814,10 @@ rpcvers_t *versp; /* ping the NFS nullproc on the server */ cl = clnt_create_vers(hostname, NFS_PROGRAM, versp, NFS_VERSMIN, - NFS_VERSMAX, "udp"); + NFS_VERSMAX, "udp"); if (cl == NULL) { errprintf(NULL, "pingnfs: %s%s", - hostname, clnt_spcreateerror("")); + hostname, clnt_spcreateerror("")); if (Debug) printf("clnt_create failed\n"); clnt_stat = RPC_TIMEDOUT; @@ -850,13 +836,12 @@ rpcvers_t *versp; if (Debug) (void) printf("%s\n", clnt_stat == RPC_SUCCESS ? - "OK" : "NO RESPONSE"); + "OK" : "NO RESPONSE"); return (clnt_stat); } -static int bindudp_resvport(client) -CLIENT *client; +static int bindudp_resvport(CLIENT *client) { struct netconfig *udpnconf; int clfd; @@ -868,8 +853,9 @@ CLIENT *client; return (-1); } - if (clnt_control(client, CLGET_FD, (char *) &clfd) == FALSE) { - errprintf(NULL, "Could not get file dscriptor for client handle\n"); + if (clnt_control(client, CLGET_FD, (char *)&clfd) == FALSE) { + errprintf(NULL, + "Could not get file dscriptor for client handle\n"); return (-1); } @@ -882,7 +868,7 @@ CLIENT *client; } } - if ((udpnconf = getnetconfigent("udp")) == (struct netconfig *) NULL) { + if ((udpnconf = getnetconfigent("udp")) == (struct netconfig *)NULL) { errprintf(NULL, "no netconfig information about \"udp\"\n"); return (-1); } @@ -892,7 +878,7 @@ CLIENT *client; } if ((rv = netdir_options(udpnconf, ND_SET_RESERVEDPORT, clfd, - (char *) NULL)) == -1) { + (char *)NULL)) == -1) { if (Debug) { printf("netdir_options fails rv=%d\n", rv); } diff --git a/usr/src/lib/libc/port/gen/nftw.c b/usr/src/lib/libc/port/gen/nftw.c index c048664f3b..f4247c2ed2 100644 --- a/usr/src/lib/libc/port/gen/nftw.c +++ b/usr/src/lib/libc/port/gen/nftw.c @@ -175,16 +175,17 @@ struct Var { dev_t cur_mount; struct FTW state; int walklevel; - int (*statf)(const char *, struct stat *, struct Save *); - int (*savedstatf)(const char *, struct stat *, struct Save *); + int (*statf)(const char *, struct stat *, struct Save *, int flags); + int (*savedstatf)(const char *, struct stat *, struct Save *, + int flags); DIR *(*opendirf)(const char *); }; static int oldclose(struct Save *); -static int cdlstat(const char *, struct stat *, struct Save *); -static int cdstat(const char *, struct stat *, struct Save *); -static int nocdlstat(const char *, struct stat *, struct Save *); -static int nocdstat(const char *, struct stat *, struct Save *); +static int cdlstat(const char *, struct stat *, struct Save *, int flags); +static int cdstat(const char *, struct stat *, struct Save *, int flags); +static int nocdlstat(const char *, struct stat *, struct Save *, int flags); +static int nocdstat(const char *, struct stat *, struct Save *, int flags); static DIR *cdopendir(const char *); static DIR *nocdopendir(const char *); static const char *get_unrooted(const char *); @@ -234,8 +235,11 @@ walk(char *component, /* * Determine the type of the component. + * + * Note that if the component is a trigger mount, this + * will cause it to load. */ - if ((*vp->statf)(comp, &statb, last) >= 0) { + if ((*vp->statf)(comp, &statb, last, _AT_TRIGGER) >= 0) { if ((statb.st_mode & S_IFMT) == S_IFDIR) { type = FTW_D; if (depth <= 1) @@ -256,17 +260,6 @@ walk(char *component, goto fail; } } - if (statb.st_fstype[0] == 'a' && - strcmp(statb.st_fstype, "autofs") == 0) { - /* - * this dir is on autofs - */ - if (fstat(this.fd->dd_fd, &statb) < 0) { - (void) closedir(this.fd); - type = FTW_NS; - goto fail; - } - } } else if ((statb.st_mode & S_IFMT) == S_IFLNK) { type = FTW_SL; } else { @@ -293,10 +286,10 @@ walk(char *component, * link. */ if (((vp->statf == cdstat) && - (cdlstat(comp, &statb, last) >= 0) && + (cdlstat(comp, &statb, last, 0) >= 0) && ((statb.st_mode & S_IFMT) == S_IFLNK)) || ((vp->statf == nocdstat) && - (nocdlstat(comp, &statb, last) >= 0) && + (nocdlstat(comp, &statb, last, 0) >= 0) && ((statb.st_mode & S_IFMT) == S_IFLNK))) { /* @@ -492,7 +485,7 @@ quit: } } else { if ((cdval = chdir("..")) >= 0) { - if ((*vp->statf)(".", &statb, last) < 0 || + if ((*vp->statf)(".", &statb, last, 0) < 0 || statb.st_ino != last->inode || statb.st_dev != last->dev) cdval = -1; @@ -502,18 +495,20 @@ quit: if (chdir(vp->fullpath) < 0) { rc = -1; } else { - /* Security check */ - if ((vp->curflags & FTW_PHYS) && - ((*vp->statf)(".", &statb, last) < 0 || - statb.st_ino != last->inode || - statb.st_dev != last->dev)) { - errno = EAGAIN; - rc = -1; - } + /* Security check */ + if ((vp->curflags & FTW_PHYS) && + ((*vp->statf)(".", &statb, + last, 0) < 0 || + statb.st_ino != last->inode || + statb.st_dev != last->dev)) { + errno = EAGAIN; + rc = -1; + } } } } } + if (this.fd) (void) closedir(this.fd); if (val > rc) @@ -610,7 +605,7 @@ _nftw(const char *path, * save the current mount point. */ if (flags & FTW_MOUNT) { - if ((*var.statf)(savepath, &statb, NULL) >= 0) + if ((*var.statf)(savepath, &statb, NULL, 0) >= 0) var.cur_mount = statb.st_dev; else goto done; @@ -641,8 +636,9 @@ done: */ /*ARGSUSED1*/ static int -cdstat(const char *path, struct stat *statp, struct Save *lp) { - return (stat(path, statp)); +cdstat(const char *path, struct stat *statp, struct Save *lp, int flags) +{ + return (fstatat(AT_FDCWD, path, statp, flags)); } /* @@ -650,44 +646,56 @@ cdstat(const char *path, struct stat *statp, struct Save *lp) { */ /*ARGSUSED1*/ static int -cdlstat(const char *path, struct stat *statp, struct Save *lp) +cdlstat(const char *path, struct stat *statp, struct Save *lp, int flags) { - return (lstat(path, statp)); + return (fstatat(AT_FDCWD, path, statp, + flags | AT_SYMLINK_NOFOLLOW)); } /* * Get stat info on path when FTW_CHDIR is not set. */ static int -nocdstat(const char *path, struct stat *statp, struct Save *lp) +nocdstat(const char *path, struct stat *statp, struct Save *lp, int flags) { - const char *unrootp; + int fd; + const char *basepath; if (lp && lp->fd) { /* get basename of path */ - unrootp = get_unrooted(path); - return (fstatat(lp->fd->dd_fd, unrootp, statp, 0)); + basepath = get_unrooted(path); + + fd = lp->fd->dd_fd; } else { - return (stat(path, statp)); + basepath = path; + + fd = AT_FDCWD; } + + return (fstatat(fd, basepath, statp, flags)); } /* * Get lstat info on path when FTW_CHDIR is not set. */ static int -nocdlstat(const char *path, struct stat *statp, struct Save *lp) +nocdlstat(const char *path, struct stat *statp, struct Save *lp, int flags) { - const char *unrootp; + int fd; + const char *basepath; if (lp && lp->fd) { /* get basename of path */ - unrootp = get_unrooted(path); - return (fstatat(lp->fd->dd_fd, unrootp, statp, - AT_SYMLINK_NOFOLLOW)); + basepath = get_unrooted(path); + + fd = lp->fd->dd_fd; } else { - return (lstat(path, statp)); + basepath = path; + + fd = AT_FDCWD; } + + return (fstatat(fd, basepath, statp, flags | AT_SYMLINK_NOFOLLOW)); } /* @@ -716,23 +724,23 @@ nocdopendir(const char *path) return (NULL); } if ((token = strtok_r(dirp, "/", &ptr)) != NULL) { - if ((fd = openat(AT_FDCWD, dirp, O_RDONLY)) < 0) { - (void) free(dirp); - errno = ENAMETOOLONG; - return (NULL); - } - while ((token = strtok_r(NULL, "/", &ptr)) != NULL) { - if ((cfd = openat(fd, token, O_RDONLY)) < 0) { - (void) close(fd); - (void) free(dirp); - errno = ENAMETOOLONG; - return (NULL); + if ((fd = openat(AT_FDCWD, dirp, O_RDONLY)) < 0) { + (void) free(dirp); + errno = ENAMETOOLONG; + return (NULL); + } + while ((token = strtok_r(NULL, "/", &ptr)) != NULL) { + if ((cfd = openat(fd, token, O_RDONLY)) < 0) { + (void) close(fd); + (void) free(dirp); + errno = ENAMETOOLONG; + return (NULL); + } + (void) close(fd); + fd = cfd; } - (void) close(fd); - fd = cfd; - } - (void) free(dirp); - return (fdopendir(fd)); + (void) free(dirp); + return (fdopendir(fd)); } (void) free(dirp); errno = ENAMETOOLONG; @@ -740,7 +748,11 @@ nocdopendir(const char *path) return (fdd); } -/* return pointer basename of path, which may contain trailing slashes */ +/* + * return pointer basename of path, which may contain trailing slashes + * + * We do this when we do not chdir() on the input. + */ static const char * get_unrooted(const char *path) { diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files index 21071a1742..ba15278285 100644 --- a/usr/src/uts/common/Makefile.files +++ b/usr/src/uts/common/Makefile.files @@ -869,7 +869,7 @@ NFS_OBJS += nfs_client.o nfs_common.o nfs_dump.o \ nfs4_acache.o nfs4_common.o nfs4_client_state.o \ nfs4_callback.o nfs4_recovery.o nfs4_client_secinfo.o \ nfs4_client_debug.o nfs_stats.o \ - nfs4_acl.o + nfs4_acl.o nfs4_stub_vnops.o NFSSRV_OBJS += nfs_server.o nfs_srv.o nfs3_srv.o \ nfs_acl_srv.o nfs_auth.o nfs_auth_xdr.o \ diff --git a/usr/src/uts/common/fs/autofs/auto_vnops.c b/usr/src/uts/common/fs/autofs/auto_vnops.c index dec18bd6e1..5ffcf57d83 100644 --- a/usr/src/uts/common/fs/autofs/auto_vnops.c +++ b/usr/src/uts/common/fs/autofs/auto_vnops.c @@ -158,17 +158,35 @@ auto_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cred) AUTOFS_DPRINT((4, "auto_getattr vp %p\n", (void *)vp)); - /* - * Recursive auto_getattr/mount; go to the vfsp == NULL - * case. - */ - if (vn_vfswlock_held(vp)) - goto defattr; + if (flags & ATTR_TRIGGER) { + /* + * Pre-trigger the mount + */ + error = auto_trigger_mount(vp, cred, &newvp); + if (error) + return (error); - if (error = vn_vfsrlock_wait(vp)) - return (error); + if (newvp == NULL) + goto defattr; + + if (error = vn_vfsrlock_wait(vp)) + return (error); + + vfsp = newvp->v_vfsp; + } else { + /* + * Recursive auto_getattr/mount; go to the vfsp == NULL + * case. + */ + if (vn_vfswlock_held(vp)) + goto defattr; + + if (error = vn_vfsrlock_wait(vp)) + return (error); + + vfsp = vn_mountedvfs(vp); + } - vfsp = vn_mountedvfs(vp); if (vfsp != NULL) { /* * Node is mounted on. @@ -299,7 +317,7 @@ auto_access(vnode_t *vp, int mode, int flags, cred_t *cred) mode &= ~(fnp->fn_mode << shift); if (mode != 0) error = secpolicy_vnode_access(cred, vp, fnp->fn_uid, - mode); + mode); } done: @@ -602,9 +620,9 @@ top: break; default: auto_log(dfnp->fn_globals->fng_verbose, - dfnp->fn_globals->fng_zoneid, CE_WARN, - "auto_lookup: unknown " - "operation %d", operation); + dfnp->fn_globals->fng_zoneid, CE_WARN, + "auto_lookup: unknown operation %d", + operation); } AUTOFS_DPRINT((5, "auto_lookup: name=%s *vpp=%p return=%d\n", @@ -914,13 +932,13 @@ again: rda.uid = crgetuid(cred); error = auto_calldaemon(fngp->fng_zoneid, - AUTOFS_READDIR, - xdr_autofs_rddirargs, - &rda, - xdr_autofs_rddirres, - (void *)&rd, - sizeof (autofs_rddirres), - TRUE); + AUTOFS_READDIR, + xdr_autofs_rddirargs, + &rda, + xdr_autofs_rddirres, + (void *)&rd, + sizeof (autofs_rddirres), + TRUE); /* * reacquire previously dropped lock @@ -954,7 +972,7 @@ again: do { this_reclen = cdp->d_reclen; if (auto_search(fnp, cdp->d_name, - NULL, cred)) { + NULL, cred)) { /* * entry not found in kernel list, * include it in readdir output. @@ -966,7 +984,7 @@ again: */ if (cdp != odp) bcopy(cdp, odp, - (size_t)this_reclen); + (size_t)this_reclen); odp = nextdp(odp); outcount += this_reclen; } else { @@ -982,7 +1000,7 @@ again: } count += this_reclen; cdp = (struct dirent64 *) - ((char *)cdp + this_reclen); + ((char *)cdp + this_reclen); } while (count < rd.rd_rddir.rddir_size); if (outcount) @@ -1029,7 +1047,7 @@ again: /* use strncpy(9f) to zero out uninitialized bytes */ (void) strncpy(dp->d_name, ".", - DIRENT64_NAMELEN(this_reclen)); + DIRENT64_NAMELEN(this_reclen)); outcount += dp->d_reclen; dp = nextdp(dp); @@ -1045,7 +1063,7 @@ again: /* use strncpy(9f) to zero out uninitialized bytes */ (void) strncpy(dp->d_name, "..", - DIRENT64_NAMELEN(this_reclen)); + DIRENT64_NAMELEN(this_reclen)); outcount += dp->d_reclen; dp = nextdp(dp); } @@ -1056,7 +1074,7 @@ again: nfnp = cfnp->fn_next; offset = cfnp->fn_offset; if ((offset >= uiop->uio_offset) && - (!(cfnp->fn_flags & MF_LOOKUP))) { + (!(cfnp->fn_flags & MF_LOOKUP))) { int reclen; /* @@ -1088,7 +1106,7 @@ again: /* use strncpy(9f) to zero out uninitialized bytes */ (void) strncpy(dp->d_name, cfnp->fn_name, - DIRENT64_NAMELEN(reclen)); + DIRENT64_NAMELEN(reclen)); outcount += dp->d_reclen; dp = nextdp(dp); } @@ -1097,6 +1115,7 @@ again: if (outcount) error = uiomove(outbuf, outcount, UIO_READ, uiop); + if (!error) { if (reached_max) { /* @@ -1109,12 +1128,12 @@ again: if (outcount == 0) error = EINVAL; } else if (autofs_nobrowse || - auto_nobrowse_option(fnip->fi_opts) || - (fnip->fi_flags & MF_DIRECT) || - (fnp->fn_trigger != NULL) || - (((vp->v_flag & VROOT) == 0) && - ((fntovn(fnp->fn_parent))->v_flag & VROOT) && - (fnp->fn_dirents == NULL))) { + auto_nobrowse_option(fnip->fi_opts) || + (fnip->fi_flags & MF_DIRECT) || + (fnp->fn_trigger != NULL) || + (((vp->v_flag & VROOT) == 0) && + ((fntovn(fnp->fn_parent))->v_flag & VROOT) && + (fnp->fn_dirents == NULL))) { /* * done reading directory entries */ @@ -1132,7 +1151,7 @@ again: done: kmem_free(outbuf, alloc_count); AUTOFS_DPRINT((5, "auto_readdir vp=%p offset=%lld eof=%d\n", - (void *)vp, uiop->uio_loffset, myeof)); + (void *)vp, uiop->uio_loffset, myeof)); return (error); } diff --git a/usr/src/uts/common/fs/nfs/nfs4_client.c b/usr/src/uts/common/fs/nfs/nfs4_client.c index 2aa86b9594..85f68c5123 100644 --- a/usr/src/uts/common/fs/nfs/nfs4_client.c +++ b/usr/src/uts/common/fs/nfs/nfs4_client.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -322,14 +322,14 @@ nfs4_purge_caches(vnode_t *vp, int purge_dnlc, cred_t *cr, int asyncpg) mutex_exit(&rp->r_statelock); args = kmem_alloc(sizeof (pgflush_t), - KM_SLEEP); + KM_SLEEP); args->vp = vp; VN_HOLD(args->vp); args->cr = cr; crhold(args->cr); (void) zthread_create(NULL, 0, - nfs4_pgflush_thread, args, 0, - minclsyspri); + nfs4_pgflush_thread, args, 0, + minclsyspri); } } } @@ -444,8 +444,8 @@ nfs4_attrcache_noinval(vnode_t *vp, nfs4_ga_res_t *garp, hrtime_t t) void nfs4_attr_cache(vnode_t *vp, nfs4_ga_res_t *garp, - hrtime_t t, cred_t *cr, int async, - change_info4 *cinfo) + hrtime_t t, cred_t *cr, int async, + change_info4 *cinfo) { rnode4_t *rp; int mtime_changed; @@ -738,7 +738,7 @@ nfs4_attrcache_va(vnode_t *vp, nfs4_ga_res_t *garp, int set_cache_timeout) if (garp->n4g_mon_fid_valid) { rp->r_mntd_fid = garp->n4g_mon_fid; - if (rp->r_flags & R4SRVSTUB) + if (RP_ISSTUB(rp)) rp->r_attr.va_nodeid = rp->r_mntd_fid; } @@ -791,8 +791,9 @@ nfs4_getattr_otw(vnode_t *vp, nfs4_ga_res_t *garp, cred_t *cr, int get_acl) (void) save_mnt_secinfo(mi->mi_curr_serv); recov_retry: + if ((e.error = nfs4_start_fop(mi, vp, NULL, OH_GETATTR, - &recov_state, NULL))) { + &recov_state, NULL))) { (void) check_mnt_secinfo(mi->mi_curr_serv, vp); return (e.error); } @@ -805,7 +806,7 @@ recov_retry: if (nfs4_start_recovery(&e, VTOMI4(vp), vp, NULL, NULL, NULL, OP_GETATTR, NULL) == FALSE) { nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_GETATTR, - &recov_state, 1); + &recov_state, 1); goto recov_retry; } } @@ -837,7 +838,7 @@ recov_retry: */ void nfs4_getattr_otw_norecovery(vnode_t *vp, nfs4_ga_res_t *garp, - nfs4_error_t *ep, cred_t *cr, int get_acl) + nfs4_error_t *ep, cred_t *cr, int get_acl) { COMPOUND4args_clnt args; COMPOUND4res_clnt res; @@ -906,35 +907,28 @@ nfs4getattr(vnode_t *vp, vattr_t *vap, cred_t *cr) /* * If we've got cached attributes, we're done, otherwise go * to the server to get attributes, which will update the cache - * in the process. + * in the process. Either way, use the cached attributes for + * the caller's vattr_t. + * + * Note that we ignore the gar set by the OTW call: the attr caching + * code may make adjustments when storing to the rnode, and we want + * to see those changes here. */ rp = VTOR4(vp); + error = 0; mutex_enter(&rp->r_statelock); - mutex_enter(&rp->r_statev4_lock); - if (ATTRCACHE4_VALID(vp)) { - mutex_exit(&rp->r_statev4_lock); - /* - * Cached attributes are valid - * Return the client's view of file size - */ - *vap = rp->r_attr; - vap->va_size = rp->r_size; + if (!ATTRCACHE4_VALID(vp)) { mutex_exit(&rp->r_statelock); - - ASSERT(nfs4_consistent_type(vp)); - - return (0); + error = nfs4_getattr_otw(vp, &gar, cr, 0); + mutex_enter(&rp->r_statelock); } - mutex_exit(&rp->r_statev4_lock); - mutex_exit(&rp->r_statelock); - error = nfs4_getattr_otw(vp, &gar, cr, 0); if (!error) - *vap = gar.n4g_va; + *vap = rp->r_attr; /* Return the client's view of file size */ - mutex_enter(&rp->r_statelock); vap->va_size = rp->r_size; + mutex_exit(&rp->r_statelock); ASSERT(nfs4_consistent_type(vp)); @@ -944,7 +938,7 @@ nfs4getattr(vnode_t *vp, vattr_t *vap, cred_t *cr) int nfs4_attr_otw(vnode_t *vp, nfs4_tag_type_t tag_type, - nfs4_ga_res_t *garp, bitmap4 reqbitmap, cred_t *cr) + nfs4_ga_res_t *garp, bitmap4 reqbitmap, cred_t *cr) { COMPOUND4args_clnt args; COMPOUND4res_clnt res; @@ -989,7 +983,7 @@ recov_retry: needrecov = nfs4_needs_recovery(&e, FALSE, vp->v_vfsp); if (!needrecov && e.error) { nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_GETATTR, &recov_state, - needrecov); + needrecov); return (e.error); } @@ -1000,9 +994,9 @@ recov_retry: "nfs4_attr_otw: initiating recovery\n")); abort = nfs4_start_recovery(&e, VTOMI4(vp), vp, NULL, NULL, - NULL, OP_GETATTR, NULL); + NULL, OP_GETATTR, NULL); nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_GETATTR, &recov_state, - needrecov); + needrecov); if (!e.error) { (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); e.error = geterrno4(res.status); @@ -1017,17 +1011,17 @@ recov_retry: } else { gerp = garp->n4g_ext_res; bcopy(&res.array[1].nfs_resop4_u.opgetattr.ga_res, - garp, sizeof (nfs4_ga_res_t)); + garp, sizeof (nfs4_ga_res_t)); garp->n4g_ext_res = gerp; if (garp->n4g_ext_res && res.array[1].nfs_resop4_u.opgetattr.ga_res.n4g_ext_res) bcopy(res.array[1].nfs_resop4_u.opgetattr. - ga_res.n4g_ext_res, - garp->n4g_ext_res, sizeof (nfs4_ga_ext_res_t)); + ga_res.n4g_ext_res, + garp->n4g_ext_res, sizeof (nfs4_ga_ext_res_t)); } (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_GETATTR, &recov_state, - needrecov); + needrecov); return (e.error); } @@ -1090,7 +1084,7 @@ nfs4_async_manager(vfs_t *vfsp) mi = VFTOMI4(vfsp); CALLB_CPR_INIT(&cprinfo, &mi->mi_async_lock, callb_generic_cpr, - "nfs4_async_manager"); + "nfs4_async_manager"); mutex_enter(&mi->mi_async_lock); /* @@ -1210,8 +1204,8 @@ nfs4_async_manager_stop(vfs_t *vfsp) int nfs4_async_readahead(vnode_t *vp, u_offset_t blkoff, caddr_t addr, - struct seg *seg, cred_t *cr, void (*readahead)(vnode_t *, - u_offset_t, caddr_t, struct seg *, cred_t *)) + struct seg *seg, cred_t *cr, void (*readahead)(vnode_t *, + u_offset_t, caddr_t, struct seg *, cred_t *)) { rnode4_t *rp; mntinfo4_t *mi; @@ -1407,7 +1401,7 @@ nfs4_async_start(struct vfs *vfsp) if (*mi->mi_async_curr == NULL || --mi->mi_async_clusters[args->a_io] == 0) { mi->mi_async_clusters[args->a_io] = - mi->mi_async_init_clusters; + mi->mi_async_init_clusters; mi->mi_async_curr++; if (mi->mi_async_curr == &mi->mi_async_reqs[NFS4_ASYNC_TYPES]) @@ -1427,26 +1421,25 @@ nfs4_async_start(struct vfs *vfsp) */ if (args->a_io == NFS4_READ_AHEAD && mi->mi_max_threads > 0) { (*args->a_nfs4_readahead)(args->a_vp, - args->a_nfs4_blkoff, - args->a_nfs4_addr, args->a_nfs4_seg, - args->a_cred); + args->a_nfs4_blkoff, args->a_nfs4_addr, + args->a_nfs4_seg, args->a_cred); } else if (args->a_io == NFS4_PUTAPAGE) { (void) (*args->a_nfs4_putapage)(args->a_vp, - args->a_nfs4_pp, args->a_nfs4_off, - args->a_nfs4_len, args->a_nfs4_flags, - args->a_cred); + args->a_nfs4_pp, args->a_nfs4_off, + args->a_nfs4_len, args->a_nfs4_flags, + args->a_cred); } else if (args->a_io == NFS4_PAGEIO) { (void) (*args->a_nfs4_pageio)(args->a_vp, - args->a_nfs4_pp, args->a_nfs4_off, - args->a_nfs4_len, args->a_nfs4_flags, - args->a_cred); + args->a_nfs4_pp, args->a_nfs4_off, + args->a_nfs4_len, args->a_nfs4_flags, + args->a_cred); } else if (args->a_io == NFS4_READDIR) { (void) ((*args->a_nfs4_readdir)(args->a_vp, - args->a_nfs4_rdc, args->a_cred)); + args->a_nfs4_rdc, args->a_cred)); } else if (args->a_io == NFS4_COMMIT) { (*args->a_nfs4_commit)(args->a_vp, args->a_nfs4_plist, - args->a_nfs4_offset, args->a_nfs4_count, - args->a_cred); + args->a_nfs4_offset, args->a_nfs4_count, + args->a_cred); } else if (args->a_io == NFS4_INACTIVE) { nfs4_inactive_otw(args->a_vp, args->a_cred); } @@ -1476,7 +1469,7 @@ nfs4_inactive_thread(mntinfo4_t *mi) vfs_t *vfsp = mi->mi_vfsp; CALLB_CPR_INIT(&cprinfo, &mi->mi_async_lock, callb_generic_cpr, - "nfs4_inactive_thread"); + "nfs4_inactive_thread"); for (;;) { mutex_enter(&mi->mi_async_lock); @@ -1625,8 +1618,8 @@ interrupted: int nfs4_async_putapage(vnode_t *vp, page_t *pp, u_offset_t off, size_t len, - int flags, cred_t *cr, int (*putapage)(vnode_t *, page_t *, - u_offset_t, size_t, int, cred_t *)) + int flags, cred_t *cr, int (*putapage)(vnode_t *, page_t *, + u_offset_t, size_t, int, cred_t *)) { rnode4_t *rp; mntinfo4_t *mi; @@ -1748,8 +1741,8 @@ noasync: int nfs4_async_pageio(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len, - int flags, cred_t *cr, int (*pageio)(vnode_t *, page_t *, u_offset_t, - size_t, int, cred_t *)) + int flags, cred_t *cr, int (*pageio)(vnode_t *, page_t *, u_offset_t, + size_t, int, cred_t *)) { rnode4_t *rp; mntinfo4_t *mi; @@ -1879,7 +1872,7 @@ noasync: void nfs4_async_readdir(vnode_t *vp, rddir4_cache *rdc, cred_t *cr, - int (*readdir)(vnode_t *, rddir4_cache *, cred_t *)) + int (*readdir)(vnode_t *, rddir4_cache *, cred_t *)) { rnode4_t *rp; mntinfo4_t *mi; @@ -1966,8 +1959,8 @@ noasync: void nfs4_async_commit(vnode_t *vp, page_t *plist, offset3 offset, count3 count, - cred_t *cr, void (*commit)(vnode_t *, page_t *, offset3, count3, - cred_t *)) + cred_t *cr, void (*commit)(vnode_t *, page_t *, offset3, count3, + cred_t *)) { rnode4_t *rp; mntinfo4_t *mi; @@ -2133,7 +2126,7 @@ nfs4_async_inactive(vnode_t *vp, cred_t *cr) */ if (rp->r_deleg_type != OPEN_DELEGATE_NONE) { (void) nfs_rw_enter_sig(&mi->mi_recovlock, RW_READER, - FALSE); + FALSE); (void) nfs4delegreturn(rp, NFS4_DR_DISCARD); nfs_rw_exit(&mi->mi_recovlock); } @@ -2231,8 +2224,8 @@ writerp4(rnode4_t *rp, caddr_t base, int tcount, struct uio *uio, int pgcreated) * created and mapped at base. */ pagecreate = pgcreated || - ((offset & PAGEOFFSET) == 0 && - (n == PAGESIZE || ((offset + n) >= rp->r_size))); + ((offset & PAGEOFFSET) == 0 && + (n == PAGESIZE || ((offset + n) >= rp->r_size))); mutex_exit(&rp->r_statelock); @@ -2251,7 +2244,7 @@ writerp4(rnode4_t *rp, caddr_t base, int tcount, struct uio *uio, int pgcreated) */ if (pgcreated == 0) (void) segmap_pagecreate(segkmap, base, - (uint_t)n, 1); + (uint_t)n, 1); saved_base = base; saved_n = n; } @@ -2279,7 +2272,7 @@ writerp4(rnode4_t *rp, caddr_t base, int tcount, struct uio *uio, int pgcreated) * with zeros. */ error = vpm_data_copy(vp, offset, n, uio, - !pagecreate, NULL, 0, S_WRITE); + !pagecreate, NULL, 0, S_WRITE); } else { error = uiomove(base, n, UIO_WRITE, uio); } @@ -2329,8 +2322,8 @@ writerp4(rnode4_t *rp, caddr_t base, int tcount, struct uio *uio, int pgcreated) * segmap_pagecreate(). */ sm_error = segmap_fault(kas.a_hat, segkmap, - saved_base, saved_n, - F_SOFTUNLOCK, S_WRITE); + saved_base, saved_n, + F_SOFTUNLOCK, S_WRITE); if (error == 0) error = sm_error; } @@ -2408,7 +2401,7 @@ nfs4_putpages(vnode_t *vp, u_offset_t off, size_t len, int flags, cred_t *cr) * the dirty pages. */ error = pvn_vplist_dirty(vp, off, rp->r_putapage, - flags, cr); + flags, cr); /* * If an error occured and the file was marked as dirty @@ -2491,7 +2484,7 @@ nfs4_invalidate_pages(vnode_t *vp, u_offset_t off, cred_t *cr) rp->r_truncaddr = off; mutex_exit(&rp->r_statelock); (void) pvn_vplist_dirty(vp, off, rp->r_putapage, - B_INVAL | B_TRUNC, cr); + B_INVAL | B_TRUNC, cr); mutex_enter(&rp->r_statelock); rp->r_flags &= ~R4TRUNCATE; cv_broadcast(&rp->r_cv); @@ -2532,8 +2525,8 @@ nfs4_mnt_kstat_update(kstat_t *ksp, int rw) * sv_currsec is NULL if no security negotiation takes place. */ mik->mik_secmod = mi->mi_curr_serv->sv_currsec ? - mi->mi_curr_serv->sv_currsec->secmod : - mi->mi_curr_serv->sv_secdata->secmod; + mi->mi_curr_serv->sv_currsec->secmod : + mi->mi_curr_serv->sv_secdata->secmod; mik->mik_curread = (uint32_t)mi->mi_curread; mik->mik_curwrite = (uint32_t)mi->mi_curwrite; mik->mik_retrans = mi->mi_retrans; @@ -2666,7 +2659,7 @@ nfs4_safemap(const vnode_t *vp) ASSERT(nfs_rw_lock_held(&rp->r_lkserlock, RW_WRITER)); NFS4_DEBUG(nfs4_client_map_debug, (CE_NOTE, "nfs4_safemap: " - "vp = %p", (void *)vp)); + "vp = %p", (void *)vp)); /* * Review all the locks for the vnode, both ones that have been @@ -2701,7 +2694,7 @@ nfs4_safemap(const vnode_t *vp) } NFS4_DEBUG(nfs4_client_map_debug, (CE_NOTE, "nfs4_safemap: %s", - safe ? "safe" : "unsafe")); + safe ? "safe" : "unsafe")); return (safe); } @@ -3157,7 +3150,7 @@ nfs4_renew_lease_thread(nfs4_server_t *sp) kmutex_t cpr_lock; NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, - "nfs4_renew_lease_thread: acting on sp 0x%p", (void*)sp)); + "nfs4_renew_lease_thread: acting on sp 0x%p", (void*)sp)); mutex_init(&cpr_lock, NULL, MUTEX_DEFAULT, NULL); CALLB_CPR_INIT(&cpr_info, &cpr_lock, callb_generic_cpr, "nfsv4Lease"); @@ -3169,34 +3162,34 @@ nfs4_renew_lease_thread(nfs4_server_t *sp) for (;;) { if (!sp->state_ref_count || - sp->lease_valid != NFS4_LEASE_VALID) { + sp->lease_valid != NFS4_LEASE_VALID) { kip_secs = MAX((sp->s_lease_time >> 1) - - (3 * sp->propagation_delay.tv_sec), 1); + (3 * sp->propagation_delay.tv_sec), 1); tick_delay = SEC_TO_TICK(kip_secs); NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, - "nfs4_renew_lease_thread: no renew : thread " - "wait %ld secs", kip_secs)); + "nfs4_renew_lease_thread: no renew : thread " + "wait %ld secs", kip_secs)); NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, - "nfs4_renew_lease_thread: no renew : " - "state_ref_count %d, lease_valid %d", - sp->state_ref_count, sp->lease_valid)); + "nfs4_renew_lease_thread: no renew : " + "state_ref_count %d, lease_valid %d", + sp->state_ref_count, sp->lease_valid)); mutex_enter(&cpr_lock); CALLB_CPR_SAFE_BEGIN(&cpr_info); mutex_exit(&cpr_lock); time_left = cv_timedwait(&sp->cv_thread_exit, - &sp->s_lock, tick_delay + lbolt); + &sp->s_lock, tick_delay + lbolt); mutex_enter(&cpr_lock); CALLB_CPR_SAFE_END(&cpr_info, &cpr_lock); mutex_exit(&cpr_lock); NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, - "nfs4_renew_lease_thread: no renew: " - "time left %ld", time_left)); + "nfs4_renew_lease_thread: no renew: " + "time left %ld", time_left)); if (sp->s_thread_exit == NFS4_THREAD_EXIT) goto die; @@ -3206,43 +3199,43 @@ nfs4_renew_lease_thread(nfs4_server_t *sp) tmp_last_renewal_time = sp->last_renewal_time; tmp_time = gethrestime_sec() - sp->last_renewal_time + - (3 * sp->propagation_delay.tv_sec); + (3 * sp->propagation_delay.tv_sec); NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, - "nfs4_renew_lease_thread: tmp_time %ld, " - "sp->last_renewal_time %ld", tmp_time, - sp->last_renewal_time)); + "nfs4_renew_lease_thread: tmp_time %ld, " + "sp->last_renewal_time %ld", tmp_time, + sp->last_renewal_time)); kip_secs = MAX((sp->s_lease_time >> 1) - tmp_time, 1); tick_delay = SEC_TO_TICK(kip_secs); NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, - "nfs4_renew_lease_thread: valid lease: sleep for %ld " - "secs", kip_secs)); + "nfs4_renew_lease_thread: valid lease: sleep for %ld " + "secs", kip_secs)); mutex_enter(&cpr_lock); CALLB_CPR_SAFE_BEGIN(&cpr_info); mutex_exit(&cpr_lock); time_left = cv_timedwait(&sp->cv_thread_exit, &sp->s_lock, - tick_delay + lbolt); + tick_delay + lbolt); mutex_enter(&cpr_lock); CALLB_CPR_SAFE_END(&cpr_info, &cpr_lock); mutex_exit(&cpr_lock); NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, - "nfs4_renew_lease_thread: valid lease: time left %ld :" - "sp last_renewal_time %ld, nfs4_client_resumed %ld, " - "tmp_last_renewal_time %ld", time_left, - sp->last_renewal_time, nfs4_client_resumed, - tmp_last_renewal_time)); + "nfs4_renew_lease_thread: valid lease: time left %ld :" + "sp last_renewal_time %ld, nfs4_client_resumed %ld, " + "tmp_last_renewal_time %ld", time_left, + sp->last_renewal_time, nfs4_client_resumed, + tmp_last_renewal_time)); if (sp->s_thread_exit == NFS4_THREAD_EXIT) goto die; if (tmp_last_renewal_time == sp->last_renewal_time || - (nfs4_client_resumed != 0 && - nfs4_client_resumed > sp->last_renewal_time)) { + (nfs4_client_resumed != 0 && + nfs4_client_resumed > sp->last_renewal_time)) { /* * Issue RENEW op since we haven't renewed the lease * since we slept. @@ -3268,20 +3261,20 @@ nfs4_renew_lease_thread(nfs4_server_t *sp) * we waited for a reply for our RENEW call. */ if (tmp_last_renewal_time == - sp->last_renewal_time) { + sp->last_renewal_time) { /* no implicit renew came */ sp->last_renewal_time = tmp_now_time; } else { NFS4_DEBUG(nfs4_client_lease_debug, - (CE_NOTE, "renew_thread: did " - "implicit renewal before reply " - "from server for RENEW")); + (CE_NOTE, "renew_thread: did " + "implicit renewal before reply " + "from server for RENEW")); } } else { /* figure out error */ NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, - "renew_thread: nfs4renew returned error" - " %d", error)); + "renew_thread: nfs4renew returned error" + " %d", error)); } } @@ -3289,14 +3282,14 @@ nfs4_renew_lease_thread(nfs4_server_t *sp) die: NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, - "nfs4_renew_lease_thread: thread exiting")); + "nfs4_renew_lease_thread: thread exiting")); while (sp->s_otw_call_count != 0) { NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, - "nfs4_renew_lease_thread: waiting for outstanding " - "otw calls to finish for sp 0x%p, current " - "s_otw_call_count %d", (void *)sp, - sp->s_otw_call_count)); + "nfs4_renew_lease_thread: waiting for outstanding " + "otw calls to finish for sp 0x%p, current " + "s_otw_call_count %d", (void *)sp, + sp->s_otw_call_count)); mutex_enter(&cpr_lock); CALLB_CPR_SAFE_BEGIN(&cpr_info); mutex_exit(&cpr_lock); @@ -3317,7 +3310,7 @@ done: mutex_destroy(&cpr_lock); NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, - "nfs4_renew_lease_thread: renew thread exit officially")); + "nfs4_renew_lease_thread: renew thread exit officially")); zthread_exit(); /* NOT REACHED */ @@ -3401,26 +3394,26 @@ recov_retry: "nfs4renew: %s call, sp 0x%p", needrecov ? "recov" : "first", (void*)sp)); NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, "before: %ld s %ld ns ", - prop_time.tv_sec, prop_time.tv_nsec)); + prop_time.tv_sec, prop_time.tv_nsec)); DTRACE_PROBE2(nfs4__renew__start, nfs4_server_t *, sp, - mntinfo4_t *, mi); + mntinfo4_t *, mi); rfs4call(mi, &args, &res, cr, &doqueue, 0, &e); crfree(cr); DTRACE_PROBE2(nfs4__renew__end, nfs4_server_t *, sp, - mntinfo4_t *, mi); + mntinfo4_t *, mi); gethrestime(&after_time); mutex_enter(&sp->s_lock); sp->propagation_delay.tv_sec = - MAX(1, after_time.tv_sec - prop_time.tv_sec); + MAX(1, after_time.tv_sec - prop_time.tv_sec); mutex_exit(&sp->s_lock); NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, "after : %ld s %ld ns ", - after_time.tv_sec, after_time.tv_nsec)); + after_time.tv_sec, after_time.tv_nsec)); if (e.error == 0 && res.status == NFS4ERR_CB_PATH_DOWN) { (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); @@ -3455,7 +3448,7 @@ recov_retry: VFS_RELE(mi->mi_vfsp); if (!e.error) (void) xdr_free(xdr_COMPOUND4res_clnt, - (caddr_t)&res); + (caddr_t)&res); mutex_enter(&sp->s_lock); goto recov_retry; } @@ -3511,8 +3504,8 @@ nfs4_inc_state_ref_count_nolock(nfs4_server_t *sp, mntinfo4_t *mi) sp->state_ref_count++; NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, - "nfs4_inc_state_ref_count: state_ref_count now %d", - sp->state_ref_count)); + "nfs4_inc_state_ref_count: state_ref_count now %d", + sp->state_ref_count)); if (sp->lease_valid == NFS4_LEASE_UNINITIALIZED) sp->lease_valid = NFS4_LEASE_VALID; @@ -3556,20 +3549,20 @@ nfs4_dec_state_ref_count_nolock(nfs4_server_t *sp, mntinfo4_t *mi) sp->state_ref_count--; NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, - "nfs4_dec_state_ref_count: state ref count now %d", - sp->state_ref_count)); + "nfs4_dec_state_ref_count: state ref count now %d", + sp->state_ref_count)); mi->mi_open_files--; NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, - "nfs4_dec_state_ref_count: mi open files %d, v4 flags 0x%x", - mi->mi_open_files, mi->mi_flags)); + "nfs4_dec_state_ref_count: mi open files %d, v4 flags 0x%x", + mi->mi_open_files, mi->mi_flags)); /* We don't have to hold the mi_lock to test mi_flags */ if (mi->mi_open_files == 0 && (mi->mi_flags & MI4_REMOVE_ON_LAST_CLOSE)) { NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, - "nfs4_dec_state_ref_count: remove mntinfo4 %p since " - "we have closed the last open file", (void*)mi)); + "nfs4_dec_state_ref_count: remove mntinfo4 %p since " + "we have closed the last open file", (void*)mi)); nfs4_remove_mi_from_server(mi, sp); } } @@ -3623,7 +3616,7 @@ void sfh4_createtab(avl_tree_t *tab) { avl_create(tab, sfh4cmp, sizeof (nfs4_sharedfh_t), - offsetof(nfs4_sharedfh_t, sfh_tree)); + offsetof(nfs4_sharedfh_t, sfh_tree)); } /* @@ -3657,7 +3650,7 @@ sfh4_put(const nfs_fh4 *fh, mntinfo4_t *mi, nfs4_sharedfh_t *key) nsfh->sfh_flags = SFH4_IN_TREE; nsfh->sfh_mi = mi; NFS4_DEBUG(nfs4_sharedfh_debug, (CE_NOTE, "sfh4_get: new object (%p)", - (void *)nsfh)); + (void *)nsfh)); (void) nfs_rw_enter_sig(&mi->mi_fh_lock, RW_WRITER, 0); sfh = avl_find(&mi->mi_filehandles, key, &where); @@ -3716,8 +3709,8 @@ sfh4_get(const nfs_fh4 *fh, mntinfo4_t *mi) mutex_enter(&sfh->sfh_lock); sfh->sfh_refcnt++; NFS4_DEBUG(nfs4_sharedfh_debug, (CE_NOTE, - "sfh4_get: found existing %p, new refcnt=%d", - (void *)sfh, sfh->sfh_refcnt)); + "sfh4_get: found existing %p, new refcnt=%d", + (void *)sfh, sfh->sfh_refcnt)); mutex_exit(&sfh->sfh_lock); nfs_rw_exit(&mi->mi_fh_lock); return (sfh); @@ -3739,8 +3732,8 @@ sfh4_hold(nfs4_sharedfh_t *sfh) mutex_enter(&sfh->sfh_lock); sfh->sfh_refcnt++; NFS4_DEBUG(nfs4_sharedfh_debug, - (CE_NOTE, "sfh4_hold %p, new refcnt=%d", - (void *)sfh, sfh->sfh_refcnt)); + (CE_NOTE, "sfh4_hold %p, new refcnt=%d", + (void *)sfh, sfh->sfh_refcnt)); mutex_exit(&sfh->sfh_lock); } @@ -3786,7 +3779,7 @@ sfh4_rele(nfs4_sharedfh_t **sfhpp) } NFS4_DEBUG(nfs4_sharedfh_debug, (CE_NOTE, - "sfh4_rele %p, last ref", (void *)sfh)); + "sfh4_rele %p, last ref", (void *)sfh)); if (sfh->sfh_flags & SFH4_IN_TREE) { avl_remove(&mi->mi_filehandles, sfh); sfh->sfh_flags &= ~SFH4_IN_TREE; @@ -3966,8 +3959,8 @@ fn_get(nfs4_fname_t *parent, char *name) avl_create(&fnp->fn_children, fncmp, sizeof (nfs4_fname_t), offsetof(nfs4_fname_t, fn_tree)); NFS4_DEBUG(nfs4_fname_debug, (CE_NOTE, - "fn_get %p:%s, a new nfs4_fname_t!", - (void *)fnp, fnp->fn_name)); + "fn_get %p:%s, a new nfs4_fname_t!", + (void *)fnp, fnp->fn_name)); if (parent != NULL) { avl_insert(&parent->fn_children, fnp, where); mutex_exit(&parent->fn_lock); @@ -3981,8 +3974,8 @@ fn_hold(nfs4_fname_t *fnp) { atomic_add_32(&fnp->fn_refcnt, 1); NFS4_DEBUG(nfs4_fname_debug, (CE_NOTE, - "fn_hold %p:%s, new refcnt=%d", - (void *)fnp, fnp->fn_name, fnp->fn_refcnt)); + "fn_hold %p:%s, new refcnt=%d", + (void *)fnp, fnp->fn_name, fnp->fn_refcnt)); } /* @@ -4008,8 +4001,8 @@ recur: newref = atomic_add_32_nv(&fnp->fn_refcnt, -1); if (newref > 0) { NFS4_DEBUG(nfs4_fname_debug, (CE_NOTE, - "fn_rele %p:%s, new refcnt=%d", - (void *)fnp, fnp->fn_name, fnp->fn_refcnt)); + "fn_rele %p:%s, new refcnt=%d", + (void *)fnp, fnp->fn_name, fnp->fn_refcnt)); if (parent != NULL) mutex_exit(&parent->fn_lock); mutex_exit(&fnp->fn_lock); @@ -4017,8 +4010,8 @@ recur: } NFS4_DEBUG(nfs4_fname_debug, (CE_NOTE, - "fn_rele %p:%s, last reference, deleting...", - (void *)fnp, fnp->fn_name)); + "fn_rele %p:%s, last reference, deleting...", + (void *)fnp, fnp->fn_name)); if (parent != NULL) { avl_remove(&parent->fn_children, fnp); mutex_exit(&parent->fn_lock); @@ -4242,8 +4235,8 @@ nfs4_consistent_type(vnode_t *vp) if (nfs4_vtype_debug && vp->v_type != VNON && rp->r_attr.va_type != VNON && vp->v_type != rp->r_attr.va_type) { cmn_err(CE_PANIC, "vnode %p type mismatch; v_type=%d, " - "rnode attr type=%d", (void *)vp, vp->v_type, - rp->r_attr.va_type); + "rnode attr type=%d", (void *)vp, vp->v_type, + rp->r_attr.va_type); } return (1); diff --git a/usr/src/uts/common/fs/nfs/nfs4_client_secinfo.c b/usr/src/uts/common/fs/nfs/nfs4_client_secinfo.c index dbdb8f9354..3546a88ea9 100644 --- a/usr/src/uts/common/fs/nfs/nfs4_client_secinfo.c +++ b/usr/src/uts/common/fs/nfs/nfs4_client_secinfo.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -92,8 +92,8 @@ nfs4_secinfo_init(void) secinfo_support = kmem_alloc(sizeof (SECINFO4res), KM_SLEEP); secinfo_support->SECINFO4resok_len = SECINFO_SUPPORT_COUNT; val = kmem_alloc( - secinfo_support->SECINFO4resok_len * sizeof (secinfo4), - KM_SLEEP); + secinfo_support->SECINFO4resok_len * sizeof (secinfo4), + KM_SLEEP); val[0].flavor = AUTH_SYS; val[0].flavor_info.oid.sec_oid4_len = 0; @@ -136,7 +136,7 @@ nfs4_secinfo_fini(void) { kmem_free(secinfo_support->SECINFO4resok_val, - secinfo_support->SECINFO4resok_len * sizeof (secinfo4)); + secinfo_support->SECINFO4resok_len * sizeof (secinfo4)); kmem_free(secinfo_support, sizeof (SECINFO4res)); } @@ -158,7 +158,7 @@ secinfo2nfsflavor(sec_oid4 *mech_oid, rpc_gss_svc_t service) { /* Is this kerberos_v5? */ if (bcmp(mech_oid->sec_oid4_val, krb5_oid.sec_oid4_val, - krb5_oid.sec_oid4_len) != 0) { + krb5_oid.sec_oid4_len) != 0) { return (0); } @@ -229,7 +229,7 @@ secinfo_create(servinfo4_t *svp, SECINFO4res *sec_info, char *servname) data->qop = (uint_t)info->qop; data->mechanism.length = info->oid.sec_oid4_len; data->mechanism.elements = - kmem_alloc(info->oid.sec_oid4_len, KM_SLEEP); + kmem_alloc(info->oid.sec_oid4_len, KM_SLEEP); bcopy(info->oid.sec_oid4_val, data->mechanism.elements, info->oid.sec_oid4_len); data->uname[0] = 'n'; data->uname[1] = 'f'; @@ -238,7 +238,7 @@ secinfo_create(servinfo4_t *svp, SECINFO4res *sec_info, char *servname) sdata[scnt].data = (caddr_t)data; sdata[scnt].secmod = - secinfo2nfsflavor(&info->oid, info->service); + secinfo2nfsflavor(&info->oid, info->service); scnt++; break; case AUTH_DH: @@ -280,32 +280,35 @@ secinfo_free(sv_secinfo_t *secinfo) return; for (i = 0; i < secinfo->count; i++) { - if (secinfo->sdata[i].rpcflavor == RPCSEC_GSS) { - gss_clntdata_t *data = (gss_clntdata_t *) - secinfo->sdata[i].data; + if (secinfo->sdata[i].rpcflavor == RPCSEC_GSS) { + gss_clntdata_t *data = (gss_clntdata_t *) + secinfo->sdata[i].data; - /* - * An auth handle may already cached in rpcsec_gss module - * per this secdata. Purge the cache entry before freeing - * up this secdata. Can't use sec_clnt_freeinfo since - * the allocation of secinfo is different from sec_data. - */ - (void) rpc_gss_secpurge((void *)&secinfo->sdata[i]); + /* + * An auth handle may already cached in rpcsec_gss + * module per this secdata. Purge the cache entry + * before freeing up this secdata. Can't use + * sec_clnt_freeinfo since the allocation of secinfo + * is different from sec_data. + */ + (void) rpc_gss_secpurge((void *)&secinfo->sdata[i]); - kmem_free(data->mechanism.elements, data->mechanism.length); - kmem_free(data, sizeof (gss_clntdata_t)); - } + kmem_free(data->mechanism.elements, + data->mechanism.length); + kmem_free(data, sizeof (gss_clntdata_t)); + } - if (secinfo->sdata[i].rpcflavor == AUTH_DH) { + if (secinfo->sdata[i].rpcflavor == AUTH_DH) { - secinfo->sdata[i].data = NULL; /* release ref to sv_dhsec */ + /* release ref to sv_dhsec */ + secinfo->sdata[i].data = NULL; - /* - * No need to purge the auth_dh cache entry (e.g. call - * purge_authtab()) since the AUTH_DH data used here - * are always the same. - */ - } + /* + * No need to purge the auth_dh cache entry (e.g. call + * purge_authtab()) since the AUTH_DH data used here + * are always the same. + */ + } } kmem_free(secinfo->sdata, sizeof (sec_data_t) * secinfo->count); kmem_free(secinfo, sizeof (sv_secinfo_t)); @@ -329,7 +332,7 @@ secinfo_check(servinfo4_t *svp) if (svp->sv_secinfo->index < svp->sv_secinfo->count) { svp->sv_flags |= SV4_TRYSECINFO; svp->sv_currsec = - &svp->sv_secinfo->sdata[svp->sv_secinfo->index]; + &svp->sv_secinfo->sdata[svp->sv_secinfo->index]; nfs_rw_exit(&svp->sv_lock); return (TRUE); } else { @@ -371,7 +374,7 @@ secinfo_update(servinfo4_t *svp, SECINFO4res *sec_info) svp->sv_secinfo->index = 0; svp->sv_flags |= SV4_TRYSECINFO; svp->sv_currsec = - &svp->sv_secinfo->sdata[svp->sv_secinfo->index]; + &svp->sv_secinfo->sdata[svp->sv_secinfo->index]; } else { svp->sv_flags &= ~SV4_TRYSECINFO; svp->sv_currsec = NULL; @@ -391,7 +394,6 @@ secinfo_update(servinfo4_t *svp, SECINFO4res *sec_info) void save_mnt_secinfo(servinfo4_t *svp) { - (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0); if (svp->sv_currsec) { svp->sv_savesec = svp->sv_currsec; @@ -418,9 +420,9 @@ check_mnt_secinfo(servinfo4_t *svp, vnode_t *vp) (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0); - is_restore = (vp == NULL || (VTOR4(vp)->r_flags & R4SRVSTUB)) && - svp->sv_save_secinfo && - (svp->sv_secinfo != svp->sv_save_secinfo); + is_restore = (vp == NULL || (RP_ISSTUB(VTOR4(vp)))) && + svp->sv_save_secinfo && + (svp->sv_secinfo != svp->sv_save_secinfo); if (is_restore) { secinfo_free(svp->sv_secinfo); @@ -435,7 +437,7 @@ check_mnt_secinfo(servinfo4_t *svp, vnode_t *vp) } } else { if (svp->sv_save_secinfo && - svp->sv_save_secinfo != svp->sv_secinfo) + svp->sv_save_secinfo != svp->sv_secinfo) secinfo_free(svp->sv_save_secinfo); } @@ -666,9 +668,9 @@ retry: num_argops = args.array_len; argop[num_argops - 1].argop = OP_SECINFO; argop[num_argops - 1].nfs_argop4_u.opsecinfo.name.utf8string_len = - comp.utf8string_len; + comp.utf8string_len; argop[num_argops - 1].nfs_argop4_u.opsecinfo.name.utf8string_val = - comp.utf8string_val; + comp.utf8string_val; doqueue = 1; @@ -701,7 +703,7 @@ retry: ncomp = tcomp; nfs4args_lookup_free(argop, num_argops); kmem_free(argop, - lookuparg.arglen * sizeof (nfs_argop4)); + lookuparg.arglen * sizeof (nfs_argop4)); (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); kmem_free(tmp_path, path_len + 1); @@ -730,22 +732,24 @@ retry: /* If not in a recovery thread, bail out */ if (!isrecov) { + if (!e.error) { + e.error = geterrno4(res.status); + (void) xdr_free(xdr_COMPOUND4res_clnt, + (caddr_t)&res); + } - if (!e.error) { - e.error = geterrno4(res.status); - (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); - } - nfs4args_lookup_free(argop, num_argops); - kmem_free(argop, lookuparg.arglen * sizeof (nfs_argop4)); - kmem_free(tmp_path, path_len + 1); - return (e.error); + nfs4args_lookup_free(argop, num_argops); + kmem_free(argop, + lookuparg.arglen * sizeof (nfs_argop4)); + kmem_free(tmp_path, path_len + 1); + return (e.error); } NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE, "nfs4secinfo_otw: recovery in a recovery thread\n")); abort = nfs4_start_recovery(&e, mi, NULL, - NULL, NULL, NULL, OP_SECINFO, NULL); + NULL, NULL, NULL, OP_SECINFO, NULL); if (!e.error) { e.error = geterrno4(res.status); (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); @@ -838,7 +842,6 @@ retry: int nfs4_secinfo_path(mntinfo4_t *mi, cred_t *cr, int isrecov) { - int error = 0; int ncomp; servinfo4_t *svp = mi->mi_curr_serv; diff --git a/usr/src/uts/common/fs/nfs/nfs4_recovery.c b/usr/src/uts/common/fs/nfs/nfs4_recovery.c index 0cfdf4827a..32df45d5f8 100644 --- a/usr/src/uts/common/fs/nfs/nfs4_recovery.c +++ b/usr/src/uts/common/fs/nfs/nfs4_recovery.c @@ -148,7 +148,6 @@ static void free_milist(mntinfo4_t **, int); static mntinfo4_t **make_milist(nfs4_server_t *, int *); static int nfs4_check_recov_err(vnode_t *, nfs4_op_hint_t, nfs4_recov_state_t *, int, char *); -static int nfs4_check_srvstub(vnode_t *vp, rnode4_t *rp, nfs4_op_hint_t op); static char *nfs4_getsrvnames(mntinfo4_t *, size_t *); static void nfs4_recov_fh_fail(vnode_t *, int, nfsstat4); static void nfs4_recov_thread(recov_info_t *); @@ -242,7 +241,7 @@ nfs4_needs_recovery(nfs4_error_t *ep, bool_t stateful, vfs_t *vfsp) case NFS4ERR_MOVED: zcmn_err(VFTOMI4(vfsp)->mi_zone->zone_id, CE_WARN, "!Can't yet recover from NFS status %d", - ep->stat); + ep->stat); break; #endif } @@ -282,8 +281,8 @@ nfs4_enqueue_lost_rqst(recov_info_t *recovp, mntinfo4_t *mi) ASSERT(lrp != NULL && lrp->lr_op != 0); NFS4_DEBUG(nfs4_lost_rqst_debug, (CE_NOTE, - "nfs4_enqueue_lost_rqst %p, op %d", - (void *)lrp, lrp->lr_op)); + "nfs4_enqueue_lost_rqst %p, op %d", + (void *)lrp, lrp->lr_op)); mutex_enter(&mi->mi_lock); mi->mi_recovflags |= MI4R_LOST_STATE; @@ -295,7 +294,7 @@ nfs4_enqueue_lost_rqst(recov_info_t *recovp, mntinfo4_t *mi) mutex_exit(&mi->mi_lock); nfs4_queue_event(RE_LOST_STATE, mi, NULL, lrp->lr_op, lrp->lr_vp, - lrp->lr_dvp, 0, NULL, 0, TAG_NONE, TAG_NONE, 0, 0); + lrp->lr_dvp, 0, NULL, 0, TAG_NONE, TAG_NONE, 0, 0); } /* @@ -361,7 +360,7 @@ nfs4_start_recovery(nfs4_error_t *ep, mntinfo4_t *mi, vnode_t *vp1, if (abort) { mutex_exit(&mi->mi_lock); NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE, - "nfs4_start_recovery: fs unmounted")); + "nfs4_start_recovery: fs unmounted")); return (TRUE); } } @@ -371,8 +370,7 @@ nfs4_start_recovery(nfs4_error_t *ep, mntinfo4_t *mi, vnode_t *vp1, recovp = kmem_alloc(sizeof (recov_info_t), KM_SLEEP); recovp->rc_orig_errors = *ep; sp = find_nfs4_server(mi); - errs_to_action(recovp, sp, mi, sid, lost_rqstp, - gone, op, bsep); + errs_to_action(recovp, sp, mi, sid, lost_rqstp, gone, op, bsep); if (sp != NULL) mutex_exit(&sp->s_lock); start_recovery(recovp, mi, vp1, vp2, sp); @@ -388,7 +386,7 @@ nfs4_start_recovery(nfs4_error_t *ep, mntinfo4_t *mi, vnode_t *vp1, */ static void start_recovery_action(nfs4_recov_t what, bool_t reboot, mntinfo4_t *mi, - vnode_t *vp1, vnode_t *vp2) + vnode_t *vp1, vnode_t *vp2) { recov_info_t *recovp; @@ -406,11 +404,11 @@ start_recovery_action(nfs4_recov_t what, bool_t reboot, mntinfo4_t *mi, static void start_recovery(recov_info_t *recovp, mntinfo4_t *mi, - vnode_t *vp1, vnode_t *vp2, nfs4_server_t *sp) + vnode_t *vp1, vnode_t *vp2, nfs4_server_t *sp) { NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE, - "start_recovery: mi %p, what %s", (void*)mi, - nfs4_recov_action_to_str(recovp->rc_action))); + "start_recovery: mi %p, what %s", (void*)mi, + nfs4_recov_action_to_str(recovp->rc_action))); /* * Bump the reference on the vfs so that we can pass it to the @@ -598,7 +596,7 @@ again: mi->mi_flags |= MI4_RECOV_ACTIV; mutex_exit(&mi->mi_lock); NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE, - "start_recovery: starting new thread for mi %p", (void*)mi)); + "start_recovery: starting new thread for mi %p", (void*)mi)); recovp->rc_mi = mi; recovp->rc_vp1 = vp1; @@ -613,7 +611,7 @@ again: } (void) zthread_create(NULL, 0, nfs4_recov_thread, recovp, 0, - minclsyspri); + minclsyspri); return; /* not reached by thread creating call */ @@ -633,39 +631,8 @@ out_no_thread: } static int -nfs4_check_srvstub(vnode_t *vp, rnode4_t *rp, nfs4_op_hint_t op) -{ - int err = 0; - - /* - * If tuneable does not allow client to cross srv mountpoints and - * object is a stub, then check check op hint and return EACCES for - * any hint other than access, rddir, getattr, lookup. - */ - if (rp->r_flags & R4SRVSTUB && op != OH_ACCESS && op != OH_GETACL && - op != OH_GETATTR && op != OH_READDIR && op != OH_LOOKUP) { - err = EACCES; -#ifdef DEBUG - NFS4_DEBUG(nfs4_srvmnt_debug, (CE_NOTE, - "nfs4_check_srvstub: op=%d err=%d rp=%p vp=%p\n" - "va_nod=%llx r_mntd_fid=%llx\n" - "sv_fsid=(%llx:%llx) r_srv_fsid=(%llx:%llx)", - op, err, (void *)rp, (void *)vp, - (u_longlong_t)rp->r_attr.va_nodeid, - (u_longlong_t)rp->r_mntd_fid, - (u_longlong_t)rp->r_server->sv_fsid.major, - (u_longlong_t)rp->r_server->sv_fsid.minor, - (u_longlong_t)rp->r_srv_fsid.major, - (u_longlong_t)rp->r_srv_fsid.minor)); -#endif - } - - return (err); -} - -static int nfs4_check_recov_err(vnode_t *vp, nfs4_op_hint_t op, - nfs4_recov_state_t *rsp, int retry_err_cnt, char *str) + nfs4_recov_state_t *rsp, int retry_err_cnt, char *str) { rnode4_t *rp; int error = 0; @@ -682,14 +649,10 @@ nfs4_check_recov_err(vnode_t *vp, nfs4_op_hint_t op, * If there was a recovery error, then allow op hints "exempt" from * recov errors to retry (currently 3 times). Either r_error or * EIO is returned for non-exempt op hints. - * - * Error heirarchy: - * a) check for R4ERECOVERR - * b) check for R4SRVSTUB (only if R4RECOVERR is not set). */ if (rp->r_flags & R4RECOVERR) { if (exempt && rsp->rs_num_retry_despite_err <= - nfs4_max_recov_error_retry) { + nfs4_max_recov_error_retry) { /* * Check to make sure that we haven't already inc'd @@ -702,8 +665,8 @@ nfs4_check_recov_err(vnode_t *vp, nfs4_op_hint_t op, rsp->rs_num_retry_despite_err++; NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE, - "nfs4_start_fop: %s %p DEAD, cnt=%d", str, - (void *)vp, rsp->rs_num_retry_despite_err)); + "nfs4_start_fop: %s %p DEAD, cnt=%d", str, + (void *)vp, rsp->rs_num_retry_despite_err)); } else { error = (rp->r_error ? rp->r_error : EIO); /* @@ -718,21 +681,17 @@ nfs4_check_recov_err(vnode_t *vp, nfs4_op_hint_t op, */ if (error == ESTALE && vp->v_type != VREG) { rp->r_flags &= - ~(R4RECOVERR|R4RECOVERRP|R4STALE); + ~(R4RECOVERR|R4RECOVERRP|R4STALE); rp->r_error = 0; error = ESTALE; } NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE, - "nfs4_start_fop: %s %p DEAD, cnt=%d error=%d", - str, (void *)vp, - rsp->rs_num_retry_despite_err, error)); + "nfs4_start_fop: %s %p DEAD, cnt=%d error=%d", + str, (void *)vp, + rsp->rs_num_retry_despite_err, error)); } - } else { - error = nfs4_check_srvstub(vp, rp, op); - NFS4_DEBUG(nfs4_client_recov_stub_debug, (CE_NOTE, - "nfs4_start_fop: %s %p SRVSTUB, error=%d", str, - (void *)vp, error)); } + mutex_exit(&rp->r_statelock); return (error); } @@ -765,7 +724,7 @@ nfs4_check_recov_err(vnode_t *vp, nfs4_op_hint_t op, int nfs4_start_fop(mntinfo4_t *mi, vnode_t *vp1, vnode_t *vp2, nfs4_op_hint_t op, - nfs4_recov_state_t *rsp, bool_t *startrecovp) + nfs4_recov_state_t *rsp, bool_t *startrecovp) { int error = 0, rerr_cnt; nfs4_server_t *sp = NULL; @@ -782,7 +741,7 @@ nfs4_start_fop(mntinfo4_t *mi, vnode_t *vp1, vnode_t *vp2, nfs4_op_hint_t op, #ifdef DEBUG if ((fop_caller = tsd_get(nfs4_tsd_key)) != NULL) { cmn_err(CE_PANIC, "Missing nfs4_end_fop: last caller %p", - fop_caller); + fop_caller); } (void) tsd_set(nfs4_tsd_key, caller()); #endif @@ -863,13 +822,13 @@ get_sp: if (sp != NULL) { if (nfs_rw_enter_sig(&sp->s_recovlock, RW_READER, - mi->mi_flags & MI4_INT)) { + mi->mi_flags & MI4_INT)) { error = EINTR; goto out; } } if (nfs_rw_enter_sig(&mi->mi_recovlock, RW_READER, - mi->mi_flags & MI4_INT)) { + mi->mi_flags & MI4_INT)) { if (sp != NULL) nfs_rw_exit(&sp->s_recovlock); error = EINTR; @@ -921,8 +880,8 @@ get_sp: */ if (NFS4_VOLATILE_FH(mi) && op != OH_MOUNT) { if (nfs_rw_enter_sig(&mi->mi_rename_lock, - op == OH_VFH_RENAME ? RW_WRITER : RW_READER, - mi->mi_flags & MI4_INT)) { + op == OH_VFH_RENAME ? RW_WRITER : RW_READER, + mi->mi_flags & MI4_INT)) { nfs_rw_exit(&mi->mi_recovlock); if (sp != NULL) nfs_rw_exit(&sp->s_recovlock); @@ -985,7 +944,7 @@ out: */ int nfs4_start_op(mntinfo4_t *mi, vnode_t *vp1, vnode_t *vp2, - nfs4_recov_state_t *rsp) + nfs4_recov_state_t *rsp) { ASSERT(rsp->rs_num_retry_despite_err == 0); rsp->rs_num_retry_despite_err = 0; @@ -1002,7 +961,7 @@ nfs4_start_op(mntinfo4_t *mi, vnode_t *vp1, vnode_t *vp2, void nfs4_end_fop(mntinfo4_t *mi, vnode_t *vp1, vnode_t *vp2, nfs4_op_hint_t op, - nfs4_recov_state_t *rsp, bool_t needs_recov) + nfs4_recov_state_t *rsp, bool_t needs_recov) { nfs4_server_t *sp = rsp->rs_sp; rnode4_t *rp = NULL; @@ -1057,7 +1016,7 @@ nfs4_end_fop(mntinfo4_t *mi, vnode_t *vp1, vnode_t *vp2, nfs4_op_hint_t op, void nfs4_end_op(mntinfo4_t *mi, vnode_t *vp1, vnode_t *vp2, - nfs4_recov_state_t *rsp, bool_t needrecov) + nfs4_recov_state_t *rsp, bool_t needrecov) { nfs4_end_fop(mi, vp1, vp2, OH_OTHER, rsp, needrecov); } @@ -1110,12 +1069,12 @@ wait_for_recovery(mntinfo4_t *mi, nfs4_op_hint_t op_hint) if (mi->mi_flags & MI4_RECOV_FAIL) { NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE, - "wait_for_recovery: fail since RECOV FAIL")); + "wait_for_recovery: fail since RECOV FAIL")); error = mi->mi_error; } else if ((mi->mi_vfsp->vfs_flag & VFS_UNMOUNTED) && !OH_IS_STATE_RELE(op_hint)) { NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE, - "wait_for_recovery: forced unmount")); + "wait_for_recovery: forced unmount")); error = EIO; } @@ -1279,12 +1238,12 @@ nfs4_recov_thread(recov_info_t *recovp) NFS4_DEBUG(nfs4_client_recov_debug && mi->mi_vfsp->vfs_flag & VFS_UNMOUNTED, (CE_NOTE, - "nfs4_recov_thread: file system has been " - "unmounted")); + "nfs4_recov_thread: file system has been " + "unmounted")); NFS4_DEBUG(nfs4_client_recov_debug && zone_status_get(curproc->p_zone) >= ZONE_IS_SHUTTING_DOWN, (CE_NOTE, - "nfs4_recov_thread: zone shutting down")); + "nfs4_recov_thread: zone shutting down")); /* * If the server has lost its state for us and * the filesystem is unmounted, then the filesystem @@ -1325,8 +1284,8 @@ nfs4_recov_thread(recov_info_t *recovp) } if (!activesrv) { NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE, - "no active fs for server %p", - (void *)sp)); + "no active fs for server %p", + (void *)sp)); mutex_enter(&mi->mi_lock); mi->mi_flags |= MI4_RECOV_FAIL; mi->mi_error = recovp->rc_error; @@ -1392,9 +1351,9 @@ nfs4_recov_thread(recov_info_t *recovp) !(mi->mi_flags & MI4_RECOV_FAIL)) { mutex_exit(&mi->mi_lock); (void) nfs_rw_enter_sig(&mi->mi_recovlock, - RW_WRITER, 0); + RW_WRITER, 0); error = nfs4_secinfo_recov(recovp->rc_mi, - recovp->rc_vp1, recovp->rc_vp2); + recovp->rc_vp1, recovp->rc_vp2); /* * If error, nothing more can be done, stop * the recovery. @@ -1420,7 +1379,7 @@ nfs4_recov_thread(recov_info_t *recovp) !(mi->mi_flags & MI4_RECOV_FAIL)) { mutex_exit(&mi->mi_lock); (void) nfs_rw_enter_sig(&mi->mi_recovlock, - RW_WRITER, 0); + RW_WRITER, 0); recov_bad_seqid(recovp); nfs_rw_exit(&mi->mi_recovlock); } else @@ -1449,7 +1408,7 @@ nfs4_recov_thread(recov_info_t *recovp) !(mi->mi_flags & MI4_RECOV_FAIL)) { mutex_exit(&mi->mi_lock); (void) nfs_rw_enter_sig(&mi->mi_recovlock, - RW_WRITER, 0); + RW_WRITER, 0); nfs4_resend_lost_rqsts(recovp, sp); if (list_head(&mi->mi_lost_state) == NULL) { /* done */ @@ -1571,7 +1530,7 @@ recov_done(mntinfo4_t *mi, recov_info_t *recovp) ASSERT(MUTEX_HELD(&mi->mi_lock)); nfs4_queue_event(RE_END, mi, NULL, 0, recovp->rc_vp1, - recovp->rc_vp2, 0, NULL, 0, TAG_NONE, TAG_NONE, 0, 0); + recovp->rc_vp2, 0, NULL, 0, TAG_NONE, TAG_NONE, 0, 0); mi->mi_recovthread = NULL; mi->mi_flags &= ~MI4_RECOV_ACTIV; mi->mi_recovflags &= ~MI4R_SRV_REBOOT; @@ -1857,9 +1816,9 @@ recov_clientid(recov_info_t *recovp, nfs4_server_t *sp) tmi = milist[i]; if (tmi != mi) { (void) nfs_rw_enter_sig(&tmi->mi_recovlock, - RW_READER, 0); + RW_READER, 0); start_recovery_action(NR_OPENFILES, TRUE, tmi, - NULL, NULL); + NULL, NULL); nfs_rw_exit(&tmi->mi_recovlock); } } @@ -1981,7 +1940,7 @@ recov_filehandle(nfs4_recov_t action, mntinfo4_t *mi, vnode_t *vp) needrecov = FALSE; if (needrecov) { (void) nfs4_start_recovery(&e, mi, vp, - NULL, NULL, NULL, OP_LOOKUP, NULL); + NULL, NULL, NULL, OP_LOOKUP, NULL); } else if (e.error != EINTR && !NFS4_FRC_UNMT_ERR(e.error, mi->mi_vfsp) && (e.error != 0 || e.stat != NFS4_OK)) { @@ -2056,7 +2015,7 @@ recov_stale(mntinfo4_t *mi, vnode_t *vp) needrecov = nfs4_needs_recovery(&e, FALSE, vp->v_vfsp); if (needrecov && (e.error != 0 || e.stat != NFS4ERR_STALE)) { (void) nfs4_start_recovery(&e, mi, vp, - NULL, NULL, NULL, OP_GETATTR, NULL); + NULL, NULL, NULL, OP_GETATTR, NULL); NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE, "recov_stale: error=%d, stat=%d seen on rp %s", e.error, e.stat, rnode4info(rp))); @@ -2105,8 +2064,8 @@ recov_stale(mntinfo4_t *mi, vnode_t *vp) needrecov = nfs4_needs_recovery(&e, FALSE, vp->v_vfsp); if (needrecov) { (void) nfs4_start_recovery(&e, - mi, rootvp, NULL, NULL, NULL, - OP_GETATTR, NULL); + mi, rootvp, NULL, NULL, NULL, + OP_GETATTR, NULL); NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE, "recov_stale: error=%d, stat=%d seen " "on rp %s", e.error, e.stat, @@ -2315,7 +2274,7 @@ relock_file(vnode_t *vp, mntinfo4_t *mi, nfs4_error_t *ep, */ static void reclaim_one_lock(vnode_t *vp, flock64_t *flk, nfs4_error_t *ep, - int *did_reclaimp) + int *did_reclaimp) { cred_t *cr; rnode4_t *rp = VTOR4(vp); @@ -2340,10 +2299,10 @@ reclaim_one_lock(vnode_t *vp, flock64_t *flk, nfs4_error_t *ep, mutex_exit(&rp->r_statelock); nfs4frlock(NFS4_LCK_CTYPE_RECLAIM, vp, F_SETLK, flk, - FREAD|FWRITE, 0, cr, ep, NULL, did_reclaimp); + FREAD|FWRITE, 0, cr, ep, NULL, did_reclaimp); if (ep->error == 0 && ep->stat == NFS4ERR_FHEXPIRED) start_recovery_action(NR_FHEXPIRED, TRUE, VTOMI4(vp), - vp, NULL); + vp, NULL); } while (ep->error == 0 && ep->stat == NFS4ERR_FHEXPIRED); crfree(cr); @@ -2417,7 +2376,7 @@ nfs4_free_lost_rqst(nfs4_lost_rqst_t *lrp, nfs4_server_t *sp) int have_sync_lock; NFS4_DEBUG(nfs4_lost_rqst_debug, - (CE_NOTE, "nfs4_free_lost_rqst:")); + (CE_NOTE, "nfs4_free_lost_rqst:")); switch (lrp->lr_op) { case OP_OPEN: @@ -2524,7 +2483,7 @@ recov_openfiles(recov_info_t *recovp, nfs4_server_t *sp) if ((sp->s_flags & (N4S_CB_PINGED | N4S_CB_WAITER)) == 0) { sp->s_flags |= N4S_CB_WAITER; (void) cv_timedwait(&sp->wait_cb_null, &sp->s_lock, - (lbolt+drv_usectohz(N4S_CB_PAUSE_TIME))); + (lbolt + drv_usectohz(N4S_CB_PAUSE_TIME))); } mutex_exit(&sp->s_lock); @@ -2535,7 +2494,7 @@ recov_openfiles(recov_info_t *recovp, nfs4_server_t *sp) nfs4_remap_root(mi, &e, 0); if (nfs4_needs_recovery(&e, FALSE, mi->mi_vfsp)) { (void) nfs4_start_recovery(&e, mi, NULL, - NULL, NULL, NULL, OP_LOOKUP, NULL); + NULL, NULL, NULL, OP_LOOKUP, NULL); } } @@ -2568,7 +2527,7 @@ recov_openfiles(recov_info_t *recovp, nfs4_server_t *sp) if (remap) { nfs4_remap_file(mi, rep->re_vp, - NFS4_REMAP_CKATTRS, &e); + NFS4_REMAP_CKATTRS, &e); } if (e.error == ENOENT || e.stat == NFS4ERR_NOENT) { /* @@ -2581,7 +2540,7 @@ recov_openfiles(recov_info_t *recovp, nfs4_server_t *sp) * problem. */ nfs4_fail_recov(rep->re_vp, - fail_msg, e.error, e.stat); + fail_msg, e.error, e.stat); /* * We've already handled the error so clear it. */ @@ -2597,15 +2556,15 @@ recov_openfiles(recov_info_t *recovp, nfs4_server_t *sp) for (j = 0; j < rep->re_numosp; j++) { nfs4_reopen(rep->re_vp, rep->re_osp[j], - &e, claim, FALSE, TRUE); + &e, claim, FALSE, TRUE); if (e.error != 0 || e.stat != NFS4_OK) break; } if (nfs4_needs_recovery(&e, TRUE, mi->mi_vfsp)) { (void) nfs4_start_recovery(&e, mi, - rep->re_vp, NULL, NULL, NULL, - OP_OPEN, NULL); + rep->re_vp, NULL, NULL, NULL, + OP_OPEN, NULL); break; } } @@ -2618,8 +2577,8 @@ recov_openfiles(recov_info_t *recovp, nfs4_server_t *sp) if (nfs4_needs_recovery(&e, TRUE, mi->mi_vfsp)) (void) nfs4_start_recovery(&e, mi, - rep->re_vp, NULL, NULL, NULL, OP_LOCK, - NULL); + rep->re_vp, NULL, NULL, NULL, OP_LOCK, + NULL); if (e.error != 0 || e.stat != NFS4_OK) break; } @@ -2632,9 +2591,9 @@ recov_openfiles(recov_info_t *recovp, nfs4_server_t *sp) if (remap) { nfs4_error_t ignore; nfs4_check_remap(mi, recovp->rc_vp1, NFS4_REMAP_CKATTRS, - &ignore); + &ignore); nfs4_check_remap(mi, recovp->rc_vp2, NFS4_REMAP_CKATTRS, - &ignore); + &ignore); } } @@ -2707,8 +2666,8 @@ nfs4_resend_lost_rqsts(recov_info_t *recovp, nfs4_server_t *sp) delay(SEC_TO_TICK(nfs4err_delay_time)); } else { (void) nfs4_start_recovery(&n4e, - mi, lrp->lr_dvp, lrp->lr_vp, NULL, NULL, - lrp->lr_op, NULL); + mi, lrp->lr_dvp, lrp->lr_vp, NULL, NULL, + lrp->lr_op, NULL); } return; } @@ -2729,7 +2688,7 @@ nfs4_resend_lost_rqsts(recov_info_t *recovp, nfs4_server_t *sp) static void resend_one_op(nfs4_lost_rqst_t *lrp, nfs4_error_t *ep, - mntinfo4_t *mi, nfs4_server_t *sp) + mntinfo4_t *mi, nfs4_server_t *sp) { vnode_t *vp; nfs4_open_stream_t *osp; @@ -2751,8 +2710,8 @@ resend_one_op(nfs4_lost_rqst_t *lrp, nfs4_error_t *ep, ASSERT(lrp->lr_osp != NULL); mutex_enter(&lrp->lr_osp->os_sync_lock); nfs4_open_downgrade(lrp->lr_dg_acc, lrp->lr_dg_deny, - lrp->lr_oop, lrp->lr_osp, vp, lrp->lr_cr, lrp, - ep, NULL, NULL); + lrp->lr_oop, lrp->lr_osp, vp, lrp->lr_cr, lrp, + ep, NULL, NULL); mutex_exit(&lrp->lr_osp->os_sync_lock); nfs4_end_open_seqid_sync(lrp->lr_oop); break; @@ -2767,7 +2726,7 @@ resend_one_op(nfs4_lost_rqst_t *lrp, nfs4_error_t *ep, acc_bits |= OPEN4_SHARE_ACCESS_WRITE; mutex_exit(&osp->os_sync_lock); nfs4close_one(vp, osp, cr, acc_bits, lrp, ep, - CLOSE_RESEND, 0, 0, 0); + CLOSE_RESEND, 0, 0, 0); break; case OP_LOCK: case OP_LOCKU: @@ -2779,7 +2738,7 @@ resend_one_op(nfs4_lost_rqst_t *lrp, nfs4_error_t *ep, default: #ifdef DEBUG cmn_err(CE_PANIC, "resend_one_op: unexpected op: %d", - lrp->lr_op); + lrp->lr_op); #endif nfs4_queue_event(RE_LOST_STATE_BAD_OP, mi, NULL, lrp->lr_op, lrp->lr_vp, lrp->lr_dvp, NFS4_OK, NULL, 0, @@ -2841,12 +2800,12 @@ done: static void close_after_open_resend(vnode_t *vp, cred_t *cr, uint32_t acc_bits, - nfs4_error_t *ep) + nfs4_error_t *ep) { for (;;) { nfs4close_one(vp, NULL, cr, acc_bits, NULL, ep, - CLOSE_AFTER_RESEND, 0, 0, 0); + CLOSE_AFTER_RESEND, 0, 0, 0); if (ep->error == 0 && ep->stat == NFS4_OK) break; /* success; done */ if (ep->error != 0 || ep->stat != NFS4ERR_FHEXPIRED) @@ -2876,7 +2835,7 @@ resend_lock(nfs4_lost_rqst_t *lrp, nfs4_error_t *ep) lrp->lr_ctype == NFS4_LCK_CTYPE_RESEND); nfs4frlock(lrp->lr_ctype, vp, F_SETLK, - lrp->lr_flk, FREAD|FWRITE, 0, lrp->lr_cr, ep, lrp, NULL); + lrp->lr_flk, FREAD|FWRITE, 0, lrp->lr_cr, ep, lrp, NULL); NFS4_DEBUG(nfs4_lost_rqst_debug, (CE_NOTE, "resend_lock: " "nfs4frlock for vp %p returned error %d, stat %d", @@ -3010,7 +2969,7 @@ flush_reinstate(nfs4_lost_rqst_t *lrp) ASSERT(lrp->lr_vp == vp); ASSERT(lrp->lr_flk->l_pid == pid); NFS4_DEBUG(nfs4_lost_rqst_debug, (CE_NOTE, - "remove reinstantiation %p", (void *)lrp)); + "remove reinstantiation %p", (void *)lrp)); list_remove(&mi->mi_lost_state, lrp); nfs4_free_lost_rqst(lrp, NULL); } @@ -3029,7 +2988,7 @@ flush_reinstate(nfs4_lost_rqst_t *lrp) static void nfs4_save_lost_rqst(nfs4_lost_rqst_t *lost_rqstp, recov_info_t *recovp, - nfs4_recov_t *action, mntinfo4_t *mi) + nfs4_recov_t *action, mntinfo4_t *mi) { nfs4_lost_rqst_t *destp; @@ -3077,7 +3036,7 @@ nfs4_save_lost_rqst(nfs4_lost_rqst_t *lost_rqstp, recov_info_t *recovp, } else { #ifdef DEBUG cmn_err(CE_PANIC, "nfs4_save_lost_rqst: bad op %d", - lost_rqstp->lr_op); + lost_rqstp->lr_op); #endif nfs4_queue_event(RE_LOST_STATE_BAD_OP, mi, NULL, lost_rqstp->lr_op, lost_rqstp->lr_vp, lost_rqstp->lr_dvp, @@ -3124,9 +3083,9 @@ nfs4_save_lost_rqst(nfs4_lost_rqst_t *lost_rqstp, recov_info_t *recovp, void errs_to_action(recov_info_t *recovp, - nfs4_server_t *sp, mntinfo4_t *mi, stateid4 *sidp, - nfs4_lost_rqst_t *lost_rqstp, int unmounted, nfs_opnum4 op, - nfs4_bseqid_entry_t *bsep) + nfs4_server_t *sp, mntinfo4_t *mi, stateid4 *sidp, + nfs4_lost_rqst_t *lost_rqstp, int unmounted, nfs_opnum4 op, + nfs4_bseqid_entry_t *bsep) { nfs4_recov_t action = NR_UNUSED; bool_t reboot = FALSE; @@ -3139,7 +3098,7 @@ errs_to_action(recov_info_t *recovp, recovp->rc_bseqid_rqst = NULL; try_f = nfs4_try_failover(&recovp->rc_orig_errors) && - FAILOVER_MOUNT4(mi); + FAILOVER_MOUNT4(mi); /* * We start recovery for EINTR only in the lost lock @@ -3209,9 +3168,9 @@ errs_to_action(recov_info_t *recovp, action = NR_CLIENTID; DTRACE_PROBE4(nfs4__expired, - nfs4_server_t *, sp, - mntinfo4_t *, mi, - stateid4 *, sidp, int, op); + nfs4_server_t *, sp, + mntinfo4_t *, mi, + stateid4 *, sidp, int, op); break; case NFS4ERR_STALE_CLIENTID: @@ -3250,7 +3209,7 @@ errs_to_action(recov_info_t *recovp, recovp->rc_srv_reboot = reboot; recovp->rc_action = action; nfs4_queue_fact(RF_ERR, mi, stat, action, op, reboot, NULL, error, - NULL); + NULL); } /* @@ -3378,9 +3337,9 @@ recov_throttle(recov_info_t *recovp, vnode_t *vp) mutex_enter(&rp->r_statelock); NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE, - "recov_throttle: now: (%d, %ld), last: (%d, %ld)", - recovp->rc_action, curtime, - rp->r_recov_act, rp->r_last_recov)); + "recov_throttle: now: (%d, %ld), last: (%d, %ld)", + recovp->rc_action, curtime, + rp->r_recov_act, rp->r_last_recov)); if (recovp->rc_action == rp->r_recov_act && rp->r_last_recov + recov_err_delay > curtime) { time_to_wait = rp->r_last_recov + recov_err_delay - curtime; diff --git a/usr/src/uts/common/fs/nfs/nfs4_rnode.c b/usr/src/uts/common/fs/nfs/nfs4_rnode.c index 6b67ec086d..35d48fd750 100644 --- a/usr/src/uts/common/fs/nfs/nfs4_rnode.c +++ b/usr/src/uts/common/fs/nfs/nfs4_rnode.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -147,6 +147,7 @@ static void nfs4_reclaim(void *); static int isrootfh(nfs4_sharedfh_t *, rnode4_t *); static void uninit_rnode4(rnode4_t *); static void destroy_rnode4(rnode4_t *); +static void r4_stub_set(rnode4_t *, nfs4_stub_type_t); #ifdef DEBUG static int r4_check_for_dups = 0; /* Flag to enable dup rnode detection. */ @@ -303,7 +304,7 @@ badrootfh_check(nfs4_sharedfh_t *fh, nfs4_fname_t *nm, mntinfo4_t *mi, ASSERT(strcmp(s, "..") != 0); if ((s[0] == '.' && s[1] == '\0') && fh && - !SFH4_SAME(mi->mi_rootfh, fh)) { + !SFH4_SAME(mi->mi_rootfh, fh)) { #ifdef DEBUG nfs4_fhandle_t fhandle; @@ -316,13 +317,13 @@ badrootfh_check(nfs4_sharedfh_t *fh, nfs4_fname_t *nm, mntinfo4_t *mi, /* print the bad fh */ fhandle.fh_len = fh->sfh_fh.nfs_fh4_len; bcopy(fh->sfh_fh.nfs_fh4_val, fhandle.fh_buf, - fhandle.fh_len); + fhandle.fh_len); nfs4_printfhandle(&fhandle); /* print mi_rootfh */ fhandle.fh_len = mi->mi_rootfh->sfh_fh.nfs_fh4_len; bcopy(mi->mi_rootfh->sfh_fh.nfs_fh4_val, fhandle.fh_buf, - fhandle.fh_len); + fhandle.fh_len); nfs4_printfhandle(&fhandle); #endif /* use mi_rootfh instead; fh will be rele by the caller */ @@ -338,6 +339,7 @@ void r4_do_attrcache(vnode_t *vp, nfs4_ga_res_t *garp, int newnode, hrtime_t t, cred_t *cr, int index) { + int is_stub; vattr_t *attr; /* * Don't add to attrcache if time overflow, but @@ -354,9 +356,9 @@ r4_do_attrcache(vnode_t *vp, nfs4_ga_res_t *garp, int newnode, if (vp->v_type != attr->va_type && vp->v_type != VNON && attr->va_type != VNON) { zcmn_err(VTOMI4(vp)->mi_zone->zone_id, CE_WARN, - "makenfs4node: type (%d) doesn't " - "match type of found node at %p (%d)", - attr->va_type, (void *)vp, vp->v_type); + "makenfs4node: type (%d) doesn't " + "match type of found node at %p (%d)", + attr->va_type, (void *)vp, vp->v_type); } #endif nfs4_attr_cache(vp, garp, t, cr, TRUE, NULL); @@ -368,39 +370,47 @@ r4_do_attrcache(vnode_t *vp, nfs4_ga_res_t *garp, int newnode, /* * Turn this object into a "stub" object if we - * crossed an underlying server fs boundary. To - * make this check, during mount we save the + * crossed an underlying server fs boundary. + * To make this check, during mount we save the * fsid of the server object being mounted. * Here we compare this object's server fsid * with the fsid we saved at mount. If they * are different, we crossed server fs boundary. * - * The stub flag is set (or not) at rnode + * The stub type is set (or not) at rnode * creation time and it never changes for life - * of rnode. + * of the rnode. * - * We don't bother with taking r_state_lock - * to set R4SRVSTUB flag because this is a new - * rnode and we're holding rtable lock. No other - * thread could have obtained access to this - * rnode. + * The stub type is also set during RO failover, + * nfs4_remap_file(). + * + * This stub will be for a mirror-mount. + * + * We don't bother with taking r_state_lock to + * set the stub type because this is a new rnode + * and we're holding the hash bucket r_lock RW_WRITER. + * No other thread could have obtained access + * to this rnode. */ + is_stub = 0; if (garp->n4g_fsid_valid) { - rp->r_srv_fsid = garp->n4g_fsid; + fattr4_fsid ga_fsid = garp->n4g_fsid; + servinfo4_t *svp = rp->r_server; - if (vp->v_type == VDIR) { - servinfo4_t *svp = rp->r_server; + rp->r_srv_fsid = ga_fsid; - (void) nfs_rw_enter_sig(&svp->sv_lock, - RW_READER, 0); - if (!FATTR4_FSID_EQ(&garp->n4g_fsid, - &svp->sv_fsid)) { - rp->r_flags |= R4SRVSTUB; - } - nfs_rw_exit(&svp->sv_lock); - } + (void) nfs_rw_enter_sig(&svp->sv_lock, + RW_READER, 0); + if (!FATTR4_FSID_EQ(&ga_fsid, &svp->sv_fsid)) + is_stub = 1; + nfs_rw_exit(&svp->sv_lock); } + if (is_stub) + r4_stub_mirrormount(rp); + else + r4_stub_none(rp); + /* Can not cache partial attr */ if (attr->va_mask == AT_ALL) nfs4_attrcache_noinval(vp, garp, t); @@ -427,8 +437,8 @@ r4_do_attrcache(vnode_t *vp, nfs4_ga_res_t *garp, int newnode, vnode_t * makenfs4node_by_fh(nfs4_sharedfh_t *sfh, nfs4_sharedfh_t *psfh, - nfs4_fname_t **npp, nfs4_ga_res_t *garp, - mntinfo4_t *mi, cred_t *cr, hrtime_t t) + nfs4_fname_t **npp, nfs4_ga_res_t *garp, + mntinfo4_t *mi, cred_t *cr, hrtime_t t) { vfs_t *vfsp = mi->mi_vfsp; int newnode = 0; @@ -480,7 +490,7 @@ makenfs4node_by_fh(nfs4_sharedfh_t *sfh, nfs4_sharedfh_t *psfh, */ vnode_t * makenfs4node(nfs4_sharedfh_t *fh, nfs4_ga_res_t *garp, struct vfs *vfsp, - hrtime_t t, cred_t *cr, vnode_t *dvp, nfs4_fname_t *nm) + hrtime_t t, cred_t *cr, vnode_t *dvp, nfs4_fname_t *nm) { vnode_t *vp; int newnode; @@ -775,7 +785,7 @@ rp4_addfree(rnode4_t *rp, cred_t *cr) */ if (rp->r_deleg_type != OPEN_DELEGATE_NONE) { (void) nfs4delegreturn(rp, - NFS4_DR_FORCE|NFS4_DR_PUSH|NFS4_DR_REOPEN); + NFS4_DR_FORCE|NFS4_DR_PUSH|NFS4_DR_REOPEN); } r4inactive(rp, cr); @@ -838,7 +848,7 @@ again: if (rp->r_deleg_type != OPEN_DELEGATE_NONE) { rw_exit(&rp->r_hashq->r_lock); (void) nfs4delegreturn(rp, - NFS4_DR_FORCE|NFS4_DR_PUSH|NFS4_DR_REOPEN); + NFS4_DR_FORCE|NFS4_DR_PUSH|NFS4_DR_REOPEN); goto again; } @@ -986,7 +996,6 @@ rp4_rmhash_locked(rnode4_t *rp) void rp4_rmhash(rnode4_t *rp) { - rw_enter(&rp->r_hashq->r_lock, RW_WRITER); rp4_rmhash_locked(rp); rw_exit(&rp->r_hashq->r_lock); @@ -1102,7 +1111,7 @@ check_rtable4(struct vfs *vfsp) if (rp->r_freef == NULL) { busy = "not on free list"; } else if (nfs4_has_pages(vp) && - (rp->r_flags & R4DIRTY)) { + (rp->r_flags & R4DIRTY)) { busy = "dirty pages"; } else if (rp->r_count > 0) { busy = "r_count > 0"; @@ -1131,7 +1140,7 @@ check_rtable4(struct vfs *vfsp) /* * Destroy inactive vnodes from the hash queues which * belong to this vfs. All of the vnodes should be inactive. - * It is essential that we destory all rnodes in case of + * It is essential that we destroy all rnodes in case of * forced unmount as well as in normal unmount case. */ @@ -1539,7 +1548,6 @@ nfs4_rnode_reclaim(void) static void nfs4_reclaim(void *cdrarg) { - #ifdef DEBUG clstat4_debug.reclaim.value.ui64++; #endif @@ -1679,14 +1687,14 @@ r4mkopenlist(mntinfo4_t *mi) * Add a new open instance to the list */ rep = kmem_zalloc(sizeof (*reopenlist), - KM_SLEEP); + KM_SLEEP); rep->re_next = reopenlist; reopenlist = rep; rep->re_vp = vp; rep->re_osp = kmem_zalloc( - numosp * sizeof (*(rep->re_osp)), - KM_SLEEP); + numosp * sizeof (*(rep->re_osp)), + KM_SLEEP); rep->re_numosp = numosp; j = 0; @@ -1724,7 +1732,7 @@ r4mkopenlist(mntinfo4_t *mi) */ if (numosp > 0) rp->r_deleg_needs_recovery = - rp->r_deleg_type; + rp->r_deleg_type; } /* Save the delegation type for use outside the lock */ dtype = rp->r_deleg_type; @@ -1758,7 +1766,7 @@ r4releopenlist(nfs4_opinst_t *reopenp) next = rep->re_next; for (i = 0; i < rep->re_numosp; i++) - open_stream_rele(rep->re_osp[i], VTOR4(rep->re_vp)); + open_stream_rele(rep->re_osp[i], VTOR4(rep->re_vp)); VN_RELE(rep->re_vp); kmem_free(rep->re_osp, @@ -1840,6 +1848,45 @@ isrootfh(nfs4_sharedfh_t *fh, rnode4_t *rp) return (isroot); } +/* + * The r4_stub_* routines assume that the rnode is newly activated, and + * that the caller either holds the hash bucket r_lock for this rnode as + * RW_WRITER, or holds r_statelock. + */ +static void +r4_stub_set(rnode4_t *rp, nfs4_stub_type_t type) +{ + vnode_t *vp = RTOV4(rp); + krwlock_t *hash_lock = &rp->r_hashq->r_lock; + + ASSERT(RW_WRITE_HELD(hash_lock) || MUTEX_HELD(&rp->r_statelock)); + + rp->r_stub_type = type; + + /* + * Safely switch this vnode to the trigger vnodeops. + * + * Currently, we don't ever switch a trigger vnode back to using + * "regular" v4 vnodeops. NFS4_STUB_NONE is only used to note that + * a new v4 object is not a trigger, and it will already have the + * correct v4 vnodeops by default. So, no "else" case required here. + */ + if (type != NFS4_STUB_NONE) + vn_setops(vp, nfs4_trigger_vnodeops); +} + +void +r4_stub_mirrormount(rnode4_t *rp) +{ + r4_stub_set(rp, NFS4_STUB_MIRRORMOUNT); +} + +void +r4_stub_none(rnode4_t *rp) +{ + r4_stub_set(rp, NFS4_STUB_NONE); +} + #ifdef DEBUG /* diff --git a/usr/src/uts/common/fs/nfs/nfs4_stub_vnops.c b/usr/src/uts/common/fs/nfs/nfs4_stub_vnops.c new file mode 100644 index 0000000000..e0b9ce1800 --- /dev/null +++ b/usr/src/uts/common/fs/nfs/nfs4_stub_vnops.c @@ -0,0 +1,2448 @@ +/* + * 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 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Support for ephemeral mounts, e.g. mirror-mounts. These mounts are + * triggered from a "stub" rnode via a special set of vnodeops. + */ + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/systm.h> +#include <sys/cred.h> +#include <sys/time.h> +#include <sys/vnode.h> +#include <sys/vfs.h> +#include <sys/vfs_opreg.h> +#include <sys/file.h> +#include <sys/filio.h> +#include <sys/uio.h> +#include <sys/buf.h> +#include <sys/mman.h> +#include <sys/pathname.h> +#include <sys/dirent.h> +#include <sys/debug.h> +#include <sys/vmsystm.h> +#include <sys/fcntl.h> +#include <sys/flock.h> +#include <sys/swap.h> +#include <sys/errno.h> +#include <sys/strsubr.h> +#include <sys/sysmacros.h> +#include <sys/kmem.h> +#include <sys/mount.h> +#include <sys/cmn_err.h> +#include <sys/pathconf.h> +#include <sys/utsname.h> +#include <sys/dnlc.h> +#include <sys/acl.h> +#include <sys/systeminfo.h> +#include <sys/policy.h> +#include <sys/sdt.h> +#include <sys/list.h> +#include <sys/stat.h> +#include <sys/mntent.h> + +#include <rpc/types.h> +#include <rpc/auth.h> +#include <rpc/clnt.h> + +#include <nfs/nfs.h> +#include <nfs/nfs_clnt.h> +#include <nfs/nfs_acl.h> +#include <nfs/lm.h> +#include <nfs/nfs4.h> +#include <nfs/nfs4_kprot.h> +#include <nfs/rnode4.h> +#include <nfs/nfs4_clnt.h> + +#include <vm/hat.h> +#include <vm/as.h> +#include <vm/page.h> +#include <vm/pvn.h> +#include <vm/seg.h> +#include <vm/seg_map.h> +#include <vm/seg_kpm.h> +#include <vm/seg_vn.h> + +#include <fs/fs_subr.h> + +#include <sys/ddi.h> +#include <sys/int_fmtio.h> + +#include <util/string.h> + +/* + * The automatic unmounter thread stuff! + */ +static int nfs4_trigger_thread_timer = 20; /* in seconds */ + +/* + * Just a default.... + */ +static uint_t nfs4_trigger_mount_to = 240; + +typedef struct nfs4_trigger_globals { + kmutex_t ntg_forest_lock; + uint_t ntg_mount_to; + int ntg_thread_started; + nfs4_ephemeral_tree_t *ntg_forest; +} nfs4_trigger_globals_t; + +kmutex_t nfs4_ephemeral_thread_lock; + +zone_key_t nfs4_ephemeral_key = ZONE_KEY_UNINITIALIZED; + +static void nfs4_ephemeral_start_harvester(nfs4_trigger_globals_t *); + +/* + * Used for ephemeral mounts; contains data either duplicated from + * servinfo4_t, or hand-crafted, depending on type of ephemeral mount. + * + * It's intended that this structure is used solely for ephemeral + * mount-type specific data, for passing this data to + * nfs4_trigger_nargs_create(). + */ +typedef struct ephemeral_servinfo { + char *esi_hostname; + char *esi_netname; + char *esi_path; + int esi_path_len; + int esi_mount_flags; + struct netbuf *esi_addr; + struct netbuf *esi_syncaddr; + struct knetconfig *esi_knconf; +} ephemeral_servinfo_t; + +/* + * Collect together the mount-type specific and generic data args. + */ +typedef struct domount_args { + ephemeral_servinfo_t *dma_esi; + char *dma_hostlist; /* comma-sep. for RO failover */ + struct nfs_args *dma_nargs; +} domount_args_t; + + +/* + * The vnode ops functions for a trigger stub vnode + */ +static int nfs4_trigger_open(vnode_t **, int, cred_t *); +static int nfs4_trigger_getattr(vnode_t *, struct vattr *, int, cred_t *); +static int nfs4_trigger_setattr(vnode_t *, struct vattr *, int, cred_t *, + caller_context_t *); +static int nfs4_trigger_access(vnode_t *, int, int, cred_t *); +static int nfs4_trigger_readlink(vnode_t *, struct uio *, cred_t *); +static int nfs4_trigger_lookup(vnode_t *, char *, vnode_t **, + struct pathname *, int, vnode_t *, cred_t *); +static int nfs4_trigger_create(vnode_t *, char *, struct vattr *, + enum vcexcl, int, vnode_t **, cred_t *, int); +static int nfs4_trigger_remove(vnode_t *, char *, cred_t *); +static int nfs4_trigger_link(vnode_t *, vnode_t *, char *, cred_t *); +static int nfs4_trigger_rename(vnode_t *, char *, vnode_t *, char *, + cred_t *); +static int nfs4_trigger_mkdir(vnode_t *, char *, struct vattr *, + vnode_t **, cred_t *); +static int nfs4_trigger_rmdir(vnode_t *, char *, vnode_t *, cred_t *); +static int nfs4_trigger_symlink(vnode_t *, char *, struct vattr *, char *, + cred_t *); +static int nfs4_trigger_cmp(vnode_t *, vnode_t *); + +/* + * Regular NFSv4 vnodeops that we need to reference directly + */ +extern int nfs4_getattr(vnode_t *, struct vattr *, int, cred_t *); +extern void nfs4_inactive(vnode_t *, cred_t *); +extern int nfs4_rwlock(vnode_t *, int, caller_context_t *); +extern void nfs4_rwunlock(vnode_t *, int, caller_context_t *); +extern int nfs4_lookup(vnode_t *, char *, vnode_t **, + struct pathname *, int, vnode_t *, cred_t *); +extern int nfs4_pathconf(vnode_t *, int, ulong_t *, cred_t *); +extern int nfs4_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *); +extern int nfs4_fid(vnode_t *, fid_t *); +extern int nfs4_realvp(vnode_t *, vnode_t **); + +static int nfs4_trigger_mount(vnode_t *, vnode_t **); +static int nfs4_trigger_domount(vnode_t *, domount_args_t *, vfs_t **, + cred_t *); +static domount_args_t *nfs4_trigger_domount_args_create(vnode_t *); +static void nfs4_trigger_domount_args_destroy(domount_args_t *dma, + vnode_t *vp); +static ephemeral_servinfo_t *nfs4_trigger_esi_create(vnode_t *, servinfo4_t *); +static void nfs4_trigger_esi_destroy(ephemeral_servinfo_t *, vnode_t *); +static ephemeral_servinfo_t *nfs4_trigger_esi_create_mirrormount(vnode_t *, + servinfo4_t *); +static struct nfs_args *nfs4_trigger_nargs_create(mntinfo4_t *, servinfo4_t *, + ephemeral_servinfo_t *); +static void nfs4_trigger_nargs_destroy(struct nfs_args *); +static char *nfs4_trigger_create_mntopts(vfs_t *); +static void nfs4_trigger_destroy_mntopts(char *); +static int nfs4_trigger_add_mntopt(char *, char *, vfs_t *); +static enum clnt_stat nfs4_trigger_ping_server(servinfo4_t *, int); + +extern int umount2_engine(vfs_t *, int, cred_t *, int); + + +vnodeops_t *nfs4_trigger_vnodeops; + +/* + * These are the vnodeops that we must define for stub vnodes. + * + * + * Many of the VOPs defined for NFSv4 do not need to be defined here, + * for various reasons. This will result in the VFS default function being + * used: + * + * - These VOPs require a previous VOP_OPEN to have occurred. That will have + * lost the reference to the stub vnode, meaning these should not be called: + * close, read, write, ioctl, readdir, seek. + * + * - These VOPs are meaningless for vnodes without data pages. Since the + * stub vnode is of type VDIR, these should not be called: + * space, getpage, putpage, map, addmap, delmap, pageio, fsync. + * + * - These VOPs are otherwise not applicable, and should not be called: + * dump, setsecattr. + * + * + * These VOPs we do not want to define, but nor do we want the VFS default + * action. Instead, we specify the VFS error function, with fs_error(), but + * note that fs_error() is not actually called. Instead it results in the + * use of the error function defined for the particular VOP, in vn_ops_table[]: + * + * - frlock, dispose, shrlock. + * + * + * These VOPs we define to use the corresponding regular NFSv4 vnodeop. + * NOTE: if any of these ops involve an OTW call with the stub FH, then + * that call must be wrapped with save_mnt_secinfo()/check_mnt_secinfo() + * to protect the security data in the servinfo4_t for the "parent" + * filesystem that contains the stub. + * + * - These VOPs should not trigger a mount, so that "ls -l" does not: + * pathconf, getsecattr. + * + * - These VOPs would not make sense to trigger: + * inactive, rwlock, rwunlock, fid, realvp. + */ +const fs_operation_def_t nfs4_trigger_vnodeops_template[] = { + VOPNAME_OPEN, { .vop_open = nfs4_trigger_open }, + VOPNAME_GETATTR, { .vop_getattr = nfs4_trigger_getattr }, + VOPNAME_SETATTR, { .vop_setattr = nfs4_trigger_setattr }, + VOPNAME_ACCESS, { .vop_access = nfs4_trigger_access }, + VOPNAME_LOOKUP, { .vop_lookup = nfs4_trigger_lookup }, + VOPNAME_CREATE, { .vop_create = nfs4_trigger_create }, + VOPNAME_REMOVE, { .vop_remove = nfs4_trigger_remove }, + VOPNAME_LINK, { .vop_link = nfs4_trigger_link }, + VOPNAME_RENAME, { .vop_rename = nfs4_trigger_rename }, + VOPNAME_MKDIR, { .vop_mkdir = nfs4_trigger_mkdir }, + VOPNAME_RMDIR, { .vop_rmdir = nfs4_trigger_rmdir }, + VOPNAME_SYMLINK, { .vop_symlink = nfs4_trigger_symlink }, + VOPNAME_READLINK, { .vop_readlink = nfs4_trigger_readlink }, + VOPNAME_INACTIVE, { .vop_inactive = nfs4_inactive }, + VOPNAME_FID, { .vop_fid = nfs4_fid }, + VOPNAME_RWLOCK, { .vop_rwlock = nfs4_rwlock }, + VOPNAME_RWUNLOCK, { .vop_rwunlock = nfs4_rwunlock }, + VOPNAME_REALVP, { .vop_realvp = nfs4_realvp }, + VOPNAME_GETSECATTR, { .vop_getsecattr = nfs4_getsecattr }, + VOPNAME_PATHCONF, { .vop_pathconf = nfs4_pathconf }, + VOPNAME_FRLOCK, { .error = fs_error }, + VOPNAME_DISPOSE, { .error = fs_error }, + VOPNAME_SHRLOCK, { .error = fs_error }, + VOPNAME_VNEVENT, { .vop_vnevent = fs_vnevent_support }, + NULL, NULL +}; + +/* + * Trigger ops for stub vnodes; for mirror mounts, etc. + * + * The general idea is that a "triggering" op will first call + * nfs4_trigger_mount(), which will find out whether a mount has already + * been triggered. + * + * If it has, then nfs4_trigger_mount() sets newvp to the root vnode + * of the covering vfs. + * + * If a mount has not yet been triggered, nfs4_trigger_mount() will do so, + * and again set newvp, as above. + * + * The triggering op may then re-issue the VOP by calling it on newvp. + * + * Note that some ops may perform custom action, and may or may not need + * to trigger a mount. + * + * Some ops need to call the regular NFSv4 vnodeop for a stub vnode. We + * obviously can't do this with VOP_<whatever>, since it's a stub vnode + * and that would just recurse. Instead, we call the v4 op directly, + * by name. This is OK, since we know that the vnode is for NFSv4, + * otherwise it couldn't be a stub. + * + */ + +static int +nfs4_trigger_open(vnode_t **vpp, int flag, cred_t *cr) +{ + int error; + vnode_t *newvp; + + error = nfs4_trigger_mount(*vpp, &newvp); + if (error) + return (error); + + /* Release the stub vnode, as we're losing the reference to it */ + VN_RELE(*vpp); + + /* Give the caller the root vnode of the newly-mounted fs */ + *vpp = newvp; + + /* return with VN_HELD(newvp) */ + return (VOP_OPEN(vpp, flag, cr)); +} + +/* + * For the majority of cases, nfs4_trigger_getattr() will not trigger + * a mount. However, if ATTR_TRIGGER is set, we are being informed + * that we need to force the mount before we attempt to determine + * the attributes. The intent is an atomic operation for security + * testing. + */ +static int +nfs4_trigger_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr) +{ + int error; + + if (flags & ATTR_TRIGGER) { + vnode_t *newvp; + + error = nfs4_trigger_mount(vp, &newvp); + if (error) + return (error); + + error = VOP_GETATTR(newvp, vap, flags, cr); + VN_RELE(newvp); + } else { + error = nfs4_getattr(vp, vap, flags, cr); + } + + return (error); +} + +static int +nfs4_trigger_setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr, + caller_context_t *ct) +{ + int error; + vnode_t *newvp; + + error = nfs4_trigger_mount(vp, &newvp); + if (error) + return (error); + + error = VOP_SETATTR(newvp, vap, flags, cr, ct); + VN_RELE(newvp); + + return (error); +} + +static int +nfs4_trigger_access(vnode_t *vp, int mode, int flags, cred_t *cr) +{ + int error; + vnode_t *newvp; + + error = nfs4_trigger_mount(vp, &newvp); + if (error) + return (error); + + error = VOP_ACCESS(newvp, mode, flags, cr); + VN_RELE(newvp); + + return (error); +} + +static int +nfs4_trigger_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp, + int flags, vnode_t *rdir, cred_t *cr) +{ + int error; + vnode_t *newdvp; + rnode4_t *drp = VTOR4(dvp); + + ASSERT(RP_ISSTUB(drp)); + + /* for now, we only support mirror-mounts */ + ASSERT(RP_ISSTUB_MIRRORMOUNT(drp)); + + /* + * It's not legal to lookup ".." for an fs root, so we mustn't pass + * that up. Instead, pass onto the regular op, regardless of whether + * we've triggered a mount. + */ + if (strcmp(nm, "..") == 0) + return (nfs4_lookup(dvp, nm, vpp, pnp, flags, rdir, cr)); + + error = nfs4_trigger_mount(dvp, &newdvp); + if (error) + return (error); + + error = VOP_LOOKUP(newdvp, nm, vpp, pnp, flags, rdir, cr); + VN_RELE(newdvp); + + return (error); +} + +static int +nfs4_trigger_create(vnode_t *dvp, char *nm, struct vattr *va, + enum vcexcl exclusive, int mode, vnode_t **vpp, cred_t *cr, + int flags) +{ + int error; + vnode_t *newdvp; + + error = nfs4_trigger_mount(dvp, &newdvp); + if (error) + return (error); + + error = VOP_CREATE(newdvp, nm, va, exclusive, mode, vpp, cr, flags); + VN_RELE(newdvp); + + return (error); +} + +static int +nfs4_trigger_remove(vnode_t *dvp, char *nm, cred_t *cr) +{ + int error; + vnode_t *newdvp; + + error = nfs4_trigger_mount(dvp, &newdvp); + if (error) + return (error); + + error = VOP_REMOVE(newdvp, nm, cr); + VN_RELE(newdvp); + + return (error); +} + +static int +nfs4_trigger_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr) +{ + int error; + vnode_t *newtdvp; + + error = nfs4_trigger_mount(tdvp, &newtdvp); + if (error) + return (error); + + /* + * We don't check whether svp is a stub. Let the NFSv4 code + * detect that error, and return accordingly. + */ + error = VOP_LINK(newtdvp, svp, tnm, cr); + VN_RELE(newtdvp); + + return (error); +} + +static int +nfs4_trigger_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm, + cred_t *cr) +{ + int error; + vnode_t *newsdvp; + rnode4_t *tdrp = VTOR4(tdvp); + + /* + * We know that sdvp is a stub, otherwise we would not be here. + * + * If tdvp is also be a stub, there are two possibilities: it + * is either the same stub as sdvp [i.e. VN_CMP(sdvp, tdvp)] + * or it is a different stub [!VN_CMP(sdvp, tdvp)]. + * + * In the former case, just trigger sdvp, and treat tdvp as + * though it were not a stub. + * + * In the latter case, it might be a different stub for the + * same server fs as sdvp, or for a different server fs. + * Regardless, from the client perspective this would still + * be a cross-filesystem rename, and should not be allowed, + * so return EXDEV, without triggering either mount. + */ + if (RP_ISSTUB(tdrp) && !VN_CMP(sdvp, tdvp)) + return (EXDEV); + + error = nfs4_trigger_mount(sdvp, &newsdvp); + if (error) + return (error); + + error = VOP_RENAME(newsdvp, snm, tdvp, tnm, cr); + + VN_RELE(newsdvp); + + return (error); +} + +static int +nfs4_trigger_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp, + cred_t *cr) +{ + int error; + vnode_t *newdvp; + + error = nfs4_trigger_mount(dvp, &newdvp); + if (error) + return (error); + + error = VOP_MKDIR(newdvp, nm, va, vpp, cr); + VN_RELE(newdvp); + + return (error); +} + +static int +nfs4_trigger_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr) +{ + int error; + vnode_t *newdvp; + + error = nfs4_trigger_mount(dvp, &newdvp); + if (error) + return (error); + + error = VOP_RMDIR(newdvp, nm, cdir, cr); + VN_RELE(newdvp); + + return (error); +} + +static int +nfs4_trigger_symlink(vnode_t *dvp, char *lnm, struct vattr *tva, char *tnm, + cred_t *cr) +{ + int error; + vnode_t *newdvp; + + error = nfs4_trigger_mount(dvp, &newdvp); + if (error) + return (error); + + error = VOP_SYMLINK(newdvp, lnm, tva, tnm, cr); + VN_RELE(newdvp); + + return (error); +} + +static int +nfs4_trigger_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr) +{ + int error; + vnode_t *newvp; + + error = nfs4_trigger_mount(vp, &newvp); + if (error) + return (error); + + error = VOP_READLINK(newvp, uiop, cr); + VN_RELE(newvp); + + return (error); +} + +/* end of trigger vnode ops */ + + +/* + * Mount upon a trigger vnode; for mirror-mounts, etc. + * + * The mount may have already occurred, via another thread. If not, + * assemble the location information - which may require fetching - and + * perform the mount. + * + * Sets newvp to be the root of the fs that is now covering vp. Note + * that we return with VN_HELD(*newvp). + * + * The caller is responsible for passing the VOP onto the covering fs. + */ +static int +nfs4_trigger_mount(vnode_t *vp, vnode_t **newvpp) +{ + int error; + vfs_t *vfsp; + rnode4_t *rp = VTOR4(vp); + mntinfo4_t *mi = VTOMI4(vp); + domount_args_t *dma; + + nfs4_ephemeral_tree_t *net; + + bool_t must_unlock = FALSE; + bool_t is_building = FALSE; + + cred_t *zcred; + + nfs4_trigger_globals_t *ntg; + + zone_t *zone = curproc->p_zone; + + ASSERT(RP_ISSTUB(rp)); + + /* for now, we only support mirror-mounts */ + ASSERT(RP_ISSTUB_MIRRORMOUNT(rp)); + + *newvpp = NULL; + + /* + * Has the mount already occurred? + */ + error = vn_vfsrlock_wait(vp); + if (error) + goto done; + vfsp = vn_mountedvfs(vp); + if (vfsp != NULL) { + /* the mount has already occurred */ + error = VFS_ROOT(vfsp, newvpp); + if (!error) { + /* need to update the reference time */ + mutex_enter(&mi->mi_lock); + if (mi->mi_ephemeral) + mi->mi_ephemeral->ne_ref_time = + gethrestime_sec(); + mutex_exit(&mi->mi_lock); + } + + vn_vfsunlock(vp); + goto done; + } + vn_vfsunlock(vp); + + ntg = zone_getspecific(nfs4_ephemeral_key, zone); + ASSERT(ntg != NULL); + + mutex_enter(&mi->mi_lock); + + /* + * We need to lock down the ephemeral tree. + */ + if (mi->mi_ephemeral_tree == NULL) { + net = kmem_zalloc(sizeof (*net), KM_SLEEP); + mutex_init(&net->net_tree_lock, NULL, MUTEX_DEFAULT, NULL); + mutex_init(&net->net_cnt_lock, NULL, MUTEX_DEFAULT, NULL); + net->net_refcnt = 1; + net->net_status = NFS4_EPHEMERAL_TREE_BUILDING; + is_building = TRUE; + + /* + * We need to add it to the zone specific list for + * automatic unmounting and harvesting of deadwood. + */ + mutex_enter(&ntg->ntg_forest_lock); + if (ntg->ntg_forest != NULL) + net->net_next = ntg->ntg_forest; + ntg->ntg_forest = net; + mutex_exit(&ntg->ntg_forest_lock); + + /* + * No lock order confusion with mi_lock because no + * other node could have grabbed net_tree_lock. + */ + mutex_enter(&net->net_tree_lock); + mi->mi_ephemeral_tree = net; + net->net_mount = mi; + mutex_exit(&mi->mi_lock); + } else { + net = mi->mi_ephemeral_tree; + mutex_exit(&mi->mi_lock); + + mutex_enter(&net->net_cnt_lock); + net->net_refcnt++; + mutex_exit(&net->net_cnt_lock); + + /* + * Note that we do not do any checks to + * see if the parent has been nuked. + * We count on the vfs layer having protected + * us from feet shooters. + */ + mutex_enter(&net->net_tree_lock); + } + + mutex_enter(&net->net_cnt_lock); + net->net_status |= NFS4_EPHEMERAL_TREE_MOUNTING; + mutex_exit(&net->net_cnt_lock); + + must_unlock = TRUE; + + dma = nfs4_trigger_domount_args_create(vp); + if (dma == NULL) { + error = EINVAL; + goto done; + } + + /* + * Need to be root for this call to make mount work. + * Note that since we define mirror mounts to work + * for any user, we allow the mount to proceed. And + * we realize that the server will perform security + * checks to make sure that the client is allowed + * access. Finally, once the mount takes place, + * directory permissions will ensure that the + * content is secure. + */ + zcred = zone_get_kcred(getzoneid()); + ASSERT(zcred != NULL); + + error = nfs4_trigger_domount(vp, dma, &vfsp, zcred); + nfs4_trigger_domount_args_destroy(dma, vp); + + crfree(zcred); + + if (!error) + error = VFS_ROOT(vfsp, newvpp); +done: + if (must_unlock) { + mutex_enter(&net->net_cnt_lock); + net->net_status &= ~NFS4_EPHEMERAL_TREE_MOUNTING; + if (is_building) + net->net_status &= ~NFS4_EPHEMERAL_TREE_BUILDING; + net->net_refcnt--; + mutex_exit(&net->net_cnt_lock); + + mutex_exit(&net->net_tree_lock); + } + + if (!error && (newvpp == NULL || *newvpp == NULL)) + error = ENOSYS; + + return (error); +} + +/* + * Collect together both the generic & mount-type specific args. + */ +static domount_args_t * +nfs4_trigger_domount_args_create(vnode_t *vp) +{ + int nointr; + char *hostlist; + servinfo4_t *svp; + struct nfs_args *nargs, *nargs_head; + enum clnt_stat status; + ephemeral_servinfo_t *esi, *esi_first; + domount_args_t *dma; + mntinfo4_t *mi = VTOMI4(vp); + + nointr = !(mi->mi_flags & MI4_INT); + hostlist = kmem_zalloc(MAXPATHLEN, KM_SLEEP); + + svp = mi->mi_curr_serv; + /* check if the current server is responding */ + status = nfs4_trigger_ping_server(svp, nointr); + if (status == RPC_SUCCESS) { + esi_first = nfs4_trigger_esi_create(vp, svp); + if (esi_first == NULL) { + kmem_free(hostlist, MAXPATHLEN); + return (NULL); + } + + (void) strlcpy(hostlist, esi_first->esi_hostname, MAXPATHLEN); + + nargs_head = nfs4_trigger_nargs_create(mi, svp, esi_first); + } else { + /* current server did not respond */ + esi_first = NULL; + nargs_head = NULL; + } + nargs = nargs_head; + + /* + * NFS RO failover. + * + * If we have multiple servinfo4 structures, linked via sv_next, + * we must create one nfs_args for each, linking the nfs_args via + * nfs_ext_u.nfs_extB.next. + * + * We need to build a corresponding esi for each, too, but that is + * used solely for building nfs_args, and may be immediately + * discarded, as domount() requires the info from just one esi, + * but all the nfs_args. + * + * Currently, the NFS mount code will hang if not all servers + * requested are available. To avoid that, we need to ping each + * server, here, and remove it from the list if it is not + * responding. This has the side-effect of that server then + * being permanently unavailable for this failover mount, even if + * it recovers. That's unfortunate, but the best we can do until + * the mount code path is fixed. + */ + + /* + * If the current server was down, loop indefinitely until we find + * at least one responsive server. + */ + do { + /* no locking needed for sv_next; it is only set at fs mount */ + for (svp = mi->mi_servers; svp != NULL; svp = svp->sv_next) { + struct nfs_args *next; + + /* + * nargs_head: the head of the nfs_args list + * nargs: the current tail of the list + * next: the newly-created element to be added + */ + + /* + * We've already tried the current server, above; + * if it was responding, we have already included it + * and it may now be ignored. + * + * Otherwise, try it again, since it may now have + * recovered. + */ + if (svp == mi->mi_curr_serv && esi_first != NULL) + continue; + + (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); + if (svp->sv_flags & SV4_NOTINUSE) { + nfs_rw_exit(&svp->sv_lock); + continue; + } + nfs_rw_exit(&svp->sv_lock); + + /* check if the server is responding */ + status = nfs4_trigger_ping_server(svp, nointr); + /* if the server did not respond, ignore it */ + if (status != RPC_SUCCESS) + continue; + + esi = nfs4_trigger_esi_create(vp, svp); + if (esi == NULL) + continue; + + /* + * If the original current server (mi_curr_serv) + * was down when when we first tried it, + * (i.e. esi_first == NULL), + * we select this new server (svp) to be the server + * that we will actually contact (esi_first). + * + * Note that it's possible that mi_curr_serv == svp, + * if that mi_curr_serv was down but has now recovered. + */ + next = nfs4_trigger_nargs_create(mi, svp, esi); + if (esi_first == NULL) { + ASSERT(nargs == NULL); + ASSERT(nargs_head == NULL); + nargs_head = next; + esi_first = esi; + (void) strlcpy(hostlist, + esi_first->esi_hostname, MAXPATHLEN); + } else { + ASSERT(nargs_head != NULL); + nargs->nfs_ext_u.nfs_extB.next = next; + (void) strlcat(hostlist, ",", MAXPATHLEN); + (void) strlcat(hostlist, esi->esi_hostname, + MAXPATHLEN); + /* esi was only needed for hostname & nargs */ + nfs4_trigger_esi_destroy(esi, vp); + } + + nargs = next; + } + + /* if we've had no response at all, wait a second */ + if (esi_first == NULL) + delay(drv_usectohz(1000000)); + + } while (esi_first == NULL); + ASSERT(nargs_head != NULL); + + dma = kmem_zalloc(sizeof (domount_args_t), KM_SLEEP); + dma->dma_esi = esi_first; + dma->dma_hostlist = hostlist; + dma->dma_nargs = nargs_head; + + return (dma); +} + +static void +nfs4_trigger_domount_args_destroy(domount_args_t *dma, vnode_t *vp) +{ + if (dma != NULL) { + if (dma->dma_esi != NULL && vp != NULL) + nfs4_trigger_esi_destroy(dma->dma_esi, vp); + + if (dma->dma_hostlist != NULL) + kmem_free(dma->dma_hostlist, MAXPATHLEN); + + if (dma->dma_nargs != NULL) { + struct nfs_args *nargs = dma->dma_nargs; + + do { + struct nfs_args *next = + nargs->nfs_ext_u.nfs_extB.next; + + nfs4_trigger_nargs_destroy(nargs); + nargs = next; + } while (nargs != NULL); + } + + kmem_free(dma, sizeof (domount_args_t)); + } +} + +/* + * The ephemeral_servinfo_t struct contains basic information we will need to + * perform the mount. Whilst the structure is generic across different + * types of ephemeral mount, the way we gather its contents differs. + */ +static ephemeral_servinfo_t * +nfs4_trigger_esi_create(vnode_t *vp, servinfo4_t *svp) +{ + ephemeral_servinfo_t *esi; + rnode4_t *rp = VTOR4(vp); + + ASSERT(RP_ISSTUB(rp)); + + /* Call the ephemeral type-specific routine */ + if (RP_ISSTUB_MIRRORMOUNT(rp)) + esi = nfs4_trigger_esi_create_mirrormount(vp, svp); + else + esi = NULL; + + /* for now, we only support mirror-mounts */ + ASSERT(esi != NULL); + + return (esi); +} + +static void +nfs4_trigger_esi_destroy(ephemeral_servinfo_t *esi, vnode_t *vp) +{ + rnode4_t *rp = VTOR4(vp); + + ASSERT(RP_ISSTUB(rp)); + + /* for now, we only support mirror-mounts */ + ASSERT(RP_ISSTUB_MIRRORMOUNT(rp)); + + /* Currently, no need for an ephemeral type-specific routine */ + + /* + * The contents of ephemeral_servinfo_t goes into nfs_args, + * and will be handled by nfs4_trigger_nargs_destroy(). + * We need only free the structure itself. + */ + if (esi != NULL) + kmem_free(esi, sizeof (ephemeral_servinfo_t)); +} + +/* + * Some of this may turn out to be common with other ephemeral types, + * in which case it should be moved to nfs4_trigger_esi_create(), or a + * common function called. + */ +static ephemeral_servinfo_t * +nfs4_trigger_esi_create_mirrormount(vnode_t *vp, servinfo4_t *svp) +{ + char *stubpath; + struct knetconfig *sikncp, *svkncp; + struct netbuf *bufp; + ephemeral_servinfo_t *esi; + + esi = kmem_zalloc(sizeof (ephemeral_servinfo_t), KM_SLEEP); + + /* initially set to be our type of ephemeral mount; may be added to */ + esi->esi_mount_flags = NFSMNT_MIRRORMOUNT; + + /* + * We're copying info from the stub rnode's servinfo4, but + * we must create new copies, not pointers, since this information + * is to be associated with the new mount, which will be + * unmounted (and its structures freed) separately + */ + + /* + * Sizes passed to kmem_[z]alloc here must match those freed + * in nfs4_free_args() + */ + + /* + * We hold sv_lock across kmem_zalloc() calls that may sleep, but this + * is difficult to avoid: as we need to read svp to calculate the + * sizes to be allocated. + */ + (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); + + esi->esi_hostname = kmem_zalloc(strlen(svp->sv_hostname) + 1, KM_SLEEP); + (void) strcat(esi->esi_hostname, svp->sv_hostname); + + esi->esi_addr = kmem_zalloc(sizeof (struct netbuf), KM_SLEEP); + bufp = esi->esi_addr; + bufp->len = svp->sv_addr.len; + bufp->maxlen = svp->sv_addr.maxlen; + bufp->buf = kmem_zalloc(bufp->len, KM_SLEEP); + bcopy(svp->sv_addr.buf, bufp->buf, bufp->len); + + esi->esi_knconf = kmem_zalloc(sizeof (*esi->esi_knconf), KM_SLEEP); + sikncp = esi->esi_knconf; + svkncp = svp->sv_knconf; + sikncp->knc_semantics = svkncp->knc_semantics; + sikncp->knc_protofmly = (caddr_t)kmem_zalloc(KNC_STRSIZE, KM_SLEEP); + (void) strcat((char *)sikncp->knc_protofmly, + (char *)svkncp->knc_protofmly); + sikncp->knc_proto = (caddr_t)kmem_zalloc(KNC_STRSIZE, KM_SLEEP); + (void) strcat((char *)sikncp->knc_proto, (char *)svkncp->knc_proto); + sikncp->knc_rdev = svkncp->knc_rdev; + + /* + * Used when AUTH_DH is negotiated. + * + * This is ephemeral mount-type specific, since it contains the + * server's time-sync syncaddr. + */ + if (svp->sv_dhsec) { + struct netbuf *bufp; + sec_data_t *sdata; + dh_k4_clntdata_t *data; + + sdata = svp->sv_dhsec; + data = (dh_k4_clntdata_t *)sdata->data; + ASSERT(sdata->rpcflavor == AUTH_DH); + + bufp = kmem_zalloc(sizeof (struct netbuf), KM_SLEEP); + bufp->len = data->syncaddr.len; + bufp->maxlen = data->syncaddr.maxlen; + bufp->buf = kmem_zalloc(bufp->len, KM_SLEEP); + bcopy(data->syncaddr.buf, bufp->buf, bufp->len); + esi->esi_syncaddr = bufp; + + if (data->netname != NULL) { + int nmlen = data->netnamelen; + + /* + * We need to copy from a dh_k4_clntdata_t + * netname/netnamelen pair to a NUL-terminated + * netname string suitable for putting in nfs_args, + * where the latter has no netnamelen field. + */ + esi->esi_netname = kmem_zalloc(nmlen + 1, KM_SLEEP); + bcopy(data->netname, esi->esi_netname, nmlen); + } + } else { + esi->esi_syncaddr = NULL; + esi->esi_netname = NULL; + } + + stubpath = fn_path(VTOSV(vp)->sv_name); + /* step over initial '.', to avoid e.g. sv_path: "/tank./ws" */ + ASSERT(*stubpath == '.'); + stubpath += 1; + + /* for nfs_args->fh */ + esi->esi_path_len = strlen(svp->sv_path) + strlen(stubpath) + 1; + esi->esi_path = kmem_zalloc(esi->esi_path_len, KM_SLEEP); + (void) strcat(esi->esi_path, svp->sv_path); + (void) strcat(esi->esi_path, stubpath); + + stubpath -= 1; + /* stubpath allocated by fn_path() */ + kmem_free(stubpath, strlen(stubpath) + 1); + + nfs_rw_exit(&svp->sv_lock); + + return (esi); +} + +/* + * Assemble the args, and call the generic VFS mount function to + * finally perform the ephemeral mount. + */ +static int +nfs4_trigger_domount(vnode_t *stubvp, domount_args_t *dma, vfs_t **vfsp, + cred_t *cr) +{ + struct mounta *uap; + char *mntpt, *orig_path, *path; + const char *orig_mntpt; + int retval; + int mntpt_len; + int spec_len; + zone_t *zone = curproc->p_zone; + bool_t has_leading_slash; + + vfs_t *stubvfsp = stubvp->v_vfsp; + ephemeral_servinfo_t *esi = dma->dma_esi; + struct nfs_args *nargs = dma->dma_nargs; + + /* first, construct the mount point for the ephemeral mount */ + orig_path = path = fn_path(VTOSV(stubvp)->sv_name); + orig_mntpt = (char *)refstr_value(stubvfsp->vfs_mntpt); + + if (*orig_path == '.') + orig_path++; + + /* + * Get rid of zone's root path + */ + if (zone != global_zone) { + /* + * -1 for trailing '/' and -1 for EOS. + */ + if (strncmp(zone->zone_rootpath, orig_mntpt, + zone->zone_rootpathlen - 1) == 0) { + orig_mntpt += (zone->zone_rootpathlen - 2); + } + } + + mntpt_len = strlen(orig_mntpt) + strlen(orig_path); + mntpt = kmem_zalloc(mntpt_len + 1, KM_SLEEP); + (void) strcat(mntpt, orig_mntpt); + (void) strcat(mntpt, orig_path); + + kmem_free(path, strlen(path) + 1); + path = esi->esi_path; + if (*path == '.') + path++; + if (path[0] == '/' && path[1] == '/') + path++; + has_leading_slash = (*path == '/'); + + spec_len = strlen(dma->dma_hostlist); + spec_len += strlen(path); + + /* We are going to have to add this in */ + if (!has_leading_slash) + spec_len++; + + /* We need to get the ':' for dma_hostlist:esi_path */ + spec_len++; + + uap = kmem_zalloc(sizeof (struct mounta), KM_SLEEP); + uap->spec = kmem_zalloc(spec_len + 1, KM_SLEEP); + (void) snprintf(uap->spec, spec_len + 1, "%s:%s%s", dma->dma_hostlist, + has_leading_slash ? "" : "/", path); + + uap->dir = mntpt; + + uap->flags = MS_SYSSPACE | MS_DATA; + /* fstype-independent mount options not covered elsewhere */ + /* copy parent's mount(1M) "-m" flag */ + if (stubvfsp->vfs_flag & VFS_NOMNTTAB) + uap->flags |= MS_NOMNTTAB; + + uap->fstype = MNTTYPE_NFS4; + uap->dataptr = (char *)nargs; + /* not needed for MS_SYSSPACE */ + uap->datalen = 0; + + /* use optptr to pass in extra mount options */ + uap->flags |= MS_OPTIONSTR; + uap->optptr = nfs4_trigger_create_mntopts(stubvfsp); + if (uap->optptr == NULL) { + retval = EINVAL; + goto done; + } + /* domount() expects us to count the trailing NUL */ + uap->optlen = strlen(uap->optptr) + 1; + + retval = domount(NULL, uap, stubvp, cr, vfsp); + if (retval == 0) + VFS_RELE(*vfsp); +done: + if (uap->optptr) + nfs4_trigger_destroy_mntopts(uap->optptr); + + kmem_free(uap->spec, spec_len + 1); + kmem_free(uap, sizeof (struct mounta)); + kmem_free(mntpt, mntpt_len + 1); + + return (retval); +} + +/* + * Build an nfs_args structure for passing to domount(). + * + * Ephemeral mount-type specific data comes from the ephemeral_servinfo_t; + * generic data - common to all ephemeral mount types - is read directly + * from the parent mount's servinfo4_t and mntinfo4_t, via the stub vnode. + */ +static struct nfs_args * +nfs4_trigger_nargs_create(mntinfo4_t *mi, servinfo4_t *svp, + ephemeral_servinfo_t *esi) +{ + sec_data_t *secdata; + struct nfs_args *nargs; + + /* setup the nfs args */ + nargs = kmem_zalloc(sizeof (struct nfs_args), KM_SLEEP); + + (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); + + nargs->addr = esi->esi_addr; + + /* for AUTH_DH by negotiation */ + if (esi->esi_syncaddr || esi->esi_netname) { + nargs->flags |= NFSMNT_SECURE; + nargs->syncaddr = esi->esi_syncaddr; + nargs->netname = esi->esi_netname; + } + + nargs->flags |= NFSMNT_KNCONF; + nargs->knconf = esi->esi_knconf; + nargs->flags |= NFSMNT_HOSTNAME; + nargs->hostname = esi->esi_hostname; + nargs->fh = esi->esi_path; + + /* general mount settings, all copied from parent mount */ + mutex_enter(&mi->mi_lock); + + if (!(mi->mi_flags & MI4_HARD)) + nargs->flags |= NFSMNT_SOFT; + + nargs->flags |= NFSMNT_WSIZE | NFSMNT_RSIZE | NFSMNT_TIMEO | + NFSMNT_RETRANS; + nargs->wsize = mi->mi_stsize; + nargs->rsize = mi->mi_tsize; + nargs->timeo = mi->mi_timeo; + nargs->retrans = mi->mi_retrans; + + if (mi->mi_flags & MI4_INT) + nargs->flags |= NFSMNT_INT; + if (mi->mi_flags & MI4_NOAC) + nargs->flags |= NFSMNT_NOAC; + + nargs->flags |= NFSMNT_ACREGMIN | NFSMNT_ACREGMAX | NFSMNT_ACDIRMIN | + NFSMNT_ACDIRMAX; + nargs->acregmin = HR2SEC(mi->mi_acregmin); + nargs->acregmax = HR2SEC(mi->mi_acregmax); + nargs->acdirmin = HR2SEC(mi->mi_acdirmin); + nargs->acdirmax = HR2SEC(mi->mi_acdirmax); + + if (mi->mi_flags & MI4_NOCTO) + nargs->flags |= NFSMNT_NOCTO; + if (mi->mi_flags & MI4_GRPID) + nargs->flags |= NFSMNT_GRPID; + if (mi->mi_flags & MI4_LLOCK) + nargs->flags |= NFSMNT_LLOCK; + if (mi->mi_flags & MI4_NOPRINT) + nargs->flags |= NFSMNT_NOPRINT; + if (mi->mi_flags & MI4_DIRECTIO) + nargs->flags |= NFSMNT_DIRECTIO; + if (mi->mi_flags & MI4_PUBLIC) + nargs->flags |= NFSMNT_PUBLIC; + + mutex_exit(&mi->mi_lock); + + /* add any specific flags for this type of ephemeral mount */ + nargs->flags |= esi->esi_mount_flags; + + /* + * Security data & negotiation policy. + * + * We need to preserve the parent mount's preference for security + * negotiation, translating SV4_TRYSECDEFAULT -> NFSMNT_SECDEFAULT. + * + * If SV4_TRYSECDEFAULT is not set, that indicates that a specific + * security flavour was requested, with data in sv_secdata, and that + * no negotiation should occur. If this specified flavour fails, that's + * it. We will copy sv_secdata, and not set NFSMNT_SECDEFAULT. + * + * If SV4_TRYSECDEFAULT is set, then we start with a passed-in + * default flavour, in sv_secdata, but then negotiate a new flavour. + * Possible flavours are recorded in an array in sv_secinfo, with + * currently in-use flavour pointed to by sv_currsec. + * + * If sv_currsec is set, i.e. if negotiation has already occurred, + * we will copy sv_currsec. Otherwise, copy sv_secdata. Regardless, + * we will set NFSMNT_SECDEFAULT, to enable negotiation. + */ + if (svp->sv_flags & SV4_TRYSECDEFAULT) { + /* enable negotiation for ephemeral mount */ + nargs->flags |= NFSMNT_SECDEFAULT; + + /* + * As a starting point for negotiation, copy parent + * mount's negotiated flavour (sv_currsec) if available, + * or its passed-in flavour (sv_secdata) if not. + */ + if (svp->sv_currsec != NULL) + secdata = copy_sec_data(svp->sv_currsec); + else if (svp->sv_secdata != NULL) + secdata = copy_sec_data(svp->sv_secdata); + else + secdata = NULL; + } else { + /* do not enable negotiation; copy parent's passed-in flavour */ + if (svp->sv_secdata != NULL) + secdata = copy_sec_data(svp->sv_secdata); + else + secdata = NULL; + } + + nfs_rw_exit(&svp->sv_lock); + + nargs->flags |= NFSMNT_NEWARGS; + nargs->nfs_args_ext = NFS_ARGS_EXTB; + nargs->nfs_ext_u.nfs_extB.secdata = secdata; + + /* for NFS RO failover; caller will set if necessary */ + nargs->nfs_ext_u.nfs_extB.next = NULL; + + return (nargs); +} + +static void +nfs4_trigger_nargs_destroy(struct nfs_args *nargs) +{ + /* + * Either the mount failed, in which case the data is not needed, or + * nfs4_mount() has either taken copies of what it needs or, + * where it has merely copied the ptr, it has set *our* ptr to NULL, + * whereby nfs4_free_args() will ignore it. + */ + nfs4_free_args(nargs); + kmem_free(nargs, sizeof (struct nfs_args)); +} + +/* + * When we finally get into the mounting, we need to add this + * node to the ephemeral tree. + * + * This is called from nfs4_mount(). + */ +void +nfs4_record_ephemeral_mount(mntinfo4_t *mi, vnode_t *mvp) +{ + mntinfo4_t *mi_parent; + nfs4_ephemeral_t *eph; + nfs4_ephemeral_tree_t *net; + + nfs4_ephemeral_t *prior; + nfs4_ephemeral_t *child; + + nfs4_ephemeral_t *peer; + + nfs4_trigger_globals_t *ntg; + zone_t *zone = curproc->p_zone; + + mi_parent = VTOMI4(mvp); + + /* + * Get this before grabbing anything else! + */ + ntg = zone_getspecific(nfs4_ephemeral_key, zone); + if (!ntg->ntg_thread_started) { + nfs4_ephemeral_start_harvester(ntg); + } + + mutex_enter(&mi_parent->mi_lock); + mutex_enter(&mi->mi_lock); + + /* + * We need to tack together the ephemeral mount + * with this new mntinfo. + */ + eph = kmem_zalloc(sizeof (*eph), KM_SLEEP); + eph->ne_mount = mi; + eph->ne_ref_time = gethrestime_sec(); + + /* + * We need to tell the ephemeral mount when + * to time out. + */ + eph->ne_mount_to = ntg->ntg_mount_to; + + mi->mi_flags |= MI4_EPHEMERAL; + mi->mi_ephemeral = eph; + + net = mi->mi_ephemeral_tree = + mi_parent->mi_ephemeral_tree; + ASSERT(net != NULL); + + /* + * If the enclosing mntinfo4 is also ephemeral, + * then we need to point to its enclosing parent. + * Else the enclosing mntinfo4 is the enclosing parent. + * + * We also need to weave this ephemeral node + * into the tree. + */ + if (mi_parent->mi_flags & MI4_EPHEMERAL) { + /* + * We need to decide if we are + * the root node of this branch + * or if we are a sibling of this + * branch. + */ + prior = mi_parent->mi_ephemeral; + ASSERT(prior != NULL); + if (prior->ne_child == NULL) { + prior->ne_child = eph; + } else { + child = prior->ne_child; + + prior->ne_child = eph; + eph->ne_peer = child; + + child->ne_prior = eph; + } + + eph->ne_prior = prior; + } else { + /* + * The parent mntinfo4 is the non-ephemeral + * root of the ephemeral tree. We + * need to decide if we are the root + * node of that tree or if we are a + * sibling of the root node. + * + * We are the root if there is no + * other node. + */ + if (net->net_root == NULL) { + net->net_root = eph; + } else { + eph->ne_peer = peer = net->net_root; + ASSERT(peer != NULL); + net->net_root = eph; + + peer->ne_prior = eph; + } + + eph->ne_prior = NULL; + } + + mutex_exit(&mi->mi_lock); + mutex_exit(&mi_parent->mi_lock); +} + +/* + * Commit the changes to the ephemeral tree for removing this node. + */ +static void +nfs4_ephemeral_umount_cleanup(nfs4_ephemeral_t *eph) +{ + nfs4_ephemeral_t *e = eph; + nfs4_ephemeral_t *peer; + nfs4_ephemeral_t *prior; + + peer = eph->ne_peer; + prior = e->ne_prior; + + /* + * If this branch root was not the + * tree root, then we need to fix back pointers. + */ + if (prior) { + if (prior->ne_child == e) { + prior->ne_child = peer; + } else { + prior->ne_peer = peer; + } + + if (peer) + peer->ne_prior = prior; + } else if (peer) { + peer->ne_mount->mi_ephemeral_tree->net_root = peer; + peer->ne_prior = NULL; + } else { + e->ne_mount->mi_ephemeral_tree->net_root = NULL; + } +} + +/* + * We want to avoid recursion at all costs. So we need to + * unroll the tree. We do this by a depth first traversal to + * leaf nodes. We blast away the leaf and work our way back + * up and down the tree. + */ +static int +nfs4_ephemeral_unmount_engine(nfs4_ephemeral_t *eph, + int isTreeRoot, int flag, cred_t *cr) +{ + nfs4_ephemeral_t *e = eph; + nfs4_ephemeral_t *prior; + mntinfo4_t *mi; + vfs_t *vfsp; + int error; + + /* + * We use the loop while unrolling the ephemeral tree. + */ + for (;;) { + /* + * First we walk down the child. + */ + if (e->ne_child) { + prior = e; + e = e->ne_child; + continue; + } + + /* + * If we are the root of the branch we are removing, + * we end it here. But if the branch is the root of + * the tree, we have to forge on. We do not consider + * the peer list for the root because while it may + * be okay to remove, it is both extra work and a + * potential for a false-positive error to stall the + * unmount attempt. + */ + if (e == eph && isTreeRoot == FALSE) + return (0); + + /* + * Next we walk down the peer list. + */ + if (e->ne_peer) { + prior = e; + e = e->ne_peer; + continue; + } + + /* + * We can only remove the node passed in by the + * caller if it is the root of the ephemeral tree. + * Otherwise, the caller will remove it. + */ + if (e == eph && isTreeRoot == FALSE) + return (0); + + /* + * Okay, we have a leaf node, time + * to prune it! + * + * Note that prior can only be NULL if + * and only if it is the root of the + * ephemeral tree. + */ + prior = e->ne_prior; + + mi = e->ne_mount; + mutex_enter(&mi->mi_lock); + vfsp = mi->mi_vfsp; + + /* + * Cleared by umount2_engine. + */ + VFS_HOLD(vfsp); + + /* + * Inform nfs4_unmount to not recursively + * descend into this node's children when it + * gets processed. + */ + mi->mi_flags |= MI4_EPHEMERAL_RECURSED; + mutex_exit(&mi->mi_lock); + + error = umount2_engine(vfsp, flag, cr, FALSE); + if (error) { + /* + * We need to reenable nfs4_unmount's ability + * to recursively descend on this node. + */ + mutex_enter(&mi->mi_lock); + mi->mi_flags &= ~MI4_EPHEMERAL_RECURSED; + mutex_exit(&mi->mi_lock); + + return (error); + } + + /* + * If we are the current node, we do not want to + * touch anything else. At this point, the only + * way the current node can have survived to here + * is if it is the root of the ephemeral tree and + * we are unmounting the enclosing mntinfo4. + */ + if (e == eph) { + ASSERT(prior == NULL); + return (0); + } + + /* + * Stitch up the prior node. Note that since + * we have handled the root of the tree, prior + * must be non-NULL. + */ + ASSERT(prior != NULL); + if (prior->ne_child == e) { + prior->ne_child = NULL; + } else { + ASSERT(prior->ne_peer == e); + + prior->ne_peer = NULL; + } + + e = prior; + } + + /* NOTREACHED */ +} + +/* + * Common code to safely release net_cnt_lock and net_tree_lock + */ +void +nfs4_ephemeral_umount_unlock(bool_t *pmust_unlock, + nfs4_ephemeral_tree_t **pnet) +{ + nfs4_ephemeral_tree_t *net = *pnet; + + if (*pmust_unlock) { + mutex_enter(&net->net_cnt_lock); + net->net_refcnt--; + net->net_status &= ~NFS4_EPHEMERAL_TREE_UMOUNTING; + mutex_exit(&net->net_cnt_lock); + + mutex_exit(&net->net_tree_lock); + + *pmust_unlock = FALSE; + } +} + +/* + * While we may have removed any child or sibling nodes of this + * ephemeral node, we can not nuke it until we know that there + * were no actived vnodes on it. This will do that final + * work once we know it is not busy. + */ +void +nfs4_ephemeral_umount_activate(mntinfo4_t *mi, bool_t *pmust_unlock, + nfs4_ephemeral_tree_t **pnet) +{ + /* + * Now we need to get rid of the ephemeral data if it exists. + */ + mutex_enter(&mi->mi_lock); + if (mi->mi_ephemeral) { + /* + * If we are the root node of an ephemeral branch + * which is being removed, then we need to fixup + * pointers into and out of the node. + */ + if (!(mi->mi_flags & MI4_EPHEMERAL_RECURSED)) + nfs4_ephemeral_umount_cleanup(mi->mi_ephemeral); + + ASSERT(mi->mi_ephemeral != NULL); + + kmem_free(mi->mi_ephemeral, sizeof (*mi->mi_ephemeral)); + mi->mi_ephemeral = NULL; + } + mutex_exit(&mi->mi_lock); + + nfs4_ephemeral_umount_unlock(pmust_unlock, pnet); +} + +/* + * Unmount an ephemeral node. + */ +int +nfs4_ephemeral_umount(mntinfo4_t *mi, int flag, cred_t *cr, + bool_t *pmust_unlock, nfs4_ephemeral_tree_t **pnet) +{ + int error = 0; + nfs4_ephemeral_t *eph; + nfs4_ephemeral_tree_t *net; + int is_derooting = FALSE; + int is_recursed = FALSE; + int was_locked = FALSE; + + /* + * The active vnodes on this file system may be ephemeral + * children. We need to check for and try to unmount them + * here. If any can not be unmounted, we are going + * to return EBUSY. + */ + mutex_enter(&mi->mi_lock); + + /* + * If an ephemeral tree, we need to check to see if + * the lock is already held. If it is, then we need + * to see if we are being called as a result of + * the recursive removal of some node of the tree or + * if we are another attempt to remove the tree. + * + * mi_flags & MI4_EPHEMERAL indicates an ephemeral + * node. mi_ephemeral being non-NULL also does this. + * + * mi_ephemeral_tree being non-NULL is sufficient + * to also indicate either it is an ephemeral node + * or the enclosing mntinfo4. + * + * Do we need MI4_EPHEMERAL? Yes, it is useful for + * when we delete the ephemeral node and need to + * differentiate from an ephemeral node and the + * enclosing root node. + */ + *pnet = net = mi->mi_ephemeral_tree; + eph = mi->mi_ephemeral; + if (net) { + is_recursed = mi->mi_flags & MI4_EPHEMERAL_RECURSED; + is_derooting = (eph == NULL); + mutex_exit(&mi->mi_lock); + + /* + * If this is not recursion, then we need to + * grab a ref count. + * + * But wait, we also do not want to do that + * if a harvester thread has already grabbed + * the lock. + */ + if (!is_recursed) { + mutex_enter(&net->net_cnt_lock); + if (net->net_status & + NFS4_EPHEMERAL_TREE_LOCKED) + was_locked = TRUE; + else + net->net_refcnt++; + mutex_exit(&net->net_cnt_lock); + } + + /* + * If we grab the lock, it means that no other + * operation is working on the tree. If we don't + * grab it, we need to decide if this is because + * we are a recursive call or a new operation. + * + * If we are a recursive call, we proceed without + * the lock. + * + * Else we have to wait until the lock becomes free. + */ + if (was_locked == FALSE && + !mutex_tryenter(&net->net_tree_lock)) { + if (!is_recursed) { + mutex_enter(&net->net_cnt_lock); + if (net->net_status & + (NFS4_EPHEMERAL_TREE_DEROOTING + | NFS4_EPHEMERAL_TREE_INVALID)) { + net->net_refcnt--; + mutex_exit(&net->net_cnt_lock); + goto is_busy; + } + mutex_exit(&net->net_cnt_lock); + + /* + * We can't hold any other locks whilst + * we wait on this to free up. + */ + mutex_enter(&net->net_tree_lock); + + /* + * Note that while mi->mi_ephemeral + * may change and thus we have to + * update eph, it is the case that + * we have tied down net and + * do not care if mi->mi_ephemeral_tree + * has changed. + */ + mutex_enter(&mi->mi_lock); + eph = mi->mi_ephemeral; + mutex_exit(&mi->mi_lock); + + /* + * Okay, we need to see if either the + * tree got nuked or the current node + * got nuked. Both of which will cause + * an error. + * + * Note that a subsequent retry of the + * umount shall work. + */ + mutex_enter(&net->net_cnt_lock); + if (net->net_status & + NFS4_EPHEMERAL_TREE_INVALID || + (!is_derooting && eph == NULL)) { + net->net_refcnt--; + mutex_exit(&net->net_cnt_lock); + mutex_exit(&net->net_tree_lock); + goto is_busy; + } + mutex_exit(&net->net_cnt_lock); + *pmust_unlock = TRUE; + } + } else if (was_locked == FALSE) { + /* + * If we grab it right away, everything must + * be great! + */ + *pmust_unlock = TRUE; + } + + /* + * Only once we have grabbed the lock can we mark what we + * are planning on doing to the ephemeral tree. + */ + if (*pmust_unlock) { + mutex_enter(&net->net_cnt_lock); + net->net_status |= NFS4_EPHEMERAL_TREE_UMOUNTING; + + /* + * Check to see if we are nuking the root. + */ + if (is_derooting) + net->net_status |= + NFS4_EPHEMERAL_TREE_DEROOTING; + mutex_exit(&net->net_cnt_lock); + } + + if (!is_derooting) { + /* + * Only work on children if the caller has not already + * done so. + */ + if (!is_recursed) { + ASSERT(eph != NULL); + + error = nfs4_ephemeral_unmount_engine(eph, + FALSE, flag, cr); + if (error) + goto is_busy; + } + } else { + eph = net->net_root; + + /* + * Only work if there is something there. + */ + if (eph) { + error = nfs4_ephemeral_unmount_engine(eph, TRUE, + flag, cr); + if (error) { + mutex_enter(&net->net_cnt_lock); + net->net_status &= + ~NFS4_EPHEMERAL_TREE_DEROOTING; + mutex_exit(&net->net_cnt_lock); + goto is_busy; + } + + /* + * Nothing else which goes wrong will + * invalidate the blowing away of the + * ephmeral tree. + */ + net->net_root = NULL; + } + + /* + * We have derooted and we have caused the tree to be + * invalid. + */ + mutex_enter(&net->net_cnt_lock); + net->net_status &= ~NFS4_EPHEMERAL_TREE_DEROOTING; + net->net_status |= NFS4_EPHEMERAL_TREE_INVALID; + net->net_refcnt--; + mutex_exit(&net->net_cnt_lock); + + /* + * At this point, the tree should no + * longer be associated with the + * mntinfo4. We need to pull it off + * there and let the harvester take + * care of it once the refcnt drops. + */ + mutex_enter(&mi->mi_lock); + mi->mi_ephemeral_tree = NULL; + mutex_exit(&mi->mi_lock); + } + } else { + mutex_exit(&mi->mi_lock); + } + + return (0); + +is_busy: + + nfs4_ephemeral_umount_unlock(pmust_unlock, pnet); + + return (error); +} + +/* + * Do the umount and record any error in the parent. + */ +static void +nfs4_ephemeral_record_umount(vfs_t *vfsp, int flag, + nfs4_ephemeral_t *e, nfs4_ephemeral_t *prior) +{ + int error; + + error = umount2_engine(vfsp, flag, kcred, FALSE); + if (error) { + if (prior) { + if (prior->ne_child == e) + prior->ne_state |= + NFS4_EPHEMERAL_CHILD_ERROR; + else + prior->ne_state |= + NFS4_EPHEMERAL_PEER_ERROR; + } + } +} + +/* + * For each tree in the forest (where the forest is in + * effect all of the ephemeral trees for this zone), + * scan to see if a node can be unmounted. Note that + * unlike nfs4_ephemeral_unmount_engine(), we do + * not process the current node before children or + * siblings. I.e., if a node can be unmounted, we + * do not recursively check to see if the nodes + * hanging off of it can also be unmounted. + * + * Instead, we delve down deep to try and remove the + * children first. Then, because we share code with + * nfs4_ephemeral_unmount_engine(), we will try + * them again. This could be a performance issue in + * the future. + * + * Also note that unlike nfs4_ephemeral_unmount_engine(), + * we do not halt on an error. We will not remove the + * current node, but we will keep on trying to remove + * the others. + * + * force indicates that we want the unmount to occur + * even if there is something blocking it. + * + * time_check indicates that we want to see if the + * mount has expired past mount_to or not. Typically + * we want to do this and only on a shutdown of the + * zone would we want to ignore the check. + */ +static void +nfs4_ephemeral_harvest_forest(nfs4_trigger_globals_t *ntg, + bool_t force, bool_t time_check) +{ + nfs4_ephemeral_tree_t *net; + nfs4_ephemeral_tree_t *prev = NULL; + nfs4_ephemeral_tree_t *next; + nfs4_ephemeral_t *e; + nfs4_ephemeral_t *prior; + time_t now = gethrestime_sec(); + + nfs4_ephemeral_tree_t *harvest = NULL; + + int flag; + + mntinfo4_t *mi; + vfs_t *vfsp; + + if (force) + flag = MS_FORCE; + else + flag = 0; + + mutex_enter(&ntg->ntg_forest_lock); + for (net = ntg->ntg_forest; net != NULL; net = next) { + next = net->net_next; + + mutex_enter(&net->net_cnt_lock); + net->net_refcnt++; + mutex_exit(&net->net_cnt_lock); + + mutex_enter(&net->net_tree_lock); + + /* + * Let the unmount code know that the + * tree is already locked! + */ + mutex_enter(&net->net_cnt_lock); + net->net_status |= NFS4_EPHEMERAL_TREE_LOCKED; + mutex_exit(&net->net_cnt_lock); + + /* + * If the intent is force all ephemeral nodes to + * be unmounted in this zone, we can short circuit a + * lot of tree traversal and simply zap the root node. + */ + if (force) { + if (net->net_root) { + mi = net->net_root->ne_mount; + vfsp = mi->mi_vfsp; + + /* + * Cleared by umount2_engine. + */ + VFS_HOLD(vfsp); + + (void) umount2_engine(vfsp, flag, + kcred, FALSE); + + goto check_done; + } + } + + e = net->net_root; + if (e) + e->ne_state = NFS4_EPHEMERAL_VISIT_CHILD; + + while (e) { + if (e->ne_state == NFS4_EPHEMERAL_VISIT_CHILD) { + e->ne_state = NFS4_EPHEMERAL_VISIT_SIBLING; + if (e->ne_child) { + e = e->ne_child; + e->ne_state = + NFS4_EPHEMERAL_VISIT_CHILD; + } + + continue; + } else if (e->ne_state == + NFS4_EPHEMERAL_VISIT_SIBLING) { + e->ne_state = NFS4_EPHEMERAL_PROCESS_ME; + if (e->ne_peer) { + e = e->ne_peer; + e->ne_state = + NFS4_EPHEMERAL_VISIT_CHILD; + } + + continue; + } else if (e->ne_state == + NFS4_EPHEMERAL_CHILD_ERROR) { + prior = e->ne_prior; + + /* + * If a child reported an error, do + * not bother trying to unmount. + * + * If your prior node is a parent, + * pass the error up such that they + * also do not try to unmount. + * + * However, if your prior is a sibling, + * let them try to unmount if they can. + */ + if (prior) { + if (prior->ne_child == e) + prior->ne_state |= + NFS4_EPHEMERAL_CHILD_ERROR; + else + prior->ne_state |= + NFS4_EPHEMERAL_PEER_ERROR; + } + + /* + * Clear the error and if needed, process peers. + * + * Once we mask out the error, we know whether + * or we have to process another node. + */ + e->ne_state &= ~NFS4_EPHEMERAL_CHILD_ERROR; + if (e->ne_state == NFS4_EPHEMERAL_PROCESS_ME) + e = prior; + + continue; + } else if (e->ne_state == + NFS4_EPHEMERAL_PEER_ERROR) { + prior = e->ne_prior; + + if (prior) { + if (prior->ne_child == e) + prior->ne_state = + NFS4_EPHEMERAL_CHILD_ERROR; + else + prior->ne_state = + NFS4_EPHEMERAL_PEER_ERROR; + } + + /* + * Clear the error from this node and do the + * correct processing. + */ + e->ne_state &= ~NFS4_EPHEMERAL_PEER_ERROR; + continue; + } + + prior = e->ne_prior; + e->ne_state = NFS4_EPHEMERAL_OK; + + /* + * It must be the case that we need to process + * this node. + */ + if (!time_check || + now - e->ne_ref_time > e->ne_mount_to) { + mi = e->ne_mount; + vfsp = mi->mi_vfsp; + + /* + * Cleared by umount2_engine. + */ + VFS_HOLD(vfsp); + + /* + * Note that we effectively work down to the + * leaf nodes first, try to unmount them, + * then work our way back up into the leaf + * nodes. + * + * Also note that we deal with a lot of + * complexity by sharing the work with + * the manual unmount code. + */ + nfs4_ephemeral_record_umount(vfsp, flag, + e, prior); + } + + e = prior; + } + +check_done: + + /* + * Are we done with this tree? + */ + mutex_enter(&net->net_cnt_lock); + if (net->net_refcnt == 1 && + net->net_status & NFS4_EPHEMERAL_TREE_INVALID) { + net->net_refcnt--; + net->net_status &= ~NFS4_EPHEMERAL_TREE_LOCKED; + mutex_exit(&net->net_cnt_lock); + mutex_exit(&net->net_tree_lock); + + if (prev) + prev->net_next = net->net_next; + else + ntg->ntg_forest = net->net_next; + + net->net_next = harvest; + harvest = net; + continue; + } + + net->net_refcnt--; + net->net_status &= ~NFS4_EPHEMERAL_TREE_LOCKED; + mutex_exit(&net->net_cnt_lock); + mutex_exit(&net->net_tree_lock); + + prev = net; + } + mutex_exit(&ntg->ntg_forest_lock); + + for (net = harvest; net != NULL; net = next) { + next = net->net_next; + + mutex_destroy(&net->net_tree_lock); + mutex_destroy(&net->net_cnt_lock); + kmem_free(net, sizeof (*net)); + } +} + +/* + * This is the thread which decides when the harvesting + * can proceed and when to kill it off for this zone. + */ +static void +nfs4_ephemeral_harvester(nfs4_trigger_globals_t *ntg) +{ + clock_t timeleft; + zone_t *zone = curproc->p_zone; + + for (;;) { + timeleft = zone_status_timedwait(zone, lbolt + + nfs4_trigger_thread_timer * hz, ZONE_IS_SHUTTING_DOWN); + + /* + * zone is exiting... + */ + if (timeleft != -1) { + ASSERT(zone_status_get(zone) >= ZONE_IS_SHUTTING_DOWN); + zthread_exit(); + /* NOTREACHED */ + } + + /* + * Only bother scanning if there is potential + * work to be done. + */ + if (ntg->ntg_forest == NULL) + continue; + + /* + * Now scan the list and get rid of everything which + * is old. + */ + nfs4_ephemeral_harvest_forest(ntg, FALSE, TRUE); + } + + /* NOTREACHED */ +} + +/* + * The zone specific glue needed to start the unmount harvester. + * + * Note that we want to avoid holding the mutex as long as possible, + * hence the multiple checks. + * + * The caller should avoid us getting down here in the first + * place. + */ +static void +nfs4_ephemeral_start_harvester(nfs4_trigger_globals_t *ntg) +{ + /* + * It got started before we got here... + */ + if (ntg->ntg_thread_started) + return; + + mutex_enter(&nfs4_ephemeral_thread_lock); + + if (ntg->ntg_thread_started) { + mutex_exit(&nfs4_ephemeral_thread_lock); + return; + } + + /* + * Start the unmounter harvester thread for this zone. + */ + (void) zthread_create(NULL, 0, nfs4_ephemeral_harvester, + ntg, 0, minclsyspri); + + ntg->ntg_thread_started = TRUE; + mutex_exit(&nfs4_ephemeral_thread_lock); +} + +/*ARGSUSED*/ +static void * +nfs4_ephemeral_zsd_create(zoneid_t zoneid) +{ + nfs4_trigger_globals_t *ntg; + + ntg = kmem_zalloc(sizeof (*ntg), KM_SLEEP); + ntg->ntg_thread_started = FALSE; + + /* + * This is the default.... + */ + ntg->ntg_mount_to = nfs4_trigger_thread_timer; + + mutex_init(&ntg->ntg_forest_lock, NULL, + MUTEX_DEFAULT, NULL); + + return (ntg); +} + +/* + * Try a nice gentle walk down the forest and convince + * all of the trees to gracefully give it up. + */ +/*ARGSUSED*/ +static void +nfs4_ephemeral_zsd_shutdown(zoneid_t zoneid, void *arg) +{ + nfs4_trigger_globals_t *ntg = arg; + + if (!ntg) + return; + + nfs4_ephemeral_harvest_forest(ntg, FALSE, FALSE); +} + +/* + * Race along the forest and rip all of the trees out by + * their rootballs! + */ +/*ARGSUSED*/ +static void +nfs4_ephemeral_zsd_destroy(zoneid_t zoneid, void *arg) +{ + nfs4_trigger_globals_t *ntg = arg; + + if (!ntg) + return; + + nfs4_ephemeral_harvest_forest(ntg, TRUE, FALSE); + + mutex_destroy(&ntg->ntg_forest_lock); + kmem_free(ntg, sizeof (*ntg)); +} + +/* + * This is the zone independent cleanup needed for + * emphemeral mount processing. + */ +void +nfs4_ephemeral_fini(void) +{ + (void) zone_key_delete(nfs4_ephemeral_key); + mutex_destroy(&nfs4_ephemeral_thread_lock); +} + +/* + * This is the zone independent initialization needed for + * emphemeral mount processing. + */ +void +nfs4_ephemeral_init(void) +{ + mutex_init(&nfs4_ephemeral_thread_lock, NULL, MUTEX_DEFAULT, + NULL); + + zone_key_create(&nfs4_ephemeral_key, nfs4_ephemeral_zsd_create, + nfs4_ephemeral_zsd_shutdown, nfs4_ephemeral_zsd_destroy); +} + +/* + * nfssys() calls this function to set the per-zone + * value of mount_to to drive when an ephemeral mount is + * timed out. Each mount will grab a copy of this value + * when mounted. + */ +void +nfs4_ephemeral_set_mount_to(uint_t mount_to) +{ + nfs4_trigger_globals_t *ntg; + zone_t *zone = curproc->p_zone; + + ntg = zone_getspecific(nfs4_ephemeral_key, zone); + + ntg->ntg_mount_to = mount_to; +} + +/* + * Walk the list of v4 mount options; if they are currently set in vfsp, + * append them to a new comma-separated mount option string, and return it. + * + * Caller should free by calling nfs4_trigger_destroy_mntopts(). + */ +static char * +nfs4_trigger_create_mntopts(vfs_t *vfsp) +{ + uint_t i; + char *mntopts; + struct vfssw *vswp; + mntopts_t *optproto; + + mntopts = kmem_zalloc(MAX_MNTOPT_STR, KM_SLEEP); + + /* get the list of applicable mount options for v4; locks *vswp */ + vswp = vfs_getvfssw(MNTTYPE_NFS4); + optproto = &vswp->vsw_optproto; + + for (i = 0; i < optproto->mo_count; i++) { + struct mntopt *mop = &optproto->mo_list[i]; + + if (mop->mo_flags & MO_EMPTY) + continue; + + if (nfs4_trigger_add_mntopt(mntopts, mop->mo_name, vfsp)) { + kmem_free(mntopts, MAX_MNTOPT_STR); + vfs_unrefvfssw(vswp); + return (NULL); + } + } + + vfs_unrefvfssw(vswp); + + /* + * MNTOPT_XATTR is not in the v4 mount opt proto list, + * and it may only be passed via MS_OPTIONSTR, so we + * must handle it here. + * + * Ideally, it would be in the list, but NFS does not specify its + * own opt proto list, it uses instead the default one. Since + * not all filesystems support extended attrs, it would not be + * appropriate to add it there. + */ + if (nfs4_trigger_add_mntopt(mntopts, MNTOPT_XATTR, vfsp) || + nfs4_trigger_add_mntopt(mntopts, MNTOPT_NOXATTR, vfsp)) { + kmem_free(mntopts, MAX_MNTOPT_STR); + return (NULL); + } + + return (mntopts); +} + +static void +nfs4_trigger_destroy_mntopts(char *mntopts) +{ + if (mntopts) + kmem_free(mntopts, MAX_MNTOPT_STR); +} + +/* + * Check a single mount option (optname). Add to mntopts if it is set in VFS. + */ +static int +nfs4_trigger_add_mntopt(char *mntopts, char *optname, vfs_t *vfsp) +{ + if (mntopts == NULL || optname == NULL || vfsp == NULL) + return (EINVAL); + + if (vfs_optionisset(vfsp, optname, NULL)) { + size_t mntoptslen = strlen(mntopts); + size_t optnamelen = strlen(optname); + + /* +1 for ',', +1 for NUL */ + if (mntoptslen + optnamelen + 2 > MAX_MNTOPT_STR) + return (EOVERFLOW); + + /* first or subsequent mount option? */ + if (*mntopts != '\0') + (void) strcat(mntopts, ","); + + (void) strcat(mntopts, optname); + } + + return (0); +} + +static enum clnt_stat +nfs4_trigger_ping_server(servinfo4_t *svp, int nointr) +{ + int retries, error; + uint_t max_msgsize; + enum clnt_stat status; + CLIENT *cl; + struct timeval timeout; + + /* as per recov_newserver() */ + max_msgsize = 0; + retries = 1; + timeout.tv_sec = 2; + timeout.tv_usec = 0; + + error = clnt_tli_kcreate(svp->sv_knconf, &svp->sv_addr, NFS_PROGRAM, + NFS_V4, max_msgsize, retries, CRED(), &cl); + if (error) + return (RPC_FAILED); + + if (nointr) + cl->cl_nosignal = TRUE; + status = CLNT_CALL(cl, RFS_NULL, xdr_void, NULL, xdr_void, NULL, + timeout); + if (nointr) + cl->cl_nosignal = FALSE; + + AUTH_DESTROY(cl->cl_auth); + CLNT_DESTROY(cl); + + return (status); +} diff --git a/usr/src/uts/common/fs/nfs/nfs4_subr.c b/usr/src/uts/common/fs/nfs/nfs4_subr.c index 2a6505ccf9..16ce81e270 100644 --- a/usr/src/uts/common/fs/nfs/nfs4_subr.c +++ b/usr/src/uts/common/fs/nfs/nfs4_subr.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -433,7 +433,7 @@ nfs4_log_badowner(mntinfo4_t *mi, nfs_opnum4 op) * Happens once per client <-> server pair. */ if (nfs_rw_enter_sig(&mi->mi_recovlock, RW_READER, - mi->mi_flags & MI4_INT)) + mi->mi_flags & MI4_INT)) return; server = find_nfs4_server(mi); @@ -470,8 +470,6 @@ nfs4_log_badowner(mntinfo4_t *mi, nfs_opnum4 op) mutex_exit(&mi->mi_lock); } - - int nfs4_time_ntov(nfstime4 *ntime, timestruc_t *vatime) { @@ -546,7 +544,7 @@ utf8_to_fn(utf8string *u8s, uint_t *lenp, char *s) ASSERT(lenp != NULL); if (u8s == NULL || u8s->utf8string_len <= 0 || - u8s->utf8string_val == NULL) + u8s->utf8string_val == NULL) return (NULL); /* @@ -659,9 +657,9 @@ utf8_copy(utf8string *src, utf8string *dest) if (src->utf8string_len > 0) { dest->utf8string_val = kmem_alloc(src->utf8string_len, - KM_SLEEP); + KM_SLEEP); bcopy(src->utf8string_val, dest->utf8string_val, - src->utf8string_len); + src->utf8string_len); dest->utf8string_len = src->utf8string_len; } else { dest->utf8string_val = NULL; @@ -778,10 +776,10 @@ authget(servinfo4_t *svp, CLIENT *ch_client, cred_t *cr) (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0); if ((svp->sv_flags & SV4_TRYSECINFO) && svp->sv_secinfo) { for (i = svp->sv_secinfo->index; i < svp->sv_secinfo->count; - i++) { + i++) { if (!(error = sec_clnt_geth(ch_client, - &svp->sv_secinfo->sdata[i], - cr, &ch_client->cl_auth))) { + &svp->sv_secinfo->sdata[i], + cr, &ch_client->cl_auth))) { svp->sv_currsec = &svp->sv_secinfo->sdata[i]; svp->sv_secinfo->index = i; @@ -804,11 +802,11 @@ authget(servinfo4_t *svp, CLIENT *ch_client, cred_t *cr) /* sv_currsec points to one of the entries in sv_secinfo */ if (svp->sv_currsec) { error = sec_clnt_geth(ch_client, svp->sv_currsec, cr, - &ch_client->cl_auth); + &ch_client->cl_auth); } else { /* If it's null, use sv_secdata. */ error = sec_clnt_geth(ch_client, svp->sv_secdata, cr, - &ch_client->cl_auth); + &ch_client->cl_auth); } } nfs_rw_exit(&svp->sv_lock); @@ -854,7 +852,7 @@ top: ch->ch_vers == ci->cl_vers && ch->ch_dev == svp->sv_knconf->knc_rdev && (strcmp(ch->ch_protofmly, - svp->sv_knconf->knc_protofmly) == 0)) + svp->sv_knconf->knc_protofmly) == 0)) break; plistp = &ch->ch_next; } @@ -1126,7 +1124,7 @@ clreclaim4_zone(struct nfs4_clnt *nfscl, uint_t cl_holdtime) cpl = ch->ch_list; cpp = &ch->ch_list; while (cpl != NULL && - cpl->ch_freed + cl_holdtime > gethrestime_sec()) { + cpl->ch_freed + cl_holdtime > gethrestime_sec()) { cpp = &cpl->ch_list; cpl = cpl->ch_list; } @@ -1279,9 +1277,9 @@ nfs4_rfscall(mntinfo4_t *mi, rpcproc_t which, xdrproc_t xdrargs, caddr_t argsp, tryagain = FALSE; NFS4_DEBUG(nfs4_rfscall_debug, (CE_NOTE, - "nfs4_rfscall: vfs_flag=0x%x, %s", - mi->mi_vfsp->vfs_flag, - is_recov ? "recov thread" : "not recov thread")); + "nfs4_rfscall: vfs_flag=0x%x, %s", + mi->mi_vfsp->vfs_flag, + is_recov ? "recov thread" : "not recov thread")); /* * It's possible while we're retrying the admin @@ -1461,7 +1459,7 @@ nfs4_rfscall(mntinfo4_t *mi, rpcproc_t which, xdrproc_t xdrargs, caddr_t argsp, } while (tryagain); DTRACE_PROBE2(nfs4__rfscall_debug, enum clnt_stat, status, - int, rpcerr.re_errno); + int, rpcerr.re_errno); if (status != RPC_SUCCESS) { zoneid_t zoneid = mi->mi_zone->zone_id; @@ -1563,7 +1561,7 @@ nfs4_rfscall(mntinfo4_t *mi, rpcproc_t which, xdrproc_t xdrargs, caddr_t argsp, */ void rfs4call(mntinfo4_t *mi, COMPOUND4args_clnt *argsp, COMPOUND4res_clnt *resp, - cred_t *cr, int *doqueue, int flags, nfs4_error_t *ep) + cred_t *cr, int *doqueue, int flags, nfs4_error_t *ep) { int i, error; enum clnt_stat rpc_status = NFS4_OK; @@ -1584,9 +1582,9 @@ rfs4call(mntinfo4_t *mi, COMPOUND4args_clnt *argsp, COMPOUND4res_clnt *resp, resp->decode_len = 0; error = nfs4_rfscall(mi, NFSPROC4_COMPOUND, - xdr_COMPOUND4args_clnt, (caddr_t)argsp, - xdr_COMPOUND4res_clnt, (caddr_t)resp, cr, - doqueue, &rpc_status, flags, nfscl); + xdr_COMPOUND4args_clnt, (caddr_t)argsp, + xdr_COMPOUND4res_clnt, (caddr_t)resp, cr, + doqueue, &rpc_status, flags, nfscl); /* Return now if it was an RPC error */ if (error) { @@ -1639,10 +1637,10 @@ nfs4rename_update(vnode_t *renvp, vnode_t *ndvp, nfs_fh4 *nfh4p, char *nnm) static void remap_lookup(nfs4_fname_t *fname, vnode_t *rootvp, - int filetype, cred_t *cr, - nfs_fh4 *fhp, nfs4_ga_res_t *garp, /* fh, attrs for object */ - nfs_fh4 *pfhp, nfs4_ga_res_t *pgarp, /* fh, attrs for parent */ - nfs4_error_t *ep) + int filetype, cred_t *cr, + nfs_fh4 *fhp, nfs4_ga_res_t *garp, /* fh, attrs for object */ + nfs_fh4 *pfhp, nfs4_ga_res_t *pgarp, /* fh, attrs for parent */ + nfs4_error_t *ep) { COMPOUND4args_clnt args; COMPOUND4res_clnt res; @@ -1773,6 +1771,7 @@ exit: void nfs4_remap_file(mntinfo4_t *mi, vnode_t *vp, int flags, nfs4_error_t *ep) { + int is_stub; rnode4_t *rp = VTOR4(vp); vnode_t *rootvp = NULL; vnode_t *dvp = NULL; @@ -1811,7 +1810,7 @@ get_remap_cred: * Puts a hold on the cred_otw and the new osp (if found). */ cred_otw = nfs4_get_otw_cred_by_osp(rp, cr, &osp, - &first_time, &last_time); + &first_time, &last_time); ASSERT(cred_otw != NULL); if (rp->r_flags & R4ISXATTR) { @@ -1830,7 +1829,7 @@ get_remap_cred: again: remap_lookup(rp->r_svnode.sv_name, rootvp, filetype, cred_otw, - &newfh, &gar, &newpfh, &pgar, ep); + &newfh, &gar, &newpfh, &pgar, ep); NFS4_DEBUG(nfs4_client_failover_debug, (CE_NOTE, "nfs4_remap_file: remap_lookup returned %d/%d", @@ -1909,8 +1908,8 @@ again: mutex_enter(&rp->r_statelock); if (flags & NFS4_REMAP_CKATTRS) { if (vp->v_type != gar.n4g_va.va_type || - (vp->v_type != VDIR && - rp->r_size != gar.n4g_va.va_size)) { + (vp->v_type != VDIR && + rp->r_size != gar.n4g_va.va_size)) { NFS4_DEBUG(nfs4_client_failover_debug, (CE_NOTE, "nfs4_remap_file: size %d vs. %d, type %d vs. %d", (int)rp->r_size, (int)gar.n4g_va.va_size, @@ -1926,21 +1925,32 @@ again: ASSERT(gar.n4g_va.va_type != VNON); rp->r_server = mi->mi_curr_serv; + /* + * Turn this object into a "stub" object if we + * crossed an underlying server fs boundary. + * + * This stub will be for a mirror-mount. + * + * See comment in r4_do_attrcache() for more details. + */ + is_stub = 0; if (gar.n4g_fsid_valid) { (void) nfs_rw_enter_sig(&rp->r_server->sv_lock, RW_READER, 0); rp->r_srv_fsid = gar.n4g_fsid; - if (FATTR4_FSID_EQ(&gar.n4g_fsid, &rp->r_server->sv_fsid)) - rp->r_flags &= ~R4SRVSTUB; - else - rp->r_flags |= R4SRVSTUB; + if (!FATTR4_FSID_EQ(&gar.n4g_fsid, &rp->r_server->sv_fsid)) + is_stub = 1; nfs_rw_exit(&rp->r_server->sv_lock); #ifdef DEBUG } else { NFS4_DEBUG(nfs4_client_failover_debug, (CE_NOTE, - "remap_file: fsid attr not provided by server. rp=%p", - (void *)rp)); + "remap_file: fsid attr not provided by server. rp=%p", + (void *)rp)); #endif } + if (is_stub) + r4_stub_mirrormount(rp); + else + r4_stub_none(rp); mutex_exit(&rp->r_statelock); nfs4_attrcache_noinval(vp, &gar, gethrtime()); /* force update */ sfh4_update(rp->r_fh, &newfh); @@ -2232,7 +2242,7 @@ sv4_free(servinfo4_t *svp) if (svp->sv_secdata) sec_clnt_freeinfo(svp->sv_secdata); if (svp->sv_save_secinfo && - svp->sv_save_secinfo != svp->sv_secinfo) + svp->sv_save_secinfo != svp->sv_secinfo) secinfo_free(svp->sv_save_secinfo); if (svp->sv_secinfo) secinfo_free(svp->sv_secinfo); @@ -2348,7 +2358,7 @@ rddir4_cache_create(rnode4_t *rp) rp->r_dir = kmem_alloc(sizeof (avl_tree_t), KM_SLEEP); avl_create(rp->r_dir, rddir4_cache_compar, sizeof (rddir4_cache_impl), - offsetof(rddir4_cache_impl, tree)); + offsetof(rddir4_cache_impl, tree)); } /* @@ -2544,14 +2554,14 @@ top: rddir4_cache_rele(rp, rdc); mutex_exit(&rp->r_statelock); (void) nfs_rw_enter_sig(&rp->r_rwlock, - RW_READER, FALSE); + RW_READER, FALSE); mutex_enter(&rp->r_statelock); return (NULL); } } mutex_exit(&rp->r_statelock); (void) nfs_rw_enter_sig(&rp->r_rwlock, - RW_READER, FALSE); + RW_READER, FALSE); mutex_enter(&rp->r_statelock); } @@ -2684,8 +2694,8 @@ cl4_snapshot(kstat_t *ksp, void *buf, int rw) * add the check just for paranoia. */ if (INGLOBALZONE(curproc)) - bcopy((char *)buf + sizeof (clstat4_tmpl), &clstat4_debug, - sizeof (clstat4_debug)); + bcopy((char *)buf + sizeof (clstat4_tmpl), + &clstat4_debug, sizeof (clstat4_debug)); #endif } else { bcopy(ksp->ks_private, buf, sizeof (clstat4_tmpl)); @@ -2792,8 +2802,8 @@ nfs4_subr_init(void) * Allocate and initialize the client handle cache */ chtab4_cache = kmem_cache_create("client_handle4_cache", - sizeof (struct chtab), 0, NULL, NULL, clreclaim4, NULL, - NULL, 0); + sizeof (struct chtab), 0, NULL, NULL, clreclaim4, NULL, + NULL, 0); /* * Initialize the list of per-zone client handles (and associated data). @@ -3015,7 +3025,7 @@ try_failover(enum clnt_stat rpc_status) err = ETIMEDOUT; #ifdef DEBUG cmn_err(CE_NOTE, "try_failover: unexpected rpc error %d", - rpc_status); + rpc_status); #endif } else err = try_failover_table[rpc_status].error; @@ -3023,8 +3033,8 @@ try_failover(enum clnt_stat rpc_status) done: if (rpc_status) NFS4_DEBUG(nfs4_client_failover_debug, (CE_NOTE, - "nfs4_try_failover: %strying failover on error %d", - err ? "" : "NOT ", rpc_status)); + "nfs4_try_failover: %strying failover on error %d", + err ? "" : "NOT ", rpc_status)); return (err); } diff --git a/usr/src/uts/common/fs/nfs/nfs4_vfsops.c b/usr/src/uts/common/fs/nfs/nfs4_vfsops.c index 4f6719117f..88281d7b67 100644 --- a/usr/src/uts/common/fs/nfs/nfs4_vfsops.c +++ b/usr/src/uts/common/fs/nfs/nfs4_vfsops.c @@ -84,12 +84,13 @@ */ typedef struct { - vfs_t *fm_vfsp; - cred_t *fm_cr; + vfs_t *fm_vfsp; + int fm_flag; + cred_t *fm_cr; } freemountargs_t; -static void async_free_mount(vfs_t *, cred_t *); -static void nfs4_free_mount(vfs_t *, cred_t *); +static void async_free_mount(vfs_t *, int, cred_t *); +static void nfs4_free_mount(vfs_t *, int, cred_t *); static void nfs4_free_mount_thread(freemountargs_t *); static int nfs4_chkdup_servinfo4(servinfo4_t *, servinfo4_t *); @@ -135,7 +136,7 @@ static int nfs4_max_mount_retry = 2; /* * nfs4 vfs operations. */ -static int nfs4_mount(vfs_t *, vnode_t *, struct mounta *, cred_t *); +int nfs4_mount(vfs_t *, vnode_t *, struct mounta *, cred_t *); static int nfs4_unmount(vfs_t *, int, cred_t *); static int nfs4_root(vfs_t *, vnode_t **); static int nfs4_statvfs(vfs_t *, struct statvfs64 *); @@ -158,6 +159,9 @@ static void nfs4setclientid_otw(mntinfo4_t *, servinfo4_t *, cred_t *, static void destroy_nfs4_server(nfs4_server_t *); static void remove_mi(nfs4_server_t *, mntinfo4_t *); +extern void nfs4_ephemeral_init(void); +extern void nfs4_ephemeral_fini(void); + /* * Initialize the vfs structure */ @@ -188,28 +192,48 @@ nfs4init(int fstyp, char *name) }; int error; + nfs4_vfsops = NULL; + nfs4_vnodeops = NULL; + nfs4_trigger_vnodeops = NULL; + error = vfs_setfsops(fstyp, nfs4_vfsops_template, &nfs4_vfsops); if (error != 0) { zcmn_err(GLOBAL_ZONEID, CE_WARN, "nfs4init: bad vfs ops template"); - return (error); + goto out; } error = vn_make_ops(name, nfs4_vnodeops_template, &nfs4_vnodeops); if (error != 0) { - (void) vfs_freevfsops_by_type(fstyp); zcmn_err(GLOBAL_ZONEID, CE_WARN, "nfs4init: bad vnode ops template"); - return (error); + goto out; } - nfs4fstyp = fstyp; + error = vn_make_ops("nfs4_trigger", nfs4_trigger_vnodeops_template, + &nfs4_trigger_vnodeops); + if (error != 0) { + zcmn_err(GLOBAL_ZONEID, CE_WARN, + "nfs4init: bad trigger vnode ops template"); + goto out; + } + nfs4fstyp = fstyp; (void) nfs4_vfsinit(); - (void) nfs4_init_dot_entries(); - return (0); +out: + if (error) { + if (nfs4_trigger_vnodeops != NULL) + vn_freevnodeops(nfs4_trigger_vnodeops); + + if (nfs4_vnodeops != NULL) + vn_freevnodeops(nfs4_vnodeops); + + (void) vfs_freevfsops_by_type(fstyp); + } + + return (error); } void @@ -227,7 +251,7 @@ nfs4fini(void) * * sec_data can be freed by sec_clnt_freeinfo(). */ -struct sec_data * +static struct sec_data * create_authdh_data(char *netname, int nlen, struct netbuf *syncaddr, struct knetconfig *knconf) { struct sec_data *secdata; @@ -272,6 +296,74 @@ create_authdh_data(char *netname, int nlen, struct netbuf *syncaddr, return (secdata); } +/* + * Returns (deep) copy of sec_data_t. Allocates all memory required; caller + * is responsible for freeing. + */ +sec_data_t * +copy_sec_data(sec_data_t *fsecdata) { + sec_data_t *tsecdata; + + if (fsecdata == NULL) + return (NULL); + + if (fsecdata->rpcflavor == AUTH_DH) { + dh_k4_clntdata_t *fdata = (dh_k4_clntdata_t *)fsecdata->data; + + if (fdata == NULL) + return (NULL); + + tsecdata = (sec_data_t *)create_authdh_data(fdata->netname, + fdata->netnamelen, &fdata->syncaddr, fdata->knconf); + + return (tsecdata); + } + + tsecdata = kmem_zalloc(sizeof (sec_data_t), KM_SLEEP); + + tsecdata->secmod = fsecdata->secmod; + tsecdata->rpcflavor = fsecdata->rpcflavor; + tsecdata->flags = fsecdata->flags; + tsecdata->uid = fsecdata->uid; + + if (fsecdata->rpcflavor == RPCSEC_GSS) { + gss_clntdata_t *gcd = (gss_clntdata_t *)fsecdata->data; + + tsecdata->data = (caddr_t)copy_sec_data_gss(gcd); + } else { + tsecdata->data = NULL; + } + + return (tsecdata); +} + +gss_clntdata_t * +copy_sec_data_gss(gss_clntdata_t *fdata) +{ + gss_clntdata_t *tdata; + + if (fdata == NULL) + return (NULL); + + tdata = kmem_zalloc(sizeof (gss_clntdata_t), KM_SLEEP); + + tdata->mechanism.length = fdata->mechanism.length; + tdata->mechanism.elements = kmem_zalloc(fdata->mechanism.length, + KM_SLEEP); + bcopy(fdata->mechanism.elements, tdata->mechanism.elements, + fdata->mechanism.length); + + tdata->service = fdata->service; + + (void) strcpy(tdata->uname, fdata->uname); + (void) strcpy(tdata->inst, fdata->inst); + (void) strcpy(tdata->realm, fdata->realm); + + tdata->qop = fdata->qop; + + return (tdata); +} + static int nfs4_chkdup_servinfo4(servinfo4_t *svp_head, servinfo4_t *svp) { @@ -293,9 +385,9 @@ nfs4_chkdup_servinfo4(servinfo4_t *svp_head, servinfo4_t *svp) continue; if (si->sv_addr.len == svp->sv_addr.len && strcmp(si->sv_knconf->knc_protofmly, - svp->sv_knconf->knc_protofmly) == 0 && + svp->sv_knconf->knc_protofmly) == 0 && bcmp(si->sv_addr.buf, svp->sv_addr.buf, - si->sv_addr.len) == 0) { + si->sv_addr.len) == 0) { /* it's a duplicate */ return (1); } @@ -310,7 +402,7 @@ nfs4_free_args(struct nfs_args *nargs) if (nargs->knconf) { if (nargs->knconf->knc_protofmly) kmem_free(nargs->knconf->knc_protofmly, - KNC_STRSIZE); + KNC_STRSIZE); if (nargs->knconf->knc_proto) kmem_free(nargs->knconf->knc_proto, KNC_STRSIZE); kmem_free(nargs->knconf, sizeof (*nargs->knconf)); @@ -353,7 +445,7 @@ nfs4_free_args(struct nfs_args *nargs) if (nargs->nfs_ext_u.nfs_extA.secdata) { sec_clnt_freeinfo( - nargs->nfs_ext_u.nfs_extA.secdata); + nargs->nfs_ext_u.nfs_extA.secdata); nargs->nfs_ext_u.nfs_extA.secdata = NULL; } } @@ -490,7 +582,7 @@ nfs4_copyin(char *data, int datalen, struct nfs_args *nargs) */ if (flags & NFSMNT_HOSTNAME) { error = copyinstr(STRUCT_FGETP(args, hostname), - netname, sizeof (netname), &hlen); + netname, sizeof (netname), &hlen); if (error) goto errout; nargs->hostname = kmem_zalloc(hlen, KM_SLEEP); @@ -512,7 +604,7 @@ nfs4_copyin(char *data, int datalen, struct nfs_args *nargs) /* get syncaddr */ STRUCT_INIT(addr_tmp, get_udatamodel()); if (copyin(STRUCT_FGETP(args, syncaddr), STRUCT_BUF(addr_tmp), - STRUCT_SIZE(addr_tmp))) { + STRUCT_SIZE(addr_tmp))) { error = EINVAL; goto errout; } @@ -531,7 +623,7 @@ nfs4_copyin(char *data, int datalen, struct nfs_args *nargs) /* get server's netname */ if (copyinstr(STRUCT_FGETP(args, netname), netname, - sizeof (netname), &nlen)) { + sizeof (netname), &nlen)) { error = EFAULT; goto errout; } @@ -548,7 +640,7 @@ nfs4_copyin(char *data, int datalen, struct nfs_args *nargs) if (flags & NFSMNT_NEWARGS) { nargs->nfs_args_ext = STRUCT_FGET(args, nfs_args_ext); if (nargs->nfs_args_ext == NFS_ARGS_EXTA || - nargs->nfs_args_ext == NFS_ARGS_EXTB) { + nargs->nfs_args_ext == NFS_ARGS_EXTB) { /* * Indicating the application is using the new * sec_data structure to pass in the security @@ -558,7 +650,7 @@ nfs4_copyin(char *data, int datalen, struct nfs_args *nargs) nfs_ext_u.nfs_extA.secdata) != NULL) { error = sec_clnt_loadinfo( (struct sec_data *)STRUCT_FGETP(args, - nfs_ext_u.nfs_extA.secdata), + nfs_ext_u.nfs_extA.secdata), &secdata, get_udatamodel()); } nargs->nfs_ext_u.nfs_extA.secdata = secdata; @@ -578,7 +670,7 @@ nfs4_copyin(char *data, int datalen, struct nfs_args *nargs) */ if (nargs->nfs_args_ext == NFS_ARGS_EXTB) nargs->nfs_ext_u.nfs_extB.next = - STRUCT_FGETP(args, nfs_ext_u.nfs_extB.next); + STRUCT_FGETP(args, nfs_ext_u.nfs_extB.next); errout: if (error) @@ -592,7 +684,7 @@ errout: * nfs mount vfsop * Set up mount info record and attach it to vfs struct. */ -static int +int nfs4_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) { char *data = uap->dataptr; @@ -616,6 +708,7 @@ nfs4_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) return (EPERM); if (mvp->v_type != VDIR) return (ENOTDIR); + /* * get arguments * @@ -640,7 +733,6 @@ more: args = (struct nfs_args *)data; } - flags = args->flags; /* @@ -664,15 +756,38 @@ more: return (0); } + /* + * For ephemeral mount trigger stub vnodes, we have two problems + * to solve: racing threads will likely fail the v_count check, and + * we want only one to proceed with the mount. + * + * For stubs, if the mount has already occurred (via a racing thread), + * just return success. If not, skip the v_count check and proceed. + * Note that we are already serialised at this point. + */ mutex_enter(&mvp->v_lock); - if (!(uap->flags & MS_OVERLAY) && - (mvp->v_count != 1 || (mvp->v_flag & VROOT))) { - mutex_exit(&mvp->v_lock); - if (!(uap->flags & MS_SYSSPACE)) { - nfs4_free_args(args); - kmem_free(args, sizeof (*args)); + if (vn_matchops(mvp, nfs4_trigger_vnodeops)) { + /* mntpt is a v4 stub vnode */ + ASSERT(RP_ISSTUB(VTOR4(mvp))); + ASSERT(!(uap->flags & MS_OVERLAY)); + ASSERT(!(mvp->v_flag & VROOT)); + if (vn_mountedvfs(mvp) != NULL) { + /* ephemeral mount has already occurred */ + ASSERT(uap->flags & MS_SYSSPACE); + mutex_exit(&mvp->v_lock); + return (0); + } + } else { + /* mntpt is a non-v4 or v4 non-stub vnode */ + if (!(uap->flags & MS_OVERLAY) && + (mvp->v_count != 1 || (mvp->v_flag & VROOT))) { + mutex_exit(&mvp->v_lock); + if (!(uap->flags & MS_SYSSPACE)) { + nfs4_free_args(args); + kmem_free(args, sizeof (*args)); + } + return (EBUSY); } - return (EBUSY); } mutex_exit(&mvp->v_lock); @@ -684,11 +799,10 @@ more: /* * A valid knetconfig structure is required. */ - if (!(flags & NFSMNT_KNCONF) || - args->knconf == NULL || args->knconf->knc_protofmly == NULL || - args->knconf->knc_proto == NULL || - (strcmp(args->knconf->knc_proto, NC_UDP) == 0)) { + args->knconf == NULL || args->knconf->knc_protofmly == NULL || + args->knconf->knc_proto == NULL || + (strcmp(args->knconf->knc_proto, NC_UDP) == 0)) { if (!(uap->flags & MS_SYSSPACE)) { nfs4_free_args(args); kmem_free(args, sizeof (*args)); @@ -697,7 +811,7 @@ more: } if ((strlen(args->knconf->knc_protofmly) >= KNC_STRSIZE) || - (strlen(args->knconf->knc_proto) >= KNC_STRSIZE)) { + (strlen(args->knconf->knc_proto) >= KNC_STRSIZE)) { if (!(uap->flags & MS_SYSSPACE)) { nfs4_free_args(args); kmem_free(args, sizeof (*args)); @@ -705,7 +819,6 @@ more: return (EINVAL); } - /* * Allocate a servinfo4 struct. */ @@ -723,11 +836,9 @@ more: svp->sv_knconf = args->knconf; args->knconf = NULL; - /* * Get server address */ - if (args->addr == NULL || args->addr->buf == NULL) { error = EINVAL; goto errout; @@ -738,7 +849,6 @@ more: svp->sv_addr.buf = args->addr->buf; args->addr->buf = NULL; - /* * Get the root fhandle */ @@ -756,7 +866,7 @@ more: */ if (flags & NFSMNT_HOSTNAME) { if (args->hostname == NULL || (strlen(args->hostname) > - MAXNETNAMELEN)) { + MAXNETNAMELEN)) { error = EINVAL; goto errout; } @@ -785,7 +895,7 @@ more: addr_type = AF_INET6; if (rdma_reachable(addr_type, &svp->sv_addr, - &rdma_knconf) == 0) { + &rdma_knconf) == 0) { /* * If successful, hijack the orignal knconf and * replace with the new one, depending on the flags. @@ -811,12 +921,10 @@ more: * Check if more servers are specified; * Failover case, otherwise bail out of mount. */ - if (args->nfs_args_ext == - NFS_ARGS_EXTB && - args->nfs_ext_u.nfs_extB.next - != NULL) { + if (args->nfs_args_ext == NFS_ARGS_EXTB && + args->nfs_ext_u.nfs_extB.next != NULL) { data = (char *) - args->nfs_ext_u.nfs_extB.next; + args->nfs_ext_u.nfs_extB.next; if (uap->flags & MS_RDONLY && !(flags & NFSMNT_SOFT)) { if (svp_head->sv_next == NULL) { @@ -873,8 +981,8 @@ more: */ if (args->flags & NFSMNT_SECURE) { svp->sv_dhsec = create_authdh_data(args->netname, - strlen(args->netname), - args->syncaddr, svp->sv_knconf); + strlen(args->netname), + args->syncaddr, svp->sv_knconf); } /* @@ -922,12 +1030,15 @@ more: } else if (flags & NFSMNT_SECURE) { /* * NFSMNT_SECURE is deprecated but we keep it - * to support the rouge user generated application + * to support the rogue user-generated application * that may use this undocumented interface to do - * AUTH_DH security. + * AUTH_DH security, e.g. our own rexd. + * + * Also note that NFSMNT_SECURE is used for passing + * AUTH_DH info to be used in negotiation. */ secdata = create_authdh_data(args->netname, - strlen(args->netname), args->syncaddr, svp->sv_knconf); + strlen(args->netname), args->syncaddr, svp->sv_knconf); } else { secdata = kmem_alloc(sizeof (*secdata), KM_SLEEP); @@ -1005,7 +1116,6 @@ more: */ proceed: error = nfs4rootvp(&rtvp, vfsp, svp_head, flags, cr, mntzone); - if (error) { /* if nfs4rootvp failed, it will free svp_head */ svp_head = NULL; @@ -1019,6 +1129,7 @@ proceed: */ nfs4_error_zinit(&n4e); nfs4setclientid(mi, cr, FALSE, &n4e); + error = n4e.error; if (error) @@ -1034,6 +1145,14 @@ proceed: mutex_exit(&mi->mi_lock); } error = nfs4_setopts(rtvp, DATAMODEL_NATIVE, args); + if (error) + goto errout; + + /* + * Time to tie in the mirror mount info at last! + */ + if (flags & NFSMNT_EPHEMERAL) + nfs4_record_ephemeral_mount(mi, mvp); errout: if (error) { @@ -1099,8 +1218,7 @@ errout: */ static int getlinktext_otw(mntinfo4_t *mi, nfs_fh4 *fh, char **linktextp, cred_t *cr, - int flags) - + int flags) { COMPOUND4args_clnt args; COMPOUND4res_clnt res; @@ -1151,14 +1269,14 @@ recov_retry: if (needrecov && !recovery && num_retry-- > 0) { NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE, - "getlinktext_otw: initiating recovery\n")); + "getlinktext_otw: initiating recovery\n")); if (nfs4_start_recovery(&e, mi, NULL, NULL, NULL, NULL, - OP_READLINK, NULL) == FALSE) { - nfs4_end_op(mi, NULL, NULL, &recov_state, needrecov); - if (!e.error) - (void) xdr_free(xdr_COMPOUND4res_clnt, - (caddr_t)&res); + OP_READLINK, NULL) == FALSE) { + nfs4_end_op(mi, NULL, NULL, &recov_state, needrecov); + if (!e.error) + (void) xdr_free(xdr_COMPOUND4res_clnt, + (caddr_t)&res); goto recov_retry; } } @@ -1229,7 +1347,7 @@ pathname_skipslashdot(struct pathname *pnp) */ int resolve_sympath(mntinfo4_t *mi, servinfo4_t *svp, int nth, nfs_fh4 *fh, - cred_t *cr, int flags) + cred_t *cr, int flags) { char *oldpath; char *symlink, *newpath; @@ -1353,7 +1471,7 @@ out: static void nfs4getfh_otw(struct mntinfo4 *mi, servinfo4_t *svp, vtype_t *vtp, - int flags, cred_t *cr, nfs4_error_t *ep) + int flags, cred_t *cr, nfs4_error_t *ep) { COMPOUND4args_clnt args; COMPOUND4res_clnt res; @@ -1387,7 +1505,7 @@ recov_retry: if (!recovery) { ep->error = nfs4_start_fop(mi, NULL, NULL, OH_MOUNT, - &recov_state, NULL); + &recov_state, NULL); /* * If recovery has been started and this request as @@ -1472,10 +1590,10 @@ recov_retry: if (recovery) { nfs4args_lookup_free(argop, num_argops); kmem_free(argop, - lookuparg.arglen * sizeof (nfs_argop4)); + lookuparg.arglen * sizeof (nfs_argop4)); if (!ep->error) (void) xdr_free(xdr_COMPOUND4res_clnt, - (caddr_t)&res); + (caddr_t)&res); return; } @@ -1483,7 +1601,7 @@ recov_retry: (CE_NOTE, "nfs4getfh_otw: initiating recovery\n")); abort = nfs4_start_recovery(ep, mi, NULL, - NULL, NULL, NULL, OP_GETFH, NULL); + NULL, NULL, NULL, OP_GETFH, NULL); if (!ep->error) { ep->error = geterrno4(res.status); (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); @@ -1505,7 +1623,7 @@ recov_retry: kmem_free(argop, lookuparg.arglen * sizeof (nfs_argop4)); if (!recovery) nfs4_end_fop(mi, NULL, NULL, OH_MOUNT, &recov_state, - needrecov); + needrecov); return; } @@ -1515,7 +1633,7 @@ is_link_err: if (res.status && res.status != NFS4ERR_SYMLINK) { if (!recovery) { nfs4_end_fop(mi, NULL, NULL, OH_MOUNT, &recov_state, - needrecov); + needrecov); } nfs4args_lookup_free(argop, num_argops); kmem_free(argop, lookuparg.arglen * sizeof (nfs_argop4)); @@ -1556,10 +1674,10 @@ is_link_err: */ if (!recovery) nfs4_end_fop(mi, NULL, NULL, OH_MOUNT, &recov_state, - needrecov); + needrecov); ep->error = resolve_sympath(mi, svp, nthcomp, tmpfhp, cr, - flags); + flags); nfs4args_lookup_free(argop, num_argops); kmem_free(argop, lookuparg.arglen * sizeof (nfs_argop4)); @@ -1595,24 +1713,24 @@ is_link_err: if (garp->n4g_ext_res->n4g_maxread == 0) mi->mi_tsize = - MIN(MAXBSIZE, mi->mi_tsize); + MIN(MAXBSIZE, mi->mi_tsize); else mi->mi_tsize = - MIN(garp->n4g_ext_res->n4g_maxread, - mi->mi_tsize); + MIN(garp->n4g_ext_res->n4g_maxread, + mi->mi_tsize); if (garp->n4g_ext_res->n4g_maxwrite == 0) mi->mi_stsize = - MIN(MAXBSIZE, mi->mi_stsize); + MIN(MAXBSIZE, mi->mi_stsize); else mi->mi_stsize = - MIN(garp->n4g_ext_res->n4g_maxwrite, - mi->mi_stsize); + MIN(garp->n4g_ext_res->n4g_maxwrite, + mi->mi_stsize); if (garp->n4g_ext_res->n4g_maxfilesize != 0) mi->mi_maxfilesize = - MIN(garp->n4g_ext_res->n4g_maxfilesize, - mi->mi_maxfilesize); + MIN(garp->n4g_ext_res->n4g_maxfilesize, + mi->mi_maxfilesize); /* * If the final component is a a symbolic link, resolve the symlink, @@ -1639,10 +1757,10 @@ is_link_err: */ if (!recovery) nfs4_end_fop(mi, NULL, NULL, OH_MOUNT, &recov_state, - needrecov); + needrecov); ep->error = resolve_sympath(mi, svp, nthcomp, resfhp, cr, - flags); + flags); nfs4args_lookup_free(argop, num_argops); kmem_free(argop, lookuparg.arglen * sizeof (nfs_argop4)); @@ -1690,7 +1808,7 @@ is_link_err: /* initialize fsid and supp_attrs for server fs */ svp->sv_fsid = garp->n4g_fsid; svp->sv_supp_attrs = - garp->n4g_ext_res->n4g_suppattrs | FATTR4_MANDATTR_MASK; + garp->n4g_ext_res->n4g_suppattrs | FATTR4_MANDATTR_MASK; nfs_rw_exit(&svp->sv_lock); @@ -1726,9 +1844,9 @@ nfs4_remap_root(mntinfo4_t *mi, nfs4_error_t *ep, int flags) remap_retry: svp = mi->mi_curr_serv; getfh_flags = - (flags & NFS4_REMAP_NEEDSOP) ? NFS4_GETFH_NEEDSOP : 0; + (flags & NFS4_REMAP_NEEDSOP) ? NFS4_GETFH_NEEDSOP : 0; getfh_flags |= - (mi->mi_flags & MI4_PUBLIC) ? NFS4_GETFH_PUBLIC : 0; + (mi->mi_flags & MI4_PUBLIC) ? NFS4_GETFH_PUBLIC : 0; mutex_exit(&mi->mi_lock); /* @@ -1792,8 +1910,8 @@ remap_retry: if (vtype != VNON && vtype != mi->mi_type) { /* shouldn't happen */ zcmn_err(mi->mi_zone->zone_id, CE_WARN, - "nfs4_remap_root: server root vnode type (%d) doesn't " - "match mount info (%d)", vtype, mi->mi_type); + "nfs4_remap_root: server root vnode type (%d) doesn't " + "match mount info (%d)", vtype, mi->mi_type); } (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0); @@ -1817,7 +1935,7 @@ remap_retry: static int nfs4rootvp(vnode_t **rtvpp, vfs_t *vfsp, struct servinfo4 *svp_head, - int flags, cred_t *cr, zone_t *zone) + int flags, cred_t *cr, zone_t *zone) { vnode_t *rtvp = NULL; mntinfo4_t *mi; @@ -1862,6 +1980,8 @@ nfs4rootvp(vnode_t **rtvpp, vfs_t *vfsp, struct servinfo4 *svp_head, mi->mi_flags |= MI4_INT; if (flags & NFSMNT_PUBLIC) mi->mi_flags |= MI4_PUBLIC; + if (flags & NFSMNT_MIRRORMOUNT) + mi->mi_flags |= MI4_MIRRORMOUNT; mi->mi_retrans = NFS_RETRIES; if (svp->sv_knconf->knc_semantics == NC_TPI_COTS_ORD || svp->sv_knconf->knc_semantics == NC_TPI_COTS) @@ -2007,8 +2127,8 @@ nfs4rootvp(vnode_t **rtvpp, vfs_t *vfsp, struct servinfo4 *svp_head, for (svp = svp_head; svp; svp = svp->sv_next) { if (nfs4_chkdup_servinfo4(svp_head, svp)) { nfs_cmn_err(error, CE_WARN, - VERS_MSG "Host %s is a duplicate%s", - svp->sv_hostname, droptext); + VERS_MSG "Host %s is a duplicate%s", + svp->sv_hostname, droptext); (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0); svp->sv_flags |= SV4_NOTINUSE; nfs_rw_exit(&svp->sv_lock); @@ -2050,7 +2170,7 @@ nfs4rootvp(vnode_t **rtvpp, vfs_t *vfsp, struct servinfo4 *svp_head, if (orig_sv_pathlen != svp->sv_pathlen) { kmem_free(svp->sv_path, svp->sv_pathlen); svp->sv_path = kmem_alloc(orig_sv_pathlen, - KM_SLEEP); + KM_SLEEP); svp->sv_pathlen = orig_sv_pathlen; } bcopy(orig_sv_path, svp->sv_path, orig_sv_pathlen); @@ -2061,8 +2181,8 @@ nfs4rootvp(vnode_t **rtvpp, vfs_t *vfsp, struct servinfo4 *svp_head, error = e.error ? e.error : geterrno4(e.stat); if (error) { nfs_cmn_err(error, CE_WARN, - VERS_MSG "initial call to %s failed%s: %m", - svp->sv_hostname, droptext); + VERS_MSG "initial call to %s failed%s: %m", + svp->sv_hostname, droptext); (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0); svp->sv_flags |= SV4_NOTINUSE; nfs_rw_exit(&svp->sv_lock); @@ -2073,8 +2193,8 @@ nfs4rootvp(vnode_t **rtvpp, vfs_t *vfsp, struct servinfo4 *svp_head, if (tmp_vtype == VBAD) { zcmn_err(mi->mi_zone->zone_id, CE_WARN, - VERS_MSG "%s returned a bad file type for " - "root%s", svp->sv_hostname, droptext); + VERS_MSG "%s returned a bad file type for " + "root%s", svp->sv_hostname, droptext); (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0); svp->sv_flags |= SV4_NOTINUSE; nfs_rw_exit(&svp->sv_lock); @@ -2085,8 +2205,8 @@ nfs4rootvp(vnode_t **rtvpp, vfs_t *vfsp, struct servinfo4 *svp_head, vtype = tmp_vtype; } else if (vtype != tmp_vtype) { zcmn_err(mi->mi_zone->zone_id, CE_WARN, - VERS_MSG "%s returned a different file type " - "for root%s", svp->sv_hostname, droptext); + VERS_MSG "%s returned a different file type " + "for root%s", svp->sv_hostname, droptext); (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0); svp->sv_flags |= SV4_NOTINUSE; nfs_rw_exit(&svp->sv_lock); @@ -2134,7 +2254,7 @@ nfs4rootvp(vnode_t **rtvpp, vfs_t *vfsp, struct servinfo4 *svp_head, MI4_HOLD(mi); VFS_HOLD(vfsp); /* add reference for thread */ mi->mi_manager_thread = zthread_create(NULL, 0, nfs4_async_manager, - vfsp, 0, minclsyspri); + vfsp, 0, minclsyspri); ASSERT(mi->mi_manager_thread != NULL); /* @@ -2144,7 +2264,7 @@ nfs4rootvp(vnode_t **rtvpp, vfs_t *vfsp, struct servinfo4 *svp_head, */ MI4_HOLD(mi); mi->mi_inactive_thread = zthread_create(NULL, 0, nfs4_inactive_thread, - mi, 0, minclsyspri); + mi, 0, minclsyspri); ASSERT(mi->mi_inactive_thread != NULL); /* If we didn't get a type, get one now */ @@ -2173,6 +2293,7 @@ bad: */ if (lcr != NULL) crfree(lcr); + if (rtvp != NULL) { /* * We need to release our reference to the root vnode and @@ -2206,9 +2327,13 @@ bad: static int nfs4_unmount(vfs_t *vfsp, int flag, cred_t *cr) { - mntinfo4_t *mi; - ushort_t omax; - int removed; + mntinfo4_t *mi; + ushort_t omax; + int removed; + + bool_t must_unlock = FALSE; + + nfs4_ephemeral_tree_t *eph_tree; if (secpolicy_fs_unmount(cr, vfsp) != 0) return (EPERM); @@ -2227,44 +2352,60 @@ nfs4_unmount(vfs_t *vfsp, int flag, cred_t *cr) NFS4_DEBUG(nfs4_client_zone_debug, (CE_NOTE, "nfs4_unmount x-zone forced unmount of vfs %p\n", (void *)vfsp)); - nfs4_free_mount(vfsp, cr); + nfs4_free_mount(vfsp, flag, cr); } else { /* * Free data structures asynchronously, to avoid * blocking the current thread (for performance * reasons only). */ - async_free_mount(vfsp, cr); + async_free_mount(vfsp, flag, cr); } + return (0); } + /* * Wait until all asynchronous putpage operations on * this file system are complete before flushing rnodes * from the cache. */ omax = mi->mi_max_threads; - if (nfs4_async_stop_sig(vfsp)) { - + if (nfs4_async_stop_sig(vfsp)) return (EINTR); - } + r4flush(vfsp, cr); + + (void) nfs4_ephemeral_umount(mi, flag, cr, + &must_unlock, &eph_tree); + /* * If there are any active vnodes on this file system, - * then the file system is busy and can't be umounted. + * then the file system is busy and can't be unmounted. */ if (check_rtable4(vfsp)) { + nfs4_ephemeral_umount_unlock(&must_unlock, &eph_tree); + mutex_enter(&mi->mi_async_lock); mi->mi_max_threads = omax; mutex_exit(&mi->mi_async_lock); + return (EBUSY); } + + /* + * The unmount can't fail from now on, so record any + * ephemeral changes. + */ + nfs4_ephemeral_umount_activate(mi, &must_unlock, &eph_tree); + /* - * The unmount can't fail from now on, and there are no active - * files that could require over-the-wire calls to the server, - * so stop the async manager and the inactive thread. + * There are no active files that could require over-the-wire + * calls to the server, so stop the async manager and the + * inactive thread. */ nfs4_async_manager_stop(vfsp); + /* * Destroy all rnodes belonging to this file system from the * rnode hash queues and purge any resources allocated to @@ -2370,7 +2511,7 @@ nfs4_statvfs(vfs_t *vfsp, struct statvfs64 *sbp) error = nfs4_statfs_otw(vp, sbp, cr); if (!error) { (void) strncpy(sbp->f_basetype, - vfssw[vfsp->vfs_fstype].vsw_name, FSTYPSZ); + vfssw[vfsp->vfs_fstype].vsw_name, FSTYPSZ); sbp->f_flag = vf_to_stf(vfsp->vfs_flag); } else { nfs4_purge_stale_fh(error, vp, cr); @@ -2609,12 +2750,14 @@ nfs4_vfsinit(void) { mutex_init(&nfs4_syncbusy, NULL, MUTEX_DEFAULT, NULL); nfs4setclientid_init(); + nfs4_ephemeral_init(); return (0); } void nfs4_vfsfini(void) { + nfs4_ephemeral_fini(); nfs4setclientid_fini(); mutex_destroy(&nfs4_syncbusy); } @@ -2799,7 +2942,7 @@ recov_retry: np->s_cred = lcr; mutex_exit(&np->s_lock); nfs4setclientid_otw(mi, svp, lcr, np, n4ep, - &retry_inuse); + &retry_inuse); } } mutex_enter(&np->s_lock); @@ -2819,7 +2962,7 @@ recov_retry: */ if (FAILOVER_MOUNT4(mi) && nfs4_try_failover(n4ep)) { (void) nfs4_start_recovery(n4ep, mi, NULL, - NULL, NULL, NULL, OP_SETCLIENTID, NULL); + NULL, NULL, NULL, OP_SETCLIENTID, NULL); /* * Don't retry here, just return and let * recovery take over. @@ -2827,23 +2970,23 @@ recov_retry: if (recovery) retry = FALSE; } else if (nfs4_rpc_retry_error(n4ep->error) || - n4ep->stat == NFS4ERR_RESOURCE || - n4ep->stat == NFS4ERR_STALE_CLIENTID) { + n4ep->stat == NFS4ERR_RESOURCE || + n4ep->stat == NFS4ERR_STALE_CLIENTID) { - retry = TRUE; - /* - * Always retry if in recovery or once had - * contact with the server (but now it's - * overloaded). - */ - if (recovery == TRUE || - n4ep->error == ETIMEDOUT || - n4ep->error == ECONNRESET) - num_retries = 0; - } else if (retry_inuse && n4ep->error == 0 && - n4ep->stat == NFS4ERR_CLID_INUSE) { - retry = TRUE; + retry = TRUE; + /* + * Always retry if in recovery or once had + * contact with the server (but now it's + * overloaded). + */ + if (recovery == TRUE || + n4ep->error == ETIMEDOUT || + n4ep->error == ECONNRESET) num_retries = 0; + } else if (retry_inuse && n4ep->error == 0 && + n4ep->stat == NFS4ERR_CLID_INUSE) { + retry = TRUE; + num_retries = 0; } } else { /* @@ -2893,7 +3036,7 @@ int nfs4setclientid_otw_debug = 0; */ static void nfs4setclientid_otw(mntinfo4_t *mi, struct servinfo4 *svp, cred_t *cr, - struct nfs4_server *np, nfs4_error_t *ep, int *retry_inusep) + struct nfs4_server *np, nfs4_error_t *ep, int *retry_inusep) { COMPOUND4args_clnt args; COMPOUND4res_clnt res; @@ -2992,7 +3135,7 @@ nfs4setclientid_otw(mntinfo4_t *mi, struct servinfo4 *svp, cred_t *cr, if (!(*retry_inusep)) { clid_inuse = &res.array->nfs_resop4_u. - opsetclientid.SETCLIENTID4res_u.client_using; + opsetclientid.SETCLIENTID4res_u.client_using; zcmn_err(mi->mi_zone->zone_id, CE_NOTE, "NFS4 mount (SETCLIENTID failed)." @@ -3016,7 +3159,7 @@ nfs4setclientid_otw(mntinfo4_t *mi, struct servinfo4 *svp, cred_t *cr, } s_resok = &res.array[2].nfs_resop4_u. - opsetclientid.SETCLIENTID4res_u.resok4; + opsetclientid.SETCLIENTID4res_u.resok4; tmp_clientid = s_resok->clientid; @@ -3055,23 +3198,23 @@ nfs4setclientid_otw(mntinfo4_t *mi, struct servinfo4 *svp, cred_t *cr, gethrestime(&prop_time); NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, "nfs4setlientid_otw: " - "start time: %ld sec %ld nsec", prop_time.tv_sec, - prop_time.tv_nsec)); + "start time: %ld sec %ld nsec", prop_time.tv_sec, + prop_time.tv_nsec)); rfs4call(mi, &args, &res, cr, &doqueue, 0, ep); gethrestime(&after_time); mutex_enter(&np->s_lock); np->propagation_delay.tv_sec = - MAX(1, after_time.tv_sec - prop_time.tv_sec); + MAX(1, after_time.tv_sec - prop_time.tv_sec); mutex_exit(&np->s_lock); NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, "nfs4setlcientid_otw: " - "finish time: %ld sec ", after_time.tv_sec)); + "finish time: %ld sec ", after_time.tv_sec)); NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, "nfs4setclientid_otw: " - "propagation delay set to %ld sec", - np->propagation_delay.tv_sec)); + "propagation delay set to %ld sec", + np->propagation_delay.tv_sec)); if (ep->error) return; @@ -3081,7 +3224,7 @@ nfs4setclientid_otw(mntinfo4_t *mi, struct servinfo4 *svp, cred_t *cr, if (!(*retry_inusep)) { clid_inuse = &res.array->nfs_resop4_u. - opsetclientid.SETCLIENTID4res_u.client_using; + opsetclientid.SETCLIENTID4res_u.client_using; zcmn_err(mi->mi_zone->zone_id, CE_NOTE, "SETCLIENTID_CONFIRM failed. " @@ -3114,7 +3257,7 @@ nfs4setclientid_otw(mntinfo4_t *mi, struct servinfo4 *svp, cred_t *cr, np->s_refcnt++; /* pass reference to thread */ (void) zthread_create(NULL, 0, nfs4_renew_lease_thread, np, 0, - minclsyspri); + minclsyspri); } mutex_exit(&np->s_lock); @@ -3138,16 +3281,16 @@ nfs4_add_mi_to_server(nfs4_server_t *sp, mntinfo4_t *mi) ASSERT(MUTEX_HELD(&sp->s_lock)); NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, - "nfs4_add_mi_to_server: add mi %p to sp %p", - (void*)mi, (void*)sp)); + "nfs4_add_mi_to_server: add mi %p to sp %p", + (void*)mi, (void*)sp)); for (tmi = sp->mntinfo4_list; tmi != NULL; tmi = tmi->mi_clientid_next) { if (tmi == mi) { NFS4_DEBUG(nfs4_client_lease_debug, - (CE_NOTE, - "nfs4_add_mi_to_server: mi in list")); + (CE_NOTE, + "nfs4_add_mi_to_server: mi in list")); in_list = 1; } } @@ -3160,7 +3303,7 @@ nfs4_add_mi_to_server(nfs4_server_t *sp, mntinfo4_t *mi) VFS_HOLD(mi->mi_vfsp); NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, "nfs4_add_mi_to_server: " - "hold vfs %p for mi: %p", (void*)mi->mi_vfsp, (void*)mi)); + "hold vfs %p for mi: %p", (void*)mi->mi_vfsp, (void*)mi)); if (!in_list) { if (sp->mntinfo4_list) @@ -3200,8 +3343,8 @@ static void nfs4_remove_mi_from_server_nolock(mntinfo4_t *mi, nfs4_server_t *sp) { NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, - "nfs4_remove_mi_from_server_nolock: remove mi %p from sp %p", - (void*)mi, (void*)sp)); + "nfs4_remove_mi_from_server_nolock: remove mi %p from sp %p", + (void*)mi, (void*)sp)); ASSERT(sp != NULL); ASSERT(MUTEX_HELD(&sp->s_lock)); @@ -3213,8 +3356,8 @@ nfs4_remove_mi_from_server_nolock(mntinfo4_t *mi, nfs4_server_t *sp) */ if (mi->mi_open_files > 0) { NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, - "nfs4_remove_mi_from_server_nolock: don't " - "remove mi since it still has files open")); + "nfs4_remove_mi_from_server_nolock: don't " + "remove mi since it still has files open")); mutex_enter(&mi->mi_lock); mi->mi_flags |= MI4_REMOVE_ON_LAST_CLOSE; @@ -3229,7 +3372,7 @@ nfs4_remove_mi_from_server_nolock(mntinfo4_t *mi, nfs4_server_t *sp) if (sp->mntinfo4_list == NULL) { /* last fs unmounted, kill the thread */ NFS4_DEBUG(nfs4_client_lease_debug, (CE_NOTE, - "remove_mi_from_nfs4_server_nolock: kill the thread")); + "remove_mi_from_nfs4_server_nolock: kill the thread")); nfs4_mark_srv_dead(sp); } } @@ -3607,7 +3750,7 @@ servinfo4_to_nfs4_server(servinfo4_t *srv_p) if (np->zoneid == zoneid && np->saddr.len == srv_p->sv_addr.len && bcmp(np->saddr.buf, srv_p->sv_addr.buf, - np->saddr.len) == 0 && + np->saddr.len) == 0 && np->s_thread_exit != NFS4_THREAD_EXIT) { mutex_enter(&np->s_lock); np->s_refcnt++; @@ -3674,7 +3817,7 @@ find_nfs4_server_all(mntinfo4_t *mi, int all) if (nfs4_server_t_debug) { /* mi->mi_clientid is unprotected, ok for debug output */ dumpnfs4slist("find_nfs4_server", mi, mi->mi_clientid, - mi->mi_curr_serv); + mi->mi_curr_serv); } #endif for (np = nfs4_server_lst.forw; np != &nfs4_server_lst; np = np->forw) { @@ -3781,13 +3924,14 @@ nfs4_server_vlock(nfs4_server_t *sp, int all) */ static void -async_free_mount(vfs_t *vfsp, cred_t *cr) +async_free_mount(vfs_t *vfsp, int flag, cred_t *cr) { freemountargs_t *args; args = kmem_alloc(sizeof (freemountargs_t), KM_SLEEP); args->fm_vfsp = vfsp; VFS_HOLD(vfsp); MI4_HOLD(VFTOMI4(vfsp)); + args->fm_flag = flag; args->fm_cr = cr; crhold(cr); (void) zthread_create(NULL, 0, nfs4_free_mount_thread, args, 0, @@ -3798,7 +3942,7 @@ static void nfs4_free_mount_thread(freemountargs_t *args) { mntinfo4_t *mi; - nfs4_free_mount(args->fm_vfsp, args->fm_cr); + nfs4_free_mount(args->fm_vfsp, args->fm_flag, args->fm_cr); mi = VFTOMI4(args->fm_vfsp); crfree(args->fm_cr); VFS_RELE(args->fm_vfsp); @@ -3812,14 +3956,17 @@ nfs4_free_mount_thread(freemountargs_t *args) * Thread to free the data structures for a given filesystem. */ static void -nfs4_free_mount(vfs_t *vfsp, cred_t *cr) +nfs4_free_mount(vfs_t *vfsp, int flag, cred_t *cr) { - mntinfo4_t *mi = VFTOMI4(vfsp); - nfs4_server_t *sp; - callb_cpr_t cpr_info; - kmutex_t cpr_lock; - boolean_t async_thread; - int removed; + mntinfo4_t *mi = VFTOMI4(vfsp); + nfs4_server_t *sp; + callb_cpr_t cpr_info; + kmutex_t cpr_lock; + boolean_t async_thread; + int removed; + + bool_t must_unlock = FALSE; + nfs4_ephemeral_tree_t *eph_tree; /* * We need to participate in the CPR framework if this is a kernel @@ -3879,6 +4026,10 @@ nfs4_free_mount(vfs_t *vfsp, cred_t *cr) } mutex_exit(&mi->mi_lock); + (void) nfs4_ephemeral_umount(mi, flag, cr, + &must_unlock, &eph_tree); + nfs4_ephemeral_umount_activate(mi, &must_unlock, &eph_tree); + /* * The original purge of the dnlc via 'dounmount' * doesn't guarantee that another dnlc entry was not diff --git a/usr/src/uts/common/fs/nfs/nfs4_vnops.c b/usr/src/uts/common/fs/nfs/nfs4_vnops.c index 897e8fac60..f788f16bef 100644 --- a/usr/src/uts/common/fs/nfs/nfs4_vnops.c +++ b/usr/src/uts/common/fs/nfs/nfs4_vnops.c @@ -204,15 +204,11 @@ static int nfs4_read(vnode_t *, struct uio *, int, cred_t *, static int nfs4_write(vnode_t *, struct uio *, int, cred_t *, caller_context_t *); static int nfs4_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *); -static int nfs4_getattr(vnode_t *, struct vattr *, int, cred_t *); static int nfs4_setattr(vnode_t *, struct vattr *, int, cred_t *, caller_context_t *); static int nfs4_access(vnode_t *, int, int, cred_t *); static int nfs4_readlink(vnode_t *, struct uio *, cred_t *); static int nfs4_fsync(vnode_t *, int, cred_t *); -static void nfs4_inactive(vnode_t *, cred_t *); -static int nfs4_lookup(vnode_t *, char *, vnode_t **, - struct pathname *, int, vnode_t *, cred_t *); static int nfs4_create(vnode_t *, char *, struct vattr *, enum vcexcl, int, vnode_t **, cred_t *, int); static int nfs4_remove(vnode_t *, char *, cred_t *); @@ -224,9 +220,6 @@ static int nfs4_rmdir(vnode_t *, char *, vnode_t *, cred_t *); static int nfs4_symlink(vnode_t *, char *, struct vattr *, char *, cred_t *); static int nfs4_readdir(vnode_t *, struct uio *, cred_t *, int *); -static int nfs4_fid(vnode_t *, fid_t *); -static int nfs4_rwlock(vnode_t *, int, caller_context_t *); -static void nfs4_rwunlock(vnode_t *, int, caller_context_t *); static int nfs4_seek(vnode_t *, offset_t, offset_t *); static int nfs4_getpage(vnode_t *, offset_t, size_t, uint_t *, page_t *[], size_t, struct seg *, caddr_t, @@ -241,16 +234,28 @@ static int nfs4_frlock(vnode_t *, int, struct flock64 *, int, offset_t, struct flk_callback *, cred_t *); static int nfs4_space(vnode_t *, int, struct flock64 *, int, offset_t, cred_t *, caller_context_t *); -static int nfs4_realvp(vnode_t *, vnode_t **); static int nfs4_delmap(vnode_t *, offset_t, struct as *, caddr_t, size_t, uint_t, uint_t, uint_t, cred_t *); -static int nfs4_pathconf(vnode_t *, int, ulong_t *, cred_t *); static int nfs4_pageio(vnode_t *, page_t *, u_offset_t, size_t, int, cred_t *); static void nfs4_dispose(vnode_t *, page_t *, int, int, cred_t *); static int nfs4_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *); -static int nfs4_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *); static int nfs4_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *); +/* + * These vnode ops are required to be called from outside this source file, + * e.g. by ephemeral mount stub vnode ops, and so may not be declared + * as static. + */ +int nfs4_getattr(vnode_t *, struct vattr *, int, cred_t *); +void nfs4_inactive(vnode_t *, cred_t *); +int nfs4_lookup(vnode_t *, char *, vnode_t **, + struct pathname *, int, vnode_t *, cred_t *); +int nfs4_fid(vnode_t *, fid_t *); +int nfs4_rwlock(vnode_t *, int, caller_context_t *); +void nfs4_rwunlock(vnode_t *, int, caller_context_t *); +int nfs4_realvp(vnode_t *, vnode_t **); +int nfs4_pathconf(vnode_t *, int, ulong_t *, cred_t *); +int nfs4_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *); /* * Used for nfs4_commit_vp() to indicate if we should @@ -297,7 +302,6 @@ int nfs4_client_map_debug = 0; static int nfs4_pageio_debug = 0; int nfs4_client_inactive_debug = 0; int nfs4_client_recov_debug = 0; -int nfs4_client_recov_stub_debug = 0; int nfs4_client_failover_debug = 0; int nfs4_client_call_debug = 0; int nfs4_client_lookup_debug = 0; @@ -416,13 +420,16 @@ const fs_operation_def_t nfs4_vnodeops_template[] = { void nfs4args_lookup_free(nfs_argop4 *argop, int arglen) { - int i; + int i; for (i = 0; i < arglen; i++) { - if (argop[i].argop == OP_LOOKUP) - kmem_free( - argop[i].nfs_argop4_u.oplookup.objname.utf8string_val, - argop[i].nfs_argop4_u.oplookup.objname.utf8string_len); + if (argop[i].argop == OP_LOOKUP) { + kmem_free( + argop[i].nfs_argop4_u.oplookup. + objname.utf8string_val, + argop[i].nfs_argop4_u.oplookup. + objname.utf8string_len); + } } } @@ -437,7 +444,7 @@ nfs4args_lock_free(nfs_argop4 *argop) open_owner = &locker->locker4_u.open_owner; if (open_owner->lock_owner.owner_val != NULL) { kmem_free(open_owner->lock_owner.owner_val, - open_owner->lock_owner.owner_len); + open_owner->lock_owner.owner_len); } } } @@ -454,8 +461,8 @@ nfs4args_lockt_free(nfs_argop4 *argop) static void nfs4args_setattr(nfs_argop4 *argop, vattr_t *vap, vsecattr_t *vsap, int flags, - rnode4_t *rp, cred_t *cr, bitmap4 supp, int *error, - nfs4_stateid_types_t *sid_types) + rnode4_t *rp, cred_t *cr, bitmap4 supp, int *error, + nfs4_stateid_types_t *sid_types) { fattr4 *attr = &argop->nfs_argop4_u.opsetattr.obj_attributes; mntinfo4_t *mi; @@ -476,8 +483,8 @@ nfs4args_setattr(nfs_argop4 *argop, vattr_t *vap, vsecattr_t *vsap, int flags, mi = VTOMI4(RTOV4(rp)); argop->nfs_argop4_u.opsetattr.stateid = - nfs4_get_stateid(cr, rp, curproc->p_pidp->pid_id, mi, - OP_SETATTR, sid_types, FALSE); + nfs4_get_stateid(cr, rp, curproc->p_pidp->pid_id, mi, + OP_SETATTR, sid_types, FALSE); } else { bzero(&argop->nfs_argop4_u.opsetattr.stateid, sizeof (stateid4)); @@ -496,7 +503,7 @@ nfs4args_setattr_free(nfs_argop4 *argop) static int nfs4args_verify(nfs_argop4 *argop, vattr_t *vap, enum nfs_opnum4 op, - bitmap4 supp) + bitmap4 supp) { fattr4 *attr; int error = 0; @@ -536,7 +543,7 @@ nfs4args_verify_free(nfs_argop4 *argop) static void nfs4args_write(nfs_argop4 *argop, stable_how4 stable, rnode4_t *rp, cred_t *cr, - WRITE4args **wargs_pp, nfs4_stateid_types_t *sid_tp) + WRITE4args **wargs_pp, nfs4_stateid_types_t *sid_tp) { WRITE4args *wargs = &argop->nfs_argop4_u.opwrite; mntinfo4_t *mi = VTOMI4(RTOV4(rp)); @@ -544,7 +551,7 @@ nfs4args_write(nfs_argop4 *argop, stable_how4 stable, rnode4_t *rp, cred_t *cr, argop->argop = OP_WRITE; wargs->stable = stable; wargs->stateid = nfs4_get_w_stateid(cr, rp, curproc->p_pidp->pid_id, - mi, OP_WRITE, sid_tp); + mi, OP_WRITE, sid_tp); wargs->mblk = NULL; *wargs_pp = wargs; } @@ -554,7 +561,7 @@ nfs4args_copen_free(OPEN4cargs *open_args) { if (open_args->owner.owner_val) { kmem_free(open_args->owner.owner_val, - open_args->owner.owner_len); + open_args->owner.owner_len); } if ((open_args->opentype == OPEN4_CREATE) && (open_args->mode != EXCLUSIVE4)) { @@ -645,7 +652,7 @@ nfs4_open(vnode_t **vpp, int flag, cred_t *cr) flag |= FWRITE; error = nfs4open_otw(dvp, fn, NULL, vpp, cr, 0, flag, 0, - just_been_created); + just_been_created); if (!error && !((*vpp)->v_flag & VROOT)) dnlc_update(dvp, fn, *vpp); @@ -668,8 +675,8 @@ nfs4_open(vnode_t **vpp, int flag, cred_t *cr) */ static void nfs4open_save_lost_rqst(int error, nfs4_lost_rqst_t *lost_rqstp, - nfs4_open_owner_t *oop, cred_t *cr, vnode_t *vp, - vnode_t *dvp, OPEN4cargs *open_args) + nfs4_open_owner_t *oop, cred_t *cr, vnode_t *vp, + vnode_t *dvp, OPEN4cargs *open_args) { vfs_t *vfsp; char *srccfp; @@ -677,15 +684,16 @@ nfs4open_save_lost_rqst(int error, nfs4_lost_rqst_t *lost_rqstp, vfsp = (dvp ? dvp->v_vfsp : vp->v_vfsp); if (error != ETIMEDOUT && error != EINTR && - !NFS4_FRC_UNMT_ERR(error, vfsp)) { + !NFS4_FRC_UNMT_ERR(error, vfsp)) { lost_rqstp->lr_op = 0; return; } NFS4_DEBUG(nfs4_lost_rqst_debug, (CE_NOTE, - "nfs4open_save_lost_rqst: error %d", error)); + "nfs4open_save_lost_rqst: error %d", error)); lost_rqstp->lr_op = OP_OPEN; + /* * The vp (if it is not NULL) and dvp are held and rele'd via * the recovery code. See nfs4_save_lost_rqst. @@ -725,8 +733,8 @@ struct nfs4_excl_time { */ static int nfs4open_otw(vnode_t *dvp, char *file_name, struct vattr *in_va, - vnode_t **vpp, cred_t *cr, int create_flag, int open_flag, - enum createmode4 createmode, int file_just_been_created) + vnode_t **vpp, cred_t *cr, int create_flag, int open_flag, + enum createmode4 createmode, int file_just_been_created) { rnode4_t *rp; rnode4_t *drp = VTOR4(dvp); @@ -825,8 +833,8 @@ nfs4open_otw(vnode_t *dvp, char *file_name, struct vattr *in_va, argop = kmem_alloc(argoplist_size, KM_SLEEP); NFS4_DEBUG(nfs4_client_state_debug, (CE_NOTE, "nfs4open_otw: " - "open %s open flag 0x%x cred %p", file_name, open_flag, - (void *)cr)); + "open %s open flag 0x%x cred %p", file_name, open_flag, + (void *)cr)); ASSERT(nfs_zone() == VTOMI4(dvp)->mi_zone); if (create_flag) { @@ -940,12 +948,12 @@ recov_retry: /* GUARDED4 or UNCHECKED4 */ v_error = vattr_to_fattr4(in_va, NULL, attr, 0, OP_OPEN, - supp_attrs); + supp_attrs); if (v_error) { bzero(attr, sizeof (*attr)); nfs4args_copen_free(open_args); nfs4_end_op(VTOMI4(dvp), dvp, vpi, - &recov_state, FALSE); + &recov_state, FALSE); if (ncr != NULL) crfree(ncr); kmem_free(argop, argoplist_size); @@ -1005,7 +1013,7 @@ recov_retry: /* Check to see if we need to do the OTW call */ if (!create_flag) { if (!nfs4_is_otw_open_necessary(oop, open_flag, vpi, - file_just_been_created, &e.error, acc, &recov_state)) { + file_just_been_created, &e.error, acc, &recov_state)) { /* * The OTW open is not necessary. Either @@ -1152,13 +1160,13 @@ recov_retry: if (!e.error && res.status == NFS4ERR_BAD_SEQID) { bsep = nfs4_create_bseqid_entry(oop, NULL, - vpi, 0, args.ctag, open_args->seqid); + vpi, 0, args.ctag, open_args->seqid); num_bseqid_retry--; } abort = nfs4_start_recovery(&e, VTOMI4(dvp), dvp, vpi, - NULL, lost_rqst.lr_op == OP_OPEN ? - &lost_rqst : NULL, OP_OPEN, bsep); + NULL, lost_rqst.lr_op == OP_OPEN ? + &lost_rqst : NULL, OP_OPEN, bsep); if (bsep) kmem_free(bsep, sizeof (*bsep)); @@ -1324,7 +1332,7 @@ recov_retry: } (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); nfs4_end_op(VTOMI4(dvp), dvp, vpi, &recov_state, - needrecov); + needrecov); open_owner_rele(oop); VN_RELE(vp); if (ncr != NULL) @@ -1364,7 +1372,7 @@ recov_retry: } (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); nfs4_end_op(VTOMI4(dvp), dvp, vpi, &recov_state, - needrecov); + needrecov); open_owner_rele(oop); if (create_flag || fh_differs) { /* rele the makenfs4node */ @@ -1488,9 +1496,9 @@ recov_retry: nfs4_end_op(VTOMI4(dvp), dvp, vpi, &recov_state, needrecov); if (createmode == EXCLUSIVE4 && - (in_va->va_mask & ~(AT_GID | AT_SIZE))) { + (in_va->va_mask & ~(AT_GID | AT_SIZE))) { NFS4_DEBUG(nfs4_client_state_debug, (CE_NOTE, "nfs4open_otw:" - " EXCLUSIVE4: sending a SETATTR")); + " EXCLUSIVE4: sending a SETATTR")); /* * If doing an exclusive create, then generate * a SETATTR to set the initial attributes. @@ -1527,8 +1535,8 @@ recov_retry: */ /* XXX will this take care of client state ? */ NFS4_DEBUG(nfs4_client_state_debug, (CE_NOTE, - "nfs4open_otw: EXCLUSIVE4: error %d on SETATTR:" - " remove file", e.error)); + "nfs4open_otw: EXCLUSIVE4: error %d on SETATTR:" + " remove file", e.error)); VN_RELE(vp); (void) nfs4_remove(dvp, file_name, cr); /* @@ -1560,14 +1568,14 @@ recov_retry: dinfo.di_time_call = t; dinfo.di_cred = cr; dinfo.di_garp = - &res.array[6].nfs_resop4_u.opgetattr.ga_res; + &res.array[6].nfs_resop4_u.opgetattr.ga_res; dinfop = &dinfo; } else { dinfop = NULL; } nfs4_update_dircaches(&op_res->cinfo, dvp, vp, file_name, - dinfop); + dinfop); } /* @@ -1632,8 +1640,8 @@ skip_update_dircaches: void nfs4_reopen(vnode_t *vp, nfs4_open_stream_t *osp, nfs4_error_t *ep, - open_claim_type4 claim, bool_t frc_use_claim_previous, - bool_t is_recov) + open_claim_type4 claim, bool_t frc_use_claim_previous, + bool_t is_recov) { COMPOUND4args_clnt args; COMPOUND4res_clnt res; @@ -1755,8 +1763,8 @@ top: * use the mntinfo parentfh */ argop[0].nfs_argop4_u.opcputfh.sfh = - (vp->v_flag & VROOT) ? mi->mi_srvparentfh : - VTOSV(vp)->sv_dfh; + (vp->v_flag & VROOT) ? mi->mi_srvparentfh : + VTOSV(vp)->sv_dfh; } else { /* putfh fh to reopen */ argop[0].nfs_argop4_u.opcputfh.sfh = rp->r_fh; @@ -1796,9 +1804,9 @@ top: */ mutex_enter(&rp->r_statev4_lock); open_args->open_claim4_u.delegate_type = - frc_use_claim_previous ? - rp->r_deleg_type : - rp->r_deleg_needs_recovery; + frc_use_claim_previous ? + rp->r_deleg_type : + rp->r_deleg_needs_recovery; mutex_exit(&rp->r_statev4_lock); } else if (claim == CLAIM_DELEGATE_CUR) { @@ -1815,7 +1823,7 @@ top: mutex_enter(&rp->r_statev4_lock); open_args->open_claim4_u.delegate_cur_info.delegate_stateid = - rp->r_deleg_stateid; + rp->r_deleg_stateid; mutex_exit(&rp->r_statev4_lock); open_args->open_claim4_u.delegate_cur_info.cfile = fn; @@ -1824,9 +1832,9 @@ top: open_args->owner.clientid = mi2clientid(mi); open_args->owner.owner_len = sizeof (oop->oo_name); open_args->owner.owner_val = - kmem_alloc(open_args->owner.owner_len, KM_SLEEP); + kmem_alloc(open_args->owner.owner_len, KM_SLEEP); bcopy(&oop->oo_name, open_args->owner.owner_val, - open_args->owner.owner_len); + open_args->owner.owner_len); open_args->share_access = 0; open_args->share_deny = 0; @@ -1868,11 +1876,11 @@ top: (ep->error == EINTR || ep->error == ETIMEDOUT || NFS4_FRC_UNMT_ERR(ep->error, vp->v_vfsp))) { nfs4open_save_lost_rqst(ep->error, &lost_rqst, oop, - cred_otw, vp, NULL, open_args); + cred_otw, vp, NULL, open_args); abort = nfs4_start_recovery(ep, - VTOMI4(vp), vp, NULL, NULL, - lost_rqst.lr_op == OP_OPEN ? - &lost_rqst : NULL, OP_OPEN, NULL); + VTOMI4(vp), vp, NULL, NULL, + lost_rqst.lr_op == OP_OPEN ? + &lost_rqst : NULL, OP_OPEN, NULL); nfs4args_copen_free(open_args); goto bailout; } @@ -1907,11 +1915,11 @@ top: break; case NFS4ERR_BAD_SEQID: bsep = nfs4_create_bseqid_entry(oop, NULL, vp, 0, - args.ctag, open_args->seqid); + args.ctag, open_args->seqid); abort = nfs4_start_recovery(ep, VTOMI4(vp), vp, NULL, - NULL, lost_rqst.lr_op == OP_OPEN ? &lost_rqst : - NULL, OP_OPEN, bsep); + NULL, lost_rqst.lr_op == OP_OPEN ? &lost_rqst : + NULL, OP_OPEN, bsep); nfs4args_copen_free(open_args); (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); @@ -1970,7 +1978,7 @@ top: case NFS4ERR_FHEXPIRED: /* recover filehandle and retry */ abort = nfs4_start_recovery(ep, - mi, vp, NULL, NULL, NULL, OP_OPEN, NULL); + mi, vp, NULL, NULL, NULL, OP_OPEN, NULL); nfs4args_copen_free(open_args); (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); nfs4_end_open_seqid_sync(oop); @@ -2067,11 +2075,11 @@ top: * compare. So kill the file. */ failed_msg = - "Couldn't reopen: file handle changed" + "Couldn't reopen: file handle changed" " due to mismatched fids"; nfs4args_copen_free(open_args); (void) xdr_free(xdr_COMPOUND4res_clnt, - (caddr_t)&res); + (caddr_t)&res); nfs_rw_exit(&mi->mi_fh_lock); goto kill_file; } else { @@ -2107,8 +2115,8 @@ top: bool_t retry_open = FALSE; nfs4open_confirm(vp, &seqid, &op_res->stateid, - cred_otw, is_recov, &retry_open, - oop, FALSE, ep, NULL); + cred_otw, is_recov, &retry_open, + oop, FALSE, ep, NULL); if (ep->error || ep->stat) { nfs4args_copen_free(open_args); (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); @@ -2192,7 +2200,7 @@ nfs4_open_non_reg_file(vnode_t **vpp, int flag, cred_t *cr) */ rp = VTOR4(*vpp); if (VTOMI4(*vpp)->mi_flags & MI4_NOCTO || - (rp->r_dir == NULL && !nfs4_has_pages(*vpp))) + (rp->r_dir == NULL && !nfs4_has_pages(*vpp))) return (0); gar.n4g_va.va_mask = AT_ALL; @@ -2321,8 +2329,8 @@ nfs4_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr) static void nfs4close_save_lost_rqst(int error, nfs4_lost_rqst_t *lost_rqstp, - nfs4_open_owner_t *oop, nfs4_open_stream_t *osp, cred_t *cr, - vnode_t *vp) + nfs4_open_owner_t *oop, nfs4_open_stream_t *osp, cred_t *cr, + vnode_t *vp) { if (error != ETIMEDOUT && error != EINTR && !NFS4_FRC_UNMT_ERR(error, vp->v_vfsp)) { @@ -2331,7 +2339,7 @@ nfs4close_save_lost_rqst(int error, nfs4_lost_rqst_t *lost_rqstp, } NFS4_DEBUG(nfs4_lost_rqst_debug, (CE_NOTE, - "nfs4close_save_lost_rqst: error %d", error)); + "nfs4close_save_lost_rqst: error %d", error)); lost_rqstp->lr_op = OP_CLOSE; /* @@ -2365,8 +2373,8 @@ nfs4close_save_lost_rqst(int error, nfs4_lost_rqst_t *lost_rqstp, */ static void nfs4close_otw(rnode4_t *rp, cred_t *cred_otw, nfs4_open_owner_t *oop, - nfs4_open_stream_t *osp, int *recov, int *did_start_seqid_syncp, - nfs4_close_type_t close_type, nfs4_error_t *ep, int *have_sync_lockp) + nfs4_open_stream_t *osp, int *recov, int *did_start_seqid_syncp, + nfs4_close_type_t close_type, nfs4_error_t *ep, int *have_sync_lockp) { COMPOUND4args_clnt args; COMPOUND4res_clnt res; @@ -2454,15 +2462,15 @@ nfs4close_otw(rnode4_t *rp, cred_t *cred_otw, nfs4_open_owner_t *oop, if (close_type != CLOSE_RESEND) nfs4close_save_lost_rqst(ep->error, &lost_rqst, oop, - osp, cred_otw, vp); + osp, cred_otw, vp); if (!ep->error && res.status == NFS4ERR_BAD_SEQID) bsep = nfs4_create_bseqid_entry(oop, NULL, vp, - 0, args.ctag, close_args->seqid); + 0, args.ctag, close_args->seqid); NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE, - "nfs4close_otw: initiating recovery. error %d " - "res.status %d", ep->error, res.status)); + "nfs4close_otw: initiating recovery. error %d " + "res.status %d", ep->error, res.status)); /* * Drop the 'os_sync_lock' here so we don't hit @@ -2472,9 +2480,9 @@ nfs4close_otw(rnode4_t *rp, cred_t *cred_otw, nfs4_open_owner_t *oop, mutex_exit(&osp->os_sync_lock); *have_sync_lockp = 0; abort = nfs4_start_recovery(ep, VTOMI4(vp), vp, NULL, NULL, - (close_type != CLOSE_RESEND && - lost_rqst.lr_op == OP_CLOSE) ? &lost_rqst : NULL, - OP_CLOSE, bsep); + (close_type != CLOSE_RESEND && + lost_rqst.lr_op == OP_CLOSE) ? &lost_rqst : NULL, + OP_CLOSE, bsep); /* drop open seq sync, and let the calling function regrab it */ nfs4_end_open_seqid_sync(oop); @@ -2529,11 +2537,11 @@ nfs4close_otw(rnode4_t *rp, cred_t *cred_otw, nfs4_open_owner_t *oop, if (!ep->error) nfs4_attr_cache(vp, - &res.array[1].nfs_resop4_u.opgetattr.ga_res, - t, cred_otw, TRUE, NULL); + &res.array[1].nfs_resop4_u.opgetattr.ga_res, + t, cred_otw, TRUE, NULL); NFS4_DEBUG(nfs4_client_state_debug, (CE_NOTE, "nfs4close_otw:" - " returning %d", ep->error)); + " returning %d", ep->error)); (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); } @@ -2541,7 +2549,7 @@ nfs4close_otw(rnode4_t *rp, cred_t *cred_otw, nfs4_open_owner_t *oop, /* ARGSUSED */ static int nfs4_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr, - caller_context_t *ct) + caller_context_t *ct) { rnode4_t *rp; u_offset_t off; @@ -2594,7 +2602,7 @@ nfs4_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr, size_t resid = 0; return (nfs4read(vp, NULL, uiop->uio_loffset, - uiop->uio_resid, &resid, cr, FALSE, uiop)); + uiop->uio_resid, &resid, cr, FALSE, uiop)); } error = 0; @@ -2620,11 +2628,10 @@ nfs4_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr, * Copy data. */ error = vpm_data_copy(vp, off + on, n, uiop, - 1, NULL, 0, S_READ); - + 1, NULL, 0, S_READ); } else { base = segmap_getmapflt(segkmap, vp, off + on, n, 1, - S_READ); + S_READ); error = uiomove(base + on, n, UIO_READ, uiop); } @@ -2661,7 +2668,7 @@ nfs4_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr, /* ARGSUSED */ static int nfs4_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr, - caller_context_t *ct) + caller_context_t *ct) { rlim64_t limit = uiop->uio_llimit; rnode4_t *rp; @@ -2798,7 +2805,7 @@ nfs4_fwrite: error = uiomove(base, count, UIO_WRITE, uiop); if (!error) { error = nfs4write(vp, base, org_offset, - count, cr, &stab_comm); + count, cr, &stab_comm); if (!error) { mutex_enter(&rp->r_statelock); if (rp->r_size < uiop->uio_loffset) @@ -2853,23 +2860,23 @@ nfs4_fwrite: if (segmap_kpm) { int pon = uiop->uio_loffset & PAGEOFFSET; size_t pn = MIN(PAGESIZE - pon, - uiop->uio_resid); + uiop->uio_resid); int pagecreate; mutex_enter(&rp->r_statelock); pagecreate = (pon == 0) && (pn == PAGESIZE || - uiop->uio_loffset + pn >= rp->r_size); + uiop->uio_loffset + pn >= rp->r_size); mutex_exit(&rp->r_statelock); base = segmap_getmapflt(segkmap, vp, off + on, - pn, !pagecreate, S_WRITE); + pn, !pagecreate, S_WRITE); error = writerp4(rp, base + pon, n, uiop, - pagecreate); + pagecreate); } else { base = segmap_getmapflt(segkmap, vp, off + on, - n, 0, S_READ); + n, 0, S_READ); error = writerp4(rp, base + on, n, uiop, 0); } } @@ -2940,7 +2947,7 @@ bottom: */ static int nfs4_rdwrlbn(vnode_t *vp, page_t *pp, u_offset_t off, size_t len, - int flags, cred_t *cr) + int flags, cred_t *cr) { struct buf *bp; int error; @@ -3057,7 +3064,7 @@ nfs4rdwr_check_osid(vnode_t *vp, nfs4_error_t *ep, cred_t *cr) */ static int nfs4write(vnode_t *vp, caddr_t base, u_offset_t offset, int count, cred_t *cr, - stable_how4 *stab_comm) + stable_how4 *stab_comm) { mntinfo4_t *mi; COMPOUND4args_clnt args; @@ -3094,7 +3101,7 @@ recov_retry: args.array = argop; e.error = nfs4_start_fop(VTOMI4(vp), vp, NULL, OH_WRITE, - &recov_state, NULL); + &recov_state, NULL); if (e.error) return (e.error); @@ -3134,7 +3141,7 @@ recov_retry: needrecov = nfs4_needs_recovery(&e, FALSE, mi->mi_vfsp); if (e.error && !needrecov) { nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_WRITE, - &recov_state, needrecov); + &recov_state, needrecov); return (e.error); } @@ -3152,28 +3159,28 @@ recov_retry: sid_types.cur_sid_type != SPEC_SID) { nfs4_save_stateid(&wargs->stateid, &sid_types); nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_WRITE, - &recov_state, needrecov); + &recov_state, needrecov); (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); goto recov_retry; } else if (e.error == 0 && res.status == NFS4ERR_BAD_STATEID && - sid_types.cur_sid_type == DEL_SID) { + sid_types.cur_sid_type == DEL_SID) { nfs4_save_stateid(&wargs->stateid, &sid_types); mutex_enter(&rp->r_statev4_lock); rp->r_deleg_return_pending = TRUE; mutex_exit(&rp->r_statev4_lock); if (nfs4rdwr_check_osid(vp, &e, cr)) { nfs4_end_fop(mi, vp, NULL, OH_WRITE, - &recov_state, needrecov); + &recov_state, needrecov); (void) xdr_free(xdr_COMPOUND4res_clnt, - (caddr_t)&res); + (caddr_t)&res); return (EIO); } nfs4_end_fop(mi, vp, NULL, OH_WRITE, - &recov_state, needrecov); + &recov_state, needrecov); /* hold needed for nfs4delegreturn_thread */ VN_HOLD(vp); nfs4delegreturn_async(rp, (NFS4_DR_PUSH|NFS4_DR_REOPEN| - NFS4_DR_DISCARD), FALSE); + NFS4_DR_DISCARD), FALSE); (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); goto recov_retry; } @@ -3182,19 +3189,19 @@ recov_retry: bool_t abort; NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE, - "nfs4write: client got error %d, res.status %d" - ", so start recovery", e.error, res.status)); + "nfs4write: client got error %d, res.status %d" + ", so start recovery", e.error, res.status)); abort = nfs4_start_recovery(&e, - VTOMI4(vp), vp, NULL, &wargs->stateid, - NULL, OP_WRITE, NULL); + VTOMI4(vp), vp, NULL, &wargs->stateid, + NULL, OP_WRITE, NULL); if (!e.error) { e.error = geterrno4(res.status); (void) xdr_free(xdr_COMPOUND4res_clnt, - (caddr_t)&res); + (caddr_t)&res); } nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_WRITE, - &recov_state, needrecov); + &recov_state, needrecov); if (abort == FALSE) goto recov_retry; return (e.error); @@ -3204,7 +3211,7 @@ recov_retry: e.error = geterrno4(res.status); (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_WRITE, - &recov_state, needrecov); + &recov_state, needrecov); return (e.error); } @@ -3215,10 +3222,10 @@ recov_retry: (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); zcmn_err(getzoneid(), CE_WARN, - "nfs4write: server wrote %u, requested was %u", + "nfs4write: server wrote %u, requested was %u", (int)wres->count, tsize); nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_WRITE, - &recov_state, needrecov); + &recov_state, needrecov); return (EIO); } if (wres->committed == UNSTABLE4) { @@ -3226,13 +3233,13 @@ recov_retry: if (wargs->stable == DATA_SYNC4 || wargs->stable == FILE_SYNC4) { (void) xdr_free(xdr_COMPOUND4res_clnt, - (caddr_t)&res); + (caddr_t)&res); zcmn_err(getzoneid(), CE_WARN, - "nfs4write: server %s did not commit " - "to stable storage", - rp->r_server->sv_hostname); + "nfs4write: server %s did not commit " + "to stable storage", + rp->r_server->sv_hostname); nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_WRITE, - &recov_state, needrecov); + &recov_state, needrecov); return (EIO); } } @@ -3277,7 +3284,7 @@ recov_retry: */ static int nfs4read(vnode_t *vp, caddr_t base, offset_t offset, int count, - size_t *residp, cred_t *cr, bool_t async, struct uio *uiop) + size_t *residp, cred_t *cr, bool_t async, struct uio *uiop) { mntinfo4_t *mi; COMPOUND4args_clnt args; @@ -3312,7 +3319,7 @@ nfs4read(vnode_t *vp, caddr_t base, offset_t offset, int count, recov_retry: e.error = nfs4_start_fop(mi, vp, NULL, OH_READ, - &recov_state, NULL); + &recov_state, NULL); if (e.error) return (e.error); @@ -3324,7 +3331,7 @@ recov_retry: argop[1].argop = OP_READ; rargs = &argop[1].nfs_argop4_u.opread; rargs->stateid = nfs4_get_stateid(cr, rp, curproc->p_pidp->pid_id, mi, - OP_READ, &sid_types, async); + OP_READ, &sid_types, async); do { if (mi->mi_io_kstats) { @@ -3373,7 +3380,7 @@ recov_retry: needrecov = nfs4_needs_recovery(&e, FALSE, mi->mi_vfsp); if (e.error != 0 && !needrecov) { nfs4_end_fop(mi, vp, NULL, OH_READ, - &recov_state, needrecov); + &recov_state, needrecov); return (e.error); } @@ -3394,41 +3401,41 @@ recov_retry: if (e.error == 0 && (res.status == NFS4ERR_OLD_STATEID || res.status == NFS4ERR_BAD_STATEID) && async) { nfs4_end_fop(mi, vp, NULL, OH_READ, - &recov_state, needrecov); + &recov_state, needrecov); if (sid_types.cur_sid_type == SPEC_SID) { (void) xdr_free(xdr_COMPOUND4res_clnt, - (caddr_t)&res); + (caddr_t)&res); return (EIO); } nfs4_save_stateid(&rargs->stateid, &sid_types); (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); goto recov_retry; } else if (e.error == 0 && res.status == NFS4ERR_OLD_STATEID && - !async && sid_types.cur_sid_type != SPEC_SID) { + !async && sid_types.cur_sid_type != SPEC_SID) { nfs4_save_stateid(&rargs->stateid, &sid_types); nfs4_end_fop(mi, vp, NULL, OH_READ, - &recov_state, needrecov); + &recov_state, needrecov); (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); goto recov_retry; } else if (e.error == 0 && res.status == NFS4ERR_BAD_STATEID && - sid_types.cur_sid_type == DEL_SID) { + sid_types.cur_sid_type == DEL_SID) { nfs4_save_stateid(&rargs->stateid, &sid_types); mutex_enter(&rp->r_statev4_lock); rp->r_deleg_return_pending = TRUE; mutex_exit(&rp->r_statev4_lock); if (nfs4rdwr_check_osid(vp, &e, cr)) { nfs4_end_fop(mi, vp, NULL, OH_READ, - &recov_state, needrecov); + &recov_state, needrecov); (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); return (EIO); } nfs4_end_fop(mi, vp, NULL, OH_READ, - &recov_state, needrecov); + &recov_state, needrecov); /* hold needed for nfs4delegreturn_thread */ VN_HOLD(vp); nfs4delegreturn_async(rp, (NFS4_DR_PUSH|NFS4_DR_REOPEN| - NFS4_DR_DISCARD), FALSE); + NFS4_DR_DISCARD), FALSE); (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); goto recov_retry; } @@ -3439,10 +3446,10 @@ recov_retry: "nfs4read: initiating recovery\n")); abort = nfs4_start_recovery(&e, - mi, vp, NULL, &rargs->stateid, - NULL, OP_READ, NULL); + mi, vp, NULL, &rargs->stateid, + NULL, OP_READ, NULL); nfs4_end_fop(mi, vp, NULL, OH_READ, - &recov_state, needrecov); + &recov_state, needrecov); /* * Do not retry if we got OLD_STATEID using a special * stateid. This avoids looping with a broken server. @@ -3460,14 +3467,14 @@ recov_retry: */ nfs4_init_stateid_types(&sid_types); (void) xdr_free(xdr_COMPOUND4res_clnt, - (caddr_t)&res); + (caddr_t)&res); goto recov_retry; } if (!e.error) { e.error = geterrno4(res.status); (void) xdr_free(xdr_COMPOUND4res_clnt, - (caddr_t)&res); + (caddr_t)&res); } return (e.error); } @@ -3475,7 +3482,7 @@ recov_retry: if (res.status) { e.error = geterrno4(res.status); nfs4_end_fop(mi, vp, NULL, OH_READ, - &recov_state, needrecov); + &recov_state, needrecov); (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); return (e.error); } @@ -3518,7 +3525,7 @@ nfs4_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp) } } -static int +int nfs4_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr) { int error; @@ -3567,11 +3574,11 @@ nfs4_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr) rp->r_gcount++; mutex_exit(&rp->r_statelock); error = - nfs4_putpage(vp, (u_offset_t)0, - 0, 0, cr); + nfs4_putpage(vp, (u_offset_t)0, + 0, 0, cr); mutex_enter(&rp->r_statelock); if (error && (error == ENOSPC || - error == EDQUOT)) { + error == EDQUOT)) { if (!rp->r_error) rp->r_error = error; } @@ -3605,7 +3612,7 @@ nfs4_compare_modes(mode_t from_server, mode_t on_client) /*ARGSUSED4*/ static int nfs4_setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr, - caller_context_t *ct) + caller_context_t *ct) { if (vap->va_mask & AT_NOSET) return (EINVAL); @@ -3643,7 +3650,7 @@ nfs4_setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr, */ static int nfs4setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr, - vsecattr_t *vsap) + vsecattr_t *vsap) { COMPOUND4args_clnt args; COMPOUND4res_clnt res, *resp = NULL; @@ -3711,7 +3718,7 @@ nfs4setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr, */ mutex_enter(&rp->r_statev4_lock); if (rp->r_deleg_type == OPEN_DELEGATE_NONE || - rp->r_deleg_return_pending) { + rp->r_deleg_return_pending) { numops = 5; ctime = rp->r_attr.va_ctime; } @@ -3759,13 +3766,13 @@ recov_retry: nfs_rw_exit(&svp->sv_lock); nfs4args_setattr(&argop[setattr_argop], vap, vsap, flags, rp, cr, - supp_attrs, &e.error, &sid_types); + supp_attrs, &e.error, &sid_types); stateid = argop[setattr_argop].nfs_argop4_u.opsetattr.stateid; if (e.error) { /* req time field(s) overflow - return immediately */ nfs4_end_op(VTOMI4(vp), vp, NULL, &recov_state, needrecov); nfs4_fattr4_free(&argop[setattr_argop].nfs_argop4_u. - opsetattr.obj_attributes); + opsetattr.obj_attributes); return (e.error); } omode = rp->r_attr.va_mode; @@ -3800,11 +3807,11 @@ recov_retry: supp_attrs = svp->sv_supp_attrs; nfs_rw_exit(&svp->sv_lock); e.error = nfs4args_verify(&argop[verify_argop], &va, - OP_VERIFY, supp_attrs); + OP_VERIFY, supp_attrs); if (e.error) { /* req time field(s) overflow - return */ nfs4_end_op(VTOMI4(vp), vp, NULL, &recov_state, - needrecov); + needrecov); break; } } @@ -3867,10 +3874,10 @@ recov_retry: sid_types.cur_sid_type != SPEC_SID && sid_types.cur_sid_type != NO_SID) { nfs4_end_op(VTOMI4(vp), vp, NULL, &recov_state, - needrecov); + needrecov); nfs4_save_stateid(&stateid, &sid_types); nfs4_fattr4_free(&argop[setattr_argop].nfs_argop4_u. - opsetattr.obj_attributes); + opsetattr.obj_attributes); if (verify_argop != -1) { nfs4args_verify_free(&argop[verify_argop]); verify_argop = -1; @@ -3883,10 +3890,10 @@ recov_retry: bool_t abort; abort = nfs4_start_recovery(&e, - VTOMI4(vp), vp, NULL, NULL, NULL, - OP_SETATTR, NULL); + VTOMI4(vp), vp, NULL, NULL, NULL, + OP_SETATTR, NULL); nfs4_end_op(VTOMI4(vp), vp, NULL, &recov_state, - needrecov); + needrecov); /* * Do not retry if we failed with OLD_STATEID using * a special stateid. This is done to avoid looping @@ -3903,10 +3910,10 @@ recov_retry: e.error = geterrno4(res.status); (void) xdr_free(xdr_COMPOUND4res_clnt, - (caddr_t)&res); + (caddr_t)&res); } nfs4_fattr4_free(&argop[setattr_argop].nfs_argop4_u. - opsetattr.obj_attributes); + opsetattr.obj_attributes); if (verify_argop != -1) { nfs4args_verify_free(&argop[verify_argop]); verify_argop = -1; @@ -3978,7 +3985,7 @@ recov_retry: } if (!e.error) { nfs4_fattr4_free(&argop[setattr_argop].nfs_argop4_u. - opsetattr.obj_attributes); + opsetattr.obj_attributes); if (verify_argop != -1) { nfs4args_verify_free(&argop[verify_argop]); verify_argop = -1; @@ -3993,7 +4000,7 @@ recov_retry: * If we are here, rfs4call has an irrecoverable error - return */ nfs4_fattr4_free(&argop[setattr_argop].nfs_argop4_u. - opsetattr.obj_attributes); + opsetattr.obj_attributes); if (verify_argop != -1) { nfs4args_verify_free(&argop[verify_argop]); verify_argop = -1; @@ -4083,7 +4090,7 @@ recov_retry: * Can free up request args and res */ nfs4_fattr4_free(&argop[setattr_argop].nfs_argop4_u. - opsetattr.obj_attributes); + opsetattr.obj_attributes); if (verify_argop != -1) { nfs4args_verify_free(&argop[verify_argop]); verify_argop = -1; @@ -4183,13 +4190,12 @@ nfs4_access(vnode_t *vp, int mode, int flags, cred_t *cr) } rp = VTOR4(vp); - if (vp->v_type == VDIR) { + if (vp->v_type == VDIR) argacc = ACCESS4_READ | ACCESS4_DELETE | ACCESS4_MODIFY | - ACCESS4_EXTEND | ACCESS4_LOOKUP; - } else { + ACCESS4_EXTEND | ACCESS4_LOOKUP; + else argacc = ACCESS4_READ | ACCESS4_MODIFY | ACCESS4_EXTEND | - ACCESS4_EXECUTE; - } + ACCESS4_EXECUTE; recov_state.rs_flags = 0; recov_state.rs_num_retry_despite_err = 0; @@ -4241,7 +4247,7 @@ recov_retry: args.array = argop; if (e.error = nfs4_start_fop(mi, vp, NULL, OH_ACCESS, - &recov_state, NULL)) { + &recov_state, NULL)) { if (ncrfree != NULL) crfree(ncrfree); return (e.error); @@ -4282,7 +4288,7 @@ recov_retry: &recov_state, needrecov); if (!e.error) (void) xdr_free(xdr_COMPOUND4res_clnt, - (caddr_t)&res); + (caddr_t)&res); goto recov_retry; } } @@ -4308,7 +4314,7 @@ recov_retry: if (do_getattr) { resop++; /* getattr res */ nfs4_attr_cache(vp, &resop->nfs_resop4_u.opgetattr.ga_res, - t, cr, FALSE, NULL); + t, cr, FALSE, NULL); } if (!e.error) { @@ -4333,7 +4339,7 @@ recov_retry: /* XXX-LP */ if (ncr != NULL) { (void) xdr_free(xdr_COMPOUND4res_clnt, - (caddr_t)&res); + (caddr_t)&res); cred = ncr; ncr = NULL; goto tryagain; @@ -4436,7 +4442,7 @@ recov_retry: NULL, OP_READLINK, NULL) == FALSE) { if (!e.error) (void) xdr_free(xdr_COMPOUND4res_clnt, - (caddr_t)&res); + (caddr_t)&res); nfs4_end_op(VTOMI4(vp), vp, NULL, &recov_state, needrecov); @@ -4535,7 +4541,7 @@ nfs4_fsync(vnode_t *vp, int syncflag, cred_t *cr) * operation while it was open, it got renamed instead. Here we * remove the renamed file. */ -static void +void nfs4_inactive(vnode_t *vp, cred_t *cr) { rnode4_t *rp; @@ -4634,7 +4640,7 @@ nfs4_inactive_otw(vnode_t *vp, cred_t *cr) #ifdef DEBUG name = fn_name(VTOSV(vp)->sv_name); NFS4_DEBUG(nfs4_client_inactive_debug, (CE_NOTE, "nfs4_inactive_otw: " - "release vnode %s", name)); + "release vnode %s", name)); kmem_free(name, MAXNAMELEN); #endif @@ -4656,8 +4662,8 @@ nfs4_inactive_otw(vnode_t *vp, cred_t *cr) } if (recov_failed) { NFS4_DEBUG(nfs4_client_recov_debug, - (CE_NOTE, "nfs4_inactive_otw: " - "close failed (recovery failure)")); + (CE_NOTE, "nfs4_inactive_otw: " + "close failed (recovery failure)")); } } } @@ -4701,7 +4707,7 @@ redo: * but we have to do this for correctness. */ if (nfs4_has_pages(vp) && - ((rp->r_flags & R4DIRTY) || rp->r_count > 0)) { + ((rp->r_flags & R4DIRTY) || rp->r_count > 0)) { ASSERT(vp->v_type != VCHR); e.error = nfs4_putpage(vp, (u_offset_t)0, 0, 0, cr); if (e.error) { @@ -4795,9 +4801,9 @@ recov_retry_remove: NULL, NULL, OP_REMOVE, NULL) == FALSE) { if (!e.error) (void) xdr_free(xdr_COMPOUND4res_clnt, - (caddr_t)&res); + (caddr_t)&res); nfs4_end_op(VTOMI4(unldvp), unldvp, NULL, - &recov_state, TRUE); + &recov_state, TRUE); goto recov_retry_remove; } } @@ -4819,9 +4825,9 @@ recov_retry_remove: * Remote file system operations having to do with directory manipulation. */ /* ARGSUSED3 */ -static int +int nfs4_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp, - int flags, vnode_t *rdir, cred_t *cr) + int flags, vnode_t *rdir, cred_t *cr) { int error; vnode_t *vp, *avp = NULL; @@ -5010,7 +5016,7 @@ nfs4lookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr, int skipdnlc) * We hit on the dnlc */ if (*vpp != DNLC_NO_VNODE || - (dvp->v_vfsp->vfs_flag & VFS_RDONLY)) { + (dvp->v_vfsp->vfs_flag & VFS_RDONLY)) { /* * But our attrs may not be valid. */ @@ -5035,7 +5041,7 @@ nfs4lookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr, int skipdnlc) *vpp = dnlc_lookup(dvp, nm); if (*vpp == NULL) return (nfs4lookupnew_otw(dvp, - nm, vpp, cr)); + nm, vpp, cr)); /* * The access cache should almost always hit @@ -5131,16 +5137,11 @@ nfs4lookupvalidate_otw(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr) args.ctag = TAG_LOOKUP_VPARENT; } else { /* - * Do not allow crossing of server mount points. The - * only visible entries in a SRVSTUB dir are . and .. - * This code handles the non-.. case. We can't even get - * this far if looking up ".". + * If dvp were a stub, it should have triggered and caused + * a mount for us to get this far. */ - if (VTOR4(dvp)->r_flags & R4SRVSTUB) { - VN_RELE(*vpp); - *vpp = NULL; - return (ENOENT); - } + ASSERT(!RP_ISSTUB(VTOR4(dvp))); + isdotdot = 0; args.ctag = TAG_LOOKUP_VALID; } @@ -5156,7 +5157,7 @@ nfs4lookupvalidate_otw(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr) recov_retry: e.error = nfs4_start_fop(mi, dvp, NULL, OH_LOOKUP, - &recov_state, NULL); + &recov_state, NULL); if (e.error) { (void) check_mnt_secinfo(mi->mi_curr_serv, nvp); VN_RELE(*vpp); @@ -5191,7 +5192,7 @@ recov_retry: /* 3. access directory */ argop[3].argop = OP_ACCESS; argop[3].nfs_argop4_u.opaccess.access = ACCESS4_READ | ACCESS4_DELETE | - ACCESS4_MODIFY | ACCESS4_EXTEND | ACCESS4_LOOKUP; + ACCESS4_MODIFY | ACCESS4_EXTEND | ACCESS4_LOOKUP; /* 4. lookup name */ if (isdotdot) { @@ -5224,13 +5225,12 @@ recov_retry: * for (PUTFH, SECINFO "..") yet. */ if (!isdotdot && res.status == NFS4ERR_WRONGSEC) { - if ((e.error = nfs4_secinfo_vnode_otw(dvp, nm, cr))) { + if ((e.error = nfs4_secinfo_vnode_otw(dvp, nm, cr))) nfs4_end_fop(mi, dvp, NULL, OH_LOOKUP, - &recov_state, FALSE); - } else { + &recov_state, FALSE); + else nfs4_end_fop(mi, dvp, NULL, OH_LOOKUP, - &recov_state, TRUE); - } + &recov_state, TRUE); (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); kmem_free(argop, argoplist_size); if (!e.error) @@ -5244,7 +5244,7 @@ recov_retry: if (nfs4_start_recovery(&e, mi, dvp, NULL, NULL, NULL, OP_LOOKUP, NULL) == FALSE) { nfs4_end_fop(mi, dvp, NULL, OH_LOOKUP, - &recov_state, TRUE); + &recov_state, TRUE); (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); kmem_free(argop, argoplist_size); @@ -5267,7 +5267,7 @@ recov_retry: */ if (e.error == 0) e.error = (res.status == NFS4ERR_MINOR_VERS_MISMATCH) ? - ENOTSUP : EIO; + ENOTSUP : EIO; VN_RELE(*vpp); *vpp = NULL; kmem_free(argop, argoplist_size); @@ -5308,8 +5308,8 @@ recov_retry: * Install new cached attributes for the directory */ nfs4_attr_cache(dvp, - &res.array[2].nfs_resop4_u.opgetattr.ga_res, - t, cr, FALSE, NULL); + &res.array[2].nfs_resop4_u.opgetattr.ga_res, + t, cr, FALSE, NULL); if (res.array[3].nfs_resop4_u.opaccess.status != NFS4_OK) { nfs4_purge_stale_fh(e.error, dvp, cr); @@ -5324,8 +5324,8 @@ recov_retry: * cache new directory access */ nfs4_access_cache(drp, - args.array[3].nfs_argop4_u.opaccess.access, - res.array[3].nfs_resop4_u.opaccess.access, cr); + args.array[3].nfs_argop4_u.opaccess.access, + res.array[3].nfs_resop4_u.opaccess.access, cr); /* * recheck VEXEC access @@ -5422,7 +5422,7 @@ recov_retry: nfs4_attr_cache(nvp, garp, t, cr, FALSE, NULL); } else { nvp = makenfs4node(sfhp, garp, dvp->v_vfsp, t, cr, - dvp, fn_get(VTOSV(dvp)->sv_name, nm)); + dvp, fn_get(VTOSV(dvp)->sv_name, nm)); /* * If v_type == VNON, then garp was NULL because * the last op in the compound failed and makenfs4node @@ -5560,13 +5560,10 @@ nfs4lookupnew_otw(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr) args.ctag = TAG_LOOKUP_PARENT; } else { /* - * Do not allow crossing of server mount points. The - * only visible entries in a SRVSTUB dir are . and .. - * This code handles the non-.. case. We can't even get - * this far if looking up ".". + * If dvp were a stub, it should have triggered and caused + * a mount for us to get this far. */ - if (VTOR4(dvp)->r_flags & R4SRVSTUB) - return (ENOENT); + ASSERT(!RP_ISSTUB(VTOR4(dvp))); isdotdot = 0; args.ctag = TAG_LOOKUP; @@ -5583,7 +5580,7 @@ nfs4lookupnew_otw(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr) recov_retry: e.error = nfs4_start_fop(mi, dvp, NULL, OH_LOOKUP, - &recov_state, NULL); + &recov_state, NULL); if (e.error) { (void) check_mnt_secinfo(mi->mi_curr_serv, nvp); return (e.error); @@ -5638,7 +5635,7 @@ recov_retry: /* 8. access directory */ argop[8].argop = OP_ACCESS; argop[8].nfs_argop4_u.opaccess.access = ACCESS4_READ | ACCESS4_DELETE | - ACCESS4_MODIFY | ACCESS4_EXTEND | ACCESS4_LOOKUP; + ACCESS4_MODIFY | ACCESS4_EXTEND | ACCESS4_LOOKUP; doqueue = 1; t = gethrtime(); @@ -5655,13 +5652,12 @@ recov_retry: * for (PUTFH, SECINFO "..") yet. */ if (!isdotdot && res.status == NFS4ERR_WRONGSEC) { - if ((e.error = nfs4_secinfo_vnode_otw(dvp, nm, cr))) { + if ((e.error = nfs4_secinfo_vnode_otw(dvp, nm, cr))) nfs4_end_fop(mi, dvp, NULL, OH_LOOKUP, - &recov_state, FALSE); - } else { + &recov_state, FALSE); + else nfs4_end_fop(mi, dvp, NULL, OH_LOOKUP, - &recov_state, TRUE); - } + &recov_state, TRUE); (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); kmem_free(argop, argoplist_size); if (!e.error) @@ -5673,7 +5669,7 @@ recov_retry: if (nfs4_start_recovery(&e, mi, dvp, NULL, NULL, NULL, OP_LOOKUP, NULL) == FALSE) { nfs4_end_fop(mi, dvp, NULL, OH_LOOKUP, - &recov_state, TRUE); + &recov_state, TRUE); (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); kmem_free(argop, argoplist_size); @@ -5696,7 +5692,7 @@ recov_retry: */ if (e.error == 0) e.error = (res.status == NFS4ERR_MINOR_VERS_MISMATCH) ? - ENOTSUP : EIO; + ENOTSUP : EIO; kmem_free(argop, argoplist_size); (void) check_mnt_secinfo(mi->mi_curr_serv, nvp); @@ -5709,7 +5705,7 @@ recov_retry: * The PUTFH and SAVEFH may have failed. */ if ((res.array[0].nfs_resop4_u.opputfh.status != NFS4_OK) || - (res.array[1].nfs_resop4_u.opsavefh.status != NFS4_OK)) { + (res.array[1].nfs_resop4_u.opsavefh.status != NFS4_OK)) { nfs4_purge_stale_fh(e.error, dvp, cr); goto exit; } @@ -5723,9 +5719,8 @@ recov_retry: /* * The lookup failed, probably no entry */ - if (e.error == ENOENT && nfs4_lookup_neg_cache) { + if (e.error == ENOENT && nfs4_lookup_neg_cache) dnlc_update(dvp, nm, DNLC_NO_VNODE); - } goto exit; } @@ -5788,8 +5783,8 @@ recov_retry: goto exit; } nfs4_attr_cache(dvp, - &res.array[7].nfs_resop4_u.opgetattr.ga_res, - t, cr, FALSE, NULL); + &res.array[7].nfs_resop4_u.opgetattr.ga_res, + t, cr, FALSE, NULL); if (res.array[8].nfs_resop4_u.opaccess.status != NFS4_OK) { nfs4_purge_stale_fh(e.error, dvp, cr); @@ -5803,8 +5798,8 @@ recov_retry: * cache new directory access */ nfs4_access_cache(drp, - args.array[8].nfs_argop4_u.opaccess.access, - res.array[8].nfs_resop4_u.opaccess.access, cr); + args.array[8].nfs_argop4_u.opaccess.access, + res.array[8].nfs_resop4_u.opaccess.access, cr); /* * recheck VEXEC access @@ -5887,7 +5882,7 @@ recov_retry: nfs4_attr_cache(nvp, garp, t, cr, FALSE, NULL); } else { nvp = makenfs4node(sfhp, garp, dvp->v_vfsp, t, cr, - dvp, fn_get(VTOSV(dvp)->sv_name, nm)); + dvp, fn_get(VTOSV(dvp)->sv_name, nm)); } sfh4_rele(&sfhp); @@ -6038,15 +6033,15 @@ nfs4lookup_setup(char *nm, lookup4_param_t *lookupargp, int needgetfh) * Find n = number of components - nm must be null terminated * Skip "." components. */ - if (*nm != '\0') { + if (*nm != '\0') for (n = 1, s = nm; *s != '\0'; s++) { if ((*s == '/') && (*(s + 1) != '/') && - (*(s + 1) != '\0') && - !(*(s + 1) == '.' && (*(s + 2) == '/' || - *(s + 2) == '\0'))) + (*(s + 1) != '\0') && + !(*(s + 1) == '.' && (*(s + 2) == '/' || + *(s + 2) == '\0'))) n++; } - } else + else n = 0; /* @@ -6101,7 +6096,9 @@ nfs4lookup_setup(char *nm, lookup4_param_t *lookupargp, int needgetfh) s++; if (*s == '\0') break; - for (p = s; (*p != '/') && (*p != '\0'); p++); + + for (p = s; (*p != '/') && (*p != '\0'); p++) + ; c = *p; *p = '\0'; @@ -6119,9 +6116,9 @@ nfs4lookup_setup(char *nm, lookup4_param_t *lookupargp, int needgetfh) /* getattr */ argop->argop = OP_GETATTR; argop->nfs_argop4_u.opgetattr.attr_request = - lookupargp->ga_bits; + lookupargp->ga_bits; argop->nfs_argop4_u.opgetattr.mi = - lookupargp->mi; + lookupargp->mi; argop++; argcnt++; @@ -6142,9 +6139,9 @@ nfs4lookup_setup(char *nm, lookup4_param_t *lookupargp, int needgetfh) /* getattr */ argop->argop = OP_GETATTR; argop->nfs_argop4_u.opgetattr.attr_request = - lookupargp->ga_bits; + lookupargp->ga_bits; argop->nfs_argop4_u.opgetattr.mi = - lookupargp->mi; + lookupargp->mi; argop++; argcnt++; *p = c; @@ -6156,7 +6153,7 @@ nfs4lookup_setup(char *nm, lookup4_param_t *lookupargp, int needgetfh) /* lookup */ argop->argop = OP_LOOKUP; (void) str_to_utf8(s, - &argop->nfs_argop4_u.oplookup.objname); + &argop->nfs_argop4_u.oplookup.objname); } lookup_idx = argcnt; argop++; @@ -6173,16 +6170,16 @@ nfs4lookup_setup(char *nm, lookup4_param_t *lookupargp, int needgetfh) /* getattr */ argop->argop = OP_GETATTR; argop->nfs_argop4_u.opgetattr.attr_request = - lookupargp->ga_bits; + lookupargp->ga_bits; argop->nfs_argop4_u.opgetattr.mi = - lookupargp->mi; + lookupargp->mi; argop++; argcnt++; } } if ((l4_getattrs != LKP4_NO_ATTRIBUTES) && - ((l4_getattrs != LKP4_ALL_ATTRIBUTES) || (lookup_idx < 0))) { + ((l4_getattrs != LKP4_ALL_ATTRIBUTES) || (lookup_idx < 0))) { if (needgetfh) { /* stick in a post-lookup getfh */ argop->argop = OP_GETFH; @@ -6192,7 +6189,7 @@ nfs4lookup_setup(char *nm, lookup4_param_t *lookupargp, int needgetfh) /* post-lookup getattr */ argop->argop = OP_GETATTR; argop->nfs_argop4_u.opgetattr.attr_request = - lookupargp->ga_bits; + lookupargp->ga_bits; argop->nfs_argop4_u.opgetattr.mi = lookupargp->mi; argcnt++; } @@ -6276,8 +6273,8 @@ recov_retry: "nfs4openattr: initiating recovery\n")); abort = nfs4_start_recovery(&e, - VTOMI4(dvp), dvp, NULL, NULL, NULL, - OP_OPENATTR, NULL); + VTOMI4(dvp), dvp, NULL, NULL, NULL, + OP_OPENATTR, NULL); nfs4_end_op(VTOMI4(dvp), dvp, NULL, &recov_state, needrecov); if (!e.error) { e.error = geterrno4(res.status); @@ -6317,7 +6314,7 @@ recov_retry: if (e.error) { (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); nfs4_end_op(VTOMI4(dvp), dvp, NULL, &recov_state, - needrecov); + needrecov); return (e.error); } } @@ -6339,8 +6336,8 @@ recov_retry: sfhp = sfh4_get(&gf_res->object, VTOMI4(dvp)); vp = makenfs4node(sfhp, &res.array[3].nfs_resop4_u.opgetattr.ga_res, - dvp->v_vfsp, t, cr, dvp, - fn_get(VTOSV(dvp)->sv_name, XATTR_RPATH)); + dvp->v_vfsp, t, cr, dvp, + fn_get(VTOSV(dvp)->sv_name, XATTR_RPATH)); sfh4_rele(&sfhp); if (e.error) @@ -6378,7 +6375,7 @@ recov_retry: /* ARGSUSED */ static int nfs4_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive, - int mode, vnode_t **vpp, cred_t *cr, int flags) + int mode, vnode_t **vpp, cred_t *cr, int flags) { int error; vnode_t *vp = NULL; @@ -6490,7 +6487,7 @@ top: if (must_trunc) { vattr.va_mask = AT_SIZE; error = nfs4setattr(vp, &vattr, 0, cr, - NULL); + NULL); } else { /* * we know we have a regular file that already @@ -6503,7 +6500,7 @@ top: rp->r_count > 0 || rp->r_mapcnt > 0)) { error = nfs4_putpage(vp, - (offset_t)0, 0, 0, cr); + (offset_t)0, 0, 0, cr); if (error && (error == ENOSPC || error == EDQUOT)) { mutex_enter( @@ -6516,7 +6513,7 @@ top: } } vattr.va_mask = (AT_SIZE | - AT_TYPE | AT_MODE); + AT_TYPE | AT_MODE); vattr.va_type = VREG; createmode = UNCHECKED4; truncating = 1; @@ -6584,7 +6581,7 @@ create_otw: /* if create was successful, throw away the file's pages */ if (!error && (vattr.va_mask & AT_SIZE)) nfs4_invalidate_pages(vp, (vattr.va_size & PAGEMASK), - cr); + cr); /* release the lookup hold */ VN_RELE(vp); vp = NULL; @@ -6658,7 +6655,7 @@ create_otw: */ static int call_nfs4_create_req(vnode_t *dvp, char *nm, void *data, struct vattr *va, - vnode_t **vpp, cred_t *cr, nfs_ftype4 type) + vnode_t **vpp, cred_t *cr, nfs_ftype4 type) { int need_end_op = FALSE; COMPOUND4args_clnt args; @@ -6684,7 +6681,7 @@ call_nfs4_create_req(vnode_t *dvp, char *nm, void *data, struct vattr *va, bitmap4 supp_attrs; ASSERT(type == NF4DIR || type == NF4LNK || type == NF4BLK || - type == NF4CHR || type == NF4SOCK || type == NF4FIFO); + type == NF4CHR || type == NF4SOCK || type == NF4FIFO); mi = VTOMI4(dvp); @@ -6781,12 +6778,12 @@ recov_retry: */ ASSERT(data != NULL); argop[idx_create].nfs_argop4_u.opccreate.ftype4_u.clinkdata = - (char *)data; + (char *)data; } if (type == NF4BLK || type == NF4CHR) { ASSERT(data != NULL); argop[idx_create].nfs_argop4_u.opccreate.ftype4_u.devdata = - *((specdata4 *)data); + *((specdata4 *)data); } crattr = &argop[idx_create].nfs_argop4_u.opccreate.createattrs; @@ -6890,7 +6887,7 @@ recov_retry: if (nfs4_start_recovery(&e, mi, dvp, NULL, NULL, NULL, OP_CREATE, NULL) == FALSE) { nfs4_end_op(mi, dvp, NULL, &recov_state, - needrecov); + needrecov); need_end_op = FALSE; nfs4_fattr4_free(crattr); if (setgid_flag) { @@ -6957,7 +6954,7 @@ recov_retry: * potential nfs4_start_op deadlock. See RFE 4777612. */ nfs4_end_op(mi, dvp, NULL, &recov_state, - needrecov); + needrecov); need_end_op = FALSE; e.error = nfs4getattr(vp, &vattr, cr); if (e.error) { @@ -6970,9 +6967,9 @@ recov_retry: e.error = 0; } else { *vpp = vp = makenfs4node(sfhp, - &res.array[idx_fattr].nfs_resop4_u.opgetattr.ga_res, - dvp->v_vfsp, t, cr, - dvp, fn_get(VTOSV(dvp)->sv_name, nm)); + &res.array[idx_fattr].nfs_resop4_u.opgetattr.ga_res, + dvp->v_vfsp, t, cr, + dvp, fn_get(VTOSV(dvp)->sv_name, nm)); } /* @@ -7010,7 +7007,7 @@ out: /* ARGSUSED */ static int nfs4mknod(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive, - int mode, vnode_t **vpp, cred_t *cr) + int mode, vnode_t **vpp, cred_t *cr) { int error; vnode_t *vp; @@ -7249,9 +7246,9 @@ recov_retry: NULL, NULL, NULL, OP_REMOVE, NULL) == FALSE) { if (!e.error) (void) xdr_free(xdr_COMPOUND4res_clnt, - (caddr_t)&res); + (caddr_t)&res); nfs4_end_op(VTOMI4(dvp), dvp, NULL, &recov_state, - needrecov); + needrecov); goto recov_retry; } } @@ -7277,12 +7274,12 @@ recov_retry: rm_res = &resop->nfs_resop4_u.opremove; dinfo.di_garp = - &res.array[2].nfs_resop4_u.opgetattr.ga_res; + &res.array[2].nfs_resop4_u.opgetattr.ga_res; dinfo.di_cred = cr; /* Update directory attr, readdir and dnlc caches */ nfs4_update_dircaches(&rm_res->cinfo, dvp, NULL, NULL, - &dinfo); + &dinfo); } } nfs_rw_exit(&drp->r_rwlock); @@ -7418,21 +7415,21 @@ recov_retry: bool_t abort; abort = nfs4_start_recovery(&e, VTOMI4(svp), svp, tdvp, - NULL, NULL, OP_LINK, NULL); + NULL, NULL, OP_LINK, NULL); if (abort == FALSE) { nfs4_end_op(VTOMI4(svp), svp, tdvp, &recov_state, - needrecov); + needrecov); kmem_free(argop, argoplist_size); if (!e.error) (void) xdr_free(xdr_COMPOUND4res_clnt, - (caddr_t)&res); + (caddr_t)&res); goto recov_retry; } else { if (e.error != 0) { PURGE_ATTRCACHE4(tdvp); PURGE_ATTRCACHE4(svp); nfs4_end_op(VTOMI4(svp), svp, tdvp, - &recov_state, needrecov); + &recov_state, needrecov); goto out; } /* fall through for res.status case */ @@ -7482,11 +7479,10 @@ recov_retry: */ resop = &res.array[3]; /* link res */ ln_res = &resop->nfs_resop4_u.oplink; - if (res.status == NFS4_OK) { + if (res.status == NFS4_OK) e.error = nfs4_update_attrcache(res.status, - &res.array[6].nfs_resop4_u.opgetattr.ga_res, - t, svp, cr); - } + &res.array[6].nfs_resop4_u.opgetattr.ga_res, + t, svp, cr); /* * Call makenfs4node to create the new shadow vp for tnm. @@ -7495,7 +7491,7 @@ recov_retry: * to create the new shadow vnode. */ nvp = makenfs4node(VTOR4(svp)->r_fh, NULL, tdvp->v_vfsp, t, cr, - tdvp, fn_get(VTOSV(tdvp)->sv_name, tnm)); + tdvp, fn_get(VTOSV(tdvp)->sv_name, tnm)); /* Update target cache attribute, readdir and dnlc caches */ dinfo.di_garp = &res.array[4].nfs_resop4_u.opgetattr.ga_res; @@ -7570,11 +7566,11 @@ nfs4rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr) ASSERT(nfs4_consistent_type(ndvp)); if (onm[0] == '.' && (onm[1] == '\0' || - (onm[1] == '.' && onm[2] == '\0'))) + (onm[1] == '.' && onm[2] == '\0'))) return (EINVAL); if (nnm[0] == '.' && (nnm[1] == '\0' || - (nnm[1] == '.' && nnm[2] == '\0'))) + (nnm[1] == '.' && nnm[2] == '\0'))) return (EINVAL); odrp = VTOR4(odvp); @@ -7825,13 +7821,13 @@ link_call: * that are open with that flag on. (XXX) */ mi = VTOMI4(odvp); - if (NFS4_VOLATILE_FH(mi)) { + if (NFS4_VOLATILE_FH(mi)) error = nfs4rename_volatile_fh(odvp, onm, ovp, ndvp, nnm, cr, - &stat); - } else { + &stat); + else error = nfs4rename_persistent_fh(odvp, onm, ovp, ndvp, nnm, cr, - &stat); - } + &stat); + ASSERT(nfs4_consistent_type(odvp)); ASSERT(nfs4_consistent_type(ndvp)); ASSERT(nfs4_consistent_type(ovp)); @@ -7975,7 +7971,7 @@ link_call: */ static int nfs4rename_persistent_fh(vnode_t *odvp, char *onm, vnode_t *renvp, - vnode_t *ndvp, char *nnm, cred_t *cr, nfsstat4 *statp) + vnode_t *ndvp, char *nnm, cred_t *cr, nfsstat4 *statp) { COMPOUND4args_clnt args; COMPOUND4res_clnt res, *resp = NULL; @@ -8072,7 +8068,7 @@ recov_retry: nfs4_end_op(mi, odvp, ndvp, &recov_state, needrecov); if (!e.error) (void) xdr_free(xdr_COMPOUND4res_clnt, - (caddr_t)&res); + (caddr_t)&res); goto recov_retry; } } @@ -8112,7 +8108,7 @@ recov_retry: dinfop = NULL; nfs4_update_dircaches(&rn_res->target_cinfo, - ndvp, NULL, NULL, dinfop); + ndvp, NULL, NULL, dinfop); /* * Update source attribute, readdir and dnlc caches @@ -8125,11 +8121,11 @@ recov_retry: opgetattr.ga_res); nfs4_update_dircaches(&rn_res->source_cinfo, - odvp, NULL, NULL, dinfop); + odvp, NULL, NULL, dinfop); } fn_move(VTOSV(renvp)->sv_name, VTOSV(ndvp)->sv_name, - nnm); + nnm); } } @@ -8163,7 +8159,7 @@ recov_retry: */ static int nfs4rename_volatile_fh(vnode_t *odvp, char *onm, vnode_t *ovp, - vnode_t *ndvp, char *nnm, cred_t *cr, nfsstat4 *statp) + vnode_t *ndvp, char *nnm, cred_t *cr, nfsstat4 *statp) { COMPOUND4args_clnt args; COMPOUND4res_clnt res, *resp = NULL; @@ -8234,7 +8230,7 @@ recov_retry: args.array = argop; e.error = nfs4_start_fop(mi, odvp, ndvp, OH_VFH_RENAME, - &recov_state, NULL); + &recov_state, NULL); if (e.error) { kmem_free(argop, argoplist_size); mutex_enter(&orp->r_statelock); @@ -8312,7 +8308,7 @@ recov_retry: PURGE_ATTRCACHE4(ndvp); if (!needrecov) { nfs4_end_fop(mi, odvp, ndvp, OH_VFH_RENAME, - &recov_state, needrecov); + &recov_state, needrecov); goto out; } } else { @@ -8323,14 +8319,14 @@ recov_retry: bool_t abort; abort = nfs4_start_recovery(&e, mi, odvp, ndvp, NULL, NULL, - OP_RENAME, NULL); + OP_RENAME, NULL); if (abort == FALSE) { nfs4_end_fop(mi, odvp, ndvp, OH_VFH_RENAME, - &recov_state, needrecov); + &recov_state, needrecov); kmem_free(argop, argoplist_size); if (!e.error) (void) xdr_free(xdr_COMPOUND4res_clnt, - (caddr_t)&res); + (caddr_t)&res); mutex_enter(&orp->r_statelock); orp->r_flags &= ~R4RECEXPFH; cv_broadcast(&orp->r_cv); @@ -8339,7 +8335,7 @@ recov_retry: } else { if (e.error != 0) { nfs4_end_fop(mi, odvp, ndvp, OH_VFH_RENAME, - &recov_state, needrecov); + &recov_state, needrecov); goto out; } /* fall through for res.status case */ @@ -8367,7 +8363,7 @@ recov_retry: if (e.error == ENOTEMPTY) e.error = EEXIST; nfs4_end_fop(mi, odvp, ndvp, OH_VFH_RENAME, &recov_state, - needrecov); + needrecov); goto out; } @@ -8377,7 +8373,7 @@ recov_retry: if (res.status == NFS4_OK) { /* Update target attribute, readdir and dnlc caches */ dinfo.di_garp = - &res.array[6].nfs_resop4_u.opgetattr.ga_res; + &res.array[6].nfs_resop4_u.opgetattr.ga_res; dinfo.di_cred = cr; dinfo.di_time_call = t; } else @@ -8396,9 +8392,9 @@ recov_retry: */ if (dinfop) dinfo.di_garp = - &res.array[11].nfs_resop4_u.opgetattr.ga_res; + &res.array[11].nfs_resop4_u.opgetattr.ga_res; nfs4_update_dircaches(&rn_res->source_cinfo, odvp, NULL, NULL, - dinfop); + dinfop); } /* @@ -8420,8 +8416,8 @@ recov_retry: if (res.status == NFS4_OK) { resop++; /* getattr res */ e.error = nfs4_update_attrcache(res.status, - &resop->nfs_resop4_u.opgetattr.ga_res, - t, ovp, cr); + &resop->nfs_resop4_u.opgetattr.ga_res, + t, ovp, cr); } out: @@ -8599,7 +8595,7 @@ recov_retry: NULL, OP_REMOVE, NULL) == FALSE) { if (!e.error) (void) xdr_free(xdr_COMPOUND4res_clnt, - (caddr_t)&res); + (caddr_t)&res); nfs4_end_op(VTOMI4(dvp), dvp, NULL, &recov_state, needrecov); @@ -8619,7 +8615,7 @@ recov_retry: e.error = geterrno4(res.status); PURGE_ATTRCACHE4(dvp); nfs4_end_op(VTOMI4(dvp), dvp, NULL, - &recov_state, needrecov); + &recov_state, needrecov); need_end_op = FALSE; nfs4_purge_stale_fh(e.error, dvp, cr); /* @@ -8637,7 +8633,7 @@ recov_retry: if (res.status == NFS4_OK) { resop = &res.array[2]; /* dir attrs */ dinfo.di_garp = - &resop->nfs_resop4_u.opgetattr.ga_res; + &resop->nfs_resop4_u.opgetattr.ga_res; dinfo.di_cred = cr; dinfop = &dinfo; } else @@ -8645,7 +8641,7 @@ recov_retry: /* Update dir attribute, readdir and dnlc caches */ nfs4_update_dircaches(&rm_res->cinfo, dvp, NULL, NULL, - dinfop); + dinfop); /* destroy rddir cache for dir that was removed */ if (VTOR4(vp)->r_dir != NULL) @@ -8691,9 +8687,8 @@ nfs4_symlink(vnode_t *dvp, char *lnm, struct vattr *tva, char *tnm, cred_t *cr) return (EOPNOTSUPP); error = call_nfs4_create_req(dvp, lnm, tnm, tva, &vp, cr, NF4LNK); - if (error) { + if (error) return (error); - } ASSERT(nfs4_consistent_type(vp)); rp = VTOR4(vp); @@ -8954,57 +8949,6 @@ do_nfs4readdir(vnode_t *vp, rddir4_cache *rdc, cred_t *cr) return (error); } -static void -nfs4readdir_stub(vnode_t *vp, rddir4_cache *rdc, cred_t *cr) -{ - int stublength; - dirent64_t *dp; - u_longlong_t nodeid, pnodeid; - vnode_t *dotdotvp = NULL; - rnode4_t *rp = VTOR4(vp); - nfs_cookie4 cookie = (nfs_cookie4)rdc->nfs4_cookie; - - rdc->error = 0; - rdc->entries = 0; - rdc->actlen = rdc->entlen = 0; - rdc->eof = TRUE; - - /* Check for EOF case for readdir of stub */ - if (cookie != 0 && cookie != 1) - return; - - nodeid = rp->r_attr.va_nodeid; - if (vp->v_flag & VROOT) { - pnodeid = nodeid; /* root of mount point */ - } else { - if (rdc->error = nfs4_lookup(vp, "..", &dotdotvp, 0, 0, 0, cr)) - return; - pnodeid = VTOR4(dotdotvp)->r_attr.va_nodeid; - VN_RELE(dotdotvp); - } - - stublength = DIRENT64_RECLEN(1) + DIRENT64_RECLEN(2); - rdc->entries = kmem_alloc(stublength, KM_SLEEP); - rdc->entlen = rdc->buflen = stublength; - rdc->eof = TRUE; - - dp = (dirent64_t *)rdc->entries; - - if (rdc->nfs4_cookie == (nfs_cookie4)0) { - bcopy(nfs4_dot_entries, rdc->entries, - DIRENT64_RECLEN(1) + DIRENT64_RECLEN(2)); - dp->d_ino = nodeid; - dp = (struct dirent64 *)(((char *)dp) + DIRENT64_RECLEN(1)); - dp->d_ino = pnodeid; - rdc->actlen = DIRENT64_RECLEN(1) + DIRENT64_RECLEN(2); - } else { /* for ".." entry */ - bcopy(nfs4_dot_dot_entry, rdc->entries, DIRENT64_RECLEN(2)); - dp->d_ino = pnodeid; - rdc->actlen = DIRENT64_RECLEN(2); - } - rdc->nfs4_ncookie = rdc->actlen; -} - /* * Read directory entries. * There are some weird things to look out for here. The uio_loffset @@ -9050,10 +8994,11 @@ nfs4readdir(vnode_t *vp, rddir4_cache *rdc, cred_t *cr) ASSERT(rdc->flags & RDDIR); ASSERT(rdc->entries == NULL); - if (rp->r_flags & R4SRVSTUB) { - nfs4readdir_stub(vp, rdc, cr); - return; - } + /* + * If rp were a stub, it should have triggered and caused + * a mount for us to get this far. + */ + ASSERT(!RP_ISSTUB(rp)); num_ops = 2; if (cookie == (nfs_cookie4)0 || cookie == (nfs_cookie4)1) { @@ -9099,7 +9044,7 @@ recov_retry: args.array_len = num_ops; if (e.error = nfs4_start_fop(VTOMI4(vp), vp, NULL, OH_READDIR, - &recov_state, NULL)) { + &recov_state, NULL)) { /* * If readdir a node that is a stub for a crossed mount point, * keep the original secinfo flavor for the current file @@ -9121,8 +9066,8 @@ recov_retry: * Get all vattr attrs plus filehandle and rdattr_error */ rd_bitsval = NFS4_VATTR_MASK | - FATTR4_RDATTR_ERROR_MASK | - FATTR4_FILEHANDLE_MASK; + FATTR4_RDATTR_ERROR_MASK | + FATTR4_FILEHANDLE_MASK; if (rp->r_flags & R4READDIRWATTR) { mutex_enter(&rp->r_statelock); @@ -9240,13 +9185,13 @@ recov_retry: "nfs4readdir: initiating recovery.\n")); abort = nfs4_start_recovery(&e, VTOMI4(vp), vp, NULL, NULL, - NULL, OP_READDIR, NULL); + NULL, OP_READDIR, NULL); if (abort == FALSE) { nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_READDIR, - &recov_state, needrecov); + &recov_state, needrecov); if (!e.error) (void) xdr_free(xdr_COMPOUND4res_clnt, - (caddr_t)&res); + (caddr_t)&res); if (rdc->entries != NULL) { kmem_free(rdc->entries, rdc->entlen); rdc->entries = NULL; @@ -9357,7 +9302,7 @@ recov_retry: */ if (garp->n4g_va.va_mask & AT_NODEID) rd_res->dotdotp->d_ino = - garp->n4g_va.va_nodeid; + garp->n4g_va.va_nodeid; /* @@ -9417,11 +9362,10 @@ nfs4_bio(struct buf *bp, stable_how4 *stab_comm, cred_t *cr, bool_t readahead) * Puts a hold on the cred_otw and the new osp (if found). */ cred_otw = nfs4_get_otw_cred_by_osp(rp, cr, &osp, - &first_time, &last_time); + &first_time, &last_time); error = bp->b_error = nfs4read(bp->b_vp, bp->b_un.b_addr, - offset, bp->b_bcount, - &bp->b_resid, cred_otw, - readahead, NULL); + offset, bp->b_bcount, &bp->b_resid, cred_otw, + readahead, NULL); crfree(cred_otw); if (!error) { if (bp->b_resid) { @@ -9449,14 +9393,14 @@ nfs4_bio(struct buf *bp, stable_how4 *stab_comm, cred_t *cr, bool_t readahead) } } else { if (!(rp->r_flags & R4STALE)) { - write_again: +write_again: /* * Releases the osp, if it is provided. * Puts a hold on the cred_otw and the new * osp (if found). */ cred_otw = nfs4_get_otw_cred_by_osp(rp, cr, &osp, - &first_time, &last_time); + &first_time, &last_time); mutex_enter(&rp->r_statelock); count = MIN(bp->b_bcount, rp->r_size - offset); mutex_exit(&rp->r_statelock); @@ -9538,14 +9482,14 @@ nfs4_bio(struct buf *bp, stable_how4 *stab_comm, cred_t *cr, bool_t readahead) } /* ARGSUSED */ -static int +int nfs4_fid(vnode_t *vp, fid_t *fidp) { return (EREMOTE); } /* ARGSUSED2 */ -static int +int nfs4_rwlock(vnode_t *vp, int write_lock, caller_context_t *ctp) { rnode4_t *rp = VTOR4(vp); @@ -9568,7 +9512,7 @@ nfs4_rwlock(vnode_t *vp, int write_lock, caller_context_t *ctp) } /* ARGSUSED */ -static void +void nfs4_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp) { rnode4_t *rp = VTOR4(vp); @@ -9601,8 +9545,8 @@ nfs4_seek(vnode_t *vp, offset_t ooff, offset_t *noffp) */ static int nfs4_getpage(vnode_t *vp, offset_t off, size_t len, uint_t *protp, - page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr, - enum seg_rw rw, cred_t *cr) + page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr, + enum seg_rw rw, cred_t *cr) { rnode4_t *rp; int error; @@ -9642,8 +9586,8 @@ retry: */ if (rw == S_CREATE) { while ((mi->mi_max_threads != 0 && - rp->r_awcount > 2 * mi->mi_max_threads) || - rp->r_gcount > 0) + rp->r_awcount > 2 * mi->mi_max_threads) || + rp->r_gcount > 0) cv_wait(&rp->r_cv, &rp->r_statelock); } @@ -9667,14 +9611,14 @@ retry: error = nfs4_getapage(vp, off, len, protp, pl, plsz, seg, addr, rw, cr); NFS4_DEBUG(nfs4_pageio_debug && error, - (CE_NOTE, "getpage error %d; off=%lld, " - "len=%lld", error, off, (u_longlong_t)len)); + (CE_NOTE, "getpage error %d; off=%lld, " + "len=%lld", error, off, (u_longlong_t)len)); } else { error = pvn_getpages(nfs4_getapage, vp, off, len, protp, pl, plsz, seg, addr, rw, cr); NFS4_DEBUG(nfs4_pageio_debug && error, - (CE_NOTE, "getpages error %d; off=%lld, " - "len=%lld", error, off, (u_longlong_t)len)); + (CE_NOTE, "getpages error %d; off=%lld, " + "len=%lld", error, off, (u_longlong_t)len)); } switch (error) { @@ -9694,8 +9638,8 @@ retry: /* ARGSUSED */ static int nfs4_getapage(vnode_t *vp, u_offset_t off, size_t len, uint_t *protp, - page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr, - enum seg_rw rw, cred_t *cr) + page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr, + enum seg_rw rw, cred_t *cr) { rnode4_t *rp; uint_t bsize; @@ -9760,8 +9704,8 @@ reread: else if (blkoff == rp->r_nextr) readahead = nfs4_nra; else if (rp->r_nextr > blkoff && - ((ra_window = (rp->r_nextr - blkoff) / bsize) - <= (nfs4_nra - 1))) + ((ra_window = (rp->r_nextr - blkoff) / bsize) + <= (nfs4_nra - 1))) readahead = nfs4_nra - ra_window; else readahead = 0; @@ -9833,7 +9777,7 @@ again: } else blksize = rp->r_size - blkoff; } else if ((off == 0) || - (off != rp->r_nextr && !readahead_issued)) { + (off != rp->r_nextr && !readahead_issued)) { blksize = PAGESIZE; blkoff = off; /* block = page here */ } else @@ -9963,7 +9907,7 @@ out: static void nfs4_readahead(vnode_t *vp, u_offset_t blkoff, caddr_t addr, struct seg *seg, - cred_t *cr) + cred_t *cr) { int error; page_t *pp; @@ -10120,7 +10064,7 @@ nfs4_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr) */ int nfs4_putapage(vnode_t *vp, page_t *pp, u_offset_t *offp, size_t *lenp, - int flags, cred_t *cr) + int flags, cred_t *cr) { u_offset_t io_off; u_offset_t lbn_off; @@ -10242,7 +10186,7 @@ nfs4_putapage(vnode_t *vp, page_t *pp, u_offset_t *offp, size_t *lenp, static int nfs4_sync_putapage(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len, - int flags, cred_t *cr) + int flags, cred_t *cr) { int error; rnode4_t *rp; @@ -10297,7 +10241,7 @@ nfs4_sync_putapage(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len, pvn_write_done(pp, flags); if (freemem < desfree) (void) nfs4_commit_vp(vp, (u_offset_t)0, 0, cr, - NFS4_WRITE_NOWAIT); + NFS4_WRITE_NOWAIT); } return (error); @@ -10309,7 +10253,7 @@ int nfs4_force_open_before_mmap = 0; static int nfs4_map(vnode_t *vp, offset_t off, struct as *as, caddr_t *addrp, - size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr) + size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr) { struct segvn_crargs vn_a; int error = 0; @@ -10526,7 +10470,7 @@ open_and_get_osp(vnode_t *map_vp, cred_t *cr, nfs4_open_stream_t **ospp) VN_HOLD(map_vp); error = nfs4open_otw(dvp, file_name, NULL, &open_vp, cr, 0, FREAD, 0, - just_created); + just_created); if (error) { nfs_rw_exit(&drp->r_rwlock); VN_RELE(dvp); @@ -10551,7 +10495,7 @@ open_and_get_osp(vnode_t *map_vp, cred_t *cr, nfs4_open_stream_t **ospp) * and let VOP_INACTIVE handle it. */ (void) nfs4close_one(open_vp, NULL, cr, FREAD, NULL, &e, - CLOSE_NORM, 0, 0, 0); + CLOSE_NORM, 0, 0, 0); VN_RELE(map_vp); return (EIO); } @@ -10569,7 +10513,7 @@ open_and_get_osp(vnode_t *map_vp, cred_t *cr, nfs4_open_stream_t **ospp) * and let VOP_INACTIVE handle it. */ (void) nfs4close_one(open_vp, NULL, cr, FREAD, NULL, &e, - CLOSE_NORM, 0, 0, 0); + CLOSE_NORM, 0, 0, 0); return (EIO); } osp = find_open_stream(oop, rp); @@ -10585,7 +10529,7 @@ open_and_get_osp(vnode_t *map_vp, cred_t *cr, nfs4_open_stream_t **ospp) /* ARGSUSED */ static int nfs4_addmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr, - size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr) + size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr) { rnode4_t *rp; int error = 0; @@ -10698,7 +10642,7 @@ nfs4_cmp(vnode_t *vp1, vnode_t *vp2) static int nfs4_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag, - offset_t offset, struct flk_callback *flk_cbp, cred_t *cr) + offset_t offset, struct flk_callback *flk_cbp, cred_t *cr) { int rc; u_offset_t start, end; @@ -10784,21 +10728,22 @@ nfs4_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag, if (cmd != F_GETLK) { mutex_enter(&rp->r_statelock); while (rp->r_count > 0) { - if (intr) { - klwp_t *lwp = ttolwp(curthread); + if (intr) { + klwp_t *lwp = ttolwp(curthread); - if (lwp != NULL) - lwp->lwp_nostop++; - if (cv_wait_sig(&rp->r_cv, &rp->r_statelock) == 0) { + if (lwp != NULL) + lwp->lwp_nostop++; + if (cv_wait_sig(&rp->r_cv, + &rp->r_statelock) == 0) { + if (lwp != NULL) + lwp->lwp_nostop--; + rc = EINTR; + break; + } if (lwp != NULL) lwp->lwp_nostop--; - rc = EINTR; - break; - } - if (lwp != NULL) - lwp->lwp_nostop--; - } else - cv_wait(&rp->r_cv, &rp->r_statelock); + } else + cv_wait(&rp->r_cv, &rp->r_statelock); } mutex_exit(&rp->r_statelock); if (rc != 0) @@ -10822,9 +10767,8 @@ nfs4_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag, * Call the lock manager to do the real work of contacting * the server and obtaining the lock. */ - nfs4frlock(NFS4_LCK_CTYPE_NORM, vp, cmd, bfp, flag, offset, - cr, &e, NULL, NULL); + cr, &e, NULL, NULL); rc = e.error; if (rc == 0) @@ -10848,7 +10792,7 @@ done: /* ARGSUSED */ static int nfs4_space(vnode_t *vp, int cmd, struct flock64 *bfp, int flag, - offset_t offset, cred_t *cr, caller_context_t *ct) + offset_t offset, cred_t *cr, caller_context_t *ct) { int error; @@ -10875,7 +10819,7 @@ nfs4_space(vnode_t *vp, int cmd, struct flock64 *bfp, int flag, } /* ARGSUSED */ -static int +int nfs4_realvp(vnode_t *vp, vnode_t **vpp) { rnode4_t *rp; @@ -10901,7 +10845,7 @@ nfs4_realvp(vnode_t *vp, vnode_t **vpp) /* ARGSUSED */ static int nfs4_delmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr, - size_t len, uint_t prot, uint_t maxprot, uint_t flags, cred_t *cr) + size_t len, uint_t prot, uint_t maxprot, uint_t flags, cred_t *cr) { int caller_found; int error; @@ -11104,7 +11048,7 @@ nfs4_delmap_callback(struct as *as, void *arg, uint_t event) if (e.error) { e.stat = puterrno4(e.error); nfs4_queue_fact(RF_DELMAP_CB_ERR, mi, e.stat, 0, - OP_COMMIT, FALSE, NULL, 0, dmapp->vp); + OP_COMMIT, FALSE, NULL, 0, dmapp->vp); dmapp->caller->error = e.error; } @@ -11167,7 +11111,7 @@ fattr4_maxfilesize_to_bits(uint64_t ll) return (l); } -static int +int nfs4_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr) { int error; @@ -11218,23 +11162,23 @@ nfs4_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr) switch (cmd) { case _PC_FILESIZEBITS: *valp = - rp->r_pathconf.pc4_filesizebits; + rp->r_pathconf.pc4_filesizebits; break; case _PC_LINK_MAX: *valp = - rp->r_pathconf.pc4_link_max; + rp->r_pathconf.pc4_link_max; break; case _PC_NAME_MAX: *valp = - rp->r_pathconf.pc4_name_max; + rp->r_pathconf.pc4_name_max; break; case _PC_CHOWN_RESTRICTED: *valp = - rp->r_pathconf.pc4_chown_restricted; + rp->r_pathconf.pc4_chown_restricted; break; case _PC_NO_TRUNC: *valp = - rp->r_pathconf.pc4_no_trunc; + rp->r_pathconf.pc4_no_trunc; break; default: error = EINVAL; @@ -11267,7 +11211,7 @@ nfs4_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr) /* interpret the max filesize */ gar.n4g_ext_res->n4g_pc4.pc4_filesizebits = - fattr4_maxfilesize_to_bits(gar.n4g_ext_res->n4g_maxfilesize); + fattr4_maxfilesize_to_bits(gar.n4g_ext_res->n4g_maxfilesize); /* Store the attributes we just received */ nfs4_attr_cache(vp, &gar, t, cr, TRUE, NULL); @@ -11304,7 +11248,7 @@ nfs4_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr) */ static int nfs4_sync_pageio(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len, - int flags, cred_t *cr) + int flags, cred_t *cr) { int error; @@ -11320,7 +11264,7 @@ nfs4_sync_pageio(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len, static int nfs4_pageio(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len, - int flags, cred_t *cr) + int flags, cred_t *cr) { int error; rnode4_t *rp; @@ -11590,7 +11534,7 @@ get_commit_cred: * Puts a hold on the cred_otw and the new osp (if found). */ cred_otw = nfs4_get_otw_cred_by_osp(rp, cr, &osp, - &first_time, &last_time); + &first_time, &last_time); args.ctag = TAG_COMMIT; recov_retry: /* @@ -11600,7 +11544,7 @@ recov_retry: args.array = argop; e.error = nfs4_start_fop(VTOMI4(vp), vp, NULL, OH_COMMIT, - &recov_state, NULL); + &recov_state, NULL); if (e.error) { crfree(cred_otw); if (osp != NULL) @@ -11623,7 +11567,7 @@ recov_retry: needrecov = nfs4_needs_recovery(&e, FALSE, mi->mi_vfsp); if (!needrecov && e.error) { nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_COMMIT, &recov_state, - needrecov); + needrecov); crfree(cred_otw); if (e.error == EACCES && last_time == FALSE) goto get_commit_cred; @@ -11636,15 +11580,15 @@ recov_retry: if (nfs4_start_recovery(&e, VTOMI4(vp), vp, NULL, NULL, NULL, OP_COMMIT, NULL) == FALSE) { nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_COMMIT, - &recov_state, needrecov); + &recov_state, needrecov); if (!e.error) (void) xdr_free(xdr_COMPOUND4res_clnt, - (caddr_t)&res); + (caddr_t)&res); goto recov_retry; } if (e.error) { nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_COMMIT, - &recov_state, needrecov); + &recov_state, needrecov); crfree(cred_otw); if (osp != NULL) open_stream_rele(osp, rp); @@ -11658,7 +11602,7 @@ recov_retry: if (e.error == EACCES && last_time == FALSE) { crfree(cred_otw); nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_COMMIT, - &recov_state, needrecov); + &recov_state, needrecov); (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); goto get_commit_cred; } @@ -11691,7 +11635,7 @@ recov_retry: mutex_exit(&rp->r_statelock); (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_COMMIT, - &recov_state, needrecov); + &recov_state, needrecov); crfree(cred_otw); if (osp != NULL) open_stream_rele(osp, rp); @@ -11836,7 +11780,7 @@ nfs4_get_commit(vnode_t *vp) (offset3)pp->p_offset + rp->r_commit.c_commlen; rp->r_commit.c_commbase = (offset3)pp->p_offset; } else if ((rp->r_commit.c_commbase + rp->r_commit.c_commlen) - <= pp->p_offset) { + <= pp->p_offset) { rp->r_commit.c_commlen = (offset3)pp->p_offset - rp->r_commit.c_commbase + PAGESIZE; } @@ -11911,7 +11855,7 @@ nfs4_get_commit_range(vnode_t *vp, u_offset_t soff, size_t len) rp->r_commit.c_commlen = PAGESIZE; } else { rp->r_commit.c_commlen = (offset3)pp->p_offset - - rp->r_commit.c_commbase + PAGESIZE; + rp->r_commit.c_commbase + PAGESIZE; } page_add(&rp->r_commit.c_pages, pp); } @@ -11999,7 +11943,7 @@ top: */ static int nfs4_commit_vp(vnode_t *vp, u_offset_t poff, size_t plen, - cred_t *cr, int wait_on_writes) + cred_t *cr, int wait_on_writes) { rnode4_t *rp; page_t *plist; @@ -12077,7 +12021,7 @@ nfs4_commit_vp(vnode_t *vp, u_offset_t poff, size_t plen, static int nfs4_sync_commit(vnode_t *vp, page_t *plist, offset3 offset, count3 count, - cred_t *cr) + cred_t *cr) { int error; page_t *pp; @@ -12115,7 +12059,7 @@ nfs4_sync_commit(vnode_t *vp, page_t *plist, offset3 offset, count3 count, static void do_nfs4_async_commit(vnode_t *vp, page_t *plist, offset3 offset, count3 count, - cred_t *cr) + cred_t *cr) { (void) nfs4_sync_commit(vp, plist, offset, count, cr); @@ -12137,10 +12081,10 @@ nfs4_setsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr) /* if we have a delegation, return it */ if (VTOR4(vp)->r_deleg_type != OPEN_DELEGATE_NONE) (void) nfs4delegreturn(VTOR4(vp), - NFS4_DR_REOPEN|NFS4_DR_PUSH); + NFS4_DR_REOPEN|NFS4_DR_PUSH); error = nfs4_is_acl_mask_valid(vsecattr->vsa_mask, - NFS4_ACL_SET); + NFS4_ACL_SET); if (error) /* EINVAL */ return (error); @@ -12169,7 +12113,7 @@ nfs4_setsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr) return (ENOSYS); } -static int +int nfs4_getsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr) { int error; @@ -12318,7 +12262,7 @@ nfs4_is_acl_mask_valid(uint_t acl_mask, nfs4_acl_op_t op) */ static int nfs4_create_getsecattr_return(vsecattr_t *filled_vsap, vsecattr_t *vsap, - uid_t uid, gid_t gid, int isdir) + uid_t uid, gid_t gid, int isdir) { int error = 0; /* Save the mask since the translators modify it. */ @@ -12437,7 +12381,7 @@ nfs4_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr) */ static int nfs4_update_attrcache(nfsstat4 status, nfs4_ga_res_t *garp, - hrtime_t t, vnode_t *vp, cred_t *cr) + hrtime_t t, vnode_t *vp, cred_t *cr) { int error = 0; @@ -12463,7 +12407,7 @@ nfs4_update_attrcache(nfsstat4 status, nfs4_ga_res_t *garp, */ static void nfs4_update_dircaches(change_info4 *cinfo, vnode_t *dvp, vnode_t *vp, char *nm, - dirattr_info_t *dinfo) + dirattr_info_t *dinfo) { rnode4_t *drp = VTOR4(dvp); @@ -12489,13 +12433,13 @@ nfs4_update_dircaches(change_info4 *cinfo, vnode_t *dvp, vnode_t *vp, char *nm, */ mutex_exit(&VTOR4(vp)->r_statev4_lock); NFS4_DEBUG(nfs4_client_state_debug, - (CE_NOTE, "nfs4_update_dircaches: " - "don't update dnlc: created_v4 flag")); + (CE_NOTE, "nfs4_update_dircaches: " + "don't update dnlc: created_v4 flag")); } } nfs4_attr_cache(dvp, dinfo->di_garp, dinfo->di_time_call, - dinfo->di_cred, FALSE, cinfo); + dinfo->di_cred, FALSE, cinfo); return; } @@ -12530,8 +12474,8 @@ nfs4_update_dircaches(change_info4 *cinfo, vnode_t *dvp, vnode_t *vp, char *nm, */ mutex_exit(&VTOR4(vp)->r_statev4_lock); NFS4_DEBUG(nfs4_client_state_debug, (CE_NOTE, - "nfs4_update_dircaches: don't" - " update dnlc: created_v4 flag")); + "nfs4_update_dircaches: don't" + " update dnlc: created_v4 flag")); } } } else { @@ -12560,8 +12504,8 @@ nfs4_update_dircaches(change_info4 *cinfo, vnode_t *dvp, vnode_t *vp, char *nm, */ void nfs4open_confirm(vnode_t *vp, seqid4 *seqid, stateid4 *stateid, cred_t *cr, - bool_t reopening_file, bool_t *retry_open, nfs4_open_owner_t *oop, - bool_t resend, nfs4_error_t *ep, int *num_bseqid_retryp) + bool_t reopening_file, bool_t *retry_open, nfs4_open_owner_t *oop, + bool_t resend, nfs4_error_t *ep, int *num_bseqid_retryp) { COMPOUND4args_clnt args; COMPOUND4res_clnt res; @@ -12622,11 +12566,11 @@ recov_retry_confirm: if (!ep->error && res.status == NFS4ERR_BAD_SEQID) bsep = nfs4_create_bseqid_entry(oop, NULL, - vp, 0, args.ctag, - open_confirm_args->seqid); + vp, 0, args.ctag, + open_confirm_args->seqid); abort = nfs4_start_recovery(ep, VTOMI4(vp), vp, - NULL, NULL, NULL, OP_OPEN_CONFIRM, bsep); + NULL, NULL, NULL, OP_OPEN_CONFIRM, bsep); if (bsep) { kmem_free(bsep, sizeof (*bsep)); if (num_bseqid_retryp && @@ -12635,11 +12579,11 @@ recov_retry_confirm: } } if ((ep->error == ETIMEDOUT || - res.status == NFS4ERR_RESOURCE) && - abort == FALSE && resend == FALSE) { + res.status == NFS4ERR_RESOURCE) && + abort == FALSE && resend == FALSE) { if (!ep->error) (void) xdr_free(xdr_COMPOUND4res_clnt, - (caddr_t)&res); + (caddr_t)&res); delay(SEC_TO_TICK(confirm_retry_sec)); goto recov_retry_confirm; @@ -12661,7 +12605,7 @@ recov_retry_confirm: resop = &res.array[1]; /* open confirm res */ bcopy(&resop->nfs_resop4_u.opopen_confirm.open_stateid, - stateid, sizeof (*stateid)); + stateid, sizeof (*stateid)); (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res); } @@ -12701,7 +12645,7 @@ nfs4_find_sysid(mntinfo4_t *mi) * Switch from RDMA knconf to original mount knconf */ return (lm_get_sysid(ORIG_KNCONF(mi), &mi->mi_curr_serv->sv_addr, - mi->mi_curr_serv->sv_hostname, NULL)); + mi->mi_curr_serv->sv_hostname, NULL)); } #ifdef DEBUG @@ -12722,7 +12666,7 @@ nfs4frlock_get_call_type(nfs4_lock_call_type_t ctype) return ("REINSTATE"); default: cmn_err(CE_PANIC, "nfs4frlock_get_call_type: got illegal " - "type %d", ctype); + "type %d", ctype); return (""); } } @@ -12762,7 +12706,7 @@ flk_to_locktype(int cmd, int l_type) */ static int nfs4frlock_validate_args(int cmd, flock64_t *flk, int flag, vnode_t *vp, - u_offset_t offset) + u_offset_t offset) { int error = 0; @@ -12818,8 +12762,8 @@ nfs4frlock_get_sysid(struct lm_sysid **lspp, vnode_t *vp, flock64_t *flk) */ static void nfs4frlock_pre_setup(clock_t *tick_delayp, nfs4_recov_state_t *recov_statep, - flock64_t *flk, short *whencep, vnode_t *vp, cred_t *search_cr, - cred_t **cred_otw) + flock64_t *flk, short *whencep, vnode_t *vp, cred_t *search_cr, + cred_t **cred_otw) { /* * set tick_delay to the base delay time. @@ -12850,9 +12794,9 @@ nfs4frlock_pre_setup(clock_t *tick_delayp, nfs4_recov_state_t *recov_statep, */ static void nfs4frlock_call_init(COMPOUND4args_clnt *argsp, COMPOUND4args_clnt **argspp, - nfs_argop4 **argopp, nfs4_op_hint_t *op_hintp, flock64_t *flk, int cmd, - bool_t *retry, bool_t *did_start_fop, COMPOUND4res_clnt **respp, - bool_t *skip_get_err, nfs4_lost_rqst_t *lost_rqstp) + nfs_argop4 **argopp, nfs4_op_hint_t *op_hintp, flock64_t *flk, int cmd, + bool_t *retry, bool_t *did_start_fop, COMPOUND4res_clnt **respp, + bool_t *skip_get_err, nfs4_lost_rqst_t *lost_rqstp) { int argoplist_size; int num_ops = 2; @@ -12887,8 +12831,8 @@ nfs4frlock_call_init(COMPOUND4args_clnt *argsp, COMPOUND4args_clnt **argspp, */ static int nfs4frlock_start_call(nfs4_lock_call_type_t ctype, vnode_t *vp, - nfs4_op_hint_t op_hint, nfs4_recov_state_t *recov_statep, - bool_t *did_start_fop, bool_t *startrecovp) + nfs4_op_hint_t op_hint, nfs4_recov_state_t *recov_statep, + bool_t *did_start_fop, bool_t *startrecovp) { int error = 0; rnode4_t *rp; @@ -12897,7 +12841,7 @@ nfs4frlock_start_call(nfs4_lock_call_type_t ctype, vnode_t *vp, if (ctype == NFS4_LCK_CTYPE_NORM) { error = nfs4_start_fop(VTOMI4(vp), vp, NULL, op_hint, - recov_statep, startrecovp); + recov_statep, startrecovp); if (error) return (error); *did_start_fop = TRUE; @@ -12927,15 +12871,15 @@ nfs4frlock_start_call(nfs4_lock_call_type_t ctype, vnode_t *vp, */ static void nfs4frlock_setup_resend_lock_args(nfs4_lost_rqst_t *resend_rqstp, - COMPOUND4args_clnt *argsp, nfs_argop4 *argop, nfs4_lock_owner_t **lopp, - nfs4_open_owner_t **oopp, nfs4_open_stream_t **ospp, - LOCK4args **lock_argsp, LOCKU4args **locku_argsp) + COMPOUND4args_clnt *argsp, nfs_argop4 *argop, nfs4_lock_owner_t **lopp, + nfs4_open_owner_t **oopp, nfs4_open_stream_t **ospp, + LOCK4args **lock_argsp, LOCKU4args **locku_argsp) { mntinfo4_t *mi = VTOMI4(resend_rqstp->lr_vp); int error; NFS4_DEBUG((nfs4_lost_rqst_debug || nfs4_client_lock_debug), - (CE_NOTE, + (CE_NOTE, "nfs4frlock_setup_resend_lock_args: have lost lock to resend")); ASSERT(resend_rqstp != NULL); ASSERT(resend_rqstp->lr_op == OP_LOCK || @@ -12966,13 +12910,13 @@ nfs4frlock_setup_resend_lock_args(nfs4_lost_rqst_t *resend_rqstp, *lock_argsp = lock_args = &argop->nfs_argop4_u.oplock; lock_args->locktype = resend_rqstp->lr_locktype; lock_args->reclaim = - (resend_rqstp->lr_ctype == NFS4_LCK_CTYPE_RECLAIM); + (resend_rqstp->lr_ctype == NFS4_LCK_CTYPE_RECLAIM); lock_args->offset = resend_rqstp->lr_flk->l_start; lock_args->length = resend_rqstp->lr_flk->l_len; if (lock_args->length == 0) lock_args->length = ~lock_args->length; nfs4_setup_lock_args(*lopp, *oopp, *ospp, - mi2clientid(mi), &lock_args->locker); + mi2clientid(mi), &lock_args->locker); switch (resend_rqstp->lr_ctype) { case NFS4_LCK_CTYPE_RESEND: @@ -13023,8 +12967,8 @@ nfs4frlock_setup_resend_lock_args(nfs4_lost_rqst_t *resend_rqstp, */ static void nfs4frlock_setup_lockt_args(nfs4_lock_call_type_t ctype, nfs_argop4 *argop, - LOCKT4args **lockt_argsp, COMPOUND4args_clnt *argsp, flock64_t *flk, - rnode4_t *rp) + LOCKT4args **lockt_argsp, COMPOUND4args_clnt *argsp, flock64_t *flk, + rnode4_t *rp) { LOCKT4args *lockt_args; @@ -13102,7 +13046,7 @@ nfs4frlock_check_deleg(vnode_t *vp, nfs4_error_t *ep, cred_t *cr, int lt) if (osp->os_failed_reopen) { NFS4_DEBUG((nfs4_open_stream_debug || - nfs4_client_lock_debug), (CE_NOTE, + nfs4_client_lock_debug), (CE_NOTE, "nfs4frlock_check_deleg: os_failed_reopen set " "for osp %p, cr %p, rp %s", (void *)osp, (void *)cr, rnode4info(rp))); @@ -13124,9 +13068,9 @@ nfs4frlock_check_deleg(vnode_t *vp, nfs4_error_t *ep, cred_t *cr, int lt) reopen_needed = osp->os_delegation || ((lt == F_RDLCK && - !(osp->os_dc_openacc & OPEN4_SHARE_ACCESS_READ)) || + !(osp->os_dc_openacc & OPEN4_SHARE_ACCESS_READ)) || (lt == F_WRLCK && - !(osp->os_dc_openacc & OPEN4_SHARE_ACCESS_WRITE))); + !(osp->os_dc_openacc & OPEN4_SHARE_ACCESS_WRITE))); mutex_exit(&osp->os_sync_lock); open_owner_rele(oop); @@ -13169,10 +13113,10 @@ nfs4frlock_check_deleg(vnode_t *vp, nfs4_error_t *ep, cred_t *cr, int lt) */ static void nfs4frlock_setup_locku_args(nfs4_lock_call_type_t ctype, nfs_argop4 *argop, - LOCKU4args **locku_argsp, flock64_t *flk, - nfs4_lock_owner_t **lopp, nfs4_error_t *ep, COMPOUND4args_clnt *argsp, - vnode_t *vp, int flag, u_offset_t offset, cred_t *cr, - bool_t *skip_get_err, bool_t *go_otwp) + LOCKU4args **locku_argsp, flock64_t *flk, + nfs4_lock_owner_t **lopp, nfs4_error_t *ep, COMPOUND4args_clnt *argsp, + vnode_t *vp, int flag, u_offset_t offset, cred_t *cr, + bool_t *skip_get_err, bool_t *go_otwp) { nfs4_lock_owner_t *lop = NULL; LOCKU4args *locku_args; @@ -13204,7 +13148,7 @@ nfs4frlock_setup_locku_args(nfs4_lock_call_type_t ctype, nfs_argop4 *argop, locku_args->locktype = READ_LT; pid = ctype == NFS4_LCK_CTYPE_NORM ? curproc->p_pidp->pid_id : - flk->l_pid; + flk->l_pid; /* * Get the lock owner stateid. If no lock owner @@ -13228,8 +13172,8 @@ nfs4frlock_setup_locku_args(nfs4_lock_call_type_t ctype, nfs_argop4 *argop, * have no lock to undo OTW. */ NFS4_DEBUG(nfs4_client_lock_debug, (CE_NOTE, - "nfs4frlock_setup_locku_args: LOCKU: no lock owner " - "(%ld) so return success", (long)pid)); + "nfs4frlock_setup_locku_args: LOCKU: no lock owner " + "(%ld) so return success", (long)pid)); if (ctype == NFS4_LCK_CTYPE_NORM) flk->l_pid = curproc->p_pid; @@ -13280,9 +13224,9 @@ nfs4frlock_setup_locku_args(nfs4_lock_call_type_t ctype, nfs_argop4 *argop, */ static void nfs4frlock_setup_lock_args(nfs4_lock_call_type_t ctype, LOCK4args **lock_argsp, - nfs4_open_owner_t **oopp, nfs4_open_stream_t **ospp, - nfs4_lock_owner_t **lopp, nfs_argop4 *argop, COMPOUND4args_clnt *argsp, - flock64_t *flk, int cmd, vnode_t *vp, cred_t *cr, nfs4_error_t *ep) + nfs4_open_owner_t **oopp, nfs4_open_stream_t **ospp, + nfs4_lock_owner_t **lopp, nfs_argop4 *argop, COMPOUND4args_clnt *argsp, + flock64_t *flk, int cmd, vnode_t *vp, cred_t *cr, nfs4_error_t *ep) { LOCK4args *lock_args; nfs4_open_owner_t *oop = NULL; @@ -13316,13 +13260,13 @@ nfs4frlock_setup_lock_args(nfs4_lock_call_type_t ctype, LOCK4args **lock_argsp, */ pid = ctype == NFS4_LCK_CTYPE_NORM ? curproc->p_pid : flk->l_pid; ep->stat = - nfs4_find_or_create_lock_owner(pid, rp, cr, &oop, &osp, &lop); + nfs4_find_or_create_lock_owner(pid, rp, cr, &oop, &osp, &lop); if (ep->stat != NFS4_OK) goto out; nfs4_setup_lock_args(lop, oop, osp, mi2clientid(VTOMI4(vp)), - &lock_args->locker); + &lock_args->locker); lock_args->offset = flk->l_start; lock_args->length = flk->l_len; @@ -13343,9 +13287,9 @@ out: */ static void nfs4frlock_save_lost_rqst(nfs4_lock_call_type_t ctype, int error, - nfs_lock_type4 locktype, nfs4_open_owner_t *oop, - nfs4_open_stream_t *osp, nfs4_lock_owner_t *lop, flock64_t *flk, - nfs4_lost_rqst_t *lost_rqstp, cred_t *cr, vnode_t *vp) + nfs_lock_type4 locktype, nfs4_open_owner_t *oop, + nfs4_open_stream_t *osp, nfs4_lock_owner_t *lop, flock64_t *flk, + nfs4_lost_rqst_t *lost_rqstp, cred_t *cr, vnode_t *vp) { bool_t unlock = (flk->l_type == F_UNLCK); @@ -13355,7 +13299,7 @@ nfs4frlock_save_lost_rqst(nfs4_lock_call_type_t ctype, int error, if (error != 0 && !unlock) { NFS4_DEBUG((nfs4_lost_rqst_debug || - nfs4_client_lock_debug), (CE_NOTE, + nfs4_client_lock_debug), (CE_NOTE, "nfs4frlock_save_lost_rqst: set lo_pending_rqsts to 1 " " for lop %p", (void *)lop)); ASSERT(lop != NULL); @@ -13379,7 +13323,7 @@ nfs4frlock_save_lost_rqst(nfs4_lock_call_type_t ctype, int error, if (error == ETIMEDOUT || error == EINTR || NFS4_FRC_UNMT_ERR(error, vp->v_vfsp)) { NFS4_DEBUG((nfs4_lost_rqst_debug || - nfs4_client_lock_debug), (CE_NOTE, + nfs4_client_lock_debug), (CE_NOTE, "nfs4frlock_save_lost_rqst: got a lost %s lock for " "lop %p oop %p osp %p", unlock ? "LOCKU" : "LOCK", (void *)lop, (void *)oop, (void *)osp)); @@ -13457,7 +13401,7 @@ nfs4frlock_check_access(vnode_t *vp, nfs4_op_hint_t op_hint, if (*did_start_fop) { nfs4_end_fop(VTOMI4(vp), vp, NULL, op_hint, recov_statep, - needrecov); + needrecov); *did_start_fop = FALSE; } ASSERT((*argspp)->array_len == 2); @@ -13506,12 +13450,12 @@ nfs4frlock_check_access(vnode_t *vp, nfs4_op_hint_t op_hint, */ static bool_t nfs4frlock_recovery(int needrecov, nfs4_error_t *ep, - COMPOUND4args_clnt **argspp, COMPOUND4res_clnt **respp, - LOCK4args *lock_args, LOCKU4args *locku_args, - nfs4_open_owner_t **oopp, nfs4_open_stream_t **ospp, - nfs4_lock_owner_t **lopp, rnode4_t *rp, vnode_t *vp, - nfs4_recov_state_t *recov_statep, nfs4_op_hint_t op_hint, - bool_t *did_start_fop, nfs4_lost_rqst_t *lost_rqstp, flock64_t *flk) + COMPOUND4args_clnt **argspp, COMPOUND4res_clnt **respp, + LOCK4args *lock_args, LOCKU4args *locku_args, + nfs4_open_owner_t **oopp, nfs4_open_stream_t **ospp, + nfs4_lock_owner_t **lopp, rnode4_t *rp, vnode_t *vp, + nfs4_recov_state_t *recov_statep, nfs4_op_hint_t op_hint, + bool_t *did_start_fop, nfs4_lost_rqst_t *lost_rqstp, flock64_t *flk) { nfs4_open_owner_t *oop = *oopp; nfs4_open_stream_t *osp = *ospp; @@ -13542,10 +13486,10 @@ nfs4frlock_recovery(int needrecov, nfs4_error_t *ep, if (lock_args) { if (lock_args->locker.new_lock_owner == TRUE) seqid = lock_args->locker.locker4_u. - open_owner.open_seqid; + open_owner.open_seqid; else seqid = lock_args->locker.locker4_u. - lock_owner.lock_seqid; + lock_owner.lock_seqid; } else if (locku_args) { seqid = locku_args->seqid; } else { @@ -13553,13 +13497,13 @@ nfs4frlock_recovery(int needrecov, nfs4_error_t *ep, } bsep = nfs4_create_bseqid_entry(oop, lop, vp, - flk->l_pid, (*argspp)->ctag, seqid); + flk->l_pid, (*argspp)->ctag, seqid); } abort = nfs4_start_recovery(ep, VTOMI4(vp), vp, NULL, NULL, - (lost_rqstp && (lost_rqstp->lr_op == OP_LOCK || - lost_rqstp->lr_op == OP_LOCKU)) ? lost_rqstp : - NULL, op, bsep); + (lost_rqstp && (lost_rqstp->lr_op == OP_LOCK || + lost_rqstp->lr_op == OP_LOCKU)) ? lost_rqstp : + NULL, op, bsep); if (bsep) kmem_free(bsep, sizeof (*bsep)); @@ -13628,8 +13572,8 @@ nfs4frlock_recovery(int needrecov, nfs4_error_t *ep, */ static void nfs4frlock_results_ok(nfs4_lock_call_type_t ctype, int cmd, flock64_t *flk, - vnode_t *vp, int flag, u_offset_t offset, - nfs4_lost_rqst_t *resend_rqstp) + vnode_t *vp, int flag, u_offset_t offset, + nfs4_lost_rqst_t *resend_rqstp) { ASSERT(nfs_zone() == VTOMI4(vp)->mi_zone); if ((cmd == F_SETLK || cmd == F_SETLKW) && @@ -13657,14 +13601,14 @@ nfs4frlock_results_ok(nfs4_lock_call_type_t ctype, int cmd, flock64_t *flk, */ static bool_t nfs4frlock_results_denied(nfs4_lock_call_type_t ctype, LOCK4args *lock_args, - LOCKT4args *lockt_args, nfs4_open_owner_t **oopp, - nfs4_open_stream_t **ospp, nfs4_lock_owner_t **lopp, int cmd, - vnode_t *vp, flock64_t *flk, nfs4_op_hint_t op_hint, - nfs4_recov_state_t *recov_statep, int needrecov, - COMPOUND4args_clnt **argspp, COMPOUND4res_clnt **respp, - clock_t *tick_delayp, short *whencep, int *errorp, - nfs_resop4 *resop, cred_t *cr, bool_t *did_start_fop, - bool_t *skip_get_err) + LOCKT4args *lockt_args, nfs4_open_owner_t **oopp, + nfs4_open_stream_t **ospp, nfs4_lock_owner_t **lopp, int cmd, + vnode_t *vp, flock64_t *flk, nfs4_op_hint_t op_hint, + nfs4_recov_state_t *recov_statep, int needrecov, + COMPOUND4args_clnt **argspp, COMPOUND4res_clnt **respp, + clock_t *tick_delayp, short *whencep, int *errorp, + nfs_resop4 *resop, cred_t *cr, bool_t *did_start_fop, + bool_t *skip_get_err) { ASSERT(nfs_zone() == VTOMI4(vp)->mi_zone); @@ -13689,7 +13633,7 @@ nfs4frlock_results_denied(nfs4_lock_call_type_t ctype, LOCK4args *lock_args, ASSERT(ctype == NFS4_LCK_CTYPE_NORM); nfs4_end_fop(VTOMI4(vp), vp, NULL, op_hint, - recov_statep, needrecov); + recov_statep, needrecov); *did_start_fop = FALSE; ASSERT((*argspp)->array_len == 2); if (argop[1].argop == OP_LOCK) @@ -13699,7 +13643,7 @@ nfs4frlock_results_denied(nfs4_lock_call_type_t ctype, LOCK4args *lock_args, kmem_free(argop, 2 * sizeof (nfs_argop4)); if (*respp) (void) xdr_free(xdr_COMPOUND4res_clnt, - (caddr_t)*respp); + (caddr_t)*respp); *argspp = NULL; *respp = NULL; nfs4_end_lock_seqid_sync(lop); @@ -13721,13 +13665,13 @@ nfs4frlock_results_denied(nfs4_lock_call_type_t ctype, LOCK4args *lock_args, if (intr) { (void) nfs_rw_enter_sig(&rp->r_lkserlock, - RW_WRITER, FALSE); + RW_WRITER, FALSE); *errorp = EINTR; return (FALSE); } (void) nfs_rw_enter_sig(&rp->r_lkserlock, - RW_WRITER, FALSE); + RW_WRITER, FALSE); /* * Make sure we are still safe to lock with @@ -13751,7 +13695,7 @@ nfs4frlock_results_denied(nfs4_lock_call_type_t ctype, LOCK4args *lock_args, "nfs4frlock_results_denied: OP_LOCKT DENIED")); denied_to_flk(&resop->nfs_resop4_u.oplockt.denied, - flk, lockt_args); + flk, lockt_args); /* according to NLM code */ *errorp = 0; @@ -13812,9 +13756,9 @@ nfs4frlock_results_default(COMPOUND4res_clnt *resp, int *errorp) */ static void nfs4frlock_update_state(LOCK4args *lock_args, LOCKU4args *locku_args, - LOCKT4args *lockt_args, nfs_resop4 *resop, nfs4_lock_owner_t *lop, - vnode_t *vp, flock64_t *flk, cred_t *cr, - nfs4_lost_rqst_t *resend_rqstp) + LOCKT4args *lockt_args, nfs_resop4 *resop, nfs4_lock_owner_t *lop, + vnode_t *vp, flock64_t *flk, cred_t *cr, + nfs4_lost_rqst_t *resend_rqstp) { ASSERT(nfs_zone() == VTOMI4(vp)->mi_zone); @@ -13870,13 +13814,13 @@ nfs4frlock_update_state(LOCK4args *lock_args, LOCKU4args *locku_args, */ static void nfs4frlock_final_cleanup(nfs4_lock_call_type_t ctype, COMPOUND4args_clnt *argsp, - COMPOUND4res_clnt *resp, vnode_t *vp, nfs4_op_hint_t op_hint, - nfs4_recov_state_t *recov_statep, int needrecov, nfs4_open_owner_t *oop, - nfs4_open_stream_t *osp, nfs4_lock_owner_t *lop, flock64_t *flk, - short whence, u_offset_t offset, struct lm_sysid *ls, - int *errorp, LOCK4args *lock_args, LOCKU4args *locku_args, - bool_t did_start_fop, bool_t skip_get_err, - cred_t *cred_otw, cred_t *cred) + COMPOUND4res_clnt *resp, vnode_t *vp, nfs4_op_hint_t op_hint, + nfs4_recov_state_t *recov_statep, int needrecov, nfs4_open_owner_t *oop, + nfs4_open_stream_t *osp, nfs4_lock_owner_t *lop, flock64_t *flk, + short whence, u_offset_t offset, struct lm_sysid *ls, + int *errorp, LOCK4args *lock_args, LOCKU4args *locku_args, + bool_t did_start_fop, bool_t skip_get_err, + cred_t *cred_otw, cred_t *cred) { mntinfo4_t *mi = VTOMI4(vp); rnode4_t *rp = VTOR4(vp); @@ -13894,9 +13838,8 @@ nfs4frlock_final_cleanup(nfs4_lock_call_type_t ctype, COMPOUND4args_clnt *argsp, *errorp = geterrno4(resp->status); if (did_start_fop == TRUE) nfs4_end_fop(mi, vp, NULL, op_hint, recov_statep, - needrecov); + needrecov); - if (!error && resp && resp->status == NFS4_OK) { /* * We've established a new lock on the server, so invalidate * the pages associated with the vnode to get the most up to @@ -13908,10 +13851,11 @@ nfs4frlock_final_cleanup(nfs4_lock_call_type_t ctype, COMPOUND4args_clnt *argsp, * nfs4_start_fop. We flush the pages below after calling * nfs4_end_fop above */ + if (!error && resp && resp->status == NFS4_OK) { int error; error = VOP_PUTPAGE(vp, (u_offset_t)0, - 0, B_INVAL, cred); + 0, B_INVAL, cred); if (error && (error == ENOSPC || error == EDQUOT)) { rnode4_t *rp = VTOR4(vp); @@ -14010,8 +13954,8 @@ nfs4frlock_final_cleanup(nfs4_lock_call_type_t ctype, COMPOUND4args_clnt *argsp, */ void nfs4frlock(nfs4_lock_call_type_t ctype, vnode_t *vp, int cmd, flock64_t *flk, - int flag, u_offset_t offset, cred_t *cr, nfs4_error_t *ep, - nfs4_lost_rqst_t *resend_rqstp, int *did_reclaimp) + int flag, u_offset_t offset, cred_t *cr, nfs4_error_t *ep, + nfs4_lost_rqst_t *resend_rqstp, int *did_reclaimp) { COMPOUND4args_clnt args, *argsp = NULL; COMPOUND4res_clnt res, *resp = NULL; @@ -14068,11 +14012,11 @@ nfs4frlock(nfs4_lock_call_type_t ctype, vnode_t *vp, int cmd, flock64_t *flk, recov_retry: nfs4frlock_call_init(&args, &argsp, &argop, &op_hint, flk, cmd, - &retry, &did_start_fop, &resp, &skip_get_err, &lost_rqst); + &retry, &did_start_fop, &resp, &skip_get_err, &lost_rqst); rp = VTOR4(vp); ep->error = nfs4frlock_start_call(ctype, vp, op_hint, &recov_state, - &did_start_fop, &recovonly); + &did_start_fop, &recovonly); if (ep->error) goto out; @@ -14090,12 +14034,12 @@ recov_retry: lop = find_lock_owner(rp, curproc->p_pid, LOWN_ANY); if (lop != NULL) { nfs4frlock_save_lost_rqst(ctype, ep->error, READ_LT, - NULL, NULL, lop, flk, &lost_rqst, cr, vp); + NULL, NULL, lop, flk, &lost_rqst, cr, vp); (void) nfs4_start_recovery(ep, - VTOMI4(vp), vp, NULL, NULL, - (lost_rqst.lr_op == OP_LOCK || - lost_rqst.lr_op == OP_LOCKU) ? - &lost_rqst : NULL, OP_LOCKU, NULL); + VTOMI4(vp), vp, NULL, NULL, + (lost_rqst.lr_op == OP_LOCK || + lost_rqst.lr_op == OP_LOCKU) ? + &lost_rqst : NULL, OP_LOCKU, NULL); lock_owner_rele(lop); lop = NULL; } @@ -14116,7 +14060,7 @@ recov_retry: if (ctype == NFS4_LCK_CTYPE_RESEND || ctype == NFS4_LCK_CTYPE_REINSTATE) { nfs4frlock_setup_resend_lock_args(resend_rqstp, argsp, - &argop[1], &lop, &oop, &osp, &lock_args, &locku_args); + &argop[1], &lop, &oop, &osp, &lock_args, &locku_args); } else { bool_t go_otw = TRUE; @@ -14126,20 +14070,20 @@ recov_retry: case F_GETLK: case F_O_GETLK: nfs4frlock_setup_lockt_args(ctype, &argop[1], - &lockt_args, argsp, flk, rp); + &lockt_args, argsp, flk, rp); break; case F_SETLKW: case F_SETLK: if (flk->l_type == F_UNLCK) nfs4frlock_setup_locku_args(ctype, - &argop[1], &locku_args, flk, - &lop, ep, argsp, - vp, flag, offset, cr, - &skip_get_err, &go_otw); + &argop[1], &locku_args, flk, + &lop, ep, argsp, + vp, flag, offset, cr, + &skip_get_err, &go_otw); else nfs4frlock_setup_lock_args(ctype, - &lock_args, &oop, &osp, &lop, &argop[1], - argsp, flk, cmd, vp, cr, ep); + &lock_args, &oop, &osp, &lop, &argop[1], + argsp, flk, cmd, vp, cr, ep); if (ep->error) goto out; @@ -14169,7 +14113,7 @@ recov_retry: break; default: NFS4_DEBUG(nfs4_client_lock_debug, (CE_NOTE, - "nfs4_frlock: invalid cmd %d", cmd)); + "nfs4_frlock: invalid cmd %d", cmd)); ep->error = EINVAL; goto out; } @@ -14264,13 +14208,13 @@ recov_retry: } nfs4frlock_save_lost_rqst(ctype, ep->error, - flk_to_locktype(cmd, flk->l_type), - oop, osp, lop, flk, &lost_rqst, cred_otw, vp); + flk_to_locktype(cmd, flk->l_type), + oop, osp, lop, flk, &lost_rqst, cred_otw, vp); retry = nfs4frlock_recovery(needrecov, ep, &argsp, - &resp, lock_args, locku_args, &oop, &osp, &lop, - rp, vp, &recov_state, op_hint, &did_start_fop, - cmd != F_GETLK ? &lost_rqst : NULL, flk); + &resp, lock_args, locku_args, &oop, &osp, &lop, + rp, vp, &recov_state, op_hint, &did_start_fop, + cmd != F_GETLK ? &lost_rqst : NULL, flk); if (retry) { ASSERT(oop == NULL); @@ -14297,21 +14241,21 @@ recov_retry: case NFS4_OK: resop = &resp->array[1]; nfs4frlock_results_ok(ctype, cmd, flk, vp, flag, offset, - resend_rqstp); + resend_rqstp); /* * Have a successful lock operation, now update state. */ nfs4frlock_update_state(lock_args, locku_args, lockt_args, - resop, lop, vp, flk, cr, resend_rqstp); + resop, lop, vp, flk, cr, resend_rqstp); break; case NFS4ERR_DENIED: resop = &resp->array[1]; retry = nfs4frlock_results_denied(ctype, lock_args, lockt_args, - &oop, &osp, &lop, cmd, vp, flk, op_hint, - &recov_state, needrecov, &argsp, &resp, - &tick_delay, &whence, &ep->error, resop, cr, - &did_start_fop, &skip_get_err); + &oop, &osp, &lop, cmd, vp, flk, op_hint, + &recov_state, needrecov, &argsp, &resp, + &tick_delay, &whence, &ep->error, resop, cr, + &did_start_fop, &skip_get_err); if (retry) { ASSERT(oop == NULL); @@ -14351,9 +14295,9 @@ out: * client recovery code. */ nfs4frlock_final_cleanup(ctype, argsp, resp, vp, op_hint, &recov_state, - needrecov, oop, osp, lop, flk, whence, offset, ls, &ep->error, - lock_args, locku_args, did_start_fop, - skip_get_err, cred_otw, cr); + needrecov, oop, osp, lop, flk, whence, offset, ls, &ep->error, + lock_args, locku_args, did_start_fop, + skip_get_err, cred_otw, cr); if (ep->error == EINTR && flk->l_type == F_UNLCK && (cmd == F_SETLK || cmd == F_SETLKW)) @@ -14377,9 +14321,9 @@ nfs4_safelock(vnode_t *vp, const struct flock64 *bfp, cred_t *cr) ASSERT(nfs_zone() == VTOMI4(vp)->mi_zone); ASSERT(rp->r_mapcnt >= 0); NFS4_DEBUG(nfs4_client_lock_debug, (CE_NOTE, "nfs4_safelock %s: " - "(%"PRIx64", %"PRIx64"); mapcnt = %ld", bfp->l_type == F_WRLCK ? - "write" : bfp->l_type == F_RDLCK ? "read" : "unlock", - bfp->l_start, bfp->l_len, rp->r_mapcnt)); + "(%"PRIx64", %"PRIx64"); mapcnt = %ld", bfp->l_type == F_WRLCK ? + "write" : bfp->l_type == F_RDLCK ? "read" : "unlock", + bfp->l_start, bfp->l_len, rp->r_mapcnt)); if (rp->r_mapcnt == 0) return (1); /* always safe if not mapped */ @@ -14393,9 +14337,9 @@ nfs4_safelock(vnode_t *vp, const struct flock64 *bfp, cred_t *cr) if (bfp->l_start != 0 || bfp->l_len != 0) { NFS4_DEBUG(nfs4_client_lock_debug, (CE_NOTE, "nfs4_safelock: " - "cannot lock a memory mapped file unless locking the " - "entire file: start %"PRIx64", len %"PRIx64, - bfp->l_start, bfp->l_len)); + "cannot lock a memory mapped file unless locking the " + "entire file: start %"PRIx64", len %"PRIx64, + bfp->l_start, bfp->l_len)); return (0); } @@ -14404,12 +14348,12 @@ nfs4_safelock(vnode_t *vp, const struct flock64 *bfp, cred_t *cr) error = VOP_GETATTR(vp, &va, 0, cr); if (error != 0) { NFS4_DEBUG(nfs4_client_lock_debug, (CE_NOTE, "nfs4_safelock: " - "getattr error %d", error)); + "getattr error %d", error)); return (0); /* treat errors conservatively */ } if (MANDLOCK(vp, va.va_mode)) { NFS4_DEBUG(nfs4_client_lock_debug, (CE_NOTE, "nfs4_safelock: " - "cannot mandatory lock and mmap a file")); + "cannot mandatory lock and mmap a file")); return (0); } @@ -14427,7 +14371,7 @@ nfs4_safelock(vnode_t *vp, const struct flock64 *bfp, cred_t *cr) */ void nfs4_register_lock_locally(vnode_t *vp, struct flock64 *flk, int flag, - u_offset_t offset) + u_offset_t offset) { int oldsysid; int error; @@ -14454,20 +14398,20 @@ nfs4_register_lock_locally(vnode_t *vp, struct flock64 *flk, int flag, #ifdef DEBUG if (error != 0) { NFS4_DEBUG(nfs4_client_lock_debug, (CE_NOTE, - "nfs4_register_lock_locally: could not register with" - " local locking")); + "nfs4_register_lock_locally: could not register with" + " local locking")); NFS4_DEBUG(nfs4_client_lock_debug, (CE_CONT, - "error %d, vp 0x%p, pid %d, sysid 0x%x", - error, (void *)vp, flk->l_pid, flk->l_sysid)); + "error %d, vp 0x%p, pid %d, sysid 0x%x", + error, (void *)vp, flk->l_pid, flk->l_sysid)); NFS4_DEBUG(nfs4_client_lock_debug, (CE_CONT, - "type %d off 0x%" PRIx64 " len 0x%" PRIx64, - flk->l_type, flk->l_start, flk->l_len)); + "type %d off 0x%" PRIx64 " len 0x%" PRIx64, + flk->l_type, flk->l_start, flk->l_len)); (void) reclock(vp, flk, 0, flag, offset, NULL); NFS4_DEBUG(nfs4_client_lock_debug, (CE_CONT, - "blocked by pid %d sysid 0x%x type %d " - "off 0x%" PRIx64 " len 0x%" PRIx64, - flk->l_pid, flk->l_sysid, flk->l_type, flk->l_start, - flk->l_len)); + "blocked by pid %d sysid 0x%x type %d " + "off 0x%" PRIx64 " len 0x%" PRIx64, + flk->l_pid, flk->l_sysid, flk->l_type, flk->l_start, + flk->l_len)); } #endif flk->l_sysid = oldsysid; @@ -14515,7 +14459,7 @@ nfs4_lockrelease(vnode_t *vp, int flag, offset_t offset, cred_t *cr) recov_state.rs_flags = 0; recov_state.rs_num_retry_despite_err = 0; error = nfs4_start_fop(mi, vp, NULL, OH_LOCKU, &recov_state, - &recovonly); + &recovonly); if (error) { mutex_enter(&rp->r_statelock); rp->r_flags |= R4LODANGLERS; @@ -14568,15 +14512,15 @@ nfs4_lockrelease(vnode_t *vp, int flag, offset_t offset, cred_t *cr) ld.l_pid = ttoproc(curthread)->p_pid; nfs4_register_lock_locally(vp, &ld, flag, offset); NFS4_DEBUG(nfs4_client_lock_debug, (CE_NOTE, - "nfs4_lockrelease: lock release error on vp" - " %p: error %d.\n", (void *)vp, ret)); + "nfs4_lockrelease: lock release error on vp" + " %p: error %d.\n", (void *)vp, ret)); } } recov_state.rs_flags = 0; recov_state.rs_num_retry_despite_err = 0; error = nfs4_start_fop(mi, vp, NULL, OH_LOCKU, &recov_state, - &recovonly); + &recovonly); if (error) { mutex_enter(&rp->r_statelock); rp->r_flags |= R4LODANGLERS; @@ -14618,8 +14562,8 @@ nfs4_block_and_wait(clock_t *tick_delay, rnode4_t *rp) return (EINTR); } NFS4_DEBUG(nfs4_client_lock_debug, (CE_NOTE, "nfs4_block_and_wait: " - "reissue the lock request: blocked for %ld clock ticks: %ld " - "milliseconds", *tick_delay, drv_hztousec(*tick_delay) / 1000)); + "reissue the lock request: blocked for %ld clock ticks: %ld " + "milliseconds", *tick_delay, drv_hztousec(*tick_delay) / 1000)); /* get the lease time */ lock_lease_time = r2lease_time(rp); @@ -14694,26 +14638,26 @@ vtodv(vnode_t *vp, vnode_t **dvpp, cred_t *cr, bool_t need_start_op) if (svnp == NULL) { NFS4_DEBUG(nfs4_client_shadow_debug, (CE_NOTE, "vtodv: " - "shadow node is NULL")); + "shadow node is NULL")); return (EINVAL); } if (svnp->sv_name == NULL || svnp->sv_dfh == NULL) { NFS4_DEBUG(nfs4_client_shadow_debug, (CE_NOTE, "vtodv: " - "shadow node name or dfh val == NULL")); + "shadow node name or dfh val == NULL")); return (EINVAL); } error = nfs4_make_dotdot(svnp->sv_dfh, 0, vp, cr, &dvp, - (int)need_start_op); + (int)need_start_op); if (error != 0) { NFS4_DEBUG(nfs4_client_shadow_debug, (CE_NOTE, "vtodv: " - "nfs4_make_dotdot returned %d", error)); + "nfs4_make_dotdot returned %d", error)); return (error); } if (!dvp) { NFS4_DEBUG(nfs4_client_shadow_debug, (CE_NOTE, "vtodv: " - "nfs4_make_dotdot returned a NULL dvp")); + "nfs4_make_dotdot returned a NULL dvp")); return (EIO); } if (dvp->v_type == VNON) @@ -14957,9 +14901,9 @@ nfs4close_all(vnode_t *vp, cred_t *cr) */ void nfs4close_one(vnode_t *vp, nfs4_open_stream_t *provided_osp, cred_t *cr, - int access_bits, nfs4_lost_rqst_t *lrp, nfs4_error_t *ep, - nfs4_close_type_t close_type, size_t len, uint_t maxprot, - uint_t mmap_flags) + int access_bits, nfs4_lost_rqst_t *lrp, nfs4_error_t *ep, + nfs4_close_type_t close_type, size_t len, uint_t maxprot, + uint_t mmap_flags) { nfs4_open_owner_t *oop; nfs4_open_stream_t *osp = NULL; @@ -14990,7 +14934,7 @@ nfs4close_one(vnode_t *vp, nfs4_open_stream_t *provided_osp, cred_t *cr, rp = VTOR4(vp); mi = VTOMI4(vp); isrecov = (close_type == CLOSE_RESEND || - close_type == CLOSE_AFTER_RESEND); + close_type == CLOSE_AFTER_RESEND); /* * First get the open owner. @@ -15031,7 +14975,7 @@ recov_retry: */ if (!isrecov) { ep->error = nfs4_start_fop(mi, vp, NULL, OH_CLOSE, - &recov_state, &recovonly); + &recov_state, &recovonly); if (!ep->error) { did_start_op = 1; } else { @@ -15044,7 +14988,7 @@ recov_retry: */ if (close_type == CLOSE_FORCE) { (void) nfs_rw_enter_sig(&mi->mi_recovlock, - RW_READER, FALSE); + RW_READER, FALSE); did_force_recovlock = 1; } else goto out; @@ -15067,7 +15011,7 @@ recov_retry: ASSERT(!isrecov); if (did_start_op) nfs4_end_fop(mi, vp, NULL, OH_CLOSE, - &recov_state, TRUE); + &recov_state, TRUE); if (did_force_recovlock) nfs_rw_exit(&mi->mi_recovlock); goto recov_retry; @@ -15177,12 +15121,12 @@ recov_retry: ASSERT(lrp == NULL); nfs4_error_init(ep, EINTR); nfs4close_save_lost_rqst(ep->error, &lost_rqst, oop, - osp, cred_otw, vp); + osp, cred_otw, vp); mutex_exit(&osp->os_sync_lock); have_sync_lock = 0; (void) nfs4_start_recovery(ep, mi, vp, NULL, NULL, - lost_rqst.lr_op == OP_CLOSE ? - &lost_rqst : NULL, OP_CLOSE, NULL); + lost_rqst.lr_op == OP_CLOSE ? + &lost_rqst : NULL, OP_CLOSE, NULL); close_failed = 1; force_close = 0; goto close_cleanup; @@ -15247,7 +15191,7 @@ recov_retry: goto out; } nfs4_open_downgrade(access_bits, 0, oop, osp, vp, cr, - lrp, ep, &odg_cred_otw, &open_dg_seqid); + lrp, ep, &odg_cred_otw, &open_dg_seqid); needrecov = nfs4_needs_recovery(ep, TRUE, mi->mi_vfsp); if (needrecov && !isrecov) { bool_t abort; @@ -15255,18 +15199,18 @@ recov_retry: if (!ep->error && ep->stat == NFS4ERR_BAD_SEQID) bsep = nfs4_create_bseqid_entry(oop, NULL, - vp, 0, - lrp ? TAG_OPEN_DG_LOST : TAG_OPEN_DG, - open_dg_seqid); + vp, 0, + lrp ? TAG_OPEN_DG_LOST : TAG_OPEN_DG, + open_dg_seqid); nfs4open_dg_save_lost_rqst(ep->error, &new_lost_rqst, oop, osp, odg_cred_otw, vp, access_bits, 0); mutex_exit(&osp->os_sync_lock); have_sync_lock = 0; abort = nfs4_start_recovery(ep, mi, vp, NULL, NULL, - new_lost_rqst.lr_op == OP_OPEN_DOWNGRADE ? - &new_lost_rqst : NULL, OP_OPEN_DOWNGRADE, - bsep); + new_lost_rqst.lr_op == OP_OPEN_DOWNGRADE ? + &new_lost_rqst : NULL, OP_OPEN_DOWNGRADE, + bsep); if (odg_cred_otw) crfree(odg_cred_otw); if (bsep) @@ -15283,7 +15227,7 @@ recov_retry: if (did_start_op) nfs4_end_fop(mi, vp, NULL, OH_CLOSE, - &recov_state, FALSE); + &recov_state, FALSE); if (did_force_recovlock) nfs_rw_exit(&mi->mi_recovlock); @@ -15394,12 +15338,12 @@ recov_retry: if (did_start_op) nfs4_end_fop(mi, vp, NULL, OH_CLOSE, - &recov_state, FALSE); + &recov_state, FALSE); if (did_force_recovlock) nfs_rw_exit(&mi->mi_recovlock); NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE, - "nfs4close_one: need to retry the close " - "operation")); + "nfs4close_one: need to retry the close " + "operation")); goto recov_retry; } close_cleanup: @@ -15496,12 +15440,12 @@ denied_to_flk(LOCK4denied *lockt_denied, flock64_t *flk, LOCKT4args *lockt_args) if (lockt_denied->owner.owner_len == sizeof (*lo)) { lo = (nfs4_lo_name_t *) - lockt_denied->owner.owner_val; + lockt_denied->owner.owner_val; flk->l_pid = lo->ln_pid; } else { NFS4_DEBUG(nfs4_client_lock_debug, (CE_NOTE, - "denied_to_flk: bad lock owner length\n")); + "denied_to_flk: bad lock owner length\n")); flk->l_pid = lo_to_pid(&lockt_denied->owner); } @@ -15601,7 +15545,7 @@ locks_intersect(flock64_t *llfp, flock64_t *curfp) curfp_end = lock_to_end(curfp); if (((llfp_end >= curfp->l_start) && - (llfp->l_start <= curfp->l_start)) || + (llfp->l_start <= curfp->l_start)) || ((curfp->l_start <= llfp->l_start) && (curfp_end >= llfp->l_start))) return (1); return (0); @@ -15613,7 +15557,7 @@ locks_intersect(flock64_t *llfp, flock64_t *curfp) */ static void nfs4_add_lock_range(flock64_t *lost_flp, flock64_t *local_flp, - locklist_t **nl_llpp, vnode_t *vp) + locklist_t **nl_llpp, vnode_t *vp) { locklist_t *intersect_llp, *tmp_fllp, *cur_fllp; off64_t lost_flp_end, local_flp_end, len, start; @@ -15660,7 +15604,7 @@ nfs4_add_lock_range(flock64_t *lost_flp, flock64_t *local_flp, tmp_fllp = *nl_llpp; cur_fllp = NULL; while (tmp_fllp != NULL && tmp_fllp->ll_flock.l_start < - intersect_llp->ll_flock.l_start) { + intersect_llp->ll_flock.l_start) { cur_fllp = tmp_fllp; tmp_fllp = tmp_fllp->ll_next; } @@ -15698,7 +15642,7 @@ nfs4_add_lock_range(flock64_t *lost_flp, flock64_t *local_flp, */ static void nfs4_reinstitute_local_lock_state(vnode_t *vp, flock64_t *lost_flp, cred_t *cr, - nfs4_lock_owner_t *lop) + nfs4_lock_owner_t *lop) { locklist_t *locks, *llp, *ri_llp, *tmp_llp; mntinfo4_t *mi = VTOMI4(vp); @@ -15707,7 +15651,7 @@ nfs4_reinstitute_local_lock_state(vnode_t *vp, flock64_t *lost_flp, cred_t *cr, flock64_t ul_fl; NFS4_DEBUG(nfs4_lost_rqst_debug, (CE_NOTE, - "nfs4_reinstitute_local_lock_state")); + "nfs4_reinstitute_local_lock_state")); /* * Find active locks for this vp from the local locking code. @@ -15785,9 +15729,9 @@ nfs4_reinstitute_local_lock_state(vnode_t *vp, flock64_t *lost_flp, cred_t *cr, continue; } NFS4_DEBUG(nfs4_lost_rqst_debug, (CE_NOTE, - "nfs4_reinstitute_local_lock_state: " - "UNLOCK [%"PRIx64" - %"PRIx64"]", - cur_start, llp->ll_flock.l_start)); + "nfs4_reinstitute_local_lock_state: " + "UNLOCK [%"PRIx64" - %"PRIx64"]", + cur_start, llp->ll_flock.l_start)); ul_fl.l_start = cur_start; ul_fl.l_len = end_to_len(cur_start, @@ -15803,9 +15747,9 @@ nfs4_reinstitute_local_lock_state(vnode_t *vp, flock64_t *lost_flp, cred_t *cr, */ if (cur_start != start_check(lost_flp_end)) { NFS4_DEBUG(nfs4_lost_rqst_debug, (CE_NOTE, - "nfs4_reinstitute_local_lock_state: UNLOCK end of the " - "lost lock region [%"PRIx64" - %"PRIx64"]", - cur_start, lost_flp->l_start + lost_flp->l_len)); + "nfs4_reinstitute_local_lock_state: UNLOCK end of the " + "lost lock region [%"PRIx64" - %"PRIx64"]", + cur_start, lost_flp->l_start + lost_flp->l_len)); ul_fl.l_start = cur_start; /* @@ -15841,7 +15785,7 @@ nfs4_reinstitute_local_lock_state(vnode_t *vp, flock64_t *lost_flp, cred_t *cr, */ static void push_reinstate(vnode_t *vp, int cmd, flock64_t *flk, cred_t *cr, - nfs4_lock_owner_t *lop) + nfs4_lock_owner_t *lop) { nfs4_lost_rqst_t req; nfs_lock_type4 locktype; @@ -15851,9 +15795,9 @@ push_reinstate(vnode_t *vp, int cmd, flock64_t *flk, cred_t *cr, locktype = flk_to_locktype(cmd, flk->l_type); nfs4frlock_save_lost_rqst(NFS4_LCK_CTYPE_REINSTATE, EINTR, locktype, - NULL, NULL, lop, flk, &req, cr, vp); + NULL, NULL, lop, flk, &req, cr, vp); (void) nfs4_start_recovery(&e, VTOMI4(vp), vp, NULL, NULL, - (req.lr_op == OP_LOCK || req.lr_op == OP_LOCKU) ? - &req : NULL, flk->l_type == F_UNLCK ? OP_LOCKU : OP_LOCK, - NULL); + (req.lr_op == OP_LOCK || req.lr_op == OP_LOCKU) ? + &req : NULL, flk->l_type == F_UNLCK ? OP_LOCKU : OP_LOCK, + NULL); } diff --git a/usr/src/uts/common/fs/nfs/nfs_sys.c b/usr/src/uts/common/fs/nfs/nfs_sys.c index f42361def0..6034b67145 100644 --- a/usr/src/uts/common/fs/nfs/nfs_sys.c +++ b/usr/src/uts/common/fs/nfs/nfs_sys.c @@ -358,6 +358,19 @@ nfssys(enum nfssys_op opcode, void *arg) break; } + case NFS4_EPHEMERAL_MOUNT_TO: { + uint_t mount_to; + + /* + * Not a very complicated call. + */ + if (copyin(arg, &mount_to, sizeof (mount_to))) + return (set_errno(EFAULT)); + nfs4_ephemeral_set_mount_to(mount_to); + error = 0; + break; + } + case MOUNTD_ARGS: { uint_t did; diff --git a/usr/src/uts/common/fs/vfs.c b/usr/src/uts/common/fs/vfs.c index db456f4d34..a1b7059e9b 100644 --- a/usr/src/uts/common/fs/vfs.c +++ b/usr/src/uts/common/fs/vfs.c @@ -957,7 +957,7 @@ stripzonepath(const char *strpath) /* * Common mount code. Called from the system call entry point, from autofs, - * and from pxfs. + * nfsv4 trigger mounts, and from pxfs. * * Takes the effective file system type, mount arguments, the mount point * vnode, flags specifying whether the mount is a remount and whether it diff --git a/usr/src/uts/common/nfs/mount.h b/usr/src/uts/common/nfs/mount.h index 91e6e66c69..4b5c3adb9c 100644 --- a/usr/src/uts/common/nfs/mount.h +++ b/usr/src/uts/common/nfs/mount.h @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -157,6 +156,12 @@ struct nfs_args32 { #define NFSMNT_SECDEFAULT 0x4000000 /* mount using default sec flavor */ #define NFSMNT_TRYRDMA 0x8000000 /* Try RDMA mount,no proto advised */ #define NFSMNT_DORDMA 0x10000000 /* Do an RDMA mount, regardless */ +#define NFSMNT_MIRRORMOUNT 0x20000000 /* Is a mirrormount */ + +/* + * This will have to change when we do referrals. + */ +#define NFSMNT_EPHEMERAL NFSMNT_MIRRORMOUNT #ifdef __cplusplus } diff --git a/usr/src/uts/common/nfs/nfs4.h b/usr/src/uts/common/nfs/nfs4.h index ef4365b9d0..2000cac44f 100644 --- a/usr/src/uts/common/nfs/nfs4.h +++ b/usr/src/uts/common/nfs/nfs4.h @@ -942,7 +942,6 @@ extern int nfs4_seqid_sync; extern int nfs4_client_map_debug; extern int nfs4_client_inactive_debug; extern int nfs4_client_recov_debug; -extern int nfs4_client_recov_stub_debug; extern int nfs4_client_failover_debug; extern int nfs4_client_call_debug; extern int nfs4_client_foo_debug; @@ -1328,6 +1327,8 @@ extern kstat_named_t *rfsproccnt_v4_ptr; extern struct vfsops *nfs4_vfsops; extern struct vnodeops *nfs4_vnodeops; extern const struct fs_operation_def nfs4_vnodeops_template[]; +extern vnodeops_t *nfs4_trigger_vnodeops; +extern const struct fs_operation_def nfs4_trigger_vnodeops_template[]; extern uint_t nfs4_tsize(struct knetconfig *); extern uint_t rfs4_tsize(struct svc_req *); diff --git a/usr/src/uts/common/nfs/nfs4_clnt.h b/usr/src/uts/common/nfs/nfs4_clnt.h index df23a4da0d..e91abcd81d 100644 --- a/usr/src/uts/common/nfs/nfs4_clnt.h +++ b/usr/src/uts/common/nfs/nfs4_clnt.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -47,6 +47,7 @@ #include <nfs/rnode.h> #include <sys/avl.h> #include <sys/list.h> +#include <rpc/auth.h> #ifdef __cplusplus extern "C" { @@ -823,6 +824,8 @@ typedef struct nfs4_debug_msg { * mi_foo_max * mi_lost_state * mi_bseqid_list + * mi_ephemeral + * mi_ephemeral_tree * * Normally the netconfig information for the mount comes from * mi_curr_serv and mi_klmconfig is NULL. If NLM calls need to use a @@ -881,8 +884,19 @@ typedef struct nfs4_debug_msg { * * mi_zone_node is linkage into the mi4_globals.mig_list, and is * protected by mi4_globals.mig_list_lock. + * + * If MI4_EPHEMERAL is set in mi_flags, then mi_ephemeral points to an + * ephemeral structure for this ephemeral mount point. It can not be + * NULL. Also, mi_ephemeral_tree points to the root of the ephemeral + * tree. + * + * If MI4_EPHEMERAL is not set in mi_flags, then mi_ephemeral has + * to be NULL. If mi_ephemeral_tree is non-NULL, then this node + * is the enclosing mntinfo4 for the ephemeral tree. */ struct zone; +struct nfs4_ephemeral; +struct nfs4_ephemeral_tree; typedef struct mntinfo4 { kmutex_t mi_lock; /* protects mntinfo4 fields */ struct servinfo4 *mi_servers; /* server list */ @@ -1003,6 +1017,12 @@ typedef struct mntinfo4 { */ struct zone *mi_zone; /* Zone mounted in */ list_node_t mi_zone_node; /* linkage into per-zone mi list */ + + /* + * Links for unmounting ephemeral mounts. + */ + struct nfs4_ephemeral *mi_ephemeral; + struct nfs4_ephemeral_tree *mi_ephemeral_tree; } mntinfo4_t; /* @@ -1019,7 +1039,11 @@ typedef struct mntinfo4 { * MI4_SHUTDOWN System is rebooting or shutting down * MI4_LINK server supports link * MI4_SYMLINK server supports symlink + * MI4_EPHEMERAL_RECURSED an ephemeral mount being unmounted + * due to a recursive call - no need + * for additional recursion * MI4_ACL server supports NFSv4 ACLs + * MI4_MIRRORMOUNT is a mirrormount * MI4_NOPRINT don't print messages * MI4_DIRECTIO do direct I/O * MI4_RECOV_ACTIV filesystem has recovery a thread @@ -1034,6 +1058,7 @@ typedef struct mntinfo4 { * MI4_BADOWNER_DEBUG badowner error msg per mount * MI4_ASYNC_MGR_STOP tell async manager to die * MI4_TIMEDOUT saw a timeout during zone shutdown + * MI4_EPHEMERAL is an ephemeral mount */ #define MI4_HARD 0x1 #define MI4_PRINTED 0x2 @@ -1046,9 +1071,10 @@ typedef struct mntinfo4 { #define MI4_SHUTDOWN 0x200 #define MI4_LINK 0x400 #define MI4_SYMLINK 0x800 -/* 0x1000 is available */ +#define MI4_EPHEMERAL_RECURSED 0x1000 #define MI4_ACL 0x2000 -/* 0x4000 is available */ +/* MI4_MIRRORMOUNT is also defined in nfsstat.c */ +#define MI4_MIRRORMOUNT 0x4000 /* 0x8000 is available */ /* 0x10000 is available */ #define MI4_NOPRINT 0x20000 @@ -1067,6 +1093,12 @@ typedef struct mntinfo4 { #define MI4_ASYNC_MGR_STOP 0x40000000 #define MI4_TIMEDOUT 0x80000000 +/* + * Note that when we add referrals, then MI4_EPHEMERAL + * will be MI4_MIRRORMOUNT | MI4_REFERRAL. + */ +#define MI4_EPHEMERAL MI4_MIRRORMOUNT + #define INTR4(vp) (VTOMI4(vp)->mi_flags & MI4_INT) #define FAILOVER_MOUNT4(mi) (mi->mi_servers->sv_next) @@ -1252,6 +1284,114 @@ typedef enum { } nfs4_op_hint_t; /* + * This data structure is used to track ephemeral mounts for both + * mirror mounts and referrals. + * + * Note that each nfs4_ephemeral can only have one other nfs4_ephemeral + * pointing at it. So we don't need two backpointers to walk + * back up the tree. + * + * An ephemeral tree is pointed to by an enclosing non-ephemeral + * mntinfo4. The root is also pointed to by its ephemeral + * mntinfo4. ne_child will get us back to it, while ne_prior + * will get us back to the non-ephemeral mntinfo4. This is an + * edge case we will need to be wary of when walking back up the + * tree. + * + * The way we handle this edge case is to have ne_prior be NULL + * for the root nfs4_ephemeral node. + */ +typedef struct nfs4_ephemeral { + mntinfo4_t *ne_mount; /* who encloses us */ + struct nfs4_ephemeral *ne_child; /* first child node */ + struct nfs4_ephemeral *ne_peer; /* next sibling */ + struct nfs4_ephemeral *ne_prior; /* who points at us */ + time_t ne_ref_time; /* time last referenced */ + uint_t ne_mount_to; /* timeout at */ + int ne_state; /* used to traverse */ +} nfs4_ephemeral_t; + +/* + * State for the node (set in ne_state): + */ +#define NFS4_EPHEMERAL_OK 0x0 +#define NFS4_EPHEMERAL_VISIT_CHILD 0x1 +#define NFS4_EPHEMERAL_VISIT_SIBLING 0x2 +#define NFS4_EPHEMERAL_PROCESS_ME 0x4 +#define NFS4_EPHEMERAL_CHILD_ERROR 0x8 +#define NFS4_EPHEMERAL_PEER_ERROR 0x10 + +/* + * These are the locks used in processing ephemeral data: + * + * mi->mi_lock + * + * net->net_tree_lock + * This lock is used to gate all tree operations. + * If it is held, then no other process may + * traverse the tree. This allows us to not + * throw a hold on each vfs_t in the tree. + * Can be held for a "long" time. + * + * net->net_cnt_lock + * Used to protect refcnt and status. + * Must be held for a really short time. + * + * nfs4_ephemeral_thread_lock + * Is only held to create the harvester for the zone. + * There is no ordering imposed on it. + * Held for a really short time. + * + * Some further detail on the interactions: + * + * net_tree_lock controls access to net_root. Access needs to first be + * attempted in a non-blocking check. + * + * net_cnt_lock controls access to net_refcnt and net_status. It must only be + * held for very short periods of time, unless the refcnt is 0 and the status + * is INVALID. + * + * Before a caller can grab net_tree_lock, it must first grab net_cnt_lock + * to bump the net_refcnt. It then releases it and does the action specific + * algorithm to get the net_tree_lock. Once it has that, then it is okay to + * grab the net_cnt_lock and change the status. The status can only be + * changed if the caller has the net_tree_lock held as well. + * + * When a caller is done with net_tree_lock, it can decrement the net_refcnt + * either before it releases net_tree_lock or after. + * + * In either event, to decrement net_refcnt, it must hold net_cnt_lock. + * + * Note that the overall locking scheme for the nodes is to control access + * via the tree. The current scheme could easily be extended such that + * the enclosing root referenced a "forest" of trees. The underlying trees + * would be autonomous with respect to locks. + * + * Note that net_next is controlled by external locks + * particular to the data structure that the tree is being added to. + */ +typedef struct nfs4_ephemeral_tree { + mntinfo4_t *net_mount; + nfs4_ephemeral_t *net_root; + struct nfs4_ephemeral_tree *net_next; + kmutex_t net_tree_lock; + kmutex_t net_cnt_lock; + uint_t net_status; + uint_t net_refcnt; +} nfs4_ephemeral_tree_t; + +/* + * State for the tree (set in net_status): + */ +#define NFS4_EPHEMERAL_TREE_OK 0x0 +#define NFS4_EPHEMERAL_TREE_BUILDING 0x1 +#define NFS4_EPHEMERAL_TREE_DEROOTING 0x2 +#define NFS4_EPHEMERAL_TREE_INVALID 0x4 +#define NFS4_EPHEMERAL_TREE_MOUNTING 0x8 +#define NFS4_EPHEMERAL_TREE_UMOUNTING 0x10 +#define NFS4_EPHEMERAL_TREE_LOCKED 0x20 + +/* * This macro evaluates to non-zero if the given op releases state at the * server. */ @@ -1335,10 +1475,14 @@ extern void nfs4open_confirm(vnode_t *, seqid4*, stateid4 *, cred_t *, nfs4_error_t *, int *); extern void nfs4_error_zinit(nfs4_error_t *); extern void nfs4_error_init(nfs4_error_t *, int); +extern void nfs4_free_args(struct nfs_args *); extern void mi_hold(mntinfo4_t *); extern void mi_rele(mntinfo4_t *); +extern sec_data_t *copy_sec_data(sec_data_t *); +extern gss_clntdata_t *copy_sec_data_gss(gss_clntdata_t *); + #ifdef DEBUG extern int nfs4_consistent_type(vnode_t *); #endif @@ -1814,6 +1958,25 @@ extern void nfs4_end_fop(struct mntinfo4 *, vnode_t *, vnode_t *, nfs4_op_hint_t, nfs4_recov_state_t *, bool_t); extern char *nfs4_recov_action_to_str(nfs4_recov_t); +/* + * In sequence, code desiring to unmount an ephemeral tree must + * call nfs4_ephemeral_umount, nfs4_ephemeral_umount_activate, + * and nfs4_ephemeral_umount_unlock. The _unlock must also be + * called on all error paths that occur before it would naturally + * be invoked. + * + * The caller must also provde a pointer to a boolean to keep track + * of whether or not the code in _unlock is to be ran. + */ +extern void nfs4_ephemeral_umount_activate(mntinfo4_t *, + bool_t *, nfs4_ephemeral_tree_t **); +extern int nfs4_ephemeral_umount(mntinfo4_t *, int, cred_t *, + bool_t *, nfs4_ephemeral_tree_t **); +extern void nfs4_ephemeral_umount_unlock(bool_t *, + nfs4_ephemeral_tree_t **); + +extern void nfs4_record_ephemeral_mount(mntinfo4_t *mi, vnode_t *mvp); + extern int wait_for_recall(vnode_t *, vnode_t *, nfs4_op_hint_t, nfs4_recov_state_t *); extern void nfs4_end_op_recall(vnode_t *, vnode_t *, nfs4_recov_state_t *); diff --git a/usr/src/uts/common/nfs/nfssys.h b/usr/src/uts/common/nfs/nfssys.h index 3e7893bfb2..f11f81e7ec 100644 --- a/usr/src/uts/common/nfs/nfssys.h +++ b/usr/src/uts/common/nfs/nfssys.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -51,7 +51,7 @@ enum nfssys_op { OLD_NFS_SVC, OLD_ASYNC_DAEMON, EXPORTFS, OLD_NFS_GETFH, LOG_FLUSH, SVCPOOL_CREATE, NFS_SVC, LM_SVC, SVCPOOL_WAIT, SVCPOOL_RUN, NFS4_SVC, RDMA_SVC_INIT, NFS4_CLR_STATE, NFS_IDMAP, NFS4_SVC_REQUEST_QUIESCE, NFS_GETFH, NFS4_DSS_SETPATHS, - NFS4_DSS_SETPATHS_SIZE, MOUNTD_ARGS }; + NFS4_DSS_SETPATHS_SIZE, NFS4_EPHEMERAL_MOUNT_TO, MOUNTD_ARGS }; struct nfs_svc_args { int fd; /* Connection endpoint */ @@ -318,6 +318,7 @@ extern int nfs4_svc(struct nfs4_svc_args *, model_t); extern int rdma_start(struct rdma_svc_args *); extern void rfs4_clear_client_state(struct nfs4clrst_args *); extern void nfs_idmap_args(struct nfsidmap_args *); +extern void nfs4_ephemeral_set_mount_to(uint_t); extern void mountd_args(uint_t); #endif diff --git a/usr/src/uts/common/nfs/rnode4.h b/usr/src/uts/common/nfs/rnode4.h index d65e1011c0..a07c2b5be0 100644 --- a/usr/src/uts/common/nfs/rnode4.h +++ b/usr/src/uts/common/nfs/rnode4.h @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -42,6 +41,11 @@ extern "C" { #include <sys/thread.h> #include <sys/sysmacros.h> /* for offsetof */ +typedef enum nfs4_stub_type { + NFS4_STUB_NONE, + NFS4_STUB_MIRRORMOUNT +} nfs4_stub_type_t; + typedef enum nfs4_access_type { NFS4_ACCESS_UNKNOWN, NFS4_ACCESS_ALLOWED, @@ -319,7 +323,9 @@ typedef struct rnode4 { fattr4_fsid r_srv_fsid; /* fsid of srv fs containing object */ /* when rnode created; compare with */ /* sv_fsid (servinfo4_t) to see why */ - /* R4SRVSTUB was set */ + /* stub type was set */ + nfs4_stub_type_t r_stub_type; + /* e.g. mirror-mount */ } rnode4_t; #define r_vnode r_svnode.sv_r_vnode @@ -343,7 +349,6 @@ typedef struct rnode4 { #define R4RECOVERR 0x2000 /* couldn't recover */ #define R4RECEXPFH 0x4000 /* recovering expired filehandle */ #define R4RECOVERRP 0x8000 /* R4RECOVERR pending, but not set (yet) */ -#define R4SRVSTUB 0x10000 /* server stub / fs mntpnt */ #define R4ISXATTR 0x20000 /* rnode is a named attribute */ #define R4DELMAPLIST 0x40000 /* delmap callers tracked for as callback */ #define R4PGFLUSH 0x80000 /* page flush thread active */ @@ -354,6 +359,9 @@ typedef struct rnode4 { #define RTOV4(rp) ((rp)->r_vnode) #define VTOR4(vp) ((rnode4_t *)((vp)->v_data)) +#define RP_ISSTUB(rp) (((rp)->r_stub_type != NFS4_STUB_NONE)) +#define RP_ISSTUB_MIRRORMOUNT(rp) ((rp)->r_stub_type == NFS4_STUB_MIRRORMOUNT) + /* * Open file instances. */ @@ -474,6 +482,9 @@ extern void rddir4_cache_destroy(rnode4_t *); extern rddir4_cache *rddir4_cache_lookup(rnode4_t *, offset_t, int); extern void rddir4_cache_rele(rnode4_t *, rddir4_cache *); +extern void r4_stub_mirrormount(rnode4_t *); +extern void r4_stub_none(rnode4_t *); + #ifdef DEBUG extern char *rddir4_cache_buf_alloc(size_t, int); extern void rddir4_cache_buf_free(void *, size_t); diff --git a/usr/src/uts/common/rpc/sec/sec_clnt.c b/usr/src/uts/common/rpc/sec/sec_clnt.c index f5e90c7225..e73c723142 100644 --- a/usr/src/uts/common/rpc/sec/sec_clnt.c +++ b/usr/src/uts/common/rpc/sec/sec_clnt.c @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -111,7 +110,7 @@ gss_clnt_loadinfo(caddr_t usrdata, caddr_t *kdata, model_t model) } else { data->mechanism.length = gd32.mechanism.length; data->mechanism.elements = - (caddr_t)(uintptr_t)gd32.mechanism.elements; + (caddr_t)(uintptr_t)gd32.mechanism.elements; data->service = gd32.service; bcopy(gd32.uname, data->uname, sizeof (gd32.uname)); bcopy(gd32.inst, data->inst, sizeof (gd32.inst)); @@ -441,6 +440,9 @@ sec_clnt_geth(CLIENT *client, struct sec_data *secdata, cred_t *cr, AUTH **ap) authflavor = secdata->rpcflavor; for (;;) { + int nlen; + char *netname; + switch (authflavor) { case AUTH_NONE: /* @@ -482,12 +484,28 @@ sec_clnt_geth(CLIENT *client, struct sec_data *secdata, cred_t *cr, AUTH **ap) */ savecred = curthread->t_cred; curthread->t_cred = cr; + + /* + * Note that authdes_create() expects a + * NUL-terminated string for netname, but + * dh_k4_clntdata_t gives us netname & netnamelen. + * + * We must create a string for authdes_create(); + * the latter takes a copy of it, so we may + * immediately free it. + */ desdata = (dh_k4_clntdata_t *)secdata->data; - stat = authdes_create(desdata->netname, authdes_win, - &desdata->syncaddr, desdata->knconf, - (des_block *)NULL, - (secdata->flags & AUTH_F_RPCTIMESYNC) ? 1 : 0, - &auth); + nlen = desdata->netnamelen; + /* must be NUL-terminated */ + netname = kmem_zalloc(nlen + 1, KM_SLEEP); + bcopy(desdata->netname, netname, nlen); + stat = authdes_create(netname, authdes_win, + &desdata->syncaddr, desdata->knconf, + (des_block *)NULL, + (secdata->flags & AUTH_F_RPCTIMESYNC) ? 1 : 0, + &auth); + kmem_free(netname, nlen + 1); + curthread->t_cred = savecred; *ap = auth; @@ -566,7 +584,7 @@ sec_clnt_geth(CLIENT *client, struct sec_data *secdata, cred_t *cr, AUTH **ap) } RPCLOG(1, "sec_clnt_geth: rpc_gss_secget" - " failed with %d", stat); + " failed with %d", stat); return (stat); default: @@ -596,14 +614,14 @@ sec_clnt_freeh(AUTH *auth) case AUTH_DES: mutex_enter(&desauthtab_lock); if (desauthtab != NULL) { - for (da = desauthtab; - da < &desauthtab[clnt_authdes_cachesz]; da++) { - if (da->da_auth == auth) { - da->da_inuse = 0; - mutex_exit(&desauthtab_lock); - return; + for (da = desauthtab; + da < &desauthtab[clnt_authdes_cachesz]; da++) { + if (da->da_auth == auth) { + da->da_inuse = 0; + mutex_exit(&desauthtab_lock); + return; + } } - } } mutex_exit(&desauthtab_lock); auth_destroy(auth); /* was overflow */ @@ -615,7 +633,7 @@ sec_clnt_freeh(AUTH *auth) default: cmn_err(CE_NOTE, "sec_clnt_freeh: unknown authflavor %d", - auth->ah_cred.oa_flavor); + auth->ah_cred.oa_flavor); break; } } @@ -678,11 +696,12 @@ sec_clnt_revoke(int rpcflavor, uid_t uid, cred_t *cr, void *mechanism, case AUTH_DES: mutex_enter(&desauthtab_lock); if (desauthtab != NULL) { - for (da = desauthtab; - da < &desauthtab[clnt_authdes_cachesz]; da++) { - if (uid == da->da_uid && zoneid == da->da_zoneid) - revoke_key(da->da_auth, 1); - } + for (da = desauthtab; + da < &desauthtab[clnt_authdes_cachesz]; da++) { + if (uid == da->da_uid && + zoneid == da->da_zoneid) + revoke_key(da->da_auth, 1); + } } mutex_exit(&desauthtab_lock); return (0); @@ -751,13 +770,13 @@ purge_authtab(struct sec_data *secdata) case AUTH_DES: mutex_enter(&desauthtab_lock); if (desauthtab != NULL) { - for (da = desauthtab; - da < &desauthtab[clnt_authdes_cachesz]; da++) { - if (da->da_data == secdata) { - da->da_data = NULL; - da->da_inuse = 0; + for (da = desauthtab; + da < &desauthtab[clnt_authdes_cachesz]; da++) { + if (da->da_data == secdata) { + da->da_data = NULL; + da->da_inuse = 0; + } } - } } mutex_exit(&desauthtab_lock); return; diff --git a/usr/src/uts/common/sys/fcntl.h b/usr/src/uts/common/sys/fcntl.h index 22050a3d54..70df5244f6 100644 --- a/usr/src/uts/common/sys/fcntl.h +++ b/usr/src/uts/common/sys/fcntl.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -349,6 +349,7 @@ typedef struct fshare { #define AT_FDCWD 0xffd19553 #define AT_SYMLINK_NOFOLLOW 0x1000 #define AT_REMOVEDIR 0x1 +#define _AT_TRIGGER 0x2 #endif #ifdef __cplusplus diff --git a/usr/src/uts/common/sys/vnode.h b/usr/src/uts/common/sys/vnode.h index 3d54125d84..56f4ac42d8 100644 --- a/usr/src/uts/common/sys/vnode.h +++ b/usr/src/uts/common/sys/vnode.h @@ -993,6 +993,7 @@ extern struct vnode zvp; #define ATTR_COMM 0x04 /* yield common vp attributes */ #define ATTR_HINT 0x08 /* information returned will be `hint' */ #define ATTR_REAL 0x10 /* yield attributes of the real vp */ +#define ATTR_TRIGGER 0x40 /* Mount first if vnode is a trigger mount */ /* * Generally useful macros. diff --git a/usr/src/uts/common/syscall/stat.c b/usr/src/uts/common/syscall/stat.c index ac249e183b..33403cf89e 100644 --- a/usr/src/uts/common/syscall/stat.c +++ b/usr/src/uts/common/syscall/stat.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -196,7 +196,9 @@ fstat(int fd, struct stat *sb) int fstatat(int fd, char *name, struct stat *sb, int flags) { - return (cstatat(fd, name, 2, sb, flags, 0)); + return (cstatat(fd, name, 2, sb, + flags & AT_SYMLINK_NOFOLLOW ? AT_SYMLINK_NOFOLLOW : 0, + flags & _AT_TRIGGER ? ATTR_TRIGGER : 0)); } #if defined(__i386) || defined(__i386_COMPAT) @@ -357,9 +359,11 @@ fstat32(int fd, struct stat32 *sb) } int -fstatat32(int fd, char *name, struct stat32 *sb, int flag) +fstatat32(int fd, char *name, struct stat32 *sb, int flags) { - return (cstatat32(fd, name, 2, sb, flag, 0)); + return (cstatat32(fd, name, 2, sb, + flags & AT_SYMLINK_NOFOLLOW ? AT_SYMLINK_NOFOLLOW : 0, + flags & _AT_TRIGGER ? ATTR_TRIGGER : 0)); } #if defined(__i386_COMPAT) @@ -503,7 +507,9 @@ fstat64(int fd, struct stat64 *sb) int fstatat64(int fd, char *name, struct stat64 *sb, int flags) { - return (cstatat64(fd, name, 2, sb, flags, 0)); + return (cstatat64(fd, name, 2, sb, + flags & AT_SYMLINK_NOFOLLOW ? AT_SYMLINK_NOFOLLOW : 0, + flags & _AT_TRIGGER ? ATTR_TRIGGER : 0)); } static int @@ -604,9 +610,11 @@ fstat64_32(int fd, struct stat64_32 *sb) } int -fstatat64_32(int fd, char *name, struct stat64_32 *sb, int flag) +fstatat64_32(int fd, char *name, struct stat64_32 *sb, int flags) { - return (cstatat64_32(fd, name, 2, sb, flag, 0)); + return (cstatat64_32(fd, name, 2, sb, + flags & AT_SYMLINK_NOFOLLOW ? AT_SYMLINK_NOFOLLOW : 0, + flags & _AT_TRIGGER ? ATTR_TRIGGER : 0)); } static int diff --git a/usr/src/uts/common/syscall/umount.c b/usr/src/uts/common/syscall/umount.c index f5fb881f5d..970afd9b2b 100644 --- a/usr/src/uts/common/syscall/umount.c +++ b/usr/src/uts/common/syscall/umount.c @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -51,6 +50,72 @@ #include <sys/policy.h> #include <sys/zone.h> +#define UMOUNT2_SET_ERRNO(e, is_syscall) ((is_syscall) ? set_errno((e)) : (e)) + +/* + * The heart of the umount2 call - it is pulled out to allow kernel + * level particpation when the only reference is the vfs pointer. + * + * Note that some of the callers may not be in the context of a + * syscall (created by zthread_create() for example) and as such + * may not have an associated curthread->t_lwp. This is handled + * by is_syscall. + */ +int +umount2_engine(vfs_t *vfsp, int flag, cred_t *cr, int is_syscall) +{ + int error; + + /* + * Protect the call to vn_vfswlock() with the vfs reflock. This + * ensures vfs_vnodecovered will either be NULL (because someone + * beat us to the umount) or valid (because vfs_lock() prevents + * another umount from getting through here until we've called + * vn_vfswlock() on the covered vnode). + * + * At one point, we did the non-blocking version (vfs_lock()), + * and if it failed, bailed out with EBUSY. However, dounmount() + * calls vfs_lock_wait() and we drop the vfs lock before calling + * dounmount(), so there's no difference between waiting here + * for the lock or waiting there because grabbed it as soon as + * we drop it below. No returning with EBUSY at this point + * reduces the number of spurious unmount failures that happen + * as a side-effect of fsflush() and other mount and unmount + * operations that might be going on simultaneously. + */ + vfs_lock_wait(vfsp); + + /* + * Call vn_vfswlock() on the covered vnode so that dounmount() + * can do its thing. It will call the corresponding vn_vfsunlock(). + * Note that vfsp->vfs_vnodecovered can be NULL here, either because + * someone did umount on "/" or because someone beat us to the umount + * before we did the vfs_lock() above. In these cases, vn_vfswlock() + * returns EBUSY and we just pass that up. Also note that we're + * looking at a vnode without doing a VN_HOLD() on it. This is + * safe because it can't go away while something is mounted on it + * and we're locking out other umounts at this point. + */ + if (vn_vfswlock(vfsp->vfs_vnodecovered)) { + vfs_unlock(vfsp); + VFS_RELE(vfsp); + return (UMOUNT2_SET_ERRNO(EBUSY, is_syscall)); + } + + /* + * Now that the VVFSLOCK in the covered vnode is protecting this + * path, we don't need the vfs reflock or the hold on the vfs anymore. + */ + vfs_unlock(vfsp); + VFS_RELE(vfsp); + + /* + * Perform the unmount. + */ + if ((error = dounmount(vfsp, flag, cr)) != 0) + return (UMOUNT2_SET_ERRNO(error, is_syscall)); + return (0); +} /* * New umount() system call (for force unmount flag and perhaps others later). @@ -126,55 +191,7 @@ umount2(char *pathp, int flag) } pn_free(&pn); - /* - * Protect the call to vn_vfswlock() with the vfs reflock. This - * ensures vfs_vnodecovered will either be NULL (because someone - * beat us to the umount) or valid (because vfs_lock() prevents - * another umount from getting through here until we've called - * vn_vfswlock() on the covered vnode). - * - * At one point, we did the non-blocking version (vfs_lock()), - * and if it failed, bailed out with EBUSY. However, dounmount() - * calls vfs_lock_wait() and we drop the vfs lock before calling - * dounmount(), so there's no difference between waiting here - * for the lock or waiting there because grabbed it as soon as - * we drop it below. No returning with EBUSY at this point - * reduces the number of spurious unmount failures that happen - * as a side-effect of fsflush() and other mount and unmount - * operations that might be going on simultaneously. - */ - vfs_lock_wait(vfsp); - - /* - * Call vn_vfswlock() on the covered vnode so that dounmount() - * can do its thing. It will call the corresponding vn_vfsunlock(). - * Note that vfsp->vfs_vnodecovered can be NULL here, either because - * someone did umount on "/" or because someone beat us to the umount - * before we did the vfs_lock() above. In these cases, vn_vfswlock() - * returns EBUSY and we just pass that up. Also note that we're - * looking at a vnode without doing a VN_HOLD() on it. This is - * safe because it can't go away while something is mounted on it - * and we're locking out other umounts at this point. - */ - if (vn_vfswlock(vfsp->vfs_vnodecovered)) { - vfs_unlock(vfsp); - VFS_RELE(vfsp); - return (set_errno(EBUSY)); - } - - /* - * Now that the VVFSLOCK in the covered vnode is protecting this - * path, we don't need the vfs reflock or the hold on the vfs anymore. - */ - vfs_unlock(vfsp); - VFS_RELE(vfsp); - - /* - * Perform the unmount. - */ - if ((error = dounmount(vfsp, flag, CRED())) != 0) - return (set_errno(error)); - return (0); + return (umount2_engine(vfsp, flag, CRED(), 1)); } /* diff --git a/usr/src/uts/intel/nfs/Makefile b/usr/src/uts/intel/nfs/Makefile index d6d3212d22..0e159d2ba6 100644 --- a/usr/src/uts/intel/nfs/Makefile +++ b/usr/src/uts/intel/nfs/Makefile @@ -21,7 +21,7 @@ # # uts/intel/nfs/Makefile # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -65,6 +65,8 @@ MODSTUBS_DIR = $(OBJS_DIR) $(MODSTUBS_O) := AS_CPPFLAGS += -DNFS_MODULE CLEANFILES += $(MODSTUBS_O) +INC_PATH += -I$(SRC)/common + # # For now, disable these lint checks; maintainers should endeavor # to investigate and remove these for maximum lint coverage. diff --git a/usr/src/uts/sparc/nfs/Makefile b/usr/src/uts/sparc/nfs/Makefile index 73fe1e7acd..49af3286df 100644 --- a/usr/src/uts/sparc/nfs/Makefile +++ b/usr/src/uts/sparc/nfs/Makefile @@ -20,7 +20,8 @@ # # # uts/sparc/nfs/Makefile -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -65,6 +66,8 @@ $(MODSTUBS_O) := AS_CPPFLAGS += -DNFS_MODULE CLEANFILES += $(MODSTUBS_O) CFLAGS += $(CCVERBOSE) +INC_PATH += -I$(SRC)/common + # # For now, disable these lint checks; maintainers should endeavor # to investigate and remove these for maximum lint coverage. |