diff options
Diffstat (limited to 'fs/ncpfs/dir.c')
-rw-r--r-- | fs/ncpfs/dir.c | 123 |
1 files changed, 59 insertions, 64 deletions
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index 6792ce11f2bf..3be047474bfc 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c | |||
@@ -23,12 +23,12 @@ | |||
23 | 23 | ||
24 | #include "ncp_fs.h" | 24 | #include "ncp_fs.h" |
25 | 25 | ||
26 | static void ncp_read_volume_list(struct file *, void *, filldir_t, | 26 | static void ncp_read_volume_list(struct file *, struct dir_context *, |
27 | struct ncp_cache_control *); | 27 | struct ncp_cache_control *); |
28 | static void ncp_do_readdir(struct file *, void *, filldir_t, | 28 | static void ncp_do_readdir(struct file *, struct dir_context *, |
29 | struct ncp_cache_control *); | 29 | struct ncp_cache_control *); |
30 | 30 | ||
31 | static int ncp_readdir(struct file *, void *, filldir_t); | 31 | static int ncp_readdir(struct file *, struct dir_context *); |
32 | 32 | ||
33 | static int ncp_create(struct inode *, struct dentry *, umode_t, bool); | 33 | static int ncp_create(struct inode *, struct dentry *, umode_t, bool); |
34 | static struct dentry *ncp_lookup(struct inode *, struct dentry *, unsigned int); | 34 | static struct dentry *ncp_lookup(struct inode *, struct dentry *, unsigned int); |
@@ -49,7 +49,7 @@ const struct file_operations ncp_dir_operations = | |||
49 | { | 49 | { |
50 | .llseek = generic_file_llseek, | 50 | .llseek = generic_file_llseek, |
51 | .read = generic_read_dir, | 51 | .read = generic_read_dir, |
52 | .readdir = ncp_readdir, | 52 | .iterate = ncp_readdir, |
53 | .unlocked_ioctl = ncp_ioctl, | 53 | .unlocked_ioctl = ncp_ioctl, |
54 | #ifdef CONFIG_COMPAT | 54 | #ifdef CONFIG_COMPAT |
55 | .compat_ioctl = ncp_compat_ioctl, | 55 | .compat_ioctl = ncp_compat_ioctl, |
@@ -73,10 +73,8 @@ const struct inode_operations ncp_dir_inode_operations = | |||
73 | * Dentry operations routines | 73 | * Dentry operations routines |
74 | */ | 74 | */ |
75 | static int ncp_lookup_validate(struct dentry *, unsigned int); | 75 | static int ncp_lookup_validate(struct dentry *, unsigned int); |
76 | static int ncp_hash_dentry(const struct dentry *, const struct inode *, | 76 | static int ncp_hash_dentry(const struct dentry *, struct qstr *); |
77 | struct qstr *); | 77 | static int ncp_compare_dentry(const struct dentry *, const struct dentry *, |
78 | static int ncp_compare_dentry(const struct dentry *, const struct inode *, | ||
79 | const struct dentry *, const struct inode *, | ||
80 | unsigned int, const char *, const struct qstr *); | 78 | unsigned int, const char *, const struct qstr *); |
81 | static int ncp_delete_dentry(const struct dentry *); | 79 | static int ncp_delete_dentry(const struct dentry *); |
82 | 80 | ||
@@ -119,11 +117,19 @@ static inline int ncp_case_sensitive(const struct inode *i) | |||
119 | /* | 117 | /* |
120 | * Note: leave the hash unchanged if the directory | 118 | * Note: leave the hash unchanged if the directory |
121 | * is case-sensitive. | 119 | * is case-sensitive. |
120 | * | ||
121 | * Accessing the parent inode can be racy under RCU pathwalking. | ||
122 | * Use ACCESS_ONCE() to make sure we use _one_ particular inode, | ||
123 | * the callers will handle races. | ||
122 | */ | 124 | */ |
123 | static int | 125 | static int |
124 | ncp_hash_dentry(const struct dentry *dentry, const struct inode *inode, | 126 | ncp_hash_dentry(const struct dentry *dentry, struct qstr *this) |
125 | struct qstr *this) | ||
126 | { | 127 | { |
128 | struct inode *inode = ACCESS_ONCE(dentry->d_inode); | ||
129 | |||
130 | if (!inode) | ||
131 | return 0; | ||
132 | |||
127 | if (!ncp_case_sensitive(inode)) { | 133 | if (!ncp_case_sensitive(inode)) { |
128 | struct super_block *sb = dentry->d_sb; | 134 | struct super_block *sb = dentry->d_sb; |
129 | struct nls_table *t; | 135 | struct nls_table *t; |
@@ -140,14 +146,24 @@ ncp_hash_dentry(const struct dentry *dentry, const struct inode *inode, | |||
140 | return 0; | 146 | return 0; |
141 | } | 147 | } |
142 | 148 | ||
149 | /* | ||
150 | * Accessing the parent inode can be racy under RCU pathwalking. | ||
151 | * Use ACCESS_ONCE() to make sure we use _one_ particular inode, | ||
152 | * the callers will handle races. | ||
153 | */ | ||
143 | static int | 154 | static int |
144 | ncp_compare_dentry(const struct dentry *parent, const struct inode *pinode, | 155 | ncp_compare_dentry(const struct dentry *parent, const struct dentry *dentry, |
145 | const struct dentry *dentry, const struct inode *inode, | ||
146 | unsigned int len, const char *str, const struct qstr *name) | 156 | unsigned int len, const char *str, const struct qstr *name) |
147 | { | 157 | { |
158 | struct inode *pinode; | ||
159 | |||
148 | if (len != name->len) | 160 | if (len != name->len) |
149 | return 1; | 161 | return 1; |
150 | 162 | ||
163 | pinode = ACCESS_ONCE(parent->d_inode); | ||
164 | if (!pinode) | ||
165 | return 1; | ||
166 | |||
151 | if (ncp_case_sensitive(pinode)) | 167 | if (ncp_case_sensitive(pinode)) |
152 | return strncmp(str, name->name, len); | 168 | return strncmp(str, name->name, len); |
153 | 169 | ||
@@ -424,9 +440,9 @@ static time_t ncp_obtain_mtime(struct dentry *dentry) | |||
424 | return ncp_date_dos2unix(i.modifyTime, i.modifyDate); | 440 | return ncp_date_dos2unix(i.modifyTime, i.modifyDate); |
425 | } | 441 | } |
426 | 442 | ||
427 | static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir) | 443 | static int ncp_readdir(struct file *file, struct dir_context *ctx) |
428 | { | 444 | { |
429 | struct dentry *dentry = filp->f_path.dentry; | 445 | struct dentry *dentry = file->f_path.dentry; |
430 | struct inode *inode = dentry->d_inode; | 446 | struct inode *inode = dentry->d_inode; |
431 | struct page *page = NULL; | 447 | struct page *page = NULL; |
432 | struct ncp_server *server = NCP_SERVER(inode); | 448 | struct ncp_server *server = NCP_SERVER(inode); |
@@ -440,7 +456,7 @@ static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
440 | 456 | ||
441 | DDPRINTK("ncp_readdir: reading %s/%s, pos=%d\n", | 457 | DDPRINTK("ncp_readdir: reading %s/%s, pos=%d\n", |
442 | dentry->d_parent->d_name.name, dentry->d_name.name, | 458 | dentry->d_parent->d_name.name, dentry->d_name.name, |
443 | (int) filp->f_pos); | 459 | (int) ctx->pos); |
444 | 460 | ||
445 | result = -EIO; | 461 | result = -EIO; |
446 | /* Do not generate '.' and '..' when server is dead. */ | 462 | /* Do not generate '.' and '..' when server is dead. */ |
@@ -448,16 +464,8 @@ static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
448 | goto out; | 464 | goto out; |
449 | 465 | ||
450 | result = 0; | 466 | result = 0; |
451 | if (filp->f_pos == 0) { | 467 | if (!dir_emit_dots(file, ctx)) |
452 | if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR)) | 468 | goto out; |
453 | goto out; | ||
454 | filp->f_pos = 1; | ||
455 | } | ||
456 | if (filp->f_pos == 1) { | ||
457 | if (filldir(dirent, "..", 2, 1, parent_ino(dentry), DT_DIR)) | ||
458 | goto out; | ||
459 | filp->f_pos = 2; | ||
460 | } | ||
461 | 469 | ||
462 | page = grab_cache_page(&inode->i_data, 0); | 470 | page = grab_cache_page(&inode->i_data, 0); |
463 | if (!page) | 471 | if (!page) |
@@ -469,7 +477,7 @@ static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
469 | if (!PageUptodate(page) || !ctl.head.eof) | 477 | if (!PageUptodate(page) || !ctl.head.eof) |
470 | goto init_cache; | 478 | goto init_cache; |
471 | 479 | ||
472 | if (filp->f_pos == 2) { | 480 | if (ctx->pos == 2) { |
473 | if (jiffies - ctl.head.time >= NCP_MAX_AGE(server)) | 481 | if (jiffies - ctl.head.time >= NCP_MAX_AGE(server)) |
474 | goto init_cache; | 482 | goto init_cache; |
475 | 483 | ||
@@ -479,10 +487,10 @@ static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
479 | goto init_cache; | 487 | goto init_cache; |
480 | } | 488 | } |
481 | 489 | ||
482 | if (filp->f_pos > ctl.head.end) | 490 | if (ctx->pos > ctl.head.end) |
483 | goto finished; | 491 | goto finished; |
484 | 492 | ||
485 | ctl.fpos = filp->f_pos + (NCP_DIRCACHE_START - 2); | 493 | ctl.fpos = ctx->pos + (NCP_DIRCACHE_START - 2); |
486 | ctl.ofs = ctl.fpos / NCP_DIRCACHE_SIZE; | 494 | ctl.ofs = ctl.fpos / NCP_DIRCACHE_SIZE; |
487 | ctl.idx = ctl.fpos % NCP_DIRCACHE_SIZE; | 495 | ctl.idx = ctl.fpos % NCP_DIRCACHE_SIZE; |
488 | 496 | ||
@@ -497,21 +505,21 @@ static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
497 | } | 505 | } |
498 | while (ctl.idx < NCP_DIRCACHE_SIZE) { | 506 | while (ctl.idx < NCP_DIRCACHE_SIZE) { |
499 | struct dentry *dent; | 507 | struct dentry *dent; |
500 | int res; | 508 | bool over; |
501 | 509 | ||
502 | dent = ncp_dget_fpos(ctl.cache->dentry[ctl.idx], | 510 | dent = ncp_dget_fpos(ctl.cache->dentry[ctl.idx], |
503 | dentry, filp->f_pos); | 511 | dentry, ctx->pos); |
504 | if (!dent) | 512 | if (!dent) |
505 | goto invalid_cache; | 513 | goto invalid_cache; |
506 | res = filldir(dirent, dent->d_name.name, | 514 | over = !dir_emit(ctx, dent->d_name.name, |
507 | dent->d_name.len, filp->f_pos, | 515 | dent->d_name.len, |
508 | dent->d_inode->i_ino, DT_UNKNOWN); | 516 | dent->d_inode->i_ino, DT_UNKNOWN); |
509 | dput(dent); | 517 | dput(dent); |
510 | if (res) | 518 | if (over) |
511 | goto finished; | 519 | goto finished; |
512 | filp->f_pos += 1; | 520 | ctx->pos += 1; |
513 | ctl.idx += 1; | 521 | ctl.idx += 1; |
514 | if (filp->f_pos > ctl.head.end) | 522 | if (ctx->pos > ctl.head.end) |
515 | goto finished; | 523 | goto finished; |
516 | } | 524 | } |
517 | if (ctl.page) { | 525 | if (ctl.page) { |
@@ -548,9 +556,9 @@ init_cache: | |||
548 | ctl.valid = 1; | 556 | ctl.valid = 1; |
549 | read_really: | 557 | read_really: |
550 | if (ncp_is_server_root(inode)) { | 558 | if (ncp_is_server_root(inode)) { |
551 | ncp_read_volume_list(filp, dirent, filldir, &ctl); | 559 | ncp_read_volume_list(file, ctx, &ctl); |
552 | } else { | 560 | } else { |
553 | ncp_do_readdir(filp, dirent, filldir, &ctl); | 561 | ncp_do_readdir(file, ctx, &ctl); |
554 | } | 562 | } |
555 | ctl.head.end = ctl.fpos - 1; | 563 | ctl.head.end = ctl.fpos - 1; |
556 | ctl.head.eof = ctl.valid; | 564 | ctl.head.eof = ctl.valid; |
@@ -573,11 +581,11 @@ out: | |||
573 | } | 581 | } |
574 | 582 | ||
575 | static int | 583 | static int |
576 | ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir, | 584 | ncp_fill_cache(struct file *file, struct dir_context *ctx, |
577 | struct ncp_cache_control *ctrl, struct ncp_entry_info *entry, | 585 | struct ncp_cache_control *ctrl, struct ncp_entry_info *entry, |
578 | int inval_childs) | 586 | int inval_childs) |
579 | { | 587 | { |
580 | struct dentry *newdent, *dentry = filp->f_path.dentry; | 588 | struct dentry *newdent, *dentry = file->f_path.dentry; |
581 | struct inode *dir = dentry->d_inode; | 589 | struct inode *dir = dentry->d_inode; |
582 | struct ncp_cache_control ctl = *ctrl; | 590 | struct ncp_cache_control ctl = *ctrl; |
583 | struct qstr qname; | 591 | struct qstr qname; |
@@ -666,15 +674,13 @@ ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir, | |||
666 | end_advance: | 674 | end_advance: |
667 | if (!valid) | 675 | if (!valid) |
668 | ctl.valid = 0; | 676 | ctl.valid = 0; |
669 | if (!ctl.filled && (ctl.fpos == filp->f_pos)) { | 677 | if (!ctl.filled && (ctl.fpos == ctx->pos)) { |
670 | if (!ino) | ||
671 | ino = find_inode_number(dentry, &qname); | ||
672 | if (!ino) | 678 | if (!ino) |
673 | ino = iunique(dir->i_sb, 2); | 679 | ino = iunique(dir->i_sb, 2); |
674 | ctl.filled = filldir(dirent, qname.name, qname.len, | 680 | ctl.filled = !dir_emit(ctx, qname.name, qname.len, |
675 | filp->f_pos, ino, DT_UNKNOWN); | 681 | ino, DT_UNKNOWN); |
676 | if (!ctl.filled) | 682 | if (!ctl.filled) |
677 | filp->f_pos += 1; | 683 | ctx->pos += 1; |
678 | } | 684 | } |
679 | ctl.fpos += 1; | 685 | ctl.fpos += 1; |
680 | ctl.idx += 1; | 686 | ctl.idx += 1; |
@@ -683,10 +689,10 @@ end_advance: | |||
683 | } | 689 | } |
684 | 690 | ||
685 | static void | 691 | static void |
686 | ncp_read_volume_list(struct file *filp, void *dirent, filldir_t filldir, | 692 | ncp_read_volume_list(struct file *file, struct dir_context *ctx, |
687 | struct ncp_cache_control *ctl) | 693 | struct ncp_cache_control *ctl) |
688 | { | 694 | { |
689 | struct dentry *dentry = filp->f_path.dentry; | 695 | struct dentry *dentry = file->f_path.dentry; |
690 | struct inode *inode = dentry->d_inode; | 696 | struct inode *inode = dentry->d_inode; |
691 | struct ncp_server *server = NCP_SERVER(inode); | 697 | struct ncp_server *server = NCP_SERVER(inode); |
692 | struct ncp_volume_info info; | 698 | struct ncp_volume_info info; |
@@ -694,7 +700,7 @@ ncp_read_volume_list(struct file *filp, void *dirent, filldir_t filldir, | |||
694 | int i; | 700 | int i; |
695 | 701 | ||
696 | DPRINTK("ncp_read_volume_list: pos=%ld\n", | 702 | DPRINTK("ncp_read_volume_list: pos=%ld\n", |
697 | (unsigned long) filp->f_pos); | 703 | (unsigned long) ctx->pos); |
698 | 704 | ||
699 | for (i = 0; i < NCP_NUMBER_OF_VOLUMES; i++) { | 705 | for (i = 0; i < NCP_NUMBER_OF_VOLUMES; i++) { |
700 | int inval_dentry; | 706 | int inval_dentry; |
@@ -715,16 +721,16 @@ ncp_read_volume_list(struct file *filp, void *dirent, filldir_t filldir, | |||
715 | } | 721 | } |
716 | inval_dentry = ncp_update_known_namespace(server, entry.i.volNumber, NULL); | 722 | inval_dentry = ncp_update_known_namespace(server, entry.i.volNumber, NULL); |
717 | entry.volume = entry.i.volNumber; | 723 | entry.volume = entry.i.volNumber; |
718 | if (!ncp_fill_cache(filp, dirent, filldir, ctl, &entry, inval_dentry)) | 724 | if (!ncp_fill_cache(file, ctx, ctl, &entry, inval_dentry)) |
719 | return; | 725 | return; |
720 | } | 726 | } |
721 | } | 727 | } |
722 | 728 | ||
723 | static void | 729 | static void |
724 | ncp_do_readdir(struct file *filp, void *dirent, filldir_t filldir, | 730 | ncp_do_readdir(struct file *file, struct dir_context *ctx, |
725 | struct ncp_cache_control *ctl) | 731 | struct ncp_cache_control *ctl) |
726 | { | 732 | { |
727 | struct dentry *dentry = filp->f_path.dentry; | 733 | struct dentry *dentry = file->f_path.dentry; |
728 | struct inode *dir = dentry->d_inode; | 734 | struct inode *dir = dentry->d_inode; |
729 | struct ncp_server *server = NCP_SERVER(dir); | 735 | struct ncp_server *server = NCP_SERVER(dir); |
730 | struct nw_search_sequence seq; | 736 | struct nw_search_sequence seq; |
@@ -736,7 +742,7 @@ ncp_do_readdir(struct file *filp, void *dirent, filldir_t filldir, | |||
736 | 742 | ||
737 | DPRINTK("ncp_do_readdir: %s/%s, fpos=%ld\n", | 743 | DPRINTK("ncp_do_readdir: %s/%s, fpos=%ld\n", |
738 | dentry->d_parent->d_name.name, dentry->d_name.name, | 744 | dentry->d_parent->d_name.name, dentry->d_name.name, |
739 | (unsigned long) filp->f_pos); | 745 | (unsigned long) ctx->pos); |
740 | PPRINTK("ncp_do_readdir: init %s, volnum=%d, dirent=%u\n", | 746 | PPRINTK("ncp_do_readdir: init %s, volnum=%d, dirent=%u\n", |
741 | dentry->d_name.name, NCP_FINFO(dir)->volNumber, | 747 | dentry->d_name.name, NCP_FINFO(dir)->volNumber, |
742 | NCP_FINFO(dir)->dirEntNum); | 748 | NCP_FINFO(dir)->dirEntNum); |
@@ -778,7 +784,7 @@ ncp_do_readdir(struct file *filp, void *dirent, filldir_t filldir, | |||
778 | rpl += onerpl; | 784 | rpl += onerpl; |
779 | rpls -= onerpl; | 785 | rpls -= onerpl; |
780 | entry.volume = entry.i.volNumber; | 786 | entry.volume = entry.i.volNumber; |
781 | if (!ncp_fill_cache(filp, dirent, filldir, ctl, &entry, 0)) | 787 | if (!ncp_fill_cache(file, ctx, ctl, &entry, 0)) |
782 | break; | 788 | break; |
783 | } | 789 | } |
784 | } while (more); | 790 | } while (more); |
@@ -1131,17 +1137,6 @@ static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
1131 | old_dentry->d_parent->d_name.name, old_dentry->d_name.name, | 1137 | old_dentry->d_parent->d_name.name, old_dentry->d_name.name, |
1132 | new_dentry->d_parent->d_name.name, new_dentry->d_name.name); | 1138 | new_dentry->d_parent->d_name.name, new_dentry->d_name.name); |
1133 | 1139 | ||
1134 | if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode)) { | ||
1135 | /* | ||
1136 | * fail with EBUSY if there are still references to this | ||
1137 | * directory. | ||
1138 | */ | ||
1139 | dentry_unhash(new_dentry); | ||
1140 | error = -EBUSY; | ||
1141 | if (!d_unhashed(new_dentry)) | ||
1142 | goto out; | ||
1143 | } | ||
1144 | |||
1145 | ncp_age_dentry(server, old_dentry); | 1140 | ncp_age_dentry(server, old_dentry); |
1146 | ncp_age_dentry(server, new_dentry); | 1141 | ncp_age_dentry(server, new_dentry); |
1147 | 1142 | ||