1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <ctype.h> 28 #include <sys/types.h> 29 #include <time.h> 30 #include <sys/utsname.h> 31 #include <unistd.h> 32 #include <sys/param.h> 33 #include <fcntl.h> 34 #include <sys/stat.h> 35 #include <sys/statvfs.h> 36 #include <errno.h> 37 #include <strings.h> 38 #include <sys/vtoc.h> 39 #include <sys/efi_partition.h> 40 #include <uuid/uuid.h> 41 #include <sys/scsi/impl/uscsi.h> 42 #include <sys/scsi/generic/commands.h> 43 #include <sys/scsi/impl/commands.h> 44 #include <libzfs.h> 45 #include <syslog.h> 46 #include <priv.h> 47 48 #include <iscsitgt_impl.h> 49 #include "queue.h" 50 #include "target.h" 51 #include "iscsi_cmd.h" 52 #include "utility.h" 53 #include "errcode.h" 54 #include "t10_spc.h" 55 #include "isns_client.h" 56 #include "mgmt_scf.h" 57 58 extern char *getfullrawname(); 59 60 static char *create_target(tgt_node_t *); 61 static char *create_initiator(tgt_node_t *); 62 static char *create_tpgt(tgt_node_t *); 63 static char *create_zfs(tgt_node_t *, ucred_t *); 64 static Boolean_t create_target_dir(char *targ_name, char *local_name); 65 static char *create_node_name(char *local_nick, char *alias); 66 static Boolean_t create_lun(char *targ_name, char *local_name, char *type, 67 int lun, char *size_str, char *backing, err_code_t *code); 68 static Boolean_t create_lun_common(char *targ_name, char *local_name, int lun, 69 uint64_t size, err_code_t *code); 70 static Boolean_t setup_disk_backing(err_code_t *code, char *path, char *backing, 71 tgt_node_t *n, uint64_t *size); 72 static Boolean_t setup_raw_backing(err_code_t *code, char *path, char *backing, 73 uint64_t *size); 74 75 /* 76 * []---- 77 * | create_func -- Branch out to appropriate object create function 78 * []---- 79 */ 80 /*ARGSUSED*/ 81 void 82 create_func(tgt_node_t *p, target_queue_t *reply, target_queue_t *mgmt, 83 ucred_t *cred) 84 { 85 tgt_node_t *x; 86 char msgbuf[80]; 87 char *reply_msg = NULL; 88 89 x = p->x_child; 90 91 /* 92 * create_zfs() does not affect SMF data 93 * therefore it is not covered by auth check 94 */ 95 if (x == NULL) { 96 xml_rtn_msg(&reply_msg, ERR_SYNTAX_MISSING_OBJECT); 97 } else if (strcmp(x->x_name, XML_ELEMENT_ZFS) == 0) { 98 reply_msg = create_zfs(x, cred); 99 } else if (check_auth_addremove(cred) != True) { 100 xml_rtn_msg(&reply_msg, ERR_NO_PERMISSION); 101 } else { 102 if (x->x_name == NULL) { 103 xml_rtn_msg(&reply_msg, ERR_SYNTAX_MISSING_OBJECT); 104 } else if (strcmp(x->x_name, XML_ELEMENT_TARG) == 0) { 105 reply_msg = create_target(x); 106 } else if (strcmp(x->x_name, XML_ELEMENT_INIT) == 0) { 107 reply_msg = create_initiator(x); 108 } else if (strcmp(x->x_name, XML_ELEMENT_TPGT) == 0) { 109 reply_msg = create_tpgt(x); 110 } else { 111 (void) snprintf(msgbuf, sizeof (msgbuf), 112 "Unknown object '%s' for create element", 113 x->x_name); 114 xml_rtn_msg(&reply_msg, ERR_INVALID_OBJECT); 115 } 116 } 117 queue_message_set(reply, 0, msg_mgmt_rply, reply_msg); 118 } 119 120 /* 121 * create_target -- an administrative request to create a target 122 */ 123 static char * 124 create_target(tgt_node_t *x) 125 { 126 char *msg = NULL; 127 char *name = NULL; 128 char *alias = NULL; 129 char *size = NULL; 130 char *type = NULL; 131 char *backing = NULL; 132 char *node_name = NULL; 133 char path[MAXPATHLEN]; 134 int lun = 0; /* default to LUN 0 */ 135 int i; 136 tgt_node_t *n, *c, *l; 137 err_code_t code; 138 139 (void) pthread_rwlock_wrlock(&targ_config_mutex); 140 (void) tgt_find_value_str(x, XML_ELEMENT_BACK, &backing); 141 (void) tgt_find_value_str(x, XML_ELEMENT_ALIAS, &alias); 142 if (tgt_find_value_intchk(x, XML_ELEMENT_LUN, &lun) == False) { 143 xml_rtn_msg(&msg, ERR_LUN_INVALID_RANGE); 144 goto error; 145 } 146 147 /* 148 * We've got to have a name element or all bets are off. 149 */ 150 if (tgt_find_value_str(x, XML_ELEMENT_NAME, &name) == False) { 151 xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); 152 goto error; 153 } 154 155 /* 156 * RFC3722 states that names must be one of: 157 * (1) a..z 158 * (2) A..Z 159 * (3) 0-9 160 * or 161 * (4) ':', '.', '-' 162 * If it's an upper case character is must be made lower 163 * case. 164 */ 165 for (i = 0; i < strlen(name); i++) { 166 if (!isalnum(name[i]) && 167 (name[i] != ':') && (name[i] != '.') && (name[i] != '-')) { 168 xml_rtn_msg(&msg, ERR_SYNTAX_INVALID_NAME); 169 goto error; 170 } else if (isupper(name[i])) 171 name[i] = tolower(name[i]); 172 } 173 174 if (tgt_find_value_str(x, XML_ELEMENT_TYPE, &type) == False) { 175 /* 176 * If a type hasn't been specified default to disk emulation. 177 * We use strdup() since at the end of this routine the code 178 * is expecting to free 'type' along with other strings. 179 */ 180 type = strdup(TGT_TYPE_DISK); 181 } 182 183 if ((strcmp(type, "raw") == 0) && (backing == NULL)) { 184 xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_BACKING_STORE); 185 goto error; 186 } 187 188 if (tgt_find_value_str(x, XML_ELEMENT_SIZE, &size) == False) { 189 if (backing != NULL) { 190 191 /* 192 * If a backing store has been provided we don't 193 * need the size since we can determine that from 194 * a READ_CAPACITY command which everyone issues. 195 * 196 * NOTE: strdup is used here, since at the end 197 * of this routine any of the string pointers which 198 * are non-NULL get freed. 199 */ 200 size = strdup("0"); 201 } else { 202 xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_SIZE); 203 goto error; 204 } 205 } 206 if ((lun < 0) || (lun > T10_MAX_LUNS)) { 207 xml_rtn_msg(&msg, ERR_LUN_INVALID_RANGE); 208 goto error; 209 } 210 211 /* 212 * See if we already have a local target name created. If so, 213 * the user is most likely wanting to create another LUN for this 214 * target. Checking to see if there's a duplicate LUN will be 215 * done later. 216 */ 217 for (n = main_config->x_child; n; n = n->x_sibling) { 218 if (strcmp(n->x_value, name) == 0) 219 break; 220 } 221 222 if (n == NULL) { 223 if (lun != 0) { 224 xml_rtn_msg(&msg, ERR_LUN_ZERO_NOT_FIRST); 225 goto error; 226 } 227 if ((node_name = create_node_name(name, alias)) == NULL) { 228 xml_rtn_msg(&msg, ERR_CREATE_NAME_TOO_LONG); 229 goto error; 230 } 231 if (create_target_dir(node_name, name) == False) { 232 xml_rtn_msg(&msg, ERR_CREATE_TARGET_DIR_FAILED); 233 goto error; 234 } 235 n = tgt_node_alloc(XML_ELEMENT_TARG, String, name); 236 c = tgt_node_alloc(XML_ELEMENT_INAME, String, node_name); 237 tgt_node_add(n, c); 238 c = tgt_node_alloc(XML_ELEMENT_LUNLIST, String, ""); 239 l = tgt_node_alloc(XML_ELEMENT_LUN, Int, &lun); 240 tgt_node_add(c, l); 241 tgt_node_add(n, c); 242 if (alias != NULL) { 243 c = tgt_node_alloc(XML_ELEMENT_ALIAS, String, alias); 244 tgt_node_add(n, c); 245 } 246 tgt_node_add(targets_config, n); 247 248 } else { 249 if (tgt_find_value_str(n, XML_ELEMENT_INAME, 250 &node_name) == False) { 251 xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_INAME); 252 goto error; 253 } 254 if ((c = tgt_node_next(n, XML_ELEMENT_LUNLIST, NULL)) == NULL) { 255 xml_rtn_msg(&msg, ERR_INTERNAL_ERROR); 256 goto error; 257 } 258 l = tgt_node_alloc(XML_ELEMENT_LUN, Int, &lun); 259 tgt_node_add(c, l); 260 } 261 262 if (create_lun(node_name, name, type, lun, size, backing, &code) 263 == True) { 264 if (mgmt_config_save2scf() == False) { 265 xml_rtn_msg(&msg, ERR_INTERNAL_ERROR); 266 goto error; 267 } 268 269 /* Only isns register on the 1st creation of the target */ 270 if (lun == 0 && isns_enabled() == True) { 271 if (isns_reg(node_name) != 0) { 272 xml_rtn_msg(&msg, ERR_ISNS_ERROR); 273 goto error; 274 } 275 } 276 277 } else if ((lun == 0) && (code != ERR_LUN_EXISTS)) { 278 279 /* 280 * The first LU will have created the directory and 281 * symbolic link. Remove those on error. 282 */ 283 (void) snprintf(path, sizeof (path), "%s/%s", 284 target_basedir, node_name); 285 (void) rmdir(path); 286 (void) snprintf(path, sizeof (path), "%s/%s", 287 target_basedir, name); 288 (void) unlink(path); 289 (void) tgt_node_remove(targets_config, n, MatchBoth); 290 } else 291 (void) tgt_node_remove(c, l, MatchBoth); 292 293 xml_rtn_msg(&msg, code); 294 295 error: 296 if (name != NULL) 297 free(name); 298 if (size != NULL) 299 free(size); 300 if (alias != NULL) 301 free(alias); 302 if (backing != NULL) 303 free(backing); 304 if (node_name != NULL) 305 free(node_name); 306 if (type != NULL) 307 free(type); 308 309 (void) pthread_rwlock_unlock(&targ_config_mutex); 310 return (msg); 311 } 312 313 static char * 314 create_initiator(tgt_node_t *x) 315 { 316 char *msg = NULL; 317 char *name = NULL; 318 char *iscsi_name = NULL; 319 tgt_node_t *inode = NULL; 320 tgt_node_t *n, *c; 321 322 (void) pthread_rwlock_wrlock(&targ_config_mutex); 323 if (tgt_find_value_str(x, XML_ELEMENT_NAME, &name) == False) { 324 xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); 325 goto error; 326 } 327 if (tgt_find_value_str(x, XML_ELEMENT_INAME, &iscsi_name) == False) { 328 xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_INAME); 329 goto error; 330 } 331 if (strlen(iscsi_name) >= ISCSI_MAX_NAME_LEN) { 332 xml_rtn_msg(&msg, ERR_NAME_TOO_LONG); 333 goto error; 334 } 335 336 while ((inode = tgt_node_next_child(main_config, XML_ELEMENT_INIT, 337 inode)) != NULL) { 338 if (strcmp(inode->x_value, name) == 0) { 339 xml_rtn_msg(&msg, ERR_INIT_EXISTS); 340 goto error; 341 } 342 } 343 344 n = tgt_node_alloc(XML_ELEMENT_INIT, String, name); 345 c = tgt_node_alloc(XML_ELEMENT_INAME, String, iscsi_name); 346 tgt_node_add(n, c); 347 tgt_node_add(main_config, n); 348 349 if (mgmt_config_save2scf() == True) 350 xml_rtn_msg(&msg, ERR_SUCCESS); 351 else 352 xml_rtn_msg(&msg, ERR_INTERNAL_ERROR); 353 354 error: 355 if (name) 356 free(name); 357 if (iscsi_name) 358 free(iscsi_name); 359 360 (void) pthread_rwlock_unlock(&targ_config_mutex); 361 return (msg); 362 } 363 364 static char * 365 create_tpgt(tgt_node_t *x) 366 { 367 char *msg = NULL; 368 char *tpgt = NULL; 369 char *extra = NULL; 370 tgt_node_t *tnode = NULL; 371 tgt_node_t *n; 372 int tpgt_val; 373 374 (void) pthread_rwlock_wrlock(&targ_config_mutex); 375 if (tgt_find_value_str(x, XML_ELEMENT_NAME, &tpgt) == False) { 376 xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); 377 goto error; 378 } 379 380 /* ---- Validation checks ---- */ 381 tpgt_val = strtol(tpgt, &extra, 0); 382 if ((extra && (*extra != '\0')) || 383 (tpgt_val < TPGT_MIN) || (tpgt_val > TPGT_MAX)) { 384 xml_rtn_msg(&msg, ERR_INVALID_TPGT); 385 goto error; 386 } 387 388 while ((tnode = tgt_node_next_child(main_config, XML_ELEMENT_TPGT, 389 tnode)) != NULL) { 390 if (strcmp(tnode->x_value, tpgt) == 0) { 391 xml_rtn_msg(&msg, ERR_TPGT_EXISTS); 392 goto error; 393 } 394 } 395 396 n = tgt_node_alloc(XML_ELEMENT_TPGT, String, tpgt); 397 tgt_node_add(main_config, n); 398 399 if (mgmt_config_save2scf() == True) 400 xml_rtn_msg(&msg, ERR_SUCCESS); 401 else 402 xml_rtn_msg(&msg, ERR_INTERNAL_ERROR); 403 404 error: 405 if (tpgt) 406 free(tpgt); 407 408 (void) pthread_rwlock_unlock(&targ_config_mutex); 409 return (msg); 410 } 411 412 /* 413 * create_zfs -- given a dataset, export it through the iSCSI protocol 414 * 415 * This function is called when someone uses the libiscsitgt function 416 * iscsitgt_zfs_share(char *dataset) 417 */ 418 static char * 419 create_zfs(tgt_node_t *x, ucred_t *cred) 420 { 421 char *msg = NULL; 422 char *dataset = NULL; 423 char *cptr = NULL; 424 char path[MAXPATHLEN]; 425 tgt_node_t *n = NULL; 426 tgt_node_t *c; 427 tgt_node_t *l; 428 uint64_t size; 429 int status; 430 431 (void) pthread_rwlock_wrlock(&targ_config_mutex); 432 /* 433 * Extract the dataset name from the arguments passed in 434 */ 435 if (tgt_find_value_str(x, XML_ELEMENT_NAME, &dataset) == False) { 436 xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); 437 goto error; 438 } 439 440 /* 441 * Since this is a create, assure that an existing dataset with the 442 * same name does not exists 443 */ 444 c = NULL; 445 while ((c = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, c))) { 446 if (strcmp(c->x_value, dataset) == 0) { 447 xml_rtn_msg(&msg, ERR_LUN_EXISTS); 448 goto error; 449 } 450 } 451 452 /* 453 * See if this is a re-create of a previously create ZVOL target 454 * If no shareiscsi properties exists, create a new set of properties 455 */ 456 status = get_zfs_shareiscsi(dataset, &n, &size, cred); 457 if ((status != ERR_SUCCESS) && (status != ERR_NULL_XML_MESSAGE)) { 458 xml_rtn_msg(&msg, status); 459 goto error; 460 } else if (status == ERR_NULL_XML_MESSAGE) { 461 462 char *name; 463 int lun = 0; 464 int guid = 0; 465 int rpm = DEFAULT_RPM; 466 int heads = DEFAULT_HEADS; 467 int cylinders = DEFAULT_CYLINDERS; 468 int spt = DEFAULT_SPT; 469 int bytes_sect = DEFAULT_BYTES_PER; 470 int interleave = DEFAULT_INTERLEAVE; 471 472 n = tgt_node_alloc(XML_ELEMENT_TARG, String, NULL); 473 c = tgt_node_alloc(XML_ELEMENT_INCORE, String, XML_VALUE_TRUE); 474 tgt_node_add_attr(n, c); 475 476 if (name = create_node_name(NULL, NULL)) { 477 c = tgt_node_alloc(XML_ELEMENT_INAME, String, name); 478 tgt_node_add(n, c); 479 free(name); 480 } else { 481 xml_rtn_msg(&msg, ERR_CREATE_NAME_TOO_LONG); 482 goto error; 483 } 484 485 c = tgt_node_alloc(XML_ELEMENT_LUNLIST, String, ""); 486 tgt_node_add(n, c); 487 488 l = tgt_node_alloc(XML_ELEMENT_LUN, Int, &lun); 489 tgt_node_add(c, l); 490 491 c = tgt_node_alloc(XML_ELEMENT_VERS, String, "1.0"); 492 tgt_node_add_attr(l, c); 493 494 c = tgt_node_alloc(XML_ELEMENT_GUID, Int, &guid); 495 tgt_node_add(l, c); 496 497 c = tgt_node_alloc(XML_ELEMENT_PID, String, DEFAULT_PID); 498 tgt_node_add(l, c); 499 500 c = tgt_node_alloc(XML_ELEMENT_VID, String, DEFAULT_VID); 501 tgt_node_add(l, c); 502 503 c = tgt_node_alloc(XML_ELEMENT_DTYPE, String, TGT_TYPE_DISK); 504 tgt_node_add(l, c); 505 506 create_geom(size, &cylinders, &heads, &spt); 507 508 c = tgt_node_alloc(XML_ELEMENT_RPM, Int, &rpm); 509 tgt_node_add(l, c); 510 511 c = tgt_node_alloc(XML_ELEMENT_HEADS, Int, &heads); 512 tgt_node_add(l, c); 513 514 c = tgt_node_alloc(XML_ELEMENT_CYLINDERS, Int, &cylinders); 515 tgt_node_add(l, c); 516 517 c = tgt_node_alloc(XML_ELEMENT_SPT, Int, &spt); 518 tgt_node_add(l, c); 519 520 c = tgt_node_alloc(XML_ELEMENT_BPS, Int, &bytes_sect); 521 tgt_node_add(l, c); 522 523 c = tgt_node_alloc(XML_ELEMENT_INTERLEAVE, Int, &interleave); 524 tgt_node_add(l, c); 525 526 c = tgt_node_alloc(XML_ELEMENT_STATUS, String, 527 TGT_STATUS_ONLINE); 528 tgt_node_add(l, c); 529 530 /* 531 * Set the ZFS persisted shareiscsi options 532 */ 533 if ((status = put_zfs_shareiscsi(dataset, n)) != ERR_SUCCESS) { 534 xml_rtn_msg(&msg, status); 535 goto error; 536 } 537 } else { 538 /* 539 * If the was a recreate of a ZVOL iSCSI Target, 'n' is expected 540 * to contain the properties for this iSCSI target node 541 * 542 * Make sure these properties have the "in-core" attribute 543 */ 544 if (tgt_find_attr_str(n, XML_ELEMENT_INCORE, &cptr) == True) { 545 if (strcmp(cptr, "true") != 0) { 546 free(cptr); 547 xml_rtn_msg(&msg, ERR_INTERNAL_ERROR); 548 goto error; 549 } 550 free(cptr); 551 } 552 } 553 554 /* 555 * Pick up the LU node from the LU List which hangs off of the target 556 * node. If either is NULL there's an internal error someplace. 557 */ 558 if (((l = tgt_node_next(n, XML_ELEMENT_LUNLIST, NULL)) == NULL) || 559 ((l = tgt_node_next(l, XML_ELEMENT_LUN, NULL)) == NULL)) { 560 xml_rtn_msg(&msg, ERR_INTERNAL_ERROR); 561 goto error; 562 } 563 564 /* 565 * With ZVOLS, some elements can change everytime we share the dataset. 566 * The TargetAlias and backing store can change since these are based on 567 * the dataset and the size of the volume. Therefore, these pieces of 568 * information are not stored as part of the iscsioptions properity, but 569 * are retained in the in-core targets_config 570 */ 571 (void) tgt_update_value_str(n, XML_ELEMENT_TARG, dataset); 572 c = tgt_node_alloc(XML_ELEMENT_ALIAS, String, dataset); 573 tgt_node_add(n, c); 574 575 (void) snprintf(path, sizeof (path), "%s%s", ZVOL_PATH, dataset); 576 c = tgt_node_alloc(XML_ELEMENT_BACK, String, path); 577 tgt_node_add(l, c); 578 579 size /= 512LL; 580 c = tgt_node_alloc(XML_ELEMENT_SIZE, Uint64, &size); 581 tgt_node_add(l, c); 582 583 cptr = NULL; 584 if (tgt_find_value_str(n, XML_ELEMENT_INAME, &cptr) != True) { 585 xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_INAME); 586 goto error; /* xml node contruction has an issue. */ 587 } 588 589 /* 590 * Add ZVOL target to config of all targets 591 */ 592 tgt_node_add(targets_config, n); 593 n = NULL; /* don't remove the node from the targets_config. */ 594 595 /* register with iSNS */ 596 if (isns_enabled() == True) { 597 if (isns_reg(cptr) != 0) { 598 xml_rtn_msg(&msg, ERR_ISNS_ERROR); 599 goto error; 600 } 601 } 602 603 xml_rtn_msg(&msg, ERR_SUCCESS); 604 605 error: 606 if (cptr) 607 free(cptr); 608 if (dataset) 609 free(dataset); 610 if (n) 611 tgt_node_free(n); 612 613 (void) pthread_rwlock_unlock(&targ_config_mutex); 614 return (msg); 615 } 616 617 /* 618 * []------------------------------------------------------------------[] 619 * | Utility functions used by the routines above. | 620 * []------------------------------------------------------------------[] 621 */ 622 623 /* 624 * []---- 625 * | create_node_name -- Creates the IQN that adhears to RFC3270 626 * []---- 627 */ 628 static char * 629 create_node_name(char *local_nick, char *alias) 630 { 631 uuid_t id; 632 char id_str[37]; 633 char *p; 634 char *anp; /* alias or nick pointer */ 635 636 if ((p = (char *)malloc(ISCSI_MAX_NAME_LEN)) == NULL) 637 return (NULL); 638 639 /* 640 * Originally we we going to use the machines MAC address and 641 * timestamp in hex format. This would be consistent with the 642 * Solaris iSCSI initiator and NAS5310. Unfortunately, someone 643 * pointed out that there's no requirement that the network 644 * interfaces be plumbed before someone attempts to create 645 * targets. If the networks aren't plumbed there are no MAC 646 * addresses available and we can't use 0 for the MAC address 647 * since that would introduce the probability of non-unique 648 * IQN names. 649 */ 650 uuid_generate(id); 651 uuid_unparse(id, id_str); 652 if (snprintf(p, ISCSI_MAX_NAME_LEN, "iqn.1986-03.com.sun:%02d:%s", 653 TARGET_NAME_VERS, id_str) > ISCSI_MAX_NAME_LEN) { 654 free(p); 655 return (NULL); 656 } 657 if (local_nick || alias) { 658 anp = (alias != NULL) ? alias : local_nick; 659 660 /* 661 * Make sure we still have room to add the alias or 662 * local nickname, a '.', and NULL character to the 663 * buffer. 664 */ 665 if ((strlen(p) + strlen(anp) + 2) > ISCSI_MAX_NAME_LEN) { 666 free(p); 667 return (NULL); 668 } 669 (void) strcat(p, "."); 670 (void) strcat(p, anp); 671 } 672 673 return (p); 674 } 675 676 /* 677 * []---- 678 * | create_target_dir -- create the target directory 679 * []---- 680 */ 681 static Boolean_t 682 create_target_dir(char *targ_name, char *local_name) 683 { 684 char path[MAXPATHLEN]; 685 char sympath[MAXPATHLEN]; 686 687 if ((mkdir(target_basedir, 0777) == -1) && (errno != EEXIST)) 688 return (False); 689 690 (void) snprintf(path, sizeof (path), "%s/%s", target_basedir, 691 targ_name); 692 (void) snprintf(sympath, sizeof (sympath), "%s/%s", target_basedir, 693 local_name); 694 695 if ((mkdir(path, 0777) == -1) && (errno != EEXIST)) 696 return (False); 697 698 /* 699 * This symbolic link is here for convenience and nothing more, so if 700 * if fails. Oh well. 701 */ 702 (void) symlink(path, sympath); 703 return (True); 704 } 705 706 /* 707 * []---- 708 * | create_lun -- given type, lun, size, backing create LU and params 709 * []---- 710 */ 711 static Boolean_t 712 create_lun(char *targ_name, char *local_name, char *type, int lun, 713 char *size_str, char *backing, err_code_t *code) 714 { 715 uint64_t size, ssize; 716 int fd = -1; 717 int rpm = DEFAULT_RPM; 718 int heads = DEFAULT_HEADS; 719 int cylinders = DEFAULT_CYLINDERS; 720 int spt = DEFAULT_SPT; 721 int bytes_sect = DEFAULT_BYTES_PER; 722 int interleave = DEFAULT_INTERLEAVE; 723 char *vid = DEFAULT_VID; 724 char *pid = DEFAULT_PID; 725 char path[MAXPATHLEN]; 726 tgt_node_t *n = NULL; 727 tgt_node_t *pn = NULL; 728 729 /* 730 * after calling stroll_multipler it's an error for size to be 731 * 0, if and only if, the size_str doesn't equal "0". The administrator 732 * may want the code to determine the size. This would be the case 733 * when the administrator has provide a backing store which exists. 734 */ 735 if ((strtoll_multiplier(size_str, &size) == False) || 736 ((size == 0) && (size_str != NULL) && strcmp(size_str, "0"))) { 737 *code = ERR_INVALID_SIZE; 738 return (False); 739 } 740 741 if ((size % 512) != 0) { 742 *code = ERR_SIZE_MOD_BLOCK; 743 return (False); 744 } 745 746 /* 747 * Make sure we're not trying to recreate an existing LU. 748 */ 749 (void) snprintf(path, sizeof (path), "%s/%s/%s%d", target_basedir, 750 targ_name, LUNBASE, lun); 751 if (access(path, F_OK) == 0) { 752 *code = ERR_LUN_EXISTS; 753 return (False); 754 } 755 756 n = tgt_node_alloc(XML_ELEMENT_PARAMS, String, NULL); 757 758 pn = tgt_node_alloc(XML_ELEMENT_VERS, String, "1.0"); 759 tgt_node_add_attr(n, pn); 760 761 pn = tgt_node_alloc(XML_ELEMENT_GUID, String, "0"); 762 tgt_node_add(n, pn); 763 pn = tgt_node_alloc(XML_ELEMENT_PID, String, pid); 764 tgt_node_add(n, pn); 765 pn = tgt_node_alloc(XML_ELEMENT_VID, String, vid); 766 tgt_node_add(n, pn); 767 pn = tgt_node_alloc(XML_ELEMENT_DTYPE, String, type); 768 tgt_node_add(n, pn); 769 770 if (strcmp(type, TGT_TYPE_DISK) == 0) { 771 772 (void) snprintf(path, sizeof (path), "%s/%s/lun.%d", 773 target_basedir, targ_name, lun); 774 if (setup_disk_backing(code, path, backing, n, &size) == False) 775 goto error; 776 777 create_geom(size, &cylinders, &heads, &spt); 778 779 pn = tgt_node_alloc(XML_ELEMENT_RPM, Int, &rpm); 780 tgt_node_add(n, pn); 781 pn = tgt_node_alloc(XML_ELEMENT_HEADS, Int, &heads); 782 tgt_node_add(n, pn); 783 pn = tgt_node_alloc(XML_ELEMENT_CYLINDERS, Int, &cylinders); 784 tgt_node_add(n, pn); 785 pn = tgt_node_alloc(XML_ELEMENT_SPT, Int, &spt); 786 tgt_node_add(n, pn); 787 pn = tgt_node_alloc(XML_ELEMENT_BPS, Int, &bytes_sect); 788 tgt_node_add(n, pn); 789 pn = tgt_node_alloc(XML_ELEMENT_INTERLEAVE, Int, &interleave); 790 tgt_node_add(n, pn); 791 pn = tgt_node_alloc(XML_ELEMENT_STATUS, String, 792 TGT_STATUS_OFFLINE); 793 tgt_node_add(n, pn); 794 795 } else if (strcmp(type, TGT_TYPE_TAPE) == 0) { 796 #ifndef _LP64 797 *code = ERR_TAPE_NOT_SUPPORTED_IN_32BIT; 798 goto error; 799 #else 800 pn = tgt_node_alloc(XML_ELEMENT_STATUS, String, 801 TGT_STATUS_OFFLINE); 802 tgt_node_add(n, pn); 803 804 (void) snprintf(path, sizeof (path), "%s/%s/lun.%d", 805 target_basedir, targ_name, lun); 806 if (setup_disk_backing(code, path, backing, n, &size) == False) 807 goto error; 808 #endif 809 810 } else if (strcmp(type, TGT_TYPE_RAW) == 0) { 811 812 pn = tgt_node_alloc(XML_ELEMENT_STATUS, String, 813 TGT_STATUS_ONLINE); 814 tgt_node_add(n, pn); 815 816 backing = getfullrawname(backing); 817 if (setup_raw_backing(code, path, backing, &size) == False) 818 goto error; 819 820 pn = tgt_node_alloc(XML_ELEMENT_MMAP_LUN, String, "false"); 821 tgt_node_add(n, pn); 822 823 (void) snprintf(path, sizeof (path), "%s/%s/lun.%d", 824 target_basedir, targ_name, lun); 825 if (symlink(backing, path)) { 826 *code = ERR_CREATE_SYMLINK_FAILED; 827 goto error; 828 } 829 830 iscsi_inventory_change(targ_name); 831 832 } else if (strcmp(type, TGT_TYPE_OSD) == 0) { 833 834 (void) snprintf(path, sizeof (path), "%s/%s/%s%d", 835 target_basedir, targ_name, OSDBASE, lun); 836 if (mkdir(path, 0700) != 0) 837 goto error; 838 } 839 840 841 /* 842 * Wait to set the size until here because it may be unknown until 843 * the possible backing store has been setup. 844 */ 845 ssize = size / 512LL; 846 pn = tgt_node_alloc(XML_ELEMENT_SIZE, Uint64, &ssize); 847 tgt_node_add(n, pn); 848 849 if (backing != NULL) { 850 pn = tgt_node_alloc(XML_ELEMENT_BACK, String, backing); 851 tgt_node_add(n, pn); 852 } 853 854 (void) mgmt_param_save2scf(n, local_name, lun); 855 856 if ((strcmp(type, TGT_TYPE_DISK) == 0) || 857 (strcmp(type, TGT_TYPE_TAPE) == 0)) { 858 if (create_lun_common(targ_name, local_name, lun, size, 859 code) == False) 860 goto error; 861 } 862 863 tgt_node_free(n); 864 865 *code = ERR_SUCCESS; 866 return (True); 867 868 error: 869 /* Free node n */ 870 tgt_node_free(n); 871 872 (void) snprintf(path, sizeof (path), "%s/%s/%s%d", target_basedir, 873 targ_name, PARAMBASE, lun); 874 (void) unlink(path); 875 if (fd == -1) 876 (void) close(fd); 877 return (False); 878 } 879 880 /* 881 * []---- 882 * | create_lun_common -- create LU and start provisioning if needed 883 * | 884 * | This function is common to both the tape and disk emulation 885 * | code. 886 * []---- 887 */ 888 static Boolean_t 889 create_lun_common(char *targ_name, char *local_name, int lun, uint64_t size, 890 err_code_t *code) 891 { 892 struct stat s; 893 int fd = -1; 894 char path[MAXPATHLEN]; 895 char buf[512]; 896 struct statvfs fs; 897 tgt_node_t *node = NULL; 898 tgt_node_t *c; 899 900 /* 901 * Touch the last block of the file which will cause file systems 902 * to understand the intent of the file to be a certain size. The 903 * space isn't allocated, but the daemon can then mmap in this file 904 * and start writing to it. 905 */ 906 (void) snprintf(path, sizeof (path), "%s/%s/%s%d", 907 target_basedir, targ_name, LUNBASE, lun); 908 if ((fd = open(path, O_RDWR|O_CREAT|O_LARGEFILE, 0600)) < 0) 909 goto error; 910 911 (void) lseek(fd, size - 512LL, 0); 912 bzero(buf, sizeof (buf)); 913 if (write(fd, buf, sizeof (buf)) != sizeof (buf)) { 914 (void) unlink(path); 915 if (errno == EFBIG) 916 *code = ERR_FILE_TOO_BIG; 917 else 918 *code = ERR_FAILED_TO_CREATE_LU; 919 goto error; 920 } 921 (void) close(fd); 922 923 /* 924 * Set the fd back to -1 so that if an error occurs we don't 925 * attempt to close this device twice. This could be an issue 926 * if another thread opened a file right after we closed this 927 * one and the system reused the file descriptor. During an 928 * error we would then close another threads file which would 929 * be ugly, not to mention difficult to track down. 930 */ 931 fd = -1; 932 933 if (stat(path, &s) != 0) { 934 *code = ERR_FAILED_TO_CREATE_LU; 935 goto error; 936 } 937 938 /* 939 * If the backing store is a regular file and the default is 940 * used which initializes the file instead of sparse allocation 941 * go ahead a set things up. 942 */ 943 if ((thin_provisioning == False) && ((s.st_mode & S_IFMT) == S_IFREG)) { 944 thick_provo_t *tp; 945 pthread_t junk; 946 947 /* 948 * Attempt to see if there is enough space currently 949 * for the LU. The initialization might still fail 950 * with "out of space" because someone else is 951 * consuming space while the initialization is occuring. 952 * Nothing we can do about that. 953 */ 954 if (statvfs(path, &fs) != 0) { 955 queue_prt(mgmtq, Q_GEN_ERRS, 956 "GEN statvfs failed for %s", path); 957 *code = ERR_FAILED_TO_CREATE_LU; 958 goto error; 959 } else if ((fs.f_frsize * fs.f_bfree) < size) { 960 queue_prt(mgmtq, Q_STE_ERRS, 961 "GEN Not enough space for LU"); 962 *code = ERR_FILE_TOO_BIG; 963 goto error; 964 } 965 966 /* 967 * Run the initialization thread in the background so that 968 * the administrator doesn't have to wait which for UFS could 969 * be a long time on a large LU. 970 */ 971 if ((tp = calloc(1, sizeof (*tp))) != NULL) { 972 tp->targ_name = strdup(targ_name); 973 tp->lun = lun; 974 tp->q = queue_alloc(); 975 (void) pthread_create(&junk, NULL, 976 thick_provo_start, tp); 977 978 /* 979 * As soon as the thread starts it will send a simple 980 * ACK to it's own queue that we can look for. When 981 * we see this message we know that the thread has 982 * started and it's been added to the provisioning 983 * list. If this were not done it's possible for someone 984 * to create and delete a target within a script and 985 * have the delete run and fail to find the provision 986 * thread in the list. 987 */ 988 queue_message_free(queue_message_get(tp->q)); 989 } 990 } else { 991 (void) mgmt_get_param(&node, local_name, lun); 992 993 c = tgt_node_alloc(XML_ELEMENT_STATUS, String, 994 TGT_STATUS_ONLINE); 995 tgt_node_replace(node, c, MatchName); 996 tgt_node_free(c); 997 998 if (mgmt_param_save2scf(node, local_name, lun) == False) { 999 queue_prt(mgmtq, Q_STE_ERRS, 1000 "GEN%d failed to dump out params", lun); 1001 goto error; 1002 } 1003 iscsi_inventory_change(targ_name); 1004 tgt_node_free(node); 1005 } 1006 1007 return (True); 1008 1009 error: 1010 if (fd != -1) 1011 (void) close(fd); 1012 if (node) 1013 tgt_node_free(node); 1014 return (False); 1015 } 1016 1017 static Boolean_t 1018 readvtoc(int fd, struct extvtoc *v, int *slice) 1019 { 1020 if ((*slice = read_extvtoc(fd, v)) >= 0) 1021 return (True); 1022 else 1023 return (False); 1024 } 1025 1026 static Boolean_t 1027 readefi(int fd, struct dk_gpt **efi, int *slice) 1028 { 1029 if ((*slice = efi_alloc_and_read(fd, efi)) >= 0) 1030 return (True); 1031 else 1032 return (False); 1033 } 1034 1035 /* 1036 * []---- 1037 * | setup_alt_backing -- use backing store link for regular file lun 1038 * | 1039 * | If the size is zero, then the administrator MUST have 1040 * | specified a backing store to use. 1041 * | If the size is non-zero and the backing store doesn't exist it will 1042 * | be created. Also a tag will be added indicating that during removal 1043 * | the backing store should be deleted as well. 1044 * []---- 1045 */ 1046 static Boolean_t 1047 setup_disk_backing(err_code_t *code, char *path, char *backing, tgt_node_t *n, 1048 uint64_t *size) 1049 { 1050 struct stat s; 1051 char *raw_name, buf[512]; 1052 struct extvtoc extvtoc; 1053 struct dk_gpt *efi; 1054 int slice, fd; 1055 tgt_node_t *pn; 1056 1057 /* 1058 * Error checking regarding size and backing store has already 1059 * been done. If the backing store is null at this point everything 1060 * is okay so just return True. 1061 */ 1062 if (backing == NULL) 1063 return (True); 1064 1065 if (stat(backing, &s) == -1) { 1066 if (*size == 0) { 1067 *code = ERR_STAT_BACKING_FAILED; 1068 return (False); 1069 } else { 1070 pn = tgt_node_alloc(XML_ELEMENT_DELETE_BACK, String, 1071 "true"); 1072 tgt_node_add(n, pn); 1073 if ((fd = open(backing, O_RDWR|O_CREAT|O_LARGEFILE, 1074 0600)) < 0) { 1075 *code = ERR_FAILED_TO_CREATE_LU; 1076 return (False); 1077 } 1078 (void) lseek(fd, *size - 512LL, 0); 1079 bzero(buf, sizeof (buf)); 1080 (void) write(fd, buf, sizeof (buf)); 1081 (void) close(fd); 1082 } 1083 } else if (*size != 0) { 1084 *code = ERR_DISK_BACKING_SIZE_OR_FILE; 1085 return (False); 1086 } else if (((s.st_mode & S_IFMT) == S_IFCHR) || 1087 ((s.st_mode & S_IFMT) == S_IFBLK)) { 1088 raw_name = getfullrawname(backing); 1089 if ((raw_name == NULL) || 1090 ((fd = open(raw_name, O_NONBLOCK|O_RDONLY)) < 0)) { 1091 *code = ERR_DISK_BACKING_NOT_VALID_RAW; 1092 (void) close(fd); 1093 if (raw_name) 1094 free(raw_name); 1095 return (False); 1096 } 1097 free(raw_name); 1098 if (readvtoc(fd, &extvtoc, &slice) == True) { 1099 *size = extvtoc.v_part[slice].p_size * 512; 1100 1101 } else if (readefi(fd, &efi, &slice) == True) { 1102 *size = efi->efi_parts[slice].p_size * 512; 1103 efi_free(efi); 1104 } else { 1105 *code = ERR_DISK_BACKING_NOT_VALID_RAW; 1106 (void) close(fd); 1107 return (False); 1108 } 1109 (void) close(fd); 1110 1111 } else if ((s.st_mode & S_IFMT) == S_IFREG) { 1112 *size = s.st_size; 1113 } else { 1114 *code = ERR_DISK_BACKING_MUST_BE_REGULAR_FILE; 1115 return (False); 1116 } 1117 1118 if (symlink(backing, path)) { 1119 *code = ERR_CREATE_SYMLINK_FAILED; 1120 return (False); 1121 } 1122 1123 return (True); 1124 } 1125 1126 /* 1127 * []---- 1128 * | validate_raw_backing -- check that device is full partition 1129 * | 1130 * | The size of the device will be returned in rtn_size in bytes. 1131 * | 1132 * | Need to guarantee that the backing store for a raw device is: 1133 * | (a) character device 1134 * | (b) Not buffered 1135 * | Don't want this host to have data which is not flushed 1136 * | out during a write since a multiple path access to 1137 * | the backing store would be possible meaning we'd have 1138 * | cache issue. 1139 * | (c) read/write will access entire device. 1140 * | To speed things up we use asynchronous I/O which means 1141 * | the path has to have access to the entire device through 1142 * | the partition table. If not, some client will issue a 1143 * | READ_CAPACITY command, but not be able to access all of 1144 * | the data. 1145 * []---- 1146 */ 1147 static Boolean_t 1148 setup_raw_backing(err_code_t *code, char *path, char *backing, 1149 uint64_t *rtn_size) 1150 { 1151 struct stat s; 1152 char buf[512]; 1153 int fd; 1154 uint64_t size; 1155 struct uscsi_cmd u; 1156 struct scsi_extended_sense sense; 1157 union scsi_cdb cdb; 1158 struct scsi_capacity cap; 1159 struct scsi_capacity_16 cap16; 1160 int cap_len = sizeof (cap16); 1161 size_t cc; 1162 Boolean_t rval = False; 1163 1164 if (stat(backing, &s) == -1) { 1165 *code = ERR_ACCESS_RAW_DEVICE_FAILED; 1166 return (False); 1167 } else if (((s.st_mode & S_IFMT) != S_IFCHR) && 1168 ((s.st_mode & S_IFMT) != S_IFBLK)) { 1169 *code = ERR_DISK_BACKING_NOT_VALID_RAW; 1170 return (False); 1171 } 1172 1173 if ((backing == NULL) || 1174 ((fd = open(backing, O_NDELAY|O_RDONLY|O_LARGEFILE)) < 0)) { 1175 *code = ERR_DISK_BACKING_NOT_VALID_RAW; 1176 (void) close(fd); 1177 return (False); 1178 } 1179 1180 bzero(&u, sizeof (u)); 1181 bzero(&cdb, sizeof (cdb)); 1182 bzero(&cap, sizeof (cap)); 1183 bzero(&sense, sizeof (sense)); 1184 1185 cdb.scc_cmd = 0x25; /* ---- READ_CAPACITY(10) ---- */ 1186 1187 u.uscsi_cdb = (caddr_t)&cdb; 1188 u.uscsi_cdblen = CDB_GROUP1; 1189 u.uscsi_bufaddr = (caddr_t)∩ 1190 u.uscsi_buflen = sizeof (cap); 1191 u.uscsi_flags = USCSI_READ | USCSI_RQENABLE; 1192 u.uscsi_rqbuf = (char *)&sense; 1193 u.uscsi_rqlen = sizeof (sense); 1194 1195 if ((ioctl(fd, USCSICMD, &u) != 0) || (u.uscsi_status != 0)) { 1196 queue_prt(mgmtq, Q_GEN_DETAILS, "GEN0 uscsi(READ_CAP) failed"); 1197 *code = ERR_DISK_BACKING_NOT_VALID_RAW; 1198 rval = False; 1199 goto error; 1200 } 1201 1202 if (cap.capacity == 0xffffffff) { 1203 1204 bzero(&u, sizeof (u)); 1205 bzero(&cdb, sizeof (cdb)); 1206 bzero(&sense, sizeof (sense)); 1207 /* 1208 * The device is to large for the 10byte CDB. 1209 * Using the larger 16byte read capacity command 1210 */ 1211 cdb.scc_cmd = 0x9E; 1212 cdb.g4_reladdr = 0x10; 1213 cdb.g4_count3 = hibyte(hiword(cap_len)); 1214 cdb.g4_count2 = lobyte(hiword(cap_len)); 1215 cdb.g4_count1 = hibyte(loword(cap_len)); 1216 cdb.g4_count0 = lobyte(loword(cap_len)); 1217 1218 u.uscsi_cdb = (caddr_t)&cdb; 1219 u.uscsi_cdblen = CDB_GROUP4; 1220 u.uscsi_bufaddr = (caddr_t)&cap16; 1221 u.uscsi_buflen = sizeof (cap16); 1222 u.uscsi_flags = USCSI_READ | USCSI_RQENABLE; 1223 u.uscsi_rqbuf = (char *)&sense; 1224 u.uscsi_rqlen = sizeof (sense); 1225 1226 if ((ioctl(fd, USCSICMD, &u) != 0) || (u.uscsi_status != 0)) { 1227 queue_prt(mgmtq, Q_GEN_DETAILS, 1228 "GEN0 uscsi(READ_CAP16) failed"); 1229 *code = ERR_DISK_BACKING_NOT_VALID_RAW; 1230 rval = False; 1231 goto error; 1232 } 1233 1234 size = ntohll(cap16.sc_capacity) - 1; 1235 } else 1236 size = (uint64_t)ntohl(cap.capacity) - 1; 1237 1238 if ((cc = pread(fd, buf, sizeof (buf), size * 512LL)) != sizeof (buf)) { 1239 queue_prt(mgmtq, Q_GEN_DETAILS, 1240 "GEN0 Partition size != capacity(0x%llx), cc=%d, errno=%d", 1241 size, cc, errno); 1242 *code = ERR_RAW_PART_NOT_CAP; 1243 rval = False; 1244 goto error; 1245 } else { 1246 *rtn_size = size * 512LL; 1247 rval = True; 1248 } 1249 1250 error: 1251 (void) close(fd); 1252 return (rval); 1253 } 1254 1255 /* 1256 * get_zfs_shareiscsi -- given a dataset, get the ZFS properties 1257 * 1258 * This function is called when "set shareiscsi=on" calles into libiscsitgt, 1259 * such that the iSCSI Target can get the ZFS_PROP_ISCSIOPTIONS. This is in 1260 * lieu of properties being stored in SCF. 1261 */ 1262 int 1263 get_zfs_shareiscsi(char *dataset, tgt_node_t **n, uint64_t *size, ucred_t *cred) 1264 { 1265 libzfs_handle_t *zh; 1266 zfs_handle_t *zfsh; 1267 const priv_set_t *eset; 1268 tgt_node_t *c; 1269 char *prop = NULL; 1270 char *cp; /* current pair */ 1271 char *np; /* next pair */ 1272 char *vp; /* value pointer */ 1273 int status = ERR_SUCCESS; 1274 1275 if (((zh = libzfs_init()) == NULL) || 1276 ((zfsh = zfs_open(zh, dataset, ZFS_TYPE_DATASET)) == NULL)) { 1277 status = ERR_INTERNAL_ERROR; 1278 goto error; 1279 } 1280 1281 if (((eset = ucred_getprivset(cred, PRIV_EFFECTIVE)) != NULL) 1282 ? !priv_ismember(eset, PRIV_SYS_CONFIG) 1283 : ucred_geteuid(cred) != 0) { 1284 /* 1285 * See if user has ZFS dataset permissions to do operation 1286 */ 1287 if (zfs_iscsi_perm_check(zh, dataset, cred) != 0) { 1288 status = ERR_NO_PERMISSION; 1289 goto error; 1290 } 1291 } 1292 1293 /* 1294 * Get the current size of the volume, return to caller 1295 */ 1296 *size = zfs_prop_get_int(zfsh, ZFS_PROP_VOLSIZE); 1297 1298 /* 1299 * Allocate a local buffer to read the ZFS properties into 1300 */ 1301 if ((prop = malloc(ZFS_PROP_SIZE)) == NULL) { 1302 status = ERR_INTERNAL_ERROR; 1303 goto error; 1304 } 1305 1306 /* 1307 * Get the shareiscsi property 1308 */ 1309 *prop = '\0'; 1310 if (zfs_prop_get(zfsh, ZFS_PROP_SHAREISCSI, prop, ZFS_PROP_SIZE, NULL, 1311 NULL, 0, B_TRUE)) { 1312 status = ERR_INTERNAL_ERROR; 1313 goto error; 1314 } 1315 1316 /* 1317 * The options property is a string with name/value pairs separated 1318 * by comma characters. Stand alone values of 'on' and 'off' are 1319 * also permitted, but having the property set to off when share() 1320 * is called is an error. 1321 * Currently we only look for 'type=<value>' and ignore others. 1322 */ 1323 1324 for (cp = prop; cp; cp = np) { 1325 if (np = strchr(cp, ',')) 1326 *np++ = '\0'; 1327 if (strcmp(cp, "on") == 0) { 1328 cp = np; 1329 continue; 1330 } 1331 if (strcmp(cp, "off") == 0) { 1332 status = ERR_ZFS_ISCSISHARE_OFF; 1333 goto error; 1334 } 1335 if (vp = strchr(cp, '=')) 1336 *vp++ = '\0'; 1337 /* 1338 * Only support 'disk' emulation at this point. 1339 */ 1340 if ((strcmp(cp, "type") == 0) && (strcmp(vp, "disk") != 0)) { 1341 status = ERR_INTERNAL_ERROR; 1342 goto error; 1343 } 1344 } 1345 1346 /* 1347 * Now get the ZFS persisted shareiscsi options 1348 */ 1349 *prop = '\0'; 1350 if (zfs_prop_get(zfsh, ZFS_PROP_ISCSIOPTIONS, prop, ZFS_PROP_SIZE, NULL, 1351 NULL, 0, B_TRUE) && (status != ERR_ZFS_ISCSISHARE_OFF)) { 1352 status = ERR_INTERNAL_ERROR; 1353 goto error; 1354 } 1355 1356 /* 1357 * Now move the ZFS persisted shareiscsi options into XML, then into 1358 * iSCSI Target properties 1359 */ 1360 if (strlen(prop)) { 1361 xmlTextReaderPtr xml_ptr = (xmlTextReaderPtr)xmlReaderForMemory( 1362 prop, strlen(prop), NULL, NULL, 0); 1363 1364 if (xml_ptr != NULL) { 1365 *n = NULL; 1366 while (xmlTextReaderRead(xml_ptr)) { 1367 if (tgt_node_process(xml_ptr, n) == False) { 1368 break; 1369 } 1370 } 1371 1372 /* Cleanup XML data */ 1373 (void) xmlTextReaderClose(xml_ptr); 1374 xmlFreeTextReader(xml_ptr); 1375 xmlCleanupParser(); 1376 1377 /* Assure these XML elements are tagged as in-core */ 1378 if (tgt_find_attr_str(*n, XML_ELEMENT_INCORE, &cp) 1379 == False) { 1380 c = tgt_node_alloc(XML_ELEMENT_INCORE, String, 1381 XML_VALUE_TRUE); 1382 tgt_node_add_attr(*n, c); 1383 } else { 1384 free(cp); 1385 } 1386 1387 } else { 1388 status = ERR_NULL_XML_MESSAGE; 1389 } 1390 } else { 1391 status = ERR_NULL_XML_MESSAGE; 1392 } 1393 1394 error: 1395 if (prop) 1396 free(prop); 1397 if (zh) { 1398 if (zfsh) 1399 zfs_close(zfsh); 1400 libzfs_fini(zh); 1401 } 1402 return (status); 1403 } 1404 1405 /* 1406 * put_zfs_shareiscsi -- given a dataset, put the ZFS properties 1407 * 1408 * This function is called whenever persistence is needed to the set of 1409 * iSCSI Target properties stored in ZFS_PROP_ISCSIOPTIONS. This is in lieu 1410 * of properties being stored in SCF. 1411 */ 1412 int 1413 put_zfs_shareiscsi(char *dataset, tgt_node_t *n) 1414 { 1415 libzfs_handle_t *zh; 1416 zfs_handle_t *zfsh; 1417 char *prop = NULL; 1418 int status; 1419 1420 if (((zh = libzfs_init()) == NULL) || 1421 ((zfsh = zfs_open(zh, dataset, ZFS_TYPE_DATASET)) == NULL)) { 1422 status = ERR_INTERNAL_ERROR; 1423 goto error; 1424 } 1425 1426 /* 1427 * Now store this information on the ZVOL property so that 1428 * next time we get a shareiscsi request the same data will be 1429 * used. 1430 */ 1431 tgt_dump2buf(n, &prop); 1432 if (zfs_prop_set(zfsh, zfs_prop_to_name(ZFS_PROP_ISCSIOPTIONS), prop)) { 1433 status = ERR_INTERNAL_ERROR; 1434 } else { 1435 status = ERR_SUCCESS; 1436 } 1437 1438 error: 1439 if (prop) 1440 free(prop); 1441 if (zh) { 1442 if (zfsh) 1443 zfs_close(zfsh); 1444 libzfs_fini(zh); 1445 } 1446 return (status); 1447 } 1448