Commit 679e2831 authored by Dariusz Stojaczyk's avatar Dariusz Stojaczyk Committed by Piotr Pelplinski
Browse files

vhost: added rpc commands to remove vhost controllers and devices



Added new rpc commands together with underlying vhost API and tests.

Change-Id: Ib9c6a530d0909193ea5115aaac4920c44f39613c
Signed-off-by: default avatarDariusz Stojaczyk <dariuszx.stojaczyk@intel.com>
parent 82d26c4f
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -63,10 +63,13 @@ struct spdk_vhost_scsi_ctrlr *spdk_vhost_scsi_ctrlr_next(struct spdk_vhost_scsi_

const char *spdk_vhost_scsi_ctrlr_get_name(struct spdk_vhost_scsi_ctrlr *ctrl);
uint64_t spdk_vhost_scsi_ctrlr_get_cpumask(struct spdk_vhost_scsi_ctrlr *ctrl);
struct spdk_vhost_scsi_ctrlr *spdk_vhost_scsi_ctrlr_find(const char *ctrlr_name);
int spdk_vhost_scsi_ctrlr_construct(const char *name, uint64_t cpumask);
int spdk_vhost_scsi_ctrlr_remove(struct spdk_vhost_scsi_ctrlr *vdev);
int spdk_vhost_parse_core_mask(const char *mask, uint64_t *cpumask);
struct spdk_scsi_dev *spdk_vhost_scsi_ctrlr_get_dev(struct spdk_vhost_scsi_ctrlr *ctrl,
		uint8_t num);
int spdk_vhost_scsi_ctrlr_add_dev(const char *name, unsigned scsi_dev_num, const char *lun_name);
int spdk_vhost_scsi_ctrlr_remove_dev(struct spdk_vhost_scsi_ctrlr *vdev, unsigned scsi_dev_num);

#endif /* SPDK_VHOST_H */
+74 −1
Original line number Diff line number Diff line
@@ -881,7 +881,7 @@ destroy_device(int vid)

static struct spdk_vhost_scsi_ctrlr *spdk_vhost_ctrlrs[MAX_SCSI_CTRLRS];

static struct spdk_vhost_scsi_ctrlr *
struct spdk_vhost_scsi_ctrlr *
spdk_vhost_scsi_ctrlr_find(const char *ctrlr_name)
{
	unsigned i;
@@ -1005,6 +1005,57 @@ spdk_vhost_scsi_ctrlr_construct(const char *name, uint64_t cpumask)
	return 0;
}

int
spdk_vhost_scsi_ctrlr_remove(struct spdk_vhost_scsi_ctrlr *vdev)
{
	unsigned ctrlr_num;
	char path[PATH_MAX];
	int i;

	if (vdev->lcore != -1) {
		SPDK_ERRLOG("Controller %s is in use and hotplug is not supported\n", vdev->name);
		return -ENODEV;
	}

	for (ctrlr_num = 0; ctrlr_num < MAX_SCSI_CTRLRS; ctrlr_num++) {
		if (spdk_vhost_ctrlrs[ctrlr_num] == vdev) {
			break;
		}
	}

	if (ctrlr_num == MAX_SCSI_CTRLRS) {
		SPDK_ERRLOG("Trying to remove invalid controller: %s.\n", vdev->name);
		return -ENOSPC;
	}

	if (snprintf(path, sizeof(path), "%s%s", dev_dirname, vdev->name) >= (int)sizeof(path)) {
		SPDK_ERRLOG("Resulting socket path for controller %s is too long: %s%s\n", vdev->name, dev_dirname,
			    vdev->name);
		return -EINVAL;
	}

	for (i = 0; i < SPDK_VHOST_SCSI_CTRLR_MAX_DEVS; ++i) {
		if (vdev->scsi_dev[i]) {
			SPDK_ERRLOG("Trying to remove non-empty controller: %s.\n", vdev->name);
			return -EBUSY;
		}
	}

	if (rte_vhost_driver_unregister(path) != 0) {
		SPDK_ERRLOG("Could not unregister controller %s with vhost library\n"
			    "Check if domain socket %s still exists\n", vdev->name, path);
		return -EIO;
	}

	SPDK_NOTICELOG("Controller %s: removed\n", vdev->name);

	free(vdev->name);
	spdk_free(spdk_vhost_ctrlrs[ctrlr_num]);
	spdk_vhost_ctrlrs[ctrlr_num] = NULL;

	return 0;
}

int
spdk_vhost_parse_core_mask(const char *mask, uint64_t *cpumask)
{
@@ -1099,6 +1150,28 @@ spdk_vhost_scsi_ctrlr_add_dev(const char *ctrlr_name, unsigned scsi_dev_num, con
	return 0;
}


int
spdk_vhost_scsi_ctrlr_remove_dev(struct spdk_vhost_scsi_ctrlr *vdev, unsigned scsi_dev_num)
{
	if (vdev->lcore != -1) {
		SPDK_ERRLOG("Controller %s is in use and hotremove is not supported\n", vdev->name);
		return -EBUSY;
	}

	if (vdev->scsi_dev[scsi_dev_num] == NULL) {
		SPDK_ERRLOG("Controller %s dev %u is not occupied\n", vdev->name, scsi_dev_num);
		return -ENODEV;
	}

	spdk_scsi_dev_destruct(vdev->scsi_dev[scsi_dev_num]);
	vdev->scsi_dev[scsi_dev_num] = NULL;

	SPDK_NOTICELOG("Controller %s: removed device 'Dev %u'\n",
		       vdev->name, scsi_dev_num);
	return 0;
}

struct spdk_vhost_scsi_ctrlr *
spdk_vhost_scsi_ctrlr_next(struct spdk_vhost_scsi_ctrlr *prev)
{
+123 −3
Original line number Diff line number Diff line
@@ -186,6 +186,64 @@ invalid:
}
SPDK_RPC_REGISTER("construct_vhost_scsi_controller", spdk_rpc_construct_vhost_scsi_controller)

struct rpc_remove_vhost_scsi_ctrlr {
	char *ctrlr;
};

static void
free_rpc_remove_vhost_scsi_ctrlr(struct rpc_remove_vhost_scsi_ctrlr *req)
{
	free(req->ctrlr);
}

static const struct spdk_json_object_decoder rpc_remove_vhost_ctrlr[] = {
	{"ctrlr", offsetof(struct rpc_remove_vhost_scsi_ctrlr, ctrlr), spdk_json_decode_string },
};

static void
spdk_rpc_remove_vhost_scsi_controller(struct spdk_jsonrpc_server_conn *conn,
				      const struct spdk_json_val *params,
				      const struct spdk_json_val *id)
{
	struct rpc_remove_vhost_scsi_ctrlr req = {NULL};
	struct spdk_json_write_ctx *w;
	struct spdk_vhost_scsi_ctrlr *vdev;
	int rc;

	if (spdk_json_decode_object(params, rpc_remove_vhost_ctrlr,
				    SPDK_COUNTOF(rpc_remove_vhost_ctrlr),
				    &req)) {
		SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_json_decode_object failed\n");
		rc = -EINVAL;
		goto invalid;
	}

	if (!(vdev = spdk_vhost_scsi_ctrlr_find(req.ctrlr))) {
		rc = -ENODEV;
		goto invalid;
	}

	rc = spdk_vhost_scsi_ctrlr_remove(vdev);
	if (rc < 0) {
		goto invalid;
	}

	free_rpc_remove_vhost_scsi_ctrlr(&req);

	if (id != NULL) {
		w = spdk_jsonrpc_begin_result(conn, id);
		spdk_json_write_bool(w, true);
		spdk_jsonrpc_end_result(conn, w);
	}

	return;
invalid:
	free_rpc_remove_vhost_scsi_ctrlr(&req);
	spdk_jsonrpc_send_error_response(conn, id, SPDK_JSONRPC_ERROR_INVALID_PARAMS, strerror(-rc));
}
SPDK_RPC_REGISTER("remove_vhost_scsi_controller", spdk_rpc_remove_vhost_scsi_controller)


struct rpc_add_vhost_scsi_ctrlr_lun {
	char *ctrlr;
	uint32_t scsi_dev_num;
@@ -229,12 +287,74 @@ spdk_rpc_add_vhost_scsi_lun(struct spdk_jsonrpc_server_conn *conn,

	free_rpc_add_vhost_scsi_ctrlr_lun(&req);

	if (id != NULL) {
		w = spdk_jsonrpc_begin_result(conn, id);
		spdk_json_write_bool(w, true);
		spdk_jsonrpc_end_result(conn, w);
	}

	return;
invalid:
	free_rpc_add_vhost_scsi_ctrlr_lun(&req);
	spdk_jsonrpc_send_error_response(conn, id, SPDK_JSONRPC_ERROR_INVALID_PARAMS, strerror(-rc));
}
SPDK_RPC_REGISTER("add_vhost_scsi_lun", spdk_rpc_add_vhost_scsi_lun)

struct rpc_remove_vhost_scsi_ctrlr_dev {
	char *ctrlr;
	uint32_t scsi_dev_num;
};

static void
free_rpc_remove_vhost_scsi_ctrlr_dev(struct rpc_remove_vhost_scsi_ctrlr_dev *req)
{
	free(req->ctrlr);
}

static const struct spdk_json_object_decoder rpc_vhost_remove_dev[] = {
	{"ctrlr", offsetof(struct rpc_remove_vhost_scsi_ctrlr_dev, ctrlr), spdk_json_decode_string },
	{"scsi_dev_num", offsetof(struct rpc_remove_vhost_scsi_ctrlr_dev, scsi_dev_num), spdk_json_decode_uint32},
};

static void
spdk_rpc_remove_vhost_scsi_dev(struct spdk_jsonrpc_server_conn *conn,
			       const struct spdk_json_val *params,
			       const struct spdk_json_val *id)
{
	struct rpc_remove_vhost_scsi_ctrlr_dev req = {0};
	struct spdk_json_write_ctx *w;
	struct spdk_vhost_scsi_ctrlr *vdev;
	int rc;

	if (spdk_json_decode_object(params, rpc_vhost_remove_dev,
				    SPDK_COUNTOF(rpc_vhost_remove_dev),
				    &req)) {
		SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_json_decode_object failed\n");
		rc = -EINVAL;
		goto invalid;
	}

	if (!(vdev = spdk_vhost_scsi_ctrlr_find(req.ctrlr))) {
		rc = -ENODEV;
		goto invalid;
	}

	rc = spdk_vhost_scsi_ctrlr_remove_dev(vdev, req.scsi_dev_num);
	if (rc < 0) {
		goto invalid;
	}

	free_rpc_remove_vhost_scsi_ctrlr_dev(&req);

	if (id != NULL) {
		w = spdk_jsonrpc_begin_result(conn, id);
		spdk_json_write_bool(w, true);
		spdk_jsonrpc_end_result(conn, w);
	}

	return;
invalid:
	free_rpc_remove_vhost_scsi_ctrlr_dev(&req);
	spdk_jsonrpc_send_error_response(conn, id, SPDK_JSONRPC_ERROR_INVALID_PARAMS, strerror(-rc));
}
SPDK_RPC_REGISTER("remove_vhost_scsi_dev", spdk_rpc_remove_vhost_scsi_dev)
+20 −0
Original line number Diff line number Diff line
@@ -473,6 +473,14 @@ p.add_argument('ctrlr', help='controller name')
p.add_argument('--cpumask', help='cpu mask for this controller')
p.set_defaults(func=construct_vhost_scsi_controller)

def remove_vhost_scsi_controller(args):
    params = {'ctrlr': args.ctrlr}
    jsonrpc_call('remove_vhost_scsi_controller', params)

p = subparsers.add_parser('remove_vhost_scsi_controller', help='Remove vhost controller')
p.add_argument('ctrlr', help='controller name')
p.set_defaults(func=remove_vhost_scsi_controller)

def add_vhost_scsi_lun(args):
    params = {
        'ctrlr': args.ctrlr,
@@ -487,5 +495,17 @@ p.add_argument('scsi_dev_num', help='scsi_dev_num', type=int)
p.add_argument('lun_name', help='lun name')
p.set_defaults(func=add_vhost_scsi_lun)

def remove_vhost_scsi_dev(args):
    params = {
        'ctrlr': args.ctrlr,
        'scsi_dev_num': args.scsi_dev_num,
    }
    jsonrpc_call('remove_vhost_scsi_dev', params)

p = subparsers.add_parser('remove_vhost_scsi_dev', help='Remove device from vhost controller')
p.add_argument('ctrlr', help='controller name to remove device from')
p.add_argument('scsi_dev_num', help='scsi_dev_num', type=int)
p.set_defaults(func=remove_vhost_scsi_dev)

args = parser.parse_args()
args.func(args)
+50 −1
Original line number Diff line number Diff line
@@ -152,12 +152,39 @@ for vm_conf in ${vms[@]}; do
	[[ x"${conf[2]}" != x"" ]] && setup_cmd+=" --disk=${conf[2]}"

	if [[ $test_type == "spdk_vhost" ]]; then
		echo "INFO: Trying to remove inexistent controller"
		if $rpc_py remove_vhost_scsi_controller unk0 > /dev/null; then
			echo "ERROR: Removing inexistent controller succeeded, but it shouldn't"
			false
		fi

		echo "INFO: Adding device via RPC ..."
		echo ""

		while IFS=':' read -ra disks; do
			for disk in "${disks[@]}"; do
				echo "INFO: Creating controller naa.$disk.${conf[0]}"
				$rpc_py construct_vhost_scsi_controller naa.$disk.${conf[0]}

				echo "INFO: Adding initial device (0) to naa.$disk.${conf[0]}"
				$rpc_py add_vhost_scsi_lun naa.$disk.${conf[0]} 0 $disk

				echo "INFO: Trying to remove inexistent device on existing controller"
				if $rpc_py remove_vhost_scsi_dev naa.$disk.${conf[0]} 1 > /dev/null; then
					echo "ERROR: Removing inexistent device (1) from controller naa.$disk.${conf[0]} succeeded, but it shouldn't"
					false
				fi

				echo "INFO: Trying to remove existing device from a controller"
				$rpc_py remove_vhost_scsi_dev naa.$disk.${conf[0]} 0

				echo "INFO: Trying to remove a just-deleted device from a controller again"
				if $rpc_py remove_vhost_scsi_dev naa.$disk.${conf[0]} 0 > /dev/null; then
					echo "ERROR: Removing device 0 from controller naa.$disk.${conf[0]} succeeded, but it shouldn't"
					false
				fi

				echo "INFO: Re-adding device 0 to naa.$disk.${conf[0]}"
				$rpc_py add_vhost_scsi_lun naa.$disk.${conf[0]} 0 $disk
			done
		done <<< "${conf[2]}"
@@ -236,8 +263,30 @@ done

if ! $no_shutdown; then
	echo "==============="
	echo "INFO: APP EXITING"
	echo "INFO: killing all VMs"
	vm_kill_all
	echo "INFO: waiting 2 seconds to let all VMs die"
	sleep 2
	if [[ $test_type == "spdk_vhost" ]]; then
		echo "INFO: Removing vhost devices & controllers via RPC ..."
		for vm_conf in ${vms[@]}; do
			IFS=',' read -ra conf <<< "$vm_conf"

			while IFS=':' read -ra disks; do
				for disk in "${disks[@]}"; do
					echo "INFO: Removing all vhost devices from controller naa.$disk.${conf[0]}"
					$rpc_py remove_vhost_scsi_dev naa.$disk.${conf[0]} 0
					$rpc_py remove_vhost_scsi_controller naa.$disk.${conf[0]}
				done
			done <<< "${conf[2]}"
		done
	fi
	echo "INFO: Testing done -> shutting down"
	at_app_exit
	echo "INFO: killing vhost app"
	spdk_vhost_kill

	echo "INFO: EXIT DONE"
	echo "==============="
else
	echo "==============="