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