diff options
| author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2005-06-22 13:16:29 -0400 |
|---|---|---|
| committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2005-06-22 16:07:34 -0400 |
| commit | f0dd2136da6d2070e12bfa6d199b136318e666c7 (patch) | |
| tree | a261d4b4d9e29dbce104cf9515a0a209cff387cf | |
| parent | 00a926422765064cb28e218d4837411c88bf6a3e (diff) | |
[PATCH] NFS: Clean up readdir changes.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
| -rw-r--r-- | fs/nfs/dir.c | 85 | ||||
| -rw-r--r-- | fs/nfs/inode.c | 1 | ||||
| -rw-r--r-- | include/linux/nfs_fs.h | 1 |
3 files changed, 48 insertions, 39 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. |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 9fa02e7984ac..6300e05e9463 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
| @@ -891,7 +891,6 @@ struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, struct rp | |||
| 891 | ctx->state = NULL; | 891 | ctx->state = NULL; |
| 892 | ctx->lockowner = current->files; | 892 | ctx->lockowner = current->files; |
| 893 | ctx->error = 0; | 893 | ctx->error = 0; |
| 894 | ctx->dir_pos = 0; | ||
| 895 | ctx->dir_cookie = 0; | 894 | ctx->dir_cookie = 0; |
| 896 | } | 895 | } |
| 897 | return ctx; | 896 | return ctx; |
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index f810195ef7ad..c90313bfa435 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h | |||
| @@ -85,7 +85,6 @@ struct nfs_open_context { | |||
| 85 | 85 | ||
| 86 | struct list_head list; | 86 | struct list_head list; |
| 87 | 87 | ||
| 88 | int dir_pos; /* Directory cookie cache */ | ||
| 89 | __u64 dir_cookie; | 88 | __u64 dir_cookie; |
| 90 | }; | 89 | }; |
| 91 | 90 | ||
