Module Name:    src
Committed By:   perseant
Date:           Fri Jul 19 16:19:16 UTC 2024

Modified Files:
        src/sbin/fsck_exfatfs [perseant-exfatfs]: fsck_exfatfs.c pass0.c
            pass1.c pass2.c
        src/sbin/newfs_exfatfs [perseant-exfatfs]: make_exfatfs.c
        src/sys/fs/exfatfs [perseant-exfatfs]: TODO exfatfs.h exfatfs_balloc.c
            exfatfs_balloc.h exfatfs_extern.c exfatfs_inode.h exfatfs_vfsops.c
            exfatfs_vnops.c
        src/usr.sbin/dumpexfatfs [perseant-exfatfs]: dumpexfatfs.c

Log Message:
Use a logical block size if the cluster size or MAXPHYS, whichever is smaller.

Protext FreeClusterCount with mutex.

Do not always update the FAT chain, but convert from NoFatChain as needed.


To generate a diff of this commit:
cvs rdiff -u -r1.1.2.1 -r1.1.2.2 src/sbin/fsck_exfatfs/fsck_exfatfs.c \
    src/sbin/fsck_exfatfs/pass0.c
cvs rdiff -u -r1.1.2.2 -r1.1.2.3 src/sbin/fsck_exfatfs/pass1.c \
    src/sbin/fsck_exfatfs/pass2.c
cvs rdiff -u -r1.1.2.2 -r1.1.2.3 src/sbin/newfs_exfatfs/make_exfatfs.c
cvs rdiff -u -r1.1.2.2 -r1.1.2.3 src/sys/fs/exfatfs/TODO \
    src/sys/fs/exfatfs/exfatfs_balloc.c src/sys/fs/exfatfs/exfatfs_balloc.h
cvs rdiff -u -r1.1.2.4 -r1.1.2.5 src/sys/fs/exfatfs/exfatfs.h \
    src/sys/fs/exfatfs/exfatfs_extern.c
cvs rdiff -u -r1.1.2.3 -r1.1.2.4 src/sys/fs/exfatfs/exfatfs_inode.h \
    src/sys/fs/exfatfs/exfatfs_vfsops.c
cvs rdiff -u -r1.1.2.6 -r1.1.2.7 src/sys/fs/exfatfs/exfatfs_vnops.c
cvs rdiff -u -r1.1.2.3 -r1.1.2.4 src/usr.sbin/dumpexfatfs/dumpexfatfs.c

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

Modified files:

Index: src/sbin/fsck_exfatfs/fsck_exfatfs.c
diff -u src/sbin/fsck_exfatfs/fsck_exfatfs.c:1.1.2.1 src/sbin/fsck_exfatfs/fsck_exfatfs.c:1.1.2.2
--- src/sbin/fsck_exfatfs/fsck_exfatfs.c:1.1.2.1	Sat Jun 29 19:43:25 2024
+++ src/sbin/fsck_exfatfs/fsck_exfatfs.c	Fri Jul 19 16:19:16 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: fsck_exfatfs.c,v 1.1.2.1 2024/06/29 19:43:25 perseant Exp $	*/
+/*	$NetBSD: fsck_exfatfs.c,v 1.1.2.2 2024/07/19 16:19:16 perseant Exp $	*/
 
 /*-
  * Copyright (c) 1989, 1992, 1993
@@ -39,7 +39,7 @@ __COPYRIGHT("@(#) Copyright (c) 1989, 19
 #if 0
 static char sccsid[] = "@(#)newfs.c	8.5 (Berkeley) 5/24/95";
 #else
-__RCSID("$NetBSD: fsck_exfatfs.c,v 1.1.2.1 2024/06/29 19:43:25 perseant Exp $");
+__RCSID("$NetBSD: fsck_exfatfs.c,v 1.1.2.2 2024/07/19 16:19:16 perseant Exp $");
 #endif
 #endif /* not lint */
 
@@ -344,12 +344,12 @@ main(int argc, char **argv)
 			
 			/* Read the FAT to find the next cluster */
 			bread(fs->xf_devvp, EXFATFS_FATBLK(fs, clust),
-			      SECSIZE(fs), 0, &bp);
+			      FATBSIZE(fs), 0, &bp);
 			clust = ((uint32_t *)bp->b_data)
 				[EXFATFS_FATOFF(clust)];
 			brelse(bp, 0);
 			SET_DSE_DATALENGTH(xip, GET_DSE_DATALENGTH(xip)
-					   + CLUSTERSIZE(fs));
+					   + EXFATFS_CSIZE(fs));
 		}
 		SET_DSE_VALIDDATALENGTH(xip, GET_DSE_DATALENGTH(xip));
 
@@ -357,16 +357,16 @@ main(int argc, char **argv)
 
 		/* Set up bitmapvp */
 		exfatfs_bmap_shared(fs->xf_rootvp, 0, NULL, &bn, NULL);
-		bread(fs->xf_devvp, bn, SECSIZE(fs), 0, &bp);
+		bread(fs->xf_devvp, bn, EXFATFS_LSIZE(fs), 0, &bp);
 		dentp = dentp0 =
 			(struct exfatfs_dirent_allocation_bitmap *)bp->b_data;
-		endp = dentp + EXFATFS_FSSEC2DIRENT(fs, 1);
+		endp = dentp + EXFATFS_S2DIRENT(fs, 1);
 		while (dentp < endp) {
 			if (dentp->xd_entryType == XD_ENTRYTYPE_ALLOC_BITMAP
 			    || dentp->xd_entryType == XD_ENTRYTYPE_UPCASE_TABLE) {
 				/* Fake file entries */
 				xip = exfatfs_newxfinode(fs,
-							 EXFATFS_HWADDR2CLUSTER(fs, bp->b_blkno),
+							 EXFATFS_D2LC(fs, bp->b_blkno),
 							 dentp - dentp0);
 				xip->xi_direntp[0] = exfatfs_newdirent();
 				xip->xi_direntp[1] = exfatfs_newdirent();
@@ -389,7 +389,7 @@ main(int argc, char **argv)
 		if (debug)
 			fprintf(stderr, "bitmap file length %llu (%llu clusters)\n",
 				(long long)GET_DSE_DATALENGTH(VTOXI(fs->xf_bitmapvp)),
-				(long long)GET_DSE_DATALENGTH(VTOXI(fs->xf_bitmapvp)) / CLUSTERSIZE(fs));
+				(long long)EXFATFS_B2C(fs, GET_DSE_DATALENGTH(VTOXI(fs->xf_bitmapvp))));
 		while (clust != 0xFFFFFFFF) {
 			if (debug)
 				fprintf(stderr, "bitmap file cluster %d\n", clust);
@@ -399,7 +399,7 @@ main(int argc, char **argv)
 			
 			/* Read the FAT to find the next cluster */
 			bread(fs->xf_devvp, EXFATFS_FATBLK(fs, clust),
-			      SECSIZE(fs), 0, &bp);
+			      FATBSIZE(fs), 0, &bp);
 
 			oclust = clust;
 			clust = ((uint32_t *)bp->b_data)
@@ -425,7 +425,7 @@ main(int argc, char **argv)
 
 			/* Read the FAT to find the next cluster */
 			bread(fs->xf_devvp, EXFATFS_FATBLK(fs, clust),
-			      SECSIZE(fs), 0, &bp);
+			      FATBSIZE(fs), 0, &bp);
 			clust = ((uint32_t *)bp->b_data)
 				[EXFATFS_FATOFF(clust)];
 			brelse(bp, 0);
Index: src/sbin/fsck_exfatfs/pass0.c
diff -u src/sbin/fsck_exfatfs/pass0.c:1.1.2.1 src/sbin/fsck_exfatfs/pass0.c:1.1.2.2
--- src/sbin/fsck_exfatfs/pass0.c:1.1.2.1	Sat Jun 29 19:43:25 2024
+++ src/sbin/fsck_exfatfs/pass0.c	Fri Jul 19 16:19:16 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: pass0.c,v 1.1.2.1 2024/06/29 19:43:25 perseant Exp $	*/
+/*	$NetBSD: pass0.c,v 1.1.2.2 2024/07/19 16:19:16 perseant Exp $	*/
 
 /*-
  * Copyright (c) 2022 The NetBSD Foundation, Inc.
@@ -73,15 +73,15 @@ pass0(struct exfatfs *fs, struct dkwedge
 		/* Read boot sectors to compute checksum */
 		for (i = 0; i < 11; i++) {
 			int written = 0;
-			bread(fs->xf_devvp, base + i, SECSIZE(fs), 0, &bp);
+			bread(fs->xf_devvp, base + i, BSSIZE(fs), 0, &bp);
 
 			cksum = exfatfs_cksum32(cksum, (uint8_t *)bp->b_data,
-						SECSIZE(fs),
+						BSSIZE(fs),
 						boot_ignore,
 						(i == 0 ? boot_ignore_len : 0));
 			if (i > 0 && i < 9) {
 				if (*(uint32_t *)((char *)bp->b_data
-					      + SECSIZE(fs)
+					      + BSSIZE(fs)
 						  - sizeof(uint32_t))
 				    != htole32(0xAA550000)) {
 						pwarn("Extended boot sector %d magic number wrong\n",
@@ -90,7 +90,7 @@ pass0(struct exfatfs *fs, struct dkwedge
 							exit(1);
 						if (reply("fix") == 1) {
 							*(uint32_t *)((char *)bp->b_data
-								      + SECSIZE(fs)
+								      + BSSIZE(fs)
 								      - sizeof(uint32_t))
 								= htole32(0xAA550000);
 							bwrite(bp);
@@ -104,8 +104,8 @@ pass0(struct exfatfs *fs, struct dkwedge
 		}
 		
 		/* Compare boot block against recorded checksum */
-		bread(fs->xf_devvp, base + i, SECSIZE(fs), 0, &bp);
-		for (j = 0; j < SECSIZE(fs) / sizeof(uint32_t); j++) {
+		bread(fs->xf_devvp, base + i, BSSIZE(fs), 0, &bp);
+		for (j = 0; j < BSSIZE(fs) / sizeof(uint32_t); j++) {
 			if (((uint32_t *)bp->b_data)[j] != cksum) {
 				pwarn("Boot block %d checksum mismatch:"
 				      " word %d expected 0x%x computed 0x%x\n",
@@ -206,7 +206,7 @@ pass0(struct exfatfs *fs, struct dkwedge
 	}
 		
 	/* FatLength */
-	if (fs->xf_FatLength < howmany((fs->xf_ClusterCount + 2) * 4, SECSIZE(fs))) {
+	if (fs->xf_FatLength < howmany((fs->xf_ClusterCount + 2) * 4, FATBSIZE(fs))) {
 		pfatal("FatLength too small\n");
 		if (Pflag || reply("continue") == 0)
 			exit(1);

Index: src/sbin/fsck_exfatfs/pass1.c
diff -u src/sbin/fsck_exfatfs/pass1.c:1.1.2.2 src/sbin/fsck_exfatfs/pass1.c:1.1.2.3
--- src/sbin/fsck_exfatfs/pass1.c:1.1.2.2	Wed Jul  3 21:56:17 2024
+++ src/sbin/fsck_exfatfs/pass1.c	Fri Jul 19 16:19:16 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: pass1.c,v 1.1.2.2 2024/07/03 21:56:17 perseant Exp $	*/
+/*	$NetBSD: pass1.c,v 1.1.2.3 2024/07/19 16:19:16 perseant Exp $	*/
 
 /*-
  * Copyright (c) 2022 The NetBSD Foundation, Inc.
@@ -219,7 +219,7 @@ validfunc(void *arg, struct xfinode *xip
 	assert(xip->xi_serial == dserial);
 
 	/* Account bitmap blocks */
-	lcncount = howmany(GET_DSE_DATALENGTH(xip), CLUSTERSIZE(fs)); /* Not always a cluster multiple! */
+	lcncount = howmany(GET_DSE_DATALENGTH(xip), EXFATFS_CSIZE(fs)); /* Not always a cluster multiple! */
 	lcn = 0;
 	pcn = GET_DSE_FIRSTCLUSTER(xip);
 	while (lcn < lcncount) {
@@ -253,7 +253,7 @@ validfunc(void *arg, struct xfinode *xip
 			/* Follow the FAT chain */
 			error = bread(fs->xf_devvp,
 				      EXFATFS_FATBLK(fs, pcn),
-				      SECSIZE(fs), 0, &bp);
+				      FATBSIZE(fs), 0, &bp);
 			if (error) {
 				warn("File 0x%lx", (unsigned long)INUM(xip));
 				goto out;
Index: src/sbin/fsck_exfatfs/pass2.c
diff -u src/sbin/fsck_exfatfs/pass2.c:1.1.2.2 src/sbin/fsck_exfatfs/pass2.c:1.1.2.3
--- src/sbin/fsck_exfatfs/pass2.c:1.1.2.2	Wed Jul  3 21:56:17 2024
+++ src/sbin/fsck_exfatfs/pass2.c	Fri Jul 19 16:19:16 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: pass2.c,v 1.1.2.2 2024/07/03 21:56:17 perseant Exp $	*/
+/*	$NetBSD: pass2.c,v 1.1.2.3 2024/07/19 16:19:16 perseant Exp $	*/
 
 /*-
  * Copyright (c) 2022 The NetBSD Foundation, Inc.
@@ -57,7 +57,7 @@ pass2(struct exfatfs *fs, uint8_t *obser
 	uint32_t base, off;
 	struct buf *bp = NULL;
 	daddr_t lbn, endlbn;
-	size_t size = bitmap_discontiguous ? SECSIZE(fs) : MAXPHYS;
+	size_t size = bitmap_discontiguous ? EXFATFS_LSIZE(fs) : MAXPHYS;
 	int modified;
 	
 	if (!Pflag) {
@@ -66,10 +66,10 @@ pass2(struct exfatfs *fs, uint8_t *obser
 	
 	assert(fs->xf_bitmapvp != NULL);
 
-	endlbn = howmany(fs->xf_ClusterCount, SECSIZE(fs) * NBBY);
-	for (lbn = 0; lbn < endlbn; lbn += size / SECSIZE(fs)) {
-		if (size > (size_t) (endlbn - lbn) * SECSIZE(fs)) {
-			size = (endlbn - lbn) * SECSIZE(fs);
+	endlbn = howmany(fs->xf_ClusterCount, EXFATFS_LSIZE(fs) * NBBY);
+	for (lbn = 0; lbn < endlbn; lbn += size / EXFATFS_LSIZE(fs)) {
+		if (size > (size_t) (endlbn - lbn) * EXFATFS_LSIZE(fs)) {
+			size = (endlbn - lbn) * EXFATFS_LSIZE(fs);
 			if (debug)
 				pwarn("At lbn %lu, switch to block size %zd\n",
 					(unsigned long)lbn, size);
@@ -80,7 +80,7 @@ pass2(struct exfatfs *fs, uint8_t *obser
 		bread(fs->xf_bitmapvp, lbn, size, 0, &bp);
 
 		/* Check the quick way first */
-		base = lbn * SECSIZE(fs) * NBBY;
+		base = lbn * EXFATFS_LSIZE(fs) * NBBY;
 		if (memcmp(bp->b_data, observed_bitmap + base / NBBY, size) == 0) {
 			brelse(bp, 0);
 			continue;

Index: src/sbin/newfs_exfatfs/make_exfatfs.c
diff -u src/sbin/newfs_exfatfs/make_exfatfs.c:1.1.2.2 src/sbin/newfs_exfatfs/make_exfatfs.c:1.1.2.3
--- src/sbin/newfs_exfatfs/make_exfatfs.c:1.1.2.2	Wed Jul  3 21:56:17 2024
+++ src/sbin/newfs_exfatfs/make_exfatfs.c	Fri Jul 19 16:19:16 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: make_exfatfs.c,v 1.1.2.2 2024/07/03 21:56:17 perseant Exp $	*/
+/*	$NetBSD: make_exfatfs.c,v 1.1.2.3 2024/07/19 16:19:16 perseant Exp $	*/
 
 /*-
  * Copyright (c) 2022 The NetBSD Foundation, Inc.
@@ -62,7 +62,7 @@
 #if 0
 static char sccsid[] = "@(#)lfs.c	8.5 (Berkeley) 5/24/95";
 #else
-__RCSID("$NetBSD: make_exfatfs.c,v 1.1.2.2 2024/07/03 21:56:17 perseant Exp $");
+__RCSID("$NetBSD: make_exfatfs.c,v 1.1.2.3 2024/07/19 16:19:16 perseant Exp $");
 #endif
 #endif /* not lint */
 
@@ -602,7 +602,7 @@ make_exfatfs(int devfd, uint secsize, st
 	if (Vflag)
 		printf("First cluster of root directory: 0x%lx (byte 0x%llx)\n",
 		       (unsigned long)fs->xf_FirstClusterOfRootDirectory,
-		       (unsigned long long)EXFATFS_CLUSTER2HWADDR(fs, fs->xf_FirstClusterOfRootDirectory) * secsize);
+		       (unsigned long long)EXFATFS_LC2D(fs, fs->xf_FirstClusterOfRootDirectory) * secsize);
 	
 	/*
 	 * Prepare root directory entries.
@@ -633,7 +633,7 @@ make_exfatfs(int devfd, uint secsize, st
 
 	/* Size of bitmap data, in clusters */
 	bitmap_cluster_size = howmany(dirent_bitmap.xd_dataLength,
-				      CLUSTERSIZE(fs));
+				      EXFATFS_CSIZE(fs));
 	
 	/* Third root directory entry: Up-case Table */
 	/* This too has cluster data, like a file */
@@ -652,21 +652,21 @@ make_exfatfs(int devfd, uint secsize, st
 		       (unsigned long)dirent_upcase.xd_firstCluster);
 	/* Size of upcase table, in clusters */
 	upcase_cluster_size = howmany(dirent_upcase.xd_dataLength,
-				      CLUSTERSIZE(fs));
+				      EXFATFS_CSIZE(fs));
 
 	/*
 	 * Write the upcase table to disk.
 	 */
-	daddr = EXFATFS_CLUSTER2HWADDR(fs, dirent_upcase.xd_firstCluster);
+	daddr = EXFATFS_LC2D(fs, dirent_upcase.xd_firstCluster);
 	resid = sizeof(exfatfs_recommended_upcase_table_compressed);
-	for (i = 0; resid > 0; i += SECSIZE(fs), resid -= SECSIZE(fs)) {
+	for (i = 0; resid > 0; i += EXFATFS_LSIZE(fs), resid -= EXFATFS_LSIZE(fs)) {
 		if (!Nflag) {
-			bp = getblk(devvp, daddr, SECSIZE(fs));
- 			memset(bp->b_data, 0, SECSIZE(fs));
-			memcpy(bp->b_data, ((const char *)exfatfs_recommended_upcase_table_compressed) + i, MIN(SECSIZE(fs), resid));
+			bp = getblk(devvp, daddr, EXFATFS_LSIZE(fs));
+ 			memset(bp->b_data, 0, EXFATFS_LSIZE(fs));
+			memcpy(bp->b_data, ((const char *)exfatfs_recommended_upcase_table_compressed) + i, MIN(EXFATFS_LSIZE(fs), resid));
 			if (Vflag)
 				printf(" write upcase sector size %d at bn 0x%lx\n",
-		       			SECSIZE(fs), (unsigned long)bp->b_blkno);
+		       			EXFATFS_LSIZE(fs), (unsigned long)bp->b_blkno);
 			bwrite(bp);
 			++daddr;
 		}
@@ -680,20 +680,20 @@ make_exfatfs(int devfd, uint secsize, st
 	 */
 	if (!Nflag) {
 		start = dirent_bitmap.xd_firstCluster;
-		daddr = EXFATFS_CLUSTER2HWADDR(fs, start);
-		bp = getblk(devvp, daddr, SECSIZE(fs));
-		memset(bp->b_data, 0, SECSIZE(fs));
+		daddr = EXFATFS_LC2D(fs, start);
+		bp = getblk(devvp, daddr, EXFATFS_LSIZE(fs));
+		memset(bp->b_data, 0, EXFATFS_LSIZE(fs));
 
 		for (i = start; i <= fs->xf_FirstClusterOfRootDirectory; i++) {
-			if ((i - start) == NBBY * SECSIZE(fs)) {
+			if ((i - start) == NBBY * EXFATFS_LSIZE(fs)) {
 				if (Vflag)
 					printf(" write used bitmap sector size %d at bn 0x%lx\n",
-			       			SECSIZE(fs), (unsigned long)bp->b_blkno);
+			       			EXFATFS_LSIZE(fs), (unsigned long)bp->b_blkno);
 				bwrite(bp);
 				start = i;
 				++daddr;
-				bp = getblk(devvp, daddr, SECSIZE(fs));
-				memset(bp->b_data, 0, SECSIZE(fs));
+				bp = getblk(devvp, daddr, EXFATFS_LSIZE(fs));
+				memset(bp->b_data, 0, EXFATFS_LSIZE(fs));
 			}
 			bit = ((i - start) & (NBBY - 1));
 			byte = (i - start) / NBBY;
@@ -703,19 +703,18 @@ make_exfatfs(int devfd, uint secsize, st
 		}
 		if (Vflag)
 			printf(" write used bitmap sector size %d at bn 0x%lx\n",
-			       SECSIZE(fs), (unsigned long)bp->b_blkno);
+			       EXFATFS_LSIZE(fs), (unsigned long)bp->b_blkno);
 		bwrite(bp);
 	}
 
 	/* Now write blank pages for the rest of the bitmap */
 	progress = oprogress = 0;
-	// for (off = roundup(fs->xf_FirstClusterOfRootDirectory, NBBY * SECSIZE(fs)) / NBBY; off < (off_t)dirent_bitmap.xd_dataLength; off += SECSIZE(fs)) {
 	start = ++daddr;
-	end = EXFATFS_CLUSTER2HWADDR(fs, fs->xf_FirstClusterOfRootDirectory);
+	end = EXFATFS_LC2D(fs, fs->xf_FirstClusterOfRootDirectory);
 	for (daddr = start; daddr < end; ++daddr) {
 		if (!Nflag) {
-			size_t size = SECSIZE(fs);
-			if (daddr < EXFATFS_CLUSTER2HWADDR(fs, fs->xf_FirstClusterOfRootDirectory) - MAXPHYS / SECSIZE(fs))
+			size_t size = EXFATFS_LSIZE(fs);
+			if (daddr < EXFATFS_LC2D(fs, fs->xf_FirstClusterOfRootDirectory) - MAXPHYS / EXFATFS_LSIZE(fs))
 				size = MAXPHYS;
 			bp = getblk(devvp, daddr, size);
 			memset(bp->b_data, 0, size);
@@ -731,8 +730,8 @@ make_exfatfs(int devfd, uint secsize, st
 				oprogress = progress;
 			}
 			bwrite(bp);
-			if (size > (size_t)SECSIZE(fs))
-				daddr += size / SECSIZE(fs) - 1;
+			if (size > (size_t)EXFATFS_LSIZE(fs))
+				daddr += size / EXFATFS_LSIZE(fs) - 1;
 		}
 	}
 	if (!Vflag) {
@@ -743,11 +742,11 @@ make_exfatfs(int devfd, uint secsize, st
 	}
 
 	/* Write the root directory following the bitmap */
-	daddr = EXFATFS_CLUSTER2HWADDR(fs, fs->xf_FirstClusterOfRootDirectory);
+	daddr = EXFATFS_LC2D(fs, fs->xf_FirstClusterOfRootDirectory);
 	if (!Nflag) {
-		bp = getblk(devvp, daddr, SECSIZE(fs));
+		bp = getblk(devvp, daddr, EXFATFS_LSIZE(fs));
 		data = bp->b_data;
-		memset(data, 0, SECSIZE(fs));
+		memset(data, 0, EXFATFS_LSIZE(fs));
 		
 		memcpy(data, &dirent_label, sizeof(dirent_label));
 		data += sizeof(dirent_label);
@@ -766,11 +765,11 @@ make_exfatfs(int devfd, uint secsize, st
 	}
 
 	/* Fill the rest of the root directory cluster with zero */
-	for (++daddr; EXFATFS_HWADDR2CLUSTER(fs, daddr)
+	for (++daddr; EXFATFS_D2LC(fs, daddr)
 		     == fs->xf_FirstClusterOfRootDirectory; ++daddr) {
 		if (!Nflag) {
-			bp = getblk(devvp, daddr, SECSIZE(fs));
-			memset(bp->b_data, 0x00, SECSIZE(fs));
+			bp = getblk(devvp, daddr, EXFATFS_LSIZE(fs));
+			memset(bp->b_data, 0x00, EXFATFS_LSIZE(fs));
 			if (Vflag)
 				printf(" write zero root directory sector at bn 0x%lx\n",
 				       (unsigned long)bp->b_blkno);
@@ -782,27 +781,27 @@ make_exfatfs(int devfd, uint secsize, st
 	 * Write the FAT.
 	 */
 	progress = oprogress = 0;
-	end = howmany(fs->xf_ClusterCount, SECSIZE(fs) / sizeof(uint32_t));
+	end = howmany(fs->xf_ClusterCount, FATBSIZE(fs) / sizeof(uint32_t));
 	for (i = 0; i < end; ++i) {
 		if (!Nflag) {
 #if 1
 			size_t size = MAXPHYS;
-			if (size > (size_t)(end - i) * SECSIZE(fs)) {
-				size = (end - i) * SECSIZE(fs);
+			if (size > (size_t)(end - i) * FATBSIZE(fs)) {
+				size = (end - i) * FATBSIZE(fs);
 				/* printf(" reset size to %zd for i=%lld\n",
 					size, (long long)i); */
 			}
 #else
-			size_t size = SECSIZE(fs);
-			if (i >= (MAXPHYS / size) && howmany(fs->xf_ClusterCount, SECSIZE(fs) / sizeof(uint32_t)) - i > (MAXPHYS / size))
+			size_t size = FATBSIZE(fs);
+			if (i >= (MAXPHYS / size) && howmany(fs->xf_ClusterCount, FATBSIZE(fs) / sizeof(uint32_t)) - i > (MAXPHYS / size))
 				size = MAXPHYS;
 #endif
 			fatspersec = size / sizeof(uint32_t);
-			daddr = (i + fs->xf_FatOffset) * (SECSIZE(fs) / DEV_BSIZE);
+			daddr = (i + fs->xf_FatOffset) * (FATBSIZE(fs) / DEV_BSIZE);
 			bp = getblk(devvp, daddr, size);
 			memset(bp->b_data, 0, size);
 			for (j = 0; j < fatspersec; j++) {
-				uint32_t sec = i * (SECSIZE(fs) / sizeof(uint32_t)) + j;
+				uint32_t sec = i * (FATBSIZE(fs) / sizeof(uint32_t)) + j;
 				uint32_t v;
 				
 				if (sec == 0) {
@@ -831,8 +830,8 @@ make_exfatfs(int devfd, uint secsize, st
 				oprogress = progress;
 			}
 			bwrite(bp);
-			if (size > (size_t)SECSIZE(fs))
-				i += (size / SECSIZE(fs)) - 1;
+			if (size > (size_t)FATBSIZE(fs))
+				i += (size / FATBSIZE(fs)) - 1;
 		}
 	}
 	if (!Vflag) {
@@ -850,44 +849,44 @@ make_exfatfs(int devfd, uint secsize, st
 	if (!Nflag) {
 		for (base = 0; base < 24; base += 12) {
 			/* Write superblock to disk */
-			bp = getblk(devvp, base + 0, SECSIZE(fs));
+			bp = getblk(devvp, base + 0, BSSIZE(fs));
 			memcpy(bp->b_data, &fs->xf_exfatdfs, sizeof(fs->xf_exfatdfs));
 			cksum = exfatfs_cksum32(0, (uint8_t *)bp->b_data,
-						SECSIZE(fs), boot_ignore,
+						BSSIZE(fs), boot_ignore,
 						sizeof(boot_ignore));
 			if (Vflag)
 				printf(" write boot sector size %d at bn 0x%lx\n",
-		       			SECSIZE(fs), (unsigned long)bp->b_blkno);
+		       			BSSIZE(fs), (unsigned long)bp->b_blkno);
 			bwrite(bp);
 			
 			/* Write extended boot sectors */
 			for (i = 1; i < 9; i++) {
-				bp = getblk(devvp, base + i, SECSIZE(fs));
-				memset(bp->b_data, 0, SECSIZE(fs));
+				bp = getblk(devvp, base + i, BSSIZE(fs));
+				memset(bp->b_data, 0, BSSIZE(fs));
 				*(uint32_t *)((char *)bp->b_data
-					      + SECSIZE(fs)
+					      + BSSIZE(fs)
 					      - sizeof(uint32_t))
 					= htole32(0xAA550000);
 				cksum = exfatfs_cksum32(cksum,
 							(uint8_t *)bp->b_data,
-							SECSIZE(fs),
+							BSSIZE(fs),
 							NULL, 0);
 				if (Vflag)
 					printf(" write extended boot sector size %d at bn 0x%lx\n",
-		       				SECSIZE(fs), (unsigned long)bp->b_blkno);
+		       				BSSIZE(fs), (unsigned long)bp->b_blkno);
 				bwrite(bp);
 			}
 			
 			/* Checksum but do not write OEM and Reserved */
 			for (i = 9; i < 11; i++) {
-				bread(devvp, base + i, SECSIZE(fs), 0, &bp);
+				bread(devvp, base + i, BSSIZE(fs), 0, &bp);
 				cksum = exfatfs_cksum32(cksum,
 							(uint8_t *)bp->b_data,
-							SECSIZE(fs),
+							BSSIZE(fs),
 							NULL, 0);
 				if (Vflag)
 					printf(" write oem/reserved block size %d at bn 0x%lx\n",
-		       				SECSIZE(fs), (unsigned long)bp->b_blkno);
+		       				BSSIZE(fs), (unsigned long)bp->b_blkno);
 				brelse(bp, 0);
 			}
 
@@ -897,8 +896,8 @@ make_exfatfs(int devfd, uint secsize, st
 				       (unsigned long)(base + i));
 
 			/* Populate checksum block and write it */
-			bp = getblk(devvp, base + i, SECSIZE(fs));
-			for (j = 0; j < SECSIZE(fs) / sizeof(uint32_t); j++)
+			bp = getblk(devvp, base + i, BSSIZE(fs));
+			for (j = 0; j < BSSIZE(fs) / sizeof(uint32_t); j++)
 				((uint32_t *)bp->b_data)[j] = cksum;
 			bwrite(bp);
 		}

Index: src/sys/fs/exfatfs/TODO
diff -u src/sys/fs/exfatfs/TODO:1.1.2.2 src/sys/fs/exfatfs/TODO:1.1.2.3
--- src/sys/fs/exfatfs/TODO:1.1.2.2	Wed Jul  3 18:57:42 2024
+++ src/sys/fs/exfatfs/TODO	Fri Jul 19 16:19:15 2024
@@ -1,2 +1 @@
-* Convert IO size from disk sector size to MAXPHYS.
 * Use unions in directory entries instead of the cumbersome casting.
Index: src/sys/fs/exfatfs/exfatfs_balloc.c
diff -u src/sys/fs/exfatfs/exfatfs_balloc.c:1.1.2.2 src/sys/fs/exfatfs/exfatfs_balloc.c:1.1.2.3
--- src/sys/fs/exfatfs/exfatfs_balloc.c:1.1.2.2	Wed Jul  3 18:41:08 2024
+++ src/sys/fs/exfatfs/exfatfs_balloc.c	Fri Jul 19 16:19:15 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: exfatfs_balloc.c,v 1.1.2.2 2024/07/03 18:41:08 perseant Exp $	*/
+/*	$NetBSD: exfatfs_balloc.c,v 1.1.2.3 2024/07/19 16:19:15 perseant Exp $	*/
 
 /*-
  * Copyright (c) 2022, 2024 The NetBSD Foundation, Inc.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: exfatfs_balloc.c,v 1.1.2.2 2024/07/03 18:41:08 perseant Exp $");
+__KERNEL_RCSID(0, "$NetBSD: exfatfs_balloc.c,v 1.1.2.3 2024/07/19 16:19:15 perseant Exp $");
 
 #include <sys/types.h>
 #include <sys/buf.h>
@@ -129,7 +129,7 @@ exfatfs_bitmap_alloc(struct exfatfs *fs,
 					    NULL);
 			DPRINTF((" lbn %u -> bn 0x%x\n",
 				 (unsigned)lbn, (unsigned)blkno));
-			if ((error = bread(fs->xf_devvp, blkno, LBNSIZE(fs), 0,
+			if ((error = bread(fs->xf_devvp, blkno, EXFATFS_LSIZE(fs), 0,
 					   &bp)) != 0)
 				return error;
 			DPRINTF((" search %u..%u\n",
@@ -152,7 +152,13 @@ exfatfs_bitmap_alloc(struct exfatfs *fs,
 					 (unsigned)lbn, (int)off));
 				setbit(data, off);
 				bdwrite(bp);
+#ifdef _KERNEL
+				mutex_enter(&fs->xf_lock);
+#endif /* _KERNEL */
 				--fs->xf_FreeClusterCount;
+#ifdef _KERNEL
+				mutex_exit(&fs->xf_lock);
+#endif /* _KERNEL */
 				if (cp != NULL)
 					*cp = r;
 				return 0;
@@ -189,14 +195,21 @@ exfatfs_bitmap_dealloc(struct exfatfs *f
 	lbn = BITMAPLBN(fs, cno);
 	off = BITMAPOFF(fs, cno);
 	exfatfs_bmap_shared(fs->xf_bitmapvp, lbn, NULL, &blkno, NULL);
-	if ((error = bread(fs->xf_devvp, blkno, LBNSIZE(fs), 0, &bp)) != 0)
+	if ((error = bread(fs->xf_devvp, blkno, EXFATFS_LSIZE(fs), 0, &bp)) != 0)
 		return error;
 	data = (uint8_t *)bp->b_data;
 	DPRINTF(("basic deallocate cluster %u at lbn %u bit %d\n",
 		 (unsigned)cno, (unsigned)lbn, (int)off));
+	assert(isset(data, off));
 	clrbit(data, off);
 	bdwrite(bp);
+#ifdef _KERNEL
+	mutex_enter(&fs->xf_lock);
+#endif /* _KERNEL */
 	++fs->xf_FreeClusterCount;
+#ifdef _KERNEL
+	mutex_exit(&fs->xf_lock);
+#endif /* _KERNEL */
 	return 0;
 }
 
@@ -222,10 +235,10 @@ exfatfs_bitmap_init(struct exfatfs *fs)
 			lbn = BITMAPLBN(fs, cn);
 			exfatfs_bmap_shared(fs->xf_bitmapvp, lbn, NULL,
 					    &blkno, NULL);
-			bread(fs->xf_devvp, blkno, LBNSIZE(fs), 0, &bp);
+			bread(fs->xf_devvp, blkno, EXFATFS_LSIZE(fs), 0, &bp);
 			data = (uint8_t *)bp->b_data;
 		}
-		for (off = 0; off < LBNSIZE(fs) && cn < end; ++off) {
+		for (off = 0; off < EXFATFS_LSIZE(fs) && cn < end; ++off) {
 			if (cn >= end - NBBY) {
 				for (i = 0; i < NBBY && cn < end; i++) {
 					if (data[off] & (1 << i))
Index: src/sys/fs/exfatfs/exfatfs_balloc.h
diff -u src/sys/fs/exfatfs/exfatfs_balloc.h:1.1.2.2 src/sys/fs/exfatfs/exfatfs_balloc.h:1.1.2.3
--- src/sys/fs/exfatfs/exfatfs_balloc.h:1.1.2.2	Wed Jul  3 04:08:47 2024
+++ src/sys/fs/exfatfs/exfatfs_balloc.h	Fri Jul 19 16:19:15 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: exfatfs_balloc.h,v 1.1.2.2 2024/07/03 04:08:47 perseant Exp $ */
+/* $NetBSD: exfatfs_balloc.h,v 1.1.2.3 2024/07/19 16:19:15 perseant Exp $ */
 
 /*-
  * Copyright (c) 2022, 2024 The NetBSD Foundation, Inc.
@@ -31,15 +31,12 @@
 
 #include <fs/exfatfs/exfatfs.h>
 
-/* Convert cluster number to disk address and offset */
+/* Convert cluster number to logical block and offset in bitmap */
 #define NBBYSHIFT		3 /* 1 << NBBYSHIFT == NBBY == 8 */
-#define LBNSIZE(fs)		(1 << LBNSHIFT(fs))
-#define LBNSHIFT(fs)		MIN(MAXPSHIFT, ((fs)->xf_BytesPerSectorShift + \
-                                (fs)->xf_SectorsPerClusterShift))
-#define LBNOFF2CLUSTER(fs, lbn, off) ((lbn << BITMAPSHIFT(fs)) + (off) + 2)
-#define BITMAPSHIFT(fs)		(LBNSHIFT(fs) + NBBYSHIFT)
+#define BITMAPSHIFT(fs)		(EXFATFS_LSHIFT(fs) + NBBYSHIFT)
 #define BITMAPLBN(fs, cn)	(((cn) - 2) >> BITMAPSHIFT(fs))
 #define BITMAPOFF(fs, cn)	(((cn) - 2) & ((1 << BITMAPSHIFT(fs)) - 1))
+#define LBNOFF2CLUSTER(fs, lbn, off) ((lbn << BITMAPSHIFT(fs)) + (off) + 2)
 #define INVALID			(~(uint32_t)0)
 
 int exfatfs_bitmap_init(struct exfatfs *);

Index: src/sys/fs/exfatfs/exfatfs.h
diff -u src/sys/fs/exfatfs/exfatfs.h:1.1.2.4 src/sys/fs/exfatfs/exfatfs.h:1.1.2.5
--- src/sys/fs/exfatfs/exfatfs.h:1.1.2.4	Wed Jul  3 04:08:47 2024
+++ src/sys/fs/exfatfs/exfatfs.h	Fri Jul 19 16:19:15 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: exfatfs.h,v 1.1.2.4 2024/07/03 04:08:47 perseant Exp $ */
+/* $NetBSD: exfatfs.h,v 1.1.2.5 2024/07/19 16:19:15 perseant Exp $ */
 
 /*-
  * Copyright (c) 2022, 2024 The NetBSD Foundation, Inc.
@@ -164,81 +164,103 @@ struct exfatfs_args {
 #define EXFATFS_LABELMAX 11
 #define EXFATFS_NAMEMAX 255
 
+/* A shift corresponding to MAXPHYS */
+#define MAXPSHIFT 16
+#define MAXPSIZE (1 << MAXPSHIFT)
+
+/*
+ * Units conversions between clusters, logical blocks, filesystem sectors
+ * and DEV_BSIZE.
+ */
+
+/* Convert between bytes and the basic three types */
+#define EXFATFS_CSHIFT(fs) ((fs)->xf_BytesPerSectorShift			\
+			+ (fs)->xf_SectorsPerClusterShift)
+#define EXFATFS_CSIZE(fs) (1 << EXFATFS_CSHIFT(fs))
+#define EXFATFS_CMASK(fs) (EXFATFS_CSIZE(fs) - 1)
+
+#define EXFATFS_LSHIFT(fs) MIN(MAXPSHIFT, EXFATFS_CSHIFT(fs))
+#define EXFATFS_LSIZE(fs)  (1 << EXFATFS_LSHIFT(fs))
+#define EXFATFS_LMASK(fs)  (EXFATFS_LSIZE(fs) - 1)
+
+#define EXFATFS_SSHIFT(fs) ((fs)->xf_BytesPerSectorShift)
+#define EXFATFS_SSIZE(fs) (1 << EXFATFS_SSHIFT(fs))
+#define EXFATFS_SMASK(fs) (EXFATFS_SSIZE(fs) - 1)
+
 /* Base shift from bytes to sizeof(struct dirent) */
-#define EXFATFS_DIRENT_BASESHIFT 5
-#define EXFATFS_BYTES2DIRENT(fs, e) ((e) >> EXFATFS_DIRENT_BASESHIFT)
-#define EXFATFS_DIRENT2BYTES(fs, e) ((e) << EXFATFS_DIRENT_BASESHIFT)
-
-/* Convert from sizeof(dirent) to cluster */
-#define EXFATFS_DIRENT_SHIFT(fs) ((fs)->xf_BytesPerSectorShift + \
-	(fs)->xf_SectorsPerClusterShift - EXFATFS_DIRENT_BASESHIFT)
-
-#define EXFATFS_DIRENT2DEVBSIZE(fs, e) ((e) >> (DEV_BSHIFT - \
-					EXFATFS_DIRENT_BASESHIFT))
-#define EXFATFS_DEVBSIZE2DIRENT(fs, e) ((e) << (DEV_BSHIFT \
-						- EXFATFS_DIRENT_BASESHIFT))
-#define EXFATFS_DIRENT2FSSEC(fs, e) ((e) >> (fs->xf_BytesPerSectorShift \
-						- EXFATFS_DIRENT_BASESHIFT))
-#define EXFATFS_FSSEC2DIRENT(fs, sec) ((sec) << (fs->xf_BytesPerSectorShift \
-						- EXFATFS_DIRENT_BASESHIFT))
-
-/* If we have an entry number we may need to convert it to lbn and offset */
-#define EXFATFS_DIRENT2ENTRY(fs, e) EXFATFS_BYTES2DIRENT((fs), \
-			(EXFATFS_DIRENT2BYTES((fs), (e)) & SECMASK(fs)))
-
-#define EXFATFS_CLUST_ENTRY2INO(fs, clust, entry) ((((uint64_t)clust) \
-				<< EXFATFS_DIRENT_SHIFT(fs)) | (entry))
-#define EXFATFS_HWADDR_ENTRY2INO(fs, bn, entry) ((EXFATFS_HWADDR2CLUSTER((fs),\
-			 (bn)) << EXFATFS_DIRENT_SHIFT(fs)) | (entry))
-#define INO2CLUST(ino) ((ino) >> EXFATFS_DIRENT_SHIFT(fs))
-#define INO2ENTRY(ino) ((ino) & ((1 << EXFATFS_DIRENT_SHIFT(fs)) - 1))
+#define EXFATFS_DIRENT_SHIFT 5
+
+/* Convert from bytes to each */
+#define EXFATFS_B2C(fs, n)      ((n) >> EXFATFS_CSHIFT(fs))
+#define EXFATFS_B2L(fs, n)      ((n) >> EXFATFS_LSHIFT(fs))
+#define EXFATFS_B2S(fs, n)      ((n) >> EXFATFS_SSHIFT(fs))
+#define EXFATFS_B2D(fs, n)      ((n) >> DEV_BSHIFT)
+#define EXFATFS_B2DIRENT(fs, n) ((n) >> EXFATFS_DIRENT_SHIFT)
+
+/* Convert from sizeof(dirent) to each */
+#define EXFATFS_DIRENT2C(fs, n) ((n) >> (EXFATFS_CSHIFT(fs) - EXFATFS_DIRENT_SHIFT))
+#define EXFATFS_DIRENT2L(fs, n) ((n) >> (EXFATFS_LSHIFT(fs) - EXFATFS_DIRENT_SHIFT))
+#define EXFATFS_DIRENT2S(fs, n) ((n) >> (EXFATFS_SSHIFT(fs) - EXFATFS_DIRENT_SHIFT))
+#define EXFATFS_DIRENT2D(fs, n) ((n) >> (DEV_BSHIFT - EXFATFS_DIRENT_SHIFT))
+#define EXFATFS_DIRENT2B(fs, n) ((n) << EXFATFS_DIRENT_SHIFT)
+
+/* Convert from DEV_BSIZE to each */
+#define EXFATFS_D2C(fs, n)      ((n) >> (EXFATFS_CSHIFT(fs) - DEV_BSHIFT))
+#define EXFATFS_D2L(fs, n)      ((n) >> (EXFATFS_LSHIFT(fs) - DEV_BSHIFT))
+#define EXFATFS_D2S(fs, n)      ((n) >> (EXFATFS_SSHIFT(fs) - DEV_BSHIFT))
+#define EXFATFS_D2DIRENT(fs, n) ((n) << (DEV_BSHIFT - EXFATFS_DIRENT_SHIFT))
+#define EXFATFS_D2B(fs, n)      ((n) << DEV_BSHIFT)
+
+/* Convert from filesystem sectors to each */
+#define EXFATFS_S2C(fs, n)      ((n) >> (EXFATFS_CSHIFT(fs) - EXFATFS_SSHIFT(fs)))
+#define EXFATFS_S2L(fs, n)      ((n) >> (EXFATFS_LSHIFT(fs) - EXFATFS_SSHIFT(fs)))
+#define EXFATFS_S2D(fs, n)      ((n) << (EXFATFS_SSHIFT(fs) - DEV_BSHIFT))
+#define EXFATFS_S2DIRENT(fs, n) ((n) << (EXFATFS_SSHIFT(fs) - EXFATFS_DIRENT_SHIFT))
+#define EXFATFS_S2B(fs, n)      ((n) << EXFATFS_SSHIFT(fs))
+
+/* Convert from logical blocks to each */
+#define EXFATFS_L2C(fs, n)      ((n) >> (EXFATFS_CSHIFT(fs) - EXFATFS_LSHIFT(fs)))
+#define EXFATFS_L2S(fs, n)      ((n) << (EXFATFS_LSHIFT(fs) - EXFATFS_SSHIFT(fs)))
+#define EXFATFS_L2D(fs, n)      ((n) << (EXFATFS_LSHIFT(fs) - DEV_BSHIFT))
+#define EXFATFS_L2DIRENT(fs, n) ((n) << (EXFATFS_LSHIFT(fs) - EXFATFS_DIRENT_SHIFT))
+#define EXFATFS_L2B(fs, n)      ((n) << EXFATFS_LSHIFT(fs))
+
+/* Convert between clusters and each */
+#define EXFATFS_C2L(fs, n)      ((n) << (EXFATFS_CSHIFT(fs) - EXFATFS_LSHIFT(fs)))
+#define EXFATFS_C2S(fs, n)      ((n) << (EXFATFS_CSHIFT(fs) - EXFATFS_SSHIFT(fs)))
+#define EXFATFS_C2D(fs, n)      ((n) << (EXFATFS_CSHIFT(fs) - DEV_BSHIFT))
+#define EXFATFS_C2DIRENT(fs, n) ((n) << (EXFATFS_CSHIFT(fs) - EXFATFS_DIRENT_SHIFT))
+#define EXFATFS_C2B(fs, n)      ((n) << EXFATFS_CSHIFT(fs))
+
+/* Cluster / DEV_BSIZE mask */
+#define EXFATFS_DCMASK(fs) (EXFATFS_C2D((fs), 1) - 1)
+
+/* Size of boot sectors */
+#define BSSHIFT(fs) EXFATFS_SSHIFT(fs)
+#define BSSIZE(fs)  EXFATFS_SSIZE(fs)
+#define BSMASK(fs)  EXFATFS_SMASK(fs)
+
+/* Size of FAT blocks */
+#define FATBSHIFT(fs) EXFATFS_SSHIFT(fs)
+#define FATBSIZE(fs)  EXFATFS_SSIZE(fs)
+#define FATBMASK(fs)  EXFATFS_SMASK(fs)
+
+/* Inode numbers are coded as (cluster, entry #) pairs */
+#define INO2CLUST(ino) EXFATFS_DIRENT2C(fs, ino)
+#define INO2ENTRY(ino) ((ino) & ((EXFATFS_C2DIRENT(fs, 1)) - 1))
+#define CE2INO(fs, c, e)   (EXFATFS_C2DIRENT(fs, (c)) | (e))
+
 #define ROOTDIRCLUST 1
 #define ROOTDIRENTRY 1
-#define ROOTINO(fs) EXFATFS_CLUST_ENTRY2INO((fs), ROOTDIRCLUST, ROOTDIRENTRY)
+#define ROOTINO(fs) CE2INO((fs), ROOTDIRCLUST, ROOTDIRENTRY)
 
 /*
- * Units conversions between clusters, filesystem sectors and DEV_BSIZE.
+ * Convert between a logical cluster number and its physical location on disk,
+ * in DEV_BSIZE units.
  */
-#define EXFATFS_FSSEC2DEVBSIZE(fs, bn) ((bn) << ((fs)->xf_BytesPerSectorShift \
-							- DEV_BSHIFT))
-#define EXFATFS_DEVBSIZE2FSSEC(fs, bn) ((bn) >> ((fs)->xf_BytesPerSectorShift \
-							- DEV_BSHIFT))
-#define EXFATFS_BYTES2CLUSTER(fs, n) ((n) >> ((fs)->xf_BytesPerSectorShift \
-					+ (fs)->xf_SectorsPerClusterShift))
-#define EXFATFS_BYTES2FSSEC(fs, n) ((n) >> ((fs)->xf_BytesPerSectorShift))
-#define EXFATFS_FSSEC2BYTES(fs, n) ((n) << ((fs)->xf_BytesPerSectorShift))
-#define EXFATFS_CLUSTER2BYTES(fs, cn) ((cn) << ((fs)->xf_BytesPerSectorShift \
-					+ (fs)->xf_SectorsPerClusterShift))
-#define EXFATFS_CLUSTER2DEVBSIZE(fs, cn) ((cn) << ((fs)->xf_BytesPerSectorShift\
-			 + (fs)->xf_SectorsPerClusterShift - DEV_BSHIFT))
-#define EXFATFS_DEVBSIZE2CLUSTER(fs, bn) ((bn) >> ((fs)->xf_BytesPerSectorShift\
-			 + (fs)->xf_SectorsPerClusterShift - DEV_BSHIFT))
-#define EXFATFS_CLUSTER2FSSEC(fs, clust) ((clust) << 			\
-			(fs)->xf_SectorsPerClusterShift)
-#define EXFATFS_FSSEC2CLUSTER(fs, lbn)   ((lbn) >> 			\
-			(fs)->xf_SectorsPerClusterShift)
-#define SECSIZE(fs) (1 << (fs)->xf_BytesPerSectorShift)
-#define SECMASK(fs) (SECSIZE(fs) - 1)
-
-#define CLUSTERSHIFT(fs)	((fs)->xf_BytesPerSectorShift + 	\
-				 (fs)->xf_SectorsPerClusterShift)
-#define CLUSTERSIZE(fs) (1 << CLUSTERSHIFT(fs))
-#define CLUSTERMASK(fs) (CLUSTERSIZE(fs) - 1)
-
-/* The unit in which I/O is performed */
-#define MAXPSHIFT 16
-#define MAXPSIZE (1 << MAXPSHIFT)	/* Must be <= MAXPHYS */
-#define IOSHIFT(fs) MIN(CLUSTERSHIFT(fs), MAXPSHIFT)
-#define IOSIZE(fs) MIN(CLUSTERSIZE(fs), MAXPSIZE)
-#define IOMASK(fs) (IOSIZE(fs) - 1)
-
-#define EXFATFS_CLUSTER2HWADDR(fs, clust) (EXFATFS_CLUSTER2FSSEC((fs),	\
-				(clust) - 2) + (fs)->xf_ClusterHeapOffset)
-#define EXFATFS_HWADDR2CLUSTER(fs, bn) (EXFATFS_FSSEC2CLUSTER((fs), (bn) \
-				- (fs)->xf_ClusterHeapOffset) + 2)
-/* The offset of this block relative to start of cluster, in dirent units */
-#define EXFATFS_HWADDR2DIRENT(fs, bn) EXFATFS_DEVBSIZE2DIRENT((fs),	\
-	((bn) - EXFATFS_CLUSTER2HWADDR((fs), 				\
-		EXFATFS_HWADDR2CLUSTER((fs), (bn)))))
+#define EXFATFS_LC2D(fs, c) (EXFATFS_C2D((fs), (c) - 2) + (fs)->xf_ClusterHeapOffset) /* EXFATFS_CLUSTER2HWADDR */
+#define EXFATFS_D2LC(fs, bn) (EXFATFS_D2C((fs), (bn) - (fs)->xf_ClusterHeapOffset) + 2) /* EXFATFS_HWADDR2CLUSTER */
+/* The offset of this DEV_BSIZE block relative to start of cluster, in dirent units */
+#define EXFATFS_DCLOFF_DIRENT(fs, bn) EXFATFS_D2DIRENT((fs), ((bn) - EXFATFS_C2D((fs), EXFATFS_D2C((fs), (bn))))) /* EXFATFS_HWADDR2DIRENT */
 
 #endif /* FS_EXFATFS_EXFATFS_H_ */
Index: src/sys/fs/exfatfs/exfatfs_extern.c
diff -u src/sys/fs/exfatfs/exfatfs_extern.c:1.1.2.4 src/sys/fs/exfatfs/exfatfs_extern.c:1.1.2.5
--- src/sys/fs/exfatfs/exfatfs_extern.c:1.1.2.4	Wed Jul  3 18:57:42 2024
+++ src/sys/fs/exfatfs/exfatfs_extern.c	Fri Jul 19 16:19:15 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: exfatfs_extern.c,v 1.1.2.4 2024/07/03 18:57:42 perseant Exp $	*/
+/*	$NetBSD: exfatfs_extern.c,v 1.1.2.5 2024/07/19 16:19:15 perseant Exp $	*/
 
 /*-
  * Copyright (c) 2022 The NetBSD Foundation, Inc.
@@ -88,11 +88,8 @@ static int checkzero(void *p, int len);
 static unsigned long serial;
 
 /*
- * Convert a logical address, in SECSIZE units, into a hardware
+ * Convert a logical address, in EXFATFS_LSIZE units, into a hardware
  * address, in DEV_BSIZE units.
- * XXX SECSIZE is too small, while CLUSTERSIZE is too big.
- * XXX We should probably use something like MIN(CLUSTERSIZE, MAXPHYS),
- * XXX and convert units when necessary.
  */
 int
 exfatfs_bmap_shared(struct vnode *vp, daddr_t targetlbn, struct vnode **vpp,
@@ -101,7 +98,7 @@ exfatfs_bmap_shared(struct vnode *vp, da
 	struct xfinode *xip;
 	struct exfatfs *fs;
 	struct buf *bp;
-	daddr_t pcn, targetcn;
+	daddr_t pcn, targetlcn;
 	uint32_t lcn;
 	int error, run = 0;
 	unsigned c;
@@ -132,8 +129,8 @@ exfatfs_bmap_shared(struct vnode *vp, da
 	/* If we can't find it, return -1 */
 	*bnp = (daddr_t)-1;
 
-	if (EXFATFS_FSSEC2CLUSTER(fs, (unsigned long)targetlbn) >
-	    EXFATFS_BYTES2CLUSTER(fs, GET_DSE_DATALENGTH_BLK(xip, fs))) {
+	if (EXFATFS_L2C(fs, (unsigned long)targetlbn) >
+	    howmany(GET_DSE_DATALENGTH(xip), EXFATFS_CSIZE(fs))) {
 		exfatfs_check_fence(fs);
 		return 0;
 	}
@@ -143,11 +140,10 @@ exfatfs_bmap_shared(struct vnode *vp, da
 	 * address using dead reckoning from the first cluster.
 	 */
 	if (IS_DSE_NOFATCHAIN(xip)) {
-		*bnp = EXFATFS_CLUSTER2HWADDR(fs, GET_DSE_FIRSTCLUSTER(xip))
-			+ EXFATFS_FSSEC2DEVBSIZE(fs, targetlbn);
+		*bnp = EXFATFS_LC2D(fs, GET_DSE_FIRSTCLUSTER(xip))
+			+ EXFATFS_L2D(fs, targetlbn);
 		if (runp) {
-			*runp = EXFATFS_BYTES2FSSEC(fs,
-					GET_DSE_DATALENGTH_BLK(xip, fs))
+			*runp = howmany(GET_DSE_DATALENGTH(xip), EXFATFS_LSIZE(fs))
 				- targetlbn;
 		}
 		return 0;
@@ -157,11 +153,11 @@ exfatfs_bmap_shared(struct vnode *vp, da
 	 * Walk the FAT chain until we reach the address of interest
 	 * By default we start from zero
 	 */
-	targetcn = EXFATFS_FSSEC2CLUSTER(fs, targetlbn);
-	assert(targetcn < fs->xf_ClusterCount);
-	DPRINTF(("BMAP targetlbn=%lu targetcn=%lu\n",
+	targetlcn = EXFATFS_L2C(fs, targetlbn);
+	assert(targetlcn < fs->xf_ClusterCount);
+	DPRINTF(("BMAP targetlbn=%lu targetlcn=%lu\n",
 		 (unsigned long)targetlbn,
-		 (unsigned long)targetcn));
+		 (unsigned long)targetlcn));
 	pcn = GET_DSE_FIRSTCLUSTER(xip);
 	lcn = 0;
 
@@ -187,7 +183,7 @@ exfatfs_bmap_shared(struct vnode *vp, da
 	
 	/* If we have a value cached, start there instead */
 #ifdef USE_FATCACHE
-	if (xip->xi_fatcache_lc > 0 && xip->xi_fatcache_lc < targetcn) {
+	if (xip->xi_fatcache_lc > 0 && xip->xi_fatcache_lc < targetlcn) {
 		lcn = xip->xi_fatcache_lc;
 		pcn = xip->xi_fatcache_pc;
 		assert(pcn >= 2 && pcn < fs->xf_ClusterCount + 2);
@@ -199,14 +195,14 @@ exfatfs_bmap_shared(struct vnode *vp, da
 	assert(fs->xf_devvp != NULL);
 	assert(pcn >= 2 && pcn < fs->xf_ClusterCount + 2);
 	c = 0;
-	while (targetcn != lcn) {
+	while (targetlcn > lcn) {
 		if (pcn < 2 || pcn >= fs->xf_ClusterCount + 2) {
 			printf("Cluster 0x%x out of bounds!\n", (unsigned)pcn);
 		}
 		assert(pcn >= 2 && pcn < fs->xf_ClusterCount + 2);
 		/* Read the FAT to find the next cluster */
 		if ((error = bread(fs->xf_devvp, EXFATFS_FATBLK(fs, pcn),
-					SECSIZE(fs), 0, &bp)) != 0) {
+					FATBSIZE(fs), 0, &bp)) != 0) {
 			printf("failed to read FAT pcn %u block 0x%x\n",
 			       (unsigned)pcn, (unsigned)EXFATFS_FATBLK(fs, pcn));
 			goto errout;
@@ -220,7 +216,7 @@ exfatfs_bmap_shared(struct vnode *vp, da
 		assert(++c <= fs->xf_ClusterCount);
 	}
 
-	if (targetcn != lcn) {
+	if (targetlcn != lcn) {
 		/* Not found */
 		*bnp = -1;
 		if (runp)
@@ -236,14 +232,13 @@ exfatfs_bmap_shared(struct vnode *vp, da
 		exfatfs_check_fence(fs);
 		return EIO;
 	}
-	xip->xi_fatcache_lc = targetcn;
+	xip->xi_fatcache_lc = targetlcn;
 	xip->xi_fatcache_pc = pcn;
-	*bnp = EXFATFS_CLUSTER2HWADDR(fs, pcn)
-		+ EXFATFS_FSSEC2DEVBSIZE(fs, (targetlbn
-			      & ((1 << fs->xf_SectorsPerClusterShift) - 1)));
+	*bnp = EXFATFS_LC2D(fs, pcn)
+		+ EXFATFS_L2D(fs, targetlbn - EXFATFS_C2L(fs, targetlcn));
 
 	/* If we found it, hint the rest of the cluster. */
-	run = EXFATFS_CLUSTER2FSSEC(fs, targetcn + 1) - targetlbn - 1;
+	run = EXFATFS_C2L(fs, targetlcn + 1) - targetlbn - 1;
 	if (runp && *bnp != (daddr_t)-1) {
 		*runp = run;
 	}
@@ -252,7 +247,7 @@ exfatfs_bmap_shared(struct vnode *vp, da
 		 (int)lcn, (unsigned long)pcn,
 		 (int)targetlbn, (int)(targetlbn + run),
 		 (unsigned long)*bnp,
-		 (unsigned long)(*bnp + EXFATFS_FSSEC2DEVBSIZE(fs, run))));
+		 (unsigned long)(*bnp + EXFATFS_L2D(fs, run))));
 errout:
 	exfatfs_check_fence(fs);
 	return error;
@@ -493,15 +488,15 @@ read_rootdir (struct exfatfs *fs)
 	int i;
 	struct buf *bp;
 	uint32_t clust = fs->xf_FirstClusterOfRootDirectory;
-	daddr_t daddr = EXFATFS_CLUSTER2HWADDR(fs, clust);
+	daddr_t daddr = EXFATFS_LC2D(fs, clust);
 	
 	exfatfs_check_fence(fs);
 	/* Print root directory contents */
-	bread(fs->xf_devvp, daddr, SECSIZE(fs), 0, &bp);
+	bread(fs->xf_devvp, daddr, EXFATFS_LSIZE(fs), 0, &bp);
 	data = (uint8_t *)bp->b_data;
 	
-	for (i = 0; i * 32 < SECSIZE(fs); i++) {
-		dp = data + i * 32;
+	for (i = 0; i * sizeof(struct exfatfs_dirent) < (size_t)EXFATFS_LSIZE(fs); i++) {
+		dp = data + i * sizeof(struct exfatfs_dirent);
 
 		switch (dp[0]) {
 		case XD_ENTRYTYPE_EOD:
@@ -521,7 +516,7 @@ read_rootdir (struct exfatfs *fs)
 						 xdab->xd_firstCluster,
 						 xdab->xd_dataLength,
 						 &fs->xf_bitmapvp);
-			bread(fs->xf_devvp, daddr, SECSIZE(fs), 0, &bp);
+			bread(fs->xf_devvp, daddr, EXFATFS_LSIZE(fs), 0, &bp);
 			data = (uint8_t *)bp->b_data;
 			break;
 
@@ -533,7 +528,7 @@ read_rootdir (struct exfatfs *fs)
 						 xdut->xd_firstCluster,
 						 xdut->xd_dataLength,
 						 &fs->xf_upcasevp);
-			bread(fs->xf_devvp, daddr, SECSIZE(fs), 0, &bp);
+			bread(fs->xf_devvp, daddr, EXFATFS_LSIZE(fs), 0, &bp);
 			data = (uint8_t *)bp->b_data;
 			break;
 
@@ -799,20 +794,20 @@ exfatfs_scandir(struct vnode *dvp,
 	entryno = 0;
 	invstart = -1;
 	have_primary = 0;
-	off = EXFATFS_BYTES2DIRENT(fs, startoff);
-	lbn = EXFATFS_BYTES2FSSEC(fs, startoff);
-	maxlbn = howmany(GET_DSE_VALIDDATALENGTH(dxip), SECSIZE(fs));
+	off = EXFATFS_B2DIRENT(fs, startoff);
+	lbn = EXFATFS_B2L(fs, startoff);
+	maxlbn = howmany(GET_DSE_VALIDDATALENGTH(dxip), EXFATFS_LSIZE(fs));
 	while(lbn < maxlbn) {
 		exfatfs_bmap_shared(dvp, lbn, NULL, &blkno, NULL);
-		error = bread(fs->xf_devvp, blkno, SECSIZE(fs), 0, &bp);
+		error = bread(fs->xf_devvp, blkno, EXFATFS_LSIZE(fs), 0, &bp);
 		if (error)
 			goto out;
 
 		assert(dxip->xi_serial == dserial);
 		data = bp->b_data;
 		dentp0 = (struct exfatfs_dirent *)data;
-		dentp = dentp0 + (off & (EXFATFS_FSSEC2DIRENT(fs, 1) - 1));
-		endp = dentp0 + EXFATFS_FSSEC2DIRENT(fs, 1);
+		dentp = dentp0 + (off & (EXFATFS_L2DIRENT(fs, 1) - 1));
+		endp = dentp0 + EXFATFS_L2DIRENT(fs, 1);
 		while (dentp < endp) {
 			if (ISPRIMARY(dentp))
 				have_primary = 1;
@@ -885,8 +880,8 @@ exfatfs_scandir(struct vnode *dvp,
 			case XD_ENTRYTYPE_FILE:
 				/* Construct key from buffer and offset */
 				memset(&xip->xi_key, 0, sizeof(xip->xi_key));
-				xip->xi_dirclust = EXFATFS_HWADDR2CLUSTER(fs, xip->xi_dirent_blk[0]);
-				xip->xi_diroffset = EXFATFS_HWADDR2DIRENT(fs, xip->xi_dirent_blk[0]) +
+				xip->xi_dirclust = EXFATFS_D2LC(fs, xip->xi_dirent_blk[0]);
+				xip->xi_diroffset = EXFATFS_DCLOFF_DIRENT(fs, xip->xi_dirent_blk[0]) +
 					xip->xi_dirent_off[0];
 				break;
 				
@@ -940,7 +935,7 @@ exfatfs_scandir(struct vnode *dvp,
 					assert(dxip->xi_serial == dserial);
 					if (validfunc != NULL) {
 						flags = (*validfunc)(arg, xip,
-						 EXFATFS_DIRENT2BYTES(fs, off));
+						 EXFATFS_DIRENT2B(fs, off));
 						assert(dxip->xi_serial
 							== dserial);
 						if (flags & SCANDIR_DONTFREE) {
@@ -991,7 +986,7 @@ out:
 	if (bp != NULL)
 		brelse(bp, 0);
 	if (endoff != NULL)
-		*endoff = EXFATFS_DIRENT2BYTES(fs, off);
+		*endoff = EXFATFS_DIRENT2B(fs, off);
 	return error;
 }
 

Index: src/sys/fs/exfatfs/exfatfs_inode.h
diff -u src/sys/fs/exfatfs/exfatfs_inode.h:1.1.2.3 src/sys/fs/exfatfs/exfatfs_inode.h:1.1.2.4
--- src/sys/fs/exfatfs/exfatfs_inode.h:1.1.2.3	Wed Jul  3 18:57:42 2024
+++ src/sys/fs/exfatfs/exfatfs_inode.h	Fri Jul 19 16:19:15 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: exfatfs_inode.h,v 1.1.2.3 2024/07/03 18:57:42 perseant Exp $	*/
+/*	$NetBSD: exfatfs_inode.h,v 1.1.2.4 2024/07/19 16:19:15 perseant Exp $	*/
 
 /*-
  * Copyright (c) 2022, 2024 The NetBSD Foundation, Inc.
@@ -226,7 +226,7 @@ do {									\
 #define GET_DSE_FIRSTCLUSTER(xip)    DSE(xip)->xd_firstCluster
 #define GET_DSE_DATALENGTH(xip)      DSE(xip)->xd_dataLength
 #define GET_DSE_DATALENGTH_BLK(xip, fs) roundup2(DSE(xip)->xd_dataLength, \
-						CLUSTERSIZE(fs))
+						EXFATFS_CSIZE(fs))
 
 #define SET_DSE_NAMELENGTH(xip, v)					\
 do {									\
@@ -325,7 +325,7 @@ void exfatfs_check_fence(struct exfatfs 
 # define exfatfs_check_fence(fs)
 #endif
 
-#define INUM(xip) EXFATFS_CLUST_ENTRY2INO((xip)->xi_fs, (xip)->xi_dirclust, \
+#define INUM(xip) CE2INO((xip)->xi_fs, (xip)->xi_dirclust, \
 					(xip)->xi_diroffset)
 
 /*
Index: src/sys/fs/exfatfs/exfatfs_vfsops.c
diff -u src/sys/fs/exfatfs/exfatfs_vfsops.c:1.1.2.3 src/sys/fs/exfatfs/exfatfs_vfsops.c:1.1.2.4
--- src/sys/fs/exfatfs/exfatfs_vfsops.c:1.1.2.3	Tue Jul  2 20:36:50 2024
+++ src/sys/fs/exfatfs/exfatfs_vfsops.c	Fri Jul 19 16:19:16 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: exfatfs_vfsops.c,v 1.1.2.3 2024/07/02 20:36:50 perseant Exp $ */
+/* $NetBSD: exfatfs_vfsops.c,v 1.1.2.4 2024/07/19 16:19:16 perseant Exp $ */
 
 /*-
  * Copyright (c) 2022 The NetBSD Foundation, Inc.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: exfatfs_vfsops.c,v 1.1.2.3 2024/07/02 20:36:50 perseant Exp $");
+__KERNEL_RCSID(0, "$NetBSD: exfatfs_vfsops.c,v 1.1.2.4 2024/07/19 16:19:16 perseant Exp $");
 
 struct vm_page;
 
@@ -502,7 +502,7 @@ exfatfs_finish_mountfs(struct exfatfs *f
 	mp->mnt_stat.f_namemax = EXFATFS_NAMEMAX;
 	mp->mnt_flag |= MNT_LOCAL;
 	mp->mnt_dev_bshift = DEV_BSHIFT;
-	mp->mnt_fs_bshift = fs->xf_BytesPerSectorShift;
+	mp->mnt_fs_bshift = EXFATFS_LSHIFT(fs);
 
 	spec_node_setmountedfs(devvp, mp);
 
@@ -636,14 +636,14 @@ exfatfs_unmount(struct mount *mp, int mn
 int
 exfatfs_statvfs(struct mount *mp, struct statvfs *sbp)
 {
-	struct exfatfs *fs = MPTOXMP(mp)->xm_fs;;
+	struct exfatfs *fs = MPTOXMP(mp)->xm_fs;
 	
-	sbp->f_bsize = CLUSTERSIZE(fs);
-	sbp->f_frsize = SECSIZE(fs); /* XXX */
-	sbp->f_iosize = MIN(sbp->f_bsize, MAXPHYS);
-	sbp->f_blocks = EXFATFS_CLUSTER2FSSEC(fs, fs->xf_ClusterCount);
-	sbp->f_bfree =  EXFATFS_CLUSTER2FSSEC(fs, fs->xf_FreeClusterCount);
-	sbp->f_bavail = EXFATFS_CLUSTER2FSSEC(fs, fs->xf_FreeClusterCount);
+	sbp->f_bsize = EXFATFS_LSIZE(fs);
+	sbp->f_frsize = EXFATFS_LSIZE(fs);
+	sbp->f_iosize = EXFATFS_LSIZE(fs);
+	sbp->f_blocks = EXFATFS_C2L(fs, fs->xf_ClusterCount);
+	sbp->f_bfree =  EXFATFS_C2L(fs, fs->xf_FreeClusterCount);
+	sbp->f_bavail = EXFATFS_C2L(fs, fs->xf_FreeClusterCount);
 	sbp->f_bresvd = 0;
 	sbp->f_files = 0; /* XXX How can we know the number of files? */
 	sbp->f_ffree = 0; /* Could compute from #files if we had that */
@@ -692,7 +692,8 @@ exfatfs_root(struct mount *mp, int lktyp
 	SET_DFE_CREATE_UTCOFF(xip, 0x80);
 	SET_DSE_FIRSTCLUSTER(xip, fs->xf_FirstClusterOfRootDirectory);
 	SET_DSE_ALLOCPOSSIBLE(xip);
-	
+	CLR_DSE_NOFATCHAIN(xip);
+
 	/*
 	 * The root directory doesn't store its length anywhere.
 	 * Walk its FAT to find out how long the file is.
@@ -702,12 +703,12 @@ exfatfs_root(struct mount *mp, int lktyp
 	while (clust != 0xFFFFFFFF) {
 		/* Read the FAT to find the next cluster */
 		bread(fs->xf_devvp, EXFATFS_FATBLK(fs, clust),
-		      SECSIZE(fs), 0, &bp);
+		      FATBSIZE(fs), 0, &bp);
 		clust = ((uint32_t *)bp->b_data)
 			[EXFATFS_FATOFF(clust)];
 		brelse(bp, 0);
 		SET_DSE_DATALENGTH(xip, GET_DSE_DATALENGTH(xip)
-				   + CLUSTERSIZE(fs));
+				   + EXFATFS_CSIZE(fs));
 	}
 	SET_DSE_VALIDDATALENGTH(xip, GET_DSE_DATALENGTH(xip));
 	/* GETPARENT(xip, dvp); */ /* Root has no parent */
@@ -889,7 +890,7 @@ int exfatfs_getnewvnode(struct exfatfs *
 		 fs, dvp, clust, off, type, vpp));
 
 	va.va_type = type;
-	va.va_fileid = EXFATFS_CLUST_ENTRY2INO(fs, clust, off);
+	va.va_fileid = CE2INO(fs, clust, off);
 	return vcache_new(XMPTOMP(fs->xf_mp), dvp,
 			  &va, NOCRED, xip, vpp);
 }

Index: src/sys/fs/exfatfs/exfatfs_vnops.c
diff -u src/sys/fs/exfatfs/exfatfs_vnops.c:1.1.2.6 src/sys/fs/exfatfs/exfatfs_vnops.c:1.1.2.7
--- src/sys/fs/exfatfs/exfatfs_vnops.c:1.1.2.6	Fri Jul 12 23:46:54 2024
+++ src/sys/fs/exfatfs/exfatfs_vnops.c	Fri Jul 19 16:19:16 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: exfatfs_vnops.c,v 1.1.2.6 2024/07/12 23:46:54 perseant Exp $	*/
+/*	$NetBSD: exfatfs_vnops.c,v 1.1.2.7 2024/07/19 16:19:16 perseant Exp $	*/
 
 /*-
  * Copyright (c) 2022 The NetBSD Foundation, Inc.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: exfatfs_vnops.c,v 1.1.2.6 2024/07/12 23:46:54 perseant Exp $");
+__KERNEL_RCSID(0, "$NetBSD: exfatfs_vnops.c,v 1.1.2.7 2024/07/19 16:19:16 perseant Exp $");
 
 #include <sys/buf.h>
 #include <sys/dirent.h>
@@ -229,7 +229,7 @@ exfatfs_getattr(void *v)
 		vap->va_mode  |= S_ARCH1;
 	}
 	vap->va_gen = 0;
-	vap->va_blocksize = SECSIZE(fs);
+	vap->va_blocksize = EXFATFS_CSIZE(fs);
 	vap->va_bytes = GET_DSE_DATALENGTH_BLK(xip, fs);
 	vap->va_type = ap->a_vp->v_type;
 	DPRINTF((" getattr returning 0\n"));
@@ -411,12 +411,12 @@ exfatfs_read(void *v)
 		if (uio->uio_offset >= GET_DSE_VALIDDATALENGTH(xip))
 			return 0;
 
-		lbn = uio->uio_offset >> IOSHIFT(fs);
-		error = bread(vp, lbn, IOSIZE(fs), 0, &bp);
+		lbn = EXFATFS_B2L(fs, uio->uio_offset);
+		error = bread(vp, lbn, EXFATFS_LSIZE(fs), 0, &bp);
 		if (error)
 			goto bad;
 
-		off = uio->uio_offset & IOMASK(fs);
+		off = uio->uio_offset & EXFATFS_LMASK(fs);
 		n = uio->uio_resid - uio->uio_offset;
 		if (uio->uio_offset + uio->uio_resid >
 		    GET_DSE_VALIDDATALENGTH(xip))
@@ -457,7 +457,7 @@ exfatfs_write(void *v)
 	int ioflag = ap->a_ioflag;
 	u_long osize;
 	vsize_t bytelen;
-	off_t oldoff;
+	off_t oldoff, newoff;
 	size_t rem;
 	struct uio *uio = ap->a_uio;
 	struct vnode *vp = ap->a_vp;
@@ -477,7 +477,7 @@ exfatfs_write(void *v)
 	switch (vp->v_type) {
 	case VREG:
 		if (ioflag & IO_APPEND)
-			uio->uio_offset = GET_DSE_VALIDDATALENGTH(xip);
+			uio->uio_offset = GET_DSE_DATALENGTH(xip);
 		break;
 	case VDIR:
 		return EISDIR;
@@ -492,7 +492,8 @@ exfatfs_write(void *v)
 		return (0);
 
 	/* Don't bother to try to write files larger than the fs limit */
-	if (uio->uio_offset + uio->uio_resid > EXFATFS_FILESIZE_MAX)
+	newoff = uio->uio_offset + uio->uio_resid;
+	if (newoff > EXFATFS_FILESIZE_MAX)
 		return (EFBIG);
 
 	/*
@@ -500,37 +501,31 @@ exfatfs_write(void *v)
 	 */
 	async = vp->v_mount->mnt_flag & MNT_ASYNC;
 	resid = uio->uio_resid;
-	osize = GET_DSE_VALIDDATALENGTH(xip);
+	osize = GET_DSE_DATALENGTH(xip);
 
 	/*
 	 * If we write beyond the end of the file, extend it to its ultimate
 	 * size ahead of time to hopefully get a contiguous area.
 	 */
-	if (uio->uio_offset + resid > GET_DSE_VALIDDATALENGTH(xip)) {
+	if (newoff > GET_DSE_DATALENGTH(xip)) {
 		/* DPRINTF(("write past valid data length\n")); */
-		if (uio->uio_offset + resid > GET_DSE_DATALENGTH_BLK(xip,
-								xip->xi_fs)) {
+		if (newoff > roundup2(GET_DSE_DATALENGTH(xip),
+							EXFATFS_CSIZE(xip->xi_fs))) {
 			DPRINTF(("write past allocation\n"));
-			if ((error = deextend(xip, uio->uio_offset + resid,
-					      ioflag, cred)) != 0)
+			if ((error = deextend(xip, newoff, ioflag, cred)) != 0)
 				goto errexit;
-			DPRINTF(("now vdl=%llu dl=%llu\n",
-				 (unsigned long long)
-					GET_DSE_VALIDDATALENGTH(xip),
-				 (unsigned long long)
-					GET_DSE_DATALENGTH_BLK(xip, fs)));
+			DPRINTF(("now dl=%llu\n",
+				 (unsigned long long)GET_DSE_DATALENGTH(xip)));
 		}
 
-		SET_DSE_DATALENGTH(xip, uio->uio_offset + resid);
-		SET_DSE_VALIDDATALENGTH(xip, uio->uio_offset + resid);
+		SET_DSE_DATALENGTH(xip, newoff);
+		SET_DSE_VALIDDATALENGTH(xip, newoff);
 		/* hint uvm to not read in extended part */
-		uvm_vnp_setwritesize(vp, GET_DSE_VALIDDATALENGTH(xip));
+		uvm_vnp_setwritesize(vp, newoff);
 		/* zero out the remainder of the last page */
-		rem = round_page(GET_DSE_VALIDDATALENGTH(xip))
-			- GET_DSE_VALIDDATALENGTH(xip);
+		rem = round_page(newoff) - newoff;
 		if (rem > 0)
-			ubc_zerorange(&vp->v_uobj,
-				      (off_t)GET_DSE_VALIDDATALENGTH(xip),
+			ubc_zerorange(&vp->v_uobj, (off_t)newoff,
 			    rem, UBC_VNODE_FLAGS(vp));
 		extended = 1;
 	}
@@ -560,7 +555,7 @@ exfatfs_write(void *v)
 	} while (error == 0 && uio->uio_resid > 0);
 
 	/* set final size */
-	uvm_vnp_setsize(vp, GET_DSE_VALIDDATALENGTH(xip));
+	uvm_vnp_setsize(vp, GET_DSE_DATALENGTH(xip));
 	if (error == 0 && ioflag & IO_SYNC) {
 		rw_enter(vp->v_uobj.vmobjlock, RW_WRITER);
 		error = VOP_PUTPAGES(vp, trunc_page(oldoff),
@@ -579,10 +574,10 @@ errexit:
 		detrunc(xip, osize, ioflag & IO_SYNC, NOCRED);
 		uio->uio_offset -= resid - uio->uio_resid;
 		uio->uio_resid = resid;
-		uvm_vnp_setsize(vp, GET_DSE_VALIDDATALENGTH(xip));
+		uvm_vnp_setsize(vp, GET_DSE_DATALENGTH(xip));
 	} else if ((ioflag & IO_SYNC) == IO_SYNC)
 		error = exfatfs_update(vp, NULL, NULL, UPDATE_WAIT);
-	KASSERT(vp->v_size == GET_DSE_VALIDDATALENGTH(xip));
+	KASSERT(vp->v_size == GET_DSE_DATALENGTH(xip));
 #if 0
 	DPRINTF(("exfatfs_write returning %d, flags 0x%x\n", error,
 		 (unsigned)xip->xi_flag));
@@ -630,11 +625,11 @@ exfatfs_writeback(struct xfinode *xip)
 			 xip->xi_direntp[i]->xd_entryType,
 			 xip->xi_dirent_blk[i],
 			 xip->xi_dirent_off[i],
-			 EXFATFS_HWADDR2CLUSTER(fs, xip->xi_dirent_blk[i]),
-			 EXFATFS_HWADDR2DIRENT(fs, xip->xi_dirent_blk[i])
+			 EXFATFS_D2LC(fs, xip->xi_dirent_blk[i]),
+			 EXFATFS_DCLOFF_DIRENT(fs, xip->xi_dirent_blk[i])
 			 + xip->xi_dirent_off[i]));
 		if ((error = bread(xip->xi_devvp, xip->xi_dirent_blk[i],
-				   SECSIZE(fs), 0, &bp)) != 0)
+				   EXFATFS_LSIZE(fs), 0, &bp)) != 0)
 			return error;
 		KASSERT(bp != NULL);
 		KASSERT(bp->b_data != NULL);
@@ -819,8 +814,9 @@ int
 exfatfs_findempty(struct vnode *dvp, struct xfinode *xip)
 {
 	off_t off = 0, r = -1, newsize, so;
-	int i, filling, modified;
+	int i, modified;
 	daddr_t blkno;
+	int filling;
 	size_t bytes;
 	struct exfatfs_dirent *dirent;
 	struct xfinode *dxip;
@@ -838,7 +834,7 @@ exfatfs_findempty(struct vnode *dvp, str
 	fs = dxip->xi_fs;
 	KASSERT(fs != NULL);
 	len = GET_DFE_SECONDARY_COUNT(xip) + 1;
-	bytes = EXFATFS_DIRENT2BYTES(fs, len);
+	bytes = EXFATFS_DIRENT2B(fs, len);
 	KASSERT(len > 2);
 	KASSERT(len <= EXFATFS_MAXDIRENT);
 	
@@ -852,15 +848,15 @@ exfatfs_findempty(struct vnode *dvp, str
 	 * need to allocate blocks or adjust its size.
 	 */
 	newsize = GET_DSE_VALIDDATALENGTH(dxip);
-	for (off = 0; off < GET_DSE_VALIDDATALENGTH(dxip); off += SECSIZE(fs)) {
-		lbn = EXFATFS_BYTES2FSSEC(fs, off);
+	for (off = 0; off < GET_DSE_VALIDDATALENGTH(dxip); off += EXFATFS_LSIZE(fs)) {
+		lbn = EXFATFS_B2L(fs, off);
 		VOP_BMAP(dvp, lbn, NULL, &blkno, NULL);
-		if ((error = bread(fs->xf_devvp, blkno, SECSIZE(fs), 0, &bp))
+		if ((error = bread(fs->xf_devvp, blkno, EXFATFS_LSIZE(fs), 0, &bp))
 		    != 0)
 			return error;
 		filling = 0;
 		modified = 0;
-		for (so = 0; so < SECSIZE(fs); so += sizeof(*dirent)) {
+		for (so = 0; so < EXFATFS_LSIZE(fs); so += sizeof(*dirent)) {
 			dirent = (struct exfatfs_dirent *)
 				(((char *)bp->b_data) + so);
 			/*
@@ -870,10 +866,12 @@ exfatfs_findempty(struct vnode *dvp, str
 			 * skip to the next, clearing any intervening EOD
 			 * markers as we go.
 			 */
-			if (r < 0 && !filling && bytes <= SECSIZE(fs)
-			    && so + bytes > SECSIZE(fs)) {
+			if (r < 0 && !filling && bytes <= EXFATFS_SSIZE(fs) &&
+			    EXFATFS_B2S(fs, so) != EXFATFS_B2S(fs, so + bytes)) {
 				filling = 1;
 			}
+			if ((so & EXFATFS_SMASK(fs)) == 0)
+				filling = 0;
 			if (filling) {
 				if (ISEOD(dirent)) {
 					dirent->xd_entryType =
@@ -906,7 +904,7 @@ exfatfs_findempty(struct vnode *dvp, str
 						 contig,
 						 (long long)r,
 						 (unsigned)
-						  EXFATFS_BYTES2DIRENT(fs, r),
+						  EXFATFS_B2DIRENT(fs, r),
 						 rblkno, blkno));
 					goto havespace;
 				}
@@ -929,7 +927,7 @@ exfatfs_findempty(struct vnode *dvp, str
 	newsize = r + len * sizeof(*dirent);
 	if (GET_DSE_DATALENGTH_BLK(dxip, fs) < newsize) {
 		/* We need to allocate blocks before extending */
-		if ((error = deextend(dxip, roundup2(newsize, CLUSTERSIZE(fs)),
+		if ((error = deextend(dxip, roundup2(newsize, EXFATFS_CSIZE(fs)),
 				      0, NOCRED)) != 0)
 			return error;
 		DPRINTF((" allocated dir 0x%lx to %llu\n",
@@ -939,7 +937,7 @@ exfatfs_findempty(struct vnode *dvp, str
 
 	/* Space is now allocated.  Adjust validDataLength if necessary. */
 	/* exFAT requires ValidDataLength == DataLength for directories */
-	SET_DSE_DATALENGTH(dxip, roundup2(newsize, CLUSTERSIZE(fs)));
+	SET_DSE_DATALENGTH(dxip, roundup2(newsize, EXFATFS_CSIZE(fs)));
 	SET_DSE_VALIDDATALENGTH(dxip, GET_DSE_DATALENGTH(dxip));
 	uvm_vnp_setsize(dvp, GET_DSE_VALIDDATALENGTH(dxip));
 
@@ -949,27 +947,27 @@ havespace:
 		return error;
 
 	DPRINTF(("new empty space at byte %lld (entry %u)\n",
-		 (long long)r, (unsigned)(r >> EXFATFS_DIRENT_BASESHIFT)));
+		 (long long)r, (unsigned)EXFATFS_B2DIRENT(r)));
 
 	/*
 	 * Assign disk addresses
 	 */
 	for (i = 0; i < len; i++) {
 		off = r + i * sizeof(struct exfatfs_dirent);
-		lbn = EXFATFS_BYTES2FSSEC(fs, off);
-		if (i == 0 || (off & SECMASK(fs)) == 0) {
+		lbn = EXFATFS_B2L(fs, off);
+		if (i == 0 || (off & EXFATFS_LMASK(fs)) == 0) {
 			VOP_BMAP(dvp, lbn, NULL, &blkno, NULL);
 		}
 		xip->xi_dirent_blk[i] = blkno;
-		xip->xi_dirent_off[i] = (off & SECMASK(fs))
-			>> EXFATFS_DIRENT_BASESHIFT;
+		xip->xi_dirent_off[i] = (off & EXFATFS_LMASK(fs))
+			>> EXFATFS_DIRENT_SHIFT;
 		DPRINTF((" entry %d at 0x%lx/%d\n", i,
 			 xip->xi_dirent_blk[i], xip->xi_dirent_off[i]));
 	}
 	
 	/* Fix key to new location */
-	xip->xi_dirclust = EXFATFS_HWADDR2CLUSTER(fs, xip->xi_dirent_blk[0]);
-	xip->xi_diroffset = EXFATFS_HWADDR2DIRENT(fs, xip->xi_dirent_blk[0]) +
+	xip->xi_dirclust = EXFATFS_D2LC(fs, xip->xi_dirent_blk[0]);
+	xip->xi_diroffset = EXFATFS_DCLOFF_DIRENT(fs, xip->xi_dirent_blk[0]) +
 		xip->xi_dirent_off[0];
 
 	return 0;
@@ -1622,7 +1620,7 @@ exfatfs_readdir(void *v)
 	DPRINTF(("readdir: vp %p, uio %p, cred %p, eofflagp %p\n",
 		 ap->a_vp, uio, ap->a_cred, ap->a_eofflag));
 	DPRINTF(("         fs = %p, ino=%u/%u, secsize %u\n",
-		 fs, xip->xi_dirclust, xip->xi_diroffset, SECSIZE(fs)));
+		 fs, xip->xi_dirclust, xip->xi_diroffset, EXFATFS_LSIZE(fs)));
 	DPRINTF(("         offset=%lu, resid=%lu\n",
 	       (unsigned long)uio->uio_offset,
 		 (unsigned long)uio->uio_resid));
@@ -2120,24 +2118,24 @@ exfatfs_symlink(void *v)
 	/* XXX Convert link target to UCS2? */
 	
 	/* Write the target into the buffer as if it were file data */
-	error = deextend(xip, roundup2(len, CLUSTERSIZE(fs)), 0, NOCRED);
+	error = deextend(xip, roundup2(len, EXFATFS_CSIZE(fs)), 0, NOCRED);
 	if (error) {
 		exfatfs_deactivate(xip, true);
 		goto out;
 	}
 
 	resid = len;
-	for (off = 0; off < len; off += SECSIZE(fs)) {
+	for (off = 0; off < len; off += EXFATFS_LSIZE(fs)) {
 #ifdef SYMLINK_SELF
-		bp = getblk(vp, EXFATFS_BYTES2FSSEC(fs, off),
-			    SECSIZE(fs), 0, 0);
+		bp = getblk(vp, EXFATFS_B2L(fs, off),
+			    EXFATFS_LSIZE(fs), 0, 0);
 #else /* 1 */
 		daddr_t blkno;
-		VOP_BMAP(vp, EXFATFS_BYTES2FSSEC(fs, off), NULL, &blkno, NULL);
-		bp = getblk(xip->xi_devvp, blkno, SECSIZE(fs), 0, 0);
+		VOP_BMAP(vp, EXFATFS_B2L(fs, off), NULL, &blkno, NULL);
+		bp = getblk(xip->xi_devvp, blkno, EXFATFS_LSIZE(fs), 0, 0);
 #endif /* 1 */
 		memcpy(bp->b_data, ap->a_target + off,
-		       MIN(resid, SECSIZE(fs)));
+		       MIN(resid, EXFATFS_LSIZE(fs)));
 		bdwrite(bp);
 	}
 	SET_DSE_DATALENGTH(xip, len);
@@ -2188,14 +2186,14 @@ exfatfs_readlink(void *v)
 		if (uio->uio_offset >= filelen)
 			return 0;
 
-		lbn = EXFATFS_BYTES2FSSEC(fs, uio->uio_offset);
+		lbn = EXFATFS_B2L(fs, uio->uio_offset);
 #ifdef SYMLINK_SELF
-		error = bread(vp, lbn, SECSIZE(fs), 0, &bp);
+		error = bread(vp, lbn, EXFATFS_LSIZE(fs), 0, &bp);
 #else /* !SYMLINK_SELF */
 		{
 			daddr_t blkno;
 			VOP_BMAP(vp, lbn, NULL, &blkno, NULL);
-			error = bread(xip->xi_devvp, blkno, SECSIZE(fs), 0,
+			error = bread(xip->xi_devvp, blkno, EXFATFS_LSIZE(fs), 0,
 				      &bp);
 		}
 #endif /* !SYMLINK_SELF */
@@ -2207,7 +2205,7 @@ exfatfs_readlink(void *v)
 			 (long)uio->uio_resid,
 			 (long)bp->b_bufsize));
 		
-		off = uio->uio_offset & SECMASK(fs);
+		off = uio->uio_offset & EXFATFS_SMASK(fs);
 		n = MIN(uio->uio_resid, filelen - uio->uio_offset);
 		n = MIN(n, bp->b_bufsize - off);
 		if (n > 0) {
@@ -2279,28 +2277,17 @@ const struct vnodeopv_desc exfatfs_vnode
 	{ &exfatfs_vnodeop_p, exfatfs_vnodeop_entries };
 
 /*
- * Truncate.  Remove all clusters not required to handle offset "bytes".
- * This essentially means walking the FAT chain and freeing the end.
+ * Truncate a fragmented file by walking the FAT chain and freeing the end.
  */
 static int
-detrunc(struct xfinode *xip, off_t bytes, int ioflags, kauth_cred_t cred) {
+detrunc_fat(struct xfinode *xip, off_t bytes, int ioflags, kauth_cred_t cred)
+{
 	struct exfatfs *fs = xip->xi_fs;
-	uint32_t newcount = EXFATFS_BYTES2CLUSTER(fs, bytes) +
-		((bytes & CLUSTERMASK(fs)) ? 1 : 0);
-	uint32_t oldcount = EXFATFS_BYTES2CLUSTER(fs,
-				GET_DSE_DATALENGTH_BLK(xip, fs));
+	uint32_t newcount = howmany(bytes, EXFATFS_CSIZE(fs));
+	uint32_t oldcount = howmany(GET_DSE_DATALENGTH(xip), EXFATFS_CSIZE(fs));
 	uint32_t pcn, opcn, lcn;
-#if 0
-	daddr_t lbn;
-#endif
 	struct buf *bp;
 
-	assert(/* oldcount >= 0 && */ oldcount <= fs->xf_ClusterCount);
-
-	/* If already at target length, nothing to do */
-	if (oldcount <= newcount)
-		return 0;
-
 	/*
 	 * Walk the FAT chain until we reach the address of interest
 	 * By default we start from zero
@@ -2331,7 +2318,7 @@ detrunc(struct xfinode *xip, off_t bytes
 		assert(pcn >= 2 && pcn < fs->xf_ClusterCount + 2);
 
 		/* Read the FAT to find the next cluster */
-		bread(fs->xf_devvp, EXFATFS_FATBLK(fs, pcn), SECSIZE(fs), 0,
+		bread(fs->xf_devvp, EXFATFS_FATBLK(fs, pcn), FATBSIZE(fs), 0,
 		      &bp);
 		opcn = pcn;
 		pcn = ((uint32_t *)bp->b_data)[EXFATFS_FATOFF(pcn)];
@@ -2341,7 +2328,7 @@ detrunc(struct xfinode *xip, off_t bytes
 				 " %u/%u\n",
 				 (unsigned)opcn, (unsigned)INUM(xip),
 				 (unsigned)lcn,
-				 (unsigned)EXFATFS_BYTES2CLUSTER(fs,
+				 (unsigned)EXFATFS_B2C(fs,
 					GET_DSE_DATALENGTH_BLK(xip, fs))));
 			exfatfs_bitmap_dealloc(fs, opcn);
 			((uint32_t *)bp->b_data)[EXFATFS_FATOFF(opcn)]
@@ -2350,37 +2337,54 @@ detrunc(struct xfinode *xip, off_t bytes
 				bwrite(bp);
 			else
 				bdwrite(bp);
-			
-			/* Invalidate the pages, if any, in the buffer cache */
-#if 0 /* use vtruncbuf instead */
-			if (ISDIRECTORY(xip) || ISSYMLINK(xip)) {
-				for (lbn = 0;
-				     lbn < EXFATFS_CLUSTER2FSSEC(fs, 1); ++lbn) {
-					binvalbuf(xip->xi_devvp,
-						  EXFATFS_CLUSTER2HWADDR(fs,
-							pcn)
-						  + EXFATFS_FSSEC2DEVBSIZE(fs,
-							lbn));
-				}
-			}
-#endif /* 0 */
-		
 		} else
 			brelse(bp, 0);
 		++lcn;
 	}
 	assert(lcn == oldcount);
-	SET_DSE_DATALENGTH(xip, bytes);
-	SET_DSE_VALIDDATALENGTH(xip, bytes);
-	vtruncbuf(XITOV(xip), newcount, 0, 0);
 
 	DPRINTF(("inum 0x%x terminating with lcn=0x%x pcn=0x%x dl=%u\n",
 		 (unsigned)INUM(xip),
 		 (unsigned)lcn,
 		 (unsigned)pcn,
-		 (unsigned)EXFATFS_BYTES2CLUSTER(fs,
+		 (unsigned)EXFATFS_B2C(fs,
 			GET_DSE_DATALENGTH_BLK(xip, fs))));
 	
+	return 0;
+}
+
+/*
+ * Truncate.  Remove all clusters not required to handle offset "bytes".
+ */
+static int
+detrunc(struct xfinode *xip, off_t bytes, int ioflags, kauth_cred_t cred)
+{
+	struct exfatfs *fs = xip->xi_fs;
+	uint32_t newcount = howmany(bytes, EXFATFS_CSIZE(fs));
+	uint32_t oldcount = howmany(GET_DSE_DATALENGTH(xip), EXFATFS_CSIZE(fs));
+	uint32_t pcn, lcn;
+
+	assert(/* oldcount >= 0 && */ oldcount <= fs->xf_ClusterCount);
+
+	if (oldcount > newcount) {
+		/* We need to deallocate blocks */
+		/* If we are contiguous, we can use dead reckoning */
+		if (IS_DSE_NOFATCHAIN(xip)) {
+			/* XXX put this loop in exfatfs_balloc.c where it can be more efficient */
+			for (lcn = oldcount; lcn > newcount; --lcn) {
+				pcn = GET_DSE_FIRSTCLUSTER(xip) + lcn - 1;
+				exfatfs_bitmap_dealloc(fs, pcn);
+			}
+		} else {
+			/* If not we need to walk the FAT */
+			detrunc_fat(xip, bytes, ioflags, cred);
+		}
+	}
+
+	SET_DSE_DATALENGTH(xip, bytes);
+	SET_DSE_VALIDDATALENGTH(xip, bytes);
+	vtruncbuf(XITOV(xip), roundup2(bytes, EXFATFS_LSIZE(fs)), 0, 0);
+
 	if (newcount == 0) {
 		CLR_DSE_NOFATCHAIN(xip);
 		SET_DSE_FIRSTCLUSTER(xip, 0);
@@ -2396,16 +2400,52 @@ detrunc(struct xfinode *xip, off_t bytes
 }
 
 /*
+ * Write FAT entries for a file that was not
+ * fragmented but has become so.
+ */
+static int
+rewrite_fat(struct xfinode *xip, uint32_t clustercount)
+{
+	uint32_t lcn, pcn;
+	struct buf *bp = NULL;
+	int error;
+	struct exfatfs *fs = xip->xi_fs;
+
+	for (lcn = 0, pcn = GET_DSE_FIRSTCLUSTER(xip);
+		lcn < clustercount;
+		++lcn, ++pcn) {
+		if (bp == NULL) {
+			if ((error = bread(fs->xf_devvp,
+			    EXFATFS_FATBLK(fs, pcn),
+			    FATBSIZE(fs), 0, &bp)) != 0)
+				return error;
+		}
+		((uint32_t *)bp->b_data)[EXFATFS_FATOFF(pcn)]
+			= (lcn == clustercount - 1
+				? 0xffffffff : pcn + 1);
+		if (EXFATFS_FATBLK(fs, pcn) != EXFATFS_FATBLK(fs, pcn + 1)) {
+			bdwrite(bp);
+			bp = NULL;
+		}
+	}
+
+	if (bp != NULL)
+		bdwrite(bp);
+
+	return 0;
+}
+
+
+/*
  * Allocate clusters from the free map.
  */
-static int deextend(struct xfinode *xip, off_t bytes, int ioflags,
+static int
+deextend(struct xfinode *xip, off_t bytes, int ioflags,
 	kauth_cred_t cred)
 {
 	struct exfatfs *fs = xip->xi_fs;
-	uint32_t newcount = EXFATFS_BYTES2CLUSTER(fs, bytes) +
-		((bytes & CLUSTERMASK(fs)) ? 1 : 0);
-	uint32_t oldcount = EXFATFS_BYTES2CLUSTER(fs,
-		GET_DSE_DATALENGTH_BLK(xip, fs));
+	uint32_t newcount = howmany(bytes, EXFATFS_CSIZE(fs));
+	uint32_t oldcount = howmany(GET_DSE_DATALENGTH(xip), EXFATFS_CSIZE(fs));
 	uint32_t pcn, lcn, opcn;
 	daddr_t bn;
 	struct buf *bp = NULL;
@@ -2433,6 +2473,8 @@ static int deextend(struct xfinode *xip,
 	if (oldcount > 0 && pcn > 0 && IS_DSE_NOFATCHAIN(xip)) {
 		lcn = oldcount - 1;
 		pcn += lcn;
+		if (pcn >= fs->xf_ClusterCount + 2)
+			pcn = 0xFFFFFFFF;
 	}
 #if defined USE_FATCACHE
 	/* But if we have a value cached, use that instead */
@@ -2472,9 +2514,14 @@ static int deextend(struct xfinode *xip,
 					brelse(bp, 0);
 				return error;
 			}
+			/* Set length so we can recover later on error */
+			SET_DSE_DATALENGTH(xip, EXFATFS_C2B(fs, lcn + 1));
+			assert(pcn < fs->xf_ClusterCount + 2);
 #ifndef ALLOC_SEQUENTIAL
 			mutex_enter(&fs->xf_lock);
 			fs->xf_next_cluster = pcn + 1;
+			if (pcn + 1 >= fs->xf_ClusterCount + 2)
+				fs->xf_next_cluster = 2;
 			mutex_exit(&fs->xf_lock);
 #endif /* !ALLOC_SEQUENTIAL */
 			allocated = 1;
@@ -2486,16 +2533,6 @@ static int deextend(struct xfinode *xip,
 				SET_DSE_FIRSTCLUSTER(xip, pcn);
 				SET_DSE_NOFATCHAIN(xip);
 			} else {
-				/* Store it in the FAT, just after opcn */
-				if ((error = bread(fs->xf_devvp,
-						   EXFATFS_FATBLK(fs, opcn),
-						   SECSIZE(fs), 0, &bp)) != 0)
-					return error;
-				((uint32_t *)bp->b_data)[EXFATFS_FATOFF(opcn)]
-					= pcn;
-				DPRINTF(("FAT %lu -> %lu\n",
-					 (unsigned long)opcn,
-					 (unsigned long)pcn));
 				/*
 				 * If the clusters are not adjacent,
 				 * readers can no longer use dead
@@ -2506,22 +2543,36 @@ static int deextend(struct xfinode *xip,
 						 " with 0x%x != 0x%x+1\n",
 						 INUM(xip), pcn, opcn));
 					CLR_DSE_NOFATCHAIN(xip);
+					if ((error = rewrite_fat(xip, lcn)) != 0)
+						return error;
+				}
+				if (!IS_DSE_NOFATCHAIN(xip)) {
+					/* Store it in the FAT, just after opcn */
+					if ((error = bread(fs->xf_devvp,
+						   	EXFATFS_FATBLK(fs, opcn),
+						   	FATBSIZE(fs), 0, &bp)) != 0)
+						return error;
+					((uint32_t *)bp->b_data)[EXFATFS_FATOFF(opcn)]
+						= pcn;
+					DPRINTF(("FAT %lu -> %lu\n",
+					 	(unsigned long)opcn,
+					 	(unsigned long)pcn));
+					if (ioflags)
+						bwrite(bp);
+					else
+						bdwrite(bp);
+					bp = NULL;
 				}
-				if (ioflags)
-					bwrite(bp);
-				else
-					bdwrite(bp);
-				bp = NULL;
 			}
 
 			/* Fill a new directory cluster with zero */
 			if (ISDIRECTORY(xip)) {
-				for (bn = EXFATFS_CLUSTER2HWADDR(fs, pcn);
-				     EXFATFS_HWADDR2CLUSTER(fs, bn) == pcn;
-				     bn += EXFATFS_FSSEC2DEVBSIZE(fs, 1)) {
+				for (bn = EXFATFS_LC2D(fs, pcn);
+				     EXFATFS_D2LC(fs, bn) == pcn;
+				     bn += EXFATFS_L2D(fs, 1)) {
 					bp = getblk(fs->xf_devvp, bn,
-						    SECSIZE(fs), 0, 0);
-					memset(bp->b_data, 0, SECSIZE(fs));
+						    EXFATFS_LSIZE(fs), 0, 0);
+					memset(bp->b_data, 0, EXFATFS_LSIZE(fs));
 					bdwrite(bp);
 					bp = NULL;
 				}
@@ -2541,11 +2592,15 @@ static int deextend(struct xfinode *xip,
 		if (allocated) {
 			pcn = 0;
 		} else {
+			uint32_t lastpcn = pcn;
 			if ((error = bread(fs->xf_devvp,
 					   EXFATFS_FATBLK(fs, pcn),
-					   SECSIZE(fs), 0, &bp)) != 0)
+					   FATBSIZE(fs), 0, &bp)) != 0)
 				return error;
 			pcn = ((uint32_t *)bp->b_data)[EXFATFS_FATOFF(pcn)];
+			if (pcn != 0xffffffff && pcn >= fs->xf_ClusterCount + 2)
+				printf("pcn %lx -> %lx\n", (unsigned long)lastpcn, (unsigned long)pcn);
+			assert(pcn == 0xffffffff || pcn < fs->xf_ClusterCount + 2);
 			brelse(bp, 0);
 			bp = NULL;
 		}

Index: src/usr.sbin/dumpexfatfs/dumpexfatfs.c
diff -u src/usr.sbin/dumpexfatfs/dumpexfatfs.c:1.1.2.3 src/usr.sbin/dumpexfatfs/dumpexfatfs.c:1.1.2.4
--- src/usr.sbin/dumpexfatfs/dumpexfatfs.c:1.1.2.3	Wed Jul  3 21:56:17 2024
+++ src/usr.sbin/dumpexfatfs/dumpexfatfs.c	Fri Jul 19 16:19:16 2024
@@ -197,7 +197,7 @@ void print_fat(struct exfatfs *fs)
 {
 	struct buf *bp;
 	int fatno, i, j;
-	int fatsperblk = SECSIZE(fs) / 4;
+	int fatsperblk = FATBSIZE(fs) / 4;
 	uint32_t *table;
 
 	for (fatno = 0; fatno < fs->xf_NumberOfFats; fatno++) {
@@ -205,11 +205,11 @@ void print_fat(struct exfatfs *fs)
 		       fs->xf_FatOffset + fatno * fs->xf_FatLength);
 		
 		for (i = 0; i < fs->xf_ClusterCount + 2; i+= fatsperblk) {
-			bread(fs->xf_devvp, EXFATFS_FSSEC2DEVBSIZE(fs, fs->xf_FatOffset + (i / fatsperblk) + fatno * fs->xf_FatLength),
-			      SECSIZE(fs), 0, &bp);
+			bread(fs->xf_devvp, EXFATFS_S2D(fs, fs->xf_FatOffset + (i / fatsperblk) + fatno * fs->xf_FatLength),
+			      FATBSIZE(fs), 0, &bp);
 			
 			table = (uint32_t *)bp->b_data;
-			for (j = 0; j < SECSIZE(fs) / 4
+			for (j = 0; j < FATBSIZE(fs) / 4
 				     && i + j < fs->xf_ClusterCount + 2; j++) {
 				printf("\t%8.8x: %8.8x\n", (unsigned int)i + j,
 				       (unsigned int)table[j]);
@@ -281,10 +281,10 @@ uint32_t next_fat(struct exfatfs *fs, ui
 	struct buf *bp;
 	uint32_t retval;
 
-	bread(fs->xf_devvp, EXFATFS_FSSEC2DEVBSIZE(fs, fs->xf_FatOffset
+	bread(fs->xf_devvp, EXFATFS_S2D(fs, fs->xf_FatOffset
 					    + (fat >> (fs->xf_BytesPerSectorShift - 2))),
-	      SECSIZE(fs), 0, &bp);
-	retval = ((uint32_t *)bp->b_data)[fat & (SECMASK(fs) >> 2)];
+	      FATBSIZE(fs), 0, &bp);
+	retval = ((uint32_t *)bp->b_data)[fat & (FATBMASK(fs) >> 2)];
 	brelse(bp, 0);
 
 	return retval;
@@ -301,16 +301,16 @@ void print_bitmap(struct exfatfs *fs)
 	printf("Bitmap beginning at cluster 2:\n");
 	total = 0;
 	for (lbn = 0; lbn < howmany(fs->xf_ClusterCount,
-				    SECSIZE(fs) / sizeof(uint32_t)); ++lbn) {
+				    EXFATFS_LSIZE(fs) / sizeof(uint32_t)); ++lbn) {
 		/* Retrieve the block */
-		bread(fs->xf_bitmapvp, lbn, SECSIZE(fs), 0, &bp);
+		bread(fs->xf_bitmapvp, lbn, EXFATFS_LSIZE(fs), 0, &bp);
 		printf("--lbn %lu hw 0x%lx\n",
 		       (unsigned long)bp->b_lblkno,
 		       (unsigned long)bp->b_blkno);
 		data = (uint8_t *)bp->b_data;
 		
 		/* Format it */
-		for (i = 0; i < SECSIZE(fs); i++) {
+		for (i = 0; i < EXFATFS_LSIZE(fs); i++) {
 			if ((total & 0x7f) == 0) {
 				printf("\t%8.8lx ", (unsigned long)total + 2);
 			} else if ((total & 0x3f) == 0) {
@@ -341,11 +341,11 @@ void print_upcase_table(struct exfatfs *
 	do {
 		for (subclust = 0; subclust < (1 << fs->xf_SectorsPerClusterShift); ++subclust) {
 			/* Retrieve the block */
-			bread(fs->xf_devvp, EXFATFS_CLUSTER2HWADDR(fs, clust) + EXFATFS_FSSEC2DEVBSIZE(fs, subclust), SECSIZE(fs), 0, &bp);
+			bread(fs->xf_devvp, EXFATFS_LC2D(fs, clust) + EXFATFS_S2D(fs, subclust), EXFATFS_LSIZE(fs), 0, &bp);
 			data = (uint16_t *)bp->b_data;
 			
 			/* Format it */
-			for (i = 0; i < SECSIZE(fs) >> 1; i++) {
+			for (i = 0; i < EXFATFS_LSIZE(fs) >> 1; i++) {
 				if ((total & 0x7) == 0) {
 					printf("\n\t");
 				}
@@ -383,15 +383,15 @@ void print_dir(struct exfatfs *fs, uint3
 		maxlen = INT_MAX;
 	} else {
 		/* Load the directory entry specified */
-		daddr_t blkno = EXFATFS_CLUSTER2HWADDR(fs, dirclust)
-			+ EXFATFS_DIRENT2DEVBSIZE(fs, diroff);
+		daddr_t blkno = EXFATFS_LC2D(fs, dirclust)
+			+ EXFATFS_DIRENT2D(fs, diroff);
 		struct exfatfs_dse *dse;
 
 		printf("Reading dirent from %d/%d, physical blk 0x%x\n",
 		       (int)dirclust, (int)diroff, (unsigned)blkno);
-		bread(fs->xf_devvp, blkno, SECSIZE(fs), 0, &bp);
+		bread(fs->xf_devvp, blkno, EXFATFS_LSIZE(fs), 0, &bp);
 		dse = malloc(sizeof(*dse));
-		memcpy(dse, ((struct exfatfs_dse *)bp->b_data) + (diroff % EXFATFS_FSSEC2DIRENT(fs, 1)) + 1, sizeof(*dse));
+		memcpy(dse, ((struct exfatfs_dse *)bp->b_data) + (diroff % EXFATFS_S2D(fs, 1)) + 1, sizeof(*dse));
 		brelse(bp, 0);
 		bp = NULL;
 		clust = dse->xd_firstCluster;
@@ -403,15 +403,15 @@ void print_dir(struct exfatfs *fs, uint3
 		printf(" Reading from cluster %d\n", clust);
 	}
 	for (off = 0; off * sizeof(*dfp) < maxlen; ++off) {
-		i = off % (SECSIZE(fs) / sizeof(*dfp));
+		i = off % (EXFATFS_LSIZE(fs) / sizeof(*dfp));
 		if (i == 0) {
 			if (bp)
 				brelse(bp, 0);
 
 			/* Maybe a new cluster, too */
-			if (off > 0 && ((off * sizeof(*dfp)) & CLUSTERMASK(fs)) == 0) {
+			if (off > 0 && ((off * sizeof(*dfp)) & EXFATFS_CMASK(fs)) == 0) {
 				if (bread(fs->xf_devvp, EXFATFS_FATBLK(fs, clust),
-					  SECSIZE(fs), 0, &bp) != 0) {
+					  FATBSIZE(fs), 0, &bp) != 0) {
 					err(1, "Read FAT entry 0x%lx\n", (unsigned long)clust);
 				}
 				clust = ((uint32_t *)bp->b_data)[EXFATFS_FATOFF(clust)];
@@ -423,13 +423,13 @@ void print_dir(struct exfatfs *fs, uint3
 					printf(" Reading from cluster %d\n", clust);
 			}
 			
-			bread(fs->xf_devvp, EXFATFS_CLUSTER2HWADDR(fs, clust)
-			      + (((off * sizeof(*dfp)) & CLUSTERMASK(fs))
+			bread(fs->xf_devvp, EXFATFS_LC2D(fs, clust)
+			      + (((off * sizeof(*dfp)) & EXFATFS_CMASK(fs))
 				 >> DEV_BSHIFT),
-			      SECSIZE(fs), 0, &bp);
+			      EXFATFS_LSIZE(fs), 0, &bp);
 			if (action == ACTION_PRINT)
 				printf("  lbn %ld at bn 0x%lx\n",
-				       (long)(off / (SECSIZE(fs) / sizeof(*dfp))),
+				       (long)(off / (EXFATFS_LSIZE(fs) / sizeof(*dfp))),
 				       (unsigned long)bp->b_blkno);
 			data = (uint8_t *)bp->b_data;
 		}
@@ -512,7 +512,7 @@ void print_dir(struct exfatfs *fs, uint3
 			streamfound = 0;
 			namefound = 0;
 			cksumreqd = dfp->xd_setChecksum;
-			inum = EXFATFS_CLUST_ENTRY2INO(fs, clust, off);
+			inum = CE2INO(fs, clust, off);
 			cksum = exfatfs_cksum16(0, (uint8_t *)dfp, sizeof(*dfp),
 						PRIMARY_IGNORE, PRIMARY_IGNORE_LEN);
 			
@@ -601,6 +601,8 @@ void print_dir(struct exfatfs *fs, uint3
 			if (action == ACTION_PRINT) {
 				printf("\tStream Extension%s\n",
 				       ISINUSE(dsp) ? "" : " (not in use)");
+				printf("\t\tSecondary Flags: 0x%hhx\n",
+				       dsp->xd_generalSecondaryFlags);
 				printf("\t\tName Length: %hhu\n",
 				       dsp->xd_nameLength);
 				printf("\t\tName Hash: 0x%hx\n",

Reply via email to