diff options
-rw-r--r-- | block/disk-events.c | 3 | ||||
-rw-r--r-- | block/genhd.c | 24 | ||||
-rw-r--r-- | include/linux/genhd.h | 2 |
3 files changed, 29 insertions, 0 deletions
diff --git a/block/disk-events.c b/block/disk-events.c index a75931ff5da4..04c52f3992ed 100644 --- a/block/disk-events.c +++ b/block/disk-events.c @@ -190,6 +190,9 @@ static void disk_check_events(struct disk_events *ev, spin_unlock_irq(&ev->lock); + if (events & DISK_EVENT_MEDIA_CHANGE) + inc_diskseq(disk); + /* * Tell userland about new events. Only the events listed in * @disk->events are reported, and only if DISK_EVENT_FLAG_UEVENT diff --git a/block/genhd.c b/block/genhd.c index 38f053074159..ceb08af72c1a 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -29,6 +29,23 @@ static struct kobject *block_depr; +/* + * Unique, monotonically increasing sequential number associated with block + * devices instances (i.e. incremented each time a device is attached). + * Associating uevents with block devices in userspace is difficult and racy: + * the uevent netlink socket is lossy, and on slow and overloaded systems has + * a very high latency. + * Block devices do not have exclusive owners in userspace, any process can set + * one up (e.g. loop devices). Moreover, device names can be reused (e.g. loop0 + * can be reused again and again). + * A userspace process setting up a block device and watching for its events + * cannot thus reliably tell whether an event relates to the device it just set + * up or another earlier instance with the same name. + * This sequential number allows userspace processes to solve this problem, and + * uniquely associate an uevent to the lifetime to a device. + */ +static atomic64_t diskseq; + /* for extended dynamic devt allocation, currently only one major is used */ #define NR_EXT_DEVT (1 << MINORBITS) static DEFINE_IDA(ext_devt_ida); @@ -1252,6 +1269,8 @@ struct gendisk *__alloc_disk_node(int minors, int node_id) disk_to_dev(disk)->class = &block_class; disk_to_dev(disk)->type = &disk_type; device_initialize(disk_to_dev(disk)); + inc_diskseq(disk); + return disk; out_destroy_part_tbl: @@ -1352,3 +1371,8 @@ int bdev_read_only(struct block_device *bdev) return bdev->bd_read_only || get_disk_ro(bdev->bd_disk); } EXPORT_SYMBOL(bdev_read_only); + +void inc_diskseq(struct gendisk *disk) +{ + disk->diskseq = atomic64_inc_return(&diskseq); +} diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 13b34177cc85..140c028845af 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -172,6 +172,7 @@ struct gendisk { int node_id; struct badblocks *bb; struct lockdep_map lockdep_map; + u64 diskseq; }; /* @@ -332,6 +333,7 @@ static inline void bd_unlink_disk_holder(struct block_device *bdev, #endif /* CONFIG_SYSFS */ dev_t part_devt(struct gendisk *disk, u8 partno); +void inc_diskseq(struct gendisk *disk); dev_t blk_lookup_devt(const char *name, int partno); void blk_request_module(dev_t devt); #ifdef CONFIG_BLOCK |