Commit 7776aaac authored by Trond Myklebust's avatar Trond Myklebust Committed by Greg Kroah-Hartman

NFSv4: Fix reboot recovery in copy offload

commit 9d8cacbf upstream.

Copy offload code needs to be hooked into the code for handling
NFS4ERR_BAD_STATEID by ensuring that we set the "stateid" field
in struct nfs4_exception.
Reported-by: default avatarOlga Kornievskaia <aglo@umich.edu>
Fixes: 2e72448b ("NFS: Add COPY nfs operation")
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@primarydata.com>
Signed-off-by: default avatarAnna Schumaker <Anna.Schumaker@Netapp.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 607137e3
...@@ -128,30 +128,26 @@ int nfs42_proc_deallocate(struct file *filep, loff_t offset, loff_t len) ...@@ -128,30 +128,26 @@ int nfs42_proc_deallocate(struct file *filep, loff_t offset, loff_t len)
return err; return err;
} }
static ssize_t _nfs42_proc_copy(struct file *src, loff_t pos_src, static ssize_t _nfs42_proc_copy(struct file *src,
struct nfs_lock_context *src_lock, struct nfs_lock_context *src_lock,
struct file *dst, loff_t pos_dst, struct file *dst,
struct nfs_lock_context *dst_lock, struct nfs_lock_context *dst_lock,
size_t count) struct nfs42_copy_args *args,
struct nfs42_copy_res *res)
{ {
struct nfs42_copy_args args = {
.src_fh = NFS_FH(file_inode(src)),
.src_pos = pos_src,
.dst_fh = NFS_FH(file_inode(dst)),
.dst_pos = pos_dst,
.count = count,
};
struct nfs42_copy_res res;
struct rpc_message msg = { struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COPY], .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COPY],
.rpc_argp = &args, .rpc_argp = args,
.rpc_resp = &res, .rpc_resp = res,
}; };
struct inode *dst_inode = file_inode(dst); struct inode *dst_inode = file_inode(dst);
struct nfs_server *server = NFS_SERVER(dst_inode); struct nfs_server *server = NFS_SERVER(dst_inode);
loff_t pos_src = args->src_pos;
loff_t pos_dst = args->dst_pos;
size_t count = args->count;
int status; int status;
status = nfs4_set_rw_stateid(&args.src_stateid, src_lock->open_context, status = nfs4_set_rw_stateid(&args->src_stateid, src_lock->open_context,
src_lock, FMODE_READ); src_lock, FMODE_READ);
if (status) if (status)
return status; return status;
...@@ -161,7 +157,7 @@ static ssize_t _nfs42_proc_copy(struct file *src, loff_t pos_src, ...@@ -161,7 +157,7 @@ static ssize_t _nfs42_proc_copy(struct file *src, loff_t pos_src,
if (status) if (status)
return status; return status;
status = nfs4_set_rw_stateid(&args.dst_stateid, dst_lock->open_context, status = nfs4_set_rw_stateid(&args->dst_stateid, dst_lock->open_context,
dst_lock, FMODE_WRITE); dst_lock, FMODE_WRITE);
if (status) if (status)
return status; return status;
...@@ -171,22 +167,22 @@ static ssize_t _nfs42_proc_copy(struct file *src, loff_t pos_src, ...@@ -171,22 +167,22 @@ static ssize_t _nfs42_proc_copy(struct file *src, loff_t pos_src,
return status; return status;
status = nfs4_call_sync(server->client, server, &msg, status = nfs4_call_sync(server->client, server, &msg,
&args.seq_args, &res.seq_res, 0); &args->seq_args, &res->seq_res, 0);
if (status == -ENOTSUPP) if (status == -ENOTSUPP)
server->caps &= ~NFS_CAP_COPY; server->caps &= ~NFS_CAP_COPY;
if (status) if (status)
return status; return status;
if (res.write_res.verifier.committed != NFS_FILE_SYNC) { if (res->write_res.verifier.committed != NFS_FILE_SYNC) {
status = nfs_commit_file(dst, &res.write_res.verifier.verifier); status = nfs_commit_file(dst, &res->write_res.verifier.verifier);
if (status) if (status)
return status; return status;
} }
truncate_pagecache_range(dst_inode, pos_dst, truncate_pagecache_range(dst_inode, pos_dst,
pos_dst + res.write_res.count); pos_dst + res->write_res.count);
return res.write_res.count; return res->write_res.count;
} }
ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src, ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
...@@ -196,8 +192,22 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src, ...@@ -196,8 +192,22 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
struct nfs_server *server = NFS_SERVER(file_inode(dst)); struct nfs_server *server = NFS_SERVER(file_inode(dst));
struct nfs_lock_context *src_lock; struct nfs_lock_context *src_lock;
struct nfs_lock_context *dst_lock; struct nfs_lock_context *dst_lock;
struct nfs4_exception src_exception = { }; struct nfs42_copy_args args = {
struct nfs4_exception dst_exception = { }; .src_fh = NFS_FH(file_inode(src)),
.src_pos = pos_src,
.dst_fh = NFS_FH(file_inode(dst)),
.dst_pos = pos_dst,
.count = count,
};
struct nfs42_copy_res res;
struct nfs4_exception src_exception = {
.inode = file_inode(src),
.stateid = &args.src_stateid,
};
struct nfs4_exception dst_exception = {
.inode = file_inode(dst),
.stateid = &args.dst_stateid,
};
ssize_t err, err2; ssize_t err, err2;
if (!nfs_server_capable(file_inode(dst), NFS_CAP_COPY)) if (!nfs_server_capable(file_inode(dst), NFS_CAP_COPY))
...@@ -207,7 +217,6 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src, ...@@ -207,7 +217,6 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
if (IS_ERR(src_lock)) if (IS_ERR(src_lock))
return PTR_ERR(src_lock); return PTR_ERR(src_lock);
src_exception.inode = file_inode(src);
src_exception.state = src_lock->open_context->state; src_exception.state = src_lock->open_context->state;
dst_lock = nfs_get_lock_context(nfs_file_open_context(dst)); dst_lock = nfs_get_lock_context(nfs_file_open_context(dst));
...@@ -216,15 +225,17 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src, ...@@ -216,15 +225,17 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
goto out_put_src_lock; goto out_put_src_lock;
} }
dst_exception.inode = file_inode(dst);
dst_exception.state = dst_lock->open_context->state; dst_exception.state = dst_lock->open_context->state;
do { do {
inode_lock(file_inode(dst)); inode_lock(file_inode(dst));
err = _nfs42_proc_copy(src, pos_src, src_lock, err = _nfs42_proc_copy(src, src_lock,
dst, pos_dst, dst_lock, count); dst, dst_lock,
&args, &res);
inode_unlock(file_inode(dst)); inode_unlock(file_inode(dst));
if (err >= 0)
break;
if (err == -ENOTSUPP) { if (err == -ENOTSUPP) {
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
break; break;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment