iscsi: make target management thread-safe by linked list
Current fixed sized array for iSCSI target is not thread safe. When newly created targets are inserted into the array, multiple targets may be inserted into the same position. Linked list is better than fixed size array to support dynamic reconfiguration. Change-Id: I4db5a3ec16844db06e0cfcd2aef1f97952f15afa Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com> Reviewed-on: https://review.gerrithub.io/385371 Tested-by: SPDK Automated Test System <sys_sgsw@intel.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com>
This commit is contained in:
parent
c2f38258f9
commit
f4e892fe14
@ -61,7 +61,6 @@
|
||||
#define MAX_NETMASK 256
|
||||
#define MAX_PORTAL_GROUP 4096
|
||||
#define MAX_INITIATOR_GROUP 4096
|
||||
#define MAX_ISCSI_TARGET_NODE 4096
|
||||
#define MAX_SESSIONS 1024
|
||||
#define MAX_ISCSI_CONNECTIONS MAX_SESSIONS
|
||||
#define MAX_FIRSTBURSTLENGTH 16777215
|
||||
@ -264,7 +263,7 @@ struct spdk_iscsi_globals {
|
||||
TAILQ_HEAD(, spdk_iscsi_portal_grp) pg_head;
|
||||
TAILQ_HEAD(, spdk_iscsi_init_grp) ig_head;
|
||||
int ntargets;
|
||||
struct spdk_iscsi_tgt_node *target[MAX_ISCSI_TARGET_NODE];
|
||||
TAILQ_HEAD(, spdk_iscsi_tgt_node) target_head;
|
||||
|
||||
int timeout;
|
||||
int nopininterval;
|
||||
|
@ -253,9 +253,8 @@ static void
|
||||
spdk_rpc_get_target_nodes(struct spdk_jsonrpc_request *request,
|
||||
const struct spdk_json_val *params)
|
||||
{
|
||||
struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi;
|
||||
struct spdk_json_write_ctx *w;
|
||||
size_t tgt_idx;
|
||||
struct spdk_iscsi_tgt_node *tgtnode;
|
||||
int i;
|
||||
|
||||
if (params != NULL) {
|
||||
@ -271,13 +270,7 @@ spdk_rpc_get_target_nodes(struct spdk_jsonrpc_request *request,
|
||||
|
||||
spdk_json_write_array_begin(w);
|
||||
|
||||
for (tgt_idx = 0 ; tgt_idx < MAX_ISCSI_TARGET_NODE; tgt_idx++) {
|
||||
struct spdk_iscsi_tgt_node *tgtnode = iscsi->target[tgt_idx];
|
||||
|
||||
if (tgtnode == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
TAILQ_FOREACH(tgtnode, &g_spdk_iscsi.target_head, tailq) {
|
||||
spdk_json_write_object_begin(w);
|
||||
|
||||
spdk_json_write_name(w, "name");
|
||||
|
@ -228,22 +228,19 @@ static const char *target_nodes_section = \
|
||||
static void
|
||||
spdk_iscsi_config_dump_target_nodes(FILE *fp)
|
||||
{
|
||||
int t = 0, l = 0, m = 0;
|
||||
int l = 0, m = 0;
|
||||
struct spdk_scsi_dev *dev = NULL;
|
||||
struct spdk_iscsi_tgt_node *target = NULL;
|
||||
|
||||
/* Create target nodes section */
|
||||
fprintf(fp, "%s", target_nodes_section);
|
||||
|
||||
for (t = 0; t < MAX_ISCSI_TARGET_NODE; t++) {
|
||||
TAILQ_FOREACH(target, &g_spdk_iscsi.target_head, tailq) {
|
||||
int idx;
|
||||
const char *authmethod = "None";
|
||||
char authgroup[32] = "None";
|
||||
const char *usedigest = "Auto";
|
||||
|
||||
target = g_spdk_iscsi.target[t];
|
||||
if (NULL == target) continue;
|
||||
|
||||
dev = target->dev;
|
||||
if (NULL == dev) continue;
|
||||
|
||||
|
@ -300,7 +300,7 @@ spdk_iscsi_send_tgts(struct spdk_iscsi_conn *conn, const char *iiqn,
|
||||
int len;
|
||||
int rc;
|
||||
int pg_tag;
|
||||
int i, j, k;
|
||||
int i, j;
|
||||
|
||||
if (conn == NULL)
|
||||
return 0;
|
||||
@ -321,10 +321,7 @@ spdk_iscsi_send_tgts(struct spdk_iscsi_conn *conn, const char *iiqn,
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&g_spdk_iscsi.mutex);
|
||||
for (i = 0; i < MAX_ISCSI_TARGET_NODE; i++) {
|
||||
target = g_spdk_iscsi.target[i];
|
||||
if (target == NULL)
|
||||
continue;
|
||||
TAILQ_FOREACH(target, &g_spdk_iscsi.target_head, tailq) {
|
||||
if (strcasecmp(tiqn, "ALL") != 0
|
||||
&& strcasecmp(tiqn, target->name) != 0) {
|
||||
continue;
|
||||
@ -339,11 +336,11 @@ spdk_iscsi_send_tgts(struct spdk_iscsi_conn *conn, const char *iiqn,
|
||||
"TargetName=%s", target->name);
|
||||
total += len + 1;
|
||||
|
||||
for (j = 0; j < target->maxmap; j++) {
|
||||
pg_tag = target->map[j].pg->tag;
|
||||
for (i = 0; i < target->maxmap; i++) {
|
||||
pg_tag = target->map[i].pg->tag;
|
||||
/* skip same pg_tag */
|
||||
for (k = 0; k < j; k++) {
|
||||
if (target->map[k].pg->tag == pg_tag) {
|
||||
for (j = 0; j < i; j++) {
|
||||
if (target->map[j].pg->tag == pg_tag) {
|
||||
goto skip_pg_tag;
|
||||
}
|
||||
}
|
||||
@ -393,18 +390,21 @@ skip_pg_tag:
|
||||
return total;
|
||||
}
|
||||
|
||||
static void
|
||||
spdk_iscsi_tgt_node_list_init(void)
|
||||
{
|
||||
g_spdk_iscsi.ntargets = 0;
|
||||
TAILQ_INIT(&g_spdk_iscsi.target_head);
|
||||
}
|
||||
|
||||
struct spdk_iscsi_tgt_node *
|
||||
spdk_iscsi_find_tgt_node(const char *target_name)
|
||||
{
|
||||
struct spdk_iscsi_tgt_node *target;
|
||||
int i;
|
||||
|
||||
if (target_name == NULL)
|
||||
return NULL;
|
||||
for (i = 0; i < MAX_ISCSI_TARGET_NODE; i++) {
|
||||
target = g_spdk_iscsi.target[i];
|
||||
if (target == NULL)
|
||||
continue;
|
||||
TAILQ_FOREACH(target, &g_spdk_iscsi.target_head, tailq) {
|
||||
if (strcasecmp(target_name, target->name) == 0) {
|
||||
return target;
|
||||
}
|
||||
@ -413,6 +413,39 @@ spdk_iscsi_find_tgt_node(const char *target_name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
spdk_iscsi_tgt_node_register(struct spdk_iscsi_tgt_node *target)
|
||||
{
|
||||
pthread_mutex_lock(&g_spdk_iscsi.mutex);
|
||||
|
||||
if (spdk_iscsi_find_tgt_node(target->name) != NULL) {
|
||||
pthread_mutex_unlock(&g_spdk_iscsi.mutex);
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
TAILQ_INSERT_TAIL(&g_spdk_iscsi.target_head, target, tailq);
|
||||
g_spdk_iscsi.ntargets++;
|
||||
|
||||
pthread_mutex_unlock(&g_spdk_iscsi.mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
spdk_iscsi_tgt_node_unregister(struct spdk_iscsi_tgt_node *target)
|
||||
{
|
||||
struct spdk_iscsi_tgt_node *t;
|
||||
|
||||
TAILQ_FOREACH(t, &g_spdk_iscsi.target_head, tailq) {
|
||||
if (t == target) {
|
||||
TAILQ_REMOVE(&g_spdk_iscsi.target_head, t, tailq);
|
||||
g_spdk_iscsi.ntargets--;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
spdk_check_iscsi_name(const char *name)
|
||||
{
|
||||
@ -476,17 +509,6 @@ spdk_iscsi_tgt_node_destruct(struct spdk_iscsi_tgt_node *target)
|
||||
free(target);
|
||||
}
|
||||
|
||||
static int spdk_get_next_available_tgt_number(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_ISCSI_TARGET_NODE; i++) {
|
||||
if (g_spdk_iscsi.target[i] == NULL)
|
||||
break;
|
||||
}
|
||||
return i; //Returns MAX_TARGET if none available.
|
||||
}
|
||||
|
||||
static struct spdk_iscsi_tgt_node_map *
|
||||
spdk_iscsi_tgt_node_add_map(struct spdk_iscsi_tgt_node *target,
|
||||
int pg_tag, int ig_tag)
|
||||
@ -561,19 +583,6 @@ spdk_iscsi_tgt_node_construct(int target_index,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (target_index == -1)
|
||||
target_index = spdk_get_next_available_tgt_number();
|
||||
|
||||
if (target_index >= MAX_ISCSI_TARGET_NODE) {
|
||||
SPDK_ERRLOG("%d over maximum unit number\n", target_index);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (g_spdk_iscsi.target[target_index] != NULL) {
|
||||
SPDK_ERRLOG("tgt_node%d: duplicate unit\n", target_index);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (name == NULL) {
|
||||
SPDK_ERRLOG("TargetName not found\n");
|
||||
return NULL;
|
||||
@ -684,10 +693,12 @@ spdk_iscsi_tgt_node_construct(int target_index,
|
||||
}
|
||||
target->queue_depth = queue_depth;
|
||||
|
||||
pthread_mutex_lock(&g_spdk_iscsi.mutex);
|
||||
g_spdk_iscsi.ntargets++;
|
||||
g_spdk_iscsi.target[target->num] = target;
|
||||
pthread_mutex_unlock(&g_spdk_iscsi.mutex);
|
||||
rc = spdk_iscsi_tgt_node_register(target);
|
||||
if (rc != 0) {
|
||||
SPDK_ERRLOG("register target is failed\n");
|
||||
spdk_iscsi_tgt_node_destruct(target);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
@ -912,6 +923,8 @@ int spdk_iscsi_init_tgt_nodes(void)
|
||||
|
||||
SPDK_DEBUGLOG(SPDK_TRACE_ISCSI, "spdk_iscsi_init_tgt_nodes\n");
|
||||
|
||||
spdk_iscsi_tgt_node_list_init();
|
||||
|
||||
sp = spdk_conf_first_section(NULL);
|
||||
while (sp != NULL) {
|
||||
if (spdk_conf_section_match_prefix(sp, "TargetNode")) {
|
||||
@ -932,50 +945,37 @@ int spdk_iscsi_init_tgt_nodes(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
void
|
||||
spdk_iscsi_shutdown_tgt_nodes(void)
|
||||
{
|
||||
struct spdk_iscsi_tgt_node *target;
|
||||
int i;
|
||||
struct spdk_iscsi_tgt_node *target, *tmp;
|
||||
|
||||
pthread_mutex_lock(&g_spdk_iscsi.mutex);
|
||||
for (i = 0; i < MAX_ISCSI_TARGET_NODE; i++) {
|
||||
target = g_spdk_iscsi.target[i];
|
||||
if (target == NULL)
|
||||
continue;
|
||||
spdk_iscsi_tgt_node_destruct(target);
|
||||
TAILQ_FOREACH_SAFE(target, &g_spdk_iscsi.target_head, tailq, tmp) {
|
||||
TAILQ_REMOVE(&g_spdk_iscsi.target_head, target, tailq);
|
||||
g_spdk_iscsi.ntargets--;
|
||||
g_spdk_iscsi.target[i] = NULL;
|
||||
spdk_iscsi_tgt_node_destruct(target);
|
||||
}
|
||||
pthread_mutex_unlock(&g_spdk_iscsi.mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
spdk_iscsi_shutdown_tgt_node_by_name(const char *target_name)
|
||||
{
|
||||
struct spdk_iscsi_tgt_node *target;
|
||||
int i = 0;
|
||||
int ret = -1;
|
||||
|
||||
pthread_mutex_lock(&g_spdk_iscsi.mutex);
|
||||
for (i = 0; i < MAX_ISCSI_TARGET_NODE; i++) {
|
||||
target = g_spdk_iscsi.target[i];
|
||||
if (target == NULL)
|
||||
continue;
|
||||
target = spdk_iscsi_find_tgt_node(target_name);
|
||||
if (target != NULL) {
|
||||
spdk_iscsi_tgt_node_unregister(target);
|
||||
spdk_iscsi_tgt_node_destruct(target);
|
||||
pthread_mutex_unlock(&g_spdk_iscsi.mutex);
|
||||
|
||||
if (strncmp(target_name, target->name, MAX_TMPBUF) == 0) {
|
||||
spdk_iscsi_tgt_node_destruct(target);
|
||||
g_spdk_iscsi.ntargets--;
|
||||
g_spdk_iscsi.target[i] = NULL;
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
pthread_mutex_unlock(&g_spdk_iscsi.mutex);
|
||||
|
||||
return ret;
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int
|
||||
@ -1014,33 +1014,29 @@ void spdk_iscsi_tgt_node_delete_map(struct spdk_iscsi_portal_grp *portal_group,
|
||||
struct spdk_iscsi_tgt_node *target;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int k = 0;
|
||||
int flag = 0;
|
||||
|
||||
for (i = 0; i < MAX_ISCSI_TARGET_NODE; i++) {
|
||||
target = g_spdk_iscsi.target[i];
|
||||
if (target == NULL)
|
||||
continue;
|
||||
TAILQ_FOREACH(target, &g_spdk_iscsi.target_head, tailq) {
|
||||
loop:
|
||||
flag = 0;
|
||||
for (j = 0; j < target->maxmap; j++) {
|
||||
for (i = 0; i < target->maxmap; i++) {
|
||||
if (portal_group) {
|
||||
if (target->map[j].pg->tag == portal_group->tag) {
|
||||
if (target->map[i].pg->tag == portal_group->tag) {
|
||||
flag = 1;
|
||||
}
|
||||
}
|
||||
if (initiator_group) {
|
||||
if (target->map[j].ig->tag == initiator_group->tag) {
|
||||
if (target->map[i].ig->tag == initiator_group->tag) {
|
||||
flag = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (flag == 1) {
|
||||
target->map[j].pg->ref--;
|
||||
target->map[j].ig->ref--;
|
||||
for (k = j; k < target->maxmap - 1; k++) {
|
||||
target->map[k].pg = target->map[k + 1].pg;
|
||||
target->map[k].ig = target->map[k + 1].ig;
|
||||
target->map[i].pg->ref--;
|
||||
target->map[i].ig->ref--;
|
||||
for (j = i; j < target->maxmap - 1; j++) {
|
||||
target->map[j].pg = target->map[j + 1].pg;
|
||||
target->map[j].ig = target->map[j + 1].ig;
|
||||
}
|
||||
target->map[target->maxmap - 1].pg = NULL;
|
||||
target->map[target->maxmap - 1].ig = NULL;
|
||||
|
@ -75,11 +75,12 @@ struct spdk_iscsi_tgt_node {
|
||||
|
||||
int maxmap;
|
||||
struct spdk_iscsi_tgt_node_map map[MAX_TARGET_MAP];
|
||||
TAILQ_ENTRY(spdk_iscsi_tgt_node) tailq;
|
||||
};
|
||||
|
||||
int spdk_iscsi_init_tgt_nodes(void);
|
||||
|
||||
int spdk_iscsi_shutdown_tgt_nodes(void);
|
||||
void spdk_iscsi_shutdown_tgt_nodes(void);
|
||||
int spdk_iscsi_shutdown_tgt_node_by_name(const char *target_name);
|
||||
int spdk_iscsi_send_tgts(struct spdk_iscsi_conn *conn, const char *iiqn,
|
||||
const char *iaddr, const char *tiqn, uint8_t *data, int alloc_len,
|
||||
|
Loading…
x
Reference in New Issue
Block a user