Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending

Pull SCSI target updates from Nicholas Bellinger:
 "The highlights this round include:

   - Introduce configfs support for unlocked configfs_depend_item()
     (krzysztof + andrezej)
   - Conversion of usb-gadget target driver to new function registration
     interface (andrzej + sebastian)
   - Enable qla2xxx FC target mode support for Extended Logins (himansu +
     giridhar)
   - Enable qla2xxx FC target mode support for Exchange Offload (himansu +
     giridhar)
   - Add qla2xxx FC target mode irq affinity notification + selective
     command queuing.  (quinn + himanshu)
   - Fix iscsi-target deadlock in se_node_acl configfs deletion (sagi +
     nab)
   - Convert se_node_acl configfs deletion + se_node_acl->queue_depth to
     proper se_session->sess_kref + target_get_session() usage.  (hch +
     sagi + nab)
   - Fix long-standing race between se_node_acl->acl_kref get and
     get_initiator_node_acl() lookup.  (hch + nab)
   - Fix target/user block-size handling, and make sure netlink reaches
     all network namespaces (sheng + andy)

  Note there is an outstanding bug-fix series for remote I_T nexus port
  TMR LUN_RESET has been posted and still being tested, and will likely
  become post -rc1 material at this point"

* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending: (56 commits)
  scsi: qla2xxxx: avoid type mismatch in comparison
  target/user: Make sure netlink would reach all network namespaces
  target: Obtain se_node_acl->acl_kref during get_initiator_node_acl
  target: Convert ACL change queue_depth se_session reference usage
  iscsi-target: Fix potential dead-lock during node acl delete
  ib_srpt: Convert acl lookup to modern get_initiator_node_acl usage
  tcm_fc: Convert acl lookup to modern get_initiator_node_acl usage
  tcm_fc: Wait for command completion before freeing a session
  target: Fix a memory leak in target_dev_lba_map_store()
  target: Support aborting tasks with a 64-bit tag
  usb/gadget: Remove set-but-not-used variables
  target: Remove an unused variable
  target: Fix indentation in target_core_configfs.c
  target/user: Allow user to set block size before enabling device
  iser-target: Fix non negative ERR_PTR isert_device_get usage
  target/fcoe: Add tag support to tcm_fc
  qla2xxx: Check for online flag instead of active reset when transmitting responses
  qla2xxx: Set all queues to 4k
  qla2xxx: Disable ZIO at start time.
  qla2xxx: Move atioq to a different lock to reduce lock contention
  ...
This commit is contained in:
Linus Torvalds
2016-01-20 17:20:53 -08:00
53 changed files with 4511 additions and 2703 deletions

View File

@@ -1333,7 +1333,7 @@ iscsit_check_dataout_hdr(struct iscsi_conn *conn, unsigned char *buf,
/*
* Check if a delayed TASK_ABORTED status needs to
* be sent now if the ISCSI_FLAG_CMD_FINAL has been
* received with the unsolicitied data out.
* received with the unsolicited data out.
*/
if (hdr->flags & ISCSI_FLAG_CMD_FINAL)
iscsit_stop_dataout_timer(cmd);
@@ -3435,7 +3435,7 @@ iscsit_build_sendtargets_response(struct iscsi_cmd *cmd,
if ((tpg->tpg_attrib.generate_node_acls == 0) &&
(tpg->tpg_attrib.demo_mode_discovery == 0) &&
(!core_tpg_get_initiator_node_acl(&tpg->tpg_se_tpg,
(!target_tpg_has_node_acl(&tpg->tpg_se_tpg,
cmd->conn->sess->sess_ops->InitiatorName))) {
continue;
}
@@ -4459,9 +4459,6 @@ int iscsit_close_connection(
return 0;
}
spin_unlock_bh(&sess->conn_lock);
return 0;
}
int iscsit_close_session(struct iscsi_session *sess)

View File

@@ -725,11 +725,8 @@ static ssize_t lio_target_nacl_cmdsn_depth_store(struct config_item *item,
if (iscsit_get_tpg(tpg) < 0)
return -EINVAL;
/*
* iscsit_tpg_set_initiator_node_queue_depth() assumes force=1
*/
ret = iscsit_tpg_set_initiator_node_queue_depth(tpg,
config_item_name(acl_ci), cmdsn_depth, 1);
ret = core_tpg_set_initiator_node_queue_depth(se_nacl, cmdsn_depth);
pr_debug("LIO_Target_ConfigFS: %s/%s Set CmdSN Window: %u for"
"InitiatorName: %s\n", config_item_name(wwn_ci),
@@ -1593,28 +1590,30 @@ static int lio_tpg_check_prot_fabric_only(
}
/*
* Called with spin_lock_bh(struct se_portal_group->session_lock) held..
*
* Also, this function calls iscsit_inc_session_usage_count() on the
* This function calls iscsit_inc_session_usage_count() on the
* struct iscsi_session in question.
*/
static int lio_tpg_shutdown_session(struct se_session *se_sess)
{
struct iscsi_session *sess = se_sess->fabric_sess_ptr;
struct se_portal_group *se_tpg = &sess->tpg->tpg_se_tpg;
spin_lock_bh(&se_tpg->session_lock);
spin_lock(&sess->conn_lock);
if (atomic_read(&sess->session_fall_back_to_erl0) ||
atomic_read(&sess->session_logout) ||
(sess->time2retain_timer_flags & ISCSI_TF_EXPIRED)) {
spin_unlock(&sess->conn_lock);
spin_unlock_bh(&se_tpg->session_lock);
return 0;
}
atomic_set(&sess->session_reinstatement, 1);
spin_unlock(&sess->conn_lock);
iscsit_stop_time2retain_timer(sess);
iscsit_stop_session(sess, 1, 1);
spin_unlock_bh(&se_tpg->session_lock);
iscsit_stop_session(sess, 1, 1);
return 1;
}

View File

@@ -160,8 +160,7 @@ static int iscsit_handle_r2t_snack(
" protocol error.\n", cmd->init_task_tag, begrun,
(begrun + runlength), cmd->acked_data_sn);
return iscsit_reject_cmd(cmd,
ISCSI_REASON_PROTOCOL_ERROR, buf);
return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR, buf);
}
if (runlength) {
@@ -628,8 +627,8 @@ int iscsit_dataout_datapduinorder_no_fbit(
if (cmd->pdu_list[i].seq_no == pdu->seq_no) {
if (!first_pdu)
first_pdu = &cmd->pdu_list[i];
xfer_len += cmd->pdu_list[i].length;
pdu_count++;
xfer_len += cmd->pdu_list[i].length;
pdu_count++;
} else if (pdu_count)
break;
}

View File

@@ -1668,7 +1668,7 @@ void iscsi_set_session_parameters(
param->value);
} else if (!strcmp(param->name, INITIALR2T)) {
ops->InitialR2T = !strcmp(param->value, YES);
pr_debug("InitialR2T: %s\n",
pr_debug("InitialR2T: %s\n",
param->value);
} else if (!strcmp(param->name, IMMEDIATEDATA)) {
ops->ImmediateData = !strcmp(param->value, YES);

View File

@@ -82,7 +82,7 @@ int iscsit_tmr_task_warm_reset(
pr_err("TMR Opcode TARGET_WARM_RESET authorization"
" failed for Initiator Node: %s\n",
sess->se_sess->se_node_acl->initiatorname);
return -1;
return -1;
}
/*
* Do the real work in transport_generic_do_tmr().

View File

@@ -590,16 +590,6 @@ int iscsit_tpg_del_network_portal(
return iscsit_tpg_release_np(tpg_np, tpg, np);
}
int iscsit_tpg_set_initiator_node_queue_depth(
struct iscsi_portal_group *tpg,
unsigned char *initiatorname,
u32 queue_depth,
int force)
{
return core_tpg_set_initiator_node_queue_depth(&tpg->tpg_se_tpg,
initiatorname, queue_depth, force);
}
int iscsit_ta_authentication(struct iscsi_portal_group *tpg, u32 authentication)
{
unsigned char buf1[256], buf2[256], *none = NULL;

View File

@@ -26,8 +26,6 @@ extern struct iscsi_tpg_np *iscsit_tpg_add_network_portal(struct iscsi_portal_gr
int);
extern int iscsit_tpg_del_network_portal(struct iscsi_portal_group *,
struct iscsi_tpg_np *);
extern int iscsit_tpg_set_initiator_node_queue_depth(struct iscsi_portal_group *,
unsigned char *, u32, int);
extern int iscsit_ta_authentication(struct iscsi_portal_group *, u32);
extern int iscsit_ta_login_timeout(struct iscsi_portal_group *, u32);
extern int iscsit_ta_netif_timeout(struct iscsi_portal_group *, u32);

View File

@@ -1036,12 +1036,26 @@ static ssize_t tcm_loop_tpg_transport_status_store(struct config_item *item,
return -EINVAL;
}
static ssize_t tcm_loop_tpg_address_show(struct config_item *item,
char *page)
{
struct se_portal_group *se_tpg = to_tpg(item);
struct tcm_loop_tpg *tl_tpg = container_of(se_tpg,
struct tcm_loop_tpg, tl_se_tpg);
struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba;
return snprintf(page, PAGE_SIZE, "%d:0:%d\n",
tl_hba->sh->host_no, tl_tpg->tl_tpgt);
}
CONFIGFS_ATTR(tcm_loop_tpg_, nexus);
CONFIGFS_ATTR(tcm_loop_tpg_, transport_status);
CONFIGFS_ATTR_RO(tcm_loop_tpg_, address);
static struct configfs_attribute *tcm_loop_tpg_attrs[] = {
&tcm_loop_tpg_attr_nexus,
&tcm_loop_tpg_attr_transport_status,
&tcm_loop_tpg_attr_address,
NULL,
};

View File

@@ -39,8 +39,6 @@
#include "sbp_target.h"
static const struct target_core_fabric_ops sbp_ops;
/* FireWire address region for management and command block address handlers */
static const struct fw_address_region sbp_register_region = {
.start = CSR_REGISTER_BASE + 0x10000,

View File

@@ -278,7 +278,7 @@ EXPORT_SYMBOL(target_depend_item);
void target_undepend_item(struct config_item *item)
{
return configfs_undepend_item(&target_core_fabrics, item);
return configfs_undepend_item(item);
}
EXPORT_SYMBOL(target_undepend_item);
@@ -499,6 +499,7 @@ DEF_CONFIGFS_ATTRIB_SHOW(max_unmap_lba_count);
DEF_CONFIGFS_ATTRIB_SHOW(max_unmap_block_desc_count);
DEF_CONFIGFS_ATTRIB_SHOW(unmap_granularity);
DEF_CONFIGFS_ATTRIB_SHOW(unmap_granularity_alignment);
DEF_CONFIGFS_ATTRIB_SHOW(unmap_zeroes_data);
DEF_CONFIGFS_ATTRIB_SHOW(max_write_same_len);
#define DEF_CONFIGFS_ATTRIB_STORE_U32(_name) \
@@ -548,7 +549,8 @@ static ssize_t _name##_store(struct config_item *item, const char *page,\
size_t count) \
{ \
printk_once(KERN_WARNING \
"ignoring deprecated ##_name## attribute\n"); \
"ignoring deprecated %s attribute\n", \
__stringify(_name)); \
return count; \
}
@@ -866,6 +868,39 @@ static ssize_t emulate_rest_reord_store(struct config_item *item,
return count;
}
static ssize_t unmap_zeroes_data_store(struct config_item *item,
const char *page, size_t count)
{
struct se_dev_attrib *da = to_attrib(item);
bool flag;
int ret;
ret = strtobool(page, &flag);
if (ret < 0)
return ret;
if (da->da_dev->export_count) {
pr_err("dev[%p]: Unable to change SE Device"
" unmap_zeroes_data while export_count is %d\n",
da->da_dev, da->da_dev->export_count);
return -EINVAL;
}
/*
* We expect this value to be non-zero when generic Block Layer
* Discard supported is detected iblock_configure_device().
*/
if (flag && !da->max_unmap_block_desc_count) {
pr_err("dev[%p]: Thin Provisioning LBPRZ will not be set"
" because max_unmap_block_desc_count is zero\n",
da->da_dev);
return -ENOSYS;
}
da->unmap_zeroes_data = flag;
pr_debug("dev[%p]: SE Device Thin Provisioning LBPRZ bit: %d\n",
da->da_dev, flag);
return 0;
}
/*
* Note, this can only be called on unexported SE Device Object.
*/
@@ -998,6 +1033,7 @@ CONFIGFS_ATTR(, max_unmap_lba_count);
CONFIGFS_ATTR(, max_unmap_block_desc_count);
CONFIGFS_ATTR(, unmap_granularity);
CONFIGFS_ATTR(, unmap_granularity_alignment);
CONFIGFS_ATTR(, unmap_zeroes_data);
CONFIGFS_ATTR(, max_write_same_len);
/*
@@ -1034,6 +1070,7 @@ struct configfs_attribute *sbc_attrib_attrs[] = {
&attr_max_unmap_block_desc_count,
&attr_unmap_granularity,
&attr_unmap_granularity_alignment,
&attr_unmap_zeroes_data,
&attr_max_write_same_len,
NULL,
};
@@ -1980,14 +2017,14 @@ static ssize_t target_dev_lba_map_store(struct config_item *item,
struct se_device *dev = to_device(item);
struct t10_alua_lba_map *lba_map = NULL;
struct list_head lba_list;
char *map_entries, *ptr;
char *map_entries, *orig, *ptr;
char state;
int pg_num = -1, pg;
int ret = 0, num = 0, pg_id, alua_state;
unsigned long start_lba = -1, end_lba = -1;
unsigned long segment_size = -1, segment_mult = -1;
map_entries = kstrdup(page, GFP_KERNEL);
orig = map_entries = kstrdup(page, GFP_KERNEL);
if (!map_entries)
return -ENOMEM;
@@ -2085,7 +2122,7 @@ out:
} else
core_alua_set_lba_map(dev, &lba_list,
segment_size, segment_mult);
kfree(map_entries);
kfree(orig);
return count;
}

View File

@@ -813,6 +813,8 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)
dev->dev_attrib.unmap_granularity = DA_UNMAP_GRANULARITY_DEFAULT;
dev->dev_attrib.unmap_granularity_alignment =
DA_UNMAP_GRANULARITY_ALIGNMENT_DEFAULT;
dev->dev_attrib.unmap_zeroes_data =
DA_UNMAP_ZEROES_DATA_DEFAULT;
dev->dev_attrib.max_write_same_len = DA_MAX_WRITE_SAME_LEN;
xcopy_lun = &dev->xcopy_lun;

View File

@@ -138,6 +138,8 @@ static int iblock_configure_device(struct se_device *dev)
q->limits.discard_granularity >> 9;
dev->dev_attrib.unmap_granularity_alignment =
q->limits.discard_alignment;
dev->dev_attrib.unmap_zeroes_data =
q->limits.discard_zeroes_data;
pr_debug("IBLOCK: BLOCK Discard support available,"
" disabled by default\n");

View File

@@ -1457,8 +1457,7 @@ static void core_scsi3_nodeacl_undepend_item(struct se_node_acl *nacl)
static int core_scsi3_lunacl_depend_item(struct se_dev_entry *se_deve)
{
struct se_lun_acl *lun_acl;
struct se_node_acl *nacl;
struct se_portal_group *tpg;
/*
* For nacl->dynamic_node_acl=1
*/
@@ -1467,17 +1466,13 @@ static int core_scsi3_lunacl_depend_item(struct se_dev_entry *se_deve)
if (!lun_acl)
return 0;
nacl = lun_acl->se_lun_nacl;
tpg = nacl->se_tpg;
return target_depend_item(&lun_acl->se_lun_group.cg_item);
}
static void core_scsi3_lunacl_undepend_item(struct se_dev_entry *se_deve)
{
struct se_lun_acl *lun_acl;
struct se_node_acl *nacl;
struct se_portal_group *tpg;
/*
* For nacl->dynamic_node_acl=1
*/
@@ -1487,8 +1482,6 @@ static void core_scsi3_lunacl_undepend_item(struct se_dev_entry *se_deve)
kref_put(&se_deve->pr_kref, target_pr_kref_release);
return;
}
nacl = lun_acl->se_lun_nacl;
tpg = nacl->se_tpg;
target_undepend_item(&lun_acl->se_lun_group.cg_item);
kref_put(&se_deve->pr_kref, target_pr_kref_release);

View File

@@ -141,9 +141,17 @@ sbc_emulate_readcapacity_16(struct se_cmd *cmd)
* Set Thin Provisioning Enable bit following sbc3r22 in section
* READ CAPACITY (16) byte 14 if emulate_tpu or emulate_tpws is enabled.
*/
if (dev->dev_attrib.emulate_tpu || dev->dev_attrib.emulate_tpws)
if (dev->dev_attrib.emulate_tpu || dev->dev_attrib.emulate_tpws) {
buf[14] |= 0x80;
/*
* LBPRZ signifies that zeroes will be read back from an LBA after
* an UNMAP or WRITE SAME w/ unmap bit (sbc3r36 5.16.2)
*/
if (dev->dev_attrib.unmap_zeroes_data)
buf[14] |= 0x40;
}
rbuf = transport_kmap_data_sg(cmd);
if (rbuf) {
memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length));

View File

@@ -635,6 +635,18 @@ spc_emulate_evpd_b2(struct se_cmd *cmd, unsigned char *buf)
if (dev->dev_attrib.emulate_tpws != 0)
buf[5] |= 0x40 | 0x20;
/*
* The unmap_zeroes_data set means that the underlying device supports
* REQ_DISCARD and has the discard_zeroes_data bit set. This satisfies
* the SBC requirements for LBPRZ, meaning that a subsequent read
* will return zeroes after an UNMAP or WRITE SAME (16) to an LBA
* See sbc4r36 6.6.4.
*/
if (((dev->dev_attrib.emulate_tpu != 0) ||
(dev->dev_attrib.emulate_tpws != 0)) &&
(dev->dev_attrib.unmap_zeroes_data != 0))
buf[5] |= 0x04;
return 0;
}

View File

@@ -201,7 +201,7 @@ static void core_tmr_drain_tmr_list(
/*
* If this function was called with a valid pr_res_key
* parameter (eg: for PROUT PREEMPT_AND_ABORT service action
* skip non regisration key matching TMRs.
* skip non registration key matching TMRs.
*/
if (target_check_cdb_and_preempt(preempt_and_abort_list, cmd))
continue;

View File

@@ -75,9 +75,21 @@ struct se_node_acl *core_tpg_get_initiator_node_acl(
unsigned char *initiatorname)
{
struct se_node_acl *acl;
/*
* Obtain se_node_acl->acl_kref using fabric driver provided
* initiatorname[] during node acl endpoint lookup driven by
* new se_session login.
*
* The reference is held until se_session shutdown -> release
* occurs via fabric driver invoked transport_deregister_session()
* or transport_free_session() code.
*/
mutex_lock(&tpg->acl_node_mutex);
acl = __core_tpg_get_initiator_node_acl(tpg, initiatorname);
if (acl) {
if (!kref_get_unless_zero(&acl->acl_kref))
acl = NULL;
}
mutex_unlock(&tpg->acl_node_mutex);
return acl;
@@ -157,28 +169,25 @@ void core_tpg_add_node_to_devs(
mutex_unlock(&tpg->tpg_lun_mutex);
}
/* core_set_queue_depth_for_node():
*
*
*/
static int core_set_queue_depth_for_node(
struct se_portal_group *tpg,
struct se_node_acl *acl)
static void
target_set_nacl_queue_depth(struct se_portal_group *tpg,
struct se_node_acl *acl, u32 queue_depth)
{
acl->queue_depth = queue_depth;
if (!acl->queue_depth) {
pr_err("Queue depth for %s Initiator Node: %s is 0,"
pr_warn("Queue depth for %s Initiator Node: %s is 0,"
"defaulting to 1.\n", tpg->se_tpg_tfo->get_fabric_name(),
acl->initiatorname);
acl->queue_depth = 1;
}
return 0;
}
static struct se_node_acl *target_alloc_node_acl(struct se_portal_group *tpg,
const unsigned char *initiatorname)
{
struct se_node_acl *acl;
u32 queue_depth;
acl = kzalloc(max(sizeof(*acl), tpg->se_tpg_tfo->node_acl_size),
GFP_KERNEL);
@@ -193,24 +202,20 @@ static struct se_node_acl *target_alloc_node_acl(struct se_portal_group *tpg,
spin_lock_init(&acl->nacl_sess_lock);
mutex_init(&acl->lun_entry_mutex);
atomic_set(&acl->acl_pr_ref_count, 0);
if (tpg->se_tpg_tfo->tpg_get_default_depth)
acl->queue_depth = tpg->se_tpg_tfo->tpg_get_default_depth(tpg);
queue_depth = tpg->se_tpg_tfo->tpg_get_default_depth(tpg);
else
acl->queue_depth = 1;
queue_depth = 1;
target_set_nacl_queue_depth(tpg, acl, queue_depth);
snprintf(acl->initiatorname, TRANSPORT_IQN_LEN, "%s", initiatorname);
acl->se_tpg = tpg;
acl->acl_index = scsi_get_new_index(SCSI_AUTH_INTR_INDEX);
tpg->se_tpg_tfo->set_default_node_attributes(acl);
if (core_set_queue_depth_for_node(tpg, acl) < 0)
goto out_free_acl;
return acl;
out_free_acl:
kfree(acl);
return NULL;
}
static void target_add_node_acl(struct se_node_acl *acl)
@@ -219,7 +224,6 @@ static void target_add_node_acl(struct se_node_acl *acl)
mutex_lock(&tpg->acl_node_mutex);
list_add_tail(&acl->acl_list, &tpg->acl_node_list);
tpg->num_node_acls++;
mutex_unlock(&tpg->acl_node_mutex);
pr_debug("%s_TPG[%hu] - Added %s ACL with TCQ Depth: %d for %s"
@@ -232,6 +236,25 @@ static void target_add_node_acl(struct se_node_acl *acl)
acl->initiatorname);
}
bool target_tpg_has_node_acl(struct se_portal_group *tpg,
const char *initiatorname)
{
struct se_node_acl *acl;
bool found = false;
mutex_lock(&tpg->acl_node_mutex);
list_for_each_entry(acl, &tpg->acl_node_list, acl_list) {
if (!strcmp(acl->initiatorname, initiatorname)) {
found = true;
break;
}
}
mutex_unlock(&tpg->acl_node_mutex);
return found;
}
EXPORT_SYMBOL(target_tpg_has_node_acl);
struct se_node_acl *core_tpg_check_initiator_node_acl(
struct se_portal_group *tpg,
unsigned char *initiatorname)
@@ -248,6 +271,15 @@ struct se_node_acl *core_tpg_check_initiator_node_acl(
acl = target_alloc_node_acl(tpg, initiatorname);
if (!acl)
return NULL;
/*
* When allocating a dynamically generated node_acl, go ahead
* and take the extra kref now before returning to the fabric
* driver caller.
*
* Note this reference will be released at session shutdown
* time within transport_free_session() code.
*/
kref_get(&acl->acl_kref);
acl->dynamic_node_acl = 1;
/*
@@ -318,7 +350,6 @@ void core_tpg_del_initiator_node_acl(struct se_node_acl *acl)
acl->dynamic_node_acl = 0;
}
list_del(&acl->acl_list);
tpg->num_node_acls--;
mutex_unlock(&tpg->acl_node_mutex);
spin_lock_irqsave(&acl->nacl_sess_lock, flags);
@@ -329,7 +360,8 @@ void core_tpg_del_initiator_node_acl(struct se_node_acl *acl)
if (sess->sess_tearing_down != 0)
continue;
target_get_session(sess);
if (!target_get_session(sess))
continue;
list_move(&sess->sess_acl_list, &sess_list);
}
spin_unlock_irqrestore(&acl->nacl_sess_lock, flags);
@@ -366,108 +398,52 @@ void core_tpg_del_initiator_node_acl(struct se_node_acl *acl)
*
*/
int core_tpg_set_initiator_node_queue_depth(
struct se_portal_group *tpg,
unsigned char *initiatorname,
u32 queue_depth,
int force)
struct se_node_acl *acl,
u32 queue_depth)
{
struct se_session *sess, *init_sess = NULL;
struct se_node_acl *acl;
LIST_HEAD(sess_list);
struct se_portal_group *tpg = acl->se_tpg;
struct se_session *sess, *sess_tmp;
unsigned long flags;
int dynamic_acl = 0;
mutex_lock(&tpg->acl_node_mutex);
acl = __core_tpg_get_initiator_node_acl(tpg, initiatorname);
if (!acl) {
pr_err("Access Control List entry for %s Initiator"
" Node %s does not exists for TPG %hu, ignoring"
" request.\n", tpg->se_tpg_tfo->get_fabric_name(),
initiatorname, tpg->se_tpg_tfo->tpg_get_tag(tpg));
mutex_unlock(&tpg->acl_node_mutex);
return -ENODEV;
}
if (acl->dynamic_node_acl) {
acl->dynamic_node_acl = 0;
dynamic_acl = 1;
}
mutex_unlock(&tpg->acl_node_mutex);
spin_lock_irqsave(&tpg->session_lock, flags);
list_for_each_entry(sess, &tpg->tpg_sess_list, sess_list) {
if (sess->se_node_acl != acl)
continue;
if (!force) {
pr_err("Unable to change queue depth for %s"
" Initiator Node: %s while session is"
" operational. To forcefully change the queue"
" depth and force session reinstatement"
" use the \"force=1\" parameter.\n",
tpg->se_tpg_tfo->get_fabric_name(), initiatorname);
spin_unlock_irqrestore(&tpg->session_lock, flags);
mutex_lock(&tpg->acl_node_mutex);
if (dynamic_acl)
acl->dynamic_node_acl = 1;
mutex_unlock(&tpg->acl_node_mutex);
return -EEXIST;
}
/*
* Determine if the session needs to be closed by our context.
*/
if (!tpg->se_tpg_tfo->shutdown_session(sess))
continue;
init_sess = sess;
break;
}
int rc;
/*
* User has requested to change the queue depth for a Initiator Node.
* Change the value in the Node's struct se_node_acl, and call
* core_set_queue_depth_for_node() to add the requested queue depth.
*
* Finally call tpg->se_tpg_tfo->close_session() to force session
* reinstatement to occur if there is an active session for the
* $FABRIC_MOD Initiator Node in question.
* target_set_nacl_queue_depth() to set the new queue depth.
*/
acl->queue_depth = queue_depth;
target_set_nacl_queue_depth(tpg, acl, queue_depth);
spin_lock_irqsave(&acl->nacl_sess_lock, flags);
list_for_each_entry_safe(sess, sess_tmp, &acl->acl_sess_list,
sess_acl_list) {
if (sess->sess_tearing_down != 0)
continue;
if (!target_get_session(sess))
continue;
spin_unlock_irqrestore(&acl->nacl_sess_lock, flags);
if (core_set_queue_depth_for_node(tpg, acl) < 0) {
spin_unlock_irqrestore(&tpg->session_lock, flags);
/*
* Force session reinstatement if
* core_set_queue_depth_for_node() failed, because we assume
* the $FABRIC_MOD has already the set session reinstatement
* bit from tpg->se_tpg_tfo->shutdown_session() called above.
* Finally call tpg->se_tpg_tfo->close_session() to force session
* reinstatement to occur if there is an active session for the
* $FABRIC_MOD Initiator Node in question.
*/
if (init_sess)
tpg->se_tpg_tfo->close_session(init_sess);
mutex_lock(&tpg->acl_node_mutex);
if (dynamic_acl)
acl->dynamic_node_acl = 1;
mutex_unlock(&tpg->acl_node_mutex);
return -EINVAL;
rc = tpg->se_tpg_tfo->shutdown_session(sess);
target_put_session(sess);
if (!rc) {
spin_lock_irqsave(&acl->nacl_sess_lock, flags);
continue;
}
target_put_session(sess);
spin_lock_irqsave(&acl->nacl_sess_lock, flags);
}
spin_unlock_irqrestore(&tpg->session_lock, flags);
/*
* If the $FABRIC_MOD session for the Initiator Node ACL exists,
* forcefully shutdown the $FABRIC_MOD session/nexus.
*/
if (init_sess)
tpg->se_tpg_tfo->close_session(init_sess);
spin_unlock_irqrestore(&acl->nacl_sess_lock, flags);
pr_debug("Successfully changed queue depth to: %d for Initiator"
" Node: %s on %s Target Portal Group: %u\n", queue_depth,
initiatorname, tpg->se_tpg_tfo->get_fabric_name(),
" Node: %s on %s Target Portal Group: %u\n", acl->queue_depth,
acl->initiatorname, tpg->se_tpg_tfo->get_fabric_name(),
tpg->se_tpg_tfo->tpg_get_tag(tpg));
mutex_lock(&tpg->acl_node_mutex);
if (dynamic_acl)
acl->dynamic_node_acl = 1;
mutex_unlock(&tpg->acl_node_mutex);
return 0;
}
EXPORT_SYMBOL(core_tpg_set_initiator_node_queue_depth);
@@ -595,7 +571,6 @@ int core_tpg_deregister(struct se_portal_group *se_tpg)
*/
list_for_each_entry_safe(nacl, nacl_tmp, &node_list, acl_list) {
list_del(&nacl->acl_list);
se_tpg->num_node_acls--;
core_tpg_wait_for_nacl_pr_ref(nacl);
core_free_device_list_for_node(nacl, se_tpg);

View File

@@ -341,7 +341,6 @@ void __transport_register_session(
&buf[0], PR_REG_ISID_LEN);
se_sess->sess_bin_isid = get_unaligned_be64(&buf[0]);
}
kref_get(&se_nacl->acl_kref);
spin_lock_irq(&se_nacl->nacl_sess_lock);
/*
@@ -384,9 +383,9 @@ static void target_release_session(struct kref *kref)
se_tpg->se_tpg_tfo->close_session(se_sess);
}
void target_get_session(struct se_session *se_sess)
int target_get_session(struct se_session *se_sess)
{
kref_get(&se_sess->sess_kref);
return kref_get_unless_zero(&se_sess->sess_kref);
}
EXPORT_SYMBOL(target_get_session);
@@ -432,6 +431,7 @@ void target_put_nacl(struct se_node_acl *nacl)
{
kref_put(&nacl->acl_kref, target_complete_nacl);
}
EXPORT_SYMBOL(target_put_nacl);
void transport_deregister_session_configfs(struct se_session *se_sess)
{
@@ -464,6 +464,15 @@ EXPORT_SYMBOL(transport_deregister_session_configfs);
void transport_free_session(struct se_session *se_sess)
{
struct se_node_acl *se_nacl = se_sess->se_node_acl;
/*
* Drop the se_node_acl->nacl_kref obtained from within
* core_tpg_get_initiator_node_acl().
*/
if (se_nacl) {
se_sess->se_node_acl = NULL;
target_put_nacl(se_nacl);
}
if (se_sess->sess_cmd_map) {
percpu_ida_destroy(&se_sess->sess_tag_pool);
kvfree(se_sess->sess_cmd_map);
@@ -478,7 +487,7 @@ void transport_deregister_session(struct se_session *se_sess)
const struct target_core_fabric_ops *se_tfo;
struct se_node_acl *se_nacl;
unsigned long flags;
bool comp_nacl = true, drop_nacl = false;
bool drop_nacl = false;
if (!se_tpg) {
transport_free_session(se_sess);
@@ -502,7 +511,6 @@ void transport_deregister_session(struct se_session *se_sess)
if (se_nacl && se_nacl->dynamic_node_acl) {
if (!se_tfo->tpg_check_demo_mode_cache(se_tpg)) {
list_del(&se_nacl->acl_list);
se_tpg->num_node_acls--;
drop_nacl = true;
}
}
@@ -511,18 +519,16 @@ void transport_deregister_session(struct se_session *se_sess)
if (drop_nacl) {
core_tpg_wait_for_nacl_pr_ref(se_nacl);
core_free_device_list_for_node(se_nacl, se_tpg);
se_sess->se_node_acl = NULL;
kfree(se_nacl);
comp_nacl = false;
}
pr_debug("TARGET_CORE[%s]: Deregistered fabric_sess\n",
se_tpg->se_tpg_tfo->get_fabric_name());
/*
* If last kref is dropping now for an explicit NodeACL, awake sleeping
* ->acl_free_comp caller to wakeup configfs se_node_acl->acl_group
* removal context.
* removal context from within transport_free_session() code.
*/
if (se_nacl && comp_nacl)
target_put_nacl(se_nacl);
transport_free_session(se_sess);
}
@@ -715,7 +721,10 @@ void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status)
cmd->transport_state |= (CMD_T_COMPLETE | CMD_T_ACTIVE);
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
queue_work(target_completion_wq, &cmd->work);
if (cmd->cpuid == -1)
queue_work(target_completion_wq, &cmd->work);
else
queue_work_on(cmd->cpuid, target_completion_wq, &cmd->work);
}
EXPORT_SYMBOL(target_complete_cmd);
@@ -1309,7 +1318,7 @@ EXPORT_SYMBOL(target_setup_cmd_from_cdb);
/*
* Used by fabric module frontends to queue tasks directly.
* Many only be used from process context only
* May only be used from process context.
*/
int transport_handle_cdb_direct(
struct se_cmd *cmd)
@@ -1582,7 +1591,7 @@ static void target_complete_tmr_failure(struct work_struct *work)
int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess,
unsigned char *sense, u64 unpacked_lun,
void *fabric_tmr_ptr, unsigned char tm_type,
gfp_t gfp, unsigned int tag, int flags)
gfp_t gfp, u64 tag, int flags)
{
struct se_portal_group *se_tpg;
int ret;

View File

@@ -152,6 +152,7 @@ static struct genl_family tcmu_genl_family = {
.maxattr = TCMU_ATTR_MAX,
.mcgrps = tcmu_mcgrps,
.n_mcgrps = ARRAY_SIZE(tcmu_mcgrps),
.netnsok = true,
};
static struct tcmu_cmd *tcmu_alloc_cmd(struct se_cmd *se_cmd)
@@ -194,7 +195,7 @@ static struct tcmu_cmd *tcmu_alloc_cmd(struct se_cmd *se_cmd)
static inline void tcmu_flush_dcache_range(void *vaddr, size_t size)
{
unsigned long offset = (unsigned long) vaddr & ~PAGE_MASK;
unsigned long offset = offset_in_page(vaddr);
size = round_up(size+offset, PAGE_SIZE);
vaddr -= offset;
@@ -840,7 +841,7 @@ static int tcmu_netlink_event(enum tcmu_genl_cmd cmd, const char *name, int mino
genlmsg_end(skb, msg_header);
ret = genlmsg_multicast(&tcmu_genl_family, skb, 0,
ret = genlmsg_multicast_allns(&tcmu_genl_family, skb, 0,
TCMU_MCGRP_CONFIG, GFP_KERNEL);
/* We don't care if no one is listening */
@@ -917,8 +918,10 @@ static int tcmu_configure_device(struct se_device *dev)
if (ret)
goto err_register;
/* User can set hw_block_size before enable the device */
if (dev->dev_attrib.hw_block_size == 0)
dev->dev_attrib.hw_block_size = 512;
/* Other attributes can be configured in userspace */
dev->dev_attrib.hw_block_size = 512;
dev->dev_attrib.hw_max_sectors = 128;
dev->dev_attrib.hw_queue_depth = 128;

View File

@@ -166,7 +166,6 @@ void ft_aborted_task(struct se_cmd *);
*/
void ft_recv_req(struct ft_sess *, struct fc_frame *);
struct ft_tpg *ft_lport_find_tpg(struct fc_lport *);
struct ft_node_acl *ft_acl_get(struct ft_tpg *, struct fc_rport_priv *);
void ft_recv_write_data(struct ft_cmd *, struct fc_frame *);
void ft_dump_cmd(struct ft_cmd *, const char *caller);

View File

@@ -171,9 +171,31 @@ static ssize_t ft_nacl_node_name_store(struct config_item *item,
CONFIGFS_ATTR(ft_nacl_, node_name);
CONFIGFS_ATTR(ft_nacl_, port_name);
static ssize_t ft_nacl_tag_show(struct config_item *item,
char *page)
{
return snprintf(page, PAGE_SIZE, "%s", acl_to_nacl(item)->acl_tag);
}
static ssize_t ft_nacl_tag_store(struct config_item *item,
const char *page, size_t count)
{
struct se_node_acl *se_nacl = acl_to_nacl(item);
int ret;
ret = core_tpg_set_initiator_node_tag(se_nacl->se_tpg, se_nacl, page);
if (ret < 0)
return ret;
return count;
}
CONFIGFS_ATTR(ft_nacl_, tag);
static struct configfs_attribute *ft_nacl_base_attrs[] = {
&ft_nacl_attr_port_name,
&ft_nacl_attr_node_name,
&ft_nacl_attr_tag,
NULL,
};
@@ -198,31 +220,6 @@ static int ft_init_nodeacl(struct se_node_acl *nacl, const char *name)
return 0;
}
struct ft_node_acl *ft_acl_get(struct ft_tpg *tpg, struct fc_rport_priv *rdata)
{
struct ft_node_acl *found = NULL;
struct ft_node_acl *acl;
struct se_portal_group *se_tpg = &tpg->se_tpg;
struct se_node_acl *se_acl;
mutex_lock(&se_tpg->acl_node_mutex);
list_for_each_entry(se_acl, &se_tpg->acl_node_list, acl_list) {
acl = container_of(se_acl, struct ft_node_acl, se_node_acl);
pr_debug("acl %p port_name %llx\n",
acl, (unsigned long long)acl->node_auth.port_name);
if (acl->node_auth.port_name == rdata->ids.port_name ||
acl->node_auth.node_name == rdata->ids.node_name) {
pr_debug("acl %p port_name %llx matched\n", acl,
(unsigned long long)rdata->ids.port_name);
found = acl;
/* XXX need to hold onto ACL */
break;
}
}
mutex_unlock(&se_tpg->acl_node_mutex);
return found;
}
/*
* local_port port_group (tpg) ops.
*/

View File

@@ -154,9 +154,9 @@ int ft_queue_data_in(struct se_cmd *se_cmd)
BUG_ON(!page);
from = kmap_atomic(page + (mem_off >> PAGE_SHIFT));
page_addr = from;
from += mem_off & ~PAGE_MASK;
from += offset_in_page(mem_off);
tlen = min(tlen, (size_t)(PAGE_SIZE -
(mem_off & ~PAGE_MASK)));
offset_in_page(mem_off)));
memcpy(to, from, tlen);
kunmap_atomic(page_addr);
to += tlen;
@@ -314,9 +314,9 @@ void ft_recv_write_data(struct ft_cmd *cmd, struct fc_frame *fp)
to = kmap_atomic(page + (mem_off >> PAGE_SHIFT));
page_addr = to;
to += mem_off & ~PAGE_MASK;
to += offset_in_page(mem_off);
tlen = min(tlen, (size_t)(PAGE_SIZE -
(mem_off & ~PAGE_MASK)));
offset_in_page(mem_off)));
memcpy(to, from, tlen);
kunmap_atomic(page_addr);

View File

@@ -191,10 +191,15 @@ out:
* Caller holds ft_lport_lock.
*/
static struct ft_sess *ft_sess_create(struct ft_tport *tport, u32 port_id,
struct ft_node_acl *acl)
struct fc_rport_priv *rdata)
{
struct se_portal_group *se_tpg = &tport->tpg->se_tpg;
struct se_node_acl *se_acl;
struct ft_sess *sess;
struct hlist_head *head;
unsigned char initiatorname[TRANSPORT_IQN_LEN];
ft_format_wwn(&initiatorname[0], TRANSPORT_IQN_LEN, rdata->ids.port_name);
head = &tport->hash[ft_sess_hash(port_id)];
hlist_for_each_entry_rcu(sess, head, hash)
@@ -212,7 +217,14 @@ static struct ft_sess *ft_sess_create(struct ft_tport *tport, u32 port_id,
kfree(sess);
return NULL;
}
sess->se_sess->se_node_acl = &acl->se_node_acl;
se_acl = core_tpg_get_initiator_node_acl(se_tpg, &initiatorname[0]);
if (!se_acl) {
transport_free_session(sess->se_sess);
kfree(sess);
return NULL;
}
sess->se_sess->se_node_acl = se_acl;
sess->tport = tport;
sess->port_id = port_id;
kref_init(&sess->kref); /* ref for table entry */
@@ -221,7 +233,7 @@ static struct ft_sess *ft_sess_create(struct ft_tport *tport, u32 port_id,
pr_debug("port_id %x sess %p\n", port_id, sess);
transport_register_session(&tport->tpg->se_tpg, &acl->se_node_acl,
transport_register_session(&tport->tpg->se_tpg, se_acl,
sess->se_sess, sess);
return sess;
}
@@ -260,6 +272,14 @@ static struct ft_sess *ft_sess_delete(struct ft_tport *tport, u32 port_id)
return NULL;
}
static void ft_close_sess(struct ft_sess *sess)
{
transport_deregister_session_configfs(sess->se_sess);
target_sess_cmd_list_set_waiting(sess->se_sess);
target_wait_for_sess_cmds(sess->se_sess);
ft_sess_put(sess);
}
/*
* Delete all sessions from tport.
* Caller holds ft_lport_lock.
@@ -273,8 +293,7 @@ static void ft_sess_delete_all(struct ft_tport *tport)
head < &tport->hash[FT_SESS_HASH_SIZE]; head++) {
hlist_for_each_entry_rcu(sess, head, hash) {
ft_sess_unhash(sess);
transport_deregister_session_configfs(sess->se_sess);
ft_sess_put(sess); /* release from table */
ft_close_sess(sess); /* release from table */
}
}
}
@@ -313,8 +332,7 @@ void ft_sess_close(struct se_session *se_sess)
pr_debug("port_id %x\n", port_id);
ft_sess_unhash(sess);
mutex_unlock(&ft_lport_lock);
transport_deregister_session_configfs(se_sess);
ft_sess_put(sess);
ft_close_sess(sess);
/* XXX Send LOGO or PRLO */
synchronize_rcu(); /* let transport deregister happen */
}
@@ -343,17 +361,12 @@ static int ft_prli_locked(struct fc_rport_priv *rdata, u32 spp_len,
{
struct ft_tport *tport;
struct ft_sess *sess;
struct ft_node_acl *acl;
u32 fcp_parm;
tport = ft_tport_get(rdata->local_port);
if (!tport)
goto not_target; /* not a target for this local port */
acl = ft_acl_get(tport->tpg, rdata);
if (!acl)
goto not_target; /* no target for this remote */
if (!rspp)
goto fill;
@@ -375,7 +388,7 @@ static int ft_prli_locked(struct fc_rport_priv *rdata, u32 spp_len,
spp->spp_flags |= FC_SPP_EST_IMG_PAIR;
if (!(fcp_parm & FCP_SPPF_INIT_FCN))
return FC_SPP_RESP_CONF;
sess = ft_sess_create(tport, rdata->ids.port_id, acl);
sess = ft_sess_create(tport, rdata->ids.port_id, rdata);
if (!sess)
return FC_SPP_RESP_RES;
if (!sess->params)
@@ -460,8 +473,7 @@ static void ft_prlo(struct fc_rport_priv *rdata)
return;
}
mutex_unlock(&ft_lport_lock);
transport_deregister_session_configfs(sess->se_sess);
ft_sess_put(sess); /* release from table */
ft_close_sess(sess); /* release from table */
rdata->prli_count--;
/* XXX TBD - clearing actions. unit attn, see 4.10 */
}