File Index
Files and directories
Sign in
FILE

kublk.h

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/ublk/kublk.h C
  1/* SPDX-License-Identifier: GPL-2.0 */
  2#ifndef KUBLK_INTERNAL_H
  3#define KUBLK_INTERNAL_H
  4
  5#include <unistd.h>
  6#include <stdlib.h>
  7#include <assert.h>
  8#include <stdio.h>
  9#include <stdarg.h>
 10#include <string.h>
 11#include <pthread.h>
 12#include <getopt.h>
 13#include <limits.h>
 14#include <poll.h>
 15#include <fcntl.h>
 16#include <sys/syscall.h>
 17#include <sys/mman.h>
 18#include <sys/ioctl.h>
 19#include <sys/inotify.h>
 20#include <sys/wait.h>
 21#include <sys/eventfd.h>
 22#include <sys/ipc.h>
 23#include <sys/shm.h>
 24#include <linux/io_uring.h>
 25#include <liburing.h>
 26#include <semaphore.h>
 27
 28/* allow ublk_dep.h to override ublk_cmd.h */
 29#include "ublk_dep.h"
 30#include <linux/ublk_cmd.h>
 31
 32#include "utils.h"
 33
 34#define MAX_BACK_FILES   4
 35
 36/****************** part 1: libublk ********************/
 37
 38#define CTRL_DEV		"/dev/ublk-control"
 39#define UBLKC_DEV		"/dev/ublkc"
 40#define UBLKB_DEV		"/dev/ublkb"
 41#define UBLK_CTRL_RING_DEPTH            32
 42#define ERROR_EVTFD_DEVID 	-2
 43
 44#define UBLK_IO_MAX_BYTES               (1 << 20)
 45#define UBLK_MAX_QUEUES_SHIFT		5
 46#define UBLK_MAX_QUEUES                 (1 << UBLK_MAX_QUEUES_SHIFT)
 47#define UBLK_MAX_THREADS_SHIFT		5
 48#define UBLK_MAX_THREADS		(1 << UBLK_MAX_THREADS_SHIFT)
 49#define UBLK_QUEUE_DEPTH                1024
 50
 51struct ublk_dev;
 52struct ublk_queue;
 53struct ublk_thread;
 54
 55struct stripe_ctx {
 56	/* stripe */
 57	unsigned int    chunk_size;
 58};
 59
 60struct fault_inject_ctx {
 61	/* fault_inject */
 62	unsigned long   delay_us;
 63};
 64
 65struct dev_ctx {
 66	char tgt_type[16];
 67	unsigned long flags;
 68	unsigned nr_hw_queues;
 69	unsigned short nthreads;
 70	unsigned queue_depth;
 71	int dev_id;
 72	int nr_files;
 73	char *files[MAX_BACK_FILES];
 74	unsigned int	logging:1;
 75	unsigned int	all:1;
 76	unsigned int	fg:1;
 77	unsigned int	recovery:1;
 78	unsigned int	auto_zc_fallback:1;
 79	unsigned int	per_io_tasks:1;
 80	unsigned int	no_ublk_fixed_fd:1;
 81
 82	int _evtfd;
 83	int _shmid;
 84
 85	/* built from shmem, only for ublk_dump_dev() */
 86	struct ublk_dev *shadow_dev;
 87
 88	/* for 'update_size' command */
 89	unsigned long long size;
 90
 91	union {
 92		struct stripe_ctx 	stripe;
 93		struct fault_inject_ctx fault_inject;
 94	};
 95};
 96
 97struct ublk_ctrl_cmd_data {
 98	__u32 cmd_op;
 99#define CTRL_CMD_HAS_DATA	1
100#define CTRL_CMD_HAS_BUF	2
101	__u32 flags;
102
103	__u64 data[2];
104	__u64 addr;
105	__u32 len;
106};
107
108struct ublk_io {
109	char *buf_addr;
110
111#define UBLKS_IO_NEED_FETCH_RQ		(1UL << 0)
112#define UBLKS_IO_NEED_COMMIT_RQ_COMP	(1UL << 1)
113#define UBLKS_IO_FREE			(1UL << 2)
114#define UBLKS_IO_NEED_GET_DATA           (1UL << 3)
115#define UBLKS_IO_NEED_REG_BUF            (1UL << 4)
116	unsigned short flags;
117	unsigned short refs;		/* used by target code only */
118
119	int tag;
120
121	int result;
122
123	unsigned short buf_index;
124	unsigned short tgt_ios;
125	void *private_data;
126};
127
128struct ublk_tgt_ops {
129	const char *name;
130	int (*init_tgt)(const struct dev_ctx *ctx, struct ublk_dev *);
131	void (*deinit_tgt)(struct ublk_dev *);
132
133	int (*queue_io)(struct ublk_thread *, struct ublk_queue *, int tag);
134	void (*tgt_io_done)(struct ublk_thread *, struct ublk_queue *,
135			    const struct io_uring_cqe *);
136
137	/*
138	 * Target specific command line handling
139	 *
140	 * each option requires argument for target command line
141	 */
142	void (*parse_cmd_line)(struct dev_ctx *ctx, int argc, char *argv[]);
143	void (*usage)(const struct ublk_tgt_ops *ops);
144
145	/* return buffer index for UBLK_F_AUTO_BUF_REG */
146	unsigned short (*buf_index)(const struct ublk_queue *, int tag);
147};
148
149struct ublk_tgt {
150	unsigned long dev_size;
151	unsigned int  sq_depth;
152	unsigned int  cq_depth;
153	const struct ublk_tgt_ops *ops;
154	struct ublk_params params;
155
156	int nr_backing_files;
157	unsigned long backing_file_size[MAX_BACK_FILES];
158	char backing_file[MAX_BACK_FILES][PATH_MAX];
159};
160
161struct ublk_queue {
162	int q_id;
163	int q_depth;
164	struct ublk_dev *dev;
165	const struct ublk_tgt_ops *tgt_ops;
166	struct ublksrv_io_desc *io_cmd_buf;
167
168/* borrow one bit of ublk uapi flags, which may never be used */
169#define UBLKS_Q_AUTO_BUF_REG_FALLBACK	(1ULL << 63)
170#define UBLKS_Q_NO_UBLK_FIXED_FD	(1ULL << 62)
171	__u64 flags;
172	int ublk_fd;	/* cached ublk char device fd */
173	struct ublk_io ios[UBLK_QUEUE_DEPTH];
174};
175
176struct ublk_thread {
177	struct ublk_dev *dev;
178	unsigned idx;
179
180#define UBLKS_T_STOPPING	(1U << 0)
181#define UBLKS_T_IDLE	(1U << 1)
182	unsigned state;
183	unsigned int cmd_inflight;
184	unsigned int io_inflight;
185	struct io_uring ring;
186};
187
188struct ublk_dev {
189	struct ublk_tgt tgt;
190	struct ublksrv_ctrl_dev_info  dev_info;
191	struct ublk_queue q[UBLK_MAX_QUEUES];
192	unsigned nthreads;
193	unsigned per_io_tasks;
194
195	int fds[MAX_BACK_FILES + 1];	/* fds[0] points to /dev/ublkcN */
196	int nr_fds;
197	int ctrl_fd;
198	struct io_uring ring;
199
200	void *private_data;
201};
202
203extern int ublk_queue_io_cmd(struct ublk_thread *t, struct ublk_io *io);
204
205
206static inline int ublk_io_auto_zc_fallback(const struct ublksrv_io_desc *iod)
207{
208	return !!(iod->op_flags & UBLK_IO_F_NEED_REG_BUF);
209}
210
211static inline __u64 ublk_user_copy_offset(unsigned q_id, unsigned tag)
212{
213	return UBLKSRV_IO_BUF_OFFSET +
214	       ((__u64)q_id << UBLK_QID_OFF | (__u64)tag << UBLK_TAG_OFF);
215}
216
217static inline int is_target_io(__u64 user_data)
218{
219	return (user_data & (1ULL << 63)) != 0;
220}
221
222static inline __u64 build_user_data(unsigned tag, unsigned op,
223		unsigned tgt_data, unsigned q_id, unsigned is_target_io)
224{
225	/* we only have 7 bits to encode q_id */
226	_Static_assert(UBLK_MAX_QUEUES_SHIFT <= 7, "UBLK_MAX_QUEUES_SHIFT must be <= 7");
227	assert(!(tag >> 16) && !(op >> 8) && !(tgt_data >> 16) && !(q_id >> 7));
228
229	return tag | (op << 16) | (tgt_data << 24) |
230		(__u64)q_id << 56 | (__u64)is_target_io << 63;
231}
232
233static inline unsigned int user_data_to_tag(__u64 user_data)
234{
235	return user_data & 0xffff;
236}
237
238static inline unsigned int user_data_to_op(__u64 user_data)
239{
240	return (user_data >> 16) & 0xff;
241}
242
243static inline unsigned int user_data_to_tgt_data(__u64 user_data)
244{
245	return (user_data >> 24) & 0xffff;
246}
247
248static inline unsigned int user_data_to_q_id(__u64 user_data)
249{
250	return (user_data >> 56) & 0x7f;
251}
252
253static inline unsigned short ublk_cmd_op_nr(unsigned int op)
254{
255	return _IOC_NR(op);
256}
257
258static inline struct ublk_queue *ublk_io_to_queue(const struct ublk_io *io)
259{
260	return container_of(io, struct ublk_queue, ios[io->tag]);
261}
262
263static inline int ublk_io_alloc_sqes(struct ublk_thread *t,
264		struct io_uring_sqe *sqes[], int nr_sqes)
265{
266	struct io_uring *ring = &t->ring;
267	unsigned left = io_uring_sq_space_left(ring);
268	int i;
269
270	if (left < nr_sqes)
271		io_uring_submit(ring);
272
273	for (i = 0; i < nr_sqes; i++) {
274		sqes[i] = io_uring_get_sqe(ring);
275		if (!sqes[i])
276			return i;
277	}
278
279	return nr_sqes;
280}
281
282static inline int ublk_get_registered_fd(struct ublk_queue *q, int fd_index)
283{
284	if (q->flags & UBLKS_Q_NO_UBLK_FIXED_FD) {
285		if (fd_index == 0)
286			/* Return the raw ublk FD for index 0 */
287			return q->ublk_fd;
288		/* Adjust index for backing files (index 1 becomes 0, etc.) */
289		return fd_index - 1;
290	}
291	return fd_index;
292}
293
294static inline void __io_uring_prep_buf_reg_unreg(struct io_uring_sqe *sqe,
295		struct ublk_queue *q, int tag, int q_id, __u64 index)
296{
297	struct ublksrv_io_cmd *cmd = (struct ublksrv_io_cmd *)sqe->cmd;
298	int dev_fd = ublk_get_registered_fd(q, 0);
299
300	io_uring_prep_read(sqe, dev_fd, 0, 0, 0);
301	sqe->opcode		= IORING_OP_URING_CMD;
302	if (q->flags & UBLKS_Q_NO_UBLK_FIXED_FD)
303		sqe->flags	&= ~IOSQE_FIXED_FILE;
304	else
305		sqe->flags	|= IOSQE_FIXED_FILE;
306
307	cmd->tag		= tag;
308	cmd->addr		= index;
309	cmd->q_id		= q_id;
310}
311
312static inline void io_uring_prep_buf_register(struct io_uring_sqe *sqe,
313		struct ublk_queue *q, int tag, int q_id, __u64 index)
314{
315	__io_uring_prep_buf_reg_unreg(sqe, q, tag, q_id, index);
316	sqe->cmd_op		= UBLK_U_IO_REGISTER_IO_BUF;
317}
318
319static inline void io_uring_prep_buf_unregister(struct io_uring_sqe *sqe,
320		struct ublk_queue *q, int tag, int q_id, __u64 index)
321{
322	__io_uring_prep_buf_reg_unreg(sqe, q, tag, q_id, index);
323	sqe->cmd_op		= UBLK_U_IO_UNREGISTER_IO_BUF;
324}
325
326static inline void *ublk_get_sqe_cmd(const struct io_uring_sqe *sqe)
327{
328	return (void *)&sqe->cmd;
329}
330
331static inline void ublk_set_io_res(struct ublk_queue *q, int tag, int res)
332{
333	q->ios[tag].result = res;
334}
335
336static inline int ublk_get_io_res(const struct ublk_queue *q, unsigned tag)
337{
338	return q->ios[tag].result;
339}
340
341static inline void ublk_mark_io_done(struct ublk_io *io, int res)
342{
343	io->flags |= (UBLKS_IO_NEED_COMMIT_RQ_COMP | UBLKS_IO_FREE);
344	io->result = res;
345}
346
347static inline const struct ublksrv_io_desc *ublk_get_iod(const struct ublk_queue *q, int tag)
348{
349	return &q->io_cmd_buf[tag];
350}
351
352static inline void ublk_set_sqe_cmd_op(struct io_uring_sqe *sqe, __u32 cmd_op)
353{
354	__u32 *addr = (__u32 *)&sqe->off;
355
356	addr[0] = cmd_op;
357	addr[1] = 0;
358}
359
360static inline struct ublk_io *ublk_get_io(struct ublk_queue *q, unsigned tag)
361{
362	return &q->ios[tag];
363}
364
365static inline int ublk_complete_io(struct ublk_thread *t, struct ublk_queue *q,
366				   unsigned tag, int res)
367{
368	struct ublk_io *io = &q->ios[tag];
369
370	ublk_mark_io_done(io, res);
371
372	return ublk_queue_io_cmd(t, io);
373}
374
375static inline void ublk_queued_tgt_io(struct ublk_thread *t, struct ublk_queue *q,
376				      unsigned tag, int queued)
377{
378	if (queued < 0)
379		ublk_complete_io(t, q, tag, queued);
380	else {
381		struct ublk_io *io = ublk_get_io(q, tag);
382
383		t->io_inflight += queued;
384		io->tgt_ios = queued;
385		io->result = 0;
386	}
387}
388
389static inline int ublk_completed_tgt_io(struct ublk_thread *t,
390					struct ublk_queue *q, unsigned tag)
391{
392	struct ublk_io *io = ublk_get_io(q, tag);
393
394	t->io_inflight--;
395
396	return --io->tgt_ios == 0;
397}
398
399static inline bool ublk_queue_use_zc(const struct ublk_queue *q)
400{
401	return !!(q->flags & UBLK_F_SUPPORT_ZERO_COPY);
402}
403
404static inline bool ublk_queue_use_auto_zc(const struct ublk_queue *q)
405{
406	return !!(q->flags & UBLK_F_AUTO_BUF_REG);
407}
408
409static inline bool ublk_queue_auto_zc_fallback(const struct ublk_queue *q)
410{
411	return !!(q->flags & UBLKS_Q_AUTO_BUF_REG_FALLBACK);
412}
413
414static inline bool ublk_queue_use_user_copy(const struct ublk_queue *q)
415{
416	return !!(q->flags & UBLK_F_USER_COPY);
417}
418
419static inline int ublk_queue_no_buf(const struct ublk_queue *q)
420{
421	return ublk_queue_use_zc(q) || ublk_queue_use_auto_zc(q);
422}
423
424extern const struct ublk_tgt_ops null_tgt_ops;
425extern const struct ublk_tgt_ops loop_tgt_ops;
426extern const struct ublk_tgt_ops stripe_tgt_ops;
427extern const struct ublk_tgt_ops fault_inject_tgt_ops;
428
429void backing_file_tgt_deinit(struct ublk_dev *dev);
430int backing_file_tgt_init(struct ublk_dev *dev);
431
432#endif
~/ Read-only file preview.