diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/block/zram/zcomp.c | 124 | ||||
-rw-r--r-- | drivers/block/zram/zcomp.h | 4 | ||||
-rw-r--r-- | drivers/block/zram/zram_drv.c | 42 | ||||
-rw-r--r-- | drivers/block/zram/zram_drv.h | 2 |
4 files changed, 167 insertions, 5 deletions
diff --git a/drivers/block/zram/zcomp.c b/drivers/block/zram/zcomp.c index 72e8071f9d73..c06f75f54718 100644 --- a/drivers/block/zram/zcomp.c +++ b/drivers/block/zram/zcomp.c | |||
@@ -24,6 +24,21 @@ struct zcomp_strm_single { | |||
24 | struct zcomp_strm *zstrm; | 24 | struct zcomp_strm *zstrm; |
25 | }; | 25 | }; |
26 | 26 | ||
27 | /* | ||
28 | * multi zcomp_strm backend | ||
29 | */ | ||
30 | struct zcomp_strm_multi { | ||
31 | /* protect strm list */ | ||
32 | spinlock_t strm_lock; | ||
33 | /* max possible number of zstrm streams */ | ||
34 | int max_strm; | ||
35 | /* number of available zstrm streams */ | ||
36 | int avail_strm; | ||
37 | /* list of available strms */ | ||
38 | struct list_head idle_strm; | ||
39 | wait_queue_head_t strm_wait; | ||
40 | }; | ||
41 | |||
27 | static struct zcomp_backend *find_backend(const char *compress) | 42 | static struct zcomp_backend *find_backend(const char *compress) |
28 | { | 43 | { |
29 | if (strncmp(compress, "lzo", 3) == 0) | 44 | if (strncmp(compress, "lzo", 3) == 0) |
@@ -62,6 +77,107 @@ static struct zcomp_strm *zcomp_strm_alloc(struct zcomp *comp) | |||
62 | return zstrm; | 77 | return zstrm; |
63 | } | 78 | } |
64 | 79 | ||
80 | /* | ||
81 | * get idle zcomp_strm or wait until other process release | ||
82 | * (zcomp_strm_release()) one for us | ||
83 | */ | ||
84 | static struct zcomp_strm *zcomp_strm_multi_find(struct zcomp *comp) | ||
85 | { | ||
86 | struct zcomp_strm_multi *zs = comp->stream; | ||
87 | struct zcomp_strm *zstrm; | ||
88 | |||
89 | while (1) { | ||
90 | spin_lock(&zs->strm_lock); | ||
91 | if (!list_empty(&zs->idle_strm)) { | ||
92 | zstrm = list_entry(zs->idle_strm.next, | ||
93 | struct zcomp_strm, list); | ||
94 | list_del(&zstrm->list); | ||
95 | spin_unlock(&zs->strm_lock); | ||
96 | return zstrm; | ||
97 | } | ||
98 | /* zstrm streams limit reached, wait for idle stream */ | ||
99 | if (zs->avail_strm >= zs->max_strm) { | ||
100 | spin_unlock(&zs->strm_lock); | ||
101 | wait_event(zs->strm_wait, !list_empty(&zs->idle_strm)); | ||
102 | continue; | ||
103 | } | ||
104 | /* allocate new zstrm stream */ | ||
105 | zs->avail_strm++; | ||
106 | spin_unlock(&zs->strm_lock); | ||
107 | |||
108 | zstrm = zcomp_strm_alloc(comp); | ||
109 | if (!zstrm) { | ||
110 | spin_lock(&zs->strm_lock); | ||
111 | zs->avail_strm--; | ||
112 | spin_unlock(&zs->strm_lock); | ||
113 | wait_event(zs->strm_wait, !list_empty(&zs->idle_strm)); | ||
114 | continue; | ||
115 | } | ||
116 | break; | ||
117 | } | ||
118 | return zstrm; | ||
119 | } | ||
120 | |||
121 | /* add stream back to idle list and wake up waiter or free the stream */ | ||
122 | static void zcomp_strm_multi_release(struct zcomp *comp, struct zcomp_strm *zstrm) | ||
123 | { | ||
124 | struct zcomp_strm_multi *zs = comp->stream; | ||
125 | |||
126 | spin_lock(&zs->strm_lock); | ||
127 | if (zs->avail_strm <= zs->max_strm) { | ||
128 | list_add(&zstrm->list, &zs->idle_strm); | ||
129 | spin_unlock(&zs->strm_lock); | ||
130 | wake_up(&zs->strm_wait); | ||
131 | return; | ||
132 | } | ||
133 | |||
134 | zs->avail_strm--; | ||
135 | spin_unlock(&zs->strm_lock); | ||
136 | zcomp_strm_free(comp, zstrm); | ||
137 | } | ||
138 | |||
139 | static void zcomp_strm_multi_destroy(struct zcomp *comp) | ||
140 | { | ||
141 | struct zcomp_strm_multi *zs = comp->stream; | ||
142 | struct zcomp_strm *zstrm; | ||
143 | |||
144 | while (!list_empty(&zs->idle_strm)) { | ||
145 | zstrm = list_entry(zs->idle_strm.next, | ||
146 | struct zcomp_strm, list); | ||
147 | list_del(&zstrm->list); | ||
148 | zcomp_strm_free(comp, zstrm); | ||
149 | } | ||
150 | kfree(zs); | ||
151 | } | ||
152 | |||
153 | static int zcomp_strm_multi_create(struct zcomp *comp, int max_strm) | ||
154 | { | ||
155 | struct zcomp_strm *zstrm; | ||
156 | struct zcomp_strm_multi *zs; | ||
157 | |||
158 | comp->destroy = zcomp_strm_multi_destroy; | ||
159 | comp->strm_find = zcomp_strm_multi_find; | ||
160 | comp->strm_release = zcomp_strm_multi_release; | ||
161 | zs = kmalloc(sizeof(struct zcomp_strm_multi), GFP_KERNEL); | ||
162 | if (!zs) | ||
163 | return -ENOMEM; | ||
164 | |||
165 | comp->stream = zs; | ||
166 | spin_lock_init(&zs->strm_lock); | ||
167 | INIT_LIST_HEAD(&zs->idle_strm); | ||
168 | init_waitqueue_head(&zs->strm_wait); | ||
169 | zs->max_strm = max_strm; | ||
170 | zs->avail_strm = 1; | ||
171 | |||
172 | zstrm = zcomp_strm_alloc(comp); | ||
173 | if (!zstrm) { | ||
174 | kfree(zs); | ||
175 | return -ENOMEM; | ||
176 | } | ||
177 | list_add(&zstrm->list, &zs->idle_strm); | ||
178 | return 0; | ||
179 | } | ||
180 | |||
65 | static struct zcomp_strm *zcomp_strm_single_find(struct zcomp *comp) | 181 | static struct zcomp_strm *zcomp_strm_single_find(struct zcomp *comp) |
66 | { | 182 | { |
67 | struct zcomp_strm_single *zs = comp->stream; | 183 | struct zcomp_strm_single *zs = comp->stream; |
@@ -139,7 +255,7 @@ void zcomp_destroy(struct zcomp *comp) | |||
139 | * if requested algorithm is not supported or in case | 255 | * if requested algorithm is not supported or in case |
140 | * of init error | 256 | * of init error |
141 | */ | 257 | */ |
142 | struct zcomp *zcomp_create(const char *compress) | 258 | struct zcomp *zcomp_create(const char *compress, int max_strm) |
143 | { | 259 | { |
144 | struct zcomp *comp; | 260 | struct zcomp *comp; |
145 | struct zcomp_backend *backend; | 261 | struct zcomp_backend *backend; |
@@ -153,7 +269,11 @@ struct zcomp *zcomp_create(const char *compress) | |||
153 | return NULL; | 269 | return NULL; |
154 | 270 | ||
155 | comp->backend = backend; | 271 | comp->backend = backend; |
156 | if (zcomp_strm_single_create(comp) != 0) { | 272 | if (max_strm > 1) |
273 | zcomp_strm_multi_create(comp, max_strm); | ||
274 | else | ||
275 | zcomp_strm_single_create(comp); | ||
276 | if (!comp->stream) { | ||
157 | kfree(comp); | 277 | kfree(comp); |
158 | return NULL; | 278 | return NULL; |
159 | } | 279 | } |
diff --git a/drivers/block/zram/zcomp.h b/drivers/block/zram/zcomp.h index dc3500d842a3..2a3684446160 100644 --- a/drivers/block/zram/zcomp.h +++ b/drivers/block/zram/zcomp.h | |||
@@ -21,6 +21,8 @@ struct zcomp_strm { | |||
21 | * working memory) | 21 | * working memory) |
22 | */ | 22 | */ |
23 | void *private; | 23 | void *private; |
24 | /* used in multi stream backend, protected by backend strm_lock */ | ||
25 | struct list_head list; | ||
24 | }; | 26 | }; |
25 | 27 | ||
26 | /* static compression backend */ | 28 | /* static compression backend */ |
@@ -47,7 +49,7 @@ struct zcomp { | |||
47 | void (*destroy)(struct zcomp *comp); | 49 | void (*destroy)(struct zcomp *comp); |
48 | }; | 50 | }; |
49 | 51 | ||
50 | struct zcomp *zcomp_create(const char *comp); | 52 | struct zcomp *zcomp_create(const char *comp, int max_strm); |
51 | void zcomp_destroy(struct zcomp *comp); | 53 | void zcomp_destroy(struct zcomp *comp); |
52 | 54 | ||
53 | struct zcomp_strm *zcomp_strm_find(struct zcomp *comp); | 55 | struct zcomp_strm *zcomp_strm_find(struct zcomp *comp); |
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index 98823f9ca8b1..bdc7eb8c6df7 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c | |||
@@ -108,6 +108,40 @@ static ssize_t mem_used_total_show(struct device *dev, | |||
108 | return sprintf(buf, "%llu\n", val); | 108 | return sprintf(buf, "%llu\n", val); |
109 | } | 109 | } |
110 | 110 | ||
111 | static ssize_t max_comp_streams_show(struct device *dev, | ||
112 | struct device_attribute *attr, char *buf) | ||
113 | { | ||
114 | int val; | ||
115 | struct zram *zram = dev_to_zram(dev); | ||
116 | |||
117 | down_read(&zram->init_lock); | ||
118 | val = zram->max_comp_streams; | ||
119 | up_read(&zram->init_lock); | ||
120 | |||
121 | return sprintf(buf, "%d\n", val); | ||
122 | } | ||
123 | |||
124 | static ssize_t max_comp_streams_store(struct device *dev, | ||
125 | struct device_attribute *attr, const char *buf, size_t len) | ||
126 | { | ||
127 | int num; | ||
128 | struct zram *zram = dev_to_zram(dev); | ||
129 | |||
130 | if (kstrtoint(buf, 0, &num)) | ||
131 | return -EINVAL; | ||
132 | if (num < 1) | ||
133 | return -EINVAL; | ||
134 | down_write(&zram->init_lock); | ||
135 | if (init_done(zram)) { | ||
136 | up_write(&zram->init_lock); | ||
137 | pr_info("Can't set max_comp_streams for initialized device\n"); | ||
138 | return -EBUSY; | ||
139 | } | ||
140 | zram->max_comp_streams = num; | ||
141 | up_write(&zram->init_lock); | ||
142 | return len; | ||
143 | } | ||
144 | |||
111 | /* flag operations needs meta->tb_lock */ | 145 | /* flag operations needs meta->tb_lock */ |
112 | static int zram_test_flag(struct zram_meta *meta, u32 index, | 146 | static int zram_test_flag(struct zram_meta *meta, u32 index, |
113 | enum zram_pageflags flag) | 147 | enum zram_pageflags flag) |
@@ -502,6 +536,8 @@ static void zram_reset_device(struct zram *zram, bool reset_capacity) | |||
502 | } | 536 | } |
503 | 537 | ||
504 | zcomp_destroy(zram->comp); | 538 | zcomp_destroy(zram->comp); |
539 | zram->max_comp_streams = 1; | ||
540 | |||
505 | zram_meta_free(zram->meta); | 541 | zram_meta_free(zram->meta); |
506 | zram->meta = NULL; | 542 | zram->meta = NULL; |
507 | /* Reset stats */ | 543 | /* Reset stats */ |
@@ -537,7 +573,7 @@ static ssize_t disksize_store(struct device *dev, | |||
537 | goto out_free_meta; | 573 | goto out_free_meta; |
538 | } | 574 | } |
539 | 575 | ||
540 | zram->comp = zcomp_create(default_compressor); | 576 | zram->comp = zcomp_create(default_compressor, zram->max_comp_streams); |
541 | if (!zram->comp) { | 577 | if (!zram->comp) { |
542 | pr_info("Cannot initialise %s compressing backend\n", | 578 | pr_info("Cannot initialise %s compressing backend\n", |
543 | default_compressor); | 579 | default_compressor); |
@@ -698,6 +734,8 @@ static DEVICE_ATTR(initstate, S_IRUGO, initstate_show, NULL); | |||
698 | static DEVICE_ATTR(reset, S_IWUSR, NULL, reset_store); | 734 | static DEVICE_ATTR(reset, S_IWUSR, NULL, reset_store); |
699 | static DEVICE_ATTR(orig_data_size, S_IRUGO, orig_data_size_show, NULL); | 735 | static DEVICE_ATTR(orig_data_size, S_IRUGO, orig_data_size_show, NULL); |
700 | static DEVICE_ATTR(mem_used_total, S_IRUGO, mem_used_total_show, NULL); | 736 | static DEVICE_ATTR(mem_used_total, S_IRUGO, mem_used_total_show, NULL); |
737 | static DEVICE_ATTR(max_comp_streams, S_IRUGO | S_IWUSR, | ||
738 | max_comp_streams_show, max_comp_streams_store); | ||
701 | 739 | ||
702 | ZRAM_ATTR_RO(num_reads); | 740 | ZRAM_ATTR_RO(num_reads); |
703 | ZRAM_ATTR_RO(num_writes); | 741 | ZRAM_ATTR_RO(num_writes); |
@@ -722,6 +760,7 @@ static struct attribute *zram_disk_attrs[] = { | |||
722 | &dev_attr_orig_data_size.attr, | 760 | &dev_attr_orig_data_size.attr, |
723 | &dev_attr_compr_data_size.attr, | 761 | &dev_attr_compr_data_size.attr, |
724 | &dev_attr_mem_used_total.attr, | 762 | &dev_attr_mem_used_total.attr, |
763 | &dev_attr_max_comp_streams.attr, | ||
725 | NULL, | 764 | NULL, |
726 | }; | 765 | }; |
727 | 766 | ||
@@ -784,6 +823,7 @@ static int create_device(struct zram *zram, int device_id) | |||
784 | } | 823 | } |
785 | 824 | ||
786 | zram->meta = NULL; | 825 | zram->meta = NULL; |
826 | zram->max_comp_streams = 1; | ||
787 | return 0; | 827 | return 0; |
788 | 828 | ||
789 | out_free_disk: | 829 | out_free_disk: |
diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h index 45e04f7b713f..ccf36d11755a 100644 --- a/drivers/block/zram/zram_drv.h +++ b/drivers/block/zram/zram_drv.h | |||
@@ -99,7 +99,7 @@ struct zram { | |||
99 | * we can store in a disk. | 99 | * we can store in a disk. |
100 | */ | 100 | */ |
101 | u64 disksize; /* bytes */ | 101 | u64 disksize; /* bytes */ |
102 | 102 | int max_comp_streams; | |
103 | struct zram_stats stats; | 103 | struct zram_stats stats; |
104 | }; | 104 | }; |
105 | #endif | 105 | #endif |