diff options
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/callback.c | 1 | ||||
-rw-r--r-- | fs/nfs/delegation.c | 1 | ||||
-rw-r--r-- | fs/nfs/dir.c | 220 | ||||
-rw-r--r-- | fs/nfs/direct.c | 2 | ||||
-rw-r--r-- | fs/nfs/file.c | 2 | ||||
-rw-r--r-- | fs/nfs/inode.c | 1 | ||||
-rw-r--r-- | fs/nfs/internal.h | 9 | ||||
-rw-r--r-- | fs/nfs/mount_clnt.c | 4 | ||||
-rw-r--r-- | fs/nfs/nfs2xdr.c | 8 | ||||
-rw-r--r-- | fs/nfs/nfs3xdr.c | 8 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 13 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 8 | ||||
-rw-r--r-- | fs/nfs/pagelist.c | 4 | ||||
-rw-r--r-- | fs/nfs/read.c | 1 | ||||
-rw-r--r-- | fs/nfs/super.c | 13 | ||||
-rw-r--r-- | fs/nfs/write.c | 3 |
16 files changed, 177 insertions, 121 deletions
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index aeec017fe814..93a8b3bd69e3 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
@@ -9,7 +9,6 @@ | |||
9 | #include <linux/completion.h> | 9 | #include <linux/completion.h> |
10 | #include <linux/ip.h> | 10 | #include <linux/ip.h> |
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/smp_lock.h> | ||
13 | #include <linux/sunrpc/svc.h> | 12 | #include <linux/sunrpc/svc.h> |
14 | #include <linux/sunrpc/svcsock.h> | 13 | #include <linux/sunrpc/svcsock.h> |
15 | #include <linux/nfs_fs.h> | 14 | #include <linux/nfs_fs.h> |
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 232a7eead33a..1fd62fc49be3 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
@@ -11,7 +11,6 @@ | |||
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/sched.h> | 12 | #include <linux/sched.h> |
13 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
14 | #include <linux/smp_lock.h> | ||
15 | #include <linux/spinlock.h> | 14 | #include <linux/spinlock.h> |
16 | 15 | ||
17 | #include <linux/nfs4.h> | 16 | #include <linux/nfs4.h> |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 07ac3847e562..996dd8989a91 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/mount.h> | 34 | #include <linux/mount.h> |
35 | #include <linux/sched.h> | 35 | #include <linux/sched.h> |
36 | #include <linux/vmalloc.h> | 36 | #include <linux/vmalloc.h> |
37 | #include <linux/kmemleak.h> | ||
37 | 38 | ||
38 | #include "delegation.h" | 39 | #include "delegation.h" |
39 | #include "iostat.h" | 40 | #include "iostat.h" |
@@ -56,7 +57,7 @@ static int nfs_rename(struct inode *, struct dentry *, | |||
56 | struct inode *, struct dentry *); | 57 | struct inode *, struct dentry *); |
57 | static int nfs_fsync_dir(struct file *, int); | 58 | static int nfs_fsync_dir(struct file *, int); |
58 | static loff_t nfs_llseek_dir(struct file *, loff_t, int); | 59 | static loff_t nfs_llseek_dir(struct file *, loff_t, int); |
59 | static int nfs_readdir_clear_array(struct page*, gfp_t); | 60 | static void nfs_readdir_clear_array(struct page*); |
60 | 61 | ||
61 | const struct file_operations nfs_dir_operations = { | 62 | const struct file_operations nfs_dir_operations = { |
62 | .llseek = nfs_llseek_dir, | 63 | .llseek = nfs_llseek_dir, |
@@ -82,8 +83,8 @@ const struct inode_operations nfs_dir_inode_operations = { | |||
82 | .setattr = nfs_setattr, | 83 | .setattr = nfs_setattr, |
83 | }; | 84 | }; |
84 | 85 | ||
85 | const struct address_space_operations nfs_dir_addr_space_ops = { | 86 | const struct address_space_operations nfs_dir_aops = { |
86 | .releasepage = nfs_readdir_clear_array, | 87 | .freepage = nfs_readdir_clear_array, |
87 | }; | 88 | }; |
88 | 89 | ||
89 | #ifdef CONFIG_NFS_V3 | 90 | #ifdef CONFIG_NFS_V3 |
@@ -161,6 +162,7 @@ struct nfs_cache_array_entry { | |||
161 | u64 cookie; | 162 | u64 cookie; |
162 | u64 ino; | 163 | u64 ino; |
163 | struct qstr string; | 164 | struct qstr string; |
165 | unsigned char d_type; | ||
164 | }; | 166 | }; |
165 | 167 | ||
166 | struct nfs_cache_array { | 168 | struct nfs_cache_array { |
@@ -170,14 +172,13 @@ struct nfs_cache_array { | |||
170 | struct nfs_cache_array_entry array[0]; | 172 | struct nfs_cache_array_entry array[0]; |
171 | }; | 173 | }; |
172 | 174 | ||
173 | #define MAX_READDIR_ARRAY ((PAGE_SIZE - sizeof(struct nfs_cache_array)) / sizeof(struct nfs_cache_array_entry)) | ||
174 | |||
175 | typedef __be32 * (*decode_dirent_t)(struct xdr_stream *, struct nfs_entry *, struct nfs_server *, int); | 175 | typedef __be32 * (*decode_dirent_t)(struct xdr_stream *, struct nfs_entry *, struct nfs_server *, int); |
176 | typedef struct { | 176 | typedef struct { |
177 | struct file *file; | 177 | struct file *file; |
178 | struct page *page; | 178 | struct page *page; |
179 | unsigned long page_index; | 179 | unsigned long page_index; |
180 | u64 *dir_cookie; | 180 | u64 *dir_cookie; |
181 | u64 last_cookie; | ||
181 | loff_t current_index; | 182 | loff_t current_index; |
182 | decode_dirent_t decode; | 183 | decode_dirent_t decode; |
183 | 184 | ||
@@ -194,9 +195,13 @@ typedef struct { | |||
194 | static | 195 | static |
195 | struct nfs_cache_array *nfs_readdir_get_array(struct page *page) | 196 | struct nfs_cache_array *nfs_readdir_get_array(struct page *page) |
196 | { | 197 | { |
198 | void *ptr; | ||
197 | if (page == NULL) | 199 | if (page == NULL) |
198 | return ERR_PTR(-EIO); | 200 | return ERR_PTR(-EIO); |
199 | return (struct nfs_cache_array *)kmap(page); | 201 | ptr = kmap(page); |
202 | if (ptr == NULL) | ||
203 | return ERR_PTR(-ENOMEM); | ||
204 | return ptr; | ||
200 | } | 205 | } |
201 | 206 | ||
202 | static | 207 | static |
@@ -209,14 +214,15 @@ void nfs_readdir_release_array(struct page *page) | |||
209 | * we are freeing strings created by nfs_add_to_readdir_array() | 214 | * we are freeing strings created by nfs_add_to_readdir_array() |
210 | */ | 215 | */ |
211 | static | 216 | static |
212 | int nfs_readdir_clear_array(struct page *page, gfp_t mask) | 217 | void nfs_readdir_clear_array(struct page *page) |
213 | { | 218 | { |
214 | struct nfs_cache_array *array = nfs_readdir_get_array(page); | 219 | struct nfs_cache_array *array; |
215 | int i; | 220 | int i; |
221 | |||
222 | array = kmap_atomic(page, KM_USER0); | ||
216 | for (i = 0; i < array->size; i++) | 223 | for (i = 0; i < array->size; i++) |
217 | kfree(array->array[i].string.name); | 224 | kfree(array->array[i].string.name); |
218 | nfs_readdir_release_array(page); | 225 | kunmap_atomic(array, KM_USER0); |
219 | return 0; | ||
220 | } | 226 | } |
221 | 227 | ||
222 | /* | 228 | /* |
@@ -231,6 +237,11 @@ int nfs_readdir_make_qstr(struct qstr *string, const char *name, unsigned int le | |||
231 | string->name = kmemdup(name, len, GFP_KERNEL); | 237 | string->name = kmemdup(name, len, GFP_KERNEL); |
232 | if (string->name == NULL) | 238 | if (string->name == NULL) |
233 | return -ENOMEM; | 239 | return -ENOMEM; |
240 | /* | ||
241 | * Avoid a kmemleak false positive. The pointer to the name is stored | ||
242 | * in a page cache page which kmemleak does not scan. | ||
243 | */ | ||
244 | kmemleak_not_leak(string->name); | ||
234 | string->hash = full_name_hash(name, len); | 245 | string->hash = full_name_hash(name, len); |
235 | return 0; | 246 | return 0; |
236 | } | 247 | } |
@@ -244,20 +255,24 @@ int nfs_readdir_add_to_array(struct nfs_entry *entry, struct page *page) | |||
244 | 255 | ||
245 | if (IS_ERR(array)) | 256 | if (IS_ERR(array)) |
246 | return PTR_ERR(array); | 257 | return PTR_ERR(array); |
247 | ret = -EIO; | ||
248 | if (array->size >= MAX_READDIR_ARRAY) | ||
249 | goto out; | ||
250 | 258 | ||
251 | cache_entry = &array->array[array->size]; | 259 | cache_entry = &array->array[array->size]; |
260 | |||
261 | /* Check that this entry lies within the page bounds */ | ||
262 | ret = -ENOSPC; | ||
263 | if ((char *)&cache_entry[1] - (char *)page_address(page) > PAGE_SIZE) | ||
264 | goto out; | ||
265 | |||
252 | cache_entry->cookie = entry->prev_cookie; | 266 | cache_entry->cookie = entry->prev_cookie; |
253 | cache_entry->ino = entry->ino; | 267 | cache_entry->ino = entry->ino; |
268 | cache_entry->d_type = entry->d_type; | ||
254 | ret = nfs_readdir_make_qstr(&cache_entry->string, entry->name, entry->len); | 269 | ret = nfs_readdir_make_qstr(&cache_entry->string, entry->name, entry->len); |
255 | if (ret) | 270 | if (ret) |
256 | goto out; | 271 | goto out; |
257 | array->last_cookie = entry->cookie; | 272 | array->last_cookie = entry->cookie; |
258 | if (entry->eof == 1) | ||
259 | array->eof_index = array->size; | ||
260 | array->size++; | 273 | array->size++; |
274 | if (entry->eof != 0) | ||
275 | array->eof_index = array->size; | ||
261 | out: | 276 | out: |
262 | nfs_readdir_release_array(page); | 277 | nfs_readdir_release_array(page); |
263 | return ret; | 278 | return ret; |
@@ -272,7 +287,7 @@ int nfs_readdir_search_for_pos(struct nfs_cache_array *array, nfs_readdir_descri | |||
272 | if (diff < 0) | 287 | if (diff < 0) |
273 | goto out_eof; | 288 | goto out_eof; |
274 | if (diff >= array->size) { | 289 | if (diff >= array->size) { |
275 | if (array->eof_index > 0) | 290 | if (array->eof_index >= 0) |
276 | goto out_eof; | 291 | goto out_eof; |
277 | desc->current_index += array->size; | 292 | desc->current_index += array->size; |
278 | return -EAGAIN; | 293 | return -EAGAIN; |
@@ -281,8 +296,6 @@ int nfs_readdir_search_for_pos(struct nfs_cache_array *array, nfs_readdir_descri | |||
281 | index = (unsigned int)diff; | 296 | index = (unsigned int)diff; |
282 | *desc->dir_cookie = array->array[index].cookie; | 297 | *desc->dir_cookie = array->array[index].cookie; |
283 | desc->cache_entry_index = index; | 298 | desc->cache_entry_index = index; |
284 | if (index == array->eof_index) | ||
285 | desc->eof = 1; | ||
286 | return 0; | 299 | return 0; |
287 | out_eof: | 300 | out_eof: |
288 | desc->eof = 1; | 301 | desc->eof = 1; |
@@ -296,17 +309,16 @@ int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_des | |||
296 | int status = -EAGAIN; | 309 | int status = -EAGAIN; |
297 | 310 | ||
298 | for (i = 0; i < array->size; i++) { | 311 | for (i = 0; i < array->size; i++) { |
299 | if (i == array->eof_index) { | ||
300 | desc->eof = 1; | ||
301 | status = -EBADCOOKIE; | ||
302 | } | ||
303 | if (array->array[i].cookie == *desc->dir_cookie) { | 312 | if (array->array[i].cookie == *desc->dir_cookie) { |
304 | desc->cache_entry_index = i; | 313 | desc->cache_entry_index = i; |
305 | status = 0; | 314 | return 0; |
306 | break; | ||
307 | } | 315 | } |
308 | } | 316 | } |
309 | 317 | if (array->eof_index >= 0) { | |
318 | status = -EBADCOOKIE; | ||
319 | if (*desc->dir_cookie == array->last_cookie) | ||
320 | desc->eof = 1; | ||
321 | } | ||
310 | return status; | 322 | return status; |
311 | } | 323 | } |
312 | 324 | ||
@@ -314,10 +326,7 @@ static | |||
314 | int nfs_readdir_search_array(nfs_readdir_descriptor_t *desc) | 326 | int nfs_readdir_search_array(nfs_readdir_descriptor_t *desc) |
315 | { | 327 | { |
316 | struct nfs_cache_array *array; | 328 | struct nfs_cache_array *array; |
317 | int status = -EBADCOOKIE; | 329 | int status; |
318 | |||
319 | if (desc->dir_cookie == NULL) | ||
320 | goto out; | ||
321 | 330 | ||
322 | array = nfs_readdir_get_array(desc->page); | 331 | array = nfs_readdir_get_array(desc->page); |
323 | if (IS_ERR(array)) { | 332 | if (IS_ERR(array)) { |
@@ -330,6 +339,10 @@ int nfs_readdir_search_array(nfs_readdir_descriptor_t *desc) | |||
330 | else | 339 | else |
331 | status = nfs_readdir_search_for_cookie(array, desc); | 340 | status = nfs_readdir_search_for_cookie(array, desc); |
332 | 341 | ||
342 | if (status == -EAGAIN) { | ||
343 | desc->last_cookie = array->last_cookie; | ||
344 | desc->page_index++; | ||
345 | } | ||
333 | nfs_readdir_release_array(desc->page); | 346 | nfs_readdir_release_array(desc->page); |
334 | out: | 347 | out: |
335 | return status; | 348 | return status; |
@@ -381,13 +394,9 @@ int xdr_decode(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry, struct x | |||
381 | static | 394 | static |
382 | int nfs_same_file(struct dentry *dentry, struct nfs_entry *entry) | 395 | int nfs_same_file(struct dentry *dentry, struct nfs_entry *entry) |
383 | { | 396 | { |
384 | struct nfs_inode *node; | ||
385 | if (dentry->d_inode == NULL) | 397 | if (dentry->d_inode == NULL) |
386 | goto different; | 398 | goto different; |
387 | node = NFS_I(dentry->d_inode); | 399 | if (nfs_compare_fh(entry->fh, NFS_FH(dentry->d_inode)) != 0) |
388 | if (node->fh.size != entry->fh->size) | ||
389 | goto different; | ||
390 | if (strncmp(node->fh.data, entry->fh->data, node->fh.size) != 0) | ||
391 | goto different; | 400 | goto different; |
392 | return 1; | 401 | return 1; |
393 | different: | 402 | different: |
@@ -449,14 +458,15 @@ out: | |||
449 | 458 | ||
450 | /* Perform conversion from xdr to cache array */ | 459 | /* Perform conversion from xdr to cache array */ |
451 | static | 460 | static |
452 | void nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry, | 461 | int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry, |
453 | void *xdr_page, struct page *page, unsigned int buflen) | 462 | void *xdr_page, struct page *page, unsigned int buflen) |
454 | { | 463 | { |
455 | struct xdr_stream stream; | 464 | struct xdr_stream stream; |
456 | struct xdr_buf buf; | 465 | struct xdr_buf buf; |
457 | __be32 *ptr = xdr_page; | 466 | __be32 *ptr = xdr_page; |
458 | int status; | ||
459 | struct nfs_cache_array *array; | 467 | struct nfs_cache_array *array; |
468 | unsigned int count = 0; | ||
469 | int status; | ||
460 | 470 | ||
461 | buf.head->iov_base = xdr_page; | 471 | buf.head->iov_base = xdr_page; |
462 | buf.head->iov_len = buflen; | 472 | buf.head->iov_len = buflen; |
@@ -471,21 +481,32 @@ void nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *e | |||
471 | 481 | ||
472 | do { | 482 | do { |
473 | status = xdr_decode(desc, entry, &stream); | 483 | status = xdr_decode(desc, entry, &stream); |
474 | if (status != 0) | 484 | if (status != 0) { |
485 | if (status == -EAGAIN) | ||
486 | status = 0; | ||
475 | break; | 487 | break; |
488 | } | ||
476 | 489 | ||
477 | if (nfs_readdir_add_to_array(entry, page) == -1) | 490 | count++; |
478 | break; | 491 | |
479 | if (desc->plus == 1) | 492 | if (desc->plus != 0) |
480 | nfs_prime_dcache(desc->file->f_path.dentry, entry); | 493 | nfs_prime_dcache(desc->file->f_path.dentry, entry); |
494 | |||
495 | status = nfs_readdir_add_to_array(entry, page); | ||
496 | if (status != 0) | ||
497 | break; | ||
481 | } while (!entry->eof); | 498 | } while (!entry->eof); |
482 | 499 | ||
483 | if (status == -EBADCOOKIE && entry->eof) { | 500 | if (count == 0 || (status == -EBADCOOKIE && entry->eof != 0)) { |
484 | array = nfs_readdir_get_array(page); | 501 | array = nfs_readdir_get_array(page); |
485 | array->eof_index = array->size - 1; | 502 | if (!IS_ERR(array)) { |
486 | status = 0; | 503 | array->eof_index = array->size; |
487 | nfs_readdir_release_array(page); | 504 | status = 0; |
505 | nfs_readdir_release_array(page); | ||
506 | } else | ||
507 | status = PTR_ERR(array); | ||
488 | } | 508 | } |
509 | return status; | ||
489 | } | 510 | } |
490 | 511 | ||
491 | static | 512 | static |
@@ -537,11 +558,11 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page, | |||
537 | struct nfs_entry entry; | 558 | struct nfs_entry entry; |
538 | struct file *file = desc->file; | 559 | struct file *file = desc->file; |
539 | struct nfs_cache_array *array; | 560 | struct nfs_cache_array *array; |
540 | int status = 0; | 561 | int status = -ENOMEM; |
541 | unsigned int array_size = ARRAY_SIZE(pages); | 562 | unsigned int array_size = ARRAY_SIZE(pages); |
542 | 563 | ||
543 | entry.prev_cookie = 0; | 564 | entry.prev_cookie = 0; |
544 | entry.cookie = *desc->dir_cookie; | 565 | entry.cookie = desc->last_cookie; |
545 | entry.eof = 0; | 566 | entry.eof = 0; |
546 | entry.fh = nfs_alloc_fhandle(); | 567 | entry.fh = nfs_alloc_fhandle(); |
547 | entry.fattr = nfs_alloc_fattr(); | 568 | entry.fattr = nfs_alloc_fattr(); |
@@ -549,6 +570,10 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page, | |||
549 | goto out; | 570 | goto out; |
550 | 571 | ||
551 | array = nfs_readdir_get_array(page); | 572 | array = nfs_readdir_get_array(page); |
573 | if (IS_ERR(array)) { | ||
574 | status = PTR_ERR(array); | ||
575 | goto out; | ||
576 | } | ||
552 | memset(array, 0, sizeof(struct nfs_cache_array)); | 577 | memset(array, 0, sizeof(struct nfs_cache_array)); |
553 | array->eof_index = -1; | 578 | array->eof_index = -1; |
554 | 579 | ||
@@ -556,12 +581,19 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page, | |||
556 | if (!pages_ptr) | 581 | if (!pages_ptr) |
557 | goto out_release_array; | 582 | goto out_release_array; |
558 | do { | 583 | do { |
584 | unsigned int pglen; | ||
559 | status = nfs_readdir_xdr_filler(pages, desc, &entry, file, inode); | 585 | status = nfs_readdir_xdr_filler(pages, desc, &entry, file, inode); |
560 | 586 | ||
561 | if (status < 0) | 587 | if (status < 0) |
562 | break; | 588 | break; |
563 | nfs_readdir_page_filler(desc, &entry, pages_ptr, page, array_size * PAGE_SIZE); | 589 | pglen = status; |
564 | } while (array->eof_index < 0 && array->size < MAX_READDIR_ARRAY); | 590 | status = nfs_readdir_page_filler(desc, &entry, pages_ptr, page, pglen); |
591 | if (status < 0) { | ||
592 | if (status == -ENOSPC) | ||
593 | status = 0; | ||
594 | break; | ||
595 | } | ||
596 | } while (array->eof_index < 0); | ||
565 | 597 | ||
566 | nfs_readdir_free_large_page(pages_ptr, pages, array_size); | 598 | nfs_readdir_free_large_page(pages_ptr, pages, array_size); |
567 | out_release_array: | 599 | out_release_array: |
@@ -582,8 +614,10 @@ static | |||
582 | int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page* page) | 614 | int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page* page) |
583 | { | 615 | { |
584 | struct inode *inode = desc->file->f_path.dentry->d_inode; | 616 | struct inode *inode = desc->file->f_path.dentry->d_inode; |
617 | int ret; | ||
585 | 618 | ||
586 | if (nfs_readdir_xdr_to_array(desc, page, inode) < 0) | 619 | ret = nfs_readdir_xdr_to_array(desc, page, inode); |
620 | if (ret < 0) | ||
587 | goto error; | 621 | goto error; |
588 | SetPageUptodate(page); | 622 | SetPageUptodate(page); |
589 | 623 | ||
@@ -595,12 +629,14 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page* page) | |||
595 | return 0; | 629 | return 0; |
596 | error: | 630 | error: |
597 | unlock_page(page); | 631 | unlock_page(page); |
598 | return -EIO; | 632 | return ret; |
599 | } | 633 | } |
600 | 634 | ||
601 | static | 635 | static |
602 | void cache_page_release(nfs_readdir_descriptor_t *desc) | 636 | void cache_page_release(nfs_readdir_descriptor_t *desc) |
603 | { | 637 | { |
638 | if (!desc->page->mapping) | ||
639 | nfs_readdir_clear_array(desc->page); | ||
604 | page_cache_release(desc->page); | 640 | page_cache_release(desc->page); |
605 | desc->page = NULL; | 641 | desc->page = NULL; |
606 | } | 642 | } |
@@ -608,12 +644,8 @@ void cache_page_release(nfs_readdir_descriptor_t *desc) | |||
608 | static | 644 | static |
609 | struct page *get_cache_page(nfs_readdir_descriptor_t *desc) | 645 | struct page *get_cache_page(nfs_readdir_descriptor_t *desc) |
610 | { | 646 | { |
611 | struct page *page; | 647 | return read_cache_page(desc->file->f_path.dentry->d_inode->i_mapping, |
612 | page = read_cache_page(desc->file->f_path.dentry->d_inode->i_mapping, | ||
613 | desc->page_index, (filler_t *)nfs_readdir_filler, desc); | 648 | desc->page_index, (filler_t *)nfs_readdir_filler, desc); |
614 | if (IS_ERR(page)) | ||
615 | desc->eof = 1; | ||
616 | return page; | ||
617 | } | 649 | } |
618 | 650 | ||
619 | /* | 651 | /* |
@@ -629,9 +661,8 @@ int find_cache_page(nfs_readdir_descriptor_t *desc) | |||
629 | return PTR_ERR(desc->page); | 661 | return PTR_ERR(desc->page); |
630 | 662 | ||
631 | res = nfs_readdir_search_array(desc); | 663 | res = nfs_readdir_search_array(desc); |
632 | if (res == 0) | 664 | if (res != 0) |
633 | return 0; | 665 | cache_page_release(desc); |
634 | cache_page_release(desc); | ||
635 | return res; | 666 | return res; |
636 | } | 667 | } |
637 | 668 | ||
@@ -639,22 +670,18 @@ int find_cache_page(nfs_readdir_descriptor_t *desc) | |||
639 | static inline | 670 | static inline |
640 | int readdir_search_pagecache(nfs_readdir_descriptor_t *desc) | 671 | int readdir_search_pagecache(nfs_readdir_descriptor_t *desc) |
641 | { | 672 | { |
642 | int res = -EAGAIN; | 673 | int res; |
643 | 674 | ||
644 | while (1) { | 675 | if (desc->page_index == 0) { |
645 | res = find_cache_page(desc); | 676 | desc->current_index = 0; |
646 | if (res != -EAGAIN) | 677 | desc->last_cookie = 0; |
647 | break; | ||
648 | desc->page_index++; | ||
649 | } | 678 | } |
679 | do { | ||
680 | res = find_cache_page(desc); | ||
681 | } while (res == -EAGAIN); | ||
650 | return res; | 682 | return res; |
651 | } | 683 | } |
652 | 684 | ||
653 | static inline unsigned int dt_type(struct inode *inode) | ||
654 | { | ||
655 | return (inode->i_mode >> 12) & 15; | ||
656 | } | ||
657 | |||
658 | /* | 685 | /* |
659 | * Once we've found the start of the dirent within a page: fill 'er up... | 686 | * Once we've found the start of the dirent within a page: fill 'er up... |
660 | */ | 687 | */ |
@@ -666,35 +693,35 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
666 | int i = 0; | 693 | int i = 0; |
667 | int res = 0; | 694 | int res = 0; |
668 | struct nfs_cache_array *array = NULL; | 695 | struct nfs_cache_array *array = NULL; |
669 | unsigned int d_type = DT_UNKNOWN; | ||
670 | struct dentry *dentry = NULL; | ||
671 | 696 | ||
672 | array = nfs_readdir_get_array(desc->page); | 697 | array = nfs_readdir_get_array(desc->page); |
698 | if (IS_ERR(array)) { | ||
699 | res = PTR_ERR(array); | ||
700 | goto out; | ||
701 | } | ||
673 | 702 | ||
674 | for (i = desc->cache_entry_index; i < array->size; i++) { | 703 | for (i = desc->cache_entry_index; i < array->size; i++) { |
675 | d_type = DT_UNKNOWN; | 704 | struct nfs_cache_array_entry *ent; |
676 | 705 | ||
677 | res = filldir(dirent, array->array[i].string.name, | 706 | ent = &array->array[i]; |
678 | array->array[i].string.len, file->f_pos, | 707 | if (filldir(dirent, ent->string.name, ent->string.len, |
679 | nfs_compat_user_ino64(array->array[i].ino), d_type); | 708 | file->f_pos, nfs_compat_user_ino64(ent->ino), |
680 | if (res < 0) | 709 | ent->d_type) < 0) { |
710 | desc->eof = 1; | ||
681 | break; | 711 | break; |
712 | } | ||
682 | file->f_pos++; | 713 | file->f_pos++; |
683 | desc->cache_entry_index = i; | ||
684 | if (i < (array->size-1)) | 714 | if (i < (array->size-1)) |
685 | *desc->dir_cookie = array->array[i+1].cookie; | 715 | *desc->dir_cookie = array->array[i+1].cookie; |
686 | else | 716 | else |
687 | *desc->dir_cookie = array->last_cookie; | 717 | *desc->dir_cookie = array->last_cookie; |
688 | if (i == array->eof_index) { | ||
689 | desc->eof = 1; | ||
690 | break; | ||
691 | } | ||
692 | } | 718 | } |
719 | if (array->eof_index >= 0) | ||
720 | desc->eof = 1; | ||
693 | 721 | ||
694 | nfs_readdir_release_array(desc->page); | 722 | nfs_readdir_release_array(desc->page); |
723 | out: | ||
695 | cache_page_release(desc); | 724 | cache_page_release(desc); |
696 | if (dentry != NULL) | ||
697 | dput(dentry); | ||
698 | dfprintk(DIRCACHE, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n", | 725 | dfprintk(DIRCACHE, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n", |
699 | (unsigned long long)*desc->dir_cookie, res); | 726 | (unsigned long long)*desc->dir_cookie, res); |
700 | return res; | 727 | return res; |
@@ -729,13 +756,14 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
729 | goto out; | 756 | goto out; |
730 | } | 757 | } |
731 | 758 | ||
732 | if (nfs_readdir_xdr_to_array(desc, page, inode) == -1) { | ||
733 | status = -EIO; | ||
734 | goto out_release; | ||
735 | } | ||
736 | |||
737 | desc->page_index = 0; | 759 | desc->page_index = 0; |
760 | desc->last_cookie = *desc->dir_cookie; | ||
738 | desc->page = page; | 761 | desc->page = page; |
762 | |||
763 | status = nfs_readdir_xdr_to_array(desc, page, inode); | ||
764 | if (status < 0) | ||
765 | goto out_release; | ||
766 | |||
739 | status = nfs_do_filldir(desc, dirent, filldir); | 767 | status = nfs_do_filldir(desc, dirent, filldir); |
740 | 768 | ||
741 | out: | 769 | out: |
@@ -757,7 +785,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
757 | struct inode *inode = dentry->d_inode; | 785 | struct inode *inode = dentry->d_inode; |
758 | nfs_readdir_descriptor_t my_desc, | 786 | nfs_readdir_descriptor_t my_desc, |
759 | *desc = &my_desc; | 787 | *desc = &my_desc; |
760 | int res = -ENOMEM; | 788 | int res; |
761 | 789 | ||
762 | dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n", | 790 | dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n", |
763 | dentry->d_parent->d_name.name, dentry->d_name.name, | 791 | dentry->d_parent->d_name.name, dentry->d_name.name, |
@@ -782,18 +810,18 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
782 | if (res < 0) | 810 | if (res < 0) |
783 | goto out; | 811 | goto out; |
784 | 812 | ||
785 | while (desc->eof != 1) { | 813 | do { |
786 | res = readdir_search_pagecache(desc); | 814 | res = readdir_search_pagecache(desc); |
787 | 815 | ||
788 | if (res == -EBADCOOKIE) { | 816 | if (res == -EBADCOOKIE) { |
817 | res = 0; | ||
789 | /* This means either end of directory */ | 818 | /* This means either end of directory */ |
790 | if (*desc->dir_cookie && desc->eof == 0) { | 819 | if (*desc->dir_cookie && desc->eof == 0) { |
791 | /* Or that the server has 'lost' a cookie */ | 820 | /* Or that the server has 'lost' a cookie */ |
792 | res = uncached_readdir(desc, dirent, filldir); | 821 | res = uncached_readdir(desc, dirent, filldir); |
793 | if (res >= 0) | 822 | if (res == 0) |
794 | continue; | 823 | continue; |
795 | } | 824 | } |
796 | res = 0; | ||
797 | break; | 825 | break; |
798 | } | 826 | } |
799 | if (res == -ETOOSMALL && desc->plus) { | 827 | if (res == -ETOOSMALL && desc->plus) { |
@@ -808,11 +836,9 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
808 | break; | 836 | break; |
809 | 837 | ||
810 | res = nfs_do_filldir(desc, dirent, filldir); | 838 | res = nfs_do_filldir(desc, dirent, filldir); |
811 | if (res < 0) { | 839 | if (res < 0) |
812 | res = 0; | ||
813 | break; | 840 | break; |
814 | } | 841 | } while (!desc->eof); |
815 | } | ||
816 | out: | 842 | out: |
817 | nfs_unblock_sillyrename(dentry); | 843 | nfs_unblock_sillyrename(dentry); |
818 | if (res > 0) | 844 | if (res > 0) |
@@ -1345,12 +1371,12 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry | |||
1345 | res = NULL; | 1371 | res = NULL; |
1346 | goto out; | 1372 | goto out; |
1347 | /* This turned out not to be a regular file */ | 1373 | /* This turned out not to be a regular file */ |
1348 | case -EISDIR: | ||
1349 | case -ENOTDIR: | 1374 | case -ENOTDIR: |
1350 | goto no_open; | 1375 | goto no_open; |
1351 | case -ELOOP: | 1376 | case -ELOOP: |
1352 | if (!(nd->intent.open.flags & O_NOFOLLOW)) | 1377 | if (!(nd->intent.open.flags & O_NOFOLLOW)) |
1353 | goto no_open; | 1378 | goto no_open; |
1379 | /* case -EISDIR: */ | ||
1354 | /* case -EINVAL: */ | 1380 | /* case -EINVAL: */ |
1355 | default: | 1381 | default: |
1356 | res = ERR_CAST(inode); | 1382 | res = ERR_CAST(inode); |
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 84d3c8b90206..e6ace0d93c71 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -867,7 +867,7 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov, | |||
867 | goto out; | 867 | goto out; |
868 | nfs_alloc_commit_data(dreq); | 868 | nfs_alloc_commit_data(dreq); |
869 | 869 | ||
870 | if (dreq->commit_data == NULL || count < wsize) | 870 | if (dreq->commit_data == NULL || count <= wsize) |
871 | sync = NFS_FILE_SYNC; | 871 | sync = NFS_FILE_SYNC; |
872 | 872 | ||
873 | dreq->inode = inode; | 873 | dreq->inode = inode; |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 60677f9f1311..7bf029ef4084 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -693,6 +693,7 @@ do_getlk(struct file *filp, int cmd, struct file_lock *fl, int is_local) | |||
693 | { | 693 | { |
694 | struct inode *inode = filp->f_mapping->host; | 694 | struct inode *inode = filp->f_mapping->host; |
695 | int status = 0; | 695 | int status = 0; |
696 | unsigned int saved_type = fl->fl_type; | ||
696 | 697 | ||
697 | /* Try local locking first */ | 698 | /* Try local locking first */ |
698 | posix_test_lock(filp, fl); | 699 | posix_test_lock(filp, fl); |
@@ -700,6 +701,7 @@ do_getlk(struct file *filp, int cmd, struct file_lock *fl, int is_local) | |||
700 | /* found a conflict */ | 701 | /* found a conflict */ |
701 | goto out; | 702 | goto out; |
702 | } | 703 | } |
704 | fl->fl_type = saved_type; | ||
703 | 705 | ||
704 | if (nfs_have_delegation(inode, FMODE_READ)) | 706 | if (nfs_have_delegation(inode, FMODE_READ)) |
705 | goto out_noconflict; | 707 | goto out_noconflict; |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 314f57164602..e67e31c73416 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -289,6 +289,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) | |||
289 | } else if (S_ISDIR(inode->i_mode)) { | 289 | } else if (S_ISDIR(inode->i_mode)) { |
290 | inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->dir_inode_ops; | 290 | inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->dir_inode_ops; |
291 | inode->i_fop = &nfs_dir_operations; | 291 | inode->i_fop = &nfs_dir_operations; |
292 | inode->i_data.a_ops = &nfs_dir_aops; | ||
292 | if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS)) | 293 | if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS)) |
293 | set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags); | 294 | set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags); |
294 | /* Deal with crossing mountpoints */ | 295 | /* Deal with crossing mountpoints */ |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index db08ff3ff454..e6356b750b77 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -362,6 +362,15 @@ unsigned int nfs_page_length(struct page *page) | |||
362 | } | 362 | } |
363 | 363 | ||
364 | /* | 364 | /* |
365 | * Convert a umode to a dirent->d_type | ||
366 | */ | ||
367 | static inline | ||
368 | unsigned char nfs_umode_to_dtype(umode_t mode) | ||
369 | { | ||
370 | return (mode >> 12) & 15; | ||
371 | } | ||
372 | |||
373 | /* | ||
365 | * Determine the number of pages in an array of length 'len' and | 374 | * Determine the number of pages in an array of length 'len' and |
366 | * with a base offset of 'base' | 375 | * with a base offset of 'base' |
367 | */ | 376 | */ |
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index eceafe74f473..4f981f1f6689 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c | |||
@@ -505,13 +505,13 @@ static struct rpc_procinfo mnt3_procedures[] = { | |||
505 | 505 | ||
506 | static struct rpc_version mnt_version1 = { | 506 | static struct rpc_version mnt_version1 = { |
507 | .number = 1, | 507 | .number = 1, |
508 | .nrprocs = 2, | 508 | .nrprocs = ARRAY_SIZE(mnt_procedures), |
509 | .procs = mnt_procedures, | 509 | .procs = mnt_procedures, |
510 | }; | 510 | }; |
511 | 511 | ||
512 | static struct rpc_version mnt_version3 = { | 512 | static struct rpc_version mnt_version3 = { |
513 | .number = 3, | 513 | .number = 3, |
514 | .nrprocs = 2, | 514 | .nrprocs = ARRAY_SIZE(mnt3_procedures), |
515 | .procs = mnt3_procedures, | 515 | .procs = mnt3_procedures, |
516 | }; | 516 | }; |
517 | 517 | ||
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index e6bf45710cc7..5914a1911c95 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c | |||
@@ -423,7 +423,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy) | |||
423 | struct page **page; | 423 | struct page **page; |
424 | size_t hdrlen; | 424 | size_t hdrlen; |
425 | unsigned int pglen, recvd; | 425 | unsigned int pglen, recvd; |
426 | int status, nr = 0; | 426 | int status; |
427 | 427 | ||
428 | if ((status = ntohl(*p++))) | 428 | if ((status = ntohl(*p++))) |
429 | return nfs_stat_to_errno(status); | 429 | return nfs_stat_to_errno(status); |
@@ -443,7 +443,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy) | |||
443 | if (pglen > recvd) | 443 | if (pglen > recvd) |
444 | pglen = recvd; | 444 | pglen = recvd; |
445 | page = rcvbuf->pages; | 445 | page = rcvbuf->pages; |
446 | return nr; | 446 | return pglen; |
447 | } | 447 | } |
448 | 448 | ||
449 | static void print_overflow_msg(const char *func, const struct xdr_stream *xdr) | 449 | static void print_overflow_msg(const char *func, const struct xdr_stream *xdr) |
@@ -485,6 +485,8 @@ nfs_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_se | |||
485 | entry->prev_cookie = entry->cookie; | 485 | entry->prev_cookie = entry->cookie; |
486 | entry->cookie = ntohl(*p++); | 486 | entry->cookie = ntohl(*p++); |
487 | 487 | ||
488 | entry->d_type = DT_UNKNOWN; | ||
489 | |||
488 | p = xdr_inline_peek(xdr, 8); | 490 | p = xdr_inline_peek(xdr, 8); |
489 | if (p != NULL) | 491 | if (p != NULL) |
490 | entry->eof = !p[0] && p[1]; | 492 | entry->eof = !p[0] && p[1]; |
@@ -495,7 +497,7 @@ nfs_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_se | |||
495 | 497 | ||
496 | out_overflow: | 498 | out_overflow: |
497 | print_overflow_msg(__func__, xdr); | 499 | print_overflow_msg(__func__, xdr); |
498 | return ERR_PTR(-EIO); | 500 | return ERR_PTR(-EAGAIN); |
499 | } | 501 | } |
500 | 502 | ||
501 | /* | 503 | /* |
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index d9a5e832c257..f6cc60f06dac 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c | |||
@@ -555,7 +555,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res | |||
555 | struct page **page; | 555 | struct page **page; |
556 | size_t hdrlen; | 556 | size_t hdrlen; |
557 | u32 recvd, pglen; | 557 | u32 recvd, pglen; |
558 | int status, nr = 0; | 558 | int status; |
559 | 559 | ||
560 | status = ntohl(*p++); | 560 | status = ntohl(*p++); |
561 | /* Decode post_op_attrs */ | 561 | /* Decode post_op_attrs */ |
@@ -586,7 +586,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res | |||
586 | pglen = recvd; | 586 | pglen = recvd; |
587 | page = rcvbuf->pages; | 587 | page = rcvbuf->pages; |
588 | 588 | ||
589 | return nr; | 589 | return pglen; |
590 | } | 590 | } |
591 | 591 | ||
592 | __be32 * | 592 | __be32 * |
@@ -622,11 +622,13 @@ nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_s | |||
622 | entry->prev_cookie = entry->cookie; | 622 | entry->prev_cookie = entry->cookie; |
623 | p = xdr_decode_hyper(p, &entry->cookie); | 623 | p = xdr_decode_hyper(p, &entry->cookie); |
624 | 624 | ||
625 | entry->d_type = DT_UNKNOWN; | ||
625 | if (plus) { | 626 | if (plus) { |
626 | entry->fattr->valid = 0; | 627 | entry->fattr->valid = 0; |
627 | p = xdr_decode_post_op_attr_stream(xdr, entry->fattr); | 628 | p = xdr_decode_post_op_attr_stream(xdr, entry->fattr); |
628 | if (IS_ERR(p)) | 629 | if (IS_ERR(p)) |
629 | goto out_overflow_exit; | 630 | goto out_overflow_exit; |
631 | entry->d_type = nfs_umode_to_dtype(entry->fattr->mode); | ||
630 | /* In fact, a post_op_fh3: */ | 632 | /* In fact, a post_op_fh3: */ |
631 | p = xdr_inline_decode(xdr, 4); | 633 | p = xdr_inline_decode(xdr, 4); |
632 | if (unlikely(!p)) | 634 | if (unlikely(!p)) |
@@ -656,7 +658,7 @@ nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_s | |||
656 | out_overflow: | 658 | out_overflow: |
657 | print_overflow_msg(__func__, xdr); | 659 | print_overflow_msg(__func__, xdr); |
658 | out_overflow_exit: | 660 | out_overflow_exit: |
659 | return ERR_PTR(-EIO); | 661 | return ERR_PTR(-EAGAIN); |
660 | } | 662 | } |
661 | 663 | ||
662 | /* | 664 | /* |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 0f24cdf2cb13..4435e5e1f904 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -2852,8 +2852,10 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | |||
2852 | nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args); | 2852 | nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args); |
2853 | res.pgbase = args.pgbase; | 2853 | res.pgbase = args.pgbase; |
2854 | status = nfs4_call_sync(NFS_SERVER(dir), &msg, &args, &res, 0); | 2854 | status = nfs4_call_sync(NFS_SERVER(dir), &msg, &args, &res, 0); |
2855 | if (status == 0) | 2855 | if (status >= 0) { |
2856 | memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); | 2856 | memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); |
2857 | status += args.pgbase; | ||
2858 | } | ||
2857 | 2859 | ||
2858 | nfs_invalidate_atime(dir); | 2860 | nfs_invalidate_atime(dir); |
2859 | 2861 | ||
@@ -3359,6 +3361,8 @@ static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen) | |||
3359 | ret = nfs_revalidate_inode(server, inode); | 3361 | ret = nfs_revalidate_inode(server, inode); |
3360 | if (ret < 0) | 3362 | if (ret < 0) |
3361 | return ret; | 3363 | return ret; |
3364 | if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_ACL) | ||
3365 | nfs_zap_acl_cache(inode); | ||
3362 | ret = nfs4_read_cached_acl(inode, buf, buflen); | 3366 | ret = nfs4_read_cached_acl(inode, buf, buflen); |
3363 | if (ret != -ENOENT) | 3367 | if (ret != -ENOENT) |
3364 | return ret; | 3368 | return ret; |
@@ -3387,6 +3391,13 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl | |||
3387 | nfs_inode_return_delegation(inode); | 3391 | nfs_inode_return_delegation(inode); |
3388 | buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase); | 3392 | buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase); |
3389 | ret = nfs4_call_sync(server, &msg, &arg, &res, 1); | 3393 | ret = nfs4_call_sync(server, &msg, &arg, &res, 1); |
3394 | /* | ||
3395 | * Acl update can result in inode attribute update. | ||
3396 | * so mark the attribute cache invalid. | ||
3397 | */ | ||
3398 | spin_lock(&inode->i_lock); | ||
3399 | NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATTR; | ||
3400 | spin_unlock(&inode->i_lock); | ||
3390 | nfs_access_zap_cache(inode); | 3401 | nfs_access_zap_cache(inode); |
3391 | nfs_zap_acl_cache(inode); | 3402 | nfs_zap_acl_cache(inode); |
3392 | return ret; | 3403 | return ret; |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index f313c4cce7e4..9f1826b012e6 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -4518,7 +4518,7 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n | |||
4518 | xdr_read_pages(xdr, pglen); | 4518 | xdr_read_pages(xdr, pglen); |
4519 | 4519 | ||
4520 | 4520 | ||
4521 | return 0; | 4521 | return pglen; |
4522 | } | 4522 | } |
4523 | 4523 | ||
4524 | static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req) | 4524 | static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req) |
@@ -6208,6 +6208,10 @@ __be32 *nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, | |||
6208 | if (entry->fattr->valid & NFS_ATTR_FATTR_FILEID) | 6208 | if (entry->fattr->valid & NFS_ATTR_FATTR_FILEID) |
6209 | entry->ino = entry->fattr->fileid; | 6209 | entry->ino = entry->fattr->fileid; |
6210 | 6210 | ||
6211 | entry->d_type = DT_UNKNOWN; | ||
6212 | if (entry->fattr->valid & NFS_ATTR_FATTR_TYPE) | ||
6213 | entry->d_type = nfs_umode_to_dtype(entry->fattr->mode); | ||
6214 | |||
6211 | if (verify_attr_len(xdr, p, len) < 0) | 6215 | if (verify_attr_len(xdr, p, len) < 0) |
6212 | goto out_overflow; | 6216 | goto out_overflow; |
6213 | 6217 | ||
@@ -6221,7 +6225,7 @@ __be32 *nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, | |||
6221 | 6225 | ||
6222 | out_overflow: | 6226 | out_overflow: |
6223 | print_overflow_msg(__func__, xdr); | 6227 | print_overflow_msg(__func__, xdr); |
6224 | return ERR_PTR(-EIO); | 6228 | return ERR_PTR(-EAGAIN); |
6225 | } | 6229 | } |
6226 | 6230 | ||
6227 | /* | 6231 | /* |
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 137b549e63db..b68536cc9046 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c | |||
@@ -115,7 +115,7 @@ int nfs_set_page_tag_locked(struct nfs_page *req) | |||
115 | { | 115 | { |
116 | if (!nfs_lock_request_dontget(req)) | 116 | if (!nfs_lock_request_dontget(req)) |
117 | return 0; | 117 | return 0; |
118 | if (req->wb_page != NULL) | 118 | if (test_bit(PG_MAPPED, &req->wb_flags)) |
119 | radix_tree_tag_set(&NFS_I(req->wb_context->path.dentry->d_inode)->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); | 119 | radix_tree_tag_set(&NFS_I(req->wb_context->path.dentry->d_inode)->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); |
120 | return 1; | 120 | return 1; |
121 | } | 121 | } |
@@ -125,7 +125,7 @@ int nfs_set_page_tag_locked(struct nfs_page *req) | |||
125 | */ | 125 | */ |
126 | void nfs_clear_page_tag_locked(struct nfs_page *req) | 126 | void nfs_clear_page_tag_locked(struct nfs_page *req) |
127 | { | 127 | { |
128 | if (req->wb_page != NULL) { | 128 | if (test_bit(PG_MAPPED, &req->wb_flags)) { |
129 | struct inode *inode = req->wb_context->path.dentry->d_inode; | 129 | struct inode *inode = req->wb_context->path.dentry->d_inode; |
130 | struct nfs_inode *nfsi = NFS_I(inode); | 130 | struct nfs_inode *nfsi = NFS_I(inode); |
131 | 131 | ||
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index e4b62c6f5a6e..aedcaa7f291f 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
@@ -152,7 +152,6 @@ static void nfs_readpage_release(struct nfs_page *req) | |||
152 | (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode), | 152 | (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode), |
153 | req->wb_bytes, | 153 | req->wb_bytes, |
154 | (long long)req_offset(req)); | 154 | (long long)req_offset(req)); |
155 | nfs_clear_request(req); | ||
156 | nfs_release_request(req); | 155 | nfs_release_request(req); |
157 | } | 156 | } |
158 | 157 | ||
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 0a42e8f4adcb..4100630c9a5b 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -39,7 +39,6 @@ | |||
39 | #include <linux/nfs_mount.h> | 39 | #include <linux/nfs_mount.h> |
40 | #include <linux/nfs4_mount.h> | 40 | #include <linux/nfs4_mount.h> |
41 | #include <linux/lockd/bind.h> | 41 | #include <linux/lockd/bind.h> |
42 | #include <linux/smp_lock.h> | ||
43 | #include <linux/seq_file.h> | 42 | #include <linux/seq_file.h> |
44 | #include <linux/mount.h> | 43 | #include <linux/mount.h> |
45 | #include <linux/mnt_namespace.h> | 44 | #include <linux/mnt_namespace.h> |
@@ -67,6 +66,12 @@ | |||
67 | 66 | ||
68 | #define NFSDBG_FACILITY NFSDBG_VFS | 67 | #define NFSDBG_FACILITY NFSDBG_VFS |
69 | 68 | ||
69 | #ifdef CONFIG_NFS_V3 | ||
70 | #define NFS_DEFAULT_VERSION 3 | ||
71 | #else | ||
72 | #define NFS_DEFAULT_VERSION 2 | ||
73 | #endif | ||
74 | |||
70 | enum { | 75 | enum { |
71 | /* Mount options that take no arguments */ | 76 | /* Mount options that take no arguments */ |
72 | Opt_soft, Opt_hard, | 77 | Opt_soft, Opt_hard, |
@@ -1064,12 +1069,10 @@ static int nfs_parse_mount_options(char *raw, | |||
1064 | mnt->flags |= NFS_MOUNT_VER3; | 1069 | mnt->flags |= NFS_MOUNT_VER3; |
1065 | mnt->version = 3; | 1070 | mnt->version = 3; |
1066 | break; | 1071 | break; |
1067 | #ifdef CONFIG_NFS_V4 | ||
1068 | case Opt_v4: | 1072 | case Opt_v4: |
1069 | mnt->flags &= ~NFS_MOUNT_VER3; | 1073 | mnt->flags &= ~NFS_MOUNT_VER3; |
1070 | mnt->version = 4; | 1074 | mnt->version = 4; |
1071 | break; | 1075 | break; |
1072 | #endif | ||
1073 | case Opt_udp: | 1076 | case Opt_udp: |
1074 | mnt->flags &= ~NFS_MOUNT_TCP; | 1077 | mnt->flags &= ~NFS_MOUNT_TCP; |
1075 | mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; | 1078 | mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; |
@@ -1281,12 +1284,10 @@ static int nfs_parse_mount_options(char *raw, | |||
1281 | mnt->flags |= NFS_MOUNT_VER3; | 1284 | mnt->flags |= NFS_MOUNT_VER3; |
1282 | mnt->version = 3; | 1285 | mnt->version = 3; |
1283 | break; | 1286 | break; |
1284 | #ifdef CONFIG_NFS_V4 | ||
1285 | case NFS4_VERSION: | 1287 | case NFS4_VERSION: |
1286 | mnt->flags &= ~NFS_MOUNT_VER3; | 1288 | mnt->flags &= ~NFS_MOUNT_VER3; |
1287 | mnt->version = 4; | 1289 | mnt->version = 4; |
1288 | break; | 1290 | break; |
1289 | #endif | ||
1290 | default: | 1291 | default: |
1291 | goto out_invalid_value; | 1292 | goto out_invalid_value; |
1292 | } | 1293 | } |
@@ -2277,7 +2278,7 @@ static int nfs_get_sb(struct file_system_type *fs_type, | |||
2277 | }; | 2278 | }; |
2278 | int error = -ENOMEM; | 2279 | int error = -ENOMEM; |
2279 | 2280 | ||
2280 | data = nfs_alloc_parsed_mount_data(3); | 2281 | data = nfs_alloc_parsed_mount_data(NFS_DEFAULT_VERSION); |
2281 | mntfh = nfs_alloc_fhandle(); | 2282 | mntfh = nfs_alloc_fhandle(); |
2282 | if (data == NULL || mntfh == NULL) | 2283 | if (data == NULL || mntfh == NULL) |
2283 | goto out_free_fh; | 2284 | goto out_free_fh; |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 4c14c17a5276..10d648ea128b 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -390,6 +390,7 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req) | |||
390 | if (nfs_have_delegation(inode, FMODE_WRITE)) | 390 | if (nfs_have_delegation(inode, FMODE_WRITE)) |
391 | nfsi->change_attr++; | 391 | nfsi->change_attr++; |
392 | } | 392 | } |
393 | set_bit(PG_MAPPED, &req->wb_flags); | ||
393 | SetPagePrivate(req->wb_page); | 394 | SetPagePrivate(req->wb_page); |
394 | set_page_private(req->wb_page, (unsigned long)req); | 395 | set_page_private(req->wb_page, (unsigned long)req); |
395 | nfsi->npages++; | 396 | nfsi->npages++; |
@@ -415,6 +416,7 @@ static void nfs_inode_remove_request(struct nfs_page *req) | |||
415 | spin_lock(&inode->i_lock); | 416 | spin_lock(&inode->i_lock); |
416 | set_page_private(req->wb_page, 0); | 417 | set_page_private(req->wb_page, 0); |
417 | ClearPagePrivate(req->wb_page); | 418 | ClearPagePrivate(req->wb_page); |
419 | clear_bit(PG_MAPPED, &req->wb_flags); | ||
418 | radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index); | 420 | radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index); |
419 | nfsi->npages--; | 421 | nfsi->npages--; |
420 | if (!nfsi->npages) { | 422 | if (!nfsi->npages) { |
@@ -422,7 +424,6 @@ static void nfs_inode_remove_request(struct nfs_page *req) | |||
422 | iput(inode); | 424 | iput(inode); |
423 | } else | 425 | } else |
424 | spin_unlock(&inode->i_lock); | 426 | spin_unlock(&inode->i_lock); |
425 | nfs_clear_request(req); | ||
426 | nfs_release_request(req); | 427 | nfs_release_request(req); |
427 | } | 428 | } |
428 | 429 | ||