Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse

Pull fuse bugfixes from Miklos Szeredi:
 "These are bugfixes and a cleanup to the "readdirplus" feature"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse:
  fuse: readdirplus: cleanup
  fuse: readdirplus: change attributes once
  fuse: readdirplus: fix instantiate
  fuse: readdirplus: sanity checks
  fuse: readdirplus: fix dentry leak
This commit is contained in:
Linus Torvalds 2013-07-23 14:37:04 -07:00
commit 55c62960b0

View File

@ -1223,30 +1223,46 @@ static int fuse_direntplus_link(struct file *file,
if (name.name[1] == '.' && name.len == 2) if (name.name[1] == '.' && name.len == 2)
return 0; return 0;
} }
if (invalid_nodeid(o->nodeid))
return -EIO;
if (!fuse_valid_type(o->attr.mode))
return -EIO;
fc = get_fuse_conn(dir); fc = get_fuse_conn(dir);
name.hash = full_name_hash(name.name, name.len); name.hash = full_name_hash(name.name, name.len);
dentry = d_lookup(parent, &name); dentry = d_lookup(parent, &name);
if (dentry && dentry->d_inode) { if (dentry) {
inode = dentry->d_inode; inode = dentry->d_inode;
if (get_node_id(inode) == o->nodeid) { if (!inode) {
d_drop(dentry);
} else if (get_node_id(inode) != o->nodeid ||
((o->attr.mode ^ inode->i_mode) & S_IFMT)) {
err = d_invalidate(dentry);
if (err)
goto out;
} else if (is_bad_inode(inode)) {
err = -EIO;
goto out;
} else {
struct fuse_inode *fi; struct fuse_inode *fi;
fi = get_fuse_inode(inode); fi = get_fuse_inode(inode);
spin_lock(&fc->lock); spin_lock(&fc->lock);
fi->nlookup++; fi->nlookup++;
spin_unlock(&fc->lock); spin_unlock(&fc->lock);
fuse_change_attributes(inode, &o->attr,
entry_attr_timeout(o),
attr_version);
/* /*
* The other branch to 'found' comes via fuse_iget() * The other branch to 'found' comes via fuse_iget()
* which bumps nlookup inside * which bumps nlookup inside
*/ */
goto found; goto found;
} }
err = d_invalidate(dentry);
if (err)
goto out;
dput(dentry); dput(dentry);
dentry = NULL;
} }
dentry = d_alloc(parent, &name); dentry = d_alloc(parent, &name);
@ -1259,25 +1275,30 @@ static int fuse_direntplus_link(struct file *file,
if (!inode) if (!inode)
goto out; goto out;
alias = d_materialise_unique(dentry, inode); if (S_ISDIR(inode->i_mode)) {
err = PTR_ERR(alias); mutex_lock(&fc->inst_mutex);
if (IS_ERR(alias)) alias = fuse_d_add_directory(dentry, inode);
goto out; mutex_unlock(&fc->inst_mutex);
err = PTR_ERR(alias);
if (IS_ERR(alias)) {
iput(inode);
goto out;
}
} else {
alias = d_splice_alias(inode, dentry);
}
if (alias) { if (alias) {
dput(dentry); dput(dentry);
dentry = alias; dentry = alias;
} }
found: found:
fuse_change_attributes(inode, &o->attr, entry_attr_timeout(o),
attr_version);
fuse_change_entry_timeout(dentry, o); fuse_change_entry_timeout(dentry, o);
err = 0; err = 0;
out: out:
if (dentry) dput(dentry);
dput(dentry);
return err; return err;
} }