aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/dm-log.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/md/dm-log.c')
-rw-r--r--drivers/md/dm-log.c254
1 files changed, 164 insertions, 90 deletions
diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c
index 2a74b2142f50..67a6f31b7fc3 100644
--- a/drivers/md/dm-log.c
+++ b/drivers/md/dm-log.c
@@ -1,5 +1,6 @@
1/* 1/*
2 * Copyright (C) 2003 Sistina Software 2 * Copyright (C) 2003 Sistina Software
3 * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
3 * 4 *
4 * This file is released under the LGPL. 5 * This file is released under the LGPL.
5 */ 6 */
@@ -8,64 +9,58 @@
8#include <linux/slab.h> 9#include <linux/slab.h>
9#include <linux/module.h> 10#include <linux/module.h>
10#include <linux/vmalloc.h> 11#include <linux/vmalloc.h>
12#include <linux/dm-io.h>
13#include <linux/dm-dirty-log.h>
11 14
12#include "dm-log.h" 15#include "dm.h"
13#include "dm-io.h"
14 16
15#define DM_MSG_PREFIX "mirror log" 17#define DM_MSG_PREFIX "dirty region log"
16 18
17static LIST_HEAD(_log_types); 19struct dm_dirty_log_internal {
18static DEFINE_SPINLOCK(_lock); 20 struct dm_dirty_log_type *type;
19 21
20int dm_register_dirty_log_type(struct dirty_log_type *type) 22 struct list_head list;
21{ 23 long use;
22 spin_lock(&_lock); 24};
23 type->use_count = 0;
24 list_add(&type->list, &_log_types);
25 spin_unlock(&_lock);
26 25
27 return 0; 26static LIST_HEAD(_log_types);
28} 27static DEFINE_SPINLOCK(_lock);
29 28
30int dm_unregister_dirty_log_type(struct dirty_log_type *type) 29static struct dm_dirty_log_internal *__find_dirty_log_type(const char *name)
31{ 30{
32 spin_lock(&_lock); 31 struct dm_dirty_log_internal *log_type;
33
34 if (type->use_count)
35 DMWARN("Attempt to unregister a log type that is still in use");
36 else
37 list_del(&type->list);
38 32
39 spin_unlock(&_lock); 33 list_for_each_entry(log_type, &_log_types, list)
34 if (!strcmp(name, log_type->type->name))
35 return log_type;
40 36
41 return 0; 37 return NULL;
42} 38}
43 39
44static struct dirty_log_type *_get_type(const char *type_name) 40static struct dm_dirty_log_internal *_get_dirty_log_type(const char *name)
45{ 41{
46 struct dirty_log_type *type; 42 struct dm_dirty_log_internal *log_type;
47 43
48 spin_lock(&_lock); 44 spin_lock(&_lock);
49 list_for_each_entry (type, &_log_types, list) 45
50 if (!strcmp(type_name, type->name)) { 46 log_type = __find_dirty_log_type(name);
51 if (!type->use_count && !try_module_get(type->module)){ 47 if (log_type) {
52 spin_unlock(&_lock); 48 if (!log_type->use && !try_module_get(log_type->type->module))
53 return NULL; 49 log_type = NULL;
54 } 50 else
55 type->use_count++; 51 log_type->use++;
56 spin_unlock(&_lock); 52 }
57 return type;
58 }
59 53
60 spin_unlock(&_lock); 54 spin_unlock(&_lock);
61 return NULL; 55
56 return log_type;
62} 57}
63 58
64/* 59/*
65 * get_type 60 * get_type
66 * @type_name 61 * @type_name
67 * 62 *
68 * Attempt to retrieve the dirty_log_type by name. If not already 63 * Attempt to retrieve the dm_dirty_log_type by name. If not already
69 * available, attempt to load the appropriate module. 64 * available, attempt to load the appropriate module.
70 * 65 *
71 * Log modules are named "dm-log-" followed by the 'type_name'. 66 * Log modules are named "dm-log-" followed by the 'type_name'.
@@ -78,14 +73,17 @@ static struct dirty_log_type *_get_type(const char *type_name)
78 * 73 *
79 * Returns: dirty_log_type* on success, NULL on failure 74 * Returns: dirty_log_type* on success, NULL on failure
80 */ 75 */
81static struct dirty_log_type *get_type(const char *type_name) 76static struct dm_dirty_log_type *get_type(const char *type_name)
82{ 77{
83 char *p, *type_name_dup; 78 char *p, *type_name_dup;
84 struct dirty_log_type *type; 79 struct dm_dirty_log_internal *log_type;
80
81 if (!type_name)
82 return NULL;
85 83
86 type = _get_type(type_name); 84 log_type = _get_dirty_log_type(type_name);
87 if (type) 85 if (log_type)
88 return type; 86 return log_type->type;
89 87
90 type_name_dup = kstrdup(type_name, GFP_KERNEL); 88 type_name_dup = kstrdup(type_name, GFP_KERNEL);
91 if (!type_name_dup) { 89 if (!type_name_dup) {
@@ -95,34 +93,106 @@ static struct dirty_log_type *get_type(const char *type_name)
95 } 93 }
96 94
97 while (request_module("dm-log-%s", type_name_dup) || 95 while (request_module("dm-log-%s", type_name_dup) ||
98 !(type = _get_type(type_name))) { 96 !(log_type = _get_dirty_log_type(type_name))) {
99 p = strrchr(type_name_dup, '-'); 97 p = strrchr(type_name_dup, '-');
100 if (!p) 98 if (!p)
101 break; 99 break;
102 p[0] = '\0'; 100 p[0] = '\0';
103 } 101 }
104 102
105 if (!type) 103 if (!log_type)
106 DMWARN("Module for logging type \"%s\" not found.", type_name); 104 DMWARN("Module for logging type \"%s\" not found.", type_name);
107 105
108 kfree(type_name_dup); 106 kfree(type_name_dup);
109 107
110 return type; 108 return log_type ? log_type->type : NULL;
111} 109}
112 110
113static void put_type(struct dirty_log_type *type) 111static void put_type(struct dm_dirty_log_type *type)
114{ 112{
113 struct dm_dirty_log_internal *log_type;
114
115 if (!type)
116 return;
117
115 spin_lock(&_lock); 118 spin_lock(&_lock);
116 if (!--type->use_count) 119 log_type = __find_dirty_log_type(type->name);
120 if (!log_type)
121 goto out;
122
123 if (!--log_type->use)
117 module_put(type->module); 124 module_put(type->module);
125
126 BUG_ON(log_type->use < 0);
127
128out:
118 spin_unlock(&_lock); 129 spin_unlock(&_lock);
119} 130}
120 131
121struct dirty_log *dm_create_dirty_log(const char *type_name, struct dm_target *ti, 132static struct dm_dirty_log_internal *_alloc_dirty_log_type(struct dm_dirty_log_type *type)
122 unsigned int argc, char **argv)
123{ 133{
124 struct dirty_log_type *type; 134 struct dm_dirty_log_internal *log_type = kzalloc(sizeof(*log_type),
125 struct dirty_log *log; 135 GFP_KERNEL);
136
137 if (log_type)
138 log_type->type = type;
139
140 return log_type;
141}
142
143int dm_dirty_log_type_register(struct dm_dirty_log_type *type)
144{
145 struct dm_dirty_log_internal *log_type = _alloc_dirty_log_type(type);
146 int r = 0;
147
148 if (!log_type)
149 return -ENOMEM;
150
151 spin_lock(&_lock);
152 if (!__find_dirty_log_type(type->name))
153 list_add(&log_type->list, &_log_types);
154 else {
155 kfree(log_type);
156 r = -EEXIST;
157 }
158 spin_unlock(&_lock);
159
160 return r;
161}
162EXPORT_SYMBOL(dm_dirty_log_type_register);
163
164int dm_dirty_log_type_unregister(struct dm_dirty_log_type *type)
165{
166 struct dm_dirty_log_internal *log_type;
167
168 spin_lock(&_lock);
169
170 log_type = __find_dirty_log_type(type->name);
171 if (!log_type) {
172 spin_unlock(&_lock);
173 return -EINVAL;
174 }
175
176 if (log_type->use) {
177 spin_unlock(&_lock);
178 return -ETXTBSY;
179 }
180
181 list_del(&log_type->list);
182
183 spin_unlock(&_lock);
184 kfree(log_type);
185
186 return 0;
187}
188EXPORT_SYMBOL(dm_dirty_log_type_unregister);
189
190struct dm_dirty_log *dm_dirty_log_create(const char *type_name,
191 struct dm_target *ti,
192 unsigned int argc, char **argv)
193{
194 struct dm_dirty_log_type *type;
195 struct dm_dirty_log *log;
126 196
127 log = kmalloc(sizeof(*log), GFP_KERNEL); 197 log = kmalloc(sizeof(*log), GFP_KERNEL);
128 if (!log) 198 if (!log)
@@ -143,13 +213,15 @@ struct dirty_log *dm_create_dirty_log(const char *type_name, struct dm_target *t
143 213
144 return log; 214 return log;
145} 215}
216EXPORT_SYMBOL(dm_dirty_log_create);
146 217
147void dm_destroy_dirty_log(struct dirty_log *log) 218void dm_dirty_log_destroy(struct dm_dirty_log *log)
148{ 219{
149 log->type->dtr(log); 220 log->type->dtr(log);
150 put_type(log->type); 221 put_type(log->type);
151 kfree(log); 222 kfree(log);
152} 223}
224EXPORT_SYMBOL(dm_dirty_log_destroy);
153 225
154/*----------------------------------------------------------------- 226/*-----------------------------------------------------------------
155 * Persistent and core logs share a lot of their implementation. 227 * Persistent and core logs share a lot of their implementation.
@@ -207,7 +279,7 @@ struct log_c {
207 struct dm_dev *log_dev; 279 struct dm_dev *log_dev;
208 struct log_header header; 280 struct log_header header;
209 281
210 struct io_region header_location; 282 struct dm_io_region header_location;
211 struct log_header *disk_header; 283 struct log_header *disk_header;
212}; 284};
213 285
@@ -215,7 +287,7 @@ struct log_c {
215 * The touched member needs to be updated every time we access 287 * The touched member needs to be updated every time we access
216 * one of the bitsets. 288 * one of the bitsets.
217 */ 289 */
218static inline int log_test_bit(uint32_t *bs, unsigned bit) 290static inline int log_test_bit(uint32_t *bs, unsigned bit)
219{ 291{
220 return ext2_test_bit(bit, (unsigned long *) bs) ? 1 : 0; 292 return ext2_test_bit(bit, (unsigned long *) bs) ? 1 : 0;
221} 293}
@@ -302,7 +374,7 @@ static inline int write_header(struct log_c *log)
302 * argv contains region_size followed optionally by [no]sync 374 * argv contains region_size followed optionally by [no]sync
303 *--------------------------------------------------------------*/ 375 *--------------------------------------------------------------*/
304#define BYTE_SHIFT 3 376#define BYTE_SHIFT 3
305static int create_log_context(struct dirty_log *log, struct dm_target *ti, 377static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti,
306 unsigned int argc, char **argv, 378 unsigned int argc, char **argv,
307 struct dm_dev *dev) 379 struct dm_dev *dev)
308{ 380{
@@ -315,7 +387,7 @@ static int create_log_context(struct dirty_log *log, struct dm_target *ti,
315 int r; 387 int r;
316 388
317 if (argc < 1 || argc > 2) { 389 if (argc < 1 || argc > 2) {
318 DMWARN("wrong number of arguments to mirror log"); 390 DMWARN("wrong number of arguments to dirty region log");
319 return -EINVAL; 391 return -EINVAL;
320 } 392 }
321 393
@@ -325,8 +397,8 @@ static int create_log_context(struct dirty_log *log, struct dm_target *ti,
325 else if (!strcmp(argv[1], "nosync")) 397 else if (!strcmp(argv[1], "nosync"))
326 sync = NOSYNC; 398 sync = NOSYNC;
327 else { 399 else {
328 DMWARN("unrecognised sync argument to mirror log: %s", 400 DMWARN("unrecognised sync argument to "
329 argv[1]); 401 "dirty region log: %s", argv[1]);
330 return -EINVAL; 402 return -EINVAL;
331 } 403 }
332 } 404 }
@@ -434,7 +506,7 @@ static int create_log_context(struct dirty_log *log, struct dm_target *ti,
434 return 0; 506 return 0;
435} 507}
436 508
437static int core_ctr(struct dirty_log *log, struct dm_target *ti, 509static int core_ctr(struct dm_dirty_log *log, struct dm_target *ti,
438 unsigned int argc, char **argv) 510 unsigned int argc, char **argv)
439{ 511{
440 return create_log_context(log, ti, argc, argv, NULL); 512 return create_log_context(log, ti, argc, argv, NULL);
@@ -447,7 +519,7 @@ static void destroy_log_context(struct log_c *lc)
447 kfree(lc); 519 kfree(lc);
448} 520}
449 521
450static void core_dtr(struct dirty_log *log) 522static void core_dtr(struct dm_dirty_log *log)
451{ 523{
452 struct log_c *lc = (struct log_c *) log->context; 524 struct log_c *lc = (struct log_c *) log->context;
453 525
@@ -460,14 +532,14 @@ static void core_dtr(struct dirty_log *log)
460 * 532 *
461 * argv contains log_device region_size followed optionally by [no]sync 533 * argv contains log_device region_size followed optionally by [no]sync
462 *--------------------------------------------------------------*/ 534 *--------------------------------------------------------------*/
463static int disk_ctr(struct dirty_log *log, struct dm_target *ti, 535static int disk_ctr(struct dm_dirty_log *log, struct dm_target *ti,
464 unsigned int argc, char **argv) 536 unsigned int argc, char **argv)
465{ 537{
466 int r; 538 int r;
467 struct dm_dev *dev; 539 struct dm_dev *dev;
468 540
469 if (argc < 2 || argc > 3) { 541 if (argc < 2 || argc > 3) {
470 DMWARN("wrong number of arguments to disk mirror log"); 542 DMWARN("wrong number of arguments to disk dirty region log");
471 return -EINVAL; 543 return -EINVAL;
472 } 544 }
473 545
@@ -485,7 +557,7 @@ static int disk_ctr(struct dirty_log *log, struct dm_target *ti,
485 return 0; 557 return 0;
486} 558}
487 559
488static void disk_dtr(struct dirty_log *log) 560static void disk_dtr(struct dm_dirty_log *log)
489{ 561{
490 struct log_c *lc = (struct log_c *) log->context; 562 struct log_c *lc = (struct log_c *) log->context;
491 563
@@ -514,7 +586,7 @@ static void fail_log_device(struct log_c *lc)
514 dm_table_event(lc->ti->table); 586 dm_table_event(lc->ti->table);
515} 587}
516 588
517static int disk_resume(struct dirty_log *log) 589static int disk_resume(struct dm_dirty_log *log)
518{ 590{
519 int r; 591 int r;
520 unsigned i; 592 unsigned i;
@@ -524,7 +596,7 @@ static int disk_resume(struct dirty_log *log)
524 /* read the disk header */ 596 /* read the disk header */
525 r = read_header(lc); 597 r = read_header(lc);
526 if (r) { 598 if (r) {
527 DMWARN("%s: Failed to read header on mirror log device", 599 DMWARN("%s: Failed to read header on dirty region log device",
528 lc->log_dev->name); 600 lc->log_dev->name);
529 fail_log_device(lc); 601 fail_log_device(lc);
530 /* 602 /*
@@ -562,7 +634,7 @@ static int disk_resume(struct dirty_log *log)
562 /* write the new header */ 634 /* write the new header */
563 r = write_header(lc); 635 r = write_header(lc);
564 if (r) { 636 if (r) {
565 DMWARN("%s: Failed to write header on mirror log device", 637 DMWARN("%s: Failed to write header on dirty region log device",
566 lc->log_dev->name); 638 lc->log_dev->name);
567 fail_log_device(lc); 639 fail_log_device(lc);
568 } 640 }
@@ -570,38 +642,38 @@ static int disk_resume(struct dirty_log *log)
570 return r; 642 return r;
571} 643}
572 644
573static uint32_t core_get_region_size(struct dirty_log *log) 645static uint32_t core_get_region_size(struct dm_dirty_log *log)
574{ 646{
575 struct log_c *lc = (struct log_c *) log->context; 647 struct log_c *lc = (struct log_c *) log->context;
576 return lc->region_size; 648 return lc->region_size;
577} 649}
578 650
579static int core_resume(struct dirty_log *log) 651static int core_resume(struct dm_dirty_log *log)
580{ 652{
581 struct log_c *lc = (struct log_c *) log->context; 653 struct log_c *lc = (struct log_c *) log->context;
582 lc->sync_search = 0; 654 lc->sync_search = 0;
583 return 0; 655 return 0;
584} 656}
585 657
586static int core_is_clean(struct dirty_log *log, region_t region) 658static int core_is_clean(struct dm_dirty_log *log, region_t region)
587{ 659{
588 struct log_c *lc = (struct log_c *) log->context; 660 struct log_c *lc = (struct log_c *) log->context;
589 return log_test_bit(lc->clean_bits, region); 661 return log_test_bit(lc->clean_bits, region);
590} 662}
591 663
592static int core_in_sync(struct dirty_log *log, region_t region, int block) 664static int core_in_sync(struct dm_dirty_log *log, region_t region, int block)
593{ 665{
594 struct log_c *lc = (struct log_c *) log->context; 666 struct log_c *lc = (struct log_c *) log->context;
595 return log_test_bit(lc->sync_bits, region); 667 return log_test_bit(lc->sync_bits, region);
596} 668}
597 669
598static int core_flush(struct dirty_log *log) 670static int core_flush(struct dm_dirty_log *log)
599{ 671{
600 /* no op */ 672 /* no op */
601 return 0; 673 return 0;
602} 674}
603 675
604static int disk_flush(struct dirty_log *log) 676static int disk_flush(struct dm_dirty_log *log)
605{ 677{
606 int r; 678 int r;
607 struct log_c *lc = (struct log_c *) log->context; 679 struct log_c *lc = (struct log_c *) log->context;
@@ -619,19 +691,19 @@ static int disk_flush(struct dirty_log *log)
619 return r; 691 return r;
620} 692}
621 693
622static void core_mark_region(struct dirty_log *log, region_t region) 694static void core_mark_region(struct dm_dirty_log *log, region_t region)
623{ 695{
624 struct log_c *lc = (struct log_c *) log->context; 696 struct log_c *lc = (struct log_c *) log->context;
625 log_clear_bit(lc, lc->clean_bits, region); 697 log_clear_bit(lc, lc->clean_bits, region);
626} 698}
627 699
628static void core_clear_region(struct dirty_log *log, region_t region) 700static void core_clear_region(struct dm_dirty_log *log, region_t region)
629{ 701{
630 struct log_c *lc = (struct log_c *) log->context; 702 struct log_c *lc = (struct log_c *) log->context;
631 log_set_bit(lc, lc->clean_bits, region); 703 log_set_bit(lc, lc->clean_bits, region);
632} 704}
633 705
634static int core_get_resync_work(struct dirty_log *log, region_t *region) 706static int core_get_resync_work(struct dm_dirty_log *log, region_t *region)
635{ 707{
636 struct log_c *lc = (struct log_c *) log->context; 708 struct log_c *lc = (struct log_c *) log->context;
637 709
@@ -654,7 +726,7 @@ static int core_get_resync_work(struct dirty_log *log, region_t *region)
654 return 1; 726 return 1;
655} 727}
656 728
657static void core_set_region_sync(struct dirty_log *log, region_t region, 729static void core_set_region_sync(struct dm_dirty_log *log, region_t region,
658 int in_sync) 730 int in_sync)
659{ 731{
660 struct log_c *lc = (struct log_c *) log->context; 732 struct log_c *lc = (struct log_c *) log->context;
@@ -669,7 +741,7 @@ static void core_set_region_sync(struct dirty_log *log, region_t region,
669 } 741 }
670} 742}
671 743
672static region_t core_get_sync_count(struct dirty_log *log) 744static region_t core_get_sync_count(struct dm_dirty_log *log)
673{ 745{
674 struct log_c *lc = (struct log_c *) log->context; 746 struct log_c *lc = (struct log_c *) log->context;
675 747
@@ -680,7 +752,7 @@ static region_t core_get_sync_count(struct dirty_log *log)
680 if (lc->sync != DEFAULTSYNC) \ 752 if (lc->sync != DEFAULTSYNC) \
681 DMEMIT("%ssync ", lc->sync == NOSYNC ? "no" : "") 753 DMEMIT("%ssync ", lc->sync == NOSYNC ? "no" : "")
682 754
683static int core_status(struct dirty_log *log, status_type_t status, 755static int core_status(struct dm_dirty_log *log, status_type_t status,
684 char *result, unsigned int maxlen) 756 char *result, unsigned int maxlen)
685{ 757{
686 int sz = 0; 758 int sz = 0;
@@ -700,7 +772,7 @@ static int core_status(struct dirty_log *log, status_type_t status,
700 return sz; 772 return sz;
701} 773}
702 774
703static int disk_status(struct dirty_log *log, status_type_t status, 775static int disk_status(struct dm_dirty_log *log, status_type_t status,
704 char *result, unsigned int maxlen) 776 char *result, unsigned int maxlen)
705{ 777{
706 int sz = 0; 778 int sz = 0;
@@ -722,7 +794,7 @@ static int disk_status(struct dirty_log *log, status_type_t status,
722 return sz; 794 return sz;
723} 795}
724 796
725static struct dirty_log_type _core_type = { 797static struct dm_dirty_log_type _core_type = {
726 .name = "core", 798 .name = "core",
727 .module = THIS_MODULE, 799 .module = THIS_MODULE,
728 .ctr = core_ctr, 800 .ctr = core_ctr,
@@ -740,7 +812,7 @@ static struct dirty_log_type _core_type = {
740 .status = core_status, 812 .status = core_status,
741}; 813};
742 814
743static struct dirty_log_type _disk_type = { 815static struct dm_dirty_log_type _disk_type = {
744 .name = "disk", 816 .name = "disk",
745 .module = THIS_MODULE, 817 .module = THIS_MODULE,
746 .ctr = disk_ctr, 818 .ctr = disk_ctr,
@@ -763,26 +835,28 @@ int __init dm_dirty_log_init(void)
763{ 835{
764 int r; 836 int r;
765 837
766 r = dm_register_dirty_log_type(&_core_type); 838 r = dm_dirty_log_type_register(&_core_type);
767 if (r) 839 if (r)
768 DMWARN("couldn't register core log"); 840 DMWARN("couldn't register core log");
769 841
770 r = dm_register_dirty_log_type(&_disk_type); 842 r = dm_dirty_log_type_register(&_disk_type);
771 if (r) { 843 if (r) {
772 DMWARN("couldn't register disk type"); 844 DMWARN("couldn't register disk type");
773 dm_unregister_dirty_log_type(&_core_type); 845 dm_dirty_log_type_unregister(&_core_type);
774 } 846 }
775 847
776 return r; 848 return r;
777} 849}
778 850
779void dm_dirty_log_exit(void) 851void __exit dm_dirty_log_exit(void)
780{ 852{
781 dm_unregister_dirty_log_type(&_disk_type); 853 dm_dirty_log_type_unregister(&_disk_type);
782 dm_unregister_dirty_log_type(&_core_type); 854 dm_dirty_log_type_unregister(&_core_type);
783} 855}
784 856
785EXPORT_SYMBOL(dm_register_dirty_log_type); 857module_init(dm_dirty_log_init);
786EXPORT_SYMBOL(dm_unregister_dirty_log_type); 858module_exit(dm_dirty_log_exit);
787EXPORT_SYMBOL(dm_create_dirty_log); 859
788EXPORT_SYMBOL(dm_destroy_dirty_log); 860MODULE_DESCRIPTION(DM_NAME " dirty region log");
861MODULE_AUTHOR("Joe Thornber, Heinz Mauelshagen <dm-devel@redhat.com>");
862MODULE_LICENSE("GPL");