aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTobias Geerinckx-Rice <me@tobias.gr>2021-09-22 19:00:42 +0200
committerTobias Geerinckx-Rice <me@tobias.gr>2021-09-23 18:17:17 +0200
commit34c105f929b73560a2476486660c0cbba7a7410a (patch)
treebdb388ad9cc8a4b7361232dd63709c7103e1312e
parent09a8fb1f37dec62070a4baa3682e48a45f49467d (diff)
downloadguix-34c105f929b73560a2476486660c0cbba7a7410a.tar
guix-34c105f929b73560a2476486660c0cbba7a7410a.tar.gz
file-systems: Add support for XFS.
* gnu/build/file-systems.scm (%xfs-endianness): New syntax. (xfs-superblock?, read-xfs-superblock, xfs-superblock-uuid) (xfs-superblock-volume-name, check-xfs-file-system): New procedures. (%partition-label-readers, %partition-uuid-readers, check-file-system): Register them. * doc/guix.texi (Keyboard Layout and Networking and Partitioning): Note XFS support.
-rw-r--r--doc/guix.texi2
-rw-r--r--gnu/build/file-systems.scm72
2 files changed, 71 insertions, 3 deletions
diff --git a/doc/guix.texi b/doc/guix.texi
index dc9b039aab..9bb91b94fd 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -2453,7 +2453,7 @@ bootloaders.
Once you are done partitioning the target hard disk drive, you have to
create a file system on the relevant partition(s)@footnote{Currently
-Guix System only supports ext4, btrfs, JFS, and F2FS file systems. In
+Guix System only supports ext4, btrfs, JFS, F2FS, and XFS file systems. In
particular, code that reads file system UUIDs and labels only works for these
file system types.}. For the ESP, if you have one and assuming it is
@file{/dev/sda1}, run:
diff --git a/gnu/build/file-systems.scm b/gnu/build/file-systems.scm
index e79037c12c..2a4dcd4c82 100644
--- a/gnu/build/file-systems.scm
+++ b/gnu/build/file-systems.scm
@@ -679,6 +679,69 @@ dirty flag to indicate that it's now safe to mount."
(_ 'fatal-error)))
+
+;;;
+;;; XFS file systems.
+;;;
+
+;; <https://git.kernel.org/pub/scm/fs/xfs/xfs-documentation.git/tree/design/XFS_Filesystem_Structure/allocation_groups.asciidoc>
+
+(define-syntax %xfs-endianness
+ ;; Endianness of XFS file systems.
+ (identifier-syntax (endianness big)))
+
+(define (xfs-superblock? sblock)
+ "Return #t when SBLOCK is an XFS superblock."
+ (bytevector=? (sub-bytevector sblock 0 4)
+ (string->utf8 "XFSB")))
+
+(define (read-xfs-superblock device)
+ "Return the raw contents of DEVICE's XFS superblock as a bytevector, or #f
+if DEVICE does not contain an XFS file system."
+ (read-superblock device 0 120 xfs-superblock?))
+
+(define (xfs-superblock-uuid sblock)
+ "Return the UUID of XFS superblock SBLOCK as a 16-byte bytevector."
+ (sub-bytevector sblock 32 16))
+
+(define (xfs-superblock-volume-name sblock)
+ "Return the volume name of XFS superblock SBLOCK as a string of at most 12
+characters, or #f if SBLOCK has no volume name."
+ (null-terminated-latin1->string (sub-bytevector sblock 108 12)))
+
+(define (check-xfs-file-system device force? repair)
+ "Return the health of an unmounted XFS file system on DEVICE. If FORCE? is
+false, return 'PASS unconditionally as XFS claims no need for off-line checks.
+When FORCE? is true, do perform a thorough check. If REPAIR is false, do not
+write to DEVICE. If it's #t, replay the log, check, and fix any errors found.
+Otherwise, only replay the log, and check without attempting further repairs."
+ (define (xfs_repair)
+ (status:exit-val
+ (apply system* `("xfs_repair" "-Pv"
+ ,@(match repair
+ (#t '("-e"))
+ (_ '("-n"))) ; will miss some errors
+ ,device))))
+ (if force?
+ ;; xfs_repair fails with exit status 2 if the log is dirty, which is
+ ;; likely in situations where you're running xfs_repair. Only the kernel
+ ;; can replay the log by {,un}mounting it cleanly.
+ (match (let ((status (xfs_repair)))
+ (if (and repair (eq? 2 status))
+ (let ((target "/replay-XFS-log"))
+ ;; The kernel helpfully prints a ‘Mounting…’ notice for us.
+ (mkdir target)
+ (mount device target "xfs")
+ (umount target)
+ (rmdir target)
+ (xfs_repair))
+ status))
+ (0 'pass)
+ (4 'errors-corrected)
+ (_ 'fatal-error))
+ 'pass))
+
+
;;;
;;; Partition lookup.
;;;
@@ -771,7 +834,9 @@ partition field reader that returned a value."
(partition-field-reader read-jfs-superblock
jfs-superblock-volume-name)
(partition-field-reader read-f2fs-superblock
- f2fs-superblock-volume-name)))
+ f2fs-superblock-volume-name)
+ (partition-field-reader read-xfs-superblock
+ xfs-superblock-volume-name)))
(define %partition-uuid-readers
(list (partition-field-reader read-iso9660-superblock
@@ -793,7 +858,9 @@ partition field reader that returned a value."
(partition-field-reader read-f2fs-superblock
f2fs-superblock-uuid)
(partition-field-reader read-ntfs-superblock
- ntfs-superblock-uuid)))
+ ntfs-superblock-uuid)
+ (partition-field-reader read-xfs-superblock
+ xfs-superblock-uuid)))
(define read-partition-label
(cut read-partition-field <> %partition-label-readers))
@@ -904,6 +971,7 @@ an exception in such cases but perform the nearest sane action."
((string-prefix? "f2fs" type) check-f2fs-file-system)
((string-prefix? "ntfs" type) check-ntfs-file-system)
((string-prefix? "nfs" type) (const 'pass))
+ ((string-prefix? "xfs" type) check-xfs-file-system)
(else #f)))
(if check-procedure