]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - drivers/block/loop.c
loopdev: update block device size in loop_set_status()
[mirror_ubuntu-bionic-kernel.git] / drivers / block / loop.c
index 54046e51160aef28e3ee733797fa453a0403a02a..ed850366f22d8eae8260b8851ae212a7115b87bb 100644 (file)
@@ -463,6 +463,7 @@ out:
  */
 static void loop_add_bio(struct loop_device *lo, struct bio *bio)
 {
+       lo->lo_bio_count++;
        bio_list_add(&lo->lo_bio_list, bio);
 }
 
@@ -471,6 +472,7 @@ static void loop_add_bio(struct loop_device *lo, struct bio *bio)
  */
 static struct bio *loop_get_bio(struct loop_device *lo)
 {
+       lo->lo_bio_count--;
        return bio_list_pop(&lo->lo_bio_list);
 }
 
@@ -489,6 +491,10 @@ static void loop_make_request(struct request_queue *q, struct bio *old_bio)
                goto out;
        if (unlikely(rw == WRITE && (lo->lo_flags & LO_FLAGS_READ_ONLY)))
                goto out;
+       if (lo->lo_bio_count >= q->nr_congestion_on)
+               wait_event_lock_irq(lo->lo_req_wait,
+                                   lo->lo_bio_count < q->nr_congestion_off,
+                                   lo->lo_lock);
        loop_add_bio(lo, old_bio);
        wake_up(&lo->lo_event);
        spin_unlock_irq(&lo->lo_lock);
@@ -546,6 +552,8 @@ static int loop_thread(void *data)
                        continue;
                spin_lock_irq(&lo->lo_lock);
                bio = loop_get_bio(lo);
+               if (lo->lo_bio_count < lo->lo_queue->nr_congestion_off)
+                       wake_up(&lo->lo_req_wait);
                spin_unlock_irq(&lo->lo_lock);
 
                BUG_ON(!bio);
@@ -873,6 +881,7 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode,
        lo->transfer = transfer_none;
        lo->ioctl = NULL;
        lo->lo_sizelimit = 0;
+       lo->lo_bio_count = 0;
        lo->old_gfp_mask = mapping_gfp_mask(mapping);
        mapping_set_gfp_mask(mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS));
 
@@ -1083,8 +1092,13 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
 
        if (lo->lo_offset != info->lo_offset ||
            lo->lo_sizelimit != info->lo_sizelimit) {
+               struct block_device *bdev = lo->lo_device;
+
                if (figure_loop_size(lo, info->lo_offset, info->lo_sizelimit))
                        return -EFBIG;
+
+               bd_set_size(bdev, (loff_t)get_capacity(bdev->bd_disk) << 9);
+               kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, KOBJ_CHANGE);
        }
        loop_config_discard(lo);
 
@@ -1276,11 +1290,9 @@ static int loop_set_capacity(struct loop_device *lo, struct block_device *bdev)
        /* the width of sector_t may be narrow for bit-shift */
        sz = sec;
        sz <<= 9;
-       mutex_lock(&bdev->bd_mutex);
        bd_set_size(bdev, sz);
        /* let user-space know about the new size */
        kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, KOBJ_CHANGE);
-       mutex_unlock(&bdev->bd_mutex);
 
  out:
        return err;
@@ -1673,6 +1685,7 @@ static int loop_add(struct loop_device **l, int i)
        lo->lo_number           = i;
        lo->lo_thread           = NULL;
        init_waitqueue_head(&lo->lo_event);
+       init_waitqueue_head(&lo->lo_req_wait);
        spin_lock_init(&lo->lo_lock);
        disk->major             = LOOP_MAJOR;
        disk->first_minor       = i << part_shift;