Skip to content

Commit 156b094

Browse files
Anna SchumakerTrond Myklebust
authored andcommitted
NFS: Request a directory delegation on ACCESS, CREATE, and UNLINK
This patch adds a new flag: NFS_INO_REQ_DIR_DELEG to signal that a directory wants to request a directory delegation the next time it does a GETATTR. I have the client request a directory delegation when doing an access, create, or unlink call since these calls indicate that a user is working with a directory. Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com> Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
1 parent 130ae65 commit 156b094

5 files changed

Lines changed: 60 additions & 4 deletions

File tree

fs/nfs/delegation.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,7 @@ nfs_detach_delegation_locked(struct nfs_inode *nfsi,
379379
delegation->inode = NULL;
380380
rcu_assign_pointer(nfsi->delegation, NULL);
381381
spin_unlock(&delegation->lock);
382+
clear_bit(NFS_INO_REQ_DIR_DELEG, &nfsi->flags);
382383
return delegation;
383384
}
384385

fs/nfs/delegation.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,12 @@ static inline int nfs_have_delegated_mtime(struct inode *inode)
124124
NFS_DELEGATION_FLAG_TIME);
125125
}
126126

127+
static inline void nfs_request_directory_delegation(struct inode *inode)
128+
{
129+
if (S_ISDIR(inode->i_mode))
130+
set_bit(NFS_INO_REQ_DIR_DELEG, &NFS_I(inode)->flags);
131+
}
132+
127133
int nfs4_delegation_hash_alloc(struct nfs_server *server);
128134

129135
#endif

fs/nfs/nfs4proc.c

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4470,6 +4470,28 @@ static int nfs4_get_referral(struct rpc_clnt *client, struct inode *dir,
44704470
return status;
44714471
}
44724472

4473+
#if IS_ENABLED(CONFIG_NFS_V4_1)
4474+
static bool should_request_dir_deleg(struct inode *inode)
4475+
{
4476+
if (!inode)
4477+
return false;
4478+
if (!S_ISDIR(inode->i_mode))
4479+
return false;
4480+
if (!nfs_server_capable(inode, NFS_CAP_DIR_DELEG))
4481+
return false;
4482+
if (!test_and_clear_bit(NFS_INO_REQ_DIR_DELEG, &(NFS_I(inode)->flags)))
4483+
return false;
4484+
if (nfs4_have_delegation(inode, FMODE_READ, 0))
4485+
return false;
4486+
return true;
4487+
}
4488+
#else
4489+
static bool should_request_dir_deleg(struct inode *inode)
4490+
{
4491+
return false;
4492+
}
4493+
#endif /* CONFIG_NFS_V4_1 */
4494+
44734495
static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
44744496
struct nfs_fattr *fattr, struct inode *inode)
44754497
{
@@ -4487,7 +4509,9 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
44874509
.rpc_argp = &args,
44884510
.rpc_resp = &res,
44894511
};
4512+
struct nfs4_gdd_res gdd_res;
44904513
unsigned short task_flags = 0;
4514+
int status;
44914515

44924516
if (nfs4_has_session(server->nfs_client))
44934517
task_flags = RPC_TASK_MOVEABLE;
@@ -4496,11 +4520,26 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
44964520
if (inode && (server->flags & NFS_MOUNT_SOFTREVAL))
44974521
task_flags |= RPC_TASK_TIMEOUT;
44984522

4523+
args.get_dir_deleg = should_request_dir_deleg(inode);
4524+
if (args.get_dir_deleg)
4525+
res.gdd_res = &gdd_res;
4526+
44994527
nfs4_bitmap_copy_adjust(bitmask, nfs4_bitmask(server, fattr->label), inode, 0);
45004528
nfs_fattr_init(fattr);
45014529
nfs4_init_sequence(&args.seq_args, &res.seq_res, 0, 0);
4502-
return nfs4_do_call_sync(server->client, server, &msg,
4503-
&args.seq_args, &res.seq_res, task_flags);
4530+
4531+
status = nfs4_do_call_sync(server->client, server, &msg,
4532+
&args.seq_args, &res.seq_res, task_flags);
4533+
if (args.get_dir_deleg) {
4534+
if (status == -EOPNOTSUPP) {
4535+
server->caps &= ~NFS_CAP_DIR_DELEG;
4536+
} else if (status == 0 && gdd_res.status == GDD4_OK) {
4537+
status = nfs_inode_set_delegation(inode, current_cred(),
4538+
FMODE_READ, &gdd_res.deleg,
4539+
0, NFS4_OPEN_DELEGATE_READ);
4540+
}
4541+
}
4542+
return status;
45044543
}
45054544

45064545
int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
@@ -4513,8 +4552,10 @@ int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
45134552
do {
45144553
err = _nfs4_proc_getattr(server, fhandle, fattr, inode);
45154554
trace_nfs4_getattr(server, fhandle, fattr, err);
4516-
err = nfs4_handle_exception(server, err,
4517-
&exception);
4555+
if (err == -EOPNOTSUPP)
4556+
exception.retry = true;
4557+
else
4558+
err = nfs4_handle_exception(server, err, &exception);
45184559
} while (exception.retry);
45194560
return err;
45204561
}
@@ -4778,6 +4819,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
47784819
int status = 0;
47794820

47804821
if (!nfs4_have_delegation(inode, FMODE_READ, 0)) {
4822+
nfs_request_directory_delegation(inode);
47814823
res.fattr = nfs_alloc_fattr();
47824824
if (res.fattr == NULL)
47834825
return -ENOMEM;
@@ -4885,6 +4927,8 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
48854927

48864928
ilabel = nfs4_label_init_security(dir, dentry, sattr, &l);
48874929

4930+
nfs_request_directory_delegation(dir);
4931+
48884932
if (!(server->attr_bitmask[2] & FATTR4_WORD2_MODE_UMASK))
48894933
sattr->ia_mode &= ~current_umask();
48904934
state = nfs4_do_open(dir, ctx, flags, sattr, ilabel, NULL);
@@ -4981,6 +5025,7 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg,
49815025
nfs4_init_sequence(&args->seq_args, &res->seq_res, 1, 0);
49825026

49835027
nfs_fattr_init(res->dir_attr);
5028+
nfs_request_directory_delegation(d_inode(dentry->d_parent));
49845029

49855030
if (inode) {
49865031
nfs4_inode_return_delegation(inode);
@@ -10832,6 +10877,7 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = {
1083210877
.minor_version = 1,
1083310878
.init_caps = NFS_CAP_READDIRPLUS
1083410879
| NFS_CAP_ATOMIC_OPEN
10880+
| NFS_CAP_DIR_DELEG
1083510881
| NFS_CAP_POSIX_LOCK
1083610882
| NFS_CAP_STATEID_NFSV41
1083710883
| NFS_CAP_ATOMIC_OPEN_V1
@@ -10858,6 +10904,7 @@ static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = {
1085810904
.minor_version = 2,
1085910905
.init_caps = NFS_CAP_READDIRPLUS
1086010906
| NFS_CAP_ATOMIC_OPEN
10907+
| NFS_CAP_DIR_DELEG
1086110908
| NFS_CAP_POSIX_LOCK
1086210909
| NFS_CAP_STATEID_NFSV41
1086310910
| NFS_CAP_ATOMIC_OPEN_V1

include/linux/nfs_fs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,7 @@ struct nfs4_copy_state {
344344
#define NFS_INO_LAYOUTCOMMITTING (10) /* layoutcommit inflight */
345345
#define NFS_INO_LAYOUTSTATS (11) /* layoutstats inflight */
346346
#define NFS_INO_ODIRECT (12) /* I/O setting is O_DIRECT */
347+
#define NFS_INO_REQ_DIR_DELEG (13) /* Request a directory delegation */
347348

348349
static inline struct nfs_inode *NFS_I(const struct inode *inode)
349350
{

include/linux/nfs_fs_sb.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,7 @@ struct nfs_server {
305305
#define NFS_CAP_REBOOT_LAYOUTRETURN (1U << 8)
306306
#define NFS_CAP_OFFLOAD_STATUS (1U << 9)
307307
#define NFS_CAP_ZERO_RANGE (1U << 10)
308+
#define NFS_CAP_DIR_DELEG (1U << 11)
308309
#define NFS_CAP_OPEN_XOR (1U << 12)
309310
#define NFS_CAP_DELEGTIME (1U << 13)
310311
#define NFS_CAP_POSIX_LOCK (1U << 14)

0 commit comments

Comments
 (0)