diff options
-rw-r--r-- | fs/coda/dir.c | 98 |
1 files changed, 54 insertions, 44 deletions
diff --git a/fs/coda/dir.c b/fs/coda/dir.c index 01f55f447d82..47ac9e21a590 100644 --- a/fs/coda/dir.c +++ b/fs/coda/dir.c | |||
@@ -43,15 +43,15 @@ static int coda_rename(struct inode *old_inode, struct dentry *old_dentry, | |||
43 | struct inode *new_inode, struct dentry *new_dentry); | 43 | struct inode *new_inode, struct dentry *new_dentry); |
44 | 44 | ||
45 | /* dir file-ops */ | 45 | /* dir file-ops */ |
46 | static int coda_readdir(struct file *file, void *dirent, filldir_t filldir); | 46 | static int coda_readdir(struct file *file, void *buf, filldir_t filldir); |
47 | 47 | ||
48 | /* dentry ops */ | 48 | /* dentry ops */ |
49 | static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd); | 49 | static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd); |
50 | static int coda_dentry_delete(struct dentry *); | 50 | static int coda_dentry_delete(struct dentry *); |
51 | 51 | ||
52 | /* support routines */ | 52 | /* support routines */ |
53 | static int coda_venus_readdir(struct file *filp, filldir_t filldir, | 53 | static int coda_venus_readdir(struct file *coda_file, void *buf, |
54 | void *dirent, struct dentry *dir); | 54 | filldir_t filldir); |
55 | 55 | ||
56 | /* same as fs/bad_inode.c */ | 56 | /* same as fs/bad_inode.c */ |
57 | static int coda_return_EIO(void) | 57 | static int coda_return_EIO(void) |
@@ -448,12 +448,10 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
448 | 448 | ||
449 | 449 | ||
450 | /* file operations for directories */ | 450 | /* file operations for directories */ |
451 | int coda_readdir(struct file *coda_file, void *dirent, filldir_t filldir) | 451 | int coda_readdir(struct file *coda_file, void *buf, filldir_t filldir) |
452 | { | 452 | { |
453 | struct dentry *coda_dentry = coda_file->f_path.dentry; | ||
454 | struct coda_file_info *cfi; | 453 | struct coda_file_info *cfi; |
455 | struct file *host_file; | 454 | struct file *host_file; |
456 | struct inode *host_inode; | ||
457 | int ret; | 455 | int ret; |
458 | 456 | ||
459 | cfi = CODA_FTOC(coda_file); | 457 | cfi = CODA_FTOC(coda_file); |
@@ -462,30 +460,31 @@ int coda_readdir(struct file *coda_file, void *dirent, filldir_t filldir) | |||
462 | 460 | ||
463 | coda_vfs_stat.readdir++; | 461 | coda_vfs_stat.readdir++; |
464 | 462 | ||
465 | host_inode = host_file->f_path.dentry->d_inode; | 463 | if (!host_file->f_op) |
466 | mutex_lock(&host_inode->i_mutex); | 464 | return -ENOTDIR; |
467 | host_file->f_pos = coda_file->f_pos; | 465 | |
468 | 466 | if (host_file->f_op->readdir) | |
469 | if (!host_file->f_op->readdir) { | 467 | { |
470 | /* Venus: we must read Venus dirents from the file */ | 468 | /* potemkin case: we were handed a directory inode. |
471 | ret = coda_venus_readdir(host_file, filldir, dirent, coda_dentry); | 469 | * We can't use vfs_readdir because we have to keep the file |
472 | } else { | 470 | * position in sync between the coda_file and the host_file. |
473 | /* potemkin case: we were handed a directory inode. */ | 471 | * and as such we need grab the inode mutex. */ |
474 | /* Yuk, we can't call vfs_readdir because we are already | 472 | struct inode *host_inode = host_file->f_path.dentry->d_inode; |
475 | * holding the inode semaphore. */ | 473 | |
476 | ret = -ENOTDIR; | 474 | mutex_lock(&host_inode->i_mutex); |
477 | if (!host_file->f_op || !host_file->f_op->readdir) | 475 | host_file->f_pos = coda_file->f_pos; |
478 | goto out; | ||
479 | 476 | ||
480 | ret = -ENOENT; | 477 | ret = -ENOENT; |
481 | if (!IS_DEADDIR(host_inode)) { | 478 | if (!IS_DEADDIR(host_inode)) { |
482 | ret = host_file->f_op->readdir(host_file, dirent, filldir); | 479 | ret = host_file->f_op->readdir(host_file, buf, filldir); |
483 | file_accessed(host_file); | 480 | file_accessed(host_file); |
484 | } | 481 | } |
482 | |||
483 | coda_file->f_pos = host_file->f_pos; | ||
484 | mutex_unlock(&host_inode->i_mutex); | ||
485 | } | 485 | } |
486 | out: | 486 | else /* Venus: we must read Venus dirents from a file */ |
487 | coda_file->f_pos = host_file->f_pos; | 487 | ret = coda_venus_readdir(coda_file, buf, filldir); |
488 | mutex_unlock(&host_inode->i_mutex); | ||
489 | 488 | ||
490 | return ret; | 489 | return ret; |
491 | } | 490 | } |
@@ -510,57 +509,68 @@ static inline unsigned int CDT2DT(unsigned char cdt) | |||
510 | } | 509 | } |
511 | 510 | ||
512 | /* support routines */ | 511 | /* support routines */ |
513 | static int coda_venus_readdir(struct file *filp, filldir_t filldir, | 512 | static int coda_venus_readdir(struct file *coda_file, void *buf, |
514 | void *dirent, struct dentry *dir) | 513 | filldir_t filldir) |
515 | { | 514 | { |
516 | int result = 0; /* # of entries returned */ | 515 | int result = 0; /* # of entries returned */ |
516 | struct coda_file_info *cfi; | ||
517 | struct coda_inode_info *cii; | ||
518 | struct file *host_file; | ||
519 | struct dentry *de; | ||
517 | struct venus_dirent *vdir; | 520 | struct venus_dirent *vdir; |
518 | unsigned long vdir_size = | 521 | unsigned long vdir_size = |
519 | (unsigned long)(&((struct venus_dirent *)0)->d_name); | 522 | (unsigned long)(&((struct venus_dirent *)0)->d_name); |
520 | unsigned int type; | 523 | unsigned int type; |
521 | struct qstr name; | 524 | struct qstr name; |
522 | ino_t ino; | 525 | ino_t ino; |
523 | int ret, i; | 526 | int ret; |
527 | |||
528 | cfi = CODA_FTOC(coda_file); | ||
529 | BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC); | ||
530 | host_file = cfi->cfi_container; | ||
531 | |||
532 | de = coda_file->f_path.dentry; | ||
533 | cii = ITOC(de->d_inode); | ||
524 | 534 | ||
525 | vdir = kmalloc(sizeof(*vdir), GFP_KERNEL); | 535 | vdir = kmalloc(sizeof(*vdir), GFP_KERNEL); |
526 | if (!vdir) return -ENOMEM; | 536 | if (!vdir) return -ENOMEM; |
527 | 537 | ||
528 | i = filp->f_pos; | 538 | switch (coda_file->f_pos) { |
529 | switch(i) { | ||
530 | case 0: | 539 | case 0: |
531 | ret = filldir(dirent, ".", 1, 0, dir->d_inode->i_ino, DT_DIR); | 540 | ret = filldir(buf, ".", 1, 0, de->d_inode->i_ino, DT_DIR); |
532 | if (ret < 0) break; | 541 | if (ret < 0) break; |
533 | result++; | 542 | result++; |
534 | filp->f_pos++; | 543 | coda_file->f_pos++; |
535 | /* fallthrough */ | 544 | /* fallthrough */ |
536 | case 1: | 545 | case 1: |
537 | ret = filldir(dirent, "..", 2, 1, dir->d_parent->d_inode->i_ino, DT_DIR); | 546 | ret = filldir(buf, "..", 2, 1, de->d_parent->d_inode->i_ino, DT_DIR); |
538 | if (ret < 0) break; | 547 | if (ret < 0) break; |
539 | result++; | 548 | result++; |
540 | filp->f_pos++; | 549 | coda_file->f_pos++; |
541 | /* fallthrough */ | 550 | /* fallthrough */ |
542 | default: | 551 | default: |
543 | while (1) { | 552 | while (1) { |
544 | /* read entries from the directory file */ | 553 | /* read entries from the directory file */ |
545 | ret = kernel_read(filp, filp->f_pos - 2, (char *)vdir, | 554 | ret = kernel_read(host_file, coda_file->f_pos - 2, (char *)vdir, |
546 | sizeof(*vdir)); | 555 | sizeof(*vdir)); |
547 | if (ret < 0) { | 556 | if (ret < 0) { |
548 | printk("coda_venus_readdir: read dir failed %d\n", ret); | 557 | printk(KERN_ERR "coda readdir: read dir %s failed %d\n", |
558 | coda_f2s(&cii->c_fid), ret); | ||
549 | break; | 559 | break; |
550 | } | 560 | } |
551 | if (ret == 0) break; /* end of directory file reached */ | 561 | if (ret == 0) break; /* end of directory file reached */ |
552 | 562 | ||
553 | /* catch truncated reads */ | 563 | /* catch truncated reads */ |
554 | if (ret < vdir_size || ret < vdir_size + vdir->d_namlen) { | 564 | if (ret < vdir_size || ret < vdir_size + vdir->d_namlen) { |
555 | printk("coda_venus_readdir: short read: %ld\n", | 565 | printk(KERN_ERR "coda readdir: short read on %s\n", |
556 | filp->f_path.dentry->d_inode->i_ino); | 566 | coda_f2s(&cii->c_fid)); |
557 | ret = -EBADF; | 567 | ret = -EBADF; |
558 | break; | 568 | break; |
559 | } | 569 | } |
560 | /* validate whether the directory file actually makes sense */ | 570 | /* validate whether the directory file actually makes sense */ |
561 | if (vdir->d_reclen < vdir_size + vdir->d_namlen) { | 571 | if (vdir->d_reclen < vdir_size + vdir->d_namlen) { |
562 | printk("coda_venus_readdir: Invalid dir: %ld\n", | 572 | printk(KERN_ERR "coda readdir: invalid dir %s\n", |
563 | filp->f_path.dentry->d_inode->i_ino); | 573 | coda_f2s(&cii->c_fid)); |
564 | ret = -EBADF; | 574 | ret = -EBADF; |
565 | break; | 575 | break; |
566 | } | 576 | } |
@@ -579,21 +589,21 @@ static int coda_venus_readdir(struct file *filp, filldir_t filldir, | |||
579 | * userspace doesn't have to worry about breaking | 589 | * userspace doesn't have to worry about breaking |
580 | * getcwd by having mismatched inode numbers for | 590 | * getcwd by having mismatched inode numbers for |
581 | * internal volume mountpoints. */ | 591 | * internal volume mountpoints. */ |
582 | ino = find_inode_number(dir, &name); | 592 | ino = find_inode_number(de, &name); |
583 | if (!ino) ino = vdir->d_fileno; | 593 | if (!ino) ino = vdir->d_fileno; |
584 | 594 | ||
585 | type = CDT2DT(vdir->d_type); | 595 | type = CDT2DT(vdir->d_type); |
586 | ret = filldir(dirent, name.name, name.len, filp->f_pos, | 596 | ret = filldir(buf, name.name, name.len, |
587 | ino, type); | 597 | coda_file->f_pos, ino, type); |
588 | /* failure means no space for filling in this round */ | 598 | /* failure means no space for filling in this round */ |
589 | if (ret < 0) break; | 599 | if (ret < 0) break; |
590 | result++; | 600 | result++; |
591 | } | 601 | } |
592 | /* we'll always have progress because d_reclen is unsigned and | 602 | /* we'll always have progress because d_reclen is unsigned and |
593 | * we've already established it is non-zero. */ | 603 | * we've already established it is non-zero. */ |
594 | filp->f_pos += vdir->d_reclen; | 604 | coda_file->f_pos += vdir->d_reclen; |
605 | } | ||
595 | } | 606 | } |
596 | } | ||
597 | kfree(vdir); | 607 | kfree(vdir); |
598 | return result ? result : ret; | 608 | return result ? result : ret; |
599 | } | 609 | } |