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:
@@ -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;
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user