static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti, unsigned int argc, char **argv, struct dm_dev *dev) { enum sync sync = DEFAULTSYNC; struct log_c *lc; uint32_t region_size; unsigned int region_count; size_t bitset_size, buf_size; int r; char dummy; if (argc < 1 || argc > 2) { DMWARN("wrong number of arguments to dirty region log"); return -EINVAL; } if (argc > 1) { if (!strcmp(argv[1], "sync")) sync = FORCESYNC; else if (!strcmp(argv[1], "nosync")) sync = NOSYNC; else { DMWARN("unrecognised sync argument to " "dirty region log: %s", argv[1]); return -EINVAL; } } if (sscanf(argv[0], "%u%c", ®ion_size, &dummy) != 1 || !_check_region_size(ti, region_size)) { DMWARN("invalid region size %s", argv[0]); return -EINVAL; } region_count = dm_sector_div_up(ti->len, region_size); lc = kmalloc(sizeof(*lc), GFP_KERNEL); if (!lc) { DMWARN("couldn't allocate core log"); return -ENOMEM; } lc->ti = ti; lc->touched_dirtied = 0; lc->touched_cleaned = 0; lc->flush_failed = 0; lc->region_size = region_size; lc->region_count = region_count; lc->sync = sync; /* * Work out how many "unsigned long"s we need to hold the bitset. */ bitset_size = dm_round_up(region_count, sizeof(*lc->clean_bits) << BYTE_SHIFT); bitset_size >>= BYTE_SHIFT; lc->bitset_uint32_count = bitset_size / sizeof(*lc->clean_bits); /* * Disk log? */ if (!dev) { lc->clean_bits = vmalloc(bitset_size); if (!lc->clean_bits) { DMWARN("couldn't allocate clean bitset"); kfree(lc); return -ENOMEM; } lc->disk_header = NULL; } else { lc->log_dev = dev; lc->log_dev_failed = 0; lc->log_dev_flush_failed = 0; lc->header_location.bdev = lc->log_dev->bdev; lc->header_location.sector = 0; /* * Buffer holds both header and bitset. */ buf_size = dm_round_up((LOG_OFFSET << SECTOR_SHIFT) + bitset_size, bdev_logical_block_size(lc->header_location. bdev)); if (buf_size > i_size_read(dev->bdev->bd_inode)) { DMWARN("log device %s too small: need %llu bytes", dev->name, (unsigned long long)buf_size); kfree(lc); return -EINVAL; } lc->header_location.count = buf_size >> SECTOR_SHIFT; lc->io_req.mem.type = DM_IO_VMA; lc->io_req.notify.fn = NULL; lc->io_req.client = dm_io_client_create(); if (IS_ERR(lc->io_req.client)) { r = PTR_ERR(lc->io_req.client); DMWARN("couldn't allocate disk io client"); kfree(lc); return r; } lc->disk_header = vmalloc(buf_size); if (!lc->disk_header) { DMWARN("couldn't allocate disk log buffer"); dm_io_client_destroy(lc->io_req.client); kfree(lc); return -ENOMEM; } lc->io_req.mem.ptr.vma = lc->disk_header; lc->clean_bits = (void *)lc->disk_header + (LOG_OFFSET << SECTOR_SHIFT); } memset(lc->clean_bits, -1, bitset_size); lc->sync_bits = vmalloc(bitset_size); if (!lc->sync_bits) { DMWARN("couldn't allocate sync bitset"); if (!dev) vfree(lc->clean_bits); else dm_io_client_destroy(lc->io_req.client); vfree(lc->disk_header); kfree(lc); return -ENOMEM; } memset(lc->sync_bits, (sync == NOSYNC) ? -1 : 0, bitset_size); lc->sync_count = (sync == NOSYNC) ? region_count : 0; lc->recovering_bits = vzalloc(bitset_size); if (!lc->recovering_bits) { DMWARN("couldn't allocate sync bitset"); vfree(lc->sync_bits); if (!dev) vfree(lc->clean_bits); else dm_io_client_destroy(lc->io_req.client); vfree(lc->disk_header); kfree(lc); return -ENOMEM; } lc->sync_search = 0; log->context = lc; return 0; }
/* * userspace_ctr * * argv contains: * <UUID> [integrated_flush] <other args> * Where 'other args' are the userspace implementation-specific log * arguments. * * Example: * <UUID> [integrated_flush] clustered-disk <arg count> <log dev> * <region_size> [[no]sync] * * This module strips off the <UUID> and uses it for identification * purposes when communicating with userspace about a log. * * If integrated_flush is defined, the kernel combines flush * and mark requests. * * The rest of the line, beginning with 'clustered-disk', is passed * to the userspace ctr function. */ static int userspace_ctr(struct dm_dirty_log *log, struct dm_target *ti, unsigned argc, char **argv) { int r = 0; int str_size; char *ctr_str = NULL; struct log_c *lc = NULL; uint64_t rdata; size_t rdata_size = sizeof(rdata); char *devices_rdata = NULL; size_t devices_rdata_size = DM_NAME_LEN; if (argc < 3) { DMWARN("Too few arguments to userspace dirty log"); return -EINVAL; } lc = kzalloc(sizeof(*lc), GFP_KERNEL); if (!lc) { DMWARN("Unable to allocate userspace log context."); return -ENOMEM; } /* The ptr value is sufficient for local unique id */ lc->luid = (unsigned long)lc; lc->ti = ti; if (strlen(argv[0]) > (DM_UUID_LEN - 1)) { DMWARN("UUID argument too long."); kfree(lc); return -EINVAL; } lc->usr_argc = argc; strncpy(lc->uuid, argv[0], DM_UUID_LEN); argc--; argv++; spin_lock_init(&lc->flush_lock); INIT_LIST_HEAD(&lc->mark_list); INIT_LIST_HEAD(&lc->clear_list); if (!strcasecmp(argv[0], "integrated_flush")) { lc->integrated_flush = 1; argc--; argv++; } str_size = build_constructor_string(ti, argc, argv, &ctr_str); if (str_size < 0) { kfree(lc); return str_size; } devices_rdata = kzalloc(devices_rdata_size, GFP_KERNEL); if (!devices_rdata) { DMERR("Failed to allocate memory for device information"); r = -ENOMEM; goto out; } lc->flush_entry_pool = mempool_create_slab_pool(FLUSH_ENTRY_POOL_SIZE, _flush_entry_cache); if (!lc->flush_entry_pool) { DMERR("Failed to create flush_entry_pool"); r = -ENOMEM; goto out; } /* * Send table string and get back any opened device. */ r = dm_consult_userspace(lc->uuid, lc->luid, DM_ULOG_CTR, ctr_str, str_size, devices_rdata, &devices_rdata_size); if (r < 0) { if (r == -ESRCH) DMERR("Userspace log server not found"); else DMERR("Userspace log server failed to create log"); goto out; } /* Since the region size does not change, get it now */ rdata_size = sizeof(rdata); r = dm_consult_userspace(lc->uuid, lc->luid, DM_ULOG_GET_REGION_SIZE, NULL, 0, (char *)&rdata, &rdata_size); if (r) { DMERR("Failed to get region size of dirty log"); goto out; } lc->region_size = (uint32_t)rdata; lc->region_count = dm_sector_div_up(ti->len, lc->region_size); if (devices_rdata_size) { if (devices_rdata[devices_rdata_size - 1] != '\0') { DMERR("DM_ULOG_CTR device return string not properly terminated"); r = -EINVAL; goto out; } r = dm_get_device(ti, devices_rdata, dm_table_get_mode(ti->table), &lc->log_dev); if (r) DMERR("Failed to register %s with device-mapper", devices_rdata); } if (lc->integrated_flush) { lc->dmlog_wq = alloc_workqueue("dmlogd", WQ_MEM_RECLAIM, 0); if (!lc->dmlog_wq) { DMERR("couldn't start dmlogd"); r = -ENOMEM; goto out; } INIT_DELAYED_WORK(&lc->flush_log_work, do_flush); atomic_set(&lc->sched_flush, 0); } out: kfree(devices_rdata); if (r) { if (lc->flush_entry_pool) mempool_destroy(lc->flush_entry_pool); kfree(lc); kfree(ctr_str); } else { lc->usr_argv_str = ctr_str; log->context = lc; } return r; }
static int create_log_context(struct dirty_log *log, struct dm_target *ti, unsigned int argc, char **argv, struct dm_dev *dev) { enum sync sync = DEFAULTSYNC; struct log_c *lc; uint32_t region_size; unsigned int region_count; size_t bitset_size, buf_size; if (argc < 1 || argc > 2) { DMWARN("wrong number of arguments to mirror log"); return -EINVAL; } if (argc > 1) { if (!strcmp(argv[1], "sync")) sync = FORCESYNC; else if (!strcmp(argv[1], "nosync")) sync = NOSYNC; else { DMWARN("unrecognised sync argument to mirror log: %s", argv[1]); return -EINVAL; } } if (sscanf(argv[0], "%u", ®ion_size) != 1) { DMWARN("invalid region size string"); return -EINVAL; } region_count = dm_sector_div_up(ti->len, region_size); lc = kmalloc(sizeof(*lc), GFP_KERNEL); if (!lc) { DMWARN("couldn't allocate core log"); return -ENOMEM; } lc->ti = ti; lc->touched = 0; lc->region_size = region_size; lc->region_count = region_count; lc->sync = sync; /* * Work out how many "unsigned long"s we need to hold the bitset. */ bitset_size = dm_round_up(region_count, sizeof(*lc->clean_bits) << BYTE_SHIFT); bitset_size >>= BYTE_SHIFT; lc->bitset_uint32_count = bitset_size / sizeof(*lc->clean_bits); /* * Disk log? */ if (!dev) { lc->clean_bits = vmalloc(bitset_size); if (!lc->clean_bits) { DMWARN("couldn't allocate clean bitset"); kfree(lc); return -ENOMEM; } lc->disk_header = NULL; } else { lc->log_dev = dev; lc->header_location.bdev = lc->log_dev->bdev; lc->header_location.sector = 0; /* * Buffer holds both header and bitset. */ buf_size = dm_round_up((LOG_OFFSET << SECTOR_SHIFT) + bitset_size, ti->limits.hardsect_size); lc->header_location.count = buf_size >> SECTOR_SHIFT; lc->disk_header = vmalloc(buf_size); if (!lc->disk_header) { DMWARN("couldn't allocate disk log buffer"); kfree(lc); return -ENOMEM; } lc->clean_bits = (void *)lc->disk_header + (LOG_OFFSET << SECTOR_SHIFT); } memset(lc->clean_bits, -1, bitset_size); lc->sync_bits = vmalloc(bitset_size); if (!lc->sync_bits) { DMWARN("couldn't allocate sync bitset"); if (!dev) vfree(lc->clean_bits); vfree(lc->disk_header); kfree(lc); return -ENOMEM; } memset(lc->sync_bits, (sync == NOSYNC) ? -1 : 0, bitset_size); lc->sync_count = (sync == NOSYNC) ? region_count : 0; lc->recovering_bits = vmalloc(bitset_size); if (!lc->recovering_bits) { DMWARN("couldn't allocate sync bitset"); vfree(lc->sync_bits); if (!dev) vfree(lc->clean_bits); vfree(lc->disk_header); kfree(lc); return -ENOMEM; } memset(lc->recovering_bits, 0, bitset_size); lc->sync_search = 0; log->context = lc; return 0; }
static int core_ctr(struct dirty_log *log, struct dm_target *ti, unsigned int argc, char **argv) { enum sync sync = DEFAULTSYNC; int failure_response = DMLOG_IOERR_IGNORE; struct log_c *lc; uint32_t region_size; unsigned int region_count; size_t bitset_size; unsigned i; if (argc < 1 || argc > 3) { DMWARN("wrong number of arguments to mirror log"); return -EINVAL; } for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "sync")) sync = FORCESYNC; else if (!strcmp(argv[i], "nosync")) sync = NOSYNC; else if (!strcmp(argv[i], "block_on_error")) failure_response = DMLOG_IOERR_BLOCK; else { DMWARN("unrecognised sync argument to mirror log: %s", argv[i]); return -EINVAL; } } if (sscanf(argv[0], "%u", ®ion_size) != 1) { DMWARN("invalid region size string"); return -EINVAL; } region_count = dm_sector_div_up(ti->len, region_size); lc = kmalloc(sizeof(*lc), GFP_KERNEL); if (!lc) { DMWARN("couldn't allocate core log"); return -ENOMEM; } lc->ti = ti; lc->touched = 0; lc->region_size = region_size; lc->region_count = region_count; lc->sync = sync; lc->failure_response = failure_response; /* * Work out how many "unsigned long"s we need to hold the bitset. */ bitset_size = dm_round_up(region_count, sizeof(uint32_t) << BYTE_SHIFT); bitset_size >>= BYTE_SHIFT; lc->bitset_uint32_count = bitset_size / sizeof(uint32_t); lc->clean_bits = vmalloc(bitset_size); if (!lc->clean_bits) { DMWARN("couldn't allocate clean bitset"); kfree(lc); return -ENOMEM; } memset(lc->clean_bits, -1, bitset_size); lc->sync_bits = vmalloc(bitset_size); if (!lc->sync_bits) { DMWARN("couldn't allocate sync bitset"); vfree(lc->clean_bits); kfree(lc); return -ENOMEM; } memset(lc->sync_bits, (sync == NOSYNC) ? -1 : 0, bitset_size); lc->sync_count = (sync == NOSYNC) ? region_count : 0; lc->recovering_bits = vmalloc(bitset_size); if (!lc->recovering_bits) { DMWARN("couldn't allocate recovering bitset"); vfree(lc->sync_bits); vfree(lc->clean_bits); kfree(lc); return -ENOMEM; } memset(lc->recovering_bits, 0, bitset_size); lc->sync_search = 0; log->context = lc; return 0; }
/* * userspace_ctr * * argv contains: * <UUID> <other args> * Where 'other args' is the userspace implementation specific log * arguments. An example might be: * <UUID> clustered_disk <arg count> <log dev> <region_size> [[no]sync] * * So, this module will strip off the <UUID> for identification purposes * when communicating with userspace about a log; but will pass on everything * else. */ static int userspace_ctr(struct dm_dirty_log *log, struct dm_target *ti, unsigned argc, char **argv) { int r = 0; int str_size; char *ctr_str = NULL; struct log_c *lc = NULL; uint64_t rdata; size_t rdata_size = sizeof(rdata); if (argc < 3) { DMWARN("Too few arguments to userspace dirty log"); return -EINVAL; } lc = kmalloc(sizeof(*lc), GFP_KERNEL); if (!lc) { DMWARN("Unable to allocate userspace log context."); return -ENOMEM; } /* The ptr value is sufficient for local unique id */ lc->luid = (unsigned long)lc; lc->ti = ti; if (strlen(argv[0]) > (DM_UUID_LEN - 1)) { DMWARN("UUID argument too long."); kfree(lc); return -EINVAL; } strncpy(lc->uuid, argv[0], DM_UUID_LEN); spin_lock_init(&lc->flush_lock); INIT_LIST_HEAD(&lc->mark_list); INIT_LIST_HEAD(&lc->clear_list); str_size = build_constructor_string(ti, argc - 1, argv + 1, &ctr_str); if (str_size < 0) { kfree(lc); return str_size; } /* Send table string */ r = dm_consult_userspace(lc->uuid, lc->luid, DM_ULOG_CTR, ctr_str, str_size, NULL, NULL); if (r < 0) { if (r == -ESRCH) DMERR("Userspace log server not found"); else DMERR("Userspace log server failed to create log"); goto out; } /* Since the region size does not change, get it now */ rdata_size = sizeof(rdata); r = dm_consult_userspace(lc->uuid, lc->luid, DM_ULOG_GET_REGION_SIZE, NULL, 0, (char *)&rdata, &rdata_size); if (r) { DMERR("Failed to get region size of dirty log"); goto out; } lc->region_size = (uint32_t)rdata; lc->region_count = dm_sector_div_up(ti->len, lc->region_size); out: if (r) { kfree(lc); kfree(ctr_str); } else { lc->usr_argv_str = ctr_str; lc->usr_argc = argc; log->context = lc; } return r; }