Module Name:    src
Committed By:   perseant
Date:           Fri Aug  2 00:16:55 UTC 2024

Modified Files:
        src/sys/fs/exfatfs [perseant-exfatfs]: TODO exfatfs.h exfatfs_balloc.c
            exfatfs_balloc.h exfatfs_extern.c exfatfs_extern.h exfatfs_vfsops.c
            exfatfs_vnops.c

Log Message:
Use a symbol for the size of the boot code.
Deallocate bitmap entries more efficiently for unfragmented files
Use TRIM if the disk driver supports it.
Share code for locating a valid superblock.
Share code for writing, and writing back, the superblock.
Correct the sense of the archive bit (it was inverted).


To generate a diff of this commit:
cvs rdiff -u -r1.1.2.3 -r1.1.2.4 src/sys/fs/exfatfs/TODO \
    src/sys/fs/exfatfs/exfatfs_balloc.c src/sys/fs/exfatfs/exfatfs_balloc.h \
    src/sys/fs/exfatfs/exfatfs_extern.h
cvs rdiff -u -r1.1.2.5 -r1.1.2.6 src/sys/fs/exfatfs/exfatfs.h \
    src/sys/fs/exfatfs/exfatfs_vfsops.c
cvs rdiff -u -r1.1.2.6 -r1.1.2.7 src/sys/fs/exfatfs/exfatfs_extern.c
cvs rdiff -u -r1.1.2.8 -r1.1.2.9 src/sys/fs/exfatfs/exfatfs_vnops.c

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

Modified files:

Index: src/sys/fs/exfatfs/TODO
diff -u src/sys/fs/exfatfs/TODO:1.1.2.3 src/sys/fs/exfatfs/TODO:1.1.2.4
--- src/sys/fs/exfatfs/TODO:1.1.2.3	Fri Jul 19 16:19:15 2024
+++ src/sys/fs/exfatfs/TODO	Fri Aug  2 00:16:55 2024
@@ -1 +1,2 @@
 * Use unions in directory entries instead of the cumbersome casting.
+* Copy extended boot code too, if requested.
\ No newline at end of file
Index: src/sys/fs/exfatfs/exfatfs_balloc.c
diff -u src/sys/fs/exfatfs/exfatfs_balloc.c:1.1.2.3 src/sys/fs/exfatfs/exfatfs_balloc.c:1.1.2.4
--- src/sys/fs/exfatfs/exfatfs_balloc.c:1.1.2.3	Fri Jul 19 16:19:15 2024
+++ src/sys/fs/exfatfs/exfatfs_balloc.c	Fri Aug  2 00:16:55 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: exfatfs_balloc.c,v 1.1.2.3 2024/07/19 16:19:15 perseant Exp $	*/
+/*	$NetBSD: exfatfs_balloc.c,v 1.1.2.4 2024/08/02 00:16:55 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.3 2024/07/19 16:19:15 perseant Exp $");
+__KERNEL_RCSID(0, "$NetBSD: exfatfs_balloc.c,v 1.1.2.4 2024/08/02 00:16:55 perseant Exp $");
 
 #include <sys/types.h>
 #include <sys/buf.h>
@@ -185,24 +185,39 @@ exfatfs_bitmap_alloc(struct exfatfs *fs,
 }
 
 int
-exfatfs_bitmap_dealloc(struct exfatfs *fs, uint32_t cno)
+exfatfs_bitmap_dealloc(struct exfatfs *fs, uint32_t cno, int len)
 {
 	daddr_t lbn, blkno;
-	struct buf *bp;
-	int off, error;
+	struct buf *bp = NULL;
+	int off, error, lbsize;
 	uint8_t *data;
-	
+
 	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, 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);
+	lbsize = EXFATFS_LSIZE(fs) * NBBY;
+	while (--len >= 0) {
+		if (off >= lbsize) {
+			/* Switch to a new block */
+			off = 0;
+			++lbn;
+			if (bp != NULL)
+				bdwrite(bp);
+			bp = NULL;
+		}
+		if (bp == NULL) {
+			exfatfs_bmap_shared(fs->xf_bitmapvp, lbn, NULL, &blkno, NULL);
+			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);
+		++off;
+	}
+	if (bp != NULL)
+		bdwrite(bp);
 #ifdef _KERNEL
 	mutex_enter(&fs->xf_lock);
 #endif /* _KERNEL */
Index: src/sys/fs/exfatfs/exfatfs_balloc.h
diff -u src/sys/fs/exfatfs/exfatfs_balloc.h:1.1.2.3 src/sys/fs/exfatfs/exfatfs_balloc.h:1.1.2.4
--- src/sys/fs/exfatfs/exfatfs_balloc.h:1.1.2.3	Fri Jul 19 16:19:15 2024
+++ src/sys/fs/exfatfs/exfatfs_balloc.h	Fri Aug  2 00:16:55 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: exfatfs_balloc.h,v 1.1.2.3 2024/07/19 16:19:15 perseant Exp $ */
+/* $NetBSD: exfatfs_balloc.h,v 1.1.2.4 2024/08/02 00:16:55 perseant Exp $ */
 
 /*-
  * Copyright (c) 2022, 2024 The NetBSD Foundation, Inc.
@@ -42,6 +42,6 @@
 int exfatfs_bitmap_init(struct exfatfs *);
 void exfatfs_bitmap_destroy(struct exfatfs *);
 int exfatfs_bitmap_alloc(struct exfatfs *, uint32_t, uint32_t *);
-int exfatfs_bitmap_dealloc(struct exfatfs *, uint32_t);
+int exfatfs_bitmap_dealloc(struct exfatfs *, uint32_t, int);
 
 #endif /* EXFATFS_BALLOC_H_ */
Index: src/sys/fs/exfatfs/exfatfs_extern.h
diff -u src/sys/fs/exfatfs/exfatfs_extern.h:1.1.2.3 src/sys/fs/exfatfs/exfatfs_extern.h:1.1.2.4
--- src/sys/fs/exfatfs/exfatfs_extern.h:1.1.2.3	Wed Jul 24 00:38:26 2024
+++ src/sys/fs/exfatfs/exfatfs_extern.h	Fri Aug  2 00:16:55 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: exfatfs_extern.h,v 1.1.2.3 2024/07/24 00:38:26 perseant Exp $	*/
+/*	$NetBSD: exfatfs_extern.h,v 1.1.2.4 2024/08/02 00:16:55 perseant Exp $	*/
 
 /*-
  * Copyright (c) 2022 The NetBSD Foundation, Inc.
@@ -37,6 +37,7 @@
 
 int exfatfs_bmap_shared(struct vnode *, daddr_t, struct vnode **, daddr_t *,
 	int *);
+int exfatfs_locate_valid_superblock(struct vnode *, size_t, struct exfatfs **);
 int exfatfs_mountfs_shared(struct vnode *, struct exfatfs_mount *, unsigned,
 	struct exfatfs **);
 struct xfinode *exfatfs_newxfinode(struct exfatfs *, uint32_t, uint32_t);
@@ -51,6 +52,6 @@ int exfatfs_scandir(struct vnode *, off_
 		    void *arg);
 #define SCANDIR_STOP     0x00000001
 #define SCANDIR_DONTFREE 0x00000002
-int exfatfs_write_sb(struct exfatfs *);
+int exfatfs_write_sb(struct exfatfs *, int);
 
 #endif /* EXFATFS_EXTERN_H_ */

Index: src/sys/fs/exfatfs/exfatfs.h
diff -u src/sys/fs/exfatfs/exfatfs.h:1.1.2.5 src/sys/fs/exfatfs/exfatfs.h:1.1.2.6
--- src/sys/fs/exfatfs/exfatfs.h:1.1.2.5	Fri Jul 19 16:19:15 2024
+++ src/sys/fs/exfatfs/exfatfs.h	Fri Aug  2 00:16:55 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: exfatfs.h,v 1.1.2.5 2024/07/19 16:19:15 perseant Exp $ */
+/* $NetBSD: exfatfs.h,v 1.1.2.6 2024/08/02 00:16:55 perseant Exp $ */
 
 /*-
  * Copyright (c) 2022, 2024 The NetBSD Foundation, Inc.
@@ -71,7 +71,8 @@ struct exfatdfs {
 	uint8_t  xdf_DriveSelect;
 	uint8_t  xdf_PercentInUse;
 	uint8_t  xdf_Reserved[7];
-	uint8_t  xdf_BootCode[390];
+#define EXFATFS_BOOTCODE_SIZE 390
+	uint8_t  xdf_BootCode[EXFATFS_BOOTCODE_SIZE];
 	uint16_t xdf_BootSignature;
 #define EXFAT_BOOT_SIGNATURE 0xAA55
 #define EXFAT_EXTENDED_BOOT_SIGNATURE 0xAA550000
Index: src/sys/fs/exfatfs/exfatfs_vfsops.c
diff -u src/sys/fs/exfatfs/exfatfs_vfsops.c:1.1.2.5 src/sys/fs/exfatfs/exfatfs_vfsops.c:1.1.2.6
--- src/sys/fs/exfatfs/exfatfs_vfsops.c:1.1.2.5	Wed Jul 24 00:38:26 2024
+++ src/sys/fs/exfatfs/exfatfs_vfsops.c	Fri Aug  2 00:16:55 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: exfatfs_vfsops.c,v 1.1.2.5 2024/07/24 00:38:26 perseant Exp $ */
+/* $NetBSD: exfatfs_vfsops.c,v 1.1.2.6 2024/08/02 00:16:55 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.5 2024/07/24 00:38:26 perseant Exp $");
+__KERNEL_RCSID(0, "$NetBSD: exfatfs_vfsops.c,v 1.1.2.6 2024/08/02 00:16:55 perseant Exp $");
 
 struct vm_page;
 
@@ -620,7 +620,7 @@ exfatfs_unmount(struct mount *mp, int mn
 	fs->xf_VolumeFlags &= ~EXFATFS_VOLUME_DIRTY;
 	fs->xf_PercentInUse = (fs->xf_ClusterCount - fs->xf_FreeClusterCount)
 		/ fs->xf_ClusterCount;
-	exfatfs_write_sb(fs);
+	exfatfs_write_sb(fs, 0);
 	DPRINTF((" lock devvp...\n"));
 	vn_lock(fs->xf_devvp, LK_EXCLUSIVE | LK_RETRY);
 	DPRINTF((" close devvp...\n"));

Index: src/sys/fs/exfatfs/exfatfs_extern.c
diff -u src/sys/fs/exfatfs/exfatfs_extern.c:1.1.2.6 src/sys/fs/exfatfs/exfatfs_extern.c:1.1.2.7
--- src/sys/fs/exfatfs/exfatfs_extern.c:1.1.2.6	Wed Jul 24 00:38:26 2024
+++ src/sys/fs/exfatfs/exfatfs_extern.c	Fri Aug  2 00:16:55 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: exfatfs_extern.c,v 1.1.2.6 2024/07/24 00:38:26 perseant Exp $	*/
+/*	$NetBSD: exfatfs_extern.c,v 1.1.2.7 2024/08/02 00:16:55 perseant Exp $	*/
 
 /*-
  * Copyright (c) 2022 The NetBSD Foundation, Inc.
@@ -33,10 +33,11 @@
 
 #ifdef _KERNEL
 # include <sys/buf.h>
+# define B_INVAL BC_INVAL
 # include <sys/malloc.h>
 # include <sys/rwlock.h>
 # include <miscfs/specfs/specdev.h>  /* For v_rdev */
-#else
+#else /* ! _KERNEL */
 # include <stdlib.h>
 # include <string.h>
 # include <assert.h>
@@ -49,7 +50,7 @@
 # define buf ubuf
 typedef struct uvvnode uvnode_t;
 # define vnode_t uvnode_t
-#endif
+#endif /* ! _KERNEL */
 
 #include <fs/exfatfs/exfatfs.h>
 #include <fs/exfatfs/exfatfs_balloc.h>
@@ -254,40 +255,21 @@ errout:
 	return error;
 }
 
-int exfatfs_mountfs_shared(struct vnode *devvp, struct exfatfs_mount *xmp,
-	unsigned secsize, struct exfatfs **fsp)
+int
+exfatfs_locate_valid_superblock(struct vnode *devvp, size_t secshift, struct exfatfs **fsp)
 {
 	struct exfatfs *fs = NULL;
 	struct buf *bp;
-	uint16_t *uctable;
-	int	error;
-	unsigned secshift;
+	int error, last_error;
 	const char *errstr;
 	int boot_offset;
 	uint8_t boot_ignore[3] = { 106, 107, 112 };
 	int bn;
 	uint32_t sum, badsb;
-	off_t res, off;
+	size_t secsize, newshift;
 
-	DPRINTF(("exfatfs_mountfs_shared(%p, %u, %p)\n",
-		 devvp, secsize, fsp));
-
-	if (secsize < DEV_BSIZE) {
-		DPRINTF(("Invalid block secsize (%d < DEV_BSIZE)\n", secsize));
-		return EINVAL;
-	}
-	secshift = DEV_BSHIFT;
-	while ((1U << secshift) < secsize)
-		++secshift;
-
-	/*
-	 * Set up our exfat-specific mount structure
-	 */
-	if (secsize < sizeof(fs->xf_exfatdfs)) {
-		DPRINTF(("sector size %u smaller than required %u\n",
-			 (unsigned)secsize, (unsigned)sizeof(fs->xf_exfatdfs)));
-		return EINVAL;
-	}
+	*fsp = NULL;
+	secsize = (1 << secshift);
 
 	/*
 	 * Check both boot blocks and checksums to find a valid one
@@ -307,8 +289,17 @@ int exfatfs_mountfs_shared(struct vnode 
 					 (unsigned long)((bn + boot_offset)
 						<< (secshift - DEV_BSHIFT)),
 					 (unsigned long)secsize, error));
+				last_error = error;
 				continue;
 			}
+
+			/* If the sectors are of a different size, switch to that size */
+			newshift = ((struct exfatfs *)bp->b_data)->xf_BytesPerSectorShift;
+			if (newshift != secshift && newshift >= 9 && newshift <= 12) {
+				brelse(bp, B_INVAL);
+				return exfatfs_locate_valid_superblock(devvp, newshift, fsp);
+			}
+
 			/*
 			 * The checksum of the first sector ignores
 			 * certain fields, per the specification.
@@ -322,26 +313,28 @@ int exfatfs_mountfs_shared(struct vnode 
 			 * this is our superblock if checksums match.
 			 */
 			if (bn == 0 && fs == NULL) {
-				fs = malloc(sizeof(*fs)
+				*fsp = malloc(sizeof(**fsp)
 #ifdef _KERNEL
 					    , M_EXFATFSBOOT, M_WAITOK
 #endif /* _KERNEL */
 					);
-				memset(fs, 0, sizeof(*fs));
-				memcpy(fs, bp->b_data, sizeof(fs->xf_exfatdfs));
+				memset(*fsp, 0, sizeof(*fs));
+				memcpy(*fsp, bp->b_data, sizeof((*fsp)->xf_exfatdfs));
 #ifdef DEBUG_VERBOSE
-				DPRINTF(("fs = %p\n", fs));
+				DPRINTF(("fs = %p\n", *fsp));
 #endif
 			}
 			brelse(bp, 0);
 		}
-		if (fs == NULL)
+		if (*fsp == NULL)
 			continue;
 
 		/* Now read the recorded checksum and compare */
 		if ((error = bread(devvp, (11 + boot_offset) << (secshift - DEV_BSHIFT),
-				   secsize, 0, &bp)) != 0)
+				   secsize, 0, &bp)) != 0) {
+			last_error = error;
 			continue;
+		}
 		if (sum != *(u_int32_t *)(bp->b_data)) {
 			DPRINTF(("Checksum mismatch at offset %u\n", boot_offset));
 			badsb = 1;
@@ -350,7 +343,7 @@ int exfatfs_mountfs_shared(struct vnode 
 		bp = NULL;
 
 		/* Check other aspects of the boot block */
-		if (!badsb && (errstr = exfatfs_check_bootblock(fs)) != NULL) {
+		if (!badsb && (errstr = exfatfs_check_bootblock(*fsp)) != NULL) {
 			DPRINTF(("%s\n", errstr));
 			badsb = 1;
 		}
@@ -359,14 +352,52 @@ int exfatfs_mountfs_shared(struct vnode 
 			break;
 
 		/* Not an error on the first one, just try the other */
-		free(fs
+		free(*fsp
 #ifdef _KERNEL
 		     , M_EXFATFSBOOT
 #endif /* _KERNEL */
 			);
-		fs = NULL;
+		*fsp = NULL;
 	}
+
+	if (*fsp)
+		last_error = 0;
+	return last_error;
+}
 	
+int exfatfs_mountfs_shared(struct vnode *devvp, struct exfatfs_mount *xmp,
+	unsigned secsize, struct exfatfs **fsp)
+{
+	struct exfatfs *fs = NULL;
+	struct buf *bp;
+	uint16_t *uctable;
+	int	error;
+	unsigned secshift;
+	off_t res, off;
+
+	DPRINTF(("exfatfs_mountfs_shared(%p, %u, %p)\n",
+		 devvp, secsize, fsp));
+
+	if (secsize < DEV_BSIZE) {
+		DPRINTF(("Invalid block secsize (%d < DEV_BSIZE)\n", secsize));
+		return EINVAL;
+	}
+	secshift = DEV_BSHIFT;
+	while ((1U << secshift) < secsize)
+		++secshift;
+
+	/*
+	 * Set up our exfat-specific mount structure
+	 */
+	if (secsize < sizeof(fs->xf_exfatdfs)) {
+		DPRINTF(("sector size %u smaller than required %u\n",
+			 (unsigned)secsize, (unsigned)sizeof(fs->xf_exfatdfs)));
+		return EINVAL;
+	}
+
+	if ((error = exfatfs_locate_valid_superblock(devvp, secshift, &fs)) != 0)
+		return error;
+
 	if (fs == NULL) {
 		DPRINTF(("Neither boot block was valid\n"));
 		return EINVAL;
@@ -381,7 +412,7 @@ int exfatfs_mountfs_shared(struct vnode 
 		/* If mounting for write, mark the fs dirty */
 		if (!(xmp->xm_flags & EXFATFSMNT_RONLY)) {
 			fs->xf_VolumeFlags |= EXFATFS_VOLUME_DIRTY;
-			exfatfs_write_sb(fs);
+			exfatfs_write_sb(fs, 0);
 		}
 	}
 	
@@ -584,7 +615,8 @@ done:
 	return 0;
 }
 
-static const char * exfatfs_check_bootblock(struct exfatfs *fs)
+static const char *
+exfatfs_check_bootblock(struct exfatfs *fs)
 {
 	unsigned i;
 
@@ -741,7 +773,8 @@ exfatfs_freedirent(struct exfatfs_dirent
 }
 
 #ifdef EXFATFS_FENCE
-static int checkzero(void *p, int len) {
+static int
+checkzero(void *p, int len) {
 	int i;
 
 	for (i = 0; i < len; i++)
@@ -1028,8 +1061,9 @@ out:
  * Assemble the file name from its various components and
  * store it in "name", with its length in "namelenp".
  */
-int exfatfs_get_file_name(struct xfinode *xip, uint16_t *name,
-			  int *namelenp, int resid)
+int
+exfatfs_get_file_name(struct xfinode *xip, uint16_t *name,
+		      int *namelenp, int resid)
 {
 	int entryno, i;
 	struct exfatfs_dfn *dfn;
@@ -1055,8 +1089,9 @@ int exfatfs_get_file_name(struct xfinode
  * to preserve other, non-filename-related, secondary entries that may
  * follow the File Name entries.
  */
-int exfatfs_set_file_name(struct xfinode *xip, uint16_t *name,
-			  int namelen)
+int
+exfatfs_set_file_name(struct xfinode *xip, uint16_t *name,
+		      int namelen)
 {
 	struct exfatfs_dirent *oldp[EXFATFS_MAXDIRENT];
 	struct exfatfs_dfn *dfnp;
@@ -1104,7 +1139,7 @@ int exfatfs_set_file_name(struct xfinode
  * Write the boot block to disk, and checksum the boot block set.
  */
 int
-exfatfs_write_sb(struct exfatfs *fs)
+exfatfs_write_sb(struct exfatfs *fs, int re_checksum)
 {
 	daddr_t base;
 	int i, error;
@@ -1120,12 +1155,16 @@ exfatfs_write_sb(struct exfatfs *fs)
 			return error;
 		memcpy(bp->b_data, &fs->xf_exfatdfs,
 		       sizeof(fs->xf_exfatdfs));
-		cksum = exfatfs_cksum32(0,
-				(uint8_t *)bp->b_data,
-				BSSIZE(fs), boot_ignore,
-				sizeof(boot_ignore));
+		if (re_checksum)
+			cksum = exfatfs_cksum32(0,
+					(uint8_t *)bp->b_data,
+					BSSIZE(fs), boot_ignore,
+					sizeof(boot_ignore));
 		bwrite(bp);
 
+		if (!re_checksum)
+			continue;
+
 		/* Checksum but do not write other sectors */
 		for (i = 1; i < 11; i++) {
 			if ((error = bread(fs->xf_devvp, base + i, BSSIZE(fs),

Index: src/sys/fs/exfatfs/exfatfs_vnops.c
diff -u src/sys/fs/exfatfs/exfatfs_vnops.c:1.1.2.8 src/sys/fs/exfatfs/exfatfs_vnops.c:1.1.2.9
--- src/sys/fs/exfatfs/exfatfs_vnops.c:1.1.2.8	Wed Jul 24 00:38:27 2024
+++ src/sys/fs/exfatfs/exfatfs_vnops.c	Fri Aug  2 00:16:55 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: exfatfs_vnops.c,v 1.1.2.8 2024/07/24 00:38:27 perseant Exp $	*/
+/*	$NetBSD: exfatfs_vnops.c,v 1.1.2.9 2024/08/02 00:16:55 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.8 2024/07/24 00:38:27 perseant Exp $");
+__KERNEL_RCSID(0, "$NetBSD: exfatfs_vnops.c,v 1.1.2.9 2024/08/02 00:16:55 perseant Exp $");
 
 #include <sys/buf.h>
 #include <sys/dirent.h>
@@ -224,7 +224,7 @@ exfatfs_getattr(void *v)
 			     GET_DFE_CREATE10MS(xip), fs->xf_gmtoff,
 			     &vap->va_ctime);
 	vap->va_flags = 0;
-	if (ISARCHIVE(xip)) {
+	if (!ISARCHIVE(xip)) {
 		vap->va_flags |= SF_ARCHIVED;
 		vap->va_mode  |= S_ARCH1;
 	}
@@ -2336,13 +2336,20 @@ detrunc_fat(struct xfinode *xip, off_t b
 				 (unsigned)lcn,
 				 (unsigned)EXFATFS_B2C(fs,
 					GET_DSE_DATALENGTH_BLK(xip, fs))));
-			exfatfs_bitmap_dealloc(fs, opcn);
+			exfatfs_bitmap_dealloc(fs, opcn, 1);
 			((uint32_t *)bp->b_data)[EXFATFS_FATOFF(opcn)]
 				= 0xFFFFFFFF;
 			if (ioflags)
 				bwrite(bp);
 			else
 				bdwrite(bp);
+
+			/* Notify underlying device for TRIM */
+			vn_lock(fs->xf_devvp, LK_EXCLUSIVE | LK_RETRY);
+			VOP_FDISCARD(fs->xf_devvp,
+				EXFATFS_LC2D(fs, pcn) << DEV_BSHIFT,
+				EXFATFS_C2B(fs, 1));
+			VOP_UNLOCK(fs->xf_devvp);
 		} else
 			brelse(bp, 0);
 		++lcn;
@@ -2368,19 +2375,23 @@ detrunc(struct xfinode *xip, off_t bytes
 	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;
+	uint32_t pcn;
 
 	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);
-			}
+			/* If we are contiguous, we can use dead reckoning */
+			pcn = GET_DSE_FIRSTCLUSTER(xip) + newcount;
+			exfatfs_bitmap_dealloc(fs, pcn, oldcount - newcount);
+
+			/* Notify underlying device for TRIM */
+			vn_lock(fs->xf_devvp, LK_EXCLUSIVE | LK_RETRY);
+			VOP_FDISCARD(fs->xf_devvp,
+				EXFATFS_LC2D(fs, pcn) << DEV_BSHIFT,
+				EXFATFS_C2B(fs, oldcount - newcount));
+			VOP_UNLOCK(fs->xf_devvp);
 		} else {
 			/* If not we need to walk the FAT */
 			detrunc_fat(xip, bytes, ioflags, cred);

Reply via email to