On Thu, Apr 25, 2019 at 05:37:29PM +0800, Ming Lei wrote:
> On Wed, Apr 24, 2019 at 04:37:04PM +0200, Christoph Hellwig wrote:
> > > - if (scsi_prot_sg_count(cmd))
> > > -         sg_free_table_chained(&cmd->prot_sdb->table, true);
> > > + if (scsi_prot_sg_count(cmd) && cmd->prot_sdb->table.sgl !=
> > > +                 scsi_prot_inline_sg(cmd))
> > > +         sg_free_table_chained(&cmd->prot_sdb->table, false);
> > 
> > Nipick: I usually find it easier to read if we break around conditions
> > instead of inside them:
> > 
> >     if (scsi_prot_sg_count(cmd) &&
> >         cmd->prot_sdb->table.sgl != scsi_prot_inline_sg(cmd))
> 
> OK.
> 
> > 
> > > +         if (ivecs <= SCSI_INLINE_PROT_SG_CNT) {
> > > +                 scsi_init_inline_sg_table(&prot_sdb->table,
> > > +                                           scsi_prot_inline_sg(cmd),
> > > +                                           SCSI_INLINE_PROT_SG_CNT);
> > > +         } else if (sg_alloc_table_chained(&prot_sdb->table,
> > > +                                           ivecs, NULL)) {
> > 
> > Hmm.  Maybe we just need to pass an nr_inline_vecs argument
> > to sg_alloc_table_chained to replace the SG_CHUNK_SIZE argument instead
> > of open coding this logic?
> 
> We can do that, however the current scatterlist code assumes that size
> of each SGL is fixed. We may change the logic to support this feature,
> seems not too difficult to do that.
> 
> Please let us know if you are fine to change the scatterlist code for
> supporting customized size of the 1st SGL.

Especially, something like the following change is needed:

 include/linux/scatterlist.h | 27 ++++++++++++++++++++-----
 lib/scatterlist.c           | 36 ++++++++++++++++++++++------------
 lib/sg_pool.c               | 48 ++++++++++++++++++++++++++++++---------------
 3 files changed, 77 insertions(+), 34 deletions(-)

diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h
index b4be960c7e5d..045d7aa81f2c 100644
--- a/include/linux/scatterlist.h
+++ b/include/linux/scatterlist.h
@@ -266,10 +266,11 @@ int sg_split(struct scatterlist *in, const int 
in_mapped_nents,
 typedef struct scatterlist *(sg_alloc_fn)(unsigned int, gfp_t);
 typedef void (sg_free_fn)(struct scatterlist *, unsigned int);
 
-void __sg_free_table(struct sg_table *, unsigned int, bool, sg_free_fn *);
+void __sg_free_table(struct sg_table *, unsigned int, unsigned int,
+                    sg_free_fn *);
 void sg_free_table(struct sg_table *);
 int __sg_alloc_table(struct sg_table *, unsigned int, unsigned int,
-                    struct scatterlist *, gfp_t, sg_alloc_fn *);
+                    struct scatterlist *, unsigned int, gfp_t, sg_alloc_fn *);
 int sg_alloc_table(struct sg_table *, unsigned int, gfp_t);
 int __sg_alloc_table_from_pages(struct sg_table *sgt, struct page **pages,
                                unsigned int n_pages, unsigned int offset,
@@ -331,9 +332,25 @@ size_t sg_zero_buffer(struct scatterlist *sgl, unsigned 
int nents,
 #endif
 
 #ifdef CONFIG_SG_POOL
-void sg_free_table_chained(struct sg_table *table, bool first_chunk);
-int sg_alloc_table_chained(struct sg_table *table, int nents,
-                          struct scatterlist *first_chunk);
+void __sg_free_table_chained(struct sg_table *table,
+                            unsigned nents_first_chunk);
+int __sg_alloc_table_chained(struct sg_table *table, int nents,
+                            struct scatterlist *first_chunk,
+                            unsigned nents_first_chunk);
+
+static inline void sg_free_table_chained(struct sg_table *table,
+                                        bool first_chunk)
+{
+       __sg_free_table_chained(table, first_chunk ? SG_CHUNK_SIZE : 0);
+}
+
+static inline int sg_alloc_table_chained(struct sg_table *table,
+                                        int nents,
+                                        struct scatterlist *first_chunk)
+{
+       return __sg_alloc_table_chained(table, nents, first_chunk,
+                                       first_chunk ? SG_CHUNK_SIZE : 0);
+}
 #endif
 
 /*
diff --git a/lib/scatterlist.c b/lib/scatterlist.c
index 739dc9fe2c55..401dd38080bc 100644
--- a/lib/scatterlist.c
+++ b/lib/scatterlist.c
@@ -181,7 +181,8 @@ static void sg_kfree(struct scatterlist *sg, unsigned int 
nents)
  * __sg_free_table - Free a previously mapped sg table
  * @table:     The sg table header to use
  * @max_ents:  The maximum number of entries per single scatterlist
- * @skip_first_chunk: don't free the (preallocated) first scatterlist chunk
+ * @nrents_first_chunk: Number of entries int the (preallocated) first
+ *     scatterlist chunk, 0 means skipping to free the first chunk
  * @free_fn:   Free function
  *
  *  Description:
@@ -191,9 +192,10 @@ static void sg_kfree(struct scatterlist *sg, unsigned int 
nents)
  *
  **/
 void __sg_free_table(struct sg_table *table, unsigned int max_ents,
-                    bool skip_first_chunk, sg_free_fn *free_fn)
+                    unsigned int nents_first_chunk, sg_free_fn *free_fn)
 {
        struct scatterlist *sgl, *next;
+       unsigned curr_max_ents = nents_first_chunk ?: max_ents;
 
        if (unlikely(!table->sgl))
                return;
@@ -209,9 +211,9 @@ void __sg_free_table(struct sg_table *table, unsigned int 
max_ents,
                 * sg_size is then one less than alloc size, since the last
                 * element is the chain pointer.
                 */
-               if (alloc_size > max_ents) {
-                       next = sg_chain_ptr(&sgl[max_ents - 1]);
-                       alloc_size = max_ents;
+               if (alloc_size > curr_max_ents) {
+                       next = sg_chain_ptr(&sgl[curr_max_ents - 1]);
+                       alloc_size = curr_max_ents;
                        sg_size = alloc_size - 1;
                } else {
                        sg_size = alloc_size;
@@ -219,11 +221,12 @@ void __sg_free_table(struct sg_table *table, unsigned int 
max_ents,
                }
 
                table->orig_nents -= sg_size;
-               if (skip_first_chunk)
-                       skip_first_chunk = false;
+               if (nents_first_chunk)
+                       nents_first_chunk = 0;
                else
                        free_fn(sgl, alloc_size);
                sgl = next;
+               curr_max_ents = max_ents;
        }
 
        table->sgl = NULL;
@@ -246,6 +249,8 @@ EXPORT_SYMBOL(sg_free_table);
  * @table:     The sg table header to use
  * @nents:     Number of entries in sg list
  * @max_ents:  The maximum number of entries the allocator returns per call
+ * @nrents_first_chunk: Number of entries int the (preallocated) first
+ *     scatterlist chunk, 0 means no such 1st chunk provided by user
  * @gfp_mask:  GFP allocation mask
  * @alloc_fn:  Allocator to use
  *
@@ -262,10 +267,13 @@ EXPORT_SYMBOL(sg_free_table);
  **/
 int __sg_alloc_table(struct sg_table *table, unsigned int nents,
                     unsigned int max_ents, struct scatterlist *first_chunk,
-                    gfp_t gfp_mask, sg_alloc_fn *alloc_fn)
+                    unsigned int nents_first_chunk, gfp_t gfp_mask,
+                    sg_alloc_fn *alloc_fn)
 {
        struct scatterlist *sg, *prv;
        unsigned int left;
+       unsigned curr_max_ents = nents_first_chunk ?: max_ents;
+       unsigned prv_max_ents;
 
        memset(table, 0, sizeof(*table));
 
@@ -281,8 +289,8 @@ int __sg_alloc_table(struct sg_table *table, unsigned int 
nents,
        do {
                unsigned int sg_size, alloc_size = left;
 
-               if (alloc_size > max_ents) {
-                       alloc_size = max_ents;
+               if (alloc_size > curr_max_ents) {
+                       alloc_size = curr_max_ents;
                        sg_size = alloc_size - 1;
                } else
                        sg_size = alloc_size;
@@ -316,7 +324,7 @@ int __sg_alloc_table(struct sg_table *table, unsigned int 
nents,
                 * If this is not the first mapping, chain previous part.
                 */
                if (prv)
-                       sg_chain(prv, max_ents, sg);
+                       sg_chain(prv, prv_max_ents, sg);
                else
                        table->sgl = sg;
 
@@ -327,6 +335,8 @@ int __sg_alloc_table(struct sg_table *table, unsigned int 
nents,
                        sg_mark_end(&sg[sg_size - 1]);
 
                prv = sg;
+               prv_max_ents = curr_max_ents;
+               curr_max_ents = max_ents;
        } while (left);
 
        return 0;
@@ -349,9 +359,9 @@ int sg_alloc_table(struct sg_table *table, unsigned int 
nents, gfp_t gfp_mask)
        int ret;
 
        ret = __sg_alloc_table(table, nents, SG_MAX_SINGLE_ALLOC,
-                              NULL, gfp_mask, sg_kmalloc);
+                              NULL, 0, gfp_mask, sg_kmalloc);
        if (unlikely(ret))
-               __sg_free_table(table, SG_MAX_SINGLE_ALLOC, false, sg_kfree);
+               __sg_free_table(table, SG_MAX_SINGLE_ALLOC, 0, sg_kfree);
 
        return ret;
 }
diff --git a/lib/sg_pool.c b/lib/sg_pool.c
index d1c1e6388eaa..e0f4bc0de8bd 100644
--- a/lib/sg_pool.c
+++ b/lib/sg_pool.c
@@ -67,56 +67,72 @@ static struct scatterlist *sg_pool_alloc(unsigned int 
nents, gfp_t gfp_mask)
 }
 
 /**
- * sg_free_table_chained - Free a previously mapped sg table
+ * __sg_free_table_chained - Free a previously mapped sg table
  * @table:     The sg table header to use
- * @first_chunk: was first_chunk not NULL in sg_alloc_table_chained?
+ * @nents_first_chunk: size of the first_chunk SGL passed to
+ *             __sg_alloc_table_chained
  *
  *  Description:
  *    Free an sg table previously allocated and setup with
- *    sg_alloc_table_chained().
+ *    __sg_alloc_table_chained().
+ *
+ *    @nents_first_chunk has to be same with that same parameter passed
+ *    to __sg_alloc_table_chained().
  *
  **/
-void sg_free_table_chained(struct sg_table *table, bool first_chunk)
+void __sg_free_table_chained(struct sg_table *table,
+               unsigned nents_first_chunk)
 {
-       if (first_chunk && table->orig_nents <= SG_CHUNK_SIZE)
+       if (table->orig_nents <= nents_first_chunk)
                return;
-       __sg_free_table(table, SG_CHUNK_SIZE, first_chunk, sg_pool_free);
+
+       if (nents_first_chunk == 1)
+               nents_first_chunk = 0;
+
+       __sg_free_table(table, SG_CHUNK_SIZE, nents_first_chunk, sg_pool_free);
 }
-EXPORT_SYMBOL_GPL(sg_free_table_chained);
+EXPORT_SYMBOL_GPL(__sg_free_table_chained);
 
 /**
- * sg_alloc_table_chained - Allocate and chain SGLs in an sg table
+ * __sg_alloc_table_chained - Allocate and chain SGLs in an sg table
  * @table:     The sg table header to use
  * @nents:     Number of entries in sg list
  * @first_chunk: first SGL
+ * @nents_first_chunk: number of the SGL of @first_chunk
  *
  *  Description:
  *    Allocate and chain SGLs in an sg table. If @nents@ is larger than
- *    SG_CHUNK_SIZE a chained sg table will be setup.
+ *    @nents_first_chunk a chained sg table will be setup.
  *
  **/
-int sg_alloc_table_chained(struct sg_table *table, int nents,
-               struct scatterlist *first_chunk)
+int __sg_alloc_table_chained(struct sg_table *table, int nents,
+               struct scatterlist *first_chunk, unsigned nents_first_chunk)
 {
        int ret;
 
        BUG_ON(!nents);
 
-       if (first_chunk) {
-               if (nents <= SG_CHUNK_SIZE) {
+       if (first_chunk && nents_first_chunk) {
+               if (nents <= nents_first_chunk) {
                        table->nents = table->orig_nents = nents;
                        sg_init_table(table->sgl, nents);
                        return 0;
                }
        }
 
+       if (nents_first_chunk == 1) {
+               first_chunk = NULL;
+               nents_first_chunk = 0;
+       }
+
        ret = __sg_alloc_table(table, nents, SG_CHUNK_SIZE,
-                              first_chunk, GFP_ATOMIC, sg_pool_alloc);
+                              first_chunk, nents_first_chunk,
+                              GFP_ATOMIC, sg_pool_alloc);
        if (unlikely(ret))
-               sg_free_table_chained(table, (bool)first_chunk);
+               __sg_free_table_chained(table, nents_first_chunk);
        return ret;
 }
-EXPORT_SYMBOL_GPL(sg_alloc_table_chained);
+EXPORT_SYMBOL_GPL(__sg_alloc_table_chained);
 
 static __init int sg_pool_init(void)
 {

Thanks,
Ming

Reply via email to