Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ea7c38fe authored by Trond Myklebust's avatar Trond Myklebust
Browse files

NFSv4: Ensure we reference the inode for return-on-close in delegreturn



If we have to do a return-on-close in the delegreturn code, then
we must ensure that the inode and super block remain referenced.

Cc: Peng Tao <tao.peng@primarydata.com>
Cc: stable@vger.kernel.org # 3.17.x
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@primarydata.com>
Reviewed-by: default avatarPeng Tao <tao.peng@primarydata.com>
parent 6ae37339
Loading
Loading
Loading
Loading
+21 −1
Original line number Diff line number Diff line
@@ -391,7 +391,7 @@ extern struct rpc_stat nfs_rpcstat;

extern int __init register_nfs_fs(void);
extern void __exit unregister_nfs_fs(void);
extern void nfs_sb_active(struct super_block *sb);
extern bool nfs_sb_active(struct super_block *sb);
extern void nfs_sb_deactive(struct super_block *sb);

/* namespace.c */
@@ -514,6 +514,26 @@ extern int nfs41_walk_client_list(struct nfs_client *clp,
				struct nfs_client **result,
				struct rpc_cred *cred);

static inline struct inode *nfs_igrab_and_active(struct inode *inode)
{
	inode = igrab(inode);
	if (inode != NULL && !nfs_sb_active(inode->i_sb)) {
		iput(inode);
		inode = NULL;
	}
	return inode;
}

static inline void nfs_iput_and_deactive(struct inode *inode)
{
	if (inode != NULL) {
		struct super_block *sb = inode->i_sb;

		iput(inode);
		nfs_sb_deactive(sb);
	}
}

/*
 * Determine the device name as a string
 */
+9 −5
Original line number Diff line number Diff line
@@ -5175,9 +5175,13 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
static void nfs4_delegreturn_release(void *calldata)
{
	struct nfs4_delegreturndata *data = calldata;
	struct inode *inode = data->inode;

	if (inode) {
		if (data->roc)
		pnfs_roc_release(data->inode);
			pnfs_roc_release(inode);
		nfs_iput_and_deactive(inode);
	}
	kfree(calldata);
}

@@ -5234,9 +5238,9 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
	nfs_fattr_init(data->res.fattr);
	data->timestamp = jiffies;
	data->rpc_status = 0;
	data->inode = inode;
	data->roc = list_empty(&NFS_I(inode)->open_files) ?
		    pnfs_roc(inode) : false;
	data->inode = nfs_igrab_and_active(inode);
	if (data->inode)
		data->roc = nfs4_roc(inode);

	task_setup_data.callback_data = data;
	msg.rpc_argp = &data->args;
+6 −3
Original line number Diff line number Diff line
@@ -405,12 +405,15 @@ void __exit unregister_nfs_fs(void)
	unregister_filesystem(&nfs_fs_type);
}

void nfs_sb_active(struct super_block *sb)
bool nfs_sb_active(struct super_block *sb)
{
	struct nfs_server *server = NFS_SB(sb);

	if (atomic_inc_return(&server->active) == 1)
		atomic_inc(&sb->s_active);
	if (!atomic_inc_not_zero(&sb->s_active))
		return false;
	if (atomic_inc_return(&server->active) != 1)
		atomic_dec(&sb->s_active);
	return true;
}
EXPORT_SYMBOL_GPL(nfs_sb_active);