@@ -33,6 +33,15 @@ struct virtio_blk_vq {
33
33
} ____cacheline_aligned_in_smp ;
34
34
35
35
struct virtio_blk {
36
+ /*
37
+ * This mutex must be held by anything that may run after
38
+ * virtblk_remove() sets vblk->vdev to NULL.
39
+ *
40
+ * blk-mq, virtqueue processing, and sysfs attribute code paths are
41
+ * shut down before vblk->vdev is set to NULL and therefore do not need
42
+ * to hold this mutex.
43
+ */
44
+ struct mutex vdev_mutex ;
36
45
struct virtio_device * vdev ;
37
46
38
47
/* The disk structure for the kernel. */
@@ -44,6 +53,13 @@ struct virtio_blk {
44
53
/* Process context for config space updates */
45
54
struct work_struct config_work ;
46
55
56
+ /*
57
+ * Tracks references from block_device_operations open/release and
58
+ * virtio_driver probe/remove so this object can be freed once no
59
+ * longer in use.
60
+ */
61
+ refcount_t refs ;
62
+
47
63
/* What host tells us, plus 2 for header & tailer. */
48
64
unsigned int sg_elems ;
49
65
@@ -295,10 +311,55 @@ static int virtblk_get_id(struct gendisk *disk, char *id_str)
295
311
return err ;
296
312
}
297
313
314
+ static void virtblk_get (struct virtio_blk * vblk )
315
+ {
316
+ refcount_inc (& vblk -> refs );
317
+ }
318
+
319
+ static void virtblk_put (struct virtio_blk * vblk )
320
+ {
321
+ if (refcount_dec_and_test (& vblk -> refs )) {
322
+ ida_simple_remove (& vd_index_ida , vblk -> index );
323
+ mutex_destroy (& vblk -> vdev_mutex );
324
+ kfree (vblk );
325
+ }
326
+ }
327
+
328
+ static int virtblk_open (struct block_device * bd , fmode_t mode )
329
+ {
330
+ struct virtio_blk * vblk = bd -> bd_disk -> private_data ;
331
+ int ret = 0 ;
332
+
333
+ mutex_lock (& vblk -> vdev_mutex );
334
+
335
+ if (vblk -> vdev )
336
+ virtblk_get (vblk );
337
+ else
338
+ ret = - ENXIO ;
339
+
340
+ mutex_unlock (& vblk -> vdev_mutex );
341
+ return ret ;
342
+ }
343
+
344
+ static void virtblk_release (struct gendisk * disk , fmode_t mode )
345
+ {
346
+ struct virtio_blk * vblk = disk -> private_data ;
347
+
348
+ virtblk_put (vblk );
349
+ }
350
+
298
351
/* We provide getgeo only to please some old bootloader/partitioning tools */
299
352
static int virtblk_getgeo (struct block_device * bd , struct hd_geometry * geo )
300
353
{
301
354
struct virtio_blk * vblk = bd -> bd_disk -> private_data ;
355
+ int ret = 0 ;
356
+
357
+ mutex_lock (& vblk -> vdev_mutex );
358
+
359
+ if (!vblk -> vdev ) {
360
+ ret = - ENXIO ;
361
+ goto out ;
362
+ }
302
363
303
364
/* see if the host passed in geometry config */
304
365
if (virtio_has_feature (vblk -> vdev , VIRTIO_BLK_F_GEOMETRY )) {
@@ -314,11 +375,15 @@ static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
314
375
geo -> sectors = 1 << 5 ;
315
376
geo -> cylinders = get_capacity (bd -> bd_disk ) >> 11 ;
316
377
}
317
- return 0 ;
378
+ out :
379
+ mutex_unlock (& vblk -> vdev_mutex );
380
+ return ret ;
318
381
}
319
382
320
383
static const struct block_device_operations virtblk_fops = {
321
384
.owner = THIS_MODULE ,
385
+ .open = virtblk_open ,
386
+ .release = virtblk_release ,
322
387
.getgeo = virtblk_getgeo ,
323
388
};
324
389
@@ -655,6 +720,10 @@ static int virtblk_probe(struct virtio_device *vdev)
655
720
goto out_free_index ;
656
721
}
657
722
723
+ /* This reference is dropped in virtblk_remove(). */
724
+ refcount_set (& vblk -> refs , 1 );
725
+ mutex_init (& vblk -> vdev_mutex );
726
+
658
727
vblk -> vdev = vdev ;
659
728
vblk -> sg_elems = sg_elems ;
660
729
@@ -820,8 +889,6 @@ static int virtblk_probe(struct virtio_device *vdev)
820
889
static void virtblk_remove (struct virtio_device * vdev )
821
890
{
822
891
struct virtio_blk * vblk = vdev -> priv ;
823
- int index = vblk -> index ;
824
- int refc ;
825
892
826
893
/* Make sure no work handler is accessing the device. */
827
894
flush_work (& vblk -> config_work );
@@ -831,18 +898,21 @@ static void virtblk_remove(struct virtio_device *vdev)
831
898
832
899
blk_mq_free_tag_set (& vblk -> tag_set );
833
900
901
+ mutex_lock (& vblk -> vdev_mutex );
902
+
834
903
/* Stop all the virtqueues. */
835
904
vdev -> config -> reset (vdev );
836
905
837
- refc = kref_read (& disk_to_dev (vblk -> disk )-> kobj .kref );
906
+ /* Virtqueues are stopped, nothing can use vblk->vdev anymore. */
907
+ vblk -> vdev = NULL ;
908
+
838
909
put_disk (vblk -> disk );
839
910
vdev -> config -> del_vqs (vdev );
840
911
kfree (vblk -> vqs );
841
- kfree (vblk );
842
912
843
- /* Only free device id if we don't have any users */
844
- if ( refc == 1 )
845
- ida_simple_remove ( & vd_index_ida , index );
913
+ mutex_unlock ( & vblk -> vdev_mutex );
914
+
915
+ virtblk_put ( vblk );
846
916
}
847
917
848
918
#ifdef CONFIG_PM_SLEEP
0 commit comments