aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorMichael Ellerman <michael@ellerman.id.au>2006-06-19 14:33:22 -0400
committerPaul Mackerras <paulus@samba.org>2006-06-21 01:01:30 -0400
commit0309f02d8e1b68811e513bdd06015672d0696af5 (patch)
tree81e73d666fecdf50264f86a6eda98073cb9f0494 /arch
parentd9379c4bcee7046182edf45eeab349334421416e (diff)
[POWERPC] spufs: fix deadlock in spu_create error path
spufs_rmdir tries to acquire the spufs root i_mutex, which is already held by spufs_create_thread. This was tracked as Bug #H9512. Signed-off-by: Michael Ellerman <michael@ellerman.id.au> Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/platforms/cell/spufs/inode.c26
1 files changed, 15 insertions, 11 deletions
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
index d9554199afa7..fed511a2b17f 100644
--- a/arch/powerpc/platforms/cell/spufs/inode.c
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -157,20 +157,12 @@ static void spufs_prune_dir(struct dentry *dir)
157 mutex_unlock(&dir->d_inode->i_mutex); 157 mutex_unlock(&dir->d_inode->i_mutex);
158} 158}
159 159
160/* Caller must hold root->i_mutex */
160static int spufs_rmdir(struct inode *root, struct dentry *dir_dentry) 161static int spufs_rmdir(struct inode *root, struct dentry *dir_dentry)
161{ 162{
162 struct spu_context *ctx;
163
164 /* remove all entries */ 163 /* remove all entries */
165 mutex_lock(&root->i_mutex);
166 spufs_prune_dir(dir_dentry); 164 spufs_prune_dir(dir_dentry);
167 mutex_unlock(&root->i_mutex);
168 165
169 /* We have to give up the mm_struct */
170 ctx = SPUFS_I(dir_dentry->d_inode)->i_ctx;
171 spu_forget(ctx);
172
173 /* XXX Do we need to hold i_mutex here ? */
174 return simple_rmdir(root, dir_dentry); 166 return simple_rmdir(root, dir_dentry);
175} 167}
176 168
@@ -199,16 +191,23 @@ out:
199 191
200static int spufs_dir_close(struct inode *inode, struct file *file) 192static int spufs_dir_close(struct inode *inode, struct file *file)
201{ 193{
194 struct spu_context *ctx;
202 struct inode *dir; 195 struct inode *dir;
203 struct dentry *dentry; 196 struct dentry *dentry;
204 int ret; 197 int ret;
205 198
206 dentry = file->f_dentry; 199 dentry = file->f_dentry;
207 dir = dentry->d_parent->d_inode; 200 dir = dentry->d_parent->d_inode;
201 ctx = SPUFS_I(dentry->d_inode)->i_ctx;
208 202
203 mutex_lock(&dir->i_mutex);
209 ret = spufs_rmdir(dir, dentry); 204 ret = spufs_rmdir(dir, dentry);
205 mutex_unlock(&dir->i_mutex);
210 WARN_ON(ret); 206 WARN_ON(ret);
211 207
208 /* We have to give up the mm_struct */
209 spu_forget(ctx);
210
212 return dcache_dir_close(inode, file); 211 return dcache_dir_close(inode, file);
213} 212}
214 213
@@ -324,8 +323,13 @@ long spufs_create_thread(struct nameidata *nd,
324 * in error path of *_open(). 323 * in error path of *_open().
325 */ 324 */
326 ret = spufs_context_open(dget(dentry), mntget(nd->mnt)); 325 ret = spufs_context_open(dget(dentry), mntget(nd->mnt));
327 if (ret < 0) 326 if (ret < 0) {
328 spufs_rmdir(nd->dentry->d_inode, dentry); 327 WARN_ON(spufs_rmdir(nd->dentry->d_inode, dentry));
328 mutex_unlock(&nd->dentry->d_inode->i_mutex);
329 spu_forget(SPUFS_I(dentry->d_inode)->i_ctx);
330 dput(dentry);
331 goto out;
332 }
329 333
330out_dput: 334out_dput:
331 dput(dentry); 335 dput(dentry);