Module Name:    src
Committed By:   chs
Date:           Thu Nov 17 06:40:41 UTC 2022

Modified Files:
        src: UPDATING
        src/distrib/sets/lists/tests: mi
        src/sbin/badsect: badsect.c
        src/sbin/cgdconfig: cgdconfig.c
        src/sbin/clri: clri.c
        src/sbin/dump: ffs_inode.c
        src/sbin/fsck_ffs: extern.h fsck.h fsck_ffs.8 main.c pass1.c pass5.c
            setup.c utilities.c
        src/sbin/fsdb: fsdb.8 fsdb.c fsdbutil.c
        src/sbin/fsirand: fsirand.c
        src/sbin/newfs: extern.h mkfs.c newfs.8 newfs.c
        src/sbin/resize_ffs: resize_ffs.c
        src/sbin/scan_ffs: scan_ffs.c
        src/sbin/tunefs: tunefs.c
        src/sys/arch/hppa/stand/xxboot: readufs_ffs.c
        src/sys/arch/sparc/stand/bootblk: bootblk.fth genfth.cf
        src/sys/arch/x68k/stand/boot_ufs: readufs_ffs.c
        src/sys/lib/libsa: ffsv1.c ffsv2.c lfsv1.c lfsv2.c ufs.c
        src/sys/ufs/ffs: ffs_balloc.c ffs_extattr.c ffs_vfsops.c fs.h
        src/sys/ufs/ufs: ufs_bmap.c ufsmount.h
        src/tests/fs/ffs: t_extattr.c
        src/tests/sbin/fsck_ffs: Makefile
        src/usr.sbin/dumpfs: dumpfs.c
        src/usr.sbin/fstyp: ufs.c
        src/usr.sbin/installboot: ffs.c
        src/usr.sbin/makefs: ffs.c ffs.h makefs.8
        src/usr.sbin/makefs/ffs: ffs_balloc.c mkfs.c
        src/usr.sbin/quot: quot.c
        src/usr.sbin/quotacheck: quotacheck.c
        src/usr.sbin/sysinst: label.c
Added Files:
        src/tests/sbin/fsck_ffs: t_extattr.sh

Log Message:
Restore backward compatibility of UFS2 with previous NetBSD releases by
disabling support in UFS2 for extended attributes (including ACLs).
Add a new variant of UFS2 called "UFS2ea" that does support extended attributes.
Add new fsck_ffs operations "-c ea" and "-c no-ea" to convert file systems
from UFS2 to UFS2ea and vice-versa (both of which delete all existing extended
attributes in the process).


To generate a diff of this commit:
cvs rdiff -u -r1.334 -r1.335 src/UPDATING
cvs rdiff -u -r1.1230 -r1.1231 src/distrib/sets/lists/tests/mi
cvs rdiff -u -r1.34 -r1.35 src/sbin/badsect/badsect.c
cvs rdiff -u -r1.60 -r1.61 src/sbin/cgdconfig/cgdconfig.c
cvs rdiff -u -r1.24 -r1.25 src/sbin/clri/clri.c
cvs rdiff -u -r1.23 -r1.24 src/sbin/dump/ffs_inode.c
cvs rdiff -u -r1.27 -r1.28 src/sbin/fsck_ffs/extern.h
cvs rdiff -u -r1.55 -r1.56 src/sbin/fsck_ffs/fsck.h
cvs rdiff -u -r1.51 -r1.52 src/sbin/fsck_ffs/fsck_ffs.8
cvs rdiff -u -r1.89 -r1.90 src/sbin/fsck_ffs/main.c
cvs rdiff -u -r1.59 -r1.60 src/sbin/fsck_ffs/pass1.c
cvs rdiff -u -r1.54 -r1.55 src/sbin/fsck_ffs/pass5.c
cvs rdiff -u -r1.103 -r1.104 src/sbin/fsck_ffs/setup.c
cvs rdiff -u -r1.66 -r1.67 src/sbin/fsck_ffs/utilities.c
cvs rdiff -u -r1.27 -r1.28 src/sbin/fsdb/fsdb.8
cvs rdiff -u -r1.52 -r1.53 src/sbin/fsdb/fsdb.c
cvs rdiff -u -r1.23 -r1.24 src/sbin/fsdb/fsdbutil.c
cvs rdiff -u -r1.32 -r1.33 src/sbin/fsirand/fsirand.c
cvs rdiff -u -r1.19 -r1.20 src/sbin/newfs/extern.h
cvs rdiff -u -r1.131 -r1.132 src/sbin/newfs/mkfs.c
cvs rdiff -u -r1.85 -r1.86 src/sbin/newfs/newfs.8
cvs rdiff -u -r1.117 -r1.118 src/sbin/newfs/newfs.c
cvs rdiff -u -r1.56 -r1.57 src/sbin/resize_ffs/resize_ffs.c
cvs rdiff -u -r1.35 -r1.36 src/sbin/scan_ffs/scan_ffs.c
cvs rdiff -u -r1.55 -r1.56 src/sbin/tunefs/tunefs.c
cvs rdiff -u -r1.1 -r1.2 src/sys/arch/hppa/stand/xxboot/readufs_ffs.c
cvs rdiff -u -r1.16 -r1.17 src/sys/arch/sparc/stand/bootblk/bootblk.fth
cvs rdiff -u -r1.9 -r1.10 src/sys/arch/sparc/stand/bootblk/genfth.cf
cvs rdiff -u -r1.14 -r1.15 src/sys/arch/x68k/stand/boot_ufs/readufs_ffs.c
cvs rdiff -u -r1.9 -r1.10 src/sys/lib/libsa/ffsv1.c src/sys/lib/libsa/ffsv2.c
cvs rdiff -u -r1.15 -r1.16 src/sys/lib/libsa/lfsv1.c \
    src/sys/lib/libsa/lfsv2.c
cvs rdiff -u -r1.86 -r1.87 src/sys/lib/libsa/ufs.c
cvs rdiff -u -r1.65 -r1.66 src/sys/ufs/ffs/ffs_balloc.c
cvs rdiff -u -r1.8 -r1.9 src/sys/ufs/ffs/ffs_extattr.c
cvs rdiff -u -r1.377 -r1.378 src/sys/ufs/ffs/ffs_vfsops.c
cvs rdiff -u -r1.69 -r1.70 src/sys/ufs/ffs/fs.h
cvs rdiff -u -r1.53 -r1.54 src/sys/ufs/ufs/ufs_bmap.c
cvs rdiff -u -r1.43 -r1.44 src/sys/ufs/ufs/ufsmount.h
cvs rdiff -u -r1.2 -r1.3 src/tests/fs/ffs/t_extattr.c
cvs rdiff -u -r1.2 -r1.3 src/tests/sbin/fsck_ffs/Makefile
cvs rdiff -u -r0 -r1.1 src/tests/sbin/fsck_ffs/t_extattr.sh
cvs rdiff -u -r1.65 -r1.66 src/usr.sbin/dumpfs/dumpfs.c
cvs rdiff -u -r1.1 -r1.2 src/usr.sbin/fstyp/ufs.c
cvs rdiff -u -r1.32 -r1.33 src/usr.sbin/installboot/ffs.c
cvs rdiff -u -r1.72 -r1.73 src/usr.sbin/makefs/ffs.c
cvs rdiff -u -r1.2 -r1.3 src/usr.sbin/makefs/ffs.h
cvs rdiff -u -r1.70 -r1.71 src/usr.sbin/makefs/makefs.8
cvs rdiff -u -r1.21 -r1.22 src/usr.sbin/makefs/ffs/ffs_balloc.c
cvs rdiff -u -r1.40 -r1.41 src/usr.sbin/makefs/ffs/mkfs.c
cvs rdiff -u -r1.34 -r1.35 src/usr.sbin/quot/quot.c
cvs rdiff -u -r1.49 -r1.50 src/usr.sbin/quotacheck/quotacheck.c
cvs rdiff -u -r1.41 -r1.42 src/usr.sbin/sysinst/label.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/UPDATING
diff -u src/UPDATING:1.334 src/UPDATING:1.335
--- src/UPDATING:1.334	Sat Nov 12 02:20:15 2022
+++ src/UPDATING	Thu Nov 17 06:40:38 2022
@@ -1,4 +1,4 @@
-$NetBSD: UPDATING,v 1.334 2022/11/12 02:20:15 mrg Exp $
+$NetBSD: UPDATING,v 1.335 2022/11/17 06:40:38 chs Exp $
 
 This file (UPDATING) is intended to be a brief reference to recent
 changes that might cause problems in the build process, and a guide for
@@ -19,6 +19,33 @@ See also: BUILDING, build.sh, Makefile.
 Recent changes:
 ^^^^^^^^^^^^^^^
 
+20221116:
+
+	The addition to NetBSD's version of UFS2 of support for extended
+	attributes broke backward compatibility with previous releases
+	of NetBSD, so UFS2 has been restored to being compatible with
+	previous NetBSD releases by disabling extended attributes.
+	(Note that ACLs are implemented as extended attributes, so
+	this changes disables ACLs as well.)
+
+	Support for UFS2 with extended attributes is now available in a new
+	UFS variant called UFS2ea.  If you have created extended attributes
+	in an original UFS2 file system then "fsck -p" will now fail due to
+	the unexpected presence of extended attributes and "fsck -y" will
+	remove all extended attributes.  If you wish to preserve extended
+	attributes rather than delete them, there is a utility to convert
+	a UFS2 file system to UFS2ea and leave extended attributes in place,
+	but this should be used with caution since it will preserve any
+	extended attributes that have been corrupted by the backward
+	incompatibility too.
+
+	If you wish to use a UFS2ea file system as your root file system,
+	then you will need to update your boot loader to a version that
+	supports UFS2ea.
+
+	For more information, see:
+	https://wiki.netbsd.org/features/UFS2ea
+
 20221111:
 	The new libdrm import worsened the conflict issues for the
 	kdump/ktruss ioctl, and i915 now conflicts with base, and has

Index: src/distrib/sets/lists/tests/mi
diff -u src/distrib/sets/lists/tests/mi:1.1230 src/distrib/sets/lists/tests/mi:1.1231
--- src/distrib/sets/lists/tests/mi:1.1230	Thu Nov 10 06:13:58 2022
+++ src/distrib/sets/lists/tests/mi	Thu Nov 17 06:40:38 2022
@@ -1,4 +1,4 @@
-# $NetBSD: mi,v 1.1230 2022/11/10 06:13:58 blymn Exp $
+# $NetBSD: mi,v 1.1231 2022/11/17 06:40:38 chs Exp $
 #
 # Note: don't delete entries from here - mark them as "obsolete" instead.
 #
@@ -4354,6 +4354,7 @@
 ./usr/tests/sbin/fsck_ffs/Kyuafile			tests-sbin-tests	compattestfile,atf,kyua
 ./usr/tests/sbin/fsck_ffs/t_check_quotas		tests-sbin-tests	compattestfile,atf
 ./usr/tests/sbin/fsck_ffs/t_enable_quotas		tests-sbin-tests	compattestfile,atf
+./usr/tests/sbin/fsck_ffs/t_extattr			tests-sbin-tests	compattestfile,atf
 ./usr/tests/sbin/gpt					tests-sbin-tests	compattestfile,atf
 ./usr/tests/sbin/gpt/Atffile				tests-sbin-tests	compattestfile,atf
 ./usr/tests/sbin/gpt/Kyuafile				tests-sbin-tests	compattestfile,atf,kyua

Index: src/sbin/badsect/badsect.c
diff -u src/sbin/badsect/badsect.c:1.34 src/sbin/badsect/badsect.c:1.35
--- src/sbin/badsect/badsect.c:1.34	Mon Sep  5 01:09:57 2016
+++ src/sbin/badsect/badsect.c	Thu Nov 17 06:40:38 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: badsect.c,v 1.34 2016/09/05 01:09:57 sevan Exp $	*/
+/*	$NetBSD: badsect.c,v 1.35 2022/11/17 06:40:38 chs Exp $	*/
 
 /*
  * Copyright (c) 1981, 1983, 1993
@@ -39,7 +39,7 @@ __COPYRIGHT("@(#) Copyright (c) 1981, 19
 #if 0
 static char sccsid[] = "@(#)badsect.c	8.2 (Berkeley) 5/4/95";
 #else
-__RCSID("$NetBSD: badsect.c,v 1.34 2016/09/05 01:09:57 sevan Exp $");
+__RCSID("$NetBSD: badsect.c,v 1.35 2022/11/17 06:40:38 chs Exp $");
 #endif
 #endif /* not lint */
 
@@ -151,11 +151,13 @@ main(int argc, char *argv[])
 		rdfs(sblock_try[i], SBLOCKSIZE, fs);
 		switch (fs->fs_magic) {
 		case FS_UFS2_MAGIC:
+		case FS_UFS2EA_MAGIC:
 			is_ufs2 = 1;
 			/* FALLTHROUGH */
 		case FS_UFS1_MAGIC:
 			break;
 		case FS_UFS2_MAGIC_SWAPPED:
+		case FS_UFS2EA_MAGIC_SWAPPED:
 			is_ufs2 = 1;
 			/* FALLTHROUGH */
 		case FS_UFS1_MAGIC_SWAPPED:

Index: src/sbin/cgdconfig/cgdconfig.c
diff -u src/sbin/cgdconfig/cgdconfig.c:1.60 src/sbin/cgdconfig/cgdconfig.c:1.61
--- src/sbin/cgdconfig/cgdconfig.c:1.60	Tue Sep 13 10:14:32 2022
+++ src/sbin/cgdconfig/cgdconfig.c	Thu Nov 17 06:40:38 2022
@@ -1,4 +1,4 @@
-/* $NetBSD: cgdconfig.c,v 1.60 2022/09/13 10:14:32 riastradh Exp $ */
+/* $NetBSD: cgdconfig.c,v 1.61 2022/11/17 06:40:38 chs Exp $ */
 
 /*-
  * Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
@@ -33,7 +33,7 @@
 #ifndef lint
 __COPYRIGHT("@(#) Copyright (c) 2002, 2003\
  The NetBSD Foundation, Inc.  All rights reserved.");
-__RCSID("$NetBSD: cgdconfig.c,v 1.60 2022/09/13 10:14:32 riastradh Exp $");
+__RCSID("$NetBSD: cgdconfig.c,v 1.61 2022/11/17 06:40:38 chs Exp $");
 #endif
 
 #ifdef HAVE_ARGON2
@@ -1207,8 +1207,10 @@ verify_ffs(int fd)
 		switch (u.fs.fs_magic) {
 		case FS_UFS1_MAGIC:
 		case FS_UFS2_MAGIC:
+		case FS_UFS2EA_MAGIC:
 		case FS_UFS1_MAGIC_SWAPPED:
 		case FS_UFS2_MAGIC_SWAPPED:
+		case FS_UFS2EA_MAGIC_SWAPPED:
 			return 0;
 		default:
 			continue;

Index: src/sbin/clri/clri.c
diff -u src/sbin/clri/clri.c:1.24 src/sbin/clri/clri.c:1.25
--- src/sbin/clri/clri.c:1.24	Sun Aug 30 05:23:17 2015
+++ src/sbin/clri/clri.c	Thu Nov 17 06:40:38 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: clri.c,v 1.24 2015/08/30 05:23:17 mlelstv Exp $	*/
+/*	$NetBSD: clri.c,v 1.25 2022/11/17 06:40:38 chs Exp $	*/
 
 /*
  * Copyright (c) 1990, 1993
@@ -42,7 +42,7 @@ __COPYRIGHT("@(#) Copyright (c) 1990, 19
 #if 0
 static char sccsid[] = "@(#)clri.c	8.3 (Berkeley) 4/28/95";
 #else
-__RCSID("$NetBSD: clri.c,v 1.24 2015/08/30 05:23:17 mlelstv Exp $");
+__RCSID("$NetBSD: clri.c,v 1.25 2022/11/17 06:40:38 chs Exp $");
 #endif
 #endif /* not lint */
 
@@ -107,11 +107,13 @@ main(int argc, char *argv[])
 		sbp = (struct fs *)sblock;
 		switch(sbp->fs_magic) {
 		case FS_UFS2_MAGIC:
+		case FS_UFS2EA_MAGIC:
 			is_ufs2 = 1;
 			/*FALLTHROUGH*/
 		case FS_UFS1_MAGIC:
 			break;
 		case FS_UFS2_MAGIC_SWAPPED:
+		case FS_UFS2EA_MAGIC_SWAPPED:
 			is_ufs2 = 1;
 			/*FALLTHROUGH*/
 		case FS_UFS1_MAGIC_SWAPPED:

Index: src/sbin/dump/ffs_inode.c
diff -u src/sbin/dump/ffs_inode.c:1.23 src/sbin/dump/ffs_inode.c:1.24
--- src/sbin/dump/ffs_inode.c:1.23	Fri Mar  1 16:42:11 2019
+++ src/sbin/dump/ffs_inode.c	Thu Nov 17 06:40:38 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: ffs_inode.c,v 1.23 2019/03/01 16:42:11 christos Exp $ */
+/*	$NetBSD: ffs_inode.c,v 1.24 2022/11/17 06:40:38 chs Exp $ */
 
 /*-
  * Copyright (c) 1980, 1991, 1993, 1994
@@ -36,7 +36,7 @@ __COPYRIGHT("@(#) Copyright (c) 1980, 19
 #endif /* not lint */
 
 #ifndef lint
-__RCSID("$NetBSD: ffs_inode.c,v 1.23 2019/03/01 16:42:11 christos Exp $");
+__RCSID("$NetBSD: ffs_inode.c,v 1.24 2022/11/17 06:40:38 chs Exp $");
 #endif /* not lint */
 
 #include <sys/param.h>
@@ -83,11 +83,17 @@ fs_read_sblock(char *superblock)
 		rawread(sblock_try[i], (char *)superblock, MAXBSIZE);
 
 		switch(sblock->fs_magic) {
+		case FS_UFS2EA_MAGIC:
+			sblock->fs_magic = FS_UFS2_MAGIC;
+			/*FALLTHROUGH*/
 		case FS_UFS2_MAGIC:
 			is_ufs2 = 1;
 			/*FALLTHROUGH*/
 		case FS_UFS1_MAGIC:
 			break;
+		case FS_UFS2EA_MAGIC_SWAPPED:
+			sblock->fs_magic = FS_UFS2_MAGIC_SWAPPED;
+			/*FALLTHROUGH*/
 		case FS_UFS2_MAGIC_SWAPPED:
 			is_ufs2 = 1;
 			/*FALLTHROUGH*/

Index: src/sbin/fsck_ffs/extern.h
diff -u src/sbin/fsck_ffs/extern.h:1.27 src/sbin/fsck_ffs/extern.h:1.28
--- src/sbin/fsck_ffs/extern.h:1.27	Thu Jun  9 19:57:52 2011
+++ src/sbin/fsck_ffs/extern.h	Thu Nov 17 06:40:38 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: extern.h,v 1.27 2011/06/09 19:57:52 christos Exp $	*/
+/*	$NetBSD: extern.h,v 1.28 2022/11/17 06:40:38 chs Exp $	*/
 
 /*
  * Copyright (c) 1994 James A. Jegers
@@ -42,6 +42,7 @@ void		clri(struct inodesc *, const char 
 int		cmpsblks(const struct fs *, struct fs *);
 int		cmpsblks42(const struct fs *, struct fs *);
 int		cmpsblks44(const struct fs *, struct fs *);
+void		cvt_magic(struct fs *);
 union		dinode * getnextinode(ino_t);
 void		direrror(ino_t, const char *);
 int		dirscan(struct inodesc *);

Index: src/sbin/fsck_ffs/fsck.h
diff -u src/sbin/fsck_ffs/fsck.h:1.55 src/sbin/fsck_ffs/fsck.h:1.56
--- src/sbin/fsck_ffs/fsck.h:1.55	Sat Apr 18 12:54:38 2020
+++ src/sbin/fsck_ffs/fsck.h	Thu Nov 17 06:40:38 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: fsck.h,v 1.55 2020/04/18 12:54:38 jdolecek Exp $	*/
+/*	$NetBSD: fsck.h,v 1.56 2022/11/17 06:40:38 chs Exp $	*/
 
 /*
  * Copyright (c) 1980, 1986, 1993
@@ -166,6 +166,7 @@ extern struct fs *sblocksave;
 		sb_oldfscompat_write(sblk.b_un.b_fs, sblocksave); \
 		if (needswap) \
 			ffs_sb_swap(sblk.b_un.b_fs, sblk.b_un.b_fs); \
+		cvt_magic(sblk.b_un.b_fs); \
 		sblk.b_dirty = 1; \
 	} while (0)
 #define	cgdirty()	do {copyback_cg(&cgblk); cgblk.b_dirty = 1;} while (0)
@@ -280,12 +281,15 @@ extern int	zflag;		/* zero unused direct
 extern int	cvtlevel;	/* convert to newer file system format */
 extern int	doinglevel1;	/* converting to new cylinder group format */
 extern int	doinglevel2;	/* converting to new inode format */
+extern int	doing2ea;	/* converting UFS2 to UFS2ea */
+extern int	doing2noea;	/* converting UFS2ea to UFS2 */
 extern int	newinofmt;	/* filesystem has new inode format */
 extern char	usedsoftdep;	/* just fix soft dependency inconsistencies */
 extern int	preen;		/* just fix normal inconsistencies */
 extern int	quiet;		/* Don't print anything if clean */
 extern int	forceimage;	/* file system is an image file */
 extern int	is_ufs2;	/* we're dealing with an UFS2 filesystem */
+extern int	is_ufs2ea;	/* is the variant that supports exattrs */
 extern int	markclean;	/* mark file system clean when done */
 extern char	havesb;		/* superblock has been read */
 extern char	skipclean;	/* skip clean file systems if preening */

Index: src/sbin/fsck_ffs/fsck_ffs.8
diff -u src/sbin/fsck_ffs/fsck_ffs.8:1.51 src/sbin/fsck_ffs/fsck_ffs.8:1.52
--- src/sbin/fsck_ffs/fsck_ffs.8:1.51	Sun May  5 14:59:06 2019
+++ src/sbin/fsck_ffs/fsck_ffs.8	Thu Nov 17 06:40:38 2022
@@ -1,4 +1,4 @@
-.\"	$NetBSD: fsck_ffs.8,v 1.51 2019/05/05 14:59:06 christos Exp $
+.\"	$NetBSD: fsck_ffs.8,v 1.52 2022/11/17 06:40:38 chs Exp $
 .\"
 .\" Copyright (c) 1980, 1989, 1991, 1993
 .\"	The Regents of the University of California.  All rights reserved.
@@ -205,7 +205,23 @@ option to
 .Xr newfs 8 .
 .El
 .Pp
-Note that FFSv2 file systems are always level 4.
+Note that FFSv2 file systems always have the features of FFSv1 level 4.
+.Pp
+FFSv2 file systems have separate conversion options:
+.Bl -tag -width 3n -offset indent
+.It ea
+Convert the file system to the format which supports extended attributes
+(and access control lists).
+After this conversion is performed, the file system will no longer be
+recognized at all by releases prior to
+.Nx 10.0 .
+.It no-ea
+Convert the file system to the format which does not support extended attributes
+(or access control lists).
+This will remove any existing extended attributes, and the file system
+will become recognizable to releases prior to
+.Nx 10.0 .
+.El
 .Pp
 In interactive mode,
 .Nm
@@ -227,6 +243,7 @@ in the second line)
 and the file system level
 .Dq ( fslevel
 in the sixth line).
+.Pp
 .It Fl d
 Print debugging output.
 .It Fl F

Index: src/sbin/fsck_ffs/main.c
diff -u src/sbin/fsck_ffs/main.c:1.89 src/sbin/fsck_ffs/main.c:1.90
--- src/sbin/fsck_ffs/main.c:1.89	Mon Apr  6 09:54:24 2020
+++ src/sbin/fsck_ffs/main.c	Thu Nov 17 06:40:38 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: main.c,v 1.89 2020/04/06 09:54:24 martin Exp $	*/
+/*	$NetBSD: main.c,v 1.90 2022/11/17 06:40:38 chs Exp $	*/
 
 /*
  * Copyright (c) 1980, 1986, 1993
@@ -39,7 +39,7 @@ __COPYRIGHT("@(#) Copyright (c) 1980, 19
 #if 0
 static char sccsid[] = "@(#)main.c	8.6 (Berkeley) 5/14/95";
 #else
-__RCSID("$NetBSD: main.c,v 1.89 2020/04/06 09:54:24 martin Exp $");
+__RCSID("$NetBSD: main.c,v 1.90 2022/11/17 06:40:38 chs Exp $");
 #endif
 #endif /* not lint */
 
@@ -102,11 +102,14 @@ int	zflag;
 int	cvtlevel;
 int	doinglevel1;
 int	doinglevel2;
+int	doing2ea;
+int	doing2noea;
 int	newinofmt;
 char	usedsoftdep;
 int	preen;
 int	forceimage;
 int	is_ufs2;
+int	is_ufs2ea;
 int	markclean;
 char	havesb;
 char	skipclean;
@@ -194,6 +197,14 @@ main(int argc, char *argv[])
 
 		case 'c':
 			skipclean = 0;
+			if (strcmp(optarg, "ea") == 0) {
+				doing2ea = 1;
+				break;
+			}
+			if (strcmp(optarg, "no-ea") == 0) {
+				doing2noea = 1;
+				break;
+			}
 			cvtlevel = argtoi('c', "conversion level", optarg, 10);
 			if (cvtlevel > 4) {
 				cvtlevel = 4;
@@ -201,7 +212,7 @@ main(int argc, char *argv[])
 				    cvtlevel);
 			}
 			break;
-		
+
 		case 'd':
 			debug++;
 			break;

Index: src/sbin/fsck_ffs/pass1.c
diff -u src/sbin/fsck_ffs/pass1.c:1.59 src/sbin/fsck_ffs/pass1.c:1.60
--- src/sbin/fsck_ffs/pass1.c:1.59	Sun Apr 19 19:37:06 2020
+++ src/sbin/fsck_ffs/pass1.c	Thu Nov 17 06:40:38 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: pass1.c,v 1.59 2020/04/19 19:37:06 christos Exp $	*/
+/*	$NetBSD: pass1.c,v 1.60 2022/11/17 06:40:38 chs Exp $	*/
 
 /*
  * Copyright (c) 1980, 1986, 1993
@@ -34,7 +34,7 @@
 #if 0
 static char sccsid[] = "@(#)pass1.c	8.6 (Berkeley) 4/28/95";
 #else
-__RCSID("$NetBSD: pass1.c,v 1.59 2020/04/19 19:37:06 christos Exp $");
+__RCSID("$NetBSD: pass1.c,v 1.60 2022/11/17 06:40:38 chs Exp $");
 #endif
 #endif /* not lint */
 
@@ -423,7 +423,23 @@ checkinode(ino_t inumber, struct inodesc
 	else
 		idesc->id_type = ADDR;
 	(void)ckinode(dp, idesc);
-	if (is_ufs2 && iswap32(dp->dp2.di_extsize) > 0) {
+	if (is_ufs2 && (!is_ufs2ea || doing2noea) &&
+	    (iswap32(dp->dp2.di_extsize) != 0 ||
+	     iswap64(dp->dp2.di_extb[0]) != 0 ||
+	     iswap64(dp->dp2.di_extb[1]) != 0)) {
+		pfatal("NON-ZERO EXTATTR FIELDS");
+		if (!reply("CLEAR EXTATTR FIELDS AND SET PERMS TO 0")) {
+			markclean = 0;
+			return;
+		}
+		dp = ginode(inumber);
+		dp->dp2.di_extsize = iswap32(0);
+		dp->dp2.di_extb[0] = iswap64(0);
+		dp->dp2.di_extb[1] = iswap64(0);
+		dp->dp2.di_mode &= ~07777;
+		inodirty();
+	}
+	if (is_ufs2ea && iswap32(dp->dp2.di_extsize) > 0) {
 		int ret, offset;
 		idesc->id_type = ADDR;
 		ndb = howmany(iswap32(dp->dp2.di_extsize), sblock->fs_bsize);

Index: src/sbin/fsck_ffs/pass5.c
diff -u src/sbin/fsck_ffs/pass5.c:1.54 src/sbin/fsck_ffs/pass5.c:1.55
--- src/sbin/fsck_ffs/pass5.c:1.54	Sun Jun 23 22:03:34 2013
+++ src/sbin/fsck_ffs/pass5.c	Thu Nov 17 06:40:38 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: pass5.c,v 1.54 2013/06/23 22:03:34 dholland Exp $	*/
+/*	$NetBSD: pass5.c,v 1.55 2022/11/17 06:40:38 chs Exp $	*/
 
 /*
  * Copyright (c) 1980, 1986, 1993
@@ -34,7 +34,7 @@
 #if 0
 static char sccsid[] = "@(#)pass5.c	8.9 (Berkeley) 4/28/95";
 #else
-__RCSID("$NetBSD: pass5.c,v 1.54 2013/06/23 22:03:34 dholland Exp $");
+__RCSID("$NetBSD: pass5.c,v 1.55 2022/11/17 06:40:38 chs Exp $");
 #endif
 #endif /* not lint */
 
@@ -223,11 +223,13 @@ pass5(void)
 		 * write back the superblock to the spare at this
 		 * cylinder group.
 		 */
-		if ((cvtlevel && sblk.b_dirty) || doswap) {
+		if ((cvtlevel && sblk.b_dirty) || doswap || doing2ea || doing2noea) {
 			bwrite(fswritefd, sblk.b_un.b_buf,
 			    FFS_FSBTODB(sblock, cgsblock(sblock, c)),
 			    sblock->fs_sbsize);
 		} else {
+			int alt_ufs2ea = 0;
+
 			/*
 			 * Read in the current alternate superblock,
 			 * and compare it to the master.  If it's
@@ -242,10 +244,15 @@ pass5(void)
 				    sblock->fs_sbsize);
 				if (needswap)
 					ffs_sb_swap(asblk.b_un.b_fs, altsblock);
+				if (altsblock->fs_magic == FS_UFS2EA_MAGIC) {
+					altsblock->fs_magic = FS_UFS2_MAGIC;
+					alt_ufs2ea = 1;
+				}
 			}
 			sb_oldfscompat_write(sblock, sblocksave);
-			if ((asblk.b_errs || cmpsblks(sblock, altsblock)) &&
-			     dofix(&idesc[3],
+			if ((asblk.b_errs || cmpsblks(sblock, altsblock) ||
+			     is_ufs2ea != alt_ufs2ea) &&
+			    dofix(&idesc[3],
 				   "ALTERNATE SUPERBLK(S) ARE INCORRECT")) {
 				bwrite(fswritefd, sblk.b_un.b_buf,
 				    FFS_FSBTODB(sblock, cgsblock(sblock, c)),

Index: src/sbin/fsck_ffs/setup.c
diff -u src/sbin/fsck_ffs/setup.c:1.103 src/sbin/fsck_ffs/setup.c:1.104
--- src/sbin/fsck_ffs/setup.c:1.103	Fri Apr 17 09:42:27 2020
+++ src/sbin/fsck_ffs/setup.c	Thu Nov 17 06:40:38 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: setup.c,v 1.103 2020/04/17 09:42:27 jdolecek Exp $	*/
+/*	$NetBSD: setup.c,v 1.104 2022/11/17 06:40:38 chs Exp $	*/
 
 /*
  * Copyright (c) 1980, 1986, 1993
@@ -34,7 +34,7 @@
 #if 0
 static char sccsid[] = "@(#)setup.c	8.10 (Berkeley) 5/9/95";
 #else
-__RCSID("$NetBSD: setup.c,v 1.103 2020/04/17 09:42:27 jdolecek Exp $");
+__RCSID("$NetBSD: setup.c,v 1.104 2022/11/17 06:40:38 chs Exp $");
 #endif
 #endif /* not lint */
 
@@ -718,7 +718,8 @@ detect_byteorder(struct fs *fs, int sblo
 	    fs->fs_magic == FS_UFS1_MAGIC_SWAPPED))
 		/* Likely to be the first alternate of a fs with 64k blocks */
 		return -1;
-	if (fs->fs_magic == FS_UFS1_MAGIC || fs->fs_magic == FS_UFS2_MAGIC) {
+	if (fs->fs_magic == FS_UFS1_MAGIC || fs->fs_magic == FS_UFS2_MAGIC ||
+	    fs->fs_magic == FS_UFS2EA_MAGIC) {
 #ifndef NO_FFS_EI
 		if (endian == 0 || BYTE_ORDER == endian) {
 			needswap = 0;
@@ -732,7 +733,8 @@ detect_byteorder(struct fs *fs, int sblo
 	}
 #ifndef NO_FFS_EI
 	else if (fs->fs_magic == FS_UFS1_MAGIC_SWAPPED ||
-		   fs->fs_magic == FS_UFS2_MAGIC_SWAPPED) {
+		 fs->fs_magic == FS_UFS2_MAGIC_SWAPPED ||
+		 fs->fs_magic == FS_UFS2EA_MAGIC_SWAPPED) {
 		if (endian == 0 || BYTE_ORDER != endian) {
 			needswap = 1;
 			doswap = do_blkswap = do_dirswap = 0;
@@ -746,6 +748,29 @@ detect_byteorder(struct fs *fs, int sblo
 	return -1;
 }
 
+/* Update on-disk fs->fs_magic if we are converting */
+void
+cvt_magic(struct fs *fs)
+{
+
+	if (is_ufs2ea || doing2ea) {
+		if (fs->fs_magic == FS_UFS2_MAGIC) {
+			fs->fs_magic = FS_UFS2EA_MAGIC;
+		}
+		if (fs->fs_magic == FS_UFS2_MAGIC_SWAPPED) {
+			fs->fs_magic = FS_UFS2EA_MAGIC_SWAPPED;
+		}
+	}
+	if (doing2noea) {
+		if (fs->fs_magic == FS_UFS2EA_MAGIC) {
+			fs->fs_magic = FS_UFS2_MAGIC;
+		}
+		if (fs->fs_magic == FS_UFS2EA_MAGIC_SWAPPED) {
+			fs->fs_magic = FS_UFS2_MAGIC_SWAPPED;
+		}
+	}
+}
+
 /*
  * Possible superblock locations ordered from most to least likely.
  */
@@ -811,9 +836,15 @@ readsb(int listerr)
 	memmove(sblock, sblk.b_un.b_fs, SBLOCKSIZE);
 	if (needswap)
 		ffs_sb_swap(sblk.b_un.b_fs, sblock);
-
+	if (sblock->fs_magic == FS_UFS2EA_MAGIC) {
+		is_ufs2ea = 1;
+		sblock->fs_magic = FS_UFS2_MAGIC;
+	}
 	is_ufs2 = sblock->fs_magic == FS_UFS2_MAGIC;
 
+	/* change on-disk magic if asked */
+	cvt_magic(fs);
+
 	/*
 	 * run a few consistency checks of the super block
 	 */
@@ -845,6 +876,11 @@ readsb(int listerr)
 	memmove(altsblock, asblk.b_un.b_fs, sblock->fs_sbsize);
 	if (needswap)
 		ffs_sb_swap(asblk.b_un.b_fs, altsblock);
+	if (altsblock->fs_magic == FS_UFS2EA_MAGIC) {
+		altsblock->fs_magic = FS_UFS2_MAGIC;
+	}
+	/* change on-disk magic if asked */
+	cvt_magic(asblk.b_un.b_fs);
 	if (cmpsblks(sblock, altsblock)) {
 		if (debug) {
 			uint32_t *nlp, *olp, *endlp;
@@ -873,7 +909,7 @@ out:
 	sb_oldfscompat_read(sblock, &sblocksave);
 
 	/* Now we know the SB is valid, we can write it back if needed */
-	if (doswap) {
+	if (doswap || doing2ea || doing2noea) {
 		sbdirty();
 		dirty(&asblk);
 	}

Index: src/sbin/fsck_ffs/utilities.c
diff -u src/sbin/fsck_ffs/utilities.c:1.66 src/sbin/fsck_ffs/utilities.c:1.67
--- src/sbin/fsck_ffs/utilities.c:1.66	Fri Apr 17 09:42:27 2020
+++ src/sbin/fsck_ffs/utilities.c	Thu Nov 17 06:40:38 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: utilities.c,v 1.66 2020/04/17 09:42:27 jdolecek Exp $	*/
+/*	$NetBSD: utilities.c,v 1.67 2022/11/17 06:40:38 chs Exp $	*/
 
 /*
  * Copyright (c) 1980, 1986, 1993
@@ -34,7 +34,7 @@
 #if 0
 static char sccsid[] = "@(#)utilities.c	8.6 (Berkeley) 5/19/95";
 #else
-__RCSID("$NetBSD: utilities.c,v 1.66 2020/04/17 09:42:27 jdolecek Exp $");
+__RCSID("$NetBSD: utilities.c,v 1.67 2022/11/17 06:40:38 chs Exp $");
 #endif
 #endif /* not lint */
 
@@ -324,6 +324,18 @@ ckfini(int noint)
 				    "\n***** FILE SYSTEM MARKED CLEAN *****\n");
 		}
 	}
+	if (doing2ea) {
+		printf("ENABLING EXTATTR SUPPORT\n");
+		is_ufs2ea = 1;
+		sbdirty();
+		flush(fswritefd, &sblk);
+	}
+	if (doing2noea) {
+		printf("DISABLING EXTATTR SUPPORT\n");
+		is_ufs2ea = 0;
+		sbdirty();
+		flush(fswritefd, &sblk);
+	}
 	if (debug)
 		printf("cache missed %ld of %ld (%d%%)\n", diskreads,
 		    totalreads, (int)(diskreads * 100 / totalreads));

Index: src/sbin/fsdb/fsdb.8
diff -u src/sbin/fsdb/fsdb.8:1.27 src/sbin/fsdb/fsdb.8:1.28
--- src/sbin/fsdb/fsdb.8:1.27	Sat May 29 16:51:25 2021
+++ src/sbin/fsdb/fsdb.8	Thu Nov 17 06:40:38 2022
@@ -1,4 +1,4 @@
-.\"	$NetBSD: fsdb.8,v 1.27 2021/05/29 16:51:25 christos Exp $
+.\"	$NetBSD: fsdb.8,v 1.28 2022/11/17 06:40:38 chs Exp $
 .\"
 .\" Copyright (c) 1996, 2017 The NetBSD Foundation, Inc.
 .\" All rights reserved.
@@ -35,7 +35,7 @@
 .Nd FFS debugging/editing tool
 .Sh SYNOPSIS
 .Nm
-.Op Fl dFn
+.Op Fl dFnN
 .Fl f Ar fsname
 .Sh DESCRIPTION
 .Nm
@@ -74,6 +74,12 @@ The
 .Fl n
 option disables writing to the device, preventing any changes from being made
 to the filesystem.
+.Pp
+The
+.Fl N
+option causes the superblock not to be marked dirty when
+.Nm
+exits.
 .Sh COMMANDS
 Besides the built-in
 .Xr editline 3

Index: src/sbin/fsdb/fsdb.c
diff -u src/sbin/fsdb/fsdb.c:1.52 src/sbin/fsdb/fsdb.c:1.53
--- src/sbin/fsdb/fsdb.c:1.52	Sat May 29 16:51:25 2021
+++ src/sbin/fsdb/fsdb.c	Thu Nov 17 06:40:38 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: fsdb.c,v 1.52 2021/05/29 16:51:25 christos Exp $	*/
+/*	$NetBSD: fsdb.c,v 1.53 2022/11/17 06:40:38 chs Exp $	*/
 
 /*-
  * Copyright (c) 1996, 2017 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: fsdb.c,v 1.52 2021/05/29 16:51:25 christos Exp $");
+__RCSID("$NetBSD: fsdb.c,v 1.53 2022/11/17 06:40:38 chs Exp $");
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -51,6 +51,7 @@ __RCSID("$NetBSD: fsdb.c,v 1.52 2021/05/
 #include <time.h>
 #include <unistd.h>
 #include <err.h>
+#include <stdbool.h>
 
 #include <ufs/ufs/dinode.h>
 #include <ufs/ufs/dir.h>
@@ -91,13 +92,17 @@ int	bflag;
 int	debug;
 int	zflag;
 int	cvtlevel;
+int	eaflag;
 int	doinglevel1;
 int	doinglevel2;
+int	doing2ea;
+int	doing2noea;
 int	newinofmt;
 char	usedsoftdep;
 int	preen;
 int	forceimage;
 int	is_ufs2;
+int	is_ufs2ea;
 int	markclean;
 char	havesb;
 char	skipclean;
@@ -137,6 +142,7 @@ static int scannames(struct inodesc *);
 static int dolookup(char *);
 static int chinumfunc(struct inodesc *);
 static int chnamefunc(struct inodesc *);
+static int chreclenfunc(struct inodesc *);
 static int dotime(char *, int64_t *, int32_t *);
 static void print_blks32(int32_t *buf, int size, uint64_t *blknum, struct wrinfo *wrp);
 static void print_blks64(int64_t *buf, int size, uint64_t *blknum, struct wrinfo *wrp);
@@ -160,7 +166,7 @@ ino_t   curinum;
 static void
 usage(void)
 {
-	errx(1, "usage: %s [-dFn] -f <fsname>", getprogname());
+	errx(1, "usage: %s [-dFfNn] <fsname>", getprogname());
 }
 /*
  * We suck in lots of fsck code, and just pick & choose the stuff we want.
@@ -173,11 +179,12 @@ main(int argc, char *argv[])
 {
 	int     ch, rval;
 	char   *fsys = NULL;
+	bool	makedirty = true;
 
 	forceimage = 0;
 	debug = 0;
 	isappleufs = 0;
-	while ((ch = getopt(argc, argv, "dFf:n")) != -1) {
+	while ((ch = getopt(argc, argv, "dFf:Nn")) != -1) {
 		switch (ch) {
 		case 'd':
 			debug++;
@@ -188,6 +195,9 @@ main(int argc, char *argv[])
 		case 'f':
 			fsys = optarg;
 			break;
+		case 'N':
+			makedirty = false;
+			break;
 		case 'n':
 			nflag++;
 			break;
@@ -195,6 +205,10 @@ main(int argc, char *argv[])
 			usage();
 		}
 	}
+	argc -= optind;
+	argv += optind;
+	if (fsys == NULL)
+		fsys = argv[0];
 	if (fsys == NULL)
 		usage();
 	endian = 0;
@@ -205,6 +219,10 @@ main(int argc, char *argv[])
 	rval = cmdloop();
 	if (nflag)
 		exit(rval);
+	if (!makedirty) {
+		ckfini(1);
+		exit(rval);
+	}
 	sblock->fs_clean = 0;	/* mark it dirty */
 	sbdirty();
 	markclean = 0;
@@ -245,6 +263,15 @@ CMDFUNC(chatime);		/* Change atime */
 CMDFUNC(chbirthtime);		/* Change birthtime */
 CMDFUNC(chinum);		/* Change inode # of dirent */
 CMDFUNC(chname);		/* Change dirname of dirent */
+CMDFUNC(chreclen);		/* Change reclen of dirent */
+CMDFUNC(chextsize);		/* Change extsize */
+CMDFUNC(chblocks);		/* Change blocks */
+CMDFUNC(chdb);			/* Change direct block pointer */
+CMDFUNC(chib);			/* Change indirect block pointer */
+CMDFUNC(chextb);		/* Change extattr block pointer */
+CMDFUNC(chfreelink);		/* Change freelink pointer */
+CMDFUNC(iptrs);			/* print raw block pointers for active inode */
+CMDFUNC(saveea);		/* Save extattrs */
 
 static struct cmdtable cmds[] = {
 	{"help", "Print out help", 1, 1, helpfn},
@@ -261,13 +288,14 @@ static struct cmdtable cmds[] = {
 	{"linkcount", "Set link count to COUNT", 2, 2, linkcount},
 	{"ls", "List current inode as directory", 1, 1, ls},
 	{"blks", "List current inode's data blocks", 1, 1, blks},
-	{"saveblks", "Save current inode's data blocks", 2, 2, blks},
+	{"saveblks", "Save current inode's data blocks to FILE", 2, 2, blks},
 	{"findblk", "Find inode owning disk block(s)", 2, 33, findblk},
 	{"rm", "Remove NAME from current inode directory", 2, 2, rm},
 	{"del", "Remove NAME from current inode directory", 2, 2, rm},
 	{"ln", "Hardlink INO into current inode directory as NAME", 3, 3, ln},
 	{"chinum", "Change dir entry number INDEX to INUM", 3, 3, chinum},
 	{"chname", "Change dir entry number INDEX to NAME", 3, 3, chname},
+	{"chreclen", "Change dir entry number INDEX to RECLEN", 3, 3, chreclen},
 	{"chtype", "Change type of current inode to TYPE", 2, 2, newtype},
 	{"chmod", "Change mode of current inode to MODE", 2, 2, chmode},
 	{"chown", "Change owner of current inode to OWNER", 2, 2, chowner},
@@ -276,11 +304,19 @@ static struct cmdtable cmds[] = {
 	{"chflags", "Change flags of current inode to FLAGS", 2, 2, chaflags},
 	{"chgen", "Change generation number of current inode to GEN", 2, 2,
 		    chgen},
+	{ "chextsize", "Change extsize of current inode to EXTSIZE", 2, 2, chextsize },
+	{ "chblocks", "Change blocks of current inode to BLOCKS", 2, 2, chblocks },
+	{ "chdb", "Change db pointer N of current inode to BLKNO", 3, 3, chdb },
+	{ "chib", "Change ib pointer N of current inode to BLKNO", 3, 3, chib },
+	{ "chextb", "Change extb pointer N of current inode to BLKNO", 3, 3, chextb },
+	{ "chfreelink", "Change freelink of current inode to FREELINK", 2, 2, chfreelink },
+	{ "iptrs", "Print raw block pointers of current inode", 1, 1, iptrs },
 	{"mtime", "Change mtime of current inode to MTIME", 2, 2, chmtime},
 	{"ctime", "Change ctime of current inode to CTIME", 2, 2, chctime},
 	{"atime", "Change atime of current inode to ATIME", 2, 2, chatime},
 	{"birthtime", "Change atime of current inode to BIRTHTIME", 2, 2,
 	    chbirthtime},
+	{"saveea", "Save current inode's extattr blocks to FILE", 2, 2, saveea},
 	{"quit", "Exit", 1, 1, quit},
 	{"q", "Exit", 1, 1, quit},
 	{"exit", "Exit", 1, 1, quit},
@@ -491,6 +527,7 @@ static const char *typename[] = {
 	"whiteout",
 };
 
+static int diroff;
 static int slot;
 
 static int
@@ -498,10 +535,11 @@ scannames(struct inodesc *idesc)
 {
 	struct direct *dirp = idesc->id_dirp;
 
-	printf("slot %d ino %d reclen %d: %s, `%.*s'\n",
-	    slot++, iswap32(dirp->d_ino), iswap16(dirp->d_reclen),
-		typename[dirp->d_type],
+	printf("slot %d off %d ino %d reclen %d: %s, `%.*s'\n",
+	    slot++, diroff, iswap32(dirp->d_ino), iswap16(dirp->d_reclen),
+	    typename[dirp->d_type],
 	    dirp->d_namlen, dirp->d_name);
+	diroff += dirp->d_reclen;
 	return (KEEPON);
 }
 
@@ -511,6 +549,7 @@ CMDFUNC(ls)
 	checkactivedir();	/* let it go on anyway */
 
 	slot = 0;
+	diroff = 0;
 	idesc.id_number = curinum;
 	idesc.id_func = scannames;
 	idesc.id_type = DATA;
@@ -524,16 +563,18 @@ CMDFUNC(ls)
 CMDFUNC(blks)
 {
 	uint64_t blkno = 0;
-	int i, type;
+	int i;
 	struct wrinfo wrinfo, *wrp = NULL;
+	bool saveblks;
 
-	if (strcmp(argv[0], "saveblks") == 0) {
+	saveblks = strcmp(argv[0], "saveblks") == 0;
+	if (saveblks) {
 		wrinfo.fd = open(argv[1], O_WRONLY | O_TRUNC | O_CREAT, 0644);
 		if (wrinfo.fd == -1) {
 			warn("unable to create file %s", argv[1]);
 			return 0;
 		}
-		wrinfo.size = DIP(curinode, size);
+		wrinfo.size = iswap64(DIP(curinode, size));
 		wrinfo.written_size = 0;
 		wrp = &wrinfo;
 	}
@@ -541,12 +582,6 @@ CMDFUNC(blks)
 		warnx("no current inode");
 		return 0;
 	}
-	type = iswap16(DIP(curinode, mode)) & IFMT;
-	if (type != IFDIR && type != IFREG) {
-		warnx("inode %llu not a file or directory",
-		    (unsigned long long)curinum);
-		return 0;
-	}
 	if (is_ufs2) {
 		printf("I=%llu %lld blocks\n", (unsigned long long)curinum,
 		    (long long)(iswap64(curinode->dp2.di_blocks)));
@@ -564,6 +599,11 @@ CMDFUNC(blks)
 		for (i = 0; i < UFS_NIADDR; i++)
 			print_indirblks64(iswap64(curinode->dp2.di_ib[i]), i,
 			    &blkno, wrp);
+		printf("Extattr blocks:\n");
+		blkno = 0;
+		if (saveblks)
+			wrinfo.size += iswap32(curinode->dp2.di_extsize);
+		print_blks64(curinode->dp2.di_extb, UFS_NXADDR, &blkno, wrp);
 	} else {
 		for (i = 0; i < UFS_NIADDR; i++)
 			print_indirblks32(iswap32(curinode->dp1.di_ib[i]), i,
@@ -827,7 +867,7 @@ static int
 writefileblk(struct wrinfo *wrp, uint64_t blk)
 {
 	char buf[MAXBSIZE];
-	long long size;
+	long long size, rsize;
 
 	size = wrp->size - wrp->written_size;
 	if (size > sblock->fs_bsize)
@@ -837,7 +877,8 @@ writefileblk(struct wrinfo *wrp, uint64_
 		return -1;
 	}
 
-	if (bread(fsreadfd, buf, FFS_FSBTODB(sblock, blk), size) != 0)
+	rsize = roundup(size, DEV_BSIZE);
+	if (bread(fsreadfd, buf, FFS_FSBTODB(sblock, blk), rsize) != 0)
 		return -1;
 	if (write(wrp->fd, buf, size) != size)
 		return -1;
@@ -1154,6 +1195,53 @@ CMDFUNC(chname)
 		}
 }
 
+static int
+chreclenfunc(struct inodesc *idesc)
+{
+	struct direct *dirp = idesc->id_dirp;
+
+	if (slotcount++ == desired) {
+		dirp->d_reclen = iswap16(idesc->id_parent);
+		return STOP | ALTERED | FOUND;
+	}
+	return KEEPON;
+}
+
+CMDFUNC(chreclen)
+{
+	char   *cp;
+	uint32_t reclen;
+	struct inodesc idesc;
+
+	slotcount = 0;
+	if (!checkactivedir())
+		return 1;
+
+	desired = strtoul(argv[1], &cp, 0);
+	if (cp == argv[1] || *cp != '\0') {
+		printf("invalid slot number `%s'\n", argv[1]);
+		return 1;
+	}
+	reclen = strtoul(argv[2], &cp, 0);
+	if (reclen >= UINT16_MAX) {
+		printf("invalid reclen `%s'\n", argv[2]);
+		return 1;
+	}
+
+	idesc.id_number = curinum;
+	idesc.id_func = chreclenfunc;
+	idesc.id_fix = IGNORE;
+	idesc.id_type = DATA;
+	idesc.id_parent = reclen;	/* XXX convenient hiding place */
+
+	if (ckinode(curinode, &idesc) & FOUND)
+		return 0;
+	else {
+		warnx("no %sth slot in current directory", argv[1]);
+		return 1;
+	}
+}
+
 static struct typemap {
 	const char *typename;
 	int     typebits;
@@ -1162,6 +1250,9 @@ static struct typemap {
 	{ "dir", IFDIR },
 	{ "socket", IFSOCK },
 	{ "fifo", IFIFO },
+	{"link", IFLNK},
+	{"chr", IFCHR},
+	{"blk", IFBLK},
 };
 
 CMDFUNC(newtype)
@@ -1217,13 +1308,13 @@ CMDFUNC(chmode)
 
 CMDFUNC(chlen)
 {
-	long    len;
+	off_t    len;
 	char   *cp;
 
 	if (!checkactive())
 		return 1;
 
-	len = strtol(argv[1], &cp, 0);
+	len = strtoull(argv[1], &cp, 0);
 	if (cp == argv[1] || *cp != '\0' || len < 0) {
 		warnx("bad length '%s'", argv[1]);
 		return 1;
@@ -1281,6 +1372,160 @@ CMDFUNC(chgen)
 	return 0;
 }
 
+CMDFUNC(chextsize)
+{
+	uint32_t extsize;
+	char *cp;
+
+	if (!is_ufs2)
+		return 1;
+	if (!checkactive())
+		return 1;
+
+	extsize = strtol(argv[1], &cp, 0);
+	if (cp == argv[1] || *cp != '\0') {
+		warnx("bad extsize `%s'", argv[1]);
+		return 1;
+	}
+
+	curinode->dp2.di_extsize = extsize;
+	inodirty();
+	printactive();
+	return 0;
+}
+
+CMDFUNC(chblocks)
+{
+	uint64_t blocks;
+	char *cp;
+
+	if (!checkactive())
+		return 1;
+
+	blocks = strtoll(argv[1], &cp, 0);
+	if (cp == argv[1] || *cp != '\0') {
+		warnx("bad blocks `%s'", argv[1]);
+		return 1;
+	}
+
+	DIP_SET(curinode, blocks, blocks);
+	inodirty();
+	printactive();
+	return 0;
+}
+
+CMDFUNC(chdb)
+{
+	unsigned int idx;
+	daddr_t bno;
+	char *cp;
+
+	if (!checkactive())
+		return 1;
+
+	idx = strtoull(argv[1], &cp, 0);
+	if (cp == argv[1] || *cp != '\0') {
+		warnx("bad pointer idx `%s'", argv[1]);
+		return 1;
+	}
+	bno = strtoll(argv[2], &cp, 0);
+	if (cp == argv[2] || *cp != '\0') {
+		warnx("bad block number `%s'", argv[2]);
+		return 1;
+	}
+	if (idx >= UFS_NDADDR) {
+		warnx("pointer index %d is out of range", idx);
+		return 1;
+	}
+
+	DIP_SET(curinode, db[idx], bno);
+	inodirty();
+	printactive();
+	return 0;
+}
+
+CMDFUNC(chib)
+{
+	unsigned int idx;
+	daddr_t bno;
+	char *cp;
+
+	if (!checkactive())
+		return 1;
+
+	idx = strtoull(argv[1], &cp, 0);
+	if (cp == argv[1] || *cp != '\0') {
+		warnx("bad pointer idx `%s'", argv[1]);
+		return 1;
+	}
+	bno = strtoll(argv[2], &cp, 0);
+	if (cp == argv[2] || *cp != '\0') {
+		warnx("bad block number `%s'", argv[2]);
+		return 1;
+	}
+	if (idx >= UFS_NIADDR) {
+		warnx("pointer index %d is out of range", idx);
+		return 1;
+	}
+
+	DIP_SET(curinode, ib[idx], bno);
+	inodirty();
+	printactive();
+	return 0;
+}
+
+CMDFUNC(chextb)
+{
+	unsigned int idx;
+	daddr_t bno;
+	char *cp;
+
+	if (!checkactive())
+		return 1;
+
+	idx = strtoull(argv[1], &cp, 0);
+	if (cp == argv[1] || *cp != '\0') {
+		warnx("bad pointer idx `%s'", argv[1]);
+		return 1;
+	}
+	bno = strtoll(argv[2], &cp, 0);
+	if (cp == argv[2] || *cp != '\0') {
+		warnx("bad block number `%s'", argv[2]);
+		return 1;
+	}
+	if (idx >= UFS_NXADDR) {
+		warnx("pointer index %d is out of range", idx);
+		return 1;
+	}
+
+	curinode->dp2.di_extb[idx] = bno;
+	inodirty();
+	printactive();
+	return 0;
+}
+
+CMDFUNC(chfreelink)
+{
+#if 0
+	ino_t freelink;
+	char *cp;
+
+	if (!checkactive())
+		return 1;
+
+	freelink = strtoll(argv[1], &cp, 0);
+	if (cp == argv[1] || *cp != '\0') {
+		warnx("bad freelink `%s'", argv[1]);
+		return 1;
+	}
+
+	DIP_SET(curinode, freelink, freelink);
+	inodirty();
+	printactive();
+#endif
+	return 0;
+}
+
 CMDFUNC(linkcount)
 {
 	int     lcnt;
@@ -1418,6 +1663,8 @@ CMDFUNC(chmtime)
 	int64_t rsec;
 	int32_t nsec;
 
+	if (!checkactive())
+		return 1;
 	if (dotime(argv[1], &rsec, &nsec))
 		return 1;
 	DIP_SET(curinode, mtime, rsec);
@@ -1432,6 +1679,8 @@ CMDFUNC(chatime)
 	int64_t rsec;
 	int32_t nsec;
 
+	if (!checkactive())
+		return 1;
 	if (dotime(argv[1], &rsec, &nsec))
 		return 1;
 	DIP_SET(curinode, atime, rsec);
@@ -1446,6 +1695,8 @@ CMDFUNC(chctime)
 	int64_t rsec;
 	int32_t nsec;
 
+	if (!checkactive())
+		return 1;
 	if (dotime(argv[1], &rsec, &nsec))
 		return 1;
 	DIP_SET(curinode, ctime, rsec);
@@ -1464,6 +1715,8 @@ CMDFUNC(chbirthtime)
 		warnx("birthtime can only be set in ufs2");
 		return 1;
 	}
+	if (!checkactive())
+		return 1;
 
 	if (dotime(argv[1], &rsec, &nsec))
 		return 1;
@@ -1473,3 +1726,43 @@ CMDFUNC(chbirthtime)
 	printactive();
 	return 0;
 }
+
+CMDFUNC(iptrs)
+{
+	int i;
+
+	if (!checkactive())
+		return 1;
+	for (i = 0; i < UFS_NDADDR; i++)
+		printf("di_db %d %ju\n", i, DIP(curinode, db[i]));
+	for (i = 0; i < UFS_NIADDR; i++)
+		printf("di_ib %d %ju\n", i, DIP(curinode, ib[i]));
+	if (is_ufs2)
+		for (i = 0; i < UFS_NXADDR; i++)
+			printf("di_extb %d %ju\n", i, curinode->dp2.di_extb[i]);
+	return 0;
+}
+
+CMDFUNC(saveea)
+{
+	struct wrinfo wrinfo;
+	uint64_t blkno = 0;
+
+	if (!is_ufs2) {
+		warnx("dumping extattrs is only supported for ufs2");
+		return 1;
+	}
+	if (!checkactive())
+		return 1;
+
+	wrinfo.fd = open(argv[1], O_WRONLY | O_TRUNC | O_CREAT, 0644);
+	if (wrinfo.fd == -1) {
+		warn("unable to create file %s", argv[1]);
+		return 0;
+	}
+
+	wrinfo.size = iswap32(curinode->dp2.di_extsize);
+	wrinfo.written_size = 0;
+	print_blks64(curinode->dp2.di_extb, UFS_NXADDR, &blkno, &wrinfo);
+	return 0;
+}

Index: src/sbin/fsdb/fsdbutil.c
diff -u src/sbin/fsdb/fsdbutil.c:1.23 src/sbin/fsdb/fsdbutil.c:1.24
--- src/sbin/fsdb/fsdbutil.c:1.23	Sat May 29 16:51:25 2021
+++ src/sbin/fsdb/fsdbutil.c	Thu Nov 17 06:40:38 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: fsdbutil.c,v 1.23 2021/05/29 16:51:25 christos Exp $	*/
+/*	$NetBSD: fsdbutil.c,v 1.24 2022/11/17 06:40:38 chs Exp $	*/
 
 /*-
  * Copyright (c) 1996 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: fsdbutil.c,v 1.23 2021/05/29 16:51:25 christos Exp $");
+__RCSID("$NetBSD: fsdbutil.c,v 1.24 2022/11/17 06:40:38 chs Exp $");
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -95,11 +95,13 @@ printstat(const char *cp, ino_t inum, un
 	time_t  t;
 	char   *p;
 	uint64_t size, blocks;
+	uint32_t extsize;
 	uint16_t mode;
 	uint32_t rdev;
 	uint32_t uid, gid;
 
 	size = iswap64(DIP(dp, size));
+	extsize = is_ufs2 ? iswap32(dp->dp2.di_extsize) : 0;
 	blocks = is_ufs2 ? iswap64(DIP(dp, blocks)) : iswap32(DIP(dp, blocks));
 	mode = iswap16(DIP(dp, mode));
 	rdev = iswap32(DIP(dp, rdev));
@@ -139,8 +141,8 @@ printstat(const char *cp, ino_t inum, un
 		puts("fifo");
 		break;
 	}
-	printf("I=%llu MODE=%o SIZE=%llu", (unsigned long long)inum, mode,
-	    (unsigned long long)size);
+	printf("I=%llu MODE=%o SIZE=%llu EXTSIZE=%u", (unsigned long long)inum,
+	    mode, (unsigned long long)size, extsize);
 	t = is_ufs2 ? iswap64(dp->dp2.di_mtime) : iswap32(dp->dp1.di_mtime);
 	p = ctime(&t);
 	printf("\n\t    MTIME=%15.15s %4.4s [%d nsec]", &p[4], &p[20],

Index: src/sbin/fsirand/fsirand.c
diff -u src/sbin/fsirand/fsirand.c:1.32 src/sbin/fsirand/fsirand.c:1.33
--- src/sbin/fsirand/fsirand.c:1.32	Sat Oct 19 01:09:58 2013
+++ src/sbin/fsirand/fsirand.c	Thu Nov 17 06:40:39 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: fsirand.c,v 1.32 2013/10/19 01:09:58 christos Exp $	*/
+/*	$NetBSD: fsirand.c,v 1.33 2022/11/17 06:40:39 chs Exp $	*/
 
 /*-
  * Copyright (c) 1997 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: fsirand.c,v 1.32 2013/10/19 01:09:58 christos Exp $");
+__RCSID("$NetBSD: fsirand.c,v 1.33 2022/11/17 06:40:39 chs Exp $");
 #endif /* lint */
 
 #include <sys/param.h>
@@ -95,11 +95,13 @@ getsblock(int fd, const char *name, stru
 
 		switch(fs->fs_magic) {
 		case FS_UFS2_MAGIC:
+		case FS_UFS2EA_MAGIC:
 			is_ufs2 = 1;
 			/* FALLTHROUGH */
 		case FS_UFS1_MAGIC:
 			break;
 		case FS_UFS2_MAGIC_SWAPPED:
+		case FS_UFS2EA_MAGIC_SWAPPED:
 			is_ufs2 = 1;
 			/* FALLTHROUGH */
 		case FS_UFS1_MAGIC_SWAPPED:

Index: src/sbin/newfs/extern.h
diff -u src/sbin/newfs/extern.h:1.19 src/sbin/newfs/extern.h:1.20
--- src/sbin/newfs/extern.h:1.19	Sat Apr 18 12:54:38 2020
+++ src/sbin/newfs/extern.h	Thu Nov 17 06:40:39 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: extern.h,v 1.19 2020/04/18 12:54:38 jdolecek Exp $	*/
+/*	$NetBSD: extern.h,v 1.20 2022/11/17 06:40:39 chs Exp $	*/
 
 /*
  * Copyright (c) 1997 Christos Zoulas.  All rights reserved.
@@ -31,6 +31,7 @@ void mkfs(const char *, int, int, mode_t
 extern int	mfs;		/* run as the memory based filesystem */
 extern int	Nflag;		/* run mkfs without writing file system */
 extern int	Oflag;		/* format as an 4.3BSD file system */
+extern int	eaflag;		/* use UFS2ea fs_magic */
 extern int	verbosity;	/* amount of printf() output */
 extern int64_t	fssize;		/* file system size */
 extern int	sectorsize;	/* bytes/sector */

Index: src/sbin/newfs/mkfs.c
diff -u src/sbin/newfs/mkfs.c:1.131 src/sbin/newfs/mkfs.c:1.132
--- src/sbin/newfs/mkfs.c:1.131	Sat Jan  1 10:32:28 2022
+++ src/sbin/newfs/mkfs.c	Thu Nov 17 06:40:39 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: mkfs.c,v 1.131 2022/01/01 10:32:28 msaitoh Exp $	*/
+/*	$NetBSD: mkfs.c,v 1.132 2022/11/17 06:40:39 chs Exp $	*/
 
 /*
  * Copyright (c) 1980, 1989, 1993
@@ -73,7 +73,7 @@
 #if 0
 static char sccsid[] = "@(#)mkfs.c	8.11 (Berkeley) 5/3/95";
 #else
-__RCSID("$NetBSD: mkfs.c,v 1.131 2022/01/01 10:32:28 msaitoh Exp $");
+__RCSID("$NetBSD: mkfs.c,v 1.132 2022/11/17 06:40:39 chs Exp $");
 #endif
 #endif /* not lint */
 
@@ -745,6 +745,8 @@ mkfs(const char *fsys, int fi, int fo,
 	memset(iobuf + sizeof(sblock), 0, i - sizeof(sblock));
 	if (needswap)
 		ffs_sb_swap(&sblock, (struct fs *)iobuf);
+	if (eaflag)
+		((struct fs *)iobuf)->fs_magic = FS_UFS2EA_MAGIC;
 	if ((sblock.fs_old_flags & FS_FLAGS_UPDATED) == 0)
 		memset(iobuf + offsetof(struct fs, fs_old_postbl_start),
 		    0xff, 256);

Index: src/sbin/newfs/newfs.8
diff -u src/sbin/newfs/newfs.8:1.85 src/sbin/newfs/newfs.8:1.86
--- src/sbin/newfs/newfs.8:1.85	Sat Apr 13 19:29:27 2019
+++ src/sbin/newfs/newfs.8	Thu Nov 17 06:40:39 2022
@@ -1,4 +1,4 @@
-.\"	$NetBSD: newfs.8,v 1.85 2019/04/13 19:29:27 maya Exp $
+.\"	$NetBSD: newfs.8,v 1.86 2022/11/17 06:40:39 chs Exp $
 .\"
 .\" Copyright (c) 1983, 1987, 1991, 1993, 1994
 .\"	The Regents of the University of California.  All rights reserved.
@@ -229,9 +229,10 @@ or
 This is the default.
 .It 2
 FFSv2; enhanced Fast File System, suited for more than 1 Terabyte capacity.
-.\" Supports access control lists.
 This is also known as
 .Sq UFS2 .
+.It 2ea
+FFSv2 plus support for extended attributes and access control lists.
 .El
 See
 .Xr fsck_ffs 8

Index: src/sbin/newfs/newfs.c
diff -u src/sbin/newfs/newfs.c:1.117 src/sbin/newfs/newfs.c:1.118
--- src/sbin/newfs/newfs.c:1.117	Sat Apr 16 18:15:20 2022
+++ src/sbin/newfs/newfs.c	Thu Nov 17 06:40:39 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: newfs.c,v 1.117 2022/04/16 18:15:20 andvar Exp $	*/
+/*	$NetBSD: newfs.c,v 1.118 2022/11/17 06:40:39 chs Exp $	*/
 
 /*
  * Copyright (c) 1983, 1989, 1993, 1994
@@ -78,7 +78,7 @@ __COPYRIGHT("@(#) Copyright (c) 1983, 19
 #if 0
 static char sccsid[] = "@(#)newfs.c	8.13 (Berkeley) 5/1/95";
 #else
-__RCSID("$NetBSD: newfs.c,v 1.117 2022/04/16 18:15:20 andvar Exp $");
+__RCSID("$NetBSD: newfs.c,v 1.118 2022/11/17 06:40:39 chs Exp $");
 #endif
 #endif /* not lint */
 
@@ -207,6 +207,7 @@ int	mfs;			/* run as the memory based fi
 int	Gflag;			/* allow garbage parameters (for testing) */
 int	Nflag;			/* run without writing file system */
 int	Oflag = 1;		/* format as an 4.3BSD file system */
+int	eaflag;			/* use UFS2ea fs_magic */
 int	verbosity;		/* amount of printf() output */
 #define DEFAULT_VERBOSITY 3	/* 4 is traditional behavior */
 int64_t	fssize;			/* file system size */
@@ -315,6 +316,10 @@ main(int argc, char *argv[])
 				verbosity = DEFAULT_VERBOSITY;
 			break;
 		case 'O':
+			if (strcmp(optarg, "2ea") == 0) {
+				eaflag = 1;
+				optarg[1] = 0;
+			}
 			Oflag = strsuftoi64("format", optarg, 0, 2, NULL);
 			break;
 		case 'S':
@@ -862,7 +867,7 @@ struct help_strings {
 	{ NEWFS,	"-I \t\tdo not check that the file system type is '4.2BSD'" },
 	{ BOTH,		"-N \t\tdo not create file system, just print out "
 			    "parameters" },
-	{ NEWFS,	"-O N\t\tfilesystem format: 0 => 4.3BSD, 1 => FFSv1, 2 => FFSv2" },
+	{ NEWFS,	"-O N\t\tfilesystem format: 0 => 4.3BSD, 1 => FFSv1, 2 => FFSv2, 2ea => FFSv2 with extattrs" },
 	{ NEWFS,	"-S secsize\tsector size" },
 #ifdef COMPAT
 	{ NEWFS,	"-T disktype\tdisk type" },

Index: src/sbin/resize_ffs/resize_ffs.c
diff -u src/sbin/resize_ffs/resize_ffs.c:1.56 src/sbin/resize_ffs/resize_ffs.c:1.57
--- src/sbin/resize_ffs/resize_ffs.c:1.56	Fri Apr  8 10:17:53 2022
+++ src/sbin/resize_ffs/resize_ffs.c	Thu Nov 17 06:40:39 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: resize_ffs.c,v 1.56 2022/04/08 10:17:53 andvar Exp $	*/
+/*	$NetBSD: resize_ffs.c,v 1.57 2022/11/17 06:40:39 chs Exp $	*/
 /* From sources sent on February 17, 2003 */
 /*-
  * As its sole author, I explicitly place this code in the public
@@ -36,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: resize_ffs.c,v 1.56 2022/04/08 10:17:53 andvar Exp $");
+__RCSID("$NetBSD: resize_ffs.c,v 1.57 2022/11/17 06:40:39 chs Exp $");
 
 #include <sys/disk.h>
 #include <sys/disklabel.h>
@@ -2227,12 +2227,14 @@ main(int argc, char **argv)
 		readat(where / DEV_BSIZE, oldsb, SBLOCKSIZE);
 		switch (oldsb->fs_magic) {
 		case FS_UFS2_MAGIC:
+		case FS_UFS2EA_MAGIC:
 			is_ufs2 = 1;
 			/* FALLTHROUGH */
 		case FS_UFS1_MAGIC:
 			needswap = 0;
 			break;
 		case FS_UFS2_MAGIC_SWAPPED:
+		case FS_UFS2EA_MAGIC_SWAPPED:
  			is_ufs2 = 1;
 			/* FALLTHROUGH */
 		case FS_UFS1_MAGIC_SWAPPED:

Index: src/sbin/scan_ffs/scan_ffs.c
diff -u src/sbin/scan_ffs/scan_ffs.c:1.35 src/sbin/scan_ffs/scan_ffs.c:1.36
--- src/sbin/scan_ffs/scan_ffs.c:1.35	Thu Jan 20 14:45:14 2022
+++ src/sbin/scan_ffs/scan_ffs.c	Thu Nov 17 06:40:39 2022
@@ -1,4 +1,4 @@
-/* $NetBSD: scan_ffs.c,v 1.35 2022/01/20 14:45:14 christos Exp $ */
+/* $NetBSD: scan_ffs.c,v 1.36 2022/11/17 06:40:39 chs Exp $ */
 
 /*
  * Copyright (c) 2005-2007 Juan Romero Pardines
@@ -33,7 +33,7 @@
  
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: scan_ffs.c,v 1.35 2022/01/20 14:45:14 christos Exp $");
+__RCSID("$NetBSD: scan_ffs.c,v 1.36 2022/11/17 06:40:39 chs Exp $");
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -128,7 +128,9 @@ ffs_checkver(struct sblockinfo *sbi)
 			sbi->ffs->fs_size = sbi->ffs->fs_old_size;
 			return FSTYPE_FFSV1;
 		case FS_UFS2_MAGIC:
+		case FS_UFS2EA_MAGIC:
 		case FS_UFS2_MAGIC_SWAPPED:
+		case FS_UFS2EA_MAGIC_SWAPPED:
 			return FSTYPE_FFSV2;
 		default:
 			return FSTYPE_NONE;

Index: src/sbin/tunefs/tunefs.c
diff -u src/sbin/tunefs/tunefs.c:1.55 src/sbin/tunefs/tunefs.c:1.56
--- src/sbin/tunefs/tunefs.c:1.55	Sat Sep 18 03:05:20 2021
+++ src/sbin/tunefs/tunefs.c	Thu Nov 17 06:40:39 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: tunefs.c,v 1.55 2021/09/18 03:05:20 christos Exp $	*/
+/*	$NetBSD: tunefs.c,v 1.56 2022/11/17 06:40:39 chs Exp $	*/
 
 /*
  * Copyright (c) 1983, 1993
@@ -39,7 +39,7 @@ __COPYRIGHT("@(#) Copyright (c) 1983, 19
 #if 0
 static char sccsid[] = "@(#)tunefs.c	8.3 (Berkeley) 5/3/95";
 #else
-__RCSID("$NetBSD: tunefs.c,v 1.55 2021/09/18 03:05:20 christos Exp $");
+__RCSID("$NetBSD: tunefs.c,v 1.56 2022/11/17 06:40:39 chs Exp $");
 #endif
 #endif /* not lint */
 
@@ -81,6 +81,7 @@ int	fi;
 long	dev_bsize = 512;
 int	needswap = 0;
 int	is_ufs2 = 0;
+int	extattr = 0;
 off_t	sblockloc;
 int	userquota = 0;
 int	groupquota = 0;
@@ -361,7 +362,9 @@ main(int argc, char *argv[])
 	if (aflag) {
 		name = "ACLs";
 		if (strcmp(avalue, "enable") == 0) {
-			if (sblock.fs_flags & FS_NFS4ACLS) {
+			if (is_ufs2 && !extattr) {
+				warnx("%s not supported by this fs", name);
+			} else if (sblock.fs_flags & FS_NFS4ACLS) {
 				warnx("%s remains unchanged as enabled", name);
 			} else if (sblock.fs_flags & FS_POSIX1EACLS) {
 				warnx("%s and POSIX.1e ACLs are mutually "
@@ -384,7 +387,9 @@ main(int argc, char *argv[])
 	if (pflag) {
 		name = "POSIX1e ACLs";
 		if (strcmp(pvalue, "enable") == 0) {
-			if (sblock.fs_flags & FS_POSIX1EACLS) {
+			if (is_ufs2 && !extattr) {
+				warnx("%s not supported by this fs", name);
+			} else if (sblock.fs_flags & FS_POSIX1EACLS) {
 				warnx("%s remains unchanged as enabled", name);
 			} else if (sblock.fs_flags & FS_NFS4ACLS) {
 				warnx("%s and ACLs are mutually "
@@ -657,11 +662,17 @@ getsb(struct fs *fs, const char *file)
 			errx(5, "cannot find filesystem superblock");
 		bread(sblock_try[i] / dev_bsize, (char *)fs, SBLOCKSIZE, file);
 		switch(fs->fs_magic) {
+		case FS_UFS2EA_MAGIC:
+			extattr = 1;
+			/*FALLTHROUGH*/
 		case FS_UFS2_MAGIC:
 			is_ufs2 = 1;
 			/*FALLTHROUGH*/
 		case FS_UFS1_MAGIC:
 			break;
+		case FS_UFS2EA_MAGIC_SWAPPED:
+			extattr = 1;
+			/*FALLTHROUGH*/
 		case FS_UFS2_MAGIC_SWAPPED:
 			is_ufs2 = 1;
 			/*FALLTHROUGH*/

Index: src/sys/arch/hppa/stand/xxboot/readufs_ffs.c
diff -u src/sys/arch/hppa/stand/xxboot/readufs_ffs.c:1.1 src/sys/arch/hppa/stand/xxboot/readufs_ffs.c:1.2
--- src/sys/arch/hppa/stand/xxboot/readufs_ffs.c:1.1	Mon Feb 24 07:23:43 2014
+++ src/sys/arch/hppa/stand/xxboot/readufs_ffs.c	Thu Nov 17 06:40:39 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: readufs_ffs.c,v 1.1 2014/02/24 07:23:43 skrll Exp $	*/
+/*	$NetBSD: readufs_ffs.c,v 1.2 2022/11/17 06:40:39 chs Exp $	*/
 /*	from Id: readufs_ffs.c,v 1.8 2004/06/12 04:26:39 itohy Exp	*/
 
 /*
@@ -66,7 +66,7 @@ try_ffs(void)
 			break;
 #endif
 #ifdef USE_UFS2
-		if (magic == FS_UFS2_MAGIC) {
+		if (magic == FS_UFS2_MAGIC || magic == FS_UFS2EA_MAGIC) {
 #ifdef USE_UFS1
 			fsi.ufstype = UFSTYPE_UFS2;
 #endif
@@ -81,7 +81,8 @@ try_ffs(void)
 	 */
 	fsi_ffs.magic = magic;
 #ifdef DEBUG_WITH_STDIO
-	printf("FFS: detected UFS%d format\n", (magic == FS_UFS2_MAGIC) + 1);
+	printf("FFS: detected UFS%d format\n",
+	       (magic == FS_UFS2_MAGIC || magic == FS_UFS2EA_MAGIC) + 1);
 #endif
 
 	/* This partition looks like an FFS. */

Index: src/sys/arch/sparc/stand/bootblk/bootblk.fth
diff -u src/sys/arch/sparc/stand/bootblk/bootblk.fth:1.16 src/sys/arch/sparc/stand/bootblk/bootblk.fth:1.17
--- src/sys/arch/sparc/stand/bootblk/bootblk.fth:1.16	Sat Jul 24 21:31:36 2021
+++ src/sys/arch/sparc/stand/bootblk/bootblk.fth	Thu Nov 17 06:40:39 2022
@@ -1,4 +1,4 @@
-\	$NetBSD: bootblk.fth,v 1.16 2021/07/24 21:31:36 andvar Exp $
+\	$NetBSD: bootblk.fth,v 1.17 2022/11/17 06:40:39 chs Exp $
 \
 \	IEEE 1275 Open Firmware Boot Block
 \
@@ -624,6 +624,7 @@ create cur-blockno -1 l, -1 l,		\ Curren
    fs_magic l@  case
       fs1_magic_value  of  init-ffs-v1 true  endof
       fs2_magic_value  of  init-ffs-v2 true  endof
+      fs2ea_magic_value  of  init-ffs-v2 true  endof
       false swap	\ Return false
    endcase
 ;
@@ -890,7 +891,7 @@ create cur-blockno -1 l, -1 l,		\ Curren
 
 : do-boot ( bootfile -- )
    ." NetBSD IEEE 1275 Multi-FS Bootblock" cr
-   ." Version $NetBSD: bootblk.fth,v 1.16 2021/07/24 21:31:36 andvar Exp $" cr
+   ." Version $NetBSD: bootblk.fth,v 1.17 2022/11/17 06:40:39 chs Exp $" cr
    boot-path load-file ( -- load-base )
    dup 0<>  if  " init-program " evaluate  then
 ; 

Index: src/sys/arch/sparc/stand/bootblk/genfth.cf
diff -u src/sys/arch/sparc/stand/bootblk/genfth.cf:1.9 src/sys/arch/sparc/stand/bootblk/genfth.cf:1.10
--- src/sys/arch/sparc/stand/bootblk/genfth.cf:1.9	Mon Jun 10 10:26:22 2013
+++ src/sys/arch/sparc/stand/bootblk/genfth.cf	Thu Nov 17 06:40:39 2022
@@ -1,4 +1,4 @@
-#	$NetBSD: genfth.cf,v 1.9 2013/06/10 10:26:22 hannken Exp $
+#	$NetBSD: genfth.cf,v 1.10 2022/11/17 06:40:39 chs Exp $
 
 #
 # Copyright (c) 1997 The NetBSD Foundation, Inc.
@@ -158,6 +158,7 @@ member	d_name
 
 define	fs1_magic_value	FS_UFS1_MAGIC
 define	fs2_magic_value	FS_UFS2_MAGIC
+define	fs2ea_magic_value FS_UFS2EA_MAGIC
 define	fs_42postblfmt	FS_42POSTBLFMT
 define	fs_44inodefmt	FS_44INODEFMT
 define	ndaddr		UFS_NDADDR

Index: src/sys/arch/x68k/stand/boot_ufs/readufs_ffs.c
diff -u src/sys/arch/x68k/stand/boot_ufs/readufs_ffs.c:1.14 src/sys/arch/x68k/stand/boot_ufs/readufs_ffs.c:1.15
--- src/sys/arch/x68k/stand/boot_ufs/readufs_ffs.c:1.14	Sun Jun 23 02:06:05 2013
+++ src/sys/arch/x68k/stand/boot_ufs/readufs_ffs.c	Thu Nov 17 06:40:39 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: readufs_ffs.c,v 1.14 2013/06/23 02:06:05 dholland Exp $	*/
+/*	$NetBSD: readufs_ffs.c,v 1.15 2022/11/17 06:40:39 chs Exp $	*/
 /*	from Id: readufs_ffs.c,v 1.6 2003/04/08 09:19:32 itohy Exp 	*/
 
 /*
@@ -69,7 +69,7 @@ try_ffs(void)
 		}
 #endif
 #ifdef USE_UFS2
-		if (magic == FS_UFS2_MAGIC) {
+		if (magic == FS_UFS2_MAGIC || magic == FS_UFS2EA_MAGIC) {
 #ifdef USE_UFS1
 			fsi.ufstype = UFSTYPE_UFS2;
 #endif
@@ -84,7 +84,8 @@ try_ffs(void)
 	 */
 	fsi_ffs.magic = magic;
 #ifdef DEBUG_WITH_STDIO
-	printf("FFS: detected UFS%d format\n", (magic == FS_UFS2_MAGIC) + 1);
+	printf("FFS: detected UFS%d format\n",
+	       (magic == FS_UFS2_MAGIC || magic == FS_UFS2EA_MAGIC) + 1);
 #endif
 
 	/* This partition looks like an FFS. */

Index: src/sys/lib/libsa/ffsv1.c
diff -u src/sys/lib/libsa/ffsv1.c:1.9 src/sys/lib/libsa/ffsv1.c:1.10
--- src/sys/lib/libsa/ffsv1.c:1.9	Sun Apr 24 06:52:59 2022
+++ src/sys/lib/libsa/ffsv1.c	Thu Nov 17 06:40:39 2022
@@ -1,4 +1,4 @@
-/* $NetBSD: ffsv1.c,v 1.9 2022/04/24 06:52:59 mlelstv Exp $ */
+/* $NetBSD: ffsv1.c,v 1.10 2022/11/17 06:40:39 chs Exp $ */
 
 #define LIBSA_FFSv1
 
@@ -17,9 +17,4 @@
 #define ufs_indp_swap	bswap32
 #define indp_t		int32_t
 
-#define FS_MAGIC FS_UFS1_MAGIC
-
-/* #define	FSMOD	"wapbl/ufs/ffs" */
-#define	FSMOD	NULL
-
 #include "ufs.c"
Index: src/sys/lib/libsa/ffsv2.c
diff -u src/sys/lib/libsa/ffsv2.c:1.9 src/sys/lib/libsa/ffsv2.c:1.10
--- src/sys/lib/libsa/ffsv2.c:1.9	Sun Apr 24 06:52:59 2022
+++ src/sys/lib/libsa/ffsv2.c	Thu Nov 17 06:40:39 2022
@@ -1,4 +1,4 @@
-/* $NetBSD: ffsv2.c,v 1.9 2022/04/24 06:52:59 mlelstv Exp $ */
+/* $NetBSD: ffsv2.c,v 1.10 2022/11/17 06:40:39 chs Exp $ */
 
 #define LIBSA_FFSv2
 
@@ -17,9 +17,4 @@
 #define ufs_indp_swap	bswap64
 #define indp_t		int64_t
 
-#define FS_MAGIC FS_UFS2_MAGIC
-
-/* #define	FSMOD	"wapbl/ufs/ffs" */
-#define	FSMOD	NULL
-
 #include "ufs.c"

Index: src/sys/lib/libsa/lfsv1.c
diff -u src/sys/lib/libsa/lfsv1.c:1.15 src/sys/lib/libsa/lfsv1.c:1.16
--- src/sys/lib/libsa/lfsv1.c:1.15	Thu May 27 06:54:44 2021
+++ src/sys/lib/libsa/lfsv1.c	Thu Nov 17 06:40:39 2022
@@ -1,4 +1,4 @@
-/* $NetBSD: lfsv1.c,v 1.15 2021/05/27 06:54:44 mrg Exp $ */
+/* $NetBSD: lfsv1.c,v 1.16 2022/11/17 06:40:39 chs Exp $ */
 
 #define	LIBSA_LFS
 #define	REQUIRED_LFS_VERSION	1
@@ -25,8 +25,6 @@
 #define dblksize(a, b, c)	lfs_dblksize((a), (b), (c))
 #define	FSBTODB(fs, daddr)	(daddr)		/* LFSv1 uses sectors for addresses */
 
-#define FS_MAGIC		LFS_MAGIC
-
 #define	FSMOD			"lfs"
 
 #include "lib/libsa/ufs.c"
Index: src/sys/lib/libsa/lfsv2.c
diff -u src/sys/lib/libsa/lfsv2.c:1.15 src/sys/lib/libsa/lfsv2.c:1.16
--- src/sys/lib/libsa/lfsv2.c:1.15	Thu May 27 06:54:44 2021
+++ src/sys/lib/libsa/lfsv2.c	Thu Nov 17 06:40:40 2022
@@ -1,4 +1,4 @@
-/* $NetBSD: lfsv2.c,v 1.15 2021/05/27 06:54:44 mrg Exp $ */
+/* $NetBSD: lfsv2.c,v 1.16 2022/11/17 06:40:40 chs Exp $ */
 
 #define	LIBSA_LFS
 #define	REQUIRED_LFS_VERSION	2
@@ -29,8 +29,6 @@
 #define dblksize(a, b, c)	lfs_dblksize((a), (b), (c))
 #define FSBTODB(a, b)		LFS_FSBTODB((a), (b))
 
-#define FS_MAGIC		LFS_MAGIC
-
 #define	FSMOD			"lfs"
 
 #include "lib/libsa/ufs.c"

Index: src/sys/lib/libsa/ufs.c
diff -u src/sys/lib/libsa/ufs.c:1.86 src/sys/lib/libsa/ufs.c:1.87
--- src/sys/lib/libsa/ufs.c:1.86	Fri Apr 29 07:42:07 2022
+++ src/sys/lib/libsa/ufs.c	Thu Nov 17 06:40:40 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: ufs.c,v 1.86 2022/04/29 07:42:07 rin Exp $	*/
+/*	$NetBSD: ufs.c,v 1.87 2022/11/17 06:40:40 chs Exp $	*/
 
 /*-
  * Copyright (c) 1993
@@ -156,9 +156,6 @@ typedef uint32_t	ino32_t;
 #ifndef FSBTODB
 #define FSBTODB(fs, indp) FFS_FSBTODB(fs, indp)
 #endif
-#ifndef FS_MAGIC
-#define FS_MAGIC FS_UFS1_MAGIC
-#endif
 #ifndef UFS_NINDIR
 #define UFS_NINDIR FFS_NINDIR
 #endif
@@ -214,17 +211,54 @@ static int search_directory(const char *
 static void ffs_oldfscompat(FS *);
 #endif
 
+#ifdef LIBSA_FFSv1
 static __inline__ bool
 ffs_is_magic(FS *fs)
 {
-	return fs->fs_magic == FS_MAGIC;
+	return fs->fs_magic == FS_UFS1_MAGIC;
+}
+
+static __inline__ bool
+ffs_is_magic_swapped(FS *fs)
+{
+	return fs->fs_magic == bswap32(FS_UFS1_MAGIC);
 }
+#endif
+
+#ifdef LIBSA_FFSv2
+static __inline__ bool
+ffs_is_magic(FS *fs)
+{
+	return fs->fs_magic == FS_UFS2_MAGIC || fs->fs_magic == FS_UFS2EA_MAGIC;
+}
+
+static __inline__ bool
+ffs_is_magic_swapped(FS *fs)
+{
+	return fs->fs_magic == bswap32(FS_UFS2_MAGIC) ||
+		fs->fs_magic == bswap32(FS_UFS2EA_MAGIC);
+}
+#endif
+
+#ifdef LIBSA_LFS
+static __inline__ bool
+ffs_is_magic(FS *fs)
+{
+	return fs->fs_magic == LFS_MAGIC;
+}
+
+static __inline__ bool
+ffs_is_magic_swapped(FS *fs)
+{
+	return fs->fs_magic == bswap32(LFS_MAGIC);
+}
+#endif
 
 static __inline__ void
 ffs_fix_magic_swapped(struct file *fp, FS *fs)
 {
 #ifdef LIBSA_FFS_EI
-	fp->f_swapped = fs->fs_magic == bswap32(FS_MAGIC);
+	fp->f_swapped = ffs_is_magic_swapped(fs);
 	if (fp->f_swapped)
 {
 		ffs_sb_swap(fs, fs);

Index: src/sys/ufs/ffs/ffs_balloc.c
diff -u src/sys/ufs/ffs/ffs_balloc.c:1.65 src/sys/ufs/ffs/ffs_balloc.c:1.66
--- src/sys/ufs/ffs/ffs_balloc.c:1.65	Sat Sep  5 16:30:13 2020
+++ src/sys/ufs/ffs/ffs_balloc.c	Thu Nov 17 06:40:40 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: ffs_balloc.c,v 1.65 2020/09/05 16:30:13 riastradh Exp $	*/
+/*	$NetBSD: ffs_balloc.c,v 1.66 2022/11/17 06:40:40 chs Exp $	*/
 
 /*
  * Copyright (c) 2002 Networks Associates Technology, Inc.
@@ -41,7 +41,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ffs_balloc.c,v 1.65 2020/09/05 16:30:13 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ffs_balloc.c,v 1.66 2022/11/17 06:40:40 chs Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_quota.h"
@@ -543,6 +543,8 @@ ffs_balloc_ufs2(struct vnode *vp, off_t 
 	const int needswap = UFS_FSNEEDSWAP(fs);
 	UVMHIST_FUNC("ffs_balloc"); UVMHIST_CALLED(ubchist);
 
+	KASSERT((ump->um_flags & UFS_EA) != 0 || (flags & IO_EXT) == 0);
+
 	lbn = ffs_lblkno(fs, off);
 	size = ffs_blkoff(fs, off) + size;
 	if (size > fs->fs_bsize)

Index: src/sys/ufs/ffs/ffs_extattr.c
diff -u src/sys/ufs/ffs/ffs_extattr.c:1.8 src/sys/ufs/ffs/ffs_extattr.c:1.9
--- src/sys/ufs/ffs/ffs_extattr.c:1.8	Tue Dec 14 11:06:50 2021
+++ src/sys/ufs/ffs/ffs_extattr.c	Thu Nov 17 06:40:40 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: ffs_extattr.c,v 1.8 2021/12/14 11:06:50 chs Exp $	*/
+/*	$NetBSD: ffs_extattr.c,v 1.9 2022/11/17 06:40:40 chs Exp $	*/
 
 /*-
  * SPDX-License-Identifier: (BSD-2-Clause-FreeBSD AND BSD-3-Clause)
@@ -66,7 +66,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ffs_extattr.c,v 1.8 2021/12/14 11:06:50 chs Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ffs_extattr.c,v 1.9 2022/11/17 06:40:40 chs Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_ffs.h"
@@ -464,6 +464,9 @@ ffs_open_ea(struct vnode *vp, kauth_cred
 	int error;
 
 	ip = VTOI(vp);
+	if ((ip->i_ump->um_flags & UFS_EA) == 0) {
+		return EOPNOTSUPP;
+	}
 
 	ffs_lock_ea(vp);
 	if (ip->i_ea_area != NULL) {
@@ -497,6 +500,7 @@ ffs_close_ea(struct vnode *vp, int commi
 	struct ufs2_dinode *dp;
 
 	ip = VTOI(vp);
+	KASSERT((ip->i_ump->um_flags & UFS_EA) != 0);
 
 	if (commit)
 		KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);

Index: src/sys/ufs/ffs/ffs_vfsops.c
diff -u src/sys/ufs/ffs/ffs_vfsops.c:1.377 src/sys/ufs/ffs/ffs_vfsops.c:1.378
--- src/sys/ufs/ffs/ffs_vfsops.c:1.377	Thu Nov 10 10:53:29 2022
+++ src/sys/ufs/ffs/ffs_vfsops.c	Thu Nov 17 06:40:40 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: ffs_vfsops.c,v 1.377 2022/11/10 10:53:29 hannken Exp $	*/
+/*	$NetBSD: ffs_vfsops.c,v 1.378 2022/11/17 06:40:40 chs Exp $	*/
 
 /*-
  * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -61,7 +61,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ffs_vfsops.c,v 1.377 2022/11/10 10:53:29 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ffs_vfsops.c,v 1.378 2022/11/17 06:40:40 chs Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_ffs.h"
@@ -845,6 +845,15 @@ ffs_reload(struct mount *mp, kauth_cred_
 
 	brelse(bp, 0);
 
+	/* Allow converting from UFS2 to UFS2EA but not vice versa. */
+	if (newfs->fs_magic == FS_UFS2EA_MAGIC) {
+		ump->um_flags |= UFS_EA;
+		newfs->fs_magic = FS_UFS2_MAGIC;
+	} else {
+		if ((ump->um_flags & UFS_EA) != 0)
+			return EINVAL;
+	}
+
 	if ((newfs->fs_magic != FS_UFS1_MAGIC) &&
 	    (newfs->fs_magic != FS_UFS2_MAGIC)) {
 		kmem_free(newfs, fs_sbsize);
@@ -1217,6 +1226,13 @@ ffs_mountfs(struct vnode *devvp, struct 
 		 * size to read the superblock. Once read, we swap the whole
 		 * superblock structure.
 		 */
+		if (fs->fs_magic == FS_UFS2EA_MAGIC) {
+			ump->um_flags |= UFS_EA;
+			fs->fs_magic = FS_UFS2_MAGIC;
+		} else if (fs->fs_magic == FS_UFS2EA_MAGIC_SWAPPED) {
+			ump->um_flags |= UFS_EA;
+			fs->fs_magic = FS_UFS2_MAGIC_SWAPPED;
+		}
 		if (fs->fs_magic == FS_UFS1_MAGIC) {
 			fs_sbsize = fs->fs_sbsize;
 			fstype = UFS1;
@@ -2375,6 +2391,11 @@ ffs_sbupdate(struct ufsmount *mp, int wa
 	memcpy(bp->b_data, fs, fs->fs_sbsize);
 
 	ffs_oldfscompat_write((struct fs *)bp->b_data, mp);
+	if (mp->um_flags & UFS_EA) {
+		struct fs *bfs = (struct fs *)bp->b_data;
+		KASSERT(bfs->fs_magic == FS_UFS2_MAGIC);
+		bfs->fs_magic = FS_UFS2EA_MAGIC;
+	}
 #ifdef FFS_EI
 	if (mp->um_flags & UFS_NEEDSWAP)
 		ffs_sb_swap((struct fs *)bp->b_data, (struct fs *)bp->b_data);

Index: src/sys/ufs/ffs/fs.h
diff -u src/sys/ufs/ffs/fs.h:1.69 src/sys/ufs/ffs/fs.h:1.70
--- src/sys/ufs/ffs/fs.h:1.69	Sat Sep 18 03:05:20 2021
+++ src/sys/ufs/ffs/fs.h	Thu Nov 17 06:40:40 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: fs.h,v 1.69 2021/09/18 03:05:20 christos Exp $	*/
+/*	$NetBSD: fs.h,v 1.70 2022/11/17 06:40:40 chs Exp $	*/
 
 /*
  * Copyright (c) 1982, 1986, 1993
@@ -398,8 +398,10 @@ struct fs {
  */
 #define	FS_UFS1_MAGIC	0x011954	/* UFS1 fast file system magic number */
 #define	FS_UFS2_MAGIC	0x19540119	/* UFS2 fast file system magic number */
+#define	FS_UFS2EA_MAGIC	0x19012038	/* UFS2 with extattrs */
 #define	FS_UFS1_MAGIC_SWAPPED	0x54190100
 #define	FS_UFS2_MAGIC_SWAPPED	0x19015419
+#define	FS_UFS2EA_MAGIC_SWAPPED	0x38200119
 #define	FS_OKAY		0x7c269d38	/* superblock checksum */
 #define	FS_42INODEFMT	-1		/* 4.2BSD inode format */
 #define	FS_44INODEFMT	2		/* 4.4BSD inode format */

Index: src/sys/ufs/ufs/ufs_bmap.c
diff -u src/sys/ufs/ufs/ufs_bmap.c:1.53 src/sys/ufs/ufs/ufs_bmap.c:1.54
--- src/sys/ufs/ufs/ufs_bmap.c:1.53	Mon Apr 20 03:57:02 2020
+++ src/sys/ufs/ufs/ufs_bmap.c	Thu Nov 17 06:40:40 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: ufs_bmap.c,v 1.53 2020/04/20 03:57:02 christos Exp $	*/
+/*	$NetBSD: ufs_bmap.c,v 1.54 2022/11/17 06:40:40 chs Exp $	*/
 
 /*
  * Copyright (c) 1989, 1991, 1993
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ufs_bmap.c,v 1.53 2020/04/20 03:57:02 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ufs_bmap.c,v 1.54 2022/11/17 06:40:40 chs Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -191,7 +191,7 @@ ufs_bmaparray(struct vnode *vp, daddr_t 
 		}
 		return (0);
 	} else if (bn < 0 && bn >= -UFS_NXADDR) {
-		KASSERT(ump->um_fstype == UFS2);
+		KASSERT(ump->um_fstype == UFS2 && (ump->um_flags & UFS_EA) != 0);
 		daddr = ufs_rw64(ip->i_ffs2_extb[-1 - bn], UFS_MPNEEDSWAP(ump));
 		*bnp = blkptrtodb(ump, daddr);
 		if (*bnp == 0)

Index: src/sys/ufs/ufs/ufsmount.h
diff -u src/sys/ufs/ufs/ufsmount.h:1.43 src/sys/ufs/ufs/ufsmount.h:1.44
--- src/sys/ufs/ufs/ufsmount.h:1.43	Fri Mar 27 17:27:56 2015
+++ src/sys/ufs/ufs/ufsmount.h	Thu Nov 17 06:40:40 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: ufsmount.h,v 1.43 2015/03/27 17:27:56 riastradh Exp $	*/
+/*	$NetBSD: ufsmount.h,v 1.44 2022/11/17 06:40:40 chs Exp $	*/
 
 /*
  * Copyright (c) 1982, 1986, 1989, 1993
@@ -163,6 +163,7 @@ struct ufs_ops {
 #define UFS_ISAPPLEUFS	0x02	/* filesystem is Apple UFS */
 #define UFS_QUOTA	0x04	/* filesystem has QUOTA (v1) */
 #define UFS_QUOTA2	0x08	/* filesystem has QUOTA2 */
+#define UFS_EA		0x10	/* UFS2 with extattrs */
 
 /*
  * Filesystem types

Index: src/tests/fs/ffs/t_extattr.c
diff -u src/tests/fs/ffs/t_extattr.c:1.2 src/tests/fs/ffs/t_extattr.c:1.3
--- src/tests/fs/ffs/t_extattr.c:1.2	Sun Apr 12 23:52:20 2020
+++ src/tests/fs/ffs/t_extattr.c	Thu Nov 17 06:40:40 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: t_extattr.c,v 1.2 2020/04/12 23:52:20 christos Exp $	*/
+/*	$NetBSD: t_extattr.c,v 1.3 2022/11/17 06:40:40 chs Exp $	*/
 
 /*-
  * Copyright (c) 2020 The NetBSD Foundation, Inc.
@@ -29,7 +29,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: t_extattr.c,v 1.2 2020/04/12 23:52:20 christos Exp $");
+__RCSID("$NetBSD: t_extattr.c,v 1.3 2022/11/17 06:40:40 chs Exp $");
 
 #include <sys/types.h>
 #include <sys/mount.h>
@@ -78,8 +78,8 @@ check_list(const char *buf, ssize_t nr)
 	}
 }
 
-// Make it ffsv2
-const char *newfs = "newfs -O 2 -F -s 10000 " IMGNAME;
+// Make it ffsv2 with extattrs
+const char *newfs = "newfs -O 2ea -F -s 10000 " IMGNAME;
 #define FAKEBLK "/dev/formula1"
 
 static void

Index: src/tests/sbin/fsck_ffs/Makefile
diff -u src/tests/sbin/fsck_ffs/Makefile:1.2 src/tests/sbin/fsck_ffs/Makefile:1.3
--- src/tests/sbin/fsck_ffs/Makefile:1.2	Sun Mar  6 17:08:41 2011
+++ src/tests/sbin/fsck_ffs/Makefile	Thu Nov 17 06:40:40 2022
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile,v 1.2 2011/03/06 17:08:41 bouyer Exp $
+# $NetBSD: Makefile,v 1.3 2022/11/17 06:40:40 chs Exp $
 
 .include <bsd.own.mk>
 
@@ -9,4 +9,6 @@ TESTS_SH+=	${name}
 TESTS_SH_SRC_${name}=	quotas_common.sh ${name}.sh
 .endfor
 
+TESTS_SH+=	t_extattr
+
 .include <bsd.test.mk>

Index: src/usr.sbin/dumpfs/dumpfs.c
diff -u src/usr.sbin/dumpfs/dumpfs.c:1.65 src/usr.sbin/dumpfs/dumpfs.c:1.66
--- src/usr.sbin/dumpfs/dumpfs.c:1.65	Sat Sep 18 03:05:20 2021
+++ src/usr.sbin/dumpfs/dumpfs.c	Thu Nov 17 06:40:40 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: dumpfs.c,v 1.65 2021/09/18 03:05:20 christos Exp $	*/
+/*	$NetBSD: dumpfs.c,v 1.66 2022/11/17 06:40:40 chs Exp $	*/
 
 /*
  * Copyright (c) 1983, 1992, 1993
@@ -39,7 +39,7 @@ __COPYRIGHT("@(#) Copyright (c) 1983, 19
 #if 0
 static char sccsid[] = "@(#)dumpfs.c	8.5 (Berkeley) 4/29/95";
 #else
-__RCSID("$NetBSD: dumpfs.c,v 1.65 2021/09/18 03:05:20 christos Exp $");
+__RCSID("$NetBSD: dumpfs.c,v 1.66 2022/11/17 06:40:40 chs Exp $");
 #endif
 #endif /* not lint */
 
@@ -192,11 +192,13 @@ dumpfs(const char *name)
 		if (read(fd, &afs, SBLOCKSIZE) != SBLOCKSIZE)
 			continue;
 		switch(afs.fs_magic) {
+		case FS_UFS2EA_MAGIC:
 		case FS_UFS2_MAGIC:
 			is_ufs2 = 1;
 			break;
 		case FS_UFS1_MAGIC:
 			break;
+		case FS_UFS2EA_MAGIC_SWAPPED:
 		case FS_UFS2_MAGIC_SWAPPED:
 			is_ufs2 = 1;
 			needswap = 1;
@@ -294,7 +296,8 @@ print_superblock(struct fs *fs, uint16_t
 	time_t t;
 	int32_t fsflags;
 
-	printf("format\tFFSv%d\n", is_ufs2+1);
+	printf("format\tFFSv%d%s\n", is_ufs2+1,
+	       fs->fs_magic == FS_UFS2EA_MAGIC ? "ea" : "");
 #if BYTE_ORDER == LITTLE_ENDIAN
 	if (needswap)
 #else

Index: src/usr.sbin/fstyp/ufs.c
diff -u src/usr.sbin/fstyp/ufs.c:1.1 src/usr.sbin/fstyp/ufs.c:1.2
--- src/usr.sbin/fstyp/ufs.c:1.1	Tue Jan  9 03:31:15 2018
+++ src/usr.sbin/fstyp/ufs.c	Thu Nov 17 06:40:40 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: ufs.c,v 1.1 2018/01/09 03:31:15 christos Exp $	*/
+/*	$NetBSD: ufs.c,v 1.2 2022/11/17 06:40:40 chs Exp $	*/
 
 /*-
  * Copyright (c) 2017 The NetBSD Foundation, Inc.
@@ -36,7 +36,7 @@
  * SUCH DAMAGE.
  */
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: ufs.c,v 1.1 2018/01/09 03:31:15 christos Exp $");
+__RCSID("$NetBSD: ufs.c,v 1.2 2022/11/17 06:40:40 chs Exp $");
 
 #include <sys/types.h>
 #include <stdint.h>
@@ -67,6 +67,12 @@ fstyp_ufs(FILE *fp, char *label, size_t 
 		fs = (struct fs *)read_buf(fp, superblock, SBLOCKSIZE);
 		if (fs == NULL)
 			continue;
+
+		if (fs->fs_magic == FS_UFS2EA_MAGIC)
+			fs->fs_magic = FS_UFS2_MAGIC;
+		else if (fs->fs_magic == FS_UFS2EA_MAGIC_SWAPPED)
+			fs->fs_magic = FS_UFS2_MAGIC_SWAPPED;
+
 		/*
 		 * Check for magic. We also need to check if file system size
 		 * is equal to providers size, because sysinstall(8) used to

Index: src/usr.sbin/installboot/ffs.c
diff -u src/usr.sbin/installboot/ffs.c:1.32 src/usr.sbin/installboot/ffs.c:1.33
--- src/usr.sbin/installboot/ffs.c:1.32	Sun Jun 23 02:06:06 2013
+++ src/usr.sbin/installboot/ffs.c	Thu Nov 17 06:40:40 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: ffs.c,v 1.32 2013/06/23 02:06:06 dholland Exp $	*/
+/*	$NetBSD: ffs.c,v 1.33 2022/11/17 06:40:40 chs Exp $	*/
 
 /*-
  * Copyright (c) 2002 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
 
 #include <sys/cdefs.h>
 #if !defined(__lint)
-__RCSID("$NetBSD: ffs.c,v 1.32 2013/06/23 02:06:06 dholland Exp $");
+__RCSID("$NetBSD: ffs.c,v 1.33 2022/11/17 06:40:40 chs Exp $");
 #endif	/* !__lint */
 
 #include <sys/param.h>
@@ -502,6 +502,7 @@ ffs_match_common(ib_params *params, off_
 			continue;
 		switch (fs->fs_magic) {
 		case FS_UFS2_MAGIC:
+		case FS_UFS2EA_MAGIC:
 			is_ufs2 = 1;
 			/* FALLTHROUGH */
 		case FS_UFS1_MAGIC:
@@ -512,6 +513,7 @@ ffs_match_common(ib_params *params, off_
 			break;
 #ifndef FFS_NO_SWAP
 		case FS_UFS2_MAGIC_SWAPPED:
+		case FS_UFS2EA_MAGIC_SWAPPED:
 			is_ufs2 = 1;
 			/* FALLTHROUGH */
 		case FS_UFS1_MAGIC_SWAPPED:

Index: src/usr.sbin/makefs/ffs.c
diff -u src/usr.sbin/makefs/ffs.c:1.72 src/usr.sbin/makefs/ffs.c:1.73
--- src/usr.sbin/makefs/ffs.c:1.72	Sat Apr  9 10:05:35 2022
+++ src/usr.sbin/makefs/ffs.c	Thu Nov 17 06:40:41 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: ffs.c,v 1.72 2022/04/09 10:05:35 riastradh Exp $	*/
+/*	$NetBSD: ffs.c,v 1.73 2022/11/17 06:40:41 chs Exp $	*/
 
 /*
  * Copyright (c) 2001 Wasabi Systems, Inc.
@@ -71,7 +71,7 @@
 
 #include <sys/cdefs.h>
 #if defined(__RCSID) && !defined(__lint)
-__RCSID("$NetBSD: ffs.c,v 1.72 2022/04/09 10:05:35 riastradh Exp $");
+__RCSID("$NetBSD: ffs.c,v 1.73 2022/11/17 06:40:41 chs Exp $");
 #endif	/* !__lint */
 
 #include <sys/param.h>
@@ -180,6 +180,8 @@ ffs_prep_opts(fsinfo_t *fsopts)
 	      0, 0, "Optimization (time|space)" },
 	    { 'l', "label", ffs_opts->label, OPT_STRARRAY,
 	      1, sizeof(ffs_opts->label), "UFS label" },
+	    { 'e', "extattr", &ffs_opts->extattr, OPT_INT32,
+	      0, 1, "extattr support" },
 	    { .name = NULL }
 	};
 
@@ -194,6 +196,7 @@ ffs_prep_opts(fsinfo_t *fsopts)
 	ffs_opts->avgfilesize= -1;
 	ffs_opts->avgfpdir= -1;
 	ffs_opts->version = 1;
+	ffs_opts->extattr = 1;
 
 	fsopts->fs_specific = ffs_opts;
 	fsopts->fs_options = copy_opts(ffs_options);

Index: src/usr.sbin/makefs/ffs.h
diff -u src/usr.sbin/makefs/ffs.h:1.2 src/usr.sbin/makefs/ffs.h:1.3
--- src/usr.sbin/makefs/ffs.h:1.2	Sun Oct  9 21:33:43 2011
+++ src/usr.sbin/makefs/ffs.h	Thu Nov 17 06:40:41 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: ffs.h,v 1.2 2011/10/09 21:33:43 christos Exp $	*/
+/*	$NetBSD: ffs.h,v 1.3 2022/11/17 06:40:41 chs Exp $	*/
 
 /*
  * Copyright (c) 2001-2003 Wasabi Systems, Inc.
@@ -60,6 +60,7 @@ typedef struct {
 	int	avgfilesize;	/* expected average file size */
 	int	avgfpdir;	/* expected # of files per directory */
 	int	version;	/* filesystem version (1 = FFS, 2 = UFS2) */
+	int	extattr;	/* use UFS2ea magic */
 	int	maxbsize;	/* maximum extent size */
 	int	maxblkspercg;	/* max # of blocks per cylinder group */
 		/* XXX: support `old' file systems ? */

Index: src/usr.sbin/makefs/makefs.8
diff -u src/usr.sbin/makefs/makefs.8:1.70 src/usr.sbin/makefs/makefs.8:1.71
--- src/usr.sbin/makefs/makefs.8:1.70	Wed Apr  6 13:39:06 2022
+++ src/usr.sbin/makefs/makefs.8	Thu Nov 17 06:40:41 2022
@@ -1,4 +1,4 @@
-.\"	$NetBSD: makefs.8,v 1.70 2022/04/06 13:39:06 wiz Exp $
+.\"	$NetBSD: makefs.8,v 1.71 2022/11/17 06:40:41 chs Exp $
 .\"
 .\" Copyright (c) 2001-2003 Wasabi Systems, Inc.
 .\" All rights reserved.
@@ -304,6 +304,8 @@ Expected number of files per directory.
 Block size.
 .It Sy density
 Bytes per inode.
+.It Sy extattr
+UFS2 with extended attributes.
 .It Sy extent
 Maximum extent size.
 .It Sy fsize

Index: src/usr.sbin/makefs/ffs/ffs_balloc.c
diff -u src/usr.sbin/makefs/ffs/ffs_balloc.c:1.21 src/usr.sbin/makefs/ffs/ffs_balloc.c:1.22
--- src/usr.sbin/makefs/ffs/ffs_balloc.c:1.21	Sun Mar 29 05:52:59 2015
+++ src/usr.sbin/makefs/ffs/ffs_balloc.c	Thu Nov 17 06:40:41 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: ffs_balloc.c,v 1.21 2015/03/29 05:52:59 agc Exp $	*/
+/*	$NetBSD: ffs_balloc.c,v 1.22 2022/11/17 06:40:41 chs Exp $	*/
 /* From NetBSD: ffs_balloc.c,v 1.25 2001/08/08 08:36:36 lukem Exp */
 
 /*
@@ -38,7 +38,7 @@
 
 #include <sys/cdefs.h>
 #if defined(__RCSID) && !defined(__lint)
-__RCSID("$NetBSD: ffs_balloc.c,v 1.21 2015/03/29 05:52:59 agc Exp $");
+__RCSID("$NetBSD: ffs_balloc.c,v 1.22 2022/11/17 06:40:41 chs Exp $");
 #endif	/* !__lint */
 
 #include <sys/param.h>
@@ -74,7 +74,8 @@ static int ffs_balloc_ufs2(struct inode 
 int
 ffs_balloc(struct inode *ip, off_t offset, int bufsize, struct buf **bpp)
 {
-	if (ip->i_fs->fs_magic == FS_UFS2_MAGIC)
+	if (ip->i_fs->fs_magic == FS_UFS2_MAGIC ||
+	    ip->i_fs->fs_magic == FS_UFS2EA_MAGIC)
 		return ffs_balloc_ufs2(ip, offset, bufsize, bpp);
 	else
 		return ffs_balloc_ufs1(ip, offset, bufsize, bpp);

Index: src/usr.sbin/makefs/ffs/mkfs.c
diff -u src/usr.sbin/makefs/ffs/mkfs.c:1.40 src/usr.sbin/makefs/ffs/mkfs.c:1.41
--- src/usr.sbin/makefs/ffs/mkfs.c:1.40	Sat Apr  2 19:16:49 2022
+++ src/usr.sbin/makefs/ffs/mkfs.c	Thu Nov 17 06:40:41 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: mkfs.c,v 1.40 2022/04/02 19:16:49 mlelstv Exp $	*/
+/*	$NetBSD: mkfs.c,v 1.41 2022/11/17 06:40:41 chs Exp $	*/
 
 /*
  * Copyright (c) 2002 Networks Associates Technology, Inc.
@@ -48,7 +48,7 @@
 static char sccsid[] = "@(#)mkfs.c	8.11 (Berkeley) 5/3/95";
 #else
 #ifdef __RCSID
-__RCSID("$NetBSD: mkfs.c,v 1.40 2022/04/02 19:16:49 mlelstv Exp $");
+__RCSID("$NetBSD: mkfs.c,v 1.41 2022/11/17 06:40:41 chs Exp $");
 #endif
 #endif
 #endif /* not lint */
@@ -109,6 +109,7 @@ union {
 #define writebuf wb.pad
 
 static int     Oflag;	   /* format as an 4.3BSD file system */
+static int     extattr;	   /* use UFS2ea magic */
 static int64_t fssize;	   /* file system size */
 static int     sectorsize;	   /* bytes/sector */
 static int     fsize;	   /* fragment size */
@@ -148,6 +149,7 @@ ffs_mkfs(const char *fsys, const fsinfo_
 	ffs_opt_t	*ffs_opts = fsopts->fs_specific;
 
 	Oflag =		ffs_opts->version;
+	extattr =	ffs_opts->extattr;
 	fssize =        fsopts->size / fsopts->sectorsize;
 	sectorsize =    fsopts->sectorsize;
 	fsize =         ffs_opts->fsize;
@@ -296,7 +298,10 @@ ffs_mkfs(const char *fsys, const fsinfo_
 		sblock.fs_old_postblformat = 1;
 		sblock.fs_old_nrpos = 1;
 	} else {
-		sblock.fs_magic = FS_UFS2_MAGIC;
+		if (extattr)
+			sblock.fs_magic = FS_UFS2EA_MAGIC;
+		else
+			sblock.fs_magic = FS_UFS2_MAGIC;
 #if 0 /* XXX makefs is used for small filesystems. */
 		sblock.fs_sblockloc = SBLOCK_UFS2;
 #else

Index: src/usr.sbin/quot/quot.c
diff -u src/usr.sbin/quot/quot.c:1.34 src/usr.sbin/quot/quot.c:1.35
--- src/usr.sbin/quot/quot.c:1.34	Thu Jul 28 08:24:58 2016
+++ src/usr.sbin/quot/quot.c	Thu Nov 17 06:40:41 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: quot.c,v 1.34 2016/07/28 08:24:58 martin Exp $	*/
+/*	$NetBSD: quot.c,v 1.35 2022/11/17 06:40:41 chs Exp $	*/
 
 /*
  * Copyright (C) 1991, 1994 Wolfgang Solfrank.
@@ -33,7 +33,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: quot.c,v 1.34 2016/07/28 08:24:58 martin Exp $");
+__RCSID("$NetBSD: quot.c,v 1.35 2022/11/17 06:40:41 chs Exp $");
 #endif /* not lint */
 
 #include <sys/param.h>
@@ -569,10 +569,12 @@ quot(const char *name, const char *mp)
 		fs = (struct fs *)superblock;
 
 		if (fs->fs_magic != FS_UFS1_MAGIC &&
-		    fs->fs_magic != FS_UFS2_MAGIC)
+		    fs->fs_magic != FS_UFS2_MAGIC &&
+		    fs->fs_magic != FS_UFS2EA_MAGIC)
 			continue;
 
 		if (fs->fs_magic == FS_UFS2_MAGIC
+		    || fs->fs_magic == FS_UFS2EA_MAGIC
 		    || fs->fs_old_flags & FS_FLAGS_UPDATED) {
 			/* Not the main superblock */
 			if (fs->fs_sblockloc != sbloc)

Index: src/usr.sbin/quotacheck/quotacheck.c
diff -u src/usr.sbin/quotacheck/quotacheck.c:1.49 src/usr.sbin/quotacheck/quotacheck.c:1.50
--- src/usr.sbin/quotacheck/quotacheck.c:1.49	Tue Jun 16 23:04:14 2015
+++ src/usr.sbin/quotacheck/quotacheck.c	Thu Nov 17 06:40:41 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: quotacheck.c,v 1.49 2015/06/16 23:04:14 christos Exp $	*/
+/*	$NetBSD: quotacheck.c,v 1.50 2022/11/17 06:40:41 chs Exp $	*/
 
 /*
  * Copyright (c) 1980, 1990, 1993
@@ -42,7 +42,7 @@ __COPYRIGHT("@(#) Copyright (c) 1980, 19
 #if 0
 static char sccsid[] = "@(#)quotacheck.c	8.6 (Berkeley) 4/28/95";
 #else
-__RCSID("$NetBSD: quotacheck.c,v 1.49 2015/06/16 23:04:14 christos Exp $");
+__RCSID("$NetBSD: quotacheck.c,v 1.50 2022/11/17 06:40:41 chs Exp $");
 #endif
 #endif /* not lint */
 
@@ -367,6 +367,9 @@ chkquota(const char *type, const char *f
 		bread(sblock_try[i], (char *)&sblock, SBLOCKSIZE);
 		switch (sblock.fs_magic) {
 #ifdef HAVE_UFSv2
+		case FS_UFS2EA_MAGIC:
+			sblock.fs_magic = FS_UFS2_MAGIC;
+			/*FALLTHROUGH*/
 		case FS_UFS2_MAGIC:
 			is_ufs2 = 1;
 			/*FALLTHROUGH*/
@@ -374,6 +377,9 @@ chkquota(const char *type, const char *f
 		case FS_UFS1_MAGIC:
 			break;
 #ifdef HAVE_UFSv2
+		case FS_UFS2EA_MAGIC_SWAPPED:
+			sblock.fs_magic = FS_UFS2_MAGIC_SWAPPED;
+			/*FALLTHROUGH*/
 		case FS_UFS2_MAGIC_SWAPPED:
 			is_ufs2 = 1;
 			/*FALLTHROUGH*/

Index: src/usr.sbin/sysinst/label.c
diff -u src/usr.sbin/sysinst/label.c:1.41 src/usr.sbin/sysinst/label.c:1.42
--- src/usr.sbin/sysinst/label.c:1.41	Tue Jun 21 15:46:10 2022
+++ src/usr.sbin/sysinst/label.c	Thu Nov 17 06:40:41 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: label.c,v 1.41 2022/06/21 15:46:10 martin Exp $	*/
+/*	$NetBSD: label.c,v 1.42 2022/11/17 06:40:41 chs Exp $	*/
 
 /*
  * Copyright 1997 Jonathan Stone
@@ -36,7 +36,7 @@
 
 #include <sys/cdefs.h>
 #if defined(LIBC_SCCS) && !defined(lint)
-__RCSID("$NetBSD: label.c,v 1.41 2022/06/21 15:46:10 martin Exp $");
+__RCSID("$NetBSD: label.c,v 1.42 2022/11/17 06:40:41 chs Exp $");
 #endif
 
 #include <sys/types.h>
@@ -2023,7 +2023,9 @@ get_last_mounted(int fd, daddr_t partsta
 				*fs_sub_type = 1;
 			continue;
 		case FS_UFS2_MAGIC:
+		case FS_UFS2EA_MAGIC:
 		case FS_UFS2_MAGIC_SWAPPED:
+		case FS_UFS2EA_MAGIC_SWAPPED:
 			/* Check we have the main superblock */
 			if (SB->fs_sblockloc == *sbp) {
 				mnt = (const char *)SB->fs_fsmnt;

Added files:

Index: src/tests/sbin/fsck_ffs/t_extattr.sh
diff -u /dev/null src/tests/sbin/fsck_ffs/t_extattr.sh:1.1
--- /dev/null	Thu Nov 17 06:40:42 2022
+++ src/tests/sbin/fsck_ffs/t_extattr.sh	Thu Nov 17 06:40:40 2022
@@ -0,0 +1,197 @@
+# $NetBSD: t_extattr.sh,v 1.1 2022/11/17 06:40:40 chs Exp $
+#
+#  Copyright (c) 2021 The NetBSD Foundation, Inc.
+#  All rights reserved.
+# 
+#  Redistribution and use in source and binary forms, with or without
+#  modification, are permitted provided that the following conditions
+#  are met:
+#  1. Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+#  2. Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in the
+#     documentation and/or other materials provided with the distribution.
+# 
+#  THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+#  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+#  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+#  PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+#  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+#  POSSIBILITY OF SUCH DAMAGE.
+#
+
+VND=vnd0
+BDEV=/dev/${VND}a
+CDEV=/dev/r${VND}a
+IMG=fsimage
+MNT=mnt
+
+atf_test_case fsck_extattr_enable cleanup
+atf_test_case fsck_extattr_enable_corrupted cleanup
+atf_test_case fsck_extattr_disable cleanup
+
+cleanup()
+{
+	echo in cleanup
+	umount -f ${MNT} > /dev/null 2>&1 || true
+	vnconfig -u ${VND} > /dev/null 2>&1 || true
+}
+
+fsck_extattr_enable_head()
+{
+	atf_set "descr" "Checks fsck_ffs enabling extattrs"
+}
+
+fsck_extattr_enable_body()
+{
+	atf_check mkdir -p ${MNT}
+
+	atf_check -o ignore newfs -O2 -s 4m -F ${IMG}
+	atf_check vnconfig ${VND} ${IMG}
+
+	# Verify that extattrs are disabled.
+	atf_check -o ignore -e 'match:POSIX1e ACLs not supported by this fs' \
+		tunefs -p enable ${CDEV}
+	atf_check mount -t ffs ${BDEV} ${MNT}
+	atf_check touch ${MNT}/file
+	atf_check -s exit:1 -e ignore setextattr user name1 value1 ${MNT}/file
+	atf_check umount ${MNT}
+
+	# Enable extattrs.
+	atf_check -o 'match:ENABLING EXTATTR SUPPORT' \
+		fsck_ffs -c ea ${CDEV}
+
+	# Verify that extattrs are now enabled.
+	atf_check -o 'match:POSIX1e ACLs set' -e ignore \
+		tunefs -p enable ${CDEV}
+	atf_check mount -t ffs ${BDEV} ${MNT}
+	atf_check touch ${MNT}/file
+	atf_check setextattr user testname testvalue ${MNT}/file
+	atf_check -o 'match:testvalue' getextattr user testname ${MNT}/file
+	atf_check umount ${MNT}
+	atf_check vnconfig -u ${VND}
+}
+
+fsck_extattr_enable_cleanup()
+{
+	cleanup
+}
+
+fsck_extattr_enable_corrupted_head()
+{
+	atf_set "descr" "Checks fsck_ffs enabling extattrs with corruption"
+}
+
+fsck_extattr_enable_corrupted_body()
+{
+	atf_check mkdir -p ${MNT}
+
+	# Create an fs with extattrs enabled and set an extattr on the test file.
+	atf_check -o ignore newfs -O2ea -b 8k -f 1k -s 4m -F ${IMG}
+	atf_check vnconfig ${VND} ${IMG}
+
+	atf_check mount -t ffs ${BDEV} ${MNT}
+	atf_check touch ${MNT}/file
+	atf_check setextattr user testname testvalue ${MNT}/file
+	atf_check -o 'match:testvalue' getextattr user testname ${MNT}/file
+	atf_check umount ${MNT}
+
+	# Find the location and size of the extattr block.
+	extb0=$(printf 'cd file\niptrs\n' | fsdb -n $CDEV | grep 'di_extb 0' |
+		awk '{print $3}')
+	extsize=$(printf 'cd file\n' | fsdb -n $CDEV | grep EXTSIZE | tail -1 |
+		awk '{print $4}' | sed 's,.*=,,')
+	atf_check [ $extb0 != 0 ]
+	atf_check [ $extsize != 0 ]
+
+	# Recreate the fs with extattrs disabled and set the extattr block
+	# size/location of the new test file to the same values as the old
+	# test file.  This simulates extattrs having been created in a
+	# UFS2-non-ea file system before UFS2ea was invented.
+	atf_check -o ignore newfs -O2 -b 8k -f 1k -s 4m -F ${IMG}
+	atf_check mount -t ffs ${BDEV} ${MNT}
+	atf_check touch ${MNT}/file
+	atf_check umount ${MNT}
+	printf "cd file\nchextb 0 $extb0\n" | fsdb -N $CDEV
+	printf "cd file\nchextsize $extsize\n" | fsdb -N $CDEV
+
+	# Convert to enable extattrs.
+	atf_check -o 'match:CLEAR EXTATTR FIELDS' \
+		  -o 'match:ENABLING EXTATTR SUPPORT' \
+		  fsck_ffs -y -c ea ${CDEV}
+
+	# Verify that the test file does not have the extattr.
+	atf_check -o ignore fsck -n ${CDEV}
+	atf_check mount -t ffs ${BDEV} ${MNT}
+	atf_check -s exit:1 -e 'match:Attribute not found' \
+		  getextattr user testname ${MNT}/file
+	atf_check umount ${MNT}
+	atf_check vnconfig -u ${VND}
+}
+
+fsck_extattr_enable_corrupted_cleanup()
+{
+	cleanup
+}
+
+fsck_extattr_disable_head()
+{
+	atf_set "descr" "Checks fsck_ffs disabling extattrs"
+}
+
+fsck_extattr_disable_body()
+{
+	atf_check mkdir -p ${MNT}
+
+	# Create an fs with extattrs enabled and set an extattr on the test file.
+	atf_check -o ignore newfs -O2ea -b 8k -f 1k -s 4m -F ${IMG}
+	atf_check vnconfig ${VND} ${IMG}
+
+	atf_check mount -t ffs ${BDEV} ${MNT}
+	atf_check touch ${MNT}/file
+	atf_check setextattr user testname testvalue ${MNT}/file
+	atf_check -o 'match:testvalue' getextattr user testname ${MNT}/file
+	atf_check umount ${MNT}
+
+	# Convert to disable extattrs.
+	atf_check -o 'match:CLEAR EXTATTR FIELDS' \
+		  -o 'match:DISABLING EXTATTR SUPPORT' \
+		  fsck_ffs -y -c no-ea ${CDEV}
+
+	# Verify that the test file does not have the test extattr.
+	atf_check -o ignore fsck -n ${CDEV}
+	atf_check mount -t ffs ${BDEV} ${MNT}
+	atf_check -s exit:1 -e 'match:getextattr: mnt/file: failed: Operation not supported' \
+		  getextattr user testname ${MNT}/file
+	atf_check umount ${MNT}
+
+	# Convert to enable extattrs again.
+	atf_check -o 'match:ENABLING EXTATTR SUPPORT' \
+		  fsck_ffs -y -c ea ${CDEV}
+
+	# Verify that the test extattr is still gone.
+	atf_check -o ignore fsck -n ${CDEV}
+	atf_check mount -t ffs ${BDEV} ${MNT}
+	atf_check -s exit:1 -e 'match:Attribute not found' \
+		  getextattr user testname ${MNT}/file
+	atf_check umount ${MNT}
+
+	atf_check vnconfig -u ${VND}
+}
+
+fsck_extattr_disable_cleanup()
+{
+	cleanup
+}
+
+atf_init_test_cases()
+{
+	atf_add_test_case fsck_extattr_enable
+	atf_add_test_case fsck_extattr_enable_corrupted
+	atf_add_test_case fsck_extattr_disable
+}

Reply via email to