From patchwork Tue Dec 31 23:47:58 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13924070 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 348E229415 for ; Tue, 31 Dec 2024 23:47:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735688879; cv=none; b=oavDYZMMSDM/qoAO8s+2BzZuRkoedKwibNS4usbGEGTV5sYVN8moE7T8NMmpx+jbH1iAHJpfC+X5QKQS9XCNRnd94trdKjHSzWkKLBDQ2xzW8hQ8drb9yJEPADbG3q9SJQptqObbmdupmgpvHQtptSFUKCINlq67BCKg7b9ZZA0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735688879; c=relaxed/simple; bh=LjusH2PxP+GNtXvK1bhZVyveE0hQJrey2O7/Hu/DV7g=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=MK+gJeTilmuGBBn9FdlvO2o32VL1efgoH0kHl+Hw0INNyTLwxAcpO7M3T260LgksMmPdsu/JNH1hwyiUIjvQGtNcS4TBoCZbbxN8Ay1QCgy1qRjKQhQKciaR4X899reczeMN2/IoxwExlF6wH66akntfRl6JdzS09WYhDOmV+cs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Lr29jpwa; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Lr29jpwa" Received: by smtp.kernel.org (Postfix) with ESMTPSA id A24B8C4CED2; Tue, 31 Dec 2024 23:47:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1735688878; bh=LjusH2PxP+GNtXvK1bhZVyveE0hQJrey2O7/Hu/DV7g=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=Lr29jpwarFP8UpQzTwT0lgiwf8YAVETgzBXjo2NU1CuUVUyY30EZMGr+ea8+X//uR bKPB7vXfgh2uj+zXLkXAKUdq7sQOkJvX59em6zDgLX36mPYiO1puPWyJnV8SGuSYpC qapHU7MhfwXNGbG876qm0V/C0OtD40T+NKK+JpizTMua5u8Lcptigz3ZAt+Kte3E7k u9+f+sEyfiPRvgnTBlliNzOMjCgVwsl0Fq1QPBJfy/+kYc44ffLdbtFcbRP7PzGXqH pydpTurotUf6x9RR+M+cMVsxyGq2ISq/6nzXDg2gZifwCxzOqP+zXwBeDax+vgf4me qJSJUc3ZvrEnQ== Date: Tue, 31 Dec 2024 15:47:58 -0800 Subject: [PATCH 01/21] xfs: create hooks for monitoring health updates From: "Darrick J. Wong" To: aalbersh@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <173568778474.2710211.1014685356160559759.stgit@frogsfrogsfrogs> In-Reply-To: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> References: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Create hooks for monitoring health events. Signed-off-by: "Darrick J. Wong" --- libxfs/xfs_health.h | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/libxfs/xfs_health.h b/libxfs/xfs_health.h index b31000f7190ce5..39fef33dedc6a8 100644 --- a/libxfs/xfs_health.h +++ b/libxfs/xfs_health.h @@ -289,4 +289,51 @@ void xfs_bulkstat_health(struct xfs_inode *ip, struct xfs_bulkstat *bs); #define xfs_metadata_is_sick(error) \ (unlikely((error) == -EFSCORRUPTED || (error) == -EFSBADCRC)) +/* + * Parameters for tracking health updates. The enum below is passed as the + * hook function argument. + */ +enum xfs_health_update_type { + XFS_HEALTHUP_SICK = 1, /* runtime corruption observed */ + XFS_HEALTHUP_CORRUPT, /* fsck reported corruption */ + XFS_HEALTHUP_HEALTHY, /* fsck reported healthy structure */ + XFS_HEALTHUP_UNMOUNT, /* filesystem is unmounting */ +}; + +/* Where in the filesystem was the event observed? */ +enum xfs_health_update_domain { + XFS_HEALTHUP_FS = 1, /* main filesystem */ + XFS_HEALTHUP_AG, /* allocation group */ + XFS_HEALTHUP_INODE, /* inode */ + XFS_HEALTHUP_RTGROUP, /* realtime group */ +}; + +struct xfs_health_update_params { + /* XFS_HEALTHUP_INODE */ + xfs_ino_t ino; + uint32_t gen; + + /* XFS_HEALTHUP_AG/RTGROUP */ + uint32_t group; + + /* XFS_SICK_* flags */ + unsigned int old_mask; + unsigned int new_mask; + + enum xfs_health_update_domain domain; +}; + +#ifdef CONFIG_XFS_LIVE_HOOKS +struct xfs_health_hook { + struct xfs_hook health_hook; +}; + +void xfs_health_hook_disable(void); +void xfs_health_hook_enable(void); + +int xfs_health_hook_add(struct xfs_mount *mp, struct xfs_health_hook *hook); +void xfs_health_hook_del(struct xfs_mount *mp, struct xfs_health_hook *hook); +void xfs_health_hook_setup(struct xfs_health_hook *hook, notifier_fn_t mod_fn); +#endif /* CONFIG_XFS_LIVE_HOOKS */ + #endif /* __XFS_HEALTH_H__ */ From patchwork Tue Dec 31 23:48:13 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13924071 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6A84D1B0425 for ; Tue, 31 Dec 2024 23:48:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735688894; cv=none; b=dqy4pL6OAUo5+P/GZNwdOTT9uF/8adrgBn3mrjDVX3B+qYlRCOxRL0bRv1pWzMOp/3pTt0VL/HJtwYphcneMJ17gVbaJVcf44thDXwG5qcnROO5SffSdLnySbtpusgu0ipJbABh8XJhGAaT/rfDXh1WEPoB6O3M858qGABVS1EY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735688894; c=relaxed/simple; bh=3o5tLxECcPqexA+7liD5fuzVzTkCbj75UANvONLluJ0=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Og5lpDGlN6tQ/U7UNhIW1r1P8ibA1unIud2OoxrLjjz05cx2CZmGP5nT540jA7gexXrKOnzV9rMcwgc+ECebz2vAXZcln8rc10yiSbFKRWO2hZp89nz4HVkfpPgrq+jy+lUS8y8mFZ0fXTv5Wf/AWUCwoKHiHi1BLOEy6B9JOvQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=NnFl39w3; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="NnFl39w3" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 46DC5C4CED2; Tue, 31 Dec 2024 23:48:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1735688894; bh=3o5tLxECcPqexA+7liD5fuzVzTkCbj75UANvONLluJ0=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=NnFl39w3mUSQawgRFthXMcXgSSYq43/RpAjmYt7umuLPZXhZb+SwKrZTm2QSiJ00V P4jpVgsnPZMHAhTExSG2Ee6BfpxZ/7C3COh6xk3WXM5b+OvlRfhaG+hMQgPQ/VxIME /n5mZO+k1m+fw8S8ZOhG1BEhYpxWMlP5fs+HeZ26ARufyyiOTvziZ4ZPpfZWLGkCKA gzlhq4t01qYCGTAYhxX5dRapMWunBRw5fxIBpuJoub+s8rgCq6cTV+rPnT0j99eiJC 1VDiAXBdHdzbEP95yKgnzv09+d5B7oGoMXrfwOq+cho2hK+jEd/oo/xbwDynDHbZVT v+WhWbWt5Wp5g== Date: Tue, 31 Dec 2024 15:48:13 -0800 Subject: [PATCH 02/21] xfs: create a special file to pass filesystem health to userspace From: "Darrick J. Wong" To: aalbersh@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <173568778490.2710211.13224859037235411069.stgit@frogsfrogsfrogs> In-Reply-To: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> References: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Create an ioctl that installs a file descriptor backed by an anon_inode file that will convey filesystem health events to userspace. Signed-off-by: "Darrick J. Wong" --- libxfs/xfs_fs.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libxfs/xfs_fs.h b/libxfs/xfs_fs.h index f4128dbdf3b9a2..d1a81b02a1a3f3 100644 --- a/libxfs/xfs_fs.h +++ b/libxfs/xfs_fs.h @@ -1100,6 +1100,13 @@ struct xfs_map_freesp { __u64 pad; /* must be zero */ }; +struct xfs_health_monitor { + __u64 flags; /* flags */ + __u8 format; /* output format */ + __u8 pad1[7]; /* zeroes */ + __u64 pad2[2]; /* zeroes */ +}; + /* * ioctl commands that are used by Linux filesystems */ @@ -1141,6 +1148,7 @@ struct xfs_map_freesp { #define XFS_IOC_RTGROUP_GEOMETRY _IOWR('X', 65, struct xfs_rtgroup_geometry) #define XFS_IOC_GETFSREFCOUNTS _IOWR('X', 66, struct xfs_getfsrefs_head) #define XFS_IOC_MAP_FREESP _IOW ('X', 67, struct xfs_map_freesp) +#define XFS_IOC_HEALTH_MONITOR _IOW ('X', 68, struct xfs_health_monitor) /* * ioctl commands that replace IRIX syssgi()'s From patchwork Tue Dec 31 23:48:29 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13924072 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5F66B29415 for ; Tue, 31 Dec 2024 23:48:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735688910; cv=none; b=EtPsfGLeLUEIQwGogzl86uMyZ3TfjfiKQWQRgIM2IKGBkn55ElcLjAYE0gcsx+aleawwiLHMLU6cZaU8Gl335c2EfJXRc8RKhXknPSojDi6VE+whMPU6c+x1sxha+J7jyqpNB6IL0ajtcDDQVIroxG6ygcSawN6Dlxvk7PGG21o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735688910; c=relaxed/simple; bh=8EGJJzbC0XxVzJc7BB3Pqu3pNodKRp+heFCIKYA8HyY=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=njaghgIC7yNRaDu/6A+ZMYYjAP1W4Dq8OAJuaQUyK7YQXiihyA3JG1QVd8j/O1AnZJrwMNszy1MdVl5lC/uRrTxnYzY62aZHbD4f0fOtzNKOoviYvGq43qgXL59Xwi91jM84Bi1kgbvEeWlvQzp6RXzj/QgXEt470iF7LhxDdzw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=kMxiEWdA; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="kMxiEWdA" Received: by smtp.kernel.org (Postfix) with ESMTPSA id D9787C4CED2; Tue, 31 Dec 2024 23:48:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1735688909; bh=8EGJJzbC0XxVzJc7BB3Pqu3pNodKRp+heFCIKYA8HyY=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=kMxiEWdAVVOvM+eyJMwDG8qWXEKry6mWi+fsYXcMkSs8QULQJpOZpbk8UrdvNAFkC ue/M+76Bc4VhzNibdNY3FxStp2h8/r0PIhd0CARbTFoZ9AsRcUcdEKRrdvwjg/2uFO KJgnifXioZdyLBhn0zzcutyBOOVkM5vCvOQfRR7xlS2YbBGpo0Efws0Mjfs1se1tO7 VuFkaXcaxE1GVUHWzx8X3BGMtsi0zylBy8tNfFrwU06zXUanLb+lvo+a8YsaXXf59/ p4/Mvk5G0w0zV/czf/EjO8jpBN0n05LdcdC+4m/AmDpspQWCyfzebho/pF39V60/rF rtNxtrlO65ubg== Date: Tue, 31 Dec 2024 15:48:29 -0800 Subject: [PATCH 03/21] xfs: create event queuing, formatting, and discovery infrastructure From: "Darrick J. Wong" To: aalbersh@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <173568778505.2710211.7052481015987415232.stgit@frogsfrogsfrogs> In-Reply-To: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> References: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Create the basic infrastructure that we need to report health events to userspace. We need a compact form for recording critical information about an event and queueing them; a means to notice that we've lost some events; and a means to format the events into something that userspace can handle. Here, we've chosen json to export information to userspace. The structured key-value nature of json gives us enormous flexibility to modify the schema of what we'll send to userspace because we can add new keys at any time. Userspace can use whatever json parsers are available to consume the events and will not be confused by keys they don't recognize. Note that we do NOT allow sending json back to the kernel, nor is there any intent to do that. Signed-off-by: "Darrick J. Wong" --- libxfs/xfs_fs.h | 8 +++++ libxfs/xfs_healthmon.schema.json | 63 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 libxfs/xfs_healthmon.schema.json diff --git a/libxfs/xfs_fs.h b/libxfs/xfs_fs.h index d1a81b02a1a3f3..d7404e6efd866d 100644 --- a/libxfs/xfs_fs.h +++ b/libxfs/xfs_fs.h @@ -1107,6 +1107,14 @@ struct xfs_health_monitor { __u64 pad2[2]; /* zeroes */ }; +/* Return all health status events, not just deltas */ +#define XFS_HEALTH_MONITOR_VERBOSE (1ULL << 0) + +#define XFS_HEALTH_MONITOR_ALL (XFS_HEALTH_MONITOR_VERBOSE) + +/* Return events in JSON format */ +#define XFS_HEALTH_MONITOR_FMT_JSON (1) + /* * ioctl commands that are used by Linux filesystems */ diff --git a/libxfs/xfs_healthmon.schema.json b/libxfs/xfs_healthmon.schema.json new file mode 100644 index 00000000000000..9772efe25f193d --- /dev/null +++ b/libxfs/xfs_healthmon.schema.json @@ -0,0 +1,63 @@ +{ + "$comment": [ + "SPDX-License-Identifier: GPL-2.0-or-later", + "Copyright (c) 2024-2025 Oracle. All Rights Reserved.", + "Author: Darrick J. Wong ", + "", + "This schema file describes the format of the json objects", + "readable from the fd returned by the XFS_IOC_HEALTHMON", + "ioctl." + ], + + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/fs/xfs/libxfs/xfs_healthmon.schema.json", + + "title": "XFS Health Monitoring Events", + + "$comment": "Events must be one of the following types:", + "oneOf": [ + { + "$ref": "#/$events/lost" + } + ], + + "$comment": "Simple data types are defined here.", + "$defs": { + "time_ns": { + "title": "Time of Event", + "description": "Timestamp of the event, in nanoseconds since the Unix epoch.", + "type": "integer" + } + }, + + "$comment": "Event types are defined here.", + "$events": { + "lost": { + "title": "Health Monitoring Events Lost", + "$comment": [ + "Previous health monitoring events were", + "dropped due to memory allocation failures", + "or queue limits." + ], + "type": "object", + + "properties": { + "type": { + "const": "lost" + }, + "time_ns": { + "$ref": "#/$defs/time_ns" + }, + "domain": { + "const": "mount" + } + }, + + "required": [ + "type", + "time_ns", + "domain" + ] + } + } +} From patchwork Tue Dec 31 23:48:45 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13924073 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A18601B0438 for ; Tue, 31 Dec 2024 23:48:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735688925; cv=none; b=kbeV240F7tr9IlNBypug7amB2dwa+iMU5GhaaJ7V1kp94xjney3D+Px1+v28aKy+3BEKIjKx1S0YWdYANLx8L4+motXIt2BrRSReu1AAxnf8kB9RfuWL2KT4wHf4FP3f9KRxag4+ZxVed+1JGPARwF8mJJ0VpQCJ/bYTJYeaKGs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735688925; c=relaxed/simple; bh=0ajwX3aP3pHkycP3D1qP6bba4/io8MZyRaW2T07LiFY=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=t8iM7XjdHQzWZNdwy/UU/X61Rg8/rF2AjewFslzRa7BL34seKZGDSCE3u0CY4AeUwrnncEawqLaqURBNXbwQ4HnBPcfHAOwLEp1pK8or09ZnGJzq0rRHJPm8fPNndN97oxmkwXmXi+inyDLbkGygYVK/9j0ZTtGMgN0hlEV3dPQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=L1pgrVPE; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="L1pgrVPE" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 78F7CC4CED2; Tue, 31 Dec 2024 23:48:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1735688925; bh=0ajwX3aP3pHkycP3D1qP6bba4/io8MZyRaW2T07LiFY=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=L1pgrVPEd+f3vxFOCt25Kxvn39P7zq8UFE0xGD0bY+guhvNL5YApM4Kj1T4YBZRb5 pITw6CaLzv/oOpKKsqGKfpEcNWtE21bUmnzVAxBWqz5yAqKF9VBSJbd9CrjoV3zeyh p89aZWY5K05ag4HVWHw68nDSHmY3xWhm/BmOTiT6ubhwQcDXUfGJfq4zWCY8Zqz48Y dI2hieUN/0JJ6H3Lso8NzjyjknDqVgMOMBJHjpsRIQuDFaBTlNJHXOLHTIMQ/R9X8C H4amlQDVAaV9VkhN97FgQkHW8lmlojyuAc76YqAWwHxwOsa1VG3HyQ444SM3VOE1Wv pzPy8nQtiLhuQ== Date: Tue, 31 Dec 2024 15:48:45 -0800 Subject: [PATCH 04/21] xfs: report metadata health events through healthmon From: "Darrick J. Wong" To: aalbersh@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <173568778520.2710211.13592512550036762462.stgit@frogsfrogsfrogs> In-Reply-To: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> References: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Set up a metadata health event hook so that we can send events to userspace as we collect information. The unmount hook severs the weak reference between the health monitor and the filesystem it's monitoring; when this happens, we stop reporting events because there's no longer any point. Signed-off-by: "Darrick J. Wong" --- libxfs/xfs_healthmon.schema.json | 328 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 328 insertions(+) diff --git a/libxfs/xfs_healthmon.schema.json b/libxfs/xfs_healthmon.schema.json index 9772efe25f193d..154ea0228a3615 100644 --- a/libxfs/xfs_healthmon.schema.json +++ b/libxfs/xfs_healthmon.schema.json @@ -18,6 +18,18 @@ "oneOf": [ { "$ref": "#/$events/lost" + }, + { + "$ref": "#/$events/fs_metadata" + }, + { + "$ref": "#/$events/rtgroup_metadata" + }, + { + "$ref": "#/$events/perag_metadata" + }, + { + "$ref": "#/$events/inode_metadata" } ], @@ -27,6 +39,169 @@ "title": "Time of Event", "description": "Timestamp of the event, in nanoseconds since the Unix epoch.", "type": "integer" + }, + "xfs_agnumber_t": { + "description": "Allocation group number", + "type": "integer", + "minimum": 0, + "maximum": 2147483647 + }, + "xfs_rgnumber_t": { + "description": "Realtime allocation group number", + "type": "integer", + "minimum": 0, + "maximum": 2147483647 + }, + "xfs_ino_t": { + "description": "Inode number", + "type": "integer", + "minimum": 1 + }, + "i_generation": { + "description": "Inode generation number", + "type": "integer" + } + }, + + "$comment": "Filesystem metadata event data are defined here.", + "$metadata": { + "status": { + "description": "Metadata health status", + "$comment": [ + "One of:", + "", + " * sick: metadata corruption discovered", + " during a runtime operation.", + " * corrupt: corruption discovered during", + " an xfs_scrub run.", + " * healthy: metadata object was found to be", + " ok by xfs_scrub." + ], + "enum": [ + "sick", + "corrupt", + "healthy" + ] + }, + "fs": { + "description": [ + "Metadata structures that affect the entire", + "filesystem. Options include:", + "", + " * fscounters: summary counters", + " * usrquota: user quota records", + " * grpquota: group quota records", + " * prjquota: project quota records", + " * quotacheck: quota counters", + " * nlinks: file link counts", + " * metadir: metadata directory", + " * metapath: metadata inode paths" + ], + "enum": [ + "fscounters", + "grpquota", + "metadir", + "metapath", + "nlinks", + "prjquota", + "quotacheck", + "usrquota" + ] + }, + "perag": { + "description": [ + "Metadata structures owned by allocation", + "groups on the data device. Options include:", + "", + " * agf: group space header", + " * agfl: per-group free block list", + " * agi: group inode header", + " * bnobt: free space by position btree", + " * cntbt: free space by length btree", + " * finobt: free inode btree", + " * inobt: inode btree", + " * rmapbt: reverse mapping btree", + " * refcountbt: reference count btree", + " * inodes: problems were recorded for", + " this group's inodes, but the", + " inodes themselves had to be", + " reclaimed.", + " * super: superblock" + ], + "enum": [ + "agf", + "agfl", + "agi", + "bnobt", + "cntbt", + "finobt", + "inobt", + "inodes", + "refcountbt", + "rmapbt", + "super" + ] + }, + "rtgroup": { + "description": [ + "Metadata structures owned by allocation", + "groups on the realtime volume. Options", + "include:", + "", + " * bitmap: free space bitmap contents", + " for this group", + " * summary: realtime free space summary file", + " * rmapbt: reverse mapping btree", + " * refcountbt: reference count btree", + " * super: group superblock" + ], + "enum": [ + "bitmap", + "summary", + "refcountbt", + "rmapbt", + "super" + ] + }, + "inode": { + "description": [ + "Metadata structures owned by file inodes.", + "Options include:", + "", + " * bmapbta: attr fork", + " * bmapbtc: cow fork", + " * bmapbtd: data fork", + " * core: inode record", + " * directory: directory entries", + " * dirtree: directory tree problems detected", + " * parent: directory parent pointer", + " * symlink: symbolic link target", + " * xattr: extended attributes", + "", + "These are set when an inode record repair had", + "to drop the corresponding data structure to", + "get the inode back to a consistent state.", + "", + " * bmapbtd_zapped", + " * bmapbta_zapped", + " * directory_zapped", + " * symlink_zapped" + ], + "enum": [ + "bmapbta", + "bmapbta_zapped", + "bmapbtc", + "bmapbtd", + "bmapbtd_zapped", + "core", + "directory", + "directory_zapped", + "dirtree", + "parent", + "symlink", + "symlink_zapped", + "xattr" + ] } }, @@ -58,6 +233,159 @@ "time_ns", "domain" ] + }, + "fs_metadata": { + "title": "Filesystem-wide metadata event", + "description": [ + "Health status updates for filesystem-wide", + "metadata objects." + ], + "type": "object", + + "properties": { + "type": { + "$ref": "#/$metadata/status" + }, + "time_ns": { + "$ref": "#/$defs/time_ns" + }, + "domain": { + "const": "fs" + }, + "structures": { + "type": "array", + "items": { + "$ref": "#/$metadata/fs" + }, + "minItems": 1 + } + }, + + "required": [ + "type", + "time_ns", + "domain", + "structures" + ] + }, + "perag_metadata": { + "title": "Data device allocation group metadata event", + "description": [ + "Health status updates for data device ", + "allocation group metadata." + ], + "type": "object", + + "properties": { + "type": { + "$ref": "#/$metadata/status" + }, + "time_ns": { + "$ref": "#/$defs/time_ns" + }, + "domain": { + "const": "perag" + }, + "group": { + "$ref": "#/$defs/xfs_agnumber_t" + }, + "structures": { + "type": "array", + "items": { + "$ref": "#/$metadata/perag" + }, + "minItems": 1 + } + }, + + "required": [ + "type", + "time_ns", + "domain", + "group", + "structures" + ] + }, + "rtgroup_metadata": { + "title": "Realtime allocation group metadata event", + "description": [ + "Health status updates for realtime allocation", + "group metadata." + ], + "type": "object", + + "properties": { + "type": { + "$ref": "#/$metadata/status" + }, + "time_ns": { + "$ref": "#/$defs/time_ns" + }, + "domain": { + "const": "rtgroup" + }, + "group": { + "$ref": "#/$defs/xfs_rgnumber_t" + }, + "structures": { + "type": "array", + "items": { + "$ref": "#/$metadata/rtgroup" + }, + "minItems": 1 + } + }, + + "required": [ + "type", + "time_ns", + "domain", + "group", + "structures" + ] + }, + "inode_metadata": { + "title": "Inode metadata event", + "description": [ + "Health status updates for inode metadata.", + "The inode and generation number describe the", + "file that is affected by the change." + ], + "type": "object", + + "properties": { + "type": { + "$ref": "#/$metadata/status" + }, + "time_ns": { + "$ref": "#/$defs/time_ns" + }, + "domain": { + "const": "inode" + }, + "inumber": { + "$ref": "#/$defs/xfs_ino_t" + }, + "generation": { + "$ref": "#/$defs/i_generation" + }, + "structures": { + "type": "array", + "items": { + "$ref": "#/$metadata/inode" + }, + "minItems": 1 + } + }, + + "required": [ + "type", + "time_ns", + "domain", + "inumber", + "generation", + "structures" + ] } } } From patchwork Tue Dec 31 23:49:00 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13924074 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 47A3B29415 for ; Tue, 31 Dec 2024 23:49:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735688941; cv=none; b=QHiOKWL0k78hXibMLKmcCyDlAjYfoSFvNVxckflVWTrUx9PViegf5eQaIRANvQ2AriFW9UeOl1wHCHtp+lNskUQSNvLyITmWqw4t74C0sik0mg3BLiEtRBb1F6GSvI0Eb4S5xFnbIA7FAoVRTjJY7nhBaLYp2SjVlQe0jGG6dFk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735688941; c=relaxed/simple; bh=qQfSzOH2pPPaAMh7rgH7g6tp8CR0TvHXzvlL37152o4=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=RH6PhrNoi07IhTYZj32IkX3eQmpD8V68huB7ajd1EmnwtNktb67dTUnSEH/ymMsZfrDk8HTjTVw0sZw2w4aBo1rYNZZuQEx/uDa2sEfIHTxKjYg8khzF+MUH4ew2ITV3hIOhk3bDxcWaRf49HeMQTNxW26qoScOKt8eKcl5WbeA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=kewbjaYM; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="kewbjaYM" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1DB88C4CED2; Tue, 31 Dec 2024 23:49:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1735688941; bh=qQfSzOH2pPPaAMh7rgH7g6tp8CR0TvHXzvlL37152o4=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=kewbjaYMYLPFjxo4LSu5H6vomgIztaG/faQsaBCCZZQKUicm7CnCCl3hB94WNmROZ wAP1oFmdOD95ahaZff/lq2xDCPZcifnlyP+7+hcvOzigso3saC5JBJKDjxf7vbJ2sx MkjrtvBBimZQQExDAQYzDy7oZlDXqOO0qrFPpVjaZzS/MysFB3ppNT+uuinmjkRgId vNQ5850Wu6kkxsr1JRCFOwuC5SXb333gtoEkIhYlqZ+MlB0OTyVyFrp+dTMWl8xiUU BkkuqeXvaFskbvraoEp3R8HJECUUzHP0XG4pQtZaxZQ/uWvXx09WAmuJKLAIXEekCH uQihguARZyi6Q== Date: Tue, 31 Dec 2024 15:49:00 -0800 Subject: [PATCH 05/21] xfs: report shutdown events through healthmon From: "Darrick J. Wong" To: aalbersh@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <173568778536.2710211.13092769848745616981.stgit@frogsfrogsfrogs> In-Reply-To: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> References: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Set up a shutdown hook so that we can send notifications to userspace. Signed-off-by: "Darrick J. Wong" --- libxfs/xfs_healthmon.schema.json | 62 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/libxfs/xfs_healthmon.schema.json b/libxfs/xfs_healthmon.schema.json index 154ea0228a3615..a8bc75b0b8c4f9 100644 --- a/libxfs/xfs_healthmon.schema.json +++ b/libxfs/xfs_healthmon.schema.json @@ -30,6 +30,9 @@ }, { "$ref": "#/$events/inode_metadata" + }, + { + "$ref": "#/$events/shutdown" } ], @@ -205,6 +208,31 @@ } }, + "$comment": "Shutdown event data are defined here.", + "$shutdown": { + "reason": { + "description": [ + "Reason for a filesystem to shut down.", + "Options include:", + "", + " * corrupt_incore: in-memory corruption", + " * corrupt_ondisk: on-disk corruption", + " * device_removed: device removed", + " * force_umount: userspace asked for it", + " * log_ioerr: log write IO error", + " * meta_ioerr: metadata writeback IO error" + ], + "enum": [ + "corrupt_incore", + "corrupt_ondisk", + "device_removed", + "force_umount", + "log_ioerr", + "meta_ioerr" + ] + } + }, + "$comment": "Event types are defined here.", "$events": { "lost": { @@ -386,6 +414,40 @@ "generation", "structures" ] + }, + "shutdown": { + "title": "Abnormal Shutdown Event", + "description": [ + "The filesystem went offline due to", + "unrecoverable errors." + ], + "type": "object", + + "properties": { + "type": { + "const": "shutdown" + }, + "time_ns": { + "$ref": "#/$defs/time_ns" + }, + "domain": { + "const": "mount" + }, + "reasons": { + "type": "array", + "items": { + "$ref": "#/$shutdown/reason" + }, + "minItems": 1 + } + }, + + "required": [ + "type", + "time_ns", + "domain", + "reasons" + ] } } } From patchwork Tue Dec 31 23:49:16 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13924075 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1E23629415 for ; Tue, 31 Dec 2024 23:49:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735688957; cv=none; b=MJlWnCNkR0bokzJ6rB2Op4p8rhxBbv28socyCEkWmmjVL6EoEEeZZTMfUkLqhsT87rnldrVfTGPaPLqjztc8awynERvjxXPS43G5z0YPnLJfMGAClXERoQWEH1vGp1OrVv4dH3r7oFBN/ShwFdZ0KpV/ArGesjhnNC4EwVMH7/8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735688957; c=relaxed/simple; bh=C2G0aTjZlccaxLYCcyxECfcpCR6kxEMTTUCSzzR5XaI=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Ri8tmAqNMHtyFKQamtbH4+Hn0PQhMREGcGSYw27WQYh3hqZB0EBQLkbuyNwdrDjHoOGKpnz4da4NAD7CefuO9ZmByctM7Uyzc989gi1Tr7b5RyVhzA/Iw3efuI/JfqcajpnYxuPgeJ3QFzRvr7wl1Ll+JCn5uuJZOYppvKg5LP0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Q8xIQnus; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Q8xIQnus" Received: by smtp.kernel.org (Postfix) with ESMTPSA id EBA93C4CED2; Tue, 31 Dec 2024 23:49:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1735688957; bh=C2G0aTjZlccaxLYCcyxECfcpCR6kxEMTTUCSzzR5XaI=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=Q8xIQnusEwc/ksP1AOYHFgG+jsNGgql6APehPHePdYGeCfEfIfLxC+UyJKYvgvAX2 rdv36BTIvVi9DN3Y2FDlp2XL78YFZG3270EMxFvP6r39Ul1ys+KB0ZzR75uX3BH9h4 Ksyd0dUDPtt3GfD3JNElhmrb+pdrajEtFVYu0yINWJGhjfLLHJ2Gg+vNCpOrb8feTH ahN0pbpvlrsE+mDgnswmpg6eddQSNtdR15A98qMie1ox/GrA77qjH0S9UmCqxQP79t H8j7mKKiT5qkyv3gkaZvDwLRDwwa35zDajuP0XGju5FkkTiishYVN9iB62T5dfPUUv tClebZwTfTF2Q== Date: Tue, 31 Dec 2024 15:49:16 -0800 Subject: [PATCH 06/21] xfs: report media errors through healthmon From: "Darrick J. Wong" To: aalbersh@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <173568778552.2710211.14335916062488397072.stgit@frogsfrogsfrogs> In-Reply-To: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> References: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Now that we have hooks to report media errors, connect this to the health monitor as well. Signed-off-by: "Darrick J. Wong" --- libxfs/xfs_healthmon.schema.json | 65 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/libxfs/xfs_healthmon.schema.json b/libxfs/xfs_healthmon.schema.json index a8bc75b0b8c4f9..006f4145faa9f5 100644 --- a/libxfs/xfs_healthmon.schema.json +++ b/libxfs/xfs_healthmon.schema.json @@ -33,6 +33,9 @@ }, { "$ref": "#/$events/shutdown" + }, + { + "$ref": "#/$events/media_error" } ], @@ -63,6 +66,31 @@ "i_generation": { "description": "Inode generation number", "type": "integer" + }, + "storage_devs": { + "description": "Storage devices in a filesystem", + "_comment": [ + "One of:", + "", + " * datadev: filesystem device", + " * logdev: external log device", + " * rtdev: realtime volume" + ], + "enum": [ + "datadev", + "logdev", + "rtdev" + ] + }, + "xfs_daddr_t": { + "description": "Storage device address, in units of 512-byte blocks", + "type": "integer", + "minimum": 0 + }, + "bbcount": { + "description": "Storage space length, in units of 512-byte blocks", + "type": "integer", + "minimum": 1 } }, @@ -448,6 +476,43 @@ "domain", "reasons" ] + }, + "media_error": { + "title": "Media Error", + "description": [ + "A storage device reported a media error.", + "The domain element tells us which storage", + "device reported the media failure. The", + "daddr and bbcount elements tell us where", + "inside that device the failure was observed." + ], + "type": "object", + + "properties": { + "type": { + "const": "media" + }, + "time_ns": { + "$ref": "#/$defs/time_ns" + }, + "domain": { + "$ref": "#/$defs/storage_devs" + }, + "daddr": { + "$ref": "#/$defs/xfs_daddr_t" + }, + "bbcount": { + "$ref": "#/$defs/bbcount" + } + }, + + "required": [ + "type", + "time_ns", + "domain", + "daddr", + "bbcount" + ] } } } From patchwork Tue Dec 31 23:49:32 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13924076 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2993229415 for ; Tue, 31 Dec 2024 23:49:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735688973; cv=none; b=be9gXItgJPQtWJIuhIX45yZlugkNoUvsmEOLyz3jMfIeTXICullaGSG7B0xTUL2FA0/jMRexok+y/tqSVdO9yOsCiETFeYjfXkyxFm0CH0Hvl5naLIEY2mk+zrgdQs7G7UHNWWlKBMc9Oag9ZU+J30ldvjcuyLtldyOlyRDgHxc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735688973; c=relaxed/simple; bh=KXC01zJz8dH5M49sRgQAXrKP9VbnYyAZzoQqBYdL3Gk=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=CwKOdYh62IkIZUWDpMIhBMG0IXbKO9vXB3oQB6hZ3fWS71j+G1fcjRmkx+fXZ1H+aCLcoJA/dyRHf9i0+D7B3FdDXn0fLztpxQxP0Fp/E370pBZgrByJYB4dV1biCT3CNm4LVlHqTOYwq2HPhBQ0jxQK4wRIp1+ZZJb8pCGxLNY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=GiKFkx/F; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="GiKFkx/F" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 9CC95C4CED2; Tue, 31 Dec 2024 23:49:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1735688972; bh=KXC01zJz8dH5M49sRgQAXrKP9VbnYyAZzoQqBYdL3Gk=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=GiKFkx/FqNxuVQQmnVlNs3/e/lBtEA28YacjT0GfeKidxLEWinCm1PT1kEK8wGhGU JidQcPfYRSEWbBf5Zq2/oMduwBnJ2kWVsoXetDATkyi4FqjTNpAAwRYTQH4czN00Sh VFinfqQaeRak6ehqNyIPHB7C7JrA3VJ/8QQEIzpH3FRbkxQSCJuME+kQruYU9G8GE1 1LboflXTJegadQ61i/m7kDIluS7/khh113wiDhHm55bVGGUKy2IuPac/2itbcnwmak 8xBDgjOnGrL+vs0CWhFfYaAoxFtSuK0XHKJ0w4/IA7/Br3IzqsTXrUQzgrUXfGudsm cR8EFqiocdUtg== Date: Tue, 31 Dec 2024 15:49:32 -0800 Subject: [PATCH 07/21] xfs: report file io errors through healthmon From: "Darrick J. Wong" To: aalbersh@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <173568778567.2710211.14890698351890932186.stgit@frogsfrogsfrogs> In-Reply-To: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> References: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Set up a file io error event hook so that we can send events about read errors, writeback errors, and directio errors to userspace. Signed-off-by: "Darrick J. Wong" --- libxfs/xfs_healthmon.schema.json | 77 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/libxfs/xfs_healthmon.schema.json b/libxfs/xfs_healthmon.schema.json index 006f4145faa9f5..9c1070a629997c 100644 --- a/libxfs/xfs_healthmon.schema.json +++ b/libxfs/xfs_healthmon.schema.json @@ -36,6 +36,9 @@ }, { "$ref": "#/$events/media_error" + }, + { + "$ref": "#/$events/file_ioerror" } ], @@ -67,6 +70,16 @@ "description": "Inode generation number", "type": "integer" }, + "off_t": { + "description": "File position, in bytes", + "type": "integer", + "minimum": 0 + }, + "size_t": { + "description": "File operation length, in bytes", + "type": "integer", + "minimum": 1 + }, "storage_devs": { "description": "Storage devices in a filesystem", "_comment": [ @@ -261,6 +274,26 @@ } }, + "$comment": "File IO event data are defined here.", + "$fileio": { + "types": { + "description": [ + "File I/O operations. One of:", + "", + " * readahead: reads into the page cache.", + " * writeback: writeback of dirty page cache.", + " * dioread: O_DIRECT reads.", + " * diowrite: O_DIRECT writes." + ], + "enum": [ + "readahead", + "writeback", + "dioread", + "diowrite" + ] + } + }, + "$comment": "Event types are defined here.", "$events": { "lost": { @@ -513,6 +546,50 @@ "daddr", "bbcount" ] + }, + "file_ioerror": { + "title": "File I/O error", + "description": [ + "A read or a write to a file failed. The", + "inode, generation, pos, and len fields", + "describe the range of the file that is", + "affected." + ], + "type": "object", + + "properties": { + "type": { + "$ref": "#/$fileio/types" + }, + "time_ns": { + "$ref": "#/$defs/time_ns" + }, + "domain": { + "const": "filerange" + }, + "inumber": { + "$ref": "#/$defs/xfs_ino_t" + }, + "generation": { + "$ref": "#/$defs/i_generation" + }, + "pos": { + "$ref": "#/$defs/off_t" + }, + "len": { + "$ref": "#/$defs/size_t" + } + }, + + "required": [ + "type", + "time_ns", + "domain", + "inumber", + "generation", + "pos", + "len" + ] } } } From patchwork Tue Dec 31 23:49:47 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13924077 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BD4C529415 for ; Tue, 31 Dec 2024 23:49:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735688988; cv=none; b=LFPlR/BKypJ8fpyW7WHbKGgUNgb0NLWgxkwjQJgAJwQlUYkQaMMP0gzPqJ/stTQz1H0TKVJIAgCd01La2s6VRdnIgs1Bu4hhJJi4sAzZ8DK+gv+qc2OsOqqlFe3jqsx0v5eypvn2zz1P/Q+SkYywWEYatQT4NKXAzqUjA8vwIgw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735688988; c=relaxed/simple; bh=aqtbj/Vcn3WV64upJKt3peMvkPC3KrxDUaYpu98rQr0=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=WB3gYr5ndPrsLlPYcEgx9EDb2fGkfxv7eUP5/ZgcEEcK6SRe5z+0uCjyM9JXOMCOsN29N7Y9l09W4iRK7fxei8PCNJYswDvT9AQ10KtONplbcSutOUcRb+sTAapB5GWbvk5tNTZuYSGV/zdHSO953oOXkEcxi19q4r55TvB+0s8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=lhx4YM9u; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="lhx4YM9u" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4497EC4CED2; Tue, 31 Dec 2024 23:49:48 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1735688988; bh=aqtbj/Vcn3WV64upJKt3peMvkPC3KrxDUaYpu98rQr0=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=lhx4YM9ukH93678ePRyTLIrJVi1ZFGaj3Pggy5YGRsMBwyk5OTDxB0+hRW1FTK6mS nkOEbUv0jh/Q/CMPzuvpoOjtSiMOco4EPvwyxdB5uqIRL4myWIAmJveJhhhxQDlrsQ oJSdiQ2kz2BvGnOZ2soeUBAIBgQ3uTdtwC47M2S6Te9SNLhA8tE5wnCFMi/5SrGzRk 0pZ2oz5rspN1I+plp1OKKpegi0JNtvRqZxKmXC9MUQLiEMS5Avs6wn01o2ct4wvEnM WemTc28DQW5ceERmjeHUHTvUUKP5oR+RmndVzVjy94HiKz46KOZ+w1IOeEwpiuD1B1 JuRTjOT8FRwag== Date: Tue, 31 Dec 2024 15:49:47 -0800 Subject: [PATCH 08/21] xfs: add media error reporting ioctl From: "Darrick J. Wong" To: aalbersh@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <173568778582.2710211.12839545225156178670.stgit@frogsfrogsfrogs> In-Reply-To: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> References: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Add a new privileged ioctl so that xfs_scrub can report media errors to the kernel for further processing. Signed-off-by: "Darrick J. Wong" --- libxfs/xfs_fs.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/libxfs/xfs_fs.h b/libxfs/xfs_fs.h index d7404e6efd866d..32e552d40b1bf5 100644 --- a/libxfs/xfs_fs.h +++ b/libxfs/xfs_fs.h @@ -1115,6 +1115,20 @@ struct xfs_health_monitor { /* Return events in JSON format */ #define XFS_HEALTH_MONITOR_FMT_JSON (1) +struct xfs_media_error { + __u64 flags; /* flags */ + __u64 daddr; /* disk address of range */ + __u64 bbcount; /* length, in 512b blocks */ + __u64 pad; /* zero */ +}; + +#define XFS_MEDIA_ERROR_DATADEV (1) /* data device */ +#define XFS_MEDIA_ERROR_LOGDEV (2) /* external log device */ +#define XFS_MEDIA_ERROR_RTDEV (3) /* realtime device */ + +/* bottom byte of flags is the device code */ +#define XFS_MEDIA_ERROR_DEVMASK (0xFF) + /* * ioctl commands that are used by Linux filesystems */ @@ -1157,6 +1171,7 @@ struct xfs_health_monitor { #define XFS_IOC_GETFSREFCOUNTS _IOWR('X', 66, struct xfs_getfsrefs_head) #define XFS_IOC_MAP_FREESP _IOW ('X', 67, struct xfs_map_freesp) #define XFS_IOC_HEALTH_MONITOR _IOW ('X', 68, struct xfs_health_monitor) +#define XFS_IOC_MEDIA_ERROR _IOW ('X', 69, struct xfs_media_error) /* * ioctl commands that replace IRIX syssgi()'s From patchwork Tue Dec 31 23:50:03 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13924078 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 142B529415 for ; Tue, 31 Dec 2024 23:50:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735689004; cv=none; b=axssYKhdWwypKkYRq3k5tpcLpEwhcAMwEcFN9eFrDlnHovBWMeqsWQOLVLB/IExsgvkndSg29By0Wo4DaX6oBdtAMBv6k8d7vQH0i+fIJESGATU0aFwNcAJXJm62mosbPJkNahZeiWNyEHJUNYx9jt8CWG3ZEPxLn0hwNCgBkaQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735689004; c=relaxed/simple; bh=E01BChRKDj93Lf3/ZyyFW34DF02y7KzDXags/INYgrM=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=E9DMHiERNwf4Ha9cY6MheU1glkoGgd5B2QmVPIJkUi/apwgfmhsem0LGCIdEUdQWfYRNfsSNfqZI+4fpyWzYxkzgw62m68WjXK+PEUHbs6VP/1c9PeHULlxrDD0K+ioxsCaTBP7D3glGr0EySUVDqKnFcBwU6qD5xIjbiJvI6jQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=D/OTJx1v; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="D/OTJx1v" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E4BB5C4CED2; Tue, 31 Dec 2024 23:50:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1735689003; bh=E01BChRKDj93Lf3/ZyyFW34DF02y7KzDXags/INYgrM=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=D/OTJx1vyFTId20zvKZg365WBsaLH5MWTkUF93MXoRjpwvV+nHXSp1BWScAPUc+qV LDADV23liwKm3XH/xQCXy11QtPXM0o4rvMwa3urgtq1S00paQ3HIRzs/DApSLTC2d6 C8X897A4mECp4QHqOPmcHuaTAgYdGGFqx1B17L6XHDM7tkLG4Hv3ROAY1PzbkoI/WK GuLdp1H+8NaqmG4yBQLuHWRGH2T1hK4+xOJXnocIkX6qsyqAv0fEYambZZVaKCDCcl Rrjy+pm6BjJyw60OVJWQRP/+VY7ZLRci1M/lEwIPCco21cRGLD2Nm1u4qt70h9Bs+T EAyTgd2szu5YA== Date: Tue, 31 Dec 2024 15:50:03 -0800 Subject: [PATCH 09/21] xfs_io: monitor filesystem health events From: "Darrick J. Wong" To: aalbersh@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <173568778598.2710211.14676877759844485020.stgit@frogsfrogsfrogs> In-Reply-To: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> References: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Create a subcommand to monitor for health events generated by the kernel. Signed-off-by: "Darrick J. Wong" --- io/Makefile | 1 io/healthmon.c | 183 +++++++++++++++++++++++++++++++++++++++++++++++++++++ io/init.c | 1 io/io.h | 1 man/man8/xfs_io.8 | 25 +++++++ 5 files changed, 211 insertions(+) create mode 100644 io/healthmon.c diff --git a/io/Makefile b/io/Makefile index c57594b090f70c..451d2a15b25919 100644 --- a/io/Makefile +++ b/io/Makefile @@ -26,6 +26,7 @@ CFILES = \ fsuuid.c \ fsync.c \ getrusage.c \ + healthmon.c \ imap.c \ init.c \ inject.c \ diff --git a/io/healthmon.c b/io/healthmon.c new file mode 100644 index 00000000000000..7d372d7d8c532b --- /dev/null +++ b/io/healthmon.c @@ -0,0 +1,183 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2024-2025 Oracle. All Rights Reserved. + * Author: Darrick J. Wong + */ +#include "libxfs.h" +#include "libfrog/fsgeom.h" +#include "libfrog/paths.h" +#include "command.h" +#include "init.h" +#include "io.h" + +static void +healthmon_help(void) +{ + printf(_( +"Monitor filesystem health events" +"\n" +"-c Replace the open file with the monitor file.\n" +"-d delay_ms Sleep this many milliseconds between reads.\n" +"-p Only probe for the existence of the ioctl.\n" +"-v Request all events.\n" +"\n")); +} + +static inline int +monitor_sleep( + int delay_ms) +{ + struct timespec ts; + + if (!delay_ms) + return 0; + + ts.tv_sec = delay_ms / 1000; + ts.tv_nsec = (delay_ms % 1000) * 1000000; + + return nanosleep(&ts, NULL); +} + +static int +monitor( + size_t bufsize, + bool consume, + int delay_ms, + bool verbose, + bool only_probe) +{ + struct xfs_health_monitor hmo = { + .format = XFS_HEALTH_MONITOR_FMT_JSON, + }; + char *buf; + ssize_t bytes_read; + int mon_fd; + int ret = 1; + + if (verbose) + hmo.flags |= XFS_HEALTH_MONITOR_ALL; + + mon_fd = ioctl(file->fd, XFS_IOC_HEALTH_MONITOR, &hmo); + if (mon_fd < 0) { + perror("XFS_IOC_HEALTH_MONITOR"); + return 1; + } + + if (only_probe) { + ret = 0; + goto out_mon; + } + + buf = malloc(bufsize); + if (!buf) { + perror("malloc"); + goto out_mon; + } + + if (consume) { + close(file->fd); + file->fd = mon_fd; + } + + monitor_sleep(delay_ms); + while ((bytes_read = read(mon_fd, buf, bufsize)) > 0) { + char *write_ptr = buf; + ssize_t bytes_written; + size_t to_write = bytes_read; + + while ((bytes_written = write(STDOUT_FILENO, write_ptr, to_write)) > 0) { + write_ptr += bytes_written; + to_write -= bytes_written; + } + if (bytes_written < 0) { + perror("healthdump"); + goto out_buf; + } + + monitor_sleep(delay_ms); + } + if (bytes_read < 0) { + perror("healthmon"); + goto out_buf; + } + + ret = 0; + +out_buf: + free(buf); +out_mon: + close(mon_fd); + return ret; +} + +static int +healthmon_f( + int argc, + char **argv) +{ + size_t bufsize = 4096; + bool consume = false; + bool verbose = false; + bool only_probe = false; + int delay_ms = 0; + int c; + + while ((c = getopt(argc, argv, "b:cd:pv")) != EOF) { + switch (c) { + case 'b': + errno = 0; + c = atoi(optarg); + if (c < 0 || errno) { + printf("%s: bufsize must be positive\n", + optarg); + exitcode = 1; + return 0; + } + bufsize = c; + break; + case 'c': + consume = true; + break; + case 'd': + errno = 0; + delay_ms = atoi(optarg); + if (delay_ms < 0 || errno) { + printf("%s: delay must be positive msecs\n", + optarg); + exitcode = 1; + return 0; + } + break; + case 'p': + only_probe = true; + break; + case 'v': + verbose = true; + break; + default: + exitcode = 1; + healthmon_help(); + return 0; + } + } + + return monitor(bufsize, consume, delay_ms, verbose, only_probe); +} + +static struct cmdinfo healthmon_cmd = { + .name = "healthmon", + .cfunc = healthmon_f, + .argmin = 0, + .argmax = -1, + .flags = CMD_FLAG_ONESHOT | CMD_NOMAP_OK, + .args = "[-c] [-d delay_ms] [-v]", + .help = healthmon_help, +}; + +void +healthmon_init(void) +{ + healthmon_cmd.oneline = _("monitor filesystem health events"); + + add_command(&healthmon_cmd); +} diff --git a/io/init.c b/io/init.c index 17b772813bc113..22ebd2f7522a18 100644 --- a/io/init.c +++ b/io/init.c @@ -92,6 +92,7 @@ init_commands(void) crc32cselftest_init(); exchangerange_init(); fsprops_init(); + healthmon_init(); } /* diff --git a/io/io.h b/io/io.h index 7ae7cf90ace323..267f3ffac36924 100644 --- a/io/io.h +++ b/io/io.h @@ -157,3 +157,4 @@ void exchangerange_init(void); void fsprops_init(void); void aginfo_init(void); void fsrefcounts_init(void); +void healthmon_init(void); diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8 index c4d09ce07f597b..632d07807f44f0 100644 --- a/man/man8/xfs_io.8 +++ b/man/man8/xfs_io.8 @@ -1419,6 +1419,31 @@ .SH FILESYSTEM COMMANDS .RE .PD +.TP +.BI "healthmon [ \-c " bufsize " ] [ \-c ] [ \-d " delay_ms " ] [ \-p ] [ \-v ]" +Watch for filesystem health events and write them to the console. +.RE +.RS 1.0i +.PD 0 +.TP +.BI "\-b " bufsize +Use a buffer of this size to read events from the kernel. +.TP +.BI \-c +Close the open file and replace it with the monitor file. +.TP +.BI "\-d " delay_ms +Sleep for this long between read attempts. +.TP +.B \-p +Probe for the existence of the functionality by opening the monitoring fd and +closing it immediately. +.TP +.BI \-v +Request all health events, even if nothing changed. +.PD +.RE + .TP .BI "inject [ " tag " ]" Inject errors into a filesystem to observe filesystem behavior at From patchwork Tue Dec 31 23:50:19 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13924079 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EBED329415 for ; Tue, 31 Dec 2024 23:50:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735689020; cv=none; b=r0w0eK7uMpKsrfyopWesg8B4uQwuTQJpBjn72xPzGPI4aVTYoQ6uaObEJLAZmTOFQ0/bweGpbmYRCXCzQhT5ywyJlhbyFofeHbCMUlq/J4/HirnfH7yqjf6cIkkgbW9Uy3PuChw0Elp4PUEd9oOGX49FEThtUvqrbTlFgYB5wD8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735689020; c=relaxed/simple; bh=rZU3sfWXOrLhH/dqQXYbBROaOC2VE++wWxyn5quvnlU=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=uqQjnlhssC8AE+5DtKVGiUUtIjcvPNhDg3EiIoS92nK5l4x05DFfV1QXC+FPIbn4lC/cSZQn/AYPmSceOPw4Lkd+lTBjvg3KyN/17TZ6cVCOFihOLdhNRbKB9hqQAxrCIhFe6t5zbaYea743VjtUCqkHHBG+cF/+oyLXY2Regk0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Uu2VJLwh; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Uu2VJLwh" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 86236C4CED2; Tue, 31 Dec 2024 23:50:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1735689019; bh=rZU3sfWXOrLhH/dqQXYbBROaOC2VE++wWxyn5quvnlU=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=Uu2VJLwhzy5Yj5i5KRNG0htruHRWcwOPdVP7ZH0hA+GqmcY0/l4HmXVV5CGHm5Lz3 /iRpOJKqkP+YywJoo//PxumdKzVxqxaBcTQqsBA6BKSavLw1l8qeXhyBoV6klsxHX1 8t2PGYyfq6fvUQViolVpMR8mfw+lHD6wNxq+SMaisMItjxtMcahOFdr9ubHDa753cM I5yyf3Y+98kdU0c6h15ECXxZ3qVca/3/CGwRc2l9WnHzYaU27tkKlivYPXkGiPhTpD 4AxDapHit/5vA8s1S3pWy+gnrnIcAIm9VFKBpynZJ+hZ5rPipwjO7+TykXdbKX2JRK QetwLc9cZCJJQ== Date: Tue, 31 Dec 2024 15:50:19 -0800 Subject: [PATCH 10/21] xfs_io: add a media error reporting command From: "Darrick J. Wong" To: aalbersh@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <173568778614.2710211.18244860267862422858.stgit@frogsfrogsfrogs> In-Reply-To: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> References: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Add a subcommand to invoke the media error ioctl to make sure it works. Signed-off-by: "Darrick J. Wong" --- io/shutdown.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++++ man/man8/xfs_io.8 | 21 ++++++++++ 2 files changed, 133 insertions(+), 1 deletion(-) diff --git a/io/shutdown.c b/io/shutdown.c index 3c29ea790643f8..b4fba7d78ba83b 100644 --- a/io/shutdown.c +++ b/io/shutdown.c @@ -53,6 +53,115 @@ shutdown_help(void) "\n")); } +static void +mediaerror_help(void) +{ + printf(_( +"\n" +" Report a media error on the data device to the filesystem.\n" +"\n" +" -l -- Report against the log device.\n" +" -r -- Report against the realtime device.\n" +"\n" +" offset is the byte offset of the start of the failed range. If offset is\n" +" specified, mapping length may (optionally) be specified as well." +"\n" +" length is the byte length of the failed range.\n" +"\n" +" If neither offset nor length are specified, the media error report will\n" +" be made against the entire device." +"\n")); +} + +static int +mediaerror_f( + int argc, + char **argv) +{ + struct xfs_media_error me = { + .daddr = 0, + .bbcount = -1ULL, + .flags = XFS_MEDIA_ERROR_DATADEV, + }; + long long l; + size_t fsblocksize, fssectsize; + int c, ret; + + init_cvtnum(&fsblocksize, &fssectsize); + + while ((c = getopt(argc, argv, "lr")) != EOF) { + switch (c) { + case 'l': + me.flags = (me.flags & ~XFS_MEDIA_ERROR_DEVMASK) | + XFS_MEDIA_ERROR_LOGDEV; + break; + case 'r': + me.flags = (me.flags & ~XFS_MEDIA_ERROR_DEVMASK) | + XFS_MEDIA_ERROR_RTDEV; + break; + default: + mediaerror_help(); + exitcode = 1; + return 0; + } + } + + /* Range start (optional) */ + if (optind < argc) { + l = cvtnum(fsblocksize, fssectsize, argv[optind]); + if (l < 0) { + printf("non-numeric offset argument -- %s\n", + argv[optind]); + exitcode = 1; + return 0; + } + + me.daddr = l / 512; + optind++; + } + + /* Range length (optional if range start was specified) */ + if (optind < argc) { + l = cvtnum(fsblocksize, fssectsize, argv[optind]); + if (l < 0) { + printf("non-numeric len argument -- %s\n", + argv[optind]); + exitcode = 1; + return 0; + } + + me.bbcount = howmany(l, 512); + optind++; + } + + if (optind < argc) { + printf("too many arguments -- %s\n", argv[optind]); + exitcode = 1; + return 0; + } + + ret = ioctl(file->fd, XFS_IOC_MEDIA_ERROR, &me); + if (ret) { + fprintf(stderr, + "%s: ioctl(XFS_IOC_MEDIA_ERROR) [\"%s\"]: %s\n", + progname, file->name, strerror(errno)); + exitcode = 1; + return 0; + } + + return 0; +} + +static struct cmdinfo mediaerror_cmd = { + .name = "mediaerror", + .cfunc = mediaerror_f, + .argmin = 0, + .argmax = -1, + .flags = CMD_FLAG_ONESHOT | CMD_NOMAP_OK, + .args = "[-lr] [offset [length]]", + .help = mediaerror_help, +}; + void shutdown_init(void) { @@ -66,6 +175,8 @@ shutdown_init(void) shutdown_cmd.oneline = _("shuts down the filesystem where the current file resides"); - if (expert) + if (expert) { add_command(&shutdown_cmd); + add_command(&mediaerror_cmd); + } } diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8 index 632d07807f44f0..2ca74e6ab57d4e 100644 --- a/man/man8/xfs_io.8 +++ b/man/man8/xfs_io.8 @@ -1452,6 +1452,27 @@ .SH FILESYSTEM COMMANDS argument, displays the list of error tags available. Only available in expert mode and requires privileges. +.TP +.BI "mediaerror [ \-lr ] [ " offset " [ " length " ]]" +Report a media error against the data device of an XFS filesystem. +The +.I offset +and +.I length +parameters are specified in units of bytes. +If neither are specified, the entire device will be reported. +.RE +.RS 1.0i +.PD 0 +.TP +.BI \-l +Report against the log device instead of the data device. +.TP +.BI \-r +Report against the realtime device instead of the data device. +.PD +.RE + .TP .BI "rginfo [ \-r " rgno " ]" Show information about or update the state of realtime allocation groups. From patchwork Tue Dec 31 23:50:34 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13924080 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 46DD429415 for ; Tue, 31 Dec 2024 23:50:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735689035; cv=none; b=tiRmyuAezjhuVUjgbXw9d7FhHLVrwDJJifeByebOprY512i2q3gQbyyJrE7eddU8KBEbh9aSDF0mqFDtuDkwU1rLqOc5mRNTIkticc9Jeaq9W/lCKZwHX6S3NpSk043Vbotjb4/vQoWeQxWay2dRKb8nzfRUEAoI6wR80tH1yHY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735689035; c=relaxed/simple; bh=7D+6DF9jStlT8NJegArPe4LMYv9T52+D0wBi3Yu07UE=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=BWVFb0Kcm8gRhcpM/GR3t+dSBgGMYKFfz4OIp5GoFptFEj21fZqRt+a3lL+k7z0z0mgXPH1WuD5JFfzs/HEog+WCT/127oKogafihS7Q/Uh3AfJfBOesq3pUVdC26E/gdx/fyAG9CJ8hl3S3CeVmbvaIrErdAjN4JlQ69MsJDW4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=e692z9qL; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="e692z9qL" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1FB98C4CED2; Tue, 31 Dec 2024 23:50:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1735689035; bh=7D+6DF9jStlT8NJegArPe4LMYv9T52+D0wBi3Yu07UE=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=e692z9qLwkaowaeRcsnyYTXHXOVZbZSGwMjYfuBPZTXoASjv6vxW0UiV29rntrP7C 7RFymTL2qvQdiPvuT1ch9SvcZBF65ncQ9jbejRrQ0pJJLO0U3RtFQkH8YjHnelB2a5 lWTeKn7U3WzlH+CaRoUm4+uNmAo/RDRnj2eAXs3JqFNk05B7Z7zQ+6X0KiuhL7MbmD SytVJSfs+VmMdM00GUAou24zTbzQaMLFhJNePfcHzmRwUfEFo17h6IDxJLxCvnKV5+ tBv82zqDHGW+pGFHEaSpOPGsm5pphOF8xQMLqh2mUvxh94YqpBxC16y5OYhXxNgpCS aBnqO9NISgS1g== Date: Tue, 31 Dec 2024 15:50:34 -0800 Subject: [PATCH 11/21] xfs_scrubbed: create daemon to listen for health events From: "Darrick J. Wong" To: aalbersh@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <173568778630.2710211.3580509295160781690.stgit@frogsfrogsfrogs> In-Reply-To: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> References: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Create a daemon program that can listen for and log health events. Signed-off-by: "Darrick J. Wong" --- scrub/Makefile | 15 ++- scrub/xfs_scrubbed.in | 287 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 300 insertions(+), 2 deletions(-) create mode 100644 scrub/xfs_scrubbed.in diff --git a/scrub/Makefile b/scrub/Makefile index 1e1109048c2a83..bd910922ceb4bb 100644 --- a/scrub/Makefile +++ b/scrub/Makefile @@ -18,6 +18,7 @@ XFS_SCRUB_ALL_PROG = xfs_scrub_all XFS_SCRUB_FAIL_PROG = xfs_scrub_fail XFS_SCRUB_ARGS = -p XFS_SCRUB_SERVICE_ARGS = -b -o autofsck +XFS_SCRUBBED_PROG = xfs_scrubbed ifeq ($(HAVE_SYSTEMD),yes) INSTALL_SCRUB += install-systemd SYSTEMD_SERVICES=\ @@ -108,9 +109,9 @@ endif # Automatically trigger a media scan once per month XFS_SCRUB_ALL_AUTO_MEDIA_SCAN_INTERVAL=1mo -LDIRT = $(XFS_SCRUB_ALL_PROG) $(XFS_SCRUB_FAIL_PROG) *.service *.cron +LDIRT = $(XFS_SCRUB_ALL_PROG) $(XFS_SCRUB_FAIL_PROG) $(XFS_SCRUBBED_PROG) *.service *.cron -default: depend $(LTCOMMAND) $(XFS_SCRUB_ALL_PROG) $(XFS_SCRUB_FAIL_PROG) $(OPTIONAL_TARGETS) +default: depend $(LTCOMMAND) $(XFS_SCRUB_ALL_PROG) $(XFS_SCRUB_FAIL_PROG) $(XFS_SCRUBBED_PROG) $(OPTIONAL_TARGETS) xfs_scrub_all: xfs_scrub_all.in $(builddefs) @echo " [SED] $@" @@ -123,6 +124,14 @@ xfs_scrub_all: xfs_scrub_all.in $(builddefs) -e "s|@scrub_args@|$(XFS_SCRUB_ARGS)|g" < $< > $@ $(Q)chmod a+x $@ +xfs_scrubbed: xfs_scrubbed.in $(builddefs) + @echo " [SED] $@" + $(Q)$(SED) -e "s|@sbindir@|$(PKG_SBIN_DIR)|g" \ + -e "s|@scrub_svcname@|$(scrub_svcname)|g" \ + -e "s|@pkg_version@|$(PKG_VERSION)|g" \ + < $< > $@ + $(Q)chmod a+x $@ + xfs_scrub_fail: xfs_scrub_fail.in $(builddefs) @echo " [SED] $@" $(Q)$(SED) -e "s|@sbindir@|$(PKG_SBIN_DIR)|g" \ @@ -165,6 +174,8 @@ install-scrub: default $(INSTALL) -m 755 -d $(PKG_SBIN_DIR) $(LTINSTALL) -m 755 $(LTCOMMAND) $(PKG_SBIN_DIR) $(INSTALL) -m 755 $(XFS_SCRUB_ALL_PROG) $(PKG_SBIN_DIR) + $(INSTALL) -m 755 -d $(PKG_LIBEXEC_DIR) + $(INSTALL) -m 755 $(XFS_SCRUBBED_PROG) $(PKG_LIBEXEC_DIR) $(INSTALL) -m 755 -d $(PKG_STATE_DIR) install-udev: $(UDEV_RULES) diff --git a/scrub/xfs_scrubbed.in b/scrub/xfs_scrubbed.in new file mode 100644 index 00000000000000..4d742a9151a082 --- /dev/null +++ b/scrub/xfs_scrubbed.in @@ -0,0 +1,287 @@ +#!/usr/bin/python3 + +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2024-2025 Oracle. All rights reserved. +# +# Author: Darrick J. Wong + +# Daemon to listen for and react to filesystem health events + +import sys +import os +import argparse +import fcntl +import json +import datetime +import errno +import ctypes +import gc +from concurrent.futures import ProcessPoolExecutor + +debug = False +log = False +everything = False +debug_fast = False +printf_prefix = '' + +# ioctl encoding stuff +_IOC_NRBITS = 8 +_IOC_TYPEBITS = 8 +_IOC_SIZEBITS = 14 +_IOC_DIRBITS = 2 + +_IOC_NRMASK = (1 << _IOC_NRBITS) - 1 +_IOC_TYPEMASK = (1 << _IOC_TYPEBITS) - 1 +_IOC_SIZEMASK = (1 << _IOC_SIZEBITS) - 1 +_IOC_DIRMASK = (1 << _IOC_DIRBITS) - 1 + +_IOC_NRSHIFT = 0 +_IOC_TYPESHIFT = (_IOC_NRSHIFT + _IOC_NRBITS) +_IOC_SIZESHIFT = (_IOC_TYPESHIFT + _IOC_TYPEBITS) +_IOC_DIRSHIFT = (_IOC_SIZESHIFT + _IOC_SIZEBITS) + +_IOC_NONE = 0 +_IOC_WRITE = 1 +_IOC_READ = 2 + +def _IOC(direction, type, nr, t): + assert direction <= _IOC_DIRMASK, direction + assert type <= _IOC_TYPEMASK, type + assert nr <= _IOC_NRMASK, nr + + size = ctypes.sizeof(t) + assert size <= _IOC_SIZEMASK, size + + return (((direction) << _IOC_DIRSHIFT) | + ((type) << _IOC_TYPESHIFT) | + ((nr) << _IOC_NRSHIFT) | + ((size) << _IOC_SIZESHIFT)) + +def _IOR(type, number, size): + return _IOC(_IOC_READ, type, number, size) + +def _IOW(type, number, size): + return _IOC(_IOC_WRITE, type, number, size) + +def _IOWR(type, number, size): + return _IOC(_IOC_READ | _IOC_WRITE, type, number, size) + +# xfs health monitoring ioctl stuff +XFS_HEALTH_MONITOR_FMT_JSON = 1 +XFS_HEALTH_MONITOR_VERBOSE = 1 << 0 + +class xfs_health_monitor(ctypes.Structure): + _fields_ = [ + ('flags', ctypes.c_ulonglong), + ('format', ctypes.c_ubyte), + ('_pad0', ctypes.c_ubyte * 7), + ('_pad1', ctypes.c_ulonglong * 2) + ] +assert ctypes.sizeof(xfs_health_monitor) == 32 + +XFS_IOC_HEALTH_MONITOR = _IOW(0x58, 68, xfs_health_monitor) + +def open_health_monitor(fd, verbose = False): + '''Return a health monitoring fd.''' + + arg = xfs_health_monitor() + arg.format = XFS_HEALTH_MONITOR_FMT_JSON + + if verbose: + arg.flags |= XFS_HEALTH_MONITOR_VERBOSE + + ret = fcntl.ioctl(fd, XFS_IOC_HEALTH_MONITOR, arg) + return ret + +# main program + +def health_reports(mon_fp): + '''Generate python objects describing health events.''' + global debug + global printf_prefix + + lines = [] + buf = mon_fp.readline() + while buf != '': + for line in buf.split('\0'): + line = line.strip() + if debug: + print(f'new line: {line}') + if line == '': + continue + + lines.append(line) + if not '}' in line: + continue + + s = ''.join(lines) + if debug: + print(f'new event: {s}') + try: + yield json.loads(s) + except json.decoder.JSONDecodeError as e: + print(f"{printf_prefix}: {e} from {s}", + file = sys.stderr) + pass + lines = [] + buf = mon_fp.readline() + +def log_event(event): + '''Log a monitoring event to stdout.''' + global printf_prefix + + print(f"{printf_prefix}: {event}") + sys.stdout.flush() + +def report_lost(event): + '''Report that the kernel lost events.''' + global printf_prefix + + print(f"{printf_prefix}: Events were lost.") + sys.stdout.flush() + +def report_shutdown(event): + '''Report an abortive shutdown of the filesystem.''' + global printf_prefix + REASONS = { + "meta_ioerr": "metadata IO error", + "log_ioerr": "log IO error", + "force_umount": "forced unmount", + "corrupt_incore": "in-memory state corruption", + "corrupt_ondisk": "ondisk metadata corruption", + "device_removed": "device removal", + } + + reasons = [] + for reason in event['reasons']: + if reason in REASONS: + reasons.append(REASONS[reason]) + else: + reasons.append(reason) + + print(f"{printf_prefix}: Filesystem shut down due to {', '.join(reasons)}.") + sys.stdout.flush() + +def handle_event(event): + '''Handle an event asynchronously.''' + def stringify_timestamp(event): + '''Try to convert a timestamp to something human readable.''' + try: + ts = datetime.datetime.fromtimestamp(event['time_ns'] / 1e9).astimezone() + event['time'] = str(ts) + del event['time_ns'] + except Exception as e: + # Not a big deal if we can't format the timestamp, but + # let's yell about that loudly + print(f'{printf_prefix}: bad timestamp: {e}', file = sys.stderr) + + global log + + stringify_timestamp(event) + if log: + log_event(event) + if event['type'] == 'lost': + report_lost(event) + elif event['type'] == 'shutdown': + report_shutdown(event) + +def monitor(mountpoint, event_queue, **kwargs): + '''Monitor the given mountpoint for health events.''' + global everything + + fd = os.open(mountpoint, os.O_RDONLY) + try: + mon_fd = open_health_monitor(fd, verbose = everything) + except OSError as e: + if e.errno != errno.ENOTTY and e.errno != errno.EOPNOTSUPP: + raise e + print(f"{mountpoint}: XFS health monitoring not supported.", + file = sys.stderr) + return 1 + finally: + # Close the mountpoint if opening the health monitor fails + os.close(fd) + + # Ownership of mon_fd (and hence responsibility for closing it) is + # transferred to the mon_fp object. + with os.fdopen(mon_fd) as mon_fp: + nr = 0 + for e in health_reports(mon_fp): + event_queue.submit(handle_event, e) + + # Periodically run the garbage collector to constrain + # memory usage in the main thread. If only there was + # a way to submit to a queue without everything being + # tied up in a Future + if nr % 5355 == 0: + gc.collect() + nr += 1 + + return 0 + +def main(): + global debug + global log + global printf_prefix + global everything + global debug_fast + + parser = argparse.ArgumentParser( \ + description = "XFS filesystem health monitoring demon.") + parser.add_argument("--debug", help = "Enabling debugging messages.", \ + action = "store_true") + parser.add_argument("--log", help = "Log health events to stdout.", \ + action = "store_true") + parser.add_argument("--everything", help = "Capture all events.", \ + action = "store_true") + parser.add_argument("-V", help = "Report version and exit.", \ + action = "store_true") + parser.add_argument('mountpoint', default = None, nargs = '?', + help = 'XFS filesystem mountpoint to target.') + parser.add_argument('--debug-fast', action = 'store_true', \ + help = argparse.SUPPRESS) + args = parser.parse_args() + + if args.V: + print("xfs_scrubbed version @pkg_version@") + return 0 + + if args.mountpoint is None: + parser.error("the following arguments are required: mountpoint") + return 1 + + if args.debug: + debug = True + if args.log: + log = True + if args.everything: + everything = True + if args.debug_fast: + debug_fast = True + + # Use a separate subprocess to handle the events so that the main event + # reading process does not block on the GIL of the event handling + # subprocess. The downside is that we cannot pass function pointers + # and all data must be pickleable; the upside is not losing events. + # + # If the secret maximum efficiency setting is enabled, assume this is + # part of QA, so use all CPUs to process events. Normally we start one + # background process to minimize service footprint. + if debug_fast: + args.event_queue = ProcessPoolExecutor() + else: + args.event_queue = ProcessPoolExecutor(max_workers = 1) + + printf_prefix = args.mountpoint + ret = 0 + try: + ret = monitor(**vars(args)) + except KeyboardInterrupt: + # Consider SIGINT to be a clean exit. + pass + + args.event_queue.shutdown() + return ret + +if __name__ == '__main__': + sys.exit(main()) From patchwork Tue Dec 31 23:50:50 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13924081 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CEAA31B0425 for ; Tue, 31 Dec 2024 23:50:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735689050; cv=none; b=NIACKYFsLCRcN3mGA/66xRq85OAjuL7YDvWT0+ZGutkJH49QA4pkjKbzfLcys5GkbMCYwxKd1qGKGXAjBTcjI1jIiqvLyScVqAnl5Zk3z/4HSm80u3gyOvFxai/uI+obm47PlpC3LN6NScMQhSfbJYuNHuoB+41ZTS8VOzYlbJo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735689050; c=relaxed/simple; bh=sf4DJSSibXS1HhhtSfuW0MSPPb5Kxi3HVM8lCpIBEN4=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=GIX3F8wnLtMMDNF0audA631/lPCTJwrVKcx88YWP59h95CFDSaQRw1iNGpq/ZJp4X6s2XXIM1sOv4gI6Xq0oB7tg7BslIwLS/xMwOGpLUHc+BdTAmfIt+kcVP0Pn6vErC+3nUWGla5QdQsQb3bMhs4JB86eh57FsfR25zUBLXNU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=HjfpMWht; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="HjfpMWht" Received: by smtp.kernel.org (Postfix) with ESMTPSA id A9D01C4CED2; Tue, 31 Dec 2024 23:50:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1735689050; bh=sf4DJSSibXS1HhhtSfuW0MSPPb5Kxi3HVM8lCpIBEN4=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=HjfpMWht0AOMCY3BxRtG4iCEHfS7ctxMj/JKbwcdZDc62/MVdrU8LvR7/+jcSCQuf ELkBLfgsa2xTKeInamqlsc819CANmX2EvbEseFgQOGqDT0rQU0ccNZ296yOGOv/oqa Pkjpe2TtKegxUgbxsGFQvzKxow+0Ys2F+xiIN8nGqreQyviuUqggEk5/fzlaXhwPnz XwED+u+8QYknbPKPEx//aF2WpbA82KN1uiR8CRlSWICUXcxK5LjHtYgkAhkWoUTXrv a5l6Kc84m9wDTahZ4AcYlsFNS6Pg464GvdqMRxRbcoZCoj/Pxhhs0l47UwIhcfF9ne fvRUcsvgoCUPQ== Date: Tue, 31 Dec 2024 15:50:50 -0800 Subject: [PATCH 12/21] xfs_scrubbed: check events against schema From: "Darrick J. Wong" To: aalbersh@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <173568778645.2710211.11707695819627896340.stgit@frogsfrogsfrogs> In-Reply-To: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> References: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Validate that the event objects that we get from the kernel actually obey the schema that the kernel publishes. Signed-off-by: "Darrick J. Wong" --- libxfs/Makefile | 10 ++++++-- scrub/Makefile | 1 + scrub/xfs_scrubbed.in | 62 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 3 deletions(-) diff --git a/libxfs/Makefile b/libxfs/Makefile index 61c43529b532b6..f84eb5b43cdddd 100644 --- a/libxfs/Makefile +++ b/libxfs/Makefile @@ -151,6 +151,8 @@ EXTRA_OBJECTS=\ LDIRT += $(EXTRA_OBJECTS) +JSON_SCHEMAS=xfs_healthmon.schema.json + # # Tracing flags: # -DMEM_DEBUG all zone memory use @@ -174,7 +176,7 @@ LTLIBS = $(LIBPTHREAD) $(LIBRT) # don't try linking xfs_repair with a debug libxfs. DEBUG = -DNDEBUG -default: ltdepend $(LTLIBRARY) $(EXTRA_OBJECTS) +default: ltdepend $(LTLIBRARY) $(EXTRA_OBJECTS) $(JSON_SCHEMAS) %dummy.o: %dummy.cpp @echo " [CXXD] $@" @@ -196,14 +198,16 @@ MAKECXXDEP := $(MAKEDEPEND) $(CXXFLAGS) include $(BUILDRULES) install: default - $(INSTALL) -m 755 -d $(PKG_INC_DIR) + $(INSTALL) -m 755 -d $(PKG_DATA_DIR) + $(INSTALL) -m 644 $(JSON_SCHEMAS) $(PKG_DATA_DIR) install-headers: $(addsuffix -hdrs, $(PKGHFILES)) %-hdrs: $(Q)$(LN_S) -f $(CURDIR)/$* $(TOPDIR)/include/xfs/$* -install-dev: install +install-dev: default + $(INSTALL) -m 755 -d $(PKG_INC_DIR) $(INSTALL) -m 644 $(PKGHFILES) $(PKG_INC_DIR) # We need to install the headers before building the dependencies. If we diff --git a/scrub/Makefile b/scrub/Makefile index bd910922ceb4bb..7d4fa0ddc09685 100644 --- a/scrub/Makefile +++ b/scrub/Makefile @@ -129,6 +129,7 @@ xfs_scrubbed: xfs_scrubbed.in $(builddefs) $(Q)$(SED) -e "s|@sbindir@|$(PKG_SBIN_DIR)|g" \ -e "s|@scrub_svcname@|$(scrub_svcname)|g" \ -e "s|@pkg_version@|$(PKG_VERSION)|g" \ + -e "s|@pkg_data_dir@|$(PKG_DATA_DIR)|g" \ < $< > $@ $(Q)chmod a+x $@ diff --git a/scrub/xfs_scrubbed.in b/scrub/xfs_scrubbed.in index 4d742a9151a082..992797113d6d30 100644 --- a/scrub/xfs_scrubbed.in +++ b/scrub/xfs_scrubbed.in @@ -18,6 +18,52 @@ import ctypes import gc from concurrent.futures import ProcessPoolExecutor +try: + # Not all systems will have this json schema validation libarary, + # so we make it optional. + import jsonschema + + def init_validation(args): + '''Initialize event json validation.''' + try: + with open(args.event_schema) as fp: + schema_js = json.load(fp) + except Exception as e: + print(f"{args.event_schema}: {e}", file = sys.stderr) + return + + try: + vcls = jsonschema.validators.validator_for(schema_js) + vcls.check_schema(schema_js) + validator = vcls(schema_js) + except jsonschema.exceptions.SchemaError as e: + print(f"{args.event_schema}: invalid event data, {e.message}", + file = sys.stderr) + return + except Exception as e: + print(f"{args.event_schema}: {e}", file = sys.stderr) + return + + def v(i): + e = jsonschema.exceptions.best_match(validator.iter_errors(i)) + if e: + print(f"{printf_prefix}: {e.message}", + file = sys.stderr) + return False + return True + + return v + +except: + def init_validation(args): + if args.require_validation: + print("JSON schema validation not available.", + file = sys.stderr) + return + + return lambda instance: True + +validator_fn = None debug = False log = False everything = False @@ -177,6 +223,12 @@ def handle_event(event): global log + # Ignore any event that doesn't pass our schema. This program must + # not try to handle a newer kernel that say things that it is not + # prepared to handle. + if not validator_fn(event): + return + stringify_timestamp(event) if log: log_event(event) @@ -225,6 +277,7 @@ def main(): global printf_prefix global everything global debug_fast + global validator_fn parser = argparse.ArgumentParser( \ description = "XFS filesystem health monitoring demon.") @@ -240,6 +293,11 @@ def main(): help = 'XFS filesystem mountpoint to target.') parser.add_argument('--debug-fast', action = 'store_true', \ help = argparse.SUPPRESS) + parser.add_argument('--require-validation', action = 'store_true', \ + help = argparse.SUPPRESS) + parser.add_argument('--event-schema', type = str, \ + default = '@pkg_data_dir@/xfs_healthmon.schema.json', \ + help = argparse.SUPPRESS) args = parser.parse_args() if args.V: @@ -250,6 +308,10 @@ def main(): parser.error("the following arguments are required: mountpoint") return 1 + validator_fn = init_validation(args) + if not validator_fn: + return 1 + if args.debug: debug = True if args.log: From patchwork Tue Dec 31 23:51:05 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13924082 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BC7E71B0428 for ; Tue, 31 Dec 2024 23:51:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735689066; cv=none; b=s3Db9JPLm2+vzpuWOh8ounxaNtA8r9OS8uyiYNYZVTTE5GEjaUw8oEo+Sy8lT11FkewCKZNwmhN5x+ta7VPaROSu5VCAH0xyEGuMsH5lPOQNiwjYLtVrGnkiVKOGn9viWbq5ee4VUYU72U5/WYv9jGaM0myH3wlEcvtDsdun2xk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735689066; c=relaxed/simple; bh=Z+XOHtJGNyHyCU2B1Ba4LxA2CntKYszeePVRd60Rchg=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=mF0wSzGjpXTBC15f2OXobESRDCmoeOH2TN895+SPnr4Mr5DVCaQDPGXfNbKfKhBpUbHN+dECSEYaTp1NesV7xM3ViDNWsoNln1C4+eir1hT+OhZwA2Cpz+ks6tSUnafScXasAqqlHE5schUcdzAsUix3Q2F1jaPO4snFeSXrEss= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=j805Z+SE; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="j805Z+SE" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 9157FC4CED2; Tue, 31 Dec 2024 23:51:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1735689066; bh=Z+XOHtJGNyHyCU2B1Ba4LxA2CntKYszeePVRd60Rchg=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=j805Z+SE3+Evok6Gjb3MjEIVBvxPzj4o1ooBPqnJJbpyNiIVbMKxDr2fjqN6oPozx chwjiTvt3ygrAr96jegJAOPmHYK3ikAtKh4Vv9unbXNwE+eujgJGvbaWM4FB7qdjnD SY2ZiYSjHOxVUmgiQCT4ImhElrMcr4ZIVyQMzXI3Ynbxyd0AXuqIg6Z8rw1f3TncqB fZA4ndqRMq8XJ8MAWKOMaG+wxAI0Oh6EsTdvPfyAindkJ6+kE9p/uctEuhgEPr0ym2 uTbUP9fdNxohCtLepQwHAu3vpd3wJKL3n1J9DkwG3HVfy1GnNDaC1i2YLTqzrnZrh4 zMF7gr71ixzhw== Date: Tue, 31 Dec 2024 15:51:05 -0800 Subject: [PATCH 13/21] xfs_scrubbed: enable repairing filesystems From: "Darrick J. Wong" To: aalbersh@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <173568778660.2710211.1025674826117983910.stgit@frogsfrogsfrogs> In-Reply-To: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> References: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Make it so that our health monitoring daemon can initiate repairs. Because repairs can take a while to run, so we don't actually want to be doing that work in the event thread because the kernel queue can drop events if userspace doesn't respond in time. Therefore, create a subprocess executor to run the repairs in the background, and do the repairs from there. The subprocess executor is similar in concept to what a libfrog workqueue does, but the workers do not share address space, which eliminates GIL contention. Signed-off-by: "Darrick J. Wong" --- scrub/xfs_scrubbed.in | 366 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 360 insertions(+), 6 deletions(-) diff --git a/scrub/xfs_scrubbed.in b/scrub/xfs_scrubbed.in index 992797113d6d30..c626c7bd56630c 100644 --- a/scrub/xfs_scrubbed.in +++ b/scrub/xfs_scrubbed.in @@ -17,6 +17,7 @@ import errno import ctypes import gc from concurrent.futures import ProcessPoolExecutor +import ctypes.util try: # Not all systems will have this json schema validation libarary, @@ -37,7 +38,7 @@ try: vcls.check_schema(schema_js) validator = vcls(schema_js) except jsonschema.exceptions.SchemaError as e: - print(f"{args.event_schema}: invalid event data, {e.message}", + print(f"{args.event_schema}: invalid event data: {e.message}", file = sys.stderr) return except Exception as e: @@ -69,6 +70,9 @@ log = False everything = False debug_fast = False printf_prefix = '' +want_repair = False +libhandle = None +repair_queue = None # placeholder for event queue worker # ioctl encoding stuff _IOC_NRBITS = 8 @@ -112,6 +116,9 @@ def _IOW(type, number, size): def _IOWR(type, number, size): return _IOC(_IOC_READ | _IOC_WRITE, type, number, size) +def _IOWR(type, number, size): + return _IOC(_IOC_READ | _IOC_WRITE, type, number, size) + # xfs health monitoring ioctl stuff XFS_HEALTH_MONITOR_FMT_JSON = 1 XFS_HEALTH_MONITOR_VERBOSE = 1 << 0 @@ -139,9 +146,206 @@ def open_health_monitor(fd, verbose = False): ret = fcntl.ioctl(fd, XFS_IOC_HEALTH_MONITOR, arg) return ret +# libhandle stuff +class xfs_fsid(ctypes.Structure): + _fields_ = [ + ("_val0", ctypes.c_uint), + ("_val1", ctypes.c_uint) + ] + +class xfs_fid(ctypes.Structure): + _fields_ = [ + ("fid_len", ctypes.c_ushort), + ("fid_pad", ctypes.c_ushort), + ("fid_gen", ctypes.c_uint), + ("fid_ino", ctypes.c_ulonglong) + ] + +class xfs_handle(ctypes.Structure): + _fields_ = [ + ("_ha_fsid", xfs_fsid), + ("ha_fid", xfs_fid) + ] +assert ctypes.sizeof(xfs_handle) == 24 + +class fshandle(object): + def __init__(self, fd, mountpoint): + global libhandle + global printf_prefix + + self.handle = xfs_handle() + + if mountpoint is None: + raise Exception('fshandle needs a mountpoint') + + self.mountpoint = mountpoint + + # Create the file and fs handles for the open mountpoint + # so that we can compare them later + buf = ctypes.c_void_p() + buflen = ctypes.c_size_t() + ret = libhandle.fd_to_handle(fd, buf, buflen) + if ret < 0: + errcode = ctypes.get_errno() + raise OSError(errcode, + f'cannot create handle: {os.strerror(errcode)}', + printf_prefix) + if buflen.value != ctypes.sizeof(xfs_handle): + libhandle.free_handle(buf, buflen.value) + raise Exception(f"fshandle expected {ctypes.sizeof(xfs_handle)} bytes, got {buflen.value}.") + + hanp = ctypes.cast(buf, ctypes.POINTER(xfs_handle)) + self.handle = hanp.contents + + def open(self): + '''Reopen a file handle obtained via weak reference.''' + global libhandle + global printf_prefix + + buf = ctypes.c_void_p() + buflen = ctypes.c_size_t() + + fd = os.open(self.mountpoint, os.O_RDONLY) + + # Create the file and fs handles for the open mountpoint + # so that we can compare them later + ret = libhandle.fd_to_handle(fd, buf, buflen) + if ret < 0: + errcode = ctypes.get_errno() + os.close(fd) + raise OSError(errcode, + f'resampling handle: {os.strerror(errcode)}', + printf_prefix) + + hanp = ctypes.cast(buf, ctypes.POINTER(xfs_handle)) + + # Did we get the same handle? + if buflen.value != ctypes.sizeof(xfs_handle) or \ + bytes(hanp.contents) != bytes(self.handle): + os.close(fd) + libhandle.free_handle(buf, buflen) + raise OSError(errno.ESTALE, + os.strerror(errno.ESTALE), + printf_prefix) + + libhandle.free_handle(buf, buflen) + return fd + +def libhandle_load(): + '''Load libhandle and set things up.''' + global libhandle + + soname = ctypes.util.find_library('handle') + if soname is None: + raise OSError(errno.ENOENT, + f'while finding library: {os.strerror(errno.ENOENT)}', + 'libhandle') + + libhandle = ctypes.CDLL(soname, use_errno = True) + libhandle.fd_to_handle.argtypes = ( + ctypes.c_int, + ctypes.POINTER(ctypes.c_void_p), + ctypes.POINTER(ctypes.c_size_t)) + libhandle.handle_to_fshandle.argtypes = ( + ctypes.c_void_p, + ctypes.c_size_t, + ctypes.POINTER(ctypes.c_void_p), + ctypes.POINTER(ctypes.c_size_t)) + libhandle.path_to_fshandle.argtypes = ( + ctypes.c_char_p, + ctypes.c_void_p, + ctypes.c_size_t) + libhandle.free_handle.argtypes = ( + ctypes.c_void_p, + ctypes.c_size_t) + +# metadata scrubbing stuff +XFS_SCRUB_TYPE_PROBE = 0 +XFS_SCRUB_TYPE_SB = 1 +XFS_SCRUB_TYPE_AGF = 2 +XFS_SCRUB_TYPE_AGFL = 3 +XFS_SCRUB_TYPE_AGI = 4 +XFS_SCRUB_TYPE_BNOBT = 5 +XFS_SCRUB_TYPE_CNTBT = 6 +XFS_SCRUB_TYPE_INOBT = 7 +XFS_SCRUB_TYPE_FINOBT = 8 +XFS_SCRUB_TYPE_RMAPBT = 9 +XFS_SCRUB_TYPE_REFCNTBT = 10 +XFS_SCRUB_TYPE_INODE = 11 +XFS_SCRUB_TYPE_BMBTD = 12 +XFS_SCRUB_TYPE_BMBTA = 13 +XFS_SCRUB_TYPE_BMBTC = 14 +XFS_SCRUB_TYPE_DIR = 15 +XFS_SCRUB_TYPE_XATTR = 16 +XFS_SCRUB_TYPE_SYMLINK = 17 +XFS_SCRUB_TYPE_PARENT = 18 +XFS_SCRUB_TYPE_RTBITMAP = 19 +XFS_SCRUB_TYPE_RTSUM = 20 +XFS_SCRUB_TYPE_UQUOTA = 21 +XFS_SCRUB_TYPE_GQUOTA = 22 +XFS_SCRUB_TYPE_PQUOTA = 23 +XFS_SCRUB_TYPE_FSCOUNTERS = 24 +XFS_SCRUB_TYPE_QUOTACHECK = 25 +XFS_SCRUB_TYPE_NLINKS = 26 +XFS_SCRUB_TYPE_HEALTHY = 27 +XFS_SCRUB_TYPE_DIRTREE = 28 +XFS_SCRUB_TYPE_METAPATH = 29 +XFS_SCRUB_TYPE_RGSUPER = 30 +XFS_SCRUB_TYPE_RGBITMAP = 31 +XFS_SCRUB_TYPE_RTRMAPBT = 32 +XFS_SCRUB_TYPE_RTREFCBT = 33 + +XFS_SCRUB_IFLAG_REPAIR = 1 << 0 +XFS_SCRUB_OFLAG_CORRUPT = 1 << 1 +XFS_SCRUB_OFLAG_PREEN = 1 << 2 +XFS_SCRUB_OFLAG_XFAIL = 1 << 3 +XFS_SCRUB_OFLAG_XCORRUPT = 1 << 4 +XFS_SCRUB_OFLAG_INCOMPLETE = 1 << 5 +XFS_SCRUB_OFLAG_WARNING = 1 << 6 +XFS_SCRUB_OFLAG_NO_REPAIR_NEEDED = 1 << 7 +XFS_SCRUB_IFLAG_FORCE_REBUILD = 1 << 8 + +class xfs_scrub_metadata(ctypes.Structure): + _fields_ = [ + ('sm_type', ctypes.c_uint), + ('sm_flags', ctypes.c_uint), + ('sm_ino', ctypes.c_ulonglong), + ('sm_gen', ctypes.c_uint), + ('sm_agno', ctypes.c_uint), + ('_pad', ctypes.c_ulonglong * 5), + ] +assert ctypes.sizeof(xfs_scrub_metadata) == 64 + +XFS_IOC_SCRUB_METADATA = _IOWR(0x58, 60, xfs_scrub_metadata) + +def __xfs_repair_metadata(fd, type, group, ino, gen): + '''Call the kernel to repair some inode metadata.''' + + arg = xfs_scrub_metadata() + arg.sm_type = type + arg.sm_flags = XFS_SCRUB_IFLAG_REPAIR + arg.sm_ino = ino + arg.sm_gen = gen + arg.sm_agno = group + + fcntl.ioctl(fd, XFS_IOC_SCRUB_METADATA, arg) + return arg.sm_flags + +def xfs_repair_fs_metadata(fd, type): + '''Call the kernel to repair some whole-fs metadata.''' + return __xfs_repair_metadata(fd, type, 0, 0, 0) + +def xfs_repair_group_metadata(fd, type, group): + '''Call the kernel to repair some group metadata.''' + return __xfs_repair_metadata(fd, type, group, 0, 0) + +def xfs_repair_inode_metadata(fd, type, ino, gen): + '''Call the kernel to repair some inode metadata.''' + return __xfs_repair_metadata(fd, type, 0, ino, gen) + # main program -def health_reports(mon_fp): +def health_reports(mon_fp, fh): '''Generate python objects describing health events.''' global debug global printf_prefix @@ -164,7 +368,7 @@ def health_reports(mon_fp): if debug: print(f'new event: {s}') try: - yield json.loads(s) + yield (json.loads(s), fh) except json.decoder.JSONDecodeError as e: print(f"{printf_prefix}: {e} from {s}", file = sys.stderr) @@ -208,7 +412,7 @@ def report_shutdown(event): print(f"{printf_prefix}: Filesystem shut down due to {', '.join(reasons)}.") sys.stdout.flush() -def handle_event(event): +def handle_event(e): '''Handle an event asynchronously.''' def stringify_timestamp(event): '''Try to convert a timestamp to something human readable.''' @@ -222,6 +426,17 @@ def handle_event(event): print(f'{printf_prefix}: bad timestamp: {e}', file = sys.stderr) global log + global repair_queue + + # Use a separate subprocess to handle the repairs so that the event + # processing worker does not block on the GIL of the repair workers. + # The downside is that we cannot pass function pointers and all data + # must be pickleable; the upside is that we don't stall processing of + # non-sickness events while repairs are in progress. + if want_repair and not repair_queue: + repair_queue = ProcessPoolExecutor(max_workers = 1) + + event, fh = e # Ignore any event that doesn't pass our schema. This program must # not try to handle a newer kernel that say things that it is not @@ -236,13 +451,21 @@ def handle_event(event): report_lost(event) elif event['type'] == 'shutdown': report_shutdown(event) + elif want_repair and event['type'] == 'sick': + repair_queue.submit(repair_metadata, event, fh) def monitor(mountpoint, event_queue, **kwargs): '''Monitor the given mountpoint for health events.''' global everything + global log + global printf_prefix + global want_repair + fh = None fd = os.open(mountpoint, os.O_RDONLY) try: + if want_repair: + fh = fshandle(fd, mountpoint) mon_fd = open_health_monitor(fd, verbose = everything) except OSError as e: if e.errno != errno.ENOTTY and e.errno != errno.EOPNOTSUPP: @@ -251,14 +474,15 @@ def monitor(mountpoint, event_queue, **kwargs): file = sys.stderr) return 1 finally: - # Close the mountpoint if opening the health monitor fails + # Close the mountpoint if opening the health monitor fails; + # the handle object will free its own memory. os.close(fd) # Ownership of mon_fd (and hence responsibility for closing it) is # transferred to the mon_fp object. with os.fdopen(mon_fd) as mon_fp: nr = 0 - for e in health_reports(mon_fp): + for e in health_reports(mon_fp, fh): event_queue.submit(handle_event, e) # Periodically run the garbage collector to constrain @@ -271,6 +495,125 @@ def monitor(mountpoint, event_queue, **kwargs): return 0 +def __scrub_type(code): + '''Convert a "structures" json list to a scrub type code.''' + SCRUB_TYPES = { + "probe": XFS_SCRUB_TYPE_PROBE, + "sb": XFS_SCRUB_TYPE_SB, + "agf": XFS_SCRUB_TYPE_AGF, + "agfl": XFS_SCRUB_TYPE_AGFL, + "agi": XFS_SCRUB_TYPE_AGI, + "bnobt": XFS_SCRUB_TYPE_BNOBT, + "cntbt": XFS_SCRUB_TYPE_CNTBT, + "inobt": XFS_SCRUB_TYPE_INOBT, + "finobt": XFS_SCRUB_TYPE_FINOBT, + "rmapbt": XFS_SCRUB_TYPE_RMAPBT, + "refcountbt": XFS_SCRUB_TYPE_REFCNTBT, + "inode": XFS_SCRUB_TYPE_INODE, + "bmapbtd": XFS_SCRUB_TYPE_BMBTD, + "bmapbta": XFS_SCRUB_TYPE_BMBTA, + "bmapbtc": XFS_SCRUB_TYPE_BMBTC, + "directory": XFS_SCRUB_TYPE_DIR, + "xattr": XFS_SCRUB_TYPE_XATTR, + "symlink": XFS_SCRUB_TYPE_SYMLINK, + "parent": XFS_SCRUB_TYPE_PARENT, + "rtbitmap": XFS_SCRUB_TYPE_RTBITMAP, + "rtsummary": XFS_SCRUB_TYPE_RTSUM, + "usrquota": XFS_SCRUB_TYPE_UQUOTA, + "grpquota": XFS_SCRUB_TYPE_GQUOTA, + "prjquota": XFS_SCRUB_TYPE_PQUOTA, + "fscounters": XFS_SCRUB_TYPE_FSCOUNTERS, + "quotacheck": XFS_SCRUB_TYPE_QUOTACHECK, + "nlinks": XFS_SCRUB_TYPE_NLINKS, + "healthy": XFS_SCRUB_TYPE_HEALTHY, + "dirtree": XFS_SCRUB_TYPE_DIRTREE, + "metapath": XFS_SCRUB_TYPE_METAPATH, + "rgsuper": XFS_SCRUB_TYPE_RGSUPER, + "rgbitmap": XFS_SCRUB_TYPE_RGBITMAP, + "rtrmapbt": XFS_SCRUB_TYPE_RTRMAPBT, + "rtrefcountbt": XFS_SCRUB_TYPE_RTREFCBT, + } + + if code not in SCRUB_TYPES: + return None + + return SCRUB_TYPES[code] + +def report_outcome(oflags): + if oflags & (XFS_SCRUB_OFLAG_CORRUPT | \ + XFS_SCRUB_OFLAG_CORRUPT | \ + XFS_SCRUB_OFLAG_INCOMPLETE): + return "Repair unsuccessful; offline repair required." + + if oflags & XFS_SCRUB_OFLAG_XFAIL: + return "Seems correct but cross-referencing failed; offline repair recommended." + + if oflags & XFS_SCRUB_OFLAG_NO_REPAIR_NEEDED: + return "No modification needed." + + return "Repairs successful." + +def repair_wholefs(event, fd): + '''React to a fs-domain corruption event by repairing it.''' + for s in event['structures']: + type = __scrub_type(s) + if type is None: + continue + try: + oflags = xfs_repair_fs_metadata(fd, type) + print(f"{printf_prefix}: {s}: {report_outcome(oflags)}") + sys.stdout.flush() + except Exception as e: + print(f"{printf_prefix}: {s}: {e}", file = sys.stderr) + +def repair_group(event, fd, group_type): + '''React to a group-domain corruption event by repairing it.''' + for s in event['structures']: + type = __scrub_type(s) + if type is None: + continue + try: + oflags = xfs_repair_group_metadata(fd, type, event['group']) + print(f"{printf_prefix}: {s}: {report_outcome(oflags)}") + sys.stdout.flush() + except Exception as e: + print(f"{printf_prefix}: {s}: {e}", file = sys.stderr) + +def repair_inode(event, fd): + '''React to a inode-domain corruption event by repairing it.''' + for s in event['structures']: + type = __scrub_type(s) + if type is None: + continue + try: + oflags = xfs_repair_inode_metadata(fd, type, + event['inumber'], event['generation']) + print(f"{printf_prefix}: {s}: {report_outcome(oflags)}") + sys.stdout.flush() + except Exception as e: + print(f"{printf_prefix}: {s}: {e}", file = sys.stderr) + +def repair_metadata(event, fh): + '''Repair a metadata corruption.''' + global debug + global printf_prefix + + if debug: + print(f'repair {event}') + + fd = fh.open() + try: + if event['domain'] in ['fs', 'realtime']: + repair_wholefs(event, fd) + elif event['domain'] in ['perag', 'rtgroup']: + repair_group(event, fd, event['domain']) + elif event['domain'] == 'inode': + repair_inode(event, fd) + else: + raise Exception(f"{printf_prefix}: Unknown metadata domain \"{event['domain']}\".") + finally: + os.close(fd) + def main(): global debug global log @@ -278,6 +621,7 @@ def main(): global everything global debug_fast global validator_fn + global want_repair parser = argparse.ArgumentParser( \ description = "XFS filesystem health monitoring demon.") @@ -287,6 +631,8 @@ def main(): action = "store_true") parser.add_argument("--everything", help = "Capture all events.", \ action = "store_true") + parser.add_argument("--repair", help = "Automatically repair corrupt metadata.", \ + action = "store_true") parser.add_argument("-V", help = "Report version and exit.", \ action = "store_true") parser.add_argument('mountpoint', default = None, nargs = '?', @@ -312,6 +658,12 @@ def main(): if not validator_fn: return 1 + try: + libhandle_load() + except OSError as e: + print(f"libhandle: {e}", file = sys.stderr) + return 1 + if args.debug: debug = True if args.log: @@ -320,6 +672,8 @@ def main(): everything = True if args.debug_fast: debug_fast = True + if args.repair: + want_repair = True # Use a separate subprocess to handle the events so that the main event # reading process does not block on the GIL of the event handling From patchwork Tue Dec 31 23:51:21 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13924083 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 689CE29415 for ; Tue, 31 Dec 2024 23:51:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735689082; cv=none; b=QTk+MFtnYiQhyolEMGqbN01jdqnFMS86i9TPSwxnoXM9I2VwKUvY/DUNNPZjjMd2ekmiq0lZMtTiyEWcB2gQ+CErsRU9iFB30P2chJXlFlrljxbB3hMthxZO77W2Ho3e2wi59vbtKoX2UJg6knRY8OwJcBkb00V/tn6mGR8oO38= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735689082; c=relaxed/simple; bh=CEbDRD88kIXr3wkBiz3lWfRHee3gP2KV8LQtslWyixg=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=FGrr39Li7ZdHiCAv4/2O9t8PP6LCI5MaaVT4Hz588c0mLRI92CT0NYk85IQR+XmqnLtNAxCQOueZqDoynVoxaP00ArTAIckKmT59KHxzukOqBj0AwfqpzlceoJKW5zFBBt1oTYdkwjjYrsovw2w8luE8wRcBX0gpZeVwZm/CYB0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=dlrLEex6; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="dlrLEex6" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 40F32C4CED2; Tue, 31 Dec 2024 23:51:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1735689082; bh=CEbDRD88kIXr3wkBiz3lWfRHee3gP2KV8LQtslWyixg=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=dlrLEex68DMP7zYt4XJX/2nWOPmwciChnjXZC6fZqPgz6sszn0WpQaWYYR9YMOvtQ vnMqBlrrsX1QUQr/hW4MXGyhyShGZITNJPgnKFnwaf+yeC4uJbk6PYtXLFDhLV1jZn UdgE0g8td1PMQ+Ovcl6eRrBfNyEpeBBB2paFf7J3Rir8sUj7NcvT7CawqoRmeWXOh0 DLSmJQO5eEjOfLvMmZcI2Ryjg0SXTU4ookWxw8T1CrE3Aan20dyC/iPPmuCN/YGWpb SNFAc2fzW/U4/88LHyHe1r8txG/XHeREB1nA2zue4N5B4424tXyOexIiQvrVWC8Dqe ikYqkSbjHKgog== Date: Tue, 31 Dec 2024 15:51:21 -0800 Subject: [PATCH 14/21] xfs_scrubbed: check for fs features needed for effective repairs From: "Darrick J. Wong" To: aalbersh@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <173568778676.2710211.10139562694492141808.stgit@frogsfrogsfrogs> In-Reply-To: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> References: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Online repair relies heavily on back references such as reverse mappings and directory parent pointers to add redundancy to the filesystem. Check for these two features and whine a bit if they are missing. Signed-off-by: "Darrick J. Wong" --- scrub/xfs_scrubbed.in | 72 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/scrub/xfs_scrubbed.in b/scrub/xfs_scrubbed.in index c626c7bd56630c..25465128864583 100644 --- a/scrub/xfs_scrubbed.in +++ b/scrub/xfs_scrubbed.in @@ -71,6 +71,8 @@ everything = False debug_fast = False printf_prefix = '' want_repair = False +has_parent = False +has_rmapbt = False libhandle = None repair_queue = None # placeholder for event queue worker @@ -343,6 +345,57 @@ def xfs_repair_inode_metadata(fd, type, ino, gen): '''Call the kernel to repair some inode metadata.''' return __xfs_repair_metadata(fd, type, 0, ino, gen) +# fsgeometry ioctl +class xfs_fsop_geom(ctypes.Structure): + _fields_ = [ + ("blocksize", ctypes.c_uint), + ("rtextesize", ctypes.c_uint), + ("agblocks", ctypes.c_uint), + ("agcount", ctypes.c_uint), + ("logblocks", ctypes.c_uint), + ("sectsize", ctypes.c_uint), + ("inodesize", ctypes.c_uint), + ("imaxpct", ctypes.c_uint), + ("datablocks", ctypes.c_ulonglong), + ("rtblocks", ctypes.c_ulonglong), + ("rtextents", ctypes.c_ulonglong), + ("logstart", ctypes.c_ulonglong), + ("uuid", ctypes.c_ubyte * 16), + ("sunit", ctypes.c_uint), + ("swidth", ctypes.c_uint), + ("version", ctypes.c_uint), + ("flags", ctypes.c_uint), + ("logsectsize", ctypes.c_uint), + ("rtsectsize", ctypes.c_uint), + ("dirblocksize", ctypes.c_uint), + ("logsunit", ctypes.c_uint), + ("sick", ctypes.c_uint), + ("checked", ctypes.c_uint), + ("rgblocks", ctypes.c_uint), + ("rgcount", ctypes.c_uint), + ("_pad", ctypes.c_ulonglong * 16), + ] +assert ctypes.sizeof(xfs_fsop_geom) == 256 + +XFS_FSOP_GEOM_FLAGS_RMAPBT = 1 << 19 +XFS_FSOP_GEOM_FLAGS_PARENT = 1 << 25 + +XFS_IOC_FSGEOMETRY = _IOR (0x58, 126, xfs_fsop_geom) + +def xfs_has_parent(fd): + '''Does this filesystem have parent pointers?''' + + arg = xfs_fsop_geom() + fcntl.ioctl(fd, XFS_IOC_FSGEOMETRY, arg) + return arg.flags & XFS_FSOP_GEOM_FLAGS_PARENT != 0 + +def xfs_has_rmapbt(fd): + '''Does this filesystem have reverse mapping?''' + + arg = xfs_fsop_geom() + fcntl.ioctl(fd, XFS_IOC_FSGEOMETRY, arg) + return arg.flags & XFS_FSOP_GEOM_FLAGS_RMAPBT != 0 + # main program def health_reports(mon_fp, fh): @@ -460,9 +513,28 @@ def monitor(mountpoint, event_queue, **kwargs): global log global printf_prefix global want_repair + global has_parent + global has_rmapbt fh = None fd = os.open(mountpoint, os.O_RDONLY) + try: + has_parent = xfs_has_parent(fd) + has_rmapbt = xfs_has_rmapbt(fd) + except Exception as e: + # Don't care if we can't detect parent pointers or rmap + print(f'{printf_prefix}: detecting fs features: {e}', file = sys.stderr) + + # Check for the backref metadata that makes repair effective. + if want_repair: + if not has_rmapbt: + print(f"{mountpoint}: XFS online repair is less effective without rmap btrees.") + if not has_parent: + print(f"{mountpoint}: XFS online repair is less effective without parent pointers.") + + # Flush anything that we may have printed about operational state. + sys.stdout.flush() + try: if want_repair: fh = fshandle(fd, mountpoint) From patchwork Tue Dec 31 23:51:37 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13924084 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 05C7229415 for ; Tue, 31 Dec 2024 23:51:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735689098; cv=none; b=NBG3hY5RRmz32Afm/LKTrHv5ax4+dkOqHug3A5O57nPHlMv33Gbg+FoevJ++BfFMeIFrt6pHFGiOB74sCpKFoW7BGMkxFigN177W9D0/XXY4CSiRqI7V7yewV+Do19M3tZ7cT+yHvI6jA2kYE2jbFB+FpheRg51zMRoFbQPBqMM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735689098; c=relaxed/simple; bh=l+oO4mt446s0+HcpIOPO7+yiBqbcvwjSBBpKjTBtokQ=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=pJdpLPz5y1U17F4Xl9UPdM4PIjh8k+jOEPVDpCMgGWHFdoigtj21ogT0v5rhu9uMWp7bIf26M1OjXA4/WaTIk3UMH0FbYfE3xsYWeyh0xM6PDtSFqpjyj6MeQEzoMX4oQtHOmYJJTvJXGChXoJETvPecX33UYcTCN2yrl2ms7lE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ufdLMi4H; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ufdLMi4H" Received: by smtp.kernel.org (Postfix) with ESMTPSA id D2781C4CED2; Tue, 31 Dec 2024 23:51:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1735689097; bh=l+oO4mt446s0+HcpIOPO7+yiBqbcvwjSBBpKjTBtokQ=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=ufdLMi4HhBaO9V3blUOSrcxXXiFG1VUZCeML4RDnm1IbtIDdoABq6U5jqFwzQRCpd 48h+9QUpk5PZ+jZNdBP1mQdKqhf9hsiaTPHItVLhJB/V+CdA8aEeQpGxAVbhnwZfl3 SUZYXZaxzXBVo89AVtmu3thgFyfXmLAdp4J/IAPEoM25UR7cddQXXfr5U2Q6njyO6y SCrXrgV46VXAMVEVGqjupWCVRXn34j0xAAgZEV/fW1RGxDR0pn+rrUxEyZtwkt1QAb Xw5wYx4nZCEzB5sTl5OzW9W2IO8f7ZlgV/5xw1BKNshVw8ssZE7XsZUkLEVpZzRPV1 kwVvnkZov1S6g== Date: Tue, 31 Dec 2024 15:51:37 -0800 Subject: [PATCH 15/21] xfs_scrubbed: use getparents to look up file names From: "Darrick J. Wong" To: aalbersh@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <173568778691.2710211.10922863184869748991.stgit@frogsfrogsfrogs> In-Reply-To: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> References: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong If the kernel tells about something that happened to a file, use the GETPARENTS ioctl to try to look up the path to that file for more ergonomic reporting. Signed-off-by: "Darrick J. Wong" --- scrub/xfs_scrubbed.in | 235 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 230 insertions(+), 5 deletions(-) diff --git a/scrub/xfs_scrubbed.in b/scrub/xfs_scrubbed.in index 25465128864583..a4e073b3098f7a 100644 --- a/scrub/xfs_scrubbed.in +++ b/scrub/xfs_scrubbed.in @@ -18,6 +18,7 @@ import ctypes import gc from concurrent.futures import ProcessPoolExecutor import ctypes.util +import collections try: # Not all systems will have this json schema validation libarary, @@ -171,12 +172,18 @@ class xfs_handle(ctypes.Structure): assert ctypes.sizeof(xfs_handle) == 24 class fshandle(object): - def __init__(self, fd, mountpoint): + def __init__(self, fd, mountpoint = None): global libhandle global printf_prefix self.handle = xfs_handle() + if isinstance(fd, fshandle): + # copy an existing fshandle + self.mountpoint = fd.mountpoint + ctypes.pointer(self.handle)[0] = fd.handle + return + if mountpoint is None: raise Exception('fshandle needs a mountpoint') @@ -233,6 +240,11 @@ class fshandle(object): libhandle.free_handle(buf, buflen) return fd + def subst(self, ino, gen): + '''Substitute the inode and generation components of a handle.''' + self.handle.ha_fid.fid_ino = ino + self.handle.ha_fid.fid_gen = gen + def libhandle_load(): '''Load libhandle and set things up.''' global libhandle @@ -396,6 +408,170 @@ def xfs_has_rmapbt(fd): fcntl.ioctl(fd, XFS_IOC_FSGEOMETRY, arg) return arg.flags & XFS_FSOP_GEOM_FLAGS_RMAPBT != 0 +# getparents ioctl +class xfs_attrlist_cursor(ctypes.Structure): + _fields_ = [ + ("_opaque0", ctypes.c_uint), + ("_opaque1", ctypes.c_uint), + ("_opaque2", ctypes.c_uint), + ("_opaque3", ctypes.c_uint) + ] + +class xfs_getparents_rec(ctypes.Structure): + _fields_ = [ + ("gpr_parent", xfs_handle), + ("gpr_reclen", ctypes.c_uint), + ("_gpr_reserved", ctypes.c_uint), + ] + +xfs_getparents_tuple = collections.namedtuple('xfs_getparents_tuple', \ + ['gpr_parent', 'gpr_reclen', 'gpr_name']) + +class xfs_getparents_rec_array(object): + def __init__(self, nr_bytes): + self.nr_bytes = nr_bytes + self.bytearray = (ctypes.c_byte * int(nr_bytes))() + + def __slice_to_record(self, bufslice): + '''Compute the number of bytes in a getparents record that contain a null-terminated directory entry name.''' + rec = ctypes.cast(bytes(bufslice), \ + ctypes.POINTER(xfs_getparents_rec)) + fixedlen = ctypes.sizeof(xfs_getparents_rec) + namelen = rec.contents.gpr_reclen - fixedlen + + for i in range(0, namelen): + if bufslice[fixedlen + i] == 0: + namelen = i + break + + if namelen == 0: + return + + return xfs_getparents_tuple( + gpr_parent = rec.contents.gpr_parent, + gpr_reclen = rec.contents.gpr_reclen, + gpr_name = bufslice[fixedlen:fixedlen + namelen]) + + def get_buffer(self): + '''Return a pointer to the bytearray masquerading as an int.''' + return ctypes.addressof(self.bytearray) + + def __iter__(self): + '''Walk the getparents records in this array.''' + off = 0 + nr = 0 + buf = bytes(self.bytearray) + while off < self.nr_bytes: + bufslice = buf[off:] + t = self.__slice_to_record(bufslice) + if t is None: + break + yield t + off += t.gpr_reclen + nr += 1 + +class xfs_getparents(ctypes.Structure): + _fields_ = [ + ("_gp_cursor", xfs_attrlist_cursor), + ("gp_iflags", ctypes.c_ushort), + ("gp_oflags", ctypes.c_ushort), + ("gp_bufsize", ctypes.c_uint), + ("_pad", ctypes.c_ulonglong), + ("gp_buffer", ctypes.c_ulonglong) + ] + + def __init__(self, fd, nr_bytes): + self.fd = fd + self.records = xfs_getparents_rec_array(nr_bytes) + self.gp_buffer = self.records.get_buffer() + self.gp_bufsize = nr_bytes + + def __call_kernel(self): + if self.gp_oflags & XFS_GETPARENTS_OFLAG_DONE: + return False + + ret = fcntl.ioctl(self.fd, XFS_IOC_GETPARENTS, self) + if ret != 0: + return False + + return self.gp_oflags & XFS_GETPARENTS_OFLAG_ROOT == 0 + + def __iter__(self): + ctypes.memset(ctypes.pointer(self._gp_cursor), 0, \ + ctypes.sizeof(xfs_attrlist_cursor)) + + while self.__call_kernel(): + for i in self.records: + yield i + +class xfs_getparents_by_handle(ctypes.Structure): + _fields_ = [ + ("gph_handle", xfs_handle), + ("gph_request", xfs_getparents) + ] + + def __init__(self, fd, fh, nr_bytes): + self.fd = fd + self.records = xfs_getparents_rec_array(nr_bytes) + self.gph_request.gp_buffer = self.records.get_buffer() + self.gph_request.gp_bufsize = nr_bytes + self.gph_handle = fh.handle + + def __call_kernel(self): + if self.gph_request.gp_oflags & XFS_GETPARENTS_OFLAG_DONE: + return False + + ret = fcntl.ioctl(self.fd, XFS_IOC_GETPARENTS_BY_HANDLE, self) + if ret != 0: + return False + + return self.gph_request.gp_oflags & XFS_GETPARENTS_OFLAG_ROOT == 0 + + def __iter__(self): + ctypes.memset(ctypes.pointer(self.gph_request._gp_cursor), 0, \ + ctypes.sizeof(xfs_attrlist_cursor)) + while self.__call_kernel(): + for i in self.records: + yield i + +assert ctypes.sizeof(xfs_getparents) == 40 +assert ctypes.sizeof(xfs_getparents_by_handle) == 64 +assert ctypes.sizeof(xfs_getparents_rec) == 32 + +XFS_GETPARENTS_OFLAG_ROOT = 1 << 0 +XFS_GETPARENTS_OFLAG_DONE = 1 << 1 + +XFS_IOC_GETPARENTS = _IOWR(0x58, 62, xfs_getparents) +XFS_IOC_GETPARENTS_BY_HANDLE = _IOWR(0x58, 63, xfs_getparents_by_handle) + +def fgetparents(fd, fh = None, bufsize = 1024): + '''Return all the parent pointers for a given fd and/or handle.''' + + if fh is not None: + return xfs_getparents_by_handle(fd, fh, bufsize) + return xfs_getparents(fd, bufsize) + +def fgetpath(fd, fh = None, mountpoint = None): + '''Return a list of path components up to the root dir of the filesystem for a given fd.''' + ret = [] + if fh is None: + nfh = fshandle(fd, mountpoint) + else: + # Don't subst into the caller's handle + nfh = fshandle(fh) + + while True: + added = False + for pptr in fgetparents(fd, nfh): + ret.insert(0, pptr.gpr_name) + nfh.subst(pptr.gpr_parent.ha_fid.fid_ino, \ + pptr.gpr_parent.ha_fid.fid_gen) + added = True + break + if not added: + break + return ret + # main program def health_reports(mon_fp, fh): @@ -429,11 +605,23 @@ def health_reports(mon_fp, fh): lines = [] buf = mon_fp.readline() +def inode_printf_prefix(event): + '''Compute the logging prefix for this event.''' + global printf_prefix + + if 'path' not in event: + return printf_prefix + + if printf_prefix.endswith(os.sep): + return f"{printf_prefix}{event['path']}" + + return f"{printf_prefix}{os.sep}{event['path']}" + def log_event(event): '''Log a monitoring event to stdout.''' global printf_prefix - print(f"{printf_prefix}: {event}") + print(f"{inode_printf_prefix(event)}: {event}") sys.stdout.flush() def report_lost(event): @@ -480,6 +668,39 @@ def handle_event(e): global log global repair_queue + global has_parent + + def pathify_event(event, fh): + '''Come up with a directory tree path for a file event.''' + try: + path_fd = fh.open() + except Exception as e: + # Not the end of the world if we get nothing + if e.errno != errno.EOPNOTSUPP and e.errno != errno.ENOTTY: + print(f'{printf_prefix}: opening file handle: {e}', file = sys.stderr) + return + + try: + fh2 = fshandle(fh) + except OSError as e: + if e.errno != errno.EOPNOTSUPP: + print(f'{printf_prefix}: making new file handle: {e}', file = sys.stderr) + os.close(path_fd) + return + except Exception as e: + print(f'{printf_prefix}: making new file handle: {e}', file = sys.stderr) + os.close(path_fd) + return + + try: + fh2.subst(event['inumber'], event['generation']) + components = [x.decode('utf-8') for x in fgetpath(path_fd, fh2)] + event['path'] = os.sep.join(components) + except OSError as e: + if e.errno != errno.EOPNOTSUPP: + print(f'{printf_prefix}: constructing path: {e}', file = sys.stderr) + finally: + os.close(path_fd) # Use a separate subprocess to handle the repairs so that the event # processing worker does not block on the GIL of the repair workers. @@ -498,6 +719,8 @@ def handle_event(e): return stringify_timestamp(event) + if event['domain'] == 'inode' and has_parent and not debug_fast: + pathify_event(event, fh) if log: log_event(event) if event['type'] == 'lost': @@ -536,7 +759,7 @@ def monitor(mountpoint, event_queue, **kwargs): sys.stdout.flush() try: - if want_repair: + if want_repair or has_parent: fh = fshandle(fd, mountpoint) mon_fd = open_health_monitor(fd, verbose = everything) except OSError as e: @@ -653,6 +876,8 @@ def repair_group(event, fd, group_type): def repair_inode(event, fd): '''React to a inode-domain corruption event by repairing it.''' + ipp = inode_printf_prefix(event) + for s in event['structures']: type = __scrub_type(s) if type is None: @@ -660,10 +885,10 @@ def repair_inode(event, fd): try: oflags = xfs_repair_inode_metadata(fd, type, event['inumber'], event['generation']) - print(f"{printf_prefix}: {s}: {report_outcome(oflags)}") + print(f"{ipp}: {s}: {report_outcome(oflags)}") sys.stdout.flush() except Exception as e: - print(f"{printf_prefix}: {s}: {e}", file = sys.stderr) + print(f"{ipp}: {s}: {e}", file = sys.stderr) def repair_metadata(event, fh): '''Repair a metadata corruption.''' From patchwork Tue Dec 31 23:51:53 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13924085 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F0B3429415 for ; Tue, 31 Dec 2024 23:51:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735689114; cv=none; b=sIp54dSCspcst4yKuDqNhb8a8Iu4jQkEl1bG6wjeLEzu47CiZkjT9/TpzgUVBLx1bcD3/Gi3XFqRYjugqJvvpmLbgv3wHPAqaLrWQyxsn+O7brrD2Nf1+iSX48hiM1IyGniMbwWcJFDKBeKS4L++pIq6yuW90TJy6wNXmfYkQRI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735689114; c=relaxed/simple; bh=9h82dR31wj2nQaoNFx94JXMkxyiQb3zqy62GtHQyqQg=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=HgBxOnA8zB86eZjmaLak/HCckV3ync//k0P5x3ZAZX3zqRvaQMt/z6Idnij4M317qzftoDdsAvkGQPJam0EgJSXgTH1/aDt9QL34Q+8HrDOqqOsAC5nINoBTW3D6hHNMhxDSWiuWOJiM5CdVk+QPJT5kWWW7/Wyek5buOeG0UAc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=V7gSd3kA; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="V7gSd3kA" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 802ADC4CED2; Tue, 31 Dec 2024 23:51:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1735689113; bh=9h82dR31wj2nQaoNFx94JXMkxyiQb3zqy62GtHQyqQg=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=V7gSd3kAYGy9Rp0O2ywF5Q7wtqv3+mOt0GdVsIPeJpM3Ie+dGk0gylGPus0gpIzwo JTSG/ZbuxJhiQTY8fW2cWIC7xXY/vHyk5KVLwDd0WbW5U7ZJhhLIV01E2fOoZ/wVLz GpzEyrqUWOlVmAWZl3syGwOtZ8NxIBo6CWL/yhsJ5J3fYpKm2Z95oUx0s4FbUmB3un nKd+1nxkKfRNGEsAKws7aNgrsVLRyVOa5zj5Ml3EBnjeBn/vTD27/nkOMS1dNLX7CD 8gg7fVfocAD/yRfshNRECuqAaEvd1TnXQ1NRPa+cbHiRmtHeNOaY4sQglPjiTL0v05 8ysTq6zH+Fn8Q== Date: Tue, 31 Dec 2024 15:51:53 -0800 Subject: [PATCH 16/21] builddefs: refactor udev directory specification From: "Darrick J. Wong" To: aalbersh@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <173568778707.2710211.17677068348003849396.stgit@frogsfrogsfrogs> In-Reply-To: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> References: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Refactor the code that finds the udev rules directory to detect the location of the parent udev directory instead. IOWs, we go from: UDEV_RULE_DIR=/foo/bar/rules.d to: UDEV_DIR=/foo/bar UDEV_RULE_DIR=/foo/bar/rules.d This is needed by the next patch, which adds a helper script. Signed-off-by: "Darrick J. Wong" --- configure.ac | 2 +- include/builddefs.in | 3 ++- m4/package_services.m4 | 30 +++++++++++++++--------------- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/configure.ac b/configure.ac index 1f7fec838e1239..cabbef51068dbc 100644 --- a/configure.ac +++ b/configure.ac @@ -175,7 +175,7 @@ if test "$enable_scrub" = "yes"; then fi AC_CONFIG_SYSTEMD_SYSTEM_UNIT_DIR AC_CONFIG_CROND_DIR -AC_CONFIG_UDEV_RULE_DIR +AC_CONFIG_UDEV_DIR AC_HAVE_BLKID_TOPO if test "$enable_ubsan" = "yes" || test "$enable_ubsan" = "probe"; then diff --git a/include/builddefs.in b/include/builddefs.in index bb022c36627a72..4a25de76d5c325 100644 --- a/include/builddefs.in +++ b/include/builddefs.in @@ -112,7 +112,8 @@ SYSTEMD_SYSTEM_UNIT_DIR = @systemd_system_unit_dir@ HAVE_CROND = @have_crond@ CROND_DIR = @crond_dir@ HAVE_UDEV = @have_udev@ -UDEV_RULE_DIR = @udev_rule_dir@ +UDEV_DIR = @udev_dir@ +UDEV_RULE_DIR = @udev_dir@/rules.d HAVE_LIBURCU_ATOMIC64 = @have_liburcu_atomic64@ USE_RADIX_TREE_FOR_INUMS = @use_radix_tree_for_inums@ diff --git a/m4/package_services.m4 b/m4/package_services.m4 index a683ddb93e0e91..de0504df0c206f 100644 --- a/m4/package_services.m4 +++ b/m4/package_services.m4 @@ -77,33 +77,33 @@ AC_DEFUN([AC_CONFIG_CROND_DIR], ]) # -# Figure out where to put udev rule files +# Figure out where to put udev files # -AC_DEFUN([AC_CONFIG_UDEV_RULE_DIR], +AC_DEFUN([AC_CONFIG_UDEV_DIR], [ AC_REQUIRE([PKG_PROG_PKG_CONFIG]) - AC_ARG_WITH([udev_rule_dir], - [AS_HELP_STRING([--with-udev-rule-dir@<:@=DIR@:>@], - [Install udev rules into DIR.])], + AC_ARG_WITH([udev_dir], + [AS_HELP_STRING([--with-udev-dir@<:@=DIR@:>@], + [Install udev files underneath DIR.])], [], - [with_udev_rule_dir=yes]) - AS_IF([test "x${with_udev_rule_dir}" != "xno"], + [with_udev_dir=yes]) + AS_IF([test "x${with_udev_dir}" != "xno"], [ - AS_IF([test "x${with_udev_rule_dir}" = "xyes"], + AS_IF([test "x${with_udev_dir}" = "xyes"], [ PKG_CHECK_MODULES([udev], [udev], [ - with_udev_rule_dir="$($PKG_CONFIG --variable=udev_dir udev)/rules.d" + with_udev_dir="$($PKG_CONFIG --variable=udev_dir udev)" ], [ - with_udev_rule_dir="" + with_udev_dir="" ]) m4_pattern_allow([^PKG_(MAJOR|MINOR|BUILD|REVISION)$]) ]) - AC_MSG_CHECKING([for udev rule dir]) - udev_rule_dir="${with_udev_rule_dir}" - AS_IF([test -n "${udev_rule_dir}"], + AC_MSG_CHECKING([for udev dir]) + udev_dir="${with_udev_dir}" + AS_IF([test -n "${udev_dir}"], [ - AC_MSG_RESULT(${udev_rule_dir}) + AC_MSG_RESULT(${udev_dir}) have_udev="yes" ], [ @@ -115,5 +115,5 @@ AC_DEFUN([AC_CONFIG_UDEV_RULE_DIR], have_udev="disabled" ]) AC_SUBST(have_udev) - AC_SUBST(udev_rule_dir) + AC_SUBST(udev_dir) ]) From patchwork Tue Dec 31 23:52:08 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13924086 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8838729415 for ; Tue, 31 Dec 2024 23:52:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735689129; cv=none; b=VfnYXEhC4TD3aznRdeC3dzMgD7wMoI9v5W6lG72jhM9AXzZuadyQ1wKhW8M+2nPpkawSYxrc6PffXTNZ0dnFe71VyuO94wrY8LenhuuCQPGd3BI0yyQrQd9rD9OLjVUcBQ6V5xrWFqDnHAOSTZz5BYMISos4XScYSDmoZM8S7HI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735689129; c=relaxed/simple; bh=08Ckdi8mNaeblSNZJERNI12xCexDUc7fJvBQ+qBIXuo=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=ShEqLxaKesZbQJNTOm0SqOqzZyuIZ3OdA7AGsbBvZzM5PUueav9g4gQ14ZWNV5m5Skqwckm1n7SWKyJfxS+0/qeV62HhyKtgmWvHW0A6HvQ0nbbV1aIgborHSeVwtnaafMTiq1rHALpzd7z8yl4CO4K/mXBiS5j4hAMnkA4yC/E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=booNxzHa; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="booNxzHa" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 20467C4CED2; Tue, 31 Dec 2024 23:52:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1735689129; bh=08Ckdi8mNaeblSNZJERNI12xCexDUc7fJvBQ+qBIXuo=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=booNxzHaWbkLPC+Uw9HJkRIT9l1VlQz6h1kXfACZJRJqlwnDcWGGRB2Rro46p/0fx YCnT2upifLXiuPvhJF3/JtcxJnil8XENomaNPLAP7WlVYGEeotb/2+kwV5OxFCB+nN +goshFM3Yu4PwDPX18P5vQlE8S13u+1Y16azZrS45poJsyklmBXkyrD1MXUdKd8WpP Hsn83I/iIySStJK9SlrKcYkuh/MwPRDMicoqTEJNLxLl1cyTlTNpcqnVUpqCr/kUEv 1zEKLg9mGXMQ93JRHw734oA+IDYDFxAb6N6DIfAP+lGMhXz+vcQxeMd7zE8GU1kH7N Y1Pvn3EMhgmSw== Date: Tue, 31 Dec 2024 15:52:08 -0800 Subject: [PATCH 17/21] xfs_scrubbed: create a background monitoring service From: "Darrick J. Wong" To: aalbersh@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <173568778722.2710211.17201402564311213099.stgit@frogsfrogsfrogs> In-Reply-To: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> References: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Create a systemd service and activate it automatically. Signed-off-by: "Darrick J. Wong" --- scrub/Makefile | 18 +++++++ scrub/xfs_scrubbed.in | 9 +++ scrub/xfs_scrubbed.rules | 7 +++ scrub/xfs_scrubbed@.service.in | 103 ++++++++++++++++++++++++++++++++++++++++ scrub/xfs_scrubbed_start | 17 +++++++ 5 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 scrub/xfs_scrubbed.rules create mode 100644 scrub/xfs_scrubbed@.service.in create mode 100755 scrub/xfs_scrubbed_start diff --git a/scrub/Makefile b/scrub/Makefile index 7d4fa0ddc09685..731810d7c7fd9a 100644 --- a/scrub/Makefile +++ b/scrub/Makefile @@ -29,8 +29,16 @@ SYSTEMD_SERVICES=\ xfs_scrub_all.service \ xfs_scrub_all_fail.service \ xfs_scrub_all.timer \ - system-xfs_scrub.slice + system-xfs_scrub.slice \ + xfs_scrubbed@.service OPTIONAL_TARGETS += $(SYSTEMD_SERVICES) + +ifeq ($(HAVE_UDEV),yes) + XFS_SCRUBBED_UDEV_RULES = xfs_scrubbed.rules + XFS_SCRUBBED_HELPER = xfs_scrubbed_start + INSTALL_SCRUB += install-udev-scrubbed + OPTIONAL_TARGETS += $(XFS_SCRUBBED_HELPER) +endif endif ifeq ($(HAVE_CROND),yes) INSTALL_SCRUB += install-crond @@ -185,6 +193,14 @@ install-udev: $(UDEV_RULES) $(INSTALL) -m 644 $$i $(UDEV_RULE_DIR)/64-$$i; \ done +install-udev-scrubbed: $(XFS_SCRUBBED_HELPER) + $(INSTALL) -m 755 -d $(UDEV_DIR) + $(INSTALL) -m 755 $(XFS_SCRUBBED_HELPER) $(UDEV_DIR) + $(INSTALL) -m 755 -d $(UDEV_RULE_DIR) + for i in $(XFS_SCRUBBED_UDEV_RULES); do \ + $(INSTALL) -m 644 $$i $(UDEV_RULE_DIR)/64-$$i; \ + done + install-dev: -include .dep diff --git a/scrub/xfs_scrubbed.in b/scrub/xfs_scrubbed.in index a4e073b3098f7a..9df6f45e53ad80 100644 --- a/scrub/xfs_scrubbed.in +++ b/scrub/xfs_scrubbed.in @@ -19,6 +19,7 @@ import gc from concurrent.futures import ProcessPoolExecutor import ctypes.util import collections +import time try: # Not all systems will have this json schema validation libarary, @@ -994,6 +995,14 @@ def main(): pass args.event_queue.shutdown() + + # See the service mode comments in xfs_scrub.c for why we sleep and + # compress all nonzero exit codes to 1. + if 'SERVICE_MODE' in os.environ: + time.sleep(2) + if ret != 0: + ret = 1 + return ret if __name__ == '__main__': diff --git a/scrub/xfs_scrubbed.rules b/scrub/xfs_scrubbed.rules new file mode 100644 index 00000000000000..c651126d5373a1 --- /dev/null +++ b/scrub/xfs_scrubbed.rules @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright (c) 2024-2025 Oracle. All rights reserved. +# Author: Darrick J. Wong +# +# Start autonomous self healing automatically +ACTION=="add", SUBSYSTEM=="xfs", ENV{TYPE}=="mount", RUN+="xfs_scrubbed_start" diff --git a/scrub/xfs_scrubbed@.service.in b/scrub/xfs_scrubbed@.service.in new file mode 100644 index 00000000000000..9656bdb3cd9a9d --- /dev/null +++ b/scrub/xfs_scrubbed@.service.in @@ -0,0 +1,103 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright (c) 2024-2025 Oracle. All Rights Reserved. +# Author: Darrick J. Wong + +[Unit] +Description=Self Healing of XFS Metadata for %f +Documentation=man:xfs_scrubbed(8) + +# Explicitly require the capabilities that this program needs +ConditionCapability=CAP_SYS_ADMIN +ConditionCapability=CAP_DAC_OVERRIDE + +# Must be a mountpoint +ConditionPathIsMountPoint=%f +RequiresMountsFor=%f + +[Service] +Type=exec +Environment=SERVICE_MODE=1 +ExecStart=@pkg_libexec_dir@/xfs_scrubbed --log %f +SyslogIdentifier=%N + +# Run scrub with minimal CPU and IO priority so that nothing else will starve. +IOSchedulingClass=idle +CPUSchedulingPolicy=idle +CPUAccounting=true +Nice=19 + +# Create the service underneath the scrub background service slice so that we +# can control resource usage. +Slice=system-xfs_scrub.slice + +# No realtime CPU scheduling +RestrictRealtime=true + +# Dynamically create a user that isn't root +DynamicUser=true + +# Make the entire filesystem readonly, but don't hide /home and don't use a +# private bind mount like xfs_scrub. We don't want to pin the filesystem, +# because we want umount to work correctly and this service to stop +# automatically. +ProtectSystem=strict +ProtectHome=no +PrivateTmp=true +PrivateDevices=true + +# Don't let scrub complain about paths in /etc/projects that have been hidden +# by our sandboxing. scrub doesn't care about project ids anyway. +InaccessiblePaths=-/etc/projects + +# No network access +PrivateNetwork=true +ProtectHostname=true +RestrictAddressFamilies=none +IPAddressDeny=any + +# Don't let the program mess with the kernel configuration at all +ProtectKernelLogs=true +ProtectKernelModules=true +ProtectKernelTunables=true +ProtectControlGroups=true +ProtectProc=invisible +RestrictNamespaces=true + +# Hide everything in /proc, even /proc/mounts +ProcSubset=pid + +# Only allow the default personality Linux +LockPersonality=true + +# No writable memory pages +MemoryDenyWriteExecute=true + +# Don't let our mounts leak out to the host +PrivateMounts=true + +# Restrict system calls to the native arch and only enough to get things going +SystemCallArchitectures=native +SystemCallFilter=@system-service +SystemCallFilter=~@privileged +SystemCallFilter=~@resources +SystemCallFilter=~@mount + +# xfs_scrubbed needs these privileges to open the rootdir and monitor +CapabilityBoundingSet=CAP_SYS_ADMIN CAP_DAC_OVERRIDE +AmbientCapabilities=CAP_SYS_ADMIN CAP_DAC_OVERRIDE +NoNewPrivileges=true + +# xfs_scrubbed doesn't create files +UMask=7777 + +# No access to hardware /dev files except for block devices +ProtectClock=true +DevicePolicy=closed + +[Install] +WantedBy=multi-user.target +# If someone tries to enable the template itself, translate that into enabling +# this service on the root directory at systemd startup time. In the +# initramfs, the udev rules in xfs_scrubbed.rules run before systemd starts. +DefaultInstance=- diff --git a/scrub/xfs_scrubbed_start b/scrub/xfs_scrubbed_start new file mode 100755 index 00000000000000..82530cf7862717 --- /dev/null +++ b/scrub/xfs_scrubbed_start @@ -0,0 +1,17 @@ +#!/bin/sh + +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright (c) 2024-2025 Oracle. All Rights Reserved. +# Author: Darrick J. Wong + +# Start the xfs_scrubbed service when the filesystem is mounted + +command -v systemctl || exit 0 + +grep "^$SOURCE[[:space:]]" /proc/mounts | while read source mntpt therest; do + inst="$(systemd-escape --path "$mntpt")" + systemctl restart --no-block "xfs_scrubbed@$inst" && break +done + +exit 0 From patchwork Tue Dec 31 23:52:24 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13924087 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 342FA1B0425 for ; Tue, 31 Dec 2024 23:52:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735689145; cv=none; b=L878IeKhi98AEc1HROU3DEt9Y/S951bQHXELSAGrVOUzp+lYxIKq5p7PFxjbRmEsjbjWQdWQBjVhnXz1LHmdbYrCfl4vL4Z3ntntkz5Arhum0vZFU3Hoankolqgp/b1VBw2VzOeXSmvIXHsFxWS0g3DQ13yIoFr7kcnSVIziM1Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735689145; c=relaxed/simple; bh=5JQxrrLr4fiunRkMVSBLEDMh8T+vnd5a0qOAFJMhvtY=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Sxnx8scRcjvrP45giF9alHaEcjEkWk0KLCrCL4NShuQwp81wTU/du2C+NwAS52Fvs1AOAltsgH4Q3aNA0LAHOg1WFRiUOAWLlRWgkrHOGXtS5qnt8TZnLKnUkXSQbVhr1uZSGb2JCkp1Mje7m9AdgnJxABjiZnui3XYX9nCf7uo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=WnAe2Lhp; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="WnAe2Lhp" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B4597C4CED2; Tue, 31 Dec 2024 23:52:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1735689144; bh=5JQxrrLr4fiunRkMVSBLEDMh8T+vnd5a0qOAFJMhvtY=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=WnAe2Lhpvl8rL8iF209TQ/dJ8/6tiT+CbmNwGj/lX36P8AweTlb7fqKSLb/sHT8r4 wl+NREfrUBDZC8tQIxhgy00jlbQHiL8r3shQWB4qTemjztl8fbJmK1avghRk937u9t pd5UGlADVxrTNb6LaJrE0wrfD1u5cT2H9XzzK74Qj1wgNDEy2rj0I+40ctI4ejImkR /Y9Ia2r68CM2/3yxWhywoZ6OkKcOFrrovhNswOrXZ5MZGZL5DfJgaU8Lz6DENHKZDg hVBNRnjPYLy5MIiTE75662Nb/UdLSBfCDKcwJrhsgUa1pHfXbqmVujd0Fjw/QViL7x dPpewE5E2KDBQ== Date: Tue, 31 Dec 2024 15:52:24 -0800 Subject: [PATCH 18/21] xfs_scrubbed: don't start service if kernel support unavailable From: "Darrick J. Wong" To: aalbersh@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <173568778738.2710211.17502333103439617688.stgit@frogsfrogsfrogs> In-Reply-To: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> References: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Use ExecCondition= in the system service to check if kernel support for the health monitor is available. If not, we don't want to run the service, have it fail, and generate a bunch of silly log messages. Signed-off-by: "Darrick J. Wong" --- scrub/xfs_scrubbed.in | 39 ++++++++++++++++++++++++++++++++++++++- scrub/xfs_scrubbed@.service.in | 1 + 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/scrub/xfs_scrubbed.in b/scrub/xfs_scrubbed.in index 9df6f45e53ad80..90602481f64c88 100644 --- a/scrub/xfs_scrubbed.in +++ b/scrub/xfs_scrubbed.in @@ -791,6 +791,38 @@ def monitor(mountpoint, event_queue, **kwargs): return 0 +def check_monitor(mountpoint): + '''Check if the kernel can send us health events for the given mountpoint.''' + global log + global printf_prefix + global everything + global want_repair + global has_parent + + try: + fd = os.open(mountpoint, os.O_RDONLY) + except OSError as e: + # Can't open mountpoint; monitor not available. + print(f"{mountpoint}: {e}", file = sys.stderr) + return 1 + + try: + mon_fd = open_health_monitor(fd, verbose = everything) + except OSError as e: + # Error opening monitor (or it's simply not there); monitor + # not available. + if e.errno == errno.ENOTTY or e.errno == errno.EOPNOTSUPP: + print(f"{mountpoint}: XFS health monitoring not supported.", + file = sys.stderr) + return 1 + finally: + # Close the mountpoint if opening the health monitor fails; + # the handle object will free its own memory. + os.close(fd) + + # Monitor available; success! + return 0 + def __scrub_type(code): '''Convert a "structures" json list to a scrub type code.''' SCRUB_TYPES = { @@ -923,6 +955,8 @@ def main(): parser = argparse.ArgumentParser( \ description = "XFS filesystem health monitoring demon.") + parser.add_argument("--check", help = "Check presense of health monitor.", \ + action = "store_true") parser.add_argument("--debug", help = "Enabling debugging messages.", \ action = "store_true") parser.add_argument("--log", help = "Log health events to stdout.", \ @@ -989,7 +1023,10 @@ def main(): printf_prefix = args.mountpoint ret = 0 try: - ret = monitor(**vars(args)) + if args.check: + ret = check_monitor(args.mountpoint) + else: + ret = monitor(**vars(args)) except KeyboardInterrupt: # Consider SIGINT to be a clean exit. pass diff --git a/scrub/xfs_scrubbed@.service.in b/scrub/xfs_scrubbed@.service.in index 9656bdb3cd9a9d..afd5c204327946 100644 --- a/scrub/xfs_scrubbed@.service.in +++ b/scrub/xfs_scrubbed@.service.in @@ -18,6 +18,7 @@ RequiresMountsFor=%f [Service] Type=exec Environment=SERVICE_MODE=1 +ExecCondition=@pkg_libexec_dir@/xfs_scrubbed --check %f ExecStart=@pkg_libexec_dir@/xfs_scrubbed --log %f SyslogIdentifier=%N From patchwork Tue Dec 31 23:52:39 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13924088 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7622F29415 for ; Tue, 31 Dec 2024 23:52:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735689160; cv=none; b=TwcOmAGuFM2kqT5gxktJQj5JWRHbu/13uUO/LnXyx78InSuUOpOFPUMpfcnzrEM8j0cStAafqImbM37NeK/9CghBc7DPQv1zgCML3tzK3zzQXikd8Z9tumewLvTG881ufGXmDHIpZetbxZ27rkoOIe05IfdKRyMv2C5fDf1T7VA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735689160; c=relaxed/simple; bh=s9bc2zPQx9Gk8KOTK/NDAHWKvm/aECuECysXqFiupUI=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=NAu6OtkR0wKeXrOHUfqKUJt7P1Ud0yAl0iy/oJu6aGeC5jPTs/ighSEiXr1+gp39D15ANx93GCNPPAnRQvuMyIxrW4MKRxUpW2KpGeH0iGiZjel4d2PfM/snmwRocfmxxFCKHk2nC28AjCVZw7XpNOhWL2jCTRR62xsqhRalCbY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=QMpfUWSK; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="QMpfUWSK" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4EF8DC4CED2; Tue, 31 Dec 2024 23:52:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1735689160; bh=s9bc2zPQx9Gk8KOTK/NDAHWKvm/aECuECysXqFiupUI=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=QMpfUWSKTcKt79BqtMemDFbzVHoNCp2J4nbv/17O0xum9u9xeOMdxXxnbyNDeqhEq Xw/McDHsAFTquXFrwxlZzXUxnDPftQkd+yq9ScuJUJA6JwYsS1+k8tZDifa4CS+e06 /uF60bTtcP3Lj0NQGsbcWSP5oTRr8oOWouF+Ubl4VKOilCCdtrIu/csYQe4FyvjOq8 P4aY/tFIi6566EOt2MN/qlzhNup+Tg5QreQ5p2ld0h2zGq+emyKRLA1jr7iojEWpEt JprOeL8dJMMLjSlmrgyyPTHnhydaq7xFK1RYe0upGonq58eAGC+oXrhnj4lsoxkIYv EKyUdDNfK/s8A== Date: Tue, 31 Dec 2024 15:52:39 -0800 Subject: [PATCH 19/21] xfs_scrubbed: use the autofsck fsproperty to select mode From: "Darrick J. Wong" To: aalbersh@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <173568778754.2710211.11864841620520710404.stgit@frogsfrogsfrogs> In-Reply-To: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> References: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Make the xfs_scrubbed background service query the autofsck filesystem property to figure out which operating mode it should use. Signed-off-by: "Darrick J. Wong" --- scrub/xfs_scrubbed.in | 62 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/scrub/xfs_scrubbed.in b/scrub/xfs_scrubbed.in index 90602481f64c88..2b34603cb361e2 100644 --- a/scrub/xfs_scrubbed.in +++ b/scrub/xfs_scrubbed.in @@ -573,6 +573,21 @@ def fgetpath(fd, fh = None, mountpoint = None): break return ret +# Filesystem properties + +FSPROP_NAMESPACE = "trusted." +FSPROP_NAME_PREFIX = "xfs:" +FSPROP_AUTOFSCK_NAME = "autofsck" + +def fsprop_attrname(n): + '''Construct the xattr name for a filesystem property.''' + return f"{FSPROP_NAMESPACE}{FSPROP_NAME_PREFIX}{n}" + +def fsprop_getstr(fd, n): + '''Return the value of a filesystem property as a string.''' + attrname = fsprop_attrname(n) + return os.getxattr(fd, attrname).decode('utf-8') + # main program def health_reports(mon_fp, fh): @@ -731,6 +746,31 @@ def handle_event(e): elif want_repair and event['type'] == 'sick': repair_queue.submit(repair_metadata, event, fh) +def want_repair_from_autofsck(fd): + '''Determine want_repair from the autofsck filesystem property.''' + global has_parent + global has_rmapbt + + try: + advice = fsprop_getstr(fd, FSPROP_AUTOFSCK_NAME) + if advice == "repair": + return True + if advice == "check" or advice == "optimize": + return False + if advice == "none": + return None + except: + # Any OS error (including ENODATA) or string parsing error is + # treated the same as an unrecognized value. + pass + + # For an unrecognized value, log but do not fix runtime corruption if + # backref metadata are enabled. If no backref metadata are available, + # the fs is too old so don't run at all. + if has_rmapbt or has_parent: + return False + return None + def monitor(mountpoint, event_queue, **kwargs): '''Monitor the given mountpoint for health events.''' global everything @@ -749,6 +789,20 @@ def monitor(mountpoint, event_queue, **kwargs): # Don't care if we can't detect parent pointers or rmap print(f'{printf_prefix}: detecting fs features: {e}', file = sys.stderr) + # Does the sysadmin have any advice for us about whether or not to + # background scrub? + if want_repair is None: + want_repair = want_repair_from_autofsck(fd) + if want_repair is None: + print(f"{mountpoint}: Disabling daemon per autofsck directive.") + os.close(fd) + return 0 + elif want_repair: + print(f"{mountpoint}: Automatically repairing per autofsck directive.") + else: + print(f"{mountpoint}: Only logging errors per autofsck directive.") + + # Check for the backref metadata that makes repair effective. if want_repair: if not has_rmapbt: @@ -963,7 +1017,11 @@ def main(): action = "store_true") parser.add_argument("--everything", help = "Capture all events.", \ action = "store_true") - parser.add_argument("--repair", help = "Automatically repair corrupt metadata.", \ + action_group = parser.add_mutually_exclusive_group() + action_group.add_argument("--repair", \ + help = "Automatically repair corrupt metadata.", \ + action = "store_true") + action_group.add_argument("--autofsck", help = argparse.SUPPRESS, \ action = "store_true") parser.add_argument("-V", help = "Report version and exit.", \ action = "store_true") @@ -1004,6 +1062,8 @@ def main(): everything = True if args.debug_fast: debug_fast = True + if args.autofsck: + want_repair = None if args.repair: want_repair = True From patchwork Tue Dec 31 23:52:55 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13924089 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 13E7D29415 for ; Tue, 31 Dec 2024 23:52:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735689176; cv=none; b=EhEOLzGtKQwYGsmNwNNJ4tl8DX5G9Q1yRVrBz7OV+zOGe0O6LGQ4AEOfoYoMyQUJb//1P4ej/Z8GWR5L33q77pbeuN9OyzHVCYFdKdg4gTSPCi3UFuQhVMIupJfan9YfEnt1FVmiaqEilU9+Xrsr0uT3CWDB53gukTowXvlBbaQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735689176; c=relaxed/simple; bh=VV+8OewEmIhVwlRjhYNNyFs9CpVvYvYUUNbCIcwhtAM=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=JqOFdfztifL+0IiVyHw0oBZ27LAVqW3NxQFwBtxxuem89JIT0Q2C8DLqvIH69XIF3WoEtWwhn0bob75B0VX2rpGtDvPfgiVY/APJf1oIJTqek6EK7wlP7myXk2yTYwJuzvaEsg5uDtkBQDRx6fZnmKkKzTHqZwuTLPKcK+s27bE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=cKvAACUO; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="cKvAACUO" Received: by smtp.kernel.org (Postfix) with ESMTPSA id DEEF0C4CED2; Tue, 31 Dec 2024 23:52:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1735689175; bh=VV+8OewEmIhVwlRjhYNNyFs9CpVvYvYUUNbCIcwhtAM=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=cKvAACUOPC3SCtV1tlN7F1F3QOWQdbiB3MiU5pQQTJYV0Yc+0pqkdqJploHK9h0F8 z5yL/YQf04GkcD2cZKFgiUOIZa1YzB9BjFr4MacbzZMWykMEma5dK7SuXK0FGl8B57 LtS8iqBfd6A2e1flZlUGhfmWrxQwElYdDHQYV605gGbYiv//U/ReBAOIeo5cZ8M1wi OZYYFg1BdbuiOe/MmQbMjZcqwlFm5Tew52XKfpsgKBbZ80pZ+7lx9rpc3aNAbTHEqb Ns0GP1g4w3yIJId0vQoDFGq1ES9Vdsm4qRjb/CRa7bdSxD4Y7ewidbsVV2wPB9s1NZ N0ns619w8tTgg== Date: Tue, 31 Dec 2024 15:52:55 -0800 Subject: [PATCH 20/21] xfs_scrub: report media scrub failures to the kernel From: "Darrick J. Wong" To: aalbersh@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <173568778769.2710211.7691395007928091819.stgit@frogsfrogsfrogs> In-Reply-To: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> References: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong If the media scan finds that media have been lost, report this to the kernel so that the healthmon code can pass that along to xfs_scrubbed. Signed-off-by: "Darrick J. Wong" --- scrub/phase6.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/scrub/phase6.c b/scrub/phase6.c index 5a1f29738680e5..b5f6f3c1d4bc63 100644 --- a/scrub/phase6.c +++ b/scrub/phase6.c @@ -671,6 +671,29 @@ clean_pool( return ret; } +static void +report_ioerr_to_kernel( + struct scrub_ctx *ctx, + struct disk *disk, + uint64_t start, + uint64_t length) +{ + struct xfs_media_error me = { + .daddr = start, + .bbcount = length, + }; + dev_t dev = disk_to_dev(ctx, disk); + + if (dev == ctx->fsinfo.fs_datadev) + me.flags |= XFS_MEDIA_ERROR_DATADEV; + else if (dev == ctx->fsinfo.fs_rtdev) + me.flags |= XFS_MEDIA_ERROR_RTDEV; + else if (dev == ctx->fsinfo.fs_logdev) + me.flags |= XFS_MEDIA_ERROR_LOGDEV; + + ioctl(ctx->mnt.fd, XFS_IOC_MEDIA_ERROR, &me); +} + /* Remember a media error for later. */ static void remember_ioerr( @@ -695,6 +718,8 @@ remember_ioerr( return; } + report_ioerr_to_kernel(ctx, disk, start, length); + tree = bitmap_for_disk(ctx, disk, vs); if (!tree) { str_liberror(ctx, ENOENT, _("finding bad block bitmap")); From patchwork Tue Dec 31 23:53:11 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13924090 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A5F8E1B0425 for ; Tue, 31 Dec 2024 23:53:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735689191; cv=none; b=S3OBadJD/7TTB8dJnCPvUDMAeN5tYz6SINjBmHwExYFxcNsymaClahjLohbGEZ545iOwMT/caj2P+OZDvKSG+TfJUHWr940R2YoVdU/BLe6/IZaJsyFN1cRPet7p3LN/+wXVUS8a070nADKAxUa+iunPy73aUCfRnoltI+ZkCA4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735689191; c=relaxed/simple; bh=Unuf4bLFsU7llW5bSf5CAC0dxUN102zmN9OReMlZChE=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=T7gMP4hdmvJwdNfDMBMjPZIg+jfexhpDlMmeQYtj8TaoMM+0IWXEQ4WY0SwYKv1C1fuJnNExFxvY/Nh1k/P68TESp4VnLzRjtCLlOiO5DL1MQqRue+VN5yo+pixWx1G1Bvca5Y727H7n96gvMOXp+3UeVnwybWDF0S+Pwq3YCU8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=N5xSmmp1; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="N5xSmmp1" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7D240C4CED2; Tue, 31 Dec 2024 23:53:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1735689191; bh=Unuf4bLFsU7llW5bSf5CAC0dxUN102zmN9OReMlZChE=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=N5xSmmp1VXcHV+DMt9O5K0zMkk/yCEQL7L/tb0O3muAb95pHwwj8lMH4X7xPFCTED fqEmY850DlAUEpedKzBZHgaVRWuAXHTfpnd82EYqGhrIlNJT4GIJ3z8fzHv/79KXfy wuwk+gdnZ1Ua9Vrl6aSKbFOHWc6eGOP9u1E8InxrSK2MxYG7/hy2zPHL6QYBjyHONX HQ/YGOGOoX2FVc2YEFrI8iymqcELdtdlH6701QyDXpbKQgmbFKpCSVwUYV3XWoBDVF YFY03+Jn7LAvB1ZXLekWoxP4v8pcXEtkroGwyP3U/lza+6PfHCq/Cc8XZDKxXe+ViY dn6u/zdd8lSZg== Date: Tue, 31 Dec 2024 15:53:11 -0800 Subject: [PATCH 21/21] debian: enable xfs_scrubbed on the root filesystem by default From: "Darrick J. Wong" To: aalbersh@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <173568778785.2710211.3816113785296897483.stgit@frogsfrogsfrogs> In-Reply-To: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> References: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Now that we're finished building autonomous repair, enable the service on the root filesystem by default. The root filesystem is mounted by the initrd prior to starting systemd, which is why the udev rule cannot autostart the service for the root filesystem. dh_installsystemd won't activate a template service (aka one with an at-sign in the name) even if it provides a DefaultInstance directive to make that possible. Use a fugly shim for this. Signed-off-by: "Darrick J. Wong" --- debian/control | 2 +- debian/postinst | 8 ++++++++ debian/prerm | 13 +++++++++++++ scrub/xfs_scrubbed@.service.in | 2 +- 4 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 debian/prerm diff --git a/debian/control b/debian/control index 66b0a47a36ee24..31ea1e988f66be 100644 --- a/debian/control +++ b/debian/control @@ -10,7 +10,7 @@ Homepage: https://xfs.wiki.kernel.org/ Package: xfsprogs Depends: ${shlibs:Depends}, ${misc:Depends}, python3-dbus, python3:any Provides: fsck-backend -Suggests: xfsdump, acl, attr, quota +Suggests: xfsdump, acl, attr, quota, python3-jsonschema Breaks: xfsdump (<< 3.0.0) Replaces: xfsdump (<< 3.0.0) Architecture: linux-any diff --git a/debian/postinst b/debian/postinst index 2ad9174658ceb4..4ba2e0c43b887e 100644 --- a/debian/postinst +++ b/debian/postinst @@ -24,5 +24,13 @@ case "${1}" in esac #DEBHELPER# +# +# dh_installsystemd doesn't handle template services even if we supply a +# default instance, so we'll install it here. +if [ -z "${DPKG_ROOT:-}" ] && [ -d /run/systemd/system ] ; then + if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ] || [ "$1" = "abort-deconfigure" ] || [ "$1" = "abort-remove" ] ; then + /bin/systemctl enable xfs_scrubbed@.service || true + fi +fi exit 0 diff --git a/debian/prerm b/debian/prerm new file mode 100644 index 00000000000000..48e8e94c4fe9ac --- /dev/null +++ b/debian/prerm @@ -0,0 +1,13 @@ +#!/bin/sh + +set -e + +# dh_installsystemd doesn't handle template services even if we supply a +# default instance, so we'll install it here. +if [ -z "${DPKG_ROOT:-}" ] && [ "$1" = remove ] && [ -d /run/systemd/system ] ; then + /bin/systemctl disable xfs_scrubbed@.service || true +fi + +#DEBHELPER# + +exit 0 diff --git a/scrub/xfs_scrubbed@.service.in b/scrub/xfs_scrubbed@.service.in index afd5c204327946..5bf1e79031af8c 100644 --- a/scrub/xfs_scrubbed@.service.in +++ b/scrub/xfs_scrubbed@.service.in @@ -19,7 +19,7 @@ RequiresMountsFor=%f Type=exec Environment=SERVICE_MODE=1 ExecCondition=@pkg_libexec_dir@/xfs_scrubbed --check %f -ExecStart=@pkg_libexec_dir@/xfs_scrubbed --log %f +ExecStart=@pkg_libexec_dir@/xfs_scrubbed --autofsck --log %f SyslogIdentifier=%N # Run scrub with minimal CPU and IO priority so that nothing else will starve.