scst_user: Document the current userspace ABI

The scst_user specification copies ioctl structures and command payloads
that predate several ABI extensions. Building a handler from those
layouts can select the wrong union member, alignment or completion path.

Commit 3fc775c75a ("EXTENDED COPY support") added remapping payloads.
Commit daee4dcb7e ("WRITE SAME command improvements") added WRITE
SAME descriptors. Commit d1bd22afd9 ("scst_user: avoid global locks")
left the explicit unregister ioctl as an obsolete no-op.

Use scst/include/scst_user.h and scst_user.c as the producer-side
source of truth. Synchronize registration, command, reply and subcommand
layouts, version checks, reserved fields and ioctl rules.

Update the fileio_tgt, stpgd and event guides from current code. Make
live-storage and event-consumption risks explicit.
This commit is contained in:
Gleb Chesnokov
2026-08-21 10:05:36 +03:00
parent 59e915e822
commit e7ad7e093e
4 changed files with 380 additions and 183 deletions
+228 -111
View File
@@ -25,8 +25,9 @@ feature virtual SCSI devices in the SCST environment.
This document assumes that the reader is familiar with the SCST
architecture and the states through which SCSI commands go during
processing in SCST. Module scst_user basically only provides hooks to
them. Their description could be found on the SCST web page on
http://scst.sf.net.
them. See doc/scst_pg.sgml for an architecture overview and verify current
lifecycle details against scst/include/scst.h and
scst/src/dev_handlers/scst_user.c.
<sect> User space API
@@ -50,21 +51,23 @@ following system calls available:
Device /dev/scst_user could be opened in blocking or non-blocking mode
using O_NONBLOCK flag. In the blocking mode ioctl()
SCST_USER_REPLY_GET_CMD function blocks until there is a new subcommand
SCST_USER_REPLY_AND_GET_CMD function blocks until there is a new subcommand
to process. In the non-blocking mode if there are no pending subcommands
SCST_USER_REPLY_GET_CMD function returns immediately with EAGAIN error
SCST_USER_REPLY_AND_GET_CMD function returns immediately with EAGAIN error
code, and the user space device handler can use poll() call to get
notification about new subcommands arrival. The blocking mode is the
default.
The module scst_user API is defined in scst_user.h file.
The module scst_user ABI is defined by scst/include/scst_user.h. Structure
definitions in this document are explanatory copies; use the installed header
when building a handler and update this document whenever that header changes.
<sect> IOCTL() functions
<p>
There are following IOCTL functions available. All of them has one
argument. They all, except SCST_USER_REGISTER_DEVICE return 0 for
success or -1 in case of error, and errno is set appropriately.
The following IOCTL functions are available. Their arguments, where
applicable, are described below. They return 0 for success or -1 in case
of error, and errno is set appropriately.
<sect1> SCST_USER_REGISTER_DEVICE
@@ -82,12 +85,12 @@ struct scst_user_dev_desc
uint8_t sgv_disable_clustered_pool;
int32_t sgv_single_alloc_pages;
int32_t sgv_purge_interval;
uint8_t has_own_order_mgmt;
struct scst_user_opt opt;
uint32_t block_size;
uint8_t enable_pr_cmds_notifications;
char name[SCST_MAX_NAME];
char sgv_name[SCST_MAX_NAME];
},
};
</verb>
where:
@@ -96,11 +99,9 @@ where:
<item> <bf/version_str/ - protocol version, shall be DEV_USER_VERSION.
<item> <bf/license_str/ - license of this module, for instance, "GPL", "GPL v2", or
"Proprietary". This field serves the same purpose as macroses
EXPORT_SYMBOL/EXPORT_SYMBOL_GPL of the Linux kernel. You can find
more info about it, if you ask at license@scst-tgt.com e-mail
address.
<item> <bf/license_str/ - pointer to the handler license string. The kernel
accepts only the GPL-compatible strings enumerated by
dev_user_check_version() in scst_user.c; usr/fileio uses "GPL".
<item> <bf/type/ - SCSI type of the device.
@@ -118,8 +119,8 @@ where:
<item> <bf/sgv_single_alloc_pages/ - if 0, then the SGV cache for this device will
work in the set of power 2 size buffers mode. If >0, then the SGV
cache will work in the fixed size buffers mode. In this case it sets
the size of each buffer in pages. See the SGV cache documentation
(http://scst.sourceforge.net/sgv_cache.txt) for more details.
the size of each buffer in pages. See the SGV cache section in
doc/scst_pg.sgml for more details.
<item> <bf/sgv_purge_interval/ - sets the SGV cache purging interval. I.e. an SG
buffer will be freed if it's unused for time t purge_interval <= t <
@@ -128,24 +129,23 @@ where:
purging will be disabled. Shrinking by the system's demand will also
be disabled.
<item> <bf/has_own_order_mgmt/ - set it in non-zero, if device implements own
ORDERED commands management, i.e. guarantees commands execution order
requirements, specified by SAM.
<item> <bf/opt/ - device options, see SCST_USER_SET_OPTIONS/SCST_USER_GET_OPTIONS below
<item> <bf/block_size/ - block size, shall be divisible by 512 for block devices
<item> <bf/enable_pr_cmds_notifications/ - if nonzero, successful PERSISTENT
RESERVE OUT commands are passed to the user-space handler for notification.
<item> <bf/name/ - name of the device
<item> <bf/sgv_name/ - name of SGV cache for this device
</itemize>
SCST_USER_REGISTER_DEVICE returns registered device's handler or -1
in case of error, and errno is set appropriately.
SCST_USER_REGISTER_DEVICE returns 0 on success or -1 in case of error,
and errno is set appropriately. The registration is associated with the
open file descriptor.
In order to unregister the device, either call SCST_USER_UNREGISTER_DEVICE
function, or close on its file descriptor.
Close the device's file descriptor to unregister it.
<sect1> SCST_USER_UNREGISTER_DEVICE
@@ -171,16 +171,20 @@ struct scst_user_opt
uint8_t on_free_cmd_type;
uint8_t memory_reuse_type;
uint8_t partial_transfers_type;
uint32_t partial_len;
int32_t partial_len;
uint8_t tst;
uint8_t tmf_only;
uint8_t queue_alg;
uint8_t qerr;
uint8_t tas;
uint8_t swp;
uint8_t d_sense;
uint8_t has_own_order_mgmt;
},
uint8_t ext_copy_remap_supported;
};
</verb>
where:
@@ -233,18 +237,12 @@ where:
<item> <bf/SCST_USER_MEM_REUSE_ALL/ - unlimited memory reuse is possible.
</itemize>
<item> <bf/partial_transfers_type/ - defines if the user space handler supports
partial data transfers, when a SCSI command, which required big data
transfer, is broken on several subcommands with smaller data
transfers. This allows to improve performance by simultaneous data
transfers from/to remote initiator and to/from the underlying storage
device as well as lower allocation memory requirements for each
(sub)command. All subcommands will have the same unique value in
"parent_cmd_h" field and SCST_USER_SUBCOMMAND flag in "partial" field
of struct scst_user_scsi_cmd_exec. The final subcommand will also
have in that field SCST_USER_SUBCOMMAND_FINAL flag. All the
subcommands will have the original unmodified CDB. Possible values
are:
<item> <bf/partial_transfers_type/ and <bf/partial_len/ are retained in
the ABI for partial-transfer support. The current implementation does
not split SCSI commands into subcommands, so only
SCST_USER_PARTIAL_TRANSFERS_NOT_SUPPORTED describes its behavior. The
header still defines and the setter accepts these other values, but
they do not enable splitting:
<itemize>
<item> <bf/SCST_USER_PARTIAL_TRANSFERS_NOT_SUPPORTED/ - the partial data
@@ -258,13 +256,16 @@ where:
are supported without limitations.
</itemize>
<item> <bf/tst/, <bf/queue_alg/, <bf/tas/, <bf/swp/, <bf/d_sense/ - set values for TST,
QUEUE ALGORITHM MODIFIER, TAS, SWP and D_SENSE fields from control mode page correspondingly,
see SPC.
<item> <bf/tst/, <bf/tmf_only/, <bf/queue_alg/, <bf/qerr/, <bf/tas/,
<bf/swp/, <bf/d_sense/ - set the corresponding fields from the SCSI control
mode page; see SPC.
<item> <bf/has_own_order_mgmt/ - true, if the user space handler has full
commands execution order management, i.e. guarantees commands execution
order as required by SAM. False otherwise.
<item> <bf/ext_copy_remap_supported/ - if nonzero, the handler supports
SCST_USER_EXT_COPY_REMAP subcommands.
</itemize>
Flags <it/parse_type/ and <it/on_free_cmd_type/ are designed to improve
@@ -301,7 +302,7 @@ struct scst_user_get_cmd
uint32_t cmd_h;
uint32_t subcode;
union {
uint64_t preply;
aligned_u64 preply;
struct scst_user_sess sess;
struct scst_user_scsi_cmd_parse parse_cmd;
struct scst_user_scsi_cmd_alloc_mem alloc_cmd;
@@ -309,8 +310,9 @@ struct scst_user_get_cmd
struct scst_user_scsi_on_free_cmd on_free_cmd;
struct scst_user_on_cached_mem_free on_cached_mem_free;
struct scst_user_tm tm_cmd;
struct scst_user_ext_copy_remap remap_cmd;
};
},
};
</verb>
where:
@@ -350,8 +352,9 @@ struct scst_user_get_multi {
int16_t replies_cnt;
int16_t replies_done;
int16_t cmds_cnt;
struct scst_user_get_cmd cmds[0];
},
int16_t pad;
struct scst_user_get_cmd cmds[];
};
</verb>
where:
@@ -396,8 +399,9 @@ struct scst_user_reply_cmd
struct scst_user_scsi_cmd_reply_parse parse_reply;
struct scst_user_scsi_cmd_reply_alloc_mem alloc_reply;
struct scst_user_scsi_cmd_reply_exec exec_reply;
struct scst_user_ext_copy_reply_remap remap_reply;
};
},
};
</verb>
where:
@@ -417,20 +421,33 @@ where:
<verb>
struct scst_user_scsi_cmd_reply_parse
{
uint8_t queue_type;
uint8_t data_direction;
uint16_t cdb_len;
aligned_i64 lba;
uint32_t op_flags;
aligned_i64 data_len;
int32_t bufflen;
int32_t out_bufflen;
},
uint8_t status;
union {
struct {
uint8_t queue_type;
uint8_t data_direction;
uint16_t cdb_len;
aligned_i64 lba;
aligned_i64 data_len;
int32_t bufflen;
uint32_t op_flags;
int32_t out_bufflen;
};
struct {
uint8_t sense_len;
aligned_u64 psense_buffer;
};
};
};
</verb>
where:
<itemize>
<item> <bf/status/ - zero for a successful parse. A nonzero value is the SAM
status to return; sense_len and psense_buffer then describe optional sense
data.
<item> <bf/queue_type/ - SCSI task attribute (queue type). NOTE! In current
implementation setting changing this field from the provided value
affects commands execution only when then produced by iSCSI-SCST
@@ -457,6 +474,11 @@ where:
<item> <bf/bufflen/ - command's buffer length
<item> <bf/out_bufflen/ - command's out buffer length (for bidirectional commands)
<item> <bf/sense_len/ - length of sense data in psense_buffer for a nonzero
status
<item> <bf/psense_buffer/ - pointer to sense data for a nonzero status
</itemize>
<bf/OR/
@@ -464,8 +486,8 @@ where:
<verb>
struct scst_user_scsi_cmd_reply_alloc_mem
{
uint64_t pbuf;
},
aligned_u64 pbuf;
};
</verb>
where:
@@ -477,22 +499,41 @@ where:
<bf/OR/
<verb>
struct scst_user_data_descriptor
{
aligned_u64 usdd_lba;
aligned_u64 usdd_blocks;
};
struct scst_user_scsi_cmd_reply_exec
{
int32_t resp_data_len;
uint64_t pbuf;
aligned_u64 pbuf;
uint8_t reply_type;
uint8_t status;
uint8_t sense_len;
aligned_u64 psense_buffer;
},
union {
struct {
uint8_t sense_len;
aligned_u64 psense_buffer;
};
struct {
uint16_t ws_descriptors_len;
aligned_u64 ws_descriptors;
};
};
};
</verb>
where:
<itemize>
<item> <bf/usdd_lba/ - first LBA of a WRITE SAME range
<item> <bf/usdd_blocks/ - number of blocks in the range. The descriptor array
must end with an entry whose usdd_blocks value is zero.
<item> <bf/resp_data_len/ - length of the response data
<item> <bf/pbuf/ - pointer to command's data buffer. Used only when in the
@@ -519,6 +560,11 @@ where:
memory can be safely reused for other needs.
<item> <bf/SCST_EXEC_REPLY_COMPLETED/ - the user space handler completed the command
<item> <bf/SCST_EXEC_REPLY_DO_WRITE_SAME/ - asks SCST to process a WRITE
SAME command using the array of scst_user_data_descriptor entries
referenced by ws_descriptors. This value is valid only for WRITE SAME
commands and requires a zero status.
</itemize>
<item> <bf/status/ - SAM status of the commands execution
@@ -526,6 +572,11 @@ where:
<item> <bf/sense_len/ - length of sense data in psense_buffer, if any
<item> <bf/psense_buffer/ - pointed to sense buffer
<item> <bf/ws_descriptors_len/ - size in bytes of the WRITE SAME descriptor
array
<item> <bf/ws_descriptors/ - pointer to the WRITE SAME descriptor array
</itemize>
@@ -574,7 +625,7 @@ SCST_USER_GET_EXTENDED_CDB has the following arguments:
struct scst_user_get_ext_cdb {
uint32_t cmd_h;
aligned_u64 ext_cdb_buffer;
},
};
</verb>
where:
@@ -600,7 +651,7 @@ It has the following arguments:
union scst_user_prealloc_buffer {
struct scst_user_prealloc_buffer_in in;
struct scst_user_prealloc_buffer_out out;
},
};
</verb>
where:
@@ -618,7 +669,7 @@ struct scst_user_prealloc_buffer_in {
aligned_u64 pbuf;
uint32_t bufflen;
uint8_t for_clust_pool;
},
};
</verb>
where:
@@ -638,7 +689,7 @@ Structure <it/scst_user_prealloc_buffer_out/ has the following definition:
<verb>
struct scst_user_prealloc_buffer_out {
uint32_t cmd_h;
}
};
</verb>
where:
@@ -663,15 +714,15 @@ contains struct scst_user_sess, which is defined as the following:
<verb>
struct scst_user_sess
{
uint64_t sess_h;
uint64_t lun;
aligned_u64 sess_h;
aligned_u64 lun;
uint16_t threads_num;
uint8_t rd_only;
uint16_t scsi_transport_version;
uint16_t phys_transport_version;
char initiator_name[SCST_MAX_NAME];
char target_name[SCST_MAX_NAME];
},
char initiator_name[SCST_MAX_EXTERNAL_NAME];
char target_name[SCST_MAX_EXTERNAL_NAME];
};
</verb>
where:
@@ -739,17 +790,17 @@ the following:
<verb>
struct scst_user_scsi_cmd_parse
{
uint64_t sess_h;
aligned_u64 sess_h;
uint8_t cdb[SCST_MAX_CDB_SIZE];
uint16_t cdb_len;
aligned_i64 lba;
uint32_t timeout;
int32_t bufflen;
aligned_i64 data_len;
int32_t bufflen;
int32_t out_bufflen;
int32_t timeout;
uint32_t op_flags;
@@ -762,7 +813,7 @@ struct scst_user_scsi_cmd_parse
int32_t expected_out_transfer_len;
uint32_t sn;
},
};
</verb>
where:
@@ -808,11 +859,15 @@ where:
<item> <bf/sn/ - command's SN, which might be used for task management
</itemize>
Bits of scst_cdb_flags can be:
The bit values are defined by enum scst_cdb_flags in
scst/include/scst_const.h. Treat that header as authoritative; the common
parsing flags below are not an exhaustive copy of the enum:
<itemize>
<item> <bf/SCST_TRANSFER_LEN_TYPE_FIXED/ - this command uses fixed blocks addressing
<item> <bf/SCST_UNKNOWN_LBA/ - the parser could not determine the command LBA
<item> <bf/SCST_SMALL_TIMEOUT/ - this command needs small timeout
<item> <bf/SCST_LONG_TIMEOUT/ - this command needs a long timeout
@@ -821,6 +876,8 @@ Bits of scst_cdb_flags can be:
<item> <bf/SCST_INFO_VALID/ - bits of op_flags are valid
<item> <bf/SCST_LBA_NOT_VALID/ - the command does not have an LBA
<item> <bf/SCST_IMPLICIT_HQ/ - this command is an implicit HEAD OF QUEUE command
<item> <bf/SCST_SKIP_UA/ - Unit Attentions shouldn't be delivered for this command
@@ -829,6 +886,9 @@ Bits of scst_cdb_flags can be:
forbidden for read-only devices
<item> <bf/SCST_LOCAL_CMD/ - this command can be processed by SCST core.
<item> <bf/SCST_FULLY_LOCAL_CMD/ - the command is handled entirely by the SCST
core without device-handler parse or completion callbacks
</itemize>
In the PARSE state of SCSI commands processing the user space device
@@ -863,7 +923,7 @@ as the following:
<verb>
struct scst_user_scsi_cmd_alloc_mem
{
uint64_t sess_h;
aligned_u64 sess_h;
uint8_t cdb[SCST_MAX_CDB_SIZE];
uint16_t cdb_len;
@@ -874,7 +934,7 @@ struct scst_user_scsi_cmd_alloc_mem
uint8_t data_direction;
uint32_t sn;
},
};
</verb>
where:
@@ -912,8 +972,7 @@ caches unused SG vectors for future allocations to improve performance.
Then, after some time of inactivity or when the system is under memory
pressure, the cache entries will be freed and the user space handler
will be notified using SCST_USER_ON_CACHED_MEM_FREE. See the SGV cache
documentation <url url="http://scst.sourceforge.net/sgv_cache.txt"> for more
details.
section in doc/scst_pg.sgml for more details.
Since the SGV cache caches SG vectors, which can be bigger, than actual
data sizes of SCSI commands, alloc_len field could also be bigger, than
@@ -969,7 +1028,7 @@ following:
<verb>
struct scst_user_scsi_cmd_exec
{
uint64_t sess_h;
aligned_u64 sess_h;
uint8_t cdb[SCST_MAX_CDB_SIZE];
uint16_t cdb_len;
@@ -979,11 +1038,11 @@ struct scst_user_scsi_cmd_exec
aligned_i64 data_len;
int32_t bufflen;
int32_t alloc_len;
uint64_t pbuf;
aligned_u64 pbuf;
uint8_t queue_type;
uint8_t data_direction;
uint8_t partial;
uint32_t timeout;
int32_t timeout;
aligned_u64 p_out_buf;
int32_t out_bufflen;
@@ -993,7 +1052,7 @@ struct scst_user_scsi_cmd_exec
uint32_t parent_cmd_h;
int32_t parent_cmd_data_len;
uint32_t partial_offset;
},
};
</verb>
where:
@@ -1024,14 +1083,8 @@ where:
<item> <bf/data_direction/ - command's data flow direction, one of SCST_DATA_*
constants
<item> <bf/partial/ - specifies, if the command is a partial subcommand, could
have the following OR'ed flags:
<itemize>
<item> <bf/SCST_USER_SUBCOMMAND/ - set if the command is a partial subcommand
<item> <bf/SCST_USER_SUBCOMMAND_FINAL/ - set if the subcommand is a final one
</itemize>
<item> <bf/partial/ - reserved for partial-transfer metadata. The current
implementation sets it to zero.
<item> <bf/timeout/ - CDB execution timeout
@@ -1044,24 +1097,86 @@ where:
<item> <bf/sn/ - command's SN, which might be used for task management
<item> <bf/parent_cmd_h/ - has the same unique value for all partial data
transfers subcommands of one original (parent) command
<item> <bf/parent_cmd_data_len/ - for partial data transfers subcommand has the
size of the overall data transfer of the original (parent) command
<item> <bf/partial_offset/ - has offset of the subcommand in the original
(parent) command
<item> <bf/parent_cmd_h/, <bf/parent_cmd_data_len/, and
<bf/partial_offset/ - reserved for partial-transfer metadata and not
populated by the current implementation.
</itemize>
It is guaranteed that only commands of the same queue_type per session
can be returned simultaneously.
In case of any error it should be reported via appropriate SAM status
and sense. If it happens for a subcommand of a partial data transfers
command, all other subcommands of this command, which already passed the
the user space handler or will be passed in the future, will be aborted
by scst_user, the user space handler should ignore them.
and sense.
<sect1> SCST_USER_EXT_COPY_REMAP
<p>
SCST_USER_EXT_COPY_REMAP asks a handler that advertised
ext_copy_remap_supported to remap an EXTENDED COPY segment. The payload
contains the current device session, source and destination sessions, and the
range to remap:
<verb>
struct scst_user_ext_copy_data_descr
{
aligned_u64 src_lba;
aligned_u64 dst_lba;
int32_t data_len;
};
struct scst_user_ext_copy_remap
{
aligned_u64 sess_h;
aligned_u64 src_sess_h;
aligned_u64 dst_sess_h;
struct scst_user_ext_copy_data_descr data_descr;
};
</verb>
where:
<itemize>
<item> <bf/sess_h/ - session handle of the EXTENDED COPY command
<item> <bf/src_sess_h/ - session handle for the source device
<item> <bf/dst_sess_h/ - session handle for the destination device
<item> <bf/src_lba/ - first source LBA
<item> <bf/dst_lba/ - first destination LBA
<item> <bf/data_len/ - length of the range in bytes
</itemize>
The corresponding reply payload is:
<verb>
struct scst_user_ext_copy_reply_remap
{
aligned_u64 remap_descriptors;
uint16_t remap_descriptors_len;
uint8_t status;
uint8_t sense_len;
aligned_u64 psense_buffer;
};
</verb>
<itemize>
<item> <bf/remap_descriptors/ - pointer to an array of
scst_user_ext_copy_data_descr entries for ranges the handler did not remap
<item> <bf/remap_descriptors_len/ - size of that array in bytes. A zero length
reports that the entire segment was remapped.
<item> <bf/status/ - SAM status. A nonzero status reports a remap error instead
of leftover ranges.
<item> <bf/sense_len/ - length of optional sense data for a nonzero status
<item> <bf/psense_buffer/ - pointer to the optional sense data
</itemize>
<sect1> SCST_USER_ON_FREE_CMD
@@ -1081,13 +1196,13 @@ as the following:
<verb>
struct scst_user_scsi_on_free_cmd
{
uint64_t pbuf;
aligned_u64 pbuf;
int32_t resp_data_len;
uint8_t buffer_cached;
uint8_t aborted;
uint8_t status;
uint8_t delivery_status;
},
};
</verb>
where:
@@ -1111,6 +1226,8 @@ where:
<item> <bf/SCST_CMD_DELIVERY_SUCCESS/ - delivery succeeded
<item> <bf/SCST_CMD_DELIVERY_FAILED/ - delivery failed
<item> <bf/SCST_CMD_DELIVERY_ABORTED/ - delivery was aborted
</itemize>
</itemize>
@@ -1129,10 +1246,10 @@ Payload contains struct scst_user_on_cached_mem_free, which is defined
as the following:
<verb>
struct scst_user_scsi_cmd_alloc_mem
struct scst_user_on_cached_mem_free
{
uint64_t pbuf;
},
aligned_u64 pbuf;
};
</verb>
where:
@@ -1152,12 +1269,12 @@ is defined as the following:
<verb>
struct scst_user_tm
{
uint64_t sess_h;
aligned_u64 sess_h;
uint32_t fn;
uint32_t cmd_h_to_abort;
uint32_t cmd_sn;
uint8_t cmd_sn_set;
},
};
</verb>
where:
+43 -2
View File
@@ -1,2 +1,43 @@
This is test/demo application for SCST events subsystem. For more
information about this subsystem, see scst_event.h file.
SCST events example
===================
events is a test and demonstration consumer for the SCST event ABI. The
authoritative ioctl definitions, wildcard rules, event codes, and payload
layouts are in scst/include/scst_event.h and scst/src/scst_event.c. The
example's current behavior is implemented in usr/events/events.c.
Build
-----
The example is intentionally omitted from the default "make usr" build and
install targets. Build it explicitly with "make -C usr/events". Installing or
running it is not required for normal SCST operation.
Usage
-----
events opens /dev/scst_event, registers one or more filters, and prints the
events it receives.
events [OPTIONS]
- -e, --allowed_event=CODE: allow CODE; zero matches any event code
- -i, --allowed_issuer=ISSUER: allow ISSUER; "*" matches any issuer
- -n, --non_blocking: use nonblocking event retrieval
- -v, --version: print the program version
- -h, --help: print usage information
The -d/--debug option is present only when tracing or debugging is compiled
in. Repeat an event-code/issuer pair to add filters, up to the implementation
limit. With no filter options, the program subscribes to every event code from
every issuer.
Safety
------
Do not run this example on a live target or alongside a production event
consumer such as stpgd. Its default wildcard subscription can receive an
event that requires SCST_EVENT_NOTIFY_DONE, while the example only sends a
completion for its synthetic event code 0x12345. A real completion-bearing
event can therefore be diverted from its intended consumer and remain pending
until the kernel timeout.
+49 -62
View File
@@ -2,82 +2,69 @@ User space FILEIO handler
=========================
Version 3.11.0-pre, 29 December 2025
----------------------------
------------------------------------
User space program fileio_tgt uses interface of SCST's scst_user dev
handler and allows to see how it works in various modes. Fileio_tgt
provides mostly the same functionality as the kernel space SCST's
scst_vdisk handler with the only exceptions that it supports O_DIRECT
mode and doesn't support BLOCKIO one. O_DIRECT mode is basically the
same as BLOCKIO, but also supports files, so for some loads it could be
significantly faster, than the regular FILEIO access. All the words
about BLOCKIO mode from SCST's README file apply to O_DIRECT mode as
well.
fileio_tgt is a user-space disk handler that demonstrates and exercises the
SCST scst_user interface. The interface is defined by
scst/include/scst_user.h and documented in doc/scst_user_spec.sgml.
Installation
------------
Build
-----
Make sure you have installed SCST core, if not, see its README file for
details how to do it.
Then run "make all install"
For the best performance make sure you don't have any debug options
(i.e. lines like "CFLAGS += -DDEBUG" containing "-DDEBUG*" string)
enabled in the Makefile.
From the repository root, "make usr" builds fileio_tgt and stpgd. To build
only this program, run "make -C usr/fileio". Installation is a separate,
privileged operation; use the corresponding install target only when system
installation is intended.
Usage
-----
Load scst_user module using modprobe or insmod, then start fileio_tgt
program. It can be used as the following:
The scst_user kernel module must be loaded before fileio_tgt is started.
Running fileio_tgt registers live SCST devices and opens every supplied
backing path. Unless read-only mode is selected, initiators can cause writes
to those paths. Do not use a real block device or valuable backing file
without an explicitly prepared test configuration.
fileio_tgt [OPTION] name path
fileio_tgt [OPTIONS] name path [name path] ...
Where:
- OPTION - one or several not required options, see below.
- name - name of the virtual device as it will be seen by SCST and used
in the subsequent access management using the corresponding SCST interface.
- path - path to the device file.
Each name is the SCST device name used by later access-management operations.
Each path is the backing file or device from which the handler determines the
virtual device size. Up to the implementation limit, multiple name/path pairs
can be registered by one process.
The following options are supported:
-b or --block=size: block size, must be power of 2 and >=512
- -b, --block=size: block size; it must be a power of two and at least 512
- -e, --threads=count: number of worker threads
- -t, --write_through: write-through mode
- -r, --read_only: read-only mode
- -o, --direct: open the backing path with O_DIRECT for data I/O
- -n, --nullio: NULLIO mode; see scst/README for its safety warning
- -c, --nv_cache: NV_CACHE mode; see scst/README for its semantics
- -p, --parse=type: "std" (default), "call", or "excpt"
- -f, --on_free=type: "ignore" (default) or "call"
- -m, --mem_reuse=type: "all" (default), "read", "write", or "none"
- -l, --non_blocking: use nonblocking scst_user operations
- -I, --vdisk_id=ID: virtual disk ID for multi-target setups
- -F, --flush=n: flush the SGV cache every n seconds
- -s, --sgv_shared: share the first device's SGV cache
- -S, --sgv_single_cache=n: use a single-entry SGV cache with n pages
- -P, --sgv_purge_interval=n: set the SGV purge interval in seconds
- -u, --unreg_before_close: exercise the obsolete unregister ioctl
- -D, --sgv_disable_clustered_pool: disable the clustered SGV pool
- -R, --prealloc_buffers=n: preallocate n buffers
- -Z, --prealloc_buffer_size=n: preallocated buffer size in KiB
- -M, --multi_cmd=v: enable or disable multi-command processing (default 1)
- -v, --version: print the program version
- -h, --help: print usage information
-e or --threads=count: number of threads
The following options are present only when their corresponding tracing or
debug feature is compiled in:
-t or --write_through: write through mode
- -d, --debug=level: tracing level
- -g, --debug_tm_ignore: enable the DEBUG_TM_IGNORE test feature
-r or --read_only: read only
-o or --direct: O_DIRECT mode, see above for details
-n or --nullio: NULLIO mode, see SCST's README file for details
-c or --nv_cache: NV_CACHE mode, see SCST's README file for details
-p or --parse=type: parse type, one of "std" (default), "call" or "excpt"
-f or --on_free=type: on free call type, one of "ignore" (default) or "call"
-m or --mem_reuse=type: Memory reuse type, one of "all" (default), "read",
"write" or "none"
-s or --prio_thread: Use separate thread for mgmt (prio) commands
-l or --non_blocking: Use non-blocking operations
Also in the debug builds the following options are supported:
-d or --debug=level: debug tracing level
-g or --debug_tm_ignore: turn on DEBUG_TM_IGNORE, one of the task management
debugging features
If you don't understand some these options, don't use them, default
values provide the best performance.
The current option parser and usage() output in usr/fileio/fileio.c are the
authoritative command-line reference.
Vladislav Bolkhovitin <vst@vlnb.net>, http://scst.sourceforge.net
+60 -8
View File
@@ -1,9 +1,61 @@
This is stpgd service called by the SCST core upon receiving SET TARGET
PORT GROUPS command via SCST events subsystem. In turn, stpgd calls
external script to actually modify ALUA state as requested by the SET
TARGET PORT GROUPS command via cluster manager and SCST sysfs. You can
find example of such script in scst_on_stpg file.
stpgd explicit ALUA helper
==========================
Reason why such dual stage approach is used is, because there is no way
from inside the kernel to control execution of external programs and
there is no way to write a service calling IOCTLs on shell.
stpgd is the user-space consumer for explicit ALUA state-transition events.
It opens the SCST event device, subscribes to events issued by the SCST core,
and handles SCST_EVENT_STPG_USER_INVOKE by executing an external helper once
for each target-port-group descriptor. The helper's exit status is reported
back to the kernel through SCST_EVENT_NOTIFY_DONE.
The event payload and ioctl ABI are defined in scst/include/scst_event.h.
The current event filtering, helper invocation, timeout handling, and
command-line parsing are implemented in usr/stpgd/stpgd_main.c.
Build and invocation
--------------------
From the repository root, "make usr" builds stpgd and fileio_tgt. To build
only this daemon, run "make -C usr/stpgd". Installation is a separate,
privileged operation.
stpgd [OPTIONS]
- -f, --foreground: do not daemonize
- -p, --path=PATH: absolute path to the executable transition helper
- -t, --timeout=SECONDS: helper timeout; the default is 17 seconds
- -v, --version: print the program version
- -h, --help: print usage information
The -d/--debug option is present only when tracing or debugging is compiled
in. Without -p, the daemon uses /usr/local/bin/scst/scst_on_stpg. If a
different installation prefix is used, pass the installed helper path
explicitly.
Helper interface
----------------
The helper receives these five positional arguments, in order:
1. SCST device name
2. previous ALUA state
3. requested ALUA state
4. device-group name
5. target-group name
The same values are supplied as SCST_DEVICE_NAME, SCST_PREV_ALUA_STATE,
SCST_ALUA_STATE, SCST_DEVICE_GROUP, and SCST_TARGET_GROUP in the helper's
environment. The daemon supplies a restricted PATH containing /bin,
/usr/bin, /sbin, and /usr/sbin.
Safety
------
usr/stpgd/scst_on_stpg is only a minimal example. It writes the requested
state directly to the target group's live SCST sysfs attribute; it does not
coordinate replication, fencing, failover, or cluster-manager state. Do not
run stpgd or deploy that helper until the transition workflow has been adapted
and validated for the exact hosts, storage, target groups, and HA stack.
SCST blocks the affected devices around the explicit transition event, as
described in the explicit ALUA section of scst/README. The external helper is
still responsible for performing every site-specific transition safely.