trim: Target SCSI UNMAP command instead of WRITE SAME.

* The UNMAP command is theoretically much faster, as it can get many block
  ranges instead of just a single range.
* Furthermore, the ATA TRIM command resembles it much better.
* Therefore, fs_trim_data now gets an array of ranges, and we use SCSI UNMAP
  to trim.
* Updated BFS code to collect array ranges to fully support the new
  fs_trim_data possibilities.
This commit is contained in:
Axel Dörfler
2013-11-07 19:03:47 +01:00
parent 960c56aea5
commit 99086aa323
13 changed files with 249 additions and 64 deletions
+6 -3
View File
@@ -172,9 +172,12 @@ typedef struct {
/* B_TRIM_DEVICE data structure */
typedef struct {
off_t offset; /* offset (in bytes) */
off_t size;
off_t trimmed_size; /* filled on return */
uint32 range_count;
uint64 trimmed_size; /* filled on return */
struct range {
uint64 offset; /* offset (in bytes) */
uint64 size;
} ranges[1];
} fs_trim_data;
+35 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2004-2010, Haiku, Inc. All RightsReserved.
* Copyright 2004-2013, Haiku, Inc. All RightsReserved.
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
*
* Distributed under the terms of the MIT License.
@@ -185,6 +185,8 @@
#define SCSI_OP_WRITE_BUFFER 0x3b
#define SCSI_OP_READ_BUFFER 0x3c
#define SCSI_OP_CHANGE_DEFINITION 0x40
#define SCSI_OP_WRITE_SAME_10 0x41
#define SCSI_OP_UNMAP 0x42
#define SCSI_OP_READ_SUB_CHANNEL 0x42
#define SCSI_OP_READ_TOC 0x43
#define SCSI_OP_PLAY_MSF 0x47
@@ -457,7 +459,38 @@ typedef struct scsi_cmd_wsame_16 {
);
uint8 control;
} _PACKED scsi_cmd_wsame_16;
// UNMAP
typedef struct scsi_cmd_unmap {
uint8 opcode;
LBITFIELD8_2(
anchor : 1,
_reserved1_7 : 7
);
uint32 _reserved1;
LBITFIELD8_2(
group_number : 5,
_reserved5_7 : 3
);
uint16 length;
uint8 control;
} _PACKED scsi_cmd_unmap;
struct scsi_unmap_block_descriptor {
uint64 lba;
uint32 block_count;
uint32 _reserved1;
} _PACKED;
struct scsi_unmap_parameter_list {
uint16 data_length;
uint16 block_data_length;
uint32 _reserved1;
struct scsi_unmap_block_descriptor blocks[1];
} _PACKED;
// REQUEST SENSE
+5 -1
View File
@@ -72,6 +72,10 @@ typedef struct scsi_periph_callbacks {
void (*media_changed)(periph_device_cookie cookie, scsi_ccb *request);
} scsi_periph_callbacks;
typedef struct scsi_block_range {
uint64 offset;
uint64 size;
} scsi_block_range;
// functions provided by this module
typedef struct scsi_periph_interface {
@@ -119,7 +123,7 @@ typedef struct scsi_periph_interface {
err_res (*synchronize_cache)(scsi_periph_device device, scsi_ccb *request);
status_t (*trim_device)(scsi_periph_device_info *device, scsi_ccb *request,
uint64 offset, uint64 numBlocks);
scsi_block_range* ranges, uint32 rangeCount);
// *** removable media ***
// to be called when a medium change is detected to block subsequent commands
+6 -3
View File
@@ -215,9 +215,12 @@ typedef struct {
/* B_TRIM_DEVICE data structure */
typedef struct {
fssh_off_t offset; /* offset (in bytes) */
fssh_off_t size;
fssh_off_t trimmed_size; /* filled on return */
uint32_t range_count;
uint64_t trimmed_size; /* filled on return */
struct range {
uint64_t offset; /* offset (in bytes) */
uint64_t size;
} ranges[1];
} fssh_fs_trim_data;
@@ -0,0 +1,48 @@
/*
* Copyright 2013, Axel Dörfler, [email protected].
* Distributed under the terms of the MIT license.
*/
#ifndef _FS_TRIM_SUPPORT_H
#define _FS_TRIM_SUPPORT_H
#include <Drivers.h>
#include <kernel.h>
static inline status_t
copy_trim_data_from_user(void* buffer, size_t size, fs_trim_data*& _trimData)
{
if (!IS_USER_ADDRESS(buffer))
return B_BAD_ADDRESS;
uint32 count;
if (user_memcpy(&count, buffer, sizeof(count)) != B_OK)
return B_BAD_ADDRESS;
size_t bytes = (count - 1) * sizeof(uint64) * 2 + sizeof(fs_trim_data);
if (bytes > size)
return B_BAD_VALUE;
void* trimBuffer = malloc(bytes);
if (trimBuffer == NULL)
return B_NO_MEMORY;
if (user_memcpy(trimBuffer, buffer, bytes) != B_OK)
return B_BAD_ADDRESS;
_trimData = (fs_trim_data*)trimBuffer;
return B_OK;
}
static inline status_t
copy_trim_data_to_user(void* buffer, fs_trim_data* trimData)
{
// Do not copy any ranges
return user_memcpy(buffer, trimData, sizeof(uint64) * 2);
}
#endif // _FS_TRIM_SUPPORT_H