dm-writecache.c (6d7e0a34206d4a5d0c619c0608eae57f4c557064) | dm-writecache.c (1edaa447d958bec24c6a79685a5790d98976fd16) |
---|---|
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) 2018 Red Hat. All rights reserved. 4 * 5 * This file is released under the GPL. 6 */ 7 8#include <linux/device-mapper.h> --- 12 unchanged lines hidden (view full) --- 21#define HIGH_WATERMARK 50 22#define LOW_WATERMARK 45 23#define MAX_WRITEBACK_JOBS 0 24#define ENDIO_LATENCY 16 25#define WRITEBACK_LATENCY 64 26#define AUTOCOMMIT_BLOCKS_SSD 65536 27#define AUTOCOMMIT_BLOCKS_PMEM 64 28#define AUTOCOMMIT_MSEC 1000 | 1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) 2018 Red Hat. All rights reserved. 4 * 5 * This file is released under the GPL. 6 */ 7 8#include <linux/device-mapper.h> --- 12 unchanged lines hidden (view full) --- 21#define HIGH_WATERMARK 50 22#define LOW_WATERMARK 45 23#define MAX_WRITEBACK_JOBS 0 24#define ENDIO_LATENCY 16 25#define WRITEBACK_LATENCY 64 26#define AUTOCOMMIT_BLOCKS_SSD 65536 27#define AUTOCOMMIT_BLOCKS_PMEM 64 28#define AUTOCOMMIT_MSEC 1000 |
29#define MAX_AGE_DIV 16 30#define MAX_AGE_UNSPECIFIED -1UL |
|
29 30#define BITMAP_GRANULARITY 65536 31#if BITMAP_GRANULARITY < PAGE_SIZE 32#undef BITMAP_GRANULARITY 33#define BITMAP_GRANULARITY PAGE_SIZE 34#endif 35 36#if IS_ENABLED(CONFIG_ARCH_HAS_PMEM_API) && IS_ENABLED(CONFIG_DAX_DRIVER) --- 46 unchanged lines hidden (view full) --- 83 :1 84#endif 85 ; 86 unsigned long index 87#if BITS_PER_LONG == 64 88 :47 89#endif 90 ; | 31 32#define BITMAP_GRANULARITY 65536 33#if BITMAP_GRANULARITY < PAGE_SIZE 34#undef BITMAP_GRANULARITY 35#define BITMAP_GRANULARITY PAGE_SIZE 36#endif 37 38#if IS_ENABLED(CONFIG_ARCH_HAS_PMEM_API) && IS_ENABLED(CONFIG_DAX_DRIVER) --- 46 unchanged lines hidden (view full) --- 85 :1 86#endif 87 ; 88 unsigned long index 89#if BITS_PER_LONG == 64 90 :47 91#endif 92 ; |
93 unsigned long age; |
|
91#ifdef DM_WRITECACHE_HANDLE_HARDWARE_ERRORS 92 uint64_t original_sector; 93 uint64_t seq_count; 94#endif 95}; 96 97#ifdef DM_WRITECACHE_HAS_PMEM 98#define WC_MODE_PMEM(wc) ((wc)->pmem_mode) --- 15 unchanged lines hidden (view full) --- 114 }; 115 }; 116 struct rb_root tree; 117 118 size_t freelist_size; 119 size_t writeback_size; 120 size_t freelist_high_watermark; 121 size_t freelist_low_watermark; | 94#ifdef DM_WRITECACHE_HANDLE_HARDWARE_ERRORS 95 uint64_t original_sector; 96 uint64_t seq_count; 97#endif 98}; 99 100#ifdef DM_WRITECACHE_HAS_PMEM 101#define WC_MODE_PMEM(wc) ((wc)->pmem_mode) --- 15 unchanged lines hidden (view full) --- 117 }; 118 }; 119 struct rb_root tree; 120 121 size_t freelist_size; 122 size_t writeback_size; 123 size_t freelist_high_watermark; 124 size_t freelist_low_watermark; |
125 unsigned long max_age; |
|
122 123 unsigned uncommitted_blocks; 124 unsigned autocommit_blocks; 125 unsigned max_writeback_jobs; 126 127 int error; 128 129 unsigned long autocommit_jiffies; 130 struct timer_list autocommit_timer; 131 struct wait_queue_head freelist_wait; 132 | 126 127 unsigned uncommitted_blocks; 128 unsigned autocommit_blocks; 129 unsigned max_writeback_jobs; 130 131 int error; 132 133 unsigned long autocommit_jiffies; 134 struct timer_list autocommit_timer; 135 struct wait_queue_head freelist_wait; 136 |
137 struct timer_list max_age_timer; 138 |
|
133 atomic_t bio_in_progress[2]; 134 struct wait_queue_head bio_in_progress_wait[2]; 135 136 struct dm_target *ti; 137 struct dm_dev *dev; 138 struct dm_dev *ssd_dev; 139 sector_t start_sector; 140 void *memory_map; --- 14 unchanged lines hidden (view full) --- 155 156 bool high_wm_percent_set:1; 157 bool low_wm_percent_set:1; 158 bool max_writeback_jobs_set:1; 159 bool autocommit_blocks_set:1; 160 bool autocommit_time_set:1; 161 bool writeback_fua_set:1; 162 bool flush_on_suspend:1; | 139 atomic_t bio_in_progress[2]; 140 struct wait_queue_head bio_in_progress_wait[2]; 141 142 struct dm_target *ti; 143 struct dm_dev *dev; 144 struct dm_dev *ssd_dev; 145 sector_t start_sector; 146 void *memory_map; --- 14 unchanged lines hidden (view full) --- 161 162 bool high_wm_percent_set:1; 163 bool low_wm_percent_set:1; 164 bool max_writeback_jobs_set:1; 165 bool autocommit_blocks_set:1; 166 bool autocommit_time_set:1; 167 bool writeback_fua_set:1; 168 bool flush_on_suspend:1; |
169 bool cleaner:1; |
|
163 164 unsigned writeback_all; 165 struct workqueue_struct *writeback_wq; 166 struct work_struct writeback_work; 167 struct work_struct flush_work; 168 169 struct dm_io_client *dm_io; 170 --- 326 unchanged lines hidden (view full) --- 497 if (wait_for_ios) 498 writecache_wait_for_ios(wc, WRITE); 499 500 writecache_disk_flush(wc, wc->ssd_dev); 501 502 memset(wc->dirty_bitmap, 0, wc->dirty_bitmap_size); 503} 504 | 170 171 unsigned writeback_all; 172 struct workqueue_struct *writeback_wq; 173 struct work_struct writeback_work; 174 struct work_struct flush_work; 175 176 struct dm_io_client *dm_io; 177 --- 326 unchanged lines hidden (view full) --- 504 if (wait_for_ios) 505 writecache_wait_for_ios(wc, WRITE); 506 507 writecache_disk_flush(wc, wc->ssd_dev); 508 509 memset(wc->dirty_bitmap, 0, wc->dirty_bitmap_size); 510} 511 |
512static void ssd_commit_superblock(struct dm_writecache *wc) 513{ 514 int r; 515 struct dm_io_region region; 516 struct dm_io_request req; 517 518 region.bdev = wc->ssd_dev->bdev; 519 region.sector = 0; 520 region.count = PAGE_SIZE; 521 522 if (unlikely(region.sector + region.count > wc->metadata_sectors)) 523 region.count = wc->metadata_sectors - region.sector; 524 525 region.sector += wc->start_sector; 526 527 req.bi_op = REQ_OP_WRITE; 528 req.bi_op_flags = REQ_SYNC | REQ_FUA; 529 req.mem.type = DM_IO_VMA; 530 req.mem.ptr.vma = (char *)wc->memory_map; 531 req.client = wc->dm_io; 532 req.notify.fn = NULL; 533 req.notify.context = NULL; 534 535 r = dm_io(&req, 1, ®ion, NULL); 536 if (unlikely(r)) 537 writecache_error(wc, r, "error writing superblock"); 538} 539 |
|
505static void writecache_commit_flushed(struct dm_writecache *wc, bool wait_for_ios) 506{ 507 if (WC_MODE_PMEM(wc)) 508 wmb(); 509 else 510 ssd_commit_flushed(wc, wait_for_ios); 511} 512 --- 78 unchanged lines hidden (view full) --- 591 if (read_original_sector(wc, e) > read_original_sector(wc, ins)) 592 node = &parent->rb_left; 593 else 594 node = &parent->rb_right; 595 } 596 rb_link_node(&ins->rb_node, parent, node); 597 rb_insert_color(&ins->rb_node, &wc->tree); 598 list_add(&ins->lru, &wc->lru); | 540static void writecache_commit_flushed(struct dm_writecache *wc, bool wait_for_ios) 541{ 542 if (WC_MODE_PMEM(wc)) 543 wmb(); 544 else 545 ssd_commit_flushed(wc, wait_for_ios); 546} 547 --- 78 unchanged lines hidden (view full) --- 626 if (read_original_sector(wc, e) > read_original_sector(wc, ins)) 627 node = &parent->rb_left; 628 else 629 node = &parent->rb_right; 630 } 631 rb_link_node(&ins->rb_node, parent, node); 632 rb_insert_color(&ins->rb_node, &wc->tree); 633 list_add(&ins->lru, &wc->lru); |
634 ins->age = jiffies; |
|
599} 600 601static void writecache_unlink(struct dm_writecache *wc, struct wc_entry *e) 602{ 603 list_del(&e->lru); 604 rb_erase(&e->rb_node, &wc->tree); 605} 606 --- 19 unchanged lines hidden (view full) --- 626} 627 628static inline void writecache_verify_watermark(struct dm_writecache *wc) 629{ 630 if (unlikely(wc->freelist_size + wc->writeback_size <= wc->freelist_high_watermark)) 631 queue_work(wc->writeback_wq, &wc->writeback_work); 632} 633 | 635} 636 637static void writecache_unlink(struct dm_writecache *wc, struct wc_entry *e) 638{ 639 list_del(&e->lru); 640 rb_erase(&e->rb_node, &wc->tree); 641} 642 --- 19 unchanged lines hidden (view full) --- 662} 663 664static inline void writecache_verify_watermark(struct dm_writecache *wc) 665{ 666 if (unlikely(wc->freelist_size + wc->writeback_size <= wc->freelist_high_watermark)) 667 queue_work(wc->writeback_wq, &wc->writeback_work); 668} 669 |
670static void writecache_max_age_timer(struct timer_list *t) 671{ 672 struct dm_writecache *wc = from_timer(wc, t, max_age_timer); 673 674 if (!dm_suspended(wc->ti) && !writecache_has_error(wc)) { 675 queue_work(wc->writeback_wq, &wc->writeback_work); 676 mod_timer(&wc->max_age_timer, jiffies + wc->max_age / MAX_AGE_DIV); 677 } 678} 679 |
|
634static struct wc_entry *writecache_pop_from_freelist(struct dm_writecache *wc, sector_t expected_sector) 635{ 636 struct wc_entry *e; 637 638 if (WC_MODE_SORT_FREELIST(wc)) { 639 struct rb_node *next; 640 if (unlikely(!wc->current_free)) 641 return NULL; --- 94 unchanged lines hidden (view full) --- 736 break; 737 e = e2; 738 cond_resched(); 739 } 740 writecache_commit_flushed(wc, true); 741 742 wc->seq_count++; 743 pmem_assign(sb(wc)->seq_count, cpu_to_le64(wc->seq_count)); | 680static struct wc_entry *writecache_pop_from_freelist(struct dm_writecache *wc, sector_t expected_sector) 681{ 682 struct wc_entry *e; 683 684 if (WC_MODE_SORT_FREELIST(wc)) { 685 struct rb_node *next; 686 if (unlikely(!wc->current_free)) 687 return NULL; --- 94 unchanged lines hidden (view full) --- 782 break; 783 e = e2; 784 cond_resched(); 785 } 786 writecache_commit_flushed(wc, true); 787 788 wc->seq_count++; 789 pmem_assign(sb(wc)->seq_count, cpu_to_le64(wc->seq_count)); |
744 writecache_flush_region(wc, &sb(wc)->seq_count, sizeof sb(wc)->seq_count); 745 writecache_commit_flushed(wc, false); | 790 if (WC_MODE_PMEM(wc)) 791 writecache_commit_flushed(wc, false); 792 else 793 ssd_commit_superblock(wc); |
746 747 wc->overwrote_committed = false; 748 749 need_flush_after_free = false; 750 while (1) { 751 /* Free another committed entry with lower seq-count */ 752 struct rb_node *rb_node = rb_prev(&e->rb_node); 753 --- 78 unchanged lines hidden (view full) --- 832} 833 834static void writecache_suspend(struct dm_target *ti) 835{ 836 struct dm_writecache *wc = ti->private; 837 bool flush_on_suspend; 838 839 del_timer_sync(&wc->autocommit_timer); | 794 795 wc->overwrote_committed = false; 796 797 need_flush_after_free = false; 798 while (1) { 799 /* Free another committed entry with lower seq-count */ 800 struct rb_node *rb_node = rb_prev(&e->rb_node); 801 --- 78 unchanged lines hidden (view full) --- 880} 881 882static void writecache_suspend(struct dm_target *ti) 883{ 884 struct dm_writecache *wc = ti->private; 885 bool flush_on_suspend; 886 887 del_timer_sync(&wc->autocommit_timer); |
888 del_timer_sync(&wc->max_age_timer); |
|
840 841 wc_lock(wc); 842 writecache_flush(wc); 843 flush_on_suspend = wc->flush_on_suspend; 844 if (flush_on_suspend) { 845 wc->flush_on_suspend = false; 846 wc->writeback_all++; 847 queue_work(wc->writeback_wq, &wc->writeback_work); --- 23 unchanged lines hidden (view full) --- 871 return 0; 872 wc->entries = vmalloc(array_size(sizeof(struct wc_entry), wc->n_blocks)); 873 if (!wc->entries) 874 return -ENOMEM; 875 for (b = 0; b < wc->n_blocks; b++) { 876 struct wc_entry *e = &wc->entries[b]; 877 e->index = b; 878 e->write_in_progress = false; | 889 890 wc_lock(wc); 891 writecache_flush(wc); 892 flush_on_suspend = wc->flush_on_suspend; 893 if (flush_on_suspend) { 894 wc->flush_on_suspend = false; 895 wc->writeback_all++; 896 queue_work(wc->writeback_wq, &wc->writeback_work); --- 23 unchanged lines hidden (view full) --- 920 return 0; 921 wc->entries = vmalloc(array_size(sizeof(struct wc_entry), wc->n_blocks)); 922 if (!wc->entries) 923 return -ENOMEM; 924 for (b = 0; b < wc->n_blocks; b++) { 925 struct wc_entry *e = &wc->entries[b]; 926 e->index = b; 927 e->write_in_progress = false; |
928 cond_resched(); |
|
879 } 880 881 return 0; 882} 883 884static void writecache_resume(struct dm_target *ti) 885{ 886 struct dm_writecache *wc = ti->private; --- 38 unchanged lines hidden (view full) --- 925 writecache_error(wc, r, "hardware memory error when reading metadata entry %lu: %d", 926 (unsigned long)b, r); 927 e->original_sector = -1; 928 e->seq_count = -1; 929 } else { 930 e->original_sector = le64_to_cpu(wme.original_sector); 931 e->seq_count = le64_to_cpu(wme.seq_count); 932 } | 929 } 930 931 return 0; 932} 933 934static void writecache_resume(struct dm_target *ti) 935{ 936 struct dm_writecache *wc = ti->private; --- 38 unchanged lines hidden (view full) --- 975 writecache_error(wc, r, "hardware memory error when reading metadata entry %lu: %d", 976 (unsigned long)b, r); 977 e->original_sector = -1; 978 e->seq_count = -1; 979 } else { 980 e->original_sector = le64_to_cpu(wme.original_sector); 981 e->seq_count = le64_to_cpu(wme.seq_count); 982 } |
983 cond_resched(); |
|
933 } 934#endif 935 for (b = 0; b < wc->n_blocks; b++) { 936 struct wc_entry *e = &wc->entries[b]; 937 if (!writecache_entry_is_committed(wc, e)) { 938 if (read_seq_count(wc, e) != -1) { 939erase_this: 940 clear_seq_count(wc, e); --- 27 unchanged lines hidden (view full) --- 968 969 if (need_flush) { 970 writecache_flush_all_metadata(wc); 971 writecache_commit_flushed(wc, false); 972 } 973 974 writecache_verify_watermark(wc); 975 | 984 } 985#endif 986 for (b = 0; b < wc->n_blocks; b++) { 987 struct wc_entry *e = &wc->entries[b]; 988 if (!writecache_entry_is_committed(wc, e)) { 989 if (read_seq_count(wc, e) != -1) { 990erase_this: 991 clear_seq_count(wc, e); --- 27 unchanged lines hidden (view full) --- 1019 1020 if (need_flush) { 1021 writecache_flush_all_metadata(wc); 1022 writecache_commit_flushed(wc, false); 1023 } 1024 1025 writecache_verify_watermark(wc); 1026 |
1027 if (wc->max_age != MAX_AGE_UNSPECIFIED) 1028 mod_timer(&wc->max_age_timer, jiffies + wc->max_age / MAX_AGE_DIV); 1029 |
|
976 wc_unlock(wc); 977} 978 979static int process_flush_mesg(unsigned argc, char **argv, struct dm_writecache *wc) 980{ 981 if (argc != 1) 982 return -EINVAL; 983 --- 32 unchanged lines hidden (view full) --- 1016 1017 wc_lock(wc); 1018 wc->flush_on_suspend = true; 1019 wc_unlock(wc); 1020 1021 return 0; 1022} 1023 | 1030 wc_unlock(wc); 1031} 1032 1033static int process_flush_mesg(unsigned argc, char **argv, struct dm_writecache *wc) 1034{ 1035 if (argc != 1) 1036 return -EINVAL; 1037 --- 32 unchanged lines hidden (view full) --- 1070 1071 wc_lock(wc); 1072 wc->flush_on_suspend = true; 1073 wc_unlock(wc); 1074 1075 return 0; 1076} 1077 |
1078static void activate_cleaner(struct dm_writecache *wc) 1079{ 1080 wc->flush_on_suspend = true; 1081 wc->cleaner = true; 1082 wc->freelist_high_watermark = wc->n_blocks; 1083 wc->freelist_low_watermark = wc->n_blocks; 1084} 1085 1086static int process_cleaner_mesg(unsigned argc, char **argv, struct dm_writecache *wc) 1087{ 1088 if (argc != 1) 1089 return -EINVAL; 1090 1091 wc_lock(wc); 1092 activate_cleaner(wc); 1093 if (!dm_suspended(wc->ti)) 1094 writecache_verify_watermark(wc); 1095 wc_unlock(wc); 1096 1097 return 0; 1098} 1099 |
|
1024static int writecache_message(struct dm_target *ti, unsigned argc, char **argv, 1025 char *result, unsigned maxlen) 1026{ 1027 int r = -EINVAL; 1028 struct dm_writecache *wc = ti->private; 1029 1030 if (!strcasecmp(argv[0], "flush")) 1031 r = process_flush_mesg(argc, argv, wc); 1032 else if (!strcasecmp(argv[0], "flush_on_suspend")) 1033 r = process_flush_on_suspend_mesg(argc, argv, wc); | 1100static int writecache_message(struct dm_target *ti, unsigned argc, char **argv, 1101 char *result, unsigned maxlen) 1102{ 1103 int r = -EINVAL; 1104 struct dm_writecache *wc = ti->private; 1105 1106 if (!strcasecmp(argv[0], "flush")) 1107 r = process_flush_mesg(argc, argv, wc); 1108 else if (!strcasecmp(argv[0], "flush_on_suspend")) 1109 r = process_flush_on_suspend_mesg(argc, argv, wc); |
1110 else if (!strcasecmp(argv[0], "cleaner")) 1111 r = process_cleaner_mesg(argc, argv, wc); |
|
1034 else 1035 DMERR("unrecognised message received: %s", argv[0]); 1036 1037 return r; 1038} 1039 1040static void bio_copy_block(struct dm_writecache *wc, struct bio *bio, void *data) 1041{ --- 147 unchanged lines hidden (view full) --- 1189 if (next_boundary < bio->bi_iter.bi_size >> SECTOR_SHIFT) { 1190 dm_accept_partial_bio(bio, next_boundary); 1191 } 1192 } 1193 goto unlock_remap_origin; 1194 } 1195 } else { 1196 do { | 1112 else 1113 DMERR("unrecognised message received: %s", argv[0]); 1114 1115 return r; 1116} 1117 1118static void bio_copy_block(struct dm_writecache *wc, struct bio *bio, void *data) 1119{ --- 147 unchanged lines hidden (view full) --- 1267 if (next_boundary < bio->bi_iter.bi_size >> SECTOR_SHIFT) { 1268 dm_accept_partial_bio(bio, next_boundary); 1269 } 1270 } 1271 goto unlock_remap_origin; 1272 } 1273 } else { 1274 do { |
1275 bool found_entry = false; |
|
1197 if (writecache_has_error(wc)) 1198 goto unlock_error; 1199 e = writecache_find_entry(wc, bio->bi_iter.bi_sector, 0); 1200 if (e) { 1201 if (!writecache_entry_is_committed(wc, e)) 1202 goto bio_copy; 1203 if (!WC_MODE_PMEM(wc) && !e->write_in_progress) { 1204 wc->overwrote_committed = true; 1205 goto bio_copy; 1206 } | 1276 if (writecache_has_error(wc)) 1277 goto unlock_error; 1278 e = writecache_find_entry(wc, bio->bi_iter.bi_sector, 0); 1279 if (e) { 1280 if (!writecache_entry_is_committed(wc, e)) 1281 goto bio_copy; 1282 if (!WC_MODE_PMEM(wc) && !e->write_in_progress) { 1283 wc->overwrote_committed = true; 1284 goto bio_copy; 1285 } |
1286 found_entry = true; 1287 } else { 1288 if (unlikely(wc->cleaner)) 1289 goto direct_write; |
|
1207 } 1208 e = writecache_pop_from_freelist(wc, (sector_t)-1); 1209 if (unlikely(!e)) { | 1290 } 1291 e = writecache_pop_from_freelist(wc, (sector_t)-1); 1292 if (unlikely(!e)) { |
1293 if (!found_entry) { 1294direct_write: 1295 e = writecache_find_entry(wc, bio->bi_iter.bi_sector, WFE_RETURN_FOLLOWING); 1296 if (e) { 1297 sector_t next_boundary = read_original_sector(wc, e) - bio->bi_iter.bi_sector; 1298 BUG_ON(!next_boundary); 1299 if (next_boundary < bio->bi_iter.bi_size >> SECTOR_SHIFT) { 1300 dm_accept_partial_bio(bio, next_boundary); 1301 } 1302 } 1303 goto unlock_remap_origin; 1304 } |
|
1210 writecache_wait_on_freelist(wc); 1211 continue; 1212 } 1213 write_original_sector_seq_count(wc, e, bio->bi_iter.bi_sector, wc->seq_count); 1214 writecache_insert_entry(wc, e); 1215 wc->uncommitted_blocks++; 1216bio_copy: 1217 if (WC_MODE_PMEM(wc)) { --- 396 unchanged lines hidden (view full) --- 1614 } 1615 1616 n_walked = 0; 1617 INIT_LIST_HEAD(&skipped); 1618 INIT_LIST_HEAD(&wbl.list); 1619 wbl.size = 0; 1620 while (!list_empty(&wc->lru) && 1621 (wc->writeback_all || | 1305 writecache_wait_on_freelist(wc); 1306 continue; 1307 } 1308 write_original_sector_seq_count(wc, e, bio->bi_iter.bi_sector, wc->seq_count); 1309 writecache_insert_entry(wc, e); 1310 wc->uncommitted_blocks++; 1311bio_copy: 1312 if (WC_MODE_PMEM(wc)) { --- 396 unchanged lines hidden (view full) --- 1709 } 1710 1711 n_walked = 0; 1712 INIT_LIST_HEAD(&skipped); 1713 INIT_LIST_HEAD(&wbl.list); 1714 wbl.size = 0; 1715 while (!list_empty(&wc->lru) && 1716 (wc->writeback_all || |
1622 wc->freelist_size + wc->writeback_size <= wc->freelist_low_watermark)) { | 1717 wc->freelist_size + wc->writeback_size <= wc->freelist_low_watermark || 1718 (jiffies - container_of(wc->lru.prev, struct wc_entry, lru)->age >= 1719 wc->max_age - wc->max_age / MAX_AGE_DIV))) { |
1623 1624 n_walked++; 1625 if (unlikely(n_walked > WRITEBACK_LATENCY) && 1626 likely(!wc->writeback_all) && likely(!dm_suspended(wc->ti))) { 1627 queue_work(wc->writeback_wq, &wc->writeback_work); 1628 break; 1629 } 1630 --- 155 unchanged lines hidden (view full) --- 1786 1787 for (b = 0; b < ARRAY_SIZE(sb(wc)->padding); b++) 1788 pmem_assign(sb(wc)->padding[b], cpu_to_le64(0)); 1789 pmem_assign(sb(wc)->version, cpu_to_le32(MEMORY_SUPERBLOCK_VERSION)); 1790 pmem_assign(sb(wc)->block_size, cpu_to_le32(wc->block_size)); 1791 pmem_assign(sb(wc)->n_blocks, cpu_to_le64(wc->n_blocks)); 1792 pmem_assign(sb(wc)->seq_count, cpu_to_le64(0)); 1793 | 1720 1721 n_walked++; 1722 if (unlikely(n_walked > WRITEBACK_LATENCY) && 1723 likely(!wc->writeback_all) && likely(!dm_suspended(wc->ti))) { 1724 queue_work(wc->writeback_wq, &wc->writeback_work); 1725 break; 1726 } 1727 --- 155 unchanged lines hidden (view full) --- 1883 1884 for (b = 0; b < ARRAY_SIZE(sb(wc)->padding); b++) 1885 pmem_assign(sb(wc)->padding[b], cpu_to_le64(0)); 1886 pmem_assign(sb(wc)->version, cpu_to_le32(MEMORY_SUPERBLOCK_VERSION)); 1887 pmem_assign(sb(wc)->block_size, cpu_to_le32(wc->block_size)); 1888 pmem_assign(sb(wc)->n_blocks, cpu_to_le64(wc->n_blocks)); 1889 pmem_assign(sb(wc)->seq_count, cpu_to_le64(0)); 1890 |
1794 for (b = 0; b < wc->n_blocks; b++) | 1891 for (b = 0; b < wc->n_blocks; b++) { |
1795 write_original_sector_seq_count(wc, &wc->entries[b], -1, -1); | 1892 write_original_sector_seq_count(wc, &wc->entries[b], -1, -1); |
1893 cond_resched(); 1894 } |
|
1796 1797 writecache_flush_all_metadata(wc); 1798 writecache_commit_flushed(wc, false); 1799 pmem_assign(sb(wc)->magic, cpu_to_le32(MEMORY_SUPERBLOCK_MAGIC)); 1800 writecache_flush_region(wc, &sb(wc)->magic, sizeof sb(wc)->magic); 1801 writecache_commit_flushed(wc, false); 1802 1803 return 0; --- 73 unchanged lines hidden (view full) --- 1877 ti->error = "Cannot allocate writecache structure"; 1878 r = -ENOMEM; 1879 goto bad; 1880 } 1881 ti->private = wc; 1882 wc->ti = ti; 1883 1884 mutex_init(&wc->lock); | 1895 1896 writecache_flush_all_metadata(wc); 1897 writecache_commit_flushed(wc, false); 1898 pmem_assign(sb(wc)->magic, cpu_to_le32(MEMORY_SUPERBLOCK_MAGIC)); 1899 writecache_flush_region(wc, &sb(wc)->magic, sizeof sb(wc)->magic); 1900 writecache_commit_flushed(wc, false); 1901 1902 return 0; --- 73 unchanged lines hidden (view full) --- 1976 ti->error = "Cannot allocate writecache structure"; 1977 r = -ENOMEM; 1978 goto bad; 1979 } 1980 ti->private = wc; 1981 wc->ti = ti; 1982 1983 mutex_init(&wc->lock); |
1984 wc->max_age = MAX_AGE_UNSPECIFIED; |
|
1885 writecache_poison_lists(wc); 1886 init_waitqueue_head(&wc->freelist_wait); 1887 timer_setup(&wc->autocommit_timer, writecache_autocommit_timer, 0); | 1985 writecache_poison_lists(wc); 1986 init_waitqueue_head(&wc->freelist_wait); 1987 timer_setup(&wc->autocommit_timer, writecache_autocommit_timer, 0); |
1988 timer_setup(&wc->max_age_timer, writecache_max_age_timer, 0); |
|
1888 1889 for (i = 0; i < 2; i++) { 1890 atomic_set(&wc->bio_in_progress[i], 0); 1891 init_waitqueue_head(&wc->bio_in_progress_wait[i]); 1892 } 1893 1894 wc->dm_io = dm_io_client_create(); 1895 if (IS_ERR(wc->dm_io)) { --- 157 unchanged lines hidden (view full) --- 2053 unsigned autocommit_msecs; 2054 string = dm_shift_arg(&as), opt_params--; 2055 if (sscanf(string, "%u%c", &autocommit_msecs, &dummy) != 1) 2056 goto invalid_optional; 2057 if (autocommit_msecs > 3600000) 2058 goto invalid_optional; 2059 wc->autocommit_jiffies = msecs_to_jiffies(autocommit_msecs); 2060 wc->autocommit_time_set = true; | 1989 1990 for (i = 0; i < 2; i++) { 1991 atomic_set(&wc->bio_in_progress[i], 0); 1992 init_waitqueue_head(&wc->bio_in_progress_wait[i]); 1993 } 1994 1995 wc->dm_io = dm_io_client_create(); 1996 if (IS_ERR(wc->dm_io)) { --- 157 unchanged lines hidden (view full) --- 2154 unsigned autocommit_msecs; 2155 string = dm_shift_arg(&as), opt_params--; 2156 if (sscanf(string, "%u%c", &autocommit_msecs, &dummy) != 1) 2157 goto invalid_optional; 2158 if (autocommit_msecs > 3600000) 2159 goto invalid_optional; 2160 wc->autocommit_jiffies = msecs_to_jiffies(autocommit_msecs); 2161 wc->autocommit_time_set = true; |
2162 } else if (!strcasecmp(string, "max_age") && opt_params >= 1) { 2163 unsigned max_age_msecs; 2164 string = dm_shift_arg(&as), opt_params--; 2165 if (sscanf(string, "%u%c", &max_age_msecs, &dummy) != 1) 2166 goto invalid_optional; 2167 if (max_age_msecs > 86400000) 2168 goto invalid_optional; 2169 wc->max_age = msecs_to_jiffies(max_age_msecs); 2170 } else if (!strcasecmp(string, "cleaner")) { 2171 wc->cleaner = true; |
|
2061 } else if (!strcasecmp(string, "fua")) { 2062 if (WC_MODE_PMEM(wc)) { 2063 wc->writeback_fua = true; 2064 wc->writeback_fua_set = true; 2065 } else goto invalid_optional; 2066 } else if (!strcasecmp(string, "nofua")) { 2067 if (WC_MODE_PMEM(wc)) { 2068 wc->writeback_fua = false; --- 161 unchanged lines hidden (view full) --- 2230 x += 50; 2231 do_div(x, 100); 2232 wc->freelist_high_watermark = x; 2233 x = (uint64_t)wc->n_blocks * (100 - low_wm_percent); 2234 x += 50; 2235 do_div(x, 100); 2236 wc->freelist_low_watermark = x; 2237 | 2172 } else if (!strcasecmp(string, "fua")) { 2173 if (WC_MODE_PMEM(wc)) { 2174 wc->writeback_fua = true; 2175 wc->writeback_fua_set = true; 2176 } else goto invalid_optional; 2177 } else if (!strcasecmp(string, "nofua")) { 2178 if (WC_MODE_PMEM(wc)) { 2179 wc->writeback_fua = false; --- 161 unchanged lines hidden (view full) --- 2341 x += 50; 2342 do_div(x, 100); 2343 wc->freelist_high_watermark = x; 2344 x = (uint64_t)wc->n_blocks * (100 - low_wm_percent); 2345 x += 50; 2346 do_div(x, 100); 2347 wc->freelist_low_watermark = x; 2348 |
2349 if (wc->cleaner) 2350 activate_cleaner(wc); 2351 |
|
2238 r = writecache_alloc_entries(wc); 2239 if (r) { 2240 ti->error = "Cannot allocate memory"; 2241 goto bad; 2242 } 2243 2244 ti->num_flush_bios = 1; 2245 ti->flush_supported = true; --- 27 unchanged lines hidden (view full) --- 2273 (unsigned long long)wc->writeback_size); 2274 break; 2275 case STATUSTYPE_TABLE: 2276 DMEMIT("%c %s %s %u ", WC_MODE_PMEM(wc) ? 'p' : 's', 2277 wc->dev->name, wc->ssd_dev->name, wc->block_size); 2278 extra_args = 0; 2279 if (wc->start_sector) 2280 extra_args += 2; | 2352 r = writecache_alloc_entries(wc); 2353 if (r) { 2354 ti->error = "Cannot allocate memory"; 2355 goto bad; 2356 } 2357 2358 ti->num_flush_bios = 1; 2359 ti->flush_supported = true; --- 27 unchanged lines hidden (view full) --- 2387 (unsigned long long)wc->writeback_size); 2388 break; 2389 case STATUSTYPE_TABLE: 2390 DMEMIT("%c %s %s %u ", WC_MODE_PMEM(wc) ? 'p' : 's', 2391 wc->dev->name, wc->ssd_dev->name, wc->block_size); 2392 extra_args = 0; 2393 if (wc->start_sector) 2394 extra_args += 2; |
2281 if (wc->high_wm_percent_set) | 2395 if (wc->high_wm_percent_set && !wc->cleaner) |
2282 extra_args += 2; | 2396 extra_args += 2; |
2283 if (wc->low_wm_percent_set) | 2397 if (wc->low_wm_percent_set && !wc->cleaner) |
2284 extra_args += 2; 2285 if (wc->max_writeback_jobs_set) 2286 extra_args += 2; 2287 if (wc->autocommit_blocks_set) 2288 extra_args += 2; 2289 if (wc->autocommit_time_set) 2290 extra_args += 2; | 2398 extra_args += 2; 2399 if (wc->max_writeback_jobs_set) 2400 extra_args += 2; 2401 if (wc->autocommit_blocks_set) 2402 extra_args += 2; 2403 if (wc->autocommit_time_set) 2404 extra_args += 2; |
2405 if (wc->cleaner) 2406 extra_args++; |
|
2291 if (wc->writeback_fua_set) 2292 extra_args++; 2293 2294 DMEMIT("%u", extra_args); 2295 if (wc->start_sector) 2296 DMEMIT(" start_sector %llu", (unsigned long long)wc->start_sector); | 2407 if (wc->writeback_fua_set) 2408 extra_args++; 2409 2410 DMEMIT("%u", extra_args); 2411 if (wc->start_sector) 2412 DMEMIT(" start_sector %llu", (unsigned long long)wc->start_sector); |
2297 if (wc->high_wm_percent_set) { | 2413 if (wc->high_wm_percent_set && !wc->cleaner) { |
2298 x = (uint64_t)wc->freelist_high_watermark * 100; 2299 x += wc->n_blocks / 2; 2300 do_div(x, (size_t)wc->n_blocks); 2301 DMEMIT(" high_watermark %u", 100 - (unsigned)x); 2302 } | 2414 x = (uint64_t)wc->freelist_high_watermark * 100; 2415 x += wc->n_blocks / 2; 2416 do_div(x, (size_t)wc->n_blocks); 2417 DMEMIT(" high_watermark %u", 100 - (unsigned)x); 2418 } |
2303 if (wc->low_wm_percent_set) { | 2419 if (wc->low_wm_percent_set && !wc->cleaner) { |
2304 x = (uint64_t)wc->freelist_low_watermark * 100; 2305 x += wc->n_blocks / 2; 2306 do_div(x, (size_t)wc->n_blocks); 2307 DMEMIT(" low_watermark %u", 100 - (unsigned)x); 2308 } 2309 if (wc->max_writeback_jobs_set) 2310 DMEMIT(" writeback_jobs %u", wc->max_writeback_jobs); 2311 if (wc->autocommit_blocks_set) 2312 DMEMIT(" autocommit_blocks %u", wc->autocommit_blocks); 2313 if (wc->autocommit_time_set) 2314 DMEMIT(" autocommit_time %u", jiffies_to_msecs(wc->autocommit_jiffies)); | 2420 x = (uint64_t)wc->freelist_low_watermark * 100; 2421 x += wc->n_blocks / 2; 2422 do_div(x, (size_t)wc->n_blocks); 2423 DMEMIT(" low_watermark %u", 100 - (unsigned)x); 2424 } 2425 if (wc->max_writeback_jobs_set) 2426 DMEMIT(" writeback_jobs %u", wc->max_writeback_jobs); 2427 if (wc->autocommit_blocks_set) 2428 DMEMIT(" autocommit_blocks %u", wc->autocommit_blocks); 2429 if (wc->autocommit_time_set) 2430 DMEMIT(" autocommit_time %u", jiffies_to_msecs(wc->autocommit_jiffies)); |
2431 if (wc->max_age != MAX_AGE_UNSPECIFIED) 2432 DMEMIT(" max_age %u", jiffies_to_msecs(wc->max_age)); 2433 if (wc->cleaner) 2434 DMEMIT(" cleaner"); |
|
2315 if (wc->writeback_fua_set) 2316 DMEMIT(" %sfua", wc->writeback_fua ? "" : "no"); 2317 break; 2318 } 2319} 2320 2321static struct target_type writecache_target = { 2322 .name = "writecache", | 2435 if (wc->writeback_fua_set) 2436 DMEMIT(" %sfua", wc->writeback_fua ? "" : "no"); 2437 break; 2438 } 2439} 2440 2441static struct target_type writecache_target = { 2442 .name = "writecache", |
2323 .version = {1, 2, 0}, | 2443 .version = {1, 3, 0}, |
2324 .module = THIS_MODULE, 2325 .ctr = writecache_ctr, 2326 .dtr = writecache_dtr, 2327 .status = writecache_status, 2328 .postsuspend = writecache_suspend, 2329 .resume = writecache_resume, 2330 .message = writecache_message, 2331 .map = writecache_map, --- 29 unchanged lines hidden --- | 2444 .module = THIS_MODULE, 2445 .ctr = writecache_ctr, 2446 .dtr = writecache_dtr, 2447 .status = writecache_status, 2448 .postsuspend = writecache_suspend, 2449 .resume = writecache_resume, 2450 .message = writecache_message, 2451 .map = writecache_map, --- 29 unchanged lines hidden --- |