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

Commit e4648aa4 authored by Olga Kornievskaia's avatar Olga Kornievskaia Committed by Anna Schumaker
Browse files

NFS recover from destination server reboot for copies



Mark the destination state to indicate a server-side copy is
happening. On detecting a reboot and recovering open state check
if any state is engaged in a server-side copy, if so, find the
copy and mark it and then signal the waiting thread. Upon wakeup,
if copy was marked then propage EAGAIN to the nfsd_copy_file_range
and restart the copy from scratch.

Signed-off-by: default avatarOlga Kornievskaia <kolga@netapp.com>
Signed-off-by: default avatarAnna Schumaker <Anna.Schumaker@Netapp.com>
parent 6b8d84e2
Loading
Loading
Loading
Loading
+13 −3
Original line number Diff line number Diff line
@@ -140,6 +140,7 @@ static int handle_async_copy(struct nfs42_copy_res *res,
	struct nfs4_copy_state *copy;
	int status = NFS4_OK;
	bool found_pending = false;
	struct nfs_open_context *ctx = nfs_file_open_context(dst);

	spin_lock(&server->nfs_client->cl_lock);
	list_for_each_entry(copy, &server->nfs_client->pending_cb_stateids,
@@ -163,6 +164,7 @@ static int handle_async_copy(struct nfs42_copy_res *res,
	}
	memcpy(&copy->stateid, &res->write_res.stateid, NFS4_STATEID_SIZE);
	init_completion(&copy->completion);
	copy->parent_state = ctx->state;

	list_add_tail(&copy->copies, &server->ss_copies);
	spin_unlock(&server->nfs_client->cl_lock);
@@ -172,15 +174,20 @@ static int handle_async_copy(struct nfs42_copy_res *res,
	list_del_init(&copy->copies);
	spin_unlock(&server->nfs_client->cl_lock);
	if (status == -ERESTARTSYS) {
		nfs42_do_offload_cancel_async(dst, &copy->stateid);
		kfree(copy);
		return status;
		goto out_cancel;
	} else if (copy->flags) {
		status = -EAGAIN;
		goto out_cancel;
	}
out:
	res->write_res.count = copy->count;
	memcpy(&res->write_res.verifier, &copy->verf, sizeof(copy->verf));
	status = -copy->error;

	kfree(copy);
	return status;
out_cancel:
	nfs42_do_offload_cancel_async(dst, &copy->stateid);
	kfree(copy);
	return status;
}
@@ -254,6 +261,9 @@ static ssize_t _nfs42_proc_copy(struct file *src,
		if (!res->commit_res.verf)
			return -ENOMEM;
	}
	set_bit(NFS_CLNT_DST_SSC_COPY_STATE,
		&dst_lock->open_context->state->flags);

	status = nfs4_call_sync(server->client, server, &msg,
				&args->seq_args, &res->seq_res, 0);
	if (status == -ENOTSUPP)
+3 −0
Original line number Diff line number Diff line
@@ -163,6 +163,9 @@ enum {
	NFS_STATE_RECOVERY_FAILED,	/* OPEN stateid state recovery failed */
	NFS_STATE_MAY_NOTIFY_LOCK,	/* server may CB_NOTIFY_LOCK */
	NFS_STATE_CHANGE_WAIT,		/* A state changing operation is outstanding */
#ifdef CONFIG_NFS_V4_2
	NFS_CLNT_DST_SSC_COPY_STATE,    /* dst server open state on client*/
#endif /* CONFIG_NFS_V4_2 */
};

struct nfs4_state {
+7 −2
Original line number Diff line number Diff line
@@ -133,10 +133,15 @@ static ssize_t nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
				    struct file *file_out, loff_t pos_out,
				    size_t count, unsigned int flags)
{
	ssize_t ret;

	if (file_inode(file_in) == file_inode(file_out))
		return -EINVAL;

	return nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count);
retry:
	ret = nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count);
	if (ret == -EAGAIN)
		goto retry;
	return ret;
}

static loff_t nfs4_file_llseek(struct file *filep, loff_t offset, int whence)
+16 −0
Original line number Diff line number Diff line
@@ -1589,6 +1589,22 @@ static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs
				}
				clear_bit(NFS_STATE_RECLAIM_NOGRACE,
					&state->flags);
#ifdef CONFIG_NFS_V4_2
				if (test_bit(NFS_CLNT_DST_SSC_COPY_STATE, &state->flags)) {
					struct nfs4_copy_state *copy;

					spin_lock(&sp->so_server->nfs_client->cl_lock);
					list_for_each_entry(copy, &sp->so_server->ss_copies, copies) {
						if (memcmp(&state->stateid.other, &copy->parent_state->stateid.other, NFS4_STATEID_SIZE))
							continue;
						copy->flags = 1;
						complete(&copy->completion);
						printk("AGLO: server rebooted waking up the copy\n");
						break;
					}
					spin_unlock(&sp->so_server->nfs_client->cl_lock);
				}
#endif /* CONFIG_NFS_V4_2 */
				nfs4_put_open_state(state);
				spin_lock(&sp->so_lock);
				goto restart;
+2 −0
Original line number Diff line number Diff line
@@ -192,6 +192,8 @@ struct nfs4_copy_state {
	uint64_t		count;
	struct nfs_writeverf	verf;
	int			error;
	int			flags;
	struct nfs4_state	*parent_state;
};

/*