Skip to content

Commit

Permalink
Merge tag 'pull-fixes' of git://git.kernel.org/pub/scm/linux/kernel/g…
Browse files Browse the repository at this point in the history
…it/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
  • Loading branch information
Linus Torvalds committed Apr 4, 2025
2 parents 06a2236 + 00cdfdc commit e48e99b
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 10 deletions.
1 change: 1 addition & 0 deletions arch/powerpc/platforms/cell/spufs/gang.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
63 changes: 53 additions & 10 deletions arch/powerpc/platforms/cell/spufs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
}

Expand Down Expand Up @@ -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};

Expand All @@ -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);
Expand All @@ -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,
Expand All @@ -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;
}

Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;
}
Expand All @@ -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;
}
Expand Down
2 changes: 2 additions & 0 deletions arch/powerpc/platforms/cell/spufs/spufs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
2 changes: 2 additions & 0 deletions arch/s390/hypfs/hypfs_diag_fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
1 change: 1 addition & 0 deletions drivers/infiniband/hw/qib/qib_fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down

0 comments on commit e48e99b

Please sign in to comment.