aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/md/dm-log.c113
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
247static int core_ctr(struct dirty_log *log, struct dm_target *ti, 247static 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
333static void core_dtr(struct dirty_log *log) 368static 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
374static 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
381static 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
406static void disk_dtr(struct dirty_log *log) 419static 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
415static int count_bits32(uint32_t *addr, unsigned size) 428static int count_bits32(uint32_t *addr, unsigned size)