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);