xref: /spdk/module/bdev/ftl/bdev_ftl.c (revision 927f1fd57bd004df581518466ec4c1b8083e5d23)
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/bdev.h"
36  #include "spdk/env.h"
37  #include "spdk/thread.h"
38  #include "spdk/json.h"
39  #include "spdk/string.h"
40  #include "spdk/likely.h"
41  #include "spdk/util.h"
42  #include "spdk/string.h"
43  #include "spdk/ftl.h"
44  #include "spdk/log.h"
45  
46  #include "bdev_ftl.h"
47  
48  struct ftl_bdev {
49  	struct spdk_bdev		bdev;
50  
51  	struct spdk_ftl_dev		*dev;
52  
53  	ftl_bdev_init_fn		init_cb;
54  
55  	void				*init_arg;
56  };
57  
58  struct ftl_deferred_init {
59  	struct ftl_bdev_init_opts	opts;
60  
61  	LIST_ENTRY(ftl_deferred_init)	entry;
62  };
63  
64  static LIST_HEAD(, ftl_deferred_init)	g_deferred_init = LIST_HEAD_INITIALIZER(g_deferred_init);
65  
66  static int bdev_ftl_initialize(void);
67  static void bdev_ftl_finish(void);
68  static void bdev_ftl_examine(struct spdk_bdev *bdev);
69  
70  static struct spdk_bdev_module g_ftl_if = {
71  	.name		= "ftl",
72  	.module_init	= bdev_ftl_initialize,
73  	.module_fini	= bdev_ftl_finish,
74  	.examine_disk	= bdev_ftl_examine,
75  };
76  
77  SPDK_BDEV_MODULE_REGISTER(ftl, &g_ftl_if)
78  
79  static void
80  bdev_ftl_free_cb(struct spdk_ftl_dev *dev, void *ctx, int status)
81  {
82  	struct ftl_bdev *ftl_bdev = ctx;
83  
84  	spdk_bdev_destruct_done(&ftl_bdev->bdev, status);
85  	free(ftl_bdev->bdev.name);
86  	free(ftl_bdev);
87  }
88  
89  static int
90  bdev_ftl_destruct(void *ctx)
91  {
92  	struct ftl_bdev *ftl_bdev = ctx;
93  	spdk_ftl_dev_free(ftl_bdev->dev, bdev_ftl_free_cb, ftl_bdev);
94  
95  	/* return 1 to indicate that the destruction is asynchronous */
96  	return 1;
97  }
98  
99  static void
100  bdev_ftl_cb(void *arg, int rc)
101  {
102  	struct spdk_bdev_io *bdev_io = arg;
103  	enum spdk_bdev_io_status status;
104  
105  	switch (rc) {
106  	case 0:
107  		status = SPDK_BDEV_IO_STATUS_SUCCESS;
108  		break;
109  	case -ENOMEM:
110  		status = SPDK_BDEV_IO_STATUS_NOMEM;
111  		break;
112  	default:
113  		status = SPDK_BDEV_IO_STATUS_FAILED;
114  		break;
115  	}
116  
117  	spdk_bdev_io_complete(bdev_io, status);
118  }
119  
120  static void
121  bdev_ftl_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io,
122  		    bool success)
123  {
124  	struct ftl_bdev *ftl_bdev;
125  	int rc;
126  
127  	ftl_bdev = bdev_io->bdev->ctxt;
128  
129  	if (!success) {
130  		spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
131  		return;
132  	}
133  
134  	rc = spdk_ftl_read(ftl_bdev->dev,
135  			   ch,
136  			   bdev_io->u.bdev.offset_blocks,
137  			   bdev_io->u.bdev.num_blocks,
138  			   bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt, bdev_ftl_cb, bdev_io);
139  
140  	if (spdk_unlikely(rc != 0)) {
141  		spdk_bdev_io_complete(bdev_io, rc);
142  	}
143  }
144  
145  static int
146  _bdev_ftl_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
147  {
148  	struct ftl_bdev *ftl_bdev = (struct ftl_bdev *)bdev_io->bdev->ctxt;
149  
150  	switch (bdev_io->type) {
151  	case SPDK_BDEV_IO_TYPE_READ:
152  		spdk_bdev_io_get_buf(bdev_io, bdev_ftl_get_buf_cb,
153  				     bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen);
154  		return 0;
155  
156  	case SPDK_BDEV_IO_TYPE_WRITE:
157  		return spdk_ftl_write(ftl_bdev->dev, ch, bdev_io->u.bdev.offset_blocks,
158  				      bdev_io->u.bdev.num_blocks, bdev_io->u.bdev.iovs,
159  				      bdev_io->u.bdev.iovcnt, bdev_ftl_cb, bdev_io);
160  
161  	case SPDK_BDEV_IO_TYPE_FLUSH:
162  		return spdk_ftl_flush(ftl_bdev->dev, bdev_ftl_cb, bdev_io);
163  
164  	case SPDK_BDEV_IO_TYPE_WRITE_ZEROES:
165  	case SPDK_BDEV_IO_TYPE_RESET:
166  	case SPDK_BDEV_IO_TYPE_UNMAP:
167  	default:
168  		return -ENOTSUP;
169  		break;
170  	}
171  }
172  
173  static void
174  bdev_ftl_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
175  {
176  	int rc = _bdev_ftl_submit_request(ch, bdev_io);
177  
178  	if (spdk_unlikely(rc != 0)) {
179  		spdk_bdev_io_complete(bdev_io, rc);
180  	}
181  }
182  
183  static bool
184  bdev_ftl_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type)
185  {
186  	switch (io_type) {
187  	case SPDK_BDEV_IO_TYPE_READ:
188  	case SPDK_BDEV_IO_TYPE_WRITE:
189  	case SPDK_BDEV_IO_TYPE_FLUSH:
190  		return true;
191  	case SPDK_BDEV_IO_TYPE_WRITE_ZEROES:
192  	case SPDK_BDEV_IO_TYPE_RESET:
193  	case SPDK_BDEV_IO_TYPE_UNMAP:
194  	default:
195  		return false;
196  	}
197  }
198  
199  static struct spdk_io_channel *
200  bdev_ftl_get_io_channel(void *ctx)
201  {
202  	struct ftl_bdev *ftl_bdev = ctx;
203  
204  	return spdk_get_io_channel(ftl_bdev->dev);
205  }
206  
207  static void
208  _bdev_ftl_write_config_info(struct ftl_bdev *ftl_bdev, struct spdk_json_write_ctx *w)
209  {
210  	struct spdk_ftl_attrs attrs = {};
211  
212  	spdk_ftl_dev_get_attrs(ftl_bdev->dev, &attrs);
213  
214  	spdk_json_write_named_string(w, "base_bdev", attrs.base_bdev);
215  
216  	if (attrs.cache_bdev) {
217  		spdk_json_write_named_string(w, "cache", attrs.cache_bdev);
218  	}
219  }
220  
221  static void
222  bdev_ftl_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w)
223  {
224  	struct ftl_bdev *ftl_bdev = bdev->ctxt;
225  	struct spdk_ftl_attrs attrs;
226  	struct spdk_ftl_conf *conf = &attrs.conf;
227  	char uuid[SPDK_UUID_STRING_LEN];
228  
229  	spdk_ftl_dev_get_attrs(ftl_bdev->dev, &attrs);
230  
231  	spdk_json_write_object_begin(w);
232  
233  	spdk_json_write_named_string(w, "method", "bdev_ftl_create");
234  
235  	spdk_json_write_named_object_begin(w, "params");
236  	spdk_json_write_named_string(w, "name", ftl_bdev->bdev.name);
237  
238  	spdk_json_write_named_bool(w, "allow_open_bands", conf->allow_open_bands);
239  	spdk_json_write_named_uint64(w, "overprovisioning", conf->lba_rsvd);
240  	spdk_json_write_named_uint64(w, "limit_crit", conf->limits[SPDK_FTL_LIMIT_CRIT].limit);
241  	spdk_json_write_named_uint64(w, "limit_crit_threshold", conf->limits[SPDK_FTL_LIMIT_CRIT].thld);
242  	spdk_json_write_named_uint64(w, "limit_high", conf->limits[SPDK_FTL_LIMIT_HIGH].limit);
243  	spdk_json_write_named_uint64(w, "limit_high_threshold", conf->limits[SPDK_FTL_LIMIT_HIGH].thld);
244  	spdk_json_write_named_uint64(w, "limit_low", conf->limits[SPDK_FTL_LIMIT_LOW].limit);
245  	spdk_json_write_named_uint64(w, "limit_low_threshold", conf->limits[SPDK_FTL_LIMIT_LOW].thld);
246  	spdk_json_write_named_uint64(w, "limit_start", conf->limits[SPDK_FTL_LIMIT_START].limit);
247  	spdk_json_write_named_uint64(w, "limit_start_threshold", conf->limits[SPDK_FTL_LIMIT_START].thld);
248  	if (conf->l2p_path) {
249  		spdk_json_write_named_string(w, "l2p_path", conf->l2p_path);
250  	}
251  
252  	spdk_uuid_fmt_lower(uuid, sizeof(uuid), &attrs.uuid);
253  	spdk_json_write_named_string(w, "uuid", uuid);
254  
255  	_bdev_ftl_write_config_info(ftl_bdev, w);
256  
257  	spdk_json_write_object_end(w);
258  	spdk_json_write_object_end(w);
259  }
260  
261  static int
262  bdev_ftl_dump_info_json(void *ctx, struct spdk_json_write_ctx *w)
263  {
264  	struct ftl_bdev *ftl_bdev = ctx;
265  	struct spdk_ftl_attrs attrs;
266  
267  	spdk_ftl_dev_get_attrs(ftl_bdev->dev, &attrs);
268  
269  	spdk_json_write_named_object_begin(w, "ftl");
270  
271  	_bdev_ftl_write_config_info(ftl_bdev, w);
272  	spdk_json_write_named_string_fmt(w, "num_zones", "%zu", attrs.num_zones);
273  	spdk_json_write_named_string_fmt(w, "zone_size", "%zu", attrs.zone_size);
274  
275  	/* ftl */
276  	spdk_json_write_object_end(w);
277  
278  	return 0;
279  }
280  
281  static const struct spdk_bdev_fn_table ftl_fn_table = {
282  	.destruct		= bdev_ftl_destruct,
283  	.submit_request		= bdev_ftl_submit_request,
284  	.io_type_supported	= bdev_ftl_io_type_supported,
285  	.get_io_channel		= bdev_ftl_get_io_channel,
286  	.write_config_json	= bdev_ftl_write_config_json,
287  	.dump_info_json		= bdev_ftl_dump_info_json,
288  };
289  
290  static void
291  bdev_ftl_create_cb(struct spdk_ftl_dev *dev, void *ctx, int status)
292  {
293  	struct ftl_bdev		*ftl_bdev = ctx;
294  	struct ftl_bdev_info	info = {};
295  	struct spdk_ftl_attrs	attrs;
296  	ftl_bdev_init_fn	init_cb = ftl_bdev->init_cb;
297  	void			*init_arg = ftl_bdev->init_arg;
298  	int			rc = -ENODEV;
299  
300  	if (status) {
301  		SPDK_ERRLOG("Failed to create FTL device (%d)\n", status);
302  		rc = status;
303  		goto error;
304  	}
305  
306  	spdk_ftl_dev_get_attrs(dev, &attrs);
307  
308  	ftl_bdev->dev = dev;
309  	ftl_bdev->bdev.product_name = "FTL disk";
310  	ftl_bdev->bdev.write_cache = 0;
311  	ftl_bdev->bdev.blocklen = attrs.block_size;
312  	ftl_bdev->bdev.blockcnt = attrs.num_blocks;
313  	ftl_bdev->bdev.uuid = attrs.uuid;
314  
315  	SPDK_DEBUGLOG(bdev_ftl, "Creating bdev %s:\n", ftl_bdev->bdev.name);
316  	SPDK_DEBUGLOG(bdev_ftl, "\tblock_len:\t%zu\n", attrs.block_size);
317  	SPDK_DEBUGLOG(bdev_ftl, "\tnum_blocks:\t%"PRIu64"\n", attrs.num_blocks);
318  
319  	ftl_bdev->bdev.ctxt = ftl_bdev;
320  	ftl_bdev->bdev.fn_table = &ftl_fn_table;
321  	ftl_bdev->bdev.module = &g_ftl_if;
322  
323  	if (spdk_bdev_register(&ftl_bdev->bdev)) {
324  		goto error;
325  	}
326  
327  	info.name = ftl_bdev->bdev.name;
328  	info.uuid = ftl_bdev->bdev.uuid;
329  
330  	init_cb(&info, init_arg, 0);
331  	return;
332  
333  error:
334  	free(ftl_bdev->bdev.name);
335  	free(ftl_bdev);
336  
337  	init_cb(NULL, init_arg, rc);
338  }
339  
340  static void
341  bdev_ftl_defer_free(struct ftl_deferred_init *init)
342  {
343  	free((char *)init->opts.name);
344  	free((char *)init->opts.base_bdev);
345  	free((char *)init->opts.cache_bdev);
346  	free(init);
347  }
348  
349  static int
350  bdev_ftl_defer_init(const struct ftl_bdev_init_opts *opts)
351  {
352  	struct ftl_deferred_init *init;
353  
354  	init = calloc(1, sizeof(*init));
355  	if (!init) {
356  		return -ENOMEM;
357  	}
358  
359  	init->opts.mode = opts->mode;
360  	init->opts.uuid = opts->uuid;
361  	init->opts.ftl_conf = opts->ftl_conf;
362  
363  	init->opts.name = strdup(opts->name);
364  	if (!init->opts.name) {
365  		SPDK_ERRLOG("Could not allocate bdev name\n");
366  		goto error;
367  	}
368  
369  	init->opts.base_bdev = strdup(opts->base_bdev);
370  	if (!init->opts.base_bdev) {
371  		SPDK_ERRLOG("Could not allocate base bdev name\n");
372  		goto error;
373  	}
374  
375  	if (opts->cache_bdev) {
376  		init->opts.cache_bdev = strdup(opts->cache_bdev);
377  		if (!init->opts.cache_bdev) {
378  			SPDK_ERRLOG("Could not allocate cache bdev name\n");
379  			goto error;
380  		}
381  	}
382  
383  	LIST_INSERT_HEAD(&g_deferred_init, init, entry);
384  
385  	return 0;
386  
387  error:
388  	bdev_ftl_defer_free(init);
389  	return -ENOMEM;
390  }
391  
392  int
393  bdev_ftl_create_bdev(const struct ftl_bdev_init_opts *bdev_opts,
394  		     ftl_bdev_init_fn cb, void *cb_arg)
395  {
396  	struct ftl_bdev *ftl_bdev = NULL;
397  	struct spdk_ftl_dev_init_opts opts = {};
398  	int rc;
399  
400  	ftl_bdev = calloc(1, sizeof(*ftl_bdev));
401  	if (!ftl_bdev) {
402  		SPDK_ERRLOG("Could not allocate ftl_bdev\n");
403  		return -ENOMEM;
404  	}
405  
406  	ftl_bdev->bdev.name = strdup(bdev_opts->name);
407  	if (!ftl_bdev->bdev.name) {
408  		rc = -ENOMEM;
409  		goto error_bdev;
410  	}
411  
412  	if (spdk_bdev_get_by_name(bdev_opts->base_bdev) == NULL ||
413  	    (bdev_opts->cache_bdev && spdk_bdev_get_by_name(bdev_opts->cache_bdev) == NULL)) {
414  		rc = bdev_ftl_defer_init(bdev_opts);
415  		if (rc == 0) {
416  			rc = -ENODEV;
417  		}
418  		goto error_name;
419  	}
420  
421  	ftl_bdev->init_cb = cb;
422  	ftl_bdev->init_arg = cb_arg;
423  
424  	opts.mode = bdev_opts->mode;
425  	opts.uuid = bdev_opts->uuid;
426  	opts.name = ftl_bdev->bdev.name;
427  	opts.base_bdev = bdev_opts->base_bdev;
428  	opts.cache_bdev = bdev_opts->cache_bdev;
429  	opts.conf = &bdev_opts->ftl_conf;
430  
431  	/* TODO: set threads based on config */
432  	opts.core_thread = spdk_get_thread();
433  
434  	rc = spdk_ftl_dev_init(&opts, bdev_ftl_create_cb, ftl_bdev);
435  	if (rc) {
436  		SPDK_ERRLOG("Could not create FTL device\n");
437  		goto error_name;
438  	}
439  
440  	return 0;
441  
442  error_name:
443  	free(ftl_bdev->bdev.name);
444  error_bdev:
445  	free(ftl_bdev);
446  	return rc;
447  }
448  
449  static int
450  bdev_ftl_initialize(void)
451  {
452  	return 0;
453  }
454  
455  void
456  bdev_ftl_delete_bdev(const char *name, spdk_bdev_unregister_cb cb_fn, void *cb_arg)
457  {
458  	int rc;
459  
460  	rc = spdk_bdev_unregister_by_name(name, &g_ftl_if, cb_fn, cb_arg);
461  	if (rc != 0) {
462  		cb_fn(cb_arg, rc);
463  	}
464  }
465  
466  static void
467  bdev_ftl_finish(void)
468  {
469  }
470  
471  static void
472  bdev_ftl_create_deferred_cb(const struct ftl_bdev_info *info, void *ctx, int status)
473  {
474  	struct ftl_deferred_init *opts = ctx;
475  
476  	if (status) {
477  		SPDK_ERRLOG("Failed to initialize FTL bdev '%s'\n", opts->opts.name);
478  	}
479  
480  	bdev_ftl_defer_free(opts);
481  
482  	spdk_bdev_module_examine_done(&g_ftl_if);
483  }
484  
485  static void
486  bdev_ftl_examine(struct spdk_bdev *bdev)
487  {
488  	struct ftl_deferred_init *opts;
489  
490  	LIST_FOREACH(opts, &g_deferred_init, entry) {
491  		if (spdk_bdev_get_by_name(opts->opts.base_bdev) == NULL) {
492  			continue;
493  		}
494  
495  		if (opts->opts.cache_bdev && spdk_bdev_get_by_name(opts->opts.base_bdev) == NULL) {
496  			continue;
497  		}
498  
499  		LIST_REMOVE(opts, entry);
500  
501  		/* spdk_bdev_module_examine_done will be called by bdev_ftl_create_deferred_cb */
502  		if (bdev_ftl_create_bdev(&opts->opts, bdev_ftl_create_deferred_cb, opts)) {
503  			SPDK_ERRLOG("Failed to initialize FTL bdev '%s'\n", opts->opts.name);
504  			bdev_ftl_defer_free(opts);
505  			break;
506  		}
507  		return;
508  	}
509  
510  	spdk_bdev_module_examine_done(&g_ftl_if);
511  }
512  
513  SPDK_LOG_REGISTER_COMPONENT(bdev_ftl)
514