Commit e48e99b6 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull dcache fixes from Al Viro:
 "Fixes for bugs caught as part of tree-in-dcache work.

  Mostly dentry refcount mishandling"

* tag 'pull-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  hypfs_create_cpu_files(): add missing check for hypfs_mkdir() failure
  qibfs: fix _another_ leak
  spufs: fix a leak in spufs_create_context()
  spufs: fix gang directory lifetimes
  spufs: fix a leak on spufs_new_file() failure
parents 06a22366 00cdfdcf
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ struct spu_gang *alloc_spu_gang(void)
	mutex_init(&gang->aff_mutex);
	INIT_LIST_HEAD(&gang->list);
	INIT_LIST_HEAD(&gang->aff_list_head);
	gang->alive = 1;

out:
	return gang;
+53 −10
Original line number Diff line number Diff line
@@ -192,13 +192,32 @@ static int spufs_fill_dir(struct dentry *dir,
			return -ENOMEM;
		ret = spufs_new_file(dir->d_sb, dentry, files->ops,
					files->mode & mode, files->size, ctx);
		if (ret)
		if (ret) {
			dput(dentry);
			return ret;
		}
		files++;
	}
	return 0;
}

static void unuse_gang(struct dentry *dir)
{
	struct inode *inode = dir->d_inode;
	struct spu_gang *gang = SPUFS_I(inode)->i_gang;

	if (gang) {
		bool dead;

		inode_lock(inode); // exclusion with spufs_create_context()
		dead = !--gang->alive;
		inode_unlock(inode);

		if (dead)
			simple_recursive_removal(dir, NULL);
	}
}

static int spufs_dir_close(struct inode *inode, struct file *file)
{
	struct inode *parent;
@@ -213,6 +232,7 @@ static int spufs_dir_close(struct inode *inode, struct file *file)
	inode_unlock(parent);
	WARN_ON(ret);

	unuse_gang(dir->d_parent);
	return dcache_dir_close(inode, file);
}

@@ -405,7 +425,7 @@ spufs_create_context(struct inode *inode, struct dentry *dentry,
{
	int ret;
	int affinity;
	struct spu_gang *gang;
	struct spu_gang *gang = SPUFS_I(inode)->i_gang;
	struct spu_context *neighbor;
	struct path path = {.mnt = mnt, .dentry = dentry};

@@ -420,11 +440,15 @@ spufs_create_context(struct inode *inode, struct dentry *dentry,
	if ((flags & SPU_CREATE_ISOLATE) && !isolated_loader)
		return -ENODEV;

	gang = NULL;
	if (gang) {
		if (!gang->alive)
			return -ENOENT;
		gang->alive++;
	}

	neighbor = NULL;
	affinity = flags & (SPU_CREATE_AFFINITY_MEM | SPU_CREATE_AFFINITY_SPU);
	if (affinity) {
		gang = SPUFS_I(inode)->i_gang;
		if (!gang)
			return -EINVAL;
		mutex_lock(&gang->aff_mutex);
@@ -436,8 +460,11 @@ spufs_create_context(struct inode *inode, struct dentry *dentry,
	}

	ret = spufs_mkdir(inode, dentry, flags, mode & 0777);
	if (ret)
	if (ret) {
		if (neighbor)
			put_spu_context(neighbor);
		goto out_aff_unlock;
	}

	if (affinity) {
		spufs_set_affinity(flags, SPUFS_I(d_inode(dentry))->i_ctx,
@@ -453,6 +480,8 @@ spufs_create_context(struct inode *inode, struct dentry *dentry,
out_aff_unlock:
	if (affinity)
		mutex_unlock(&gang->aff_mutex);
	if (ret && gang)
		gang->alive--; // can't reach 0
	return ret;
}

@@ -482,6 +511,7 @@ spufs_mkgang(struct inode *dir, struct dentry *dentry, umode_t mode)
	inode->i_fop = &simple_dir_operations;

	d_instantiate(dentry, inode);
	dget(dentry);
	inc_nlink(dir);
	inc_nlink(d_inode(dentry));
	return ret;
@@ -492,6 +522,21 @@ spufs_mkgang(struct inode *dir, struct dentry *dentry, umode_t mode)
	return ret;
}

static int spufs_gang_close(struct inode *inode, struct file *file)
{
	unuse_gang(file->f_path.dentry);
	return dcache_dir_close(inode, file);
}

static const struct file_operations spufs_gang_fops = {
	.open		= dcache_dir_open,
	.release	= spufs_gang_close,
	.llseek		= dcache_dir_lseek,
	.read		= generic_read_dir,
	.iterate_shared	= dcache_readdir,
	.fsync		= noop_fsync,
};

static int spufs_gang_open(const struct path *path)
{
	int ret;
@@ -511,7 +556,7 @@ static int spufs_gang_open(const struct path *path)
		return PTR_ERR(filp);
	}

	filp->f_op = &simple_dir_operations;
	filp->f_op = &spufs_gang_fops;
	fd_install(ret, filp);
	return ret;
}
@@ -526,10 +571,8 @@ static int spufs_create_gang(struct inode *inode,
	ret = spufs_mkgang(inode, dentry, mode & 0777);
	if (!ret) {
		ret = spufs_gang_open(&path);
		if (ret < 0) {
			int err = simple_rmdir(inode, dentry);
			WARN_ON(err);
		}
		if (ret < 0)
			unuse_gang(dentry);
	}
	return ret;
}
+2 −0
Original line number Diff line number Diff line
@@ -151,6 +151,8 @@ struct spu_gang {
	int aff_flags;
	struct spu *aff_ref_spu;
	atomic_t aff_sched_count;

	int alive;
};

/* Flag bits for spu_gang aff_flags */
+2 −0
Original line number Diff line number Diff line
@@ -209,6 +209,8 @@ static int hypfs_create_cpu_files(struct dentry *cpus_dir, void *cpu_info)
	snprintf(buffer, TMP_SIZE, "%d", cpu_info__cpu_addr(diag204_get_info_type(),
							    cpu_info));
	cpu_dir = hypfs_mkdir(cpus_dir, buffer);
	if (IS_ERR(cpu_dir))
		return PTR_ERR(cpu_dir);
	rc = hypfs_create_u64(cpu_dir, "mgmtime",
			      cpu_info__acc_time(diag204_get_info_type(), cpu_info) -
			      cpu_info__lp_time(diag204_get_info_type(), cpu_info));
+1 −0
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ static int qibfs_mknod(struct inode *dir, struct dentry *dentry,
	struct inode *inode = new_inode(dir->i_sb);

	if (!inode) {
		dput(dentry);
		error = -EPERM;
		goto bail;
	}