Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
1c6dcbe5 AS |
2 | /* |
3 | * Copyright (c) 2014 Anna Schumaker <Anna.Schumaker@Netapp.com> | |
4 | */ | |
5 | #include <linux/fs.h> | |
0491567b | 6 | #include <linux/sunrpc/addr.h> |
1c6dcbe5 AS |
7 | #include <linux/sunrpc/sched.h> |
8 | #include <linux/nfs.h> | |
9 | #include <linux/nfs3.h> | |
10 | #include <linux/nfs4.h> | |
11 | #include <linux/nfs_xdr.h> | |
12 | #include <linux/nfs_fs.h> | |
13 | #include "nfs4_fs.h" | |
14 | #include "nfs42.h" | |
1b4a4bd8 PT |
15 | #include "iostat.h" |
16 | #include "pnfs.h" | |
efc6f4aa | 17 | #include "nfs4session.h" |
1b4a4bd8 | 18 | #include "internal.h" |
0491567b | 19 | #include "delegation.h" |
638037b1 | 20 | #include "nfs4trace.h" |
1b4a4bd8 | 21 | |
291e1b94 | 22 | #define NFSDBG_FACILITY NFSDBG_PROC |
c975c209 | 23 | static int nfs42_do_offload_cancel_async(struct file *dst, nfs4_stateid *std); |
1c6dcbe5 | 24 | |
0491567b OK |
25 | static void nfs42_set_netaddr(struct file *filep, struct nfs42_netaddr *naddr) |
26 | { | |
27 | struct nfs_client *clp = (NFS_SERVER(file_inode(filep)))->nfs_client; | |
28 | unsigned short port = 2049; | |
29 | ||
30 | rcu_read_lock(); | |
31 | naddr->netid_len = scnprintf(naddr->netid, | |
32 | sizeof(naddr->netid), "%s", | |
33 | rpc_peeraddr2str(clp->cl_rpcclient, | |
34 | RPC_DISPLAY_NETID)); | |
35 | naddr->addr_len = scnprintf(naddr->addr, | |
36 | sizeof(naddr->addr), | |
37 | "%s.%u.%u", | |
38 | rpc_peeraddr2str(clp->cl_rpcclient, | |
39 | RPC_DISPLAY_ADDR), | |
40 | port >> 8, port & 255); | |
41 | rcu_read_unlock(); | |
42 | } | |
43 | ||
f4ac1674 | 44 | static int _nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep, |
4bdf87eb | 45 | struct nfs_lock_context *lock, loff_t offset, loff_t len) |
f4ac1674 AS |
46 | { |
47 | struct inode *inode = file_inode(filep); | |
9a51940b | 48 | struct nfs_server *server = NFS_SERVER(inode); |
34bf20ce | 49 | u32 bitmask[NFS_BITMASK_SZ]; |
f4ac1674 AS |
50 | struct nfs42_falloc_args args = { |
51 | .falloc_fh = NFS_FH(inode), | |
52 | .falloc_offset = offset, | |
53 | .falloc_length = len, | |
e99812e1 | 54 | .falloc_bitmask = bitmask, |
9a51940b AS |
55 | }; |
56 | struct nfs42_falloc_res res = { | |
57 | .falloc_server = server, | |
f4ac1674 | 58 | }; |
f4ac1674 AS |
59 | int status; |
60 | ||
61 | msg->rpc_argp = &args; | |
62 | msg->rpc_resp = &res; | |
63 | ||
4bdf87eb CH |
64 | status = nfs4_set_rw_stateid(&args.falloc_stateid, lock->open_context, |
65 | lock, FMODE_WRITE); | |
d826e5b8 OK |
66 | if (status) { |
67 | if (status == -EAGAIN) | |
68 | status = -NFS4ERR_BAD_STATEID; | |
f4ac1674 | 69 | return status; |
d826e5b8 | 70 | } |
f4ac1674 | 71 | |
34bf20ce TM |
72 | nfs4_bitmask_set(bitmask, server->cache_consistency_bitmask, inode, |
73 | NFS_INO_INVALID_BLOCKS); | |
e99812e1 | 74 | |
9a51940b AS |
75 | res.falloc_fattr = nfs_alloc_fattr(); |
76 | if (!res.falloc_fattr) | |
77 | return -ENOMEM; | |
78 | ||
79 | status = nfs4_call_sync(server->client, server, msg, | |
80 | &args.seq_args, &res.seq_res, 0); | |
d7a51186 AS |
81 | if (status == 0) { |
82 | if (nfs_should_remove_suid(inode)) { | |
83 | spin_lock(&inode->i_lock); | |
84 | nfs_set_cache_invalid(inode, NFS_INO_INVALID_MODE); | |
85 | spin_unlock(&inode->i_lock); | |
86 | } | |
e99812e1 TM |
87 | status = nfs_post_op_update_inode_force_wcc(inode, |
88 | res.falloc_fattr); | |
d7a51186 | 89 | } |
40a82417 OK |
90 | if (msg->rpc_proc == &nfs4_procedures[NFSPROC4_CLNT_ALLOCATE]) |
91 | trace_nfs4_fallocate(inode, &args, status); | |
92 | else | |
93 | trace_nfs4_deallocate(inode, &args, status); | |
9a51940b AS |
94 | kfree(res.falloc_fattr); |
95 | return status; | |
f4ac1674 AS |
96 | } |
97 | ||
98 | static int nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep, | |
99 | loff_t offset, loff_t len) | |
100 | { | |
99f23783 TM |
101 | struct inode *inode = file_inode(filep); |
102 | struct nfs_server *server = NFS_SERVER(inode); | |
f4ac1674 | 103 | struct nfs4_exception exception = { }; |
4bdf87eb | 104 | struct nfs_lock_context *lock; |
f4ac1674 AS |
105 | int err; |
106 | ||
4bdf87eb CH |
107 | lock = nfs_get_lock_context(nfs_file_open_context(filep)); |
108 | if (IS_ERR(lock)) | |
109 | return PTR_ERR(lock); | |
110 | ||
99f23783 | 111 | exception.inode = inode; |
4bdf87eb CH |
112 | exception.state = lock->open_context->state; |
113 | ||
99f23783 TM |
114 | err = nfs_sync_inode(inode); |
115 | if (err) | |
116 | goto out; | |
117 | ||
f4ac1674 | 118 | do { |
4bdf87eb CH |
119 | err = _nfs42_proc_fallocate(msg, filep, lock, offset, len); |
120 | if (err == -ENOTSUPP) { | |
121 | err = -EOPNOTSUPP; | |
122 | break; | |
123 | } | |
f4ac1674 AS |
124 | err = nfs4_handle_exception(server, err, &exception); |
125 | } while (exception.retry); | |
99f23783 | 126 | out: |
4bdf87eb | 127 | nfs_put_lock_context(lock); |
f4ac1674 AS |
128 | return err; |
129 | } | |
130 | ||
131 | int nfs42_proc_allocate(struct file *filep, loff_t offset, loff_t len) | |
132 | { | |
133 | struct rpc_message msg = { | |
134 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ALLOCATE], | |
135 | }; | |
136 | struct inode *inode = file_inode(filep); | |
137 | int err; | |
138 | ||
139 | if (!nfs_server_capable(inode, NFS_CAP_ALLOCATE)) | |
140 | return -EOPNOTSUPP; | |
141 | ||
5955102c | 142 | inode_lock(inode); |
f830f7dd | 143 | |
f4ac1674 AS |
144 | err = nfs42_proc_fallocate(&msg, filep, offset, len); |
145 | if (err == -EOPNOTSUPP) | |
146 | NFS_SERVER(inode)->caps &= ~NFS_CAP_ALLOCATE; | |
f830f7dd | 147 | |
5955102c | 148 | inode_unlock(inode); |
f4ac1674 AS |
149 | return err; |
150 | } | |
151 | ||
624bd5b7 AS |
152 | int nfs42_proc_deallocate(struct file *filep, loff_t offset, loff_t len) |
153 | { | |
154 | struct rpc_message msg = { | |
155 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_DEALLOCATE], | |
156 | }; | |
157 | struct inode *inode = file_inode(filep); | |
158 | int err; | |
159 | ||
160 | if (!nfs_server_capable(inode, NFS_CAP_DEALLOCATE)) | |
161 | return -EOPNOTSUPP; | |
162 | ||
5955102c | 163 | inode_lock(inode); |
f830f7dd | 164 | |
624bd5b7 | 165 | err = nfs42_proc_fallocate(&msg, filep, offset, len); |
9a51940b AS |
166 | if (err == 0) |
167 | truncate_pagecache_range(inode, offset, (offset + len) -1); | |
624bd5b7 AS |
168 | if (err == -EOPNOTSUPP) |
169 | NFS_SERVER(inode)->caps &= ~NFS_CAP_DEALLOCATE; | |
99f23783 | 170 | |
5955102c | 171 | inode_unlock(inode); |
624bd5b7 AS |
172 | return err; |
173 | } | |
174 | ||
62164f31 | 175 | static int handle_async_copy(struct nfs42_copy_res *res, |
0e65a32c OK |
176 | struct nfs_server *dst_server, |
177 | struct nfs_server *src_server, | |
62164f31 OK |
178 | struct file *src, |
179 | struct file *dst, | |
0e65a32c OK |
180 | nfs4_stateid *src_stateid, |
181 | bool *restart) | |
62164f31 | 182 | { |
3de24f3d | 183 | struct nfs4_copy_state *copy, *tmp_copy = NULL, *iter; |
62164f31 | 184 | int status = NFS4_OK; |
0e65a32c OK |
185 | struct nfs_open_context *dst_ctx = nfs_file_open_context(dst); |
186 | struct nfs_open_context *src_ctx = nfs_file_open_context(src); | |
bc0c9079 | 187 | |
4fb547be | 188 | copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_KERNEL); |
99f2c555 OK |
189 | if (!copy) |
190 | return -ENOMEM; | |
191 | ||
0e65a32c | 192 | spin_lock(&dst_server->nfs_client->cl_lock); |
3de24f3d | 193 | list_for_each_entry(iter, |
0e65a32c | 194 | &dst_server->nfs_client->pending_cb_stateids, |
bc0c9079 | 195 | copies) { |
3de24f3d | 196 | if (memcmp(&res->write_res.stateid, &iter->stateid, |
bc0c9079 OK |
197 | NFS4_STATEID_SIZE)) |
198 | continue; | |
3de24f3d JK |
199 | tmp_copy = iter; |
200 | list_del(&iter->copies); | |
bc0c9079 OK |
201 | break; |
202 | } | |
3de24f3d | 203 | if (tmp_copy) { |
0e65a32c | 204 | spin_unlock(&dst_server->nfs_client->cl_lock); |
99f2c555 OK |
205 | kfree(copy); |
206 | copy = tmp_copy; | |
bc0c9079 OK |
207 | goto out; |
208 | } | |
62164f31 | 209 | |
62164f31 OK |
210 | memcpy(©->stateid, &res->write_res.stateid, NFS4_STATEID_SIZE); |
211 | init_completion(©->completion); | |
0e65a32c OK |
212 | copy->parent_dst_state = dst_ctx->state; |
213 | copy->parent_src_state = src_ctx->state; | |
62164f31 | 214 | |
0e65a32c OK |
215 | list_add_tail(©->copies, &dst_server->ss_copies); |
216 | spin_unlock(&dst_server->nfs_client->cl_lock); | |
217 | ||
218 | if (dst_server != src_server) { | |
219 | spin_lock(&src_server->nfs_client->cl_lock); | |
220 | list_add_tail(©->src_copies, &src_server->ss_copies); | |
221 | spin_unlock(&src_server->nfs_client->cl_lock); | |
222 | } | |
62164f31 | 223 | |
c975c209 | 224 | status = wait_for_completion_interruptible(©->completion); |
0e65a32c | 225 | spin_lock(&dst_server->nfs_client->cl_lock); |
62164f31 | 226 | list_del_init(©->copies); |
0e65a32c OK |
227 | spin_unlock(&dst_server->nfs_client->cl_lock); |
228 | if (dst_server != src_server) { | |
229 | spin_lock(&src_server->nfs_client->cl_lock); | |
230 | list_del_init(©->src_copies); | |
231 | spin_unlock(&src_server->nfs_client->cl_lock); | |
232 | } | |
c975c209 | 233 | if (status == -ERESTARTSYS) { |
e4648aa4 | 234 | goto out_cancel; |
0e65a32c | 235 | } else if (copy->flags || copy->error == NFS4ERR_PARTNER_NO_AUTH) { |
e4648aa4 | 236 | status = -EAGAIN; |
0e65a32c | 237 | *restart = true; |
e4648aa4 | 238 | goto out_cancel; |
c975c209 | 239 | } |
bc0c9079 | 240 | out: |
62164f31 OK |
241 | res->write_res.count = copy->count; |
242 | memcpy(&res->write_res.verifier, ©->verf, sizeof(copy->verf)); | |
243 | status = -copy->error; | |
244 | ||
12406025 | 245 | out_free: |
e4648aa4 OK |
246 | kfree(copy); |
247 | return status; | |
248 | out_cancel: | |
249 | nfs42_do_offload_cancel_async(dst, ©->stateid); | |
12406025 OK |
250 | if (!nfs42_files_from_same_server(src, dst)) |
251 | nfs42_do_offload_cancel_async(src, src_stateid); | |
252 | goto out_free; | |
62164f31 OK |
253 | } |
254 | ||
6b8d84e2 OK |
255 | static int process_copy_commit(struct file *dst, loff_t pos_dst, |
256 | struct nfs42_copy_res *res) | |
257 | { | |
258 | struct nfs_commitres cres; | |
259 | int status = -ENOMEM; | |
260 | ||
4fb547be | 261 | cres.verf = kzalloc(sizeof(struct nfs_writeverf), GFP_KERNEL); |
6b8d84e2 OK |
262 | if (!cres.verf) |
263 | goto out; | |
264 | ||
265 | status = nfs4_proc_commit(dst, pos_dst, res->write_res.count, &cres); | |
266 | if (status) | |
267 | goto out_free; | |
268 | if (nfs_write_verifier_cmp(&res->write_res.verifier.verifier, | |
269 | &cres.verf->verifier)) { | |
270 | dprintk("commit verf differs from copy verf\n"); | |
271 | status = -EAGAIN; | |
272 | } | |
273 | out_free: | |
274 | kfree(cres.verf); | |
275 | out: | |
276 | return status; | |
277 | } | |
278 | ||
94d202d5 TM |
279 | /** |
280 | * nfs42_copy_dest_done - perform inode cache updates after clone/copy offload | |
281 | * @inode: pointer to destination inode | |
282 | * @pos: destination offset | |
283 | * @len: copy length | |
284 | * | |
285 | * Punch a hole in the inode page cache, so that the NFS client will | |
286 | * know to retrieve new data. | |
287 | * Update the file size if necessary, and then mark the inode as having | |
288 | * invalid cached values for change attribute, ctime, mtime and space used. | |
289 | */ | |
290 | static void nfs42_copy_dest_done(struct inode *inode, loff_t pos, loff_t len) | |
291 | { | |
292 | loff_t newsize = pos + len; | |
293 | loff_t end = newsize - 1; | |
294 | ||
3f015d89 BC |
295 | WARN_ON_ONCE(invalidate_inode_pages2_range(inode->i_mapping, |
296 | pos >> PAGE_SHIFT, end >> PAGE_SHIFT)); | |
297 | ||
94d202d5 TM |
298 | spin_lock(&inode->i_lock); |
299 | if (newsize > i_size_read(inode)) | |
300 | i_size_write(inode, newsize); | |
301 | nfs_set_cache_invalid(inode, NFS_INO_INVALID_CHANGE | | |
302 | NFS_INO_INVALID_CTIME | | |
303 | NFS_INO_INVALID_MTIME | | |
304 | NFS_INO_INVALID_BLOCKS); | |
305 | spin_unlock(&inode->i_lock); | |
306 | } | |
307 | ||
9d8cacbf | 308 | static ssize_t _nfs42_proc_copy(struct file *src, |
2e72448b | 309 | struct nfs_lock_context *src_lock, |
9d8cacbf | 310 | struct file *dst, |
2e72448b | 311 | struct nfs_lock_context *dst_lock, |
9d8cacbf | 312 | struct nfs42_copy_args *args, |
1d38f3f0 OK |
313 | struct nfs42_copy_res *res, |
314 | struct nl4_server *nss, | |
0e65a32c OK |
315 | nfs4_stateid *cnr_stateid, |
316 | bool *restart) | |
2e72448b | 317 | { |
2e72448b AS |
318 | struct rpc_message msg = { |
319 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COPY], | |
9d8cacbf TM |
320 | .rpc_argp = args, |
321 | .rpc_resp = res, | |
2e72448b AS |
322 | }; |
323 | struct inode *dst_inode = file_inode(dst); | |
0e65a32c OK |
324 | struct inode *src_inode = file_inode(src); |
325 | struct nfs_server *dst_server = NFS_SERVER(dst_inode); | |
326 | struct nfs_server *src_server = NFS_SERVER(src_inode); | |
9d8cacbf TM |
327 | loff_t pos_src = args->src_pos; |
328 | loff_t pos_dst = args->dst_pos; | |
329 | size_t count = args->count; | |
1ee48bdd | 330 | ssize_t status; |
2e72448b | 331 | |
1d38f3f0 OK |
332 | if (nss) { |
333 | args->cp_src = nss; | |
334 | nfs4_stateid_copy(&args->src_stateid, cnr_stateid); | |
335 | } else { | |
336 | status = nfs4_set_rw_stateid(&args->src_stateid, | |
337 | src_lock->open_context, src_lock, FMODE_READ); | |
d826e5b8 OK |
338 | if (status) { |
339 | if (status == -EAGAIN) | |
340 | status = -NFS4ERR_BAD_STATEID; | |
1d38f3f0 | 341 | return status; |
d826e5b8 | 342 | } |
1d38f3f0 | 343 | } |
265a04b0 | 344 | status = nfs_filemap_write_and_wait_range(src->f_mapping, |
837bb1d7 TM |
345 | pos_src, pos_src + (loff_t)count - 1); |
346 | if (status) | |
347 | return status; | |
348 | ||
9d8cacbf | 349 | status = nfs4_set_rw_stateid(&args->dst_stateid, dst_lock->open_context, |
2e72448b | 350 | dst_lock, FMODE_WRITE); |
d826e5b8 OK |
351 | if (status) { |
352 | if (status == -EAGAIN) | |
353 | status = -NFS4ERR_BAD_STATEID; | |
2e72448b | 354 | return status; |
d826e5b8 | 355 | } |
837bb1d7 TM |
356 | |
357 | status = nfs_sync_inode(dst_inode); | |
358 | if (status) | |
359 | return status; | |
2e72448b | 360 | |
62164f31 OK |
361 | res->commit_res.verf = NULL; |
362 | if (args->sync) { | |
363 | res->commit_res.verf = | |
4fb547be | 364 | kzalloc(sizeof(struct nfs_writeverf), GFP_KERNEL); |
62164f31 OK |
365 | if (!res->commit_res.verf) |
366 | return -ENOMEM; | |
367 | } | |
0e65a32c OK |
368 | set_bit(NFS_CLNT_SRC_SSC_COPY_STATE, |
369 | &src_lock->open_context->state->flags); | |
e4648aa4 OK |
370 | set_bit(NFS_CLNT_DST_SSC_COPY_STATE, |
371 | &dst_lock->open_context->state->flags); | |
372 | ||
0e65a32c | 373 | status = nfs4_call_sync(dst_server->client, dst_server, &msg, |
9d8cacbf | 374 | &args->seq_args, &res->seq_res, 0); |
ce7cea1b | 375 | trace_nfs4_copy(src_inode, dst_inode, args, res, nss, status); |
2e72448b | 376 | if (status == -ENOTSUPP) |
0e65a32c | 377 | dst_server->caps &= ~NFS_CAP_COPY; |
2e72448b | 378 | if (status) |
e0926934 | 379 | goto out; |
2e72448b | 380 | |
62164f31 OK |
381 | if (args->sync && |
382 | nfs_write_verifier_cmp(&res->write_res.verifier.verifier, | |
e0926934 OK |
383 | &res->commit_res.verf->verifier)) { |
384 | status = -EAGAIN; | |
385 | goto out; | |
2e72448b AS |
386 | } |
387 | ||
62164f31 | 388 | if (!res->synchronous) { |
0e65a32c OK |
389 | status = handle_async_copy(res, dst_server, src_server, src, |
390 | dst, &args->src_stateid, restart); | |
62164f31 | 391 | if (status) |
123c23c6 | 392 | goto out; |
62164f31 OK |
393 | } |
394 | ||
6b8d84e2 OK |
395 | if ((!res->synchronous || !args->sync) && |
396 | res->write_res.verifier.committed != NFS_FILE_SYNC) { | |
397 | status = process_copy_commit(dst, pos_dst, res); | |
398 | if (status) | |
123c23c6 | 399 | goto out; |
6b8d84e2 OK |
400 | } |
401 | ||
94d202d5 | 402 | nfs42_copy_dest_done(dst_inode, pos_dst, res->write_res.count); |
febfeaae | 403 | nfs_invalidate_atime(src_inode); |
e0926934 OK |
404 | status = res->write_res.count; |
405 | out: | |
62164f31 OK |
406 | if (args->sync) |
407 | kfree(res->commit_res.verf); | |
e0926934 | 408 | return status; |
2e72448b AS |
409 | } |
410 | ||
411 | ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src, | |
1d38f3f0 OK |
412 | struct file *dst, loff_t pos_dst, size_t count, |
413 | struct nl4_server *nss, | |
12751010 | 414 | nfs4_stateid *cnr_stateid, bool sync) |
2e72448b AS |
415 | { |
416 | struct nfs_server *server = NFS_SERVER(file_inode(dst)); | |
417 | struct nfs_lock_context *src_lock; | |
418 | struct nfs_lock_context *dst_lock; | |
9d8cacbf TM |
419 | struct nfs42_copy_args args = { |
420 | .src_fh = NFS_FH(file_inode(src)), | |
421 | .src_pos = pos_src, | |
422 | .dst_fh = NFS_FH(file_inode(dst)), | |
423 | .dst_pos = pos_dst, | |
424 | .count = count, | |
12751010 | 425 | .sync = sync, |
9d8cacbf TM |
426 | }; |
427 | struct nfs42_copy_res res; | |
428 | struct nfs4_exception src_exception = { | |
429 | .inode = file_inode(src), | |
430 | .stateid = &args.src_stateid, | |
431 | }; | |
432 | struct nfs4_exception dst_exception = { | |
433 | .inode = file_inode(dst), | |
434 | .stateid = &args.dst_stateid, | |
435 | }; | |
2e72448b | 436 | ssize_t err, err2; |
0e65a32c | 437 | bool restart = false; |
2e72448b | 438 | |
2e72448b AS |
439 | src_lock = nfs_get_lock_context(nfs_file_open_context(src)); |
440 | if (IS_ERR(src_lock)) | |
441 | return PTR_ERR(src_lock); | |
442 | ||
2e72448b AS |
443 | src_exception.state = src_lock->open_context->state; |
444 | ||
445 | dst_lock = nfs_get_lock_context(nfs_file_open_context(dst)); | |
446 | if (IS_ERR(dst_lock)) { | |
447 | err = PTR_ERR(dst_lock); | |
448 | goto out_put_src_lock; | |
449 | } | |
450 | ||
2e72448b AS |
451 | dst_exception.state = dst_lock->open_context->state; |
452 | ||
453 | do { | |
ea8ea737 | 454 | inode_lock(file_inode(dst)); |
9d8cacbf TM |
455 | err = _nfs42_proc_copy(src, src_lock, |
456 | dst, dst_lock, | |
1d38f3f0 | 457 | &args, &res, |
0e65a32c | 458 | nss, cnr_stateid, &restart); |
ea8ea737 | 459 | inode_unlock(file_inode(dst)); |
2e72448b | 460 | |
9d8cacbf TM |
461 | if (err >= 0) |
462 | break; | |
47305153 TM |
463 | if ((err == -ENOTSUPP || |
464 | err == -NFS4ERR_OFFLOAD_DENIED) && | |
12406025 | 465 | nfs42_files_from_same_server(src, dst)) { |
2e72448b AS |
466 | err = -EOPNOTSUPP; |
467 | break; | |
539f57b3 | 468 | } else if (err == -EAGAIN) { |
0e65a32c OK |
469 | if (!restart) { |
470 | dst_exception.retry = 1; | |
471 | continue; | |
472 | } | |
473 | break; | |
539f57b3 OK |
474 | } else if (err == -NFS4ERR_OFFLOAD_NO_REQS && !args.sync) { |
475 | args.sync = true; | |
e0926934 OK |
476 | dst_exception.retry = 1; |
477 | continue; | |
6b61c969 | 478 | } else if ((err == -ESTALE || |
12406025 OK |
479 | err == -NFS4ERR_OFFLOAD_DENIED || |
480 | err == -ENOTSUPP) && | |
7e350197 OK |
481 | !nfs42_files_from_same_server(src, dst)) { |
482 | nfs42_do_offload_cancel_async(src, &args.src_stateid); | |
483 | err = -EOPNOTSUPP; | |
484 | break; | |
2e72448b AS |
485 | } |
486 | ||
487 | err2 = nfs4_handle_exception(server, err, &src_exception); | |
488 | err = nfs4_handle_exception(server, err, &dst_exception); | |
489 | if (!err) | |
490 | err = err2; | |
491 | } while (src_exception.retry || dst_exception.retry); | |
492 | ||
493 | nfs_put_lock_context(dst_lock); | |
494 | out_put_src_lock: | |
495 | nfs_put_lock_context(src_lock); | |
496 | return err; | |
497 | } | |
498 | ||
c975c209 OK |
499 | struct nfs42_offloadcancel_data { |
500 | struct nfs_server *seq_server; | |
501 | struct nfs42_offload_status_args args; | |
502 | struct nfs42_offload_status_res res; | |
503 | }; | |
504 | ||
505 | static void nfs42_offload_cancel_prepare(struct rpc_task *task, void *calldata) | |
506 | { | |
507 | struct nfs42_offloadcancel_data *data = calldata; | |
508 | ||
509 | nfs4_setup_sequence(data->seq_server->nfs_client, | |
510 | &data->args.osa_seq_args, | |
511 | &data->res.osr_seq_res, task); | |
512 | } | |
513 | ||
514 | static void nfs42_offload_cancel_done(struct rpc_task *task, void *calldata) | |
515 | { | |
516 | struct nfs42_offloadcancel_data *data = calldata; | |
517 | ||
127becab | 518 | trace_nfs4_offload_cancel(&data->args, task->tk_status); |
c975c209 OK |
519 | nfs41_sequence_done(task, &data->res.osr_seq_res); |
520 | if (task->tk_status && | |
521 | nfs4_async_handle_error(task, data->seq_server, NULL, | |
522 | NULL) == -EAGAIN) | |
523 | rpc_restart_call_prepare(task); | |
524 | } | |
525 | ||
526 | static void nfs42_free_offloadcancel_data(void *data) | |
527 | { | |
528 | kfree(data); | |
529 | } | |
530 | ||
531 | static const struct rpc_call_ops nfs42_offload_cancel_ops = { | |
532 | .rpc_call_prepare = nfs42_offload_cancel_prepare, | |
533 | .rpc_call_done = nfs42_offload_cancel_done, | |
534 | .rpc_release = nfs42_free_offloadcancel_data, | |
535 | }; | |
536 | ||
537 | static int nfs42_do_offload_cancel_async(struct file *dst, | |
538 | nfs4_stateid *stateid) | |
539 | { | |
540 | struct nfs_server *dst_server = NFS_SERVER(file_inode(dst)); | |
541 | struct nfs42_offloadcancel_data *data = NULL; | |
542 | struct nfs_open_context *ctx = nfs_file_open_context(dst); | |
543 | struct rpc_task *task; | |
544 | struct rpc_message msg = { | |
545 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OFFLOAD_CANCEL], | |
546 | .rpc_cred = ctx->cred, | |
547 | }; | |
548 | struct rpc_task_setup task_setup_data = { | |
549 | .rpc_client = dst_server->client, | |
550 | .rpc_message = &msg, | |
551 | .callback_ops = &nfs42_offload_cancel_ops, | |
552 | .workqueue = nfsiod_workqueue, | |
553 | .flags = RPC_TASK_ASYNC, | |
554 | }; | |
555 | int status; | |
556 | ||
557 | if (!(dst_server->caps & NFS_CAP_OFFLOAD_CANCEL)) | |
558 | return -EOPNOTSUPP; | |
559 | ||
4fb547be | 560 | data = kzalloc(sizeof(struct nfs42_offloadcancel_data), GFP_KERNEL); |
c975c209 OK |
561 | if (data == NULL) |
562 | return -ENOMEM; | |
563 | ||
564 | data->seq_server = dst_server; | |
565 | data->args.osa_src_fh = NFS_FH(file_inode(dst)); | |
566 | memcpy(&data->args.osa_stateid, stateid, | |
567 | sizeof(data->args.osa_stateid)); | |
568 | msg.rpc_argp = &data->args; | |
569 | msg.rpc_resp = &data->res; | |
570 | task_setup_data.callback_data = data; | |
571 | nfs4_init_sequence(&data->args.osa_seq_args, &data->res.osr_seq_res, | |
572 | 1, 0); | |
573 | task = rpc_run_task(&task_setup_data); | |
574 | if (IS_ERR(task)) | |
575 | return PTR_ERR(task); | |
576 | status = rpc_wait_for_completion_task(task); | |
577 | if (status == -ENOTSUPP) | |
578 | dst_server->caps &= ~NFS_CAP_OFFLOAD_CANCEL; | |
579 | rpc_put_task(task); | |
580 | return status; | |
581 | } | |
582 | ||
00030104 Y |
583 | static int _nfs42_proc_copy_notify(struct file *src, struct file *dst, |
584 | struct nfs42_copy_notify_args *args, | |
585 | struct nfs42_copy_notify_res *res) | |
0491567b OK |
586 | { |
587 | struct nfs_server *src_server = NFS_SERVER(file_inode(src)); | |
588 | struct rpc_message msg = { | |
589 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COPY_NOTIFY], | |
590 | .rpc_argp = args, | |
591 | .rpc_resp = res, | |
592 | }; | |
593 | int status; | |
594 | struct nfs_open_context *ctx; | |
595 | struct nfs_lock_context *l_ctx; | |
596 | ||
597 | ctx = get_nfs_open_context(nfs_file_open_context(src)); | |
598 | l_ctx = nfs_get_lock_context(ctx); | |
b7f114ed XX |
599 | if (IS_ERR(l_ctx)) { |
600 | status = PTR_ERR(l_ctx); | |
601 | goto out; | |
602 | } | |
0491567b OK |
603 | |
604 | status = nfs4_set_rw_stateid(&args->cna_src_stateid, ctx, l_ctx, | |
605 | FMODE_READ); | |
606 | nfs_put_lock_context(l_ctx); | |
d826e5b8 OK |
607 | if (status) { |
608 | if (status == -EAGAIN) | |
609 | status = -NFS4ERR_BAD_STATEID; | |
b7f114ed | 610 | goto out; |
d826e5b8 | 611 | } |
0491567b OK |
612 | |
613 | status = nfs4_call_sync(src_server->client, src_server, &msg, | |
614 | &args->cna_seq_args, &res->cnr_seq_res, 0); | |
488b170c | 615 | trace_nfs4_copy_notify(file_inode(src), args, res, status); |
0491567b OK |
616 | if (status == -ENOTSUPP) |
617 | src_server->caps &= ~NFS_CAP_COPY_NOTIFY; | |
618 | ||
b7f114ed | 619 | out: |
0491567b OK |
620 | put_nfs_open_context(nfs_file_open_context(src)); |
621 | return status; | |
622 | } | |
623 | ||
624 | int nfs42_proc_copy_notify(struct file *src, struct file *dst, | |
625 | struct nfs42_copy_notify_res *res) | |
626 | { | |
627 | struct nfs_server *src_server = NFS_SERVER(file_inode(src)); | |
628 | struct nfs42_copy_notify_args *args; | |
629 | struct nfs4_exception exception = { | |
630 | .inode = file_inode(src), | |
631 | }; | |
632 | int status; | |
633 | ||
634 | if (!(src_server->caps & NFS_CAP_COPY_NOTIFY)) | |
635 | return -EOPNOTSUPP; | |
636 | ||
4fb547be | 637 | args = kzalloc(sizeof(struct nfs42_copy_notify_args), GFP_KERNEL); |
0491567b OK |
638 | if (args == NULL) |
639 | return -ENOMEM; | |
640 | ||
641 | args->cna_src_fh = NFS_FH(file_inode(src)), | |
642 | args->cna_dst.nl4_type = NL4_NETADDR; | |
643 | nfs42_set_netaddr(dst, &args->cna_dst.u.nl4_addr); | |
644 | exception.stateid = &args->cna_src_stateid; | |
645 | ||
646 | do { | |
647 | status = _nfs42_proc_copy_notify(src, dst, args, res); | |
648 | if (status == -ENOTSUPP) { | |
649 | status = -EOPNOTSUPP; | |
650 | goto out; | |
651 | } | |
652 | status = nfs4_handle_exception(src_server, status, &exception); | |
653 | } while (exception.retry); | |
654 | ||
655 | out: | |
656 | kfree(args); | |
657 | return status; | |
658 | } | |
659 | ||
4bdf87eb CH |
660 | static loff_t _nfs42_proc_llseek(struct file *filep, |
661 | struct nfs_lock_context *lock, loff_t offset, int whence) | |
1c6dcbe5 AS |
662 | { |
663 | struct inode *inode = file_inode(filep); | |
664 | struct nfs42_seek_args args = { | |
665 | .sa_fh = NFS_FH(inode), | |
666 | .sa_offset = offset, | |
667 | .sa_what = (whence == SEEK_HOLE) ? | |
668 | NFS4_CONTENT_HOLE : NFS4_CONTENT_DATA, | |
669 | }; | |
670 | struct nfs42_seek_res res; | |
671 | struct rpc_message msg = { | |
672 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEEK], | |
673 | .rpc_argp = &args, | |
674 | .rpc_resp = &res, | |
675 | }; | |
676 | struct nfs_server *server = NFS_SERVER(inode); | |
677 | int status; | |
678 | ||
878ffa9f | 679 | if (!nfs_server_capable(inode, NFS_CAP_SEEK)) |
1c6dcbe5 AS |
680 | return -ENOTSUPP; |
681 | ||
4bdf87eb CH |
682 | status = nfs4_set_rw_stateid(&args.sa_stateid, lock->open_context, |
683 | lock, FMODE_READ); | |
d826e5b8 OK |
684 | if (status) { |
685 | if (status == -EAGAIN) | |
686 | status = -NFS4ERR_BAD_STATEID; | |
1c6dcbe5 | 687 | return status; |
d826e5b8 | 688 | } |
1c6dcbe5 | 689 | |
e95fc4a0 TM |
690 | status = nfs_filemap_write_and_wait_range(inode->i_mapping, |
691 | offset, LLONG_MAX); | |
692 | if (status) | |
693 | return status; | |
694 | ||
1c6dcbe5 AS |
695 | status = nfs4_call_sync(server->client, server, &msg, |
696 | &args.seq_args, &res.seq_res, 0); | |
f628d462 | 697 | trace_nfs4_llseek(inode, &args, &res, status); |
1c6dcbe5 AS |
698 | if (status == -ENOTSUPP) |
699 | server->caps &= ~NFS_CAP_SEEK; | |
700 | if (status) | |
701 | return status; | |
702 | ||
73f5c88f OK |
703 | if (whence == SEEK_DATA && res.sr_eof) |
704 | return -NFS4ERR_NXIO; | |
705 | else | |
706 | return vfs_setpos(filep, res.sr_offset, inode->i_sb->s_maxbytes); | |
1c6dcbe5 | 707 | } |
be3a5d23 | 708 | |
bdcc2cd1 BF |
709 | loff_t nfs42_proc_llseek(struct file *filep, loff_t offset, int whence) |
710 | { | |
711 | struct nfs_server *server = NFS_SERVER(file_inode(filep)); | |
712 | struct nfs4_exception exception = { }; | |
4bdf87eb | 713 | struct nfs_lock_context *lock; |
306a5549 | 714 | loff_t err; |
bdcc2cd1 | 715 | |
4bdf87eb CH |
716 | lock = nfs_get_lock_context(nfs_file_open_context(filep)); |
717 | if (IS_ERR(lock)) | |
718 | return PTR_ERR(lock); | |
719 | ||
720 | exception.inode = file_inode(filep); | |
721 | exception.state = lock->open_context->state; | |
722 | ||
bdcc2cd1 | 723 | do { |
4bdf87eb | 724 | err = _nfs42_proc_llseek(filep, lock, offset, whence); |
306a5549 BF |
725 | if (err >= 0) |
726 | break; | |
4bdf87eb CH |
727 | if (err == -ENOTSUPP) { |
728 | err = -EOPNOTSUPP; | |
729 | break; | |
730 | } | |
bdcc2cd1 BF |
731 | err = nfs4_handle_exception(server, err, &exception); |
732 | } while (exception.retry); | |
733 | ||
4bdf87eb | 734 | nfs_put_lock_context(lock); |
bdcc2cd1 BF |
735 | return err; |
736 | } | |
737 | ||
738 | ||
1b4a4bd8 PT |
739 | static void |
740 | nfs42_layoutstat_prepare(struct rpc_task *task, void *calldata) | |
741 | { | |
742 | struct nfs42_layoutstat_data *data = calldata; | |
9a0fe867 TM |
743 | struct inode *inode = data->inode; |
744 | struct nfs_server *server = NFS_SERVER(inode); | |
745 | struct pnfs_layout_hdr *lo; | |
1b4a4bd8 | 746 | |
9a0fe867 TM |
747 | spin_lock(&inode->i_lock); |
748 | lo = NFS_I(inode)->layout; | |
749 | if (!pnfs_layout_is_valid(lo)) { | |
750 | spin_unlock(&inode->i_lock); | |
751 | rpc_exit(task, 0); | |
752 | return; | |
753 | } | |
754 | nfs4_stateid_copy(&data->args.stateid, &lo->plh_stateid); | |
755 | spin_unlock(&inode->i_lock); | |
6de7e12f AS |
756 | nfs4_setup_sequence(server->nfs_client, &data->args.seq_args, |
757 | &data->res.seq_res, task); | |
1b4a4bd8 PT |
758 | } |
759 | ||
760 | static void | |
761 | nfs42_layoutstat_done(struct rpc_task *task, void *calldata) | |
762 | { | |
763 | struct nfs42_layoutstat_data *data = calldata; | |
68d264cf PT |
764 | struct inode *inode = data->inode; |
765 | struct pnfs_layout_hdr *lo; | |
1b4a4bd8 PT |
766 | |
767 | if (!nfs4_sequence_done(task, &data->res.seq_res)) | |
768 | return; | |
769 | ||
6c5a0d89 TM |
770 | switch (task->tk_status) { |
771 | case 0: | |
638037b1 | 772 | return; |
cf61eb26 TM |
773 | case -NFS4ERR_BADHANDLE: |
774 | case -ESTALE: | |
775 | pnfs_destroy_layout(NFS_I(inode)); | |
776 | break; | |
68d264cf | 777 | case -NFS4ERR_EXPIRED: |
206b3bb5 TM |
778 | case -NFS4ERR_ADMIN_REVOKED: |
779 | case -NFS4ERR_DELEG_REVOKED: | |
68d264cf | 780 | case -NFS4ERR_STALE_STATEID: |
68d264cf PT |
781 | case -NFS4ERR_BAD_STATEID: |
782 | spin_lock(&inode->i_lock); | |
783 | lo = NFS_I(inode)->layout; | |
9a0fe867 TM |
784 | if (pnfs_layout_is_valid(lo) && |
785 | nfs4_stateid_match(&data->args.stateid, | |
68d264cf PT |
786 | &lo->plh_stateid)) { |
787 | LIST_HEAD(head); | |
788 | ||
789 | /* | |
790 | * Mark the bad layout state as invalid, then retry | |
791 | * with the current stateid. | |
792 | */ | |
5f46be04 | 793 | pnfs_mark_layout_stateid_invalid(lo, &head); |
68d264cf PT |
794 | spin_unlock(&inode->i_lock); |
795 | pnfs_free_lseg_list(&head); | |
1f18b82c | 796 | nfs_commit_inode(inode, 0); |
68d264cf PT |
797 | } else |
798 | spin_unlock(&inode->i_lock); | |
799 | break; | |
9a0fe867 TM |
800 | case -NFS4ERR_OLD_STATEID: |
801 | spin_lock(&inode->i_lock); | |
802 | lo = NFS_I(inode)->layout; | |
803 | if (pnfs_layout_is_valid(lo) && | |
804 | nfs4_stateid_match_other(&data->args.stateid, | |
805 | &lo->plh_stateid)) { | |
806 | /* Do we need to delay before resending? */ | |
807 | if (!nfs4_stateid_is_newer(&lo->plh_stateid, | |
808 | &data->args.stateid)) | |
809 | rpc_delay(task, HZ); | |
810 | rpc_restart_call_prepare(task); | |
811 | } | |
812 | spin_unlock(&inode->i_lock); | |
813 | break; | |
6c5a0d89 TM |
814 | case -ENOTSUPP: |
815 | case -EOPNOTSUPP: | |
68d264cf | 816 | NFS_SERVER(inode)->caps &= ~NFS_CAP_LAYOUTSTATS; |
6c5a0d89 | 817 | } |
638037b1 TM |
818 | |
819 | trace_nfs4_layoutstats(inode, &data->args.stateid, task->tk_status); | |
1b4a4bd8 PT |
820 | } |
821 | ||
822 | static void | |
823 | nfs42_layoutstat_release(void *calldata) | |
824 | { | |
825 | struct nfs42_layoutstat_data *data = calldata; | |
422c93c8 TM |
826 | struct nfs42_layoutstat_devinfo *devinfo = data->args.devinfo; |
827 | int i; | |
8733408d | 828 | |
422c93c8 TM |
829 | for (i = 0; i < data->args.num_dev; i++) { |
830 | if (devinfo[i].ld_private.ops && devinfo[i].ld_private.ops->free) | |
831 | devinfo[i].ld_private.ops->free(&devinfo[i].ld_private); | |
832 | } | |
1b4a4bd8 PT |
833 | |
834 | pnfs_put_layout_hdr(NFS_I(data->args.inode)->layout); | |
1bfe3b25 PT |
835 | smp_mb__before_atomic(); |
836 | clear_bit(NFS_INO_LAYOUTSTATS, &NFS_I(data->args.inode)->flags); | |
837 | smp_mb__after_atomic(); | |
1b4a4bd8 PT |
838 | nfs_iput_and_deactive(data->inode); |
839 | kfree(data->args.devinfo); | |
840 | kfree(data); | |
841 | } | |
842 | ||
be3a5d23 | 843 | static const struct rpc_call_ops nfs42_layoutstat_ops = { |
1b4a4bd8 PT |
844 | .rpc_call_prepare = nfs42_layoutstat_prepare, |
845 | .rpc_call_done = nfs42_layoutstat_done, | |
846 | .rpc_release = nfs42_layoutstat_release, | |
be3a5d23 TM |
847 | }; |
848 | ||
849 | int nfs42_proc_layoutstats_generic(struct nfs_server *server, | |
850 | struct nfs42_layoutstat_data *data) | |
851 | { | |
852 | struct rpc_message msg = { | |
853 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTSTATS], | |
854 | .rpc_argp = &data->args, | |
855 | .rpc_resp = &data->res, | |
856 | }; | |
857 | struct rpc_task_setup task_setup = { | |
858 | .rpc_client = server->client, | |
859 | .rpc_message = &msg, | |
860 | .callback_ops = &nfs42_layoutstat_ops, | |
861 | .callback_data = data, | |
862 | .flags = RPC_TASK_ASYNC, | |
863 | }; | |
864 | struct rpc_task *task; | |
865 | ||
1b4a4bd8 PT |
866 | data->inode = nfs_igrab_and_active(data->args.inode); |
867 | if (!data->inode) { | |
868 | nfs42_layoutstat_release(data); | |
869 | return -EAGAIN; | |
870 | } | |
fba83f34 | 871 | nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0, 0); |
be3a5d23 TM |
872 | task = rpc_run_task(&task_setup); |
873 | if (IS_ERR(task)) | |
874 | return PTR_ERR(task); | |
3f807e5a | 875 | rpc_put_task(task); |
be3a5d23 TM |
876 | return 0; |
877 | } | |
e5341f3a | 878 | |
3eb86093 TM |
879 | static struct nfs42_layouterror_data * |
880 | nfs42_alloc_layouterror_data(struct pnfs_layout_segment *lseg, gfp_t gfp_flags) | |
881 | { | |
882 | struct nfs42_layouterror_data *data; | |
883 | struct inode *inode = lseg->pls_layout->plh_inode; | |
884 | ||
885 | data = kzalloc(sizeof(*data), gfp_flags); | |
886 | if (data) { | |
887 | data->args.inode = data->inode = nfs_igrab_and_active(inode); | |
888 | if (data->inode) { | |
889 | data->lseg = pnfs_get_lseg(lseg); | |
890 | if (data->lseg) | |
891 | return data; | |
892 | nfs_iput_and_deactive(data->inode); | |
893 | } | |
894 | kfree(data); | |
895 | } | |
896 | return NULL; | |
897 | } | |
898 | ||
899 | static void | |
900 | nfs42_free_layouterror_data(struct nfs42_layouterror_data *data) | |
901 | { | |
902 | pnfs_put_lseg(data->lseg); | |
903 | nfs_iput_and_deactive(data->inode); | |
904 | kfree(data); | |
905 | } | |
906 | ||
907 | static void | |
908 | nfs42_layouterror_prepare(struct rpc_task *task, void *calldata) | |
909 | { | |
910 | struct nfs42_layouterror_data *data = calldata; | |
911 | struct inode *inode = data->inode; | |
912 | struct nfs_server *server = NFS_SERVER(inode); | |
913 | struct pnfs_layout_hdr *lo = data->lseg->pls_layout; | |
914 | unsigned i; | |
915 | ||
916 | spin_lock(&inode->i_lock); | |
917 | if (!pnfs_layout_is_valid(lo)) { | |
918 | spin_unlock(&inode->i_lock); | |
919 | rpc_exit(task, 0); | |
920 | return; | |
921 | } | |
922 | for (i = 0; i < data->args.num_errors; i++) | |
923 | nfs4_stateid_copy(&data->args.errors[i].stateid, | |
924 | &lo->plh_stateid); | |
925 | spin_unlock(&inode->i_lock); | |
926 | nfs4_setup_sequence(server->nfs_client, &data->args.seq_args, | |
927 | &data->res.seq_res, task); | |
928 | } | |
929 | ||
930 | static void | |
931 | nfs42_layouterror_done(struct rpc_task *task, void *calldata) | |
932 | { | |
933 | struct nfs42_layouterror_data *data = calldata; | |
934 | struct inode *inode = data->inode; | |
935 | struct pnfs_layout_hdr *lo = data->lseg->pls_layout; | |
936 | ||
937 | if (!nfs4_sequence_done(task, &data->res.seq_res)) | |
938 | return; | |
939 | ||
940 | switch (task->tk_status) { | |
941 | case 0: | |
638037b1 | 942 | return; |
3eb86093 TM |
943 | case -NFS4ERR_BADHANDLE: |
944 | case -ESTALE: | |
945 | pnfs_destroy_layout(NFS_I(inode)); | |
946 | break; | |
947 | case -NFS4ERR_EXPIRED: | |
948 | case -NFS4ERR_ADMIN_REVOKED: | |
949 | case -NFS4ERR_DELEG_REVOKED: | |
950 | case -NFS4ERR_STALE_STATEID: | |
951 | case -NFS4ERR_BAD_STATEID: | |
952 | spin_lock(&inode->i_lock); | |
953 | if (pnfs_layout_is_valid(lo) && | |
954 | nfs4_stateid_match(&data->args.errors[0].stateid, | |
955 | &lo->plh_stateid)) { | |
956 | LIST_HEAD(head); | |
957 | ||
958 | /* | |
959 | * Mark the bad layout state as invalid, then retry | |
960 | * with the current stateid. | |
961 | */ | |
962 | pnfs_mark_layout_stateid_invalid(lo, &head); | |
963 | spin_unlock(&inode->i_lock); | |
964 | pnfs_free_lseg_list(&head); | |
965 | nfs_commit_inode(inode, 0); | |
966 | } else | |
967 | spin_unlock(&inode->i_lock); | |
968 | break; | |
969 | case -NFS4ERR_OLD_STATEID: | |
970 | spin_lock(&inode->i_lock); | |
971 | if (pnfs_layout_is_valid(lo) && | |
972 | nfs4_stateid_match_other(&data->args.errors[0].stateid, | |
973 | &lo->plh_stateid)) { | |
974 | /* Do we need to delay before resending? */ | |
975 | if (!nfs4_stateid_is_newer(&lo->plh_stateid, | |
976 | &data->args.errors[0].stateid)) | |
977 | rpc_delay(task, HZ); | |
978 | rpc_restart_call_prepare(task); | |
979 | } | |
980 | spin_unlock(&inode->i_lock); | |
981 | break; | |
982 | case -ENOTSUPP: | |
983 | case -EOPNOTSUPP: | |
984 | NFS_SERVER(inode)->caps &= ~NFS_CAP_LAYOUTERROR; | |
985 | } | |
638037b1 TM |
986 | |
987 | trace_nfs4_layouterror(inode, &data->args.errors[0].stateid, | |
988 | task->tk_status); | |
3eb86093 TM |
989 | } |
990 | ||
991 | static void | |
992 | nfs42_layouterror_release(void *calldata) | |
993 | { | |
994 | struct nfs42_layouterror_data *data = calldata; | |
995 | ||
996 | nfs42_free_layouterror_data(data); | |
997 | } | |
998 | ||
999 | static const struct rpc_call_ops nfs42_layouterror_ops = { | |
1000 | .rpc_call_prepare = nfs42_layouterror_prepare, | |
1001 | .rpc_call_done = nfs42_layouterror_done, | |
1002 | .rpc_release = nfs42_layouterror_release, | |
1003 | }; | |
1004 | ||
1005 | int nfs42_proc_layouterror(struct pnfs_layout_segment *lseg, | |
1006 | const struct nfs42_layout_error *errors, size_t n) | |
1007 | { | |
1008 | struct inode *inode = lseg->pls_layout->plh_inode; | |
1009 | struct nfs42_layouterror_data *data; | |
1010 | struct rpc_task *task; | |
1011 | struct rpc_message msg = { | |
1012 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTERROR], | |
1013 | }; | |
1014 | struct rpc_task_setup task_setup = { | |
1015 | .rpc_message = &msg, | |
1016 | .callback_ops = &nfs42_layouterror_ops, | |
1017 | .flags = RPC_TASK_ASYNC, | |
1018 | }; | |
1019 | unsigned int i; | |
1020 | ||
1021 | if (!nfs_server_capable(inode, NFS_CAP_LAYOUTERROR)) | |
1022 | return -EOPNOTSUPP; | |
1023 | if (n > NFS42_LAYOUTERROR_MAX) | |
1024 | return -EINVAL; | |
63d8a41b | 1025 | data = nfs42_alloc_layouterror_data(lseg, nfs_io_gfp_mask()); |
3eb86093 TM |
1026 | if (!data) |
1027 | return -ENOMEM; | |
1028 | for (i = 0; i < n; i++) { | |
1029 | data->args.errors[i] = errors[i]; | |
1030 | data->args.num_errors++; | |
1031 | data->res.num_errors++; | |
1032 | } | |
1033 | msg.rpc_argp = &data->args; | |
1034 | msg.rpc_resp = &data->res; | |
1035 | task_setup.callback_data = data; | |
1036 | task_setup.rpc_client = NFS_SERVER(inode)->client; | |
1037 | nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0, 0); | |
1038 | task = rpc_run_task(&task_setup); | |
1039 | if (IS_ERR(task)) | |
1040 | return PTR_ERR(task); | |
1041 | rpc_put_task(task); | |
1042 | return 0; | |
1043 | } | |
1044 | EXPORT_SYMBOL_GPL(nfs42_proc_layouterror); | |
1045 | ||
e5341f3a | 1046 | static int _nfs42_proc_clone(struct rpc_message *msg, struct file *src_f, |
4bdf87eb CH |
1047 | struct file *dst_f, struct nfs_lock_context *src_lock, |
1048 | struct nfs_lock_context *dst_lock, loff_t src_offset, | |
1049 | loff_t dst_offset, loff_t count) | |
e5341f3a PT |
1050 | { |
1051 | struct inode *src_inode = file_inode(src_f); | |
1052 | struct inode *dst_inode = file_inode(dst_f); | |
1053 | struct nfs_server *server = NFS_SERVER(dst_inode); | |
34bf20ce | 1054 | __u32 dst_bitmask[NFS_BITMASK_SZ]; |
e5341f3a PT |
1055 | struct nfs42_clone_args args = { |
1056 | .src_fh = NFS_FH(src_inode), | |
1057 | .dst_fh = NFS_FH(dst_inode), | |
1058 | .src_offset = src_offset, | |
1059 | .dst_offset = dst_offset, | |
9494b2ce | 1060 | .count = count, |
34bf20ce | 1061 | .dst_bitmask = dst_bitmask, |
e5341f3a PT |
1062 | }; |
1063 | struct nfs42_clone_res res = { | |
1064 | .server = server, | |
1065 | }; | |
1066 | int status; | |
1067 | ||
1068 | msg->rpc_argp = &args; | |
1069 | msg->rpc_resp = &res; | |
1070 | ||
4bdf87eb CH |
1071 | status = nfs4_set_rw_stateid(&args.src_stateid, src_lock->open_context, |
1072 | src_lock, FMODE_READ); | |
d826e5b8 OK |
1073 | if (status) { |
1074 | if (status == -EAGAIN) | |
1075 | status = -NFS4ERR_BAD_STATEID; | |
e5341f3a | 1076 | return status; |
d826e5b8 | 1077 | } |
4bdf87eb CH |
1078 | status = nfs4_set_rw_stateid(&args.dst_stateid, dst_lock->open_context, |
1079 | dst_lock, FMODE_WRITE); | |
d826e5b8 OK |
1080 | if (status) { |
1081 | if (status == -EAGAIN) | |
1082 | status = -NFS4ERR_BAD_STATEID; | |
e5341f3a | 1083 | return status; |
d826e5b8 | 1084 | } |
e5341f3a PT |
1085 | |
1086 | res.dst_fattr = nfs_alloc_fattr(); | |
1087 | if (!res.dst_fattr) | |
1088 | return -ENOMEM; | |
1089 | ||
34bf20ce TM |
1090 | nfs4_bitmask_set(dst_bitmask, server->cache_consistency_bitmask, |
1091 | dst_inode, NFS_INO_INVALID_BLOCKS); | |
1092 | ||
e5341f3a PT |
1093 | status = nfs4_call_sync(server->client, server, msg, |
1094 | &args.seq_args, &res.seq_res, 0); | |
2a65ca8b | 1095 | trace_nfs4_clone(src_inode, dst_inode, &args, status); |
94d202d5 | 1096 | if (status == 0) { |
038efb63 BC |
1097 | /* a zero-length count means clone to EOF in src */ |
1098 | if (count == 0 && res.dst_fattr->valid & NFS_ATTR_FATTR_SIZE) | |
1099 | count = nfs_size_to_loff_t(res.dst_fattr->size) - dst_offset; | |
94d202d5 | 1100 | nfs42_copy_dest_done(dst_inode, dst_offset, count); |
e5341f3a | 1101 | status = nfs_post_op_update_inode(dst_inode, res.dst_fattr); |
94d202d5 | 1102 | } |
e5341f3a PT |
1103 | |
1104 | kfree(res.dst_fattr); | |
1105 | return status; | |
1106 | } | |
1107 | ||
1108 | int nfs42_proc_clone(struct file *src_f, struct file *dst_f, | |
1109 | loff_t src_offset, loff_t dst_offset, loff_t count) | |
1110 | { | |
1111 | struct rpc_message msg = { | |
1112 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLONE], | |
1113 | }; | |
1114 | struct inode *inode = file_inode(src_f); | |
1115 | struct nfs_server *server = NFS_SERVER(file_inode(src_f)); | |
4bdf87eb CH |
1116 | struct nfs_lock_context *src_lock; |
1117 | struct nfs_lock_context *dst_lock; | |
1118 | struct nfs4_exception src_exception = { }; | |
1119 | struct nfs4_exception dst_exception = { }; | |
1120 | int err, err2; | |
e5341f3a PT |
1121 | |
1122 | if (!nfs_server_capable(inode, NFS_CAP_CLONE)) | |
1123 | return -EOPNOTSUPP; | |
1124 | ||
4bdf87eb CH |
1125 | src_lock = nfs_get_lock_context(nfs_file_open_context(src_f)); |
1126 | if (IS_ERR(src_lock)) | |
1127 | return PTR_ERR(src_lock); | |
1128 | ||
1129 | src_exception.inode = file_inode(src_f); | |
1130 | src_exception.state = src_lock->open_context->state; | |
1131 | ||
1132 | dst_lock = nfs_get_lock_context(nfs_file_open_context(dst_f)); | |
1133 | if (IS_ERR(dst_lock)) { | |
1134 | err = PTR_ERR(dst_lock); | |
1135 | goto out_put_src_lock; | |
1136 | } | |
1137 | ||
1138 | dst_exception.inode = file_inode(dst_f); | |
1139 | dst_exception.state = dst_lock->open_context->state; | |
1140 | ||
e5341f3a | 1141 | do { |
4bdf87eb CH |
1142 | err = _nfs42_proc_clone(&msg, src_f, dst_f, src_lock, dst_lock, |
1143 | src_offset, dst_offset, count); | |
e5341f3a PT |
1144 | if (err == -ENOTSUPP || err == -EOPNOTSUPP) { |
1145 | NFS_SERVER(inode)->caps &= ~NFS_CAP_CLONE; | |
4bdf87eb CH |
1146 | err = -EOPNOTSUPP; |
1147 | break; | |
e5341f3a | 1148 | } |
e5341f3a | 1149 | |
4bdf87eb CH |
1150 | err2 = nfs4_handle_exception(server, err, &src_exception); |
1151 | err = nfs4_handle_exception(server, err, &dst_exception); | |
1152 | if (!err) | |
1153 | err = err2; | |
1154 | } while (src_exception.retry || dst_exception.retry); | |
e5341f3a | 1155 | |
4bdf87eb CH |
1156 | nfs_put_lock_context(dst_lock); |
1157 | out_put_src_lock: | |
1158 | nfs_put_lock_context(src_lock); | |
1159 | return err; | |
e5341f3a | 1160 | } |
c10a7514 FL |
1161 | |
1162 | #define NFS4XATTR_MAXPAGES DIV_ROUND_UP(XATTR_SIZE_MAX, PAGE_SIZE) | |
1163 | ||
1164 | static int _nfs42_proc_removexattr(struct inode *inode, const char *name) | |
1165 | { | |
1166 | struct nfs_server *server = NFS_SERVER(inode); | |
1167 | struct nfs42_removexattrargs args = { | |
1168 | .fh = NFS_FH(inode), | |
1169 | .xattr_name = name, | |
1170 | }; | |
1171 | struct nfs42_removexattrres res; | |
1172 | struct rpc_message msg = { | |
1173 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVEXATTR], | |
1174 | .rpc_argp = &args, | |
1175 | .rpc_resp = &res, | |
1176 | }; | |
1177 | int ret; | |
1178 | unsigned long timestamp = jiffies; | |
1179 | ||
1180 | ret = nfs4_call_sync(server->client, server, &msg, &args.seq_args, | |
1181 | &res.seq_res, 1); | |
27ffed10 | 1182 | trace_nfs4_removexattr(inode, name, ret); |
c10a7514 FL |
1183 | if (!ret) |
1184 | nfs4_update_changeattr(inode, &res.cinfo, timestamp, 0); | |
1185 | ||
1186 | return ret; | |
1187 | } | |
1188 | ||
1189 | static int _nfs42_proc_setxattr(struct inode *inode, const char *name, | |
1190 | const void *buf, size_t buflen, int flags) | |
1191 | { | |
1192 | struct nfs_server *server = NFS_SERVER(inode); | |
86e2e1f6 | 1193 | __u32 bitmask[NFS_BITMASK_SZ]; |
c10a7514 FL |
1194 | struct page *pages[NFS4XATTR_MAXPAGES]; |
1195 | struct nfs42_setxattrargs arg = { | |
1196 | .fh = NFS_FH(inode), | |
86e2e1f6 | 1197 | .bitmask = bitmask, |
c10a7514 FL |
1198 | .xattr_pages = pages, |
1199 | .xattr_len = buflen, | |
1200 | .xattr_name = name, | |
1201 | .xattr_flags = flags, | |
1202 | }; | |
86e2e1f6 AS |
1203 | struct nfs42_setxattrres res = { |
1204 | .server = server, | |
1205 | }; | |
c10a7514 FL |
1206 | struct rpc_message msg = { |
1207 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETXATTR], | |
1208 | .rpc_argp = &arg, | |
1209 | .rpc_resp = &res, | |
1210 | }; | |
1211 | int ret, np; | |
1212 | unsigned long timestamp = jiffies; | |
1213 | ||
1214 | if (buflen > server->sxasize) | |
1215 | return -ERANGE; | |
1216 | ||
86e2e1f6 AS |
1217 | res.fattr = nfs_alloc_fattr(); |
1218 | if (!res.fattr) | |
1219 | return -ENOMEM; | |
1220 | ||
c10a7514 FL |
1221 | if (buflen > 0) { |
1222 | np = nfs4_buf_to_pages_noslab(buf, buflen, arg.xattr_pages); | |
86e2e1f6 AS |
1223 | if (np < 0) { |
1224 | ret = np; | |
1225 | goto out; | |
1226 | } | |
c10a7514 FL |
1227 | } else |
1228 | np = 0; | |
1229 | ||
86e2e1f6 AS |
1230 | nfs4_bitmask_set(bitmask, server->cache_consistency_bitmask, |
1231 | inode, NFS_INO_INVALID_CHANGE); | |
1232 | ||
c10a7514 FL |
1233 | ret = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, |
1234 | &res.seq_res, 1); | |
27ffed10 | 1235 | trace_nfs4_setxattr(inode, name, ret); |
c10a7514 FL |
1236 | |
1237 | for (; np > 0; np--) | |
1238 | put_page(pages[np - 1]); | |
1239 | ||
86e2e1f6 | 1240 | if (!ret) { |
c10a7514 | 1241 | nfs4_update_changeattr(inode, &res.cinfo, timestamp, 0); |
86e2e1f6 AS |
1242 | ret = nfs_post_op_update_inode(inode, res.fattr); |
1243 | } | |
c10a7514 | 1244 | |
86e2e1f6 AS |
1245 | out: |
1246 | kfree(res.fattr); | |
c10a7514 FL |
1247 | return ret; |
1248 | } | |
1249 | ||
1250 | static ssize_t _nfs42_proc_getxattr(struct inode *inode, const char *name, | |
a1f26739 FL |
1251 | void *buf, size_t buflen, struct page **pages, |
1252 | size_t plen) | |
c10a7514 FL |
1253 | { |
1254 | struct nfs_server *server = NFS_SERVER(inode); | |
c10a7514 FL |
1255 | struct nfs42_getxattrargs arg = { |
1256 | .fh = NFS_FH(inode), | |
c10a7514 FL |
1257 | .xattr_name = name, |
1258 | }; | |
1259 | struct nfs42_getxattrres res; | |
1260 | struct rpc_message msg = { | |
1261 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETXATTR], | |
1262 | .rpc_argp = &arg, | |
1263 | .rpc_resp = &res, | |
1264 | }; | |
a1f26739 FL |
1265 | ssize_t ret; |
1266 | ||
1267 | arg.xattr_len = plen; | |
1268 | arg.xattr_pages = pages; | |
c10a7514 FL |
1269 | |
1270 | ret = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, | |
1271 | &res.seq_res, 0); | |
27ffed10 | 1272 | trace_nfs4_getxattr(inode, name, ret); |
c10a7514 FL |
1273 | if (ret < 0) |
1274 | return ret; | |
1275 | ||
95ad37f9 FL |
1276 | /* |
1277 | * Normally, the caching is done one layer up, but for successful | |
1278 | * RPCS, always cache the result here, even if the caller was | |
1279 | * just querying the length, or if the reply was too big for | |
1280 | * the caller. This avoids a second RPC in the case of the | |
1281 | * common query-alloc-retrieve cycle for xattrs. | |
1282 | * | |
1283 | * Note that xattr_len is always capped to XATTR_SIZE_MAX. | |
1284 | */ | |
1285 | ||
1286 | nfs4_xattr_cache_add(inode, name, NULL, pages, res.xattr_len); | |
1287 | ||
c10a7514 FL |
1288 | if (buflen) { |
1289 | if (res.xattr_len > buflen) | |
1290 | return -ERANGE; | |
1291 | _copy_from_pages(buf, pages, 0, res.xattr_len); | |
1292 | } | |
1293 | ||
c10a7514 FL |
1294 | return res.xattr_len; |
1295 | } | |
1296 | ||
1297 | static ssize_t _nfs42_proc_listxattrs(struct inode *inode, void *buf, | |
1298 | size_t buflen, u64 *cookiep, bool *eofp) | |
1299 | { | |
1300 | struct nfs_server *server = NFS_SERVER(inode); | |
1301 | struct page **pages; | |
1302 | struct nfs42_listxattrsargs arg = { | |
1303 | .fh = NFS_FH(inode), | |
1304 | .cookie = *cookiep, | |
1305 | }; | |
1306 | struct nfs42_listxattrsres res = { | |
1307 | .eof = false, | |
1308 | .xattr_buf = buf, | |
1309 | .xattr_len = buflen, | |
1310 | }; | |
1311 | struct rpc_message msg = { | |
1312 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LISTXATTRS], | |
1313 | .rpc_argp = &arg, | |
1314 | .rpc_resp = &res, | |
1315 | }; | |
1316 | u32 xdrlen; | |
5482e09a | 1317 | int ret, np, i; |
c10a7514 FL |
1318 | |
1319 | ||
5482e09a | 1320 | ret = -ENOMEM; |
c10a7514 FL |
1321 | res.scratch = alloc_page(GFP_KERNEL); |
1322 | if (!res.scratch) | |
5482e09a | 1323 | goto out; |
c10a7514 FL |
1324 | |
1325 | xdrlen = nfs42_listxattr_xdrsize(buflen); | |
1326 | if (xdrlen > server->lxasize) | |
1327 | xdrlen = server->lxasize; | |
1328 | np = xdrlen / PAGE_SIZE + 1; | |
1329 | ||
1330 | pages = kcalloc(np, sizeof(struct page *), GFP_KERNEL); | |
5482e09a CL |
1331 | if (!pages) |
1332 | goto out_free_scratch; | |
1333 | for (i = 0; i < np; i++) { | |
1334 | pages[i] = alloc_page(GFP_KERNEL); | |
1335 | if (!pages[i]) | |
1336 | goto out_free_pages; | |
c10a7514 FL |
1337 | } |
1338 | ||
1339 | arg.xattr_pages = pages; | |
1340 | arg.count = xdrlen; | |
1341 | ||
1342 | ret = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, | |
1343 | &res.seq_res, 0); | |
a0b685e7 | 1344 | trace_nfs4_listxattr(inode, ret); |
c10a7514 FL |
1345 | |
1346 | if (ret >= 0) { | |
1347 | ret = res.copied; | |
1348 | *cookiep = res.cookie; | |
1349 | *eofp = res.eof; | |
1350 | } | |
1351 | ||
5482e09a | 1352 | out_free_pages: |
c10a7514 FL |
1353 | while (--np >= 0) { |
1354 | if (pages[np]) | |
1355 | __free_page(pages[np]); | |
1356 | } | |
c10a7514 | 1357 | kfree(pages); |
5482e09a CL |
1358 | out_free_scratch: |
1359 | __free_page(res.scratch); | |
1360 | out: | |
c10a7514 FL |
1361 | return ret; |
1362 | ||
1363 | } | |
1364 | ||
1365 | ssize_t nfs42_proc_getxattr(struct inode *inode, const char *name, | |
1366 | void *buf, size_t buflen) | |
1367 | { | |
1368 | struct nfs4_exception exception = { }; | |
a1f26739 FL |
1369 | ssize_t err, np, i; |
1370 | struct page **pages; | |
1371 | ||
1372 | np = nfs_page_array_len(0, buflen ?: XATTR_SIZE_MAX); | |
1373 | pages = kmalloc_array(np, sizeof(*pages), GFP_KERNEL); | |
1374 | if (!pages) | |
1375 | return -ENOMEM; | |
1376 | ||
1377 | for (i = 0; i < np; i++) { | |
1378 | pages[i] = alloc_page(GFP_KERNEL); | |
1379 | if (!pages[i]) { | |
7be9b38a | 1380 | err = -ENOMEM; |
a1f26739 FL |
1381 | goto out; |
1382 | } | |
1383 | } | |
c10a7514 | 1384 | |
a1f26739 FL |
1385 | /* |
1386 | * The GETXATTR op has no length field in the call, and the | |
1387 | * xattr data is at the end of the reply. | |
1388 | * | |
1389 | * There is no downside in using the page-aligned length. It will | |
1390 | * allow receiving and caching xattrs that are too large for the | |
1391 | * caller but still fit in the page-rounded value. | |
1392 | */ | |
c10a7514 | 1393 | do { |
a1f26739 FL |
1394 | err = _nfs42_proc_getxattr(inode, name, buf, buflen, |
1395 | pages, np * PAGE_SIZE); | |
c10a7514 FL |
1396 | if (err >= 0) |
1397 | break; | |
1398 | err = nfs4_handle_exception(NFS_SERVER(inode), err, | |
1399 | &exception); | |
1400 | } while (exception.retry); | |
1401 | ||
a1f26739 | 1402 | out: |
4e3733fd FP |
1403 | while (--i >= 0) |
1404 | __free_page(pages[i]); | |
a1f26739 FL |
1405 | kfree(pages); |
1406 | ||
c10a7514 FL |
1407 | return err; |
1408 | } | |
1409 | ||
1410 | int nfs42_proc_setxattr(struct inode *inode, const char *name, | |
1411 | const void *buf, size_t buflen, int flags) | |
1412 | { | |
1413 | struct nfs4_exception exception = { }; | |
1414 | int err; | |
1415 | ||
1416 | do { | |
1417 | err = _nfs42_proc_setxattr(inode, name, buf, buflen, flags); | |
1418 | if (!err) | |
1419 | break; | |
1420 | err = nfs4_handle_exception(NFS_SERVER(inode), err, | |
1421 | &exception); | |
1422 | } while (exception.retry); | |
1423 | ||
1424 | return err; | |
1425 | } | |
1426 | ||
1427 | ssize_t nfs42_proc_listxattrs(struct inode *inode, void *buf, | |
1428 | size_t buflen, u64 *cookiep, bool *eofp) | |
1429 | { | |
1430 | struct nfs4_exception exception = { }; | |
1431 | ssize_t err; | |
1432 | ||
1433 | do { | |
1434 | err = _nfs42_proc_listxattrs(inode, buf, buflen, | |
1435 | cookiep, eofp); | |
1436 | if (err >= 0) | |
1437 | break; | |
1438 | err = nfs4_handle_exception(NFS_SERVER(inode), err, | |
1439 | &exception); | |
1440 | } while (exception.retry); | |
1441 | ||
1442 | return err; | |
1443 | } | |
1444 | ||
1445 | int nfs42_proc_removexattr(struct inode *inode, const char *name) | |
1446 | { | |
1447 | struct nfs4_exception exception = { }; | |
1448 | int err; | |
1449 | ||
1450 | do { | |
1451 | err = _nfs42_proc_removexattr(inode, name); | |
1452 | if (!err) | |
1453 | break; | |
1454 | err = nfs4_handle_exception(NFS_SERVER(inode), err, | |
1455 | &exception); | |
1456 | } while (exception.retry); | |
1457 | ||
1458 | return err; | |
1459 | } |