xref: /aosp_15_r20/external/ublksrv/demo_null.c (revision 94c4a1e103eb1715230460aab379dff275992c20)
1 // SPDX-License-Identifier: MIT or GPL-2.0-only
2 
3 #include <config.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <sched.h>
7 #include <pthread.h>
8 #include <getopt.h>
9 #include <stdarg.h>
10 #include <errno.h>
11 #include <error.h>
12 #include <string.h>
13 #include <sys/types.h>
14 #include <unistd.h>
15 
16 #include "ublksrv.h"
17 #include "ublksrv_utils.h"
18 
19 #define UBLKSRV_TGT_TYPE_DEMO  0
20 
21 struct demo_queue_info {
22 	const struct ublksrv_dev *dev;
23 	int qid;
24 	pthread_t thread;
25 };
26 
27 static struct ublksrv_ctrl_dev *this_dev;
28 
29 static pthread_mutex_t jbuf_lock;
30 static char jbuf[4096];
31 
sig_handler(int sig)32 static void sig_handler(int sig)
33 {
34 	fprintf(stderr, "got signal %d\n", sig);
35 	ublksrv_ctrl_stop_dev(this_dev);
36 }
37 
38 /*
39  * io handler for each ublkdev's queue
40  *
41  * Just for showing how to build ublksrv target's io handling, so callers
42  * can apply these APIs in their own thread context for making one ublk
43  * block device.
44  */
demo_null_io_handler_fn(void * data)45 static void *demo_null_io_handler_fn(void *data)
46 {
47 	struct demo_queue_info *info = (struct demo_queue_info *)data;
48 	const struct ublksrv_dev *dev = info->dev;
49 	const struct ublksrv_ctrl_dev_info *dinfo =
50 		ublksrv_ctrl_get_dev_info(ublksrv_get_ctrl_dev(dev));
51 	unsigned dev_id = dinfo->dev_id;
52 	unsigned short q_id = info->qid;
53 	const struct ublksrv_queue *q;
54 
55 	sched_setscheduler(getpid(), SCHED_RR, NULL);
56 
57 	pthread_mutex_lock(&jbuf_lock);
58 	ublksrv_json_write_queue_info(ublksrv_get_ctrl_dev(dev), jbuf, sizeof jbuf,
59 			q_id, ublksrv_gettid());
60 	pthread_mutex_unlock(&jbuf_lock);
61 	q = ublksrv_queue_init(dev, q_id, NULL);
62 	if (!q) {
63 		fprintf(stderr, "ublk dev %d queue %d init queue failed\n",
64 				dinfo->dev_id, q_id);
65 		return NULL;
66 	}
67 
68 	fprintf(stdout, "tid %d: ublk dev %d queue %d started\n",
69 			ublksrv_gettid(),
70 			dev_id, q->q_id);
71 	do {
72 		if (ublksrv_process_io(q) < 0)
73 			break;
74 	} while (1);
75 
76 	fprintf(stdout, "ublk dev %d queue %d exited\n", dev_id, q->q_id);
77 	ublksrv_queue_deinit(q);
78 	return NULL;
79 }
80 
demo_null_set_parameters(struct ublksrv_ctrl_dev * cdev,const struct ublksrv_dev * dev)81 static void demo_null_set_parameters(struct ublksrv_ctrl_dev *cdev,
82 		const struct ublksrv_dev *dev)
83  {
84 	const struct ublksrv_ctrl_dev_info *info =
85 		ublksrv_ctrl_get_dev_info(cdev);
86 	struct ublk_params p = {
87 		.types = UBLK_PARAM_TYPE_BASIC,
88 		.basic = {
89 			.logical_bs_shift	= 9,
90 			.physical_bs_shift	= 12,
91 			.io_opt_shift		= 12,
92 			.io_min_shift		= 9,
93 			.max_sectors		= info->max_io_buf_bytes >> 9,
94 			.dev_sectors		= dev->tgt.dev_size >> 9,
95 		},
96 	};
97 	int ret;
98 
99 	pthread_mutex_lock(&jbuf_lock);
100 	ublksrv_json_write_params(&p, jbuf, sizeof jbuf);
101 	pthread_mutex_unlock(&jbuf_lock);
102 
103 	ret = ublksrv_ctrl_set_params(cdev, &p);
104 	if (ret)
105 		fprintf(stderr, "dev %d set basic parameter failed %d\n",
106 				info->dev_id, ret);
107 }
108 
demo_null_io_handler(struct ublksrv_ctrl_dev * ctrl_dev)109 static int demo_null_io_handler(struct ublksrv_ctrl_dev *ctrl_dev)
110 {
111 	int ret, i;
112 	const struct ublksrv_dev *dev;
113 	struct demo_queue_info *info_array;
114 	void *thread_ret;
115 	const struct ublksrv_ctrl_dev_info *dinfo =
116 		ublksrv_ctrl_get_dev_info(ctrl_dev);
117 
118 	info_array = (struct demo_queue_info *)
119 		calloc(sizeof(struct demo_queue_info), dinfo->nr_hw_queues);
120 	if (!info_array)
121 		return -ENOMEM;
122 
123 	dev = ublksrv_dev_init(ctrl_dev);
124 	if (!dev) {
125 		free(info_array);
126 		return -ENOMEM;
127 	}
128 
129 	for (i = 0; i < dinfo->nr_hw_queues; i++) {
130 		info_array[i].dev = dev;
131 		info_array[i].qid = i;
132 		pthread_create(&info_array[i].thread, NULL,
133 				demo_null_io_handler_fn,
134 				&info_array[i]);
135 	}
136 
137 	demo_null_set_parameters(ctrl_dev, dev);
138 
139 	/* everything is fine now, start us */
140 	ret = ublksrv_ctrl_start_dev(ctrl_dev, getpid());
141 	if (ret < 0)
142 		goto fail;
143 
144 	ublksrv_ctrl_get_info(ctrl_dev);
145 	ublksrv_ctrl_dump(ctrl_dev, jbuf);
146 
147 	/* wait until we are terminated */
148 	for (i = 0; i < dinfo->nr_hw_queues; i++)
149 		pthread_join(info_array[i].thread, &thread_ret);
150  fail:
151 	ublksrv_dev_deinit(dev);
152 
153 	free(info_array);
154 
155 	return ret;
156 }
157 
ublksrv_start_daemon(struct ublksrv_ctrl_dev * ctrl_dev)158 static int ublksrv_start_daemon(struct ublksrv_ctrl_dev *ctrl_dev)
159 {
160 	int ret;
161 
162 	if (ublksrv_ctrl_get_affinity(ctrl_dev) < 0)
163 		return -1;
164 
165 	ret = demo_null_io_handler(ctrl_dev);
166 
167 	return ret;
168 }
169 
170 
171 
demo_init_tgt(struct ublksrv_dev * dev,int type,int argc,char * argv[])172 static int demo_init_tgt(struct ublksrv_dev *dev, int type, int argc,
173 		char *argv[])
174 {
175 	const struct ublksrv_ctrl_dev_info *info =
176 		ublksrv_ctrl_get_dev_info(ublksrv_get_ctrl_dev(dev));
177 	struct ublksrv_tgt_info *tgt = &dev->tgt;
178 	struct ublksrv_tgt_base_json tgt_json = {
179 		.type = type,
180 	};
181         strcpy(tgt_json.name, "null");
182 
183 
184 	if (type != UBLKSRV_TGT_TYPE_DEMO)
185 		return -1;
186 
187 	tgt_json.dev_size = tgt->dev_size = 250UL * 1024 * 1024 * 1024;
188 	tgt->tgt_ring_depth = info->queue_depth;
189 	tgt->nr_fds = 0;
190 
191 	ublksrv_json_write_dev_info(ublksrv_get_ctrl_dev(dev), jbuf, sizeof jbuf);
192 	ublksrv_json_write_target_base_info(jbuf, sizeof jbuf, &tgt_json);
193 
194 	return 0;
195 }
196 
demo_handle_io_async(const struct ublksrv_queue * q,const struct ublk_io_data * data)197 static int demo_handle_io_async(const struct ublksrv_queue *q,
198 		const struct ublk_io_data *data)
199 {
200 	const struct ublksrv_io_desc *iod = data->iod;
201 
202 	ublksrv_complete_io(q, data->tag, iod->nr_sectors << 9);
203 
204 	return 0;
205 }
206 
null_alloc_io_buf(const struct ublksrv_queue * q,int tag,int size)207 void *null_alloc_io_buf(const struct ublksrv_queue *q, int tag, int size)
208 {
209 	return malloc(size);
210 }
211 
null_free_io_buf(const struct ublksrv_queue * q,void * buf,int tag)212 void null_free_io_buf(const struct ublksrv_queue *q, void *buf, int tag)
213 {
214 	free(buf);
215 }
216 
217 static struct ublksrv_tgt_type demo_tgt_type = {
218 	.type	= UBLKSRV_TGT_TYPE_DEMO,
219 	.name	=  "demo_null",
220 	.init_tgt = demo_init_tgt,
221 	.handle_io_async = demo_handle_io_async,
222 	//.alloc_io_buf = null_alloc_io_buf,
223 	//.free_io_buf = null_free_io_buf,
224 };
225 
main(int argc,char * argv[])226 int main(int argc, char *argv[])
227 {
228 	struct ublksrv_dev_data data = {
229 		.dev_id = -1,
230 		.max_io_buf_bytes = DEF_BUF_SIZE,
231 		.nr_hw_queues = DEF_NR_HW_QUEUES,
232 		.queue_depth = DEF_QD,
233 		.tgt_type = "demo_null",
234 		.tgt_ops = &demo_tgt_type,
235 		.flags = 0,
236 	};
237 	struct ublksrv_ctrl_dev *dev;
238 	int ret;
239 	static const struct option longopts[] = {
240 		{ "buf",		1,	NULL, 'b' },
241 		{ "need_get_data",	1,	NULL, 'g' },
242 		{ NULL }
243 	};
244 	int opt;
245 	bool use_buf = false;
246 
247 	while ((opt = getopt_long(argc, argv, ":bg",
248 				  longopts, NULL)) != -1) {
249 		switch (opt) {
250 		case 'b':
251 			use_buf = true;
252 			break;
253 		case 'g':
254 			data.flags |= UBLK_F_NEED_GET_DATA;
255 			break;
256 		}
257 	}
258 
259 	if (signal(SIGTERM, sig_handler) == SIG_ERR)
260 		error(EXIT_FAILURE, errno, "signal");
261 	if (signal(SIGINT, sig_handler) == SIG_ERR)
262 		error(EXIT_FAILURE, errno, "signal");
263 
264 	if (use_buf) {
265 		demo_tgt_type.alloc_io_buf = null_alloc_io_buf;
266 		demo_tgt_type.free_io_buf = null_free_io_buf;
267 	}
268 
269 	pthread_mutex_init(&jbuf_lock, NULL);
270 	dev = ublksrv_ctrl_init(&data);
271 	if (!dev)
272 		error(EXIT_FAILURE, ENODEV, "ublksrv_ctrl_init");
273 	/* ugly, but signal handler needs this_dev */
274 	this_dev = dev;
275 
276 	ret = ublksrv_ctrl_add_dev(dev);
277 	if (ret < 0) {
278 		error(0, -ret, "can't add dev %d", data.dev_id);
279 		goto fail;
280 	}
281 
282 	ret = ublksrv_start_daemon(dev);
283 	if (ret < 0) {
284 		error(0, -ret, "can't start daemon");
285 		goto fail_del_dev;
286 	}
287 
288 	ublksrv_ctrl_del_dev(dev);
289 	ublksrv_ctrl_deinit(dev);
290 	exit(EXIT_SUCCESS);
291 
292  fail_del_dev:
293 	ublksrv_ctrl_del_dev(dev);
294  fail:
295 	ublksrv_ctrl_deinit(dev);
296 
297 	exit(EXIT_FAILURE);
298 }
299