Commit 156b0948 authored by Anna Schumaker's avatar Anna Schumaker Committed by Trond Myklebust
Browse files

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: default avatarAnna Schumaker <anna.schumaker@oracle.com>
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
parent 130ae65c
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -379,6 +379,7 @@ nfs_detach_delegation_locked(struct nfs_inode *nfsi,
	delegation->inode = NULL;
	rcu_assign_pointer(nfsi->delegation, NULL);
	spin_unlock(&delegation->lock);
	clear_bit(NFS_INO_REQ_DIR_DELEG, &nfsi->flags);
	return delegation;
}

+6 −0
Original line number Diff line number Diff line
@@ -124,6 +124,12 @@ static inline int nfs_have_delegated_mtime(struct inode *inode)
						 NFS_DELEGATION_FLAG_TIME);
}

static inline void nfs_request_directory_delegation(struct inode *inode)
{
	if (S_ISDIR(inode->i_mode))
		set_bit(NFS_INO_REQ_DIR_DELEG, &NFS_I(inode)->flags);
}

int nfs4_delegation_hash_alloc(struct nfs_server *server);

#endif
+51 −4
Original line number Diff line number Diff line
@@ -4470,6 +4470,28 @@ static int nfs4_get_referral(struct rpc_clnt *client, struct inode *dir,
	return status;
}

#if IS_ENABLED(CONFIG_NFS_V4_1)
static bool should_request_dir_deleg(struct inode *inode)
{
	if (!inode)
		return false;
	if (!S_ISDIR(inode->i_mode))
		return false;
	if (!nfs_server_capable(inode, NFS_CAP_DIR_DELEG))
		return false;
	if (!test_and_clear_bit(NFS_INO_REQ_DIR_DELEG, &(NFS_I(inode)->flags)))
		return false;
	if (nfs4_have_delegation(inode, FMODE_READ, 0))
		return false;
	return true;
}
#else
static bool should_request_dir_deleg(struct inode *inode)
{
	return false;
}
#endif /* CONFIG_NFS_V4_1 */

static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
				struct nfs_fattr *fattr, struct inode *inode)
{
@@ -4487,7 +4509,9 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
		.rpc_argp = &args,
		.rpc_resp = &res,
	};
	struct nfs4_gdd_res gdd_res;
	unsigned short task_flags = 0;
	int status;

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

	args.get_dir_deleg = should_request_dir_deleg(inode);
	if (args.get_dir_deleg)
		res.gdd_res = &gdd_res;

	nfs4_bitmap_copy_adjust(bitmask, nfs4_bitmask(server, fattr->label), inode, 0);
	nfs_fattr_init(fattr);
	nfs4_init_sequence(&args.seq_args, &res.seq_res, 0, 0);
	return nfs4_do_call_sync(server->client, server, &msg,

	status = nfs4_do_call_sync(server->client, server, &msg,
				   &args.seq_args, &res.seq_res, task_flags);
	if (args.get_dir_deleg) {
		if (status == -EOPNOTSUPP) {
			server->caps &= ~NFS_CAP_DIR_DELEG;
		} else if (status == 0 && gdd_res.status == GDD4_OK) {
			status = nfs_inode_set_delegation(inode, current_cred(),
							  FMODE_READ, &gdd_res.deleg,
							  0, NFS4_OPEN_DELEGATE_READ);
		}
	}
	return status;
}

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,
	do {
		err = _nfs4_proc_getattr(server, fhandle, fattr, inode);
		trace_nfs4_getattr(server, fhandle, fattr, err);
		err = nfs4_handle_exception(server, err,
				&exception);
		if (err == -EOPNOTSUPP)
			exception.retry = true;
		else
			err = nfs4_handle_exception(server, err, &exception);
	} while (exception.retry);
	return err;
}
@@ -4778,6 +4819,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
	int status = 0;

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

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

	nfs_request_directory_delegation(dir);

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

	nfs_fattr_init(res->dir_attr);
	nfs_request_directory_delegation(d_inode(dentry->d_parent));

	if (inode) {
		nfs4_inode_return_delegation(inode);
@@ -10832,6 +10877,7 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = {
	.minor_version = 1,
	.init_caps = NFS_CAP_READDIRPLUS
		| NFS_CAP_ATOMIC_OPEN
		| NFS_CAP_DIR_DELEG
		| NFS_CAP_POSIX_LOCK
		| NFS_CAP_STATEID_NFSV41
		| NFS_CAP_ATOMIC_OPEN_V1
@@ -10858,6 +10904,7 @@ static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = {
	.minor_version = 2,
	.init_caps = NFS_CAP_READDIRPLUS
		| NFS_CAP_ATOMIC_OPEN
		| NFS_CAP_DIR_DELEG
		| NFS_CAP_POSIX_LOCK
		| NFS_CAP_STATEID_NFSV41
		| NFS_CAP_ATOMIC_OPEN_V1
+1 −0
Original line number Diff line number Diff line
@@ -344,6 +344,7 @@ struct nfs4_copy_state {
#define NFS_INO_LAYOUTCOMMITTING (10)		/* layoutcommit inflight */
#define NFS_INO_LAYOUTSTATS	(11)		/* layoutstats inflight */
#define NFS_INO_ODIRECT		(12)		/* I/O setting is O_DIRECT */
#define NFS_INO_REQ_DIR_DELEG	(13)		/* Request a directory delegation */

static inline struct nfs_inode *NFS_I(const struct inode *inode)
{
+1 −0
Original line number Diff line number Diff line
@@ -305,6 +305,7 @@ struct nfs_server {
#define NFS_CAP_REBOOT_LAYOUTRETURN	(1U << 8)
#define NFS_CAP_OFFLOAD_STATUS	(1U << 9)
#define NFS_CAP_ZERO_RANGE	(1U << 10)
#define NFS_CAP_DIR_DELEG	(1U << 11)
#define NFS_CAP_OPEN_XOR	(1U << 12)
#define NFS_CAP_DELEGTIME	(1U << 13)
#define NFS_CAP_POSIX_LOCK	(1U << 14)