aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ncpfs/dir.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ncpfs/dir.c')
-rw-r--r--fs/ncpfs/dir.c123
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
26static void ncp_read_volume_list(struct file *, void *, filldir_t, 26static void ncp_read_volume_list(struct file *, struct dir_context *,
27 struct ncp_cache_control *); 27 struct ncp_cache_control *);
28static void ncp_do_readdir(struct file *, void *, filldir_t, 28static void ncp_do_readdir(struct file *, struct dir_context *,
29 struct ncp_cache_control *); 29 struct ncp_cache_control *);
30 30
31static int ncp_readdir(struct file *, void *, filldir_t); 31static int ncp_readdir(struct file *, struct dir_context *);
32 32
33static int ncp_create(struct inode *, struct dentry *, umode_t, bool); 33static int ncp_create(struct inode *, struct dentry *, umode_t, bool);
34static struct dentry *ncp_lookup(struct inode *, struct dentry *, unsigned int); 34static 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 */
75static int ncp_lookup_validate(struct dentry *, unsigned int); 75static int ncp_lookup_validate(struct dentry *, unsigned int);
76static int ncp_hash_dentry(const struct dentry *, const struct inode *, 76static int ncp_hash_dentry(const struct dentry *, struct qstr *);
77 struct qstr *); 77static int ncp_compare_dentry(const struct dentry *, const struct dentry *,
78static 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 *);
81static int ncp_delete_dentry(const struct dentry *); 79static 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 */
123static int 125static int
124ncp_hash_dentry(const struct dentry *dentry, const struct inode *inode, 126ncp_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 */
143static int 154static int
144ncp_compare_dentry(const struct dentry *parent, const struct inode *pinode, 155ncp_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
427static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir) 443static 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;
549read_really: 557read_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
575static int 583static int
576ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir, 584ncp_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,
666end_advance: 674end_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
685static void 691static void
686ncp_read_volume_list(struct file *filp, void *dirent, filldir_t filldir, 692ncp_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
723static void 729static void
724ncp_do_readdir(struct file *filp, void *dirent, filldir_t filldir, 730ncp_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