In crypto engine framework, one request can combine (copy) other requests' scatterlists into its dynamic sg table to manage them together as a bulk block , which can improve engine efficency with handling bulk block. Thus we need some helper functions to manage dynamic scattertables. This patch introduces 'sg_is_contiguous()' function to check if two scatterlists are contiguous, 'sg_alloc_empty_table()' function to allocate one empty dynamic sg table, 'sg_add_sg_to_table()' function to copy one mapped scatterlist into sg table and 'sg_table_is_empty' function to check if the sg table is empty. Signed-off-by: Baolin Wang <baolin.wang@xxxxxxxxxx> --- include/linux/scatterlist.h | 33 +++++++++++++++++++++ lib/scatterlist.c | 69 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+) diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h index 556ec1e..c1ed9f4 100644 --- a/include/linux/scatterlist.h +++ b/include/linux/scatterlist.h @@ -212,6 +212,20 @@ static inline void sg_unmark_end(struct scatterlist *sg) } /** + * sg_table_is_empty - Check if the sg table is empty + * @sgt: sg table + * + * Description: + * The 'orig_nents' member of one sg table is used to indicate how many + * scatterlists in the sg table. + * + **/ +static inline bool sg_table_is_empty(struct sg_table *sgt) +{ + return !sgt->orig_nents; +} + +/** * sg_phys - Return physical address of an sg entry * @sg: SG entry * @@ -241,6 +255,23 @@ static inline void *sg_virt(struct scatterlist *sg) return page_address(sg_page(sg)) + sg->offset; } +/** + * sg_is_contiguous - Check if the scatterlists are contiguous + * @sga: SG entry + * @sgb: SG entry + * + * Description: + * If the sga scatterlist is contiguous with the sgb scatterlist, + * that means they can be merged together. + * + **/ +static inline bool sg_is_contiguous(struct scatterlist *sga, + struct scatterlist *sgb) +{ + return *(unsigned long *)sg_virt(sga) + sga->length == + *(unsigned long *)sg_virt(sgb); +} + int sg_nents(struct scatterlist *sg); int sg_nents_for_len(struct scatterlist *sg, u64 len); struct scatterlist *sg_next(struct scatterlist *); @@ -261,6 +292,8 @@ 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 *); int sg_alloc_table(struct sg_table *, unsigned int, gfp_t); +int sg_alloc_empty_table(struct sg_table *, unsigned int, gfp_t); +int sg_add_sg_to_table(struct sg_table *, struct scatterlist *); int sg_alloc_table_from_pages(struct sg_table *sgt, struct page **pages, unsigned int n_pages, unsigned long offset, unsigned long size, diff --git a/lib/scatterlist.c b/lib/scatterlist.c index 004fc70..6d3f3b0 100644 --- a/lib/scatterlist.c +++ b/lib/scatterlist.c @@ -370,6 +370,75 @@ int sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask) EXPORT_SYMBOL(sg_alloc_table); /** + * sg_add_sg_to_table - Add one scatterlist into sg table + * @sgt: The sg table header to use + * @src: The sg need to be added into sg table + * + * Description: + * The 'nents' member indicates how many mapped scatterlists has been added + * in the dynamic sg table. The 'orig_nents' member indicates the size of the + * dynamic sg table. + * + * Copy one mapped @src@ scatterlist into the dynamic sg table and increase + * 'nents' member. + * + **/ +int sg_add_sg_to_table(struct sg_table *sgt, struct scatterlist *src) +{ + unsigned int i = 0, orig_nents = sgt->orig_nents; + struct scatterlist *sgl = sgt->sgl; + struct scatterlist *sg; + + /* Check if there are enough space for the new sg to be added */ + if (sgt->nents >= sgt->orig_nents) + return -EINVAL; + + for_each_sg(sgl, sg, orig_nents, i) { + if (sgt->nents > 0 && i == (sgt->nents - 1)) { + sg_unmark_end(sg); + } else if (i == sgt->nents) { + memcpy(sg, src, sizeof(struct scatterlist)); + sg_mark_end(sg); + sgt->nents++; + break; + } + } + + return 0; +} + +/** + * sg_alloc_empty_table - Allocate one empty dynamic sg table + * @sgt: The sg table header to use + * @nents: Number of entries in sg list + * @gfp_mask: GFP allocation mask + * + * Description: + * Allocate and initialize one dynamic sg table. One dynamic sg table means + * it need allocate @nents@ empty scatterlists entries and is used to copy + * other mapped scatterlists into the dynamic sg table. + * + * The 'nents' member indicates how many scatterlists has been copied into + * the dynamic sg table. It should set 0 which means there are no mapped + * scatterlists added in this sg table now. + * + * The 'orig_nents' member indicates the size of the dynamic sg table. + * + **/ +int sg_alloc_empty_table(struct sg_table *sgt, unsigned int nents, + gfp_t gfp_mask) +{ + int ret; + + ret = sg_alloc_table(sgt, nents, gfp_mask); + if (ret) + return ret; + + sgt->nents = 0; + return 0; +} + +/** * sg_alloc_table_from_pages - Allocate and initialize an sg table from * an array of pages * @sgt: The sg table header to use -- 1.7.9.5 -- dm-devel mailing list dm-devel@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/dm-devel