diff options
-rw-r--r-- | drivers/block/zram/zram_drv.c | 69 | ||||
-rw-r--r-- | drivers/block/zram/zram_drv.h | 24 |
2 files changed, 60 insertions, 33 deletions
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index 40743972eaf7..dfa4024c448a 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c | |||
@@ -183,19 +183,32 @@ static ssize_t comp_algorithm_store(struct device *dev, | |||
183 | static int zram_test_flag(struct zram_meta *meta, u32 index, | 183 | static int zram_test_flag(struct zram_meta *meta, u32 index, |
184 | enum zram_pageflags flag) | 184 | enum zram_pageflags flag) |
185 | { | 185 | { |
186 | return meta->table[index].flags & BIT(flag); | 186 | return meta->table[index].value & BIT(flag); |
187 | } | 187 | } |
188 | 188 | ||
189 | static void zram_set_flag(struct zram_meta *meta, u32 index, | 189 | static void zram_set_flag(struct zram_meta *meta, u32 index, |
190 | enum zram_pageflags flag) | 190 | enum zram_pageflags flag) |
191 | { | 191 | { |
192 | meta->table[index].flags |= BIT(flag); | 192 | meta->table[index].value |= BIT(flag); |
193 | } | 193 | } |
194 | 194 | ||
195 | static void zram_clear_flag(struct zram_meta *meta, u32 index, | 195 | static void zram_clear_flag(struct zram_meta *meta, u32 index, |
196 | enum zram_pageflags flag) | 196 | enum zram_pageflags flag) |
197 | { | 197 | { |
198 | meta->table[index].flags &= ~BIT(flag); | 198 | meta->table[index].value &= ~BIT(flag); |
199 | } | ||
200 | |||
201 | static size_t zram_get_obj_size(struct zram_meta *meta, u32 index) | ||
202 | { | ||
203 | return meta->table[index].value & (BIT(ZRAM_FLAG_SHIFT) - 1); | ||
204 | } | ||
205 | |||
206 | static void zram_set_obj_size(struct zram_meta *meta, | ||
207 | u32 index, size_t size) | ||
208 | { | ||
209 | unsigned long flags = meta->table[index].value >> ZRAM_FLAG_SHIFT; | ||
210 | |||
211 | meta->table[index].value = (flags << ZRAM_FLAG_SHIFT) | size; | ||
199 | } | 212 | } |
200 | 213 | ||
201 | static inline int is_partial_io(struct bio_vec *bvec) | 214 | static inline int is_partial_io(struct bio_vec *bvec) |
@@ -255,7 +268,6 @@ static struct zram_meta *zram_meta_alloc(u64 disksize) | |||
255 | goto free_table; | 268 | goto free_table; |
256 | } | 269 | } |
257 | 270 | ||
258 | rwlock_init(&meta->tb_lock); | ||
259 | return meta; | 271 | return meta; |
260 | 272 | ||
261 | free_table: | 273 | free_table: |
@@ -304,7 +316,12 @@ static void handle_zero_page(struct bio_vec *bvec) | |||
304 | flush_dcache_page(page); | 316 | flush_dcache_page(page); |
305 | } | 317 | } |
306 | 318 | ||
307 | /* NOTE: caller should hold meta->tb_lock with write-side */ | 319 | |
320 | /* | ||
321 | * To protect concurrent access to the same index entry, | ||
322 | * caller should hold this table index entry's bit_spinlock to | ||
323 | * indicate this index entry is accessing. | ||
324 | */ | ||
308 | static void zram_free_page(struct zram *zram, size_t index) | 325 | static void zram_free_page(struct zram *zram, size_t index) |
309 | { | 326 | { |
310 | struct zram_meta *meta = zram->meta; | 327 | struct zram_meta *meta = zram->meta; |
@@ -324,11 +341,12 @@ static void zram_free_page(struct zram *zram, size_t index) | |||
324 | 341 | ||
325 | zs_free(meta->mem_pool, handle); | 342 | zs_free(meta->mem_pool, handle); |
326 | 343 | ||
327 | atomic64_sub(meta->table[index].size, &zram->stats.compr_data_size); | 344 | atomic64_sub(zram_get_obj_size(meta, index), |
345 | &zram->stats.compr_data_size); | ||
328 | atomic64_dec(&zram->stats.pages_stored); | 346 | atomic64_dec(&zram->stats.pages_stored); |
329 | 347 | ||
330 | meta->table[index].handle = 0; | 348 | meta->table[index].handle = 0; |
331 | meta->table[index].size = 0; | 349 | zram_set_obj_size(meta, index, 0); |
332 | } | 350 | } |
333 | 351 | ||
334 | static int zram_decompress_page(struct zram *zram, char *mem, u32 index) | 352 | static int zram_decompress_page(struct zram *zram, char *mem, u32 index) |
@@ -339,12 +357,12 @@ static int zram_decompress_page(struct zram *zram, char *mem, u32 index) | |||
339 | unsigned long handle; | 357 | unsigned long handle; |
340 | size_t size; | 358 | size_t size; |
341 | 359 | ||
342 | read_lock(&meta->tb_lock); | 360 | bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value); |
343 | handle = meta->table[index].handle; | 361 | handle = meta->table[index].handle; |
344 | size = meta->table[index].size; | 362 | size = zram_get_obj_size(meta, index); |
345 | 363 | ||
346 | if (!handle || zram_test_flag(meta, index, ZRAM_ZERO)) { | 364 | if (!handle || zram_test_flag(meta, index, ZRAM_ZERO)) { |
347 | read_unlock(&meta->tb_lock); | 365 | bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value); |
348 | clear_page(mem); | 366 | clear_page(mem); |
349 | return 0; | 367 | return 0; |
350 | } | 368 | } |
@@ -355,7 +373,7 @@ static int zram_decompress_page(struct zram *zram, char *mem, u32 index) | |||
355 | else | 373 | else |
356 | ret = zcomp_decompress(zram->comp, cmem, size, mem); | 374 | ret = zcomp_decompress(zram->comp, cmem, size, mem); |
357 | zs_unmap_object(meta->mem_pool, handle); | 375 | zs_unmap_object(meta->mem_pool, handle); |
358 | read_unlock(&meta->tb_lock); | 376 | bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value); |
359 | 377 | ||
360 | /* Should NEVER happen. Return bio error if it does. */ | 378 | /* Should NEVER happen. Return bio error if it does. */ |
361 | if (unlikely(ret)) { | 379 | if (unlikely(ret)) { |
@@ -376,14 +394,14 @@ static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec, | |||
376 | struct zram_meta *meta = zram->meta; | 394 | struct zram_meta *meta = zram->meta; |
377 | page = bvec->bv_page; | 395 | page = bvec->bv_page; |
378 | 396 | ||
379 | read_lock(&meta->tb_lock); | 397 | bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value); |
380 | if (unlikely(!meta->table[index].handle) || | 398 | if (unlikely(!meta->table[index].handle) || |
381 | zram_test_flag(meta, index, ZRAM_ZERO)) { | 399 | zram_test_flag(meta, index, ZRAM_ZERO)) { |
382 | read_unlock(&meta->tb_lock); | 400 | bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value); |
383 | handle_zero_page(bvec); | 401 | handle_zero_page(bvec); |
384 | return 0; | 402 | return 0; |
385 | } | 403 | } |
386 | read_unlock(&meta->tb_lock); | 404 | bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value); |
387 | 405 | ||
388 | if (is_partial_io(bvec)) | 406 | if (is_partial_io(bvec)) |
389 | /* Use a temporary buffer to decompress the page */ | 407 | /* Use a temporary buffer to decompress the page */ |
@@ -461,10 +479,10 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, | |||
461 | if (page_zero_filled(uncmem)) { | 479 | if (page_zero_filled(uncmem)) { |
462 | kunmap_atomic(user_mem); | 480 | kunmap_atomic(user_mem); |
463 | /* Free memory associated with this sector now. */ | 481 | /* Free memory associated with this sector now. */ |
464 | write_lock(&zram->meta->tb_lock); | 482 | bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value); |
465 | zram_free_page(zram, index); | 483 | zram_free_page(zram, index); |
466 | zram_set_flag(meta, index, ZRAM_ZERO); | 484 | zram_set_flag(meta, index, ZRAM_ZERO); |
467 | write_unlock(&zram->meta->tb_lock); | 485 | bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value); |
468 | 486 | ||
469 | atomic64_inc(&zram->stats.zero_pages); | 487 | atomic64_inc(&zram->stats.zero_pages); |
470 | ret = 0; | 488 | ret = 0; |
@@ -514,12 +532,12 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, | |||
514 | * Free memory associated with this sector | 532 | * Free memory associated with this sector |
515 | * before overwriting unused sectors. | 533 | * before overwriting unused sectors. |
516 | */ | 534 | */ |
517 | write_lock(&zram->meta->tb_lock); | 535 | bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value); |
518 | zram_free_page(zram, index); | 536 | zram_free_page(zram, index); |
519 | 537 | ||
520 | meta->table[index].handle = handle; | 538 | meta->table[index].handle = handle; |
521 | meta->table[index].size = clen; | 539 | zram_set_obj_size(meta, index, clen); |
522 | write_unlock(&zram->meta->tb_lock); | 540 | bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value); |
523 | 541 | ||
524 | /* Update stats */ | 542 | /* Update stats */ |
525 | atomic64_add(clen, &zram->stats.compr_data_size); | 543 | atomic64_add(clen, &zram->stats.compr_data_size); |
@@ -560,6 +578,7 @@ static void zram_bio_discard(struct zram *zram, u32 index, | |||
560 | int offset, struct bio *bio) | 578 | int offset, struct bio *bio) |
561 | { | 579 | { |
562 | size_t n = bio->bi_iter.bi_size; | 580 | size_t n = bio->bi_iter.bi_size; |
581 | struct zram_meta *meta = zram->meta; | ||
563 | 582 | ||
564 | /* | 583 | /* |
565 | * zram manages data in physical block size units. Because logical block | 584 | * zram manages data in physical block size units. Because logical block |
@@ -580,13 +599,9 @@ static void zram_bio_discard(struct zram *zram, u32 index, | |||
580 | } | 599 | } |
581 | 600 | ||
582 | while (n >= PAGE_SIZE) { | 601 | while (n >= PAGE_SIZE) { |
583 | /* | 602 | bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value); |
584 | * Discard request can be large so the lock hold times could be | ||
585 | * lengthy. So take the lock once per page. | ||
586 | */ | ||
587 | write_lock(&zram->meta->tb_lock); | ||
588 | zram_free_page(zram, index); | 603 | zram_free_page(zram, index); |
589 | write_unlock(&zram->meta->tb_lock); | 604 | bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value); |
590 | index++; | 605 | index++; |
591 | n -= PAGE_SIZE; | 606 | n -= PAGE_SIZE; |
592 | } | 607 | } |
@@ -821,9 +836,9 @@ static void zram_slot_free_notify(struct block_device *bdev, | |||
821 | zram = bdev->bd_disk->private_data; | 836 | zram = bdev->bd_disk->private_data; |
822 | meta = zram->meta; | 837 | meta = zram->meta; |
823 | 838 | ||
824 | write_lock(&meta->tb_lock); | 839 | bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value); |
825 | zram_free_page(zram, index); | 840 | zram_free_page(zram, index); |
826 | write_unlock(&meta->tb_lock); | 841 | bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value); |
827 | atomic64_inc(&zram->stats.notify_free); | 842 | atomic64_inc(&zram->stats.notify_free); |
828 | } | 843 | } |
829 | 844 | ||
diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h index c8161bd8969c..5b0afde729cd 100644 --- a/drivers/block/zram/zram_drv.h +++ b/drivers/block/zram/zram_drv.h | |||
@@ -50,10 +50,24 @@ static const size_t max_zpage_size = PAGE_SIZE / 4 * 3; | |||
50 | #define ZRAM_SECTOR_PER_LOGICAL_BLOCK \ | 50 | #define ZRAM_SECTOR_PER_LOGICAL_BLOCK \ |
51 | (1 << (ZRAM_LOGICAL_BLOCK_SHIFT - SECTOR_SHIFT)) | 51 | (1 << (ZRAM_LOGICAL_BLOCK_SHIFT - SECTOR_SHIFT)) |
52 | 52 | ||
53 | /* Flags for zram pages (table[page_no].flags) */ | 53 | |
54 | /* | ||
55 | * The lower ZRAM_FLAG_SHIFT bits of table.value is for | ||
56 | * object size (excluding header), the higher bits is for | ||
57 | * zram_pageflags. | ||
58 | * | ||
59 | * zram is mainly used for memory efficiency so we want to keep memory | ||
60 | * footprint small so we can squeeze size and flags into a field. | ||
61 | * The lower ZRAM_FLAG_SHIFT bits is for object size (excluding header), | ||
62 | * the higher bits is for zram_pageflags. | ||
63 | */ | ||
64 | #define ZRAM_FLAG_SHIFT 24 | ||
65 | |||
66 | /* Flags for zram pages (table[page_no].value) */ | ||
54 | enum zram_pageflags { | 67 | enum zram_pageflags { |
55 | /* Page consists entirely of zeros */ | 68 | /* Page consists entirely of zeros */ |
56 | ZRAM_ZERO, | 69 | ZRAM_ZERO = ZRAM_FLAG_SHIFT + 1, |
70 | ZRAM_ACCESS, /* page in now accessed */ | ||
57 | 71 | ||
58 | __NR_ZRAM_PAGEFLAGS, | 72 | __NR_ZRAM_PAGEFLAGS, |
59 | }; | 73 | }; |
@@ -63,9 +77,8 @@ enum zram_pageflags { | |||
63 | /* Allocated for each disk page */ | 77 | /* Allocated for each disk page */ |
64 | struct zram_table_entry { | 78 | struct zram_table_entry { |
65 | unsigned long handle; | 79 | unsigned long handle; |
66 | u16 size; /* object size (excluding header) */ | 80 | unsigned long value; |
67 | u8 flags; | 81 | }; |
68 | } __aligned(4); | ||
69 | 82 | ||
70 | struct zram_stats { | 83 | struct zram_stats { |
71 | atomic64_t compr_data_size; /* compressed size of pages stored */ | 84 | atomic64_t compr_data_size; /* compressed size of pages stored */ |
@@ -80,7 +93,6 @@ struct zram_stats { | |||
80 | }; | 93 | }; |
81 | 94 | ||
82 | struct zram_meta { | 95 | struct zram_meta { |
83 | rwlock_t tb_lock; /* protect table */ | ||
84 | struct zram_table_entry *table; | 96 | struct zram_table_entry *table; |
85 | struct zs_pool *mem_pool; | 97 | struct zs_pool *mem_pool; |
86 | }; | 98 | }; |