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 | |
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>
-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; |