mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/
synced 2025-04-19 20:58:31 +09:00
fixes for bugs caught as part of tree-in-dcache work
mostly dentry refcount mishandling Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> -----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQQqUNBr3gm4hGXdBJlZ7Krx/gZQ6wUCZ+3eRQAKCRBZ7Krx/gZQ 6/FlAP9uekG4L7IyvXBitM7fp/SU+YwiPJy3r/1gLLhEGAL6IwEAu+RfXVD9KY7+ yrsQi2i37uuUEit9KymVFUGeTJvAaQQ= =hjki -----END PGP SIGNATURE----- Merge tag 'pull-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs 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
This commit is contained in:
commit
e48e99b6ed
@ -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;
|
||||
|
@ -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 @@ out:
|
||||
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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user