summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README74
-rw-r--r--doc/iscsiadm.812
-rw-r--r--usr/discovery.c56
-rw-r--r--usr/idbm.c114
-rw-r--r--usr/idbm.h15
-rw-r--r--usr/iscsiadm.c259
-rw-r--r--usr/iscsiadm.h2
-rw-r--r--usr/isns.c2
-rw-r--r--usr/mgmt_ipc.c4
-rw-r--r--usr/util.c2
10 files changed, 418 insertions, 122 deletions
diff --git a/README b/README
index 639524a..88178a4 100644
--- a/README
+++ b/README
@@ -174,10 +174,36 @@ Usage: iscsiadm [OPTION]
-m, --mode <op> specify operational mode op = <discovery|node>
-m discovery --type=[type] --interface=iscsi_ifacename \
- --portal=[ip:port] --login --print=[N]
+ --portal=[ip:port] --login --print=[N] \
+ --op=[op]=[NEW | UPDATE | DELETE]
perform [type] discovery for target portal with
ip-address [ip] and port [port].
+ By default this command will remove records
+ for portals no longer returned. And, if a portal is
+ returned by the target, then the discovery command
+ will create a new record or modify an existing one
+ with values from iscsi.conf and the command line.
+
+ [op] can be passed in multiple times to this
+ command, and it will alter the DB manipulation.
+
+ If [op] is passed in and the value is
+ "new", iscsiadm will add records for portals that do
+ not yet have records in the db.
+
+ If [op] is passed in and the value is
+ "update", iscsiadm will update records using info
+ from iscsi.conf and the command line for portals
+ that are returned during discovery and have
+ a record in the db.
+
+ if [op] is passed in and the value is "delete",
+ iscsiadm will delete records for portals that
+ were not returned during discovery.
+
+ See the example section for more info.
+
See below for how to setup iscsi ifaces for
software iscsi or override the system defaults.
@@ -346,7 +372,7 @@ with the name "iface0" this command will overwrite it.)
(This will set the hwaddress.)
# iscsiadm -m iface -I iface0 --op=update -n iface.hwaddress -v 00:0F:1F:92:6B:BF
-If you had sessions logged in iscsiadm will not update, delete or overwrite
+If you had sessions logged in iscsiadm will not update, overwrite
a iface. You must log out first. If you have a iface bound to a node/portal
but you have not logged in then, iscsiadm will update the config and
all existing bindings.
@@ -406,7 +432,49 @@ iscsiadm -m node -p ip:port -I iface0 --op=delete
discovery will be setup so that they can logged in through
those interfaces.
- - SendTargets iSCSI Discovery with a specific interface. If you
+ - SendTargets iSCSI Discovery updating existing records:
+
+ ./iscsiadm -m discovery -t sendtargets -p 192.168.1.1:3260 \
+ -o update
+
+ If there a record for targetX and portalY exists in the DB, and
+ is returned during discovery, it will be updated with the info
+ from the iscsi.conf. No new portals will be added and stale
+ portals will not be removed.
+
+ - SendTargets iSCSI Discovery deleting existing records:
+
+ ./iscsiadm -m discovery -t sendtargets -p 192.168.1.1:3260 \
+ -o delete
+
+ If there a record for targetX and portalY exists in the DB, but
+ is not returned during discovery it will be removed from the DB.
+ No new portals will be added and existing portal records will not
+ be changed.
+
+ Note: If a session is logged into portal we are going to delete
+ a record for, it will be logged out then the record will be
+ deleted.
+
+ - SendTargets iSCSI Discovery adding new records:
+
+ ./iscsiadm -m discovery -t sendtargets -p 192.168.1.1:3260 \
+ -o new
+
+ If there targetX and portalY is returned during discovery and does
+ not have a record, it will be added. Existing records are not
+ modified.
+
+ - SendTargets iSCSI Discovery using multiple ops:
+
+ ./iscsiadm -m discovery -t sendtargets -p 192.168.1.1:3260 \
+ -o new -o delete
+
+ This command will add new portals and delete records for portals
+ no longer returned. It will not change the record information for
+ existing portals.
+
+ - SendTargets iSCSI Discovery with a specific interface. If you
wish to only use a subset of the interfaces in /etc/iscsi/ifaces
then you can pass them in during discovery:
diff --git a/doc/iscsiadm.8 b/doc/iscsiadm.8
index f64f763..11f49e2 100644
--- a/doc/iscsiadm.8
+++ b/doc/iscsiadm.8
@@ -125,16 +125,14 @@ operator.
Specifies a database operator \fIop\fR. \fIop\fR must be one of
\fInew\fR, \fIdelete\fR, \fIupdate\fR or \fIshow\fR.
.IP
-This option is only valid for all modes, but delete should not be used on a running session.
+This option is valid for all modes except fw. Delete should not be used on a running session. If it is iscsiadm will stop the session and then delete the
+record.
.IP
-\fInew\fR is currently valid only for node, session and iface mode. It creates
-a new database record for a given \fIportal\fR (IP address and port number).
+\fInew\fR creates a new database record for a given \fIportal\fR (IP address and port number). In discovery mode, iscsiadm will create new records for portals returned by the target.
.IP
-\fIdelete\fR deletes a specified \fIrecid\fR.
+\fIdelete\fR deletes a specified \fIrecid\fR. In discovery node, iscsiadm will delete records for portals that are no longer returned.
.IP
-\fIupdate\fR is currently valid only for node, session, and iface mode.
-It updates a specified
-\fIrecid\fR with \fIname\fR to the specified \fIvalue\fR.
+\fIupdate\fR will update the \fIrecid\fR with \fIname\fR to the specified \fIvalue\fR. In discovery node the \fIrecid\fR, \fIname\fR and \fIvalue\fR arguments are not needed. The update operation will operate on the portals returned by the target, and will update the record with info from the config file and command line.
.IP
\fIshow\fR is the default behaviour for node, discovery and iface mode. It is
also used when there are no commands passed into session mode and a running
diff --git a/usr/discovery.c b/usr/discovery.c
index 80fc866..c5b6ac0 100644
--- a/usr/discovery.c
+++ b/usr/discovery.c
@@ -183,12 +183,13 @@ iterate_targets(iscsi_session_t *session, uint32_t ttt)
return 1;
}
-static int add_portal(idbm_t *db, discovery_rec_t *drec,
- struct list_head *ifaces, node_rec_t *rec,
- char *address, char *port, char *tag)
+static int add_portal(idbm_t *db, struct list_head *rec_list,
+ discovery_rec_t *drec, char *targetname, char *address,
+ char *port, char *tag)
{
struct sockaddr_storage ss;
char host[NI_MAXHOST];
+ struct node_rec *rec;
/* resolve the address, in case it was a DNS name */
if (resolve_address(address, port, &ss)) {
@@ -200,6 +201,16 @@ static int add_portal(idbm_t *db, discovery_rec_t *drec,
getnameinfo((struct sockaddr *) &ss, sizeof(ss),
host, sizeof(host), NULL, 0, NI_NUMERICHOST);
+ rec = calloc(1, sizeof(*rec));
+ if (!rec)
+ return 0;
+
+ idbm_node_setup_from_conf(db, rec);
+ rec->disc_type = drec->type;
+ rec->disc_port = drec->port;
+ strcpy(rec->disc_address, drec->address);
+
+ strncpy(rec->name, targetname, TARGET_NAME_MAXLEN);
if (tag && *tag)
rec->tpgt = atoi(tag);
else
@@ -210,21 +221,18 @@ static int add_portal(idbm_t *db, discovery_rec_t *drec,
rec->conn[0].port = ISCSI_LISTEN_PORT;
strncpy(rec->conn[0].address, address, NI_MAXHOST);
- if (idbm_add_nodes(db, rec, drec, ifaces))
- log_error("Could not add record for %s %s,%d,%d\n",
- rec->name, address, rec->conn[0].port, rec->tpgt);
+ list_add_tail(&rec->list, rec_list);
return 1;
}
static int
add_target_record(idbm_t *db, char *name, char *end,
- discovery_rec_t *drec, struct list_head *ifaces,
+ discovery_rec_t *drec, struct list_head *rec_list,
char *default_port)
{
char *text = NULL;
char *nul = name;
size_t length;
- node_rec_t rec;
/* address = IPv4
* address = [IPv6]
@@ -251,10 +259,6 @@ add_target_record(idbm_t *db, char *name, char *end,
log_error("TargetName %s too long, ignoring", name);
return 0;
}
-
- idbm_node_setup_from_conf(db, &rec);
- strncpy(rec.name, name, TARGET_NAME_MAXLEN);
-
text = name + length;
/* skip NULs after the name */
@@ -267,7 +271,7 @@ add_target_record(idbm_t *db, char *name, char *end,
log_error("no default address known for target %s",
name);
return 0;
- } else if (!add_portal(db, drec, ifaces, &rec, drec->address,
+ } else if (!add_portal(db, rec_list, drec, name, drec->address,
default_port, NULL)) {
log_error("failed to add default portal, ignoring "
"target %s", name);
@@ -305,7 +309,7 @@ add_target_record(idbm_t *db, char *name, char *end,
*temp = '\0';
}
- if (!add_portal(db, drec, ifaces, &rec, address, port,
+ if (!add_portal(db, rec_list, drec, name, address, port,
tag)) {
log_error("failed to add default portal, "
"ignoring target %s", name);
@@ -323,7 +327,7 @@ add_target_record(idbm_t *db, char *name, char *end,
static int
process_sendtargets_response(idbm_t *db, struct string_buffer *sendtargets,
int final, discovery_rec_t *drec,
- struct list_head *ifaces,
+ struct list_head *rec_list,
char *default_port)
{
char *start = buffer_data(sendtargets);
@@ -375,7 +379,7 @@ process_sendtargets_response(idbm_t *db, struct string_buffer *sendtargets,
* "TargetName=" prefix.
*/
if (!add_target_record(db, record + 11, text,
- drec, ifaces,
+ drec, rec_list,
default_port)) {
log_error(
"failed to add target record");
@@ -404,7 +408,7 @@ process_sendtargets_response(idbm_t *db, struct string_buffer *sendtargets,
"line %s",
record, record);
if (add_target_record (db, record + 11, text,
- drec, ifaces, default_port)) {
+ drec, rec_list, default_port)) {
num_targets++;
record = NULL;
truncate_buffer(sendtargets, 0);
@@ -684,7 +688,7 @@ setup_authentication(iscsi_session_t *session,
static int
process_recvd_pdu(idbm_t *db, struct iscsi_hdr *pdu,
discovery_rec_t *drec,
- struct list_head *ifaces,
+ struct list_head *rec_list,
iscsi_session_t *session,
struct string_buffer *sendtargets,
char *default_port,
@@ -721,22 +725,12 @@ process_recvd_pdu(idbm_t *db, struct iscsi_hdr *pdu,
memcpy(buffer_data(sendtargets) + curr_data_length,
data, dlength);
- /*
- * we got a response so clear out the current
- * db values
- *
- * TODO: should we make whether rm the current
- * values configurable (maybe a --clear option)
- */
- if (!*valid_text)
- idbm_new_discovery(db, drec);
*valid_text = 1;
-
/* process as much as we can right now */
process_sendtargets_response(db, sendtargets,
final,
drec,
- ifaces,
+ rec_list,
default_port);
if (final) {
@@ -828,7 +822,7 @@ done:
}
int discovery_sendtargets(idbm_t *db, discovery_rec_t *drec,
- struct list_head *ifaces)
+ struct list_head *rec_list)
{
iscsi_session_t *session;
struct pollfd pfd;
@@ -1125,7 +1119,7 @@ repoll:
/*
* process iSCSI PDU received
*/
- rc = process_recvd_pdu(db, pdu, drec, ifaces,
+ rc = process_recvd_pdu(db, pdu, drec, rec_list,
session, &sendtargets,
default_port,
&active, &valid_text, data);
diff --git a/usr/idbm.c b/usr/idbm.c
index bd46824..240c134 100644
--- a/usr/idbm.c
+++ b/usr/idbm.c
@@ -2094,14 +2094,16 @@ free_portal:
return rc;
}
-static int
-idbm_add_discovery(idbm_t *db, discovery_rec_t *newrec)
+int
+idbm_add_discovery(idbm_t *db, discovery_rec_t *newrec, int overwrite)
{
discovery_rec_t rec;
int rc;
if (!idbm_discovery_read(db, &rec, newrec->address,
newrec->port)) {
+ if (!overwrite)
+ return 0;
log_debug(7, "overwriting existing record");
} else
log_debug(7, "adding new DB record");
@@ -2159,7 +2161,8 @@ static int setup_disc_to_node_link(char *disc_portal, node_rec_t *rec)
return rc;
}
-int idbm_add_node(idbm_t *db, node_rec_t *newrec, discovery_rec_t *drec)
+int idbm_add_node(idbm_t *db, node_rec_t *newrec, discovery_rec_t *drec,
+ int overwrite)
{
node_rec_t rec;
char *node_portal, *disc_portal;
@@ -2168,7 +2171,10 @@ int idbm_add_node(idbm_t *db, node_rec_t *newrec, discovery_rec_t *drec)
if (!idbm_rec_read(db, &rec, newrec->name, newrec->tpgt,
newrec->conn[0].address, newrec->conn[0].port,
&newrec->iface)) {
- rc = idbm_delete_node(db, NULL, &rec);
+ if (!overwrite)
+ return 0;
+
+ rc = idbm_delete_node(db, &rec);
if (rc)
return rc;
log_debug(7, "overwriting existing record");
@@ -2221,8 +2227,26 @@ free_portal:
return rc;
}
-int idbm_add_nodes(idbm_t *db, node_rec_t *newrec, discovery_rec_t *drec,
- struct list_head *ifaces)
+static int idbm_bind_iface_to_node(struct node_rec *new_rec,
+ struct iface_rec *iface,
+ struct list_head *bound_recs)
+{
+ struct node_rec *clone_rec;
+
+ clone_rec = calloc(1, sizeof(*clone_rec));
+ if (!clone_rec)
+ return ENOMEM;
+
+ memcpy(clone_rec, new_rec, sizeof(*clone_rec));
+ INIT_LIST_HEAD(&clone_rec->list);
+ iface_copy(&clone_rec->iface, iface);
+ list_add_tail(&clone_rec->list, bound_recs);
+ return 0;
+}
+
+int idbm_bind_ifaces_to_node(idbm_t *db, struct node_rec *new_rec,
+ struct list_head *ifaces,
+ struct list_head *bound_recs)
{
struct iface_rec *iface, *tmp;
struct iscsi_transport *t;
@@ -2239,18 +2263,75 @@ int idbm_add_nodes(idbm_t *db, node_rec_t *newrec, discovery_rec_t *drec,
list_for_each_entry_safe(iface, tmp, &def_ifaces, list) {
list_del(&iface->list);
t = get_transport_by_name(iface->transport_name);
- if (!t) {
+ if (!t || t->caps & CAP_FW_DB) {
free(iface);
continue;
}
- if (t->caps & CAP_FW_DB) {
+ rc = idbm_bind_iface_to_node(new_rec, iface,
+ bound_recs);
+ free(iface);
+ if (rc)
+ return rc;
+ found = 1;
+ }
+
+ /* create default iface with old/default behavior */
+ if (!found) {
+ struct iface_rec def_iface;
+
+ iface_init(&def_iface);
+ return idbm_bind_iface_to_node(new_rec, &def_iface,
+ bound_recs);
+ }
+ } else {
+ list_for_each_entry(iface, ifaces, list) {
+ if (strcmp(iface->name, DEFAULT_IFACENAME) &&
+ !iface_is_bound(iface)) {
+ log_error("iface %s is not bound. Will not "
+ "bind node to it. Iface settings "
+ iface_fmt, iface->name,
+ iface_str(iface));
+ continue;
+ }
+
+ rc = idbm_bind_iface_to_node(new_rec, iface,
+ bound_recs);
+ if (rc)
+ return rc;
+ }
+ }
+ return 0;
+}
+
+/*
+ * remove this when isns is converted
+ */
+int idbm_add_nodes(idbm_t *db, node_rec_t *newrec, discovery_rec_t *drec,
+ struct list_head *ifaces, int update)
+{
+ struct iface_rec *iface, *tmp;
+ struct iscsi_transport *t;
+ int rc = 0, found = 0;
+
+ if (!ifaces || list_empty(ifaces)) {
+ struct list_head def_ifaces;
+
+ INIT_LIST_HEAD(&def_ifaces);
+ idbm_lock(db);
+ idbm_read_def_ifaces(&def_ifaces);
+ idbm_unlock(db);
+
+ list_for_each_entry_safe(iface, tmp, &def_ifaces, list) {
+ list_del(&iface->list);
+ t = get_transport_by_name(iface->transport_name);
+ if (!t || t->caps & CAP_FW_DB) {
free(iface);
continue;
}
iface_copy(&newrec->iface, iface);
- rc = idbm_add_node(db, newrec, drec);
+ rc = idbm_add_node(db, newrec, drec, update);
free(iface);
if (rc)
return rc;
@@ -2260,7 +2341,7 @@ int idbm_add_nodes(idbm_t *db, node_rec_t *newrec, discovery_rec_t *drec,
/* create default iface with old/default behavior */
if (!found) {
iface_init(&newrec->iface);
- return idbm_add_node(db, newrec, drec);
+ return idbm_add_node(db, newrec, drec, update);
}
} else {
list_for_each_entry(iface, ifaces, list) {
@@ -2274,7 +2355,7 @@ int idbm_add_nodes(idbm_t *db, node_rec_t *newrec, discovery_rec_t *drec,
}
iface_copy(&newrec->iface, iface);
- rc = idbm_add_node(db, newrec, drec);
+ rc = idbm_add_node(db, newrec, drec, update);
if (rc)
return rc;
}
@@ -2282,13 +2363,6 @@ int idbm_add_nodes(idbm_t *db, node_rec_t *newrec, discovery_rec_t *drec,
return 0;
}
-void idbm_new_discovery(idbm_t *db, discovery_rec_t *drec)
-{
- idbm_delete_discovery(db, drec);
- if (idbm_add_discovery(db, drec))
- log_error("can not update discovery record.");
-}
-
static void idbm_rm_disc_node_links(idbm_t *db, char *disc_dir)
{
char *target = NULL, *tpgt = NULL, *port = NULL;
@@ -2328,7 +2402,7 @@ static void idbm_rm_disc_node_links(idbm_t *db, char *disc_dir)
strncpy(rec->conn[0].address, address, NI_MAXHOST);
strncpy(rec->iface.name, iface_id, ISCSI_MAX_IFACE_LEN);
- if (idbm_delete_node(db, NULL, rec))
+ if (idbm_delete_node(db, rec))
log_error("Could not delete node %s/%s/%s,%s/%s",
NODE_CONFIG_DIR, target, address, port,
iface_id);
@@ -2438,7 +2512,7 @@ done:
return rc;
}
-int idbm_delete_node(idbm_t *db, void *data, node_rec_t *rec)
+int idbm_delete_node(idbm_t *db, node_rec_t *rec)
{
struct stat statb;
char *portal;
diff --git a/usr/idbm.h b/usr/idbm.h
index 9664031..676e8b3 100644
--- a/usr/idbm.h
+++ b/usr/idbm.h
@@ -110,13 +110,18 @@ extern int idbm_print_discovered(idbm_t *db, discovery_rec_t *drec,
int info_level);
extern int idbm_delete_discovery(idbm_t *db, discovery_rec_t *rec);
extern void idbm_node_setup_defaults(node_rec_t *rec);
-extern int idbm_delete_node(idbm_t *db, void *data, node_rec_t *rec);
-extern int idbm_add_node(idbm_t *db, node_rec_t *newrec, discovery_rec_t *drec);
-
+extern int idbm_delete_node(idbm_t *db, node_rec_t *rec);
+extern int idbm_add_node(idbm_t *db, node_rec_t *newrec, discovery_rec_t *drec,
+ int overwrite);
struct list_head;
+extern int idbm_bind_ifaces_to_node(idbm_t *db, struct node_rec *new_rec,
+ struct list_head *ifaces,
+ struct list_head *bound_recs);
extern int idbm_add_nodes(idbm_t *db, node_rec_t *newrec,
- discovery_rec_t *drec, struct list_head *ifaces);
-extern void idbm_new_discovery(idbm_t *db, discovery_rec_t *drec);
+ discovery_rec_t *drec, struct list_head *ifaces,
+ int overwrite);
+extern int idbm_add_discovery(idbm_t *db, discovery_rec_t *newrec,
+ int overwrite);
extern void idbm_sendtargets_defaults(idbm_t *db,
struct iscsi_sendtargets_config *cfg);
extern void idbm_slp_defaults(idbm_t *db, struct iscsi_slp_config *cfg);
diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c
index e86f00d..ad074b8 100644
--- a/usr/iscsiadm.c
+++ b/usr/iscsiadm.c
@@ -55,10 +55,11 @@ enum iscsiadm_mode {
};
enum iscsiadm_op {
- OP_NEW,
- OP_DELETE,
- OP_UPDATE,
- OP_SHOW,
+ OP_NOOP = 0x0,
+ OP_NEW = 0x1,
+ OP_DELETE = 0x2,
+ OP_UPDATE = 0x4,
+ OP_SHOW = 0x8,
};
static struct option const long_options[] =
@@ -121,7 +122,7 @@ str_to_op(char *str)
else if (!strcmp("show", str))
op = OP_SHOW;
else
- op = -1;
+ op = OP_NOOP;
return op;
}
@@ -1321,7 +1322,7 @@ static int add_static_rec(idbm_t *db, int *found, char *targetname, int tpgt,
iface_copy(&rec->iface, iface);
}
- rc = idbm_add_node(db, rec, drec);
+ rc = idbm_add_node(db, rec, drec, 1);
if (!rc) {
(*found)++;
printf("New iSCSI node [%s:" iface_fmt " %s,%d,%d %s] added\n",
@@ -1431,35 +1432,196 @@ static int login_discovered_portal(void *data, struct list_head *list,
return 0;
}
+/* TODO merge with initiator.c implementation */
+/* And add locking */
+static int check_for_session_through_iface(struct node_rec *rec)
+{
+ int nr_found = 0;
+ if (sysfs_for_each_session(rec, &nr_found, iscsi_match_session))
+ return 1;
+ return 0;
+}
+
+static int delete_node(struct idbm *db, void *data, struct node_rec *rec)
+{
+ if (check_for_session_through_iface(rec)) {
+ /*
+ * perf is not important in this path, so do not worry
+ * about doing a async logout
+ */
+ switch (iscsid_req(MGMT_IPC_SESSION_LOGOUT, rec)) {
+ case MGMT_IPC_ERR_NOT_FOUND:
+ case MGMT_IPC_OK:
+ break;
+ default:
+ log_error("Could not remove record, because there "
+ "is a session to the portal that cannot "
+ "stopped. Please log out session: "
+ "[iface: %s, target: %s, portal: %s,%d]"
+ "and then remove record.",
+ rec->iface.name, rec->name,
+ rec->conn[0].address, rec->conn[0].port);
+ return EINVAL;
+ }
+ }
+ return idbm_delete_node(db, rec);
+}
+
+static int delete_stale_recs(struct idbm *db, void *data, struct node_rec *rec)
+{
+ struct list_head *new_rec_list = data;
+ struct node_rec *new_rec;
+
+ list_for_each_entry(new_rec, new_rec_list, list) {
+ /*
+ * We could also move this to idbm.c and instead of looping
+ * over every node just loop over disc to node links.
+ */
+ if (rec->disc_type != new_rec->disc_type ||
+ rec->disc_port != new_rec->disc_port ||
+ strcmp(rec->disc_address, new_rec->disc_address))
+ /*
+ * if we are not from the same discovery source
+ * ignore it
+ */
+ return 0;
+
+ /*
+ * we only care if the target endpoint matches, because
+ * it is gone and we want to logout all sessions with
+ * that endpoint, so we pass in null for the iface.
+ */
+ if (__iscsi_match_session(rec,
+ new_rec->name,
+ new_rec->conn[0].address,
+ new_rec->conn[0].port,
+ &new_rec->iface))
+ return 0;
+ }
+ /* if there is a error we can continue on */
+ delete_node(db, NULL, rec);
+ return 0;
+}
+
static int
-do_sofware_sendtargets(idbm_t *db, discovery_rec_t *drec,
- struct list_head *ifaces, int info_level, int do_login)
+update_discovery_recs(idbm_t *db, discovery_rec_t *drec,
+ struct list_head *new_rec_list, struct list_head *ifaces,
+ int info_level, int do_login, int op)
{
- int rc, err, nr_found = 0;
- struct list_head rec_list;
+ int rc, err, found = 0;
+ struct list_head bound_rec_list;
+ struct node_rec *new_rec, *tmp;
+
+ INIT_LIST_HEAD(&bound_rec_list);
+
+ /* bind ifaces to node recs so we know what we have */
+ list_for_each_entry(new_rec, new_rec_list, list) {
+ rc = idbm_bind_ifaces_to_node(db, new_rec, ifaces,
+ &bound_rec_list);
+ if (rc)
+ goto free_bound_recs;
+ }
+
+
+ /* clean up node db */
+ if (op & OP_DELETE)
+ idbm_for_each_rec(db, &found, &bound_rec_list,
+ delete_stale_recs);
+
+ if (op & OP_NEW || op & OP_UPDATE) {
+ /* now add/update records */
+ list_for_each_entry(new_rec, &bound_rec_list, list) {
+ int update = op & OP_UPDATE;
+
+ if (update &&
+ check_for_session_through_iface(new_rec)) {
+ log_warning("Could not update record for "
+ "[iface: %s, target: %s, portal: "
+ "%s,%d], because session is "
+ "logged in. Log out session "
+ "then retry operation, or run "
+ "discovery without the 'update' "
+ "option.",
+ new_rec->iface.name, new_rec->name,
+ new_rec->conn[0].address,
+ new_rec->conn[0].port);
+ continue;
+ }
- drec->type = DISCOVERY_TYPE_SENDTARGETS;
- rc = discovery_sendtargets(db, drec, ifaces);
- if (rc)
- return rc;
+ rc = idbm_add_node(db, new_rec, drec, update);
+ if (rc)
+ log_error("Could not add/update "
+ "[%s:" iface_fmt " %s,%d,%d %s]",
+ new_rec->iface.transport_name,
+ iface_str(&new_rec->iface),
+ new_rec->conn[0].address,
+ new_rec->conn[0].port,
+ new_rec->tpgt, new_rec->name);
+ }
+ }
idbm_print_discovered(db, drec, info_level);
- if (!do_login)
- return 0;
+ if (!do_login) {
+ rc = 0;
+ goto free_bound_recs;
+ }
- INIT_LIST_HEAD(&rec_list);
- rc = idbm_for_each_rec(db, &nr_found, &rec_list, link_recs);
- err = __login_portals(drec, &nr_found, &rec_list,
+ err = __login_portals(drec, &found, &bound_rec_list,
login_discovered_portal);
if (err && !rc)
rc = err;
+
+free_bound_recs:
+ list_for_each_entry_safe(new_rec, tmp, &bound_rec_list, list) {
+ list_del(&new_rec->list);
+ free(new_rec);
+ }
+ return rc;
+}
+
+static int
+do_sofware_sendtargets(idbm_t *db, discovery_rec_t *drec,
+ struct list_head *ifaces, int info_level, int do_login,
+ int op)
+{
+ struct list_head new_rec_list;
+ struct node_rec *new_rec, *tmp;
+ int rc;
+
+ INIT_LIST_HEAD(&new_rec_list);
+ /*
+ * compat: if the user did not pass any op then we do all
+ * ops for them
+ */
+ if (!op)
+ op = OP_NEW | OP_DELETE | OP_UPDATE;
+
+ drec->type = DISCOVERY_TYPE_SENDTARGETS;
+ rc = discovery_sendtargets(db, drec, &new_rec_list);
+ if (rc)
+ return rc;
+
+ rc = idbm_add_discovery(db, drec, op & OP_UPDATE);
+ if (rc) {
+ log_error("Could not add new discovery record.");
+ goto free_new_recs;
+ }
+
+ rc = update_discovery_recs(db, drec, &new_rec_list, ifaces,
+ info_level, do_login, op);
+
+free_new_recs:
+ list_for_each_entry_safe(new_rec, tmp, &new_rec_list, list) {
+ list_del(&new_rec->list);
+ free(new_rec);
+ }
return rc;
}
static int
do_sendtargets(idbm_t *db, discovery_rec_t *drec, struct list_head *ifaces,
- int info_level, int do_login)
+ int info_level, int do_login, int op)
{
struct iface_rec *tmp, *iface;
int rc, host_no;
@@ -1519,7 +1681,8 @@ do_sendtargets(idbm_t *db, discovery_rec_t *drec, struct list_head *ifaces,
return ENODEV;
sw_st:
- return do_sofware_sendtargets(db, drec, ifaces, info_level, do_login);
+ return do_sofware_sendtargets(db, drec, ifaces, info_level, do_login,
+ op);
}
/* TODO: merge this with the idbm code */
@@ -1584,16 +1747,6 @@ static void catch_sigint( int signo ) {
exit(1);
}
-/* TODO merge with initiator.c implementation */
-/* And add locking */
-static int check_for_session_through_iface(struct node_rec *rec)
-{
- int nr_found = 0;
- if (sysfs_for_each_session(rec, &nr_found, iscsi_match_session))
- return 1;
- return 0;
-}
-
static int exec_iface_op(idbm_t *db, int op, int do_show, int info_level,
struct iface_rec *iface, char *name, char *value)
{
@@ -1641,13 +1794,8 @@ new_fail:
}
if (iface_is_bound(&rec->iface)) {
- if (check_for_session_through_iface(rec)) {
- rc = EBUSY;
- goto delete_fail;
- }
-
- /* delete node records using it first */
- rc = __for_each_rec(db, 0, rec, NULL, idbm_delete_node);
+ /* logout and delete records using it first */
+ rc = __for_each_rec(db, 0, rec, NULL, delete_node);
if (rc && rc != ENODEV)
goto delete_fail;
}
@@ -1732,7 +1880,7 @@ update_fail:
iface->name);
break;
default:
- if (op < 0 || op == OP_SHOW)
+ if (op == OP_NOOP || op == OP_SHOW)
rc = print_ifaces(db, info_level);
else
rc = EINVAL;
@@ -1781,14 +1929,14 @@ static int exec_node_op(idbm_t *db, int op, int do_login, int do_logout,
goto out;
}
- if ((do_login || do_logout) && op >= 0) {
+ if ((do_login || do_logout) && op > OP_NOOP) {
log_error("either operation or login/logout "
"at the time allowed!");
rc = -1;
goto out;
}
- if ((!do_login && !do_logout && op < 0) &&
+ if ((!do_login && !do_logout && op == OP_NOOP) &&
(!strlen(rec->name) && !strlen(rec->conn[0].address) &&
!strlen(rec->iface.name))) {
rc = print_nodes(db, info_level, rec);
@@ -1807,7 +1955,7 @@ static int exec_node_op(idbm_t *db, int op, int do_login, int do_logout,
goto out;
}
- if (op < 0 || (!do_login && !do_logout && op == OP_SHOW)) {
+ if (op == OP_NOOP || (!do_login && !do_logout && op == OP_SHOW)) {
if (for_each_rec(db, rec, &do_show, idbm_print_node_info))
rc = -1;
goto out;
@@ -1824,11 +1972,19 @@ static int exec_node_op(idbm_t *db, int op, int do_login, int do_logout,
set_param.name = name;
set_param.value = value;
+ if (check_for_session_through_iface(rec)) {
+ log_error("Could not update record, because a "
+ "session is accessing it. Please log "
+ "out session, then retry operation.");
+ rc = -1;
+ goto out;
+ }
+
if (for_each_rec(db, rec, &set_param, idbm_node_set_param))
rc = -1;
goto out;
} else if (op == OP_DELETE) {
- if (for_each_rec(db, rec, NULL, idbm_delete_node))
+ if (for_each_rec(db, rec, NULL, delete_node))
rc = -1;
goto out;
} else {
@@ -1962,9 +2118,9 @@ main(int argc, char **argv)
char *ip = NULL, *name = NULL, *value = NULL;
char *targetname = NULL, *group_session_mgmt_mode = NULL;
int ch, longindex, mode=-1, port=-1, do_login=0, do_rescan=0;
- int rc=0, sid=-1, op=-1, type=-1, do_logout=0, do_stats=0, do_show=0;
+ int rc=0, sid=-1, op=OP_NOOP, type=-1, do_logout=0, do_stats=0;
int do_login_all=0, do_logout_all=0, info_level=-1, num_ifaces = 0;
- int tpgt = PORTAL_GROUP_TAG_UNKNOWN, killiscsid=-1;
+ int tpgt = PORTAL_GROUP_TAG_UNKNOWN, killiscsid=-1, do_show=0;
idbm_t *db = NULL;
struct sigaction sa_old;
struct sigaction sa_new;
@@ -2006,8 +2162,8 @@ main(int argc, char **argv)
type = str_to_type(optarg);
break;
case 'o':
- op = str_to_op(optarg);
- if (op < 0) {
+ op |= str_to_op(optarg);
+ if (op == OP_NOOP) {
log_error("can not recognize operation: '%s'",
optarg);
return -1;
@@ -2167,7 +2323,7 @@ main(int argc, char **argv)
drec.port = port;
if (do_sendtargets(db, &drec, &ifaces, info_level,
- do_login)) {
+ do_login, op)) {
rc = -1;
goto out;
}
@@ -2199,7 +2355,8 @@ main(int argc, char **argv)
if (do_login &&
drec.type == DISCOVERY_TYPE_SENDTARGETS) {
do_sendtargets(db, &drec, &ifaces,
- info_level, do_login);
+ info_level, do_login,
+ op);
} else if (do_login &&
drec.type == DISCOVERY_TYPE_SLP) {
log_error("SLP discovery is not fully "
@@ -2212,7 +2369,7 @@ main(int argc, char **argv)
"implemented yet.");
rc = -1;
goto out;
- } else if (op < 0 || op == OP_SHOW) {
+ } else if (op == OP_NOOP || op == OP_SHOW) {
if (!idbm_print_discovery_info(db,
&drec, do_show)) {
log_error("no records found!");
@@ -2230,7 +2387,7 @@ main(int argc, char **argv)
goto out;
}
- } else if (op < 0 || op == OP_SHOW) {
+ } else if (op == OP_NOOP || op == OP_SHOW) {
if (!idbm_print_all_discovery(db, info_level))
rc = -1;
goto out;
diff --git a/usr/iscsiadm.h b/usr/iscsiadm.h
index f707984..76ac2ec 100644
--- a/usr/iscsiadm.h
+++ b/usr/iscsiadm.h
@@ -29,7 +29,7 @@ struct discovery_rec;
struct list_head;
extern int discovery_sendtargets(struct idbm *db, struct discovery_rec *drec,
- struct list_head *ifaces);
+ struct list_head *rec_list);
extern int discovery_offload_sendtargets(struct idbm *db, int host_no,
int do_login, discovery_rec_t *drec);
#endif /* ISCSIADM_H */
diff --git a/usr/isns.c b/usr/isns.c
index 191b58b..69a9c83 100644
--- a/usr/isns.c
+++ b/usr/isns.c
@@ -309,7 +309,7 @@ static void add_new_target_node(char *targetname, uint8_t *ip, int port,
/* TODO?: shoudl we set the address and port of the server ? */
memset(&drec, 0, sizeof(discovery_rec_t));
drec.type = DISCOVERY_TYPE_ISNS;
- err = idbm_add_nodes(db, &rec, &drec, NULL);
+ err = idbm_add_nodes(db, &rec, &drec, NULL, 0);
if (err)
log_error("Could not add new target node:%s %s,%d",
targetname, dst, port);
diff --git a/usr/mgmt_ipc.c b/usr/mgmt_ipc.c
index cb6daa1..3567ac0 100644
--- a/usr/mgmt_ipc.c
+++ b/usr/mgmt_ipc.c
@@ -139,7 +139,7 @@ mgmt_ipc_session_logout(queue_task_t *qtask)
iscsi_session_t *session;
if (!(session = session_find_by_rec(rec))) {
- log_error("session [%s,%s,%d] not found!", rec->name,
+ log_debug(1, "session [%s,%s,%d] not found!", rec->name,
rec->conn[0].address, rec->conn[0].port);
return MGMT_IPC_ERR_NOT_FOUND;
}
@@ -172,7 +172,7 @@ mgmt_ipc_session_info(queue_task_t *qtask)
struct ipc_msg_session_state *info;
if (!(session = session_find_by_sid(sid))) {
- log_error("session with sid %d not found!", sid);
+ log_debug(1, "session with sid %d not found!", sid);
return MGMT_IPC_ERR_NOT_FOUND;
}
diff --git a/usr/util.c b/usr/util.c
index 59bcf57..90008f3 100644
--- a/usr/util.c
+++ b/usr/util.c
@@ -313,7 +313,7 @@ int __iscsi_match_session(node_rec_t *rec, char *targetname,
if (rec->conn[0].port != -1 && port != rec->conn[0].port)
return 0;
- if (strlen(rec->iface.transport_name) &&
+ if (iface && strlen(rec->iface.transport_name) &&
strcmp(rec->iface.transport_name, iface->transport_name))
return 0;