Commit 17c2f540 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull NFS client bugfixes from Trond Myklebust:

 - Fix a NFSv4 state manager deadlock when returning a delegation

 - NFSv4.2 copy do not allocate memory under the lock

 - flexfiles: Use the correct stateid for IO in the tightly coupled case

* tag 'nfs-for-4.20-4' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
  flexfiles: use per-mirror specified stateid for IO
  NFSv4.2 copy do not allocate memory under the lock
  NFSv4: Fix a NFSv4 state manager deadlock
parents 4e962ff6 bb21ce0a
Loading
Loading
Loading
Loading
+11 −11
Original line number Diff line number Diff line
@@ -686,20 +686,24 @@ __be32 nfs4_callback_offload(void *data, void *dummy,
{
	struct cb_offloadargs *args = data;
	struct nfs_server *server;
	struct nfs4_copy_state *copy;
	struct nfs4_copy_state *copy, *tmp_copy;
	bool found = false;

	copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_NOFS);
	if (!copy)
		return htonl(NFS4ERR_SERVERFAULT);

	spin_lock(&cps->clp->cl_lock);
	rcu_read_lock();
	list_for_each_entry_rcu(server, &cps->clp->cl_superblocks,
				client_link) {
		list_for_each_entry(copy, &server->ss_copies, copies) {
		list_for_each_entry(tmp_copy, &server->ss_copies, copies) {
			if (memcmp(args->coa_stateid.other,
					copy->stateid.other,
					tmp_copy->stateid.other,
					sizeof(args->coa_stateid.other)))
				continue;
			nfs4_copy_cb_args(copy, args);
			complete(&copy->completion);
			nfs4_copy_cb_args(tmp_copy, args);
			complete(&tmp_copy->completion);
			found = true;
			goto out;
		}
@@ -707,15 +711,11 @@ __be32 nfs4_callback_offload(void *data, void *dummy,
out:
	rcu_read_unlock();
	if (!found) {
		copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_NOFS);
		if (!copy) {
			spin_unlock(&cps->clp->cl_lock);
			return htonl(NFS4ERR_SERVERFAULT);
		}
		memcpy(&copy->stateid, &args->coa_stateid, NFS4_STATEID_SIZE);
		nfs4_copy_cb_args(copy, args);
		list_add_tail(&copy->copies, &cps->clp->pending_cb_stateids);
	}
	} else
		kfree(copy);
	spin_unlock(&cps->clp->cl_lock);

	return 0;
+9 −12
Original line number Diff line number Diff line
@@ -1361,12 +1361,7 @@ static void ff_layout_read_prepare_v4(struct rpc_task *task, void *data)
				task))
		return;

	if (ff_layout_read_prepare_common(task, hdr))
		return;

	if (nfs4_set_rw_stateid(&hdr->args.stateid, hdr->args.context,
			hdr->args.lock_context, FMODE_READ) == -EIO)
		rpc_exit(task, -EIO); /* lost lock, terminate I/O */
	ff_layout_read_prepare_common(task, hdr);
}

static void ff_layout_read_call_done(struct rpc_task *task, void *data)
@@ -1542,12 +1537,7 @@ static void ff_layout_write_prepare_v4(struct rpc_task *task, void *data)
				task))
		return;

	if (ff_layout_write_prepare_common(task, hdr))
		return;

	if (nfs4_set_rw_stateid(&hdr->args.stateid, hdr->args.context,
			hdr->args.lock_context, FMODE_WRITE) == -EIO)
		rpc_exit(task, -EIO); /* lost lock, terminate I/O */
	ff_layout_write_prepare_common(task, hdr);
}

static void ff_layout_write_call_done(struct rpc_task *task, void *data)
@@ -1742,6 +1732,10 @@ ff_layout_read_pagelist(struct nfs_pgio_header *hdr)
	fh = nfs4_ff_layout_select_ds_fh(lseg, idx);
	if (fh)
		hdr->args.fh = fh;

	if (!nfs4_ff_layout_select_ds_stateid(lseg, idx, &hdr->args.stateid))
		goto out_failed;

	/*
	 * Note that if we ever decide to split across DSes,
	 * then we may need to handle dense-like offsets.
@@ -1804,6 +1798,9 @@ ff_layout_write_pagelist(struct nfs_pgio_header *hdr, int sync)
	if (fh)
		hdr->args.fh = fh;

	if (!nfs4_ff_layout_select_ds_stateid(lseg, idx, &hdr->args.stateid))
		goto out_failed;

	/*
	 * Note that if we ever decide to split across DSes,
	 * then we may need to handle dense-like offsets.
+4 −0
Original line number Diff line number Diff line
@@ -215,6 +215,10 @@ unsigned int ff_layout_fetch_ds_ioerr(struct pnfs_layout_hdr *lo,
		unsigned int maxnum);
struct nfs_fh *
nfs4_ff_layout_select_ds_fh(struct pnfs_layout_segment *lseg, u32 mirror_idx);
int
nfs4_ff_layout_select_ds_stateid(struct pnfs_layout_segment *lseg,
				u32 mirror_idx,
				nfs4_stateid *stateid);

struct nfs4_pnfs_ds *
nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx,
+19 −0
Original line number Diff line number Diff line
@@ -370,6 +370,25 @@ out:
	return fh;
}

int
nfs4_ff_layout_select_ds_stateid(struct pnfs_layout_segment *lseg,
				u32 mirror_idx,
				nfs4_stateid *stateid)
{
	struct nfs4_ff_layout_mirror *mirror = FF_LAYOUT_COMP(lseg, mirror_idx);

	if (!ff_layout_mirror_valid(lseg, mirror, false)) {
		pr_err_ratelimited("NFS: %s: No data server for mirror offset index %d\n",
			__func__, mirror_idx);
		goto out;
	}

	nfs4_stateid_copy(stateid, &mirror->stateid);
	return 1;
out:
	return 0;
}

/**
 * nfs4_ff_layout_prepare_ds - prepare a DS connection for an RPC call
 * @lseg: the layout segment we're operating on
+10 −9
Original line number Diff line number Diff line
@@ -137,31 +137,32 @@ static int handle_async_copy(struct nfs42_copy_res *res,
			     struct file *dst,
			     nfs4_stateid *src_stateid)
{
	struct nfs4_copy_state *copy;
	struct nfs4_copy_state *copy, *tmp_copy;
	int status = NFS4_OK;
	bool found_pending = false;
	struct nfs_open_context *ctx = nfs_file_open_context(dst);

	copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_NOFS);
	if (!copy)
		return -ENOMEM;

	spin_lock(&server->nfs_client->cl_lock);
	list_for_each_entry(copy, &server->nfs_client->pending_cb_stateids,
	list_for_each_entry(tmp_copy, &server->nfs_client->pending_cb_stateids,
				copies) {
		if (memcmp(&res->write_res.stateid, &copy->stateid,
		if (memcmp(&res->write_res.stateid, &tmp_copy->stateid,
				NFS4_STATEID_SIZE))
			continue;
		found_pending = true;
		list_del(&copy->copies);
		list_del(&tmp_copy->copies);
		break;
	}
	if (found_pending) {
		spin_unlock(&server->nfs_client->cl_lock);
		kfree(copy);
		copy = tmp_copy;
		goto out;
	}

	copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_NOFS);
	if (!copy) {
		spin_unlock(&server->nfs_client->cl_lock);
		return -ENOMEM;
	}
	memcpy(&copy->stateid, &res->write_res.stateid, NFS4_STATEID_SIZE);
	init_completion(&copy->completion);
	copy->parent_state = ctx->state;
Loading