diff options
Diffstat (limited to 'drivers/md/dm-log.c')
-rw-r--r-- | drivers/md/dm-log.c | 157 |
1 files changed, 73 insertions, 84 deletions
diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c index d73779a42417..64b764bd02cc 100644 --- a/drivers/md/dm-log.c +++ b/drivers/md/dm-log.c | |||
@@ -12,6 +12,8 @@ | |||
12 | #include "dm-log.h" | 12 | #include "dm-log.h" |
13 | #include "dm-io.h" | 13 | #include "dm-io.h" |
14 | 14 | ||
15 | #define DM_MSG_PREFIX "mirror log" | ||
16 | |||
15 | static LIST_HEAD(_log_types); | 17 | static LIST_HEAD(_log_types); |
16 | static DEFINE_SPINLOCK(_lock); | 18 | static DEFINE_SPINLOCK(_lock); |
17 | 19 | ||
@@ -155,8 +157,6 @@ struct log_c { | |||
155 | 157 | ||
156 | struct io_region header_location; | 158 | struct io_region header_location; |
157 | struct log_header *disk_header; | 159 | struct log_header *disk_header; |
158 | |||
159 | struct io_region bits_location; | ||
160 | }; | 160 | }; |
161 | 161 | ||
162 | /* | 162 | /* |
@@ -241,43 +241,21 @@ static inline int write_header(struct log_c *log) | |||
241 | } | 241 | } |
242 | 242 | ||
243 | /*---------------------------------------------------------------- | 243 | /*---------------------------------------------------------------- |
244 | * Bits IO | ||
245 | *--------------------------------------------------------------*/ | ||
246 | static int read_bits(struct log_c *log) | ||
247 | { | ||
248 | int r; | ||
249 | unsigned long ebits; | ||
250 | |||
251 | r = dm_io_sync_vm(1, &log->bits_location, READ, | ||
252 | log->clean_bits, &ebits); | ||
253 | if (r) | ||
254 | return r; | ||
255 | |||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | static int write_bits(struct log_c *log) | ||
260 | { | ||
261 | unsigned long ebits; | ||
262 | return dm_io_sync_vm(1, &log->bits_location, WRITE, | ||
263 | log->clean_bits, &ebits); | ||
264 | } | ||
265 | |||
266 | /*---------------------------------------------------------------- | ||
267 | * core log constructor/destructor | 244 | * core log constructor/destructor |
268 | * | 245 | * |
269 | * argv contains region_size followed optionally by [no]sync | 246 | * argv contains region_size followed optionally by [no]sync |
270 | *--------------------------------------------------------------*/ | 247 | *--------------------------------------------------------------*/ |
271 | #define BYTE_SHIFT 3 | 248 | #define BYTE_SHIFT 3 |
272 | static int core_ctr(struct dirty_log *log, struct dm_target *ti, | 249 | static int create_log_context(struct dirty_log *log, struct dm_target *ti, |
273 | unsigned int argc, char **argv) | 250 | unsigned int argc, char **argv, |
251 | struct dm_dev *dev) | ||
274 | { | 252 | { |
275 | enum sync sync = DEFAULTSYNC; | 253 | enum sync sync = DEFAULTSYNC; |
276 | 254 | ||
277 | struct log_c *lc; | 255 | struct log_c *lc; |
278 | uint32_t region_size; | 256 | uint32_t region_size; |
279 | unsigned int region_count; | 257 | unsigned int region_count; |
280 | size_t bitset_size; | 258 | size_t bitset_size, buf_size; |
281 | 259 | ||
282 | if (argc < 1 || argc > 2) { | 260 | if (argc < 1 || argc > 2) { |
283 | DMWARN("wrong number of arguments to mirror log"); | 261 | DMWARN("wrong number of arguments to mirror log"); |
@@ -319,22 +297,53 @@ static int core_ctr(struct dirty_log *log, struct dm_target *ti, | |||
319 | * Work out how many "unsigned long"s we need to hold the bitset. | 297 | * Work out how many "unsigned long"s we need to hold the bitset. |
320 | */ | 298 | */ |
321 | bitset_size = dm_round_up(region_count, | 299 | bitset_size = dm_round_up(region_count, |
322 | sizeof(unsigned long) << BYTE_SHIFT); | 300 | sizeof(*lc->clean_bits) << BYTE_SHIFT); |
323 | bitset_size >>= BYTE_SHIFT; | 301 | bitset_size >>= BYTE_SHIFT; |
324 | 302 | ||
325 | lc->bitset_uint32_count = bitset_size / 4; | 303 | lc->bitset_uint32_count = bitset_size / sizeof(*lc->clean_bits); |
326 | lc->clean_bits = vmalloc(bitset_size); | 304 | |
327 | if (!lc->clean_bits) { | 305 | /* |
328 | DMWARN("couldn't allocate clean bitset"); | 306 | * Disk log? |
329 | kfree(lc); | 307 | */ |
330 | return -ENOMEM; | 308 | if (!dev) { |
309 | lc->clean_bits = vmalloc(bitset_size); | ||
310 | if (!lc->clean_bits) { | ||
311 | DMWARN("couldn't allocate clean bitset"); | ||
312 | kfree(lc); | ||
313 | return -ENOMEM; | ||
314 | } | ||
315 | lc->disk_header = NULL; | ||
316 | } else { | ||
317 | lc->log_dev = dev; | ||
318 | lc->header_location.bdev = lc->log_dev->bdev; | ||
319 | lc->header_location.sector = 0; | ||
320 | |||
321 | /* | ||
322 | * Buffer holds both header and bitset. | ||
323 | */ | ||
324 | buf_size = dm_round_up((LOG_OFFSET << SECTOR_SHIFT) + | ||
325 | bitset_size, ti->limits.hardsect_size); | ||
326 | lc->header_location.count = buf_size >> SECTOR_SHIFT; | ||
327 | |||
328 | lc->disk_header = vmalloc(buf_size); | ||
329 | if (!lc->disk_header) { | ||
330 | DMWARN("couldn't allocate disk log buffer"); | ||
331 | kfree(lc); | ||
332 | return -ENOMEM; | ||
333 | } | ||
334 | |||
335 | lc->clean_bits = (void *)lc->disk_header + | ||
336 | (LOG_OFFSET << SECTOR_SHIFT); | ||
331 | } | 337 | } |
338 | |||
332 | memset(lc->clean_bits, -1, bitset_size); | 339 | memset(lc->clean_bits, -1, bitset_size); |
333 | 340 | ||
334 | lc->sync_bits = vmalloc(bitset_size); | 341 | lc->sync_bits = vmalloc(bitset_size); |
335 | if (!lc->sync_bits) { | 342 | if (!lc->sync_bits) { |
336 | DMWARN("couldn't allocate sync bitset"); | 343 | DMWARN("couldn't allocate sync bitset"); |
337 | vfree(lc->clean_bits); | 344 | if (!dev) |
345 | vfree(lc->clean_bits); | ||
346 | vfree(lc->disk_header); | ||
338 | kfree(lc); | 347 | kfree(lc); |
339 | return -ENOMEM; | 348 | return -ENOMEM; |
340 | } | 349 | } |
@@ -345,25 +354,40 @@ static int core_ctr(struct dirty_log *log, struct dm_target *ti, | |||
345 | if (!lc->recovering_bits) { | 354 | if (!lc->recovering_bits) { |
346 | DMWARN("couldn't allocate sync bitset"); | 355 | DMWARN("couldn't allocate sync bitset"); |
347 | vfree(lc->sync_bits); | 356 | vfree(lc->sync_bits); |
348 | vfree(lc->clean_bits); | 357 | if (!dev) |
358 | vfree(lc->clean_bits); | ||
359 | vfree(lc->disk_header); | ||
349 | kfree(lc); | 360 | kfree(lc); |
350 | return -ENOMEM; | 361 | return -ENOMEM; |
351 | } | 362 | } |
352 | memset(lc->recovering_bits, 0, bitset_size); | 363 | memset(lc->recovering_bits, 0, bitset_size); |
353 | lc->sync_search = 0; | 364 | lc->sync_search = 0; |
354 | log->context = lc; | 365 | log->context = lc; |
366 | |||
355 | return 0; | 367 | return 0; |
356 | } | 368 | } |
357 | 369 | ||
358 | static void core_dtr(struct dirty_log *log) | 370 | static int core_ctr(struct dirty_log *log, struct dm_target *ti, |
371 | unsigned int argc, char **argv) | ||
372 | { | ||
373 | return create_log_context(log, ti, argc, argv, NULL); | ||
374 | } | ||
375 | |||
376 | static void destroy_log_context(struct log_c *lc) | ||
359 | { | 377 | { |
360 | struct log_c *lc = (struct log_c *) log->context; | ||
361 | vfree(lc->clean_bits); | ||
362 | vfree(lc->sync_bits); | 378 | vfree(lc->sync_bits); |
363 | vfree(lc->recovering_bits); | 379 | vfree(lc->recovering_bits); |
364 | kfree(lc); | 380 | kfree(lc); |
365 | } | 381 | } |
366 | 382 | ||
383 | static void core_dtr(struct dirty_log *log) | ||
384 | { | ||
385 | struct log_c *lc = (struct log_c *) log->context; | ||
386 | |||
387 | vfree(lc->clean_bits); | ||
388 | destroy_log_context(lc); | ||
389 | } | ||
390 | |||
367 | /*---------------------------------------------------------------- | 391 | /*---------------------------------------------------------------- |
368 | * disk log constructor/destructor | 392 | * disk log constructor/destructor |
369 | * | 393 | * |
@@ -373,8 +397,6 @@ static int disk_ctr(struct dirty_log *log, struct dm_target *ti, | |||
373 | unsigned int argc, char **argv) | 397 | unsigned int argc, char **argv) |
374 | { | 398 | { |
375 | int r; | 399 | int r; |
376 | size_t size; | ||
377 | struct log_c *lc; | ||
378 | struct dm_dev *dev; | 400 | struct dm_dev *dev; |
379 | 401 | ||
380 | if (argc < 2 || argc > 3) { | 402 | if (argc < 2 || argc > 3) { |
@@ -387,49 +409,22 @@ static int disk_ctr(struct dirty_log *log, struct dm_target *ti, | |||
387 | if (r) | 409 | if (r) |
388 | return r; | 410 | return r; |
389 | 411 | ||
390 | r = core_ctr(log, ti, argc - 1, argv + 1); | 412 | r = create_log_context(log, ti, argc - 1, argv + 1, dev); |
391 | if (r) { | 413 | if (r) { |
392 | dm_put_device(ti, dev); | 414 | dm_put_device(ti, dev); |
393 | return r; | 415 | return r; |
394 | } | 416 | } |
395 | 417 | ||
396 | lc = (struct log_c *) log->context; | ||
397 | lc->log_dev = dev; | ||
398 | |||
399 | /* setup the disk header fields */ | ||
400 | lc->header_location.bdev = lc->log_dev->bdev; | ||
401 | lc->header_location.sector = 0; | ||
402 | lc->header_location.count = 1; | ||
403 | |||
404 | /* | ||
405 | * We can't read less than this amount, even though we'll | ||
406 | * not be using most of this space. | ||
407 | */ | ||
408 | lc->disk_header = vmalloc(1 << SECTOR_SHIFT); | ||
409 | if (!lc->disk_header) | ||
410 | goto bad; | ||
411 | |||
412 | /* setup the disk bitset fields */ | ||
413 | lc->bits_location.bdev = lc->log_dev->bdev; | ||
414 | lc->bits_location.sector = LOG_OFFSET; | ||
415 | |||
416 | size = dm_round_up(lc->bitset_uint32_count * sizeof(uint32_t), | ||
417 | 1 << SECTOR_SHIFT); | ||
418 | lc->bits_location.count = size >> SECTOR_SHIFT; | ||
419 | return 0; | 418 | return 0; |
420 | |||
421 | bad: | ||
422 | dm_put_device(ti, lc->log_dev); | ||
423 | core_dtr(log); | ||
424 | return -ENOMEM; | ||
425 | } | 419 | } |
426 | 420 | ||
427 | static void disk_dtr(struct dirty_log *log) | 421 | static void disk_dtr(struct dirty_log *log) |
428 | { | 422 | { |
429 | struct log_c *lc = (struct log_c *) log->context; | 423 | struct log_c *lc = (struct log_c *) log->context; |
424 | |||
430 | dm_put_device(lc->ti, lc->log_dev); | 425 | dm_put_device(lc->ti, lc->log_dev); |
431 | vfree(lc->disk_header); | 426 | vfree(lc->disk_header); |
432 | core_dtr(log); | 427 | destroy_log_context(lc); |
433 | } | 428 | } |
434 | 429 | ||
435 | static int count_bits32(uint32_t *addr, unsigned size) | 430 | static int count_bits32(uint32_t *addr, unsigned size) |
@@ -454,12 +449,7 @@ static int disk_resume(struct dirty_log *log) | |||
454 | if (r) | 449 | if (r) |
455 | return r; | 450 | return r; |
456 | 451 | ||
457 | /* read the bits */ | 452 | /* set or clear any new bits -- device has grown */ |
458 | r = read_bits(lc); | ||
459 | if (r) | ||
460 | return r; | ||
461 | |||
462 | /* set or clear any new bits */ | ||
463 | if (lc->sync == NOSYNC) | 453 | if (lc->sync == NOSYNC) |
464 | for (i = lc->header.nr_regions; i < lc->region_count; i++) | 454 | for (i = lc->header.nr_regions; i < lc->region_count; i++) |
465 | /* FIXME: amazingly inefficient */ | 455 | /* FIXME: amazingly inefficient */ |
@@ -469,15 +459,14 @@ static int disk_resume(struct dirty_log *log) | |||
469 | /* FIXME: amazingly inefficient */ | 459 | /* FIXME: amazingly inefficient */ |
470 | log_clear_bit(lc, lc->clean_bits, i); | 460 | log_clear_bit(lc, lc->clean_bits, i); |
471 | 461 | ||
462 | /* clear any old bits -- device has shrunk */ | ||
463 | for (i = lc->region_count; i % (sizeof(*lc->clean_bits) << BYTE_SHIFT); i++) | ||
464 | log_clear_bit(lc, lc->clean_bits, i); | ||
465 | |||
472 | /* copy clean across to sync */ | 466 | /* copy clean across to sync */ |
473 | memcpy(lc->sync_bits, lc->clean_bits, size); | 467 | memcpy(lc->sync_bits, lc->clean_bits, size); |
474 | lc->sync_count = count_bits32(lc->clean_bits, lc->bitset_uint32_count); | 468 | lc->sync_count = count_bits32(lc->clean_bits, lc->bitset_uint32_count); |
475 | 469 | ||
476 | /* write the bits */ | ||
477 | r = write_bits(lc); | ||
478 | if (r) | ||
479 | return r; | ||
480 | |||
481 | /* set the correct number of regions in the header */ | 470 | /* set the correct number of regions in the header */ |
482 | lc->header.nr_regions = lc->region_count; | 471 | lc->header.nr_regions = lc->region_count; |
483 | 472 | ||
@@ -518,7 +507,7 @@ static int disk_flush(struct dirty_log *log) | |||
518 | if (!lc->touched) | 507 | if (!lc->touched) |
519 | return 0; | 508 | return 0; |
520 | 509 | ||
521 | r = write_bits(lc); | 510 | r = write_header(lc); |
522 | if (!r) | 511 | if (!r) |
523 | lc->touched = 0; | 512 | lc->touched = 0; |
524 | 513 | ||