Back to home page

LXR

 
 

    


0001 #include <linux/module.h>
0002 #include <linux/scatterlist.h>
0003 #include <linux/mempool.h>
0004 #include <linux/slab.h>
0005 
0006 #define SG_MEMPOOL_NR       ARRAY_SIZE(sg_pools)
0007 #define SG_MEMPOOL_SIZE     2
0008 
0009 struct sg_pool {
0010     size_t      size;
0011     char        *name;
0012     struct kmem_cache   *slab;
0013     mempool_t   *pool;
0014 };
0015 
0016 #define SP(x) { .size = x, "sgpool-" __stringify(x) }
0017 #if (SG_CHUNK_SIZE < 32)
0018 #error SG_CHUNK_SIZE is too small (must be 32 or greater)
0019 #endif
0020 static struct sg_pool sg_pools[] = {
0021     SP(8),
0022     SP(16),
0023 #if (SG_CHUNK_SIZE > 32)
0024     SP(32),
0025 #if (SG_CHUNK_SIZE > 64)
0026     SP(64),
0027 #if (SG_CHUNK_SIZE > 128)
0028     SP(128),
0029 #if (SG_CHUNK_SIZE > 256)
0030 #error SG_CHUNK_SIZE is too large (256 MAX)
0031 #endif
0032 #endif
0033 #endif
0034 #endif
0035     SP(SG_CHUNK_SIZE)
0036 };
0037 #undef SP
0038 
0039 static inline unsigned int sg_pool_index(unsigned short nents)
0040 {
0041     unsigned int index;
0042 
0043     BUG_ON(nents > SG_CHUNK_SIZE);
0044 
0045     if (nents <= 8)
0046         index = 0;
0047     else
0048         index = get_count_order(nents) - 3;
0049 
0050     return index;
0051 }
0052 
0053 static void sg_pool_free(struct scatterlist *sgl, unsigned int nents)
0054 {
0055     struct sg_pool *sgp;
0056 
0057     sgp = sg_pools + sg_pool_index(nents);
0058     mempool_free(sgl, sgp->pool);
0059 }
0060 
0061 static struct scatterlist *sg_pool_alloc(unsigned int nents, gfp_t gfp_mask)
0062 {
0063     struct sg_pool *sgp;
0064 
0065     sgp = sg_pools + sg_pool_index(nents);
0066     return mempool_alloc(sgp->pool, gfp_mask);
0067 }
0068 
0069 /**
0070  * sg_free_table_chained - Free a previously mapped sg table
0071  * @table:  The sg table header to use
0072  * @first_chunk: was first_chunk not NULL in sg_alloc_table_chained?
0073  *
0074  *  Description:
0075  *    Free an sg table previously allocated and setup with
0076  *    sg_alloc_table_chained().
0077  *
0078  **/
0079 void sg_free_table_chained(struct sg_table *table, bool first_chunk)
0080 {
0081     if (first_chunk && table->orig_nents <= SG_CHUNK_SIZE)
0082         return;
0083     __sg_free_table(table, SG_CHUNK_SIZE, first_chunk, sg_pool_free);
0084 }
0085 EXPORT_SYMBOL_GPL(sg_free_table_chained);
0086 
0087 /**
0088  * sg_alloc_table_chained - Allocate and chain SGLs in an sg table
0089  * @table:  The sg table header to use
0090  * @nents:  Number of entries in sg list
0091  * @first_chunk: first SGL
0092  *
0093  *  Description:
0094  *    Allocate and chain SGLs in an sg table. If @nents@ is larger than
0095  *    SG_CHUNK_SIZE a chained sg table will be setup.
0096  *
0097  **/
0098 int sg_alloc_table_chained(struct sg_table *table, int nents,
0099         struct scatterlist *first_chunk)
0100 {
0101     int ret;
0102 
0103     BUG_ON(!nents);
0104 
0105     if (first_chunk) {
0106         if (nents <= SG_CHUNK_SIZE) {
0107             table->nents = table->orig_nents = nents;
0108             sg_init_table(table->sgl, nents);
0109             return 0;
0110         }
0111     }
0112 
0113     ret = __sg_alloc_table(table, nents, SG_CHUNK_SIZE,
0114                    first_chunk, GFP_ATOMIC, sg_pool_alloc);
0115     if (unlikely(ret))
0116         sg_free_table_chained(table, (bool)first_chunk);
0117     return ret;
0118 }
0119 EXPORT_SYMBOL_GPL(sg_alloc_table_chained);
0120 
0121 static __init int sg_pool_init(void)
0122 {
0123     int i;
0124 
0125     for (i = 0; i < SG_MEMPOOL_NR; i++) {
0126         struct sg_pool *sgp = sg_pools + i;
0127         int size = sgp->size * sizeof(struct scatterlist);
0128 
0129         sgp->slab = kmem_cache_create(sgp->name, size, 0,
0130                 SLAB_HWCACHE_ALIGN, NULL);
0131         if (!sgp->slab) {
0132             printk(KERN_ERR "SG_POOL: can't init sg slab %s\n",
0133                     sgp->name);
0134             goto cleanup_sdb;
0135         }
0136 
0137         sgp->pool = mempool_create_slab_pool(SG_MEMPOOL_SIZE,
0138                              sgp->slab);
0139         if (!sgp->pool) {
0140             printk(KERN_ERR "SG_POOL: can't init sg mempool %s\n",
0141                     sgp->name);
0142             goto cleanup_sdb;
0143         }
0144     }
0145 
0146     return 0;
0147 
0148 cleanup_sdb:
0149     for (i = 0; i < SG_MEMPOOL_NR; i++) {
0150         struct sg_pool *sgp = sg_pools + i;
0151         if (sgp->pool)
0152             mempool_destroy(sgp->pool);
0153         if (sgp->slab)
0154             kmem_cache_destroy(sgp->slab);
0155     }
0156 
0157     return -ENOMEM;
0158 }
0159 
0160 static __exit void sg_pool_exit(void)
0161 {
0162     int i;
0163 
0164     for (i = 0; i < SG_MEMPOOL_NR; i++) {
0165         struct sg_pool *sgp = sg_pools + i;
0166         mempool_destroy(sgp->pool);
0167         kmem_cache_destroy(sgp->slab);
0168     }
0169 }
0170 
0171 module_init(sg_pool_init);
0172 module_exit(sg_pool_exit);