Blob Blame History Raw
From 360a9cc1e5ae8d281c2dcf3cb41fb5e40999f01d Mon Sep 17 00:00:00 2001
From: Martin Wilck <mwilck@suse.com>
Date: Thu, 17 Jan 2019 22:30:48 +0100
Subject: [PATCH v2 1/4] block: disk_events: introduce event flags
Git-commit: c92e2f04b35938da23eb9a7f7101cbdd5ac7cdc4
Patch-mainline: v5.2-rc1
References: bsc#1110946, bsc#1119843

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 two flag bits that can be set to have the
device treated like one that has 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. They can easily be fit in the int
reserved for event bits.

This patch doesn't change behavior.

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 block/genhd.c         |   22 ++++++++++++++++------
 drivers/scsi/sd.c     |    3 ++-
 drivers/scsi/sr.c     |    3 ++-
 include/linux/genhd.h |    7 +++++++
 4 files changed, 27 insertions(+), 8 deletions(-)

--- a/block/genhd.c
+++ b/block/genhd.c
@@ -1577,7 +1577,8 @@ static unsigned long disk_events_poll_ji
 	 */
 	if (ev->poll_msecs >= 0)
 		intv_msecs = ev->poll_msecs;
-	else if (disk->events & ~disk->async_events)
+	else if (disk->events & DISK_EVENT_FLAG_POLL
+		 && disk->events & ~disk->async_events)
 		intv_msecs = disk_events_dfl_poll_msecs;
 
 	return msecs_to_jiffies(intv_msecs);
@@ -1787,11 +1788,13 @@ static void disk_check_events(struct dis
 
 	/*
 	 * 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->events & DISK_EVENT_FLAG_UEVENT)
 			envp[nr_events++] = disk_uevents[i];
 
 	if (nr_events)
@@ -1828,7 +1831,10 @@ static ssize_t disk_events_show(struct d
 {
 	struct gendisk *disk = dev_to_disk(dev);
 
-	return __disk_events_show(disk->events, buf);
+	if (!(disk->events & DISK_EVENT_FLAG_UEVENT))
+		return 0;
+
+	return __disk_events_show(disk->events & DISK_EVENT_TYPES_MASK, buf);
 }
 
 static ssize_t disk_events_async_show(struct device *dev,
@@ -1836,7 +1842,11 @@ static ssize_t disk_events_async_show(st
 {
 	struct gendisk *disk = dev_to_disk(dev);
 
-	return __disk_events_show(disk->async_events, buf);
+	if (!(disk->events & DISK_EVENT_FLAG_UEVENT))
+		return 0;
+
+	return __disk_events_show(disk->async_events & DISK_EVENT_TYPES_MASK,
+				  buf);
 }
 
 static ssize_t disk_events_poll_msecs_show(struct device *dev,
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -3296,7 +3296,8 @@ static void sd_probe_async(void *data, a
 	gd->flags = GENHD_FL_EXT_DEVT;
 	if (sdp->removable) {
 		gd->flags |= GENHD_FL_REMOVABLE;
-		gd->events |= DISK_EVENT_MEDIA_CHANGE;
+		gd->events |= DISK_EVENT_MEDIA_CHANGE |
+			DISK_EVENT_FLAG_POLL | DISK_EVENT_FLAG_UEVENT;
 	}
 
 	blk_pm_runtime_init(sdp->request_queue, dev);
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -702,7 +702,8 @@ static int sr_probe(struct device *dev)
 	sprintf(disk->disk_name, "sr%d", minor);
 	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->events = DISK_EVENT_MEDIA_CHANGE | DISK_EVENT_EJECT_REQUEST
+		| DISK_EVENT_FLAG_POLL | DISK_EVENT_FLAG_UEVENT;
 
 	blk_queue_rq_timeout(sdev->request_queue, SR_TIMEOUT);
 
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -145,8 +145,15 @@ struct hd_struct {
 enum {
 	DISK_EVENT_MEDIA_CHANGE			= 1 << 0, /* media changed */
 	DISK_EVENT_EJECT_REQUEST		= 1 << 1, /* eject requested */
+	/* Poll even if events_poll_msecs is unset */
+	DISK_EVENT_FLAG_POLL			= 1 << 16,
+	/* Forward events to udev */
+	DISK_EVENT_FLAG_UEVENT			= 1 << 17,
 };
 
+#define DISK_EVENT_TYPES_MASK \
+	(DISK_EVENT_MEDIA_CHANGE | DISK_EVENT_EJECT_REQUEST)
+
 struct disk_part_tbl {
 	struct rcu_head rcu_head;
 	int len;