Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Anna Schumaker and committed by
Trond Myklebust
156b0948 130ae65c

+60 -4
+1
fs/nfs/delegation.c
··· 379 379 delegation->inode = NULL; 380 380 rcu_assign_pointer(nfsi->delegation, NULL); 381 381 spin_unlock(&delegation->lock); 382 + clear_bit(NFS_INO_REQ_DIR_DELEG, &nfsi->flags); 382 383 return delegation; 383 384 } 384 385
+6
fs/nfs/delegation.h
··· 124 124 NFS_DELEGATION_FLAG_TIME); 125 125 } 126 126 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 + 127 133 int nfs4_delegation_hash_alloc(struct nfs_server *server); 128 134 129 135 #endif
+51 -4
fs/nfs/nfs4proc.c
··· 4470 4470 return status; 4471 4471 } 4472 4472 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 + 4473 4495 static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, 4474 4496 struct nfs_fattr *fattr, struct inode *inode) 4475 4497 { ··· 4509 4487 .rpc_argp = &args, 4510 4488 .rpc_resp = &res, 4511 4489 }; 4490 + struct nfs4_gdd_res gdd_res; 4512 4491 unsigned short task_flags = 0; 4492 + int status; 4513 4493 4514 4494 if (nfs4_has_session(server->nfs_client)) 4515 4495 task_flags = RPC_TASK_MOVEABLE; ··· 4520 4496 if (inode && (server->flags & NFS_MOUNT_SOFTREVAL)) 4521 4497 task_flags |= RPC_TASK_TIMEOUT; 4522 4498 4499 + args.get_dir_deleg = should_request_dir_deleg(inode); 4500 + if (args.get_dir_deleg) 4501 + res.gdd_res = &gdd_res; 4502 + 4523 4503 nfs4_bitmap_copy_adjust(bitmask, nfs4_bitmask(server, fattr->label), inode, 0); 4524 4504 nfs_fattr_init(fattr); 4525 4505 nfs4_init_sequence(&args.seq_args, &res.seq_res, 0, 0); 4526 - return nfs4_do_call_sync(server->client, server, &msg, 4527 - &args.seq_args, &res.seq_res, task_flags); 4506 + 4507 + status = nfs4_do_call_sync(server->client, server, &msg, 4508 + &args.seq_args, &res.seq_res, task_flags); 4509 + if (args.get_dir_deleg) { 4510 + if (status == -EOPNOTSUPP) { 4511 + server->caps &= ~NFS_CAP_DIR_DELEG; 4512 + } else if (status == 0 && gdd_res.status == GDD4_OK) { 4513 + status = nfs_inode_set_delegation(inode, current_cred(), 4514 + FMODE_READ, &gdd_res.deleg, 4515 + 0, NFS4_OPEN_DELEGATE_READ); 4516 + } 4517 + } 4518 + return status; 4528 4519 } 4529 4520 4530 4521 int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, ··· 4552 4513 do { 4553 4514 err = _nfs4_proc_getattr(server, fhandle, fattr, inode); 4554 4515 trace_nfs4_getattr(server, fhandle, fattr, err); 4555 - err = nfs4_handle_exception(server, err, 4556 - &exception); 4516 + if (err == -EOPNOTSUPP) 4517 + exception.retry = true; 4518 + else 4519 + err = nfs4_handle_exception(server, err, &exception); 4557 4520 } while (exception.retry); 4558 4521 return err; 4559 4522 } ··· 4819 4778 int status = 0; 4820 4779 4821 4780 if (!nfs4_have_delegation(inode, FMODE_READ, 0)) { 4781 + nfs_request_directory_delegation(inode); 4822 4782 res.fattr = nfs_alloc_fattr(); 4823 4783 if (res.fattr == NULL) 4824 4784 return -ENOMEM; ··· 4927 4885 4928 4886 ilabel = nfs4_label_init_security(dir, dentry, sattr, &l); 4929 4887 4888 + nfs_request_directory_delegation(dir); 4889 + 4930 4890 if (!(server->attr_bitmask[2] & FATTR4_WORD2_MODE_UMASK)) 4931 4891 sattr->ia_mode &= ~current_umask(); 4932 4892 state = nfs4_do_open(dir, ctx, flags, sattr, ilabel, NULL); ··· 5025 4981 nfs4_init_sequence(&args->seq_args, &res->seq_res, 1, 0); 5026 4982 5027 4983 nfs_fattr_init(res->dir_attr); 4984 + nfs_request_directory_delegation(d_inode(dentry->d_parent)); 5028 4985 5029 4986 if (inode) { 5030 4987 nfs4_inode_return_delegation(inode); ··· 10877 10832 .minor_version = 1, 10878 10833 .init_caps = NFS_CAP_READDIRPLUS 10879 10834 | NFS_CAP_ATOMIC_OPEN 10835 + | NFS_CAP_DIR_DELEG 10880 10836 | NFS_CAP_POSIX_LOCK 10881 10837 | NFS_CAP_STATEID_NFSV41 10882 10838 | NFS_CAP_ATOMIC_OPEN_V1 ··· 10904 10858 .minor_version = 2, 10905 10859 .init_caps = NFS_CAP_READDIRPLUS 10906 10860 | NFS_CAP_ATOMIC_OPEN 10861 + | NFS_CAP_DIR_DELEG 10907 10862 | NFS_CAP_POSIX_LOCK 10908 10863 | NFS_CAP_STATEID_NFSV41 10909 10864 | NFS_CAP_ATOMIC_OPEN_V1
+1
include/linux/nfs_fs.h
··· 344 344 #define NFS_INO_LAYOUTCOMMITTING (10) /* layoutcommit inflight */ 345 345 #define NFS_INO_LAYOUTSTATS (11) /* layoutstats inflight */ 346 346 #define NFS_INO_ODIRECT (12) /* I/O setting is O_DIRECT */ 347 + #define NFS_INO_REQ_DIR_DELEG (13) /* Request a directory delegation */ 347 348 348 349 static inline struct nfs_inode *NFS_I(const struct inode *inode) 349 350 {
+1
include/linux/nfs_fs_sb.h
··· 305 305 #define NFS_CAP_REBOOT_LAYOUTRETURN (1U << 8) 306 306 #define NFS_CAP_OFFLOAD_STATUS (1U << 9) 307 307 #define NFS_CAP_ZERO_RANGE (1U << 10) 308 + #define NFS_CAP_DIR_DELEG (1U << 11) 308 309 #define NFS_CAP_OPEN_XOR (1U << 12) 309 310 #define NFS_CAP_DELEGTIME (1U << 13) 310 311 #define NFS_CAP_POSIX_LOCK (1U << 14)