Commit 960d4b34 authored by Hugh Dickins's avatar Hugh Dickins Committed by Linus Torvalds

[PATCH] shm_destroy lock hang

Martin Schwidefsky <schwidefsky@de.ibm.com> reported "Bug with shared
memory" to LKML 14 May: hang due to schedule in truncate_list_pages
called from .... shm_destroy holding shm_lock spinlock.  shm_destroy
needs that lock for shm_rmid, but it can be safely unlocked once link
from id to shp has been removed.
parent 7e9b34ab
...@@ -105,12 +105,14 @@ static void shm_open (struct vm_area_struct *shmd) ...@@ -105,12 +105,14 @@ static void shm_open (struct vm_area_struct *shmd)
* *
* @shp: struct to free * @shp: struct to free
* *
* It has to be called with shp and shm_ids.sem locked * It has to be called with shp and shm_ids.sem locked,
* but returns with shp unlocked and freed.
*/ */
static void shm_destroy (struct shmid_kernel *shp) static void shm_destroy (struct shmid_kernel *shp)
{ {
shm_tot -= (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT; shm_tot -= (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT;
shm_rmid (shp->id); shm_rmid (shp->id);
shm_unlock(shp->id);
shmem_lock(shp->shm_file, 0); shmem_lock(shp->shm_file, 0);
fput (shp->shm_file); fput (shp->shm_file);
kfree (shp); kfree (shp);
...@@ -138,8 +140,8 @@ static void shm_close (struct vm_area_struct *shmd) ...@@ -138,8 +140,8 @@ static void shm_close (struct vm_area_struct *shmd)
if(shp->shm_nattch == 0 && if(shp->shm_nattch == 0 &&
shp->shm_flags & SHM_DEST) shp->shm_flags & SHM_DEST)
shm_destroy (shp); shm_destroy (shp);
else
shm_unlock(id); shm_unlock(id);
up (&shm_ids.sem); up (&shm_ids.sem);
} }
...@@ -502,11 +504,9 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf) ...@@ -502,11 +504,9 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
shp->shm_flags |= SHM_DEST; shp->shm_flags |= SHM_DEST;
/* Do not find it any more */ /* Do not find it any more */
shp->shm_perm.key = IPC_PRIVATE; shp->shm_perm.key = IPC_PRIVATE;
shm_unlock(shmid);
} else } else
shm_destroy (shp); shm_destroy (shp);
/* Unlock */
shm_unlock(shmid);
up(&shm_ids.sem); up(&shm_ids.sem);
return err; return err;
} }
...@@ -644,7 +644,8 @@ asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr) ...@@ -644,7 +644,8 @@ asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
if(shp->shm_nattch == 0 && if(shp->shm_nattch == 0 &&
shp->shm_flags & SHM_DEST) shp->shm_flags & SHM_DEST)
shm_destroy (shp); shm_destroy (shp);
shm_unlock(shmid); else
shm_unlock(shmid);
up (&shm_ids.sem); up (&shm_ids.sem);
*raddr = (unsigned long) user_addr; *raddr = (unsigned long) user_addr;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment