diff --git a/scst/include/scst.h b/scst/include/scst.h index 66c2d4bfc..7ad9d0472 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -1106,6 +1106,11 @@ struct scst_tgt { struct scst_acg *default_acg; /* The default acg for this target. */ + /* + * Device ACG groups + */ + struct list_head acg_list; + /* * Maximum SG table size. Needed here, since different cards on the * same target template can have different SG table limitations. @@ -1966,8 +1971,8 @@ struct scst_acg { /* List of attached acn's, protected by scst_mutex */ struct list_head acn_list; - /* List entry in scst_acg_list */ - struct list_head scst_acg_list_entry; + /* List entry in tgt acg_list */ + struct list_head acg_list_entry; /* Name of this acg */ const char *acg_name; @@ -1976,6 +1981,15 @@ struct scst_acg { /* The pointer to the /proc directory entry */ struct proc_dir_entry *acg_proc_root; #endif + + unsigned int acg_kobj_initialized:1; + unsigned int in_tgt_acg_list:1; + + /* kobject for this structure */ + struct kobject acg_kobj; + + struct kobject *luns_kobj; + struct kobject *initiators_kobj; }; /* @@ -1987,6 +2001,9 @@ struct scst_acn { const char *name; /* List entry in acg->acn_list */ struct list_head acn_list_entry; + + /* sysfs file attributes */ + struct kobj_attribute *acn_attr; }; /* diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index df978af98..98b3e2005 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -1808,6 +1808,14 @@ void scst_free_tgt(struct scst_tgt *tgt) { TRACE_ENTRY(); + if (tgt->default_acg != NULL) + scst_free_acg(tgt->default_acg); + + kfree(tgt->tgt_name); +#ifdef CONFIG_SCST_PROC + kfree(tgt->default_group_name); +#endif + kfree(tgt); TRACE_EXIT(); @@ -1930,6 +1938,11 @@ void scst_acg_dev_destroy(struct scst_acg_dev *acg_dev) { TRACE_ENTRY(); +#ifndef CONFIG_SCST_PROC + if ((acg_dev->dev != NULL) && acg_dev->dev->dev_kobj_initialized) + kobject_put(&acg_dev->dev->dev_kobj); +#endif + kmem_cache_free(scst_acgd_cachep, acg_dev); TRACE_EXIT(); @@ -1957,7 +1970,8 @@ static void scst_free_acg_dev(struct scst_acg_dev *acg_dev) } /* The activity supposed to be suspended and scst_mutex held */ -struct scst_acg *scst_alloc_add_acg(const char *acg_name) +struct scst_acg *scst_alloc_add_acg(struct scst_tgt *tgt, + const char *acg_name) { struct scst_acg *acg; @@ -1965,43 +1979,78 @@ struct scst_acg *scst_alloc_add_acg(const char *acg_name) acg = kzalloc(sizeof(*acg), GFP_KERNEL); if (acg == NULL) { - TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of acg failed"); + PRINT_ERROR("%s", "Allocation of acg failed"); goto out; } INIT_LIST_HEAD(&acg->acg_dev_list); INIT_LIST_HEAD(&acg->acg_sess_list); INIT_LIST_HEAD(&acg->acn_list); - acg->acg_name = acg_name; + acg->acg_name = kstrdup(acg_name, GFP_KERNEL); + if (acg->acg_name == NULL) { + PRINT_ERROR("%s", "Allocation of acg_name failed"); + goto out_free; + } +#ifdef CONFIG_SCST_PROC TRACE_DBG("Adding acg %s to scst_acg_list", acg_name); - list_add_tail(&acg->scst_acg_list_entry, &scst_acg_list); + list_add_tail(&acg->acg_list_entry, &scst_acg_list); scst_check_reassign_sessions(); +#else + if (tgt != NULL) { + TRACE_DBG("Adding acg '%s' to device '%s' acg_list", acg_name, + tgt->tgt_name); + list_add_tail(&acg->acg_list_entry, &tgt->acg_list); + acg->in_tgt_acg_list = 1; + } +#endif out: TRACE_EXIT_HRES(acg); return acg; + +out_free: + kfree(acg); + acg = NULL; + goto out; +} + +void scst_free_acg(struct scst_acg *acg) +{ + TRACE_ENTRY(); + + sBUG_ON(!list_empty(&acg->acg_sess_list)); + sBUG_ON(!list_empty(&acg->acg_dev_list)); + sBUG_ON(!list_empty(&acg->acn_list)); + + kfree(acg->acg_name); + kfree(acg); + + TRACE_EXIT(); + return; } /* The activity supposed to be suspended and scst_mutex held */ -int scst_destroy_acg(struct scst_acg *acg) +void scst_clear_acg(struct scst_acg *acg) { struct scst_acn *n, *nn; struct scst_acg_dev *acg_dev, *acg_dev_tmp; - int res = 0; TRACE_ENTRY(); - if (!list_empty(&acg->acg_sess_list)) { - PRINT_ERROR("%s: acg_sess_list is not empty!", __func__); - res = -EBUSY; - goto out; + TRACE_DBG("Clearing acg %s from list", acg->acg_name); + + sBUG_ON(!list_empty(&acg->acg_sess_list)); +#ifdef CONFIG_SCST_PROC + list_del(&acg->acg_list_entry); +#else + if (acg->in_tgt_acg_list) { + TRACE_DBG("Removing acg %s from list", acg->acg_name); + list_del(&acg->acg_list_entry); + acg->in_tgt_acg_list = 0; } - - TRACE_DBG("Removing acg %s from scst_acg_list", acg->acg_name); - list_del(&acg->scst_acg_list_entry); - +#endif /* Freeing acg_devs */ list_for_each_entry_safe(acg_dev, acg_dev_tmp, &acg->acg_dev_list, acg_dev_list_entry) { @@ -2018,16 +2067,49 @@ int scst_destroy_acg(struct scst_acg *acg) /* Freeing names */ list_for_each_entry_safe(n, nn, &acg->acn_list, acn_list_entry) { - list_del(&n->acn_list_entry); - kfree(n->name); - kfree(n); +#ifdef CONFIG_SCST_PROC + scst_acg_remove_acn(n); + if (list_is_last(&n->acn_list_entry, &acg->acn_list)) + scst_check_reassign_sessions(); +#else + scst_acn_sysfs_del(acg, n, + list_is_last(&n->acn_list_entry, &acg->acn_list)); +#endif } INIT_LIST_HEAD(&acg->acn_list); - kfree(acg); -out: - TRACE_EXIT_RES(res); - return res; + TRACE_EXIT(); + return; +} + +/* The activity supposed to be suspended and scst_mutex held */ +void scst_destroy_acg(struct scst_acg *acg) +{ + TRACE_ENTRY(); + + scst_clear_acg(acg); + scst_free_acg(acg); + + TRACE_EXIT(); + return; +} + +/* The activity supposed to be suspended and scst_mutex held */ +struct scst_acg *scst_tgt_find_acg(struct scst_tgt *tgt, const char *name) +{ + struct scst_acg *acg, *acg_ret = NULL; + + TRACE_ENTRY(); + + list_for_each_entry(acg, &tgt->acg_list, acg_list_entry) { + if (strcmp(acg->acg_name, name) == 0) { + acg_ret = acg; + break; + } + } + + TRACE_EXIT(); + return acg_ret; } /* @@ -2483,35 +2565,64 @@ int scst_acg_add_name(struct scst_acg *acg, const char *name) strcpy(nm, name); n->name = nm; + res = scst_create_acn_sysfs(acg, n); + if (res != 0) + goto out_free_nm; + list_add_tail(&n->acn_list_entry, &acg->acn_list); out: if (res == 0) { - PRINT_INFO("Added name %s to group %s", name, acg->acg_name); + PRINT_INFO("Added name '%s' to group '%s'", name, acg->acg_name); scst_check_reassign_sessions(); } TRACE_EXIT_RES(res); return res; +out_free_nm: + kfree(nm); + out_free: kfree(n); goto out; } +/* The activity supposed to be suspended and scst_mutex held */ +struct scst_acn *scst_acg_find_name(struct scst_acg *acg, const char *name) +{ + struct scst_acn *n; + + TRACE_ENTRY(); + + TRACE_DBG("Trying to find name '%s'", name); + + list_for_each_entry(n, &acg->acn_list, acn_list_entry) { + if (strcmp(n->name, name) == 0) { + TRACE_DBG("%s", "Found"); + goto out; + } + } + n = NULL; +out: + TRACE_EXIT(); + return n; +} + /* scst_mutex supposed to be held */ -void __scst_acg_remove_acn(struct scst_acn *n) +void scst_acg_remove_acn(struct scst_acn *acn) { TRACE_ENTRY(); - list_del(&n->acn_list_entry); - kfree(n->name); - kfree(n); + list_del(&acn->acn_list_entry); + kfree(acn->name); + kfree(acn); TRACE_EXIT(); return; } +#ifdef CONFIG_SCST_PROC /* The activity supposed to be suspended and scst_mutex held */ int scst_acg_remove_name(struct scst_acg *acg, const char *name, bool reassign) { @@ -2522,24 +2633,25 @@ int scst_acg_remove_name(struct scst_acg *acg, const char *name, bool reassign) list_for_each_entry(n, &acg->acn_list, acn_list_entry) { if (strcmp(n->name, name) == 0) { - __scst_acg_remove_acn(n); + scst_acg_remove_acn(n); res = 0; break; } } if (res == 0) { - PRINT_INFO("Removed name %s from group %s", name, + PRINT_INFO("Removed name '%s' from group '%s'", name, acg->acg_name); if (reassign) scst_check_reassign_sessions(); } else - PRINT_ERROR("Unable to find name %s in group %s", name, + PRINT_ERROR("Unable to find name '%s' in group '%s'", name, acg->acg_name); TRACE_EXIT_RES(res); return res; } +#endif static struct scst_cmd *scst_create_prepare_internal_cmd( struct scst_cmd *orig_cmd, int bufsize) diff --git a/scst/src/scst_main.c b/scst/src/scst_main.c index f647b50fa..ea0746e33 100644 --- a/scst/src/scst_main.c +++ b/scst/src/scst_main.c @@ -102,8 +102,8 @@ struct kmem_cache *scst_tgtd_cachep; struct kmem_cache *scst_sess_cachep; struct kmem_cache *scst_acgd_cachep; -struct list_head scst_acg_list; #ifdef CONFIG_SCST_PROC +struct list_head scst_acg_list; struct scst_acg *scst_default_acg; #endif @@ -416,14 +416,16 @@ struct scst_tgt *scst_register(struct scst_tgt_template *vtt, SCST_DEFAULT_TGT_NAME_SUFFIX, tgt_num++); } - tgt->default_acg = scst_alloc_add_acg(tgt->tgt_name); + tgt->default_acg = scst_alloc_add_acg(NULL, tgt->tgt_name); if (tgt->default_acg == NULL) goto out_free_tgt_name; + INIT_LIST_HEAD(&tgt->acg_list); + #ifdef CONFIG_SCST_PROC rc = scst_build_proc_target_entries(tgt); if (rc < 0) - goto out_free_acg; + goto out_clear_acg; #endif rc = scst_create_tgt_sysfs(tgt); @@ -431,7 +433,7 @@ struct scst_tgt *scst_register(struct scst_tgt_template *vtt, #ifdef CONFIG_SCST_PROC goto out_clean_proc; #else - goto out_free_acg; + goto out_clear_acg; #endif list_add_tail(&tgt->tgt_list_entry, &vtt->tgt_list); @@ -451,8 +453,8 @@ out_clean_proc: scst_cleanup_proc_target_entries(tgt); #endif -out_free_acg: - scst_destroy_acg(tgt->default_acg); +out_clear_acg: + scst_clear_acg(tgt->default_acg); out_free_tgt_name: kfree(tgt->tgt_name); @@ -492,6 +494,7 @@ void scst_unregister(struct scst_tgt *tgt) { struct scst_session *sess; struct scst_tgt_template *vtt = tgt->tgtt; + struct scst_acg *acg, *acg_tmp; TRACE_ENTRY(); @@ -534,16 +537,11 @@ again: mutex_unlock(&scst_mutex); scst_resume_activity(); - /* - * It should be before freeing of tgt_name, because acg_name - * points to it. - */ - scst_destroy_acg(tgt->default_acg); + scst_clear_acg(tgt->default_acg); - kfree(tgt->tgt_name); -#ifdef CONFIG_SCST_PROC - kfree(tgt->default_group_name); -#endif + list_for_each_entry_safe(acg, acg_tmp, &tgt->acg_list, acg_list_entry) { + scst_acg_sysfs_put(acg); + } del_timer_sync(&tgt->retry_timer); @@ -1904,7 +1902,9 @@ static int __init init_scst(void) INIT_LIST_HEAD(&scst_dev_list); INIT_LIST_HEAD(&scst_dev_type_list); spin_lock_init(&scst_main_lock); +#ifdef CONFIG_SCST_PROC INIT_LIST_HEAD(&scst_acg_list); +#endif spin_lock_init(&scst_init_lock); init_waitqueue_head(&scst_init_cmd_list_waitQ); INIT_LIST_HEAD(&scst_init_cmd_list); @@ -2048,7 +2048,7 @@ static int __init init_scst(void) goto out_sysfs_cleanup; #ifdef CONFIG_SCST_PROC - scst_default_acg = scst_alloc_add_acg(SCST_DEFAULT_ACG_NAME); + scst_default_acg = scst_alloc_add_acg(NULL, SCST_DEFAULT_ACG_NAME); if (scst_default_acg == NULL) { res = -ENOMEM; goto out_destroy_sgv_pool; diff --git a/scst/src/scst_priv.h b/scst/src/scst_priv.h index 0c3ff6a96..77c901544 100644 --- a/scst/src/scst_priv.h +++ b/scst/src/scst_priv.h @@ -150,8 +150,8 @@ extern struct list_head scst_dev_list; extern struct list_head scst_dev_type_list; extern wait_queue_head_t scst_dev_cmd_waitQ; -extern struct list_head scst_acg_list; #ifdef CONFIG_SCST_PROC +extern struct list_head scst_acg_list; extern struct scst_acg *scst_default_acg; #endif @@ -303,8 +303,13 @@ void scst_free_tgt(struct scst_tgt *tgt); int scst_alloc_device(gfp_t gfp_mask, struct scst_device **out_dev); void scst_free_device(struct scst_device *dev); -struct scst_acg *scst_alloc_add_acg(const char *acg_name); -int scst_destroy_acg(struct scst_acg *acg); +struct scst_acg *scst_alloc_add_acg(struct scst_tgt *tgt, + const char *acg_name); +void scst_clear_acg(struct scst_acg *acg); +void scst_destroy_acg(struct scst_acg *acg); +void scst_free_acg(struct scst_acg *acg); + +struct scst_acg *scst_tgt_find_acg(struct scst_tgt *tgt, const char *name); struct scst_acg *scst_find_acg(const struct scst_session *sess); @@ -322,8 +327,17 @@ int scst_acg_remove_dev(struct scst_acg *acg, struct scst_device *dev, void scst_acg_dev_destroy(struct scst_acg_dev *acg_dev); int scst_acg_add_name(struct scst_acg *acg, const char *name); +#ifdef CONFIG_SCST_PROC int scst_acg_remove_name(struct scst_acg *acg, const char *name, bool reassign); -void __scst_acg_remove_acn(struct scst_acn *n); +#endif +void scst_acg_remove_acn(struct scst_acn *acn); +struct scst_acn *scst_acg_find_name(struct scst_acg *acg, const char *name); + +/* The activity supposed to be suspended and scst_mutex held */ +static inline bool scst_acg_sess_is_empty(struct scst_acg *acg) +{ + return list_empty(&acg->acg_sess_list); +} int scst_prepare_request_sense(struct scst_cmd *orig_cmd); int scst_finish_internal_cmd(struct scst_cmd *cmd); @@ -490,6 +504,17 @@ static inline int scst_create_devt_dev_sysfs(struct scst_device *dev) } static inline void scst_devt_dev_sysfs_put(struct scst_device *dev) { } +static inline int scst_create_acn_sysfs(struct scst_acg *acg, + struct scst_acn *acn) +{ + return 0; +} + +static inline void scst_acn_sysfs_del(struct scst_acg *acg, + struct scst_acn *acn, bool reassign) { } + +static inline void scst_acg_sysfs_put(struct scst_acg *acg) { } + #else /* CONFIG_SCST_PROC */ int scst_sysfs_init(void); @@ -509,6 +534,11 @@ int scst_create_device_sysfs(struct scst_device *dev); void scst_device_sysfs_put(struct scst_device *dev); int scst_create_devt_dev_sysfs(struct scst_device *dev); void scst_devt_dev_sysfs_put(struct scst_device *dev); +int scst_create_acn_sysfs(struct scst_acg *acg, struct scst_acn *acn); +void scst_acn_sysfs_del(struct scst_acg *acg, struct scst_acn *acn, + bool reassign); + +void scst_acg_sysfs_put(struct scst_acg *acg); #endif /* CONFIG_SCST_PROC */ diff --git a/scst/src/scst_proc.c b/scst/src/scst_proc.c index e3c2b2b0c..ab060d58e 100644 --- a/scst/src/scst_proc.c +++ b/scst/src/scst_proc.c @@ -437,7 +437,7 @@ static int lat_info_show(struct seq_file *seq, void *v) goto out; } - list_for_each_entry(acg, &scst_acg_list, scst_acg_list_entry) { + list_for_each_entry(acg, &scst_acg_list, acg_list_entry) { bool header_printed = false; list_for_each_entry(sess, &acg->acg_sess_list, @@ -688,7 +688,7 @@ static ssize_t scst_proc_scsi_tgt_gen_write_lat(struct file *file, goto out; } - list_for_each_entry(acg, &scst_acg_list, scst_acg_list_entry) { + list_for_each_entry(acg, &scst_acg_list, acg_list_entry) { list_for_each_entry(sess, &acg->acg_sess_list, acg_sess_list_entry) { PRINT_INFO("Zeroing latency statistics for initiator " @@ -881,7 +881,7 @@ static int scst_proc_group_add(const char *p) } strncpy(name, p, len); - acg = scst_alloc_add_acg(name); + acg = scst_alloc_add_acg(NULL, name); if (acg == NULL) { PRINT_ERROR("scst_alloc_add_acg() (name %s) failed", name); goto out_free; @@ -909,22 +909,22 @@ out_nomem: /* The activity supposed to be suspended and scst_mutex held */ static int scst_proc_del_free_acg(struct scst_acg *acg, int remove_proc) { - const char *name; struct proc_dir_entry *acg_proc_root = acg->acg_proc_root; int res = 0; TRACE_ENTRY(); if (acg != scst_default_acg) { - name = acg->acg_name; - res = scst_destroy_acg(acg); - if (res == 0) { - if (remove_proc) - scst_proc_del_acg_tree(acg_proc_root, name); - kfree(name); + if (!scst_acg_sess_is_empty(acg)) { + PRINT_ERROR("%s", "Session is not empty"); + res = -EBUSY; + goto out; } + if (remove_proc) + scst_proc_del_acg_tree(acg_proc_root, acg->acg_name); + scst_destroy_acg(acg); } - +out: TRACE_EXIT_RES(res); return res; } @@ -1009,7 +1009,7 @@ static void scst_proc_cleanup_groups(void) /* remove all groups (dir & entries) */ list_for_each_entry_safe(acg, acg_tmp, &scst_acg_list, - scst_acg_list_entry) { + acg_list_entry) { scst_proc_del_free_acg(acg, 1); } @@ -1635,7 +1635,7 @@ static ssize_t scst_proc_scsi_tgt_gen_write(struct file *file, goto out_up_free; } - list_for_each_entry(a, &scst_acg_list, scst_acg_list_entry) { + list_for_each_entry(a, &scst_acg_list, acg_list_entry) { if (strcmp(a->acg_name, p) == 0) { TRACE_DBG("group (acg) %p %s found", a, a->acg_name); @@ -2172,7 +2172,7 @@ static ssize_t scst_proc_groups_names_write(struct file *file, goto out_free_unlock; } } - list_for_each_entry(a, &scst_acg_list, scst_acg_list_entry) { + list_for_each_entry(a, &scst_acg_list, acg_list_entry) { if (strcmp(a->acg_name, p) == 0) { TRACE_DBG("group (acg) %p %s found", a, a->acg_name); @@ -2189,12 +2189,14 @@ static ssize_t scst_proc_groups_names_write(struct file *file, if (rc != 0) goto out_free_unlock; rc = scst_acg_add_name(new_acg, name); + if (rc != 0) + scst_acg_add_name(acg, name); break; } case SCST_PROC_ACTION_CLEAR: list_for_each_entry_safe(n, nn, &acg->acn_list, acn_list_entry) { - __scst_acg_remove_acn(n); + scst_acg_remove_acn(n); } scst_check_reassign_sessions(); break; @@ -2327,7 +2329,7 @@ static int scst_sessions_info_show(struct seq_file *seq, void *v) "Target name", "Initiator name", "Group name", "Active/All Commands Count"); - list_for_each_entry(acg, &scst_acg_list, scst_acg_list_entry) { + list_for_each_entry(acg, &scst_acg_list, acg_list_entry) { list_for_each_entry(sess, &acg->acg_sess_list, acg_sess_list_entry) { int active_cmds = 0, t; diff --git a/scst/src/scst_sysfs.c b/scst/src/scst_sysfs.c index e3b3779f2..e88eb76a1 100644 --- a/scst/src/scst_sysfs.c +++ b/scst/src/scst_sysfs.c @@ -109,6 +109,26 @@ static ssize_t scst_luns_mgmt_show(struct kobject *kobj, static ssize_t scst_luns_mgmt_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count); +static ssize_t scst_ini_group_mgmt_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf); +static ssize_t scst_ini_group_mgmt_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count); +static ssize_t scst_acg_luns_mgmt_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf); +static ssize_t scst_acg_luns_mgmt_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count); +static ssize_t scst_acg_ini_mgmt_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf); +static ssize_t scst_acg_ini_mgmt_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count); +static ssize_t scst_acn_file_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf); static void scst_sysfs_release(struct kobject *kobj) { @@ -288,7 +308,7 @@ static void scst_tgt_release(struct kobject *kobj) } static ssize_t scst_tgt_attr_show(struct kobject *kobj, struct attribute *attr, - char *buf) + char *buf) { int res; struct kobj_attribute *kobj_attr; @@ -311,8 +331,8 @@ out: return res; } -static ssize_t scst_tgt_attr_store(struct kobject *kobj, struct attribute *attr, - const char *buf, size_t count) +static ssize_t scst_tgt_attr_store(struct kobject *kobj, + struct attribute *attr, const char *buf, size_t count) { int res; struct kobj_attribute *kobj_attr; @@ -345,10 +365,41 @@ static struct kobj_type tgt_ktype = { .release = scst_tgt_release, }; +static void scst_acg_release(struct kobject *kobj) +{ + struct scst_acg *acg; + + TRACE_ENTRY(); + + acg = container_of(kobj, struct scst_acg, acg_kobj); + + scst_destroy_acg(acg); + + TRACE_EXIT(); + return; +} + +static struct kobj_type acg_ktype = { + .sysfs_ops = &scst_sysfs_ops, + .release = scst_acg_release, +}; + static struct kobj_attribute scst_luns_mgmt = __ATTR(mgmt, S_IRUGO | S_IWUSR, scst_luns_mgmt_show, scst_luns_mgmt_store); +static struct kobj_attribute scst_acg_luns_mgmt = + __ATTR(mgmt, S_IRUGO | S_IWUSR, scst_acg_luns_mgmt_show, + scst_acg_luns_mgmt_store); + +static struct kobj_attribute scst_acg_ini_mgmt = + __ATTR(mgmt, S_IRUGO | S_IWUSR, scst_acg_ini_mgmt_show, + scst_acg_ini_mgmt_store); + +static struct kobj_attribute scst_ini_group_mgmt = + __ATTR(mgmt, S_IRUGO | S_IWUSR, scst_ini_group_mgmt_show, + scst_ini_group_mgmt_store); + static ssize_t scst_tgt_enable_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { @@ -458,6 +509,14 @@ int scst_create_tgt_sysfs(struct scst_tgt *tgt) goto out_nomem; } + retval = sysfs_create_file(tgt->tgt_ini_grp_kobj, + &scst_ini_group_mgmt.attr); + if (retval != 0) { + PRINT_ERROR("Can't add tgt attr %s for tgt %s", + scst_ini_group_mgmt.attr.name, tgt->tgt_name); + goto out; + } + pattr = tgt->tgtt->tgt_attrs; if (pattr != NULL) { while (*pattr != NULL) { @@ -506,8 +565,6 @@ void scst_tgt_sysfs_put(struct scst_tgt *tgt) kobject_del(tgt->tgt_sess_kobj); kobject_put(tgt->tgt_sess_kobj); - sysfs_remove_file(tgt->tgt_luns_kobj, &scst_luns_mgmt.attr); - kobject_del(tgt->tgt_luns_kobj); kobject_put(tgt->tgt_luns_kobj); @@ -752,10 +809,9 @@ void scst_device_sysfs_put(struct scst_device *dev) TRACE_ENTRY(); if (dev->dev_kobj_initialized) { - if (dev->dev_exp_kobj != NULL) { - kobject_del(dev->dev_exp_kobj); - kobject_put(dev->dev_exp_kobj); - } + kobject_del(dev->dev_exp_kobj); + kobject_put(dev->dev_exp_kobj); + kobject_del(&dev->dev_kobj); down_write(&dev->dev_attr_rwsem); @@ -1083,6 +1139,8 @@ int scst_create_acg_dev_sysfs(struct scst_acg *acg, unsigned int virt_lun, snprintf(str, sizeof(str), "export%u", acg_dev->dev->dev_exported_lun_num++); + kobject_get(&acg_dev->dev->dev_kobj); + acg_dev->acg_dev_kobj_initialized = 1; retval = kobject_init_and_add(&acg_dev->acg_dev_kobj, &acg_dev_ktype, @@ -1115,39 +1173,22 @@ out: return retval; } -static ssize_t scst_luns_mgmt_show(struct kobject *kobj, - struct kobj_attribute *attr, - char *buf) -{ - static char *help = "Usage: echo \"add|del H:C:I:L lun [READ_ONLY]\" " - ">mgmt\n" - " echo \"add|del VNAME lun [READ_ONLY]\" " - ">mgmt\n"; - - return sprintf(buf, help); -} - -static ssize_t scst_luns_mgmt_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t count) +static ssize_t __scst_luns_mgmt_store(struct scst_acg *acg, + struct kobject *kobj, const char *buf, size_t count) { int res, virt = 0, read_only = 0, action; char *buffer, *p, *e = NULL; unsigned int host, channel = 0, id = 0, lun = 0, virt_lun; - struct scst_acg *acg; struct scst_acg_dev *acg_dev = NULL, *acg_dev_tmp; struct scst_device *d, *dev = NULL; - struct scst_tgt *tgt; #define SCST_LUN_ACTION_ADD 1 #define SCST_LUN_ACTION_DEL 2 #define SCST_LUN_ACTION_REPLACE 3 +#define SCST_LUN_ACTION_CLEAR 4 TRACE_ENTRY(); - tgt = container_of(kobj->parent, struct scst_tgt, tgt_kobj); - acg = tgt->default_acg; - buffer = kzalloc(count+1, GFP_KERNEL); if (buffer == NULL) { res = -ENOMEM; @@ -1170,18 +1211,15 @@ static ssize_t scst_luns_mgmt_store(struct kobject *kobj, } else if (!strncasecmp("replace", p, 7)) { p += 7; action = SCST_LUN_ACTION_REPLACE; + } else if (!strncasecmp("clear", p, 5)) { + p += 5; + action = SCST_LUN_ACTION_CLEAR; } else { PRINT_ERROR("Unknown action \"%s\"", p); res = -EINVAL; goto out_free; } - if (!isspace(*p)) { - PRINT_ERROR("%s", "Syntax error"); - res = -EINVAL; - goto out_free; - } - res = scst_suspend_activity(true); if (res != 0) goto out_free; @@ -1191,53 +1229,61 @@ static ssize_t scst_luns_mgmt_store(struct kobject *kobj, goto out_free_resume; } - while (isspace(*p) && *p != '\0') - p++; - e = p; /* save p */ - host = simple_strtoul(p, &p, 0); - if (*p == ':') { - channel = simple_strtoul(p + 1, &p, 0); - id = simple_strtoul(p + 1, &p, 0); - lun = simple_strtoul(p + 1, &p, 0); - e = p; - } else { - virt++; - p = e; /* restore p */ - while (!isspace(*e) && *e != '\0') - e++; - *e = '\0'; - } + if (action != SCST_LUN_ACTION_CLEAR) { + if (!isspace(*p)) { + PRINT_ERROR("%s", "Syntax error"); + res = -EINVAL; + goto out_free_up; + } - list_for_each_entry(d, &scst_dev_list, dev_list_entry) { - if (virt) { - if (d->virt_id && !strcmp(d->virt_name, p)) { - dev = d; - TRACE_DBG("Virt device %p (%s) found", - dev, p); - break; - } + while (isspace(*p) && *p != '\0') + p++; + e = p; /* save p */ + host = simple_strtoul(p, &p, 0); + if (*p == ':') { + channel = simple_strtoul(p + 1, &p, 0); + id = simple_strtoul(p + 1, &p, 0); + lun = simple_strtoul(p + 1, &p, 0); + e = p; } else { - if (d->scsi_dev && - d->scsi_dev->host->host_no == host && - d->scsi_dev->channel == channel && - d->scsi_dev->id == id && - d->scsi_dev->lun == lun) { - dev = d; - TRACE_DBG("Dev %p (%d:%d:%d:%d) found", - dev, host, channel, id, lun); - break; + virt++; + p = e; /* restore p */ + while (!isspace(*e) && *e != '\0') + e++; + *e = '\0'; + } + + list_for_each_entry(d, &scst_dev_list, dev_list_entry) { + if (virt) { + if (d->virt_id && !strcmp(d->virt_name, p)) { + dev = d; + TRACE_DBG("Virt device %p (%s) found", + dev, p); + break; + } + } else { + if (d->scsi_dev && + d->scsi_dev->host->host_no == host && + d->scsi_dev->channel == channel && + d->scsi_dev->id == id && + d->scsi_dev->lun == lun) { + dev = d; + TRACE_DBG("Dev %p (%d:%d:%d:%d) found", + dev, host, channel, id, lun); + break; + } } } - } - if (dev == NULL) { - if (virt) { - PRINT_ERROR("Virt device %s not found", p); - } else { - PRINT_ERROR("Device %d:%d:%d:%d not found", - host, channel, id, lun); + if (dev == NULL) { + if (virt) { + PRINT_ERROR("Virt device '%s' not found", p); + } else { + PRINT_ERROR("Device %d:%d:%d:%d not found", + host, channel, id, lun); + } + res = -EINVAL; + goto out_free_up; } - res = -EINVAL; - goto out_free_up; } switch (action) { @@ -1306,7 +1352,7 @@ static ssize_t scst_luns_mgmt_store(struct kobject *kobj, struct scst_tgt_dev *tgt_dev; list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list, - dev_tgt_dev_list_entry) { + dev_tgt_dev_list_entry) { if ((tgt_dev->acg_dev->acg == acg) && (tgt_dev->lun == virt_lun)) { TRACE_MGMT_DBG("INQUIRY DATA HAS CHANGED" @@ -1324,6 +1370,19 @@ static ssize_t scst_luns_mgmt_store(struct kobject *kobj, if (res != 0) goto out_free_up; break; + case SCST_LUN_ACTION_CLEAR: + PRINT_INFO("Removed all devices from group %s", + acg->acg_name); + list_for_each_entry_safe(acg_dev, acg_dev_tmp, + &acg->acg_dev_list, + acg_dev_list_entry) { + res = scst_acg_remove_dev(acg, acg_dev->dev, + list_is_last(&acg_dev->acg_dev_list_entry, + &acg->acg_dev_list)); + if (res) + goto out_free_up; + } + break; } res = count; @@ -1348,6 +1407,624 @@ out_remove_acg_dev: #undef SCST_LUN_ACTION_ADD #undef SCST_LUN_ACTION_DEL #undef SCST_LUN_ACTION_REPLACE +#undef SCST_LUN_ACTION_CLEAR +} + +static ssize_t scst_luns_mgmt_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + static char *help = "Usage: echo \"add|del H:C:I:L lun [READ_ONLY]\" " + ">mgmt\n" + " echo \"add|del VNAME lun [READ_ONLY]\" " + ">mgmt\n" + " echo \"replace H:C:I:L lun [READ_ONLY]\" " + ">mgmt\n" + " echo \"replace VNAME lun [READ_ONLY]\" " + ">mgmt\n" + " echo \"clear\" " + ">mgmt\n"; + + return sprintf(buf, help); +} + +static ssize_t scst_luns_mgmt_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + int res; + struct scst_acg *acg; + struct scst_tgt *tgt; + + tgt = container_of(kobj->parent, struct scst_tgt, tgt_kobj); + acg = tgt->default_acg; + res = __scst_luns_mgmt_store(acg, kobj, buf, count); + + TRACE_EXIT_RES(res); + return res; +} + +static int scst_create_acg_sysfs(struct scst_tgt *tgt, + struct scst_acg *acg) +{ + int retval = 0; + + TRACE_ENTRY(); + + acg->acg_kobj_initialized = 1; + + retval = kobject_init_and_add(&acg->acg_kobj, &acg_ktype, + tgt->tgt_ini_grp_kobj, acg->acg_name); + if (retval != 0) { + PRINT_ERROR("Can't add acg '%s' to sysfs", acg->acg_name); + goto out; + } + + acg->luns_kobj = kobject_create_and_add("luns", &acg->acg_kobj); + if (acg->luns_kobj == NULL) { + PRINT_ERROR("Can't create luns kobj for tgt %s", + tgt->tgt_name); + retval = -ENOMEM; + goto out; + } + + retval = sysfs_create_file(acg->luns_kobj, &scst_acg_luns_mgmt.attr); + if (retval != 0) { + PRINT_ERROR("Can't add tgt attr %s for tgt %s", + scst_acg_luns_mgmt.attr.name, tgt->tgt_name); + goto out; + } + + acg->initiators_kobj = kobject_create_and_add("initiators", + &acg->acg_kobj); + if (acg->initiators_kobj == NULL) { + PRINT_ERROR("Can't create initiators kobj for tgt %s", + tgt->tgt_name); + retval = -ENOMEM; + goto out; + } + + retval = sysfs_create_file(acg->initiators_kobj, + &scst_acg_ini_mgmt.attr); + if (retval != 0) { + PRINT_ERROR("Can't add tgt attr %s for tgt %s", + scst_acg_ini_mgmt.attr.name, tgt->tgt_name); + goto out; + } +out: + TRACE_EXIT_RES(retval); + return retval; +} + +void scst_acg_sysfs_put(struct scst_acg *acg) +{ + TRACE_ENTRY(); + + if (acg->acg_kobj_initialized) { + scst_clear_acg(acg); + + kobject_del(acg->luns_kobj); + kobject_put(acg->luns_kobj); + + kobject_del(acg->initiators_kobj); + kobject_put(acg->initiators_kobj); + + kobject_del(&acg->acg_kobj); + kobject_put(&acg->acg_kobj); + } else + scst_destroy_acg(acg); + + TRACE_EXIT(); + return; +} + +static ssize_t scst_ini_group_mgmt_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + static char *help = "Usage: echo \"create GROUP_NAME\" " + ">mgmt\n" + " echo \"del GROUP_NAME\" " + ">mgmt\n"; + + return sprintf(buf, help); +} + +static ssize_t scst_ini_group_mgmt_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + int res, action; + int len; + char *name; + char *buffer, *p, *e = NULL; + struct scst_acg *a, *acg = NULL; + struct scst_tgt *tgt; + +#define SCST_INI_GROUP_ACTION_CREATE 1 +#define SCST_INI_GROUP_ACTION_DEL 2 + + TRACE_ENTRY(); + + tgt = container_of(kobj->parent, struct scst_tgt, tgt_kobj); + + buffer = kzalloc(count+1, GFP_KERNEL); + if (buffer == NULL) { + res = -ENOMEM; + goto out; + } + + memcpy(buffer, buf, count); + buffer[count] = '\0'; + p = buffer; + + p = buffer; + if (p[strlen(p) - 1] == '\n') + p[strlen(p) - 1] = '\0'; + if (strncasecmp("create ", p, 7) == 0) { + p += 7; + action = SCST_INI_GROUP_ACTION_CREATE; + } else if (strncasecmp("del ", p, 4) == 0) { + p += 4; + action = SCST_INI_GROUP_ACTION_DEL; + } else { + PRINT_ERROR("Unknown action \"%s\"", p); + res = -EINVAL; + goto out_free; + } + + res = scst_suspend_activity(true); + if (res != 0) + goto out_free; + + if (mutex_lock_interruptible(&scst_mutex) != 0) { + res = -EINTR; + goto out_free_resume; + } + + while (isspace(*p) && *p != '\0') + p++; + e = p; + while (!isspace(*e) && *e != '\0') + e++; + *e = '\0'; + + if (p[0] == '\0') { + PRINT_ERROR("%s", "Group name required"); + res = -EINVAL; + goto out_free_up; + } + + list_for_each_entry(a, &tgt->acg_list, acg_list_entry) { + if (strcmp(a->acg_name, p) == 0) { + TRACE_DBG("group (acg) %p %s found", + a, a->acg_name); + acg = a; + break; + } + } + + switch (action) { + case SCST_INI_GROUP_ACTION_CREATE: + TRACE_DBG("Creating group '%s'", p); + if (acg != NULL) { + PRINT_ERROR("acg name %s exist", p); + res = -EINVAL; + goto out_free_up; + } + + len = strlen(p) + 1; + name = kmalloc(len, GFP_KERNEL); + if (name == NULL) { + PRINT_ERROR("%s", "Allocation of name failed"); + res = -ENOMEM; + goto out_free_up; + } + strncpy(name, p, len); + + acg = scst_alloc_add_acg(tgt, name); + kfree(name); + if (acg == NULL) + goto out_free_up; + + res = scst_create_acg_sysfs(tgt, acg); + if (res != 0) + goto out_free_acg; + break; + case SCST_INI_GROUP_ACTION_DEL: + TRACE_DBG("Deleting group '%s'", p); + if (acg == NULL) { + PRINT_ERROR("Group %s not found", p); + res = -EINVAL; + goto out_free_up; + } + if (!scst_acg_sess_is_empty(acg)) { + PRINT_ERROR("Group %s is not empty", acg->acg_name); + res = -EBUSY; + goto out_free_up; + } + scst_acg_sysfs_put(acg); + break; + } + + res = count; + +out_free_up: + mutex_unlock(&scst_mutex); + +out_free_resume: + scst_resume_activity(); + +out_free: + kfree(buffer); + +out: + TRACE_EXIT_RES(res); + return res; + +out_free_acg: + scst_acg_sysfs_put(acg); + goto out_free_up; + +#undef SCST_LUN_ACTION_CREATE +#undef SCST_LUN_ACTION_DEL +} + +int scst_create_acn_sysfs(struct scst_acg *acg, struct scst_acn *acn) +{ + int retval = 0; + int len; + struct kobj_attribute *attr = NULL; + + TRACE_ENTRY(); + + acn->acn_attr = NULL; + + attr = kzalloc(sizeof(struct kobj_attribute), GFP_KERNEL); + if (attr == NULL) { + PRINT_ERROR("Unable to allocate attributes for initiator '%s'", + acn->name); + retval = -ENOMEM; + goto out; + } + + len = strlen(acn->name) + 1; + attr->attr.name = kzalloc(len, GFP_KERNEL); + if (attr->attr.name == NULL) { + PRINT_ERROR("Unable to allocate attributes for initiator '%s'", + acn->name); + retval = -ENOMEM; + goto out_free; + } + strncpy((char *)attr->attr.name, acn->name, len); + + attr->attr.owner = THIS_MODULE; + attr->attr.mode = S_IRUGO; + attr->show = scst_acn_file_show; + attr->store = NULL; + + retval = sysfs_create_file(acg->initiators_kobj, &attr->attr); + if (retval != 0) { + PRINT_ERROR("Unable to allocate initiator '%s' for group '%s'", + acn->name, acg->acg_name); + kfree(attr->attr.name); + goto out_free; + } + + acn->acn_attr = attr; + +out: + TRACE_EXIT_RES(retval); + return retval; + +out_free: + kfree(attr); + goto out; +} + +void scst_acn_sysfs_del(struct scst_acg *acg, struct scst_acn *acn, + bool reassign) +{ + TRACE_ENTRY(); + + if (acn->acn_attr != NULL) { + sysfs_remove_file(acg->initiators_kobj, + &acn->acn_attr->attr); + kfree(acn->acn_attr->attr.name); + kfree(acn->acn_attr); + } + scst_acg_remove_acn(acn); + if (reassign) + scst_check_reassign_sessions(); + + TRACE_EXIT(); + return; +} + +static ssize_t scst_acn_file_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return scnprintf(buf, SCST_SYSFS_BLOCK_SIZE, "%s\n", + attr->attr.name); +} + +static ssize_t scst_acg_luns_mgmt_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + static char *help = "Usage: echo \"add|del H:C:I:L lun [READ_ONLY]\" " + ">mgmt\n" + " echo \"add|del VNAME lun [READ_ONLY]\" " + ">mgmt\n" + " echo \"replace H:C:I:L lun [READ_ONLY]\" " + ">mgmt\n" + " echo \"replace VNAME lun [READ_ONLY]\" " + ">mgmt\n" + " echo \"clear\" " + ">mgmt\n"; + + return sprintf(buf, help); +} + +static ssize_t scst_acg_luns_mgmt_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + int res; + struct scst_acg *acg; + + acg = container_of(kobj->parent, struct scst_acg, acg_kobj); + res = __scst_luns_mgmt_store(acg, kobj, buf, count); + + TRACE_EXIT_RES(res); + return res; +} + +static ssize_t scst_acg_ini_mgmt_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + static char *help = "Usage: echo \"add INITIATOR_NAME\" " + ">mgmt\n" + " echo \"del INITIATOR_NAME\" " + ">mgmt\n" + " echo \"move INITIATOR_NAME DEST_GROUP_NAME\" " + ">mgmt\n" + " echo \"clear\" " + ">mgmt\n"; + + return sprintf(buf, help); +} + +static ssize_t scst_acg_ini_mgmt_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + int res, action; + char *buffer, *p, *e = NULL; + char *name = NULL, *group = NULL; + struct scst_acg *acg = NULL, *acg_dest = NULL; + struct scst_tgt *tgt = NULL; + struct scst_acn *acn = NULL, *acn_tmp; + +#define SCST_ACG_ACTION_INI_ADD 1 +#define SCST_ACG_ACTION_INI_DEL 2 +#define SCST_ACG_ACTION_INI_CLEAR 3 +#define SCST_ACG_ACTION_INI_MOVE 4 + + TRACE_ENTRY(); + + acg = container_of(kobj->parent, struct scst_acg, acg_kobj); + + buffer = kzalloc(count+1, GFP_KERNEL); + if (buffer == NULL) { + res = -ENOMEM; + goto out; + } + + memcpy(buffer, buf, count); + buffer[count] = '\0'; + p = buffer; + + p = buffer; + if (p[strlen(p) - 1] == '\n') + p[strlen(p) - 1] = '\0'; + + if (strncasecmp("add", p, 3) == 0) { + p += 3; + action = SCST_ACG_ACTION_INI_ADD; + } else if (strncasecmp("del", p, 3) == 0) { + p += 3; + action = SCST_ACG_ACTION_INI_DEL; + } else if (strncasecmp("clear", p, 5) == 0) { + p += 5; + action = SCST_ACG_ACTION_INI_CLEAR; + } else if (strncasecmp("move", p, 4) == 0) { + p += 4; + action = SCST_ACG_ACTION_INI_MOVE; + } else { + PRINT_ERROR("Unknown action \"%s\"", p); + res = -EINVAL; + goto out_free; + } + + if (action != SCST_ACG_ACTION_INI_CLEAR) + if (!isspace(*p)) { + PRINT_ERROR("%s", "Syntax error"); + res = -EINVAL; + goto out_free; + } + + res = scst_suspend_activity(true); + if (res != 0) + goto out_free; + + if (mutex_lock_interruptible(&scst_mutex) != 0) { + res = -EINTR; + goto out_free_resume; + } + + if (action != SCST_ACG_ACTION_INI_CLEAR) + while (isspace(*p) && *p != '\0') + p++; + + switch (action) { + case SCST_ACG_ACTION_INI_ADD: + e = p; + while (!isspace(*e) && *e != '\0') + e++; + *e = '\0'; + name = p; + + if (name[0] == '\0') { + PRINT_ERROR("%s", "Invalid initiator name"); + res = -EINVAL; + goto out_free_up; + } + + res = scst_acg_add_name(acg, name); + if (res != 0) + goto out_free_up; + break; + case SCST_ACG_ACTION_INI_DEL: + e = p; + while (!isspace(*e) && *e != '\0') + e++; + *e = '\0'; + name = p; + + if (name[0] == '\0') { + PRINT_ERROR("%s", "Invalid initiator name"); + res = -EINVAL; + goto out_free_up; + } + + acn = scst_acg_find_name(acg, name); + if (acn == NULL) { + PRINT_ERROR("Unable to find " + "initiator '%s' in group '%s'", + name, acg->acg_name); + res = -EINVAL; + goto out_free_up; + } + scst_acn_sysfs_del(acg, acn, true); + break; + case SCST_ACG_ACTION_INI_CLEAR: + list_for_each_entry_safe(acn, acn_tmp, &acg->acn_list, + acn_list_entry) { + scst_acn_sysfs_del(acg, acn, false); + } + scst_check_reassign_sessions(); + break; + case SCST_ACG_ACTION_INI_MOVE: + e = p; + while (!isspace(*e) && *e != '\0') + e++; + if (*e == '\0') { + PRINT_ERROR("%s", "Too few parameters"); + res = -EINVAL; + goto out_free_up; + } + *e = '\0'; + name = p; + + if (name[0] == '\0') { + PRINT_ERROR("%s", "Invalid initiator name"); + res = -EINVAL; + goto out_free_up; + } + + e++; + p = e; + while (!isspace(*e) && *e != '\0') + e++; + *e = '\0'; + group = p; + + if (group[0] == '\0') { + PRINT_ERROR("%s", "Invalid group name"); + res = -EINVAL; + goto out_free_up; + } + + TRACE_DBG("Move initiator '%s' to group '%s'", + name, group); + + /* + * Better get tgt from hierarchy tgt_kobj -> tgt_ini_grp_kobj -> + * acg_kobj -> initiators_kobj than have direct pointer to tgt + * in struct acg and have a headache to care about its possible + * wrong dereference on the destruction time. + */ + { + struct kobject *k; + + /* acg_kobj */ + k = kobj->parent; + if (k == NULL) { + res = -EINVAL; + goto out_free_up; + } + /* tgt_ini_grp_kobj */ + k = k->parent; + if (k == NULL) { + res = -EINVAL; + goto out_free_up; + } + /* tgt_kobj */ + k = k->parent; + if (k == NULL) { + res = -EINVAL; + goto out_free_up; + } + + tgt = container_of(k, struct scst_tgt, tgt_kobj); + } + + acn = scst_acg_find_name(acg, name); + if (acn == NULL) { + PRINT_ERROR("Unable to find " + "initiator '%s' in group '%s'", + name, acg->acg_name); + res = -EINVAL; + goto out_free_up; + } + acg_dest = scst_tgt_find_acg(tgt, group); + if (acg_dest == NULL) { + PRINT_ERROR("Unable to find group '%s' in target '%s'", + group, tgt->tgt_name); + res = -EINVAL; + goto out_free_up; + } + if (scst_acg_find_name(acg_dest, name) != NULL) { + PRINT_ERROR("Initiator '%s' already exists in group '%s'", + name, acg_dest->acg_name); + res = -EEXIST; + goto out_free_up; + } + scst_acn_sysfs_del(acg, acn, false); + + res = scst_acg_add_name(acg_dest, name); + if (res != 0) + goto out_free_up; + break; + } + + res = count; + +out_free_up: + mutex_unlock(&scst_mutex); + +out_free_resume: + scst_resume_activity(); + +out_free: + kfree(buffer); + +out: + TRACE_EXIT_RES(res); + return res; + +#undef SCST_ACG_ACTION_INI_ADD +#undef SCST_ACG_ACTION_INI_DEL +#undef SCST_ACG_ACTION_INI_CLEAR +#undef SCST_ACG_ACTION_INI_MOVE } /* @@ -1660,7 +2337,7 @@ static int scst_write_trace(const char *buf, size_t length, p++; res = strict_strtoul(p, 0, &level); if (res != 0) { - PRINT_ERROR("Invalud trace value \"%s\"", p); + PRINT_ERROR("Invalid trace value \"%s\"", p); res = -EINVAL; goto out_free; } diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index 00f2092bf..f4b30bc82 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -5332,6 +5332,8 @@ static bool wildcmp(const char *wild, const char *string) return !*wild; } +#ifdef CONFIG_SCST_PROC + /* scst_mutex supposed to be held */ static struct scst_acg *scst_find_acg_by_name_wild(const char *initiator_name) { @@ -5340,7 +5342,7 @@ static struct scst_acg *scst_find_acg_by_name_wild(const char *initiator_name) TRACE_ENTRY(); - list_for_each_entry(acg, &scst_acg_list, scst_acg_list_entry) { + list_for_each_entry(acg, &scst_acg_list, acg_list_entry) { list_for_each_entry(n, &acg->acn_list, acn_list_entry) { if (wildcmp(n->name, initiator_name)) { TRACE_DBG("Access control group %s found", @@ -5356,7 +5358,6 @@ out: return res; } -#ifdef CONFIG_SCST_PROC /* scst_mutex supposed to be held */ static struct scst_acg *scst_find_acg_by_name(const char *acg_name) { @@ -5364,7 +5365,7 @@ static struct scst_acg *scst_find_acg_by_name(const char *acg_name) TRACE_ENTRY(); - list_for_each_entry(acg, &scst_acg_list, scst_acg_list_entry) { + list_for_each_entry(acg, &scst_acg_list, acg_list_entry) { if (strcmp(acg->acg_name, acg_name) == 0) { TRACE_DBG("Access control group %s found", acg->acg_name); @@ -5377,27 +5378,55 @@ out: TRACE_EXIT_HRES(res); return res; } + +#else /* CONFIG_SCST_PROC */ + +/* scst_mutex supposed to be held */ +static struct scst_acg *scst_find_tgt_acg_by_name_wild(struct scst_tgt *tgt, + const char *initiator_name) +{ + struct scst_acg *acg, *res = NULL; + struct scst_acn *n; + + TRACE_ENTRY(); + + if (initiator_name == NULL) + goto out; + + list_for_each_entry(acg, &tgt->acg_list, acg_list_entry) { + list_for_each_entry(n, &acg->acn_list, acn_list_entry) { + if (wildcmp(n->name, initiator_name)) { + TRACE_DBG("Access control group %s found", + acg->acg_name); + res = acg; + goto out; + } + } + } + +out: + TRACE_EXIT_HRES(res); + return res; +} + #endif /* CONFIG_SCST_PROC */ -/* Must be called under scst_mitex */ +/* Must be called under scst_mutex */ struct scst_acg *scst_find_acg(const struct scst_session *sess) { struct scst_acg *acg = NULL; TRACE_ENTRY(); +#ifdef CONFIG_SCST_PROC if (sess->initiator_name) acg = scst_find_acg_by_name_wild(sess->initiator_name); -#ifdef CONFIG_SCST_PROC if ((acg == NULL) && (sess->tgt->default_group_name != NULL)) acg = scst_find_acg_by_name(sess->tgt->default_group_name); - if (acg == NULL) { - if (list_empty(&sess->tgt->default_acg->acg_dev_list)) - acg = scst_default_acg; - else - acg = sess->tgt->default_acg; - } + if (acg == NULL) + acg = scst_default_acg; #else + acg = scst_find_tgt_acg_by_name_wild(sess->tgt, sess->initiator_name); if (acg == NULL) acg = sess->tgt->default_acg; #endif