From a3977bea20c226a1ed0e52404aec3f57c8509a58 Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Sun, 6 Sep 2015 11:23:01 +0000 Subject: [PATCH] Allow LUN options modification via CTL_LUNREQ_MODIFY. Not all changes take effect, but that is a different question. --- sys/cam/ctl/ctl.h | 2 + sys/cam/ctl/ctl_backend.c | 41 +++++++++++++-- sys/cam/ctl/ctl_backend_block.c | 18 +++---- sys/cam/ctl/ctl_backend_ramdisk.c | 29 ++++------- usr.sbin/ctladm/ctladm.8 | 9 +++- usr.sbin/ctladm/ctladm.c | 83 +++++++++++++++++++++++++++++-- usr.sbin/ctld/ctld.c | 18 +++---- usr.sbin/ctld/ctld.h | 2 +- usr.sbin/ctld/kernel.c | 29 ++++++++++- 9 files changed, 181 insertions(+), 50 deletions(-) diff --git a/sys/cam/ctl/ctl.h b/sys/cam/ctl/ctl.h index f672610e088b..0e0bfb69287c 100644 --- a/sys/cam/ctl/ctl.h +++ b/sys/cam/ctl/ctl.h @@ -208,6 +208,8 @@ typedef STAILQ_HEAD(ctl_options, ctl_option) ctl_options_t; struct ctl_be_arg; void ctl_init_opts(ctl_options_t *opts, int num_args, struct ctl_be_arg *args); +void ctl_update_opts(ctl_options_t *opts, int num_args, + struct ctl_be_arg *args); void ctl_free_opts(ctl_options_t *opts); char * ctl_get_opt(ctl_options_t *opts, const char *name); int ctl_expand_number(const char *buf, uint64_t *num); diff --git a/sys/cam/ctl/ctl_backend.c b/sys/cam/ctl/ctl_backend.c index ae5034bdc296..f243d0bfa31c 100644 --- a/sys/cam/ctl/ctl_backend.c +++ b/sys/cam/ctl/ctl_backend.c @@ -185,14 +185,47 @@ ctl_init_opts(ctl_options_t *opts, int num_args, struct ctl_be_arg *args) if ((args[i].flags & CTL_BEARG_ASCII) == 0) continue; opt = malloc(sizeof(*opt), M_CTL, M_WAITOK); - opt->name = malloc(strlen(args[i].kname) + 1, M_CTL, M_WAITOK); - strcpy(opt->name, args[i].kname); - opt->value = malloc(strlen(args[i].kvalue) + 1, M_CTL, M_WAITOK); - strcpy(opt->value, args[i].kvalue); + opt->name = strdup(args[i].kname, M_CTL); + opt->value = strdup(args[i].kvalue, M_CTL); STAILQ_INSERT_TAIL(opts, opt, links); } } +void +ctl_update_opts(ctl_options_t *opts, int num_args, struct ctl_be_arg *args) +{ + struct ctl_option *opt; + int i; + + for (i = 0; i < num_args; i++) { + if ((args[i].flags & CTL_BEARG_RD) == 0) + continue; + if ((args[i].flags & CTL_BEARG_ASCII) == 0) + continue; + STAILQ_FOREACH(opt, opts, links) { + if (strcmp(opt->name, args[i].kname) == 0) + break; + } + if (args[i].kvalue != NULL && + ((char *)args[i].kvalue)[0] != 0) { + if (opt) { + free(opt->value, M_CTL); + opt->value = strdup(args[i].kvalue, M_CTL); + } else { + opt = malloc(sizeof(*opt), M_CTL, M_WAITOK); + opt->name = strdup(args[i].kname, M_CTL); + opt->value = strdup(args[i].kvalue, M_CTL); + STAILQ_INSERT_TAIL(opts, opt, links); + } + } else if (opt) { + STAILQ_REMOVE(opts, opt, ctl_option, links); + free(opt->name, M_CTL); + free(opt->value, M_CTL); + free(opt, M_CTL); + } + } +} + void ctl_free_opts(ctl_options_t *opts) { diff --git a/sys/cam/ctl/ctl_backend_block.c b/sys/cam/ctl/ctl_backend_block.c index 1a9b55bb9ee0..799f74273ace 100644 --- a/sys/cam/ctl/ctl_backend_block.c +++ b/sys/cam/ctl/ctl_backend_block.c @@ -2423,9 +2423,6 @@ ctl_be_block_rm(struct ctl_be_block_softc *softc, struct ctl_lun_req *req) params = &req->reqdata.rm; mtx_lock(&softc->lock); - - be_lun = NULL; - STAILQ_FOREACH(be_lun, &softc->lun_list, links) { if (be_lun->cbe_lun.lun_id == params->lun_id) break; @@ -2589,13 +2586,13 @@ ctl_be_block_modify(struct ctl_be_block_softc *softc, struct ctl_lun_req *req) { struct ctl_lun_modify_params *params; struct ctl_be_block_lun *be_lun; + struct ctl_be_lun *cbe_lun; uint64_t oldsize; int error; params = &req->reqdata.modify; mtx_lock(&softc->lock); - be_lun = NULL; STAILQ_FOREACH(be_lun, &softc->lun_list, links) { if (be_lun->cbe_lun.lun_id == params->lun_id) break; @@ -2608,8 +2605,11 @@ ctl_be_block_modify(struct ctl_be_block_softc *softc, struct ctl_lun_req *req) params->lun_id); goto bailout_error; } + cbe_lun = &be_lun->cbe_lun; - be_lun->params.lun_size_bytes = params->lun_size_bytes; + if (params->lun_size_bytes != 0) + be_lun->params.lun_size_bytes = params->lun_size_bytes; + ctl_update_opts(&cbe_lun->options, req->num_be_args, req->kern_be_args); oldsize = be_lun->size_blocks; if (be_lun->vn == NULL) @@ -2622,11 +2622,11 @@ ctl_be_block_modify(struct ctl_be_block_softc *softc, struct ctl_lun_req *req) error = EINVAL; if (be_lun->size_blocks != oldsize) - ctl_lun_capacity_changed(&be_lun->cbe_lun); - if ((be_lun->cbe_lun.flags & CTL_LUN_FLAG_OFFLINE) && + ctl_lun_capacity_changed(cbe_lun); + if ((cbe_lun->flags & CTL_LUN_FLAG_OFFLINE) && be_lun->vn != NULL) { - be_lun->cbe_lun.flags &= ~CTL_LUN_FLAG_OFFLINE; - ctl_lun_online(&be_lun->cbe_lun); + cbe_lun->flags &= ~CTL_LUN_FLAG_OFFLINE; + ctl_lun_online(cbe_lun); } /* Tell the user the exact size we ended up using */ diff --git a/sys/cam/ctl/ctl_backend_ramdisk.c b/sys/cam/ctl/ctl_backend_ramdisk.c index 368c8dc4ccec..c39d1b60e5c1 100644 --- a/sys/cam/ctl/ctl_backend_ramdisk.c +++ b/sys/cam/ctl/ctl_backend_ramdisk.c @@ -73,6 +73,7 @@ typedef enum { } ctl_be_ramdisk_lun_flags; struct ctl_be_ramdisk_lun { + struct ctl_lun_create_params params; char lunname[32]; uint64_t size_bytes; uint64_t size_blocks; @@ -535,6 +536,7 @@ ctl_backend_ramdisk_create(struct ctl_be_ramdisk_softc *softc, be_lun = malloc(sizeof(*be_lun), M_RAMDISK, M_ZERO | M_WAITOK); cbe_lun = &be_lun->cbe_lun; cbe_lun->be_lun = be_lun; + be_lun->params = req->reqdata.create; be_lun->softc = softc; sprintf(be_lun->lunname, "cram%d", softc->num_luns); ctl_init_opts(&cbe_lun->options, req->num_be_args, req->kern_be_args); @@ -713,13 +715,12 @@ ctl_backend_ramdisk_modify(struct ctl_be_ramdisk_softc *softc, struct ctl_lun_req *req) { struct ctl_be_ramdisk_lun *be_lun; + struct ctl_be_lun *cbe_lun; struct ctl_lun_modify_params *params; uint32_t blocksize; params = &req->reqdata.modify; - be_lun = NULL; - mtx_lock(&softc->lock); STAILQ_FOREACH(be_lun, &softc->lun_list, links) { if (be_lun->cbe_lun.lun_id == params->lun_id) @@ -733,32 +734,22 @@ ctl_backend_ramdisk_modify(struct ctl_be_ramdisk_softc *softc, __func__, params->lun_id); goto bailout_error; } + cbe_lun = &be_lun->cbe_lun; - if (params->lun_size_bytes == 0) { - snprintf(req->error_str, sizeof(req->error_str), - "%s: LUN size \"auto\" not supported " - "by the ramdisk backend", __func__); - goto bailout_error; - } - + if (params->lun_size_bytes != 0) + be_lun->params.lun_size_bytes = params->lun_size_bytes; + ctl_update_opts(&cbe_lun->options, req->num_be_args, req->kern_be_args); blocksize = be_lun->cbe_lun.blocksize; - if (params->lun_size_bytes < blocksize) { + if (be_lun->params.lun_size_bytes < blocksize) { snprintf(req->error_str, sizeof(req->error_str), "%s: LUN size %ju < blocksize %u", __func__, - params->lun_size_bytes, blocksize); + be_lun->params.lun_size_bytes, blocksize); goto bailout_error; } - be_lun->size_blocks = params->lun_size_bytes / blocksize; + be_lun->size_blocks = be_lun->params.lun_size_bytes / blocksize; be_lun->size_bytes = be_lun->size_blocks * blocksize; - - /* - * The maximum LBA is the size - 1. - * - * XXX: Note that this field is being updated without locking, - * which might cause problems on 32-bit architectures. - */ be_lun->cbe_lun.maxlba = be_lun->size_blocks - 1; ctl_lun_capacity_changed(&be_lun->cbe_lun); diff --git a/usr.sbin/ctladm/ctladm.8 b/usr.sbin/ctladm/ctladm.8 index 261205651ea2..cc1fc1f0e337 100644 --- a/usr.sbin/ctladm/ctladm.8 +++ b/usr.sbin/ctladm/ctladm.8 @@ -34,7 +34,7 @@ .\" $Id: //depot/users/kenm/FreeBSD-test2/usr.sbin/ctladm/ctladm.8#3 $ .\" $FreeBSD$ .\" -.Dd June 3, 2015 +.Dd September 6, 2015 .Dt CTLADM 8 .Os .Sh NAME @@ -166,6 +166,7 @@ .Ic modify .Aq Fl b Ar backend .Aq Fl l Ar lun_id +.Op Fl o Ar name=value .Aq Fl s Ar size_bytes .Nm .Ic devlist @@ -859,6 +860,12 @@ and .Dq block . .It Fl l Ar lun_id Specify the LUN number to remove. +.It Fl o Ar name=value +Specify a backend-specific name/value pair. +Multiple +.Fl o +arguments may be specified. +Refer to the backend documentation for arguments that may be used. .It Fl s Ar size_bytes Specify the size of the LUN in bytes. For the diff --git a/usr.sbin/ctladm/ctladm.c b/usr.sbin/ctladm/ctladm.c index bc42dbd88f93..cca46c846986 100644 --- a/usr.sbin/ctladm/ctladm.c +++ b/usr.sbin/ctladm/ctladm.c @@ -183,7 +183,7 @@ static struct ctladm_opts option_table[] = { {"lunlist", CTLADM_CMD_LUNLIST, CTLADM_ARG_NONE, NULL}, {"lunmap", CTLADM_CMD_LUNMAP, CTLADM_ARG_NONE, "p:l:L:"}, {"modesense", CTLADM_CMD_MODESENSE, CTLADM_ARG_NEED_TL, "P:S:dlm:c:"}, - {"modify", CTLADM_CMD_MODIFY, CTLADM_ARG_NONE, "b:l:s:"}, + {"modify", CTLADM_CMD_MODIFY, CTLADM_ARG_NONE, "b:l:o:s:"}, {"port", CTLADM_CMD_PORT, CTLADM_ARG_NONE, "lo:p:qt:w:W:x"}, {"portlist", CTLADM_CMD_PORTLIST, CTLADM_ARG_NONE, "f:ilp:qvx"}, {"prin", CTLADM_CMD_PRES_IN, CTLADM_ARG_NEED_TL, "a:"}, @@ -3169,8 +3169,11 @@ cctl_modify_lun(int fd, int argc, char **argv, char *combinedopt) uint32_t lun_id = 0; int lun_id_set = 0, lun_size_set = 0; char *backend_name = NULL; + STAILQ_HEAD(, cctl_req_option) option_list; + int num_options = 0; int retval = 0, c; + STAILQ_INIT(&option_list); while ((c = getopt(argc, argv, combinedopt)) != -1) { switch (c) { case 'b': @@ -3180,6 +3183,43 @@ cctl_modify_lun(int fd, int argc, char **argv, char *combinedopt) lun_id = strtoul(optarg, NULL, 0); lun_id_set = 1; break; + case 'o': { + struct cctl_req_option *option; + char *tmpstr; + char *name, *value; + + tmpstr = strdup(optarg); + name = strsep(&tmpstr, "="); + if (name == NULL) { + warnx("%s: option -o takes \"name=value\"" + "argument", __func__); + retval = 1; + goto bailout; + } + value = strsep(&tmpstr, "="); + if (value == NULL) { + warnx("%s: option -o takes \"name=value\"" + "argument", __func__); + retval = 1; + goto bailout; + } + option = malloc(sizeof(*option)); + if (option == NULL) { + warn("%s: error allocating %zd bytes", + __func__, sizeof(*option)); + retval = 1; + goto bailout; + } + option->name = strdup(name); + option->namelen = strlen(name) + 1; + option->value = strdup(value); + option->vallen = strlen(value) + 1; + free(tmpstr); + + STAILQ_INSERT_TAIL(&option_list, option, links); + num_options++; + break; + } case 's': if (strcasecmp(optarg, "auto") != 0) { retval = expand_number(optarg, &lun_size); @@ -3203,8 +3243,9 @@ cctl_modify_lun(int fd, int argc, char **argv, char *combinedopt) if (lun_id_set == 0) errx(1, "%s: LUN id (-l) must be specified", __func__); - if (lun_size_set == 0) - errx(1, "%s: size (-s) must be specified", __func__); + if (lun_size_set == 0 && num_options == 0) + errx(1, "%s: size (-s) or options (-o) must be specified", + __func__); bzero(&req, sizeof(req)); @@ -3214,6 +3255,42 @@ cctl_modify_lun(int fd, int argc, char **argv, char *combinedopt) req.reqdata.modify.lun_id = lun_id; req.reqdata.modify.lun_size_bytes = lun_size; + req.num_be_args = num_options; + if (num_options > 0) { + struct cctl_req_option *option, *next_option; + int i; + + req.be_args = malloc(num_options * sizeof(*req.be_args)); + if (req.be_args == NULL) { + warn("%s: error allocating %zd bytes", __func__, + num_options * sizeof(*req.be_args)); + retval = 1; + goto bailout; + } + + for (i = 0, option = STAILQ_FIRST(&option_list); + i < num_options; i++, option = next_option) { + next_option = STAILQ_NEXT(option, links); + + req.be_args[i].namelen = option->namelen; + req.be_args[i].name = strdup(option->name); + req.be_args[i].vallen = option->vallen; + req.be_args[i].value = strdup(option->value); + /* + * XXX KDM do we want a way to specify a writeable + * flag of some sort? Do we want a way to specify + * binary data? + */ + req.be_args[i].flags = CTL_BEARG_ASCII | CTL_BEARG_RD; + + STAILQ_REMOVE(&option_list, option, cctl_req_option, + links); + free(option->name); + free(option->value); + free(option); + } + } + if (ioctl(fd, CTL_LUN_REQ, &req) == -1) { warn("%s: error issuing CTL_LUN_REQ ioctl", __func__); retval = 1; diff --git a/usr.sbin/ctld/ctld.c b/usr.sbin/ctld/ctld.c index 6f0c63b92d1a..f146ee6625b6 100644 --- a/usr.sbin/ctld/ctld.c +++ b/usr.sbin/ctld/ctld.c @@ -1961,18 +1961,14 @@ conf_apply(struct conf *oldconf, struct conf *newconf) TAILQ_FOREACH_SAFE(newlun, &newconf->conf_luns, l_next, tmplun) { oldlun = lun_find(oldconf, newlun->l_name); if (oldlun != NULL) { - if (newlun->l_size != oldlun->l_size || - newlun->l_size == 0) { - log_debugx("resizing lun \"%s\", CTL lun %d", + log_debugx("modifying lun \"%s\", CTL lun %d", + newlun->l_name, newlun->l_ctl_lun); + error = kernel_lun_modify(newlun); + if (error != 0) { + log_warnx("failed to " + "modify lun \"%s\", CTL lun %d", newlun->l_name, newlun->l_ctl_lun); - error = kernel_lun_resize(newlun); - if (error != 0) { - log_warnx("failed to " - "resize lun \"%s\", CTL lun %d", - newlun->l_name, - newlun->l_ctl_lun); - cumulated_error++; - } + cumulated_error++; } continue; } diff --git a/usr.sbin/ctld/ctld.h b/usr.sbin/ctld/ctld.h index f066b27232a0..8ac8de708f42 100644 --- a/usr.sbin/ctld/ctld.h +++ b/usr.sbin/ctld/ctld.h @@ -391,7 +391,7 @@ void lun_option_set(struct lun_option *clo, void kernel_init(void); int kernel_lun_add(struct lun *lun); -int kernel_lun_resize(struct lun *lun); +int kernel_lun_modify(struct lun *lun); int kernel_lun_remove(struct lun *lun); void kernel_handoff(struct connection *conn); void kernel_limits(const char *offload, diff --git a/usr.sbin/ctld/kernel.c b/usr.sbin/ctld/kernel.c index 776a782f2f41..b75527f16dbb 100644 --- a/usr.sbin/ctld/kernel.c +++ b/usr.sbin/ctld/kernel.c @@ -743,9 +743,11 @@ kernel_lun_add(struct lun *lun) } int -kernel_lun_resize(struct lun *lun) +kernel_lun_modify(struct lun *lun) { + struct lun_option *lo; struct ctl_lun_req req; + int error, i, num_options; bzero(&req, sizeof(req)); @@ -755,7 +757,30 @@ kernel_lun_resize(struct lun *lun) req.reqdata.modify.lun_id = lun->l_ctl_lun; req.reqdata.modify.lun_size_bytes = lun->l_size; - if (ioctl(ctl_fd, CTL_LUN_REQ, &req) == -1) { + num_options = 0; + TAILQ_FOREACH(lo, &lun->l_options, lo_next) + num_options++; + + req.num_be_args = num_options; + if (num_options > 0) { + req.be_args = malloc(num_options * sizeof(*req.be_args)); + if (req.be_args == NULL) { + log_warn("error allocating %zd bytes", + num_options * sizeof(*req.be_args)); + return (1); + } + + i = 0; + TAILQ_FOREACH(lo, &lun->l_options, lo_next) { + str_arg(&req.be_args[i], lo->lo_name, lo->lo_value); + i++; + } + assert(i == num_options); + } + + error = ioctl(ctl_fd, CTL_LUN_REQ, &req); + free(req.be_args); + if (error != 0) { log_warn("error issuing CTL_LUN_REQ ioctl"); return (1); }