Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 55c62960 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
parents 4f3cc480 c7263bcd
Loading
Loading
Loading
Loading
+36 −15
Original line number Diff line number Diff line
@@ -1223,30 +1223,46 @@ static int fuse_direntplus_link(struct file *file,
		if (name.name[1] == '.' && name.len == 2)
			return 0;
	}

	if (invalid_nodeid(o->nodeid))
		return -EIO;
	if (!fuse_valid_type(o->attr.mode))
		return -EIO;

	fc = get_fuse_conn(dir);

	name.hash = full_name_hash(name.name, name.len);
	dentry = d_lookup(parent, &name);
	if (dentry && dentry->d_inode) {
	if (dentry) {
		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;
			fi = get_fuse_inode(inode);
			spin_lock(&fc->lock);
			fi->nlookup++;
			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()
			 * which bumps nlookup inside
			 */
			goto found;
		}
		err = d_invalidate(dentry);
		if (err)
			goto out;
		dput(dentry);
		dentry = NULL;
	}

	dentry = d_alloc(parent, &name);
@@ -1259,24 +1275,29 @@ static int fuse_direntplus_link(struct file *file,
	if (!inode)
		goto out;

	alias = d_materialise_unique(dentry, inode);
	if (S_ISDIR(inode->i_mode)) {
		mutex_lock(&fc->inst_mutex);
		alias = fuse_d_add_directory(dentry, inode);
		mutex_unlock(&fc->inst_mutex);
		err = PTR_ERR(alias);
	if (IS_ERR(alias))
		if (IS_ERR(alias)) {
			iput(inode);
			goto out;
		}
	} else {
		alias = d_splice_alias(inode, dentry);
	}

	if (alias) {
		dput(dentry);
		dentry = alias;
	}

found:
	fuse_change_attributes(inode, &o->attr, entry_attr_timeout(o),
			       attr_version);

	fuse_change_entry_timeout(dentry, o);

	err = 0;
out:
	if (dentry)
	dput(dentry);
	return err;
}