931 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2006-2009 Red Hat, Inc.4 *5 * This file is released under the LGPL.6 */7 8#include <linux/bio.h>9#include <linux/slab.h>10#include <linux/jiffies.h>11#include <linux/dm-dirty-log.h>12#include <linux/device-mapper.h>13#include <linux/dm-log-userspace.h>14#include <linux/module.h>15#include <linux/workqueue.h>16 17#include "dm-log-userspace-transfer.h"18 19#define DM_LOG_USERSPACE_VSN "1.3.0"20 21#define FLUSH_ENTRY_POOL_SIZE 1622 23struct dm_dirty_log_flush_entry {24 int type;25 region_t region;26 struct list_head list;27};28 29/*30 * This limit on the number of mark and clear request is, to a degree,31 * arbitrary. However, there is some basis for the choice in the limits32 * imposed on the size of data payload by dm-log-userspace-transfer.c:33 * dm_consult_userspace().34 */35#define MAX_FLUSH_GROUP_COUNT 3236 37struct log_c {38 struct dm_target *ti;39 struct dm_dev *log_dev;40 41 char *usr_argv_str;42 uint32_t usr_argc;43 44 uint32_t region_size;45 region_t region_count;46 uint64_t luid;47 char uuid[DM_UUID_LEN];48 49 /*50 * Mark and clear requests are held until a flush is issued51 * so that we can group, and thereby limit, the amount of52 * network traffic between kernel and userspace. The 'flush_lock'53 * is used to protect these lists.54 */55 spinlock_t flush_lock;56 struct list_head mark_list;57 struct list_head clear_list;58 59 /*60 * in_sync_hint gets set when doing is_remote_recovering. It61 * represents the first region that needs recovery. IOW, the62 * first zero bit of sync_bits. This can be useful for to limit63 * traffic for calls like is_remote_recovering and get_resync_work,64 * but be take care in its use for anything else.65 */66 uint64_t in_sync_hint;67 68 /*69 * Workqueue for flush of clear region requests.70 */71 struct workqueue_struct *dmlog_wq;72 struct delayed_work flush_log_work;73 atomic_t sched_flush;74 75 /*76 * Combine userspace flush and mark requests for efficiency.77 */78 uint32_t integrated_flush;79 80 mempool_t flush_entry_pool;81};82 83static struct kmem_cache *_flush_entry_cache;84 85static int userspace_do_request(struct log_c *lc, const char *uuid,86 int request_type, char *data, size_t data_size,87 char *rdata, size_t *rdata_size)88{89 int r;90 91 /*92 * If the server isn't there, -ESRCH is returned,93 * and we must keep trying until the server is94 * restored.95 */96retry:97 r = dm_consult_userspace(uuid, lc->luid, request_type, data,98 data_size, rdata, rdata_size);99 100 if (r != -ESRCH)101 return r;102 103 DMERR(" Userspace log server not found.");104 while (1) {105 set_current_state(TASK_INTERRUPTIBLE);106 schedule_timeout(2*HZ);107 DMWARN("Attempting to contact userspace log server...");108 r = dm_consult_userspace(uuid, lc->luid, DM_ULOG_CTR,109 lc->usr_argv_str,110 strlen(lc->usr_argv_str) + 1,111 NULL, NULL);112 if (!r)113 break;114 }115 DMINFO("Reconnected to userspace log server... DM_ULOG_CTR complete");116 r = dm_consult_userspace(uuid, lc->luid, DM_ULOG_RESUME, NULL,117 0, NULL, NULL);118 if (!r)119 goto retry;120 121 DMERR("Error trying to resume userspace log: %d", r);122 123 return -ESRCH;124}125 126static int build_constructor_string(struct dm_target *ti,127 unsigned int argc, char **argv,128 char **ctr_str)129{130 int i, str_size;131 char *str = NULL;132 133 *ctr_str = NULL;134 135 /*136 * Determine overall size of the string.137 */138 for (i = 0, str_size = 0; i < argc; i++)139 str_size += strlen(argv[i]) + 1; /* +1 for space between args */140 141 str_size += 20; /* Max number of chars in a printed u64 number */142 143 str = kzalloc(str_size, GFP_KERNEL);144 if (!str) {145 DMWARN("Unable to allocate memory for constructor string");146 return -ENOMEM;147 }148 149 str_size = sprintf(str, "%llu", (unsigned long long)ti->len);150 for (i = 0; i < argc; i++)151 str_size += sprintf(str + str_size, " %s", argv[i]);152 153 *ctr_str = str;154 return str_size;155}156 157static void do_flush(struct work_struct *work)158{159 int r;160 struct log_c *lc = container_of(work, struct log_c, flush_log_work.work);161 162 atomic_set(&lc->sched_flush, 0);163 164 r = userspace_do_request(lc, lc->uuid, DM_ULOG_FLUSH, NULL, 0, NULL, NULL);165 166 if (r)167 dm_table_event(lc->ti->table);168}169 170/*171 * userspace_ctr172 *173 * argv contains:174 * <UUID> [integrated_flush] <other args>175 * Where 'other args' are the userspace implementation-specific log176 * arguments.177 *178 * Example:179 * <UUID> [integrated_flush] clustered-disk <arg count> <log dev>180 * <region_size> [[no]sync]181 *182 * This module strips off the <UUID> and uses it for identification183 * purposes when communicating with userspace about a log.184 *185 * If integrated_flush is defined, the kernel combines flush186 * and mark requests.187 *188 * The rest of the line, beginning with 'clustered-disk', is passed189 * to the userspace ctr function.190 */191static int userspace_ctr(struct dm_dirty_log *log, struct dm_target *ti,192 unsigned int argc, char **argv)193{194 int r = 0;195 int str_size;196 char *ctr_str = NULL;197 struct log_c *lc = NULL;198 uint64_t rdata;199 size_t rdata_size = sizeof(rdata);200 char *devices_rdata = NULL;201 size_t devices_rdata_size = DM_NAME_LEN;202 203 if (argc < 3) {204 DMWARN("Too few arguments to userspace dirty log");205 return -EINVAL;206 }207 208 lc = kzalloc(sizeof(*lc), GFP_KERNEL);209 if (!lc) {210 DMWARN("Unable to allocate userspace log context.");211 return -ENOMEM;212 }213 214 /* The ptr value is sufficient for local unique id */215 lc->luid = (unsigned long)lc;216 217 lc->ti = ti;218 219 if (strlen(argv[0]) > (DM_UUID_LEN - 1)) {220 DMWARN("UUID argument too long.");221 kfree(lc);222 return -EINVAL;223 }224 225 lc->usr_argc = argc;226 227 strscpy(lc->uuid, argv[0], sizeof(lc->uuid));228 argc--;229 argv++;230 spin_lock_init(&lc->flush_lock);231 INIT_LIST_HEAD(&lc->mark_list);232 INIT_LIST_HEAD(&lc->clear_list);233 234 if (!strcasecmp(argv[0], "integrated_flush")) {235 lc->integrated_flush = 1;236 argc--;237 argv++;238 }239 240 str_size = build_constructor_string(ti, argc, argv, &ctr_str);241 if (str_size < 0) {242 kfree(lc);243 return str_size;244 }245 246 devices_rdata = kzalloc(devices_rdata_size, GFP_KERNEL);247 if (!devices_rdata) {248 DMERR("Failed to allocate memory for device information");249 r = -ENOMEM;250 goto out;251 }252 253 r = mempool_init_slab_pool(&lc->flush_entry_pool, FLUSH_ENTRY_POOL_SIZE,254 _flush_entry_cache);255 if (r) {256 DMERR("Failed to create flush_entry_pool");257 goto out;258 }259 260 /*261 * Send table string and get back any opened device.262 */263 r = dm_consult_userspace(lc->uuid, lc->luid, DM_ULOG_CTR,264 ctr_str, str_size,265 devices_rdata, &devices_rdata_size);266 267 if (r < 0) {268 if (r == -ESRCH)269 DMERR("Userspace log server not found");270 else271 DMERR("Userspace log server failed to create log");272 goto out;273 }274 275 /* Since the region size does not change, get it now */276 rdata_size = sizeof(rdata);277 r = dm_consult_userspace(lc->uuid, lc->luid, DM_ULOG_GET_REGION_SIZE,278 NULL, 0, (char *)&rdata, &rdata_size);279 280 if (r) {281 DMERR("Failed to get region size of dirty log");282 goto out;283 }284 285 lc->region_size = (uint32_t)rdata;286 lc->region_count = dm_sector_div_up(ti->len, lc->region_size);287 288 if (devices_rdata_size) {289 if (devices_rdata[devices_rdata_size - 1] != '\0') {290 DMERR("DM_ULOG_CTR device return string not properly terminated");291 r = -EINVAL;292 goto out;293 }294 r = dm_get_device(ti, devices_rdata,295 dm_table_get_mode(ti->table), &lc->log_dev);296 if (r)297 DMERR("Failed to register %s with device-mapper",298 devices_rdata);299 }300 301 if (lc->integrated_flush) {302 lc->dmlog_wq = alloc_workqueue("dmlogd", WQ_MEM_RECLAIM, 0);303 if (!lc->dmlog_wq) {304 DMERR("couldn't start dmlogd");305 r = -ENOMEM;306 goto out;307 }308 309 INIT_DELAYED_WORK(&lc->flush_log_work, do_flush);310 atomic_set(&lc->sched_flush, 0);311 }312 313out:314 kfree(devices_rdata);315 if (r) {316 mempool_exit(&lc->flush_entry_pool);317 kfree(lc);318 kfree(ctr_str);319 } else {320 lc->usr_argv_str = ctr_str;321 log->context = lc;322 }323 324 return r;325}326 327static void userspace_dtr(struct dm_dirty_log *log)328{329 struct log_c *lc = log->context;330 331 if (lc->integrated_flush) {332 /* flush workqueue */333 if (atomic_read(&lc->sched_flush))334 flush_delayed_work(&lc->flush_log_work);335 336 destroy_workqueue(lc->dmlog_wq);337 }338 339 (void) dm_consult_userspace(lc->uuid, lc->luid, DM_ULOG_DTR,340 NULL, 0, NULL, NULL);341 342 if (lc->log_dev)343 dm_put_device(lc->ti, lc->log_dev);344 345 mempool_exit(&lc->flush_entry_pool);346 347 kfree(lc->usr_argv_str);348 kfree(lc);349}350 351static int userspace_presuspend(struct dm_dirty_log *log)352{353 int r;354 struct log_c *lc = log->context;355 356 r = dm_consult_userspace(lc->uuid, lc->luid, DM_ULOG_PRESUSPEND,357 NULL, 0, NULL, NULL);358 359 return r;360}361 362static int userspace_postsuspend(struct dm_dirty_log *log)363{364 int r;365 struct log_c *lc = log->context;366 367 /*368 * Run planned flush earlier.369 */370 if (lc->integrated_flush && atomic_read(&lc->sched_flush))371 flush_delayed_work(&lc->flush_log_work);372 373 r = dm_consult_userspace(lc->uuid, lc->luid, DM_ULOG_POSTSUSPEND,374 NULL, 0, NULL, NULL);375 376 return r;377}378 379static int userspace_resume(struct dm_dirty_log *log)380{381 int r;382 struct log_c *lc = log->context;383 384 lc->in_sync_hint = 0;385 r = dm_consult_userspace(lc->uuid, lc->luid, DM_ULOG_RESUME,386 NULL, 0, NULL, NULL);387 388 return r;389}390 391static uint32_t userspace_get_region_size(struct dm_dirty_log *log)392{393 struct log_c *lc = log->context;394 395 return lc->region_size;396}397 398/*399 * userspace_is_clean400 *401 * Check whether a region is clean. If there is any sort of402 * failure when consulting the server, we return not clean.403 *404 * Returns: 1 if clean, 0 otherwise405 */406static int userspace_is_clean(struct dm_dirty_log *log, region_t region)407{408 int r;409 uint64_t region64 = (uint64_t)region;410 int64_t is_clean;411 size_t rdata_size;412 struct log_c *lc = log->context;413 414 rdata_size = sizeof(is_clean);415 r = userspace_do_request(lc, lc->uuid, DM_ULOG_IS_CLEAN,416 (char *)®ion64, sizeof(region64),417 (char *)&is_clean, &rdata_size);418 419 return (r) ? 0 : (int)is_clean;420}421 422/*423 * userspace_in_sync424 *425 * Check if the region is in-sync. If there is any sort426 * of failure when consulting the server, we assume that427 * the region is not in sync.428 *429 * If 'can_block' is set, return immediately430 *431 * Returns: 1 if in-sync, 0 if not-in-sync, -EWOULDBLOCK432 */433static int userspace_in_sync(struct dm_dirty_log *log, region_t region,434 int can_block)435{436 int r;437 uint64_t region64 = region;438 int64_t in_sync;439 size_t rdata_size;440 struct log_c *lc = log->context;441 442 /*443 * We can never respond directly - even if in_sync_hint is444 * set. This is because another machine could see a device445 * failure and mark the region out-of-sync. If we don't go446 * to userspace to ask, we might think the region is in-sync447 * and allow a read to pick up data that is stale. (This is448 * very unlikely if a device actually fails; but it is very449 * likely if a connection to one device from one machine fails.)450 *451 * There still might be a problem if the mirror caches the region452 * state as in-sync... but then this call would not be made. So,453 * that is a mirror problem.454 */455 if (!can_block)456 return -EWOULDBLOCK;457 458 rdata_size = sizeof(in_sync);459 r = userspace_do_request(lc, lc->uuid, DM_ULOG_IN_SYNC,460 (char *)®ion64, sizeof(region64),461 (char *)&in_sync, &rdata_size);462 return (r) ? 0 : (int)in_sync;463}464 465static int flush_one_by_one(struct log_c *lc, struct list_head *flush_list)466{467 int r = 0;468 struct dm_dirty_log_flush_entry *fe;469 470 list_for_each_entry(fe, flush_list, list) {471 r = userspace_do_request(lc, lc->uuid, fe->type,472 (char *)&fe->region,473 sizeof(fe->region),474 NULL, NULL);475 if (r)476 break;477 }478 479 return r;480}481 482static int flush_by_group(struct log_c *lc, struct list_head *flush_list,483 int flush_with_payload)484{485 int r = 0;486 int count;487 uint32_t type = 0;488 struct dm_dirty_log_flush_entry *fe, *tmp_fe;489 LIST_HEAD(tmp_list);490 uint64_t group[MAX_FLUSH_GROUP_COUNT];491 492 /*493 * Group process the requests494 */495 while (!list_empty(flush_list)) {496 count = 0;497 498 list_for_each_entry_safe(fe, tmp_fe, flush_list, list) {499 group[count] = fe->region;500 count++;501 502 list_move(&fe->list, &tmp_list);503 504 type = fe->type;505 if (count >= MAX_FLUSH_GROUP_COUNT)506 break;507 }508 509 if (flush_with_payload) {510 r = userspace_do_request(lc, lc->uuid, DM_ULOG_FLUSH,511 (char *)(group),512 count * sizeof(uint64_t),513 NULL, NULL);514 /*515 * Integrated flush failed.516 */517 if (r)518 break;519 } else {520 r = userspace_do_request(lc, lc->uuid, type,521 (char *)(group),522 count * sizeof(uint64_t),523 NULL, NULL);524 if (r) {525 /*526 * Group send failed. Attempt one-by-one.527 */528 list_splice_init(&tmp_list, flush_list);529 r = flush_one_by_one(lc, flush_list);530 break;531 }532 }533 }534 535 /*536 * Must collect flush_entrys that were successfully processed537 * as a group so that they will be free'd by the caller.538 */539 list_splice_init(&tmp_list, flush_list);540 541 return r;542}543 544/*545 * userspace_flush546 *547 * This function is ok to block.548 * The flush happens in two stages. First, it sends all549 * clear/mark requests that are on the list. Then it550 * tells the server to commit them. This gives the551 * server a chance to optimise the commit, instead of552 * doing it for every request.553 *554 * Additionally, we could implement another thread that555 * sends the requests up to the server - reducing the556 * load on flush. Then the flush would have less in557 * the list and be responsible for the finishing commit.558 *559 * Returns: 0 on success, < 0 on failure560 */561static int userspace_flush(struct dm_dirty_log *log)562{563 int r = 0;564 unsigned long flags;565 struct log_c *lc = log->context;566 LIST_HEAD(mark_list);567 LIST_HEAD(clear_list);568 int mark_list_is_empty;569 int clear_list_is_empty;570 struct dm_dirty_log_flush_entry *fe, *tmp_fe;571 mempool_t *flush_entry_pool = &lc->flush_entry_pool;572 573 spin_lock_irqsave(&lc->flush_lock, flags);574 list_splice_init(&lc->mark_list, &mark_list);575 list_splice_init(&lc->clear_list, &clear_list);576 spin_unlock_irqrestore(&lc->flush_lock, flags);577 578 mark_list_is_empty = list_empty(&mark_list);579 clear_list_is_empty = list_empty(&clear_list);580 581 if (mark_list_is_empty && clear_list_is_empty)582 return 0;583 584 r = flush_by_group(lc, &clear_list, 0);585 if (r)586 goto out;587 588 if (!lc->integrated_flush) {589 r = flush_by_group(lc, &mark_list, 0);590 if (r)591 goto out;592 r = userspace_do_request(lc, lc->uuid, DM_ULOG_FLUSH,593 NULL, 0, NULL, NULL);594 goto out;595 }596 597 /*598 * Send integrated flush request with mark_list as payload.599 */600 r = flush_by_group(lc, &mark_list, 1);601 if (r)602 goto out;603 604 if (mark_list_is_empty && !atomic_read(&lc->sched_flush)) {605 /*606 * When there are only clear region requests,607 * we schedule a flush in the future.608 */609 queue_delayed_work(lc->dmlog_wq, &lc->flush_log_work, 3 * HZ);610 atomic_set(&lc->sched_flush, 1);611 } else {612 /*613 * Cancel pending flush because we614 * have already flushed in mark_region.615 */616 cancel_delayed_work(&lc->flush_log_work);617 atomic_set(&lc->sched_flush, 0);618 }619 620out:621 /*622 * We can safely remove these entries, even after failure.623 * Calling code will receive an error and will know that624 * the log facility has failed.625 */626 list_for_each_entry_safe(fe, tmp_fe, &mark_list, list) {627 list_del(&fe->list);628 mempool_free(fe, flush_entry_pool);629 }630 list_for_each_entry_safe(fe, tmp_fe, &clear_list, list) {631 list_del(&fe->list);632 mempool_free(fe, flush_entry_pool);633 }634 635 if (r)636 dm_table_event(lc->ti->table);637 638 return r;639}640 641/*642 * userspace_mark_region643 *644 * This function should avoid blocking unless absolutely required.645 * (Memory allocation is valid for blocking.)646 */647static void userspace_mark_region(struct dm_dirty_log *log, region_t region)648{649 unsigned long flags;650 struct log_c *lc = log->context;651 struct dm_dirty_log_flush_entry *fe;652 653 /* Wait for an allocation, but _never_ fail */654 fe = mempool_alloc(&lc->flush_entry_pool, GFP_NOIO);655 BUG_ON(!fe);656 657 spin_lock_irqsave(&lc->flush_lock, flags);658 fe->type = DM_ULOG_MARK_REGION;659 fe->region = region;660 list_add(&fe->list, &lc->mark_list);661 spin_unlock_irqrestore(&lc->flush_lock, flags);662}663 664/*665 * userspace_clear_region666 *667 * This function must not block.668 * So, the alloc can't block. In the worst case, it is ok to669 * fail. It would simply mean we can't clear the region.670 * Does nothing to current sync context, but does mean671 * the region will be re-sync'ed on a reload of the mirror672 * even though it is in-sync.673 */674static void userspace_clear_region(struct dm_dirty_log *log, region_t region)675{676 unsigned long flags;677 struct log_c *lc = log->context;678 struct dm_dirty_log_flush_entry *fe;679 680 /*681 * If we fail to allocate, we skip the clearing of682 * the region. This doesn't hurt us in any way, except683 * to cause the region to be resync'ed when the684 * device is activated next time.685 */686 fe = mempool_alloc(&lc->flush_entry_pool, GFP_ATOMIC);687 if (!fe) {688 DMERR("Failed to allocate memory to clear region.");689 return;690 }691 692 spin_lock_irqsave(&lc->flush_lock, flags);693 fe->type = DM_ULOG_CLEAR_REGION;694 fe->region = region;695 list_add(&fe->list, &lc->clear_list);696 spin_unlock_irqrestore(&lc->flush_lock, flags);697}698 699/*700 * userspace_get_resync_work701 *702 * Get a region that needs recovery. It is valid to return703 * an error for this function.704 *705 * Returns: 1 if region filled, 0 if no work, <0 on error706 */707static int userspace_get_resync_work(struct dm_dirty_log *log, region_t *region)708{709 int r;710 size_t rdata_size;711 struct log_c *lc = log->context;712 struct {713 int64_t i; /* 64-bit for mix arch compatibility */714 region_t r;715 } pkg;716 717 if (lc->in_sync_hint >= lc->region_count)718 return 0;719 720 rdata_size = sizeof(pkg);721 r = userspace_do_request(lc, lc->uuid, DM_ULOG_GET_RESYNC_WORK,722 NULL, 0, (char *)&pkg, &rdata_size);723 724 *region = pkg.r;725 return (r) ? r : (int)pkg.i;726}727 728/*729 * userspace_set_region_sync730 *731 * Set the sync status of a given region. This function732 * must not fail.733 */734static void userspace_set_region_sync(struct dm_dirty_log *log,735 region_t region, int in_sync)736{737 struct log_c *lc = log->context;738 struct {739 region_t r;740 int64_t i;741 } pkg;742 743 pkg.r = region;744 pkg.i = (int64_t)in_sync;745 746 (void) userspace_do_request(lc, lc->uuid, DM_ULOG_SET_REGION_SYNC,747 (char *)&pkg, sizeof(pkg), NULL, NULL);748 749 /*750 * It would be nice to be able to report failures.751 * However, it is easy enough to detect and resolve.752 */753}754 755/*756 * userspace_get_sync_count757 *758 * If there is any sort of failure when consulting the server,759 * we assume that the sync count is zero.760 *761 * Returns: sync count on success, 0 on failure762 */763static region_t userspace_get_sync_count(struct dm_dirty_log *log)764{765 int r;766 size_t rdata_size;767 uint64_t sync_count;768 struct log_c *lc = log->context;769 770 rdata_size = sizeof(sync_count);771 r = userspace_do_request(lc, lc->uuid, DM_ULOG_GET_SYNC_COUNT,772 NULL, 0, (char *)&sync_count, &rdata_size);773 774 if (r)775 return 0;776 777 if (sync_count >= lc->region_count)778 lc->in_sync_hint = lc->region_count;779 780 return (region_t)sync_count;781}782 783/*784 * userspace_status785 *786 * Returns: amount of space consumed787 */788static int userspace_status(struct dm_dirty_log *log, status_type_t status_type,789 char *result, unsigned int maxlen)790{791 int r = 0;792 char *table_args;793 size_t sz = (size_t)maxlen;794 struct log_c *lc = log->context;795 796 switch (status_type) {797 case STATUSTYPE_INFO:798 r = userspace_do_request(lc, lc->uuid, DM_ULOG_STATUS_INFO,799 NULL, 0, result, &sz);800 801 if (r) {802 sz = 0;803 DMEMIT("%s 1 COM_FAILURE", log->type->name);804 }805 break;806 case STATUSTYPE_TABLE:807 sz = 0;808 table_args = strchr(lc->usr_argv_str, ' ');809 BUG_ON(!table_args); /* There will always be a ' ' */810 table_args++;811 812 DMEMIT("%s %u %s ", log->type->name, lc->usr_argc, lc->uuid);813 if (lc->integrated_flush)814 DMEMIT("integrated_flush ");815 DMEMIT("%s ", table_args);816 break;817 case STATUSTYPE_IMA:818 *result = '\0';819 break;820 }821 return (r) ? 0 : (int)sz;822}823 824/*825 * userspace_is_remote_recovering826 *827 * Returns: 1 if region recovering, 0 otherwise828 */829static int userspace_is_remote_recovering(struct dm_dirty_log *log,830 region_t region)831{832 int r;833 uint64_t region64 = region;834 struct log_c *lc = log->context;835 static unsigned long limit;836 struct {837 int64_t is_recovering;838 uint64_t in_sync_hint;839 } pkg;840 size_t rdata_size = sizeof(pkg);841 842 /*843 * Once the mirror has been reported to be in-sync,844 * it will never again ask for recovery work. So,845 * we can safely say there is not a remote machine846 * recovering if the device is in-sync. (in_sync_hint847 * must be reset at resume time.)848 */849 if (region < lc->in_sync_hint)850 return 0;851 else if (time_after(limit, jiffies))852 return 1;853 854 limit = jiffies + (HZ / 4);855 r = userspace_do_request(lc, lc->uuid, DM_ULOG_IS_REMOTE_RECOVERING,856 (char *)®ion64, sizeof(region64),857 (char *)&pkg, &rdata_size);858 if (r)859 return 1;860 861 lc->in_sync_hint = pkg.in_sync_hint;862 863 return (int)pkg.is_recovering;864}865 866static struct dm_dirty_log_type _userspace_type = {867 .name = "userspace",868 .module = THIS_MODULE,869 .ctr = userspace_ctr,870 .dtr = userspace_dtr,871 .presuspend = userspace_presuspend,872 .postsuspend = userspace_postsuspend,873 .resume = userspace_resume,874 .get_region_size = userspace_get_region_size,875 .is_clean = userspace_is_clean,876 .in_sync = userspace_in_sync,877 .flush = userspace_flush,878 .mark_region = userspace_mark_region,879 .clear_region = userspace_clear_region,880 .get_resync_work = userspace_get_resync_work,881 .set_region_sync = userspace_set_region_sync,882 .get_sync_count = userspace_get_sync_count,883 .status = userspace_status,884 .is_remote_recovering = userspace_is_remote_recovering,885};886 887static int __init userspace_dirty_log_init(void)888{889 int r = 0;890 891 _flush_entry_cache = KMEM_CACHE(dm_dirty_log_flush_entry, 0);892 if (!_flush_entry_cache) {893 DMWARN("Unable to create flush_entry_cache: No memory.");894 return -ENOMEM;895 }896 897 r = dm_ulog_tfr_init();898 if (r) {899 DMWARN("Unable to initialize userspace log communications");900 kmem_cache_destroy(_flush_entry_cache);901 return r;902 }903 904 r = dm_dirty_log_type_register(&_userspace_type);905 if (r) {906 DMWARN("Couldn't register userspace dirty log type");907 dm_ulog_tfr_exit();908 kmem_cache_destroy(_flush_entry_cache);909 return r;910 }911 912 DMINFO("version " DM_LOG_USERSPACE_VSN " loaded");913 return 0;914}915 916static void __exit userspace_dirty_log_exit(void)917{918 dm_dirty_log_type_unregister(&_userspace_type);919 dm_ulog_tfr_exit();920 kmem_cache_destroy(_flush_entry_cache);921 922 DMINFO("version " DM_LOG_USERSPACE_VSN " unloaded");923}924 925module_init(userspace_dirty_log_init);926module_exit(userspace_dirty_log_exit);927 928MODULE_DESCRIPTION(DM_NAME " userspace dirty log link");929MODULE_AUTHOR("Jonathan Brassow <dm-devel@lists.linux.dev>");930MODULE_LICENSE("GPL");931