@@ -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+
202221static 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,
453480out_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+
495540static 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}
0 commit comments