From: David Howells <dhowells@redhat.com> To: viro@zeniv.linux.org.uk Cc: dhowells@redhat.com, raven@themaw.net, linux-fsdevel@vger.kernel.org, linux-api@vger.kernel.org, linux-block@vger.kernel.org, keyrings@vger.kernel.org, linux-security-module@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 11/13] block: Add block layer notifications [ver #4] Date: Fri, 07 Jun 2019 15:19:04 +0100 [thread overview] Message-ID: <155991714448.15579.1960242962075486353.stgit@warthog.procyon.org.uk> (raw) In-Reply-To: <155991702981.15579.6007568669839441045.stgit@warthog.procyon.org.uk> Add a block layer notification mechanism whereby notifications about block-layer events such as I/O errors, can be reported to a monitoring process asynchronously. Firstly, an event queue needs to be created: fd = open("/dev/event_queue", O_RDWR); ioctl(fd, IOC_WATCH_QUEUE_SET_SIZE, page_size << n); then a notification can be set up to report block notifications via that queue: struct watch_notification_filter filter = { .nr_filters = 1, .filters = { [0] = { .type = WATCH_TYPE_BLOCK_NOTIFY, .subtype_filter[0] = UINT_MAX; }, }, }; ioctl(fd, IOC_WATCH_QUEUE_SET_FILTER, &filter); watch_devices(fd, 12); After that, records will be placed into the queue when, for example, errors occur on a block device. Records are of the following format: struct block_notification { struct watch_notification watch; __u64 dev; __u64 sector; } *n; Where: n->watch.type will be WATCH_TYPE_BLOCK_NOTIFY n->watch.subtype will be the type of notification, such as NOTIFY_BLOCK_ERROR_CRITICAL_MEDIUM. n->watch.info & WATCH_INFO_LENGTH will indicate the length of the record. n->watch.info & WATCH_INFO_ID will be the second argument to watch_devices(), shifted. n->dev will be the device numbers munged together. n->sector will indicate the affected sector (if appropriate for the event). Note that it is permissible for event records to be of variable length - or, at least, the length may be dependent on the subtype. Signed-off-by: David Howells <dhowells@redhat.com> --- Documentation/watch_queue.rst | 10 +++++++++- block/Kconfig | 9 +++++++++ block/blk-core.c | 29 +++++++++++++++++++++++++++++ include/linux/blkdev.h | 15 +++++++++++++++ include/uapi/linux/watch_queue.h | 27 +++++++++++++++++++++++++++ 5 files changed, 89 insertions(+), 1 deletion(-) diff --git a/Documentation/watch_queue.rst b/Documentation/watch_queue.rst index e4b8233d5aa8..c2954e191989 100644 --- a/Documentation/watch_queue.rst +++ b/Documentation/watch_queue.rst @@ -11,7 +11,9 @@ receive notifications from the kernel. This can be used in conjunction with:: * Superblock event notifications - * General device event notifications + * General device event notifications, including:: + + * Block layer event notifications The notifications buffers can be enabled by: @@ -336,6 +338,12 @@ Any particular buffer can be fed from multiple sources. Sources include: See Documentation/security/keys/core.rst for more information. + * WATCH_TYPE_BLOCK_NOTIFY + + Notifications of this type indicate block layer events, such as I/O errors + or temporary link loss. Watchpoints of this type are set on the global + device watch list. + Event Filtering =============== diff --git a/block/Kconfig b/block/Kconfig index 1b220101a9cb..4ff4a56ba9f9 100644 --- a/block/Kconfig +++ b/block/Kconfig @@ -163,6 +163,15 @@ config BLK_SED_OPAL Enabling this option enables users to setup/unlock/lock Locking ranges for SED devices using the Opal protocol. +config BLK_NOTIFICATIONS + bool "Block layer event notifications" + select DEVICE_NOTIFICATIONS + help + This option provides support for getting block layer event + notifications. This makes use of the /dev/watch_queue misc device to + handle the notification buffer and provides the device_notify() system + call to enable/disable watches. + menu "Partition Types" source "block/partitions/Kconfig" diff --git a/block/blk-core.c b/block/blk-core.c index 419d600e6637..edad86172d47 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -144,6 +144,22 @@ static const struct { [BLK_STS_IOERR] = { -EIO, "I/O" }, }; +#ifdef CONFIG_BLK_NOTIFICATIONS +static const +enum block_notification_type blk_notifications[ARRAY_SIZE(blk_errors)] = { + [BLK_STS_TIMEOUT] = NOTIFY_BLOCK_ERROR_TIMEOUT, + [BLK_STS_NOSPC] = NOTIFY_BLOCK_ERROR_NO_SPACE, + [BLK_STS_TRANSPORT] = NOTIFY_BLOCK_ERROR_RECOVERABLE_TRANSPORT, + [BLK_STS_TARGET] = NOTIFY_BLOCK_ERROR_CRITICAL_TARGET, + [BLK_STS_NEXUS] = NOTIFY_BLOCK_ERROR_CRITICAL_NEXUS, + [BLK_STS_MEDIUM] = NOTIFY_BLOCK_ERROR_CRITICAL_MEDIUM, + [BLK_STS_PROTECTION] = NOTIFY_BLOCK_ERROR_PROTECTION, + [BLK_STS_RESOURCE] = NOTIFY_BLOCK_ERROR_KERNEL_RESOURCE, + [BLK_STS_DEV_RESOURCE] = NOTIFY_BLOCK_ERROR_DEVICE_RESOURCE, + [BLK_STS_IOERR] = NOTIFY_BLOCK_ERROR_IO, +}; +#endif + blk_status_t errno_to_blk_status(int errno) { int i; @@ -179,6 +195,19 @@ static void print_req_error(struct request *req, blk_status_t status) req->rq_disk ? req->rq_disk->disk_name : "?", (unsigned long long)blk_rq_pos(req), req->cmd_flags); + +#ifdef CONFIG_BLK_NOTIFICATIONS + if (blk_notifications[idx]) { + struct block_notification n = { + .watch.type = WATCH_TYPE_BLOCK_NOTIFY, + .watch.subtype = blk_notifications[idx], + .watch.info = sizeof(n), + .dev = req->rq_disk ? disk_devt(req->rq_disk) : 0, + .sector = blk_rq_pos(req), + }; + post_block_notification(&n); + } +#endif } static void req_bio_endio(struct request *rq, struct bio *bio, diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 1aafeb923e7b..8b8e235f47c9 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -43,6 +43,7 @@ struct pr_ops; struct rq_qos; struct blk_queue_stats; struct blk_stat_callback; +struct block_notification; #define BLKDEV_MIN_RQ 4 #define BLKDEV_MAX_RQ 128 /* Default maximum */ @@ -1744,6 +1745,20 @@ static inline bool blk_req_can_dispatch_to_zone(struct request *rq) } #endif /* CONFIG_BLK_DEV_ZONED */ +#ifdef CONFIG_BLK_NOTIFICATIONS +static inline void post_block_notification(struct block_notification *n) +{ + u64 id = 0; /* Might want to allow dev# here. */ + + post_device_notification(&n->watch, id); +} +#else +static inline void post_block_notification(struct block_notification *n) +{ +} +#endif + + #else /* CONFIG_BLOCK */ struct block_device; diff --git a/include/uapi/linux/watch_queue.h b/include/uapi/linux/watch_queue.h index aeffcfd7a742..22e3326b83a6 100644 --- a/include/uapi/linux/watch_queue.h +++ b/include/uapi/linux/watch_queue.h @@ -155,4 +155,31 @@ struct superblock_error_notification { __u32 error_cookie; }; +/* + * Type of block layer notification. + */ +enum block_notification_type { + NOTIFY_BLOCK_ERROR_TIMEOUT = 1, /* Timeout error */ + NOTIFY_BLOCK_ERROR_NO_SPACE = 2, /* Critical space allocation error */ + NOTIFY_BLOCK_ERROR_RECOVERABLE_TRANSPORT = 3, /* Recoverable transport error */ + NOTIFY_BLOCK_ERROR_CRITICAL_TARGET = 4, /* Critical target error */ + NOTIFY_BLOCK_ERROR_CRITICAL_NEXUS = 5, /* Critical nexus error */ + NOTIFY_BLOCK_ERROR_CRITICAL_MEDIUM = 6, /* Critical medium error */ + NOTIFY_BLOCK_ERROR_PROTECTION = 7, /* Protection error */ + NOTIFY_BLOCK_ERROR_KERNEL_RESOURCE = 8, /* Kernel resource error */ + NOTIFY_BLOCK_ERROR_DEVICE_RESOURCE = 9, /* Device resource error */ + NOTIFY_BLOCK_ERROR_IO = 10, /* Other I/O error */ +}; + +/* + * Block layer notification record. + * - watch.type = WATCH_TYPE_BLOCK_NOTIFY + * - watch.subtype = enum block_notification_type + */ +struct block_notification { + struct watch_notification watch; /* WATCH_TYPE_BLOCK_NOTIFY */ + __u64 dev; /* Device number */ + __u64 sector; /* Affected sector */ +}; + #endif /* _UAPI_LINUX_WATCH_QUEUE_H */
WARNING: multiple messages have this Message-ID (diff)
From: David Howells <dhowells@redhat.com> To: viro@zeniv.linux.org.uk Cc: dhowells@redhat.com, raven@themaw.net, linux-fsdevel@vger.kernel.org, linux-api@vger.kernel.org, linux-block@vger.kernel.org, keyrings@vger.kernel.org, linux-security-module@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 11/13] block: Add block layer notifications [ver #4] Date: Fri, 07 Jun 2019 14:19:04 +0000 [thread overview] Message-ID: <155991714448.15579.1960242962075486353.stgit@warthog.procyon.org.uk> (raw) In-Reply-To: <155991702981.15579.6007568669839441045.stgit@warthog.procyon.org.uk> Add a block layer notification mechanism whereby notifications about block-layer events such as I/O errors, can be reported to a monitoring process asynchronously. Firstly, an event queue needs to be created: fd = open("/dev/event_queue", O_RDWR); ioctl(fd, IOC_WATCH_QUEUE_SET_SIZE, page_size << n); then a notification can be set up to report block notifications via that queue: struct watch_notification_filter filter = { .nr_filters = 1, .filters = { [0] = { .type = WATCH_TYPE_BLOCK_NOTIFY, .subtype_filter[0] = UINT_MAX; }, }, }; ioctl(fd, IOC_WATCH_QUEUE_SET_FILTER, &filter); watch_devices(fd, 12); After that, records will be placed into the queue when, for example, errors occur on a block device. Records are of the following format: struct block_notification { struct watch_notification watch; __u64 dev; __u64 sector; } *n; Where: n->watch.type will be WATCH_TYPE_BLOCK_NOTIFY n->watch.subtype will be the type of notification, such as NOTIFY_BLOCK_ERROR_CRITICAL_MEDIUM. n->watch.info & WATCH_INFO_LENGTH will indicate the length of the record. n->watch.info & WATCH_INFO_ID will be the second argument to watch_devices(), shifted. n->dev will be the device numbers munged together. n->sector will indicate the affected sector (if appropriate for the event). Note that it is permissible for event records to be of variable length - or, at least, the length may be dependent on the subtype. Signed-off-by: David Howells <dhowells@redhat.com> --- Documentation/watch_queue.rst | 10 +++++++++- block/Kconfig | 9 +++++++++ block/blk-core.c | 29 +++++++++++++++++++++++++++++ include/linux/blkdev.h | 15 +++++++++++++++ include/uapi/linux/watch_queue.h | 27 +++++++++++++++++++++++++++ 5 files changed, 89 insertions(+), 1 deletion(-) diff --git a/Documentation/watch_queue.rst b/Documentation/watch_queue.rst index e4b8233d5aa8..c2954e191989 100644 --- a/Documentation/watch_queue.rst +++ b/Documentation/watch_queue.rst @@ -11,7 +11,9 @@ receive notifications from the kernel. This can be used in conjunction with:: * Superblock event notifications - * General device event notifications + * General device event notifications, including:: + + * Block layer event notifications The notifications buffers can be enabled by: @@ -336,6 +338,12 @@ Any particular buffer can be fed from multiple sources. Sources include: See Documentation/security/keys/core.rst for more information. + * WATCH_TYPE_BLOCK_NOTIFY + + Notifications of this type indicate block layer events, such as I/O errors + or temporary link loss. Watchpoints of this type are set on the global + device watch list. + Event Filtering =======diff --git a/block/Kconfig b/block/Kconfig index 1b220101a9cb..4ff4a56ba9f9 100644 --- a/block/Kconfig +++ b/block/Kconfig @@ -163,6 +163,15 @@ config BLK_SED_OPAL Enabling this option enables users to setup/unlock/lock Locking ranges for SED devices using the Opal protocol. +config BLK_NOTIFICATIONS + bool "Block layer event notifications" + select DEVICE_NOTIFICATIONS + help + This option provides support for getting block layer event + notifications. This makes use of the /dev/watch_queue misc device to + handle the notification buffer and provides the device_notify() system + call to enable/disable watches. + menu "Partition Types" source "block/partitions/Kconfig" diff --git a/block/blk-core.c b/block/blk-core.c index 419d600e6637..edad86172d47 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -144,6 +144,22 @@ static const struct { [BLK_STS_IOERR] = { -EIO, "I/O" }, }; +#ifdef CONFIG_BLK_NOTIFICATIONS +static const +enum block_notification_type blk_notifications[ARRAY_SIZE(blk_errors)] = { + [BLK_STS_TIMEOUT] = NOTIFY_BLOCK_ERROR_TIMEOUT, + [BLK_STS_NOSPC] = NOTIFY_BLOCK_ERROR_NO_SPACE, + [BLK_STS_TRANSPORT] = NOTIFY_BLOCK_ERROR_RECOVERABLE_TRANSPORT, + [BLK_STS_TARGET] = NOTIFY_BLOCK_ERROR_CRITICAL_TARGET, + [BLK_STS_NEXUS] = NOTIFY_BLOCK_ERROR_CRITICAL_NEXUS, + [BLK_STS_MEDIUM] = NOTIFY_BLOCK_ERROR_CRITICAL_MEDIUM, + [BLK_STS_PROTECTION] = NOTIFY_BLOCK_ERROR_PROTECTION, + [BLK_STS_RESOURCE] = NOTIFY_BLOCK_ERROR_KERNEL_RESOURCE, + [BLK_STS_DEV_RESOURCE] = NOTIFY_BLOCK_ERROR_DEVICE_RESOURCE, + [BLK_STS_IOERR] = NOTIFY_BLOCK_ERROR_IO, +}; +#endif + blk_status_t errno_to_blk_status(int errno) { int i; @@ -179,6 +195,19 @@ static void print_req_error(struct request *req, blk_status_t status) req->rq_disk ? req->rq_disk->disk_name : "?", (unsigned long long)blk_rq_pos(req), req->cmd_flags); + +#ifdef CONFIG_BLK_NOTIFICATIONS + if (blk_notifications[idx]) { + struct block_notification n = { + .watch.type = WATCH_TYPE_BLOCK_NOTIFY, + .watch.subtype = blk_notifications[idx], + .watch.info = sizeof(n), + .dev = req->rq_disk ? disk_devt(req->rq_disk) : 0, + .sector = blk_rq_pos(req), + }; + post_block_notification(&n); + } +#endif } static void req_bio_endio(struct request *rq, struct bio *bio, diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 1aafeb923e7b..8b8e235f47c9 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -43,6 +43,7 @@ struct pr_ops; struct rq_qos; struct blk_queue_stats; struct blk_stat_callback; +struct block_notification; #define BLKDEV_MIN_RQ 4 #define BLKDEV_MAX_RQ 128 /* Default maximum */ @@ -1744,6 +1745,20 @@ static inline bool blk_req_can_dispatch_to_zone(struct request *rq) } #endif /* CONFIG_BLK_DEV_ZONED */ +#ifdef CONFIG_BLK_NOTIFICATIONS +static inline void post_block_notification(struct block_notification *n) +{ + u64 id = 0; /* Might want to allow dev# here. */ + + post_device_notification(&n->watch, id); +} +#else +static inline void post_block_notification(struct block_notification *n) +{ +} +#endif + + #else /* CONFIG_BLOCK */ struct block_device; diff --git a/include/uapi/linux/watch_queue.h b/include/uapi/linux/watch_queue.h index aeffcfd7a742..22e3326b83a6 100644 --- a/include/uapi/linux/watch_queue.h +++ b/include/uapi/linux/watch_queue.h @@ -155,4 +155,31 @@ struct superblock_error_notification { __u32 error_cookie; }; +/* + * Type of block layer notification. + */ +enum block_notification_type { + NOTIFY_BLOCK_ERROR_TIMEOUT = 1, /* Timeout error */ + NOTIFY_BLOCK_ERROR_NO_SPACE = 2, /* Critical space allocation error */ + NOTIFY_BLOCK_ERROR_RECOVERABLE_TRANSPORT = 3, /* Recoverable transport error */ + NOTIFY_BLOCK_ERROR_CRITICAL_TARGET = 4, /* Critical target error */ + NOTIFY_BLOCK_ERROR_CRITICAL_NEXUS = 5, /* Critical nexus error */ + NOTIFY_BLOCK_ERROR_CRITICAL_MEDIUM = 6, /* Critical medium error */ + NOTIFY_BLOCK_ERROR_PROTECTION = 7, /* Protection error */ + NOTIFY_BLOCK_ERROR_KERNEL_RESOURCE = 8, /* Kernel resource error */ + NOTIFY_BLOCK_ERROR_DEVICE_RESOURCE = 9, /* Device resource error */ + NOTIFY_BLOCK_ERROR_IO = 10, /* Other I/O error */ +}; + +/* + * Block layer notification record. + * - watch.type = WATCH_TYPE_BLOCK_NOTIFY + * - watch.subtype = enum block_notification_type + */ +struct block_notification { + struct watch_notification watch; /* WATCH_TYPE_BLOCK_NOTIFY */ + __u64 dev; /* Device number */ + __u64 sector; /* Affected sector */ +}; + #endif /* _UAPI_LINUX_WATCH_QUEUE_H */
next prev parent reply other threads:[~2019-06-07 14:19 UTC|newest] Thread overview: 80+ messages / expand[flat|nested] mbox.gz Atom feed top 2019-06-07 14:17 [RFC][PATCH 00/13] Mount, FS, Block and Keyrings notifications [ver #4] David Howells 2019-06-07 14:17 ` David Howells 2019-06-07 14:17 ` David Howells 2019-06-07 14:17 ` [PATCH 01/13] security: Override creds in __fput() with last fputter's creds " David Howells 2019-06-07 14:17 ` David Howells 2019-06-07 14:17 ` David Howells 2019-06-07 14:17 ` [PATCH 02/13] uapi: General notification ring definitions " David Howells 2019-06-07 14:17 ` David Howells 2019-06-07 15:12 ` Darrick J. Wong 2019-06-07 15:12 ` Darrick J. Wong 2019-06-07 15:30 ` David Howells 2019-06-07 15:30 ` David Howells 2019-06-07 15:51 ` David Howells 2019-06-07 15:51 ` David Howells 2019-06-09 4:35 ` Randy Dunlap 2019-06-09 4:35 ` Randy Dunlap 2019-06-13 13:34 ` David Howells 2019-06-13 13:34 ` David Howells 2019-06-13 14:49 ` Randy Dunlap 2019-06-13 14:49 ` Randy Dunlap 2019-06-07 14:17 ` [PATCH 03/13] security: Add hooks to rule on setting a watch " David Howells 2019-06-07 14:17 ` David Howells 2019-06-07 14:17 ` David Howells 2019-06-07 14:17 ` [PATCH 04/13] security: Add a hook for the point of notification insertion " David Howells 2019-06-07 14:17 ` David Howells 2019-06-07 14:17 ` David Howells 2019-06-07 14:18 ` [PATCH 05/13] General notification queue with user mmap()'able ring buffer " David Howells 2019-06-07 14:18 ` David Howells 2019-06-07 14:18 ` [PATCH 06/13] keys: Add a notification facility " David Howells 2019-06-07 14:18 ` David Howells 2019-06-10 17:11 ` Jonathan Corbet 2019-06-10 17:11 ` Jonathan Corbet 2019-06-10 17:47 ` David Howells 2019-06-10 17:47 ` David Howells 2019-06-07 14:18 ` [PATCH 07/13] vfs: Add a mount-notification " David Howells 2019-06-07 14:18 ` David Howells 2019-06-07 14:18 ` [PATCH 08/13] vfs: Add superblock notifications " David Howells 2019-06-07 14:18 ` David Howells 2019-06-07 14:18 ` [PATCH 09/13] fsinfo: Export superblock notification counter " David Howells 2019-06-07 14:18 ` David Howells 2019-06-07 14:18 ` [PATCH 10/13] Add a general, global device notification watch list " David Howells 2019-06-07 14:18 ` David Howells 2019-06-07 14:19 ` David Howells [this message] 2019-06-07 14:19 ` [PATCH 11/13] block: Add block layer notifications " David Howells 2019-06-07 14:19 ` [PATCH 12/13] usb: Add USB subsystem " David Howells 2019-06-07 14:19 ` David Howells 2019-06-07 14:19 ` [PATCH 13/13] Add sample notification program " David Howells 2019-06-07 14:19 ` David Howells 2019-06-10 15:21 ` [RFC][PATCH 00/13] Mount, FS, Block and Keyrings notifications " Stephen Smalley 2019-06-10 15:21 ` Stephen Smalley 2019-06-10 16:33 ` Casey Schaufler 2019-06-10 16:33 ` Casey Schaufler 2019-06-10 16:42 ` Andy Lutomirski 2019-06-10 16:42 ` Andy Lutomirski 2019-06-10 18:01 ` Casey Schaufler 2019-06-10 18:01 ` Casey Schaufler 2019-06-10 18:22 ` Andy Lutomirski 2019-06-10 18:22 ` Andy Lutomirski 2019-06-10 19:33 ` Casey Schaufler 2019-06-10 19:33 ` Casey Schaufler 2019-06-10 19:53 ` Andy Lutomirski 2019-06-10 19:53 ` Andy Lutomirski 2019-06-10 21:25 ` Casey Schaufler 2019-06-10 21:25 ` Casey Schaufler 2019-06-11 0:13 ` Andy Lutomirski 2019-06-11 0:13 ` Andy Lutomirski 2019-06-11 14:32 ` Stephen Smalley 2019-06-11 14:32 ` Stephen Smalley 2019-06-12 8:55 ` David Howells 2019-06-12 8:55 ` David Howells 2019-06-10 22:07 ` David Howells 2019-06-10 22:07 ` David Howells 2019-06-11 14:21 ` What do LSMs *actually* need for checks on notifications? David Howells 2019-06-11 15:57 ` Stephen Smalley 2019-06-11 16:22 ` Casey Schaufler 2019-06-12 11:43 ` David Howells 2019-06-13 18:46 ` Stephen Smalley 2019-06-12 17:41 ` David Howells 2019-06-12 18:14 ` Casey Schaufler 2019-06-12 18:36 ` David Howells
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=155991714448.15579.1960242962075486353.stgit@warthog.procyon.org.uk \ --to=dhowells@redhat.com \ --cc=keyrings@vger.kernel.org \ --cc=linux-api@vger.kernel.org \ --cc=linux-block@vger.kernel.org \ --cc=linux-fsdevel@vger.kernel.org \ --cc=linux-kernel@vger.kernel.org \ --cc=linux-security-module@vger.kernel.org \ --cc=raven@themaw.net \ --cc=viro@zeniv.linux.org.uk \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.