diff options
author | Marcel Telka <marcel@telka.sk> | 2016-11-29 16:41:54 +0100 |
---|---|---|
committer | Dan McDonald <danmcd@omniti.com> | 2016-11-29 11:08:04 -0500 |
commit | 4a6959565df1e2af817732421764a9da2f446da9 (patch) | |
tree | f795337988e01775590bdd7b3e58cb324b2192ee | |
parent | 4d86c0eab246bdfddc2dd52410ba808433bd6266 (diff) | |
download | illumos-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.c | 11 | ||||
-rw-r--r-- | usr/src/uts/common/fs/nfs/nfs4_srv_attr.c | 123 | ||||
-rw-r--r-- | usr/src/uts/common/fs/nfs/nfs4_srv_ns.c | 213 | ||||
-rw-r--r-- | usr/src/uts/common/fs/nfs/nfs4_srv_readdir.c | 26 | ||||
-rw-r--r-- | usr/src/uts/common/fs/nfs/nfs4_vnops.c | 4 | ||||
-rw-r--r-- | usr/src/uts/common/fs/nfs/nfs_export.c | 27 | ||||
-rw-r--r-- | usr/src/uts/common/nfs/export.h | 9 |
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. |