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

tcm_fc: Convert to per-cpu command map pre-allocation of ft_cmd

This patch converts tcm_fc to use transport_init_session_tags()
pre-allocation logic for struct ft_cmd descriptors using per-cpu
session tag pooling in order to effectively avoid memory allocation
+ release for each received I/O.

It adds percpu_ida_alloc() in ft_recv_cmd() to obtain an tag and
locate ft_cmd from se_sess->sess_cmd_map[], and percpu_ida_free()
in ft_free_cmd() to release the tag based upon se_cmd->map_tag id.

It also uses a TCM_FC_DEFAULT_TAGS value of 512, that puts the
per se_sess->sess_cmd_map allocation at ~360K on 64-bit.

v2 changes:

- Handle possible tag < 0 failure with GFP_ATOMIC

Cc: Mark Rustad <mark.d.rustad@intel.com>
Cc: Robert Love <robert.w.love@intel.com>
Cc: Kent Overstreet <kmo@daterainc.com>
Signed-off-by: Nicholas Bellinger <nab@daterainc.com>

authored by

Nicholas Bellinger and committed by
Nicholas Bellinger
5f544cfa 15c03dd4

+17 -5
+1
drivers/target/tcm_fc/tcm_fc.h
··· 22 22 #define FT_NAMELEN 32 /* length of ASCII WWPNs including pad */ 23 23 #define FT_TPG_NAMELEN 32 /* max length of TPG name */ 24 24 #define FT_LUN_NAMELEN 32 /* max length of LUN name */ 25 + #define TCM_FC_DEFAULT_TAGS 512 /* tags used for per-session preallocation */ 25 26 26 27 struct ft_transport_id { 27 28 __u8 format;
+14 -4
drivers/target/tcm_fc/tfc_cmd.c
··· 28 28 #include <linux/configfs.h> 29 29 #include <linux/ctype.h> 30 30 #include <linux/hash.h> 31 + #include <linux/percpu_ida.h> 31 32 #include <asm/unaligned.h> 32 33 #include <scsi/scsi.h> 33 34 #include <scsi/scsi_host.h> ··· 90 89 { 91 90 struct fc_frame *fp; 92 91 struct fc_lport *lport; 92 + struct se_session *se_sess; 93 93 94 94 if (!cmd) 95 95 return; 96 + se_sess = cmd->sess->se_sess; 96 97 fp = cmd->req_frame; 97 98 lport = fr_dev(fp); 98 99 if (fr_seq(fp)) 99 100 lport->tt.seq_release(fr_seq(fp)); 100 101 fc_frame_free(fp); 102 + percpu_ida_free(&se_sess->sess_tag_pool, cmd->se_cmd.map_tag); 101 103 ft_sess_put(cmd->sess); /* undo get from lookup at recv */ 102 - kfree(cmd); 103 104 } 104 105 105 106 void ft_release_cmd(struct se_cmd *se_cmd) ··· 435 432 { 436 433 struct ft_cmd *cmd; 437 434 struct fc_lport *lport = sess->tport->lport; 435 + struct se_session *se_sess = sess->se_sess; 436 + int tag; 438 437 439 - cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC); 440 - if (!cmd) 438 + tag = percpu_ida_alloc(&se_sess->sess_tag_pool, GFP_ATOMIC); 439 + if (tag < 0) 441 440 goto busy; 441 + 442 + cmd = &((struct ft_cmd *)se_sess->sess_cmd_map)[tag]; 443 + memset(cmd, 0, sizeof(struct ft_cmd)); 444 + 445 + cmd->se_cmd.map_tag = tag; 442 446 cmd->sess = sess; 443 447 cmd->seq = lport->tt.seq_assign(lport, fp); 444 448 if (!cmd->seq) { 445 - kfree(cmd); 449 + percpu_ida_free(&se_sess->sess_tag_pool, tag); 446 450 goto busy; 447 451 } 448 452 cmd->req_frame = fp; /* hold frame during cmd */
+2 -1
drivers/target/tcm_fc/tfc_sess.c
··· 210 210 if (!sess) 211 211 return NULL; 212 212 213 - sess->se_sess = transport_init_session(); 213 + sess->se_sess = transport_init_session_tags(TCM_FC_DEFAULT_TAGS, 214 + sizeof(struct ft_cmd)); 214 215 if (IS_ERR(sess->se_sess)) { 215 216 kfree(sess); 216 217 return NULL;