summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorRobert Thurlow <Robert.Thurlow@Sun.COM>2009-12-09 17:27:22 -0600
committerRobert Thurlow <Robert.Thurlow@Sun.COM>2009-12-09 17:27:22 -0600
commit2f172c55ef76964744bc62b4500ece87f3089b4d (patch)
tree68a197e4eb4d77acf9993e2e3d75c3f3b06f6a86 /usr/src
parent1dbbbf767041f5cea7771826e2efc21c03bbffda (diff)
downloadillumos-joyent-2f172c55ef76964744bc62b4500ece87f3089b4d.tar.gz
6232737 Client should support NFS4ERR_MOVED and fs_locations
6232743 Server should support NFS4ERR_MOVED and fs_locations 6891289 client panick mutex_vector_tryenter with some stress testing
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_nfs4.c546
-rw-r--r--usr/src/cmd/fs.d/autofs/Makefile11
-rw-r--r--usr/src/cmd/fs.d/autofs/autod_nfs.c868
-rw-r--r--usr/src/cmd/fs.d/autofs/autod_xdr.c6
-rw-r--r--usr/src/cmd/fs.d/nfs/Makefile6
-rw-r--r--usr/src/cmd/fs.d/nfs/lib/nfs_resolve.c386
-rw-r--r--usr/src/cmd/fs.d/nfs/lib/nfs_resolve.h50
-rw-r--r--usr/src/cmd/fs.d/nfs/lib/ref_subr.c311
-rw-r--r--usr/src/cmd/fs.d/nfs/lib/ref_subr.h57
-rw-r--r--usr/src/cmd/fs.d/nfs/nfsmapid/Makefile9
-rw-r--r--usr/src/cmd/fs.d/nfs/nfsmapid/nfsmapid_server.c287
-rw-r--r--usr/src/cmd/fs.d/nfs/nfsref/Makefile69
-rw-r--r--usr/src/cmd/fs.d/nfs/nfsref/nfsref.c401
-rw-r--r--usr/src/cmd/fs.d/nfs/nfsstat/nfsstat.c5
-rw-r--r--usr/src/cmd/fs.d/nfs/rp_basic/Makefile56
-rw-r--r--usr/src/cmd/fs.d/nfs/rp_basic/Makefile.com65
-rw-r--r--usr/src/cmd/fs.d/nfs/rp_basic/amd64/Makefile28
-rw-r--r--usr/src/cmd/fs.d/nfs/rp_basic/i386/Makefile27
-rw-r--r--usr/src/cmd/fs.d/nfs/rp_basic/libnfs_basic.c310
-rw-r--r--usr/src/cmd/fs.d/nfs/rp_basic/mapfile-vers46
-rw-r--r--usr/src/cmd/fs.d/nfs/rp_basic/sparc/Makefile27
-rw-r--r--usr/src/cmd/fs.d/nfs/rp_basic/sparcv9/Makefile28
-rw-r--r--usr/src/cmd/fs.d/nfs/svc/server.xml7
-rw-r--r--usr/src/head/rpcsvc/daemon_utils.h10
-rw-r--r--usr/src/head/rpcsvc/nfs4_prot.x17
-rw-r--r--usr/src/lib/libshare/nfs/libshare_nfs.c8
-rw-r--r--usr/src/lib/libshare/nfs/libshare_nfs.h3
-rw-r--r--usr/src/pkgdefs/SUNWnfscu/prototype_com4
-rw-r--r--usr/src/pkgdefs/SUNWnfssu/prototype_com8
-rw-r--r--usr/src/pkgdefs/SUNWnfssu/prototype_i3867
-rw-r--r--usr/src/pkgdefs/SUNWnfssu/prototype_sparc7
-rw-r--r--usr/src/uts/common/fs/fs_subr.c18
-rw-r--r--usr/src/uts/common/fs/nfs/nfs3_srv.c61
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_attr.c43
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_callback.c8
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_client.c6
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_client_debug.c26
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_client_secinfo.c6
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_common.c15
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_idmap.c5
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_recovery.c41
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_rnode.c59
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_srv.c421
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_srv_attr.c114
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_srv_readdir.c31
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_state.c160
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_stub_vnops.c839
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_subr.c13
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_vfsops.c553
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_vnops.c88
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_xdr.c177
-rw-r--r--usr/src/uts/common/fs/nfs/nfs_srv.c72
-rw-r--r--usr/src/uts/common/fs/nfs/nfs_stats.c8
-rw-r--r--usr/src/uts/common/fs/vnode.c29
-rw-r--r--usr/src/uts/common/nfs/export.h5
-rw-r--r--usr/src/uts/common/nfs/mount.h10
-rw-r--r--usr/src/uts/common/nfs/nfs.h3
-rw-r--r--usr/src/uts/common/nfs/nfs4.h23
-rw-r--r--usr/src/uts/common/nfs/nfs4_attr.h10
-rw-r--r--usr/src/uts/common/nfs/nfs4_clnt.h51
-rw-r--r--usr/src/uts/common/nfs/nfs4_kprot.h18
-rw-r--r--usr/src/uts/common/nfs/nfsid_map.h39
-rw-r--r--usr/src/uts/common/nfs/rnode4.h8
-rw-r--r--usr/src/uts/common/sys/mkdev.h14
-rw-r--r--usr/src/uts/common/sys/vnode.h1
65 files changed, 5490 insertions, 1155 deletions
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_nfs4.c b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_nfs4.c
index dc675cf905..bb1db5c979 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_nfs4.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_nfs4.c
@@ -19,13 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-
#include <ctype.h>
#include <string.h>
#include <strings.h>
@@ -578,7 +575,7 @@ static void showxdr_utf8string(char *);
static char *utf8localize(utf8string *);
static void utf8free(void);
static void sum_pathname4(char *, size_t, pathname4 *);
-static void detail_pathname4(pathname4 *pathp);
+static void detail_pathname4(pathname4 *pathp, char *);
static void sum_compname4(char *buf, size_t buflen, component4 *comp);
static void detail_compname4(component4 *comp);
@@ -696,8 +693,8 @@ interpret_nfs4_cb(int flags, int type, int xid, int vers, int proc,
if (type == CALL) {
(void) sprintf(line, "NFS C %s",
- proc == CB_COMPOUND ? "CB4" :
- cb_procnames_short[proc]);
+ proc == CB_COMPOUND ? "CB4" :
+ cb_procnames_short[proc]);
line += strlen(line);
if (proc == CB_COMPOUND) {
@@ -706,15 +703,15 @@ interpret_nfs4_cb(int flags, int type, int xid, int vers, int proc,
if (!xdr_utf8string(&xdrm, &tag))
longjmp(xdr_err, 1);
sprintf(line, " (%.20s) %s",
- utf8localize(&tag),
- sum_cb_compound4args());
+ utf8localize(&tag),
+ sum_cb_compound4args());
xdr_free(xdr_utf8string, (char *)&tag);
}
check_retransmit(line, xid);
} else {
(void) sprintf(line, "NFS R %s ",
- proc == CB_COMPOUND ? "CB4" :
- cb_procnames_short[proc]);
+ proc == CB_COMPOUND ? "CB4" :
+ cb_procnames_short[proc]);
line += strlen(line);
if (proc == CB_COMPOUND)
sum_comp4res(line, sum_cb_compound4res);
@@ -725,7 +722,7 @@ interpret_nfs4_cb(int flags, int type, int xid, int vers, int proc,
show_header("NFS: ", "Sun NFS4 CallBack", len);
show_space();
(void) sprintf(get_line(0, 0), "Proc = %d (%s)",
- proc, cb_procnames_long[proc]);
+ proc, cb_procnames_long[proc]);
if (proc == CB_COMPOUND) {
if (type == CALL) {
showxdr_utf8string("Tag = %s");
@@ -736,7 +733,7 @@ interpret_nfs4_cb(int flags, int type, int xid, int vers, int proc,
status = getxdr_long();
showxdr_utf8string("Tag = %s");
sprintf(get_line(0, 0), "Status = %d (%s)",
- status, status_name(status));
+ status, status_name(status));
detail_cb_resop4();
}
}
@@ -766,8 +763,8 @@ interpret_nfs4(int flags, int type, int xid, int vers, int proc,
if (type == CALL) {
(void) sprintf(line, "NFS C %s",
- proc == NFSPROC4_COMPOUND ? "4" :
- procnames_short[proc]);
+ proc == NFSPROC4_COMPOUND ? "4" :
+ procnames_short[proc]);
line += strlen(line);
if (proc == NFSPROC4_COMPOUND) {
@@ -776,15 +773,15 @@ interpret_nfs4(int flags, int type, int xid, int vers, int proc,
if (!xdr_utf8string(&xdrm, &tag))
longjmp(xdr_err, 1);
sprintf(line, " (%.20s) %s",
- utf8localize(&tag),
- sum_compound4args());
+ utf8localize(&tag),
+ sum_compound4args());
xdr_free(xdr_utf8string, (char *)&tag);
}
check_retransmit(line, xid);
} else {
(void) sprintf(line, "NFS R %s ",
- proc == NFSPROC4_COMPOUND ? "4" :
- procnames_short[proc]);
+ proc == NFSPROC4_COMPOUND ? "4" :
+ procnames_short[proc]);
line += strlen(line);
if (proc == NFSPROC4_COMPOUND)
@@ -796,7 +793,7 @@ interpret_nfs4(int flags, int type, int xid, int vers, int proc,
show_header("NFS: ", "Sun NFS", len);
show_space();
(void) sprintf(get_line(0, 0), "Proc = %d (%s)",
- proc, procnames_long[proc]);
+ proc, procnames_long[proc]);
if (proc == NFSPROC4_COMPOUND) {
if (type == CALL) {
showxdr_utf8string("Tag = %s");
@@ -807,7 +804,7 @@ interpret_nfs4(int flags, int type, int xid, int vers, int proc,
status = getxdr_long();
showxdr_utf8string("Tag = %s");
sprintf(get_line(0, 0), "Status = %d (%s)",
- status, status_name(status));
+ status, status_name(status));
detail_nfs_resop4();
}
}
@@ -840,7 +837,7 @@ sum_compound4args(void)
if (setjmp(xdr_err)) {
bp = buf + strlen(buf);
snprintf(bp, buflen - (bp - buf),
- nfs4_fragged_rpc ? nfs4err_fragrpc : nfs4err_xdrfrag);
+ nfs4_fragged_rpc ? nfs4err_fragrpc : nfs4err_xdrfrag);
return (buf);
}
@@ -863,7 +860,7 @@ sum_compound4args(void)
longjmp(xdr_err, 1);
}
snprintf(bp, buflen - (bp - buf), "%s ",
- opcode_name(one_op.argop));
+ opcode_name(one_op.argop));
bp += strlen(bp);
operand = sum_operand(&one_op);
@@ -952,7 +949,7 @@ sum_cb_compound4args(void)
if (setjmp(xdr_err)) {
bp = buf + strlen(buf);
snprintf(bp, buflen - (bp - buf), "<XDR Error or Fragmented"
- " RPC>");
+ " RPC>");
return (buf);
}
@@ -981,7 +978,7 @@ sum_cb_compound4args(void)
}
snprintf(bp, buflen - (bp - buf), "%s ",
- cb_opcode_name(one_op.argop));
+ cb_opcode_name(one_op.argop));
bp += strlen(bp);
operand = sum_cb_operand(&one_op);
if (strlen(operand) > 0) {
@@ -1058,11 +1055,11 @@ detail_nfs_argop4(void)
longjmp(xdr_err, 1);
(void) sprintf(get_line(0, 0), "Minor version = %u",
- minor_version);
+ minor_version);
numops = getxdr_long();
(void) sprintf(get_line(0, 0), "Number of operations = %d",
- numops);
+ numops);
while (numops-- > 0) {
bzero(&one_op, sizeof (one_op));
@@ -1074,7 +1071,7 @@ detail_nfs_argop4(void)
get_line(0, 0); /* blank line to separate ops */
sprintf(get_line(0, 0), "Op = %d (%s)",
- one_op.argop, opcode_name(one_op.argop));
+ one_op.argop, opcode_name(one_op.argop));
if (one_op.argop < num_opcodes) {
fmtproc = opcode_info[one_op.argop].dtlarg;
if (fmtproc != NULL)
@@ -1104,16 +1101,16 @@ detail_cb_argop4(void)
if (!xdr_uint32_t(&xdrm, &minor_version))
longjmp(xdr_err, 1);
(void) sprintf(get_line(0, 0), "Minor version = %u",
- minor_version);
+ minor_version);
if (!xdr_uint32_t(&xdrm, &callback_ident))
longjmp(xdr_err, 1);
(void) sprintf(get_line(0, 0), "Callback Ident = %u",
- callback_ident);
+ callback_ident);
numops = getxdr_long();
(void) sprintf(get_line(0, 0), "Number of operations = %d",
- numops);
+ numops);
while (numops-- > 0) {
bzero(&one_op, sizeof (one_op));
@@ -1124,7 +1121,7 @@ detail_cb_argop4(void)
get_line(0, 0); /* blank line to separate ops */
sprintf(get_line(0, 0), "Op = %d (%s)",
- one_op.argop, cb_opcode_name(one_op.argop));
+ one_op.argop, cb_opcode_name(one_op.argop));
if (one_op.argop < cb_num_opcodes) {
fmtproc = cb_opcode_info[one_op.argop].dtlarg;
if (fmtproc != NULL)
@@ -1268,10 +1265,10 @@ _sum_stateid(stateid4 *stateid, char *prefix)
if ((spec = special_stateid(stateid)) < 0)
snprintf(buf, sizeof (buf), "%s%04X:%u", prefix,
- stateid_hash(stateid), stateid->seqid);
+ stateid_hash(stateid), stateid->seqid);
else
snprintf(buf, sizeof (buf), "%s%s", prefix,
- spec == 0 ? "SPC0" : (spec == 1 ? "SPC1" : "SPC?"));
+ spec == 0 ? "SPC0" : (spec == 1 ? "SPC1" : "SPC?"));
return (buf);
}
@@ -1285,15 +1282,15 @@ _detail_stateid(stateid4 *stateid, char *prefix)
if (spec < 0)
sprintf(get_line(0, 0), "%sState ID hash = %04X",
- prefix, stateid_hash(stateid));
+ prefix, stateid_hash(stateid));
else
sprintf(get_line(0, 0), "%sState ID hash = %s", prefix,
- spec == 0 ? "SPECIAL_0" :
- (spec == 1 ? "SPECIAL_1" : "SPECIAL_?"));
+ spec == 0 ? "SPECIAL_0" :
+ (spec == 1 ? "SPECIAL_1" : "SPECIAL_?"));
sprintf(get_line(0, 0), " len = %u val = %s",
- sizeof (stateid->other),
- tohex(stateid->other, sizeof (stateid->other)));
+ sizeof (stateid->other),
+ tohex(stateid->other, sizeof (stateid->other)));
/*
* If spec 0/1 stateid, print seqid in hex; otherwise,
@@ -1307,7 +1304,7 @@ _detail_stateid(stateid4 *stateid, char *prefix)
sprintf(seqstr, "%08X", stateid->seqid);
sprintf(get_line(0, 0), " %sState ID Sequence ID = %s",
- prefix, seqstr);
+ prefix, seqstr);
}
@@ -1317,9 +1314,9 @@ sum_lock_denied(LOCK4denied *denied)
static char buf[64];
sprintf(buf, "%s %llu %llu LO=%04X",
- sum_lock_type_name(denied->locktype),
- denied->offset, denied->length,
- owner_hash(&denied->owner.owner));
+ sum_lock_type_name(denied->locktype),
+ denied->offset, denied->length,
+ owner_hash(&denied->owner.owner));
return (buf);
}
@@ -1368,7 +1365,7 @@ static void
detail_createhow4(createhow4 *crtp)
{
sprintf(get_line(0, 0), "Method = %s",
- createhow4_name(crtp));
+ createhow4_name(crtp));
switch (crtp->mode) {
case UNCHECKED4:
@@ -1377,8 +1374,8 @@ detail_createhow4(createhow4 *crtp)
break;
case EXCLUSIVE4:
sprintf(get_line(0, 0), " Verifier = %s",
- tohex(crtp->createhow4_u.createverf,
- NFS4_VERIFIER_SIZE));
+ tohex(crtp->createhow4_u.createverf,
+ NFS4_VERIFIER_SIZE));
break;
}
}
@@ -1387,17 +1384,17 @@ static void
detail_createtype4(createtype4 *crtp)
{
sprintf(get_line(0, 0), "Type = %s",
- detail_type_name(crtp->type));
+ detail_type_name(crtp->type));
switch (crtp->type) {
case NF4LNK:
sprintf(get_line(0, 0), "Linkdata = %s",
- utf8localize(&crtp->createtype4_u.linkdata));
+ utf8localize(&crtp->createtype4_u.linkdata));
break;
case NF4BLK:
case NF4CHR:
sprintf(get_line(0, 0), "Specdata1 = %04x Specdata2 = %04x",
- crtp->createtype4_u.devdata.specdata1,
- crtp->createtype4_u.devdata.specdata2);
+ crtp->createtype4_u.devdata.specdata1,
+ crtp->createtype4_u.devdata.specdata2);
break;
default:
break;
@@ -1426,7 +1423,7 @@ sumarg_close(char *buf, size_t buflen, void *obj)
CLOSE4args *args = (CLOSE4args *)obj;
snprintf(buf, buflen, "SQ=%u %s",
- args->seqid, sum_open_stateid(&args->open_stateid));
+ args->seqid, sum_open_stateid(&args->open_stateid));
}
static void
@@ -1444,7 +1441,7 @@ sumarg_commit(char *buf, size_t buflen, void *obj)
COMMIT4args *args = (COMMIT4args *)obj;
snprintf(buf, buflen, "at %llu for %u ", args->offset,
- args->count);
+ args->count);
}
static void
@@ -1478,7 +1475,7 @@ sumarg_create(char *buf, size_t buflen, void *obj)
CREATE4args *args = (CREATE4args *)obj;
snprintf(buf, buflen, "%s %s ", component_name(&args->objname),
- sum_type_name(args->objtype.type));
+ sum_type_name(args->objtype.type));
}
static void
@@ -1566,7 +1563,7 @@ sumarg_cb_recall(char *buf, size_t buflen, void *obj)
char *bp = buf;
snprintf(bp, buflen, "%s %s TR=%s", sum_fh4(&args->fh),
- sum_stateid(&args->stateid), args->truncate ? "T" : "F");
+ sum_stateid(&args->stateid), args->truncate ? "T" : "F");
}
static void
@@ -1577,7 +1574,7 @@ dtlarg_cb_recall(void *obj)
detail_fh4(&args->fh);
detail_stateid(&args->stateid);
sprintf(get_line(0, 0), "Truncate = %s",
- args->truncate ? "True" : "False");
+ args->truncate ? "True" : "False");
}
@@ -1608,9 +1605,9 @@ sumarg_open(char *buf, size_t buflen, void *obj)
blen -= len;
snprintf(bp, blen, " AC=%s DN=%s OO=%04X",
- sum_open_share_access(args->share_access),
- sum_open_share_deny(args->share_deny),
- owner_hash(&args->owner.owner));
+ sum_open_share_access(args->share_access),
+ sum_open_share_deny(args->share_deny),
+ owner_hash(&args->owner.owner));
}
static void
@@ -1623,9 +1620,9 @@ dtlarg_open(void *obj)
detail_open_owner(&args->owner);
sprintf(get_line(0, 0), "Sequence ID = %u", args->seqid);
sprintf(get_line(0, 0), "Access = 0x%x (%s)",
- args->share_access, sum_open_share_access(args->share_access));
+ args->share_access, sum_open_share_access(args->share_access));
sprintf(get_line(0, 0), "Deny = 0x%x (%s)",
- args->share_deny, sum_open_share_access(args->share_deny));
+ args->share_deny, sum_open_share_access(args->share_deny));
}
static void
@@ -1634,7 +1631,7 @@ sumarg_openattr(char *buf, size_t buflen, void *obj)
OPENATTR4args *args = (OPENATTR4args *)obj;
snprintf(buf, buflen, "CD=%s",
- args->createdir ? "T" : "F");
+ args->createdir ? "T" : "F");
}
static void
@@ -1643,7 +1640,7 @@ dtlarg_openattr(void *obj)
OPENATTR4args *args = (OPENATTR4args *)obj;
sprintf(get_line(0, 0), "CreateDir = %s",
- args->createdir ? "True" : "False");
+ args->createdir ? "True" : "False");
}
static void
@@ -1653,7 +1650,7 @@ sumarg_open_confirm(char *buf, size_t buflen, void *obj)
OPEN_CONFIRM4args *args = (OPEN_CONFIRM4args *)obj;
snprintf(bp, buflen, "SQ=%u %s", args->seqid,
- sum_open_stateid(&args->open_stateid));
+ sum_open_stateid(&args->open_stateid));
}
static void
@@ -1671,9 +1668,9 @@ sumarg_open_downgrd(char *buf, size_t buflen, void *obj)
OPEN_DOWNGRADE4args *args = (OPEN_DOWNGRADE4args *)obj;
snprintf(buf, buflen, "SQ=%u %s AC=%s DN=%s",
- args->seqid, sum_open_stateid(&args->open_stateid),
- sum_open_share_access(args->share_access),
- sum_open_share_deny(args->share_deny));
+ args->seqid, sum_open_stateid(&args->open_stateid),
+ sum_open_share_access(args->share_access),
+ sum_open_share_deny(args->share_deny));
}
static void
@@ -1684,9 +1681,9 @@ dtlarg_open_downgrd(void *obj)
sprintf(get_line(0, 0), "Open Sequence ID = %u", args->seqid);
detail_open_stateid(&args->open_stateid);
sprintf(get_line(0, 0), "Access = 0x%x (%s)",
- args->share_access, sum_open_share_access(args->share_access));
+ args->share_access, sum_open_share_access(args->share_access));
sprintf(get_line(0, 0), "Deny = 0x%x (%s)",
- args->share_deny, sum_open_share_access(args->share_deny));
+ args->share_deny, sum_open_share_access(args->share_deny));
}
static void
@@ -1719,22 +1716,22 @@ dtlarg_link(void *obj)
LINK4args *args = (LINK4args *)obj;
sprintf(get_line(0, 0), "New name = %s",
- component_name(&args->newname));
+ component_name(&args->newname));
}
static void
sum_open_to_lock_owner(char *buf, int buflen, open_to_lock_owner4 *own)
{
snprintf(buf, buflen, " OSQ=%u %s LSQ=%u LO=%04X", own->open_seqid,
- sum_open_stateid(&own->open_stateid), own->lock_seqid,
- owner_hash(&own->lock_owner.owner));
+ sum_open_stateid(&own->open_stateid), own->lock_seqid,
+ owner_hash(&own->lock_owner.owner));
}
static void
sum_exist_lock_owner(char *buf, int buflen, exist_lock_owner4 *own)
{
snprintf(buf, buflen, " LSQ=%u %s", own->lock_seqid,
- sum_lock_stateid(&own->lock_stateid));
+ sum_lock_stateid(&own->lock_stateid));
}
static void
@@ -1779,9 +1776,9 @@ sumarg_lock(char *buf, size_t buflen, void *obj)
char *bp = buf;
snprintf(buf, buflen, "%s%s%llu:%llu",
- sum_lock_type_name(args->locktype),
- args->reclaim ? " reclaim " : " ",
- args->offset, args->length);
+ sum_lock_type_name(args->locktype),
+ args->reclaim ? " reclaim " : " ",
+ args->offset, args->length);
bp += strlen(buf);
sum_locker(bp, buflen - (bp - buf), &args->locker);
@@ -1819,7 +1816,7 @@ dtlarg_lock(void *obj)
sprintf(get_line(0, 0), "Type = %s", lock_type_name(args->locktype));
sprintf(get_line(0, 0), "Reclaim = %s",
- args->reclaim ? "TRUE" : "FALSE");
+ args->reclaim ? "TRUE" : "FALSE");
sprintf(get_line(0, 0), "Offset = %llu", args->offset);
sprintf(get_line(0, 0), "Length = %llu", args->length);
detail_locker(&args->locker);
@@ -1831,7 +1828,7 @@ sumarg_lockt(char *buf, size_t buflen, void *obj)
LOCKT4args *args = (LOCKT4args *)obj;
snprintf(buf, buflen, "R=%llu:%llu",
- args->offset, args->length);
+ args->offset, args->length);
}
static void
@@ -1851,8 +1848,8 @@ sumarg_locku(char *buf, size_t buflen, void *obj)
LOCKU4args *args = (LOCKU4args *)obj;
snprintf(buf, buflen, "R=%llu:%llu LSQ=%u %s",
- args->offset, args->length, args->seqid,
- sum_lock_stateid(&args->lock_stateid));
+ args->offset, args->length, args->seqid,
+ sum_lock_stateid(&args->lock_stateid));
}
@@ -1890,7 +1887,7 @@ sumarg_read(char *buf, size_t buflen, void *obj)
READ4args *args = (READ4args *)obj;
snprintf(buf, buflen, "%s at %llu for %u",
- sum_stateid(&args->stateid), args->offset, args->count);
+ sum_stateid(&args->stateid), args->offset, args->count);
}
static void
@@ -1909,8 +1906,8 @@ sumarg_readdir(char *buf, size_t buflen, void *obj)
READDIR4args *args = (READDIR4args *)obj;
snprintf(buf, buflen, "Cookie=%llu (%s) for %u/%u",
- args->cookie, tohex(args->cookieverf, NFS4_VERIFIER_SIZE),
- args->dircount, args->maxcount);
+ args->cookie, tohex(args->cookieverf, NFS4_VERIFIER_SIZE),
+ args->dircount, args->maxcount);
}
static void
@@ -1920,7 +1917,7 @@ dtlarg_readdir(void *obj)
sprintf(get_line(0, 0), "Cookie = %llu", args->cookie);
sprintf(get_line(0, 0), "Verifier = %s",
- tohex(args->cookieverf, NFS4_VERIFIER_SIZE));
+ tohex(args->cookieverf, NFS4_VERIFIER_SIZE));
sprintf(get_line(0, 0), "Dircount = %u", args->dircount);
sprintf(get_line(0, 0), "Maxcount = %u", args->maxcount);
detail_attr_bitmap("", &args->attr_request, NULL);
@@ -1949,8 +1946,8 @@ sumarg_rename(char *buf, size_t buflen, void *obj)
RENAME4args *args = (RENAME4args *)obj;
snprintf(buf, buflen, "%s to %s",
- component_name(&args->oldname),
- component_name(&args->newname));
+ component_name(&args->oldname),
+ component_name(&args->newname));
}
static void
@@ -1959,9 +1956,9 @@ dtlarg_rename(void *obj)
RENAME4args *args = (RENAME4args *)obj;
sprintf(get_line(0, 0), "Old name = %s",
- component_name(&args->oldname));
+ component_name(&args->oldname));
sprintf(get_line(0, 0), "New name = %s",
- component_name(&args->newname));
+ component_name(&args->newname));
}
static void
@@ -1985,7 +1982,7 @@ sumarg_secinfo(char *buf, size_t buflen, void *obj)
SECINFO4args *args = (SECINFO4args *)obj;
snprintf(buf, buflen, "%s",
- component_name(&args->name));
+ component_name(&args->name));
}
static void
@@ -1994,7 +1991,7 @@ dtlarg_secinfo(void *obj)
SECINFO4args *args = (SECINFO4args *)obj;
sprintf(get_line(0, 0), "Name = %s",
- component_name(&args->name));
+ component_name(&args->name));
}
static void
@@ -2020,9 +2017,9 @@ sumarg_setclid(char *buf, size_t buflen, void *obj)
SETCLIENTID4args *args = (SETCLIENTID4args *)obj;
snprintf(buf, buflen, "Prog=%u ID=%s Addr=%s CBID=%u",
- args->callback.cb_program,
- args->callback.cb_location.r_netid,
- args->callback.cb_location.r_addr, args->callback_ident);
+ args->callback.cb_program,
+ args->callback.cb_location.r_netid,
+ args->callback.cb_location.r_addr, args->callback_ident);
}
static void
@@ -2031,17 +2028,17 @@ dtlarg_setclid(void *obj)
SETCLIENTID4args *args = (SETCLIENTID4args *)obj;
sprintf(get_line(0, 0), "Verifier=%s",
- tohex(args->client.verifier, NFS4_VERIFIER_SIZE));
+ tohex(args->client.verifier, NFS4_VERIFIER_SIZE));
sprintf(get_line(0, 0), "ID = (%d) %s",
- args->client.id.id_len,
- tohex(args->client.id.id_val, args->client.id.id_len));
+ args->client.id.id_len,
+ tohex(args->client.id.id_val, args->client.id.id_len));
sprintf(get_line(0, 0), "Callback Program = %u",
- args->callback.cb_program);
+ args->callback.cb_program);
sprintf(get_line(0, 0), "Callback Net ID = %s",
- args->callback.cb_location.r_netid);
+ args->callback.cb_location.r_netid);
sprintf(get_line(0, 0), "Callback Addr = %s",
- args->callback.cb_location.r_addr);
+ args->callback.cb_location.r_addr);
sprintf(get_line(0, 0), "Callback Ident = %u", args->callback_ident);
}
@@ -2051,7 +2048,7 @@ sumarg_setclid_cfm(char *buf, size_t buflen, void *obj)
SETCLIENTID_CONFIRM4args *args = (SETCLIENTID_CONFIRM4args *)obj;
snprintf(buf, buflen, "%s CFV=%s", sum_clientid(args->clientid),
- tohex(args->setclientid_confirm, NFS4_VERIFIER_SIZE));
+ tohex(args->setclientid_confirm, NFS4_VERIFIER_SIZE));
}
static void
@@ -2061,7 +2058,7 @@ dtlarg_setclid_cfm(void *obj)
detail_clientid(args->clientid);
sprintf(get_line(0, 0), "Set Client ID Confirm Verifier = %s",
- tohex(args->setclientid_confirm, NFS4_VERIFIER_SIZE));
+ tohex(args->setclientid_confirm, NFS4_VERIFIER_SIZE));
}
@@ -2079,7 +2076,7 @@ sumarg_write(char *buf, size_t buflen, void *obj)
WRITE4args *args = (WRITE4args *)obj;
snprintf(buf, buflen, "%s at %llu for %u",
- sum_stateid(&args->stateid), args->offset, args->data.data_len);
+ sum_stateid(&args->stateid), args->offset, args->data.data_len);
}
static void
@@ -2134,7 +2131,7 @@ detail_fattr4(fattr4 *attrp)
jmp_buf old_errbuf;
xdrmem_create(&attrxdr, attrp->attr_vals.attrlist4_val,
- attrp->attr_vals.attrlist4_len, XDR_DECODE);
+ attrp->attr_vals.attrlist4_len, XDR_DECODE);
bcopy(xdr_err, old_errbuf, sizeof (old_errbuf));
if (setjmp(xdr_err)) {
@@ -2171,8 +2168,8 @@ sum_attr_bitmap(char *buf, size_t buflen, bitmap4 *mapp)
bp = buf + curlen;
remaining = buflen - curlen;
snprintf(bp, remaining,
- num_words == 0 ? "%x" : " %x",
- mapp->bitmap4_val[num_words]);
+ num_words == 0 ? "%x" : " %x",
+ mapp->bitmap4_val[num_words]);
}
}
@@ -2216,7 +2213,7 @@ detail_attr_bitmap(char *prefix, bitmap4 *bitp, unpkd_attrmap_t *unpacked)
attr_name(attrnum + bit));
if (unpacked != NULL)
unpacked->map[attrnum + bit] =
- 1;
+ 1;
}
}
}
@@ -2238,7 +2235,7 @@ sum_comp4res(char *line, char *(*sumres_fn)(void))
longjmp(xdr_err, 1);
sprintf(line, "(%.20s) %s %s", utf8localize(&tag),
- status_name(status), sumres_fn());
+ status_name(status), sumres_fn());
xdr_free(xdr_utf8string, (char *)&tag);
}
@@ -2263,7 +2260,7 @@ sum_compound4res(void)
if (setjmp(xdr_err)) {
bp = buf + strlen(buf);
snprintf(bp, buflen - (bp - buf),
- nfs4_fragged_rpc ? nfs4err_fragrpc : nfs4err_xdrfrag);
+ nfs4_fragged_rpc ? nfs4err_fragrpc : nfs4err_xdrfrag);
return (buf);
}
@@ -2280,7 +2277,7 @@ sum_compound4res(void)
}
snprintf(bp, buflen - (bp - buf), "%s ",
- opcode_name(one_res.resop));
+ opcode_name(one_res.resop));
bp += strlen(bp);
result = sum_result(&one_res);
@@ -2325,7 +2322,7 @@ sum_cb_compound4res(void)
if (setjmp(xdr_err)) {
bp = buf + strlen(buf);
snprintf(bp, buflen - (bp - buf), "<XDR Error or Fragmented"
- " RPC>");
+ " RPC>");
return (buf);
}
@@ -2338,8 +2335,8 @@ sum_cb_compound4res(void)
longjmp(xdr_err, 1);
}
snprintf(bp, buflen - (bp - buf), "%s %s ",
- cb_opcode_name(one_res.resop),
- sum_cb_result(&one_res));
+ cb_opcode_name(one_res.resop),
+ sum_cb_result(&one_res));
bp += strlen(bp);
xdr_free(xdr_nfs_cb_resop4, (char *)&one_res);
@@ -2410,7 +2407,7 @@ dtl_change_info(char *msg, change_info4 *infop)
{
sprintf(get_line(0, 0), "%s:", msg);
sprintf(get_line(0, 0), " Atomic = %s",
- infop->atomic ? "TRUE" : "FALSE");
+ infop->atomic ? "TRUE" : "FALSE");
detail_fattr4_change(" Before", infop->before);
detail_fattr4_change(" After", infop->after);
}
@@ -2436,7 +2433,7 @@ dtl_nfsstat4(void *obj)
nfsstat4 status = *(nfsstat4 *)obj;
sprintf(get_line(0, 0), "Status = %d (%s)", status,
- status_name(status));
+ status_name(status));
}
static void
@@ -2475,9 +2472,9 @@ dtlres_access(void *obj)
dtl_nfsstat4(obj);
if (res->status == NFS4_OK) {
detail_access4("Supported Attributes",
- res->ACCESS4res_u.resok4.supported);
+ res->ACCESS4res_u.resok4.supported);
detail_access4("Allowed Attributes",
- res->ACCESS4res_u.resok4.access);
+ res->ACCESS4res_u.resok4.access);
}
}
@@ -2488,7 +2485,7 @@ sumres_close(char *buf, size_t buflen, void *obj)
if (res->status == NFS4_OK)
snprintf(buf, buflen, "%s",
- sum_open_stateid(&res->CLOSE4res_u.open_stateid));
+ sum_open_stateid(&res->CLOSE4res_u.open_stateid));
}
static void
@@ -2509,8 +2506,8 @@ sumres_commit(char *buf, size_t buflen, void *obj)
if (res->status == NFS4_OK)
snprintf(buf, buflen, "Verf=%s",
- tohex(res->COMMIT4res_u.resok4.writeverf,
- NFS4_VERIFIER_SIZE));
+ tohex(res->COMMIT4res_u.resok4.writeverf,
+ NFS4_VERIFIER_SIZE));
}
static void
@@ -2521,8 +2518,8 @@ dtlres_commit(void *obj)
dtl_nfsstat4(obj);
if (res->status == NFS4_OK) {
sprintf(get_line(0, 0), "Verifier = %s",
- tohex(res->COMMIT4res_u.resok4.writeverf,
- NFS4_VERIFIER_SIZE));
+ tohex(res->COMMIT4res_u.resok4.writeverf,
+ NFS4_VERIFIER_SIZE));
}
}
@@ -2534,9 +2531,9 @@ dtlres_create(void *obj)
dtl_nfsstat4(obj);
if (res->status == NFS4_OK) {
dtl_change_info("Change Information",
- &res->CREATE4res_u.resok4.cinfo);
+ &res->CREATE4res_u.resok4.cinfo);
detail_attr_bitmap("", &res->CREATE4res_u.resok4.attrset,
- NULL);
+ NULL);
}
}
@@ -2589,7 +2586,7 @@ sumres_getfh(char *buf, size_t buflen, void *obj)
if (res->status == NFS4_OK) {
bp = buf + strlen(buf);
snprintf(bp, buflen - (bp - buf), " %s",
- sum_fh4(&res->GETFH4res_u.resok4.object));
+ sum_fh4(&res->GETFH4res_u.resok4.object));
}
}
@@ -2612,7 +2609,7 @@ dtlres_link(void *obj)
dtl_nfsstat4(obj);
if (res->status == NFS4_OK) {
dtl_change_info("Change Information",
- &res->LINK4res_u.resok4.cinfo);
+ &res->LINK4res_u.resok4.cinfo);
}
}
@@ -2626,12 +2623,12 @@ sumres_lock(char *buf, size_t buflen, void *obj)
if (res->status == NFS4_OK) {
bp = buf + strlen(buf);
snprintf(bp, buflen - (bp - buf), " %s",
- sum_lock_stateid(&res->LOCK4res_u.resok4.lock_stateid));
+ sum_lock_stateid(&res->LOCK4res_u.resok4.lock_stateid));
}
if (res->status == NFS4ERR_DENIED) {
bp = buf + strlen(buf);
snprintf(bp, buflen - (bp - buf), " %s",
- sum_lock_denied(&res->LOCK4res_u.denied));
+ sum_lock_denied(&res->LOCK4res_u.denied));
}
}
@@ -2659,7 +2656,7 @@ sumres_lockt(char *buf, size_t buflen, void *obj)
if (res->status == NFS4ERR_DENIED) {
bp = buf + strlen(buf);
snprintf(bp, buflen - (bp - buf), " %s",
- sum_lock_denied(&res->LOCKT4res_u.denied));
+ sum_lock_denied(&res->LOCKT4res_u.denied));
}
}
@@ -2684,7 +2681,7 @@ sumres_locku(char *buf, size_t buflen, void *obj)
bp = buf + strlen(buf);
if (res->status == NFS4_OK)
snprintf(bp, buflen - (bp - buf), " %s",
- sum_lock_stateid(&res->LOCKU4res_u.lock_stateid));
+ sum_lock_stateid(&res->LOCKU4res_u.lock_stateid));
}
static void
@@ -2712,7 +2709,7 @@ sumres_open(char *buf, size_t buflen, void *obj)
blen -= len;
snprintf(bp, blen, " %s",
- sum_stateid(&res->OPEN4res_u.resok4.stateid));
+ sum_stateid(&res->OPEN4res_u.resok4.stateid));
bp += (len = strlen(bp));
blen -= len;
@@ -2735,12 +2732,12 @@ dtlres_open(void *obj)
if (res->status == NFS4_OK) {
detail_stateid(&res->OPEN4res_u.resok4.stateid);
dtl_change_info("Change Information",
- &res->OPEN4res_u.resok4.cinfo);
+ &res->OPEN4res_u.resok4.cinfo);
sprintf(get_line(0, 0), "Flags = 0x%x (%s)",
- res->OPEN4res_u.resok4.rflags,
- detail_open_rflags(res->OPEN4res_u.resok4.rflags));
+ res->OPEN4res_u.resok4.rflags,
+ detail_open_rflags(res->OPEN4res_u.resok4.rflags));
detail_attr_bitmap("", &res->OPEN4res_u.resok4.attrset,
- NULL);
+ NULL);
detail_delegation(&res->OPEN4res_u.resok4.delegation);
}
}
@@ -2755,8 +2752,8 @@ sumres_open_confirm(char *buf, size_t buflen, void *obj)
if (res->status == NFS4_OK) {
bp = buf + strlen(buf);
snprintf(bp, buflen - (bp - buf), " %s",
- sum_open_stateid(&res->OPEN_CONFIRM4res_u.resok4.
- open_stateid));
+ sum_open_stateid(&res->OPEN_CONFIRM4res_u.resok4.
+ open_stateid));
}
}
@@ -2768,7 +2765,7 @@ dtlres_open_confirm(void *obj)
dtl_nfsstat4(obj);
if (res->status == NFS4_OK) {
detail_open_stateid(&res->OPEN_CONFIRM4res_u.resok4.
- open_stateid);
+ open_stateid);
}
}
@@ -2782,8 +2779,8 @@ sumres_open_downgrd(char *buf, size_t buflen, void *obj)
if (res->status == NFS4_OK) {
bp = buf + strlen(buf);
snprintf(bp, buflen - (bp - buf), " %s",
- sum_open_stateid(&res->OPEN_DOWNGRADE4res_u.resok4.
- open_stateid));
+ sum_open_stateid(&res->OPEN_DOWNGRADE4res_u.resok4.
+ open_stateid));
}
}
@@ -2795,7 +2792,7 @@ dtlres_open_downgrd(void *obj)
dtl_nfsstat4(obj);
if (res->status == NFS4_OK) {
detail_open_stateid(&res->OPEN_DOWNGRADE4res_u.resok4.
- open_stateid);
+ open_stateid);
}
}
@@ -2809,8 +2806,8 @@ sumres_read(char *buf, size_t buflen, void *obj)
if (res->status == NFS4_OK) {
bp = buf + strlen(buf);
snprintf(bp, buflen - (bp - buf), " (%u bytes) %s",
- res->READ4res_u.resok4.data.data_len,
- res->READ4res_u.resok4.eof ? "EOF" : "");
+ res->READ4res_u.resok4.data.data_len,
+ res->READ4res_u.resok4.eof ? "EOF" : "");
}
}
@@ -2822,9 +2819,9 @@ dtlres_read(void *obj)
dtl_nfsstat4(obj);
if (res->status == NFS4_OK) {
sprintf(get_line(0, 0), "Count = %u bytes read",
- res->READ4res_u.resok4.data.data_len);
+ res->READ4res_u.resok4.data.data_len);
sprintf(get_line(0, 0), "End of file = %s",
- res->READ4res_u.resok4.eof ? "TRUE" : "FALSE");
+ res->READ4res_u.resok4.eof ? "TRUE" : "FALSE");
}
}
@@ -2844,9 +2841,9 @@ sumres_readdir(char *buf, size_t buflen, void *obj)
num_entries++;
bp = buf + strlen(buf);
snprintf(bp, buflen - (bp - buf), " %d entries (%s)",
- num_entries,
- res->READDIR4res_u.resok4.reply.eof
- ? "No more" : "More");
+ num_entries,
+ res->READDIR4res_u.resok4.reply.eof
+ ? "No more" : "More");
}
}
@@ -2864,12 +2861,12 @@ dtlres_readdir(void *obj)
ep = ep->nextentry) {
num_entries++;
sprintf(get_line(0, 0),
- "------------------ entry #%d",
- num_entries);
+ "------------------ entry #%d",
+ num_entries);
sprintf(get_line(0, 0), "Cookie = %llu",
- ep->cookie);
+ ep->cookie);
sprintf(get_line(0, 0), "Name = %s",
- component_name(&ep->name));
+ component_name(&ep->name));
detail_fattr4(&ep->attrs);
}
if (num_entries == 0)
@@ -2877,8 +2874,8 @@ dtlres_readdir(void *obj)
sprintf(get_line(0, 0), "EOF = %s",
res->READDIR4res_u.resok4.reply.eof ? "TRUE" : "FALSE");
sprintf(get_line(0, 0), "Verifer = %s",
- tohex(res->READDIR4res_u.resok4.cookieverf,
- NFS4_VERIFIER_SIZE));
+ tohex(res->READDIR4res_u.resok4.cookieverf,
+ NFS4_VERIFIER_SIZE));
}
}
@@ -2892,7 +2889,7 @@ sumres_readlnk(char *buf, size_t buflen, void *obj)
if (res->status == NFS4_OK) {
bp = buf + strlen(buf);
snprintf(bp, buflen - (bp - buf), " %s",
- linktext_name(&res->READLINK4res_u.resok4.link));
+ linktext_name(&res->READLINK4res_u.resok4.link));
}
}
@@ -2904,7 +2901,7 @@ dtlres_readlnk(void *obj)
dtl_nfsstat4(obj);
if (res->status == NFS4_OK) {
sprintf(get_line(0, 0), "Link = %s",
- linktext_name(&res->READLINK4res_u.resok4.link));
+ linktext_name(&res->READLINK4res_u.resok4.link));
}
}
@@ -2916,7 +2913,7 @@ dtlres_remove(void *obj)
dtl_nfsstat4(obj);
if (res->status == NFS4_OK) {
dtl_change_info("Change Information",
- &res->REMOVE4res_u.resok4.cinfo);
+ &res->REMOVE4res_u.resok4.cinfo);
}
}
@@ -2928,9 +2925,9 @@ dtlres_rename(void *obj)
dtl_nfsstat4(obj);
if (res->status == NFS4_OK) {
dtl_change_info("Source Change Information",
- &res->RENAME4res_u.resok4.source_cinfo);
+ &res->RENAME4res_u.resok4.source_cinfo);
dtl_change_info("Target Change Information",
- &res->RENAME4res_u.resok4.target_cinfo);
+ &res->RENAME4res_u.resok4.target_cinfo);
}
}
@@ -2950,7 +2947,7 @@ sumres_secinfo(char *buf, size_t buflen, void *obj)
numinfo != 0;
infop++, numinfo--) {
snprintf(bp, buflen - (bp - buf), " %s",
- flavor_name(infop->flavor));
+ flavor_name(infop->flavor));
bp += strlen(bp);
}
}
@@ -2964,7 +2961,7 @@ dtlres_secinfo(void *obj)
dtl_nfsstat4(obj);
if (res->status == NFS4_OK) {
uint_t numinfo =
- res->SECINFO4res_u.resok4.SECINFO4resok_len;
+ res->SECINFO4res_u.resok4.SECINFO4resok_len;
secinfo4 *infop;
for (infop = res->SECINFO4res_u.resok4.SECINFO4resok_val;
@@ -3004,15 +3001,15 @@ sumres_setclid(char *buf, size_t buflen, void *obj)
case NFS_OK:
bp = buf + strlen(buf);
snprintf(bp, buflen - (bp - buf), " %s CFV=%s",
- sum_clientid(res->SETCLIENTID4res_u.resok4.clientid),
- tohex(res->SETCLIENTID4res_u.resok4.setclientid_confirm,
- NFS4_VERIFIER_SIZE));
+ sum_clientid(res->SETCLIENTID4res_u.resok4.clientid),
+ tohex(res->SETCLIENTID4res_u.resok4.setclientid_confirm,
+ NFS4_VERIFIER_SIZE));
break;
case NFS4ERR_CLID_INUSE:
bp = buf + strlen(buf);
snprintf(bp, buflen - (bp - buf), " ID=%s Addr=%s",
- res->SETCLIENTID4res_u.client_using.r_netid,
- res->SETCLIENTID4res_u.client_using.r_addr);
+ res->SETCLIENTID4res_u.client_using.r_netid,
+ res->SETCLIENTID4res_u.client_using.r_addr);
break;
}
}
@@ -3027,14 +3024,14 @@ dtlres_setclid(void *obj)
case NFS_OK:
detail_clientid(res->SETCLIENTID4res_u.resok4.clientid);
sprintf(get_line(0, 0), "Set Client ID Confirm Verifier = %s",
- tohex(res->SETCLIENTID4res_u.resok4.setclientid_confirm,
- NFS4_VERIFIER_SIZE));
+ tohex(res->SETCLIENTID4res_u.resok4.setclientid_confirm,
+ NFS4_VERIFIER_SIZE));
break;
case NFS4ERR_CLID_INUSE:
sprintf(get_line(0, 0), "Used by Net ID = %s",
- res->SETCLIENTID4res_u.client_using.r_netid);
+ res->SETCLIENTID4res_u.client_using.r_netid);
sprintf(get_line(0, 0), "Used by Addr = %s",
- res->SETCLIENTID4res_u.client_using.r_addr);
+ res->SETCLIENTID4res_u.client_using.r_addr);
break;
}
}
@@ -3049,8 +3046,8 @@ sumres_write(char *buf, size_t buflen, void *obj)
if (res->status == NFS4_OK) {
bp = buf + strlen(buf);
snprintf(bp, buflen - (bp - buf), " %u (%s)",
- res->WRITE4res_u.resok4.count,
- stable_how4_name(res->WRITE4res_u.resok4.committed));
+ res->WRITE4res_u.resok4.count,
+ stable_how4_name(res->WRITE4res_u.resok4.committed));
}
}
@@ -3062,12 +3059,12 @@ dtlres_write(void *obj)
dtl_nfsstat4(obj);
if (res->status == NFS4_OK) {
sprintf(get_line(0, 0), "Count = %u bytes written",
- res->WRITE4res_u.resok4.count);
+ res->WRITE4res_u.resok4.count);
sprintf(get_line(0, 0), "Stable = %s",
- stable_how4_name(res->WRITE4res_u.resok4.committed));
+ stable_how4_name(res->WRITE4res_u.resok4.committed));
sprintf(get_line(0, 0), "Verifier = %s",
- tohex(res->WRITE4res_u.resok4.writeverf,
- NFS4_VERIFIER_SIZE));
+ tohex(res->WRITE4res_u.resok4.writeverf,
+ NFS4_VERIFIER_SIZE));
}
}
@@ -3084,7 +3081,7 @@ detail_nfs_resop4(void)
numres = getxdr_long();
(void) sprintf(get_line(0, 0), "Number of results = %d",
- numres);
+ numres);
while (numres-- > 0) {
bzero(&one_res, sizeof (one_res));
@@ -3096,7 +3093,7 @@ detail_nfs_resop4(void)
get_line(0, 0); /* blank line to separate ops */
sprintf(get_line(0, 0), "Op = %d (%s)",
- one_res.resop, opcode_name(one_res.resop));
+ one_res.resop, opcode_name(one_res.resop));
if (one_res.resop < num_opcodes)
fmtproc = opcode_info[one_res.resop].dtlres;
else if (one_res.resop == OP_ILLEGAL)
@@ -3129,7 +3126,7 @@ detail_cb_resop4(void)
numres = getxdr_long();
(void) sprintf(get_line(0, 0), "Number of results = %d",
- numres);
+ numres);
while (numres-- > 0) {
bzero(&one_res, sizeof (one_res));
@@ -3138,7 +3135,7 @@ detail_cb_resop4(void)
get_line(0, 0); /* blank line to separate ops */
sprintf(get_line(0, 0), "Op = %d (%s)",
- one_res.resop, cb_opcode_name(one_res.resop));
+ one_res.resop, cb_opcode_name(one_res.resop));
if (one_res.resop < cb_num_opcodes)
fmtproc = cb_opcode_info[one_res.resop].dtlres;
else if (one_res.resop == OP_CB_ILLEGAL)
@@ -3256,17 +3253,17 @@ detail_access4(char *descrip, uint32_t bits)
sprintf(get_line(0, 0), "%s = 0x%08x", descrip, bits);
(void) sprintf(get_line(0, 0), " %s",
- getflag(bits, ACCESS4_READ, "Read", "(no read)"));
+ getflag(bits, ACCESS4_READ, "Read", "(no read)"));
(void) sprintf(get_line(0, 0), " %s",
- getflag(bits, ACCESS4_LOOKUP, "Lookup", "(no lookup)"));
+ getflag(bits, ACCESS4_LOOKUP, "Lookup", "(no lookup)"));
(void) sprintf(get_line(0, 0), " %s",
- getflag(bits, ACCESS4_MODIFY, "Modify", "(no modify)"));
+ getflag(bits, ACCESS4_MODIFY, "Modify", "(no modify)"));
(void) sprintf(get_line(0, 0), " %s",
- getflag(bits, ACCESS4_EXTEND, "Extend", "(no extend)"));
+ getflag(bits, ACCESS4_EXTEND, "Extend", "(no extend)"));
(void) sprintf(get_line(0, 0), " %s",
- getflag(bits, ACCESS4_DELETE, "Delete", "(no delete)"));
+ getflag(bits, ACCESS4_DELETE, "Delete", "(no delete)"));
(void) sprintf(get_line(0, 0), " %s",
- getflag(bits, ACCESS4_EXECUTE, "Execute", "(no execute)"));
+ getflag(bits, ACCESS4_EXECUTE, "Execute", "(no execute)"));
}
@@ -3281,19 +3278,19 @@ sum_name(char *buf, size_t buflen, open_claim4 *claim)
switch (claim->claim) {
case CLAIM_NULL:
snprintf(bp, buflen, "%s ",
- component_name(&claim->open_claim4_u.file));
+ component_name(&claim->open_claim4_u.file));
break;
case CLAIM_PREVIOUS:
break;
case CLAIM_DELEGATE_CUR:
snprintf(bp, buflen, "%s ",
- component_name(&claim->open_claim4_u.
- delegate_cur_info.file));
+ component_name(&claim->open_claim4_u.
+ delegate_cur_info.file));
break;
case CLAIM_DELEGATE_PREV:
snprintf(bp, buflen, "%s ",
- component_name(&claim->open_claim4_u.
- file_delegate_prev));
+ component_name(&claim->open_claim4_u.
+ file_delegate_prev));
break;
}
}
@@ -3312,12 +3309,12 @@ sum_claim(char *buf, size_t buflen, open_claim4 *claim)
break;
case CLAIM_PREVIOUS:
snprintf(bp, buflen, " CT=P DT=%s",
- get_deleg_typestr(claim->open_claim4_u.delegate_type));
+ get_deleg_typestr(claim->open_claim4_u.delegate_type));
break;
case CLAIM_DELEGATE_CUR:
snprintf(bp, buflen, " CT=DC %s",
- sum_deleg_stateid(&claim->open_claim4_u.
- delegate_cur_info.delegate_stateid));
+ sum_deleg_stateid(&claim->open_claim4_u.
+ delegate_cur_info.delegate_stateid));
break;
case CLAIM_DELEGATE_PREV:
snprintf(bp, buflen, " CT=DP");
@@ -3358,7 +3355,7 @@ static void
detail_claim(open_claim4 *claim)
{
sprintf(get_line(0, 0), "Claim Type = %d (%s)",
- claim->claim, claim_name(claim->claim));
+ claim->claim, claim_name(claim->claim));
switch (claim->claim) {
case CLAIM_NULL:
@@ -3366,13 +3363,13 @@ detail_claim(open_claim4 *claim)
break;
case CLAIM_PREVIOUS:
sprintf(get_line(0, 0), "Delegate Type = %s (val = %d)",
- get_deleg_typestr(claim->open_claim4_u.delegate_type),
- claim->open_claim4_u.delegate_type);
+ get_deleg_typestr(claim->open_claim4_u.delegate_type),
+ claim->open_claim4_u.delegate_type);
break;
case CLAIM_DELEGATE_CUR:
detail_compname4(&claim->open_claim4_u.delegate_cur_info.file);
detail_deleg_stateid(&claim->open_claim4_u.delegate_cur_info.
- delegate_stateid);
+ delegate_stateid);
break;
case CLAIM_DELEGATE_PREV:
detail_compname4(&claim->open_claim4_u.file_delegate_prev);
@@ -3415,15 +3412,15 @@ sum_delegation(char *buf, size_t buflen, open_delegation4 *delp)
break;
case OPEN_DELEGATE_READ:
snprintf(buf, buflen, " DT=R %s",
- sum_deleg_stateid(&delp->open_delegation4_u.write.
- stateid));
+ sum_deleg_stateid(&delp->open_delegation4_u.write.
+ stateid));
break;
case OPEN_DELEGATE_WRITE:
snprintf(buf, buflen, " DT=W %s %s",
- sum_deleg_stateid(&delp->open_delegation4_u.write.
- stateid),
- sum_space_limit(&delp->open_delegation4_u.write.
- space_limit));
+ sum_deleg_stateid(&delp->open_delegation4_u.write.
+ stateid),
+ sum_space_limit(&delp->open_delegation4_u.write.
+ space_limit));
break;
default:
snprintf(buf, buflen, " DT=?");
@@ -3435,8 +3432,8 @@ static void
detail_delegation(open_delegation4 *delp)
{
sprintf(get_line(0, 0), "Delegation Type = %d (%s)",
- delp->delegation_type,
- delegation_type_name(delp->delegation_type));
+ delp->delegation_type,
+ delegation_type_name(delp->delegation_type));
switch (delp->delegation_type) {
case OPEN_DELEGATE_NONE:
@@ -3445,17 +3442,17 @@ detail_delegation(open_delegation4 *delp)
case OPEN_DELEGATE_READ:
detail_deleg_stateid(&delp->open_delegation4_u.read.stateid);
sprintf(get_line(0, 0), "Recall = %s",
- delp->open_delegation4_u.read.recall ?
- "TRUE" : "FALSE");
+ delp->open_delegation4_u.read.recall ?
+ "TRUE" : "FALSE");
sprintf(get_line(0, 0), "[nfsacl4]");
break;
case OPEN_DELEGATE_WRITE:
detail_deleg_stateid(&delp->open_delegation4_u.write.stateid);
sprintf(get_line(0, 0), "Recall = %s",
- delp->open_delegation4_u.write.recall ?
- "TRUE" : "FALSE");
+ delp->open_delegation4_u.write.recall ?
+ "TRUE" : "FALSE");
detail_space_limit(&delp->open_delegation4_u.write.
- space_limit);
+ space_limit);
sprintf(get_line(0, 0), "[nfsacl4]");
break;
}
@@ -3466,10 +3463,10 @@ static void
detail_open_owner(open_owner4 *owner)
{
sprintf(get_line(0, 0), "Open Owner hash = [%04X] ",
- owner_hash(&owner->owner));
+ owner_hash(&owner->owner));
sprintf(get_line(0, 0), " len = %u val = %s ",
- owner->owner.owner_len,
- tohex(owner->owner.owner_val, owner->owner.owner_len));
+ owner->owner.owner_len,
+ tohex(owner->owner.owner_val, owner->owner.owner_len));
detail_clientid(owner->clientid);
}
@@ -3477,10 +3474,10 @@ static void
detail_lock_owner(lock_owner4 *owner)
{
sprintf(get_line(0, 0), "Lock Owner hash = [%04X] ",
- owner_hash(&owner->owner));
+ owner_hash(&owner->owner));
sprintf(get_line(0, 0), " len = %u val = %s ",
- owner->owner.owner_len,
- tohex(owner->owner.owner_val, owner->owner.owner_len));
+ owner->owner.owner_len,
+ tohex(owner->owner.owner_val, owner->owner.owner_len));
detail_clientid(owner->clientid);
}
@@ -3500,7 +3497,7 @@ sum_openflag(char *bufp, int buflen, openflag4 *flagp)
break;
default:
snprintf(bufp, buflen, "OT=CR(?:%d)",
- flagp->openflag4_u.how.mode);
+ flagp->openflag4_u.how.mode);
break;
}
} else
@@ -3511,7 +3508,7 @@ static void
detail_openflag(openflag4 *flagp)
{
sprintf(get_line(0, 0), "Open Type = %s",
- flagp->opentype == OPEN4_CREATE ? "CREATE" : "NOCREATE");
+ flagp->opentype == OPEN4_CREATE ? "CREATE" : "NOCREATE");
if (flagp->opentype == OPEN4_CREATE)
detail_createhow4(&flagp->openflag4_u.how);
}
@@ -3528,8 +3525,8 @@ sum_pathname4(char *buf, size_t buflen, pathname4 *pathp)
for (component = 0; component < pathp->pathname4_len;
component++) {
snprintf(bp, buflen - (bp - buf),
- component == 0 ? "%s" : "/%s",
- component_name(&pathp->pathname4_val[component]));
+ component == 0 ? "%s" : "/%s",
+ component_name(&pathp->pathname4_val[component]));
bp += strlen(bp);
}
}
@@ -3547,17 +3544,17 @@ detail_compname4(component4 *comp)
}
static void
-detail_pathname4(pathname4 *pathp)
+detail_pathname4(pathname4 *pathp, char *what)
{
char *bp = get_line(0, 0);
uint_t component;
- sprintf(bp, "File name = ");
+ sprintf(bp, what);
bp += strlen(bp);
for (component = 0; component < pathp->pathname4_len; component++) {
sprintf(bp, component == 0 ? "%s" : "/%s",
- component_name(&pathp->pathname4_val[component]));
+ component_name(&pathp->pathname4_val[component]));
bp += strlen(bp);
}
}
@@ -3571,10 +3568,10 @@ static void
detail_rpcsec_gss(rpcsec_gss_info *info)
{
sprintf(get_line(0, 0), "OID = %s",
- tohex(info->oid.sec_oid4_val, info->oid.sec_oid4_len));
+ tohex(info->oid.sec_oid4_val, info->oid.sec_oid4_len));
sprintf(get_line(0, 0), "QOP = %u", info->qop);
sprintf(get_line(0, 0), "Service = %d (%s)",
- info->service, gss_svc_name(info->service));
+ info->service, gss_svc_name(info->service));
}
/*
@@ -3585,7 +3582,7 @@ static void
detail_secinfo4(secinfo4 *infop)
{
sprintf(get_line(0, 0), "Flavor = %d (%s)",
- infop->flavor, flavor_name(infop->flavor));
+ infop->flavor, flavor_name(infop->flavor));
switch (infop->flavor) {
case RPCSEC_GSS:
detail_rpcsec_gss(&infop->secinfo4_u.flavor_info);
@@ -3608,12 +3605,12 @@ sum_space_limit(nfs_space_limit4 *limitp)
switch (limitp->limitby) {
case NFS_LIMIT_SIZE:
snprintf(buf, buflen, "LB=SZ(%llu)",
- limitp->nfs_space_limit4_u.filesize);
+ limitp->nfs_space_limit4_u.filesize);
break;
case NFS_LIMIT_BLOCKS:
snprintf(buf, buflen, "LB=BL(%u*%u)",
- limitp->nfs_space_limit4_u.mod_blocks.num_blocks,
- limitp->nfs_space_limit4_u.mod_blocks.bytes_per_block);
+ limitp->nfs_space_limit4_u.mod_blocks.num_blocks,
+ limitp->nfs_space_limit4_u.mod_blocks.bytes_per_block);
break;
default:
snprintf(buf, buflen, "LB=?(%d)", limitp->limitby);
@@ -3631,19 +3628,19 @@ static void
detail_space_limit(nfs_space_limit4 *limitp)
{
sprintf(get_line(0, 0), "LimitBy = %d (%s)",
- limitp->limitby,
- limitby_name(limitp->limitby));
+ limitp->limitby,
+ limitby_name(limitp->limitby));
switch (limitp->limitby) {
case NFS_LIMIT_SIZE:
sprintf(get_line(0, 0), "Bytes = %llu",
- limitp->nfs_space_limit4_u.filesize);
+ limitp->nfs_space_limit4_u.filesize);
break;
case NFS_LIMIT_BLOCKS:
sprintf(get_line(0, 0), "Blocks = %u",
- limitp->nfs_space_limit4_u.mod_blocks.num_blocks);
+ limitp->nfs_space_limit4_u.mod_blocks.num_blocks);
sprintf(get_line(0, 0), "Bytes Per Block = %u",
- limitp->nfs_space_limit4_u.mod_blocks.bytes_per_block);
+ limitp->nfs_space_limit4_u.mod_blocks.bytes_per_block);
break;
}
}
@@ -3927,8 +3924,8 @@ status_name(int status)
case NFS4ERR_RESOURCE: p = "NFS4ERR_RESOURCE"; break;
case NFS4ERR_MOVED: p = "NFS4ERR_MOVED"; break;
case NFS4ERR_NOFILEHANDLE: p = "NFS4ERR_NOFILEHANDLE"; break;
- case NFS4ERR_MINOR_VERS_MISMATCH: p =
- "NFS4ERR_MINOR_VERS_MISMATCH"; break;
+ case NFS4ERR_MINOR_VERS_MISMATCH: p = "NFS4ERR_MINOR_VERS_MISMATCH";
+ break;
case NFS4ERR_STALE_CLIENTID: p = "NFS4ERR_STALE_CLIENTID"; break;
case NFS4ERR_STALE_STATEID: p = "NFS4ERR_STALE_STATEID"; break;
case NFS4ERR_OLD_STATEID: p = "NFS4ERR_OLD_STATEID"; break;
@@ -4007,7 +4004,7 @@ prt_fh_expire_type(XDR *xdr)
sprintf(buf, "Filehandle expire type = ");
if ((val & (FH4_NOEXPIRE_WITH_OPEN | FH4_VOLATILE_ANY |
- FH4_VOL_MIGRATION | FH4_VOL_RENAME)) == 0) {
+ FH4_VOL_MIGRATION | FH4_VOL_RENAME)) == 0) {
strcat(buf, "Persistent");
return;
}
@@ -4067,7 +4064,7 @@ prt_link_support(XDR *xdr)
if (!xdr_bool(xdr, &val))
longjmp(xdr_err, 1);
sprintf(get_line(0, 0), "Link Support = %s",
- val ? "TRUE" : "FALSE");
+ val ? "TRUE" : "FALSE");
}
static void
@@ -4078,7 +4075,7 @@ prt_symlink_support(XDR *xdr)
if (!xdr_bool(xdr, &val))
longjmp(xdr_err, 1);
sprintf(get_line(0, 0), "Symlink Support = %s",
- val ? "TRUE" : "FALSE");
+ val ? "TRUE" : "FALSE");
}
static void
@@ -4089,7 +4086,7 @@ prt_named_attr(XDR *xdr)
if (!xdr_bool(xdr, &val))
longjmp(xdr_err, 1);
sprintf(get_line(0, 0), "Has Named Attributes = %s",
- val ? "TRUE" : "FALSE");
+ val ? "TRUE" : "FALSE");
}
static void
@@ -4100,7 +4097,7 @@ prt_fsid(XDR *xdr)
if (!xdr_fsid4(xdr, &val))
longjmp(xdr_err, 1);
sprintf(get_line(0, 0), "FS ID: Major = %llx, Minor = %llx",
- val.major, val.minor);
+ val.major, val.minor);
}
static void
@@ -4111,7 +4108,7 @@ prt_unique_handles(XDR *xdr)
if (!xdr_bool(xdr, &val))
longjmp(xdr_err, 1);
sprintf(get_line(0, 0), "Unique Handles = %s",
- val ? "TRUE" : "FALSE");
+ val ? "TRUE" : "FALSE");
}
static void
@@ -4132,7 +4129,7 @@ prt_rdattr_error(XDR *xdr)
if (!xdr_nfsstat4(xdr, &val))
longjmp(xdr_err, 1);
sprintf(get_line(0, 0), "Rdattr Error = %u (%s)",
- val, status_name(val));
+ val, status_name(val));
}
static void
@@ -4253,7 +4250,7 @@ prt_archive(XDR *xdr)
if (!xdr_bool(xdr, &val))
longjmp(xdr_err, 1);
sprintf(get_line(0, 0), "Archived = %s",
- val ? "TRUE" : "FALSE");
+ val ? "TRUE" : "FALSE");
}
static void
@@ -4264,7 +4261,7 @@ prt_cansettime(XDR *xdr)
if (!xdr_bool(xdr, &val))
longjmp(xdr_err, 1);
sprintf(get_line(0, 0), "Server Can Set Time = %s",
- val ? "TRUE" : "FALSE");
+ val ? "TRUE" : "FALSE");
}
static void
@@ -4275,7 +4272,7 @@ prt_case_insensitive(XDR *xdr)
if (!xdr_bool(xdr, &val))
longjmp(xdr_err, 1);
sprintf(get_line(0, 0), "Case Insensitive Lookups = %s",
- val ? "TRUE" : "FALSE");
+ val ? "TRUE" : "FALSE");
}
static void
@@ -4286,7 +4283,7 @@ prt_case_preserving(XDR *xdr)
if (!xdr_bool(xdr, &val))
longjmp(xdr_err, 1);
sprintf(get_line(0, 0), "Case Preserving = %s",
- val ? "TRUE" : "FALSE");
+ val ? "TRUE" : "FALSE");
}
static void
@@ -4297,7 +4294,7 @@ prt_chown_restricted(XDR *xdr)
if (!xdr_bool(xdr, &val))
longjmp(xdr_err, 1);
sprintf(get_line(0, 0), "Chown Is Restricted = %s",
- val ? "TRUE" : "FALSE");
+ val ? "TRUE" : "FALSE");
}
static void
@@ -4362,14 +4359,29 @@ prt_files_total(XDR *xdr)
}
static void
+prt_fs_location(fs_location4 *fsl)
+{
+ int i;
+
+ for (i = 0; i < fsl->server.server_len; i++)
+ sprintf(get_line(0, 0), "server: %s",
+ utf8localize(&fsl->server.server_val[i]));
+
+ detail_pathname4(&fsl->rootpath, "rootpath: ");
+}
+
+static void
prt_fs_locations(XDR *xdr)
{
static fs_locations4 val;
+ int i;
if (!xdr_fs_locations4(xdr, &val))
longjmp(xdr_err, 1);
- sprintf(get_line(0, 0), "[fs_locations]"); /* XXX */
- detail_pathname4(&val.fs_root);
+ sprintf(get_line(0, 0), "[fs_locations]");
+ detail_pathname4(&val.fs_root, "fs_root: ");
+ for (i = 0; i < val.locations.locations_len; i++)
+ prt_fs_location(&val.locations.locations_val[i]);
xdr_free(xdr_fs_locations4, (char *)&val);
}
@@ -4381,7 +4393,7 @@ prt_hidden(XDR *xdr)
if (!xdr_bool(xdr, &val))
longjmp(xdr_err, 1);
sprintf(get_line(0, 0), "Hidden = %s",
- val ? "TRUE" : "FALSE");
+ val ? "TRUE" : "FALSE");
}
static void
@@ -4392,7 +4404,7 @@ prt_homogeneous(XDR *xdr)
if (!xdr_bool(xdr, &val))
longjmp(xdr_err, 1);
sprintf(get_line(0, 0), "FS Is Homogeneous = %s",
- val ? "TRUE" : "FALSE");
+ val ? "TRUE" : "FALSE");
}
static void
@@ -4475,7 +4487,7 @@ prt_no_trunc(XDR *xdr)
if (!xdr_bool(xdr, &val))
longjmp(xdr_err, 1);
sprintf(get_line(0, 0), "Long Names Are Error (no_trunc) = %s",
- val ? "TRUE" : "FALSE");
+ val ? "TRUE" : "FALSE");
}
static void
@@ -4548,7 +4560,7 @@ prt_rawdev(XDR *xdr)
if (!xdr_specdata4(xdr, &val))
longjmp(xdr_err, 1);
sprintf(get_line(0, 0), "Raw Device ID = %u, %u",
- val.specdata1, val.specdata2);
+ val.specdata1, val.specdata2);
}
static void
@@ -4599,7 +4611,7 @@ prt_system(XDR *xdr)
if (!xdr_bool(xdr, &val))
longjmp(xdr_err, 1);
sprintf(get_line(0, 0), "System File = %s",
- val ? "TRUE" : "FALSE");
+ val ? "TRUE" : "FALSE");
}
static void
@@ -4610,7 +4622,7 @@ prt_time_access(XDR *xdr)
if (!xdr_nfstime4(xdr, &val))
longjmp(xdr_err, 1);
sprintf(get_line(0, 0), "Last Access Time = %s",
- format_time(val.seconds, val.nseconds));
+ format_time(val.seconds, val.nseconds));
}
static void
@@ -4622,8 +4634,8 @@ prt_time_access_set(XDR *xdr)
longjmp(xdr_err, 1);
if (val.set_it == SET_TO_CLIENT_TIME4) {
sprintf(get_line(0, 0), "Access Time = %s (set to client time)",
- format_time(val.settime4_u.time.seconds,
- val.settime4_u.time.nseconds));
+ format_time(val.settime4_u.time.seconds,
+ val.settime4_u.time.nseconds));
} else if (val.set_it == SET_TO_SERVER_TIME4) {
sprintf(get_line(0, 0), "Access Time (set to server time)");
} else
@@ -4638,7 +4650,7 @@ prt_time_backup(XDR *xdr)
if (!xdr_nfstime4(xdr, &val))
longjmp(xdr_err, 1);
sprintf(get_line(0, 0), "Last Backup Time = %s",
- format_time(val.seconds, val.nseconds));
+ format_time(val.seconds, val.nseconds));
}
static void
@@ -4649,7 +4661,7 @@ prt_time_create(XDR *xdr)
if (!xdr_nfstime4(xdr, &val))
longjmp(xdr_err, 1);
sprintf(get_line(0, 0), "Creation Time = %s",
- format_time(val.seconds, val.nseconds));
+ format_time(val.seconds, val.nseconds));
}
static void
@@ -4660,7 +4672,7 @@ prt_time_delta(XDR *xdr)
if (!xdr_nfstime4(xdr, &val))
longjmp(xdr_err, 1);
sprintf(get_line(0, 0), "Server Time Granularity = %lld.%09d sec",
- val.seconds, val.nseconds);
+ val.seconds, val.nseconds);
}
static void
@@ -4671,7 +4683,7 @@ prt_time_metadata(XDR *xdr)
if (!xdr_nfstime4(xdr, &val))
longjmp(xdr_err, 1);
sprintf(get_line(0, 0), "Last Metadata Change Time = %s",
- format_time(val.seconds, val.nseconds));
+ format_time(val.seconds, val.nseconds));
}
static void
@@ -4682,7 +4694,7 @@ prt_time_modify(XDR *xdr)
if (!xdr_nfstime4(xdr, &val))
longjmp(xdr_err, 1);
sprintf(get_line(0, 0), "Last Modification Time = %s",
- format_time(val.seconds, val.nseconds));
+ format_time(val.seconds, val.nseconds));
}
static void
@@ -4694,12 +4706,12 @@ prt_time_modify_set(XDR *xdr)
longjmp(xdr_err, 1);
if (val.set_it == SET_TO_CLIENT_TIME4) {
sprintf(get_line(0, 0),
- "Modification Time = %s (set to client time)",
- format_time(val.settime4_u.time.seconds,
- val.settime4_u.time.nseconds));
+ "Modification Time = %s (set to client time)",
+ format_time(val.settime4_u.time.seconds,
+ val.settime4_u.time.nseconds));
} else if (val.set_it == SET_TO_SERVER_TIME4) {
sprintf(get_line(0, 0),
- "Modification Time (set to server time)");
+ "Modification Time (set to server time)");
} else
longjmp(xdr_err, 1);
}
@@ -4760,7 +4772,7 @@ utf8localize(utf8string *utf8str)
}
if (newsize != oldsize) {
utf_buf[cur_utf_buf] = realloc(utf_buf[cur_utf_buf],
- newsize);
+ newsize);
if (utf_buf[cur_utf_buf] == NULL) {
pr_err("out of memory\n");
utf_buflen[cur_utf_buf] = 0;
diff --git a/usr/src/cmd/fs.d/autofs/Makefile b/usr/src/cmd/fs.d/autofs/Makefile
index c5cc33e46a..71021cbce5 100644
--- a/usr/src/cmd/fs.d/autofs/Makefile
+++ b/usr/src/cmd/fs.d/autofs/Makefile
@@ -71,8 +71,8 @@ LOCAL= autod_main.o \
autod_parse.o autod_mount.o autod_nfs.o nfs_cast.o \
autod_autofs.o autod_xdr.o autod_readdir.o autod_lookup.o
-TYPEOBJS= $(LOCAL) $(COMMON) replica.o nfs_sec.o nfs_subr.o $(FSLIB) \
- webnfs_xdr.o webnfs_client.o selfcheck.o
+TYPEOBJS= $(LOCAL) $(COMMON) replica.o nfs_sec.o nfs_resolve.o nfs_subr.o \
+ $(FSLIB) webnfs_xdr.o webnfs_client.o selfcheck.o
SHAREOBJS= $(SHARESRCS:%.c=%.o)
@@ -87,7 +87,7 @@ $(MOUNT):= LDLIBS += -lnsl
$(TYPEPROG) := LDLIBS += -lrpcsvc -lsocket -lnsl -lsldap -lkstat
CFLAGS += $(CCVERBOSE) -D_FILE_OFFSET_BITS=64
-CPPFLAGS= -I. -I.. -I../nfs/lib $(CPPFLAGS.master) -D_REENTRANT \
+CPPFLAGS= -I. -I.. -I../nfs/lib $(CPPFLAGS.master) -D_REENTRANT \
$(MALLOC_DEBUG)
OBJS= $(AUTOOBJS) $(MOUNTOBJS) $(TYPEOBJS) \
$(SHAREOBJS) $(UNSHAREOBJS)
@@ -96,7 +96,8 @@ AUTOSRCS= automount.c $(COMMON:%.o=%.c) $(FSLIBSRC)
MOUNTSRCS= mount.c $(FSLIBSRC)
TYPESRCS= $(LOCAL:%.o=%.c) $(COMMON:%.o=%.c) \
../nfs/lib/replica.c ../nfs/lib/nfs_sec.c \
- ../nfs/lib/nfs_subr.c $(FSLIBSRC) ../nfs/lib/selfcheck.c
+ ../nfs/lib/nfs_subr.c $(FSLIBSRC) ../nfs/lib/selfcheck.c \
+ ../nfs/lib/nfs_resolve.c
SHARESRCS= $(SHARE:%=%.c)
UNSHARESRCS= $(UNSHARE:%=%.c)
DFSHARESSRCS= $(DFSHARES:%=%.sh)
@@ -168,6 +169,8 @@ nfs_subr.o: ../nfs/lib/nfs_subr.c
selfcheck.o: ../nfs/lib/selfcheck.c
$(COMPILE.c) ../nfs/lib/selfcheck.c
+nfs_resolve.o: ../nfs/lib/nfs_resolve.c
+ $(COMPILE.c) ../nfs/lib/nfs_resolve.c
webnfs_xdr.c: webnfs.x
$(RPCGEN) -M -C -c -o $@ webnfs.x
diff --git a/usr/src/cmd/fs.d/autofs/autod_nfs.c b/usr/src/cmd/fs.d/autofs/autod_nfs.c
index 89f278b904..32f96245ad 100644
--- a/usr/src/cmd/fs.d/autofs/autod_nfs.c
+++ b/usr/src/cmd/fs.d/autofs/autod_nfs.c
@@ -74,9 +74,9 @@
#include "replica.h"
#include "nfs_subr.h"
#include "webnfs.h"
+#include "nfs_resolve.h"
#include <sys/sockio.h>
#include <net/if.h>
-#include <assert.h>
#include <rpcsvc/daemon_utils.h>
#include <pwd.h>
#include <strings.h>
@@ -91,11 +91,6 @@ extern enum snego_stat nfs_sec_nego();
#define MAXHOSTS 512
-/* number of transports to try */
-#define MNT_PREF_LISTLEN 2
-#define FIRST_TRY 1
-#define SECOND_TRY 2
-
#define MNTTYPE_CACHEFS "cachefs"
/*
@@ -134,9 +129,7 @@ static enum nfsstat nfsmount(struct mapfs *, char *, char *, int, int, uid_t,
action_list *);
static int is_nfs_port(char *);
-void netbuf_free(struct netbuf *);
-struct knetconfig *get_knconf(struct netconfig *);
-void free_knconf(struct knetconfig *);
+static void netbuf_free(struct netbuf *);
static int get_pathconf(CLIENT *, char *, char *, struct pathcnf **, int);
static struct mapfs *enum_servers(struct mapent *, char *);
static struct mapfs *get_mysubnet_servers(struct mapfs *);
@@ -156,12 +149,18 @@ enum type_of_stuff {
SERVER_FH = 2
};
-void *get_server_stuff(enum type_of_stuff, char *, rpcprog_t,
+static void *get_server_netinfo(enum type_of_stuff, char *, rpcprog_t,
rpcvers_t, mfs_snego_t *, struct netconfig **, char *, ushort_t,
struct t_info *, caddr_t *, bool_t, char *, enum clnt_stat *);
-
-void *get_the_stuff(enum type_of_stuff, char *, rpcprog_t,
- rpcvers_t, mfs_snego_t *, struct netconfig *, ushort_t, struct t_info *,
+static void *get_netconfig_info(enum type_of_stuff, char *, rpcprog_t,
+ rpcvers_t, struct netconfig *, ushort_t, struct t_info *,
+ struct t_bind *, caddr_t *, bool_t, char *, enum clnt_stat *,
+ mfs_snego_t *);
+static void *get_server_addrorping(char *, rpcprog_t, rpcvers_t,
+ struct netconfig *, ushort_t, struct t_info *, struct t_bind *,
+ caddr_t *, bool_t, char *, enum clnt_stat *, int);
+static void *get_server_fh(char *, rpcprog_t, rpcvers_t, mfs_snego_t *,
+ struct netconfig *, ushort_t, struct t_info *, struct t_bind *,
caddr_t *, bool_t, char *, enum clnt_stat *);
struct mapfs *add_mfs(struct mapfs *, int, struct mapfs **, struct mapfs **);
@@ -1877,13 +1876,14 @@ try_mnt_slash:
/*
* For NFSv4, we want to avoid rpcbind, so call
- * get_server_stuff() directly to tell it that
+ * get_server_netinfo() directly to tell it that
* we want to go "direct_to_server". Otherwise,
* do what has always been done.
*/
if (nfsvers == NFS_V4) {
enum clnt_stat cstat;
- argp->addr = get_server_stuff(SERVER_ADDR,
+
+ argp->addr = get_server_netinfo(SERVER_ADDR,
host, NFS_PROGRAM, nfsvers, NULL,
&nconf, nfs_proto, thisport, NULL,
NULL, TRUE, NULL, &cstat);
@@ -2010,7 +2010,7 @@ try_mnt_slash:
*
* Eventurally, we want to move this code to nfs_clnt_secdata()
* when autod_nfs.c and mount.c can share the same
- * get_the_addr/get_the_stuff routine.
+ * get_the_addr/get_netconfig_info routine.
*/
secflags = 0;
syncaddr = NULL;
@@ -2024,9 +2024,10 @@ try_mnt_slash:
*/
if ((mfs->mfs_flags & MFS_FH_VIA_WEBNFS) == 0 &&
nfsvers != NFS_V4) {
- syncaddr = get_the_stuff(SERVER_ADDR, host, RPCBPROG,
- RPCBVERS, NULL, nconf, 0, NULL, NULL, FALSE,
- NULL, NULL);
+ enum clnt_stat cstat;
+ syncaddr = get_server_netinfo(SERVER_ADDR,
+ host, RPCBPROG, RPCBVERS, NULL, &nconf,
+ NULL, 0, NULL, NULL, FALSE, NULL, &cstat);
}
if (syncaddr != NULL) {
@@ -2527,50 +2528,6 @@ get_pathconf(CLIENT *cl, char *path, char *fsname, struct pathcnf **pcnf,
return (RET_OK);
}
-struct knetconfig *
-get_knconf(nconf)
- struct netconfig *nconf;
-{
- struct stat stbuf;
- struct knetconfig *k;
-
- if (stat(nconf->nc_device, &stbuf) < 0) {
- syslog(LOG_ERR, "get_knconf: stat %s: %m", nconf->nc_device);
- return (NULL);
- }
- k = (struct knetconfig *)malloc(sizeof (*k));
- if (k == NULL)
- goto nomem;
- k->knc_semantics = nconf->nc_semantics;
- k->knc_protofmly = strdup(nconf->nc_protofmly);
- if (k->knc_protofmly == NULL)
- goto nomem;
- k->knc_proto = strdup(nconf->nc_proto);
- if (k->knc_proto == NULL)
- goto nomem;
- k->knc_rdev = stbuf.st_rdev;
-
- return (k);
-
-nomem:
- syslog(LOG_ERR, "get_knconf: no memory");
- free_knconf(k);
- return (NULL);
-}
-
-void
-free_knconf(k)
- struct knetconfig *k;
-{
- if (k == NULL)
- return;
- if (k->knc_protofmly)
- free(k->knc_protofmly);
- if (k->knc_proto)
- free(k->knc_proto);
- free(k);
-}
-
void
netbuf_free(nb)
struct netbuf *nb;
@@ -2833,393 +2790,6 @@ get_cached_srv_addr(char *hostname, rpcprog_t prog, rpcvers_t vers,
}
/*
- * Get the network address on "hostname" for program "prog"
- * with version "vers" by using the nconf configuration data
- * passed in.
- *
- * If the address of a netconfig pointer is null then
- * information is not sufficient and no netbuf will be returned.
- *
- * tinfo argument is for matching the get_the_addr() defined in
- * ../nfs/mount/mount.c
- */
-void *
-get_the_stuff(
- enum type_of_stuff type_of_stuff,
- char *hostname,
- rpcprog_t prog,
- rpcprog_t vers,
- mfs_snego_t *mfssnego,
- struct netconfig *nconf,
- ushort_t port,
- struct t_info *tinfo,
- caddr_t *fhp,
- bool_t direct_to_server,
- char *fspath,
- enum clnt_stat *cstat)
-
-{
- struct netbuf *nb = NULL;
- struct t_bind *tbind = NULL;
- int fd = -1;
- enum clnt_stat cs = RPC_TIMEDOUT;
- CLIENT *cl = NULL;
- struct timeval tv;
- AUTH *ah = NULL;
- AUTH *new_ah = NULL;
- struct snego_t snego;
-
- if (nconf == NULL) {
- goto done;
- }
-
- if (prog == NFS_PROGRAM && vers == NFS_V4)
- if (strncasecmp(nconf->nc_proto, NC_UDP, strlen(NC_UDP)) == 0)
- goto done;
-
- if ((fd = t_open(nconf->nc_device, O_RDWR, tinfo)) < 0) {
- goto done;
- }
-
- /* LINTED pointer alignment */
- if ((tbind = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR))
- == NULL) {
- goto done;
- }
-
- if (direct_to_server == TRUE) {
- struct nd_hostserv hs;
- struct nd_addrlist *retaddrs;
- hs.h_host = hostname;
-
- if (trace > 1)
- trace_prt(1, " get_the_stuff: %s call "
- "direct to server %s\n",
- type_of_stuff == SERVER_FH ? "pub fh" :
- type_of_stuff == SERVER_ADDR ? "get address" :
- type_of_stuff == SERVER_PING ? "ping" :
- "unknown", hostname);
- if (port == 0)
- hs.h_serv = "nfs";
- else
- hs.h_serv = NULL;
-
- if (netdir_getbyname(nconf, &hs, &retaddrs) != ND_OK) {
- goto done;
- }
- memcpy(tbind->addr.buf, retaddrs->n_addrs->buf,
- retaddrs->n_addrs->len);
- tbind->addr.len = retaddrs->n_addrs->len;
- netdir_free((void *)retaddrs, ND_ADDRLIST);
- if (port) {
- /* LINTED pointer alignment */
-
- if (strcmp(nconf->nc_protofmly, NC_INET) == NULL)
- ((struct sockaddr_in *)
- tbind->addr.buf)->sin_port =
- htons((ushort_t)port);
- else if (strcmp(nconf->nc_protofmly, NC_INET6) == NULL)
- ((struct sockaddr_in6 *)
- tbind->addr.buf)->sin6_port =
- htons((ushort_t)port);
- }
-
- if (type_of_stuff == SERVER_FH) {
- if (netdir_options(nconf, ND_SET_RESERVEDPORT, fd,
- NULL) == -1)
- if (trace > 1)
- trace_prt(1, "\tget_the_stuff: "
- "ND_SET_RESERVEDPORT(%s) "
- "failed\n", hostname);
- }
-
- cl = clnt_tli_create(fd, nconf, &tbind->addr, prog,
- vers, 0, 0);
-
- if (trace > 1)
- trace_prt(1, " get_the_stuff: clnt_tli_create(%s) "
- "returned %p\n", hostname, cl);
- if (cl == NULL)
- goto done;
-#ifdef MALLOC_DEBUG
- add_alloc("CLNT_HANDLE", cl, 0, __FILE__, __LINE__);
- add_alloc("AUTH_HANDLE", cl->cl_auth, 0,
- __FILE__, __LINE__);
-#endif
-
- switch (type_of_stuff) {
- case SERVER_FH:
- {
- enum snego_stat sec;
-
- ah = authsys_create_default();
- if (ah != NULL) {
-#ifdef MALLOC_DEBUG
- drop_alloc("AUTH_HANDLE", cl->cl_auth,
- __FILE__, __LINE__);
-#endif
- AUTH_DESTROY(cl->cl_auth);
- cl->cl_auth = ah;
-#ifdef MALLOC_DEBUG
- add_alloc("AUTH_HANDLE", cl->cl_auth, 0,
- __FILE__, __LINE__);
-#endif
- }
-
- if (!mfssnego->snego_done && vers != NFS_V4) {
- /*
- * 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 (mfssnego->sec_opt) {
- for (jj = 0; jj < snego.cnt; jj++) {
- if (snego.array[jj] ==
- mfssnego->nfs_sec.sc_nfsnum) {
- mfssnego->snego_done = TRUE;
- break;
- }
- }
- }
-
- /*
- * find a common sec flavor
- */
- if (!mfssnego->snego_done) {
- for (jj = 0; jj < snego.cnt; jj++) {
- if (!nfs_getseconfig_bynumber(
- snego.array[jj], &mfssnego->nfs_sec)) {
- mfssnego->snego_done = TRUE;
- break;
- }
- }
- }
- if (!mfssnego->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,
- &mfssnego->nfs_sec);
- if (new_ah == NULL)
- goto done;
-#ifdef MALLOC_DEBUG
- drop_alloc("AUTH_HANDLE", cl->cl_auth,
- __FILE__, __LINE__);
-#endif
- AUTH_DESTROY(cl->cl_auth);
- cl->cl_auth = new_ah;
-#ifdef MALLOC_DEBUG
- add_alloc("AUTH_HANDLE", cl->cl_auth, 0,
- __FILE__, __LINE__);
-#endif
- } else if (sec == SNEGO_ARRAY_TOO_SMALL ||
- sec == SNEGO_FAILURE) {
- goto done;
- }
- /*
- * Note that if sec == SNEGO_DEF_VALID
- * the default sec flavor is acceptable.
- * Use it to get the filehandle.
- */
- }
- }
-
- switch (vers) {
- case NFS_VERSION:
- {
- wnl_diropargs arg;
- wnl_diropres res;
-
- memset((char *)&arg.dir, 0, sizeof (wnl_fh));
- memset((char *)&res, 0, sizeof (wnl_diropres));
- arg.name = fspath;
- if (wnlproc_lookup_2(&arg, &res, cl) !=
- RPC_SUCCESS || res.status != NFS_OK)
- goto done;
- *fhp = malloc(sizeof (wnl_fh));
-
- if (*fhp == NULL) {
- syslog(LOG_ERR, "no memory\n");
- goto done;
- }
-
- memcpy((char *)*fhp,
- (char *)&res.wnl_diropres_u.wnl_diropres.file,
- sizeof (wnl_fh));
- cs = RPC_SUCCESS;
- }
- break;
- case NFS_V3:
- {
- WNL_LOOKUP3args arg;
- WNL_LOOKUP3res res;
- nfs_fh3 *fh3p;
-
- memset((char *)&arg.what.dir, 0, sizeof (wnl_fh3));
- memset((char *)&res, 0, sizeof (WNL_LOOKUP3res));
- arg.what.name = fspath;
- if (wnlproc3_lookup_3(&arg, &res, cl) !=
- RPC_SUCCESS || res.status != NFS3_OK)
- goto done;
-
- fh3p = (nfs_fh3 *)malloc(sizeof (*fh3p));
-
- if (fh3p == NULL) {
- syslog(LOG_ERR, "no memory\n");
- 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;
-
- cs = RPC_SUCCESS;
- }
- break;
- case NFS_V4:
- tv.tv_sec = 10;
- tv.tv_usec = 0;
- cs = clnt_call(cl, NULLPROC, xdr_void, 0,
- xdr_void, 0, tv);
- if (cs != RPC_SUCCESS)
- goto done;
- *fhp = strdup(fspath);
- break;
- }
- break;
- case SERVER_ADDR:
- case SERVER_PING:
- tv.tv_sec = 10;
- tv.tv_usec = 0;
- cs = clnt_call(cl, NULLPROC, xdr_void, 0,
- xdr_void, 0, tv);
- if (trace > 1)
- trace_prt(1,
- "get_the_stuff: clnt_call(%s) "
- "returned %s\n",
- hostname,
- cs == RPC_SUCCESS ? "success" :
- "failure");
-
- if (cs != RPC_SUCCESS)
- goto done;
- break;
- }
-
- } else if (type_of_stuff != SERVER_FH) {
-
- if (type_of_stuff == SERVER_ADDR) {
- if (get_cached_srv_addr(hostname, prog, vers, nconf,
- &tbind->addr) == 0)
- goto done;
- }
-
- if (port) {
- /* LINTED pointer alignment */
- if (strcmp(nconf->nc_protofmly, NC_INET) == NULL)
- ((struct sockaddr_in *)
- tbind->addr.buf)->sin_port =
- htons((ushort_t)port);
- else if (strcmp(nconf->nc_protofmly, NC_INET6) == NULL)
- ((struct sockaddr_in6 *)
- tbind->addr.buf)->sin6_port =
- htons((ushort_t)port);
- cl = clnt_tli_create(fd, nconf, &tbind->addr,
- prog, vers, 0, 0);
- if (cl == NULL)
- goto done;
-#ifdef MALLOC_DEBUG
- add_alloc("CLNT_HANDLE", cl, 0, __FILE__, __LINE__);
- add_alloc("AUTH_HANDLE", cl->cl_auth, 0,
- __FILE__, __LINE__);
-#endif
- tv.tv_sec = 10;
- tv.tv_usec = 0;
- cs = clnt_call(cl, NULLPROC, xdr_void, 0, xdr_void,
- 0, tv);
- if (cs != RPC_SUCCESS)
- goto done;
- }
-
- } else {
- /* can't happen */
- goto done;
- }
-
- if (type_of_stuff != SERVER_PING) {
-
- cs = RPC_SYSTEMERROR;
-
- /*
- * Make a copy of the netbuf to return
- */
- nb = (struct netbuf *)malloc(sizeof (struct netbuf));
- if (nb == NULL) {
- syslog(LOG_ERR, "no memory\n");
- goto done;
- }
- *nb = tbind->addr;
- nb->buf = (char *)malloc(nb->maxlen);
- if (nb->buf == NULL) {
- syslog(LOG_ERR, "no memory\n");
- free(nb);
- nb = NULL;
- goto done;
- }
- (void) memcpy(nb->buf, tbind->addr.buf, tbind->addr.len);
-
- cs = RPC_SUCCESS;
- }
-
-done:
- if (cl != NULL) {
- if (ah != NULL) {
-#ifdef MALLOC_DEBUG
- drop_alloc("AUTH_HANDLE", cl->cl_auth,
- __FILE__, __LINE__);
-#endif
- AUTH_DESTROY(cl->cl_auth);
- cl->cl_auth = NULL;
- }
-#ifdef MALLOC_DEBUG
- drop_alloc("CLNT_HANDLE", cl, __FILE__, __LINE__);
-#endif
- clnt_destroy(cl);
- }
-
- if (tbind) {
- t_free((char *)tbind, T_BIND);
- tbind = NULL;
- }
-
- if (fd >= 0)
- (void) t_close(fd);
-
- if (cstat != NULL)
- *cstat = cs;
-
- return (nb);
-}
-
-/*
* Get a network address on "hostname" for program "prog"
* with version "vers". If the port number is specified (non zero)
* then try for a TCP/UDP transport and set the port number of the
@@ -3242,7 +2812,7 @@ get_addr(char *hostname, rpcprog_t prog, rpcvers_t vers,
{
enum clnt_stat cstat;
- return (get_server_stuff(SERVER_ADDR, hostname, prog, vers, NULL,
+ return (get_server_netinfo(SERVER_ADDR, hostname, prog, vers, NULL,
nconfp, proto, port, tinfo, NULL, FALSE, NULL, &cstat));
}
@@ -3253,7 +2823,7 @@ get_pubfh(char *hostname, rpcvers_t vers, mfs_snego_t *mfssnego,
{
enum clnt_stat cstat;
- return (get_server_stuff(SERVER_FH, hostname, NFS_PROGRAM, vers,
+ return (get_server_netinfo(SERVER_FH, hostname, NFS_PROGRAM, vers,
mfssnego, nconfp, proto, port, tinfo, fhp, get_pubfh, fspath,
&cstat));
}
@@ -3264,14 +2834,15 @@ get_ping(char *hostname, rpcprog_t prog, rpcvers_t vers,
{
enum clnt_stat cstat;
- (void) get_server_stuff(SERVER_PING, hostname, prog, vers, NULL, nconfp,
- NULL, port, NULL, NULL, direct_to_server, NULL, &cstat);
+ (void) get_server_netinfo(SERVER_PING, hostname, prog,
+ vers, NULL, nconfp, NULL, port, NULL, NULL,
+ direct_to_server, NULL, &cstat);
return (cstat);
}
void *
-get_server_stuff(
+get_server_netinfo(
enum type_of_stuff type_of_stuff,
char *hostname,
rpcprog_t prog,
@@ -3289,13 +2860,16 @@ get_server_stuff(
struct netbuf *nb = NULL;
struct netconfig *nconf = NULL;
NCONF_HANDLE *nc = NULL;
+ int error = 0;
+ int fd = 0;
+ struct t_bind *tbind = NULL;
int nthtry = FIRST_TRY;
- if (nconfp && *nconfp)
- return (get_the_stuff(type_of_stuff, hostname, prog, vers,
- mfssnego, *nconfp, port, tinfo, fhp, direct_to_server,
- fspath, cstatp));
-
+ if (nconfp && *nconfp) {
+ return (get_netconfig_info(type_of_stuff, hostname,
+ prog, vers, nconf, port, tinfo, tbind, fhp,
+ direct_to_server, fspath, cstatp, mfssnego));
+ }
/*
* No nconf passed in.
@@ -3314,8 +2888,7 @@ get_server_stuff(
* otherwise try COTS first, if failed, then try CLTS.
*/
if (proto) {
-
- while (nconf = getnetpath(nc)) {
+ while ((nconf = getnetpath(nc)) != NULL) {
if (strcmp(nconf->nc_proto, proto))
continue;
/*
@@ -3329,24 +2902,20 @@ get_server_stuff(
strcmp(nconf->nc_proto, NC_UDP)))
continue;
}
-
- nb = get_the_stuff(type_of_stuff, hostname, prog, vers,
- mfssnego, nconf, port, tinfo, fhp,
- direct_to_server, fspath, cstatp);
-
+ nb = get_netconfig_info(type_of_stuff, hostname,
+ prog, vers, nconf, port, tinfo, tbind, fhp,
+ direct_to_server, fspath, cstatp, mfssnego);
if (*cstatp == RPC_SUCCESS)
break;
assert(nb == NULL);
- } /* end of while */
-
+ }
if (nconf == NULL)
goto done;
-
} else {
retry:
- while (nconf = getnetpath(nc)) {
+ while ((nconf = getnetpath(nc)) != NULL) {
if (nconf->nc_flag & NC_VISIBLE) {
if (nthtry == FIRST_TRY) {
if ((nconf->nc_semantics ==
@@ -3379,7 +2948,8 @@ retry:
}
}
}
- } /* while */
+ }
+
if (nconf == NULL) {
if (++nthtry <= MNT_PREF_LISTLEN) {
endnetpath(nc);
@@ -3389,9 +2959,9 @@ retry:
} else
goto done;
} else {
- nb = get_the_stuff(type_of_stuff, hostname, prog, vers,
- mfssnego, nconf, port, tinfo, fhp, direct_to_server,
- fspath, cstatp);
+ nb = get_netconfig_info(type_of_stuff, hostname,
+ prog, vers, nconf, port, tinfo, tbind, fhp,
+ direct_to_server, fspath, cstatp, mfssnego);
if (*cstatp != RPC_SUCCESS)
/*
* Continue the same search path in the
@@ -3400,17 +2970,20 @@ retry:
*/
goto retry;
}
- } /* if !proto */
+ }
/*
* Got nconf and nb. Now dup the netconfig structure (nconf)
* and return it thru nconfp.
*/
- *nconfp = getnetconfigent(nconf->nc_netid);
- if (*nconfp == NULL) {
- syslog(LOG_ERR, "no memory\n");
- free(nb);
- nb = NULL;
+ if (nconf != NULL) {
+ if ((*nconfp = getnetconfigent(nconf->nc_netid)) == NULL) {
+ syslog(LOG_ERR, "no memory\n");
+ free(nb);
+ nb = NULL;
+ }
+ } else {
+ *nconfp = NULL;
}
done:
if (nc)
@@ -3418,6 +2991,221 @@ done:
return (nb);
}
+void *
+get_server_fh(char *hostname, rpcprog_t prog, rpcvers_t vers,
+ mfs_snego_t *mfssnego, struct netconfig *nconf, ushort_t port,
+ struct t_info *tinfo, struct t_bind *tbind, caddr_t *fhp,
+ bool_t direct_to_server, char *fspath, enum clnt_stat *cstat)
+{
+ AUTH *ah = NULL;
+ AUTH *new_ah = NULL;
+ struct snego_t snego;
+ enum clnt_stat cs = RPC_TIMEDOUT;
+ struct timeval tv;
+ bool_t file_handle = 1;
+ enum snego_stat sec;
+ CLIENT *cl = NULL;
+ int fd = -1;
+ struct netbuf *nb = NULL;
+
+ if (direct_to_server != TRUE)
+ return (NULL);
+
+ if (prog == NFS_PROGRAM && vers == NFS_V4)
+ if (strncasecmp(nconf->nc_proto, NC_UDP, strlen(NC_UDP)) == 0)
+ goto done;
+
+ if ((fd = t_open(nconf->nc_device, O_RDWR, tinfo)) < 0)
+ goto done;
+
+ /* LINTED pointer alignment */
+ if ((tbind = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR)) == NULL)
+ goto done;
+
+ if (setup_nb_parms(nconf, tbind, tinfo, hostname, fd,
+ direct_to_server, port, prog, vers, file_handle) < 0) {
+ goto done;
+ }
+
+ cl = clnt_tli_create(fd, nconf, &tbind->addr, prog, vers, 0, 0);
+ if (cl == NULL)
+ goto done;
+
+ ah = authsys_create_default();
+ if (ah != NULL) {
+#ifdef MALLOC_DEBUG
+ drop_alloc("AUTH_HANDLE", cl->cl_auth,
+ __FILE__, __LINE__);
+#endif
+ AUTH_DESTROY(cl->cl_auth);
+ cl->cl_auth = ah;
+#ifdef MALLOC_DEBUG
+ add_alloc("AUTH_HANDLE", cl->cl_auth, 0,
+ __FILE__, __LINE__);
+#endif
+ }
+
+ if (!mfssnego->snego_done && vers != NFS_V4) {
+ /*
+ * 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 (mfssnego->sec_opt) {
+ for (jj = 0; jj < snego.cnt; jj++) {
+ if (snego.array[jj] ==
+ mfssnego->nfs_sec.sc_nfsnum) {
+ mfssnego->snego_done = TRUE;
+ break;
+ }
+ }
+ }
+
+ /*
+ * find a common sec flavor
+ */
+ if (!mfssnego->snego_done) {
+ for (jj = 0; jj < snego.cnt; jj++) {
+ if (!nfs_getseconfig_bynumber(
+ snego.array[jj],
+ &mfssnego->nfs_sec)) {
+ mfssnego->snego_done = TRUE;
+ break;
+ }
+ }
+ }
+ if (!mfssnego->snego_done)
+ goto done;
+ /*
+ * 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,
+ &mfssnego->nfs_sec);
+ if (new_ah == NULL)
+ goto done;
+#ifdef MALLOC_DEBUG
+ drop_alloc("AUTH_HANDLE", cl->cl_auth,
+ __FILE__, __LINE__);
+#endif
+ AUTH_DESTROY(cl->cl_auth);
+ cl->cl_auth = new_ah;
+#ifdef MALLOC_DEBUG
+ add_alloc("AUTH_HANDLE", cl->cl_auth, 0,
+ __FILE__, __LINE__);
+#endif
+ } else if (sec == SNEGO_ARRAY_TOO_SMALL ||
+ sec == SNEGO_FAILURE) {
+ goto done;
+ }
+ }
+
+ switch (vers) {
+ case NFS_VERSION:
+ {
+ wnl_diropargs arg;
+ wnl_diropres res;
+
+ memset((char *)&arg.dir, 0, sizeof (wnl_fh));
+ memset((char *)&res, 0, sizeof (wnl_diropres));
+ arg.name = fspath;
+ if (wnlproc_lookup_2(&arg, &res, cl) !=
+ RPC_SUCCESS || res.status != NFS_OK)
+ goto done;
+ *fhp = malloc(sizeof (wnl_fh));
+
+ if (*fhp == NULL) {
+ syslog(LOG_ERR, "no memory\n");
+ goto done;
+ }
+
+ memcpy((char *)*fhp,
+ (char *)&res.wnl_diropres_u.wnl_diropres.file,
+ sizeof (wnl_fh));
+ cs = RPC_SUCCESS;
+ }
+ break;
+ case NFS_V3:
+ {
+ WNL_LOOKUP3args arg;
+ WNL_LOOKUP3res res;
+ nfs_fh3 *fh3p;
+
+ memset((char *)&arg.what.dir, 0, sizeof (wnl_fh3));
+ memset((char *)&res, 0, sizeof (WNL_LOOKUP3res));
+ arg.what.name = fspath;
+ if (wnlproc3_lookup_3(&arg, &res, cl) !=
+ RPC_SUCCESS || res.status != NFS3_OK)
+ goto done;
+
+ fh3p = (nfs_fh3 *)malloc(sizeof (*fh3p));
+
+ if (fh3p == NULL) {
+ syslog(LOG_ERR, "no memory\n");
+ 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;
+
+ cs = RPC_SUCCESS;
+ }
+ break;
+ case NFS_V4:
+ tv.tv_sec = 10;
+ tv.tv_usec = 0;
+ cs = clnt_call(cl, NULLPROC, xdr_void, 0,
+ xdr_void, 0, tv);
+ if (cs != RPC_SUCCESS)
+ goto done;
+
+ *fhp = strdup(fspath);
+ if (fhp == NULL) {
+ cs = RPC_SYSTEMERROR;
+ goto done;
+ }
+ break;
+ }
+ nb = (struct netbuf *)malloc(sizeof (struct netbuf));
+ if (nb == NULL) {
+ syslog(LOG_ERR, "no memory\n");
+ cs = RPC_SYSTEMERROR;
+ goto done;
+ }
+ nb->buf = (char *)malloc(tbind->addr.maxlen);
+ if (nb->buf == NULL) {
+ syslog(LOG_ERR, "no memory\n");
+ free(nb);
+ nb = NULL;
+ cs = RPC_SYSTEMERROR;
+ goto done;
+ }
+ (void) memcpy(nb->buf, tbind->addr.buf, tbind->addr.len);
+ nb->len = tbind->addr.len;
+ nb->maxlen = tbind->addr.maxlen;
+done:
+ if (cstat != NULL)
+ *cstat = cs;
+ destroy_auth_client_handle(cl);
+ cleanup_tli_parms(tbind, fd);
+ return (nb);
+}
/*
* Sends a null call to the remote host's (NFS program, versp). versp
@@ -4535,3 +4323,121 @@ free_nfs_args(struct nfs_args *argp)
free(oldp);
}
}
+
+void *
+get_netconfig_info(enum type_of_stuff type_of_stuff, char *hostname,
+ rpcprog_t prog, rpcvers_t vers, struct netconfig *nconf,
+ ushort_t port, struct t_info *tinfo, struct t_bind *tbind,
+ caddr_t *fhp, bool_t direct_to_server, char *fspath,
+ enum clnt_stat *cstat, mfs_snego_t *mfssnego)
+{
+ struct netconfig *nb = NULL;
+ int ping_server = 0;
+
+
+ if (nconf == NULL)
+ return (NULL);
+
+ switch (type_of_stuff) {
+ case SERVER_FH:
+ nb = get_server_fh(hostname, prog, vers, mfssnego,
+ nconf, port, tinfo, tbind, fhp, direct_to_server,
+ fspath, cstat);
+ break;
+ case SERVER_PING:
+ ping_server = 1;
+ case SERVER_ADDR:
+ nb = get_server_addrorping(hostname, prog, vers,
+ nconf, port, tinfo, tbind, fhp, direct_to_server,
+ fspath, cstat, ping_server);
+ break;
+ default:
+ assert(nb != NULL);
+ }
+ return (nb);
+}
+
+/*
+ * Get the server address or can we ping it or not.
+ * Check the portmap cache first for server address.
+ * If no entries there, ping the server with a NULLPROC rpc.
+ */
+void *
+get_server_addrorping(char *hostname, rpcprog_t prog, rpcvers_t vers,
+ struct netconfig *nconf, ushort_t port, struct t_info *tinfo,
+ struct t_bind *tbind, caddr_t *fhp, bool_t direct_to_server,
+ char *fspath, enum clnt_stat *cstat, int ping_server)
+{
+ struct timeval tv;
+ enum clnt_stat cs = RPC_TIMEDOUT;
+ struct netbuf *nb = NULL;
+ CLIENT *cl = NULL;
+ int fd = -1;
+
+ if (prog == NFS_PROGRAM && vers == NFS_V4)
+ if (strncasecmp(nconf->nc_proto, NC_UDP, strlen(NC_UDP)) == 0)
+ goto done;
+
+ if ((fd = t_open(nconf->nc_device, O_RDWR, tinfo)) < 0) {
+ goto done;
+ }
+
+ /* LINTED pointer alignment */
+ if ((tbind = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR))
+ == NULL) {
+ goto done;
+ }
+
+ if (direct_to_server != TRUE) {
+ if (!ping_server) {
+ if (get_cached_srv_addr(hostname, prog, vers,
+ nconf, &tbind->addr) == 0)
+ goto done;
+ } else {
+ if (port == 0)
+ goto done;
+ }
+ }
+ if (setup_nb_parms(nconf, tbind, tinfo, hostname,
+ fd, direct_to_server, port, prog, vers, 0) < 0)
+ goto done;
+
+ if (port || (direct_to_server == TRUE)) {
+ tv.tv_sec = 10;
+ tv.tv_usec = 0;
+ cl = clnt_tli_create(fd, nconf, &tbind->addr,
+ prog, vers, 0, 0);
+ if (cl == NULL)
+ goto done;
+
+ cs = clnt_call(cl, NULLPROC, xdr_void, 0,
+ xdr_void, 0, tv);
+ if (cs != RPC_SUCCESS) {
+ syslog(LOG_ERR, "error is %d", cs);
+ goto done;
+ }
+ }
+ if (!ping_server) {
+ nb = (struct netbuf *)malloc(sizeof (struct netbuf));
+ if (nb == NULL) {
+ syslog(LOG_ERR, "no memory\n");
+ goto done;
+ }
+ nb->buf = (char *)malloc(tbind->addr.maxlen);
+ if (nb->buf == NULL) {
+ syslog(LOG_ERR, "no memory\n");
+ free(nb);
+ nb = NULL;
+ goto done;
+ }
+ (void) memcpy(nb->buf, tbind->addr.buf, tbind->addr.len);
+ nb->len = tbind->addr.len;
+ nb->maxlen = tbind->addr.maxlen;
+ cs = RPC_SUCCESS;
+ }
+done:
+ destroy_auth_client_handle(cl);
+ cleanup_tli_parms(tbind, fd);
+ *cstat = cs;
+ return (nb);
+}
diff --git a/usr/src/cmd/fs.d/autofs/autod_xdr.c b/usr/src/cmd/fs.d/autofs/autod_xdr.c
index 262a518eff..221ebcd2ce 100644
--- a/usr/src/cmd/fs.d/autofs/autod_xdr.c
+++ b/usr/src/cmd/fs.d/autofs/autod_xdr.c
@@ -21,12 +21,10 @@
/*
* autod_xdr.c
*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* This file can not be automatically generated by rpcgen from
* autofs_prot.x because of the xdr routines that provide readdir
@@ -37,6 +35,8 @@
#include <sys/sysmacros.h> /* includes roundup() */
#include <string.h>
#include <rpcsvc/autofs_prot.h>
+#include <nfs/nfs4.h>
+#include <rpcsvc/nfs4_prot.h>
#include <rpc/xdr.h>
#include <stdlib.h>
#include <strings.h>
diff --git a/usr/src/cmd/fs.d/nfs/Makefile b/usr/src/cmd/fs.d/nfs/Makefile
index 9d737f3004..4687ae9d04 100644
--- a/usr/src/cmd/fs.d/nfs/Makefile
+++ b/usr/src/cmd/fs.d/nfs/Makefile
@@ -19,9 +19,8 @@
# CDDL HEADER END
#
#
-#ident "%Z%%M% %I% %E% SMI"
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# cmd/fs.d/nfs/Makefile
@@ -36,7 +35,8 @@ SUBDIR1= exportfs nfsd rquotad \
statd nfsstat mountd dfshares \
nfsfind nfs4cbd share
SUBDIR2= clear_locks umount showmount \
- mount dfmounts nfslog nfsmapid
+ mount dfmounts nfslog nfsmapid \
+ nfsref rp_basic
SUBDIR3= etc svc
SUBDIRS= $(SUBDIR1) $(SUBDIR2) $(SUBDIR3)
diff --git a/usr/src/cmd/fs.d/nfs/lib/nfs_resolve.c b/usr/src/cmd/fs.d/nfs/lib/nfs_resolve.c
new file mode 100644
index 0000000000..4951afd001
--- /dev/null
+++ b/usr/src/cmd/fs.d/nfs/lib/nfs_resolve.c
@@ -0,0 +1,386 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+/*
+ * Helper routines for nfsmapid and autod daemon
+ * to translate hostname to IP address and Netinfo.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <alloca.h>
+#include <signal.h>
+#include <libintl.h>
+#include <limits.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <string.h>
+#include <memory.h>
+#include <pwd.h>
+#include <grp.h>
+#include <door.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <assert.h>
+#include <deflt.h>
+#include <netdir.h>
+#include <nfs/nfs4.h>
+#include <nfs/nfssys.h>
+#include <nfs/nfsid_map.h>
+#include <nfs/mapid.h>
+#include <nfs/nfs_sec.h>
+#include <sys/sdt.h>
+#include <sys/idmap.h>
+#include <idmap.h>
+#include <sys/fs/autofs.h>
+#include "nfs_resolve.h"
+
+void
+free_knconf(struct knetconfig *k)
+{
+ if (k == NULL)
+ return;
+ if (k->knc_protofmly)
+ free(k->knc_protofmly);
+ if (k->knc_proto)
+ free(k->knc_proto);
+ free(k);
+}
+
+struct knetconfig *
+get_knconf(struct netconfig *nconf)
+{
+ struct stat stbuf;
+ struct knetconfig *k = NULL;
+ int len;
+
+ if (stat(nconf->nc_device, &stbuf) < 0) {
+ syslog(LOG_ERR, "get_knconf: stat %s: %m", nconf->nc_device);
+ return (NULL);
+ }
+ k = (struct knetconfig *)malloc(sizeof (*k));
+ if (k == NULL)
+ goto nomem;
+ k->knc_semantics = nconf->nc_semantics;
+
+ len = strlen(nconf->nc_protofmly);
+ if (len <= 0)
+ goto err_out;
+ k->knc_protofmly = malloc(KNC_STRSIZE);
+ if (k->knc_protofmly == NULL)
+ goto nomem;
+ bzero(k->knc_protofmly, KNC_STRSIZE);
+ bcopy(nconf->nc_protofmly, k->knc_protofmly, len);
+
+ len = strlen(nconf->nc_proto);
+ if (len <= 0)
+ goto err_out;
+ k->knc_proto = malloc(KNC_STRSIZE);
+ if (k->knc_proto == NULL)
+ goto nomem;
+ bzero(k->knc_proto, KNC_STRSIZE);
+ bcopy(nconf->nc_proto, k->knc_proto, len);
+
+ k->knc_rdev = stbuf.st_rdev;
+
+ return (k);
+
+nomem:
+ syslog(LOG_ERR, "get_knconf: no memory");
+err_out:
+ if (k != NULL)
+ (void) free_knconf(k);
+ return (NULL);
+}
+
+/*
+ * Get the information needed for an NFSv4.x referral. This
+ * information includes the netbuf, netname and knconfig.
+ */
+struct nfs_fsl_info *
+get_nfs4ref_info(char *host, int port, int nfsver)
+{
+ char netname[MAXNETNAMELEN + 1];
+ enum clnt_stat cstat;
+ struct nfs_fsl_info *fsl_retp = NULL;
+ struct netconfig *netconf = NULL;
+ char *nametemp, *namex = NULL;
+ struct netbuf *nb = NULL;
+ NCONF_HANDLE *nc = NULL;
+
+ fsl_retp = calloc(1, sizeof (struct nfs_fsl_info));
+ if (fsl_retp == NULL) {
+ syslog(LOG_ERR, "get_nfs4ref_info: no memory\n");
+ return (NULL);
+ }
+
+ nametemp = malloc(MAXNETNAMELEN + 1);
+ if (nametemp == NULL) {
+ free(fsl_retp);
+ return (NULL);
+ }
+ host2netname(nametemp, host, NULL);
+ namex = calloc(1, strlen(nametemp) + 1);
+ if (namex == NULL) {
+ free(nametemp);
+ free(fsl_retp);
+ return (NULL);
+ }
+ strncpy(namex, nametemp, strlen(nametemp));
+ free(nametemp);
+ fsl_retp->netname = namex;
+ fsl_retp->netnm_len = strlen(namex) + 1;
+
+ fsl_retp->addr = resolve_netconf(host, NFS_PROGRAM, nfsver,
+ &netconf, port, NULL, NULL, TRUE, NULL, &cstat);
+
+ if (netconf == NULL || fsl_retp->addr == NULL)
+ goto done;
+
+ fsl_retp->knconf = get_knconf(netconf);
+ if (fsl_retp->knconf == NULL)
+ goto done;
+ fsl_retp->knconf_len = (sizeof (struct knetconfig) +
+ (KNC_STRSIZE * 2));
+ fsl_retp->netbuf_len = (sizeof (struct netbuf) +
+ fsl_retp->addr->maxlen);
+ return (fsl_retp);
+done:
+ free_nfs4ref_info(fsl_retp);
+ return (NULL);
+}
+
+void
+free_nfs4ref_info(struct nfs_fsl_info *fsl_retp)
+{
+ if (fsl_retp == NULL)
+ return;
+ free_knconf(fsl_retp->knconf);
+ free(fsl_retp->netname);
+ if (fsl_retp->addr != NULL) {
+ free(fsl_retp->addr->buf);
+ free(fsl_retp->addr);
+ }
+ free(fsl_retp);
+}
+
+void
+cleanup_tli_parms(struct t_bind *tbind, int fd)
+{
+ if (tbind != NULL) {
+ t_free((char *)tbind, T_BIND);
+ tbind = NULL;
+ }
+ if (fd >= 0)
+ (void) t_close(fd);
+ fd = -1;
+}
+
+struct netbuf *
+resolve_netconf(char *host, rpcprog_t prog, rpcvers_t nfsver,
+ struct netconfig **netconf, ushort_t port,
+ struct t_info *tinfo, caddr_t *fhp, bool_t direct_to_server,
+ char *fspath, enum clnt_stat *cstatp)
+{
+ NCONF_HANDLE *nc;
+ struct netconfig *nconf = NULL;
+ int nthtry = FIRST_TRY;
+ struct netbuf *nb;
+ enum clnt_stat cstat;
+
+ nc = setnetpath();
+ if (nc == NULL)
+ goto done;
+retry:
+ while (nconf = getnetpath(nc)) {
+ 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 ((strcmp(nconf->nc_protofmly,
+ NC_INET) == 0 ||
+ strcmp(nconf->nc_protofmly,
+ NC_INET6) == 0) &&
+ (strcmp(nconf->nc_proto,
+ NC_TCP) == 0))
+ 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;
+ }
+ }
+ }
+ } /* while */
+ if (nconf == NULL) {
+ if (++nthtry <= MNT_PREF_LISTLEN) {
+ endnetpath(nc);
+ if ((nc = setnetpath()) == NULL)
+ goto done;
+ goto retry;
+ } else
+ return (NULL);
+ } else {
+ nb = get_server_addr(host, NFS_PROGRAM, nfsver,
+ nconf, port, NULL, NULL, TRUE, NULL, &cstat);
+ if (cstat != RPC_SUCCESS)
+ goto retry;
+ }
+done:
+ *netconf = nconf;
+ *cstatp = cstat;
+ if (nc)
+ endnetpath(nc);
+ return (nb);
+}
+
+int
+setup_nb_parms(struct netconfig *nconf, struct t_bind *tbind,
+ struct t_info *tinfo, char *hostname, int fd, bool_t direct_to_server,
+ ushort_t port, rpcprog_t prog, rpcvers_t vers, bool_t file_handle)
+{
+ if (nconf == NULL) {
+ return (-1);
+ }
+ if (direct_to_server == TRUE) {
+ struct nd_hostserv hs;
+ struct nd_addrlist *retaddrs;
+ hs.h_host = hostname;
+
+ if (port == 0)
+ hs.h_serv = "nfs";
+ else
+ hs.h_serv = NULL;
+
+ if (netdir_getbyname(nconf, &hs, &retaddrs) != ND_OK) {
+ return (-1);
+ }
+ memcpy(tbind->addr.buf, retaddrs->n_addrs->buf,
+ retaddrs->n_addrs->len);
+ tbind->addr.len = retaddrs->n_addrs->len;
+ tbind->addr.maxlen = retaddrs->n_addrs->maxlen;
+ netdir_free((void *)retaddrs, ND_ADDRLIST);
+ if (port) {
+ /* LINTED pointer alignment */
+ if (strcmp(nconf->nc_protofmly, NC_INET) == NULL)
+ ((struct sockaddr_in *)
+ tbind->addr.buf)->sin_port =
+ htons((ushort_t)port);
+ else if (strcmp(nconf->nc_protofmly, NC_INET6) == NULL)
+ ((struct sockaddr_in6 *)
+ tbind->addr.buf)->sin6_port =
+ htons((ushort_t)port);
+ }
+
+ if (file_handle) {
+ if (netdir_options(nconf, ND_SET_RESERVEDPORT, fd,
+ NULL) == -1)
+ return (-1);
+ }
+ } else if (!file_handle) {
+ if (port) {
+ /* LINTED pointer alignment */
+ if (strcmp(nconf->nc_protofmly, NC_INET) == NULL)
+ ((struct sockaddr_in *)
+ tbind->addr.buf)->sin_port =
+ htons((ushort_t)port);
+ else if (strcmp(nconf->nc_protofmly, NC_INET6) == NULL)
+ ((struct sockaddr_in6 *)
+ tbind->addr.buf)->sin6_port =
+ htons((ushort_t)port);
+ }
+ } else {
+ return (-1);
+ }
+ return (1);
+}
+
+/*
+ * Sets up TLI interface and finds the address withe netdir_getbyname().
+ * returns the address returned from the call.
+ * Caller frees up the memory allocated here.
+ */
+struct netbuf *
+get_server_addr(char *hostname, rpcprog_t prog, rpcvers_t vers,
+ struct netconfig *nconf, ushort_t port,
+ struct t_info *tinfo, caddr_t *fhp, bool_t direct_to_server,
+ char *fspath, enum clnt_stat *cstat)
+{
+ int fd = -1;
+ struct t_bind *tbind = NULL;
+ enum clnt_stat cs = RPC_SYSTEMERROR;
+ struct netbuf *nb = NULL;
+ int ret = -1;
+
+ if (prog == NFS_PROGRAM && vers == NFS_V4)
+ if (strncasecmp(nconf->nc_proto, NC_UDP, strlen(NC_UDP)) == 0)
+ goto done;
+
+ if ((fd = t_open(nconf->nc_device, O_RDWR, tinfo)) < 0)
+ goto done;
+
+ if ((tbind = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR)) == NULL)
+ goto done;
+
+ if (setup_nb_parms(nconf, tbind, tinfo, hostname, fd, direct_to_server,
+ port, prog, vers, 0) < 0)
+ goto done;
+
+ nb = (struct netbuf *)malloc(sizeof (struct netbuf));
+ if (nb == NULL) {
+ syslog(LOG_ERR, "no memory\n");
+ goto done;
+ }
+ nb->buf = (char *)malloc(tbind->addr.maxlen);
+ if (nb->buf == NULL) {
+ syslog(LOG_ERR, "no memory\n");
+ free(nb);
+ nb = NULL;
+ goto done;
+ }
+ (void) memcpy(nb->buf, tbind->addr.buf, tbind->addr.len);
+ nb->len = tbind->addr.len;
+ nb->maxlen = tbind->addr.maxlen;
+ cs = RPC_SUCCESS;
+done:
+ *cstat = cs;
+ cleanup_tli_parms(tbind, fd);
+ return (nb);
+}
diff --git a/usr/src/cmd/fs.d/nfs/lib/nfs_resolve.h b/usr/src/cmd/fs.d/nfs/lib/nfs_resolve.h
new file mode 100644
index 0000000000..0b3055c123
--- /dev/null
+++ b/usr/src/cmd/fs.d/nfs/lib/nfs_resolve.h
@@ -0,0 +1,50 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _NFS_RESOLVE_H
+#define _NFS_RESOLVE_H
+
+/* number of transports to try */
+#define MNT_PREF_LISTLEN 2
+#define FIRST_TRY 1
+#define SECOND_TRY 2
+
+extern struct knetconfig *get_knconf(struct netconfig *);
+extern void free_knconf(struct knetconfig *);
+extern bool_t xdr_nfs_fsl_info(XDR *, struct nfs_fsl_info *);
+extern struct netconfig *get_netconfig(NCONF_HANDLE *, ushort_t, char *);
+extern int setup_nb_parms(struct netconfig *, struct t_bind *, struct t_info *,
+ char *, int, bool_t, ushort_t, rpcprog_t, rpcvers_t, int);
+extern void cleanup_tli_parms(struct t_bind *, int);
+extern struct nfs_fsl_info *get_nfs4ref_info(char *, int, int);
+extern void free_nfs4ref_info(struct nfs_fsl_info *);
+extern struct netbuf *get_server_addr(char *, rpcprog_t, rpcvers_t,
+ struct netconfig *, ushort_t, struct t_info *, caddr_t *,
+ bool_t, char *, enum clnt_stat *);
+extern struct netbuf *resolve_netconf(char *, rpcprog_t, rpcvers_t,
+ struct netconfig **, ushort_t, struct t_info *,
+ caddr_t *, bool_t, char *, enum clnt_stat *);
+
+#endif /* _NFS_RESOLVE_H */
diff --git a/usr/src/cmd/fs.d/nfs/lib/ref_subr.c b/usr/src/cmd/fs.d/nfs/lib/ref_subr.c
new file mode 100644
index 0000000000..b4980593d7
--- /dev/null
+++ b/usr/src/cmd/fs.d/nfs/lib/ref_subr.c
@@ -0,0 +1,311 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <strings.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/errno.h>
+#include <limits.h>
+#include <libnvpair.h>
+#include <dlfcn.h>
+#include <link.h>
+#include <rp_plugin.h>
+#include <fcntl.h>
+#include <uuid/uuid.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/auth.h>
+#include <rpc/clnt.h>
+#include <rpc/rpc_msg.h>
+#include <sys/param.h>
+#include <nfs/nfs4.h>
+#include <rpcsvc/nfs4_prot.h>
+
+/*
+ * str_to_utf8 - converts a null-terminated C string to a utf8 string
+ */
+utf8string *
+str_to_utf8(char *nm, utf8string *str)
+{
+ int len;
+
+ if (str == NULL)
+ return (NULL);
+
+ if (nm == NULL || *nm == '\0') {
+ str->utf8string_len = 0;
+ str->utf8string_val = NULL;
+ return (NULL);
+ }
+
+ len = strlen(nm);
+
+ str->utf8string_val = malloc(len);
+ if (str->utf8string_val == NULL) {
+ str->utf8string_len = 0;
+ return (NULL);
+ }
+ str->utf8string_len = len;
+ bcopy(nm, str->utf8string_val, len);
+
+ return (str);
+}
+
+/*
+ * Converts a utf8 string to a C string.
+ * kmem_allocs a new string if not supplied
+ */
+char *
+utf8_to_str(utf8string *str, uint_t *lenp, char *s)
+{
+ char *sp;
+ char *u8p;
+ int len;
+ int i;
+
+ if (str == NULL)
+ return (NULL);
+
+ u8p = str->utf8string_val;
+ len = str->utf8string_len;
+ if (len <= 0 || u8p == NULL) {
+ if (s)
+ *s = '\0';
+ return (NULL);
+ }
+
+ sp = s;
+ if (sp == NULL)
+ sp = malloc(len + 1);
+ if (sp == NULL)
+ return (NULL);
+
+ /*
+ * At least check for embedded nulls
+ */
+ for (i = 0; i < len; i++) {
+ sp[i] = u8p[i];
+ if (u8p[i] == '\0') {
+ if (s == NULL)
+ free(sp);
+ return (NULL);
+ }
+ }
+ sp[len] = '\0';
+ *lenp = len + 1;
+
+ return (sp);
+}
+
+void
+print_referral_summary(fs_locations4 *fsl)
+{
+ int i, j;
+ uint_t l;
+ char *s;
+ fs_location4 *fs;
+
+ if (fsl == NULL) {
+ printf("NULL\n");
+ return;
+ }
+
+ for (i = 0; i < fsl->locations.locations_len; i++) {
+ if (i > 0)
+ printf("\n");
+ fs = &fsl->locations.locations_val[i];
+ for (j = 0; j < fs->server.server_len; j++) {
+ s = utf8_to_str(&fs->server.server_val[j], &l, NULL);
+ if (j > 0)
+ printf(",");
+ printf("%s", s ? s : "");
+ if (s)
+ free(s);
+ }
+ printf(":");
+ for (j = 0; j < fs->rootpath.pathname4_len; j++) {
+ s = utf8_to_str(&fs->rootpath.pathname4_val[j],
+ &l, NULL);
+ printf("/%s", s ? s : "");
+ if (s)
+ free(s);
+ }
+ if (fs->rootpath.pathname4_len == 0)
+ printf("/");
+ }
+ printf("\n");
+}
+
+/*
+ * There is a kernel copy of this routine in nfs4_srv.c.
+ * Changes should be kept in sync.
+ */
+static int
+nfs4_create_components(char *path, component4 *comp4)
+{
+ int slen, plen, ncomp;
+ char *ori_path, *nxtc, buf[MAXNAMELEN];
+
+ if (path == NULL)
+ return (0);
+
+ plen = strlen(path) + 1; /* include the terminator */
+ ori_path = path;
+ ncomp = 0;
+
+ /* count number of components in the path */
+ for (nxtc = path; nxtc < ori_path + plen; nxtc++) {
+ if (*nxtc == '/' || *nxtc == '\0' || *nxtc == '\n') {
+ if ((slen = nxtc - path) == 0) {
+ path = nxtc + 1;
+ continue;
+ }
+
+ if (comp4 != NULL) {
+ bcopy(path, buf, slen);
+ buf[slen] = '\0';
+ if (str_to_utf8(buf, &comp4[ncomp]) == NULL)
+ return (NULL);
+ }
+
+ ncomp++; /* 1 valid component */
+ path = nxtc + 1;
+ }
+ if (*nxtc == '\0' || *nxtc == '\n')
+ break;
+ }
+
+ return (ncomp);
+}
+
+/*
+ * There is a kernel copy of this routine in nfs4_srv.c.
+ * Changes should be kept in sync.
+ */
+int
+make_pathname4(char *path, pathname4 *pathname)
+{
+ int ncomp;
+ component4 *comp4;
+
+ if (pathname == NULL)
+ return (0);
+
+ if (path == NULL) {
+ pathname->pathname4_val = NULL;
+ pathname->pathname4_len = 0;
+ return (0);
+ }
+
+ /* count number of components to alloc buffer */
+ if ((ncomp = nfs4_create_components(path, NULL)) == 0) {
+ pathname->pathname4_val = NULL;
+ pathname->pathname4_len = 0;
+ return (0);
+ }
+ comp4 = calloc(ncomp * sizeof (component4), 1);
+ if (comp4 == NULL) {
+ pathname->pathname4_val = NULL;
+ pathname->pathname4_len = 0;
+ return (0);
+ }
+
+ /* copy components into allocated buffer */
+ ncomp = nfs4_create_components(path, comp4);
+
+ pathname->pathname4_val = comp4;
+ pathname->pathname4_len = ncomp;
+
+ return (ncomp);
+}
+
+bool_t
+xdr_component4(register XDR *xdrs, component4 *objp)
+{
+
+ if (!xdr_utf8string(xdrs, objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_utf8string(register XDR *xdrs, utf8string *objp)
+{
+
+ if (xdrs->x_op != XDR_FREE)
+ return (xdr_bytes(xdrs, (char **)&objp->utf8string_val,
+ (uint_t *)&objp->utf8string_len, NFS4_MAX_UTF8STRING));
+ return (TRUE);
+}
+
+bool_t
+xdr_pathname4(register XDR *xdrs, pathname4 *objp)
+{
+
+ if (!xdr_array(xdrs, (char **)&objp->pathname4_val,
+ (uint_t *)&objp->pathname4_len, NFS4_MAX_PATHNAME4,
+ sizeof (component4), (xdrproc_t)xdr_component4))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_fs_location4(register XDR *xdrs, fs_location4 *objp)
+{
+
+ if (xdrs->x_op == XDR_DECODE) {
+ objp->server.server_val = NULL;
+ objp->rootpath.pathname4_val = NULL;
+ }
+ if (!xdr_array(xdrs, (char **)&objp->server.server_val,
+ (uint_t *)&objp->server.server_len, ~0,
+ sizeof (utf8string), (xdrproc_t)xdr_utf8string))
+ return (FALSE);
+ if (!xdr_pathname4(xdrs, &objp->rootpath))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_fs_locations4(register XDR *xdrs, fs_locations4 *objp)
+{
+
+ if (xdrs->x_op == XDR_DECODE) {
+ objp->fs_root.pathname4_len = 0;
+ objp->fs_root.pathname4_val = NULL;
+ objp->locations.locations_val = NULL;
+ }
+ if (!xdr_pathname4(xdrs, &objp->fs_root))
+ return (FALSE);
+ if (!xdr_array(xdrs, (char **)&objp->locations.locations_val,
+ (uint_t *)&objp->locations.locations_len, ~0,
+ sizeof (fs_location4), (xdrproc_t)xdr_fs_location4))
+ return (FALSE);
+ return (TRUE);
+}
diff --git a/usr/src/cmd/fs.d/nfs/lib/ref_subr.h b/usr/src/cmd/fs.d/nfs/lib/ref_subr.h
new file mode 100644
index 0000000000..6550411a10
--- /dev/null
+++ b/usr/src/cmd/fs.d/nfs/lib/ref_subr.h
@@ -0,0 +1,57 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _REF_SUBR_H
+#define _REF_SUBR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/auth.h>
+#include <rpc/clnt.h>
+#include <rpc/rpc_msg.h>
+#include <nfs/nfs4.h>
+#include <rpcsvc/nfs4_prot.h>
+
+extern utf8string *str_to_utf8(char *, utf8string *);
+extern char *utf8_to_str(utf8string *, uint_t *, char *);
+extern void print_referral_summary(fs_locations4 *);
+extern int make_pathname4(char *, pathname4 *);
+extern bool_t xdr_component4(register XDR *, component4 *);
+extern bool_t xdr_utf8string(register XDR *, utf8string *);
+extern bool_t xdr_pathname4(register XDR *, pathname4 *);
+extern bool_t xdr_fs_location4(register XDR *, fs_location4 *);
+extern bool_t xdr_fs_locations4(register XDR *, fs_locations4 *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _REF_SUBR_H */
diff --git a/usr/src/cmd/fs.d/nfs/nfsmapid/Makefile b/usr/src/cmd/fs.d/nfs/nfsmapid/Makefile
index 3a7cf93211..7d29271eb0 100644
--- a/usr/src/cmd/fs.d/nfs/nfsmapid/Makefile
+++ b/usr/src/cmd/fs.d/nfs/nfsmapid/Makefile
@@ -32,12 +32,14 @@ include ../../Makefile.fstype
LDLIBS += -L$(ROOT)/usr/lib/nfs -R/usr/lib/nfs
LDLIBS += -lnsl -lmapid -ldtrace -lidmap
-SRCS = nfsmapid.c nfsmapid_server.c
+COMMON = nfs_resolve.o
+SRCS = nfsmapid.c ../lib/nfs_resolve.c nfsmapid_server.c
DSRC = nfsmapid_dt.d
DOBJ = $(DSRC:%.d=%.o)
-OBJS = $(SRCS:%.c=%.o)
+OBJS = nfsmapid.o nfsmapid_server.o $(COMMON)
CPPFLAGS += -I../lib -D_POSIX_PTHREAD_SEMANTICS
+
all: $(TYPEPROG) $(TESTPROG)
$(TYPEPROG): $(OBJS) $(DSRC)
@@ -45,6 +47,9 @@ $(TYPEPROG): $(OBJS) $(DSRC)
$(LINK.c) $(ZIGNORE) -o $@ $(DOBJ) $(OBJS) $(LDLIBS)
$(POST_PROCESS)
+nfs_resolve.o: ../lib/nfs_resolve.c
+ $(COMPILE.c) ../lib/nfs_resolve.c
+
TESTSRCS = nfsmapid_test.c
TESTOBJS = $(TESTSRCS:%.c=%.o)
TEST_OBJS = $(TESTOBJS)
diff --git a/usr/src/cmd/fs.d/nfs/nfsmapid/nfsmapid_server.c b/usr/src/cmd/fs.d/nfs/nfsmapid/nfsmapid_server.c
index e8ec47503a..a80263cd51 100644
--- a/usr/src/cmd/fs.d/nfs/nfsmapid/nfsmapid_server.c
+++ b/usr/src/cmd/fs.d/nfs/nfsmapid/nfsmapid_server.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -53,6 +53,9 @@
#include <sys/sdt.h>
#include <sys/idmap.h>
#include <idmap.h>
+#include <sys/fs/autofs.h>
+#include <sys/mkdev.h>
+#include "nfs_resolve.h"
#define UID_MAX_STR_LEN 11 /* Digits in UID_MAX + 1 */
#define DIAG_FILE "/var/run/nfs4_domain"
@@ -585,6 +588,97 @@ done:
}
}
+void
+nfsmapid_server_netinfo(refd_door_args_t *referral_args, size_t arg_size)
+{
+ char *res;
+ int res_size;
+ int error;
+ int srsz = 0;
+ char host[MAXHOSTNAMELEN];
+ utf8string *nfsfsloc_args;
+ refd_door_res_t *door_res;
+ refd_door_res_t failed_res;
+ struct nfs_fsl_info *nfs_fsloc_res;
+
+ if (arg_size < sizeof (refd_door_args_t)) {
+ failed_res.res_status = EINVAL;
+ res = (char *)&failed_res;
+ res_size = sizeof (refd_door_res_t);
+ syslog(LOG_ERR,
+ "nfsmapid_server_netinfo failed: Invalid data\n");
+ goto send_response;
+ }
+
+ if (decode_args(xdr_utf8string, (refd_door_args_t *)referral_args,
+ (caddr_t *)&nfsfsloc_args, sizeof (utf8string))) {
+ syslog(LOG_ERR, "cannot allocate memory");
+ failed_res.res_status = ENOMEM;
+ failed_res.xdr_len = 0;
+ res = (caddr_t)&failed_res;
+ res_size = sizeof (refd_door_res_t);
+ goto send_response;
+ }
+
+ if (nfsfsloc_args->utf8string_len >= MAXHOSTNAMELEN) {
+ syslog(LOG_ERR, "argument too large");
+ failed_res.res_status = EOVERFLOW;
+ failed_res.xdr_len = 0;
+ res = (caddr_t)&failed_res;
+ res_size = sizeof (refd_door_res_t);
+ goto send_response;
+ }
+
+ snprintf(host, nfsfsloc_args->utf8string_len + 1,
+ "%s", nfsfsloc_args->utf8string_val);
+
+ nfs_fsloc_res =
+ get_nfs4ref_info(host, NFS_PORT, NFS_V4);
+
+ xdr_free(xdr_utf8string, (char *)&nfsfsloc_args);
+
+ if (nfs_fsloc_res) {
+ error = 0;
+ error = encode_res(xdr_nfs_fsl_info, &door_res,
+ (caddr_t)nfs_fsloc_res, &res_size);
+ free_nfs4ref_info(nfs_fsloc_res);
+ if (error != 0) {
+ syslog(LOG_ERR,
+ "error allocating fs_locations "
+ "results buffer");
+ failed_res.res_status = error;
+ failed_res.xdr_len = srsz;
+ res = (caddr_t)&failed_res;
+ res_size = sizeof (refd_door_res_t);
+ } else {
+ door_res->res_status = 0;
+ res = (caddr_t)door_res;
+ }
+ } else {
+ failed_res.res_status = EINVAL;
+ failed_res.xdr_len = 0;
+ res = (caddr_t)&failed_res;
+ res_size = sizeof (refd_door_res_t);
+ }
+
+send_response:
+ srsz = res_size;
+ errno = 0;
+
+ error = door_return(res, res_size, NULL, 0);
+ if (errno == E2BIG) {
+ failed_res.res_status = EOVERFLOW;
+ failed_res.xdr_len = srsz;
+ res = (caddr_t)&failed_res;
+ res_size = sizeof (refd_door_res_t);
+ } else {
+ res = NULL;
+ res_size = 0;
+ }
+
+ door_return(res, res_size, NULL, 0);
+}
+
/* ARGSUSED */
void
nfsmapid_func(void *cookie, char *argp, size_t arg_size,
@@ -592,6 +686,7 @@ nfsmapid_func(void *cookie, char *argp, size_t arg_size,
{
struct mapid_arg *mapargp;
struct mapid_res mapres;
+ refd_door_args_t *referral_args;
/*
* Make sure we have a valid argument
@@ -606,6 +701,7 @@ nfsmapid_func(void *cookie, char *argp, size_t arg_size,
/* LINTED pointer cast */
mapargp = (struct mapid_arg *)argp;
+ referral_args = (refd_door_args_t *)argp;
switch (mapargp->cmd) {
case NFSMAPID_STR_UID:
nfsmapid_str_uid(mapargp, arg_size);
@@ -619,6 +715,8 @@ nfsmapid_func(void *cookie, char *argp, size_t arg_size,
case NFSMAPID_GID_STR:
nfsmapid_gid_str(mapargp, arg_size);
return;
+ case NFSMAPID_SRV_NETINFO:
+ nfsmapid_server_netinfo(referral_args, arg_size);
default:
break;
}
@@ -796,3 +894,190 @@ cb_update_domain(void *arg)
return (NULL);
}
+
+bool_t
+xdr_utf8string(XDR *xdrs, utf8string *objp)
+{
+ if (xdrs->x_op != XDR_FREE)
+ return (xdr_bytes(xdrs, (char **)&objp->utf8string_val,
+ (uint_t *)&objp->utf8string_len, NFS4_MAX_UTF8STRING));
+ return (TRUE);
+}
+
+
+int
+decode_args(xdrproc_t xdrfunc, refd_door_args_t *argp, caddr_t *xdrargs,
+ int size)
+{
+ XDR xdrs;
+
+ caddr_t tmpargs = (caddr_t)&((refd_door_args_t *)argp)->xdr_arg;
+ size_t arg_size = ((refd_door_args_t *)argp)->xdr_len;
+
+ xdrmem_create(&xdrs, tmpargs, arg_size, XDR_DECODE);
+
+ *xdrargs = calloc(1, size);
+ if (*xdrargs == NULL) {
+ syslog(LOG_ERR, "error allocating arguments buffer");
+ return (ENOMEM);
+ }
+
+ if (!(*xdrfunc)(&xdrs, *xdrargs)) {
+ free(*xdrargs);
+ *xdrargs = NULL;
+ syslog(LOG_ERR, "error decoding arguments");
+ return (EINVAL);
+ }
+
+ return (0);
+}
+
+int
+encode_res(
+ xdrproc_t xdrfunc,
+ refd_door_res_t **results,
+ caddr_t resp,
+ int *size)
+{
+ XDR xdrs;
+
+ *size = xdr_sizeof((*xdrfunc), resp);
+ *results = malloc(sizeof (refd_door_res_t) + *size);
+ if (*results == NULL) {
+ return (ENOMEM);
+ }
+ (*results)->xdr_len = *size;
+ *size = sizeof (refd_door_res_t) + (*results)->xdr_len;
+ xdrmem_create(&xdrs, (caddr_t)((*results)->xdr_res),
+ (*results)->xdr_len, XDR_ENCODE);
+ if (!(*xdrfunc)(&xdrs, resp)) {
+ (*results)->res_status = EINVAL;
+ syslog(LOG_ERR, "error encoding results");
+ return ((*results)->res_status);
+ }
+ (*results)->res_status = 0;
+ return ((*results)->res_status);
+}
+
+
+bool_t
+xdr_knetconfig(XDR *xdrs, struct knetconfig *objp)
+{
+ rpc_inline_t *buf;
+ int i;
+ u_longlong_t dev64;
+#if !defined(_LP64)
+ uint32_t major, minor;
+#endif
+
+ if (!xdr_u_int(xdrs, &objp->knc_semantics))
+ return (FALSE);
+ if (!xdr_opaque(xdrs, objp->knc_protofmly, KNC_STRSIZE))
+ return (FALSE);
+ if (!xdr_opaque(xdrs, objp->knc_proto, KNC_STRSIZE))
+ return (FALSE);
+
+ /*
+ * For interoperability between 32-bit daemon and 64-bit kernel,
+ * we always treat dev_t as 64-bit number and do the expanding
+ * or compression of dev_t as needed.
+ * We have to hand craft the conversion since there is no available
+ * function in ddi.c. Besides ddi.c is available only in the kernel
+ * and we want to keep both user and kernel of xdr_knetconfig() the
+ * same for consistency.
+ */
+
+ if (xdrs->x_op == XDR_ENCODE) {
+#if defined(_LP64)
+ dev64 = objp->knc_rdev;
+#else
+ major = (objp->knc_rdev >> NBITSMINOR32) & MAXMAJ32;
+ minor = objp->knc_rdev & MAXMIN32;
+ dev64 = (((unsigned long long)major) << NBITSMINOR64) | minor;
+#endif
+ if (!xdr_u_longlong_t(xdrs, &dev64))
+ return (FALSE);
+ }
+ if (xdrs->x_op == XDR_DECODE) {
+#if defined(_LP64)
+ if (!xdr_u_longlong_t(xdrs, (u_longlong_t *)&objp->knc_rdev))
+ return (FALSE);
+#else
+ if (!xdr_u_longlong_t(xdrs, &dev64))
+ return (FALSE);
+
+ major = (dev64 >> NBITSMINOR64) & L_MAXMAJ32;
+ minor = dev64 & L_MAXMIN32;
+ objp->knc_rdev = (major << L_BITSMINOR32) | minor;
+#endif
+ }
+
+ if (xdrs->x_op == XDR_ENCODE) {
+ buf = XDR_INLINE(xdrs, (8) * BYTES_PER_XDR_UNIT);
+ if (buf == NULL) {
+ if (!xdr_vector(xdrs, (char *)objp->knc_unused, 8,
+ sizeof (uint_t), (xdrproc_t)xdr_u_int))
+ return (FALSE);
+ } else {
+ uint_t *genp;
+
+ for (i = 0, genp = objp->knc_unused;
+ i < 8; i++) {
+#if defined(_LP64) || defined(_KERNEL)
+ IXDR_PUT_U_INT32(buf, *genp++);
+#else
+ IXDR_PUT_U_LONG(buf, *genp++);
+#endif
+ }
+ }
+ return (TRUE);
+ } else if (xdrs->x_op == XDR_DECODE) {
+ buf = XDR_INLINE(xdrs, (8) * BYTES_PER_XDR_UNIT);
+ if (buf == NULL) {
+ if (!xdr_vector(xdrs, (char *)objp->knc_unused, 8,
+ sizeof (uint_t), (xdrproc_t)xdr_u_int))
+ return (FALSE);
+ } else {
+ uint_t *genp;
+
+ for (i = 0, genp = objp->knc_unused;
+ i < 8; i++) {
+#if defined(_LP64) || defined(_KERNEL)
+ *genp++ = IXDR_GET_U_INT32(buf);
+#else
+ *genp++ = IXDR_GET_U_LONG(buf);
+#endif
+ }
+ }
+ return (TRUE);
+ }
+
+ if (!xdr_vector(xdrs, (char *)objp->knc_unused, 8,
+ sizeof (uint_t), (xdrproc_t)xdr_u_int))
+ return (FALSE);
+ return (TRUE);
+}
+
+/*
+ * used by NFSv4 referrals to get info needed for NFSv4 referral mount.
+ */
+bool_t
+xdr_nfs_fsl_info(XDR *xdrs, struct nfs_fsl_info *objp)
+{
+
+ if (!xdr_u_int(xdrs, &objp->netbuf_len))
+ return (FALSE);
+ if (!xdr_u_int(xdrs, &objp->netnm_len))
+ return (FALSE);
+ if (!xdr_u_int(xdrs, &objp->knconf_len))
+ return (FALSE);
+ if (!xdr_string(xdrs, &objp->netname, ~0))
+ return (FALSE);
+ if (!xdr_pointer(xdrs, (char **)&objp->addr, objp->netbuf_len,
+ (xdrproc_t)xdr_netbuf))
+ return (FALSE);
+ if (!xdr_pointer(xdrs, (char **)&objp->knconf,
+ objp->knconf_len, (xdrproc_t)xdr_knetconfig))
+ return (FALSE);
+ return (TRUE);
+}
diff --git a/usr/src/cmd/fs.d/nfs/nfsref/Makefile b/usr/src/cmd/fs.d/nfs/nfsref/Makefile
new file mode 100644
index 0000000000..fa5d58460d
--- /dev/null
+++ b/usr/src/cmd/fs.d/nfs/nfsref/Makefile
@@ -0,0 +1,69 @@
+#
+# 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 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/fs.d/nfs/nfsref/Makefile
+
+PROG= nfsref
+
+POFILE= nfsref.po
+
+include ../../../Makefile.cmd
+
+CFLAGS += $(CCVERBOSE) -I../lib
+OBJS= nfsref.o ref_subr.o
+SRCS= nfsref.c
+
+LDLIBS += -lreparse -lnvpair -lnsl -lumem
+
+$(PROG): $(OBJS)
+ $(LINK.c) -o $@ $(LDLIBS) $(OBJS)
+ $(POST_PROCESS)
+
+FILEMODE= 0555
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+ref_subr.o: ../lib/ref_subr.c
+ $(COMPILE.c) ../lib/ref_subr.c
+
+install: all $(ROOTUSRSBINPROG)
+
+catalog: $(POFILE)
+
+$(POFILE): $(SRCS)
+ $(RM) $@
+ $(COMPILE.cpp) $(SRCS) > $(POFILE).i
+ $(XGETTEXT) $(XGETFLAGS) $(POFILE).i
+ sed "/^domain/d" messages.po > $@
+ $(RM) $(POFILE).i messages.po
+
+lint:
+ $(LINT.c) $(SRCS) $(LDLIBS)
+
+clean:
+ $(RM) $(OBJS)
+
+include ../../../Makefile.targ
diff --git a/usr/src/cmd/fs.d/nfs/nfsref/nfsref.c b/usr/src/cmd/fs.d/nfs/nfsref/nfsref.c
new file mode 100644
index 0000000000..2fe520df0f
--- /dev/null
+++ b/usr/src/cmd/fs.d/nfs/nfsref/nfsref.c
@@ -0,0 +1,401 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <strings.h>
+#include <string.h>
+#include <limits.h>
+#include <libnvpair.h>
+#include <locale.h>
+#include <sys/stat.h>
+#include <sys/fs_reparse.h>
+#include <rp_plugin.h>
+#include <uuid/uuid.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <priv.h>
+#include <nfs/nfs4.h>
+#include <rpcsvc/nfs4_prot.h>
+#include "ref_subr.h"
+
+#ifndef TEXT_DOMAIN
+#define TEXT_DOMAIN "SUNW_OST_OSCMD"
+#endif /* TEXT_DOMAIN */
+
+extern int errno;
+
+void
+usage()
+{
+ fprintf(stderr, gettext("Usage:\n"));
+ fprintf(stderr,
+ gettext("\tnfsref [-t type] add path location [location ...]\n"));
+ fprintf(stderr, gettext("\tnfsref [-t type] remove path\n"));
+ fprintf(stderr, gettext("\tnfsref [-t type] lookup path\n"));
+}
+
+/*
+ * Copy a string from source to destination, escaping space
+ * with a backslash and escaping the escape character as well.
+ */
+int
+add_escape(char *src, char *dest, int limit)
+{
+ char *sp, *dp;
+ int destlen = 0;
+
+ sp = src;
+ dp = dest;
+
+ while (*sp && destlen < limit) {
+ if (*sp == '\\') {
+ *dp++ = '\\';
+ *dp++ = '\\';
+ destlen++;
+ } else if (*sp == ' ') {
+ *dp++ = '\\';
+ *dp++ = ' ';
+ destlen++;
+ } else
+ *dp++ = *sp;
+ destlen++;
+ sp++;
+ }
+ if (limit <= 0)
+ return (-1);
+ return (destlen);
+}
+
+int
+addref(char *sl_path, char *svc_type, int optind, int argc, char *argv[])
+{
+ int err, fd, i, len, oldlen, notfound = 0;
+ char *text, *location;
+ nvlist_t *nvl = NULL;
+ char buf[SYMLINK_MAX];
+ struct stat sbuf;
+
+ /* Get an nvlist */
+ nvl = reparse_init();
+ if (nvl == NULL)
+ return (ENOMEM);
+
+ /* Get the reparse point data, if the RP exists */
+ err = readlink(sl_path, buf, SYMLINK_MAX);
+ if (err == -1) {
+ if (errno == ENOENT) {
+ notfound = 1;
+ err = 0;
+ } else {
+ reparse_free(nvl);
+ return (errno);
+ }
+ } else {
+ buf[err] = '\0';
+ }
+
+ /* Get any data into nvlist */
+ if (notfound == 0)
+ err = reparse_parse(buf, nvl);
+ if (err != 0) {
+ reparse_free(nvl);
+ return (err);
+ }
+
+ /*
+ * Accumulate multiple locations on the command line into 'buf'
+ */
+ oldlen = len = 0;
+ location = NULL;
+ for (i = optind; i < argc; i++) {
+ bzero(buf, sizeof (buf));
+ len += add_escape(argv[i], buf, SYMLINK_MAX) + 2;
+ location = realloc(location, len);
+ location[oldlen] = '\0';
+ oldlen = len;
+ strlcat(location, buf, len);
+ strlcat(location, " ", len);
+ }
+ location[len - 2] = '\0';
+
+ /* Add to the list */
+ err = reparse_add(nvl, svc_type, location);
+ if (err) {
+ reparse_free(nvl);
+ return (err);
+ }
+
+ /* Get the new or modified symlink contents */
+ err = reparse_unparse(nvl, &text);
+ reparse_free(nvl);
+ if (err)
+ return (err);
+
+ /* Delete first if found */
+ if (notfound == 0) {
+ err = reparse_delete(sl_path);
+ if (err) {
+ free(text);
+ return (err);
+ }
+ }
+
+ /* Finally, write out the reparse point */
+ err = reparse_create(sl_path, text);
+ free(text);
+ if (err)
+ return (err);
+
+ err = lstat(sl_path, &sbuf);
+ if (err == 0 && strcasecmp(sbuf.st_fstype, "ZFS") != 0)
+ printf(gettext(
+ "Warning: referrals do not work on this filesystem\n"));
+
+ if (notfound)
+ printf(gettext("Created reparse point %s\n"), sl_path);
+ else
+ printf(gettext("Added to reparse point %s\n"), sl_path);
+
+ return (0);
+}
+
+int
+delref(char *sl_path, char *svc_type)
+{
+ char *cp;
+ char *svc_data;
+ int err;
+ nvlist_t *nvl;
+ nvpair_t *curr;
+ char buf[SYMLINK_MAX];
+ int fd, fd2;
+ FILE *fp, *fp2;
+ char uuid[UUID_PRINTABLE_STRING_LENGTH], path[256], loc[2048];
+
+ /* Get an nvlist */
+ if (!(nvl = reparse_init()))
+ return (ENOMEM);
+
+ /* Get the symlink data (should be there) */
+ err = readlink(sl_path, buf, SYMLINK_MAX);
+ if (err == -1) {
+ reparse_free(nvl);
+ return (errno);
+ }
+ buf[err] = '\0';
+
+ /* Get the records into the nvlist */
+ err = reparse_parse(buf, nvl);
+ if (err) {
+ reparse_free(nvl);
+ return (err);
+ }
+
+ /* Remove from nvlist */
+ err = reparse_remove(nvl, svc_type);
+ if (err) {
+ reparse_free(nvl);
+ return (err);
+ }
+
+ /* Any list entries left? If so, turn nvlist back to string. */
+ curr = nvlist_next_nvpair(nvl, NULL);
+ if (curr != NULL) {
+ err = reparse_unparse(nvl, &cp);
+ reparse_free(nvl);
+ if (err)
+ return (err);
+ } else {
+ reparse_free(nvl);
+ cp = NULL;
+ }
+
+ /* Finally, delete and perhaps recreate the reparse point */
+ err = reparse_delete(sl_path);
+ if (err) {
+ free(cp);
+ return (err);
+ }
+
+ if (cp != NULL) {
+ err = reparse_create(sl_path, cp);
+ free(cp);
+ if (err)
+ return (err);
+ }
+ printf(gettext("Removed svc_type '%s' from %s\n"), svc_type, sl_path);
+ return (err);
+}
+
+int
+lookup(char *sl_path, char *svc_type, int type_set)
+{
+ int err;
+ size_t bufsize;
+ char buf[1024];
+ char *type, *svc_data;
+ nvlist_t *nvl;
+ nvpair_t *curr;
+ fs_locations4 fsl;
+ XDR xdr;
+
+ if (!(nvl = reparse_init()))
+ return (-1);
+
+ /* Get reparse point data */
+ err = readlink(sl_path, buf, SYMLINK_MAX);
+ if (err == -1)
+ return (errno);
+ buf[err] = '\0';
+
+ /* Parse it to an nvlist */
+ err = reparse_parse(buf, nvl);
+ if (err) {
+ reparse_free(nvl);
+ return (err);
+ }
+
+ /* Look for entries of the requested service type */
+ curr = NULL;
+ while ((curr = nvlist_next_nvpair(nvl, curr)) != NULL) {
+ type = nvpair_name(curr);
+ if (type_set && strcasecmp(type, svc_type) == 0)
+ break;
+ if (!type_set && strncasecmp(type, "nfs", 3) == 0)
+ break;
+ }
+ if (curr == NULL) {
+ reparse_free(nvl);
+ return (ENOENT);
+ }
+
+ /* Get the service data and look it up */
+ nvpair_value_string(curr, &svc_data);
+
+ bufsize = sizeof (buf);
+ err = reparse_deref(type, svc_data, buf, &bufsize);
+ reparse_free(nvl);
+ if (err)
+ return (err);
+
+ xdrmem_create(&xdr, buf, bufsize, XDR_DECODE);
+ err = xdr_fs_locations4(&xdr, &fsl);
+ XDR_DESTROY(&xdr);
+ if (err != TRUE)
+ return (ENOENT);
+ printf(gettext("%s points to: "), sl_path);
+ print_referral_summary(&fsl);
+ return (0);
+}
+
+extern char *optarg;
+extern int optind, optopt;
+
+int
+main(int argc, char *argv[])
+{
+ char c, *command, *sl_path, *svc_type;
+ int type_set, err;
+
+ (void) setlocale(LC_ALL, "");
+ (void) textdomain(TEXT_DOMAIN);
+
+ svc_type = "nfs-basic"; /* Default from SMF some day */
+ type_set = 0; /* Lookup any nfs type */
+
+ /* Look for options (just the service type now) */
+ while ((c = getopt(argc, argv, "t:")) != -1) {
+ switch (c) {
+ case 't':
+ svc_type = optarg;
+ type_set = 1;
+ break;
+
+ default:
+ usage();
+ exit(1);
+ }
+ }
+
+ /* Make sure there's at least a command and one argument */
+ if (optind + 1 >= argc) {
+ usage();
+ exit(1);
+ }
+
+ err = rp_plugin_init();
+ switch (err) {
+ case RP_OK:
+ break;
+ case RP_NO_PLUGIN_DIR:
+ fprintf(stderr,
+ gettext("Warning: no plugin directory, continuing...\n"));
+ break;
+ case RP_NO_PLUGIN:
+ fprintf(stderr,
+ gettext("Warning: no plugin found, continuing...\n"));
+ break;
+ case RP_NO_MEMORY:
+ fprintf(stderr,
+ gettext("rp_plugin_init failed, no memory\n"));
+ exit(0);
+ default:
+ fprintf(stderr,
+ gettext("rp_plugin_init failed, error %d\n"), err);
+ exit(0);
+ }
+
+ command = argv[optind++];
+ sl_path = argv[optind++];
+
+ if (strcmp(command, "add") == 0) {
+
+ if (optind >= argc) {
+ usage();
+ exit(1);
+ }
+
+ err = addref(sl_path, svc_type, optind, argc, argv);
+
+ } else if (strcmp(command, "remove") == 0) {
+
+ err = delref(sl_path, svc_type);
+
+ } else if (strcmp(command, "lookup") == 0) {
+
+ err = lookup(sl_path, svc_type, type_set);
+
+ } else {
+ usage();
+ exit(1);
+ }
+ if (err != 0)
+ fprintf(stderr, gettext("Command %s failed: %s\n"), command,
+ strerror(err));
+ return (err);
+}
diff --git a/usr/src/cmd/fs.d/nfs/nfsstat/nfsstat.c b/usr/src/cmd/fs.d/nfs/nfsstat/nfsstat.c
index 5c406e331d..50b597d0f8 100644
--- a/usr/src/cmd/fs.d/nfs/nfsstat/nfsstat.c
+++ b/usr/src/cmd/fs.d/nfs/nfsstat/nfsstat.c
@@ -117,9 +117,10 @@ static int count; /* number of iterations the stat is printed */
/*
* MI4_MIRRORMOUNT is canonically defined in nfs4_clnt.h, but we cannot
- * include that file here.
+ * include that file here. Same with MI4_REFERRAL.
*/
#define MI4_MIRRORMOUNT 0x4000
+#define MI4_REFERRAL 0x8000
#define NFS_V4 4
static int req_width(kstat_t *, int);
@@ -1241,6 +1242,8 @@ mi_print(void)
if (mik.mik_vers >= NFS_V4) {
if (mik.mik_flags & MI4_MIRRORMOUNT)
printf(",mirrormount");
+ if (mik.mik_flags & MI4_REFERRAL)
+ printf(",referral");
}
printf(",rsize=%d,wsize=%d,retrans=%d,timeo=%d",
diff --git a/usr/src/cmd/fs.d/nfs/rp_basic/Makefile b/usr/src/cmd/fs.d/nfs/rp_basic/Makefile
new file mode 100644
index 0000000000..2c2af534c6
--- /dev/null
+++ b/usr/src/cmd/fs.d/nfs/rp_basic/Makefile
@@ -0,0 +1,56 @@
+#
+# 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 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include $(SRC)/lib/Makefile.lib
+
+SUBDIRS = $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+MSGFILES = libnfs_basic.c
+POFILE = rp_basic.po
+
+all := TARGET= all
+clean := TARGET= clean
+clobber := TARGET= clobber
+install := TARGET= install
+lint := TARGET= lint
+
+.KEEP_STATE:
+
+all clean clobber install lint: $(SUBDIRS)
+
+catalog: $(POFILE)
+
+$(POFILE): $(MSGFILES)
+ $(BUILDPO.msgfiles)
+
+_msg: $(MSGDOMAINPOFILE)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include $(SRC)/lib/Makefile.targ
+include $(SRC)/Makefile.msg.targ
diff --git a/usr/src/cmd/fs.d/nfs/rp_basic/Makefile.com b/usr/src/cmd/fs.d/nfs/rp_basic/Makefile.com
new file mode 100644
index 0000000000..85567a3537
--- /dev/null
+++ b/usr/src/cmd/fs.d/nfs/rp_basic/Makefile.com
@@ -0,0 +1,65 @@
+#
+# 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 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+LIBRARY = libnfs_basic.a
+VERS = .1
+
+LIBOBJS = libnfs_basic.o
+COMMON = ref_subr.o
+OBJECTS = $(LIBOBJS) $(COMMON)
+
+include $(SRC)/lib/Makefile.lib
+
+lintcheck := SRCS = ../libnfs_basic.c ../../lib/ref_subr.c
+
+ROOTLIBDIR = $(ROOT)/usr/lib/reparse
+ROOTLIBDIR64 = $(ROOT)/usr/lib/reparse/$(MACH64)
+
+LIBSRCS = $(LIBOBJS:%.o=$(SRCDIR)/%.c)
+
+LIBS = $(DYNLIB)
+LDLIBS += -lc -lnsl
+
+CFLAGS += $(CCVERBOSE)
+CPPFLAGS += -D_REENTRANT -I$(SRC)/cmd/fs.d/nfs/lib
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+install: $(ROOTLIBDIR) $(ROOTLIBDIR64) all
+
+lint: lintcheck
+
+pics/ref_subr.o: ../../lib/ref_subr.c
+ $(COMPILE.c) -o pics/ref_subr.o ../../lib/ref_subr.c
+ $(POST_PROCESS_O)
+
+$(ROOTLIBDIR):
+ $(INS.dir)
+
+$(ROOTLIBDIR64):
+ $(INS.dir)
+
+include $(SRC)/lib/Makefile.targ
diff --git a/usr/src/cmd/fs.d/nfs/rp_basic/amd64/Makefile b/usr/src/cmd/fs.d/nfs/rp_basic/amd64/Makefile
new file mode 100644
index 0000000000..f013cacc18
--- /dev/null
+++ b/usr/src/cmd/fs.d/nfs/rp_basic/amd64/Makefile
@@ -0,0 +1,28 @@
+#
+# 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 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+include $(SRC)/lib/Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
diff --git a/usr/src/cmd/fs.d/nfs/rp_basic/i386/Makefile b/usr/src/cmd/fs.d/nfs/rp_basic/i386/Makefile
new file mode 100644
index 0000000000..8673a37a6e
--- /dev/null
+++ b/usr/src/cmd/fs.d/nfs/rp_basic/i386/Makefile
@@ -0,0 +1,27 @@
+#
+# 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 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS)
diff --git a/usr/src/cmd/fs.d/nfs/rp_basic/libnfs_basic.c b/usr/src/cmd/fs.d/nfs/rp_basic/libnfs_basic.c
new file mode 100644
index 0000000000..d49b2cc594
--- /dev/null
+++ b/usr/src/cmd/fs.d/nfs/rp_basic/libnfs_basic.c
@@ -0,0 +1,310 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <strings.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/errno.h>
+#include <limits.h>
+#include <libnvpair.h>
+#include <dlfcn.h>
+#include <link.h>
+#include <rp_plugin.h>
+#include <fcntl.h>
+#include <uuid/uuid.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/auth.h>
+#include <rpc/clnt.h>
+#include <rpc/rpc_msg.h>
+#include <sys/param.h>
+#include <nfs/nfs4.h>
+#include <rpcsvc/nfs4_prot.h>
+#include "ref_subr.h"
+
+extern int errno;
+
+#define SERVICE_TYPE "nfs-basic"
+
+char *nfs_basic_service_type(void);
+boolean_t nfs_basic_supports_svc(const char *);
+int nfs_basic_deref(const char *, const char *, char *, size_t *);
+int nfs_basic_form(const char *, const char *, char *, size_t *);
+
+struct rp_plugin_ops rp_plugin_ops = {
+ RP_PLUGIN_V1,
+ NULL, /* rpo_init */
+ NULL, /* rpo_fini */
+ nfs_basic_service_type,
+ nfs_basic_supports_svc,
+ nfs_basic_form,
+ nfs_basic_deref
+};
+
+/*
+ * What service type does this module support?
+ */
+char *
+nfs_basic_service_type()
+{
+ return (SERVICE_TYPE);
+}
+
+/*
+ * Does this module support a particular service type?
+ */
+boolean_t
+nfs_basic_supports_svc(const char *svc_type)
+{
+ if (!svc_type)
+ return (0);
+ return (!strncasecmp(svc_type, SERVICE_TYPE, strlen(SERVICE_TYPE)));
+}
+
+/*
+ * Take a string with a set of locations like this:
+ * host1:/path1 host2:/path2 host3:/path3
+ * and convert it to an fs_locations4 for the deref routine.
+ */
+static fs_locations4 *
+get_fs_locations(char *buf)
+{
+ fs_locations4 *result = NULL;
+ fs_location4 *fsl_array;
+ int i = 0, fsl_count = 0, gothost = 0, escape = 0, delimiter = 0;
+ int len;
+ char *p, *sp, *dp, buf2[SYMLINK_MAX];
+
+ if (buf == NULL)
+ return (NULL);
+#ifdef DEBUG
+ printf("get_fs_locations: input %s\n", buf);
+#endif
+ /*
+ * Count fs_location entries by counting spaces.
+ * Remember that escaped spaces ("\ ") may exist.
+ * We mark the location boundaries with null bytes.
+ * Variable use:
+ * escape - set if we have found a backspace,
+ * part of either "\ " or "\\"
+ * delimiter - set if we have found a space and
+ * used to skip multiple spaces
+ */
+ for (sp = buf; sp && *sp; sp++) {
+ if (*sp == '\\') {
+ escape = 1;
+ delimiter = 0;
+ continue;
+ }
+ if (*sp == ' ') {
+ if (delimiter == 1)
+ continue;
+ if (escape == 0) {
+ delimiter = 1;
+ fsl_count++;
+ *sp = '\0';
+ } else
+ escape = 0;
+ } else
+ delimiter = 0;
+ }
+ len = sp - buf;
+ sp--;
+ if (escape == 0 && *sp != '\0')
+ fsl_count++;
+#ifdef DEBUG
+ printf("get_fs_locations: fsl_count %d\n", fsl_count);
+#endif
+ if (fsl_count == 0)
+ goto out;
+
+ /* Alloc space for everything */
+ result = malloc(sizeof (fs_locations4));
+ if (result == NULL)
+ goto out;
+ fsl_array = malloc(fsl_count * sizeof (fs_location4));
+ if (fsl_array == NULL) {
+ free(result);
+ result = NULL;
+ goto out;
+ }
+ result->locations.locations_len = fsl_count;
+ result->locations.locations_val = fsl_array;
+ result->fs_root.pathname4_len = 0;
+ result->fs_root.pathname4_val = NULL;
+
+ /*
+ * Copy input, removing escapes from host:/path/to/my\ files
+ */
+ sp = buf;
+ dp = buf2;
+ bzero(buf2, sizeof (buf2));
+
+ while ((sp && *sp && (sp - buf < len)) || gothost) {
+
+ if (!gothost) {
+ /* Drop leading spaces */
+ if (*sp == ' ') {
+ sp++;
+ continue;
+ }
+
+ /* Look for the rightmost colon for host */
+ p = strrchr(sp, ':');
+ if (!p) {
+#ifdef DEBUG
+ printf("get_fs_locations: skipping %s\n", sp);
+#endif
+ sp += strlen(sp) + 1;
+ } else {
+ bcopy(sp, dp, p - sp);
+ sp = p + 1;
+#ifdef DEBUG
+ printf("get_fs_locations: host %s\n", buf2);
+#endif
+ fsl_array[i].server.server_len = 1;
+ fsl_array[i].server.server_val =
+ malloc(sizeof (utf8string));
+ if (fsl_array[i].server.server_val == NULL) {
+ int j;
+
+ free(result);
+ result = NULL;
+ for (j = 0; j < i; j++)
+ free(fsl_array[j].
+ server.server_val);
+ free(fsl_array);
+ goto out;
+ }
+ str_to_utf8(buf2,
+ fsl_array[i].server.server_val);
+ gothost = 1;
+ dp = buf2;
+ bzero(buf2, sizeof (buf2));
+ }
+ continue;
+ }
+
+ /* End of string should mean a pathname */
+ if (*sp == '\0' && gothost) {
+#ifdef DEBUG
+ printf("get_fs_locations: path %s\n", buf2);
+#endif
+ (void) make_pathname4(buf2, &fsl_array[i].rootpath);
+ i++;
+ gothost = 0;
+ dp = buf2;
+ bzero(buf2, sizeof (buf2));
+ if (sp - buf < len)
+ sp++;
+ continue;
+ }
+
+ /* Skip a single escape character */
+ if (*sp == '\\')
+ sp++;
+
+ /* Plain char, just copy it */
+ *dp++ = *sp++;
+ }
+
+out:
+ return (result);
+}
+
+/*
+ * Deref function for nfs-basic service type returns an fs_locations4.
+ */
+int
+nfs_basic_deref(const char *svc_type, const char *svc_data, char *buf,
+ size_t *bufsz)
+{
+ int slen, err;
+ fs_locations4 *fsl;
+ XDR xdr;
+
+ if ((!svc_type) || (!svc_data) || (!buf) || (!bufsz) || (*bufsz == 0))
+ return (EINVAL);
+
+ if (strcasecmp(svc_type, SERVICE_TYPE))
+ return (ENOTSUP);
+
+ fsl = get_fs_locations((char *)svc_data);
+ if (fsl == NULL)
+ return (ENOENT);
+#ifdef DEBUG
+ printf("nfs_basic_deref: past get_fs_locations()\n");
+#endif
+ slen = xdr_sizeof(xdr_fs_locations4, (void *)fsl);
+ if (slen > *bufsz) {
+ *bufsz = slen;
+ xdr_free(xdr_fs_locations4, (char *)fsl);
+ return (EOVERFLOW);
+ }
+#ifdef DEBUG
+ printf("nfs_basic_deref: past buffer check\n");
+ print_referral_summary(fsl);
+#endif
+ xdrmem_create(&xdr, buf, *bufsz, XDR_ENCODE);
+ err = xdr_fs_locations4(&xdr, fsl);
+ XDR_DESTROY(&xdr);
+ xdr_free(xdr_fs_locations4, (char *)fsl);
+ if (err != TRUE)
+ return (EINVAL);
+ *bufsz = slen;
+#ifdef DEBUG
+ printf("nfs_basic_deref: past xdr_fs_locations4() and done\n");
+#endif
+ return (0);
+}
+
+/*
+ * Form function for nfs-basic service type.
+ */
+int
+nfs_basic_form(const char *svc_type, const char *svc_data, char *buf,
+ size_t *bufsz)
+{
+ int slen;
+
+ if ((!svc_type) || (!svc_data) || (!buf) || (*bufsz == 0))
+ return (EINVAL);
+
+ if (strcmp(svc_type, SERVICE_TYPE))
+ return (ENOTSUP);
+
+ slen = strlen(svc_data) + 1;
+ if (slen > *bufsz) {
+ *bufsz = slen;
+ return (EOVERFLOW);
+ }
+ *bufsz = slen;
+ strncpy(buf, svc_data, slen);
+ return (0);
+}
diff --git a/usr/src/cmd/fs.d/nfs/rp_basic/mapfile-vers b/usr/src/cmd/fs.d/nfs/rp_basic/mapfile-vers
new file mode 100644
index 0000000000..7a1e01b707
--- /dev/null
+++ b/usr/src/cmd/fs.d/nfs/rp_basic/mapfile-vers
@@ -0,0 +1,46 @@
+#
+# 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 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+SUNWprivate_1.1 {
+ global:
+ rp_plugin_ops;
+ local:
+ *;
+};
+
diff --git a/usr/src/cmd/fs.d/nfs/rp_basic/sparc/Makefile b/usr/src/cmd/fs.d/nfs/rp_basic/sparc/Makefile
new file mode 100644
index 0000000000..8673a37a6e
--- /dev/null
+++ b/usr/src/cmd/fs.d/nfs/rp_basic/sparc/Makefile
@@ -0,0 +1,27 @@
+#
+# 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 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS)
diff --git a/usr/src/cmd/fs.d/nfs/rp_basic/sparcv9/Makefile b/usr/src/cmd/fs.d/nfs/rp_basic/sparcv9/Makefile
new file mode 100644
index 0000000000..f013cacc18
--- /dev/null
+++ b/usr/src/cmd/fs.d/nfs/rp_basic/sparcv9/Makefile
@@ -0,0 +1,28 @@
+#
+# 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 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+include $(SRC)/lib/Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
diff --git a/usr/src/cmd/fs.d/nfs/svc/server.xml b/usr/src/cmd/fs.d/nfs/svc/server.xml
index e709cc8b36..4a8fac519c 100644
--- a/usr/src/cmd/fs.d/nfs/svc/server.xml
+++ b/usr/src/cmd/fs.d/nfs/svc/server.xml
@@ -94,6 +94,13 @@
<service_fmri value='svc:/network/shares/group' />
</dependency>
+ <dependency name='reparse'
+ grouping='optional_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/system/filesystem/reparse' />
+ </dependency>
+
<!-- Must have all local filesystems mounted before we share them -->
<dependency name='filesystem-local'
grouping='require_all'
diff --git a/usr/src/head/rpcsvc/daemon_utils.h b/usr/src/head/rpcsvc/daemon_utils.h
index 8ba538fe81..50611a9579 100644
--- a/usr/src/head/rpcsvc/daemon_utils.h
+++ b/usr/src/head/rpcsvc/daemon_utils.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,15 +19,13 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _DAEMON_UTILS_H
#define _DAEMON_UTILS_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/stat.h>
#ifdef __cplusplus
@@ -43,6 +40,7 @@ extern "C" {
#define NFS4CBD "svc:/network/nfs/cbd:default"
#define NFSMAPID "svc:/network/nfs/mapid:default"
#define RQUOTAD "svc:/network/nfs/rquota:default"
+#define REPARSED "svc:/system/filesystem/reparse:default"
#define DAEMON_UID 1
#define DAEMON_GID 12
diff --git a/usr/src/head/rpcsvc/nfs4_prot.x b/usr/src/head/rpcsvc/nfs4_prot.x
index 770784fa10..0a218a6a36 100644
--- a/usr/src/head/rpcsvc/nfs4_prot.x
+++ b/usr/src/head/rpcsvc/nfs4_prot.x
@@ -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.
@@ -28,8 +27,6 @@
* nfs4_prot.x
*/
-%#pragma ident "@(#)nfs4_prot.x 1.122"
-
/*
* Basic typedefs for RFC 1832 data type definitions
*/
@@ -211,6 +208,16 @@ struct fs_locations4 {
fs_location4 locations<>;
};
+struct nfs_fsl_info {
+ uint_t netbuf_len;
+ uint_t netnm_len;
+ uint_t knconf_len;
+ string netname<MAXNETNAMELEN>;
+ struct netbuf *addr;
+ struct knetconfig *knconf;
+};
+
+
/*
* Various Access Control Entry definitions
*/
diff --git a/usr/src/lib/libshare/nfs/libshare_nfs.c b/usr/src/lib/libshare/nfs/libshare_nfs.c
index 4286f18d22..dc6e5f61d4 100644
--- a/usr/src/lib/libshare/nfs/libshare_nfs.c
+++ b/usr/src/lib/libshare/nfs/libshare_nfs.c
@@ -114,9 +114,10 @@ struct sa_plugin_ops sa_plugin_ops = {
*/
static char *service_list_default[] =
- { STATD, LOCKD, MOUNTD, NFSD, NFSMAPID, RQUOTAD, NULL };
+ { STATD, LOCKD, MOUNTD, NFSD, NFSMAPID, RQUOTAD, REPARSED, NULL };
static char *service_list_logging[] =
- { STATD, LOCKD, MOUNTD, NFSD, NFSMAPID, RQUOTAD, NFSLOGD, NULL };
+ { STATD, LOCKD, MOUNTD, NFSD, NFSMAPID, RQUOTAD, NFSLOGD, REPARSED,
+ NULL };
/*
* option definitions. Make sure to keep the #define for the option
@@ -2930,6 +2931,9 @@ restart_service(uint32_t svcs)
case SVC_NFSLOGD:
service = NFSLOGD;
break;
+ case SVC_REPARSED:
+ service = REPARSED;
+ break;
default:
continue;
}
diff --git a/usr/src/lib/libshare/nfs/libshare_nfs.h b/usr/src/lib/libshare/nfs/libshare_nfs.h
index 3b612b2954..e67d3b49a8 100644
--- a/usr/src/lib/libshare/nfs/libshare_nfs.h
+++ b/usr/src/lib/libshare/nfs/libshare_nfs.h
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -97,6 +97,7 @@ struct option_defs {
#define SVC_NFSMAPID 0x0020
#define SVC_RQUOTAD 0x0040
#define SVC_NFSLOGD 0x0080
+#define SVC_REPARSED 0x0100
/*
* place holder for future service -- will move to daemon_utils.h when
diff --git a/usr/src/pkgdefs/SUNWnfscu/prototype_com b/usr/src/pkgdefs/SUNWnfscu/prototype_com
index 0c6c0391db..6ff3f563e0 100644
--- a/usr/src/pkgdefs/SUNWnfscu/prototype_com
+++ b/usr/src/pkgdefs/SUNWnfscu/prototype_com
@@ -19,11 +19,9 @@
# CDDL HEADER END
#
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-#pragma ident "%Z%%M% %I% %E% SMI"
-#
# This required package information file contains a list of package contents.
# The 'pkgmk' command uses this file to identify the contents of a package
# and their location on the development machine when building the package.
diff --git a/usr/src/pkgdefs/SUNWnfssu/prototype_com b/usr/src/pkgdefs/SUNWnfssu/prototype_com
index f63bfed138..bd6e0bcf82 100644
--- a/usr/src/pkgdefs/SUNWnfssu/prototype_com
+++ b/usr/src/pkgdefs/SUNWnfssu/prototype_com
@@ -18,11 +18,9 @@
#
# CDDL HEADER END
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
-#
# This required package information file contains a list of package contents.
# The 'pkgmk' command uses this file to identify the contents of a package
# and their location on the development machine when building the package.
@@ -53,5 +51,9 @@ f none usr/lib/nfs/mountd 555 root bin
f none usr/lib/nfs/nfsd 555 root bin
f none usr/lib/nfs/nfslogd 555 root bin
f none usr/lib/nfs/rquotad 555 root bin
+d none usr/lib/reparse 755 root bin
+f none usr/lib/reparse/libnfs_basic.so.1 755 root bin
+s none usr/lib/reparse/libnfs_basic.so=./libnfs_basic.so.1
d none usr/sbin 755 root bin
f none usr/sbin/exportfs 555 root bin
+f none usr/sbin/nfsref 555 root bin
diff --git a/usr/src/pkgdefs/SUNWnfssu/prototype_i386 b/usr/src/pkgdefs/SUNWnfssu/prototype_i386
index a6d0dfdab4..23f31e60c8 100644
--- a/usr/src/pkgdefs/SUNWnfssu/prototype_i386
+++ b/usr/src/pkgdefs/SUNWnfssu/prototype_i386
@@ -18,11 +18,9 @@
#
# CDDL HEADER END
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
-#
# This required package information file contains a list of package contents.
# The 'pkgmk' command uses this file to identify the contents of a package
# and their location on the development machine when building the package.
@@ -47,3 +45,6 @@
#
d none usr/lib/fs/nfs/amd64 755 root sys
f none usr/lib/fs/nfs/amd64/libshare_nfs.so.1 755 root bin
+d none usr/lib/reparse/amd64 755 root sys
+f none usr/lib/reparse/amd64/libnfs_basic.so.1 755 root bin
+s none usr/lib/reparse/amd64/libnfs_basic.so=./libnfs_basic.so.1
diff --git a/usr/src/pkgdefs/SUNWnfssu/prototype_sparc b/usr/src/pkgdefs/SUNWnfssu/prototype_sparc
index e4ae96f821..f2f9b32c48 100644
--- a/usr/src/pkgdefs/SUNWnfssu/prototype_sparc
+++ b/usr/src/pkgdefs/SUNWnfssu/prototype_sparc
@@ -18,11 +18,9 @@
#
# CDDL HEADER END
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
-#
# This required package information file contains a list of package contents.
# The 'pkgmk' command uses this file to identify the contents of a package
# and their location on the development machine when building the package.
@@ -46,3 +44,6 @@
#
d none usr/lib/fs/nfs/sparcv9 755 root sys
f none usr/lib/fs/nfs/sparcv9/libshare_nfs.so.1 755 root bin
+d none usr/lib/reparse/sparcv9 755 root sys
+f none usr/lib/reparse/sparcv9/libnfs_basic.so.1 755 root bin
+s none usr/lib/reparse/sparcv9/libnfs_basic.so=./libnfs_basic.so.1
diff --git a/usr/src/uts/common/fs/fs_subr.c b/usr/src/uts/common/fs/fs_subr.c
index a465a97043..b1fec8b4ba 100644
--- a/usr/src/uts/common/fs/fs_subr.c
+++ b/usr/src/uts/common/fs/fs_subr.c
@@ -938,7 +938,7 @@ int
reparse_kderef(const char *svc_type, const char *svc_data, char *buf,
size_t *bufsize)
{
- int err, retries, need_free;
+ int err, retries, need_free, retried_doorhd;
size_t dlen, res_len;
char *darg;
door_arg_t door_args;
@@ -975,6 +975,7 @@ reparse_kderef(const char *svc_type, const char *svc_data, char *buf,
door_args.rsize = *bufsize;
/* do the door_call */
+ retried_doorhd = 0;
retries = 0;
door_ki_hold(rp_door);
while ((err = door_ki_upcall_limited(rp_door, &door_args,
@@ -987,10 +988,23 @@ reparse_kderef(const char *svc_type, const char *svc_data, char *buf,
} else if (err == EBADF) {
/* door server goes away... */
reparse_door_reset_handle();
+
+ if (retried_doorhd == 0) {
+ door_ki_rele(rp_door);
+ retried_doorhd++;
+ rp_door = reparse_door_get_handle();
+ if (rp_door != NULL) {
+ door_ki_hold(rp_door);
+ continue;
+ }
+ }
}
break;
}
- door_ki_rele(rp_door);
+
+ if (rp_door)
+ door_ki_rele(rp_door);
+
if (need_free)
kmem_free(darg, dlen); /* done with args buffer */
diff --git a/usr/src/uts/common/fs/nfs/nfs3_srv.c b/usr/src/uts/common/fs/nfs/nfs3_srv.c
index e060023197..71ebdb2d74 100644
--- a/usr/src/uts/common/fs/nfs/nfs3_srv.c
+++ b/usr/src/uts/common/fs/nfs/nfs3_srv.c
@@ -112,6 +112,10 @@ rfs3_getattr(GETATTR3args *args, GETATTR3res *resp, struct exportinfo *exi,
error = rfs4_delegated_getattr(vp, &va, 0, cr);
if (!error) {
+ /* Lie about the object type for a referral */
+ if (vn_is_nfs_reparse(vp, cr))
+ va.va_type = VLNK;
+
/* overflow error if time or size is out of range */
error = vattr_to_fattr3(&va, &resp->resok.obj_attributes);
if (error)
@@ -792,6 +796,7 @@ rfs3_readlink(READLINK3args *args, READLINK3res *resp, struct exportinfo *exi,
char *data;
struct sockaddr *ca;
char *name = NULL;
+ int is_referral = 0;
vap = NULL;
@@ -817,7 +822,11 @@ rfs3_readlink(READLINK3args *args, READLINK3res *resp, struct exportinfo *exi,
vap = &va;
#endif
- if (vp->v_type != VLNK) {
+ /* We lied about the object type for a referral */
+ if (vn_is_nfs_reparse(vp, cr))
+ is_referral = 1;
+
+ if (vp->v_type != VLNK && !is_referral) {
resp->status = NFS3ERR_INVAL;
goto out1;
}
@@ -845,16 +854,39 @@ rfs3_readlink(READLINK3args *args, READLINK3res *resp, struct exportinfo *exi,
data = kmem_alloc(MAXPATHLEN + 1, KM_SLEEP);
- iov.iov_base = data;
- iov.iov_len = MAXPATHLEN;
- uio.uio_iov = &iov;
- uio.uio_iovcnt = 1;
- uio.uio_segflg = UIO_SYSSPACE;
- uio.uio_extflg = UIO_COPY_CACHED;
- uio.uio_loffset = 0;
- uio.uio_resid = MAXPATHLEN;
+ if (is_referral) {
+ char *s;
+ size_t strsz;
+
+ /* Get an artificial symlink based on a referral */
+ s = build_symlink(vp, cr, &strsz);
+ global_svstat_ptr[3][NFS_REFERLINKS].value.ui64++;
+ DTRACE_PROBE2(nfs3serv__func__referral__reflink,
+ vnode_t *, vp, char *, s);
+ if (s == NULL)
+ error = EINVAL;
+ else {
+ error = 0;
+ (void) strlcpy(data, s, MAXPATHLEN + 1);
+ kmem_free(s, strsz);
+ }
- error = VOP_READLINK(vp, &uio, cr, NULL);
+ } else {
+
+ iov.iov_base = data;
+ iov.iov_len = MAXPATHLEN;
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_segflg = UIO_SYSSPACE;
+ uio.uio_extflg = UIO_COPY_CACHED;
+ uio.uio_loffset = 0;
+ uio.uio_resid = MAXPATHLEN;
+
+ error = VOP_READLINK(vp, &uio, cr, NULL);
+
+ if (!error)
+ *(data + MAXPATHLEN - uio.uio_resid) = '\0';
+ }
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
@@ -866,6 +898,9 @@ rfs3_readlink(READLINK3args *args, READLINK3res *resp, struct exportinfo *exi,
va.va_mask = AT_ALL;
vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
#endif
+ /* Lie about object type again just to be consistent */
+ if (is_referral && vap != NULL)
+ vap->va_type = VLNK;
#if 0 /* notyet */
/*
@@ -884,8 +919,6 @@ rfs3_readlink(READLINK3args *args, READLINK3res *resp, struct exportinfo *exi,
goto out;
}
- *(data + MAXPATHLEN - uio.uio_resid) = '\0';
-
ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
name = nfscmd_convname(ca, exi, data, NFSCMD_CONV_OUTBOUND,
MAXPATHLEN + 1);
@@ -3863,6 +3896,10 @@ good:
nva.va_mask = AT_ALL;
nvap = rfs4_delegated_getattr(nvp, &nva, 0, cr) ? NULL : &nva;
#endif
+ /* Lie about the object type for a referral */
+ if (vn_is_nfs_reparse(nvp, cr))
+ nvap->va_type = VLNK;
+
vattr_to_post_op_attr(nvap, &infop[i].attr);
#ifdef DEBUG
diff --git a/usr/src/uts/common/fs/nfs/nfs4_attr.c b/usr/src/uts/common/fs/nfs/nfs4_attr.c
index 1740b64d30..c32a9526ec 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_attr.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_attr.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,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc.
- * All rights reserved. Use is subject to license terms.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/time.h>
#include <sys/systm.h>
@@ -107,7 +104,7 @@ nfs4_ver_fattr4_attr(vattr_t *vap, struct nfs4_ntov_map *ntovp,
case AT_ATIME:
if ((ntovp->nval != FATTR4_TIME_ACCESS) ||
(*errorp = nfs4_time_vton(&vap->va_ctime,
- &nap->time_access))) {
+ &nap->time_access))) {
/*
* either asked for FATTR4_TIME_ACCESS_SET -
* not used for setattr
@@ -119,7 +116,7 @@ nfs4_ver_fattr4_attr(vattr_t *vap, struct nfs4_ntov_map *ntovp,
case AT_MTIME:
if ((ntovp->nval != FATTR4_TIME_MODIFY) ||
(*errorp = nfs4_time_vton(&vap->va_mtime,
- &nap->time_modify))) {
+ &nap->time_modify))) {
/*
* either asked for FATTR4_TIME_MODIFY_SET -
* not used for setattr
@@ -130,7 +127,7 @@ nfs4_ver_fattr4_attr(vattr_t *vap, struct nfs4_ntov_map *ntovp,
break;
case AT_CTIME:
if (*errorp = nfs4_time_vton(&vap->va_ctime,
- &nap->time_metadata)) {
+ &nap->time_metadata)) {
/*
* system time invalid for otw transfers
*/
@@ -196,7 +193,7 @@ nfs4_set_fattr4_attr(vattr_t *vap, vsecattr_t *vsap,
case AT_ATIME:
if ((ntovp->nval != FATTR4_TIME_ACCESS_SET) ||
(*errorp = timestruc_to_settime4(&vap->va_atime,
- &nap->time_access_set, flags))) {
+ &nap->time_access_set, flags))) {
/* FATTR4_TIME_ACCESS - not used for verify */
retval = FALSE;
}
@@ -204,7 +201,7 @@ nfs4_set_fattr4_attr(vattr_t *vap, vsecattr_t *vsap,
case AT_MTIME:
if ((ntovp->nval != FATTR4_TIME_MODIFY_SET) ||
(*errorp = timestruc_to_settime4(&vap->va_mtime,
- &nap->time_modify_set, flags))) {
+ &nap->time_modify_set, flags))) {
/* FATTR4_TIME_MODIFY - not used for verify */
retval = FALSE;
}
@@ -260,7 +257,7 @@ vattr_to_fattr4(vattr_t *vap, vsecattr_t *vsap, fattr4 *fattrp, int flags,
fattrp->attrlist4_len = 0;
fattrp->attrlist4 = NULL;
na = kmem_zalloc(sizeof (union nfs4_attr_u) * nfs4_ntov_map_size,
- KM_SLEEP);
+ KM_SLEEP);
if (op == OP_SETATTR || op == OP_CREATE || op == OP_OPEN) {
/*
@@ -341,8 +338,8 @@ vattr_to_fattr4(vattr_t *vap, vsecattr_t *vsap, fattr4 *fattrp, int flags,
xdr_size += nfs4_ntov_map[i].xdr_size;
if ((nfs4_ntov_map[i].nval == FATTR4_TIME_ACCESS_SET ||
nfs4_ntov_map[i].nval == FATTR4_TIME_MODIFY_SET) &&
- attrfunc == nfs4_set_fattr4_attr &&
- !(flags & ATTR_UTIME)) {
+ attrfunc == nfs4_set_fattr4_attr &&
+ !(flags & ATTR_UTIME)) {
xdr_size -= 3 * BYTES_PER_XDR_UNIT;
}
} else {
@@ -351,19 +348,19 @@ vattr_to_fattr4(vattr_t *vap, vsecattr_t *vsap, fattr4 *fattrp, int flags,
* are AT_UID, AT_GID and FATTR4_ACL_MASK
*/
ASSERT(nfs4_ntov_map[i].vbit == AT_UID ||
- nfs4_ntov_map[i].vbit == AT_GID ||
- nfs4_ntov_map[i].fbit == FATTR4_ACL_MASK);
+ nfs4_ntov_map[i].vbit == AT_GID ||
+ nfs4_ntov_map[i].fbit == FATTR4_ACL_MASK);
if (nfs4_ntov_map[i].vbit == AT_UID) {
uid_attr = attrcnt;
xdr_size += BYTES_PER_XDR_UNIT; /* length */
xdr_size +=
- RNDUP(na[attrcnt].owner.utf8string_len);
+ RNDUP(na[attrcnt].owner.utf8string_len);
} else if (nfs4_ntov_map[i].vbit == AT_GID) {
gid_attr = attrcnt;
xdr_size += BYTES_PER_XDR_UNIT; /* length */
xdr_size +=
RNDUP(
- na[attrcnt].owner_group.utf8string_len);
+ na[attrcnt].owner_group.utf8string_len);
} else if (nfs4_ntov_map[i].fbit == FATTR4_ACL_MASK) {
nfsace4 *tmpacl = (nfsace4 *)vsap->vsa_aclentp;
@@ -411,7 +408,7 @@ vattr_to_fattr4(vattr_t *vap, vsecattr_t *vsap, fattr4 *fattrp, int flags,
for (i = 0; i < attrcnt; i++) {
if ((*nfs4_ntov_map[amap[i]].xfunc)(&xdr, &na[i]) == FALSE) {
cmn_err(CE_WARN, "vattr_to_fattr4: xdr encode of "
- "attribute failed\n");
+ "attribute failed\n");
error = EINVAL;
break;
}
@@ -422,11 +419,11 @@ done:
*/
if (uid_attr != -1 && na[uid_attr].owner.utf8string_val != NULL) {
kmem_free(na[uid_attr].owner.utf8string_val,
- na[uid_attr].owner.utf8string_len);
+ na[uid_attr].owner.utf8string_len);
}
if (gid_attr != -1 && na[gid_attr].owner_group.utf8string_val != NULL) {
kmem_free(na[gid_attr].owner_group.utf8string_val,
- na[gid_attr].owner_group.utf8string_len);
+ na[gid_attr].owner_group.utf8string_len);
}
/* xdrmem_destroy(&xdrs); */ /* NO-OP */
@@ -770,7 +767,7 @@ struct nfs4_ntov_map nfs4_ntov_map[] = {
FATTR4_TIME_MODIFY_SET, 4 * BYTES_PER_XDR_UNIT, xdr_settime4,
NULL, "fattr4_time_modify_set" },
- { FATTR4_MOUNTED_ON_FILEID_MASK, 0, FALSE, FALSE,
+ { FATTR4_MOUNTED_ON_FILEID_MASK, AT_NODEID, FALSE, FALSE,
FATTR4_MOUNTED_ON_FILEID, 2 * BYTES_PER_XDR_UNIT,
xdr_u_longlong_t,
NULL, "fattr4_mounted_on_fileid" },
diff --git a/usr/src/uts/common/fs/nfs/nfs4_callback.c b/usr/src/uts/common/fs/nfs/nfs4_callback.c
index 057eb3c608..90c570ba24 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_callback.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_callback.c
@@ -1493,7 +1493,8 @@ nfs4_do_delegreturn(rnode4_t *rp, int flags, cred_t *cr,
(void) nfs4_start_recovery(&e, mi, vp,
NULL, &rp->r_deleg_stateid,
lost_rqst.lr_op == OP_DELEGRETURN ?
- &lost_rqst : NULL, OP_DELEGRETURN, NULL);
+ &lost_rqst : NULL, OP_DELEGRETURN, NULL,
+ NULL, NULL);
nfs4_end_op(mi, vp, NULL, &recov_state, needrecov);
break;
}
@@ -1517,7 +1518,8 @@ nfs4_do_delegreturn(rnode4_t *rp, int flags, cred_t *cr,
(void) nfs4_start_recovery(&e, mi, vp,
NULL, &rp->r_deleg_stateid,
lost_rqst.lr_op == OP_DELEGRETURN ?
- &lost_rqst : NULL, OP_DELEGRETURN, NULL);
+ &lost_rqst : NULL, OP_DELEGRETURN, NULL,
+ NULL, NULL);
} else {
nfs4delegreturn_cleanup_impl(rp, NULL, ncg);
done = TRUE;
@@ -1956,7 +1958,7 @@ retry:
* thread will take it from here.
*/
(void) nfs4_start_recovery(&e, mi, vp, NULL, NULL,
- NULL, OP_OPEN, NULL);
+ NULL, OP_OPEN, NULL, NULL, NULL);
open_stream_rele(osp, rp);
*recovp = TRUE;
break;
diff --git a/usr/src/uts/common/fs/nfs/nfs4_client.c b/usr/src/uts/common/fs/nfs/nfs4_client.c
index b60b211df1..abbdaebee7 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_client.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_client.c
@@ -837,7 +837,7 @@ recov_retry:
if (nfs4_needs_recovery(&e, FALSE, vp->v_vfsp)) {
if (nfs4_start_recovery(&e, VTOMI4(vp), vp, NULL, NULL,
- NULL, OP_GETATTR, NULL) == FALSE) {
+ NULL, OP_GETATTR, NULL, NULL, NULL) == FALSE) {
nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_GETATTR,
&recov_state, 1);
goto recov_retry;
@@ -1027,7 +1027,7 @@ 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, NULL, NULL);
nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_GETATTR, &recov_state,
needrecov);
if (!e.error) {
@@ -3492,7 +3492,7 @@ recov_retry:
"nfs4renew: initiating recovery\n"));
if (nfs4_start_recovery(&e, mi, NULL, NULL, NULL, NULL,
- OP_RENEW, NULL) == FALSE) {
+ OP_RENEW, NULL, NULL, NULL) == FALSE) {
nfs4_end_op(mi, NULL, NULL, &recov_state, needrecov);
VFS_RELE(mi->mi_vfsp);
if (!e.error)
diff --git a/usr/src/uts/common/fs/nfs/nfs4_client_debug.c b/usr/src/uts/common/fs/nfs/nfs4_client_debug.c
index 5336ddf0c8..b8e85ae198 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_client_debug.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_client_debug.c
@@ -303,6 +303,17 @@ set_event(nfs4_event_type_t id, nfs4_revent_t *ep, mntinfo4_t *mi,
if (rp2 != NULL && rp2->r_svnode.sv_name != NULL)
ep->re_char2 = fn_path(rp2->r_svnode.sv_name);
break;
+ case RE_REFERRAL:
+ /* server we're being referred to */
+ if (server1 != NULL) {
+ len = strlen(server1);
+ ep->re_char1 = kmem_alloc(len + 1, KM_SLEEP);
+ bcopy(server1, ep->re_char1, len);
+ ep->re_char1[len] = '\0';
+ } else {
+ ep->re_char1 = NULL;
+ }
+ break;
default:
break;
}
@@ -391,6 +402,8 @@ successful_comm(nfs4_debug_msg_t *msgp)
case RE_SIGLOST:
case RE_SIGLOST_NO_DUMP:
case RE_LOST_STATE_BAD_OP:
+ case RE_REFERRAL:
+ /* placeholder */
return (0);
default:
return (0);
@@ -1039,6 +1052,18 @@ queue_print_event(nfs4_debug_msg_t *msg, mntinfo4_t *mi, int dump)
ep->re_char1, (void *)ep->re_rp1, ep->re_char2,
(void *)ep->re_rp2);
break;
+ case RE_REFERRAL:
+ if (ep->re_char1)
+ zcmn_err(zoneid, CE_NOTE,
+ "![NFS4][Server: %s][Mntpt: %s]"
+ "being referred from %s to %s", msg->msg_srv,
+ msg->msg_mntpt, msg->msg_srv, ep->re_char1);
+ else
+ zcmn_err(zoneid, CE_NOTE,
+ "![NFS4][Server: %s][Mntpt: %s]"
+ "NFS4: being referred from %s to unknown server",
+ msg->msg_srv, msg->msg_mntpt, msg->msg_srv);
+ break;
default:
zcmn_err(zoneid, CE_WARN,
"!queue_print_event: illegal event %d", ep->re_type);
@@ -1186,6 +1211,7 @@ id_to_dump_solo_event(nfs4_event_type_t id)
case RE_UNEXPECTED_ERRNO:
case RE_UNEXPECTED_STATUS:
case RE_LOST_STATE_BAD_OP:
+ case RE_REFERRAL:
return (1);
default:
return (0);
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 3546a88ea9..ed2c2c167a 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_client_secinfo.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_client_secinfo.c
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* NFS Version 4 client side SECINFO code.
*/
@@ -749,7 +747,7 @@ retry:
"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, NULL, NULL);
if (!e.error) {
e.error = geterrno4(res.status);
(void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
diff --git a/usr/src/uts/common/fs/nfs/nfs4_common.c b/usr/src/uts/common/fs/nfs/nfs4_common.c
index 4966d48946..fbd2670acc 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_common.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_common.c
@@ -19,13 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-
/*
* This is the loadable module wrapper.
*/
@@ -164,28 +161,28 @@ nfs4_setopts(vnode_t *vp, model_t model, struct nfs_args *buf)
mi->mi_acregmin = SEC2HR(ACMINMAX);
else
mi->mi_acregmin = SEC2HR(MIN(STRUCT_FGET(args,
- acregmin), ACMINMAX));
+ acregmin), ACMINMAX));
}
if (flags & NFSMNT_ACREGMAX) {
if (STRUCT_FGET(args, acregmax) < 0)
mi->mi_acregmax = SEC2HR(ACMAXMAX);
else
mi->mi_acregmax = SEC2HR(MIN(STRUCT_FGET(args,
- acregmax), ACMAXMAX));
+ acregmax), ACMAXMAX));
}
if (flags & NFSMNT_ACDIRMIN) {
if (STRUCT_FGET(args, acdirmin) < 0)
mi->mi_acdirmin = SEC2HR(ACMINMAX);
else
mi->mi_acdirmin = SEC2HR(MIN(STRUCT_FGET(args,
- acdirmin), ACMINMAX));
+ acdirmin), ACMINMAX));
}
if (flags & NFSMNT_ACDIRMAX) {
if (STRUCT_FGET(args, acdirmax) < 0)
mi->mi_acdirmax = SEC2HR(ACMAXMAX);
else
mi->mi_acdirmax = SEC2HR(MIN(STRUCT_FGET(args,
- acdirmax), ACMAXMAX));
+ acdirmax), ACMAXMAX));
}
return (0);
@@ -437,6 +434,8 @@ nfs4_recov_action_to_str(nfs4_recov_t what)
return ("NR_LOST_LOCK");
case NR_LOST_STATE_RQST:
return ("NR_LOST_STATE_RQST");
+ case NR_MOVED:
+ return ("NR_MOVED");
default:
(void) snprintf(buf, 40, "Unknown, code %d", (int)what);
return (buf);
diff --git a/usr/src/uts/common/fs/nfs/nfs4_idmap.c b/usr/src/uts/common/fs/nfs/nfs4_idmap.c
index 14e1708e53..a5f05a5d34 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_idmap.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_idmap.c
@@ -19,11 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
/*
* There are well defined policies for mapping uid and gid values to and
@@ -134,7 +133,7 @@
/*
* Truly global modular globals
*/
-static zone_key_t nfsidmap_zone_key;
+zone_key_t nfsidmap_zone_key;
static list_t nfsidmap_globals_list;
static kmutex_t nfsidmap_globals_lock;
static kmem_cache_t *nfsidmap_cache;
diff --git a/usr/src/uts/common/fs/nfs/nfs4_recovery.c b/usr/src/uts/common/fs/nfs/nfs4_recovery.c
index 9d2ef14175..ca32816d19 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_recovery.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_recovery.c
@@ -39,6 +39,11 @@
#include <sys/disp.h>
#include <sys/list.h>
#include <sys/sdt.h>
+#include <sys/mount.h>
+#include <sys/door.h>
+#include <nfs/nfssys.h>
+#include <nfs/nfsid_map.h>
+#include <nfs/nfs4_idmap_impl.h>
extern r4hashq_t *rtable4;
@@ -69,6 +74,8 @@ typedef struct {
nfs4_error_t rc_orig_errors; /* original errors causing recovery */
int rc_error;
nfs4_bseqid_entry_t *rc_bseqid_rqst;
+ vnode_t *rc_moved_vp;
+ char *rc_moved_nm;
} recov_info_t;
/*
@@ -135,6 +142,8 @@ int nfs4_srvmnt_fail_cnt = 0;
int nfs4_srvmnt_debug = 0;
#endif
+extern zone_key_t nfs4clnt_zone_key;
+
/* forward references, in alphabetic order */
static void close_after_open_resend(vnode_t *, cred_t *, uint32_t,
nfs4_error_t *);
@@ -169,7 +178,7 @@ static void resend_one_op(nfs4_lost_rqst_t *, nfs4_error_t *, mntinfo4_t *,
nfs4_server_t *);
static void save_bseqid_rqst(nfs4_bseqid_entry_t *, recov_info_t *);
static void start_recovery(recov_info_t *, mntinfo4_t *, vnode_t *, vnode_t *,
- nfs4_server_t *);
+ nfs4_server_t *, vnode_t *, char *);
static void start_recovery_action(nfs4_recov_t, bool_t, mntinfo4_t *, vnode_t *,
vnode_t *);
static int wait_for_recovery(mntinfo4_t *, nfs4_op_hint_t);
@@ -330,7 +339,7 @@ enqueue_bseqid_rqst(recov_info_t *recovp, mntinfo4_t *mi)
bool_t
nfs4_start_recovery(nfs4_error_t *ep, mntinfo4_t *mi, vnode_t *vp1,
vnode_t *vp2, stateid4 *sid, nfs4_lost_rqst_t *lost_rqstp, nfs_opnum4 op,
- nfs4_bseqid_entry_t *bsep)
+ nfs4_bseqid_entry_t *bsep, vnode_t *moved_vp, char *moved_nm)
{
recov_info_t *recovp;
nfs4_server_t *sp;
@@ -371,7 +380,7 @@ nfs4_start_recovery(nfs4_error_t *ep, mntinfo4_t *mi, vnode_t *vp1,
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);
+ start_recovery(recovp, mi, vp1, vp2, sp, moved_vp, moved_nm);
if (sp != NULL)
nfs4_server_rele(sp);
return (FALSE);
@@ -397,12 +406,13 @@ start_recovery_action(nfs4_recov_t what, bool_t reboot, mntinfo4_t *mi,
recovp->rc_action = what;
recovp->rc_srv_reboot = reboot;
recovp->rc_error = EIO;
- start_recovery(recovp, mi, vp1, vp2, NULL);
+ start_recovery(recovp, mi, vp1, vp2, NULL, NULL, NULL);
}
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,
+ vnode_t *moved_vp, char *moved_nm)
{
NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE,
"start_recovery: mi %p, what %s", (void*)mi,
@@ -563,7 +573,6 @@ again:
case NR_LOST_LOCK:
nfs4_enqueue_lost_rqst(recovp, mi);
break;
-
default:
nfs4_queue_event(RE_UNEXPECTED_ACTION, mi, NULL,
recovp->rc_action, NULL, NULL, 0, NULL, 0, TAG_NONE,
@@ -607,6 +616,8 @@ again:
ASSERT(VTOMI4(vp2) == mi);
VN_HOLD(recovp->rc_vp2);
}
+ recovp->rc_moved_vp = moved_vp;
+ recovp->rc_moved_nm = moved_nm;
(void) zthread_create(NULL, 0, nfs4_recov_thread, recovp, 0,
minclsyspri);
@@ -1937,7 +1948,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, NULL, NULL);
} else if (e.error != EINTR &&
!NFS4_FRC_UNMT_ERR(e.error, mi->mi_vfsp) &&
(e.error != 0 || e.stat != NFS4_OK)) {
@@ -2012,7 +2023,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, NULL, 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)));
@@ -2062,7 +2073,7 @@ recov_stale(mntinfo4_t *mi, vnode_t *vp)
if (needrecov) {
(void) nfs4_start_recovery(&e,
mi, rootvp, NULL, NULL, NULL,
- OP_GETATTR, NULL);
+ OP_GETATTR, NULL, NULL, NULL);
NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE,
"recov_stale: error=%d, stat=%d seen "
"on rp %s", e.error, e.stat,
@@ -2491,7 +2502,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, NULL, NULL);
}
}
@@ -2561,7 +2572,7 @@ recov_openfiles(recov_info_t *recovp, nfs4_server_t *sp)
mi->mi_vfsp)) {
(void) nfs4_start_recovery(&e, mi,
rep->re_vp, NULL, NULL, NULL,
- OP_OPEN, NULL);
+ OP_OPEN, NULL, NULL, NULL);
break;
}
}
@@ -2575,7 +2586,7 @@ 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);
+ NULL, NULL, NULL);
if (e.error != 0 || e.stat != NFS4_OK)
break;
}
@@ -2664,7 +2675,7 @@ nfs4_resend_lost_rqsts(recov_info_t *recovp, nfs4_server_t *sp)
} else {
(void) nfs4_start_recovery(&n4e,
mi, lrp->lr_dvp, lrp->lr_vp, NULL, NULL,
- lrp->lr_op, NULL);
+ lrp->lr_op, NULL, NULL, NULL);
}
return;
}
@@ -3122,10 +3133,10 @@ errs_to_action(recov_info_t *recovp,
case NFS4ERR_LEASE_MOVED:
action = xxx;
break;
+#endif
case NFS4ERR_MOVED:
- action = xxx;
+ action = NR_MOVED;
break;
-#endif
case NFS4ERR_BADHANDLE:
action = NR_BADHANDLE;
break;
diff --git a/usr/src/uts/common/fs/nfs/nfs4_rnode.c b/usr/src/uts/common/fs/nfs/nfs4_rnode.c
index 14cb143e95..48e9eafbb0 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_rnode.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_rnode.c
@@ -381,11 +381,12 @@ r4_do_attrcache(vnode_t *vp, nfs4_ga_res_t *garp, int newnode,
* creation time and it never changes for life
* of the rnode.
*
+ * This stub will be for a mirror-mount, rather than
+ * a referral (the latter also sets R4SRVSTUB).
+ *
* 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.
@@ -1769,6 +1770,52 @@ r4mkopenlist(mntinfo4_t *mi)
}
/*
+ * Given a filesystem id, check to see if any rnodes
+ * within this fsid reside in the rnode cache, other
+ * than one we know about.
+ *
+ * Return 1 if an rnode is found, 0 otherwise
+ */
+int
+r4find_by_fsid(mntinfo4_t *mi, fattr4_fsid *moved_fsid)
+{
+ rnode4_t *rp;
+ vnode_t *vp;
+ vfs_t *vfsp = mi->mi_vfsp;
+ fattr4_fsid *fsid;
+ int index, found = 0;
+
+ for (index = 0; index < rtable4size; index++) {
+ rw_enter(&rtable4[index].r_lock, RW_READER);
+ for (rp = rtable4[index].r_hashf;
+ rp != (rnode4_t *)(&rtable4[index]);
+ rp = rp->r_hashf) {
+
+ vp = RTOV4(rp);
+ if (vp->v_vfsp != vfsp)
+ continue;
+
+ /*
+ * XXX there might be a case where a
+ * replicated fs may have the same fsid
+ * across two different servers. This
+ * check isn't good enough in that case
+ */
+ fsid = &rp->r_srv_fsid;
+ if (FATTR4_FSID_EQ(moved_fsid, fsid)) {
+ found = 1;
+ break;
+ }
+ }
+ rw_exit(&rtable4[index].r_lock);
+
+ if (found)
+ break;
+ }
+ return (found);
+}
+
+/*
* Release the list of open instance references.
*/
@@ -1898,6 +1945,14 @@ r4_stub_mirrormount(rnode4_t *rp)
}
void
+r4_stub_referral(rnode4_t *rp)
+{
+ DTRACE_PROBE1(nfs4clnt__func__referral__moved,
+ vnode_t *, RTOV4(rp));
+ r4_stub_set(rp, NFS4_STUB_REFERRAL);
+}
+
+void
r4_stub_none(rnode4_t *rp)
{
r4_stub_set(rp, NFS4_STUB_NONE);
diff --git a/usr/src/uts/common/fs/nfs/nfs4_srv.c b/usr/src/uts/common/fs/nfs/nfs4_srv.c
index 842c30d53e..c7163712c0 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_srv.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_srv.c
@@ -56,6 +56,8 @@
#include <sys/ddi.h>
#include <sys/zone.h>
+#include <fs/fs_reparse.h>
+
#include <rpc/types.h>
#include <rpc/auth.h>
#include <rpc/rpcsec_gss.h>
@@ -82,7 +84,6 @@ static int rfs4_maxlock_tries = RFS4_MAXLOCK_TRIES;
#define RFS4_LOCK_DELAY 10 /* Milliseconds */
static clock_t rfs4_lock_delay = RFS4_LOCK_DELAY;
extern struct svc_ops rdma_svc_ops;
-/* End of Tunables */
static int rdma_setup_read_data4(READ4args *, READ4res *);
@@ -243,7 +244,7 @@ static void rfs4_op_secinfo_free(nfs_resop4 *);
static nfsstat4 check_open_access(uint32_t,
struct compound_state *, struct svc_req *);
nfsstat4 rfs4_client_sysid(rfs4_client_t *, sysid_t *);
-void rfs4_ss_clid(rfs4_client_t *, struct svc_req *);
+void rfs4_ss_clid(rfs4_client_t *);
/*
* translation table for attrs
@@ -465,6 +466,8 @@ void rfs4_ss_chkclid(rfs4_client_t *);
extern size_t strlcpy(char *dst, const char *src, size_t dstsize);
+extern void rfs4_free_fs_locations4(fs_locations4 *);
+
#ifdef nextdp
#undef nextdp
#endif
@@ -1609,6 +1612,7 @@ rfs4_op_create(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
resp->attrset = 0;
sarg.sbp = &sb;
+ sarg.is_referral = B_FALSE;
nfs4_ntov_table_init(&ntov);
status = do_rfs4_set_attrs(&resp->attrset,
@@ -2314,13 +2318,26 @@ rfs4_op_getattr(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
sarg.sbp = &sb;
sarg.cs = cs;
+ sarg.is_referral = B_FALSE;
status = bitmap4_to_attrmask(args->attr_request, &sarg);
if (status == NFS4_OK) {
+
status = bitmap4_get_sysattrs(&sarg);
- if (status == NFS4_OK)
+ if (status == NFS4_OK) {
+
+ /* Is this a referral? */
+ if (vn_is_nfs_reparse(cs->vp, cs->cr)) {
+ /* Older V4 Solaris client sees a link */
+ if (client_is_downrev(req))
+ sarg.vap->va_type = VLNK;
+ else
+ sarg.is_referral = B_TRUE;
+ }
+
status = do_rfs4_op_getattr(args->attr_request,
&resp->obj_attributes, &sarg);
+ }
}
*cs->statusp = resp->status = status;
out:
@@ -2354,6 +2371,25 @@ rfs4_op_getfh(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
goto out;
}
+ /* check for reparse point at the share point */
+ if (cs->exi->exi_moved || vn_is_nfs_reparse(cs->exi->exi_vp, cs->cr)) {
+ /* it's all bad */
+ cs->exi->exi_moved = 1;
+ *cs->statusp = resp->status = NFS4ERR_MOVED;
+ DTRACE_PROBE2(nfs4serv__func__referral__shared__moved,
+ vnode_t *, cs->vp, char *, "rfs4_op_getfh");
+ return;
+ }
+
+ /* check for reparse point at vp */
+ if (vn_is_nfs_reparse(cs->vp, cs->cr) && !client_is_downrev(req)) {
+ /* it's not all bad */
+ *cs->statusp = resp->status = NFS4ERR_MOVED;
+ DTRACE_PROBE2(nfs4serv__func__referral__moved,
+ vnode_t *, cs->vp, char *, "rfs4_op_getfh");
+ return;
+ }
+
resp->object.nfs_fh4_val =
kmem_alloc(cs->fh.nfs_fh4_len, KM_SLEEP);
nfs_fh4_copy(&cs->fh, &resp->object);
@@ -3688,6 +3724,7 @@ rfs4_op_readlink(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
char *data;
struct sockaddr *ca;
char *name = NULL;
+ int is_referral;
DTRACE_NFSV4_1(op__readlink__start, struct compound_state *, cs);
@@ -3703,14 +3740,25 @@ rfs4_op_readlink(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
goto out;
}
- if (vp->v_type == VDIR) {
- *cs->statusp = resp->status = NFS4ERR_ISDIR;
- goto out;
- }
+ /* Is it a referral? */
+ if (vn_is_nfs_reparse(vp, cs->cr) && client_is_downrev(req)) {
+
+ is_referral = 1;
+
+ } else {
+
+ is_referral = 0;
+
+ if (vp->v_type == VDIR) {
+ *cs->statusp = resp->status = NFS4ERR_ISDIR;
+ goto out;
+ }
+
+ if (vp->v_type != VLNK) {
+ *cs->statusp = resp->status = NFS4ERR_INVAL;
+ goto out;
+ }
- if (vp->v_type != VLNK) {
- *cs->statusp = resp->status = NFS4ERR_INVAL;
- goto out;
}
va.va_mask = AT_MODE;
@@ -3727,16 +3775,39 @@ rfs4_op_readlink(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
data = kmem_alloc(MAXPATHLEN + 1, KM_SLEEP);
- iov.iov_base = data;
- iov.iov_len = MAXPATHLEN;
- uio.uio_iov = &iov;
- uio.uio_iovcnt = 1;
- uio.uio_segflg = UIO_SYSSPACE;
- uio.uio_extflg = UIO_COPY_CACHED;
- uio.uio_loffset = 0;
- uio.uio_resid = MAXPATHLEN;
+ if (is_referral) {
+ char *s;
+ size_t strsz;
+
+ /* Get an artificial symlink based on a referral */
+ s = build_symlink(vp, cs->cr, &strsz);
+ global_svstat_ptr[4][NFS_REFERLINKS].value.ui64++;
+ DTRACE_PROBE2(nfs4serv__func__referral__reflink,
+ vnode_t *, vp, char *, s);
+ if (s == NULL)
+ error = EINVAL;
+ else {
+ error = 0;
+ (void) strlcpy(data, s, MAXPATHLEN + 1);
+ kmem_free(s, strsz);
+ }
+
+ } else {
+
+ iov.iov_base = data;
+ iov.iov_len = MAXPATHLEN;
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_segflg = UIO_SYSSPACE;
+ uio.uio_extflg = UIO_COPY_CACHED;
+ uio.uio_loffset = 0;
+ uio.uio_resid = MAXPATHLEN;
+
+ error = VOP_READLINK(vp, &uio, cs->cr, NULL);
- error = VOP_READLINK(vp, &uio, cs->cr, NULL);
+ if (!error)
+ *(data + MAXPATHLEN - uio.uio_resid) = '\0';
+ }
if (error) {
kmem_free((caddr_t)data, (uint_t)MAXPATHLEN + 1);
@@ -3744,8 +3815,6 @@ rfs4_op_readlink(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
goto out;
}
- *(data + MAXPATHLEN - uio.uio_resid) = '\0';
-
ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
name = nfscmd_convname(ca, cs->exi, data, NFSCMD_CONV_OUTBOUND,
MAXPATHLEN + 1);
@@ -5053,6 +5122,7 @@ do_rfs4_op_setattr(bitmap4 *resp, fattr4 *fattrp, struct compound_state *cs,
*resp = 0;
sarg.sbp = &sb;
+ sarg.is_referral = B_FALSE;
nfs4_ntov_table_init(&ntov);
status = do_rfs4_set_attrs(resp, fattrp, cs, &sarg, &ntov,
NFS4ATTR_SETIT);
@@ -5347,6 +5417,7 @@ rfs4_op_verify(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
}
sarg.sbp = &sb;
+ sarg.is_referral = B_FALSE;
nfs4_ntov_table_init(&ntov);
resp->status = do_rfs4_set_attrs(NULL, &args->obj_attributes, cs,
&sarg, &ntov, NFS4ATTR_VERIT);
@@ -5408,6 +5479,7 @@ rfs4_op_nverify(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
return;
}
sarg.sbp = &sb;
+ sarg.is_referral = B_FALSE;
nfs4_ntov_table_init(&ntov);
resp->status = do_rfs4_set_attrs(NULL, &args->obj_attributes, cs,
&sarg, &ntov, NFS4ATTR_VERIT);
@@ -6212,6 +6284,7 @@ rfs4_createfile(OPEN4args *args, struct svc_req *req, struct compound_state *cs,
char *name = NULL;
sarg.sbp = &sb;
+ sarg.is_referral = B_FALSE;
dvp = cs->vp;
@@ -7806,7 +7879,8 @@ rfs4_op_setclientid(nfs_argop4 *argop, nfs_resop4 *resop,
SETCLIENTID4args *args = &argop->nfs_argop4_u.opsetclientid;
SETCLIENTID4res *res = &resop->nfs_resop4_u.opsetclientid;
rfs4_client_t *cp, *newcp, *cp_confirmed, *cp_unconfirmed;
- bool_t create = TRUE;
+ rfs4_clntip_t *ci;
+ bool_t create;
char *addr, *netid;
int len;
@@ -7816,6 +7890,27 @@ retry:
newcp = cp_confirmed = cp_unconfirmed = NULL;
/*
+ * Save the caller's IP address
+ */
+ args->client.cl_addr =
+ (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
+
+ /*
+ * Record if it is a Solaris client that cannot handle referrals.
+ */
+ if (strstr(args->client.id_val, "Solaris") &&
+ !strstr(args->client.id_val, "+referrals")) {
+ /* Add a "yes, it's downrev" record */
+ create = TRUE;
+ ci = rfs4_find_clntip(args->client.cl_addr, &create);
+ ASSERT(ci != NULL);
+ rfs4_dbe_rele(ci->ri_dbe);
+ } else {
+ /* Remove any previous record */
+ rfs4_invalidate_clntip(args->client.cl_addr);
+ }
+
+ /*
* In search of an EXISTING client matching the incoming
* request to establish a new client identifier at the server
*/
@@ -8063,7 +8158,7 @@ rfs4_op_setclientid_confirm(nfs_argop4 *argop, nfs_resop4 *resop,
* Record clientid in stable storage.
* Must be done after server instance has been assigned.
*/
- rfs4_ss_clid(cp, req);
+ rfs4_ss_clid(cp);
rfs4_dbe_unlock(cp->rc_dbe);
@@ -9363,3 +9458,283 @@ rdma_setup_read_data4(READ4args *args, READ4res *rok)
rok->wlist = wcl;
return (TRUE);
}
+
+/* tunable to disable server referrals */
+int rfs4_no_referrals = 0;
+
+/*
+ * Find an NFS record in reparse point data.
+ * Returns 0 for success and <0 or an errno value on failure.
+ */
+int
+vn_find_nfs_record(vnode_t *vp, nvlist_t **nvlp, char **svcp, char **datap)
+{
+ int err;
+ char *stype, *val;
+ nvlist_t *nvl;
+ nvpair_t *curr;
+
+ if ((nvl = reparse_init()) == NULL)
+ return (-1);
+
+ if ((err = reparse_vnode_parse(vp, nvl)) != 0) {
+ reparse_free(nvl);
+ return (err);
+ }
+
+ curr = NULL;
+ while ((curr = nvlist_next_nvpair(nvl, curr)) != NULL) {
+ if ((stype = nvpair_name(curr)) == NULL) {
+ reparse_free(nvl);
+ return (-2);
+ }
+ if (strncasecmp(stype, "NFS", 3) == 0)
+ break;
+ }
+
+ if ((curr == NULL) ||
+ (nvpair_value_string(curr, &val))) {
+ reparse_free(nvl);
+ return (-3);
+ }
+ *nvlp = nvl;
+ *svcp = stype;
+ *datap = val;
+ return (0);
+}
+
+int
+vn_is_nfs_reparse(vnode_t *vp, cred_t *cr)
+{
+ nvlist_t *nvl;
+ char *s, *d;
+
+ if (rfs4_no_referrals != 0)
+ return (B_FALSE);
+
+ if (vn_is_reparse(vp, cr, NULL) == B_FALSE)
+ return (B_FALSE);
+
+ if (vn_find_nfs_record(vp, &nvl, &s, &d) != 0)
+ return (B_FALSE);
+
+ reparse_free(nvl);
+
+ return (B_TRUE);
+}
+
+/*
+ * There is a user-level copy of this routine in ref_subr.c.
+ * Changes should be kept in sync.
+ */
+static int
+nfs4_create_components(char *path, component4 *comp4)
+{
+ int slen, plen, ncomp;
+ char *ori_path, *nxtc, buf[MAXNAMELEN];
+
+ if (path == NULL)
+ return (0);
+
+ plen = strlen(path) + 1; /* include the terminator */
+ ori_path = path;
+ ncomp = 0;
+
+ /* count number of components in the path */
+ for (nxtc = path; nxtc < ori_path + plen; nxtc++) {
+ if (*nxtc == '/' || *nxtc == '\0' || *nxtc == '\n') {
+ if ((slen = nxtc - path) == 0) {
+ path = nxtc + 1;
+ continue;
+ }
+
+ if (comp4 != NULL) {
+ bcopy(path, buf, slen);
+ buf[slen] = '\0';
+ str_to_utf8(buf, &comp4[ncomp]);
+ }
+
+ ncomp++; /* 1 valid component */
+ path = nxtc + 1;
+ }
+ if (*nxtc == '\0' || *nxtc == '\n')
+ break;
+ }
+
+ return (ncomp);
+}
+
+/*
+ * There is a user-level copy of this routine in ref_subr.c.
+ * Changes should be kept in sync.
+ */
+static int
+make_pathname4(char *path, pathname4 *pathname)
+{
+ int ncomp;
+ component4 *comp4;
+
+ if (pathname == NULL)
+ return (0);
+
+ if (path == NULL) {
+ pathname->pathname4_val = NULL;
+ pathname->pathname4_len = 0;
+ return (0);
+ }
+
+ /* count number of components to alloc buffer */
+ if ((ncomp = nfs4_create_components(path, NULL)) == 0) {
+ pathname->pathname4_val = NULL;
+ pathname->pathname4_len = 0;
+ return (0);
+ }
+ comp4 = kmem_zalloc(ncomp * sizeof (component4), KM_SLEEP);
+
+ /* copy components into allocated buffer */
+ ncomp = nfs4_create_components(path, comp4);
+
+ pathname->pathname4_val = comp4;
+ pathname->pathname4_len = ncomp;
+
+ return (ncomp);
+}
+
+#define xdr_fs_locations4 xdr_fattr4_fs_locations
+
+fs_locations4 *
+fetch_referral(vnode_t *vp, cred_t *cr)
+{
+ nvlist_t *nvl;
+ char *stype, *sdata;
+ fs_locations4 *result;
+ char buf[1024];
+ size_t bufsize;
+ XDR xdr;
+ int err;
+
+ /*
+ * Check attrs to ensure it's a reparse point
+ */
+ if (vn_is_reparse(vp, cr, NULL) == B_FALSE)
+ return (NULL);
+
+ /*
+ * Look for an NFS record and get the type and data
+ */
+ if (vn_find_nfs_record(vp, &nvl, &stype, &sdata) != 0)
+ return (NULL);
+
+ /*
+ * With the type and data, upcall to get the referral
+ */
+ bufsize = sizeof (buf);
+ bzero(buf, sizeof (buf));
+ err = reparse_kderef((const char *)stype, (const char *)sdata,
+ buf, &bufsize);
+ reparse_free(nvl);
+
+ DTRACE_PROBE4(nfs4serv__func__referral__upcall,
+ char *, stype, char *, sdata, char *, buf, int, err);
+ if (err) {
+ cmn_err(CE_NOTE,
+ "reparsed daemon not running: unable to get referral (%d)",
+ err);
+ return (NULL);
+ }
+
+ /*
+ * We get an XDR'ed record back from the kderef call
+ */
+ xdrmem_create(&xdr, buf, bufsize, XDR_DECODE);
+ result = kmem_alloc(sizeof (fs_locations4), KM_SLEEP);
+ err = xdr_fs_locations4(&xdr, result);
+ XDR_DESTROY(&xdr);
+ if (err != TRUE) {
+ DTRACE_PROBE1(nfs4serv__func__referral__upcall__xdrfail,
+ int, err);
+ return (NULL);
+ }
+
+ /*
+ * Look at path to recover fs_root, ignoring the leading '/'
+ */
+ (void) make_pathname4(vp->v_path, &result->fs_root);
+
+ return (result);
+}
+
+char *
+build_symlink(vnode_t *vp, cred_t *cr, size_t *strsz)
+{
+ fs_locations4 *fsl;
+ fs_location4 *fs;
+ char *server, *path, *symbuf;
+ static char *prefix = "/net/";
+ int i, size, npaths;
+ uint_t len;
+
+ /* Get the referral */
+ if ((fsl = fetch_referral(vp, cr)) == NULL)
+ return (NULL);
+
+ /* Deal with only the first location and first server */
+ fs = &fsl->locations_val[0];
+ server = utf8_to_str(&fs->server_val[0], &len, NULL);
+ if (server == NULL) {
+ rfs4_free_fs_locations4(fsl);
+ kmem_free(fsl, sizeof (fs_locations4));
+ return (NULL);
+ }
+
+ /* Figure out size for "/net/" + host + /path/path/path + NULL */
+ size = strlen(prefix) + len;
+ for (i = 0; i < fs->rootpath.pathname4_len; i++)
+ size += fs->rootpath.pathname4_val[i].utf8string_len + 1;
+
+ /* Allocate the symlink buffer and fill it */
+ symbuf = kmem_zalloc(size, KM_SLEEP);
+ (void) strcat(symbuf, prefix);
+ (void) strcat(symbuf, server);
+ kmem_free(server, len);
+
+ npaths = 0;
+ for (i = 0; i < fs->rootpath.pathname4_len; i++) {
+ path = utf8_to_str(&fs->rootpath.pathname4_val[i], &len, NULL);
+ if (path == NULL)
+ continue;
+ (void) strcat(symbuf, "/");
+ (void) strcat(symbuf, path);
+ npaths++;
+ kmem_free(path, len);
+ }
+
+ rfs4_free_fs_locations4(fsl);
+ kmem_free(fsl, sizeof (fs_locations4));
+
+ if (strsz != NULL)
+ *strsz = size;
+ return (symbuf);
+}
+
+/*
+ * Check to see if we have a downrev Solaris client, so that we
+ * can send it a symlink instead of a referral.
+ */
+int
+client_is_downrev(struct svc_req *req)
+{
+ struct sockaddr *ca;
+ rfs4_clntip_t *ci;
+ bool_t create = FALSE;
+ int is_downrev;
+
+ ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
+ ASSERT(ca);
+ ci = rfs4_find_clntip(ca, &create);
+ if (ci == NULL)
+ return (0);
+ is_downrev = ci->ri_no_referrals;
+ rfs4_dbe_rele(ci->ri_dbe);
+ return (is_downrev);
+}
diff --git a/usr/src/uts/common/fs/nfs/nfs4_srv_attr.c b/usr/src/uts/common/fs/nfs/nfs4_srv_attr.c
index 729718b5b9..c1f64d69bc 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_srv_attr.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_srv_attr.c
@@ -29,6 +29,9 @@
#include <nfs/export.h>
#include <nfs/nfs4.h>
#include <sys/ddi.h>
+#include <sys/door.h>
+#include <sys/sdt.h>
+#include <nfs/nfssys.h>
void rfs4_init_compound_state(struct compound_state *);
@@ -141,6 +144,7 @@ rfs4_attr_init()
sarg.flag = 0;
sarg.rdattr_error = NFS4_OK;
sarg.rdattr_error_req = FALSE;
+ sarg.is_referral = B_FALSE;
rfs4_ntov_init();
@@ -634,7 +638,10 @@ rfs4_fattr4_fsid(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
error = EINVAL;
break; /* this attr is supported */
case NFS4ATTR_GETIT:
- if (sarg->cs->exi->exi_volatile_dev) {
+ if (sarg->is_referral) {
+ na->fsid.major = 1;
+ na->fsid.minor = 0;
+ } else if (sarg->cs->exi->exi_volatile_dev) {
pmaj[0] = sarg->cs->exi->exi_fsid.val[0];
pmaj[1] = sarg->cs->exi->exi_fsid.val[1];
na->fsid.minor = 0;
@@ -647,7 +654,11 @@ rfs4_fattr4_fsid(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
error = EINVAL;
break;
case NFS4ATTR_VERIT:
- if (sarg->cs->exi->exi_volatile_dev) {
+ if (sarg->is_referral) {
+ if (na->fsid.major != 1 ||
+ na->fsid.minor != 0)
+ error = -1;
+ } else if (sarg->cs->exi->exi_volatile_dev) {
if (pmaj[0] != sarg->cs->exi->exi_fsid.val[0] ||
pmaj[1] != sarg->cs->exi->exi_fsid.val[1] ||
na->fsid.minor != 0)
@@ -1495,12 +1506,109 @@ rfs4_fattr4_files_total(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
return (error);
}
+static void
+rfs4_free_pathname4(pathname4 *pn4)
+{
+ int i, len;
+ utf8string *utf8s;
+
+ if (pn4 == NULL || (len = pn4->pathname4_len) == 0 ||
+ (utf8s = pn4->pathname4_val) == NULL)
+ return;
+
+ for (i = 0; i < len; i++, utf8s++) {
+ if (utf8s->utf8string_val == NULL ||
+ utf8s->utf8string_len == 0)
+ continue;
+
+ kmem_free(utf8s->utf8string_val, utf8s->utf8string_len);
+ utf8s->utf8string_val = NULL;
+ }
+
+ kmem_free(pn4->pathname4_val,
+ sizeof (utf8string) * pn4->pathname4_len);
+ pn4->pathname4_val = 0;
+}
+
+static void
+rfs4_free_fs_location4(fs_location4 *fsl4)
+{
+ if (fsl4 == NULL)
+ return;
+
+ rfs4_free_pathname4((pathname4 *)&fsl4->server_len);
+ rfs4_free_pathname4(&fsl4->rootpath);
+}
+
+void
+rfs4_free_fs_locations4(fs_locations4 *fsls4)
+{
+ int i, len;
+ fs_location4 *fsl4;
+
+ if (fsls4 == NULL)
+ return;
+
+ /* free fs_root */
+ rfs4_free_pathname4(&fsls4->fs_root);
+
+ if ((len = fsls4->locations_len) == 0 ||
+ (fsl4 = fsls4->locations_val) == NULL)
+ return;
+
+ /* free fs_location4 */
+ for (i = 0; i < len; i++) {
+ rfs4_free_fs_location4(fsl4);
+ fsl4++;
+ }
+
+ kmem_free(fsls4->locations_val, sizeof (fs_location4) * len);
+ fsls4->locations_val = NULL;
+}
+
/* ARGSUSED */
static int
rfs4_fattr4_fs_locations(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
- return (ENOTSUP);
+ int error = 0;
+ fs_locations4 *fsl;
+
+ if (RFS4_MANDATTR_ONLY)
+ return (ENOTSUP);
+
+ switch (cmd) {
+ case NFS4ATTR_SUPPORTED:
+ if (sarg->op == NFS4ATTR_SETIT || sarg->op == NFS4ATTR_VERIT)
+ error = EINVAL;
+ break; /* this attr is supported */
+
+ case NFS4ATTR_GETIT:
+ fsl = fetch_referral(sarg->cs->vp, sarg->cs->cr);
+ if (fsl == NULL)
+ error = EINVAL;
+ else {
+ na->fs_locations = *fsl;
+ kmem_free(fsl, sizeof (fs_locations4));
+ }
+ global_svstat_ptr[4][NFS_REFERRALS].value.ui64++;
+ break;
+
+ case NFS4ATTR_FREEIT:
+ if (sarg->op == NFS4ATTR_SETIT || sarg->op == NFS4ATTR_VERIT)
+ error = EINVAL;
+ rfs4_free_fs_locations4(&na->fs_locations);
+ break;
+
+ case NFS4ATTR_SETIT:
+ case NFS4ATTR_VERIT:
+ /*
+ * read-only attr
+ */
+ error = EINVAL;
+ break;
+ }
+ return (error);
}
/* ARGSUSED */
diff --git a/usr/src/uts/common/fs/nfs/nfs4_srv_readdir.c b/usr/src/uts/common/fs/nfs/nfs4_srv_readdir.c
index debdacc1cd..3069a98835 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_srv_readdir.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_srv_readdir.c
@@ -97,7 +97,6 @@ static nfs_ftype4 vt_to_nf4[] = {
0, NF4REG, NF4DIR, NF4BLK, NF4CHR, NF4LNK, NF4FIFO, 0, 0, NF4SOCK, 0
};
-
int
nfs4_readdir_getvp(vnode_t *dvp, char *d_name, vnode_t **vpp,
struct exportinfo **exi, struct svc_req *req,
@@ -117,8 +116,20 @@ nfs4_readdir_getvp(vnode_t *dvp, char *d_name, vnode_t **vpp,
NULL, NULL, NULL))
return (error);
+ /*
+ * If the directory is a referral point, don't return the
+ * attrs, instead set rdattr_error to MOVED.
+ */
+ if (vn_is_nfs_reparse(vp, cs->cr) && !client_is_downrev(req)) {
+ VN_RELE(vp);
+ DTRACE_PROBE2(nfs4serv__func__referral__moved,
+ vnode_t *, vp, char *, "nfs4_readdir_getvp");
+ return (NFS4ERR_MOVED);
+ }
+
/* Is this object mounted upon? */
ismntpt = vn_ismntpt(vp);
+
/*
* Nothing more to do if object is not a mount point or
* a possible LOFS shadow of an LOFS mount (which won't
@@ -141,6 +152,13 @@ nfs4_readdir_getvp(vnode_t *dvp, char *d_name, vnode_t **vpp,
VN_RELE(pre_tvp);
return (error);
}
+ if (vn_is_nfs_reparse(vp, cs->cr)) {
+ VN_RELE(vp);
+ VN_RELE(pre_tvp);
+ DTRACE_PROBE2(nfs4serv__func__referral__moved,
+ vnode_t *, vp, char *, "nfs4_readdir_getvp");
+ return (NFS4ERR_MOVED);
+ }
}
bzero(&fid, sizeof (fid));
@@ -818,9 +836,18 @@ reencode_attrs:
va.va_mask = AT_ALL;
rddirattr_error =
VOP_GETATTR(vp, &va, 0, cs->cr, NULL);
- if (rddirattr_error)
+ if (rddirattr_error) {
ae = ar & (FATTR4_RDATTR_ERROR_MASK |
FATTR4_MOUNTED_ON_FILEID_MASK);
+ } else {
+ /*
+ * We may lie about the object
+ * type for a referral
+ */
+ if (vn_is_nfs_reparse(vp, cs->cr) &&
+ client_is_downrev(req))
+ va.va_type = VLNK;
+ }
}
}
diff --git a/usr/src/uts/common/fs/nfs/nfs4_state.c b/usr/src/uts/common/fs/nfs/nfs4_state.c
index ef0f2c800b..0659e8c253 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_state.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_state.c
@@ -288,6 +288,8 @@ rfs4_table_t *rfs4_client_tab;
static rfs4_index_t *rfs4_clientid_idx;
static rfs4_index_t *rfs4_nfsclnt_idx;
+static rfs4_table_t *rfs4_clntip_tab;
+static rfs4_index_t *rfs4_clntip_idx;
static rfs4_table_t *rfs4_openowner_tab;
static rfs4_index_t *rfs4_openowner_idx;
static rfs4_table_t *rfs4_state_tab;
@@ -330,6 +332,7 @@ static rfs4_index_t *rfs4_deleg_state_idx;
static time_t rfs4_client_cache_time = 0;
+static time_t rfs4_clntip_cache_time = 0;
static time_t rfs4_openowner_cache_time = 0;
static time_t rfs4_state_cache_time = 0;
static time_t rfs4_lo_state_cache_time = 0;
@@ -348,6 +351,12 @@ static void *clientid_mkkey(rfs4_entry_t);
static uint32_t nfsclnt_hash(void *);
static bool_t nfsclnt_compare(rfs4_entry_t, void *);
static void *nfsclnt_mkkey(rfs4_entry_t);
+static bool_t rfs4_clntip_expiry(rfs4_entry_t);
+static void rfs4_clntip_destroy(rfs4_entry_t);
+static bool_t rfs4_clntip_create(rfs4_entry_t, void *);
+static uint32_t clntip_hash(void *);
+static bool_t clntip_compare(rfs4_entry_t, void *);
+static void *clntip_mkkey(rfs4_entry_t);
static bool_t rfs4_openowner_create(rfs4_entry_t, void *);
static void rfs4_openowner_destroy(rfs4_entry_t);
static bool_t rfs4_openowner_expiry(rfs4_entry_t);
@@ -883,7 +892,7 @@ rfs4_ss_chkclid_sip(rfs4_client_t *cp, rfs4_servinst_t *sip)
* the server-generated short-hand clientid.
*/
void
-rfs4_ss_clid(rfs4_client_t *cp, struct svc_req *req)
+rfs4_ss_clid(rfs4_client_t *cp)
{
const char *kinet_ntop6(uchar_t *, char *, size_t);
char leaf[MAXNAMELEN], buf[INET6_ADDRSTRLEN];
@@ -896,19 +905,12 @@ rfs4_ss_clid(rfs4_client_t *cp, struct svc_req *req)
buf[0] = 0;
-
- ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
- if (ca == NULL) {
- return;
- }
+ ca = (struct sockaddr *)&cp->rc_addr;
/*
* Convert the caller's IP address to a dotted string
*/
if (ca->sa_family == AF_INET) {
-
- bcopy(svc_getrpccaller(req->rq_xprt)->buf, &cp->rc_addr,
- sizeof (struct sockaddr_in));
b = (uchar_t *)&((struct sockaddr_in *)ca)->sin_addr;
(void) sprintf(buf, "%03d.%03d.%03d.%03d", b[0] & 0xFF,
b[1] & 0xFF, b[2] & 0xFF, b[3] & 0xFF);
@@ -916,8 +918,6 @@ rfs4_ss_clid(rfs4_client_t *cp, struct svc_req *req)
struct sockaddr_in6 *sin6;
sin6 = (struct sockaddr_in6 *)ca;
- bcopy(svc_getrpccaller(req->rq_xprt)->buf, &cp->rc_addr,
- sizeof (struct sockaddr_in6));
(void) kinet_ntop6((uchar_t *)&sin6->sin6_addr,
buf, INET6_ADDRSTRLEN);
}
@@ -1257,6 +1257,22 @@ rfs4_state_init()
clientid_compare, clientid_mkkey,
FALSE);
+ rfs4_clntip_cache_time = 86400 * 365; /* about a year */
+ rfs4_clntip_tab = rfs4_table_create(rfs4_server_state,
+ "ClntIP",
+ rfs4_clntip_cache_time,
+ 1,
+ rfs4_clntip_create,
+ rfs4_clntip_destroy,
+ rfs4_clntip_expiry,
+ sizeof (rfs4_clntip_t),
+ TABSIZE,
+ MAXTABSZ, 100);
+ rfs4_clntip_idx = rfs4_index_create(rfs4_clntip_tab,
+ "client_ip", clntip_hash,
+ clntip_compare, clntip_mkkey,
+ TRUE);
+
rfs4_openowner_cache_time *= rfs4_lease_time;
rfs4_openowner_tab = rfs4_table_create(rfs4_server_state,
"OpenOwner",
@@ -1649,6 +1665,7 @@ rfs4_client_create(rfs4_entry_t u_entry, void *arg)
{
rfs4_client_t *cp = (rfs4_client_t *)u_entry;
nfs_client_id4 *client = (nfs_client_id4 *)arg;
+ struct sockaddr *ca;
cid *cidp;
scid_confirm_verf *scvp;
@@ -1667,6 +1684,14 @@ rfs4_client_create(rfs4_entry_t u_entry, void *arg)
bcopy(client->id_val, cp->rc_nfs_client.id_val, client->id_len);
cp->rc_nfs_client.verifier = client->verifier;
+ /* Copy client's IP address */
+ ca = client->cl_addr;
+ if (ca->sa_family == AF_INET)
+ bcopy(ca, &cp->rc_addr, sizeof (struct sockaddr_in));
+ else if (ca->sa_family == AF_INET6)
+ bcopy(ca, &cp->rc_addr, sizeof (struct sockaddr_in6));
+ cp->rc_nfs_client.cl_addr = (struct sockaddr *)&cp->rc_addr;
+
/* Init the value for the SETCLIENTID_CONFIRM verifier */
scvp = (scid_confirm_verf *)&cp->rc_confirm_verf;
scvp->cv_impl.c_id = cidp->impl_id.c_id;
@@ -1781,6 +1806,119 @@ rfs4_findclient_by_id(clientid4 clientid, bool_t find_unconfirmed)
}
}
+static uint32_t
+clntip_hash(void *key)
+{
+ struct sockaddr *addr = key;
+ int i, len = 0;
+ uint32_t hash = 0;
+
+ if (addr->sa_family == AF_INET)
+ len = sizeof (struct sockaddr_in);
+ else if (addr->sa_family == AF_INET6)
+ len = sizeof (struct sockaddr_in6);
+
+ for (i = 0; i < len; i++) {
+ hash <<= 1;
+ hash += (uint_t)(((char *)addr)[i]);
+ }
+ return (hash);
+}
+
+static bool_t
+clntip_compare(rfs4_entry_t entry, void *key)
+{
+ rfs4_clntip_t *cp = (rfs4_clntip_t *)entry;
+ struct sockaddr *addr = key;
+ int len = 0;
+
+ if (addr->sa_family == AF_INET)
+ len = sizeof (struct sockaddr_in);
+ else if (addr->sa_family == AF_INET6)
+ len = sizeof (struct sockaddr_in6);
+ else
+ return (0);
+
+ return (bcmp(&cp->ri_addr, addr, len) == 0);
+}
+
+static void *
+clntip_mkkey(rfs4_entry_t entry)
+{
+ rfs4_clntip_t *cp = (rfs4_clntip_t *)entry;
+
+ return (&cp->ri_addr);
+}
+
+static bool_t
+rfs4_clntip_expiry(rfs4_entry_t u_entry)
+{
+ rfs4_clntip_t *cp = (rfs4_clntip_t *)u_entry;
+
+ if (rfs4_dbe_is_invalid(cp->ri_dbe))
+ return (TRUE);
+ return (FALSE);
+}
+
+/* ARGSUSED */
+static void
+rfs4_clntip_destroy(rfs4_entry_t u_entry)
+{
+}
+
+static bool_t
+rfs4_clntip_create(rfs4_entry_t u_entry, void *arg)
+{
+ rfs4_clntip_t *cp = (rfs4_clntip_t *)u_entry;
+ struct sockaddr *ca = (struct sockaddr *)arg;
+
+ /* Copy client's IP address */
+ if (ca->sa_family == AF_INET)
+ bcopy(ca, &cp->ri_addr, sizeof (struct sockaddr_in));
+ else if (ca->sa_family == AF_INET6)
+ bcopy(ca, &cp->ri_addr, sizeof (struct sockaddr_in6));
+ else
+ return (FALSE);
+ cp->ri_no_referrals = 1;
+
+ return (TRUE);
+}
+
+rfs4_clntip_t *
+rfs4_find_clntip(struct sockaddr *addr, bool_t *create)
+{
+ rfs4_clntip_t *cp;
+
+ rw_enter(&rfs4_findclient_lock, RW_READER);
+
+ cp = (rfs4_clntip_t *)rfs4_dbsearch(rfs4_clntip_idx, addr,
+ create, addr, RFS4_DBS_VALID);
+
+ rw_exit(&rfs4_findclient_lock);
+
+ return (cp);
+}
+
+void
+rfs4_invalidate_clntip(struct sockaddr *addr)
+{
+ rfs4_clntip_t *cp;
+ bool_t create = FALSE;
+
+ rw_enter(&rfs4_findclient_lock, RW_READER);
+
+ cp = (rfs4_clntip_t *)rfs4_dbsearch(rfs4_clntip_idx, addr,
+ &create, NULL, RFS4_DBS_VALID);
+ if (cp == NULL) {
+ rw_exit(&rfs4_findclient_lock);
+ return;
+ }
+ rfs4_dbe_invalidate(cp->ri_dbe);
+ rfs4_dbe_rele(cp->ri_dbe);
+
+ rw_exit(&rfs4_findclient_lock);
+}
+
bool_t
rfs4_lease_expired(rfs4_client_t *cp)
{
diff --git a/usr/src/uts/common/fs/nfs/nfs4_stub_vnops.c b/usr/src/uts/common/fs/nfs/nfs4_stub_vnops.c
index 37bc502b0b..40d9236765 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_stub_vnops.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_stub_vnops.c
@@ -65,6 +65,7 @@
#include <sys/list.h>
#include <sys/stat.h>
#include <sys/mntent.h>
+#include <sys/priv.h>
#include <rpc/types.h>
#include <rpc/auth.h>
@@ -78,6 +79,8 @@
#include <nfs/nfs4_kprot.h>
#include <nfs/rnode4.h>
#include <nfs/nfs4_clnt.h>
+#include <nfs/nfsid_map.h>
+#include <nfs/nfs4_idmap_impl.h>
#include <vm/hat.h>
#include <vm/as.h>
@@ -97,6 +100,9 @@
#include <sys/priv_names.h>
+extern zone_key_t nfs4clnt_zone_key;
+extern zone_key_t nfsidmap_zone_key;
+
/*
* The automatic unmounter thread stuff!
*/
@@ -202,13 +208,16 @@ extern int nfs4_realvp(vnode_t *, vnode_t **, caller_context_t *);
static int nfs4_trigger_mount(vnode_t *, cred_t *, vnode_t **);
static int nfs4_trigger_domount(vnode_t *, domount_args_t *, vfs_t **,
cred_t *, vnode_t **);
-static domount_args_t *nfs4_trigger_domount_args_create(vnode_t *);
+static domount_args_t *nfs4_trigger_domount_args_create(vnode_t *, cred_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 ephemeral_servinfo_t *nfs4_trigger_esi_create(vnode_t *, servinfo4_t *,
+ cred_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 ephemeral_servinfo_t *nfs4_trigger_esi_create_referral(vnode_t *,
+ cred_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 *);
@@ -216,10 +225,11 @@ 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);
+static enum clnt_stat nfs4_ping_server_common(struct knetconfig *,
+ struct netbuf *, int);
extern int umount2_engine(vfs_t *, int, cred_t *, int);
-
vnodeops_t *nfs4_trigger_vnodeops;
/*
@@ -372,12 +382,46 @@ nfs4_trigger_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
return (VOP_OPEN(vpp, flag, cr, ct));
}
+void
+nfs4_fake_attrs(vnode_t *vp, struct vattr *vap)
+{
+ uint_t mask;
+ timespec_t now;
+
+ /*
+ * Set some attributes here for referrals.
+ */
+ mask = vap->va_mask;
+ bzero(vap, sizeof (struct vattr));
+ vap->va_mask = mask;
+ vap->va_uid = 0;
+ vap->va_gid = 0;
+ vap->va_nlink = 1;
+ vap->va_size = 1;
+ gethrestime(&now);
+ vap->va_atime = now;
+ vap->va_mtime = now;
+ vap->va_ctime = now;
+ vap->va_type = VDIR;
+ vap->va_mode = 0555;
+ vap->va_fsid = vp->v_vfsp->vfs_dev;
+ vap->va_rdev = 0;
+ vap->va_blksize = MAXBSIZE;
+ vap->va_nblocks = 1;
+ vap->va_seq = 0;
+}
+
/*
* 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.
+ *
+ * If we're not triggering a mount, we can still inquire about the
+ * actual attributes from the server in the mirror mount case,
+ * and will return manufactured attributes for a referral (see
+ * the 'create' branch of find_referral_stubvp()).
*/
static int
nfs4_trigger_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
@@ -394,8 +438,15 @@ nfs4_trigger_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
error = VOP_GETATTR(newvp, vap, flags, cr, ct);
VN_RELE(newvp);
- } else {
+
+ } else if (RP_ISSTUB_MIRRORMOUNT(VTOR4(vp))) {
+
error = nfs4_getattr(vp, vap, flags, cr, ct);
+
+ } else if (RP_ISSTUB_REFERRAL(VTOR4(vp))) {
+
+ nfs4_fake_attrs(vp, vap);
+ error = 0;
}
return (error);
@@ -446,17 +497,19 @@ nfs4_trigger_lookup(vnode_t *dvp, char *nm, vnode_t **vpp,
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,
- ct, deflags, rpnp));
+ if (RP_ISSTUB_MIRRORMOUNT(drp)) {
+ return (nfs4_lookup(dvp, nm, vpp, pnp, flags, rdir, cr,
+ ct, deflags, rpnp));
+ } else if (RP_ISSTUB_REFERRAL(drp)) {
+ /* Return the parent vnode */
+ return (vtodv(dvp, vpp, cr, TRUE));
+ }
error = nfs4_trigger_mount(dvp, cr, &newdvp);
if (error)
@@ -672,7 +725,7 @@ nfs4_trigger_mounted_already(vnode_t *vp, vnode_t **newvpp,
}
/*
- * Mount upon a trigger vnode; for mirror-mounts, etc.
+ * Mount upon a trigger vnode; for mirror-mounts, referrals, etc.
*
* The mount may have already occurred, via another thread. If not,
* assemble the location information - which may require fetching - and
@@ -706,9 +759,6 @@ nfs4_trigger_mount(vnode_t *vp, cred_t *cr, vnode_t **newvpp)
ASSERT(RP_ISSTUB(rp));
- /* for now, we only support mirror-mounts */
- ASSERT(RP_ISSTUB_MIRRORMOUNT(rp));
-
*newvpp = NULL;
/*
@@ -782,7 +832,7 @@ nfs4_trigger_mount(vnode_t *vp, cred_t *cr, vnode_t **newvpp)
must_unlock = TRUE;
- dma = nfs4_trigger_domount_args_create(vp);
+ dma = nfs4_trigger_domount_args_create(vp, cr);
if (dma == NULL) {
error = EINVAL;
goto done;
@@ -801,10 +851,15 @@ nfs4_trigger_mount(vnode_t *vp, cred_t *cr, vnode_t **newvpp)
}
crset_zone_privall(mcred);
+ if (is_system_labeled())
+ (void) setpflags(NET_MAC_AWARE, 1, mcred);
error = nfs4_trigger_domount(vp, dma, &vfsp, mcred, newvpp);
nfs4_trigger_domount_args_destroy(dma, vp);
+ DTRACE_PROBE2(nfs4clnt__func__referral__mount,
+ vnode_t *, vp, int, error);
+
crfree(mcred);
done:
@@ -812,9 +867,20 @@ done:
if (must_unlock) {
mutex_enter(&net->net_cnt_lock);
net->net_status &= ~NFS4_EPHEMERAL_TREE_MOUNTING;
+
+ /*
+ * REFCNT: If we are the root of the tree, then we need
+ * to keep a reference because we malloced the tree and
+ * this is where we tied it to our mntinfo.
+ *
+ * If we are not the root of the tree, then our tie to
+ * the mntinfo occured elsewhere and we need to
+ * decrement the reference to the tree.
+ */
if (is_building)
net->net_status &= ~NFS4_EPHEMERAL_TREE_BUILDING;
- nfs4_ephemeral_tree_decr(net);
+ else
+ nfs4_ephemeral_tree_decr(net);
mutex_exit(&net->net_cnt_lock);
mutex_exit(&net->net_tree_lock);
@@ -830,7 +896,7 @@ done:
* Collect together both the generic & mount-type specific args.
*/
static domount_args_t *
-nfs4_trigger_domount_args_create(vnode_t *vp)
+nfs4_trigger_domount_args_create(vnode_t *vp, cred_t *cr)
{
int nointr;
char *hostlist;
@@ -848,7 +914,7 @@ nfs4_trigger_domount_args_create(vnode_t *vp)
/* 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);
+ esi_first = nfs4_trigger_esi_create(vp, svp, cr);
if (esi_first == NULL) {
kmem_free(hostlist, MAXPATHLEN);
return (NULL);
@@ -924,7 +990,7 @@ nfs4_trigger_domount_args_create(vnode_t *vp)
if (status != RPC_SUCCESS)
continue;
- esi = nfs4_trigger_esi_create(vp, svp);
+ esi = nfs4_trigger_esi_create(vp, svp, cr);
if (esi == NULL)
continue;
@@ -1006,7 +1072,7 @@ nfs4_trigger_domount_args_destroy(domount_args_t *dma, vnode_t *vp)
* 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)
+nfs4_trigger_esi_create(vnode_t *vp, servinfo4_t *svp, cred_t *cr)
{
ephemeral_servinfo_t *esi;
rnode4_t *rp = VTOR4(vp);
@@ -1016,12 +1082,10 @@ nfs4_trigger_esi_create(vnode_t *vp, servinfo4_t *svp)
/* Call the ephemeral type-specific routine */
if (RP_ISSTUB_MIRRORMOUNT(rp))
esi = nfs4_trigger_esi_create_mirrormount(vp, svp);
+ else if (RP_ISSTUB_REFERRAL(rp))
+ esi = nfs4_trigger_esi_create_referral(vp, cr);
else
esi = NULL;
-
- /* for now, we only support mirror-mounts */
- ASSERT(esi != NULL);
-
return (esi);
}
@@ -1032,9 +1096,6 @@ nfs4_trigger_esi_destroy(ephemeral_servinfo_t *esi, vnode_t *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 */
/*
@@ -1051,6 +1112,10 @@ nfs4_trigger_esi_destroy(ephemeral_servinfo_t *esi, vnode_t *vp)
* in which case it should be moved to nfs4_trigger_esi_create(), or a
* common function called.
*/
+
+/*
+ * Mirror mounts case - should have all data available
+ */
static ephemeral_servinfo_t *
nfs4_trigger_esi_create_mirrormount(vnode_t *vp, servinfo4_t *svp)
{
@@ -1149,9 +1214,12 @@ nfs4_trigger_esi_create_mirrormount(vnode_t *vp, servinfo4_t *svp)
stubpath += 1;
/* for nfs_args->fh */
- esi->esi_path_len = strlen(svp->sv_path) + strlen(stubpath) + 1;
+ esi->esi_path_len = strlen(stubpath) + 1;
+ if (strcmp(svp->sv_path, "/") != 0)
+ esi->esi_path_len += strlen(svp->sv_path);
esi->esi_path = kmem_zalloc(esi->esi_path_len, KM_SLEEP);
- (void) strcat(esi->esi_path, svp->sv_path);
+ if (strcmp(svp->sv_path, "/") != 0)
+ (void) strcat(esi->esi_path, svp->sv_path);
(void) strcat(esi->esi_path, stubpath);
stubpath -= 1;
@@ -1164,6 +1232,592 @@ nfs4_trigger_esi_create_mirrormount(vnode_t *vp, servinfo4_t *svp)
}
/*
+ * Makes an upcall to NFSMAPID daemon to resolve hostname of NFS server to
+ * get network information required to do the mount call.
+ */
+int
+nfs4_callmapid(utf8string *server, struct nfs_fsl_info *resp)
+{
+ door_arg_t door_args;
+ door_handle_t dh;
+ XDR xdr;
+ refd_door_args_t *xdr_argsp;
+ refd_door_res_t *orig_resp;
+ k_sigset_t smask;
+ int xdr_len = 0;
+ int res_len = 16; /* length of an ip adress */
+ int orig_reslen = res_len;
+ int error = 0;
+ struct nfsidmap_globals *nig;
+
+ if (zone_status_get(curproc->p_zone) >= ZONE_IS_SHUTTING_DOWN)
+ return (ECONNREFUSED);
+
+ nig = zone_getspecific(nfsidmap_zone_key, nfs_zone());
+ ASSERT(nig != NULL);
+
+ mutex_enter(&nig->nfsidmap_daemon_lock);
+ dh = nig->nfsidmap_daemon_dh;
+ if (dh == NULL) {
+ mutex_exit(&nig->nfsidmap_daemon_lock);
+ cmn_err(CE_NOTE,
+ "nfs4_callmapid: nfsmapid daemon not " \
+ "running unable to resolve host name\n");
+ return (EINVAL);
+ }
+ door_ki_hold(dh);
+ mutex_exit(&nig->nfsidmap_daemon_lock);
+
+ xdr_len = xdr_sizeof(&(xdr_utf8string), server);
+
+ xdr_argsp = kmem_zalloc(xdr_len + sizeof (*xdr_argsp), KM_SLEEP);
+ xdr_argsp->xdr_len = xdr_len;
+ xdr_argsp->cmd = NFSMAPID_SRV_NETINFO;
+
+ xdrmem_create(&xdr, (char *)&xdr_argsp->xdr_arg,
+ xdr_len, XDR_ENCODE);
+
+ if (!xdr_utf8string(&xdr, server)) {
+ kmem_free(xdr_argsp, xdr_len + sizeof (*xdr_argsp));
+ door_ki_rele(dh);
+ return (1);
+ }
+
+ if (orig_reslen)
+ orig_resp = kmem_alloc(orig_reslen, KM_SLEEP);
+
+ door_args.data_ptr = (char *)xdr_argsp;
+ door_args.data_size = sizeof (*xdr_argsp) + xdr_argsp->xdr_len;
+ door_args.desc_ptr = NULL;
+ door_args.desc_num = 0;
+ door_args.rbuf = orig_resp ? (char *)orig_resp : NULL;
+ door_args.rsize = res_len;
+
+ sigintr(&smask, 1);
+ error = door_ki_upcall(dh, &door_args);
+ sigunintr(&smask);
+
+ door_ki_rele(dh);
+
+ kmem_free(xdr_argsp, xdr_len + sizeof (*xdr_argsp));
+ if (error) {
+ kmem_free(orig_resp, orig_reslen);
+ /*
+ * There is no door to connect to. The referral daemon
+ * must not be running yet.
+ */
+ cmn_err(CE_WARN,
+ "nfsmapid not running cannot resolve host name");
+ goto out;
+ }
+
+ /*
+ * If the results buffer passed back are not the same as
+ * what was sent free the old buffer and use the new one.
+ */
+ if (orig_resp && orig_reslen) {
+ refd_door_res_t *door_resp;
+
+ door_resp = (refd_door_res_t *)door_args.rbuf;
+ if ((void *)door_args.rbuf != orig_resp)
+ kmem_free(orig_resp, orig_reslen);
+ if (door_resp->res_status == 0) {
+ xdrmem_create(&xdr, (char *)&door_resp->xdr_res,
+ door_resp->xdr_len, XDR_DECODE);
+ bzero(resp, sizeof (struct nfs_fsl_info));
+ if (!xdr_nfs_fsl_info(&xdr, resp)) {
+ DTRACE_PROBE2(
+ nfs4clnt__debug__referral__upcall__xdrfail,
+ struct nfs_fsl_info *, resp,
+ char *, "nfs4_callmapid");
+ error = EINVAL;
+ }
+ } else {
+ DTRACE_PROBE2(
+ nfs4clnt__debug__referral__upcall__badstatus,
+ int, door_resp->res_status,
+ char *, "nfs4_callmapid");
+ error = door_resp->res_status;
+ }
+ kmem_free(door_args.rbuf, door_args.rsize);
+ }
+out:
+ DTRACE_PROBE2(nfs4clnt__func__referral__upcall,
+ char *, server, int, error);
+ return (error);
+}
+
+/*
+ * Fetches the fs_locations attribute. Typically called
+ * from a Replication/Migration/Referrals/Mirror-mount context
+ *
+ * Fills in the attributes in garp. The caller is assumed
+ * to have allocated memory for garp.
+ *
+ * lock: if set do not lock s_recovlock and mi_recovlock mutex,
+ * it's already done by caller. Otherwise lock these mutexes
+ * before doing the rfs4call().
+ *
+ * Returns
+ * 1 for success
+ * 0 for failure
+ */
+int
+nfs4_fetch_locations(mntinfo4_t *mi, nfs4_sharedfh_t *sfh, char *nm,
+ cred_t *cr, nfs4_ga_res_t *garp, COMPOUND4res_clnt *callres, bool_t lock)
+{
+ COMPOUND4args_clnt args;
+ COMPOUND4res_clnt res;
+ nfs_argop4 *argop;
+ int argoplist_size = 3 * sizeof (nfs_argop4);
+ nfs4_server_t *sp = NULL;
+ int doqueue = 1;
+ nfs4_error_t e = { 0, NFS4_OK, RPC_SUCCESS };
+ int retval = 1;
+ struct nfs4_clnt *nfscl;
+
+ if (lock == TRUE)
+ (void) nfs_rw_enter_sig(&mi->mi_recovlock, RW_READER, 0);
+ else
+ ASSERT(nfs_rw_lock_held(&mi->mi_recovlock, RW_READER) ||
+ nfs_rw_lock_held(&mi->mi_recovlock, RW_WRITER));
+
+ sp = find_nfs4_server(mi);
+ if (lock == TRUE)
+ nfs_rw_exit(&mi->mi_recovlock);
+
+ if (sp != NULL)
+ mutex_exit(&sp->s_lock);
+
+ if (lock == TRUE) {
+ if (sp != NULL)
+ (void) nfs_rw_enter_sig(&sp->s_recovlock,
+ RW_WRITER, 0);
+ (void) nfs_rw_enter_sig(&mi->mi_recovlock, RW_WRITER, 0);
+ } else {
+ if (sp != NULL) {
+ ASSERT(nfs_rw_lock_held(&sp->s_recovlock, RW_READER) ||
+ nfs_rw_lock_held(&sp->s_recovlock, RW_WRITER));
+ }
+ }
+
+ /*
+ * Do we want to do the setup for recovery here?
+ *
+ * We know that the server responded to a null ping a very
+ * short time ago, and we know that we intend to do a
+ * single stateless operation - we want to fetch attributes,
+ * so we know we can't encounter errors about state. If
+ * something goes wrong with the GETATTR, like not being
+ * able to get a response from the server or getting any
+ * kind of FH error, we should fail the mount.
+ *
+ * We may want to re-visited this at a later time.
+ */
+ argop = kmem_alloc(argoplist_size, KM_SLEEP);
+
+ args.ctag = TAG_GETATTR_FSLOCATION;
+ /* PUTFH LOOKUP GETATTR */
+ args.array_len = 3;
+ args.array = argop;
+
+ /* 0. putfh file */
+ argop[0].argop = OP_CPUTFH;
+ argop[0].nfs_argop4_u.opcputfh.sfh = sfh;
+
+ /* 1. lookup name, can't be dotdot */
+ argop[1].argop = OP_CLOOKUP;
+ argop[1].nfs_argop4_u.opclookup.cname = nm;
+
+ /* 2. file attrs */
+ argop[2].argop = OP_GETATTR;
+ argop[2].nfs_argop4_u.opgetattr.attr_request =
+ FATTR4_FSID_MASK | FATTR4_FS_LOCATIONS_MASK |
+ FATTR4_MOUNTED_ON_FILEID_MASK;
+ argop[2].nfs_argop4_u.opgetattr.mi = mi;
+
+ rfs4call(mi, &args, &res, cr, &doqueue, 0, &e);
+
+ if (lock == TRUE) {
+ nfs_rw_exit(&mi->mi_recovlock);
+ if (sp != NULL)
+ nfs_rw_exit(&sp->s_recovlock);
+ }
+
+ nfscl = zone_getspecific(nfs4clnt_zone_key, nfs_zone());
+ nfscl->nfscl_stat.referrals.value.ui64++;
+ DTRACE_PROBE3(nfs4clnt__func__referral__fsloc,
+ nfs4_sharedfh_t *, sfh, char *, nm, nfs4_error_t *, &e);
+
+ if (e.error != 0) {
+ if (sp != NULL)
+ nfs4_server_rele(sp);
+ kmem_free(argop, argoplist_size);
+ return (0);
+ }
+
+ /*
+ * Check for all possible error conditions.
+ * For valid replies without an ops array or for illegal
+ * replies, return a failure.
+ */
+ if (res.status != NFS4_OK || res.array_len < 3 ||
+ res.array[2].nfs_resop4_u.opgetattr.status != NFS4_OK) {
+ retval = 0;
+ goto exit;
+ }
+
+ /*
+ * There isn't much value in putting the attributes
+ * in the attr cache since fs_locations4 aren't
+ * encountered very frequently, so just make them
+ * available to the caller.
+ */
+ *garp = res.array[2].nfs_resop4_u.opgetattr.ga_res;
+
+ DTRACE_PROBE2(nfs4clnt__debug__referral__fsloc,
+ nfs4_ga_res_t *, garp, char *, "nfs4_fetch_locations");
+
+ /* No fs_locations? -- return a failure */
+ if (garp->n4g_ext_res == NULL ||
+ garp->n4g_ext_res->n4g_fslocations.locations_val == NULL) {
+ retval = 0;
+ goto exit;
+ }
+
+ if (!garp->n4g_fsid_valid)
+ retval = 0;
+
+exit:
+ if (retval == 0) {
+ /* the call was ok but failed validating the call results */
+ (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
+ } else {
+ ASSERT(callres != NULL);
+ *callres = res;
+ }
+
+ if (sp != NULL)
+ nfs4_server_rele(sp);
+ kmem_free(argop, argoplist_size);
+ return (retval);
+}
+
+/* tunable to disable referral mounts */
+int nfs4_no_referrals = 0;
+
+/*
+ * Returns NULL if the vnode cannot be created or found.
+ */
+vnode_t *
+find_referral_stubvp(vnode_t *dvp, char *nm, cred_t *cr)
+{
+ nfs_fh4 *stub_fh, *dfh;
+ nfs4_sharedfh_t *sfhp;
+ char *newfhval;
+ vnode_t *vp = NULL;
+ fattr4_mounted_on_fileid mnt_on_fileid;
+ nfs4_ga_res_t garp;
+ mntinfo4_t *mi;
+ COMPOUND4res_clnt callres;
+ hrtime_t t;
+
+ if (nfs4_no_referrals)
+ return (NULL);
+
+ /*
+ * Get the mounted_on_fileid, unique on that server::fsid
+ */
+ mi = VTOMI4(dvp);
+ if (nfs4_fetch_locations(mi, VTOR4(dvp)->r_fh, nm, cr,
+ &garp, &callres, FALSE) == 0)
+ return (NULL);
+ mnt_on_fileid = garp.n4g_mon_fid;
+ (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&callres);
+
+ /*
+ * Build a fake filehandle from the dir FH and the mounted_on_fileid
+ */
+ dfh = &VTOR4(dvp)->r_fh->sfh_fh;
+ stub_fh = kmem_alloc(sizeof (nfs_fh4), KM_SLEEP);
+ stub_fh->nfs_fh4_val = kmem_alloc(dfh->nfs_fh4_len +
+ sizeof (fattr4_mounted_on_fileid), KM_SLEEP);
+ newfhval = stub_fh->nfs_fh4_val;
+
+ /* copy directory's file handle */
+ bcopy(dfh->nfs_fh4_val, newfhval, dfh->nfs_fh4_len);
+ stub_fh->nfs_fh4_len = dfh->nfs_fh4_len;
+ newfhval = newfhval + dfh->nfs_fh4_len;
+
+ /* Add mounted_on_fileid. Use bcopy to avoid alignment problem */
+ bcopy((char *)&mnt_on_fileid, newfhval,
+ sizeof (fattr4_mounted_on_fileid));
+ stub_fh->nfs_fh4_len += sizeof (fattr4_mounted_on_fileid);
+
+ sfhp = sfh4_put(stub_fh, VTOMI4(dvp), NULL);
+ kmem_free(stub_fh->nfs_fh4_val, dfh->nfs_fh4_len +
+ sizeof (fattr4_mounted_on_fileid));
+ kmem_free(stub_fh, sizeof (nfs_fh4));
+ if (sfhp == NULL)
+ return (NULL);
+
+ t = gethrtime();
+ garp.n4g_va.va_type = VDIR;
+ vp = makenfs4node(sfhp, NULL, dvp->v_vfsp, t,
+ cr, dvp, fn_get(VTOSV(dvp)->sv_name, nm, sfhp));
+
+ if (vp != NULL)
+ vp->v_type = VDIR;
+
+ sfh4_rele(&sfhp);
+ return (vp);
+}
+
+int
+nfs4_setup_referral(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr)
+{
+ vnode_t *nvp;
+ rnode4_t *rp;
+
+ if ((nvp = find_referral_stubvp(dvp, nm, cr)) == NULL)
+ return (EINVAL);
+
+ rp = VTOR4(nvp);
+ mutex_enter(&rp->r_statelock);
+ r4_stub_referral(rp);
+ mutex_exit(&rp->r_statelock);
+ dnlc_enter(dvp, nm, nvp);
+
+ if (*vpp != NULL)
+ VN_RELE(*vpp); /* no longer need this vnode */
+
+ *vpp = nvp;
+
+ return (0);
+}
+
+/*
+ * Fetch the location information and resolve the new server.
+ * Caller needs to free up the XDR data which is returned.
+ * Input: mount info, shared filehandle, nodename
+ * Return: Index to the result or Error(-1)
+ * Output: FsLocations Info, Resolved Server Info.
+ */
+int
+nfs4_process_referral(mntinfo4_t *mi, nfs4_sharedfh_t *sfh,
+ char *nm, cred_t *cr, nfs4_ga_res_t *grp, COMPOUND4res_clnt *res,
+ struct nfs_fsl_info *fsloc)
+{
+ fs_location4 *fsp;
+ struct nfs_fsl_info nfsfsloc;
+ int ret, i, error;
+ nfs4_ga_res_t garp;
+ COMPOUND4res_clnt callres;
+ struct knetconfig *knc;
+
+ ret = nfs4_fetch_locations(mi, sfh, nm, cr, &garp, &callres, TRUE);
+ if (ret == 0)
+ return (-1);
+
+ /*
+ * As a lame attempt to figuring out if we're
+ * handling a migration event or a referral,
+ * look for rnodes with this fsid in the rnode
+ * cache.
+ *
+ * If we can find one or more such rnodes, it
+ * means we're handling a migration event and
+ * we want to bail out in that case.
+ */
+ if (r4find_by_fsid(mi, &garp.n4g_fsid)) {
+ DTRACE_PROBE3(nfs4clnt__debug__referral__migration,
+ mntinfo4_t *, mi, nfs4_ga_res_t *, &garp,
+ char *, "nfs4_process_referral");
+ (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&callres);
+ return (-1);
+ }
+
+ /*
+ * Find the first responsive server to mount. When we find
+ * one, fsp will point to it.
+ */
+ for (i = 0; i < garp.n4g_ext_res->n4g_fslocations.locations_len; i++) {
+
+ fsp = &garp.n4g_ext_res->n4g_fslocations.locations_val[i];
+ if (fsp->server_len == 0 || fsp->server_val == NULL)
+ continue;
+
+ error = nfs4_callmapid(fsp->server_val, &nfsfsloc);
+ if (error != 0)
+ continue;
+
+ error = nfs4_ping_server_common(nfsfsloc.knconf,
+ nfsfsloc.addr, !(mi->mi_flags & MI4_INT));
+ if (error == RPC_SUCCESS)
+ break;
+
+ DTRACE_PROBE2(nfs4clnt__debug__referral__srvaddr,
+ sockaddr_in *, (struct sockaddr_in *)nfsfsloc.addr->buf,
+ char *, "nfs4_process_referral");
+
+ (void) xdr_free(xdr_nfs_fsl_info, (char *)&nfsfsloc);
+ }
+ knc = nfsfsloc.knconf;
+ if ((i >= garp.n4g_ext_res->n4g_fslocations.locations_len) ||
+ (knc->knc_protofmly == NULL) || (knc->knc_proto == NULL)) {
+ DTRACE_PROBE2(nfs4clnt__debug__referral__nofsloc,
+ nfs4_ga_res_t *, &garp, char *, "nfs4_process_referral");
+ (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&callres);
+ return (-1);
+ }
+
+ /* Send the results back */
+ *fsloc = nfsfsloc;
+ *grp = garp;
+ *res = callres;
+ return (i);
+}
+
+/*
+ * Referrals case - need to fetch referral data and then upcall to
+ * user-level to get complete mount data.
+ */
+static ephemeral_servinfo_t *
+nfs4_trigger_esi_create_referral(vnode_t *vp, cred_t *cr)
+{
+ struct knetconfig *sikncp, *svkncp;
+ struct netbuf *bufp;
+ ephemeral_servinfo_t *esi;
+ vnode_t *dvp;
+ rnode4_t *drp;
+ fs_location4 *fsp;
+ struct nfs_fsl_info nfsfsloc;
+ nfs4_ga_res_t garp;
+ char *p;
+ char fn[MAXNAMELEN];
+ int i, index = -1;
+ mntinfo4_t *mi;
+ COMPOUND4res_clnt callres;
+
+ /*
+ * If we're passed in a stub vnode that
+ * isn't a "referral" stub, bail out
+ * and return a failure
+ */
+ if (!RP_ISSTUB_REFERRAL(VTOR4(vp)))
+ return (NULL);
+
+ if (vtodv(vp, &dvp, CRED(), TRUE) != 0)
+ return (NULL);
+
+ drp = VTOR4(dvp);
+ if (nfs_rw_enter_sig(&drp->r_rwlock, RW_READER, INTR4(dvp))) {
+ VN_RELE(dvp);
+ return (NULL);
+ }
+
+ if (vtoname(vp, fn, MAXNAMELEN) != 0) {
+ nfs_rw_exit(&drp->r_rwlock);
+ VN_RELE(dvp);
+ return (NULL);
+ }
+
+ mi = VTOMI4(dvp);
+ index = nfs4_process_referral(mi, drp->r_fh, fn, cr,
+ &garp, &callres, &nfsfsloc);
+ nfs_rw_exit(&drp->r_rwlock);
+ VN_RELE(dvp);
+ if (index < 0)
+ return (NULL);
+
+ fsp = &garp.n4g_ext_res->n4g_fslocations.locations_val[index];
+ 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_REFERRAL;
+
+ esi->esi_hostname =
+ kmem_zalloc(fsp->server_val->utf8string_len + 1, KM_SLEEP);
+ bcopy(fsp->server_val->utf8string_val, esi->esi_hostname,
+ fsp->server_val->utf8string_len);
+ esi->esi_hostname[fsp->server_val->utf8string_len] = '\0';
+
+ bufp = kmem_alloc(sizeof (struct netbuf), KM_SLEEP);
+ bufp->len = nfsfsloc.addr->len;
+ bufp->maxlen = nfsfsloc.addr->maxlen;
+ bufp->buf = kmem_zalloc(bufp->len, KM_SLEEP);
+ bcopy(nfsfsloc.addr->buf, bufp->buf, bufp->len);
+ esi->esi_addr = bufp;
+
+ esi->esi_knconf = kmem_zalloc(sizeof (*esi->esi_knconf), KM_SLEEP);
+ sikncp = esi->esi_knconf;
+
+ DTRACE_PROBE2(nfs4clnt__debug__referral__nfsfsloc,
+ struct nfs_fsl_info *, &nfsfsloc,
+ char *, "nfs4_trigger_esi_create_referral");
+
+ svkncp = nfsfsloc.knconf;
+ sikncp->knc_semantics = svkncp->knc_semantics;
+ sikncp->knc_protofmly = (caddr_t)kmem_zalloc(KNC_STRSIZE, KM_SLEEP);
+ (void) strlcat((char *)sikncp->knc_protofmly,
+ (char *)svkncp->knc_protofmly, KNC_STRSIZE);
+ sikncp->knc_proto = (caddr_t)kmem_zalloc(KNC_STRSIZE, KM_SLEEP);
+ (void) strlcat((char *)sikncp->knc_proto, (char *)svkncp->knc_proto,
+ KNC_STRSIZE);
+ sikncp->knc_rdev = svkncp->knc_rdev;
+
+ DTRACE_PROBE2(nfs4clnt__debug__referral__knetconf,
+ struct knetconfig *, sikncp,
+ char *, "nfs4_trigger_esi_create_referral");
+
+ esi->esi_netname = kmem_zalloc(nfsfsloc.netnm_len, KM_SLEEP);
+ bcopy(nfsfsloc.netname, esi->esi_netname, nfsfsloc.netnm_len);
+ esi->esi_syncaddr = NULL;
+
+ esi->esi_path = p = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
+ esi->esi_path_len = MAXPATHLEN;
+ *p++ = '/';
+ for (i = 0; i < fsp->rootpath.pathname4_len; i++) {
+ component4 *comp;
+
+ comp = &fsp->rootpath.pathname4_val[i];
+ /* If no space, null the string and bail */
+ if ((p - esi->esi_path) + comp->utf8string_len + 1 > MAXPATHLEN)
+ goto err;
+ bcopy(comp->utf8string_val, p, comp->utf8string_len);
+ p += comp->utf8string_len;
+ *p++ = '/';
+ }
+ if (fsp->rootpath.pathname4_len != 0)
+ *(p - 1) = '\0';
+ else
+ *p = '\0';
+ p = esi->esi_path;
+ esi->esi_path = strdup(p);
+ esi->esi_path_len = strlen(p) + 1;
+ kmem_free(p, MAXPATHLEN);
+
+ /* Allocated in nfs4_process_referral() */
+ (void) xdr_free(xdr_nfs_fsl_info, (char *)&nfsfsloc);
+ (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&callres);
+
+ return (esi);
+err:
+ kmem_free(esi->esi_path, esi->esi_path_len);
+ kmem_free(esi->esi_hostname, fsp->server_val->utf8string_len + 1);
+ kmem_free(esi->esi_addr->buf, esi->esi_addr->len);
+ kmem_free(esi->esi_addr, sizeof (struct netbuf));
+ kmem_free(esi->esi_knconf->knc_protofmly, KNC_STRSIZE);
+ kmem_free(esi->esi_knconf->knc_proto, KNC_STRSIZE);
+ kmem_free(esi->esi_knconf, sizeof (*esi->esi_knconf));
+ kmem_free(esi->esi_netname, nfsfsloc.netnm_len);
+ kmem_free(esi, sizeof (ephemeral_servinfo_t));
+ (void) xdr_free(xdr_nfs_fsl_info, (char *)&nfsfsloc);
+ (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&callres);
+ return (NULL);
+}
+
+/*
* Assemble the args, and call the generic VFS mount function to
* finally perform the ephemeral mount.
*/
@@ -1357,6 +2011,9 @@ nfs4_trigger_nargs_create(mntinfo4_t *mi, servinfo4_t *svp,
nargs->acdirmin = HR2SEC(mi->mi_acdirmin);
nargs->acdirmax = HR2SEC(mi->mi_acdirmax);
+ /* add any specific flags for this type of ephemeral mount */
+ nargs->flags |= esi->esi_mount_flags;
+
if (mi->mi_flags & MI4_NOCTO)
nargs->flags |= NFSMNT_NOCTO;
if (mi->mi_flags & MI4_GRPID)
@@ -1367,19 +2024,28 @@ nfs4_trigger_nargs_create(mntinfo4_t *mi, servinfo4_t *svp,
nargs->flags |= NFSMNT_NOPRINT;
if (mi->mi_flags & MI4_DIRECTIO)
nargs->flags |= NFSMNT_DIRECTIO;
- if (mi->mi_flags & MI4_PUBLIC)
+ if (mi->mi_flags & MI4_PUBLIC && nargs->flags & NFSMNT_MIRRORMOUNT)
nargs->flags |= NFSMNT_PUBLIC;
- mutex_exit(&mi->mi_lock);
+ /* Do some referral-specific option tweaking */
+ if (nargs->flags & NFSMNT_REFERRAL) {
+ nargs->flags &= ~NFSMNT_DORDMA;
+ nargs->flags |= NFSMNT_TRYRDMA;
+ }
- /* add any specific flags for this type of ephemeral mount */
- nargs->flags |= esi->esi_mount_flags;
+ mutex_exit(&mi->mi_lock);
/*
* Security data & negotiation policy.
*
- * We need to preserve the parent mount's preference for security
- * negotiation, translating SV4_TRYSECDEFAULT -> NFSMNT_SECDEFAULT.
+ * For mirror mounts, we need to preserve the parent mount's
+ * preference for security negotiation, translating SV4_TRYSECDEFAULT
+ * to NFSMNT_SECDEFAULT if present.
+ *
+ * For referrals, we always want security negotiation and will
+ * set NFSMNT_SECDEFAULT and we will not copy current secdata.
+ * The reason is that we can't negotiate down from a parent's
+ * Kerberos flavor to AUTH_SYS.
*
* If SV4_TRYSECDEFAULT is not set, that indicates that a specific
* security flavour was requested, with data in sv_secdata, and that
@@ -1395,8 +2061,16 @@ nfs4_trigger_nargs_create(mntinfo4_t *mi, servinfo4_t *svp,
* 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 */
+ if (nargs->flags & NFSMNT_REFERRAL) {
+ /* enable negotiation for referral mount */
+ nargs->flags |= NFSMNT_SECDEFAULT;
+ secdata = kmem_alloc(sizeof (sec_data_t), KM_SLEEP);
+ secdata->secmod = secdata->rpcflavor = AUTH_SYS;
+ secdata->data = NULL;
+ }
+
+ else if (svp->sv_flags & SV4_TRYSECDEFAULT) {
+ /* enable negotiation for mirror mount */
nargs->flags |= NFSMNT_SECDEFAULT;
/*
@@ -1499,6 +2173,11 @@ nfs4_record_ephemeral_mount(mntinfo4_t *mi, vnode_t *mvp)
return (EBUSY);
}
+ /*
+ * We've just tied the mntinfo to the tree, so
+ * now we bump the refcnt and hold it there until
+ * this mntinfo is removed from the tree.
+ */
nfs4_ephemeral_tree_hold(net);
/*
@@ -1515,7 +2194,6 @@ nfs4_record_ephemeral_mount(mntinfo4_t *mi, vnode_t *mvp)
*/
eph->ne_mount_to = ntg->ntg_mount_to;
- mi->mi_flags |= MI4_EPHEMERAL;
mi->mi_ephemeral = eph;
/*
@@ -1542,6 +2220,7 @@ nfs4_record_ephemeral_mount(mntinfo4_t *mi, vnode_t *mvp)
mi->mi_flags &= ~MI4_EPHEMERAL;
mi->mi_ephemeral = NULL;
kmem_free(eph, sizeof (*eph));
+ nfs4_ephemeral_tree_rele(net);
rc = EBUSY;
} else {
if (prior->ne_child == NULL) {
@@ -1581,8 +2260,6 @@ nfs4_record_ephemeral_mount(mntinfo4_t *mi, vnode_t *mvp)
eph->ne_prior = NULL;
}
- nfs4_ephemeral_tree_rele(net);
-
mutex_exit(&mi->mi_lock);
mutex_exit(&mi_parent->mi_lock);
@@ -1758,15 +2435,13 @@ nfs4_ephemeral_unmount_engine(nfs4_ephemeral_t *eph,
*/
void
nfs4_ephemeral_umount_unlock(bool_t *pmust_unlock,
- bool_t *pmust_rele, nfs4_ephemeral_tree_t **pnet)
+ nfs4_ephemeral_tree_t **pnet)
{
nfs4_ephemeral_tree_t *net = *pnet;
if (*pmust_unlock) {
mutex_enter(&net->net_cnt_lock);
net->net_status &= ~NFS4_EPHEMERAL_TREE_UMOUNTING;
- if (*pmust_rele)
- nfs4_ephemeral_tree_decr(net);
mutex_exit(&net->net_cnt_lock);
mutex_exit(&net->net_tree_lock);
@@ -1783,7 +2458,7 @@ nfs4_ephemeral_umount_unlock(bool_t *pmust_unlock,
*/
void
nfs4_ephemeral_umount_activate(mntinfo4_t *mi, bool_t *pmust_unlock,
- bool_t *pmust_rele, nfs4_ephemeral_tree_t **pnet)
+ nfs4_ephemeral_tree_t **pnet)
{
/*
* Now we need to get rid of the ephemeral data if it exists.
@@ -1798,6 +2473,7 @@ nfs4_ephemeral_umount_activate(mntinfo4_t *mi, bool_t *pmust_unlock,
if (!(mi->mi_flags & MI4_EPHEMERAL_RECURSED))
nfs4_ephemeral_umount_cleanup(mi->mi_ephemeral);
+ nfs4_ephemeral_tree_rele(*pnet);
ASSERT(mi->mi_ephemeral != NULL);
kmem_free(mi->mi_ephemeral, sizeof (*mi->mi_ephemeral));
@@ -1805,15 +2481,19 @@ nfs4_ephemeral_umount_activate(mntinfo4_t *mi, bool_t *pmust_unlock,
}
mutex_exit(&mi->mi_lock);
- nfs4_ephemeral_umount_unlock(pmust_unlock, pmust_rele, pnet);
+ nfs4_ephemeral_umount_unlock(pmust_unlock, pnet);
}
/*
* Unmount an ephemeral node.
+ *
+ * Note that if this code fails, then it must unlock.
+ *
+ * If it succeeds, then the caller must be prepared to do so.
*/
int
nfs4_ephemeral_umount(mntinfo4_t *mi, int flag, cred_t *cr,
- bool_t *pmust_unlock, bool_t *pmust_rele, nfs4_ephemeral_tree_t **pnet)
+ bool_t *pmust_unlock, nfs4_ephemeral_tree_t **pnet)
{
int error = 0;
nfs4_ephemeral_t *eph;
@@ -1826,7 +2506,7 @@ nfs4_ephemeral_umount(mntinfo4_t *mi, int flag, cred_t *cr,
* Make sure to set the default state for cleaning
* up the tree in the caller (and on the way out).
*/
- *pmust_unlock = *pmust_rele = FALSE;
+ *pmust_unlock = FALSE;
/*
* The active vnodes on this file system may be ephemeral
@@ -1865,16 +2545,18 @@ nfs4_ephemeral_umount(mntinfo4_t *mi, int flag, cred_t *cr,
is_recursed = mi->mi_flags & MI4_EPHEMERAL_RECURSED;
is_derooting = (eph == NULL);
+ mutex_enter(&net->net_cnt_lock);
+
/*
* If this is not recursion, then we need to
- * grab a ref count.
+ * check to see if a harvester thread has
+ * already grabbed the lock.
*
- * But wait, we also do not want to do that
- * if a harvester thread has already grabbed
- * the lock.
+ * After we exit this branch, we may not
+ * blindly return, we need to jump to
+ * is_busy!
*/
if (!is_recursed) {
- mutex_enter(&net->net_cnt_lock);
if (net->net_status &
NFS4_EPHEMERAL_TREE_LOCKED) {
/*
@@ -1902,13 +2584,10 @@ nfs4_ephemeral_umount(mntinfo4_t *mi, int flag, cred_t *cr,
}
was_locked = TRUE;
- } else {
- nfs4_ephemeral_tree_incr(net);
- *pmust_rele = TRUE;
}
-
- mutex_exit(&net->net_cnt_lock);
}
+
+ mutex_exit(&net->net_cnt_lock);
mutex_exit(&mi->mi_lock);
/*
@@ -1936,9 +2615,7 @@ nfs4_ephemeral_umount(mntinfo4_t *mi, int flag, cred_t *cr,
if (net->net_status &
(NFS4_EPHEMERAL_TREE_DEROOTING
| NFS4_EPHEMERAL_TREE_INVALID)) {
- nfs4_ephemeral_tree_decr(net);
mutex_exit(&net->net_cnt_lock);
- *pmust_rele = FALSE;
goto is_busy;
}
mutex_exit(&net->net_cnt_lock);
@@ -1974,10 +2651,8 @@ nfs4_ephemeral_umount(mntinfo4_t *mi, int flag, cred_t *cr,
if (net->net_status &
NFS4_EPHEMERAL_TREE_INVALID ||
(!is_derooting && eph == NULL)) {
- nfs4_ephemeral_tree_decr(net);
mutex_exit(&net->net_cnt_lock);
mutex_exit(&net->net_tree_lock);
- *pmust_rele = FALSE;
goto is_busy;
}
mutex_exit(&net->net_cnt_lock);
@@ -2048,8 +2723,14 @@ nfs4_ephemeral_umount(mntinfo4_t *mi, int flag, cred_t *cr,
mutex_enter(&net->net_cnt_lock);
net->net_status &= ~NFS4_EPHEMERAL_TREE_DEROOTING;
net->net_status |= NFS4_EPHEMERAL_TREE_INVALID;
- if (was_locked == FALSE)
- nfs4_ephemeral_tree_decr(net);
+ DTRACE_NFSV4_1(nfs4clnt__dbg__ephemeral__tree__derooting,
+ uint_t, net->net_refcnt);
+
+ /*
+ * We will not finalize this node, so safe to
+ * release it.
+ */
+ nfs4_ephemeral_tree_decr(net);
mutex_exit(&net->net_cnt_lock);
if (was_locked == FALSE)
@@ -2057,8 +2738,8 @@ nfs4_ephemeral_umount(mntinfo4_t *mi, int flag, cred_t *cr,
/*
* We have just blown away any notation of this
- * tree being locked. We can't let the caller
- * try to clean things up.
+ * tree being locked or having a refcnt.
+ * We can't let the caller try to clean things up.
*/
*pmust_unlock = FALSE;
@@ -2077,8 +2758,7 @@ nfs4_ephemeral_umount(mntinfo4_t *mi, int flag, cred_t *cr,
is_busy:
- nfs4_ephemeral_umount_unlock(pmust_unlock, pmust_rele,
- pnet);
+ nfs4_ephemeral_umount_unlock(pmust_unlock, pnet);
return (error);
}
@@ -2314,19 +2994,18 @@ check_done:
/*
* At this point we are done processing this tree.
*
- * If the tree is invalid and we are the only reference
+ * If the tree is invalid and we were the only reference
* to it, then we push it on the local linked list
* to remove it at the end. We avoid that action now
* to keep the tree processing going along at a fair clip.
*
- * Else, even if we are the only reference, we drop
- * our hold on the current tree and allow it to be
- * reused as needed.
+ * Else, even if we were the only reference, we
+ * allow it to be reused as needed.
*/
mutex_enter(&net->net_cnt_lock);
- if (net->net_refcnt == 1 &&
+ nfs4_ephemeral_tree_decr(net);
+ if (net->net_refcnt == 0 &&
net->net_status & NFS4_EPHEMERAL_TREE_INVALID) {
- nfs4_ephemeral_tree_decr(net);
net->net_status &= ~NFS4_EPHEMERAL_TREE_LOCKED;
mutex_exit(&net->net_cnt_lock);
mutex_exit(&net->net_tree_lock);
@@ -2341,7 +3020,6 @@ check_done:
continue;
}
- nfs4_ephemeral_tree_decr(net);
net->net_status &= ~NFS4_EPHEMERAL_TREE_LOCKED;
mutex_exit(&net->net_cnt_lock);
mutex_exit(&net->net_tree_lock);
@@ -2620,9 +3298,9 @@ nfs4_trigger_add_mntopt(char *mntopts, char *optname, vfs_t *vfsp)
}
static enum clnt_stat
-nfs4_trigger_ping_server(servinfo4_t *svp, int nointr)
+nfs4_ping_server_common(struct knetconfig *knc, struct netbuf *addr, int nointr)
{
- int retries, error;
+ int retries;
uint_t max_msgsize;
enum clnt_stat status;
CLIENT *cl;
@@ -2634,9 +3312,8 @@ nfs4_trigger_ping_server(servinfo4_t *svp, int nointr)
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)
+ if (clnt_tli_kcreate(knc, addr, NFS_PROGRAM, NFS_V4,
+ max_msgsize, retries, CRED(), &cl) != 0)
return (RPC_FAILED);
if (nointr)
@@ -2651,3 +3328,9 @@ nfs4_trigger_ping_server(servinfo4_t *svp, int nointr)
return (status);
}
+
+static enum clnt_stat
+nfs4_trigger_ping_server(servinfo4_t *svp, int nointr)
+{
+ return (nfs4_ping_server_common(svp->sv_knconf, &svp->sv_addr, nointr));
+}
diff --git a/usr/src/uts/common/fs/nfs/nfs4_subr.c b/usr/src/uts/common/fs/nfs/nfs4_subr.c
index 27261bf583..b94d41899d 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_subr.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_subr.c
@@ -59,6 +59,8 @@
static const struct clstat4 clstat4_tmpl = {
{ "calls", KSTAT_DATA_UINT64 },
{ "badcalls", KSTAT_DATA_UINT64 },
+ { "referrals", KSTAT_DATA_UINT64 },
+ { "referlinks", KSTAT_DATA_UINT64 },
{ "clgets", KSTAT_DATA_UINT64 },
{ "cltoomany", KSTAT_DATA_UINT64 },
#ifdef DEBUG
@@ -90,7 +92,7 @@ struct clstat4_debug clstat4_debug = {
*/
static list_t nfs4_clnt_list;
static kmutex_t nfs4_clnt_list_lock;
-static zone_key_t nfs4clnt_zone_key;
+zone_key_t nfs4clnt_zone_key;
static struct kmem_cache *chtab4_cache;
@@ -1943,6 +1945,9 @@ again:
* crossed an underlying server fs boundary.
*
* This stub will be for a mirror-mount.
+ * A referral would look like a boundary crossing
+ * as well, but would not be the same type of object,
+ * so we would expect to mark the object dead.
*
* See comment in r4_do_attrcache() for more details.
*/
@@ -2109,7 +2114,8 @@ recov_retry:
bool_t abort;
abort = nfs4_start_recovery(&e, mi,
- rootvp, NULL, NULL, NULL, OP_LOOKUP, NULL);
+ rootvp, NULL, NULL, NULL, OP_LOOKUP, NULL, NULL,
+ NULL);
if (abort) {
nfs4_end_fop(mi, rootvp, NULL, OH_LOOKUP,
&recov_state, FALSE);
@@ -2169,7 +2175,7 @@ recov_retry:
abort = nfs4_start_recovery(&e, mi,
rootvp, NULL, NULL, NULL,
- OP_LOOKUP, NULL);
+ OP_LOOKUP, NULL, NULL, NULL);
if (abort) {
nfs4_end_fop(mi, rootvp, NULL,
OH_LOOKUP, &recov_state,
@@ -2757,6 +2763,7 @@ clinit4_zone(zoneid_t zoneid)
mutex_enter(&nfs4_clnt_list_lock);
list_insert_head(&nfs4_clnt_list, nfscl);
mutex_exit(&nfs4_clnt_list_lock);
+
return (nfscl);
}
diff --git a/usr/src/uts/common/fs/nfs/nfs4_vfsops.c b/usr/src/uts/common/fs/nfs/nfs4_vfsops.c
index 71bb6f7f2f..2ebd9d6fdd 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_vfsops.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_vfsops.c
@@ -76,6 +76,8 @@
#include <nfs/nfs4_clnt.h>
#include <sys/fs/autofs.h>
+#include <sys/sdt.h>
+
/*
* Arguments passed to thread to free data structures from forced unmount.
@@ -160,6 +162,14 @@ static void remove_mi(nfs4_server_t *, mntinfo4_t *);
extern void nfs4_ephemeral_init(void);
extern void nfs4_ephemeral_fini(void);
+/* referral related routines */
+static servinfo4_t *copy_svp(servinfo4_t *);
+static void free_knconf_contents(struct knetconfig *k);
+static char *extract_referral_point(const char *, int);
+static void setup_newsvpath(servinfo4_t *, int);
+static void update_servinfo4(servinfo4_t *, fs_location4 *,
+ struct nfs_fsl_info *, char *, int);
+
/*
* Initialize the vfs structure
*/
@@ -1270,7 +1280,7 @@ recov_retry:
"getlinktext_otw: initiating recovery\n"));
if (nfs4_start_recovery(&e, mi, NULL, NULL, NULL, NULL,
- OP_READLINK, NULL) == FALSE) {
+ OP_READLINK, NULL, NULL, NULL) == FALSE) {
nfs4_end_op(mi, NULL, NULL, &recov_state, needrecov);
if (!e.error)
(void) xdr_free(xdr_COMPOUND4res_clnt,
@@ -1457,6 +1467,198 @@ out:
}
/*
+ * This routine updates servinfo4 structure with the new referred server
+ * info.
+ * nfsfsloc has the location related information
+ * fsp has the hostname and pathname info.
+ * new path = pathname from referral + part of orig pathname(based on nth).
+ */
+static void
+update_servinfo4(servinfo4_t *svp, fs_location4 *fsp,
+ struct nfs_fsl_info *nfsfsloc, char *orig_path, int nth)
+{
+ struct knetconfig *knconf, *svknconf;
+ struct netbuf *saddr;
+ sec_data_t *secdata;
+ utf8string *host;
+ int i = 0, num_slashes = 0;
+ char *p, *spath, *op, *new_path;
+
+ /* Update knconf */
+ knconf = svp->sv_knconf;
+ free_knconf_contents(knconf);
+ bzero(knconf, sizeof (struct knetconfig));
+ svknconf = nfsfsloc->knconf;
+ knconf->knc_semantics = svknconf->knc_semantics;
+ knconf->knc_protofmly = kmem_zalloc(KNC_STRSIZE, KM_SLEEP);
+ knconf->knc_proto = kmem_zalloc(KNC_STRSIZE, KM_SLEEP);
+ knconf->knc_rdev = svknconf->knc_rdev;
+ bcopy(svknconf->knc_protofmly, knconf->knc_protofmly, KNC_STRSIZE);
+ bcopy(svknconf->knc_proto, knconf->knc_proto, KNC_STRSIZE);
+
+ /* Update server address */
+ saddr = &svp->sv_addr;
+ if (saddr->buf != NULL)
+ kmem_free(saddr->buf, saddr->maxlen);
+ saddr->buf = kmem_alloc(nfsfsloc->addr->maxlen, KM_SLEEP);
+ saddr->len = nfsfsloc->addr->len;
+ saddr->maxlen = nfsfsloc->addr->maxlen;
+ bcopy(nfsfsloc->addr->buf, saddr->buf, nfsfsloc->addr->len);
+
+ /* Update server name */
+ host = fsp->server_val;
+ kmem_free(svp->sv_hostname, svp->sv_hostnamelen);
+ svp->sv_hostname = kmem_zalloc(host->utf8string_len + 1, KM_SLEEP);
+ bcopy(host->utf8string_val, svp->sv_hostname, host->utf8string_len);
+ svp->sv_hostname[host->utf8string_len] = '\0';
+ svp->sv_hostnamelen = host->utf8string_len + 1;
+
+ /*
+ * Update server path.
+ * We need to setup proper path here.
+ * For ex., If we got a path name serv1:/rp/aaa/bbb
+ * where aaa is a referral and points to serv2:/rpool/aa
+ * we need to set the path to serv2:/rpool/aa/bbb
+ * The first part of this below code generates /rpool/aa
+ * and the second part appends /bbb to the server path.
+ */
+ spath = p = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
+ *p++ = '/';
+ for (i = 0; i < fsp->rootpath.pathname4_len; i++) {
+ component4 *comp;
+
+ comp = &fsp->rootpath.pathname4_val[i];
+ /* If no space, null the string and bail */
+ if ((p - spath) + comp->utf8string_len + 1 > MAXPATHLEN) {
+ p = spath + MAXPATHLEN - 1;
+ spath[0] = '\0';
+ break;
+ }
+ bcopy(comp->utf8string_val, p, comp->utf8string_len);
+ p += comp->utf8string_len;
+ *p++ = '/';
+ }
+ if (fsp->rootpath.pathname4_len != 0)
+ *(p - 1) = '\0';
+ else
+ *p = '\0';
+ p = spath;
+
+ new_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
+ (void) strlcpy(new_path, p, MAXPATHLEN);
+ kmem_free(p, MAXPATHLEN);
+ i = strlen(new_path);
+
+ for (op = orig_path; *op; op++) {
+ if (*op == '/')
+ num_slashes++;
+ if (num_slashes == nth + 2) {
+ while (*op != '\0') {
+ new_path[i] = *op;
+ i++;
+ op++;
+ }
+ break;
+ }
+ }
+ new_path[i] = '\0';
+
+ kmem_free(svp->sv_path, svp->sv_pathlen);
+ svp->sv_pathlen = strlen(new_path) + 1;
+ svp->sv_path = kmem_alloc(svp->sv_pathlen, KM_SLEEP);
+ bcopy(new_path, svp->sv_path, svp->sv_pathlen);
+ kmem_free(new_path, MAXPATHLEN);
+
+ /*
+ * All the security data is specific to old server.
+ * Clean it up except secdata which deals with mount options.
+ * We need to inherit that data. Copy secdata into our new servinfo4.
+ */
+ if (svp->sv_dhsec) {
+ sec_clnt_freeinfo(svp->sv_dhsec);
+ svp->sv_dhsec = NULL;
+ }
+ if (svp->sv_save_secinfo &&
+ svp->sv_save_secinfo != svp->sv_secinfo) {
+ secinfo_free(svp->sv_save_secinfo);
+ svp->sv_save_secinfo = NULL;
+ }
+ if (svp->sv_secinfo) {
+ secinfo_free(svp->sv_secinfo);
+ svp->sv_secinfo = NULL;
+ }
+ svp->sv_currsec = NULL;
+
+ secdata = kmem_alloc(sizeof (*secdata), KM_SLEEP);
+ *secdata = *svp->sv_secdata;
+ secdata->data = NULL;
+ if (svp->sv_secdata) {
+ sec_clnt_freeinfo(svp->sv_secdata);
+ svp->sv_secdata = NULL;
+ }
+ svp->sv_secdata = secdata;
+}
+
+/*
+ * Resolve a referral. The referral is in the n+1th component of
+ * svp->sv_path and has a parent nfs4 file handle "fh".
+ * Upon return, the sv_path will point to the new path that has referral
+ * component resolved to its referred path and part of original path.
+ * Hostname and other address information is also updated.
+ */
+int
+resolve_referral(mntinfo4_t *mi, servinfo4_t *svp, cred_t *cr, int nth,
+ nfs_fh4 *fh)
+{
+ nfs4_sharedfh_t *sfh;
+ struct nfs_fsl_info nfsfsloc;
+ nfs4_ga_res_t garp;
+ COMPOUND4res_clnt callres;
+ fs_location4 *fsp;
+ char *nm, *orig_path;
+ int orig_pathlen = 0, ret = -1, index;
+
+ if (svp->sv_pathlen <= 0)
+ return (ret);
+
+ (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0);
+ orig_pathlen = svp->sv_pathlen;
+ orig_path = kmem_alloc(orig_pathlen, KM_SLEEP);
+ bcopy(svp->sv_path, orig_path, orig_pathlen);
+ nm = extract_referral_point(svp->sv_path, nth);
+ setup_newsvpath(svp, nth);
+ nfs_rw_exit(&svp->sv_lock);
+
+ sfh = sfh4_get(fh, mi);
+ index = nfs4_process_referral(mi, sfh, nm, cr,
+ &garp, &callres, &nfsfsloc);
+ sfh4_rele(&sfh);
+ kmem_free(nm, MAXPATHLEN);
+ if (index < 0) {
+ kmem_free(orig_path, orig_pathlen);
+ return (index);
+ }
+
+ fsp = &garp.n4g_ext_res->n4g_fslocations.locations_val[index];
+ (void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0);
+ update_servinfo4(svp, fsp, &nfsfsloc, orig_path, nth);
+ nfs_rw_exit(&svp->sv_lock);
+
+ mutex_enter(&mi->mi_lock);
+ mi->mi_vfs_referral_loop_cnt++;
+ mutex_exit(&mi->mi_lock);
+
+ ret = 0;
+bad:
+ /* Free up XDR memory allocated in nfs4_process_referral() */
+ xdr_free(xdr_nfs_fsl_info, (char *)&nfsfsloc);
+ xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&callres);
+ kmem_free(orig_path, orig_pathlen);
+
+ return (ret);
+}
+
+/*
* Get the root filehandle for the given filesystem and server, and update
* svp.
*
@@ -1466,7 +1668,6 @@ out:
*
* Errors are returned by the nfs4_error_t parameter.
*/
-
static void
nfs4getfh_otw(struct mntinfo4 *mi, servinfo4_t *svp, vtype_t *vtp,
int flags, cred_t *cr, nfs4_error_t *ep)
@@ -1498,7 +1699,14 @@ nfs4getfh_otw(struct mntinfo4 *mi, servinfo4_t *svp, vtype_t *vtp,
recov_state.rs_flags = 0;
recov_state.rs_num_retry_despite_err = 0;
+
recov_retry:
+ if (mi->mi_vfs_referral_loop_cnt >= NFS4_REFERRAL_LOOP_MAX) {
+ DTRACE_PROBE3(nfs4clnt__debug__referral__loop, mntinfo4 *,
+ mi, servinfo4_t *, svp, char *, "nfs4getfh_otw");
+ nfs4_error_init(ep, EINVAL);
+ return;
+ }
nfs4_error_zinit(ep);
if (!recovery) {
@@ -1599,7 +1807,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, NULL, NULL);
if (!ep->error) {
ep->error = geterrno4(res.status);
(void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
@@ -1628,7 +1836,8 @@ recov_retry:
is_link_err:
/* for non-recovery errors */
- if (res.status && res.status != NFS4ERR_SYMLINK) {
+ if (res.status && res.status != NFS4ERR_SYMLINK &&
+ res.status != NFS4ERR_MOVED) {
if (!recovery) {
nfs4_end_fop(mi, NULL, NULL, OH_MOUNT, &recov_state,
needrecov);
@@ -1643,10 +1852,18 @@ is_link_err:
* If any intermediate component in the path is a symbolic link,
* resolve the symlink, then try mount again using the new path.
*/
- if (res.status == NFS4ERR_SYMLINK) {
+ if (res.status == NFS4ERR_SYMLINK || res.status == NFS4ERR_MOVED) {
int where;
/*
+ * Need to call nfs4_end_op before resolve_sympath to avoid
+ * potential nfs4_start_op deadlock.
+ */
+ if (!recovery)
+ nfs4_end_fop(mi, NULL, NULL, OH_MOUNT, &recov_state,
+ needrecov);
+
+ /*
* This must be from OP_LOOKUP failure. The (cfh) for this
* OP_LOOKUP is a symlink node. Found out where the
* OP_GETFH is for the (cfh) that is a symlink node.
@@ -1661,21 +1878,24 @@ is_link_err:
where = res.array_len - 2;
ASSERT(where > 0);
- resop = &res.array[where - 1];
- ASSERT(resop->resop == OP_GETFH);
- tmpfhp = &resop->nfs_resop4_u.opgetfh.object;
- nthcomp = res.array_len/3 - 1;
+ if (res.status == NFS4ERR_SYMLINK) {
- /*
- * Need to call nfs4_end_op before resolve_sympath to avoid
- * potential nfs4_start_op deadlock.
- */
- if (!recovery)
- nfs4_end_fop(mi, NULL, NULL, OH_MOUNT, &recov_state,
- needrecov);
+ resop = &res.array[where - 1];
+ ASSERT(resop->resop == OP_GETFH);
+ tmpfhp = &resop->nfs_resop4_u.opgetfh.object;
+ nthcomp = res.array_len/3 - 1;
+ ep->error = resolve_sympath(mi, svp, nthcomp,
+ tmpfhp, cr, flags);
- ep->error = resolve_sympath(mi, svp, nthcomp, tmpfhp, cr,
- flags);
+ } else if (res.status == NFS4ERR_MOVED) {
+
+ resop = &res.array[where - 2];
+ ASSERT(resop->resop == OP_GETFH);
+ tmpfhp = &resop->nfs_resop4_u.opgetfh.object;
+ nthcomp = res.array_len/3 - 1;
+ ep->error = resolve_referral(mi, svp, cr, nthcomp,
+ tmpfhp);
+ }
nfs4args_lookup_free(argop, num_argops);
kmem_free(argop, lookuparg.arglen * sizeof (nfs_argop4));
@@ -1809,7 +2029,6 @@ is_link_err:
garp->n4g_ext_res->n4g_suppattrs | FATTR4_MANDATTR_MASK;
nfs_rw_exit(&svp->sv_lock);
-
nfs4args_lookup_free(argop, num_argops);
kmem_free(argop, lookuparg.arglen * sizeof (nfs_argop4));
(void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
@@ -1817,6 +2036,128 @@ is_link_err:
nfs4_end_fop(mi, NULL, NULL, OH_MOUNT, &recov_state, needrecov);
}
+/*
+ * Save a copy of Servinfo4_t structure.
+ * We might need when there is a failure in getting file handle
+ * in case of a referral to replace servinfo4 struct and try again.
+ */
+static struct servinfo4 *
+copy_svp(servinfo4_t *nsvp)
+{
+ servinfo4_t *svp = NULL;
+ struct knetconfig *sknconf, *tknconf;
+ struct netbuf *saddr, *taddr;
+
+ svp = kmem_zalloc(sizeof (*svp), KM_SLEEP);
+ nfs_rw_init(&svp->sv_lock, NULL, RW_DEFAULT, NULL);
+ svp->sv_flags = nsvp->sv_flags;
+ svp->sv_fsid = nsvp->sv_fsid;
+ svp->sv_hostnamelen = nsvp->sv_hostnamelen;
+ svp->sv_pathlen = nsvp->sv_pathlen;
+ svp->sv_supp_attrs = nsvp->sv_supp_attrs;
+
+ svp->sv_path = kmem_alloc(svp->sv_pathlen, KM_SLEEP);
+ svp->sv_hostname = kmem_alloc(svp->sv_hostnamelen, KM_SLEEP);
+ bcopy(nsvp->sv_hostname, svp->sv_hostname, svp->sv_hostnamelen);
+ bcopy(nsvp->sv_path, svp->sv_path, svp->sv_pathlen);
+
+ saddr = &nsvp->sv_addr;
+ taddr = &svp->sv_addr;
+ taddr->maxlen = saddr->maxlen;
+ taddr->len = saddr->len;
+ if (saddr->len > 0) {
+ taddr->buf = kmem_zalloc(saddr->maxlen, KM_SLEEP);
+ bcopy(saddr->buf, taddr->buf, saddr->len);
+ }
+
+ svp->sv_knconf = kmem_zalloc(sizeof (struct knetconfig), KM_SLEEP);
+ sknconf = nsvp->sv_knconf;
+ tknconf = svp->sv_knconf;
+ tknconf->knc_semantics = sknconf->knc_semantics;
+ tknconf->knc_rdev = sknconf->knc_rdev;
+ if (sknconf->knc_proto != NULL) {
+ tknconf->knc_proto = kmem_zalloc(KNC_STRSIZE, KM_SLEEP);
+ bcopy(sknconf->knc_proto, (char *)tknconf->knc_proto,
+ KNC_STRSIZE);
+ }
+ if (sknconf->knc_protofmly != NULL) {
+ tknconf->knc_protofmly = kmem_zalloc(KNC_STRSIZE, KM_SLEEP);
+ bcopy(sknconf->knc_protofmly, (char *)tknconf->knc_protofmly,
+ KNC_STRSIZE);
+ }
+
+ if (nsvp->sv_origknconf != NULL) {
+ svp->sv_origknconf = kmem_zalloc(sizeof (struct knetconfig),
+ KM_SLEEP);
+ sknconf = nsvp->sv_origknconf;
+ tknconf = svp->sv_origknconf;
+ tknconf->knc_semantics = sknconf->knc_semantics;
+ tknconf->knc_rdev = sknconf->knc_rdev;
+ if (sknconf->knc_proto != NULL) {
+ tknconf->knc_proto = kmem_zalloc(KNC_STRSIZE, KM_SLEEP);
+ bcopy(sknconf->knc_proto, (char *)tknconf->knc_proto,
+ KNC_STRSIZE);
+ }
+ if (sknconf->knc_protofmly != NULL) {
+ tknconf->knc_protofmly = kmem_zalloc(KNC_STRSIZE,
+ KM_SLEEP);
+ bcopy(sknconf->knc_protofmly,
+ (char *)tknconf->knc_protofmly, KNC_STRSIZE);
+ }
+ }
+
+ svp->sv_secdata = copy_sec_data(nsvp->sv_secdata);
+ svp->sv_dhsec = copy_sec_data(svp->sv_dhsec);
+ /*
+ * Rest of the security information is not copied as they are built
+ * with the information available from secdata and dhsec.
+ */
+ svp->sv_next = NULL;
+
+ return (svp);
+}
+
+servinfo4_t *
+restore_svp(mntinfo4_t *mi, servinfo4_t *svp, servinfo4_t *origsvp)
+{
+ servinfo4_t *srvnext, *tmpsrv;
+
+ if (strcmp(svp->sv_hostname, origsvp->sv_hostname) != 0) {
+ /*
+ * Since the hostname changed, we must be dealing
+ * with a referral, and the lookup failed. We will
+ * restore the whole servinfo4_t to what it was before.
+ */
+ srvnext = svp->sv_next;
+ svp->sv_next = NULL;
+ tmpsrv = copy_svp(origsvp);
+ sv4_free(svp);
+ svp = tmpsrv;
+ svp->sv_next = srvnext;
+ mutex_enter(&mi->mi_lock);
+ mi->mi_servers = svp;
+ mi->mi_curr_serv = svp;
+ mutex_exit(&mi->mi_lock);
+
+ } else if (origsvp->sv_pathlen != svp->sv_pathlen) {
+
+ /*
+ * For symlink case: restore original path because
+ * it might have contained symlinks that were
+ * expanded by nfsgetfh_otw before the failure occurred.
+ */
+ nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0);
+ kmem_free(svp->sv_path, svp->sv_pathlen);
+ svp->sv_path =
+ kmem_alloc(origsvp->sv_pathlen, KM_SLEEP);
+ svp->sv_pathlen = origsvp->sv_pathlen;
+ bcopy(origsvp->sv_path, svp->sv_path,
+ origsvp->sv_pathlen);
+ nfs_rw_exit(&svp->sv_lock);
+ }
+ return (svp);
+}
+
static ushort_t nfs4_max_threads = 8; /* max number of active async threads */
static uint_t nfs4_bsize = 32 * 1024; /* client `block' size */
static uint_t nfs4_async_clusters = 1; /* # of reqs from each async queue */
@@ -1830,12 +2171,11 @@ static uint_t nfs4_cots_timeo = NFS_COTS_TIMEO;
void
nfs4_remap_root(mntinfo4_t *mi, nfs4_error_t *ep, int flags)
{
- struct servinfo4 *svp;
+ struct servinfo4 *svp, *origsvp;
vtype_t vtype;
nfs_fh4 rootfh;
int getfh_flags;
- char *orig_sv_path;
- int orig_sv_pathlen, num_retry;
+ int num_retry;
mutex_enter(&mi->mi_lock);
@@ -1861,9 +2201,7 @@ remap_retry:
* to re-lookup everything and recover.
*/
(void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0);
- orig_sv_pathlen = svp->sv_pathlen;
- orig_sv_path = kmem_alloc(orig_sv_pathlen, KM_SLEEP);
- bcopy(svp->sv_path, orig_sv_path, orig_sv_pathlen);
+ origsvp = copy_svp(svp);
nfs_rw_exit(&svp->sv_lock);
num_retry = nfs4_max_mount_retry;
@@ -1882,24 +2220,13 @@ remap_retry:
/*
* For some reason, the mount compound failed. Before
- * retrying, we need to restore the original sv_path
- * because it might have contained symlinks that were
- * expanded by nfsgetfh_otw before the failure occurred.
- * replace current sv_path with orig sv_path -- just in case
- * it changed due to embedded symlinks.
+ * retrying, we need to restore original conditions.
*/
- (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0);
- 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);
- svp->sv_pathlen = orig_sv_pathlen;
- }
- bcopy(orig_sv_path, svp->sv_path, orig_sv_pathlen);
- nfs_rw_exit(&svp->sv_lock);
+ svp = restore_svp(mi, svp, origsvp);
} while (num_retry-- > 0);
- kmem_free(orig_sv_path, orig_sv_pathlen);
+ sv4_free(origsvp);
if (ep->error != 0 || ep->stat != 0) {
return;
@@ -1940,7 +2267,7 @@ nfs4rootvp(vnode_t **rtvpp, vfs_t *vfsp, struct servinfo4 *svp_head,
dev_t nfs_dev;
int error = 0;
rnode4_t *rp;
- int i;
+ int i, len;
struct vattr va;
vtype_t vtype = VNON;
vtype_t tmp_vtype = VNON;
@@ -1951,9 +2278,10 @@ nfs4rootvp(vnode_t **rtvpp, vfs_t *vfsp, struct servinfo4 *svp_head,
struct nfs_stats *nfsstatsp;
nfs4_fname_t *mfname;
nfs4_error_t e;
- char *orig_sv_path;
- int orig_sv_pathlen, num_retry, removed;
+ int num_retry, removed;
cred_t *lcr = NULL, *tcr = cr;
+ struct servinfo4 *origsvp;
+ char *resource;
nfsstatsp = zone_getspecific(nfsstat_zone_key, nfs_zone());
ASSERT(nfsstatsp != NULL);
@@ -1980,6 +2308,8 @@ nfs4rootvp(vnode_t **rtvpp, vfs_t *vfsp, struct servinfo4 *svp_head,
mi->mi_flags |= MI4_PUBLIC;
if (flags & NFSMNT_MIRRORMOUNT)
mi->mi_flags |= MI4_MIRRORMOUNT;
+ if (flags & NFSMNT_REFERRAL)
+ mi->mi_flags |= MI4_REFERRAL;
mi->mi_retrans = NFS_RETRIES;
if (svp->sv_knconf->knc_semantics == NC_TPI_COTS_ORD ||
svp->sv_knconf->knc_semantics == NC_TPI_COTS)
@@ -2100,9 +2430,7 @@ nfs4rootvp(vnode_t **rtvpp, vfs_t *vfsp, struct servinfo4 *svp_head,
* Save server path we're attempting to mount.
*/
(void) nfs_rw_enter_sig(&svp->sv_lock, RW_WRITER, 0);
- orig_sv_pathlen = svp_head->sv_pathlen;
- orig_sv_path = kmem_alloc(svp_head->sv_pathlen, KM_SLEEP);
- bcopy(svp_head->sv_path, orig_sv_path, svp_head->sv_pathlen);
+ origsvp = copy_svp(svp);
nfs_rw_exit(&svp->sv_lock);
/*
@@ -2162,21 +2490,13 @@ nfs4rootvp(vnode_t **rtvpp, vfs_t *vfsp, struct servinfo4 *svp_head,
break;
/*
- * replace current sv_path with orig sv_path -- just in
- * case it changed due to embedded symlinks.
+ * For some reason, the mount compound failed. Before
+ * retrying, we need to restore original conditions.
*/
- (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0);
- 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);
- svp->sv_pathlen = orig_sv_pathlen;
- }
- bcopy(orig_sv_path, svp->sv_path, orig_sv_pathlen);
- nfs_rw_exit(&svp->sv_lock);
+ svp = restore_svp(mi, svp, origsvp);
+ svp_head = svp;
} while (num_retry-- > 0);
-
error = e.error ? e.error : geterrno4(e.stat);
if (error) {
nfs_cmn_err(error, CE_WARN,
@@ -2215,8 +2535,6 @@ nfs4rootvp(vnode_t **rtvpp, vfs_t *vfsp, struct servinfo4 *svp_head,
firstsvp = svp;
}
- kmem_free(orig_sv_path, orig_sv_pathlen);
-
if (firstsvp == NULL) {
if (error == 0)
error = ENOENT;
@@ -2286,6 +2604,19 @@ nfs4rootvp(vnode_t **rtvpp, vfs_t *vfsp, struct servinfo4 *svp_head,
mi->mi_flags &= ~MI4_MOUNTING;
mutex_exit(&mi->mi_lock);
+ /* Update VFS with new server and path info */
+ if ((strcmp(svp->sv_hostname, origsvp->sv_hostname) != 0) ||
+ (strcmp(svp->sv_path, origsvp->sv_path) != 0)) {
+ len = svp->sv_hostnamelen + svp->sv_pathlen;
+ resource = kmem_zalloc(len, KM_SLEEP);
+ (void) strcat(resource, svp->sv_hostname);
+ (void) strcat(resource, ":");
+ (void) strcat(resource, svp->sv_path);
+ vfs_setresource(vfsp, resource);
+ kmem_free(resource, len);
+ }
+
+ sv4_free(origsvp);
*rtvpp = rtvp;
if (lcr != NULL)
crfree(lcr);
@@ -2321,6 +2652,9 @@ bad:
*/
MI4_RELE(mi);
+ if (origsvp != NULL)
+ sv4_free(origsvp);
+
*rtvpp = NULL;
return (error);
}
@@ -2336,7 +2670,6 @@ nfs4_unmount(vfs_t *vfsp, int flag, cred_t *cr)
int removed;
bool_t must_unlock;
- bool_t must_rele;
nfs4_ephemeral_tree_t *eph_tree;
@@ -2388,7 +2721,7 @@ nfs4_unmount(vfs_t *vfsp, int flag, cred_t *cr)
* again when needed.
*/
if (nfs4_ephemeral_umount(mi, flag, cr,
- &must_unlock, &must_rele, &eph_tree)) {
+ &must_unlock, &eph_tree)) {
ASSERT(must_unlock == FALSE);
mutex_enter(&mi->mi_async_lock);
mi->mi_max_threads = omax;
@@ -2402,8 +2735,7 @@ nfs4_unmount(vfs_t *vfsp, int flag, cred_t *cr)
* then the file system is busy and can't be unmounted.
*/
if (check_rtable4(vfsp)) {
- nfs4_ephemeral_umount_unlock(&must_unlock, &must_rele,
- &eph_tree);
+ nfs4_ephemeral_umount_unlock(&must_unlock, &eph_tree);
mutex_enter(&mi->mi_async_lock);
mi->mi_max_threads = omax;
@@ -2416,8 +2748,7 @@ nfs4_unmount(vfs_t *vfsp, int flag, cred_t *cr)
* The unmount can't fail from now on, so record any
* ephemeral changes.
*/
- nfs4_ephemeral_umount_activate(mi, &must_unlock,
- &must_rele, &eph_tree);
+ nfs4_ephemeral_umount_activate(mi, &must_unlock, &eph_tree);
/*
* There are no active files that could require over-the-wire
@@ -2982,7 +3313,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, NULL, NULL);
/*
* Don't retry here, just return and let
* recovery take over.
@@ -3534,7 +3865,12 @@ new_nfs4_server(struct servinfo4 *svp, cred_t *cr)
} un_curtime;
verifier4 un_verifier;
} nfs4clientid_verifier;
- char id_val[] = "Solaris: %s, NFSv4 kernel client";
+ /*
+ * We change this ID string carefully and with the Solaris
+ * NFS server behaviour in mind. "+referrals" indicates
+ * a client that can handle an NFSv4 referral.
+ */
+ char id_val[] = "Solaris: %s, NFSv4 kernel client +referrals";
int len;
np = kmem_zalloc(sizeof (struct nfs4_server), KM_SLEEP);
@@ -3946,7 +4282,6 @@ nfs4_free_mount(vfs_t *vfsp, int flag, cred_t *cr)
int removed;
bool_t must_unlock;
- bool_t must_rele;
nfs4_ephemeral_tree_t *eph_tree;
/*
@@ -4020,9 +4355,9 @@ nfs4_free_mount(vfs_t *vfsp, int flag, cred_t *cr)
* directory tree, we are okay.
*/
if (!nfs4_ephemeral_umount(mi, flag, cr,
- &must_unlock, &must_rele, &eph_tree))
+ &must_unlock, &eph_tree))
nfs4_ephemeral_umount_activate(mi, &must_unlock,
- &must_rele, &eph_tree);
+ &eph_tree);
/*
* The original purge of the dnlc via 'dounmount'
@@ -4058,3 +4393,81 @@ nfs4_free_mount(vfs_t *vfsp, int flag, cred_t *cr)
if (removed)
zone_rele(mi->mi_zone);
}
+
+/* Referral related sub-routines */
+
+/* Freeup knetconfig */
+static void
+free_knconf_contents(struct knetconfig *k)
+{
+ if (k == NULL)
+ return;
+ if (k->knc_protofmly)
+ kmem_free(k->knc_protofmly, KNC_STRSIZE);
+ if (k->knc_proto)
+ kmem_free(k->knc_proto, KNC_STRSIZE);
+}
+
+/*
+ * This updates newpath variable with exact name component from the
+ * path which gave us a NFS4ERR_MOVED error.
+ * If the path is /rp/aaa/bbb and nth value is 1, aaa is returned.
+ */
+static char *
+extract_referral_point(const char *svp, int nth)
+{
+ int num_slashes = 0;
+ const char *p;
+ char *newpath = NULL;
+ int i = 0;
+
+ newpath = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
+ for (p = svp; *p; p++) {
+ if (*p == '/')
+ num_slashes++;
+ if (num_slashes == nth + 1) {
+ p++;
+ while (*p != '/') {
+ if (*p == '\0')
+ break;
+ newpath[i] = *p;
+ i++;
+ p++;
+ }
+ newpath[i++] = '\0';
+ break;
+ }
+ }
+ return (newpath);
+}
+
+/*
+ * This sets up a new path in sv_path to do a lookup of the referral point.
+ * If the path is /rp/aaa/bbb and the referral point is aaa,
+ * this updates /rp/aaa. This path will be used to get referral
+ * location.
+ */
+static void
+setup_newsvpath(servinfo4_t *svp, int nth)
+{
+ int num_slashes = 0, pathlen, i = 0;
+ char *newpath, *p;
+
+ newpath = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
+ for (p = svp->sv_path; *p; p++) {
+ newpath[i] = *p;
+ if (*p == '/')
+ num_slashes++;
+ if (num_slashes == nth + 1) {
+ newpath[i] = '\0';
+ pathlen = strlen(newpath) + 1;
+ kmem_free(svp->sv_path, svp->sv_pathlen);
+ svp->sv_path = kmem_alloc(pathlen, KM_SLEEP);
+ svp->sv_pathlen = pathlen;
+ bcopy(newpath, svp->sv_path, pathlen);
+ break;
+ }
+ i++;
+ }
+ kmem_free(newpath, MAXPATHLEN);
+}
diff --git a/usr/src/uts/common/fs/nfs/nfs4_vnops.c b/usr/src/uts/common/fs/nfs/nfs4_vnops.c
index 5e79c7138f..49d2359d78 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_vnops.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_vnops.c
@@ -90,6 +90,7 @@
#include <sys/ddi.h>
#include <sys/int_fmtio.h>
+#include <sys/fs/autofs.h>
typedef struct {
nfs4_ga_res_t *di_garp;
@@ -164,7 +165,6 @@ static void nfs4_register_lock_locally(vnode_t *, struct flock64 *, int,
static int nfs4_lockrelease(vnode_t *, int, offset_t, cred_t *);
static int nfs4_block_and_wait(clock_t *, rnode4_t *);
static cred_t *state_to_cred(nfs4_open_stream_t *);
-static int vtoname(vnode_t *, char *, ssize_t);
static void denied_to_flk(LOCK4denied *, flock64_t *, LOCKT4args *);
static pid_t lo_to_pid(lock_owner4 *);
static void nfs4_reinstitute_local_lock_state(vnode_t *, flock64_t *,
@@ -1183,7 +1183,7 @@ recov_retry:
abort = nfs4_start_recovery(&e, VTOMI4(dvp), dvp, vpi,
NULL, lost_rqst.lr_op == OP_OPEN ?
- &lost_rqst : NULL, OP_OPEN, bsep);
+ &lost_rqst : NULL, OP_OPEN, bsep, NULL, NULL);
if (bsep)
kmem_free(bsep, sizeof (*bsep));
@@ -1897,7 +1897,7 @@ top:
abort = nfs4_start_recovery(ep,
VTOMI4(vp), vp, NULL, NULL,
lost_rqst.lr_op == OP_OPEN ?
- &lost_rqst : NULL, OP_OPEN, NULL);
+ &lost_rqst : NULL, OP_OPEN, NULL, NULL, NULL);
nfs4args_copen_free(open_args);
goto bailout;
}
@@ -1936,7 +1936,7 @@ top:
abort = nfs4_start_recovery(ep, VTOMI4(vp), vp, NULL,
NULL, lost_rqst.lr_op == OP_OPEN ? &lost_rqst :
- NULL, OP_OPEN, bsep);
+ NULL, OP_OPEN, bsep, NULL, NULL);
nfs4args_copen_free(open_args);
(void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
@@ -1995,7 +1995,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, NULL, NULL);
nfs4args_copen_free(open_args);
(void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
nfs4_end_open_seqid_sync(oop);
@@ -2511,7 +2511,7 @@ nfs4close_otw(rnode4_t *rp, cred_t *cred_otw, nfs4_open_owner_t *oop,
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);
+ OP_CLOSE, bsep, NULL, NULL);
/* drop open seq sync, and let the calling function regrab it */
nfs4_end_open_seqid_sync(oop);
@@ -3280,7 +3280,7 @@ recov_retry:
abort = nfs4_start_recovery(&e,
VTOMI4(vp), vp, NULL, &wargs->stateid,
- NULL, OP_WRITE, NULL);
+ NULL, OP_WRITE, NULL, NULL, NULL);
if (!e.error) {
e.error = geterrno4(res.status);
(void) xdr_free(xdr_COMPOUND4res_clnt,
@@ -3540,7 +3540,7 @@ recov_retry:
"nfs4read: initiating recovery\n"));
abort = nfs4_start_recovery(&e,
mi, vp, NULL, &rargs->stateid,
- NULL, OP_READ, NULL);
+ NULL, OP_READ, NULL, NULL, NULL);
nfs4_end_fop(mi, vp, NULL, OH_READ,
&recov_state, needrecov);
/*
@@ -3987,7 +3987,7 @@ recov_retry:
abort = nfs4_start_recovery(&e,
VTOMI4(vp), vp, NULL, NULL, NULL,
- OP_SETATTR, NULL);
+ OP_SETATTR, NULL, NULL, NULL);
nfs4_end_op(VTOMI4(vp), vp, NULL, &recov_state,
needrecov);
/*
@@ -4379,7 +4379,7 @@ recov_retry:
"nfs4_access: initiating recovery\n"));
if (nfs4_start_recovery(&e, VTOMI4(vp), vp, NULL, NULL,
- NULL, OP_ACCESS, NULL) == FALSE) {
+ NULL, OP_ACCESS, NULL, NULL, NULL) == FALSE) {
nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_ACCESS,
&recov_state, needrecov);
if (!e.error)
@@ -4536,7 +4536,7 @@ recov_retry:
"nfs4_readlink: initiating recovery\n"));
if (nfs4_start_recovery(&e, VTOMI4(vp), vp, NULL, NULL,
- NULL, OP_READLINK, NULL) == FALSE) {
+ NULL, OP_READLINK, NULL, NULL, NULL) == FALSE) {
if (!e.error)
(void) xdr_free(xdr_COMPOUND4res_clnt,
(caddr_t)&res);
@@ -4897,7 +4897,7 @@ recov_retry_remove:
if (nfs4_needs_recovery(&e, FALSE, unldvp->v_vfsp)) {
if (nfs4_start_recovery(&e, VTOMI4(unldvp), unldvp, NULL,
- NULL, NULL, OP_REMOVE, NULL) == FALSE) {
+ NULL, NULL, OP_REMOVE, NULL, NULL, NULL) == FALSE) {
if (!e.error)
(void) xdr_free(xdr_COMPOUND4res_clnt,
(caddr_t)&res);
@@ -5316,6 +5316,17 @@ recov_retry:
rfs4call(VTOMI4(dvp), &args, &res, cr, &doqueue, 0, &e);
+ if (!isdotdot && res.status == NFS4ERR_MOVED) {
+ e.error = nfs4_setup_referral(dvp, nm, vpp, cr);
+ if (e.error != 0 && *vpp != NULL)
+ VN_RELE(*vpp);
+ nfs4_end_fop(mi, dvp, NULL, OH_LOOKUP,
+ &recov_state, FALSE);
+ (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
+ kmem_free(argop, argoplist_size);
+ return (e.error);
+ }
+
if (nfs4_needs_recovery(&e, FALSE, dvp->v_vfsp)) {
/*
* For WRONGSEC of a non-dotdot case, send secinfo directly
@@ -5343,7 +5354,7 @@ recov_retry:
}
if (nfs4_start_recovery(&e, mi, dvp, NULL, NULL, NULL,
- OP_LOOKUP, NULL) == FALSE) {
+ OP_LOOKUP, NULL, NULL, NULL) == FALSE) {
nfs4_end_fop(mi, dvp, NULL, OH_LOOKUP,
&recov_state, TRUE);
@@ -5743,6 +5754,17 @@ recov_retry:
rfs4call(VTOMI4(dvp), &args, &res, cr, &doqueue, 0, &e);
+ if (!isdotdot && res.status == NFS4ERR_MOVED) {
+ e.error = nfs4_setup_referral(dvp, nm, vpp, cr);
+ if (e.error != 0 && *vpp != NULL)
+ VN_RELE(*vpp);
+ nfs4_end_fop(mi, dvp, NULL, OH_LOOKUP,
+ &recov_state, FALSE);
+ (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
+ kmem_free(argop, argoplist_size);
+ return (e.error);
+ }
+
if (nfs4_needs_recovery(&e, FALSE, dvp->v_vfsp)) {
/*
* For WRONGSEC of a non-dotdot case, send secinfo directly
@@ -5768,7 +5790,7 @@ recov_retry:
}
if (nfs4_start_recovery(&e, mi, dvp, NULL, NULL, NULL,
- OP_LOOKUP, NULL) == FALSE) {
+ OP_LOOKUP, NULL, NULL, NULL) == FALSE) {
nfs4_end_fop(mi, dvp, NULL, OH_LOOKUP,
&recov_state, TRUE);
@@ -6374,7 +6396,7 @@ recov_retry:
abort = nfs4_start_recovery(&e,
VTOMI4(dvp), dvp, NULL, NULL, NULL,
- OP_OPENATTR, NULL);
+ OP_OPENATTR, NULL, NULL, NULL);
nfs4_end_op(VTOMI4(dvp), dvp, NULL, &recov_state, needrecov);
if (!e.error) {
e.error = geterrno4(res.status);
@@ -6986,7 +7008,7 @@ recov_retry:
if (needrecov) {
if (nfs4_start_recovery(&e, mi, dvp, NULL, NULL, NULL,
- OP_CREATE, NULL) == FALSE) {
+ OP_CREATE, NULL, NULL, NULL) == FALSE) {
nfs4_end_op(mi, dvp, NULL, &recov_state,
needrecov);
need_end_op = FALSE;
@@ -7345,7 +7367,7 @@ recov_retry:
if (needrecov) {
if (nfs4_start_recovery(&e, VTOMI4(dvp), dvp,
- NULL, NULL, NULL, OP_REMOVE, NULL) == FALSE) {
+ NULL, NULL, NULL, OP_REMOVE, NULL, NULL, NULL) == FALSE) {
if (!e.error)
(void) xdr_free(xdr_COMPOUND4res_clnt,
(caddr_t)&res);
@@ -7519,7 +7541,7 @@ recov_retry:
bool_t abort;
abort = nfs4_start_recovery(&e, VTOMI4(svp), svp, tdvp,
- NULL, NULL, OP_LINK, NULL);
+ NULL, NULL, OP_LINK, NULL, NULL, NULL);
if (abort == FALSE) {
nfs4_end_op(VTOMI4(svp), svp, tdvp, &recov_state,
needrecov);
@@ -8187,7 +8209,7 @@ recov_retry:
if (needrecov) {
if (nfs4_start_recovery(&e, mi, odvp, ndvp, NULL, NULL,
- OP_RENAME, NULL) == FALSE) {
+ OP_RENAME, NULL, NULL, NULL) == FALSE) {
nfs4_end_op(mi, odvp, ndvp, &recov_state, needrecov);
if (!e.error)
(void) xdr_free(xdr_COMPOUND4res_clnt,
@@ -8444,7 +8466,7 @@ recov_retry:
bool_t abort;
abort = nfs4_start_recovery(&e, mi, odvp, ndvp, NULL, NULL,
- OP_RENAME, NULL);
+ OP_RENAME, NULL, NULL, NULL);
if (abort == FALSE) {
nfs4_end_fop(mi, odvp, ndvp, OH_VFH_RENAME,
&recov_state, needrecov);
@@ -8722,7 +8744,7 @@ recov_retry:
if (needrecov) {
if (nfs4_start_recovery(&e, VTOMI4(dvp), dvp, NULL, NULL,
- NULL, OP_REMOVE, NULL) == FALSE) {
+ NULL, OP_REMOVE, NULL, NULL, NULL) == FALSE) {
if (!e.error)
(void) xdr_free(xdr_COMPOUND4res_clnt,
(caddr_t)&res);
@@ -9319,7 +9341,7 @@ recov_retry:
"nfs4readdir: initiating recovery.\n"));
abort = nfs4_start_recovery(&e, VTOMI4(vp), vp, NULL, NULL,
- NULL, OP_READDIR, NULL);
+ NULL, OP_READDIR, NULL, NULL, NULL);
if (abort == FALSE) {
nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_READDIR,
&recov_state, needrecov);
@@ -11756,7 +11778,7 @@ recov_retry:
if (needrecov) {
if (nfs4_start_recovery(&e, VTOMI4(vp), vp, NULL, NULL,
- NULL, OP_COMMIT, NULL) == FALSE) {
+ NULL, OP_COMMIT, NULL, NULL, NULL) == FALSE) {
nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_COMMIT,
&recov_state, needrecov);
if (!e.error)
@@ -12318,6 +12340,12 @@ nfs4_getsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr,
if (error) /* EINVAL */
return (error);
+ /*
+ * If this is a referral stub, don't try to go OTW for an ACL
+ */
+ if (RP_ISSTUB_REFERRAL(VTOR4(vp)))
+ return (fs_fab_acl(vp, vsecattr, flag, cr, ct));
+
if (mi->mi_flags & MI4_ACL) {
/*
* Check if the data is cached and the cache is valid. If it
@@ -12752,8 +12780,8 @@ recov_retry_confirm:
vp, 0, args.ctag,
open_confirm_args->seqid);
- abort = nfs4_start_recovery(ep, VTOMI4(vp), vp,
- NULL, NULL, NULL, OP_OPEN_CONFIRM, bsep);
+ abort = nfs4_start_recovery(ep, VTOMI4(vp), vp, NULL,
+ NULL, NULL, OP_OPEN_CONFIRM, bsep, NULL, NULL);
if (bsep) {
kmem_free(bsep, sizeof (*bsep));
if (num_bseqid_retryp &&
@@ -13686,7 +13714,7 @@ nfs4frlock_recovery(int needrecov, nfs4_error_t *ep,
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);
+ NULL, op, bsep, NULL, NULL);
if (bsep)
kmem_free(bsep, sizeof (*bsep));
@@ -14215,7 +14243,7 @@ recov_retry:
VTOMI4(vp), vp, NULL, NULL,
(lost_rqst.lr_op == OP_LOCK ||
lost_rqst.lr_op == OP_LOCKU) ?
- &lost_rqst : NULL, OP_LOCKU, NULL);
+ &lost_rqst : NULL, OP_LOCKU, NULL, NULL, NULL);
lock_owner_rele(lop);
lop = NULL;
}
@@ -15303,7 +15331,7 @@ recov_retry:
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 : NULL, OP_CLOSE, NULL, NULL, NULL);
close_failed = 1;
force_close = 0;
goto close_cleanup;
@@ -15387,7 +15415,7 @@ recov_retry:
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);
+ bsep, NULL, NULL);
if (odg_cred_otw)
crfree(odg_cred_otw);
if (bsep)
@@ -15976,5 +16004,5 @@ push_reinstate(vnode_t *vp, int cmd, flock64_t *flk, cred_t *cr,
(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);
+ NULL, NULL, NULL);
}
diff --git a/usr/src/uts/common/fs/nfs/nfs4_xdr.c b/usr/src/uts/common/fs/nfs/nfs4_xdr.c
index 1b3d1462a6..e2e14cff8a 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_xdr.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_xdr.c
@@ -42,7 +42,16 @@
#include <nfs/nfs4.h>
#include <nfs/nfs4_clnt.h>
#include <sys/sdt.h>
+#include <sys/mkdev.h>
#include <rpc/rpc_rdma.h>
+#include <rpc/xdr.h>
+
+#define xdr_dev_t xdr_u_int
+
+extern bool_t xdr_netbuf(XDR *, struct netbuf *);
+extern bool_t xdr_vector(XDR *, char *, const uint_t, const uint_t,
+ const xdrproc_t);
+bool_t xdr_knetconfig(XDR *, struct knetconfig *);
bool_t
xdr_bitmap4(XDR *xdrs, bitmap4 *objp)
@@ -146,6 +155,143 @@ xdr_utf8string(XDR *xdrs, utf8string *objp)
}
/*
+ * used by NFSv4 referrals to get info needed for NFSv4 referral mount.
+ */
+bool_t
+xdr_nfs_fsl_info(XDR *xdrs, struct nfs_fsl_info *objp)
+{
+
+ if (!xdr_u_int(xdrs, &objp->netbuf_len))
+ return (FALSE);
+ if (!xdr_u_int(xdrs, &objp->netnm_len))
+ return (FALSE);
+ if (!xdr_u_int(xdrs, &objp->knconf_len))
+ return (FALSE);
+
+#if defined(_LP64)
+ /*
+ * The object can come from a 32-bit binary; nfsmapid.
+ * To be safe we double the size of the knetconfig to
+ * allow some buffering for decoding.
+ */
+ if (xdrs->x_op == XDR_DECODE)
+ objp->knconf_len += sizeof (struct knetconfig);
+#endif
+
+ if (!xdr_string(xdrs, &objp->netname, ~0))
+ return (FALSE);
+ if (!xdr_pointer(xdrs, (char **)&objp->addr, objp->netbuf_len,
+ (xdrproc_t)xdr_netbuf))
+ return (FALSE);
+ if (!xdr_pointer(xdrs, (char **)&objp->knconf,
+ objp->knconf_len, (xdrproc_t)xdr_knetconfig))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_knetconfig(XDR *xdrs, struct knetconfig *objp)
+{
+ rpc_inline_t *buf;
+ u_longlong_t dev64;
+#if !defined(_LP64)
+ uint32_t major, minor;
+#endif
+ int i;
+
+ if (!xdr_u_int(xdrs, &objp->knc_semantics))
+ return (FALSE);
+ if (xdrs->x_op == XDR_DECODE) {
+ objp->knc_protofmly = (((char *)objp) +
+ sizeof (struct knetconfig));
+ objp->knc_proto = objp->knc_protofmly + KNC_STRSIZE;
+ }
+ if (!xdr_opaque(xdrs, objp->knc_protofmly, KNC_STRSIZE))
+ return (FALSE);
+ if (!xdr_opaque(xdrs, objp->knc_proto, KNC_STRSIZE))
+ return (FALSE);
+
+ /*
+ * For interoperability between 32-bit daemon and 64-bit kernel,
+ * we always treat dev_t as 64-bit number and do the expanding
+ * or compression of dev_t as needed.
+ * We have to hand craft the conversion since there is no available
+ * function in ddi.c. Besides ddi.c is available only in the kernel
+ * and we want to keep both user and kernel of xdr_knetconfig() the
+ * same for consistency.
+ */
+ if (xdrs->x_op == XDR_ENCODE) {
+#if defined(_LP64)
+ dev64 = objp->knc_rdev;
+#else
+ major = (objp->knc_rdev >> NBITSMINOR32) & MAXMAJ32;
+ minor = objp->knc_rdev & MAXMIN32;
+ dev64 = (((unsigned long long)major) << NBITSMINOR64) | minor;
+#endif
+ if (!xdr_u_longlong_t(xdrs, &dev64))
+ return (FALSE);
+ }
+ if (xdrs->x_op == XDR_DECODE) {
+#if defined(_LP64)
+ if (!xdr_u_longlong_t(xdrs, (u_longlong_t *)&objp->knc_rdev))
+ return (FALSE);
+#else
+ if (!xdr_u_longlong_t(xdrs, &dev64))
+ return (FALSE);
+
+ major = (dev64 >> NBITSMINOR64) & L_MAXMAJ32;
+ minor = dev64 & L_MAXMIN32;
+ objp->knc_rdev = (major << L_BITSMINOR32) | minor;
+#endif
+ }
+
+ if (xdrs->x_op == XDR_ENCODE) {
+ buf = XDR_INLINE(xdrs, (8) * BYTES_PER_XDR_UNIT);
+ if (buf == NULL) {
+ if (!xdr_vector(xdrs, (char *)objp->knc_unused, 8,
+ sizeof (uint_t), (xdrproc_t)xdr_u_int))
+ return (FALSE);
+ } else {
+ uint_t *genp;
+
+ for (i = 0, genp = objp->knc_unused;
+ i < 8; i++) {
+#if defined(_LP64) || defined(_KERNEL)
+ IXDR_PUT_U_INT32(buf, *genp++);
+#else
+ IXDR_PUT_U_LONG(buf, *genp++);
+#endif
+ }
+ }
+ return (TRUE);
+ } else if (xdrs->x_op == XDR_DECODE) {
+ buf = XDR_INLINE(xdrs, (8) * BYTES_PER_XDR_UNIT);
+ if (buf == NULL) {
+ if (!xdr_vector(xdrs, (char *)objp->knc_unused, 8,
+ sizeof (uint_t), (xdrproc_t)xdr_u_int))
+ return (FALSE);
+ } else {
+ uint_t *genp;
+
+ for (i = 0, genp = objp->knc_unused;
+ i < 8; i++) {
+#if defined(_LP64) || defined(_KERNEL)
+ *genp++ = IXDR_GET_U_INT32(buf);
+#else
+ *genp++ = IXDR_GET_U_LONG(buf);
+#endif
+ }
+ }
+ return (TRUE);
+ }
+
+ if (!xdr_vector(xdrs, (char *)objp->knc_unused, 8,
+ sizeof (uint_t), (xdrproc_t)xdr_u_int))
+ return (FALSE);
+ return (TRUE);
+}
+
+/*
* XDR_INLINE decode a filehandle.
*/
bool_t
@@ -492,8 +638,12 @@ xdr_nfs_fh4(XDR *xdrs, nfs_fh4 *objp)
static bool_t
xdr_fs_location4(XDR *xdrs, fs_location4 *objp)
{
+ if (xdrs->x_op == XDR_DECODE) {
+ objp->server_val = NULL;
+ objp->rootpath.pathname4_val = NULL;
+ }
if (!xdr_array(xdrs, (char **)&objp->server_val,
- (uint_t *)&objp->server_len, NFS4_FS_LOCATIONS_LIMIT,
+ (uint_t *)&objp->server_len, NFS4_MAX_UTF8STRING,
sizeof (utf8string), (xdrproc_t)xdr_utf8string))
return (FALSE);
return (xdr_array(xdrs, (char **)&objp->rootpath.pathname4_val,
@@ -560,6 +710,11 @@ xdr_fattr4_acl(XDR *xdrs, fattr4_acl *objp)
bool_t
xdr_fattr4_fs_locations(XDR *xdrs, fattr4_fs_locations *objp)
{
+ if (xdrs->x_op == XDR_DECODE) {
+ objp->fs_root.pathname4_len = 0;
+ objp->fs_root.pathname4_val = NULL;
+ objp->locations_val = NULL;
+ }
if (!xdr_array(xdrs, (char **)&objp->fs_root.pathname4_val,
(uint_t *)&objp->fs_root.pathname4_len,
NFS4_MAX_PATHNAME4,
@@ -930,7 +1085,9 @@ xdr_ga_fattr_res(XDR *xdrs, struct nfs4_ga_res *garp, bitmap4 resbmap,
FATTR4_HOMOGENEOUS_MASK)) {
if (resbmap & FATTR4_FS_LOCATIONS_MASK) {
- ASSERT(0);
+ if (!xdr_fattr4_fs_locations(xdrs,
+ &gesp->n4g_fslocations))
+ return (FALSE);
}
if (resbmap & FATTR4_HIDDEN_MASK) {
ASSERT(0);
@@ -2253,7 +2410,9 @@ noentries:
static bool_t
xdr_ga_res(XDR *xdrs, GETATTR4res *objp, GETATTR4args *aobjp)
{
+#ifdef INLINE
uint32_t *ptr;
+#endif
bitmap4 resbmap;
uint32_t attrlen;
@@ -2307,11 +2466,13 @@ xdr_ga_res(XDR *xdrs, GETATTR4res *objp, GETATTR4args *aobjp)
}
/* Check to see if the attrs can be inlined and go for it if so */
+#ifdef INLINE
if (!(resbmap & FATTR4_ACL_MASK) &&
(ptr = (uint32_t *)XDR_INLINE(xdrs, attrlen)) != NULL)
return (xdr_ga_fattr_res_inline(ptr, &objp->ga_res,
resbmap, aobjp->attr_request, aobjp->mi, NULL));
else
+#endif
return (xdr_ga_fattr_res(xdrs, &objp->ga_res,
resbmap, aobjp->attr_request, aobjp->mi, NULL));
}
@@ -4300,6 +4461,7 @@ xdr_nfs_resop4_free(XDR *xdrs, nfs_resop4 **arrayp, int len, int decode_len)
{
int i;
nfs_resop4 *array = *arrayp;
+ nfs4_ga_res_t *gr;
/*
* Optimized XDR_FREE only results array
@@ -4319,10 +4481,15 @@ xdr_nfs_resop4_free(XDR *xdrs, nfs_resop4 **arrayp, int len, int decode_len)
case OP_GETATTR:
if (array[i].nfs_resop4_u.opgetattr.status != NFS4_OK)
continue;
- if (array[i].nfs_resop4_u.opgetattr.ga_res.n4g_ext_res)
- kmem_free(array[i].nfs_resop4_u.opgetattr.
- ga_res.n4g_ext_res,
+
+ gr = &array[i].nfs_resop4_u.opgetattr.ga_res;
+ if (gr->n4g_ext_res) {
+ if (gr->n4g_resbmap & FATTR4_FS_LOCATIONS_MASK)
+ (void) xdr_fattr4_fs_locations(xdrs,
+ &gr->n4g_ext_res->n4g_fslocations);
+ kmem_free(gr->n4g_ext_res,
sizeof (struct nfs4_ga_ext_res));
+ }
continue;
case OP_GETFH:
if (array[i].nfs_resop4_u.opgetfh.status != NFS4_OK)
diff --git a/usr/src/uts/common/fs/nfs/nfs_srv.c b/usr/src/uts/common/fs/nfs/nfs_srv.c
index 4fb64c62b1..4d98017403 100644
--- a/usr/src/uts/common/fs/nfs/nfs_srv.c
+++ b/usr/src/uts/common/fs/nfs/nfs_srv.c
@@ -117,6 +117,10 @@ rfs_getattr(fhandle_t *fhp, struct nfsattrstat *ns, struct exportinfo *exi,
/* check for overflows */
if (!error) {
+ /* Lie about the object type for a referral */
+ if (vn_is_nfs_reparse(vp, cr))
+ va.va_type = VLNK;
+
acl_perm(vp, exi, &va, cr);
error = vattr_to_nattr(&va, &ns->ns_attr);
}
@@ -489,6 +493,7 @@ rfs_readlink(fhandle_t *fhp, struct nfsrdlnres *rl, struct exportinfo *exi,
struct vattr va;
struct sockaddr *ca;
char *name = NULL;
+ int is_referral = 0;
vp = nfs_fhtovp(fhp, exi);
if (vp == NULL) {
@@ -515,11 +520,15 @@ rfs_readlink(fhandle_t *fhp, struct nfsrdlnres *rl, struct exportinfo *exi,
return;
}
+ /* We lied about the object type for a referral */
+ if (vn_is_nfs_reparse(vp, cr))
+ is_referral = 1;
+
/*
* XNFS and RFC1094 require us to return ENXIO if argument
* is not a link. BUGID 1138002.
*/
- if (vp->v_type != VLNK) {
+ if (vp->v_type != VLNK && !is_referral) {
VN_RELE(vp);
rl->rl_data = NULL;
rl->rl_status = NFSERR_NXIO;
@@ -531,27 +540,52 @@ rfs_readlink(fhandle_t *fhp, struct nfsrdlnres *rl, struct exportinfo *exi,
*/
rl->rl_data = kmem_alloc(NFS_MAXPATHLEN, KM_SLEEP);
- /*
- * Set up io vector to read sym link data
- */
- iov.iov_base = rl->rl_data;
- iov.iov_len = NFS_MAXPATHLEN;
- uio.uio_iov = &iov;
- uio.uio_iovcnt = 1;
- uio.uio_segflg = UIO_SYSSPACE;
- uio.uio_extflg = UIO_COPY_CACHED;
- uio.uio_loffset = (offset_t)0;
- uio.uio_resid = NFS_MAXPATHLEN;
+ if (is_referral) {
+ char *s;
+ size_t strsz;
+
+ /* Get an artificial symlink based on a referral */
+ s = build_symlink(vp, cr, &strsz);
+ global_svstat_ptr[2][NFS_REFERLINKS].value.ui64++;
+ DTRACE_PROBE2(nfs2serv__func__referral__reflink,
+ vnode_t *, vp, char *, s);
+ if (s == NULL)
+ error = EINVAL;
+ else {
+ error = 0;
+ (void) strlcpy(rl->rl_data, s, NFS_MAXPATHLEN);
+ rl->rl_count = (uint32_t)MIN(strsz, NFS_MAXPATHLEN);
+ kmem_free(s, strsz);
+ }
- /*
- * Do the readlink.
- */
- error = VOP_READLINK(vp, &uio, cr, NULL);
+ } else {
- VN_RELE(vp);
+ /*
+ * Set up io vector to read sym link data
+ */
+ iov.iov_base = rl->rl_data;
+ iov.iov_len = NFS_MAXPATHLEN;
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_segflg = UIO_SYSSPACE;
+ uio.uio_extflg = UIO_COPY_CACHED;
+ uio.uio_loffset = (offset_t)0;
+ uio.uio_resid = NFS_MAXPATHLEN;
+
+ /*
+ * Do the readlink.
+ */
+ error = VOP_READLINK(vp, &uio, cr, NULL);
+
+ rl->rl_count = (uint32_t)(NFS_MAXPATHLEN - uio.uio_resid);
- rl->rl_count = (uint32_t)(NFS_MAXPATHLEN - uio.uio_resid);
- rl->rl_data[rl->rl_count] = '\0';
+ if (!error)
+ rl->rl_data[rl->rl_count] = '\0';
+
+ }
+
+
+ VN_RELE(vp);
ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
name = nfscmd_convname(ca, exi, rl->rl_data,
diff --git a/usr/src/uts/common/fs/nfs/nfs_stats.c b/usr/src/uts/common/fs/nfs/nfs_stats.c
index b125a06d6c..baaf47a82a 100644
--- a/usr/src/uts/common/fs/nfs/nfs_stats.c
+++ b/usr/src/uts/common/fs/nfs/nfs_stats.c
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#include <sys/kstat.h>
#include <sys/zone.h>
@@ -87,6 +85,8 @@ nfsstat_zone_fini_common(zoneid_t zoneid, const char *module, int vers,
static const kstat_named_t svstat_tmpl[] = {
{ "calls", KSTAT_DATA_UINT64 },
{ "badcalls", KSTAT_DATA_UINT64 },
+ { "referrals", KSTAT_DATA_UINT64 },
+ { "referlinks", KSTAT_DATA_UINT64 },
};
/* Points to the global zone server kstat data for all nfs versions */
@@ -108,7 +108,7 @@ nfsstat_zone_init_server(zoneid_t zoneid, kstat_named_t *svstatp[])
for (vers = NFS_VERSION; vers <= NFS_V4; vers++) {
svstatp[vers] = nfsstat_zone_init_common(zoneid, "nfs", vers,
- "nfs_server", svstat_tmpl, sizeof (svstat_tmpl));
+ "nfs_server", svstat_tmpl, sizeof (svstat_tmpl));
if (zoneid == GLOBAL_ZONEID)
global_svstat_ptr[vers] = svstatp[vers];
}
diff --git a/usr/src/uts/common/fs/vnode.c b/usr/src/uts/common/fs/vnode.c
index a42259df93..2f7aa751ad 100644
--- a/usr/src/uts/common/fs/vnode.c
+++ b/usr/src/uts/common/fs/vnode.c
@@ -4441,3 +4441,32 @@ fs_reparse_mark(char *target, vattr_t *vap, xvattr_t *xvattr)
return (0);
}
+
+/*
+ * Function to check whether a symlink is a reparse point.
+ * Return B_TRUE if it is a reparse point, else return B_FALSE
+ */
+boolean_t
+vn_is_reparse(vnode_t *vp, cred_t *cr, caller_context_t *ct)
+{
+ xvattr_t xvattr;
+ xoptattr_t *xoap;
+
+ if ((vp->v_type != VLNK) ||
+ !(vfs_has_feature(vp->v_vfsp, VFSFT_XVATTR)))
+ return (B_FALSE);
+
+ xva_init(&xvattr);
+ xoap = xva_getxoptattr(&xvattr);
+ ASSERT(xoap);
+ XVA_SET_REQ(&xvattr, XAT_REPARSE);
+
+ if (VOP_GETATTR(vp, &xvattr.xva_vattr, 0, cr, ct))
+ return (B_FALSE);
+
+ if ((!(xvattr.xva_vattr.va_mask & AT_XVATTR)) ||
+ (!(XVA_ISSET_RTN(&xvattr, XAT_REPARSE))))
+ return (B_FALSE);
+
+ return (xoap->xoa_reparse ? B_TRUE : B_FALSE);
+}
diff --git a/usr/src/uts/common/nfs/export.h b/usr/src/uts/common/nfs/export.h
index b66c00c389..21d6e9e4f6 100644
--- a/usr/src/uts/common/nfs/export.h
+++ b/usr/src/uts/common/nfs/export.h
@@ -295,6 +295,7 @@ struct charset_cache {
/* Forward declarations */
struct exportinfo;
struct exp_visible;
+struct svc_req;
/*
* Treenodes are used to build tree representing every node which is part
@@ -409,6 +410,7 @@ struct exportinfo {
struct exp_visible *exi_visible;
struct charset_cache *exi_charset;
unsigned exi_volatile_dev:1;
+ unsigned exi_moved:1;
#ifdef VOLATILE_FH_TEST
uint32_t exi_volatile_id;
struct ex_vol_rename *exi_vol_rename;
@@ -512,6 +514,9 @@ extern void export_link(struct exportinfo *);
extern int export_unlink(fsid_t *, fid_t *, vnode_t *,
struct exportinfo **);
extern vnode_t *untraverse(vnode_t *);
+extern int vn_is_nfs_reparse(vnode_t *, cred_t *);
+extern int client_is_downrev(struct svc_req *);
+extern char *build_symlink(vnode_t *, cred_t *, size_t *);
/*
* Functions that handle the NFSv4 server namespace
diff --git a/usr/src/uts/common/nfs/mount.h b/usr/src/uts/common/nfs/mount.h
index 4b5c3adb9c..c2785ce73f 100644
--- a/usr/src/uts/common/nfs/mount.h
+++ b/usr/src/uts/common/nfs/mount.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -31,8 +31,6 @@
#ifndef _NFS_MOUNT_H
#define _NFS_MOUNT_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -157,11 +155,9 @@ struct nfs_args32 {
#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 */
+#define NFSMNT_REFERRAL 0x40000000 /* Is a referral */
-/*
- * This will have to change when we do referrals.
- */
-#define NFSMNT_EPHEMERAL NFSMNT_MIRRORMOUNT
+#define NFSMNT_EPHEMERAL (NFSMNT_MIRRORMOUNT | NFSMNT_REFERRAL)
#ifdef __cplusplus
}
diff --git a/usr/src/uts/common/nfs/nfs.h b/usr/src/uts/common/nfs/nfs.h
index a3aa522944..77e5a397c2 100644
--- a/usr/src/uts/common/nfs/nfs.h
+++ b/usr/src/uts/common/nfs/nfs.h
@@ -884,7 +884,8 @@ extern void rfs_srvrfini(void);
#define NATIVEPATH 0x02 /* Native path, i.e., via mount protocol */
#define SECURITY_QUERY 0x04 /* Security query */
-enum nfs_svccounts {NFS_CALLS, NFS_BADCALLS}; /* index for svstat_ptr */
+/* index for svstat_ptr */
+enum nfs_svccounts {NFS_CALLS, NFS_BADCALLS, NFS_REFERRALS, NFS_REFERLINKS};
/* function defs for NFS kernel */
extern int nfs_waitfor_purge_complete(vnode_t *);
diff --git a/usr/src/uts/common/nfs/nfs4.h b/usr/src/uts/common/nfs/nfs4.h
index eccc885a2d..c72c238f7e 100644
--- a/usr/src/uts/common/nfs/nfs4.h
+++ b/usr/src/uts/common/nfs/nfs4.h
@@ -460,6 +460,7 @@ nvlist_t *rfs4_dss_paths, *rfs4_dss_oldpaths;
* ss_remove - indicates that the rfs4_client_destroy function should
* clean up stable storage file.
* forced_expire - set if the sysadmin has used clear_locks for this client.
+ * no_referrals - set if the client is Solaris and pre-dates referrals
* deleg_revoked - how many delegations have been revoked for this client?
*
* cp_confirmed - this refers to a confirmed client struct that has
@@ -499,6 +500,17 @@ typedef struct rfs4_client {
} rfs4_client_t;
/*
+ * ClntIP struct - holds the diagnosis about whether the client
+ * cannot support referrals. Set to true for old Solaris clients.
+ */
+
+typedef struct rfs4_clntip {
+ rfs4_dbe_t *ri_dbe;
+ struct sockaddr_storage ri_addr;
+ unsigned ri_no_referrals:1;
+} rfs4_clntip_t;
+
+/*
* The openowner contains the client supplied open_owner4 as well as
* the matching sequence id and is used to track the client's usage of
* the open_owner4. Note that a reply is saved here as well for
@@ -775,6 +787,7 @@ extern void rfs4_copy_reply(nfs_resop4 *, nfs_resop4 *);
extern rfs4_client_t *rfs4_findclient(nfs_client_id4 *,
bool_t *, rfs4_client_t *);
extern rfs4_client_t *rfs4_findclient_by_id(clientid4, bool_t);
+extern rfs4_client_t *rfs4_findclient_by_addr(struct sockaddr *);
extern void rfs4_client_rele(rfs4_client_t *);
extern void rfs4_client_close(rfs4_client_t *);
extern void rfs4_client_state_remove(rfs4_client_t *);
@@ -783,6 +796,10 @@ extern void rfs4_update_lease(rfs4_client_t *);
extern bool_t rfs4_lease_expired(rfs4_client_t *);
extern nfsstat4 rfs4_check_clientid(clientid4 *, int);
+/* rfs4_clntip_t handling */
+extern rfs4_clntip_t *rfs4_find_clntip(struct sockaddr *, bool_t *);
+extern void rfs4_invalidate_clntip(struct sockaddr *);
+
/* rfs4_openowner_t handling */
extern rfs4_openowner_t *rfs4_findopenowner(open_owner4 *, bool_t *, seqid4);
extern void rfs4_update_open_sequence(rfs4_openowner_t *);
@@ -1095,6 +1112,7 @@ struct nfs4_svgetit_arg {
/* rdattr_error */
nfsstat4 rdattr_error; /* used for per-entry status */
/* (if rdattr_err) */
+ bool_t is_referral; /* because sometimes we tell lies */
bool_t mntdfid_set;
fattr4_mounted_on_fileid
mounted_on_fileid;
@@ -1302,6 +1320,11 @@ extern void vs_acet_destroy(vsecattr_t *);
extern void vs_ace4_destroy(vsecattr_t *);
extern void vs_aent_destroy(vsecattr_t *);
+extern int vn_find_nfs_record(vnode_t *, nvlist_t **, char **, char **);
+extern int vn_is_nfs_reparse(vnode_t *, cred_t *);
+extern fs_locations4 *fetch_referral(vnode_t *, cred_t *);
+extern char *build_symlink(vnode_t *, cred_t *, size_t *);
+
extern int stateid4_cmp(stateid4 *, stateid4 *);
extern vtype_t nf4_to_vt[];
diff --git a/usr/src/uts/common/nfs/nfs4_attr.h b/usr/src/uts/common/nfs/nfs4_attr.h
index aa28ff9d40..44acf555b4 100644
--- a/usr/src/uts/common/nfs/nfs4_attr.h
+++ b/usr/src/uts/common/nfs/nfs4_attr.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,15 +19,13 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _NFS4_ATTR_H
#define _NFS4_ATTR_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -436,6 +433,7 @@ typedef struct nfs4_ga_ext_res {
* ACL4_SUPPORT_ALARM_ACL
*/
fattr4_aclsupport n4g_aclsupport;
+ fattr4_fs_locations n4g_fslocations;
} nfs4_ga_ext_res_t;
extern bitmap4 rfs4_supported_attrs;
diff --git a/usr/src/uts/common/nfs/nfs4_clnt.h b/usr/src/uts/common/nfs/nfs4_clnt.h
index e0d9852c78..8796b96e0b 100644
--- a/usr/src/uts/common/nfs/nfs4_clnt.h
+++ b/usr/src/uts/common/nfs/nfs4_clnt.h
@@ -46,6 +46,7 @@
#include <sys/avl.h>
#include <sys/list.h>
#include <rpc/auth.h>
+#include <sys/door.h>
#ifdef __cplusplus
extern "C" {
@@ -161,6 +162,8 @@ typedef struct nfs4_delmap_args {
struct clstat4 {
kstat_named_t calls; /* client requests */
kstat_named_t badcalls; /* rpc failures */
+ kstat_named_t referrals; /* referrals */
+ kstat_named_t referlinks; /* referrals as symlinks */
kstat_named_t clgets; /* client handle gets */
kstat_named_t cltoomany; /* client handle cache misses */
#ifdef DEBUG
@@ -302,6 +305,7 @@ typedef enum nfs4_tag_type {
TAG_FSINFO,
TAG_GET_SYMLINK,
TAG_GETATTR,
+ TAG_GETATTR_FSLOCATION,
TAG_INACTIVE,
TAG_LINK,
TAG_LOCK,
@@ -374,6 +378,8 @@ typedef enum nfs4_tag_type {
{0x67657420, 0x736c6e6b, 0x20747874}}, \
{TAG_GETATTR, "getattr", \
{0x67657461, 0x74747220, 0x20202020}}, \
+ {TAG_GETATTR_FSLOCATION, "getattr fslocation", \
+ {0x67657461, 0x74747220, 0x66736c6f}}, \
{TAG_INACTIVE, "inactive", \
{0x696e6163, 0x74697665, 0x20202020}}, \
{TAG_LINK, "link", \
@@ -553,7 +559,8 @@ typedef struct nfs4_open_owner {
/*
* Static server information.
- * These fields are read-only once they are initialized:
+ * These fields are read-only once they are initialized; sv_lock
+ * should be held as writer if they are changed during mount:
* sv_addr
* sv_dhsec
* sv_hostname
@@ -699,7 +706,8 @@ typedef enum {
NR_DELAY,
NR_LOST_LOCK,
NR_LOST_STATE_RQST,
- NR_STALE
+ NR_STALE,
+ NR_MOVED
} nfs4_recov_t;
/*
@@ -709,6 +717,8 @@ typedef enum {
#define NFS4_MSG_MAX 100
extern int nfs4_msg_max;
+#define NFS4_REFERRAL_LOOP_MAX 20
+
typedef enum {
RE_BAD_SEQID,
RE_BADHANDLE,
@@ -729,7 +739,8 @@ typedef enum {
RE_UNEXPECTED_ERRNO,
RE_UNEXPECTED_STATUS,
RE_WRONGSEC,
- RE_LOST_STATE_BAD_OP
+ RE_LOST_STATE_BAD_OP,
+ RE_REFERRAL
} nfs4_event_type_t;
typedef enum {
@@ -1033,6 +1044,10 @@ typedef struct mntinfo4 {
uint_t mi_srvset_cnt; /* increment when changing the nfs4_server_t */
struct nfs4_server *mi_srv; /* backpointer to nfs4_server_t */
+ /*
+ * Referral related info.
+ */
+ int mi_vfs_referral_loop_cnt;
} mntinfo4_t;
/*
@@ -1085,7 +1100,7 @@ typedef struct mntinfo4 {
#define MI4_ACL 0x2000
/* MI4_MIRRORMOUNT is also defined in nfsstat.c */
#define MI4_MIRRORMOUNT 0x4000
-/* 0x8000 is available */
+#define MI4_REFERRAL 0x8000
/* 0x10000 is available */
#define MI4_NOPRINT 0x20000
#define MI4_DIRECTIO 0x40000
@@ -1103,11 +1118,7 @@ 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 MI4_EPHEMERAL (MI4_MIRRORMOUNT | MI4_REFERRAL)
#define INTR4(vp) (VTOMI4(vp)->mi_flags & MI4_INT)
@@ -1128,6 +1139,7 @@ typedef struct mntinfo4 {
#define MI4R_SRV_REBOOT 0x20 /* server has rebooted */
#define MI4R_LOST_STATE 0x40
#define MI4R_BAD_SEQID 0x80
+#define MI4R_MOVED 0x100
#define MI4_HOLD(mi) { \
mi_hold(mi); \
@@ -1492,6 +1504,7 @@ extern void nfs4_write_error(vnode_t *, int, cred_t *);
extern void nfs4_lockcompletion(vnode_t *, int);
extern bool_t nfs4_map_lost_lock_conflict(vnode_t *);
extern int vtodv(vnode_t *, vnode_t **, cred_t *, bool_t);
+extern int vtoname(vnode_t *, char *, ssize_t);
extern void nfs4open_confirm(vnode_t *, seqid4*, stateid4 *, cred_t *,
bool_t, bool_t *, nfs4_open_owner_t *, bool_t,
nfs4_error_t *, int *);
@@ -1502,6 +1515,9 @@ extern void nfs4_free_args(struct nfs_args *);
extern void mi_hold(mntinfo4_t *);
extern void mi_rele(mntinfo4_t *);
+extern vnode_t *find_referral_stubvp(vnode_t *, char *, cred_t *);
+extern int nfs4_setup_referral(vnode_t *, char *, vnode_t **, cred_t *);
+
extern sec_data_t *copy_sec_data(sec_data_t *);
extern gss_clntdata_t *copy_sec_data_gss(gss_clntdata_t *);
@@ -1969,7 +1985,8 @@ extern int nfs4_needs_recovery(nfs4_error_t *, bool_t, vfs_t *);
extern int nfs4_recov_marks_dead(nfsstat4);
extern bool_t nfs4_start_recovery(nfs4_error_t *, struct mntinfo4 *,
vnode_t *, vnode_t *, stateid4 *,
- nfs4_lost_rqst_t *, nfs_opnum4, nfs4_bseqid_entry_t *);
+ nfs4_lost_rqst_t *, nfs_opnum4, nfs4_bseqid_entry_t *,
+ vnode_t *, char *);
extern int nfs4_start_op(struct mntinfo4 *, vnode_t *, vnode_t *,
nfs4_recov_state_t *);
extern void nfs4_end_op(struct mntinfo4 *, vnode_t *, vnode_t *,
@@ -1991,14 +2008,18 @@ extern char *nfs4_recov_action_to_str(nfs4_recov_t);
* of whether or not the code in _unlock is to be ran.
*/
extern void nfs4_ephemeral_umount_activate(mntinfo4_t *,
- bool_t *, bool_t *, nfs4_ephemeral_tree_t **);
+ bool_t *, nfs4_ephemeral_tree_t **);
extern int nfs4_ephemeral_umount(mntinfo4_t *, int, cred_t *,
- bool_t *, bool_t *, nfs4_ephemeral_tree_t **);
-extern void nfs4_ephemeral_umount_unlock(bool_t *, bool_t *,
+ bool_t *, nfs4_ephemeral_tree_t **);
+extern void nfs4_ephemeral_umount_unlock(bool_t *,
nfs4_ephemeral_tree_t **);
extern int nfs4_record_ephemeral_mount(mntinfo4_t *mi, vnode_t *mvp);
+extern int nfs4_callmapid(utf8string *, struct nfs_fsl_info *);
+extern int nfs4_fetch_locations(mntinfo4_t *, struct nfs4_sharedfh *,
+ char *, cred_t *, nfs4_ga_res_t *, COMPOUND4res_clnt *, bool_t);
+
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 *);
@@ -2138,6 +2159,10 @@ extern char *fn_path(nfs4_fname_t *);
extern void fn_move(nfs4_fname_t *, nfs4_fname_t *, char *);
extern nfs4_fname_t *fn_parent(nfs4_fname_t *);
+/* Referral Support */
+extern int nfs4_process_referral(mntinfo4_t *, nfs4_sharedfh_t *, char *,
+ cred_t *, nfs4_ga_res_t *, COMPOUND4res_clnt *, struct nfs_fsl_info *);
+
#endif
/*
diff --git a/usr/src/uts/common/nfs/nfs4_kprot.h b/usr/src/uts/common/nfs/nfs4_kprot.h
index 3e35d29f25..be30bed10c 100644
--- a/usr/src/uts/common/nfs/nfs4_kprot.h
+++ b/usr/src/uts/common/nfs/nfs4_kprot.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -227,6 +227,15 @@ struct fs_locations4 {
};
typedef struct fs_locations4 fs_locations4;
+struct nfs_fsl_info {
+ uint_t netbuf_len;
+ uint_t netnm_len;
+ uint_t knconf_len;
+ char *netname;
+ struct netbuf *addr;
+ struct knetconfig *knconf;
+};
+
/*
* ACL support
*/
@@ -590,6 +599,7 @@ struct nfs_client_id4 {
verifier4 verifier;
uint_t id_len;
char *id_val;
+ struct sockaddr *cl_addr;
};
typedef struct nfs_client_id4 nfs_client_id4;
@@ -1636,6 +1646,12 @@ extern bool_t xdr_CB_COMPOUND4args_clnt(XDR *, CB_COMPOUND4args *);
extern bool_t xdr_CB_COMPOUND4args_srv(XDR *, CB_COMPOUND4args *);
extern bool_t xdr_CB_COMPOUND4res(XDR *, CB_COMPOUND4res *);
+/*
+ * xdr for referrrals upcall
+ */
+extern bool_t xdr_knetconfig(XDR *, struct knetconfig *);
+extern bool_t xdr_nfs_fsl_info(XDR *, struct nfs_fsl_info *);
+
#ifdef __cplusplus
}
diff --git a/usr/src/uts/common/nfs/nfsid_map.h b/usr/src/uts/common/nfs/nfsid_map.h
index c617695245..197970d4d2 100644
--- a/usr/src/uts/common/nfs/nfsid_map.h
+++ b/usr/src/uts/common/nfs/nfsid_map.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,15 +19,13 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _NFSID_MAP_H
#define _NFSID_MAP_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifndef _KERNEL
#include <stddef.h>
#endif
@@ -59,6 +56,7 @@ extern "C" {
#define NFSMAPID_UID_STR 2
#define NFSMAPID_STR_GID 3
#define NFSMAPID_GID_STR 4
+#define NFSMAPID_SRV_NETINFO 5
/*
* We are passing in arguments in a variable length struct
@@ -145,6 +143,35 @@ typedef struct mapid_res mapid_res_t;
#define MAPID_RES_LEN(str_length) \
((offsetof(mapid_res_t, str[0]) + 1 + (str_length) + 7) & ~ 7)
+/*
+ * Support for referral name resolution by the NFS client
+ */
+typedef struct refd_door_args {
+ int cmd; /* NFS4_FS_LOCATIONS/NFS4_SRV_NETINFO */
+ int xdr_len; /* Length of xdr Buffer */
+ char xdr_arg[1]; /* Buffer holding xdr encoded data */
+} refd_door_args_t;
+
+typedef struct refd_door_res {
+ int res_status;
+ int xdr_len;
+ char xdr_res[1];
+} refd_door_res_t;
+
+#ifdef _SYSCALL32
+typedef struct refd_door_args32 {
+ int32_t cmd;
+ int32_t xdr_len;
+ char xdr_arg[1];
+} refd_door_args32_t;
+
+typedef struct refd_door_res32 {
+ int32_t res_status;
+ int32_t xdr_len;
+ char xdr_res[1];
+} refd_door_res32_t;
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/uts/common/nfs/rnode4.h b/usr/src/uts/common/nfs/rnode4.h
index a8d6c5ac71..61ea044ca5 100644
--- a/usr/src/uts/common/nfs/rnode4.h
+++ b/usr/src/uts/common/nfs/rnode4.h
@@ -41,7 +41,8 @@ extern "C" {
typedef enum nfs4_stub_type {
NFS4_STUB_NONE,
- NFS4_STUB_MIRRORMOUNT
+ NFS4_STUB_MIRRORMOUNT,
+ NFS4_STUB_REFERRAL
} nfs4_stub_type_t;
typedef enum nfs4_access_type {
@@ -333,7 +334,7 @@ typedef struct rnode4 {
/* sv_fsid (servinfo4_t) to see why */
/* stub type was set */
nfs4_stub_type_t r_stub_type;
- /* e.g. mirror-mount */
+ /* e.g. mirror-mount or referral */
uint_t r_inmap; /* to serialize read/write and mmap */
} rnode4_t;
@@ -371,6 +372,7 @@ typedef struct rnode4 {
#define RP_ISSTUB(rp) (((rp)->r_stub_type != NFS4_STUB_NONE))
#define RP_ISSTUB_MIRRORMOUNT(rp) ((rp)->r_stub_type == NFS4_STUB_MIRRORMOUNT)
+#define RP_ISSTUB_REFERRAL(rp) ((rp)->r_stub_type == NFS4_STUB_REFERRAL)
/*
* Open file instances.
@@ -415,6 +417,7 @@ extern vnode_t *makenfs4node_by_fh(nfs4_sharedfh_t *, nfs4_sharedfh_t *,
extern nfs4_opinst_t *r4mkopenlist(struct mntinfo4 *);
extern void r4releopenlist(nfs4_opinst_t *);
+extern int r4find_by_fsid(mntinfo4_t *, fattr4_fsid *);
/* Access cache calls */
extern nfs4_access_type_t nfs4_access_check(rnode4_t *, uint32_t, cred_t *);
@@ -499,6 +502,7 @@ 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_referral(rnode4_t *);
extern void r4_stub_none(rnode4_t *);
#ifdef DEBUG
diff --git a/usr/src/uts/common/sys/mkdev.h b/usr/src/uts/common/sys/mkdev.h
index 8969362360..0b0f7deb64 100644
--- a/usr/src/uts/common/sys/mkdev.h
+++ b/usr/src/uts/common/sys/mkdev.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 1997 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -30,8 +29,6 @@
#ifndef _SYS_MKDEV_H
#define _SYS_MKDEV_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#ifdef __cplusplus
@@ -54,10 +51,11 @@ extern "C" {
#define MAXMAJ32 0x3ffful /* SVR4 max major value */
#define MAXMIN32 0x3fffful /* SVR4 max minor value */
-#ifdef _LP64
-
#define NBITSMAJOR64 32 /* # of major device bits in 64-bit Solaris */
#define NBITSMINOR64 32 /* # of minor device bits in 64-bit Solaris */
+
+#ifdef _LP64
+
#define MAXMAJ64 0xfffffffful /* max major value */
#define MAXMIN64 0xfffffffful /* max minor value */
diff --git a/usr/src/uts/common/sys/vnode.h b/usr/src/uts/common/sys/vnode.h
index cdf4fe9b68..97504aabf3 100644
--- a/usr/src/uts/common/sys/vnode.h
+++ b/usr/src/uts/common/sys/vnode.h
@@ -1239,6 +1239,7 @@ vnode_t *specvp(struct vnode *vp, dev_t dev, vtype_t type, struct cred *cr);
vnode_t *makespecvp(dev_t dev, vtype_t type);
vn_vfslocks_entry_t *vn_vfslocks_getlock(void *);
void vn_vfslocks_rele(vn_vfslocks_entry_t *);
+boolean_t vn_is_reparse(vnode_t *, cred_t *, caller_context_t *);
void vn_copypath(struct vnode *src, struct vnode *dst);
void vn_setpath_str(struct vnode *vp, const char *str, size_t len);