Skip to content

Commit 4635873

Browse files
Ming Leimartinkpetersen
authored andcommitted
scsi: lib/sg_pool.c: improve APIs for allocating sg pool
sg_alloc_table_chained() currently allows the caller to provide one preallocated SGL and returns if the requested number isn't bigger than size of that SGL. This is used to inline an SGL for an IO request. However, scattergather code only allows that size of the 1st preallocated SGL to be SG_CHUNK_SIZE(128). This means a substantial amount of memory (4KB) is claimed for the SGL for each IO request. If the I/O is small, it would be prudent to allocate a smaller SGL. Introduce an extra parameter to sg_alloc_table_chained() and sg_free_table_chained() for specifying size of the preallocated SGL. Both __sg_free_table() and __sg_alloc_table() assume that each SGL has the same size except for the last one. Change the code to allow both functions to accept a variable size for the 1st preallocated SGL. [mkp: attempted to clarify commit desc] Cc: Christoph Hellwig <hch@lst.de> Cc: Bart Van Assche <bvanassche@acm.org> Cc: Ewan D. Milne <emilne@redhat.com> Cc: Hannes Reinecke <hare@suse.com> Cc: Sagi Grimberg <sagi@grimberg.me> Cc: Chuck Lever <chuck.lever@oracle.com> Cc: netdev@vger.kernel.org Cc: linux-nvme@lists.infradead.org Suggested-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Ming Lei <ming.lei@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
1 parent ee5a1db commit 4635873

8 files changed

Lines changed: 76 additions & 41 deletions

File tree

drivers/nvme/host/fc.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2112,7 +2112,8 @@ nvme_fc_map_data(struct nvme_fc_ctrl *ctrl, struct request *rq,
21122112

21132113
freq->sg_table.sgl = freq->first_sgl;
21142114
ret = sg_alloc_table_chained(&freq->sg_table,
2115-
blk_rq_nr_phys_segments(rq), freq->sg_table.sgl);
2115+
blk_rq_nr_phys_segments(rq), freq->sg_table.sgl,
2116+
SG_CHUNK_SIZE);
21162117
if (ret)
21172118
return -ENOMEM;
21182119

@@ -2122,7 +2123,7 @@ nvme_fc_map_data(struct nvme_fc_ctrl *ctrl, struct request *rq,
21222123
freq->sg_cnt = fc_dma_map_sg(ctrl->lport->dev, freq->sg_table.sgl,
21232124
op->nents, dir);
21242125
if (unlikely(freq->sg_cnt <= 0)) {
2125-
sg_free_table_chained(&freq->sg_table, true);
2126+
sg_free_table_chained(&freq->sg_table, SG_CHUNK_SIZE);
21262127
freq->sg_cnt = 0;
21272128
return -EFAULT;
21282129
}
@@ -2148,7 +2149,7 @@ nvme_fc_unmap_data(struct nvme_fc_ctrl *ctrl, struct request *rq,
21482149

21492150
nvme_cleanup_cmd(rq);
21502151

2151-
sg_free_table_chained(&freq->sg_table, true);
2152+
sg_free_table_chained(&freq->sg_table, SG_CHUNK_SIZE);
21522153

21532154
freq->sg_cnt = 0;
21542155
}

drivers/nvme/host/rdma.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1133,7 +1133,7 @@ static void nvme_rdma_unmap_data(struct nvme_rdma_queue *queue,
11331133
WRITE ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
11341134

11351135
nvme_cleanup_cmd(rq);
1136-
sg_free_table_chained(&req->sg_table, true);
1136+
sg_free_table_chained(&req->sg_table, SG_CHUNK_SIZE);
11371137
}
11381138

11391139
static int nvme_rdma_set_sg_null(struct nvme_command *c)
@@ -1248,7 +1248,8 @@ static int nvme_rdma_map_data(struct nvme_rdma_queue *queue,
12481248

12491249
req->sg_table.sgl = req->first_sgl;
12501250
ret = sg_alloc_table_chained(&req->sg_table,
1251-
blk_rq_nr_phys_segments(rq), req->sg_table.sgl);
1251+
blk_rq_nr_phys_segments(rq), req->sg_table.sgl,
1252+
SG_CHUNK_SIZE);
12521253
if (ret)
12531254
return -ENOMEM;
12541255

@@ -1288,7 +1289,7 @@ static int nvme_rdma_map_data(struct nvme_rdma_queue *queue,
12881289
req->nents, rq_data_dir(rq) ==
12891290
WRITE ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
12901291
out_free_table:
1291-
sg_free_table_chained(&req->sg_table, true);
1292+
sg_free_table_chained(&req->sg_table, SG_CHUNK_SIZE);
12921293
return ret;
12931294
}
12941295

drivers/nvme/target/loop.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ static void nvme_loop_complete_rq(struct request *req)
7777
struct nvme_loop_iod *iod = blk_mq_rq_to_pdu(req);
7878

7979
nvme_cleanup_cmd(req);
80-
sg_free_table_chained(&iod->sg_table, true);
80+
sg_free_table_chained(&iod->sg_table, SG_CHUNK_SIZE);
8181
nvme_complete_rq(req);
8282
}
8383

@@ -157,7 +157,7 @@ static blk_status_t nvme_loop_queue_rq(struct blk_mq_hw_ctx *hctx,
157157
iod->sg_table.sgl = iod->first_sgl;
158158
if (sg_alloc_table_chained(&iod->sg_table,
159159
blk_rq_nr_phys_segments(req),
160-
iod->sg_table.sgl))
160+
iod->sg_table.sgl, SG_CHUNK_SIZE))
161161
return BLK_STS_RESOURCE;
162162

163163
iod->req.sg = iod->sg_table.sgl;

drivers/scsi/scsi_lib.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -541,9 +541,9 @@ static void scsi_uninit_cmd(struct scsi_cmnd *cmd)
541541
static void scsi_mq_free_sgtables(struct scsi_cmnd *cmd)
542542
{
543543
if (cmd->sdb.table.nents)
544-
sg_free_table_chained(&cmd->sdb.table, true);
544+
sg_free_table_chained(&cmd->sdb.table, SG_CHUNK_SIZE);
545545
if (scsi_prot_sg_count(cmd))
546-
sg_free_table_chained(&cmd->prot_sdb->table, true);
546+
sg_free_table_chained(&cmd->prot_sdb->table, SG_CHUNK_SIZE);
547547
}
548548

549549
static void scsi_mq_uninit_cmd(struct scsi_cmnd *cmd)
@@ -976,7 +976,8 @@ static blk_status_t scsi_init_sgtable(struct request *req,
976976
* If sg table allocation fails, requeue request later.
977977
*/
978978
if (unlikely(sg_alloc_table_chained(&sdb->table,
979-
blk_rq_nr_phys_segments(req), sdb->table.sgl)))
979+
blk_rq_nr_phys_segments(req), sdb->table.sgl,
980+
SG_CHUNK_SIZE)))
980981
return BLK_STS_RESOURCE;
981982

982983
/*
@@ -1030,7 +1031,8 @@ blk_status_t scsi_init_io(struct scsi_cmnd *cmd)
10301031
ivecs = blk_rq_count_integrity_sg(rq->q, rq->bio);
10311032

10321033
if (sg_alloc_table_chained(&prot_sdb->table, ivecs,
1033-
prot_sdb->table.sgl)) {
1034+
prot_sdb->table.sgl,
1035+
SG_CHUNK_SIZE)) {
10341036
ret = BLK_STS_RESOURCE;
10351037
goto out_free_sgtables;
10361038
}

include/linux/scatterlist.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -266,10 +266,11 @@ int sg_split(struct scatterlist *in, const int in_mapped_nents,
266266
typedef struct scatterlist *(sg_alloc_fn)(unsigned int, gfp_t);
267267
typedef void (sg_free_fn)(struct scatterlist *, unsigned int);
268268

269-
void __sg_free_table(struct sg_table *, unsigned int, bool, sg_free_fn *);
269+
void __sg_free_table(struct sg_table *, unsigned int, unsigned int,
270+
sg_free_fn *);
270271
void sg_free_table(struct sg_table *);
271272
int __sg_alloc_table(struct sg_table *, unsigned int, unsigned int,
272-
struct scatterlist *, gfp_t, sg_alloc_fn *);
273+
struct scatterlist *, unsigned int, gfp_t, sg_alloc_fn *);
273274
int sg_alloc_table(struct sg_table *, unsigned int, gfp_t);
274275
int __sg_alloc_table_from_pages(struct sg_table *sgt, struct page **pages,
275276
unsigned int n_pages, unsigned int offset,
@@ -331,9 +332,11 @@ size_t sg_zero_buffer(struct scatterlist *sgl, unsigned int nents,
331332
#endif
332333

333334
#ifdef CONFIG_SG_POOL
334-
void sg_free_table_chained(struct sg_table *table, bool first_chunk);
335+
void sg_free_table_chained(struct sg_table *table,
336+
unsigned nents_first_chunk);
335337
int sg_alloc_table_chained(struct sg_table *table, int nents,
336-
struct scatterlist *first_chunk);
338+
struct scatterlist *first_chunk,
339+
unsigned nents_first_chunk);
337340
#endif
338341

339342
/*

lib/scatterlist.c

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,8 @@ static void sg_kfree(struct scatterlist *sg, unsigned int nents)
181181
* __sg_free_table - Free a previously mapped sg table
182182
* @table: The sg table header to use
183183
* @max_ents: The maximum number of entries per single scatterlist
184-
* @skip_first_chunk: don't free the (preallocated) first scatterlist chunk
184+
* @nents_first_chunk: Number of entries int the (preallocated) first
185+
* scatterlist chunk, 0 means no such preallocated first chunk
185186
* @free_fn: Free function
186187
*
187188
* Description:
@@ -191,9 +192,10 @@ static void sg_kfree(struct scatterlist *sg, unsigned int nents)
191192
*
192193
**/
193194
void __sg_free_table(struct sg_table *table, unsigned int max_ents,
194-
bool skip_first_chunk, sg_free_fn *free_fn)
195+
unsigned int nents_first_chunk, sg_free_fn *free_fn)
195196
{
196197
struct scatterlist *sgl, *next;
198+
unsigned curr_max_ents = nents_first_chunk ?: max_ents;
197199

198200
if (unlikely(!table->sgl))
199201
return;
@@ -209,21 +211,22 @@ void __sg_free_table(struct sg_table *table, unsigned int max_ents,
209211
* sg_size is then one less than alloc size, since the last
210212
* element is the chain pointer.
211213
*/
212-
if (alloc_size > max_ents) {
213-
next = sg_chain_ptr(&sgl[max_ents - 1]);
214-
alloc_size = max_ents;
214+
if (alloc_size > curr_max_ents) {
215+
next = sg_chain_ptr(&sgl[curr_max_ents - 1]);
216+
alloc_size = curr_max_ents;
215217
sg_size = alloc_size - 1;
216218
} else {
217219
sg_size = alloc_size;
218220
next = NULL;
219221
}
220222

221223
table->orig_nents -= sg_size;
222-
if (skip_first_chunk)
223-
skip_first_chunk = false;
224+
if (nents_first_chunk)
225+
nents_first_chunk = 0;
224226
else
225227
free_fn(sgl, alloc_size);
226228
sgl = next;
229+
curr_max_ents = max_ents;
227230
}
228231

229232
table->sgl = NULL;
@@ -246,6 +249,8 @@ EXPORT_SYMBOL(sg_free_table);
246249
* @table: The sg table header to use
247250
* @nents: Number of entries in sg list
248251
* @max_ents: The maximum number of entries the allocator returns per call
252+
* @nents_first_chunk: Number of entries int the (preallocated) first
253+
* scatterlist chunk, 0 means no such preallocated chunk provided by user
249254
* @gfp_mask: GFP allocation mask
250255
* @alloc_fn: Allocator to use
251256
*
@@ -262,10 +267,13 @@ EXPORT_SYMBOL(sg_free_table);
262267
**/
263268
int __sg_alloc_table(struct sg_table *table, unsigned int nents,
264269
unsigned int max_ents, struct scatterlist *first_chunk,
265-
gfp_t gfp_mask, sg_alloc_fn *alloc_fn)
270+
unsigned int nents_first_chunk, gfp_t gfp_mask,
271+
sg_alloc_fn *alloc_fn)
266272
{
267273
struct scatterlist *sg, *prv;
268274
unsigned int left;
275+
unsigned curr_max_ents = nents_first_chunk ?: max_ents;
276+
unsigned prv_max_ents;
269277

270278
memset(table, 0, sizeof(*table));
271279

@@ -281,8 +289,8 @@ int __sg_alloc_table(struct sg_table *table, unsigned int nents,
281289
do {
282290
unsigned int sg_size, alloc_size = left;
283291

284-
if (alloc_size > max_ents) {
285-
alloc_size = max_ents;
292+
if (alloc_size > curr_max_ents) {
293+
alloc_size = curr_max_ents;
286294
sg_size = alloc_size - 1;
287295
} else
288296
sg_size = alloc_size;
@@ -316,7 +324,7 @@ int __sg_alloc_table(struct sg_table *table, unsigned int nents,
316324
* If this is not the first mapping, chain previous part.
317325
*/
318326
if (prv)
319-
sg_chain(prv, max_ents, sg);
327+
sg_chain(prv, prv_max_ents, sg);
320328
else
321329
table->sgl = sg;
322330

@@ -327,6 +335,8 @@ int __sg_alloc_table(struct sg_table *table, unsigned int nents,
327335
sg_mark_end(&sg[sg_size - 1]);
328336

329337
prv = sg;
338+
prv_max_ents = curr_max_ents;
339+
curr_max_ents = max_ents;
330340
} while (left);
331341

332342
return 0;
@@ -349,9 +359,9 @@ int sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask)
349359
int ret;
350360

351361
ret = __sg_alloc_table(table, nents, SG_MAX_SINGLE_ALLOC,
352-
NULL, gfp_mask, sg_kmalloc);
362+
NULL, 0, gfp_mask, sg_kmalloc);
353363
if (unlikely(ret))
354-
__sg_free_table(table, SG_MAX_SINGLE_ALLOC, false, sg_kfree);
364+
__sg_free_table(table, SG_MAX_SINGLE_ALLOC, 0, sg_kfree);
355365

356366
return ret;
357367
}

lib/sg_pool.c

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -69,18 +69,27 @@ static struct scatterlist *sg_pool_alloc(unsigned int nents, gfp_t gfp_mask)
6969
/**
7070
* sg_free_table_chained - Free a previously mapped sg table
7171
* @table: The sg table header to use
72-
* @first_chunk: was first_chunk not NULL in sg_alloc_table_chained?
72+
* @nents_first_chunk: size of the first_chunk SGL passed to
73+
* sg_alloc_table_chained
7374
*
7475
* Description:
7576
* Free an sg table previously allocated and setup with
7677
* sg_alloc_table_chained().
7778
*
79+
* @nents_first_chunk has to be same with that same parameter passed
80+
* to sg_alloc_table_chained().
81+
*
7882
**/
79-
void sg_free_table_chained(struct sg_table *table, bool first_chunk)
83+
void sg_free_table_chained(struct sg_table *table,
84+
unsigned nents_first_chunk)
8085
{
81-
if (first_chunk && table->orig_nents <= SG_CHUNK_SIZE)
86+
if (table->orig_nents <= nents_first_chunk)
8287
return;
83-
__sg_free_table(table, SG_CHUNK_SIZE, first_chunk, sg_pool_free);
88+
89+
if (nents_first_chunk == 1)
90+
nents_first_chunk = 0;
91+
92+
__sg_free_table(table, SG_CHUNK_SIZE, nents_first_chunk, sg_pool_free);
8493
}
8594
EXPORT_SYMBOL_GPL(sg_free_table_chained);
8695

@@ -89,31 +98,39 @@ EXPORT_SYMBOL_GPL(sg_free_table_chained);
8998
* @table: The sg table header to use
9099
* @nents: Number of entries in sg list
91100
* @first_chunk: first SGL
101+
* @nents_first_chunk: number of the SGL of @first_chunk
92102
*
93103
* Description:
94104
* Allocate and chain SGLs in an sg table. If @nents@ is larger than
95-
* SG_CHUNK_SIZE a chained sg table will be setup.
105+
* @nents_first_chunk a chained sg table will be setup.
96106
*
97107
**/
98108
int sg_alloc_table_chained(struct sg_table *table, int nents,
99-
struct scatterlist *first_chunk)
109+
struct scatterlist *first_chunk, unsigned nents_first_chunk)
100110
{
101111
int ret;
102112

103113
BUG_ON(!nents);
104114

105-
if (first_chunk) {
106-
if (nents <= SG_CHUNK_SIZE) {
115+
if (first_chunk && nents_first_chunk) {
116+
if (nents <= nents_first_chunk) {
107117
table->nents = table->orig_nents = nents;
108118
sg_init_table(table->sgl, nents);
109119
return 0;
110120
}
111121
}
112122

123+
/* User supposes that the 1st SGL includes real entry */
124+
if (nents_first_chunk == 1) {
125+
first_chunk = NULL;
126+
nents_first_chunk = 0;
127+
}
128+
113129
ret = __sg_alloc_table(table, nents, SG_CHUNK_SIZE,
114-
first_chunk, GFP_ATOMIC, sg_pool_alloc);
130+
first_chunk, nents_first_chunk,
131+
GFP_ATOMIC, sg_pool_alloc);
115132
if (unlikely(ret))
116-
sg_free_table_chained(table, (bool)first_chunk);
133+
sg_free_table_chained(table, nents_first_chunk);
117134
return ret;
118135
}
119136
EXPORT_SYMBOL_GPL(sg_alloc_table_chained);

net/sunrpc/xprtrdma/svc_rdma_rw.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ svc_rdma_get_rw_ctxt(struct svcxprt_rdma *rdma, unsigned int sges)
7373

7474
ctxt->rw_sg_table.sgl = ctxt->rw_first_sgl;
7575
if (sg_alloc_table_chained(&ctxt->rw_sg_table, sges,
76-
ctxt->rw_sg_table.sgl)) {
76+
ctxt->rw_sg_table.sgl,
77+
SG_CHUNK_SIZE)) {
7778
kfree(ctxt);
7879
ctxt = NULL;
7980
}
@@ -84,7 +85,7 @@ svc_rdma_get_rw_ctxt(struct svcxprt_rdma *rdma, unsigned int sges)
8485
static void svc_rdma_put_rw_ctxt(struct svcxprt_rdma *rdma,
8586
struct svc_rdma_rw_ctxt *ctxt)
8687
{
87-
sg_free_table_chained(&ctxt->rw_sg_table, true);
88+
sg_free_table_chained(&ctxt->rw_sg_table, SG_CHUNK_SIZE);
8889

8990
spin_lock(&rdma->sc_rw_ctxt_lock);
9091
list_add(&ctxt->rw_list, &rdma->sc_rw_ctxts);

0 commit comments

Comments
 (0)