xref: /spdk/examples/bdev/hello_world/hello_bdev.c (revision 8a0a98d35e21f282088edf28b9e8da66ec390e3a)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (c) Intel Corporation.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "spdk/stdinc.h"
35 #include "spdk/thread.h"
36 #include "spdk/bdev.h"
37 #include "spdk/env.h"
38 #include "spdk/event.h"
39 #include "spdk/log.h"
40 #include "spdk/string.h"
41 #include "spdk/bdev_module.h"
42 
43 static char *g_bdev_name = "Malloc0";
44 
45 /*
46  * We'll use this struct to gather housekeeping hello_context to pass between
47  * our events and callbacks.
48  */
49 struct hello_context_t {
50 	struct spdk_bdev *bdev;
51 	struct spdk_bdev_desc *bdev_desc;
52 	struct spdk_io_channel *bdev_io_channel;
53 	char *buff;
54 	char *bdev_name;
55 };
56 
57 /*
58  * Usage function for printing parameters that are specific to this application
59  */
60 static void
61 hello_bdev_usage(void)
62 {
63 	printf(" -b bdev name\n");
64 }
65 
66 /*
67  * This function is called to parse the parameters that are specific to this application
68  */
69 static void hello_bdev_parse_arg(int ch, char *arg)
70 {
71 	switch (ch) {
72 	case 'b':
73 		g_bdev_name = arg;
74 		break;
75 	}
76 }
77 
78 /*
79  * Callback function for read io completion.
80  */
81 static void
82 read_complete(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
83 {
84 	struct hello_context_t *hello_context = cb_arg;
85 
86 	if (success) {
87 		SPDK_NOTICELOG("Read string from bdev : %s\n", hello_context->buff);
88 	} else {
89 		SPDK_ERRLOG("bdev io read error\n");
90 	}
91 
92 	/* Complete the bdev io and close the channel */
93 	spdk_bdev_free_io(bdev_io);
94 	spdk_put_io_channel(hello_context->bdev_io_channel);
95 	spdk_bdev_close(hello_context->bdev_desc);
96 	SPDK_NOTICELOG("Stopping app\n");
97 	spdk_app_stop(success ? 0 : -1);
98 }
99 
100 /*
101  * Callback function for write io completion.
102  */
103 static void
104 write_complete(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
105 {
106 	struct hello_context_t *hello_context = cb_arg;
107 	int rc;
108 	uint32_t blk_size;
109 
110 	/* Complete the I/O */
111 	spdk_bdev_free_io(bdev_io);
112 
113 	if (success) {
114 		SPDK_NOTICELOG("bdev io write completed successfully\n");
115 	} else {
116 		SPDK_ERRLOG("bdev io write error: %d\n", EIO);
117 		spdk_put_io_channel(hello_context->bdev_io_channel);
118 		spdk_bdev_close(hello_context->bdev_desc);
119 		spdk_app_stop(-1);
120 		return;
121 	}
122 
123 	/* Zero the buffer so that we can use it for reading */
124 	blk_size = spdk_bdev_get_block_size(hello_context->bdev);
125 	memset(hello_context->buff, 0, blk_size);
126 
127 	SPDK_NOTICELOG("Reading io\n");
128 	rc = spdk_bdev_read(hello_context->bdev_desc, hello_context->bdev_io_channel,
129 			    hello_context->buff, 0, blk_size, read_complete, hello_context);
130 
131 	if (rc) {
132 		SPDK_ERRLOG("%s error while reading from bdev: %d\n", spdk_strerror(-rc), rc);
133 		spdk_put_io_channel(hello_context->bdev_io_channel);
134 		spdk_bdev_close(hello_context->bdev_desc);
135 		spdk_app_stop(-1);
136 		return;
137 	}
138 }
139 
140 /*
141  * Our initial event that kicks off everything from main().
142  */
143 static void
144 hello_start(void *arg1, void *arg2)
145 {
146 	struct hello_context_t *hello_context = arg1;
147 	uint32_t blk_size, buf_align;
148 	int rc = 0;
149 	hello_context->bdev = NULL;
150 	hello_context->bdev_desc = NULL;
151 
152 	SPDK_NOTICELOG("Successfully started the application\n");
153 
154 	/*
155 	 * Get the bdev. There can be many bdevs configured in
156 	 * in the configuration file but this application will only
157 	 * use the one input by the user at runtime so we get it via its name.
158 	 */
159 	hello_context->bdev = spdk_bdev_get_by_name(hello_context->bdev_name);
160 	if (hello_context->bdev == NULL) {
161 		SPDK_ERRLOG("Could not find the bdev: %s\n", hello_context->bdev_name);
162 		spdk_app_stop(-1);
163 		return;
164 	}
165 
166 	/*
167 	 * Open the bdev by calling spdk_bdev_open()
168 	 * The function will return a descriptor
169 	 */
170 	SPDK_NOTICELOG("Opening the bdev %s\n", hello_context->bdev_name);
171 	rc = spdk_bdev_open(hello_context->bdev, true, NULL, NULL, &hello_context->bdev_desc);
172 	if (rc) {
173 		SPDK_ERRLOG("Could not open bdev: %s\n", hello_context->bdev_name);
174 		spdk_app_stop(-1);
175 		return;
176 	}
177 
178 	SPDK_NOTICELOG("Opening io channel\n");
179 	/* Open I/O channel */
180 	hello_context->bdev_io_channel = spdk_bdev_get_io_channel(hello_context->bdev_desc);
181 	if (hello_context->bdev_io_channel == NULL) {
182 		SPDK_ERRLOG("Could not create bdev I/O channel!!\n");
183 		spdk_bdev_close(hello_context->bdev_desc);
184 		spdk_app_stop(-1);
185 		return;
186 	}
187 
188 	/* Allocate memory for the write buffer.
189 	 * Initialize the write buffer with the string "Hello World!"
190 	 */
191 	blk_size = spdk_bdev_get_block_size(hello_context->bdev);
192 	buf_align = spdk_bdev_get_buf_align(hello_context->bdev);
193 	hello_context->buff = spdk_dma_zmalloc(blk_size, buf_align, NULL);
194 	if (!hello_context->buff) {
195 		SPDK_ERRLOG("Failed to allocate buffer\n");
196 		spdk_put_io_channel(hello_context->bdev_io_channel);
197 		spdk_bdev_close(hello_context->bdev_desc);
198 		spdk_app_stop(-1);
199 		return;
200 	}
201 	snprintf(hello_context->buff, blk_size, "%s", "Hello World!\n");
202 
203 	SPDK_NOTICELOG("Writing to the bdev\n");
204 	rc = spdk_bdev_write(hello_context->bdev_desc, hello_context->bdev_io_channel,
205 			     hello_context->buff, 0, blk_size, write_complete, hello_context);
206 	if (rc) {
207 		SPDK_ERRLOG("%s error while writing to bdev: %d\n", spdk_strerror(-rc), rc);
208 		spdk_bdev_close(hello_context->bdev_desc);
209 		spdk_put_io_channel(hello_context->bdev_io_channel);
210 		spdk_app_stop(-1);
211 		return;
212 	}
213 }
214 
215 int
216 main(int argc, char **argv)
217 {
218 	struct spdk_app_opts opts = {};
219 	int rc = 0;
220 	struct hello_context_t hello_context = {};
221 
222 	/* Set default values in opts structure. */
223 	spdk_app_opts_init(&opts);
224 	opts.name = "hello_bdev";
225 	opts.config_file = "bdev.conf";
226 
227 	/*
228 	 * The user can provide the config file and bdev name at run time.
229 	 * For example, to use Malloc0 in file bdev.conf run with params
230 	 * ./hello_bdev -c bdev.conf -b Malloc0
231 	 * To use passthru bdev PT0 run with params
232 	 * ./hello_bdev -c bdev.conf -b PT0
233 	 * If none of the parameters are provide the application will use the
234 	 * default parameters(-c bdev.conf -b Malloc0).
235 	 */
236 	if ((rc = spdk_app_parse_args(argc, argv, &opts, "b:", hello_bdev_parse_arg,
237 				      hello_bdev_usage)) != SPDK_APP_PARSE_ARGS_SUCCESS) {
238 		exit(rc);
239 	}
240 	hello_context.bdev_name = g_bdev_name;
241 
242 	/*
243 	 * spdk_app_start() will block running hello_start() until
244 	 * spdk_app_stop() is called by someone (not simply when
245 	 * hello_start() returns), or if an error occurs during
246 	 * spdk_app_start() before hello_start() runs.
247 	 */
248 	rc = spdk_app_start(&opts, hello_start, &hello_context, NULL);
249 	if (rc) {
250 		SPDK_ERRLOG("ERROR starting application\n");
251 	}
252 
253 	/* When the app stops, free up memory that we allocated. */
254 	spdk_dma_free(hello_context.buff);
255 
256 	/* Gracefully close out all of the SPDK subsystems. */
257 	spdk_app_fini();
258 	return rc;
259 }
260