diff options
Diffstat (limited to 'fs/ncpfs/dir.c')
-rw-r--r-- | fs/ncpfs/dir.c | 88 |
1 files changed, 38 insertions, 50 deletions
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index f22b12e7d337..28f136d4aaec 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
18 | #include <linux/vmalloc.h> | 18 | #include <linux/vmalloc.h> |
19 | #include <linux/mm.h> | 19 | #include <linux/mm.h> |
20 | #include <linux/namei.h> | ||
20 | #include <asm/uaccess.h> | 21 | #include <asm/uaccess.h> |
21 | #include <asm/byteorder.h> | 22 | #include <asm/byteorder.h> |
22 | 23 | ||
@@ -74,9 +75,12 @@ const struct inode_operations ncp_dir_inode_operations = | |||
74 | * Dentry operations routines | 75 | * Dentry operations routines |
75 | */ | 76 | */ |
76 | static int ncp_lookup_validate(struct dentry *, struct nameidata *); | 77 | static int ncp_lookup_validate(struct dentry *, struct nameidata *); |
77 | static int ncp_hash_dentry(struct dentry *, struct qstr *); | 78 | static int ncp_hash_dentry(const struct dentry *, const struct inode *, |
78 | static int ncp_compare_dentry (struct dentry *, struct qstr *, struct qstr *); | 79 | struct qstr *); |
79 | static int ncp_delete_dentry(struct dentry *); | 80 | static int ncp_compare_dentry(const struct dentry *, const struct inode *, |
81 | const struct dentry *, const struct inode *, | ||
82 | unsigned int, const char *, const struct qstr *); | ||
83 | static int ncp_delete_dentry(const struct dentry *); | ||
80 | 84 | ||
81 | static const struct dentry_operations ncp_dentry_operations = | 85 | static const struct dentry_operations ncp_dentry_operations = |
82 | { | 86 | { |
@@ -113,10 +117,10 @@ static inline int ncp_preserve_entry_case(struct inode *i, __u32 nscreator) | |||
113 | 117 | ||
114 | #define ncp_preserve_case(i) (ncp_namespace(i) != NW_NS_DOS) | 118 | #define ncp_preserve_case(i) (ncp_namespace(i) != NW_NS_DOS) |
115 | 119 | ||
116 | static inline int ncp_case_sensitive(struct dentry *dentry) | 120 | static inline int ncp_case_sensitive(const struct inode *i) |
117 | { | 121 | { |
118 | #ifdef CONFIG_NCPFS_NFS_NS | 122 | #ifdef CONFIG_NCPFS_NFS_NS |
119 | return ncp_namespace(dentry->d_inode) == NW_NS_NFS; | 123 | return ncp_namespace(i) == NW_NS_NFS; |
120 | #else | 124 | #else |
121 | return 0; | 125 | return 0; |
122 | #endif /* CONFIG_NCPFS_NFS_NS */ | 126 | #endif /* CONFIG_NCPFS_NFS_NS */ |
@@ -127,14 +131,16 @@ static inline int ncp_case_sensitive(struct dentry *dentry) | |||
127 | * is case-sensitive. | 131 | * is case-sensitive. |
128 | */ | 132 | */ |
129 | static int | 133 | static int |
130 | ncp_hash_dentry(struct dentry *dentry, struct qstr *this) | 134 | ncp_hash_dentry(const struct dentry *dentry, const struct inode *inode, |
135 | struct qstr *this) | ||
131 | { | 136 | { |
132 | if (!ncp_case_sensitive(dentry)) { | 137 | if (!ncp_case_sensitive(inode)) { |
138 | struct super_block *sb = dentry->d_sb; | ||
133 | struct nls_table *t; | 139 | struct nls_table *t; |
134 | unsigned long hash; | 140 | unsigned long hash; |
135 | int i; | 141 | int i; |
136 | 142 | ||
137 | t = NCP_IO_TABLE(dentry); | 143 | t = NCP_IO_TABLE(sb); |
138 | hash = init_name_hash(); | 144 | hash = init_name_hash(); |
139 | for (i=0; i<this->len ; i++) | 145 | for (i=0; i<this->len ; i++) |
140 | hash = partial_name_hash(ncp_tolower(t, this->name[i]), | 146 | hash = partial_name_hash(ncp_tolower(t, this->name[i]), |
@@ -145,15 +151,17 @@ ncp_hash_dentry(struct dentry *dentry, struct qstr *this) | |||
145 | } | 151 | } |
146 | 152 | ||
147 | static int | 153 | static int |
148 | ncp_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b) | 154 | ncp_compare_dentry(const struct dentry *parent, const struct inode *pinode, |
155 | const struct dentry *dentry, const struct inode *inode, | ||
156 | unsigned int len, const char *str, const struct qstr *name) | ||
149 | { | 157 | { |
150 | if (a->len != b->len) | 158 | if (len != name->len) |
151 | return 1; | 159 | return 1; |
152 | 160 | ||
153 | if (ncp_case_sensitive(dentry)) | 161 | if (ncp_case_sensitive(pinode)) |
154 | return strncmp(a->name, b->name, a->len); | 162 | return strncmp(str, name->name, len); |
155 | 163 | ||
156 | return ncp_strnicmp(NCP_IO_TABLE(dentry), a->name, b->name, a->len); | 164 | return ncp_strnicmp(NCP_IO_TABLE(pinode->i_sb), str, name->name, len); |
157 | } | 165 | } |
158 | 166 | ||
159 | /* | 167 | /* |
@@ -162,7 +170,7 @@ ncp_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b) | |||
162 | * Closing files can be safely postponed until iput() - it's done there anyway. | 170 | * Closing files can be safely postponed until iput() - it's done there anyway. |
163 | */ | 171 | */ |
164 | static int | 172 | static int |
165 | ncp_delete_dentry(struct dentry * dentry) | 173 | ncp_delete_dentry(const struct dentry * dentry) |
166 | { | 174 | { |
167 | struct inode *inode = dentry->d_inode; | 175 | struct inode *inode = dentry->d_inode; |
168 | 176 | ||
@@ -301,6 +309,9 @@ ncp_lookup_validate(struct dentry *dentry, struct nameidata *nd) | |||
301 | int res, val = 0, len; | 309 | int res, val = 0, len; |
302 | __u8 __name[NCP_MAXPATHLEN + 1]; | 310 | __u8 __name[NCP_MAXPATHLEN + 1]; |
303 | 311 | ||
312 | if (nd->flags & LOOKUP_RCU) | ||
313 | return -ECHILD; | ||
314 | |||
304 | parent = dget_parent(dentry); | 315 | parent = dget_parent(dentry); |
305 | dir = parent->d_inode; | 316 | dir = parent->d_inode; |
306 | 317 | ||
@@ -384,21 +395,21 @@ ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos) | |||
384 | } | 395 | } |
385 | 396 | ||
386 | /* If a pointer is invalid, we search the dentry. */ | 397 | /* If a pointer is invalid, we search the dentry. */ |
387 | spin_lock(&dcache_lock); | 398 | spin_lock(&parent->d_lock); |
388 | next = parent->d_subdirs.next; | 399 | next = parent->d_subdirs.next; |
389 | while (next != &parent->d_subdirs) { | 400 | while (next != &parent->d_subdirs) { |
390 | dent = list_entry(next, struct dentry, d_u.d_child); | 401 | dent = list_entry(next, struct dentry, d_u.d_child); |
391 | if ((unsigned long)dent->d_fsdata == fpos) { | 402 | if ((unsigned long)dent->d_fsdata == fpos) { |
392 | if (dent->d_inode) | 403 | if (dent->d_inode) |
393 | dget_locked(dent); | 404 | dget(dent); |
394 | else | 405 | else |
395 | dent = NULL; | 406 | dent = NULL; |
396 | spin_unlock(&dcache_lock); | 407 | spin_unlock(&parent->d_lock); |
397 | goto out; | 408 | goto out; |
398 | } | 409 | } |
399 | next = next->next; | 410 | next = next->next; |
400 | } | 411 | } |
401 | spin_unlock(&dcache_lock); | 412 | spin_unlock(&parent->d_lock); |
402 | return NULL; | 413 | return NULL; |
403 | 414 | ||
404 | out: | 415 | out: |
@@ -592,7 +603,7 @@ ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir, | |||
592 | qname.hash = full_name_hash(qname.name, qname.len); | 603 | qname.hash = full_name_hash(qname.name, qname.len); |
593 | 604 | ||
594 | if (dentry->d_op && dentry->d_op->d_hash) | 605 | if (dentry->d_op && dentry->d_op->d_hash) |
595 | if (dentry->d_op->d_hash(dentry, &qname) != 0) | 606 | if (dentry->d_op->d_hash(dentry, dentry->d_inode, &qname) != 0) |
596 | goto end_advance; | 607 | goto end_advance; |
597 | 608 | ||
598 | newdent = d_lookup(dentry, &qname); | 609 | newdent = d_lookup(dentry, &qname); |
@@ -611,35 +622,12 @@ ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir, | |||
611 | shrink_dcache_parent(newdent); | 622 | shrink_dcache_parent(newdent); |
612 | 623 | ||
613 | /* | 624 | /* |
614 | * It is not as dangerous as it looks. NetWare's OS2 namespace is | 625 | * NetWare's OS2 namespace is case preserving yet case |
615 | * case preserving yet case insensitive. So we update dentry's name | 626 | * insensitive. So we update dentry's name as received from |
616 | * as received from server. We found dentry via d_lookup with our | 627 | * server. Parent dir's i_mutex is locked because we're in |
617 | * hash, so we know that hash does not change, and so replacing name | 628 | * readdir. |
618 | * should be reasonably safe. | ||
619 | */ | 629 | */ |
620 | if (qname.len == newdent->d_name.len && | 630 | dentry_update_name_case(newdent, &qname); |
621 | memcmp(newdent->d_name.name, qname.name, newdent->d_name.len)) { | ||
622 | struct inode *inode = newdent->d_inode; | ||
623 | |||
624 | /* | ||
625 | * Inside ncpfs all uses of d_name are either for debugging, | ||
626 | * or on functions which acquire inode mutex (mknod, creat, | ||
627 | * lookup). So grab i_mutex here, to be sure. d_path | ||
628 | * uses dcache_lock when generating path, so we should too. | ||
629 | * And finally d_compare is protected by dentry's d_lock, so | ||
630 | * here we go. | ||
631 | */ | ||
632 | if (inode) | ||
633 | mutex_lock(&inode->i_mutex); | ||
634 | spin_lock(&dcache_lock); | ||
635 | spin_lock(&newdent->d_lock); | ||
636 | memcpy((char *) newdent->d_name.name, qname.name, | ||
637 | newdent->d_name.len); | ||
638 | spin_unlock(&newdent->d_lock); | ||
639 | spin_unlock(&dcache_lock); | ||
640 | if (inode) | ||
641 | mutex_unlock(&inode->i_mutex); | ||
642 | } | ||
643 | } | 631 | } |
644 | 632 | ||
645 | if (!newdent->d_inode) { | 633 | if (!newdent->d_inode) { |
@@ -649,7 +637,7 @@ ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir, | |||
649 | entry->ino = iunique(dir->i_sb, 2); | 637 | entry->ino = iunique(dir->i_sb, 2); |
650 | inode = ncp_iget(dir->i_sb, entry); | 638 | inode = ncp_iget(dir->i_sb, entry); |
651 | if (inode) { | 639 | if (inode) { |
652 | newdent->d_op = &ncp_dentry_operations; | 640 | d_set_d_op(newdent, &ncp_dentry_operations); |
653 | d_instantiate(newdent, inode); | 641 | d_instantiate(newdent, inode); |
654 | if (!hashed) | 642 | if (!hashed) |
655 | d_rehash(newdent); | 643 | d_rehash(newdent); |
@@ -657,7 +645,7 @@ ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir, | |||
657 | } else { | 645 | } else { |
658 | struct inode *inode = newdent->d_inode; | 646 | struct inode *inode = newdent->d_inode; |
659 | 647 | ||
660 | mutex_lock(&inode->i_mutex); | 648 | mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD); |
661 | ncp_update_inode2(inode, entry); | 649 | ncp_update_inode2(inode, entry); |
662 | mutex_unlock(&inode->i_mutex); | 650 | mutex_unlock(&inode->i_mutex); |
663 | } | 651 | } |
@@ -905,7 +893,7 @@ static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, struc | |||
905 | if (inode) { | 893 | if (inode) { |
906 | ncp_new_dentry(dentry); | 894 | ncp_new_dentry(dentry); |
907 | add_entry: | 895 | add_entry: |
908 | dentry->d_op = &ncp_dentry_operations; | 896 | d_set_d_op(dentry, &ncp_dentry_operations); |
909 | d_add(dentry, inode); | 897 | d_add(dentry, inode); |
910 | error = 0; | 898 | error = 0; |
911 | } | 899 | } |