diff options
author | Michael Ellerman <michael@ellerman.id.au> | 2006-06-19 14:33:22 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2006-06-21 01:01:30 -0400 |
commit | 0309f02d8e1b68811e513bdd06015672d0696af5 (patch) | |
tree | 81e73d666fecdf50264f86a6eda98073cb9f0494 /arch | |
parent | d9379c4bcee7046182edf45eeab349334421416e (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.c | 26 |
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 */ | ||
160 | static int spufs_rmdir(struct inode *root, struct dentry *dir_dentry) | 161 | static 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 | ||
200 | static int spufs_dir_close(struct inode *inode, struct file *file) | 192 | static 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 | ||
330 | out_dput: | 334 | out_dput: |
331 | dput(dentry); | 335 | dput(dentry); |