4 * Copyright (C) 2006 - 2009 Vladislav Bolkhovitin <vst@vlnb.net>
5 * Copyright (C) 2007 - 2009 ID7 Ltd.
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, version 2
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
18 #include <linux/init.h>
19 #include <linux/kernel.h>
20 #include <linux/errno.h>
21 #include <linux/list.h>
22 #include <linux/spinlock.h>
23 #include <linux/slab.h>
24 #include <linux/sched.h>
26 #include <linux/unistd.h>
27 #include <linux/string.h>
30 #include "scst_priv.h"
33 #define SGV_DEFAULT_PURGE_INTERVAL (60 * HZ)
34 #define SGV_MIN_SHRINK_INTERVAL (1 * HZ)
36 /* Max pages freed from a pool per shrinking iteration */
37 #define MAX_PAGES_PER_POOL 50
39 static struct sgv_pool *sgv_norm_clust_pool, *sgv_norm_pool, *sgv_dma_pool;
41 static atomic_t sgv_pages_total = ATOMIC_INIT(0);
44 static int sgv_hi_wmk;
45 static int sgv_lo_wmk;
47 static int sgv_max_local_pages, sgv_max_trans_pages;
49 static DEFINE_SPINLOCK(sgv_pools_lock); /* inner lock for sgv_pool_lock! */
50 static DEFINE_MUTEX(sgv_pools_mutex);
52 /* Both protected by sgv_pools_lock */
53 static struct sgv_pool *sgv_cur_purge_pool;
54 static LIST_HEAD(sgv_active_pools_list);
56 static atomic_t sgv_releases_on_hiwmk = ATOMIC_INIT(0);
57 static atomic_t sgv_releases_on_hiwmk_failed = ATOMIC_INIT(0);
59 static atomic_t sgv_other_total_alloc = ATOMIC_INIT(0);
61 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23))
62 static struct shrinker *sgv_shrinker;
64 static struct shrinker sgv_shrinker;
68 * Protected by sgv_pools_mutex AND sgv_pools_lock for writes,
69 * either one for reads.
71 static LIST_HEAD(sgv_pools_list);
73 static inline bool sgv_pool_clustered(const struct sgv_pool *pool)
75 return pool->clustering_type != sgv_no_clustering;
78 void scst_sgv_pool_use_norm(struct scst_tgt_dev *tgt_dev)
80 tgt_dev->gfp_mask = __GFP_NOWARN;
81 tgt_dev->pool = sgv_norm_pool;
82 clear_bit(SCST_TGT_DEV_CLUST_POOL, &tgt_dev->tgt_dev_flags);
85 void scst_sgv_pool_use_norm_clust(struct scst_tgt_dev *tgt_dev)
87 TRACE_MEM("%s", "Use clustering");
88 tgt_dev->gfp_mask = __GFP_NOWARN;
89 tgt_dev->pool = sgv_norm_clust_pool;
90 set_bit(SCST_TGT_DEV_CLUST_POOL, &tgt_dev->tgt_dev_flags);
93 void scst_sgv_pool_use_dma(struct scst_tgt_dev *tgt_dev)
95 TRACE_MEM("%s", "Use ISA DMA memory");
96 tgt_dev->gfp_mask = __GFP_NOWARN | GFP_DMA;
97 tgt_dev->pool = sgv_dma_pool;
98 clear_bit(SCST_TGT_DEV_CLUST_POOL, &tgt_dev->tgt_dev_flags);
101 /* Must be no locks */
102 static void sgv_dtor_and_free(struct sgv_pool_obj *obj)
104 struct sgv_pool *pool = obj->owner_pool;
106 TRACE_MEM("Destroying sgv obj %p", obj);
108 if (obj->sg_count != 0) {
109 pool->alloc_fns.free_pages_fn(obj->sg_entries,
110 obj->sg_count, obj->allocator_priv);
112 if (obj->sg_entries != obj->sg_entries_data) {
113 if (obj->trans_tbl !=
114 (struct trans_tbl_ent *)obj->sg_entries_data) {
115 /* kfree() handles NULL parameter */
116 kfree(obj->trans_tbl);
117 obj->trans_tbl = NULL;
119 kfree(obj->sg_entries);
122 kmem_cache_free(pool->caches[obj->cache_num], obj);
126 /* Might be called under sgv_pool_lock */
127 static inline void sgv_del_from_active(struct sgv_pool *pool)
129 struct list_head *next;
131 TRACE_MEM("Deleting sgv pool %p from the active list", pool);
133 spin_lock_bh(&sgv_pools_lock);
135 next = pool->sgv_active_pools_list_entry.next;
136 list_del(&pool->sgv_active_pools_list_entry);
138 if (sgv_cur_purge_pool == pool) {
139 TRACE_MEM("Sgv pool %p is sgv cur purge pool", pool);
141 if (next == &sgv_active_pools_list)
144 if (next == &sgv_active_pools_list) {
145 sgv_cur_purge_pool = NULL;
146 TRACE_MEM("%s", "Sgv active list now empty");
148 sgv_cur_purge_pool = list_entry(next, typeof(*pool),
149 sgv_active_pools_list_entry);
150 TRACE_MEM("New sgv cur purge pool %p",
155 spin_unlock_bh(&sgv_pools_lock);
159 /* Must be called under sgv_pool_lock held */
160 static void sgv_dec_cached_entries(struct sgv_pool *pool, int pages)
162 pool->cached_entries--;
163 pool->cached_pages -= pages;
165 if (pool->cached_entries == 0)
166 sgv_del_from_active(pool);
171 /* Must be called under sgv_pool_lock held */
172 static void __sgv_purge_from_cache(struct sgv_pool_obj *obj)
174 int pages = obj->pages;
175 struct sgv_pool *pool = obj->owner_pool;
177 TRACE_MEM("Purging sgv obj %p from pool %p (new cached_entries %d)",
178 obj, pool, pool->cached_entries-1);
180 list_del(&obj->sorted_recycling_list_entry);
181 list_del(&obj->recycling_list_entry);
183 pool->inactive_cached_pages -= pages;
184 sgv_dec_cached_entries(pool, pages);
186 atomic_sub(pages, &sgv_pages_total);
191 /* Must be called under sgv_pool_lock held */
192 static bool sgv_purge_from_cache(struct sgv_pool_obj *obj, int min_interval,
193 unsigned long cur_time)
195 EXTRACHECKS_BUG_ON(min_interval < 0);
197 TRACE_MEM("Checking if sgv obj %p should be purged (cur time %ld, "
198 "obj time %ld, time to purge %ld)", obj, cur_time,
199 obj->time_stamp, obj->time_stamp + min_interval);
201 if (time_after_eq(cur_time, (obj->time_stamp + min_interval))) {
202 __sgv_purge_from_cache(obj);
209 static int sgv_shrink_pool(struct sgv_pool *pool, int nr, int min_interval,
210 unsigned long cur_time)
216 TRACE_MEM("Trying to shrink pool %p (nr %d, min_interval %d)",
217 pool, nr, min_interval);
219 if (pool->purge_interval < 0) {
220 TRACE_MEM("Not shrinkable pool %p, skipping", pool);
224 spin_lock_bh(&pool->sgv_pool_lock);
226 while (!list_empty(&pool->sorted_recycling_list) &&
227 (atomic_read(&sgv_pages_total) > sgv_lo_wmk)) {
228 struct sgv_pool_obj *obj = list_entry(
229 pool->sorted_recycling_list.next,
230 struct sgv_pool_obj, sorted_recycling_list_entry);
232 if (sgv_purge_from_cache(obj, min_interval, cur_time)) {
233 int pages = obj->pages;
238 TRACE_MEM("%d pages purged from pool %p (nr left %d, "
239 "total freed %d)", pages, pool, nr, freed);
241 spin_unlock_bh(&pool->sgv_pool_lock);
242 sgv_dtor_and_free(obj);
243 spin_lock_bh(&pool->sgv_pool_lock);
247 if ((nr <= 0) || (freed >= MAX_PAGES_PER_POOL)) {
248 if (freed >= MAX_PAGES_PER_POOL)
249 TRACE_MEM("%d pages purged from pool %p, "
250 "leaving", freed, pool);
255 spin_unlock_bh(&pool->sgv_pool_lock);
263 static int __sgv_shrink(int nr, int min_interval)
265 struct sgv_pool *pool;
266 unsigned long cur_time = jiffies;
272 TRACE_MEM("Trying to shrink %d pages from all sgv pools "
273 "(min_interval %d)", nr, min_interval);
276 struct list_head *next;
278 spin_lock_bh(&sgv_pools_lock);
280 pool = sgv_cur_purge_pool;
282 if (list_empty(&sgv_active_pools_list)) {
283 TRACE_MEM("%s", "Active pools list is empty");
287 pool = list_entry(sgv_active_pools_list.next,
289 sgv_active_pools_list_entry);
293 next = pool->sgv_active_pools_list_entry.next;
294 if (next == &sgv_active_pools_list) {
295 if (circle && (prev_nr == nr)) {
296 TRACE_MEM("Full circle done, but no progress, "
297 "leaving (nr %d)", nr);
306 sgv_cur_purge_pool = list_entry(next, typeof(*pool),
307 sgv_active_pools_list_entry);
308 TRACE_MEM("New cur purge pool %p", sgv_cur_purge_pool);
310 spin_unlock_bh(&sgv_pools_lock);
312 nr = sgv_shrink_pool(pool, nr, min_interval, cur_time);
322 spin_unlock_bh(&sgv_pools_lock);
326 spin_unlock_bh(&sgv_pools_lock);
331 static int sgv_shrink(int nr, gfp_t gfpm)
336 nr = __sgv_shrink(nr, SGV_MIN_SHRINK_INTERVAL);
337 TRACE_MEM("Left %d", nr);
339 struct sgv_pool *pool;
340 int inactive_pages = 0;
342 spin_lock_bh(&sgv_pools_lock);
343 list_for_each_entry(pool, &sgv_active_pools_list,
344 sgv_active_pools_list_entry) {
345 if (pool->purge_interval > 0)
346 inactive_pages += pool->inactive_cached_pages;
348 spin_unlock_bh(&sgv_pools_lock);
350 nr = max((int)0, inactive_pages - sgv_lo_wmk);
351 TRACE_MEM("Can free %d (total %d)", nr,
352 atomic_read(&sgv_pages_total));
359 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
360 static void sgv_purge_work_fn(void *p)
362 static void sgv_purge_work_fn(struct delayed_work *work)
365 unsigned long cur_time = jiffies;
366 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
367 struct sgv_pool *pool = (struct sgv_pool *)p;
369 struct sgv_pool *pool = container_of(work, struct sgv_pool,
375 TRACE_MEM("Purge work for pool %p", pool);
377 spin_lock_bh(&pool->sgv_pool_lock);
379 pool->purge_work_scheduled = false;
381 while (!list_empty(&pool->sorted_recycling_list)) {
382 struct sgv_pool_obj *obj = list_entry(
383 pool->sorted_recycling_list.next,
384 struct sgv_pool_obj, sorted_recycling_list_entry);
386 if (sgv_purge_from_cache(obj, pool->purge_interval, cur_time)) {
387 spin_unlock_bh(&pool->sgv_pool_lock);
388 sgv_dtor_and_free(obj);
389 spin_lock_bh(&pool->sgv_pool_lock);
392 * Let's reschedule it for full period to not get here
393 * too often. In the worst case we have shrinker
394 * to reclaim buffers quickier.
396 TRACE_MEM("Rescheduling purge work for pool %p (delay "
397 "%d HZ/%d sec)", pool, pool->purge_interval,
398 pool->purge_interval/HZ);
399 schedule_delayed_work(&pool->sgv_purge_work,
400 pool->purge_interval);
401 pool->purge_work_scheduled = true;
406 spin_unlock_bh(&pool->sgv_pool_lock);
408 TRACE_MEM("Leaving purge work for pool %p", pool);
414 static int sgv_check_full_clustering(struct scatterlist *sg, int cur, int hint)
418 unsigned long pfn_cur = page_to_pfn(sg_page(&sg[cur]));
419 int len_cur = sg[cur].length;
420 unsigned long pfn_cur_next = pfn_cur + (len_cur >> PAGE_SHIFT);
421 int full_page_cur = (len_cur & (PAGE_SIZE - 1)) == 0;
422 unsigned long pfn, pfn_next;
426 TRACE_MEM("pfn_cur %ld, pfn_cur_next %ld, len_cur %d, full_page_cur %d",
427 pfn_cur, pfn_cur_next, len_cur, full_page_cur);
430 /* check the hint first */
432 pfn = page_to_pfn(sg_page(&sg[i]));
433 pfn_next = pfn + (sg[i].length >> PAGE_SHIFT);
434 full_page = (sg[i].length & (PAGE_SIZE - 1)) == 0;
436 if ((pfn == pfn_cur_next) && full_page_cur)
439 if ((pfn_next == pfn_cur) && full_page)
443 /* ToDo: implement more intelligent search */
444 for (i = cur - 1; i >= 0; i--) {
445 pfn = page_to_pfn(sg_page(&sg[i]));
446 pfn_next = pfn + (sg[i].length >> PAGE_SHIFT);
447 full_page = (sg[i].length & (PAGE_SIZE - 1)) == 0;
449 if ((pfn == pfn_cur_next) && full_page_cur)
452 if ((pfn_next == pfn_cur) && full_page)
460 TRACE_MEM("SG segment %d will be tail merged with segment %d", cur, i);
461 sg[i].length += len_cur;
467 TRACE_MEM("SG segment %d will be head merged with segment %d", cur, i);
468 sg_assign_page(&sg[i], sg_page(&sg[cur]));
469 sg[i].length += len_cur;
475 static int sgv_check_tail_clustering(struct scatterlist *sg, int cur, int hint)
478 unsigned long pfn_cur = page_to_pfn(sg_page(&sg[cur]));
479 int len_cur = sg[cur].length;
481 unsigned long pfn_prev;
485 if (page >= highmem_start_page) {
486 TRACE_MEM("%s", "HIGHMEM page allocated, no clustering")
492 TRACE_MEM("pfn_cur %ld, pfn_cur_next %ld, len_cur %d, full_page_cur %d",
493 pfn_cur, pfn_cur_next, len_cur, full_page_cur);
500 pfn_prev = page_to_pfn(sg_page(&sg[prev])) +
501 (sg[prev].length >> PAGE_SHIFT);
502 full_page = (sg[prev].length & (PAGE_SIZE - 1)) == 0;
504 if ((pfn_prev == pfn_cur) && full_page) {
505 TRACE_MEM("SG segment %d will be tail merged with segment %d",
507 sg[prev].length += len_cur;
516 static void sgv_free_sys_sg_entries(struct scatterlist *sg, int sg_count,
521 TRACE_MEM("sg=%p, sg_count=%d", sg, sg_count);
523 for (i = 0; i < sg_count; i++) {
524 struct page *p = sg_page(&sg[i]);
525 int len = sg[i].length;
527 (len >> PAGE_SHIFT) + ((len & ~PAGE_MASK) != 0);
529 TRACE_MEM("page %lx, len %d, pages %d",
530 (unsigned long)p, len, pages);
536 * __free_pages() doesn't like freeing pages with not that order with
537 * which they were allocated, so disable this small optimization.
541 while (((1 << order) << PAGE_SHIFT) < len)
546 TRACE_MEM("free_pages(): order %d, page %lx",
547 order, (unsigned long)p);
549 __free_pages(p, order);
557 static struct page *sgv_alloc_sys_pages(struct scatterlist *sg,
558 gfp_t gfp_mask, void *priv)
560 struct page *page = alloc_pages(gfp_mask, 0);
562 sg_set_page(sg, page, PAGE_SIZE, 0);
563 TRACE_MEM("page=%p, sg=%p, priv=%p", page, sg, priv);
565 TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of "
571 static int sgv_alloc_sg_entries(struct scatterlist *sg, int pages,
572 gfp_t gfp_mask, enum sgv_clustering_types clustering_type,
573 struct trans_tbl_ent *trans_tbl,
574 const struct sgv_pool_alloc_fns *alloc_fns, void *priv)
580 TRACE_MEM("pages=%d, clustering_type=%d", pages, clustering_type);
583 gfp_mask |= __GFP_COLD;
585 #ifdef CONFIG_SCST_STRICT_SECURITY
586 gfp_mask |= __GFP_ZERO;
589 for (pg = 0; pg < pages; pg++) {
591 #ifdef CONFIG_SCST_DEBUG_OOM
592 if (((gfp_mask & __GFP_NOFAIL) != __GFP_NOFAIL) &&
593 ((scst_random() % 10000) == 55))
597 rc = alloc_fns->alloc_pages_fn(&sg[sg_count], gfp_mask,
603 * This code allows compiler to see full body of the clustering
604 * functions and gives it a chance to generate better code.
605 * At least, the resulting code is smaller, comparing to
606 * calling them using a function pointer.
608 if (clustering_type == sgv_full_clustering)
609 merged = sgv_check_full_clustering(sg, sg_count, merged);
610 else if (clustering_type == sgv_tail_clustering)
611 merged = sgv_check_tail_clustering(sg, sg_count, merged);
618 TRACE_MEM("pg=%d, merged=%d, sg_count=%d", pg, merged,
622 if ((clustering_type != sgv_no_clustering) && (trans_tbl != NULL)) {
624 for (i = 0; i < pages; i++) {
625 int n = (sg[i].length >> PAGE_SHIFT) +
626 ((sg[i].length & ~PAGE_MASK) != 0);
627 trans_tbl[i].pg_count = pg;
628 for (j = 0; j < n; j++)
629 trans_tbl[pg++].sg_num = i+1;
630 TRACE_MEM("i=%d, n=%d, pg_count=%d", i, n,
631 trans_tbl[i].pg_count);
636 TRACE_MEM("sg_count=%d", sg_count);
640 alloc_fns->free_pages_fn(sg, sg_count, priv);
645 static int sgv_alloc_arrays(struct sgv_pool_obj *obj,
646 int pages_to_alloc, gfp_t gfp_mask)
653 sz = pages_to_alloc * sizeof(obj->sg_entries[0]);
655 obj->sg_entries = kmalloc(sz, gfp_mask);
656 if (unlikely(obj->sg_entries == NULL)) {
657 TRACE(TRACE_OUT_OF_MEM, "Allocation of sgv_pool_obj "
658 "SG vector failed (size %d)", sz);
663 sg_init_table(obj->sg_entries, pages_to_alloc);
665 if (sgv_pool_clustered(obj->owner_pool)) {
666 if (pages_to_alloc <= sgv_max_trans_pages) {
668 (struct trans_tbl_ent *)obj->sg_entries_data;
670 * No need to clear trans_tbl, if needed, it will be
671 * fully rewritten in sgv_alloc_sg_entries()
674 tsz = pages_to_alloc * sizeof(obj->trans_tbl[0]);
675 obj->trans_tbl = kzalloc(tsz, gfp_mask);
676 if (unlikely(obj->trans_tbl == NULL)) {
677 TRACE(TRACE_OUT_OF_MEM, "Allocation of "
678 "trans_tbl failed (size %d)", tsz);
685 TRACE_MEM("pages_to_alloc %d, sz %d, tsz %d, obj %p, sg_entries %p, "
686 "trans_tbl %p", pages_to_alloc, sz, tsz, obj, obj->sg_entries,
694 kfree(obj->sg_entries);
695 obj->sg_entries = NULL;
699 static struct sgv_pool_obj *sgv_get_obj(struct sgv_pool *pool, int cache_num,
700 int pages, gfp_t gfp_mask, bool get_new)
702 struct sgv_pool_obj *obj;
704 spin_lock_bh(&pool->sgv_pool_lock);
706 if (unlikely(get_new)) {
707 /* Used only for buffers preallocation */
711 if (likely(!list_empty(&pool->recycling_lists[cache_num]))) {
712 obj = list_entry(pool->recycling_lists[cache_num].next,
713 struct sgv_pool_obj, recycling_list_entry);
715 list_del(&obj->sorted_recycling_list_entry);
716 list_del(&obj->recycling_list_entry);
718 pool->inactive_cached_pages -= pages;
720 spin_unlock_bh(&pool->sgv_pool_lock);
725 if (pool->cached_entries == 0) {
726 TRACE_MEM("Adding pool %p to the active list", pool);
727 spin_lock_bh(&sgv_pools_lock);
728 list_add_tail(&pool->sgv_active_pools_list_entry,
729 &sgv_active_pools_list);
730 spin_unlock_bh(&sgv_pools_lock);
733 pool->cached_entries++;
734 pool->cached_pages += pages;
736 spin_unlock_bh(&pool->sgv_pool_lock);
738 TRACE_MEM("New cached entries %d (pool %p)", pool->cached_entries,
741 obj = kmem_cache_alloc(pool->caches[cache_num],
742 gfp_mask & ~(__GFP_HIGHMEM|GFP_DMA));
744 memset(obj, 0, sizeof(*obj));
745 obj->cache_num = cache_num;
747 obj->owner_pool = pool;
749 spin_lock_bh(&pool->sgv_pool_lock);
750 sgv_dec_cached_entries(pool, pages);
751 spin_unlock_bh(&pool->sgv_pool_lock);
758 static void sgv_put_obj(struct sgv_pool_obj *obj)
760 struct sgv_pool *pool = obj->owner_pool;
761 struct list_head *entry;
762 struct list_head *list = &pool->recycling_lists[obj->cache_num];
763 int pages = obj->pages;
765 spin_lock_bh(&pool->sgv_pool_lock);
767 TRACE_MEM("sgv %p, cache num %d, pages %d, sg_count %d", obj,
768 obj->cache_num, pages, obj->sg_count);
770 if (sgv_pool_clustered(pool)) {
771 /* Make objects with less entries more preferred */
772 __list_for_each(entry, list) {
773 struct sgv_pool_obj *tmp = list_entry(entry,
774 struct sgv_pool_obj, recycling_list_entry);
776 TRACE_MEM("tmp %p, cache num %d, pages %d, sg_count %d",
777 tmp, tmp->cache_num, tmp->pages, tmp->sg_count);
779 if (obj->sg_count <= tmp->sg_count)
786 TRACE_MEM("Adding in %p (list %p)", entry, list);
787 list_add(&obj->recycling_list_entry, entry);
789 list_add_tail(&obj->sorted_recycling_list_entry,
790 &pool->sorted_recycling_list);
792 obj->time_stamp = jiffies;
794 pool->inactive_cached_pages += pages;
796 if (!pool->purge_work_scheduled) {
797 TRACE_MEM("Scheduling purge work for pool %p", pool);
798 pool->purge_work_scheduled = true;
799 schedule_delayed_work(&pool->sgv_purge_work,
800 pool->purge_interval);
803 spin_unlock_bh(&pool->sgv_pool_lock);
808 static int sgv_hiwmk_check(int pages_to_alloc)
811 int pages = pages_to_alloc;
813 pages += atomic_read(&sgv_pages_total);
815 if (unlikely(pages > sgv_hi_wmk)) {
817 atomic_inc(&sgv_releases_on_hiwmk);
819 pages = __sgv_shrink(pages, 0);
821 TRACE(TRACE_OUT_OF_MEM, "Requested amount of "
822 "memory (%d pages) for being executed "
823 "commands together with the already "
824 "allocated memory exceeds the allowed "
825 "maximum %d. Should you increase "
826 "scst_max_cmd_mem?", pages_to_alloc,
828 atomic_inc(&sgv_releases_on_hiwmk_failed);
834 atomic_add(pages_to_alloc, &sgv_pages_total);
837 TRACE_MEM("pages_to_alloc %d, new total %d", pages_to_alloc,
838 atomic_read(&sgv_pages_total));
844 static void sgv_hiwmk_uncheck(int pages)
846 atomic_sub(pages, &sgv_pages_total);
847 TRACE_MEM("pages %d, new total %d", pages,
848 atomic_read(&sgv_pages_total));
853 static bool sgv_check_allowed_mem(struct scst_mem_lim *mem_lim, int pages)
858 alloced = atomic_add_return(pages, &mem_lim->alloced_pages);
859 if (unlikely(alloced > mem_lim->max_allowed_pages)) {
860 TRACE(TRACE_OUT_OF_MEM, "Requested amount of memory "
861 "(%d pages) for being executed commands on a device "
862 "together with the already allocated memory exceeds "
863 "the allowed maximum %d. Should you increase "
864 "scst_max_dev_cmd_mem?", pages,
865 mem_lim->max_allowed_pages);
866 atomic_sub(pages, &mem_lim->alloced_pages);
870 TRACE_MEM("mem_lim %p, pages %d, res %d, new alloced %d", mem_lim,
871 pages, res, atomic_read(&mem_lim->alloced_pages));
877 static void sgv_uncheck_allowed_mem(struct scst_mem_lim *mem_lim, int pages)
879 atomic_sub(pages, &mem_lim->alloced_pages);
881 TRACE_MEM("mem_lim %p, pages %d, new alloced %d", mem_lim,
882 pages, atomic_read(&mem_lim->alloced_pages));
886 struct scatterlist *sgv_pool_alloc(struct sgv_pool *pool, unsigned int size,
887 gfp_t gfp_mask, int flags, int *count,
888 struct sgv_pool_obj **sgv, struct scst_mem_lim *mem_lim, void *priv)
890 struct sgv_pool_obj *obj;
891 int cache_num, pages, cnt;
892 struct scatterlist *res = NULL;
894 int no_cached = flags & SGV_POOL_ALLOC_NO_CACHED;
895 bool allowed_mem_checked = false, hiwmk_checked = false;
899 if (unlikely(size == 0))
902 EXTRACHECKS_BUG_ON((gfp_mask & __GFP_NOFAIL) == __GFP_NOFAIL);
904 pages = ((size + PAGE_SIZE - 1) >> PAGE_SHIFT);
905 if (pool->single_alloc_pages == 0) {
906 int pages_order = get_order(size);
907 cache_num = pages_order;
908 pages_to_alloc = (1 << pages_order);
911 pages_to_alloc = max(pool->single_alloc_pages, pages);
914 TRACE_MEM("size=%d, pages=%d, pages_to_alloc=%d, cache num=%d, "
915 "flags=%x, no_cached=%d, *sgv=%p", size, pages,
916 pages_to_alloc, cache_num, flags, no_cached, *sgv);
921 TRACE_MEM("Supplied obj %p, cache num %d", obj, obj->cache_num);
923 EXTRACHECKS_BUG_ON(obj->sg_count != 0);
925 if (unlikely(!sgv_check_allowed_mem(mem_lim, pages_to_alloc)))
926 goto out_fail_free_sg_entries;
927 allowed_mem_checked = true;
929 if (unlikely(sgv_hiwmk_check(pages_to_alloc) != 0))
930 goto out_fail_free_sg_entries;
931 hiwmk_checked = true;
932 } else if ((pages_to_alloc <= pool->max_cached_pages) && !no_cached) {
933 if (unlikely(!sgv_check_allowed_mem(mem_lim, pages_to_alloc)))
935 allowed_mem_checked = true;
937 obj = sgv_get_obj(pool, cache_num, pages_to_alloc, gfp_mask,
938 flags & SGV_POOL_ALLOC_GET_NEW);
939 if (unlikely(obj == NULL)) {
940 TRACE(TRACE_OUT_OF_MEM, "Allocation of "
941 "sgv_pool_obj failed (size %d)", size);
945 if (obj->sg_count != 0) {
946 TRACE_MEM("Cached obj %p", obj);
947 atomic_inc(&pool->cache_acc[cache_num].hit_alloc);
951 if (flags & SGV_POOL_NO_ALLOC_ON_CACHE_MISS) {
952 if (!(flags & SGV_POOL_RETURN_OBJ_ON_ALLOC_FAIL))
956 TRACE_MEM("Brand new obj %p", obj);
958 if (pages_to_alloc <= sgv_max_local_pages) {
959 obj->sg_entries = obj->sg_entries_data;
960 sg_init_table(obj->sg_entries, pages_to_alloc);
961 TRACE_MEM("sg_entries %p", obj->sg_entries);
962 if (sgv_pool_clustered(pool)) {
963 obj->trans_tbl = (struct trans_tbl_ent *)
964 (obj->sg_entries + pages_to_alloc);
965 TRACE_MEM("trans_tbl %p", obj->trans_tbl);
967 * No need to clear trans_tbl, if needed, it
968 * will be fully rewritten in
969 * sgv_alloc_sg_entries().
973 if (unlikely(sgv_alloc_arrays(obj, pages_to_alloc,
978 if ((flags & SGV_POOL_NO_ALLOC_ON_CACHE_MISS) &&
979 (flags & SGV_POOL_RETURN_OBJ_ON_ALLOC_FAIL))
982 obj->allocator_priv = priv;
984 if (unlikely(sgv_hiwmk_check(pages_to_alloc) != 0))
985 goto out_fail_free_sg_entries;
986 hiwmk_checked = true;
990 pages_to_alloc = pages;
992 if (unlikely(!sgv_check_allowed_mem(mem_lim, pages_to_alloc)))
994 allowed_mem_checked = true;
996 if (flags & SGV_POOL_NO_ALLOC_ON_CACHE_MISS)
999 sz = sizeof(*obj) + pages * sizeof(obj->sg_entries[0]);
1001 obj = kmalloc(sz, gfp_mask);
1002 if (unlikely(obj == NULL)) {
1003 TRACE(TRACE_OUT_OF_MEM, "Allocation of "
1004 "sgv_pool_obj failed (size %d)", size);
1007 memset(obj, 0, sizeof(*obj));
1009 obj->owner_pool = pool;
1011 obj->cache_num = cache_num;
1012 obj->pages = pages_to_alloc;
1013 obj->allocator_priv = priv;
1015 obj->sg_entries = obj->sg_entries_data;
1016 sg_init_table(obj->sg_entries, pages);
1018 if (unlikely(sgv_hiwmk_check(pages_to_alloc) != 0))
1019 goto out_fail_free_sg_entries;
1020 hiwmk_checked = true;
1022 TRACE_MEM("Big or no_cached obj %p (size %d)", obj, sz);
1025 obj->sg_count = sgv_alloc_sg_entries(obj->sg_entries,
1026 pages_to_alloc, gfp_mask, pool->clustering_type,
1027 obj->trans_tbl, &pool->alloc_fns, priv);
1028 if (unlikely(obj->sg_count <= 0)) {
1030 if ((flags & SGV_POOL_RETURN_OBJ_ON_ALLOC_FAIL) &&
1034 goto out_fail_free_sg_entries;
1037 if (cache_num >= 0) {
1038 atomic_add(pages_to_alloc - obj->sg_count,
1039 &pool->cache_acc[cache_num].merged);
1042 atomic_add(pages_to_alloc,
1043 &pool->other_pages);
1044 atomic_add(pages_to_alloc - obj->sg_count,
1045 &pool->other_merged);
1047 atomic_add(pages_to_alloc,
1049 atomic_add(pages_to_alloc - obj->sg_count,
1055 if (cache_num >= 0) {
1057 atomic_inc(&pool->cache_acc[cache_num].total_alloc);
1058 if (sgv_pool_clustered(pool))
1059 cnt = obj->trans_tbl[pages-1].sg_num;
1064 obj->orig_length = obj->sg_entries[sg].length;
1065 if (sgv_pool_clustered(pool)) {
1066 obj->sg_entries[sg].length =
1067 (pages - obj->trans_tbl[sg].pg_count) << PAGE_SHIFT;
1070 cnt = obj->sg_count;
1072 atomic_inc(&pool->other_alloc);
1074 atomic_inc(&pool->big_alloc);
1078 res = obj->sg_entries;
1081 if (size & ~PAGE_MASK)
1082 obj->sg_entries[cnt-1].length -=
1083 PAGE_SIZE - (size & ~PAGE_MASK);
1085 TRACE_MEM("obj=%p, sg_entries %p (size=%d, pages=%d, sg_count=%d, "
1086 "count=%d, last_len=%d)", obj, obj->sg_entries, size, pages,
1087 obj->sg_count, *count, obj->sg_entries[obj->orig_sg].length);
1090 TRACE_EXIT_HRES(res);
1094 obj->allocator_priv = priv;
1095 obj->owner_pool = pool;
1099 TRACE_MEM("Returning failed obj %p (count %d)", obj, *count);
1102 *count = pages_to_alloc;
1106 out_fail_free_sg_entries:
1107 if (obj->sg_entries != obj->sg_entries_data) {
1108 if (obj->trans_tbl !=
1109 (struct trans_tbl_ent *)obj->sg_entries_data) {
1110 /* kfree() handles NULL parameter */
1111 kfree(obj->trans_tbl);
1112 obj->trans_tbl = NULL;
1114 kfree(obj->sg_entries);
1115 obj->sg_entries = NULL;
1119 if (cache_num >= 0) {
1120 spin_lock_bh(&pool->sgv_pool_lock);
1121 sgv_dec_cached_entries(pool, pages_to_alloc);
1122 spin_unlock_bh(&pool->sgv_pool_lock);
1124 kmem_cache_free(pool->caches[obj->cache_num], obj);
1132 TRACE_MEM("%s", "Allocation failed");
1136 sgv_hiwmk_uncheck(pages_to_alloc);
1137 if (allowed_mem_checked)
1138 sgv_uncheck_allowed_mem(mem_lim, pages_to_alloc);
1141 EXPORT_SYMBOL(sgv_pool_alloc);
1143 void *sgv_get_priv(struct sgv_pool_obj *obj)
1145 return obj->allocator_priv;
1147 EXPORT_SYMBOL(sgv_get_priv);
1149 void sgv_pool_free(struct sgv_pool_obj *obj, struct scst_mem_lim *mem_lim)
1151 int pages = (obj->sg_count != 0) ? obj->pages : 0;
1153 TRACE_MEM("Freeing obj %p, cache num %d, pages %d, sg_entries %p, "
1154 "sg_count %d, allocator_priv %p", obj, obj->cache_num, pages,
1155 obj->sg_entries, obj->sg_count, obj->allocator_priv);
1156 if (obj->cache_num >= 0) {
1157 obj->sg_entries[obj->orig_sg].length = obj->orig_length;
1160 obj->owner_pool->alloc_fns.free_pages_fn(obj->sg_entries,
1161 obj->sg_count, obj->allocator_priv);
1163 sgv_hiwmk_uncheck(pages);
1166 sgv_uncheck_allowed_mem(mem_lim, pages);
1169 EXPORT_SYMBOL(sgv_pool_free);
1171 struct scatterlist *scst_alloc(int size, gfp_t gfp_mask, int *count)
1173 struct scatterlist *res;
1174 int pages = (size >> PAGE_SHIFT) + ((size & ~PAGE_MASK) != 0);
1175 struct sgv_pool_alloc_fns sys_alloc_fns = {
1176 sgv_alloc_sys_pages, sgv_free_sys_sg_entries };
1177 int no_fail = ((gfp_mask & __GFP_NOFAIL) == __GFP_NOFAIL);
1181 atomic_inc(&sgv_other_total_alloc);
1183 if (unlikely(sgv_hiwmk_check(pages) != 0)) {
1189 * Update active_pages_total since alloc can't fail.
1190 * If it wasn't updated then the counter would cross 0
1193 sgv_hiwmk_uncheck(-pages);
1197 res = kmalloc(pages*sizeof(*res), gfp_mask);
1199 TRACE(TRACE_OUT_OF_MEM, "Unable to allocate sg for %d pages",
1204 sg_init_table(res, pages);
1207 * If we allow use clustering here, we will have troubles in
1208 * scst_free() to figure out how many pages are in the SG vector.
1209 * So, always don't use clustering.
1211 *count = sgv_alloc_sg_entries(res, pages, gfp_mask, sgv_no_clustering,
1212 NULL, &sys_alloc_fns, NULL);
1217 TRACE_MEM("Alloced sg %p (count %d) \"no fail\" %d", res, *count, no_fail);
1219 TRACE_EXIT_HRES(res);
1228 sgv_hiwmk_uncheck(pages);
1231 EXPORT_SYMBOL(scst_alloc);
1233 void scst_free(struct scatterlist *sg, int count)
1235 TRACE_MEM("Freeing sg=%p", sg);
1237 sgv_hiwmk_uncheck(count);
1239 sgv_free_sys_sg_entries(sg, count, NULL);
1243 EXPORT_SYMBOL(scst_free);
1245 /* Must be called under sgv_pools_mutex */
1246 static void sgv_pool_init_cache(struct sgv_pool *pool, int cache_num)
1250 struct sgv_pool_obj *obj;
1252 atomic_set(&pool->cache_acc[cache_num].total_alloc, 0);
1253 atomic_set(&pool->cache_acc[cache_num].hit_alloc, 0);
1254 atomic_set(&pool->cache_acc[cache_num].merged, 0);
1256 if (pool->single_alloc_pages == 0)
1257 pages = 1 << cache_num;
1259 pages = pool->single_alloc_pages;
1261 if (pages <= sgv_max_local_pages) {
1262 size = sizeof(*obj) + pages *
1263 (sizeof(obj->sg_entries[0]) +
1264 ((pool->clustering_type != sgv_no_clustering) ?
1265 sizeof(obj->trans_tbl[0]) : 0));
1266 } else if (pages <= sgv_max_trans_pages) {
1268 * sg_entries is allocated outside object,
1269 * but trans_tbl is still embedded.
1271 size = sizeof(*obj) + pages *
1272 (((pool->clustering_type != sgv_no_clustering) ?
1273 sizeof(obj->trans_tbl[0]) : 0));
1275 size = sizeof(*obj);
1276 /* both sgv and trans_tbl are kmalloc'ed() */
1279 TRACE_MEM("pages=%d, size=%d", pages, size);
1281 scnprintf(pool->cache_names[cache_num],
1282 sizeof(pool->cache_names[cache_num]),
1283 "%s-%uK", pool->name, (pages << PAGE_SHIFT) >> 10);
1284 pool->caches[cache_num] = kmem_cache_create(
1285 pool->cache_names[cache_num], size, 0, SCST_SLAB_FLAGS, NULL
1286 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23))
1294 /* Must be called under sgv_pools_mutex */
1295 static int sgv_pool_init(struct sgv_pool *pool, const char *name,
1296 enum sgv_clustering_types clustering_type, int single_alloc_pages,
1304 if (single_alloc_pages < 0) {
1305 PRINT_ERROR("Wrong single_alloc_pages value %d",
1306 single_alloc_pages);
1311 memset(pool, 0, sizeof(*pool));
1313 atomic_set(&pool->big_alloc, 0);
1314 atomic_set(&pool->big_pages, 0);
1315 atomic_set(&pool->big_merged, 0);
1316 atomic_set(&pool->other_alloc, 0);
1317 atomic_set(&pool->other_pages, 0);
1318 atomic_set(&pool->other_merged, 0);
1320 pool->clustering_type = clustering_type;
1321 pool->single_alloc_pages = single_alloc_pages;
1322 if (purge_interval != 0) {
1323 pool->purge_interval = purge_interval;
1324 if (purge_interval < 0) {
1325 /* Let's pretend that it's always scheduled */
1326 pool->purge_work_scheduled = 1;
1329 pool->purge_interval = SGV_DEFAULT_PURGE_INTERVAL;
1330 if (single_alloc_pages == 0) {
1331 pool->max_caches = SGV_POOL_ELEMENTS;
1332 pool->max_cached_pages = 1 << SGV_POOL_ELEMENTS;
1334 pool->max_caches = 1;
1335 pool->max_cached_pages = single_alloc_pages;
1337 pool->alloc_fns.alloc_pages_fn = sgv_alloc_sys_pages;
1338 pool->alloc_fns.free_pages_fn = sgv_free_sys_sg_entries;
1340 TRACE_MEM("name %s, sizeof(*obj)=%zd, clustering_type=%d, "
1341 "single_alloc_pages=%d, max_caches=%d, max_cached_pages=%d",
1342 name, sizeof(struct sgv_pool_obj), clustering_type,
1343 single_alloc_pages, pool->max_caches, pool->max_cached_pages);
1345 strncpy(pool->name, name, sizeof(pool->name)-1);
1346 pool->name[sizeof(pool->name)-1] = '\0';
1348 pool->owner_mm = current->mm;
1350 for (i = 0; i < pool->max_caches; i++) {
1351 sgv_pool_init_cache(pool, i);
1352 if (pool->caches[i] == NULL) {
1353 TRACE(TRACE_OUT_OF_MEM, "Allocation of sgv_pool "
1354 "cache %s(%d) failed", name, i);
1359 atomic_set(&pool->sgv_pool_ref, 1);
1360 spin_lock_init(&pool->sgv_pool_lock);
1361 INIT_LIST_HEAD(&pool->sorted_recycling_list);
1362 for (i = 0; i < pool->max_caches; i++)
1363 INIT_LIST_HEAD(&pool->recycling_lists[i]);
1365 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20))
1366 INIT_DELAYED_WORK(&pool->sgv_purge_work,
1367 (void (*)(struct work_struct *))sgv_purge_work_fn);
1369 INIT_WORK(&pool->sgv_purge_work, sgv_purge_work_fn, pool);
1372 spin_lock_bh(&sgv_pools_lock);
1373 list_add_tail(&pool->sgv_pools_list_entry, &sgv_pools_list);
1374 spin_unlock_bh(&sgv_pools_lock);
1379 TRACE_EXIT_RES(res);
1383 for (i = 0; i < pool->max_caches; i++) {
1384 if (pool->caches[i]) {
1385 kmem_cache_destroy(pool->caches[i]);
1386 pool->caches[i] = NULL;
1393 static void sgv_evaluate_local_max_pages(void)
1395 int space4sgv_ttbl = PAGE_SIZE - sizeof(struct sgv_pool_obj);
1397 sgv_max_local_pages = space4sgv_ttbl /
1398 (sizeof(struct trans_tbl_ent) + sizeof(struct scatterlist));
1400 sgv_max_trans_pages = space4sgv_ttbl / sizeof(struct trans_tbl_ent);
1402 TRACE_MEM("sgv_max_local_pages %d, sgv_max_trans_pages %d",
1403 sgv_max_local_pages, sgv_max_trans_pages);
1407 void sgv_pool_flush(struct sgv_pool *pool)
1413 for (i = 0; i < pool->max_caches; i++) {
1414 struct sgv_pool_obj *obj;
1416 spin_lock_bh(&pool->sgv_pool_lock);
1418 while (!list_empty(&pool->recycling_lists[i])) {
1419 obj = list_entry(pool->recycling_lists[i].next,
1420 struct sgv_pool_obj, recycling_list_entry);
1422 __sgv_purge_from_cache(obj);
1424 spin_unlock_bh(&pool->sgv_pool_lock);
1426 EXTRACHECKS_BUG_ON(obj->owner_pool != pool);
1427 sgv_dtor_and_free(obj);
1429 spin_lock_bh(&pool->sgv_pool_lock);
1431 spin_unlock_bh(&pool->sgv_pool_lock);
1437 EXPORT_SYMBOL(sgv_pool_flush);
1439 static void sgv_pool_deinit_put(struct sgv_pool *pool)
1445 cancel_delayed_work_sync(&pool->sgv_purge_work);
1447 sgv_pool_flush(pool);
1449 mutex_lock(&sgv_pools_mutex);
1450 spin_lock_bh(&sgv_pools_lock);
1451 list_del(&pool->sgv_pools_list_entry);
1452 spin_unlock_bh(&sgv_pools_lock);
1453 mutex_unlock(&sgv_pools_mutex);
1455 for (i = 0; i < pool->max_caches; i++) {
1456 if (pool->caches[i])
1457 kmem_cache_destroy(pool->caches[i]);
1458 pool->caches[i] = NULL;
1461 scst_sgv_sysfs_put(pool);
1463 /* pool can be dead here */
1469 void sgv_pool_set_allocator(struct sgv_pool *pool,
1470 struct page *(*alloc_pages_fn)(struct scatterlist *, gfp_t, void *),
1471 void (*free_pages_fn)(struct scatterlist *, int, void *))
1473 pool->alloc_fns.alloc_pages_fn = alloc_pages_fn;
1474 pool->alloc_fns.free_pages_fn = free_pages_fn;
1477 EXPORT_SYMBOL(sgv_pool_set_allocator);
1479 struct sgv_pool *sgv_pool_create(const char *name,
1480 enum sgv_clustering_types clustering_type,
1481 int single_alloc_pages, bool shared, int purge_interval)
1483 struct sgv_pool *pool;
1488 mutex_lock(&sgv_pools_mutex);
1489 list_for_each_entry(pool, &sgv_pools_list, sgv_pools_list_entry) {
1490 if (strcmp(pool->name, name) == 0) {
1492 if (pool->owner_mm != current->mm) {
1493 PRINT_ERROR("Attempt of a shared use "
1494 "of SGV pool %s with "
1495 "different MM", name);
1496 goto out_err_unlock;
1501 PRINT_ERROR("SGV pool %s already exists", name);
1502 goto out_err_unlock;
1507 pool = kzalloc(sizeof(*pool), GFP_KERNEL);
1509 TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of sgv_pool failed");
1513 rc = sgv_pool_init(pool, name, clustering_type, single_alloc_pages,
1516 goto out_free_unlock;
1518 rc = scst_create_sgv_sysfs(pool);
1520 goto out_err_unlock_put;
1523 mutex_unlock(&sgv_pools_mutex);
1525 TRACE_EXIT_RES(pool != NULL);
1536 mutex_unlock(&sgv_pools_mutex);
1537 sgv_pool_deinit_put(pool);
1538 goto out_err_unlock;
1540 EXPORT_SYMBOL(sgv_pool_create);
1542 void sgv_pool_destroy(struct sgv_pool *pool)
1552 void sgv_pool_get(struct sgv_pool *pool)
1554 atomic_inc(&pool->sgv_pool_ref);
1555 TRACE_MEM("Incrementing sgv pool %p ref (new value %d)",
1556 pool, atomic_read(&pool->sgv_pool_ref));
1559 EXPORT_SYMBOL(sgv_pool_get);
1561 void sgv_pool_put(struct sgv_pool *pool)
1563 TRACE_MEM("Decrementing sgv pool %p ref (new value %d)",
1564 pool, atomic_read(&pool->sgv_pool_ref)-1);
1565 if (atomic_dec_and_test(&pool->sgv_pool_ref))
1566 sgv_pool_deinit_put(pool);
1569 EXPORT_SYMBOL(sgv_pool_put);
1571 void sgv_pool_del(struct sgv_pool *pool)
1580 EXPORT_SYMBOL(sgv_pool_del);
1582 /* Both parameters in pages */
1583 int scst_sgv_pools_init(unsigned long mem_hwmark, unsigned long mem_lwmark)
1589 sgv_hi_wmk = mem_hwmark;
1590 sgv_lo_wmk = mem_lwmark;
1592 sgv_evaluate_local_max_pages();
1594 sgv_norm_pool = sgv_pool_create("sgv", sgv_no_clustering, 0, false, 0);
1595 if (sgv_norm_pool == NULL)
1598 sgv_norm_clust_pool = sgv_pool_create("sgv-clust",
1599 sgv_full_clustering, 0, false, 0);
1600 if (sgv_norm_clust_pool == NULL)
1603 sgv_dma_pool = sgv_pool_create("sgv-dma", sgv_no_clustering, 0,
1605 if (sgv_dma_pool == NULL)
1606 goto out_free_clust;
1608 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23))
1609 sgv_shrinker = set_shrinker(DEFAULT_SEEKS, sgv_shrink);
1611 sgv_shrinker.shrink = sgv_shrink;
1612 sgv_shrinker.seeks = DEFAULT_SEEKS;
1613 register_shrinker(&sgv_shrinker);
1617 TRACE_EXIT_RES(res);
1621 sgv_pool_deinit_put(sgv_norm_clust_pool);
1624 sgv_pool_deinit_put(sgv_norm_pool);
1631 void scst_sgv_pools_deinit(void)
1635 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23))
1636 remove_shrinker(sgv_shrinker);
1638 unregister_shrinker(&sgv_shrinker);
1641 sgv_pool_deinit_put(sgv_dma_pool);
1642 sgv_pool_deinit_put(sgv_norm_pool);
1643 sgv_pool_deinit_put(sgv_norm_clust_pool);
1645 flush_scheduled_work();
1651 #ifdef CONFIG_SCST_PROC
1653 static void sgv_do_proc_read(struct seq_file *seq, const struct sgv_pool *pool)
1655 int i, total = 0, hit = 0, merged = 0, allocated = 0;
1658 for (i = 0; i < pool->max_caches; i++) {
1661 hit += atomic_read(&pool->cache_acc[i].hit_alloc);
1662 total += atomic_read(&pool->cache_acc[i].total_alloc);
1664 t = atomic_read(&pool->cache_acc[i].total_alloc) -
1665 atomic_read(&pool->cache_acc[i].hit_alloc);
1666 if (pool->single_alloc_pages == 0)
1667 allocated += t * (1 << i);
1669 allocated += t * pool->single_alloc_pages;
1670 merged += atomic_read(&pool->cache_acc[i].merged);
1673 seq_printf(seq, "\n%-30s %-11d %-11d %-11d %d/%d/%d\n", pool->name,
1674 hit, total, (allocated != 0) ? merged*100/allocated : 0,
1675 pool->cached_pages, pool->inactive_cached_pages,
1676 pool->cached_entries);
1678 for (i = 0; i < pool->max_caches; i++) {
1679 int t = atomic_read(&pool->cache_acc[i].total_alloc) -
1680 atomic_read(&pool->cache_acc[i].hit_alloc);
1681 if (pool->single_alloc_pages == 0)
1682 allocated = t * (1 << i);
1684 allocated = t * pool->single_alloc_pages;
1685 merged = atomic_read(&pool->cache_acc[i].merged);
1687 seq_printf(seq, " %-28s %-11d %-11d %d\n",
1688 pool->cache_names[i],
1689 atomic_read(&pool->cache_acc[i].hit_alloc),
1690 atomic_read(&pool->cache_acc[i].total_alloc),
1691 (allocated != 0) ? merged*100/allocated : 0);
1694 allocated = atomic_read(&pool->big_pages);
1695 merged = atomic_read(&pool->big_merged);
1696 oa = atomic_read(&pool->other_pages);
1697 om = atomic_read(&pool->other_merged);
1699 seq_printf(seq, " %-40s %d/%-9d %d/%d\n", "big/other",
1700 atomic_read(&pool->big_alloc), atomic_read(&pool->other_alloc),
1701 (allocated != 0) ? merged*100/allocated : 0,
1702 (oa != 0) ? om/oa : 0);
1707 int sgv_procinfo_show(struct seq_file *seq, void *v)
1709 struct sgv_pool *pool;
1710 int inactive_pages = 0;
1714 spin_lock_bh(&sgv_pools_lock);
1715 list_for_each_entry(pool, &sgv_active_pools_list,
1716 sgv_active_pools_list_entry) {
1717 inactive_pages += pool->inactive_cached_pages;
1719 spin_unlock_bh(&sgv_pools_lock);
1721 seq_printf(seq, "%-42s %d/%d\n%-42s %d/%d\n%-42s %d/%d\n\n",
1722 "Inactive/active pages", inactive_pages,
1723 atomic_read(&sgv_pages_total) - inactive_pages,
1724 "Hi/lo watermarks [pages]", sgv_hi_wmk, sgv_lo_wmk,
1725 "Hi watermark releases/failures",
1726 atomic_read(&sgv_releases_on_hiwmk),
1727 atomic_read(&sgv_releases_on_hiwmk_failed));
1729 seq_printf(seq, "%-30s %-11s %-11s %-11s %-11s", "Name", "Hit", "Total",
1730 "% merged", "Cached (P/I/O)");
1732 mutex_lock(&sgv_pools_mutex);
1733 list_for_each_entry(pool, &sgv_pools_list, sgv_pools_list_entry) {
1734 sgv_do_proc_read(seq, pool);
1736 mutex_unlock(&sgv_pools_mutex);
1738 seq_printf(seq, "\n%-42s %-11d\n", "other",
1739 atomic_read(&sgv_other_total_alloc));
1745 #else /* CONFIG_SCST_PROC */
1747 ssize_t sgv_sysfs_stat_show(struct kobject *kobj,
1748 struct kobj_attribute *attr, char *buf)
1750 struct sgv_pool *pool;
1751 int i, total = 0, hit = 0, merged = 0, allocated = 0;
1754 pool = container_of(kobj, struct sgv_pool, sgv_kobj);
1756 for (i = 0; i < SGV_POOL_ELEMENTS; i++) {
1759 hit += atomic_read(&pool->cache_acc[i].hit_alloc);
1760 total += atomic_read(&pool->cache_acc[i].total_alloc);
1762 t = atomic_read(&pool->cache_acc[i].total_alloc) -
1763 atomic_read(&pool->cache_acc[i].hit_alloc);
1764 allocated += t * (1 << i);
1765 merged += atomic_read(&pool->cache_acc[i].merged);
1768 res = sprintf(buf, "%-30s %-11s %-11s %-11s %-11s", "Name", "Hit", "Total",
1769 "% merged", "Cached (P/I/O)");
1771 res += sprintf(&buf[res], "\n%-30s %-11d %-11d %-11d %d/%d/%d\n",
1772 pool->name, hit, total,
1773 (allocated != 0) ? merged*100/allocated : 0,
1774 pool->cached_pages, pool->inactive_cached_pages,
1775 pool->cached_entries);
1777 for (i = 0; i < SGV_POOL_ELEMENTS; i++) {
1778 int t = atomic_read(&pool->cache_acc[i].total_alloc) -
1779 atomic_read(&pool->cache_acc[i].hit_alloc);
1780 allocated = t * (1 << i);
1781 merged = atomic_read(&pool->cache_acc[i].merged);
1783 res += sprintf(&buf[res], " %-28s %-11d %-11d %d\n",
1784 pool->cache_names[i],
1785 atomic_read(&pool->cache_acc[i].hit_alloc),
1786 atomic_read(&pool->cache_acc[i].total_alloc),
1787 (allocated != 0) ? merged*100/allocated : 0);
1790 allocated = atomic_read(&pool->big_pages);
1791 merged = atomic_read(&pool->big_merged);
1792 oa = atomic_read(&pool->other_pages);
1793 om = atomic_read(&pool->other_merged);
1795 res += sprintf(&buf[res], " %-40s %d/%-9d %d/%d\n", "big/other",
1796 atomic_read(&pool->big_alloc), atomic_read(&pool->other_alloc),
1797 (allocated != 0) ? merged*100/allocated : 0,
1798 (oa != 0) ? om/oa : 0);
1803 ssize_t sgv_sysfs_global_stat_show(struct kobject *kobj,
1804 struct kobj_attribute *attr, char *buf)
1806 struct sgv_pool *pool;
1807 int inactive_pages = 0, res;
1811 spin_lock_bh(&sgv_pools_lock);
1812 list_for_each_entry(pool, &sgv_active_pools_list,
1813 sgv_active_pools_list_entry) {
1814 inactive_pages += pool->inactive_cached_pages;
1816 spin_unlock_bh(&sgv_pools_lock);
1818 res = sprintf(buf, "%-42s %d/%d\n%-42s %d/%d\n%-42s %d/%d\n"
1820 "Inactive/active pages", inactive_pages,
1821 atomic_read(&sgv_pages_total) - inactive_pages,
1822 "Hi/lo watermarks [pages]", sgv_hi_wmk, sgv_lo_wmk,
1823 "Hi watermark releases/failures",
1824 atomic_read(&sgv_releases_on_hiwmk),
1825 atomic_read(&sgv_releases_on_hiwmk_failed),
1826 "Other allocs", atomic_read(&sgv_other_total_alloc));
1832 #endif /* CONFIG_SCST_PROC */