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