diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-25 12:18:27 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-25 12:18:27 -0500 |
commit | 53846a21c1766326bb14ce8ab6e997a0c120675d (patch) | |
tree | 37b04485e29844b4e734479181276a2f4d2447e4 /fs/nfs | |
parent | 2e9abdd9bad485970b37cd53a82f92702054984c (diff) | |
parent | 1ebbe2b20091d306453a5cf480a87e6cd28ae76f (diff) |
Merge git://git.linux-nfs.org/pub/linux/nfs-2.6
* git://git.linux-nfs.org/pub/linux/nfs-2.6: (103 commits)
SUNRPC,RPCSEC_GSS: spkm3--fix config dependencies
SUNRPC,RPCSEC_GSS: spkm3: import contexts using NID_cast5_cbc
LOCKD: Make nlmsvc_traverse_shares return void
LOCKD: nlmsvc_traverse_blocks return is unused
SUNRPC,RPCSEC_GSS: fix krb5 sequence numbers.
NFSv4: Dont list system.nfs4_acl for filesystems that don't support it.
SUNRPC,RPCSEC_GSS: remove unnecessary kmalloc of a checksum
SUNRPC: Ensure rpc_call_async() always calls tk_ops->rpc_release()
SUNRPC: Fix memory barriers for req->rq_received
NFS: Fix a race in nfs_sync_inode()
NFS: Clean up nfs_flush_list()
NFS: Fix a race with PG_private and nfs_release_page()
NFSv4: Ensure the callback daemon flushes signals
SUNRPC: Fix a 'Busy inodes' error in rpc_pipefs
NFS, NLM: Allow blocking locks to respect signals
NFS: Make nfs_fhget() return appropriate error values
NFSv4: Fix an oops in nfs4_fill_super
lockd: blocks should hold a reference to the nlm_file
NFSv4: SETCLIENTID_CONFIRM should handle NFS4ERR_DELAY/NFS4ERR_RESOURCE
NFSv4: Send the delegation stateid for SETATTR calls
...
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/callback.c | 20 | ||||
-rw-r--r-- | fs/nfs/callback_xdr.c | 28 | ||||
-rw-r--r-- | fs/nfs/delegation.c | 19 | ||||
-rw-r--r-- | fs/nfs/delegation.h | 1 | ||||
-rw-r--r-- | fs/nfs/dir.c | 114 | ||||
-rw-r--r-- | fs/nfs/direct.c | 949 | ||||
-rw-r--r-- | fs/nfs/file.c | 49 | ||||
-rw-r--r-- | fs/nfs/idmap.c | 47 | ||||
-rw-r--r-- | fs/nfs/inode.c | 229 | ||||
-rw-r--r-- | fs/nfs/iostat.h | 164 | ||||
-rw-r--r-- | fs/nfs/mount_clnt.c | 17 | ||||
-rw-r--r-- | fs/nfs/nfs2xdr.c | 4 | ||||
-rw-r--r-- | fs/nfs/nfs3acl.c | 16 | ||||
-rw-r--r-- | fs/nfs/nfs3proc.c | 246 | ||||
-rw-r--r-- | fs/nfs/nfs3xdr.c | 6 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 180 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 1 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 2 | ||||
-rw-r--r-- | fs/nfs/pagelist.c | 16 | ||||
-rw-r--r-- | fs/nfs/proc.c | 156 | ||||
-rw-r--r-- | fs/nfs/read.c | 102 | ||||
-rw-r--r-- | fs/nfs/unlink.c | 3 | ||||
-rw-r--r-- | fs/nfs/write.c | 288 |
23 files changed, 1691 insertions, 966 deletions
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index fcd97406a778..99d2cfbce863 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
@@ -55,7 +55,12 @@ static void nfs_callback_svc(struct svc_rqst *rqstp) | |||
55 | 55 | ||
56 | complete(&nfs_callback_info.started); | 56 | complete(&nfs_callback_info.started); |
57 | 57 | ||
58 | while (nfs_callback_info.users != 0 || !signalled()) { | 58 | for(;;) { |
59 | if (signalled()) { | ||
60 | if (nfs_callback_info.users == 0) | ||
61 | break; | ||
62 | flush_signals(current); | ||
63 | } | ||
59 | /* | 64 | /* |
60 | * Listen for a request on the socket | 65 | * Listen for a request on the socket |
61 | */ | 66 | */ |
@@ -73,6 +78,7 @@ static void nfs_callback_svc(struct svc_rqst *rqstp) | |||
73 | svc_process(serv, rqstp); | 78 | svc_process(serv, rqstp); |
74 | } | 79 | } |
75 | 80 | ||
81 | svc_exit_thread(rqstp); | ||
76 | nfs_callback_info.pid = 0; | 82 | nfs_callback_info.pid = 0; |
77 | complete(&nfs_callback_info.stopped); | 83 | complete(&nfs_callback_info.stopped); |
78 | unlock_kernel(); | 84 | unlock_kernel(); |
@@ -134,11 +140,13 @@ int nfs_callback_down(void) | |||
134 | 140 | ||
135 | lock_kernel(); | 141 | lock_kernel(); |
136 | down(&nfs_callback_sema); | 142 | down(&nfs_callback_sema); |
137 | if (--nfs_callback_info.users || nfs_callback_info.pid == 0) | 143 | nfs_callback_info.users--; |
138 | goto out; | 144 | do { |
139 | kill_proc(nfs_callback_info.pid, SIGKILL, 1); | 145 | if (nfs_callback_info.users != 0 || nfs_callback_info.pid == 0) |
140 | wait_for_completion(&nfs_callback_info.stopped); | 146 | break; |
141 | out: | 147 | if (kill_proc(nfs_callback_info.pid, SIGKILL, 1) < 0) |
148 | break; | ||
149 | } while (wait_for_completion_timeout(&nfs_callback_info.stopped, 5*HZ) == 0); | ||
142 | up(&nfs_callback_sema); | 150 | up(&nfs_callback_sema); |
143 | unlock_kernel(); | 151 | unlock_kernel(); |
144 | return ret; | 152 | return ret; |
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index 7c33b9a81a94..05c38cf40b69 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c | |||
@@ -330,7 +330,7 @@ static unsigned encode_op_hdr(struct xdr_stream *xdr, uint32_t op, uint32_t res) | |||
330 | 330 | ||
331 | static unsigned encode_getattr_res(struct svc_rqst *rqstp, struct xdr_stream *xdr, const struct cb_getattrres *res) | 331 | static unsigned encode_getattr_res(struct svc_rqst *rqstp, struct xdr_stream *xdr, const struct cb_getattrres *res) |
332 | { | 332 | { |
333 | uint32_t *savep; | 333 | uint32_t *savep = NULL; |
334 | unsigned status = res->status; | 334 | unsigned status = res->status; |
335 | 335 | ||
336 | if (unlikely(status != 0)) | 336 | if (unlikely(status != 0)) |
@@ -358,23 +358,26 @@ static unsigned process_op(struct svc_rqst *rqstp, | |||
358 | struct xdr_stream *xdr_in, void *argp, | 358 | struct xdr_stream *xdr_in, void *argp, |
359 | struct xdr_stream *xdr_out, void *resp) | 359 | struct xdr_stream *xdr_out, void *resp) |
360 | { | 360 | { |
361 | struct callback_op *op; | 361 | struct callback_op *op = &callback_ops[0]; |
362 | unsigned int op_nr; | 362 | unsigned int op_nr = OP_CB_ILLEGAL; |
363 | unsigned int status = 0; | 363 | unsigned int status = 0; |
364 | long maxlen; | 364 | long maxlen; |
365 | unsigned res; | 365 | unsigned res; |
366 | 366 | ||
367 | dprintk("%s: start\n", __FUNCTION__); | 367 | dprintk("%s: start\n", __FUNCTION__); |
368 | status = decode_op_hdr(xdr_in, &op_nr); | 368 | status = decode_op_hdr(xdr_in, &op_nr); |
369 | if (unlikely(status != 0)) { | 369 | if (likely(status == 0)) { |
370 | op_nr = OP_CB_ILLEGAL; | 370 | switch (op_nr) { |
371 | op = &callback_ops[0]; | 371 | case OP_CB_GETATTR: |
372 | } else if (unlikely(op_nr != OP_CB_GETATTR && op_nr != OP_CB_RECALL)) { | 372 | case OP_CB_RECALL: |
373 | op_nr = OP_CB_ILLEGAL; | 373 | op = &callback_ops[op_nr]; |
374 | op = &callback_ops[0]; | 374 | break; |
375 | status = htonl(NFS4ERR_OP_ILLEGAL); | 375 | default: |
376 | } else | 376 | op_nr = OP_CB_ILLEGAL; |
377 | op = &callback_ops[op_nr]; | 377 | op = &callback_ops[0]; |
378 | status = htonl(NFS4ERR_OP_ILLEGAL); | ||
379 | } | ||
380 | } | ||
378 | 381 | ||
379 | maxlen = xdr_out->end - xdr_out->p; | 382 | maxlen = xdr_out->end - xdr_out->p; |
380 | if (maxlen > 0 && maxlen < PAGE_SIZE) { | 383 | if (maxlen > 0 && maxlen < PAGE_SIZE) { |
@@ -416,6 +419,7 @@ static int nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *resp | |||
416 | decode_compound_hdr_arg(&xdr_in, &hdr_arg); | 419 | decode_compound_hdr_arg(&xdr_in, &hdr_arg); |
417 | hdr_res.taglen = hdr_arg.taglen; | 420 | hdr_res.taglen = hdr_arg.taglen; |
418 | hdr_res.tag = hdr_arg.tag; | 421 | hdr_res.tag = hdr_arg.tag; |
422 | hdr_res.nops = NULL; | ||
419 | encode_compound_hdr_res(&xdr_out, &hdr_res); | 423 | encode_compound_hdr_res(&xdr_out, &hdr_res); |
420 | 424 | ||
421 | for (;;) { | 425 | for (;;) { |
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index c6f07c1c71e6..d3be923d4e43 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
@@ -421,3 +421,22 @@ void nfs_delegation_reap_unclaimed(struct nfs4_client *clp) | |||
421 | nfs_free_delegation(delegation); | 421 | nfs_free_delegation(delegation); |
422 | } | 422 | } |
423 | } | 423 | } |
424 | |||
425 | int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode) | ||
426 | { | ||
427 | struct nfs4_client *clp = NFS_SERVER(inode)->nfs4_state; | ||
428 | struct nfs_inode *nfsi = NFS_I(inode); | ||
429 | struct nfs_delegation *delegation; | ||
430 | int res = 0; | ||
431 | |||
432 | if (nfsi->delegation_state == 0) | ||
433 | return 0; | ||
434 | spin_lock(&clp->cl_lock); | ||
435 | delegation = nfsi->delegation; | ||
436 | if (delegation != NULL) { | ||
437 | memcpy(dst->data, delegation->stateid.data, sizeof(dst->data)); | ||
438 | res = 1; | ||
439 | } | ||
440 | spin_unlock(&clp->cl_lock); | ||
441 | return res; | ||
442 | } | ||
diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h index 7a0b2bfce771..3858694652fa 100644 --- a/fs/nfs/delegation.h +++ b/fs/nfs/delegation.h | |||
@@ -41,6 +41,7 @@ void nfs_delegation_reap_unclaimed(struct nfs4_client *clp); | |||
41 | int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid); | 41 | int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid); |
42 | int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state); | 42 | int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state); |
43 | int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl); | 43 | int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl); |
44 | int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode); | ||
44 | 45 | ||
45 | static inline int nfs_have_delegation(struct inode *inode, int flags) | 46 | static inline int nfs_have_delegation(struct inode *inode, int flags) |
46 | { | 47 | { |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index a1554bead692..06c48b385c94 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -34,6 +34,7 @@ | |||
34 | 34 | ||
35 | #include "nfs4_fs.h" | 35 | #include "nfs4_fs.h" |
36 | #include "delegation.h" | 36 | #include "delegation.h" |
37 | #include "iostat.h" | ||
37 | 38 | ||
38 | #define NFS_PARANOIA 1 | 39 | #define NFS_PARANOIA 1 |
39 | /* #define NFS_DEBUG_VERBOSE 1 */ | 40 | /* #define NFS_DEBUG_VERBOSE 1 */ |
@@ -129,6 +130,9 @@ nfs_opendir(struct inode *inode, struct file *filp) | |||
129 | { | 130 | { |
130 | int res = 0; | 131 | int res = 0; |
131 | 132 | ||
133 | dfprintk(VFS, "NFS: opendir(%s/%ld)\n", | ||
134 | inode->i_sb->s_id, inode->i_ino); | ||
135 | |||
132 | lock_kernel(); | 136 | lock_kernel(); |
133 | /* Call generic open code in order to cache credentials */ | 137 | /* Call generic open code in order to cache credentials */ |
134 | if (!res) | 138 | if (!res) |
@@ -172,7 +176,9 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page) | |||
172 | unsigned long timestamp; | 176 | unsigned long timestamp; |
173 | int error; | 177 | int error; |
174 | 178 | ||
175 | dfprintk(VFS, "NFS: nfs_readdir_filler() reading cookie %Lu into page %lu.\n", (long long)desc->entry->cookie, page->index); | 179 | dfprintk(DIRCACHE, "NFS: %s: reading cookie %Lu into page %lu\n", |
180 | __FUNCTION__, (long long)desc->entry->cookie, | ||
181 | page->index); | ||
176 | 182 | ||
177 | again: | 183 | again: |
178 | timestamp = jiffies; | 184 | timestamp = jiffies; |
@@ -244,7 +250,8 @@ int find_dirent(nfs_readdir_descriptor_t *desc) | |||
244 | status; | 250 | status; |
245 | 251 | ||
246 | while((status = dir_decode(desc)) == 0) { | 252 | while((status = dir_decode(desc)) == 0) { |
247 | dfprintk(VFS, "NFS: found cookie %Lu\n", (unsigned long long)entry->cookie); | 253 | dfprintk(DIRCACHE, "NFS: %s: examining cookie %Lu\n", |
254 | __FUNCTION__, (unsigned long long)entry->cookie); | ||
248 | if (entry->prev_cookie == *desc->dir_cookie) | 255 | if (entry->prev_cookie == *desc->dir_cookie) |
249 | break; | 256 | break; |
250 | if (loop_count++ > 200) { | 257 | if (loop_count++ > 200) { |
@@ -252,7 +259,6 @@ int find_dirent(nfs_readdir_descriptor_t *desc) | |||
252 | schedule(); | 259 | schedule(); |
253 | } | 260 | } |
254 | } | 261 | } |
255 | dfprintk(VFS, "NFS: find_dirent() returns %d\n", status); | ||
256 | return status; | 262 | return status; |
257 | } | 263 | } |
258 | 264 | ||
@@ -276,7 +282,8 @@ int find_dirent_index(nfs_readdir_descriptor_t *desc) | |||
276 | if (status) | 282 | if (status) |
277 | break; | 283 | break; |
278 | 284 | ||
279 | dfprintk(VFS, "NFS: found cookie %Lu at index %Ld\n", (unsigned long long)entry->cookie, desc->current_index); | 285 | dfprintk(DIRCACHE, "NFS: found cookie %Lu at index %Ld\n", |
286 | (unsigned long long)entry->cookie, desc->current_index); | ||
280 | 287 | ||
281 | if (desc->file->f_pos == desc->current_index) { | 288 | if (desc->file->f_pos == desc->current_index) { |
282 | *desc->dir_cookie = entry->cookie; | 289 | *desc->dir_cookie = entry->cookie; |
@@ -288,7 +295,6 @@ int find_dirent_index(nfs_readdir_descriptor_t *desc) | |||
288 | schedule(); | 295 | schedule(); |
289 | } | 296 | } |
290 | } | 297 | } |
291 | dfprintk(VFS, "NFS: find_dirent_index() returns %d\n", status); | ||
292 | return status; | 298 | return status; |
293 | } | 299 | } |
294 | 300 | ||
@@ -303,7 +309,9 @@ int find_dirent_page(nfs_readdir_descriptor_t *desc) | |||
303 | struct page *page; | 309 | struct page *page; |
304 | int status; | 310 | int status; |
305 | 311 | ||
306 | dfprintk(VFS, "NFS: find_dirent_page() searching directory page %ld\n", desc->page_index); | 312 | dfprintk(DIRCACHE, "NFS: %s: searching page %ld for target %Lu\n", |
313 | __FUNCTION__, desc->page_index, | ||
314 | (long long) *desc->dir_cookie); | ||
307 | 315 | ||
308 | page = read_cache_page(inode->i_mapping, desc->page_index, | 316 | page = read_cache_page(inode->i_mapping, desc->page_index, |
309 | (filler_t *)nfs_readdir_filler, desc); | 317 | (filler_t *)nfs_readdir_filler, desc); |
@@ -324,7 +332,7 @@ int find_dirent_page(nfs_readdir_descriptor_t *desc) | |||
324 | if (status < 0) | 332 | if (status < 0) |
325 | dir_page_release(desc); | 333 | dir_page_release(desc); |
326 | out: | 334 | out: |
327 | dfprintk(VFS, "NFS: find_dirent_page() returns %d\n", status); | 335 | dfprintk(DIRCACHE, "NFS: %s: returns %d\n", __FUNCTION__, status); |
328 | return status; | 336 | return status; |
329 | read_error: | 337 | read_error: |
330 | page_cache_release(page); | 338 | page_cache_release(page); |
@@ -346,13 +354,15 @@ int readdir_search_pagecache(nfs_readdir_descriptor_t *desc) | |||
346 | 354 | ||
347 | /* Always search-by-index from the beginning of the cache */ | 355 | /* Always search-by-index from the beginning of the cache */ |
348 | if (*desc->dir_cookie == 0) { | 356 | if (*desc->dir_cookie == 0) { |
349 | dfprintk(VFS, "NFS: readdir_search_pagecache() searching for offset %Ld\n", (long long)desc->file->f_pos); | 357 | dfprintk(DIRCACHE, "NFS: readdir_search_pagecache() searching for offset %Ld\n", |
358 | (long long)desc->file->f_pos); | ||
350 | desc->page_index = 0; | 359 | desc->page_index = 0; |
351 | desc->entry->cookie = desc->entry->prev_cookie = 0; | 360 | desc->entry->cookie = desc->entry->prev_cookie = 0; |
352 | desc->entry->eof = 0; | 361 | desc->entry->eof = 0; |
353 | desc->current_index = 0; | 362 | desc->current_index = 0; |
354 | } else | 363 | } else |
355 | dfprintk(VFS, "NFS: readdir_search_pagecache() searching for cookie %Lu\n", (unsigned long long)*desc->dir_cookie); | 364 | dfprintk(DIRCACHE, "NFS: readdir_search_pagecache() searching for cookie %Lu\n", |
365 | (unsigned long long)*desc->dir_cookie); | ||
356 | 366 | ||
357 | for (;;) { | 367 | for (;;) { |
358 | res = find_dirent_page(desc); | 368 | res = find_dirent_page(desc); |
@@ -365,7 +375,8 @@ int readdir_search_pagecache(nfs_readdir_descriptor_t *desc) | |||
365 | schedule(); | 375 | schedule(); |
366 | } | 376 | } |
367 | } | 377 | } |
368 | dfprintk(VFS, "NFS: readdir_search_pagecache() returned %d\n", res); | 378 | |
379 | dfprintk(DIRCACHE, "NFS: %s: returns %d\n", __FUNCTION__, res); | ||
369 | return res; | 380 | return res; |
370 | } | 381 | } |
371 | 382 | ||
@@ -390,7 +401,8 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
390 | int loop_count = 0, | 401 | int loop_count = 0, |
391 | res; | 402 | res; |
392 | 403 | ||
393 | dfprintk(VFS, "NFS: nfs_do_filldir() filling starting @ cookie %Lu\n", (long long)entry->cookie); | 404 | dfprintk(DIRCACHE, "NFS: nfs_do_filldir() filling starting @ cookie %Lu\n", |
405 | (unsigned long long)entry->cookie); | ||
394 | 406 | ||
395 | for(;;) { | 407 | for(;;) { |
396 | unsigned d_type = DT_UNKNOWN; | 408 | unsigned d_type = DT_UNKNOWN; |
@@ -427,7 +439,8 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
427 | dir_page_release(desc); | 439 | dir_page_release(desc); |
428 | if (dentry != NULL) | 440 | if (dentry != NULL) |
429 | dput(dentry); | 441 | dput(dentry); |
430 | dfprintk(VFS, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n", (unsigned long long)*desc->dir_cookie, res); | 442 | dfprintk(DIRCACHE, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n", |
443 | (unsigned long long)*desc->dir_cookie, res); | ||
431 | return res; | 444 | return res; |
432 | } | 445 | } |
433 | 446 | ||
@@ -453,7 +466,8 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
453 | struct page *page = NULL; | 466 | struct page *page = NULL; |
454 | int status; | 467 | int status; |
455 | 468 | ||
456 | dfprintk(VFS, "NFS: uncached_readdir() searching for cookie %Lu\n", (unsigned long long)*desc->dir_cookie); | 469 | dfprintk(DIRCACHE, "NFS: uncached_readdir() searching for cookie %Lu\n", |
470 | (unsigned long long)*desc->dir_cookie); | ||
457 | 471 | ||
458 | page = alloc_page(GFP_HIGHUSER); | 472 | page = alloc_page(GFP_HIGHUSER); |
459 | if (!page) { | 473 | if (!page) { |
@@ -485,7 +499,8 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
485 | desc->entry->cookie = desc->entry->prev_cookie = 0; | 499 | desc->entry->cookie = desc->entry->prev_cookie = 0; |
486 | desc->entry->eof = 0; | 500 | desc->entry->eof = 0; |
487 | out: | 501 | out: |
488 | dfprintk(VFS, "NFS: uncached_readdir() returns %d\n", status); | 502 | dfprintk(DIRCACHE, "NFS: %s: returns %d\n", |
503 | __FUNCTION__, status); | ||
489 | return status; | 504 | return status; |
490 | out_release: | 505 | out_release: |
491 | dir_page_release(desc); | 506 | dir_page_release(desc); |
@@ -507,6 +522,11 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
507 | struct nfs_fattr fattr; | 522 | struct nfs_fattr fattr; |
508 | long res; | 523 | long res; |
509 | 524 | ||
525 | dfprintk(VFS, "NFS: readdir(%s/%s) starting at cookie %Lu\n", | ||
526 | dentry->d_parent->d_name.name, dentry->d_name.name, | ||
527 | (long long)filp->f_pos); | ||
528 | nfs_inc_stats(inode, NFSIOS_VFSGETDENTS); | ||
529 | |||
510 | lock_kernel(); | 530 | lock_kernel(); |
511 | 531 | ||
512 | res = nfs_revalidate_inode(NFS_SERVER(inode), inode); | 532 | res = nfs_revalidate_inode(NFS_SERVER(inode), inode); |
@@ -566,9 +586,12 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
566 | } | 586 | } |
567 | } | 587 | } |
568 | unlock_kernel(); | 588 | unlock_kernel(); |
569 | if (res < 0) | 589 | if (res > 0) |
570 | return res; | 590 | res = 0; |
571 | return 0; | 591 | dfprintk(VFS, "NFS: readdir(%s/%s) returns %ld\n", |
592 | dentry->d_parent->d_name.name, dentry->d_name.name, | ||
593 | res); | ||
594 | return res; | ||
572 | } | 595 | } |
573 | 596 | ||
574 | loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin) | 597 | loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin) |
@@ -599,6 +622,10 @@ out: | |||
599 | */ | 622 | */ |
600 | int nfs_fsync_dir(struct file *filp, struct dentry *dentry, int datasync) | 623 | int nfs_fsync_dir(struct file *filp, struct dentry *dentry, int datasync) |
601 | { | 624 | { |
625 | dfprintk(VFS, "NFS: fsync_dir(%s/%s) datasync %d\n", | ||
626 | dentry->d_parent->d_name.name, dentry->d_name.name, | ||
627 | datasync); | ||
628 | |||
602 | return 0; | 629 | return 0; |
603 | } | 630 | } |
604 | 631 | ||
@@ -713,6 +740,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) | |||
713 | parent = dget_parent(dentry); | 740 | parent = dget_parent(dentry); |
714 | lock_kernel(); | 741 | lock_kernel(); |
715 | dir = parent->d_inode; | 742 | dir = parent->d_inode; |
743 | nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE); | ||
716 | inode = dentry->d_inode; | 744 | inode = dentry->d_inode; |
717 | 745 | ||
718 | if (!inode) { | 746 | if (!inode) { |
@@ -722,8 +750,9 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) | |||
722 | } | 750 | } |
723 | 751 | ||
724 | if (is_bad_inode(inode)) { | 752 | if (is_bad_inode(inode)) { |
725 | dfprintk(VFS, "nfs_lookup_validate: %s/%s has dud inode\n", | 753 | dfprintk(LOOKUPCACHE, "%s: %s/%s has dud inode\n", |
726 | dentry->d_parent->d_name.name, dentry->d_name.name); | 754 | __FUNCTION__, dentry->d_parent->d_name.name, |
755 | dentry->d_name.name); | ||
727 | goto out_bad; | 756 | goto out_bad; |
728 | } | 757 | } |
729 | 758 | ||
@@ -755,6 +784,9 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) | |||
755 | out_valid: | 784 | out_valid: |
756 | unlock_kernel(); | 785 | unlock_kernel(); |
757 | dput(parent); | 786 | dput(parent); |
787 | dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is valid\n", | ||
788 | __FUNCTION__, dentry->d_parent->d_name.name, | ||
789 | dentry->d_name.name); | ||
758 | return 1; | 790 | return 1; |
759 | out_zap_parent: | 791 | out_zap_parent: |
760 | nfs_zap_caches(dir); | 792 | nfs_zap_caches(dir); |
@@ -771,6 +803,9 @@ out_zap_parent: | |||
771 | d_drop(dentry); | 803 | d_drop(dentry); |
772 | unlock_kernel(); | 804 | unlock_kernel(); |
773 | dput(parent); | 805 | dput(parent); |
806 | dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is invalid\n", | ||
807 | __FUNCTION__, dentry->d_parent->d_name.name, | ||
808 | dentry->d_name.name); | ||
774 | return 0; | 809 | return 0; |
775 | } | 810 | } |
776 | 811 | ||
@@ -844,6 +879,7 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru | |||
844 | 879 | ||
845 | dfprintk(VFS, "NFS: lookup(%s/%s)\n", | 880 | dfprintk(VFS, "NFS: lookup(%s/%s)\n", |
846 | dentry->d_parent->d_name.name, dentry->d_name.name); | 881 | dentry->d_parent->d_name.name, dentry->d_name.name); |
882 | nfs_inc_stats(dir, NFSIOS_VFSLOOKUP); | ||
847 | 883 | ||
848 | res = ERR_PTR(-ENAMETOOLONG); | 884 | res = ERR_PTR(-ENAMETOOLONG); |
849 | if (dentry->d_name.len > NFS_SERVER(dir)->namelen) | 885 | if (dentry->d_name.len > NFS_SERVER(dir)->namelen) |
@@ -865,9 +901,9 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru | |||
865 | res = ERR_PTR(error); | 901 | res = ERR_PTR(error); |
866 | goto out_unlock; | 902 | goto out_unlock; |
867 | } | 903 | } |
868 | res = ERR_PTR(-EACCES); | ||
869 | inode = nfs_fhget(dentry->d_sb, &fhandle, &fattr); | 904 | inode = nfs_fhget(dentry->d_sb, &fhandle, &fattr); |
870 | if (!inode) | 905 | res = (struct dentry *)inode; |
906 | if (IS_ERR(res)) | ||
871 | goto out_unlock; | 907 | goto out_unlock; |
872 | no_entry: | 908 | no_entry: |
873 | res = d_add_unique(dentry, inode); | 909 | res = d_add_unique(dentry, inode); |
@@ -912,6 +948,9 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry | |||
912 | struct dentry *res = NULL; | 948 | struct dentry *res = NULL; |
913 | int error; | 949 | int error; |
914 | 950 | ||
951 | dfprintk(VFS, "NFS: atomic_lookup(%s/%ld), %s\n", | ||
952 | dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); | ||
953 | |||
915 | /* Check that we are indeed trying to open this file */ | 954 | /* Check that we are indeed trying to open this file */ |
916 | if (!is_atomic_open(dir, nd)) | 955 | if (!is_atomic_open(dir, nd)) |
917 | goto no_open; | 956 | goto no_open; |
@@ -1057,7 +1096,7 @@ static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc) | |||
1057 | return NULL; | 1096 | return NULL; |
1058 | dentry->d_op = NFS_PROTO(dir)->dentry_ops; | 1097 | dentry->d_op = NFS_PROTO(dir)->dentry_ops; |
1059 | inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr); | 1098 | inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr); |
1060 | if (!inode) { | 1099 | if (IS_ERR(inode)) { |
1061 | dput(dentry); | 1100 | dput(dentry); |
1062 | return NULL; | 1101 | return NULL; |
1063 | } | 1102 | } |
@@ -1095,9 +1134,9 @@ int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle, | |||
1095 | if (error < 0) | 1134 | if (error < 0) |
1096 | goto out_err; | 1135 | goto out_err; |
1097 | } | 1136 | } |
1098 | error = -ENOMEM; | ||
1099 | inode = nfs_fhget(dentry->d_sb, fhandle, fattr); | 1137 | inode = nfs_fhget(dentry->d_sb, fhandle, fattr); |
1100 | if (inode == NULL) | 1138 | error = PTR_ERR(inode); |
1139 | if (IS_ERR(inode)) | ||
1101 | goto out_err; | 1140 | goto out_err; |
1102 | d_instantiate(dentry, inode); | 1141 | d_instantiate(dentry, inode); |
1103 | return 0; | 1142 | return 0; |
@@ -1119,8 +1158,8 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode, | |||
1119 | int error; | 1158 | int error; |
1120 | int open_flags = 0; | 1159 | int open_flags = 0; |
1121 | 1160 | ||
1122 | dfprintk(VFS, "NFS: create(%s/%ld, %s\n", dir->i_sb->s_id, | 1161 | dfprintk(VFS, "NFS: create(%s/%ld), %s\n", |
1123 | dir->i_ino, dentry->d_name.name); | 1162 | dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); |
1124 | 1163 | ||
1125 | attr.ia_mode = mode; | 1164 | attr.ia_mode = mode; |
1126 | attr.ia_valid = ATTR_MODE; | 1165 | attr.ia_valid = ATTR_MODE; |
@@ -1153,8 +1192,8 @@ nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) | |||
1153 | struct iattr attr; | 1192 | struct iattr attr; |
1154 | int status; | 1193 | int status; |
1155 | 1194 | ||
1156 | dfprintk(VFS, "NFS: mknod(%s/%ld, %s\n", dir->i_sb->s_id, | 1195 | dfprintk(VFS, "NFS: mknod(%s/%ld), %s\n", |
1157 | dir->i_ino, dentry->d_name.name); | 1196 | dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); |
1158 | 1197 | ||
1159 | if (!new_valid_dev(rdev)) | 1198 | if (!new_valid_dev(rdev)) |
1160 | return -EINVAL; | 1199 | return -EINVAL; |
@@ -1186,8 +1225,8 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
1186 | struct iattr attr; | 1225 | struct iattr attr; |
1187 | int error; | 1226 | int error; |
1188 | 1227 | ||
1189 | dfprintk(VFS, "NFS: mkdir(%s/%ld, %s\n", dir->i_sb->s_id, | 1228 | dfprintk(VFS, "NFS: mkdir(%s/%ld), %s\n", |
1190 | dir->i_ino, dentry->d_name.name); | 1229 | dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); |
1191 | 1230 | ||
1192 | attr.ia_valid = ATTR_MODE; | 1231 | attr.ia_valid = ATTR_MODE; |
1193 | attr.ia_mode = mode | S_IFDIR; | 1232 | attr.ia_mode = mode | S_IFDIR; |
@@ -1212,8 +1251,8 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry) | |||
1212 | { | 1251 | { |
1213 | int error; | 1252 | int error; |
1214 | 1253 | ||
1215 | dfprintk(VFS, "NFS: rmdir(%s/%ld, %s\n", dir->i_sb->s_id, | 1254 | dfprintk(VFS, "NFS: rmdir(%s/%ld), %s\n", |
1216 | dir->i_ino, dentry->d_name.name); | 1255 | dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); |
1217 | 1256 | ||
1218 | lock_kernel(); | 1257 | lock_kernel(); |
1219 | nfs_begin_data_update(dir); | 1258 | nfs_begin_data_update(dir); |
@@ -1241,6 +1280,7 @@ static int nfs_sillyrename(struct inode *dir, struct dentry *dentry) | |||
1241 | dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)\n", | 1280 | dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)\n", |
1242 | dentry->d_parent->d_name.name, dentry->d_name.name, | 1281 | dentry->d_parent->d_name.name, dentry->d_name.name, |
1243 | atomic_read(&dentry->d_count)); | 1282 | atomic_read(&dentry->d_count)); |
1283 | nfs_inc_stats(dir, NFSIOS_SILLYRENAME); | ||
1244 | 1284 | ||
1245 | #ifdef NFS_PARANOIA | 1285 | #ifdef NFS_PARANOIA |
1246 | if (!dentry->d_inode) | 1286 | if (!dentry->d_inode) |
@@ -1268,8 +1308,8 @@ dentry->d_parent->d_name.name, dentry->d_name.name); | |||
1268 | sillycounter++; | 1308 | sillycounter++; |
1269 | sprintf(suffix, "%*.*x", countersize, countersize, sillycounter); | 1309 | sprintf(suffix, "%*.*x", countersize, countersize, sillycounter); |
1270 | 1310 | ||
1271 | dfprintk(VFS, "trying to rename %s to %s\n", | 1311 | dfprintk(VFS, "NFS: trying to rename %s to %s\n", |
1272 | dentry->d_name.name, silly); | 1312 | dentry->d_name.name, silly); |
1273 | 1313 | ||
1274 | sdentry = lookup_one_len(silly, dentry->d_parent, slen); | 1314 | sdentry = lookup_one_len(silly, dentry->d_parent, slen); |
1275 | /* | 1315 | /* |
@@ -1640,6 +1680,8 @@ int nfs_permission(struct inode *inode, int mask, struct nameidata *nd) | |||
1640 | struct rpc_cred *cred; | 1680 | struct rpc_cred *cred; |
1641 | int res = 0; | 1681 | int res = 0; |
1642 | 1682 | ||
1683 | nfs_inc_stats(inode, NFSIOS_VFSACCESS); | ||
1684 | |||
1643 | if (mask == 0) | 1685 | if (mask == 0) |
1644 | goto out; | 1686 | goto out; |
1645 | /* Is this sys_access() ? */ | 1687 | /* Is this sys_access() ? */ |
@@ -1679,13 +1721,15 @@ force_lookup: | |||
1679 | res = PTR_ERR(cred); | 1721 | res = PTR_ERR(cred); |
1680 | unlock_kernel(); | 1722 | unlock_kernel(); |
1681 | out: | 1723 | out: |
1724 | dfprintk(VFS, "NFS: permission(%s/%ld), mask=0x%x, res=%d\n", | ||
1725 | inode->i_sb->s_id, inode->i_ino, mask, res); | ||
1682 | return res; | 1726 | return res; |
1683 | out_notsup: | 1727 | out_notsup: |
1684 | res = nfs_revalidate_inode(NFS_SERVER(inode), inode); | 1728 | res = nfs_revalidate_inode(NFS_SERVER(inode), inode); |
1685 | if (res == 0) | 1729 | if (res == 0) |
1686 | res = generic_permission(inode, mask, NULL); | 1730 | res = generic_permission(inode, mask, NULL); |
1687 | unlock_kernel(); | 1731 | unlock_kernel(); |
1688 | return res; | 1732 | goto out; |
1689 | } | 1733 | } |
1690 | 1734 | ||
1691 | /* | 1735 | /* |
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 4ae2f3b33fef..0f583cb16ddb 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -7,11 +7,11 @@ | |||
7 | * | 7 | * |
8 | * There are important applications whose performance or correctness | 8 | * There are important applications whose performance or correctness |
9 | * depends on uncached access to file data. Database clusters | 9 | * depends on uncached access to file data. Database clusters |
10 | * (multiple copies of the same instance running on separate hosts) | 10 | * (multiple copies of the same instance running on separate hosts) |
11 | * implement their own cache coherency protocol that subsumes file | 11 | * implement their own cache coherency protocol that subsumes file |
12 | * system cache protocols. Applications that process datasets | 12 | * system cache protocols. Applications that process datasets |
13 | * considerably larger than the client's memory do not always benefit | 13 | * considerably larger than the client's memory do not always benefit |
14 | * from a local cache. A streaming video server, for instance, has no | 14 | * from a local cache. A streaming video server, for instance, has no |
15 | * need to cache the contents of a file. | 15 | * need to cache the contents of a file. |
16 | * | 16 | * |
17 | * When an application requests uncached I/O, all read and write requests | 17 | * When an application requests uncached I/O, all read and write requests |
@@ -34,6 +34,7 @@ | |||
34 | * 08 Jun 2003 Port to 2.5 APIs --cel | 34 | * 08 Jun 2003 Port to 2.5 APIs --cel |
35 | * 31 Mar 2004 Handle direct I/O without VFS support --cel | 35 | * 31 Mar 2004 Handle direct I/O without VFS support --cel |
36 | * 15 Sep 2004 Parallel async reads --cel | 36 | * 15 Sep 2004 Parallel async reads --cel |
37 | * 04 May 2005 support O_DIRECT with aio --cel | ||
37 | * | 38 | * |
38 | */ | 39 | */ |
39 | 40 | ||
@@ -54,10 +55,10 @@ | |||
54 | #include <asm/uaccess.h> | 55 | #include <asm/uaccess.h> |
55 | #include <asm/atomic.h> | 56 | #include <asm/atomic.h> |
56 | 57 | ||
58 | #include "iostat.h" | ||
59 | |||
57 | #define NFSDBG_FACILITY NFSDBG_VFS | 60 | #define NFSDBG_FACILITY NFSDBG_VFS |
58 | #define MAX_DIRECTIO_SIZE (4096UL << PAGE_SHIFT) | ||
59 | 61 | ||
60 | static void nfs_free_user_pages(struct page **pages, int npages, int do_dirty); | ||
61 | static kmem_cache_t *nfs_direct_cachep; | 62 | static kmem_cache_t *nfs_direct_cachep; |
62 | 63 | ||
63 | /* | 64 | /* |
@@ -65,38 +66,78 @@ static kmem_cache_t *nfs_direct_cachep; | |||
65 | */ | 66 | */ |
66 | struct nfs_direct_req { | 67 | struct nfs_direct_req { |
67 | struct kref kref; /* release manager */ | 68 | struct kref kref; /* release manager */ |
68 | struct list_head list; /* nfs_read_data structs */ | 69 | |
69 | wait_queue_head_t wait; /* wait for i/o completion */ | 70 | /* I/O parameters */ |
71 | struct list_head list, /* nfs_read/write_data structs */ | ||
72 | rewrite_list; /* saved nfs_write_data structs */ | ||
73 | struct nfs_open_context *ctx; /* file open context info */ | ||
74 | struct kiocb * iocb; /* controlling i/o request */ | ||
75 | struct inode * inode; /* target file of i/o */ | ||
76 | unsigned long user_addr; /* location of user's buffer */ | ||
77 | size_t user_count; /* total bytes to move */ | ||
78 | loff_t pos; /* starting offset in file */ | ||
70 | struct page ** pages; /* pages in our buffer */ | 79 | struct page ** pages; /* pages in our buffer */ |
71 | unsigned int npages; /* count of pages */ | 80 | unsigned int npages; /* count of pages */ |
72 | atomic_t complete, /* i/os we're waiting for */ | 81 | |
73 | count, /* bytes actually processed */ | 82 | /* completion state */ |
83 | spinlock_t lock; /* protect completion state */ | ||
84 | int outstanding; /* i/os we're waiting for */ | ||
85 | ssize_t count, /* bytes actually processed */ | ||
74 | error; /* any reported error */ | 86 | error; /* any reported error */ |
87 | struct completion completion; /* wait for i/o completion */ | ||
88 | |||
89 | /* commit state */ | ||
90 | struct nfs_write_data * commit_data; /* special write_data for commits */ | ||
91 | int flags; | ||
92 | #define NFS_ODIRECT_DO_COMMIT (1) /* an unstable reply was received */ | ||
93 | #define NFS_ODIRECT_RESCHED_WRITES (2) /* write verification failed */ | ||
94 | struct nfs_writeverf verf; /* unstable write verifier */ | ||
75 | }; | 95 | }; |
76 | 96 | ||
97 | static void nfs_direct_write_schedule(struct nfs_direct_req *dreq, int sync); | ||
98 | static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode *inode); | ||
77 | 99 | ||
78 | /** | 100 | /** |
79 | * nfs_get_user_pages - find and set up pages underlying user's buffer | 101 | * nfs_direct_IO - NFS address space operation for direct I/O |
80 | * rw: direction (read or write) | 102 | * @rw: direction (read or write) |
81 | * user_addr: starting address of this segment of user's buffer | 103 | * @iocb: target I/O control block |
82 | * count: size of this segment | 104 | * @iov: array of vectors that define I/O buffer |
83 | * @pages: returned array of page struct pointers underlying user's buffer | 105 | * @pos: offset in file to begin the operation |
106 | * @nr_segs: size of iovec array | ||
107 | * | ||
108 | * The presence of this routine in the address space ops vector means | ||
109 | * the NFS client supports direct I/O. However, we shunt off direct | ||
110 | * read and write requests before the VFS gets them, so this method | ||
111 | * should never be called. | ||
84 | */ | 112 | */ |
85 | static inline int | 113 | ssize_t nfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_t pos, unsigned long nr_segs) |
86 | nfs_get_user_pages(int rw, unsigned long user_addr, size_t size, | 114 | { |
87 | struct page ***pages) | 115 | struct dentry *dentry = iocb->ki_filp->f_dentry; |
116 | |||
117 | dprintk("NFS: nfs_direct_IO (%s) off/no(%Ld/%lu) EINVAL\n", | ||
118 | dentry->d_name.name, (long long) pos, nr_segs); | ||
119 | |||
120 | return -EINVAL; | ||
121 | } | ||
122 | |||
123 | static void nfs_free_user_pages(struct page **pages, int npages, int do_dirty) | ||
124 | { | ||
125 | int i; | ||
126 | for (i = 0; i < npages; i++) { | ||
127 | struct page *page = pages[i]; | ||
128 | if (do_dirty && !PageCompound(page)) | ||
129 | set_page_dirty_lock(page); | ||
130 | page_cache_release(page); | ||
131 | } | ||
132 | kfree(pages); | ||
133 | } | ||
134 | |||
135 | static inline int nfs_get_user_pages(int rw, unsigned long user_addr, size_t size, struct page ***pages) | ||
88 | { | 136 | { |
89 | int result = -ENOMEM; | 137 | int result = -ENOMEM; |
90 | unsigned long page_count; | 138 | unsigned long page_count; |
91 | size_t array_size; | 139 | size_t array_size; |
92 | 140 | ||
93 | /* set an arbitrary limit to prevent type overflow */ | ||
94 | /* XXX: this can probably be as large as INT_MAX */ | ||
95 | if (size > MAX_DIRECTIO_SIZE) { | ||
96 | *pages = NULL; | ||
97 | return -EFBIG; | ||
98 | } | ||
99 | |||
100 | page_count = (user_addr + size + PAGE_SIZE - 1) >> PAGE_SHIFT; | 141 | page_count = (user_addr + size + PAGE_SIZE - 1) >> PAGE_SHIFT; |
101 | page_count -= user_addr >> PAGE_SHIFT; | 142 | page_count -= user_addr >> PAGE_SHIFT; |
102 | 143 | ||
@@ -108,75 +149,117 @@ nfs_get_user_pages(int rw, unsigned long user_addr, size_t size, | |||
108 | page_count, (rw == READ), 0, | 149 | page_count, (rw == READ), 0, |
109 | *pages, NULL); | 150 | *pages, NULL); |
110 | up_read(¤t->mm->mmap_sem); | 151 | up_read(¤t->mm->mmap_sem); |
111 | /* | 152 | if (result != page_count) { |
112 | * If we got fewer pages than expected from get_user_pages(), | 153 | /* |
113 | * the user buffer runs off the end of a mapping; return EFAULT. | 154 | * If we got fewer pages than expected from |
114 | */ | 155 | * get_user_pages(), the user buffer runs off the |
115 | if (result >= 0 && result < page_count) { | 156 | * end of a mapping; return EFAULT. |
116 | nfs_free_user_pages(*pages, result, 0); | 157 | */ |
158 | if (result >= 0) { | ||
159 | nfs_free_user_pages(*pages, result, 0); | ||
160 | result = -EFAULT; | ||
161 | } else | ||
162 | kfree(*pages); | ||
117 | *pages = NULL; | 163 | *pages = NULL; |
118 | result = -EFAULT; | ||
119 | } | 164 | } |
120 | } | 165 | } |
121 | return result; | 166 | return result; |
122 | } | 167 | } |
123 | 168 | ||
124 | /** | 169 | static inline struct nfs_direct_req *nfs_direct_req_alloc(void) |
125 | * nfs_free_user_pages - tear down page struct array | ||
126 | * @pages: array of page struct pointers underlying target buffer | ||
127 | * @npages: number of pages in the array | ||
128 | * @do_dirty: dirty the pages as we release them | ||
129 | */ | ||
130 | static void | ||
131 | nfs_free_user_pages(struct page **pages, int npages, int do_dirty) | ||
132 | { | 170 | { |
133 | int i; | 171 | struct nfs_direct_req *dreq; |
134 | for (i = 0; i < npages; i++) { | 172 | |
135 | struct page *page = pages[i]; | 173 | dreq = kmem_cache_alloc(nfs_direct_cachep, SLAB_KERNEL); |
136 | if (do_dirty && !PageCompound(page)) | 174 | if (!dreq) |
137 | set_page_dirty_lock(page); | 175 | return NULL; |
138 | page_cache_release(page); | 176 | |
139 | } | 177 | kref_init(&dreq->kref); |
140 | kfree(pages); | 178 | init_completion(&dreq->completion); |
179 | INIT_LIST_HEAD(&dreq->list); | ||
180 | INIT_LIST_HEAD(&dreq->rewrite_list); | ||
181 | dreq->iocb = NULL; | ||
182 | dreq->ctx = NULL; | ||
183 | spin_lock_init(&dreq->lock); | ||
184 | dreq->outstanding = 0; | ||
185 | dreq->count = 0; | ||
186 | dreq->error = 0; | ||
187 | dreq->flags = 0; | ||
188 | |||
189 | return dreq; | ||
141 | } | 190 | } |
142 | 191 | ||
143 | /** | ||
144 | * nfs_direct_req_release - release nfs_direct_req structure for direct read | ||
145 | * @kref: kref object embedded in an nfs_direct_req structure | ||
146 | * | ||
147 | */ | ||
148 | static void nfs_direct_req_release(struct kref *kref) | 192 | static void nfs_direct_req_release(struct kref *kref) |
149 | { | 193 | { |
150 | struct nfs_direct_req *dreq = container_of(kref, struct nfs_direct_req, kref); | 194 | struct nfs_direct_req *dreq = container_of(kref, struct nfs_direct_req, kref); |
195 | |||
196 | if (dreq->ctx != NULL) | ||
197 | put_nfs_open_context(dreq->ctx); | ||
151 | kmem_cache_free(nfs_direct_cachep, dreq); | 198 | kmem_cache_free(nfs_direct_cachep, dreq); |
152 | } | 199 | } |
153 | 200 | ||
154 | /** | 201 | /* |
155 | * nfs_direct_read_alloc - allocate nfs_read_data structures for direct read | 202 | * Collects and returns the final error value/byte-count. |
156 | * @count: count of bytes for the read request | 203 | */ |
157 | * @rsize: local rsize setting | 204 | static ssize_t nfs_direct_wait(struct nfs_direct_req *dreq) |
205 | { | ||
206 | ssize_t result = -EIOCBQUEUED; | ||
207 | |||
208 | /* Async requests don't wait here */ | ||
209 | if (dreq->iocb) | ||
210 | goto out; | ||
211 | |||
212 | result = wait_for_completion_interruptible(&dreq->completion); | ||
213 | |||
214 | if (!result) | ||
215 | result = dreq->error; | ||
216 | if (!result) | ||
217 | result = dreq->count; | ||
218 | |||
219 | out: | ||
220 | kref_put(&dreq->kref, nfs_direct_req_release); | ||
221 | return (ssize_t) result; | ||
222 | } | ||
223 | |||
224 | /* | ||
225 | * We must hold a reference to all the pages in this direct read request | ||
226 | * until the RPCs complete. This could be long *after* we are woken up in | ||
227 | * nfs_direct_wait (for instance, if someone hits ^C on a slow server). | ||
158 | * | 228 | * |
229 | * In addition, synchronous I/O uses a stack-allocated iocb. Thus we | ||
230 | * can't trust the iocb is still valid here if this is a synchronous | ||
231 | * request. If the waiter is woken prematurely, the iocb is long gone. | ||
232 | */ | ||
233 | static void nfs_direct_complete(struct nfs_direct_req *dreq) | ||
234 | { | ||
235 | nfs_free_user_pages(dreq->pages, dreq->npages, 1); | ||
236 | |||
237 | if (dreq->iocb) { | ||
238 | long res = (long) dreq->error; | ||
239 | if (!res) | ||
240 | res = (long) dreq->count; | ||
241 | aio_complete(dreq->iocb, res, 0); | ||
242 | } | ||
243 | complete_all(&dreq->completion); | ||
244 | |||
245 | kref_put(&dreq->kref, nfs_direct_req_release); | ||
246 | } | ||
247 | |||
248 | /* | ||
159 | * Note we also set the number of requests we have in the dreq when we are | 249 | * Note we also set the number of requests we have in the dreq when we are |
160 | * done. This prevents races with I/O completion so we will always wait | 250 | * done. This prevents races with I/O completion so we will always wait |
161 | * until all requests have been dispatched and completed. | 251 | * until all requests have been dispatched and completed. |
162 | */ | 252 | */ |
163 | static struct nfs_direct_req *nfs_direct_read_alloc(size_t nbytes, unsigned int rsize) | 253 | static struct nfs_direct_req *nfs_direct_read_alloc(size_t nbytes, size_t rsize) |
164 | { | 254 | { |
165 | struct list_head *list; | 255 | struct list_head *list; |
166 | struct nfs_direct_req *dreq; | 256 | struct nfs_direct_req *dreq; |
167 | unsigned int reads = 0; | ||
168 | unsigned int rpages = (rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | 257 | unsigned int rpages = (rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; |
169 | 258 | ||
170 | dreq = kmem_cache_alloc(nfs_direct_cachep, SLAB_KERNEL); | 259 | dreq = nfs_direct_req_alloc(); |
171 | if (!dreq) | 260 | if (!dreq) |
172 | return NULL; | 261 | return NULL; |
173 | 262 | ||
174 | kref_init(&dreq->kref); | ||
175 | init_waitqueue_head(&dreq->wait); | ||
176 | INIT_LIST_HEAD(&dreq->list); | ||
177 | atomic_set(&dreq->count, 0); | ||
178 | atomic_set(&dreq->error, 0); | ||
179 | |||
180 | list = &dreq->list; | 263 | list = &dreq->list; |
181 | for(;;) { | 264 | for(;;) { |
182 | struct nfs_read_data *data = nfs_readdata_alloc(rpages); | 265 | struct nfs_read_data *data = nfs_readdata_alloc(rpages); |
@@ -196,72 +279,70 @@ static struct nfs_direct_req *nfs_direct_read_alloc(size_t nbytes, unsigned int | |||
196 | list_add(&data->pages, list); | 279 | list_add(&data->pages, list); |
197 | 280 | ||
198 | data->req = (struct nfs_page *) dreq; | 281 | data->req = (struct nfs_page *) dreq; |
199 | reads++; | 282 | dreq->outstanding++; |
200 | if (nbytes <= rsize) | 283 | if (nbytes <= rsize) |
201 | break; | 284 | break; |
202 | nbytes -= rsize; | 285 | nbytes -= rsize; |
203 | } | 286 | } |
204 | kref_get(&dreq->kref); | 287 | kref_get(&dreq->kref); |
205 | atomic_set(&dreq->complete, reads); | ||
206 | return dreq; | 288 | return dreq; |
207 | } | 289 | } |
208 | 290 | ||
209 | /** | 291 | static void nfs_direct_read_result(struct rpc_task *task, void *calldata) |
210 | * nfs_direct_read_result - handle a read reply for a direct read request | ||
211 | * @data: address of NFS READ operation control block | ||
212 | * @status: status of this NFS READ operation | ||
213 | * | ||
214 | * We must hold a reference to all the pages in this direct read request | ||
215 | * until the RPCs complete. This could be long *after* we are woken up in | ||
216 | * nfs_direct_read_wait (for instance, if someone hits ^C on a slow server). | ||
217 | */ | ||
218 | static void nfs_direct_read_result(struct nfs_read_data *data, int status) | ||
219 | { | 292 | { |
293 | struct nfs_read_data *data = calldata; | ||
220 | struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; | 294 | struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; |
221 | 295 | ||
222 | if (likely(status >= 0)) | 296 | if (nfs_readpage_result(task, data) != 0) |
223 | atomic_add(data->res.count, &dreq->count); | 297 | return; |
298 | |||
299 | spin_lock(&dreq->lock); | ||
300 | |||
301 | if (likely(task->tk_status >= 0)) | ||
302 | dreq->count += data->res.count; | ||
224 | else | 303 | else |
225 | atomic_set(&dreq->error, status); | 304 | dreq->error = task->tk_status; |
226 | 305 | ||
227 | if (unlikely(atomic_dec_and_test(&dreq->complete))) { | 306 | if (--dreq->outstanding) { |
228 | nfs_free_user_pages(dreq->pages, dreq->npages, 1); | 307 | spin_unlock(&dreq->lock); |
229 | wake_up(&dreq->wait); | 308 | return; |
230 | kref_put(&dreq->kref, nfs_direct_req_release); | ||
231 | } | 309 | } |
310 | |||
311 | spin_unlock(&dreq->lock); | ||
312 | nfs_direct_complete(dreq); | ||
232 | } | 313 | } |
233 | 314 | ||
234 | /** | 315 | static const struct rpc_call_ops nfs_read_direct_ops = { |
235 | * nfs_direct_read_schedule - dispatch NFS READ operations for a direct read | 316 | .rpc_call_done = nfs_direct_read_result, |
236 | * @dreq: address of nfs_direct_req struct for this request | 317 | .rpc_release = nfs_readdata_release, |
237 | * @inode: target inode | 318 | }; |
238 | * @ctx: target file open context | 319 | |
239 | * @user_addr: starting address of this segment of user's buffer | 320 | /* |
240 | * @count: size of this segment | ||
241 | * @file_offset: offset in file to begin the operation | ||
242 | * | ||
243 | * For each nfs_read_data struct that was allocated on the list, dispatch | 321 | * For each nfs_read_data struct that was allocated on the list, dispatch |
244 | * an NFS READ operation | 322 | * an NFS READ operation |
245 | */ | 323 | */ |
246 | static void nfs_direct_read_schedule(struct nfs_direct_req *dreq, | 324 | static void nfs_direct_read_schedule(struct nfs_direct_req *dreq) |
247 | struct inode *inode, struct nfs_open_context *ctx, | ||
248 | unsigned long user_addr, size_t count, loff_t file_offset) | ||
249 | { | 325 | { |
326 | struct nfs_open_context *ctx = dreq->ctx; | ||
327 | struct inode *inode = ctx->dentry->d_inode; | ||
250 | struct list_head *list = &dreq->list; | 328 | struct list_head *list = &dreq->list; |
251 | struct page **pages = dreq->pages; | 329 | struct page **pages = dreq->pages; |
330 | size_t count = dreq->user_count; | ||
331 | loff_t pos = dreq->pos; | ||
332 | size_t rsize = NFS_SERVER(inode)->rsize; | ||
252 | unsigned int curpage, pgbase; | 333 | unsigned int curpage, pgbase; |
253 | unsigned int rsize = NFS_SERVER(inode)->rsize; | ||
254 | 334 | ||
255 | curpage = 0; | 335 | curpage = 0; |
256 | pgbase = user_addr & ~PAGE_MASK; | 336 | pgbase = dreq->user_addr & ~PAGE_MASK; |
257 | do { | 337 | do { |
258 | struct nfs_read_data *data; | 338 | struct nfs_read_data *data; |
259 | unsigned int bytes; | 339 | size_t bytes; |
260 | 340 | ||
261 | bytes = rsize; | 341 | bytes = rsize; |
262 | if (count < rsize) | 342 | if (count < rsize) |
263 | bytes = count; | 343 | bytes = count; |
264 | 344 | ||
345 | BUG_ON(list_empty(list)); | ||
265 | data = list_entry(list->next, struct nfs_read_data, pages); | 346 | data = list_entry(list->next, struct nfs_read_data, pages); |
266 | list_del_init(&data->pages); | 347 | list_del_init(&data->pages); |
267 | 348 | ||
@@ -269,7 +350,7 @@ static void nfs_direct_read_schedule(struct nfs_direct_req *dreq, | |||
269 | data->cred = ctx->cred; | 350 | data->cred = ctx->cred; |
270 | data->args.fh = NFS_FH(inode); | 351 | data->args.fh = NFS_FH(inode); |
271 | data->args.context = ctx; | 352 | data->args.context = ctx; |
272 | data->args.offset = file_offset; | 353 | data->args.offset = pos; |
273 | data->args.pgbase = pgbase; | 354 | data->args.pgbase = pgbase; |
274 | data->args.pages = &pages[curpage]; | 355 | data->args.pages = &pages[curpage]; |
275 | data->args.count = bytes; | 356 | data->args.count = bytes; |
@@ -277,77 +358,38 @@ static void nfs_direct_read_schedule(struct nfs_direct_req *dreq, | |||
277 | data->res.eof = 0; | 358 | data->res.eof = 0; |
278 | data->res.count = bytes; | 359 | data->res.count = bytes; |
279 | 360 | ||
361 | rpc_init_task(&data->task, NFS_CLIENT(inode), RPC_TASK_ASYNC, | ||
362 | &nfs_read_direct_ops, data); | ||
280 | NFS_PROTO(inode)->read_setup(data); | 363 | NFS_PROTO(inode)->read_setup(data); |
281 | 364 | ||
282 | data->task.tk_cookie = (unsigned long) inode; | 365 | data->task.tk_cookie = (unsigned long) inode; |
283 | data->complete = nfs_direct_read_result; | ||
284 | 366 | ||
285 | lock_kernel(); | 367 | lock_kernel(); |
286 | rpc_execute(&data->task); | 368 | rpc_execute(&data->task); |
287 | unlock_kernel(); | 369 | unlock_kernel(); |
288 | 370 | ||
289 | dfprintk(VFS, "NFS: %4d initiated direct read call (req %s/%Ld, %u bytes @ offset %Lu)\n", | 371 | dfprintk(VFS, "NFS: %5u initiated direct read call (req %s/%Ld, %zu bytes @ offset %Lu)\n", |
290 | data->task.tk_pid, | 372 | data->task.tk_pid, |
291 | inode->i_sb->s_id, | 373 | inode->i_sb->s_id, |
292 | (long long)NFS_FILEID(inode), | 374 | (long long)NFS_FILEID(inode), |
293 | bytes, | 375 | bytes, |
294 | (unsigned long long)data->args.offset); | 376 | (unsigned long long)data->args.offset); |
295 | 377 | ||
296 | file_offset += bytes; | 378 | pos += bytes; |
297 | pgbase += bytes; | 379 | pgbase += bytes; |
298 | curpage += pgbase >> PAGE_SHIFT; | 380 | curpage += pgbase >> PAGE_SHIFT; |
299 | pgbase &= ~PAGE_MASK; | 381 | pgbase &= ~PAGE_MASK; |
300 | 382 | ||
301 | count -= bytes; | 383 | count -= bytes; |
302 | } while (count != 0); | 384 | } while (count != 0); |
385 | BUG_ON(!list_empty(list)); | ||
303 | } | 386 | } |
304 | 387 | ||
305 | /** | 388 | static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size_t count, loff_t pos, struct page **pages, unsigned int nr_pages) |
306 | * nfs_direct_read_wait - wait for I/O completion for direct reads | ||
307 | * @dreq: request on which we are to wait | ||
308 | * @intr: whether or not this wait can be interrupted | ||
309 | * | ||
310 | * Collects and returns the final error value/byte-count. | ||
311 | */ | ||
312 | static ssize_t nfs_direct_read_wait(struct nfs_direct_req *dreq, int intr) | ||
313 | { | ||
314 | int result = 0; | ||
315 | |||
316 | if (intr) { | ||
317 | result = wait_event_interruptible(dreq->wait, | ||
318 | (atomic_read(&dreq->complete) == 0)); | ||
319 | } else { | ||
320 | wait_event(dreq->wait, (atomic_read(&dreq->complete) == 0)); | ||
321 | } | ||
322 | |||
323 | if (!result) | ||
324 | result = atomic_read(&dreq->error); | ||
325 | if (!result) | ||
326 | result = atomic_read(&dreq->count); | ||
327 | |||
328 | kref_put(&dreq->kref, nfs_direct_req_release); | ||
329 | return (ssize_t) result; | ||
330 | } | ||
331 | |||
332 | /** | ||
333 | * nfs_direct_read_seg - Read in one iov segment. Generate separate | ||
334 | * read RPCs for each "rsize" bytes. | ||
335 | * @inode: target inode | ||
336 | * @ctx: target file open context | ||
337 | * @user_addr: starting address of this segment of user's buffer | ||
338 | * @count: size of this segment | ||
339 | * @file_offset: offset in file to begin the operation | ||
340 | * @pages: array of addresses of page structs defining user's buffer | ||
341 | * @nr_pages: number of pages in the array | ||
342 | * | ||
343 | */ | ||
344 | static ssize_t nfs_direct_read_seg(struct inode *inode, | ||
345 | struct nfs_open_context *ctx, unsigned long user_addr, | ||
346 | size_t count, loff_t file_offset, struct page **pages, | ||
347 | unsigned int nr_pages) | ||
348 | { | 389 | { |
349 | ssize_t result; | 390 | ssize_t result; |
350 | sigset_t oldset; | 391 | sigset_t oldset; |
392 | struct inode *inode = iocb->ki_filp->f_mapping->host; | ||
351 | struct rpc_clnt *clnt = NFS_CLIENT(inode); | 393 | struct rpc_clnt *clnt = NFS_CLIENT(inode); |
352 | struct nfs_direct_req *dreq; | 394 | struct nfs_direct_req *dreq; |
353 | 395 | ||
@@ -355,284 +397,350 @@ static ssize_t nfs_direct_read_seg(struct inode *inode, | |||
355 | if (!dreq) | 397 | if (!dreq) |
356 | return -ENOMEM; | 398 | return -ENOMEM; |
357 | 399 | ||
400 | dreq->user_addr = user_addr; | ||
401 | dreq->user_count = count; | ||
402 | dreq->pos = pos; | ||
358 | dreq->pages = pages; | 403 | dreq->pages = pages; |
359 | dreq->npages = nr_pages; | 404 | dreq->npages = nr_pages; |
405 | dreq->inode = inode; | ||
406 | dreq->ctx = get_nfs_open_context((struct nfs_open_context *)iocb->ki_filp->private_data); | ||
407 | if (!is_sync_kiocb(iocb)) | ||
408 | dreq->iocb = iocb; | ||
360 | 409 | ||
410 | nfs_add_stats(inode, NFSIOS_DIRECTREADBYTES, count); | ||
361 | rpc_clnt_sigmask(clnt, &oldset); | 411 | rpc_clnt_sigmask(clnt, &oldset); |
362 | nfs_direct_read_schedule(dreq, inode, ctx, user_addr, count, | 412 | nfs_direct_read_schedule(dreq); |
363 | file_offset); | 413 | result = nfs_direct_wait(dreq); |
364 | result = nfs_direct_read_wait(dreq, clnt->cl_intr); | ||
365 | rpc_clnt_sigunmask(clnt, &oldset); | 414 | rpc_clnt_sigunmask(clnt, &oldset); |
366 | 415 | ||
367 | return result; | 416 | return result; |
368 | } | 417 | } |
369 | 418 | ||
370 | /** | 419 | static void nfs_direct_free_writedata(struct nfs_direct_req *dreq) |
371 | * nfs_direct_read - For each iov segment, map the user's buffer | ||
372 | * then generate read RPCs. | ||
373 | * @inode: target inode | ||
374 | * @ctx: target file open context | ||
375 | * @iov: array of vectors that define I/O buffer | ||
376 | * file_offset: offset in file to begin the operation | ||
377 | * nr_segs: size of iovec array | ||
378 | * | ||
379 | * We've already pushed out any non-direct writes so that this read | ||
380 | * will see them when we read from the server. | ||
381 | */ | ||
382 | static ssize_t | ||
383 | nfs_direct_read(struct inode *inode, struct nfs_open_context *ctx, | ||
384 | const struct iovec *iov, loff_t file_offset, | ||
385 | unsigned long nr_segs) | ||
386 | { | 420 | { |
387 | ssize_t tot_bytes = 0; | 421 | list_splice_init(&dreq->rewrite_list, &dreq->list); |
388 | unsigned long seg = 0; | 422 | while (!list_empty(&dreq->list)) { |
389 | 423 | struct nfs_write_data *data = list_entry(dreq->list.next, struct nfs_write_data, pages); | |
390 | while ((seg < nr_segs) && (tot_bytes >= 0)) { | 424 | list_del(&data->pages); |
391 | ssize_t result; | 425 | nfs_writedata_release(data); |
392 | int page_count; | 426 | } |
393 | struct page **pages; | 427 | } |
394 | const struct iovec *vec = &iov[seg++]; | ||
395 | unsigned long user_addr = (unsigned long) vec->iov_base; | ||
396 | size_t size = vec->iov_len; | ||
397 | |||
398 | page_count = nfs_get_user_pages(READ, user_addr, size, &pages); | ||
399 | if (page_count < 0) { | ||
400 | nfs_free_user_pages(pages, 0, 0); | ||
401 | if (tot_bytes > 0) | ||
402 | break; | ||
403 | return page_count; | ||
404 | } | ||
405 | 428 | ||
406 | result = nfs_direct_read_seg(inode, ctx, user_addr, size, | 429 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
407 | file_offset, pages, page_count); | 430 | static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) |
431 | { | ||
432 | struct list_head *pos; | ||
408 | 433 | ||
409 | if (result <= 0) { | 434 | list_splice_init(&dreq->rewrite_list, &dreq->list); |
410 | if (tot_bytes > 0) | 435 | list_for_each(pos, &dreq->list) |
411 | break; | 436 | dreq->outstanding++; |
412 | return result; | 437 | dreq->count = 0; |
413 | } | 438 | |
414 | tot_bytes += result; | 439 | nfs_direct_write_schedule(dreq, FLUSH_STABLE); |
415 | file_offset += result; | 440 | } |
416 | if (result < size) | 441 | |
417 | break; | 442 | static void nfs_direct_commit_result(struct rpc_task *task, void *calldata) |
443 | { | ||
444 | struct nfs_write_data *data = calldata; | ||
445 | struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; | ||
446 | |||
447 | /* Call the NFS version-specific code */ | ||
448 | if (NFS_PROTO(data->inode)->commit_done(task, data) != 0) | ||
449 | return; | ||
450 | if (unlikely(task->tk_status < 0)) { | ||
451 | dreq->error = task->tk_status; | ||
452 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; | ||
453 | } | ||
454 | if (memcmp(&dreq->verf, &data->verf, sizeof(data->verf))) { | ||
455 | dprintk("NFS: %5u commit verify failed\n", task->tk_pid); | ||
456 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; | ||
418 | } | 457 | } |
419 | 458 | ||
420 | return tot_bytes; | 459 | dprintk("NFS: %5u commit returned %d\n", task->tk_pid, task->tk_status); |
460 | nfs_direct_write_complete(dreq, data->inode); | ||
421 | } | 461 | } |
422 | 462 | ||
423 | /** | 463 | static const struct rpc_call_ops nfs_commit_direct_ops = { |
424 | * nfs_direct_write_seg - Write out one iov segment. Generate separate | 464 | .rpc_call_done = nfs_direct_commit_result, |
425 | * write RPCs for each "wsize" bytes, then commit. | 465 | .rpc_release = nfs_commit_release, |
426 | * @inode: target inode | 466 | }; |
427 | * @ctx: target file open context | 467 | |
428 | * user_addr: starting address of this segment of user's buffer | 468 | static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) |
429 | * count: size of this segment | ||
430 | * file_offset: offset in file to begin the operation | ||
431 | * @pages: array of addresses of page structs defining user's buffer | ||
432 | * nr_pages: size of pages array | ||
433 | */ | ||
434 | static ssize_t nfs_direct_write_seg(struct inode *inode, | ||
435 | struct nfs_open_context *ctx, unsigned long user_addr, | ||
436 | size_t count, loff_t file_offset, struct page **pages, | ||
437 | int nr_pages) | ||
438 | { | 469 | { |
439 | const unsigned int wsize = NFS_SERVER(inode)->wsize; | 470 | struct nfs_write_data *data = dreq->commit_data; |
440 | size_t request; | 471 | struct rpc_task *task = &data->task; |
441 | int curpage, need_commit; | ||
442 | ssize_t result, tot_bytes; | ||
443 | struct nfs_writeverf first_verf; | ||
444 | struct nfs_write_data *wdata; | ||
445 | |||
446 | wdata = nfs_writedata_alloc(NFS_SERVER(inode)->wpages); | ||
447 | if (!wdata) | ||
448 | return -ENOMEM; | ||
449 | 472 | ||
450 | wdata->inode = inode; | 473 | data->inode = dreq->inode; |
451 | wdata->cred = ctx->cred; | 474 | data->cred = dreq->ctx->cred; |
452 | wdata->args.fh = NFS_FH(inode); | ||
453 | wdata->args.context = ctx; | ||
454 | wdata->args.stable = NFS_UNSTABLE; | ||
455 | if (IS_SYNC(inode) || NFS_PROTO(inode)->version == 2 || count <= wsize) | ||
456 | wdata->args.stable = NFS_FILE_SYNC; | ||
457 | wdata->res.fattr = &wdata->fattr; | ||
458 | wdata->res.verf = &wdata->verf; | ||
459 | 475 | ||
460 | nfs_begin_data_update(inode); | 476 | data->args.fh = NFS_FH(data->inode); |
461 | retry: | 477 | data->args.offset = dreq->pos; |
462 | need_commit = 0; | 478 | data->args.count = dreq->user_count; |
463 | tot_bytes = 0; | 479 | data->res.count = 0; |
464 | curpage = 0; | 480 | data->res.fattr = &data->fattr; |
465 | request = count; | 481 | data->res.verf = &data->verf; |
466 | wdata->args.pgbase = user_addr & ~PAGE_MASK; | ||
467 | wdata->args.offset = file_offset; | ||
468 | do { | ||
469 | wdata->args.count = request; | ||
470 | if (wdata->args.count > wsize) | ||
471 | wdata->args.count = wsize; | ||
472 | wdata->args.pages = &pages[curpage]; | ||
473 | 482 | ||
474 | dprintk("NFS: direct write: c=%u o=%Ld ua=%lu, pb=%u, cp=%u\n", | 483 | rpc_init_task(&data->task, NFS_CLIENT(dreq->inode), RPC_TASK_ASYNC, |
475 | wdata->args.count, (long long) wdata->args.offset, | 484 | &nfs_commit_direct_ops, data); |
476 | user_addr + tot_bytes, wdata->args.pgbase, curpage); | 485 | NFS_PROTO(data->inode)->commit_setup(data, 0); |
477 | 486 | ||
478 | lock_kernel(); | 487 | data->task.tk_priority = RPC_PRIORITY_NORMAL; |
479 | result = NFS_PROTO(inode)->write(wdata); | 488 | data->task.tk_cookie = (unsigned long)data->inode; |
480 | unlock_kernel(); | 489 | /* Note: task.tk_ops->rpc_release will free dreq->commit_data */ |
490 | dreq->commit_data = NULL; | ||
481 | 491 | ||
482 | if (result <= 0) { | 492 | dprintk("NFS: %5u initiated commit call\n", task->tk_pid); |
483 | if (tot_bytes > 0) | ||
484 | break; | ||
485 | goto out; | ||
486 | } | ||
487 | 493 | ||
488 | if (tot_bytes == 0) | 494 | lock_kernel(); |
489 | memcpy(&first_verf.verifier, &wdata->verf.verifier, | 495 | rpc_execute(&data->task); |
490 | sizeof(first_verf.verifier)); | 496 | unlock_kernel(); |
491 | if (wdata->verf.committed != NFS_FILE_SYNC) { | 497 | } |
492 | need_commit = 1; | ||
493 | if (memcmp(&first_verf.verifier, &wdata->verf.verifier, | ||
494 | sizeof(first_verf.verifier))) | ||
495 | goto sync_retry; | ||
496 | } | ||
497 | 498 | ||
498 | tot_bytes += result; | 499 | static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode *inode) |
500 | { | ||
501 | int flags = dreq->flags; | ||
499 | 502 | ||
500 | /* in case of a short write: stop now, let the app recover */ | 503 | dreq->flags = 0; |
501 | if (result < wdata->args.count) | 504 | switch (flags) { |
505 | case NFS_ODIRECT_DO_COMMIT: | ||
506 | nfs_direct_commit_schedule(dreq); | ||
502 | break; | 507 | break; |
508 | case NFS_ODIRECT_RESCHED_WRITES: | ||
509 | nfs_direct_write_reschedule(dreq); | ||
510 | break; | ||
511 | default: | ||
512 | nfs_end_data_update(inode); | ||
513 | if (dreq->commit_data != NULL) | ||
514 | nfs_commit_free(dreq->commit_data); | ||
515 | nfs_direct_free_writedata(dreq); | ||
516 | nfs_direct_complete(dreq); | ||
517 | } | ||
518 | } | ||
503 | 519 | ||
504 | wdata->args.offset += result; | 520 | static void nfs_alloc_commit_data(struct nfs_direct_req *dreq) |
505 | wdata->args.pgbase += result; | 521 | { |
506 | curpage += wdata->args.pgbase >> PAGE_SHIFT; | 522 | dreq->commit_data = nfs_commit_alloc(0); |
507 | wdata->args.pgbase &= ~PAGE_MASK; | 523 | if (dreq->commit_data != NULL) |
508 | request -= result; | 524 | dreq->commit_data->req = (struct nfs_page *) dreq; |
509 | } while (request != 0); | 525 | } |
526 | #else | ||
527 | static inline void nfs_alloc_commit_data(struct nfs_direct_req *dreq) | ||
528 | { | ||
529 | dreq->commit_data = NULL; | ||
530 | } | ||
510 | 531 | ||
511 | /* | 532 | static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode *inode) |
512 | * Commit data written so far, even in the event of an error | 533 | { |
513 | */ | 534 | nfs_end_data_update(inode); |
514 | if (need_commit) { | 535 | nfs_direct_free_writedata(dreq); |
515 | wdata->args.count = tot_bytes; | 536 | nfs_direct_complete(dreq); |
516 | wdata->args.offset = file_offset; | 537 | } |
538 | #endif | ||
517 | 539 | ||
518 | lock_kernel(); | 540 | static struct nfs_direct_req *nfs_direct_write_alloc(size_t nbytes, size_t wsize) |
519 | result = NFS_PROTO(inode)->commit(wdata); | 541 | { |
520 | unlock_kernel(); | 542 | struct list_head *list; |
543 | struct nfs_direct_req *dreq; | ||
544 | unsigned int wpages = (wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | ||
545 | |||
546 | dreq = nfs_direct_req_alloc(); | ||
547 | if (!dreq) | ||
548 | return NULL; | ||
549 | |||
550 | list = &dreq->list; | ||
551 | for(;;) { | ||
552 | struct nfs_write_data *data = nfs_writedata_alloc(wpages); | ||
521 | 553 | ||
522 | if (result < 0 || memcmp(&first_verf.verifier, | 554 | if (unlikely(!data)) { |
523 | &wdata->verf.verifier, | 555 | while (!list_empty(list)) { |
524 | sizeof(first_verf.verifier)) != 0) | 556 | data = list_entry(list->next, |
525 | goto sync_retry; | 557 | struct nfs_write_data, pages); |
558 | list_del(&data->pages); | ||
559 | nfs_writedata_free(data); | ||
560 | } | ||
561 | kref_put(&dreq->kref, nfs_direct_req_release); | ||
562 | return NULL; | ||
563 | } | ||
564 | |||
565 | INIT_LIST_HEAD(&data->pages); | ||
566 | list_add(&data->pages, list); | ||
567 | |||
568 | data->req = (struct nfs_page *) dreq; | ||
569 | dreq->outstanding++; | ||
570 | if (nbytes <= wsize) | ||
571 | break; | ||
572 | nbytes -= wsize; | ||
526 | } | 573 | } |
527 | result = tot_bytes; | ||
528 | 574 | ||
529 | out: | 575 | nfs_alloc_commit_data(dreq); |
530 | nfs_end_data_update(inode); | ||
531 | nfs_writedata_free(wdata); | ||
532 | return result; | ||
533 | 576 | ||
534 | sync_retry: | 577 | kref_get(&dreq->kref); |
535 | wdata->args.stable = NFS_FILE_SYNC; | 578 | return dreq; |
536 | goto retry; | ||
537 | } | 579 | } |
538 | 580 | ||
539 | /** | 581 | static void nfs_direct_write_result(struct rpc_task *task, void *calldata) |
540 | * nfs_direct_write - For each iov segment, map the user's buffer | ||
541 | * then generate write and commit RPCs. | ||
542 | * @inode: target inode | ||
543 | * @ctx: target file open context | ||
544 | * @iov: array of vectors that define I/O buffer | ||
545 | * file_offset: offset in file to begin the operation | ||
546 | * nr_segs: size of iovec array | ||
547 | * | ||
548 | * Upon return, generic_file_direct_IO invalidates any cached pages | ||
549 | * that non-direct readers might access, so they will pick up these | ||
550 | * writes immediately. | ||
551 | */ | ||
552 | static ssize_t nfs_direct_write(struct inode *inode, | ||
553 | struct nfs_open_context *ctx, const struct iovec *iov, | ||
554 | loff_t file_offset, unsigned long nr_segs) | ||
555 | { | 582 | { |
556 | ssize_t tot_bytes = 0; | 583 | struct nfs_write_data *data = calldata; |
557 | unsigned long seg = 0; | 584 | struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; |
558 | 585 | int status = task->tk_status; | |
559 | while ((seg < nr_segs) && (tot_bytes >= 0)) { | 586 | |
560 | ssize_t result; | 587 | if (nfs_writeback_done(task, data) != 0) |
561 | int page_count; | 588 | return; |
562 | struct page **pages; | 589 | |
563 | const struct iovec *vec = &iov[seg++]; | 590 | spin_lock(&dreq->lock); |
564 | unsigned long user_addr = (unsigned long) vec->iov_base; | ||
565 | size_t size = vec->iov_len; | ||
566 | |||
567 | page_count = nfs_get_user_pages(WRITE, user_addr, size, &pages); | ||
568 | if (page_count < 0) { | ||
569 | nfs_free_user_pages(pages, 0, 0); | ||
570 | if (tot_bytes > 0) | ||
571 | break; | ||
572 | return page_count; | ||
573 | } | ||
574 | 591 | ||
575 | result = nfs_direct_write_seg(inode, ctx, user_addr, size, | 592 | if (likely(status >= 0)) |
576 | file_offset, pages, page_count); | 593 | dreq->count += data->res.count; |
577 | nfs_free_user_pages(pages, page_count, 0); | 594 | else |
595 | dreq->error = task->tk_status; | ||
578 | 596 | ||
579 | if (result <= 0) { | 597 | if (data->res.verf->committed != NFS_FILE_SYNC) { |
580 | if (tot_bytes > 0) | 598 | switch (dreq->flags) { |
599 | case 0: | ||
600 | memcpy(&dreq->verf, &data->verf, sizeof(dreq->verf)); | ||
601 | dreq->flags = NFS_ODIRECT_DO_COMMIT; | ||
581 | break; | 602 | break; |
582 | return result; | 603 | case NFS_ODIRECT_DO_COMMIT: |
604 | if (memcmp(&dreq->verf, &data->verf, sizeof(dreq->verf))) { | ||
605 | dprintk("NFS: %5u write verify failed\n", task->tk_pid); | ||
606 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; | ||
607 | } | ||
583 | } | 608 | } |
584 | tot_bytes += result; | ||
585 | file_offset += result; | ||
586 | if (result < size) | ||
587 | break; | ||
588 | } | 609 | } |
589 | return tot_bytes; | 610 | /* In case we have to resend */ |
611 | data->args.stable = NFS_FILE_SYNC; | ||
612 | |||
613 | spin_unlock(&dreq->lock); | ||
590 | } | 614 | } |
591 | 615 | ||
592 | /** | 616 | /* |
593 | * nfs_direct_IO - NFS address space operation for direct I/O | 617 | * NB: Return the value of the first error return code. Subsequent |
594 | * rw: direction (read or write) | 618 | * errors after the first one are ignored. |
595 | * @iocb: target I/O control block | ||
596 | * @iov: array of vectors that define I/O buffer | ||
597 | * file_offset: offset in file to begin the operation | ||
598 | * nr_segs: size of iovec array | ||
599 | * | ||
600 | */ | 619 | */ |
601 | ssize_t | 620 | static void nfs_direct_write_release(void *calldata) |
602 | nfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, | ||
603 | loff_t file_offset, unsigned long nr_segs) | ||
604 | { | 621 | { |
605 | ssize_t result = -EINVAL; | 622 | struct nfs_write_data *data = calldata; |
606 | struct file *file = iocb->ki_filp; | 623 | struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; |
607 | struct nfs_open_context *ctx; | ||
608 | struct dentry *dentry = file->f_dentry; | ||
609 | struct inode *inode = dentry->d_inode; | ||
610 | 624 | ||
611 | /* | 625 | spin_lock(&dreq->lock); |
612 | * No support for async yet | 626 | if (--dreq->outstanding) { |
613 | */ | 627 | spin_unlock(&dreq->lock); |
614 | if (!is_sync_kiocb(iocb)) | 628 | return; |
615 | return result; | ||
616 | |||
617 | ctx = (struct nfs_open_context *)file->private_data; | ||
618 | switch (rw) { | ||
619 | case READ: | ||
620 | dprintk("NFS: direct_IO(read) (%s) off/no(%Lu/%lu)\n", | ||
621 | dentry->d_name.name, file_offset, nr_segs); | ||
622 | |||
623 | result = nfs_direct_read(inode, ctx, iov, | ||
624 | file_offset, nr_segs); | ||
625 | break; | ||
626 | case WRITE: | ||
627 | dprintk("NFS: direct_IO(write) (%s) off/no(%Lu/%lu)\n", | ||
628 | dentry->d_name.name, file_offset, nr_segs); | ||
629 | |||
630 | result = nfs_direct_write(inode, ctx, iov, | ||
631 | file_offset, nr_segs); | ||
632 | break; | ||
633 | default: | ||
634 | break; | ||
635 | } | 629 | } |
630 | spin_unlock(&dreq->lock); | ||
631 | |||
632 | nfs_direct_write_complete(dreq, data->inode); | ||
633 | } | ||
634 | |||
635 | static const struct rpc_call_ops nfs_write_direct_ops = { | ||
636 | .rpc_call_done = nfs_direct_write_result, | ||
637 | .rpc_release = nfs_direct_write_release, | ||
638 | }; | ||
639 | |||
640 | /* | ||
641 | * For each nfs_write_data struct that was allocated on the list, dispatch | ||
642 | * an NFS WRITE operation | ||
643 | */ | ||
644 | static void nfs_direct_write_schedule(struct nfs_direct_req *dreq, int sync) | ||
645 | { | ||
646 | struct nfs_open_context *ctx = dreq->ctx; | ||
647 | struct inode *inode = ctx->dentry->d_inode; | ||
648 | struct list_head *list = &dreq->list; | ||
649 | struct page **pages = dreq->pages; | ||
650 | size_t count = dreq->user_count; | ||
651 | loff_t pos = dreq->pos; | ||
652 | size_t wsize = NFS_SERVER(inode)->wsize; | ||
653 | unsigned int curpage, pgbase; | ||
654 | |||
655 | curpage = 0; | ||
656 | pgbase = dreq->user_addr & ~PAGE_MASK; | ||
657 | do { | ||
658 | struct nfs_write_data *data; | ||
659 | size_t bytes; | ||
660 | |||
661 | bytes = wsize; | ||
662 | if (count < wsize) | ||
663 | bytes = count; | ||
664 | |||
665 | BUG_ON(list_empty(list)); | ||
666 | data = list_entry(list->next, struct nfs_write_data, pages); | ||
667 | list_move_tail(&data->pages, &dreq->rewrite_list); | ||
668 | |||
669 | data->inode = inode; | ||
670 | data->cred = ctx->cred; | ||
671 | data->args.fh = NFS_FH(inode); | ||
672 | data->args.context = ctx; | ||
673 | data->args.offset = pos; | ||
674 | data->args.pgbase = pgbase; | ||
675 | data->args.pages = &pages[curpage]; | ||
676 | data->args.count = bytes; | ||
677 | data->res.fattr = &data->fattr; | ||
678 | data->res.count = bytes; | ||
679 | data->res.verf = &data->verf; | ||
680 | |||
681 | rpc_init_task(&data->task, NFS_CLIENT(inode), RPC_TASK_ASYNC, | ||
682 | &nfs_write_direct_ops, data); | ||
683 | NFS_PROTO(inode)->write_setup(data, sync); | ||
684 | |||
685 | data->task.tk_priority = RPC_PRIORITY_NORMAL; | ||
686 | data->task.tk_cookie = (unsigned long) inode; | ||
687 | |||
688 | lock_kernel(); | ||
689 | rpc_execute(&data->task); | ||
690 | unlock_kernel(); | ||
691 | |||
692 | dfprintk(VFS, "NFS: %5u initiated direct write call (req %s/%Ld, %zu bytes @ offset %Lu)\n", | ||
693 | data->task.tk_pid, | ||
694 | inode->i_sb->s_id, | ||
695 | (long long)NFS_FILEID(inode), | ||
696 | bytes, | ||
697 | (unsigned long long)data->args.offset); | ||
698 | |||
699 | pos += bytes; | ||
700 | pgbase += bytes; | ||
701 | curpage += pgbase >> PAGE_SHIFT; | ||
702 | pgbase &= ~PAGE_MASK; | ||
703 | |||
704 | count -= bytes; | ||
705 | } while (count != 0); | ||
706 | BUG_ON(!list_empty(list)); | ||
707 | } | ||
708 | |||
709 | static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, size_t count, loff_t pos, struct page **pages, int nr_pages) | ||
710 | { | ||
711 | ssize_t result; | ||
712 | sigset_t oldset; | ||
713 | struct inode *inode = iocb->ki_filp->f_mapping->host; | ||
714 | struct rpc_clnt *clnt = NFS_CLIENT(inode); | ||
715 | struct nfs_direct_req *dreq; | ||
716 | size_t wsize = NFS_SERVER(inode)->wsize; | ||
717 | int sync = 0; | ||
718 | |||
719 | dreq = nfs_direct_write_alloc(count, wsize); | ||
720 | if (!dreq) | ||
721 | return -ENOMEM; | ||
722 | if (dreq->commit_data == NULL || count < wsize) | ||
723 | sync = FLUSH_STABLE; | ||
724 | |||
725 | dreq->user_addr = user_addr; | ||
726 | dreq->user_count = count; | ||
727 | dreq->pos = pos; | ||
728 | dreq->pages = pages; | ||
729 | dreq->npages = nr_pages; | ||
730 | dreq->inode = inode; | ||
731 | dreq->ctx = get_nfs_open_context((struct nfs_open_context *)iocb->ki_filp->private_data); | ||
732 | if (!is_sync_kiocb(iocb)) | ||
733 | dreq->iocb = iocb; | ||
734 | |||
735 | nfs_add_stats(inode, NFSIOS_DIRECTWRITTENBYTES, count); | ||
736 | |||
737 | nfs_begin_data_update(inode); | ||
738 | |||
739 | rpc_clnt_sigmask(clnt, &oldset); | ||
740 | nfs_direct_write_schedule(dreq, sync); | ||
741 | result = nfs_direct_wait(dreq); | ||
742 | rpc_clnt_sigunmask(clnt, &oldset); | ||
743 | |||
636 | return result; | 744 | return result; |
637 | } | 745 | } |
638 | 746 | ||
@@ -640,49 +748,40 @@ nfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, | |||
640 | * nfs_file_direct_read - file direct read operation for NFS files | 748 | * nfs_file_direct_read - file direct read operation for NFS files |
641 | * @iocb: target I/O control block | 749 | * @iocb: target I/O control block |
642 | * @buf: user's buffer into which to read data | 750 | * @buf: user's buffer into which to read data |
643 | * count: number of bytes to read | 751 | * @count: number of bytes to read |
644 | * pos: byte offset in file where reading starts | 752 | * @pos: byte offset in file where reading starts |
645 | * | 753 | * |
646 | * We use this function for direct reads instead of calling | 754 | * We use this function for direct reads instead of calling |
647 | * generic_file_aio_read() in order to avoid gfar's check to see if | 755 | * generic_file_aio_read() in order to avoid gfar's check to see if |
648 | * the request starts before the end of the file. For that check | 756 | * the request starts before the end of the file. For that check |
649 | * to work, we must generate a GETATTR before each direct read, and | 757 | * to work, we must generate a GETATTR before each direct read, and |
650 | * even then there is a window between the GETATTR and the subsequent | 758 | * even then there is a window between the GETATTR and the subsequent |
651 | * READ where the file size could change. So our preference is simply | 759 | * READ where the file size could change. Our preference is simply |
652 | * to do all reads the application wants, and the server will take | 760 | * to do all reads the application wants, and the server will take |
653 | * care of managing the end of file boundary. | 761 | * care of managing the end of file boundary. |
654 | * | 762 | * |
655 | * This function also eliminates unnecessarily updating the file's | 763 | * This function also eliminates unnecessarily updating the file's |
656 | * atime locally, as the NFS server sets the file's atime, and this | 764 | * atime locally, as the NFS server sets the file's atime, and this |
657 | * client must read the updated atime from the server back into its | 765 | * client must read the updated atime from the server back into its |
658 | * cache. | 766 | * cache. |
659 | */ | 767 | */ |
660 | ssize_t | 768 | ssize_t nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t pos) |
661 | nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t pos) | ||
662 | { | 769 | { |
663 | ssize_t retval = -EINVAL; | 770 | ssize_t retval = -EINVAL; |
664 | loff_t *ppos = &iocb->ki_pos; | 771 | int page_count; |
772 | struct page **pages; | ||
665 | struct file *file = iocb->ki_filp; | 773 | struct file *file = iocb->ki_filp; |
666 | struct nfs_open_context *ctx = | ||
667 | (struct nfs_open_context *) file->private_data; | ||
668 | struct address_space *mapping = file->f_mapping; | 774 | struct address_space *mapping = file->f_mapping; |
669 | struct inode *inode = mapping->host; | ||
670 | struct iovec iov = { | ||
671 | .iov_base = buf, | ||
672 | .iov_len = count, | ||
673 | }; | ||
674 | 775 | ||
675 | dprintk("nfs: direct read(%s/%s, %lu@%Ld)\n", | 776 | dprintk("nfs: direct read(%s/%s, %lu@%Ld)\n", |
676 | file->f_dentry->d_parent->d_name.name, | 777 | file->f_dentry->d_parent->d_name.name, |
677 | file->f_dentry->d_name.name, | 778 | file->f_dentry->d_name.name, |
678 | (unsigned long) count, (long long) pos); | 779 | (unsigned long) count, (long long) pos); |
679 | 780 | ||
680 | if (!is_sync_kiocb(iocb)) | ||
681 | goto out; | ||
682 | if (count < 0) | 781 | if (count < 0) |
683 | goto out; | 782 | goto out; |
684 | retval = -EFAULT; | 783 | retval = -EFAULT; |
685 | if (!access_ok(VERIFY_WRITE, iov.iov_base, iov.iov_len)) | 784 | if (!access_ok(VERIFY_WRITE, buf, count)) |
686 | goto out; | 785 | goto out; |
687 | retval = 0; | 786 | retval = 0; |
688 | if (!count) | 787 | if (!count) |
@@ -692,9 +791,16 @@ nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t | |||
692 | if (retval) | 791 | if (retval) |
693 | goto out; | 792 | goto out; |
694 | 793 | ||
695 | retval = nfs_direct_read(inode, ctx, &iov, pos, 1); | 794 | retval = nfs_get_user_pages(READ, (unsigned long) buf, |
795 | count, &pages); | ||
796 | if (retval < 0) | ||
797 | goto out; | ||
798 | page_count = retval; | ||
799 | |||
800 | retval = nfs_direct_read(iocb, (unsigned long) buf, count, pos, | ||
801 | pages, page_count); | ||
696 | if (retval > 0) | 802 | if (retval > 0) |
697 | *ppos = pos + retval; | 803 | iocb->ki_pos = pos + retval; |
698 | 804 | ||
699 | out: | 805 | out: |
700 | return retval; | 806 | return retval; |
@@ -704,8 +810,8 @@ out: | |||
704 | * nfs_file_direct_write - file direct write operation for NFS files | 810 | * nfs_file_direct_write - file direct write operation for NFS files |
705 | * @iocb: target I/O control block | 811 | * @iocb: target I/O control block |
706 | * @buf: user's buffer from which to write data | 812 | * @buf: user's buffer from which to write data |
707 | * count: number of bytes to write | 813 | * @count: number of bytes to write |
708 | * pos: byte offset in file where writing starts | 814 | * @pos: byte offset in file where writing starts |
709 | * | 815 | * |
710 | * We use this function for direct writes instead of calling | 816 | * We use this function for direct writes instead of calling |
711 | * generic_file_aio_write() in order to avoid taking the inode | 817 | * generic_file_aio_write() in order to avoid taking the inode |
@@ -725,28 +831,19 @@ out: | |||
725 | * Note that O_APPEND is not supported for NFS direct writes, as there | 831 | * Note that O_APPEND is not supported for NFS direct writes, as there |
726 | * is no atomic O_APPEND write facility in the NFS protocol. | 832 | * is no atomic O_APPEND write facility in the NFS protocol. |
727 | */ | 833 | */ |
728 | ssize_t | 834 | ssize_t nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos) |
729 | nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos) | ||
730 | { | 835 | { |
731 | ssize_t retval; | 836 | ssize_t retval; |
837 | int page_count; | ||
838 | struct page **pages; | ||
732 | struct file *file = iocb->ki_filp; | 839 | struct file *file = iocb->ki_filp; |
733 | struct nfs_open_context *ctx = | ||
734 | (struct nfs_open_context *) file->private_data; | ||
735 | struct address_space *mapping = file->f_mapping; | 840 | struct address_space *mapping = file->f_mapping; |
736 | struct inode *inode = mapping->host; | ||
737 | struct iovec iov = { | ||
738 | .iov_base = (char __user *)buf, | ||
739 | }; | ||
740 | 841 | ||
741 | dfprintk(VFS, "nfs: direct write(%s/%s, %lu@%Ld)\n", | 842 | dfprintk(VFS, "nfs: direct write(%s/%s, %lu@%Ld)\n", |
742 | file->f_dentry->d_parent->d_name.name, | 843 | file->f_dentry->d_parent->d_name.name, |
743 | file->f_dentry->d_name.name, | 844 | file->f_dentry->d_name.name, |
744 | (unsigned long) count, (long long) pos); | 845 | (unsigned long) count, (long long) pos); |
745 | 846 | ||
746 | retval = -EINVAL; | ||
747 | if (!is_sync_kiocb(iocb)) | ||
748 | goto out; | ||
749 | |||
750 | retval = generic_write_checks(file, &pos, &count, 0); | 847 | retval = generic_write_checks(file, &pos, &count, 0); |
751 | if (retval) | 848 | if (retval) |
752 | goto out; | 849 | goto out; |
@@ -757,19 +854,35 @@ nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, | |||
757 | retval = 0; | 854 | retval = 0; |
758 | if (!count) | 855 | if (!count) |
759 | goto out; | 856 | goto out; |
760 | iov.iov_len = count, | ||
761 | 857 | ||
762 | retval = -EFAULT; | 858 | retval = -EFAULT; |
763 | if (!access_ok(VERIFY_READ, iov.iov_base, iov.iov_len)) | 859 | if (!access_ok(VERIFY_READ, buf, count)) |
764 | goto out; | 860 | goto out; |
765 | 861 | ||
766 | retval = nfs_sync_mapping(mapping); | 862 | retval = nfs_sync_mapping(mapping); |
767 | if (retval) | 863 | if (retval) |
768 | goto out; | 864 | goto out; |
769 | 865 | ||
770 | retval = nfs_direct_write(inode, ctx, &iov, pos, 1); | 866 | retval = nfs_get_user_pages(WRITE, (unsigned long) buf, |
867 | count, &pages); | ||
868 | if (retval < 0) | ||
869 | goto out; | ||
870 | page_count = retval; | ||
871 | |||
872 | retval = nfs_direct_write(iocb, (unsigned long) buf, count, | ||
873 | pos, pages, page_count); | ||
874 | |||
875 | /* | ||
876 | * XXX: nfs_end_data_update() already ensures this file's | ||
877 | * cached data is subsequently invalidated. Do we really | ||
878 | * need to call invalidate_inode_pages2() again here? | ||
879 | * | ||
880 | * For aio writes, this invalidation will almost certainly | ||
881 | * occur before the writes complete. Kind of racey. | ||
882 | */ | ||
771 | if (mapping->nrpages) | 883 | if (mapping->nrpages) |
772 | invalidate_inode_pages2(mapping); | 884 | invalidate_inode_pages2(mapping); |
885 | |||
773 | if (retval > 0) | 886 | if (retval > 0) |
774 | iocb->ki_pos = pos + retval; | 887 | iocb->ki_pos = pos + retval; |
775 | 888 | ||
@@ -777,6 +890,10 @@ out: | |||
777 | return retval; | 890 | return retval; |
778 | } | 891 | } |
779 | 892 | ||
893 | /** | ||
894 | * nfs_init_directcache - create a slab cache for nfs_direct_req structures | ||
895 | * | ||
896 | */ | ||
780 | int nfs_init_directcache(void) | 897 | int nfs_init_directcache(void) |
781 | { | 898 | { |
782 | nfs_direct_cachep = kmem_cache_create("nfs_direct_cache", | 899 | nfs_direct_cachep = kmem_cache_create("nfs_direct_cache", |
@@ -790,6 +907,10 @@ int nfs_init_directcache(void) | |||
790 | return 0; | 907 | return 0; |
791 | } | 908 | } |
792 | 909 | ||
910 | /** | ||
911 | * nfs_init_directcache - destroy the slab cache for nfs_direct_req structures | ||
912 | * | ||
913 | */ | ||
793 | void nfs_destroy_directcache(void) | 914 | void nfs_destroy_directcache(void) |
794 | { | 915 | { |
795 | if (kmem_cache_destroy(nfs_direct_cachep)) | 916 | if (kmem_cache_destroy(nfs_direct_cachep)) |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 7a79fbe9f539..5263b2864a44 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <asm/system.h> | 32 | #include <asm/system.h> |
33 | 33 | ||
34 | #include "delegation.h" | 34 | #include "delegation.h" |
35 | #include "iostat.h" | ||
35 | 36 | ||
36 | #define NFSDBG_FACILITY NFSDBG_FILE | 37 | #define NFSDBG_FACILITY NFSDBG_FILE |
37 | 38 | ||
@@ -102,18 +103,15 @@ static int nfs_check_flags(int flags) | |||
102 | static int | 103 | static int |
103 | nfs_file_open(struct inode *inode, struct file *filp) | 104 | nfs_file_open(struct inode *inode, struct file *filp) |
104 | { | 105 | { |
105 | struct nfs_server *server = NFS_SERVER(inode); | ||
106 | int (*open)(struct inode *, struct file *); | ||
107 | int res; | 106 | int res; |
108 | 107 | ||
109 | res = nfs_check_flags(filp->f_flags); | 108 | res = nfs_check_flags(filp->f_flags); |
110 | if (res) | 109 | if (res) |
111 | return res; | 110 | return res; |
112 | 111 | ||
112 | nfs_inc_stats(inode, NFSIOS_VFSOPEN); | ||
113 | lock_kernel(); | 113 | lock_kernel(); |
114 | /* Do NFSv4 open() call */ | 114 | res = NFS_SERVER(inode)->rpc_ops->file_open(inode, filp); |
115 | if ((open = server->rpc_ops->file_open) != NULL) | ||
116 | res = open(inode, filp); | ||
117 | unlock_kernel(); | 115 | unlock_kernel(); |
118 | return res; | 116 | return res; |
119 | } | 117 | } |
@@ -124,6 +122,7 @@ nfs_file_release(struct inode *inode, struct file *filp) | |||
124 | /* Ensure that dirty pages are flushed out with the right creds */ | 122 | /* Ensure that dirty pages are flushed out with the right creds */ |
125 | if (filp->f_mode & FMODE_WRITE) | 123 | if (filp->f_mode & FMODE_WRITE) |
126 | filemap_fdatawrite(filp->f_mapping); | 124 | filemap_fdatawrite(filp->f_mapping); |
125 | nfs_inc_stats(inode, NFSIOS_VFSRELEASE); | ||
127 | return NFS_PROTO(inode)->file_release(inode, filp); | 126 | return NFS_PROTO(inode)->file_release(inode, filp); |
128 | } | 127 | } |
129 | 128 | ||
@@ -199,6 +198,7 @@ nfs_file_flush(struct file *file) | |||
199 | 198 | ||
200 | if ((file->f_mode & FMODE_WRITE) == 0) | 199 | if ((file->f_mode & FMODE_WRITE) == 0) |
201 | return 0; | 200 | return 0; |
201 | nfs_inc_stats(inode, NFSIOS_VFSFLUSH); | ||
202 | lock_kernel(); | 202 | lock_kernel(); |
203 | /* Ensure that data+attribute caches are up to date after close() */ | 203 | /* Ensure that data+attribute caches are up to date after close() */ |
204 | status = nfs_wb_all(inode); | 204 | status = nfs_wb_all(inode); |
@@ -229,6 +229,7 @@ nfs_file_read(struct kiocb *iocb, char __user * buf, size_t count, loff_t pos) | |||
229 | (unsigned long) count, (unsigned long) pos); | 229 | (unsigned long) count, (unsigned long) pos); |
230 | 230 | ||
231 | result = nfs_revalidate_file(inode, iocb->ki_filp); | 231 | result = nfs_revalidate_file(inode, iocb->ki_filp); |
232 | nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, count); | ||
232 | if (!result) | 233 | if (!result) |
233 | result = generic_file_aio_read(iocb, buf, count, pos); | 234 | result = generic_file_aio_read(iocb, buf, count, pos); |
234 | return result; | 235 | return result; |
@@ -282,6 +283,7 @@ nfs_fsync(struct file *file, struct dentry *dentry, int datasync) | |||
282 | 283 | ||
283 | dfprintk(VFS, "nfs: fsync(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino); | 284 | dfprintk(VFS, "nfs: fsync(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino); |
284 | 285 | ||
286 | nfs_inc_stats(inode, NFSIOS_VFSFSYNC); | ||
285 | lock_kernel(); | 287 | lock_kernel(); |
286 | status = nfs_wb_all(inode); | 288 | status = nfs_wb_all(inode); |
287 | if (!status) { | 289 | if (!status) { |
@@ -316,6 +318,17 @@ static int nfs_commit_write(struct file *file, struct page *page, unsigned offse | |||
316 | return status; | 318 | return status; |
317 | } | 319 | } |
318 | 320 | ||
321 | static int nfs_invalidate_page(struct page *page, unsigned long offset) | ||
322 | { | ||
323 | /* FIXME: we really should cancel any unstarted writes on this page */ | ||
324 | return 1; | ||
325 | } | ||
326 | |||
327 | static int nfs_release_page(struct page *page, gfp_t gfp) | ||
328 | { | ||
329 | return !nfs_wb_page(page->mapping->host, page); | ||
330 | } | ||
331 | |||
319 | struct address_space_operations nfs_file_aops = { | 332 | struct address_space_operations nfs_file_aops = { |
320 | .readpage = nfs_readpage, | 333 | .readpage = nfs_readpage, |
321 | .readpages = nfs_readpages, | 334 | .readpages = nfs_readpages, |
@@ -324,6 +337,8 @@ struct address_space_operations nfs_file_aops = { | |||
324 | .writepages = nfs_writepages, | 337 | .writepages = nfs_writepages, |
325 | .prepare_write = nfs_prepare_write, | 338 | .prepare_write = nfs_prepare_write, |
326 | .commit_write = nfs_commit_write, | 339 | .commit_write = nfs_commit_write, |
340 | .invalidatepage = nfs_invalidate_page, | ||
341 | .releasepage = nfs_release_page, | ||
327 | #ifdef CONFIG_NFS_DIRECTIO | 342 | #ifdef CONFIG_NFS_DIRECTIO |
328 | .direct_IO = nfs_direct_IO, | 343 | .direct_IO = nfs_direct_IO, |
329 | #endif | 344 | #endif |
@@ -365,6 +380,7 @@ nfs_file_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t | |||
365 | if (!count) | 380 | if (!count) |
366 | goto out; | 381 | goto out; |
367 | 382 | ||
383 | nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, count); | ||
368 | result = generic_file_aio_write(iocb, buf, count, pos); | 384 | result = generic_file_aio_write(iocb, buf, count, pos); |
369 | out: | 385 | out: |
370 | return result; | 386 | return result; |
@@ -376,15 +392,17 @@ out_swapfile: | |||
376 | 392 | ||
377 | static int do_getlk(struct file *filp, int cmd, struct file_lock *fl) | 393 | static int do_getlk(struct file *filp, int cmd, struct file_lock *fl) |
378 | { | 394 | { |
379 | struct file_lock *cfl; | 395 | struct file_lock cfl; |
380 | struct inode *inode = filp->f_mapping->host; | 396 | struct inode *inode = filp->f_mapping->host; |
381 | int status = 0; | 397 | int status = 0; |
382 | 398 | ||
383 | lock_kernel(); | 399 | lock_kernel(); |
384 | /* Try local locking first */ | 400 | /* Try local locking first */ |
385 | cfl = posix_test_lock(filp, fl); | 401 | if (posix_test_lock(filp, fl, &cfl)) { |
386 | if (cfl != NULL) { | 402 | fl->fl_start = cfl.fl_start; |
387 | locks_copy_lock(fl, cfl); | 403 | fl->fl_end = cfl.fl_end; |
404 | fl->fl_type = cfl.fl_type; | ||
405 | fl->fl_pid = cfl.fl_pid; | ||
388 | goto out; | 406 | goto out; |
389 | } | 407 | } |
390 | 408 | ||
@@ -425,10 +443,8 @@ static int do_vfs_lock(struct file *file, struct file_lock *fl) | |||
425 | static int do_unlk(struct file *filp, int cmd, struct file_lock *fl) | 443 | static int do_unlk(struct file *filp, int cmd, struct file_lock *fl) |
426 | { | 444 | { |
427 | struct inode *inode = filp->f_mapping->host; | 445 | struct inode *inode = filp->f_mapping->host; |
428 | sigset_t oldset; | ||
429 | int status; | 446 | int status; |
430 | 447 | ||
431 | rpc_clnt_sigmask(NFS_CLIENT(inode), &oldset); | ||
432 | /* | 448 | /* |
433 | * Flush all pending writes before doing anything | 449 | * Flush all pending writes before doing anything |
434 | * with locks.. | 450 | * with locks.. |
@@ -446,17 +462,14 @@ static int do_unlk(struct file *filp, int cmd, struct file_lock *fl) | |||
446 | else | 462 | else |
447 | status = do_vfs_lock(filp, fl); | 463 | status = do_vfs_lock(filp, fl); |
448 | unlock_kernel(); | 464 | unlock_kernel(); |
449 | rpc_clnt_sigunmask(NFS_CLIENT(inode), &oldset); | ||
450 | return status; | 465 | return status; |
451 | } | 466 | } |
452 | 467 | ||
453 | static int do_setlk(struct file *filp, int cmd, struct file_lock *fl) | 468 | static int do_setlk(struct file *filp, int cmd, struct file_lock *fl) |
454 | { | 469 | { |
455 | struct inode *inode = filp->f_mapping->host; | 470 | struct inode *inode = filp->f_mapping->host; |
456 | sigset_t oldset; | ||
457 | int status; | 471 | int status; |
458 | 472 | ||
459 | rpc_clnt_sigmask(NFS_CLIENT(inode), &oldset); | ||
460 | /* | 473 | /* |
461 | * Flush all pending writes before doing anything | 474 | * Flush all pending writes before doing anything |
462 | * with locks.. | 475 | * with locks.. |
@@ -489,7 +502,6 @@ static int do_setlk(struct file *filp, int cmd, struct file_lock *fl) | |||
489 | nfs_sync_mapping(filp->f_mapping); | 502 | nfs_sync_mapping(filp->f_mapping); |
490 | nfs_zap_caches(inode); | 503 | nfs_zap_caches(inode); |
491 | out: | 504 | out: |
492 | rpc_clnt_sigunmask(NFS_CLIENT(inode), &oldset); | ||
493 | return status; | 505 | return status; |
494 | } | 506 | } |
495 | 507 | ||
@@ -504,9 +516,7 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl) | |||
504 | inode->i_sb->s_id, inode->i_ino, | 516 | inode->i_sb->s_id, inode->i_ino, |
505 | fl->fl_type, fl->fl_flags, | 517 | fl->fl_type, fl->fl_flags, |
506 | (long long)fl->fl_start, (long long)fl->fl_end); | 518 | (long long)fl->fl_start, (long long)fl->fl_end); |
507 | 519 | nfs_inc_stats(inode, NFSIOS_VFSLOCK); | |
508 | if (!inode) | ||
509 | return -EINVAL; | ||
510 | 520 | ||
511 | /* No mandatory locks over NFS */ | 521 | /* No mandatory locks over NFS */ |
512 | if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID && | 522 | if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID && |
@@ -531,9 +541,6 @@ static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl) | |||
531 | inode->i_sb->s_id, inode->i_ino, | 541 | inode->i_sb->s_id, inode->i_ino, |
532 | fl->fl_type, fl->fl_flags); | 542 | fl->fl_type, fl->fl_flags); |
533 | 543 | ||
534 | if (!inode) | ||
535 | return -EINVAL; | ||
536 | |||
537 | /* | 544 | /* |
538 | * No BSD flocks over NFS allowed. | 545 | * No BSD flocks over NFS allowed. |
539 | * Note: we could try to fake a POSIX lock request here by | 546 | * Note: we could try to fake a POSIX lock request here by |
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index 821edd30333b..3fab5b0cfc5a 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c | |||
@@ -35,6 +35,7 @@ | |||
35 | */ | 35 | */ |
36 | 36 | ||
37 | #include <linux/module.h> | 37 | #include <linux/module.h> |
38 | #include <linux/mutex.h> | ||
38 | #include <linux/init.h> | 39 | #include <linux/init.h> |
39 | #include <linux/types.h> | 40 | #include <linux/types.h> |
40 | #include <linux/slab.h> | 41 | #include <linux/slab.h> |
@@ -74,8 +75,8 @@ struct idmap { | |||
74 | struct dentry *idmap_dentry; | 75 | struct dentry *idmap_dentry; |
75 | wait_queue_head_t idmap_wq; | 76 | wait_queue_head_t idmap_wq; |
76 | struct idmap_msg idmap_im; | 77 | struct idmap_msg idmap_im; |
77 | struct semaphore idmap_lock; /* Serializes upcalls */ | 78 | struct mutex idmap_lock; /* Serializes upcalls */ |
78 | struct semaphore idmap_im_lock; /* Protects the hashtable */ | 79 | struct mutex idmap_im_lock; /* Protects the hashtable */ |
79 | struct idmap_hashtable idmap_user_hash; | 80 | struct idmap_hashtable idmap_user_hash; |
80 | struct idmap_hashtable idmap_group_hash; | 81 | struct idmap_hashtable idmap_group_hash; |
81 | }; | 82 | }; |
@@ -101,11 +102,9 @@ nfs_idmap_new(struct nfs4_client *clp) | |||
101 | 102 | ||
102 | if (clp->cl_idmap != NULL) | 103 | if (clp->cl_idmap != NULL) |
103 | return; | 104 | return; |
104 | if ((idmap = kmalloc(sizeof(*idmap), GFP_KERNEL)) == NULL) | 105 | if ((idmap = kzalloc(sizeof(*idmap), GFP_KERNEL)) == NULL) |
105 | return; | 106 | return; |
106 | 107 | ||
107 | memset(idmap, 0, sizeof(*idmap)); | ||
108 | |||
109 | snprintf(idmap->idmap_path, sizeof(idmap->idmap_path), | 108 | snprintf(idmap->idmap_path, sizeof(idmap->idmap_path), |
110 | "%s/idmap", clp->cl_rpcclient->cl_pathname); | 109 | "%s/idmap", clp->cl_rpcclient->cl_pathname); |
111 | 110 | ||
@@ -116,8 +115,8 @@ nfs_idmap_new(struct nfs4_client *clp) | |||
116 | return; | 115 | return; |
117 | } | 116 | } |
118 | 117 | ||
119 | init_MUTEX(&idmap->idmap_lock); | 118 | mutex_init(&idmap->idmap_lock); |
120 | init_MUTEX(&idmap->idmap_im_lock); | 119 | mutex_init(&idmap->idmap_im_lock); |
121 | init_waitqueue_head(&idmap->idmap_wq); | 120 | init_waitqueue_head(&idmap->idmap_wq); |
122 | idmap->idmap_user_hash.h_type = IDMAP_TYPE_USER; | 121 | idmap->idmap_user_hash.h_type = IDMAP_TYPE_USER; |
123 | idmap->idmap_group_hash.h_type = IDMAP_TYPE_GROUP; | 122 | idmap->idmap_group_hash.h_type = IDMAP_TYPE_GROUP; |
@@ -132,6 +131,8 @@ nfs_idmap_delete(struct nfs4_client *clp) | |||
132 | 131 | ||
133 | if (!idmap) | 132 | if (!idmap) |
134 | return; | 133 | return; |
134 | dput(idmap->idmap_dentry); | ||
135 | idmap->idmap_dentry = NULL; | ||
135 | rpc_unlink(idmap->idmap_path); | 136 | rpc_unlink(idmap->idmap_path); |
136 | clp->cl_idmap = NULL; | 137 | clp->cl_idmap = NULL; |
137 | kfree(idmap); | 138 | kfree(idmap); |
@@ -232,8 +233,8 @@ nfs_idmap_id(struct idmap *idmap, struct idmap_hashtable *h, | |||
232 | if (namelen >= IDMAP_NAMESZ) | 233 | if (namelen >= IDMAP_NAMESZ) |
233 | return -EINVAL; | 234 | return -EINVAL; |
234 | 235 | ||
235 | down(&idmap->idmap_lock); | 236 | mutex_lock(&idmap->idmap_lock); |
236 | down(&idmap->idmap_im_lock); | 237 | mutex_lock(&idmap->idmap_im_lock); |
237 | 238 | ||
238 | he = idmap_lookup_name(h, name, namelen); | 239 | he = idmap_lookup_name(h, name, namelen); |
239 | if (he != NULL) { | 240 | if (he != NULL) { |
@@ -259,11 +260,11 @@ nfs_idmap_id(struct idmap *idmap, struct idmap_hashtable *h, | |||
259 | } | 260 | } |
260 | 261 | ||
261 | set_current_state(TASK_UNINTERRUPTIBLE); | 262 | set_current_state(TASK_UNINTERRUPTIBLE); |
262 | up(&idmap->idmap_im_lock); | 263 | mutex_unlock(&idmap->idmap_im_lock); |
263 | schedule(); | 264 | schedule(); |
264 | current->state = TASK_RUNNING; | 265 | current->state = TASK_RUNNING; |
265 | remove_wait_queue(&idmap->idmap_wq, &wq); | 266 | remove_wait_queue(&idmap->idmap_wq, &wq); |
266 | down(&idmap->idmap_im_lock); | 267 | mutex_lock(&idmap->idmap_im_lock); |
267 | 268 | ||
268 | if (im->im_status & IDMAP_STATUS_SUCCESS) { | 269 | if (im->im_status & IDMAP_STATUS_SUCCESS) { |
269 | *id = im->im_id; | 270 | *id = im->im_id; |
@@ -272,8 +273,8 @@ nfs_idmap_id(struct idmap *idmap, struct idmap_hashtable *h, | |||
272 | 273 | ||
273 | out: | 274 | out: |
274 | memset(im, 0, sizeof(*im)); | 275 | memset(im, 0, sizeof(*im)); |
275 | up(&idmap->idmap_im_lock); | 276 | mutex_unlock(&idmap->idmap_im_lock); |
276 | up(&idmap->idmap_lock); | 277 | mutex_unlock(&idmap->idmap_lock); |
277 | return (ret); | 278 | return (ret); |
278 | } | 279 | } |
279 | 280 | ||
@@ -293,8 +294,8 @@ nfs_idmap_name(struct idmap *idmap, struct idmap_hashtable *h, | |||
293 | 294 | ||
294 | im = &idmap->idmap_im; | 295 | im = &idmap->idmap_im; |
295 | 296 | ||
296 | down(&idmap->idmap_lock); | 297 | mutex_lock(&idmap->idmap_lock); |
297 | down(&idmap->idmap_im_lock); | 298 | mutex_lock(&idmap->idmap_im_lock); |
298 | 299 | ||
299 | he = idmap_lookup_id(h, id); | 300 | he = idmap_lookup_id(h, id); |
300 | if (he != 0) { | 301 | if (he != 0) { |
@@ -320,11 +321,11 @@ nfs_idmap_name(struct idmap *idmap, struct idmap_hashtable *h, | |||
320 | } | 321 | } |
321 | 322 | ||
322 | set_current_state(TASK_UNINTERRUPTIBLE); | 323 | set_current_state(TASK_UNINTERRUPTIBLE); |
323 | up(&idmap->idmap_im_lock); | 324 | mutex_unlock(&idmap->idmap_im_lock); |
324 | schedule(); | 325 | schedule(); |
325 | current->state = TASK_RUNNING; | 326 | current->state = TASK_RUNNING; |
326 | remove_wait_queue(&idmap->idmap_wq, &wq); | 327 | remove_wait_queue(&idmap->idmap_wq, &wq); |
327 | down(&idmap->idmap_im_lock); | 328 | mutex_lock(&idmap->idmap_im_lock); |
328 | 329 | ||
329 | if (im->im_status & IDMAP_STATUS_SUCCESS) { | 330 | if (im->im_status & IDMAP_STATUS_SUCCESS) { |
330 | if ((len = strnlen(im->im_name, IDMAP_NAMESZ)) == 0) | 331 | if ((len = strnlen(im->im_name, IDMAP_NAMESZ)) == 0) |
@@ -335,8 +336,8 @@ nfs_idmap_name(struct idmap *idmap, struct idmap_hashtable *h, | |||
335 | 336 | ||
336 | out: | 337 | out: |
337 | memset(im, 0, sizeof(*im)); | 338 | memset(im, 0, sizeof(*im)); |
338 | up(&idmap->idmap_im_lock); | 339 | mutex_unlock(&idmap->idmap_im_lock); |
339 | up(&idmap->idmap_lock); | 340 | mutex_unlock(&idmap->idmap_lock); |
340 | return ret; | 341 | return ret; |
341 | } | 342 | } |
342 | 343 | ||
@@ -380,7 +381,7 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) | |||
380 | if (copy_from_user(&im_in, src, mlen) != 0) | 381 | if (copy_from_user(&im_in, src, mlen) != 0) |
381 | return (-EFAULT); | 382 | return (-EFAULT); |
382 | 383 | ||
383 | down(&idmap->idmap_im_lock); | 384 | mutex_lock(&idmap->idmap_im_lock); |
384 | 385 | ||
385 | ret = mlen; | 386 | ret = mlen; |
386 | im->im_status = im_in.im_status; | 387 | im->im_status = im_in.im_status; |
@@ -440,7 +441,7 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) | |||
440 | idmap_update_entry(he, im_in.im_name, namelen_in, im_in.im_id); | 441 | idmap_update_entry(he, im_in.im_name, namelen_in, im_in.im_id); |
441 | ret = mlen; | 442 | ret = mlen; |
442 | out: | 443 | out: |
443 | up(&idmap->idmap_im_lock); | 444 | mutex_unlock(&idmap->idmap_im_lock); |
444 | return ret; | 445 | return ret; |
445 | } | 446 | } |
446 | 447 | ||
@@ -452,10 +453,10 @@ idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg) | |||
452 | 453 | ||
453 | if (msg->errno >= 0) | 454 | if (msg->errno >= 0) |
454 | return; | 455 | return; |
455 | down(&idmap->idmap_im_lock); | 456 | mutex_lock(&idmap->idmap_im_lock); |
456 | im->im_status = IDMAP_STATUS_LOOKUPFAIL; | 457 | im->im_status = IDMAP_STATUS_LOOKUPFAIL; |
457 | wake_up(&idmap->idmap_wq); | 458 | wake_up(&idmap->idmap_wq); |
458 | up(&idmap->idmap_im_lock); | 459 | mutex_unlock(&idmap->idmap_im_lock); |
459 | } | 460 | } |
460 | 461 | ||
461 | /* | 462 | /* |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 3413996f9a86..2f7656b911b6 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/unistd.h> | 26 | #include <linux/unistd.h> |
27 | #include <linux/sunrpc/clnt.h> | 27 | #include <linux/sunrpc/clnt.h> |
28 | #include <linux/sunrpc/stats.h> | 28 | #include <linux/sunrpc/stats.h> |
29 | #include <linux/sunrpc/metrics.h> | ||
29 | #include <linux/nfs_fs.h> | 30 | #include <linux/nfs_fs.h> |
30 | #include <linux/nfs_mount.h> | 31 | #include <linux/nfs_mount.h> |
31 | #include <linux/nfs4_mount.h> | 32 | #include <linux/nfs4_mount.h> |
@@ -42,6 +43,7 @@ | |||
42 | #include "nfs4_fs.h" | 43 | #include "nfs4_fs.h" |
43 | #include "callback.h" | 44 | #include "callback.h" |
44 | #include "delegation.h" | 45 | #include "delegation.h" |
46 | #include "iostat.h" | ||
45 | 47 | ||
46 | #define NFSDBG_FACILITY NFSDBG_VFS | 48 | #define NFSDBG_FACILITY NFSDBG_VFS |
47 | #define NFS_PARANOIA 1 | 49 | #define NFS_PARANOIA 1 |
@@ -65,6 +67,7 @@ static void nfs_clear_inode(struct inode *); | |||
65 | static void nfs_umount_begin(struct super_block *); | 67 | static void nfs_umount_begin(struct super_block *); |
66 | static int nfs_statfs(struct super_block *, struct kstatfs *); | 68 | static int nfs_statfs(struct super_block *, struct kstatfs *); |
67 | static int nfs_show_options(struct seq_file *, struct vfsmount *); | 69 | static int nfs_show_options(struct seq_file *, struct vfsmount *); |
70 | static int nfs_show_stats(struct seq_file *, struct vfsmount *); | ||
68 | static void nfs_zap_acl_cache(struct inode *); | 71 | static void nfs_zap_acl_cache(struct inode *); |
69 | 72 | ||
70 | static struct rpc_program nfs_program; | 73 | static struct rpc_program nfs_program; |
@@ -78,6 +81,7 @@ static struct super_operations nfs_sops = { | |||
78 | .clear_inode = nfs_clear_inode, | 81 | .clear_inode = nfs_clear_inode, |
79 | .umount_begin = nfs_umount_begin, | 82 | .umount_begin = nfs_umount_begin, |
80 | .show_options = nfs_show_options, | 83 | .show_options = nfs_show_options, |
84 | .show_stats = nfs_show_stats, | ||
81 | }; | 85 | }; |
82 | 86 | ||
83 | /* | 87 | /* |
@@ -133,7 +137,7 @@ nfs_fattr_to_ino_t(struct nfs_fattr *fattr) | |||
133 | static int | 137 | static int |
134 | nfs_write_inode(struct inode *inode, int sync) | 138 | nfs_write_inode(struct inode *inode, int sync) |
135 | { | 139 | { |
136 | int flags = sync ? FLUSH_WAIT : 0; | 140 | int flags = sync ? FLUSH_SYNC : 0; |
137 | int ret; | 141 | int ret; |
138 | 142 | ||
139 | ret = nfs_commit_inode(inode, flags); | 143 | ret = nfs_commit_inode(inode, flags); |
@@ -237,7 +241,6 @@ static struct inode * | |||
237 | nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh, struct nfs_fsinfo *fsinfo) | 241 | nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh, struct nfs_fsinfo *fsinfo) |
238 | { | 242 | { |
239 | struct nfs_server *server = NFS_SB(sb); | 243 | struct nfs_server *server = NFS_SB(sb); |
240 | struct inode *rooti; | ||
241 | int error; | 244 | int error; |
242 | 245 | ||
243 | error = server->rpc_ops->getroot(server, rootfh, fsinfo); | 246 | error = server->rpc_ops->getroot(server, rootfh, fsinfo); |
@@ -246,10 +249,7 @@ nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh, struct nfs_fsinfo *f | |||
246 | return ERR_PTR(error); | 249 | return ERR_PTR(error); |
247 | } | 250 | } |
248 | 251 | ||
249 | rooti = nfs_fhget(sb, rootfh, fsinfo->fattr); | 252 | return nfs_fhget(sb, rootfh, fsinfo->fattr); |
250 | if (!rooti) | ||
251 | return ERR_PTR(-ENOMEM); | ||
252 | return rooti; | ||
253 | } | 253 | } |
254 | 254 | ||
255 | /* | 255 | /* |
@@ -277,6 +277,10 @@ nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor) | |||
277 | 277 | ||
278 | sb->s_magic = NFS_SUPER_MAGIC; | 278 | sb->s_magic = NFS_SUPER_MAGIC; |
279 | 279 | ||
280 | server->io_stats = nfs_alloc_iostats(); | ||
281 | if (server->io_stats == NULL) | ||
282 | return -ENOMEM; | ||
283 | |||
280 | root_inode = nfs_get_root(sb, &server->fh, &fsinfo); | 284 | root_inode = nfs_get_root(sb, &server->fh, &fsinfo); |
281 | /* Did getting the root inode fail? */ | 285 | /* Did getting the root inode fail? */ |
282 | if (IS_ERR(root_inode)) { | 286 | if (IS_ERR(root_inode)) { |
@@ -290,6 +294,9 @@ nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor) | |||
290 | } | 294 | } |
291 | sb->s_root->d_op = server->rpc_ops->dentry_ops; | 295 | sb->s_root->d_op = server->rpc_ops->dentry_ops; |
292 | 296 | ||
297 | /* mount time stamp, in seconds */ | ||
298 | server->mount_time = jiffies; | ||
299 | |||
293 | /* Get some general file system info */ | 300 | /* Get some general file system info */ |
294 | if (server->namelen == 0 && | 301 | if (server->namelen == 0 && |
295 | server->rpc_ops->pathconf(server, &server->fh, &pathinfo) >= 0) | 302 | server->rpc_ops->pathconf(server, &server->fh, &pathinfo) >= 0) |
@@ -396,6 +403,9 @@ nfs_create_client(struct nfs_server *server, const struct nfs_mount_data *data) | |||
396 | 403 | ||
397 | nfs_init_timeout_values(&timeparms, proto, data->timeo, data->retrans); | 404 | nfs_init_timeout_values(&timeparms, proto, data->timeo, data->retrans); |
398 | 405 | ||
406 | server->retrans_timeo = timeparms.to_initval; | ||
407 | server->retrans_count = timeparms.to_retries; | ||
408 | |||
399 | /* create transport and client */ | 409 | /* create transport and client */ |
400 | xprt = xprt_create_proto(proto, &server->addr, &timeparms); | 410 | xprt = xprt_create_proto(proto, &server->addr, &timeparms); |
401 | if (IS_ERR(xprt)) { | 411 | if (IS_ERR(xprt)) { |
@@ -579,7 +589,7 @@ nfs_statfs(struct super_block *sb, struct kstatfs *buf) | |||
579 | 589 | ||
580 | } | 590 | } |
581 | 591 | ||
582 | static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt) | 592 | static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, int showdefaults) |
583 | { | 593 | { |
584 | static struct proc_nfs_info { | 594 | static struct proc_nfs_info { |
585 | int flag; | 595 | int flag; |
@@ -588,28 +598,26 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt) | |||
588 | } nfs_info[] = { | 598 | } nfs_info[] = { |
589 | { NFS_MOUNT_SOFT, ",soft", ",hard" }, | 599 | { NFS_MOUNT_SOFT, ",soft", ",hard" }, |
590 | { NFS_MOUNT_INTR, ",intr", "" }, | 600 | { NFS_MOUNT_INTR, ",intr", "" }, |
591 | { NFS_MOUNT_POSIX, ",posix", "" }, | ||
592 | { NFS_MOUNT_NOCTO, ",nocto", "" }, | 601 | { NFS_MOUNT_NOCTO, ",nocto", "" }, |
593 | { NFS_MOUNT_NOAC, ",noac", "" }, | 602 | { NFS_MOUNT_NOAC, ",noac", "" }, |
594 | { NFS_MOUNT_NONLM, ",nolock", ",lock" }, | 603 | { NFS_MOUNT_NONLM, ",nolock", "" }, |
595 | { NFS_MOUNT_NOACL, ",noacl", "" }, | 604 | { NFS_MOUNT_NOACL, ",noacl", "" }, |
596 | { 0, NULL, NULL } | 605 | { 0, NULL, NULL } |
597 | }; | 606 | }; |
598 | struct proc_nfs_info *nfs_infop; | 607 | struct proc_nfs_info *nfs_infop; |
599 | struct nfs_server *nfss = NFS_SB(mnt->mnt_sb); | ||
600 | char buf[12]; | 608 | char buf[12]; |
601 | char *proto; | 609 | char *proto; |
602 | 610 | ||
603 | seq_printf(m, ",v%d", nfss->rpc_ops->version); | 611 | seq_printf(m, ",vers=%d", nfss->rpc_ops->version); |
604 | seq_printf(m, ",rsize=%d", nfss->rsize); | 612 | seq_printf(m, ",rsize=%d", nfss->rsize); |
605 | seq_printf(m, ",wsize=%d", nfss->wsize); | 613 | seq_printf(m, ",wsize=%d", nfss->wsize); |
606 | if (nfss->acregmin != 3*HZ) | 614 | if (nfss->acregmin != 3*HZ || showdefaults) |
607 | seq_printf(m, ",acregmin=%d", nfss->acregmin/HZ); | 615 | seq_printf(m, ",acregmin=%d", nfss->acregmin/HZ); |
608 | if (nfss->acregmax != 60*HZ) | 616 | if (nfss->acregmax != 60*HZ || showdefaults) |
609 | seq_printf(m, ",acregmax=%d", nfss->acregmax/HZ); | 617 | seq_printf(m, ",acregmax=%d", nfss->acregmax/HZ); |
610 | if (nfss->acdirmin != 30*HZ) | 618 | if (nfss->acdirmin != 30*HZ || showdefaults) |
611 | seq_printf(m, ",acdirmin=%d", nfss->acdirmin/HZ); | 619 | seq_printf(m, ",acdirmin=%d", nfss->acdirmin/HZ); |
612 | if (nfss->acdirmax != 60*HZ) | 620 | if (nfss->acdirmax != 60*HZ || showdefaults) |
613 | seq_printf(m, ",acdirmax=%d", nfss->acdirmax/HZ); | 621 | seq_printf(m, ",acdirmax=%d", nfss->acdirmax/HZ); |
614 | for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) { | 622 | for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) { |
615 | if (nfss->flags & nfs_infop->flag) | 623 | if (nfss->flags & nfs_infop->flag) |
@@ -629,8 +637,96 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt) | |||
629 | proto = buf; | 637 | proto = buf; |
630 | } | 638 | } |
631 | seq_printf(m, ",proto=%s", proto); | 639 | seq_printf(m, ",proto=%s", proto); |
640 | seq_printf(m, ",timeo=%lu", 10U * nfss->retrans_timeo / HZ); | ||
641 | seq_printf(m, ",retrans=%u", nfss->retrans_count); | ||
642 | } | ||
643 | |||
644 | static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt) | ||
645 | { | ||
646 | struct nfs_server *nfss = NFS_SB(mnt->mnt_sb); | ||
647 | |||
648 | nfs_show_mount_options(m, nfss, 0); | ||
649 | |||
632 | seq_puts(m, ",addr="); | 650 | seq_puts(m, ",addr="); |
633 | seq_escape(m, nfss->hostname, " \t\n\\"); | 651 | seq_escape(m, nfss->hostname, " \t\n\\"); |
652 | |||
653 | return 0; | ||
654 | } | ||
655 | |||
656 | static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt) | ||
657 | { | ||
658 | int i, cpu; | ||
659 | struct nfs_server *nfss = NFS_SB(mnt->mnt_sb); | ||
660 | struct rpc_auth *auth = nfss->client->cl_auth; | ||
661 | struct nfs_iostats totals = { }; | ||
662 | |||
663 | seq_printf(m, "statvers=%s", NFS_IOSTAT_VERS); | ||
664 | |||
665 | /* | ||
666 | * Display all mount option settings | ||
667 | */ | ||
668 | seq_printf(m, "\n\topts:\t"); | ||
669 | seq_puts(m, mnt->mnt_sb->s_flags & MS_RDONLY ? "ro" : "rw"); | ||
670 | seq_puts(m, mnt->mnt_sb->s_flags & MS_SYNCHRONOUS ? ",sync" : ""); | ||
671 | seq_puts(m, mnt->mnt_sb->s_flags & MS_NOATIME ? ",noatime" : ""); | ||
672 | seq_puts(m, mnt->mnt_sb->s_flags & MS_NODIRATIME ? ",nodiratime" : ""); | ||
673 | nfs_show_mount_options(m, nfss, 1); | ||
674 | |||
675 | seq_printf(m, "\n\tage:\t%lu", (jiffies - nfss->mount_time) / HZ); | ||
676 | |||
677 | seq_printf(m, "\n\tcaps:\t"); | ||
678 | seq_printf(m, "caps=0x%x", nfss->caps); | ||
679 | seq_printf(m, ",wtmult=%d", nfss->wtmult); | ||
680 | seq_printf(m, ",dtsize=%d", nfss->dtsize); | ||
681 | seq_printf(m, ",bsize=%d", nfss->bsize); | ||
682 | seq_printf(m, ",namelen=%d", nfss->namelen); | ||
683 | |||
684 | #ifdef CONFIG_NFS_V4 | ||
685 | if (nfss->rpc_ops->version == 4) { | ||
686 | seq_printf(m, "\n\tnfsv4:\t"); | ||
687 | seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]); | ||
688 | seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]); | ||
689 | seq_printf(m, ",acl=0x%x", nfss->acl_bitmask); | ||
690 | } | ||
691 | #endif | ||
692 | |||
693 | /* | ||
694 | * Display security flavor in effect for this mount | ||
695 | */ | ||
696 | seq_printf(m, "\n\tsec:\tflavor=%d", auth->au_ops->au_flavor); | ||
697 | if (auth->au_flavor) | ||
698 | seq_printf(m, ",pseudoflavor=%d", auth->au_flavor); | ||
699 | |||
700 | /* | ||
701 | * Display superblock I/O counters | ||
702 | */ | ||
703 | for (cpu = 0; cpu < NR_CPUS; cpu++) { | ||
704 | struct nfs_iostats *stats; | ||
705 | |||
706 | if (!cpu_possible(cpu)) | ||
707 | continue; | ||
708 | |||
709 | preempt_disable(); | ||
710 | stats = per_cpu_ptr(nfss->io_stats, cpu); | ||
711 | |||
712 | for (i = 0; i < __NFSIOS_COUNTSMAX; i++) | ||
713 | totals.events[i] += stats->events[i]; | ||
714 | for (i = 0; i < __NFSIOS_BYTESMAX; i++) | ||
715 | totals.bytes[i] += stats->bytes[i]; | ||
716 | |||
717 | preempt_enable(); | ||
718 | } | ||
719 | |||
720 | seq_printf(m, "\n\tevents:\t"); | ||
721 | for (i = 0; i < __NFSIOS_COUNTSMAX; i++) | ||
722 | seq_printf(m, "%lu ", totals.events[i]); | ||
723 | seq_printf(m, "\n\tbytes:\t"); | ||
724 | for (i = 0; i < __NFSIOS_BYTESMAX; i++) | ||
725 | seq_printf(m, "%Lu ", totals.bytes[i]); | ||
726 | seq_printf(m, "\n"); | ||
727 | |||
728 | rpc_print_iostats(m, nfss->client); | ||
729 | |||
634 | return 0; | 730 | return 0; |
635 | } | 731 | } |
636 | 732 | ||
@@ -660,6 +756,8 @@ static void nfs_zap_caches_locked(struct inode *inode) | |||
660 | struct nfs_inode *nfsi = NFS_I(inode); | 756 | struct nfs_inode *nfsi = NFS_I(inode); |
661 | int mode = inode->i_mode; | 757 | int mode = inode->i_mode; |
662 | 758 | ||
759 | nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE); | ||
760 | |||
663 | NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode); | 761 | NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode); |
664 | NFS_ATTRTIMEO_UPDATE(inode) = jiffies; | 762 | NFS_ATTRTIMEO_UPDATE(inode) = jiffies; |
665 | 763 | ||
@@ -751,7 +849,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) | |||
751 | .fh = fh, | 849 | .fh = fh, |
752 | .fattr = fattr | 850 | .fattr = fattr |
753 | }; | 851 | }; |
754 | struct inode *inode = NULL; | 852 | struct inode *inode = ERR_PTR(-ENOENT); |
755 | unsigned long hash; | 853 | unsigned long hash; |
756 | 854 | ||
757 | if ((fattr->valid & NFS_ATTR_FATTR) == 0) | 855 | if ((fattr->valid & NFS_ATTR_FATTR) == 0) |
@@ -764,8 +862,11 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) | |||
764 | 862 | ||
765 | hash = nfs_fattr_to_ino_t(fattr); | 863 | hash = nfs_fattr_to_ino_t(fattr); |
766 | 864 | ||
767 | if (!(inode = iget5_locked(sb, hash, nfs_find_actor, nfs_init_locked, &desc))) | 865 | inode = iget5_locked(sb, hash, nfs_find_actor, nfs_init_locked, &desc); |
866 | if (inode == NULL) { | ||
867 | inode = ERR_PTR(-ENOMEM); | ||
768 | goto out_no_inode; | 868 | goto out_no_inode; |
869 | } | ||
769 | 870 | ||
770 | if (inode->i_state & I_NEW) { | 871 | if (inode->i_state & I_NEW) { |
771 | struct nfs_inode *nfsi = NFS_I(inode); | 872 | struct nfs_inode *nfsi = NFS_I(inode); |
@@ -834,7 +935,7 @@ out: | |||
834 | return inode; | 935 | return inode; |
835 | 936 | ||
836 | out_no_inode: | 937 | out_no_inode: |
837 | printk("nfs_fhget: iget failed\n"); | 938 | dprintk("nfs_fhget: iget failed with error %ld\n", PTR_ERR(inode)); |
838 | goto out; | 939 | goto out; |
839 | } | 940 | } |
840 | 941 | ||
@@ -847,6 +948,8 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
847 | struct nfs_fattr fattr; | 948 | struct nfs_fattr fattr; |
848 | int error; | 949 | int error; |
849 | 950 | ||
951 | nfs_inc_stats(inode, NFSIOS_VFSSETATTR); | ||
952 | |||
850 | if (attr->ia_valid & ATTR_SIZE) { | 953 | if (attr->ia_valid & ATTR_SIZE) { |
851 | if (!S_ISREG(inode->i_mode) || attr->ia_size == i_size_read(inode)) | 954 | if (!S_ISREG(inode->i_mode) || attr->ia_size == i_size_read(inode)) |
852 | attr->ia_valid &= ~ATTR_SIZE; | 955 | attr->ia_valid &= ~ATTR_SIZE; |
@@ -859,11 +962,9 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
859 | 962 | ||
860 | lock_kernel(); | 963 | lock_kernel(); |
861 | nfs_begin_data_update(inode); | 964 | nfs_begin_data_update(inode); |
862 | /* Write all dirty data if we're changing file permissions or size */ | 965 | /* Write all dirty data */ |
863 | if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE)) != 0) { | 966 | filemap_write_and_wait(inode->i_mapping); |
864 | filemap_write_and_wait(inode->i_mapping); | 967 | nfs_wb_all(inode); |
865 | nfs_wb_all(inode); | ||
866 | } | ||
867 | /* | 968 | /* |
868 | * Return any delegations if we're going to change ACLs | 969 | * Return any delegations if we're going to change ACLs |
869 | */ | 970 | */ |
@@ -902,6 +1003,7 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr) | |||
902 | spin_unlock(&inode->i_lock); | 1003 | spin_unlock(&inode->i_lock); |
903 | } | 1004 | } |
904 | if ((attr->ia_valid & ATTR_SIZE) != 0) { | 1005 | if ((attr->ia_valid & ATTR_SIZE) != 0) { |
1006 | nfs_inc_stats(inode, NFSIOS_SETATTRTRUNC); | ||
905 | inode->i_size = attr->ia_size; | 1007 | inode->i_size = attr->ia_size; |
906 | vmtruncate(inode, attr->ia_size); | 1008 | vmtruncate(inode, attr->ia_size); |
907 | } | 1009 | } |
@@ -949,7 +1051,7 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | |||
949 | int err; | 1051 | int err; |
950 | 1052 | ||
951 | /* Flush out writes to the server in order to update c/mtime */ | 1053 | /* Flush out writes to the server in order to update c/mtime */ |
952 | nfs_sync_inode(inode, 0, 0, FLUSH_WAIT|FLUSH_NOCOMMIT); | 1054 | nfs_sync_inode_wait(inode, 0, 0, FLUSH_NOCOMMIT); |
953 | 1055 | ||
954 | /* | 1056 | /* |
955 | * We may force a getattr if the user cares about atime. | 1057 | * We may force a getattr if the user cares about atime. |
@@ -973,7 +1075,7 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | |||
973 | return err; | 1075 | return err; |
974 | } | 1076 | } |
975 | 1077 | ||
976 | struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, struct rpc_cred *cred) | 1078 | static struct nfs_open_context *alloc_nfs_open_context(struct vfsmount *mnt, struct dentry *dentry, struct rpc_cred *cred) |
977 | { | 1079 | { |
978 | struct nfs_open_context *ctx; | 1080 | struct nfs_open_context *ctx; |
979 | 1081 | ||
@@ -981,6 +1083,7 @@ struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, struct rp | |||
981 | if (ctx != NULL) { | 1083 | if (ctx != NULL) { |
982 | atomic_set(&ctx->count, 1); | 1084 | atomic_set(&ctx->count, 1); |
983 | ctx->dentry = dget(dentry); | 1085 | ctx->dentry = dget(dentry); |
1086 | ctx->vfsmnt = mntget(mnt); | ||
984 | ctx->cred = get_rpccred(cred); | 1087 | ctx->cred = get_rpccred(cred); |
985 | ctx->state = NULL; | 1088 | ctx->state = NULL; |
986 | ctx->lockowner = current->files; | 1089 | ctx->lockowner = current->files; |
@@ -1011,6 +1114,7 @@ void put_nfs_open_context(struct nfs_open_context *ctx) | |||
1011 | if (ctx->cred != NULL) | 1114 | if (ctx->cred != NULL) |
1012 | put_rpccred(ctx->cred); | 1115 | put_rpccred(ctx->cred); |
1013 | dput(ctx->dentry); | 1116 | dput(ctx->dentry); |
1117 | mntput(ctx->vfsmnt); | ||
1014 | kfree(ctx); | 1118 | kfree(ctx); |
1015 | } | 1119 | } |
1016 | } | 1120 | } |
@@ -1019,7 +1123,7 @@ void put_nfs_open_context(struct nfs_open_context *ctx) | |||
1019 | * Ensure that mmap has a recent RPC credential for use when writing out | 1123 | * Ensure that mmap has a recent RPC credential for use when writing out |
1020 | * shared pages | 1124 | * shared pages |
1021 | */ | 1125 | */ |
1022 | void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx) | 1126 | static void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx) |
1023 | { | 1127 | { |
1024 | struct inode *inode = filp->f_dentry->d_inode; | 1128 | struct inode *inode = filp->f_dentry->d_inode; |
1025 | struct nfs_inode *nfsi = NFS_I(inode); | 1129 | struct nfs_inode *nfsi = NFS_I(inode); |
@@ -1051,7 +1155,7 @@ struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_c | |||
1051 | return ctx; | 1155 | return ctx; |
1052 | } | 1156 | } |
1053 | 1157 | ||
1054 | void nfs_file_clear_open_context(struct file *filp) | 1158 | static void nfs_file_clear_open_context(struct file *filp) |
1055 | { | 1159 | { |
1056 | struct inode *inode = filp->f_dentry->d_inode; | 1160 | struct inode *inode = filp->f_dentry->d_inode; |
1057 | struct nfs_open_context *ctx = (struct nfs_open_context *)filp->private_data; | 1161 | struct nfs_open_context *ctx = (struct nfs_open_context *)filp->private_data; |
@@ -1076,7 +1180,7 @@ int nfs_open(struct inode *inode, struct file *filp) | |||
1076 | cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0); | 1180 | cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0); |
1077 | if (IS_ERR(cred)) | 1181 | if (IS_ERR(cred)) |
1078 | return PTR_ERR(cred); | 1182 | return PTR_ERR(cred); |
1079 | ctx = alloc_nfs_open_context(filp->f_dentry, cred); | 1183 | ctx = alloc_nfs_open_context(filp->f_vfsmnt, filp->f_dentry, cred); |
1080 | put_rpccred(cred); | 1184 | put_rpccred(cred); |
1081 | if (ctx == NULL) | 1185 | if (ctx == NULL) |
1082 | return -ENOMEM; | 1186 | return -ENOMEM; |
@@ -1185,6 +1289,7 @@ int nfs_attribute_timeout(struct inode *inode) | |||
1185 | */ | 1289 | */ |
1186 | int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | 1290 | int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) |
1187 | { | 1291 | { |
1292 | nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE); | ||
1188 | if (!(NFS_I(inode)->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA)) | 1293 | if (!(NFS_I(inode)->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA)) |
1189 | && !nfs_attribute_timeout(inode)) | 1294 | && !nfs_attribute_timeout(inode)) |
1190 | return NFS_STALE(inode) ? -ESTALE : 0; | 1295 | return NFS_STALE(inode) ? -ESTALE : 0; |
@@ -1201,6 +1306,7 @@ void nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping) | |||
1201 | struct nfs_inode *nfsi = NFS_I(inode); | 1306 | struct nfs_inode *nfsi = NFS_I(inode); |
1202 | 1307 | ||
1203 | if (nfsi->cache_validity & NFS_INO_INVALID_DATA) { | 1308 | if (nfsi->cache_validity & NFS_INO_INVALID_DATA) { |
1309 | nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE); | ||
1204 | if (S_ISREG(inode->i_mode)) | 1310 | if (S_ISREG(inode->i_mode)) |
1205 | nfs_sync_mapping(mapping); | 1311 | nfs_sync_mapping(mapping); |
1206 | invalidate_inode_pages2(mapping); | 1312 | invalidate_inode_pages2(mapping); |
@@ -1299,39 +1405,37 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat | |||
1299 | if ((fattr->valid & NFS_ATTR_FATTR) == 0) | 1405 | if ((fattr->valid & NFS_ATTR_FATTR) == 0) |
1300 | return 0; | 1406 | return 0; |
1301 | 1407 | ||
1408 | /* Has the inode gone and changed behind our back? */ | ||
1409 | if (nfsi->fileid != fattr->fileid | ||
1410 | || (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT)) { | ||
1411 | return -EIO; | ||
1412 | } | ||
1413 | |||
1302 | /* Are we in the process of updating data on the server? */ | 1414 | /* Are we in the process of updating data on the server? */ |
1303 | data_unstable = nfs_caches_unstable(inode); | 1415 | data_unstable = nfs_caches_unstable(inode); |
1304 | 1416 | ||
1305 | /* Do atomic weak cache consistency updates */ | 1417 | /* Do atomic weak cache consistency updates */ |
1306 | nfs_wcc_update_inode(inode, fattr); | 1418 | nfs_wcc_update_inode(inode, fattr); |
1307 | 1419 | ||
1308 | if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0 && | 1420 | if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0) { |
1309 | nfsi->change_attr != fattr->change_attr) { | 1421 | if (nfsi->change_attr == fattr->change_attr) |
1422 | goto out; | ||
1310 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR; | 1423 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR; |
1311 | if (!data_unstable) | 1424 | if (!data_unstable) |
1312 | nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE; | 1425 | nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE; |
1313 | } | 1426 | } |
1314 | 1427 | ||
1315 | /* Has the inode gone and changed behind our back? */ | ||
1316 | if (nfsi->fileid != fattr->fileid | ||
1317 | || (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT)) { | ||
1318 | return -EIO; | ||
1319 | } | ||
1320 | |||
1321 | cur_size = i_size_read(inode); | ||
1322 | new_isize = nfs_size_to_loff_t(fattr->size); | ||
1323 | |||
1324 | /* Verify a few of the more important attributes */ | 1428 | /* Verify a few of the more important attributes */ |
1325 | if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) { | 1429 | if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) { |
1326 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR; | 1430 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR; |
1327 | if (!data_unstable) | 1431 | if (!data_unstable) |
1328 | nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE; | 1432 | nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE; |
1329 | } | 1433 | } |
1330 | if (cur_size != new_isize) { | 1434 | |
1331 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR; | 1435 | cur_size = i_size_read(inode); |
1332 | if (nfsi->npages == 0) | 1436 | new_isize = nfs_size_to_loff_t(fattr->size); |
1333 | nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE; | 1437 | if (cur_size != new_isize && nfsi->npages == 0) |
1334 | } | 1438 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE; |
1335 | 1439 | ||
1336 | /* Have any file permissions changed? */ | 1440 | /* Have any file permissions changed? */ |
1337 | if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) | 1441 | if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) |
@@ -1343,6 +1447,7 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat | |||
1343 | if (inode->i_nlink != fattr->nlink) | 1447 | if (inode->i_nlink != fattr->nlink) |
1344 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR; | 1448 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR; |
1345 | 1449 | ||
1450 | out: | ||
1346 | if (!timespec_equal(&inode->i_atime, &fattr->atime)) | 1451 | if (!timespec_equal(&inode->i_atime, &fattr->atime)) |
1347 | nfsi->cache_validity |= NFS_INO_INVALID_ATIME; | 1452 | nfsi->cache_validity |= NFS_INO_INVALID_ATIME; |
1348 | 1453 | ||
@@ -1481,15 +1586,6 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1481 | nfsi->cache_change_attribute = jiffies; | 1586 | nfsi->cache_change_attribute = jiffies; |
1482 | } | 1587 | } |
1483 | 1588 | ||
1484 | if ((fattr->valid & NFS_ATTR_FATTR_V4) | ||
1485 | && nfsi->change_attr != fattr->change_attr) { | ||
1486 | dprintk("NFS: change_attr change on server for file %s/%ld\n", | ||
1487 | inode->i_sb->s_id, inode->i_ino); | ||
1488 | nfsi->change_attr = fattr->change_attr; | ||
1489 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; | ||
1490 | nfsi->cache_change_attribute = jiffies; | ||
1491 | } | ||
1492 | |||
1493 | /* If ctime has changed we should definitely clear access+acl caches */ | 1589 | /* If ctime has changed we should definitely clear access+acl caches */ |
1494 | if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) { | 1590 | if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) { |
1495 | invalid |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; | 1591 | invalid |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; |
@@ -1519,8 +1615,20 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1519 | inode->i_blksize = fattr->du.nfs2.blocksize; | 1615 | inode->i_blksize = fattr->du.nfs2.blocksize; |
1520 | } | 1616 | } |
1521 | 1617 | ||
1618 | if ((fattr->valid & NFS_ATTR_FATTR_V4)) { | ||
1619 | if (nfsi->change_attr != fattr->change_attr) { | ||
1620 | dprintk("NFS: change_attr change on server for file %s/%ld\n", | ||
1621 | inode->i_sb->s_id, inode->i_ino); | ||
1622 | nfsi->change_attr = fattr->change_attr; | ||
1623 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; | ||
1624 | nfsi->cache_change_attribute = jiffies; | ||
1625 | } else | ||
1626 | invalid &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA); | ||
1627 | } | ||
1628 | |||
1522 | /* Update attrtimeo value if we're out of the unstable period */ | 1629 | /* Update attrtimeo value if we're out of the unstable period */ |
1523 | if (invalid & NFS_INO_INVALID_ATTR) { | 1630 | if (invalid & NFS_INO_INVALID_ATTR) { |
1631 | nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE); | ||
1524 | nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); | 1632 | nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); |
1525 | nfsi->attrtimeo_timestamp = jiffies; | 1633 | nfsi->attrtimeo_timestamp = jiffies; |
1526 | } else if (time_after(jiffies, nfsi->attrtimeo_timestamp+nfsi->attrtimeo)) { | 1634 | } else if (time_after(jiffies, nfsi->attrtimeo_timestamp+nfsi->attrtimeo)) { |
@@ -1637,10 +1745,9 @@ static struct super_block *nfs_get_sb(struct file_system_type *fs_type, | |||
1637 | #endif /* CONFIG_NFS_V3 */ | 1745 | #endif /* CONFIG_NFS_V3 */ |
1638 | 1746 | ||
1639 | s = ERR_PTR(-ENOMEM); | 1747 | s = ERR_PTR(-ENOMEM); |
1640 | server = kmalloc(sizeof(struct nfs_server), GFP_KERNEL); | 1748 | server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL); |
1641 | if (!server) | 1749 | if (!server) |
1642 | goto out_err; | 1750 | goto out_err; |
1643 | memset(server, 0, sizeof(struct nfs_server)); | ||
1644 | /* Zero out the NFS state stuff */ | 1751 | /* Zero out the NFS state stuff */ |
1645 | init_nfsv4_state(server); | 1752 | init_nfsv4_state(server); |
1646 | server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL); | 1753 | server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL); |
@@ -1712,6 +1819,7 @@ static void nfs_kill_super(struct super_block *s) | |||
1712 | 1819 | ||
1713 | rpciod_down(); /* release rpciod */ | 1820 | rpciod_down(); /* release rpciod */ |
1714 | 1821 | ||
1822 | nfs_free_iostats(server->io_stats); | ||
1715 | kfree(server->hostname); | 1823 | kfree(server->hostname); |
1716 | kfree(server); | 1824 | kfree(server); |
1717 | } | 1825 | } |
@@ -1738,6 +1846,7 @@ static struct super_operations nfs4_sops = { | |||
1738 | .clear_inode = nfs4_clear_inode, | 1846 | .clear_inode = nfs4_clear_inode, |
1739 | .umount_begin = nfs_umount_begin, | 1847 | .umount_begin = nfs_umount_begin, |
1740 | .show_options = nfs_show_options, | 1848 | .show_options = nfs_show_options, |
1849 | .show_stats = nfs_show_stats, | ||
1741 | }; | 1850 | }; |
1742 | 1851 | ||
1743 | /* | 1852 | /* |
@@ -1800,6 +1909,9 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, | |||
1800 | 1909 | ||
1801 | nfs_init_timeout_values(&timeparms, data->proto, data->timeo, data->retrans); | 1910 | nfs_init_timeout_values(&timeparms, data->proto, data->timeo, data->retrans); |
1802 | 1911 | ||
1912 | server->retrans_timeo = timeparms.to_initval; | ||
1913 | server->retrans_count = timeparms.to_retries; | ||
1914 | |||
1803 | clp = nfs4_get_client(&server->addr.sin_addr); | 1915 | clp = nfs4_get_client(&server->addr.sin_addr); |
1804 | if (!clp) { | 1916 | if (!clp) { |
1805 | dprintk("%s: failed to create NFS4 client.\n", __FUNCTION__); | 1917 | dprintk("%s: failed to create NFS4 client.\n", __FUNCTION__); |
@@ -1941,10 +2053,9 @@ static struct super_block *nfs4_get_sb(struct file_system_type *fs_type, | |||
1941 | return ERR_PTR(-EINVAL); | 2053 | return ERR_PTR(-EINVAL); |
1942 | } | 2054 | } |
1943 | 2055 | ||
1944 | server = kmalloc(sizeof(struct nfs_server), GFP_KERNEL); | 2056 | server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL); |
1945 | if (!server) | 2057 | if (!server) |
1946 | return ERR_PTR(-ENOMEM); | 2058 | return ERR_PTR(-ENOMEM); |
1947 | memset(server, 0, sizeof(struct nfs_server)); | ||
1948 | /* Zero out the NFS state stuff */ | 2059 | /* Zero out the NFS state stuff */ |
1949 | init_nfsv4_state(server); | 2060 | init_nfsv4_state(server); |
1950 | server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL); | 2061 | server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL); |
@@ -2024,10 +2135,12 @@ static void nfs4_kill_super(struct super_block *sb) | |||
2024 | 2135 | ||
2025 | if (server->client != NULL && !IS_ERR(server->client)) | 2136 | if (server->client != NULL && !IS_ERR(server->client)) |
2026 | rpc_shutdown_client(server->client); | 2137 | rpc_shutdown_client(server->client); |
2027 | rpciod_down(); /* release rpciod */ | ||
2028 | 2138 | ||
2029 | destroy_nfsv4_state(server); | 2139 | destroy_nfsv4_state(server); |
2030 | 2140 | ||
2141 | rpciod_down(); | ||
2142 | |||
2143 | nfs_free_iostats(server->io_stats); | ||
2031 | kfree(server->hostname); | 2144 | kfree(server->hostname); |
2032 | kfree(server); | 2145 | kfree(server); |
2033 | } | 2146 | } |
diff --git a/fs/nfs/iostat.h b/fs/nfs/iostat.h new file mode 100644 index 000000000000..6350ecbde589 --- /dev/null +++ b/fs/nfs/iostat.h | |||
@@ -0,0 +1,164 @@ | |||
1 | /* | ||
2 | * linux/fs/nfs/iostat.h | ||
3 | * | ||
4 | * Declarations for NFS client per-mount statistics | ||
5 | * | ||
6 | * Copyright (C) 2005, 2006 Chuck Lever <cel@netapp.com> | ||
7 | * | ||
8 | * NFS client per-mount statistics provide information about the health of | ||
9 | * the NFS client and the health of each NFS mount point. Generally these | ||
10 | * are not for detailed problem diagnosis, but simply to indicate that there | ||
11 | * is a problem. | ||
12 | * | ||
13 | * These counters are not meant to be human-readable, but are meant to be | ||
14 | * integrated into system monitoring tools such as "sar" and "iostat". As | ||
15 | * such, the counters are sampled by the tools over time, and are never | ||
16 | * zeroed after a file system is mounted. Moving averages can be computed | ||
17 | * by the tools by taking the difference between two instantaneous samples | ||
18 | * and dividing that by the time between the samples. | ||
19 | */ | ||
20 | |||
21 | #ifndef _NFS_IOSTAT | ||
22 | #define _NFS_IOSTAT | ||
23 | |||
24 | #define NFS_IOSTAT_VERS "1.0" | ||
25 | |||
26 | /* | ||
27 | * NFS byte counters | ||
28 | * | ||
29 | * 1. SERVER - the number of payload bytes read from or written to the | ||
30 | * server by the NFS client via an NFS READ or WRITE request. | ||
31 | * | ||
32 | * 2. NORMAL - the number of bytes read or written by applications via | ||
33 | * the read(2) and write(2) system call interfaces. | ||
34 | * | ||
35 | * 3. DIRECT - the number of bytes read or written from files opened | ||
36 | * with the O_DIRECT flag. | ||
37 | * | ||
38 | * These counters give a view of the data throughput into and out of the NFS | ||
39 | * client. Comparing the number of bytes requested by an application with the | ||
40 | * number of bytes the client requests from the server can provide an | ||
41 | * indication of client efficiency (per-op, cache hits, etc). | ||
42 | * | ||
43 | * These counters can also help characterize which access methods are in | ||
44 | * use. DIRECT by itself shows whether there is any O_DIRECT traffic. | ||
45 | * NORMAL + DIRECT shows how much data is going through the system call | ||
46 | * interface. A large amount of SERVER traffic without much NORMAL or | ||
47 | * DIRECT traffic shows that applications are using mapped files. | ||
48 | * | ||
49 | * NFS page counters | ||
50 | * | ||
51 | * These count the number of pages read or written via nfs_readpage(), | ||
52 | * nfs_readpages(), or their write equivalents. | ||
53 | */ | ||
54 | enum nfs_stat_bytecounters { | ||
55 | NFSIOS_NORMALREADBYTES = 0, | ||
56 | NFSIOS_NORMALWRITTENBYTES, | ||
57 | NFSIOS_DIRECTREADBYTES, | ||
58 | NFSIOS_DIRECTWRITTENBYTES, | ||
59 | NFSIOS_SERVERREADBYTES, | ||
60 | NFSIOS_SERVERWRITTENBYTES, | ||
61 | NFSIOS_READPAGES, | ||
62 | NFSIOS_WRITEPAGES, | ||
63 | __NFSIOS_BYTESMAX, | ||
64 | }; | ||
65 | |||
66 | /* | ||
67 | * NFS event counters | ||
68 | * | ||
69 | * These counters provide a low-overhead way of monitoring client activity | ||
70 | * without enabling NFS trace debugging. The counters show the rate at | ||
71 | * which VFS requests are made, and how often the client invalidates its | ||
72 | * data and attribute caches. This allows system administrators to monitor | ||
73 | * such things as how close-to-open is working, and answer questions such | ||
74 | * as "why are there so many GETATTR requests on the wire?" | ||
75 | * | ||
76 | * They also count anamolous events such as short reads and writes, silly | ||
77 | * renames due to close-after-delete, and operations that change the size | ||
78 | * of a file (such operations can often be the source of data corruption | ||
79 | * if applications aren't using file locking properly). | ||
80 | */ | ||
81 | enum nfs_stat_eventcounters { | ||
82 | NFSIOS_INODEREVALIDATE = 0, | ||
83 | NFSIOS_DENTRYREVALIDATE, | ||
84 | NFSIOS_DATAINVALIDATE, | ||
85 | NFSIOS_ATTRINVALIDATE, | ||
86 | NFSIOS_VFSOPEN, | ||
87 | NFSIOS_VFSLOOKUP, | ||
88 | NFSIOS_VFSACCESS, | ||
89 | NFSIOS_VFSUPDATEPAGE, | ||
90 | NFSIOS_VFSREADPAGE, | ||
91 | NFSIOS_VFSREADPAGES, | ||
92 | NFSIOS_VFSWRITEPAGE, | ||
93 | NFSIOS_VFSWRITEPAGES, | ||
94 | NFSIOS_VFSGETDENTS, | ||
95 | NFSIOS_VFSSETATTR, | ||
96 | NFSIOS_VFSFLUSH, | ||
97 | NFSIOS_VFSFSYNC, | ||
98 | NFSIOS_VFSLOCK, | ||
99 | NFSIOS_VFSRELEASE, | ||
100 | NFSIOS_CONGESTIONWAIT, | ||
101 | NFSIOS_SETATTRTRUNC, | ||
102 | NFSIOS_EXTENDWRITE, | ||
103 | NFSIOS_SILLYRENAME, | ||
104 | NFSIOS_SHORTREAD, | ||
105 | NFSIOS_SHORTWRITE, | ||
106 | NFSIOS_DELAY, | ||
107 | __NFSIOS_COUNTSMAX, | ||
108 | }; | ||
109 | |||
110 | #ifdef __KERNEL__ | ||
111 | |||
112 | #include <linux/percpu.h> | ||
113 | #include <linux/cache.h> | ||
114 | |||
115 | struct nfs_iostats { | ||
116 | unsigned long long bytes[__NFSIOS_BYTESMAX]; | ||
117 | unsigned long events[__NFSIOS_COUNTSMAX]; | ||
118 | } ____cacheline_aligned; | ||
119 | |||
120 | static inline void nfs_inc_server_stats(struct nfs_server *server, enum nfs_stat_eventcounters stat) | ||
121 | { | ||
122 | struct nfs_iostats *iostats; | ||
123 | int cpu; | ||
124 | |||
125 | cpu = get_cpu(); | ||
126 | iostats = per_cpu_ptr(server->io_stats, cpu); | ||
127 | iostats->events[stat] ++; | ||
128 | put_cpu_no_resched(); | ||
129 | } | ||
130 | |||
131 | static inline void nfs_inc_stats(struct inode *inode, enum nfs_stat_eventcounters stat) | ||
132 | { | ||
133 | nfs_inc_server_stats(NFS_SERVER(inode), stat); | ||
134 | } | ||
135 | |||
136 | static inline void nfs_add_server_stats(struct nfs_server *server, enum nfs_stat_bytecounters stat, unsigned long addend) | ||
137 | { | ||
138 | struct nfs_iostats *iostats; | ||
139 | int cpu; | ||
140 | |||
141 | cpu = get_cpu(); | ||
142 | iostats = per_cpu_ptr(server->io_stats, cpu); | ||
143 | iostats->bytes[stat] += addend; | ||
144 | put_cpu_no_resched(); | ||
145 | } | ||
146 | |||
147 | static inline void nfs_add_stats(struct inode *inode, enum nfs_stat_bytecounters stat, unsigned long addend) | ||
148 | { | ||
149 | nfs_add_server_stats(NFS_SERVER(inode), stat, addend); | ||
150 | } | ||
151 | |||
152 | static inline struct nfs_iostats *nfs_alloc_iostats(void) | ||
153 | { | ||
154 | return alloc_percpu(struct nfs_iostats); | ||
155 | } | ||
156 | |||
157 | static inline void nfs_free_iostats(struct nfs_iostats *stats) | ||
158 | { | ||
159 | if (stats != NULL) | ||
160 | free_percpu(stats); | ||
161 | } | ||
162 | |||
163 | #endif | ||
164 | #endif | ||
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index 0b9a78353d6e..445abb4d4214 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c | |||
@@ -49,9 +49,12 @@ nfsroot_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh, | |||
49 | struct mnt_fhstatus result = { | 49 | struct mnt_fhstatus result = { |
50 | .fh = fh | 50 | .fh = fh |
51 | }; | 51 | }; |
52 | struct rpc_message msg = { | ||
53 | .rpc_argp = path, | ||
54 | .rpc_resp = &result, | ||
55 | }; | ||
52 | char hostname[32]; | 56 | char hostname[32]; |
53 | int status; | 57 | int status; |
54 | int call; | ||
55 | 58 | ||
56 | dprintk("NFS: nfs_mount(%08x:%s)\n", | 59 | dprintk("NFS: nfs_mount(%08x:%s)\n", |
57 | (unsigned)ntohl(addr->sin_addr.s_addr), path); | 60 | (unsigned)ntohl(addr->sin_addr.s_addr), path); |
@@ -61,8 +64,12 @@ nfsroot_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh, | |||
61 | if (IS_ERR(mnt_clnt)) | 64 | if (IS_ERR(mnt_clnt)) |
62 | return PTR_ERR(mnt_clnt); | 65 | return PTR_ERR(mnt_clnt); |
63 | 66 | ||
64 | call = (version == NFS_MNT3_VERSION) ? MOUNTPROC3_MNT : MNTPROC_MNT; | 67 | if (version == NFS_MNT3_VERSION) |
65 | status = rpc_call(mnt_clnt, call, path, &result, 0); | 68 | msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC3_MNT]; |
69 | else | ||
70 | msg.rpc_proc = &mnt_clnt->cl_procinfo[MNTPROC_MNT]; | ||
71 | |||
72 | status = rpc_call_sync(mnt_clnt, &msg, 0); | ||
66 | return status < 0? status : (result.status? -EACCES : 0); | 73 | return status < 0? status : (result.status? -EACCES : 0); |
67 | } | 74 | } |
68 | 75 | ||
@@ -137,6 +144,8 @@ static struct rpc_procinfo mnt_procedures[] = { | |||
137 | .p_encode = (kxdrproc_t) xdr_encode_dirpath, | 144 | .p_encode = (kxdrproc_t) xdr_encode_dirpath, |
138 | .p_decode = (kxdrproc_t) xdr_decode_fhstatus, | 145 | .p_decode = (kxdrproc_t) xdr_decode_fhstatus, |
139 | .p_bufsiz = MNT_dirpath_sz << 2, | 146 | .p_bufsiz = MNT_dirpath_sz << 2, |
147 | .p_statidx = MNTPROC_MNT, | ||
148 | .p_name = "MOUNT", | ||
140 | }, | 149 | }, |
141 | }; | 150 | }; |
142 | 151 | ||
@@ -146,6 +155,8 @@ static struct rpc_procinfo mnt3_procedures[] = { | |||
146 | .p_encode = (kxdrproc_t) xdr_encode_dirpath, | 155 | .p_encode = (kxdrproc_t) xdr_encode_dirpath, |
147 | .p_decode = (kxdrproc_t) xdr_decode_fhstatus3, | 156 | .p_decode = (kxdrproc_t) xdr_decode_fhstatus3, |
148 | .p_bufsiz = MNT_dirpath_sz << 2, | 157 | .p_bufsiz = MNT_dirpath_sz << 2, |
158 | .p_statidx = MOUNTPROC3_MNT, | ||
159 | .p_name = "MOUNT", | ||
149 | }, | 160 | }, |
150 | }; | 161 | }; |
151 | 162 | ||
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index 6548a65de944..f0015fa876e1 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c | |||
@@ -682,7 +682,9 @@ nfs_stat_to_errno(int stat) | |||
682 | .p_encode = (kxdrproc_t) nfs_xdr_##argtype, \ | 682 | .p_encode = (kxdrproc_t) nfs_xdr_##argtype, \ |
683 | .p_decode = (kxdrproc_t) nfs_xdr_##restype, \ | 683 | .p_decode = (kxdrproc_t) nfs_xdr_##restype, \ |
684 | .p_bufsiz = MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2, \ | 684 | .p_bufsiz = MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2, \ |
685 | .p_timer = timer \ | 685 | .p_timer = timer, \ |
686 | .p_statidx = NFSPROC_##proc, \ | ||
687 | .p_name = #proc, \ | ||
686 | } | 688 | } |
687 | struct rpc_procinfo nfs_procedures[] = { | 689 | struct rpc_procinfo nfs_procedures[] = { |
688 | PROC(GETATTR, fhandle, attrstat, 1), | 690 | PROC(GETATTR, fhandle, attrstat, 1), |
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c index 6a5bbc0ae941..33287879bd23 100644 --- a/fs/nfs/nfs3acl.c +++ b/fs/nfs/nfs3acl.c | |||
@@ -190,6 +190,10 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) | |||
190 | struct nfs3_getaclres res = { | 190 | struct nfs3_getaclres res = { |
191 | .fattr = &fattr, | 191 | .fattr = &fattr, |
192 | }; | 192 | }; |
193 | struct rpc_message msg = { | ||
194 | .rpc_argp = &args, | ||
195 | .rpc_resp = &res, | ||
196 | }; | ||
193 | struct posix_acl *acl; | 197 | struct posix_acl *acl; |
194 | int status, count; | 198 | int status, count; |
195 | 199 | ||
@@ -218,8 +222,8 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) | |||
218 | return NULL; | 222 | return NULL; |
219 | 223 | ||
220 | dprintk("NFS call getacl\n"); | 224 | dprintk("NFS call getacl\n"); |
221 | status = rpc_call(server->client_acl, ACLPROC3_GETACL, | 225 | msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_GETACL]; |
222 | &args, &res, 0); | 226 | status = rpc_call_sync(server->client_acl, &msg, 0); |
223 | dprintk("NFS reply getacl: %d\n", status); | 227 | dprintk("NFS reply getacl: %d\n", status); |
224 | 228 | ||
225 | /* pages may have been allocated at the xdr layer. */ | 229 | /* pages may have been allocated at the xdr layer. */ |
@@ -286,6 +290,10 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, | |||
286 | .acl_access = acl, | 290 | .acl_access = acl, |
287 | .pages = pages, | 291 | .pages = pages, |
288 | }; | 292 | }; |
293 | struct rpc_message msg = { | ||
294 | .rpc_argp = &args, | ||
295 | .rpc_resp = &fattr, | ||
296 | }; | ||
289 | int status, count; | 297 | int status, count; |
290 | 298 | ||
291 | status = -EOPNOTSUPP; | 299 | status = -EOPNOTSUPP; |
@@ -306,8 +314,8 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, | |||
306 | 314 | ||
307 | dprintk("NFS call setacl\n"); | 315 | dprintk("NFS call setacl\n"); |
308 | nfs_begin_data_update(inode); | 316 | nfs_begin_data_update(inode); |
309 | status = rpc_call(server->client_acl, ACLPROC3_SETACL, | 317 | msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_SETACL]; |
310 | &args, &fattr, 0); | 318 | status = rpc_call_sync(server->client_acl, &msg, 0); |
311 | spin_lock(&inode->i_lock); | 319 | spin_lock(&inode->i_lock); |
312 | NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ACCESS; | 320 | NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ACCESS; |
313 | spin_unlock(&inode->i_lock); | 321 | spin_unlock(&inode->i_lock); |
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index ed67567f0556..cf186f0d2b3b 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c | |||
@@ -19,6 +19,8 @@ | |||
19 | #include <linux/smp_lock.h> | 19 | #include <linux/smp_lock.h> |
20 | #include <linux/nfs_mount.h> | 20 | #include <linux/nfs_mount.h> |
21 | 21 | ||
22 | #include "iostat.h" | ||
23 | |||
22 | #define NFSDBG_FACILITY NFSDBG_PROC | 24 | #define NFSDBG_FACILITY NFSDBG_PROC |
23 | 25 | ||
24 | extern struct rpc_procinfo nfs3_procedures[]; | 26 | extern struct rpc_procinfo nfs3_procedures[]; |
@@ -41,27 +43,14 @@ nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags) | |||
41 | return res; | 43 | return res; |
42 | } | 44 | } |
43 | 45 | ||
44 | static inline int | 46 | #define rpc_call_sync(clnt, msg, flags) nfs3_rpc_wrapper(clnt, msg, flags) |
45 | nfs3_rpc_call_wrapper(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags) | ||
46 | { | ||
47 | struct rpc_message msg = { | ||
48 | .rpc_proc = &clnt->cl_procinfo[proc], | ||
49 | .rpc_argp = argp, | ||
50 | .rpc_resp = resp, | ||
51 | }; | ||
52 | return nfs3_rpc_wrapper(clnt, &msg, flags); | ||
53 | } | ||
54 | |||
55 | #define rpc_call(clnt, proc, argp, resp, flags) \ | ||
56 | nfs3_rpc_call_wrapper(clnt, proc, argp, resp, flags) | ||
57 | #define rpc_call_sync(clnt, msg, flags) \ | ||
58 | nfs3_rpc_wrapper(clnt, msg, flags) | ||
59 | 47 | ||
60 | static int | 48 | static int |
61 | nfs3_async_handle_jukebox(struct rpc_task *task) | 49 | nfs3_async_handle_jukebox(struct rpc_task *task, struct inode *inode) |
62 | { | 50 | { |
63 | if (task->tk_status != -EJUKEBOX) | 51 | if (task->tk_status != -EJUKEBOX) |
64 | return 0; | 52 | return 0; |
53 | nfs_inc_stats(inode, NFSIOS_DELAY); | ||
65 | task->tk_status = 0; | 54 | task->tk_status = 0; |
66 | rpc_restart_call(task); | 55 | rpc_restart_call(task); |
67 | rpc_delay(task, NFS_JUKEBOX_RETRY_TIME); | 56 | rpc_delay(task, NFS_JUKEBOX_RETRY_TIME); |
@@ -72,14 +61,21 @@ static int | |||
72 | do_proc_get_root(struct rpc_clnt *client, struct nfs_fh *fhandle, | 61 | do_proc_get_root(struct rpc_clnt *client, struct nfs_fh *fhandle, |
73 | struct nfs_fsinfo *info) | 62 | struct nfs_fsinfo *info) |
74 | { | 63 | { |
64 | struct rpc_message msg = { | ||
65 | .rpc_proc = &nfs3_procedures[NFS3PROC_FSINFO], | ||
66 | .rpc_argp = fhandle, | ||
67 | .rpc_resp = info, | ||
68 | }; | ||
75 | int status; | 69 | int status; |
76 | 70 | ||
77 | dprintk("%s: call fsinfo\n", __FUNCTION__); | 71 | dprintk("%s: call fsinfo\n", __FUNCTION__); |
78 | nfs_fattr_init(info->fattr); | 72 | nfs_fattr_init(info->fattr); |
79 | status = rpc_call(client, NFS3PROC_FSINFO, fhandle, info, 0); | 73 | status = rpc_call_sync(client, &msg, 0); |
80 | dprintk("%s: reply fsinfo: %d\n", __FUNCTION__, status); | 74 | dprintk("%s: reply fsinfo: %d\n", __FUNCTION__, status); |
81 | if (!(info->fattr->valid & NFS_ATTR_FATTR)) { | 75 | if (!(info->fattr->valid & NFS_ATTR_FATTR)) { |
82 | status = rpc_call(client, NFS3PROC_GETATTR, fhandle, info->fattr, 0); | 76 | msg.rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR]; |
77 | msg.rpc_resp = info->fattr; | ||
78 | status = rpc_call_sync(client, &msg, 0); | ||
83 | dprintk("%s: reply getattr: %d\n", __FUNCTION__, status); | 79 | dprintk("%s: reply getattr: %d\n", __FUNCTION__, status); |
84 | } | 80 | } |
85 | return status; | 81 | return status; |
@@ -107,12 +103,16 @@ static int | |||
107 | nfs3_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, | 103 | nfs3_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, |
108 | struct nfs_fattr *fattr) | 104 | struct nfs_fattr *fattr) |
109 | { | 105 | { |
106 | struct rpc_message msg = { | ||
107 | .rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR], | ||
108 | .rpc_argp = fhandle, | ||
109 | .rpc_resp = fattr, | ||
110 | }; | ||
110 | int status; | 111 | int status; |
111 | 112 | ||
112 | dprintk("NFS call getattr\n"); | 113 | dprintk("NFS call getattr\n"); |
113 | nfs_fattr_init(fattr); | 114 | nfs_fattr_init(fattr); |
114 | status = rpc_call(server->client, NFS3PROC_GETATTR, | 115 | status = rpc_call_sync(server->client, &msg, 0); |
115 | fhandle, fattr, 0); | ||
116 | dprintk("NFS reply getattr: %d\n", status); | 116 | dprintk("NFS reply getattr: %d\n", status); |
117 | return status; | 117 | return status; |
118 | } | 118 | } |
@@ -126,11 +126,16 @@ nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | |||
126 | .fh = NFS_FH(inode), | 126 | .fh = NFS_FH(inode), |
127 | .sattr = sattr, | 127 | .sattr = sattr, |
128 | }; | 128 | }; |
129 | struct rpc_message msg = { | ||
130 | .rpc_proc = &nfs3_procedures[NFS3PROC_SETATTR], | ||
131 | .rpc_argp = &arg, | ||
132 | .rpc_resp = fattr, | ||
133 | }; | ||
129 | int status; | 134 | int status; |
130 | 135 | ||
131 | dprintk("NFS call setattr\n"); | 136 | dprintk("NFS call setattr\n"); |
132 | nfs_fattr_init(fattr); | 137 | nfs_fattr_init(fattr); |
133 | status = rpc_call(NFS_CLIENT(inode), NFS3PROC_SETATTR, &arg, fattr, 0); | 138 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); |
134 | if (status == 0) | 139 | if (status == 0) |
135 | nfs_setattr_update_inode(inode, sattr); | 140 | nfs_setattr_update_inode(inode, sattr); |
136 | dprintk("NFS reply setattr: %d\n", status); | 141 | dprintk("NFS reply setattr: %d\n", status); |
@@ -152,15 +157,23 @@ nfs3_proc_lookup(struct inode *dir, struct qstr *name, | |||
152 | .fh = fhandle, | 157 | .fh = fhandle, |
153 | .fattr = fattr | 158 | .fattr = fattr |
154 | }; | 159 | }; |
160 | struct rpc_message msg = { | ||
161 | .rpc_proc = &nfs3_procedures[NFS3PROC_LOOKUP], | ||
162 | .rpc_argp = &arg, | ||
163 | .rpc_resp = &res, | ||
164 | }; | ||
155 | int status; | 165 | int status; |
156 | 166 | ||
157 | dprintk("NFS call lookup %s\n", name->name); | 167 | dprintk("NFS call lookup %s\n", name->name); |
158 | nfs_fattr_init(&dir_attr); | 168 | nfs_fattr_init(&dir_attr); |
159 | nfs_fattr_init(fattr); | 169 | nfs_fattr_init(fattr); |
160 | status = rpc_call(NFS_CLIENT(dir), NFS3PROC_LOOKUP, &arg, &res, 0); | 170 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
161 | if (status >= 0 && !(fattr->valid & NFS_ATTR_FATTR)) | 171 | if (status >= 0 && !(fattr->valid & NFS_ATTR_FATTR)) { |
162 | status = rpc_call(NFS_CLIENT(dir), NFS3PROC_GETATTR, | 172 | msg.rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR]; |
163 | fhandle, fattr, 0); | 173 | msg.rpc_argp = fhandle; |
174 | msg.rpc_resp = fattr; | ||
175 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | ||
176 | } | ||
164 | dprintk("NFS reply lookup: %d\n", status); | 177 | dprintk("NFS reply lookup: %d\n", status); |
165 | if (status >= 0) | 178 | if (status >= 0) |
166 | status = nfs_refresh_inode(dir, &dir_attr); | 179 | status = nfs_refresh_inode(dir, &dir_attr); |
@@ -180,7 +193,7 @@ static int nfs3_proc_access(struct inode *inode, struct nfs_access_entry *entry) | |||
180 | .rpc_proc = &nfs3_procedures[NFS3PROC_ACCESS], | 193 | .rpc_proc = &nfs3_procedures[NFS3PROC_ACCESS], |
181 | .rpc_argp = &arg, | 194 | .rpc_argp = &arg, |
182 | .rpc_resp = &res, | 195 | .rpc_resp = &res, |
183 | .rpc_cred = entry->cred | 196 | .rpc_cred = entry->cred, |
184 | }; | 197 | }; |
185 | int mode = entry->mask; | 198 | int mode = entry->mask; |
186 | int status; | 199 | int status; |
@@ -226,12 +239,16 @@ static int nfs3_proc_readlink(struct inode *inode, struct page *page, | |||
226 | .pglen = pglen, | 239 | .pglen = pglen, |
227 | .pages = &page | 240 | .pages = &page |
228 | }; | 241 | }; |
242 | struct rpc_message msg = { | ||
243 | .rpc_proc = &nfs3_procedures[NFS3PROC_READLINK], | ||
244 | .rpc_argp = &args, | ||
245 | .rpc_resp = &fattr, | ||
246 | }; | ||
229 | int status; | 247 | int status; |
230 | 248 | ||
231 | dprintk("NFS call readlink\n"); | 249 | dprintk("NFS call readlink\n"); |
232 | nfs_fattr_init(&fattr); | 250 | nfs_fattr_init(&fattr); |
233 | status = rpc_call(NFS_CLIENT(inode), NFS3PROC_READLINK, | 251 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); |
234 | &args, &fattr, 0); | ||
235 | nfs_refresh_inode(inode, &fattr); | 252 | nfs_refresh_inode(inode, &fattr); |
236 | dprintk("NFS reply readlink: %d\n", status); | 253 | dprintk("NFS reply readlink: %d\n", status); |
237 | return status; | 254 | return status; |
@@ -327,6 +344,11 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
327 | .fh = &fhandle, | 344 | .fh = &fhandle, |
328 | .fattr = &fattr | 345 | .fattr = &fattr |
329 | }; | 346 | }; |
347 | struct rpc_message msg = { | ||
348 | .rpc_proc = &nfs3_procedures[NFS3PROC_CREATE], | ||
349 | .rpc_argp = &arg, | ||
350 | .rpc_resp = &res, | ||
351 | }; | ||
330 | mode_t mode = sattr->ia_mode; | 352 | mode_t mode = sattr->ia_mode; |
331 | int status; | 353 | int status; |
332 | 354 | ||
@@ -343,8 +365,8 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
343 | again: | 365 | again: |
344 | nfs_fattr_init(&dir_attr); | 366 | nfs_fattr_init(&dir_attr); |
345 | nfs_fattr_init(&fattr); | 367 | nfs_fattr_init(&fattr); |
346 | status = rpc_call(NFS_CLIENT(dir), NFS3PROC_CREATE, &arg, &res, 0); | 368 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
347 | nfs_post_op_update_inode(dir, &dir_attr); | 369 | nfs_refresh_inode(dir, &dir_attr); |
348 | 370 | ||
349 | /* If the server doesn't support the exclusive creation semantics, | 371 | /* If the server doesn't support the exclusive creation semantics, |
350 | * try again with simple 'guarded' mode. */ | 372 | * try again with simple 'guarded' mode. */ |
@@ -447,7 +469,7 @@ nfs3_proc_unlink_done(struct dentry *dir, struct rpc_task *task) | |||
447 | struct rpc_message *msg = &task->tk_msg; | 469 | struct rpc_message *msg = &task->tk_msg; |
448 | struct nfs_fattr *dir_attr; | 470 | struct nfs_fattr *dir_attr; |
449 | 471 | ||
450 | if (nfs3_async_handle_jukebox(task)) | 472 | if (nfs3_async_handle_jukebox(task, dir->d_inode)) |
451 | return 1; | 473 | return 1; |
452 | if (msg->rpc_argp) { | 474 | if (msg->rpc_argp) { |
453 | dir_attr = (struct nfs_fattr*)msg->rpc_resp; | 475 | dir_attr = (struct nfs_fattr*)msg->rpc_resp; |
@@ -474,12 +496,17 @@ nfs3_proc_rename(struct inode *old_dir, struct qstr *old_name, | |||
474 | .fromattr = &old_dir_attr, | 496 | .fromattr = &old_dir_attr, |
475 | .toattr = &new_dir_attr | 497 | .toattr = &new_dir_attr |
476 | }; | 498 | }; |
499 | struct rpc_message msg = { | ||
500 | .rpc_proc = &nfs3_procedures[NFS3PROC_RENAME], | ||
501 | .rpc_argp = &arg, | ||
502 | .rpc_resp = &res, | ||
503 | }; | ||
477 | int status; | 504 | int status; |
478 | 505 | ||
479 | dprintk("NFS call rename %s -> %s\n", old_name->name, new_name->name); | 506 | dprintk("NFS call rename %s -> %s\n", old_name->name, new_name->name); |
480 | nfs_fattr_init(&old_dir_attr); | 507 | nfs_fattr_init(&old_dir_attr); |
481 | nfs_fattr_init(&new_dir_attr); | 508 | nfs_fattr_init(&new_dir_attr); |
482 | status = rpc_call(NFS_CLIENT(old_dir), NFS3PROC_RENAME, &arg, &res, 0); | 509 | status = rpc_call_sync(NFS_CLIENT(old_dir), &msg, 0); |
483 | nfs_post_op_update_inode(old_dir, &old_dir_attr); | 510 | nfs_post_op_update_inode(old_dir, &old_dir_attr); |
484 | nfs_post_op_update_inode(new_dir, &new_dir_attr); | 511 | nfs_post_op_update_inode(new_dir, &new_dir_attr); |
485 | dprintk("NFS reply rename: %d\n", status); | 512 | dprintk("NFS reply rename: %d\n", status); |
@@ -500,12 +527,17 @@ nfs3_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) | |||
500 | .dir_attr = &dir_attr, | 527 | .dir_attr = &dir_attr, |
501 | .fattr = &fattr | 528 | .fattr = &fattr |
502 | }; | 529 | }; |
530 | struct rpc_message msg = { | ||
531 | .rpc_proc = &nfs3_procedures[NFS3PROC_LINK], | ||
532 | .rpc_argp = &arg, | ||
533 | .rpc_resp = &res, | ||
534 | }; | ||
503 | int status; | 535 | int status; |
504 | 536 | ||
505 | dprintk("NFS call link %s\n", name->name); | 537 | dprintk("NFS call link %s\n", name->name); |
506 | nfs_fattr_init(&dir_attr); | 538 | nfs_fattr_init(&dir_attr); |
507 | nfs_fattr_init(&fattr); | 539 | nfs_fattr_init(&fattr); |
508 | status = rpc_call(NFS_CLIENT(inode), NFS3PROC_LINK, &arg, &res, 0); | 540 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); |
509 | nfs_post_op_update_inode(dir, &dir_attr); | 541 | nfs_post_op_update_inode(dir, &dir_attr); |
510 | nfs_post_op_update_inode(inode, &fattr); | 542 | nfs_post_op_update_inode(inode, &fattr); |
511 | dprintk("NFS reply link: %d\n", status); | 543 | dprintk("NFS reply link: %d\n", status); |
@@ -531,6 +563,11 @@ nfs3_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, | |||
531 | .fh = fhandle, | 563 | .fh = fhandle, |
532 | .fattr = fattr | 564 | .fattr = fattr |
533 | }; | 565 | }; |
566 | struct rpc_message msg = { | ||
567 | .rpc_proc = &nfs3_procedures[NFS3PROC_SYMLINK], | ||
568 | .rpc_argp = &arg, | ||
569 | .rpc_resp = &res, | ||
570 | }; | ||
534 | int status; | 571 | int status; |
535 | 572 | ||
536 | if (path->len > NFS3_MAXPATHLEN) | 573 | if (path->len > NFS3_MAXPATHLEN) |
@@ -538,7 +575,7 @@ nfs3_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, | |||
538 | dprintk("NFS call symlink %s -> %s\n", name->name, path->name); | 575 | dprintk("NFS call symlink %s -> %s\n", name->name, path->name); |
539 | nfs_fattr_init(&dir_attr); | 576 | nfs_fattr_init(&dir_attr); |
540 | nfs_fattr_init(fattr); | 577 | nfs_fattr_init(fattr); |
541 | status = rpc_call(NFS_CLIENT(dir), NFS3PROC_SYMLINK, &arg, &res, 0); | 578 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
542 | nfs_post_op_update_inode(dir, &dir_attr); | 579 | nfs_post_op_update_inode(dir, &dir_attr); |
543 | dprintk("NFS reply symlink: %d\n", status); | 580 | dprintk("NFS reply symlink: %d\n", status); |
544 | return status; | 581 | return status; |
@@ -560,6 +597,11 @@ nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) | |||
560 | .fh = &fhandle, | 597 | .fh = &fhandle, |
561 | .fattr = &fattr | 598 | .fattr = &fattr |
562 | }; | 599 | }; |
600 | struct rpc_message msg = { | ||
601 | .rpc_proc = &nfs3_procedures[NFS3PROC_MKDIR], | ||
602 | .rpc_argp = &arg, | ||
603 | .rpc_resp = &res, | ||
604 | }; | ||
563 | int mode = sattr->ia_mode; | 605 | int mode = sattr->ia_mode; |
564 | int status; | 606 | int status; |
565 | 607 | ||
@@ -569,7 +611,7 @@ nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) | |||
569 | 611 | ||
570 | nfs_fattr_init(&dir_attr); | 612 | nfs_fattr_init(&dir_attr); |
571 | nfs_fattr_init(&fattr); | 613 | nfs_fattr_init(&fattr); |
572 | status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKDIR, &arg, &res, 0); | 614 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
573 | nfs_post_op_update_inode(dir, &dir_attr); | 615 | nfs_post_op_update_inode(dir, &dir_attr); |
574 | if (status != 0) | 616 | if (status != 0) |
575 | goto out; | 617 | goto out; |
@@ -591,11 +633,16 @@ nfs3_proc_rmdir(struct inode *dir, struct qstr *name) | |||
591 | .name = name->name, | 633 | .name = name->name, |
592 | .len = name->len | 634 | .len = name->len |
593 | }; | 635 | }; |
636 | struct rpc_message msg = { | ||
637 | .rpc_proc = &nfs3_procedures[NFS3PROC_RMDIR], | ||
638 | .rpc_argp = &arg, | ||
639 | .rpc_resp = &dir_attr, | ||
640 | }; | ||
594 | int status; | 641 | int status; |
595 | 642 | ||
596 | dprintk("NFS call rmdir %s\n", name->name); | 643 | dprintk("NFS call rmdir %s\n", name->name); |
597 | nfs_fattr_init(&dir_attr); | 644 | nfs_fattr_init(&dir_attr); |
598 | status = rpc_call(NFS_CLIENT(dir), NFS3PROC_RMDIR, &arg, &dir_attr, 0); | 645 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
599 | nfs_post_op_update_inode(dir, &dir_attr); | 646 | nfs_post_op_update_inode(dir, &dir_attr); |
600 | dprintk("NFS reply rmdir: %d\n", status); | 647 | dprintk("NFS reply rmdir: %d\n", status); |
601 | return status; | 648 | return status; |
@@ -672,6 +719,11 @@ nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
672 | .fh = &fh, | 719 | .fh = &fh, |
673 | .fattr = &fattr | 720 | .fattr = &fattr |
674 | }; | 721 | }; |
722 | struct rpc_message msg = { | ||
723 | .rpc_proc = &nfs3_procedures[NFS3PROC_MKNOD], | ||
724 | .rpc_argp = &arg, | ||
725 | .rpc_resp = &res, | ||
726 | }; | ||
675 | mode_t mode = sattr->ia_mode; | 727 | mode_t mode = sattr->ia_mode; |
676 | int status; | 728 | int status; |
677 | 729 | ||
@@ -690,7 +742,7 @@ nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
690 | 742 | ||
691 | nfs_fattr_init(&dir_attr); | 743 | nfs_fattr_init(&dir_attr); |
692 | nfs_fattr_init(&fattr); | 744 | nfs_fattr_init(&fattr); |
693 | status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKNOD, &arg, &res, 0); | 745 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
694 | nfs_post_op_update_inode(dir, &dir_attr); | 746 | nfs_post_op_update_inode(dir, &dir_attr); |
695 | if (status != 0) | 747 | if (status != 0) |
696 | goto out; | 748 | goto out; |
@@ -707,11 +759,16 @@ static int | |||
707 | nfs3_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, | 759 | nfs3_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, |
708 | struct nfs_fsstat *stat) | 760 | struct nfs_fsstat *stat) |
709 | { | 761 | { |
762 | struct rpc_message msg = { | ||
763 | .rpc_proc = &nfs3_procedures[NFS3PROC_FSSTAT], | ||
764 | .rpc_argp = fhandle, | ||
765 | .rpc_resp = stat, | ||
766 | }; | ||
710 | int status; | 767 | int status; |
711 | 768 | ||
712 | dprintk("NFS call fsstat\n"); | 769 | dprintk("NFS call fsstat\n"); |
713 | nfs_fattr_init(stat->fattr); | 770 | nfs_fattr_init(stat->fattr); |
714 | status = rpc_call(server->client, NFS3PROC_FSSTAT, fhandle, stat, 0); | 771 | status = rpc_call_sync(server->client, &msg, 0); |
715 | dprintk("NFS reply statfs: %d\n", status); | 772 | dprintk("NFS reply statfs: %d\n", status); |
716 | return status; | 773 | return status; |
717 | } | 774 | } |
@@ -720,11 +777,16 @@ static int | |||
720 | nfs3_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, | 777 | nfs3_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, |
721 | struct nfs_fsinfo *info) | 778 | struct nfs_fsinfo *info) |
722 | { | 779 | { |
780 | struct rpc_message msg = { | ||
781 | .rpc_proc = &nfs3_procedures[NFS3PROC_FSINFO], | ||
782 | .rpc_argp = fhandle, | ||
783 | .rpc_resp = info, | ||
784 | }; | ||
723 | int status; | 785 | int status; |
724 | 786 | ||
725 | dprintk("NFS call fsinfo\n"); | 787 | dprintk("NFS call fsinfo\n"); |
726 | nfs_fattr_init(info->fattr); | 788 | nfs_fattr_init(info->fattr); |
727 | status = rpc_call(server->client_sys, NFS3PROC_FSINFO, fhandle, info, 0); | 789 | status = rpc_call_sync(server->client_sys, &msg, 0); |
728 | dprintk("NFS reply fsinfo: %d\n", status); | 790 | dprintk("NFS reply fsinfo: %d\n", status); |
729 | return status; | 791 | return status; |
730 | } | 792 | } |
@@ -733,40 +795,34 @@ static int | |||
733 | nfs3_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, | 795 | nfs3_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, |
734 | struct nfs_pathconf *info) | 796 | struct nfs_pathconf *info) |
735 | { | 797 | { |
798 | struct rpc_message msg = { | ||
799 | .rpc_proc = &nfs3_procedures[NFS3PROC_PATHCONF], | ||
800 | .rpc_argp = fhandle, | ||
801 | .rpc_resp = info, | ||
802 | }; | ||
736 | int status; | 803 | int status; |
737 | 804 | ||
738 | dprintk("NFS call pathconf\n"); | 805 | dprintk("NFS call pathconf\n"); |
739 | nfs_fattr_init(info->fattr); | 806 | nfs_fattr_init(info->fattr); |
740 | status = rpc_call(server->client, NFS3PROC_PATHCONF, fhandle, info, 0); | 807 | status = rpc_call_sync(server->client, &msg, 0); |
741 | dprintk("NFS reply pathconf: %d\n", status); | 808 | dprintk("NFS reply pathconf: %d\n", status); |
742 | return status; | 809 | return status; |
743 | } | 810 | } |
744 | 811 | ||
745 | extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int); | 812 | extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int); |
746 | 813 | ||
747 | static void nfs3_read_done(struct rpc_task *task, void *calldata) | 814 | static int nfs3_read_done(struct rpc_task *task, struct nfs_read_data *data) |
748 | { | 815 | { |
749 | struct nfs_read_data *data = calldata; | 816 | if (nfs3_async_handle_jukebox(task, data->inode)) |
750 | 817 | return -EAGAIN; | |
751 | if (nfs3_async_handle_jukebox(task)) | ||
752 | return; | ||
753 | /* Call back common NFS readpage processing */ | 818 | /* Call back common NFS readpage processing */ |
754 | if (task->tk_status >= 0) | 819 | if (task->tk_status >= 0) |
755 | nfs_refresh_inode(data->inode, &data->fattr); | 820 | nfs_refresh_inode(data->inode, &data->fattr); |
756 | nfs_readpage_result(task, calldata); | 821 | return 0; |
757 | } | 822 | } |
758 | 823 | ||
759 | static const struct rpc_call_ops nfs3_read_ops = { | 824 | static void nfs3_proc_read_setup(struct nfs_read_data *data) |
760 | .rpc_call_done = nfs3_read_done, | ||
761 | .rpc_release = nfs_readdata_release, | ||
762 | }; | ||
763 | |||
764 | static void | ||
765 | nfs3_proc_read_setup(struct nfs_read_data *data) | ||
766 | { | 825 | { |
767 | struct rpc_task *task = &data->task; | ||
768 | struct inode *inode = data->inode; | ||
769 | int flags; | ||
770 | struct rpc_message msg = { | 826 | struct rpc_message msg = { |
771 | .rpc_proc = &nfs3_procedures[NFS3PROC_READ], | 827 | .rpc_proc = &nfs3_procedures[NFS3PROC_READ], |
772 | .rpc_argp = &data->args, | 828 | .rpc_argp = &data->args, |
@@ -774,37 +830,20 @@ nfs3_proc_read_setup(struct nfs_read_data *data) | |||
774 | .rpc_cred = data->cred, | 830 | .rpc_cred = data->cred, |
775 | }; | 831 | }; |
776 | 832 | ||
777 | /* N.B. Do we need to test? Never called for swapfile inode */ | 833 | rpc_call_setup(&data->task, &msg, 0); |
778 | flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); | ||
779 | |||
780 | /* Finalize the task. */ | ||
781 | rpc_init_task(task, NFS_CLIENT(inode), flags, &nfs3_read_ops, data); | ||
782 | rpc_call_setup(task, &msg, 0); | ||
783 | } | 834 | } |
784 | 835 | ||
785 | static void nfs3_write_done(struct rpc_task *task, void *calldata) | 836 | static int nfs3_write_done(struct rpc_task *task, struct nfs_write_data *data) |
786 | { | 837 | { |
787 | struct nfs_write_data *data = calldata; | 838 | if (nfs3_async_handle_jukebox(task, data->inode)) |
788 | 839 | return -EAGAIN; | |
789 | if (nfs3_async_handle_jukebox(task)) | ||
790 | return; | ||
791 | if (task->tk_status >= 0) | 840 | if (task->tk_status >= 0) |
792 | nfs_post_op_update_inode(data->inode, data->res.fattr); | 841 | nfs_post_op_update_inode(data->inode, data->res.fattr); |
793 | nfs_writeback_done(task, calldata); | 842 | return 0; |
794 | } | 843 | } |
795 | 844 | ||
796 | static const struct rpc_call_ops nfs3_write_ops = { | 845 | static void nfs3_proc_write_setup(struct nfs_write_data *data, int how) |
797 | .rpc_call_done = nfs3_write_done, | ||
798 | .rpc_release = nfs_writedata_release, | ||
799 | }; | ||
800 | |||
801 | static void | ||
802 | nfs3_proc_write_setup(struct nfs_write_data *data, int how) | ||
803 | { | 846 | { |
804 | struct rpc_task *task = &data->task; | ||
805 | struct inode *inode = data->inode; | ||
806 | int stable; | ||
807 | int flags; | ||
808 | struct rpc_message msg = { | 847 | struct rpc_message msg = { |
809 | .rpc_proc = &nfs3_procedures[NFS3PROC_WRITE], | 848 | .rpc_proc = &nfs3_procedures[NFS3PROC_WRITE], |
810 | .rpc_argp = &data->args, | 849 | .rpc_argp = &data->args, |
@@ -812,45 +851,28 @@ nfs3_proc_write_setup(struct nfs_write_data *data, int how) | |||
812 | .rpc_cred = data->cred, | 851 | .rpc_cred = data->cred, |
813 | }; | 852 | }; |
814 | 853 | ||
854 | data->args.stable = NFS_UNSTABLE; | ||
815 | if (how & FLUSH_STABLE) { | 855 | if (how & FLUSH_STABLE) { |
816 | if (!NFS_I(inode)->ncommit) | 856 | data->args.stable = NFS_FILE_SYNC; |
817 | stable = NFS_FILE_SYNC; | 857 | if (NFS_I(data->inode)->ncommit) |
818 | else | 858 | data->args.stable = NFS_DATA_SYNC; |
819 | stable = NFS_DATA_SYNC; | 859 | } |
820 | } else | ||
821 | stable = NFS_UNSTABLE; | ||
822 | data->args.stable = stable; | ||
823 | |||
824 | /* Set the initial flags for the task. */ | ||
825 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | ||
826 | 860 | ||
827 | /* Finalize the task. */ | 861 | /* Finalize the task. */ |
828 | rpc_init_task(task, NFS_CLIENT(inode), flags, &nfs3_write_ops, data); | 862 | rpc_call_setup(&data->task, &msg, 0); |
829 | rpc_call_setup(task, &msg, 0); | ||
830 | } | 863 | } |
831 | 864 | ||
832 | static void nfs3_commit_done(struct rpc_task *task, void *calldata) | 865 | static int nfs3_commit_done(struct rpc_task *task, struct nfs_write_data *data) |
833 | { | 866 | { |
834 | struct nfs_write_data *data = calldata; | 867 | if (nfs3_async_handle_jukebox(task, data->inode)) |
835 | 868 | return -EAGAIN; | |
836 | if (nfs3_async_handle_jukebox(task)) | ||
837 | return; | ||
838 | if (task->tk_status >= 0) | 869 | if (task->tk_status >= 0) |
839 | nfs_post_op_update_inode(data->inode, data->res.fattr); | 870 | nfs_post_op_update_inode(data->inode, data->res.fattr); |
840 | nfs_commit_done(task, calldata); | 871 | return 0; |
841 | } | 872 | } |
842 | 873 | ||
843 | static const struct rpc_call_ops nfs3_commit_ops = { | 874 | static void nfs3_proc_commit_setup(struct nfs_write_data *data, int how) |
844 | .rpc_call_done = nfs3_commit_done, | ||
845 | .rpc_release = nfs_commit_release, | ||
846 | }; | ||
847 | |||
848 | static void | ||
849 | nfs3_proc_commit_setup(struct nfs_write_data *data, int how) | ||
850 | { | 875 | { |
851 | struct rpc_task *task = &data->task; | ||
852 | struct inode *inode = data->inode; | ||
853 | int flags; | ||
854 | struct rpc_message msg = { | 876 | struct rpc_message msg = { |
855 | .rpc_proc = &nfs3_procedures[NFS3PROC_COMMIT], | 877 | .rpc_proc = &nfs3_procedures[NFS3PROC_COMMIT], |
856 | .rpc_argp = &data->args, | 878 | .rpc_argp = &data->args, |
@@ -858,12 +880,7 @@ nfs3_proc_commit_setup(struct nfs_write_data *data, int how) | |||
858 | .rpc_cred = data->cred, | 880 | .rpc_cred = data->cred, |
859 | }; | 881 | }; |
860 | 882 | ||
861 | /* Set the initial flags for the task. */ | 883 | rpc_call_setup(&data->task, &msg, 0); |
862 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | ||
863 | |||
864 | /* Finalize the task. */ | ||
865 | rpc_init_task(task, NFS_CLIENT(inode), flags, &nfs3_commit_ops, data); | ||
866 | rpc_call_setup(task, &msg, 0); | ||
867 | } | 884 | } |
868 | 885 | ||
869 | static int | 886 | static int |
@@ -902,8 +919,11 @@ struct nfs_rpc_ops nfs_v3_clientops = { | |||
902 | .pathconf = nfs3_proc_pathconf, | 919 | .pathconf = nfs3_proc_pathconf, |
903 | .decode_dirent = nfs3_decode_dirent, | 920 | .decode_dirent = nfs3_decode_dirent, |
904 | .read_setup = nfs3_proc_read_setup, | 921 | .read_setup = nfs3_proc_read_setup, |
922 | .read_done = nfs3_read_done, | ||
905 | .write_setup = nfs3_proc_write_setup, | 923 | .write_setup = nfs3_proc_write_setup, |
924 | .write_done = nfs3_write_done, | ||
906 | .commit_setup = nfs3_proc_commit_setup, | 925 | .commit_setup = nfs3_proc_commit_setup, |
926 | .commit_done = nfs3_commit_done, | ||
907 | .file_open = nfs_open, | 927 | .file_open = nfs_open, |
908 | .file_release = nfs_release, | 928 | .file_release = nfs_release, |
909 | .lock = nfs3_proc_lock, | 929 | .lock = nfs3_proc_lock, |
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index 5224a191efb6..ec233619687e 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c | |||
@@ -1109,7 +1109,9 @@ nfs3_xdr_setaclres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr) | |||
1109 | .p_encode = (kxdrproc_t) nfs3_xdr_##argtype, \ | 1109 | .p_encode = (kxdrproc_t) nfs3_xdr_##argtype, \ |
1110 | .p_decode = (kxdrproc_t) nfs3_xdr_##restype, \ | 1110 | .p_decode = (kxdrproc_t) nfs3_xdr_##restype, \ |
1111 | .p_bufsiz = MAX(NFS3_##argtype##_sz,NFS3_##restype##_sz) << 2, \ | 1111 | .p_bufsiz = MAX(NFS3_##argtype##_sz,NFS3_##restype##_sz) << 2, \ |
1112 | .p_timer = timer \ | 1112 | .p_timer = timer, \ |
1113 | .p_statidx = NFS3PROC_##proc, \ | ||
1114 | .p_name = #proc, \ | ||
1113 | } | 1115 | } |
1114 | 1116 | ||
1115 | struct rpc_procinfo nfs3_procedures[] = { | 1117 | struct rpc_procinfo nfs3_procedures[] = { |
@@ -1150,6 +1152,7 @@ static struct rpc_procinfo nfs3_acl_procedures[] = { | |||
1150 | .p_decode = (kxdrproc_t) nfs3_xdr_getaclres, | 1152 | .p_decode = (kxdrproc_t) nfs3_xdr_getaclres, |
1151 | .p_bufsiz = MAX(ACL3_getaclargs_sz, ACL3_getaclres_sz) << 2, | 1153 | .p_bufsiz = MAX(ACL3_getaclargs_sz, ACL3_getaclres_sz) << 2, |
1152 | .p_timer = 1, | 1154 | .p_timer = 1, |
1155 | .p_name = "GETACL", | ||
1153 | }, | 1156 | }, |
1154 | [ACLPROC3_SETACL] = { | 1157 | [ACLPROC3_SETACL] = { |
1155 | .p_proc = ACLPROC3_SETACL, | 1158 | .p_proc = ACLPROC3_SETACL, |
@@ -1157,6 +1160,7 @@ static struct rpc_procinfo nfs3_acl_procedures[] = { | |||
1157 | .p_decode = (kxdrproc_t) nfs3_xdr_setaclres, | 1160 | .p_decode = (kxdrproc_t) nfs3_xdr_setaclres, |
1158 | .p_bufsiz = MAX(ACL3_setaclargs_sz, ACL3_setaclres_sz) << 2, | 1161 | .p_bufsiz = MAX(ACL3_setaclargs_sz, ACL3_setaclres_sz) << 2, |
1159 | .p_timer = 0, | 1162 | .p_timer = 0, |
1163 | .p_name = "SETACL", | ||
1160 | }, | 1164 | }, |
1161 | }; | 1165 | }; |
1162 | 1166 | ||
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index f8c0066e02e1..47ece1dd3c67 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -51,6 +51,7 @@ | |||
51 | 51 | ||
52 | #include "nfs4_fs.h" | 52 | #include "nfs4_fs.h" |
53 | #include "delegation.h" | 53 | #include "delegation.h" |
54 | #include "iostat.h" | ||
54 | 55 | ||
55 | #define NFSDBG_FACILITY NFSDBG_PROC | 56 | #define NFSDBG_FACILITY NFSDBG_PROC |
56 | 57 | ||
@@ -335,7 +336,7 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data | |||
335 | if (!(data->f_attr.valid & NFS_ATTR_FATTR)) | 336 | if (!(data->f_attr.valid & NFS_ATTR_FATTR)) |
336 | goto out; | 337 | goto out; |
337 | inode = nfs_fhget(data->dir->d_sb, &data->o_res.fh, &data->f_attr); | 338 | inode = nfs_fhget(data->dir->d_sb, &data->o_res.fh, &data->f_attr); |
338 | if (inode == NULL) | 339 | if (IS_ERR(inode)) |
339 | goto out; | 340 | goto out; |
340 | state = nfs4_get_open_state(inode, data->owner); | 341 | state = nfs4_get_open_state(inode, data->owner); |
341 | if (state == NULL) | 342 | if (state == NULL) |
@@ -604,11 +605,14 @@ static int _nfs4_proc_open_confirm(struct nfs4_opendata *data) | |||
604 | int status; | 605 | int status; |
605 | 606 | ||
606 | atomic_inc(&data->count); | 607 | atomic_inc(&data->count); |
608 | /* | ||
609 | * If rpc_run_task() ends up calling ->rpc_release(), we | ||
610 | * want to ensure that it takes the 'error' code path. | ||
611 | */ | ||
612 | data->rpc_status = -ENOMEM; | ||
607 | task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_confirm_ops, data); | 613 | task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_confirm_ops, data); |
608 | if (IS_ERR(task)) { | 614 | if (IS_ERR(task)) |
609 | nfs4_opendata_free(data); | ||
610 | return PTR_ERR(task); | 615 | return PTR_ERR(task); |
611 | } | ||
612 | status = nfs4_wait_for_completion_rpc_task(task); | 616 | status = nfs4_wait_for_completion_rpc_task(task); |
613 | if (status != 0) { | 617 | if (status != 0) { |
614 | data->cancelled = 1; | 618 | data->cancelled = 1; |
@@ -707,11 +711,14 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) | |||
707 | int status; | 711 | int status; |
708 | 712 | ||
709 | atomic_inc(&data->count); | 713 | atomic_inc(&data->count); |
714 | /* | ||
715 | * If rpc_run_task() ends up calling ->rpc_release(), we | ||
716 | * want to ensure that it takes the 'error' code path. | ||
717 | */ | ||
718 | data->rpc_status = -ENOMEM; | ||
710 | task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_ops, data); | 719 | task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_ops, data); |
711 | if (IS_ERR(task)) { | 720 | if (IS_ERR(task)) |
712 | nfs4_opendata_free(data); | ||
713 | return PTR_ERR(task); | 721 | return PTR_ERR(task); |
714 | } | ||
715 | status = nfs4_wait_for_completion_rpc_task(task); | 722 | status = nfs4_wait_for_completion_rpc_task(task); |
716 | if (status != 0) { | 723 | if (status != 0) { |
717 | data->cancelled = 1; | 724 | data->cancelled = 1; |
@@ -908,7 +915,7 @@ out_put_state_owner: | |||
908 | static struct nfs4_state *nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred *cred) | 915 | static struct nfs4_state *nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred *cred) |
909 | { | 916 | { |
910 | struct nfs4_exception exception = { }; | 917 | struct nfs4_exception exception = { }; |
911 | struct nfs4_state *res; | 918 | struct nfs4_state *res = ERR_PTR(-EIO); |
912 | int err; | 919 | int err; |
913 | 920 | ||
914 | do { | 921 | do { |
@@ -1017,12 +1024,12 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, struct dentry *dentry, | |||
1017 | return res; | 1024 | return res; |
1018 | } | 1025 | } |
1019 | 1026 | ||
1020 | static int _nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, | 1027 | static int _nfs4_do_setattr(struct inode *inode, struct nfs_fattr *fattr, |
1021 | struct nfs_fh *fhandle, struct iattr *sattr, | 1028 | struct iattr *sattr, struct nfs4_state *state) |
1022 | struct nfs4_state *state) | ||
1023 | { | 1029 | { |
1030 | struct nfs_server *server = NFS_SERVER(inode); | ||
1024 | struct nfs_setattrargs arg = { | 1031 | struct nfs_setattrargs arg = { |
1025 | .fh = fhandle, | 1032 | .fh = NFS_FH(inode), |
1026 | .iap = sattr, | 1033 | .iap = sattr, |
1027 | .server = server, | 1034 | .server = server, |
1028 | .bitmask = server->attr_bitmask, | 1035 | .bitmask = server->attr_bitmask, |
@@ -1041,7 +1048,9 @@ static int _nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, | |||
1041 | 1048 | ||
1042 | nfs_fattr_init(fattr); | 1049 | nfs_fattr_init(fattr); |
1043 | 1050 | ||
1044 | if (state != NULL) { | 1051 | if (nfs4_copy_delegation_stateid(&arg.stateid, inode)) { |
1052 | /* Use that stateid */ | ||
1053 | } else if (state != NULL) { | ||
1045 | msg.rpc_cred = state->owner->so_cred; | 1054 | msg.rpc_cred = state->owner->so_cred; |
1046 | nfs4_copy_stateid(&arg.stateid, state, current->files); | 1055 | nfs4_copy_stateid(&arg.stateid, state, current->files); |
1047 | } else | 1056 | } else |
@@ -1053,16 +1062,15 @@ static int _nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, | |||
1053 | return status; | 1062 | return status; |
1054 | } | 1063 | } |
1055 | 1064 | ||
1056 | static int nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, | 1065 | static int nfs4_do_setattr(struct inode *inode, struct nfs_fattr *fattr, |
1057 | struct nfs_fh *fhandle, struct iattr *sattr, | 1066 | struct iattr *sattr, struct nfs4_state *state) |
1058 | struct nfs4_state *state) | ||
1059 | { | 1067 | { |
1068 | struct nfs_server *server = NFS_SERVER(inode); | ||
1060 | struct nfs4_exception exception = { }; | 1069 | struct nfs4_exception exception = { }; |
1061 | int err; | 1070 | int err; |
1062 | do { | 1071 | do { |
1063 | err = nfs4_handle_exception(server, | 1072 | err = nfs4_handle_exception(server, |
1064 | _nfs4_do_setattr(server, fattr, fhandle, sattr, | 1073 | _nfs4_do_setattr(inode, fattr, sattr, state), |
1065 | state), | ||
1066 | &exception); | 1074 | &exception); |
1067 | } while (exception.retry); | 1075 | } while (exception.retry); |
1068 | return err; | 1076 | return err; |
@@ -1503,8 +1511,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | |||
1503 | if (ctx != NULL) | 1511 | if (ctx != NULL) |
1504 | state = ctx->state; | 1512 | state = ctx->state; |
1505 | 1513 | ||
1506 | status = nfs4_do_setattr(NFS_SERVER(inode), fattr, | 1514 | status = nfs4_do_setattr(inode, fattr, sattr, state); |
1507 | NFS_FH(inode), sattr, state); | ||
1508 | if (status == 0) | 1515 | if (status == 0) |
1509 | nfs_setattr_update_inode(inode, sattr); | 1516 | nfs_setattr_update_inode(inode, sattr); |
1510 | if (ctx != NULL) | 1517 | if (ctx != NULL) |
@@ -1823,8 +1830,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
1823 | d_instantiate(dentry, igrab(state->inode)); | 1830 | d_instantiate(dentry, igrab(state->inode)); |
1824 | if (flags & O_EXCL) { | 1831 | if (flags & O_EXCL) { |
1825 | struct nfs_fattr fattr; | 1832 | struct nfs_fattr fattr; |
1826 | status = nfs4_do_setattr(NFS_SERVER(dir), &fattr, | 1833 | status = nfs4_do_setattr(state->inode, &fattr, sattr, state); |
1827 | NFS_FH(state->inode), sattr, state); | ||
1828 | if (status == 0) | 1834 | if (status == 0) |
1829 | nfs_setattr_update_inode(state->inode, sattr); | 1835 | nfs_setattr_update_inode(state->inode, sattr); |
1830 | } | 1836 | } |
@@ -2344,75 +2350,50 @@ static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, | |||
2344 | return err; | 2350 | return err; |
2345 | } | 2351 | } |
2346 | 2352 | ||
2347 | static void nfs4_read_done(struct rpc_task *task, void *calldata) | 2353 | static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data) |
2348 | { | 2354 | { |
2349 | struct nfs_read_data *data = calldata; | 2355 | struct nfs_server *server = NFS_SERVER(data->inode); |
2350 | struct inode *inode = data->inode; | ||
2351 | 2356 | ||
2352 | if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) { | 2357 | if (nfs4_async_handle_error(task, server) == -EAGAIN) { |
2353 | rpc_restart_call(task); | 2358 | rpc_restart_call(task); |
2354 | return; | 2359 | return -EAGAIN; |
2355 | } | 2360 | } |
2356 | if (task->tk_status > 0) | 2361 | if (task->tk_status > 0) |
2357 | renew_lease(NFS_SERVER(inode), data->timestamp); | 2362 | renew_lease(server, data->timestamp); |
2358 | /* Call back common NFS readpage processing */ | 2363 | return 0; |
2359 | nfs_readpage_result(task, calldata); | ||
2360 | } | 2364 | } |
2361 | 2365 | ||
2362 | static const struct rpc_call_ops nfs4_read_ops = { | 2366 | static void nfs4_proc_read_setup(struct nfs_read_data *data) |
2363 | .rpc_call_done = nfs4_read_done, | ||
2364 | .rpc_release = nfs_readdata_release, | ||
2365 | }; | ||
2366 | |||
2367 | static void | ||
2368 | nfs4_proc_read_setup(struct nfs_read_data *data) | ||
2369 | { | 2367 | { |
2370 | struct rpc_task *task = &data->task; | ||
2371 | struct rpc_message msg = { | 2368 | struct rpc_message msg = { |
2372 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ], | 2369 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ], |
2373 | .rpc_argp = &data->args, | 2370 | .rpc_argp = &data->args, |
2374 | .rpc_resp = &data->res, | 2371 | .rpc_resp = &data->res, |
2375 | .rpc_cred = data->cred, | 2372 | .rpc_cred = data->cred, |
2376 | }; | 2373 | }; |
2377 | struct inode *inode = data->inode; | ||
2378 | int flags; | ||
2379 | 2374 | ||
2380 | data->timestamp = jiffies; | 2375 | data->timestamp = jiffies; |
2381 | 2376 | ||
2382 | /* N.B. Do we need to test? Never called for swapfile inode */ | 2377 | rpc_call_setup(&data->task, &msg, 0); |
2383 | flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); | ||
2384 | |||
2385 | /* Finalize the task. */ | ||
2386 | rpc_init_task(task, NFS_CLIENT(inode), flags, &nfs4_read_ops, data); | ||
2387 | rpc_call_setup(task, &msg, 0); | ||
2388 | } | 2378 | } |
2389 | 2379 | ||
2390 | static void nfs4_write_done(struct rpc_task *task, void *calldata) | 2380 | static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) |
2391 | { | 2381 | { |
2392 | struct nfs_write_data *data = calldata; | ||
2393 | struct inode *inode = data->inode; | 2382 | struct inode *inode = data->inode; |
2394 | 2383 | ||
2395 | if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) { | 2384 | if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) { |
2396 | rpc_restart_call(task); | 2385 | rpc_restart_call(task); |
2397 | return; | 2386 | return -EAGAIN; |
2398 | } | 2387 | } |
2399 | if (task->tk_status >= 0) { | 2388 | if (task->tk_status >= 0) { |
2400 | renew_lease(NFS_SERVER(inode), data->timestamp); | 2389 | renew_lease(NFS_SERVER(inode), data->timestamp); |
2401 | nfs_post_op_update_inode(inode, data->res.fattr); | 2390 | nfs_post_op_update_inode(inode, data->res.fattr); |
2402 | } | 2391 | } |
2403 | /* Call back common NFS writeback processing */ | 2392 | return 0; |
2404 | nfs_writeback_done(task, calldata); | ||
2405 | } | 2393 | } |
2406 | 2394 | ||
2407 | static const struct rpc_call_ops nfs4_write_ops = { | 2395 | static void nfs4_proc_write_setup(struct nfs_write_data *data, int how) |
2408 | .rpc_call_done = nfs4_write_done, | ||
2409 | .rpc_release = nfs_writedata_release, | ||
2410 | }; | ||
2411 | |||
2412 | static void | ||
2413 | nfs4_proc_write_setup(struct nfs_write_data *data, int how) | ||
2414 | { | 2396 | { |
2415 | struct rpc_task *task = &data->task; | ||
2416 | struct rpc_message msg = { | 2397 | struct rpc_message msg = { |
2417 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE], | 2398 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE], |
2418 | .rpc_argp = &data->args, | 2399 | .rpc_argp = &data->args, |
@@ -2422,7 +2403,6 @@ nfs4_proc_write_setup(struct nfs_write_data *data, int how) | |||
2422 | struct inode *inode = data->inode; | 2403 | struct inode *inode = data->inode; |
2423 | struct nfs_server *server = NFS_SERVER(inode); | 2404 | struct nfs_server *server = NFS_SERVER(inode); |
2424 | int stable; | 2405 | int stable; |
2425 | int flags; | ||
2426 | 2406 | ||
2427 | if (how & FLUSH_STABLE) { | 2407 | if (how & FLUSH_STABLE) { |
2428 | if (!NFS_I(inode)->ncommit) | 2408 | if (!NFS_I(inode)->ncommit) |
@@ -2437,57 +2417,37 @@ nfs4_proc_write_setup(struct nfs_write_data *data, int how) | |||
2437 | 2417 | ||
2438 | data->timestamp = jiffies; | 2418 | data->timestamp = jiffies; |
2439 | 2419 | ||
2440 | /* Set the initial flags for the task. */ | ||
2441 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | ||
2442 | |||
2443 | /* Finalize the task. */ | 2420 | /* Finalize the task. */ |
2444 | rpc_init_task(task, NFS_CLIENT(inode), flags, &nfs4_write_ops, data); | 2421 | rpc_call_setup(&data->task, &msg, 0); |
2445 | rpc_call_setup(task, &msg, 0); | ||
2446 | } | 2422 | } |
2447 | 2423 | ||
2448 | static void nfs4_commit_done(struct rpc_task *task, void *calldata) | 2424 | static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data) |
2449 | { | 2425 | { |
2450 | struct nfs_write_data *data = calldata; | ||
2451 | struct inode *inode = data->inode; | 2426 | struct inode *inode = data->inode; |
2452 | 2427 | ||
2453 | if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) { | 2428 | if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) { |
2454 | rpc_restart_call(task); | 2429 | rpc_restart_call(task); |
2455 | return; | 2430 | return -EAGAIN; |
2456 | } | 2431 | } |
2457 | if (task->tk_status >= 0) | 2432 | if (task->tk_status >= 0) |
2458 | nfs_post_op_update_inode(inode, data->res.fattr); | 2433 | nfs_post_op_update_inode(inode, data->res.fattr); |
2459 | /* Call back common NFS writeback processing */ | 2434 | return 0; |
2460 | nfs_commit_done(task, calldata); | ||
2461 | } | 2435 | } |
2462 | 2436 | ||
2463 | static const struct rpc_call_ops nfs4_commit_ops = { | 2437 | static void nfs4_proc_commit_setup(struct nfs_write_data *data, int how) |
2464 | .rpc_call_done = nfs4_commit_done, | ||
2465 | .rpc_release = nfs_commit_release, | ||
2466 | }; | ||
2467 | |||
2468 | static void | ||
2469 | nfs4_proc_commit_setup(struct nfs_write_data *data, int how) | ||
2470 | { | 2438 | { |
2471 | struct rpc_task *task = &data->task; | ||
2472 | struct rpc_message msg = { | 2439 | struct rpc_message msg = { |
2473 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT], | 2440 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT], |
2474 | .rpc_argp = &data->args, | 2441 | .rpc_argp = &data->args, |
2475 | .rpc_resp = &data->res, | 2442 | .rpc_resp = &data->res, |
2476 | .rpc_cred = data->cred, | 2443 | .rpc_cred = data->cred, |
2477 | }; | 2444 | }; |
2478 | struct inode *inode = data->inode; | 2445 | struct nfs_server *server = NFS_SERVER(data->inode); |
2479 | struct nfs_server *server = NFS_SERVER(inode); | ||
2480 | int flags; | ||
2481 | 2446 | ||
2482 | data->args.bitmask = server->attr_bitmask; | 2447 | data->args.bitmask = server->attr_bitmask; |
2483 | data->res.server = server; | 2448 | data->res.server = server; |
2484 | 2449 | ||
2485 | /* Set the initial flags for the task. */ | 2450 | rpc_call_setup(&data->task, &msg, 0); |
2486 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | ||
2487 | |||
2488 | /* Finalize the task. */ | ||
2489 | rpc_init_task(task, NFS_CLIENT(inode), flags, &nfs4_commit_ops, data); | ||
2490 | rpc_call_setup(task, &msg, 0); | ||
2491 | } | 2451 | } |
2492 | 2452 | ||
2493 | /* | 2453 | /* |
@@ -2755,8 +2715,10 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server) | |||
2755 | rpc_wake_up_task(task); | 2715 | rpc_wake_up_task(task); |
2756 | task->tk_status = 0; | 2716 | task->tk_status = 0; |
2757 | return -EAGAIN; | 2717 | return -EAGAIN; |
2758 | case -NFS4ERR_GRACE: | ||
2759 | case -NFS4ERR_DELAY: | 2718 | case -NFS4ERR_DELAY: |
2719 | nfs_inc_server_stats((struct nfs_server *) server, | ||
2720 | NFSIOS_DELAY); | ||
2721 | case -NFS4ERR_GRACE: | ||
2760 | rpc_delay(task, NFS4_POLL_RETRY_MAX); | 2722 | rpc_delay(task, NFS4_POLL_RETRY_MAX); |
2761 | task->tk_status = 0; | 2723 | task->tk_status = 0; |
2762 | return -EAGAIN; | 2724 | return -EAGAIN; |
@@ -2893,8 +2855,7 @@ int nfs4_proc_setclientid(struct nfs4_client *clp, u32 program, unsigned short p | |||
2893 | return status; | 2855 | return status; |
2894 | } | 2856 | } |
2895 | 2857 | ||
2896 | int | 2858 | static int _nfs4_proc_setclientid_confirm(struct nfs4_client *clp, struct rpc_cred *cred) |
2897 | nfs4_proc_setclientid_confirm(struct nfs4_client *clp, struct rpc_cred *cred) | ||
2898 | { | 2859 | { |
2899 | struct nfs_fsinfo fsinfo; | 2860 | struct nfs_fsinfo fsinfo; |
2900 | struct rpc_message msg = { | 2861 | struct rpc_message msg = { |
@@ -2918,6 +2879,24 @@ nfs4_proc_setclientid_confirm(struct nfs4_client *clp, struct rpc_cred *cred) | |||
2918 | return status; | 2879 | return status; |
2919 | } | 2880 | } |
2920 | 2881 | ||
2882 | int nfs4_proc_setclientid_confirm(struct nfs4_client *clp, struct rpc_cred *cred) | ||
2883 | { | ||
2884 | long timeout; | ||
2885 | int err; | ||
2886 | do { | ||
2887 | err = _nfs4_proc_setclientid_confirm(clp, cred); | ||
2888 | switch (err) { | ||
2889 | case 0: | ||
2890 | return err; | ||
2891 | case -NFS4ERR_RESOURCE: | ||
2892 | /* The IBM lawyers misread another document! */ | ||
2893 | case -NFS4ERR_DELAY: | ||
2894 | err = nfs4_delay(clp->cl_rpcclient, &timeout); | ||
2895 | } | ||
2896 | } while (err == 0); | ||
2897 | return err; | ||
2898 | } | ||
2899 | |||
2921 | struct nfs4_delegreturndata { | 2900 | struct nfs4_delegreturndata { |
2922 | struct nfs4_delegreturnargs args; | 2901 | struct nfs4_delegreturnargs args; |
2923 | struct nfs4_delegreturnres res; | 2902 | struct nfs4_delegreturnres res; |
@@ -2958,7 +2937,7 @@ static void nfs4_delegreturn_release(void *calldata) | |||
2958 | kfree(calldata); | 2937 | kfree(calldata); |
2959 | } | 2938 | } |
2960 | 2939 | ||
2961 | const static struct rpc_call_ops nfs4_delegreturn_ops = { | 2940 | static const struct rpc_call_ops nfs4_delegreturn_ops = { |
2962 | .rpc_call_prepare = nfs4_delegreturn_prepare, | 2941 | .rpc_call_prepare = nfs4_delegreturn_prepare, |
2963 | .rpc_call_done = nfs4_delegreturn_done, | 2942 | .rpc_call_done = nfs4_delegreturn_done, |
2964 | .rpc_release = nfs4_delegreturn_release, | 2943 | .rpc_release = nfs4_delegreturn_release, |
@@ -2986,10 +2965,8 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co | |||
2986 | data->rpc_status = 0; | 2965 | data->rpc_status = 0; |
2987 | 2966 | ||
2988 | task = rpc_run_task(NFS_CLIENT(inode), RPC_TASK_ASYNC, &nfs4_delegreturn_ops, data); | 2967 | task = rpc_run_task(NFS_CLIENT(inode), RPC_TASK_ASYNC, &nfs4_delegreturn_ops, data); |
2989 | if (IS_ERR(task)) { | 2968 | if (IS_ERR(task)) |
2990 | nfs4_delegreturn_release(data); | ||
2991 | return PTR_ERR(task); | 2969 | return PTR_ERR(task); |
2992 | } | ||
2993 | status = nfs4_wait_for_completion_rpc_task(task); | 2970 | status = nfs4_wait_for_completion_rpc_task(task); |
2994 | if (status == 0) { | 2971 | if (status == 0) { |
2995 | status = data->rpc_status; | 2972 | status = data->rpc_status; |
@@ -3209,7 +3186,6 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl, | |||
3209 | struct nfs_seqid *seqid) | 3186 | struct nfs_seqid *seqid) |
3210 | { | 3187 | { |
3211 | struct nfs4_unlockdata *data; | 3188 | struct nfs4_unlockdata *data; |
3212 | struct rpc_task *task; | ||
3213 | 3189 | ||
3214 | data = nfs4_alloc_unlockdata(fl, ctx, lsp, seqid); | 3190 | data = nfs4_alloc_unlockdata(fl, ctx, lsp, seqid); |
3215 | if (data == NULL) { | 3191 | if (data == NULL) { |
@@ -3219,10 +3195,7 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl, | |||
3219 | 3195 | ||
3220 | /* Unlock _before_ we do the RPC call */ | 3196 | /* Unlock _before_ we do the RPC call */ |
3221 | do_vfs_lock(fl->fl_file, fl); | 3197 | do_vfs_lock(fl->fl_file, fl); |
3222 | task = rpc_run_task(NFS_CLIENT(lsp->ls_state->inode), RPC_TASK_ASYNC, &nfs4_locku_ops, data); | 3198 | return rpc_run_task(NFS_CLIENT(lsp->ls_state->inode), RPC_TASK_ASYNC, &nfs4_locku_ops, data); |
3223 | if (IS_ERR(task)) | ||
3224 | nfs4_locku_release_calldata(data); | ||
3225 | return task; | ||
3226 | } | 3199 | } |
3227 | 3200 | ||
3228 | static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request) | 3201 | static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request) |
@@ -3403,10 +3376,8 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f | |||
3403 | data->arg.reclaim = 1; | 3376 | data->arg.reclaim = 1; |
3404 | task = rpc_run_task(NFS_CLIENT(state->inode), RPC_TASK_ASYNC, | 3377 | task = rpc_run_task(NFS_CLIENT(state->inode), RPC_TASK_ASYNC, |
3405 | &nfs4_lock_ops, data); | 3378 | &nfs4_lock_ops, data); |
3406 | if (IS_ERR(task)) { | 3379 | if (IS_ERR(task)) |
3407 | nfs4_lock_release(data); | ||
3408 | return PTR_ERR(task); | 3380 | return PTR_ERR(task); |
3409 | } | ||
3410 | ret = nfs4_wait_for_completion_rpc_task(task); | 3381 | ret = nfs4_wait_for_completion_rpc_task(task); |
3411 | if (ret == 0) { | 3382 | if (ret == 0) { |
3412 | ret = data->rpc_status; | 3383 | ret = data->rpc_status; |
@@ -3588,6 +3559,8 @@ ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen) | |||
3588 | { | 3559 | { |
3589 | size_t len = strlen(XATTR_NAME_NFSV4_ACL) + 1; | 3560 | size_t len = strlen(XATTR_NAME_NFSV4_ACL) + 1; |
3590 | 3561 | ||
3562 | if (!nfs4_server_supports_acls(NFS_SERVER(dentry->d_inode))) | ||
3563 | return 0; | ||
3591 | if (buf && buflen < len) | 3564 | if (buf && buflen < len) |
3592 | return -ERANGE; | 3565 | return -ERANGE; |
3593 | if (buf) | 3566 | if (buf) |
@@ -3644,8 +3617,11 @@ struct nfs_rpc_ops nfs_v4_clientops = { | |||
3644 | .pathconf = nfs4_proc_pathconf, | 3617 | .pathconf = nfs4_proc_pathconf, |
3645 | .decode_dirent = nfs4_decode_dirent, | 3618 | .decode_dirent = nfs4_decode_dirent, |
3646 | .read_setup = nfs4_proc_read_setup, | 3619 | .read_setup = nfs4_proc_read_setup, |
3620 | .read_done = nfs4_read_done, | ||
3647 | .write_setup = nfs4_proc_write_setup, | 3621 | .write_setup = nfs4_proc_write_setup, |
3622 | .write_done = nfs4_write_done, | ||
3648 | .commit_setup = nfs4_proc_commit_setup, | 3623 | .commit_setup = nfs4_proc_commit_setup, |
3624 | .commit_done = nfs4_commit_done, | ||
3649 | .file_open = nfs_open, | 3625 | .file_open = nfs_open, |
3650 | .file_release = nfs_release, | 3626 | .file_release = nfs_release, |
3651 | .lock = nfs4_proc_lock, | 3627 | .lock = nfs4_proc_lock, |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index afad0255e7db..96e5b82c153b 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -977,6 +977,7 @@ out: | |||
977 | out_error: | 977 | out_error: |
978 | printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %u.%u.%u.%u with error %d\n", | 978 | printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %u.%u.%u.%u with error %d\n", |
979 | NIPQUAD(clp->cl_addr.s_addr), -status); | 979 | NIPQUAD(clp->cl_addr.s_addr), -status); |
980 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
980 | goto out; | 981 | goto out; |
981 | } | 982 | } |
982 | 983 | ||
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 0a1bd36a4837..7c5d70efe720 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -4344,6 +4344,8 @@ nfs_stat_to_errno(int stat) | |||
4344 | .p_encode = (kxdrproc_t) nfs4_xdr_##argtype, \ | 4344 | .p_encode = (kxdrproc_t) nfs4_xdr_##argtype, \ |
4345 | .p_decode = (kxdrproc_t) nfs4_xdr_##restype, \ | 4345 | .p_decode = (kxdrproc_t) nfs4_xdr_##restype, \ |
4346 | .p_bufsiz = MAX(NFS4_##argtype##_sz,NFS4_##restype##_sz) << 2, \ | 4346 | .p_bufsiz = MAX(NFS4_##argtype##_sz,NFS4_##restype##_sz) << 2, \ |
4347 | .p_statidx = NFSPROC4_CLNT_##proc, \ | ||
4348 | .p_name = #proc, \ | ||
4347 | } | 4349 | } |
4348 | 4350 | ||
4349 | struct rpc_procinfo nfs4_procedures[] = { | 4351 | struct rpc_procinfo nfs4_procedures[] = { |
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index d53857b148e2..106aca388ebc 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c | |||
@@ -85,6 +85,9 @@ nfs_create_request(struct nfs_open_context *ctx, struct inode *inode, | |||
85 | atomic_set(&req->wb_complete, 0); | 85 | atomic_set(&req->wb_complete, 0); |
86 | req->wb_index = page->index; | 86 | req->wb_index = page->index; |
87 | page_cache_get(page); | 87 | page_cache_get(page); |
88 | BUG_ON(PagePrivate(page)); | ||
89 | BUG_ON(!PageLocked(page)); | ||
90 | BUG_ON(page->mapping->host != inode); | ||
88 | req->wb_offset = offset; | 91 | req->wb_offset = offset; |
89 | req->wb_pgbase = offset; | 92 | req->wb_pgbase = offset; |
90 | req->wb_bytes = count; | 93 | req->wb_bytes = count; |
@@ -132,9 +135,11 @@ void nfs_clear_page_writeback(struct nfs_page *req) | |||
132 | { | 135 | { |
133 | struct nfs_inode *nfsi = NFS_I(req->wb_context->dentry->d_inode); | 136 | struct nfs_inode *nfsi = NFS_I(req->wb_context->dentry->d_inode); |
134 | 137 | ||
135 | spin_lock(&nfsi->req_lock); | 138 | if (req->wb_page != NULL) { |
136 | radix_tree_tag_clear(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_WRITEBACK); | 139 | spin_lock(&nfsi->req_lock); |
137 | spin_unlock(&nfsi->req_lock); | 140 | radix_tree_tag_clear(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_WRITEBACK); |
141 | spin_unlock(&nfsi->req_lock); | ||
142 | } | ||
138 | nfs_unlock_request(req); | 143 | nfs_unlock_request(req); |
139 | } | 144 | } |
140 | 145 | ||
@@ -147,8 +152,9 @@ void nfs_clear_page_writeback(struct nfs_page *req) | |||
147 | */ | 152 | */ |
148 | void nfs_clear_request(struct nfs_page *req) | 153 | void nfs_clear_request(struct nfs_page *req) |
149 | { | 154 | { |
150 | if (req->wb_page) { | 155 | struct page *page = req->wb_page; |
151 | page_cache_release(req->wb_page); | 156 | if (page != NULL) { |
157 | page_cache_release(page); | ||
152 | req->wb_page = NULL; | 158 | req->wb_page = NULL; |
153 | } | 159 | } |
154 | } | 160 | } |
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index f5150d71c03d..9dd85cac2df0 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c | |||
@@ -58,16 +58,23 @@ nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, | |||
58 | { | 58 | { |
59 | struct nfs_fattr *fattr = info->fattr; | 59 | struct nfs_fattr *fattr = info->fattr; |
60 | struct nfs2_fsstat fsinfo; | 60 | struct nfs2_fsstat fsinfo; |
61 | struct rpc_message msg = { | ||
62 | .rpc_proc = &nfs_procedures[NFSPROC_GETATTR], | ||
63 | .rpc_argp = fhandle, | ||
64 | .rpc_resp = fattr, | ||
65 | }; | ||
61 | int status; | 66 | int status; |
62 | 67 | ||
63 | dprintk("%s: call getattr\n", __FUNCTION__); | 68 | dprintk("%s: call getattr\n", __FUNCTION__); |
64 | nfs_fattr_init(fattr); | 69 | nfs_fattr_init(fattr); |
65 | status = rpc_call(server->client_sys, NFSPROC_GETATTR, fhandle, fattr, 0); | 70 | status = rpc_call_sync(server->client_sys, &msg, 0); |
66 | dprintk("%s: reply getattr: %d\n", __FUNCTION__, status); | 71 | dprintk("%s: reply getattr: %d\n", __FUNCTION__, status); |
67 | if (status) | 72 | if (status) |
68 | return status; | 73 | return status; |
69 | dprintk("%s: call statfs\n", __FUNCTION__); | 74 | dprintk("%s: call statfs\n", __FUNCTION__); |
70 | status = rpc_call(server->client_sys, NFSPROC_STATFS, fhandle, &fsinfo, 0); | 75 | msg.rpc_proc = &nfs_procedures[NFSPROC_STATFS]; |
76 | msg.rpc_resp = &fsinfo; | ||
77 | status = rpc_call_sync(server->client_sys, &msg, 0); | ||
71 | dprintk("%s: reply statfs: %d\n", __FUNCTION__, status); | 78 | dprintk("%s: reply statfs: %d\n", __FUNCTION__, status); |
72 | if (status) | 79 | if (status) |
73 | return status; | 80 | return status; |
@@ -90,12 +97,16 @@ static int | |||
90 | nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, | 97 | nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, |
91 | struct nfs_fattr *fattr) | 98 | struct nfs_fattr *fattr) |
92 | { | 99 | { |
100 | struct rpc_message msg = { | ||
101 | .rpc_proc = &nfs_procedures[NFSPROC_GETATTR], | ||
102 | .rpc_argp = fhandle, | ||
103 | .rpc_resp = fattr, | ||
104 | }; | ||
93 | int status; | 105 | int status; |
94 | 106 | ||
95 | dprintk("NFS call getattr\n"); | 107 | dprintk("NFS call getattr\n"); |
96 | nfs_fattr_init(fattr); | 108 | nfs_fattr_init(fattr); |
97 | status = rpc_call(server->client, NFSPROC_GETATTR, | 109 | status = rpc_call_sync(server->client, &msg, 0); |
98 | fhandle, fattr, 0); | ||
99 | dprintk("NFS reply getattr: %d\n", status); | 110 | dprintk("NFS reply getattr: %d\n", status); |
100 | return status; | 111 | return status; |
101 | } | 112 | } |
@@ -109,6 +120,11 @@ nfs_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | |||
109 | .fh = NFS_FH(inode), | 120 | .fh = NFS_FH(inode), |
110 | .sattr = sattr | 121 | .sattr = sattr |
111 | }; | 122 | }; |
123 | struct rpc_message msg = { | ||
124 | .rpc_proc = &nfs_procedures[NFSPROC_SETATTR], | ||
125 | .rpc_argp = &arg, | ||
126 | .rpc_resp = fattr, | ||
127 | }; | ||
112 | int status; | 128 | int status; |
113 | 129 | ||
114 | /* Mask out the non-modebit related stuff from attr->ia_mode */ | 130 | /* Mask out the non-modebit related stuff from attr->ia_mode */ |
@@ -116,7 +132,7 @@ nfs_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | |||
116 | 132 | ||
117 | dprintk("NFS call setattr\n"); | 133 | dprintk("NFS call setattr\n"); |
118 | nfs_fattr_init(fattr); | 134 | nfs_fattr_init(fattr); |
119 | status = rpc_call(NFS_CLIENT(inode), NFSPROC_SETATTR, &arg, fattr, 0); | 135 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); |
120 | if (status == 0) | 136 | if (status == 0) |
121 | nfs_setattr_update_inode(inode, sattr); | 137 | nfs_setattr_update_inode(inode, sattr); |
122 | dprintk("NFS reply setattr: %d\n", status); | 138 | dprintk("NFS reply setattr: %d\n", status); |
@@ -136,11 +152,16 @@ nfs_proc_lookup(struct inode *dir, struct qstr *name, | |||
136 | .fh = fhandle, | 152 | .fh = fhandle, |
137 | .fattr = fattr | 153 | .fattr = fattr |
138 | }; | 154 | }; |
155 | struct rpc_message msg = { | ||
156 | .rpc_proc = &nfs_procedures[NFSPROC_LOOKUP], | ||
157 | .rpc_argp = &arg, | ||
158 | .rpc_resp = &res, | ||
159 | }; | ||
139 | int status; | 160 | int status; |
140 | 161 | ||
141 | dprintk("NFS call lookup %s\n", name->name); | 162 | dprintk("NFS call lookup %s\n", name->name); |
142 | nfs_fattr_init(fattr); | 163 | nfs_fattr_init(fattr); |
143 | status = rpc_call(NFS_CLIENT(dir), NFSPROC_LOOKUP, &arg, &res, 0); | 164 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
144 | dprintk("NFS reply lookup: %d\n", status); | 165 | dprintk("NFS reply lookup: %d\n", status); |
145 | return status; | 166 | return status; |
146 | } | 167 | } |
@@ -154,10 +175,14 @@ static int nfs_proc_readlink(struct inode *inode, struct page *page, | |||
154 | .pglen = pglen, | 175 | .pglen = pglen, |
155 | .pages = &page | 176 | .pages = &page |
156 | }; | 177 | }; |
178 | struct rpc_message msg = { | ||
179 | .rpc_proc = &nfs_procedures[NFSPROC_READLINK], | ||
180 | .rpc_argp = &args, | ||
181 | }; | ||
157 | int status; | 182 | int status; |
158 | 183 | ||
159 | dprintk("NFS call readlink\n"); | 184 | dprintk("NFS call readlink\n"); |
160 | status = rpc_call(NFS_CLIENT(inode), NFSPROC_READLINK, &args, NULL, 0); | 185 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); |
161 | dprintk("NFS reply readlink: %d\n", status); | 186 | dprintk("NFS reply readlink: %d\n", status); |
162 | return status; | 187 | return status; |
163 | } | 188 | } |
@@ -233,11 +258,16 @@ nfs_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
233 | .fh = &fhandle, | 258 | .fh = &fhandle, |
234 | .fattr = &fattr | 259 | .fattr = &fattr |
235 | }; | 260 | }; |
261 | struct rpc_message msg = { | ||
262 | .rpc_proc = &nfs_procedures[NFSPROC_CREATE], | ||
263 | .rpc_argp = &arg, | ||
264 | .rpc_resp = &res, | ||
265 | }; | ||
236 | int status; | 266 | int status; |
237 | 267 | ||
238 | nfs_fattr_init(&fattr); | 268 | nfs_fattr_init(&fattr); |
239 | dprintk("NFS call create %s\n", dentry->d_name.name); | 269 | dprintk("NFS call create %s\n", dentry->d_name.name); |
240 | status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 0); | 270 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
241 | if (status == 0) | 271 | if (status == 0) |
242 | status = nfs_instantiate(dentry, &fhandle, &fattr); | 272 | status = nfs_instantiate(dentry, &fhandle, &fattr); |
243 | dprintk("NFS reply create: %d\n", status); | 273 | dprintk("NFS reply create: %d\n", status); |
@@ -263,6 +293,11 @@ nfs_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
263 | .fh = &fhandle, | 293 | .fh = &fhandle, |
264 | .fattr = &fattr | 294 | .fattr = &fattr |
265 | }; | 295 | }; |
296 | struct rpc_message msg = { | ||
297 | .rpc_proc = &nfs_procedures[NFSPROC_CREATE], | ||
298 | .rpc_argp = &arg, | ||
299 | .rpc_resp = &res, | ||
300 | }; | ||
266 | int status, mode; | 301 | int status, mode; |
267 | 302 | ||
268 | dprintk("NFS call mknod %s\n", dentry->d_name.name); | 303 | dprintk("NFS call mknod %s\n", dentry->d_name.name); |
@@ -277,13 +312,13 @@ nfs_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
277 | } | 312 | } |
278 | 313 | ||
279 | nfs_fattr_init(&fattr); | 314 | nfs_fattr_init(&fattr); |
280 | status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 0); | 315 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
281 | nfs_mark_for_revalidate(dir); | 316 | nfs_mark_for_revalidate(dir); |
282 | 317 | ||
283 | if (status == -EINVAL && S_ISFIFO(mode)) { | 318 | if (status == -EINVAL && S_ISFIFO(mode)) { |
284 | sattr->ia_mode = mode; | 319 | sattr->ia_mode = mode; |
285 | nfs_fattr_init(&fattr); | 320 | nfs_fattr_init(&fattr); |
286 | status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 0); | 321 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
287 | } | 322 | } |
288 | if (status == 0) | 323 | if (status == 0) |
289 | status = nfs_instantiate(dentry, &fhandle, &fattr); | 324 | status = nfs_instantiate(dentry, &fhandle, &fattr); |
@@ -302,8 +337,6 @@ nfs_proc_remove(struct inode *dir, struct qstr *name) | |||
302 | struct rpc_message msg = { | 337 | struct rpc_message msg = { |
303 | .rpc_proc = &nfs_procedures[NFSPROC_REMOVE], | 338 | .rpc_proc = &nfs_procedures[NFSPROC_REMOVE], |
304 | .rpc_argp = &arg, | 339 | .rpc_argp = &arg, |
305 | .rpc_resp = NULL, | ||
306 | .rpc_cred = NULL | ||
307 | }; | 340 | }; |
308 | int status; | 341 | int status; |
309 | 342 | ||
@@ -355,10 +388,14 @@ nfs_proc_rename(struct inode *old_dir, struct qstr *old_name, | |||
355 | .toname = new_name->name, | 388 | .toname = new_name->name, |
356 | .tolen = new_name->len | 389 | .tolen = new_name->len |
357 | }; | 390 | }; |
391 | struct rpc_message msg = { | ||
392 | .rpc_proc = &nfs_procedures[NFSPROC_RENAME], | ||
393 | .rpc_argp = &arg, | ||
394 | }; | ||
358 | int status; | 395 | int status; |
359 | 396 | ||
360 | dprintk("NFS call rename %s -> %s\n", old_name->name, new_name->name); | 397 | dprintk("NFS call rename %s -> %s\n", old_name->name, new_name->name); |
361 | status = rpc_call(NFS_CLIENT(old_dir), NFSPROC_RENAME, &arg, NULL, 0); | 398 | status = rpc_call_sync(NFS_CLIENT(old_dir), &msg, 0); |
362 | nfs_mark_for_revalidate(old_dir); | 399 | nfs_mark_for_revalidate(old_dir); |
363 | nfs_mark_for_revalidate(new_dir); | 400 | nfs_mark_for_revalidate(new_dir); |
364 | dprintk("NFS reply rename: %d\n", status); | 401 | dprintk("NFS reply rename: %d\n", status); |
@@ -374,10 +411,14 @@ nfs_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) | |||
374 | .toname = name->name, | 411 | .toname = name->name, |
375 | .tolen = name->len | 412 | .tolen = name->len |
376 | }; | 413 | }; |
414 | struct rpc_message msg = { | ||
415 | .rpc_proc = &nfs_procedures[NFSPROC_LINK], | ||
416 | .rpc_argp = &arg, | ||
417 | }; | ||
377 | int status; | 418 | int status; |
378 | 419 | ||
379 | dprintk("NFS call link %s\n", name->name); | 420 | dprintk("NFS call link %s\n", name->name); |
380 | status = rpc_call(NFS_CLIENT(inode), NFSPROC_LINK, &arg, NULL, 0); | 421 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); |
381 | nfs_mark_for_revalidate(inode); | 422 | nfs_mark_for_revalidate(inode); |
382 | nfs_mark_for_revalidate(dir); | 423 | nfs_mark_for_revalidate(dir); |
383 | dprintk("NFS reply link: %d\n", status); | 424 | dprintk("NFS reply link: %d\n", status); |
@@ -397,6 +438,10 @@ nfs_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, | |||
397 | .tolen = path->len, | 438 | .tolen = path->len, |
398 | .sattr = sattr | 439 | .sattr = sattr |
399 | }; | 440 | }; |
441 | struct rpc_message msg = { | ||
442 | .rpc_proc = &nfs_procedures[NFSPROC_SYMLINK], | ||
443 | .rpc_argp = &arg, | ||
444 | }; | ||
400 | int status; | 445 | int status; |
401 | 446 | ||
402 | if (path->len > NFS2_MAXPATHLEN) | 447 | if (path->len > NFS2_MAXPATHLEN) |
@@ -404,7 +449,7 @@ nfs_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, | |||
404 | dprintk("NFS call symlink %s -> %s\n", name->name, path->name); | 449 | dprintk("NFS call symlink %s -> %s\n", name->name, path->name); |
405 | nfs_fattr_init(fattr); | 450 | nfs_fattr_init(fattr); |
406 | fhandle->size = 0; | 451 | fhandle->size = 0; |
407 | status = rpc_call(NFS_CLIENT(dir), NFSPROC_SYMLINK, &arg, NULL, 0); | 452 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
408 | nfs_mark_for_revalidate(dir); | 453 | nfs_mark_for_revalidate(dir); |
409 | dprintk("NFS reply symlink: %d\n", status); | 454 | dprintk("NFS reply symlink: %d\n", status); |
410 | return status; | 455 | return status; |
@@ -425,11 +470,16 @@ nfs_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) | |||
425 | .fh = &fhandle, | 470 | .fh = &fhandle, |
426 | .fattr = &fattr | 471 | .fattr = &fattr |
427 | }; | 472 | }; |
473 | struct rpc_message msg = { | ||
474 | .rpc_proc = &nfs_procedures[NFSPROC_MKDIR], | ||
475 | .rpc_argp = &arg, | ||
476 | .rpc_resp = &res, | ||
477 | }; | ||
428 | int status; | 478 | int status; |
429 | 479 | ||
430 | dprintk("NFS call mkdir %s\n", dentry->d_name.name); | 480 | dprintk("NFS call mkdir %s\n", dentry->d_name.name); |
431 | nfs_fattr_init(&fattr); | 481 | nfs_fattr_init(&fattr); |
432 | status = rpc_call(NFS_CLIENT(dir), NFSPROC_MKDIR, &arg, &res, 0); | 482 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
433 | nfs_mark_for_revalidate(dir); | 483 | nfs_mark_for_revalidate(dir); |
434 | if (status == 0) | 484 | if (status == 0) |
435 | status = nfs_instantiate(dentry, &fhandle, &fattr); | 485 | status = nfs_instantiate(dentry, &fhandle, &fattr); |
@@ -445,10 +495,14 @@ nfs_proc_rmdir(struct inode *dir, struct qstr *name) | |||
445 | .name = name->name, | 495 | .name = name->name, |
446 | .len = name->len | 496 | .len = name->len |
447 | }; | 497 | }; |
498 | struct rpc_message msg = { | ||
499 | .rpc_proc = &nfs_procedures[NFSPROC_RMDIR], | ||
500 | .rpc_argp = &arg, | ||
501 | }; | ||
448 | int status; | 502 | int status; |
449 | 503 | ||
450 | dprintk("NFS call rmdir %s\n", name->name); | 504 | dprintk("NFS call rmdir %s\n", name->name); |
451 | status = rpc_call(NFS_CLIENT(dir), NFSPROC_RMDIR, &arg, NULL, 0); | 505 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
452 | nfs_mark_for_revalidate(dir); | 506 | nfs_mark_for_revalidate(dir); |
453 | dprintk("NFS reply rmdir: %d\n", status); | 507 | dprintk("NFS reply rmdir: %d\n", status); |
454 | return status; | 508 | return status; |
@@ -470,13 +524,12 @@ nfs_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | |||
470 | .fh = NFS_FH(dir), | 524 | .fh = NFS_FH(dir), |
471 | .cookie = cookie, | 525 | .cookie = cookie, |
472 | .count = count, | 526 | .count = count, |
473 | .pages = &page | 527 | .pages = &page, |
474 | }; | 528 | }; |
475 | struct rpc_message msg = { | 529 | struct rpc_message msg = { |
476 | .rpc_proc = &nfs_procedures[NFSPROC_READDIR], | 530 | .rpc_proc = &nfs_procedures[NFSPROC_READDIR], |
477 | .rpc_argp = &arg, | 531 | .rpc_argp = &arg, |
478 | .rpc_resp = NULL, | 532 | .rpc_cred = cred, |
479 | .rpc_cred = cred | ||
480 | }; | 533 | }; |
481 | int status; | 534 | int status; |
482 | 535 | ||
@@ -495,11 +548,16 @@ nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, | |||
495 | struct nfs_fsstat *stat) | 548 | struct nfs_fsstat *stat) |
496 | { | 549 | { |
497 | struct nfs2_fsstat fsinfo; | 550 | struct nfs2_fsstat fsinfo; |
551 | struct rpc_message msg = { | ||
552 | .rpc_proc = &nfs_procedures[NFSPROC_STATFS], | ||
553 | .rpc_argp = fhandle, | ||
554 | .rpc_resp = &fsinfo, | ||
555 | }; | ||
498 | int status; | 556 | int status; |
499 | 557 | ||
500 | dprintk("NFS call statfs\n"); | 558 | dprintk("NFS call statfs\n"); |
501 | nfs_fattr_init(stat->fattr); | 559 | nfs_fattr_init(stat->fattr); |
502 | status = rpc_call(server->client, NFSPROC_STATFS, fhandle, &fsinfo, 0); | 560 | status = rpc_call_sync(server->client, &msg, 0); |
503 | dprintk("NFS reply statfs: %d\n", status); | 561 | dprintk("NFS reply statfs: %d\n", status); |
504 | if (status) | 562 | if (status) |
505 | goto out; | 563 | goto out; |
@@ -518,11 +576,16 @@ nfs_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, | |||
518 | struct nfs_fsinfo *info) | 576 | struct nfs_fsinfo *info) |
519 | { | 577 | { |
520 | struct nfs2_fsstat fsinfo; | 578 | struct nfs2_fsstat fsinfo; |
579 | struct rpc_message msg = { | ||
580 | .rpc_proc = &nfs_procedures[NFSPROC_STATFS], | ||
581 | .rpc_argp = fhandle, | ||
582 | .rpc_resp = &fsinfo, | ||
583 | }; | ||
521 | int status; | 584 | int status; |
522 | 585 | ||
523 | dprintk("NFS call fsinfo\n"); | 586 | dprintk("NFS call fsinfo\n"); |
524 | nfs_fattr_init(info->fattr); | 587 | nfs_fattr_init(info->fattr); |
525 | status = rpc_call(server->client, NFSPROC_STATFS, fhandle, &fsinfo, 0); | 588 | status = rpc_call_sync(server->client, &msg, 0); |
526 | dprintk("NFS reply fsinfo: %d\n", status); | 589 | dprintk("NFS reply fsinfo: %d\n", status); |
527 | if (status) | 590 | if (status) |
528 | goto out; | 591 | goto out; |
@@ -550,10 +613,8 @@ nfs_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, | |||
550 | 613 | ||
551 | extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int); | 614 | extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int); |
552 | 615 | ||
553 | static void nfs_read_done(struct rpc_task *task, void *calldata) | 616 | static int nfs_read_done(struct rpc_task *task, struct nfs_read_data *data) |
554 | { | 617 | { |
555 | struct nfs_read_data *data = calldata; | ||
556 | |||
557 | if (task->tk_status >= 0) { | 618 | if (task->tk_status >= 0) { |
558 | nfs_refresh_inode(data->inode, data->res.fattr); | 619 | nfs_refresh_inode(data->inode, data->res.fattr); |
559 | /* Emulate the eof flag, which isn't normally needed in NFSv2 | 620 | /* Emulate the eof flag, which isn't normally needed in NFSv2 |
@@ -562,20 +623,11 @@ static void nfs_read_done(struct rpc_task *task, void *calldata) | |||
562 | if (data->args.offset + data->args.count >= data->res.fattr->size) | 623 | if (data->args.offset + data->args.count >= data->res.fattr->size) |
563 | data->res.eof = 1; | 624 | data->res.eof = 1; |
564 | } | 625 | } |
565 | nfs_readpage_result(task, calldata); | 626 | return 0; |
566 | } | 627 | } |
567 | 628 | ||
568 | static const struct rpc_call_ops nfs_read_ops = { | 629 | static void nfs_proc_read_setup(struct nfs_read_data *data) |
569 | .rpc_call_done = nfs_read_done, | ||
570 | .rpc_release = nfs_readdata_release, | ||
571 | }; | ||
572 | |||
573 | static void | ||
574 | nfs_proc_read_setup(struct nfs_read_data *data) | ||
575 | { | 630 | { |
576 | struct rpc_task *task = &data->task; | ||
577 | struct inode *inode = data->inode; | ||
578 | int flags; | ||
579 | struct rpc_message msg = { | 631 | struct rpc_message msg = { |
580 | .rpc_proc = &nfs_procedures[NFSPROC_READ], | 632 | .rpc_proc = &nfs_procedures[NFSPROC_READ], |
581 | .rpc_argp = &data->args, | 633 | .rpc_argp = &data->args, |
@@ -583,34 +635,18 @@ nfs_proc_read_setup(struct nfs_read_data *data) | |||
583 | .rpc_cred = data->cred, | 635 | .rpc_cred = data->cred, |
584 | }; | 636 | }; |
585 | 637 | ||
586 | /* N.B. Do we need to test? Never called for swapfile inode */ | 638 | rpc_call_setup(&data->task, &msg, 0); |
587 | flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); | ||
588 | |||
589 | /* Finalize the task. */ | ||
590 | rpc_init_task(task, NFS_CLIENT(inode), flags, &nfs_read_ops, data); | ||
591 | rpc_call_setup(task, &msg, 0); | ||
592 | } | 639 | } |
593 | 640 | ||
594 | static void nfs_write_done(struct rpc_task *task, void *calldata) | 641 | static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data) |
595 | { | 642 | { |
596 | struct nfs_write_data *data = calldata; | ||
597 | |||
598 | if (task->tk_status >= 0) | 643 | if (task->tk_status >= 0) |
599 | nfs_post_op_update_inode(data->inode, data->res.fattr); | 644 | nfs_post_op_update_inode(data->inode, data->res.fattr); |
600 | nfs_writeback_done(task, calldata); | 645 | return 0; |
601 | } | 646 | } |
602 | 647 | ||
603 | static const struct rpc_call_ops nfs_write_ops = { | 648 | static void nfs_proc_write_setup(struct nfs_write_data *data, int how) |
604 | .rpc_call_done = nfs_write_done, | ||
605 | .rpc_release = nfs_writedata_release, | ||
606 | }; | ||
607 | |||
608 | static void | ||
609 | nfs_proc_write_setup(struct nfs_write_data *data, int how) | ||
610 | { | 649 | { |
611 | struct rpc_task *task = &data->task; | ||
612 | struct inode *inode = data->inode; | ||
613 | int flags; | ||
614 | struct rpc_message msg = { | 650 | struct rpc_message msg = { |
615 | .rpc_proc = &nfs_procedures[NFSPROC_WRITE], | 651 | .rpc_proc = &nfs_procedures[NFSPROC_WRITE], |
616 | .rpc_argp = &data->args, | 652 | .rpc_argp = &data->args, |
@@ -621,12 +657,8 @@ nfs_proc_write_setup(struct nfs_write_data *data, int how) | |||
621 | /* Note: NFSv2 ignores @stable and always uses NFS_FILE_SYNC */ | 657 | /* Note: NFSv2 ignores @stable and always uses NFS_FILE_SYNC */ |
622 | data->args.stable = NFS_FILE_SYNC; | 658 | data->args.stable = NFS_FILE_SYNC; |
623 | 659 | ||
624 | /* Set the initial flags for the task. */ | ||
625 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | ||
626 | |||
627 | /* Finalize the task. */ | 660 | /* Finalize the task. */ |
628 | rpc_init_task(task, NFS_CLIENT(inode), flags, &nfs_write_ops, data); | 661 | rpc_call_setup(&data->task, &msg, 0); |
629 | rpc_call_setup(task, &msg, 0); | ||
630 | } | 662 | } |
631 | 663 | ||
632 | static void | 664 | static void |
@@ -672,7 +704,9 @@ struct nfs_rpc_ops nfs_v2_clientops = { | |||
672 | .pathconf = nfs_proc_pathconf, | 704 | .pathconf = nfs_proc_pathconf, |
673 | .decode_dirent = nfs_decode_dirent, | 705 | .decode_dirent = nfs_decode_dirent, |
674 | .read_setup = nfs_proc_read_setup, | 706 | .read_setup = nfs_proc_read_setup, |
707 | .read_done = nfs_read_done, | ||
675 | .write_setup = nfs_proc_write_setup, | 708 | .write_setup = nfs_proc_write_setup, |
709 | .write_done = nfs_write_done, | ||
676 | .commit_setup = nfs_proc_commit_setup, | 710 | .commit_setup = nfs_proc_commit_setup, |
677 | .file_open = nfs_open, | 711 | .file_open = nfs_open, |
678 | .file_release = nfs_release, | 712 | .file_release = nfs_release, |
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 05eb43fadf8e..3961524fd4ab 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
@@ -31,17 +31,49 @@ | |||
31 | 31 | ||
32 | #include <asm/system.h> | 32 | #include <asm/system.h> |
33 | 33 | ||
34 | #include "iostat.h" | ||
35 | |||
34 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE | 36 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE |
35 | 37 | ||
36 | static int nfs_pagein_one(struct list_head *, struct inode *); | 38 | static int nfs_pagein_one(struct list_head *, struct inode *); |
37 | static void nfs_readpage_result_partial(struct nfs_read_data *, int); | 39 | static const struct rpc_call_ops nfs_read_partial_ops; |
38 | static void nfs_readpage_result_full(struct nfs_read_data *, int); | 40 | static const struct rpc_call_ops nfs_read_full_ops; |
39 | 41 | ||
40 | static kmem_cache_t *nfs_rdata_cachep; | 42 | static kmem_cache_t *nfs_rdata_cachep; |
41 | mempool_t *nfs_rdata_mempool; | 43 | static mempool_t *nfs_rdata_mempool; |
42 | 44 | ||
43 | #define MIN_POOL_READ (32) | 45 | #define MIN_POOL_READ (32) |
44 | 46 | ||
47 | struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount) | ||
48 | { | ||
49 | struct nfs_read_data *p = mempool_alloc(nfs_rdata_mempool, SLAB_NOFS); | ||
50 | |||
51 | if (p) { | ||
52 | memset(p, 0, sizeof(*p)); | ||
53 | INIT_LIST_HEAD(&p->pages); | ||
54 | if (pagecount < NFS_PAGEVEC_SIZE) | ||
55 | p->pagevec = &p->page_array[0]; | ||
56 | else { | ||
57 | size_t size = ++pagecount * sizeof(struct page *); | ||
58 | p->pagevec = kmalloc(size, GFP_NOFS); | ||
59 | if (p->pagevec) { | ||
60 | memset(p->pagevec, 0, size); | ||
61 | } else { | ||
62 | mempool_free(p, nfs_rdata_mempool); | ||
63 | p = NULL; | ||
64 | } | ||
65 | } | ||
66 | } | ||
67 | return p; | ||
68 | } | ||
69 | |||
70 | void nfs_readdata_free(struct nfs_read_data *p) | ||
71 | { | ||
72 | if (p && (p->pagevec != &p->page_array[0])) | ||
73 | kfree(p->pagevec); | ||
74 | mempool_free(p, nfs_rdata_mempool); | ||
75 | } | ||
76 | |||
45 | void nfs_readdata_release(void *data) | 77 | void nfs_readdata_release(void *data) |
46 | { | 78 | { |
47 | nfs_readdata_free(data); | 79 | nfs_readdata_free(data); |
@@ -133,6 +165,8 @@ static int nfs_readpage_sync(struct nfs_open_context *ctx, struct inode *inode, | |||
133 | } | 165 | } |
134 | count -= result; | 166 | count -= result; |
135 | rdata->args.pgbase += result; | 167 | rdata->args.pgbase += result; |
168 | nfs_add_stats(inode, NFSIOS_SERVERREADBYTES, result); | ||
169 | |||
136 | /* Note: result == 0 should only happen if we're caching | 170 | /* Note: result == 0 should only happen if we're caching |
137 | * a write that extends the file and punches a hole. | 171 | * a write that extends the file and punches a hole. |
138 | */ | 172 | */ |
@@ -196,9 +230,11 @@ static void nfs_readpage_release(struct nfs_page *req) | |||
196 | * Set up the NFS read request struct | 230 | * Set up the NFS read request struct |
197 | */ | 231 | */ |
198 | static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, | 232 | static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, |
233 | const struct rpc_call_ops *call_ops, | ||
199 | unsigned int count, unsigned int offset) | 234 | unsigned int count, unsigned int offset) |
200 | { | 235 | { |
201 | struct inode *inode; | 236 | struct inode *inode; |
237 | int flags; | ||
202 | 238 | ||
203 | data->req = req; | 239 | data->req = req; |
204 | data->inode = inode = req->wb_context->dentry->d_inode; | 240 | data->inode = inode = req->wb_context->dentry->d_inode; |
@@ -216,6 +252,9 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, | |||
216 | data->res.eof = 0; | 252 | data->res.eof = 0; |
217 | nfs_fattr_init(&data->fattr); | 253 | nfs_fattr_init(&data->fattr); |
218 | 254 | ||
255 | /* Set up the initial task struct. */ | ||
256 | flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); | ||
257 | rpc_init_task(&data->task, NFS_CLIENT(inode), flags, call_ops, data); | ||
219 | NFS_PROTO(inode)->read_setup(data); | 258 | NFS_PROTO(inode)->read_setup(data); |
220 | 259 | ||
221 | data->task.tk_cookie = (unsigned long)inode; | 260 | data->task.tk_cookie = (unsigned long)inode; |
@@ -303,14 +342,15 @@ static int nfs_pagein_multi(struct list_head *head, struct inode *inode) | |||
303 | list_del_init(&data->pages); | 342 | list_del_init(&data->pages); |
304 | 343 | ||
305 | data->pagevec[0] = page; | 344 | data->pagevec[0] = page; |
306 | data->complete = nfs_readpage_result_partial; | ||
307 | 345 | ||
308 | if (nbytes > rsize) { | 346 | if (nbytes > rsize) { |
309 | nfs_read_rpcsetup(req, data, rsize, offset); | 347 | nfs_read_rpcsetup(req, data, &nfs_read_partial_ops, |
348 | rsize, offset); | ||
310 | offset += rsize; | 349 | offset += rsize; |
311 | nbytes -= rsize; | 350 | nbytes -= rsize; |
312 | } else { | 351 | } else { |
313 | nfs_read_rpcsetup(req, data, nbytes, offset); | 352 | nfs_read_rpcsetup(req, data, &nfs_read_partial_ops, |
353 | nbytes, offset); | ||
314 | nbytes = 0; | 354 | nbytes = 0; |
315 | } | 355 | } |
316 | nfs_execute_read(data); | 356 | nfs_execute_read(data); |
@@ -356,8 +396,7 @@ static int nfs_pagein_one(struct list_head *head, struct inode *inode) | |||
356 | } | 396 | } |
357 | req = nfs_list_entry(data->pages.next); | 397 | req = nfs_list_entry(data->pages.next); |
358 | 398 | ||
359 | data->complete = nfs_readpage_result_full; | 399 | nfs_read_rpcsetup(req, data, &nfs_read_full_ops, count, 0); |
360 | nfs_read_rpcsetup(req, data, count, 0); | ||
361 | 400 | ||
362 | nfs_execute_read(data); | 401 | nfs_execute_read(data); |
363 | return 0; | 402 | return 0; |
@@ -391,12 +430,15 @@ nfs_pagein_list(struct list_head *head, int rpages) | |||
391 | /* | 430 | /* |
392 | * Handle a read reply that fills part of a page. | 431 | * Handle a read reply that fills part of a page. |
393 | */ | 432 | */ |
394 | static void nfs_readpage_result_partial(struct nfs_read_data *data, int status) | 433 | static void nfs_readpage_result_partial(struct rpc_task *task, void *calldata) |
395 | { | 434 | { |
435 | struct nfs_read_data *data = calldata; | ||
396 | struct nfs_page *req = data->req; | 436 | struct nfs_page *req = data->req; |
397 | struct page *page = req->wb_page; | 437 | struct page *page = req->wb_page; |
398 | 438 | ||
399 | if (status >= 0) { | 439 | if (nfs_readpage_result(task, data) != 0) |
440 | return; | ||
441 | if (task->tk_status >= 0) { | ||
400 | unsigned int request = data->args.count; | 442 | unsigned int request = data->args.count; |
401 | unsigned int result = data->res.count; | 443 | unsigned int result = data->res.count; |
402 | 444 | ||
@@ -415,20 +457,28 @@ static void nfs_readpage_result_partial(struct nfs_read_data *data, int status) | |||
415 | } | 457 | } |
416 | } | 458 | } |
417 | 459 | ||
460 | static const struct rpc_call_ops nfs_read_partial_ops = { | ||
461 | .rpc_call_done = nfs_readpage_result_partial, | ||
462 | .rpc_release = nfs_readdata_release, | ||
463 | }; | ||
464 | |||
418 | /* | 465 | /* |
419 | * This is the callback from RPC telling us whether a reply was | 466 | * This is the callback from RPC telling us whether a reply was |
420 | * received or some error occurred (timeout or socket shutdown). | 467 | * received or some error occurred (timeout or socket shutdown). |
421 | */ | 468 | */ |
422 | static void nfs_readpage_result_full(struct nfs_read_data *data, int status) | 469 | static void nfs_readpage_result_full(struct rpc_task *task, void *calldata) |
423 | { | 470 | { |
471 | struct nfs_read_data *data = calldata; | ||
424 | unsigned int count = data->res.count; | 472 | unsigned int count = data->res.count; |
425 | 473 | ||
474 | if (nfs_readpage_result(task, data) != 0) | ||
475 | return; | ||
426 | while (!list_empty(&data->pages)) { | 476 | while (!list_empty(&data->pages)) { |
427 | struct nfs_page *req = nfs_list_entry(data->pages.next); | 477 | struct nfs_page *req = nfs_list_entry(data->pages.next); |
428 | struct page *page = req->wb_page; | 478 | struct page *page = req->wb_page; |
429 | nfs_list_remove_request(req); | 479 | nfs_list_remove_request(req); |
430 | 480 | ||
431 | if (status >= 0) { | 481 | if (task->tk_status >= 0) { |
432 | if (count < PAGE_CACHE_SIZE) { | 482 | if (count < PAGE_CACHE_SIZE) { |
433 | if (count < req->wb_bytes) | 483 | if (count < req->wb_bytes) |
434 | memclear_highpage_flush(page, | 484 | memclear_highpage_flush(page, |
@@ -444,22 +494,33 @@ static void nfs_readpage_result_full(struct nfs_read_data *data, int status) | |||
444 | } | 494 | } |
445 | } | 495 | } |
446 | 496 | ||
497 | static const struct rpc_call_ops nfs_read_full_ops = { | ||
498 | .rpc_call_done = nfs_readpage_result_full, | ||
499 | .rpc_release = nfs_readdata_release, | ||
500 | }; | ||
501 | |||
447 | /* | 502 | /* |
448 | * This is the callback from RPC telling us whether a reply was | 503 | * This is the callback from RPC telling us whether a reply was |
449 | * received or some error occurred (timeout or socket shutdown). | 504 | * received or some error occurred (timeout or socket shutdown). |
450 | */ | 505 | */ |
451 | void nfs_readpage_result(struct rpc_task *task, void *calldata) | 506 | int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data) |
452 | { | 507 | { |
453 | struct nfs_read_data *data = calldata; | ||
454 | struct nfs_readargs *argp = &data->args; | 508 | struct nfs_readargs *argp = &data->args; |
455 | struct nfs_readres *resp = &data->res; | 509 | struct nfs_readres *resp = &data->res; |
456 | int status = task->tk_status; | 510 | int status; |
457 | 511 | ||
458 | dprintk("NFS: %4d nfs_readpage_result, (status %d)\n", | 512 | dprintk("NFS: %4d nfs_readpage_result, (status %d)\n", |
459 | task->tk_pid, status); | 513 | task->tk_pid, task->tk_status); |
514 | |||
515 | status = NFS_PROTO(data->inode)->read_done(task, data); | ||
516 | if (status != 0) | ||
517 | return status; | ||
518 | |||
519 | nfs_add_stats(data->inode, NFSIOS_SERVERREADBYTES, resp->count); | ||
460 | 520 | ||
461 | /* Is this a short read? */ | 521 | /* Is this a short read? */ |
462 | if (task->tk_status >= 0 && resp->count < argp->count && !resp->eof) { | 522 | if (task->tk_status >= 0 && resp->count < argp->count && !resp->eof) { |
523 | nfs_inc_stats(data->inode, NFSIOS_SHORTREAD); | ||
463 | /* Has the server at least made some progress? */ | 524 | /* Has the server at least made some progress? */ |
464 | if (resp->count != 0) { | 525 | if (resp->count != 0) { |
465 | /* Yes, so retry the read at the end of the data */ | 526 | /* Yes, so retry the read at the end of the data */ |
@@ -467,14 +528,14 @@ void nfs_readpage_result(struct rpc_task *task, void *calldata) | |||
467 | argp->pgbase += resp->count; | 528 | argp->pgbase += resp->count; |
468 | argp->count -= resp->count; | 529 | argp->count -= resp->count; |
469 | rpc_restart_call(task); | 530 | rpc_restart_call(task); |
470 | return; | 531 | return -EAGAIN; |
471 | } | 532 | } |
472 | task->tk_status = -EIO; | 533 | task->tk_status = -EIO; |
473 | } | 534 | } |
474 | spin_lock(&data->inode->i_lock); | 535 | spin_lock(&data->inode->i_lock); |
475 | NFS_I(data->inode)->cache_validity |= NFS_INO_INVALID_ATIME; | 536 | NFS_I(data->inode)->cache_validity |= NFS_INO_INVALID_ATIME; |
476 | spin_unlock(&data->inode->i_lock); | 537 | spin_unlock(&data->inode->i_lock); |
477 | data->complete(data, status); | 538 | return 0; |
478 | } | 539 | } |
479 | 540 | ||
480 | /* | 541 | /* |
@@ -491,6 +552,9 @@ int nfs_readpage(struct file *file, struct page *page) | |||
491 | 552 | ||
492 | dprintk("NFS: nfs_readpage (%p %ld@%lu)\n", | 553 | dprintk("NFS: nfs_readpage (%p %ld@%lu)\n", |
493 | page, PAGE_CACHE_SIZE, page->index); | 554 | page, PAGE_CACHE_SIZE, page->index); |
555 | nfs_inc_stats(inode, NFSIOS_VFSREADPAGE); | ||
556 | nfs_add_stats(inode, NFSIOS_READPAGES, 1); | ||
557 | |||
494 | /* | 558 | /* |
495 | * Try to flush any pending writes to the file.. | 559 | * Try to flush any pending writes to the file.. |
496 | * | 560 | * |
@@ -570,6 +634,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping, | |||
570 | inode->i_sb->s_id, | 634 | inode->i_sb->s_id, |
571 | (long long)NFS_FILEID(inode), | 635 | (long long)NFS_FILEID(inode), |
572 | nr_pages); | 636 | nr_pages); |
637 | nfs_inc_stats(inode, NFSIOS_VFSREADPAGES); | ||
573 | 638 | ||
574 | if (filp == NULL) { | 639 | if (filp == NULL) { |
575 | desc.ctx = nfs_find_open_context(inode, NULL, FMODE_READ); | 640 | desc.ctx = nfs_find_open_context(inode, NULL, FMODE_READ); |
@@ -582,6 +647,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping, | |||
582 | if (!list_empty(&head)) { | 647 | if (!list_empty(&head)) { |
583 | int err = nfs_pagein_list(&head, server->rpages); | 648 | int err = nfs_pagein_list(&head, server->rpages); |
584 | if (!ret) | 649 | if (!ret) |
650 | nfs_add_stats(inode, NFSIOS_READPAGES, err); | ||
585 | ret = err; | 651 | ret = err; |
586 | } | 652 | } |
587 | put_nfs_open_context(desc.ctx); | 653 | put_nfs_open_context(desc.ctx); |
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index a65c7b53d558..0e28189c2151 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c | |||
@@ -163,10 +163,9 @@ nfs_async_unlink(struct dentry *dentry) | |||
163 | struct rpc_clnt *clnt = NFS_CLIENT(dir->d_inode); | 163 | struct rpc_clnt *clnt = NFS_CLIENT(dir->d_inode); |
164 | int status = -ENOMEM; | 164 | int status = -ENOMEM; |
165 | 165 | ||
166 | data = kmalloc(sizeof(*data), GFP_KERNEL); | 166 | data = kzalloc(sizeof(*data), GFP_KERNEL); |
167 | if (!data) | 167 | if (!data) |
168 | goto out; | 168 | goto out; |
169 | memset(data, 0, sizeof(*data)); | ||
170 | 169 | ||
171 | data->cred = rpcauth_lookupcred(clnt->cl_auth, 0); | 170 | data->cred = rpcauth_lookupcred(clnt->cl_auth, 0); |
172 | if (IS_ERR(data->cred)) { | 171 | if (IS_ERR(data->cred)) { |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 9449b6835509..3f5225404c97 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -63,6 +63,7 @@ | |||
63 | #include <linux/smp_lock.h> | 63 | #include <linux/smp_lock.h> |
64 | 64 | ||
65 | #include "delegation.h" | 65 | #include "delegation.h" |
66 | #include "iostat.h" | ||
66 | 67 | ||
67 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE | 68 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE |
68 | 69 | ||
@@ -76,20 +77,21 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context*, | |||
76 | struct inode *, | 77 | struct inode *, |
77 | struct page *, | 78 | struct page *, |
78 | unsigned int, unsigned int); | 79 | unsigned int, unsigned int); |
79 | static void nfs_writeback_done_partial(struct nfs_write_data *, int); | ||
80 | static void nfs_writeback_done_full(struct nfs_write_data *, int); | ||
81 | static int nfs_wait_on_write_congestion(struct address_space *, int); | 80 | static int nfs_wait_on_write_congestion(struct address_space *, int); |
82 | static int nfs_wait_on_requests(struct inode *, unsigned long, unsigned int); | 81 | static int nfs_wait_on_requests(struct inode *, unsigned long, unsigned int); |
83 | static int nfs_flush_inode(struct inode *inode, unsigned long idx_start, | 82 | static int nfs_flush_inode(struct inode *inode, unsigned long idx_start, |
84 | unsigned int npages, int how); | 83 | unsigned int npages, int how); |
84 | static const struct rpc_call_ops nfs_write_partial_ops; | ||
85 | static const struct rpc_call_ops nfs_write_full_ops; | ||
86 | static const struct rpc_call_ops nfs_commit_ops; | ||
85 | 87 | ||
86 | static kmem_cache_t *nfs_wdata_cachep; | 88 | static kmem_cache_t *nfs_wdata_cachep; |
87 | mempool_t *nfs_wdata_mempool; | 89 | static mempool_t *nfs_wdata_mempool; |
88 | static mempool_t *nfs_commit_mempool; | 90 | static mempool_t *nfs_commit_mempool; |
89 | 91 | ||
90 | static DECLARE_WAIT_QUEUE_HEAD(nfs_write_congestion); | 92 | static DECLARE_WAIT_QUEUE_HEAD(nfs_write_congestion); |
91 | 93 | ||
92 | static inline struct nfs_write_data *nfs_commit_alloc(unsigned int pagecount) | 94 | struct nfs_write_data *nfs_commit_alloc(unsigned int pagecount) |
93 | { | 95 | { |
94 | struct nfs_write_data *p = mempool_alloc(nfs_commit_mempool, SLAB_NOFS); | 96 | struct nfs_write_data *p = mempool_alloc(nfs_commit_mempool, SLAB_NOFS); |
95 | 97 | ||
@@ -100,11 +102,39 @@ static inline struct nfs_write_data *nfs_commit_alloc(unsigned int pagecount) | |||
100 | p->pagevec = &p->page_array[0]; | 102 | p->pagevec = &p->page_array[0]; |
101 | else { | 103 | else { |
102 | size_t size = ++pagecount * sizeof(struct page *); | 104 | size_t size = ++pagecount * sizeof(struct page *); |
105 | p->pagevec = kzalloc(size, GFP_NOFS); | ||
106 | if (!p->pagevec) { | ||
107 | mempool_free(p, nfs_commit_mempool); | ||
108 | p = NULL; | ||
109 | } | ||
110 | } | ||
111 | } | ||
112 | return p; | ||
113 | } | ||
114 | |||
115 | void nfs_commit_free(struct nfs_write_data *p) | ||
116 | { | ||
117 | if (p && (p->pagevec != &p->page_array[0])) | ||
118 | kfree(p->pagevec); | ||
119 | mempool_free(p, nfs_commit_mempool); | ||
120 | } | ||
121 | |||
122 | struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount) | ||
123 | { | ||
124 | struct nfs_write_data *p = mempool_alloc(nfs_wdata_mempool, SLAB_NOFS); | ||
125 | |||
126 | if (p) { | ||
127 | memset(p, 0, sizeof(*p)); | ||
128 | INIT_LIST_HEAD(&p->pages); | ||
129 | if (pagecount < NFS_PAGEVEC_SIZE) | ||
130 | p->pagevec = &p->page_array[0]; | ||
131 | else { | ||
132 | size_t size = ++pagecount * sizeof(struct page *); | ||
103 | p->pagevec = kmalloc(size, GFP_NOFS); | 133 | p->pagevec = kmalloc(size, GFP_NOFS); |
104 | if (p->pagevec) { | 134 | if (p->pagevec) { |
105 | memset(p->pagevec, 0, size); | 135 | memset(p->pagevec, 0, size); |
106 | } else { | 136 | } else { |
107 | mempool_free(p, nfs_commit_mempool); | 137 | mempool_free(p, nfs_wdata_mempool); |
108 | p = NULL; | 138 | p = NULL; |
109 | } | 139 | } |
110 | } | 140 | } |
@@ -112,11 +142,11 @@ static inline struct nfs_write_data *nfs_commit_alloc(unsigned int pagecount) | |||
112 | return p; | 142 | return p; |
113 | } | 143 | } |
114 | 144 | ||
115 | static inline void nfs_commit_free(struct nfs_write_data *p) | 145 | void nfs_writedata_free(struct nfs_write_data *p) |
116 | { | 146 | { |
117 | if (p && (p->pagevec != &p->page_array[0])) | 147 | if (p && (p->pagevec != &p->page_array[0])) |
118 | kfree(p->pagevec); | 148 | kfree(p->pagevec); |
119 | mempool_free(p, nfs_commit_mempool); | 149 | mempool_free(p, nfs_wdata_mempool); |
120 | } | 150 | } |
121 | 151 | ||
122 | void nfs_writedata_release(void *wdata) | 152 | void nfs_writedata_release(void *wdata) |
@@ -136,6 +166,7 @@ static void nfs_grow_file(struct page *page, unsigned int offset, unsigned int c | |||
136 | end = ((loff_t)page->index << PAGE_CACHE_SHIFT) + ((loff_t)offset+count); | 166 | end = ((loff_t)page->index << PAGE_CACHE_SHIFT) + ((loff_t)offset+count); |
137 | if (i_size >= end) | 167 | if (i_size >= end) |
138 | return; | 168 | return; |
169 | nfs_inc_stats(inode, NFSIOS_EXTENDWRITE); | ||
139 | i_size_write(inode, end); | 170 | i_size_write(inode, end); |
140 | } | 171 | } |
141 | 172 | ||
@@ -225,6 +256,7 @@ static int nfs_writepage_sync(struct nfs_open_context *ctx, struct inode *inode, | |||
225 | wdata->args.pgbase += result; | 256 | wdata->args.pgbase += result; |
226 | written += result; | 257 | written += result; |
227 | count -= result; | 258 | count -= result; |
259 | nfs_add_stats(inode, NFSIOS_SERVERWRITTENBYTES, result); | ||
228 | } while (count); | 260 | } while (count); |
229 | /* Update file length */ | 261 | /* Update file length */ |
230 | nfs_grow_file(page, offset, written); | 262 | nfs_grow_file(page, offset, written); |
@@ -281,6 +313,9 @@ int nfs_writepage(struct page *page, struct writeback_control *wbc) | |||
281 | int priority = wb_priority(wbc); | 313 | int priority = wb_priority(wbc); |
282 | int err; | 314 | int err; |
283 | 315 | ||
316 | nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE); | ||
317 | nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1); | ||
318 | |||
284 | /* | 319 | /* |
285 | * Note: We need to ensure that we have a reference to the inode | 320 | * Note: We need to ensure that we have a reference to the inode |
286 | * if we are to do asynchronous writes. If not, waiting | 321 | * if we are to do asynchronous writes. If not, waiting |
@@ -345,6 +380,8 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) | |||
345 | struct inode *inode = mapping->host; | 380 | struct inode *inode = mapping->host; |
346 | int err; | 381 | int err; |
347 | 382 | ||
383 | nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGES); | ||
384 | |||
348 | err = generic_writepages(mapping, wbc); | 385 | err = generic_writepages(mapping, wbc); |
349 | if (err) | 386 | if (err) |
350 | return err; | 387 | return err; |
@@ -356,6 +393,7 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) | |||
356 | err = nfs_flush_inode(inode, 0, 0, wb_priority(wbc)); | 393 | err = nfs_flush_inode(inode, 0, 0, wb_priority(wbc)); |
357 | if (err < 0) | 394 | if (err < 0) |
358 | goto out; | 395 | goto out; |
396 | nfs_add_stats(inode, NFSIOS_WRITEPAGES, err); | ||
359 | wbc->nr_to_write -= err; | 397 | wbc->nr_to_write -= err; |
360 | if (!wbc->nonblocking && wbc->sync_mode == WB_SYNC_ALL) { | 398 | if (!wbc->nonblocking && wbc->sync_mode == WB_SYNC_ALL) { |
361 | err = nfs_wait_on_requests(inode, 0, 0); | 399 | err = nfs_wait_on_requests(inode, 0, 0); |
@@ -391,6 +429,7 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req) | |||
391 | if (nfs_have_delegation(inode, FMODE_WRITE)) | 429 | if (nfs_have_delegation(inode, FMODE_WRITE)) |
392 | nfsi->change_attr++; | 430 | nfsi->change_attr++; |
393 | } | 431 | } |
432 | SetPagePrivate(req->wb_page); | ||
394 | nfsi->npages++; | 433 | nfsi->npages++; |
395 | atomic_inc(&req->wb_count); | 434 | atomic_inc(&req->wb_count); |
396 | return 0; | 435 | return 0; |
@@ -407,6 +446,7 @@ static void nfs_inode_remove_request(struct nfs_page *req) | |||
407 | BUG_ON (!NFS_WBACK_BUSY(req)); | 446 | BUG_ON (!NFS_WBACK_BUSY(req)); |
408 | 447 | ||
409 | spin_lock(&nfsi->req_lock); | 448 | spin_lock(&nfsi->req_lock); |
449 | ClearPagePrivate(req->wb_page); | ||
410 | radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index); | 450 | radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index); |
411 | nfsi->npages--; | 451 | nfsi->npages--; |
412 | if (!nfsi->npages) { | 452 | if (!nfsi->npages) { |
@@ -499,8 +539,7 @@ nfs_mark_request_commit(struct nfs_page *req) | |||
499 | * | 539 | * |
500 | * Interruptible by signals only if mounted with intr flag. | 540 | * Interruptible by signals only if mounted with intr flag. |
501 | */ | 541 | */ |
502 | static int | 542 | static int nfs_wait_on_requests_locked(struct inode *inode, unsigned long idx_start, unsigned int npages) |
503 | nfs_wait_on_requests(struct inode *inode, unsigned long idx_start, unsigned int npages) | ||
504 | { | 543 | { |
505 | struct nfs_inode *nfsi = NFS_I(inode); | 544 | struct nfs_inode *nfsi = NFS_I(inode); |
506 | struct nfs_page *req; | 545 | struct nfs_page *req; |
@@ -513,7 +552,6 @@ nfs_wait_on_requests(struct inode *inode, unsigned long idx_start, unsigned int | |||
513 | else | 552 | else |
514 | idx_end = idx_start + npages - 1; | 553 | idx_end = idx_start + npages - 1; |
515 | 554 | ||
516 | spin_lock(&nfsi->req_lock); | ||
517 | next = idx_start; | 555 | next = idx_start; |
518 | while (radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree, (void **)&req, next, 1, NFS_PAGE_TAG_WRITEBACK)) { | 556 | while (radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree, (void **)&req, next, 1, NFS_PAGE_TAG_WRITEBACK)) { |
519 | if (req->wb_index > idx_end) | 557 | if (req->wb_index > idx_end) |
@@ -526,15 +564,25 @@ nfs_wait_on_requests(struct inode *inode, unsigned long idx_start, unsigned int | |||
526 | spin_unlock(&nfsi->req_lock); | 564 | spin_unlock(&nfsi->req_lock); |
527 | error = nfs_wait_on_request(req); | 565 | error = nfs_wait_on_request(req); |
528 | nfs_release_request(req); | 566 | nfs_release_request(req); |
567 | spin_lock(&nfsi->req_lock); | ||
529 | if (error < 0) | 568 | if (error < 0) |
530 | return error; | 569 | return error; |
531 | spin_lock(&nfsi->req_lock); | ||
532 | res++; | 570 | res++; |
533 | } | 571 | } |
534 | spin_unlock(&nfsi->req_lock); | ||
535 | return res; | 572 | return res; |
536 | } | 573 | } |
537 | 574 | ||
575 | static int nfs_wait_on_requests(struct inode *inode, unsigned long idx_start, unsigned int npages) | ||
576 | { | ||
577 | struct nfs_inode *nfsi = NFS_I(inode); | ||
578 | int ret; | ||
579 | |||
580 | spin_lock(&nfsi->req_lock); | ||
581 | ret = nfs_wait_on_requests_locked(inode, idx_start, npages); | ||
582 | spin_unlock(&nfsi->req_lock); | ||
583 | return ret; | ||
584 | } | ||
585 | |||
538 | /* | 586 | /* |
539 | * nfs_scan_dirty - Scan an inode for dirty requests | 587 | * nfs_scan_dirty - Scan an inode for dirty requests |
540 | * @inode: NFS inode to scan | 588 | * @inode: NFS inode to scan |
@@ -586,6 +634,11 @@ nfs_scan_commit(struct inode *inode, struct list_head *dst, unsigned long idx_st | |||
586 | } | 634 | } |
587 | return res; | 635 | return res; |
588 | } | 636 | } |
637 | #else | ||
638 | static inline int nfs_scan_commit(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages) | ||
639 | { | ||
640 | return 0; | ||
641 | } | ||
589 | #endif | 642 | #endif |
590 | 643 | ||
591 | static int nfs_wait_on_write_congestion(struct address_space *mapping, int intr) | 644 | static int nfs_wait_on_write_congestion(struct address_space *mapping, int intr) |
@@ -598,6 +651,9 @@ static int nfs_wait_on_write_congestion(struct address_space *mapping, int intr) | |||
598 | 651 | ||
599 | if (!bdi_write_congested(bdi)) | 652 | if (!bdi_write_congested(bdi)) |
600 | return 0; | 653 | return 0; |
654 | |||
655 | nfs_inc_stats(mapping->host, NFSIOS_CONGESTIONWAIT); | ||
656 | |||
601 | if (intr) { | 657 | if (intr) { |
602 | struct rpc_clnt *clnt = NFS_CLIENT(mapping->host); | 658 | struct rpc_clnt *clnt = NFS_CLIENT(mapping->host); |
603 | sigset_t oldset; | 659 | sigset_t oldset; |
@@ -653,8 +709,11 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, | |||
653 | spin_unlock(&nfsi->req_lock); | 709 | spin_unlock(&nfsi->req_lock); |
654 | error = nfs_wait_on_request(req); | 710 | error = nfs_wait_on_request(req); |
655 | nfs_release_request(req); | 711 | nfs_release_request(req); |
656 | if (error < 0) | 712 | if (error < 0) { |
713 | if (new) | ||
714 | nfs_release_request(new); | ||
657 | return ERR_PTR(error); | 715 | return ERR_PTR(error); |
716 | } | ||
658 | continue; | 717 | continue; |
659 | } | 718 | } |
660 | spin_unlock(&nfsi->req_lock); | 719 | spin_unlock(&nfsi->req_lock); |
@@ -748,6 +807,8 @@ int nfs_updatepage(struct file *file, struct page *page, | |||
748 | struct nfs_page *req; | 807 | struct nfs_page *req; |
749 | int status = 0; | 808 | int status = 0; |
750 | 809 | ||
810 | nfs_inc_stats(inode, NFSIOS_VFSUPDATEPAGE); | ||
811 | |||
751 | dprintk("NFS: nfs_updatepage(%s/%s %d@%Ld)\n", | 812 | dprintk("NFS: nfs_updatepage(%s/%s %d@%Ld)\n", |
752 | file->f_dentry->d_parent->d_name.name, | 813 | file->f_dentry->d_parent->d_name.name, |
753 | file->f_dentry->d_name.name, count, | 814 | file->f_dentry->d_name.name, count, |
@@ -857,10 +918,12 @@ static inline int flush_task_priority(int how) | |||
857 | */ | 918 | */ |
858 | static void nfs_write_rpcsetup(struct nfs_page *req, | 919 | static void nfs_write_rpcsetup(struct nfs_page *req, |
859 | struct nfs_write_data *data, | 920 | struct nfs_write_data *data, |
921 | const struct rpc_call_ops *call_ops, | ||
860 | unsigned int count, unsigned int offset, | 922 | unsigned int count, unsigned int offset, |
861 | int how) | 923 | int how) |
862 | { | 924 | { |
863 | struct inode *inode; | 925 | struct inode *inode; |
926 | int flags; | ||
864 | 927 | ||
865 | /* Set up the RPC argument and reply structs | 928 | /* Set up the RPC argument and reply structs |
866 | * NB: take care not to mess about with data->commit et al. */ | 929 | * NB: take care not to mess about with data->commit et al. */ |
@@ -881,6 +944,9 @@ static void nfs_write_rpcsetup(struct nfs_page *req, | |||
881 | data->res.verf = &data->verf; | 944 | data->res.verf = &data->verf; |
882 | nfs_fattr_init(&data->fattr); | 945 | nfs_fattr_init(&data->fattr); |
883 | 946 | ||
947 | /* Set up the initial task struct. */ | ||
948 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | ||
949 | rpc_init_task(&data->task, NFS_CLIENT(inode), flags, call_ops, data); | ||
884 | NFS_PROTO(inode)->write_setup(data, how); | 950 | NFS_PROTO(inode)->write_setup(data, how); |
885 | 951 | ||
886 | data->task.tk_priority = flush_task_priority(how); | 952 | data->task.tk_priority = flush_task_priority(how); |
@@ -910,7 +976,7 @@ static void nfs_execute_write(struct nfs_write_data *data) | |||
910 | * Generate multiple small requests to write out a single | 976 | * Generate multiple small requests to write out a single |
911 | * contiguous dirty area on one page. | 977 | * contiguous dirty area on one page. |
912 | */ | 978 | */ |
913 | static int nfs_flush_multi(struct list_head *head, struct inode *inode, int how) | 979 | static int nfs_flush_multi(struct inode *inode, struct list_head *head, int how) |
914 | { | 980 | { |
915 | struct nfs_page *req = nfs_list_entry(head->next); | 981 | struct nfs_page *req = nfs_list_entry(head->next); |
916 | struct page *page = req->wb_page; | 982 | struct page *page = req->wb_page; |
@@ -944,14 +1010,15 @@ static int nfs_flush_multi(struct list_head *head, struct inode *inode, int how) | |||
944 | list_del_init(&data->pages); | 1010 | list_del_init(&data->pages); |
945 | 1011 | ||
946 | data->pagevec[0] = page; | 1012 | data->pagevec[0] = page; |
947 | data->complete = nfs_writeback_done_partial; | ||
948 | 1013 | ||
949 | if (nbytes > wsize) { | 1014 | if (nbytes > wsize) { |
950 | nfs_write_rpcsetup(req, data, wsize, offset, how); | 1015 | nfs_write_rpcsetup(req, data, &nfs_write_partial_ops, |
1016 | wsize, offset, how); | ||
951 | offset += wsize; | 1017 | offset += wsize; |
952 | nbytes -= wsize; | 1018 | nbytes -= wsize; |
953 | } else { | 1019 | } else { |
954 | nfs_write_rpcsetup(req, data, nbytes, offset, how); | 1020 | nfs_write_rpcsetup(req, data, &nfs_write_partial_ops, |
1021 | nbytes, offset, how); | ||
955 | nbytes = 0; | 1022 | nbytes = 0; |
956 | } | 1023 | } |
957 | nfs_execute_write(data); | 1024 | nfs_execute_write(data); |
@@ -978,16 +1045,13 @@ out_bad: | |||
978 | * This is the case if nfs_updatepage detects a conflicting request | 1045 | * This is the case if nfs_updatepage detects a conflicting request |
979 | * that has been written but not committed. | 1046 | * that has been written but not committed. |
980 | */ | 1047 | */ |
981 | static int nfs_flush_one(struct list_head *head, struct inode *inode, int how) | 1048 | static int nfs_flush_one(struct inode *inode, struct list_head *head, int how) |
982 | { | 1049 | { |
983 | struct nfs_page *req; | 1050 | struct nfs_page *req; |
984 | struct page **pages; | 1051 | struct page **pages; |
985 | struct nfs_write_data *data; | 1052 | struct nfs_write_data *data; |
986 | unsigned int count; | 1053 | unsigned int count; |
987 | 1054 | ||
988 | if (NFS_SERVER(inode)->wsize < PAGE_CACHE_SIZE) | ||
989 | return nfs_flush_multi(head, inode, how); | ||
990 | |||
991 | data = nfs_writedata_alloc(NFS_SERVER(inode)->wpages); | 1055 | data = nfs_writedata_alloc(NFS_SERVER(inode)->wpages); |
992 | if (!data) | 1056 | if (!data) |
993 | goto out_bad; | 1057 | goto out_bad; |
@@ -1005,9 +1069,8 @@ static int nfs_flush_one(struct list_head *head, struct inode *inode, int how) | |||
1005 | } | 1069 | } |
1006 | req = nfs_list_entry(data->pages.next); | 1070 | req = nfs_list_entry(data->pages.next); |
1007 | 1071 | ||
1008 | data->complete = nfs_writeback_done_full; | ||
1009 | /* Set up the argument struct */ | 1072 | /* Set up the argument struct */ |
1010 | nfs_write_rpcsetup(req, data, count, 0, how); | 1073 | nfs_write_rpcsetup(req, data, &nfs_write_full_ops, count, 0, how); |
1011 | 1074 | ||
1012 | nfs_execute_write(data); | 1075 | nfs_execute_write(data); |
1013 | return 0; | 1076 | return 0; |
@@ -1021,24 +1084,32 @@ static int nfs_flush_one(struct list_head *head, struct inode *inode, int how) | |||
1021 | return -ENOMEM; | 1084 | return -ENOMEM; |
1022 | } | 1085 | } |
1023 | 1086 | ||
1024 | static int | 1087 | static int nfs_flush_list(struct inode *inode, struct list_head *head, int npages, int how) |
1025 | nfs_flush_list(struct list_head *head, int wpages, int how) | ||
1026 | { | 1088 | { |
1027 | LIST_HEAD(one_request); | 1089 | LIST_HEAD(one_request); |
1028 | struct nfs_page *req; | 1090 | int (*flush_one)(struct inode *, struct list_head *, int); |
1029 | int error = 0; | 1091 | struct nfs_page *req; |
1030 | unsigned int pages = 0; | 1092 | int wpages = NFS_SERVER(inode)->wpages; |
1093 | int wsize = NFS_SERVER(inode)->wsize; | ||
1094 | int error; | ||
1031 | 1095 | ||
1032 | while (!list_empty(head)) { | 1096 | flush_one = nfs_flush_one; |
1033 | pages += nfs_coalesce_requests(head, &one_request, wpages); | 1097 | if (wsize < PAGE_CACHE_SIZE) |
1098 | flush_one = nfs_flush_multi; | ||
1099 | /* For single writes, FLUSH_STABLE is more efficient */ | ||
1100 | if (npages <= wpages && npages == NFS_I(inode)->npages | ||
1101 | && nfs_list_entry(head->next)->wb_bytes <= wsize) | ||
1102 | how |= FLUSH_STABLE; | ||
1103 | |||
1104 | do { | ||
1105 | nfs_coalesce_requests(head, &one_request, wpages); | ||
1034 | req = nfs_list_entry(one_request.next); | 1106 | req = nfs_list_entry(one_request.next); |
1035 | error = nfs_flush_one(&one_request, req->wb_context->dentry->d_inode, how); | 1107 | error = flush_one(inode, &one_request, how); |
1036 | if (error < 0) | 1108 | if (error < 0) |
1037 | break; | 1109 | goto out_err; |
1038 | } | 1110 | } while (!list_empty(head)); |
1039 | if (error >= 0) | 1111 | return 0; |
1040 | return pages; | 1112 | out_err: |
1041 | |||
1042 | while (!list_empty(head)) { | 1113 | while (!list_empty(head)) { |
1043 | req = nfs_list_entry(head->next); | 1114 | req = nfs_list_entry(head->next); |
1044 | nfs_list_remove_request(req); | 1115 | nfs_list_remove_request(req); |
@@ -1051,8 +1122,9 @@ nfs_flush_list(struct list_head *head, int wpages, int how) | |||
1051 | /* | 1122 | /* |
1052 | * Handle a write reply that flushed part of a page. | 1123 | * Handle a write reply that flushed part of a page. |
1053 | */ | 1124 | */ |
1054 | static void nfs_writeback_done_partial(struct nfs_write_data *data, int status) | 1125 | static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata) |
1055 | { | 1126 | { |
1127 | struct nfs_write_data *data = calldata; | ||
1056 | struct nfs_page *req = data->req; | 1128 | struct nfs_page *req = data->req; |
1057 | struct page *page = req->wb_page; | 1129 | struct page *page = req->wb_page; |
1058 | 1130 | ||
@@ -1062,11 +1134,14 @@ static void nfs_writeback_done_partial(struct nfs_write_data *data, int status) | |||
1062 | req->wb_bytes, | 1134 | req->wb_bytes, |
1063 | (long long)req_offset(req)); | 1135 | (long long)req_offset(req)); |
1064 | 1136 | ||
1065 | if (status < 0) { | 1137 | if (nfs_writeback_done(task, data) != 0) |
1138 | return; | ||
1139 | |||
1140 | if (task->tk_status < 0) { | ||
1066 | ClearPageUptodate(page); | 1141 | ClearPageUptodate(page); |
1067 | SetPageError(page); | 1142 | SetPageError(page); |
1068 | req->wb_context->error = status; | 1143 | req->wb_context->error = task->tk_status; |
1069 | dprintk(", error = %d\n", status); | 1144 | dprintk(", error = %d\n", task->tk_status); |
1070 | } else { | 1145 | } else { |
1071 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 1146 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
1072 | if (data->verf.committed < NFS_FILE_SYNC) { | 1147 | if (data->verf.committed < NFS_FILE_SYNC) { |
@@ -1087,6 +1162,11 @@ static void nfs_writeback_done_partial(struct nfs_write_data *data, int status) | |||
1087 | nfs_writepage_release(req); | 1162 | nfs_writepage_release(req); |
1088 | } | 1163 | } |
1089 | 1164 | ||
1165 | static const struct rpc_call_ops nfs_write_partial_ops = { | ||
1166 | .rpc_call_done = nfs_writeback_done_partial, | ||
1167 | .rpc_release = nfs_writedata_release, | ||
1168 | }; | ||
1169 | |||
1090 | /* | 1170 | /* |
1091 | * Handle a write reply that flushes a whole page. | 1171 | * Handle a write reply that flushes a whole page. |
1092 | * | 1172 | * |
@@ -1094,11 +1174,15 @@ static void nfs_writeback_done_partial(struct nfs_write_data *data, int status) | |||
1094 | * writebacks since the page->count is kept > 1 for as long | 1174 | * writebacks since the page->count is kept > 1 for as long |
1095 | * as the page has a write request pending. | 1175 | * as the page has a write request pending. |
1096 | */ | 1176 | */ |
1097 | static void nfs_writeback_done_full(struct nfs_write_data *data, int status) | 1177 | static void nfs_writeback_done_full(struct rpc_task *task, void *calldata) |
1098 | { | 1178 | { |
1179 | struct nfs_write_data *data = calldata; | ||
1099 | struct nfs_page *req; | 1180 | struct nfs_page *req; |
1100 | struct page *page; | 1181 | struct page *page; |
1101 | 1182 | ||
1183 | if (nfs_writeback_done(task, data) != 0) | ||
1184 | return; | ||
1185 | |||
1102 | /* Update attributes as result of writeback. */ | 1186 | /* Update attributes as result of writeback. */ |
1103 | while (!list_empty(&data->pages)) { | 1187 | while (!list_empty(&data->pages)) { |
1104 | req = nfs_list_entry(data->pages.next); | 1188 | req = nfs_list_entry(data->pages.next); |
@@ -1111,13 +1195,13 @@ static void nfs_writeback_done_full(struct nfs_write_data *data, int status) | |||
1111 | req->wb_bytes, | 1195 | req->wb_bytes, |
1112 | (long long)req_offset(req)); | 1196 | (long long)req_offset(req)); |
1113 | 1197 | ||
1114 | if (status < 0) { | 1198 | if (task->tk_status < 0) { |
1115 | ClearPageUptodate(page); | 1199 | ClearPageUptodate(page); |
1116 | SetPageError(page); | 1200 | SetPageError(page); |
1117 | req->wb_context->error = status; | 1201 | req->wb_context->error = task->tk_status; |
1118 | end_page_writeback(page); | 1202 | end_page_writeback(page); |
1119 | nfs_inode_remove_request(req); | 1203 | nfs_inode_remove_request(req); |
1120 | dprintk(", error = %d\n", status); | 1204 | dprintk(", error = %d\n", task->tk_status); |
1121 | goto next; | 1205 | goto next; |
1122 | } | 1206 | } |
1123 | end_page_writeback(page); | 1207 | end_page_writeback(page); |
@@ -1139,18 +1223,30 @@ static void nfs_writeback_done_full(struct nfs_write_data *data, int status) | |||
1139 | } | 1223 | } |
1140 | } | 1224 | } |
1141 | 1225 | ||
1226 | static const struct rpc_call_ops nfs_write_full_ops = { | ||
1227 | .rpc_call_done = nfs_writeback_done_full, | ||
1228 | .rpc_release = nfs_writedata_release, | ||
1229 | }; | ||
1230 | |||
1231 | |||
1142 | /* | 1232 | /* |
1143 | * This function is called when the WRITE call is complete. | 1233 | * This function is called when the WRITE call is complete. |
1144 | */ | 1234 | */ |
1145 | void nfs_writeback_done(struct rpc_task *task, void *calldata) | 1235 | int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) |
1146 | { | 1236 | { |
1147 | struct nfs_write_data *data = calldata; | ||
1148 | struct nfs_writeargs *argp = &data->args; | 1237 | struct nfs_writeargs *argp = &data->args; |
1149 | struct nfs_writeres *resp = &data->res; | 1238 | struct nfs_writeres *resp = &data->res; |
1239 | int status; | ||
1150 | 1240 | ||
1151 | dprintk("NFS: %4d nfs_writeback_done (status %d)\n", | 1241 | dprintk("NFS: %4d nfs_writeback_done (status %d)\n", |
1152 | task->tk_pid, task->tk_status); | 1242 | task->tk_pid, task->tk_status); |
1153 | 1243 | ||
1244 | /* Call the NFS version-specific code */ | ||
1245 | status = NFS_PROTO(data->inode)->write_done(task, data); | ||
1246 | if (status != 0) | ||
1247 | return status; | ||
1248 | nfs_add_stats(data->inode, NFSIOS_SERVERWRITTENBYTES, resp->count); | ||
1249 | |||
1154 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 1250 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
1155 | if (resp->verf->committed < argp->stable && task->tk_status >= 0) { | 1251 | if (resp->verf->committed < argp->stable && task->tk_status >= 0) { |
1156 | /* We tried a write call, but the server did not | 1252 | /* We tried a write call, but the server did not |
@@ -1176,6 +1272,8 @@ void nfs_writeback_done(struct rpc_task *task, void *calldata) | |||
1176 | if (task->tk_status >= 0 && resp->count < argp->count) { | 1272 | if (task->tk_status >= 0 && resp->count < argp->count) { |
1177 | static unsigned long complain; | 1273 | static unsigned long complain; |
1178 | 1274 | ||
1275 | nfs_inc_stats(data->inode, NFSIOS_SHORTWRITE); | ||
1276 | |||
1179 | /* Has the server at least made some progress? */ | 1277 | /* Has the server at least made some progress? */ |
1180 | if (resp->count != 0) { | 1278 | if (resp->count != 0) { |
1181 | /* Was this an NFSv2 write or an NFSv3 stable write? */ | 1279 | /* Was this an NFSv2 write or an NFSv3 stable write? */ |
@@ -1191,7 +1289,7 @@ void nfs_writeback_done(struct rpc_task *task, void *calldata) | |||
1191 | argp->stable = NFS_FILE_SYNC; | 1289 | argp->stable = NFS_FILE_SYNC; |
1192 | } | 1290 | } |
1193 | rpc_restart_call(task); | 1291 | rpc_restart_call(task); |
1194 | return; | 1292 | return -EAGAIN; |
1195 | } | 1293 | } |
1196 | if (time_before(complain, jiffies)) { | 1294 | if (time_before(complain, jiffies)) { |
1197 | printk(KERN_WARNING | 1295 | printk(KERN_WARNING |
@@ -1202,11 +1300,7 @@ void nfs_writeback_done(struct rpc_task *task, void *calldata) | |||
1202 | /* Can't do anything about it except throw an error. */ | 1300 | /* Can't do anything about it except throw an error. */ |
1203 | task->tk_status = -EIO; | 1301 | task->tk_status = -EIO; |
1204 | } | 1302 | } |
1205 | 1303 | return 0; | |
1206 | /* | ||
1207 | * Process the nfs_page list | ||
1208 | */ | ||
1209 | data->complete(data, task->tk_status); | ||
1210 | } | 1304 | } |
1211 | 1305 | ||
1212 | 1306 | ||
@@ -1220,10 +1314,12 @@ void nfs_commit_release(void *wdata) | |||
1220 | * Set up the argument/result storage required for the RPC call. | 1314 | * Set up the argument/result storage required for the RPC call. |
1221 | */ | 1315 | */ |
1222 | static void nfs_commit_rpcsetup(struct list_head *head, | 1316 | static void nfs_commit_rpcsetup(struct list_head *head, |
1223 | struct nfs_write_data *data, int how) | 1317 | struct nfs_write_data *data, |
1318 | int how) | ||
1224 | { | 1319 | { |
1225 | struct nfs_page *first; | 1320 | struct nfs_page *first; |
1226 | struct inode *inode; | 1321 | struct inode *inode; |
1322 | int flags; | ||
1227 | 1323 | ||
1228 | /* Set up the RPC argument and reply structs | 1324 | /* Set up the RPC argument and reply structs |
1229 | * NB: take care not to mess about with data->commit et al. */ | 1325 | * NB: take care not to mess about with data->commit et al. */ |
@@ -1243,7 +1339,10 @@ static void nfs_commit_rpcsetup(struct list_head *head, | |||
1243 | data->res.fattr = &data->fattr; | 1339 | data->res.fattr = &data->fattr; |
1244 | data->res.verf = &data->verf; | 1340 | data->res.verf = &data->verf; |
1245 | nfs_fattr_init(&data->fattr); | 1341 | nfs_fattr_init(&data->fattr); |
1246 | 1342 | ||
1343 | /* Set up the initial task struct. */ | ||
1344 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | ||
1345 | rpc_init_task(&data->task, NFS_CLIENT(inode), flags, &nfs_commit_ops, data); | ||
1247 | NFS_PROTO(inode)->commit_setup(data, how); | 1346 | NFS_PROTO(inode)->commit_setup(data, how); |
1248 | 1347 | ||
1249 | data->task.tk_priority = flush_task_priority(how); | 1348 | data->task.tk_priority = flush_task_priority(how); |
@@ -1284,7 +1383,7 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how) | |||
1284 | /* | 1383 | /* |
1285 | * COMMIT call returned | 1384 | * COMMIT call returned |
1286 | */ | 1385 | */ |
1287 | void nfs_commit_done(struct rpc_task *task, void *calldata) | 1386 | static void nfs_commit_done(struct rpc_task *task, void *calldata) |
1288 | { | 1387 | { |
1289 | struct nfs_write_data *data = calldata; | 1388 | struct nfs_write_data *data = calldata; |
1290 | struct nfs_page *req; | 1389 | struct nfs_page *req; |
@@ -1293,6 +1392,10 @@ void nfs_commit_done(struct rpc_task *task, void *calldata) | |||
1293 | dprintk("NFS: %4d nfs_commit_done (status %d)\n", | 1392 | dprintk("NFS: %4d nfs_commit_done (status %d)\n", |
1294 | task->tk_pid, task->tk_status); | 1393 | task->tk_pid, task->tk_status); |
1295 | 1394 | ||
1395 | /* Call the NFS version-specific code */ | ||
1396 | if (NFS_PROTO(data->inode)->commit_done(task, data) != 0) | ||
1397 | return; | ||
1398 | |||
1296 | while (!list_empty(&data->pages)) { | 1399 | while (!list_empty(&data->pages)) { |
1297 | req = nfs_list_entry(data->pages.next); | 1400 | req = nfs_list_entry(data->pages.next); |
1298 | nfs_list_remove_request(req); | 1401 | nfs_list_remove_request(req); |
@@ -1326,6 +1429,16 @@ void nfs_commit_done(struct rpc_task *task, void *calldata) | |||
1326 | } | 1429 | } |
1327 | sub_page_state(nr_unstable,res); | 1430 | sub_page_state(nr_unstable,res); |
1328 | } | 1431 | } |
1432 | |||
1433 | static const struct rpc_call_ops nfs_commit_ops = { | ||
1434 | .rpc_call_done = nfs_commit_done, | ||
1435 | .rpc_release = nfs_commit_release, | ||
1436 | }; | ||
1437 | #else | ||
1438 | static inline int nfs_commit_list(struct inode *inode, struct list_head *head, int how) | ||
1439 | { | ||
1440 | return 0; | ||
1441 | } | ||
1329 | #endif | 1442 | #endif |
1330 | 1443 | ||
1331 | static int nfs_flush_inode(struct inode *inode, unsigned long idx_start, | 1444 | static int nfs_flush_inode(struct inode *inode, unsigned long idx_start, |
@@ -1333,24 +1446,16 @@ static int nfs_flush_inode(struct inode *inode, unsigned long idx_start, | |||
1333 | { | 1446 | { |
1334 | struct nfs_inode *nfsi = NFS_I(inode); | 1447 | struct nfs_inode *nfsi = NFS_I(inode); |
1335 | LIST_HEAD(head); | 1448 | LIST_HEAD(head); |
1336 | int res, | 1449 | int res; |
1337 | error = 0; | ||
1338 | 1450 | ||
1339 | spin_lock(&nfsi->req_lock); | 1451 | spin_lock(&nfsi->req_lock); |
1340 | res = nfs_scan_dirty(inode, &head, idx_start, npages); | 1452 | res = nfs_scan_dirty(inode, &head, idx_start, npages); |
1341 | spin_unlock(&nfsi->req_lock); | 1453 | spin_unlock(&nfsi->req_lock); |
1342 | if (res) { | 1454 | if (res) { |
1343 | struct nfs_server *server = NFS_SERVER(inode); | 1455 | int error = nfs_flush_list(inode, &head, res, how); |
1344 | 1456 | if (error < 0) | |
1345 | /* For single writes, FLUSH_STABLE is more efficient */ | 1457 | return error; |
1346 | if (res == nfsi->npages && nfsi->npages <= server->wpages) { | ||
1347 | if (res > 1 || nfs_list_entry(head.next)->wb_bytes <= server->wsize) | ||
1348 | how |= FLUSH_STABLE; | ||
1349 | } | ||
1350 | error = nfs_flush_list(&head, server->wpages, how); | ||
1351 | } | 1458 | } |
1352 | if (error < 0) | ||
1353 | return error; | ||
1354 | return res; | 1459 | return res; |
1355 | } | 1460 | } |
1356 | 1461 | ||
@@ -1359,14 +1464,13 @@ int nfs_commit_inode(struct inode *inode, int how) | |||
1359 | { | 1464 | { |
1360 | struct nfs_inode *nfsi = NFS_I(inode); | 1465 | struct nfs_inode *nfsi = NFS_I(inode); |
1361 | LIST_HEAD(head); | 1466 | LIST_HEAD(head); |
1362 | int res, | 1467 | int res; |
1363 | error = 0; | ||
1364 | 1468 | ||
1365 | spin_lock(&nfsi->req_lock); | 1469 | spin_lock(&nfsi->req_lock); |
1366 | res = nfs_scan_commit(inode, &head, 0, 0); | 1470 | res = nfs_scan_commit(inode, &head, 0, 0); |
1367 | spin_unlock(&nfsi->req_lock); | 1471 | spin_unlock(&nfsi->req_lock); |
1368 | if (res) { | 1472 | if (res) { |
1369 | error = nfs_commit_list(inode, &head, how); | 1473 | int error = nfs_commit_list(inode, &head, how); |
1370 | if (error < 0) | 1474 | if (error < 0) |
1371 | return error; | 1475 | return error; |
1372 | } | 1476 | } |
@@ -1374,28 +1478,38 @@ int nfs_commit_inode(struct inode *inode, int how) | |||
1374 | } | 1478 | } |
1375 | #endif | 1479 | #endif |
1376 | 1480 | ||
1377 | int nfs_sync_inode(struct inode *inode, unsigned long idx_start, | 1481 | int nfs_sync_inode_wait(struct inode *inode, unsigned long idx_start, |
1378 | unsigned int npages, int how) | 1482 | unsigned int npages, int how) |
1379 | { | 1483 | { |
1484 | struct nfs_inode *nfsi = NFS_I(inode); | ||
1485 | LIST_HEAD(head); | ||
1380 | int nocommit = how & FLUSH_NOCOMMIT; | 1486 | int nocommit = how & FLUSH_NOCOMMIT; |
1381 | int wait = how & FLUSH_WAIT; | 1487 | int pages, ret; |
1382 | int error; | ||
1383 | |||
1384 | how &= ~(FLUSH_WAIT|FLUSH_NOCOMMIT); | ||
1385 | 1488 | ||
1489 | how &= ~FLUSH_NOCOMMIT; | ||
1490 | spin_lock(&nfsi->req_lock); | ||
1386 | do { | 1491 | do { |
1387 | if (wait) { | 1492 | ret = nfs_wait_on_requests_locked(inode, idx_start, npages); |
1388 | error = nfs_wait_on_requests(inode, idx_start, npages); | 1493 | if (ret != 0) |
1389 | if (error != 0) | ||
1390 | continue; | ||
1391 | } | ||
1392 | error = nfs_flush_inode(inode, idx_start, npages, how); | ||
1393 | if (error != 0) | ||
1394 | continue; | 1494 | continue; |
1395 | if (!nocommit) | 1495 | pages = nfs_scan_dirty(inode, &head, idx_start, npages); |
1396 | error = nfs_commit_inode(inode, how); | 1496 | if (pages != 0) { |
1397 | } while (error > 0); | 1497 | spin_unlock(&nfsi->req_lock); |
1398 | return error; | 1498 | ret = nfs_flush_list(inode, &head, pages, how); |
1499 | spin_lock(&nfsi->req_lock); | ||
1500 | continue; | ||
1501 | } | ||
1502 | if (nocommit) | ||
1503 | break; | ||
1504 | pages = nfs_scan_commit(inode, &head, 0, 0); | ||
1505 | if (pages == 0) | ||
1506 | break; | ||
1507 | spin_unlock(&nfsi->req_lock); | ||
1508 | ret = nfs_commit_list(inode, &head, how); | ||
1509 | spin_lock(&nfsi->req_lock); | ||
1510 | } while (ret >= 0); | ||
1511 | spin_unlock(&nfsi->req_lock); | ||
1512 | return ret; | ||
1399 | } | 1513 | } |
1400 | 1514 | ||
1401 | int nfs_init_writepagecache(void) | 1515 | int nfs_init_writepagecache(void) |