/*
* Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <inttypes.h>
#include <stdint.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <poll.h>
#include <pthread.h>
#ifdef HAVE_PTHREAD_NP_H
#include <pthread_np.h>
#endif
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "istgt.h"
#include "istgt_ver.h"
#include "istgt_log.h"
#include "istgt_conf.h"
#include "istgt_sock.h"
#include "istgt_misc.h"
#include "istgt_crc32c.h"
#include "istgt_iscsi.h"
#include "istgt_lu.h"
#include "istgt_proto.h"
#ifdef ISTGT_USE_KQUEUE
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
#endif
#if !defined(__GNUC__)
#undef __attribute__
#define __attribute__(x)
#endif
#define POLLWAIT 5000
#define PORTNUMLEN 32
ISTGT g_istgt;
static int
istgt_parse_portal(const char *portal, char **host, char **port)
{
const char *p;
int n;
if (portal == NULL) {
ISTGT_ERRLOG("portal error\n");
return -1;
}
if (portal[0] == '[') {
/* IPv6 */
p = strchr(portal + 1, ']');
if (p == NULL) {
ISTGT_ERRLOG("portal error\n");
return -1;
}
p++;
n = p - portal;
if (host != NULL) {
*host = xmalloc(n + 1);
memcpy(*host, portal, n);
(*host)[n] = '\0';
}
if (p[0] == '\0') {
if (port != NULL) {
*port = xmalloc(PORTNUMLEN);
snprintf(*port, PORTNUMLEN, "%d", DEFAULT_PORT);
}
} else {
if (p[0] != ':') {
ISTGT_ERRLOG("portal error\n");
if (host != NULL)
xfree(*host);
return -1;
}
if (port != NULL)
*port = xstrdup(p + 1);
}
} else {
/* IPv4 */
p = strchr(portal, ':');
if (p == NULL) {
p = portal + strlen(portal);
}
n = p - portal;
if (host != NULL) {
*host = xmalloc(n + 1);
memcpy(*host, portal, n);
(*host)[n] = '\0';
}
if (p[0] == '\0') {
if (port != NULL) {
*port = xmalloc(PORTNUMLEN);
snprintf(*port, PORTNUMLEN, "%d", DEFAULT_PORT);
}
} else {
if (p[0] != ':') {
ISTGT_ERRLOG("portal error\n");
if (host != NULL)
xfree(*host);
return -1;
}
if (port != NULL)
*port = xstrdup(p + 1);
}
}
return 0;
}
static int
istgt_add_portal_group(ISTGT_Ptr istgt, CF_SECTION *sp, int *pgp_idx)
{
const char *val;
char *label, *portal, *host, *port;
int alloc_len;
int idx, free_idx;
int portals;
int rc;
int i;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "add portal group %d\n", sp->num);
val = istgt_get_val(sp, "Comment");
if (val != NULL) {
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Comment %s\n", val);
}
/* counts number of definition */
for (i = 0; ; i++) {
label = istgt_get_nmval(sp, "Portal", i, 0);
portal = istgt_get_nmval(sp, "Portal", i, 1);
if (label == NULL || portal == NULL)
break;
rc = istgt_parse_portal(portal, NULL, NULL);
if (rc < 0) {
ISTGT_ERRLOG("parse portal error (%s)\n", portal);
return -1;
}
}
portals = i;
if (portals > MAX_PORTAL) {
ISTGT_ERRLOG("%d > MAX_PORTAL\n", portals);
return -1;
}
MTX_LOCK(&istgt->mutex);
idx = istgt->nportal_group;
free_idx = -1;
for (i = 0; i < istgt->nportal_group; i++) {
if (istgt->portal_group[i].tag != 0)
continue;
if (istgt->portal_group[i].nportals == portals) {
free_idx = i;
break;
}
}
if (free_idx >= 0)
idx = free_idx;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
"Index=%d, Tag=%d, Portals=%d\n",
idx, sp->num, portals);
if (idx < MAX_PORTAL_GROUP) {
if (free_idx < 0) {
istgt->portal_group[idx].nportals = portals;
alloc_len = sizeof (PORTAL *) * portals;
istgt->portal_group[idx].portals = xmalloc(alloc_len);
}
istgt->portal_group[idx].ref = 0;
istgt->portal_group[idx].idx = idx;
istgt->portal_group[idx].tag = sp->num;
for (i = 0; i < portals; i++) {
label = istgt_get_nmval(sp, "Portal", i, 0);
portal = istgt_get_nmval(sp, "Portal", i, 1);
if (label == NULL || portal == NULL) {
if (free_idx < 0) {
xfree(istgt->portal_group[idx].portals);
istgt->portal_group[idx].nportals = 0;
}
istgt->portal_group[idx].tag = 0;
MTX_UNLOCK(&istgt->mutex);
ISTGT_ERRLOG("portal error\n");
return -1;
}
rc = istgt_parse_portal(portal, &host, &port);
if (rc < 0) {
if (free_idx < 0) {
xfree(istgt->portal_group[idx].portals);
istgt->portal_group[idx].nportals = 0;
}
istgt->portal_group[idx].tag = 0;
MTX_UNLOCK(&istgt->mutex);
ISTGT_ERRLOG("parse portal error (%s)\n", portal);
return -1;
}
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
"RIndex=%d, Host=%s, Port=%s, Tag=%d\n",
i, host, port, sp->num);
if (free_idx < 0) {
istgt->portal_group[idx].portals[i] = xmalloc(sizeof (PORTAL));
} else {
xfree(istgt->portal_group[idx].portals[i]->label);
xfree(istgt->portal_group[idx].portals[i]->host);
xfree(istgt->portal_group[idx].portals[i]->port);
}
istgt->portal_group[idx].portals[i]->label = xstrdup(label);
istgt->portal_group[idx].portals[i]->host = host;
istgt->portal_group[idx].portals[i]->port = port;
istgt->portal_group[idx].portals[i]->ref = 0;
istgt->portal_group[idx].portals[i]->idx = i;
istgt->portal_group[idx].portals[i]->tag = sp->num;
istgt->portal_group[idx].portals[i]->sock = -1;
}
if (pgp_idx != NULL)
*pgp_idx = idx;
if (free_idx < 0) {
idx++;
istgt->nportal_group = idx;
}
} else {
MTX_UNLOCK(&istgt->mutex);
ISTGT_ERRLOG("nportal_group(%d) >= MAX_PORTAL_GROUP\n", idx);
return -1;
}
MTX_UNLOCK(&istgt->mutex);
return 0;
}
static int
istgt_pg_match_all(PORTAL_GROUP *pgp, CF_SECTION *sp)
{
char *label, *portal, *host, *port;
int rc;
int i;
for (i = 0; i < pgp->nportals; i++) {
label = istgt_get_nmval(sp, "Portal", i, 0);
portal = istgt_get_nmval(sp, "Portal", i, 1);
if (label == NULL || portal == NULL)
return 0;
rc = istgt_parse_portal(portal, &host, &port);
if (rc < 0)
return 0;
if (strcmp(pgp->portals[i]->label, label) != 0)
return 0;
if (strcmp(pgp->portals[i]->host, host) != 0)
return 0;
if (strcmp(pgp->portals[i]->port, port) != 0)
return 0;
}
label = istgt_get_nmval(sp, "Portal", i, 0);
portal = istgt_get_nmval(sp, "Portal", i, 1);
if (label != NULL || portal != NULL)
return 0;
return 1;
}
static int
istgt_update_portal_group(ISTGT_Ptr istgt, CF_SECTION *sp, int *pgp_idx)
{
const char *val;
char *label, *portal, *host, *port;
int alloc_len;
int idx, free_idx;
int portals;
int rc;
int i;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "update portal group %d\n", sp->num);
val = istgt_get_val(sp, "Comment");
if (val != NULL) {
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Comment %s\n", val);
}
/* counts number of definition */
for (i = 0; ; i++) {
label = istgt_get_nmval(sp, "Portal", i, 0);
portal = istgt_get_nmval(sp, "Portal", i, 1);
if (label == NULL || portal == NULL)
break;
rc = istgt_parse_portal(portal, NULL, NULL);
if (rc < 0) {
ISTGT_ERRLOG("parse portal error (%s)\n", portal);
return -1;
}
}
portals = i;
if (portals > MAX_PORTAL) {
ISTGT_ERRLOG("%d > MAX_PORTAL\n", portals);
return -1;
}
MTX_LOCK(&istgt->mutex);
idx = -1;
for (i = 0; i < istgt->nportal_group; i++) {
if (istgt->portal_group[i].tag == sp->num) {
idx = i;
break;
}
}
if (idx < 0) {
MTX_UNLOCK(&istgt->mutex);
ISTGT_ERRLOG("can't find PG%d\n", sp->num);
return -1;
}
if (istgt_pg_match_all(&istgt->portal_group[i], sp)) {
MTX_UNLOCK(&istgt->mutex);
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "skip for PG%d\n", sp->num);
return 0;
}
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
"Index=%d, Tag=%d, Portals=%d\n",
idx, sp->num, portals);
if (istgt->portal_group[idx].nportals == portals) {
/* udpate PG */
for (i = 0; i < portals; i++) {
label = istgt_get_nmval(sp, "Portal", i, 0);
portal = istgt_get_nmval(sp, "Portal", i, 1);
if (label == NULL || portal == NULL) {
xfree(istgt->portal_group[idx].portals);
istgt->portal_group[idx].nportals = 0;
istgt->portal_group[idx].tag = 0;
MTX_UNLOCK(&istgt->mutex);
ISTGT_ERRLOG("portal error\n");
return -1;
}
rc = istgt_parse_portal(portal, &host, &port);
if (rc < 0) {
xfree(istgt->portal_group[idx].portals);
istgt->portal_group[idx].nportals = 0;
istgt->portal_group[idx].tag = 0;
MTX_UNLOCK(&istgt->mutex);
ISTGT_ERRLOG("parse portal error (%s)\n", portal);
return -1;
}
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
"RIndex=%d, Host=%s, Port=%s, Tag=%d\n",
i, host, port, sp->num);
/* free old PG */
xfree(istgt->portal_group[idx].portals[i]->label);
xfree(istgt->portal_group[idx].portals[i]->host);
xfree(istgt->portal_group[idx].portals[i]->port);
/* allocate new PG */
istgt->portal_group[idx].portals[i]->label = xstrdup(label);
istgt->portal_group[idx].portals[i]->host = host;
istgt->portal_group[idx].portals[i]->port = port;
//istgt->portal_group[idx].portals[i]->ref = 0;
//istgt->portal_group[idx].portals[i]->idx = i;
//istgt->portal_group[idx].portals[i]->tag = sp->num;
//istgt->portal_group[idx].portals[i]->sock = -1;
}
if (pgp_idx != NULL)
*pgp_idx = idx;
} else {
/* mark as free */
istgt->portal_group[*pgp_idx].tag = 0;
/* allocate new PG */
idx = istgt->nportal_group;
free_idx = -1;
for (i = 0; i < istgt->nportal_group; i++) {
if (istgt->portal_group[i].tag != 0)
continue;
if (istgt->portal_group[i].nportals == portals) {
free_idx = i;
break;
}
}
if (free_idx >= 0)
idx = free_idx;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
"Index=%d, Tag=%d, Portals=%d -> %d\n",
idx, sp->num, istgt->portal_group[*pgp_idx].nportals, portals);
if (idx < MAX_PORTAL_GROUP) {
if (free_idx < 0) {
istgt->portal_group[idx].nportals = portals;
alloc_len = sizeof (PORTAL *) * portals;
istgt->portal_group[idx].portals = xmalloc(alloc_len);
}
istgt->portal_group[idx].ref = istgt->portal_group[*pgp_idx].ref;
istgt->portal_group[idx].idx = idx;
istgt->portal_group[idx].tag = sp->num;
for (i = 0; i < portals; i++) {
label = istgt_get_nmval(sp, "Portal", i, 0);
portal = istgt_get_nmval(sp, "Portal", i, 1);
if (label == NULL || portal == NULL) {
if (free_idx < 0) {
xfree(istgt->portal_group[idx].portals);
istgt->portal_group[idx].nportals = 0;
}
istgt->portal_group[idx].tag = 0;
MTX_UNLOCK(&istgt->mutex);
ISTGT_ERRLOG("portal error\n");
return -1;
}
rc = istgt_parse_portal(portal, &host, &port);
if (rc < 0) {
if (free_idx < 0) {
xfree(istgt->portal_group[idx].portals);
istgt->portal_group[idx].nportals = 0;
}
istgt->portal_group[idx].tag = 0;
MTX_UNLOCK(&istgt->mutex);
ISTGT_ERRLOG("parse portal error (%s)\n", portal);
return -1;
}
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
"RIndex=%d, Host=%s, Port=%s, Tag=%d\n",
i, host, port, sp->num);
if (free_idx < 0) {
istgt->portal_group[idx].portals[i] = xmalloc(sizeof (PORTAL));
} else {
xfree(istgt->portal_group[idx].portals[i]->label);
xfree(istgt->portal_group[idx].portals[i]->host);
xfree(istgt->portal_group[idx].portals[i]->port);
}
istgt->portal_group[idx].portals[i]->label = xstrdup(label);
istgt->portal_group[idx].portals[i]->host = host;
istgt->portal_group[idx].portals[i]->port = port;
istgt->portal_group[idx].portals[i]->ref = 0;
istgt->portal_group[idx].portals[i]->idx = i;
istgt->portal_group[idx].portals[i]->tag = sp->num;
istgt->portal_group[idx].portals[i]->sock = -1;
}
if (pgp_idx != NULL)
*pgp_idx = idx;
if (free_idx < 0) {
idx++;
istgt->nportal_group = idx;
}
} else {
MTX_UNLOCK(&istgt->mutex);
ISTGT_ERRLOG("nportal_group(%d) >= MAX_PORTAL_GROUP\n", idx);
return -1;
}
}
MTX_UNLOCK(&istgt->mutex);
return 1;
}
static int
istgt_build_portal_group_array(ISTGT_Ptr istgt)
{
CF_SECTION *sp;
int rc;
sp = istgt->config->section;
while (sp != NULL) {
if (sp->type == ST_PORTALGROUP) {
if (sp->num == 0) {
ISTGT_ERRLOG("Group 0 is invalid\n");
return -1;
}
rc = istgt_add_portal_group(istgt, sp, NULL);
if (rc < 0) {
ISTGT_ERRLOG("add_portal_group() failed\n");
return -1;
}
}
sp = sp->next;
}
return 0;
}
static void
istgt_destroy_portal_group_array(ISTGT_Ptr istgt)
{
int i, j;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_destory_portal_group_array\n");
MTX_LOCK(&istgt->mutex);
for (i = 0; i < istgt->nportal_group; i++) {
for (j = 0; j < istgt->portal_group[i].nportals; j++) {
xfree(istgt->portal_group[i].portals[j]->label);
xfree(istgt->portal_group[i].portals[j]->host);
xfree(istgt->portal_group[i].portals[j]->port);
xfree(istgt->portal_group[i].portals[j]);
}
xfree(istgt->portal_group[i].portals);
istgt->portal_group[i].nportals = 0;
istgt->portal_group[i].portals = NULL;
istgt->portal_group[i].ref = 0;
istgt->portal_group[i].idx = i;
istgt->portal_group[i].tag = 0;
}
istgt->nportal_group = 0;
MTX_UNLOCK(&istgt->mutex);
}
static int
istgt_open_portal_group(PORTAL_GROUP *pgp)
{
int port;
int sock;
int i;
for (i = 0; i < pgp->nportals; i++) {
if (pgp->portals[i]->sock < 0) {
ISTGT_TRACELOG(ISTGT_TRACE_NET, "open host %s, port %s, tag %d\n",
pgp->portals[i]->host, pgp->portals[i]->port,
pgp->portals[i]->tag);
port = (int)strtol(pgp->portals[i]->port, NULL, 0);
sock = istgt_listen(pgp->portals[i]->host, port);
if (sock < 0) {
ISTGT_ERRLOG("listen error %.64s:%d\n",
pgp->portals[i]->host, port);
return -1;
}
pgp->portals[i]->sock = sock;
}
}
return 0;
}
static int
istgt_open_all_portals(ISTGT_Ptr istgt)
{
int rc;
int i;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_open_portal\n");
MTX_LOCK(&istgt->mutex);
for (i = 0; i < istgt->nportal_group; i++) {
rc = istgt_open_portal_group(&istgt->portal_group[i]);
if (rc < 0) {
MTX_UNLOCK(&istgt->mutex);
return -1;
}
}
MTX_UNLOCK(&istgt->mutex);
return 0;
}
static int
istgt_close_portal_group(PORTAL_GROUP *pgp)
{
int i;
for (i = 0; i < pgp->nportals; i++) {
if (pgp->portals[i]->sock >= 0) {
ISTGT_TRACELOG(ISTGT_TRACE_NET, "close host %s, port %s, tag %d\n",
pgp->portals[i]->host, pgp->portals[i]->port,
pgp->portals[i]->tag);
close(pgp->portals[i]->sock);
pgp->portals[i]->sock = -1;
}
}
return 0;
}
static int
istgt_close_all_portals(ISTGT_Ptr istgt)
{
int rc;
int i;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_close_portal\n");
MTX_LOCK(&istgt->mutex);
for (i = 0; i < istgt->nportal_group; i++) {
rc = istgt_close_portal_group(&istgt->portal_group[i]);
if (rc < 0) {
MTX_UNLOCK(&istgt->mutex);
return -1;
}
}
MTX_UNLOCK(&istgt->mutex);
return 0;
}
static int
istgt_add_initiator_group(ISTGT_Ptr istgt, CF_SECTION *sp)
{
const char *val;
int alloc_len;
int idx;
int names;
int masks;
int i;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "add initiator group %d\n", sp->num);
val = istgt_get_val(sp, "Comment");
if (val != NULL) {
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Comment %s\n", val);
}
/* counts number of definition */
for (i = 0; ; i++) {
val = istgt_get_nval(sp, "InitiatorName", i);
if (val == NULL)
break;
}
names = i;
if (names > MAX_INITIATOR) {
ISTGT_ERRLOG("%d > MAX_INITIATOR\n", names);
return -1;
}
for (i = 0; ; i++) {
val = istgt_get_nval(sp, "Netmask", i);
if (val == NULL)
break;
}
masks = i;
if (masks > MAX_NETMASK) {
ISTGT_ERRLOG("%d > MAX_NETMASK\n", masks);
return -1;
}
MTX_LOCK(&istgt->mutex);
idx = istgt->ninitiator_group;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
"Index=%d, Tag=%d, Names=%d, Masks=%d\n",
idx, sp->num, names, masks);
if (idx < MAX_INITIATOR_GROUP) {
istgt->initiator_group[idx].ninitiators = names;
alloc_len = sizeof (char *) * names;
istgt->initiator_group[idx].initiators = xmalloc(alloc_len);
istgt->initiator_group[idx].nnetmasks = masks;
alloc_len = sizeof (char *) * masks;
istgt->initiator_group[idx].netmasks = xmalloc(alloc_len);
istgt->initiator_group[idx].ref = 0;
istgt->initiator_group[idx].idx = idx;
istgt->initiator_group[idx].tag = sp->num;
for (i = 0; i < names; i++) {
val = istgt_get_nval(sp, "InitiatorName", i);
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
"InitiatorName %s\n", val);
istgt->initiator_group[idx].initiators[i] = xstrdup(val);
}
for (i = 0; i < masks; i++) {
val = istgt_get_nval(sp, "Netmask", i);
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Netmask %s\n", val);
istgt->initiator_group[idx].netmasks[i] = xstrdup(val);
}
idx++;
istgt->ninitiator_group = idx;
} else {
MTX_UNLOCK(&istgt->mutex);
ISTGT_ERRLOG("ninitiator_group(%d) >= MAX_INITIATOR_GROUP\n", idx);
return -1;
}
MTX_UNLOCK(&istgt->mutex);
return 0;
}
static int
istgt_ig_match_all(INITIATOR_GROUP *igp, CF_SECTION *sp)
{
const char *val;
int i;
for (i = 0; i < igp->ninitiators; i++) {
val = istgt_get_nval(sp, "InitiatorName", i);
if (val == NULL)
return 0;
if (strcmp(igp->initiators[i], val) != 0)
return 0;
}
val = istgt_get_nval(sp, "InitiatorName", i);
if (val != NULL)
return 0;
for (i = 0; i < igp->nnetmasks; i++) {
val = istgt_get_nval(sp, "Netmask", i);
if (val == NULL)
return 0;
if (strcmp(igp->netmasks[i], val) != 0)
return 0;
}
val = istgt_get_nval(sp, "Netmask", i);
if (val != NULL)
return 0;
return 1;
}
static int
istgt_update_initiator_group(ISTGT_Ptr istgt, CF_SECTION *sp)
{
const char *val;
int alloc_len;
int idx;
int names;
int masks;
int i;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "update initiator group %d\n", sp->num);
val = istgt_get_val(sp, "Comment");
if (val != NULL) {
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Comment %s\n", val);
}
/* counts number of definition */
for (i = 0; ; i++) {
val = istgt_get_nval(sp, "InitiatorName", i);
if (val == NULL)
break;
}
names = i;
if (names > MAX_INITIATOR) {
ISTGT_ERRLOG("%d > MAX_INITIATOR\n", names);
return -1;
}
for (i = 0; ; i++) {
val = istgt_get_nval(sp, "Netmask", i);
if (val == NULL)
break;
}
masks = i;
if (masks > MAX_NETMASK) {
ISTGT_ERRLOG("%d > MAX_NETMASK\n", masks);
return -1;
}
MTX_LOCK(&istgt->mutex);
idx = -1;
for (i = 0; i < istgt->ninitiator_group; i++) {
if (istgt->initiator_group[i].tag == sp->num) {
idx = i;
break;
}
}
if (idx < 0) {
MTX_UNLOCK(&istgt->mutex);
ISTGT_ERRLOG("can't find IG%d\n", sp->num);
return -1;
}
if (istgt_ig_match_all(&istgt->initiator_group[i], sp)) {
MTX_UNLOCK(&istgt->mutex);
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "skip for IG%d\n", sp->num);
return 0;
}
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
"Index=%d, Tag=%d, Names=%d, Masks=%d\n",
idx, sp->num, names, masks);
/* free old IG */
for (i = 0; i < istgt->initiator_group[idx].ninitiators; i++) {
xfree(istgt->initiator_group[idx].initiators[i]);
}
xfree(istgt->initiator_group[idx].initiators);
for (i = 0; i < istgt->initiator_group[idx].nnetmasks; i++) {
xfree(istgt->initiator_group[idx].netmasks[i]);
}
xfree(istgt->initiator_group[idx].netmasks);
/* allocate new IG */
istgt->initiator_group[idx].ninitiators = names;
alloc_len = sizeof (char *) * names;
istgt->initiator_group[idx].initiators = xmalloc(alloc_len);
istgt->initiator_group[idx].nnetmasks = masks;
alloc_len = sizeof (char *) * masks;
istgt->initiator_group[idx].netmasks = xmalloc(alloc_len);
//istgt->initiator_group[idx].ref = 0;
//istgt->initiator_group[idx].idx = idx;
//istgt->initiator_group[idx].tag = sp->num;
/* copy new strings */
for (i = 0; i < names; i++) {
val = istgt_get_nval(sp, "InitiatorName", i);
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
"InitiatorName %s\n", val);
istgt->initiator_group[idx].initiators[i] = xstrdup(val);
}
for (i = 0; i < masks; i++) {
val = istgt_get_nval(sp, "Netmask", i);
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Netmask %s\n", val);
istgt->initiator_group[idx].netmasks[i] = xstrdup(val);
}
MTX_UNLOCK(&istgt->mutex);
return 1;
}
static int
istgt_build_initiator_group_array(ISTGT_Ptr istgt)
{
CF_SECTION *sp;
int rc;
sp = istgt->config->section;
while (sp != NULL) {
if (sp->type == ST_INITIATORGROUP) {
if (sp->num == 0) {
ISTGT_ERRLOG("Group 0 is invalid\n");
return -1;
}
rc = istgt_add_initiator_group(istgt, sp);
if (rc < 0) {
ISTGT_ERRLOG("add_initiator_group() failed\n");
return -1;
}
}
sp = sp->next;
}
return 0;
}
static void
istgt_destory_initiator_group_array(ISTGT_Ptr istgt)
{
int i, j;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_destory_initiator_group_array\n");
MTX_LOCK(&istgt->mutex);
for (i = 0; i < istgt->ninitiator_group; i++) {
for (j = 0; j < istgt->initiator_group[i].ninitiators; j++) {
xfree(istgt->initiator_group[i].initiators[j]);
}
xfree(istgt->initiator_group[i].initiators);
for (j = 0; j < istgt->initiator_group[i].nnetmasks; j++) {
xfree(istgt->initiator_group[i].netmasks[j]);
}
xfree(istgt->initiator_group[i].netmasks);
istgt->initiator_group[i].ninitiators = 0;
istgt->initiator_group[i].initiators = NULL;
istgt->initiator_group[i].nnetmasks = 0;
istgt->initiator_group[i].netmasks = NULL;
istgt->initiator_group[i].ref = 0;
istgt->initiator_group[i].idx = i;
istgt->initiator_group[i].tag = 0;
}
istgt->ninitiator_group = 0;
MTX_UNLOCK(&istgt->mutex);
}
static int
istgt_build_uctl_portal(ISTGT_Ptr istgt)
{
CF_SECTION *sp;
const char *val;
char *label, *portal, *host, *port;
int tag;
int idx;
int rc;
int i;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_build_uctl_portal\n");
sp = istgt_find_cf_section(istgt->config, "UnitControl");
if (sp == NULL) {
ISTGT_ERRLOG("find_cf_section failed()\n");
return -1;
}
for (i = 0; ; i++) {
val = istgt_get_nval(sp, "Portal", i);
if (val == NULL)
break;
label = istgt_get_nmval(sp, "Portal", i, 0);
portal = istgt_get_nmval(sp, "Portal", i, 1);
if (label == NULL || portal == NULL) {
ISTGT_ERRLOG("uctl portal error\n");
return -1;
}
rc = istgt_parse_portal(portal, &host, &port);
if (rc < 0) {
ISTGT_ERRLOG("parse uctl portal error\n");
return -1;
}
idx = istgt->nuctl_portal;
tag = ISTGT_UC_TAG;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
"Index=%d, Host=%s, Port=%s, Tag=%d\n",
idx, host, port, tag);
if (idx < MAX_UCPORTAL) {
istgt->uctl_portal[idx].label = xstrdup(label);
istgt->uctl_portal[idx].host = host;
istgt->uctl_portal[idx].port = port;
istgt->uctl_portal[idx].ref = 0;
istgt->uctl_portal[idx].idx = idx;
istgt->uctl_portal[idx].tag = tag;
istgt->uctl_portal[idx].sock = -1;
idx++;
istgt->nuctl_portal = idx;
} else {
ISTGT_ERRLOG("nportal(%d) >= MAX_UCPORTAL\n", idx);
xfree(host);
xfree(port);
return -1;
}
}
return 0;
}
static void
istgt_destroy_uctl_portal(ISTGT_Ptr istgt)
{
int i;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_destroy_uctl_portal\n");
for (i = 0; i < istgt->nuctl_portal; i++) {
xfree(istgt->uctl_portal[i].label);
xfree(istgt->uctl_portal[i].host);
xfree(istgt->uctl_portal[i].port);
istgt->uctl_portal[i].label = NULL;
istgt->uctl_portal[i].host = NULL;
istgt->uctl_portal[i].port = NULL;
istgt->uctl_portal[i].ref = 0;
istgt->uctl_portal[i].idx = i;
istgt->uctl_portal[i].tag = 0;
}
istgt->nuctl_portal = 0;
}
static int
istgt_open_uctl_portal(ISTGT_Ptr istgt)
{
int port;
int sock;
int i;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_open_uctl_portal\n");
for (i = 0; i < istgt->nuctl_portal; i++) {
if (istgt->uctl_portal[i].sock < 0) {
ISTGT_TRACELOG(ISTGT_TRACE_NET,
"open host %s, port %s, tag %d\n",
istgt->uctl_portal[i].host,
istgt->uctl_portal[i].port,
istgt->uctl_portal[i].tag);
port = (int)strtol(istgt->uctl_portal[i].port, NULL, 0);
sock = istgt_listen(istgt->uctl_portal[i].host, port);
if (sock < 0) {
ISTGT_ERRLOG("listen error %.64s:%d\n",
istgt->uctl_portal[i].host, port);
return -1;
}
istgt->uctl_portal[i].sock = sock;
}
}
return 0;
}
static int
istgt_close_uctl_portal(ISTGT_Ptr istgt)
{
int i;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_close_uctl_portal\n");
for (i = 0; i < istgt->nuctl_portal; i++) {
if (istgt->uctl_portal[i].sock >= 0) {
ISTGT_TRACELOG(ISTGT_TRACE_NET,
"close host %s, port %s, tag %d\n",
istgt->uctl_portal[i].host,
istgt->uctl_portal[i].port,
istgt->uctl_portal[i].tag);
close(istgt->uctl_portal[i].sock);
istgt->uctl_portal[i].sock = -1;
}
}
return 0;
}
static int
istgt_write_pidfile(ISTGT_Ptr istgt)
{
FILE *fp;
pid_t pid;
int rc;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_write_pidfile\n");
rc = remove(istgt->pidfile);
if (rc != 0) {
if (errno != ENOENT) {
ISTGT_ERRLOG("pidfile remove error %d\n", errno);
return -1;
}
}
fp = fopen(istgt->pidfile, "w");
if (fp == NULL) {
ISTGT_ERRLOG("pidfile open error %d\n", errno);
return -1;
}
pid = getpid();
fprintf(fp, "%d\n", (int)pid);
fclose(fp);
return 0;
}
static void
istgt_remove_pidfile(ISTGT_Ptr istgt)
{
int rc;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_remove_pidfile\n");
rc = remove(istgt->pidfile);
if (rc != 0) {
ISTGT_ERRLOG("pidfile remove error %d\n", errno);
/* ignore error */
}
}
char *
istgt_get_nmval(CF_SECTION *sp, const char *key, int idx1, int idx2)
{
CF_ITEM *ip;
CF_VALUE *vp;
int i;
ip = istgt_find_cf_nitem(sp, key, idx1);
if (ip == NULL)
return NULL;
vp = ip->val;
if (vp == NULL)
return NULL;
for (i = 0; vp != NULL; vp = vp->next) {
if (i == idx2)
return vp->value;
i++;
}
return NULL;
}
char *
istgt_get_nval(CF_SECTION *sp, const char *key, int idx)
{
CF_ITEM *ip;
CF_VALUE *vp;
ip = istgt_find_cf_nitem(sp, key, idx);
if (ip == NULL)
return NULL;
vp = ip->val;
if (vp == NULL)
return NULL;
return vp->value;
}
char *
istgt_get_val(CF_SECTION *sp, const char *key)
{
return istgt_get_nval(sp, key, 0);
}
int
istgt_get_nintval(CF_SECTION *sp, const char *key, int idx)
{
const char *v;
int value;
v = istgt_get_nval(sp, key, idx);
if (v == NULL)
return -1;
value = (int)strtol(v, NULL, 10);
return value;
}
int
istgt_get_intval(CF_SECTION *sp, const char *key)
{
return istgt_get_nintval(sp, key, 0);
}
static const char *
istgt_get_log_facility(CONFIG *config)
{
CF_SECTION *sp;
const char *logfacility;
sp = istgt_find_cf_section(config, "Global");
if (sp == NULL) {
return NULL;
}
logfacility = istgt_get_val(sp, "LogFacility");
if (logfacility == NULL) {
logfacility = DEFAULT_LOG_FACILITY;
}
#if 0
if (g_trace_flag & ISTGT_TRACE_DEBUG) {
fprintf(stderr, "LogFacility %s\n", logfacility);
}
#endif
return logfacility;
}
static int
istgt_init(ISTGT_Ptr istgt)
{
CF_SECTION *sp;
const char *ag_tag;
const char *val;
size_t stacksize;
int ag_tag_i;
int MaxSessions;
int MaxConnections;
int MaxOutstandingR2T;
int DefaultTime2Wait;
int DefaultTime2Retain;
int FirstBurstLength;
int MaxBurstLength;
int MaxRecvDataSegmentLength;
int InitialR2T;
int ImmediateData;
int DataPDUInOrder;
int DataSequenceInOrder;
int ErrorRecoveryLevel;
int timeout;
int nopininterval;
int maxr2t;
int rc;
int i;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_init\n");
sp = istgt_find_cf_section(istgt->config, "Global");
if (sp == NULL) {
ISTGT_ERRLOG("find_cf_section failed()\n");
return -1;
}
val = istgt_get_val(sp, "Comment");
if (val != NULL) {
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Comment %s\n", val);
}
val = istgt_get_val(sp, "PidFile");
if (val == NULL) {
val = DEFAULT_PIDFILE;
}
istgt->pidfile = xstrdup(val);
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "PidFile %s\n",
istgt->pidfile);
val = istgt_get_val(sp, "AuthFile");
if (val == NULL) {
val = DEFAULT_AUTHFILE;
}
istgt->authfile = xstrdup(val);
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "AuthFile %s\n",
istgt->authfile);
#if 0
val = istgt_get_val(sp, "MediaFile");
if (val == NULL) {
val = DEFAULT_MEDIAFILE;
}
istgt->mediafile = xstrdup(val);
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MediaFile %s\n",
istgt->mediafile);
#endif
#if 0
val = istgt_get_val(sp, "LiveFile");
if (val == NULL) {
val = DEFAULT_LIVEFILE;
}
istgt->livefile = xstrdup(val);
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LiveFile %s\n",
istgt->livefile);
#endif
val = istgt_get_val(sp, "MediaDirectory");
if (val == NULL) {
val = DEFAULT_MEDIADIRECTORY;
}
istgt->mediadirectory = xstrdup(val);
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MediaDirectory %s\n",
istgt->mediadirectory);
val = istgt_get_val(sp, "NodeBase");
if (val == NULL) {
val = DEFAULT_NODEBASE;
}
istgt->nodebase = xstrdup(val);
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "NodeBase %s\n",
istgt->nodebase);
MaxSessions = istgt_get_intval(sp, "MaxSessions");
if (MaxSessions < 1) {
MaxSessions = DEFAULT_MAX_SESSIONS;
}
istgt->MaxSessions = MaxSessions;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MaxSessions %d\n",
istgt->MaxSessions);
MaxConnections = istgt_get_intval(sp, "MaxConnections");
if (MaxConnections < 1) {
MaxConnections = DEFAULT_MAX_CONNECTIONS;
}
istgt->MaxConnections = MaxConnections;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MaxConnections %d\n",
istgt->MaxConnections);
/* limited to 16bits - RFC3720(12.2) */
if (MaxSessions > 0xffff) {
ISTGT_ERRLOG("over 65535 sessions are not supported\n");
return -1;
}
if (MaxConnections > 0xffff) {
ISTGT_ERRLOG("over 65535 connections are not supported\n");
return -1;
}
MaxOutstandingR2T = istgt_get_intval(sp, "MaxOutstandingR2T");
if (MaxOutstandingR2T < 1) {
MaxOutstandingR2T = DEFAULT_MAXOUTSTANDINGR2T;
}
istgt->MaxOutstandingR2T = MaxOutstandingR2T;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MaxOutstandingR2T %d\n",
istgt->MaxOutstandingR2T);
DefaultTime2Wait = istgt_get_intval(sp, "DefaultTime2Wait");
if (DefaultTime2Wait < 0) {
DefaultTime2Wait = DEFAULT_DEFAULTTIME2WAIT;
}
istgt->DefaultTime2Wait = DefaultTime2Wait;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "DefaultTime2Wait %d\n",
istgt->DefaultTime2Wait);
DefaultTime2Retain = istgt_get_intval(sp, "DefaultTime2Retain");
if (DefaultTime2Retain < 0) {
DefaultTime2Retain = DEFAULT_DEFAULTTIME2RETAIN;
}
istgt->DefaultTime2Retain = DefaultTime2Retain;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "DefaultTime2Retain %d\n",
istgt->DefaultTime2Retain);
/* check size limit - RFC3720(12.15, 12.16, 12.17) */
if (istgt->MaxOutstandingR2T > 65535) {
ISTGT_ERRLOG("MaxOutstandingR2T(%d) > 65535\n",
istgt->MaxOutstandingR2T);
return -1;
}
if (istgt->DefaultTime2Wait > 3600) {
ISTGT_ERRLOG("DefaultTime2Wait(%d) > 3600\n",
istgt->DefaultTime2Wait);
return -1;
}
if (istgt->DefaultTime2Retain > 3600) {
ISTGT_ERRLOG("DefaultTime2Retain(%d) > 3600\n",
istgt->DefaultTime2Retain);
return -1;
}
FirstBurstLength = istgt_get_intval(sp, "FirstBurstLength");
if (FirstBurstLength < 0) {
FirstBurstLength = DEFAULT_FIRSTBURSTLENGTH;
}
istgt->FirstBurstLength = FirstBurstLength;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "FirstBurstLength %d\n",
istgt->FirstBurstLength);
MaxBurstLength = istgt_get_intval(sp, "MaxBurstLength");
if (MaxBurstLength < 0) {
MaxBurstLength = DEFAULT_MAXBURSTLENGTH;
}
istgt->MaxBurstLength = MaxBurstLength;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MaxBurstLength %d\n",
istgt->MaxBurstLength);
MaxRecvDataSegmentLength
= istgt_get_intval(sp, "MaxRecvDataSegmentLength");
if (MaxRecvDataSegmentLength < 0) {
MaxRecvDataSegmentLength = DEFAULT_MAXRECVDATASEGMENTLENGTH;
}
istgt->MaxRecvDataSegmentLength = MaxRecvDataSegmentLength;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MaxRecvDataSegmentLength %d\n",
istgt->MaxRecvDataSegmentLength);
/* check size limit (up to 24bits - RFC3720(12.12)) */
if (istgt->MaxBurstLength < 512) {
ISTGT_ERRLOG("MaxBurstLength(%d) < 512\n",
istgt->MaxBurstLength);
return -1;
}
if (istgt->FirstBurstLength < 512) {
ISTGT_ERRLOG("FirstBurstLength(%d) < 512\n",
istgt->FirstBurstLength);
return -1;
}
if (istgt->FirstBurstLength > istgt->MaxBurstLength) {
ISTGT_ERRLOG("FirstBurstLength(%d) > MaxBurstLength(%d)\n",
istgt->FirstBurstLength, istgt->MaxBurstLength);
return -1;
}
if (istgt->MaxBurstLength > 0x00ffffff) {
ISTGT_ERRLOG("MaxBurstLength(%d) > 0x00ffffff\n",
istgt->MaxBurstLength);
return -1;
}
if (istgt->MaxRecvDataSegmentLength < 512) {
ISTGT_ERRLOG("MaxRecvDataSegmentLength(%d) < 512\n",
istgt->MaxRecvDataSegmentLength);
return -1;
}
if (istgt->MaxRecvDataSegmentLength > 0x00ffffff) {
ISTGT_ERRLOG("MaxRecvDataSegmentLength(%d) > 0x00ffffff\n",
istgt->MaxRecvDataSegmentLength);
return -1;
}
val = istgt_get_val(sp, "InitialR2T");
if (val == NULL) {
InitialR2T = DEFAULT_INITIALR2T;
} else if (strcasecmp(val, "Yes") == 0) {
InitialR2T = 1;
} else if (strcasecmp(val, "No") == 0) {
#if 0
InitialR2T = 0;
#else
ISTGT_ERRLOG("not supported value %s\n", val);
return -1;
#endif
} else {
ISTGT_ERRLOG("unknown value %s\n", val);
return -1;
}
istgt->InitialR2T = InitialR2T;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "InitialR2T %s\n",
istgt->InitialR2T ? "Yes" : "No");
val = istgt_get_val(sp, "ImmediateData");
if (val == NULL) {
ImmediateData = DEFAULT_IMMEDIATEDATA;
} else if (strcasecmp(val, "Yes") == 0) {
ImmediateData = 1;
} else if (strcasecmp(val, "No") == 0) {
ImmediateData = 0;
} else {
ISTGT_ERRLOG("unknown value %s\n", val);
return -1;
}
istgt->ImmediateData = ImmediateData;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "ImmediateData %s\n",
istgt->ImmediateData ? "Yes" : "No");
val = istgt_get_val(sp, "DataPDUInOrder");
if (val == NULL) {
DataPDUInOrder = DEFAULT_DATAPDUINORDER;
} else if (strcasecmp(val, "Yes") == 0) {
DataPDUInOrder = 1;
} else if (strcasecmp(val, "No") == 0) {
#if 0
DataPDUInOrder = 0;
#else
ISTGT_ERRLOG("not supported value %s\n", val);
return -1;
#endif
} else {
ISTGT_ERRLOG("unknown value %s\n", val);
return -1;
}
istgt->DataPDUInOrder = DataPDUInOrder;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "DataPDUInOrder %s\n",
istgt->DataPDUInOrder ? "Yes" : "No");
val = istgt_get_val(sp, "DataSequenceInOrder");
if (val == NULL) {
DataSequenceInOrder = DEFAULT_DATASEQUENCEINORDER;
} else if (strcasecmp(val, "Yes") == 0) {
DataSequenceInOrder = 1;
} else if (strcasecmp(val, "No") == 0) {
#if 0
DataSequenceInOrder = 0;
#else
ISTGT_ERRLOG("not supported value %s\n", val);
return -1;
#endif
} else {
ISTGT_ERRLOG("unknown value %s\n", val);
return -1;
}
istgt->DataSequenceInOrder = DataSequenceInOrder;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "DataSequenceInOrder %s\n",
istgt->DataSequenceInOrder ? "Yes" : "No");
ErrorRecoveryLevel = istgt_get_intval(sp, "ErrorRecoveryLevel");
if (ErrorRecoveryLevel < 0) {
ErrorRecoveryLevel = DEFAULT_ERRORRECOVERYLEVEL;
} else if (ErrorRecoveryLevel == 0) {
ErrorRecoveryLevel = 0;
} else if (ErrorRecoveryLevel == 1) {
#if 0
ErrorRecoveryLevel = 1;
#else
ISTGT_ERRLOG("not supported value %d\n", ErrorRecoveryLevel);
return -1;
#endif
} else if (ErrorRecoveryLevel == 2) {
#if 0
ErrorRecoveryLevel = 2;
#else
ISTGT_ERRLOG("not supported value %d\n", ErrorRecoveryLevel);
return -1;
#endif
} else {
ISTGT_ERRLOG("not supported value %d\n", ErrorRecoveryLevel);
return -1;
}
istgt->ErrorRecoveryLevel = ErrorRecoveryLevel;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "ErrorRecoveryLevel %d\n",
istgt->ErrorRecoveryLevel);
timeout = istgt_get_intval(sp, "Timeout");
if (timeout < 0) {
timeout = DEFAULT_TIMEOUT;
}
istgt->timeout = timeout;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Timeout %d\n",
istgt->timeout);
nopininterval = istgt_get_intval(sp, "NopInInterval");
if (nopininterval < 0) {
nopininterval = DEFAULT_NOPININTERVAL;
}
istgt->nopininterval = nopininterval;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "NopInInterval %d\n",
istgt->nopininterval);
maxr2t = istgt_get_intval(sp, "MaxR2T");
if (maxr2t < 0) {
maxr2t = DEFAULT_MAXR2T;
}
if (maxr2t > MAX_R2T) {
ISTGT_ERRLOG("MaxR2T(%d) > %d\n",
maxr2t, MAX_R2T);
return -1;
}
istgt->maxr2t = maxr2t;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MaxR2T %d\n",
istgt->maxr2t);
val = istgt_get_val(sp, "DiscoveryAuthMethod");
if (val == NULL) {
istgt->no_discovery_auth = 0;
istgt->req_discovery_auth = 0;
istgt->req_discovery_auth_mutual = 0;
} else {
istgt->no_discovery_auth = 0;
for (i = 0; ; i++) {
val = istgt_get_nmval(sp, "DiscoveryAuthMethod", 0, i);
if (val == NULL)
break;
if (strcasecmp(val, "CHAP") == 0) {
istgt->req_discovery_auth = 1;
} else if (strcasecmp(val, "Mutual") == 0) {
istgt->req_discovery_auth_mutual = 1;
} else if (strcasecmp(val, "Auto") == 0) {
istgt->req_discovery_auth = 0;
istgt->req_discovery_auth_mutual = 0;
} else if (strcasecmp(val, "None") == 0) {
istgt->no_discovery_auth = 1;
istgt->req_discovery_auth = 0;
istgt->req_discovery_auth_mutual = 0;
} else {
ISTGT_ERRLOG("unknown auth\n");
return -1;
}
}
if (istgt->req_discovery_auth_mutual && !istgt->req_discovery_auth) {
ISTGT_ERRLOG("Mutual but not CHAP\n");
return -1;
}
}
if (istgt->no_discovery_auth != 0) {
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
"DiscoveryAuthMethod None\n");
} else if (istgt->req_discovery_auth == 0) {
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
"DiscoveryAuthMethod Auto\n");
} else {
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
"DiscoveryAuthMethod %s %s\n",
istgt->req_discovery_auth ? "CHAP" : "",
istgt->req_discovery_auth_mutual ? "Mutual" : "");
}
val = istgt_get_val(sp, "DiscoveryAuthGroup");
if (val == NULL) {
istgt->discovery_auth_group = 0;
} else {
ag_tag = val;
if (strcasecmp(ag_tag, "None") == 0) {
ag_tag_i = 0;
} else {
if (strncasecmp(ag_tag, "AuthGroup",
strlen("AuthGroup")) != 0
|| sscanf(ag_tag, "%*[^0-9]%d", &ag_tag_i) != 1) {
ISTGT_ERRLOG("auth group error\n");
return -1;
}
if (ag_tag_i == 0) {
ISTGT_ERRLOG("invalid auth group %d\n",
ag_tag_i);
return -1;
}
}
istgt->discovery_auth_group = ag_tag_i;
}
if (istgt->discovery_auth_group == 0) {
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
"DiscoveryAuthGroup None\n");
} else {
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
"DiscoveryAuthGroup AuthGroup%d\n",
istgt->discovery_auth_group);
}
rc = istgt_uctl_init(istgt);
if (rc < 0) {
ISTGT_ERRLOG("istgt_uctl_init() failed\n");
return -1;
}
rc = istgt_build_uctl_portal(istgt);
if (rc < 0) {
ISTGT_ERRLOG("istgt_build_uctl_portal() failed\n");
return -1;
}
rc = istgt_build_portal_group_array(istgt);
if (rc < 0) {
ISTGT_ERRLOG("istgt_build_portal_array() failed\n");
return -1;
}
rc = istgt_build_initiator_group_array(istgt);
if (rc < 0) {
ISTGT_ERRLOG("build_initiator_group_array() failed\n");
return -1;
}
rc = pthread_attr_init(&istgt->attr);
if (rc != 0) {
ISTGT_ERRLOG("pthread_attr_init() failed\n");
return -1;
}
rc = pthread_attr_getstacksize(&istgt->attr, &stacksize);
if (rc != 0) {
ISTGT_ERRLOG("pthread_attr_getstacksize() failed\n");
return -1;
}
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "current thread stack = %zd\n", stacksize);
if (stacksize < ISTGT_STACKSIZE) {
stacksize = ISTGT_STACKSIZE;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "new thread stack = %zd\n", stacksize);
rc = pthread_attr_setstacksize(&istgt->attr, stacksize);
if (rc != 0) {
ISTGT_ERRLOG("pthread_attr_setstacksize() failed\n");
return -1;
}
}
rc = pthread_mutexattr_init(&istgt->mutex_attr);
if (rc != 0) {
ISTGT_ERRLOG("mutexattr_init() failed\n");
return -1;
}
#ifdef HAVE_PTHREAD_MUTEX_ADAPTIVE_NP
rc = pthread_mutexattr_settype(&istgt->mutex_attr, PTHREAD_MUTEX_ADAPTIVE_NP);
#else
rc = pthread_mutexattr_settype(&istgt->mutex_attr, PTHREAD_MUTEX_ERRORCHECK);
#endif
if (rc != 0) {
ISTGT_ERRLOG("mutexattr_settype() failed\n");
return -1;
}
rc = pthread_mutex_init(&istgt->mutex, NULL);
if (rc != 0) {
ISTGT_ERRLOG("mutex_init() failed\n");
return -1;
}
rc = pthread_mutex_init(&istgt->state_mutex, &istgt->mutex_attr);
if (rc != 0) {
ISTGT_ERRLOG("mutex_init() failed\n");
return -1;
}
rc = pthread_mutex_init(&istgt->reload_mutex, &istgt->mutex_attr);
if (rc != 0) {
ISTGT_ERRLOG("mutex_init() failed\n");
return -1;
}
rc = pthread_cond_init(&istgt->reload_cond, NULL);
if (rc != 0) {
ISTGT_ERRLOG("cond_init() failed\n");
return -1;
}
rc = pipe(istgt->sig_pipe);
if (rc != 0) {
ISTGT_ERRLOG("pipe() failed\n");
istgt->sig_pipe[0] = -1;
istgt->sig_pipe[1] = -1;
return -1;
}
/* XXX TODO: add initializer */
istgt_set_state(istgt, ISTGT_STATE_INITIALIZED);
return 0;
}
static void
istgt_shutdown(ISTGT_Ptr istgt)
{
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_shutdown\n");
istgt_destory_initiator_group_array(istgt);
istgt_destroy_portal_group_array(istgt);
istgt_destroy_uctl_portal(istgt);
istgt_uctl_shutdown(istgt);
istgt_remove_pidfile(istgt);
xfree(istgt->pidfile);
xfree(istgt->authfile);
#if 0
xfree(istgt->mediafile);
xfree(istgt->livefile);
#endif
xfree(istgt->mediadirectory);
xfree(istgt->nodebase);
if (istgt->sig_pipe[0] != -1)
close(istgt->sig_pipe[0]);
if (istgt->sig_pipe[1] != -1)
close(istgt->sig_pipe[1]);
(void) pthread_cond_destroy(&istgt->reload_cond);
(void) pthread_mutex_destroy(&istgt->reload_mutex);
(void) pthread_mutex_destroy(&istgt->state_mutex);
(void) pthread_mutex_destroy(&istgt->mutex);
(void) pthread_attr_destroy(&istgt->attr);
}
static int
istgt_pg_exist_num(CONFIG *config, int num)
{
CF_SECTION *sp;
sp = config->section;
while (sp != NULL) {
if (sp->type == ST_PORTALGROUP) {
if (sp->num == num) {
return 1;
}
}
sp = sp->next;
}
return -1;
}
static PORTAL_GROUP *
istgt_get_tag_portal(ISTGT_Ptr istgt, int tag)
{
int i;
if (tag == 0)
return NULL;
MTX_LOCK(&istgt->mutex);
for (i = 0; i < istgt->nportal_group; i++) {
if (istgt->portal_group[i].tag == tag) {
MTX_UNLOCK(&istgt->mutex);
return &istgt->portal_group[i];
}
}
MTX_UNLOCK(&istgt->mutex);
return NULL;
}
#if 0
static int
istgt_get_num_of_portals(CF_SECTION *sp)
{
char *label, *portal;
int portals;
int rc;
int i;
for (i = 0; ; i++) {
label = istgt_get_nmval(sp, "Portal", i, 0);
portal = istgt_get_nmval(sp, "Portal", i, 1);
if (label == NULL || portal == NULL)
break;
rc = istgt_parse_portal(portal, NULL, NULL);
if (rc < 0) {
ISTGT_ERRLOG("parse portal error (%s)\n", portal);
return -1;
}
}
portals = i;
if (portals > MAX_PORTAL) {
ISTGT_ERRLOG("%d > MAX_PORTAL\n", portals);
return -1;
}
return portals;
}
#endif
#define RELOAD_CMD_LENGTH 5
static int
istgt_pg_reload_delete(ISTGT_Ptr istgt)
{
char tmp[RELOAD_CMD_LENGTH];
int rc;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_pg_reload_delete\n");
istgt->pg_reload = 0;
/* request delete */
tmp[0] = 'D';
DSET32(&tmp[1], 0);
rc = write(istgt->sig_pipe[1], tmp, RELOAD_CMD_LENGTH);
if (rc < 0 || rc != RELOAD_CMD_LENGTH) {
ISTGT_ERRLOG("write() failed\n");
return -1;
}
/* wait for completion */
MTX_LOCK(&istgt->reload_mutex);
while (istgt->pg_reload == 0) {
pthread_cond_wait(&istgt->reload_cond, &istgt->reload_mutex);
}
rc = istgt->pg_reload;
MTX_UNLOCK(&istgt->reload_mutex);
if (rc < 0) {
if (istgt_get_state(istgt) != ISTGT_STATE_RUNNING) {
ISTGT_WARNLOG("pg_reload abort\n");
return -1;
}
}
return 0;
}
static int
istgt_pg_reload_update(ISTGT_Ptr istgt)
{
char tmp[RELOAD_CMD_LENGTH];
int rc;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_pg_reload_update\n");
istgt->pg_reload = 0;
/* request update */
tmp[0] = 'U';
DSET32(&tmp[1], 0);
rc = write(istgt->sig_pipe[1], tmp, RELOAD_CMD_LENGTH);
if (rc < 0 || rc != RELOAD_CMD_LENGTH) {
ISTGT_ERRLOG("write() failed\n");
return -1;
}
/* wait for completion */
MTX_LOCK(&istgt->reload_mutex);
while (istgt->pg_reload == 0) {
pthread_cond_wait(&istgt->reload_cond, &istgt->reload_mutex);
}
rc = istgt->pg_reload;
MTX_UNLOCK(&istgt->reload_mutex);
if (rc < 0) {
if (istgt_get_state(istgt) != ISTGT_STATE_RUNNING) {
ISTGT_WARNLOG("pg_reload abort\n");
return -1;
}
}
return 0;
}
static int
istgt_ig_exist_num(CONFIG *config, int num)
{
CF_SECTION *sp;
sp = config->section;
while (sp != NULL) {
if (sp->type == ST_INITIATORGROUP) {
if (sp->num == num) {
return 1;
}
}
sp = sp->next;
}
return -1;
}
static int
istgt_ig_reload_delete(ISTGT_Ptr istgt)
{
INITIATOR_GROUP *igp;
int rc;
int i, j;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_ig_reload_delete\n");
MTX_LOCK(&istgt->mutex);
for (i = 0; i < istgt->ninitiator_group; i++) {
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "IG reload idx=%d, (%d)\n",
i, istgt->ninitiator_group);
igp = &istgt->initiator_group[i];
rc = istgt_ig_exist_num(istgt->config, igp->tag);
if (rc < 0) {
if (igp->ref != 0) {
ISTGT_ERRLOG("delete request for referenced IG%d\n",
igp->tag);
} else {
ISTGT_NOTICELOG("delete IG%d\n", igp->tag);
/* free old IG */
for (j = 0; j < istgt->initiator_group[i].ninitiators; j++) {
xfree(istgt->initiator_group[i].initiators[j]);
}
xfree(istgt->initiator_group[i].initiators);
for (j = 0; j < istgt->initiator_group[i].nnetmasks; j++) {
xfree(istgt->initiator_group[i].netmasks[j]);
}
xfree(istgt->initiator_group[i].netmasks);
/* move from beyond the IG */
for (j = i; j < istgt->ninitiator_group - 1; j++) {
istgt->initiator_group[j].ninitiators
= istgt->initiator_group[j+1].ninitiators;
istgt->initiator_group[j].initiators
= istgt->initiator_group[j+1].initiators;
istgt->initiator_group[j].nnetmasks
= istgt->initiator_group[j+1].nnetmasks;
istgt->initiator_group[j].netmasks
= istgt->initiator_group[j+1].netmasks;
istgt->initiator_group[j].ref
= istgt->initiator_group[j+1].ref;
istgt->initiator_group[j].idx
= istgt->initiator_group[j+1].idx;
istgt->initiator_group[j].tag
= istgt->initiator_group[j+1].tag;
}
istgt->ninitiator_group--;
}
}
}
MTX_UNLOCK(&istgt->mutex);
return 0;
}
static int
istgt_ig_reload_update(ISTGT_Ptr istgt)
{
CF_SECTION *sp;
int rc;
int i;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_ig_reload_update\n");
sp = istgt->config->section;
while (sp != NULL) {
if (sp->type == ST_INITIATORGROUP) {
if (sp->num == 0) {
ISTGT_ERRLOG("Group 0 is invalid\n");
goto skip_ig;
}
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "IG reload tag=%d\n", sp->num);
#if 0
rc = istgt_ig_exist_num(istgt->config_old, sp->num);
#else
rc = -1;
MTX_LOCK(&istgt->mutex);
for (i = 0; i < istgt->ninitiator_group; i++) {
if (istgt->initiator_group[i].tag == sp->num) {
rc = 1;
break;
}
}
MTX_UNLOCK(&istgt->mutex);
#endif
if (rc < 0) {
rc = istgt_add_initiator_group(istgt, sp);
if (rc < 0) {
ISTGT_ERRLOG("add_initiator_group() failed\n");
goto skip_ig;
}
ISTGT_NOTICELOG("add IG%d\n", sp->num);
} else {
rc = istgt_update_initiator_group(istgt, sp);
if (rc < 0) {
ISTGT_ERRLOG("update_initiator_group() failed\n");
goto skip_ig;
} else if (rc == 0) {
// not modified
} else if (rc > 0) {
ISTGT_NOTICELOG("update IG%d\n", sp->num);
}
}
}
skip_ig:
sp = sp->next;
}
return 0;
}
static int
istgt_reload(ISTGT_Ptr istgt)
{
CONFIG *config_new, *config_old;
char *config_file;
int rc;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_reload\n");
/* prepare config structure */
config_new = istgt_allocate_config();
config_old = istgt->config;
config_file = config_old->file;
rc = istgt_read_config(config_new, config_file);
if (rc < 0) {
ISTGT_ERRLOG("config error\n");
return -1;
}
if (config_new->section == NULL) {
ISTGT_ERRLOG("empty config\n");
istgt_free_config(config_new);
return -1;
}
istgt->config = config_new;
istgt->config_old = config_old;
istgt->generation++;
/* reload sub groups */
ISTGT_NOTICELOG("reload configuration #%"PRIu32"\n", istgt->generation);
rc = istgt_lu_reload_delete(istgt);
if (rc < 0) {
ISTGT_ERRLOG("LU reload del error\n");
return -1;
}
rc = istgt_ig_reload_delete(istgt);
if (rc < 0) {
ISTGT_ERRLOG("IG reload del error\n");
return -1;
}
rc = istgt_pg_reload_delete(istgt);
if (rc < 0) {
ISTGT_ERRLOG("PG reload del error\n");
return -1;
}
rc = istgt_pg_reload_update(istgt);
if (rc < 0) {
ISTGT_ERRLOG("PG reload add error\n");
return -1;
}
rc = istgt_ig_reload_update(istgt);
if (rc < 0) {
ISTGT_ERRLOG("IG reload add error\n");
return -1;
}
rc = istgt_lu_reload_update(istgt);
if (rc < 0) {
ISTGT_ERRLOG("LU reload add error\n");
return -1;
}
istgt->config_old = NULL;
istgt_free_config(config_old);
return 0;
}
static int
istgt_stop_loop(ISTGT_Ptr istgt)
{
char tmp[RELOAD_CMD_LENGTH];
int rc;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_stop_loop\n");
tmp[0] = 'E';
DSET32(&tmp[1], 0);
rc = write(istgt->sig_pipe[1], tmp, RELOAD_CMD_LENGTH);
if (rc < 0 || rc != RELOAD_CMD_LENGTH) {
ISTGT_ERRLOG("write() failed\n");
/* ignore error */
}
return 0;
}
static void
istgt_sigint(int signo __attribute__((__unused__)))
{
}
static void
istgt_sigterm(int signo __attribute__((__unused__)))
{
}
static void
istgt_sighup(int signo __attribute__((__unused__)))
{
}
#ifdef SIGINFO
static void
istgt_siginfo(int signo __attribute__((__unused__)))
{
/* nothing */
}
#endif
static void
istgt_sigwakeup(int signo __attribute__((__unused__)))
{
}
#ifdef SIGIO
static void
istgt_sigio(int signo __attribute__((__unused__)))
{
}
#endif
static void *
istgt_sighandler(void *arg)
{
ISTGT_Ptr istgt = (ISTGT_Ptr) arg;
sigset_t signew;
int signo;
sigemptyset(&signew);
sigaddset(&signew, SIGINT);
sigaddset(&signew, SIGTERM);
sigaddset(&signew, SIGQUIT);
sigaddset(&signew, SIGHUP);
#ifdef SIGINFO
sigaddset(&signew, SIGINFO);
#endif
sigaddset(&signew, SIGUSR1);
sigaddset(&signew, SIGUSR2);
#ifdef SIGIO
sigaddset(&signew, SIGIO);
#endif
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "loop start\n");
while (1) {
if (istgt_get_state(istgt) == ISTGT_STATE_EXITING
|| istgt_get_state(istgt) == ISTGT_STATE_SHUTDOWN) {
break;
}
sigwait(&signew, &signo);
switch (signo) {
case SIGINT:
printf("SIGINT catch\n");
istgt_stop_loop(istgt);
istgt_set_state(istgt, ISTGT_STATE_EXITING);
istgt_lu_set_all_state(istgt, ISTGT_STATE_EXITING);
break;
case SIGTERM:
printf("SIGTERM catch\n");
istgt_stop_loop(istgt);
istgt_set_state(istgt, ISTGT_STATE_EXITING);
istgt_lu_set_all_state(istgt, ISTGT_STATE_EXITING);
break;
case SIGQUIT:
printf("SIGQUIT catch\n");
exit(EXIT_SUCCESS);
break;
case SIGHUP:
printf("SIGHUP catch\n");
istgt_reload(istgt);
break;
#ifdef SIGINFO
case SIGINFO:
printf("SIGINFO catch\n");
istgt_set_trace_flag(ISTGT_TRACE_ISCSI);
break;
#endif
case SIGUSR1:
printf("SIGUSR1 catch\n");
istgt_set_trace_flag(ISTGT_TRACE_NONE);
break;
case SIGUSR2:
printf("SIGUSR2 catch\n");
//istgt_set_trace_flag(ISTGT_TRACE_SCSI);
istgt_set_trace_flag(ISTGT_TRACE_ALL);
break;
#ifdef SIGIO
case SIGIO:
//printf("SIGIO catch\n");
break;
#endif
default:
break;
}
}
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "loop ended\n");
return NULL;
}
static PORTAL *
istgt_get_sock_portal(ISTGT_Ptr istgt, int sock)
{
int i, j;
if (sock < 0)
return NULL;
MTX_LOCK(&istgt->mutex);
for (i = 0; i < istgt->nportal_group; i++) {
for (j = 0; j < istgt->portal_group[i].nportals; j++) {
if (istgt->portal_group[i].portals[j]->sock == sock) {
MTX_UNLOCK(&istgt->mutex);
return istgt->portal_group[i].portals[j];
}
}
}
MTX_UNLOCK(&istgt->mutex);
return NULL;
}
static int
istgt_pg_delete(ISTGT_Ptr istgt)
{
PORTAL_GROUP *pgp;
int rc;
int i;
MTX_LOCK(&istgt->mutex);
for (i = 0; i < istgt->nportal_group; i++) {
pgp = &istgt->portal_group[i];
if (pgp->tag == 0)
continue;
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "PG reload idx=%d, tag=%d, (%d)\n",
i, pgp->tag, istgt->nportal_group);
rc = istgt_pg_exist_num(istgt->config, pgp->tag);
if (rc < 0) {
if (pgp->ref != 0) {
ISTGT_ERRLOG("delete request for referenced PG%d\n",
pgp->tag);
} else {
ISTGT_NOTICELOG("delete PG%d\n", pgp->tag);
pgp->tag = 0;
(void) istgt_close_portal_group(pgp);
}
}
}
MTX_UNLOCK(&istgt->mutex);
return 0;
}
static int
istgt_pg_update(ISTGT_Ptr istgt)
{
PORTAL_GROUP *pgp;
CF_SECTION *sp;
int pgp_idx;
int rc;
int i;
sp = istgt->config->section;
while (sp != NULL) {
if (sp->type == ST_PORTALGROUP) {
if (sp->num == 0) {
ISTGT_ERRLOG("Group 0 is invalid\n");
goto skip_pg;
}
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "PG reload tag=%d\n", sp->num);
#if 0
rc = istgt_pg_exist_num(istgt->config_old, sp->num);
#else
rc = -1;
MTX_LOCK(&istgt->mutex);
for (i = 0; i < istgt->nportal_group; i++) {
if (istgt->portal_group[i].tag == sp->num) {
rc = 1;
break;
}
}
MTX_UNLOCK(&istgt->mutex);
#endif
if (rc < 0) {
rc = istgt_add_portal_group(istgt, sp, &pgp_idx);
if (rc < 0) {
ISTGT_ERRLOG("add_portal_group() failed\n");
goto skip_pg;
}
MTX_LOCK(&istgt->mutex);
pgp = &istgt->portal_group[pgp_idx];
(void) istgt_open_portal_group(pgp);
MTX_UNLOCK(&istgt->mutex);
ISTGT_NOTICELOG("add PG%d\n", sp->num);
} else {
//portals = istgt_get_num_of_portals(sp);
pgp = istgt_get_tag_portal(istgt, sp->num);
if (istgt_pg_match_all(pgp, sp)) {
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
"skip for PG%d\n", sp->num);
} else if (pgp->ref != 0) {
ISTGT_ERRLOG("update request for referenced PG%d\n",
pgp->tag);
} else {
/* delete old sock */
MTX_LOCK(&istgt->mutex);
pgp_idx = pgp->idx;
(void) istgt_close_portal_group(pgp);
MTX_UNLOCK(&istgt->mutex);
rc = istgt_update_portal_group(istgt, sp, &pgp_idx);
if (rc < 0) {
ISTGT_ERRLOG("update_portal_group() failed\n");
goto skip_pg;
} else if (rc == 0) {
// not modified
} else if (rc > 0) {
/* add new sock */
MTX_LOCK(&istgt->mutex);
pgp = &istgt->portal_group[pgp_idx];
(void) istgt_open_portal_group(pgp);
MTX_UNLOCK(&istgt->mutex);
ISTGT_NOTICELOG("update PG%d\n", sp->num);
}
}
}
}
skip_pg:
sp = sp->next;
}
return 0;
}
static int
istgt_acceptor(ISTGT_Ptr istgt)
{
PORTAL *pp;
#ifdef ISTGT_USE_KQUEUE
int kq;
struct kevent kev;
struct timespec kev_timeout;
int kqsocks[MAX_PORTAL_GROUP + MAX_UCPORTAL];
#else
struct pollfd fds[MAX_PORTAL_GROUP + MAX_UCPORTAL];
#endif /* ISTGT_USE_KQUEUE */
struct sockaddr_storage sa;
socklen_t salen;
int sock;
int rc, n;
int ucidx;
int nidx;
int i, j;
if (istgt_get_state(istgt) != ISTGT_STATE_INITIALIZED) {
ISTGT_ERRLOG("not initialized\n");
return -1;
}
/* now running main thread */
istgt_set_state(istgt, ISTGT_STATE_RUNNING);
reload:
nidx = 0;
#ifdef ISTGT_USE_KQUEUE
kq = kqueue();
if (kq == -1) {
ISTGT_ERRLOG("kqueue() failed\n");
return -1;
}
for (i = 0; i < (int)(sizeof kqsocks / sizeof *kqsocks); i++) {
kqsocks[i] = -1;
}
MTX_LOCK(&istgt->mutex);
for (i = 0; i < istgt->nportal_group; i++) {
for (j = 0; j < istgt->portal_group[i].nportals; j++) {
if (istgt->portal_group[i].portals[j]->sock >= 0) {
ISTGT_EV_SET(&kev, istgt->portal_group[i].portals[j]->sock,
EVFILT_READ, EV_ADD, 0, 0, NULL);
rc = kevent(kq, &kev, 1, NULL, 0, NULL);
if (rc == -1) {
MTX_UNLOCK(&istgt->mutex);
ISTGT_ERRLOG("kevent() failed\n");
close(kq);
return -1;
}
kqsocks[nidx] = istgt->portal_group[i].portals[j]->sock;
nidx++;
}
}
}
MTX_UNLOCK(&istgt->mutex);
ucidx = nidx;
for (i = 0; i < istgt->nuctl_portal; i++) {
ISTGT_EV_SET(&kev, istgt->uctl_portal[i].sock,
EVFILT_READ, EV_ADD, 0, 0, NULL);
rc = kevent(kq, &kev, 1, NULL, 0, NULL);
if (rc == -1) {
ISTGT_ERRLOG("kevent() failed\n");
close(kq);
return -1;
}
kqsocks[nidx] = istgt->uctl_portal[i].sock;
nidx++;
}
ISTGT_EV_SET(&kev, istgt->sig_pipe[0], EVFILT_READ, EV_ADD, 0, 0, NULL);
rc = kevent(kq, &kev, 1, NULL, 0, NULL);
if (rc == -1) {
ISTGT_ERRLOG("kevent() failed\n");
close(kq);
return -1;
}
kqsocks[nidx] = istgt->sig_pipe[0];
nidx++;
if (!istgt->daemon) {
ISTGT_EV_SET(&kev, SIGINT, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
rc = kevent(kq, &kev, 1, NULL, 0, NULL);
if (rc == -1) {
ISTGT_ERRLOG("kevent() failed\n");
close(kq);
return -1;
}
ISTGT_EV_SET(&kev, SIGTERM, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
rc = kevent(kq, &kev, 1, NULL, 0, NULL);
if (rc == -1) {
ISTGT_ERRLOG("kevent() failed\n");
close(kq);
return -1;
}
}
#else
memset(&fds, 0, sizeof fds);
MTX_LOCK(&istgt->mutex);
for (i = 0; i < istgt->nportal_group; i++) {
for (j = 0; j < istgt->portal_group[i].nportals; j++) {
if (istgt->portal_group[i].portals[j]->sock >= 0) {
fds[i].fd = istgt->portal_group[i].portals[j]->sock;
fds[i].events = POLLIN;
nidx++;
}
}
}
MTX_UNLOCK(&istgt->mutex);
ucidx = nidx;
for (i = 0; i < istgt->nuctl_portal; i++) {
fds[ucidx + i].fd = istgt->uctl_portal[i].sock;
fds[ucidx + i].events = POLLIN;
nidx++;
}
fds[nidx].fd = istgt->sig_pipe[0];
fds[nidx].events = POLLIN;
nidx++;
#endif /* ISTGT_USE_KQUEUE */
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "loop start\n");
while (1) {
if (istgt_get_state(istgt) != ISTGT_STATE_RUNNING) {
break;
}
#ifdef ISTGT_USE_KQUEUE
//ISTGT_TRACELOG(ISTGT_TRACE_NET, "kevent %d\n", nidx);
kev_timeout.tv_sec = 10;
kev_timeout.tv_nsec = 0;
rc = kevent(kq, NULL, 0, &kev, 1, &kev_timeout);
if (rc == -1 && errno == EINTR) {
continue;
}
if (rc == -1) {
ISTGT_ERRLOG("kevent() failed\n");
break;
}
if (rc == 0) {
/* idle timeout */
//ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "kevent TIMEOUT\n");
continue;
}
if (kev.filter == EVFILT_SIGNAL) {
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "kevent SIGNAL\n");
if (kev.ident == SIGINT || kev.ident == SIGTERM) {
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
"kevent SIGNAL SIGINT/SIGTERM\n");
break;
}
continue;
}
#else
//ISTGT_TRACELOG(ISTGT_TRACE_NET, "poll %d\n", nidx);
rc = poll(fds, nidx, POLLWAIT);
if (rc == -1 && errno == EINTR) {
continue;
}
if (rc == -1) {
ISTGT_ERRLOG("poll() failed\n");
break;
}
if (rc == 0) {
/* no fds */
//ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "poll TIMEOUT\n");
continue;
}
#endif /* ISTGT_USE_KQUEUE */
n = rc;
for (i = 0; n != 0 && i < ucidx; i++) {
#ifdef ISTGT_USE_KQUEUE
if (kev.ident == (uintptr_t)kqsocks[i]) {
if (kev.flags) {
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
"flags %x\n",
kev.flags);
}
#else
if (fds[i].revents) {
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
"events %x\n",
fds[i].revents);
}
if (fds[i].revents & POLLIN) {
#endif /* ISTGT_USE_KQUEUE */
n--;
memset(&sa, 0, sizeof(sa));
salen = sizeof(sa);
#ifdef ISTGT_USE_KQUEUE
ISTGT_TRACELOG(ISTGT_TRACE_NET, "accept %ld\n",
(unsigned long)kev.ident);
pp = istgt_get_sock_portal(istgt, kev.ident);
rc = accept(kev.ident, (struct sockaddr *) &sa, &salen);
#else
ISTGT_TRACELOG(ISTGT_TRACE_NET, "accept %d\n",
fds[i].fd);
pp = istgt_get_sock_portal(istgt, fds[i].fd);
rc = accept(fds[i].fd, (struct sockaddr *) &sa, &salen);
#endif /* ISTGT_USE_KQUEUE */
if (rc < 0) {
ISTGT_ERRLOG("accept error: %d\n", rc);
continue;
}
sock = rc;
#if 0
rc = fcntl(sock, F_GETFL, 0);
if (rc == -1) {
ISTGT_ERRLOG("fcntl() failed\n");
continue;
}
rc = fcntl(sock, F_SETFL, (rc | O_NONBLOCK));
if (rc == -1) {
ISTGT_ERRLOG("fcntl() failed\n");
continue;
}
#endif
rc = istgt_create_conn(istgt, pp, sock,
(struct sockaddr *) &sa, salen);
if (rc < 0) {
close(sock);
ISTGT_ERRLOG("istgt_create_conn() failed\n");
continue;
}
}
}
/* check for control */
for (i = 0; n != 0 && i < istgt->nuctl_portal; i++) {
#ifdef ISTGT_USE_KQUEUE
if (kev.ident == (uintptr_t)istgt->uctl_portal[i].sock) {
if (kev.flags) {
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
"flags %x\n",
kev.flags);
}
#else
if (fds[ucidx + i].revents) {
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
"events %x\n",
fds[ucidx + i].revents);
}
if (fds[ucidx + i].revents & POLLIN) {
#endif /* ISTGT_USE_KQUEUE */
n--;
memset(&sa, 0, sizeof(sa));
salen = sizeof(sa);
#ifdef ISTGT_USE_KQUEUE
ISTGT_TRACELOG(ISTGT_TRACE_NET,
"accept %ld\n", (unsigned long)kev.ident);
rc = accept(kev.ident,
(struct sockaddr *) &sa, &salen);
#else
ISTGT_TRACELOG(ISTGT_TRACE_NET,
"accept %d\n", fds[ucidx + i].fd);
rc = accept(fds[ucidx + i].fd,
(struct sockaddr *) &sa, &salen);
#endif /* ISTGT_USE_KQUEUE */
if (rc < 0) {
ISTGT_ERRLOG("accept error: %d\n", rc);
continue;
}
sock = rc;
rc = istgt_create_uctl(istgt,
&istgt->uctl_portal[i], sock,
(struct sockaddr *) &sa, salen);
if (rc < 0) {
close(sock);
ISTGT_ERRLOG("istgt_create_uctl() failed\n");
continue;
}
}
}
/* check for signal thread */
#ifdef ISTGT_USE_KQUEUE
if (kev.ident == (uintptr_t)istgt->sig_pipe[0]) {
if (kev.flags & (EV_EOF|EV_ERROR)) {
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
"kevent EOF/ERROR\n");
break;
}
#else
if (fds[nidx - 1].revents & POLLHUP) {
break;
}
if (fds[nidx - 1].revents & POLLIN) {
#endif /* ISTGT_USE_KQUEUE */
char tmp[RELOAD_CMD_LENGTH];
//int pgp_idx;
int rc2;
rc = read(istgt->sig_pipe[0], tmp, RELOAD_CMD_LENGTH);
if (rc < 0 || rc == 0 || rc != RELOAD_CMD_LENGTH) {
ISTGT_ERRLOG("read() failed\n");
break;
}
//pgp_idx = (int)DGET32(&tmp[1]);
if (tmp[0] == 'E') {
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
"exit request (main loop)\n");
break;
}
if (tmp[0] == 'D') {
rc = istgt_pg_delete(istgt);
MTX_LOCK(&istgt->reload_mutex);
istgt->pg_reload = rc < 0 ? -1 : 1;
rc2 = pthread_cond_broadcast(&istgt->reload_cond);
if (rc2 != 0) {
ISTGT_ERRLOG("cond_broadcast() failed\n");
}
MTX_UNLOCK(&istgt->reload_mutex);
if (rc < 0) {
ISTGT_ERRLOG("pg_delete() failed\n");
//break;
}
}
if (tmp[0] == 'U') {
rc = istgt_pg_update(istgt);
MTX_LOCK(&istgt->reload_mutex);
istgt->pg_reload = rc < 0 ? -1 : 1;
rc2 = pthread_cond_broadcast(&istgt->reload_cond);
if (rc2 != 0) {
ISTGT_ERRLOG("cond_broadcast() failed\n");
}
MTX_UNLOCK(&istgt->reload_mutex);
if (rc < 0) {
ISTGT_ERRLOG("pg_update() failed\n");
//break;
}
}
#ifdef ISTGT_USE_KQUEUE
close(kq);
#endif /* ISTGT_USE_KQUEUE */
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "reload accept loop\n");
goto reload;
}
}
#ifdef ISTGT_USE_KQUEUE
close(kq);
#endif /* ISTGT_USE_KQUEUE */
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "loop ended\n");
istgt_set_state(istgt, ISTGT_STATE_EXITING);
istgt_lu_set_all_state(istgt, ISTGT_STATE_EXITING);
return 0;
}
static void
usage(void)
{
printf("istgt [options]\n");
printf("options:\n");
printf(" -c config config file (default %s)\n", DEFAULT_CONFIG);
printf(" -p pidfile use specific file\n");
printf(" -l facility use specific syslog facility (default %s)\n",
DEFAULT_LOG_FACILITY);
printf(" -m mode operational mode (default %d, 0=traditional, "
"1=normal, 2=experimental)\n", DEFAULT_ISTGT_SWMODE);
printf(" -t flag trace flag (all, net, iscsi, scsi, lu)\n");
printf(" -q quiet warnings\n");
printf(" -D don't detach from tty\n");
printf(" -H show this usage\n");
printf(" -V show version\n");
}
int
main(int argc, char **argv)
{
ISTGT_Ptr istgt;
const char *config_file = DEFAULT_CONFIG;
const char *pidfile = NULL;
const char *logfacility = NULL;
const char *logpriority = NULL;
CONFIG *config;
pthread_t sigthread;
struct sigaction sigact, sigoldact_pipe, sigoldact_int, sigoldact_term;
struct sigaction sigoldact_hup, sigoldact_info;
struct sigaction sigoldact_wakeup, sigoldact_io;
sigset_t signew, sigold;
int retry = 10;
int detach = 1;
int swmode;
int ch;
int rc;
if (sizeof (ISCSI_BHS) != ISCSI_BHS_LEN) {
fprintf(stderr, "Internal Error\n");
exit(EXIT_FAILURE);
}
memset(&g_istgt, 0, sizeof g_istgt);
istgt = &g_istgt;
istgt->state = ISTGT_STATE_INVALID;
istgt->swmode = DEFAULT_ISTGT_SWMODE;
istgt->sig_pipe[0] = istgt->sig_pipe[1] = -1;
istgt->daemon = 0;
istgt->generation = 0;
while ((ch = getopt(argc, argv, "c:p:l:m:t:qDHV")) != -1) {
switch (ch) {
case 'c':
config_file = optarg;
break;
case 'p':
pidfile = optarg;
break;
case 'l':
logfacility = optarg;
break;
case 'm':
swmode = strtol(optarg, NULL, 10);
if (swmode == ISTGT_SWMODE_TRADITIONAL
|| swmode == ISTGT_SWMODE_NORMAL
|| swmode == ISTGT_SWMODE_EXPERIMENTAL) {
istgt->swmode = swmode;
} else {
fprintf(stderr, "unknown mode %x\n", swmode);
usage();
exit(EXIT_FAILURE);
}
break;
case 't':
if (strcasecmp(optarg, "NET") == 0) {
istgt_set_trace_flag(ISTGT_TRACE_NET);
} else if (strcasecmp(optarg, "ISCSI") == 0) {
istgt_set_trace_flag(ISTGT_TRACE_ISCSI);
} else if (strcasecmp(optarg, "SCSI") == 0) {
istgt_set_trace_flag(ISTGT_TRACE_SCSI);
} else if (strcasecmp(optarg, "LU") == 0) {
istgt_set_trace_flag(ISTGT_TRACE_LU);
} else if (strcasecmp(optarg, "ALL") == 0) {
istgt_set_trace_flag(ISTGT_TRACE_ALL);
} else if (strcasecmp(optarg, "NONE") == 0) {
istgt_set_trace_flag(ISTGT_TRACE_NONE);
} else {
fprintf(stderr, "unknown flag\n");
usage();
exit(EXIT_FAILURE);
}
break;
case 'q':
g_warn_flag = 0;
break;
case 'D':
detach = 0;
break;
case 'V':
printf("istgt version %s\n", ISTGT_VERSION);
printf("istgt extra version %s\n", ISTGT_EXTRA_VERSION);
exit(EXIT_SUCCESS);
case 'H':
default:
usage();
exit(EXIT_SUCCESS);
}
}
/* read config files */
config = istgt_allocate_config();
rc = istgt_read_config(config, config_file);
if (rc < 0) {
fprintf(stderr, "config error\n");
exit(EXIT_FAILURE);
}
if (config->section == NULL) {
fprintf(stderr, "empty config\n");
istgt_free_config(config);
exit(EXIT_FAILURE);
}
istgt->config = config;
istgt->config_old = NULL;
//istgt_print_config(config);
/* open log files */
if (logfacility == NULL) {
logfacility = istgt_get_log_facility(config);
}
rc = istgt_set_log_facility(logfacility);
if (rc < 0) {
fprintf(stderr, "log facility error\n");
istgt_free_config(config);
exit(EXIT_FAILURE);
}
if (logpriority == NULL) {
logpriority = DEFAULT_LOG_PRIORITY;
}
rc = istgt_set_log_priority(logpriority);
if (rc < 0) {
fprintf(stderr, "log priority error\n");
istgt_free_config(config);
exit(EXIT_FAILURE);
}
istgt_open_log();
ISTGT_NOTICELOG("istgt version %s (%s)\n", ISTGT_VERSION,
ISTGT_EXTRA_VERSION);
switch (istgt->swmode) {
case ISTGT_SWMODE_TRADITIONAL:
ISTGT_NOTICELOG("traditional mode\n");
break;
case ISTGT_SWMODE_NORMAL:
ISTGT_NOTICELOG("normal mode\n");
break;
case ISTGT_SWMODE_EXPERIMENTAL:
ISTGT_NOTICELOG("experimental mode\n");
break;
default:
break;
}
#ifdef ISTGT_USE_KQUEUE
ISTGT_NOTICELOG("using kqueue\n");
#else
ISTGT_NOTICELOG("using poll\n");
#endif /* ISTGT_USE_KQUEUE */
#ifdef USE_ATOMIC
ISTGT_NOTICELOG("using host atomic\n");
#elif defined (USE_GCC_ATOMIC)
ISTGT_NOTICELOG("using gcc atomic\n");
#else
ISTGT_NOTICELOG("using generic atomic\n");
#endif /* USE_ATOMIC */
#ifdef ISTGT_USE_CRC32C_TABLE
/* build crc32c table */
istgt_init_crc32c_table();
#endif /* ISTGT_USE_CRC32C_TABLE */
/* initialize sub modules */
rc = istgt_init(istgt);
if (rc < 0) {
ISTGT_ERRLOG("istgt_init() failed\n");
initialize_error:
istgt_close_log();
istgt_free_config(config);
exit(EXIT_FAILURE);
}
rc = istgt_lu_init(istgt);
if (rc < 0) {
ISTGT_ERRLOG("istgt_lu_init() failed\n");
goto initialize_error;
}
rc = istgt_iscsi_init(istgt);
if (rc < 0) {
ISTGT_ERRLOG("istgt_iscsi_init() failed\n");
goto initialize_error;
}
/* override by command line */
if (pidfile != NULL) {
xfree(istgt->pidfile);
istgt->pidfile = xstrdup(pidfile);
}
/* detach from tty and run background */
fflush(stdout);
if (detach) {
istgt->daemon = 1;
rc = daemon(0, 0);
if (rc < 0) {
ISTGT_ERRLOG("daemon() failed\n");
goto initialize_error;
}
}
/* setup signal handler thread */
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "setup signal handler\n");
memset(&sigact, 0, sizeof sigact);
memset(&sigoldact_pipe, 0, sizeof sigoldact_pipe);
memset(&sigoldact_int, 0, sizeof sigoldact_int);
memset(&sigoldact_term, 0, sizeof sigoldact_term);
memset(&sigoldact_hup, 0, sizeof sigoldact_hup);
memset(&sigoldact_info, 0, sizeof sigoldact_info);
memset(&sigoldact_wakeup, 0, sizeof sigoldact_wakeup);
memset(&sigoldact_io, 0, sizeof sigoldact_io);
sigact.sa_handler = SIG_IGN;
sigemptyset(&sigact.sa_mask);
rc = sigaction(SIGPIPE, &sigact, &sigoldact_pipe);
if (rc < 0) {
ISTGT_ERRLOG("sigaction(SIGPIPE) failed\n");
goto initialize_error;
}
sigact.sa_handler = istgt_sigint;
sigemptyset(&sigact.sa_mask);
rc = sigaction(SIGINT, &sigact, &sigoldact_int);
if (rc < 0) {
ISTGT_ERRLOG("sigaction(SIGINT) failed\n");
goto initialize_error;
}
sigact.sa_handler = istgt_sigterm;
sigemptyset(&sigact.sa_mask);
rc = sigaction(SIGTERM, &sigact, &sigoldact_term);
if (rc < 0) {
ISTGT_ERRLOG("sigaction(SIGTERM) failed\n");
goto initialize_error;
}
sigact.sa_handler = istgt_sighup;
sigemptyset(&sigact.sa_mask);
rc = sigaction(SIGHUP, &sigact, &sigoldact_hup);
if (rc < 0) {
ISTGT_ERRLOG("sigaction(SIGHUP) failed\n");
goto initialize_error;
}
#ifdef SIGINFO
sigact.sa_handler = istgt_siginfo;
sigemptyset(&sigact.sa_mask);
rc = sigaction(SIGINFO, &sigact, &sigoldact_info);
if (rc < 0) {
ISTGT_ERRLOG("sigaction(SIGINFO) failed\n");
goto initialize_error;
}
#endif
#ifdef ISTGT_USE_SIGRT
if (ISTGT_SIGWAKEUP < SIGRTMIN
|| ISTGT_SIGWAKEUP > SIGRTMAX) {
ISTGT_ERRLOG("SIGRT error\n");
goto initialize_error;
}
#endif /* ISTGT_USE_SIGRT */
sigact.sa_handler = istgt_sigwakeup;
sigemptyset(&sigact.sa_mask);
rc = sigaction(ISTGT_SIGWAKEUP, &sigact, &sigoldact_wakeup);
if (rc < 0) {
ISTGT_ERRLOG("sigaction(ISTGT_SIGWAKEUP) failed\n");
goto initialize_error;
}
#ifdef SIGIO
sigact.sa_handler = istgt_sigio;
sigemptyset(&sigact.sa_mask);
rc = sigaction(SIGIO, &sigact, &sigoldact_io);
if (rc < 0) {
ISTGT_ERRLOG("sigaction(SIGIO) failed\n");
goto initialize_error;
}
#endif
pthread_sigmask(SIG_SETMASK, NULL, &signew);
sigaddset(&signew, SIGINT);
sigaddset(&signew, SIGTERM);
sigaddset(&signew, SIGQUIT);
sigaddset(&signew, SIGHUP);
#ifdef SIGINFO
sigaddset(&signew, SIGINFO);
#endif
sigaddset(&signew, SIGUSR1);
sigaddset(&signew, SIGUSR2);
#ifdef SIGIO
sigaddset(&signew, SIGIO);
#endif
sigaddset(&signew, ISTGT_SIGWAKEUP);
pthread_sigmask(SIG_SETMASK, &signew, &sigold);
#ifdef ISTGT_STACKSIZE
rc = pthread_create(&sigthread, &istgt->attr, &istgt_sighandler,
(void *) istgt);
#else
rc = pthread_create(&sigthread, NULL, &istgt_sighandler,
(void *) istgt);
#endif
if (rc != 0) {
ISTGT_ERRLOG("pthread_create() failed\n");
goto initialize_error;
}
#if 0
rc = pthread_detach(sigthread);
if (rc != 0) {
ISTGT_ERRLOG("pthread_detach() failed\n");
goto initialize_error;
}
#endif
#ifdef HAVE_PTHREAD_SET_NAME_NP
pthread_set_name_np(sigthread, "sigthread");
pthread_set_name_np(pthread_self(), "mainthread");
#endif
/* create LUN threads for command queuing */
rc = istgt_lu_create_threads(istgt);
if (rc < 0) {
ISTGT_ERRLOG("lu_create_threads() failed\n");
goto initialize_error;
}
rc = istgt_lu_set_all_state(istgt, ISTGT_STATE_RUNNING);
if (rc < 0) {
ISTGT_ERRLOG("lu_set_all_state() failed\n");
goto initialize_error;
}
/* open portals */
rc = istgt_open_uctl_portal(istgt);
if (rc < 0) {
ISTGT_ERRLOG("istgt_open_uctl_portal() failed\n");
goto initialize_error;
}
rc = istgt_open_all_portals(istgt);
if (rc < 0) {
ISTGT_ERRLOG("istgt_open_all_portals() failed\n");
goto initialize_error;
}
/* write pid */
rc = istgt_write_pidfile(istgt);
if (rc < 0) {
ISTGT_ERRLOG("istgt_write_pid() failed\n");
goto initialize_error;
}
/* accept loop */
rc = istgt_acceptor(istgt);
if (rc < 0) {
ISTGT_ERRLOG("istgt_acceptor() failed\n");
istgt_close_all_portals(istgt);
istgt_close_uctl_portal(istgt);
istgt_iscsi_shutdown(istgt);
istgt_lu_shutdown(istgt);
istgt_shutdown(istgt);
istgt_close_log();
config = istgt->config;
istgt->config = NULL;
istgt_free_config(config);
exit(EXIT_FAILURE);
}
/* wait threads */
istgt_stop_conns();
while (retry > 0) {
if (istgt_get_active_conns() == 0) {
break;
}
sleep(1);
retry--;
}
ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "retry=%d\n", retry);
ISTGT_NOTICELOG("istgt version %s (%s) exiting\n", ISTGT_VERSION,
ISTGT_EXTRA_VERSION);
/* stop signal thread */
rc = pthread_join(sigthread, NULL);
if (rc != 0) {
ISTGT_ERRLOG("pthread_join() failed\n");
exit (EXIT_FAILURE);
}
/* cleanup */
istgt_close_all_portals(istgt);
istgt_close_uctl_portal(istgt);
istgt_iscsi_shutdown(istgt);
istgt_lu_shutdown(istgt);
istgt_shutdown(istgt);
istgt_close_log();
config = istgt->config;
istgt->config = NULL;
istgt_free_config(config);
istgt->state = ISTGT_STATE_SHUTDOWN;
return 0;
}
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>