diff options
Diffstat (limited to 'fs/coda')
-rw-r--r-- | fs/coda/dir.c | 77 |
1 files changed, 19 insertions, 58 deletions
diff --git a/fs/coda/dir.c b/fs/coda/dir.c index fc66861b3598..87e0ee9f4465 100644 --- a/fs/coda/dir.c +++ b/fs/coda/dir.c | |||
@@ -43,15 +43,14 @@ 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 *buf, filldir_t filldir); | 46 | static int coda_readdir(struct file *file, struct dir_context *ctx); |
47 | 47 | ||
48 | /* dentry ops */ | 48 | /* dentry ops */ |
49 | static int coda_dentry_revalidate(struct dentry *de, unsigned int flags); | 49 | static int coda_dentry_revalidate(struct dentry *de, unsigned int flags); |
50 | static int coda_dentry_delete(const struct dentry *); | 50 | static int coda_dentry_delete(const struct dentry *); |
51 | 51 | ||
52 | /* support routines */ | 52 | /* support routines */ |
53 | static int coda_venus_readdir(struct file *coda_file, void *buf, | 53 | static int coda_venus_readdir(struct file *, struct dir_context *); |
54 | filldir_t filldir); | ||
55 | 54 | ||
56 | /* same as fs/bad_inode.c */ | 55 | /* same as fs/bad_inode.c */ |
57 | static int coda_return_EIO(void) | 56 | static int coda_return_EIO(void) |
@@ -85,7 +84,7 @@ const struct inode_operations coda_dir_inode_operations = | |||
85 | const struct file_operations coda_dir_operations = { | 84 | const struct file_operations coda_dir_operations = { |
86 | .llseek = generic_file_llseek, | 85 | .llseek = generic_file_llseek, |
87 | .read = generic_read_dir, | 86 | .read = generic_read_dir, |
88 | .readdir = coda_readdir, | 87 | .iterate = coda_readdir, |
89 | .open = coda_open, | 88 | .open = coda_open, |
90 | .release = coda_release, | 89 | .release = coda_release, |
91 | .fsync = coda_fsync, | 90 | .fsync = coda_fsync, |
@@ -378,7 +377,7 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
378 | 377 | ||
379 | 378 | ||
380 | /* file operations for directories */ | 379 | /* file operations for directories */ |
381 | static int coda_readdir(struct file *coda_file, void *buf, filldir_t filldir) | 380 | static int coda_readdir(struct file *coda_file, struct dir_context *ctx) |
382 | { | 381 | { |
383 | struct coda_file_info *cfi; | 382 | struct coda_file_info *cfi; |
384 | struct file *host_file; | 383 | struct file *host_file; |
@@ -391,28 +390,8 @@ static int coda_readdir(struct file *coda_file, void *buf, filldir_t filldir) | |||
391 | if (!host_file->f_op) | 390 | if (!host_file->f_op) |
392 | return -ENOTDIR; | 391 | return -ENOTDIR; |
393 | 392 | ||
394 | if (host_file->f_op->readdir) { | 393 | if (host_file->f_op->iterate) { |
395 | /* potemkin case: we were handed a directory inode. | ||
396 | * We can't use vfs_readdir because we have to keep the file | ||
397 | * position in sync between the coda_file and the host_file. | ||
398 | * and as such we need grab the inode mutex. */ | ||
399 | struct inode *host_inode = file_inode(host_file); | 394 | struct inode *host_inode = file_inode(host_file); |
400 | |||
401 | mutex_lock(&host_inode->i_mutex); | ||
402 | host_file->f_pos = coda_file->f_pos; | ||
403 | |||
404 | ret = -ENOENT; | ||
405 | if (!IS_DEADDIR(host_inode)) { | ||
406 | ret = host_file->f_op->readdir(host_file, buf, filldir); | ||
407 | file_accessed(host_file); | ||
408 | } | ||
409 | |||
410 | coda_file->f_pos = host_file->f_pos; | ||
411 | mutex_unlock(&host_inode->i_mutex); | ||
412 | } else if (host_file->f_op->iterate) { | ||
413 | struct inode *host_inode = file_inode(host_file); | ||
414 | struct dir_context *ctx = buf; | ||
415 | |||
416 | mutex_lock(&host_inode->i_mutex); | 395 | mutex_lock(&host_inode->i_mutex); |
417 | ret = -ENOENT; | 396 | ret = -ENOENT; |
418 | if (!IS_DEADDIR(host_inode)) { | 397 | if (!IS_DEADDIR(host_inode)) { |
@@ -420,12 +399,10 @@ static int coda_readdir(struct file *coda_file, void *buf, filldir_t filldir) | |||
420 | file_accessed(host_file); | 399 | file_accessed(host_file); |
421 | } | 400 | } |
422 | mutex_unlock(&host_inode->i_mutex); | 401 | mutex_unlock(&host_inode->i_mutex); |
423 | 402 | return ret; | |
424 | coda_file->f_pos = ctx->pos; | 403 | } |
425 | } else /* Venus: we must read Venus dirents from a file */ | 404 | /* Venus: we must read Venus dirents from a file */ |
426 | ret = coda_venus_readdir(coda_file, buf, filldir); | 405 | return coda_venus_readdir(coda_file, ctx); |
427 | |||
428 | return ret; | ||
429 | } | 406 | } |
430 | 407 | ||
431 | static inline unsigned int CDT2DT(unsigned char cdt) | 408 | static inline unsigned int CDT2DT(unsigned char cdt) |
@@ -448,10 +425,8 @@ static inline unsigned int CDT2DT(unsigned char cdt) | |||
448 | } | 425 | } |
449 | 426 | ||
450 | /* support routines */ | 427 | /* support routines */ |
451 | static int coda_venus_readdir(struct file *coda_file, void *buf, | 428 | static int coda_venus_readdir(struct file *coda_file, struct dir_context *ctx) |
452 | filldir_t filldir) | ||
453 | { | 429 | { |
454 | int result = 0; /* # of entries returned */ | ||
455 | struct coda_file_info *cfi; | 430 | struct coda_file_info *cfi; |
456 | struct coda_inode_info *cii; | 431 | struct coda_inode_info *cii; |
457 | struct file *host_file; | 432 | struct file *host_file; |
@@ -473,23 +448,12 @@ static int coda_venus_readdir(struct file *coda_file, void *buf, | |||
473 | vdir = kmalloc(sizeof(*vdir), GFP_KERNEL); | 448 | vdir = kmalloc(sizeof(*vdir), GFP_KERNEL); |
474 | if (!vdir) return -ENOMEM; | 449 | if (!vdir) return -ENOMEM; |
475 | 450 | ||
476 | if (coda_file->f_pos == 0) { | 451 | if (!dir_emit_dots(coda_file, ctx)) |
477 | ret = filldir(buf, ".", 1, 0, de->d_inode->i_ino, DT_DIR); | 452 | goto out; |
478 | if (ret < 0) | 453 | |
479 | goto out; | ||
480 | result++; | ||
481 | coda_file->f_pos++; | ||
482 | } | ||
483 | if (coda_file->f_pos == 1) { | ||
484 | ret = filldir(buf, "..", 2, 1, parent_ino(de), DT_DIR); | ||
485 | if (ret < 0) | ||
486 | goto out; | ||
487 | result++; | ||
488 | coda_file->f_pos++; | ||
489 | } | ||
490 | while (1) { | 454 | while (1) { |
491 | /* read entries from the directory file */ | 455 | /* read entries from the directory file */ |
492 | ret = kernel_read(host_file, coda_file->f_pos - 2, (char *)vdir, | 456 | ret = kernel_read(host_file, ctx->pos - 2, (char *)vdir, |
493 | sizeof(*vdir)); | 457 | sizeof(*vdir)); |
494 | if (ret < 0) { | 458 | if (ret < 0) { |
495 | printk(KERN_ERR "coda readdir: read dir %s failed %d\n", | 459 | printk(KERN_ERR "coda readdir: read dir %s failed %d\n", |
@@ -518,7 +482,7 @@ static int coda_venus_readdir(struct file *coda_file, void *buf, | |||
518 | 482 | ||
519 | /* Make sure we skip '.' and '..', we already got those */ | 483 | /* Make sure we skip '.' and '..', we already got those */ |
520 | if (name.name[0] == '.' && (name.len == 1 || | 484 | if (name.name[0] == '.' && (name.len == 1 || |
521 | (vdir->d_name[1] == '.' && name.len == 2))) | 485 | (name.name[1] == '.' && name.len == 2))) |
522 | vdir->d_fileno = name.len = 0; | 486 | vdir->d_fileno = name.len = 0; |
523 | 487 | ||
524 | /* skip null entries */ | 488 | /* skip null entries */ |
@@ -531,19 +495,16 @@ static int coda_venus_readdir(struct file *coda_file, void *buf, | |||
531 | if (!ino) ino = vdir->d_fileno; | 495 | if (!ino) ino = vdir->d_fileno; |
532 | 496 | ||
533 | type = CDT2DT(vdir->d_type); | 497 | type = CDT2DT(vdir->d_type); |
534 | ret = filldir(buf, name.name, name.len, | 498 | if (!dir_emit(ctx, name.name, name.len, ino, type)) |
535 | coda_file->f_pos, ino, type); | 499 | break; |
536 | /* failure means no space for filling in this round */ | ||
537 | if (ret < 0) break; | ||
538 | result++; | ||
539 | } | 500 | } |
540 | /* we'll always have progress because d_reclen is unsigned and | 501 | /* we'll always have progress because d_reclen is unsigned and |
541 | * we've already established it is non-zero. */ | 502 | * we've already established it is non-zero. */ |
542 | coda_file->f_pos += vdir->d_reclen; | 503 | ctx->pos += vdir->d_reclen; |
543 | } | 504 | } |
544 | out: | 505 | out: |
545 | kfree(vdir); | 506 | kfree(vdir); |
546 | return result ? result : ret; | 507 | return 0; |
547 | } | 508 | } |
548 | 509 | ||
549 | /* called when a cache lookup succeeds */ | 510 | /* called when a cache lookup succeeds */ |