diff options
Diffstat (limited to 'drivers/md/dm-log.c')
-rw-r--r-- | drivers/md/dm-log.c | 77 |
1 files changed, 63 insertions, 14 deletions
diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c index 6a9261351848..a66428d860fe 100644 --- a/drivers/md/dm-log.c +++ b/drivers/md/dm-log.c | |||
@@ -149,9 +149,12 @@ struct log_c { | |||
149 | FORCESYNC, /* Force a sync to happen */ | 149 | FORCESYNC, /* Force a sync to happen */ |
150 | } sync; | 150 | } sync; |
151 | 151 | ||
152 | struct dm_io_request io_req; | ||
153 | |||
152 | /* | 154 | /* |
153 | * Disk log fields | 155 | * Disk log fields |
154 | */ | 156 | */ |
157 | int log_dev_failed; | ||
155 | struct dm_dev *log_dev; | 158 | struct dm_dev *log_dev; |
156 | struct log_header header; | 159 | struct log_header header; |
157 | 160 | ||
@@ -199,13 +202,20 @@ static void header_from_disk(struct log_header *core, struct log_header *disk) | |||
199 | core->nr_regions = le64_to_cpu(disk->nr_regions); | 202 | core->nr_regions = le64_to_cpu(disk->nr_regions); |
200 | } | 203 | } |
201 | 204 | ||
205 | static int rw_header(struct log_c *lc, int rw) | ||
206 | { | ||
207 | lc->io_req.bi_rw = rw; | ||
208 | lc->io_req.mem.ptr.vma = lc->disk_header; | ||
209 | lc->io_req.notify.fn = NULL; | ||
210 | |||
211 | return dm_io(&lc->io_req, 1, &lc->header_location, NULL); | ||
212 | } | ||
213 | |||
202 | static int read_header(struct log_c *log) | 214 | static int read_header(struct log_c *log) |
203 | { | 215 | { |
204 | int r; | 216 | int r; |
205 | unsigned long ebits; | ||
206 | 217 | ||
207 | r = dm_io_sync_vm(1, &log->header_location, READ, | 218 | r = rw_header(log, READ); |
208 | log->disk_header, &ebits); | ||
209 | if (r) | 219 | if (r) |
210 | return r; | 220 | return r; |
211 | 221 | ||
@@ -233,11 +243,8 @@ static int read_header(struct log_c *log) | |||
233 | 243 | ||
234 | static inline int write_header(struct log_c *log) | 244 | static inline int write_header(struct log_c *log) |
235 | { | 245 | { |
236 | unsigned long ebits; | ||
237 | |||
238 | header_to_disk(&log->header, log->disk_header); | 246 | header_to_disk(&log->header, log->disk_header); |
239 | return dm_io_sync_vm(1, &log->header_location, WRITE, | 247 | return rw_header(log, WRITE); |
240 | log->disk_header, &ebits); | ||
241 | } | 248 | } |
242 | 249 | ||
243 | /*---------------------------------------------------------------- | 250 | /*---------------------------------------------------------------- |
@@ -256,6 +263,7 @@ static int create_log_context(struct dirty_log *log, struct dm_target *ti, | |||
256 | uint32_t region_size; | 263 | uint32_t region_size; |
257 | unsigned int region_count; | 264 | unsigned int region_count; |
258 | size_t bitset_size, buf_size; | 265 | size_t bitset_size, buf_size; |
266 | int r; | ||
259 | 267 | ||
260 | if (argc < 1 || argc > 2) { | 268 | if (argc < 1 || argc > 2) { |
261 | DMWARN("wrong number of arguments to mirror log"); | 269 | DMWARN("wrong number of arguments to mirror log"); |
@@ -315,6 +323,7 @@ static int create_log_context(struct dirty_log *log, struct dm_target *ti, | |||
315 | lc->disk_header = NULL; | 323 | lc->disk_header = NULL; |
316 | } else { | 324 | } else { |
317 | lc->log_dev = dev; | 325 | lc->log_dev = dev; |
326 | lc->log_dev_failed = 0; | ||
318 | lc->header_location.bdev = lc->log_dev->bdev; | 327 | lc->header_location.bdev = lc->log_dev->bdev; |
319 | lc->header_location.sector = 0; | 328 | lc->header_location.sector = 0; |
320 | 329 | ||
@@ -324,6 +333,15 @@ static int create_log_context(struct dirty_log *log, struct dm_target *ti, | |||
324 | buf_size = dm_round_up((LOG_OFFSET << SECTOR_SHIFT) + | 333 | buf_size = dm_round_up((LOG_OFFSET << SECTOR_SHIFT) + |
325 | bitset_size, ti->limits.hardsect_size); | 334 | bitset_size, ti->limits.hardsect_size); |
326 | lc->header_location.count = buf_size >> SECTOR_SHIFT; | 335 | lc->header_location.count = buf_size >> SECTOR_SHIFT; |
336 | lc->io_req.mem.type = DM_IO_VMA; | ||
337 | lc->io_req.client = dm_io_client_create(dm_div_up(buf_size, | ||
338 | PAGE_SIZE)); | ||
339 | if (IS_ERR(lc->io_req.client)) { | ||
340 | r = PTR_ERR(lc->io_req.client); | ||
341 | DMWARN("couldn't allocate disk io client"); | ||
342 | kfree(lc); | ||
343 | return -ENOMEM; | ||
344 | } | ||
327 | 345 | ||
328 | lc->disk_header = vmalloc(buf_size); | 346 | lc->disk_header = vmalloc(buf_size); |
329 | if (!lc->disk_header) { | 347 | if (!lc->disk_header) { |
@@ -424,6 +442,7 @@ static void disk_dtr(struct dirty_log *log) | |||
424 | 442 | ||
425 | dm_put_device(lc->ti, lc->log_dev); | 443 | dm_put_device(lc->ti, lc->log_dev); |
426 | vfree(lc->disk_header); | 444 | vfree(lc->disk_header); |
445 | dm_io_client_destroy(lc->io_req.client); | ||
427 | destroy_log_context(lc); | 446 | destroy_log_context(lc); |
428 | } | 447 | } |
429 | 448 | ||
@@ -437,6 +456,15 @@ static int count_bits32(uint32_t *addr, unsigned size) | |||
437 | return count; | 456 | return count; |
438 | } | 457 | } |
439 | 458 | ||
459 | static void fail_log_device(struct log_c *lc) | ||
460 | { | ||
461 | if (lc->log_dev_failed) | ||
462 | return; | ||
463 | |||
464 | lc->log_dev_failed = 1; | ||
465 | dm_table_event(lc->ti->table); | ||
466 | } | ||
467 | |||
440 | static int disk_resume(struct dirty_log *log) | 468 | static int disk_resume(struct dirty_log *log) |
441 | { | 469 | { |
442 | int r; | 470 | int r; |
@@ -446,8 +474,19 @@ static int disk_resume(struct dirty_log *log) | |||
446 | 474 | ||
447 | /* read the disk header */ | 475 | /* read the disk header */ |
448 | r = read_header(lc); | 476 | r = read_header(lc); |
449 | if (r) | 477 | if (r) { |
450 | return r; | 478 | DMWARN("%s: Failed to read header on mirror log device", |
479 | lc->log_dev->name); | ||
480 | fail_log_device(lc); | ||
481 | /* | ||
482 | * If the log device cannot be read, we must assume | ||
483 | * all regions are out-of-sync. If we simply return | ||
484 | * here, the state will be uninitialized and could | ||
485 | * lead us to return 'in-sync' status for regions | ||
486 | * that are actually 'out-of-sync'. | ||
487 | */ | ||
488 | lc->header.nr_regions = 0; | ||
489 | } | ||
451 | 490 | ||
452 | /* set or clear any new bits -- device has grown */ | 491 | /* set or clear any new bits -- device has grown */ |
453 | if (lc->sync == NOSYNC) | 492 | if (lc->sync == NOSYNC) |
@@ -472,7 +511,14 @@ static int disk_resume(struct dirty_log *log) | |||
472 | lc->header.nr_regions = lc->region_count; | 511 | lc->header.nr_regions = lc->region_count; |
473 | 512 | ||
474 | /* write the new header */ | 513 | /* write the new header */ |
475 | return write_header(lc); | 514 | r = write_header(lc); |
515 | if (r) { | ||
516 | DMWARN("%s: Failed to write header on mirror log device", | ||
517 | lc->log_dev->name); | ||
518 | fail_log_device(lc); | ||
519 | } | ||
520 | |||
521 | return r; | ||
476 | } | 522 | } |
477 | 523 | ||
478 | static uint32_t core_get_region_size(struct dirty_log *log) | 524 | static uint32_t core_get_region_size(struct dirty_log *log) |
@@ -516,7 +562,9 @@ static int disk_flush(struct dirty_log *log) | |||
516 | return 0; | 562 | return 0; |
517 | 563 | ||
518 | r = write_header(lc); | 564 | r = write_header(lc); |
519 | if (!r) | 565 | if (r) |
566 | fail_log_device(lc); | ||
567 | else | ||
520 | lc->touched = 0; | 568 | lc->touched = 0; |
521 | 569 | ||
522 | return r; | 570 | return r; |
@@ -591,6 +639,7 @@ static int core_status(struct dirty_log *log, status_type_t status, | |||
591 | 639 | ||
592 | switch(status) { | 640 | switch(status) { |
593 | case STATUSTYPE_INFO: | 641 | case STATUSTYPE_INFO: |
642 | DMEMIT("1 %s", log->type->name); | ||
594 | break; | 643 | break; |
595 | 644 | ||
596 | case STATUSTYPE_TABLE: | 645 | case STATUSTYPE_TABLE: |
@@ -606,17 +655,17 @@ static int disk_status(struct dirty_log *log, status_type_t status, | |||
606 | char *result, unsigned int maxlen) | 655 | char *result, unsigned int maxlen) |
607 | { | 656 | { |
608 | int sz = 0; | 657 | int sz = 0; |
609 | char buffer[16]; | ||
610 | struct log_c *lc = log->context; | 658 | struct log_c *lc = log->context; |
611 | 659 | ||
612 | switch(status) { | 660 | switch(status) { |
613 | case STATUSTYPE_INFO: | 661 | case STATUSTYPE_INFO: |
662 | DMEMIT("3 %s %s %c", log->type->name, lc->log_dev->name, | ||
663 | lc->log_dev_failed ? 'D' : 'A'); | ||
614 | break; | 664 | break; |
615 | 665 | ||
616 | case STATUSTYPE_TABLE: | 666 | case STATUSTYPE_TABLE: |
617 | format_dev_t(buffer, lc->log_dev->bdev->bd_dev); | ||
618 | DMEMIT("%s %u %s %u ", log->type->name, | 667 | DMEMIT("%s %u %s %u ", log->type->name, |
619 | lc->sync == DEFAULTSYNC ? 2 : 3, buffer, | 668 | lc->sync == DEFAULTSYNC ? 2 : 3, lc->log_dev->name, |
620 | lc->region_size); | 669 | lc->region_size); |
621 | DMEMIT_SYNC; | 670 | DMEMIT_SYNC; |
622 | } | 671 | } |