diff options
Diffstat (limited to 'fs/ncpfs')
-rw-r--r-- | fs/ncpfs/dir.c | 88 | ||||
-rw-r--r-- | fs/ncpfs/inode.c | 12 | ||||
-rw-r--r-- | fs/ncpfs/ncplib_kernel.h | 16 |
3 files changed, 56 insertions, 60 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 | } |
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index 31532330d016..9b39a5dd4131 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/vfs.h> | 29 | #include <linux/vfs.h> |
30 | #include <linux/mount.h> | 30 | #include <linux/mount.h> |
31 | #include <linux/seq_file.h> | 31 | #include <linux/seq_file.h> |
32 | #include <linux/namei.h> | ||
32 | 33 | ||
33 | #include <linux/ncp_fs.h> | 34 | #include <linux/ncp_fs.h> |
34 | 35 | ||
@@ -58,11 +59,18 @@ static struct inode *ncp_alloc_inode(struct super_block *sb) | |||
58 | return &ei->vfs_inode; | 59 | return &ei->vfs_inode; |
59 | } | 60 | } |
60 | 61 | ||
61 | static void ncp_destroy_inode(struct inode *inode) | 62 | static void ncp_i_callback(struct rcu_head *head) |
62 | { | 63 | { |
64 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
65 | INIT_LIST_HEAD(&inode->i_dentry); | ||
63 | kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode)); | 66 | kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode)); |
64 | } | 67 | } |
65 | 68 | ||
69 | static void ncp_destroy_inode(struct inode *inode) | ||
70 | { | ||
71 | call_rcu(&inode->i_rcu, ncp_i_callback); | ||
72 | } | ||
73 | |||
66 | static void init_once(void *foo) | 74 | static void init_once(void *foo) |
67 | { | 75 | { |
68 | struct ncp_inode_info *ei = (struct ncp_inode_info *) foo; | 76 | struct ncp_inode_info *ei = (struct ncp_inode_info *) foo; |
@@ -715,7 +723,7 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent) | |||
715 | sb->s_root = d_alloc_root(root_inode); | 723 | sb->s_root = d_alloc_root(root_inode); |
716 | if (!sb->s_root) | 724 | if (!sb->s_root) |
717 | goto out_no_root; | 725 | goto out_no_root; |
718 | sb->s_root->d_op = &ncp_root_dentry_operations; | 726 | d_set_d_op(sb->s_root, &ncp_root_dentry_operations); |
719 | return 0; | 727 | return 0; |
720 | 728 | ||
721 | out_no_root: | 729 | out_no_root: |
diff --git a/fs/ncpfs/ncplib_kernel.h b/fs/ncpfs/ncplib_kernel.h index 3c57eca634ce..1220df75ff22 100644 --- a/fs/ncpfs/ncplib_kernel.h +++ b/fs/ncpfs/ncplib_kernel.h | |||
@@ -135,7 +135,7 @@ int ncp__vol2io(struct ncp_server *, unsigned char *, unsigned int *, | |||
135 | const unsigned char *, unsigned int, int); | 135 | const unsigned char *, unsigned int, int); |
136 | 136 | ||
137 | #define NCP_ESC ':' | 137 | #define NCP_ESC ':' |
138 | #define NCP_IO_TABLE(dentry) (NCP_SERVER((dentry)->d_inode)->nls_io) | 138 | #define NCP_IO_TABLE(sb) (NCP_SBP(sb)->nls_io) |
139 | #define ncp_tolower(t, c) nls_tolower(t, c) | 139 | #define ncp_tolower(t, c) nls_tolower(t, c) |
140 | #define ncp_toupper(t, c) nls_toupper(t, c) | 140 | #define ncp_toupper(t, c) nls_toupper(t, c) |
141 | #define ncp_strnicmp(t, s1, s2, len) \ | 141 | #define ncp_strnicmp(t, s1, s2, len) \ |
@@ -150,15 +150,15 @@ int ncp__io2vol(unsigned char *, unsigned int *, | |||
150 | int ncp__vol2io(unsigned char *, unsigned int *, | 150 | int ncp__vol2io(unsigned char *, unsigned int *, |
151 | const unsigned char *, unsigned int, int); | 151 | const unsigned char *, unsigned int, int); |
152 | 152 | ||
153 | #define NCP_IO_TABLE(dentry) NULL | 153 | #define NCP_IO_TABLE(sb) NULL |
154 | #define ncp_tolower(t, c) tolower(c) | 154 | #define ncp_tolower(t, c) tolower(c) |
155 | #define ncp_toupper(t, c) toupper(c) | 155 | #define ncp_toupper(t, c) toupper(c) |
156 | #define ncp_io2vol(S,m,i,n,k,U) ncp__io2vol(m,i,n,k,U) | 156 | #define ncp_io2vol(S,m,i,n,k,U) ncp__io2vol(m,i,n,k,U) |
157 | #define ncp_vol2io(S,m,i,n,k,U) ncp__vol2io(m,i,n,k,U) | 157 | #define ncp_vol2io(S,m,i,n,k,U) ncp__vol2io(m,i,n,k,U) |
158 | 158 | ||
159 | 159 | ||
160 | static inline int ncp_strnicmp(struct nls_table *t, const unsigned char *s1, | 160 | static inline int ncp_strnicmp(const struct nls_table *t, |
161 | const unsigned char *s2, int len) | 161 | const unsigned char *s1, const unsigned char *s2, int len) |
162 | { | 162 | { |
163 | while (len--) { | 163 | while (len--) { |
164 | if (tolower(*s1++) != tolower(*s2++)) | 164 | if (tolower(*s1++) != tolower(*s2++)) |
@@ -193,7 +193,7 @@ ncp_renew_dentries(struct dentry *parent) | |||
193 | struct list_head *next; | 193 | struct list_head *next; |
194 | struct dentry *dentry; | 194 | struct dentry *dentry; |
195 | 195 | ||
196 | spin_lock(&dcache_lock); | 196 | spin_lock(&parent->d_lock); |
197 | next = parent->d_subdirs.next; | 197 | next = parent->d_subdirs.next; |
198 | while (next != &parent->d_subdirs) { | 198 | while (next != &parent->d_subdirs) { |
199 | dentry = list_entry(next, struct dentry, d_u.d_child); | 199 | dentry = list_entry(next, struct dentry, d_u.d_child); |
@@ -205,7 +205,7 @@ ncp_renew_dentries(struct dentry *parent) | |||
205 | 205 | ||
206 | next = next->next; | 206 | next = next->next; |
207 | } | 207 | } |
208 | spin_unlock(&dcache_lock); | 208 | spin_unlock(&parent->d_lock); |
209 | } | 209 | } |
210 | 210 | ||
211 | static inline void | 211 | static inline void |
@@ -215,7 +215,7 @@ ncp_invalidate_dircache_entries(struct dentry *parent) | |||
215 | struct list_head *next; | 215 | struct list_head *next; |
216 | struct dentry *dentry; | 216 | struct dentry *dentry; |
217 | 217 | ||
218 | spin_lock(&dcache_lock); | 218 | spin_lock(&parent->d_lock); |
219 | next = parent->d_subdirs.next; | 219 | next = parent->d_subdirs.next; |
220 | while (next != &parent->d_subdirs) { | 220 | while (next != &parent->d_subdirs) { |
221 | dentry = list_entry(next, struct dentry, d_u.d_child); | 221 | dentry = list_entry(next, struct dentry, d_u.d_child); |
@@ -223,7 +223,7 @@ ncp_invalidate_dircache_entries(struct dentry *parent) | |||
223 | ncp_age_dentry(server, dentry); | 223 | ncp_age_dentry(server, dentry); |
224 | next = next->next; | 224 | next = next->next; |
225 | } | 225 | } |
226 | spin_unlock(&dcache_lock); | 226 | spin_unlock(&parent->d_lock); |
227 | } | 227 | } |
228 | 228 | ||
229 | struct ncp_cache_head { | 229 | struct ncp_cache_head { |