aboutsummaryrefslogtreecommitdiffstats
path: root/fs/coda/dir.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/coda/dir.c')
-rw-r--r--fs/coda/dir.c98
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 */
46static int coda_readdir(struct file *file, void *dirent, filldir_t filldir); 46static int coda_readdir(struct file *file, void *buf, filldir_t filldir);
47 47
48/* dentry ops */ 48/* dentry ops */
49static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd); 49static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd);
50static int coda_dentry_delete(struct dentry *); 50static int coda_dentry_delete(struct dentry *);
51 51
52/* support routines */ 52/* support routines */
53static int coda_venus_readdir(struct file *filp, filldir_t filldir, 53static 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 */
57static int coda_return_EIO(void) 57static 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 */
451int coda_readdir(struct file *coda_file, void *dirent, filldir_t filldir) 451int 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 }
486out: 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 */
513static int coda_venus_readdir(struct file *filp, filldir_t filldir, 512static 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}