diff options
| -rw-r--r-- | fs/fuse/dir.c | 24 |
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 | */ |
| 242 | static int fuse_d_add_directory(struct dentry *entry, struct inode *inode) | 242 | static 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 | ||
| 256 | static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | 258 | static 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 | /* |
