diff options
author | Michal Marek <mmarek@suse.cz> | 2010-08-04 07:59:13 -0400 |
---|---|---|
committer | Michal Marek <mmarek@suse.cz> | 2010-08-04 07:59:13 -0400 |
commit | 772320e84588dcbe1600ffb83e5f328f2209ac2a (patch) | |
tree | a7de21b79340aeaa17c58126f6b801b82c77b53a /fs/nfs | |
parent | 1ce53adf13a54375d2a5c7cdbe341b2558389615 (diff) | |
parent | 9fe6206f400646a2322096b56c59891d530e8d51 (diff) |
Merge commit 'v2.6.35' into kbuild/kbuild
Conflicts:
arch/powerpc/Makefile
Diffstat (limited to 'fs/nfs')
39 files changed, 1720 insertions, 1130 deletions
diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig index 59e5673b4597..a43d07e7b924 100644 --- a/fs/nfs/Kconfig +++ b/fs/nfs/Kconfig | |||
@@ -95,8 +95,7 @@ config ROOT_NFS | |||
95 | Most people say N here. | 95 | Most people say N here. |
96 | 96 | ||
97 | config NFS_FSCACHE | 97 | config NFS_FSCACHE |
98 | bool "Provide NFS client caching support (EXPERIMENTAL)" | 98 | bool "Provide NFS client caching support" |
99 | depends on EXPERIMENTAL | ||
100 | depends on NFS_FS=m && FSCACHE || NFS_FS=y && FSCACHE=y | 99 | depends on NFS_FS=m && FSCACHE || NFS_FS=y && FSCACHE=y |
101 | help | 100 | help |
102 | Say Y here if you want NFS data to be cached locally on disc through | 101 | Say Y here if you want NFS data to be cached locally on disc through |
diff --git a/fs/nfs/cache_lib.c b/fs/nfs/cache_lib.c index b4ffd0146ea6..84690319e625 100644 --- a/fs/nfs/cache_lib.c +++ b/fs/nfs/cache_lib.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/moduleparam.h> | 10 | #include <linux/moduleparam.h> |
11 | #include <linux/mount.h> | 11 | #include <linux/mount.h> |
12 | #include <linux/namei.h> | 12 | #include <linux/namei.h> |
13 | #include <linux/slab.h> | ||
13 | #include <linux/sunrpc/cache.h> | 14 | #include <linux/sunrpc/cache.h> |
14 | #include <linux/sunrpc/rpc_pipe_fs.h> | 15 | #include <linux/sunrpc/rpc_pipe_fs.h> |
15 | 16 | ||
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 73ab220354df..36dfdae95123 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
@@ -118,7 +118,6 @@ nfs4_callback_up(struct svc_serv *serv) | |||
118 | dprintk("NFS: Callback listener port = %u (af %u)\n", | 118 | dprintk("NFS: Callback listener port = %u (af %u)\n", |
119 | nfs_callback_tcpport, PF_INET); | 119 | nfs_callback_tcpport, PF_INET); |
120 | 120 | ||
121 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
122 | ret = svc_create_xprt(serv, "tcp", PF_INET6, | 121 | ret = svc_create_xprt(serv, "tcp", PF_INET6, |
123 | nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS); | 122 | nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS); |
124 | if (ret > 0) { | 123 | if (ret > 0) { |
@@ -129,7 +128,6 @@ nfs4_callback_up(struct svc_serv *serv) | |||
129 | ret = 0; | 128 | ret = 0; |
130 | else | 129 | else |
131 | goto out_err; | 130 | goto out_err; |
132 | #endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ | ||
133 | 131 | ||
134 | return svc_prepare_thread(serv, &serv->sv_pools[0]); | 132 | return svc_prepare_thread(serv, &serv->sv_pools[0]); |
135 | 133 | ||
diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h index d4036be0b589..85a7cfd1b8dd 100644 --- a/fs/nfs/callback.h +++ b/fs/nfs/callback.h | |||
@@ -119,6 +119,14 @@ struct cb_recallanyargs { | |||
119 | }; | 119 | }; |
120 | 120 | ||
121 | extern unsigned nfs4_callback_recallany(struct cb_recallanyargs *args, void *dummy); | 121 | extern unsigned nfs4_callback_recallany(struct cb_recallanyargs *args, void *dummy); |
122 | |||
123 | struct cb_recallslotargs { | ||
124 | struct sockaddr *crsa_addr; | ||
125 | uint32_t crsa_target_max_slots; | ||
126 | }; | ||
127 | extern unsigned nfs4_callback_recallslot(struct cb_recallslotargs *args, | ||
128 | void *dummy); | ||
129 | |||
122 | #endif /* CONFIG_NFS_V4_1 */ | 130 | #endif /* CONFIG_NFS_V4_1 */ |
123 | 131 | ||
124 | extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res); | 132 | extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res); |
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index defa9b4c470e..a08770a7e857 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
@@ -7,6 +7,7 @@ | |||
7 | */ | 7 | */ |
8 | #include <linux/nfs4.h> | 8 | #include <linux/nfs4.h> |
9 | #include <linux/nfs_fs.h> | 9 | #include <linux/nfs_fs.h> |
10 | #include <linux/slab.h> | ||
10 | #include "nfs4_fs.h" | 11 | #include "nfs4_fs.h" |
11 | #include "callback.h" | 12 | #include "callback.h" |
12 | #include "delegation.h" | 13 | #include "delegation.h" |
@@ -143,44 +144,49 @@ int nfs41_validate_delegation_stateid(struct nfs_delegation *delegation, const n | |||
143 | * Return success if the sequenceID is one more than what we last saw on | 144 | * Return success if the sequenceID is one more than what we last saw on |
144 | * this slot, accounting for wraparound. Increments the slot's sequence. | 145 | * this slot, accounting for wraparound. Increments the slot's sequence. |
145 | * | 146 | * |
146 | * We don't yet implement a duplicate request cache, so at this time | 147 | * We don't yet implement a duplicate request cache, instead we set the |
147 | * we will log replays, and process them as if we had not seen them before, | 148 | * back channel ca_maxresponsesize_cached to zero. This is OK for now |
148 | * but we don't bump the sequence in the slot. Not too worried about it, | ||
149 | * since we only currently implement idempotent callbacks anyway. | 149 | * since we only currently implement idempotent callbacks anyway. |
150 | * | 150 | * |
151 | * We have a single slot backchannel at this time, so we don't bother | 151 | * We have a single slot backchannel at this time, so we don't bother |
152 | * checking the used_slots bit array on the table. The lower layer guarantees | 152 | * checking the used_slots bit array on the table. The lower layer guarantees |
153 | * a single outstanding callback request at a time. | 153 | * a single outstanding callback request at a time. |
154 | */ | 154 | */ |
155 | static int | 155 | static __be32 |
156 | validate_seqid(struct nfs4_slot_table *tbl, u32 slotid, u32 seqid) | 156 | validate_seqid(struct nfs4_slot_table *tbl, struct cb_sequenceargs * args) |
157 | { | 157 | { |
158 | struct nfs4_slot *slot; | 158 | struct nfs4_slot *slot; |
159 | 159 | ||
160 | dprintk("%s enter. slotid %d seqid %d\n", | 160 | dprintk("%s enter. slotid %d seqid %d\n", |
161 | __func__, slotid, seqid); | 161 | __func__, args->csa_slotid, args->csa_sequenceid); |
162 | 162 | ||
163 | if (slotid > NFS41_BC_MAX_CALLBACKS) | 163 | if (args->csa_slotid > NFS41_BC_MAX_CALLBACKS) |
164 | return htonl(NFS4ERR_BADSLOT); | 164 | return htonl(NFS4ERR_BADSLOT); |
165 | 165 | ||
166 | slot = tbl->slots + slotid; | 166 | slot = tbl->slots + args->csa_slotid; |
167 | dprintk("%s slot table seqid: %d\n", __func__, slot->seq_nr); | 167 | dprintk("%s slot table seqid: %d\n", __func__, slot->seq_nr); |
168 | 168 | ||
169 | /* Normal */ | 169 | /* Normal */ |
170 | if (likely(seqid == slot->seq_nr + 1)) { | 170 | if (likely(args->csa_sequenceid == slot->seq_nr + 1)) { |
171 | slot->seq_nr++; | 171 | slot->seq_nr++; |
172 | return htonl(NFS4_OK); | 172 | return htonl(NFS4_OK); |
173 | } | 173 | } |
174 | 174 | ||
175 | /* Replay */ | 175 | /* Replay */ |
176 | if (seqid == slot->seq_nr) { | 176 | if (args->csa_sequenceid == slot->seq_nr) { |
177 | dprintk("%s seqid %d is a replay - no DRC available\n", | 177 | dprintk("%s seqid %d is a replay\n", |
178 | __func__, seqid); | 178 | __func__, args->csa_sequenceid); |
179 | return htonl(NFS4_OK); | 179 | /* Signal process_op to set this error on next op */ |
180 | if (args->csa_cachethis == 0) | ||
181 | return htonl(NFS4ERR_RETRY_UNCACHED_REP); | ||
182 | |||
183 | /* The ca_maxresponsesize_cached is 0 with no DRC */ | ||
184 | else if (args->csa_cachethis == 1) | ||
185 | return htonl(NFS4ERR_REP_TOO_BIG_TO_CACHE); | ||
180 | } | 186 | } |
181 | 187 | ||
182 | /* Wraparound */ | 188 | /* Wraparound */ |
183 | if (seqid == 1 && (slot->seq_nr + 1) == 0) { | 189 | if (args->csa_sequenceid == 1 && (slot->seq_nr + 1) == 0) { |
184 | slot->seq_nr = 1; | 190 | slot->seq_nr = 1; |
185 | return htonl(NFS4_OK); | 191 | return htonl(NFS4_OK); |
186 | } | 192 | } |
@@ -225,27 +231,87 @@ validate_seqid(struct nfs4_slot_table *tbl, u32 slotid, u32 seqid) | |||
225 | return NULL; | 231 | return NULL; |
226 | } | 232 | } |
227 | 233 | ||
228 | /* FIXME: referring calls should be processed */ | 234 | /* |
229 | unsigned nfs4_callback_sequence(struct cb_sequenceargs *args, | 235 | * For each referring call triple, check the session's slot table for |
236 | * a match. If the slot is in use and the sequence numbers match, the | ||
237 | * client is still waiting for a response to the original request. | ||
238 | */ | ||
239 | static bool referring_call_exists(struct nfs_client *clp, | ||
240 | uint32_t nrclists, | ||
241 | struct referring_call_list *rclists) | ||
242 | { | ||
243 | bool status = 0; | ||
244 | int i, j; | ||
245 | struct nfs4_session *session; | ||
246 | struct nfs4_slot_table *tbl; | ||
247 | struct referring_call_list *rclist; | ||
248 | struct referring_call *ref; | ||
249 | |||
250 | /* | ||
251 | * XXX When client trunking is implemented, this becomes | ||
252 | * a session lookup from within the loop | ||
253 | */ | ||
254 | session = clp->cl_session; | ||
255 | tbl = &session->fc_slot_table; | ||
256 | |||
257 | for (i = 0; i < nrclists; i++) { | ||
258 | rclist = &rclists[i]; | ||
259 | if (memcmp(session->sess_id.data, | ||
260 | rclist->rcl_sessionid.data, | ||
261 | NFS4_MAX_SESSIONID_LEN) != 0) | ||
262 | continue; | ||
263 | |||
264 | for (j = 0; j < rclist->rcl_nrefcalls; j++) { | ||
265 | ref = &rclist->rcl_refcalls[j]; | ||
266 | |||
267 | dprintk("%s: sessionid %x:%x:%x:%x sequenceid %u " | ||
268 | "slotid %u\n", __func__, | ||
269 | ((u32 *)&rclist->rcl_sessionid.data)[0], | ||
270 | ((u32 *)&rclist->rcl_sessionid.data)[1], | ||
271 | ((u32 *)&rclist->rcl_sessionid.data)[2], | ||
272 | ((u32 *)&rclist->rcl_sessionid.data)[3], | ||
273 | ref->rc_sequenceid, ref->rc_slotid); | ||
274 | |||
275 | spin_lock(&tbl->slot_tbl_lock); | ||
276 | status = (test_bit(ref->rc_slotid, tbl->used_slots) && | ||
277 | tbl->slots[ref->rc_slotid].seq_nr == | ||
278 | ref->rc_sequenceid); | ||
279 | spin_unlock(&tbl->slot_tbl_lock); | ||
280 | if (status) | ||
281 | goto out; | ||
282 | } | ||
283 | } | ||
284 | |||
285 | out: | ||
286 | return status; | ||
287 | } | ||
288 | |||
289 | __be32 nfs4_callback_sequence(struct cb_sequenceargs *args, | ||
230 | struct cb_sequenceres *res) | 290 | struct cb_sequenceres *res) |
231 | { | 291 | { |
232 | struct nfs_client *clp; | 292 | struct nfs_client *clp; |
233 | int i, status; | 293 | int i; |
234 | 294 | __be32 status; | |
235 | for (i = 0; i < args->csa_nrclists; i++) | ||
236 | kfree(args->csa_rclists[i].rcl_refcalls); | ||
237 | kfree(args->csa_rclists); | ||
238 | 295 | ||
239 | status = htonl(NFS4ERR_BADSESSION); | 296 | status = htonl(NFS4ERR_BADSESSION); |
240 | clp = find_client_with_session(args->csa_addr, 4, &args->csa_sessionid); | 297 | clp = find_client_with_session(args->csa_addr, 4, &args->csa_sessionid); |
241 | if (clp == NULL) | 298 | if (clp == NULL) |
242 | goto out; | 299 | goto out; |
243 | 300 | ||
244 | status = validate_seqid(&clp->cl_session->bc_slot_table, | 301 | status = validate_seqid(&clp->cl_session->bc_slot_table, args); |
245 | args->csa_slotid, args->csa_sequenceid); | ||
246 | if (status) | 302 | if (status) |
247 | goto out_putclient; | 303 | goto out_putclient; |
248 | 304 | ||
305 | /* | ||
306 | * Check for pending referring calls. If a match is found, a | ||
307 | * related callback was received before the response to the original | ||
308 | * call. | ||
309 | */ | ||
310 | if (referring_call_exists(clp, args->csa_nrclists, args->csa_rclists)) { | ||
311 | status = htonl(NFS4ERR_DELAY); | ||
312 | goto out_putclient; | ||
313 | } | ||
314 | |||
249 | memcpy(&res->csr_sessionid, &args->csa_sessionid, | 315 | memcpy(&res->csr_sessionid, &args->csa_sessionid, |
250 | sizeof(res->csr_sessionid)); | 316 | sizeof(res->csr_sessionid)); |
251 | res->csr_sequenceid = args->csa_sequenceid; | 317 | res->csr_sequenceid = args->csa_sequenceid; |
@@ -256,15 +322,23 @@ unsigned nfs4_callback_sequence(struct cb_sequenceargs *args, | |||
256 | out_putclient: | 322 | out_putclient: |
257 | nfs_put_client(clp); | 323 | nfs_put_client(clp); |
258 | out: | 324 | out: |
259 | dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); | 325 | for (i = 0; i < args->csa_nrclists; i++) |
260 | res->csr_status = status; | 326 | kfree(args->csa_rclists[i].rcl_refcalls); |
261 | return res->csr_status; | 327 | kfree(args->csa_rclists); |
328 | |||
329 | if (status == htonl(NFS4ERR_RETRY_UNCACHED_REP)) | ||
330 | res->csr_status = 0; | ||
331 | else | ||
332 | res->csr_status = status; | ||
333 | dprintk("%s: exit with status = %d res->csr_status %d\n", __func__, | ||
334 | ntohl(status), ntohl(res->csr_status)); | ||
335 | return status; | ||
262 | } | 336 | } |
263 | 337 | ||
264 | unsigned nfs4_callback_recallany(struct cb_recallanyargs *args, void *dummy) | 338 | __be32 nfs4_callback_recallany(struct cb_recallanyargs *args, void *dummy) |
265 | { | 339 | { |
266 | struct nfs_client *clp; | 340 | struct nfs_client *clp; |
267 | int status; | 341 | __be32 status; |
268 | fmode_t flags = 0; | 342 | fmode_t flags = 0; |
269 | 343 | ||
270 | status = htonl(NFS4ERR_OP_NOT_IN_SESSION); | 344 | status = htonl(NFS4ERR_OP_NOT_IN_SESSION); |
@@ -289,4 +363,40 @@ out: | |||
289 | dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); | 363 | dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); |
290 | return status; | 364 | return status; |
291 | } | 365 | } |
366 | |||
367 | /* Reduce the fore channel's max_slots to the target value */ | ||
368 | __be32 nfs4_callback_recallslot(struct cb_recallslotargs *args, void *dummy) | ||
369 | { | ||
370 | struct nfs_client *clp; | ||
371 | struct nfs4_slot_table *fc_tbl; | ||
372 | __be32 status; | ||
373 | |||
374 | status = htonl(NFS4ERR_OP_NOT_IN_SESSION); | ||
375 | clp = nfs_find_client(args->crsa_addr, 4); | ||
376 | if (clp == NULL) | ||
377 | goto out; | ||
378 | |||
379 | dprintk("NFS: CB_RECALL_SLOT request from %s target max slots %d\n", | ||
380 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR), | ||
381 | args->crsa_target_max_slots); | ||
382 | |||
383 | fc_tbl = &clp->cl_session->fc_slot_table; | ||
384 | |||
385 | status = htonl(NFS4ERR_BAD_HIGH_SLOT); | ||
386 | if (args->crsa_target_max_slots > fc_tbl->max_slots || | ||
387 | args->crsa_target_max_slots < 1) | ||
388 | goto out_putclient; | ||
389 | |||
390 | status = htonl(NFS4_OK); | ||
391 | if (args->crsa_target_max_slots == fc_tbl->max_slots) | ||
392 | goto out_putclient; | ||
393 | |||
394 | fc_tbl->target_max_slots = args->crsa_target_max_slots; | ||
395 | nfs41_handle_recall_slot(clp); | ||
396 | out_putclient: | ||
397 | nfs_put_client(clp); /* balance nfs_find_client */ | ||
398 | out: | ||
399 | dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); | ||
400 | return status; | ||
401 | } | ||
292 | #endif /* CONFIG_NFS_V4_1 */ | 402 | #endif /* CONFIG_NFS_V4_1 */ |
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index 8e1a2511c8be..05af212f0edf 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <linux/sunrpc/svc.h> | 9 | #include <linux/sunrpc/svc.h> |
10 | #include <linux/nfs4.h> | 10 | #include <linux/nfs4.h> |
11 | #include <linux/nfs_fs.h> | 11 | #include <linux/nfs_fs.h> |
12 | #include <linux/slab.h> | ||
12 | #include "nfs4_fs.h" | 13 | #include "nfs4_fs.h" |
13 | #include "callback.h" | 14 | #include "callback.h" |
14 | 15 | ||
@@ -24,10 +25,14 @@ | |||
24 | #define CB_OP_SEQUENCE_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ + \ | 25 | #define CB_OP_SEQUENCE_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ + \ |
25 | 4 + 1 + 3) | 26 | 4 + 1 + 3) |
26 | #define CB_OP_RECALLANY_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) | 27 | #define CB_OP_RECALLANY_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) |
28 | #define CB_OP_RECALLSLOT_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) | ||
27 | #endif /* CONFIG_NFS_V4_1 */ | 29 | #endif /* CONFIG_NFS_V4_1 */ |
28 | 30 | ||
29 | #define NFSDBG_FACILITY NFSDBG_CALLBACK | 31 | #define NFSDBG_FACILITY NFSDBG_CALLBACK |
30 | 32 | ||
33 | /* Internal error code */ | ||
34 | #define NFS4ERR_RESOURCE_HDR 11050 | ||
35 | |||
31 | typedef __be32 (*callback_process_op_t)(void *, void *); | 36 | typedef __be32 (*callback_process_op_t)(void *, void *); |
32 | typedef __be32 (*callback_decode_arg_t)(struct svc_rqst *, struct xdr_stream *, void *); | 37 | typedef __be32 (*callback_decode_arg_t)(struct svc_rqst *, struct xdr_stream *, void *); |
33 | typedef __be32 (*callback_encode_res_t)(struct svc_rqst *, struct xdr_stream *, void *); | 38 | typedef __be32 (*callback_encode_res_t)(struct svc_rqst *, struct xdr_stream *, void *); |
@@ -173,7 +178,7 @@ static __be32 decode_op_hdr(struct xdr_stream *xdr, unsigned int *op) | |||
173 | __be32 *p; | 178 | __be32 *p; |
174 | p = read_buf(xdr, 4); | 179 | p = read_buf(xdr, 4); |
175 | if (unlikely(p == NULL)) | 180 | if (unlikely(p == NULL)) |
176 | return htonl(NFS4ERR_RESOURCE); | 181 | return htonl(NFS4ERR_RESOURCE_HDR); |
177 | *op = ntohl(*p); | 182 | *op = ntohl(*p); |
178 | return 0; | 183 | return 0; |
179 | } | 184 | } |
@@ -215,10 +220,10 @@ out: | |||
215 | 220 | ||
216 | #if defined(CONFIG_NFS_V4_1) | 221 | #if defined(CONFIG_NFS_V4_1) |
217 | 222 | ||
218 | static unsigned decode_sessionid(struct xdr_stream *xdr, | 223 | static __be32 decode_sessionid(struct xdr_stream *xdr, |
219 | struct nfs4_sessionid *sid) | 224 | struct nfs4_sessionid *sid) |
220 | { | 225 | { |
221 | uint32_t *p; | 226 | __be32 *p; |
222 | int len = NFS4_MAX_SESSIONID_LEN; | 227 | int len = NFS4_MAX_SESSIONID_LEN; |
223 | 228 | ||
224 | p = read_buf(xdr, len); | 229 | p = read_buf(xdr, len); |
@@ -229,12 +234,12 @@ static unsigned decode_sessionid(struct xdr_stream *xdr, | |||
229 | return 0; | 234 | return 0; |
230 | } | 235 | } |
231 | 236 | ||
232 | static unsigned decode_rc_list(struct xdr_stream *xdr, | 237 | static __be32 decode_rc_list(struct xdr_stream *xdr, |
233 | struct referring_call_list *rc_list) | 238 | struct referring_call_list *rc_list) |
234 | { | 239 | { |
235 | uint32_t *p; | 240 | __be32 *p; |
236 | int i; | 241 | int i; |
237 | unsigned status; | 242 | __be32 status; |
238 | 243 | ||
239 | status = decode_sessionid(xdr, &rc_list->rcl_sessionid); | 244 | status = decode_sessionid(xdr, &rc_list->rcl_sessionid); |
240 | if (status) | 245 | if (status) |
@@ -267,13 +272,13 @@ out: | |||
267 | return status; | 272 | return status; |
268 | } | 273 | } |
269 | 274 | ||
270 | static unsigned decode_cb_sequence_args(struct svc_rqst *rqstp, | 275 | static __be32 decode_cb_sequence_args(struct svc_rqst *rqstp, |
271 | struct xdr_stream *xdr, | 276 | struct xdr_stream *xdr, |
272 | struct cb_sequenceargs *args) | 277 | struct cb_sequenceargs *args) |
273 | { | 278 | { |
274 | uint32_t *p; | 279 | __be32 *p; |
275 | int i; | 280 | int i; |
276 | unsigned status; | 281 | __be32 status; |
277 | 282 | ||
278 | status = decode_sessionid(xdr, &args->csa_sessionid); | 283 | status = decode_sessionid(xdr, &args->csa_sessionid); |
279 | if (status) | 284 | if (status) |
@@ -327,11 +332,11 @@ out_free: | |||
327 | goto out; | 332 | goto out; |
328 | } | 333 | } |
329 | 334 | ||
330 | static unsigned decode_recallany_args(struct svc_rqst *rqstp, | 335 | static __be32 decode_recallany_args(struct svc_rqst *rqstp, |
331 | struct xdr_stream *xdr, | 336 | struct xdr_stream *xdr, |
332 | struct cb_recallanyargs *args) | 337 | struct cb_recallanyargs *args) |
333 | { | 338 | { |
334 | uint32_t *p; | 339 | __be32 *p; |
335 | 340 | ||
336 | args->craa_addr = svc_addr(rqstp); | 341 | args->craa_addr = svc_addr(rqstp); |
337 | p = read_buf(xdr, 4); | 342 | p = read_buf(xdr, 4); |
@@ -346,6 +351,20 @@ static unsigned decode_recallany_args(struct svc_rqst *rqstp, | |||
346 | return 0; | 351 | return 0; |
347 | } | 352 | } |
348 | 353 | ||
354 | static __be32 decode_recallslot_args(struct svc_rqst *rqstp, | ||
355 | struct xdr_stream *xdr, | ||
356 | struct cb_recallslotargs *args) | ||
357 | { | ||
358 | __be32 *p; | ||
359 | |||
360 | args->crsa_addr = svc_addr(rqstp); | ||
361 | p = read_buf(xdr, 4); | ||
362 | if (unlikely(p == NULL)) | ||
363 | return htonl(NFS4ERR_BADXDR); | ||
364 | args->crsa_target_max_slots = ntohl(*p++); | ||
365 | return 0; | ||
366 | } | ||
367 | |||
349 | #endif /* CONFIG_NFS_V4_1 */ | 368 | #endif /* CONFIG_NFS_V4_1 */ |
350 | 369 | ||
351 | static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str) | 370 | static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str) |
@@ -465,7 +484,7 @@ static __be32 encode_op_hdr(struct xdr_stream *xdr, uint32_t op, __be32 res) | |||
465 | 484 | ||
466 | p = xdr_reserve_space(xdr, 8); | 485 | p = xdr_reserve_space(xdr, 8); |
467 | if (unlikely(p == NULL)) | 486 | if (unlikely(p == NULL)) |
468 | return htonl(NFS4ERR_RESOURCE); | 487 | return htonl(NFS4ERR_RESOURCE_HDR); |
469 | *p++ = htonl(op); | 488 | *p++ = htonl(op); |
470 | *p = res; | 489 | *p = res; |
471 | return 0; | 490 | return 0; |
@@ -499,10 +518,10 @@ out: | |||
499 | 518 | ||
500 | #if defined(CONFIG_NFS_V4_1) | 519 | #if defined(CONFIG_NFS_V4_1) |
501 | 520 | ||
502 | static unsigned encode_sessionid(struct xdr_stream *xdr, | 521 | static __be32 encode_sessionid(struct xdr_stream *xdr, |
503 | const struct nfs4_sessionid *sid) | 522 | const struct nfs4_sessionid *sid) |
504 | { | 523 | { |
505 | uint32_t *p; | 524 | __be32 *p; |
506 | int len = NFS4_MAX_SESSIONID_LEN; | 525 | int len = NFS4_MAX_SESSIONID_LEN; |
507 | 526 | ||
508 | p = xdr_reserve_space(xdr, len); | 527 | p = xdr_reserve_space(xdr, len); |
@@ -513,11 +532,11 @@ static unsigned encode_sessionid(struct xdr_stream *xdr, | |||
513 | return 0; | 532 | return 0; |
514 | } | 533 | } |
515 | 534 | ||
516 | static unsigned encode_cb_sequence_res(struct svc_rqst *rqstp, | 535 | static __be32 encode_cb_sequence_res(struct svc_rqst *rqstp, |
517 | struct xdr_stream *xdr, | 536 | struct xdr_stream *xdr, |
518 | const struct cb_sequenceres *res) | 537 | const struct cb_sequenceres *res) |
519 | { | 538 | { |
520 | uint32_t *p; | 539 | __be32 *p; |
521 | unsigned status = res->csr_status; | 540 | unsigned status = res->csr_status; |
522 | 541 | ||
523 | if (unlikely(status != 0)) | 542 | if (unlikely(status != 0)) |
@@ -554,6 +573,7 @@ preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op) | |||
554 | case OP_CB_RECALL: | 573 | case OP_CB_RECALL: |
555 | case OP_CB_SEQUENCE: | 574 | case OP_CB_SEQUENCE: |
556 | case OP_CB_RECALL_ANY: | 575 | case OP_CB_RECALL_ANY: |
576 | case OP_CB_RECALL_SLOT: | ||
557 | *op = &callback_ops[op_nr]; | 577 | *op = &callback_ops[op_nr]; |
558 | break; | 578 | break; |
559 | 579 | ||
@@ -562,7 +582,6 @@ preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op) | |||
562 | case OP_CB_NOTIFY: | 582 | case OP_CB_NOTIFY: |
563 | case OP_CB_PUSH_DELEG: | 583 | case OP_CB_PUSH_DELEG: |
564 | case OP_CB_RECALLABLE_OBJ_AVAIL: | 584 | case OP_CB_RECALLABLE_OBJ_AVAIL: |
565 | case OP_CB_RECALL_SLOT: | ||
566 | case OP_CB_WANTS_CANCELLED: | 585 | case OP_CB_WANTS_CANCELLED: |
567 | case OP_CB_NOTIFY_LOCK: | 586 | case OP_CB_NOTIFY_LOCK: |
568 | return htonl(NFS4ERR_NOTSUPP); | 587 | return htonl(NFS4ERR_NOTSUPP); |
@@ -602,20 +621,18 @@ preprocess_nfs4_op(unsigned int op_nr, struct callback_op **op) | |||
602 | static __be32 process_op(uint32_t minorversion, int nop, | 621 | static __be32 process_op(uint32_t minorversion, int nop, |
603 | struct svc_rqst *rqstp, | 622 | struct svc_rqst *rqstp, |
604 | struct xdr_stream *xdr_in, void *argp, | 623 | struct xdr_stream *xdr_in, void *argp, |
605 | struct xdr_stream *xdr_out, void *resp) | 624 | struct xdr_stream *xdr_out, void *resp, int* drc_status) |
606 | { | 625 | { |
607 | struct callback_op *op = &callback_ops[0]; | 626 | struct callback_op *op = &callback_ops[0]; |
608 | unsigned int op_nr = OP_CB_ILLEGAL; | 627 | unsigned int op_nr; |
609 | __be32 status; | 628 | __be32 status; |
610 | long maxlen; | 629 | long maxlen; |
611 | __be32 res; | 630 | __be32 res; |
612 | 631 | ||
613 | dprintk("%s: start\n", __func__); | 632 | dprintk("%s: start\n", __func__); |
614 | status = decode_op_hdr(xdr_in, &op_nr); | 633 | status = decode_op_hdr(xdr_in, &op_nr); |
615 | if (unlikely(status)) { | 634 | if (unlikely(status)) |
616 | status = htonl(NFS4ERR_OP_ILLEGAL); | 635 | return status; |
617 | goto out; | ||
618 | } | ||
619 | 636 | ||
620 | dprintk("%s: minorversion=%d nop=%d op_nr=%u\n", | 637 | dprintk("%s: minorversion=%d nop=%d op_nr=%u\n", |
621 | __func__, minorversion, nop, op_nr); | 638 | __func__, minorversion, nop, op_nr); |
@@ -624,19 +641,32 @@ static __be32 process_op(uint32_t minorversion, int nop, | |||
624 | preprocess_nfs4_op(op_nr, &op); | 641 | preprocess_nfs4_op(op_nr, &op); |
625 | if (status == htonl(NFS4ERR_OP_ILLEGAL)) | 642 | if (status == htonl(NFS4ERR_OP_ILLEGAL)) |
626 | op_nr = OP_CB_ILLEGAL; | 643 | op_nr = OP_CB_ILLEGAL; |
627 | out: | 644 | if (status) |
645 | goto encode_hdr; | ||
646 | |||
647 | if (*drc_status) { | ||
648 | status = *drc_status; | ||
649 | goto encode_hdr; | ||
650 | } | ||
651 | |||
628 | maxlen = xdr_out->end - xdr_out->p; | 652 | maxlen = xdr_out->end - xdr_out->p; |
629 | if (maxlen > 0 && maxlen < PAGE_SIZE) { | 653 | if (maxlen > 0 && maxlen < PAGE_SIZE) { |
630 | if (likely(status == 0 && op->decode_args != NULL)) | 654 | status = op->decode_args(rqstp, xdr_in, argp); |
631 | status = op->decode_args(rqstp, xdr_in, argp); | 655 | if (likely(status == 0)) |
632 | if (likely(status == 0 && op->process_op != NULL)) | ||
633 | status = op->process_op(argp, resp); | 656 | status = op->process_op(argp, resp); |
634 | } else | 657 | } else |
635 | status = htonl(NFS4ERR_RESOURCE); | 658 | status = htonl(NFS4ERR_RESOURCE); |
636 | 659 | ||
660 | /* Only set by OP_CB_SEQUENCE processing */ | ||
661 | if (status == htonl(NFS4ERR_RETRY_UNCACHED_REP)) { | ||
662 | *drc_status = status; | ||
663 | status = 0; | ||
664 | } | ||
665 | |||
666 | encode_hdr: | ||
637 | res = encode_op_hdr(xdr_out, op_nr, status); | 667 | res = encode_op_hdr(xdr_out, op_nr, status); |
638 | if (status == 0) | 668 | if (unlikely(res)) |
639 | status = res; | 669 | return res; |
640 | if (op->encode_res != NULL && status == 0) | 670 | if (op->encode_res != NULL && status == 0) |
641 | status = op->encode_res(rqstp, xdr_out, resp); | 671 | status = op->encode_res(rqstp, xdr_out, resp); |
642 | dprintk("%s: done, status = %d\n", __func__, ntohl(status)); | 672 | dprintk("%s: done, status = %d\n", __func__, ntohl(status)); |
@@ -652,7 +682,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r | |||
652 | struct cb_compound_hdr_res hdr_res = { NULL }; | 682 | struct cb_compound_hdr_res hdr_res = { NULL }; |
653 | struct xdr_stream xdr_in, xdr_out; | 683 | struct xdr_stream xdr_in, xdr_out; |
654 | __be32 *p; | 684 | __be32 *p; |
655 | __be32 status; | 685 | __be32 status, drc_status = 0; |
656 | unsigned int nops = 0; | 686 | unsigned int nops = 0; |
657 | 687 | ||
658 | dprintk("%s: start\n", __func__); | 688 | dprintk("%s: start\n", __func__); |
@@ -672,11 +702,18 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r | |||
672 | return rpc_system_err; | 702 | return rpc_system_err; |
673 | 703 | ||
674 | while (status == 0 && nops != hdr_arg.nops) { | 704 | while (status == 0 && nops != hdr_arg.nops) { |
675 | status = process_op(hdr_arg.minorversion, nops, | 705 | status = process_op(hdr_arg.minorversion, nops, rqstp, |
676 | rqstp, &xdr_in, argp, &xdr_out, resp); | 706 | &xdr_in, argp, &xdr_out, resp, &drc_status); |
677 | nops++; | 707 | nops++; |
678 | } | 708 | } |
679 | 709 | ||
710 | /* Buffer overflow in decode_ops_hdr or encode_ops_hdr. Return | ||
711 | * resource error in cb_compound status without returning op */ | ||
712 | if (unlikely(status == htonl(NFS4ERR_RESOURCE_HDR))) { | ||
713 | status = htonl(NFS4ERR_RESOURCE); | ||
714 | nops--; | ||
715 | } | ||
716 | |||
680 | *hdr_res.status = status; | 717 | *hdr_res.status = status; |
681 | *hdr_res.nops = htonl(nops); | 718 | *hdr_res.nops = htonl(nops); |
682 | dprintk("%s: done, status = %u\n", __func__, ntohl(status)); | 719 | dprintk("%s: done, status = %u\n", __func__, ntohl(status)); |
@@ -713,6 +750,11 @@ static struct callback_op callback_ops[] = { | |||
713 | .decode_args = (callback_decode_arg_t)decode_recallany_args, | 750 | .decode_args = (callback_decode_arg_t)decode_recallany_args, |
714 | .res_maxsize = CB_OP_RECALLANY_RES_MAXSZ, | 751 | .res_maxsize = CB_OP_RECALLANY_RES_MAXSZ, |
715 | }, | 752 | }, |
753 | [OP_CB_RECALL_SLOT] = { | ||
754 | .process_op = (callback_process_op_t)nfs4_callback_recallslot, | ||
755 | .decode_args = (callback_decode_arg_t)decode_recallslot_args, | ||
756 | .res_maxsize = CB_OP_RECALLSLOT_RES_MAXSZ, | ||
757 | }, | ||
716 | #endif /* CONFIG_NFS_V4_1 */ | 758 | #endif /* CONFIG_NFS_V4_1 */ |
717 | }; | 759 | }; |
718 | 760 | ||
@@ -741,6 +783,7 @@ struct svc_version nfs4_callback_version1 = { | |||
741 | .vs_proc = nfs4_callback_procedures1, | 783 | .vs_proc = nfs4_callback_procedures1, |
742 | .vs_xdrsize = NFS4_CALLBACK_XDRSIZE, | 784 | .vs_xdrsize = NFS4_CALLBACK_XDRSIZE, |
743 | .vs_dispatch = NULL, | 785 | .vs_dispatch = NULL, |
786 | .vs_hidden = 1, | ||
744 | }; | 787 | }; |
745 | 788 | ||
746 | struct svc_version nfs4_callback_version4 = { | 789 | struct svc_version nfs4_callback_version4 = { |
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index ee77713ce68b..d25b5257b7a1 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/vfs.h> | 35 | #include <linux/vfs.h> |
36 | #include <linux/inet.h> | 36 | #include <linux/inet.h> |
37 | #include <linux/in6.h> | 37 | #include <linux/in6.h> |
38 | #include <linux/slab.h> | ||
38 | #include <net/ipv6.h> | 39 | #include <net/ipv6.h> |
39 | #include <linux/nfs_xdr.h> | 40 | #include <linux/nfs_xdr.h> |
40 | #include <linux/sunrpc/bc_xprt.h> | 41 | #include <linux/sunrpc/bc_xprt.h> |
@@ -164,30 +165,7 @@ error_0: | |||
164 | return ERR_PTR(err); | 165 | return ERR_PTR(err); |
165 | } | 166 | } |
166 | 167 | ||
167 | static void nfs4_shutdown_client(struct nfs_client *clp) | ||
168 | { | ||
169 | #ifdef CONFIG_NFS_V4 | ||
170 | if (__test_and_clear_bit(NFS_CS_RENEWD, &clp->cl_res_state)) | ||
171 | nfs4_kill_renewd(clp); | ||
172 | BUG_ON(!RB_EMPTY_ROOT(&clp->cl_state_owners)); | ||
173 | if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state)) | ||
174 | nfs_idmap_delete(clp); | ||
175 | |||
176 | rpc_destroy_wait_queue(&clp->cl_rpcwaitq); | ||
177 | #endif | ||
178 | } | ||
179 | |||
180 | /* | ||
181 | * Destroy the NFS4 callback service | ||
182 | */ | ||
183 | static void nfs4_destroy_callback(struct nfs_client *clp) | ||
184 | { | ||
185 | #ifdef CONFIG_NFS_V4 | 168 | #ifdef CONFIG_NFS_V4 |
186 | if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) | ||
187 | nfs_callback_down(clp->cl_minorversion); | ||
188 | #endif /* CONFIG_NFS_V4 */ | ||
189 | } | ||
190 | |||
191 | /* | 169 | /* |
192 | * Clears/puts all minor version specific parts from an nfs_client struct | 170 | * Clears/puts all minor version specific parts from an nfs_client struct |
193 | * reverting it to minorversion 0. | 171 | * reverting it to minorversion 0. |
@@ -202,9 +180,33 @@ static void nfs4_clear_client_minor_version(struct nfs_client *clp) | |||
202 | 180 | ||
203 | clp->cl_call_sync = _nfs4_call_sync; | 181 | clp->cl_call_sync = _nfs4_call_sync; |
204 | #endif /* CONFIG_NFS_V4_1 */ | 182 | #endif /* CONFIG_NFS_V4_1 */ |
183 | } | ||
205 | 184 | ||
185 | /* | ||
186 | * Destroy the NFS4 callback service | ||
187 | */ | ||
188 | static void nfs4_destroy_callback(struct nfs_client *clp) | ||
189 | { | ||
190 | if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) | ||
191 | nfs_callback_down(clp->cl_minorversion); | ||
192 | } | ||
193 | |||
194 | static void nfs4_shutdown_client(struct nfs_client *clp) | ||
195 | { | ||
196 | if (__test_and_clear_bit(NFS_CS_RENEWD, &clp->cl_res_state)) | ||
197 | nfs4_kill_renewd(clp); | ||
198 | nfs4_clear_client_minor_version(clp); | ||
206 | nfs4_destroy_callback(clp); | 199 | nfs4_destroy_callback(clp); |
200 | if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state)) | ||
201 | nfs_idmap_delete(clp); | ||
202 | |||
203 | rpc_destroy_wait_queue(&clp->cl_rpcwaitq); | ||
207 | } | 204 | } |
205 | #else | ||
206 | static void nfs4_shutdown_client(struct nfs_client *clp) | ||
207 | { | ||
208 | } | ||
209 | #endif /* CONFIG_NFS_V4 */ | ||
208 | 210 | ||
209 | /* | 211 | /* |
210 | * Destroy a shared client record | 212 | * Destroy a shared client record |
@@ -213,7 +215,6 @@ static void nfs_free_client(struct nfs_client *clp) | |||
213 | { | 215 | { |
214 | dprintk("--> nfs_free_client(%u)\n", clp->rpc_ops->version); | 216 | dprintk("--> nfs_free_client(%u)\n", clp->rpc_ops->version); |
215 | 217 | ||
216 | nfs4_clear_client_minor_version(clp); | ||
217 | nfs4_shutdown_client(clp); | 218 | nfs4_shutdown_client(clp); |
218 | 219 | ||
219 | nfs_fscache_release_client_cookie(clp); | 220 | nfs_fscache_release_client_cookie(clp); |
@@ -933,7 +934,6 @@ static int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *mntfh, str | |||
933 | } | 934 | } |
934 | 935 | ||
935 | fsinfo.fattr = fattr; | 936 | fsinfo.fattr = fattr; |
936 | nfs_fattr_init(fattr); | ||
937 | error = clp->rpc_ops->fsinfo(server, mntfh, &fsinfo); | 937 | error = clp->rpc_ops->fsinfo(server, mntfh, &fsinfo); |
938 | if (error < 0) | 938 | if (error < 0) |
939 | goto out_error; | 939 | goto out_error; |
@@ -965,6 +965,8 @@ out_error: | |||
965 | static void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_server *source) | 965 | static void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_server *source) |
966 | { | 966 | { |
967 | target->flags = source->flags; | 967 | target->flags = source->flags; |
968 | target->rsize = source->rsize; | ||
969 | target->wsize = source->wsize; | ||
968 | target->acregmin = source->acregmin; | 970 | target->acregmin = source->acregmin; |
969 | target->acregmax = source->acregmax; | 971 | target->acregmax = source->acregmax; |
970 | target->acdirmin = source->acdirmin; | 972 | target->acdirmin = source->acdirmin; |
@@ -1044,13 +1046,18 @@ struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data, | |||
1044 | struct nfs_fh *mntfh) | 1046 | struct nfs_fh *mntfh) |
1045 | { | 1047 | { |
1046 | struct nfs_server *server; | 1048 | struct nfs_server *server; |
1047 | struct nfs_fattr fattr; | 1049 | struct nfs_fattr *fattr; |
1048 | int error; | 1050 | int error; |
1049 | 1051 | ||
1050 | server = nfs_alloc_server(); | 1052 | server = nfs_alloc_server(); |
1051 | if (!server) | 1053 | if (!server) |
1052 | return ERR_PTR(-ENOMEM); | 1054 | return ERR_PTR(-ENOMEM); |
1053 | 1055 | ||
1056 | error = -ENOMEM; | ||
1057 | fattr = nfs_alloc_fattr(); | ||
1058 | if (fattr == NULL) | ||
1059 | goto error; | ||
1060 | |||
1054 | /* Get a client representation */ | 1061 | /* Get a client representation */ |
1055 | error = nfs_init_server(server, data); | 1062 | error = nfs_init_server(server, data); |
1056 | if (error < 0) | 1063 | if (error < 0) |
@@ -1061,7 +1068,7 @@ struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data, | |||
1061 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); | 1068 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); |
1062 | 1069 | ||
1063 | /* Probe the root fh to retrieve its FSID */ | 1070 | /* Probe the root fh to retrieve its FSID */ |
1064 | error = nfs_probe_fsinfo(server, mntfh, &fattr); | 1071 | error = nfs_probe_fsinfo(server, mntfh, fattr); |
1065 | if (error < 0) | 1072 | if (error < 0) |
1066 | goto error; | 1073 | goto error; |
1067 | if (server->nfs_client->rpc_ops->version == 3) { | 1074 | if (server->nfs_client->rpc_ops->version == 3) { |
@@ -1074,14 +1081,14 @@ struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data, | |||
1074 | server->namelen = NFS2_MAXNAMLEN; | 1081 | server->namelen = NFS2_MAXNAMLEN; |
1075 | } | 1082 | } |
1076 | 1083 | ||
1077 | if (!(fattr.valid & NFS_ATTR_FATTR)) { | 1084 | if (!(fattr->valid & NFS_ATTR_FATTR)) { |
1078 | error = server->nfs_client->rpc_ops->getattr(server, mntfh, &fattr); | 1085 | error = server->nfs_client->rpc_ops->getattr(server, mntfh, fattr); |
1079 | if (error < 0) { | 1086 | if (error < 0) { |
1080 | dprintk("nfs_create_server: getattr error = %d\n", -error); | 1087 | dprintk("nfs_create_server: getattr error = %d\n", -error); |
1081 | goto error; | 1088 | goto error; |
1082 | } | 1089 | } |
1083 | } | 1090 | } |
1084 | memcpy(&server->fsid, &fattr.fsid, sizeof(server->fsid)); | 1091 | memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid)); |
1085 | 1092 | ||
1086 | dprintk("Server FSID: %llx:%llx\n", | 1093 | dprintk("Server FSID: %llx:%llx\n", |
1087 | (unsigned long long) server->fsid.major, | 1094 | (unsigned long long) server->fsid.major, |
@@ -1093,9 +1100,11 @@ struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data, | |||
1093 | spin_unlock(&nfs_client_lock); | 1100 | spin_unlock(&nfs_client_lock); |
1094 | 1101 | ||
1095 | server->mount_time = jiffies; | 1102 | server->mount_time = jiffies; |
1103 | nfs_free_fattr(fattr); | ||
1096 | return server; | 1104 | return server; |
1097 | 1105 | ||
1098 | error: | 1106 | error: |
1107 | nfs_free_fattr(fattr); | ||
1099 | nfs_free_server(server); | 1108 | nfs_free_server(server); |
1100 | return ERR_PTR(error); | 1109 | return ERR_PTR(error); |
1101 | } | 1110 | } |
@@ -1277,6 +1286,55 @@ static void nfs4_session_set_rwsize(struct nfs_server *server) | |||
1277 | #endif /* CONFIG_NFS_V4_1 */ | 1286 | #endif /* CONFIG_NFS_V4_1 */ |
1278 | } | 1287 | } |
1279 | 1288 | ||
1289 | static int nfs4_server_common_setup(struct nfs_server *server, | ||
1290 | struct nfs_fh *mntfh) | ||
1291 | { | ||
1292 | struct nfs_fattr *fattr; | ||
1293 | int error; | ||
1294 | |||
1295 | BUG_ON(!server->nfs_client); | ||
1296 | BUG_ON(!server->nfs_client->rpc_ops); | ||
1297 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); | ||
1298 | |||
1299 | fattr = nfs_alloc_fattr(); | ||
1300 | if (fattr == NULL) | ||
1301 | return -ENOMEM; | ||
1302 | |||
1303 | /* We must ensure the session is initialised first */ | ||
1304 | error = nfs4_init_session(server); | ||
1305 | if (error < 0) | ||
1306 | goto out; | ||
1307 | |||
1308 | /* Probe the root fh to retrieve its FSID and filehandle */ | ||
1309 | error = nfs4_get_rootfh(server, mntfh); | ||
1310 | if (error < 0) | ||
1311 | goto out; | ||
1312 | |||
1313 | dprintk("Server FSID: %llx:%llx\n", | ||
1314 | (unsigned long long) server->fsid.major, | ||
1315 | (unsigned long long) server->fsid.minor); | ||
1316 | dprintk("Mount FH: %d\n", mntfh->size); | ||
1317 | |||
1318 | nfs4_session_set_rwsize(server); | ||
1319 | |||
1320 | error = nfs_probe_fsinfo(server, mntfh, fattr); | ||
1321 | if (error < 0) | ||
1322 | goto out; | ||
1323 | |||
1324 | if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN) | ||
1325 | server->namelen = NFS4_MAXNAMLEN; | ||
1326 | |||
1327 | spin_lock(&nfs_client_lock); | ||
1328 | list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks); | ||
1329 | list_add_tail(&server->master_link, &nfs_volume_list); | ||
1330 | spin_unlock(&nfs_client_lock); | ||
1331 | |||
1332 | server->mount_time = jiffies; | ||
1333 | out: | ||
1334 | nfs_free_fattr(fattr); | ||
1335 | return error; | ||
1336 | } | ||
1337 | |||
1280 | /* | 1338 | /* |
1281 | * Create a version 4 volume record | 1339 | * Create a version 4 volume record |
1282 | */ | 1340 | */ |
@@ -1293,7 +1351,8 @@ static int nfs4_init_server(struct nfs_server *server, | |||
1293 | 1351 | ||
1294 | /* Initialise the client representation from the mount data */ | 1352 | /* Initialise the client representation from the mount data */ |
1295 | server->flags = data->flags; | 1353 | server->flags = data->flags; |
1296 | server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR; | 1354 | server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR| |
1355 | NFS_CAP_POSIX_LOCK; | ||
1297 | server->options = data->options; | 1356 | server->options = data->options; |
1298 | 1357 | ||
1299 | /* Get a client record */ | 1358 | /* Get a client record */ |
@@ -1336,7 +1395,6 @@ error: | |||
1336 | struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, | 1395 | struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, |
1337 | struct nfs_fh *mntfh) | 1396 | struct nfs_fh *mntfh) |
1338 | { | 1397 | { |
1339 | struct nfs_fattr fattr; | ||
1340 | struct nfs_server *server; | 1398 | struct nfs_server *server; |
1341 | int error; | 1399 | int error; |
1342 | 1400 | ||
@@ -1351,39 +1409,10 @@ struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, | |||
1351 | if (error < 0) | 1409 | if (error < 0) |
1352 | goto error; | 1410 | goto error; |
1353 | 1411 | ||
1354 | BUG_ON(!server->nfs_client); | 1412 | error = nfs4_server_common_setup(server, mntfh); |
1355 | BUG_ON(!server->nfs_client->rpc_ops); | ||
1356 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); | ||
1357 | |||
1358 | error = nfs4_init_session(server); | ||
1359 | if (error < 0) | ||
1360 | goto error; | ||
1361 | |||
1362 | /* Probe the root fh to retrieve its FSID */ | ||
1363 | error = nfs4_path_walk(server, mntfh, data->nfs_server.export_path); | ||
1364 | if (error < 0) | ||
1365 | goto error; | ||
1366 | |||
1367 | dprintk("Server FSID: %llx:%llx\n", | ||
1368 | (unsigned long long) server->fsid.major, | ||
1369 | (unsigned long long) server->fsid.minor); | ||
1370 | dprintk("Mount FH: %d\n", mntfh->size); | ||
1371 | |||
1372 | nfs4_session_set_rwsize(server); | ||
1373 | |||
1374 | error = nfs_probe_fsinfo(server, mntfh, &fattr); | ||
1375 | if (error < 0) | 1413 | if (error < 0) |
1376 | goto error; | 1414 | goto error; |
1377 | 1415 | ||
1378 | if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN) | ||
1379 | server->namelen = NFS4_MAXNAMLEN; | ||
1380 | |||
1381 | spin_lock(&nfs_client_lock); | ||
1382 | list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks); | ||
1383 | list_add_tail(&server->master_link, &nfs_volume_list); | ||
1384 | spin_unlock(&nfs_client_lock); | ||
1385 | |||
1386 | server->mount_time = jiffies; | ||
1387 | dprintk("<-- nfs4_create_server() = %p\n", server); | 1416 | dprintk("<-- nfs4_create_server() = %p\n", server); |
1388 | return server; | 1417 | return server; |
1389 | 1418 | ||
@@ -1401,7 +1430,6 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
1401 | { | 1430 | { |
1402 | struct nfs_client *parent_client; | 1431 | struct nfs_client *parent_client; |
1403 | struct nfs_server *server, *parent_server; | 1432 | struct nfs_server *server, *parent_server; |
1404 | struct nfs_fattr fattr; | ||
1405 | int error; | 1433 | int error; |
1406 | 1434 | ||
1407 | dprintk("--> nfs4_create_referral_server()\n"); | 1435 | dprintk("--> nfs4_create_referral_server()\n"); |
@@ -1434,34 +1462,10 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
1434 | if (error < 0) | 1462 | if (error < 0) |
1435 | goto error; | 1463 | goto error; |
1436 | 1464 | ||
1437 | BUG_ON(!server->nfs_client); | 1465 | error = nfs4_server_common_setup(server, mntfh); |
1438 | BUG_ON(!server->nfs_client->rpc_ops); | ||
1439 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); | ||
1440 | |||
1441 | /* Probe the root fh to retrieve its FSID and filehandle */ | ||
1442 | error = nfs4_path_walk(server, mntfh, data->mnt_path); | ||
1443 | if (error < 0) | 1466 | if (error < 0) |
1444 | goto error; | 1467 | goto error; |
1445 | 1468 | ||
1446 | /* probe the filesystem info for this server filesystem */ | ||
1447 | error = nfs_probe_fsinfo(server, mntfh, &fattr); | ||
1448 | if (error < 0) | ||
1449 | goto error; | ||
1450 | |||
1451 | if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN) | ||
1452 | server->namelen = NFS4_MAXNAMLEN; | ||
1453 | |||
1454 | dprintk("Referral FSID: %llx:%llx\n", | ||
1455 | (unsigned long long) server->fsid.major, | ||
1456 | (unsigned long long) server->fsid.minor); | ||
1457 | |||
1458 | spin_lock(&nfs_client_lock); | ||
1459 | list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks); | ||
1460 | list_add_tail(&server->master_link, &nfs_volume_list); | ||
1461 | spin_unlock(&nfs_client_lock); | ||
1462 | |||
1463 | server->mount_time = jiffies; | ||
1464 | |||
1465 | dprintk("<-- nfs_create_referral_server() = %p\n", server); | 1469 | dprintk("<-- nfs_create_referral_server() = %p\n", server); |
1466 | return server; | 1470 | return server; |
1467 | 1471 | ||
@@ -1481,7 +1485,7 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source, | |||
1481 | struct nfs_fattr *fattr) | 1485 | struct nfs_fattr *fattr) |
1482 | { | 1486 | { |
1483 | struct nfs_server *server; | 1487 | struct nfs_server *server; |
1484 | struct nfs_fattr fattr_fsinfo; | 1488 | struct nfs_fattr *fattr_fsinfo; |
1485 | int error; | 1489 | int error; |
1486 | 1490 | ||
1487 | dprintk("--> nfs_clone_server(,%llx:%llx,)\n", | 1491 | dprintk("--> nfs_clone_server(,%llx:%llx,)\n", |
@@ -1492,6 +1496,11 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source, | |||
1492 | if (!server) | 1496 | if (!server) |
1493 | return ERR_PTR(-ENOMEM); | 1497 | return ERR_PTR(-ENOMEM); |
1494 | 1498 | ||
1499 | error = -ENOMEM; | ||
1500 | fattr_fsinfo = nfs_alloc_fattr(); | ||
1501 | if (fattr_fsinfo == NULL) | ||
1502 | goto out_free_server; | ||
1503 | |||
1495 | /* Copy data from the source */ | 1504 | /* Copy data from the source */ |
1496 | server->nfs_client = source->nfs_client; | 1505 | server->nfs_client = source->nfs_client; |
1497 | atomic_inc(&server->nfs_client->cl_count); | 1506 | atomic_inc(&server->nfs_client->cl_count); |
@@ -1508,7 +1517,7 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source, | |||
1508 | nfs_init_server_aclclient(server); | 1517 | nfs_init_server_aclclient(server); |
1509 | 1518 | ||
1510 | /* probe the filesystem info for this server filesystem */ | 1519 | /* probe the filesystem info for this server filesystem */ |
1511 | error = nfs_probe_fsinfo(server, fh, &fattr_fsinfo); | 1520 | error = nfs_probe_fsinfo(server, fh, fattr_fsinfo); |
1512 | if (error < 0) | 1521 | if (error < 0) |
1513 | goto out_free_server; | 1522 | goto out_free_server; |
1514 | 1523 | ||
@@ -1530,10 +1539,12 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source, | |||
1530 | 1539 | ||
1531 | server->mount_time = jiffies; | 1540 | server->mount_time = jiffies; |
1532 | 1541 | ||
1542 | nfs_free_fattr(fattr_fsinfo); | ||
1533 | dprintk("<-- nfs_clone_server() = %p\n", server); | 1543 | dprintk("<-- nfs_clone_server() = %p\n", server); |
1534 | return server; | 1544 | return server; |
1535 | 1545 | ||
1536 | out_free_server: | 1546 | out_free_server: |
1547 | nfs_free_fattr(fattr_fsinfo); | ||
1537 | nfs_free_server(server); | 1548 | nfs_free_server(server); |
1538 | dprintk("<-- nfs_clone_server() = error %d\n", error); | 1549 | dprintk("<-- nfs_clone_server() = error %d\n", error); |
1539 | return ERR_PTR(error); | 1550 | return ERR_PTR(error); |
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 2563bebc4c67..301634543974 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/kthread.h> | 10 | #include <linux/kthread.h> |
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/sched.h> | 12 | #include <linux/sched.h> |
13 | #include <linux/slab.h> | ||
13 | #include <linux/smp_lock.h> | 14 | #include <linux/smp_lock.h> |
14 | #include <linux/spinlock.h> | 15 | #include <linux/spinlock.h> |
15 | 16 | ||
@@ -23,6 +24,8 @@ | |||
23 | 24 | ||
24 | static void nfs_do_free_delegation(struct nfs_delegation *delegation) | 25 | static void nfs_do_free_delegation(struct nfs_delegation *delegation) |
25 | { | 26 | { |
27 | if (delegation->cred) | ||
28 | put_rpccred(delegation->cred); | ||
26 | kfree(delegation); | 29 | kfree(delegation); |
27 | } | 30 | } |
28 | 31 | ||
@@ -35,13 +38,7 @@ static void nfs_free_delegation_callback(struct rcu_head *head) | |||
35 | 38 | ||
36 | static void nfs_free_delegation(struct nfs_delegation *delegation) | 39 | static void nfs_free_delegation(struct nfs_delegation *delegation) |
37 | { | 40 | { |
38 | struct rpc_cred *cred; | ||
39 | |||
40 | cred = rcu_dereference(delegation->cred); | ||
41 | rcu_assign_pointer(delegation->cred, NULL); | ||
42 | call_rcu(&delegation->rcu, nfs_free_delegation_callback); | 41 | call_rcu(&delegation->rcu, nfs_free_delegation_callback); |
43 | if (cred) | ||
44 | put_rpccred(cred); | ||
45 | } | 42 | } |
46 | 43 | ||
47 | void nfs_mark_delegation_referenced(struct nfs_delegation *delegation) | 44 | void nfs_mark_delegation_referenced(struct nfs_delegation *delegation) |
@@ -128,21 +125,35 @@ again: | |||
128 | */ | 125 | */ |
129 | void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res) | 126 | void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res) |
130 | { | 127 | { |
131 | struct nfs_delegation *delegation = NFS_I(inode)->delegation; | 128 | struct nfs_delegation *delegation; |
132 | struct rpc_cred *oldcred; | 129 | struct rpc_cred *oldcred = NULL; |
133 | 130 | ||
134 | if (delegation == NULL) | 131 | rcu_read_lock(); |
135 | return; | 132 | delegation = rcu_dereference(NFS_I(inode)->delegation); |
136 | memcpy(delegation->stateid.data, res->delegation.data, | 133 | if (delegation != NULL) { |
137 | sizeof(delegation->stateid.data)); | 134 | spin_lock(&delegation->lock); |
138 | delegation->type = res->delegation_type; | 135 | if (delegation->inode != NULL) { |
139 | delegation->maxsize = res->maxsize; | 136 | memcpy(delegation->stateid.data, res->delegation.data, |
140 | oldcred = delegation->cred; | 137 | sizeof(delegation->stateid.data)); |
141 | delegation->cred = get_rpccred(cred); | 138 | delegation->type = res->delegation_type; |
142 | clear_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags); | 139 | delegation->maxsize = res->maxsize; |
143 | NFS_I(inode)->delegation_state = delegation->type; | 140 | oldcred = delegation->cred; |
144 | smp_wmb(); | 141 | delegation->cred = get_rpccred(cred); |
145 | put_rpccred(oldcred); | 142 | clear_bit(NFS_DELEGATION_NEED_RECLAIM, |
143 | &delegation->flags); | ||
144 | NFS_I(inode)->delegation_state = delegation->type; | ||
145 | spin_unlock(&delegation->lock); | ||
146 | put_rpccred(oldcred); | ||
147 | rcu_read_unlock(); | ||
148 | } else { | ||
149 | /* We appear to have raced with a delegation return. */ | ||
150 | spin_unlock(&delegation->lock); | ||
151 | rcu_read_unlock(); | ||
152 | nfs_inode_set_delegation(inode, cred, res); | ||
153 | } | ||
154 | } else { | ||
155 | rcu_read_unlock(); | ||
156 | } | ||
146 | } | 157 | } |
147 | 158 | ||
148 | static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *delegation, int issync) | 159 | static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *delegation, int issync) |
@@ -165,9 +176,13 @@ static struct inode *nfs_delegation_grab_inode(struct nfs_delegation *delegation | |||
165 | return inode; | 176 | return inode; |
166 | } | 177 | } |
167 | 178 | ||
168 | static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfsi, const nfs4_stateid *stateid) | 179 | static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfsi, |
180 | const nfs4_stateid *stateid, | ||
181 | struct nfs_client *clp) | ||
169 | { | 182 | { |
170 | struct nfs_delegation *delegation = rcu_dereference(nfsi->delegation); | 183 | struct nfs_delegation *delegation = |
184 | rcu_dereference_protected(nfsi->delegation, | ||
185 | lockdep_is_held(&clp->cl_lock)); | ||
171 | 186 | ||
172 | if (delegation == NULL) | 187 | if (delegation == NULL) |
173 | goto nomatch; | 188 | goto nomatch; |
@@ -194,11 +209,11 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct | |||
194 | { | 209 | { |
195 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; | 210 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; |
196 | struct nfs_inode *nfsi = NFS_I(inode); | 211 | struct nfs_inode *nfsi = NFS_I(inode); |
197 | struct nfs_delegation *delegation; | 212 | struct nfs_delegation *delegation, *old_delegation; |
198 | struct nfs_delegation *freeme = NULL; | 213 | struct nfs_delegation *freeme = NULL; |
199 | int status = 0; | 214 | int status = 0; |
200 | 215 | ||
201 | delegation = kmalloc(sizeof(*delegation), GFP_KERNEL); | 216 | delegation = kmalloc(sizeof(*delegation), GFP_NOFS); |
202 | if (delegation == NULL) | 217 | if (delegation == NULL) |
203 | return -ENOMEM; | 218 | return -ENOMEM; |
204 | memcpy(delegation->stateid.data, res->delegation.data, | 219 | memcpy(delegation->stateid.data, res->delegation.data, |
@@ -212,10 +227,12 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct | |||
212 | spin_lock_init(&delegation->lock); | 227 | spin_lock_init(&delegation->lock); |
213 | 228 | ||
214 | spin_lock(&clp->cl_lock); | 229 | spin_lock(&clp->cl_lock); |
215 | if (rcu_dereference(nfsi->delegation) != NULL) { | 230 | old_delegation = rcu_dereference_protected(nfsi->delegation, |
216 | if (memcmp(&delegation->stateid, &nfsi->delegation->stateid, | 231 | lockdep_is_held(&clp->cl_lock)); |
217 | sizeof(delegation->stateid)) == 0 && | 232 | if (old_delegation != NULL) { |
218 | delegation->type == nfsi->delegation->type) { | 233 | if (memcmp(&delegation->stateid, &old_delegation->stateid, |
234 | sizeof(old_delegation->stateid)) == 0 && | ||
235 | delegation->type == old_delegation->type) { | ||
219 | goto out; | 236 | goto out; |
220 | } | 237 | } |
221 | /* | 238 | /* |
@@ -225,12 +242,12 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct | |||
225 | dfprintk(FILE, "%s: server %s handed out " | 242 | dfprintk(FILE, "%s: server %s handed out " |
226 | "a duplicate delegation!\n", | 243 | "a duplicate delegation!\n", |
227 | __func__, clp->cl_hostname); | 244 | __func__, clp->cl_hostname); |
228 | if (delegation->type <= nfsi->delegation->type) { | 245 | if (delegation->type <= old_delegation->type) { |
229 | freeme = delegation; | 246 | freeme = delegation; |
230 | delegation = NULL; | 247 | delegation = NULL; |
231 | goto out; | 248 | goto out; |
232 | } | 249 | } |
233 | freeme = nfs_detach_delegation_locked(nfsi, NULL); | 250 | freeme = nfs_detach_delegation_locked(nfsi, NULL, clp); |
234 | } | 251 | } |
235 | list_add_rcu(&delegation->super_list, &clp->cl_delegations); | 252 | list_add_rcu(&delegation->super_list, &clp->cl_delegations); |
236 | nfsi->delegation_state = delegation->type; | 253 | nfsi->delegation_state = delegation->type; |
@@ -300,7 +317,7 @@ restart: | |||
300 | if (inode == NULL) | 317 | if (inode == NULL) |
301 | continue; | 318 | continue; |
302 | spin_lock(&clp->cl_lock); | 319 | spin_lock(&clp->cl_lock); |
303 | delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL); | 320 | delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL, clp); |
304 | spin_unlock(&clp->cl_lock); | 321 | spin_unlock(&clp->cl_lock); |
305 | rcu_read_unlock(); | 322 | rcu_read_unlock(); |
306 | if (delegation != NULL) { | 323 | if (delegation != NULL) { |
@@ -329,9 +346,9 @@ void nfs_inode_return_delegation_noreclaim(struct inode *inode) | |||
329 | struct nfs_inode *nfsi = NFS_I(inode); | 346 | struct nfs_inode *nfsi = NFS_I(inode); |
330 | struct nfs_delegation *delegation; | 347 | struct nfs_delegation *delegation; |
331 | 348 | ||
332 | if (rcu_dereference(nfsi->delegation) != NULL) { | 349 | if (rcu_access_pointer(nfsi->delegation) != NULL) { |
333 | spin_lock(&clp->cl_lock); | 350 | spin_lock(&clp->cl_lock); |
334 | delegation = nfs_detach_delegation_locked(nfsi, NULL); | 351 | delegation = nfs_detach_delegation_locked(nfsi, NULL, clp); |
335 | spin_unlock(&clp->cl_lock); | 352 | spin_unlock(&clp->cl_lock); |
336 | if (delegation != NULL) | 353 | if (delegation != NULL) |
337 | nfs_do_return_delegation(inode, delegation, 0); | 354 | nfs_do_return_delegation(inode, delegation, 0); |
@@ -345,9 +362,9 @@ int nfs_inode_return_delegation(struct inode *inode) | |||
345 | struct nfs_delegation *delegation; | 362 | struct nfs_delegation *delegation; |
346 | int err = 0; | 363 | int err = 0; |
347 | 364 | ||
348 | if (rcu_dereference(nfsi->delegation) != NULL) { | 365 | if (rcu_access_pointer(nfsi->delegation) != NULL) { |
349 | spin_lock(&clp->cl_lock); | 366 | spin_lock(&clp->cl_lock); |
350 | delegation = nfs_detach_delegation_locked(nfsi, NULL); | 367 | delegation = nfs_detach_delegation_locked(nfsi, NULL, clp); |
351 | spin_unlock(&clp->cl_lock); | 368 | spin_unlock(&clp->cl_lock); |
352 | if (delegation != NULL) { | 369 | if (delegation != NULL) { |
353 | nfs_msync_inode(inode); | 370 | nfs_msync_inode(inode); |
@@ -525,7 +542,7 @@ restart: | |||
525 | if (inode == NULL) | 542 | if (inode == NULL) |
526 | continue; | 543 | continue; |
527 | spin_lock(&clp->cl_lock); | 544 | spin_lock(&clp->cl_lock); |
528 | delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL); | 545 | delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL, clp); |
529 | spin_unlock(&clp->cl_lock); | 546 | spin_unlock(&clp->cl_lock); |
530 | rcu_read_unlock(); | 547 | rcu_read_unlock(); |
531 | if (delegation != NULL) | 548 | if (delegation != NULL) |
diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h index 944b627ec6e1..69e7b8140122 100644 --- a/fs/nfs/delegation.h +++ b/fs/nfs/delegation.h | |||
@@ -71,4 +71,10 @@ static inline int nfs_inode_return_delegation(struct inode *inode) | |||
71 | } | 71 | } |
72 | #endif | 72 | #endif |
73 | 73 | ||
74 | static inline int nfs_have_delegated_attributes(struct inode *inode) | ||
75 | { | ||
76 | return nfs_have_delegation(inode, FMODE_READ) && | ||
77 | !(NFS_I(inode)->cache_validity & NFS_INO_REVAL_FORCED); | ||
78 | } | ||
79 | |||
74 | #endif | 80 | #endif |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 3c7f03b669fb..e60416d3f818 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -53,7 +53,7 @@ static int nfs_link(struct dentry *, struct inode *, struct dentry *); | |||
53 | static int nfs_mknod(struct inode *, struct dentry *, int, dev_t); | 53 | static int nfs_mknod(struct inode *, struct dentry *, int, dev_t); |
54 | static int nfs_rename(struct inode *, struct dentry *, | 54 | static int nfs_rename(struct inode *, struct dentry *, |
55 | struct inode *, struct dentry *); | 55 | struct inode *, struct dentry *); |
56 | static int nfs_fsync_dir(struct file *, struct dentry *, int); | 56 | static int nfs_fsync_dir(struct file *, int); |
57 | static loff_t nfs_llseek_dir(struct file *, loff_t, int); | 57 | static loff_t nfs_llseek_dir(struct file *, loff_t, int); |
58 | 58 | ||
59 | const struct file_operations nfs_dir_operations = { | 59 | const struct file_operations nfs_dir_operations = { |
@@ -530,9 +530,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
530 | nfs_readdir_descriptor_t my_desc, | 530 | nfs_readdir_descriptor_t my_desc, |
531 | *desc = &my_desc; | 531 | *desc = &my_desc; |
532 | struct nfs_entry my_entry; | 532 | struct nfs_entry my_entry; |
533 | struct nfs_fh fh; | 533 | int res = -ENOMEM; |
534 | struct nfs_fattr fattr; | ||
535 | long res; | ||
536 | 534 | ||
537 | dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n", | 535 | dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n", |
538 | dentry->d_parent->d_name.name, dentry->d_name.name, | 536 | dentry->d_parent->d_name.name, dentry->d_name.name, |
@@ -554,13 +552,15 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
554 | 552 | ||
555 | my_entry.cookie = my_entry.prev_cookie = 0; | 553 | my_entry.cookie = my_entry.prev_cookie = 0; |
556 | my_entry.eof = 0; | 554 | my_entry.eof = 0; |
557 | my_entry.fh = &fh; | 555 | my_entry.fh = nfs_alloc_fhandle(); |
558 | my_entry.fattr = &fattr; | 556 | my_entry.fattr = nfs_alloc_fattr(); |
559 | nfs_fattr_init(&fattr); | 557 | if (my_entry.fh == NULL || my_entry.fattr == NULL) |
558 | goto out_alloc_failed; | ||
559 | |||
560 | desc->entry = &my_entry; | 560 | desc->entry = &my_entry; |
561 | 561 | ||
562 | nfs_block_sillyrename(dentry); | 562 | nfs_block_sillyrename(dentry); |
563 | res = nfs_revalidate_mapping_nolock(inode, filp->f_mapping); | 563 | res = nfs_revalidate_mapping(inode, filp->f_mapping); |
564 | if (res < 0) | 564 | if (res < 0) |
565 | goto out; | 565 | goto out; |
566 | 566 | ||
@@ -598,7 +598,10 @@ out: | |||
598 | nfs_unblock_sillyrename(dentry); | 598 | nfs_unblock_sillyrename(dentry); |
599 | if (res > 0) | 599 | if (res > 0) |
600 | res = 0; | 600 | res = 0; |
601 | dfprintk(FILE, "NFS: readdir(%s/%s) returns %ld\n", | 601 | out_alloc_failed: |
602 | nfs_free_fattr(my_entry.fattr); | ||
603 | nfs_free_fhandle(my_entry.fh); | ||
604 | dfprintk(FILE, "NFS: readdir(%s/%s) returns %d\n", | ||
602 | dentry->d_parent->d_name.name, dentry->d_name.name, | 605 | dentry->d_parent->d_name.name, dentry->d_name.name, |
603 | res); | 606 | res); |
604 | return res; | 607 | return res; |
@@ -638,8 +641,10 @@ out: | |||
638 | * All directory operations under NFS are synchronous, so fsync() | 641 | * All directory operations under NFS are synchronous, so fsync() |
639 | * is a dummy operation. | 642 | * is a dummy operation. |
640 | */ | 643 | */ |
641 | static int nfs_fsync_dir(struct file *filp, struct dentry *dentry, int datasync) | 644 | static int nfs_fsync_dir(struct file *filp, int datasync) |
642 | { | 645 | { |
646 | struct dentry *dentry = filp->f_path.dentry; | ||
647 | |||
643 | dfprintk(FILE, "NFS: fsync dir(%s/%s) datasync %d\n", | 648 | dfprintk(FILE, "NFS: fsync dir(%s/%s) datasync %d\n", |
644 | dentry->d_parent->d_name.name, dentry->d_name.name, | 649 | dentry->d_parent->d_name.name, dentry->d_name.name, |
645 | datasync); | 650 | datasync); |
@@ -776,9 +781,9 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) | |||
776 | struct inode *dir; | 781 | struct inode *dir; |
777 | struct inode *inode; | 782 | struct inode *inode; |
778 | struct dentry *parent; | 783 | struct dentry *parent; |
784 | struct nfs_fh *fhandle = NULL; | ||
785 | struct nfs_fattr *fattr = NULL; | ||
779 | int error; | 786 | int error; |
780 | struct nfs_fh fhandle; | ||
781 | struct nfs_fattr fattr; | ||
782 | 787 | ||
783 | parent = dget_parent(dentry); | 788 | parent = dget_parent(dentry); |
784 | dir = parent->d_inode; | 789 | dir = parent->d_inode; |
@@ -811,14 +816,22 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) | |||
811 | if (NFS_STALE(inode)) | 816 | if (NFS_STALE(inode)) |
812 | goto out_bad; | 817 | goto out_bad; |
813 | 818 | ||
814 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr); | 819 | error = -ENOMEM; |
820 | fhandle = nfs_alloc_fhandle(); | ||
821 | fattr = nfs_alloc_fattr(); | ||
822 | if (fhandle == NULL || fattr == NULL) | ||
823 | goto out_error; | ||
824 | |||
825 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); | ||
815 | if (error) | 826 | if (error) |
816 | goto out_bad; | 827 | goto out_bad; |
817 | if (nfs_compare_fh(NFS_FH(inode), &fhandle)) | 828 | if (nfs_compare_fh(NFS_FH(inode), fhandle)) |
818 | goto out_bad; | 829 | goto out_bad; |
819 | if ((error = nfs_refresh_inode(inode, &fattr)) != 0) | 830 | if ((error = nfs_refresh_inode(inode, fattr)) != 0) |
820 | goto out_bad; | 831 | goto out_bad; |
821 | 832 | ||
833 | nfs_free_fattr(fattr); | ||
834 | nfs_free_fhandle(fhandle); | ||
822 | out_set_verifier: | 835 | out_set_verifier: |
823 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | 836 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); |
824 | out_valid: | 837 | out_valid: |
@@ -837,14 +850,26 @@ out_zap_parent: | |||
837 | /* If we have submounts, don't unhash ! */ | 850 | /* If we have submounts, don't unhash ! */ |
838 | if (have_submounts(dentry)) | 851 | if (have_submounts(dentry)) |
839 | goto out_valid; | 852 | goto out_valid; |
853 | if (dentry->d_flags & DCACHE_DISCONNECTED) | ||
854 | goto out_valid; | ||
840 | shrink_dcache_parent(dentry); | 855 | shrink_dcache_parent(dentry); |
841 | } | 856 | } |
842 | d_drop(dentry); | 857 | d_drop(dentry); |
858 | nfs_free_fattr(fattr); | ||
859 | nfs_free_fhandle(fhandle); | ||
843 | dput(parent); | 860 | dput(parent); |
844 | dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is invalid\n", | 861 | dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is invalid\n", |
845 | __func__, dentry->d_parent->d_name.name, | 862 | __func__, dentry->d_parent->d_name.name, |
846 | dentry->d_name.name); | 863 | dentry->d_name.name); |
847 | return 0; | 864 | return 0; |
865 | out_error: | ||
866 | nfs_free_fattr(fattr); | ||
867 | nfs_free_fhandle(fhandle); | ||
868 | dput(parent); | ||
869 | dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) lookup returned error %d\n", | ||
870 | __func__, dentry->d_parent->d_name.name, | ||
871 | dentry->d_name.name, error); | ||
872 | return error; | ||
848 | } | 873 | } |
849 | 874 | ||
850 | /* | 875 | /* |
@@ -909,9 +934,9 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru | |||
909 | struct dentry *res; | 934 | struct dentry *res; |
910 | struct dentry *parent; | 935 | struct dentry *parent; |
911 | struct inode *inode = NULL; | 936 | struct inode *inode = NULL; |
937 | struct nfs_fh *fhandle = NULL; | ||
938 | struct nfs_fattr *fattr = NULL; | ||
912 | int error; | 939 | int error; |
913 | struct nfs_fh fhandle; | ||
914 | struct nfs_fattr fattr; | ||
915 | 940 | ||
916 | dfprintk(VFS, "NFS: lookup(%s/%s)\n", | 941 | dfprintk(VFS, "NFS: lookup(%s/%s)\n", |
917 | dentry->d_parent->d_name.name, dentry->d_name.name); | 942 | dentry->d_parent->d_name.name, dentry->d_name.name); |
@@ -921,7 +946,6 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru | |||
921 | if (dentry->d_name.len > NFS_SERVER(dir)->namelen) | 946 | if (dentry->d_name.len > NFS_SERVER(dir)->namelen) |
922 | goto out; | 947 | goto out; |
923 | 948 | ||
924 | res = ERR_PTR(-ENOMEM); | ||
925 | dentry->d_op = NFS_PROTO(dir)->dentry_ops; | 949 | dentry->d_op = NFS_PROTO(dir)->dentry_ops; |
926 | 950 | ||
927 | /* | 951 | /* |
@@ -934,17 +958,23 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru | |||
934 | goto out; | 958 | goto out; |
935 | } | 959 | } |
936 | 960 | ||
961 | res = ERR_PTR(-ENOMEM); | ||
962 | fhandle = nfs_alloc_fhandle(); | ||
963 | fattr = nfs_alloc_fattr(); | ||
964 | if (fhandle == NULL || fattr == NULL) | ||
965 | goto out; | ||
966 | |||
937 | parent = dentry->d_parent; | 967 | parent = dentry->d_parent; |
938 | /* Protect against concurrent sillydeletes */ | 968 | /* Protect against concurrent sillydeletes */ |
939 | nfs_block_sillyrename(parent); | 969 | nfs_block_sillyrename(parent); |
940 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr); | 970 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); |
941 | if (error == -ENOENT) | 971 | if (error == -ENOENT) |
942 | goto no_entry; | 972 | goto no_entry; |
943 | if (error < 0) { | 973 | if (error < 0) { |
944 | res = ERR_PTR(error); | 974 | res = ERR_PTR(error); |
945 | goto out_unblock_sillyrename; | 975 | goto out_unblock_sillyrename; |
946 | } | 976 | } |
947 | inode = nfs_fhget(dentry->d_sb, &fhandle, &fattr); | 977 | inode = nfs_fhget(dentry->d_sb, fhandle, fattr); |
948 | res = (struct dentry *)inode; | 978 | res = (struct dentry *)inode; |
949 | if (IS_ERR(res)) | 979 | if (IS_ERR(res)) |
950 | goto out_unblock_sillyrename; | 980 | goto out_unblock_sillyrename; |
@@ -960,6 +990,8 @@ no_entry: | |||
960 | out_unblock_sillyrename: | 990 | out_unblock_sillyrename: |
961 | nfs_unblock_sillyrename(parent); | 991 | nfs_unblock_sillyrename(parent); |
962 | out: | 992 | out: |
993 | nfs_free_fattr(fattr); | ||
994 | nfs_free_fhandle(fhandle); | ||
963 | return res; | 995 | return res; |
964 | } | 996 | } |
965 | 997 | ||
@@ -1025,12 +1057,12 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry | |||
1025 | res = NULL; | 1057 | res = NULL; |
1026 | goto out; | 1058 | goto out; |
1027 | /* This turned out not to be a regular file */ | 1059 | /* This turned out not to be a regular file */ |
1060 | case -EISDIR: | ||
1028 | case -ENOTDIR: | 1061 | case -ENOTDIR: |
1029 | goto no_open; | 1062 | goto no_open; |
1030 | case -ELOOP: | 1063 | case -ELOOP: |
1031 | if (!(nd->intent.open.flags & O_NOFOLLOW)) | 1064 | if (!(nd->intent.open.flags & O_NOFOLLOW)) |
1032 | goto no_open; | 1065 | goto no_open; |
1033 | /* case -EISDIR: */ | ||
1034 | /* case -EINVAL: */ | 1066 | /* case -EINVAL: */ |
1035 | default: | 1067 | default: |
1036 | goto out; | 1068 | goto out; |
@@ -1050,7 +1082,7 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
1050 | struct inode *dir; | 1082 | struct inode *dir; |
1051 | int openflags, ret = 0; | 1083 | int openflags, ret = 0; |
1052 | 1084 | ||
1053 | if (!is_atomic_open(nd)) | 1085 | if (!is_atomic_open(nd) || d_mountpoint(dentry)) |
1054 | goto no_open; | 1086 | goto no_open; |
1055 | parent = dget_parent(dentry); | 1087 | parent = dget_parent(dentry); |
1056 | dir = parent->d_inode; | 1088 | dir = parent->d_inode; |
@@ -1667,28 +1699,33 @@ static void nfs_access_free_entry(struct nfs_access_entry *entry) | |||
1667 | smp_mb__after_atomic_dec(); | 1699 | smp_mb__after_atomic_dec(); |
1668 | } | 1700 | } |
1669 | 1701 | ||
1670 | int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask) | 1702 | static void nfs_access_free_list(struct list_head *head) |
1703 | { | ||
1704 | struct nfs_access_entry *cache; | ||
1705 | |||
1706 | while (!list_empty(head)) { | ||
1707 | cache = list_entry(head->next, struct nfs_access_entry, lru); | ||
1708 | list_del(&cache->lru); | ||
1709 | nfs_access_free_entry(cache); | ||
1710 | } | ||
1711 | } | ||
1712 | |||
1713 | int nfs_access_cache_shrinker(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask) | ||
1671 | { | 1714 | { |
1672 | LIST_HEAD(head); | 1715 | LIST_HEAD(head); |
1673 | struct nfs_inode *nfsi; | 1716 | struct nfs_inode *nfsi; |
1674 | struct nfs_access_entry *cache; | 1717 | struct nfs_access_entry *cache; |
1675 | 1718 | ||
1676 | restart: | 1719 | if ((gfp_mask & GFP_KERNEL) != GFP_KERNEL) |
1720 | return (nr_to_scan == 0) ? 0 : -1; | ||
1721 | |||
1677 | spin_lock(&nfs_access_lru_lock); | 1722 | spin_lock(&nfs_access_lru_lock); |
1678 | list_for_each_entry(nfsi, &nfs_access_lru_list, access_cache_inode_lru) { | 1723 | list_for_each_entry(nfsi, &nfs_access_lru_list, access_cache_inode_lru) { |
1679 | struct rw_semaphore *s_umount; | ||
1680 | struct inode *inode; | 1724 | struct inode *inode; |
1681 | 1725 | ||
1682 | if (nr_to_scan-- == 0) | 1726 | if (nr_to_scan-- == 0) |
1683 | break; | 1727 | break; |
1684 | s_umount = &nfsi->vfs_inode.i_sb->s_umount; | 1728 | inode = &nfsi->vfs_inode; |
1685 | if (!down_read_trylock(s_umount)) | ||
1686 | continue; | ||
1687 | inode = igrab(&nfsi->vfs_inode); | ||
1688 | if (inode == NULL) { | ||
1689 | up_read(s_umount); | ||
1690 | continue; | ||
1691 | } | ||
1692 | spin_lock(&inode->i_lock); | 1729 | spin_lock(&inode->i_lock); |
1693 | if (list_empty(&nfsi->access_cache_entry_lru)) | 1730 | if (list_empty(&nfsi->access_cache_entry_lru)) |
1694 | goto remove_lru_entry; | 1731 | goto remove_lru_entry; |
@@ -1702,61 +1739,48 @@ restart: | |||
1702 | else { | 1739 | else { |
1703 | remove_lru_entry: | 1740 | remove_lru_entry: |
1704 | list_del_init(&nfsi->access_cache_inode_lru); | 1741 | list_del_init(&nfsi->access_cache_inode_lru); |
1742 | smp_mb__before_clear_bit(); | ||
1705 | clear_bit(NFS_INO_ACL_LRU_SET, &nfsi->flags); | 1743 | clear_bit(NFS_INO_ACL_LRU_SET, &nfsi->flags); |
1744 | smp_mb__after_clear_bit(); | ||
1706 | } | 1745 | } |
1707 | spin_unlock(&inode->i_lock); | 1746 | spin_unlock(&inode->i_lock); |
1708 | spin_unlock(&nfs_access_lru_lock); | ||
1709 | iput(inode); | ||
1710 | up_read(s_umount); | ||
1711 | goto restart; | ||
1712 | } | 1747 | } |
1713 | spin_unlock(&nfs_access_lru_lock); | 1748 | spin_unlock(&nfs_access_lru_lock); |
1714 | while (!list_empty(&head)) { | 1749 | nfs_access_free_list(&head); |
1715 | cache = list_entry(head.next, struct nfs_access_entry, lru); | ||
1716 | list_del(&cache->lru); | ||
1717 | nfs_access_free_entry(cache); | ||
1718 | } | ||
1719 | return (atomic_long_read(&nfs_access_nr_entries) / 100) * sysctl_vfs_cache_pressure; | 1750 | return (atomic_long_read(&nfs_access_nr_entries) / 100) * sysctl_vfs_cache_pressure; |
1720 | } | 1751 | } |
1721 | 1752 | ||
1722 | static void __nfs_access_zap_cache(struct inode *inode) | 1753 | static void __nfs_access_zap_cache(struct nfs_inode *nfsi, struct list_head *head) |
1723 | { | 1754 | { |
1724 | struct nfs_inode *nfsi = NFS_I(inode); | ||
1725 | struct rb_root *root_node = &nfsi->access_cache; | 1755 | struct rb_root *root_node = &nfsi->access_cache; |
1726 | struct rb_node *n, *dispose = NULL; | 1756 | struct rb_node *n; |
1727 | struct nfs_access_entry *entry; | 1757 | struct nfs_access_entry *entry; |
1728 | 1758 | ||
1729 | /* Unhook entries from the cache */ | 1759 | /* Unhook entries from the cache */ |
1730 | while ((n = rb_first(root_node)) != NULL) { | 1760 | while ((n = rb_first(root_node)) != NULL) { |
1731 | entry = rb_entry(n, struct nfs_access_entry, rb_node); | 1761 | entry = rb_entry(n, struct nfs_access_entry, rb_node); |
1732 | rb_erase(n, root_node); | 1762 | rb_erase(n, root_node); |
1733 | list_del(&entry->lru); | 1763 | list_move(&entry->lru, head); |
1734 | n->rb_left = dispose; | ||
1735 | dispose = n; | ||
1736 | } | 1764 | } |
1737 | nfsi->cache_validity &= ~NFS_INO_INVALID_ACCESS; | 1765 | nfsi->cache_validity &= ~NFS_INO_INVALID_ACCESS; |
1738 | spin_unlock(&inode->i_lock); | ||
1739 | |||
1740 | /* Now kill them all! */ | ||
1741 | while (dispose != NULL) { | ||
1742 | n = dispose; | ||
1743 | dispose = n->rb_left; | ||
1744 | nfs_access_free_entry(rb_entry(n, struct nfs_access_entry, rb_node)); | ||
1745 | } | ||
1746 | } | 1766 | } |
1747 | 1767 | ||
1748 | void nfs_access_zap_cache(struct inode *inode) | 1768 | void nfs_access_zap_cache(struct inode *inode) |
1749 | { | 1769 | { |
1770 | LIST_HEAD(head); | ||
1771 | |||
1772 | if (test_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags) == 0) | ||
1773 | return; | ||
1750 | /* Remove from global LRU init */ | 1774 | /* Remove from global LRU init */ |
1751 | if (test_and_clear_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags)) { | 1775 | spin_lock(&nfs_access_lru_lock); |
1752 | spin_lock(&nfs_access_lru_lock); | 1776 | if (test_and_clear_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags)) |
1753 | list_del_init(&NFS_I(inode)->access_cache_inode_lru); | 1777 | list_del_init(&NFS_I(inode)->access_cache_inode_lru); |
1754 | spin_unlock(&nfs_access_lru_lock); | ||
1755 | } | ||
1756 | 1778 | ||
1757 | spin_lock(&inode->i_lock); | 1779 | spin_lock(&inode->i_lock); |
1758 | /* This will release the spinlock */ | 1780 | __nfs_access_zap_cache(NFS_I(inode), &head); |
1759 | __nfs_access_zap_cache(inode); | 1781 | spin_unlock(&inode->i_lock); |
1782 | spin_unlock(&nfs_access_lru_lock); | ||
1783 | nfs_access_free_list(&head); | ||
1760 | } | 1784 | } |
1761 | 1785 | ||
1762 | static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, struct rpc_cred *cred) | 1786 | static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, struct rpc_cred *cred) |
@@ -1789,7 +1813,7 @@ static int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, str | |||
1789 | cache = nfs_access_search_rbtree(inode, cred); | 1813 | cache = nfs_access_search_rbtree(inode, cred); |
1790 | if (cache == NULL) | 1814 | if (cache == NULL) |
1791 | goto out; | 1815 | goto out; |
1792 | if (!nfs_have_delegation(inode, FMODE_READ) && | 1816 | if (!nfs_have_delegated_attributes(inode) && |
1793 | !time_in_range_open(jiffies, cache->jiffies, cache->jiffies + nfsi->attrtimeo)) | 1817 | !time_in_range_open(jiffies, cache->jiffies, cache->jiffies + nfsi->attrtimeo)) |
1794 | goto out_stale; | 1818 | goto out_stale; |
1795 | res->jiffies = cache->jiffies; | 1819 | res->jiffies = cache->jiffies; |
@@ -1807,8 +1831,8 @@ out_stale: | |||
1807 | nfs_access_free_entry(cache); | 1831 | nfs_access_free_entry(cache); |
1808 | return -ENOENT; | 1832 | return -ENOENT; |
1809 | out_zap: | 1833 | out_zap: |
1810 | /* This will release the spinlock */ | 1834 | spin_unlock(&inode->i_lock); |
1811 | __nfs_access_zap_cache(inode); | 1835 | nfs_access_zap_cache(inode); |
1812 | return -ENOENT; | 1836 | return -ENOENT; |
1813 | } | 1837 | } |
1814 | 1838 | ||
@@ -1863,9 +1887,11 @@ static void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *s | |||
1863 | smp_mb__after_atomic_inc(); | 1887 | smp_mb__after_atomic_inc(); |
1864 | 1888 | ||
1865 | /* Add inode to global LRU list */ | 1889 | /* Add inode to global LRU list */ |
1866 | if (!test_and_set_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags)) { | 1890 | if (!test_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags)) { |
1867 | spin_lock(&nfs_access_lru_lock); | 1891 | spin_lock(&nfs_access_lru_lock); |
1868 | list_add_tail(&NFS_I(inode)->access_cache_inode_lru, &nfs_access_lru_list); | 1892 | if (!test_and_set_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags)) |
1893 | list_add_tail(&NFS_I(inode)->access_cache_inode_lru, | ||
1894 | &nfs_access_lru_list); | ||
1869 | spin_unlock(&nfs_access_lru_lock); | 1895 | spin_unlock(&nfs_access_lru_lock); |
1870 | } | 1896 | } |
1871 | } | 1897 | } |
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index e1d415e97849..ad4cd31d6050 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #include <linux/file.h> | 44 | #include <linux/file.h> |
45 | #include <linux/pagemap.h> | 45 | #include <linux/pagemap.h> |
46 | #include <linux/kref.h> | 46 | #include <linux/kref.h> |
47 | #include <linux/slab.h> | ||
47 | 48 | ||
48 | #include <linux/nfs_fs.h> | 49 | #include <linux/nfs_fs.h> |
49 | #include <linux/nfs_page.h> | 50 | #include <linux/nfs_page.h> |
@@ -342,6 +343,7 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq, | |||
342 | data->res.fattr = &data->fattr; | 343 | data->res.fattr = &data->fattr; |
343 | data->res.eof = 0; | 344 | data->res.eof = 0; |
344 | data->res.count = bytes; | 345 | data->res.count = bytes; |
346 | nfs_fattr_init(&data->fattr); | ||
345 | msg.rpc_argp = &data->args; | 347 | msg.rpc_argp = &data->args; |
346 | msg.rpc_resp = &data->res; | 348 | msg.rpc_resp = &data->res; |
347 | 349 | ||
@@ -575,6 +577,7 @@ static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) | |||
575 | data->res.count = 0; | 577 | data->res.count = 0; |
576 | data->res.fattr = &data->fattr; | 578 | data->res.fattr = &data->fattr; |
577 | data->res.verf = &data->verf; | 579 | data->res.verf = &data->verf; |
580 | nfs_fattr_init(&data->fattr); | ||
578 | 581 | ||
579 | NFS_PROTO(data->inode)->commit_setup(data, &msg); | 582 | NFS_PROTO(data->inode)->commit_setup(data, &msg); |
580 | 583 | ||
@@ -766,6 +769,7 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq, | |||
766 | data->res.fattr = &data->fattr; | 769 | data->res.fattr = &data->fattr; |
767 | data->res.count = bytes; | 770 | data->res.count = bytes; |
768 | data->res.verf = &data->verf; | 771 | data->res.verf = &data->verf; |
772 | nfs_fattr_init(&data->fattr); | ||
769 | 773 | ||
770 | task_setup_data.task = &data->task; | 774 | task_setup_data.task = &data->task; |
771 | task_setup_data.callback_data = data; | 775 | task_setup_data.callback_data = data; |
diff --git a/fs/nfs/dns_resolve.c b/fs/nfs/dns_resolve.c index 95e1ca765d47..76fd235d0024 100644 --- a/fs/nfs/dns_resolve.c +++ b/fs/nfs/dns_resolve.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <linux/hash.h> | 9 | #include <linux/hash.h> |
10 | #include <linux/string.h> | 10 | #include <linux/string.h> |
11 | #include <linux/kmod.h> | 11 | #include <linux/kmod.h> |
12 | #include <linux/slab.h> | ||
12 | #include <linux/module.h> | 13 | #include <linux/module.h> |
13 | #include <linux/socket.h> | 14 | #include <linux/socket.h> |
14 | #include <linux/seq_file.h> | 15 | #include <linux/seq_file.h> |
@@ -36,6 +37,19 @@ struct nfs_dns_ent { | |||
36 | }; | 37 | }; |
37 | 38 | ||
38 | 39 | ||
40 | static void nfs_dns_ent_update(struct cache_head *cnew, | ||
41 | struct cache_head *ckey) | ||
42 | { | ||
43 | struct nfs_dns_ent *new; | ||
44 | struct nfs_dns_ent *key; | ||
45 | |||
46 | new = container_of(cnew, struct nfs_dns_ent, h); | ||
47 | key = container_of(ckey, struct nfs_dns_ent, h); | ||
48 | |||
49 | memcpy(&new->addr, &key->addr, key->addrlen); | ||
50 | new->addrlen = key->addrlen; | ||
51 | } | ||
52 | |||
39 | static void nfs_dns_ent_init(struct cache_head *cnew, | 53 | static void nfs_dns_ent_init(struct cache_head *cnew, |
40 | struct cache_head *ckey) | 54 | struct cache_head *ckey) |
41 | { | 55 | { |
@@ -49,8 +63,7 @@ static void nfs_dns_ent_init(struct cache_head *cnew, | |||
49 | new->hostname = kstrndup(key->hostname, key->namelen, GFP_KERNEL); | 63 | new->hostname = kstrndup(key->hostname, key->namelen, GFP_KERNEL); |
50 | if (new->hostname) { | 64 | if (new->hostname) { |
51 | new->namelen = key->namelen; | 65 | new->namelen = key->namelen; |
52 | memcpy(&new->addr, &key->addr, key->addrlen); | 66 | nfs_dns_ent_update(cnew, ckey); |
53 | new->addrlen = key->addrlen; | ||
54 | } else { | 67 | } else { |
55 | new->namelen = 0; | 68 | new->namelen = 0; |
56 | new->addrlen = 0; | 69 | new->addrlen = 0; |
@@ -234,7 +247,7 @@ static struct cache_detail nfs_dns_resolve = { | |||
234 | .cache_show = nfs_dns_show, | 247 | .cache_show = nfs_dns_show, |
235 | .match = nfs_dns_match, | 248 | .match = nfs_dns_match, |
236 | .init = nfs_dns_ent_init, | 249 | .init = nfs_dns_ent_init, |
237 | .update = nfs_dns_ent_init, | 250 | .update = nfs_dns_ent_update, |
238 | .alloc = nfs_dns_ent_alloc, | 251 | .alloc = nfs_dns_ent_alloc, |
239 | }; | 252 | }; |
240 | 253 | ||
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 6b891328f332..f036153d9f50 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -24,9 +24,10 @@ | |||
24 | #include <linux/nfs_fs.h> | 24 | #include <linux/nfs_fs.h> |
25 | #include <linux/nfs_mount.h> | 25 | #include <linux/nfs_mount.h> |
26 | #include <linux/mm.h> | 26 | #include <linux/mm.h> |
27 | #include <linux/slab.h> | ||
28 | #include <linux/pagemap.h> | 27 | #include <linux/pagemap.h> |
29 | #include <linux/aio.h> | 28 | #include <linux/aio.h> |
29 | #include <linux/gfp.h> | ||
30 | #include <linux/swap.h> | ||
30 | 31 | ||
31 | #include <asm/uaccess.h> | 32 | #include <asm/uaccess.h> |
32 | #include <asm/system.h> | 33 | #include <asm/system.h> |
@@ -53,7 +54,7 @@ static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe, | |||
53 | static ssize_t nfs_file_write(struct kiocb *, const struct iovec *iov, | 54 | static ssize_t nfs_file_write(struct kiocb *, const struct iovec *iov, |
54 | unsigned long nr_segs, loff_t pos); | 55 | unsigned long nr_segs, loff_t pos); |
55 | static int nfs_file_flush(struct file *, fl_owner_t id); | 56 | static int nfs_file_flush(struct file *, fl_owner_t id); |
56 | static int nfs_file_fsync(struct file *, struct dentry *dentry, int datasync); | 57 | static int nfs_file_fsync(struct file *, int datasync); |
57 | static int nfs_check_flags(int flags); | 58 | static int nfs_check_flags(int flags); |
58 | static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl); | 59 | static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl); |
59 | static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl); | 60 | static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl); |
@@ -123,11 +124,11 @@ nfs_file_open(struct inode *inode, struct file *filp) | |||
123 | filp->f_path.dentry->d_parent->d_name.name, | 124 | filp->f_path.dentry->d_parent->d_name.name, |
124 | filp->f_path.dentry->d_name.name); | 125 | filp->f_path.dentry->d_name.name); |
125 | 126 | ||
127 | nfs_inc_stats(inode, NFSIOS_VFSOPEN); | ||
126 | res = nfs_check_flags(filp->f_flags); | 128 | res = nfs_check_flags(filp->f_flags); |
127 | if (res) | 129 | if (res) |
128 | return res; | 130 | return res; |
129 | 131 | ||
130 | nfs_inc_stats(inode, NFSIOS_VFSOPEN); | ||
131 | res = nfs_open(inode, filp); | 132 | res = nfs_open(inode, filp); |
132 | return res; | 133 | return res; |
133 | } | 134 | } |
@@ -161,14 +162,17 @@ static int nfs_revalidate_file_size(struct inode *inode, struct file *filp) | |||
161 | struct nfs_server *server = NFS_SERVER(inode); | 162 | struct nfs_server *server = NFS_SERVER(inode); |
162 | struct nfs_inode *nfsi = NFS_I(inode); | 163 | struct nfs_inode *nfsi = NFS_I(inode); |
163 | 164 | ||
164 | if (server->flags & NFS_MOUNT_NOAC) | 165 | if (nfs_have_delegated_attributes(inode)) |
165 | goto force_reval; | 166 | goto out_noreval; |
167 | |||
166 | if (filp->f_flags & O_DIRECT) | 168 | if (filp->f_flags & O_DIRECT) |
167 | goto force_reval; | 169 | goto force_reval; |
168 | if (nfsi->npages != 0) | 170 | if (nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE) |
169 | return 0; | 171 | goto force_reval; |
170 | if (!(nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE) && !nfs_attribute_timeout(inode)) | 172 | if (nfs_attribute_timeout(inode)) |
171 | return 0; | 173 | goto force_reval; |
174 | out_noreval: | ||
175 | return 0; | ||
172 | force_reval: | 176 | force_reval: |
173 | return __nfs_revalidate_inode(server, inode); | 177 | return __nfs_revalidate_inode(server, inode); |
174 | } | 178 | } |
@@ -237,9 +241,9 @@ nfs_file_flush(struct file *file, fl_owner_t id) | |||
237 | dentry->d_parent->d_name.name, | 241 | dentry->d_parent->d_name.name, |
238 | dentry->d_name.name); | 242 | dentry->d_name.name); |
239 | 243 | ||
244 | nfs_inc_stats(inode, NFSIOS_VFSFLUSH); | ||
240 | if ((file->f_mode & FMODE_WRITE) == 0) | 245 | if ((file->f_mode & FMODE_WRITE) == 0) |
241 | return 0; | 246 | return 0; |
242 | nfs_inc_stats(inode, NFSIOS_VFSFLUSH); | ||
243 | 247 | ||
244 | /* Flush writes to the server and return any errors */ | 248 | /* Flush writes to the server and return any errors */ |
245 | return nfs_do_fsync(ctx, inode); | 249 | return nfs_do_fsync(ctx, inode); |
@@ -262,9 +266,11 @@ nfs_file_read(struct kiocb *iocb, const struct iovec *iov, | |||
262 | (unsigned long) count, (unsigned long) pos); | 266 | (unsigned long) count, (unsigned long) pos); |
263 | 267 | ||
264 | result = nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping); | 268 | result = nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping); |
265 | nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, count); | 269 | if (!result) { |
266 | if (!result) | ||
267 | result = generic_file_aio_read(iocb, iov, nr_segs, pos); | 270 | result = generic_file_aio_read(iocb, iov, nr_segs, pos); |
271 | if (result > 0) | ||
272 | nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, result); | ||
273 | } | ||
268 | return result; | 274 | return result; |
269 | } | 275 | } |
270 | 276 | ||
@@ -282,8 +288,11 @@ nfs_file_splice_read(struct file *filp, loff_t *ppos, | |||
282 | (unsigned long) count, (unsigned long long) *ppos); | 288 | (unsigned long) count, (unsigned long long) *ppos); |
283 | 289 | ||
284 | res = nfs_revalidate_mapping(inode, filp->f_mapping); | 290 | res = nfs_revalidate_mapping(inode, filp->f_mapping); |
285 | if (!res) | 291 | if (!res) { |
286 | res = generic_file_splice_read(filp, ppos, pipe, count, flags); | 292 | res = generic_file_splice_read(filp, ppos, pipe, count, flags); |
293 | if (res > 0) | ||
294 | nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, res); | ||
295 | } | ||
287 | return res; | 296 | return res; |
288 | } | 297 | } |
289 | 298 | ||
@@ -314,8 +323,9 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma) | |||
314 | * whether any write errors occurred for this process. | 323 | * whether any write errors occurred for this process. |
315 | */ | 324 | */ |
316 | static int | 325 | static int |
317 | nfs_file_fsync(struct file *file, struct dentry *dentry, int datasync) | 326 | nfs_file_fsync(struct file *file, int datasync) |
318 | { | 327 | { |
328 | struct dentry *dentry = file->f_path.dentry; | ||
319 | struct nfs_open_context *ctx = nfs_file_open_context(file); | 329 | struct nfs_open_context *ctx = nfs_file_open_context(file); |
320 | struct inode *inode = dentry->d_inode; | 330 | struct inode *inode = dentry->d_inode; |
321 | 331 | ||
@@ -484,8 +494,19 @@ static void nfs_invalidate_page(struct page *page, unsigned long offset) | |||
484 | */ | 494 | */ |
485 | static int nfs_release_page(struct page *page, gfp_t gfp) | 495 | static int nfs_release_page(struct page *page, gfp_t gfp) |
486 | { | 496 | { |
497 | struct address_space *mapping = page->mapping; | ||
498 | |||
487 | dfprintk(PAGECACHE, "NFS: release_page(%p)\n", page); | 499 | dfprintk(PAGECACHE, "NFS: release_page(%p)\n", page); |
488 | 500 | ||
501 | /* Only do I/O if gfp is a superset of GFP_KERNEL */ | ||
502 | if (mapping && (gfp & GFP_KERNEL) == GFP_KERNEL) { | ||
503 | int how = FLUSH_SYNC; | ||
504 | |||
505 | /* Don't let kswapd deadlock waiting for OOM RPC calls */ | ||
506 | if (current_is_kswapd()) | ||
507 | how = 0; | ||
508 | nfs_commit_inode(mapping->host, how); | ||
509 | } | ||
489 | /* If PagePrivate() is set, then the page is not freeable */ | 510 | /* If PagePrivate() is set, then the page is not freeable */ |
490 | if (PagePrivate(page)) | 511 | if (PagePrivate(page)) |
491 | return 0; | 512 | return 0; |
@@ -594,6 +615,7 @@ static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov, | |||
594 | { | 615 | { |
595 | struct dentry * dentry = iocb->ki_filp->f_path.dentry; | 616 | struct dentry * dentry = iocb->ki_filp->f_path.dentry; |
596 | struct inode * inode = dentry->d_inode; | 617 | struct inode * inode = dentry->d_inode; |
618 | unsigned long written = 0; | ||
597 | ssize_t result; | 619 | ssize_t result; |
598 | size_t count = iov_length(iov, nr_segs); | 620 | size_t count = iov_length(iov, nr_segs); |
599 | 621 | ||
@@ -620,14 +642,18 @@ static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov, | |||
620 | if (!count) | 642 | if (!count) |
621 | goto out; | 643 | goto out; |
622 | 644 | ||
623 | nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, count); | ||
624 | result = generic_file_aio_write(iocb, iov, nr_segs, pos); | 645 | result = generic_file_aio_write(iocb, iov, nr_segs, pos); |
646 | if (result > 0) | ||
647 | written = result; | ||
648 | |||
625 | /* Return error values for O_DSYNC and IS_SYNC() */ | 649 | /* Return error values for O_DSYNC and IS_SYNC() */ |
626 | if (result >= 0 && nfs_need_sync_write(iocb->ki_filp, inode)) { | 650 | if (result >= 0 && nfs_need_sync_write(iocb->ki_filp, inode)) { |
627 | int err = nfs_do_fsync(nfs_file_open_context(iocb->ki_filp), inode); | 651 | int err = nfs_do_fsync(nfs_file_open_context(iocb->ki_filp), inode); |
628 | if (err < 0) | 652 | if (err < 0) |
629 | result = err; | 653 | result = err; |
630 | } | 654 | } |
655 | if (result > 0) | ||
656 | nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, written); | ||
631 | out: | 657 | out: |
632 | return result; | 658 | return result; |
633 | 659 | ||
@@ -642,6 +668,7 @@ static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe, | |||
642 | { | 668 | { |
643 | struct dentry *dentry = filp->f_path.dentry; | 669 | struct dentry *dentry = filp->f_path.dentry; |
644 | struct inode *inode = dentry->d_inode; | 670 | struct inode *inode = dentry->d_inode; |
671 | unsigned long written = 0; | ||
645 | ssize_t ret; | 672 | ssize_t ret; |
646 | 673 | ||
647 | dprintk("NFS splice_write(%s/%s, %lu@%llu)\n", | 674 | dprintk("NFS splice_write(%s/%s, %lu@%llu)\n", |
@@ -652,14 +679,17 @@ static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe, | |||
652 | * The combination of splice and an O_APPEND destination is disallowed. | 679 | * The combination of splice and an O_APPEND destination is disallowed. |
653 | */ | 680 | */ |
654 | 681 | ||
655 | nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, count); | ||
656 | |||
657 | ret = generic_file_splice_write(pipe, filp, ppos, count, flags); | 682 | ret = generic_file_splice_write(pipe, filp, ppos, count, flags); |
683 | if (ret > 0) | ||
684 | written = ret; | ||
685 | |||
658 | if (ret >= 0 && nfs_need_sync_write(filp, inode)) { | 686 | if (ret >= 0 && nfs_need_sync_write(filp, inode)) { |
659 | int err = nfs_do_fsync(nfs_file_open_context(filp), inode); | 687 | int err = nfs_do_fsync(nfs_file_open_context(filp), inode); |
660 | if (err < 0) | 688 | if (err < 0) |
661 | ret = err; | 689 | ret = err; |
662 | } | 690 | } |
691 | if (ret > 0) | ||
692 | nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, written); | ||
663 | return ret; | 693 | return ret; |
664 | } | 694 | } |
665 | 695 | ||
diff --git a/fs/nfs/fscache.c b/fs/nfs/fscache.c index fa588006588d..ce153a6b3aec 100644 --- a/fs/nfs/fscache.c +++ b/fs/nfs/fscache.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/nfs_fs_sb.h> | 17 | #include <linux/nfs_fs_sb.h> |
18 | #include <linux/in6.h> | 18 | #include <linux/in6.h> |
19 | #include <linux/seq_file.h> | 19 | #include <linux/seq_file.h> |
20 | #include <linux/slab.h> | ||
20 | 21 | ||
21 | #include "internal.h" | 22 | #include "internal.h" |
22 | #include "iostat.h" | 23 | #include "iostat.h" |
@@ -354,12 +355,11 @@ void nfs_fscache_reset_inode_cookie(struct inode *inode) | |||
354 | */ | 355 | */ |
355 | int nfs_fscache_release_page(struct page *page, gfp_t gfp) | 356 | int nfs_fscache_release_page(struct page *page, gfp_t gfp) |
356 | { | 357 | { |
357 | struct nfs_inode *nfsi = NFS_I(page->mapping->host); | ||
358 | struct fscache_cookie *cookie = nfsi->fscache; | ||
359 | |||
360 | BUG_ON(!cookie); | ||
361 | |||
362 | if (PageFsCache(page)) { | 358 | if (PageFsCache(page)) { |
359 | struct nfs_inode *nfsi = NFS_I(page->mapping->host); | ||
360 | struct fscache_cookie *cookie = nfsi->fscache; | ||
361 | |||
362 | BUG_ON(!cookie); | ||
363 | dfprintk(FSCACHE, "NFS: fscache releasepage (0x%p/0x%p/0x%p)\n", | 363 | dfprintk(FSCACHE, "NFS: fscache releasepage (0x%p/0x%p/0x%p)\n", |
364 | cookie, page, nfsi); | 364 | cookie, page, nfsi); |
365 | 365 | ||
@@ -467,7 +467,8 @@ int __nfs_readpages_from_fscache(struct nfs_open_context *ctx, | |||
467 | struct list_head *pages, | 467 | struct list_head *pages, |
468 | unsigned *nr_pages) | 468 | unsigned *nr_pages) |
469 | { | 469 | { |
470 | int ret, npages = *nr_pages; | 470 | unsigned npages = *nr_pages; |
471 | int ret; | ||
471 | 472 | ||
472 | dfprintk(FSCACHE, "NFS: nfs_getpages_from_fscache (0x%p/%u/0x%p)\n", | 473 | dfprintk(FSCACHE, "NFS: nfs_getpages_from_fscache (0x%p/%u/0x%p)\n", |
473 | NFS_I(inode)->fscache, npages, inode); | 474 | NFS_I(inode)->fscache, npages, inode); |
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c index b35d2a616066..a70e446e1605 100644 --- a/fs/nfs/getroot.c +++ b/fs/nfs/getroot.c | |||
@@ -78,159 +78,94 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh) | |||
78 | { | 78 | { |
79 | struct nfs_server *server = NFS_SB(sb); | 79 | struct nfs_server *server = NFS_SB(sb); |
80 | struct nfs_fsinfo fsinfo; | 80 | struct nfs_fsinfo fsinfo; |
81 | struct nfs_fattr fattr; | 81 | struct dentry *ret; |
82 | struct dentry *mntroot; | ||
83 | struct inode *inode; | 82 | struct inode *inode; |
84 | int error; | 83 | int error; |
85 | 84 | ||
86 | /* get the actual root for this mount */ | 85 | /* get the actual root for this mount */ |
87 | fsinfo.fattr = &fattr; | 86 | fsinfo.fattr = nfs_alloc_fattr(); |
87 | if (fsinfo.fattr == NULL) | ||
88 | return ERR_PTR(-ENOMEM); | ||
88 | 89 | ||
89 | error = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo); | 90 | error = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo); |
90 | if (error < 0) { | 91 | if (error < 0) { |
91 | dprintk("nfs_get_root: getattr error = %d\n", -error); | 92 | dprintk("nfs_get_root: getattr error = %d\n", -error); |
92 | return ERR_PTR(error); | 93 | ret = ERR_PTR(error); |
94 | goto out; | ||
93 | } | 95 | } |
94 | 96 | ||
95 | inode = nfs_fhget(sb, mntfh, fsinfo.fattr); | 97 | inode = nfs_fhget(sb, mntfh, fsinfo.fattr); |
96 | if (IS_ERR(inode)) { | 98 | if (IS_ERR(inode)) { |
97 | dprintk("nfs_get_root: get root inode failed\n"); | 99 | dprintk("nfs_get_root: get root inode failed\n"); |
98 | return ERR_CAST(inode); | 100 | ret = ERR_CAST(inode); |
101 | goto out; | ||
99 | } | 102 | } |
100 | 103 | ||
101 | error = nfs_superblock_set_dummy_root(sb, inode); | 104 | error = nfs_superblock_set_dummy_root(sb, inode); |
102 | if (error != 0) | 105 | if (error != 0) { |
103 | return ERR_PTR(error); | 106 | ret = ERR_PTR(error); |
107 | goto out; | ||
108 | } | ||
104 | 109 | ||
105 | /* root dentries normally start off anonymous and get spliced in later | 110 | /* root dentries normally start off anonymous and get spliced in later |
106 | * if the dentry tree reaches them; however if the dentry already | 111 | * if the dentry tree reaches them; however if the dentry already |
107 | * exists, we'll pick it up at this point and use it as the root | 112 | * exists, we'll pick it up at this point and use it as the root |
108 | */ | 113 | */ |
109 | mntroot = d_obtain_alias(inode); | 114 | ret = d_obtain_alias(inode); |
110 | if (IS_ERR(mntroot)) { | 115 | if (IS_ERR(ret)) { |
111 | dprintk("nfs_get_root: get root dentry failed\n"); | 116 | dprintk("nfs_get_root: get root dentry failed\n"); |
112 | return mntroot; | 117 | goto out; |
113 | } | 118 | } |
114 | 119 | ||
115 | security_d_instantiate(mntroot, inode); | 120 | security_d_instantiate(ret, inode); |
116 | |||
117 | if (!mntroot->d_op) | ||
118 | mntroot->d_op = server->nfs_client->rpc_ops->dentry_ops; | ||
119 | 121 | ||
120 | return mntroot; | 122 | if (ret->d_op == NULL) |
123 | ret->d_op = server->nfs_client->rpc_ops->dentry_ops; | ||
124 | out: | ||
125 | nfs_free_fattr(fsinfo.fattr); | ||
126 | return ret; | ||
121 | } | 127 | } |
122 | 128 | ||
123 | #ifdef CONFIG_NFS_V4 | 129 | #ifdef CONFIG_NFS_V4 |
124 | 130 | ||
125 | /* | 131 | int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh) |
126 | * Do a simple pathwalk from the root FH of the server to the nominated target | ||
127 | * of the mountpoint | ||
128 | * - give error on symlinks | ||
129 | * - give error on ".." occurring in the path | ||
130 | * - follow traversals | ||
131 | */ | ||
132 | int nfs4_path_walk(struct nfs_server *server, | ||
133 | struct nfs_fh *mntfh, | ||
134 | const char *path) | ||
135 | { | 132 | { |
136 | struct nfs_fsinfo fsinfo; | 133 | struct nfs_fsinfo fsinfo; |
137 | struct nfs_fattr fattr; | 134 | int ret = -ENOMEM; |
138 | struct nfs_fh lastfh; | ||
139 | struct qstr name; | ||
140 | int ret; | ||
141 | 135 | ||
142 | dprintk("--> nfs4_path_walk(,,%s)\n", path); | 136 | dprintk("--> nfs4_get_rootfh()\n"); |
143 | 137 | ||
144 | fsinfo.fattr = &fattr; | 138 | fsinfo.fattr = nfs_alloc_fattr(); |
145 | nfs_fattr_init(&fattr); | 139 | if (fsinfo.fattr == NULL) |
146 | 140 | goto out; | |
147 | /* Eat leading slashes */ | ||
148 | while (*path == '/') | ||
149 | path++; | ||
150 | 141 | ||
151 | /* Start by getting the root filehandle from the server */ | 142 | /* Start by getting the root filehandle from the server */ |
152 | ret = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo); | 143 | ret = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo); |
153 | if (ret < 0) { | 144 | if (ret < 0) { |
154 | dprintk("nfs4_get_root: getroot error = %d\n", -ret); | 145 | dprintk("nfs4_get_rootfh: getroot error = %d\n", -ret); |
155 | return ret; | 146 | goto out; |
156 | } | 147 | } |
157 | 148 | ||
158 | if (!S_ISDIR(fattr.mode)) { | 149 | if (!(fsinfo.fattr->valid & NFS_ATTR_FATTR_TYPE) |
159 | printk(KERN_ERR "nfs4_get_root:" | 150 | || !S_ISDIR(fsinfo.fattr->mode)) { |
151 | printk(KERN_ERR "nfs4_get_rootfh:" | ||
160 | " getroot encountered non-directory\n"); | 152 | " getroot encountered non-directory\n"); |
161 | return -ENOTDIR; | 153 | ret = -ENOTDIR; |
154 | goto out; | ||
162 | } | 155 | } |
163 | 156 | ||
164 | /* FIXME: It is quite valid for the server to return a referral here */ | 157 | if (fsinfo.fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) { |
165 | if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) { | 158 | printk(KERN_ERR "nfs4_get_rootfh:" |
166 | printk(KERN_ERR "nfs4_get_root:" | ||
167 | " getroot obtained referral\n"); | 159 | " getroot obtained referral\n"); |
168 | return -EREMOTE; | 160 | ret = -EREMOTE; |
169 | } | 161 | goto out; |
170 | |||
171 | next_component: | ||
172 | dprintk("Next: %s\n", path); | ||
173 | |||
174 | /* extract the next bit of the path */ | ||
175 | if (!*path) | ||
176 | goto path_walk_complete; | ||
177 | |||
178 | name.name = path; | ||
179 | while (*path && *path != '/') | ||
180 | path++; | ||
181 | name.len = path - (const char *) name.name; | ||
182 | |||
183 | if (name.len > NFS4_MAXNAMLEN) | ||
184 | return -ENAMETOOLONG; | ||
185 | |||
186 | eat_dot_dir: | ||
187 | while (*path == '/') | ||
188 | path++; | ||
189 | |||
190 | if (path[0] == '.' && (path[1] == '/' || !path[1])) { | ||
191 | path += 2; | ||
192 | goto eat_dot_dir; | ||
193 | } | ||
194 | |||
195 | /* FIXME: Why shouldn't the user be able to use ".." in the path? */ | ||
196 | if (path[0] == '.' && path[1] == '.' && (path[2] == '/' || !path[2]) | ||
197 | ) { | ||
198 | printk(KERN_ERR "nfs4_get_root:" | ||
199 | " Mount path contains reference to \"..\"\n"); | ||
200 | return -EINVAL; | ||
201 | } | 162 | } |
202 | 163 | ||
203 | /* lookup the next FH in the sequence */ | 164 | memcpy(&server->fsid, &fsinfo.fattr->fsid, sizeof(server->fsid)); |
204 | memcpy(&lastfh, mntfh, sizeof(lastfh)); | 165 | out: |
205 | 166 | nfs_free_fattr(fsinfo.fattr); | |
206 | dprintk("LookupFH: %*.*s [%s]\n", name.len, name.len, name.name, path); | 167 | dprintk("<-- nfs4_get_rootfh() = %d\n", ret); |
207 | 168 | return ret; | |
208 | ret = server->nfs_client->rpc_ops->lookupfh(server, &lastfh, &name, | ||
209 | mntfh, &fattr); | ||
210 | if (ret < 0) { | ||
211 | dprintk("nfs4_get_root: getroot error = %d\n", -ret); | ||
212 | return ret; | ||
213 | } | ||
214 | |||
215 | if (!S_ISDIR(fattr.mode)) { | ||
216 | printk(KERN_ERR "nfs4_get_root:" | ||
217 | " lookupfh encountered non-directory\n"); | ||
218 | return -ENOTDIR; | ||
219 | } | ||
220 | |||
221 | /* FIXME: Referrals are quite valid here too */ | ||
222 | if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) { | ||
223 | printk(KERN_ERR "nfs4_get_root:" | ||
224 | " lookupfh obtained referral\n"); | ||
225 | return -EREMOTE; | ||
226 | } | ||
227 | |||
228 | goto next_component; | ||
229 | |||
230 | path_walk_complete: | ||
231 | memcpy(&server->fsid, &fattr.fsid, sizeof(server->fsid)); | ||
232 | dprintk("<-- nfs4_path_walk() = 0\n"); | ||
233 | return 0; | ||
234 | } | 169 | } |
235 | 170 | ||
236 | /* | 171 | /* |
@@ -239,8 +174,8 @@ path_walk_complete: | |||
239 | struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh) | 174 | struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh) |
240 | { | 175 | { |
241 | struct nfs_server *server = NFS_SB(sb); | 176 | struct nfs_server *server = NFS_SB(sb); |
242 | struct nfs_fattr fattr; | 177 | struct nfs_fattr *fattr = NULL; |
243 | struct dentry *mntroot; | 178 | struct dentry *ret; |
244 | struct inode *inode; | 179 | struct inode *inode; |
245 | int error; | 180 | int error; |
246 | 181 | ||
@@ -254,40 +189,50 @@ struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh) | |||
254 | return ERR_PTR(error); | 189 | return ERR_PTR(error); |
255 | } | 190 | } |
256 | 191 | ||
192 | fattr = nfs_alloc_fattr(); | ||
193 | if (fattr == NULL) | ||
194 | return ERR_PTR(-ENOMEM);; | ||
195 | |||
257 | /* get the actual root for this mount */ | 196 | /* get the actual root for this mount */ |
258 | error = server->nfs_client->rpc_ops->getattr(server, mntfh, &fattr); | 197 | error = server->nfs_client->rpc_ops->getattr(server, mntfh, fattr); |
259 | if (error < 0) { | 198 | if (error < 0) { |
260 | dprintk("nfs_get_root: getattr error = %d\n", -error); | 199 | dprintk("nfs_get_root: getattr error = %d\n", -error); |
261 | return ERR_PTR(error); | 200 | ret = ERR_PTR(error); |
201 | goto out; | ||
262 | } | 202 | } |
263 | 203 | ||
264 | inode = nfs_fhget(sb, mntfh, &fattr); | 204 | inode = nfs_fhget(sb, mntfh, fattr); |
265 | if (IS_ERR(inode)) { | 205 | if (IS_ERR(inode)) { |
266 | dprintk("nfs_get_root: get root inode failed\n"); | 206 | dprintk("nfs_get_root: get root inode failed\n"); |
267 | return ERR_CAST(inode); | 207 | ret = ERR_CAST(inode); |
208 | goto out; | ||
268 | } | 209 | } |
269 | 210 | ||
270 | error = nfs_superblock_set_dummy_root(sb, inode); | 211 | error = nfs_superblock_set_dummy_root(sb, inode); |
271 | if (error != 0) | 212 | if (error != 0) { |
272 | return ERR_PTR(error); | 213 | ret = ERR_PTR(error); |
214 | goto out; | ||
215 | } | ||
273 | 216 | ||
274 | /* root dentries normally start off anonymous and get spliced in later | 217 | /* root dentries normally start off anonymous and get spliced in later |
275 | * if the dentry tree reaches them; however if the dentry already | 218 | * if the dentry tree reaches them; however if the dentry already |
276 | * exists, we'll pick it up at this point and use it as the root | 219 | * exists, we'll pick it up at this point and use it as the root |
277 | */ | 220 | */ |
278 | mntroot = d_obtain_alias(inode); | 221 | ret = d_obtain_alias(inode); |
279 | if (IS_ERR(mntroot)) { | 222 | if (IS_ERR(ret)) { |
280 | dprintk("nfs_get_root: get root dentry failed\n"); | 223 | dprintk("nfs_get_root: get root dentry failed\n"); |
281 | return mntroot; | 224 | goto out; |
282 | } | 225 | } |
283 | 226 | ||
284 | security_d_instantiate(mntroot, inode); | 227 | security_d_instantiate(ret, inode); |
285 | 228 | ||
286 | if (!mntroot->d_op) | 229 | if (ret->d_op == NULL) |
287 | mntroot->d_op = server->nfs_client->rpc_ops->dentry_ops; | 230 | ret->d_op = server->nfs_client->rpc_ops->dentry_ops; |
288 | 231 | ||
232 | out: | ||
233 | nfs_free_fattr(fattr); | ||
289 | dprintk("<-- nfs4_get_root()\n"); | 234 | dprintk("<-- nfs4_get_root()\n"); |
290 | return mntroot; | 235 | return ret; |
291 | } | 236 | } |
292 | 237 | ||
293 | #endif /* CONFIG_NFS_V4 */ | 238 | #endif /* CONFIG_NFS_V4 */ |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index faa091865ad0..099b3518feea 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <linux/vfs.h> | 36 | #include <linux/vfs.h> |
37 | #include <linux/inet.h> | 37 | #include <linux/inet.h> |
38 | #include <linux/nfs_xdr.h> | 38 | #include <linux/nfs_xdr.h> |
39 | #include <linux/slab.h> | ||
39 | 40 | ||
40 | #include <asm/system.h> | 41 | #include <asm/system.h> |
41 | #include <asm/uaccess.h> | 42 | #include <asm/uaccess.h> |
@@ -97,22 +98,6 @@ u64 nfs_compat_user_ino64(u64 fileid) | |||
97 | return ino; | 98 | return ino; |
98 | } | 99 | } |
99 | 100 | ||
100 | int nfs_write_inode(struct inode *inode, int sync) | ||
101 | { | ||
102 | int ret; | ||
103 | |||
104 | if (sync) { | ||
105 | ret = filemap_fdatawait(inode->i_mapping); | ||
106 | if (ret == 0) | ||
107 | ret = nfs_commit_inode(inode, FLUSH_SYNC); | ||
108 | } else | ||
109 | ret = nfs_commit_inode(inode, 0); | ||
110 | if (ret >= 0) | ||
111 | return 0; | ||
112 | __mark_inode_dirty(inode, I_DIRTY_DATASYNC); | ||
113 | return ret; | ||
114 | } | ||
115 | |||
116 | void nfs_clear_inode(struct inode *inode) | 101 | void nfs_clear_inode(struct inode *inode) |
117 | { | 102 | { |
118 | /* | 103 | /* |
@@ -130,16 +115,12 @@ void nfs_clear_inode(struct inode *inode) | |||
130 | */ | 115 | */ |
131 | int nfs_sync_mapping(struct address_space *mapping) | 116 | int nfs_sync_mapping(struct address_space *mapping) |
132 | { | 117 | { |
133 | int ret; | 118 | int ret = 0; |
134 | 119 | ||
135 | if (mapping->nrpages == 0) | 120 | if (mapping->nrpages != 0) { |
136 | return 0; | 121 | unmap_mapping_range(mapping, 0, 0, 0); |
137 | unmap_mapping_range(mapping, 0, 0, 0); | 122 | ret = nfs_wb_all(mapping->host); |
138 | ret = filemap_write_and_wait(mapping); | 123 | } |
139 | if (ret != 0) | ||
140 | goto out; | ||
141 | ret = nfs_wb_all(mapping->host); | ||
142 | out: | ||
143 | return ret; | 124 | return ret; |
144 | } | 125 | } |
145 | 126 | ||
@@ -412,8 +393,8 @@ int | |||
412 | nfs_setattr(struct dentry *dentry, struct iattr *attr) | 393 | nfs_setattr(struct dentry *dentry, struct iattr *attr) |
413 | { | 394 | { |
414 | struct inode *inode = dentry->d_inode; | 395 | struct inode *inode = dentry->d_inode; |
415 | struct nfs_fattr fattr; | 396 | struct nfs_fattr *fattr; |
416 | int error; | 397 | int error = -ENOMEM; |
417 | 398 | ||
418 | nfs_inc_stats(inode, NFSIOS_VFSSETATTR); | 399 | nfs_inc_stats(inode, NFSIOS_VFSSETATTR); |
419 | 400 | ||
@@ -436,14 +417,20 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
436 | filemap_write_and_wait(inode->i_mapping); | 417 | filemap_write_and_wait(inode->i_mapping); |
437 | nfs_wb_all(inode); | 418 | nfs_wb_all(inode); |
438 | } | 419 | } |
420 | |||
421 | fattr = nfs_alloc_fattr(); | ||
422 | if (fattr == NULL) | ||
423 | goto out; | ||
439 | /* | 424 | /* |
440 | * Return any delegations if we're going to change ACLs | 425 | * Return any delegations if we're going to change ACLs |
441 | */ | 426 | */ |
442 | if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) | 427 | if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) |
443 | nfs_inode_return_delegation(inode); | 428 | nfs_inode_return_delegation(inode); |
444 | error = NFS_PROTO(inode)->setattr(dentry, &fattr, attr); | 429 | error = NFS_PROTO(inode)->setattr(dentry, fattr, attr); |
445 | if (error == 0) | 430 | if (error == 0) |
446 | nfs_refresh_inode(inode, &fattr); | 431 | nfs_refresh_inode(inode, fattr); |
432 | nfs_free_fattr(fattr); | ||
433 | out: | ||
447 | return error; | 434 | return error; |
448 | } | 435 | } |
449 | 436 | ||
@@ -511,17 +498,11 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | |||
511 | int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME; | 498 | int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME; |
512 | int err; | 499 | int err; |
513 | 500 | ||
514 | /* | 501 | /* Flush out writes to the server in order to update c/mtime. */ |
515 | * Flush out writes to the server in order to update c/mtime. | ||
516 | * | ||
517 | * Hold the i_mutex to suspend application writes temporarily; | ||
518 | * this prevents long-running writing applications from blocking | ||
519 | * nfs_wb_nocommit. | ||
520 | */ | ||
521 | if (S_ISREG(inode->i_mode)) { | 502 | if (S_ISREG(inode->i_mode)) { |
522 | mutex_lock(&inode->i_mutex); | 503 | err = filemap_write_and_wait(inode->i_mapping); |
523 | nfs_wb_nocommit(inode); | 504 | if (err) |
524 | mutex_unlock(&inode->i_mutex); | 505 | goto out; |
525 | } | 506 | } |
526 | 507 | ||
527 | /* | 508 | /* |
@@ -545,6 +526,7 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | |||
545 | generic_fillattr(inode, stat); | 526 | generic_fillattr(inode, stat); |
546 | stat->ino = nfs_compat_user_ino64(NFS_FILEID(inode)); | 527 | stat->ino = nfs_compat_user_ino64(NFS_FILEID(inode)); |
547 | } | 528 | } |
529 | out: | ||
548 | return err; | 530 | return err; |
549 | } | 531 | } |
550 | 532 | ||
@@ -574,14 +556,14 @@ void nfs_close_context(struct nfs_open_context *ctx, int is_sync) | |||
574 | nfs_revalidate_inode(server, inode); | 556 | nfs_revalidate_inode(server, inode); |
575 | } | 557 | } |
576 | 558 | ||
577 | static struct nfs_open_context *alloc_nfs_open_context(struct vfsmount *mnt, struct dentry *dentry, struct rpc_cred *cred) | 559 | static struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct rpc_cred *cred) |
578 | { | 560 | { |
579 | struct nfs_open_context *ctx; | 561 | struct nfs_open_context *ctx; |
580 | 562 | ||
581 | ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); | 563 | ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); |
582 | if (ctx != NULL) { | 564 | if (ctx != NULL) { |
583 | ctx->path.dentry = dget(dentry); | 565 | ctx->path = *path; |
584 | ctx->path.mnt = mntget(mnt); | 566 | path_get(&ctx->path); |
585 | ctx->cred = get_rpccred(cred); | 567 | ctx->cred = get_rpccred(cred); |
586 | ctx->state = NULL; | 568 | ctx->state = NULL; |
587 | ctx->lockowner = current->files; | 569 | ctx->lockowner = current->files; |
@@ -620,11 +602,6 @@ void put_nfs_open_context(struct nfs_open_context *ctx) | |||
620 | __put_nfs_open_context(ctx, 0); | 602 | __put_nfs_open_context(ctx, 0); |
621 | } | 603 | } |
622 | 604 | ||
623 | static void put_nfs_open_context_sync(struct nfs_open_context *ctx) | ||
624 | { | ||
625 | __put_nfs_open_context(ctx, 1); | ||
626 | } | ||
627 | |||
628 | /* | 605 | /* |
629 | * Ensure that mmap has a recent RPC credential for use when writing out | 606 | * Ensure that mmap has a recent RPC credential for use when writing out |
630 | * shared pages | 607 | * shared pages |
@@ -652,10 +629,10 @@ struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_c | |||
652 | list_for_each_entry(pos, &nfsi->open_files, list) { | 629 | list_for_each_entry(pos, &nfsi->open_files, list) { |
653 | if (cred != NULL && pos->cred != cred) | 630 | if (cred != NULL && pos->cred != cred) |
654 | continue; | 631 | continue; |
655 | if ((pos->mode & mode) == mode) { | 632 | if ((pos->mode & (FMODE_READ|FMODE_WRITE)) != mode) |
656 | ctx = get_nfs_open_context(pos); | 633 | continue; |
657 | break; | 634 | ctx = get_nfs_open_context(pos); |
658 | } | 635 | break; |
659 | } | 636 | } |
660 | spin_unlock(&inode->i_lock); | 637 | spin_unlock(&inode->i_lock); |
661 | return ctx; | 638 | return ctx; |
@@ -671,7 +648,7 @@ static void nfs_file_clear_open_context(struct file *filp) | |||
671 | spin_lock(&inode->i_lock); | 648 | spin_lock(&inode->i_lock); |
672 | list_move_tail(&ctx->list, &NFS_I(inode)->open_files); | 649 | list_move_tail(&ctx->list, &NFS_I(inode)->open_files); |
673 | spin_unlock(&inode->i_lock); | 650 | spin_unlock(&inode->i_lock); |
674 | put_nfs_open_context_sync(ctx); | 651 | __put_nfs_open_context(ctx, filp->f_flags & O_DIRECT ? 0 : 1); |
675 | } | 652 | } |
676 | } | 653 | } |
677 | 654 | ||
@@ -686,7 +663,7 @@ int nfs_open(struct inode *inode, struct file *filp) | |||
686 | cred = rpc_lookup_cred(); | 663 | cred = rpc_lookup_cred(); |
687 | if (IS_ERR(cred)) | 664 | if (IS_ERR(cred)) |
688 | return PTR_ERR(cred); | 665 | return PTR_ERR(cred); |
689 | ctx = alloc_nfs_open_context(filp->f_path.mnt, filp->f_path.dentry, cred); | 666 | ctx = alloc_nfs_open_context(&filp->f_path, cred); |
690 | put_rpccred(cred); | 667 | put_rpccred(cred); |
691 | if (ctx == NULL) | 668 | if (ctx == NULL) |
692 | return -ENOMEM; | 669 | return -ENOMEM; |
@@ -711,7 +688,7 @@ int | |||
711 | __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | 688 | __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) |
712 | { | 689 | { |
713 | int status = -ESTALE; | 690 | int status = -ESTALE; |
714 | struct nfs_fattr fattr; | 691 | struct nfs_fattr *fattr = NULL; |
715 | struct nfs_inode *nfsi = NFS_I(inode); | 692 | struct nfs_inode *nfsi = NFS_I(inode); |
716 | 693 | ||
717 | dfprintk(PAGECACHE, "NFS: revalidating (%s/%Ld)\n", | 694 | dfprintk(PAGECACHE, "NFS: revalidating (%s/%Ld)\n", |
@@ -722,8 +699,13 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | |||
722 | if (NFS_STALE(inode)) | 699 | if (NFS_STALE(inode)) |
723 | goto out; | 700 | goto out; |
724 | 701 | ||
702 | status = -ENOMEM; | ||
703 | fattr = nfs_alloc_fattr(); | ||
704 | if (fattr == NULL) | ||
705 | goto out; | ||
706 | |||
725 | nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE); | 707 | nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE); |
726 | status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), &fattr); | 708 | status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), fattr); |
727 | if (status != 0) { | 709 | if (status != 0) { |
728 | dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d\n", | 710 | dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d\n", |
729 | inode->i_sb->s_id, | 711 | inode->i_sb->s_id, |
@@ -736,7 +718,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | |||
736 | goto out; | 718 | goto out; |
737 | } | 719 | } |
738 | 720 | ||
739 | status = nfs_refresh_inode(inode, &fattr); | 721 | status = nfs_refresh_inode(inode, fattr); |
740 | if (status) { | 722 | if (status) { |
741 | dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) refresh failed, error=%d\n", | 723 | dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) refresh failed, error=%d\n", |
742 | inode->i_sb->s_id, | 724 | inode->i_sb->s_id, |
@@ -752,6 +734,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | |||
752 | (long long)NFS_FILEID(inode)); | 734 | (long long)NFS_FILEID(inode)); |
753 | 735 | ||
754 | out: | 736 | out: |
737 | nfs_free_fattr(fattr); | ||
755 | return status; | 738 | return status; |
756 | } | 739 | } |
757 | 740 | ||
@@ -759,11 +742,16 @@ int nfs_attribute_timeout(struct inode *inode) | |||
759 | { | 742 | { |
760 | struct nfs_inode *nfsi = NFS_I(inode); | 743 | struct nfs_inode *nfsi = NFS_I(inode); |
761 | 744 | ||
762 | if (nfs_have_delegation(inode, FMODE_READ)) | ||
763 | return 0; | ||
764 | return !time_in_range_open(jiffies, nfsi->read_cache_jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo); | 745 | return !time_in_range_open(jiffies, nfsi->read_cache_jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo); |
765 | } | 746 | } |
766 | 747 | ||
748 | static int nfs_attribute_cache_expired(struct inode *inode) | ||
749 | { | ||
750 | if (nfs_have_delegated_attributes(inode)) | ||
751 | return 0; | ||
752 | return nfs_attribute_timeout(inode); | ||
753 | } | ||
754 | |||
767 | /** | 755 | /** |
768 | * nfs_revalidate_inode - Revalidate the inode attributes | 756 | * nfs_revalidate_inode - Revalidate the inode attributes |
769 | * @server - pointer to nfs_server struct | 757 | * @server - pointer to nfs_server struct |
@@ -774,12 +762,12 @@ int nfs_attribute_timeout(struct inode *inode) | |||
774 | int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | 762 | int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) |
775 | { | 763 | { |
776 | if (!(NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATTR) | 764 | if (!(NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATTR) |
777 | && !nfs_attribute_timeout(inode)) | 765 | && !nfs_attribute_cache_expired(inode)) |
778 | return NFS_STALE(inode) ? -ESTALE : 0; | 766 | return NFS_STALE(inode) ? -ESTALE : 0; |
779 | return __nfs_revalidate_inode(server, inode); | 767 | return __nfs_revalidate_inode(server, inode); |
780 | } | 768 | } |
781 | 769 | ||
782 | static int nfs_invalidate_mapping_nolock(struct inode *inode, struct address_space *mapping) | 770 | static int nfs_invalidate_mapping(struct inode *inode, struct address_space *mapping) |
783 | { | 771 | { |
784 | struct nfs_inode *nfsi = NFS_I(inode); | 772 | struct nfs_inode *nfsi = NFS_I(inode); |
785 | 773 | ||
@@ -800,49 +788,10 @@ static int nfs_invalidate_mapping_nolock(struct inode *inode, struct address_spa | |||
800 | return 0; | 788 | return 0; |
801 | } | 789 | } |
802 | 790 | ||
803 | static int nfs_invalidate_mapping(struct inode *inode, struct address_space *mapping) | ||
804 | { | ||
805 | int ret = 0; | ||
806 | |||
807 | mutex_lock(&inode->i_mutex); | ||
808 | if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_DATA) { | ||
809 | ret = nfs_sync_mapping(mapping); | ||
810 | if (ret == 0) | ||
811 | ret = nfs_invalidate_mapping_nolock(inode, mapping); | ||
812 | } | ||
813 | mutex_unlock(&inode->i_mutex); | ||
814 | return ret; | ||
815 | } | ||
816 | |||
817 | /** | ||
818 | * nfs_revalidate_mapping_nolock - Revalidate the pagecache | ||
819 | * @inode - pointer to host inode | ||
820 | * @mapping - pointer to mapping | ||
821 | */ | ||
822 | int nfs_revalidate_mapping_nolock(struct inode *inode, struct address_space *mapping) | ||
823 | { | ||
824 | struct nfs_inode *nfsi = NFS_I(inode); | ||
825 | int ret = 0; | ||
826 | |||
827 | if ((nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE) | ||
828 | || nfs_attribute_timeout(inode) || NFS_STALE(inode)) { | ||
829 | ret = __nfs_revalidate_inode(NFS_SERVER(inode), inode); | ||
830 | if (ret < 0) | ||
831 | goto out; | ||
832 | } | ||
833 | if (nfsi->cache_validity & NFS_INO_INVALID_DATA) | ||
834 | ret = nfs_invalidate_mapping_nolock(inode, mapping); | ||
835 | out: | ||
836 | return ret; | ||
837 | } | ||
838 | |||
839 | /** | 791 | /** |
840 | * nfs_revalidate_mapping - Revalidate the pagecache | 792 | * nfs_revalidate_mapping - Revalidate the pagecache |
841 | * @inode - pointer to host inode | 793 | * @inode - pointer to host inode |
842 | * @mapping - pointer to mapping | 794 | * @mapping - pointer to mapping |
843 | * | ||
844 | * This version of the function will take the inode->i_mutex and attempt to | ||
845 | * flush out all dirty data if it needs to invalidate the page cache. | ||
846 | */ | 795 | */ |
847 | int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping) | 796 | int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping) |
848 | { | 797 | { |
@@ -850,7 +799,8 @@ int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping) | |||
850 | int ret = 0; | 799 | int ret = 0; |
851 | 800 | ||
852 | if ((nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE) | 801 | if ((nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE) |
853 | || nfs_attribute_timeout(inode) || NFS_STALE(inode)) { | 802 | || nfs_attribute_cache_expired(inode) |
803 | || NFS_STALE(inode)) { | ||
854 | ret = __nfs_revalidate_inode(NFS_SERVER(inode), inode); | 804 | ret = __nfs_revalidate_inode(NFS_SERVER(inode), inode); |
855 | if (ret < 0) | 805 | if (ret < 0) |
856 | goto out; | 806 | goto out; |
@@ -984,6 +934,26 @@ void nfs_fattr_init(struct nfs_fattr *fattr) | |||
984 | fattr->gencount = nfs_inc_attr_generation_counter(); | 934 | fattr->gencount = nfs_inc_attr_generation_counter(); |
985 | } | 935 | } |
986 | 936 | ||
937 | struct nfs_fattr *nfs_alloc_fattr(void) | ||
938 | { | ||
939 | struct nfs_fattr *fattr; | ||
940 | |||
941 | fattr = kmalloc(sizeof(*fattr), GFP_NOFS); | ||
942 | if (fattr != NULL) | ||
943 | nfs_fattr_init(fattr); | ||
944 | return fattr; | ||
945 | } | ||
946 | |||
947 | struct nfs_fh *nfs_alloc_fhandle(void) | ||
948 | { | ||
949 | struct nfs_fh *fh; | ||
950 | |||
951 | fh = kmalloc(sizeof(struct nfs_fh), GFP_NOFS); | ||
952 | if (fh != NULL) | ||
953 | fh->size = 0; | ||
954 | return fh; | ||
955 | } | ||
956 | |||
987 | /** | 957 | /** |
988 | * nfs_inode_attrs_need_update - check if the inode attributes need updating | 958 | * nfs_inode_attrs_need_update - check if the inode attributes need updating |
989 | * @inode - pointer to inode | 959 | * @inode - pointer to inode |
@@ -1261,8 +1231,10 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1261 | 1231 | ||
1262 | if (fattr->valid & NFS_ATTR_FATTR_MODE) { | 1232 | if (fattr->valid & NFS_ATTR_FATTR_MODE) { |
1263 | if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)) { | 1233 | if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)) { |
1234 | umode_t newmode = inode->i_mode & S_IFMT; | ||
1235 | newmode |= fattr->mode & S_IALLUGO; | ||
1236 | inode->i_mode = newmode; | ||
1264 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; | 1237 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; |
1265 | inode->i_mode = fattr->mode; | ||
1266 | } | 1238 | } |
1267 | } else if (server->caps & NFS_CAP_MODE) | 1239 | } else if (server->caps & NFS_CAP_MODE) |
1268 | invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR | 1240 | invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR |
@@ -1418,6 +1390,7 @@ static void init_once(void *foo) | |||
1418 | INIT_LIST_HEAD(&nfsi->access_cache_inode_lru); | 1390 | INIT_LIST_HEAD(&nfsi->access_cache_inode_lru); |
1419 | INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC); | 1391 | INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC); |
1420 | nfsi->npages = 0; | 1392 | nfsi->npages = 0; |
1393 | nfsi->ncommit = 0; | ||
1421 | atomic_set(&nfsi->silly_count, 1); | 1394 | atomic_set(&nfsi->silly_count, 1); |
1422 | INIT_HLIST_HEAD(&nfsi->silly_list); | 1395 | INIT_HLIST_HEAD(&nfsi->silly_list); |
1423 | init_waitqueue_head(&nfsi->waitqueue); | 1396 | init_waitqueue_head(&nfsi->waitqueue); |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 29e464d23b32..e70f44b9b3f4 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -205,13 +205,14 @@ extern struct rpc_procinfo nfs4_procedures[]; | |||
205 | void nfs_close_context(struct nfs_open_context *ctx, int is_sync); | 205 | void nfs_close_context(struct nfs_open_context *ctx, int is_sync); |
206 | 206 | ||
207 | /* dir.c */ | 207 | /* dir.c */ |
208 | extern int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask); | 208 | extern int nfs_access_cache_shrinker(struct shrinker *shrink, |
209 | int nr_to_scan, gfp_t gfp_mask); | ||
209 | 210 | ||
210 | /* inode.c */ | 211 | /* inode.c */ |
211 | extern struct workqueue_struct *nfsiod_workqueue; | 212 | extern struct workqueue_struct *nfsiod_workqueue; |
212 | extern struct inode *nfs_alloc_inode(struct super_block *sb); | 213 | extern struct inode *nfs_alloc_inode(struct super_block *sb); |
213 | extern void nfs_destroy_inode(struct inode *); | 214 | extern void nfs_destroy_inode(struct inode *); |
214 | extern int nfs_write_inode(struct inode *,int); | 215 | extern int nfs_write_inode(struct inode *, struct writeback_control *); |
215 | extern void nfs_clear_inode(struct inode *); | 216 | extern void nfs_clear_inode(struct inode *); |
216 | #ifdef CONFIG_NFS_V4 | 217 | #ifdef CONFIG_NFS_V4 |
217 | extern void nfs4_clear_inode(struct inode *); | 218 | extern void nfs4_clear_inode(struct inode *); |
@@ -244,9 +245,7 @@ extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *); | |||
244 | #ifdef CONFIG_NFS_V4 | 245 | #ifdef CONFIG_NFS_V4 |
245 | extern struct dentry *nfs4_get_root(struct super_block *, struct nfs_fh *); | 246 | extern struct dentry *nfs4_get_root(struct super_block *, struct nfs_fh *); |
246 | 247 | ||
247 | extern int nfs4_path_walk(struct nfs_server *server, | 248 | extern int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh); |
248 | struct nfs_fh *mntfh, | ||
249 | const char *path); | ||
250 | #endif | 249 | #endif |
251 | 250 | ||
252 | /* read.c */ | 251 | /* read.c */ |
diff --git a/fs/nfs/iostat.h b/fs/nfs/iostat.h index 46d779abafd3..c5832487c456 100644 --- a/fs/nfs/iostat.h +++ b/fs/nfs/iostat.h | |||
@@ -36,14 +36,14 @@ static inline void nfs_inc_stats(const struct inode *inode, | |||
36 | 36 | ||
37 | static inline void nfs_add_server_stats(const struct nfs_server *server, | 37 | static inline void nfs_add_server_stats(const struct nfs_server *server, |
38 | enum nfs_stat_bytecounters stat, | 38 | enum nfs_stat_bytecounters stat, |
39 | unsigned long addend) | 39 | long addend) |
40 | { | 40 | { |
41 | this_cpu_add(server->io_stats->bytes[stat], addend); | 41 | this_cpu_add(server->io_stats->bytes[stat], addend); |
42 | } | 42 | } |
43 | 43 | ||
44 | static inline void nfs_add_stats(const struct inode *inode, | 44 | static inline void nfs_add_stats(const struct inode *inode, |
45 | enum nfs_stat_bytecounters stat, | 45 | enum nfs_stat_bytecounters stat, |
46 | unsigned long addend) | 46 | long addend) |
47 | { | 47 | { |
48 | nfs_add_server_stats(NFS_SERVER(inode), stat, addend); | 48 | nfs_add_server_stats(NFS_SERVER(inode), stat, addend); |
49 | } | 49 | } |
@@ -51,18 +51,18 @@ static inline void nfs_add_stats(const struct inode *inode, | |||
51 | #ifdef CONFIG_NFS_FSCACHE | 51 | #ifdef CONFIG_NFS_FSCACHE |
52 | static inline void nfs_add_fscache_stats(struct inode *inode, | 52 | static inline void nfs_add_fscache_stats(struct inode *inode, |
53 | enum nfs_stat_fscachecounters stat, | 53 | enum nfs_stat_fscachecounters stat, |
54 | unsigned long addend) | 54 | long addend) |
55 | { | 55 | { |
56 | this_cpu_add(NFS_SERVER(inode)->io_stats->fscache[stat], addend); | 56 | this_cpu_add(NFS_SERVER(inode)->io_stats->fscache[stat], addend); |
57 | } | 57 | } |
58 | #endif | 58 | #endif |
59 | 59 | ||
60 | static inline struct nfs_iostats *nfs_alloc_iostats(void) | 60 | static inline struct nfs_iostats __percpu *nfs_alloc_iostats(void) |
61 | { | 61 | { |
62 | return alloc_percpu(struct nfs_iostats); | 62 | return alloc_percpu(struct nfs_iostats); |
63 | } | 63 | } |
64 | 64 | ||
65 | static inline void nfs_free_iostats(struct nfs_iostats *stats) | 65 | static inline void nfs_free_iostats(struct nfs_iostats __percpu *stats) |
66 | { | 66 | { |
67 | if (stats != NULL) | 67 | if (stats != NULL) |
68 | free_percpu(stats); | 68 | free_percpu(stats); |
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index 0adefc40cc89..59047f8d7d72 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c | |||
@@ -120,7 +120,7 @@ static struct { | |||
120 | { .status = MNT3ERR_INVAL, .errno = -EINVAL, }, | 120 | { .status = MNT3ERR_INVAL, .errno = -EINVAL, }, |
121 | { .status = MNT3ERR_NAMETOOLONG, .errno = -ENAMETOOLONG, }, | 121 | { .status = MNT3ERR_NAMETOOLONG, .errno = -ENAMETOOLONG, }, |
122 | { .status = MNT3ERR_NOTSUPP, .errno = -ENOTSUPP, }, | 122 | { .status = MNT3ERR_NOTSUPP, .errno = -ENOTSUPP, }, |
123 | { .status = MNT3ERR_SERVERFAULT, .errno = -ESERVERFAULT, }, | 123 | { .status = MNT3ERR_SERVERFAULT, .errno = -EREMOTEIO, }, |
124 | }; | 124 | }; |
125 | 125 | ||
126 | struct mountres { | 126 | struct mountres { |
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index 40c766782891..db6aa3673cf3 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c | |||
@@ -8,6 +8,7 @@ | |||
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/dcache.h> | 10 | #include <linux/dcache.h> |
11 | #include <linux/gfp.h> | ||
11 | #include <linux/mount.h> | 12 | #include <linux/mount.h> |
12 | #include <linux/namei.h> | 13 | #include <linux/namei.h> |
13 | #include <linux/nfs_fs.h> | 14 | #include <linux/nfs_fs.h> |
@@ -104,8 +105,8 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) | |||
104 | struct vfsmount *mnt; | 105 | struct vfsmount *mnt; |
105 | struct nfs_server *server = NFS_SERVER(dentry->d_inode); | 106 | struct nfs_server *server = NFS_SERVER(dentry->d_inode); |
106 | struct dentry *parent; | 107 | struct dentry *parent; |
107 | struct nfs_fh fh; | 108 | struct nfs_fh *fh = NULL; |
108 | struct nfs_fattr fattr; | 109 | struct nfs_fattr *fattr = NULL; |
109 | int err; | 110 | int err; |
110 | 111 | ||
111 | dprintk("--> nfs_follow_mountpoint()\n"); | 112 | dprintk("--> nfs_follow_mountpoint()\n"); |
@@ -114,6 +115,12 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) | |||
114 | if (IS_ROOT(dentry)) | 115 | if (IS_ROOT(dentry)) |
115 | goto out_err; | 116 | goto out_err; |
116 | 117 | ||
118 | err = -ENOMEM; | ||
119 | fh = nfs_alloc_fhandle(); | ||
120 | fattr = nfs_alloc_fattr(); | ||
121 | if (fh == NULL || fattr == NULL) | ||
122 | goto out_err; | ||
123 | |||
117 | dprintk("%s: enter\n", __func__); | 124 | dprintk("%s: enter\n", __func__); |
118 | dput(nd->path.dentry); | 125 | dput(nd->path.dentry); |
119 | nd->path.dentry = dget(dentry); | 126 | nd->path.dentry = dget(dentry); |
@@ -122,16 +129,16 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) | |||
122 | parent = dget_parent(nd->path.dentry); | 129 | parent = dget_parent(nd->path.dentry); |
123 | err = server->nfs_client->rpc_ops->lookup(parent->d_inode, | 130 | err = server->nfs_client->rpc_ops->lookup(parent->d_inode, |
124 | &nd->path.dentry->d_name, | 131 | &nd->path.dentry->d_name, |
125 | &fh, &fattr); | 132 | fh, fattr); |
126 | dput(parent); | 133 | dput(parent); |
127 | if (err != 0) | 134 | if (err != 0) |
128 | goto out_err; | 135 | goto out_err; |
129 | 136 | ||
130 | if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) | 137 | if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) |
131 | mnt = nfs_do_refmount(nd->path.mnt, nd->path.dentry); | 138 | mnt = nfs_do_refmount(nd->path.mnt, nd->path.dentry); |
132 | else | 139 | else |
133 | mnt = nfs_do_submount(nd->path.mnt, nd->path.dentry, &fh, | 140 | mnt = nfs_do_submount(nd->path.mnt, nd->path.dentry, fh, |
134 | &fattr); | 141 | fattr); |
135 | err = PTR_ERR(mnt); | 142 | err = PTR_ERR(mnt); |
136 | if (IS_ERR(mnt)) | 143 | if (IS_ERR(mnt)) |
137 | goto out_err; | 144 | goto out_err; |
@@ -150,6 +157,8 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) | |||
150 | nd->path.dentry = dget(mnt->mnt_root); | 157 | nd->path.dentry = dget(mnt->mnt_root); |
151 | schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout); | 158 | schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout); |
152 | out: | 159 | out: |
160 | nfs_free_fattr(fattr); | ||
161 | nfs_free_fhandle(fh); | ||
153 | dprintk("%s: done, returned %d\n", __func__, err); | 162 | dprintk("%s: done, returned %d\n", __func__, err); |
154 | 163 | ||
155 | dprintk("<-- nfs_follow_mountpoint() = %d\n", err); | 164 | dprintk("<-- nfs_follow_mountpoint() = %d\n", err); |
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index 5e078b222b4e..81cf14257916 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c | |||
@@ -12,7 +12,6 @@ | |||
12 | #include <linux/param.h> | 12 | #include <linux/param.h> |
13 | #include <linux/time.h> | 13 | #include <linux/time.h> |
14 | #include <linux/mm.h> | 14 | #include <linux/mm.h> |
15 | #include <linux/slab.h> | ||
16 | #include <linux/errno.h> | 15 | #include <linux/errno.h> |
17 | #include <linux/string.h> | 16 | #include <linux/string.h> |
18 | #include <linux/in.h> | 17 | #include <linux/in.h> |
@@ -699,7 +698,7 @@ static struct { | |||
699 | { NFSERR_BAD_COOKIE, -EBADCOOKIE }, | 698 | { NFSERR_BAD_COOKIE, -EBADCOOKIE }, |
700 | { NFSERR_NOTSUPP, -ENOTSUPP }, | 699 | { NFSERR_NOTSUPP, -ENOTSUPP }, |
701 | { NFSERR_TOOSMALL, -ETOOSMALL }, | 700 | { NFSERR_TOOSMALL, -ETOOSMALL }, |
702 | { NFSERR_SERVERFAULT, -ESERVERFAULT }, | 701 | { NFSERR_SERVERFAULT, -EREMOTEIO }, |
703 | { NFSERR_BADTYPE, -EBADTYPE }, | 702 | { NFSERR_BADTYPE, -EBADTYPE }, |
704 | { NFSERR_JUKEBOX, -EJUKEBOX }, | 703 | { NFSERR_JUKEBOX, -EJUKEBOX }, |
705 | { -1, -EIO } | 704 | { -1, -EIO } |
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c index bac60515a4b3..9f88c5f4c7e2 100644 --- a/fs/nfs/nfs3acl.c +++ b/fs/nfs/nfs3acl.c | |||
@@ -1,4 +1,5 @@ | |||
1 | #include <linux/fs.h> | 1 | #include <linux/fs.h> |
2 | #include <linux/gfp.h> | ||
2 | #include <linux/nfs.h> | 3 | #include <linux/nfs.h> |
3 | #include <linux/nfs3.h> | 4 | #include <linux/nfs3.h> |
4 | #include <linux/nfs_fs.h> | 5 | #include <linux/nfs_fs.h> |
@@ -184,7 +185,6 @@ static void nfs3_cache_acls(struct inode *inode, struct posix_acl *acl, | |||
184 | struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) | 185 | struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) |
185 | { | 186 | { |
186 | struct nfs_server *server = NFS_SERVER(inode); | 187 | struct nfs_server *server = NFS_SERVER(inode); |
187 | struct nfs_fattr fattr; | ||
188 | struct page *pages[NFSACL_MAXPAGES] = { }; | 188 | struct page *pages[NFSACL_MAXPAGES] = { }; |
189 | struct nfs3_getaclargs args = { | 189 | struct nfs3_getaclargs args = { |
190 | .fh = NFS_FH(inode), | 190 | .fh = NFS_FH(inode), |
@@ -192,7 +192,7 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) | |||
192 | .pages = pages, | 192 | .pages = pages, |
193 | }; | 193 | }; |
194 | struct nfs3_getaclres res = { | 194 | struct nfs3_getaclres res = { |
195 | .fattr = &fattr, | 195 | 0 |
196 | }; | 196 | }; |
197 | struct rpc_message msg = { | 197 | struct rpc_message msg = { |
198 | .rpc_argp = &args, | 198 | .rpc_argp = &args, |
@@ -227,7 +227,10 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) | |||
227 | 227 | ||
228 | dprintk("NFS call getacl\n"); | 228 | dprintk("NFS call getacl\n"); |
229 | msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_GETACL]; | 229 | msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_GETACL]; |
230 | nfs_fattr_init(&fattr); | 230 | res.fattr = nfs_alloc_fattr(); |
231 | if (res.fattr == NULL) | ||
232 | return ERR_PTR(-ENOMEM); | ||
233 | |||
231 | status = rpc_call_sync(server->client_acl, &msg, 0); | 234 | status = rpc_call_sync(server->client_acl, &msg, 0); |
232 | dprintk("NFS reply getacl: %d\n", status); | 235 | dprintk("NFS reply getacl: %d\n", status); |
233 | 236 | ||
@@ -237,7 +240,7 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) | |||
237 | 240 | ||
238 | switch (status) { | 241 | switch (status) { |
239 | case 0: | 242 | case 0: |
240 | status = nfs_refresh_inode(inode, &fattr); | 243 | status = nfs_refresh_inode(inode, res.fattr); |
241 | break; | 244 | break; |
242 | case -EPFNOSUPPORT: | 245 | case -EPFNOSUPPORT: |
243 | case -EPROTONOSUPPORT: | 246 | case -EPROTONOSUPPORT: |
@@ -277,6 +280,7 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) | |||
277 | getout: | 280 | getout: |
278 | posix_acl_release(res.acl_access); | 281 | posix_acl_release(res.acl_access); |
279 | posix_acl_release(res.acl_default); | 282 | posix_acl_release(res.acl_default); |
283 | nfs_free_fattr(res.fattr); | ||
280 | 284 | ||
281 | if (status != 0) { | 285 | if (status != 0) { |
282 | posix_acl_release(acl); | 286 | posix_acl_release(acl); |
@@ -289,7 +293,7 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, | |||
289 | struct posix_acl *dfacl) | 293 | struct posix_acl *dfacl) |
290 | { | 294 | { |
291 | struct nfs_server *server = NFS_SERVER(inode); | 295 | struct nfs_server *server = NFS_SERVER(inode); |
292 | struct nfs_fattr fattr; | 296 | struct nfs_fattr *fattr; |
293 | struct page *pages[NFSACL_MAXPAGES]; | 297 | struct page *pages[NFSACL_MAXPAGES]; |
294 | struct nfs3_setaclargs args = { | 298 | struct nfs3_setaclargs args = { |
295 | .inode = inode, | 299 | .inode = inode, |
@@ -334,8 +338,13 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, | |||
334 | } | 338 | } |
335 | 339 | ||
336 | dprintk("NFS call setacl\n"); | 340 | dprintk("NFS call setacl\n"); |
341 | status = -ENOMEM; | ||
342 | fattr = nfs_alloc_fattr(); | ||
343 | if (fattr == NULL) | ||
344 | goto out_freepages; | ||
345 | |||
337 | msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_SETACL]; | 346 | msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_SETACL]; |
338 | nfs_fattr_init(&fattr); | 347 | msg.rpc_resp = fattr; |
339 | status = rpc_call_sync(server->client_acl, &msg, 0); | 348 | status = rpc_call_sync(server->client_acl, &msg, 0); |
340 | nfs_access_zap_cache(inode); | 349 | nfs_access_zap_cache(inode); |
341 | nfs_zap_acl_cache(inode); | 350 | nfs_zap_acl_cache(inode); |
@@ -343,7 +352,7 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, | |||
343 | 352 | ||
344 | switch (status) { | 353 | switch (status) { |
345 | case 0: | 354 | case 0: |
346 | status = nfs_refresh_inode(inode, &fattr); | 355 | status = nfs_refresh_inode(inode, fattr); |
347 | nfs3_cache_acls(inode, acl, dfacl); | 356 | nfs3_cache_acls(inode, acl, dfacl); |
348 | break; | 357 | break; |
349 | case -EPFNOSUPPORT: | 358 | case -EPFNOSUPPORT: |
@@ -354,6 +363,7 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, | |||
354 | case -ENOTSUPP: | 363 | case -ENOTSUPP: |
355 | status = -EOPNOTSUPP; | 364 | status = -EOPNOTSUPP; |
356 | } | 365 | } |
366 | nfs_free_fattr(fattr); | ||
357 | out_freepages: | 367 | out_freepages: |
358 | while (args.npages != 0) { | 368 | while (args.npages != 0) { |
359 | args.npages--; | 369 | args.npages--; |
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 3f8881d1a050..fabb4f2849a1 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/errno.h> | 10 | #include <linux/errno.h> |
11 | #include <linux/string.h> | 11 | #include <linux/string.h> |
12 | #include <linux/sunrpc/clnt.h> | 12 | #include <linux/sunrpc/clnt.h> |
13 | #include <linux/slab.h> | ||
13 | #include <linux/nfs.h> | 14 | #include <linux/nfs.h> |
14 | #include <linux/nfs3.h> | 15 | #include <linux/nfs3.h> |
15 | #include <linux/nfs_fs.h> | 16 | #include <linux/nfs_fs.h> |
@@ -22,14 +23,14 @@ | |||
22 | 23 | ||
23 | #define NFSDBG_FACILITY NFSDBG_PROC | 24 | #define NFSDBG_FACILITY NFSDBG_PROC |
24 | 25 | ||
25 | /* A wrapper to handle the EJUKEBOX error message */ | 26 | /* A wrapper to handle the EJUKEBOX and EKEYEXPIRED error messages */ |
26 | static int | 27 | static int |
27 | nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags) | 28 | nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags) |
28 | { | 29 | { |
29 | int res; | 30 | int res; |
30 | do { | 31 | do { |
31 | res = rpc_call_sync(clnt, msg, flags); | 32 | res = rpc_call_sync(clnt, msg, flags); |
32 | if (res != -EJUKEBOX) | 33 | if (res != -EJUKEBOX && res != -EKEYEXPIRED) |
33 | break; | 34 | break; |
34 | schedule_timeout_killable(NFS_JUKEBOX_RETRY_TIME); | 35 | schedule_timeout_killable(NFS_JUKEBOX_RETRY_TIME); |
35 | res = -ERESTARTSYS; | 36 | res = -ERESTARTSYS; |
@@ -42,9 +43,10 @@ nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags) | |||
42 | static int | 43 | static int |
43 | nfs3_async_handle_jukebox(struct rpc_task *task, struct inode *inode) | 44 | nfs3_async_handle_jukebox(struct rpc_task *task, struct inode *inode) |
44 | { | 45 | { |
45 | if (task->tk_status != -EJUKEBOX) | 46 | if (task->tk_status != -EJUKEBOX && task->tk_status != -EKEYEXPIRED) |
46 | return 0; | 47 | return 0; |
47 | nfs_inc_stats(inode, NFSIOS_DELAY); | 48 | if (task->tk_status == -EJUKEBOX) |
49 | nfs_inc_stats(inode, NFSIOS_DELAY); | ||
48 | task->tk_status = 0; | 50 | task->tk_status = 0; |
49 | rpc_restart_call(task); | 51 | rpc_restart_call(task); |
50 | rpc_delay(task, NFS_JUKEBOX_RETRY_TIME); | 52 | rpc_delay(task, NFS_JUKEBOX_RETRY_TIME); |
@@ -142,14 +144,12 @@ static int | |||
142 | nfs3_proc_lookup(struct inode *dir, struct qstr *name, | 144 | nfs3_proc_lookup(struct inode *dir, struct qstr *name, |
143 | struct nfs_fh *fhandle, struct nfs_fattr *fattr) | 145 | struct nfs_fh *fhandle, struct nfs_fattr *fattr) |
144 | { | 146 | { |
145 | struct nfs_fattr dir_attr; | ||
146 | struct nfs3_diropargs arg = { | 147 | struct nfs3_diropargs arg = { |
147 | .fh = NFS_FH(dir), | 148 | .fh = NFS_FH(dir), |
148 | .name = name->name, | 149 | .name = name->name, |
149 | .len = name->len | 150 | .len = name->len |
150 | }; | 151 | }; |
151 | struct nfs3_diropres res = { | 152 | struct nfs3_diropres res = { |
152 | .dir_attr = &dir_attr, | ||
153 | .fh = fhandle, | 153 | .fh = fhandle, |
154 | .fattr = fattr | 154 | .fattr = fattr |
155 | }; | 155 | }; |
@@ -161,29 +161,30 @@ nfs3_proc_lookup(struct inode *dir, struct qstr *name, | |||
161 | int status; | 161 | int status; |
162 | 162 | ||
163 | dprintk("NFS call lookup %s\n", name->name); | 163 | dprintk("NFS call lookup %s\n", name->name); |
164 | nfs_fattr_init(&dir_attr); | 164 | res.dir_attr = nfs_alloc_fattr(); |
165 | if (res.dir_attr == NULL) | ||
166 | return -ENOMEM; | ||
167 | |||
165 | nfs_fattr_init(fattr); | 168 | nfs_fattr_init(fattr); |
166 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 169 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
167 | nfs_refresh_inode(dir, &dir_attr); | 170 | nfs_refresh_inode(dir, res.dir_attr); |
168 | if (status >= 0 && !(fattr->valid & NFS_ATTR_FATTR)) { | 171 | if (status >= 0 && !(fattr->valid & NFS_ATTR_FATTR)) { |
169 | msg.rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR]; | 172 | msg.rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR]; |
170 | msg.rpc_argp = fhandle; | 173 | msg.rpc_argp = fhandle; |
171 | msg.rpc_resp = fattr; | 174 | msg.rpc_resp = fattr; |
172 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 175 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
173 | } | 176 | } |
177 | nfs_free_fattr(res.dir_attr); | ||
174 | dprintk("NFS reply lookup: %d\n", status); | 178 | dprintk("NFS reply lookup: %d\n", status); |
175 | return status; | 179 | return status; |
176 | } | 180 | } |
177 | 181 | ||
178 | static int nfs3_proc_access(struct inode *inode, struct nfs_access_entry *entry) | 182 | static int nfs3_proc_access(struct inode *inode, struct nfs_access_entry *entry) |
179 | { | 183 | { |
180 | struct nfs_fattr fattr; | ||
181 | struct nfs3_accessargs arg = { | 184 | struct nfs3_accessargs arg = { |
182 | .fh = NFS_FH(inode), | 185 | .fh = NFS_FH(inode), |
183 | }; | 186 | }; |
184 | struct nfs3_accessres res = { | 187 | struct nfs3_accessres res; |
185 | .fattr = &fattr, | ||
186 | }; | ||
187 | struct rpc_message msg = { | 188 | struct rpc_message msg = { |
188 | .rpc_proc = &nfs3_procedures[NFS3PROC_ACCESS], | 189 | .rpc_proc = &nfs3_procedures[NFS3PROC_ACCESS], |
189 | .rpc_argp = &arg, | 190 | .rpc_argp = &arg, |
@@ -191,7 +192,7 @@ static int nfs3_proc_access(struct inode *inode, struct nfs_access_entry *entry) | |||
191 | .rpc_cred = entry->cred, | 192 | .rpc_cred = entry->cred, |
192 | }; | 193 | }; |
193 | int mode = entry->mask; | 194 | int mode = entry->mask; |
194 | int status; | 195 | int status = -ENOMEM; |
195 | 196 | ||
196 | dprintk("NFS call access\n"); | 197 | dprintk("NFS call access\n"); |
197 | 198 | ||
@@ -208,9 +209,13 @@ static int nfs3_proc_access(struct inode *inode, struct nfs_access_entry *entry) | |||
208 | if (mode & MAY_EXEC) | 209 | if (mode & MAY_EXEC) |
209 | arg.access |= NFS3_ACCESS_EXECUTE; | 210 | arg.access |= NFS3_ACCESS_EXECUTE; |
210 | } | 211 | } |
211 | nfs_fattr_init(&fattr); | 212 | |
213 | res.fattr = nfs_alloc_fattr(); | ||
214 | if (res.fattr == NULL) | ||
215 | goto out; | ||
216 | |||
212 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | 217 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); |
213 | nfs_refresh_inode(inode, &fattr); | 218 | nfs_refresh_inode(inode, res.fattr); |
214 | if (status == 0) { | 219 | if (status == 0) { |
215 | entry->mask = 0; | 220 | entry->mask = 0; |
216 | if (res.access & NFS3_ACCESS_READ) | 221 | if (res.access & NFS3_ACCESS_READ) |
@@ -220,6 +225,8 @@ static int nfs3_proc_access(struct inode *inode, struct nfs_access_entry *entry) | |||
220 | if (res.access & (NFS3_ACCESS_LOOKUP|NFS3_ACCESS_EXECUTE)) | 225 | if (res.access & (NFS3_ACCESS_LOOKUP|NFS3_ACCESS_EXECUTE)) |
221 | entry->mask |= MAY_EXEC; | 226 | entry->mask |= MAY_EXEC; |
222 | } | 227 | } |
228 | nfs_free_fattr(res.fattr); | ||
229 | out: | ||
223 | dprintk("NFS reply access: %d\n", status); | 230 | dprintk("NFS reply access: %d\n", status); |
224 | return status; | 231 | return status; |
225 | } | 232 | } |
@@ -227,7 +234,7 @@ static int nfs3_proc_access(struct inode *inode, struct nfs_access_entry *entry) | |||
227 | static int nfs3_proc_readlink(struct inode *inode, struct page *page, | 234 | static int nfs3_proc_readlink(struct inode *inode, struct page *page, |
228 | unsigned int pgbase, unsigned int pglen) | 235 | unsigned int pgbase, unsigned int pglen) |
229 | { | 236 | { |
230 | struct nfs_fattr fattr; | 237 | struct nfs_fattr *fattr; |
231 | struct nfs3_readlinkargs args = { | 238 | struct nfs3_readlinkargs args = { |
232 | .fh = NFS_FH(inode), | 239 | .fh = NFS_FH(inode), |
233 | .pgbase = pgbase, | 240 | .pgbase = pgbase, |
@@ -237,14 +244,19 @@ static int nfs3_proc_readlink(struct inode *inode, struct page *page, | |||
237 | struct rpc_message msg = { | 244 | struct rpc_message msg = { |
238 | .rpc_proc = &nfs3_procedures[NFS3PROC_READLINK], | 245 | .rpc_proc = &nfs3_procedures[NFS3PROC_READLINK], |
239 | .rpc_argp = &args, | 246 | .rpc_argp = &args, |
240 | .rpc_resp = &fattr, | ||
241 | }; | 247 | }; |
242 | int status; | 248 | int status = -ENOMEM; |
243 | 249 | ||
244 | dprintk("NFS call readlink\n"); | 250 | dprintk("NFS call readlink\n"); |
245 | nfs_fattr_init(&fattr); | 251 | fattr = nfs_alloc_fattr(); |
252 | if (fattr == NULL) | ||
253 | goto out; | ||
254 | msg.rpc_resp = fattr; | ||
255 | |||
246 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | 256 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); |
247 | nfs_refresh_inode(inode, &fattr); | 257 | nfs_refresh_inode(inode, fattr); |
258 | nfs_free_fattr(fattr); | ||
259 | out: | ||
248 | dprintk("NFS reply readlink: %d\n", status); | 260 | dprintk("NFS reply readlink: %d\n", status); |
249 | return status; | 261 | return status; |
250 | } | 262 | } |
@@ -394,12 +406,17 @@ nfs3_proc_remove(struct inode *dir, struct qstr *name) | |||
394 | .rpc_argp = &arg, | 406 | .rpc_argp = &arg, |
395 | .rpc_resp = &res, | 407 | .rpc_resp = &res, |
396 | }; | 408 | }; |
397 | int status; | 409 | int status = -ENOMEM; |
398 | 410 | ||
399 | dprintk("NFS call remove %s\n", name->name); | 411 | dprintk("NFS call remove %s\n", name->name); |
400 | nfs_fattr_init(&res.dir_attr); | 412 | res.dir_attr = nfs_alloc_fattr(); |
413 | if (res.dir_attr == NULL) | ||
414 | goto out; | ||
415 | |||
401 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 416 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
402 | nfs_post_op_update_inode(dir, &res.dir_attr); | 417 | nfs_post_op_update_inode(dir, res.dir_attr); |
418 | nfs_free_fattr(res.dir_attr); | ||
419 | out: | ||
403 | dprintk("NFS reply remove: %d\n", status); | 420 | dprintk("NFS reply remove: %d\n", status); |
404 | return status; | 421 | return status; |
405 | } | 422 | } |
@@ -417,7 +434,7 @@ nfs3_proc_unlink_done(struct rpc_task *task, struct inode *dir) | |||
417 | if (nfs3_async_handle_jukebox(task, dir)) | 434 | if (nfs3_async_handle_jukebox(task, dir)) |
418 | return 0; | 435 | return 0; |
419 | res = task->tk_msg.rpc_resp; | 436 | res = task->tk_msg.rpc_resp; |
420 | nfs_post_op_update_inode(dir, &res->dir_attr); | 437 | nfs_post_op_update_inode(dir, res->dir_attr); |
421 | return 1; | 438 | return 1; |
422 | } | 439 | } |
423 | 440 | ||
@@ -425,7 +442,6 @@ static int | |||
425 | nfs3_proc_rename(struct inode *old_dir, struct qstr *old_name, | 442 | nfs3_proc_rename(struct inode *old_dir, struct qstr *old_name, |
426 | struct inode *new_dir, struct qstr *new_name) | 443 | struct inode *new_dir, struct qstr *new_name) |
427 | { | 444 | { |
428 | struct nfs_fattr old_dir_attr, new_dir_attr; | ||
429 | struct nfs3_renameargs arg = { | 445 | struct nfs3_renameargs arg = { |
430 | .fromfh = NFS_FH(old_dir), | 446 | .fromfh = NFS_FH(old_dir), |
431 | .fromname = old_name->name, | 447 | .fromname = old_name->name, |
@@ -434,23 +450,27 @@ nfs3_proc_rename(struct inode *old_dir, struct qstr *old_name, | |||
434 | .toname = new_name->name, | 450 | .toname = new_name->name, |
435 | .tolen = new_name->len | 451 | .tolen = new_name->len |
436 | }; | 452 | }; |
437 | struct nfs3_renameres res = { | 453 | struct nfs3_renameres res; |
438 | .fromattr = &old_dir_attr, | ||
439 | .toattr = &new_dir_attr | ||
440 | }; | ||
441 | struct rpc_message msg = { | 454 | struct rpc_message msg = { |
442 | .rpc_proc = &nfs3_procedures[NFS3PROC_RENAME], | 455 | .rpc_proc = &nfs3_procedures[NFS3PROC_RENAME], |
443 | .rpc_argp = &arg, | 456 | .rpc_argp = &arg, |
444 | .rpc_resp = &res, | 457 | .rpc_resp = &res, |
445 | }; | 458 | }; |
446 | int status; | 459 | int status = -ENOMEM; |
447 | 460 | ||
448 | dprintk("NFS call rename %s -> %s\n", old_name->name, new_name->name); | 461 | dprintk("NFS call rename %s -> %s\n", old_name->name, new_name->name); |
449 | nfs_fattr_init(&old_dir_attr); | 462 | |
450 | nfs_fattr_init(&new_dir_attr); | 463 | res.fromattr = nfs_alloc_fattr(); |
464 | res.toattr = nfs_alloc_fattr(); | ||
465 | if (res.fromattr == NULL || res.toattr == NULL) | ||
466 | goto out; | ||
467 | |||
451 | status = rpc_call_sync(NFS_CLIENT(old_dir), &msg, 0); | 468 | status = rpc_call_sync(NFS_CLIENT(old_dir), &msg, 0); |
452 | nfs_post_op_update_inode(old_dir, &old_dir_attr); | 469 | nfs_post_op_update_inode(old_dir, res.fromattr); |
453 | nfs_post_op_update_inode(new_dir, &new_dir_attr); | 470 | nfs_post_op_update_inode(new_dir, res.toattr); |
471 | out: | ||
472 | nfs_free_fattr(res.toattr); | ||
473 | nfs_free_fattr(res.fromattr); | ||
454 | dprintk("NFS reply rename: %d\n", status); | 474 | dprintk("NFS reply rename: %d\n", status); |
455 | return status; | 475 | return status; |
456 | } | 476 | } |
@@ -458,30 +478,32 @@ nfs3_proc_rename(struct inode *old_dir, struct qstr *old_name, | |||
458 | static int | 478 | static int |
459 | nfs3_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) | 479 | nfs3_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) |
460 | { | 480 | { |
461 | struct nfs_fattr dir_attr, fattr; | ||
462 | struct nfs3_linkargs arg = { | 481 | struct nfs3_linkargs arg = { |
463 | .fromfh = NFS_FH(inode), | 482 | .fromfh = NFS_FH(inode), |
464 | .tofh = NFS_FH(dir), | 483 | .tofh = NFS_FH(dir), |
465 | .toname = name->name, | 484 | .toname = name->name, |
466 | .tolen = name->len | 485 | .tolen = name->len |
467 | }; | 486 | }; |
468 | struct nfs3_linkres res = { | 487 | struct nfs3_linkres res; |
469 | .dir_attr = &dir_attr, | ||
470 | .fattr = &fattr | ||
471 | }; | ||
472 | struct rpc_message msg = { | 488 | struct rpc_message msg = { |
473 | .rpc_proc = &nfs3_procedures[NFS3PROC_LINK], | 489 | .rpc_proc = &nfs3_procedures[NFS3PROC_LINK], |
474 | .rpc_argp = &arg, | 490 | .rpc_argp = &arg, |
475 | .rpc_resp = &res, | 491 | .rpc_resp = &res, |
476 | }; | 492 | }; |
477 | int status; | 493 | int status = -ENOMEM; |
478 | 494 | ||
479 | dprintk("NFS call link %s\n", name->name); | 495 | dprintk("NFS call link %s\n", name->name); |
480 | nfs_fattr_init(&dir_attr); | 496 | res.fattr = nfs_alloc_fattr(); |
481 | nfs_fattr_init(&fattr); | 497 | res.dir_attr = nfs_alloc_fattr(); |
498 | if (res.fattr == NULL || res.dir_attr == NULL) | ||
499 | goto out; | ||
500 | |||
482 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | 501 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); |
483 | nfs_post_op_update_inode(dir, &dir_attr); | 502 | nfs_post_op_update_inode(dir, res.dir_attr); |
484 | nfs_post_op_update_inode(inode, &fattr); | 503 | nfs_post_op_update_inode(inode, res.fattr); |
504 | out: | ||
505 | nfs_free_fattr(res.dir_attr); | ||
506 | nfs_free_fattr(res.fattr); | ||
485 | dprintk("NFS reply link: %d\n", status); | 507 | dprintk("NFS reply link: %d\n", status); |
486 | return status; | 508 | return status; |
487 | } | 509 | } |
@@ -552,7 +574,7 @@ out: | |||
552 | static int | 574 | static int |
553 | nfs3_proc_rmdir(struct inode *dir, struct qstr *name) | 575 | nfs3_proc_rmdir(struct inode *dir, struct qstr *name) |
554 | { | 576 | { |
555 | struct nfs_fattr dir_attr; | 577 | struct nfs_fattr *dir_attr; |
556 | struct nfs3_diropargs arg = { | 578 | struct nfs3_diropargs arg = { |
557 | .fh = NFS_FH(dir), | 579 | .fh = NFS_FH(dir), |
558 | .name = name->name, | 580 | .name = name->name, |
@@ -561,14 +583,19 @@ nfs3_proc_rmdir(struct inode *dir, struct qstr *name) | |||
561 | struct rpc_message msg = { | 583 | struct rpc_message msg = { |
562 | .rpc_proc = &nfs3_procedures[NFS3PROC_RMDIR], | 584 | .rpc_proc = &nfs3_procedures[NFS3PROC_RMDIR], |
563 | .rpc_argp = &arg, | 585 | .rpc_argp = &arg, |
564 | .rpc_resp = &dir_attr, | ||
565 | }; | 586 | }; |
566 | int status; | 587 | int status = -ENOMEM; |
567 | 588 | ||
568 | dprintk("NFS call rmdir %s\n", name->name); | 589 | dprintk("NFS call rmdir %s\n", name->name); |
569 | nfs_fattr_init(&dir_attr); | 590 | dir_attr = nfs_alloc_fattr(); |
591 | if (dir_attr == NULL) | ||
592 | goto out; | ||
593 | |||
594 | msg.rpc_resp = dir_attr; | ||
570 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 595 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
571 | nfs_post_op_update_inode(dir, &dir_attr); | 596 | nfs_post_op_update_inode(dir, dir_attr); |
597 | nfs_free_fattr(dir_attr); | ||
598 | out: | ||
572 | dprintk("NFS reply rmdir: %d\n", status); | 599 | dprintk("NFS reply rmdir: %d\n", status); |
573 | return status; | 600 | return status; |
574 | } | 601 | } |
@@ -587,7 +614,6 @@ nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | |||
587 | u64 cookie, struct page *page, unsigned int count, int plus) | 614 | u64 cookie, struct page *page, unsigned int count, int plus) |
588 | { | 615 | { |
589 | struct inode *dir = dentry->d_inode; | 616 | struct inode *dir = dentry->d_inode; |
590 | struct nfs_fattr dir_attr; | ||
591 | __be32 *verf = NFS_COOKIEVERF(dir); | 617 | __be32 *verf = NFS_COOKIEVERF(dir); |
592 | struct nfs3_readdirargs arg = { | 618 | struct nfs3_readdirargs arg = { |
593 | .fh = NFS_FH(dir), | 619 | .fh = NFS_FH(dir), |
@@ -598,7 +624,6 @@ nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | |||
598 | .pages = &page | 624 | .pages = &page |
599 | }; | 625 | }; |
600 | struct nfs3_readdirres res = { | 626 | struct nfs3_readdirres res = { |
601 | .dir_attr = &dir_attr, | ||
602 | .verf = verf, | 627 | .verf = verf, |
603 | .plus = plus | 628 | .plus = plus |
604 | }; | 629 | }; |
@@ -608,7 +633,7 @@ nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | |||
608 | .rpc_resp = &res, | 633 | .rpc_resp = &res, |
609 | .rpc_cred = cred | 634 | .rpc_cred = cred |
610 | }; | 635 | }; |
611 | int status; | 636 | int status = -ENOMEM; |
612 | 637 | ||
613 | if (plus) | 638 | if (plus) |
614 | msg.rpc_proc = &nfs3_procedures[NFS3PROC_READDIRPLUS]; | 639 | msg.rpc_proc = &nfs3_procedures[NFS3PROC_READDIRPLUS]; |
@@ -616,12 +641,17 @@ nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | |||
616 | dprintk("NFS call readdir%s %d\n", | 641 | dprintk("NFS call readdir%s %d\n", |
617 | plus? "plus" : "", (unsigned int) cookie); | 642 | plus? "plus" : "", (unsigned int) cookie); |
618 | 643 | ||
619 | nfs_fattr_init(&dir_attr); | 644 | res.dir_attr = nfs_alloc_fattr(); |
645 | if (res.dir_attr == NULL) | ||
646 | goto out; | ||
647 | |||
620 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 648 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
621 | 649 | ||
622 | nfs_invalidate_atime(dir); | 650 | nfs_invalidate_atime(dir); |
651 | nfs_refresh_inode(dir, res.dir_attr); | ||
623 | 652 | ||
624 | nfs_refresh_inode(dir, &dir_attr); | 653 | nfs_free_fattr(res.dir_attr); |
654 | out: | ||
625 | dprintk("NFS reply readdir: %d\n", status); | 655 | dprintk("NFS reply readdir: %d\n", status); |
626 | return status; | 656 | return status; |
627 | } | 657 | } |
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index 5fe5492fbd29..75dcfc7da365 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c | |||
@@ -9,7 +9,6 @@ | |||
9 | #include <linux/param.h> | 9 | #include <linux/param.h> |
10 | #include <linux/time.h> | 10 | #include <linux/time.h> |
11 | #include <linux/mm.h> | 11 | #include <linux/mm.h> |
12 | #include <linux/slab.h> | ||
13 | #include <linux/errno.h> | 12 | #include <linux/errno.h> |
14 | #include <linux/string.h> | 13 | #include <linux/string.h> |
15 | #include <linux/in.h> | 14 | #include <linux/in.h> |
@@ -763,7 +762,7 @@ nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) | |||
763 | static int | 762 | static int |
764 | nfs3_xdr_removeres(struct rpc_rqst *req, __be32 *p, struct nfs_removeres *res) | 763 | nfs3_xdr_removeres(struct rpc_rqst *req, __be32 *p, struct nfs_removeres *res) |
765 | { | 764 | { |
766 | return nfs3_xdr_wccstat(req, p, &res->dir_attr); | 765 | return nfs3_xdr_wccstat(req, p, res->dir_attr); |
767 | } | 766 | } |
768 | 767 | ||
769 | /* | 768 | /* |
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 865265bdca03..c538c6106e16 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -46,6 +46,7 @@ enum nfs4_client_state { | |||
46 | NFS4CLNT_DELEGRETURN, | 46 | NFS4CLNT_DELEGRETURN, |
47 | NFS4CLNT_SESSION_RESET, | 47 | NFS4CLNT_SESSION_RESET, |
48 | NFS4CLNT_SESSION_DRAINING, | 48 | NFS4CLNT_SESSION_DRAINING, |
49 | NFS4CLNT_RECALL_SLOT, | ||
49 | }; | 50 | }; |
50 | 51 | ||
51 | /* | 52 | /* |
@@ -146,6 +147,7 @@ enum { | |||
146 | NFS_O_RDWR_STATE, /* OPEN stateid has read/write state */ | 147 | NFS_O_RDWR_STATE, /* OPEN stateid has read/write state */ |
147 | NFS_STATE_RECLAIM_REBOOT, /* OPEN stateid server rebooted */ | 148 | NFS_STATE_RECLAIM_REBOOT, /* OPEN stateid server rebooted */ |
148 | NFS_STATE_RECLAIM_NOGRACE, /* OPEN stateid needs to recover state */ | 149 | NFS_STATE_RECLAIM_NOGRACE, /* OPEN stateid needs to recover state */ |
150 | NFS_STATE_POSIX_LOCKS, /* Posix locks are supported */ | ||
149 | }; | 151 | }; |
150 | 152 | ||
151 | struct nfs4_state { | 153 | struct nfs4_state { |
@@ -204,14 +206,14 @@ extern ssize_t nfs4_listxattr(struct dentry *, char *, size_t); | |||
204 | 206 | ||
205 | 207 | ||
206 | /* nfs4proc.c */ | 208 | /* nfs4proc.c */ |
207 | extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struct rpc_cred *); | 209 | extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struct rpc_cred *, struct nfs4_setclientid_res *); |
208 | extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct rpc_cred *); | 210 | extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct nfs4_setclientid_res *arg, struct rpc_cred *); |
209 | extern int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred); | 211 | extern int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred); |
210 | extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *); | 212 | extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *); |
211 | extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *); | 213 | extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *); |
212 | extern int nfs4_init_clientid(struct nfs_client *, struct rpc_cred *); | 214 | extern int nfs4_init_clientid(struct nfs_client *, struct rpc_cred *); |
213 | extern int nfs41_init_clientid(struct nfs_client *, struct rpc_cred *); | 215 | extern int nfs41_init_clientid(struct nfs_client *, struct rpc_cred *); |
214 | extern int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait); | 216 | extern int nfs4_do_close(struct path *path, struct nfs4_state *state, gfp_t gfp_mask, int wait); |
215 | extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); | 217 | extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); |
216 | extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); | 218 | extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); |
217 | extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); | 219 | extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); |
@@ -277,12 +279,14 @@ extern void nfs4_state_set_mode_locked(struct nfs4_state *, fmode_t); | |||
277 | extern void nfs4_schedule_state_recovery(struct nfs_client *); | 279 | extern void nfs4_schedule_state_recovery(struct nfs_client *); |
278 | extern void nfs4_schedule_state_manager(struct nfs_client *); | 280 | extern void nfs4_schedule_state_manager(struct nfs_client *); |
279 | extern int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state); | 281 | extern int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state); |
282 | extern int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_state *state); | ||
280 | extern void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags); | 283 | extern void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags); |
284 | extern void nfs41_handle_recall_slot(struct nfs_client *clp); | ||
281 | extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); | 285 | extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); |
282 | extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); | 286 | extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); |
283 | extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t); | 287 | extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t); |
284 | 288 | ||
285 | extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter); | 289 | extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask); |
286 | extern int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task); | 290 | extern int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task); |
287 | extern void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid); | 291 | extern void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid); |
288 | extern void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid); | 292 | extern void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid); |
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index fa3408f20112..3c2a1724fbd2 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/mount.h> | 11 | #include <linux/mount.h> |
12 | #include <linux/namei.h> | 12 | #include <linux/namei.h> |
13 | #include <linux/nfs_fs.h> | 13 | #include <linux/nfs_fs.h> |
14 | #include <linux/slab.h> | ||
14 | #include <linux/string.h> | 15 | #include <linux/string.h> |
15 | #include <linux/sunrpc/clnt.h> | 16 | #include <linux/sunrpc/clnt.h> |
16 | #include <linux/vfs.h> | 17 | #include <linux/vfs.h> |
@@ -114,6 +115,7 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, | |||
114 | char *page, char *page2, | 115 | char *page, char *page2, |
115 | const struct nfs4_fs_location *location) | 116 | const struct nfs4_fs_location *location) |
116 | { | 117 | { |
118 | const size_t addr_bufsize = sizeof(struct sockaddr_storage); | ||
117 | struct vfsmount *mnt = ERR_PTR(-ENOENT); | 119 | struct vfsmount *mnt = ERR_PTR(-ENOENT); |
118 | char *mnt_path; | 120 | char *mnt_path; |
119 | unsigned int maxbuflen; | 121 | unsigned int maxbuflen; |
@@ -125,9 +127,12 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, | |||
125 | mountdata->mnt_path = mnt_path; | 127 | mountdata->mnt_path = mnt_path; |
126 | maxbuflen = mnt_path - 1 - page2; | 128 | maxbuflen = mnt_path - 1 - page2; |
127 | 129 | ||
130 | mountdata->addr = kmalloc(addr_bufsize, GFP_KERNEL); | ||
131 | if (mountdata->addr == NULL) | ||
132 | return ERR_PTR(-ENOMEM); | ||
133 | |||
128 | for (s = 0; s < location->nservers; s++) { | 134 | for (s = 0; s < location->nservers; s++) { |
129 | const struct nfs4_string *buf = &location->servers[s]; | 135 | const struct nfs4_string *buf = &location->servers[s]; |
130 | struct sockaddr_storage addr; | ||
131 | 136 | ||
132 | if (buf->len <= 0 || buf->len >= maxbuflen) | 137 | if (buf->len <= 0 || buf->len >= maxbuflen) |
133 | continue; | 138 | continue; |
@@ -136,11 +141,10 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, | |||
136 | continue; | 141 | continue; |
137 | 142 | ||
138 | mountdata->addrlen = nfs_parse_server_name(buf->data, buf->len, | 143 | mountdata->addrlen = nfs_parse_server_name(buf->data, buf->len, |
139 | (struct sockaddr *)&addr, sizeof(addr)); | 144 | mountdata->addr, addr_bufsize); |
140 | if (mountdata->addrlen == 0) | 145 | if (mountdata->addrlen == 0) |
141 | continue; | 146 | continue; |
142 | 147 | ||
143 | mountdata->addr = (struct sockaddr *)&addr; | ||
144 | rpc_set_port(mountdata->addr, NFS_PORT); | 148 | rpc_set_port(mountdata->addr, NFS_PORT); |
145 | 149 | ||
146 | memcpy(page2, buf->data, buf->len); | 150 | memcpy(page2, buf->data, buf->len); |
@@ -155,6 +159,7 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, | |||
155 | if (!IS_ERR(mnt)) | 159 | if (!IS_ERR(mnt)) |
156 | break; | 160 | break; |
157 | } | 161 | } |
162 | kfree(mountdata->addr); | ||
158 | return mnt; | 163 | return mnt; |
159 | } | 164 | } |
160 | 165 | ||
@@ -220,8 +225,8 @@ out: | |||
220 | 225 | ||
221 | /* | 226 | /* |
222 | * nfs_do_refmount - handle crossing a referral on server | 227 | * nfs_do_refmount - handle crossing a referral on server |
228 | * @mnt_parent - mountpoint of referral | ||
223 | * @dentry - dentry of referral | 229 | * @dentry - dentry of referral |
224 | * @nd - nameidata info | ||
225 | * | 230 | * |
226 | */ | 231 | */ |
227 | struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry) | 232 | struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry) |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 198d51d17c13..70015dd60a98 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <linux/delay.h> | 39 | #include <linux/delay.h> |
40 | #include <linux/errno.h> | 40 | #include <linux/errno.h> |
41 | #include <linux/string.h> | 41 | #include <linux/string.h> |
42 | #include <linux/slab.h> | ||
42 | #include <linux/sunrpc/clnt.h> | 43 | #include <linux/sunrpc/clnt.h> |
43 | #include <linux/nfs.h> | 44 | #include <linux/nfs.h> |
44 | #include <linux/nfs4.h> | 45 | #include <linux/nfs4.h> |
@@ -69,6 +70,9 @@ static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinf | |||
69 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *); | 70 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *); |
70 | static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr); | 71 | static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr); |
71 | static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr); | 72 | static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr); |
73 | static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, | ||
74 | struct nfs_fattr *fattr, struct iattr *sattr, | ||
75 | struct nfs4_state *state); | ||
72 | 76 | ||
73 | /* Prevent leaks of NFSv4 errors into userland */ | 77 | /* Prevent leaks of NFSv4 errors into userland */ |
74 | static int nfs4_map_errors(int err) | 78 | static int nfs4_map_errors(int err) |
@@ -249,19 +253,15 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, | |||
249 | if (state == NULL) | 253 | if (state == NULL) |
250 | break; | 254 | break; |
251 | nfs4_state_mark_reclaim_nograce(clp, state); | 255 | nfs4_state_mark_reclaim_nograce(clp, state); |
252 | case -NFS4ERR_STALE_CLIENTID: | 256 | goto do_state_recovery; |
253 | case -NFS4ERR_STALE_STATEID: | 257 | case -NFS4ERR_STALE_STATEID: |
254 | case -NFS4ERR_EXPIRED: | 258 | if (state == NULL) |
255 | nfs4_schedule_state_recovery(clp); | ||
256 | ret = nfs4_wait_clnt_recover(clp); | ||
257 | if (ret == 0) | ||
258 | exception->retry = 1; | ||
259 | #if !defined(CONFIG_NFS_V4_1) | ||
260 | break; | ||
261 | #else /* !defined(CONFIG_NFS_V4_1) */ | ||
262 | if (!nfs4_has_session(server->nfs_client)) | ||
263 | break; | 259 | break; |
264 | /* FALLTHROUGH */ | 260 | nfs4_state_mark_reclaim_reboot(clp, state); |
261 | case -NFS4ERR_STALE_CLIENTID: | ||
262 | case -NFS4ERR_EXPIRED: | ||
263 | goto do_state_recovery; | ||
264 | #if defined(CONFIG_NFS_V4_1) | ||
265 | case -NFS4ERR_BADSESSION: | 265 | case -NFS4ERR_BADSESSION: |
266 | case -NFS4ERR_BADSLOT: | 266 | case -NFS4ERR_BADSLOT: |
267 | case -NFS4ERR_BAD_HIGH_SLOT: | 267 | case -NFS4ERR_BAD_HIGH_SLOT: |
@@ -274,7 +274,7 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, | |||
274 | nfs4_schedule_state_recovery(clp); | 274 | nfs4_schedule_state_recovery(clp); |
275 | exception->retry = 1; | 275 | exception->retry = 1; |
276 | break; | 276 | break; |
277 | #endif /* !defined(CONFIG_NFS_V4_1) */ | 277 | #endif /* defined(CONFIG_NFS_V4_1) */ |
278 | case -NFS4ERR_FILE_OPEN: | 278 | case -NFS4ERR_FILE_OPEN: |
279 | if (exception->timeout > HZ) { | 279 | if (exception->timeout > HZ) { |
280 | /* We have retried a decent amount, time to | 280 | /* We have retried a decent amount, time to |
@@ -285,6 +285,7 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, | |||
285 | } | 285 | } |
286 | case -NFS4ERR_GRACE: | 286 | case -NFS4ERR_GRACE: |
287 | case -NFS4ERR_DELAY: | 287 | case -NFS4ERR_DELAY: |
288 | case -EKEYEXPIRED: | ||
288 | ret = nfs4_delay(server->client, &exception->timeout); | 289 | ret = nfs4_delay(server->client, &exception->timeout); |
289 | if (ret != 0) | 290 | if (ret != 0) |
290 | break; | 291 | break; |
@@ -293,6 +294,12 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, | |||
293 | } | 294 | } |
294 | /* We failed to handle the error */ | 295 | /* We failed to handle the error */ |
295 | return nfs4_map_errors(ret); | 296 | return nfs4_map_errors(ret); |
297 | do_state_recovery: | ||
298 | nfs4_schedule_state_recovery(clp); | ||
299 | ret = nfs4_wait_clnt_recover(clp); | ||
300 | if (ret == 0) | ||
301 | exception->retry = 1; | ||
302 | return ret; | ||
296 | } | 303 | } |
297 | 304 | ||
298 | 305 | ||
@@ -416,7 +423,8 @@ static void nfs41_sequence_done(struct nfs_client *clp, | |||
416 | clp->cl_last_renewal = timestamp; | 423 | clp->cl_last_renewal = timestamp; |
417 | spin_unlock(&clp->cl_lock); | 424 | spin_unlock(&clp->cl_lock); |
418 | /* Check sequence flags */ | 425 | /* Check sequence flags */ |
419 | nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags); | 426 | if (atomic_read(&clp->cl_count) > 1) |
427 | nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags); | ||
420 | } | 428 | } |
421 | out: | 429 | out: |
422 | /* The session may be reset by one of the error handlers. */ | 430 | /* The session may be reset by one of the error handlers. */ |
@@ -709,21 +717,22 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p) | |||
709 | 717 | ||
710 | static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, | 718 | static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, |
711 | struct nfs4_state_owner *sp, fmode_t fmode, int flags, | 719 | struct nfs4_state_owner *sp, fmode_t fmode, int flags, |
712 | const struct iattr *attrs) | 720 | const struct iattr *attrs, |
721 | gfp_t gfp_mask) | ||
713 | { | 722 | { |
714 | struct dentry *parent = dget_parent(path->dentry); | 723 | struct dentry *parent = dget_parent(path->dentry); |
715 | struct inode *dir = parent->d_inode; | 724 | struct inode *dir = parent->d_inode; |
716 | struct nfs_server *server = NFS_SERVER(dir); | 725 | struct nfs_server *server = NFS_SERVER(dir); |
717 | struct nfs4_opendata *p; | 726 | struct nfs4_opendata *p; |
718 | 727 | ||
719 | p = kzalloc(sizeof(*p), GFP_KERNEL); | 728 | p = kzalloc(sizeof(*p), gfp_mask); |
720 | if (p == NULL) | 729 | if (p == NULL) |
721 | goto err; | 730 | goto err; |
722 | p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid); | 731 | p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid, gfp_mask); |
723 | if (p->o_arg.seqid == NULL) | 732 | if (p->o_arg.seqid == NULL) |
724 | goto err_free; | 733 | goto err_free; |
725 | p->path.mnt = mntget(path->mnt); | 734 | path_get(path); |
726 | p->path.dentry = dget(path->dentry); | 735 | p->path = *path; |
727 | p->dir = parent; | 736 | p->dir = parent; |
728 | p->owner = sp; | 737 | p->owner = sp; |
729 | atomic_inc(&sp->so_count); | 738 | atomic_inc(&sp->so_count); |
@@ -1055,7 +1064,7 @@ static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context | |||
1055 | { | 1064 | { |
1056 | struct nfs4_opendata *opendata; | 1065 | struct nfs4_opendata *opendata; |
1057 | 1066 | ||
1058 | opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, 0, NULL); | 1067 | opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, 0, NULL, GFP_NOFS); |
1059 | if (opendata == NULL) | 1068 | if (opendata == NULL) |
1060 | return ERR_PTR(-ENOMEM); | 1069 | return ERR_PTR(-ENOMEM); |
1061 | opendata->state = state; | 1070 | opendata->state = state; |
@@ -1161,7 +1170,7 @@ static int nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state | |||
1161 | int err; | 1170 | int err; |
1162 | do { | 1171 | do { |
1163 | err = _nfs4_do_open_reclaim(ctx, state); | 1172 | err = _nfs4_do_open_reclaim(ctx, state); |
1164 | if (err != -NFS4ERR_DELAY) | 1173 | if (err != -NFS4ERR_DELAY && err != -EKEYEXPIRED) |
1165 | break; | 1174 | break; |
1166 | nfs4_handle_exception(server, err, &exception); | 1175 | nfs4_handle_exception(server, err, &exception); |
1167 | } while (exception.retry); | 1176 | } while (exception.retry); |
@@ -1518,6 +1527,8 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) | |||
1518 | nfs_post_op_update_inode(dir, o_res->dir_attr); | 1527 | nfs_post_op_update_inode(dir, o_res->dir_attr); |
1519 | } else | 1528 | } else |
1520 | nfs_refresh_inode(dir, o_res->dir_attr); | 1529 | nfs_refresh_inode(dir, o_res->dir_attr); |
1530 | if ((o_res->rflags & NFS4_OPEN_RESULT_LOCKTYPE_POSIX) == 0) | ||
1531 | server->caps &= ~NFS_CAP_POSIX_LOCK; | ||
1521 | if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) { | 1532 | if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) { |
1522 | status = _nfs4_proc_open_confirm(data); | 1533 | status = _nfs4_proc_open_confirm(data); |
1523 | if (status != 0) | 1534 | if (status != 0) |
@@ -1580,6 +1591,7 @@ static int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4_state | |||
1580 | goto out; | 1591 | goto out; |
1581 | case -NFS4ERR_GRACE: | 1592 | case -NFS4ERR_GRACE: |
1582 | case -NFS4ERR_DELAY: | 1593 | case -NFS4ERR_DELAY: |
1594 | case -EKEYEXPIRED: | ||
1583 | nfs4_handle_exception(server, err, &exception); | 1595 | nfs4_handle_exception(server, err, &exception); |
1584 | err = 0; | 1596 | err = 0; |
1585 | } | 1597 | } |
@@ -1640,7 +1652,7 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, fmode_t fmode, in | |||
1640 | if (path->dentry->d_inode != NULL) | 1652 | if (path->dentry->d_inode != NULL) |
1641 | nfs4_return_incompatible_delegation(path->dentry->d_inode, fmode); | 1653 | nfs4_return_incompatible_delegation(path->dentry->d_inode, fmode); |
1642 | status = -ENOMEM; | 1654 | status = -ENOMEM; |
1643 | opendata = nfs4_opendata_alloc(path, sp, fmode, flags, sattr); | 1655 | opendata = nfs4_opendata_alloc(path, sp, fmode, flags, sattr, GFP_KERNEL); |
1644 | if (opendata == NULL) | 1656 | if (opendata == NULL) |
1645 | goto err_put_state_owner; | 1657 | goto err_put_state_owner; |
1646 | 1658 | ||
@@ -1651,13 +1663,24 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, fmode_t fmode, in | |||
1651 | if (status != 0) | 1663 | if (status != 0) |
1652 | goto err_opendata_put; | 1664 | goto err_opendata_put; |
1653 | 1665 | ||
1654 | if (opendata->o_arg.open_flags & O_EXCL) | ||
1655 | nfs4_exclusive_attrset(opendata, sattr); | ||
1656 | |||
1657 | state = nfs4_opendata_to_nfs4_state(opendata); | 1666 | state = nfs4_opendata_to_nfs4_state(opendata); |
1658 | status = PTR_ERR(state); | 1667 | status = PTR_ERR(state); |
1659 | if (IS_ERR(state)) | 1668 | if (IS_ERR(state)) |
1660 | goto err_opendata_put; | 1669 | goto err_opendata_put; |
1670 | if (server->caps & NFS_CAP_POSIX_LOCK) | ||
1671 | set_bit(NFS_STATE_POSIX_LOCKS, &state->flags); | ||
1672 | |||
1673 | if (opendata->o_arg.open_flags & O_EXCL) { | ||
1674 | nfs4_exclusive_attrset(opendata, sattr); | ||
1675 | |||
1676 | nfs_fattr_init(opendata->o_res.f_attr); | ||
1677 | status = nfs4_do_setattr(state->inode, cred, | ||
1678 | opendata->o_res.f_attr, sattr, | ||
1679 | state); | ||
1680 | if (status == 0) | ||
1681 | nfs_setattr_update_inode(state->inode, sattr); | ||
1682 | nfs_post_op_update_inode(state->inode, opendata->o_res.f_attr); | ||
1683 | } | ||
1661 | nfs4_opendata_put(opendata); | 1684 | nfs4_opendata_put(opendata); |
1662 | nfs4_put_state_owner(sp); | 1685 | nfs4_put_state_owner(sp); |
1663 | *res = state; | 1686 | *res = state; |
@@ -1904,7 +1927,7 @@ static const struct rpc_call_ops nfs4_close_ops = { | |||
1904 | * | 1927 | * |
1905 | * NOTE: Caller must be holding the sp->so_owner semaphore! | 1928 | * NOTE: Caller must be holding the sp->so_owner semaphore! |
1906 | */ | 1929 | */ |
1907 | int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | 1930 | int nfs4_do_close(struct path *path, struct nfs4_state *state, gfp_t gfp_mask, int wait) |
1908 | { | 1931 | { |
1909 | struct nfs_server *server = NFS_SERVER(state->inode); | 1932 | struct nfs_server *server = NFS_SERVER(state->inode); |
1910 | struct nfs4_closedata *calldata; | 1933 | struct nfs4_closedata *calldata; |
@@ -1923,7 +1946,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
1923 | }; | 1946 | }; |
1924 | int status = -ENOMEM; | 1947 | int status = -ENOMEM; |
1925 | 1948 | ||
1926 | calldata = kzalloc(sizeof(*calldata), GFP_KERNEL); | 1949 | calldata = kzalloc(sizeof(*calldata), gfp_mask); |
1927 | if (calldata == NULL) | 1950 | if (calldata == NULL) |
1928 | goto out; | 1951 | goto out; |
1929 | calldata->inode = state->inode; | 1952 | calldata->inode = state->inode; |
@@ -1931,7 +1954,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
1931 | calldata->arg.fh = NFS_FH(state->inode); | 1954 | calldata->arg.fh = NFS_FH(state->inode); |
1932 | calldata->arg.stateid = &state->open_stateid; | 1955 | calldata->arg.stateid = &state->open_stateid; |
1933 | /* Serialization for the sequence id */ | 1956 | /* Serialization for the sequence id */ |
1934 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); | 1957 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid, gfp_mask); |
1935 | if (calldata->arg.seqid == NULL) | 1958 | if (calldata->arg.seqid == NULL) |
1936 | goto out_free_calldata; | 1959 | goto out_free_calldata; |
1937 | calldata->arg.fmode = 0; | 1960 | calldata->arg.fmode = 0; |
@@ -1940,8 +1963,8 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
1940 | calldata->res.seqid = calldata->arg.seqid; | 1963 | calldata->res.seqid = calldata->arg.seqid; |
1941 | calldata->res.server = server; | 1964 | calldata->res.server = server; |
1942 | calldata->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | 1965 | calldata->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; |
1943 | calldata->path.mnt = mntget(path->mnt); | 1966 | path_get(path); |
1944 | calldata->path.dentry = dget(path->dentry); | 1967 | calldata->path = *path; |
1945 | 1968 | ||
1946 | msg.rpc_argp = &calldata->arg, | 1969 | msg.rpc_argp = &calldata->arg, |
1947 | msg.rpc_resp = &calldata->res, | 1970 | msg.rpc_resp = &calldata->res, |
@@ -2060,8 +2083,7 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st | |||
2060 | case -EDQUOT: | 2083 | case -EDQUOT: |
2061 | case -ENOSPC: | 2084 | case -ENOSPC: |
2062 | case -EROFS: | 2085 | case -EROFS: |
2063 | lookup_instantiate_filp(nd, (struct dentry *)state, NULL); | 2086 | return PTR_ERR(state); |
2064 | return 1; | ||
2065 | default: | 2087 | default: |
2066 | goto out_drop; | 2088 | goto out_drop; |
2067 | } | 2089 | } |
@@ -2395,14 +2417,12 @@ static int nfs4_proc_lookup(struct inode *dir, struct qstr *name, struct nfs_fh | |||
2395 | static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry) | 2417 | static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry) |
2396 | { | 2418 | { |
2397 | struct nfs_server *server = NFS_SERVER(inode); | 2419 | struct nfs_server *server = NFS_SERVER(inode); |
2398 | struct nfs_fattr fattr; | ||
2399 | struct nfs4_accessargs args = { | 2420 | struct nfs4_accessargs args = { |
2400 | .fh = NFS_FH(inode), | 2421 | .fh = NFS_FH(inode), |
2401 | .bitmask = server->attr_bitmask, | 2422 | .bitmask = server->attr_bitmask, |
2402 | }; | 2423 | }; |
2403 | struct nfs4_accessres res = { | 2424 | struct nfs4_accessres res = { |
2404 | .server = server, | 2425 | .server = server, |
2405 | .fattr = &fattr, | ||
2406 | }; | 2426 | }; |
2407 | struct rpc_message msg = { | 2427 | struct rpc_message msg = { |
2408 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ACCESS], | 2428 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ACCESS], |
@@ -2429,7 +2449,11 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry | |||
2429 | if (mode & MAY_EXEC) | 2449 | if (mode & MAY_EXEC) |
2430 | args.access |= NFS4_ACCESS_EXECUTE; | 2450 | args.access |= NFS4_ACCESS_EXECUTE; |
2431 | } | 2451 | } |
2432 | nfs_fattr_init(&fattr); | 2452 | |
2453 | res.fattr = nfs_alloc_fattr(); | ||
2454 | if (res.fattr == NULL) | ||
2455 | return -ENOMEM; | ||
2456 | |||
2433 | status = nfs4_call_sync(server, &msg, &args, &res, 0); | 2457 | status = nfs4_call_sync(server, &msg, &args, &res, 0); |
2434 | if (!status) { | 2458 | if (!status) { |
2435 | entry->mask = 0; | 2459 | entry->mask = 0; |
@@ -2439,8 +2463,9 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry | |||
2439 | entry->mask |= MAY_WRITE; | 2463 | entry->mask |= MAY_WRITE; |
2440 | if (res.access & (NFS4_ACCESS_LOOKUP|NFS4_ACCESS_EXECUTE)) | 2464 | if (res.access & (NFS4_ACCESS_LOOKUP|NFS4_ACCESS_EXECUTE)) |
2441 | entry->mask |= MAY_EXEC; | 2465 | entry->mask |= MAY_EXEC; |
2442 | nfs_refresh_inode(inode, &fattr); | 2466 | nfs_refresh_inode(inode, res.fattr); |
2443 | } | 2467 | } |
2468 | nfs_free_fattr(res.fattr); | ||
2444 | return status; | 2469 | return status; |
2445 | } | 2470 | } |
2446 | 2471 | ||
@@ -2553,13 +2578,6 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
2553 | } | 2578 | } |
2554 | d_add(dentry, igrab(state->inode)); | 2579 | d_add(dentry, igrab(state->inode)); |
2555 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | 2580 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); |
2556 | if (flags & O_EXCL) { | ||
2557 | struct nfs_fattr fattr; | ||
2558 | status = nfs4_do_setattr(state->inode, cred, &fattr, sattr, state); | ||
2559 | if (status == 0) | ||
2560 | nfs_setattr_update_inode(state->inode, sattr); | ||
2561 | nfs_post_op_update_inode(state->inode, &fattr); | ||
2562 | } | ||
2563 | if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0) | 2581 | if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0) |
2564 | status = nfs4_intent_set_file(nd, &path, state, fmode); | 2582 | status = nfs4_intent_set_file(nd, &path, state, fmode); |
2565 | else | 2583 | else |
@@ -2587,14 +2605,19 @@ static int _nfs4_proc_remove(struct inode *dir, struct qstr *name) | |||
2587 | .rpc_argp = &args, | 2605 | .rpc_argp = &args, |
2588 | .rpc_resp = &res, | 2606 | .rpc_resp = &res, |
2589 | }; | 2607 | }; |
2590 | int status; | 2608 | int status = -ENOMEM; |
2609 | |||
2610 | res.dir_attr = nfs_alloc_fattr(); | ||
2611 | if (res.dir_attr == NULL) | ||
2612 | goto out; | ||
2591 | 2613 | ||
2592 | nfs_fattr_init(&res.dir_attr); | ||
2593 | status = nfs4_call_sync(server, &msg, &args, &res, 1); | 2614 | status = nfs4_call_sync(server, &msg, &args, &res, 1); |
2594 | if (status == 0) { | 2615 | if (status == 0) { |
2595 | update_changeattr(dir, &res.cinfo); | 2616 | update_changeattr(dir, &res.cinfo); |
2596 | nfs_post_op_update_inode(dir, &res.dir_attr); | 2617 | nfs_post_op_update_inode(dir, res.dir_attr); |
2597 | } | 2618 | } |
2619 | nfs_free_fattr(res.dir_attr); | ||
2620 | out: | ||
2598 | return status; | 2621 | return status; |
2599 | } | 2622 | } |
2600 | 2623 | ||
@@ -2629,7 +2652,7 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir) | |||
2629 | if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN) | 2652 | if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN) |
2630 | return 0; | 2653 | return 0; |
2631 | update_changeattr(dir, &res->cinfo); | 2654 | update_changeattr(dir, &res->cinfo); |
2632 | nfs_post_op_update_inode(dir, &res->dir_attr); | 2655 | nfs_post_op_update_inode(dir, res->dir_attr); |
2633 | return 1; | 2656 | return 1; |
2634 | } | 2657 | } |
2635 | 2658 | ||
@@ -2644,29 +2667,31 @@ static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, | |||
2644 | .new_name = new_name, | 2667 | .new_name = new_name, |
2645 | .bitmask = server->attr_bitmask, | 2668 | .bitmask = server->attr_bitmask, |
2646 | }; | 2669 | }; |
2647 | struct nfs_fattr old_fattr, new_fattr; | ||
2648 | struct nfs4_rename_res res = { | 2670 | struct nfs4_rename_res res = { |
2649 | .server = server, | 2671 | .server = server, |
2650 | .old_fattr = &old_fattr, | ||
2651 | .new_fattr = &new_fattr, | ||
2652 | }; | 2672 | }; |
2653 | struct rpc_message msg = { | 2673 | struct rpc_message msg = { |
2654 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME], | 2674 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME], |
2655 | .rpc_argp = &arg, | 2675 | .rpc_argp = &arg, |
2656 | .rpc_resp = &res, | 2676 | .rpc_resp = &res, |
2657 | }; | 2677 | }; |
2658 | int status; | 2678 | int status = -ENOMEM; |
2659 | 2679 | ||
2660 | nfs_fattr_init(res.old_fattr); | 2680 | res.old_fattr = nfs_alloc_fattr(); |
2661 | nfs_fattr_init(res.new_fattr); | 2681 | res.new_fattr = nfs_alloc_fattr(); |
2662 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); | 2682 | if (res.old_fattr == NULL || res.new_fattr == NULL) |
2683 | goto out; | ||
2663 | 2684 | ||
2685 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); | ||
2664 | if (!status) { | 2686 | if (!status) { |
2665 | update_changeattr(old_dir, &res.old_cinfo); | 2687 | update_changeattr(old_dir, &res.old_cinfo); |
2666 | nfs_post_op_update_inode(old_dir, res.old_fattr); | 2688 | nfs_post_op_update_inode(old_dir, res.old_fattr); |
2667 | update_changeattr(new_dir, &res.new_cinfo); | 2689 | update_changeattr(new_dir, &res.new_cinfo); |
2668 | nfs_post_op_update_inode(new_dir, res.new_fattr); | 2690 | nfs_post_op_update_inode(new_dir, res.new_fattr); |
2669 | } | 2691 | } |
2692 | out: | ||
2693 | nfs_free_fattr(res.new_fattr); | ||
2694 | nfs_free_fattr(res.old_fattr); | ||
2670 | return status; | 2695 | return status; |
2671 | } | 2696 | } |
2672 | 2697 | ||
@@ -2693,28 +2718,30 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr * | |||
2693 | .name = name, | 2718 | .name = name, |
2694 | .bitmask = server->attr_bitmask, | 2719 | .bitmask = server->attr_bitmask, |
2695 | }; | 2720 | }; |
2696 | struct nfs_fattr fattr, dir_attr; | ||
2697 | struct nfs4_link_res res = { | 2721 | struct nfs4_link_res res = { |
2698 | .server = server, | 2722 | .server = server, |
2699 | .fattr = &fattr, | ||
2700 | .dir_attr = &dir_attr, | ||
2701 | }; | 2723 | }; |
2702 | struct rpc_message msg = { | 2724 | struct rpc_message msg = { |
2703 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LINK], | 2725 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LINK], |
2704 | .rpc_argp = &arg, | 2726 | .rpc_argp = &arg, |
2705 | .rpc_resp = &res, | 2727 | .rpc_resp = &res, |
2706 | }; | 2728 | }; |
2707 | int status; | 2729 | int status = -ENOMEM; |
2730 | |||
2731 | res.fattr = nfs_alloc_fattr(); | ||
2732 | res.dir_attr = nfs_alloc_fattr(); | ||
2733 | if (res.fattr == NULL || res.dir_attr == NULL) | ||
2734 | goto out; | ||
2708 | 2735 | ||
2709 | nfs_fattr_init(res.fattr); | ||
2710 | nfs_fattr_init(res.dir_attr); | ||
2711 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); | 2736 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); |
2712 | if (!status) { | 2737 | if (!status) { |
2713 | update_changeattr(dir, &res.cinfo); | 2738 | update_changeattr(dir, &res.cinfo); |
2714 | nfs_post_op_update_inode(dir, res.dir_attr); | 2739 | nfs_post_op_update_inode(dir, res.dir_attr); |
2715 | nfs_post_op_update_inode(inode, res.fattr); | 2740 | nfs_post_op_update_inode(inode, res.fattr); |
2716 | } | 2741 | } |
2717 | 2742 | out: | |
2743 | nfs_free_fattr(res.dir_attr); | ||
2744 | nfs_free_fattr(res.fattr); | ||
2718 | return status; | 2745 | return status; |
2719 | } | 2746 | } |
2720 | 2747 | ||
@@ -3137,14 +3164,31 @@ static void nfs4_proc_commit_setup(struct nfs_write_data *data, struct rpc_messa | |||
3137 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT]; | 3164 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT]; |
3138 | } | 3165 | } |
3139 | 3166 | ||
3167 | struct nfs4_renewdata { | ||
3168 | struct nfs_client *client; | ||
3169 | unsigned long timestamp; | ||
3170 | }; | ||
3171 | |||
3140 | /* | 3172 | /* |
3141 | * nfs4_proc_async_renew(): This is not one of the nfs_rpc_ops; it is a special | 3173 | * nfs4_proc_async_renew(): This is not one of the nfs_rpc_ops; it is a special |
3142 | * standalone procedure for queueing an asynchronous RENEW. | 3174 | * standalone procedure for queueing an asynchronous RENEW. |
3143 | */ | 3175 | */ |
3144 | static void nfs4_renew_done(struct rpc_task *task, void *data) | 3176 | static void nfs4_renew_release(void *calldata) |
3145 | { | 3177 | { |
3146 | struct nfs_client *clp = (struct nfs_client *)task->tk_msg.rpc_argp; | 3178 | struct nfs4_renewdata *data = calldata; |
3147 | unsigned long timestamp = (unsigned long)data; | 3179 | struct nfs_client *clp = data->client; |
3180 | |||
3181 | if (atomic_read(&clp->cl_count) > 1) | ||
3182 | nfs4_schedule_state_renewal(clp); | ||
3183 | nfs_put_client(clp); | ||
3184 | kfree(data); | ||
3185 | } | ||
3186 | |||
3187 | static void nfs4_renew_done(struct rpc_task *task, void *calldata) | ||
3188 | { | ||
3189 | struct nfs4_renewdata *data = calldata; | ||
3190 | struct nfs_client *clp = data->client; | ||
3191 | unsigned long timestamp = data->timestamp; | ||
3148 | 3192 | ||
3149 | if (task->tk_status < 0) { | 3193 | if (task->tk_status < 0) { |
3150 | /* Unless we're shutting down, schedule state recovery! */ | 3194 | /* Unless we're shutting down, schedule state recovery! */ |
@@ -3160,6 +3204,7 @@ static void nfs4_renew_done(struct rpc_task *task, void *data) | |||
3160 | 3204 | ||
3161 | static const struct rpc_call_ops nfs4_renew_ops = { | 3205 | static const struct rpc_call_ops nfs4_renew_ops = { |
3162 | .rpc_call_done = nfs4_renew_done, | 3206 | .rpc_call_done = nfs4_renew_done, |
3207 | .rpc_release = nfs4_renew_release, | ||
3163 | }; | 3208 | }; |
3164 | 3209 | ||
3165 | int nfs4_proc_async_renew(struct nfs_client *clp, struct rpc_cred *cred) | 3210 | int nfs4_proc_async_renew(struct nfs_client *clp, struct rpc_cred *cred) |
@@ -3169,9 +3214,17 @@ int nfs4_proc_async_renew(struct nfs_client *clp, struct rpc_cred *cred) | |||
3169 | .rpc_argp = clp, | 3214 | .rpc_argp = clp, |
3170 | .rpc_cred = cred, | 3215 | .rpc_cred = cred, |
3171 | }; | 3216 | }; |
3217 | struct nfs4_renewdata *data; | ||
3172 | 3218 | ||
3219 | if (!atomic_inc_not_zero(&clp->cl_count)) | ||
3220 | return -EIO; | ||
3221 | data = kmalloc(sizeof(*data), GFP_KERNEL); | ||
3222 | if (data == NULL) | ||
3223 | return -ENOMEM; | ||
3224 | data->client = clp; | ||
3225 | data->timestamp = jiffies; | ||
3173 | return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT, | 3226 | return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT, |
3174 | &nfs4_renew_ops, (void *)jiffies); | 3227 | &nfs4_renew_ops, data); |
3175 | } | 3228 | } |
3176 | 3229 | ||
3177 | int nfs4_proc_renew(struct nfs_client *clp, struct rpc_cred *cred) | 3230 | int nfs4_proc_renew(struct nfs_client *clp, struct rpc_cred *cred) |
@@ -3422,15 +3475,14 @@ _nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
3422 | if (state == NULL) | 3475 | if (state == NULL) |
3423 | break; | 3476 | break; |
3424 | nfs4_state_mark_reclaim_nograce(clp, state); | 3477 | nfs4_state_mark_reclaim_nograce(clp, state); |
3425 | case -NFS4ERR_STALE_CLIENTID: | 3478 | goto do_state_recovery; |
3426 | case -NFS4ERR_STALE_STATEID: | 3479 | case -NFS4ERR_STALE_STATEID: |
3480 | if (state == NULL) | ||
3481 | break; | ||
3482 | nfs4_state_mark_reclaim_reboot(clp, state); | ||
3483 | case -NFS4ERR_STALE_CLIENTID: | ||
3427 | case -NFS4ERR_EXPIRED: | 3484 | case -NFS4ERR_EXPIRED: |
3428 | rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL); | 3485 | goto do_state_recovery; |
3429 | nfs4_schedule_state_recovery(clp); | ||
3430 | if (test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) == 0) | ||
3431 | rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task); | ||
3432 | task->tk_status = 0; | ||
3433 | return -EAGAIN; | ||
3434 | #if defined(CONFIG_NFS_V4_1) | 3486 | #if defined(CONFIG_NFS_V4_1) |
3435 | case -NFS4ERR_BADSESSION: | 3487 | case -NFS4ERR_BADSESSION: |
3436 | case -NFS4ERR_BADSLOT: | 3488 | case -NFS4ERR_BADSLOT: |
@@ -3449,6 +3501,7 @@ _nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
3449 | if (server) | 3501 | if (server) |
3450 | nfs_inc_server_stats(server, NFSIOS_DELAY); | 3502 | nfs_inc_server_stats(server, NFSIOS_DELAY); |
3451 | case -NFS4ERR_GRACE: | 3503 | case -NFS4ERR_GRACE: |
3504 | case -EKEYEXPIRED: | ||
3452 | rpc_delay(task, NFS4_POLL_RETRY_MAX); | 3505 | rpc_delay(task, NFS4_POLL_RETRY_MAX); |
3453 | task->tk_status = 0; | 3506 | task->tk_status = 0; |
3454 | return -EAGAIN; | 3507 | return -EAGAIN; |
@@ -3458,6 +3511,13 @@ _nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
3458 | } | 3511 | } |
3459 | task->tk_status = nfs4_map_errors(task->tk_status); | 3512 | task->tk_status = nfs4_map_errors(task->tk_status); |
3460 | return 0; | 3513 | return 0; |
3514 | do_state_recovery: | ||
3515 | rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL); | ||
3516 | nfs4_schedule_state_recovery(clp); | ||
3517 | if (test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) == 0) | ||
3518 | rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task); | ||
3519 | task->tk_status = 0; | ||
3520 | return -EAGAIN; | ||
3461 | } | 3521 | } |
3462 | 3522 | ||
3463 | static int | 3523 | static int |
@@ -3466,7 +3526,9 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
3466 | return _nfs4_async_handle_error(task, server, server->nfs_client, state); | 3526 | return _nfs4_async_handle_error(task, server, server->nfs_client, state); |
3467 | } | 3527 | } |
3468 | 3528 | ||
3469 | int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short port, struct rpc_cred *cred) | 3529 | int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, |
3530 | unsigned short port, struct rpc_cred *cred, | ||
3531 | struct nfs4_setclientid_res *res) | ||
3470 | { | 3532 | { |
3471 | nfs4_verifier sc_verifier; | 3533 | nfs4_verifier sc_verifier; |
3472 | struct nfs4_setclientid setclientid = { | 3534 | struct nfs4_setclientid setclientid = { |
@@ -3476,7 +3538,7 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short po | |||
3476 | struct rpc_message msg = { | 3538 | struct rpc_message msg = { |
3477 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID], | 3539 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID], |
3478 | .rpc_argp = &setclientid, | 3540 | .rpc_argp = &setclientid, |
3479 | .rpc_resp = clp, | 3541 | .rpc_resp = res, |
3480 | .rpc_cred = cred, | 3542 | .rpc_cred = cred, |
3481 | }; | 3543 | }; |
3482 | __be32 *p; | 3544 | __be32 *p; |
@@ -3519,12 +3581,14 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short po | |||
3519 | return status; | 3581 | return status; |
3520 | } | 3582 | } |
3521 | 3583 | ||
3522 | static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct rpc_cred *cred) | 3584 | static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, |
3585 | struct nfs4_setclientid_res *arg, | ||
3586 | struct rpc_cred *cred) | ||
3523 | { | 3587 | { |
3524 | struct nfs_fsinfo fsinfo; | 3588 | struct nfs_fsinfo fsinfo; |
3525 | struct rpc_message msg = { | 3589 | struct rpc_message msg = { |
3526 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID_CONFIRM], | 3590 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID_CONFIRM], |
3527 | .rpc_argp = clp, | 3591 | .rpc_argp = arg, |
3528 | .rpc_resp = &fsinfo, | 3592 | .rpc_resp = &fsinfo, |
3529 | .rpc_cred = cred, | 3593 | .rpc_cred = cred, |
3530 | }; | 3594 | }; |
@@ -3542,18 +3606,21 @@ static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct rpc_cre | |||
3542 | return status; | 3606 | return status; |
3543 | } | 3607 | } |
3544 | 3608 | ||
3545 | int nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct rpc_cred *cred) | 3609 | int nfs4_proc_setclientid_confirm(struct nfs_client *clp, |
3610 | struct nfs4_setclientid_res *arg, | ||
3611 | struct rpc_cred *cred) | ||
3546 | { | 3612 | { |
3547 | long timeout = 0; | 3613 | long timeout = 0; |
3548 | int err; | 3614 | int err; |
3549 | do { | 3615 | do { |
3550 | err = _nfs4_proc_setclientid_confirm(clp, cred); | 3616 | err = _nfs4_proc_setclientid_confirm(clp, arg, cred); |
3551 | switch (err) { | 3617 | switch (err) { |
3552 | case 0: | 3618 | case 0: |
3553 | return err; | 3619 | return err; |
3554 | case -NFS4ERR_RESOURCE: | 3620 | case -NFS4ERR_RESOURCE: |
3555 | /* The IBM lawyers misread another document! */ | 3621 | /* The IBM lawyers misread another document! */ |
3556 | case -NFS4ERR_DELAY: | 3622 | case -NFS4ERR_DELAY: |
3623 | case -EKEYEXPIRED: | ||
3557 | err = nfs4_delay(clp->cl_rpcclient, &timeout); | 3624 | err = nfs4_delay(clp->cl_rpcclient, &timeout); |
3558 | } | 3625 | } |
3559 | } while (err == 0); | 3626 | } while (err == 0); |
@@ -3638,7 +3705,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co | |||
3638 | }; | 3705 | }; |
3639 | int status = 0; | 3706 | int status = 0; |
3640 | 3707 | ||
3641 | data = kzalloc(sizeof(*data), GFP_KERNEL); | 3708 | data = kzalloc(sizeof(*data), GFP_NOFS); |
3642 | if (data == NULL) | 3709 | if (data == NULL) |
3643 | return -ENOMEM; | 3710 | return -ENOMEM; |
3644 | data->args.fhandle = &data->fh; | 3711 | data->args.fhandle = &data->fh; |
@@ -3794,7 +3861,7 @@ static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl, | |||
3794 | struct nfs4_unlockdata *p; | 3861 | struct nfs4_unlockdata *p; |
3795 | struct inode *inode = lsp->ls_state->inode; | 3862 | struct inode *inode = lsp->ls_state->inode; |
3796 | 3863 | ||
3797 | p = kzalloc(sizeof(*p), GFP_KERNEL); | 3864 | p = kzalloc(sizeof(*p), GFP_NOFS); |
3798 | if (p == NULL) | 3865 | if (p == NULL) |
3799 | return NULL; | 3866 | return NULL; |
3800 | p->arg.fh = NFS_FH(inode); | 3867 | p->arg.fh = NFS_FH(inode); |
@@ -3932,7 +3999,7 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock * | |||
3932 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) | 3999 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) |
3933 | goto out; | 4000 | goto out; |
3934 | lsp = request->fl_u.nfs4_fl.owner; | 4001 | lsp = request->fl_u.nfs4_fl.owner; |
3935 | seqid = nfs_alloc_seqid(&lsp->ls_seqid); | 4002 | seqid = nfs_alloc_seqid(&lsp->ls_seqid, GFP_KERNEL); |
3936 | status = -ENOMEM; | 4003 | status = -ENOMEM; |
3937 | if (seqid == NULL) | 4004 | if (seqid == NULL) |
3938 | goto out; | 4005 | goto out; |
@@ -3960,22 +4027,23 @@ struct nfs4_lockdata { | |||
3960 | }; | 4027 | }; |
3961 | 4028 | ||
3962 | static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, | 4029 | static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, |
3963 | struct nfs_open_context *ctx, struct nfs4_lock_state *lsp) | 4030 | struct nfs_open_context *ctx, struct nfs4_lock_state *lsp, |
4031 | gfp_t gfp_mask) | ||
3964 | { | 4032 | { |
3965 | struct nfs4_lockdata *p; | 4033 | struct nfs4_lockdata *p; |
3966 | struct inode *inode = lsp->ls_state->inode; | 4034 | struct inode *inode = lsp->ls_state->inode; |
3967 | struct nfs_server *server = NFS_SERVER(inode); | 4035 | struct nfs_server *server = NFS_SERVER(inode); |
3968 | 4036 | ||
3969 | p = kzalloc(sizeof(*p), GFP_KERNEL); | 4037 | p = kzalloc(sizeof(*p), gfp_mask); |
3970 | if (p == NULL) | 4038 | if (p == NULL) |
3971 | return NULL; | 4039 | return NULL; |
3972 | 4040 | ||
3973 | p->arg.fh = NFS_FH(inode); | 4041 | p->arg.fh = NFS_FH(inode); |
3974 | p->arg.fl = &p->fl; | 4042 | p->arg.fl = &p->fl; |
3975 | p->arg.open_seqid = nfs_alloc_seqid(&lsp->ls_state->owner->so_seqid); | 4043 | p->arg.open_seqid = nfs_alloc_seqid(&lsp->ls_state->owner->so_seqid, gfp_mask); |
3976 | if (p->arg.open_seqid == NULL) | 4044 | if (p->arg.open_seqid == NULL) |
3977 | goto out_free; | 4045 | goto out_free; |
3978 | p->arg.lock_seqid = nfs_alloc_seqid(&lsp->ls_seqid); | 4046 | p->arg.lock_seqid = nfs_alloc_seqid(&lsp->ls_seqid, gfp_mask); |
3979 | if (p->arg.lock_seqid == NULL) | 4047 | if (p->arg.lock_seqid == NULL) |
3980 | goto out_free_seqid; | 4048 | goto out_free_seqid; |
3981 | p->arg.lock_stateid = &lsp->ls_stateid; | 4049 | p->arg.lock_stateid = &lsp->ls_stateid; |
@@ -4088,6 +4156,28 @@ static const struct rpc_call_ops nfs4_recover_lock_ops = { | |||
4088 | .rpc_release = nfs4_lock_release, | 4156 | .rpc_release = nfs4_lock_release, |
4089 | }; | 4157 | }; |
4090 | 4158 | ||
4159 | static void nfs4_handle_setlk_error(struct nfs_server *server, struct nfs4_lock_state *lsp, int new_lock_owner, int error) | ||
4160 | { | ||
4161 | struct nfs_client *clp = server->nfs_client; | ||
4162 | struct nfs4_state *state = lsp->ls_state; | ||
4163 | |||
4164 | switch (error) { | ||
4165 | case -NFS4ERR_ADMIN_REVOKED: | ||
4166 | case -NFS4ERR_BAD_STATEID: | ||
4167 | case -NFS4ERR_EXPIRED: | ||
4168 | if (new_lock_owner != 0 || | ||
4169 | (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0) | ||
4170 | nfs4_state_mark_reclaim_nograce(clp, state); | ||
4171 | lsp->ls_seqid.flags &= ~NFS_SEQID_CONFIRMED; | ||
4172 | break; | ||
4173 | case -NFS4ERR_STALE_STATEID: | ||
4174 | if (new_lock_owner != 0 || | ||
4175 | (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0) | ||
4176 | nfs4_state_mark_reclaim_reboot(clp, state); | ||
4177 | lsp->ls_seqid.flags &= ~NFS_SEQID_CONFIRMED; | ||
4178 | }; | ||
4179 | } | ||
4180 | |||
4091 | static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *fl, int recovery_type) | 4181 | static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *fl, int recovery_type) |
4092 | { | 4182 | { |
4093 | struct nfs4_lockdata *data; | 4183 | struct nfs4_lockdata *data; |
@@ -4107,7 +4197,8 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f | |||
4107 | 4197 | ||
4108 | dprintk("%s: begin!\n", __func__); | 4198 | dprintk("%s: begin!\n", __func__); |
4109 | data = nfs4_alloc_lockdata(fl, nfs_file_open_context(fl->fl_file), | 4199 | data = nfs4_alloc_lockdata(fl, nfs_file_open_context(fl->fl_file), |
4110 | fl->fl_u.nfs4_fl.owner); | 4200 | fl->fl_u.nfs4_fl.owner, |
4201 | recovery_type == NFS_LOCK_NEW ? GFP_KERNEL : GFP_NOFS); | ||
4111 | if (data == NULL) | 4202 | if (data == NULL) |
4112 | return -ENOMEM; | 4203 | return -ENOMEM; |
4113 | if (IS_SETLKW(cmd)) | 4204 | if (IS_SETLKW(cmd)) |
@@ -4126,6 +4217,9 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f | |||
4126 | ret = nfs4_wait_for_completion_rpc_task(task); | 4217 | ret = nfs4_wait_for_completion_rpc_task(task); |
4127 | if (ret == 0) { | 4218 | if (ret == 0) { |
4128 | ret = data->rpc_status; | 4219 | ret = data->rpc_status; |
4220 | if (ret) | ||
4221 | nfs4_handle_setlk_error(data->server, data->lsp, | ||
4222 | data->arg.new_lock_owner, ret); | ||
4129 | } else | 4223 | } else |
4130 | data->cancelled = 1; | 4224 | data->cancelled = 1; |
4131 | rpc_put_task(task); | 4225 | rpc_put_task(task); |
@@ -4144,7 +4238,7 @@ static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request | |||
4144 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0) | 4238 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0) |
4145 | return 0; | 4239 | return 0; |
4146 | err = _nfs4_do_setlk(state, F_SETLK, request, NFS_LOCK_RECLAIM); | 4240 | err = _nfs4_do_setlk(state, F_SETLK, request, NFS_LOCK_RECLAIM); |
4147 | if (err != -NFS4ERR_DELAY) | 4241 | if (err != -NFS4ERR_DELAY && err != -EKEYEXPIRED) |
4148 | break; | 4242 | break; |
4149 | nfs4_handle_exception(server, err, &exception); | 4243 | nfs4_handle_exception(server, err, &exception); |
4150 | } while (exception.retry); | 4244 | } while (exception.retry); |
@@ -4169,6 +4263,7 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request | |||
4169 | goto out; | 4263 | goto out; |
4170 | case -NFS4ERR_GRACE: | 4264 | case -NFS4ERR_GRACE: |
4171 | case -NFS4ERR_DELAY: | 4265 | case -NFS4ERR_DELAY: |
4266 | case -EKEYEXPIRED: | ||
4172 | nfs4_handle_exception(server, err, &exception); | 4267 | nfs4_handle_exception(server, err, &exception); |
4173 | err = 0; | 4268 | err = 0; |
4174 | } | 4269 | } |
@@ -4181,8 +4276,11 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock | |||
4181 | { | 4276 | { |
4182 | struct nfs_inode *nfsi = NFS_I(state->inode); | 4277 | struct nfs_inode *nfsi = NFS_I(state->inode); |
4183 | unsigned char fl_flags = request->fl_flags; | 4278 | unsigned char fl_flags = request->fl_flags; |
4184 | int status; | 4279 | int status = -ENOLCK; |
4185 | 4280 | ||
4281 | if ((fl_flags & FL_POSIX) && | ||
4282 | !test_bit(NFS_STATE_POSIX_LOCKS, &state->flags)) | ||
4283 | goto out; | ||
4186 | /* Is this a delegated open? */ | 4284 | /* Is this a delegated open? */ |
4187 | status = nfs4_set_lock_state(state, request); | 4285 | status = nfs4_set_lock_state(state, request); |
4188 | if (status != 0) | 4286 | if (status != 0) |
@@ -4317,6 +4415,7 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl) | |||
4317 | err = 0; | 4415 | err = 0; |
4318 | goto out; | 4416 | goto out; |
4319 | case -NFS4ERR_DELAY: | 4417 | case -NFS4ERR_DELAY: |
4418 | case -EKEYEXPIRED: | ||
4320 | break; | 4419 | break; |
4321 | } | 4420 | } |
4322 | err = nfs4_handle_exception(server, err, &exception); | 4421 | err = nfs4_handle_exception(server, err, &exception); |
@@ -4462,7 +4561,7 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) | |||
4462 | 4561 | ||
4463 | status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); | 4562 | status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); |
4464 | 4563 | ||
4465 | if (status != NFS4ERR_CLID_INUSE) | 4564 | if (status != -NFS4ERR_CLID_INUSE) |
4466 | break; | 4565 | break; |
4467 | 4566 | ||
4468 | if (signalled()) | 4567 | if (signalled()) |
@@ -4516,6 +4615,7 @@ static void nfs4_get_lease_time_done(struct rpc_task *task, void *calldata) | |||
4516 | switch (task->tk_status) { | 4615 | switch (task->tk_status) { |
4517 | case -NFS4ERR_DELAY: | 4616 | case -NFS4ERR_DELAY: |
4518 | case -NFS4ERR_GRACE: | 4617 | case -NFS4ERR_GRACE: |
4618 | case -EKEYEXPIRED: | ||
4519 | dprintk("%s Retry: tk_status %d\n", __func__, task->tk_status); | 4619 | dprintk("%s Retry: tk_status %d\n", __func__, task->tk_status); |
4520 | rpc_delay(task, NFS4_POLL_RETRY_MIN); | 4620 | rpc_delay(task, NFS4_POLL_RETRY_MIN); |
4521 | task->tk_status = 0; | 4621 | task->tk_status = 0; |
@@ -4573,26 +4673,32 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo) | |||
4573 | /* | 4673 | /* |
4574 | * Reset a slot table | 4674 | * Reset a slot table |
4575 | */ | 4675 | */ |
4576 | static int nfs4_reset_slot_table(struct nfs4_slot_table *tbl, int max_slots, | 4676 | static int nfs4_reset_slot_table(struct nfs4_slot_table *tbl, u32 max_reqs, |
4577 | int old_max_slots, int ivalue) | 4677 | int ivalue) |
4578 | { | 4678 | { |
4679 | struct nfs4_slot *new = NULL; | ||
4579 | int i; | 4680 | int i; |
4580 | int ret = 0; | 4681 | int ret = 0; |
4581 | 4682 | ||
4582 | dprintk("--> %s: max_reqs=%u, tbl %p\n", __func__, max_slots, tbl); | 4683 | dprintk("--> %s: max_reqs=%u, tbl->max_slots %d\n", __func__, |
4684 | max_reqs, tbl->max_slots); | ||
4583 | 4685 | ||
4584 | /* | 4686 | /* Does the newly negotiated max_reqs match the existing slot table? */ |
4585 | * Until we have dynamic slot table adjustment, insist | 4687 | if (max_reqs != tbl->max_slots) { |
4586 | * upon the same slot table size | 4688 | ret = -ENOMEM; |
4587 | */ | 4689 | new = kmalloc(max_reqs * sizeof(struct nfs4_slot), |
4588 | if (max_slots != old_max_slots) { | 4690 | GFP_NOFS); |
4589 | dprintk("%s reset slot table does't match old\n", | 4691 | if (!new) |
4590 | __func__); | 4692 | goto out; |
4591 | ret = -EINVAL; /*XXX NFS4ERR_REQ_TOO_BIG ? */ | 4693 | ret = 0; |
4592 | goto out; | 4694 | kfree(tbl->slots); |
4593 | } | 4695 | } |
4594 | spin_lock(&tbl->slot_tbl_lock); | 4696 | spin_lock(&tbl->slot_tbl_lock); |
4595 | for (i = 0; i < max_slots; ++i) | 4697 | if (new) { |
4698 | tbl->slots = new; | ||
4699 | tbl->max_slots = max_reqs; | ||
4700 | } | ||
4701 | for (i = 0; i < tbl->max_slots; ++i) | ||
4596 | tbl->slots[i].seq_nr = ivalue; | 4702 | tbl->slots[i].seq_nr = ivalue; |
4597 | spin_unlock(&tbl->slot_tbl_lock); | 4703 | spin_unlock(&tbl->slot_tbl_lock); |
4598 | dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__, | 4704 | dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__, |
@@ -4610,16 +4716,12 @@ static int nfs4_reset_slot_tables(struct nfs4_session *session) | |||
4610 | int status; | 4716 | int status; |
4611 | 4717 | ||
4612 | status = nfs4_reset_slot_table(&session->fc_slot_table, | 4718 | status = nfs4_reset_slot_table(&session->fc_slot_table, |
4613 | session->fc_attrs.max_reqs, | 4719 | session->fc_attrs.max_reqs, 1); |
4614 | session->fc_slot_table.max_slots, | ||
4615 | 1); | ||
4616 | if (status) | 4720 | if (status) |
4617 | return status; | 4721 | return status; |
4618 | 4722 | ||
4619 | status = nfs4_reset_slot_table(&session->bc_slot_table, | 4723 | status = nfs4_reset_slot_table(&session->bc_slot_table, |
4620 | session->bc_attrs.max_reqs, | 4724 | session->bc_attrs.max_reqs, 0); |
4621 | session->bc_slot_table.max_slots, | ||
4622 | 0); | ||
4623 | return status; | 4725 | return status; |
4624 | } | 4726 | } |
4625 | 4727 | ||
@@ -4650,7 +4752,7 @@ static int nfs4_init_slot_table(struct nfs4_slot_table *tbl, | |||
4650 | 4752 | ||
4651 | dprintk("--> %s: max_reqs=%u\n", __func__, max_slots); | 4753 | dprintk("--> %s: max_reqs=%u\n", __func__, max_slots); |
4652 | 4754 | ||
4653 | slot = kcalloc(max_slots, sizeof(struct nfs4_slot), GFP_KERNEL); | 4755 | slot = kcalloc(max_slots, sizeof(struct nfs4_slot), GFP_NOFS); |
4654 | if (!slot) | 4756 | if (!slot) |
4655 | goto out; | 4757 | goto out; |
4656 | ret = 0; | 4758 | ret = 0; |
@@ -4699,7 +4801,7 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp) | |||
4699 | struct nfs4_session *session; | 4801 | struct nfs4_session *session; |
4700 | struct nfs4_slot_table *tbl; | 4802 | struct nfs4_slot_table *tbl; |
4701 | 4803 | ||
4702 | session = kzalloc(sizeof(struct nfs4_session), GFP_KERNEL); | 4804 | session = kzalloc(sizeof(struct nfs4_session), GFP_NOFS); |
4703 | if (!session) | 4805 | if (!session) |
4704 | return NULL; | 4806 | return NULL; |
4705 | 4807 | ||
@@ -4760,16 +4862,14 @@ static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args) | |||
4760 | args->fc_attrs.headerpadsz = 0; | 4862 | args->fc_attrs.headerpadsz = 0; |
4761 | args->fc_attrs.max_rqst_sz = mxrqst_sz; | 4863 | args->fc_attrs.max_rqst_sz = mxrqst_sz; |
4762 | args->fc_attrs.max_resp_sz = mxresp_sz; | 4864 | args->fc_attrs.max_resp_sz = mxresp_sz; |
4763 | args->fc_attrs.max_resp_sz_cached = mxresp_sz; | ||
4764 | args->fc_attrs.max_ops = NFS4_MAX_OPS; | 4865 | args->fc_attrs.max_ops = NFS4_MAX_OPS; |
4765 | args->fc_attrs.max_reqs = session->clp->cl_rpcclient->cl_xprt->max_reqs; | 4866 | args->fc_attrs.max_reqs = session->clp->cl_rpcclient->cl_xprt->max_reqs; |
4766 | 4867 | ||
4767 | dprintk("%s: Fore Channel : max_rqst_sz=%u max_resp_sz=%u " | 4868 | dprintk("%s: Fore Channel : max_rqst_sz=%u max_resp_sz=%u " |
4768 | "max_resp_sz_cached=%u max_ops=%u max_reqs=%u\n", | 4869 | "max_ops=%u max_reqs=%u\n", |
4769 | __func__, | 4870 | __func__, |
4770 | args->fc_attrs.max_rqst_sz, args->fc_attrs.max_resp_sz, | 4871 | args->fc_attrs.max_rqst_sz, args->fc_attrs.max_resp_sz, |
4771 | args->fc_attrs.max_resp_sz_cached, args->fc_attrs.max_ops, | 4872 | args->fc_attrs.max_ops, args->fc_attrs.max_reqs); |
4772 | args->fc_attrs.max_reqs); | ||
4773 | 4873 | ||
4774 | /* Back channel attributes */ | 4874 | /* Back channel attributes */ |
4775 | args->bc_attrs.headerpadsz = 0; | 4875 | args->bc_attrs.headerpadsz = 0; |
@@ -4978,7 +5078,16 @@ static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred) | |||
4978 | &res, args.sa_cache_this, 1); | 5078 | &res, args.sa_cache_this, 1); |
4979 | } | 5079 | } |
4980 | 5080 | ||
4981 | void nfs41_sequence_call_done(struct rpc_task *task, void *data) | 5081 | static void nfs41_sequence_release(void *data) |
5082 | { | ||
5083 | struct nfs_client *clp = (struct nfs_client *)data; | ||
5084 | |||
5085 | if (atomic_read(&clp->cl_count) > 1) | ||
5086 | nfs4_schedule_state_renewal(clp); | ||
5087 | nfs_put_client(clp); | ||
5088 | } | ||
5089 | |||
5090 | static void nfs41_sequence_call_done(struct rpc_task *task, void *data) | ||
4982 | { | 5091 | { |
4983 | struct nfs_client *clp = (struct nfs_client *)data; | 5092 | struct nfs_client *clp = (struct nfs_client *)data; |
4984 | 5093 | ||
@@ -4986,6 +5095,8 @@ void nfs41_sequence_call_done(struct rpc_task *task, void *data) | |||
4986 | 5095 | ||
4987 | if (task->tk_status < 0) { | 5096 | if (task->tk_status < 0) { |
4988 | dprintk("%s ERROR %d\n", __func__, task->tk_status); | 5097 | dprintk("%s ERROR %d\n", __func__, task->tk_status); |
5098 | if (atomic_read(&clp->cl_count) == 1) | ||
5099 | goto out; | ||
4989 | 5100 | ||
4990 | if (_nfs4_async_handle_error(task, NULL, clp, NULL) | 5101 | if (_nfs4_async_handle_error(task, NULL, clp, NULL) |
4991 | == -EAGAIN) { | 5102 | == -EAGAIN) { |
@@ -4994,7 +5105,7 @@ void nfs41_sequence_call_done(struct rpc_task *task, void *data) | |||
4994 | } | 5105 | } |
4995 | } | 5106 | } |
4996 | dprintk("%s rpc_cred %p\n", __func__, task->tk_msg.rpc_cred); | 5107 | dprintk("%s rpc_cred %p\n", __func__, task->tk_msg.rpc_cred); |
4997 | 5108 | out: | |
4998 | kfree(task->tk_msg.rpc_argp); | 5109 | kfree(task->tk_msg.rpc_argp); |
4999 | kfree(task->tk_msg.rpc_resp); | 5110 | kfree(task->tk_msg.rpc_resp); |
5000 | 5111 | ||
@@ -5019,6 +5130,7 @@ static void nfs41_sequence_prepare(struct rpc_task *task, void *data) | |||
5019 | static const struct rpc_call_ops nfs41_sequence_ops = { | 5130 | static const struct rpc_call_ops nfs41_sequence_ops = { |
5020 | .rpc_call_done = nfs41_sequence_call_done, | 5131 | .rpc_call_done = nfs41_sequence_call_done, |
5021 | .rpc_call_prepare = nfs41_sequence_prepare, | 5132 | .rpc_call_prepare = nfs41_sequence_prepare, |
5133 | .rpc_release = nfs41_sequence_release, | ||
5022 | }; | 5134 | }; |
5023 | 5135 | ||
5024 | static int nfs41_proc_async_sequence(struct nfs_client *clp, | 5136 | static int nfs41_proc_async_sequence(struct nfs_client *clp, |
@@ -5031,12 +5143,14 @@ static int nfs41_proc_async_sequence(struct nfs_client *clp, | |||
5031 | .rpc_cred = cred, | 5143 | .rpc_cred = cred, |
5032 | }; | 5144 | }; |
5033 | 5145 | ||
5034 | args = kzalloc(sizeof(*args), GFP_KERNEL); | 5146 | if (!atomic_inc_not_zero(&clp->cl_count)) |
5035 | if (!args) | 5147 | return -EIO; |
5036 | return -ENOMEM; | 5148 | args = kzalloc(sizeof(*args), GFP_NOFS); |
5037 | res = kzalloc(sizeof(*res), GFP_KERNEL); | 5149 | res = kzalloc(sizeof(*res), GFP_NOFS); |
5038 | if (!res) { | 5150 | if (!args || !res) { |
5039 | kfree(args); | 5151 | kfree(args); |
5152 | kfree(res); | ||
5153 | nfs_put_client(clp); | ||
5040 | return -ENOMEM; | 5154 | return -ENOMEM; |
5041 | } | 5155 | } |
5042 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | 5156 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; |
@@ -5133,7 +5247,7 @@ static int nfs41_proc_reclaim_complete(struct nfs_client *clp) | |||
5133 | int status = -ENOMEM; | 5247 | int status = -ENOMEM; |
5134 | 5248 | ||
5135 | dprintk("--> %s\n", __func__); | 5249 | dprintk("--> %s\n", __func__); |
5136 | calldata = kzalloc(sizeof(*calldata), GFP_KERNEL); | 5250 | calldata = kzalloc(sizeof(*calldata), GFP_NOFS); |
5137 | if (calldata == NULL) | 5251 | if (calldata == NULL) |
5138 | goto out; | 5252 | goto out; |
5139 | calldata->clp = clp; | 5253 | calldata->clp = clp; |
@@ -5144,9 +5258,12 @@ static int nfs41_proc_reclaim_complete(struct nfs_client *clp) | |||
5144 | msg.rpc_resp = &calldata->res; | 5258 | msg.rpc_resp = &calldata->res; |
5145 | task_setup_data.callback_data = calldata; | 5259 | task_setup_data.callback_data = calldata; |
5146 | task = rpc_run_task(&task_setup_data); | 5260 | task = rpc_run_task(&task_setup_data); |
5147 | if (IS_ERR(task)) | 5261 | if (IS_ERR(task)) { |
5148 | status = PTR_ERR(task); | 5262 | status = PTR_ERR(task); |
5263 | goto out; | ||
5264 | } | ||
5149 | rpc_put_task(task); | 5265 | rpc_put_task(task); |
5266 | return 0; | ||
5150 | out: | 5267 | out: |
5151 | dprintk("<-- %s status=%d\n", __func__, status); | 5268 | dprintk("<-- %s status=%d\n", __func__, status); |
5152 | return status; | 5269 | return status; |
diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c index 0156c01c212c..d87f10327b72 100644 --- a/fs/nfs/nfs4renewd.c +++ b/fs/nfs/nfs4renewd.c | |||
@@ -36,11 +36,6 @@ | |||
36 | * as an rpc_task, not a real kernel thread, so it always runs in rpciod's | 36 | * as an rpc_task, not a real kernel thread, so it always runs in rpciod's |
37 | * context. There is one renewd per nfs_server. | 37 | * context. There is one renewd per nfs_server. |
38 | * | 38 | * |
39 | * TODO: If the send queue gets backlogged (e.g., if the server goes down), | ||
40 | * we will keep filling the queue with periodic RENEW requests. We need a | ||
41 | * mechanism for ensuring that if renewd successfully sends off a request, | ||
42 | * then it only wakes up when the request is finished. Maybe use the | ||
43 | * child task framework of the RPC layer? | ||
44 | */ | 39 | */ |
45 | 40 | ||
46 | #include <linux/mm.h> | 41 | #include <linux/mm.h> |
@@ -63,7 +58,7 @@ nfs4_renew_state(struct work_struct *work) | |||
63 | struct nfs_client *clp = | 58 | struct nfs_client *clp = |
64 | container_of(work, struct nfs_client, cl_renewd.work); | 59 | container_of(work, struct nfs_client, cl_renewd.work); |
65 | struct rpc_cred *cred; | 60 | struct rpc_cred *cred; |
66 | long lease, timeout; | 61 | long lease; |
67 | unsigned long last, now; | 62 | unsigned long last, now; |
68 | 63 | ||
69 | ops = nfs4_state_renewal_ops[clp->cl_minorversion]; | 64 | ops = nfs4_state_renewal_ops[clp->cl_minorversion]; |
@@ -75,7 +70,6 @@ nfs4_renew_state(struct work_struct *work) | |||
75 | lease = clp->cl_lease_time; | 70 | lease = clp->cl_lease_time; |
76 | last = clp->cl_last_renewal; | 71 | last = clp->cl_last_renewal; |
77 | now = jiffies; | 72 | now = jiffies; |
78 | timeout = (2 * lease) / 3 + (long)last - (long)now; | ||
79 | /* Are we close to a lease timeout? */ | 73 | /* Are we close to a lease timeout? */ |
80 | if (time_after(now, last + lease/3)) { | 74 | if (time_after(now, last + lease/3)) { |
81 | cred = ops->get_state_renewal_cred_locked(clp); | 75 | cred = ops->get_state_renewal_cred_locked(clp); |
@@ -90,19 +84,15 @@ nfs4_renew_state(struct work_struct *work) | |||
90 | /* Queue an asynchronous RENEW. */ | 84 | /* Queue an asynchronous RENEW. */ |
91 | ops->sched_state_renewal(clp, cred); | 85 | ops->sched_state_renewal(clp, cred); |
92 | put_rpccred(cred); | 86 | put_rpccred(cred); |
87 | goto out_exp; | ||
93 | } | 88 | } |
94 | timeout = (2 * lease) / 3; | 89 | } else { |
95 | spin_lock(&clp->cl_lock); | ||
96 | } else | ||
97 | dprintk("%s: failed to call renewd. Reason: lease not expired \n", | 90 | dprintk("%s: failed to call renewd. Reason: lease not expired \n", |
98 | __func__); | 91 | __func__); |
99 | if (timeout < 5 * HZ) /* safeguard */ | 92 | spin_unlock(&clp->cl_lock); |
100 | timeout = 5 * HZ; | 93 | } |
101 | dprintk("%s: requeueing work. Lease period = %ld\n", | 94 | nfs4_schedule_state_renewal(clp); |
102 | __func__, (timeout + HZ - 1) / HZ); | 95 | out_exp: |
103 | cancel_delayed_work(&clp->cl_renewd); | ||
104 | schedule_delayed_work(&clp->cl_renewd, timeout); | ||
105 | spin_unlock(&clp->cl_lock); | ||
106 | nfs_expire_unreferenced_delegations(clp); | 96 | nfs_expire_unreferenced_delegations(clp); |
107 | out: | 97 | out: |
108 | dprintk("%s: done\n", __func__); | 98 | dprintk("%s: done\n", __func__); |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 6d263ed79e92..34acf5926fdc 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -62,6 +62,7 @@ static LIST_HEAD(nfs4_clientid_list); | |||
62 | 62 | ||
63 | int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) | 63 | int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) |
64 | { | 64 | { |
65 | struct nfs4_setclientid_res clid; | ||
65 | unsigned short port; | 66 | unsigned short port; |
66 | int status; | 67 | int status; |
67 | 68 | ||
@@ -69,11 +70,15 @@ int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) | |||
69 | if (clp->cl_addr.ss_family == AF_INET6) | 70 | if (clp->cl_addr.ss_family == AF_INET6) |
70 | port = nfs_callback_tcpport6; | 71 | port = nfs_callback_tcpport6; |
71 | 72 | ||
72 | status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, port, cred); | 73 | status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, port, cred, &clid); |
73 | if (status == 0) | 74 | if (status != 0) |
74 | status = nfs4_proc_setclientid_confirm(clp, cred); | 75 | goto out; |
75 | if (status == 0) | 76 | status = nfs4_proc_setclientid_confirm(clp, &clid, cred); |
76 | nfs4_schedule_state_renewal(clp); | 77 | if (status != 0) |
78 | goto out; | ||
79 | clp->cl_clientid = clid.clientid; | ||
80 | nfs4_schedule_state_renewal(clp); | ||
81 | out: | ||
77 | return status; | 82 | return status; |
78 | } | 83 | } |
79 | 84 | ||
@@ -361,7 +366,7 @@ nfs4_alloc_state_owner(void) | |||
361 | { | 366 | { |
362 | struct nfs4_state_owner *sp; | 367 | struct nfs4_state_owner *sp; |
363 | 368 | ||
364 | sp = kzalloc(sizeof(*sp),GFP_KERNEL); | 369 | sp = kzalloc(sizeof(*sp),GFP_NOFS); |
365 | if (!sp) | 370 | if (!sp) |
366 | return NULL; | 371 | return NULL; |
367 | spin_lock_init(&sp->so_lock); | 372 | spin_lock_init(&sp->so_lock); |
@@ -435,7 +440,7 @@ nfs4_alloc_open_state(void) | |||
435 | { | 440 | { |
436 | struct nfs4_state *state; | 441 | struct nfs4_state *state; |
437 | 442 | ||
438 | state = kzalloc(sizeof(*state), GFP_KERNEL); | 443 | state = kzalloc(sizeof(*state), GFP_NOFS); |
439 | if (!state) | 444 | if (!state) |
440 | return NULL; | 445 | return NULL; |
441 | atomic_set(&state->count, 1); | 446 | atomic_set(&state->count, 1); |
@@ -537,7 +542,8 @@ void nfs4_put_open_state(struct nfs4_state *state) | |||
537 | /* | 542 | /* |
538 | * Close the current file. | 543 | * Close the current file. |
539 | */ | 544 | */ |
540 | static void __nfs4_close(struct path *path, struct nfs4_state *state, fmode_t fmode, int wait) | 545 | static void __nfs4_close(struct path *path, struct nfs4_state *state, |
546 | fmode_t fmode, gfp_t gfp_mask, int wait) | ||
541 | { | 547 | { |
542 | struct nfs4_state_owner *owner = state->owner; | 548 | struct nfs4_state_owner *owner = state->owner; |
543 | int call_close = 0; | 549 | int call_close = 0; |
@@ -578,17 +584,17 @@ static void __nfs4_close(struct path *path, struct nfs4_state *state, fmode_t fm | |||
578 | nfs4_put_open_state(state); | 584 | nfs4_put_open_state(state); |
579 | nfs4_put_state_owner(owner); | 585 | nfs4_put_state_owner(owner); |
580 | } else | 586 | } else |
581 | nfs4_do_close(path, state, wait); | 587 | nfs4_do_close(path, state, gfp_mask, wait); |
582 | } | 588 | } |
583 | 589 | ||
584 | void nfs4_close_state(struct path *path, struct nfs4_state *state, fmode_t fmode) | 590 | void nfs4_close_state(struct path *path, struct nfs4_state *state, fmode_t fmode) |
585 | { | 591 | { |
586 | __nfs4_close(path, state, fmode, 0); | 592 | __nfs4_close(path, state, fmode, GFP_NOFS, 0); |
587 | } | 593 | } |
588 | 594 | ||
589 | void nfs4_close_sync(struct path *path, struct nfs4_state *state, fmode_t fmode) | 595 | void nfs4_close_sync(struct path *path, struct nfs4_state *state, fmode_t fmode) |
590 | { | 596 | { |
591 | __nfs4_close(path, state, fmode, 1); | 597 | __nfs4_close(path, state, fmode, GFP_KERNEL, 1); |
592 | } | 598 | } |
593 | 599 | ||
594 | /* | 600 | /* |
@@ -618,7 +624,7 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f | |||
618 | struct nfs4_lock_state *lsp; | 624 | struct nfs4_lock_state *lsp; |
619 | struct nfs_client *clp = state->owner->so_client; | 625 | struct nfs_client *clp = state->owner->so_client; |
620 | 626 | ||
621 | lsp = kzalloc(sizeof(*lsp), GFP_KERNEL); | 627 | lsp = kzalloc(sizeof(*lsp), GFP_NOFS); |
622 | if (lsp == NULL) | 628 | if (lsp == NULL) |
623 | return NULL; | 629 | return NULL; |
624 | rpc_init_wait_queue(&lsp->ls_sequence.wait, "lock_seqid_waitqueue"); | 630 | rpc_init_wait_queue(&lsp->ls_sequence.wait, "lock_seqid_waitqueue"); |
@@ -754,11 +760,11 @@ void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t f | |||
754 | nfs4_put_lock_state(lsp); | 760 | nfs4_put_lock_state(lsp); |
755 | } | 761 | } |
756 | 762 | ||
757 | struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter) | 763 | struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask) |
758 | { | 764 | { |
759 | struct nfs_seqid *new; | 765 | struct nfs_seqid *new; |
760 | 766 | ||
761 | new = kmalloc(sizeof(*new), GFP_KERNEL); | 767 | new = kmalloc(sizeof(*new), gfp_mask); |
762 | if (new != NULL) { | 768 | if (new != NULL) { |
763 | new->sequence = counter; | 769 | new->sequence = counter; |
764 | INIT_LIST_HEAD(&new->list); | 770 | INIT_LIST_HEAD(&new->list); |
@@ -901,7 +907,7 @@ void nfs4_schedule_state_recovery(struct nfs_client *clp) | |||
901 | nfs4_schedule_state_manager(clp); | 907 | nfs4_schedule_state_manager(clp); |
902 | } | 908 | } |
903 | 909 | ||
904 | static int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_state *state) | 910 | int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_state *state) |
905 | { | 911 | { |
906 | 912 | ||
907 | set_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags); | 913 | set_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags); |
@@ -1249,26 +1255,65 @@ static int nfs4_reclaim_lease(struct nfs_client *clp) | |||
1249 | } | 1255 | } |
1250 | 1256 | ||
1251 | #ifdef CONFIG_NFS_V4_1 | 1257 | #ifdef CONFIG_NFS_V4_1 |
1258 | void nfs41_handle_recall_slot(struct nfs_client *clp) | ||
1259 | { | ||
1260 | set_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state); | ||
1261 | nfs4_schedule_state_recovery(clp); | ||
1262 | } | ||
1263 | |||
1264 | static void nfs4_reset_all_state(struct nfs_client *clp) | ||
1265 | { | ||
1266 | if (test_and_set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0) { | ||
1267 | clp->cl_boot_time = CURRENT_TIME; | ||
1268 | nfs4_state_start_reclaim_nograce(clp); | ||
1269 | nfs4_schedule_state_recovery(clp); | ||
1270 | } | ||
1271 | } | ||
1272 | |||
1273 | static void nfs41_handle_server_reboot(struct nfs_client *clp) | ||
1274 | { | ||
1275 | if (test_and_set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0) { | ||
1276 | nfs4_state_start_reclaim_reboot(clp); | ||
1277 | nfs4_schedule_state_recovery(clp); | ||
1278 | } | ||
1279 | } | ||
1280 | |||
1281 | static void nfs41_handle_state_revoked(struct nfs_client *clp) | ||
1282 | { | ||
1283 | /* Temporary */ | ||
1284 | nfs4_reset_all_state(clp); | ||
1285 | } | ||
1286 | |||
1287 | static void nfs41_handle_recallable_state_revoked(struct nfs_client *clp) | ||
1288 | { | ||
1289 | /* This will need to handle layouts too */ | ||
1290 | nfs_expire_all_delegations(clp); | ||
1291 | } | ||
1292 | |||
1293 | static void nfs41_handle_cb_path_down(struct nfs_client *clp) | ||
1294 | { | ||
1295 | nfs_expire_all_delegations(clp); | ||
1296 | if (test_and_set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state) == 0) | ||
1297 | nfs4_schedule_state_recovery(clp); | ||
1298 | } | ||
1299 | |||
1252 | void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags) | 1300 | void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags) |
1253 | { | 1301 | { |
1254 | if (!flags) | 1302 | if (!flags) |
1255 | return; | 1303 | return; |
1256 | else if (flags & SEQ4_STATUS_RESTART_RECLAIM_NEEDED) { | 1304 | else if (flags & SEQ4_STATUS_RESTART_RECLAIM_NEEDED) |
1257 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | 1305 | nfs41_handle_server_reboot(clp); |
1258 | nfs4_state_start_reclaim_reboot(clp); | 1306 | else if (flags & (SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED | |
1259 | nfs4_schedule_state_recovery(clp); | ||
1260 | } else if (flags & (SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED | | ||
1261 | SEQ4_STATUS_EXPIRED_SOME_STATE_REVOKED | | 1307 | SEQ4_STATUS_EXPIRED_SOME_STATE_REVOKED | |
1262 | SEQ4_STATUS_ADMIN_STATE_REVOKED | | 1308 | SEQ4_STATUS_ADMIN_STATE_REVOKED | |
1263 | SEQ4_STATUS_RECALLABLE_STATE_REVOKED | | 1309 | SEQ4_STATUS_LEASE_MOVED)) |
1264 | SEQ4_STATUS_LEASE_MOVED)) { | 1310 | nfs41_handle_state_revoked(clp); |
1265 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | 1311 | else if (flags & SEQ4_STATUS_RECALLABLE_STATE_REVOKED) |
1266 | nfs4_state_start_reclaim_nograce(clp); | 1312 | nfs41_handle_recallable_state_revoked(clp); |
1267 | nfs4_schedule_state_recovery(clp); | 1313 | else if (flags & (SEQ4_STATUS_CB_PATH_DOWN | |
1268 | } else if (flags & (SEQ4_STATUS_CB_PATH_DOWN | | ||
1269 | SEQ4_STATUS_BACKCHANNEL_FAULT | | 1314 | SEQ4_STATUS_BACKCHANNEL_FAULT | |
1270 | SEQ4_STATUS_CB_PATH_DOWN_SESSION)) | 1315 | SEQ4_STATUS_CB_PATH_DOWN_SESSION)) |
1271 | nfs_expire_all_delegations(clp); | 1316 | nfs41_handle_cb_path_down(clp); |
1272 | } | 1317 | } |
1273 | 1318 | ||
1274 | static int nfs4_reset_session(struct nfs_client *clp) | 1319 | static int nfs4_reset_session(struct nfs_client *clp) |
@@ -1285,23 +1330,52 @@ static int nfs4_reset_session(struct nfs_client *clp) | |||
1285 | 1330 | ||
1286 | memset(clp->cl_session->sess_id.data, 0, NFS4_MAX_SESSIONID_LEN); | 1331 | memset(clp->cl_session->sess_id.data, 0, NFS4_MAX_SESSIONID_LEN); |
1287 | status = nfs4_proc_create_session(clp); | 1332 | status = nfs4_proc_create_session(clp); |
1288 | if (status) | 1333 | if (status) { |
1289 | status = nfs4_recovery_handle_error(clp, status); | 1334 | status = nfs4_recovery_handle_error(clp, status); |
1335 | goto out; | ||
1336 | } | ||
1337 | /* create_session negotiated new slot table */ | ||
1338 | clear_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state); | ||
1290 | 1339 | ||
1291 | out: | 1340 | /* Let the state manager reestablish state */ |
1292 | /* | 1341 | if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) |
1293 | * Let the state manager reestablish state | ||
1294 | */ | ||
1295 | if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) && | ||
1296 | status == 0) | ||
1297 | nfs41_setup_state_renewal(clp); | 1342 | nfs41_setup_state_renewal(clp); |
1298 | 1343 | out: | |
1299 | return status; | 1344 | return status; |
1300 | } | 1345 | } |
1301 | 1346 | ||
1347 | static int nfs4_recall_slot(struct nfs_client *clp) | ||
1348 | { | ||
1349 | struct nfs4_slot_table *fc_tbl = &clp->cl_session->fc_slot_table; | ||
1350 | struct nfs4_channel_attrs *fc_attrs = &clp->cl_session->fc_attrs; | ||
1351 | struct nfs4_slot *new, *old; | ||
1352 | int i; | ||
1353 | |||
1354 | nfs4_begin_drain_session(clp); | ||
1355 | new = kmalloc(fc_tbl->target_max_slots * sizeof(struct nfs4_slot), | ||
1356 | GFP_NOFS); | ||
1357 | if (!new) | ||
1358 | return -ENOMEM; | ||
1359 | |||
1360 | spin_lock(&fc_tbl->slot_tbl_lock); | ||
1361 | for (i = 0; i < fc_tbl->target_max_slots; i++) | ||
1362 | new[i].seq_nr = fc_tbl->slots[i].seq_nr; | ||
1363 | old = fc_tbl->slots; | ||
1364 | fc_tbl->slots = new; | ||
1365 | fc_tbl->max_slots = fc_tbl->target_max_slots; | ||
1366 | fc_tbl->target_max_slots = 0; | ||
1367 | fc_attrs->max_reqs = fc_tbl->max_slots; | ||
1368 | spin_unlock(&fc_tbl->slot_tbl_lock); | ||
1369 | |||
1370 | kfree(old); | ||
1371 | nfs4_end_drain_session(clp); | ||
1372 | return 0; | ||
1373 | } | ||
1374 | |||
1302 | #else /* CONFIG_NFS_V4_1 */ | 1375 | #else /* CONFIG_NFS_V4_1 */ |
1303 | static int nfs4_reset_session(struct nfs_client *clp) { return 0; } | 1376 | static int nfs4_reset_session(struct nfs_client *clp) { return 0; } |
1304 | static int nfs4_end_drain_session(struct nfs_client *clp) { return 0; } | 1377 | static int nfs4_end_drain_session(struct nfs_client *clp) { return 0; } |
1378 | static int nfs4_recall_slot(struct nfs_client *clp) { return 0; } | ||
1305 | #endif /* CONFIG_NFS_V4_1 */ | 1379 | #endif /* CONFIG_NFS_V4_1 */ |
1306 | 1380 | ||
1307 | /* Set NFS4CLNT_LEASE_EXPIRED for all v4.0 errors and for recoverable errors | 1381 | /* Set NFS4CLNT_LEASE_EXPIRED for all v4.0 errors and for recoverable errors |
@@ -1314,6 +1388,7 @@ static void nfs4_set_lease_expired(struct nfs_client *clp, int status) | |||
1314 | case -NFS4ERR_DELAY: | 1388 | case -NFS4ERR_DELAY: |
1315 | case -NFS4ERR_CLID_INUSE: | 1389 | case -NFS4ERR_CLID_INUSE: |
1316 | case -EAGAIN: | 1390 | case -EAGAIN: |
1391 | case -EKEYEXPIRED: | ||
1317 | break; | 1392 | break; |
1318 | 1393 | ||
1319 | case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery | 1394 | case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery |
@@ -1397,6 +1472,15 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
1397 | nfs_client_return_marked_delegations(clp); | 1472 | nfs_client_return_marked_delegations(clp); |
1398 | continue; | 1473 | continue; |
1399 | } | 1474 | } |
1475 | /* Recall session slots */ | ||
1476 | if (test_and_clear_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state) | ||
1477 | && nfs4_has_session(clp)) { | ||
1478 | status = nfs4_recall_slot(clp); | ||
1479 | if (status < 0) | ||
1480 | goto out_error; | ||
1481 | continue; | ||
1482 | } | ||
1483 | |||
1400 | 1484 | ||
1401 | nfs4_clear_state_manager_bit(clp); | 1485 | nfs4_clear_state_manager_bit(clp); |
1402 | /* Did we race with an attempt to give us more work? */ | 1486 | /* Did we race with an attempt to give us more work? */ |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index e437fd6a819f..65c8dae4b267 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -38,7 +38,6 @@ | |||
38 | #include <linux/param.h> | 38 | #include <linux/param.h> |
39 | #include <linux/time.h> | 39 | #include <linux/time.h> |
40 | #include <linux/mm.h> | 40 | #include <linux/mm.h> |
41 | #include <linux/slab.h> | ||
42 | #include <linux/errno.h> | 41 | #include <linux/errno.h> |
43 | #include <linux/string.h> | 42 | #include <linux/string.h> |
44 | #include <linux/in.h> | 43 | #include <linux/in.h> |
@@ -863,8 +862,8 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const | |||
863 | bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET; | 862 | bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET; |
864 | *p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME); | 863 | *p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME); |
865 | *p++ = cpu_to_be32(0); | 864 | *p++ = cpu_to_be32(0); |
866 | *p++ = cpu_to_be32(iap->ia_mtime.tv_sec); | 865 | *p++ = cpu_to_be32(iap->ia_atime.tv_sec); |
867 | *p++ = cpu_to_be32(iap->ia_mtime.tv_nsec); | 866 | *p++ = cpu_to_be32(iap->ia_atime.tv_nsec); |
868 | } | 867 | } |
869 | else if (iap->ia_valid & ATTR_ATIME) { | 868 | else if (iap->ia_valid & ATTR_ATIME) { |
870 | bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET; | 869 | bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET; |
@@ -1505,14 +1504,14 @@ static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclie | |||
1505 | hdr->replen += decode_setclientid_maxsz; | 1504 | hdr->replen += decode_setclientid_maxsz; |
1506 | } | 1505 | } |
1507 | 1506 | ||
1508 | static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_client *client_state, struct compound_hdr *hdr) | 1507 | static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs4_setclientid_res *arg, struct compound_hdr *hdr) |
1509 | { | 1508 | { |
1510 | __be32 *p; | 1509 | __be32 *p; |
1511 | 1510 | ||
1512 | p = reserve_space(xdr, 12 + NFS4_VERIFIER_SIZE); | 1511 | p = reserve_space(xdr, 12 + NFS4_VERIFIER_SIZE); |
1513 | *p++ = cpu_to_be32(OP_SETCLIENTID_CONFIRM); | 1512 | *p++ = cpu_to_be32(OP_SETCLIENTID_CONFIRM); |
1514 | p = xdr_encode_hyper(p, client_state->cl_clientid); | 1513 | p = xdr_encode_hyper(p, arg->clientid); |
1515 | xdr_encode_opaque_fixed(p, client_state->cl_confirm.data, NFS4_VERIFIER_SIZE); | 1514 | xdr_encode_opaque_fixed(p, arg->confirm.data, NFS4_VERIFIER_SIZE); |
1516 | hdr->nops++; | 1515 | hdr->nops++; |
1517 | hdr->replen += decode_setclientid_confirm_maxsz; | 1516 | hdr->replen += decode_setclientid_confirm_maxsz; |
1518 | } | 1517 | } |
@@ -1578,6 +1577,14 @@ static void encode_create_session(struct xdr_stream *xdr, | |||
1578 | char machine_name[NFS4_MAX_MACHINE_NAME_LEN]; | 1577 | char machine_name[NFS4_MAX_MACHINE_NAME_LEN]; |
1579 | uint32_t len; | 1578 | uint32_t len; |
1580 | struct nfs_client *clp = args->client; | 1579 | struct nfs_client *clp = args->client; |
1580 | u32 max_resp_sz_cached; | ||
1581 | |||
1582 | /* | ||
1583 | * Assumes OPEN is the biggest non-idempotent compound. | ||
1584 | * 2 is the verifier. | ||
1585 | */ | ||
1586 | max_resp_sz_cached = (NFS4_dec_open_sz + RPC_REPHDRSIZE + | ||
1587 | RPC_MAX_AUTH_SIZE + 2) * XDR_UNIT; | ||
1581 | 1588 | ||
1582 | len = scnprintf(machine_name, sizeof(machine_name), "%s", | 1589 | len = scnprintf(machine_name, sizeof(machine_name), "%s", |
1583 | clp->cl_ipaddr); | 1590 | clp->cl_ipaddr); |
@@ -1592,7 +1599,7 @@ static void encode_create_session(struct xdr_stream *xdr, | |||
1592 | *p++ = cpu_to_be32(args->fc_attrs.headerpadsz); /* header padding size */ | 1599 | *p++ = cpu_to_be32(args->fc_attrs.headerpadsz); /* header padding size */ |
1593 | *p++ = cpu_to_be32(args->fc_attrs.max_rqst_sz); /* max req size */ | 1600 | *p++ = cpu_to_be32(args->fc_attrs.max_rqst_sz); /* max req size */ |
1594 | *p++ = cpu_to_be32(args->fc_attrs.max_resp_sz); /* max resp size */ | 1601 | *p++ = cpu_to_be32(args->fc_attrs.max_resp_sz); /* max resp size */ |
1595 | *p++ = cpu_to_be32(args->fc_attrs.max_resp_sz_cached); /* Max resp sz cached */ | 1602 | *p++ = cpu_to_be32(max_resp_sz_cached); /* Max resp sz cached */ |
1596 | *p++ = cpu_to_be32(args->fc_attrs.max_ops); /* max operations */ | 1603 | *p++ = cpu_to_be32(args->fc_attrs.max_ops); /* max operations */ |
1597 | *p++ = cpu_to_be32(args->fc_attrs.max_reqs); /* max requests */ | 1604 | *p++ = cpu_to_be32(args->fc_attrs.max_reqs); /* max requests */ |
1598 | *p++ = cpu_to_be32(0); /* rdmachannel_attrs */ | 1605 | *p++ = cpu_to_be32(0); /* rdmachannel_attrs */ |
@@ -2317,7 +2324,7 @@ static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, __be32 *p, struct nfs4 | |||
2317 | /* | 2324 | /* |
2318 | * a SETCLIENTID_CONFIRM request | 2325 | * a SETCLIENTID_CONFIRM request |
2319 | */ | 2326 | */ |
2320 | static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_client *clp) | 2327 | static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, __be32 *p, struct nfs4_setclientid_res *arg) |
2321 | { | 2328 | { |
2322 | struct xdr_stream xdr; | 2329 | struct xdr_stream xdr; |
2323 | struct compound_hdr hdr = { | 2330 | struct compound_hdr hdr = { |
@@ -2327,7 +2334,7 @@ static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, __be32 *p, str | |||
2327 | 2334 | ||
2328 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2335 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
2329 | encode_compound_hdr(&xdr, req, &hdr); | 2336 | encode_compound_hdr(&xdr, req, &hdr); |
2330 | encode_setclientid_confirm(&xdr, clp, &hdr); | 2337 | encode_setclientid_confirm(&xdr, arg, &hdr); |
2331 | encode_putrootfh(&xdr, &hdr); | 2338 | encode_putrootfh(&xdr, &hdr); |
2332 | encode_fsinfo(&xdr, lease_bitmap, &hdr); | 2339 | encode_fsinfo(&xdr, lease_bitmap, &hdr); |
2333 | encode_nops(&hdr); | 2340 | encode_nops(&hdr); |
@@ -4390,7 +4397,7 @@ out_overflow: | |||
4390 | return -EIO; | 4397 | return -EIO; |
4391 | } | 4398 | } |
4392 | 4399 | ||
4393 | static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp) | 4400 | static int decode_setclientid(struct xdr_stream *xdr, struct nfs4_setclientid_res *res) |
4394 | { | 4401 | { |
4395 | __be32 *p; | 4402 | __be32 *p; |
4396 | uint32_t opnum; | 4403 | uint32_t opnum; |
@@ -4410,8 +4417,8 @@ static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp) | |||
4410 | p = xdr_inline_decode(xdr, 8 + NFS4_VERIFIER_SIZE); | 4417 | p = xdr_inline_decode(xdr, 8 + NFS4_VERIFIER_SIZE); |
4411 | if (unlikely(!p)) | 4418 | if (unlikely(!p)) |
4412 | goto out_overflow; | 4419 | goto out_overflow; |
4413 | p = xdr_decode_hyper(p, &clp->cl_clientid); | 4420 | p = xdr_decode_hyper(p, &res->clientid); |
4414 | memcpy(clp->cl_confirm.data, p, NFS4_VERIFIER_SIZE); | 4421 | memcpy(res->confirm.data, p, NFS4_VERIFIER_SIZE); |
4415 | } else if (nfserr == NFSERR_CLID_INUSE) { | 4422 | } else if (nfserr == NFSERR_CLID_INUSE) { |
4416 | uint32_t len; | 4423 | uint32_t len; |
4417 | 4424 | ||
@@ -4631,7 +4638,7 @@ static int decode_sequence(struct xdr_stream *xdr, | |||
4631 | * If the server returns different values for sessionID, slotID or | 4638 | * If the server returns different values for sessionID, slotID or |
4632 | * sequence number, the server is looney tunes. | 4639 | * sequence number, the server is looney tunes. |
4633 | */ | 4640 | */ |
4634 | status = -ESERVERFAULT; | 4641 | status = -EREMOTEIO; |
4635 | 4642 | ||
4636 | if (memcmp(id.data, res->sr_session->sess_id.data, | 4643 | if (memcmp(id.data, res->sr_session->sess_id.data, |
4637 | NFS4_MAX_SESSIONID_LEN)) { | 4644 | NFS4_MAX_SESSIONID_LEN)) { |
@@ -4808,7 +4815,7 @@ static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs_rem | |||
4808 | goto out; | 4815 | goto out; |
4809 | if ((status = decode_remove(&xdr, &res->cinfo)) != 0) | 4816 | if ((status = decode_remove(&xdr, &res->cinfo)) != 0) |
4810 | goto out; | 4817 | goto out; |
4811 | decode_getfattr(&xdr, &res->dir_attr, res->server, | 4818 | decode_getfattr(&xdr, res->dir_attr, res->server, |
4812 | !RPC_IS_ASYNC(rqstp->rq_task)); | 4819 | !RPC_IS_ASYNC(rqstp->rq_task)); |
4813 | out: | 4820 | out: |
4814 | return status; | 4821 | return status; |
@@ -5491,7 +5498,7 @@ static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, __be32 *p, void *dummy) | |||
5491 | * Decode SETCLIENTID response | 5498 | * Decode SETCLIENTID response |
5492 | */ | 5499 | */ |
5493 | static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, __be32 *p, | 5500 | static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, __be32 *p, |
5494 | struct nfs_client *clp) | 5501 | struct nfs4_setclientid_res *res) |
5495 | { | 5502 | { |
5496 | struct xdr_stream xdr; | 5503 | struct xdr_stream xdr; |
5497 | struct compound_hdr hdr; | 5504 | struct compound_hdr hdr; |
@@ -5500,7 +5507,7 @@ static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, __be32 *p, | |||
5500 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | 5507 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); |
5501 | status = decode_compound_hdr(&xdr, &hdr); | 5508 | status = decode_compound_hdr(&xdr, &hdr); |
5502 | if (!status) | 5509 | if (!status) |
5503 | status = decode_setclientid(&xdr, clp); | 5510 | status = decode_setclientid(&xdr, res); |
5504 | return status; | 5511 | return status; |
5505 | } | 5512 | } |
5506 | 5513 | ||
@@ -5544,6 +5551,8 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, __be32 *p, struct nf | |||
5544 | if (status != 0) | 5551 | if (status != 0) |
5545 | goto out; | 5552 | goto out; |
5546 | status = decode_delegreturn(&xdr); | 5553 | status = decode_delegreturn(&xdr); |
5554 | if (status != 0) | ||
5555 | goto out; | ||
5547 | decode_getfattr(&xdr, res->fattr, res->server, | 5556 | decode_getfattr(&xdr, res->fattr, res->server, |
5548 | !RPC_IS_ASYNC(rqstp->rq_task)); | 5557 | !RPC_IS_ASYNC(rqstp->rq_task)); |
5549 | out: | 5558 | out: |
@@ -5774,7 +5783,7 @@ static struct { | |||
5774 | { NFS4ERR_BAD_COOKIE, -EBADCOOKIE }, | 5783 | { NFS4ERR_BAD_COOKIE, -EBADCOOKIE }, |
5775 | { NFS4ERR_NOTSUPP, -ENOTSUPP }, | 5784 | { NFS4ERR_NOTSUPP, -ENOTSUPP }, |
5776 | { NFS4ERR_TOOSMALL, -ETOOSMALL }, | 5785 | { NFS4ERR_TOOSMALL, -ETOOSMALL }, |
5777 | { NFS4ERR_SERVERFAULT, -ESERVERFAULT }, | 5786 | { NFS4ERR_SERVERFAULT, -EREMOTEIO }, |
5778 | { NFS4ERR_BADTYPE, -EBADTYPE }, | 5787 | { NFS4ERR_BADTYPE, -EBADTYPE }, |
5779 | { NFS4ERR_LOCKED, -EAGAIN }, | 5788 | { NFS4ERR_LOCKED, -EAGAIN }, |
5780 | { NFS4ERR_SYMLINK, -ELOOP }, | 5789 | { NFS4ERR_SYMLINK, -ELOOP }, |
@@ -5801,7 +5810,7 @@ nfs4_stat_to_errno(int stat) | |||
5801 | } | 5810 | } |
5802 | if (stat <= 10000 || stat > 10100) { | 5811 | if (stat <= 10000 || stat > 10100) { |
5803 | /* The server is looney tunes. */ | 5812 | /* The server is looney tunes. */ |
5804 | return -ESERVERFAULT; | 5813 | return -EREMOTEIO; |
5805 | } | 5814 | } |
5806 | /* If we cannot translate the error, the recovery routines should | 5815 | /* If we cannot translate the error, the recovery routines should |
5807 | * handle it. | 5816 | * handle it. |
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index 8c55b27c0de4..df101d9f546a 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c | |||
@@ -105,7 +105,7 @@ static char nfs_root_name[256] __initdata = ""; | |||
105 | static __be32 servaddr __initdata = 0; | 105 | static __be32 servaddr __initdata = 0; |
106 | 106 | ||
107 | /* Name of directory to mount */ | 107 | /* Name of directory to mount */ |
108 | static char nfs_export_path[NFS_MAXPATHLEN] __initdata = { 0, }; | 108 | static char nfs_export_path[NFS_MAXPATHLEN + 1] __initdata = { 0, }; |
109 | 109 | ||
110 | /* NFS-related data */ | 110 | /* NFS-related data */ |
111 | static struct nfs_mount_data nfs_data __initdata = { 0, };/* NFS mount info */ | 111 | static struct nfs_mount_data nfs_data __initdata = { 0, };/* NFS mount info */ |
@@ -488,7 +488,6 @@ static int __init root_nfs_ports(void) | |||
488 | */ | 488 | */ |
489 | static int __init root_nfs_get_handle(void) | 489 | static int __init root_nfs_get_handle(void) |
490 | { | 490 | { |
491 | struct nfs_fh fh; | ||
492 | struct sockaddr_in sin; | 491 | struct sockaddr_in sin; |
493 | unsigned int auth_flav_len = 0; | 492 | unsigned int auth_flav_len = 0; |
494 | struct nfs_mount_request request = { | 493 | struct nfs_mount_request request = { |
@@ -499,21 +498,24 @@ static int __init root_nfs_get_handle(void) | |||
499 | NFS_MNT3_VERSION : NFS_MNT_VERSION, | 498 | NFS_MNT3_VERSION : NFS_MNT_VERSION, |
500 | .protocol = (nfs_data.flags & NFS_MOUNT_TCP) ? | 499 | .protocol = (nfs_data.flags & NFS_MOUNT_TCP) ? |
501 | XPRT_TRANSPORT_TCP : XPRT_TRANSPORT_UDP, | 500 | XPRT_TRANSPORT_TCP : XPRT_TRANSPORT_UDP, |
502 | .fh = &fh, | ||
503 | .auth_flav_len = &auth_flav_len, | 501 | .auth_flav_len = &auth_flav_len, |
504 | }; | 502 | }; |
505 | int status; | 503 | int status = -ENOMEM; |
506 | 504 | ||
505 | request.fh = nfs_alloc_fhandle(); | ||
506 | if (!request.fh) | ||
507 | goto out; | ||
507 | set_sockaddr(&sin, servaddr, htons(mount_port)); | 508 | set_sockaddr(&sin, servaddr, htons(mount_port)); |
508 | status = nfs_mount(&request); | 509 | status = nfs_mount(&request); |
509 | if (status < 0) | 510 | if (status < 0) |
510 | printk(KERN_ERR "Root-NFS: Server returned error %d " | 511 | printk(KERN_ERR "Root-NFS: Server returned error %d " |
511 | "while mounting %s\n", status, nfs_export_path); | 512 | "while mounting %s\n", status, nfs_export_path); |
512 | else { | 513 | else { |
513 | nfs_data.root.size = fh.size; | 514 | nfs_data.root.size = request.fh->size; |
514 | memcpy(nfs_data.root.data, fh.data, fh.size); | 515 | memcpy(&nfs_data.root.data, request.fh->data, request.fh->size); |
515 | } | 516 | } |
516 | 517 | nfs_free_fhandle(request.fh); | |
518 | out: | ||
517 | return status; | 519 | return status; |
518 | } | 520 | } |
519 | 521 | ||
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index e2975939126a..a3654e57b589 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c | |||
@@ -60,16 +60,10 @@ nfs_create_request(struct nfs_open_context *ctx, struct inode *inode, | |||
60 | { | 60 | { |
61 | struct nfs_page *req; | 61 | struct nfs_page *req; |
62 | 62 | ||
63 | for (;;) { | 63 | /* try to allocate the request struct */ |
64 | /* try to allocate the request struct */ | 64 | req = nfs_page_alloc(); |
65 | req = nfs_page_alloc(); | 65 | if (req == NULL) |
66 | if (req != NULL) | 66 | return ERR_PTR(-ENOMEM); |
67 | break; | ||
68 | |||
69 | if (fatal_signal_pending(current)) | ||
70 | return ERR_PTR(-ERESTARTSYS); | ||
71 | yield(); | ||
72 | } | ||
73 | 67 | ||
74 | /* Initialize the request struct. Initially, we assume a | 68 | /* Initialize the request struct. Initially, we assume a |
75 | * long write-back delay. This will be adjusted in | 69 | * long write-back delay. This will be adjusted in |
@@ -112,12 +106,10 @@ void nfs_unlock_request(struct nfs_page *req) | |||
112 | */ | 106 | */ |
113 | int nfs_set_page_tag_locked(struct nfs_page *req) | 107 | int nfs_set_page_tag_locked(struct nfs_page *req) |
114 | { | 108 | { |
115 | struct nfs_inode *nfsi = NFS_I(req->wb_context->path.dentry->d_inode); | ||
116 | |||
117 | if (!nfs_lock_request_dontget(req)) | 109 | if (!nfs_lock_request_dontget(req)) |
118 | return 0; | 110 | return 0; |
119 | if (req->wb_page != NULL) | 111 | if (req->wb_page != NULL) |
120 | radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); | 112 | radix_tree_tag_set(&NFS_I(req->wb_context->path.dentry->d_inode)->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); |
121 | return 1; | 113 | return 1; |
122 | } | 114 | } |
123 | 115 | ||
@@ -126,10 +118,10 @@ int nfs_set_page_tag_locked(struct nfs_page *req) | |||
126 | */ | 118 | */ |
127 | void nfs_clear_page_tag_locked(struct nfs_page *req) | 119 | void nfs_clear_page_tag_locked(struct nfs_page *req) |
128 | { | 120 | { |
129 | struct inode *inode = req->wb_context->path.dentry->d_inode; | ||
130 | struct nfs_inode *nfsi = NFS_I(inode); | ||
131 | |||
132 | if (req->wb_page != NULL) { | 121 | if (req->wb_page != NULL) { |
122 | struct inode *inode = req->wb_context->path.dentry->d_inode; | ||
123 | struct nfs_inode *nfsi = NFS_I(inode); | ||
124 | |||
133 | spin_lock(&inode->i_lock); | 125 | spin_lock(&inode->i_lock); |
134 | radix_tree_tag_clear(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); | 126 | radix_tree_tag_clear(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); |
135 | nfs_unlock_request(req); | 127 | nfs_unlock_request(req); |
@@ -142,16 +134,22 @@ void nfs_clear_page_tag_locked(struct nfs_page *req) | |||
142 | * nfs_clear_request - Free up all resources allocated to the request | 134 | * nfs_clear_request - Free up all resources allocated to the request |
143 | * @req: | 135 | * @req: |
144 | * | 136 | * |
145 | * Release page resources associated with a write request after it | 137 | * Release page and open context resources associated with a read/write |
146 | * has completed. | 138 | * request after it has completed. |
147 | */ | 139 | */ |
148 | void nfs_clear_request(struct nfs_page *req) | 140 | void nfs_clear_request(struct nfs_page *req) |
149 | { | 141 | { |
150 | struct page *page = req->wb_page; | 142 | struct page *page = req->wb_page; |
143 | struct nfs_open_context *ctx = req->wb_context; | ||
144 | |||
151 | if (page != NULL) { | 145 | if (page != NULL) { |
152 | page_cache_release(page); | 146 | page_cache_release(page); |
153 | req->wb_page = NULL; | 147 | req->wb_page = NULL; |
154 | } | 148 | } |
149 | if (ctx != NULL) { | ||
150 | put_nfs_open_context(ctx); | ||
151 | req->wb_context = NULL; | ||
152 | } | ||
155 | } | 153 | } |
156 | 154 | ||
157 | 155 | ||
@@ -165,9 +163,8 @@ static void nfs_free_request(struct kref *kref) | |||
165 | { | 163 | { |
166 | struct nfs_page *req = container_of(kref, struct nfs_page, wb_kref); | 164 | struct nfs_page *req = container_of(kref, struct nfs_page, wb_kref); |
167 | 165 | ||
168 | /* Release struct file or cached credential */ | 166 | /* Release struct file and open context */ |
169 | nfs_clear_request(req); | 167 | nfs_clear_request(req); |
170 | put_nfs_open_context(req->wb_context); | ||
171 | nfs_page_free(req); | 168 | nfs_page_free(req); |
172 | } | 169 | } |
173 | 170 | ||
@@ -176,6 +173,12 @@ void nfs_release_request(struct nfs_page *req) | |||
176 | kref_put(&req->wb_kref, nfs_free_request); | 173 | kref_put(&req->wb_kref, nfs_free_request); |
177 | } | 174 | } |
178 | 175 | ||
176 | static int nfs_wait_bit_uninterruptible(void *word) | ||
177 | { | ||
178 | io_schedule(); | ||
179 | return 0; | ||
180 | } | ||
181 | |||
179 | /** | 182 | /** |
180 | * nfs_wait_on_request - Wait for a request to complete. | 183 | * nfs_wait_on_request - Wait for a request to complete. |
181 | * @req: request to wait upon. | 184 | * @req: request to wait upon. |
@@ -186,14 +189,9 @@ void nfs_release_request(struct nfs_page *req) | |||
186 | int | 189 | int |
187 | nfs_wait_on_request(struct nfs_page *req) | 190 | nfs_wait_on_request(struct nfs_page *req) |
188 | { | 191 | { |
189 | int ret = 0; | 192 | return wait_on_bit(&req->wb_flags, PG_BUSY, |
190 | 193 | nfs_wait_bit_uninterruptible, | |
191 | if (!test_bit(PG_BUSY, &req->wb_flags)) | 194 | TASK_UNINTERRUPTIBLE); |
192 | goto out; | ||
193 | ret = out_of_line_wait_on_bit(&req->wb_flags, PG_BUSY, | ||
194 | nfs_wait_bit_killable, TASK_KILLABLE); | ||
195 | out: | ||
196 | return ret; | ||
197 | } | 195 | } |
198 | 196 | ||
199 | /** | 197 | /** |
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index ef583854d8d0..611bec22f552 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c | |||
@@ -29,7 +29,6 @@ | |||
29 | 29 | ||
30 | #include <linux/types.h> | 30 | #include <linux/types.h> |
31 | #include <linux/param.h> | 31 | #include <linux/param.h> |
32 | #include <linux/slab.h> | ||
33 | #include <linux/time.h> | 32 | #include <linux/time.h> |
34 | #include <linux/mm.h> | 33 | #include <linux/mm.h> |
35 | #include <linux/errno.h> | 34 | #include <linux/errno.h> |
@@ -47,6 +46,39 @@ | |||
47 | #define NFSDBG_FACILITY NFSDBG_PROC | 46 | #define NFSDBG_FACILITY NFSDBG_PROC |
48 | 47 | ||
49 | /* | 48 | /* |
49 | * wrapper to handle the -EKEYEXPIRED error message. This should generally | ||
50 | * only happen if using krb5 auth and a user's TGT expires. NFSv2 doesn't | ||
51 | * support the NFSERR_JUKEBOX error code, but we handle this situation in the | ||
52 | * same way that we handle that error with NFSv3. | ||
53 | */ | ||
54 | static int | ||
55 | nfs_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags) | ||
56 | { | ||
57 | int res; | ||
58 | do { | ||
59 | res = rpc_call_sync(clnt, msg, flags); | ||
60 | if (res != -EKEYEXPIRED) | ||
61 | break; | ||
62 | schedule_timeout_killable(NFS_JUKEBOX_RETRY_TIME); | ||
63 | res = -ERESTARTSYS; | ||
64 | } while (!fatal_signal_pending(current)); | ||
65 | return res; | ||
66 | } | ||
67 | |||
68 | #define rpc_call_sync(clnt, msg, flags) nfs_rpc_wrapper(clnt, msg, flags) | ||
69 | |||
70 | static int | ||
71 | nfs_async_handle_expired_key(struct rpc_task *task) | ||
72 | { | ||
73 | if (task->tk_status != -EKEYEXPIRED) | ||
74 | return 0; | ||
75 | task->tk_status = 0; | ||
76 | rpc_restart_call(task); | ||
77 | rpc_delay(task, NFS_JUKEBOX_RETRY_TIME); | ||
78 | return 1; | ||
79 | } | ||
80 | |||
81 | /* | ||
50 | * Bare-bones access to getattr: this is for nfs_read_super. | 82 | * Bare-bones access to getattr: this is for nfs_read_super. |
51 | */ | 83 | */ |
52 | static int | 84 | static int |
@@ -192,35 +224,60 @@ static int nfs_proc_readlink(struct inode *inode, struct page *page, | |||
192 | return status; | 224 | return status; |
193 | } | 225 | } |
194 | 226 | ||
227 | struct nfs_createdata { | ||
228 | struct nfs_createargs arg; | ||
229 | struct nfs_diropok res; | ||
230 | struct nfs_fh fhandle; | ||
231 | struct nfs_fattr fattr; | ||
232 | }; | ||
233 | |||
234 | static struct nfs_createdata *nfs_alloc_createdata(struct inode *dir, | ||
235 | struct dentry *dentry, struct iattr *sattr) | ||
236 | { | ||
237 | struct nfs_createdata *data; | ||
238 | |||
239 | data = kmalloc(sizeof(*data), GFP_KERNEL); | ||
240 | |||
241 | if (data != NULL) { | ||
242 | data->arg.fh = NFS_FH(dir); | ||
243 | data->arg.name = dentry->d_name.name; | ||
244 | data->arg.len = dentry->d_name.len; | ||
245 | data->arg.sattr = sattr; | ||
246 | nfs_fattr_init(&data->fattr); | ||
247 | data->fhandle.size = 0; | ||
248 | data->res.fh = &data->fhandle; | ||
249 | data->res.fattr = &data->fattr; | ||
250 | } | ||
251 | return data; | ||
252 | }; | ||
253 | |||
254 | static void nfs_free_createdata(const struct nfs_createdata *data) | ||
255 | { | ||
256 | kfree(data); | ||
257 | } | ||
258 | |||
195 | static int | 259 | static int |
196 | nfs_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | 260 | nfs_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, |
197 | int flags, struct nameidata *nd) | 261 | int flags, struct nameidata *nd) |
198 | { | 262 | { |
199 | struct nfs_fh fhandle; | 263 | struct nfs_createdata *data; |
200 | struct nfs_fattr fattr; | ||
201 | struct nfs_createargs arg = { | ||
202 | .fh = NFS_FH(dir), | ||
203 | .name = dentry->d_name.name, | ||
204 | .len = dentry->d_name.len, | ||
205 | .sattr = sattr | ||
206 | }; | ||
207 | struct nfs_diropok res = { | ||
208 | .fh = &fhandle, | ||
209 | .fattr = &fattr | ||
210 | }; | ||
211 | struct rpc_message msg = { | 264 | struct rpc_message msg = { |
212 | .rpc_proc = &nfs_procedures[NFSPROC_CREATE], | 265 | .rpc_proc = &nfs_procedures[NFSPROC_CREATE], |
213 | .rpc_argp = &arg, | ||
214 | .rpc_resp = &res, | ||
215 | }; | 266 | }; |
216 | int status; | 267 | int status = -ENOMEM; |
217 | 268 | ||
218 | nfs_fattr_init(&fattr); | ||
219 | dprintk("NFS call create %s\n", dentry->d_name.name); | 269 | dprintk("NFS call create %s\n", dentry->d_name.name); |
270 | data = nfs_alloc_createdata(dir, dentry, sattr); | ||
271 | if (data == NULL) | ||
272 | goto out; | ||
273 | msg.rpc_argp = &data->arg; | ||
274 | msg.rpc_resp = &data->res; | ||
220 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 275 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
221 | nfs_mark_for_revalidate(dir); | 276 | nfs_mark_for_revalidate(dir); |
222 | if (status == 0) | 277 | if (status == 0) |
223 | status = nfs_instantiate(dentry, &fhandle, &fattr); | 278 | status = nfs_instantiate(dentry, data->res.fh, data->res.fattr); |
279 | nfs_free_createdata(data); | ||
280 | out: | ||
224 | dprintk("NFS reply create: %d\n", status); | 281 | dprintk("NFS reply create: %d\n", status); |
225 | return status; | 282 | return status; |
226 | } | 283 | } |
@@ -232,24 +289,12 @@ static int | |||
232 | nfs_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | 289 | nfs_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, |
233 | dev_t rdev) | 290 | dev_t rdev) |
234 | { | 291 | { |
235 | struct nfs_fh fhandle; | 292 | struct nfs_createdata *data; |
236 | struct nfs_fattr fattr; | ||
237 | struct nfs_createargs arg = { | ||
238 | .fh = NFS_FH(dir), | ||
239 | .name = dentry->d_name.name, | ||
240 | .len = dentry->d_name.len, | ||
241 | .sattr = sattr | ||
242 | }; | ||
243 | struct nfs_diropok res = { | ||
244 | .fh = &fhandle, | ||
245 | .fattr = &fattr | ||
246 | }; | ||
247 | struct rpc_message msg = { | 293 | struct rpc_message msg = { |
248 | .rpc_proc = &nfs_procedures[NFSPROC_CREATE], | 294 | .rpc_proc = &nfs_procedures[NFSPROC_CREATE], |
249 | .rpc_argp = &arg, | ||
250 | .rpc_resp = &res, | ||
251 | }; | 295 | }; |
252 | int status, mode; | 296 | umode_t mode; |
297 | int status = -ENOMEM; | ||
253 | 298 | ||
254 | dprintk("NFS call mknod %s\n", dentry->d_name.name); | 299 | dprintk("NFS call mknod %s\n", dentry->d_name.name); |
255 | 300 | ||
@@ -262,17 +307,24 @@ nfs_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
262 | sattr->ia_size = new_encode_dev(rdev);/* get out your barf bag */ | 307 | sattr->ia_size = new_encode_dev(rdev);/* get out your barf bag */ |
263 | } | 308 | } |
264 | 309 | ||
265 | nfs_fattr_init(&fattr); | 310 | data = nfs_alloc_createdata(dir, dentry, sattr); |
311 | if (data == NULL) | ||
312 | goto out; | ||
313 | msg.rpc_argp = &data->arg; | ||
314 | msg.rpc_resp = &data->res; | ||
315 | |||
266 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 316 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
267 | nfs_mark_for_revalidate(dir); | 317 | nfs_mark_for_revalidate(dir); |
268 | 318 | ||
269 | if (status == -EINVAL && S_ISFIFO(mode)) { | 319 | if (status == -EINVAL && S_ISFIFO(mode)) { |
270 | sattr->ia_mode = mode; | 320 | sattr->ia_mode = mode; |
271 | nfs_fattr_init(&fattr); | 321 | nfs_fattr_init(data->res.fattr); |
272 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 322 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
273 | } | 323 | } |
274 | if (status == 0) | 324 | if (status == 0) |
275 | status = nfs_instantiate(dentry, &fhandle, &fattr); | 325 | status = nfs_instantiate(dentry, data->res.fh, data->res.fattr); |
326 | nfs_free_createdata(data); | ||
327 | out: | ||
276 | dprintk("NFS reply mknod: %d\n", status); | 328 | dprintk("NFS reply mknod: %d\n", status); |
277 | return status; | 329 | return status; |
278 | } | 330 | } |
@@ -307,6 +359,8 @@ nfs_proc_unlink_setup(struct rpc_message *msg, struct inode *dir) | |||
307 | 359 | ||
308 | static int nfs_proc_unlink_done(struct rpc_task *task, struct inode *dir) | 360 | static int nfs_proc_unlink_done(struct rpc_task *task, struct inode *dir) |
309 | { | 361 | { |
362 | if (nfs_async_handle_expired_key(task)) | ||
363 | return 0; | ||
310 | nfs_mark_for_revalidate(dir); | 364 | nfs_mark_for_revalidate(dir); |
311 | return 1; | 365 | return 1; |
312 | } | 366 | } |
@@ -364,8 +418,8 @@ static int | |||
364 | nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page, | 418 | nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page, |
365 | unsigned int len, struct iattr *sattr) | 419 | unsigned int len, struct iattr *sattr) |
366 | { | 420 | { |
367 | struct nfs_fh fhandle; | 421 | struct nfs_fh *fh; |
368 | struct nfs_fattr fattr; | 422 | struct nfs_fattr *fattr; |
369 | struct nfs_symlinkargs arg = { | 423 | struct nfs_symlinkargs arg = { |
370 | .fromfh = NFS_FH(dir), | 424 | .fromfh = NFS_FH(dir), |
371 | .fromname = dentry->d_name.name, | 425 | .fromname = dentry->d_name.name, |
@@ -378,12 +432,18 @@ nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page, | |||
378 | .rpc_proc = &nfs_procedures[NFSPROC_SYMLINK], | 432 | .rpc_proc = &nfs_procedures[NFSPROC_SYMLINK], |
379 | .rpc_argp = &arg, | 433 | .rpc_argp = &arg, |
380 | }; | 434 | }; |
381 | int status; | 435 | int status = -ENAMETOOLONG; |
436 | |||
437 | dprintk("NFS call symlink %s\n", dentry->d_name.name); | ||
382 | 438 | ||
383 | if (len > NFS2_MAXPATHLEN) | 439 | if (len > NFS2_MAXPATHLEN) |
384 | return -ENAMETOOLONG; | 440 | goto out; |
385 | 441 | ||
386 | dprintk("NFS call symlink %s\n", dentry->d_name.name); | 442 | fh = nfs_alloc_fhandle(); |
443 | fattr = nfs_alloc_fattr(); | ||
444 | status = -ENOMEM; | ||
445 | if (fh == NULL || fattr == NULL) | ||
446 | goto out; | ||
387 | 447 | ||
388 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 448 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
389 | nfs_mark_for_revalidate(dir); | 449 | nfs_mark_for_revalidate(dir); |
@@ -393,12 +453,12 @@ nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page, | |||
393 | * filehandle size to zero indicates to nfs_instantiate that it | 453 | * filehandle size to zero indicates to nfs_instantiate that it |
394 | * should fill in the data with a LOOKUP call on the wire. | 454 | * should fill in the data with a LOOKUP call on the wire. |
395 | */ | 455 | */ |
396 | if (status == 0) { | 456 | if (status == 0) |
397 | nfs_fattr_init(&fattr); | 457 | status = nfs_instantiate(dentry, fh, fattr); |
398 | fhandle.size = 0; | ||
399 | status = nfs_instantiate(dentry, &fhandle, &fattr); | ||
400 | } | ||
401 | 458 | ||
459 | nfs_free_fattr(fattr); | ||
460 | nfs_free_fhandle(fh); | ||
461 | out: | ||
402 | dprintk("NFS reply symlink: %d\n", status); | 462 | dprintk("NFS reply symlink: %d\n", status); |
403 | return status; | 463 | return status; |
404 | } | 464 | } |
@@ -406,31 +466,25 @@ nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page, | |||
406 | static int | 466 | static int |
407 | nfs_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) | 467 | nfs_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) |
408 | { | 468 | { |
409 | struct nfs_fh fhandle; | 469 | struct nfs_createdata *data; |
410 | struct nfs_fattr fattr; | ||
411 | struct nfs_createargs arg = { | ||
412 | .fh = NFS_FH(dir), | ||
413 | .name = dentry->d_name.name, | ||
414 | .len = dentry->d_name.len, | ||
415 | .sattr = sattr | ||
416 | }; | ||
417 | struct nfs_diropok res = { | ||
418 | .fh = &fhandle, | ||
419 | .fattr = &fattr | ||
420 | }; | ||
421 | struct rpc_message msg = { | 470 | struct rpc_message msg = { |
422 | .rpc_proc = &nfs_procedures[NFSPROC_MKDIR], | 471 | .rpc_proc = &nfs_procedures[NFSPROC_MKDIR], |
423 | .rpc_argp = &arg, | ||
424 | .rpc_resp = &res, | ||
425 | }; | 472 | }; |
426 | int status; | 473 | int status = -ENOMEM; |
427 | 474 | ||
428 | dprintk("NFS call mkdir %s\n", dentry->d_name.name); | 475 | dprintk("NFS call mkdir %s\n", dentry->d_name.name); |
429 | nfs_fattr_init(&fattr); | 476 | data = nfs_alloc_createdata(dir, dentry, sattr); |
477 | if (data == NULL) | ||
478 | goto out; | ||
479 | msg.rpc_argp = &data->arg; | ||
480 | msg.rpc_resp = &data->res; | ||
481 | |||
430 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 482 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
431 | nfs_mark_for_revalidate(dir); | 483 | nfs_mark_for_revalidate(dir); |
432 | if (status == 0) | 484 | if (status == 0) |
433 | status = nfs_instantiate(dentry, &fhandle, &fattr); | 485 | status = nfs_instantiate(dentry, data->res.fh, data->res.fattr); |
486 | nfs_free_createdata(data); | ||
487 | out: | ||
434 | dprintk("NFS reply mkdir: %d\n", status); | 488 | dprintk("NFS reply mkdir: %d\n", status); |
435 | return status; | 489 | return status; |
436 | } | 490 | } |
@@ -560,6 +614,9 @@ nfs_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, | |||
560 | 614 | ||
561 | static int nfs_read_done(struct rpc_task *task, struct nfs_read_data *data) | 615 | static int nfs_read_done(struct rpc_task *task, struct nfs_read_data *data) |
562 | { | 616 | { |
617 | if (nfs_async_handle_expired_key(task)) | ||
618 | return -EAGAIN; | ||
619 | |||
563 | nfs_invalidate_atime(data->inode); | 620 | nfs_invalidate_atime(data->inode); |
564 | if (task->tk_status >= 0) { | 621 | if (task->tk_status >= 0) { |
565 | nfs_refresh_inode(data->inode, data->res.fattr); | 622 | nfs_refresh_inode(data->inode, data->res.fattr); |
@@ -579,6 +636,9 @@ static void nfs_proc_read_setup(struct nfs_read_data *data, struct rpc_message * | |||
579 | 636 | ||
580 | static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data) | 637 | static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data) |
581 | { | 638 | { |
639 | if (nfs_async_handle_expired_key(task)) | ||
640 | return -EAGAIN; | ||
641 | |||
582 | if (task->tk_status >= 0) | 642 | if (task->tk_status >= 0) |
583 | nfs_post_op_update_inode_force_wcc(data->inode, data->res.fattr); | 643 | nfs_post_op_update_inode_force_wcc(data->inode, data->res.fattr); |
584 | return 0; | 644 | return 0; |
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index db9b360ae19d..6e2b06e6ca79 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
@@ -40,7 +40,7 @@ static mempool_t *nfs_rdata_mempool; | |||
40 | 40 | ||
41 | struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount) | 41 | struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount) |
42 | { | 42 | { |
43 | struct nfs_read_data *p = mempool_alloc(nfs_rdata_mempool, GFP_NOFS); | 43 | struct nfs_read_data *p = mempool_alloc(nfs_rdata_mempool, GFP_KERNEL); |
44 | 44 | ||
45 | if (p) { | 45 | if (p) { |
46 | memset(p, 0, sizeof(*p)); | 46 | memset(p, 0, sizeof(*p)); |
@@ -50,7 +50,7 @@ struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount) | |||
50 | if (pagecount <= ARRAY_SIZE(p->page_array)) | 50 | if (pagecount <= ARRAY_SIZE(p->page_array)) |
51 | p->pagevec = p->page_array; | 51 | p->pagevec = p->page_array; |
52 | else { | 52 | else { |
53 | p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_NOFS); | 53 | p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_KERNEL); |
54 | if (!p->pagevec) { | 54 | if (!p->pagevec) { |
55 | mempool_free(p, nfs_rdata_mempool); | 55 | mempool_free(p, nfs_rdata_mempool); |
56 | p = NULL; | 56 | p = NULL; |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index ce907efc5508..f9df16de4a56 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -48,6 +48,7 @@ | |||
48 | #include <linux/vfs.h> | 48 | #include <linux/vfs.h> |
49 | #include <linux/inet.h> | 49 | #include <linux/inet.h> |
50 | #include <linux/in6.h> | 50 | #include <linux/in6.h> |
51 | #include <linux/slab.h> | ||
51 | #include <net/ipv6.h> | 52 | #include <net/ipv6.h> |
52 | #include <linux/netdevice.h> | 53 | #include <linux/netdevice.h> |
53 | #include <linux/nfs_xdr.h> | 54 | #include <linux/nfs_xdr.h> |
@@ -140,7 +141,6 @@ static const match_table_t nfs_mount_option_tokens = { | |||
140 | { Opt_resvport, "resvport" }, | 141 | { Opt_resvport, "resvport" }, |
141 | { Opt_noresvport, "noresvport" }, | 142 | { Opt_noresvport, "noresvport" }, |
142 | { Opt_fscache, "fsc" }, | 143 | { Opt_fscache, "fsc" }, |
143 | { Opt_fscache_uniq, "fsc=%s" }, | ||
144 | { Opt_nofscache, "nofsc" }, | 144 | { Opt_nofscache, "nofsc" }, |
145 | 145 | ||
146 | { Opt_port, "port=%s" }, | 146 | { Opt_port, "port=%s" }, |
@@ -170,6 +170,7 @@ static const match_table_t nfs_mount_option_tokens = { | |||
170 | { Opt_mountaddr, "mountaddr=%s" }, | 170 | { Opt_mountaddr, "mountaddr=%s" }, |
171 | 171 | ||
172 | { Opt_lookupcache, "lookupcache=%s" }, | 172 | { Opt_lookupcache, "lookupcache=%s" }, |
173 | { Opt_fscache_uniq, "fsc=%s" }, | ||
173 | 174 | ||
174 | { Opt_err, NULL } | 175 | { Opt_err, NULL } |
175 | }; | 176 | }; |
@@ -243,6 +244,7 @@ static int nfs_show_stats(struct seq_file *, struct vfsmount *); | |||
243 | static int nfs_get_sb(struct file_system_type *, int, const char *, void *, struct vfsmount *); | 244 | static int nfs_get_sb(struct file_system_type *, int, const char *, void *, struct vfsmount *); |
244 | static int nfs_xdev_get_sb(struct file_system_type *fs_type, | 245 | static int nfs_xdev_get_sb(struct file_system_type *fs_type, |
245 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | 246 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); |
247 | static void nfs_put_super(struct super_block *); | ||
246 | static void nfs_kill_super(struct super_block *); | 248 | static void nfs_kill_super(struct super_block *); |
247 | static int nfs_remount(struct super_block *sb, int *flags, char *raw_data); | 249 | static int nfs_remount(struct super_block *sb, int *flags, char *raw_data); |
248 | 250 | ||
@@ -266,6 +268,7 @@ static const struct super_operations nfs_sops = { | |||
266 | .alloc_inode = nfs_alloc_inode, | 268 | .alloc_inode = nfs_alloc_inode, |
267 | .destroy_inode = nfs_destroy_inode, | 269 | .destroy_inode = nfs_destroy_inode, |
268 | .write_inode = nfs_write_inode, | 270 | .write_inode = nfs_write_inode, |
271 | .put_super = nfs_put_super, | ||
269 | .statfs = nfs_statfs, | 272 | .statfs = nfs_statfs, |
270 | .clear_inode = nfs_clear_inode, | 273 | .clear_inode = nfs_clear_inode, |
271 | .umount_begin = nfs_umount_begin, | 274 | .umount_begin = nfs_umount_begin, |
@@ -335,6 +338,7 @@ static const struct super_operations nfs4_sops = { | |||
335 | .alloc_inode = nfs_alloc_inode, | 338 | .alloc_inode = nfs_alloc_inode, |
336 | .destroy_inode = nfs_destroy_inode, | 339 | .destroy_inode = nfs_destroy_inode, |
337 | .write_inode = nfs_write_inode, | 340 | .write_inode = nfs_write_inode, |
341 | .put_super = nfs_put_super, | ||
338 | .statfs = nfs_statfs, | 342 | .statfs = nfs_statfs, |
339 | .clear_inode = nfs4_clear_inode, | 343 | .clear_inode = nfs4_clear_inode, |
340 | .umount_begin = nfs_umount_begin, | 344 | .umount_begin = nfs_umount_begin, |
@@ -419,15 +423,19 @@ static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
419 | unsigned char blockbits; | 423 | unsigned char blockbits; |
420 | unsigned long blockres; | 424 | unsigned long blockres; |
421 | struct nfs_fh *fh = NFS_FH(dentry->d_inode); | 425 | struct nfs_fh *fh = NFS_FH(dentry->d_inode); |
422 | struct nfs_fattr fattr; | 426 | struct nfs_fsstat res; |
423 | struct nfs_fsstat res = { | 427 | int error = -ENOMEM; |
424 | .fattr = &fattr, | 428 | |
425 | }; | 429 | res.fattr = nfs_alloc_fattr(); |
426 | int error; | 430 | if (res.fattr == NULL) |
431 | goto out_err; | ||
427 | 432 | ||
428 | error = server->nfs_client->rpc_ops->statfs(server, fh, &res); | 433 | error = server->nfs_client->rpc_ops->statfs(server, fh, &res); |
434 | |||
435 | nfs_free_fattr(res.fattr); | ||
429 | if (error < 0) | 436 | if (error < 0) |
430 | goto out_err; | 437 | goto out_err; |
438 | |||
431 | buf->f_type = NFS_SUPER_MAGIC; | 439 | buf->f_type = NFS_SUPER_MAGIC; |
432 | 440 | ||
433 | /* | 441 | /* |
@@ -562,6 +570,22 @@ static void nfs_show_mountd_options(struct seq_file *m, struct nfs_server *nfss, | |||
562 | nfs_show_mountd_netid(m, nfss, showdefaults); | 570 | nfs_show_mountd_netid(m, nfss, showdefaults); |
563 | } | 571 | } |
564 | 572 | ||
573 | #ifdef CONFIG_NFS_V4 | ||
574 | static void nfs_show_nfsv4_options(struct seq_file *m, struct nfs_server *nfss, | ||
575 | int showdefaults) | ||
576 | { | ||
577 | struct nfs_client *clp = nfss->nfs_client; | ||
578 | |||
579 | seq_printf(m, ",clientaddr=%s", clp->cl_ipaddr); | ||
580 | seq_printf(m, ",minorversion=%u", clp->cl_minorversion); | ||
581 | } | ||
582 | #else | ||
583 | static void nfs_show_nfsv4_options(struct seq_file *m, struct nfs_server *nfss, | ||
584 | int showdefaults) | ||
585 | { | ||
586 | } | ||
587 | #endif | ||
588 | |||
565 | /* | 589 | /* |
566 | * Describe the mount options in force on this server representation | 590 | * Describe the mount options in force on this server representation |
567 | */ | 591 | */ |
@@ -623,11 +647,9 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |||
623 | 647 | ||
624 | if (version != 4) | 648 | if (version != 4) |
625 | nfs_show_mountd_options(m, nfss, showdefaults); | 649 | nfs_show_mountd_options(m, nfss, showdefaults); |
650 | else | ||
651 | nfs_show_nfsv4_options(m, nfss, showdefaults); | ||
626 | 652 | ||
627 | #ifdef CONFIG_NFS_V4 | ||
628 | if (clp->rpc_ops->version == 4) | ||
629 | seq_printf(m, ",clientaddr=%s", clp->cl_ipaddr); | ||
630 | #endif | ||
631 | if (nfss->options & NFS_OPTION_FSCACHE) | 653 | if (nfss->options & NFS_OPTION_FSCACHE) |
632 | seq_printf(m, ",fsc"); | 654 | seq_printf(m, ",fsc"); |
633 | } | 655 | } |
@@ -1042,14 +1064,6 @@ static int nfs_parse_mount_options(char *raw, | |||
1042 | kfree(mnt->fscache_uniq); | 1064 | kfree(mnt->fscache_uniq); |
1043 | mnt->fscache_uniq = NULL; | 1065 | mnt->fscache_uniq = NULL; |
1044 | break; | 1066 | break; |
1045 | case Opt_fscache_uniq: | ||
1046 | string = match_strdup(args); | ||
1047 | if (!string) | ||
1048 | goto out_nomem; | ||
1049 | kfree(mnt->fscache_uniq); | ||
1050 | mnt->fscache_uniq = string; | ||
1051 | mnt->options |= NFS_OPTION_FSCACHE; | ||
1052 | break; | ||
1053 | 1067 | ||
1054 | /* | 1068 | /* |
1055 | * options that take numeric values | 1069 | * options that take numeric values |
@@ -1060,7 +1074,7 @@ static int nfs_parse_mount_options(char *raw, | |||
1060 | goto out_nomem; | 1074 | goto out_nomem; |
1061 | rc = strict_strtoul(string, 10, &option); | 1075 | rc = strict_strtoul(string, 10, &option); |
1062 | kfree(string); | 1076 | kfree(string); |
1063 | if (rc != 0 || option > USHORT_MAX) | 1077 | if (rc != 0 || option > USHRT_MAX) |
1064 | goto out_invalid_value; | 1078 | goto out_invalid_value; |
1065 | mnt->nfs_server.port = option; | 1079 | mnt->nfs_server.port = option; |
1066 | break; | 1080 | break; |
@@ -1181,7 +1195,7 @@ static int nfs_parse_mount_options(char *raw, | |||
1181 | goto out_nomem; | 1195 | goto out_nomem; |
1182 | rc = strict_strtoul(string, 10, &option); | 1196 | rc = strict_strtoul(string, 10, &option); |
1183 | kfree(string); | 1197 | kfree(string); |
1184 | if (rc != 0 || option > USHORT_MAX) | 1198 | if (rc != 0 || option > USHRT_MAX) |
1185 | goto out_invalid_value; | 1199 | goto out_invalid_value; |
1186 | mnt->mount_server.port = option; | 1200 | mnt->mount_server.port = option; |
1187 | break; | 1201 | break; |
@@ -1380,6 +1394,14 @@ static int nfs_parse_mount_options(char *raw, | |||
1380 | return 0; | 1394 | return 0; |
1381 | }; | 1395 | }; |
1382 | break; | 1396 | break; |
1397 | case Opt_fscache_uniq: | ||
1398 | string = match_strdup(args); | ||
1399 | if (string == NULL) | ||
1400 | goto out_nomem; | ||
1401 | kfree(mnt->fscache_uniq); | ||
1402 | mnt->fscache_uniq = string; | ||
1403 | mnt->options |= NFS_OPTION_FSCACHE; | ||
1404 | break; | ||
1383 | 1405 | ||
1384 | /* | 1406 | /* |
1385 | * Special options | 1407 | * Special options |
@@ -2168,7 +2190,7 @@ static int nfs_get_sb(struct file_system_type *fs_type, | |||
2168 | int error = -ENOMEM; | 2190 | int error = -ENOMEM; |
2169 | 2191 | ||
2170 | data = nfs_alloc_parsed_mount_data(3); | 2192 | data = nfs_alloc_parsed_mount_data(3); |
2171 | mntfh = kzalloc(sizeof(*mntfh), GFP_KERNEL); | 2193 | mntfh = nfs_alloc_fhandle(); |
2172 | if (data == NULL || mntfh == NULL) | 2194 | if (data == NULL || mntfh == NULL) |
2173 | goto out_free_fh; | 2195 | goto out_free_fh; |
2174 | 2196 | ||
@@ -2183,6 +2205,7 @@ static int nfs_get_sb(struct file_system_type *fs_type, | |||
2183 | if (data->version == 4) { | 2205 | if (data->version == 4) { |
2184 | error = nfs4_try_mount(flags, dev_name, data, mnt); | 2206 | error = nfs4_try_mount(flags, dev_name, data, mnt); |
2185 | kfree(data->client_address); | 2207 | kfree(data->client_address); |
2208 | kfree(data->nfs_server.export_path); | ||
2186 | goto out; | 2209 | goto out; |
2187 | } | 2210 | } |
2188 | #endif /* CONFIG_NFS_V4 */ | 2211 | #endif /* CONFIG_NFS_V4 */ |
@@ -2211,7 +2234,7 @@ static int nfs_get_sb(struct file_system_type *fs_type, | |||
2211 | } else { | 2234 | } else { |
2212 | error = nfs_bdi_register(server); | 2235 | error = nfs_bdi_register(server); |
2213 | if (error) | 2236 | if (error) |
2214 | goto error_splat_super; | 2237 | goto error_splat_bdi; |
2215 | } | 2238 | } |
2216 | 2239 | ||
2217 | if (!s->s_root) { | 2240 | if (!s->s_root) { |
@@ -2242,7 +2265,7 @@ out: | |||
2242 | kfree(data->fscache_uniq); | 2265 | kfree(data->fscache_uniq); |
2243 | security_free_mnt_opts(&data->lsm_opts); | 2266 | security_free_mnt_opts(&data->lsm_opts); |
2244 | out_free_fh: | 2267 | out_free_fh: |
2245 | kfree(mntfh); | 2268 | nfs_free_fhandle(mntfh); |
2246 | kfree(data); | 2269 | kfree(data); |
2247 | return error; | 2270 | return error; |
2248 | 2271 | ||
@@ -2253,11 +2276,25 @@ out_err_nosb: | |||
2253 | error_splat_root: | 2276 | error_splat_root: |
2254 | dput(mntroot); | 2277 | dput(mntroot); |
2255 | error_splat_super: | 2278 | error_splat_super: |
2279 | if (server && !s->s_root) | ||
2280 | bdi_unregister(&server->backing_dev_info); | ||
2281 | error_splat_bdi: | ||
2256 | deactivate_locked_super(s); | 2282 | deactivate_locked_super(s); |
2257 | goto out; | 2283 | goto out; |
2258 | } | 2284 | } |
2259 | 2285 | ||
2260 | /* | 2286 | /* |
2287 | * Ensure that we unregister the bdi before kill_anon_super | ||
2288 | * releases the device name | ||
2289 | */ | ||
2290 | static void nfs_put_super(struct super_block *s) | ||
2291 | { | ||
2292 | struct nfs_server *server = NFS_SB(s); | ||
2293 | |||
2294 | bdi_unregister(&server->backing_dev_info); | ||
2295 | } | ||
2296 | |||
2297 | /* | ||
2261 | * Destroy an NFS2/3 superblock | 2298 | * Destroy an NFS2/3 superblock |
2262 | */ | 2299 | */ |
2263 | static void nfs_kill_super(struct super_block *s) | 2300 | static void nfs_kill_super(struct super_block *s) |
@@ -2265,7 +2302,6 @@ static void nfs_kill_super(struct super_block *s) | |||
2265 | struct nfs_server *server = NFS_SB(s); | 2302 | struct nfs_server *server = NFS_SB(s); |
2266 | 2303 | ||
2267 | kill_anon_super(s); | 2304 | kill_anon_super(s); |
2268 | bdi_unregister(&server->backing_dev_info); | ||
2269 | nfs_fscache_release_super_cookie(s); | 2305 | nfs_fscache_release_super_cookie(s); |
2270 | nfs_free_server(server); | 2306 | nfs_free_server(server); |
2271 | } | 2307 | } |
@@ -2313,7 +2349,7 @@ static int nfs_xdev_get_sb(struct file_system_type *fs_type, int flags, | |||
2313 | } else { | 2349 | } else { |
2314 | error = nfs_bdi_register(server); | 2350 | error = nfs_bdi_register(server); |
2315 | if (error) | 2351 | if (error) |
2316 | goto error_splat_super; | 2352 | goto error_splat_bdi; |
2317 | } | 2353 | } |
2318 | 2354 | ||
2319 | if (!s->s_root) { | 2355 | if (!s->s_root) { |
@@ -2350,6 +2386,9 @@ out_err_noserver: | |||
2350 | return error; | 2386 | return error; |
2351 | 2387 | ||
2352 | error_splat_super: | 2388 | error_splat_super: |
2389 | if (server && !s->s_root) | ||
2390 | bdi_unregister(&server->backing_dev_info); | ||
2391 | error_splat_bdi: | ||
2353 | deactivate_locked_super(s); | 2392 | deactivate_locked_super(s); |
2354 | dprintk("<-- nfs_xdev_get_sb() = %d [splat]\n", error); | 2393 | dprintk("<-- nfs_xdev_get_sb() = %d [splat]\n", error); |
2355 | return error; | 2394 | return error; |
@@ -2535,7 +2574,7 @@ static int nfs4_remote_get_sb(struct file_system_type *fs_type, | |||
2535 | }; | 2574 | }; |
2536 | int error = -ENOMEM; | 2575 | int error = -ENOMEM; |
2537 | 2576 | ||
2538 | mntfh = kzalloc(sizeof(*mntfh), GFP_KERNEL); | 2577 | mntfh = nfs_alloc_fhandle(); |
2539 | if (data == NULL || mntfh == NULL) | 2578 | if (data == NULL || mntfh == NULL) |
2540 | goto out_free_fh; | 2579 | goto out_free_fh; |
2541 | 2580 | ||
@@ -2565,7 +2604,7 @@ static int nfs4_remote_get_sb(struct file_system_type *fs_type, | |||
2565 | } else { | 2604 | } else { |
2566 | error = nfs_bdi_register(server); | 2605 | error = nfs_bdi_register(server); |
2567 | if (error) | 2606 | if (error) |
2568 | goto error_splat_super; | 2607 | goto error_splat_bdi; |
2569 | } | 2608 | } |
2570 | 2609 | ||
2571 | if (!s->s_root) { | 2610 | if (!s->s_root) { |
@@ -2593,7 +2632,7 @@ static int nfs4_remote_get_sb(struct file_system_type *fs_type, | |||
2593 | out: | 2632 | out: |
2594 | security_free_mnt_opts(&data->lsm_opts); | 2633 | security_free_mnt_opts(&data->lsm_opts); |
2595 | out_free_fh: | 2634 | out_free_fh: |
2596 | kfree(mntfh); | 2635 | nfs_free_fhandle(mntfh); |
2597 | return error; | 2636 | return error; |
2598 | 2637 | ||
2599 | out_free: | 2638 | out_free: |
@@ -2603,6 +2642,9 @@ out_free: | |||
2603 | error_splat_root: | 2642 | error_splat_root: |
2604 | dput(mntroot); | 2643 | dput(mntroot); |
2605 | error_splat_super: | 2644 | error_splat_super: |
2645 | if (server && !s->s_root) | ||
2646 | bdi_unregister(&server->backing_dev_info); | ||
2647 | error_splat_bdi: | ||
2606 | deactivate_locked_super(s); | 2648 | deactivate_locked_super(s); |
2607 | goto out; | 2649 | goto out; |
2608 | } | 2650 | } |
@@ -2634,7 +2676,7 @@ static void nfs_fix_devname(const struct path *path, struct vfsmount *mnt) | |||
2634 | devname = nfs_path(path->mnt->mnt_devname, | 2676 | devname = nfs_path(path->mnt->mnt_devname, |
2635 | path->mnt->mnt_root, path->dentry, | 2677 | path->mnt->mnt_root, path->dentry, |
2636 | page, PAGE_SIZE); | 2678 | page, PAGE_SIZE); |
2637 | if (devname == NULL) | 2679 | if (IS_ERR(devname)) |
2638 | goto out_freepage; | 2680 | goto out_freepage; |
2639 | tmp = kstrdup(devname, GFP_KERNEL); | 2681 | tmp = kstrdup(devname, GFP_KERNEL); |
2640 | if (tmp == NULL) | 2682 | if (tmp == NULL) |
@@ -2645,41 +2687,120 @@ out_freepage: | |||
2645 | free_page((unsigned long)page); | 2687 | free_page((unsigned long)page); |
2646 | } | 2688 | } |
2647 | 2689 | ||
2690 | struct nfs_referral_count { | ||
2691 | struct list_head list; | ||
2692 | const struct task_struct *task; | ||
2693 | unsigned int referral_count; | ||
2694 | }; | ||
2695 | |||
2696 | static LIST_HEAD(nfs_referral_count_list); | ||
2697 | static DEFINE_SPINLOCK(nfs_referral_count_list_lock); | ||
2698 | |||
2699 | static struct nfs_referral_count *nfs_find_referral_count(void) | ||
2700 | { | ||
2701 | struct nfs_referral_count *p; | ||
2702 | |||
2703 | list_for_each_entry(p, &nfs_referral_count_list, list) { | ||
2704 | if (p->task == current) | ||
2705 | return p; | ||
2706 | } | ||
2707 | return NULL; | ||
2708 | } | ||
2709 | |||
2710 | #define NFS_MAX_NESTED_REFERRALS 2 | ||
2711 | |||
2712 | static int nfs_referral_loop_protect(void) | ||
2713 | { | ||
2714 | struct nfs_referral_count *p, *new; | ||
2715 | int ret = -ENOMEM; | ||
2716 | |||
2717 | new = kmalloc(sizeof(*new), GFP_KERNEL); | ||
2718 | if (!new) | ||
2719 | goto out; | ||
2720 | new->task = current; | ||
2721 | new->referral_count = 1; | ||
2722 | |||
2723 | ret = 0; | ||
2724 | spin_lock(&nfs_referral_count_list_lock); | ||
2725 | p = nfs_find_referral_count(); | ||
2726 | if (p != NULL) { | ||
2727 | if (p->referral_count >= NFS_MAX_NESTED_REFERRALS) | ||
2728 | ret = -ELOOP; | ||
2729 | else | ||
2730 | p->referral_count++; | ||
2731 | } else { | ||
2732 | list_add(&new->list, &nfs_referral_count_list); | ||
2733 | new = NULL; | ||
2734 | } | ||
2735 | spin_unlock(&nfs_referral_count_list_lock); | ||
2736 | kfree(new); | ||
2737 | out: | ||
2738 | return ret; | ||
2739 | } | ||
2740 | |||
2741 | static void nfs_referral_loop_unprotect(void) | ||
2742 | { | ||
2743 | struct nfs_referral_count *p; | ||
2744 | |||
2745 | spin_lock(&nfs_referral_count_list_lock); | ||
2746 | p = nfs_find_referral_count(); | ||
2747 | p->referral_count--; | ||
2748 | if (p->referral_count == 0) | ||
2749 | list_del(&p->list); | ||
2750 | else | ||
2751 | p = NULL; | ||
2752 | spin_unlock(&nfs_referral_count_list_lock); | ||
2753 | kfree(p); | ||
2754 | } | ||
2755 | |||
2648 | static int nfs_follow_remote_path(struct vfsmount *root_mnt, | 2756 | static int nfs_follow_remote_path(struct vfsmount *root_mnt, |
2649 | const char *export_path, struct vfsmount *mnt_target) | 2757 | const char *export_path, struct vfsmount *mnt_target) |
2650 | { | 2758 | { |
2759 | struct nameidata *nd = NULL; | ||
2651 | struct mnt_namespace *ns_private; | 2760 | struct mnt_namespace *ns_private; |
2652 | struct nameidata nd; | ||
2653 | struct super_block *s; | 2761 | struct super_block *s; |
2654 | int ret; | 2762 | int ret; |
2655 | 2763 | ||
2764 | nd = kmalloc(sizeof(*nd), GFP_KERNEL); | ||
2765 | if (nd == NULL) | ||
2766 | return -ENOMEM; | ||
2767 | |||
2656 | ns_private = create_mnt_ns(root_mnt); | 2768 | ns_private = create_mnt_ns(root_mnt); |
2657 | ret = PTR_ERR(ns_private); | 2769 | ret = PTR_ERR(ns_private); |
2658 | if (IS_ERR(ns_private)) | 2770 | if (IS_ERR(ns_private)) |
2659 | goto out_mntput; | 2771 | goto out_mntput; |
2660 | 2772 | ||
2773 | ret = nfs_referral_loop_protect(); | ||
2774 | if (ret != 0) | ||
2775 | goto out_put_mnt_ns; | ||
2776 | |||
2661 | ret = vfs_path_lookup(root_mnt->mnt_root, root_mnt, | 2777 | ret = vfs_path_lookup(root_mnt->mnt_root, root_mnt, |
2662 | export_path, LOOKUP_FOLLOW, &nd); | 2778 | export_path, LOOKUP_FOLLOW, nd); |
2663 | 2779 | ||
2780 | nfs_referral_loop_unprotect(); | ||
2664 | put_mnt_ns(ns_private); | 2781 | put_mnt_ns(ns_private); |
2665 | 2782 | ||
2666 | if (ret != 0) | 2783 | if (ret != 0) |
2667 | goto out_err; | 2784 | goto out_err; |
2668 | 2785 | ||
2669 | s = nd.path.mnt->mnt_sb; | 2786 | s = nd->path.mnt->mnt_sb; |
2670 | atomic_inc(&s->s_active); | 2787 | atomic_inc(&s->s_active); |
2671 | mnt_target->mnt_sb = s; | 2788 | mnt_target->mnt_sb = s; |
2672 | mnt_target->mnt_root = dget(nd.path.dentry); | 2789 | mnt_target->mnt_root = dget(nd->path.dentry); |
2673 | 2790 | ||
2674 | /* Correct the device pathname */ | 2791 | /* Correct the device pathname */ |
2675 | nfs_fix_devname(&nd.path, mnt_target); | 2792 | nfs_fix_devname(&nd->path, mnt_target); |
2676 | 2793 | ||
2677 | path_put(&nd.path); | 2794 | path_put(&nd->path); |
2795 | kfree(nd); | ||
2678 | down_write(&s->s_umount); | 2796 | down_write(&s->s_umount); |
2679 | return 0; | 2797 | return 0; |
2798 | out_put_mnt_ns: | ||
2799 | put_mnt_ns(ns_private); | ||
2680 | out_mntput: | 2800 | out_mntput: |
2681 | mntput(root_mnt); | 2801 | mntput(root_mnt); |
2682 | out_err: | 2802 | out_err: |
2803 | kfree(nd); | ||
2683 | return ret; | 2804 | return ret; |
2684 | } | 2805 | } |
2685 | 2806 | ||
@@ -2798,7 +2919,7 @@ static int nfs4_xdev_get_sb(struct file_system_type *fs_type, int flags, | |||
2798 | } else { | 2919 | } else { |
2799 | error = nfs_bdi_register(server); | 2920 | error = nfs_bdi_register(server); |
2800 | if (error) | 2921 | if (error) |
2801 | goto error_splat_super; | 2922 | goto error_splat_bdi; |
2802 | } | 2923 | } |
2803 | 2924 | ||
2804 | if (!s->s_root) { | 2925 | if (!s->s_root) { |
@@ -2834,6 +2955,9 @@ out_err_noserver: | |||
2834 | return error; | 2955 | return error; |
2835 | 2956 | ||
2836 | error_splat_super: | 2957 | error_splat_super: |
2958 | if (server && !s->s_root) | ||
2959 | bdi_unregister(&server->backing_dev_info); | ||
2960 | error_splat_bdi: | ||
2837 | deactivate_locked_super(s); | 2961 | deactivate_locked_super(s); |
2838 | dprintk("<-- nfs4_xdev_get_sb() = %d [splat]\n", error); | 2962 | dprintk("<-- nfs4_xdev_get_sb() = %d [splat]\n", error); |
2839 | return error; | 2963 | return error; |
@@ -2847,17 +2971,21 @@ static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type, | |||
2847 | struct super_block *s; | 2971 | struct super_block *s; |
2848 | struct nfs_server *server; | 2972 | struct nfs_server *server; |
2849 | struct dentry *mntroot; | 2973 | struct dentry *mntroot; |
2850 | struct nfs_fh mntfh; | 2974 | struct nfs_fh *mntfh; |
2851 | int (*compare_super)(struct super_block *, void *) = nfs_compare_super; | 2975 | int (*compare_super)(struct super_block *, void *) = nfs_compare_super; |
2852 | struct nfs_sb_mountdata sb_mntdata = { | 2976 | struct nfs_sb_mountdata sb_mntdata = { |
2853 | .mntflags = flags, | 2977 | .mntflags = flags, |
2854 | }; | 2978 | }; |
2855 | int error; | 2979 | int error = -ENOMEM; |
2856 | 2980 | ||
2857 | dprintk("--> nfs4_referral_get_sb()\n"); | 2981 | dprintk("--> nfs4_referral_get_sb()\n"); |
2858 | 2982 | ||
2983 | mntfh = nfs_alloc_fhandle(); | ||
2984 | if (mntfh == NULL) | ||
2985 | goto out_err_nofh; | ||
2986 | |||
2859 | /* create a new volume representation */ | 2987 | /* create a new volume representation */ |
2860 | server = nfs4_create_referral_server(data, &mntfh); | 2988 | server = nfs4_create_referral_server(data, mntfh); |
2861 | if (IS_ERR(server)) { | 2989 | if (IS_ERR(server)) { |
2862 | error = PTR_ERR(server); | 2990 | error = PTR_ERR(server); |
2863 | goto out_err_noserver; | 2991 | goto out_err_noserver; |
@@ -2880,7 +3008,7 @@ static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type, | |||
2880 | } else { | 3008 | } else { |
2881 | error = nfs_bdi_register(server); | 3009 | error = nfs_bdi_register(server); |
2882 | if (error) | 3010 | if (error) |
2883 | goto error_splat_super; | 3011 | goto error_splat_bdi; |
2884 | } | 3012 | } |
2885 | 3013 | ||
2886 | if (!s->s_root) { | 3014 | if (!s->s_root) { |
@@ -2889,7 +3017,7 @@ static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type, | |||
2889 | nfs_fscache_get_super_cookie(s, NULL, data); | 3017 | nfs_fscache_get_super_cookie(s, NULL, data); |
2890 | } | 3018 | } |
2891 | 3019 | ||
2892 | mntroot = nfs4_get_root(s, &mntfh); | 3020 | mntroot = nfs4_get_root(s, mntfh); |
2893 | if (IS_ERR(mntroot)) { | 3021 | if (IS_ERR(mntroot)) { |
2894 | error = PTR_ERR(mntroot); | 3022 | error = PTR_ERR(mntroot); |
2895 | goto error_splat_super; | 3023 | goto error_splat_super; |
@@ -2906,17 +3034,24 @@ static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type, | |||
2906 | 3034 | ||
2907 | security_sb_clone_mnt_opts(data->sb, s); | 3035 | security_sb_clone_mnt_opts(data->sb, s); |
2908 | 3036 | ||
3037 | nfs_free_fhandle(mntfh); | ||
2909 | dprintk("<-- nfs4_referral_get_sb() = 0\n"); | 3038 | dprintk("<-- nfs4_referral_get_sb() = 0\n"); |
2910 | return 0; | 3039 | return 0; |
2911 | 3040 | ||
2912 | out_err_nosb: | 3041 | out_err_nosb: |
2913 | nfs_free_server(server); | 3042 | nfs_free_server(server); |
2914 | out_err_noserver: | 3043 | out_err_noserver: |
3044 | nfs_free_fhandle(mntfh); | ||
3045 | out_err_nofh: | ||
2915 | dprintk("<-- nfs4_referral_get_sb() = %d [error]\n", error); | 3046 | dprintk("<-- nfs4_referral_get_sb() = %d [error]\n", error); |
2916 | return error; | 3047 | return error; |
2917 | 3048 | ||
2918 | error_splat_super: | 3049 | error_splat_super: |
3050 | if (server && !s->s_root) | ||
3051 | bdi_unregister(&server->backing_dev_info); | ||
3052 | error_splat_bdi: | ||
2919 | deactivate_locked_super(s); | 3053 | deactivate_locked_super(s); |
3054 | nfs_free_fhandle(mntfh); | ||
2920 | dprintk("<-- nfs4_referral_get_sb() = %d [splat]\n", error); | 3055 | dprintk("<-- nfs4_referral_get_sb() = %d [splat]\n", error); |
2921 | return error; | 3056 | return error; |
2922 | } | 3057 | } |
diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c index 412738dbfbc7..05c9e02f4153 100644 --- a/fs/nfs/symlink.c +++ b/fs/nfs/symlink.c | |||
@@ -19,7 +19,6 @@ | |||
19 | #include <linux/pagemap.h> | 19 | #include <linux/pagemap.h> |
20 | #include <linux/stat.h> | 20 | #include <linux/stat.h> |
21 | #include <linux/mm.h> | 21 | #include <linux/mm.h> |
22 | #include <linux/slab.h> | ||
23 | #include <linux/string.h> | 22 | #include <linux/string.h> |
24 | #include <linux/namei.h> | 23 | #include <linux/namei.h> |
25 | 24 | ||
@@ -50,7 +49,7 @@ static void *nfs_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
50 | struct page *page; | 49 | struct page *page; |
51 | void *err; | 50 | void *err; |
52 | 51 | ||
53 | err = ERR_PTR(nfs_revalidate_mapping_nolock(inode, inode->i_mapping)); | 52 | err = ERR_PTR(nfs_revalidate_mapping(inode, inode->i_mapping)); |
54 | if (err) | 53 | if (err) |
55 | goto read_failed; | 54 | goto read_failed; |
56 | page = read_cache_page(&inode->i_data, 0, | 55 | page = read_cache_page(&inode->i_data, 0, |
diff --git a/fs/nfs/sysctl.c b/fs/nfs/sysctl.c index 70e1fbbaaeab..ad4d2e787b20 100644 --- a/fs/nfs/sysctl.c +++ b/fs/nfs/sysctl.c | |||
@@ -15,8 +15,10 @@ | |||
15 | 15 | ||
16 | #include "callback.h" | 16 | #include "callback.h" |
17 | 17 | ||
18 | #ifdef CONFIG_NFS_V4 | ||
18 | static const int nfs_set_port_min = 0; | 19 | static const int nfs_set_port_min = 0; |
19 | static const int nfs_set_port_max = 65535; | 20 | static const int nfs_set_port_max = 65535; |
21 | #endif | ||
20 | static struct ctl_table_header *nfs_callback_sysctl_table; | 22 | static struct ctl_table_header *nfs_callback_sysctl_table; |
21 | 23 | ||
22 | static ctl_table nfs_cb_sysctls[] = { | 24 | static ctl_table nfs_cb_sysctls[] = { |
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 6da3d3ff6edd..a2242af6a17d 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c | |||
@@ -23,6 +23,7 @@ struct nfs_unlinkdata { | |||
23 | struct nfs_removeres res; | 23 | struct nfs_removeres res; |
24 | struct inode *dir; | 24 | struct inode *dir; |
25 | struct rpc_cred *cred; | 25 | struct rpc_cred *cred; |
26 | struct nfs_fattr dir_attr; | ||
26 | }; | 27 | }; |
27 | 28 | ||
28 | /** | 29 | /** |
@@ -169,7 +170,7 @@ static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct n | |||
169 | } | 170 | } |
170 | nfs_sb_active(dir->i_sb); | 171 | nfs_sb_active(dir->i_sb); |
171 | data->args.fh = NFS_FH(dir); | 172 | data->args.fh = NFS_FH(dir); |
172 | nfs_fattr_init(&data->res.dir_attr); | 173 | nfs_fattr_init(data->res.dir_attr); |
173 | 174 | ||
174 | NFS_PROTO(dir)->unlink_setup(&msg, dir); | 175 | NFS_PROTO(dir)->unlink_setup(&msg, dir); |
175 | 176 | ||
@@ -259,6 +260,7 @@ nfs_async_unlink(struct inode *dir, struct dentry *dentry) | |||
259 | goto out_free; | 260 | goto out_free; |
260 | } | 261 | } |
261 | data->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | 262 | data->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; |
263 | data->res.dir_attr = &data->dir_attr; | ||
262 | 264 | ||
263 | status = -EBUSY; | 265 | status = -EBUSY; |
264 | spin_lock(&dentry->d_lock); | 266 | spin_lock(&dentry->d_lock); |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index d171696017f4..9f81bdd91c55 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -201,6 +201,7 @@ static int nfs_set_page_writeback(struct page *page) | |||
201 | struct inode *inode = page->mapping->host; | 201 | struct inode *inode = page->mapping->host; |
202 | struct nfs_server *nfss = NFS_SERVER(inode); | 202 | struct nfs_server *nfss = NFS_SERVER(inode); |
203 | 203 | ||
204 | page_cache_get(page); | ||
204 | if (atomic_long_inc_return(&nfss->writeback) > | 205 | if (atomic_long_inc_return(&nfss->writeback) > |
205 | NFS_CONGESTION_ON_THRESH) { | 206 | NFS_CONGESTION_ON_THRESH) { |
206 | set_bdi_congested(&nfss->backing_dev_info, | 207 | set_bdi_congested(&nfss->backing_dev_info, |
@@ -216,11 +217,12 @@ static void nfs_end_page_writeback(struct page *page) | |||
216 | struct nfs_server *nfss = NFS_SERVER(inode); | 217 | struct nfs_server *nfss = NFS_SERVER(inode); |
217 | 218 | ||
218 | end_page_writeback(page); | 219 | end_page_writeback(page); |
220 | page_cache_release(page); | ||
219 | if (atomic_long_dec_return(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH) | 221 | if (atomic_long_dec_return(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH) |
220 | clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC); | 222 | clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC); |
221 | } | 223 | } |
222 | 224 | ||
223 | static struct nfs_page *nfs_find_and_lock_request(struct page *page) | 225 | static struct nfs_page *nfs_find_and_lock_request(struct page *page, bool nonblock) |
224 | { | 226 | { |
225 | struct inode *inode = page->mapping->host; | 227 | struct inode *inode = page->mapping->host; |
226 | struct nfs_page *req; | 228 | struct nfs_page *req; |
@@ -239,7 +241,10 @@ static struct nfs_page *nfs_find_and_lock_request(struct page *page) | |||
239 | * request as dirty (in which case we don't care). | 241 | * request as dirty (in which case we don't care). |
240 | */ | 242 | */ |
241 | spin_unlock(&inode->i_lock); | 243 | spin_unlock(&inode->i_lock); |
242 | ret = nfs_wait_on_request(req); | 244 | if (!nonblock) |
245 | ret = nfs_wait_on_request(req); | ||
246 | else | ||
247 | ret = -EAGAIN; | ||
243 | nfs_release_request(req); | 248 | nfs_release_request(req); |
244 | if (ret != 0) | 249 | if (ret != 0) |
245 | return ERR_PTR(ret); | 250 | return ERR_PTR(ret); |
@@ -254,12 +259,12 @@ static struct nfs_page *nfs_find_and_lock_request(struct page *page) | |||
254 | * May return an error if the user signalled nfs_wait_on_request(). | 259 | * May return an error if the user signalled nfs_wait_on_request(). |
255 | */ | 260 | */ |
256 | static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, | 261 | static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, |
257 | struct page *page) | 262 | struct page *page, bool nonblock) |
258 | { | 263 | { |
259 | struct nfs_page *req; | 264 | struct nfs_page *req; |
260 | int ret = 0; | 265 | int ret = 0; |
261 | 266 | ||
262 | req = nfs_find_and_lock_request(page); | 267 | req = nfs_find_and_lock_request(page, nonblock); |
263 | if (!req) | 268 | if (!req) |
264 | goto out; | 269 | goto out; |
265 | ret = PTR_ERR(req); | 270 | ret = PTR_ERR(req); |
@@ -281,12 +286,20 @@ out: | |||
281 | static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, struct nfs_pageio_descriptor *pgio) | 286 | static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, struct nfs_pageio_descriptor *pgio) |
282 | { | 287 | { |
283 | struct inode *inode = page->mapping->host; | 288 | struct inode *inode = page->mapping->host; |
289 | int ret; | ||
284 | 290 | ||
285 | nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE); | 291 | nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE); |
286 | nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1); | 292 | nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1); |
287 | 293 | ||
288 | nfs_pageio_cond_complete(pgio, page->index); | 294 | nfs_pageio_cond_complete(pgio, page->index); |
289 | return nfs_page_async_flush(pgio, page); | 295 | ret = nfs_page_async_flush(pgio, page, |
296 | wbc->sync_mode == WB_SYNC_NONE || | ||
297 | wbc->nonblocking != 0); | ||
298 | if (ret == -EAGAIN) { | ||
299 | redirty_page_for_writepage(wbc, page); | ||
300 | ret = 0; | ||
301 | } | ||
302 | return ret; | ||
290 | } | 303 | } |
291 | 304 | ||
292 | /* | 305 | /* |
@@ -421,6 +434,7 @@ static void | |||
421 | nfs_mark_request_dirty(struct nfs_page *req) | 434 | nfs_mark_request_dirty(struct nfs_page *req) |
422 | { | 435 | { |
423 | __set_page_dirty_nobuffers(req->wb_page); | 436 | __set_page_dirty_nobuffers(req->wb_page); |
437 | __mark_inode_dirty(req->wb_page->mapping->host, I_DIRTY_DATASYNC); | ||
424 | } | 438 | } |
425 | 439 | ||
426 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 440 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
@@ -438,6 +452,7 @@ nfs_mark_request_commit(struct nfs_page *req) | |||
438 | radix_tree_tag_set(&nfsi->nfs_page_tree, | 452 | radix_tree_tag_set(&nfsi->nfs_page_tree, |
439 | req->wb_index, | 453 | req->wb_index, |
440 | NFS_PAGE_TAG_COMMIT); | 454 | NFS_PAGE_TAG_COMMIT); |
455 | nfsi->ncommit++; | ||
441 | spin_unlock(&inode->i_lock); | 456 | spin_unlock(&inode->i_lock); |
442 | inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); | 457 | inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); |
443 | inc_bdi_stat(req->wb_page->mapping->backing_dev_info, BDI_RECLAIMABLE); | 458 | inc_bdi_stat(req->wb_page->mapping->backing_dev_info, BDI_RECLAIMABLE); |
@@ -501,57 +516,6 @@ int nfs_reschedule_unstable_write(struct nfs_page *req) | |||
501 | } | 516 | } |
502 | #endif | 517 | #endif |
503 | 518 | ||
504 | /* | ||
505 | * Wait for a request to complete. | ||
506 | * | ||
507 | * Interruptible by fatal signals only. | ||
508 | */ | ||
509 | static int nfs_wait_on_requests_locked(struct inode *inode, pgoff_t idx_start, unsigned int npages) | ||
510 | { | ||
511 | struct nfs_inode *nfsi = NFS_I(inode); | ||
512 | struct nfs_page *req; | ||
513 | pgoff_t idx_end, next; | ||
514 | unsigned int res = 0; | ||
515 | int error; | ||
516 | |||
517 | if (npages == 0) | ||
518 | idx_end = ~0; | ||
519 | else | ||
520 | idx_end = idx_start + npages - 1; | ||
521 | |||
522 | next = idx_start; | ||
523 | while (radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree, (void **)&req, next, 1, NFS_PAGE_TAG_LOCKED)) { | ||
524 | if (req->wb_index > idx_end) | ||
525 | break; | ||
526 | |||
527 | next = req->wb_index + 1; | ||
528 | BUG_ON(!NFS_WBACK_BUSY(req)); | ||
529 | |||
530 | kref_get(&req->wb_kref); | ||
531 | spin_unlock(&inode->i_lock); | ||
532 | error = nfs_wait_on_request(req); | ||
533 | nfs_release_request(req); | ||
534 | spin_lock(&inode->i_lock); | ||
535 | if (error < 0) | ||
536 | return error; | ||
537 | res++; | ||
538 | } | ||
539 | return res; | ||
540 | } | ||
541 | |||
542 | static void nfs_cancel_commit_list(struct list_head *head) | ||
543 | { | ||
544 | struct nfs_page *req; | ||
545 | |||
546 | while(!list_empty(head)) { | ||
547 | req = nfs_list_entry(head->next); | ||
548 | nfs_list_remove_request(req); | ||
549 | nfs_clear_request_commit(req); | ||
550 | nfs_inode_remove_request(req); | ||
551 | nfs_unlock_request(req); | ||
552 | } | ||
553 | } | ||
554 | |||
555 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 519 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
556 | static int | 520 | static int |
557 | nfs_need_commit(struct nfs_inode *nfsi) | 521 | nfs_need_commit(struct nfs_inode *nfsi) |
@@ -573,11 +537,17 @@ static int | |||
573 | nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages) | 537 | nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages) |
574 | { | 538 | { |
575 | struct nfs_inode *nfsi = NFS_I(inode); | 539 | struct nfs_inode *nfsi = NFS_I(inode); |
540 | int ret; | ||
576 | 541 | ||
577 | if (!nfs_need_commit(nfsi)) | 542 | if (!nfs_need_commit(nfsi)) |
578 | return 0; | 543 | return 0; |
579 | 544 | ||
580 | return nfs_scan_list(nfsi, dst, idx_start, npages, NFS_PAGE_TAG_COMMIT); | 545 | ret = nfs_scan_list(nfsi, dst, idx_start, npages, NFS_PAGE_TAG_COMMIT); |
546 | if (ret > 0) | ||
547 | nfsi->ncommit -= ret; | ||
548 | if (nfs_need_commit(NFS_I(inode))) | ||
549 | __mark_inode_dirty(inode, I_DIRTY_DATASYNC); | ||
550 | return ret; | ||
581 | } | 551 | } |
582 | #else | 552 | #else |
583 | static inline int nfs_need_commit(struct nfs_inode *nfsi) | 553 | static inline int nfs_need_commit(struct nfs_inode *nfsi) |
@@ -642,9 +612,10 @@ static struct nfs_page *nfs_try_to_update_request(struct inode *inode, | |||
642 | spin_lock(&inode->i_lock); | 612 | spin_lock(&inode->i_lock); |
643 | } | 613 | } |
644 | 614 | ||
645 | if (nfs_clear_request_commit(req)) | 615 | if (nfs_clear_request_commit(req) && |
646 | radix_tree_tag_clear(&NFS_I(inode)->nfs_page_tree, | 616 | radix_tree_tag_clear(&NFS_I(inode)->nfs_page_tree, |
647 | req->wb_index, NFS_PAGE_TAG_COMMIT); | 617 | req->wb_index, NFS_PAGE_TAG_COMMIT) != NULL) |
618 | NFS_I(inode)->ncommit--; | ||
648 | 619 | ||
649 | /* Okay, the request matches. Update the region */ | 620 | /* Okay, the request matches. Update the region */ |
650 | if (offset < req->wb_offset) { | 621 | if (offset < req->wb_offset) { |
@@ -703,9 +674,11 @@ static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page, | |||
703 | req = nfs_setup_write_request(ctx, page, offset, count); | 674 | req = nfs_setup_write_request(ctx, page, offset, count); |
704 | if (IS_ERR(req)) | 675 | if (IS_ERR(req)) |
705 | return PTR_ERR(req); | 676 | return PTR_ERR(req); |
677 | nfs_mark_request_dirty(req); | ||
706 | /* Update file length */ | 678 | /* Update file length */ |
707 | nfs_grow_file(page, offset, count); | 679 | nfs_grow_file(page, offset, count); |
708 | nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes); | 680 | nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes); |
681 | nfs_mark_request_dirty(req); | ||
709 | nfs_clear_page_tag_locked(req); | 682 | nfs_clear_page_tag_locked(req); |
710 | return 0; | 683 | return 0; |
711 | } | 684 | } |
@@ -782,8 +755,6 @@ int nfs_updatepage(struct file *file, struct page *page, | |||
782 | status = nfs_writepage_setup(ctx, page, offset, count); | 755 | status = nfs_writepage_setup(ctx, page, offset, count); |
783 | if (status < 0) | 756 | if (status < 0) |
784 | nfs_set_pageerror(page); | 757 | nfs_set_pageerror(page); |
785 | else | ||
786 | __set_page_dirty_nobuffers(page); | ||
787 | 758 | ||
788 | dprintk("NFS: nfs_updatepage returns %d (isize %lld)\n", | 759 | dprintk("NFS: nfs_updatepage returns %d (isize %lld)\n", |
789 | status, (long long)i_size_read(inode)); | 760 | status, (long long)i_size_read(inode)); |
@@ -792,13 +763,12 @@ int nfs_updatepage(struct file *file, struct page *page, | |||
792 | 763 | ||
793 | static void nfs_writepage_release(struct nfs_page *req) | 764 | static void nfs_writepage_release(struct nfs_page *req) |
794 | { | 765 | { |
766 | struct page *page = req->wb_page; | ||
795 | 767 | ||
796 | if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req)) { | 768 | if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req)) |
797 | nfs_end_page_writeback(req->wb_page); | ||
798 | nfs_inode_remove_request(req); | 769 | nfs_inode_remove_request(req); |
799 | } else | ||
800 | nfs_end_page_writeback(req->wb_page); | ||
801 | nfs_clear_page_tag_locked(req); | 770 | nfs_clear_page_tag_locked(req); |
771 | nfs_end_page_writeback(page); | ||
802 | } | 772 | } |
803 | 773 | ||
804 | static int flush_task_priority(int how) | 774 | static int flush_task_priority(int how) |
@@ -822,7 +792,6 @@ static int nfs_write_rpcsetup(struct nfs_page *req, | |||
822 | int how) | 792 | int how) |
823 | { | 793 | { |
824 | struct inode *inode = req->wb_context->path.dentry->d_inode; | 794 | struct inode *inode = req->wb_context->path.dentry->d_inode; |
825 | int flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | ||
826 | int priority = flush_task_priority(how); | 795 | int priority = flush_task_priority(how); |
827 | struct rpc_task *task; | 796 | struct rpc_task *task; |
828 | struct rpc_message msg = { | 797 | struct rpc_message msg = { |
@@ -837,9 +806,10 @@ static int nfs_write_rpcsetup(struct nfs_page *req, | |||
837 | .callback_ops = call_ops, | 806 | .callback_ops = call_ops, |
838 | .callback_data = data, | 807 | .callback_data = data, |
839 | .workqueue = nfsiod_workqueue, | 808 | .workqueue = nfsiod_workqueue, |
840 | .flags = flags, | 809 | .flags = RPC_TASK_ASYNC, |
841 | .priority = priority, | 810 | .priority = priority, |
842 | }; | 811 | }; |
812 | int ret = 0; | ||
843 | 813 | ||
844 | /* Set up the RPC argument and reply structs | 814 | /* Set up the RPC argument and reply structs |
845 | * NB: take care not to mess about with data->commit et al. */ | 815 | * NB: take care not to mess about with data->commit et al. */ |
@@ -878,10 +848,18 @@ static int nfs_write_rpcsetup(struct nfs_page *req, | |||
878 | (unsigned long long)data->args.offset); | 848 | (unsigned long long)data->args.offset); |
879 | 849 | ||
880 | task = rpc_run_task(&task_setup_data); | 850 | task = rpc_run_task(&task_setup_data); |
881 | if (IS_ERR(task)) | 851 | if (IS_ERR(task)) { |
882 | return PTR_ERR(task); | 852 | ret = PTR_ERR(task); |
853 | goto out; | ||
854 | } | ||
855 | if (how & FLUSH_SYNC) { | ||
856 | ret = rpc_wait_for_completion_task(task); | ||
857 | if (ret == 0) | ||
858 | ret = task->tk_status; | ||
859 | } | ||
883 | rpc_put_task(task); | 860 | rpc_put_task(task); |
884 | return 0; | 861 | out: |
862 | return ret; | ||
885 | } | 863 | } |
886 | 864 | ||
887 | /* If a nfs_flush_* function fails, it should remove reqs from @head and | 865 | /* If a nfs_flush_* function fails, it should remove reqs from @head and |
@@ -890,9 +868,11 @@ static int nfs_write_rpcsetup(struct nfs_page *req, | |||
890 | */ | 868 | */ |
891 | static void nfs_redirty_request(struct nfs_page *req) | 869 | static void nfs_redirty_request(struct nfs_page *req) |
892 | { | 870 | { |
871 | struct page *page = req->wb_page; | ||
872 | |||
893 | nfs_mark_request_dirty(req); | 873 | nfs_mark_request_dirty(req); |
894 | nfs_end_page_writeback(req->wb_page); | ||
895 | nfs_clear_page_tag_locked(req); | 874 | nfs_clear_page_tag_locked(req); |
875 | nfs_end_page_writeback(page); | ||
896 | } | 876 | } |
897 | 877 | ||
898 | /* | 878 | /* |
@@ -1127,16 +1107,15 @@ static void nfs_writeback_release_full(void *calldata) | |||
1127 | if (nfs_write_need_commit(data)) { | 1107 | if (nfs_write_need_commit(data)) { |
1128 | memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf)); | 1108 | memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf)); |
1129 | nfs_mark_request_commit(req); | 1109 | nfs_mark_request_commit(req); |
1130 | nfs_end_page_writeback(page); | ||
1131 | dprintk(" marked for commit\n"); | 1110 | dprintk(" marked for commit\n"); |
1132 | goto next; | 1111 | goto next; |
1133 | } | 1112 | } |
1134 | dprintk(" OK\n"); | 1113 | dprintk(" OK\n"); |
1135 | remove_request: | 1114 | remove_request: |
1136 | nfs_end_page_writeback(page); | ||
1137 | nfs_inode_remove_request(req); | 1115 | nfs_inode_remove_request(req); |
1138 | next: | 1116 | next: |
1139 | nfs_clear_page_tag_locked(req); | 1117 | nfs_clear_page_tag_locked(req); |
1118 | nfs_end_page_writeback(page); | ||
1140 | } | 1119 | } |
1141 | nfs_writedata_release(calldata); | 1120 | nfs_writedata_release(calldata); |
1142 | } | 1121 | } |
@@ -1233,7 +1212,26 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1233 | 1212 | ||
1234 | 1213 | ||
1235 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 1214 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
1236 | void nfs_commitdata_release(void *data) | 1215 | static int nfs_commit_set_lock(struct nfs_inode *nfsi, int may_wait) |
1216 | { | ||
1217 | if (!test_and_set_bit(NFS_INO_COMMIT, &nfsi->flags)) | ||
1218 | return 1; | ||
1219 | if (may_wait && !out_of_line_wait_on_bit_lock(&nfsi->flags, | ||
1220 | NFS_INO_COMMIT, nfs_wait_bit_killable, | ||
1221 | TASK_KILLABLE)) | ||
1222 | return 1; | ||
1223 | return 0; | ||
1224 | } | ||
1225 | |||
1226 | static void nfs_commit_clear_lock(struct nfs_inode *nfsi) | ||
1227 | { | ||
1228 | clear_bit(NFS_INO_COMMIT, &nfsi->flags); | ||
1229 | smp_mb__after_clear_bit(); | ||
1230 | wake_up_bit(&nfsi->flags, NFS_INO_COMMIT); | ||
1231 | } | ||
1232 | |||
1233 | |||
1234 | static void nfs_commitdata_release(void *data) | ||
1237 | { | 1235 | { |
1238 | struct nfs_write_data *wdata = data; | 1236 | struct nfs_write_data *wdata = data; |
1239 | 1237 | ||
@@ -1250,7 +1248,6 @@ static int nfs_commit_rpcsetup(struct list_head *head, | |||
1250 | { | 1248 | { |
1251 | struct nfs_page *first = nfs_list_entry(head->next); | 1249 | struct nfs_page *first = nfs_list_entry(head->next); |
1252 | struct inode *inode = first->wb_context->path.dentry->d_inode; | 1250 | struct inode *inode = first->wb_context->path.dentry->d_inode; |
1253 | int flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | ||
1254 | int priority = flush_task_priority(how); | 1251 | int priority = flush_task_priority(how); |
1255 | struct rpc_task *task; | 1252 | struct rpc_task *task; |
1256 | struct rpc_message msg = { | 1253 | struct rpc_message msg = { |
@@ -1265,7 +1262,7 @@ static int nfs_commit_rpcsetup(struct list_head *head, | |||
1265 | .callback_ops = &nfs_commit_ops, | 1262 | .callback_ops = &nfs_commit_ops, |
1266 | .callback_data = data, | 1263 | .callback_data = data, |
1267 | .workqueue = nfsiod_workqueue, | 1264 | .workqueue = nfsiod_workqueue, |
1268 | .flags = flags, | 1265 | .flags = RPC_TASK_ASYNC, |
1269 | .priority = priority, | 1266 | .priority = priority, |
1270 | }; | 1267 | }; |
1271 | 1268 | ||
@@ -1325,6 +1322,7 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how) | |||
1325 | BDI_RECLAIMABLE); | 1322 | BDI_RECLAIMABLE); |
1326 | nfs_clear_page_tag_locked(req); | 1323 | nfs_clear_page_tag_locked(req); |
1327 | } | 1324 | } |
1325 | nfs_commit_clear_lock(NFS_I(inode)); | ||
1328 | return -ENOMEM; | 1326 | return -ENOMEM; |
1329 | } | 1327 | } |
1330 | 1328 | ||
@@ -1380,6 +1378,7 @@ static void nfs_commit_release(void *calldata) | |||
1380 | next: | 1378 | next: |
1381 | nfs_clear_page_tag_locked(req); | 1379 | nfs_clear_page_tag_locked(req); |
1382 | } | 1380 | } |
1381 | nfs_commit_clear_lock(NFS_I(data->inode)); | ||
1383 | nfs_commitdata_release(calldata); | 1382 | nfs_commitdata_release(calldata); |
1384 | } | 1383 | } |
1385 | 1384 | ||
@@ -1394,8 +1393,11 @@ static const struct rpc_call_ops nfs_commit_ops = { | |||
1394 | int nfs_commit_inode(struct inode *inode, int how) | 1393 | int nfs_commit_inode(struct inode *inode, int how) |
1395 | { | 1394 | { |
1396 | LIST_HEAD(head); | 1395 | LIST_HEAD(head); |
1397 | int res; | 1396 | int may_wait = how & FLUSH_SYNC; |
1397 | int res = 0; | ||
1398 | 1398 | ||
1399 | if (!nfs_commit_set_lock(NFS_I(inode), may_wait)) | ||
1400 | goto out_mark_dirty; | ||
1399 | spin_lock(&inode->i_lock); | 1401 | spin_lock(&inode->i_lock); |
1400 | res = nfs_scan_commit(inode, &head, 0, 0); | 1402 | res = nfs_scan_commit(inode, &head, 0, 0); |
1401 | spin_unlock(&inode->i_lock); | 1403 | spin_unlock(&inode->i_lock); |
@@ -1403,95 +1405,64 @@ int nfs_commit_inode(struct inode *inode, int how) | |||
1403 | int error = nfs_commit_list(inode, &head, how); | 1405 | int error = nfs_commit_list(inode, &head, how); |
1404 | if (error < 0) | 1406 | if (error < 0) |
1405 | return error; | 1407 | return error; |
1406 | } | 1408 | if (may_wait) |
1409 | wait_on_bit(&NFS_I(inode)->flags, NFS_INO_COMMIT, | ||
1410 | nfs_wait_bit_killable, | ||
1411 | TASK_KILLABLE); | ||
1412 | else | ||
1413 | goto out_mark_dirty; | ||
1414 | } else | ||
1415 | nfs_commit_clear_lock(NFS_I(inode)); | ||
1416 | return res; | ||
1417 | /* Note: If we exit without ensuring that the commit is complete, | ||
1418 | * we must mark the inode as dirty. Otherwise, future calls to | ||
1419 | * sync_inode() with the WB_SYNC_ALL flag set will fail to ensure | ||
1420 | * that the data is on the disk. | ||
1421 | */ | ||
1422 | out_mark_dirty: | ||
1423 | __mark_inode_dirty(inode, I_DIRTY_DATASYNC); | ||
1407 | return res; | 1424 | return res; |
1408 | } | 1425 | } |
1409 | #else | ||
1410 | static inline int nfs_commit_list(struct inode *inode, struct list_head *head, int how) | ||
1411 | { | ||
1412 | return 0; | ||
1413 | } | ||
1414 | #endif | ||
1415 | 1426 | ||
1416 | long nfs_sync_mapping_wait(struct address_space *mapping, struct writeback_control *wbc, int how) | 1427 | static int nfs_commit_unstable_pages(struct inode *inode, struct writeback_control *wbc) |
1417 | { | 1428 | { |
1418 | struct inode *inode = mapping->host; | 1429 | struct nfs_inode *nfsi = NFS_I(inode); |
1419 | pgoff_t idx_start, idx_end; | 1430 | int flags = FLUSH_SYNC; |
1420 | unsigned int npages = 0; | 1431 | int ret = 0; |
1421 | LIST_HEAD(head); | 1432 | |
1422 | int nocommit = how & FLUSH_NOCOMMIT; | 1433 | /* Don't commit yet if this is a non-blocking flush and there are |
1423 | long pages, ret; | 1434 | * lots of outstanding writes for this mapping. |
1424 | 1435 | */ | |
1425 | /* FIXME */ | 1436 | if (wbc->sync_mode == WB_SYNC_NONE && |
1426 | if (wbc->range_cyclic) | 1437 | nfsi->ncommit <= (nfsi->npages >> 1)) |
1427 | idx_start = 0; | 1438 | goto out_mark_dirty; |
1428 | else { | 1439 | |
1429 | idx_start = wbc->range_start >> PAGE_CACHE_SHIFT; | 1440 | if (wbc->nonblocking || wbc->for_background) |
1430 | idx_end = wbc->range_end >> PAGE_CACHE_SHIFT; | 1441 | flags = 0; |
1431 | if (idx_end > idx_start) { | 1442 | ret = nfs_commit_inode(inode, flags); |
1432 | pgoff_t l_npages = 1 + idx_end - idx_start; | 1443 | if (ret >= 0) { |
1433 | npages = l_npages; | 1444 | if (wbc->sync_mode == WB_SYNC_NONE) { |
1434 | if (sizeof(npages) != sizeof(l_npages) && | 1445 | if (ret < wbc->nr_to_write) |
1435 | (pgoff_t)npages != l_npages) | 1446 | wbc->nr_to_write -= ret; |
1436 | npages = 0; | 1447 | else |
1448 | wbc->nr_to_write = 0; | ||
1437 | } | 1449 | } |
1450 | return 0; | ||
1438 | } | 1451 | } |
1439 | how &= ~FLUSH_NOCOMMIT; | 1452 | out_mark_dirty: |
1440 | spin_lock(&inode->i_lock); | 1453 | __mark_inode_dirty(inode, I_DIRTY_DATASYNC); |
1441 | do { | ||
1442 | ret = nfs_wait_on_requests_locked(inode, idx_start, npages); | ||
1443 | if (ret != 0) | ||
1444 | continue; | ||
1445 | if (nocommit) | ||
1446 | break; | ||
1447 | pages = nfs_scan_commit(inode, &head, idx_start, npages); | ||
1448 | if (pages == 0) | ||
1449 | break; | ||
1450 | if (how & FLUSH_INVALIDATE) { | ||
1451 | spin_unlock(&inode->i_lock); | ||
1452 | nfs_cancel_commit_list(&head); | ||
1453 | ret = pages; | ||
1454 | spin_lock(&inode->i_lock); | ||
1455 | continue; | ||
1456 | } | ||
1457 | pages += nfs_scan_commit(inode, &head, 0, 0); | ||
1458 | spin_unlock(&inode->i_lock); | ||
1459 | ret = nfs_commit_list(inode, &head, how); | ||
1460 | spin_lock(&inode->i_lock); | ||
1461 | |||
1462 | } while (ret >= 0); | ||
1463 | spin_unlock(&inode->i_lock); | ||
1464 | return ret; | 1454 | return ret; |
1465 | } | 1455 | } |
1466 | 1456 | #else | |
1467 | static int __nfs_write_mapping(struct address_space *mapping, struct writeback_control *wbc, int how) | 1457 | static int nfs_commit_unstable_pages(struct inode *inode, struct writeback_control *wbc) |
1468 | { | 1458 | { |
1469 | int ret; | ||
1470 | |||
1471 | ret = nfs_writepages(mapping, wbc); | ||
1472 | if (ret < 0) | ||
1473 | goto out; | ||
1474 | ret = nfs_sync_mapping_wait(mapping, wbc, how); | ||
1475 | if (ret < 0) | ||
1476 | goto out; | ||
1477 | return 0; | 1459 | return 0; |
1478 | out: | ||
1479 | __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); | ||
1480 | return ret; | ||
1481 | } | 1460 | } |
1461 | #endif | ||
1482 | 1462 | ||
1483 | /* Two pass sync: first using WB_SYNC_NONE, then WB_SYNC_ALL */ | 1463 | int nfs_write_inode(struct inode *inode, struct writeback_control *wbc) |
1484 | static int nfs_write_mapping(struct address_space *mapping, int how) | ||
1485 | { | 1464 | { |
1486 | struct writeback_control wbc = { | 1465 | return nfs_commit_unstable_pages(inode, wbc); |
1487 | .bdi = mapping->backing_dev_info, | ||
1488 | .sync_mode = WB_SYNC_ALL, | ||
1489 | .nr_to_write = LONG_MAX, | ||
1490 | .range_start = 0, | ||
1491 | .range_end = LLONG_MAX, | ||
1492 | }; | ||
1493 | |||
1494 | return __nfs_write_mapping(mapping, &wbc, how); | ||
1495 | } | 1466 | } |
1496 | 1467 | ||
1497 | /* | 1468 | /* |
@@ -1499,37 +1470,27 @@ static int nfs_write_mapping(struct address_space *mapping, int how) | |||
1499 | */ | 1470 | */ |
1500 | int nfs_wb_all(struct inode *inode) | 1471 | int nfs_wb_all(struct inode *inode) |
1501 | { | 1472 | { |
1502 | return nfs_write_mapping(inode->i_mapping, 0); | 1473 | struct writeback_control wbc = { |
1503 | } | 1474 | .sync_mode = WB_SYNC_ALL, |
1475 | .nr_to_write = LONG_MAX, | ||
1476 | .range_start = 0, | ||
1477 | .range_end = LLONG_MAX, | ||
1478 | }; | ||
1504 | 1479 | ||
1505 | int nfs_wb_nocommit(struct inode *inode) | 1480 | return sync_inode(inode, &wbc); |
1506 | { | ||
1507 | return nfs_write_mapping(inode->i_mapping, FLUSH_NOCOMMIT); | ||
1508 | } | 1481 | } |
1509 | 1482 | ||
1510 | int nfs_wb_page_cancel(struct inode *inode, struct page *page) | 1483 | int nfs_wb_page_cancel(struct inode *inode, struct page *page) |
1511 | { | 1484 | { |
1512 | struct nfs_page *req; | 1485 | struct nfs_page *req; |
1513 | loff_t range_start = page_offset(page); | ||
1514 | loff_t range_end = range_start + (loff_t)(PAGE_CACHE_SIZE - 1); | ||
1515 | struct writeback_control wbc = { | ||
1516 | .bdi = page->mapping->backing_dev_info, | ||
1517 | .sync_mode = WB_SYNC_ALL, | ||
1518 | .nr_to_write = LONG_MAX, | ||
1519 | .range_start = range_start, | ||
1520 | .range_end = range_end, | ||
1521 | }; | ||
1522 | int ret = 0; | 1486 | int ret = 0; |
1523 | 1487 | ||
1524 | BUG_ON(!PageLocked(page)); | 1488 | BUG_ON(!PageLocked(page)); |
1525 | for (;;) { | 1489 | for (;;) { |
1490 | wait_on_page_writeback(page); | ||
1526 | req = nfs_page_find_request(page); | 1491 | req = nfs_page_find_request(page); |
1527 | if (req == NULL) | 1492 | if (req == NULL) |
1528 | goto out; | ||
1529 | if (test_bit(PG_CLEAN, &req->wb_flags)) { | ||
1530 | nfs_release_request(req); | ||
1531 | break; | 1493 | break; |
1532 | } | ||
1533 | if (nfs_lock_request_dontget(req)) { | 1494 | if (nfs_lock_request_dontget(req)) { |
1534 | nfs_inode_remove_request(req); | 1495 | nfs_inode_remove_request(req); |
1535 | /* | 1496 | /* |
@@ -1541,55 +1502,47 @@ int nfs_wb_page_cancel(struct inode *inode, struct page *page) | |||
1541 | break; | 1502 | break; |
1542 | } | 1503 | } |
1543 | ret = nfs_wait_on_request(req); | 1504 | ret = nfs_wait_on_request(req); |
1505 | nfs_release_request(req); | ||
1544 | if (ret < 0) | 1506 | if (ret < 0) |
1545 | goto out; | 1507 | break; |
1546 | } | 1508 | } |
1547 | if (!PagePrivate(page)) | ||
1548 | return 0; | ||
1549 | ret = nfs_sync_mapping_wait(page->mapping, &wbc, FLUSH_INVALIDATE); | ||
1550 | out: | ||
1551 | return ret; | 1509 | return ret; |
1552 | } | 1510 | } |
1553 | 1511 | ||
1554 | static int nfs_wb_page_priority(struct inode *inode, struct page *page, | 1512 | /* |
1555 | int how) | 1513 | * Write back all requests on one page - we do this before reading it. |
1514 | */ | ||
1515 | int nfs_wb_page(struct inode *inode, struct page *page) | ||
1556 | { | 1516 | { |
1557 | loff_t range_start = page_offset(page); | 1517 | loff_t range_start = page_offset(page); |
1558 | loff_t range_end = range_start + (loff_t)(PAGE_CACHE_SIZE - 1); | 1518 | loff_t range_end = range_start + (loff_t)(PAGE_CACHE_SIZE - 1); |
1559 | struct writeback_control wbc = { | 1519 | struct writeback_control wbc = { |
1560 | .bdi = page->mapping->backing_dev_info, | ||
1561 | .sync_mode = WB_SYNC_ALL, | 1520 | .sync_mode = WB_SYNC_ALL, |
1562 | .nr_to_write = LONG_MAX, | 1521 | .nr_to_write = 0, |
1563 | .range_start = range_start, | 1522 | .range_start = range_start, |
1564 | .range_end = range_end, | 1523 | .range_end = range_end, |
1565 | }; | 1524 | }; |
1566 | int ret; | 1525 | int ret; |
1567 | 1526 | ||
1568 | do { | 1527 | for (;;) { |
1528 | wait_on_page_writeback(page); | ||
1569 | if (clear_page_dirty_for_io(page)) { | 1529 | if (clear_page_dirty_for_io(page)) { |
1570 | ret = nfs_writepage_locked(page, &wbc); | 1530 | ret = nfs_writepage_locked(page, &wbc); |
1571 | if (ret < 0) | 1531 | if (ret < 0) |
1572 | goto out_error; | 1532 | goto out_error; |
1573 | } else if (!PagePrivate(page)) | 1533 | continue; |
1534 | } | ||
1535 | if (!PagePrivate(page)) | ||
1574 | break; | 1536 | break; |
1575 | ret = nfs_sync_mapping_wait(page->mapping, &wbc, how); | 1537 | ret = nfs_commit_inode(inode, FLUSH_SYNC); |
1576 | if (ret < 0) | 1538 | if (ret < 0) |
1577 | goto out_error; | 1539 | goto out_error; |
1578 | } while (PagePrivate(page)); | 1540 | } |
1579 | return 0; | 1541 | return 0; |
1580 | out_error: | 1542 | out_error: |
1581 | __mark_inode_dirty(inode, I_DIRTY_PAGES); | ||
1582 | return ret; | 1543 | return ret; |
1583 | } | 1544 | } |
1584 | 1545 | ||
1585 | /* | ||
1586 | * Write back all requests on one page - we do this before reading it. | ||
1587 | */ | ||
1588 | int nfs_wb_page(struct inode *inode, struct page* page) | ||
1589 | { | ||
1590 | return nfs_wb_page_priority(inode, page, FLUSH_STABLE); | ||
1591 | } | ||
1592 | |||
1593 | #ifdef CONFIG_MIGRATION | 1546 | #ifdef CONFIG_MIGRATION |
1594 | int nfs_migrate_page(struct address_space *mapping, struct page *newpage, | 1547 | int nfs_migrate_page(struct address_space *mapping, struct page *newpage, |
1595 | struct page *page) | 1548 | struct page *page) |
@@ -1597,10 +1550,9 @@ int nfs_migrate_page(struct address_space *mapping, struct page *newpage, | |||
1597 | struct nfs_page *req; | 1550 | struct nfs_page *req; |
1598 | int ret; | 1551 | int ret; |
1599 | 1552 | ||
1600 | if (PageFsCache(page)) | 1553 | nfs_fscache_release_page(page, GFP_KERNEL); |
1601 | nfs_fscache_release_page(page, GFP_KERNEL); | ||
1602 | 1554 | ||
1603 | req = nfs_find_and_lock_request(page); | 1555 | req = nfs_find_and_lock_request(page, false); |
1604 | ret = PTR_ERR(req); | 1556 | ret = PTR_ERR(req); |
1605 | if (IS_ERR(req)) | 1557 | if (IS_ERR(req)) |
1606 | goto out; | 1558 | goto out; |