diff options
-rw-r--r-- | drivers/md/dm-log.c | 113 |
1 files changed, 63 insertions, 50 deletions
diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c index ae41628b75c0..f52a78fc82bb 100644 --- a/drivers/md/dm-log.c +++ b/drivers/md/dm-log.c | |||
@@ -244,15 +244,16 @@ static inline int write_header(struct log_c *log) | |||
244 | * argv contains region_size followed optionally by [no]sync | 244 | * argv contains region_size followed optionally by [no]sync |
245 | *--------------------------------------------------------------*/ | 245 | *--------------------------------------------------------------*/ |
246 | #define BYTE_SHIFT 3 | 246 | #define BYTE_SHIFT 3 |
247 | static int core_ctr(struct dirty_log *log, struct dm_target *ti, | 247 | static int create_log_context(struct dirty_log *log, struct dm_target *ti, |
248 | unsigned int argc, char **argv) | 248 | unsigned int argc, char **argv, |
249 | struct dm_dev *dev) | ||
249 | { | 250 | { |
250 | enum sync sync = DEFAULTSYNC; | 251 | enum sync sync = DEFAULTSYNC; |
251 | 252 | ||
252 | struct log_c *lc; | 253 | struct log_c *lc; |
253 | uint32_t region_size; | 254 | uint32_t region_size; |
254 | unsigned int region_count; | 255 | unsigned int region_count; |
255 | size_t bitset_size; | 256 | size_t bitset_size, buf_size; |
256 | 257 | ||
257 | if (argc < 1 || argc > 2) { | 258 | if (argc < 1 || argc > 2) { |
258 | DMWARN("wrong number of arguments to mirror log"); | 259 | DMWARN("wrong number of arguments to mirror log"); |
@@ -298,18 +299,49 @@ static int core_ctr(struct dirty_log *log, struct dm_target *ti, | |||
298 | bitset_size >>= BYTE_SHIFT; | 299 | bitset_size >>= BYTE_SHIFT; |
299 | 300 | ||
300 | lc->bitset_uint32_count = bitset_size / 4; | 301 | lc->bitset_uint32_count = bitset_size / 4; |
301 | lc->clean_bits = vmalloc(bitset_size); | 302 | |
302 | if (!lc->clean_bits) { | 303 | /* |
303 | DMWARN("couldn't allocate clean bitset"); | 304 | * Disk log? |
304 | kfree(lc); | 305 | */ |
305 | return -ENOMEM; | 306 | if (!dev) { |
307 | lc->clean_bits = vmalloc(bitset_size); | ||
308 | if (!lc->clean_bits) { | ||
309 | DMWARN("couldn't allocate clean bitset"); | ||
310 | kfree(lc); | ||
311 | return -ENOMEM; | ||
312 | } | ||
313 | lc->disk_header = NULL; | ||
314 | } else { | ||
315 | lc->log_dev = dev; | ||
316 | lc->header_location.bdev = lc->log_dev->bdev; | ||
317 | lc->header_location.sector = 0; | ||
318 | |||
319 | /* | ||
320 | * Buffer holds both header and bitset. | ||
321 | */ | ||
322 | buf_size = dm_round_up((LOG_OFFSET << SECTOR_SHIFT) + | ||
323 | bitset_size, ti->limits.hardsect_size); | ||
324 | lc->header_location.count = buf_size >> SECTOR_SHIFT; | ||
325 | |||
326 | lc->disk_header = vmalloc(buf_size); | ||
327 | if (!lc->disk_header) { | ||
328 | DMWARN("couldn't allocate disk log buffer"); | ||
329 | kfree(lc); | ||
330 | return -ENOMEM; | ||
331 | } | ||
332 | |||
333 | lc->clean_bits = (void *)lc->disk_header + | ||
334 | (LOG_OFFSET << SECTOR_SHIFT); | ||
306 | } | 335 | } |
336 | |||
307 | memset(lc->clean_bits, -1, bitset_size); | 337 | memset(lc->clean_bits, -1, bitset_size); |
308 | 338 | ||
309 | lc->sync_bits = vmalloc(bitset_size); | 339 | lc->sync_bits = vmalloc(bitset_size); |
310 | if (!lc->sync_bits) { | 340 | if (!lc->sync_bits) { |
311 | DMWARN("couldn't allocate sync bitset"); | 341 | DMWARN("couldn't allocate sync bitset"); |
312 | vfree(lc->clean_bits); | 342 | if (!dev) |
343 | vfree(lc->clean_bits); | ||
344 | vfree(lc->disk_header); | ||
313 | kfree(lc); | 345 | kfree(lc); |
314 | return -ENOMEM; | 346 | return -ENOMEM; |
315 | } | 347 | } |
@@ -320,25 +352,40 @@ static int core_ctr(struct dirty_log *log, struct dm_target *ti, | |||
320 | if (!lc->recovering_bits) { | 352 | if (!lc->recovering_bits) { |
321 | DMWARN("couldn't allocate sync bitset"); | 353 | DMWARN("couldn't allocate sync bitset"); |
322 | vfree(lc->sync_bits); | 354 | vfree(lc->sync_bits); |
323 | vfree(lc->clean_bits); | 355 | if (!dev) |
356 | vfree(lc->clean_bits); | ||
357 | vfree(lc->disk_header); | ||
324 | kfree(lc); | 358 | kfree(lc); |
325 | return -ENOMEM; | 359 | return -ENOMEM; |
326 | } | 360 | } |
327 | memset(lc->recovering_bits, 0, bitset_size); | 361 | memset(lc->recovering_bits, 0, bitset_size); |
328 | lc->sync_search = 0; | 362 | lc->sync_search = 0; |
329 | log->context = lc; | 363 | log->context = lc; |
364 | |||
330 | return 0; | 365 | return 0; |
331 | } | 366 | } |
332 | 367 | ||
333 | static void core_dtr(struct dirty_log *log) | 368 | static int core_ctr(struct dirty_log *log, struct dm_target *ti, |
369 | unsigned int argc, char **argv) | ||
370 | { | ||
371 | return create_log_context(log, ti, argc, argv, NULL); | ||
372 | } | ||
373 | |||
374 | static void destroy_log_context(struct log_c *lc) | ||
334 | { | 375 | { |
335 | struct log_c *lc = (struct log_c *) log->context; | ||
336 | vfree(lc->clean_bits); | ||
337 | vfree(lc->sync_bits); | 376 | vfree(lc->sync_bits); |
338 | vfree(lc->recovering_bits); | 377 | vfree(lc->recovering_bits); |
339 | kfree(lc); | 378 | kfree(lc); |
340 | } | 379 | } |
341 | 380 | ||
381 | static void core_dtr(struct dirty_log *log) | ||
382 | { | ||
383 | struct log_c *lc = (struct log_c *) log->context; | ||
384 | |||
385 | vfree(lc->clean_bits); | ||
386 | destroy_log_context(lc); | ||
387 | } | ||
388 | |||
342 | /*---------------------------------------------------------------- | 389 | /*---------------------------------------------------------------- |
343 | * disk log constructor/destructor | 390 | * disk log constructor/destructor |
344 | * | 391 | * |
@@ -348,10 +395,7 @@ static int disk_ctr(struct dirty_log *log, struct dm_target *ti, | |||
348 | unsigned int argc, char **argv) | 395 | unsigned int argc, char **argv) |
349 | { | 396 | { |
350 | int r; | 397 | int r; |
351 | size_t size, bitset_size; | ||
352 | struct log_c *lc; | ||
353 | struct dm_dev *dev; | 398 | struct dm_dev *dev; |
354 | uint32_t *clean_bits; | ||
355 | 399 | ||
356 | if (argc < 2 || argc > 3) { | 400 | if (argc < 2 || argc > 3) { |
357 | DMWARN("wrong number of arguments to disk mirror log"); | 401 | DMWARN("wrong number of arguments to disk mirror log"); |
@@ -363,53 +407,22 @@ static int disk_ctr(struct dirty_log *log, struct dm_target *ti, | |||
363 | if (r) | 407 | if (r) |
364 | return r; | 408 | return r; |
365 | 409 | ||
366 | r = core_ctr(log, ti, argc - 1, argv + 1); | 410 | r = create_log_context(log, ti, argc - 1, argv + 1, dev); |
367 | if (r) { | 411 | if (r) { |
368 | dm_put_device(ti, dev); | 412 | dm_put_device(ti, dev); |
369 | return r; | 413 | return r; |
370 | } | 414 | } |
371 | 415 | ||
372 | lc = (struct log_c *) log->context; | ||
373 | lc->log_dev = dev; | ||
374 | |||
375 | /* setup the disk header fields */ | ||
376 | lc->header_location.bdev = lc->log_dev->bdev; | ||
377 | lc->header_location.sector = 0; | ||
378 | |||
379 | /* Include both the header and the bitset in one buffer. */ | ||
380 | bitset_size = lc->bitset_uint32_count * sizeof(uint32_t); | ||
381 | size = dm_round_up((LOG_OFFSET << SECTOR_SHIFT) + bitset_size, | ||
382 | ti->limits.hardsect_size); | ||
383 | lc->header_location.count = size >> SECTOR_SHIFT; | ||
384 | |||
385 | lc->disk_header = vmalloc(size); | ||
386 | if (!lc->disk_header) | ||
387 | goto bad; | ||
388 | |||
389 | /* | ||
390 | * Deallocate the clean_bits buffer that was allocated in core_ctr() | ||
391 | * and point it at the appropriate place in the disk_header buffer. | ||
392 | */ | ||
393 | clean_bits = lc->clean_bits; | ||
394 | lc->clean_bits = (void *)lc->disk_header + (LOG_OFFSET << SECTOR_SHIFT); | ||
395 | memcpy(lc->clean_bits, clean_bits, bitset_size); | ||
396 | vfree(clean_bits); | ||
397 | |||
398 | return 0; | 416 | return 0; |
399 | |||
400 | bad: | ||
401 | dm_put_device(ti, lc->log_dev); | ||
402 | core_dtr(log); | ||
403 | return -ENOMEM; | ||
404 | } | 417 | } |
405 | 418 | ||
406 | static void disk_dtr(struct dirty_log *log) | 419 | static void disk_dtr(struct dirty_log *log) |
407 | { | 420 | { |
408 | struct log_c *lc = (struct log_c *) log->context; | 421 | struct log_c *lc = (struct log_c *) log->context; |
422 | |||
409 | dm_put_device(lc->ti, lc->log_dev); | 423 | dm_put_device(lc->ti, lc->log_dev); |
410 | vfree(lc->disk_header); | 424 | vfree(lc->disk_header); |
411 | lc->clean_bits = NULL; | 425 | destroy_log_context(lc); |
412 | core_dtr(log); | ||
413 | } | 426 | } |
414 | 427 | ||
415 | static int count_bits32(uint32_t *addr, unsigned size) | 428 | static int count_bits32(uint32_t *addr, unsigned size) |