diff options
Diffstat (limited to 'drivers/target')
| -rw-r--r-- | drivers/target/Kconfig | 1 | ||||
| -rw-r--r-- | drivers/target/iscsi/cxgbit/cxgbit_cm.c | 3 | ||||
| -rw-r--r-- | drivers/target/iscsi/iscsi_target_auth.c | 3 | ||||
| -rw-r--r-- | drivers/target/iscsi/iscsi_target_nego.c | 3 | ||||
| -rw-r--r-- | drivers/target/loopback/tcm_loop.c | 145 | ||||
| -rw-r--r-- | drivers/target/sbp/sbp_target.c | 13 | ||||
| -rw-r--r-- | drivers/target/target_core_configfs.c | 6 | ||||
| -rw-r--r-- | drivers/target/target_core_device.c | 4 | ||||
| -rw-r--r-- | drivers/target/target_core_fabric_lib.c | 6 | ||||
| -rw-r--r-- | drivers/target/target_core_internal.h | 3 | ||||
| -rw-r--r-- | drivers/target/target_core_pr.c | 4 | ||||
| -rw-r--r-- | drivers/target/target_core_sbc.c | 8 | ||||
| -rw-r--r-- | drivers/target/target_core_transport.c | 49 | ||||
| -rw-r--r-- | drivers/target/target_core_user.c | 983 | 
14 files changed, 800 insertions, 431 deletions
| diff --git a/drivers/target/Kconfig b/drivers/target/Kconfig index e2bc99980f75..4c44d7bed01a 100644 --- a/drivers/target/Kconfig +++ b/drivers/target/Kconfig @@ -5,6 +5,7 @@ menuconfig TARGET_CORE  	select CONFIGFS_FS  	select CRC_T10DIF  	select BLK_SCSI_REQUEST # only for scsi_command_size_tbl.. +	select SGL_ALLOC  	default n  	help  	Say Y or M here to enable the TCM Storage Engine and ConfigFS enabled diff --git a/drivers/target/iscsi/cxgbit/cxgbit_cm.c b/drivers/target/iscsi/cxgbit/cxgbit_cm.c index 92eb57e2adaf..8de16016b6de 100644 --- a/drivers/target/iscsi/cxgbit/cxgbit_cm.c +++ b/drivers/target/iscsi/cxgbit/cxgbit_cm.c @@ -893,6 +893,9 @@ cxgbit_offload_init(struct cxgbit_sock *csk, int iptype, __u8 *peer_ip,  		return -ENODEV;  	rcu_read_lock(); +	if (!(n->nud_state & NUD_VALID)) +		neigh_event_send(n, NULL); +  	ret = -ENOMEM;  	if (n->dev->flags & IFF_LOOPBACK) {  		if (iptype == 4) diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c index f9bc8ec6fb6b..9518ffd8b8ba 100644 --- a/drivers/target/iscsi/iscsi_target_auth.c +++ b/drivers/target/iscsi/iscsi_target_auth.c @@ -421,7 +421,8 @@ static int chap_server_compute_md5(  	auth_ret = 0;  out:  	kzfree(desc); -	crypto_free_shash(tfm); +	if (tfm) +		crypto_free_shash(tfm);  	kfree(challenge);  	kfree(challenge_binhex);  	return auth_ret; diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c index b686e2ce9c0e..8a5e8d17a942 100644 --- a/drivers/target/iscsi/iscsi_target_nego.c +++ b/drivers/target/iscsi/iscsi_target_nego.c @@ -432,6 +432,9 @@ static void iscsi_target_sk_data_ready(struct sock *sk)  	if (test_and_set_bit(LOGIN_FLAGS_READ_ACTIVE, &conn->login_flags)) {  		write_unlock_bh(&sk->sk_callback_lock);  		pr_debug("Got LOGIN_FLAGS_READ_ACTIVE=1, conn: %p >>>>\n", conn); +		if (iscsi_target_sk_data_ready == conn->orig_data_ready) +			return; +		conn->orig_data_ready(sk);  		return;  	} diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index b6a913e38b30..9cd4ffe76c07 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -64,7 +64,7 @@ static void tcm_loop_release_cmd(struct se_cmd *se_cmd)  static int tcm_loop_show_info(struct seq_file *m, struct Scsi_Host *host)  { -	seq_printf(m, "tcm_loop_proc_info()\n"); +	seq_puts(m, "tcm_loop_proc_info()\n");  	return 0;  } @@ -123,8 +123,8 @@ static void tcm_loop_submission_work(struct work_struct *work)  	}  	tl_nexus = tl_tpg->tl_nexus;  	if (!tl_nexus) { -		scmd_printk(KERN_ERR, sc, "TCM_Loop I_T Nexus" -				" does not exist\n"); +		scmd_printk(KERN_ERR, sc, +			    "TCM_Loop I_T Nexus does not exist\n");  		set_host_byte(sc, DID_ERROR);  		goto out_done;  	} @@ -166,7 +166,6 @@ static void tcm_loop_submission_work(struct work_struct *work)  out_done:  	kmem_cache_free(tcm_loop_cmd_cache, tl_cmd);  	sc->scsi_done(sc); -	return;  }  /* @@ -177,14 +176,13 @@ static int tcm_loop_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc)  {  	struct tcm_loop_cmd *tl_cmd; -	pr_debug("tcm_loop_queuecommand() %d:%d:%d:%llu got CDB: 0x%02x" -		" scsi_buf_len: %u\n", sc->device->host->host_no, -		sc->device->id, sc->device->channel, sc->device->lun, -		sc->cmnd[0], scsi_bufflen(sc)); +	pr_debug("%s() %d:%d:%d:%llu got CDB: 0x%02x scsi_buf_len: %u\n", +		 __func__, sc->device->host->host_no, sc->device->id, +		 sc->device->channel, sc->device->lun, sc->cmnd[0], +		 scsi_bufflen(sc));  	tl_cmd = kmem_cache_zalloc(tcm_loop_cmd_cache, GFP_ATOMIC);  	if (!tl_cmd) { -		pr_err("Unable to allocate struct tcm_loop_cmd\n");  		set_host_byte(sc, DID_ERROR);  		sc->scsi_done(sc);  		return 0; @@ -204,10 +202,10 @@ static int tcm_loop_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc)  static int tcm_loop_issue_tmr(struct tcm_loop_tpg *tl_tpg,  			      u64 lun, int task, enum tcm_tmreq_table tmr)  { -	struct se_cmd *se_cmd = NULL; +	struct se_cmd *se_cmd;  	struct se_session *se_sess;  	struct tcm_loop_nexus *tl_nexus; -	struct tcm_loop_cmd *tl_cmd = NULL; +	struct tcm_loop_cmd *tl_cmd;  	int ret = TMR_FUNCTION_FAILED, rc;  	/* @@ -215,16 +213,13 @@ static int tcm_loop_issue_tmr(struct tcm_loop_tpg *tl_tpg,  	 */  	tl_nexus = tl_tpg->tl_nexus;  	if (!tl_nexus) { -		pr_err("Unable to perform device reset without" -				" active I_T Nexus\n"); +		pr_err("Unable to perform device reset without active I_T Nexus\n");  		return ret;  	}  	tl_cmd = kmem_cache_zalloc(tcm_loop_cmd_cache, GFP_KERNEL); -	if (!tl_cmd) { -		pr_err("Unable to allocate memory for tl_cmd\n"); +	if (!tl_cmd)  		return ret; -	}  	init_completion(&tl_cmd->tmr_done); @@ -298,8 +293,7 @@ static int tcm_loop_target_reset(struct scsi_cmnd *sc)  	 */  	tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host);  	if (!tl_hba) { -		pr_err("Unable to perform device reset without" -				" active I_T Nexus\n"); +		pr_err("Unable to perform device reset without active I_T Nexus\n");  		return FAILED;  	}  	/* @@ -417,8 +411,7 @@ static int tcm_loop_setup_hba_bus(struct tcm_loop_hba *tl_hba, int tcm_loop_host  	ret = device_register(&tl_hba->dev);  	if (ret) { -		pr_err("device_register() failed for" -				" tl_hba->dev: %d\n", ret); +		pr_err("device_register() failed for tl_hba->dev: %d\n", ret);  		return -ENODEV;  	} @@ -447,8 +440,7 @@ static int tcm_loop_alloc_core_bus(void)  	ret = driver_register(&tcm_loop_driverfs);  	if (ret) { -		pr_err("driver_register() failed for" -				"tcm_loop_driverfs\n"); +		pr_err("driver_register() failed for tcm_loop_driverfs\n");  		goto bus_unreg;  	} @@ -587,8 +579,8 @@ static int tcm_loop_queue_data_in(struct se_cmd *se_cmd)  				struct tcm_loop_cmd, tl_se_cmd);  	struct scsi_cmnd *sc = tl_cmd->sc; -	pr_debug("tcm_loop_queue_data_in() called for scsi_cmnd: %p" -		     " cdb: 0x%02x\n", sc, sc->cmnd[0]); +	pr_debug("%s() called for scsi_cmnd: %p cdb: 0x%02x\n", +		 __func__, sc, sc->cmnd[0]);  	sc->result = SAM_STAT_GOOD;  	set_host_byte(sc, DID_OK); @@ -605,8 +597,8 @@ static int tcm_loop_queue_status(struct se_cmd *se_cmd)  				struct tcm_loop_cmd, tl_se_cmd);  	struct scsi_cmnd *sc = tl_cmd->sc; -	pr_debug("tcm_loop_queue_status() called for scsi_cmnd: %p" -			" cdb: 0x%02x\n", sc, sc->cmnd[0]); +	pr_debug("%s() called for scsi_cmnd: %p cdb: 0x%02x\n", +		 __func__, sc, sc->cmnd[0]);  	if (se_cmd->sense_buffer &&  	   ((se_cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) || @@ -691,8 +683,8 @@ static void tcm_loop_port_unlink(  	sd = scsi_device_lookup(tl_hba->sh, 0, tl_tpg->tl_tpgt,  				se_lun->unpacked_lun);  	if (!sd) { -		pr_err("Unable to locate struct scsi_device for %d:%d:" -			"%llu\n", 0, tl_tpg->tl_tpgt, se_lun->unpacked_lun); +		pr_err("Unable to locate struct scsi_device for %d:%d:%llu\n", +		       0, tl_tpg->tl_tpgt, se_lun->unpacked_lun);  		return;  	}  	/* @@ -772,11 +764,9 @@ static int tcm_loop_make_nexus(  		return -EEXIST;  	} -	tl_nexus = kzalloc(sizeof(struct tcm_loop_nexus), GFP_KERNEL); -	if (!tl_nexus) { -		pr_err("Unable to allocate struct tcm_loop_nexus\n"); +	tl_nexus = kzalloc(sizeof(*tl_nexus), GFP_KERNEL); +	if (!tl_nexus)  		return -ENOMEM; -	}  	tl_nexus->se_sess = target_alloc_session(&tl_tpg->tl_se_tpg, 0, 0,  					TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS, @@ -787,9 +777,8 @@ static int tcm_loop_make_nexus(  		return ret;  	} -	pr_debug("TCM_Loop_ConfigFS: Established I_T Nexus to emulated" -		" %s Initiator Port: %s\n", tcm_loop_dump_proto_id(tl_hba), -		name); +	pr_debug("TCM_Loop_ConfigFS: Established I_T Nexus to emulated %s Initiator Port: %s\n", +		 tcm_loop_dump_proto_id(tl_hba), name);  	return 0;  } @@ -808,15 +797,14 @@ static int tcm_loop_drop_nexus(  		return -ENODEV;  	if (atomic_read(&tpg->tl_tpg_port_count)) { -		pr_err("Unable to remove TCM_Loop I_T Nexus with" -			" active TPG port count: %d\n", -			atomic_read(&tpg->tl_tpg_port_count)); +		pr_err("Unable to remove TCM_Loop I_T Nexus with active TPG port count: %d\n", +		       atomic_read(&tpg->tl_tpg_port_count));  		return -EPERM;  	} -	pr_debug("TCM_Loop_ConfigFS: Removing I_T Nexus to emulated" -		" %s Initiator Port: %s\n", tcm_loop_dump_proto_id(tpg->tl_hba), -		tl_nexus->se_sess->se_node_acl->initiatorname); +	pr_debug("TCM_Loop_ConfigFS: Removing I_T Nexus to emulated %s Initiator Port: %s\n", +		 tcm_loop_dump_proto_id(tpg->tl_hba), +		 tl_nexus->se_sess->se_node_acl->initiatorname);  	/*  	 * Release the SCSI I_T Nexus to the emulated Target Port  	 */ @@ -868,8 +856,8 @@ static ssize_t tcm_loop_tpg_nexus_store(struct config_item *item,  	 * tcm_loop_make_nexus()  	 */  	if (strlen(page) >= TL_WWN_ADDR_LEN) { -		pr_err("Emulated NAA Sas Address: %s, exceeds" -				" max: %d\n", page, TL_WWN_ADDR_LEN); +		pr_err("Emulated NAA Sas Address: %s, exceeds max: %d\n", +		       page, TL_WWN_ADDR_LEN);  		return -EINVAL;  	}  	snprintf(&i_port[0], TL_WWN_ADDR_LEN, "%s", page); @@ -877,9 +865,8 @@ static ssize_t tcm_loop_tpg_nexus_store(struct config_item *item,  	ptr = strstr(i_port, "naa.");  	if (ptr) {  		if (tl_hba->tl_proto_id != SCSI_PROTOCOL_SAS) { -			pr_err("Passed SAS Initiator Port %s does not" -				" match target port protoid: %s\n", i_port, -				tcm_loop_dump_proto_id(tl_hba)); +			pr_err("Passed SAS Initiator Port %s does not match target port protoid: %s\n", +			       i_port, tcm_loop_dump_proto_id(tl_hba));  			return -EINVAL;  		}  		port_ptr = &i_port[0]; @@ -888,9 +875,8 @@ static ssize_t tcm_loop_tpg_nexus_store(struct config_item *item,  	ptr = strstr(i_port, "fc.");  	if (ptr) {  		if (tl_hba->tl_proto_id != SCSI_PROTOCOL_FCP) { -			pr_err("Passed FCP Initiator Port %s does not" -				" match target port protoid: %s\n", i_port, -				tcm_loop_dump_proto_id(tl_hba)); +			pr_err("Passed FCP Initiator Port %s does not match target port protoid: %s\n", +			       i_port, tcm_loop_dump_proto_id(tl_hba));  			return -EINVAL;  		}  		port_ptr = &i_port[3]; /* Skip over "fc." */ @@ -899,16 +885,15 @@ static ssize_t tcm_loop_tpg_nexus_store(struct config_item *item,  	ptr = strstr(i_port, "iqn.");  	if (ptr) {  		if (tl_hba->tl_proto_id != SCSI_PROTOCOL_ISCSI) { -			pr_err("Passed iSCSI Initiator Port %s does not" -				" match target port protoid: %s\n", i_port, -				tcm_loop_dump_proto_id(tl_hba)); +			pr_err("Passed iSCSI Initiator Port %s does not match target port protoid: %s\n", +			       i_port, tcm_loop_dump_proto_id(tl_hba));  			return -EINVAL;  		}  		port_ptr = &i_port[0];  		goto check_newline;  	} -	pr_err("Unable to locate prefix for emulated Initiator Port:" -			" %s\n", i_port); +	pr_err("Unable to locate prefix for emulated Initiator Port: %s\n", +	       i_port);  	return -EINVAL;  	/*  	 * Clear any trailing newline for the NAA WWN @@ -1010,16 +995,15 @@ static struct se_portal_group *tcm_loop_make_naa_tpg(  	unsigned long tpgt;  	if (strstr(name, "tpgt_") != name) { -		pr_err("Unable to locate \"tpgt_#\" directory" -				" group\n"); +		pr_err("Unable to locate \"tpgt_#\" directory group\n");  		return ERR_PTR(-EINVAL);  	}  	if (kstrtoul(name+5, 10, &tpgt))  		return ERR_PTR(-EINVAL);  	if (tpgt >= TL_TPGS_PER_HBA) { -		pr_err("Passed tpgt: %lu exceeds TL_TPGS_PER_HBA:" -				" %u\n", tpgt, TL_TPGS_PER_HBA); +		pr_err("Passed tpgt: %lu exceeds TL_TPGS_PER_HBA: %u\n", +		       tpgt, TL_TPGS_PER_HBA);  		return ERR_PTR(-EINVAL);  	}  	tl_tpg = &tl_hba->tl_hba_tpgs[tpgt]; @@ -1032,10 +1016,9 @@ static struct se_portal_group *tcm_loop_make_naa_tpg(  	if (ret < 0)  		return ERR_PTR(-ENOMEM); -	pr_debug("TCM_Loop_ConfigFS: Allocated Emulated %s" -		" Target Port %s,t,0x%04lx\n", tcm_loop_dump_proto_id(tl_hba), -		config_item_name(&wwn->wwn_group.cg_item), tpgt); - +	pr_debug("TCM_Loop_ConfigFS: Allocated Emulated %s Target Port %s,t,0x%04lx\n", +		 tcm_loop_dump_proto_id(tl_hba), +		 config_item_name(&wwn->wwn_group.cg_item), tpgt);  	return &tl_tpg->tl_se_tpg;  } @@ -1062,9 +1045,9 @@ static void tcm_loop_drop_naa_tpg(  	tl_tpg->tl_hba = NULL;  	tl_tpg->tl_tpgt = 0; -	pr_debug("TCM_Loop_ConfigFS: Deallocated Emulated %s" -		" Target Port %s,t,0x%04x\n", tcm_loop_dump_proto_id(tl_hba), -		config_item_name(&wwn->wwn_group.cg_item), tpgt); +	pr_debug("TCM_Loop_ConfigFS: Deallocated Emulated %s Target Port %s,t,0x%04x\n", +		 tcm_loop_dump_proto_id(tl_hba), +		 config_item_name(&wwn->wwn_group.cg_item), tpgt);  }  /* End items for tcm_loop_naa_cit */ @@ -1081,11 +1064,10 @@ static struct se_wwn *tcm_loop_make_scsi_hba(  	char *ptr;  	int ret, off = 0; -	tl_hba = kzalloc(sizeof(struct tcm_loop_hba), GFP_KERNEL); -	if (!tl_hba) { -		pr_err("Unable to allocate struct tcm_loop_hba\n"); +	tl_hba = kzalloc(sizeof(*tl_hba), GFP_KERNEL); +	if (!tl_hba)  		return ERR_PTR(-ENOMEM); -	} +  	/*  	 * Determine the emulated Protocol Identifier and Target Port Name  	 * based on the incoming configfs directory name. @@ -1103,8 +1085,8 @@ static struct se_wwn *tcm_loop_make_scsi_hba(  	}  	ptr = strstr(name, "iqn.");  	if (!ptr) { -		pr_err("Unable to locate prefix for emulated Target " -				"Port: %s\n", name); +		pr_err("Unable to locate prefix for emulated Target Port: %s\n", +		       name);  		ret = -EINVAL;  		goto out;  	} @@ -1112,9 +1094,8 @@ static struct se_wwn *tcm_loop_make_scsi_hba(  check_len:  	if (strlen(name) >= TL_WWN_ADDR_LEN) { -		pr_err("Emulated NAA %s Address: %s, exceeds" -			" max: %d\n", name, tcm_loop_dump_proto_id(tl_hba), -			TL_WWN_ADDR_LEN); +		pr_err("Emulated NAA %s Address: %s, exceeds max: %d\n", +		       name, tcm_loop_dump_proto_id(tl_hba), TL_WWN_ADDR_LEN);  		ret = -EINVAL;  		goto out;  	} @@ -1131,10 +1112,8 @@ check_len:  	sh = tl_hba->sh;  	tcm_loop_hba_no_cnt++; -	pr_debug("TCM_Loop_ConfigFS: Allocated emulated Target" -		" %s Address: %s at Linux/SCSI Host ID: %d\n", -		tcm_loop_dump_proto_id(tl_hba), name, sh->host_no); - +	pr_debug("TCM_Loop_ConfigFS: Allocated emulated Target %s Address: %s at Linux/SCSI Host ID: %d\n", +		 tcm_loop_dump_proto_id(tl_hba), name, sh->host_no);  	return &tl_hba->tl_hba_wwn;  out:  	kfree(tl_hba); @@ -1147,10 +1126,9 @@ static void tcm_loop_drop_scsi_hba(  	struct tcm_loop_hba *tl_hba = container_of(wwn,  				struct tcm_loop_hba, tl_hba_wwn); -	pr_debug("TCM_Loop_ConfigFS: Deallocating emulated Target" -		" %s Address: %s at Linux/SCSI Host ID: %d\n", -		tcm_loop_dump_proto_id(tl_hba), tl_hba->tl_wwn_address, -		tl_hba->sh->host_no); +	pr_debug("TCM_Loop_ConfigFS: Deallocating emulated Target %s Address: %s at Linux/SCSI Host ID: %d\n", +		 tcm_loop_dump_proto_id(tl_hba), tl_hba->tl_wwn_address, +		 tl_hba->sh->host_no);  	/*  	 * Call device_unregister() on the original tl_hba->dev.  	 * tcm_loop_fabric_scsi.c:tcm_loop_release_adapter() will @@ -1223,8 +1201,7 @@ static int __init tcm_loop_fabric_init(void)  				__alignof__(struct tcm_loop_cmd),  				0, NULL);  	if (!tcm_loop_cmd_cache) { -		pr_debug("kmem_cache_create() for" -			" tcm_loop_cmd_cache failed\n"); +		pr_debug("kmem_cache_create() for tcm_loop_cmd_cache failed\n");  		goto out_destroy_workqueue;  	} diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index e5c3e5f827d0..fb1003921d85 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -201,10 +201,9 @@ static struct sbp_session *sbp_session_create(  	snprintf(guid_str, sizeof(guid_str), "%016llx", guid);  	sess = kmalloc(sizeof(*sess), GFP_KERNEL); -	if (!sess) { -		pr_err("failed to allocate session descriptor\n"); +	if (!sess)  		return ERR_PTR(-ENOMEM); -	} +  	spin_lock_init(&sess->lock);  	INIT_LIST_HEAD(&sess->login_list);  	INIT_DELAYED_WORK(&sess->maint_work, session_maintenance_work); @@ -2029,10 +2028,8 @@ static struct se_portal_group *sbp_make_tpg(  	}  	tpg = kzalloc(sizeof(*tpg), GFP_KERNEL); -	if (!tpg) { -		pr_err("Unable to allocate struct sbp_tpg\n"); +	if (!tpg)  		return ERR_PTR(-ENOMEM); -	}  	tpg->tport = tport;  	tpg->tport_tpgt = tpgt; @@ -2088,10 +2085,8 @@ static struct se_wwn *sbp_make_tport(  		return ERR_PTR(-EINVAL);  	tport = kzalloc(sizeof(*tport), GFP_KERNEL); -	if (!tport) { -		pr_err("Unable to allocate struct sbp_tport\n"); +	if (!tport)  		return ERR_PTR(-ENOMEM); -	}  	tport->guid = guid;  	sbp_format_wwn(tport->tport_name, SBP_NAMELEN, guid); diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 72b1cd1bf9d9..3f4bf126eed0 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -1197,6 +1197,7 @@ struct configfs_attribute *passthrough_attrib_attrs[] = {  EXPORT_SYMBOL(passthrough_attrib_attrs);  TB_CIT_SETUP_DRV(dev_attrib, NULL, NULL); +TB_CIT_SETUP_DRV(dev_action, NULL, NULL);  /* End functions for struct config_item_type tb_dev_attrib_cit */ @@ -2940,6 +2941,10 @@ static struct config_group *target_core_make_subdev(  	config_group_init_type_name(&dev->dev_group, name, &tb->tb_dev_cit); +	config_group_init_type_name(&dev->dev_action_group, "action", +			&tb->tb_dev_action_cit); +	configfs_add_default_group(&dev->dev_action_group, &dev->dev_group); +  	config_group_init_type_name(&dev->dev_attrib.da_group, "attrib",  			&tb->tb_dev_attrib_cit);  	configfs_add_default_group(&dev->dev_attrib.da_group, &dev->dev_group); @@ -3200,6 +3205,7 @@ static const struct config_item_type target_core_cit = {  void target_setup_backend_cits(struct target_backend *tb)  {  	target_core_setup_dev_cit(tb); +	target_core_setup_dev_action_cit(tb);  	target_core_setup_dev_attrib_cit(tb);  	target_core_setup_dev_pr_cit(tb);  	target_core_setup_dev_wwn_cit(tb); diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index e8dd6da164b2..e27db4d45a9d 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -997,7 +997,7 @@ int target_configure_device(struct se_device *dev)  	ret = core_setup_alua(dev);  	if (ret) -		goto out_free_index; +		goto out_destroy_device;  	/*  	 * Startup the struct se_device processing thread @@ -1041,6 +1041,8 @@ int target_configure_device(struct se_device *dev)  out_free_alua:  	core_alua_free_lu_gp_mem(dev); +out_destroy_device: +	dev->transport->destroy_device(dev);  out_free_index:  	mutex_lock(&device_mutex);  	idr_remove(&devices_idr, dev->dev_index); diff --git a/drivers/target/target_core_fabric_lib.c b/drivers/target/target_core_fabric_lib.c index 508da345b73f..71a80257a052 100644 --- a/drivers/target/target_core_fabric_lib.c +++ b/drivers/target/target_core_fabric_lib.c @@ -273,7 +273,7 @@ static int iscsi_get_pr_transport_id_len(  static char *iscsi_parse_pr_out_transport_id(  	struct se_portal_group *se_tpg, -	const char *buf, +	char *buf,  	u32 *out_tid_len,  	char **port_nexus_ptr)  { @@ -356,7 +356,7 @@ static char *iscsi_parse_pr_out_transport_id(  		}  	} -	return (char *)&buf[4]; +	return &buf[4];  }  int target_get_pr_transport_id_len(struct se_node_acl *nacl, @@ -405,7 +405,7 @@ int target_get_pr_transport_id(struct se_node_acl *nacl,  }  const char *target_parse_pr_out_transport_id(struct se_portal_group *tpg, -		const char *buf, u32 *out_tid_len, char **port_nexus_ptr) +		char *buf, u32 *out_tid_len, char **port_nexus_ptr)  {  	u32 offset; diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index 9384d19a7326..1d5afc3ae017 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -17,6 +17,7 @@ struct target_backend {  	struct config_item_type tb_dev_cit;  	struct config_item_type tb_dev_attrib_cit; +	struct config_item_type tb_dev_action_cit;  	struct config_item_type tb_dev_pr_cit;  	struct config_item_type tb_dev_wwn_cit;  	struct config_item_type tb_dev_alua_tg_pt_gps_cit; @@ -102,7 +103,7 @@ int	target_get_pr_transport_id(struct se_node_acl *nacl,  		struct t10_pr_registration *pr_reg, int *format_code,  		unsigned char *buf);  const char *target_parse_pr_out_transport_id(struct se_portal_group *tpg, -		const char *buf, u32 *out_tid_len, char **port_nexus_ptr); +		char *buf, u32 *out_tid_len, char **port_nexus_ptr);  /* target_core_hba.c */  struct se_hba *core_alloc_hba(const char *, u32, u32); diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index b024613f9217..01ac306131c1 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -1601,7 +1601,7 @@ core_scsi3_decode_spec_i_port(  			dest_rtpi = tmp_lun->lun_rtpi;  			i_str = target_parse_pr_out_transport_id(tmp_tpg, -					(const char *)ptr, &tid_len, &iport_ptr); +					ptr, &tid_len, &iport_ptr);  			if (!i_str)  				continue; @@ -3287,7 +3287,7 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key,  		goto out;  	}  	initiator_str = target_parse_pr_out_transport_id(dest_se_tpg, -			(const char *)&buf[24], &tmp_tid_len, &iport_ptr); +			&buf[24], &tmp_tid_len, &iport_ptr);  	if (!initiator_str) {  		pr_err("SPC-3 PR REGISTER_AND_MOVE: Unable to locate"  			" initiator_str from Transport ID\n"); diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 750a04ed0e93..b054682e974f 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -1216,9 +1216,11 @@ sbc_execute_unmap(struct se_cmd *cmd)  			goto err;  		} -		ret = ops->execute_unmap(cmd, lba, range); -		if (ret) -			goto err; +		if (range) { +			ret = ops->execute_unmap(cmd, lba, range); +			if (ret) +				goto err; +		}  		ptr += 16;  		size -= 16; diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 58caacd54a3b..4558f2e1fe1b 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1774,6 +1774,9 @@ void transport_generic_request_failure(struct se_cmd *cmd,  	case TCM_OUT_OF_RESOURCES:  		cmd->scsi_status = SAM_STAT_TASK_SET_FULL;  		goto queue_status; +	case TCM_LUN_BUSY: +		cmd->scsi_status = SAM_STAT_BUSY; +		goto queue_status;  	case TCM_RESERVATION_CONFLICT:  		/*  		 * No SENSE Data payload for this case, set SCSI Status @@ -2300,13 +2303,7 @@ queue_full:  void target_free_sgl(struct scatterlist *sgl, int nents)  { -	struct scatterlist *sg; -	int count; - -	for_each_sg(sgl, sg, nents, count) -		__free_page(sg_page(sg)); - -	kfree(sgl); +	sgl_free_n_order(sgl, nents, 0);  }  EXPORT_SYMBOL(target_free_sgl); @@ -2414,42 +2411,10 @@ int  target_alloc_sgl(struct scatterlist **sgl, unsigned int *nents, u32 length,  		 bool zero_page, bool chainable)  { -	struct scatterlist *sg; -	struct page *page; -	gfp_t zero_flag = (zero_page) ? __GFP_ZERO : 0; -	unsigned int nalloc, nent; -	int i = 0; - -	nalloc = nent = DIV_ROUND_UP(length, PAGE_SIZE); -	if (chainable) -		nalloc++; -	sg = kmalloc_array(nalloc, sizeof(struct scatterlist), GFP_KERNEL); -	if (!sg) -		return -ENOMEM; - -	sg_init_table(sg, nalloc); - -	while (length) { -		u32 page_len = min_t(u32, length, PAGE_SIZE); -		page = alloc_page(GFP_KERNEL | zero_flag); -		if (!page) -			goto out; +	gfp_t gfp = GFP_KERNEL | (zero_page ? __GFP_ZERO : 0); -		sg_set_page(&sg[i], page, page_len, 0); -		length -= page_len; -		i++; -	} -	*sgl = sg; -	*nents = nent; -	return 0; - -out: -	while (i > 0) { -		i--; -		__free_page(sg_page(&sg[i])); -	} -	kfree(sg); -	return -ENOMEM; +	*sgl = sgl_alloc_order(length, 0, chainable, gfp, nents); +	return *sgl ? 0 : -ENOMEM;  }  EXPORT_SYMBOL(target_alloc_sgl); diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index a415d87f22d2..4ad89ea71a70 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -32,7 +32,7 @@  #include <linux/highmem.h>  #include <linux/configfs.h>  #include <linux/mutex.h> -#include <linux/kthread.h> +#include <linux/workqueue.h>  #include <net/genetlink.h>  #include <scsi/scsi_common.h>  #include <scsi/scsi_proto.h> @@ -77,15 +77,21 @@   * the total size is 256K * PAGE_SIZE.   */  #define DATA_BLOCK_SIZE PAGE_SIZE -#define DATA_BLOCK_BITS (256 * 1024) +#define DATA_BLOCK_SHIFT PAGE_SHIFT +#define DATA_BLOCK_BITS_DEF (256 * 1024)  #define DATA_SIZE (DATA_BLOCK_BITS * DATA_BLOCK_SIZE) -#define DATA_BLOCK_INIT_BITS 128 + +#define TCMU_MBS_TO_BLOCKS(_mbs) (_mbs << (20 - DATA_BLOCK_SHIFT)) +#define TCMU_BLOCKS_TO_MBS(_blocks) (_blocks >> (20 - DATA_BLOCK_SHIFT))  /* The total size of the ring is 8M + 256K * PAGE_SIZE */  #define TCMU_RING_SIZE (CMDR_SIZE + DATA_SIZE) -/* Default maximum of the global data blocks(512K * PAGE_SIZE) */ -#define TCMU_GLOBAL_MAX_BLOCKS (512 * 1024) +/* + * Default number of global data blocks(512K * PAGE_SIZE) + * when the unmap thread will be started. + */ +#define TCMU_GLOBAL_MAX_BLOCKS_DEF (512 * 1024)  static u8 tcmu_kern_cmd_reply_supported; @@ -107,6 +113,7 @@ struct tcmu_nl_cmd {  struct tcmu_dev {  	struct list_head node;  	struct kref kref; +  	struct se_device se_dev;  	char *name; @@ -114,6 +121,7 @@ struct tcmu_dev {  #define TCMU_DEV_BIT_OPEN 0  #define TCMU_DEV_BIT_BROKEN 1 +#define TCMU_DEV_BIT_BLOCKED 2  	unsigned long flags;  	struct uio_info uio_info; @@ -128,22 +136,27 @@ struct tcmu_dev {  	/* Must add data_off and mb_addr to get the address */  	size_t data_off;  	size_t data_size; +	uint32_t max_blocks; +	size_t ring_size; -	wait_queue_head_t wait_cmdr;  	struct mutex cmdr_lock; +	struct list_head cmdr_queue; -	bool waiting_global;  	uint32_t dbi_max;  	uint32_t dbi_thresh; -	DECLARE_BITMAP(data_bitmap, DATA_BLOCK_BITS); +	unsigned long *data_bitmap;  	struct radix_tree_root data_blocks;  	struct idr commands; -	spinlock_t commands_lock; -	struct timer_list timeout; +	struct timer_list cmd_timer;  	unsigned int cmd_time_out; +	struct timer_list qfull_timer; +	int qfull_time_out; + +	struct list_head timedout_entry; +  	spinlock_t nl_cmd_lock;  	struct tcmu_nl_cmd curr_nl_cmd;  	/* wake up threads waiting on curr_nl_cmd */ @@ -161,6 +174,7 @@ struct tcmu_dev {  struct tcmu_cmd {  	struct se_cmd *se_cmd;  	struct tcmu_dev *tcmu_dev; +	struct list_head cmdr_queue_entry;  	uint16_t cmd_id; @@ -175,16 +189,68 @@ struct tcmu_cmd {  #define TCMU_CMD_BIT_EXPIRED 0  	unsigned long flags;  }; - -static struct task_struct *unmap_thread; -static wait_queue_head_t unmap_wait; +/* + * To avoid dead lock the mutex lock order should always be: + * + * mutex_lock(&root_udev_mutex); + * ... + * mutex_lock(&tcmu_dev->cmdr_lock); + * mutex_unlock(&tcmu_dev->cmdr_lock); + * ... + * mutex_unlock(&root_udev_mutex); + */  static DEFINE_MUTEX(root_udev_mutex);  static LIST_HEAD(root_udev); -static atomic_t global_db_count = ATOMIC_INIT(0); +static DEFINE_SPINLOCK(timed_out_udevs_lock); +static LIST_HEAD(timed_out_udevs);  static struct kmem_cache *tcmu_cmd_cache; +static atomic_t global_db_count = ATOMIC_INIT(0); +static struct delayed_work tcmu_unmap_work; +static int tcmu_global_max_blocks = TCMU_GLOBAL_MAX_BLOCKS_DEF; + +static int tcmu_set_global_max_data_area(const char *str, +					 const struct kernel_param *kp) +{ +	int ret, max_area_mb; + +	ret = kstrtoint(str, 10, &max_area_mb); +	if (ret) +		return -EINVAL; + +	if (max_area_mb <= 0) { +		pr_err("global_max_data_area must be larger than 0.\n"); +		return -EINVAL; +	} + +	tcmu_global_max_blocks = TCMU_MBS_TO_BLOCKS(max_area_mb); +	if (atomic_read(&global_db_count) > tcmu_global_max_blocks) +		schedule_delayed_work(&tcmu_unmap_work, 0); +	else +		cancel_delayed_work_sync(&tcmu_unmap_work); + +	return 0; +} + +static int tcmu_get_global_max_data_area(char *buffer, +					 const struct kernel_param *kp) +{ +	return sprintf(buffer, "%d", TCMU_BLOCKS_TO_MBS(tcmu_global_max_blocks)); +} + +static const struct kernel_param_ops tcmu_global_max_data_area_op = { +	.set = tcmu_set_global_max_data_area, +	.get = tcmu_get_global_max_data_area, +}; + +module_param_cb(global_max_data_area_mb, &tcmu_global_max_data_area_op, NULL, +		S_IWUSR | S_IRUGO); +MODULE_PARM_DESC(global_max_data_area_mb, +		 "Max MBs allowed to be allocated to all the tcmu device's " +		 "data areas."); +  /* multicast group */  enum tcmu_multicast_groups {  	TCMU_MCGRP_CONFIG, @@ -345,10 +411,8 @@ static inline bool tcmu_get_empty_block(struct tcmu_dev *udev,  	page = radix_tree_lookup(&udev->data_blocks, dbi);  	if (!page) {  		if (atomic_add_return(1, &global_db_count) > -					TCMU_GLOBAL_MAX_BLOCKS) { -			atomic_dec(&global_db_count); -			return false; -		} +				      tcmu_global_max_blocks) +			schedule_delayed_work(&tcmu_unmap_work, 0);  		/* try to get new page from the mm */  		page = alloc_page(GFP_KERNEL); @@ -379,19 +443,11 @@ static bool tcmu_get_empty_blocks(struct tcmu_dev *udev,  {  	int i; -	udev->waiting_global = false; -  	for (i = tcmu_cmd->dbi_cur; i < tcmu_cmd->dbi_cnt; i++) {  		if (!tcmu_get_empty_block(udev, tcmu_cmd)) -			goto err; +			return false;  	}  	return true; - -err: -	udev->waiting_global = true; -	/* Try to wake up the unmap thread */ -	wake_up(&unmap_wait); -	return false;  }  static inline struct page * @@ -437,6 +493,7 @@ static struct tcmu_cmd *tcmu_alloc_cmd(struct se_cmd *se_cmd)  	if (!tcmu_cmd)  		return NULL; +	INIT_LIST_HEAD(&tcmu_cmd->cmdr_queue_entry);  	tcmu_cmd->se_cmd = se_cmd;  	tcmu_cmd->tcmu_dev = udev; @@ -455,12 +512,13 @@ 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 = offset_in_page(vaddr); +	void *start = vaddr - offset;  	size = round_up(size+offset, PAGE_SIZE); -	vaddr -= offset;  	while (size) { -		flush_dcache_page(virt_to_page(vaddr)); +		flush_dcache_page(virt_to_page(start)); +		start += PAGE_SIZE;  		size -= PAGE_SIZE;  	}  } @@ -490,8 +548,7 @@ static inline size_t head_to_end(size_t head, size_t size)  	return size - head;  } -static inline void new_iov(struct iovec **iov, int *iov_cnt, -			   struct tcmu_dev *udev) +static inline void new_iov(struct iovec **iov, int *iov_cnt)  {  	struct iovec *iovec; @@ -518,7 +575,7 @@ static inline size_t iov_tail(struct iovec *iov)  	return (size_t)iov->iov_base + iov->iov_len;  } -static int scatter_data_area(struct tcmu_dev *udev, +static void scatter_data_area(struct tcmu_dev *udev,  	struct tcmu_cmd *tcmu_cmd, struct scatterlist *data_sg,  	unsigned int data_nents, struct iovec **iov,  	int *iov_cnt, bool copy_data) @@ -544,19 +601,38 @@ static int scatter_data_area(struct tcmu_dev *udev,  				to = kmap_atomic(page);  			} -			copy_bytes = min_t(size_t, sg_remaining, -					block_remaining); +			/* +			 * Covert to virtual offset of the ring data area. +			 */  			to_offset = get_block_offset_user(udev, dbi,  					block_remaining); +			/* +			 * The following code will gather and map the blocks +			 * to the same iovec when the blocks are all next to +			 * each other. +			 */ +			copy_bytes = min_t(size_t, sg_remaining, +					block_remaining);  			if (*iov_cnt != 0 &&  			    to_offset == iov_tail(*iov)) { +				/* +				 * Will append to the current iovec, because +				 * the current block page is next to the +				 * previous one. +				 */  				(*iov)->iov_len += copy_bytes;  			} else { -				new_iov(iov, iov_cnt, udev); +				/* +				 * Will allocate a new iovec because we are +				 * first time here or the current block page +				 * is not next to the previous one. +				 */ +				new_iov(iov, iov_cnt);  				(*iov)->iov_base = (void __user *)to_offset;  				(*iov)->iov_len = copy_bytes;  			} +  			if (copy_data) {  				offset = DATA_BLOCK_SIZE - block_remaining;  				memcpy(to + offset, @@ -564,15 +640,15 @@ static int scatter_data_area(struct tcmu_dev *udev,  				       copy_bytes);  				tcmu_flush_dcache_range(to, copy_bytes);  			} +  			sg_remaining -= copy_bytes;  			block_remaining -= copy_bytes;  		}  		kunmap_atomic(from - sg->offset);  	} +  	if (to)  		kunmap_atomic(to); - -	return 0;  }  static void gather_data_area(struct tcmu_dev *udev, struct tcmu_cmd *cmd, @@ -637,7 +713,7 @@ static void gather_data_area(struct tcmu_dev *udev, struct tcmu_cmd *cmd,  static inline size_t spc_bitmap_free(unsigned long *bitmap, uint32_t thresh)  { -	return DATA_BLOCK_SIZE * (thresh - bitmap_weight(bitmap, thresh)); +	return thresh - bitmap_weight(bitmap, thresh);  }  /* @@ -677,9 +753,9 @@ static bool is_ring_space_avail(struct tcmu_dev *udev, struct tcmu_cmd *cmd,  	/* try to check and get the data blocks as needed */  	space = spc_bitmap_free(udev->data_bitmap, udev->dbi_thresh); -	if (space < data_needed) { -		unsigned long blocks_left = DATA_BLOCK_BITS - udev->dbi_thresh; -		unsigned long grow; +	if ((space * DATA_BLOCK_SIZE) < data_needed) { +		unsigned long blocks_left = +				(udev->max_blocks - udev->dbi_thresh) + space;  		if (blocks_left < blocks_needed) {  			pr_debug("no data space: only %lu available, but ask for %zu\n", @@ -688,23 +764,9 @@ static bool is_ring_space_avail(struct tcmu_dev *udev, struct tcmu_cmd *cmd,  			return false;  		} -		/* Try to expand the thresh */ -		if (!udev->dbi_thresh) { -			/* From idle state */ -			uint32_t init_thresh = DATA_BLOCK_INIT_BITS; - -			udev->dbi_thresh = max(blocks_needed, init_thresh); -		} else { -			/* -			 * Grow the data area by max(blocks needed, -			 * dbi_thresh / 2), but limited to the max -			 * DATA_BLOCK_BITS size. -			 */ -			grow = max(blocks_needed, udev->dbi_thresh / 2); -			udev->dbi_thresh += grow; -			if (udev->dbi_thresh > DATA_BLOCK_BITS) -				udev->dbi_thresh = DATA_BLOCK_BITS; -		} +		udev->dbi_thresh += blocks_needed; +		if (udev->dbi_thresh > udev->max_blocks) +			udev->dbi_thresh = udev->max_blocks;  	}  	return tcmu_get_empty_blocks(udev, cmd); @@ -731,14 +793,14 @@ static inline size_t tcmu_cmd_get_cmd_size(struct tcmu_cmd *tcmu_cmd,  	return command_size;  } -static int tcmu_setup_cmd_timer(struct tcmu_cmd *tcmu_cmd) +static int tcmu_setup_cmd_timer(struct tcmu_cmd *tcmu_cmd, unsigned int tmo, +				struct timer_list *timer)  {  	struct tcmu_dev *udev = tcmu_cmd->tcmu_dev; -	unsigned long tmo = udev->cmd_time_out;  	int cmd_id;  	if (tcmu_cmd->cmd_id) -		return 0; +		goto setup_timer;  	cmd_id = idr_alloc(&udev->commands, tcmu_cmd, 1, USHRT_MAX, GFP_NOWAIT);  	if (cmd_id < 0) { @@ -747,16 +809,58 @@ static int tcmu_setup_cmd_timer(struct tcmu_cmd *tcmu_cmd)  	}  	tcmu_cmd->cmd_id = cmd_id; +	pr_debug("allocated cmd %u for dev %s tmo %lu\n", tcmu_cmd->cmd_id, +		 udev->name, tmo / MSEC_PER_SEC); + +setup_timer:  	if (!tmo)  		return 0;  	tcmu_cmd->deadline = round_jiffies_up(jiffies + msecs_to_jiffies(tmo)); -	mod_timer(&udev->timeout, tcmu_cmd->deadline); +	mod_timer(timer, tcmu_cmd->deadline);  	return 0;  } -static sense_reason_t -tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) +static int add_to_cmdr_queue(struct tcmu_cmd *tcmu_cmd) +{ +	struct tcmu_dev *udev = tcmu_cmd->tcmu_dev; +	unsigned int tmo; +	int ret; + +	/* +	 * For backwards compat if qfull_time_out is not set use +	 * cmd_time_out and if that's not set use the default time out. +	 */ +	if (!udev->qfull_time_out) +		return -ETIMEDOUT; +	else if (udev->qfull_time_out > 0) +		tmo = udev->qfull_time_out; +	else if (udev->cmd_time_out) +		tmo = udev->cmd_time_out; +	else +		tmo = TCMU_TIME_OUT; + +	ret = tcmu_setup_cmd_timer(tcmu_cmd, tmo, &udev->qfull_timer); +	if (ret) +		return ret; + +	list_add_tail(&tcmu_cmd->cmdr_queue_entry, &udev->cmdr_queue); +	pr_debug("adding cmd %u on dev %s to ring space wait queue\n", +		 tcmu_cmd->cmd_id, udev->name); +	return 0; +} + +/** + * queue_cmd_ring - queue cmd to ring or internally + * @tcmu_cmd: cmd to queue + * @scsi_err: TCM error code if failure (-1) returned. + * + * Returns: + * -1 we cannot queue internally or to the ring. + *  0 success + *  1 internally queued to wait for ring memory to free. + */ +static sense_reason_t queue_cmd_ring(struct tcmu_cmd *tcmu_cmd, int *scsi_err)  {  	struct tcmu_dev *udev = tcmu_cmd->tcmu_dev;  	struct se_cmd *se_cmd = tcmu_cmd->se_cmd; @@ -770,8 +874,17 @@ tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)  	bool copy_to_data_area;  	size_t data_length = tcmu_cmd_get_data_length(tcmu_cmd); -	if (test_bit(TCMU_DEV_BIT_BROKEN, &udev->flags)) -		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; +	*scsi_err = TCM_NO_SENSE; + +	if (test_bit(TCMU_DEV_BIT_BLOCKED, &udev->flags)) { +		*scsi_err = TCM_LUN_BUSY; +		return -1; +	} + +	if (test_bit(TCMU_DEV_BIT_BROKEN, &udev->flags)) { +		*scsi_err = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; +		return -1; +	}  	/*  	 * Must be a certain minimum size for response sense info, but @@ -788,7 +901,8 @@ tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)  	base_command_size = tcmu_cmd_get_base_cmd_size(tcmu_cmd->dbi_cnt);  	command_size = tcmu_cmd_get_cmd_size(tcmu_cmd, base_command_size); -	mutex_lock(&udev->cmdr_lock); +	if (!list_empty(&udev->cmdr_queue)) +		goto queue;  	mb = udev->mb_addr;  	cmd_head = mb->cmd_head % udev->cmdr_size; /* UAM */ @@ -797,33 +911,18 @@ tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)  		pr_warn("TCMU: Request of size %zu/%zu is too big for %u/%zu "  			"cmd ring/data area\n", command_size, data_length,  			udev->cmdr_size, udev->data_size); -		mutex_unlock(&udev->cmdr_lock); -		return TCM_INVALID_CDB_FIELD; +		*scsi_err = TCM_INVALID_CDB_FIELD; +		return -1;  	} -	while (!is_ring_space_avail(udev, tcmu_cmd, command_size, data_length)) { -		int ret; -		DEFINE_WAIT(__wait); - -		prepare_to_wait(&udev->wait_cmdr, &__wait, TASK_INTERRUPTIBLE); - -		pr_debug("sleeping for ring space\n"); -		mutex_unlock(&udev->cmdr_lock); -		if (udev->cmd_time_out) -			ret = schedule_timeout( -					msecs_to_jiffies(udev->cmd_time_out)); -		else -			ret = schedule_timeout(msecs_to_jiffies(TCMU_TIME_OUT)); -		finish_wait(&udev->wait_cmdr, &__wait); -		if (!ret) { -			pr_warn("tcmu: command timed out\n"); -			return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -		} - -		mutex_lock(&udev->cmdr_lock); - -		/* We dropped cmdr_lock, cmd_head is stale */ -		cmd_head = mb->cmd_head % udev->cmdr_size; /* UAM */ +	if (!is_ring_space_avail(udev, tcmu_cmd, command_size, data_length)) { +		/* +		 * Don't leave commands partially setup because the unmap +		 * thread might need the blocks to make forward progress. +		 */ +		tcmu_cmd_free_data(tcmu_cmd, tcmu_cmd->dbi_cur); +		tcmu_cmd_reset_dbi_cur(tcmu_cmd); +		goto queue;  	}  	/* Insert a PAD if end-of-ring space is too small */ @@ -855,41 +954,29 @@ tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)  	iov_cnt = 0;  	copy_to_data_area = (se_cmd->data_direction == DMA_TO_DEVICE  		|| se_cmd->se_cmd_flags & SCF_BIDI); -	ret = scatter_data_area(udev, tcmu_cmd, se_cmd->t_data_sg, -				se_cmd->t_data_nents, &iov, &iov_cnt, -				copy_to_data_area); -	if (ret) { -		tcmu_cmd_free_data(tcmu_cmd, tcmu_cmd->dbi_cnt); -		mutex_unlock(&udev->cmdr_lock); - -		pr_err("tcmu: alloc and scatter data failed\n"); -		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -	} +	scatter_data_area(udev, tcmu_cmd, se_cmd->t_data_sg, +			  se_cmd->t_data_nents, &iov, &iov_cnt, +			  copy_to_data_area);  	entry->req.iov_cnt = iov_cnt;  	/* Handle BIDI commands */  	iov_cnt = 0;  	if (se_cmd->se_cmd_flags & SCF_BIDI) {  		iov++; -		ret = scatter_data_area(udev, tcmu_cmd, -					se_cmd->t_bidi_data_sg, -					se_cmd->t_bidi_data_nents, -					&iov, &iov_cnt, false); -		if (ret) { -			tcmu_cmd_free_data(tcmu_cmd, tcmu_cmd->dbi_cnt); -			mutex_unlock(&udev->cmdr_lock); - -			pr_err("tcmu: alloc and scatter bidi data failed\n"); -			return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -		} +		scatter_data_area(udev, tcmu_cmd, se_cmd->t_bidi_data_sg, +				  se_cmd->t_bidi_data_nents, &iov, &iov_cnt, +				  false);  	}  	entry->req.iov_bidi_cnt = iov_cnt; -	ret = tcmu_setup_cmd_timer(tcmu_cmd); +	ret = tcmu_setup_cmd_timer(tcmu_cmd, udev->cmd_time_out, +				   &udev->cmd_timer);  	if (ret) {  		tcmu_cmd_free_data(tcmu_cmd, tcmu_cmd->dbi_cnt);  		mutex_unlock(&udev->cmdr_lock); -		return TCM_OUT_OF_RESOURCES; + +		*scsi_err = TCM_OUT_OF_RESOURCES; +		return -1;  	}  	entry->hdr.cmd_id = tcmu_cmd->cmd_id; @@ -911,36 +998,40 @@ tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)  	UPDATE_HEAD(mb->cmd_head, command_size, udev->cmdr_size);  	tcmu_flush_dcache_range(mb, sizeof(*mb)); -	mutex_unlock(&udev->cmdr_lock);  	/* TODO: only if FLUSH and FUA? */  	uio_event_notify(&udev->uio_info); -	if (udev->cmd_time_out) -		mod_timer(&udev->timeout, round_jiffies_up(jiffies + -			  msecs_to_jiffies(udev->cmd_time_out))); +	return 0; + +queue: +	if (add_to_cmdr_queue(tcmu_cmd)) { +		*scsi_err = TCM_OUT_OF_RESOURCES; +		return -1; +	} -	return TCM_NO_SENSE; +	return 1;  }  static sense_reason_t  tcmu_queue_cmd(struct se_cmd *se_cmd)  { +	struct se_device *se_dev = se_cmd->se_dev; +	struct tcmu_dev *udev = TCMU_DEV(se_dev);  	struct tcmu_cmd *tcmu_cmd; -	sense_reason_t ret; +	sense_reason_t scsi_ret; +	int ret;  	tcmu_cmd = tcmu_alloc_cmd(se_cmd);  	if (!tcmu_cmd)  		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -	ret = tcmu_queue_cmd_ring(tcmu_cmd); -	if (ret != TCM_NO_SENSE) { -		pr_err("TCMU: Could not queue command\n"); - +	mutex_lock(&udev->cmdr_lock); +	ret = queue_cmd_ring(tcmu_cmd, &scsi_ret); +	mutex_unlock(&udev->cmdr_lock); +	if (ret < 0)  		tcmu_free_cmd(tcmu_cmd); -	} - -	return ret; +	return scsi_ret;  }  static void tcmu_handle_completion(struct tcmu_cmd *cmd, struct tcmu_cmd_entry *entry) @@ -1011,12 +1102,10 @@ static unsigned int tcmu_handle_completions(struct tcmu_dev *udev)  		}  		WARN_ON(tcmu_hdr_get_op(entry->hdr.len_op) != TCMU_OP_CMD); -		spin_lock(&udev->commands_lock);  		cmd = idr_remove(&udev->commands, entry->hdr.cmd_id); -		spin_unlock(&udev->commands_lock); -  		if (!cmd) { -			pr_err("cmd_id not found, ring is broken\n"); +			pr_err("cmd_id %u not found, ring is broken\n", +			       entry->hdr.cmd_id);  			set_bit(TCMU_DEV_BIT_BROKEN, &udev->flags);  			break;  		} @@ -1030,10 +1119,20 @@ static unsigned int tcmu_handle_completions(struct tcmu_dev *udev)  		handled++;  	} -	if (mb->cmd_tail == mb->cmd_head) -		del_timer(&udev->timeout); /* no more pending cmds */ +	if (mb->cmd_tail == mb->cmd_head) { +		/* no more pending commands */ +		del_timer(&udev->cmd_timer); -	wake_up(&udev->wait_cmdr); +		if (list_empty(&udev->cmdr_queue)) { +			/* +			 * no more pending or waiting commands so try to +			 * reclaim blocks if needed. +			 */ +			if (atomic_read(&global_db_count) > +			    tcmu_global_max_blocks) +				schedule_delayed_work(&tcmu_unmap_work, 0); +		} +	}  	return handled;  } @@ -1041,6 +1140,10 @@ static unsigned int tcmu_handle_completions(struct tcmu_dev *udev)  static int tcmu_check_expired_cmd(int id, void *p, void *data)  {  	struct tcmu_cmd *cmd = p; +	struct tcmu_dev *udev = cmd->tcmu_dev; +	u8 scsi_status; +	struct se_cmd *se_cmd; +	bool is_running;  	if (test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags))  		return 0; @@ -1048,29 +1151,61 @@ static int tcmu_check_expired_cmd(int id, void *p, void *data)  	if (!time_after(jiffies, cmd->deadline))  		return 0; -	set_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags); -	target_complete_cmd(cmd->se_cmd, SAM_STAT_CHECK_CONDITION); -	cmd->se_cmd = NULL; +	is_running = list_empty(&cmd->cmdr_queue_entry); +	se_cmd = cmd->se_cmd; + +	if (is_running) { +		/* +		 * If cmd_time_out is disabled but qfull is set deadline +		 * will only reflect the qfull timeout. Ignore it. +		 */ +		if (!udev->cmd_time_out) +			return 0; + +		set_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags); +		/* +		 * target_complete_cmd will translate this to LUN COMM FAILURE +		 */ +		scsi_status = SAM_STAT_CHECK_CONDITION; +	} else { +		list_del_init(&cmd->cmdr_queue_entry); + +		idr_remove(&udev->commands, id); +		tcmu_free_cmd(cmd); +		scsi_status = SAM_STAT_TASK_SET_FULL; +	} + +	pr_debug("Timing out cmd %u on dev %s that is %s.\n", +		 id, udev->name, is_running ? "inflight" : "queued"); +	target_complete_cmd(se_cmd, scsi_status);  	return 0;  } -static void tcmu_device_timedout(struct timer_list *t) +static void tcmu_device_timedout(struct tcmu_dev *udev)  { -	struct tcmu_dev *udev = from_timer(udev, t, timeout); -	unsigned long flags; +	spin_lock(&timed_out_udevs_lock); +	if (list_empty(&udev->timedout_entry)) +		list_add_tail(&udev->timedout_entry, &timed_out_udevs); +	spin_unlock(&timed_out_udevs_lock); -	spin_lock_irqsave(&udev->commands_lock, flags); -	idr_for_each(&udev->commands, tcmu_check_expired_cmd, NULL); -	spin_unlock_irqrestore(&udev->commands_lock, flags); +	schedule_delayed_work(&tcmu_unmap_work, 0); +} -	/* Try to wake up the ummap thread */ -	wake_up(&unmap_wait); +static void tcmu_cmd_timedout(struct timer_list *t) +{ +	struct tcmu_dev *udev = from_timer(udev, t, cmd_timer); -	/* -	 * We don't need to wakeup threads on wait_cmdr since they have their -	 * own timeout. -	 */ +	pr_debug("%s cmd timeout has expired\n", udev->name); +	tcmu_device_timedout(udev); +} + +static void tcmu_qfull_timedout(struct timer_list *t) +{ +	struct tcmu_dev *udev = from_timer(udev, t, qfull_timer); + +	pr_debug("%s qfull timeout has expired\n", udev->name); +	tcmu_device_timedout(udev);  }  static int tcmu_attach_hba(struct se_hba *hba, u32 host_id) @@ -1110,14 +1245,17 @@ static struct se_device *tcmu_alloc_device(struct se_hba *hba, const char *name)  	udev->hba = hba;  	udev->cmd_time_out = TCMU_TIME_OUT; +	udev->qfull_time_out = -1; -	init_waitqueue_head(&udev->wait_cmdr); +	udev->max_blocks = DATA_BLOCK_BITS_DEF;  	mutex_init(&udev->cmdr_lock); +	INIT_LIST_HEAD(&udev->timedout_entry); +	INIT_LIST_HEAD(&udev->cmdr_queue);  	idr_init(&udev->commands); -	spin_lock_init(&udev->commands_lock); -	timer_setup(&udev->timeout, tcmu_device_timedout, 0); +	timer_setup(&udev->qfull_timer, tcmu_qfull_timedout, 0); +	timer_setup(&udev->cmd_timer, tcmu_cmd_timedout, 0);  	init_waitqueue_head(&udev->nl_cmd_wq);  	spin_lock_init(&udev->nl_cmd_lock); @@ -1127,13 +1265,79 @@ static struct se_device *tcmu_alloc_device(struct se_hba *hba, const char *name)  	return &udev->se_dev;  } +static bool run_cmdr_queue(struct tcmu_dev *udev, bool fail) +{ +	struct tcmu_cmd *tcmu_cmd, *tmp_cmd; +	LIST_HEAD(cmds); +	bool drained = true; +	sense_reason_t scsi_ret; +	int ret; + +	if (list_empty(&udev->cmdr_queue)) +		return true; + +	pr_debug("running %s's cmdr queue forcefail %d\n", udev->name, fail); + +	list_splice_init(&udev->cmdr_queue, &cmds); + +	list_for_each_entry_safe(tcmu_cmd, tmp_cmd, &cmds, cmdr_queue_entry) { +		list_del_init(&tcmu_cmd->cmdr_queue_entry); + +	        pr_debug("removing cmd %u on dev %s from queue\n", +		         tcmu_cmd->cmd_id, udev->name); + +		if (fail) { +			idr_remove(&udev->commands, tcmu_cmd->cmd_id); +			/* +			 * We were not able to even start the command, so +			 * fail with busy to allow a retry in case runner +			 * was only temporarily down. If the device is being +			 * removed then LIO core will do the right thing and +			 * fail the retry. +			 */ +			target_complete_cmd(tcmu_cmd->se_cmd, SAM_STAT_BUSY); +			tcmu_free_cmd(tcmu_cmd); +			continue; +		} + +		ret = queue_cmd_ring(tcmu_cmd, &scsi_ret); +		if (ret < 0) { +		        pr_debug("cmd %u on dev %s failed with %u\n", +			         tcmu_cmd->cmd_id, udev->name, scsi_ret); + +			idr_remove(&udev->commands, tcmu_cmd->cmd_id); +			/* +			 * Ignore scsi_ret for now. target_complete_cmd +			 * drops it. +			 */ +			target_complete_cmd(tcmu_cmd->se_cmd, +					    SAM_STAT_CHECK_CONDITION); +			tcmu_free_cmd(tcmu_cmd); +		} else if (ret > 0) { +			pr_debug("ran out of space during cmdr queue run\n"); +			/* +			 * cmd was requeued, so just put all cmds back in +			 * the queue +			 */ +			list_splice_tail(&cmds, &udev->cmdr_queue); +			drained = false; +			goto done; +		} +	} +	if (list_empty(&udev->cmdr_queue)) +		del_timer(&udev->qfull_timer); +done: +	return drained; +} +  static int tcmu_irqcontrol(struct uio_info *info, s32 irq_on)  { -	struct tcmu_dev *tcmu_dev = container_of(info, struct tcmu_dev, uio_info); +	struct tcmu_dev *udev = container_of(info, struct tcmu_dev, uio_info); -	mutex_lock(&tcmu_dev->cmdr_lock); -	tcmu_handle_completions(tcmu_dev); -	mutex_unlock(&tcmu_dev->cmdr_lock); +	mutex_lock(&udev->cmdr_lock); +	tcmu_handle_completions(udev); +	run_cmdr_queue(udev, false); +	mutex_unlock(&udev->cmdr_lock);  	return 0;  } @@ -1158,7 +1362,6 @@ static int tcmu_find_mem_index(struct vm_area_struct *vma)  static struct page *tcmu_try_get_block_page(struct tcmu_dev *udev, uint32_t dbi)  {  	struct page *page; -	int ret;  	mutex_lock(&udev->cmdr_lock);  	page = tcmu_get_block_page(udev, dbi); @@ -1168,42 +1371,12 @@ static struct page *tcmu_try_get_block_page(struct tcmu_dev *udev, uint32_t dbi)  	}  	/* -	 * Normally it shouldn't be here: -	 * Only when the userspace has touched the blocks which -	 * are out of the tcmu_cmd's data iov[], and will return -	 * one zeroed page. +	 * Userspace messed up and passed in a address not in the +	 * data iov passed to it.  	 */ -	pr_warn("Block(%u) out of cmd's iov[] has been touched!\n", dbi); -	pr_warn("Mostly it will be a bug of userspace, please have a check!\n"); - -	if (dbi >= udev->dbi_thresh) { -		/* Extern the udev->dbi_thresh to dbi + 1 */ -		udev->dbi_thresh = dbi + 1; -		udev->dbi_max = dbi; -	} - -	page = radix_tree_lookup(&udev->data_blocks, dbi); -	if (!page) { -		page = alloc_page(GFP_KERNEL | __GFP_ZERO); -		if (!page) { -			mutex_unlock(&udev->cmdr_lock); -			return NULL; -		} - -		ret = radix_tree_insert(&udev->data_blocks, dbi, page); -		if (ret) { -			mutex_unlock(&udev->cmdr_lock); -			__free_page(page); -			return NULL; -		} - -		/* -		 * Since this case is rare in page fault routine, here we -		 * will allow the global_db_count >= TCMU_GLOBAL_MAX_BLOCKS -		 * to reduce possible page fault call trace. -		 */ -		atomic_inc(&global_db_count); -	} +	pr_err("Invalid addr to data block mapping  (dbi %u) on device %s\n", +	       dbi, udev->name); +	page = NULL;  	mutex_unlock(&udev->cmdr_lock);  	return page; @@ -1238,7 +1411,7 @@ static int tcmu_vma_fault(struct vm_fault *vmf)  		dbi = (offset - udev->data_off) / DATA_BLOCK_SIZE;  		page = tcmu_try_get_block_page(udev, dbi);  		if (!page) -			return VM_FAULT_NOPAGE; +			return VM_FAULT_SIGBUS;  	}  	get_page(page); @@ -1260,7 +1433,7 @@ static int tcmu_mmap(struct uio_info *info, struct vm_area_struct *vma)  	vma->vm_private_data = udev;  	/* Ensure the mmap is exactly the right size */ -	if (vma_pages(vma) != (TCMU_RING_SIZE >> PAGE_SHIFT)) +	if (vma_pages(vma) != (udev->ring_size >> PAGE_SHIFT))  		return -EINVAL;  	return 0; @@ -1301,21 +1474,19 @@ static int tcmu_check_and_free_pending_cmd(struct tcmu_cmd *cmd)  	return -EINVAL;  } -static void tcmu_blocks_release(struct tcmu_dev *udev) +static void tcmu_blocks_release(struct radix_tree_root *blocks, +				int start, int end)  {  	int i;  	struct page *page; -	/* Try to release all block pages */ -	mutex_lock(&udev->cmdr_lock); -	for (i = 0; i <= udev->dbi_max; i++) { -		page = radix_tree_delete(&udev->data_blocks, i); +	for (i = start; i < end; i++) { +		page = radix_tree_delete(blocks, i);  		if (page) {  			__free_page(page);  			atomic_dec(&global_db_count);  		}  	} -	mutex_unlock(&udev->cmdr_lock);  }  static void tcmu_dev_kref_release(struct kref *kref) @@ -1329,17 +1500,23 @@ static void tcmu_dev_kref_release(struct kref *kref)  	vfree(udev->mb_addr);  	udev->mb_addr = NULL; +	spin_lock_bh(&timed_out_udevs_lock); +	if (!list_empty(&udev->timedout_entry)) +		list_del(&udev->timedout_entry); +	spin_unlock_bh(&timed_out_udevs_lock); +  	/* Upper layer should drain all requests before calling this */ -	spin_lock_irq(&udev->commands_lock); +	mutex_lock(&udev->cmdr_lock);  	idr_for_each_entry(&udev->commands, cmd, i) {  		if (tcmu_check_and_free_pending_cmd(cmd) != 0)  			all_expired = false;  	}  	idr_destroy(&udev->commands); -	spin_unlock_irq(&udev->commands_lock);  	WARN_ON(!all_expired); -	tcmu_blocks_release(udev); +	tcmu_blocks_release(&udev->data_blocks, 0, udev->dbi_max + 1); +	kfree(udev->data_bitmap); +	mutex_unlock(&udev->cmdr_lock);  	call_rcu(&dev->rcu_head, tcmu_dev_call_rcu);  } @@ -1406,7 +1583,7 @@ static int tcmu_wait_genl_cmd_reply(struct tcmu_dev *udev)  	wake_up_all(&udev->nl_cmd_wq); -	return ret;; +	return ret;  }  static int tcmu_netlink_event(struct tcmu_dev *udev, enum tcmu_genl_cmd cmd, @@ -1515,6 +1692,13 @@ static int tcmu_configure_device(struct se_device *dev)  	info = &udev->uio_info; +	udev->data_bitmap = kzalloc(BITS_TO_LONGS(udev->max_blocks) * +				    sizeof(unsigned long), GFP_KERNEL); +	if (!udev->data_bitmap) { +		ret = -ENOMEM; +		goto err_bitmap_alloc; +	} +  	udev->mb_addr = vzalloc(CMDR_SIZE);  	if (!udev->mb_addr) {  		ret = -ENOMEM; @@ -1524,9 +1708,8 @@ static int tcmu_configure_device(struct se_device *dev)  	/* mailbox fits in first part of CMDR space */  	udev->cmdr_size = CMDR_SIZE - CMDR_OFF;  	udev->data_off = CMDR_SIZE; -	udev->data_size = DATA_SIZE; +	udev->data_size = udev->max_blocks * DATA_BLOCK_SIZE;  	udev->dbi_thresh = 0; /* Default in Idle state */ -	udev->waiting_global = false;  	/* Initialise the mailbox of the ring buffer */  	mb = udev->mb_addr; @@ -1543,7 +1726,7 @@ static int tcmu_configure_device(struct se_device *dev)  	info->mem[0].name = "tcm-user command & data buffer";  	info->mem[0].addr = (phys_addr_t)(uintptr_t)udev->mb_addr; -	info->mem[0].size = TCMU_RING_SIZE; +	info->mem[0].size = udev->ring_size = udev->data_size + CMDR_SIZE;  	info->mem[0].memtype = UIO_MEM_NONE;  	info->irqcontrol = tcmu_irqcontrol; @@ -1596,6 +1779,9 @@ err_register:  	vfree(udev->mb_addr);  	udev->mb_addr = NULL;  err_vzalloc: +	kfree(udev->data_bitmap); +	udev->data_bitmap = NULL; +err_bitmap_alloc:  	kfree(info->name);  	info->name = NULL; @@ -1619,7 +1805,8 @@ static void tcmu_destroy_device(struct se_device *dev)  {  	struct tcmu_dev *udev = TCMU_DEV(dev); -	del_timer_sync(&udev->timeout); +	del_timer_sync(&udev->cmd_timer); +	del_timer_sync(&udev->qfull_timer);  	mutex_lock(&root_udev_mutex);  	list_del(&udev->node); @@ -1633,9 +1820,81 @@ static void tcmu_destroy_device(struct se_device *dev)  	kref_put(&udev->kref, tcmu_dev_kref_release);  } +static void tcmu_unblock_dev(struct tcmu_dev *udev) +{ +	mutex_lock(&udev->cmdr_lock); +	clear_bit(TCMU_DEV_BIT_BLOCKED, &udev->flags); +	mutex_unlock(&udev->cmdr_lock); +} + +static void tcmu_block_dev(struct tcmu_dev *udev) +{ +	mutex_lock(&udev->cmdr_lock); + +	if (test_and_set_bit(TCMU_DEV_BIT_BLOCKED, &udev->flags)) +		goto unlock; + +	/* complete IO that has executed successfully */ +	tcmu_handle_completions(udev); +	/* fail IO waiting to be queued */ +	run_cmdr_queue(udev, true); + +unlock: +	mutex_unlock(&udev->cmdr_lock); +} + +static void tcmu_reset_ring(struct tcmu_dev *udev, u8 err_level) +{ +	struct tcmu_mailbox *mb; +	struct tcmu_cmd *cmd; +	int i; + +	mutex_lock(&udev->cmdr_lock); + +	idr_for_each_entry(&udev->commands, cmd, i) { +		if (!list_empty(&cmd->cmdr_queue_entry)) +			continue; + +		pr_debug("removing cmd %u on dev %s from ring (is expired %d)\n", +			  cmd->cmd_id, udev->name, +			  test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags)); + +		idr_remove(&udev->commands, i); +		if (!test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags)) { +			if (err_level == 1) { +				/* +				 * Userspace was not able to start the +				 * command or it is retryable. +				 */ +				target_complete_cmd(cmd->se_cmd, SAM_STAT_BUSY); +			} else { +				/* hard failure */ +				target_complete_cmd(cmd->se_cmd, +						    SAM_STAT_CHECK_CONDITION); +			} +		} +		tcmu_cmd_free_data(cmd, cmd->dbi_cnt); +		tcmu_free_cmd(cmd); +	} + +	mb = udev->mb_addr; +	tcmu_flush_dcache_range(mb, sizeof(*mb)); +	pr_debug("mb last %u head %u tail %u\n", udev->cmdr_last_cleaned, +		 mb->cmd_tail, mb->cmd_head); + +	udev->cmdr_last_cleaned = 0; +	mb->cmd_tail = 0; +	mb->cmd_head = 0; +	tcmu_flush_dcache_range(mb, sizeof(*mb)); + +	del_timer(&udev->cmd_timer); + +	mutex_unlock(&udev->cmdr_lock); +} +  enum {  	Opt_dev_config, Opt_dev_size, Opt_hw_block_size, Opt_hw_max_sectors, -	Opt_nl_reply_supported, Opt_err, +	Opt_nl_reply_supported, Opt_max_data_area_mb, Opt_err,  };  static match_table_t tokens = { @@ -1644,6 +1903,7 @@ static match_table_t tokens = {  	{Opt_hw_block_size, "hw_block_size=%u"},  	{Opt_hw_max_sectors, "hw_max_sectors=%u"},  	{Opt_nl_reply_supported, "nl_reply_supported=%d"}, +	{Opt_max_data_area_mb, "max_data_area_mb=%u"},  	{Opt_err, NULL}  }; @@ -1677,7 +1937,7 @@ static ssize_t tcmu_set_configfs_dev_params(struct se_device *dev,  	struct tcmu_dev *udev = TCMU_DEV(dev);  	char *orig, *ptr, *opts, *arg_p;  	substring_t args[MAX_OPT_ARGS]; -	int ret = 0, token; +	int ret = 0, token, tmpval;  	opts = kstrdup(page, GFP_KERNEL);  	if (!opts) @@ -1729,6 +1989,39 @@ static ssize_t tcmu_set_configfs_dev_params(struct se_device *dev,  			if (ret < 0)  				pr_err("kstrtoint() failed for nl_reply_supported=\n");  			break; +		case Opt_max_data_area_mb: +			if (dev->export_count) { +				pr_err("Unable to set max_data_area_mb while exports exist\n"); +				ret = -EINVAL; +				break; +			} + +			arg_p = match_strdup(&args[0]); +			if (!arg_p) { +				ret = -ENOMEM; +				break; +			} +			ret = kstrtoint(arg_p, 0, &tmpval); +			kfree(arg_p); +			if (ret < 0) { +				pr_err("kstrtoint() failed for max_data_area_mb=\n"); +				break; +			} + +			if (tmpval <= 0) { +				pr_err("Invalid max_data_area %d\n", tmpval); +				ret = -EINVAL; +				break; +			} + +			udev->max_blocks = TCMU_MBS_TO_BLOCKS(tmpval); +			if (udev->max_blocks > tcmu_global_max_blocks) { +				pr_err("%d is too large. Adjusting max_data_area_mb to global limit of %u\n", +				       tmpval, +				       TCMU_BLOCKS_TO_MBS(tcmu_global_max_blocks)); +				udev->max_blocks = tcmu_global_max_blocks; +			} +			break;  		default:  			break;  		} @@ -1748,7 +2041,9 @@ static ssize_t tcmu_show_configfs_dev_params(struct se_device *dev, char *b)  	bl = sprintf(b + bl, "Config: %s ",  		     udev->dev_config[0] ? udev->dev_config : "NULL"); -	bl += sprintf(b + bl, "Size: %zu\n", udev->dev_size); +	bl += sprintf(b + bl, "Size: %zu ", udev->dev_size); +	bl += sprintf(b + bl, "MaxDataAreaMB: %u\n", +		      TCMU_BLOCKS_TO_MBS(udev->max_blocks));  	return bl;  } @@ -1800,6 +2095,51 @@ static ssize_t tcmu_cmd_time_out_store(struct config_item *item, const char *pag  }  CONFIGFS_ATTR(tcmu_, cmd_time_out); +static ssize_t tcmu_qfull_time_out_show(struct config_item *item, char *page) +{ +	struct se_dev_attrib *da = container_of(to_config_group(item), +						struct se_dev_attrib, da_group); +	struct tcmu_dev *udev = TCMU_DEV(da->da_dev); + +	return snprintf(page, PAGE_SIZE, "%ld\n", udev->qfull_time_out <= 0 ? +			udev->qfull_time_out : +			udev->qfull_time_out / MSEC_PER_SEC); +} + +static ssize_t tcmu_qfull_time_out_store(struct config_item *item, +					 const char *page, size_t count) +{ +	struct se_dev_attrib *da = container_of(to_config_group(item), +					struct se_dev_attrib, da_group); +	struct tcmu_dev *udev = TCMU_DEV(da->da_dev); +	s32 val; +	int ret; + +	ret = kstrtos32(page, 0, &val); +	if (ret < 0) +		return ret; + +	if (val >= 0) { +		udev->qfull_time_out = val * MSEC_PER_SEC; +	} else { +		printk(KERN_ERR "Invalid qfull timeout value %d\n", val); +		return -EINVAL; +	} +	return count; +} +CONFIGFS_ATTR(tcmu_, qfull_time_out); + +static ssize_t tcmu_max_data_area_mb_show(struct config_item *item, char *page) +{ +	struct se_dev_attrib *da = container_of(to_config_group(item), +						struct se_dev_attrib, da_group); +	struct tcmu_dev *udev = TCMU_DEV(da->da_dev); + +	return snprintf(page, PAGE_SIZE, "%u\n", +			TCMU_BLOCKS_TO_MBS(udev->max_blocks)); +} +CONFIGFS_ATTR_RO(tcmu_, max_data_area_mb); +  static ssize_t tcmu_dev_config_show(struct config_item *item, char *page)  {  	struct se_dev_attrib *da = container_of(to_config_group(item), @@ -1943,8 +2283,74 @@ static ssize_t tcmu_emulate_write_cache_store(struct config_item *item,  }  CONFIGFS_ATTR(tcmu_, emulate_write_cache); +static ssize_t tcmu_block_dev_show(struct config_item *item, char *page) +{ +	struct se_device *se_dev = container_of(to_config_group(item), +						struct se_device, +						dev_action_group); +	struct tcmu_dev *udev = TCMU_DEV(se_dev); + +	if (test_bit(TCMU_DEV_BIT_BLOCKED, &udev->flags)) +		return snprintf(page, PAGE_SIZE, "%s\n", "blocked"); +	else +		return snprintf(page, PAGE_SIZE, "%s\n", "unblocked"); +} + +static ssize_t tcmu_block_dev_store(struct config_item *item, const char *page, +				    size_t count) +{ +	struct se_device *se_dev = container_of(to_config_group(item), +						struct se_device, +						dev_action_group); +	struct tcmu_dev *udev = TCMU_DEV(se_dev); +	u8 val; +	int ret; + +	ret = kstrtou8(page, 0, &val); +	if (ret < 0) +		return ret; + +	if (val > 1) { +		pr_err("Invalid block value %d\n", val); +		return -EINVAL; +	} + +	if (!val) +		tcmu_unblock_dev(udev); +	else +		tcmu_block_dev(udev); +	return count; +} +CONFIGFS_ATTR(tcmu_, block_dev); + +static ssize_t tcmu_reset_ring_store(struct config_item *item, const char *page, +				     size_t count) +{ +	struct se_device *se_dev = container_of(to_config_group(item), +						struct se_device, +						dev_action_group); +	struct tcmu_dev *udev = TCMU_DEV(se_dev); +	u8 val; +	int ret; + +	ret = kstrtou8(page, 0, &val); +	if (ret < 0) +		return ret; + +	if (val != 1 && val != 2) { +		pr_err("Invalid reset ring value %d\n", val); +		return -EINVAL; +	} + +	tcmu_reset_ring(udev, val); +	return count; +} +CONFIGFS_ATTR_WO(tcmu_, reset_ring); +  static struct configfs_attribute *tcmu_attrib_attrs[] = {  	&tcmu_attr_cmd_time_out, +	&tcmu_attr_qfull_time_out, +	&tcmu_attr_max_data_area_mb,  	&tcmu_attr_dev_config,  	&tcmu_attr_dev_size,  	&tcmu_attr_emulate_write_cache, @@ -1954,6 +2360,12 @@ static struct configfs_attribute *tcmu_attrib_attrs[] = {  static struct configfs_attribute **tcmu_attrs; +static struct configfs_attribute *tcmu_action_attrs[] = { +	&tcmu_attr_block_dev, +	&tcmu_attr_reset_ring, +	NULL, +}; +  static struct target_backend_ops tcmu_ops = {  	.name			= "user",  	.owner			= THIS_MODULE, @@ -1969,85 +2381,93 @@ static struct target_backend_ops tcmu_ops = {  	.show_configfs_dev_params = tcmu_show_configfs_dev_params,  	.get_device_type	= sbc_get_device_type,  	.get_blocks		= tcmu_get_blocks, -	.tb_dev_attrib_attrs	= NULL, +	.tb_dev_action_attrs	= tcmu_action_attrs,  }; -static int unmap_thread_fn(void *data) +static void find_free_blocks(void)  {  	struct tcmu_dev *udev;  	loff_t off; -	uint32_t start, end, block; -	struct page *page; -	int i; +	u32 start, end, block, total_freed = 0; -	while (!kthread_should_stop()) { -		DEFINE_WAIT(__wait); +	if (atomic_read(&global_db_count) <= tcmu_global_max_blocks) +		return; -		prepare_to_wait(&unmap_wait, &__wait, TASK_INTERRUPTIBLE); -		schedule(); -		finish_wait(&unmap_wait, &__wait); +	mutex_lock(&root_udev_mutex); +	list_for_each_entry(udev, &root_udev, node) { +		mutex_lock(&udev->cmdr_lock); -		if (kthread_should_stop()) -			break; +		/* Try to complete the finished commands first */ +		tcmu_handle_completions(udev); -		mutex_lock(&root_udev_mutex); -		list_for_each_entry(udev, &root_udev, node) { -			mutex_lock(&udev->cmdr_lock); +		/* Skip the udevs in idle */ +		if (!udev->dbi_thresh) { +			mutex_unlock(&udev->cmdr_lock); +			continue; +		} -			/* Try to complete the finished commands first */ -			tcmu_handle_completions(udev); +		end = udev->dbi_max + 1; +		block = find_last_bit(udev->data_bitmap, end); +		if (block == udev->dbi_max) { +			/* +			 * The last bit is dbi_max, so it is not possible +			 * reclaim any blocks. +			 */ +			mutex_unlock(&udev->cmdr_lock); +			continue; +		} else if (block == end) { +			/* The current udev will goto idle state */ +			udev->dbi_thresh = start = 0; +			udev->dbi_max = 0; +		} else { +			udev->dbi_thresh = start = block + 1; +			udev->dbi_max = block; +		} -			/* Skip the udevs waiting the global pool or in idle */ -			if (udev->waiting_global || !udev->dbi_thresh) { -				mutex_unlock(&udev->cmdr_lock); -				continue; -			} +		/* Here will truncate the data area from off */ +		off = udev->data_off + start * DATA_BLOCK_SIZE; +		unmap_mapping_range(udev->inode->i_mapping, off, 0, 1); -			end = udev->dbi_max + 1; -			block = find_last_bit(udev->data_bitmap, end); -			if (block == udev->dbi_max) { -				/* -				 * The last bit is dbi_max, so there is -				 * no need to shrink any blocks. -				 */ -				mutex_unlock(&udev->cmdr_lock); -				continue; -			} else if (block == end) { -				/* The current udev will goto idle state */ -				udev->dbi_thresh = start = 0; -				udev->dbi_max = 0; -			} else { -				udev->dbi_thresh = start = block + 1; -				udev->dbi_max = block; -			} +		/* Release the block pages */ +		tcmu_blocks_release(&udev->data_blocks, start, end); +		mutex_unlock(&udev->cmdr_lock); -			/* Here will truncate the data area from off */ -			off = udev->data_off + start * DATA_BLOCK_SIZE; -			unmap_mapping_range(udev->inode->i_mapping, off, 0, 1); - -			/* Release the block pages */ -			for (i = start; i < end; i++) { -				page = radix_tree_delete(&udev->data_blocks, i); -				if (page) { -					__free_page(page); -					atomic_dec(&global_db_count); -				} -			} -			mutex_unlock(&udev->cmdr_lock); -		} +		total_freed += end - start; +		pr_debug("Freed %u blocks (total %u) from %s.\n", end - start, +			 total_freed, udev->name); +	} +	mutex_unlock(&root_udev_mutex); -		/* -		 * Try to wake up the udevs who are waiting -		 * for the global data pool. -		 */ -		list_for_each_entry(udev, &root_udev, node) { -			if (udev->waiting_global) -				wake_up(&udev->wait_cmdr); -		} -		mutex_unlock(&root_udev_mutex); +	if (atomic_read(&global_db_count) > tcmu_global_max_blocks) +		schedule_delayed_work(&tcmu_unmap_work, msecs_to_jiffies(5000)); +} + +static void check_timedout_devices(void) +{ +	struct tcmu_dev *udev, *tmp_dev; +	LIST_HEAD(devs); + +	spin_lock_bh(&timed_out_udevs_lock); +	list_splice_init(&timed_out_udevs, &devs); + +	list_for_each_entry_safe(udev, tmp_dev, &devs, timedout_entry) { +		list_del_init(&udev->timedout_entry); +		spin_unlock_bh(&timed_out_udevs_lock); + +		mutex_lock(&udev->cmdr_lock); +		idr_for_each(&udev->commands, tcmu_check_expired_cmd, NULL); +		mutex_unlock(&udev->cmdr_lock); + +		spin_lock_bh(&timed_out_udevs_lock);  	} -	return 0; +	spin_unlock_bh(&timed_out_udevs_lock); +} + +static void tcmu_unmap_work_fn(struct work_struct *work) +{ +	check_timedout_devices(); +	find_free_blocks();  }  static int __init tcmu_module_init(void) @@ -2056,6 +2476,8 @@ static int __init tcmu_module_init(void)  	BUILD_BUG_ON((sizeof(struct tcmu_cmd_entry) % TCMU_OP_ALIGN_SIZE) != 0); +	INIT_DELAYED_WORK(&tcmu_unmap_work, tcmu_unmap_work_fn); +  	tcmu_cmd_cache = kmem_cache_create("tcmu_cmd_cache",  				sizeof(struct tcmu_cmd),  				__alignof__(struct tcmu_cmd), @@ -2101,17 +2523,8 @@ static int __init tcmu_module_init(void)  	if (ret)  		goto out_attrs; -	init_waitqueue_head(&unmap_wait); -	unmap_thread = kthread_run(unmap_thread_fn, NULL, "tcmu_unmap"); -	if (IS_ERR(unmap_thread)) { -		ret = PTR_ERR(unmap_thread); -		goto out_unreg_transport; -	} -  	return 0; -out_unreg_transport: -	target_backend_unregister(&tcmu_ops);  out_attrs:  	kfree(tcmu_attrs);  out_unreg_genl: @@ -2126,7 +2539,7 @@ out_free_cache:  static void __exit tcmu_module_exit(void)  { -	kthread_stop(unmap_thread); +	cancel_delayed_work_sync(&tcmu_unmap_work);  	target_backend_unregister(&tcmu_ops);  	kfree(tcmu_attrs);  	genl_unregister_family(&tcmu_genl_family); |