aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/fuse/dir.c24
1 files changed, 14 insertions, 10 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 2060bf06b906..e5217b213b44 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -239,18 +239,20 @@ int fuse_valid_type(int m)
239 * Add a directory inode to a dentry, ensuring that no other dentry 239 * Add a directory inode to a dentry, ensuring that no other dentry
240 * refers to this inode. Called with fc->inst_mutex. 240 * refers to this inode. Called with fc->inst_mutex.
241 */ 241 */
242static int fuse_d_add_directory(struct dentry *entry, struct inode *inode) 242static struct dentry *fuse_d_add_directory(struct dentry *entry,
243 struct inode *inode)
243{ 244{
244 struct dentry *alias = d_find_alias(inode); 245 struct dentry *alias = d_find_alias(inode);
245 if (alias) { 246 if (alias && !(alias->d_flags & DCACHE_DISCONNECTED)) {
246 /* This tries to shrink the subtree below alias */ 247 /* This tries to shrink the subtree below alias */
247 fuse_invalidate_entry(alias); 248 fuse_invalidate_entry(alias);
248 dput(alias); 249 dput(alias);
249 if (!list_empty(&inode->i_dentry)) 250 if (!list_empty(&inode->i_dentry))
250 return -EBUSY; 251 return ERR_PTR(-EBUSY);
252 } else {
253 dput(alias);
251 } 254 }
252 d_add(entry, inode); 255 return d_splice_alias(inode, entry);
253 return 0;
254} 256}
255 257
256static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, 258static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
@@ -259,6 +261,7 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
259 int err; 261 int err;
260 struct fuse_entry_out outarg; 262 struct fuse_entry_out outarg;
261 struct inode *inode = NULL; 263 struct inode *inode = NULL;
264 struct dentry *newent;
262 struct fuse_conn *fc = get_fuse_conn(dir); 265 struct fuse_conn *fc = get_fuse_conn(dir);
263 struct fuse_req *req; 266 struct fuse_req *req;
264 struct fuse_req *forget_req; 267 struct fuse_req *forget_req;
@@ -303,21 +306,22 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
303 306
304 if (inode && S_ISDIR(inode->i_mode)) { 307 if (inode && S_ISDIR(inode->i_mode)) {
305 mutex_lock(&fc->inst_mutex); 308 mutex_lock(&fc->inst_mutex);
306 err = fuse_d_add_directory(entry, inode); 309 newent = fuse_d_add_directory(entry, inode);
307 mutex_unlock(&fc->inst_mutex); 310 mutex_unlock(&fc->inst_mutex);
308 if (err) { 311 if (IS_ERR(newent)) {
309 iput(inode); 312 iput(inode);
310 return ERR_PTR(err); 313 return newent;
311 } 314 }
312 } else 315 } else
313 d_add(entry, inode); 316 newent = d_splice_alias(inode, entry);
314 317
318 entry = newent ? newent : entry;
315 entry->d_op = &fuse_dentry_operations; 319 entry->d_op = &fuse_dentry_operations;
316 if (!err) 320 if (!err)
317 fuse_change_entry_timeout(entry, &outarg); 321 fuse_change_entry_timeout(entry, &outarg);
318 else 322 else
319 fuse_invalidate_entry_cache(entry); 323 fuse_invalidate_entry_cache(entry);
320 return NULL; 324 return newent;
321} 325}
322 326
323/* 327/*