xref: /spdk/examples/fsdev/hello_world/hello_fsdev.c (revision 6cb9c75cafe98f52604eba94d6b76356861de077)
14ed98d54SEvgeniy Kochetov /*   SPDX-License-Identifier: BSD-3-Clause
24ed98d54SEvgeniy Kochetov  *   Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
34ed98d54SEvgeniy Kochetov  */
44ed98d54SEvgeniy Kochetov 
54ed98d54SEvgeniy Kochetov #include "spdk/stdinc.h"
64ed98d54SEvgeniy Kochetov #include "spdk/thread.h"
74ed98d54SEvgeniy Kochetov #include "spdk/fsdev.h"
84ed98d54SEvgeniy Kochetov #include "spdk/env.h"
94ed98d54SEvgeniy Kochetov #include "spdk/event.h"
104ed98d54SEvgeniy Kochetov #include "spdk/log.h"
114ed98d54SEvgeniy Kochetov #include "spdk/string.h"
124ed98d54SEvgeniy Kochetov 
134ed98d54SEvgeniy Kochetov #define TEST_FILENAME "hello_file"
144ed98d54SEvgeniy Kochetov #define DATA_SIZE 512
154ed98d54SEvgeniy Kochetov #define ROOT_NODEID 1
164ed98d54SEvgeniy Kochetov 
174ed98d54SEvgeniy Kochetov static char *g_fsdev_name = "Fs0";
184ed98d54SEvgeniy Kochetov int g_result = 0;
194ed98d54SEvgeniy Kochetov 
204ed98d54SEvgeniy Kochetov /*
214ed98d54SEvgeniy Kochetov  * We'll use this struct to gather housekeeping hello_context to pass between
224ed98d54SEvgeniy Kochetov  * our events and callbacks.
234ed98d54SEvgeniy Kochetov  */
244ed98d54SEvgeniy Kochetov struct hello_context_t {
254ed98d54SEvgeniy Kochetov 	struct spdk_thread *app_thread;
264ed98d54SEvgeniy Kochetov 	struct spdk_fsdev_desc *fsdev_desc;
274ed98d54SEvgeniy Kochetov 	struct spdk_io_channel *fsdev_io_channel;
284ed98d54SEvgeniy Kochetov 	struct spdk_fsdev_file_object *root_fobject;
294ed98d54SEvgeniy Kochetov 	char *fsdev_name;
304ed98d54SEvgeniy Kochetov 	int thread_count;
314ed98d54SEvgeniy Kochetov };
324ed98d54SEvgeniy Kochetov 
334ed98d54SEvgeniy Kochetov struct hello_thread_t {
344ed98d54SEvgeniy Kochetov 	struct hello_context_t *hello_context;
354ed98d54SEvgeniy Kochetov 	struct spdk_thread *thread;
364ed98d54SEvgeniy Kochetov 	struct spdk_io_channel *fsdev_io_channel;
374ed98d54SEvgeniy Kochetov 	uint64_t unique;
384ed98d54SEvgeniy Kochetov 	uint8_t *buf;
394ed98d54SEvgeniy Kochetov 	char *file_name;
404ed98d54SEvgeniy Kochetov 	struct spdk_fsdev_file_object *fobject;
414ed98d54SEvgeniy Kochetov 	struct spdk_fsdev_file_handle *fhandle;
424ed98d54SEvgeniy Kochetov 	struct iovec iov[2];
434ed98d54SEvgeniy Kochetov };
444ed98d54SEvgeniy Kochetov 
454ed98d54SEvgeniy Kochetov /*
464ed98d54SEvgeniy Kochetov  * Usage function for printing parameters that are specific to this application
474ed98d54SEvgeniy Kochetov  */
484ed98d54SEvgeniy Kochetov static void
494ed98d54SEvgeniy Kochetov hello_fsdev_usage(void)
504ed98d54SEvgeniy Kochetov {
514ed98d54SEvgeniy Kochetov 	printf(" -f <fs>                 name of the fsdev to use\n");
524ed98d54SEvgeniy Kochetov }
534ed98d54SEvgeniy Kochetov 
544ed98d54SEvgeniy Kochetov /*
554ed98d54SEvgeniy Kochetov  * This function is called to parse the parameters that are specific to this application
564ed98d54SEvgeniy Kochetov  */
574ed98d54SEvgeniy Kochetov static int
584ed98d54SEvgeniy Kochetov hello_fsdev_parse_arg(int ch, char *arg)
594ed98d54SEvgeniy Kochetov {
604ed98d54SEvgeniy Kochetov 	switch (ch) {
614ed98d54SEvgeniy Kochetov 	case 'f':
624ed98d54SEvgeniy Kochetov 		g_fsdev_name = arg;
634ed98d54SEvgeniy Kochetov 		break;
644ed98d54SEvgeniy Kochetov 	default:
654ed98d54SEvgeniy Kochetov 		return -EINVAL;
664ed98d54SEvgeniy Kochetov 	}
674ed98d54SEvgeniy Kochetov 	return 0;
684ed98d54SEvgeniy Kochetov }
694ed98d54SEvgeniy Kochetov 
704ed98d54SEvgeniy Kochetov static void
714ed98d54SEvgeniy Kochetov hello_app_done(struct hello_context_t *hello_context, int rc)
724ed98d54SEvgeniy Kochetov {
734ed98d54SEvgeniy Kochetov 	spdk_put_io_channel(hello_context->fsdev_io_channel);
744ed98d54SEvgeniy Kochetov 	spdk_fsdev_close(hello_context->fsdev_desc);
754ed98d54SEvgeniy Kochetov 	SPDK_NOTICELOG("Stopping app: rc %d\n", rc);
764ed98d54SEvgeniy Kochetov 	spdk_app_stop(rc);
774ed98d54SEvgeniy Kochetov }
784ed98d54SEvgeniy Kochetov 
794ed98d54SEvgeniy Kochetov static void
804ed98d54SEvgeniy Kochetov root_forget_complete(void *cb_arg, struct spdk_io_channel *ch, int status)
814ed98d54SEvgeniy Kochetov {
824ed98d54SEvgeniy Kochetov 	struct hello_context_t *hello_context = cb_arg;
834ed98d54SEvgeniy Kochetov 
844ed98d54SEvgeniy Kochetov 	SPDK_NOTICELOG("Root forget complete (status=%d)\n", status);
854ed98d54SEvgeniy Kochetov 	if (status) {
864ed98d54SEvgeniy Kochetov 		SPDK_ERRLOG("Root forget failed: error %d\n", status);
874ed98d54SEvgeniy Kochetov 		g_result = EINVAL;
884ed98d54SEvgeniy Kochetov 	}
894ed98d54SEvgeniy Kochetov 
904ed98d54SEvgeniy Kochetov 	hello_app_done(hello_context, g_result);
914ed98d54SEvgeniy Kochetov }
924ed98d54SEvgeniy Kochetov 
934ed98d54SEvgeniy Kochetov static void
944ed98d54SEvgeniy Kochetov hello_root_release(struct hello_context_t *hello_context)
954ed98d54SEvgeniy Kochetov {
964ed98d54SEvgeniy Kochetov 	int res;
974ed98d54SEvgeniy Kochetov 
984ed98d54SEvgeniy Kochetov 	SPDK_NOTICELOG("Forget root\n");
994ed98d54SEvgeniy Kochetov 	res = spdk_fsdev_forget(hello_context->fsdev_desc, hello_context->fsdev_io_channel, 0,
1004ed98d54SEvgeniy Kochetov 				hello_context->root_fobject, 1,
1014ed98d54SEvgeniy Kochetov 				root_forget_complete, hello_context);
1024ed98d54SEvgeniy Kochetov 	if (res) {
1034ed98d54SEvgeniy Kochetov 		SPDK_ERRLOG("Failed to forget root (err=%d)\n", res);
1044ed98d54SEvgeniy Kochetov 		hello_app_done(hello_context, EINVAL);
1054ed98d54SEvgeniy Kochetov 	}
1064ed98d54SEvgeniy Kochetov }
1074ed98d54SEvgeniy Kochetov 
1084ed98d54SEvgeniy Kochetov static void
1094ed98d54SEvgeniy Kochetov hello_app_notify_thread_done(void *ctx)
1104ed98d54SEvgeniy Kochetov {
1114ed98d54SEvgeniy Kochetov 	struct hello_context_t *hello_context = (struct hello_context_t *)ctx;
1124ed98d54SEvgeniy Kochetov 
1134ed98d54SEvgeniy Kochetov 	assert(hello_context->thread_count > 0);
1144ed98d54SEvgeniy Kochetov 	hello_context->thread_count--;
1154ed98d54SEvgeniy Kochetov 	if (hello_context->thread_count == 0) {
1164ed98d54SEvgeniy Kochetov 		hello_root_release(hello_context);
1174ed98d54SEvgeniy Kochetov 	}
1184ed98d54SEvgeniy Kochetov }
1194ed98d54SEvgeniy Kochetov 
1204ed98d54SEvgeniy Kochetov static void
1214ed98d54SEvgeniy Kochetov hello_thread_done(struct hello_thread_t *hello_thread, int rc)
1224ed98d54SEvgeniy Kochetov {
1234ed98d54SEvgeniy Kochetov 	struct hello_context_t *hello_context = hello_thread->hello_context;
1244ed98d54SEvgeniy Kochetov 
1254ed98d54SEvgeniy Kochetov 	spdk_put_io_channel(hello_thread->fsdev_io_channel);
1264ed98d54SEvgeniy Kochetov 	free(hello_thread->buf);
1274ed98d54SEvgeniy Kochetov 	free(hello_thread->file_name);
1284ed98d54SEvgeniy Kochetov 	SPDK_NOTICELOG("Thread %s done: rc %d\n",
1294ed98d54SEvgeniy Kochetov 		       spdk_thread_get_name(hello_thread->thread), rc);
1304ed98d54SEvgeniy Kochetov 	spdk_thread_exit(hello_thread->thread);
1314ed98d54SEvgeniy Kochetov 	free(hello_thread);
1324ed98d54SEvgeniy Kochetov 	if (rc) {
1334ed98d54SEvgeniy Kochetov 		g_result = rc;
1344ed98d54SEvgeniy Kochetov 	}
1354ed98d54SEvgeniy Kochetov 
1364ed98d54SEvgeniy Kochetov 	spdk_thread_send_msg(hello_context->app_thread, hello_app_notify_thread_done, hello_context);
1374ed98d54SEvgeniy Kochetov }
1384ed98d54SEvgeniy Kochetov 
1394ed98d54SEvgeniy Kochetov static bool
1404ed98d54SEvgeniy Kochetov hello_check_complete(struct hello_thread_t *hello_thread, int status, const char *op)
1414ed98d54SEvgeniy Kochetov {
1424ed98d54SEvgeniy Kochetov 	hello_thread->unique++;
1434ed98d54SEvgeniy Kochetov 	if (status) {
1444ed98d54SEvgeniy Kochetov 		SPDK_ERRLOG("%s failed with %d\n", op, status);
1454ed98d54SEvgeniy Kochetov 		hello_thread_done(hello_thread, EIO);
1464ed98d54SEvgeniy Kochetov 		return false;
1474ed98d54SEvgeniy Kochetov 	}
1484ed98d54SEvgeniy Kochetov 
1494ed98d54SEvgeniy Kochetov 	return true;
1504ed98d54SEvgeniy Kochetov }
1514ed98d54SEvgeniy Kochetov 
1524ed98d54SEvgeniy Kochetov static void
1534ed98d54SEvgeniy Kochetov unlink_complete(void *cb_arg, struct spdk_io_channel *ch, int status)
1544ed98d54SEvgeniy Kochetov {
1554ed98d54SEvgeniy Kochetov 	struct hello_thread_t *hello_thread = cb_arg;
1564ed98d54SEvgeniy Kochetov 
1574ed98d54SEvgeniy Kochetov 	SPDK_NOTICELOG("Unlink complete (status=%d)\n", status);
1584ed98d54SEvgeniy Kochetov 	if (!hello_check_complete(hello_thread, status, "unlink")) {
1594ed98d54SEvgeniy Kochetov 		return;
1604ed98d54SEvgeniy Kochetov 	}
1614ed98d54SEvgeniy Kochetov 
1624ed98d54SEvgeniy Kochetov 	hello_thread->fobject = NULL;
1634ed98d54SEvgeniy Kochetov 	hello_thread_done(hello_thread, 0);
1644ed98d54SEvgeniy Kochetov }
1654ed98d54SEvgeniy Kochetov 
1664ed98d54SEvgeniy Kochetov static void
1674ed98d54SEvgeniy Kochetov hello_unlink(struct hello_thread_t *hello_thread)
1684ed98d54SEvgeniy Kochetov {
1694ed98d54SEvgeniy Kochetov 	struct hello_context_t *hello_context = hello_thread->hello_context;
1704ed98d54SEvgeniy Kochetov 	int res;
1714ed98d54SEvgeniy Kochetov 
1724ed98d54SEvgeniy Kochetov 	SPDK_NOTICELOG("Unlink file %s\n", hello_thread->file_name);
1734ed98d54SEvgeniy Kochetov 
1744ed98d54SEvgeniy Kochetov 	res = spdk_fsdev_unlink(hello_context->fsdev_desc, hello_thread->fsdev_io_channel,
1754ed98d54SEvgeniy Kochetov 				hello_thread->unique, hello_context->root_fobject, hello_thread->file_name,
1764ed98d54SEvgeniy Kochetov 				unlink_complete, hello_thread);
1774ed98d54SEvgeniy Kochetov 	if (res) {
1784ed98d54SEvgeniy Kochetov 		SPDK_ERRLOG("unlink failed with %d\n", res);
1794ed98d54SEvgeniy Kochetov 		hello_thread_done(hello_thread, EIO);
1804ed98d54SEvgeniy Kochetov 	}
1814ed98d54SEvgeniy Kochetov }
1824ed98d54SEvgeniy Kochetov 
1834ed98d54SEvgeniy Kochetov static void
1844ed98d54SEvgeniy Kochetov release_complete(void *cb_arg, struct spdk_io_channel *ch, int status)
1854ed98d54SEvgeniy Kochetov {
1864ed98d54SEvgeniy Kochetov 	struct hello_thread_t *hello_thread = cb_arg;
1874ed98d54SEvgeniy Kochetov 
1884ed98d54SEvgeniy Kochetov 	SPDK_NOTICELOG("Release complete (status=%d)\n", status);
1894ed98d54SEvgeniy Kochetov 	if (!hello_check_complete(hello_thread, status, "release")) {
1904ed98d54SEvgeniy Kochetov 		return;
1914ed98d54SEvgeniy Kochetov 	}
1924ed98d54SEvgeniy Kochetov 
1934ed98d54SEvgeniy Kochetov 	hello_thread->fhandle = NULL;
1944ed98d54SEvgeniy Kochetov 	hello_unlink(hello_thread);
1954ed98d54SEvgeniy Kochetov }
1964ed98d54SEvgeniy Kochetov 
1974ed98d54SEvgeniy Kochetov static void
1984ed98d54SEvgeniy Kochetov hello_release(struct hello_thread_t *hello_thread)
1994ed98d54SEvgeniy Kochetov {
2004ed98d54SEvgeniy Kochetov 	struct hello_context_t *hello_context = hello_thread->hello_context;
2014ed98d54SEvgeniy Kochetov 	int res;
2024ed98d54SEvgeniy Kochetov 
2034ed98d54SEvgeniy Kochetov 	SPDK_NOTICELOG("Release file handle %p\n", hello_thread->fhandle);
2044ed98d54SEvgeniy Kochetov 
2054ed98d54SEvgeniy Kochetov 	res = spdk_fsdev_release(hello_context->fsdev_desc, hello_thread->fsdev_io_channel,
2064ed98d54SEvgeniy Kochetov 				 hello_thread->unique, hello_thread->fobject, hello_thread->fhandle,
2074ed98d54SEvgeniy Kochetov 				 release_complete, hello_thread);
2084ed98d54SEvgeniy Kochetov 	if (res) {
2094ed98d54SEvgeniy Kochetov 		SPDK_ERRLOG("release failed with %d\n", res);
2104ed98d54SEvgeniy Kochetov 		hello_thread_done(hello_thread, EIO);
2114ed98d54SEvgeniy Kochetov 	}
2124ed98d54SEvgeniy Kochetov }
2134ed98d54SEvgeniy Kochetov 
2144ed98d54SEvgeniy Kochetov static void
2154ed98d54SEvgeniy Kochetov read_complete(void *cb_arg, struct spdk_io_channel *ch, int status, uint32_t data_size)
2164ed98d54SEvgeniy Kochetov {
2174ed98d54SEvgeniy Kochetov 	struct hello_thread_t *hello_thread = cb_arg;
2184ed98d54SEvgeniy Kochetov 	uint8_t data = spdk_env_get_current_core();
2194ed98d54SEvgeniy Kochetov 	uint32_t i;
2204ed98d54SEvgeniy Kochetov 
2214ed98d54SEvgeniy Kochetov 	SPDK_NOTICELOG("Read complete (status=%d, %" PRIu32 "bytes read)\n", status, data_size);
2224ed98d54SEvgeniy Kochetov 	if (!hello_check_complete(hello_thread, status, "read")) {
2234ed98d54SEvgeniy Kochetov 		return;
2244ed98d54SEvgeniy Kochetov 	}
2254ed98d54SEvgeniy Kochetov 
2264ed98d54SEvgeniy Kochetov 	assert(data_size == DATA_SIZE);
2274ed98d54SEvgeniy Kochetov 
2284ed98d54SEvgeniy Kochetov 	for (i = 0; i < DATA_SIZE; ++i) {
2294ed98d54SEvgeniy Kochetov 		if (hello_thread->buf[i] != data) {
2304ed98d54SEvgeniy Kochetov 			SPDK_NOTICELOG("Bad read data at offset %d, 0x%02X != 0x%02X\n",
2314ed98d54SEvgeniy Kochetov 				       i, hello_thread->buf[i], data);
2324ed98d54SEvgeniy Kochetov 			break;
2334ed98d54SEvgeniy Kochetov 		}
2344ed98d54SEvgeniy Kochetov 	}
2354ed98d54SEvgeniy Kochetov 
2364ed98d54SEvgeniy Kochetov 	hello_release(hello_thread);
2374ed98d54SEvgeniy Kochetov }
2384ed98d54SEvgeniy Kochetov 
2394ed98d54SEvgeniy Kochetov static void
2404ed98d54SEvgeniy Kochetov hello_read(struct hello_thread_t *hello_thread)
2414ed98d54SEvgeniy Kochetov {
2424ed98d54SEvgeniy Kochetov 	struct hello_context_t *hello_context = hello_thread->hello_context;
2434ed98d54SEvgeniy Kochetov 	int res;
2444ed98d54SEvgeniy Kochetov 
2454ed98d54SEvgeniy Kochetov 	SPDK_NOTICELOG("Read from file handle %p\n", hello_thread->fhandle);
2464ed98d54SEvgeniy Kochetov 
2474ed98d54SEvgeniy Kochetov 	memset(hello_thread->buf, 0xFF, DATA_SIZE);
2484ed98d54SEvgeniy Kochetov 
2494ed98d54SEvgeniy Kochetov 	hello_thread->iov[0].iov_base = hello_thread->buf;
2504ed98d54SEvgeniy Kochetov 	hello_thread->iov[0].iov_len = DATA_SIZE / 4;
2514ed98d54SEvgeniy Kochetov 	hello_thread->iov[1].iov_base = hello_thread->buf + hello_thread->iov[0].iov_len;
2524ed98d54SEvgeniy Kochetov 	hello_thread->iov[1].iov_len = DATA_SIZE - hello_thread->iov[0].iov_len;
2534ed98d54SEvgeniy Kochetov 
2544ed98d54SEvgeniy Kochetov 	res = spdk_fsdev_read(hello_context->fsdev_desc, hello_thread->fsdev_io_channel,
2554ed98d54SEvgeniy Kochetov 			      hello_thread->unique, hello_thread->fobject, hello_thread->fhandle,
2564ed98d54SEvgeniy Kochetov 			      DATA_SIZE, 0, 0, hello_thread->iov, 2, NULL,
2574ed98d54SEvgeniy Kochetov 			      read_complete, hello_thread);
2584ed98d54SEvgeniy Kochetov 	if (res) {
2594ed98d54SEvgeniy Kochetov 		SPDK_ERRLOG("write failed with %d\n", res);
2604ed98d54SEvgeniy Kochetov 		hello_thread_done(hello_thread, EIO);
2614ed98d54SEvgeniy Kochetov 	}
2624ed98d54SEvgeniy Kochetov }
2634ed98d54SEvgeniy Kochetov 
2644ed98d54SEvgeniy Kochetov static void
2654ed98d54SEvgeniy Kochetov write_complete(void *cb_arg, struct spdk_io_channel *ch, int status, uint32_t data_size)
2664ed98d54SEvgeniy Kochetov {
2674ed98d54SEvgeniy Kochetov 	struct hello_thread_t *hello_thread = cb_arg;
2684ed98d54SEvgeniy Kochetov 
2694ed98d54SEvgeniy Kochetov 	SPDK_NOTICELOG("Write complete (status=%d, %" PRIu32 "bytes written)\n", status, data_size);
2704ed98d54SEvgeniy Kochetov 	if (!hello_check_complete(hello_thread, status, "write")) {
2714ed98d54SEvgeniy Kochetov 		return;
2724ed98d54SEvgeniy Kochetov 	}
2734ed98d54SEvgeniy Kochetov 
2744ed98d54SEvgeniy Kochetov 	assert(data_size == DATA_SIZE);
2754ed98d54SEvgeniy Kochetov 	hello_read(hello_thread);
2764ed98d54SEvgeniy Kochetov }
2774ed98d54SEvgeniy Kochetov 
2784ed98d54SEvgeniy Kochetov static void
2794ed98d54SEvgeniy Kochetov hello_write(struct hello_thread_t *hello_thread)
2804ed98d54SEvgeniy Kochetov {
2814ed98d54SEvgeniy Kochetov 	uint8_t data = spdk_env_get_current_core();
2824ed98d54SEvgeniy Kochetov 	struct hello_context_t *hello_context = hello_thread->hello_context;
2834ed98d54SEvgeniy Kochetov 	int res;
2844ed98d54SEvgeniy Kochetov 
2854ed98d54SEvgeniy Kochetov 	SPDK_NOTICELOG("Write to file handle %p\n", hello_thread->fhandle);
2864ed98d54SEvgeniy Kochetov 
2874ed98d54SEvgeniy Kochetov 	memset(hello_thread->buf, data, DATA_SIZE);
2884ed98d54SEvgeniy Kochetov 
2894ed98d54SEvgeniy Kochetov 	hello_thread->iov[0].iov_base = hello_thread->buf;
2904ed98d54SEvgeniy Kochetov 	hello_thread->iov[0].iov_len = DATA_SIZE / 2;
2914ed98d54SEvgeniy Kochetov 	hello_thread->iov[1].iov_base = hello_thread->buf + hello_thread->iov[0].iov_len;
2924ed98d54SEvgeniy Kochetov 	hello_thread->iov[1].iov_len = DATA_SIZE - hello_thread->iov[0].iov_len;
2934ed98d54SEvgeniy Kochetov 
2944ed98d54SEvgeniy Kochetov 	res = spdk_fsdev_write(hello_context->fsdev_desc, hello_thread->fsdev_io_channel,
2954ed98d54SEvgeniy Kochetov 			       hello_thread->unique, hello_thread->fobject, hello_thread->fhandle,
2964ed98d54SEvgeniy Kochetov 			       DATA_SIZE, 0, 0, hello_thread->iov, 2, NULL,
2974ed98d54SEvgeniy Kochetov 			       write_complete, hello_thread);
2984ed98d54SEvgeniy Kochetov 	if (res) {
2994ed98d54SEvgeniy Kochetov 		SPDK_ERRLOG("write failed with %d\n", res);
3004ed98d54SEvgeniy Kochetov 		hello_thread_done(hello_thread, EIO);
3014ed98d54SEvgeniy Kochetov 	}
3024ed98d54SEvgeniy Kochetov }
3034ed98d54SEvgeniy Kochetov 
3044ed98d54SEvgeniy Kochetov static void
3054ed98d54SEvgeniy Kochetov fopen_complete(void *cb_arg, struct spdk_io_channel *ch, int status,
3064ed98d54SEvgeniy Kochetov 	       struct spdk_fsdev_file_handle *fhandle)
3074ed98d54SEvgeniy Kochetov {
3084ed98d54SEvgeniy Kochetov 	struct hello_thread_t *hello_thread = cb_arg;
3094ed98d54SEvgeniy Kochetov 
3104ed98d54SEvgeniy Kochetov 	SPDK_NOTICELOG("Open complete (status=%d)\n", status);
3114ed98d54SEvgeniy Kochetov 	if (!hello_check_complete(hello_thread, status, "open")) {
3124ed98d54SEvgeniy Kochetov 		return;
3134ed98d54SEvgeniy Kochetov 	}
3144ed98d54SEvgeniy Kochetov 
3154ed98d54SEvgeniy Kochetov 	hello_thread->fhandle = fhandle;
3164ed98d54SEvgeniy Kochetov 	hello_write(hello_thread);
3174ed98d54SEvgeniy Kochetov }
3184ed98d54SEvgeniy Kochetov 
3194ed98d54SEvgeniy Kochetov static void
3204ed98d54SEvgeniy Kochetov hello_open(struct hello_thread_t *hello_thread)
3214ed98d54SEvgeniy Kochetov {
3224ed98d54SEvgeniy Kochetov 	struct hello_context_t *hello_context = hello_thread->hello_context;
3234ed98d54SEvgeniy Kochetov 	int res;
3244ed98d54SEvgeniy Kochetov 
3254ed98d54SEvgeniy Kochetov 	SPDK_NOTICELOG("Open fobject %p\n", hello_thread->fobject);
3264ed98d54SEvgeniy Kochetov 
3274ed98d54SEvgeniy Kochetov 	res = spdk_fsdev_fopen(hello_context->fsdev_desc, hello_thread->fsdev_io_channel,
3284ed98d54SEvgeniy Kochetov 			       hello_thread->unique, hello_thread->fobject, O_RDWR,
3294ed98d54SEvgeniy Kochetov 			       fopen_complete, hello_thread);
3304ed98d54SEvgeniy Kochetov 	if (res) {
3314ed98d54SEvgeniy Kochetov 		SPDK_ERRLOG("open failed with %d\n", res);
3324ed98d54SEvgeniy Kochetov 		hello_thread_done(hello_thread, EIO);
3334ed98d54SEvgeniy Kochetov 	}
3344ed98d54SEvgeniy Kochetov }
3354ed98d54SEvgeniy Kochetov 
3364ed98d54SEvgeniy Kochetov static void
3374ed98d54SEvgeniy Kochetov lookup_complete(void *cb_arg, struct spdk_io_channel *ch, int status,
3384ed98d54SEvgeniy Kochetov 		struct spdk_fsdev_file_object *fobject, const struct spdk_fsdev_file_attr *attr)
3394ed98d54SEvgeniy Kochetov {
3404ed98d54SEvgeniy Kochetov 	struct hello_thread_t *hello_thread = cb_arg;
3414ed98d54SEvgeniy Kochetov 
3424ed98d54SEvgeniy Kochetov 	SPDK_NOTICELOG("Lookup complete (status=%d)\n", status);
3434ed98d54SEvgeniy Kochetov 	if (!hello_check_complete(hello_thread, status, "lookup")) {
3444ed98d54SEvgeniy Kochetov 		return;
3454ed98d54SEvgeniy Kochetov 	}
3464ed98d54SEvgeniy Kochetov 
3474ed98d54SEvgeniy Kochetov 	assert(hello_thread->fobject == fobject);
3484ed98d54SEvgeniy Kochetov 	hello_open(hello_thread);
3494ed98d54SEvgeniy Kochetov }
3504ed98d54SEvgeniy Kochetov 
3514ed98d54SEvgeniy Kochetov static void
3524ed98d54SEvgeniy Kochetov hello_lookup(struct hello_thread_t *hello_thread)
3534ed98d54SEvgeniy Kochetov {
3544ed98d54SEvgeniy Kochetov 	struct hello_context_t *hello_context = hello_thread->hello_context;
3554ed98d54SEvgeniy Kochetov 	int res;
3564ed98d54SEvgeniy Kochetov 
3574ed98d54SEvgeniy Kochetov 	SPDK_NOTICELOG("Lookup file %s\n", hello_thread->file_name);
3584ed98d54SEvgeniy Kochetov 
3594ed98d54SEvgeniy Kochetov 	res = spdk_fsdev_lookup(hello_context->fsdev_desc, hello_thread->fsdev_io_channel,
3604ed98d54SEvgeniy Kochetov 				hello_thread->unique, hello_context->root_fobject, hello_thread->file_name,
3614ed98d54SEvgeniy Kochetov 				lookup_complete, hello_thread);
3624ed98d54SEvgeniy Kochetov 	if (res) {
3634ed98d54SEvgeniy Kochetov 		SPDK_ERRLOG("lookup failed with %d\n", res);
3644ed98d54SEvgeniy Kochetov 		hello_thread_done(hello_thread, EIO);
3654ed98d54SEvgeniy Kochetov 	}
3664ed98d54SEvgeniy Kochetov }
3674ed98d54SEvgeniy Kochetov 
3684ed98d54SEvgeniy Kochetov static void
3694ed98d54SEvgeniy Kochetov mknod_complete(void *cb_arg, struct spdk_io_channel *ch, int status,
3704ed98d54SEvgeniy Kochetov 	       struct spdk_fsdev_file_object *fobject, const struct spdk_fsdev_file_attr *attr)
3714ed98d54SEvgeniy Kochetov {
3724ed98d54SEvgeniy Kochetov 	struct hello_thread_t *hello_thread = cb_arg;
3734ed98d54SEvgeniy Kochetov 
3744ed98d54SEvgeniy Kochetov 	SPDK_NOTICELOG("Mknod complete (status=%d)\n", status);
3754ed98d54SEvgeniy Kochetov 	if (!hello_check_complete(hello_thread, status, "mknod")) {
3764ed98d54SEvgeniy Kochetov 		return;
3774ed98d54SEvgeniy Kochetov 	}
3784ed98d54SEvgeniy Kochetov 
3794ed98d54SEvgeniy Kochetov 	hello_thread->fobject = fobject;
3804ed98d54SEvgeniy Kochetov 	hello_lookup(hello_thread);
3814ed98d54SEvgeniy Kochetov }
3824ed98d54SEvgeniy Kochetov 
3834ed98d54SEvgeniy Kochetov static void
3844ed98d54SEvgeniy Kochetov hello_mknod(void *ctx)
3854ed98d54SEvgeniy Kochetov {
3864ed98d54SEvgeniy Kochetov 	struct hello_thread_t *hello_thread = (struct hello_thread_t *)ctx;
3874ed98d54SEvgeniy Kochetov 	struct hello_context_t *hello_context = hello_thread->hello_context;
3884ed98d54SEvgeniy Kochetov 	int res;
3894ed98d54SEvgeniy Kochetov 
3904ed98d54SEvgeniy Kochetov 	SPDK_NOTICELOG("Mknod file %s\n", hello_thread->file_name);
3914ed98d54SEvgeniy Kochetov 
3924ed98d54SEvgeniy Kochetov 	res = spdk_fsdev_mknod(hello_context->fsdev_desc, hello_thread->fsdev_io_channel,
3934ed98d54SEvgeniy Kochetov 			       hello_thread->unique, hello_context->root_fobject, hello_thread->file_name,
3944ed98d54SEvgeniy Kochetov 			       S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO, 0, 0, 0, mknod_complete, hello_thread);
3954ed98d54SEvgeniy Kochetov 	if (res) {
3964ed98d54SEvgeniy Kochetov 		SPDK_ERRLOG("mknod failed with %d\n", res);
3974ed98d54SEvgeniy Kochetov 		hello_thread_done(hello_thread, EIO);
3984ed98d54SEvgeniy Kochetov 	}
3994ed98d54SEvgeniy Kochetov }
4004ed98d54SEvgeniy Kochetov 
4014ed98d54SEvgeniy Kochetov static void
4024ed98d54SEvgeniy Kochetov hello_start_thread(void *ctx)
4034ed98d54SEvgeniy Kochetov {
4044ed98d54SEvgeniy Kochetov 	struct hello_context_t *hello_context = (struct hello_context_t *)ctx;
4054ed98d54SEvgeniy Kochetov 	struct hello_thread_t *hello_thread;
4064ed98d54SEvgeniy Kochetov 	/* File name size assumes that core number will fit into 3 characters */
4074ed98d54SEvgeniy Kochetov 	const int filename_size = strlen(TEST_FILENAME) + 5;
4084ed98d54SEvgeniy Kochetov 
4094ed98d54SEvgeniy Kochetov 	hello_thread = calloc(1, sizeof(struct hello_thread_t));
4104ed98d54SEvgeniy Kochetov 	if (!hello_thread) {
4114ed98d54SEvgeniy Kochetov 		SPDK_ERRLOG("Failed to allocate thread context\n");
4124ed98d54SEvgeniy Kochetov 		spdk_thread_send_msg(hello_context->app_thread, hello_app_notify_thread_done, hello_context);
4134ed98d54SEvgeniy Kochetov 		return;
4144ed98d54SEvgeniy Kochetov 	}
4154ed98d54SEvgeniy Kochetov 
4164ed98d54SEvgeniy Kochetov 	hello_thread->hello_context = hello_context;
4174ed98d54SEvgeniy Kochetov 	hello_thread->thread = spdk_get_thread();
4184ed98d54SEvgeniy Kochetov 	hello_thread->unique = 1;
4194ed98d54SEvgeniy Kochetov 	hello_thread->buf = (char *)malloc(DATA_SIZE);
4204ed98d54SEvgeniy Kochetov 	if (!hello_thread->buf) {
4214ed98d54SEvgeniy Kochetov 		SPDK_ERRLOG("Could not allocate data buffer\n");
4224ed98d54SEvgeniy Kochetov 		hello_thread_done(hello_thread, ENOMEM);
4234ed98d54SEvgeniy Kochetov 		return;
4244ed98d54SEvgeniy Kochetov 	}
4254ed98d54SEvgeniy Kochetov 
4264ed98d54SEvgeniy Kochetov 	hello_thread->file_name = (char *)malloc(filename_size);
4274ed98d54SEvgeniy Kochetov 	if (!hello_thread->file_name) {
4284ed98d54SEvgeniy Kochetov 		SPDK_ERRLOG("Could not allocate file name buffer\n");
4294ed98d54SEvgeniy Kochetov 		hello_thread_done(hello_thread, ENOMEM);
4304ed98d54SEvgeniy Kochetov 		return;
4314ed98d54SEvgeniy Kochetov 	}
4324ed98d54SEvgeniy Kochetov 
4334ed98d54SEvgeniy Kochetov 	if (snprintf(hello_thread->file_name, filename_size, "%s_%u",
4344ed98d54SEvgeniy Kochetov 		     TEST_FILENAME, spdk_env_get_current_core()) >= filename_size) {
4354ed98d54SEvgeniy Kochetov 		SPDK_ERRLOG("File name size doesn't fit into buffer\n");
4364ed98d54SEvgeniy Kochetov 		hello_thread_done(hello_thread, ENOMEM);
4374ed98d54SEvgeniy Kochetov 		return;
4384ed98d54SEvgeniy Kochetov 	}
4394ed98d54SEvgeniy Kochetov 
4404ed98d54SEvgeniy Kochetov 	hello_thread->fsdev_io_channel = spdk_fsdev_get_io_channel(hello_thread->hello_context->fsdev_desc);
4414ed98d54SEvgeniy Kochetov 	if (!hello_thread->fsdev_io_channel) {
4424ed98d54SEvgeniy Kochetov 		SPDK_ERRLOG("Could not create fsdev I/O channel!\n");
4434ed98d54SEvgeniy Kochetov 		hello_thread_done(hello_thread, ENOMEM);
4444ed98d54SEvgeniy Kochetov 		return;
4454ed98d54SEvgeniy Kochetov 	}
4464ed98d54SEvgeniy Kochetov 
4474ed98d54SEvgeniy Kochetov 	SPDK_NOTICELOG("Started thread %s on core %u\n",
4484ed98d54SEvgeniy Kochetov 		       spdk_thread_get_name(hello_thread->thread),
4494ed98d54SEvgeniy Kochetov 		       spdk_env_get_current_core());
4504ed98d54SEvgeniy Kochetov 	spdk_thread_send_msg(hello_thread->thread, hello_mknod, hello_thread);
4514ed98d54SEvgeniy Kochetov }
4524ed98d54SEvgeniy Kochetov 
4534ed98d54SEvgeniy Kochetov static void
4544ed98d54SEvgeniy Kochetov hello_create_threads(struct hello_context_t *hello_context)
4554ed98d54SEvgeniy Kochetov {
4564ed98d54SEvgeniy Kochetov 	uint32_t cpu;
4574ed98d54SEvgeniy Kochetov 	char thread_name[32];
4584ed98d54SEvgeniy Kochetov 	struct spdk_cpuset mask = {};
4594ed98d54SEvgeniy Kochetov 	struct spdk_thread *thread;
4604ed98d54SEvgeniy Kochetov 
4614ed98d54SEvgeniy Kochetov 	SPDK_ENV_FOREACH_CORE(cpu) {
4624ed98d54SEvgeniy Kochetov 		snprintf(thread_name, sizeof(thread_name), "hello_fsdev_%u", cpu);
4634ed98d54SEvgeniy Kochetov 		spdk_cpuset_zero(&mask);
4644ed98d54SEvgeniy Kochetov 		spdk_cpuset_set_cpu(&mask, cpu, true);
4654ed98d54SEvgeniy Kochetov 		thread = spdk_thread_create(thread_name, &mask);
4664ed98d54SEvgeniy Kochetov 		assert(thread != NULL);
4674ed98d54SEvgeniy Kochetov 		hello_context->thread_count++;
4684ed98d54SEvgeniy Kochetov 		spdk_thread_send_msg(thread, hello_start_thread, hello_context);
4694ed98d54SEvgeniy Kochetov 	}
4704ed98d54SEvgeniy Kochetov }
4714ed98d54SEvgeniy Kochetov 
4724ed98d54SEvgeniy Kochetov 
4734ed98d54SEvgeniy Kochetov static void
4744ed98d54SEvgeniy Kochetov root_lookup_complete(void *cb_arg, struct spdk_io_channel *ch, int status,
4754ed98d54SEvgeniy Kochetov 		     struct spdk_fsdev_file_object *fobject, const struct spdk_fsdev_file_attr *attr)
4764ed98d54SEvgeniy Kochetov {
4774ed98d54SEvgeniy Kochetov 	struct hello_context_t *hello_context = cb_arg;
4784ed98d54SEvgeniy Kochetov 
4794ed98d54SEvgeniy Kochetov 	SPDK_NOTICELOG("Root lookup complete (status=%d)\n", status);
4804ed98d54SEvgeniy Kochetov 	if (status) {
4814ed98d54SEvgeniy Kochetov 		SPDK_ERRLOG("Fuse init failed: error %d\n", status);
4824ed98d54SEvgeniy Kochetov 		hello_app_done(hello_context, status);
4834ed98d54SEvgeniy Kochetov 		return;
4844ed98d54SEvgeniy Kochetov 	}
4854ed98d54SEvgeniy Kochetov 
4864ed98d54SEvgeniy Kochetov 	hello_context->root_fobject = fobject;
4874ed98d54SEvgeniy Kochetov 
4884ed98d54SEvgeniy Kochetov 	hello_create_threads(hello_context);
4894ed98d54SEvgeniy Kochetov }
4904ed98d54SEvgeniy Kochetov 
4914ed98d54SEvgeniy Kochetov static void
4924ed98d54SEvgeniy Kochetov root_lookup(struct hello_context_t *hello_context)
4934ed98d54SEvgeniy Kochetov {
4944ed98d54SEvgeniy Kochetov 	int res;
4954ed98d54SEvgeniy Kochetov 
4964ed98d54SEvgeniy Kochetov 	SPDK_NOTICELOG("Lookup for the root\n");
4974ed98d54SEvgeniy Kochetov 
4984ed98d54SEvgeniy Kochetov 	res = spdk_fsdev_lookup(hello_context->fsdev_desc, hello_context->fsdev_io_channel, 0,
4994ed98d54SEvgeniy Kochetov 				NULL /* root */, "" /* will be ignored */, root_lookup_complete, hello_context);
5004ed98d54SEvgeniy Kochetov 	if (res) {
5014ed98d54SEvgeniy Kochetov 		SPDK_ERRLOG("Failed to initiate lookup for the root (err=%d)\n", res);
5024ed98d54SEvgeniy Kochetov 		hello_app_done(hello_context, res);
5034ed98d54SEvgeniy Kochetov 		return;
5044ed98d54SEvgeniy Kochetov 	}
5054ed98d54SEvgeniy Kochetov }
5064ed98d54SEvgeniy Kochetov 
5074ed98d54SEvgeniy Kochetov static void
5084ed98d54SEvgeniy Kochetov hello_fsdev_event_cb(enum spdk_fsdev_event_type type, struct spdk_fsdev *fsdev, void *event_ctx)
5094ed98d54SEvgeniy Kochetov {
5104ed98d54SEvgeniy Kochetov 	SPDK_NOTICELOG("Unsupported fsdev event: type %d\n", type);
5114ed98d54SEvgeniy Kochetov }
5124ed98d54SEvgeniy Kochetov 
5134ed98d54SEvgeniy Kochetov /*
5144ed98d54SEvgeniy Kochetov  * Our initial event that kicks off everything from main().
5154ed98d54SEvgeniy Kochetov  */
5164ed98d54SEvgeniy Kochetov static void
5174ed98d54SEvgeniy Kochetov hello_start(void *arg1)
5184ed98d54SEvgeniy Kochetov {
5194ed98d54SEvgeniy Kochetov 	struct hello_context_t *hello_context = arg1;
5204ed98d54SEvgeniy Kochetov 	int rc = 0;
5214ed98d54SEvgeniy Kochetov 	hello_context->fsdev_desc = NULL;
5224ed98d54SEvgeniy Kochetov 
5234ed98d54SEvgeniy Kochetov 	SPDK_NOTICELOG("Successfully started the application\n");
5244ed98d54SEvgeniy Kochetov 
5254ed98d54SEvgeniy Kochetov 	hello_context->app_thread = spdk_get_thread();
5264ed98d54SEvgeniy Kochetov 
5274ed98d54SEvgeniy Kochetov 	/*
5284ed98d54SEvgeniy Kochetov 	 * There can be many fsdevs configured, but this application will only use
5294ed98d54SEvgeniy Kochetov 	 * the one input by the user at runtime.
5304ed98d54SEvgeniy Kochetov 	 *
5314ed98d54SEvgeniy Kochetov 	 * Open the fs by calling spdk_fsdev_open() with its name.
5324ed98d54SEvgeniy Kochetov 	 * The function will return a descriptor
5334ed98d54SEvgeniy Kochetov 	 */
5344ed98d54SEvgeniy Kochetov 	SPDK_NOTICELOG("Opening the fsdev %s\n", hello_context->fsdev_name);
5354ed98d54SEvgeniy Kochetov 	rc = spdk_fsdev_open(hello_context->fsdev_name,
536*6cb9c75cSAnton Nayshtut 			     hello_fsdev_event_cb, NULL,
5374ed98d54SEvgeniy Kochetov 			     &hello_context->fsdev_desc);
5384ed98d54SEvgeniy Kochetov 	if (rc) {
5394ed98d54SEvgeniy Kochetov 		SPDK_ERRLOG("Could not open fsdev: %s\n", hello_context->fsdev_name);
5404ed98d54SEvgeniy Kochetov 		spdk_app_stop(-1);
5414ed98d54SEvgeniy Kochetov 		return;
5424ed98d54SEvgeniy Kochetov 	}
5434ed98d54SEvgeniy Kochetov 
5444ed98d54SEvgeniy Kochetov 	SPDK_NOTICELOG("Opening io channel\n");
5454ed98d54SEvgeniy Kochetov 	/* Open I/O channel */
5464ed98d54SEvgeniy Kochetov 	hello_context->fsdev_io_channel = spdk_fsdev_get_io_channel(hello_context->fsdev_desc);
5474ed98d54SEvgeniy Kochetov 	if (!hello_context->fsdev_io_channel) {
5484ed98d54SEvgeniy Kochetov 		SPDK_ERRLOG("Could not create fsdev I/O channel!\n");
5494ed98d54SEvgeniy Kochetov 		spdk_fsdev_close(hello_context->fsdev_desc);
5504ed98d54SEvgeniy Kochetov 		spdk_app_stop(-1);
5514ed98d54SEvgeniy Kochetov 		return;
5524ed98d54SEvgeniy Kochetov 	}
5534ed98d54SEvgeniy Kochetov 
5544ed98d54SEvgeniy Kochetov 	root_lookup(hello_context);
5554ed98d54SEvgeniy Kochetov }
5564ed98d54SEvgeniy Kochetov 
5574ed98d54SEvgeniy Kochetov int
5584ed98d54SEvgeniy Kochetov main(int argc, char **argv)
5594ed98d54SEvgeniy Kochetov {
5604ed98d54SEvgeniy Kochetov 	struct spdk_app_opts opts = {};
5614ed98d54SEvgeniy Kochetov 	int rc = 0;
5624ed98d54SEvgeniy Kochetov 	struct hello_context_t hello_context = {};
5634ed98d54SEvgeniy Kochetov 
5644ed98d54SEvgeniy Kochetov 	/* Set default values in opts structure. */
5654ed98d54SEvgeniy Kochetov 	spdk_app_opts_init(&opts, sizeof(opts));
5664ed98d54SEvgeniy Kochetov 	opts.name = "hello_fsdev";
5674ed98d54SEvgeniy Kochetov 
5684ed98d54SEvgeniy Kochetov 	/*
5694ed98d54SEvgeniy Kochetov 	 * Parse built-in SPDK command line parameters as well
5704ed98d54SEvgeniy Kochetov 	 * as our custom one(s).
5714ed98d54SEvgeniy Kochetov 	 */
5724ed98d54SEvgeniy Kochetov 	if ((rc = spdk_app_parse_args(argc, argv, &opts, "f:", NULL, hello_fsdev_parse_arg,
5734ed98d54SEvgeniy Kochetov 				      hello_fsdev_usage)) != SPDK_APP_PARSE_ARGS_SUCCESS) {
5744ed98d54SEvgeniy Kochetov 		exit(rc);
5754ed98d54SEvgeniy Kochetov 	}
5764ed98d54SEvgeniy Kochetov 	hello_context.fsdev_name = g_fsdev_name;
5774ed98d54SEvgeniy Kochetov 
5784ed98d54SEvgeniy Kochetov 	/*
5794ed98d54SEvgeniy Kochetov 	 * spdk_app_start() will initialize the SPDK framework, call hello_start(),
5804ed98d54SEvgeniy Kochetov 	 * and then block until spdk_app_stop() is called (or if an initialization
5814ed98d54SEvgeniy Kochetov 	 * error occurs, spdk_app_start() will return with rc even without calling
5824ed98d54SEvgeniy Kochetov 	 * hello_start().
5834ed98d54SEvgeniy Kochetov 	 */
5844ed98d54SEvgeniy Kochetov 	rc = spdk_app_start(&opts, hello_start, &hello_context);
5854ed98d54SEvgeniy Kochetov 	if (rc) {
5864ed98d54SEvgeniy Kochetov 		SPDK_ERRLOG("ERROR starting application\n");
5874ed98d54SEvgeniy Kochetov 	}
5884ed98d54SEvgeniy Kochetov 
5894ed98d54SEvgeniy Kochetov 	/* At this point either spdk_app_stop() was called, or spdk_app_start()
5904ed98d54SEvgeniy Kochetov 	 * failed because of internal error.
5914ed98d54SEvgeniy Kochetov 	 */
5924ed98d54SEvgeniy Kochetov 
5934ed98d54SEvgeniy Kochetov 	/* Gracefully close out all of the SPDK subsystems. */
5944ed98d54SEvgeniy Kochetov 	spdk_app_fini();
5954ed98d54SEvgeniy Kochetov 	return rc;
5964ed98d54SEvgeniy Kochetov }
597