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.c77
1 files changed, 64 insertions, 13 deletions
diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c
index 9443896ede07..7035582786fb 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
@@ -614,6 +635,11 @@ static int disk_resume(struct dm_dirty_log *log)
614 635
615 /* write the new header */ 636 /* write the new header */
616 r = rw_header(lc, WRITE); 637 r = rw_header(lc, WRITE);
638 if (!r) {
639 r = flush_header(lc);
640 if (r)
641 lc->log_dev_flush_failed = 1;
642 }
617 if (r) { 643 if (r) {
618 DMWARN("%s: Failed to write header on dirty region log device", 644 DMWARN("%s: Failed to write header on dirty region log device",
619 lc->log_dev->name); 645 lc->log_dev->name);
@@ -656,18 +682,40 @@ static int core_flush(struct dm_dirty_log *log)
656 682
657static int disk_flush(struct dm_dirty_log *log) 683static int disk_flush(struct dm_dirty_log *log)
658{ 684{
659 int r; 685 int r, i;
660 struct log_c *lc = (struct log_c *) log->context; 686 struct log_c *lc = log->context;
661 687
662 /* only write if the log has changed */ 688 /* only write if the log has changed */
663 if (!lc->touched) 689 if (!lc->touched_cleaned && !lc->touched_dirtied)
664 return 0; 690 return 0;
665 691
692 if (lc->touched_cleaned && log->flush_callback_fn &&
693 log->flush_callback_fn(lc->ti)) {
694 /*
695 * At this point it is impossible to determine which
696 * regions are clean and which are dirty (without
697 * re-reading the log off disk). So mark all of them
698 * dirty.
699 */
700 lc->flush_failed = 1;
701 for (i = 0; i < lc->region_count; i++)
702 log_clear_bit(lc, lc->clean_bits, i);
703 }
704
666 r = rw_header(lc, WRITE); 705 r = rw_header(lc, WRITE);
667 if (r) 706 if (r)
668 fail_log_device(lc); 707 fail_log_device(lc);
669 else 708 else {
670 lc->touched = 0; 709 if (lc->touched_dirtied) {
710 r = flush_header(lc);
711 if (r) {
712 lc->log_dev_flush_failed = 1;
713 fail_log_device(lc);
714 } else
715 lc->touched_dirtied = 0;
716 }
717 lc->touched_cleaned = 0;
718 }
671 719
672 return r; 720 return r;
673} 721}
@@ -681,7 +729,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) 729static void core_clear_region(struct dm_dirty_log *log, region_t region)
682{ 730{
683 struct log_c *lc = (struct log_c *) log->context; 731 struct log_c *lc = (struct log_c *) log->context;
684 log_set_bit(lc, lc->clean_bits, region); 732 if (likely(!lc->flush_failed))
733 log_set_bit(lc, lc->clean_bits, region);
685} 734}
686 735
687static int core_get_resync_work(struct dm_dirty_log *log, region_t *region) 736static int core_get_resync_work(struct dm_dirty_log *log, region_t *region)
@@ -762,7 +811,9 @@ static int disk_status(struct dm_dirty_log *log, status_type_t status,
762 switch(status) { 811 switch(status) {
763 case STATUSTYPE_INFO: 812 case STATUSTYPE_INFO:
764 DMEMIT("3 %s %s %c", log->type->name, lc->log_dev->name, 813 DMEMIT("3 %s %s %c", log->type->name, lc->log_dev->name,
765 lc->log_dev_failed ? 'D' : 'A'); 814 lc->log_dev_flush_failed ? 'F' :
815 lc->log_dev_failed ? 'D' :
816 'A');
766 break; 817 break;
767 818
768 case STATUSTYPE_TABLE: 819 case STATUSTYPE_TABLE: