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

Pull SCSI target updates from Nicholas Bellinger:
 "Things were a lot more calm than previously expected. It's primarily
  fixes in various areas, with most of the new functionality centering
  around TCMU backend driver work that Xiubo Li has been driving.

  Here's the summary on the feature side:

   - Make T10-PI verify configurable for emulated (FILEIO + RD) backends
    (Dmitry Monakhov)
   - Allow target-core/TCMU pass-through to use in-kernel SPC-PR logic
    (Bryant Ly + MNC)
   - Add TCMU support for growing ring buffer size (Xiubo Li + MNC)
   - Add TCMU support for global block data pool (Xiubo Li + MNC)

  and on the bug-fix side:

   - Fix COMPARE_AND_WRITE non GOOD status handling for READ phase
    failures (Gary Guo + nab)
   - Fix iscsi-target hang with explicitly changing per NodeACL
    CmdSN number depth with concurrent login driven session
    reinstatement.  (Gary Guo + nab)
   - Fix ibmvscsis fabric driver ABORT task handling (Bryant Ly)
   - Fix target-core/FILEIO zero length handling (Bart Van Assche)

  Also, there was an OOPs introduced with the WRITE_VERIFY changes that
  I ended up reverting at the last minute, because as not unusual Bart
  and I could not agree on the fix in time for -rc1. Since it's specific
  to a conformance test, it's been reverted for now.

  There is a separate patch in the queue to address the underlying
  control CDB write overflow regression in >= v4.3 separate from the
  WRITE_VERIFY revert here, that will be pushed post -rc1"

* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending: (30 commits)
  Revert "target: Fix VERIFY and WRITE VERIFY command parsing"
  IB/srpt: Avoid that aborting a command triggers a kernel warning
  IB/srpt: Fix abort handling
  target/fileio: Fix zero-length READ and WRITE handling
  ibmvscsis: Do not send aborted task response
  tcmu: fix module removal due to stuck thread
  target: Don't force session reset if queue_depth does not change
  iscsi-target: Set session_fall_back_to_erl0 when forcing reinstatement
  target: Fix compare_and_write_callback handling for non GOOD status
  tcmu: Recalculate the tcmu_cmd size to save cmd area memories
  tcmu: Add global data block pool support
  tcmu: Add dynamic growing data area feature support
  target: fixup error message in target_tg_pt_gp_tg_pt_gp_id_store()
  target: fixup error message in target_tg_pt_gp_alua_access_type_store()
  target/user: PGR Support
  target: Add WRITE_VERIFY_16
  Documentation/target: add an example script to configure an iSCSI target
  target: Use kmalloc_array() in transport_kmap_data_sg()
  target: Use kmalloc_array() in compare_and_write_callback()
  target: Improve size determinations in two functions
  ...
This commit is contained in:
Linus Torvalds 2017-05-12 11:44:13 -07:00
commit bd1286f964
23 changed files with 859 additions and 269 deletions

View File

@ -0,0 +1,80 @@
#!/bin/sh
#
# This script illustrates the sequence of operations in configfs to
# create a very simple LIO iSCSI target with a file or block device
# backstore.
#
# (C) Copyright 2014 Christophe Vu-Brugier <cvubrugier@fastmail.fm>
#
print_usage() {
cat <<EOF
Usage: $(basename $0) [-p PORTAL] DEVICE|FILE
Export a block device or a file as an iSCSI target with a single LUN
EOF
}
die() {
echo $1
exit 1
}
while getopts "hp:" arg; do
case $arg in
h) print_usage; exit 0;;
p) PORTAL=${OPTARG};;
esac
done
shift $(($OPTIND - 1))
DEVICE=$1
[ -n "$DEVICE" ] || die "Missing device or file argument"
[ -b $DEVICE -o -f $DEVICE ] || die "Invalid device or file: ${DEVICE}"
IQN="iqn.2003-01.org.linux-iscsi.$(hostname):$(basename $DEVICE)"
[ -n "$PORTAL" ] || PORTAL="0.0.0.0:3260"
CONFIGFS=/sys/kernel/config
CORE_DIR=$CONFIGFS/target/core
ISCSI_DIR=$CONFIGFS/target/iscsi
# Load the target modules and mount the config file system
lsmod | grep -q configfs || modprobe configfs
lsmod | grep -q target_core_mod || modprobe target_core_mod
mount | grep -q ^configfs || mount -t configfs none $CONFIGFS
mkdir -p $ISCSI_DIR
# Create a backstore
if [ -b $DEVICE ]; then
BACKSTORE_DIR=$CORE_DIR/iblock_0/data
mkdir -p $BACKSTORE_DIR
echo "udev_path=${DEVICE}" > $BACKSTORE_DIR/control
else
BACKSTORE_DIR=$CORE_DIR/fileio_0/data
mkdir -p $BACKSTORE_DIR
DEVICE_SIZE=$(du -b $DEVICE | cut -f1)
echo "fd_dev_name=${DEVICE}" > $BACKSTORE_DIR/control
echo "fd_dev_size=${DEVICE_SIZE}" > $BACKSTORE_DIR/control
echo 1 > $BACKSTORE_DIR/attrib/emulate_write_cache
fi
echo 1 > $BACKSTORE_DIR/enable
# Create an iSCSI target and a target portal group (TPG)
mkdir $ISCSI_DIR/$IQN
mkdir $ISCSI_DIR/$IQN/tpgt_1/
# Create a LUN
mkdir $ISCSI_DIR/$IQN/tpgt_1/lun/lun_0
ln -s $BACKSTORE_DIR $ISCSI_DIR/$IQN/tpgt_1/lun/lun_0/data
echo 1 > $ISCSI_DIR/$IQN/tpgt_1/enable
# Create a network portal
mkdir $ISCSI_DIR/$IQN/tpgt_1/np/$PORTAL
# Disable authentication
echo 0 > $ISCSI_DIR/$IQN/tpgt_1/attrib/authentication
echo 1 > $ISCSI_DIR/$IQN/tpgt_1/attrib/generate_node_acls
# Allow write access for non authenticated initiators
echo 0 > $ISCSI_DIR/$IQN/tpgt_1/attrib/demo_mode_write_protect
echo "Target ${IQN}, portal ${PORTAL} has been created"

View File

@ -2302,12 +2302,8 @@ static void srpt_queue_response(struct se_cmd *cmd)
}
spin_unlock_irqrestore(&ioctx->spinlock, flags);
if (unlikely(transport_check_aborted_status(&ioctx->cmd, false)
|| WARN_ON_ONCE(state == SRPT_STATE_CMD_RSP_SENT))) {
atomic_inc(&ch->req_lim_delta);
srpt_abort_cmd(ioctx);
if (unlikely(WARN_ON_ONCE(state == SRPT_STATE_CMD_RSP_SENT)))
return;
}
/* For read commands, transfer the data to the initiator. */
if (ioctx->cmd.data_direction == DMA_FROM_DEVICE &&
@ -2689,7 +2685,8 @@ static void srpt_release_cmd(struct se_cmd *se_cmd)
struct srpt_rdma_ch *ch = ioctx->ch;
unsigned long flags;
WARN_ON(ioctx->state != SRPT_STATE_DONE);
WARN_ON_ONCE(ioctx->state != SRPT_STATE_DONE &&
!(ioctx->cmd.transport_state & CMD_T_ABORTED));
if (ioctx->n_rw_ctx) {
srpt_free_rw_ctxs(ch, ioctx);

View File

@ -1170,6 +1170,7 @@ static struct ibmvscsis_cmd *ibmvscsis_get_free_cmd(struct scsi_info *vscsi)
cmd = list_first_entry_or_null(&vscsi->free_cmd,
struct ibmvscsis_cmd, list);
if (cmd) {
cmd->flags &= ~(DELAY_SEND);
list_del(&cmd->list);
cmd->iue = iue;
cmd->type = UNSET_TYPE;
@ -1749,16 +1750,45 @@ static void srp_snd_msg_failed(struct scsi_info *vscsi, long rc)
static void ibmvscsis_send_messages(struct scsi_info *vscsi)
{
u64 msg_hi = 0;
/* note do not attmempt to access the IU_data_ptr with this pointer
/* note do not attempt to access the IU_data_ptr with this pointer
* it is not valid
*/
struct viosrp_crq *crq = (struct viosrp_crq *)&msg_hi;
struct ibmvscsis_cmd *cmd, *nxt;
struct iu_entry *iue;
long rc = ADAPT_SUCCESS;
bool retry = false;
if (!(vscsi->flags & RESPONSE_Q_DOWN)) {
list_for_each_entry_safe(cmd, nxt, &vscsi->waiting_rsp, list) {
do {
retry = false;
list_for_each_entry_safe(cmd, nxt, &vscsi->waiting_rsp,
list) {
/*
* Check to make sure abort cmd gets processed
* prior to the abort tmr cmd
*/
if (cmd->flags & DELAY_SEND)
continue;
if (cmd->abort_cmd) {
retry = true;
cmd->abort_cmd->flags &= ~(DELAY_SEND);
}
/*
* If CMD_T_ABORTED w/o CMD_T_TAS scenarios and
* the case where LIO issued a
* ABORT_TASK: Sending TMR_TASK_DOES_NOT_EXIST
* case then we dont send a response, since it
* was already done.
*/
if (cmd->se_cmd.transport_state & CMD_T_ABORTED &&
!(cmd->se_cmd.transport_state & CMD_T_TAS)) {
list_del(&cmd->list);
ibmvscsis_free_cmd_resources(vscsi,
cmd);
} else {
iue = cmd->iue;
crq->valid = VALID_CMD_RESP_EL;
@ -1776,18 +1806,23 @@ static void ibmvscsis_send_messages(struct scsi_info *vscsi)
pr_debug("send_messages: cmd %p, tag 0x%llx, rc %ld\n",
cmd, be64_to_cpu(cmd->rsp.tag), rc);
/* if all ok free up the command element resources */
/* if all ok free up the command
* element resources
*/
if (rc == H_SUCCESS) {
/* some movement has occurred */
vscsi->rsp_q_timer.timer_pops = 0;
list_del(&cmd->list);
ibmvscsis_free_cmd_resources(vscsi, cmd);
ibmvscsis_free_cmd_resources(vscsi,
cmd);
} else {
srp_snd_msg_failed(vscsi, rc);
break;
}
}
}
} while (retry);
if (!rc) {
/*
@ -2708,6 +2743,7 @@ static int ibmvscsis_alloc_cmds(struct scsi_info *vscsi, int num)
for (i = 0, cmd = (struct ibmvscsis_cmd *)vscsi->cmd_pool; i < num;
i++, cmd++) {
cmd->abort_cmd = NULL;
cmd->adapter = vscsi;
INIT_WORK(&cmd->work, ibmvscsis_scheduler);
list_add_tail(&cmd->list, &vscsi->free_cmd);
@ -3579,9 +3615,20 @@ static int ibmvscsis_write_pending(struct se_cmd *se_cmd)
{
struct ibmvscsis_cmd *cmd = container_of(se_cmd, struct ibmvscsis_cmd,
se_cmd);
struct scsi_info *vscsi = cmd->adapter;
struct iu_entry *iue = cmd->iue;
int rc;
/*
* If CLIENT_FAILED OR RESPONSE_Q_DOWN, then just return success
* since LIO can't do anything about it, and we dont want to
* attempt an srp_transfer_data.
*/
if ((vscsi->flags & (CLIENT_FAILED | RESPONSE_Q_DOWN))) {
pr_err("write_pending failed since: %d\n", vscsi->flags);
return 0;
}
rc = srp_transfer_data(cmd, &vio_iu(iue)->srp.cmd, ibmvscsis_rdma,
1, 1);
if (rc) {
@ -3660,11 +3707,28 @@ static void ibmvscsis_queue_tm_rsp(struct se_cmd *se_cmd)
struct ibmvscsis_cmd *cmd = container_of(se_cmd, struct ibmvscsis_cmd,
se_cmd);
struct scsi_info *vscsi = cmd->adapter;
struct ibmvscsis_cmd *cmd_itr;
struct iu_entry *iue = iue = cmd->iue;
struct srp_tsk_mgmt *srp_tsk = &vio_iu(iue)->srp.tsk_mgmt;
u64 tag_to_abort = be64_to_cpu(srp_tsk->task_tag);
uint len;
pr_debug("queue_tm_rsp %p, status %d\n",
se_cmd, (int)se_cmd->se_tmr_req->response);
if (srp_tsk->tsk_mgmt_func == SRP_TSK_ABORT_TASK &&
cmd->se_cmd.se_tmr_req->response == TMR_TASK_DOES_NOT_EXIST) {
spin_lock_bh(&vscsi->intr_lock);
list_for_each_entry(cmd_itr, &vscsi->active_q, list) {
if (tag_to_abort == cmd_itr->se_cmd.tag) {
cmd_itr->abort_cmd = cmd;
cmd->flags |= DELAY_SEND;
break;
}
}
spin_unlock_bh(&vscsi->intr_lock);
}
srp_build_response(vscsi, cmd, &len);
cmd->rsp.format = SRP_FORMAT;
cmd->rsp.len = len;
@ -3672,8 +3736,8 @@ static void ibmvscsis_queue_tm_rsp(struct se_cmd *se_cmd)
static void ibmvscsis_aborted_task(struct se_cmd *se_cmd)
{
/* TBD: What (if anything) should we do here? */
pr_debug("ibmvscsis_aborted_task %p\n", se_cmd);
pr_debug("ibmvscsis_aborted_task %p task_tag: %llu\n",
se_cmd, se_cmd->tag);
}
static struct se_wwn *ibmvscsis_make_tport(struct target_fabric_configfs *tf,

View File

@ -168,10 +168,12 @@ struct ibmvscsis_cmd {
struct iu_rsp rsp;
struct work_struct work;
struct scsi_info *adapter;
struct ibmvscsis_cmd *abort_cmd;
/* Sense buffer that will be mapped into outgoing status */
unsigned char sense_buf[TRANSPORT_SENSE_BUFFER];
u64 init_time;
#define CMD_FAST_FAIL BIT(0)
#define DELAY_SEND BIT(1)
u32 flags;
char type;
};

View File

@ -128,11 +128,9 @@ struct iscsi_tiqn *iscsit_add_tiqn(unsigned char *buf)
return ERR_PTR(-EINVAL);
}
tiqn = kzalloc(sizeof(struct iscsi_tiqn), GFP_KERNEL);
if (!tiqn) {
pr_err("Unable to allocate struct iscsi_tiqn\n");
tiqn = kzalloc(sizeof(*tiqn), GFP_KERNEL);
if (!tiqn)
return ERR_PTR(-ENOMEM);
}
sprintf(tiqn->tiqn, "%s", buf);
INIT_LIST_HEAD(&tiqn->tiqn_list);
@ -362,9 +360,8 @@ struct iscsi_np *iscsit_add_np(
return np;
}
np = kzalloc(sizeof(struct iscsi_np), GFP_KERNEL);
np = kzalloc(sizeof(*np), GFP_KERNEL);
if (!np) {
pr_err("Unable to allocate memory for struct iscsi_np\n");
mutex_unlock(&np_lock);
return ERR_PTR(-ENOMEM);
}
@ -696,12 +693,10 @@ static int __init iscsi_target_init_module(void)
int ret = 0, size;
pr_debug("iSCSI-Target "ISCSIT_VERSION"\n");
iscsit_global = kzalloc(sizeof(struct iscsit_global), GFP_KERNEL);
if (!iscsit_global) {
pr_err("Unable to allocate memory for iscsit_global\n");
iscsit_global = kzalloc(sizeof(*iscsit_global), GFP_KERNEL);
if (!iscsit_global)
return -1;
}
spin_lock_init(&iscsit_global->ts_bitmap_lock);
mutex_init(&auth_id_lock);
spin_lock_init(&sess_idr_lock);
@ -714,10 +709,8 @@ static int __init iscsi_target_init_module(void)
size = BITS_TO_LONGS(ISCSIT_BITMAP_BITS) * sizeof(long);
iscsit_global->ts_bitmap = vzalloc(size);
if (!iscsit_global->ts_bitmap) {
pr_err("Unable to allocate iscsit_global->ts_bitmap\n");
if (!iscsit_global->ts_bitmap)
goto configfs_out;
}
lio_qr_cache = kmem_cache_create("lio_qr_cache",
sizeof(struct iscsi_queue_req),
@ -984,12 +977,9 @@ static int iscsit_allocate_iovecs(struct iscsi_cmd *cmd)
u32 iov_count = max(1UL, DIV_ROUND_UP(cmd->se_cmd.data_length, PAGE_SIZE));
iov_count += ISCSI_IOV_DATA_BUFFER;
cmd->iov_data = kzalloc(iov_count * sizeof(struct kvec), GFP_KERNEL);
if (!cmd->iov_data) {
pr_err("Unable to allocate cmd->iov_data\n");
cmd->iov_data = kcalloc(iov_count, sizeof(*cmd->iov_data), GFP_KERNEL);
if (!cmd->iov_data)
return -ENOMEM;
}
cmd->orig_iov_data_count = iov_count;
return 0;
@ -1850,8 +1840,6 @@ static int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
ping_data = kzalloc(payload_length + 1, GFP_KERNEL);
if (!ping_data) {
pr_err("Unable to allocate memory for"
" NOPOUT ping data.\n");
ret = -1;
goto out;
}
@ -1997,15 +1985,11 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
hdr->refcmdsn = cpu_to_be32(ISCSI_RESERVED_TAG);
cmd->data_direction = DMA_NONE;
cmd->tmr_req = kzalloc(sizeof(struct iscsi_tmr_req), GFP_KERNEL);
if (!cmd->tmr_req) {
pr_err("Unable to allocate memory for"
" Task Management command!\n");
cmd->tmr_req = kzalloc(sizeof(*cmd->tmr_req), GFP_KERNEL);
if (!cmd->tmr_req)
return iscsit_add_reject_cmd(cmd,
ISCSI_REASON_BOOKMARK_NO_RESOURCES,
buf);
}
/*
* TASK_REASSIGN for ERL=2 / connection stays inside of
@ -2265,11 +2249,9 @@ iscsit_handle_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
struct kvec iov[3];
text_in = kzalloc(payload_length, GFP_KERNEL);
if (!text_in) {
pr_err("Unable to allocate memory for"
" incoming text parameters\n");
if (!text_in)
goto reject;
}
cmd->text_in_ptr = text_in;
memset(iov, 0, 3 * sizeof(struct kvec));
@ -3353,11 +3335,9 @@ iscsit_build_sendtargets_response(struct iscsi_cmd *cmd,
SENDTARGETS_BUF_LIMIT);
payload = kzalloc(buffer_len, GFP_KERNEL);
if (!payload) {
pr_err("Unable to allocate memory for sendtargets"
" response.\n");
if (!payload)
return -ENOMEM;
}
/*
* Locate pointer to iqn./eui. string for ICF_SENDTARGETS_SINGLE
* explicit case..
@ -4683,6 +4663,7 @@ int iscsit_release_sessions_for_tpg(struct iscsi_portal_group *tpg, int force)
continue;
}
atomic_set(&sess->session_reinstatement, 1);
atomic_set(&sess->session_fall_back_to_erl0, 1);
spin_unlock(&sess->conn_lock);
list_move_tail(&se_sess->sess_list, &free_list);

View File

@ -1506,6 +1506,7 @@ static void lio_tpg_close_session(struct se_session *se_sess)
return;
}
atomic_set(&sess->session_reinstatement, 1);
atomic_set(&sess->session_fall_back_to_erl0, 1);
spin_unlock(&sess->conn_lock);
iscsit_stop_time2retain_timer(sess);

View File

@ -208,6 +208,7 @@ int iscsi_check_for_session_reinstatement(struct iscsi_conn *conn)
initiatorname_param->value) &&
(sess_p->sess_ops->SessionType == sessiontype))) {
atomic_set(&sess_p->session_reinstatement, 1);
atomic_set(&sess_p->session_fall_back_to_erl0, 1);
spin_unlock(&sess_p->conn_lock);
iscsit_inc_session_usage_count(sess_p);
iscsit_stop_time2retain_timer(sess_p);

View File

@ -533,6 +533,7 @@ DEF_CONFIGFS_ATTRIB_SHOW(emulate_3pc);
DEF_CONFIGFS_ATTRIB_SHOW(pi_prot_type);
DEF_CONFIGFS_ATTRIB_SHOW(hw_pi_prot_type);
DEF_CONFIGFS_ATTRIB_SHOW(pi_prot_format);
DEF_CONFIGFS_ATTRIB_SHOW(pi_prot_verify);
DEF_CONFIGFS_ATTRIB_SHOW(enforce_pr_isids);
DEF_CONFIGFS_ATTRIB_SHOW(is_nonrot);
DEF_CONFIGFS_ATTRIB_SHOW(emulate_rest_reord);
@ -823,6 +824,7 @@ static ssize_t pi_prot_type_store(struct config_item *item,
ret = dev->transport->init_prot(dev);
if (ret) {
da->pi_prot_type = old_prot;
da->pi_prot_verify = (bool) da->pi_prot_type;
return ret;
}
@ -830,6 +832,7 @@ static ssize_t pi_prot_type_store(struct config_item *item,
dev->transport->free_prot(dev);
}
da->pi_prot_verify = (bool) da->pi_prot_type;
pr_debug("dev[%p]: SE Device Protection Type: %d\n", dev, flag);
return count;
}
@ -872,6 +875,35 @@ static ssize_t pi_prot_format_store(struct config_item *item,
return count;
}
static ssize_t pi_prot_verify_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 (!flag) {
da->pi_prot_verify = flag;
return count;
}
if (da->hw_pi_prot_type) {
pr_warn("DIF protection enabled on underlying hardware,"
" ignoring\n");
return count;
}
if (!da->pi_prot_type) {
pr_warn("DIF protection not supported by backend, ignoring\n");
return count;
}
da->pi_prot_verify = flag;
return count;
}
static ssize_t force_pr_aptpl_store(struct config_item *item,
const char *page, size_t count)
{
@ -1067,6 +1099,7 @@ CONFIGFS_ATTR(, emulate_3pc);
CONFIGFS_ATTR(, pi_prot_type);
CONFIGFS_ATTR_RO(, hw_pi_prot_type);
CONFIGFS_ATTR(, pi_prot_format);
CONFIGFS_ATTR(, pi_prot_verify);
CONFIGFS_ATTR(, enforce_pr_isids);
CONFIGFS_ATTR(, is_nonrot);
CONFIGFS_ATTR(, emulate_rest_reord);
@ -1104,6 +1137,7 @@ struct configfs_attribute *sbc_attrib_attrs[] = {
&attr_pi_prot_type,
&attr_hw_pi_prot_type,
&attr_pi_prot_format,
&attr_pi_prot_verify,
&attr_enforce_pr_isids,
&attr_is_nonrot,
&attr_emulate_rest_reord,
@ -1366,7 +1400,7 @@ static ssize_t target_pr_res_holder_show(struct config_item *item, char *page)
struct se_device *dev = pr_to_dev(item);
int ret;
if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_PGR)
return sprintf(page, "Passthrough\n");
spin_lock(&dev->dev_reservation_lock);
@ -1506,7 +1540,7 @@ static ssize_t target_pr_res_type_show(struct config_item *item, char *page)
{
struct se_device *dev = pr_to_dev(item);
if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_PGR)
return sprintf(page, "SPC_PASSTHROUGH\n");
else if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS)
return sprintf(page, "SPC2_RESERVATIONS\n");
@ -1519,7 +1553,7 @@ static ssize_t target_pr_res_aptpl_active_show(struct config_item *item,
{
struct se_device *dev = pr_to_dev(item);
if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_PGR)
return 0;
return sprintf(page, "APTPL Bit Status: %s\n",
@ -1531,7 +1565,7 @@ static ssize_t target_pr_res_aptpl_metadata_show(struct config_item *item,
{
struct se_device *dev = pr_to_dev(item);
if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_PGR)
return 0;
return sprintf(page, "Ready to process PR APTPL metadata..\n");
@ -1577,7 +1611,7 @@ static ssize_t target_pr_res_aptpl_metadata_store(struct config_item *item,
u16 tpgt = 0;
u8 type = 0;
if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_PGR)
return count;
if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS)
return count;
@ -2511,7 +2545,7 @@ static ssize_t target_tg_pt_gp_alua_support_##_name##_store( \
int ret; \
\
if (!t->tg_pt_gp_valid_id) { \
pr_err("Unable to do set ##_name ALUA state on non" \
pr_err("Unable to do set " #_name " ALUA state on non" \
" valid tg_pt_gp ID: %hu\n", \
t->tg_pt_gp_valid_id); \
return -EINVAL; \
@ -2643,13 +2677,13 @@ static ssize_t target_tg_pt_gp_tg_pt_gp_id_store(struct config_item *item,
ret = kstrtoul(page, 0, &tg_pt_gp_id);
if (ret < 0) {
pr_err("kstrtoul() returned %d for"
" tg_pt_gp_id\n", ret);
pr_err("ALUA tg_pt_gp_id: invalid value '%s' for tg_pt_gp_id\n",
page);
return ret;
}
if (tg_pt_gp_id > 0x0000ffff) {
pr_err("ALUA tg_pt_gp_id: %lu exceeds maximum:"
" 0x0000ffff\n", tg_pt_gp_id);
pr_err("ALUA tg_pt_gp_id: %lu exceeds maximum: 0x0000ffff\n",
tg_pt_gp_id);
return -EINVAL;
}

View File

@ -1045,6 +1045,8 @@ passthrough_parse_cdb(struct se_cmd *cmd,
sense_reason_t (*exec_cmd)(struct se_cmd *cmd))
{
unsigned char *cdb = cmd->t_task_cdb;
struct se_device *dev = cmd->se_dev;
unsigned int size;
/*
* Clear a lun set in the cdb if the initiator talking to use spoke
@ -1076,6 +1078,42 @@ passthrough_parse_cdb(struct se_cmd *cmd,
return TCM_NO_SENSE;
}
/*
* For PERSISTENT RESERVE IN/OUT, RELEASE, and RESERVE we need to
* emulate the response, since tcmu does not have the information
* required to process these commands.
*/
if (!(dev->transport->transport_flags &
TRANSPORT_FLAG_PASSTHROUGH_PGR)) {
if (cdb[0] == PERSISTENT_RESERVE_IN) {
cmd->execute_cmd = target_scsi3_emulate_pr_in;
size = (cdb[7] << 8) + cdb[8];
return target_cmd_size_check(cmd, size);
}
if (cdb[0] == PERSISTENT_RESERVE_OUT) {
cmd->execute_cmd = target_scsi3_emulate_pr_out;
size = (cdb[7] << 8) + cdb[8];
return target_cmd_size_check(cmd, size);
}
if (cdb[0] == RELEASE || cdb[0] == RELEASE_10) {
cmd->execute_cmd = target_scsi2_reservation_release;
if (cdb[0] == RELEASE_10)
size = (cdb[7] << 8) | cdb[8];
else
size = cmd->data_length;
return target_cmd_size_check(cmd, size);
}
if (cdb[0] == RESERVE || cdb[0] == RESERVE_10) {
cmd->execute_cmd = target_scsi2_reservation_reserve;
if (cdb[0] == RESERVE_10)
size = (cdb[7] << 8) | cdb[8];
else
size = cmd->data_length;
return target_cmd_size_check(cmd, size);
}
}
/* Set DATA_CDB flag for ops that should have it */
switch (cdb[0]) {
case READ_6:

View File

@ -277,12 +277,11 @@ static int fd_do_rw(struct se_cmd *cmd, struct file *fd,
else
ret = vfs_iter_read(fd, &iter, &pos);
kfree(bvec);
if (is_write) {
if (ret < 0 || ret != data_length) {
pr_err("%s() write returned %d\n", __func__, ret);
return (ret < 0 ? ret : -EINVAL);
if (ret >= 0)
ret = -EINVAL;
}
} else {
/*
@ -295,17 +294,29 @@ static int fd_do_rw(struct se_cmd *cmd, struct file *fd,
pr_err("%s() returned %d, expecting %u for "
"S_ISBLK\n", __func__, ret,
data_length);
return (ret < 0 ? ret : -EINVAL);
if (ret >= 0)
ret = -EINVAL;
}
} else {
if (ret < 0) {
pr_err("%s() returned %d for non S_ISBLK\n",
__func__, ret);
} else if (ret != data_length) {
/*
* Short read case:
* Probably some one truncate file under us.
* We must explicitly zero sg-pages to prevent
* expose uninizialized pages to userspace.
*/
if (ret < data_length)
ret += iov_iter_zero(data_length - ret, &iter);
else
ret = -EINVAL;
}
}
}
kfree(bvec);
return ret;
}
}
}
return 1;
}
static sense_reason_t
@ -543,7 +554,8 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
ret = fd_do_rw(cmd, file, dev->dev_attrib.block_size,
sgl, sgl_nents, cmd->data_length, 0);
if (ret > 0 && cmd->prot_type && dev->dev_attrib.pi_prot_type) {
if (ret > 0 && cmd->prot_type && dev->dev_attrib.pi_prot_type &&
dev->dev_attrib.pi_prot_verify) {
u32 sectors = cmd->data_length >>
ilog2(dev->dev_attrib.block_size);
@ -553,7 +565,8 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
return rc;
}
} else {
if (cmd->prot_type && dev->dev_attrib.pi_prot_type) {
if (cmd->prot_type && dev->dev_attrib.pi_prot_type &&
dev->dev_attrib.pi_prot_verify) {
u32 sectors = cmd->data_length >>
ilog2(dev->dev_attrib.block_size);
@ -595,7 +608,6 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
if (ret < 0)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
if (ret)
target_complete_cmd(cmd, SAM_STAT_GOOD);
return 0;
}

View File

@ -279,7 +279,7 @@ static void iblock_complete_cmd(struct se_cmd *cmd)
struct iblock_req *ibr = cmd->priv;
u8 status;
if (!atomic_dec_and_test(&ibr->pending))
if (!refcount_dec_and_test(&ibr->pending))
return;
if (atomic_read(&ibr->ib_bio_err_cnt))
@ -487,7 +487,7 @@ iblock_execute_write_same(struct se_cmd *cmd)
bio_list_init(&list);
bio_list_add(&list, bio);
atomic_set(&ibr->pending, 1);
refcount_set(&ibr->pending, 1);
while (sectors) {
while (bio_add_page(bio, sg_page(sg), sg->length, sg->offset)
@ -498,7 +498,7 @@ iblock_execute_write_same(struct se_cmd *cmd)
if (!bio)
goto fail_put_bios;
atomic_inc(&ibr->pending);
refcount_inc(&ibr->pending);
bio_list_add(&list, bio);
}
@ -706,7 +706,7 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
cmd->priv = ibr;
if (!sgl_nents) {
atomic_set(&ibr->pending, 1);
refcount_set(&ibr->pending, 1);
iblock_complete_cmd(cmd);
return 0;
}
@ -719,7 +719,7 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
bio_list_init(&list);
bio_list_add(&list, bio);
atomic_set(&ibr->pending, 2);
refcount_set(&ibr->pending, 2);
bio_cnt = 1;
for_each_sg(sgl, sg, sgl_nents, i) {
@ -740,7 +740,7 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
if (!bio)
goto fail_put_bios;
atomic_inc(&ibr->pending);
refcount_inc(&ibr->pending);
bio_list_add(&list, bio);
bio_cnt++;
}

View File

@ -2,6 +2,7 @@
#define TARGET_CORE_IBLOCK_H
#include <linux/atomic.h>
#include <linux/refcount.h>
#include <target/target_core_base.h>
#define IBLOCK_VERSION "4.0"
@ -10,7 +11,7 @@
#define IBLOCK_LBA_SHIFT 9
struct iblock_req {
atomic_t pending;
refcount_t pending;
atomic_t ib_bio_err_cnt;
} ____cacheline_aligned;

View File

@ -4147,7 +4147,7 @@ target_check_reservation(struct se_cmd *cmd)
return 0;
if (dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)
return 0;
if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_PGR)
return 0;
spin_lock(&dev->dev_reservation_lock);

View File

@ -7,7 +7,7 @@
/*
* PERSISTENT_RESERVE_OUT service action codes
*
* spc4r17 section 6.14.2 Table 171
* spc5r04b section 6.15.2 Table 174
*/
#define PRO_REGISTER 0x00
#define PRO_RESERVE 0x01
@ -17,10 +17,11 @@
#define PRO_PREEMPT_AND_ABORT 0x05
#define PRO_REGISTER_AND_IGNORE_EXISTING_KEY 0x06
#define PRO_REGISTER_AND_MOVE 0x07
#define PRO_REPLACE_LOST_RESERVATION 0x08
/*
* PERSISTENT_RESERVE_IN service action codes
*
* spc4r17 section 6.13.1 Table 159
* spc5r04b section 6.14.1 Table 162
*/
#define PRI_READ_KEYS 0x00
#define PRI_READ_RESERVATION 0x01
@ -29,13 +30,13 @@
/*
* PERSISTENT_RESERVE_ SCOPE field
*
* spc4r17 section 6.13.3.3 Table 163
* spc5r04b section 6.14.3.2 Table 166
*/
#define PR_SCOPE_LU_SCOPE 0x00
/*
* PERSISTENT_RESERVE_* TYPE field
*
* spc4r17 section 6.13.3.4 Table 164
* spc5r04b section 6.14.3.3 Table 167
*/
#define PR_TYPE_WRITE_EXCLUSIVE 0x01
#define PR_TYPE_EXCLUSIVE_ACCESS 0x03

View File

@ -1081,7 +1081,8 @@ static const struct target_backend_ops pscsi_ops = {
.name = "pscsi",
.owner = THIS_MODULE,
.transport_flags = TRANSPORT_FLAG_PASSTHROUGH |
TRANSPORT_FLAG_PASSTHROUGH_ALUA,
TRANSPORT_FLAG_PASSTHROUGH_ALUA |
TRANSPORT_FLAG_PASSTHROUGH_PGR,
.attach_hba = pscsi_attach_hba,
.detach_hba = pscsi_detach_hba,
.pmode_enable_hba = pscsi_pmode_enable_hba,

View File

@ -47,11 +47,9 @@ static int rd_attach_hba(struct se_hba *hba, u32 host_id)
{
struct rd_host *rd_host;
rd_host = kzalloc(sizeof(struct rd_host), GFP_KERNEL);
if (!rd_host) {
pr_err("Unable to allocate memory for struct rd_host\n");
rd_host = kzalloc(sizeof(*rd_host), GFP_KERNEL);
if (!rd_host)
return -ENOMEM;
}
rd_host->rd_host_id = host_id;
@ -148,11 +146,8 @@ static int rd_allocate_sgl_table(struct rd_dev *rd_dev, struct rd_dev_sg_table *
sg = kcalloc(sg_per_table + chain_entry, sizeof(*sg),
GFP_KERNEL);
if (!sg) {
pr_err("Unable to allocate scatterlist array"
" for struct rd_dev\n");
if (!sg)
return -ENOMEM;
}
sg_init_table(sg, sg_per_table + chain_entry);
@ -210,13 +205,9 @@ static int rd_build_device_space(struct rd_dev *rd_dev)
total_sg_needed = rd_dev->rd_page_count;
sg_tables = (total_sg_needed / max_sg_per_table) + 1;
sg_table = kzalloc(sg_tables * sizeof(struct rd_dev_sg_table), GFP_KERNEL);
if (!sg_table) {
pr_err("Unable to allocate memory for Ramdisk"
" scatterlist tables\n");
sg_table = kcalloc(sg_tables, sizeof(*sg_table), GFP_KERNEL);
if (!sg_table)
return -ENOMEM;
}
rd_dev->sg_table_array = sg_table;
rd_dev->sg_table_count = sg_tables;
@ -271,13 +262,9 @@ static int rd_build_prot_space(struct rd_dev *rd_dev, int prot_length, int block
total_sg_needed = (rd_dev->rd_page_count * prot_length / block_size) + 1;
sg_tables = (total_sg_needed / max_sg_per_table) + 1;
sg_table = kzalloc(sg_tables * sizeof(struct rd_dev_sg_table), GFP_KERNEL);
if (!sg_table) {
pr_err("Unable to allocate memory for Ramdisk protection"
" scatterlist tables\n");
sg_table = kcalloc(sg_tables, sizeof(*sg_table), GFP_KERNEL);
if (!sg_table)
return -ENOMEM;
}
rd_dev->sg_prot_array = sg_table;
rd_dev->sg_prot_count = sg_tables;
@ -298,11 +285,9 @@ static struct se_device *rd_alloc_device(struct se_hba *hba, const char *name)
struct rd_dev *rd_dev;
struct rd_host *rd_host = hba->hba_ptr;
rd_dev = kzalloc(sizeof(struct rd_dev), GFP_KERNEL);
if (!rd_dev) {
pr_err("Unable to allocate memory for struct rd_dev\n");
rd_dev = kzalloc(sizeof(*rd_dev), GFP_KERNEL);
if (!rd_dev)
return NULL;
}
rd_dev->rd_host = rd_host;
@ -410,7 +395,7 @@ static sense_reason_t rd_do_prot_rw(struct se_cmd *cmd, bool is_read)
u32 prot_offset, prot_page;
u32 prot_npages __maybe_unused;
u64 tmp;
sense_reason_t rc = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
sense_reason_t rc = 0;
tmp = cmd->t_task_lba * se_dev->prot_length;
prot_offset = do_div(tmp, PAGE_SIZE);
@ -423,13 +408,14 @@ static sense_reason_t rd_do_prot_rw(struct se_cmd *cmd, bool is_read)
prot_sg = &prot_table->sg_table[prot_page -
prot_table->page_start_offset];
if (se_dev->dev_attrib.pi_prot_verify) {
if (is_read)
rc = sbc_dif_verify(cmd, cmd->t_task_lba, sectors, 0,
prot_sg, prot_offset);
else
rc = sbc_dif_verify(cmd, cmd->t_task_lba, sectors, 0,
cmd->t_prot_sg, 0);
}
if (!rc)
sbc_dif_copy_prot(cmd, sectors, is_read, prot_sg, prot_offset);

View File

@ -507,8 +507,11 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool succes
* been failed with a non-zero SCSI status.
*/
if (cmd->scsi_status) {
pr_err("compare_and_write_callback: non zero scsi_status:"
pr_debug("compare_and_write_callback: non zero scsi_status:"
" 0x%02x\n", cmd->scsi_status);
*post_ret = 1;
if (cmd->scsi_status == SAM_STAT_CHECK_CONDITION)
ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
goto out;
}
@ -519,7 +522,7 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool succes
goto out;
}
write_sg = kmalloc(sizeof(struct scatterlist) * cmd->t_data_nents,
write_sg = kmalloc_array(cmd->t_data_nents, sizeof(*write_sg),
GFP_KERNEL);
if (!write_sg) {
pr_err("Unable to allocate compare_and_write sg\n");
@ -924,6 +927,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
cmd->execute_cmd = sbc_execute_rw;
break;
case WRITE_16:
case WRITE_VERIFY_16:
sectors = transport_get_sectors_16(cdb);
cmd->t_task_lba = transport_lba_64(cdb);

View File

@ -397,6 +397,13 @@ int core_tpg_set_initiator_node_queue_depth(
{
struct se_portal_group *tpg = acl->se_tpg;
/*
* Allow the setting of se_node_acl queue_depth to be idempotent,
* and not force a session shutdown event if the value is not
* changing.
*/
if (acl->queue_depth == queue_depth)
return 0;
/*
* 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

View File

@ -2311,7 +2311,7 @@ void *transport_kmap_data_sg(struct se_cmd *cmd)
return kmap(sg_page(sg)) + sg->offset;
/* >1 page. use vmap */
pages = kmalloc(sizeof(*pages) * cmd->t_data_nents, GFP_KERNEL);
pages = kmalloc_array(cmd->t_data_nents, sizeof(*pages), GFP_KERNEL);
if (!pages)
return NULL;

File diff suppressed because it is too large Load Diff

View File

@ -112,6 +112,7 @@
#define WRITE_16 0x8a
#define READ_ATTRIBUTE 0x8c
#define WRITE_ATTRIBUTE 0x8d
#define WRITE_VERIFY_16 0x8e
#define VERIFY_16 0x8f
#define SYNCHRONIZE_CACHE_16 0x91
#define WRITE_SAME_16 0x93

View File

@ -10,6 +10,7 @@
* backend module.
*/
#define TRANSPORT_FLAG_PASSTHROUGH_ALUA 0x2
#define TRANSPORT_FLAG_PASSTHROUGH_PGR 0x4
struct request_queue;
struct scatterlist;

View File

@ -664,6 +664,7 @@ struct se_dev_attrib {
int pi_prot_format;
enum target_prot_type pi_prot_type;
enum target_prot_type hw_pi_prot_type;
int pi_prot_verify;
int enforce_pr_isids;
int force_pr_aptpl;
int is_nonrot;