2022-12-13 10:09:45

by Chengen Du

[permalink] [raw]
Subject: [PATCH] NFS: fix client permission error after adding user to permissible group

The access cache only expires if either NFS_INO_INVALID_ACCESS flag is on
or timeout (without delegation).
Adding a user to a group in the NFS server will not cause any file
attributes to change.
The client will encounter permission errors until other file attributes
are changed or the memory cache is dropped.

Steps to reproduce the issue:
1.[client side] testuser is not part of testgroup
testuser@kinetic:~$ ls -ld /mnt/private/
drwxrwx--- 2 root testgroup 4096 Nov 24 08:23 /mnt/private/
testuser@kinetic:~$ mktemp -p /mnt/private/
mktemp: failed to create file via template
‘/mnt/private/tmp.XXXXXXXXXX’: Permission denied
2.[server side] add testuser into testgroup, which has access to folder
root@kinetic:~$ usermod -aG testgroup testuser &&
echo `date +'%s'` > /proc/net/rpc/auth.unix.gid/flush
3.[client side] create a file again but still fail
testuser@kinetic:~$ mktemp -p /mnt/private/
mktemp: failed to create file via template
‘/mnt/private/tmp.XXXXXXXXXX’: Permission denied

Signed-off-by: Chengen Du <[email protected]>
---
fs/nfs/dir.c | 2 +-
fs/nfs/inode.c | 12 ++++++++++++
fs/nfs/nfs4_fs.h | 3 +++
fs/nfs/nfs4proc.c | 5 +++--
fs/nfs/nfs4xdr.c | 25 +++++++++++++++++++++++++
fs/nfsd/nfs4xdr.c | 21 +++++++++++++++++++++
fs/nfsd/nfsd.h | 3 ++-
include/linux/nfs4.h | 1 +
include/linux/nfs_xdr.h | 2 ++
9 files changed, 70 insertions(+), 4 deletions(-)

diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index f594dac436a7..966f680ebbc8 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -2929,7 +2929,7 @@ static int access_cmp(const struct cred *a, const struct nfs_access_entry *b)
return 0;
}

-static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, const struct cred *cred)
+struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, const struct cred *cred)
{
struct rb_node *n = NFS_I(inode)->access_cache.rb_node;

diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 6b2cfa59a1a2..8f952f86b126 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -2177,6 +2177,18 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
nfsi->cache_validity |=
save_cache_validity & NFS_INO_INVALID_NLINK;

+ if (fattr->valid & NFS_ATTR_FATTR_ACCESS) {
+ if (!(invalid & NFS_INO_INVALID_ACCESS)) {
+ const struct cred *cred = current_cred();
+ struct nfs_access_entry *cache;
+
+ cache = nfs_access_search_rbtree(inode, cred);
+ if (cache != NULL && cache->mask != fattr->access) {
+ invalid |= NFS_INO_INVALID_ACCESS;
+ }
+ }
+ }
+
if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) {
/*
* report the blocks in 512byte units
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index cfef738d765e..68ed8d4f95a9 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -272,6 +272,9 @@ extern const struct dentry_operations nfs4_dentry_operations;
int nfs_atomic_open(struct inode *, struct dentry *, struct file *,
unsigned, umode_t);

+extern struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode,
+ const struct cred *cred);
+
/* fs_context.c */
extern struct file_system_type nfs4_fs_type;

diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 86ed5c0142c3..7f8790ab5c7a 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -206,7 +206,8 @@ const u32 nfs4_fattr_bitmap[3] = {
| FATTR4_WORD1_TIME_ACCESS
| FATTR4_WORD1_TIME_METADATA
| FATTR4_WORD1_TIME_MODIFY
- | FATTR4_WORD1_MOUNTED_ON_FILEID,
+ | FATTR4_WORD1_MOUNTED_ON_FILEID
+ | FATTR4_WORD1_ACCESS,
#ifdef CONFIG_NFS_V4_SECURITY_LABEL
FATTR4_WORD2_SECURITY_LABEL
#endif
@@ -3820,7 +3821,7 @@ static void nfs4_close_context(struct nfs_open_context *ctx, int is_sync)
nfs4_close_state(ctx->state, _nfs4_ctx_to_openmode(ctx));
}

-#define FATTR4_WORD1_NFS40_MASK (2*FATTR4_WORD1_MOUNTED_ON_FILEID - 1UL)
+#define FATTR4_WORD1_NFS40_MASK (2*FATTR4_WORD1_ACCESS - 1UL)
#define FATTR4_WORD2_NFS41_MASK (2*FATTR4_WORD2_SUPPATTR_EXCLCREAT - 1UL)
#define FATTR4_WORD2_NFS42_MASK (2*FATTR4_WORD2_XATTR_SUPPORT - 1UL)

diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index acfe5f4bda48..cf651e9b4a5d 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -4296,6 +4296,26 @@ static int decode_attr_xattrsupport(struct xdr_stream *xdr, uint32_t *bitmap,
return 0;
}

+static int decode_attr_access(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *access)
+{
+ __be32 *p;
+ int ret = 0;
+
+ *access = 0;
+ if (unlikely(bitmap[1] & (FATTR4_WORD1_ACCESS - 1U)))
+ return -EIO;
+ if (likely(bitmap[1] & FATTR4_WORD1_ACCESS)) {
+ p = xdr_inline_decode(xdr, 4);
+ if (unlikely(!p))
+ return -EIO;
+ *access = be32_to_cpup(p);
+ bitmap[1] &= ~FATTR4_WORD1_ACCESS;
+ ret = NFS_ATTR_FATTR_ACCESS;
+ }
+ dprintk("%s: access=%u\n", __func__, (unsigned int)*access);
+ return ret;
+}
+
static int verify_attr_len(struct xdr_stream *xdr, unsigned int savep, uint32_t attrlen)
{
unsigned int attrwords = XDR_QUADLEN(attrlen);
@@ -4747,6 +4767,11 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
goto xdr_error;
fattr->valid |= status;

+ status = decode_attr_access(xdr, bitmap, &fattr->access);
+ if (status < 0)
+ goto xdr_error;
+ fattr->valid |= status;
+
status = -EIO;
if (unlikely(bitmap[1]))
goto xdr_error;
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 2b4ae858c89b..788e9faaa6e5 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -3396,6 +3396,27 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
}
p = xdr_encode_hyper(p, ino);
}
+ if (bmval1 & FATTR4_WORD1_ACCESS) {
+ u32 access;
+ u32 supported;
+
+ access = NFS3_ACCESS_READ | NFS3_ACCESS_MODIFY | NFS3_ACCESS_EXTEND;
+ if (minorversion >= 2) {
+ access |= NFS4_ACCESS_XALIST | NFS4_ACCESS_XAREAD |
+ NFS4_ACCESS_XAWRITE;
+ }
+ if (S_ISDIR(d_inode(dentry)->i_mode))
+ access |= NFS3_ACCESS_DELETE | NFS3_ACCESS_LOOKUP;
+ else
+ access |= NFS3_ACCESS_EXECUTE;
+ status = nfsd_access(rqstp, fhp, &access, &supported);
+ if (status)
+ goto out;
+ p = xdr_reserve_space(xdr, 4);
+ if (!p)
+ goto out_resource;
+ *p++ = cpu_to_be32(access);
+ }
#ifdef CONFIG_NFSD_PNFS
if (bmval1 & FATTR4_WORD1_FS_LAYOUT_TYPES) {
status = nfsd4_encode_layout_types(xdr, exp->ex_layout_types);
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
index 93b42ef9ed91..648a4ec3e2d4 100644
--- a/fs/nfsd/nfsd.h
+++ b/fs/nfsd/nfsd.h
@@ -378,7 +378,8 @@ void nfsd_lockd_shutdown(void);
| FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE | FATTR4_WORD1_SPACE_TOTAL \
| FATTR4_WORD1_SPACE_USED | FATTR4_WORD1_TIME_ACCESS | FATTR4_WORD1_TIME_ACCESS_SET \
| FATTR4_WORD1_TIME_DELTA | FATTR4_WORD1_TIME_METADATA | FATTR4_WORD1_TIME_CREATE \
- | FATTR4_WORD1_TIME_MODIFY | FATTR4_WORD1_TIME_MODIFY_SET | FATTR4_WORD1_MOUNTED_ON_FILEID)
+ | FATTR4_WORD1_TIME_MODIFY | FATTR4_WORD1_TIME_MODIFY_SET | FATTR4_WORD1_MOUNTED_ON_FILEID \
+ | FATTR4_WORD1_ACCESS)

#define NFSD4_SUPPORTED_ATTRS_WORD2 0

diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 730003c4f4af..63d0e31c6552 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -451,6 +451,7 @@ enum lock_type4 {
#define FATTR4_WORD1_TIME_MODIFY (1UL << 21)
#define FATTR4_WORD1_TIME_MODIFY_SET (1UL << 22)
#define FATTR4_WORD1_MOUNTED_ON_FILEID (1UL << 23)
+#define FATTR4_WORD1_ACCESS (1UL << 24)
#define FATTR4_WORD1_DACL (1UL << 26)
#define FATTR4_WORD1_SACL (1UL << 27)
#define FATTR4_WORD1_FS_LAYOUT_TYPES (1UL << 30)
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index e86cf6642d21..4626e27588de 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -78,6 +78,7 @@ struct nfs_fattr {
struct nfs4_string *group_name;
struct nfs4_threshold *mdsthreshold; /* pNFS threshold hints */
struct nfs4_label *label;
+ __u32 access;
};

#define NFS_ATTR_FATTR_TYPE (1U << 0)
@@ -106,6 +107,7 @@ struct nfs_fattr {
#define NFS_ATTR_FATTR_OWNER_NAME (1U << 23)
#define NFS_ATTR_FATTR_GROUP_NAME (1U << 24)
#define NFS_ATTR_FATTR_V4_SECURITY_LABEL (1U << 25)
+#define NFS_ATTR_FATTR_ACCESS (1U << 26)

#define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \
| NFS_ATTR_FATTR_MODE \
--
2.37.2


2022-12-13 12:21:21

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH] NFS: fix client permission error after adding user to permissible group

Hi Chengen,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on trondmy-nfs/linux-next]
[also build test WARNING on linus/master v6.1 next-20221213]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url: https://github.com/intel-lab-lkp/linux/commits/Chengen-Du/NFS-fix-client-permission-error-after-adding-user-to-permissible-group/20221213-180531
base: git://git.linux-nfs.org/projects/trondmy/linux-nfs.git linux-next
patch link: https://lore.kernel.org/r/20221213100241.254681-1-chengen.du%40canonical.com
patch subject: [PATCH] NFS: fix client permission error after adding user to permissible group
config: arc-defconfig
compiler: arc-elf-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/intel-lab-lkp/linux/commit/7206036f9265a95f957d3f58a973c9ab27979284
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review Chengen-Du/NFS-fix-client-permission-error-after-adding-user-to-permissible-group/20221213-180531
git checkout 7206036f9265a95f957d3f58a973c9ab27979284
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=arc SHELL=/bin/bash fs/nfs/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <[email protected]>

All warnings (new ones prefixed by >>):

>> fs/nfs/dir.c:2937:26: warning: no previous prototype for 'nfs_access_search_rbtree' [-Wmissing-prototypes]
2937 | struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, const struct cred *cred)
| ^~~~~~~~~~~~~~~~~~~~~~~~
--
fs/nfs/inode.c: In function 'nfs_update_inode':
fs/nfs/inode.c:2186:33: error: implicit declaration of function 'nfs_access_search_rbtree' [-Werror=implicit-function-declaration]
2186 | cache = nfs_access_search_rbtree(inode, cred);
| ^~~~~~~~~~~~~~~~~~~~~~~~
>> fs/nfs/inode.c:2186:31: warning: assignment to 'struct nfs_access_entry *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
2186 | cache = nfs_access_search_rbtree(inode, cred);
| ^
cc1: some warnings being treated as errors


vim +/nfs_access_search_rbtree +2937 fs/nfs/dir.c

2936
> 2937 struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, const struct cred *cred)
2938 {
2939 struct rb_node *n = NFS_I(inode)->access_cache.rb_node;
2940
2941 while (n != NULL) {
2942 struct nfs_access_entry *entry =
2943 rb_entry(n, struct nfs_access_entry, rb_node);
2944 int cmp = access_cmp(cred, entry);
2945
2946 if (cmp < 0)
2947 n = n->rb_left;
2948 else if (cmp > 0)
2949 n = n->rb_right;
2950 else
2951 return entry;
2952 }
2953 return NULL;
2954 }
2955

--
0-DAY CI Kernel Test Service
https://01.org/lkp


Attachments:
(No filename) (3.37 kB)
config (40.49 kB)
Download all attachments

2022-12-13 13:05:21

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH] NFS: fix client permission error after adding user to permissible group

Hi Chengen,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on trondmy-nfs/linux-next]
[also build test ERROR on linus/master v6.1 next-20221213]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url: https://github.com/intel-lab-lkp/linux/commits/Chengen-Du/NFS-fix-client-permission-error-after-adding-user-to-permissible-group/20221213-180531
base: git://git.linux-nfs.org/projects/trondmy/linux-nfs.git linux-next
patch link: https://lore.kernel.org/r/20221213100241.254681-1-chengen.du%40canonical.com
patch subject: [PATCH] NFS: fix client permission error after adding user to permissible group
config: arc-defconfig
compiler: arc-elf-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/intel-lab-lkp/linux/commit/7206036f9265a95f957d3f58a973c9ab27979284
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review Chengen-Du/NFS-fix-client-permission-error-after-adding-user-to-permissible-group/20221213-180531
git checkout 7206036f9265a95f957d3f58a973c9ab27979284
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=arc SHELL=/bin/bash

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <[email protected]>

All errors (new ones prefixed by >>):

fs/nfs/inode.c: In function 'nfs_update_inode':
>> fs/nfs/inode.c:2186:33: error: implicit declaration of function 'nfs_access_search_rbtree' [-Werror=implicit-function-declaration]
2186 | cache = nfs_access_search_rbtree(inode, cred);
| ^~~~~~~~~~~~~~~~~~~~~~~~
fs/nfs/inode.c:2186:31: warning: assignment to 'struct nfs_access_entry *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
2186 | cache = nfs_access_search_rbtree(inode, cred);
| ^
cc1: some warnings being treated as errors


vim +/nfs_access_search_rbtree +2186 fs/nfs/inode.c

1970
1971
1972 /*
1973 * Many nfs protocol calls return the new file attributes after
1974 * an operation. Here we update the inode to reflect the state
1975 * of the server's inode.
1976 *
1977 * This is a bit tricky because we have to make sure all dirty pages
1978 * have been sent off to the server before calling invalidate_inode_pages.
1979 * To make sure no other process adds more write requests while we try
1980 * our best to flush them, we make them sleep during the attribute refresh.
1981 *
1982 * A very similar scenario holds for the dir cache.
1983 */
1984 static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
1985 {
1986 struct nfs_server *server = NFS_SERVER(inode);
1987 struct nfs_inode *nfsi = NFS_I(inode);
1988 loff_t cur_isize, new_isize;
1989 u64 fattr_supported = server->fattr_valid;
1990 unsigned long invalid = 0;
1991 unsigned long now = jiffies;
1992 unsigned long save_cache_validity;
1993 bool have_writers = nfs_file_has_buffered_writers(nfsi);
1994 bool cache_revalidated = true;
1995 bool attr_changed = false;
1996 bool have_delegation;
1997
1998 dfprintk(VFS, "NFS: %s(%s/%lu fh_crc=0x%08x ct=%d info=0x%x)\n",
1999 __func__, inode->i_sb->s_id, inode->i_ino,
2000 nfs_display_fhandle_hash(NFS_FH(inode)),
2001 atomic_read(&inode->i_count), fattr->valid);
2002
2003 if (!(fattr->valid & NFS_ATTR_FATTR_FILEID)) {
2004 /* Only a mounted-on-fileid? Just exit */
2005 if (fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID)
2006 return 0;
2007 /* Has the inode gone and changed behind our back? */
2008 } else if (nfsi->fileid != fattr->fileid) {
2009 /* Is this perhaps the mounted-on fileid? */
2010 if ((fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) &&
2011 nfsi->fileid == fattr->mounted_on_fileid)
2012 return 0;
2013 printk(KERN_ERR "NFS: server %s error: fileid changed\n"
2014 "fsid %s: expected fileid 0x%Lx, got 0x%Lx\n",
2015 NFS_SERVER(inode)->nfs_client->cl_hostname,
2016 inode->i_sb->s_id, (long long)nfsi->fileid,
2017 (long long)fattr->fileid);
2018 goto out_err;
2019 }
2020
2021 /*
2022 * Make sure the inode's type hasn't changed.
2023 */
2024 if ((fattr->valid & NFS_ATTR_FATTR_TYPE) && inode_wrong_type(inode, fattr->mode)) {
2025 /*
2026 * Big trouble! The inode has become a different object.
2027 */
2028 printk(KERN_DEBUG "NFS: %s: inode %lu mode changed, %07o to %07o\n",
2029 __func__, inode->i_ino, inode->i_mode, fattr->mode);
2030 goto out_err;
2031 }
2032
2033 /* Update the fsid? */
2034 if (S_ISDIR(inode->i_mode) && (fattr->valid & NFS_ATTR_FATTR_FSID) &&
2035 !nfs_fsid_equal(&server->fsid, &fattr->fsid) &&
2036 !IS_AUTOMOUNT(inode))
2037 server->fsid = fattr->fsid;
2038
2039 /* Save the delegation state before clearing cache_validity */
2040 have_delegation = nfs_have_delegated_attributes(inode);
2041
2042 /*
2043 * Update the read time so we don't revalidate too often.
2044 */
2045 nfsi->read_cache_jiffies = fattr->time_start;
2046
2047 save_cache_validity = nfsi->cache_validity;
2048 nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR
2049 | NFS_INO_INVALID_ATIME
2050 | NFS_INO_REVAL_FORCED
2051 | NFS_INO_INVALID_BLOCKS);
2052
2053 /* Do atomic weak cache consistency updates */
2054 nfs_wcc_update_inode(inode, fattr);
2055
2056 if (pnfs_layoutcommit_outstanding(inode)) {
2057 nfsi->cache_validity |=
2058 save_cache_validity &
2059 (NFS_INO_INVALID_CHANGE | NFS_INO_INVALID_CTIME |
2060 NFS_INO_INVALID_MTIME | NFS_INO_INVALID_SIZE |
2061 NFS_INO_INVALID_BLOCKS);
2062 cache_revalidated = false;
2063 }
2064
2065 /* More cache consistency checks */
2066 if (fattr->valid & NFS_ATTR_FATTR_CHANGE) {
2067 if (!inode_eq_iversion_raw(inode, fattr->change_attr)) {
2068 /* Could it be a race with writeback? */
2069 if (!(have_writers || have_delegation)) {
2070 invalid |= NFS_INO_INVALID_DATA
2071 | NFS_INO_INVALID_ACCESS
2072 | NFS_INO_INVALID_ACL
2073 | NFS_INO_INVALID_XATTR;
2074 /* Force revalidate of all attributes */
2075 save_cache_validity |= NFS_INO_INVALID_CTIME
2076 | NFS_INO_INVALID_MTIME
2077 | NFS_INO_INVALID_SIZE
2078 | NFS_INO_INVALID_BLOCKS
2079 | NFS_INO_INVALID_NLINK
2080 | NFS_INO_INVALID_MODE
2081 | NFS_INO_INVALID_OTHER;
2082 if (S_ISDIR(inode->i_mode))
2083 nfs_force_lookup_revalidate(inode);
2084 attr_changed = true;
2085 dprintk("NFS: change_attr change on server for file %s/%ld\n",
2086 inode->i_sb->s_id,
2087 inode->i_ino);
2088 } else if (!have_delegation)
2089 nfsi->cache_validity |= NFS_INO_DATA_INVAL_DEFER;
2090 inode_set_iversion_raw(inode, fattr->change_attr);
2091 }
2092 } else {
2093 nfsi->cache_validity |=
2094 save_cache_validity & NFS_INO_INVALID_CHANGE;
2095 if (!have_delegation ||
2096 (nfsi->cache_validity & NFS_INO_INVALID_CHANGE) != 0)
2097 cache_revalidated = false;
2098 }
2099
2100 if (fattr->valid & NFS_ATTR_FATTR_MTIME)
2101 inode->i_mtime = fattr->mtime;
2102 else if (fattr_supported & NFS_ATTR_FATTR_MTIME)
2103 nfsi->cache_validity |=
2104 save_cache_validity & NFS_INO_INVALID_MTIME;
2105
2106 if (fattr->valid & NFS_ATTR_FATTR_CTIME)
2107 inode->i_ctime = fattr->ctime;
2108 else if (fattr_supported & NFS_ATTR_FATTR_CTIME)
2109 nfsi->cache_validity |=
2110 save_cache_validity & NFS_INO_INVALID_CTIME;
2111
2112 /* Check if our cached file size is stale */
2113 if (fattr->valid & NFS_ATTR_FATTR_SIZE) {
2114 new_isize = nfs_size_to_loff_t(fattr->size);
2115 cur_isize = i_size_read(inode);
2116 if (new_isize != cur_isize && !have_delegation) {
2117 /* Do we perhaps have any outstanding writes, or has
2118 * the file grown beyond our last write? */
2119 if (!nfs_have_writebacks(inode) || new_isize > cur_isize) {
2120 trace_nfs_size_update(inode, new_isize);
2121 i_size_write(inode, new_isize);
2122 if (!have_writers)
2123 invalid |= NFS_INO_INVALID_DATA;
2124 }
2125 }
2126 if (new_isize == 0 &&
2127 !(fattr->valid & (NFS_ATTR_FATTR_SPACE_USED |
2128 NFS_ATTR_FATTR_BLOCKS_USED))) {
2129 fattr->du.nfs3.used = 0;
2130 fattr->valid |= NFS_ATTR_FATTR_SPACE_USED;
2131 }
2132 } else
2133 nfsi->cache_validity |=
2134 save_cache_validity & NFS_INO_INVALID_SIZE;
2135
2136 if (fattr->valid & NFS_ATTR_FATTR_ATIME)
2137 inode->i_atime = fattr->atime;
2138 else if (fattr_supported & NFS_ATTR_FATTR_ATIME)
2139 nfsi->cache_validity |=
2140 save_cache_validity & NFS_INO_INVALID_ATIME;
2141
2142 if (fattr->valid & NFS_ATTR_FATTR_MODE) {
2143 if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)) {
2144 umode_t newmode = inode->i_mode & S_IFMT;
2145 newmode |= fattr->mode & S_IALLUGO;
2146 inode->i_mode = newmode;
2147 invalid |= NFS_INO_INVALID_ACCESS
2148 | NFS_INO_INVALID_ACL;
2149 }
2150 } else if (fattr_supported & NFS_ATTR_FATTR_MODE)
2151 nfsi->cache_validity |=
2152 save_cache_validity & NFS_INO_INVALID_MODE;
2153
2154 if (fattr->valid & NFS_ATTR_FATTR_OWNER) {
2155 if (!uid_eq(inode->i_uid, fattr->uid)) {
2156 invalid |= NFS_INO_INVALID_ACCESS
2157 | NFS_INO_INVALID_ACL;
2158 inode->i_uid = fattr->uid;
2159 }
2160 } else if (fattr_supported & NFS_ATTR_FATTR_OWNER)
2161 nfsi->cache_validity |=
2162 save_cache_validity & NFS_INO_INVALID_OTHER;
2163
2164 if (fattr->valid & NFS_ATTR_FATTR_GROUP) {
2165 if (!gid_eq(inode->i_gid, fattr->gid)) {
2166 invalid |= NFS_INO_INVALID_ACCESS
2167 | NFS_INO_INVALID_ACL;
2168 inode->i_gid = fattr->gid;
2169 }
2170 } else if (fattr_supported & NFS_ATTR_FATTR_GROUP)
2171 nfsi->cache_validity |=
2172 save_cache_validity & NFS_INO_INVALID_OTHER;
2173
2174 if (fattr->valid & NFS_ATTR_FATTR_NLINK) {
2175 if (inode->i_nlink != fattr->nlink)
2176 set_nlink(inode, fattr->nlink);
2177 } else if (fattr_supported & NFS_ATTR_FATTR_NLINK)
2178 nfsi->cache_validity |=
2179 save_cache_validity & NFS_INO_INVALID_NLINK;
2180
2181 if (fattr->valid & NFS_ATTR_FATTR_ACCESS) {
2182 if (!(invalid & NFS_INO_INVALID_ACCESS)) {
2183 const struct cred *cred = current_cred();
2184 struct nfs_access_entry *cache;
2185
> 2186 cache = nfs_access_search_rbtree(inode, cred);
2187 if (cache != NULL && cache->mask != fattr->access) {
2188 invalid |= NFS_INO_INVALID_ACCESS;
2189 }
2190 }
2191 }
2192
2193 if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) {
2194 /*
2195 * report the blocks in 512byte units
2196 */
2197 inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used);
2198 } else if (fattr_supported & NFS_ATTR_FATTR_SPACE_USED)
2199 nfsi->cache_validity |=
2200 save_cache_validity & NFS_INO_INVALID_BLOCKS;
2201
2202 if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED)
2203 inode->i_blocks = fattr->du.nfs2.blocks;
2204 else if (fattr_supported & NFS_ATTR_FATTR_BLOCKS_USED)
2205 nfsi->cache_validity |=
2206 save_cache_validity & NFS_INO_INVALID_BLOCKS;
2207
2208 /* Update attrtimeo value if we're out of the unstable period */
2209 if (attr_changed) {
2210 nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
2211 nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
2212 nfsi->attrtimeo_timestamp = now;
2213 /* Set barrier to be more recent than all outstanding updates */
2214 nfsi->attr_gencount = nfs_inc_attr_generation_counter();
2215 } else {
2216 if (cache_revalidated) {
2217 if (!time_in_range_open(now, nfsi->attrtimeo_timestamp,
2218 nfsi->attrtimeo_timestamp + nfsi->attrtimeo)) {
2219 nfsi->attrtimeo <<= 1;
2220 if (nfsi->attrtimeo > NFS_MAXATTRTIMEO(inode))
2221 nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode);
2222 }
2223 nfsi->attrtimeo_timestamp = now;
2224 }
2225 /* Set the barrier to be more recent than this fattr */
2226 if ((long)(fattr->gencount - nfsi->attr_gencount) > 0)
2227 nfsi->attr_gencount = fattr->gencount;
2228 }
2229
2230 /* Don't invalidate the data if we were to blame */
2231 if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)
2232 || S_ISLNK(inode->i_mode)))
2233 invalid &= ~NFS_INO_INVALID_DATA;
2234 nfs_set_cache_invalid(inode, invalid);
2235
2236 return 0;
2237 out_err:
2238 /*
2239 * No need to worry about unhashing the dentry, as the
2240 * lookup validation will know that the inode is bad.
2241 * (But we fall through to invalidate the caches.)
2242 */
2243 nfs_set_inode_stale_locked(inode);
2244 return -ESTALE;
2245 }
2246

--
0-DAY CI Kernel Test Service
https://01.org/lkp


Attachments:
(No filename) (13.66 kB)
config (40.49 kB)
Download all attachments