@@ -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+
44734495static 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
45064545int 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
0 commit comments