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.c80
1 files changed, 65 insertions, 15 deletions
diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c
index 9443896ede07..5a08be0222db 100644
--- a/drivers/md/dm-log.c
+++ b/drivers/md/dm-log.c
@@ -145,8 +145,9 @@ int dm_dirty_log_type_unregister(struct dm_dirty_log_type *type)
145EXPORT_SYMBOL(dm_dirty_log_type_unregister); 145EXPORT_SYMBOL(dm_dirty_log_type_unregister);
146 146
147struct dm_dirty_log *dm_dirty_log_create(const char *type_name, 147struct dm_dirty_log *dm_dirty_log_create(const char *type_name,
148 struct dm_target *ti, 148 struct dm_target *ti,
149 unsigned int argc, char **argv) 149 int (*flush_callback_fn)(struct dm_target *ti),
150 unsigned int argc, char **argv)
150{ 151{
151 struct dm_dirty_log_type *type; 152 struct dm_dirty_log_type *type;
152 struct dm_dirty_log *log; 153 struct dm_dirty_log *log;
@@ -161,6 +162,7 @@ struct dm_dirty_log *dm_dirty_log_create(const char *type_name,
161 return NULL; 162 return NULL;
162 } 163 }
163 164
165 log->flush_callback_fn = flush_callback_fn;
164 log->type = type; 166 log->type = type;
165 if (type->ctr(log, ti, argc, argv)) { 167 if (type->ctr(log, ti, argc, argv)) {
166 kfree(log); 168 kfree(log);
@@ -208,7 +210,9 @@ struct log_header {
208 210
209struct log_c { 211struct log_c {
210 struct dm_target *ti; 212 struct dm_target *ti;
211 int touched; 213 int touched_dirtied;
214 int touched_cleaned;
215 int flush_failed;
212 uint32_t region_size; 216 uint32_t region_size;
213 unsigned int region_count; 217 unsigned int region_count;
214 region_t sync_count; 218 region_t sync_count;
@@ -233,6 +237,7 @@ struct log_c {
233 * Disk log fields 237 * Disk log fields
234 */ 238 */
235 int log_dev_failed; 239 int log_dev_failed;
240 int log_dev_flush_failed;
236 struct dm_dev *log_dev; 241 struct dm_dev *log_dev;
237 struct log_header header; 242 struct log_header header;
238 243
@@ -253,14 +258,14 @@ static inline void log_set_bit(struct log_c *l,
253 uint32_t *bs, unsigned bit) 258 uint32_t *bs, unsigned bit)
254{ 259{
255 ext2_set_bit(bit, (unsigned long *) bs); 260 ext2_set_bit(bit, (unsigned long *) bs);
256 l->touched = 1; 261 l->touched_cleaned = 1;
257} 262}
258 263
259static inline void log_clear_bit(struct log_c *l, 264static inline void log_clear_bit(struct log_c *l,
260 uint32_t *bs, unsigned bit) 265 uint32_t *bs, unsigned bit)
261{ 266{
262 ext2_clear_bit(bit, (unsigned long *) bs); 267 ext2_clear_bit(bit, (unsigned long *) bs);
263 l->touched = 1; 268 l->touched_dirtied = 1;
264} 269}
265 270
266/*---------------------------------------------------------------- 271/*----------------------------------------------------------------
@@ -287,6 +292,19 @@ static int rw_header(struct log_c *lc, int rw)
287 return dm_io(&lc->io_req, 1, &lc->header_location, NULL); 292 return dm_io(&lc->io_req, 1, &lc->header_location, NULL);
288} 293}
289 294
295static int flush_header(struct log_c *lc)
296{
297 struct dm_io_region null_location = {
298 .bdev = lc->header_location.bdev,
299 .sector = 0,
300 .count = 0,
301 };
302
303 lc->io_req.bi_rw = WRITE_BARRIER;
304
305 return dm_io(&lc->io_req, 1, &null_location, NULL);
306}
307
290static int read_header(struct log_c *log) 308static int read_header(struct log_c *log)
291{ 309{
292 int r; 310 int r;
@@ -378,7 +396,9 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti,
378 } 396 }
379 397
380 lc->ti = ti; 398 lc->ti = ti;
381 lc->touched = 0; 399 lc->touched_dirtied = 0;
400 lc->touched_cleaned = 0;
401 lc->flush_failed = 0;
382 lc->region_size = region_size; 402 lc->region_size = region_size;
383 lc->region_count = region_count; 403 lc->region_count = region_count;
384 lc->sync = sync; 404 lc->sync = sync;
@@ -406,6 +426,7 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti,
406 } else { 426 } else {
407 lc->log_dev = dev; 427 lc->log_dev = dev;
408 lc->log_dev_failed = 0; 428 lc->log_dev_failed = 0;
429 lc->log_dev_flush_failed = 0;
409 lc->header_location.bdev = lc->log_dev->bdev; 430 lc->header_location.bdev = lc->log_dev->bdev;
410 lc->header_location.sector = 0; 431 lc->header_location.sector = 0;
411 432
@@ -522,8 +543,7 @@ static int disk_ctr(struct dm_dirty_log *log, struct dm_target *ti,
522 return -EINVAL; 543 return -EINVAL;
523 } 544 }
524 545
525 r = dm_get_device(ti, argv[0], 0, 0 /* FIXME */, 546 r = dm_get_device(ti, argv[0], FMODE_READ | FMODE_WRITE, &dev);
526 FMODE_READ | FMODE_WRITE, &dev);
527 if (r) 547 if (r)
528 return r; 548 return r;
529 549
@@ -614,6 +634,11 @@ static int disk_resume(struct dm_dirty_log *log)
614 634
615 /* write the new header */ 635 /* write the new header */
616 r = rw_header(lc, WRITE); 636 r = rw_header(lc, WRITE);
637 if (!r) {
638 r = flush_header(lc);
639 if (r)
640 lc->log_dev_flush_failed = 1;
641 }
617 if (r) { 642 if (r) {
618 DMWARN("%s: Failed to write header on dirty region log device", 643 DMWARN("%s: Failed to write header on dirty region log device",
619 lc->log_dev->name); 644 lc->log_dev->name);
@@ -656,18 +681,40 @@ static int core_flush(struct dm_dirty_log *log)
656 681
657static int disk_flush(struct dm_dirty_log *log) 682static int disk_flush(struct dm_dirty_log *log)
658{ 683{
659 int r; 684 int r, i;
660 struct log_c *lc = (struct log_c *) log->context; 685 struct log_c *lc = log->context;
661 686
662 /* only write if the log has changed */ 687 /* only write if the log has changed */
663 if (!lc->touched) 688 if (!lc->touched_cleaned && !lc->touched_dirtied)
664 return 0; 689 return 0;
665 690
691 if (lc->touched_cleaned && log->flush_callback_fn &&
692 log->flush_callback_fn(lc->ti)) {
693 /*
694 * At this point it is impossible to determine which
695 * regions are clean and which are dirty (without
696 * re-reading the log off disk). So mark all of them
697 * dirty.
698 */
699 lc->flush_failed = 1;
700 for (i = 0; i < lc->region_count; i++)
701 log_clear_bit(lc, lc->clean_bits, i);
702 }
703
666 r = rw_header(lc, WRITE); 704 r = rw_header(lc, WRITE);
667 if (r) 705 if (r)
668 fail_log_device(lc); 706 fail_log_device(lc);
669 else 707 else {
670 lc->touched = 0; 708 if (lc->touched_dirtied) {
709 r = flush_header(lc);
710 if (r) {
711 lc->log_dev_flush_failed = 1;
712 fail_log_device(lc);
713 } else
714 lc->touched_dirtied = 0;
715 }
716 lc->touched_cleaned = 0;
717 }
671 718
672 return r; 719 return r;
673} 720}
@@ -681,7 +728,8 @@ static void core_mark_region(struct dm_dirty_log *log, region_t region)
681static void core_clear_region(struct dm_dirty_log *log, region_t region) 728static void core_clear_region(struct dm_dirty_log *log, region_t region)
682{ 729{
683 struct log_c *lc = (struct log_c *) log->context; 730 struct log_c *lc = (struct log_c *) log->context;
684 log_set_bit(lc, lc->clean_bits, region); 731 if (likely(!lc->flush_failed))
732 log_set_bit(lc, lc->clean_bits, region);
685} 733}
686 734
687static int core_get_resync_work(struct dm_dirty_log *log, region_t *region) 735static int core_get_resync_work(struct dm_dirty_log *log, region_t *region)
@@ -762,7 +810,9 @@ static int disk_status(struct dm_dirty_log *log, status_type_t status,
762 switch(status) { 810 switch(status) {
763 case STATUSTYPE_INFO: 811 case STATUSTYPE_INFO:
764 DMEMIT("3 %s %s %c", log->type->name, lc->log_dev->name, 812 DMEMIT("3 %s %s %c", log->type->name, lc->log_dev->name,
765 lc->log_dev_failed ? 'D' : 'A'); 813 lc->log_dev_flush_failed ? 'F' :
814 lc->log_dev_failed ? 'D' :
815 'A');
766 break; 816 break;
767 817
768 case STATUSTYPE_TABLE: 818 case STATUSTYPE_TABLE: