On Wed, 13 Feb 2008, Jiri Kosina wrote:

> From: Jiri Kosina <[EMAIL PROTECTED]>
> 
> loop - fix deadlock against block
> 
> A:                                      B:
>         bdev_open() for ino X
>            (locks bd_mutex for bdev Y)
>                                           lo_ioctl(LOOP_CLR_FD) for ino X
>                                             (locks lo_ctl_mutex)
>                                           fput()
>                                           __fput()
>                                           blkdev_close()
>                                             (hangs on bd_mutex for bdev Y)
>         lo_open()
>            (hangs on lo_ctl_mutex)
> 
> Fix this by letting releasing the lock inside loop_clr_fd() after the 
> loopback structure has been completely deinitialized, but before calling 
> final fput().
> 
> Signed-off-by: Jiri Kosina <[EMAIL PROTECTED]>

OK, the previous one was buggy, could you please try this one instead?

diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 91ebb00..bfb2e90 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -881,6 +881,7 @@ static int loop_clr_fd(struct loop_device *lo, struct 
block_device *bdev)
        struct file *filp = lo->lo_backing_file;
        gfp_t gfp = lo->old_gfp_mask;
 
+       mutex_lock(&lo->lo_ctl_mutex);
        if (lo->lo_state != Lo_bound)
                return -ENXIO;
 
@@ -916,6 +917,7 @@ static int loop_clr_fd(struct loop_device *lo, struct 
block_device *bdev)
        bd_set_size(bdev, 0);
        mapping_set_gfp_mask(filp->f_mapping, gfp);
        lo->lo_state = Lo_unbound;
+       mutex_unlock(&lo->lo_ctl_mutex);
        fput(filp);
        /* This is safe: open() is still holding a reference. */
        module_put(THIS_MODULE);
@@ -1143,8 +1145,11 @@ static int lo_ioctl(struct inode * inode, struct file * 
file,
                err = loop_change_fd(lo, file, inode->i_bdev, arg);
                break;
        case LOOP_CLR_FD:
+               /* loop_clr_fd must do the locking itself, so that it
+                * doesn't deadlock with bdev */
+               mutex_unlock(&lo->lo_ctl_mutex);
                err = loop_clr_fd(lo, inode->i_bdev);
-               break;
+               goto out_unlocked;
        case LOOP_SET_STATUS:
                err = loop_set_status_old(lo, (struct loop_info __user *) arg);
                break;
@@ -1161,6 +1166,7 @@ static int lo_ioctl(struct inode * inode, struct file * 
file,
                err = lo->ioctl ? lo->ioctl(lo, cmd, arg) : -EINVAL;
        }
        mutex_unlock(&lo->lo_ctl_mutex);
+out_unlocked:
        return err;
 }
 
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to