diff options
Diffstat (limited to 'fs/nfs/dir.c')
-rw-r--r-- | fs/nfs/dir.c | 85 |
1 files changed, 48 insertions, 37 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index fceef29c65a3..b38a57e78a63 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -51,8 +51,10 @@ static int nfs_mknod(struct inode *, struct dentry *, int, dev_t); | |||
51 | static int nfs_rename(struct inode *, struct dentry *, | 51 | static int nfs_rename(struct inode *, struct dentry *, |
52 | struct inode *, struct dentry *); | 52 | struct inode *, struct dentry *); |
53 | static int nfs_fsync_dir(struct file *, struct dentry *, int); | 53 | static int nfs_fsync_dir(struct file *, struct dentry *, int); |
54 | static loff_t nfs_llseek_dir(struct file *, loff_t, int); | ||
54 | 55 | ||
55 | struct file_operations nfs_dir_operations = { | 56 | struct file_operations nfs_dir_operations = { |
57 | .llseek = nfs_llseek_dir, | ||
56 | .read = generic_read_dir, | 58 | .read = generic_read_dir, |
57 | .readdir = nfs_readdir, | 59 | .readdir = nfs_readdir, |
58 | .open = nfs_opendir, | 60 | .open = nfs_opendir, |
@@ -141,9 +143,8 @@ typedef struct { | |||
141 | struct page *page; | 143 | struct page *page; |
142 | unsigned long page_index; | 144 | unsigned long page_index; |
143 | u32 *ptr; | 145 | u32 *ptr; |
144 | u64 target_cookie; | 146 | u64 *dir_cookie; |
145 | int target_index; | 147 | loff_t current_index; |
146 | int current_index; | ||
147 | struct nfs_entry *entry; | 148 | struct nfs_entry *entry; |
148 | decode_dirent_t decode; | 149 | decode_dirent_t decode; |
149 | int plus; | 150 | int plus; |
@@ -227,7 +228,7 @@ void dir_page_release(nfs_readdir_descriptor_t *desc) | |||
227 | 228 | ||
228 | /* | 229 | /* |
229 | * Given a pointer to a buffer that has already been filled by a call | 230 | * Given a pointer to a buffer that has already been filled by a call |
230 | * to readdir, find the next entry with cookie 'desc->target_cookie'. | 231 | * to readdir, find the next entry with cookie '*desc->dir_cookie'. |
231 | * | 232 | * |
232 | * If the end of the buffer has been reached, return -EAGAIN, if not, | 233 | * If the end of the buffer has been reached, return -EAGAIN, if not, |
233 | * return the offset within the buffer of the next entry to be | 234 | * return the offset within the buffer of the next entry to be |
@@ -241,8 +242,8 @@ int find_dirent(nfs_readdir_descriptor_t *desc) | |||
241 | status; | 242 | status; |
242 | 243 | ||
243 | while((status = dir_decode(desc)) == 0) { | 244 | while((status = dir_decode(desc)) == 0) { |
244 | dfprintk(VFS, "NFS: found cookie %Lu\n", (long long)entry->cookie); | 245 | dfprintk(VFS, "NFS: found cookie %Lu\n", (unsigned long long)entry->cookie); |
245 | if (entry->prev_cookie == desc->target_cookie) | 246 | if (entry->prev_cookie == *desc->dir_cookie) |
246 | break; | 247 | break; |
247 | if (loop_count++ > 200) { | 248 | if (loop_count++ > 200) { |
248 | loop_count = 0; | 249 | loop_count = 0; |
@@ -255,7 +256,7 @@ int find_dirent(nfs_readdir_descriptor_t *desc) | |||
255 | 256 | ||
256 | /* | 257 | /* |
257 | * Given a pointer to a buffer that has already been filled by a call | 258 | * Given a pointer to a buffer that has already been filled by a call |
258 | * to readdir, find the entry at offset 'desc->target_index'. | 259 | * to readdir, find the entry at offset 'desc->file->f_pos'. |
259 | * | 260 | * |
260 | * If the end of the buffer has been reached, return -EAGAIN, if not, | 261 | * If the end of the buffer has been reached, return -EAGAIN, if not, |
261 | * return the offset within the buffer of the next entry to be | 262 | * return the offset within the buffer of the next entry to be |
@@ -273,10 +274,10 @@ int find_dirent_index(nfs_readdir_descriptor_t *desc) | |||
273 | if (status) | 274 | if (status) |
274 | break; | 275 | break; |
275 | 276 | ||
276 | dfprintk(VFS, "NFS: found cookie %Lu at index %d\n", (long long)entry->cookie, desc->current_index); | 277 | dfprintk(VFS, "NFS: found cookie %Lu at index %Ld\n", (unsigned long long)entry->cookie, desc->current_index); |
277 | 278 | ||
278 | if (desc->target_index == desc->current_index) { | 279 | if (desc->file->f_pos == desc->current_index) { |
279 | desc->target_cookie = entry->cookie; | 280 | *desc->dir_cookie = entry->cookie; |
280 | break; | 281 | break; |
281 | } | 282 | } |
282 | desc->current_index++; | 283 | desc->current_index++; |
@@ -314,7 +315,7 @@ int find_dirent_page(nfs_readdir_descriptor_t *desc) | |||
314 | /* NOTE: Someone else may have changed the READDIRPLUS flag */ | 315 | /* NOTE: Someone else may have changed the READDIRPLUS flag */ |
315 | desc->page = page; | 316 | desc->page = page; |
316 | desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */ | 317 | desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */ |
317 | if (desc->target_cookie) | 318 | if (*desc->dir_cookie != 0) |
318 | status = find_dirent(desc); | 319 | status = find_dirent(desc); |
319 | else | 320 | else |
320 | status = find_dirent_index(desc); | 321 | status = find_dirent_index(desc); |
@@ -332,8 +333,8 @@ int find_dirent_page(nfs_readdir_descriptor_t *desc) | |||
332 | * Recurse through the page cache pages, and return a | 333 | * Recurse through the page cache pages, and return a |
333 | * filled nfs_entry structure of the next directory entry if possible. | 334 | * filled nfs_entry structure of the next directory entry if possible. |
334 | * | 335 | * |
335 | * The target for the search is 'desc->target_cookie' if non-0, | 336 | * The target for the search is '*desc->dir_cookie' if non-0, |
336 | * 'desc->target_index' otherwise | 337 | * 'desc->file->f_pos' otherwise |
337 | */ | 338 | */ |
338 | static inline | 339 | static inline |
339 | int readdir_search_pagecache(nfs_readdir_descriptor_t *desc) | 340 | int readdir_search_pagecache(nfs_readdir_descriptor_t *desc) |
@@ -341,18 +342,15 @@ int readdir_search_pagecache(nfs_readdir_descriptor_t *desc) | |||
341 | int loop_count = 0; | 342 | int loop_count = 0; |
342 | int res; | 343 | int res; |
343 | 344 | ||
344 | if (desc->target_cookie) | ||
345 | dfprintk(VFS, "NFS: readdir_search_pagecache() searching for cookie %Lu\n", (long long)desc->target_cookie); | ||
346 | else | ||
347 | dfprintk(VFS, "NFS: readdir_search_pagecache() searching for cookie number %d\n", desc->target_index); | ||
348 | |||
349 | /* Always search-by-index from the beginning of the cache */ | 345 | /* Always search-by-index from the beginning of the cache */ |
350 | if (!(desc->target_cookie)) { | 346 | if (*desc->dir_cookie == 0) { |
347 | dfprintk(VFS, "NFS: readdir_search_pagecache() searching for offset %Ld\n", (long long)desc->file->f_pos); | ||
351 | desc->page_index = 0; | 348 | desc->page_index = 0; |
352 | desc->entry->cookie = desc->entry->prev_cookie = 0; | 349 | desc->entry->cookie = desc->entry->prev_cookie = 0; |
353 | desc->entry->eof = 0; | 350 | desc->entry->eof = 0; |
354 | desc->current_index = 0; | 351 | desc->current_index = 0; |
355 | } | 352 | } else |
353 | dfprintk(VFS, "NFS: readdir_search_pagecache() searching for cookie %Lu\n", (unsigned long long)*desc->dir_cookie); | ||
356 | 354 | ||
357 | for (;;) { | 355 | for (;;) { |
358 | res = find_dirent_page(desc); | 356 | res = find_dirent_page(desc); |
@@ -386,7 +384,6 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
386 | struct file *file = desc->file; | 384 | struct file *file = desc->file; |
387 | struct nfs_entry *entry = desc->entry; | 385 | struct nfs_entry *entry = desc->entry; |
388 | struct dentry *dentry = NULL; | 386 | struct dentry *dentry = NULL; |
389 | struct nfs_open_context *ctx = file->private_data; | ||
390 | unsigned long fileid; | 387 | unsigned long fileid; |
391 | int loop_count = 0, | 388 | int loop_count = 0, |
392 | res; | 389 | res; |
@@ -415,7 +412,7 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
415 | if (res < 0) | 412 | if (res < 0) |
416 | break; | 413 | break; |
417 | file->f_pos++; | 414 | file->f_pos++; |
418 | desc->target_cookie = entry->cookie; | 415 | *desc->dir_cookie = entry->cookie; |
419 | if (dir_decode(desc) != 0) { | 416 | if (dir_decode(desc) != 0) { |
420 | desc->page_index ++; | 417 | desc->page_index ++; |
421 | break; | 418 | break; |
@@ -425,12 +422,10 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
425 | schedule(); | 422 | schedule(); |
426 | } | 423 | } |
427 | } | 424 | } |
428 | ctx->dir_pos = file->f_pos; | ||
429 | ctx->dir_cookie = desc->target_cookie; | ||
430 | dir_page_release(desc); | 425 | dir_page_release(desc); |
431 | if (dentry != NULL) | 426 | if (dentry != NULL) |
432 | dput(dentry); | 427 | dput(dentry); |
433 | dfprintk(VFS, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n", (long long)desc->target_cookie, res); | 428 | dfprintk(VFS, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n", (unsigned long long)*desc->dir_cookie, res); |
434 | return res; | 429 | return res; |
435 | } | 430 | } |
436 | 431 | ||
@@ -456,14 +451,14 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
456 | struct page *page = NULL; | 451 | struct page *page = NULL; |
457 | int status; | 452 | int status; |
458 | 453 | ||
459 | dfprintk(VFS, "NFS: uncached_readdir() searching for cookie %Lu\n", (long long)desc->target_cookie); | 454 | dfprintk(VFS, "NFS: uncached_readdir() searching for cookie %Lu\n", (unsigned long long)*desc->dir_cookie); |
460 | 455 | ||
461 | page = alloc_page(GFP_HIGHUSER); | 456 | page = alloc_page(GFP_HIGHUSER); |
462 | if (!page) { | 457 | if (!page) { |
463 | status = -ENOMEM; | 458 | status = -ENOMEM; |
464 | goto out; | 459 | goto out; |
465 | } | 460 | } |
466 | desc->error = NFS_PROTO(inode)->readdir(file->f_dentry, cred, desc->target_cookie, | 461 | desc->error = NFS_PROTO(inode)->readdir(file->f_dentry, cred, *desc->dir_cookie, |
467 | page, | 462 | page, |
468 | NFS_SERVER(inode)->dtsize, | 463 | NFS_SERVER(inode)->dtsize, |
469 | desc->plus); | 464 | desc->plus); |
@@ -472,7 +467,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
472 | desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */ | 467 | desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */ |
473 | if (desc->error >= 0) { | 468 | if (desc->error >= 0) { |
474 | if ((status = dir_decode(desc)) == 0) | 469 | if ((status = dir_decode(desc)) == 0) |
475 | desc->entry->prev_cookie = desc->target_cookie; | 470 | desc->entry->prev_cookie = *desc->dir_cookie; |
476 | } else | 471 | } else |
477 | status = -EIO; | 472 | status = -EIO; |
478 | if (status < 0) | 473 | if (status < 0) |
@@ -501,7 +496,6 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
501 | { | 496 | { |
502 | struct dentry *dentry = filp->f_dentry; | 497 | struct dentry *dentry = filp->f_dentry; |
503 | struct inode *inode = dentry->d_inode; | 498 | struct inode *inode = dentry->d_inode; |
504 | struct nfs_open_context *ctx = filp->private_data; | ||
505 | nfs_readdir_descriptor_t my_desc, | 499 | nfs_readdir_descriptor_t my_desc, |
506 | *desc = &my_desc; | 500 | *desc = &my_desc; |
507 | struct nfs_entry my_entry; | 501 | struct nfs_entry my_entry; |
@@ -519,21 +513,16 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
519 | 513 | ||
520 | /* | 514 | /* |
521 | * filp->f_pos points to the dirent entry number. | 515 | * filp->f_pos points to the dirent entry number. |
522 | * ctx->dir_pos has the number of the cached cookie. We have | 516 | * *desc->dir_cookie has the cookie for the next entry. We have |
523 | * to either find the entry with the appropriate number or | 517 | * to either find the entry with the appropriate number or |
524 | * revalidate the cookie. | 518 | * revalidate the cookie. |
525 | */ | 519 | */ |
526 | memset(desc, 0, sizeof(*desc)); | 520 | memset(desc, 0, sizeof(*desc)); |
527 | 521 | ||
528 | desc->file = filp; | 522 | desc->file = filp; |
523 | desc->dir_cookie = &((struct nfs_open_context *)filp->private_data)->dir_cookie; | ||
529 | desc->decode = NFS_PROTO(inode)->decode_dirent; | 524 | desc->decode = NFS_PROTO(inode)->decode_dirent; |
530 | desc->plus = NFS_USE_READDIRPLUS(inode); | 525 | desc->plus = NFS_USE_READDIRPLUS(inode); |
531 | desc->target_index = filp->f_pos; | ||
532 | |||
533 | if (filp->f_pos == ctx->dir_pos) | ||
534 | desc->target_cookie = ctx->dir_cookie; | ||
535 | else | ||
536 | desc->target_cookie = 0; | ||
537 | 526 | ||
538 | my_entry.cookie = my_entry.prev_cookie = 0; | 527 | my_entry.cookie = my_entry.prev_cookie = 0; |
539 | my_entry.eof = 0; | 528 | my_entry.eof = 0; |
@@ -546,7 +535,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
546 | 535 | ||
547 | if (res == -EBADCOOKIE) { | 536 | if (res == -EBADCOOKIE) { |
548 | /* This means either end of directory */ | 537 | /* This means either end of directory */ |
549 | if (desc->target_cookie && desc->entry->cookie != desc->target_cookie) { | 538 | if (*desc->dir_cookie && desc->entry->cookie != *desc->dir_cookie) { |
550 | /* Or that the server has 'lost' a cookie */ | 539 | /* Or that the server has 'lost' a cookie */ |
551 | res = uncached_readdir(desc, dirent, filldir); | 540 | res = uncached_readdir(desc, dirent, filldir); |
552 | if (res >= 0) | 541 | if (res >= 0) |
@@ -579,6 +568,28 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
579 | return 0; | 568 | return 0; |
580 | } | 569 | } |
581 | 570 | ||
571 | loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin) | ||
572 | { | ||
573 | down(&filp->f_dentry->d_inode->i_sem); | ||
574 | switch (origin) { | ||
575 | case 1: | ||
576 | offset += filp->f_pos; | ||
577 | case 0: | ||
578 | if (offset >= 0) | ||
579 | break; | ||
580 | default: | ||
581 | offset = -EINVAL; | ||
582 | goto out; | ||
583 | } | ||
584 | if (offset != filp->f_pos) { | ||
585 | filp->f_pos = offset; | ||
586 | ((struct nfs_open_context *)filp->private_data)->dir_cookie = 0; | ||
587 | } | ||
588 | out: | ||
589 | up(&filp->f_dentry->d_inode->i_sem); | ||
590 | return offset; | ||
591 | } | ||
592 | |||
582 | /* | 593 | /* |
583 | * All directory operations under NFS are synchronous, so fsync() | 594 | * All directory operations under NFS are synchronous, so fsync() |
584 | * is a dummy operation. | 595 | * is a dummy operation. |