Commit 534d8695 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] loop oops fix

loop-on-file oopses during unmount.  This is because lo_queue is now freed
during lo_ioctl(LOOP_CLR_FD).  I think the scenario is:

1: umount(8) opens /dev/loop0

2: umount(8) runs lo_ioctl(LOOP_CLR_FD) (this frees the queue)

3: umount(8) closes the /dev/loop0 handle.  The blockdev layer syncs the
   blockdev, but its mapping->backing_dev_info now points into la-la-land.

We shouldn't be freeing the queue until all refs to it have gone away.  This
patch gives the queue the same lifetime as the controlling loop_device
itself.  It also makes the loop driver's queue appear in sysfs again.

It would be better to free the queue when the device is not in use, but I'm
not sure how we can hook into the blockdev layer to do that.
parent 2afe8ba3
......@@ -735,15 +735,6 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file,
lo->lo_bio = lo->lo_biotail = NULL;
lo->lo_queue = blk_alloc_queue(GFP_KERNEL);
if (!lo->lo_queue) {
error = -ENOMEM;
fput(file);
goto out_putf;
}
disks[lo->lo_number]->queue = lo->lo_queue;
/*
* set queue make_request_fn, and add limits based on lower level
* device
......@@ -857,7 +848,6 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
filp->f_dentry->d_inode->i_mapping->gfp_mask = gfp;
lo->lo_state = Lo_unbound;
fput(filp);
blk_put_queue(lo->lo_queue);
/* This is safe: open() is still holding a reference. */
module_put(THIS_MODULE);
return 0;
......@@ -1186,6 +1176,7 @@ int __init loop_init(void)
loop_dev = kmalloc(max_loop * sizeof(struct loop_device), GFP_KERNEL);
if (!loop_dev)
goto out_mem1;
memset(loop_dev, 0, max_loop * sizeof(struct loop_device));
disks = kmalloc(max_loop * sizeof(struct gendisk *), GFP_KERNEL);
if (!disks)
......@@ -1202,7 +1193,12 @@ int __init loop_init(void)
for (i = 0; i < max_loop; i++) {
struct loop_device *lo = &loop_dev[i];
struct gendisk *disk = disks[i];
memset(lo, 0, sizeof(*lo));
lo->lo_queue = blk_alloc_queue(GFP_KERNEL);
if (!lo->lo_queue)
goto out_mem4;
disks[i]->queue = lo->lo_queue;
init_MUTEX(&lo->lo_ctl_mutex);
init_MUTEX_LOCKED(&lo->lo_sem);
init_MUTEX_LOCKED(&lo->lo_bh_mutex);
......@@ -1220,6 +1216,10 @@ int __init loop_init(void)
printk(KERN_INFO "loop: loaded (max %d devices)\n", max_loop);
return 0;
out_mem4:
while (i--)
blk_put_queue(loop_dev[i].lo_queue);
i = max_loop;
out_mem3:
while (i--)
put_disk(disks[i]);
......@@ -1237,6 +1237,7 @@ void loop_exit(void)
int i;
for (i = 0; i < max_loop; i++) {
blk_put_queue(loop_dev[i].lo_queue);
del_gendisk(disks[i]);
put_disk(disks[i]);
}
......
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