Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Revert "ib_srpt: Convert to percpu_ida tag allocation"

This reverts commit 0fd10721fe3664f7549e74af9d28a509c9a68719.

That patch causes the ib_srpt driver to crash as soon as the first SCSI
command is received:

kernel BUG at drivers/infiniband/ulp/srpt/ib_srpt.c:1439!
invalid opcode: 0000 [#1] SMP
Workqueue: target_completion target_complete_ok_work [target_core_mod]
RIP: srpt_queue_response+0x437/0x4a0 [ib_srpt]
Call Trace:
srpt_queue_data_in+0x9/0x10 [ib_srpt]
target_complete_ok_work+0x152/0x2b0 [target_core_mod]
process_one_work+0x197/0x480
worker_thread+0x49/0x490
kthread+0xea/0x100
ret_from_fork+0x22/0x40

Aside from the crash, the shortcomings of that patch are as follows:

- It makes the ib_srpt driver use I/O contexts allocated by
transport_alloc_session_tags() but it does not initialize these I/O
contexts properly. All the initializations performed by
srpt_alloc_ioctx() are skipped.

- It swaps the order of the send ioctx allocation and the transition to
RTR mode which is wrong.

- The amount of memory that is needed for I/O contexts is doubled.

- srpt_rdma_ch.free_list is no longer used but is not removed.

Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com>
Cc: Nicholas Bellinger <nab@linux-iscsi.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Bart Van Assche and committed by
Linus Torvalds
3c968887 93061f39

+40 -17
+38 -17
drivers/infiniband/ulp/srpt/ib_srpt.c
··· 1264 1264 */ 1265 1265 static struct srpt_send_ioctx *srpt_get_send_ioctx(struct srpt_rdma_ch *ch) 1266 1266 { 1267 - struct se_session *se_sess; 1268 1267 struct srpt_send_ioctx *ioctx; 1269 - int tag; 1268 + unsigned long flags; 1270 1269 1271 1270 BUG_ON(!ch); 1272 - se_sess = ch->sess; 1273 1271 1274 - tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING); 1275 - if (tag < 0) { 1276 - pr_err("Unable to obtain tag for srpt_send_ioctx\n"); 1277 - return NULL; 1272 + ioctx = NULL; 1273 + spin_lock_irqsave(&ch->spinlock, flags); 1274 + if (!list_empty(&ch->free_list)) { 1275 + ioctx = list_first_entry(&ch->free_list, 1276 + struct srpt_send_ioctx, free_list); 1277 + list_del(&ioctx->free_list); 1278 1278 } 1279 - ioctx = &((struct srpt_send_ioctx *)se_sess->sess_cmd_map)[tag]; 1280 - memset(ioctx, 0, sizeof(struct srpt_send_ioctx)); 1281 - ioctx->ch = ch; 1279 + spin_unlock_irqrestore(&ch->spinlock, flags); 1280 + 1281 + if (!ioctx) 1282 + return ioctx; 1283 + 1284 + BUG_ON(ioctx->ch != ch); 1282 1285 spin_lock_init(&ioctx->spinlock); 1283 1286 ioctx->state = SRPT_STATE_NEW; 1287 + ioctx->n_rbuf = 0; 1288 + ioctx->rbufs = NULL; 1289 + ioctx->n_rdma = 0; 1290 + ioctx->n_rdma_wrs = 0; 1291 + ioctx->rdma_wrs = NULL; 1292 + ioctx->mapped_sg_count = 0; 1284 1293 init_completion(&ioctx->tx_done); 1285 - 1286 - ioctx->cmd.map_tag = tag; 1294 + ioctx->queue_status_only = false; 1295 + /* 1296 + * transport_init_se_cmd() does not initialize all fields, so do it 1297 + * here. 1298 + */ 1299 + memset(&ioctx->cmd, 0, sizeof(ioctx->cmd)); 1300 + memset(&ioctx->sense_data, 0, sizeof(ioctx->sense_data)); 1287 1301 1288 1302 return ioctx; 1289 1303 } ··· 2035 2021 struct ib_cm_rep_param *rep_param; 2036 2022 struct srpt_rdma_ch *ch, *tmp_ch; 2037 2023 u32 it_iu_len; 2038 - int ret = 0; 2024 + int i, ret = 0; 2039 2025 unsigned char *p; 2040 2026 2041 2027 WARN_ON_ONCE(irqs_disabled()); ··· 2157 2143 if (!ch->ioctx_ring) 2158 2144 goto free_ch; 2159 2145 2146 + INIT_LIST_HEAD(&ch->free_list); 2147 + for (i = 0; i < ch->rq_size; i++) { 2148 + ch->ioctx_ring[i]->ch = ch; 2149 + list_add_tail(&ch->ioctx_ring[i]->free_list, &ch->free_list); 2150 + } 2151 + 2160 2152 ret = srpt_create_ch_ib(ch); 2161 2153 if (ret) { 2162 2154 rej->reason = cpu_to_be32( ··· 2193 2173 p = &ch->sess_name[0]; 2194 2174 2195 2175 try_again: 2196 - ch->sess = target_alloc_session(&sport->port_tpg_1, ch->rq_size, 2197 - sizeof(struct srpt_send_ioctx), 2176 + ch->sess = target_alloc_session(&sport->port_tpg_1, 0, 0, 2198 2177 TARGET_PROT_NORMAL, p, ch, NULL); 2199 2178 if (IS_ERR(ch->sess)) { 2200 2179 pr_info("Rejected login because no ACL has been" ··· 2900 2881 struct srpt_send_ioctx *ioctx = container_of(se_cmd, 2901 2882 struct srpt_send_ioctx, cmd); 2902 2883 struct srpt_rdma_ch *ch = ioctx->ch; 2903 - struct se_session *se_sess = ch->sess; 2884 + unsigned long flags; 2904 2885 2905 2886 WARN_ON(ioctx->state != SRPT_STATE_DONE); 2906 2887 WARN_ON(ioctx->mapped_sg_count != 0); ··· 2911 2892 ioctx->n_rbuf = 0; 2912 2893 } 2913 2894 2914 - percpu_ida_free(&se_sess->sess_tag_pool, se_cmd->map_tag); 2895 + spin_lock_irqsave(&ch->spinlock, flags); 2896 + list_add(&ioctx->free_list, &ch->free_list); 2897 + spin_unlock_irqrestore(&ch->spinlock, flags); 2915 2898 } 2916 2899 2917 2900 /**
+2
drivers/infiniband/ulp/srpt/ib_srpt.h
··· 179 179 * struct srpt_send_ioctx - SRPT send I/O context. 180 180 * @ioctx: See above. 181 181 * @ch: Channel pointer. 182 + * @free_list: Node in srpt_rdma_ch.free_list. 182 183 * @n_rbuf: Number of data buffers in the received SRP command. 183 184 * @rbufs: Pointer to SRP data buffer array. 184 185 * @single_rbuf: SRP data buffer if the command has only a single buffer. ··· 202 201 struct srp_direct_buf *rbufs; 203 202 struct srp_direct_buf single_rbuf; 204 203 struct scatterlist *sg; 204 + struct list_head free_list; 205 205 spinlock_t spinlock; 206 206 enum srpt_command_state state; 207 207 struct se_cmd cmd;