diff options
Diffstat (limited to 'fs/ncpfs/dir.c')
-rw-r--r-- | fs/ncpfs/dir.c | 45 |
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 | */ |
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 | ||
@@ -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 | ||