DCMD_CAM_DATA_SET_MGNT

QNX SDP8.0Devctl and Ioctl CommandsDeveloper

Send trim or discard instructions to flash storage devices

Synopsis:

#include <sys/dcmd_cam.h>

#define DCMD_CAM_DATA_SET_MGNT   __DIOT(_DCMD_CAM, 26, struct _data_set_mgnt)
            

Arguments to devctl():

Argument Value
filedes A file descriptor obtained by opening the device.
dcmd DCMD_CAM_DATA_SET_MGNT
dev_data_ptr A pointer to a _data_set_mgnt structure followed by one or more _data_set_mgnt_range structure entries.
n_bytes Number of bytes represented by sizeof(struct _data_set_mgnt) plus all _data_set_mgnt_range structure entries.
dev_info_ptr NULL

Description:

This command sends a non-secure TRIM or DISCARD request to a targeted flash storage device (e.g., NVME, UFS, eMMC). These operations tell the device that specific logical block address (LBA) ranges are no longer needed but may be reused at a later time.

Before using this command, determine the set of LBAs to trim. The devctl() function accepts a list of ranges within a single command.

When trimming blocks in a filesystem, use DCMD_FSYS_MAP_OFFSET to map the file's logical offset to its disk location; then send the request to the underlying device instead of the filesystem.

CAUTION:
Don't use this command on read/write power-safe filesystems (i.e., fs-qnx6). Doing so may result in data loss and filesystem corruption. The Power-Safe filesystem issues safe TRIM/DISCARD operations internally.

Input:

One _data_set_mgnt structure, followed by a list of _data_set_mgnt_range structures. These structures define the LBA ranges to trim.

typedef struct _data_set_mgnt {
#define DSM_OPT_TRIM        1
#define DSM_OPT_DISCARD     2
    _Uint32t                opt;
    _Uint32t                nranges;
    _Uint32t                rsvd[4];
/*	DATA_SET_MGNT_RANGE     ranges[ ];  variable length ranges */
} DATA_SET_MGNT;


typedef struct _data_set_mgnt_range {
    _Uint64t				lba;
    _Uint32t				nlba;
    _Uint32t				rsvd;
} DATA_SET_MGNT_RANGE;
            

The input members for _data_set_mgnt include:

opt
The type of operation (TRIM or DISCARD).
nranges
The number of _data_set_mgnt_range entries. This must match the number of _data_set_mgnt_range structures that follow the _data_set_mgnt header. To ensure compatibility across different servers, each devctl() call should include no more than 128 ranges.
rsvd
Reserved. Set this field to zero.

The input members for _data_set_mgnt_range include:

lba
Logical block address.
nlba
The number of logical blocks to process.
rsvd
Reserved. Set this field to zero.
Note:
The LBA size depends on the native size of the device. For SATA, NVME, and eMMC, it's usually 512 bytes. UFS typically uses 4096 bytes.

Output:

None.

Returns:

EOK
Success.
ENOTTY
Unknown command.
ENXIO
One or more ranges are beyond the end of the device.
ENOTBLK
The filedes argument doesn't point to a block device.
ENODEV
The device doesn't support TRIM or DISCARD operations.

Example:

#include <sys/stat.h>
#include <devctl.h>
#include <sys/dcmd_cam.h>

struct trim_data {
    DATA_SET_MGNT header;
    DATA_SET_MGNT_RANGE ranges[8]; /* space for up to 8 ranges in one devctl() call */
};

int trim_blks (int fd) {
    struct stat sbuf;
    struct trim_data trim_cmd;
    memset(&trim_cmd, 0, sizeof(trim_cmd));

    /* Trim the first 100 disk blocks and the last 100 disk blks */
    trim_cmd.ranges[0].lba = 0;
    trim_cmd.ranges[0].nlba = 100;

    /* Determine the start of the last 100 blocks */
    trim_cmd.ranges[1].lba = start_of_last_100;
    trim_cmd.ranges[1].nlba = 100;

    trim_cmd.header.opt = DSM_OPT_TRIM;
    trim_cmd.header.nranges = 2;

    size_t command_size = sizeof(trim_cmd.header) + (sizeof(trim_cmd.ranges[0]) * trim_cmd.header.nranges);
    int error = devctl(fd, DCMD_DATA_SET_MGNT, &trim_cmd, command_size, NULL);
}
            

See also:

devctl() in the QNX OS C Library Reference

Page updated: