block: disk_events: introduce event flags
authorMartin Wilck <mwilck@suse.com>
Wed, 27 Mar 2019 13:51:02 +0000 (14:51 +0100)
committerJens Axboe <axboe@kernel.dk>
Fri, 12 Apr 2019 19:35:24 +0000 (13:35 -0600)
Currently, an empty disk->events field tells the block layer not to
forward media change events to user space. This was done in commit
7c88a168da80 ("block: don't propagate unlisted DISK_EVENTs to userland")
in order to avoid events from "fringe" drivers to be forwarded to user
space. By doing so, the block layer lost the information which events
were supported by a particular block device, and most importantly,
whether or not a given device supports media change events at all.

Prepare for not interpreting the "events" field this way in the future
any more. This is done by adding an additional field "event_flags" to
struct gendisk, and two flag bits that can be set to have the device
treated like one that had the "events" field set to a non-zero value
before. This applies only to the sd and sr drivers, which are changed to
set the new flags.

The new flags are DISK_EVENT_FLAG_POLL to enforce polling of the device
for synchronous events, and DISK_EVENT_FLAG_UEVENT to tell the
blocklayer to generate udev events from kernel events.

In order to add the event_flags field to struct gendisk, the events
field is converted to an "unsigned short"; it doesn't need to hold
values bigger than 2 anyway.

This patch doesn't change behavior.

Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
block/genhd.c
drivers/scsi/sd.c
drivers/scsi/sr.c
include/linux/genhd.h

index ee76de0fb4ccec076744d34e8ffa1dff5f31478c..5375be39e8a5f50c636c3bb21182f51827c588be 100644 (file)
@@ -1632,7 +1632,7 @@ static unsigned long disk_events_poll_jiffies(struct gendisk *disk)
         */
        if (ev->poll_msecs >= 0)
                intv_msecs = ev->poll_msecs;
-       else if (disk->events)
+       else if (disk->event_flags & DISK_EVENT_FLAG_POLL)
                intv_msecs = disk_events_dfl_poll_msecs;
 
        return msecs_to_jiffies(intv_msecs);
@@ -1842,11 +1842,13 @@ static void disk_check_events(struct disk_events *ev,
 
        /*
         * Tell userland about new events.  Only the events listed in
-        * @disk->events are reported.  Unlisted events are processed the
-        * same internally but never get reported to userland.
+        * @disk->events are reported, and only if DISK_EVENT_FLAG_UEVENT
+        * is set. Otherwise, events are processed internally but never
+        * get reported to userland.
         */
        for (i = 0; i < ARRAY_SIZE(disk_uevents); i++)
-               if (events & disk->events & (1 << i))
+               if ((events & disk->events & (1 << i)) &&
+                   (disk->event_flags & DISK_EVENT_FLAG_UEVENT))
                        envp[nr_events++] = disk_uevents[i];
 
        if (nr_events)
@@ -1884,6 +1886,9 @@ static ssize_t disk_events_show(struct device *dev,
 {
        struct gendisk *disk = dev_to_disk(dev);
 
+       if (!(disk->event_flags & DISK_EVENT_FLAG_UEVENT))
+               return 0;
+
        return __disk_events_show(disk->events, buf);
 }
 
index 92c34d93e0512726b58093d7524c80701ebc6a6b..ebc80354714c57de7e5cfda37ce3611e7d238d11 100644 (file)
@@ -3293,6 +3293,7 @@ static void sd_probe_async(void *data, async_cookie_t cookie)
        if (sdp->removable) {
                gd->flags |= GENHD_FL_REMOVABLE;
                gd->events |= DISK_EVENT_MEDIA_CHANGE;
+               gd->event_flags = DISK_EVENT_FLAG_POLL | DISK_EVENT_FLAG_UEVENT;
        }
 
        blk_pm_runtime_init(sdp->request_queue, dev);
index 039c27c2d7b3a3cc2e8d6e0470e798d8144e5585..c3f443d5aea89ca8fa76900eb8b1eb913d076cab 100644 (file)
@@ -716,6 +716,7 @@ static int sr_probe(struct device *dev)
        disk->fops = &sr_bdops;
        disk->flags = GENHD_FL_CD | GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE;
        disk->events = DISK_EVENT_MEDIA_CHANGE | DISK_EVENT_EJECT_REQUEST;
+       disk->event_flags = DISK_EVENT_FLAG_POLL | DISK_EVENT_FLAG_UEVENT;
 
        blk_queue_rq_timeout(sdev->request_queue, SR_TIMEOUT);
 
index a65d9fc17369d894b3850750b3f991ced17f0ef4..6547c9256d5c1b8f033dbac32a157cd04a769ac2 100644 (file)
@@ -150,6 +150,13 @@ enum {
        DISK_EVENT_EJECT_REQUEST                = 1 << 1, /* eject requested */
 };
 
+enum {
+       /* Poll even if events_poll_msecs is unset */
+       DISK_EVENT_FLAG_POLL                    = 1 << 0,
+       /* Forward events to udev */
+       DISK_EVENT_FLAG_UEVENT                  = 1 << 1,
+};
+
 struct disk_part_tbl {
        struct rcu_head rcu_head;
        int len;
@@ -184,7 +191,8 @@ struct gendisk {
        char disk_name[DISK_NAME_LEN];  /* name of major driver */
        char *(*devnode)(struct gendisk *gd, umode_t *mode);
 
-       unsigned int events;            /* supported events */
+       unsigned short events;          /* supported events */
+       unsigned short event_flags;     /* flags related to event processing */
 
        /* Array of pointers to partitions indexed by partno.
         * Protected with matching bdev lock but stat and other