Skip to content

Commit e48e99b

Browse files
committed
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
2 parents 06a2236 + 00cdfdc commit e48e99b

File tree

5 files changed

+59
-10
lines changed

5 files changed

+59
-10
lines changed

arch/powerpc/platforms/cell/spufs/gang.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ struct spu_gang *alloc_spu_gang(void)
2525
mutex_init(&gang->aff_mutex);
2626
INIT_LIST_HEAD(&gang->list);
2727
INIT_LIST_HEAD(&gang->aff_list_head);
28+
gang->alive = 1;
2829

2930
out:
3031
return gang;

arch/powerpc/platforms/cell/spufs/inode.c

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -192,13 +192,32 @@ static int spufs_fill_dir(struct dentry *dir,
192192
return -ENOMEM;
193193
ret = spufs_new_file(dir->d_sb, dentry, files->ops,
194194
files->mode & mode, files->size, ctx);
195-
if (ret)
195+
if (ret) {
196+
dput(dentry);
196197
return ret;
198+
}
197199
files++;
198200
}
199201
return 0;
200202
}
201203

204+
static void unuse_gang(struct dentry *dir)
205+
{
206+
struct inode *inode = dir->d_inode;
207+
struct spu_gang *gang = SPUFS_I(inode)->i_gang;
208+
209+
if (gang) {
210+
bool dead;
211+
212+
inode_lock(inode); // exclusion with spufs_create_context()
213+
dead = !--gang->alive;
214+
inode_unlock(inode);
215+
216+
if (dead)
217+
simple_recursive_removal(dir, NULL);
218+
}
219+
}
220+
202221
static int spufs_dir_close(struct inode *inode, struct file *file)
203222
{
204223
struct inode *parent;
@@ -213,6 +232,7 @@ static int spufs_dir_close(struct inode *inode, struct file *file)
213232
inode_unlock(parent);
214233
WARN_ON(ret);
215234

235+
unuse_gang(dir->d_parent);
216236
return dcache_dir_close(inode, file);
217237
}
218238

@@ -405,7 +425,7 @@ spufs_create_context(struct inode *inode, struct dentry *dentry,
405425
{
406426
int ret;
407427
int affinity;
408-
struct spu_gang *gang;
428+
struct spu_gang *gang = SPUFS_I(inode)->i_gang;
409429
struct spu_context *neighbor;
410430
struct path path = {.mnt = mnt, .dentry = dentry};
411431

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

423-
gang = NULL;
443+
if (gang) {
444+
if (!gang->alive)
445+
return -ENOENT;
446+
gang->alive++;
447+
}
448+
424449
neighbor = NULL;
425450
affinity = flags & (SPU_CREATE_AFFINITY_MEM | SPU_CREATE_AFFINITY_SPU);
426451
if (affinity) {
427-
gang = SPUFS_I(inode)->i_gang;
428452
if (!gang)
429453
return -EINVAL;
430454
mutex_lock(&gang->aff_mutex);
@@ -436,8 +460,11 @@ spufs_create_context(struct inode *inode, struct dentry *dentry,
436460
}
437461

438462
ret = spufs_mkdir(inode, dentry, flags, mode & 0777);
439-
if (ret)
463+
if (ret) {
464+
if (neighbor)
465+
put_spu_context(neighbor);
440466
goto out_aff_unlock;
467+
}
441468

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

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

484513
d_instantiate(dentry, inode);
514+
dget(dentry);
485515
inc_nlink(dir);
486516
inc_nlink(d_inode(dentry));
487517
return ret;
@@ -492,6 +522,21 @@ spufs_mkgang(struct inode *dir, struct dentry *dentry, umode_t mode)
492522
return ret;
493523
}
494524

525+
static int spufs_gang_close(struct inode *inode, struct file *file)
526+
{
527+
unuse_gang(file->f_path.dentry);
528+
return dcache_dir_close(inode, file);
529+
}
530+
531+
static const struct file_operations spufs_gang_fops = {
532+
.open = dcache_dir_open,
533+
.release = spufs_gang_close,
534+
.llseek = dcache_dir_lseek,
535+
.read = generic_read_dir,
536+
.iterate_shared = dcache_readdir,
537+
.fsync = noop_fsync,
538+
};
539+
495540
static int spufs_gang_open(const struct path *path)
496541
{
497542
int ret;
@@ -511,7 +556,7 @@ static int spufs_gang_open(const struct path *path)
511556
return PTR_ERR(filp);
512557
}
513558

514-
filp->f_op = &simple_dir_operations;
559+
filp->f_op = &spufs_gang_fops;
515560
fd_install(ret, filp);
516561
return ret;
517562
}
@@ -526,10 +571,8 @@ static int spufs_create_gang(struct inode *inode,
526571
ret = spufs_mkgang(inode, dentry, mode & 0777);
527572
if (!ret) {
528573
ret = spufs_gang_open(&path);
529-
if (ret < 0) {
530-
int err = simple_rmdir(inode, dentry);
531-
WARN_ON(err);
532-
}
574+
if (ret < 0)
575+
unuse_gang(dentry);
533576
}
534577
return ret;
535578
}

arch/powerpc/platforms/cell/spufs/spufs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ struct spu_gang {
151151
int aff_flags;
152152
struct spu *aff_ref_spu;
153153
atomic_t aff_sched_count;
154+
155+
int alive;
154156
};
155157

156158
/* Flag bits for spu_gang aff_flags */

arch/s390/hypfs/hypfs_diag_fs.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,8 @@ static int hypfs_create_cpu_files(struct dentry *cpus_dir, void *cpu_info)
209209
snprintf(buffer, TMP_SIZE, "%d", cpu_info__cpu_addr(diag204_get_info_type(),
210210
cpu_info));
211211
cpu_dir = hypfs_mkdir(cpus_dir, buffer);
212+
if (IS_ERR(cpu_dir))
213+
return PTR_ERR(cpu_dir);
212214
rc = hypfs_create_u64(cpu_dir, "mgmtime",
213215
cpu_info__acc_time(diag204_get_info_type(), cpu_info) -
214216
cpu_info__lp_time(diag204_get_info_type(), cpu_info));

drivers/infiniband/hw/qib/qib_fs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ static int qibfs_mknod(struct inode *dir, struct dentry *dentry,
5555
struct inode *inode = new_inode(dir->i_sb);
5656

5757
if (!inode) {
58+
dput(dentry);
5859
error = -EPERM;
5960
goto bail;
6061
}

0 commit comments

Comments
 (0)