summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcel Telka <marcel@telka.sk>2016-11-29 16:41:54 +0100
committerDan McDonald <danmcd@omniti.com>2016-11-29 11:08:04 -0500
commit4a6959565df1e2af817732421764a9da2f446da9 (patch)
treef795337988e01775590bdd7b3e58cb324b2192ee
parent4d86c0eab246bdfddc2dd52410ba808433bd6266 (diff)
downloadillumos-joyent-4a6959565df1e2af817732421764a9da2f446da9.tar.gz
6911 nfs4: unexpected permission denied
Reviewed by: Simon Klinkert <simon.klinkert@gmail.com> Reviewed by: Igor Kozhukhov <igor@dilos.org> Approved by: Dan McDonald <danmcd@omniti.com>
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_client.c11
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_srv_attr.c123
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_srv_ns.c213
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_srv_readdir.c26
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_vnops.c4
-rw-r--r--usr/src/uts/common/fs/nfs/nfs_export.c27
-rw-r--r--usr/src/uts/common/nfs/export.h9
7 files changed, 284 insertions, 129 deletions
diff --git a/usr/src/uts/common/fs/nfs/nfs4_client.c b/usr/src/uts/common/fs/nfs/nfs4_client.c
index 7bfa46e1fb..5438038105 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_client.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_client.c
@@ -184,7 +184,6 @@ nfs4_validate_caches(vnode_t *vp, cred_t *cr)
return (0);
}
- gar.n4g_va.va_mask = AT_ALL;
return (nfs4_getattr_otw(vp, &gar, cr, 0));
}
@@ -582,6 +581,16 @@ nfs4_attr_cache(vnode_t *vp, nfs4_ga_res_t *garp,
rp->r_attr.va_ctime.tv_nsec !=
vap->va_ctime.tv_nsec)
ctime_changed = 1;
+
+ /*
+ * If the change attribute was not provided by server
+ * or it differs, then flush all caches.
+ */
+ if (!garp->n4g_change_valid ||
+ rp->r_change != garp->n4g_change) {
+ mtime_changed = 1;
+ ctime_changed = 1;
+ }
} else {
writemodify_set = B_TRUE;
}
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 855cd8cd92..7240faa356 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_srv_attr.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_srv_attr.c
@@ -209,7 +209,7 @@ rfs4_attr_init()
/* ARGSUSED */
static int
rfs4_fattr4_supported_attrs(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
@@ -251,7 +251,7 @@ static nfs_ftype4 vt_to_nf4[] = {
/* ARGSUSED */
static int
rfs4_fattr4_type(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
@@ -357,7 +357,7 @@ fattr4_get_fh_expire_type(struct exportinfo *exi, uint32_t *fh_expire_typep)
/* ARGSUSED */
static int
rfs4_fattr4_fh_expire_type(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
uint32_t fh_expire_type;
int error = 0;
@@ -396,6 +396,7 @@ fattr4_get_change(struct nfs4_svgetit_arg *sarg, fattr4_change *changep)
struct compound_state *cs = sarg->cs;
vnode_t *vp = cs->vp;
nfsstat4 status;
+ timespec_t vis_change;
if ((vap->va_mask & AT_CTIME) == 0) {
if (sarg->rdattr_error && (vp == NULL)) {
@@ -408,14 +409,22 @@ fattr4_get_change(struct nfs4_svgetit_arg *sarg, fattr4_change *changep)
if (status != NFS4_OK)
return (geterrno4(status));
}
- NFS4_SET_FATTR4_CHANGE(*changep, vap->va_ctime)
+ NFS4_SET_FATTR4_CHANGE(*changep, vap->va_ctime);
+
+ if (nfs_visible_change(cs->exi, vp, &vis_change)) {
+ fattr4_change visch;
+ NFS4_SET_FATTR4_CHANGE(visch, vis_change);
+ if (visch > *changep)
+ *changep = visch;
+ }
+
return (0);
}
/* ARGSUSED */
static int
rfs4_fattr4_change(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
fattr4_change change;
@@ -453,7 +462,7 @@ rfs4_fattr4_change(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_size(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
@@ -490,7 +499,7 @@ rfs4_fattr4_size(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_link_support(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
@@ -525,7 +534,7 @@ rfs4_fattr4_link_support(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_symlink_support(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
@@ -556,7 +565,7 @@ rfs4_fattr4_symlink_support(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_named_attr(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
ulong_t val;
@@ -626,7 +635,7 @@ rfs4_fattr4_named_attr(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_fsid(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
int *pmaj = (int *)&na->fsid.major;
@@ -681,7 +690,7 @@ rfs4_fattr4_fsid(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_unique_handles(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
/*
* XXX
@@ -718,7 +727,7 @@ rfs4_fattr4_unique_handles(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_lease_time(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
@@ -749,7 +758,7 @@ rfs4_fattr4_lease_time(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_rdattr_error(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
@@ -798,7 +807,7 @@ rfs4fhcmp(nfs_fh4 *wirefh, nfs_fh4 *srvfh)
/* ARGSUSED */
static int
rfs4_fattr4_filehandle(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
nfs_fh4 *fh;
@@ -861,7 +870,7 @@ rfs4_fattr4_filehandle(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_acl(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
vsecattr_t vs_native, vs_ace4;
@@ -1047,7 +1056,7 @@ rfs4_fattr4_acl(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_aclsupport(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
@@ -1079,7 +1088,7 @@ rfs4_fattr4_aclsupport(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_archive(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
return (ENOTSUP);
}
@@ -1087,7 +1096,7 @@ rfs4_fattr4_archive(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_cansettime(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
@@ -1125,7 +1134,7 @@ rfs4_fattr4_cansettime(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_case_insensitive(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
@@ -1159,7 +1168,7 @@ rfs4_fattr4_case_insensitive(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_case_preserving(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
@@ -1194,7 +1203,7 @@ rfs4_fattr4_case_preserving(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_chown_restricted(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
ulong_t val;
@@ -1244,7 +1253,7 @@ rfs4_fattr4_chown_restricted(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_fileid(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
@@ -1352,7 +1361,7 @@ rfs4_get_mntdfileid(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg)
/* ARGSUSED */
static int
rfs4_fattr4_mounted_on_fileid(nfs4_attr_cmd_t cmd,
- struct nfs4_svgetit_arg *sarg, union nfs4_attr_u *na)
+ struct nfs4_svgetit_arg *sarg, union nfs4_attr_u *na)
{
int error = 0;
@@ -1391,7 +1400,7 @@ rfs4_fattr4_mounted_on_fileid(nfs4_attr_cmd_t cmd,
/* ARGSUSED */
static int
rfs4_fattr4_files_avail(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
@@ -1431,7 +1440,7 @@ rfs4_fattr4_files_avail(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_files_free(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
@@ -1471,7 +1480,7 @@ rfs4_fattr4_files_free(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_files_total(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
@@ -1571,7 +1580,7 @@ rfs4_free_fs_locations4(fs_locations4 *fsls4)
/* ARGSUSED */
static int
rfs4_fattr4_fs_locations(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
fs_locations4 *fsl;
@@ -1617,7 +1626,7 @@ rfs4_fattr4_fs_locations(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_hidden(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
return (ENOTSUP);
}
@@ -1625,7 +1634,7 @@ rfs4_fattr4_hidden(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_homogeneous(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
@@ -1659,7 +1668,7 @@ rfs4_fattr4_homogeneous(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_maxfilesize(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
ulong_t val;
@@ -1737,7 +1746,7 @@ rfs4_fattr4_maxfilesize(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_maxlink(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
ulong_t val;
@@ -1784,7 +1793,7 @@ rfs4_fattr4_maxlink(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_maxname(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
ulong_t val;
@@ -1831,7 +1840,7 @@ rfs4_fattr4_maxname(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_maxread(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
@@ -1865,7 +1874,7 @@ rfs4_fattr4_maxread(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_maxwrite(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
@@ -1899,7 +1908,7 @@ rfs4_fattr4_maxwrite(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_mimetype(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
return (ENOTSUP);
}
@@ -1907,7 +1916,7 @@ rfs4_fattr4_mimetype(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_mode(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
@@ -1950,7 +1959,7 @@ rfs4_fattr4_mode(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_no_trunc(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
@@ -1984,7 +1993,7 @@ rfs4_fattr4_no_trunc(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_numlinks(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
@@ -2024,7 +2033,7 @@ rfs4_fattr4_numlinks(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_owner(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
uid_t uid;
@@ -2136,7 +2145,7 @@ rfs4_fattr4_owner(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_owner_group(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
gid_t gid;
@@ -2252,7 +2261,7 @@ rfs4_fattr4_owner_group(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_quota_avail_hard(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
return (ENOTSUP);
}
@@ -2260,7 +2269,7 @@ rfs4_fattr4_quota_avail_hard(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_quota_avail_soft(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
return (ENOTSUP);
}
@@ -2268,7 +2277,7 @@ rfs4_fattr4_quota_avail_soft(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_quota_used(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
return (ENOTSUP);
}
@@ -2276,7 +2285,7 @@ rfs4_fattr4_quota_used(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_rawdev(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
@@ -2320,7 +2329,7 @@ rfs4_fattr4_rawdev(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_space_avail(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
@@ -2367,7 +2376,7 @@ rfs4_fattr4_space_avail(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_space_free(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
@@ -2414,7 +2423,7 @@ rfs4_fattr4_space_free(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_space_total(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
@@ -2461,7 +2470,7 @@ rfs4_fattr4_space_total(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_space_used(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
@@ -2502,7 +2511,7 @@ rfs4_fattr4_space_used(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_system(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
return (ENOTSUP);
}
@@ -2510,7 +2519,7 @@ rfs4_fattr4_system(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_time_access(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
timestruc_t atime;
@@ -2557,7 +2566,7 @@ rfs4_fattr4_time_access(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_time_access_set(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
settime4 *ta;
@@ -2601,7 +2610,7 @@ rfs4_fattr4_time_access_set(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_time_backup(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
return (ENOTSUP);
}
@@ -2609,7 +2618,7 @@ rfs4_fattr4_time_backup(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_time_create(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
return (ENOTSUP);
}
@@ -2617,7 +2626,7 @@ rfs4_fattr4_time_create(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_time_delta(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
@@ -2653,7 +2662,7 @@ rfs4_fattr4_time_delta(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_time_metadata(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
timestruc_t ctime;
@@ -2698,7 +2707,7 @@ rfs4_fattr4_time_metadata(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_time_modify(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
timestruc_t mtime;
@@ -2745,7 +2754,7 @@ rfs4_fattr4_time_modify(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/* ARGSUSED */
static int
rfs4_fattr4_time_modify_set(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
- union nfs4_attr_u *na)
+ union nfs4_attr_u *na)
{
int error = 0;
settime4 *tm;
diff --git a/usr/src/uts/common/fs/nfs/nfs4_srv_ns.c b/usr/src/uts/common/fs/nfs/nfs4_srv_ns.c
index ce0c9485a6..26839633df 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_srv_ns.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_srv_ns.c
@@ -143,7 +143,7 @@ nfs4_vget_pseudo(struct exportinfo *exi, vnode_t **vpp, fid_t *fidp)
*/
struct exportinfo *
pseudo_exportfs(vnode_t *vp, fid_t *fid, struct exp_visible *vis_head,
- struct exportdata *exdata)
+ struct exportdata *exdata)
{
struct exportinfo *exi;
struct exportdata *kex;
@@ -445,8 +445,12 @@ more_visible(struct exportinfo *exi, treenode_t *tree_head)
* list just assign the entire supplied list.
*/
if (exi->exi_visible == NULL) {
- tree_add_child(exi->exi_tree, tree_head);
+ tree_add_child(connect_point, tree_head);
exi->exi_visible = vis_head;
+
+ /* Update the change timestamp */
+ tree_update_change(connect_point, &vis_head->vis_change);
+
return;
}
@@ -503,6 +507,11 @@ more_visible(struct exportinfo *exi, treenode_t *tree_head)
connect_point = child;
} else { /* Branching */
tree_add_child(connect_point, curr);
+
+ /* Update the change timestamp */
+ tree_update_change(connect_point,
+ &curr->tree_vis->vis_change);
+
connect_point = NULL;
}
}
@@ -611,15 +620,17 @@ treeclimb_export(struct exportinfo *exip)
fid_t fid;
int error;
int exportdir;
- struct exportinfo *exi = NULL;
struct exportinfo *new_exi = exip;
struct exp_visible *visp;
struct exp_visible *vis_head = NULL;
struct vattr va;
treenode_t *tree_head = NULL;
+ timespec_t now;
ASSERT(RW_WRITE_HELD(&exported_lock));
+ gethrestime(&now);
+
vp = exip->exi_vp;
VN_HOLD(vp);
exportdir = 1;
@@ -632,36 +643,33 @@ treeclimb_export(struct exportinfo *exip)
if (error)
break;
- if (! exportdir) {
- /*
- * Check if this exportroot is a VROOT dir. If so,
- * then attach the pseudonodes. If not, then
- * continue .. traversal until we hit a VROOT
- * export (pseudo or real).
- */
- exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp);
- if (exi != NULL && vp->v_flag & VROOT) {
- /*
- * Found an export info
- *
- * Extend the list of visible
- * directories whether it's a pseudo
- * or a real export.
- */
- more_visible(exi, tree_head);
- break; /* and climb no further */
- }
- }
-
/*
- * If at the root of the filesystem, need
- * to traverse across the mountpoint
- * and continue the climb on the mounted-on
- * filesystem.
+ * The root of the file system needs special handling
*/
if (vp->v_flag & VROOT) {
-
if (! exportdir) {
+ struct exportinfo *exi;
+
+ /*
+ * Check if this VROOT dir is already exported.
+ * If so, then attach the pseudonodes. If not,
+ * then continue .. traversal until we hit a
+ * VROOT export (pseudo or real).
+ */
+ exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid,
+ vp);
+ if (exi != NULL) {
+ /*
+ * Found an export info
+ *
+ * Extend the list of visible
+ * directories whether it's a pseudo
+ * or a real export.
+ */
+ more_visible(exi, tree_head);
+ break; /* and climb no further */
+ }
+
/*
* Found the root directory of a filesystem
* that isn't exported. Need to export
@@ -678,13 +686,21 @@ treeclimb_export(struct exportinfo *exip)
/*
* If sharing "/", new_exi is shared exportinfo
* (exip). Otherwise, new_exi is exportinfo
- * created in pseudo_exportfs() above.
+ * created by pseudo_exportfs() above.
*/
- ns_root = tree_prepend_node(tree_head, 0,
+ ns_root = tree_prepend_node(tree_head, NULL,
new_exi);
+
+ /* Update the change timestamp */
+ tree_update_change(ns_root, &now);
+
break;
}
+ /*
+ * Traverse across the mountpoint and continue the
+ * climb on the mounted-on filesystem.
+ */
vp = untraverse(vp);
exportdir = 0;
continue;
@@ -711,10 +727,10 @@ treeclimb_export(struct exportinfo *exip)
visp->vis_exported = exportdir;
visp->vis_secinfo = NULL;
visp->vis_seccnt = 0;
+ visp->vis_change = now; /* structure copy */
visp->vis_next = vis_head;
vis_head = visp;
-
/*
* Will set treenode's pointer to exportinfo to
* 1. shared exportinfo (exip) - if first visit here
@@ -764,7 +780,7 @@ treeclimb_export(struct exportinfo *exip)
/* Connect unconnected exportinfo, if there is any. */
if (new_exi && new_exi != exip)
- tree_head = tree_prepend_node(tree_head, 0, new_exi);
+ tree_head = tree_prepend_node(tree_head, NULL, new_exi);
while (tree_head) {
treenode_t *t2 = tree_head;
@@ -798,6 +814,7 @@ void
treeclimb_unexport(struct exportinfo *exip)
{
treenode_t *tnode, *old_nd;
+ treenode_t *connect_point = NULL;
ASSERT(RW_WRITE_HELD(&exported_lock));
@@ -808,25 +825,25 @@ treeclimb_unexport(struct exportinfo *exip)
*/
tnode->tree_exi = NULL;
- if (tnode->tree_vis) /* system root has tree_vis == NULL */
+ if (tnode->tree_vis != NULL) /* system root has tree_vis == NULL */
tnode->tree_vis->vis_exported = 0;
- while (tnode) {
+ while (tnode != NULL) {
/* Stop at VROOT node which is exported or has child */
if (TREE_ROOT(tnode) &&
- (TREE_EXPORTED(tnode) || tnode->tree_child_first))
+ (TREE_EXPORTED(tnode) || tnode->tree_child_first != NULL))
break;
/* Release pseudo export if it has no child */
if (TREE_ROOT(tnode) && !TREE_EXPORTED(tnode) &&
- tnode->tree_child_first == 0) {
+ tnode->tree_child_first == NULL) {
export_unlink(tnode->tree_exi);
exi_rele(tnode->tree_exi);
}
/* Release visible in parent's exportinfo */
- if (tnode->tree_vis)
+ if (tnode->tree_vis != NULL)
less_visible(vis2exi(tnode), tnode->tree_vis);
/* Continue with parent */
@@ -834,9 +851,16 @@ treeclimb_unexport(struct exportinfo *exip)
tnode = tnode->tree_parent;
/* Remove itself, if this is a leaf and non-exported node */
- if (old_nd->tree_child_first == NULL && !TREE_EXPORTED(old_nd))
+ if (old_nd->tree_child_first == NULL &&
+ !TREE_EXPORTED(old_nd)) {
tree_remove_node(old_nd);
+ connect_point = tnode;
+ }
}
+
+ /* Update the change timestamp */
+ if (connect_point != NULL)
+ tree_update_change(connect_point, NULL);
}
/*
@@ -928,7 +952,7 @@ has_visible(struct exportinfo *exi, vnode_t *vp)
fid_t fid;
bool_t vp_is_exported;
- vp_is_exported = VN_CMP(vp, exi->exi_vp);
+ vp_is_exported = VN_CMP(vp, exi->exi_vp);
/*
* An exported root vnode has a sub-dir shared if it has a visible list.
@@ -1110,10 +1134,9 @@ nfs_exported(struct exportinfo *exi, vnode_t *vp)
* skips . and .. entries.
*/
int
-nfs_visible_inode(struct exportinfo *exi, ino64_t ino, int *expseudo)
+nfs_visible_inode(struct exportinfo *exi, ino64_t ino,
+ struct exp_visible **visp)
{
- struct exp_visible *visp;
-
/*
* Only a PSEUDO node has a visible list or an exported VROOT
* node may have a visible list.
@@ -1121,12 +1144,108 @@ nfs_visible_inode(struct exportinfo *exi, ino64_t ino, int *expseudo)
if (! PSEUDO(exi))
exi = get_root_export(exi);
- for (visp = exi->exi_visible; visp; visp = visp->vis_next)
- if ((u_longlong_t)ino == visp->vis_ino) {
- *expseudo = visp->vis_exported;
+ for (*visp = exi->exi_visible; *visp != NULL; *visp = (*visp)->vis_next)
+ if ((u_longlong_t)ino == (*visp)->vis_ino) {
return (1);
}
- *expseudo = 0;
return (0);
}
+
+/*
+ * The change attribute value of the root of nfs pseudo namespace.
+ *
+ * The ns_root_change is protected by exported_lock because all of the treenode
+ * operations are protected by exported_lock too.
+ */
+static timespec_t ns_root_change;
+
+/*
+ * Get the change attribute from visible and returns TRUE.
+ * If the change value is not available returns FALSE.
+ */
+bool_t
+nfs_visible_change(struct exportinfo *exi, vnode_t *vp, timespec_t *change)
+{
+ struct exp_visible *visp;
+ fid_t fid;
+ treenode_t *node;
+
+ /*
+ * First check to see if vp is export root.
+ */
+ if (VN_CMP(vp, exi->exi_vp))
+ goto exproot;
+
+ /*
+ * Only a PSEUDO node has a visible list or an exported VROOT
+ * node may have a visible list.
+ */
+ if (!PSEUDO(exi))
+ exi = get_root_export(exi);
+
+ /* Get the fid of the vnode */
+ bzero(&fid, sizeof (fid));
+ fid.fid_len = MAXFIDSZ;
+ if (vop_fid_pseudo(vp, &fid) != 0)
+ return (FALSE);
+
+ /*
+ * We can't trust VN_CMP() above because of LOFS.
+ * Even though VOP_CMP will do the right thing for LOFS
+ * objects, VN_CMP will short circuit out early when the
+ * vnode ops ptrs are different. Just in case we're dealing
+ * with LOFS, compare exi_fid/fsid here.
+ */
+ if (EQFID(&exi->exi_fid, &fid) &&
+ EQFSID(&exi->exi_fsid, &vp->v_vfsp->vfs_fsid))
+ goto exproot;
+
+ /* See if it matches any fid in the visible list */
+ for (visp = exi->exi_visible; visp; visp = visp->vis_next) {
+ if (EQFID(&fid, &visp->vis_fid)) {
+ *change = visp->vis_change;
+ return (TRUE);
+ }
+ }
+
+ return (FALSE);
+
+exproot:
+ /* The VROOT export have its visible available through treenode */
+ node = exi->exi_tree;
+ if (node != ns_root) {
+ ASSERT(node->tree_vis != NULL);
+ *change = node->tree_vis->vis_change;
+ } else {
+ ASSERT(node->tree_vis == NULL);
+ *change = ns_root_change;
+ }
+
+ return (TRUE);
+}
+
+/*
+ * Update the change attribute value for a particular treenode. The change
+ * attribute value is stored in the visible attached to the treenode, or in the
+ * ns_root_change.
+ *
+ * If the change value is not supplied, the current time is used.
+ */
+void
+tree_update_change(treenode_t *tnode, timespec_t *change)
+{
+ timespec_t *vis_change;
+
+ ASSERT(tnode != NULL);
+ ASSERT((tnode != ns_root && tnode->tree_vis != NULL) ||
+ (tnode == ns_root && tnode->tree_vis == NULL));
+
+ vis_change = tnode == ns_root ? &ns_root_change
+ : &tnode->tree_vis->vis_change;
+
+ if (change != NULL)
+ *vis_change = *change;
+ else
+ gethrestime(vis_change);
+}
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 276d3b4f19..01c76cb203 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_srv_readdir.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_srv_readdir.c
@@ -104,8 +104,8 @@ static nfs_ftype4 vt_to_nf4[] = {
int
nfs4_readdir_getvp(vnode_t *dvp, char *d_name, vnode_t **vpp,
- struct exportinfo **exi, struct svc_req *req,
- struct compound_state *cs, int expseudo)
+ struct exportinfo **exi, struct svc_req *req, struct compound_state *cs,
+ int expseudo)
{
int error;
int ismntpt;
@@ -382,8 +382,8 @@ rfs4_get_sb_encode(vfs_t *vfsp, rfs4_sb_encode_t *psbe)
*/
/* ARGSUSED */
void
-rfs4_op_readdir(nfs_argop4 *argop, nfs_resop4 *resop,
- struct svc_req *req, struct compound_state *cs)
+rfs4_op_readdir(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
+ struct compound_state *cs)
{
READDIR4args *args = &argop->nfs_argop4_u.opreaddir;
READDIR4res *resp = &resop->nfs_resop4_u.opreaddir;
@@ -409,7 +409,7 @@ rfs4_op_readdir(nfs_argop4 *argop, nfs_resop4 *resop,
struct uio uio;
int tsize;
int check_visible;
- int expseudo = 0;
+ struct exp_visible *visp;
uint32_t *ptr, *ptr_redzone;
uint32_t *beginning_ptr;
@@ -687,8 +687,8 @@ readagain:
for (dp = (struct dirent64 *)rddir_data;
!no_space && rddir_result_size > 0; dp = nextdp(dp)) {
- /* reset expseudo */
- expseudo = 0;
+ /* reset visp */
+ visp = NULL;
if (vp) {
VN_RELE(vp);
@@ -707,7 +707,7 @@ readagain:
}
if (check_visible &&
- !nfs_visible_inode(cs->exi, dp->d_ino, &expseudo)) {
+ !nfs_visible_inode(cs->exi, dp->d_ino, &visp)) {
rddir_next_offset = dp->d_off;
continue;
}
@@ -724,7 +724,8 @@ readagain:
goto reencode_attrs;
error = nfs4_readdir_getvp(dvp, dp->d_name,
- &vp, &newexi, req, cs, expseudo);
+ &vp, &newexi, req, cs,
+ visp != NULL ? visp->vis_exported : 0);
if (error == ENOENT) {
rddir_next_offset = dp->d_off;
continue;
@@ -917,6 +918,13 @@ reencode_attrs:
u_longlong_t change;
NFS4_SET_FATTR4_CHANGE(change,
va.va_ctime);
+ if (visp != NULL) {
+ u_longlong_t visch;
+ NFS4_SET_FATTR4_CHANGE(visch,
+ visp->vis_change);
+ if (visch > change)
+ change = visch;
+ }
IXDR_PUT_HYPER(ptr, change);
}
if (ae & FATTR4_SIZE_MASK) {
diff --git a/usr/src/uts/common/fs/nfs/nfs4_vnops.c b/usr/src/uts/common/fs/nfs/nfs4_vnops.c
index ccd9b1f0a3..840655f443 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_vnops.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_vnops.c
@@ -2233,7 +2233,6 @@ nfs4_open_non_reg_file(vnode_t **vpp, int flag, cred_t *cr)
(rp->r_dir == NULL && !nfs4_has_pages(*vpp)))
return (0);
- gar.n4g_va.va_mask = AT_ALL;
return (nfs4_getattr_otw(*vpp, &gar, cr, 0));
}
@@ -12376,9 +12375,8 @@ nfs4_getsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr,
/*
* The getattr otw call will always get both the acl, in
* the form of a list of nfsace4's, and the number of acl
- * entries; independent of the value of gar.n4g_vsa.vsa_mask.
+ * entries; independent of the value of gar.n4g_va.va_mask.
*/
- gar.n4g_va.va_mask = AT_ALL;
error = nfs4_getattr_otw(vp, &gar, cr, 1);
if (error) {
vs_ace4_destroy(&gar.n4g_vsa);
diff --git a/usr/src/uts/common/fs/nfs/nfs_export.c b/usr/src/uts/common/fs/nfs/nfs_export.c
index 4c316a3876..200ef6668d 100644
--- a/usr/src/uts/common/fs/nfs/nfs_export.c
+++ b/usr/src/uts/common/fs/nfs/nfs_export.c
@@ -83,7 +83,7 @@ extern void sec_svc_freerootnames(int, int, caddr_t *);
static int build_seclist_nodups(exportdata_t *, secinfo_t *, int);
static void srv_secinfo_add(secinfo_t **, int *, secinfo_t *, int, int);
static void srv_secinfo_remove(secinfo_t **, int *, secinfo_t *, int);
-static void srv_secinfo_treeclimb(exportinfo_t *, secinfo_t *, int, int);
+static void srv_secinfo_treeclimb(exportinfo_t *, secinfo_t *, int, bool_t);
#ifdef VOLATILE_FH_TEST
static struct ex_vol_rename *find_volrnm_fh(exportinfo_t *, nfs_fh4 *);
@@ -703,12 +703,13 @@ vis2exi(treenode_t *tnode)
* given exportinfo from its ancestors upto the system root.
*/
void
-srv_secinfo_treeclimb(exportinfo_t *exip, secinfo_t *sec, int seccnt, int isadd)
+srv_secinfo_treeclimb(exportinfo_t *exip, secinfo_t *sec, int seccnt,
+ bool_t isadd)
{
treenode_t *tnode = exip->exi_tree;
ASSERT(RW_WRITE_HELD(&exported_lock));
- ASSERT(tnode);
+ ASSERT(tnode != NULL);
if (seccnt == 0)
return;
@@ -716,7 +717,7 @@ srv_secinfo_treeclimb(exportinfo_t *exip, secinfo_t *sec, int seccnt, int isadd)
/*
* If flavors are being added and the new export root isn't
* also VROOT, its implicitly allowed flavors are inherited from
- * from its pseudonode.
+ * its pseudonode.
* Note - for VROOT exports the implicitly allowed flavors were
* transferred from the PSEUDO export in exportfs()
*/
@@ -733,10 +734,10 @@ srv_secinfo_treeclimb(exportinfo_t *exip, secinfo_t *sec, int seccnt, int isadd)
*/
tnode = tnode->tree_parent;
- while (tnode) {
+ while (tnode != NULL) {
/* If there is exportinfo, update it */
- if (tnode->tree_exi) {
+ if (tnode->tree_exi != NULL) {
secinfo_t **pxsec =
&tnode->tree_exi->exi_export.ex_secinfo;
int *pxcnt = &tnode->tree_exi->exi_export.ex_seccnt;
@@ -749,7 +750,7 @@ srv_secinfo_treeclimb(exportinfo_t *exip, secinfo_t *sec, int seccnt, int isadd)
}
/* Update every visible - only root node has no visible */
- if (tnode->tree_vis) {
+ if (tnode->tree_vis != NULL) {
secinfo_t **pxsec = &tnode->tree_vis->vis_secinfo;
int *pxcnt = &tnode->tree_vis->vis_seccnt;
if (isadd)
@@ -1517,9 +1518,12 @@ exportfs(struct exportfs_args *args, model_t model, cred_t *cr)
if (error)
goto out7;
} else {
- /* If it's a re-export update namespace tree */
+ /* If it's a re-export update namespace tree */
exi->exi_tree = ex->exi_tree;
exi->exi_tree->tree_exi = exi;
+
+ /* Update the change timestamp */
+ tree_update_change(exi->exi_tree, NULL);
}
/*
@@ -1670,7 +1674,7 @@ unexport(struct exportinfo *exi)
* a pseudo export here to retain the visible list
* for paths to exports below.
*/
- if (exi->exi_visible) {
+ if (exi->exi_visible != NULL) {
struct exportinfo *newexi;
newexi = pseudo_exportfs(exi->exi_vp, &exi->exi_fid,
@@ -1680,6 +1684,9 @@ unexport(struct exportinfo *exi)
/* interconnect the existing treenode with the new exportinfo */
newexi->exi_tree = exi->exi_tree;
newexi->exi_tree->tree_exi = newexi;
+
+ /* Update the change timestamp */
+ tree_update_change(exi->exi_tree, NULL);
} else {
treeclimb_unexport(exi);
}
@@ -1893,7 +1900,7 @@ nfs_getfh(struct nfs_getfh_args *args, model_t model, cred_t *cr)
*/
struct exportinfo *
nfs_vptoexi(vnode_t *dvp, vnode_t *vp, cred_t *cr, int *walk,
- int *err, bool_t v4srv)
+ int *err, bool_t v4srv)
{
fid_t fid;
int error;
diff --git a/usr/src/uts/common/nfs/export.h b/usr/src/uts/common/nfs/export.h
index b6d223627d..66b86cdf8f 100644
--- a/usr/src/uts/common/nfs/export.h
+++ b/usr/src/uts/common/nfs/export.h
@@ -539,7 +539,7 @@ typedef struct secinfo secinfo_t;
* a real export at the mount point (VROOT) which has a subtree shared
* has a visible list.
*
- * The exi_visible field is NULL for normal, non=pseudo filesystems
+ * The exi_visible field is NULL for normal, non-pseudo filesystems
* which do not have any subtree exported. If the field is non-null,
* it points to a list of visible entries, identified by vis_fid and/or
* vis_ino. The presence of a "visible" list means that if this export
@@ -568,6 +568,7 @@ struct exp_visible {
struct exp_visible *vis_next;
struct secinfo *vis_secinfo;
int vis_seccnt;
+ timespec_t vis_change;
};
typedef struct exp_visible exp_visible_t;
@@ -635,7 +636,8 @@ extern exportinfo_t *vis2exi(treenode_t *);
extern int treeclimb_export(struct exportinfo *);
extern void treeclimb_unexport(struct exportinfo *);
extern int nfs_visible(struct exportinfo *, vnode_t *, int *);
-extern int nfs_visible_inode(struct exportinfo *, ino64_t, int *);
+extern int nfs_visible_inode(struct exportinfo *, ino64_t,
+ struct exp_visible **);
extern int has_visible(struct exportinfo *, vnode_t *);
extern void free_visible(struct exp_visible *);
extern int nfs_exported(struct exportinfo *, vnode_t *);
@@ -643,6 +645,9 @@ extern struct exportinfo *pseudo_exportfs(vnode_t *, fid_t *,
struct exp_visible *, struct exportdata *);
extern int vop_fid_pseudo(vnode_t *, fid_t *);
extern int nfs4_vget_pseudo(struct exportinfo *, vnode_t **, fid_t *);
+extern bool_t nfs_visible_change(struct exportinfo *, vnode_t *,
+ timespec_t *);
+extern void tree_update_change(treenode_t *, timespec_t *);
/*
* Functions that handle the NFSv4 server namespace security flavors
* information.