kill d_instantiate_no_diralias()
The only user is fuse_create_new_entry(), and there it's used to mitigate the same mkdir/open-by-handle race as in nfs_mkdir(). The same solution applies - unhash the mkdir argument, then call d_splice_alias() and if that returns a reference to preexisting alias, dput() and report success. ->mkdir() argument left unhashed negative with the preexisting alias moved in the right place is just fine from the ->mkdir() callers point of view. Cc: Miklos Szeredi <miklos@szeredi.hu> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
b0c6108ecf
commit
c971e6a006
27
fs/dcache.c
27
fs/dcache.c
|
@ -1899,33 +1899,6 @@ void d_instantiate_new(struct dentry *entry, struct inode *inode)
|
|||
}
|
||||
EXPORT_SYMBOL(d_instantiate_new);
|
||||
|
||||
/**
|
||||
* d_instantiate_no_diralias - instantiate a non-aliased dentry
|
||||
* @entry: dentry to complete
|
||||
* @inode: inode to attach to this dentry
|
||||
*
|
||||
* Fill in inode information in the entry. If a directory alias is found, then
|
||||
* return an error (and drop inode). Together with d_materialise_unique() this
|
||||
* guarantees that a directory inode may never have more than one alias.
|
||||
*/
|
||||
int d_instantiate_no_diralias(struct dentry *entry, struct inode *inode)
|
||||
{
|
||||
BUG_ON(!hlist_unhashed(&entry->d_u.d_alias));
|
||||
|
||||
security_d_instantiate(entry, inode);
|
||||
spin_lock(&inode->i_lock);
|
||||
if (S_ISDIR(inode->i_mode) && !hlist_empty(&inode->i_dentry)) {
|
||||
spin_unlock(&inode->i_lock);
|
||||
iput(inode);
|
||||
return -EBUSY;
|
||||
}
|
||||
__d_instantiate(entry, inode);
|
||||
spin_unlock(&inode->i_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(d_instantiate_no_diralias);
|
||||
|
||||
struct dentry *d_make_root(struct inode *root_inode)
|
||||
{
|
||||
struct dentry *res = NULL;
|
||||
|
|
|
@ -539,6 +539,7 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_args *args,
|
|||
{
|
||||
struct fuse_entry_out outarg;
|
||||
struct inode *inode;
|
||||
struct dentry *d;
|
||||
int err;
|
||||
struct fuse_forget_link *forget;
|
||||
|
||||
|
@ -570,11 +571,17 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_args *args,
|
|||
}
|
||||
kfree(forget);
|
||||
|
||||
err = d_instantiate_no_diralias(entry, inode);
|
||||
if (err)
|
||||
return err;
|
||||
d_drop(entry);
|
||||
d = d_splice_alias(inode, entry);
|
||||
if (IS_ERR(d))
|
||||
return PTR_ERR(d);
|
||||
|
||||
fuse_change_entry_timeout(entry, &outarg);
|
||||
if (d) {
|
||||
fuse_change_entry_timeout(d, &outarg);
|
||||
dput(d);
|
||||
} else {
|
||||
fuse_change_entry_timeout(entry, &outarg);
|
||||
}
|
||||
fuse_invalidate_attr(dir);
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -227,7 +227,6 @@ extern void d_instantiate(struct dentry *, struct inode *);
|
|||
extern void d_instantiate_new(struct dentry *, struct inode *);
|
||||
extern struct dentry * d_instantiate_unique(struct dentry *, struct inode *);
|
||||
extern struct dentry * d_instantiate_anon(struct dentry *, struct inode *);
|
||||
extern int d_instantiate_no_diralias(struct dentry *, struct inode *);
|
||||
extern void __d_drop(struct dentry *dentry);
|
||||
extern void d_drop(struct dentry *dentry);
|
||||
extern void d_delete(struct dentry *);
|
||||
|
|
Loading…
Reference in New Issue