static void userspace_dtr(struct dm_dirty_log *log) { struct log_c *lc = log->context; if (lc->integrated_flush) { /* flush workqueue */ if (atomic_read(&lc->sched_flush)) flush_delayed_work(&lc->flush_log_work); destroy_workqueue(lc->dmlog_wq); } (void) dm_consult_userspace(lc->uuid, lc->luid, DM_ULOG_DTR, NULL, 0, NULL, NULL); if (lc->log_dev) dm_put_device(lc->ti, lc->log_dev); mempool_destroy(lc->flush_entry_pool); kfree(lc->usr_argv_str); kfree(lc); return; }
static int userspace_presuspend(struct dm_dirty_log *log) { int r; struct log_c *lc = log->context; r = dm_consult_userspace(lc->uuid, lc->luid, DM_ULOG_PRESUSPEND, NULL, 0, NULL, NULL); return r; }
static int userspace_resume(struct dm_dirty_log *log) { int r; struct log_c *lc = log->context; lc->in_sync_hint = 0; r = dm_consult_userspace(lc->uuid, lc->luid, DM_ULOG_RESUME, NULL, 0, NULL, NULL); return r; }
static int userspace_do_request(struct log_c *lc, const char *uuid, int request_type, char *data, size_t data_size, char *rdata, size_t *rdata_size) { int r; /* * If the server isn't there, -ESRCH is returned, * and we must keep trying until the server is * restored. */ retry: r = dm_consult_userspace(uuid, lc->luid, request_type, data, data_size, rdata, rdata_size); if (r != -ESRCH) return r; DMERR(" Userspace log server not found."); while (1) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(2*HZ); DMWARN("Attempting to contact userspace log server..."); r = dm_consult_userspace(uuid, lc->luid, DM_ULOG_CTR, lc->usr_argv_str, strlen(lc->usr_argv_str) + 1, NULL, NULL); if (!r) break; } DMINFO("Reconnected to userspace log server... DM_ULOG_CTR complete"); r = dm_consult_userspace(uuid, lc->luid, DM_ULOG_RESUME, NULL, 0, NULL, NULL); if (!r) goto retry; DMERR("Error trying to resume userspace log: %d", r); return -ESRCH; }
static void userspace_dtr(struct dm_dirty_log *log) { struct log_c *lc = log->context; (void) dm_consult_userspace(lc->uuid, lc->luid, DM_ULOG_DTR, NULL, 0, NULL, NULL); kfree(lc->usr_argv_str); kfree(lc); return; }
static int userspace_postsuspend(struct dm_dirty_log *log) { int r; struct log_c *lc = log->context; /* * Run planned flush earlier. */ if (lc->integrated_flush && atomic_read(&lc->sched_flush)) flush_delayed_work(&lc->flush_log_work); r = dm_consult_userspace(lc->uuid, lc->luid, DM_ULOG_POSTSUSPEND, NULL, 0, NULL, NULL); return r; }
/* * 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; }
/* * 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; }