aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse/dir.c
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@suse.cz>2013-09-05 05:44:42 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2013-09-05 16:23:53 -0400
commit5835f3390e35ae3da9add646a2ca2cc30b47370e (patch)
tree01bf2c9ddb37a08b4db112281b77fc1a97f7c537 /fs/fuse/dir.c
parent6497d160f6abf8d1082ff1a4efd841118cb1fddd (diff)
fuse: use d_materialise_unique()
Use d_materialise_unique() instead of d_splice_alias(). This allows dentry subtrees to be moved to a new place if there moved, even if something is referencing a dentry in the subtree (open fd, cwd, etc..). This will also allow us to drop a subtree if it is found to be replaced by something else. In this case the disconnected subtree can later be reconnected to its new location. d_materialise_unique() ensures that a directory entry only ever has one alias. We keep fc->inst_mutex around the calls for d_materialise_unique() on directories to prevent a race with mkdir "stealing" the inode. Signed-off-by: Miklos Szeredi <mszeredi@suse.cz> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/fuse/dir.c')
-rw-r--r--fs/fuse/dir.c69
1 files changed, 26 insertions, 43 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 72a5d5b04494..131d14b604ef 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -267,26 +267,6 @@ int fuse_valid_type(int m)
267 S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m); 267 S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m);
268} 268}
269 269
270/*
271 * Add a directory inode to a dentry, ensuring that no other dentry
272 * refers to this inode. Called with fc->inst_mutex.
273 */
274static struct dentry *fuse_d_add_directory(struct dentry *entry,
275 struct inode *inode)
276{
277 struct dentry *alias = d_find_alias(inode);
278 if (alias && !(alias->d_flags & DCACHE_DISCONNECTED)) {
279 /* This tries to shrink the subtree below alias */
280 fuse_invalidate_entry(alias);
281 dput(alias);
282 if (!hlist_empty(&inode->i_dentry))
283 return ERR_PTR(-EBUSY);
284 } else {
285 dput(alias);
286 }
287 return d_splice_alias(inode, entry);
288}
289
290int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name, 270int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name,
291 struct fuse_entry_out *outarg, struct inode **inode) 271 struct fuse_entry_out *outarg, struct inode **inode)
292{ 272{
@@ -345,6 +325,24 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name,
345 return err; 325 return err;
346} 326}
347 327
328static struct dentry *fuse_materialise_dentry(struct dentry *dentry,
329 struct inode *inode)
330{
331 struct dentry *newent;
332
333 if (inode && S_ISDIR(inode->i_mode)) {
334 struct fuse_conn *fc = get_fuse_conn(inode);
335
336 mutex_lock(&fc->inst_mutex);
337 newent = d_materialise_unique(dentry, inode);
338 mutex_unlock(&fc->inst_mutex);
339 } else {
340 newent = d_materialise_unique(dentry, inode);
341 }
342
343 return newent;
344}
345
348static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, 346static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
349 unsigned int flags) 347 unsigned int flags)
350{ 348{
@@ -352,7 +350,6 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
352 struct fuse_entry_out outarg; 350 struct fuse_entry_out outarg;
353 struct inode *inode; 351 struct inode *inode;
354 struct dentry *newent; 352 struct dentry *newent;
355 struct fuse_conn *fc = get_fuse_conn(dir);
356 bool outarg_valid = true; 353 bool outarg_valid = true;
357 354
358 err = fuse_lookup_name(dir->i_sb, get_node_id(dir), &entry->d_name, 355 err = fuse_lookup_name(dir->i_sb, get_node_id(dir), &entry->d_name,
@@ -368,16 +365,10 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
368 if (inode && get_node_id(inode) == FUSE_ROOT_ID) 365 if (inode && get_node_id(inode) == FUSE_ROOT_ID)
369 goto out_iput; 366 goto out_iput;
370 367
371 if (inode && S_ISDIR(inode->i_mode)) { 368 newent = fuse_materialise_dentry(entry, inode);
372 mutex_lock(&fc->inst_mutex); 369 err = PTR_ERR(newent);
373 newent = fuse_d_add_directory(entry, inode); 370 if (IS_ERR(newent))
374 mutex_unlock(&fc->inst_mutex); 371 goto out_err;
375 err = PTR_ERR(newent);
376 if (IS_ERR(newent))
377 goto out_iput;
378 } else {
379 newent = d_splice_alias(inode, entry);
380 }
381 372
382 entry = newent ? newent : entry; 373 entry = newent ? newent : entry;
383 if (outarg_valid) 374 if (outarg_valid)
@@ -1275,18 +1266,10 @@ static int fuse_direntplus_link(struct file *file,
1275 if (!inode) 1266 if (!inode)
1276 goto out; 1267 goto out;
1277 1268
1278 if (S_ISDIR(inode->i_mode)) { 1269 alias = fuse_materialise_dentry(dentry, inode);
1279 mutex_lock(&fc->inst_mutex); 1270 err = PTR_ERR(alias);
1280 alias = fuse_d_add_directory(dentry, inode); 1271 if (IS_ERR(alias))
1281 mutex_unlock(&fc->inst_mutex); 1272 goto out;
1282 err = PTR_ERR(alias);
1283 if (IS_ERR(alias)) {
1284 iput(inode);
1285 goto out;
1286 }
1287 } else {
1288 alias = d_splice_alias(inode, dentry);
1289 }
1290 1273
1291 if (alias) { 1274 if (alias) {
1292 dput(dentry); 1275 dput(dentry);