Commit 818b9c05 authored by Artur Paszkiewicz's avatar Artur Paszkiewicz Committed by Jim Harris
Browse files

ftl: support for metadata on shared memory

parent aaa1ddc3
Loading
Loading
Loading
Loading
+9 −3
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ ftl_mngt_init_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
	struct ftl_layout *layout = &dev->layout;
	struct ftl_layout_region *region = layout->region;
	uint64_t i;
	int md_flags;

	for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; i++, region++) {
		if (layout->md[i]) {
@@ -61,8 +62,11 @@ ftl_mngt_init_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
			 */
			continue;
		}
		md_flags = is_buffer_needed(i) ?
			   FTL_MD_CREATE_SHM | FTL_MD_CREATE_SHM_NEW :
			   FTL_MD_CREATE_NO_MEM;
		layout->md[i] = ftl_md_create(dev, region->current.blocks, region->vss_blksz, region->name,
					      !is_buffer_needed(i), region);
					      md_flags, region);
		if (NULL == layout->md[i]) {
			ftl_mngt_fail_step(mngt);
			return;
@@ -245,6 +249,7 @@ ftl_mngt_superblock_init(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt
	struct ftl_layout *layout = &dev->layout;
	struct ftl_layout_region *region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB];
	char uuid[SPDK_UUID_STRING_LEN];
	int md_create_flags = FTL_MD_CREATE_SHM | FTL_MD_CREATE_SHM_NEW;

	/* Must generate UUID before MD create on SHM for the SB */
	if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
@@ -261,7 +266,8 @@ ftl_mngt_superblock_init(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt

	/* Allocate md buf */
	layout->md[FTL_LAYOUT_REGION_TYPE_SB] = ftl_md_create(dev, region->current.blocks,
						region->vss_blksz, region->name, false, region);
						region->vss_blksz, region->name,
						md_create_flags, region);
	if (NULL == layout->md[FTL_LAYOUT_REGION_TYPE_SB]) {
		ftl_mngt_fail_step(mngt);
		return;
@@ -273,7 +279,7 @@ ftl_mngt_superblock_init(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt
	/* Setup superblock mirror to QLC */
	region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB_BASE];
	layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE] = ftl_md_create(dev, region->current.blocks,
			region->vss_blksz, NULL, false, region);
			region->vss_blksz, NULL, FTL_MD_CREATE_HEAP, region);
	if (NULL == layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE]) {
		ftl_mngt_fail_step(mngt);
		return;
+216 −15
Original line number Diff line number Diff line
@@ -61,8 +61,194 @@ xfer_size(struct ftl_md *md)
	return ftl_md_xfer_blocks(md->dev) * FTL_BLOCK_SIZE;
}

static void
ftl_md_create_heap(struct ftl_md *md, uint64_t vss_blksz)
{
	md->shm_fd = -1;
	md->vss_data = NULL;
	md->data = calloc(md->data_blocks, FTL_BLOCK_SIZE + vss_blksz);

	if (md->data && vss_blksz) {
		md->vss_data = ((char *)md->data) + md->data_blocks * FTL_BLOCK_SIZE;
	}
}

static void
ftl_md_destroy_heap(struct ftl_md *md)
{
	if (md->data) {
		free(md->data);
		md->data = NULL;
		md->vss_data = NULL;
	}
}

static int
ftl_wrapper_open(const char *name, int of, mode_t m)
{
	return open(name, of, m);
}

static void
ftl_md_setup_obj(struct ftl_md *md, int flags,
		 const char *name)
{
	char uuid_str[SPDK_UUID_STRING_LEN];
	const char *fmt;

	if (!(flags & FTL_MD_CREATE_SHM)) {
		assert(false);
		return;
	}

	/* TODO: temporary, define a proper hugetlbfs mountpoint */
	fmt = "/dev/hugepages/ftl_%s_%s";
	md->shm_mmap_flags = MAP_SHARED;
	md->shm_open = ftl_wrapper_open;
	md->shm_unlink = unlink;

	if (name == NULL ||
	    spdk_uuid_fmt_lower(uuid_str, SPDK_UUID_STRING_LEN, &md->dev->conf.uuid) ||
	    snprintf(md->name, sizeof(md->name) / sizeof(md->name[0]),
		     fmt, uuid_str, name) <= 0) {
		md->name[0] = 0;
	}
}

static void
ftl_md_create_shm(struct ftl_md *md, uint64_t vss_blksz, int flags)
{
	struct stat shm_stat;
	size_t vss_blk_offs;
	void *shm_ptr;
	int open_flags = O_RDWR;
	mode_t open_mode = S_IRUSR | S_IWUSR;

	assert(md->shm_open && md->shm_unlink);
	md->data = NULL;
	md->vss_data = NULL;
	md->shm_sz = 0;

	/* Must have an object name */
	if (md->name[0] == 0) {
		assert(false);
		return;
	}

	/* If specified, unlink before create a new SHM object */
	if (flags & FTL_MD_CREATE_SHM_NEW) {
		if (md->shm_unlink(md->name) < 0 && errno != ENOENT) {
			return;
		}
		open_flags += O_CREAT | O_TRUNC;
	}

	/* Open existing or create a new SHM object, then query its props */
	md->shm_fd = md->shm_open(md->name, open_flags, open_mode);
	if (md->shm_fd < 0 || fstat(md->shm_fd, &shm_stat) < 0) {
		goto err_shm;
	}

	/* Verify open mode hasn't changed */
	if ((shm_stat.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)) != open_mode) {
		goto err_shm;
	}

	/* Round up the SHM obj size to the nearest blk size (i.e. page size) */
	md->shm_sz = spdk_divide_round_up(md->data_blocks * FTL_BLOCK_SIZE, shm_stat.st_blksize);

	/* Add some blks for VSS metadata */
	vss_blk_offs = md->shm_sz;

	if (vss_blksz) {
		md->shm_sz += spdk_divide_round_up(md->data_blocks * vss_blksz,
						   shm_stat.st_blksize);
	}

	/* Total SHM obj size */
	md->shm_sz *= shm_stat.st_blksize;

	/* Set or check the object size - zero init`d in case of set (FTL_MD_CREATE_SHM_NEW) */
	if ((shm_stat.st_size == 0 && (ftruncate(md->shm_fd, md->shm_sz) < 0 ||
				       (flags & FTL_MD_CREATE_SHM_NEW) == 0))
	    || (shm_stat.st_size > 0 && (size_t)shm_stat.st_size != md->shm_sz)) {
		goto err_shm;
	}

	/* Create a virtual memory mapping for the object */
	shm_ptr = mmap(NULL, md->shm_sz, PROT_READ | PROT_WRITE, md->shm_mmap_flags,
		       md->shm_fd, 0);
	if (shm_ptr == MAP_FAILED) {
		goto err_shm;
	}

	md->data = shm_ptr;
	if (vss_blksz) {
		md->vss_data = ((char *)shm_ptr) + vss_blk_offs * shm_stat.st_blksize;
	}

	/* Lock the pages in memory (i.e. prevent the pages to be paged out) */
	if (mlock(md->data, md->shm_sz) < 0) {
		goto err_map;
	}

	if (spdk_mem_register(md->data, md->shm_sz)) {
		goto err_mlock;
	}
	md->mem_reg = true;

	return;

	/* Cleanup upon fault */
err_mlock:
	munlock(md->data, md->shm_sz);

err_map:
	munmap(md->data, md->shm_sz);
	md->data = NULL;
	md->vss_data = NULL;
	md->shm_sz = 0;

err_shm:
	if (md->shm_fd >= 0) {
		close(md->shm_fd);
		md->shm_unlink(md->name);
		md->shm_fd = -1;
	}
}

static void
ftl_md_destroy_shm(struct ftl_md *md)
{
	if (!md->data) {
		return;
	}

	assert(md->shm_sz > 0);
	if (md->mem_reg) {
		spdk_mem_unregister(md->data, md->shm_sz);
		md->mem_reg = false;
	}

	/* Unlock the pages in memory */
	munlock(md->data, md->shm_sz);

	/* Remove the virtual memory mapping for the object */
	munmap(md->data, md->shm_sz);

	/* Close SHM object fd */
	close(md->shm_fd);

	md->data = NULL;
	md->vss_data = NULL;

	/* Otherwise destroy/unlink the object */
	assert(md->name[0] != 0 && md->shm_unlink != NULL);
	md->shm_unlink(md->name);
}

struct ftl_md *ftl_md_create(struct spdk_ftl_dev *dev, uint64_t blocks,
			     uint64_t vss_blksz, const char *name, bool no_mem,
			     uint64_t vss_blksz, const char *name, int flags,
			     const struct ftl_layout_region *region)
{
	struct ftl_md *md;
@@ -75,20 +261,19 @@ struct ftl_md *ftl_md_create(struct spdk_ftl_dev *dev, uint64_t blocks,
	md->data_blocks = blocks;
	md->mirror_enabled = true;

	if (!no_mem) {
		size_t buf_size = md->data_blocks * (FTL_BLOCK_SIZE + vss_blksz);
		int ret;
	if (flags != FTL_MD_CREATE_NO_MEM) {
		if (flags & FTL_MD_CREATE_SHM) {
			ftl_md_setup_obj(md, flags, name);
			ftl_md_create_shm(md, vss_blksz, flags);
		} else {
			assert((flags & FTL_MD_CREATE_HEAP) == FTL_MD_CREATE_HEAP);
			ftl_md_create_heap(md, vss_blksz);
		}

		ret = posix_memalign((void **)&md->data, FTL_BLOCK_SIZE, buf_size);
		if (ret) {
		if (!md->data) {
			free(md);
			return NULL;
		}
		memset(md->data, 0, buf_size);

		if (vss_blksz) {
			md->vss_data = ((char *)md->data) + md->data_blocks * FTL_BLOCK_SIZE;
		}
	}

	if (region) {
@@ -114,6 +299,22 @@ err:
	return NULL;
}

int
ftl_md_unlink(struct spdk_ftl_dev *dev, const char *name, int flags)
{
	struct ftl_md md = { 0 };

	if (0 == (flags & FTL_MD_CREATE_SHM)) {
		/* Unlink can be called for shared memory only */
		return -EINVAL;
	}

	md.dev = dev;
	ftl_md_setup_obj(&md, flags, name);

	return md.shm_unlink(md.name);
}

void
ftl_md_destroy(struct ftl_md *md)
{
@@ -136,10 +337,10 @@ ftl_md_free_buf(struct ftl_md *md)
		return;
	}

	if (md->data) {
		free(md->data);
		md->data = NULL;
		md->vss_data = NULL;
	if (md->shm_fd < 0) {
		ftl_md_destroy_heap(md);
	} else {
		ftl_md_destroy_shm(md);
	}
}

+55 −2
Original line number Diff line number Diff line
@@ -20,6 +20,9 @@ enum ftl_md_ops {
	FTL_MD_OP_CLEAR,
};

typedef int (*shm_open_t)(const char *, int, mode_t);
typedef int (*shm_unlink_t)(const char *);

/* FTL metadata container which allows to store/restore/recover */
struct ftl_md {
	/* Context of owner (Caller of restore/persist/clear operation) */
@@ -64,6 +67,27 @@ struct ftl_md {
		struct spdk_bdev_io_wait_entry bdev_io_wait;
	} io;

	/* SHM object file descriptor or -1 if heap alloc */
	int shm_fd;

	/* Object name */
	char name[NAME_MAX + 1];

	/* mmap flags for the SHM object */
	int shm_mmap_flags;

	/* Total size of SHM object (data + md) */
	size_t shm_sz;

	/* open() for the SHM object */
	shm_open_t shm_open;

	/* unlink() for the SHM object */
	shm_unlink_t shm_unlink;

	/* Memory was registered to SPDK */
	bool mem_reg;

	/* Metadata primary object */
	struct ftl_md *mirror;

@@ -104,6 +128,23 @@ union ftl_md_vss {

SPDK_STATIC_ASSERT(sizeof(union ftl_md_vss) == FTL_MD_VSS_SZ, "Invalid md vss size");

/**
 *  FTL metadata creation flags
 */
enum ftl_md_create_flags {
	/** FTL metadata will be created without memory allocation */
	FTL_MD_CREATE_NO_MEM =		0x0,

	/** FTL metadata data buf will be allocated in SHM */
	FTL_MD_CREATE_SHM =		0x1,

	/** Always create a new SHM obj, i.e. issue shm_unlink() before shm_open(), only valid with FTL_MD_CREATE_SHM */
	FTL_MD_CREATE_SHM_NEW =		0x2,

	/** FTL metadata will be created on heap */
	FTL_MD_CREATE_HEAP =		0x4,
};

/**
 * @brief Creates FTL metadata
 *
@@ -111,7 +152,7 @@ SPDK_STATIC_ASSERT(sizeof(union ftl_md_vss) == FTL_MD_VSS_SZ, "Invalid md vss si
 * @param blocks Size of buffer in FTL block size unit
 * @param vss_blksz Size of VSS MD
 * @param name Name of the object being created
 * @param no_mem If true metadata will be created without memory allocation
 * @param flags Bit flags of ftl_md_create_flags type
 * @param region Region associated with FTL metadata
 *
 * @note if buffer is NULL, the buffer will be allocated internally by the object
@@ -119,9 +160,21 @@ SPDK_STATIC_ASSERT(sizeof(union ftl_md_vss) == FTL_MD_VSS_SZ, "Invalid md vss si
 * @return FTL metadata
 */
struct ftl_md *ftl_md_create(struct spdk_ftl_dev *dev, uint64_t blocks,
			     uint64_t vss_blksz, const char *name, bool no_mem,
			     uint64_t vss_blksz, const char *name, int flags,
			     const struct ftl_layout_region *region);

/**
 * @brief Unlinks metadata object from FS
 * @param dev The FTL device
 * @param name Name of the object being unlinked
 * @param flags Bit flag describing the MD object
 *
 * @note Unlink is possible only for objects created with FTL_MD_CREATE_SHM flag
 *
 * @return Operation result
 */
int ftl_md_unlink(struct spdk_ftl_dev *dev, const char *name, int flags);

/**
 * @brief Destroys metadata
 *
+2 −0
Original line number Diff line number Diff line
@@ -32,3 +32,5 @@ for ((i = 0; i < ${#tests[@]}; i++)); do
	trap - SIGINT SIGTERM EXIT
	timing_exit "${tests[$i]}"
done

remove_shm
+10 −0
Original line number Diff line number Diff line
@@ -46,3 +46,13 @@ function create_base_bdev() {
		$rootdir/scripts/rpc.py bdev_lvol_create ${base_bdev}p0 $size -t -u $lvs
	fi
}

# Remove not needed files from shared memory
function remove_shm() {
	echo Remove shared memory files
	rm -f rm -f /dev/shm/ftl*
	rm -f rm -f /dev/hugepages/ftl*
	rm -f rm -f /dev/shm/spdk*
	rm -f rm -f /dev/shm/iscsi
	rm -f rm -f /dev/hugepages/spdk*
}
Loading