Commit 10e9cbb6 authored by Matthew Wilcox's avatar Matthew Wilcox Committed by Martin K. Petersen

scsi: target: Convert target drivers to use sbitmap

The sbitmap and the percpu_ida perform essentially the same task,
allocating tags for commands.  The sbitmap outperforms the percpu_ida as
documented here: https://lkml.org/lkml/2014/4/22/553

The sbitmap interface is a little harder to use, but being able to remove
the percpu_ida code and getting better performance justifies the additional
complexity.
Signed-off-by: default avatarMatthew Wilcox <willy@infradead.org>
Acked-by: Felipe Balbi <felipe.balbi@linux.intel.com>	# f_tcm
Reviewed-by: default avatarJens Axboe <axboe@kernel.dk>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 83c2b54b
...@@ -4277,9 +4277,9 @@ static struct qla_tgt_cmd *qlt_get_tag(scsi_qla_host_t *vha, ...@@ -4277,9 +4277,9 @@ static struct qla_tgt_cmd *qlt_get_tag(scsi_qla_host_t *vha,
{ {
struct se_session *se_sess = sess->se_sess; struct se_session *se_sess = sess->se_sess;
struct qla_tgt_cmd *cmd; struct qla_tgt_cmd *cmd;
int tag; int tag, cpu;
tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING); tag = sbitmap_queue_get(&se_sess->sess_tag_pool, &cpu);
if (tag < 0) if (tag < 0)
return NULL; return NULL;
...@@ -4292,6 +4292,7 @@ static struct qla_tgt_cmd *qlt_get_tag(scsi_qla_host_t *vha, ...@@ -4292,6 +4292,7 @@ static struct qla_tgt_cmd *qlt_get_tag(scsi_qla_host_t *vha,
qlt_incr_num_pend_cmds(vha); qlt_incr_num_pend_cmds(vha);
cmd->vha = vha; cmd->vha = vha;
cmd->se_cmd.map_tag = tag; cmd->se_cmd.map_tag = tag;
cmd->se_cmd.map_cpu = cpu;
cmd->sess = sess; cmd->sess = sess;
cmd->loop_id = sess->loop_id; cmd->loop_id = sess->loop_id;
cmd->conf_compl_supported = sess->conf_compl_supported; cmd->conf_compl_supported = sess->conf_compl_supported;
...@@ -5294,7 +5295,7 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha, ...@@ -5294,7 +5295,7 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha,
struct fc_port *sess; struct fc_port *sess;
struct se_session *se_sess; struct se_session *se_sess;
struct qla_tgt_cmd *cmd; struct qla_tgt_cmd *cmd;
int tag; int tag, cpu;
unsigned long flags; unsigned long flags;
if (unlikely(tgt->tgt_stop)) { if (unlikely(tgt->tgt_stop)) {
...@@ -5326,7 +5327,7 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha, ...@@ -5326,7 +5327,7 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha,
se_sess = sess->se_sess; se_sess = sess->se_sess;
tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING); tag = sbitmap_queue_get(&se_sess->sess_tag_pool, &cpu);
if (tag < 0) if (tag < 0)
return; return;
...@@ -5357,6 +5358,7 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha, ...@@ -5357,6 +5358,7 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha,
cmd->reset_count = ha->base_qpair->chip_reset; cmd->reset_count = ha->base_qpair->chip_reset;
cmd->q_full = 1; cmd->q_full = 1;
cmd->qpair = ha->base_qpair; cmd->qpair = ha->base_qpair;
cmd->se_cmd.map_cpu = cpu;
if (qfull) { if (qfull) {
cmd->q_full = 1; cmd->q_full = 1;
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
******************************************************************************/ ******************************************************************************/
#include <linux/list.h> #include <linux/list.h>
#include <linux/percpu_ida.h> #include <linux/sched/signal.h>
#include <net/ipv6.h> /* ipv6_addr_equal() */ #include <net/ipv6.h> /* ipv6_addr_equal() */
#include <scsi/scsi_tcq.h> #include <scsi/scsi_tcq.h>
#include <scsi/iscsi_proto.h> #include <scsi/iscsi_proto.h>
...@@ -147,6 +147,30 @@ void iscsit_free_r2ts_from_list(struct iscsi_cmd *cmd) ...@@ -147,6 +147,30 @@ void iscsit_free_r2ts_from_list(struct iscsi_cmd *cmd)
spin_unlock_bh(&cmd->r2t_lock); spin_unlock_bh(&cmd->r2t_lock);
} }
static int iscsit_wait_for_tag(struct se_session *se_sess, int state, int *cpup)
{
int tag = -1;
DEFINE_WAIT(wait);
struct sbq_wait_state *ws;
if (state == TASK_RUNNING)
return tag;
ws = &se_sess->sess_tag_pool.ws[0];
for (;;) {
prepare_to_wait_exclusive(&ws->wait, &wait, state);
if (signal_pending_state(state, current))
break;
tag = sbitmap_queue_get(&se_sess->sess_tag_pool, cpup);
if (tag >= 0)
break;
schedule();
}
finish_wait(&ws->wait, &wait);
return tag;
}
/* /*
* May be called from software interrupt (timer) context for allocating * May be called from software interrupt (timer) context for allocating
* iSCSI NopINs. * iSCSI NopINs.
...@@ -155,9 +179,11 @@ struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, int state) ...@@ -155,9 +179,11 @@ struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, int state)
{ {
struct iscsi_cmd *cmd; struct iscsi_cmd *cmd;
struct se_session *se_sess = conn->sess->se_sess; struct se_session *se_sess = conn->sess->se_sess;
int size, tag; int size, tag, cpu;
tag = percpu_ida_alloc(&se_sess->sess_tag_pool, state); tag = sbitmap_queue_get(&se_sess->sess_tag_pool, &cpu);
if (tag < 0)
tag = iscsit_wait_for_tag(se_sess, state, &cpu);
if (tag < 0) if (tag < 0)
return NULL; return NULL;
...@@ -166,6 +192,7 @@ struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, int state) ...@@ -166,6 +192,7 @@ struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, int state)
memset(cmd, 0, size); memset(cmd, 0, size);
cmd->se_cmd.map_tag = tag; cmd->se_cmd.map_tag = tag;
cmd->se_cmd.map_cpu = cpu;
cmd->conn = conn; cmd->conn = conn;
cmd->data_direction = DMA_NONE; cmd->data_direction = DMA_NONE;
INIT_LIST_HEAD(&cmd->i_conn_node); INIT_LIST_HEAD(&cmd->i_conn_node);
......
...@@ -926,15 +926,16 @@ static struct sbp_target_request *sbp_mgt_get_req(struct sbp_session *sess, ...@@ -926,15 +926,16 @@ static struct sbp_target_request *sbp_mgt_get_req(struct sbp_session *sess,
{ {
struct se_session *se_sess = sess->se_sess; struct se_session *se_sess = sess->se_sess;
struct sbp_target_request *req; struct sbp_target_request *req;
int tag; int tag, cpu;
tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING); tag = sbitmap_queue_get(&se_sess->sess_tag_pool, &cpu);
if (tag < 0) if (tag < 0)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
req = &((struct sbp_target_request *)se_sess->sess_cmd_map)[tag]; req = &((struct sbp_target_request *)se_sess->sess_cmd_map)[tag];
memset(req, 0, sizeof(*req)); memset(req, 0, sizeof(*req));
req->se_cmd.map_tag = tag; req->se_cmd.map_tag = tag;
req->se_cmd.map_cpu = cpu;
req->se_cmd.tag = next_orb; req->se_cmd.tag = next_orb;
return req; return req;
......
...@@ -260,7 +260,8 @@ int transport_alloc_session_tags(struct se_session *se_sess, ...@@ -260,7 +260,8 @@ int transport_alloc_session_tags(struct se_session *se_sess,
} }
} }
rc = percpu_ida_init(&se_sess->sess_tag_pool, tag_num); rc = sbitmap_queue_init_node(&se_sess->sess_tag_pool, tag_num, -1,
false, GFP_KERNEL, NUMA_NO_NODE);
if (rc < 0) { if (rc < 0) {
pr_err("Unable to init se_sess->sess_tag_pool," pr_err("Unable to init se_sess->sess_tag_pool,"
" tag_num: %u\n", tag_num); " tag_num: %u\n", tag_num);
...@@ -547,7 +548,7 @@ void transport_free_session(struct se_session *se_sess) ...@@ -547,7 +548,7 @@ void transport_free_session(struct se_session *se_sess)
target_put_nacl(se_nacl); target_put_nacl(se_nacl);
} }
if (se_sess->sess_cmd_map) { if (se_sess->sess_cmd_map) {
percpu_ida_destroy(&se_sess->sess_tag_pool); sbitmap_queue_free(&se_sess->sess_tag_pool);
kvfree(se_sess->sess_cmd_map); kvfree(se_sess->sess_cmd_map);
} }
kmem_cache_free(se_sess_cache, se_sess); kmem_cache_free(se_sess_cache, se_sess);
......
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
#include <linux/configfs.h> #include <linux/configfs.h>
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/hash.h> #include <linux/hash.h>
#include <linux/percpu_ida.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
#include <scsi/scsi_tcq.h> #include <scsi/scsi_tcq.h>
#include <scsi/libfc.h> #include <scsi/libfc.h>
...@@ -448,9 +447,9 @@ static void ft_recv_cmd(struct ft_sess *sess, struct fc_frame *fp) ...@@ -448,9 +447,9 @@ static void ft_recv_cmd(struct ft_sess *sess, struct fc_frame *fp)
struct ft_cmd *cmd; struct ft_cmd *cmd;
struct fc_lport *lport = sess->tport->lport; struct fc_lport *lport = sess->tport->lport;
struct se_session *se_sess = sess->se_sess; struct se_session *se_sess = sess->se_sess;
int tag; int tag, cpu;
tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING); tag = sbitmap_queue_get(&se_sess->sess_tag_pool, &cpu);
if (tag < 0) if (tag < 0)
goto busy; goto busy;
...@@ -458,6 +457,7 @@ static void ft_recv_cmd(struct ft_sess *sess, struct fc_frame *fp) ...@@ -458,6 +457,7 @@ static void ft_recv_cmd(struct ft_sess *sess, struct fc_frame *fp)
memset(cmd, 0, sizeof(struct ft_cmd)); memset(cmd, 0, sizeof(struct ft_cmd));
cmd->se_cmd.map_tag = tag; cmd->se_cmd.map_tag = tag;
cmd->se_cmd.map_cpu = cpu;
cmd->sess = sess; cmd->sess = sess;
cmd->seq = fc_seq_assign(lport, fp); cmd->seq = fc_seq_assign(lport, fp);
if (!cmd->seq) { if (!cmd->seq) {
......
...@@ -1071,15 +1071,16 @@ static struct usbg_cmd *usbg_get_cmd(struct f_uas *fu, ...@@ -1071,15 +1071,16 @@ static struct usbg_cmd *usbg_get_cmd(struct f_uas *fu,
{ {
struct se_session *se_sess = tv_nexus->tvn_se_sess; struct se_session *se_sess = tv_nexus->tvn_se_sess;
struct usbg_cmd *cmd; struct usbg_cmd *cmd;
int tag; int tag, cpu;
tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING); tag = sbitmap_queue_get(&se_sess->sess_tag_pool, &cpu);
if (tag < 0) if (tag < 0)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
cmd = &((struct usbg_cmd *)se_sess->sess_cmd_map)[tag]; cmd = &((struct usbg_cmd *)se_sess->sess_cmd_map)[tag];
memset(cmd, 0, sizeof(*cmd)); memset(cmd, 0, sizeof(*cmd));
cmd->se_cmd.map_tag = tag; cmd->se_cmd.map_tag = tag;
cmd->se_cmd.map_cpu = cpu;
cmd->se_cmd.tag = cmd->tag = scsi_tag; cmd->se_cmd.tag = cmd->tag = scsi_tag;
cmd->fu = fu; cmd->fu = fu;
......
...@@ -46,7 +46,6 @@ ...@@ -46,7 +46,6 @@
#include <linux/virtio_scsi.h> #include <linux/virtio_scsi.h>
#include <linux/llist.h> #include <linux/llist.h>
#include <linux/bitmap.h> #include <linux/bitmap.h>
#include <linux/percpu_ida.h>
#include "vhost.h" #include "vhost.h"
...@@ -567,7 +566,7 @@ vhost_scsi_get_tag(struct vhost_virtqueue *vq, struct vhost_scsi_tpg *tpg, ...@@ -567,7 +566,7 @@ vhost_scsi_get_tag(struct vhost_virtqueue *vq, struct vhost_scsi_tpg *tpg,
struct se_session *se_sess; struct se_session *se_sess;
struct scatterlist *sg, *prot_sg; struct scatterlist *sg, *prot_sg;
struct page **pages; struct page **pages;
int tag; int tag, cpu;
tv_nexus = tpg->tpg_nexus; tv_nexus = tpg->tpg_nexus;
if (!tv_nexus) { if (!tv_nexus) {
...@@ -576,7 +575,7 @@ vhost_scsi_get_tag(struct vhost_virtqueue *vq, struct vhost_scsi_tpg *tpg, ...@@ -576,7 +575,7 @@ vhost_scsi_get_tag(struct vhost_virtqueue *vq, struct vhost_scsi_tpg *tpg,
} }
se_sess = tv_nexus->tvn_se_sess; se_sess = tv_nexus->tvn_se_sess;
tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING); tag = sbitmap_queue_get(&se_sess->sess_tag_pool, &cpu);
if (tag < 0) { if (tag < 0) {
pr_err("Unable to obtain tag for vhost_scsi_cmd\n"); pr_err("Unable to obtain tag for vhost_scsi_cmd\n");
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -591,6 +590,7 @@ vhost_scsi_get_tag(struct vhost_virtqueue *vq, struct vhost_scsi_tpg *tpg, ...@@ -591,6 +590,7 @@ vhost_scsi_get_tag(struct vhost_virtqueue *vq, struct vhost_scsi_tpg *tpg,
cmd->tvc_prot_sgl = prot_sg; cmd->tvc_prot_sgl = prot_sg;
cmd->tvc_upages = pages; cmd->tvc_upages = pages;
cmd->tvc_se_cmd.map_tag = tag; cmd->tvc_se_cmd.map_tag = tag;
cmd->tvc_se_cmd.map_cpu = cpu;
cmd->tvc_tag = scsi_tag; cmd->tvc_tag = scsi_tag;
cmd->tvc_lun = lun; cmd->tvc_lun = lun;
cmd->tvc_task_attr = task_attr; cmd->tvc_task_attr = task_attr;
......
...@@ -654,9 +654,9 @@ static struct vscsibk_pend *scsiback_get_pend_req(struct vscsiif_back_ring *ring ...@@ -654,9 +654,9 @@ static struct vscsibk_pend *scsiback_get_pend_req(struct vscsiif_back_ring *ring
struct scsiback_nexus *nexus = tpg->tpg_nexus; struct scsiback_nexus *nexus = tpg->tpg_nexus;
struct se_session *se_sess = nexus->tvn_se_sess; struct se_session *se_sess = nexus->tvn_se_sess;
struct vscsibk_pend *req; struct vscsibk_pend *req;
int tag, i; int tag, cpu, i;
tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING); tag = sbitmap_queue_get(&se_sess->sess_tag_pool, &cpu);
if (tag < 0) { if (tag < 0) {
pr_err("Unable to obtain tag for vscsiif_request\n"); pr_err("Unable to obtain tag for vscsiif_request\n");
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -665,6 +665,7 @@ static struct vscsibk_pend *scsiback_get_pend_req(struct vscsiif_back_ring *ring ...@@ -665,6 +665,7 @@ static struct vscsibk_pend *scsiback_get_pend_req(struct vscsiif_back_ring *ring
req = &((struct vscsibk_pend *)se_sess->sess_cmd_map)[tag]; req = &((struct vscsibk_pend *)se_sess->sess_cmd_map)[tag];
memset(req, 0, sizeof(*req)); memset(req, 0, sizeof(*req));
req->se_cmd.map_tag = tag; req->se_cmd.map_tag = tag;
req->se_cmd.map_cpu = cpu;
for (i = 0; i < VSCSI_MAX_GRANTS; i++) for (i = 0; i < VSCSI_MAX_GRANTS; i++)
req->grant_handles[i] = SCSIBACK_INVALID_HANDLE; req->grant_handles[i] = SCSIBACK_INVALID_HANDLE;
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include <linux/dma-direction.h> /* enum dma_data_direction */ #include <linux/dma-direction.h> /* enum dma_data_direction */
#include <linux/list.h> /* struct list_head */ #include <linux/list.h> /* struct list_head */
#include <linux/sched.h>
#include <linux/socket.h> /* struct sockaddr_storage */ #include <linux/socket.h> /* struct sockaddr_storage */
#include <linux/types.h> /* u8 */ #include <linux/types.h> /* u8 */
#include <scsi/iscsi_proto.h> /* itt_t */ #include <scsi/iscsi_proto.h> /* itt_t */
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
#include <linux/configfs.h> /* struct config_group */ #include <linux/configfs.h> /* struct config_group */
#include <linux/dma-direction.h> /* enum dma_data_direction */ #include <linux/dma-direction.h> /* enum dma_data_direction */
#include <linux/percpu_ida.h> /* struct percpu_ida */ #include <linux/sbitmap.h>
#include <linux/percpu-refcount.h> #include <linux/percpu-refcount.h>
#include <linux/semaphore.h> /* struct semaphore */ #include <linux/semaphore.h> /* struct semaphore */
#include <linux/completion.h> #include <linux/completion.h>
...@@ -455,6 +455,7 @@ struct se_cmd { ...@@ -455,6 +455,7 @@ struct se_cmd {
int sam_task_attr; int sam_task_attr;
/* Used for se_sess->sess_tag_pool */ /* Used for se_sess->sess_tag_pool */
unsigned int map_tag; unsigned int map_tag;
int map_cpu;
/* Transport protocol dependent state, see transport_state_table */ /* Transport protocol dependent state, see transport_state_table */
enum transport_state_table t_state; enum transport_state_table t_state;
/* See se_cmd_flags_table */ /* See se_cmd_flags_table */
...@@ -608,7 +609,7 @@ struct se_session { ...@@ -608,7 +609,7 @@ struct se_session {
struct list_head sess_wait_list; struct list_head sess_wait_list;
spinlock_t sess_cmd_lock; spinlock_t sess_cmd_lock;
void *sess_cmd_map; void *sess_cmd_map;
struct percpu_ida sess_tag_pool; struct sbitmap_queue sess_tag_pool;
}; };
struct se_device; struct se_device;
...@@ -936,7 +937,7 @@ static inline void atomic_dec_mb(atomic_t *v) ...@@ -936,7 +937,7 @@ static inline void atomic_dec_mb(atomic_t *v)
static inline void target_free_tag(struct se_session *sess, struct se_cmd *cmd) static inline void target_free_tag(struct se_session *sess, struct se_cmd *cmd)
{ {
percpu_ida_free(&sess->sess_tag_pool, cmd->map_tag); sbitmap_queue_clear(&sess->sess_tag_pool, cmd->map_tag, cmd->map_cpu);
} }
#endif /* TARGET_CORE_BASE_H */ #endif /* TARGET_CORE_BASE_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment