diff options
| author | Trond Myklebust <trond.myklebust@primarydata.com> | 2017-02-17 18:42:32 -0500 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-03-12 00:41:51 -0500 |
| commit | 77bbc0c7712a43442e2637247eaa4f01f73f0eb8 (patch) | |
| tree | 63bd755f1f09592b6b63b3fc9dad4425063f3ac0 /fs/nfs | |
| parent | 0465339eb54953f0be1f03e980b07eeb01e16fca (diff) | |
NFSv4: Fix reboot recovery in copy offload
commit 9d8cacbf5636657d2cd0dda17438a56d806d3224 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: Olga Kornievskaia <aglo@umich.edu>
Fixes: 2e72448b07dc3 ("NFS: Add COPY nfs operation")
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs/nfs')
| -rw-r--r-- | fs/nfs/nfs42proc.c | 63 |
1 files changed, 37 insertions, 26 deletions
diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c index 608501971fe0..5cda392028ce 100644 --- a/fs/nfs/nfs42proc.c +++ b/fs/nfs/nfs42proc.c | |||
| @@ -128,30 +128,26 @@ out_unlock: | |||
| 128 | return err; | 128 | return err; |
| 129 | } | 129 | } |
| 130 | 130 | ||
| 131 | static ssize_t _nfs42_proc_copy(struct file *src, loff_t pos_src, | 131 | static ssize_t _nfs42_proc_copy(struct file *src, |
| 132 | struct nfs_lock_context *src_lock, | 132 | struct nfs_lock_context *src_lock, |
| 133 | struct file *dst, loff_t pos_dst, | 133 | struct file *dst, |
| 134 | struct nfs_lock_context *dst_lock, | 134 | struct nfs_lock_context *dst_lock, |
| 135 | size_t count) | 135 | struct nfs42_copy_args *args, |
| 136 | struct nfs42_copy_res *res) | ||
| 136 | { | 137 | { |
| 137 | struct nfs42_copy_args args = { | ||
| 138 | .src_fh = NFS_FH(file_inode(src)), | ||
| 139 | .src_pos = pos_src, | ||
| 140 | .dst_fh = NFS_FH(file_inode(dst)), | ||
| 141 | .dst_pos = pos_dst, | ||
| 142 | .count = count, | ||
| 143 | }; | ||
| 144 | struct nfs42_copy_res res; | ||
| 145 | struct rpc_message msg = { | 138 | struct rpc_message msg = { |
| 146 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COPY], | 139 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COPY], |
| 147 | .rpc_argp = &args, | 140 | .rpc_argp = args, |
| 148 | .rpc_resp = &res, | 141 | .rpc_resp = res, |
| 149 | }; | 142 | }; |
| 150 | struct inode *dst_inode = file_inode(dst); | 143 | struct inode *dst_inode = file_inode(dst); |
| 151 | struct nfs_server *server = NFS_SERVER(dst_inode); | 144 | struct nfs_server *server = NFS_SERVER(dst_inode); |
| 145 | loff_t pos_src = args->src_pos; | ||
| 146 | loff_t pos_dst = args->dst_pos; | ||
| 147 | size_t count = args->count; | ||
| 152 | int status; | 148 | int status; |
| 153 | 149 | ||
| 154 | status = nfs4_set_rw_stateid(&args.src_stateid, src_lock->open_context, | 150 | status = nfs4_set_rw_stateid(&args->src_stateid, src_lock->open_context, |
| 155 | src_lock, FMODE_READ); | 151 | src_lock, FMODE_READ); |
| 156 | if (status) | 152 | if (status) |
| 157 | return status; | 153 | return status; |
| @@ -161,7 +157,7 @@ static ssize_t _nfs42_proc_copy(struct file *src, loff_t pos_src, | |||
| 161 | if (status) | 157 | if (status) |
| 162 | return status; | 158 | return status; |
| 163 | 159 | ||
| 164 | status = nfs4_set_rw_stateid(&args.dst_stateid, dst_lock->open_context, | 160 | status = nfs4_set_rw_stateid(&args->dst_stateid, dst_lock->open_context, |
| 165 | dst_lock, FMODE_WRITE); | 161 | dst_lock, FMODE_WRITE); |
| 166 | if (status) | 162 | if (status) |
| 167 | return status; | 163 | return status; |
| @@ -171,22 +167,22 @@ static ssize_t _nfs42_proc_copy(struct file *src, loff_t pos_src, | |||
| 171 | return status; | 167 | return status; |
| 172 | 168 | ||
| 173 | status = nfs4_call_sync(server->client, server, &msg, | 169 | status = nfs4_call_sync(server->client, server, &msg, |
| 174 | &args.seq_args, &res.seq_res, 0); | 170 | &args->seq_args, &res->seq_res, 0); |
| 175 | if (status == -ENOTSUPP) | 171 | if (status == -ENOTSUPP) |
| 176 | server->caps &= ~NFS_CAP_COPY; | 172 | server->caps &= ~NFS_CAP_COPY; |
| 177 | if (status) | 173 | if (status) |
| 178 | return status; | 174 | return status; |
| 179 | 175 | ||
| 180 | if (res.write_res.verifier.committed != NFS_FILE_SYNC) { | 176 | if (res->write_res.verifier.committed != NFS_FILE_SYNC) { |
| 181 | status = nfs_commit_file(dst, &res.write_res.verifier.verifier); | 177 | status = nfs_commit_file(dst, &res->write_res.verifier.verifier); |
| 182 | if (status) | 178 | if (status) |
| 183 | return status; | 179 | return status; |
| 184 | } | 180 | } |
| 185 | 181 | ||
| 186 | truncate_pagecache_range(dst_inode, pos_dst, | 182 | truncate_pagecache_range(dst_inode, pos_dst, |
| 187 | pos_dst + res.write_res.count); | 183 | pos_dst + res->write_res.count); |
| 188 | 184 | ||
| 189 | return res.write_res.count; | 185 | return res->write_res.count; |
| 190 | } | 186 | } |
| 191 | 187 | ||
| 192 | ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src, | 188 | 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 | struct nfs_server *server = NFS_SERVER(file_inode(dst)); | 192 | struct nfs_server *server = NFS_SERVER(file_inode(dst)); |
| 197 | struct nfs_lock_context *src_lock; | 193 | struct nfs_lock_context *src_lock; |
| 198 | struct nfs_lock_context *dst_lock; | 194 | struct nfs_lock_context *dst_lock; |
| 199 | struct nfs4_exception src_exception = { }; | 195 | struct nfs42_copy_args args = { |
| 200 | struct nfs4_exception dst_exception = { }; | 196 | .src_fh = NFS_FH(file_inode(src)), |
| 197 | .src_pos = pos_src, | ||
| 198 | .dst_fh = NFS_FH(file_inode(dst)), | ||
| 199 | .dst_pos = pos_dst, | ||
| 200 | .count = count, | ||
| 201 | }; | ||
| 202 | struct nfs42_copy_res res; | ||
| 203 | struct nfs4_exception src_exception = { | ||
| 204 | .inode = file_inode(src), | ||
| 205 | .stateid = &args.src_stateid, | ||
| 206 | }; | ||
| 207 | struct nfs4_exception dst_exception = { | ||
| 208 | .inode = file_inode(dst), | ||
| 209 | .stateid = &args.dst_stateid, | ||
| 210 | }; | ||
| 201 | ssize_t err, err2; | 211 | ssize_t err, err2; |
| 202 | 212 | ||
| 203 | if (!nfs_server_capable(file_inode(dst), NFS_CAP_COPY)) | 213 | 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 | if (IS_ERR(src_lock)) | 217 | if (IS_ERR(src_lock)) |
| 208 | return PTR_ERR(src_lock); | 218 | return PTR_ERR(src_lock); |
| 209 | 219 | ||
| 210 | src_exception.inode = file_inode(src); | ||
| 211 | src_exception.state = src_lock->open_context->state; | 220 | src_exception.state = src_lock->open_context->state; |
| 212 | 221 | ||
| 213 | dst_lock = nfs_get_lock_context(nfs_file_open_context(dst)); | 222 | 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 | goto out_put_src_lock; | 225 | goto out_put_src_lock; |
| 217 | } | 226 | } |
| 218 | 227 | ||
| 219 | dst_exception.inode = file_inode(dst); | ||
| 220 | dst_exception.state = dst_lock->open_context->state; | 228 | dst_exception.state = dst_lock->open_context->state; |
| 221 | 229 | ||
| 222 | do { | 230 | do { |
| 223 | inode_lock(file_inode(dst)); | 231 | inode_lock(file_inode(dst)); |
| 224 | err = _nfs42_proc_copy(src, pos_src, src_lock, | 232 | err = _nfs42_proc_copy(src, src_lock, |
| 225 | dst, pos_dst, dst_lock, count); | 233 | dst, dst_lock, |
| 234 | &args, &res); | ||
| 226 | inode_unlock(file_inode(dst)); | 235 | inode_unlock(file_inode(dst)); |
| 227 | 236 | ||
| 237 | if (err >= 0) | ||
| 238 | break; | ||
| 228 | if (err == -ENOTSUPP) { | 239 | if (err == -ENOTSUPP) { |
| 229 | err = -EOPNOTSUPP; | 240 | err = -EOPNOTSUPP; |
| 230 | break; | 241 | break; |
