diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-11-09 21:11:22 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-11-09 21:11:22 -0500 |
commit | e6604ecb70d4b1dbc0372c6518b51c25c4b135a1 (patch) | |
tree | 2d12c51b84c3ba8472e59ddbe37da034e2c5251f /fs/nfs | |
parent | 9d74288ca79249af4b906215788b37d52263b58b (diff) | |
parent | 941c3ff3102ccce440034d59cf9e4e9cc10b720d (diff) |
Merge tag 'nfs-for-4.4-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client updates from Trond Myklebust:
"Highlights include:
New features:
- RDMA client backchannel from Chuck
- Support for NFSv4.2 file CLONE using the btrfs ioctl
Bugfixes + cleanups:
- Move socket data receive out of the bottom halves and into a
workqueue
- Refactor NFSv4 error handling so synchronous and asynchronous RPC
handles errors identically.
- Fix a panic when blocks or object layouts reads return a bad data
length
- Fix nfsroot so it can handle a 1024 byte long path.
- Fix bad usage of page offset in bl_read_pagelist
- Various NFSv4 callback cleanups+fixes
- Fix GETATTR bitmap verification
- Support hexadecimal number for sunrpc debug sysctl files"
* tag 'nfs-for-4.4-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (53 commits)
Sunrpc: Supports hexadecimal number for sysctl files of sunrpc debug
nfs: Fix GETATTR bitmap verification
nfs: Remove unused xdr page offsets in getacl/setacl arguments
fs/nfs: remove unnecessary new_valid_dev check
SUNRPC: fix variable type
NFS: Enable client side NFSv4.1 backchannel to use other transports
pNFS/flexfiles: Add support for FF_FLAGS_NO_IO_THRU_MDS
pNFS/flexfiles: When mirrored, retry failed reads by switching mirrors
SUNRPC: Remove the TCP-only restriction in bc_svc_process()
svcrdma: Add backward direction service for RPC/RDMA transport
xprtrdma: Handle incoming backward direction RPC calls
xprtrdma: Add support for sending backward direction RPC replies
xprtrdma: Pre-allocate Work Requests for backchannel
xprtrdma: Pre-allocate backward rpc_rqst and send/receive buffers
SUNRPC: Abstract backchannel operations
xprtrdma: Saving IRQs no longer needed for rb_lock
xprtrdma: Remove reply tasklet
xprtrdma: Use workqueue to process RPC/RDMA replies
xprtrdma: Replace send and receive arrays
xprtrdma: Refactor reply handler error handling
...
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/blocklayout/blocklayout.c | 7 | ||||
-rw-r--r-- | fs/nfs/callback.c | 40 | ||||
-rw-r--r-- | fs/nfs/callback.h | 12 | ||||
-rw-r--r-- | fs/nfs/callback_proc.c | 2 | ||||
-rw-r--r-- | fs/nfs/callback_xdr.c | 39 | ||||
-rw-r--r-- | fs/nfs/client.c | 1 | ||||
-rw-r--r-- | fs/nfs/delegation.c | 6 | ||||
-rw-r--r-- | fs/nfs/dir.c | 3 | ||||
-rw-r--r-- | fs/nfs/flexfilelayout/flexfilelayout.c | 40 | ||||
-rw-r--r-- | fs/nfs/flexfilelayout/flexfilelayout.h | 7 | ||||
-rw-r--r-- | fs/nfs/mount_clnt.c | 4 | ||||
-rw-r--r-- | fs/nfs/nfs42.h | 1 | ||||
-rw-r--r-- | fs/nfs/nfs42proc.c | 71 | ||||
-rw-r--r-- | fs/nfs/nfs42xdr.c | 97 | ||||
-rw-r--r-- | fs/nfs/nfs4_fs.h | 6 | ||||
-rw-r--r-- | fs/nfs/nfs4file.c | 136 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 182 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 53 | ||||
-rw-r--r-- | fs/nfs/nfsroot.c | 2 | ||||
-rw-r--r-- | fs/nfs/pnfs.c | 12 | ||||
-rw-r--r-- | fs/nfs/read.c | 9 | ||||
-rw-r--r-- | fs/nfs/super.c | 2 | ||||
-rw-r--r-- | fs/nfs/write.c | 7 |
23 files changed, 542 insertions, 197 deletions
diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c index 9cd4eb3a1e22..ddd0138f410c 100644 --- a/fs/nfs/blocklayout/blocklayout.c +++ b/fs/nfs/blocklayout/blocklayout.c | |||
@@ -229,7 +229,7 @@ bl_read_pagelist(struct nfs_pgio_header *header) | |||
229 | struct parallel_io *par; | 229 | struct parallel_io *par; |
230 | loff_t f_offset = header->args.offset; | 230 | loff_t f_offset = header->args.offset; |
231 | size_t bytes_left = header->args.count; | 231 | size_t bytes_left = header->args.count; |
232 | unsigned int pg_offset, pg_len; | 232 | unsigned int pg_offset = header->args.pgbase, pg_len; |
233 | struct page **pages = header->args.pages; | 233 | struct page **pages = header->args.pages; |
234 | int pg_index = header->args.pgbase >> PAGE_CACHE_SHIFT; | 234 | int pg_index = header->args.pgbase >> PAGE_CACHE_SHIFT; |
235 | const bool is_dio = (header->dreq != NULL); | 235 | const bool is_dio = (header->dreq != NULL); |
@@ -262,7 +262,6 @@ bl_read_pagelist(struct nfs_pgio_header *header) | |||
262 | extent_length = be.be_length - (isect - be.be_f_offset); | 262 | extent_length = be.be_length - (isect - be.be_f_offset); |
263 | } | 263 | } |
264 | 264 | ||
265 | pg_offset = f_offset & ~PAGE_CACHE_MASK; | ||
266 | if (is_dio) { | 265 | if (is_dio) { |
267 | if (pg_offset + bytes_left > PAGE_CACHE_SIZE) | 266 | if (pg_offset + bytes_left > PAGE_CACHE_SIZE) |
268 | pg_len = PAGE_CACHE_SIZE - pg_offset; | 267 | pg_len = PAGE_CACHE_SIZE - pg_offset; |
@@ -273,9 +272,6 @@ bl_read_pagelist(struct nfs_pgio_header *header) | |||
273 | pg_len = PAGE_CACHE_SIZE; | 272 | pg_len = PAGE_CACHE_SIZE; |
274 | } | 273 | } |
275 | 274 | ||
276 | isect += (pg_offset >> SECTOR_SHIFT); | ||
277 | extent_length -= (pg_offset >> SECTOR_SHIFT); | ||
278 | |||
279 | if (is_hole(&be)) { | 275 | if (is_hole(&be)) { |
280 | bio = bl_submit_bio(READ, bio); | 276 | bio = bl_submit_bio(READ, bio); |
281 | /* Fill hole w/ zeroes w/o accessing device */ | 277 | /* Fill hole w/ zeroes w/o accessing device */ |
@@ -301,6 +297,7 @@ bl_read_pagelist(struct nfs_pgio_header *header) | |||
301 | extent_length -= (pg_len >> SECTOR_SHIFT); | 297 | extent_length -= (pg_len >> SECTOR_SHIFT); |
302 | f_offset += pg_len; | 298 | f_offset += pg_len; |
303 | bytes_left -= pg_len; | 299 | bytes_left -= pg_len; |
300 | pg_offset = 0; | ||
304 | } | 301 | } |
305 | if ((isect << SECTOR_SHIFT) >= header->inode->i_size) { | 302 | if ((isect << SECTOR_SHIFT) >= header->inode->i_size) { |
306 | header->res.eof = 1; | 303 | header->res.eof = 1; |
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 75f7c0a7538a..a7f2e6e33305 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
@@ -99,17 +99,6 @@ nfs4_callback_up(struct svc_serv *serv) | |||
99 | } | 99 | } |
100 | 100 | ||
101 | #if defined(CONFIG_NFS_V4_1) | 101 | #if defined(CONFIG_NFS_V4_1) |
102 | static int nfs41_callback_up_net(struct svc_serv *serv, struct net *net) | ||
103 | { | ||
104 | /* | ||
105 | * Create an svc_sock for the back channel service that shares the | ||
106 | * fore channel connection. | ||
107 | * Returns the input port (0) and sets the svc_serv bc_xprt on success | ||
108 | */ | ||
109 | return svc_create_xprt(serv, "tcp-bc", net, PF_INET, 0, | ||
110 | SVC_SOCK_ANONYMOUS); | ||
111 | } | ||
112 | |||
113 | /* | 102 | /* |
114 | * The callback service for NFSv4.1 callbacks | 103 | * The callback service for NFSv4.1 callbacks |
115 | */ | 104 | */ |
@@ -184,11 +173,6 @@ static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt, | |||
184 | xprt->bc_serv = serv; | 173 | xprt->bc_serv = serv; |
185 | } | 174 | } |
186 | #else | 175 | #else |
187 | static int nfs41_callback_up_net(struct svc_serv *serv, struct net *net) | ||
188 | { | ||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | static void nfs_minorversion_callback_svc_setup(struct svc_serv *serv, | 176 | static void nfs_minorversion_callback_svc_setup(struct svc_serv *serv, |
193 | struct svc_rqst **rqstpp, int (**callback_svc)(void *vrqstp)) | 177 | struct svc_rqst **rqstpp, int (**callback_svc)(void *vrqstp)) |
194 | { | 178 | { |
@@ -259,7 +243,8 @@ static void nfs_callback_down_net(u32 minorversion, struct svc_serv *serv, struc | |||
259 | svc_shutdown_net(serv, net); | 243 | svc_shutdown_net(serv, net); |
260 | } | 244 | } |
261 | 245 | ||
262 | static int nfs_callback_up_net(int minorversion, struct svc_serv *serv, struct net *net) | 246 | static int nfs_callback_up_net(int minorversion, struct svc_serv *serv, |
247 | struct net *net, struct rpc_xprt *xprt) | ||
263 | { | 248 | { |
264 | struct nfs_net *nn = net_generic(net, nfs_net_id); | 249 | struct nfs_net *nn = net_generic(net, nfs_net_id); |
265 | int ret; | 250 | int ret; |
@@ -275,20 +260,11 @@ static int nfs_callback_up_net(int minorversion, struct svc_serv *serv, struct n | |||
275 | goto err_bind; | 260 | goto err_bind; |
276 | } | 261 | } |
277 | 262 | ||
278 | switch (minorversion) { | 263 | ret = -EPROTONOSUPPORT; |
279 | case 0: | 264 | if (minorversion == 0) |
280 | ret = nfs4_callback_up_net(serv, net); | 265 | ret = nfs4_callback_up_net(serv, net); |
281 | break; | 266 | else if (xprt->ops->bc_up) |
282 | case 1: | 267 | ret = xprt->ops->bc_up(serv, net); |
283 | case 2: | ||
284 | ret = nfs41_callback_up_net(serv, net); | ||
285 | break; | ||
286 | default: | ||
287 | printk(KERN_ERR "NFS: unknown callback version: %d\n", | ||
288 | minorversion); | ||
289 | ret = -EINVAL; | ||
290 | break; | ||
291 | } | ||
292 | 268 | ||
293 | if (ret < 0) { | 269 | if (ret < 0) { |
294 | printk(KERN_ERR "NFS: callback service start failed\n"); | 270 | printk(KERN_ERR "NFS: callback service start failed\n"); |
@@ -364,7 +340,7 @@ int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt) | |||
364 | goto err_create; | 340 | goto err_create; |
365 | } | 341 | } |
366 | 342 | ||
367 | ret = nfs_callback_up_net(minorversion, serv, net); | 343 | ret = nfs_callback_up_net(minorversion, serv, net, xprt); |
368 | if (ret < 0) | 344 | if (ret < 0) |
369 | goto err_net; | 345 | goto err_net; |
370 | 346 | ||
diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h index 84326e9fb47a..ff8195bd75ea 100644 --- a/fs/nfs/callback.h +++ b/fs/nfs/callback.h | |||
@@ -61,7 +61,6 @@ struct cb_compound_hdr_res { | |||
61 | }; | 61 | }; |
62 | 62 | ||
63 | struct cb_getattrargs { | 63 | struct cb_getattrargs { |
64 | struct sockaddr *addr; | ||
65 | struct nfs_fh fh; | 64 | struct nfs_fh fh; |
66 | uint32_t bitmap[2]; | 65 | uint32_t bitmap[2]; |
67 | }; | 66 | }; |
@@ -76,7 +75,6 @@ struct cb_getattrres { | |||
76 | }; | 75 | }; |
77 | 76 | ||
78 | struct cb_recallargs { | 77 | struct cb_recallargs { |
79 | struct sockaddr *addr; | ||
80 | struct nfs_fh fh; | 78 | struct nfs_fh fh; |
81 | nfs4_stateid stateid; | 79 | nfs4_stateid stateid; |
82 | uint32_t truncate; | 80 | uint32_t truncate; |
@@ -119,9 +117,6 @@ extern __be32 nfs4_callback_sequence(struct cb_sequenceargs *args, | |||
119 | struct cb_sequenceres *res, | 117 | struct cb_sequenceres *res, |
120 | struct cb_process_state *cps); | 118 | struct cb_process_state *cps); |
121 | 119 | ||
122 | extern int nfs41_validate_delegation_stateid(struct nfs_delegation *delegation, | ||
123 | const nfs4_stateid *stateid); | ||
124 | |||
125 | #define RCA4_TYPE_MASK_RDATA_DLG 0 | 120 | #define RCA4_TYPE_MASK_RDATA_DLG 0 |
126 | #define RCA4_TYPE_MASK_WDATA_DLG 1 | 121 | #define RCA4_TYPE_MASK_WDATA_DLG 1 |
127 | #define RCA4_TYPE_MASK_DIR_DLG 2 | 122 | #define RCA4_TYPE_MASK_DIR_DLG 2 |
@@ -134,7 +129,6 @@ extern int nfs41_validate_delegation_stateid(struct nfs_delegation *delegation, | |||
134 | #define RCA4_TYPE_MASK_ALL 0xf31f | 129 | #define RCA4_TYPE_MASK_ALL 0xf31f |
135 | 130 | ||
136 | struct cb_recallanyargs { | 131 | struct cb_recallanyargs { |
137 | struct sockaddr *craa_addr; | ||
138 | uint32_t craa_objs_to_keep; | 132 | uint32_t craa_objs_to_keep; |
139 | uint32_t craa_type_mask; | 133 | uint32_t craa_type_mask; |
140 | }; | 134 | }; |
@@ -144,7 +138,6 @@ extern __be32 nfs4_callback_recallany(struct cb_recallanyargs *args, | |||
144 | struct cb_process_state *cps); | 138 | struct cb_process_state *cps); |
145 | 139 | ||
146 | struct cb_recallslotargs { | 140 | struct cb_recallslotargs { |
147 | struct sockaddr *crsa_addr; | ||
148 | uint32_t crsa_target_highest_slotid; | 141 | uint32_t crsa_target_highest_slotid; |
149 | }; | 142 | }; |
150 | extern __be32 nfs4_callback_recallslot(struct cb_recallslotargs *args, | 143 | extern __be32 nfs4_callback_recallslot(struct cb_recallslotargs *args, |
@@ -152,7 +145,6 @@ extern __be32 nfs4_callback_recallslot(struct cb_recallslotargs *args, | |||
152 | struct cb_process_state *cps); | 145 | struct cb_process_state *cps); |
153 | 146 | ||
154 | struct cb_layoutrecallargs { | 147 | struct cb_layoutrecallargs { |
155 | struct sockaddr *cbl_addr; | ||
156 | uint32_t cbl_recall_type; | 148 | uint32_t cbl_recall_type; |
157 | uint32_t cbl_layout_type; | 149 | uint32_t cbl_layout_type; |
158 | uint32_t cbl_layoutchanged; | 150 | uint32_t cbl_layoutchanged; |
@@ -196,9 +188,6 @@ extern __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy, | |||
196 | #if IS_ENABLED(CONFIG_NFS_V4) | 188 | #if IS_ENABLED(CONFIG_NFS_V4) |
197 | extern int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt); | 189 | extern int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt); |
198 | extern void nfs_callback_down(int minorversion, struct net *net); | 190 | extern void nfs_callback_down(int minorversion, struct net *net); |
199 | extern int nfs4_validate_delegation_stateid(struct nfs_delegation *delegation, | ||
200 | const nfs4_stateid *stateid); | ||
201 | extern int nfs4_set_callback_sessionid(struct nfs_client *clp); | ||
202 | #endif /* CONFIG_NFS_V4 */ | 191 | #endif /* CONFIG_NFS_V4 */ |
203 | /* | 192 | /* |
204 | * nfs41: Callbacks are expected to not cause substantial latency, | 193 | * nfs41: Callbacks are expected to not cause substantial latency, |
@@ -209,6 +198,5 @@ extern int nfs4_set_callback_sessionid(struct nfs_client *clp); | |||
209 | #define NFS41_BC_MAX_CALLBACKS 1 | 198 | #define NFS41_BC_MAX_CALLBACKS 1 |
210 | 199 | ||
211 | extern unsigned int nfs_callback_set_tcpport; | 200 | extern unsigned int nfs_callback_set_tcpport; |
212 | extern unsigned short nfs_callback_tcpport; | ||
213 | 201 | ||
214 | #endif /* __LINUX_FS_NFS_CALLBACK_H */ | 202 | #endif /* __LINUX_FS_NFS_CALLBACK_H */ |
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index b85cf7a30232..807eb6ef4f91 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
@@ -17,9 +17,7 @@ | |||
17 | #include "nfs4session.h" | 17 | #include "nfs4session.h" |
18 | #include "nfs4trace.h" | 18 | #include "nfs4trace.h" |
19 | 19 | ||
20 | #ifdef NFS_DEBUG | ||
21 | #define NFSDBG_FACILITY NFSDBG_CALLBACK | 20 | #define NFSDBG_FACILITY NFSDBG_CALLBACK |
22 | #endif | ||
23 | 21 | ||
24 | __be32 nfs4_callback_getattr(struct cb_getattrargs *args, | 22 | __be32 nfs4_callback_getattr(struct cb_getattrargs *args, |
25 | struct cb_getattrres *res, | 23 | struct cb_getattrres *res, |
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index 6b1697a01dde..646cdac73488 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c | |||
@@ -18,19 +18,21 @@ | |||
18 | #include "internal.h" | 18 | #include "internal.h" |
19 | #include "nfs4session.h" | 19 | #include "nfs4session.h" |
20 | 20 | ||
21 | #define CB_OP_TAGLEN_MAXSZ (512) | 21 | #define CB_OP_TAGLEN_MAXSZ (512) |
22 | #define CB_OP_HDR_RES_MAXSZ (2 + CB_OP_TAGLEN_MAXSZ) | 22 | #define CB_OP_HDR_RES_MAXSZ (2 * 4) // opcode, status |
23 | #define CB_OP_GETATTR_BITMAP_MAXSZ (4) | 23 | #define CB_OP_GETATTR_BITMAP_MAXSZ (4 * 4) // bitmap length, 3 bitmaps |
24 | #define CB_OP_GETATTR_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ + \ | 24 | #define CB_OP_GETATTR_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ + \ |
25 | CB_OP_GETATTR_BITMAP_MAXSZ + \ | 25 | CB_OP_GETATTR_BITMAP_MAXSZ + \ |
26 | 2 + 2 + 3 + 3) | 26 | /* change, size, ctime, mtime */\ |
27 | #define CB_OP_RECALL_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) | 27 | (2 + 2 + 3 + 3) * 4) |
28 | #define CB_OP_RECALL_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) | ||
28 | 29 | ||
29 | #if defined(CONFIG_NFS_V4_1) | 30 | #if defined(CONFIG_NFS_V4_1) |
30 | #define CB_OP_LAYOUTRECALL_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) | 31 | #define CB_OP_LAYOUTRECALL_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) |
31 | #define CB_OP_DEVICENOTIFY_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) | 32 | #define CB_OP_DEVICENOTIFY_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) |
32 | #define CB_OP_SEQUENCE_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ + \ | 33 | #define CB_OP_SEQUENCE_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ + \ |
33 | 4 + 1 + 3) | 34 | NFS4_MAX_SESSIONID_LEN + \ |
35 | (1 + 3) * 4) // seqid, 3 slotids | ||
34 | #define CB_OP_RECALLANY_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) | 36 | #define CB_OP_RECALLANY_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) |
35 | #define CB_OP_RECALLSLOT_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) | 37 | #define CB_OP_RECALLSLOT_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) |
36 | #endif /* CONFIG_NFS_V4_1 */ | 38 | #endif /* CONFIG_NFS_V4_1 */ |
@@ -157,7 +159,7 @@ static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound | |||
157 | if (unlikely(status != 0)) | 159 | if (unlikely(status != 0)) |
158 | return status; | 160 | return status; |
159 | /* We do not like overly long tags! */ | 161 | /* We do not like overly long tags! */ |
160 | if (hdr->taglen > CB_OP_TAGLEN_MAXSZ - 12) { | 162 | if (hdr->taglen > CB_OP_TAGLEN_MAXSZ) { |
161 | printk("NFS: NFSv4 CALLBACK %s: client sent tag of length %u\n", | 163 | printk("NFS: NFSv4 CALLBACK %s: client sent tag of length %u\n", |
162 | __func__, hdr->taglen); | 164 | __func__, hdr->taglen); |
163 | return htonl(NFS4ERR_RESOURCE); | 165 | return htonl(NFS4ERR_RESOURCE); |
@@ -198,7 +200,6 @@ static __be32 decode_getattr_args(struct svc_rqst *rqstp, struct xdr_stream *xdr | |||
198 | status = decode_fh(xdr, &args->fh); | 200 | status = decode_fh(xdr, &args->fh); |
199 | if (unlikely(status != 0)) | 201 | if (unlikely(status != 0)) |
200 | goto out; | 202 | goto out; |
201 | args->addr = svc_addr(rqstp); | ||
202 | status = decode_bitmap(xdr, args->bitmap); | 203 | status = decode_bitmap(xdr, args->bitmap); |
203 | out: | 204 | out: |
204 | dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); | 205 | dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); |
@@ -210,7 +211,6 @@ static __be32 decode_recall_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, | |||
210 | __be32 *p; | 211 | __be32 *p; |
211 | __be32 status; | 212 | __be32 status; |
212 | 213 | ||
213 | args->addr = svc_addr(rqstp); | ||
214 | status = decode_stateid(xdr, &args->stateid); | 214 | status = decode_stateid(xdr, &args->stateid); |
215 | if (unlikely(status != 0)) | 215 | if (unlikely(status != 0)) |
216 | goto out; | 216 | goto out; |
@@ -236,7 +236,6 @@ static __be32 decode_layoutrecall_args(struct svc_rqst *rqstp, | |||
236 | __be32 status = 0; | 236 | __be32 status = 0; |
237 | uint32_t iomode; | 237 | uint32_t iomode; |
238 | 238 | ||
239 | args->cbl_addr = svc_addr(rqstp); | ||
240 | p = read_buf(xdr, 4 * sizeof(uint32_t)); | 239 | p = read_buf(xdr, 4 * sizeof(uint32_t)); |
241 | if (unlikely(p == NULL)) { | 240 | if (unlikely(p == NULL)) { |
242 | status = htonl(NFS4ERR_BADXDR); | 241 | status = htonl(NFS4ERR_BADXDR); |
@@ -383,13 +382,12 @@ static __be32 decode_sessionid(struct xdr_stream *xdr, | |||
383 | struct nfs4_sessionid *sid) | 382 | struct nfs4_sessionid *sid) |
384 | { | 383 | { |
385 | __be32 *p; | 384 | __be32 *p; |
386 | int len = NFS4_MAX_SESSIONID_LEN; | ||
387 | 385 | ||
388 | p = read_buf(xdr, len); | 386 | p = read_buf(xdr, NFS4_MAX_SESSIONID_LEN); |
389 | if (unlikely(p == NULL)) | 387 | if (unlikely(p == NULL)) |
390 | return htonl(NFS4ERR_RESOURCE); | 388 | return htonl(NFS4ERR_RESOURCE); |
391 | 389 | ||
392 | memcpy(sid->data, p, len); | 390 | memcpy(sid->data, p, NFS4_MAX_SESSIONID_LEN); |
393 | return 0; | 391 | return 0; |
394 | } | 392 | } |
395 | 393 | ||
@@ -500,7 +498,6 @@ static __be32 decode_recallany_args(struct svc_rqst *rqstp, | |||
500 | uint32_t bitmap[2]; | 498 | uint32_t bitmap[2]; |
501 | __be32 *p, status; | 499 | __be32 *p, status; |
502 | 500 | ||
503 | args->craa_addr = svc_addr(rqstp); | ||
504 | p = read_buf(xdr, 4); | 501 | p = read_buf(xdr, 4); |
505 | if (unlikely(p == NULL)) | 502 | if (unlikely(p == NULL)) |
506 | return htonl(NFS4ERR_BADXDR); | 503 | return htonl(NFS4ERR_BADXDR); |
@@ -519,7 +516,6 @@ static __be32 decode_recallslot_args(struct svc_rqst *rqstp, | |||
519 | { | 516 | { |
520 | __be32 *p; | 517 | __be32 *p; |
521 | 518 | ||
522 | args->crsa_addr = svc_addr(rqstp); | ||
523 | p = read_buf(xdr, 4); | 519 | p = read_buf(xdr, 4); |
524 | if (unlikely(p == NULL)) | 520 | if (unlikely(p == NULL)) |
525 | return htonl(NFS4ERR_BADXDR); | 521 | return htonl(NFS4ERR_BADXDR); |
@@ -684,13 +680,12 @@ static __be32 encode_sessionid(struct xdr_stream *xdr, | |||
684 | const struct nfs4_sessionid *sid) | 680 | const struct nfs4_sessionid *sid) |
685 | { | 681 | { |
686 | __be32 *p; | 682 | __be32 *p; |
687 | int len = NFS4_MAX_SESSIONID_LEN; | ||
688 | 683 | ||
689 | p = xdr_reserve_space(xdr, len); | 684 | p = xdr_reserve_space(xdr, NFS4_MAX_SESSIONID_LEN); |
690 | if (unlikely(p == NULL)) | 685 | if (unlikely(p == NULL)) |
691 | return htonl(NFS4ERR_RESOURCE); | 686 | return htonl(NFS4ERR_RESOURCE); |
692 | 687 | ||
693 | memcpy(p, sid, len); | 688 | memcpy(p, sid, NFS4_MAX_SESSIONID_LEN); |
694 | return 0; | 689 | return 0; |
695 | } | 690 | } |
696 | 691 | ||
@@ -704,7 +699,9 @@ static __be32 encode_cb_sequence_res(struct svc_rqst *rqstp, | |||
704 | if (unlikely(status != 0)) | 699 | if (unlikely(status != 0)) |
705 | goto out; | 700 | goto out; |
706 | 701 | ||
707 | encode_sessionid(xdr, &res->csr_sessionid); | 702 | status = encode_sessionid(xdr, &res->csr_sessionid); |
703 | if (status) | ||
704 | goto out; | ||
708 | 705 | ||
709 | p = xdr_reserve_space(xdr, 4 * sizeof(uint32_t)); | 706 | p = xdr_reserve_space(xdr, 4 * sizeof(uint32_t)); |
710 | if (unlikely(p == NULL)) | 707 | if (unlikely(p == NULL)) |
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 57c5a02f6213..d6d5d2a48e83 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -764,6 +764,7 @@ static void nfs_server_set_fsinfo(struct nfs_server *server, | |||
764 | 764 | ||
765 | server->time_delta = fsinfo->time_delta; | 765 | server->time_delta = fsinfo->time_delta; |
766 | 766 | ||
767 | server->clone_blksize = fsinfo->clone_blksize; | ||
767 | /* We're airborne Set socket buffersize */ | 768 | /* We're airborne Set socket buffersize */ |
768 | rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100); | 769 | rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100); |
769 | } | 770 | } |
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index be806ead7f4d..5166adcfc0fb 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
@@ -721,14 +721,12 @@ int nfs_async_inode_return_delegation(struct inode *inode, | |||
721 | struct nfs_client *clp = server->nfs_client; | 721 | struct nfs_client *clp = server->nfs_client; |
722 | struct nfs_delegation *delegation; | 722 | struct nfs_delegation *delegation; |
723 | 723 | ||
724 | filemap_flush(inode->i_mapping); | ||
725 | |||
726 | rcu_read_lock(); | 724 | rcu_read_lock(); |
727 | delegation = rcu_dereference(NFS_I(inode)->delegation); | 725 | delegation = rcu_dereference(NFS_I(inode)->delegation); |
728 | if (delegation == NULL) | 726 | if (delegation == NULL) |
729 | goto out_enoent; | 727 | goto out_enoent; |
730 | 728 | if (stateid != NULL && | |
731 | if (!clp->cl_mvops->match_stateid(&delegation->stateid, stateid)) | 729 | !clp->cl_mvops->match_stateid(&delegation->stateid, stateid)) |
732 | goto out_enoent; | 730 | goto out_enoent; |
733 | nfs_mark_return_delegation(server, delegation); | 731 | nfs_mark_return_delegation(server, delegation); |
734 | rcu_read_unlock(); | 732 | rcu_read_unlock(); |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 3d8e4ffa0a33..ce5a21861074 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -1714,9 +1714,6 @@ nfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev) | |||
1714 | dfprintk(VFS, "NFS: mknod(%s/%lu), %pd\n", | 1714 | dfprintk(VFS, "NFS: mknod(%s/%lu), %pd\n", |
1715 | dir->i_sb->s_id, dir->i_ino, dentry); | 1715 | dir->i_sb->s_id, dir->i_ino, dentry); |
1716 | 1716 | ||
1717 | if (!new_valid_dev(rdev)) | ||
1718 | return -EINVAL; | ||
1719 | |||
1720 | attr.ia_mode = mode; | 1717 | attr.ia_mode = mode; |
1721 | attr.ia_valid = ATTR_MODE; | 1718 | attr.ia_valid = ATTR_MODE; |
1722 | 1719 | ||
diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c index fbc5a56de875..03516c80855a 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.c +++ b/fs/nfs/flexfilelayout/flexfilelayout.c | |||
@@ -339,6 +339,19 @@ static void ff_layout_sort_mirrors(struct nfs4_ff_layout_segment *fls) | |||
339 | } | 339 | } |
340 | } | 340 | } |
341 | 341 | ||
342 | static void ff_layout_mark_devices_valid(struct nfs4_ff_layout_segment *fls) | ||
343 | { | ||
344 | struct nfs4_deviceid_node *node; | ||
345 | int i; | ||
346 | |||
347 | if (!(fls->flags & FF_FLAGS_NO_IO_THRU_MDS)) | ||
348 | return; | ||
349 | for (i = 0; i < fls->mirror_array_cnt; i++) { | ||
350 | node = &fls->mirror_array[i]->mirror_ds->id_node; | ||
351 | clear_bit(NFS_DEVICEID_UNAVAILABLE, &node->flags); | ||
352 | } | ||
353 | } | ||
354 | |||
342 | static struct pnfs_layout_segment * | 355 | static struct pnfs_layout_segment * |
343 | ff_layout_alloc_lseg(struct pnfs_layout_hdr *lh, | 356 | ff_layout_alloc_lseg(struct pnfs_layout_hdr *lh, |
344 | struct nfs4_layoutget_res *lgr, | 357 | struct nfs4_layoutget_res *lgr, |
@@ -499,6 +512,7 @@ ff_layout_alloc_lseg(struct pnfs_layout_hdr *lh, | |||
499 | rc = ff_layout_check_layout(lgr); | 512 | rc = ff_layout_check_layout(lgr); |
500 | if (rc) | 513 | if (rc) |
501 | goto out_err_free; | 514 | goto out_err_free; |
515 | ff_layout_mark_devices_valid(fls); | ||
502 | 516 | ||
503 | ret = &fls->generic_hdr; | 517 | ret = &fls->generic_hdr; |
504 | dprintk("<-- %s (success)\n", __func__); | 518 | dprintk("<-- %s (success)\n", __func__); |
@@ -741,17 +755,17 @@ ff_layout_alloc_commit_info(struct pnfs_layout_segment *lseg, | |||
741 | } | 755 | } |
742 | 756 | ||
743 | static struct nfs4_pnfs_ds * | 757 | static struct nfs4_pnfs_ds * |
744 | ff_layout_choose_best_ds_for_read(struct nfs_pageio_descriptor *pgio, | 758 | ff_layout_choose_best_ds_for_read(struct pnfs_layout_segment *lseg, |
759 | int start_idx, | ||
745 | int *best_idx) | 760 | int *best_idx) |
746 | { | 761 | { |
747 | struct nfs4_ff_layout_segment *fls; | 762 | struct nfs4_ff_layout_segment *fls = FF_LAYOUT_LSEG(lseg); |
748 | struct nfs4_pnfs_ds *ds; | 763 | struct nfs4_pnfs_ds *ds; |
749 | int idx; | 764 | int idx; |
750 | 765 | ||
751 | fls = FF_LAYOUT_LSEG(pgio->pg_lseg); | ||
752 | /* mirrors are sorted by efficiency */ | 766 | /* mirrors are sorted by efficiency */ |
753 | for (idx = 0; idx < fls->mirror_array_cnt; idx++) { | 767 | for (idx = start_idx; idx < fls->mirror_array_cnt; idx++) { |
754 | ds = nfs4_ff_layout_prepare_ds(pgio->pg_lseg, idx, false); | 768 | ds = nfs4_ff_layout_prepare_ds(lseg, idx, false); |
755 | if (ds) { | 769 | if (ds) { |
756 | *best_idx = idx; | 770 | *best_idx = idx; |
757 | return ds; | 771 | return ds; |
@@ -782,7 +796,7 @@ ff_layout_pg_init_read(struct nfs_pageio_descriptor *pgio, | |||
782 | if (pgio->pg_lseg == NULL) | 796 | if (pgio->pg_lseg == NULL) |
783 | goto out_mds; | 797 | goto out_mds; |
784 | 798 | ||
785 | ds = ff_layout_choose_best_ds_for_read(pgio, &ds_idx); | 799 | ds = ff_layout_choose_best_ds_for_read(pgio->pg_lseg, 0, &ds_idx); |
786 | if (!ds) | 800 | if (!ds) |
787 | goto out_mds; | 801 | goto out_mds; |
788 | mirror = FF_LAYOUT_COMP(pgio->pg_lseg, ds_idx); | 802 | mirror = FF_LAYOUT_COMP(pgio->pg_lseg, ds_idx); |
@@ -1035,7 +1049,8 @@ static int ff_layout_async_handle_error_v4(struct rpc_task *task, | |||
1035 | rpc_wake_up(&tbl->slot_tbl_waitq); | 1049 | rpc_wake_up(&tbl->slot_tbl_waitq); |
1036 | /* fall through */ | 1050 | /* fall through */ |
1037 | default: | 1051 | default: |
1038 | if (ff_layout_has_available_ds(lseg)) | 1052 | if (ff_layout_no_fallback_to_mds(lseg) || |
1053 | ff_layout_has_available_ds(lseg)) | ||
1039 | return -NFS4ERR_RESET_TO_PNFS; | 1054 | return -NFS4ERR_RESET_TO_PNFS; |
1040 | reset: | 1055 | reset: |
1041 | dprintk("%s Retry through MDS. Error %d\n", __func__, | 1056 | dprintk("%s Retry through MDS. Error %d\n", __func__, |
@@ -1153,7 +1168,6 @@ static void ff_layout_io_track_ds_error(struct pnfs_layout_segment *lseg, | |||
1153 | } | 1168 | } |
1154 | 1169 | ||
1155 | /* NFS_PROTO call done callback routines */ | 1170 | /* NFS_PROTO call done callback routines */ |
1156 | |||
1157 | static int ff_layout_read_done_cb(struct rpc_task *task, | 1171 | static int ff_layout_read_done_cb(struct rpc_task *task, |
1158 | struct nfs_pgio_header *hdr) | 1172 | struct nfs_pgio_header *hdr) |
1159 | { | 1173 | { |
@@ -1171,6 +1185,10 @@ static int ff_layout_read_done_cb(struct rpc_task *task, | |||
1171 | 1185 | ||
1172 | switch (err) { | 1186 | switch (err) { |
1173 | case -NFS4ERR_RESET_TO_PNFS: | 1187 | case -NFS4ERR_RESET_TO_PNFS: |
1188 | if (ff_layout_choose_best_ds_for_read(hdr->lseg, | ||
1189 | hdr->pgio_mirror_idx + 1, | ||
1190 | &hdr->pgio_mirror_idx)) | ||
1191 | goto out_eagain; | ||
1174 | set_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE, | 1192 | set_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE, |
1175 | &hdr->lseg->pls_layout->plh_flags); | 1193 | &hdr->lseg->pls_layout->plh_flags); |
1176 | pnfs_read_resend_pnfs(hdr); | 1194 | pnfs_read_resend_pnfs(hdr); |
@@ -1179,11 +1197,13 @@ static int ff_layout_read_done_cb(struct rpc_task *task, | |||
1179 | ff_layout_reset_read(hdr); | 1197 | ff_layout_reset_read(hdr); |
1180 | return task->tk_status; | 1198 | return task->tk_status; |
1181 | case -EAGAIN: | 1199 | case -EAGAIN: |
1182 | rpc_restart_call_prepare(task); | 1200 | goto out_eagain; |
1183 | return -EAGAIN; | ||
1184 | } | 1201 | } |
1185 | 1202 | ||
1186 | return 0; | 1203 | return 0; |
1204 | out_eagain: | ||
1205 | rpc_restart_call_prepare(task); | ||
1206 | return -EAGAIN; | ||
1187 | } | 1207 | } |
1188 | 1208 | ||
1189 | static bool | 1209 | static bool |
diff --git a/fs/nfs/flexfilelayout/flexfilelayout.h b/fs/nfs/flexfilelayout/flexfilelayout.h index 68cc0d9828f9..2bb08bc6aaf0 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.h +++ b/fs/nfs/flexfilelayout/flexfilelayout.h | |||
@@ -10,6 +10,7 @@ | |||
10 | #define FS_NFS_NFS4FLEXFILELAYOUT_H | 10 | #define FS_NFS_NFS4FLEXFILELAYOUT_H |
11 | 11 | ||
12 | #define FF_FLAGS_NO_LAYOUTCOMMIT 1 | 12 | #define FF_FLAGS_NO_LAYOUTCOMMIT 1 |
13 | #define FF_FLAGS_NO_IO_THRU_MDS 2 | ||
13 | 14 | ||
14 | #include "../pnfs.h" | 15 | #include "../pnfs.h" |
15 | 16 | ||
@@ -146,6 +147,12 @@ FF_LAYOUT_MIRROR_COUNT(struct pnfs_layout_segment *lseg) | |||
146 | } | 147 | } |
147 | 148 | ||
148 | static inline bool | 149 | static inline bool |
150 | ff_layout_no_fallback_to_mds(struct pnfs_layout_segment *lseg) | ||
151 | { | ||
152 | return FF_LAYOUT_LSEG(lseg)->flags & FF_FLAGS_NO_IO_THRU_MDS; | ||
153 | } | ||
154 | |||
155 | static inline bool | ||
149 | ff_layout_test_devid_unavailable(struct nfs4_deviceid_node *node) | 156 | ff_layout_test_devid_unavailable(struct nfs4_deviceid_node *node) |
150 | { | 157 | { |
151 | return nfs4_test_deviceid_unavailable(node); | 158 | return nfs4_test_deviceid_unavailable(node); |
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index 99a45283b9ee..09b190015df4 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c | |||
@@ -16,9 +16,7 @@ | |||
16 | #include <linux/nfs_fs.h> | 16 | #include <linux/nfs_fs.h> |
17 | #include "internal.h" | 17 | #include "internal.h" |
18 | 18 | ||
19 | #ifdef NFS_DEBUG | 19 | #define NFSDBG_FACILITY NFSDBG_MOUNT |
20 | # define NFSDBG_FACILITY NFSDBG_MOUNT | ||
21 | #endif | ||
22 | 20 | ||
23 | /* | 21 | /* |
24 | * Defined by RFC 1094, section A.3; and RFC 1813, section 5.1.4 | 22 | * Defined by RFC 1094, section A.3; and RFC 1813, section 5.1.4 |
diff --git a/fs/nfs/nfs42.h b/fs/nfs/nfs42.h index 814c1255f1d2..b587ccd31083 100644 --- a/fs/nfs/nfs42.h +++ b/fs/nfs/nfs42.h | |||
@@ -17,5 +17,6 @@ int nfs42_proc_deallocate(struct file *, loff_t, loff_t); | |||
17 | loff_t nfs42_proc_llseek(struct file *, loff_t, int); | 17 | loff_t nfs42_proc_llseek(struct file *, loff_t, int); |
18 | int nfs42_proc_layoutstats_generic(struct nfs_server *, | 18 | int nfs42_proc_layoutstats_generic(struct nfs_server *, |
19 | struct nfs42_layoutstat_data *); | 19 | struct nfs42_layoutstat_data *); |
20 | int nfs42_proc_clone(struct file *, struct file *, loff_t, loff_t, loff_t); | ||
20 | 21 | ||
21 | #endif /* __LINUX_FS_NFS_NFS4_2_H */ | 22 | #endif /* __LINUX_FS_NFS_NFS4_2_H */ |
diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c index 0f020e4d8421..3e92a3cde15d 100644 --- a/fs/nfs/nfs42proc.c +++ b/fs/nfs/nfs42proc.c | |||
@@ -271,3 +271,74 @@ int nfs42_proc_layoutstats_generic(struct nfs_server *server, | |||
271 | return PTR_ERR(task); | 271 | return PTR_ERR(task); |
272 | return 0; | 272 | return 0; |
273 | } | 273 | } |
274 | |||
275 | static int _nfs42_proc_clone(struct rpc_message *msg, struct file *src_f, | ||
276 | struct file *dst_f, loff_t src_offset, | ||
277 | loff_t dst_offset, loff_t count) | ||
278 | { | ||
279 | struct inode *src_inode = file_inode(src_f); | ||
280 | struct inode *dst_inode = file_inode(dst_f); | ||
281 | struct nfs_server *server = NFS_SERVER(dst_inode); | ||
282 | struct nfs42_clone_args args = { | ||
283 | .src_fh = NFS_FH(src_inode), | ||
284 | .dst_fh = NFS_FH(dst_inode), | ||
285 | .src_offset = src_offset, | ||
286 | .dst_offset = dst_offset, | ||
287 | .dst_bitmask = server->cache_consistency_bitmask, | ||
288 | }; | ||
289 | struct nfs42_clone_res res = { | ||
290 | .server = server, | ||
291 | }; | ||
292 | int status; | ||
293 | |||
294 | msg->rpc_argp = &args; | ||
295 | msg->rpc_resp = &res; | ||
296 | |||
297 | status = nfs42_set_rw_stateid(&args.src_stateid, src_f, FMODE_READ); | ||
298 | if (status) | ||
299 | return status; | ||
300 | |||
301 | status = nfs42_set_rw_stateid(&args.dst_stateid, dst_f, FMODE_WRITE); | ||
302 | if (status) | ||
303 | return status; | ||
304 | |||
305 | res.dst_fattr = nfs_alloc_fattr(); | ||
306 | if (!res.dst_fattr) | ||
307 | return -ENOMEM; | ||
308 | |||
309 | status = nfs4_call_sync(server->client, server, msg, | ||
310 | &args.seq_args, &res.seq_res, 0); | ||
311 | if (status == 0) | ||
312 | status = nfs_post_op_update_inode(dst_inode, res.dst_fattr); | ||
313 | |||
314 | kfree(res.dst_fattr); | ||
315 | return status; | ||
316 | } | ||
317 | |||
318 | int nfs42_proc_clone(struct file *src_f, struct file *dst_f, | ||
319 | loff_t src_offset, loff_t dst_offset, loff_t count) | ||
320 | { | ||
321 | struct rpc_message msg = { | ||
322 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLONE], | ||
323 | }; | ||
324 | struct inode *inode = file_inode(src_f); | ||
325 | struct nfs_server *server = NFS_SERVER(file_inode(src_f)); | ||
326 | struct nfs4_exception exception = { }; | ||
327 | int err; | ||
328 | |||
329 | if (!nfs_server_capable(inode, NFS_CAP_CLONE)) | ||
330 | return -EOPNOTSUPP; | ||
331 | |||
332 | do { | ||
333 | err = _nfs42_proc_clone(&msg, src_f, dst_f, src_offset, | ||
334 | dst_offset, count); | ||
335 | if (err == -ENOTSUPP || err == -EOPNOTSUPP) { | ||
336 | NFS_SERVER(inode)->caps &= ~NFS_CAP_CLONE; | ||
337 | return -EOPNOTSUPP; | ||
338 | } | ||
339 | err = nfs4_handle_exception(server, err, &exception); | ||
340 | } while (exception.retry); | ||
341 | |||
342 | return err; | ||
343 | |||
344 | } | ||
diff --git a/fs/nfs/nfs42xdr.c b/fs/nfs/nfs42xdr.c index 0eb29e14070d..0ca482a51e53 100644 --- a/fs/nfs/nfs42xdr.c +++ b/fs/nfs/nfs42xdr.c | |||
@@ -34,6 +34,12 @@ | |||
34 | 1 /* opaque devaddr4 length */ + \ | 34 | 1 /* opaque devaddr4 length */ + \ |
35 | XDR_QUADLEN(PNFS_LAYOUTSTATS_MAXSIZE)) | 35 | XDR_QUADLEN(PNFS_LAYOUTSTATS_MAXSIZE)) |
36 | #define decode_layoutstats_maxsz (op_decode_hdr_maxsz) | 36 | #define decode_layoutstats_maxsz (op_decode_hdr_maxsz) |
37 | #define encode_clone_maxsz (encode_stateid_maxsz + \ | ||
38 | encode_stateid_maxsz + \ | ||
39 | 2 /* src offset */ + \ | ||
40 | 2 /* dst offset */ + \ | ||
41 | 2 /* count */) | ||
42 | #define decode_clone_maxsz (op_decode_hdr_maxsz) | ||
37 | 43 | ||
38 | #define NFS4_enc_allocate_sz (compound_encode_hdr_maxsz + \ | 44 | #define NFS4_enc_allocate_sz (compound_encode_hdr_maxsz + \ |
39 | encode_putfh_maxsz + \ | 45 | encode_putfh_maxsz + \ |
@@ -65,7 +71,20 @@ | |||
65 | decode_sequence_maxsz + \ | 71 | decode_sequence_maxsz + \ |
66 | decode_putfh_maxsz + \ | 72 | decode_putfh_maxsz + \ |
67 | PNFS_LAYOUTSTATS_MAXDEV * decode_layoutstats_maxsz) | 73 | PNFS_LAYOUTSTATS_MAXDEV * decode_layoutstats_maxsz) |
68 | 74 | #define NFS4_enc_clone_sz (compound_encode_hdr_maxsz + \ | |
75 | encode_sequence_maxsz + \ | ||
76 | encode_putfh_maxsz + \ | ||
77 | encode_savefh_maxsz + \ | ||
78 | encode_putfh_maxsz + \ | ||
79 | encode_clone_maxsz + \ | ||
80 | encode_getattr_maxsz) | ||
81 | #define NFS4_dec_clone_sz (compound_decode_hdr_maxsz + \ | ||
82 | decode_sequence_maxsz + \ | ||
83 | decode_putfh_maxsz + \ | ||
84 | decode_savefh_maxsz + \ | ||
85 | decode_putfh_maxsz + \ | ||
86 | decode_clone_maxsz + \ | ||
87 | decode_getattr_maxsz) | ||
69 | 88 | ||
70 | static void encode_fallocate(struct xdr_stream *xdr, | 89 | static void encode_fallocate(struct xdr_stream *xdr, |
71 | struct nfs42_falloc_args *args) | 90 | struct nfs42_falloc_args *args) |
@@ -128,6 +147,21 @@ static void encode_layoutstats(struct xdr_stream *xdr, | |||
128 | encode_uint32(xdr, 0); | 147 | encode_uint32(xdr, 0); |
129 | } | 148 | } |
130 | 149 | ||
150 | static void encode_clone(struct xdr_stream *xdr, | ||
151 | struct nfs42_clone_args *args, | ||
152 | struct compound_hdr *hdr) | ||
153 | { | ||
154 | __be32 *p; | ||
155 | |||
156 | encode_op_hdr(xdr, OP_CLONE, decode_clone_maxsz, hdr); | ||
157 | encode_nfs4_stateid(xdr, &args->src_stateid); | ||
158 | encode_nfs4_stateid(xdr, &args->dst_stateid); | ||
159 | p = reserve_space(xdr, 3*8); | ||
160 | p = xdr_encode_hyper(p, args->src_offset); | ||
161 | p = xdr_encode_hyper(p, args->dst_offset); | ||
162 | xdr_encode_hyper(p, args->count); | ||
163 | } | ||
164 | |||
131 | /* | 165 | /* |
132 | * Encode ALLOCATE request | 166 | * Encode ALLOCATE request |
133 | */ | 167 | */ |
@@ -206,6 +240,27 @@ static void nfs4_xdr_enc_layoutstats(struct rpc_rqst *req, | |||
206 | encode_nops(&hdr); | 240 | encode_nops(&hdr); |
207 | } | 241 | } |
208 | 242 | ||
243 | /* | ||
244 | * Encode CLONE request | ||
245 | */ | ||
246 | static void nfs4_xdr_enc_clone(struct rpc_rqst *req, | ||
247 | struct xdr_stream *xdr, | ||
248 | struct nfs42_clone_args *args) | ||
249 | { | ||
250 | struct compound_hdr hdr = { | ||
251 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), | ||
252 | }; | ||
253 | |||
254 | encode_compound_hdr(xdr, req, &hdr); | ||
255 | encode_sequence(xdr, &args->seq_args, &hdr); | ||
256 | encode_putfh(xdr, args->src_fh, &hdr); | ||
257 | encode_savefh(xdr, &hdr); | ||
258 | encode_putfh(xdr, args->dst_fh, &hdr); | ||
259 | encode_clone(xdr, args, &hdr); | ||
260 | encode_getfattr(xdr, args->dst_bitmask, &hdr); | ||
261 | encode_nops(&hdr); | ||
262 | } | ||
263 | |||
209 | static int decode_allocate(struct xdr_stream *xdr, struct nfs42_falloc_res *res) | 264 | static int decode_allocate(struct xdr_stream *xdr, struct nfs42_falloc_res *res) |
210 | { | 265 | { |
211 | return decode_op_hdr(xdr, OP_ALLOCATE); | 266 | return decode_op_hdr(xdr, OP_ALLOCATE); |
@@ -243,6 +298,11 @@ static int decode_layoutstats(struct xdr_stream *xdr) | |||
243 | return decode_op_hdr(xdr, OP_LAYOUTSTATS); | 298 | return decode_op_hdr(xdr, OP_LAYOUTSTATS); |
244 | } | 299 | } |
245 | 300 | ||
301 | static int decode_clone(struct xdr_stream *xdr) | ||
302 | { | ||
303 | return decode_op_hdr(xdr, OP_CLONE); | ||
304 | } | ||
305 | |||
246 | /* | 306 | /* |
247 | * Decode ALLOCATE request | 307 | * Decode ALLOCATE request |
248 | */ | 308 | */ |
@@ -351,4 +411,39 @@ out: | |||
351 | return status; | 411 | return status; |
352 | } | 412 | } |
353 | 413 | ||
414 | /* | ||
415 | * Decode CLONE request | ||
416 | */ | ||
417 | static int nfs4_xdr_dec_clone(struct rpc_rqst *rqstp, | ||
418 | struct xdr_stream *xdr, | ||
419 | struct nfs42_clone_res *res) | ||
420 | { | ||
421 | struct compound_hdr hdr; | ||
422 | int status; | ||
423 | |||
424 | status = decode_compound_hdr(xdr, &hdr); | ||
425 | if (status) | ||
426 | goto out; | ||
427 | status = decode_sequence(xdr, &res->seq_res, rqstp); | ||
428 | if (status) | ||
429 | goto out; | ||
430 | status = decode_putfh(xdr); | ||
431 | if (status) | ||
432 | goto out; | ||
433 | status = decode_savefh(xdr); | ||
434 | if (status) | ||
435 | goto out; | ||
436 | status = decode_putfh(xdr); | ||
437 | if (status) | ||
438 | goto out; | ||
439 | status = decode_clone(xdr); | ||
440 | if (status) | ||
441 | goto out; | ||
442 | status = decode_getfattr(xdr, res->dst_fattr, res->server); | ||
443 | |||
444 | out: | ||
445 | res->rpc_status = status; | ||
446 | return status; | ||
447 | } | ||
448 | |||
354 | #endif /* __LINUX_FS_NFS_NFS4_2XDR_H */ | 449 | #endif /* __LINUX_FS_NFS_NFS4_2XDR_H */ |
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 50cfc4ca7a02..4afdee420d25 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -183,10 +183,12 @@ struct nfs4_state { | |||
183 | 183 | ||
184 | 184 | ||
185 | struct nfs4_exception { | 185 | struct nfs4_exception { |
186 | long timeout; | ||
187 | int retry; | ||
188 | struct nfs4_state *state; | 186 | struct nfs4_state *state; |
189 | struct inode *inode; | 187 | struct inode *inode; |
188 | long timeout; | ||
189 | unsigned char delay : 1, | ||
190 | recovering : 1, | ||
191 | retry : 1; | ||
190 | }; | 192 | }; |
191 | 193 | ||
192 | struct nfs4_state_recovery_ops { | 194 | struct nfs4_state_recovery_ops { |
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c index b0dbe0abed53..4aa571956cd6 100644 --- a/fs/nfs/nfs4file.c +++ b/fs/nfs/nfs4file.c | |||
@@ -4,6 +4,7 @@ | |||
4 | * Copyright (C) 1992 Rick Sladkey | 4 | * Copyright (C) 1992 Rick Sladkey |
5 | */ | 5 | */ |
6 | #include <linux/fs.h> | 6 | #include <linux/fs.h> |
7 | #include <linux/file.h> | ||
7 | #include <linux/falloc.h> | 8 | #include <linux/falloc.h> |
8 | #include <linux/nfs_fs.h> | 9 | #include <linux/nfs_fs.h> |
9 | #include "delegation.h" | 10 | #include "delegation.h" |
@@ -192,8 +193,138 @@ static long nfs42_fallocate(struct file *filep, int mode, loff_t offset, loff_t | |||
192 | return nfs42_proc_deallocate(filep, offset, len); | 193 | return nfs42_proc_deallocate(filep, offset, len); |
193 | return nfs42_proc_allocate(filep, offset, len); | 194 | return nfs42_proc_allocate(filep, offset, len); |
194 | } | 195 | } |
196 | |||
197 | static noinline long | ||
198 | nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd, | ||
199 | u64 src_off, u64 dst_off, u64 count) | ||
200 | { | ||
201 | struct inode *dst_inode = file_inode(dst_file); | ||
202 | struct nfs_server *server = NFS_SERVER(dst_inode); | ||
203 | struct fd src_file; | ||
204 | struct inode *src_inode; | ||
205 | unsigned int bs = server->clone_blksize; | ||
206 | int ret; | ||
207 | |||
208 | /* dst file must be opened for writing */ | ||
209 | if (!(dst_file->f_mode & FMODE_WRITE)) | ||
210 | return -EINVAL; | ||
211 | |||
212 | ret = mnt_want_write_file(dst_file); | ||
213 | if (ret) | ||
214 | return ret; | ||
215 | |||
216 | src_file = fdget(srcfd); | ||
217 | if (!src_file.file) { | ||
218 | ret = -EBADF; | ||
219 | goto out_drop_write; | ||
220 | } | ||
221 | |||
222 | src_inode = file_inode(src_file.file); | ||
223 | |||
224 | /* src and dst must be different files */ | ||
225 | ret = -EINVAL; | ||
226 | if (src_inode == dst_inode) | ||
227 | goto out_fput; | ||
228 | |||
229 | /* src file must be opened for reading */ | ||
230 | if (!(src_file.file->f_mode & FMODE_READ)) | ||
231 | goto out_fput; | ||
232 | |||
233 | /* src and dst must be regular files */ | ||
234 | ret = -EISDIR; | ||
235 | if (!S_ISREG(src_inode->i_mode) || !S_ISREG(dst_inode->i_mode)) | ||
236 | goto out_fput; | ||
237 | |||
238 | ret = -EXDEV; | ||
239 | if (src_file.file->f_path.mnt != dst_file->f_path.mnt || | ||
240 | src_inode->i_sb != dst_inode->i_sb) | ||
241 | goto out_fput; | ||
242 | |||
243 | /* check alignment w.r.t. clone_blksize */ | ||
244 | ret = -EINVAL; | ||
245 | if (bs) { | ||
246 | if (!IS_ALIGNED(src_off, bs) || !IS_ALIGNED(dst_off, bs)) | ||
247 | goto out_fput; | ||
248 | if (!IS_ALIGNED(count, bs) && i_size_read(src_inode) != (src_off + count)) | ||
249 | goto out_fput; | ||
250 | } | ||
251 | |||
252 | /* XXX: do we lock at all? what if server needs CB_RECALL_LAYOUT? */ | ||
253 | if (dst_inode < src_inode) { | ||
254 | mutex_lock_nested(&dst_inode->i_mutex, I_MUTEX_PARENT); | ||
255 | mutex_lock_nested(&src_inode->i_mutex, I_MUTEX_CHILD); | ||
256 | } else { | ||
257 | mutex_lock_nested(&src_inode->i_mutex, I_MUTEX_PARENT); | ||
258 | mutex_lock_nested(&dst_inode->i_mutex, I_MUTEX_CHILD); | ||
259 | } | ||
260 | |||
261 | /* flush all pending writes on both src and dst so that server | ||
262 | * has the latest data */ | ||
263 | ret = nfs_sync_inode(src_inode); | ||
264 | if (ret) | ||
265 | goto out_unlock; | ||
266 | ret = nfs_sync_inode(dst_inode); | ||
267 | if (ret) | ||
268 | goto out_unlock; | ||
269 | |||
270 | ret = nfs42_proc_clone(src_file.file, dst_file, src_off, dst_off, count); | ||
271 | |||
272 | /* truncate inode page cache of the dst range so that future reads can fetch | ||
273 | * new data from server */ | ||
274 | if (!ret) | ||
275 | truncate_inode_pages_range(&dst_inode->i_data, dst_off, dst_off + count - 1); | ||
276 | |||
277 | out_unlock: | ||
278 | if (dst_inode < src_inode) { | ||
279 | mutex_unlock(&src_inode->i_mutex); | ||
280 | mutex_unlock(&dst_inode->i_mutex); | ||
281 | } else { | ||
282 | mutex_unlock(&dst_inode->i_mutex); | ||
283 | mutex_unlock(&src_inode->i_mutex); | ||
284 | } | ||
285 | out_fput: | ||
286 | fdput(src_file); | ||
287 | out_drop_write: | ||
288 | mnt_drop_write_file(dst_file); | ||
289 | return ret; | ||
290 | } | ||
291 | |||
292 | static long nfs42_ioctl_clone_range(struct file *dst_file, void __user *argp) | ||
293 | { | ||
294 | struct nfs_ioctl_clone_range_args args; | ||
295 | |||
296 | if (copy_from_user(&args, argp, sizeof(args))) | ||
297 | return -EFAULT; | ||
298 | |||
299 | return nfs42_ioctl_clone(dst_file, args.src_fd, args.src_off, args.dst_off, args.count); | ||
300 | } | ||
301 | #else | ||
302 | static long nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd, | ||
303 | u64 src_off, u64 dst_off, u64 count) | ||
304 | { | ||
305 | return -ENOTTY; | ||
306 | } | ||
307 | |||
308 | static long nfs42_ioctl_clone_range(struct file *dst_file, void __user *argp) | ||
309 | { | ||
310 | return -ENOTTY; | ||
311 | } | ||
195 | #endif /* CONFIG_NFS_V4_2 */ | 312 | #endif /* CONFIG_NFS_V4_2 */ |
196 | 313 | ||
314 | long nfs4_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
315 | { | ||
316 | void __user *argp = (void __user *)arg; | ||
317 | |||
318 | switch (cmd) { | ||
319 | case NFS_IOC_CLONE: | ||
320 | return nfs42_ioctl_clone(file, arg, 0, 0, 0); | ||
321 | case NFS_IOC_CLONE_RANGE: | ||
322 | return nfs42_ioctl_clone_range(file, argp); | ||
323 | } | ||
324 | |||
325 | return -ENOTTY; | ||
326 | } | ||
327 | |||
197 | const struct file_operations nfs4_file_operations = { | 328 | const struct file_operations nfs4_file_operations = { |
198 | #ifdef CONFIG_NFS_V4_2 | 329 | #ifdef CONFIG_NFS_V4_2 |
199 | .llseek = nfs4_file_llseek, | 330 | .llseek = nfs4_file_llseek, |
@@ -216,4 +347,9 @@ const struct file_operations nfs4_file_operations = { | |||
216 | #endif /* CONFIG_NFS_V4_2 */ | 347 | #endif /* CONFIG_NFS_V4_2 */ |
217 | .check_flags = nfs_check_flags, | 348 | .check_flags = nfs_check_flags, |
218 | .setlease = simple_nosetlease, | 349 | .setlease = simple_nosetlease, |
350 | #ifdef CONFIG_COMPAT | ||
351 | .unlocked_ioctl = nfs4_ioctl, | ||
352 | #else | ||
353 | .compat_ioctl = nfs4_ioctl, | ||
354 | #endif /* CONFIG_COMPAT */ | ||
219 | }; | 355 | }; |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 0e5ff69455c7..ff5bddc49a2a 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -78,7 +78,6 @@ struct nfs4_opendata; | |||
78 | static int _nfs4_proc_open(struct nfs4_opendata *data); | 78 | static int _nfs4_proc_open(struct nfs4_opendata *data); |
79 | static int _nfs4_recover_proc_open(struct nfs4_opendata *data); | 79 | static int _nfs4_recover_proc_open(struct nfs4_opendata *data); |
80 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); | 80 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); |
81 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *, long *); | ||
82 | static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr); | 81 | static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr); |
83 | static int nfs4_proc_getattr(struct nfs_server *, struct nfs_fh *, struct nfs_fattr *, struct nfs4_label *label); | 82 | static int nfs4_proc_getattr(struct nfs_server *, struct nfs_fh *, struct nfs_fattr *, struct nfs4_label *label); |
84 | static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr, struct nfs4_label *label); | 83 | static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr, struct nfs4_label *label); |
@@ -239,6 +238,7 @@ const u32 nfs4_fsinfo_bitmap[3] = { FATTR4_WORD0_MAXFILESIZE | |||
239 | FATTR4_WORD1_TIME_DELTA | 238 | FATTR4_WORD1_TIME_DELTA |
240 | | FATTR4_WORD1_FS_LAYOUT_TYPES, | 239 | | FATTR4_WORD1_FS_LAYOUT_TYPES, |
241 | FATTR4_WORD2_LAYOUT_BLKSIZE | 240 | FATTR4_WORD2_LAYOUT_BLKSIZE |
241 | | FATTR4_WORD2_CLONE_BLKSIZE | ||
242 | }; | 242 | }; |
243 | 243 | ||
244 | const u32 nfs4_fs_locations_bitmap[3] = { | 244 | const u32 nfs4_fs_locations_bitmap[3] = { |
@@ -344,13 +344,16 @@ static int nfs4_delay(struct rpc_clnt *clnt, long *timeout) | |||
344 | /* This is the error handling routine for processes that are allowed | 344 | /* This is the error handling routine for processes that are allowed |
345 | * to sleep. | 345 | * to sleep. |
346 | */ | 346 | */ |
347 | int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_exception *exception) | 347 | static int nfs4_do_handle_exception(struct nfs_server *server, |
348 | int errorcode, struct nfs4_exception *exception) | ||
348 | { | 349 | { |
349 | struct nfs_client *clp = server->nfs_client; | 350 | struct nfs_client *clp = server->nfs_client; |
350 | struct nfs4_state *state = exception->state; | 351 | struct nfs4_state *state = exception->state; |
351 | struct inode *inode = exception->inode; | 352 | struct inode *inode = exception->inode; |
352 | int ret = errorcode; | 353 | int ret = errorcode; |
353 | 354 | ||
355 | exception->delay = 0; | ||
356 | exception->recovering = 0; | ||
354 | exception->retry = 0; | 357 | exception->retry = 0; |
355 | switch(errorcode) { | 358 | switch(errorcode) { |
356 | case 0: | 359 | case 0: |
@@ -359,11 +362,9 @@ int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_ | |||
359 | case -NFS4ERR_DELEG_REVOKED: | 362 | case -NFS4ERR_DELEG_REVOKED: |
360 | case -NFS4ERR_ADMIN_REVOKED: | 363 | case -NFS4ERR_ADMIN_REVOKED: |
361 | case -NFS4ERR_BAD_STATEID: | 364 | case -NFS4ERR_BAD_STATEID: |
362 | if (inode && nfs4_have_delegation(inode, FMODE_READ)) { | 365 | if (inode && nfs_async_inode_return_delegation(inode, |
363 | nfs4_inode_return_delegation(inode); | 366 | NULL) == 0) |
364 | exception->retry = 1; | 367 | goto wait_on_recovery; |
365 | return 0; | ||
366 | } | ||
367 | if (state == NULL) | 368 | if (state == NULL) |
368 | break; | 369 | break; |
369 | ret = nfs4_schedule_stateid_recovery(server, state); | 370 | ret = nfs4_schedule_stateid_recovery(server, state); |
@@ -409,11 +410,12 @@ int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_ | |||
409 | ret = -EBUSY; | 410 | ret = -EBUSY; |
410 | break; | 411 | break; |
411 | } | 412 | } |
412 | case -NFS4ERR_GRACE: | ||
413 | case -NFS4ERR_DELAY: | 413 | case -NFS4ERR_DELAY: |
414 | ret = nfs4_delay(server->client, &exception->timeout); | 414 | nfs_inc_server_stats(server, NFSIOS_DELAY); |
415 | if (ret != 0) | 415 | case -NFS4ERR_GRACE: |
416 | break; | 416 | exception->delay = 1; |
417 | return 0; | ||
418 | |||
417 | case -NFS4ERR_RETRY_UNCACHED_REP: | 419 | case -NFS4ERR_RETRY_UNCACHED_REP: |
418 | case -NFS4ERR_OLD_STATEID: | 420 | case -NFS4ERR_OLD_STATEID: |
419 | exception->retry = 1; | 421 | exception->retry = 1; |
@@ -434,14 +436,85 @@ int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_ | |||
434 | /* We failed to handle the error */ | 436 | /* We failed to handle the error */ |
435 | return nfs4_map_errors(ret); | 437 | return nfs4_map_errors(ret); |
436 | wait_on_recovery: | 438 | wait_on_recovery: |
437 | ret = nfs4_wait_clnt_recover(clp); | 439 | exception->recovering = 1; |
440 | return 0; | ||
441 | } | ||
442 | |||
443 | /* This is the error handling routine for processes that are allowed | ||
444 | * to sleep. | ||
445 | */ | ||
446 | int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_exception *exception) | ||
447 | { | ||
448 | struct nfs_client *clp = server->nfs_client; | ||
449 | int ret; | ||
450 | |||
451 | ret = nfs4_do_handle_exception(server, errorcode, exception); | ||
452 | if (exception->delay) { | ||
453 | ret = nfs4_delay(server->client, &exception->timeout); | ||
454 | goto out_retry; | ||
455 | } | ||
456 | if (exception->recovering) { | ||
457 | ret = nfs4_wait_clnt_recover(clp); | ||
458 | if (test_bit(NFS_MIG_FAILED, &server->mig_status)) | ||
459 | return -EIO; | ||
460 | goto out_retry; | ||
461 | } | ||
462 | return ret; | ||
463 | out_retry: | ||
464 | if (ret == 0) | ||
465 | exception->retry = 1; | ||
466 | return ret; | ||
467 | } | ||
468 | |||
469 | static int | ||
470 | nfs4_async_handle_exception(struct rpc_task *task, struct nfs_server *server, | ||
471 | int errorcode, struct nfs4_exception *exception) | ||
472 | { | ||
473 | struct nfs_client *clp = server->nfs_client; | ||
474 | int ret; | ||
475 | |||
476 | ret = nfs4_do_handle_exception(server, errorcode, exception); | ||
477 | if (exception->delay) { | ||
478 | rpc_delay(task, nfs4_update_delay(&exception->timeout)); | ||
479 | goto out_retry; | ||
480 | } | ||
481 | if (exception->recovering) { | ||
482 | rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL); | ||
483 | if (test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) == 0) | ||
484 | rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task); | ||
485 | goto out_retry; | ||
486 | } | ||
438 | if (test_bit(NFS_MIG_FAILED, &server->mig_status)) | 487 | if (test_bit(NFS_MIG_FAILED, &server->mig_status)) |
439 | return -EIO; | 488 | ret = -EIO; |
489 | return ret; | ||
490 | out_retry: | ||
440 | if (ret == 0) | 491 | if (ret == 0) |
441 | exception->retry = 1; | 492 | exception->retry = 1; |
442 | return ret; | 493 | return ret; |
443 | } | 494 | } |
444 | 495 | ||
496 | static int | ||
497 | nfs4_async_handle_error(struct rpc_task *task, struct nfs_server *server, | ||
498 | struct nfs4_state *state, long *timeout) | ||
499 | { | ||
500 | struct nfs4_exception exception = { | ||
501 | .state = state, | ||
502 | }; | ||
503 | |||
504 | if (task->tk_status >= 0) | ||
505 | return 0; | ||
506 | if (timeout) | ||
507 | exception.timeout = *timeout; | ||
508 | task->tk_status = nfs4_async_handle_exception(task, server, | ||
509 | task->tk_status, | ||
510 | &exception); | ||
511 | if (exception.delay && timeout) | ||
512 | *timeout = exception.timeout; | ||
513 | if (exception.retry) | ||
514 | return -EAGAIN; | ||
515 | return 0; | ||
516 | } | ||
517 | |||
445 | /* | 518 | /* |
446 | * Return 'true' if 'clp' is using an rpc_client that is integrity protected | 519 | * Return 'true' if 'clp' is using an rpc_client that is integrity protected |
447 | * or 'false' otherwise. | 520 | * or 'false' otherwise. |
@@ -4530,7 +4603,7 @@ static inline int nfs4_server_supports_acls(struct nfs_server *server) | |||
4530 | #define NFS4ACL_MAXPAGES DIV_ROUND_UP(XATTR_SIZE_MAX, PAGE_SIZE) | 4603 | #define NFS4ACL_MAXPAGES DIV_ROUND_UP(XATTR_SIZE_MAX, PAGE_SIZE) |
4531 | 4604 | ||
4532 | static int buf_to_pages_noslab(const void *buf, size_t buflen, | 4605 | static int buf_to_pages_noslab(const void *buf, size_t buflen, |
4533 | struct page **pages, unsigned int *pgbase) | 4606 | struct page **pages) |
4534 | { | 4607 | { |
4535 | struct page *newpage, **spages; | 4608 | struct page *newpage, **spages; |
4536 | int rc = 0; | 4609 | int rc = 0; |
@@ -4674,7 +4747,6 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu | |||
4674 | goto out_free; | 4747 | goto out_free; |
4675 | 4748 | ||
4676 | args.acl_len = npages * PAGE_SIZE; | 4749 | args.acl_len = npages * PAGE_SIZE; |
4677 | args.acl_pgbase = 0; | ||
4678 | 4750 | ||
4679 | dprintk("%s buf %p buflen %zu npages %d args.acl_len %zu\n", | 4751 | dprintk("%s buf %p buflen %zu npages %d args.acl_len %zu\n", |
4680 | __func__, buf, buflen, npages, args.acl_len); | 4752 | __func__, buf, buflen, npages, args.acl_len); |
@@ -4766,7 +4838,7 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl | |||
4766 | return -EOPNOTSUPP; | 4838 | return -EOPNOTSUPP; |
4767 | if (npages > ARRAY_SIZE(pages)) | 4839 | if (npages > ARRAY_SIZE(pages)) |
4768 | return -ERANGE; | 4840 | return -ERANGE; |
4769 | i = buf_to_pages_noslab(buf, buflen, arg.acl_pages, &arg.acl_pgbase); | 4841 | i = buf_to_pages_noslab(buf, buflen, arg.acl_pages); |
4770 | if (i < 0) | 4842 | if (i < 0) |
4771 | return i; | 4843 | return i; |
4772 | nfs4_inode_return_delegation(inode); | 4844 | nfs4_inode_return_delegation(inode); |
@@ -4955,79 +5027,6 @@ out: | |||
4955 | #endif /* CONFIG_NFS_V4_SECURITY_LABEL */ | 5027 | #endif /* CONFIG_NFS_V4_SECURITY_LABEL */ |
4956 | 5028 | ||
4957 | 5029 | ||
4958 | static int | ||
4959 | nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | ||
4960 | struct nfs4_state *state, long *timeout) | ||
4961 | { | ||
4962 | struct nfs_client *clp = server->nfs_client; | ||
4963 | |||
4964 | if (task->tk_status >= 0) | ||
4965 | return 0; | ||
4966 | switch(task->tk_status) { | ||
4967 | case -NFS4ERR_DELEG_REVOKED: | ||
4968 | case -NFS4ERR_ADMIN_REVOKED: | ||
4969 | case -NFS4ERR_BAD_STATEID: | ||
4970 | case -NFS4ERR_OPENMODE: | ||
4971 | if (state == NULL) | ||
4972 | break; | ||
4973 | if (nfs4_schedule_stateid_recovery(server, state) < 0) | ||
4974 | goto recovery_failed; | ||
4975 | goto wait_on_recovery; | ||
4976 | case -NFS4ERR_EXPIRED: | ||
4977 | if (state != NULL) { | ||
4978 | if (nfs4_schedule_stateid_recovery(server, state) < 0) | ||
4979 | goto recovery_failed; | ||
4980 | } | ||
4981 | case -NFS4ERR_STALE_STATEID: | ||
4982 | case -NFS4ERR_STALE_CLIENTID: | ||
4983 | nfs4_schedule_lease_recovery(clp); | ||
4984 | goto wait_on_recovery; | ||
4985 | case -NFS4ERR_MOVED: | ||
4986 | if (nfs4_schedule_migration_recovery(server) < 0) | ||
4987 | goto recovery_failed; | ||
4988 | goto wait_on_recovery; | ||
4989 | case -NFS4ERR_LEASE_MOVED: | ||
4990 | nfs4_schedule_lease_moved_recovery(clp); | ||
4991 | goto wait_on_recovery; | ||
4992 | #if defined(CONFIG_NFS_V4_1) | ||
4993 | case -NFS4ERR_BADSESSION: | ||
4994 | case -NFS4ERR_BADSLOT: | ||
4995 | case -NFS4ERR_BAD_HIGH_SLOT: | ||
4996 | case -NFS4ERR_DEADSESSION: | ||
4997 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: | ||
4998 | case -NFS4ERR_SEQ_FALSE_RETRY: | ||
4999 | case -NFS4ERR_SEQ_MISORDERED: | ||
5000 | dprintk("%s ERROR %d, Reset session\n", __func__, | ||
5001 | task->tk_status); | ||
5002 | nfs4_schedule_session_recovery(clp->cl_session, task->tk_status); | ||
5003 | goto wait_on_recovery; | ||
5004 | #endif /* CONFIG_NFS_V4_1 */ | ||
5005 | case -NFS4ERR_DELAY: | ||
5006 | nfs_inc_server_stats(server, NFSIOS_DELAY); | ||
5007 | rpc_delay(task, nfs4_update_delay(timeout)); | ||
5008 | goto restart_call; | ||
5009 | case -NFS4ERR_GRACE: | ||
5010 | rpc_delay(task, NFS4_POLL_RETRY_MAX); | ||
5011 | case -NFS4ERR_RETRY_UNCACHED_REP: | ||
5012 | case -NFS4ERR_OLD_STATEID: | ||
5013 | goto restart_call; | ||
5014 | } | ||
5015 | task->tk_status = nfs4_map_errors(task->tk_status); | ||
5016 | return 0; | ||
5017 | recovery_failed: | ||
5018 | task->tk_status = -EIO; | ||
5019 | return 0; | ||
5020 | wait_on_recovery: | ||
5021 | rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL); | ||
5022 | if (test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) == 0) | ||
5023 | rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task); | ||
5024 | if (test_bit(NFS_MIG_FAILED, &server->mig_status)) | ||
5025 | goto recovery_failed; | ||
5026 | restart_call: | ||
5027 | task->tk_status = 0; | ||
5028 | return -EAGAIN; | ||
5029 | } | ||
5030 | |||
5031 | static void nfs4_init_boot_verifier(const struct nfs_client *clp, | 5030 | static void nfs4_init_boot_verifier(const struct nfs_client *clp, |
5032 | nfs4_verifier *bootverf) | 5031 | nfs4_verifier *bootverf) |
5033 | { | 5032 | { |
@@ -5522,7 +5521,7 @@ struct nfs4_unlockdata { | |||
5522 | struct nfs4_lock_state *lsp; | 5521 | struct nfs4_lock_state *lsp; |
5523 | struct nfs_open_context *ctx; | 5522 | struct nfs_open_context *ctx; |
5524 | struct file_lock fl; | 5523 | struct file_lock fl; |
5525 | const struct nfs_server *server; | 5524 | struct nfs_server *server; |
5526 | unsigned long timestamp; | 5525 | unsigned long timestamp; |
5527 | }; | 5526 | }; |
5528 | 5527 | ||
@@ -8718,7 +8717,8 @@ static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = { | |||
8718 | | NFS_CAP_ALLOCATE | 8717 | | NFS_CAP_ALLOCATE |
8719 | | NFS_CAP_DEALLOCATE | 8718 | | NFS_CAP_DEALLOCATE |
8720 | | NFS_CAP_SEEK | 8719 | | NFS_CAP_SEEK |
8721 | | NFS_CAP_LAYOUTSTATS, | 8720 | | NFS_CAP_LAYOUTSTATS |
8721 | | NFS_CAP_CLONE, | ||
8722 | .init_client = nfs41_init_client, | 8722 | .init_client = nfs41_init_client, |
8723 | .shutdown_client = nfs41_shutdown_client, | 8723 | .shutdown_client = nfs41_shutdown_client, |
8724 | .match_stateid = nfs41_match_stateid, | 8724 | .match_stateid = nfs41_match_stateid, |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 788adf3897c7..dfed4f5c8fcc 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -1659,7 +1659,7 @@ encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg, struct compoun | |||
1659 | *p = cpu_to_be32(FATTR4_WORD0_ACL); | 1659 | *p = cpu_to_be32(FATTR4_WORD0_ACL); |
1660 | p = reserve_space(xdr, 4); | 1660 | p = reserve_space(xdr, 4); |
1661 | *p = cpu_to_be32(arg->acl_len); | 1661 | *p = cpu_to_be32(arg->acl_len); |
1662 | xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len); | 1662 | xdr_write_pages(xdr, arg->acl_pages, 0, arg->acl_len); |
1663 | } | 1663 | } |
1664 | 1664 | ||
1665 | static void | 1665 | static void |
@@ -2491,7 +2491,7 @@ static void nfs4_xdr_enc_getacl(struct rpc_rqst *req, struct xdr_stream *xdr, | |||
2491 | encode_getattr_two(xdr, FATTR4_WORD0_ACL, 0, &hdr); | 2491 | encode_getattr_two(xdr, FATTR4_WORD0_ACL, 0, &hdr); |
2492 | 2492 | ||
2493 | xdr_inline_pages(&req->rq_rcv_buf, replen << 2, | 2493 | xdr_inline_pages(&req->rq_rcv_buf, replen << 2, |
2494 | args->acl_pages, args->acl_pgbase, args->acl_len); | 2494 | args->acl_pages, 0, args->acl_len); |
2495 | 2495 | ||
2496 | encode_nops(&hdr); | 2496 | encode_nops(&hdr); |
2497 | } | 2497 | } |
@@ -4375,6 +4375,11 @@ static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat) | |||
4375 | goto xdr_error; | 4375 | goto xdr_error; |
4376 | if ((status = decode_attr_files_total(xdr, bitmap, &fsstat->tfiles)) != 0) | 4376 | if ((status = decode_attr_files_total(xdr, bitmap, &fsstat->tfiles)) != 0) |
4377 | goto xdr_error; | 4377 | goto xdr_error; |
4378 | |||
4379 | status = -EIO; | ||
4380 | if (unlikely(bitmap[0])) | ||
4381 | goto xdr_error; | ||
4382 | |||
4378 | if ((status = decode_attr_space_avail(xdr, bitmap, &fsstat->abytes)) != 0) | 4383 | if ((status = decode_attr_space_avail(xdr, bitmap, &fsstat->abytes)) != 0) |
4379 | goto xdr_error; | 4384 | goto xdr_error; |
4380 | if ((status = decode_attr_space_free(xdr, bitmap, &fsstat->fbytes)) != 0) | 4385 | if ((status = decode_attr_space_free(xdr, bitmap, &fsstat->fbytes)) != 0) |
@@ -4574,6 +4579,10 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap, | |||
4574 | goto xdr_error; | 4579 | goto xdr_error; |
4575 | fattr->valid |= status; | 4580 | fattr->valid |= status; |
4576 | 4581 | ||
4582 | status = -EIO; | ||
4583 | if (unlikely(bitmap[0])) | ||
4584 | goto xdr_error; | ||
4585 | |||
4577 | status = decode_attr_mode(xdr, bitmap, &fmode); | 4586 | status = decode_attr_mode(xdr, bitmap, &fmode); |
4578 | if (status < 0) | 4587 | if (status < 0) |
4579 | goto xdr_error; | 4588 | goto xdr_error; |
@@ -4627,6 +4636,10 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap, | |||
4627 | goto xdr_error; | 4636 | goto xdr_error; |
4628 | fattr->valid |= status; | 4637 | fattr->valid |= status; |
4629 | 4638 | ||
4639 | status = -EIO; | ||
4640 | if (unlikely(bitmap[1])) | ||
4641 | goto xdr_error; | ||
4642 | |||
4630 | status = decode_attr_mdsthreshold(xdr, bitmap, fattr->mdsthreshold); | 4643 | status = decode_attr_mdsthreshold(xdr, bitmap, fattr->mdsthreshold); |
4631 | if (status < 0) | 4644 | if (status < 0) |
4632 | goto xdr_error; | 4645 | goto xdr_error; |
@@ -4764,6 +4777,28 @@ static int decode_attr_layout_blksize(struct xdr_stream *xdr, uint32_t *bitmap, | |||
4764 | return 0; | 4777 | return 0; |
4765 | } | 4778 | } |
4766 | 4779 | ||
4780 | /* | ||
4781 | * The granularity of a CLONE operation. | ||
4782 | */ | ||
4783 | static int decode_attr_clone_blksize(struct xdr_stream *xdr, uint32_t *bitmap, | ||
4784 | uint32_t *res) | ||
4785 | { | ||
4786 | __be32 *p; | ||
4787 | |||
4788 | dprintk("%s: bitmap is %x\n", __func__, bitmap[2]); | ||
4789 | *res = 0; | ||
4790 | if (bitmap[2] & FATTR4_WORD2_CLONE_BLKSIZE) { | ||
4791 | p = xdr_inline_decode(xdr, 4); | ||
4792 | if (unlikely(!p)) { | ||
4793 | print_overflow_msg(__func__, xdr); | ||
4794 | return -EIO; | ||
4795 | } | ||
4796 | *res = be32_to_cpup(p); | ||
4797 | bitmap[2] &= ~FATTR4_WORD2_CLONE_BLKSIZE; | ||
4798 | } | ||
4799 | return 0; | ||
4800 | } | ||
4801 | |||
4767 | static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo) | 4802 | static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo) |
4768 | { | 4803 | { |
4769 | unsigned int savep; | 4804 | unsigned int savep; |
@@ -4789,15 +4824,28 @@ static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo) | |||
4789 | if ((status = decode_attr_maxwrite(xdr, bitmap, &fsinfo->wtmax)) != 0) | 4824 | if ((status = decode_attr_maxwrite(xdr, bitmap, &fsinfo->wtmax)) != 0) |
4790 | goto xdr_error; | 4825 | goto xdr_error; |
4791 | fsinfo->wtpref = fsinfo->wtmax; | 4826 | fsinfo->wtpref = fsinfo->wtmax; |
4827 | |||
4828 | status = -EIO; | ||
4829 | if (unlikely(bitmap[0])) | ||
4830 | goto xdr_error; | ||
4831 | |||
4792 | status = decode_attr_time_delta(xdr, bitmap, &fsinfo->time_delta); | 4832 | status = decode_attr_time_delta(xdr, bitmap, &fsinfo->time_delta); |
4793 | if (status != 0) | 4833 | if (status != 0) |
4794 | goto xdr_error; | 4834 | goto xdr_error; |
4795 | status = decode_attr_pnfstype(xdr, bitmap, &fsinfo->layouttype); | 4835 | status = decode_attr_pnfstype(xdr, bitmap, &fsinfo->layouttype); |
4796 | if (status != 0) | 4836 | if (status != 0) |
4797 | goto xdr_error; | 4837 | goto xdr_error; |
4838 | |||
4839 | status = -EIO; | ||
4840 | if (unlikely(bitmap[1])) | ||
4841 | goto xdr_error; | ||
4842 | |||
4798 | status = decode_attr_layout_blksize(xdr, bitmap, &fsinfo->blksize); | 4843 | status = decode_attr_layout_blksize(xdr, bitmap, &fsinfo->blksize); |
4799 | if (status) | 4844 | if (status) |
4800 | goto xdr_error; | 4845 | goto xdr_error; |
4846 | status = decode_attr_clone_blksize(xdr, bitmap, &fsinfo->clone_blksize); | ||
4847 | if (status) | ||
4848 | goto xdr_error; | ||
4801 | 4849 | ||
4802 | status = verify_attr_len(xdr, savep, attrlen); | 4850 | status = verify_attr_len(xdr, savep, attrlen); |
4803 | xdr_error: | 4851 | xdr_error: |
@@ -7465,6 +7513,7 @@ struct rpc_procinfo nfs4_procedures[] = { | |||
7465 | PROC(ALLOCATE, enc_allocate, dec_allocate), | 7513 | PROC(ALLOCATE, enc_allocate, dec_allocate), |
7466 | PROC(DEALLOCATE, enc_deallocate, dec_deallocate), | 7514 | PROC(DEALLOCATE, enc_deallocate, dec_deallocate), |
7467 | PROC(LAYOUTSTATS, enc_layoutstats, dec_layoutstats), | 7515 | PROC(LAYOUTSTATS, enc_layoutstats, dec_layoutstats), |
7516 | PROC(CLONE, enc_clone, dec_clone), | ||
7468 | #endif /* CONFIG_NFS_V4_2 */ | 7517 | #endif /* CONFIG_NFS_V4_2 */ |
7469 | }; | 7518 | }; |
7470 | 7519 | ||
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index 9bc9f04fb7f6..89a15dbe5efc 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c | |||
@@ -90,7 +90,7 @@ | |||
90 | #define NFS_DEF_OPTIONS "vers=2,udp,rsize=4096,wsize=4096" | 90 | #define NFS_DEF_OPTIONS "vers=2,udp,rsize=4096,wsize=4096" |
91 | 91 | ||
92 | /* Parameters passed from the kernel command line */ | 92 | /* Parameters passed from the kernel command line */ |
93 | static char nfs_root_parms[256] __initdata = ""; | 93 | static char nfs_root_parms[NFS_MAXPATHLEN + 1] __initdata = ""; |
94 | 94 | ||
95 | /* Text-based mount options passed to super.c */ | 95 | /* Text-based mount options passed to super.c */ |
96 | static char nfs_root_options[256] __initdata = NFS_DEF_OPTIONS; | 96 | static char nfs_root_options[256] __initdata = NFS_DEF_OPTIONS; |
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 8abe27165ad0..93496c059837 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
@@ -1912,12 +1912,13 @@ static void pnfs_ld_handle_write_error(struct nfs_pgio_header *hdr) | |||
1912 | */ | 1912 | */ |
1913 | void pnfs_ld_write_done(struct nfs_pgio_header *hdr) | 1913 | void pnfs_ld_write_done(struct nfs_pgio_header *hdr) |
1914 | { | 1914 | { |
1915 | trace_nfs4_pnfs_write(hdr, hdr->pnfs_error); | 1915 | if (likely(!hdr->pnfs_error)) { |
1916 | if (!hdr->pnfs_error) { | ||
1917 | pnfs_set_layoutcommit(hdr->inode, hdr->lseg, | 1916 | pnfs_set_layoutcommit(hdr->inode, hdr->lseg, |
1918 | hdr->mds_offset + hdr->res.count); | 1917 | hdr->mds_offset + hdr->res.count); |
1919 | hdr->mds_ops->rpc_call_done(&hdr->task, hdr); | 1918 | hdr->mds_ops->rpc_call_done(&hdr->task, hdr); |
1920 | } else | 1919 | } |
1920 | trace_nfs4_pnfs_write(hdr, hdr->pnfs_error); | ||
1921 | if (unlikely(hdr->pnfs_error)) | ||
1921 | pnfs_ld_handle_write_error(hdr); | 1922 | pnfs_ld_handle_write_error(hdr); |
1922 | hdr->mds_ops->rpc_release(hdr); | 1923 | hdr->mds_ops->rpc_release(hdr); |
1923 | } | 1924 | } |
@@ -2028,11 +2029,12 @@ static void pnfs_ld_handle_read_error(struct nfs_pgio_header *hdr) | |||
2028 | */ | 2029 | */ |
2029 | void pnfs_ld_read_done(struct nfs_pgio_header *hdr) | 2030 | void pnfs_ld_read_done(struct nfs_pgio_header *hdr) |
2030 | { | 2031 | { |
2031 | trace_nfs4_pnfs_read(hdr, hdr->pnfs_error); | ||
2032 | if (likely(!hdr->pnfs_error)) { | 2032 | if (likely(!hdr->pnfs_error)) { |
2033 | __nfs4_read_done_cb(hdr); | 2033 | __nfs4_read_done_cb(hdr); |
2034 | hdr->mds_ops->rpc_call_done(&hdr->task, hdr); | 2034 | hdr->mds_ops->rpc_call_done(&hdr->task, hdr); |
2035 | } else | 2035 | } |
2036 | trace_nfs4_pnfs_read(hdr, hdr->pnfs_error); | ||
2037 | if (unlikely(hdr->pnfs_error)) | ||
2036 | pnfs_ld_handle_read_error(hdr); | 2038 | pnfs_ld_handle_read_error(hdr); |
2037 | hdr->mds_ops->rpc_release(hdr); | 2039 | hdr->mds_ops->rpc_release(hdr); |
2038 | } | 2040 | } |
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 01b8cc8e8cfc..0a5e33f33b5c 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
@@ -246,6 +246,13 @@ static void nfs_readpage_retry(struct rpc_task *task, | |||
246 | nfs_set_pgio_error(hdr, -EIO, argp->offset); | 246 | nfs_set_pgio_error(hdr, -EIO, argp->offset); |
247 | return; | 247 | return; |
248 | } | 248 | } |
249 | |||
250 | /* For non rpc-based layout drivers, retry-through-MDS */ | ||
251 | if (!task->tk_ops) { | ||
252 | hdr->pnfs_error = -EAGAIN; | ||
253 | return; | ||
254 | } | ||
255 | |||
249 | /* Yes, so retry the read at the end of the hdr */ | 256 | /* Yes, so retry the read at the end of the hdr */ |
250 | hdr->mds_offset += resp->count; | 257 | hdr->mds_offset += resp->count; |
251 | argp->offset += resp->count; | 258 | argp->offset += resp->count; |
@@ -268,7 +275,7 @@ static void nfs_readpage_result(struct rpc_task *task, | |||
268 | hdr->good_bytes = bound - hdr->io_start; | 275 | hdr->good_bytes = bound - hdr->io_start; |
269 | } | 276 | } |
270 | spin_unlock(&hdr->lock); | 277 | spin_unlock(&hdr->lock); |
271 | } else if (hdr->res.count != hdr->args.count) | 278 | } else if (hdr->res.count < hdr->args.count) |
272 | nfs_readpage_retry(task, hdr); | 279 | nfs_readpage_retry(task, hdr); |
273 | } | 280 | } |
274 | 281 | ||
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 383a027de452..f1268280244e 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -2816,7 +2816,6 @@ out_invalid_transport_udp: | |||
2816 | * NFS client for backwards compatibility | 2816 | * NFS client for backwards compatibility |
2817 | */ | 2817 | */ |
2818 | unsigned int nfs_callback_set_tcpport; | 2818 | unsigned int nfs_callback_set_tcpport; |
2819 | unsigned short nfs_callback_tcpport; | ||
2820 | /* Default cache timeout is 10 minutes */ | 2819 | /* Default cache timeout is 10 minutes */ |
2821 | unsigned int nfs_idmap_cache_timeout = 600; | 2820 | unsigned int nfs_idmap_cache_timeout = 600; |
2822 | /* Turn off NFSv4 uid/gid mapping when using AUTH_SYS */ | 2821 | /* Turn off NFSv4 uid/gid mapping when using AUTH_SYS */ |
@@ -2827,7 +2826,6 @@ char nfs4_client_id_uniquifier[NFS4_CLIENT_ID_UNIQ_LEN] = ""; | |||
2827 | bool recover_lost_locks = false; | 2826 | bool recover_lost_locks = false; |
2828 | 2827 | ||
2829 | EXPORT_SYMBOL_GPL(nfs_callback_set_tcpport); | 2828 | EXPORT_SYMBOL_GPL(nfs_callback_set_tcpport); |
2830 | EXPORT_SYMBOL_GPL(nfs_callback_tcpport); | ||
2831 | EXPORT_SYMBOL_GPL(nfs_idmap_cache_timeout); | 2829 | EXPORT_SYMBOL_GPL(nfs_idmap_cache_timeout); |
2832 | EXPORT_SYMBOL_GPL(nfs4_disable_idmapping); | 2830 | EXPORT_SYMBOL_GPL(nfs4_disable_idmapping); |
2833 | EXPORT_SYMBOL_GPL(max_session_slots); | 2831 | EXPORT_SYMBOL_GPL(max_session_slots); |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 75ab7622e0cc..7b9316406930 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -1505,6 +1505,13 @@ static void nfs_writeback_result(struct rpc_task *task, | |||
1505 | task->tk_status = -EIO; | 1505 | task->tk_status = -EIO; |
1506 | return; | 1506 | return; |
1507 | } | 1507 | } |
1508 | |||
1509 | /* For non rpc-based layout drivers, retry-through-MDS */ | ||
1510 | if (!task->tk_ops) { | ||
1511 | hdr->pnfs_error = -EAGAIN; | ||
1512 | return; | ||
1513 | } | ||
1514 | |||
1508 | /* Was this an NFSv2 write or an NFSv3 stable write? */ | 1515 | /* Was this an NFSv2 write or an NFSv3 stable write? */ |
1509 | if (resp->verf->committed != NFS_UNSTABLE) { | 1516 | if (resp->verf->committed != NFS_UNSTABLE) { |
1510 | /* Resend from where the server left off */ | 1517 | /* Resend from where the server left off */ |