From patchwork Wed Nov 11 21:52:06 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gabriel Krisman Bertazi X-Patchwork-Id: 11898629 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C7B7D921 for ; Wed, 11 Nov 2020 21:52:33 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B0F77208CA for ; Wed, 11 Nov 2020 21:52:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726511AbgKKVwc (ORCPT ); Wed, 11 Nov 2020 16:52:32 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46692 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725933AbgKKVwc (ORCPT ); Wed, 11 Nov 2020 16:52:32 -0500 Received: from bhuna.collabora.co.uk (bhuna.collabora.co.uk [IPv6:2a00:1098:0:82:1000:25:2eeb:e3e3]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F3233C0613D1; Wed, 11 Nov 2020 13:52:31 -0800 (PST) Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: krisman) with ESMTPSA id E32E01F45DC8 From: Gabriel Krisman Bertazi To: dhowells@redhat.com Cc: viro@zeniv.linux.org.uk, tytso@mit.edu, khazhy@google.com, adilger.kernel@dilger.ca, linux-ext4@vger.kernel.org, linux-fsdevel@vger.kernel.org, kernel@collabora.com, Miklos Szeredi , Gabriel Krisman Bertazi Subject: [PATCH RFC v2 1/8] watch_queue: Make watch_sizeof() check record size Date: Wed, 11 Nov 2020 16:52:06 -0500 Message-Id: <20201111215213.4152354-2-krisman@collabora.com> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201111215213.4152354-1-krisman@collabora.com> References: <20201111215213.4152354-1-krisman@collabora.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org From: David Howells Make watch_sizeof() give a build error if the size of the struct won't fit into the size field in the header. Reported-by: Miklos Szeredi Signed-off-by: David Howells [Rebase to 5.10] Signed-off-by: Gabriel Krisman Bertazi --- include/linux/watch_queue.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/include/linux/watch_queue.h b/include/linux/watch_queue.h index c994d1b2cdba..f1086d12cd03 100644 --- a/include/linux/watch_queue.h +++ b/include/linux/watch_queue.h @@ -120,7 +120,12 @@ static inline void remove_watch_list(struct watch_list *wlist, u64 id) * watch_sizeof - Calculate the information part of the size of a watch record, * given the structure size. */ -#define watch_sizeof(STRUCT) (sizeof(STRUCT) << WATCH_INFO_LENGTH__SHIFT) +#define watch_sizeof(STRUCT) \ + ({ \ + size_t max = WATCH_INFO_LENGTH >> WATCH_INFO_LENGTH__SHIFT; \ + BUILD_BUG_ON(sizeof(STRUCT) > max); \ + sizeof(STRUCT) << WATCH_INFO_LENGTH__SHIFT; \ + }) #else static inline int watch_queue_init(struct pipe_inode_info *pipe) From patchwork Wed Nov 11 21:52:07 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gabriel Krisman Bertazi X-Patchwork-Id: 11898631 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 69CDE921 for ; Wed, 11 Nov 2020 21:52:37 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 524F12087D for ; Wed, 11 Nov 2020 21:52:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726704AbgKKVwg (ORCPT ); Wed, 11 Nov 2020 16:52:36 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46700 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726618AbgKKVwe (ORCPT ); Wed, 11 Nov 2020 16:52:34 -0500 Received: from bhuna.collabora.co.uk (bhuna.collabora.co.uk [IPv6:2a00:1098:0:82:1000:25:2eeb:e3e3]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0D3A5C0613D1; Wed, 11 Nov 2020 13:52:34 -0800 (PST) Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: krisman) with ESMTPSA id BE9711F45E06 From: Gabriel Krisman Bertazi To: dhowells@redhat.com Cc: viro@zeniv.linux.org.uk, tytso@mit.edu, khazhy@google.com, adilger.kernel@dilger.ca, linux-ext4@vger.kernel.org, linux-fsdevel@vger.kernel.org, kernel@collabora.com, Gabriel Krisman Bertazi Subject: [PATCH RFC v2 2/8] security: Add hooks to rule on setting a watch for superblock Date: Wed, 11 Nov 2020 16:52:07 -0500 Message-Id: <20201111215213.4152354-3-krisman@collabora.com> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201111215213.4152354-1-krisman@collabora.com> References: <20201111215213.4152354-1-krisman@collabora.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org From: David Howells Add security hooks that will allow an LSM to rule on whether or not a watch may be set for a supperblock. Signed-off-by: David Howells [Drop mount and key changes. Rebase to mainline] Signed-off-by: Gabriel Krisman Bertazi --- include/linux/lsm_hook_defs.h | 1 + include/linux/lsm_hooks.h | 4 ++++ include/linux/security.h | 13 +++++++++++++ security/security.c | 6 ++++++ 4 files changed, 24 insertions(+) diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h index 32a940117e7a..8fa8533598bc 100644 --- a/include/linux/lsm_hook_defs.h +++ b/include/linux/lsm_hook_defs.h @@ -261,6 +261,7 @@ LSM_HOOK(int, 0, inode_getsecctx, struct inode *inode, void **ctx, #if defined(CONFIG_SECURITY) && defined(CONFIG_WATCH_QUEUE) LSM_HOOK(int, 0, post_notification, const struct cred *w_cred, const struct cred *cred, struct watch_notification *n) +LSM_HOOK(int, 0, watch_sb, struct super_block *sb) #endif /* CONFIG_SECURITY && CONFIG_WATCH_QUEUE */ #if defined(CONFIG_SECURITY) && defined(CONFIG_KEY_NOTIFICATIONS) diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index c503f7ab8afb..11197bf167d3 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -1475,6 +1475,10 @@ * @w_cred: The credentials of the whoever set the watch. * @cred: The event-triggerer's credentials * @n: The notification being posted + * @watch_sb: + * Check to see if a process is allowed to watch for event notifications + * from a superblock. + * @sb: The superblock to watch. * * @watch_key: * Check to see if a process is allowed to watch for event notifications diff --git a/include/linux/security.h b/include/linux/security.h index bc2725491560..078e11a8872a 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -456,6 +456,11 @@ int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen); int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen); int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen); int security_locked_down(enum lockdown_reason what); + +#ifdef CONFIG_WATCH_QUEUE +int security_watch_sb(struct super_block *sb); +#endif /* CONFIG_WATCH_QUEUE */ + #else /* CONFIG_SECURITY */ static inline int call_blocking_lsm_notifier(enum lsm_event event, void *data) @@ -1304,6 +1309,14 @@ static inline int security_locked_down(enum lockdown_reason what) { return 0; } + +#ifdef CONFIG_WATCH_QUEUE +static inline int security_watch_sb(struct super_block *sb) +{ + return 0; +} +#endif /* CONFIG_WATCH_QUEUE */ + #endif /* CONFIG_SECURITY */ #if defined(CONFIG_SECURITY) && defined(CONFIG_WATCH_QUEUE) diff --git a/security/security.c b/security/security.c index a28045dc9e7f..a23a972063cd 100644 --- a/security/security.c +++ b/security/security.c @@ -2074,6 +2074,12 @@ int security_post_notification(const struct cred *w_cred, { return call_int_hook(post_notification, 0, w_cred, cred, n); } + +int security_watch_sb(struct super_block *sb) +{ + return call_int_hook(watch_sb, 0, sb); +} + #endif /* CONFIG_WATCH_QUEUE */ #ifdef CONFIG_KEY_NOTIFICATIONS From patchwork Wed Nov 11 21:52:08 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gabriel Krisman Bertazi X-Patchwork-Id: 11898633 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 3331A1668 for ; Wed, 11 Nov 2020 21:52:41 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 1C8C6208B3 for ; Wed, 11 Nov 2020 21:52:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726746AbgKKVwj (ORCPT ); Wed, 11 Nov 2020 16:52:39 -0500 Received: from bhuna.collabora.co.uk ([46.235.227.227]:49772 "EHLO bhuna.collabora.co.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726723AbgKKVwh (ORCPT ); Wed, 11 Nov 2020 16:52:37 -0500 Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: krisman) with ESMTPSA id DA4F41F45EA4 From: Gabriel Krisman Bertazi To: dhowells@redhat.com Cc: viro@zeniv.linux.org.uk, tytso@mit.edu, khazhy@google.com, adilger.kernel@dilger.ca, linux-ext4@vger.kernel.org, linux-fsdevel@vger.kernel.org, Gabriel Krisman Bertazi , kernel@collabora.com Subject: [PATCH RFC v2 3/8] watch_queue: Support a text field at the end of the notification Date: Wed, 11 Nov 2020 16:52:08 -0500 Message-Id: <20201111215213.4152354-4-krisman@collabora.com> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201111215213.4152354-1-krisman@collabora.com> References: <20201111215213.4152354-1-krisman@collabora.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org This allow notifications to send text information to userspace without having to copy it to a temporary buffer to then copy to the ring. One use case to pass text information in notifications is for error reporting, where more debug information might be needed, but we don't want to explode the number of subtypes of notifications. For instance, ext4 can have a single inode error notification subtype, and pass more information on the cause of the error in this field. Signed-off-by: Gabriel Krisman Bertazi --- include/linux/watch_queue.h | 14 ++++++++++++-- kernel/watch_queue.c | 29 ++++++++++++++++++++++++----- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/include/linux/watch_queue.h b/include/linux/watch_queue.h index f1086d12cd03..2f5a7446bca6 100644 --- a/include/linux/watch_queue.h +++ b/include/linux/watch_queue.h @@ -79,7 +79,7 @@ struct watch_list { extern void __post_watch_notification(struct watch_list *, struct watch_notification *, const struct cred *, - u64); + u64, const char*, va_list*); extern struct watch_queue *get_watch_queue(int); extern void put_watch_queue(struct watch_queue *); extern void init_watch(struct watch *, struct watch_queue *); @@ -105,7 +105,17 @@ static inline void post_watch_notification(struct watch_list *wlist, u64 id) { if (unlikely(wlist)) - __post_watch_notification(wlist, n, cred, id); + __post_watch_notification(wlist, n, cred, id, NULL, NULL); +} + +static inline void post_watch_notification_string(struct watch_list *wlist, + struct watch_notification *n, + const struct cred *cred, + u64 id, const char *fmt, + va_list *args) +{ + if (unlikely(wlist)) + __post_watch_notification(wlist, n, cred, id, fmt, args); } static inline void remove_watch_list(struct watch_list *wlist, u64 id) diff --git a/kernel/watch_queue.c b/kernel/watch_queue.c index 0ef8f65bd2d7..89fcf0420ce7 100644 --- a/kernel/watch_queue.c +++ b/kernel/watch_queue.c @@ -70,13 +70,15 @@ static const struct pipe_buf_operations watch_queue_pipe_buf_ops = { * Post a notification to a watch queue. */ static bool post_one_notification(struct watch_queue *wqueue, - struct watch_notification *n) + struct watch_notification *n, + const char *fmt, va_list *args) { void *p; struct pipe_inode_info *pipe = wqueue->pipe; struct pipe_buffer *buf; struct page *page; unsigned int head, tail, mask, note, offset, len; + int wlen = 0; bool done = false; if (!pipe) @@ -102,6 +104,23 @@ static bool post_one_notification(struct watch_queue *wqueue, get_page(page); len = n->info & WATCH_INFO_LENGTH; p = kmap_atomic(page); + /* + * Write the tail description before the actual header, because + * the string needs to be generated to calculate the final + * notification size, that is passed in the header. + */ + if (fmt) { + wlen = vscnprintf(p + offset + len, WATCH_INFO_LENGTH - len, + fmt, (args ? *args : NULL)); + wlen += 1; /* vscnprintf doesn't include '\0' */ + if (wlen > 0) { + n->info = n->info & ~WATCH_INFO_LENGTH; + n->info |= (len + wlen) & WATCH_INFO_LENGTH; + } else { + /* Drop errors when writing the extra string. */ + wlen = 0; + } + } memcpy(p + offset, n, len); kunmap_atomic(p); @@ -110,7 +129,7 @@ static bool post_one_notification(struct watch_queue *wqueue, buf->private = (unsigned long)wqueue; buf->ops = &watch_queue_pipe_buf_ops; buf->offset = offset; - buf->len = len; + buf->len = (len + wlen); buf->flags = PIPE_BUF_FLAG_WHOLE; pipe->head = head + 1; @@ -175,7 +194,7 @@ static bool filter_watch_notification(const struct watch_filter *wf, void __post_watch_notification(struct watch_list *wlist, struct watch_notification *n, const struct cred *cred, - u64 id) + u64 id, const char *fmt, va_list *args) { const struct watch_filter *wf; struct watch_queue *wqueue; @@ -202,7 +221,7 @@ void __post_watch_notification(struct watch_list *wlist, if (security_post_notification(watch->cred, cred, n) < 0) continue; - post_one_notification(wqueue, n); + post_one_notification(wqueue, n, fmt, args); } rcu_read_unlock(); @@ -522,7 +541,7 @@ int remove_watch_from_object(struct watch_list *wlist, struct watch_queue *wq, * protecting *wqueue from deallocation. */ if (wqueue) { - post_one_notification(wqueue, &n.watch); + post_one_notification(wqueue, &n.watch, NULL, NULL); spin_lock_bh(&wqueue->lock); From patchwork Wed Nov 11 21:52:09 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gabriel Krisman Bertazi X-Patchwork-Id: 11898635 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 3527E1668 for ; Wed, 11 Nov 2020 21:52:42 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0855C208CA for ; Wed, 11 Nov 2020 21:52:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726843AbgKKVwl (ORCPT ); Wed, 11 Nov 2020 16:52:41 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46718 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726781AbgKKVwk (ORCPT ); Wed, 11 Nov 2020 16:52:40 -0500 Received: from bhuna.collabora.co.uk (bhuna.collabora.co.uk [IPv6:2a00:1098:0:82:1000:25:2eeb:e3e3]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 35781C0613D1; Wed, 11 Nov 2020 13:52:40 -0800 (PST) Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: krisman) with ESMTPSA id E0D871F45EAA From: Gabriel Krisman Bertazi To: dhowells@redhat.com Cc: viro@zeniv.linux.org.uk, tytso@mit.edu, khazhy@google.com, adilger.kernel@dilger.ca, linux-ext4@vger.kernel.org, linux-fsdevel@vger.kernel.org, kernel@collabora.com, Gabriel Krisman Bertazi Subject: [PATCH RFC v2 4/8] vfs: Add superblock notifications Date: Wed, 11 Nov 2020 16:52:09 -0500 Message-Id: <20201111215213.4152354-5-krisman@collabora.com> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201111215213.4152354-1-krisman@collabora.com> References: <20201111215213.4152354-1-krisman@collabora.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org From: David Howells Add a superblock event notification facility whereby notifications about superblock events, such as I/O errors (EIO), quota limits being hit (EDQUOT) and running out of space (ENOSPC) can be reported to a monitoring process asynchronously. Note that this does not cover vfsmount topology changes. watch_mount() is used for that. Records are of the following format: struct superblock_notification { struct watch_notification watch; __u64 sb_id; } *n; Where: n->watch.type will be WATCH_TYPE_SB_NOTIFY. n->watch.subtype will indicate the type of event, such as NOTIFY_SUPERBLOCK_READONLY. n->watch.info & WATCH_INFO_LENGTH will indicate the length of the record. n->watch.info & WATCH_INFO_ID will be the fifth argument to watch_sb(), shifted. n->watch.info & NOTIFY_SUPERBLOCK_IS_NOW_RO will be used for NOTIFY_SUPERBLOCK_READONLY, being set if the superblock becomes R/O, and being cleared otherwise. n->sb_id will be the ID of the superblock, as can be retrieved with the fsinfo() syscall, as part of the fsinfo_sb_notifications attribute in the watch_id field. Note that it is permissible for event records to be of variable length - or, at least, the length may be dependent on the subtype. Note also that the queue can be shared between multiple notifications of various types. Signed-off-by: David Howells [Rebase to mainline. Expose inode and block on sb_error. Update API and commit message] Signed-off-by: Gabriel Krisman Bertazi --- arch/x86/entry/syscalls/syscall_32.tbl | 1 + arch/x86/entry/syscalls/syscall_64.tbl | 1 + fs/Kconfig | 12 +++ fs/super.c | 127 +++++++++++++++++++++++++ include/linux/fs.h | 87 +++++++++++++++++ include/linux/syscalls.h | 2 + include/uapi/asm-generic/unistd.h | 4 +- include/uapi/linux/watch_queue.h | 34 ++++++- kernel/sys_ni.c | 3 + 9 files changed, 269 insertions(+), 2 deletions(-) diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl index 0d0667a9fbd7..c481ab8c4454 100644 --- a/arch/x86/entry/syscalls/syscall_32.tbl +++ b/arch/x86/entry/syscalls/syscall_32.tbl @@ -445,3 +445,4 @@ 438 i386 pidfd_getfd sys_pidfd_getfd 439 i386 faccessat2 sys_faccessat2 440 i386 process_madvise sys_process_madvise +441 i386 watch_sb sys_watch_sb diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl index 379819244b91..87efe2577169 100644 --- a/arch/x86/entry/syscalls/syscall_64.tbl +++ b/arch/x86/entry/syscalls/syscall_64.tbl @@ -362,6 +362,7 @@ 438 common pidfd_getfd sys_pidfd_getfd 439 common faccessat2 sys_faccessat2 440 common process_madvise sys_process_madvise +441 common watch_sb sys_watch_sb # # Due to a historical design error, certain syscalls are numbered differently diff --git a/fs/Kconfig b/fs/Kconfig index aa4c12282301..4e96521c37a1 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -117,6 +117,18 @@ source "fs/verity/Kconfig" source "fs/notify/Kconfig" +config SB_NOTIFICATIONS + bool "Superblock event notifications" + select WATCH_QUEUE + help + This option provides support for receiving superblock event + notifications. This makes use of the watch_queue API to + handle the notification buffer and provides the sb_notify() + system call to enable/disable watches. + + Events can include things like changing between R/W and R/O, EIO + generation, ENOSPC generation and EDQUOT generation. + source "fs/quota/Kconfig" source "fs/autofs/Kconfig" diff --git a/fs/super.c b/fs/super.c index a51c2083cd6b..8178a595a336 100644 --- a/fs/super.c +++ b/fs/super.c @@ -37,6 +37,8 @@ #include #include #include +#include +#include #include #include "internal.h" @@ -330,6 +332,10 @@ void deactivate_locked_super(struct super_block *s) { struct file_system_type *fs = s->s_type; if (atomic_dec_and_test(&s->s_active)) { +#ifdef CONFIG_SB_NOTIFICATIONS + if (s->s_watchers) + remove_watch_list(s->s_watchers, s->s_unique_id); +#endif cleancache_invalidate_fs(s); unregister_shrinker(&s->s_shrink); fs->kill_sb(s); @@ -969,6 +975,8 @@ int reconfigure_super(struct fs_context *fc) /* Needs to be ordered wrt mnt_is_readonly() */ smp_wmb(); sb->s_readonly_remount = 0; + notify_sb(sb, NOTIFY_SUPERBLOCK_READONLY, + remount_ro ? NOTIFY_SUPERBLOCK_IS_NOW_RO : 0); /* * Some filesystems modify their metadata via some other path than the @@ -1867,3 +1875,122 @@ int thaw_super(struct super_block *sb) return thaw_super_locked(sb); } EXPORT_SYMBOL(thaw_super); + +#ifdef CONFIG_SB_NOTIFICATIONS +/* + * Post superblock notifications. + */ + +void post_sb_notification(struct super_block *s, struct superblock_notification *n, + const char *fmt, va_list *args) +{ + post_watch_notification_string(s->s_watchers, &n->watch, current_cred(), + s->s_unique_id, fmt, args); +} + +/** + * sys_watch_sb - Watch for superblock events. + * @dfd: Base directory to pathwalk from or fd referring to superblock. + * @filename: Path to superblock to place the watch upon + * @at_flags: Pathwalk control flags + * @watch_fd: The watch queue to send notifications to. + * @watch_id: The watch ID to be placed in the notification (-1 to remove watch) + */ +SYSCALL_DEFINE5(watch_sb, + int, dfd, + const char __user *, filename, + unsigned int, at_flags, + int, watch_fd, + int, watch_id) +{ + struct watch_queue *wqueue; + struct super_block *s; + struct watch_list *wlist = NULL; + struct watch *watch = NULL; + struct path path; + unsigned int lookup_flags = + LOOKUP_DIRECTORY | LOOKUP_FOLLOW | LOOKUP_AUTOMOUNT; + int ret; + + if (watch_id < -1 || watch_id > 0xff) + return -EINVAL; + if ((at_flags & ~(AT_NO_AUTOMOUNT | AT_EMPTY_PATH)) != 0) + return -EINVAL; + if (at_flags & AT_NO_AUTOMOUNT) + lookup_flags &= ~LOOKUP_AUTOMOUNT; + if (at_flags & AT_EMPTY_PATH) + lookup_flags |= LOOKUP_EMPTY; + + ret = user_path_at(dfd, filename, at_flags, &path); + if (ret) + return ret; + + ret = inode_permission(path.dentry->d_inode, MAY_EXEC); + if (ret) + goto err_path; + + wqueue = get_watch_queue(watch_fd); + if (IS_ERR(wqueue)) + goto err_path; + + s = path.dentry->d_sb; + if (watch_id >= 0) { + ret = -ENOMEM; + if (!s->s_watchers) { + wlist = kzalloc(sizeof(*wlist), GFP_KERNEL); + if (!wlist) + goto err_wqueue; + init_watch_list(wlist, NULL); + } + + watch = kzalloc(sizeof(*watch), GFP_KERNEL); + if (!watch) + goto err_wlist; + + init_watch(watch, wqueue); + watch->id = s->s_unique_id; + watch->private = s; + watch->info_id = (u32)watch_id << 24; + + ret = security_watch_sb(s); + if (ret < 0) + goto err_watch; + + down_write(&s->s_umount); + ret = -EIO; + if (atomic_read(&s->s_active)) { + if (!s->s_watchers) { + s->s_watchers = wlist; + wlist = NULL; + } + + ret = add_watch_to_object(watch, s->s_watchers); + if (ret == 0) { + spin_lock(&sb_lock); + s->s_count++; + spin_unlock(&sb_lock); + watch = NULL; + } + } + up_write(&s->s_umount); + } else { + ret = -EBADSLT; + if (READ_ONCE(s->s_watchers)) { + down_write(&s->s_umount); + ret = remove_watch_from_object(s->s_watchers, wqueue, + s->s_unique_id, false); + up_write(&s->s_umount); + } + } + +err_watch: + kfree(watch); +err_wlist: + kfree(wlist); +err_wqueue: + put_watch_queue(wqueue); +err_path: + path_put(&path); + return ret; +} +#endif diff --git a/include/linux/fs.h b/include/linux/fs.h index 21cc971fd960..cf5245f414c2 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -1547,6 +1548,13 @@ struct super_block { spinlock_t s_inode_wblist_lock; struct list_head s_inodes_wb; /* writeback inodes */ + + /* Superblock event notifications */ + u64 s_unique_id; + +#ifdef CONFIG_SB_NOTIFICATIONS + struct watch_list *s_watchers; +#endif } __randomize_layout; /* Helper functions so that in most cases filesystems will @@ -3460,4 +3468,83 @@ static inline int inode_drain_writes(struct inode *inode) return filemap_write_and_wait(inode->i_mapping); } +extern void post_sb_notification(struct super_block *, struct superblock_notification *, + const char *fmt, va_list *args); +/** + * notify_sb: Post simple superblock notification. + * @s: The superblock the notification is about. + * @subtype: The type of notification. + * @info: WATCH_INFO_FLAG_* flags to be set in the record. + */ +static inline void notify_sb(struct super_block *s, + enum superblock_notification_type subtype, + u32 info) +{ +#ifdef CONFIG_SB_NOTIFICATIONS + if (unlikely(s->s_watchers)) { + struct superblock_notification n = { + .watch.type = WATCH_TYPE_SB_NOTIFY, + .watch.subtype = subtype, + .watch.info = watch_sizeof(n) | info, + .sb_id = s->s_unique_id, + }; + + post_sb_notification(s, &n, NULL, NULL); + } + +#endif +} + +/** + * notify_sb_error: Post superblock error notification. + * @s: The superblock the notification is about. + * @error: The error number to be recorded. + * @inode: The inode the error refers to (if available, 0 otherwise) + * @block: The block the error refers to (if available, 0 otherwise) + * @fmt: Formating string for extra information appended to the notification + * @args: arguments for extra information string appended to the notification + */ +static inline int notify_sb_error(struct super_block *s, int error, u64 inode, + u64 block, const char *fmt, va_list *args) +{ +#ifdef CONFIG_SB_NOTIFICATIONS + if (unlikely(s->s_watchers)) { + struct superblock_error_notification n = { + .s.watch.type = WATCH_TYPE_SB_NOTIFY, + .s.watch.subtype = NOTIFY_SUPERBLOCK_ERROR, + .s.watch.info = watch_sizeof(n), + .s.sb_id = s->s_unique_id, + .error_number = error, + .error_cookie = 0, + .inode = inode, + .block = block, + }; + + post_sb_notification(s, &n.s, fmt, args); + } +#endif + return error; +} + +/** + * notify_sb_EDQUOT: Post superblock quota overrun notification. + * @s: The superblock the notification is about. + */ +static inline int notify_sb_EQDUOT(struct super_block *s) +{ +#ifdef CONFIG_SB_NOTIFICATIONS + if (unlikely(s->s_watchers)) { + struct superblock_notification n = { + .watch.type = WATCH_TYPE_SB_NOTIFY, + .watch.subtype = NOTIFY_SUPERBLOCK_EDQUOT, + .watch.info = watch_sizeof(n), + .sb_id = s->s_unique_id, + }; + + post_sb_notification(s, &n, NULL, NULL); + } +#endif + return -EDQUOT; +} + #endif /* _LINUX_FS_H */ diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 37bea07c12f2..5f7b282d331d 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -1008,6 +1008,8 @@ asmlinkage long sys_pidfd_send_signal(int pidfd, int sig, siginfo_t __user *info, unsigned int flags); asmlinkage long sys_pidfd_getfd(int pidfd, int fd, unsigned int flags); +asmlinkage long sys_watch_sb(int dfd, const char __user *path, + unsigned int at_flags, int watch_fd, int watch_id); /* * Architecture-specific system calls diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h index 2056318988f7..5eec69e2b312 100644 --- a/include/uapi/asm-generic/unistd.h +++ b/include/uapi/asm-generic/unistd.h @@ -859,9 +859,11 @@ __SYSCALL(__NR_pidfd_getfd, sys_pidfd_getfd) __SYSCALL(__NR_faccessat2, sys_faccessat2) #define __NR_process_madvise 440 __SYSCALL(__NR_process_madvise, sys_process_madvise) +#define __NR_watch_sb 441 +__SYSCALL(__NR_watch_sb, sys_watch_sb) #undef __NR_syscalls -#define __NR_syscalls 441 +#define __NR_syscalls 442 /* * 32 bit systems traditionally used different diff --git a/include/uapi/linux/watch_queue.h b/include/uapi/linux/watch_queue.h index c3d8320b5d3a..937363d9f7b3 100644 --- a/include/uapi/linux/watch_queue.h +++ b/include/uapi/linux/watch_queue.h @@ -14,7 +14,8 @@ enum watch_notification_type { WATCH_TYPE_META = 0, /* Special record */ WATCH_TYPE_KEY_NOTIFY = 1, /* Key change event notification */ - WATCH_TYPE__NR = 2 + WATCH_TYPE_SB_NOTIFY = 2, + WATCH_TYPE__NR = 3 }; enum watch_meta_notification_subtype { @@ -101,4 +102,35 @@ struct key_notification { __u32 aux; /* Per-type auxiliary data */ }; +/* + * Type of superblock notification. + */ +enum superblock_notification_type { + NOTIFY_SUPERBLOCK_READONLY = 0, /* Filesystem toggled between R/O and R/W */ + NOTIFY_SUPERBLOCK_ERROR = 1, /* Error in filesystem or blockdev */ + NOTIFY_SUPERBLOCK_EDQUOT = 2, /* EDQUOT notification */ + NOTIFY_SUPERBLOCK_NETWORK = 3, /* Network status change */ +}; + +#define NOTIFY_SUPERBLOCK_IS_NOW_RO WATCH_INFO_FLAG_0 /* Superblock changed to R/O */ + +/* + * Superblock notification record. + * - watch.type = WATCH_TYPE_MOUNT_NOTIFY + * - watch.subtype = enum superblock_notification_subtype + */ +struct superblock_notification { + struct watch_notification watch; /* WATCH_TYPE_SB_NOTIFY */ + __u64 sb_id; /* 64-bit superblock ID [fsinfo_ids::f_sb_id] */ +}; + +struct superblock_error_notification { + struct superblock_notification s; /* subtype = notify_superblock_error */ + __u32 error_number; + __u32 error_cookie; + __u64 inode; + __u64 block; + char desc[0]; +}; + #endif /* _UAPI_LINUX_WATCH_QUEUE_H */ diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c index f27ac94d5fa7..3e97984bc4c8 100644 --- a/kernel/sys_ni.c +++ b/kernel/sys_ni.c @@ -51,6 +51,9 @@ COND_SYSCALL_COMPAT(io_pgetevents); COND_SYSCALL(io_uring_setup); COND_SYSCALL(io_uring_enter); COND_SYSCALL(io_uring_register); +COND_SYSCALL(fsinfo); +COND_SYSCALL(watch_mount); +COND_SYSCALL(watch_sb); /* fs/xattr.c */ From patchwork Wed Nov 11 21:52:10 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gabriel Krisman Bertazi X-Patchwork-Id: 11898637 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E6B1E921 for ; Wed, 11 Nov 2020 21:52:45 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id CEC60208B3 for ; Wed, 11 Nov 2020 21:52:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726865AbgKKVwo (ORCPT ); Wed, 11 Nov 2020 16:52:44 -0500 Received: from bhuna.collabora.co.uk ([46.235.227.227]:49794 "EHLO bhuna.collabora.co.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726766AbgKKVwo (ORCPT ); Wed, 11 Nov 2020 16:52:44 -0500 Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: krisman) with ESMTPSA id 5BB801F45EB0 From: Gabriel Krisman Bertazi To: dhowells@redhat.com Cc: viro@zeniv.linux.org.uk, tytso@mit.edu, khazhy@google.com, adilger.kernel@dilger.ca, linux-ext4@vger.kernel.org, linux-fsdevel@vger.kernel.org, Gabriel Krisman Bertazi , kernel@collabora.com Subject: [PATCH RFC v2 5/8] vfs: Include origin of the SB error notification Date: Wed, 11 Nov 2020 16:52:10 -0500 Message-Id: <20201111215213.4152354-6-krisman@collabora.com> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201111215213.4152354-1-krisman@collabora.com> References: <20201111215213.4152354-1-krisman@collabora.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org When reporting a filesystem error, we really need to know where the error came from, therefore, include "function:line" information in the notification sent to userspace. There is no current users of notify_sb in the kernel, so there are no callers to update. Signed-off-by: Gabriel Krisman Bertazi --- include/linux/fs.h | 11 +++++++++-- include/uapi/linux/watch_queue.h | 3 +++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/include/linux/fs.h b/include/linux/fs.h index cf5245f414c2..81aaa673ada7 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -3498,14 +3498,17 @@ static inline void notify_sb(struct super_block *s, /** * notify_sb_error: Post superblock error notification. * @s: The superblock the notification is about. + * @function: function name reported as source of the warning. + * @line: source code line reported as source of the warning. * @error: The error number to be recorded. * @inode: The inode the error refers to (if available, 0 otherwise) * @block: The block the error refers to (if available, 0 otherwise) * @fmt: Formating string for extra information appended to the notification * @args: arguments for extra information string appended to the notification */ -static inline int notify_sb_error(struct super_block *s, int error, u64 inode, - u64 block, const char *fmt, va_list *args) +static inline int notify_sb_error(struct super_block *s, const char *function, int line, + int error, u64 inode, u64 block, + const char *fmt, va_list *args) { #ifdef CONFIG_SB_NOTIFICATIONS if (unlikely(s->s_watchers)) { @@ -3518,8 +3521,12 @@ static inline int notify_sb_error(struct super_block *s, int error, u64 inode, .error_cookie = 0, .inode = inode, .block = block, + .line = line, }; + memcpy(&n.function, function, SB_NOTIFICATION_FNAME_LEN); + n.function[SB_NOTIFICATION_FNAME_LEN-1] = '\0'; + post_sb_notification(s, &n.s, fmt, args); } #endif diff --git a/include/uapi/linux/watch_queue.h b/include/uapi/linux/watch_queue.h index 937363d9f7b3..5fa5286c5cc7 100644 --- a/include/uapi/linux/watch_queue.h +++ b/include/uapi/linux/watch_queue.h @@ -114,6 +114,7 @@ enum superblock_notification_type { #define NOTIFY_SUPERBLOCK_IS_NOW_RO WATCH_INFO_FLAG_0 /* Superblock changed to R/O */ +#define SB_NOTIFICATION_FNAME_LEN 30 /* * Superblock notification record. * - watch.type = WATCH_TYPE_MOUNT_NOTIFY @@ -130,6 +131,8 @@ struct superblock_error_notification { __u32 error_cookie; __u64 inode; __u64 block; + char function[SB_NOTIFICATION_FNAME_LEN]; + __u16 line; char desc[0]; }; From patchwork Wed Nov 11 21:52:11 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gabriel Krisman Bertazi X-Patchwork-Id: 11898639 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 002E0921 for ; Wed, 11 Nov 2020 21:52:53 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id DCDC7208B3 for ; Wed, 11 Nov 2020 21:52:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726953AbgKKVwv (ORCPT ); Wed, 11 Nov 2020 16:52:51 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46752 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726255AbgKKVwv (ORCPT ); Wed, 11 Nov 2020 16:52:51 -0500 Received: from bhuna.collabora.co.uk (bhuna.collabora.co.uk [IPv6:2a00:1098:0:82:1000:25:2eeb:e3e3]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5325DC0613D1; Wed, 11 Nov 2020 13:52:51 -0800 (PST) Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: krisman) with ESMTPSA id 8A3D21F45E06 From: Gabriel Krisman Bertazi To: dhowells@redhat.com Cc: viro@zeniv.linux.org.uk, tytso@mit.edu, khazhy@google.com, adilger.kernel@dilger.ca, linux-ext4@vger.kernel.org, linux-fsdevel@vger.kernel.org, Gabriel Krisman Bertazi , kernel@collabora.com Subject: [PATCH RFC v2 6/8] fs: Add more superblock error subtypes Date: Wed, 11 Nov 2020 16:52:11 -0500 Message-Id: <20201111215213.4152354-7-krisman@collabora.com> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201111215213.4152354-1-krisman@collabora.com> References: <20201111215213.4152354-1-krisman@collabora.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org Expose new SB notification subtype for warnings, errors and general messages. This is modeled after the information exposed by ext4, but should be the same for other filesystems. Signed-off-by: Gabriel Krisman Bertazi --- include/linux/fs.h | 56 ++++++++++++++++++++++++++++++++ include/uapi/linux/watch_queue.h | 17 ++++++++++ 2 files changed, 73 insertions(+) diff --git a/include/linux/fs.h b/include/linux/fs.h index 81aaa673ada7..9c241689d8bc 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -3533,6 +3533,62 @@ static inline int notify_sb_error(struct super_block *s, const char *function, i return error; } +/** + * notify_sb_warning: Post superblock warning notification. + * @s: The superblock the notification is about. + * @function: function name reported as source of the warning. + * @line: source code line reported as source of the warning. + * @inode: The inode the error refers to (if available, 0 otherwise) + * @block: The block the error refers to (if available, 0 otherwise) + * @fmt: Formating string for extra information appended to the notification + * @args: arguments for extra information string appended to the notification + */ +static inline void notify_sb_warning(struct super_block *s, const char *function, + int line, u64 inode, u64 block, + const char *fmt, va_list *args) +{ +#ifdef CONFIG_SB_NOTIFICATIONS + if (unlikely(s->s_watchers)) { + struct superblock_error_notification n = { + .s.watch.type = WATCH_TYPE_SB_NOTIFY, + .s.watch.subtype = NOTIFY_SUPERBLOCK_WARNING, + .s.watch.info = watch_sizeof(n), + .s.sb_id = s->s_unique_id, + .inode = inode, + .block = block, + .line = line, + }; + + memcpy(&n.function, function, SB_NOTIFICATION_FNAME_LEN); + n.function[SB_NOTIFICATION_FNAME_LEN-1] = '\0'; + + post_sb_notification(s, &n.s, fmt, args); + } +#endif +} + +/** + * notify_sb_msg: Post superblock message. + * @s: The superblock the notification is about. + * @fmt: Formating string for extra information appended to the notification + * @args: arguments for extra information string appended to the notification + */ +static inline void notify_sb_msg(struct super_block *s, const char *fmt, va_list *args) +{ +#ifdef CONFIG_SB_NOTIFICATIONS + if (unlikely(s->s_watchers)) { + struct superblock_msg_notification n = { + .s.watch.type = WATCH_TYPE_SB_NOTIFY, + .s.watch.subtype = NOTIFY_SUPERBLOCK_MSG, + .s.watch.info = watch_sizeof(n), + .s.sb_id = s->s_unique_id, + }; + + post_sb_notification(s, &n.s, fmt, args); + } +#endif +} + /** * notify_sb_EDQUOT: Post superblock quota overrun notification. * @s: The superblock the notification is about. diff --git a/include/uapi/linux/watch_queue.h b/include/uapi/linux/watch_queue.h index 5fa5286c5cc7..c4afd545e234 100644 --- a/include/uapi/linux/watch_queue.h +++ b/include/uapi/linux/watch_queue.h @@ -110,6 +110,9 @@ enum superblock_notification_type { NOTIFY_SUPERBLOCK_ERROR = 1, /* Error in filesystem or blockdev */ NOTIFY_SUPERBLOCK_EDQUOT = 2, /* EDQUOT notification */ NOTIFY_SUPERBLOCK_NETWORK = 3, /* Network status change */ + NOTIFY_SUPERBLOCK_MSG = 4, /* Filesystem message */ + NOTIFY_SUPERBLOCK_WARNING = 5, /* Filesystem warning */ + }; #define NOTIFY_SUPERBLOCK_IS_NOW_RO WATCH_INFO_FLAG_0 /* Superblock changed to R/O */ @@ -136,4 +139,18 @@ struct superblock_error_notification { char desc[0]; }; +struct superblock_msg_notification { + struct superblock_notification s; /* subtype = notify_superblock_msg */ + char desc[0]; +}; + +struct superblock_warning_notification { + struct superblock_notification s; /* subtype = notify_superblock_warning */ + __u64 inode; + __u64 block; + char function[SB_NOTIFICATION_FNAME_LEN]; + __u16 line; + char desc[0]; +}; + #endif /* _UAPI_LINUX_WATCH_QUEUE_H */ From patchwork Wed Nov 11 21:52:12 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gabriel Krisman Bertazi X-Patchwork-Id: 11898641 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id DEF27921 for ; Wed, 11 Nov 2020 21:52:56 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id C5874208FE for ; Wed, 11 Nov 2020 21:52:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726871AbgKKVwz (ORCPT ); Wed, 11 Nov 2020 16:52:55 -0500 Received: from bhuna.collabora.co.uk ([46.235.227.227]:49818 "EHLO bhuna.collabora.co.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726188AbgKKVwz (ORCPT ); Wed, 11 Nov 2020 16:52:55 -0500 Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: krisman) with ESMTPSA id A2A7C1F45DAF From: Gabriel Krisman Bertazi To: dhowells@redhat.com Cc: viro@zeniv.linux.org.uk, tytso@mit.edu, khazhy@google.com, adilger.kernel@dilger.ca, linux-ext4@vger.kernel.org, linux-fsdevel@vger.kernel.org, Gabriel Krisman Bertazi , kernel@collabora.com Subject: [PATCH RFC v2 7/8] ext4: Implement SB error notification through watch_sb Date: Wed, 11 Nov 2020 16:52:12 -0500 Message-Id: <20201111215213.4152354-8-krisman@collabora.com> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201111215213.4152354-1-krisman@collabora.com> References: <20201111215213.4152354-1-krisman@collabora.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org This follows the same implementation of ext4 error reporting via dmesg, but expose that information via the new watch_queue notifications API. Signed-off-by: Gabriel Krisman Bertazi --- fs/ext4/super.c | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index c3b864588a0b..58dc1e48b683 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -724,15 +724,17 @@ void __ext4_error(struct super_block *sb, const char *function, return; trace_ext4_error(sb, function, line); + va_start(args, fmt); if (ext4_error_ratelimit(sb)) { - va_start(args, fmt); vaf.fmt = fmt; vaf.va = &args; printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: comm %s: %pV\n", sb->s_id, function, line, current->comm, &vaf); - va_end(args); } + notify_sb_error(sb, function, line, error, 0, 0, fmt, &args); + va_end(args); + save_error_info(sb, error, 0, block, function, line); ext4_handle_error(sb); } @@ -748,8 +750,8 @@ void __ext4_error_inode(struct inode *inode, const char *function, return; trace_ext4_error(inode->i_sb, function, line); + va_start(args, fmt); if (ext4_error_ratelimit(inode->i_sb)) { - va_start(args, fmt); vaf.fmt = fmt; vaf.va = &args; if (block) @@ -762,8 +764,11 @@ void __ext4_error_inode(struct inode *inode, const char *function, "inode #%lu: comm %s: %pV\n", inode->i_sb->s_id, function, line, inode->i_ino, current->comm, &vaf); - va_end(args); } + notify_sb_error(inode->i_sb, function, line, error, inode->i_ino, block, + fmt, &args); + va_end(args); + save_error_info(inode->i_sb, error, inode->i_ino, block, function, line); ext4_handle_error(inode->i_sb); @@ -782,11 +787,11 @@ void __ext4_error_file(struct file *file, const char *function, return; trace_ext4_error(inode->i_sb, function, line); + va_start(args, fmt); if (ext4_error_ratelimit(inode->i_sb)) { path = file_path(file, pathname, sizeof(pathname)); if (IS_ERR(path)) path = "(unknown)"; - va_start(args, fmt); vaf.fmt = fmt; vaf.va = &args; if (block) @@ -801,8 +806,11 @@ void __ext4_error_file(struct file *file, const char *function, "comm %s: path %s: %pV\n", inode->i_sb->s_id, function, line, inode->i_ino, current->comm, path, &vaf); - va_end(args); } + notify_sb_error(inode->i_sb, function, line, EFSCORRUPTED, + inode->i_ino, block, fmt, &args); + va_end(args); + save_error_info(inode->i_sb, EFSCORRUPTED, inode->i_ino, block, function, line); ext4_handle_error(inode->i_sb); @@ -872,6 +880,8 @@ void __ext4_std_error(struct super_block *sb, const char *function, sb->s_id, function, line, errstr); } + notify_sb_error(sb, function, line, errno, 0, 0, errstr, NULL); + save_error_info(sb, -errno, 0, 0, function, line); ext4_handle_error(sb); } @@ -901,6 +911,7 @@ void __ext4_abort(struct super_block *sb, const char *function, vaf.va = &args; printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: %pV\n", sb->s_id, function, line, &vaf); + notify_sb_error(sb, function, line, error, 0, 0, fmt, &args); va_end(args); if (sb_rdonly(sb) == 0) { @@ -934,6 +945,7 @@ void __ext4_msg(struct super_block *sb, vaf.fmt = fmt; vaf.va = &args; printk("%sEXT4-fs (%s): %pV\n", prefix, sb->s_id, &vaf); + notify_sb_msg(sb, fmt, &args); va_end(args); } @@ -958,6 +970,7 @@ void __ext4_warning(struct super_block *sb, const char *function, vaf.va = &args; printk(KERN_WARNING "EXT4-fs warning (device %s): %s:%d: %pV\n", sb->s_id, function, line, &vaf); + notify_sb_warning(sb, function, line, 0, 0, fmt, &args); va_end(args); } @@ -976,6 +989,7 @@ void __ext4_warning_inode(const struct inode *inode, const char *function, printk(KERN_WARNING "EXT4-fs warning (device %s): %s:%d: " "inode #%lu: comm %s: %pV\n", inode->i_sb->s_id, function, line, inode->i_ino, current->comm, &vaf); + notify_sb_warning(inode->i_sb, function, line, inode->i_ino, 0, fmt, &args); va_end(args); } @@ -995,8 +1009,8 @@ __acquires(bitlock) trace_ext4_error(sb, function, line); __save_error_info(sb, EFSCORRUPTED, ino, block, function, line); + va_start(args, fmt); if (ext4_error_ratelimit(sb)) { - va_start(args, fmt); vaf.fmt = fmt; vaf.va = &args; printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: group %u, ", @@ -1007,8 +1021,9 @@ __acquires(bitlock) printk(KERN_CONT "block %llu:", (unsigned long long) block); printk(KERN_CONT "%pV\n", &vaf); - va_end(args); } + notify_sb_error(sb, function, line, EFSCORRUPTED, ino, block, fmt, &args); + va_end(args); if (test_opt(sb, WARN_ON_ERROR)) WARN_ON_ONCE(1); From patchwork Wed Nov 11 21:52:13 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gabriel Krisman Bertazi X-Patchwork-Id: 11898643 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 89F0B1668 for ; Wed, 11 Nov 2020 21:52:59 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 71DF5208FE for ; Wed, 11 Nov 2020 21:52:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726960AbgKKVw6 (ORCPT ); Wed, 11 Nov 2020 16:52:58 -0500 Received: from bhuna.collabora.co.uk ([46.235.227.227]:49830 "EHLO bhuna.collabora.co.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726188AbgKKVw6 (ORCPT ); Wed, 11 Nov 2020 16:52:58 -0500 Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: krisman) with ESMTPSA id 6716E1F45DC8 From: Gabriel Krisman Bertazi To: dhowells@redhat.com Cc: viro@zeniv.linux.org.uk, tytso@mit.edu, khazhy@google.com, adilger.kernel@dilger.ca, linux-ext4@vger.kernel.org, linux-fsdevel@vger.kernel.org, Gabriel Krisman Bertazi , kernel@collabora.com Subject: [PATCH RFC v2 8/8] samples: watch_queue: Add sample of SB notifications Date: Wed, 11 Nov 2020 16:52:13 -0500 Message-Id: <20201111215213.4152354-9-krisman@collabora.com> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201111215213.4152354-1-krisman@collabora.com> References: <20201111215213.4152354-1-krisman@collabora.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org This sample demonstrates how to use the watch_sb syscall. It exposes notifications like the following: root@host:~# ./watch_sb /mnt read() = 93 NOTIFY[000]: ty=000002 sy=01 i=0300005d SB AT ext4_remount:5636 ERROR: 16 inode=0 block=0 description: Abort forced by user read() = 96 NOTIFY[000]: ty=000002 sy=01 i=03000060 SB AT ext4_lookup:1706 ERROR: 0 inode=13 block=0 description: iget: bogus i_mode (45) Signed-off-by: Gabriel Krisman Bertazi --- samples/watch_queue/Makefile | 2 +- samples/watch_queue/watch_sb.c | 114 +++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 samples/watch_queue/watch_sb.c diff --git a/samples/watch_queue/Makefile b/samples/watch_queue/Makefile index c0db3a6bc524..6067d57a5bb1 100644 --- a/samples/watch_queue/Makefile +++ b/samples/watch_queue/Makefile @@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only -userprogs-always-y += watch_test +userprogs-always-y += watch_test watch_sb userccflags += -I usr/include diff --git a/samples/watch_queue/watch_sb.c b/samples/watch_queue/watch_sb.c new file mode 100644 index 000000000000..51b660334f6b --- /dev/null +++ b/samples/watch_queue/watch_sb.c @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Use watch_sb to watch for SB notifications. + * + * Copyright (C) 2020 Collabora Ltd. + * Written by Gabriel Krisman Bertazi + * Based on watch_test.c by David Howells (dhowells@redhat.com) + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifndef __NR_watch_sb +# define __NR_watch_sb 441 +#endif + +static void consumer(int fd) +{ + unsigned char buffer[433], *p, *end; + union { + struct watch_notification n; + unsigned char buf1[128]; + struct superblock_error_notification sen; + struct superblock_warning_notification swn; + struct superblock_msg_notification smn; + } n; + ssize_t buf_len; + + for (;;) { + buf_len = read(fd, buffer, sizeof(buffer)); + if (buf_len == -1) + err(1, "read"); + + if (buf_len == 0) { + printf("-- END --\n"); + return; + } + + if (buf_len > sizeof(buffer)) { + err(1, "Read buffer overrun: %zd\n", buf_len); + return; + } + + printf("read() = %zd\n", buf_len); + + p = buffer; + end = buffer + buf_len; + while (p < end) { + size_t largest, len; + + largest = end - p; + if (largest > 128) + largest = 128; + if (largest < sizeof(struct watch_notification)) + err(1, "Short message header: %zu\n", largest); + + memcpy(&n, p, largest); + + printf("NOTIFY[%03zx]: ty=%06x sy=%02x i=%08x\n", + p - buffer, n.n.type, n.n.subtype, n.n.info); + + len = n.n.info & WATCH_INFO_LENGTH; + if (len < sizeof(n.n) || len > largest) + err(1, "Bad message length: %zu/%zu\n", len, largest); + + switch (n.n.subtype) { + case NOTIFY_SUPERBLOCK_ERROR: + printf("\t SB AT %s:%d ERROR: %d inode=%llu block=%llu\n", + n.sen.function, n.sen.line, n.sen.error_number, + n.sen.inode, n.sen.block); + if (len > sizeof(n.sen)) + printf("description: %s\n", n.sen.desc); + break; + case NOTIFY_SUPERBLOCK_MSG: + printf("\t Ext4 MSG: %s\n", n.smn.desc); + break; + case NOTIFY_SUPERBLOCK_WARNING: + printf("\t SB AT %s:%d WARNING inode=%llu block=%llu\n", + n.swn.function, n.swn.line, n.swn.inode, n.swn.block); + if (len > sizeof(n.sen)) + printf("description: %s\n", n.swn.desc); + break; + default: + printf("unknown subtype %c\n", n.n.subtype); + } + p += len; + } + } +} + +int main (int argc, char **argv) +{ + int fd[2]; + + if (argc != 2) + errx(1, "Missing mount point\n"); + + if (syscall(293, fd, O_NOTIFICATION_PIPE) < 0) + err(1, "Failed to open pipe\n"); + + if (ioctl(fd[0], IOC_WATCH_QUEUE_SET_SIZE, 256) < 0) + err(1, "ioctl fail\n"); + + if (syscall(__NR_watch_sb, 0, argv[1], NULL, fd[0], 0x3) < 0) + err(1, "Failed to watch SB\n"); + + consumer(fd[0]); + + return 0; +}