]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - block/genhd.c
block: fix memleak when __blk_rq_map_user_iov() is failed
[mirror_ubuntu-bionic-kernel.git] / block / genhd.c
index 96a66f67172045d571be9fe18248dbefc99766ef..76fa1e96ebd3bb0963970d980566f115423a2960 100644 (file)
@@ -82,6 +82,18 @@ void part_in_flight(struct request_queue *q, struct hd_struct *part,
        }
 }
 
+void part_in_flight_rw(struct request_queue *q, struct hd_struct *part,
+                      unsigned int inflight[2])
+{
+       if (q->mq_ops) {
+               blk_mq_in_flight_rw(q, part, inflight);
+               return;
+       }
+
+       inflight[0] = atomic_read(&part->in_flight[0]);
+       inflight[1] = atomic_read(&part->in_flight[1]);
+}
+
 struct hd_struct *__disk_get_part(struct gendisk *disk, int partno)
 {
        struct disk_part_tbl *ptbl = rcu_dereference(disk->part_tbl);
@@ -503,6 +515,18 @@ void blk_free_devt(dev_t devt)
        }
 }
 
+/**
+ *     We invalidate devt by assigning NULL pointer for devt in idr.
+ */
+void blk_invalidate_devt(dev_t devt)
+{
+       if (MAJOR(devt) == BLOCK_EXT_MAJOR) {
+               spin_lock_bh(&ext_devt_lock);
+               idr_replace(&ext_devt_idr, NULL, blk_mangle_minor(MINOR(devt)));
+               spin_unlock_bh(&ext_devt_lock);
+       }
+}
+
 static char *bdevt_str(dev_t devt, char *buf)
 {
        if (MAJOR(devt) <= 0xff && MINOR(devt) <= 0xff) {
@@ -733,6 +757,13 @@ void del_gendisk(struct gendisk *disk)
 
        if (!(disk->flags & GENHD_FL_HIDDEN))
                blk_unregister_region(disk_devt(disk), disk->minors);
+       /*
+        * Remove gendisk pointer from idr so that it cannot be looked up
+        * while RCU period before freeing gendisk is running to prevent
+        * use-after-free issues. Note that the device number stays
+        * "in-use" until we really free the gendisk.
+        */
+       blk_invalidate_devt(disk_devt(disk));
 
        kobject_put(disk->part0.holder_dir);
        kobject_put(disk->slave_dir);