Commit 0af934b3 authored by Krzysztof Karas's avatar Krzysztof Karas Committed by Tomasz Zawadzki
Browse files

event: add CPU lock files



When running SPDK application on a given set of
CPU cores, create lock files for each of them.
This wil prevent user misconfiguration and
assigning a core to more than one SPDK instance.

The introduced mechanism is based on device locks
implemented in spdk_pci_device_claim() function.

Add a command line option to disable lock files.
This feature will be useful in cases where differing
CPU cores is impossible (eg. setup with only one core
available).

The patch also fixes all existing cases of overlapping
core masks.

Change-Id: Ie9aacb7523a3597b9aa20f2c3fa9efe4db92c44c
Signed-off-by: default avatarKrzysztof Karas <krzysztof.karas@intel.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/14919


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Community-CI: Mellanox Build Bot
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Reviewed-by: default avatarTomasz Zawadzki <tomasz.zawadzki@intel.com>
Reviewed-by: default avatarShuhei Matsumoto <smatsumoto@nvidia.com>
parent 311d014d
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -27,6 +27,13 @@ New `spdk_bdev_copy_blocks` and `spdk_bdev_get_max_copy` APIs to support copy co

A new API `spdk_bdev_io_get_submit_tsc` was added to get the submit_tsc of the bdev I/O.

### event

Added core lock file mechanism to prevent the same CPU cores from being used by multiple
SPDK application instances.

Added a command line switch to disable CPU locks on SPDK startup.

## v22.09

### accel
+108 −0
Original line number Diff line number Diff line
@@ -31,6 +31,8 @@
#define SPDK_APP_DPDK_DEFAULT_BASE_VIRTADDR	0x200000000000
#define SPDK_APP_DEFAULT_CORE_LIMIT		0x140000000 /* 5 GiB */

#define MAX_CPU_CORES				128

struct spdk_app {
	const char			*json_config_file;
	bool				json_config_ignore_errors;
@@ -49,6 +51,9 @@ static bool g_delay_subsystem_init = false;
static bool g_shutdown_sig_received = false;
static char *g_executable_name;
static struct spdk_app_opts g_default_opts;
static bool g_disable_cpumask_locks = false;

static int g_core_locks[MAX_CPU_CORES];

int
spdk_app_get_shm_id(void)
@@ -116,6 +121,8 @@ static const struct option g_cmdline_options[] = {
	{"base-virtaddr",		required_argument,	NULL, BASE_VIRTADDR_OPT_IDX},
#define ENV_CONTEXT_OPT_IDX	266
	{"env-context",			required_argument,	NULL, ENV_CONTEXT_OPT_IDX},
#define DISABLE_CPUMASK_LOCKS_OPT_IDX	267
	{"disable-cpumask-locks",	no_argument,		NULL, DISABLE_CPUMASK_LOCKS_OPT_IDX},
};

static void
@@ -508,6 +515,86 @@ app_copy_opts(struct spdk_app_opts *opts, struct spdk_app_opts *opts_user, size_
#undef SET_FIELD
}

static void
unclaim_cpu_cores(void)
{
	char core_name[40];
	uint32_t i;

	for (i = 0; i < MAX_CPU_CORES; i++) {
		if (g_core_locks[i] != -1) {
			snprintf(core_name, sizeof(core_name), "/var/tmp/spdk_cpu_lock_%03d", i);
			close(g_core_locks[i]);
			unlink(core_name);
		}
	}
}

static int
claim_cpu_cores(uint32_t *failed_core)
{
	char core_name[40];
	int core_fd, pid;
	int *core_map;
	uint32_t core;

	struct flock core_lock = {
		.l_type = F_WRLCK,
		.l_whence = SEEK_SET,
		.l_start = 0,
		.l_len = 0,
	};

	SPDK_ENV_FOREACH_CORE(core) {
		snprintf(core_name, sizeof(core_name), "/var/tmp/spdk_cpu_lock_%03d", core);
		core_fd = open(core_name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
		if (core_fd == -1) {
			SPDK_ERRLOG("Could not open %s (%s).\n", core_name, spdk_strerror(errno));
			/* Return number of core we failed to claim. */
			goto error;
		}

		if (ftruncate(core_fd, sizeof(int)) != 0) {
			SPDK_ERRLOG("Could not truncate %s (%s).\n", core_name, spdk_strerror(errno));
			close(core_fd);
			goto error;
		}

		core_map = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, core_fd, 0);
		if (core_map == MAP_FAILED) {
			SPDK_ERRLOG("Could not mmap core %s (%s).\n", core_name, spdk_strerror(errno));
			close(core_fd);
			goto error;
		}

		if (fcntl(core_fd, F_SETLK, &core_lock) != 0) {
			pid = *core_map;
			SPDK_ERRLOG("Cannot create lock on core %" PRIu32 ", probably process %d has claimed it.\n",
				    core, pid);
			munmap(core_map, sizeof(int));
			close(core_fd);
			goto error;
		}

		/* We write the PID to the core lock file so that other processes trying
		* to claim the same core will know what process is holding the lock. */
		*core_map = (int)getpid();
		munmap(core_map, sizeof(int));
		g_core_locks[core] = core_fd;
		/* Keep core_fd open to maintain the lock. */
	}

	return 0;

error:
	if (failed_core != NULL) {
		/* Set number of core we failed to claim. */
		*failed_core = core;
	}
	unclaim_cpu_cores();
	return -1;
}

int
spdk_app_start(struct spdk_app_opts *opts_user, spdk_msg_fn start_fn,
	       void *arg1)
@@ -518,6 +605,7 @@ spdk_app_start(struct spdk_app_opts *opts_user, spdk_msg_fn start_fn,
	static bool		g_env_was_setup = false;
	struct spdk_app_opts opts_local = {};
	struct spdk_app_opts *opts = &opts_local;
	uint32_t i;

	if (!opts_user) {
		SPDK_ERRLOG("opts_user should not be NULL\n");
@@ -583,6 +671,21 @@ spdk_app_start(struct spdk_app_opts *opts_user, spdk_msg_fn start_fn,
	}

	spdk_log_open(opts->log);

	/* Initialize each lock to -1 to indicate "empty" status */
	for (i = 0; i < MAX_CPU_CORES; i++) {
		g_core_locks[i] = -1;
	}

	if (!g_disable_cpumask_locks) {
		if (claim_cpu_cores(NULL)) {
			SPDK_ERRLOG("Unable to acquire lock on assigned core mask - exiting.\n");
			return 1;
		}
	} else {
		SPDK_NOTICELOG("CPU core locks deactivated.\n");
	}

	SPDK_NOTICELOG("Total cores available: %d\n", spdk_env_get_core_count());

	if ((rc = spdk_reactors_init(opts->msg_mempool_size)) != 0) {
@@ -639,6 +742,7 @@ spdk_app_fini(void)
	spdk_reactors_fini();
	spdk_env_fini();
	spdk_log_close();
	unclaim_cpu_cores();
}

static void
@@ -718,6 +822,7 @@ usage(void (*app_usage)(void))
	{
		printf("%dMB)\n", g_default_opts.mem_size >= 0 ? g_default_opts.mem_size : 0);
	}
	printf("     --disable-cpumask-locks    Disable CPU core lock files.\n");
	printf("     --silence-noticelog   disable notice level logging to stderr\n");
	printf(" -u, --no-pci              disable PCI access\n");
	printf("     --wait-for-rpc        wait for RPCs to initialize subsystems\n");
@@ -843,6 +948,9 @@ spdk_app_parse_args(int argc, char **argv, struct spdk_app_opts *opts,
		case CPUMASK_OPT_IDX:
			opts->reactor_mask = optarg;
			break;
		case DISABLE_CPUMASK_LOCKS_OPT_IDX:
			g_disable_cpumask_locks = true;
			break;
		case MEM_CHANNELS_OPT_IDX:
			opts->mem_channel = spdk_strtol(optarg, 0);
			if (opts->mem_channel < 0) {
+1 −0
Original line number Diff line number Diff line
@@ -422,6 +422,7 @@ function cleanup_linux() {
		files_to_clean+=("$dir/"*)
	done
	file_locks+=(/var/tmp/spdk_pci_lock*)
	file_locks+=(/var/tmp/spdk_cpu_lock*)

	files_to_clean+=(/dev/shm/@(@($match_spdk)_trace|spdk_iscsi_conns)*)
	files_to_clean+=("${file_locks[@]}")
+9 −9
Original line number Diff line number Diff line
@@ -119,39 +119,39 @@ timing_enter sock_ssl_server
echo "Testing SSL server path"

# start echo server using hello_sock echo server
$HELLO_SOCK_APP -H $TARGET_IP -P $ISCSI_PORT -S $PSK &
$HELLO_SOCK_APP -H $TARGET_IP -P $ISCSI_PORT -S $PSK -m 0x1 &
server_pid=$!
trap 'killprocess $server_pid; iscsitestfini; exit 1' SIGINT SIGTERM EXIT
waitforlisten $server_pid

# send message using hello_sock client
message="**MESSAGE:This is a test message from the hello_sock client with ssl**"
response=$(echo $message | $HELLO_SOCK_APP -H $TARGET_IP -P $ISCSI_PORT $PSK)
response=$(echo $message | $HELLO_SOCK_APP -H $TARGET_IP -P $ISCSI_PORT $PSK -m 0x2)
if ! echo "$response" | grep -q "$message"; then
	exit 1
fi

# send message using hello_sock client using TLS 1.3
message="**MESSAGE:This is a test message from the hello_sock client with ssl using TLS 1.3**"
response=$(echo $message | $HELLO_SOCK_APP -H $TARGET_IP -P $ISCSI_PORT $PSK -T 13)
response=$(echo $message | $HELLO_SOCK_APP -H $TARGET_IP -P $ISCSI_PORT $PSK -T 13 -m 0x2)
if ! echo "$response" | grep -q "$message"; then
	exit 1
fi

# send message using hello_sock client using TLS 1.2
message="**MESSAGE:This is a test message from the hello_sock client with ssl using TLS 1.2**"
response=$(echo $message | $HELLO_SOCK_APP -H $TARGET_IP -P $ISCSI_PORT $PSK -T 12)
response=$(echo $message | $HELLO_SOCK_APP -H $TARGET_IP -P $ISCSI_PORT $PSK -T 12 -m 0x2)
if ! echo "$response" | grep -q "$message"; then
	exit 1
fi

# send message using hello_sock client using incorrect TLS 7
message="**MESSAGE:This is a test message from the hello_sock client with ssl using incorrect TLS 7**"
echo $message | $HELLO_SOCK_APP -H $TARGET_IP -P $ISCSI_PORT $PSK -T 7 && exit 1
echo $message | $HELLO_SOCK_APP -H $TARGET_IP -P $ISCSI_PORT $PSK -T 7 -m 0x2 && exit 1

# send message using hello_sock client with KTLS disabled
message="**MESSAGE:This is a test message from the hello_sock client with KTLS disabled**"
response=$(echo $message | $HELLO_SOCK_APP -H $TARGET_IP -P $ISCSI_PORT $PSK -k)
response=$(echo $message | $HELLO_SOCK_APP -H $TARGET_IP -P $ISCSI_PORT $PSK -k -m 0x2)
if ! echo "$response" | grep -q "$message"; then
	exit 1
fi
@@ -187,11 +187,11 @@ fi

# send message using hello_sock client with unmatching PSK KEY, expect a failure
message="**MESSAGE:This is a test message from the hello_sock client with unmatching psk_key**"
echo $message | $HELLO_SOCK_APP -H $TARGET_IP -P $ISCSI_PORT $PSK -E 4321DEADBEEF1234 && exit 1
echo $message | $HELLO_SOCK_APP -H $TARGET_IP -P $ISCSI_PORT $PSK -E 4321DEADBEEF1234 -m 0x2 && exit 1

# send message using hello_sock client with unmatching PSK IDENTITY, expect a failure
message="**MESSAGE:This is a test message from the hello_sock client with unmatching psk_key**"
echo $message | $HELLO_SOCK_APP -H $TARGET_IP -P $ISCSI_PORT $PSK -I WRONG_PSK_ID && exit 1
echo $message | $HELLO_SOCK_APP -H $TARGET_IP -P $ISCSI_PORT $PSK -I WRONG_PSK_ID -m 0x2 && exit 1

trap '-' SIGINT SIGTERM EXIT
# NOTE: socat returns code 143 on SIGINT
@@ -206,7 +206,7 @@ timing_exit sock_ssl_server
timing_enter sock_server

# start echo server using hello_sock echo server
$HELLO_SOCK_APP -H $TARGET_IP -P $ISCSI_PORT -S -N "posix" &
$HELLO_SOCK_APP -H $TARGET_IP -P $ISCSI_PORT -S -N "posix" -m 0x1 &
server_pid=$!
trap 'killprocess $server_pid; iscsitestfini; exit 1' SIGINT SIGTERM EXIT
waitforlisten $server_pid
+1 −1
Original line number Diff line number Diff line
@@ -9,7 +9,7 @@ MALLOC_BDEV_SIZE=64
MALLOC_BLOCK_SIZE=512

function tgt_init() {
	nvmfappstart -m 0xF
	nvmfappstart -m 0xE

	$rpc_py nvmf_create_transport $NVMF_TRANSPORT_OPTS -u 8192
	$rpc_py bdev_malloc_create $MALLOC_BDEV_SIZE $MALLOC_BLOCK_SIZE -b Malloc0
Loading