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.c45
1 files changed, 24 insertions, 21 deletions
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index 0e7f00298213..3be047474bfc 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -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
@@ -660,8 +676,6 @@ end_advance:
660 ctl.valid = 0; 676 ctl.valid = 0;
661 if (!ctl.filled && (ctl.fpos == ctx->pos)) { 677 if (!ctl.filled && (ctl.fpos == ctx->pos)) {
662 if (!ino) 678 if (!ino)
663 ino = find_inode_number(dentry, &qname);
664 if (!ino)
665 ino = iunique(dir->i_sb, 2); 679 ino = iunique(dir->i_sb, 2);
666 ctl.filled = !dir_emit(ctx, qname.name, qname.len, 680 ctl.filled = !dir_emit(ctx, qname.name, qname.len,
667 ino, DT_UNKNOWN); 681 ino, DT_UNKNOWN);
@@ -1123,17 +1137,6 @@ static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
1123 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,
1124 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);
1125 1139
1126 if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode)) {
1127 /*
1128 * fail with EBUSY if there are still references to this
1129 * directory.
1130 */
1131 dentry_unhash(new_dentry);
1132 error = -EBUSY;
1133 if (!d_unhashed(new_dentry))
1134 goto out;
1135 }
1136
1137 ncp_age_dentry(server, old_dentry); 1140 ncp_age_dentry(server, old_dentry);
1138 ncp_age_dentry(server, new_dentry); 1141 ncp_age_dentry(server, new_dentry);
1139 1142