@@ -1082,7 +1082,7 @@ static int _nfs42_proc_clone(struct rpc_message *msg, struct file *src_f,
if (!res.dst_fattr)
return -ENOMEM;
- nfs4_bitmask_set(dst_bitmask, server->cache_consistency_bitmask,
+ nfs4_bitmask_set(dst_bitmask, server->cache_consistency_bitmask_nl,
dst_inode, NFS_INO_INVALID_BLOCKS);
status = nfs4_call_sync(server->client, server, msg,
@@ -3665,7 +3665,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
/* Close-to-open cache consistency revalidation */
if (!nfs4_have_delegation(inode, FMODE_READ)) {
nfs4_bitmask_set(calldata->arg.bitmask_store,
- server->cache_consistency_bitmask,
+ server->cache_consistency_bitmask_nl,
inode, 0);
calldata->arg.bitmask = calldata->arg.bitmask_store;
} else
@@ -3905,7 +3905,12 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
memcpy(server->cache_consistency_bitmask, res.attr_bitmask, sizeof(server->cache_consistency_bitmask));
server->cache_consistency_bitmask[0] &= FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE;
server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY;
- server->cache_consistency_bitmask[2] = 0;
+ server->cache_consistency_bitmask[2] = res.attr_bitmask[2] & FATTR4_WORD2_SECURITY_LABEL;
+
+ memcpy(server->cache_consistency_bitmask_nl, server->cache_consistency_bitmask, sizeof(server->cache_consistency_bitmask));
+ server->cache_consistency_bitmask_nl[2] = 0;
+
+
/* Avoid a regression due to buggy server */
for (i = 0; i < ARRAY_SIZE(res.exclcreat_bitmask); i++)
@@ -4576,7 +4581,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
res.fattr = nfs_alloc_fattr();
if (res.fattr == NULL)
return -ENOMEM;
- args.bitmask = server->cache_consistency_bitmask;
+ args.bitmask = server->cache_consistency_bitmask_nl;
}
status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
if (!status) {
@@ -5098,14 +5103,19 @@ static int _nfs4_proc_readdir(struct nfs_readdir_arg *nr_arg,
.rpc_resp = &res,
.rpc_cred = nr_arg->cred,
};
- int status;
+ int status = -ENOMEM;
dprintk("%s: dentry = %pd2, cookie = %llu\n", __func__,
nr_arg->dentry, (unsigned long long)nr_arg->cookie);
if (!(server->caps & NFS_CAP_SECURITY_LABEL))
- args.bitmask = server->attr_bitmask_nl;
+ args.bitmask = server->cache_consistency_bitmask_nl;
else
- args.bitmask = server->attr_bitmask;
+ args.bitmask = server->cache_consistency_bitmask;
+
+ res.dir_attr = nfs_alloc_fattr();
+ if (res.dir_attr == NULL)
+ goto out;
+ res.server = server;
nfs4_setup_readdir(nr_arg->cookie, nr_arg->verf, nr_arg->dentry, &args);
res.pgbase = args.pgbase;
@@ -5118,6 +5128,9 @@ static int _nfs4_proc_readdir(struct nfs_readdir_arg *nr_arg,
nfs_invalidate_atime(dir);
+ nfs_refresh_inode(dir, res.dir_attr);
+ nfs_free_fattr(res.dir_attr);
+out:
dprintk("%s: returns %d\n", __func__, status);
return status;
}
@@ -5583,7 +5596,7 @@ static void nfs4_proc_write_setup(struct nfs_pgio_header *hdr,
hdr->res.fattr = NULL;
} else {
nfs4_bitmask_set(hdr->args.bitmask_store,
- server->cache_consistency_bitmask,
+ server->cache_consistency_bitmask_nl,
hdr->inode, NFS_INO_INVALID_BLOCKS);
hdr->args.bitmask = hdr->args.bitmask_store;
}
@@ -6622,7 +6635,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, const struct cred *cred,
data->args.fhandle = &data->fh;
data->args.stateid = &data->stateid;
nfs4_bitmask_set(data->args.bitmask_store,
- server->cache_consistency_bitmask, inode, 0);
+ server->cache_consistency_bitmask_nl, inode, 0);
data->args.bitmask = data->args.bitmask_store;
nfs_copy_fh(&data->fh, NFS_FH(inode));
nfs4_stateid_copy(&data->stateid, stateid);
@@ -469,10 +469,12 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
#define NFS4_enc_readdir_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putfh_maxsz + \
+ encode_getattr_maxsz + \
encode_readdir_maxsz)
#define NFS4_dec_readdir_sz (compound_decode_hdr_maxsz + \
decode_sequence_maxsz + \
decode_putfh_maxsz + \
+ decode_getattr_maxsz + \
decode_readdir_maxsz)
#define NFS4_enc_write_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
@@ -2529,6 +2531,7 @@ static void nfs4_xdr_enc_readdir(struct rpc_rqst *req, struct xdr_stream *xdr,
encode_compound_hdr(xdr, req, &hdr);
encode_sequence(xdr, &args->seq_args, &hdr);
encode_putfh(xdr, args->fh, &hdr);
+ encode_getfattr(xdr, args->bitmask, &hdr);
encode_readdir(xdr, args, req, &hdr);
rpc_prepare_reply_pages(req, args->pages, args->pgbase,
@@ -6769,6 +6772,9 @@ static int nfs4_xdr_dec_readdir(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
if (status)
goto out;
status = decode_putfh(xdr);
+ if (status)
+ goto out;
+ status = decode_getfattr(xdr, res->dir_attr, res->server);
if (status)
goto out;
status = decode_readdir(xdr, rqstp, res);
@@ -213,6 +213,11 @@ struct nfs_server {
of change attribute, size, ctime
and mtime attributes supported by
the server */
+ u32 cache_consistency_bitmask_nl[3];
+ /* V4 bitmask representing the subset
+ of change attribute, size, ctime
+ and mtime attributes supported by
+ the server excluding label support */
u32 acl_bitmask; /* V4 bitmask representing the ACEs
that are supported on this
filesystem */
@@ -1139,6 +1139,8 @@ struct nfs4_readdir_res {
struct nfs4_sequence_res seq_res;
nfs4_verifier verifier;
unsigned int pgbase;
+ struct nfs_fattr *dir_attr;
+ const struct nfs_server *server;
};
struct nfs4_readlink {
For each batch of entries, track whether the directory has changed. We can use this information to better manage the cache when reading long directories. Signed-off-by: Benjamin Coddington <bcodding@redhat.com> --- fs/nfs/nfs42proc.c | 2 +- fs/nfs/nfs4proc.c | 29 +++++++++++++++++++++-------- fs/nfs/nfs4xdr.c | 6 ++++++ include/linux/nfs_fs_sb.h | 5 +++++ include/linux/nfs_xdr.h | 2 ++ 5 files changed, 35 insertions(+), 9 deletions(-)