Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/ctld/kernel.c
Show First 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | |||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/capsicum.h> | #include <sys/capsicum.h> | ||||
#include <sys/callout.h> | #include <sys/callout.h> | ||||
#include <sys/ioctl.h> | #include <sys/ioctl.h> | ||||
#include <sys/linker.h> | #include <sys/linker.h> | ||||
#include <sys/module.h> | #include <sys/module.h> | ||||
#include <sys/queue.h> | #include <sys/queue.h> | ||||
#include <sys/sbuf.h> | #include <sys/sbuf.h> | ||||
#include <sys/nv.h> | |||||
#include <sys/stat.h> | #include <sys/stat.h> | ||||
#include <assert.h> | #include <assert.h> | ||||
#include <bsdxml.h> | #include <bsdxml.h> | ||||
#include <ctype.h> | #include <ctype.h> | ||||
#include <errno.h> | #include <errno.h> | ||||
#include <fcntl.h> | #include <fcntl.h> | ||||
#include <stdint.h> | #include <stdint.h> | ||||
#include <stdio.h> | #include <stdio.h> | ||||
Show All 10 Lines | |||||
#include <cam/ctl/ctl_scsi_all.h> | #include <cam/ctl/ctl_scsi_all.h> | ||||
#include "ctld.h" | #include "ctld.h" | ||||
#ifdef ICL_KERNEL_PROXY | #ifdef ICL_KERNEL_PROXY | ||||
#include <netdb.h> | #include <netdb.h> | ||||
#endif | #endif | ||||
#define NVLIST_BUFSIZE 1024 | |||||
extern bool proxy_mode; | extern bool proxy_mode; | ||||
static int ctl_fd = 0; | static int ctl_fd = 0; | ||||
void | void | ||||
kernel_init(void) | kernel_init(void) | ||||
{ | { | ||||
int retval, saved_errno; | int retval, saved_errno; | ||||
▲ Show 20 Lines • Show All 563 Lines • ▼ Show 20 Lines | STAILQ_FOREACH(nv, &lun->attr_list, links) { | ||||
nv->name, (uintmax_t) lun->lun_id, | nv->name, (uintmax_t) lun->lun_id, | ||||
cl->l_name); | cl->l_name); | ||||
} | } | ||||
} | } | ||||
return (conf); | return (conf); | ||||
} | } | ||||
static void | |||||
str_arg(struct ctl_be_arg *arg, const char *name, const char *value) | |||||
{ | |||||
arg->namelen = strlen(name) + 1; | |||||
arg->name = __DECONST(char *, name); | |||||
arg->vallen = strlen(value) + 1; | |||||
arg->value = __DECONST(char *, value); | |||||
arg->flags = CTL_BEARG_ASCII | CTL_BEARG_RD; | |||||
} | |||||
int | int | ||||
kernel_lun_add(struct lun *lun) | kernel_lun_add(struct lun *lun) | ||||
{ | { | ||||
struct option *o; | struct option *o; | ||||
struct ctl_lun_req req; | struct ctl_lun_req req; | ||||
int error, i, num_options; | int error; | ||||
bzero(&req, sizeof(req)); | bzero(&req, sizeof(req)); | ||||
strlcpy(req.backend, lun->l_backend, sizeof(req.backend)); | strlcpy(req.backend, lun->l_backend, sizeof(req.backend)); | ||||
req.reqtype = CTL_LUNREQ_CREATE; | req.reqtype = CTL_LUNREQ_CREATE; | ||||
req.reqdata.create.blocksize_bytes = lun->l_blocksize; | req.reqdata.create.blocksize_bytes = lun->l_blocksize; | ||||
Show All 37 Lines | if (o != NULL) { | ||||
o = option_new(&lun->l_options, "ctld_name", lun->l_name); | o = option_new(&lun->l_options, "ctld_name", lun->l_name); | ||||
assert(o != NULL); | assert(o != NULL); | ||||
} | } | ||||
o = option_find(&lun->l_options, "scsiname"); | o = option_find(&lun->l_options, "scsiname"); | ||||
if (o == NULL && lun->l_scsiname != NULL) { | if (o == NULL && lun->l_scsiname != NULL) { | ||||
o = option_new(&lun->l_options, "scsiname", lun->l_scsiname); | o = option_new(&lun->l_options, "scsiname", lun->l_scsiname); | ||||
assert(o != NULL); | assert(o != NULL); | ||||
} | } | ||||
mav: Again double conversion. Not a huge deal, but would probably be nice to use nvlists directly. | |||||
num_options = 0; | if (!TAILQ_EMPTY(&lun->l_options)) { | ||||
req.args_nvl = nvlist_create(0); | |||||
if (req.args_nvl == NULL) { | |||||
log_warn("error allocating nvlist"); | |||||
return (1); | |||||
} | |||||
TAILQ_FOREACH(o, &lun->l_options, o_next) | TAILQ_FOREACH(o, &lun->l_options, o_next) | ||||
num_options++; | nvlist_add_string(req.args_nvl, o->o_name, o->o_value); | ||||
req.num_be_args = num_options; | req.args = nvlist_pack(req.args_nvl, &req.args_len); | ||||
if (num_options > 0) { | if (req.args == NULL) { | ||||
req.be_args = malloc(num_options * sizeof(*req.be_args)); | log_warn("error packing nvlist"); | ||||
if (req.be_args == NULL) { | |||||
log_warn("error allocating %zd bytes", | |||||
num_options * sizeof(*req.be_args)); | |||||
return (1); | return (1); | ||||
} | } | ||||
i = 0; | |||||
TAILQ_FOREACH(o, &lun->l_options, o_next) { | |||||
str_arg(&req.be_args[i], o->o_name, o->o_value); | |||||
i++; | |||||
} | } | ||||
assert(i == num_options); | |||||
} | |||||
error = ioctl(ctl_fd, CTL_LUN_REQ, &req); | error = ioctl(ctl_fd, CTL_LUN_REQ, &req); | ||||
free(req.be_args); | nvlist_destroy(req.args_nvl); | ||||
if (error != 0) { | if (error != 0) { | ||||
log_warn("error issuing CTL_LUN_REQ ioctl"); | log_warn("error issuing CTL_LUN_REQ ioctl"); | ||||
return (1); | return (1); | ||||
} | } | ||||
switch (req.status) { | switch (req.status) { | ||||
case CTL_LUN_ERROR: | case CTL_LUN_ERROR: | ||||
log_warnx("LUN creation error: %s", req.error_str); | log_warnx("LUN creation error: %s", req.error_str); | ||||
Show All 13 Lines | kernel_lun_add(struct lun *lun) | ||||
return (0); | return (0); | ||||
} | } | ||||
int | int | ||||
kernel_lun_modify(struct lun *lun) | kernel_lun_modify(struct lun *lun) | ||||
{ | { | ||||
struct option *o; | struct option *o; | ||||
struct ctl_lun_req req; | struct ctl_lun_req req; | ||||
int error, i, num_options; | int error; | ||||
bzero(&req, sizeof(req)); | bzero(&req, sizeof(req)); | ||||
strlcpy(req.backend, lun->l_backend, sizeof(req.backend)); | strlcpy(req.backend, lun->l_backend, sizeof(req.backend)); | ||||
req.reqtype = CTL_LUNREQ_MODIFY; | req.reqtype = CTL_LUNREQ_MODIFY; | ||||
req.reqdata.modify.lun_id = lun->l_ctl_lun; | req.reqdata.modify.lun_id = lun->l_ctl_lun; | ||||
req.reqdata.modify.lun_size_bytes = lun->l_size; | req.reqdata.modify.lun_size_bytes = lun->l_size; | ||||
num_options = 0; | if (!TAILQ_EMPTY(&lun->l_options)) { | ||||
req.args_nvl = nvlist_create(0); | |||||
if (req.args_nvl == NULL) { | |||||
log_warn("error allocating nvlist"); | |||||
return (1); | |||||
} | |||||
TAILQ_FOREACH(o, &lun->l_options, o_next) | TAILQ_FOREACH(o, &lun->l_options, o_next) | ||||
num_options++; | nvlist_add_string(req.args_nvl, o->o_name, o->o_value); | ||||
req.num_be_args = num_options; | req.args = nvlist_pack(req.args_nvl, &req.args_len); | ||||
if (num_options > 0) { | if (req.args == NULL) { | ||||
req.be_args = malloc(num_options * sizeof(*req.be_args)); | log_warn("error packing nvlist"); | ||||
if (req.be_args == NULL) { | |||||
log_warn("error allocating %zd bytes", | |||||
num_options * sizeof(*req.be_args)); | |||||
return (1); | return (1); | ||||
} | } | ||||
i = 0; | |||||
TAILQ_FOREACH(o, &lun->l_options, o_next) { | |||||
str_arg(&req.be_args[i], o->o_name, o->o_value); | |||||
i++; | |||||
} | } | ||||
assert(i == num_options); | |||||
} | |||||
error = ioctl(ctl_fd, CTL_LUN_REQ, &req); | error = ioctl(ctl_fd, CTL_LUN_REQ, &req); | ||||
free(req.be_args); | nvlist_destroy(req.args_nvl); | ||||
if (error != 0) { | if (error != 0) { | ||||
log_warn("error issuing CTL_LUN_REQ ioctl"); | log_warn("error issuing CTL_LUN_REQ ioctl"); | ||||
return (1); | return (1); | ||||
} | } | ||||
switch (req.status) { | switch (req.status) { | ||||
case CTL_LUN_ERROR: | case CTL_LUN_ERROR: | ||||
log_warnx("LUN modification error: %s", req.error_str); | log_warnx("LUN modification error: %s", req.error_str); | ||||
▲ Show 20 Lines • Show All 163 Lines • ▼ Show 20 Lines | |||||
kernel_port_add(struct port *port) | kernel_port_add(struct port *port) | ||||
{ | { | ||||
struct option *o; | struct option *o; | ||||
struct ctl_port_entry entry; | struct ctl_port_entry entry; | ||||
struct ctl_req req; | struct ctl_req req; | ||||
struct ctl_lun_map lm; | struct ctl_lun_map lm; | ||||
struct target *targ = port->p_target; | struct target *targ = port->p_target; | ||||
struct portal_group *pg = port->p_portal_group; | struct portal_group *pg = port->p_portal_group; | ||||
char tagstr[16]; | char result_buf[NVLIST_BUFSIZE]; | ||||
int error, i, n; | int error, i; | ||||
/* Create iSCSI port. */ | /* Create iSCSI port. */ | ||||
if (port->p_portal_group) { | if (port->p_portal_group || port->p_ioctl_port) { | ||||
bzero(&req, sizeof(req)); | bzero(&req, sizeof(req)); | ||||
strlcpy(req.driver, "iscsi", sizeof(req.driver)); | |||||
req.reqtype = CTL_REQ_CREATE; | req.reqtype = CTL_REQ_CREATE; | ||||
req.num_args = 5; | |||||
if (port->p_portal_group) { | |||||
strlcpy(req.driver, "iscsi", sizeof(req.driver)); | |||||
req.args_nvl = nvlist_create(0); | |||||
nvlist_add_string(req.args_nvl, "cfiscsi_target", | |||||
targ->t_name); | |||||
nvlist_add_string(req.args_nvl, | |||||
"ctld_portal_group_name", pg->pg_name); | |||||
nvlist_add_stringf(req.args_nvl, | |||||
"cfiscsi_portal_group_tag", "%u", pg->pg_tag); | |||||
if (targ->t_alias) { | |||||
nvlist_add_string(req.args_nvl, | |||||
"cfiscsi_target_alias", targ->t_alias); | |||||
} | |||||
TAILQ_FOREACH(o, &pg->pg_options, o_next) | TAILQ_FOREACH(o, &pg->pg_options, o_next) | ||||
req.num_args++; | nvlist_add_string(req.args_nvl, o->o_name, | ||||
req.args = malloc(req.num_args * sizeof(*req.args)); | o->o_value); | ||||
if (req.args == NULL) | } | ||||
log_err(1, "malloc"); | |||||
n = 0; | if (port->p_ioctl_port) { | ||||
req.args[n].namelen = sizeof("port_id"); | strlcpy(req.driver, "ioctl", sizeof(req.driver)); | ||||
req.args[n].name = __DECONST(char *, "port_id"); | req.args_nvl = nvlist_create(0); | ||||
req.args[n].vallen = sizeof(port->p_ctl_port); | nvlist_add_stringf(req.args_nvl, "pp", "%d", | ||||
req.args[n].value = &port->p_ctl_port; | port->p_ioctl_pp); | ||||
req.args[n++].flags = CTL_BEARG_WR; | nvlist_add_stringf(req.args_nvl, "vp", "%d", | ||||
str_arg(&req.args[n++], "cfiscsi_target", targ->t_name); | port->p_ioctl_vp); | ||||
snprintf(tagstr, sizeof(tagstr), "%d", pg->pg_tag); | } | ||||
str_arg(&req.args[n++], "cfiscsi_portal_group_tag", tagstr); | |||||
if (targ->t_alias) | req.args = nvlist_pack(req.args_nvl, &req.args_len); | ||||
str_arg(&req.args[n++], "cfiscsi_target_alias", targ->t_alias); | if (req.args == NULL) { | ||||
str_arg(&req.args[n++], "ctld_portal_group_name", pg->pg_name); | log_warn("error packing nvlist"); | ||||
TAILQ_FOREACH(o, &pg->pg_options, o_next) | return (1); | ||||
str_arg(&req.args[n++], o->o_name, o->o_value); | } | ||||
req.num_args = n; | |||||
req.result = result_buf; | |||||
req.result_len = sizeof(result_buf); | |||||
error = ioctl(ctl_fd, CTL_PORT_REQ, &req); | error = ioctl(ctl_fd, CTL_PORT_REQ, &req); | ||||
free(req.args); | nvlist_destroy(req.args_nvl); | ||||
if (error != 0) { | if (error != 0) { | ||||
log_warn("error issuing CTL_PORT_REQ ioctl"); | log_warn("error issuing CTL_PORT_REQ ioctl"); | ||||
return (1); | return (1); | ||||
} | } | ||||
if (req.status == CTL_LUN_ERROR) { | if (req.status == CTL_LUN_ERROR) { | ||||
log_warnx("error returned from port creation request: %s", | log_warnx("error returned from port creation request: %s", | ||||
Not Done Inline ActionsAs I have already mentioned before, there is no any result overflow checking here. It will try to unpack non-written memory. mav: As I have already mentioned before, there is no any result overflow checking here. It will try… | |||||
req.error_str); | req.error_str); | ||||
return (1); | return (1); | ||||
} | } | ||||
if (req.status != CTL_LUN_OK) { | if (req.status != CTL_LUN_OK) { | ||||
log_warnx("unknown port creation request status %d", | log_warnx("unknown port creation request status %d", | ||||
req.status); | req.status); | ||||
return (1); | return (1); | ||||
} | } | ||||
req.result_nvl = nvlist_unpack(result_buf, req.result_len, 0); | |||||
if (req.result_nvl == NULL) { | |||||
log_warnx("error unpacking result nvlist"); | |||||
return (1); | |||||
} | |||||
port->p_ctl_port = nvlist_get_number(req.result_nvl, "port_id"); | |||||
nvlist_destroy(req.result_nvl); | |||||
} else if (port->p_pport) { | } else if (port->p_pport) { | ||||
port->p_ctl_port = port->p_pport->pp_ctl_port; | port->p_ctl_port = port->p_pport->pp_ctl_port; | ||||
if (strncmp(targ->t_name, "naa.", 4) == 0 && | if (strncmp(targ->t_name, "naa.", 4) == 0 && | ||||
strlen(targ->t_name) == 20) { | strlen(targ->t_name) == 20) { | ||||
bzero(&entry, sizeof(entry)); | bzero(&entry, sizeof(entry)); | ||||
entry.port_type = CTL_PORT_NONE; | entry.port_type = CTL_PORT_NONE; | ||||
entry.targ_port = port->p_ctl_port; | entry.targ_port = port->p_ctl_port; | ||||
▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
int | int | ||||
kernel_port_remove(struct port *port) | kernel_port_remove(struct port *port) | ||||
{ | { | ||||
struct ctl_port_entry entry; | struct ctl_port_entry entry; | ||||
struct ctl_lun_map lm; | struct ctl_lun_map lm; | ||||
struct ctl_req req; | struct ctl_req req; | ||||
char tagstr[16]; | |||||
struct target *targ = port->p_target; | struct target *targ = port->p_target; | ||||
struct portal_group *pg = port->p_portal_group; | struct portal_group *pg = port->p_portal_group; | ||||
int error; | int error; | ||||
/* Disable port */ | /* Disable port */ | ||||
bzero(&entry, sizeof(entry)); | bzero(&entry, sizeof(entry)); | ||||
entry.targ_port = port->p_ctl_port; | entry.targ_port = port->p_ctl_port; | ||||
error = ioctl(ctl_fd, CTL_DISABLE_PORT, &entry); | error = ioctl(ctl_fd, CTL_DISABLE_PORT, &entry); | ||||
if (error != 0) { | if (error != 0) { | ||||
log_warn("CTL_DISABLE_PORT ioctl failed"); | log_warn("CTL_DISABLE_PORT ioctl failed"); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
/* Remove iSCSI port. */ | /* Remove iSCSI or ioctl port. */ | ||||
if (port->p_portal_group) { | if (port->p_portal_group || port->p_ioctl_port) { | ||||
bzero(&req, sizeof(req)); | bzero(&req, sizeof(req)); | ||||
strlcpy(req.driver, "iscsi", sizeof(req.driver)); | strlcpy(req.driver, port->p_ioctl_port ? "ioctl" : "iscsi", | ||||
sizeof(req.driver)); | |||||
req.reqtype = CTL_REQ_REMOVE; | req.reqtype = CTL_REQ_REMOVE; | ||||
req.num_args = 2; | req.args_nvl = nvlist_create(0); | ||||
req.args = malloc(req.num_args * sizeof(*req.args)); | if (req.args_nvl == NULL) | ||||
if (req.args == NULL) | log_err(1, "nvlist_create"); | ||||
log_err(1, "malloc"); | |||||
str_arg(&req.args[0], "cfiscsi_target", targ->t_name); | if (port->p_ioctl_port) | ||||
snprintf(tagstr, sizeof(tagstr), "%d", pg->pg_tag); | nvlist_add_stringf(req.args_nvl, "port_id", "%d", | ||||
str_arg(&req.args[1], "cfiscsi_portal_group_tag", tagstr); | port->p_ctl_port); | ||||
else { | |||||
nvlist_add_string(req.args_nvl, "cfiscsi_target", | |||||
targ->t_name); | |||||
nvlist_add_stringf(req.args_nvl, | |||||
"cfiscsi_portal_group_tag", "%u", pg->pg_tag); | |||||
} | |||||
req.args = nvlist_pack(req.args_nvl, &req.args_len); | |||||
if (req.args == NULL) { | |||||
log_warn("error packing nvlist"); | |||||
return (1); | |||||
} | |||||
error = ioctl(ctl_fd, CTL_PORT_REQ, &req); | error = ioctl(ctl_fd, CTL_PORT_REQ, &req); | ||||
free(req.args); | nvlist_destroy(req.args_nvl); | ||||
if (error != 0) { | if (error != 0) { | ||||
log_warn("error issuing CTL_PORT_REQ ioctl"); | log_warn("error issuing CTL_PORT_REQ ioctl"); | ||||
return (1); | return (1); | ||||
} | } | ||||
if (req.status == CTL_LUN_ERROR) { | if (req.status == CTL_LUN_ERROR) { | ||||
log_warnx("error returned from port removal request: %s", | log_warnx("error returned from port removal request: %s", | ||||
req.error_str); | req.error_str); | ||||
return (1); | return (1); | ||||
▲ Show 20 Lines • Show All 158 Lines • Show Last 20 Lines |
Again double conversion. Not a huge deal, but would probably be nice to use nvlists directly. Though this can be done later.