Does OS X sometimes run a TRIM routine with drives that are not explicitly supported?
When an HFS Plus volume is unmounted or ejected, maybe?
Background
Noted recently in Console, whilst repeatedly/aggressively partitioning a simple USB flash drive and erasing its multiple journaled HFS Plus file systems, messages such as this:
2013-12-29 21:56:18.000 kernel[0]: hfs_unmap_free_ext: ignoring trim vol=swivel @ off 4698607616 len 159744
In System Information, the drive – a Kingston DataTraveler 400 – is not treated as a solid state medium, and there's no 'TRIM Support:' line.
I don't do code, but it seems to me that ignoring trim appears in a part of the code – the hfs_unmap_free_extent
routine – that would apply where TRIM is in some way supported.
This leaves me wondering whether – in addition to supposed nanosecond-critical routine(s) that may run whilst a file system is mounted – a lesser-known and relatively crude (less critical) routine can run at other times.
Related
Optimize macbook pro for internal SSD+HDD drives (2011), where the accepted answer drew attention to a July 2011 comment by Hyram in response to an digitaldj.net article by Grant Pannell. Within that comment:
… Apple locked TRIM support for a very good reason — their code works reliably with the SSD’s they’ve chosen to use and no others, because they have programmed in nanosecond-critical timing loops that match perfectly with the access timings of the controllers used in Apple’s SSDs. …
However, a November 2011 digitaldj.net article cast doubt on some of Hyram's statements. In particular:
… There is zero evidence that Apple has specific code to handle their specific SSD hardware for reading and writing. …
Please note, this question is not about third party TRIM Enabler and the like. It's about:
- what's integral to the operating system
– and I'd like authoritative answers. Evidence-based if possible, although I appreciate that the closed source portions of OS X may make this difficult.
From HFS-related source code for the kernel
/*
;________________________________________________________________________________
;
; Routine: hfs_unmap_free_extent
;
; Function: Make note of a range of allocation blocks that should be
; unmapped (trimmed). That is, the given range of blocks no
; longer have useful content, and the device can unmap the
; previous contents. For example, a solid state disk may reuse
; the underlying storage for other blocks.
;
; This routine is only supported for journaled volumes. The extent
; being freed is passed to the journal code, and the extent will
; be unmapped after the current transaction is written to disk.
;
; Input Arguments:
; hfsmp - The volume containing the allocation blocks.
; startingBlock - The first allocation block of the extent being freed.
; numBlocks - The number of allocation blocks of the extent being freed.
;________________________________________________________________________________
*/
static void hfs_unmap_free_extent(struct hfsmount *hfsmp, u_int32_t startingBlock, u_int32_t numBlocks)
{
u_int64_t offset;
u_int64_t length;
u_int64_t device_sz;
int err = 0;
if (hfs_kdebug_allocation & HFSDBG_UNMAP_ENABLED)
KERNEL_DEBUG_CONSTANT(HFSDBG_UNMAP_FREE | DBG_FUNC_START, startingBlock, numBlocks, 0, 0, 0);
if (ALLOC_DEBUG) {
if (hfs_isallocated(hfsmp, startingBlock, numBlocks)) {
panic("hfs: %p: (%u,%u) unmapping allocated blocks", hfsmp, startingBlock, numBlocks);
}
}
if (hfsmp->jnl != NULL) {
device_sz = hfsmp->hfs_logical_bytes;
offset = (u_int64_t) startingBlock * hfsmp->blockSize + (u_int64_t) hfsmp->hfsPlusIOPosOffset;
length = (u_int64_t) numBlocks * hfsmp->blockSize;
/* Validate that the trim is in a valid range of bytes */
if ((offset >= device_sz) || ((offset + length) > device_sz)) {
printf("hfs_unmap_free_ext: ignoring trim vol=%s @ off %lld len %lld \n", hfsmp->vcbVN, offset, length);
err = EINVAL;
}
if (err == 0) {
err = journal_trim_add_extent(hfsmp->jnl, offset, length);
if (err) {
printf("hfs_unmap_free_extent: error %d from journal_trim_add_extent for vol=%s", err, hfsmp->vcbVN);
}
}
}
if (hfs_kdebug_allocation & HFSDBG_UNMAP_ENABLED)
KERNEL_DEBUG_CONSTANT(HFSDBG_UNMAP_FREE | DBG_FUNC_END, err, 0, 0, 0, 0);
}
First appearance in Apple open source: http://www.opensource.apple.com/source/xnu/xnu-2050.9.2/bsd/hfs/hfscommon/Misc/VolumeAllocation.c (Mac OS X 10.8.1)
Most recent appearance: http://www.opensource.apple.com/source/xnu/xnu-2422.1.72/bsd/hfs/hfscommon/Misc/VolumeAllocation.c
Also, from the latter:
/*
* Validation Routine to verify that the TRIM list maintained by the journal
* is in good shape relative to what we think the bitmap should have. We should
* never encounter allocated blocks in the TRIM list, so if we ever encounter them,
* we panic.
*/
…
/*
;________________________________________________________________________________
;
; Routine: hfs_track_unmap_blocks
;
; Function: Make note of a range of allocation blocks that should be
; unmapped (trimmed). That is, the given range of blocks no
; longer have useful content, and the device can unmap the
; previous contents. For example, a solid state disk may reuse
; the underlying storage for other blocks.
;
; This routine is only supported for journaled volumes.
;
; *****NOTE*****:
; This function should *NOT* be used when the volume is fully
; mounted. This function is intended to support a bitmap iteration
; at mount time to fully inform the SSD driver of the state of all blocks
; at mount time, and assumes that there is no allocation/deallocation
; interference during its iteration.,
;
; Input Arguments:
; hfsmp - The volume containing the allocation blocks.
; offset - The first allocation block of the extent being freed.
; numBlocks - The number of allocation blocks of the extent being freed.
; list - The list of currently tracked trim ranges.
;________________________________________________________________________________
*/
… and so on.