dm-region-hash.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 2003 Sistina Software Limited.
  4. * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
  5. *
  6. * This file is released under the GPL.
  7. */
  8. #include <linux/dm-dirty-log.h>
  9. #include <linux/dm-region-hash.h>
  10. #include <linux/ctype.h>
  11. #include <linux/init.h>
  12. #include <linux/module.h>
  13. #include <linux/slab.h>
  14. #include <linux/vmalloc.h>
  15. #include "dm.h"
  16. #define DM_MSG_PREFIX "region hash"
  17. /*
  18. *------------------------------------------------------------------
  19. * Region hash
  20. *
  21. * The mirror splits itself up into discrete regions. Each
  22. * region can be in one of three states: clean, dirty,
  23. * nosync. There is no need to put clean regions in the hash.
  24. *
  25. * In addition to being present in the hash table a region _may_
  26. * be present on one of three lists.
  27. *
  28. * clean_regions: Regions on this list have no io pending to
  29. * them, they are in sync, we are no longer interested in them,
  30. * they are dull. dm_rh_update_states() will remove them from the
  31. * hash table.
  32. *
  33. * quiesced_regions: These regions have been spun down, ready
  34. * for recovery. rh_recovery_start() will remove regions from
  35. * this list and hand them to kmirrord, which will schedule the
  36. * recovery io with kcopyd.
  37. *
  38. * recovered_regions: Regions that kcopyd has successfully
  39. * recovered. dm_rh_update_states() will now schedule any delayed
  40. * io, up the recovery_count, and remove the region from the
  41. * hash.
  42. *
  43. * There are 2 locks:
  44. * A rw spin lock 'hash_lock' protects just the hash table,
  45. * this is never held in write mode from interrupt context,
  46. * which I believe means that we only have to disable irqs when
  47. * doing a write lock.
  48. *
  49. * An ordinary spin lock 'region_lock' that protects the three
  50. * lists in the region_hash, with the 'state', 'list' and
  51. * 'delayed_bios' fields of the regions. This is used from irq
  52. * context, so all other uses will have to suspend local irqs.
  53. *------------------------------------------------------------------
  54. */
  55. struct dm_region_hash {
  56. uint32_t region_size;
  57. unsigned int region_shift;
  58. /* holds persistent region state */
  59. struct dm_dirty_log *log;
  60. /* hash table */
  61. rwlock_t hash_lock;
  62. unsigned int mask;
  63. unsigned int nr_buckets;
  64. unsigned int prime;
  65. unsigned int shift;
  66. struct list_head *buckets;
  67. /*
  68. * If there was a flush failure no regions can be marked clean.
  69. */
  70. int flush_failure;
  71. unsigned int max_recovery; /* Max # of regions to recover in parallel */
  72. spinlock_t region_lock;
  73. atomic_t recovery_in_flight;
  74. struct list_head clean_regions;
  75. struct list_head quiesced_regions;
  76. struct list_head recovered_regions;
  77. struct list_head failed_recovered_regions;
  78. struct semaphore recovery_count;
  79. mempool_t region_pool;
  80. void *context;
  81. sector_t target_begin;
  82. /* Callback function to schedule bios writes */
  83. void (*dispatch_bios)(void *context, struct bio_list *bios);
  84. /* Callback function to wakeup callers worker thread. */
  85. void (*wakeup_workers)(void *context);
  86. /* Callback function to wakeup callers recovery waiters. */
  87. void (*wakeup_all_recovery_waiters)(void *context);
  88. };
  89. struct dm_region {
  90. struct dm_region_hash *rh; /* FIXME: can we get rid of this ? */
  91. region_t key;
  92. int state;
  93. struct list_head hash_list;
  94. struct list_head list;
  95. atomic_t pending;
  96. struct bio_list delayed_bios;
  97. };
  98. /*
  99. * Conversion fns
  100. */
  101. static region_t dm_rh_sector_to_region(struct dm_region_hash *rh, sector_t sector)
  102. {
  103. return sector >> rh->region_shift;
  104. }
  105. sector_t dm_rh_region_to_sector(struct dm_region_hash *rh, region_t region)
  106. {
  107. return region << rh->region_shift;
  108. }
  109. EXPORT_SYMBOL_GPL(dm_rh_region_to_sector);
  110. region_t dm_rh_bio_to_region(struct dm_region_hash *rh, struct bio *bio)
  111. {
  112. return dm_rh_sector_to_region(rh, bio->bi_iter.bi_sector -
  113. rh->target_begin);
  114. }
  115. EXPORT_SYMBOL_GPL(dm_rh_bio_to_region);
  116. void *dm_rh_region_context(struct dm_region *reg)
  117. {
  118. return reg->rh->context;
  119. }
  120. EXPORT_SYMBOL_GPL(dm_rh_region_context);
  121. region_t dm_rh_get_region_key(struct dm_region *reg)
  122. {
  123. return reg->key;
  124. }
  125. EXPORT_SYMBOL_GPL(dm_rh_get_region_key);
  126. sector_t dm_rh_get_region_size(struct dm_region_hash *rh)
  127. {
  128. return rh->region_size;
  129. }
  130. EXPORT_SYMBOL_GPL(dm_rh_get_region_size);
  131. /*
  132. * FIXME: shall we pass in a structure instead of all these args to
  133. * dm_region_hash_create()????
  134. */
  135. #define RH_HASH_MULT 2654435387U
  136. #define RH_HASH_SHIFT 12
  137. #define MIN_REGIONS 64
  138. struct dm_region_hash *dm_region_hash_create(
  139. void *context, void (*dispatch_bios)(void *context,
  140. struct bio_list *bios),
  141. void (*wakeup_workers)(void *context),
  142. void (*wakeup_all_recovery_waiters)(void *context),
  143. sector_t target_begin, unsigned int max_recovery,
  144. struct dm_dirty_log *log, uint32_t region_size,
  145. region_t nr_regions)
  146. {
  147. struct dm_region_hash *rh;
  148. unsigned int nr_buckets, max_buckets;
  149. size_t i;
  150. int ret;
  151. /*
  152. * Calculate a suitable number of buckets for our hash
  153. * table.
  154. */
  155. max_buckets = nr_regions >> 6;
  156. for (nr_buckets = 128u; nr_buckets < max_buckets; nr_buckets <<= 1)
  157. ;
  158. nr_buckets >>= 1;
  159. rh = kzalloc_obj(*rh);
  160. if (!rh) {
  161. DMERR("unable to allocate region hash memory");
  162. return ERR_PTR(-ENOMEM);
  163. }
  164. rh->context = context;
  165. rh->dispatch_bios = dispatch_bios;
  166. rh->wakeup_workers = wakeup_workers;
  167. rh->wakeup_all_recovery_waiters = wakeup_all_recovery_waiters;
  168. rh->target_begin = target_begin;
  169. rh->max_recovery = max_recovery;
  170. rh->log = log;
  171. rh->region_size = region_size;
  172. rh->region_shift = __ffs(region_size);
  173. rwlock_init(&rh->hash_lock);
  174. rh->mask = nr_buckets - 1;
  175. rh->nr_buckets = nr_buckets;
  176. rh->shift = RH_HASH_SHIFT;
  177. rh->prime = RH_HASH_MULT;
  178. rh->buckets = vmalloc_array(nr_buckets, sizeof(*rh->buckets));
  179. if (!rh->buckets) {
  180. DMERR("unable to allocate region hash bucket memory");
  181. kfree(rh);
  182. return ERR_PTR(-ENOMEM);
  183. }
  184. for (i = 0; i < nr_buckets; i++)
  185. INIT_LIST_HEAD(rh->buckets + i);
  186. spin_lock_init(&rh->region_lock);
  187. sema_init(&rh->recovery_count, 0);
  188. atomic_set(&rh->recovery_in_flight, 0);
  189. INIT_LIST_HEAD(&rh->clean_regions);
  190. INIT_LIST_HEAD(&rh->quiesced_regions);
  191. INIT_LIST_HEAD(&rh->recovered_regions);
  192. INIT_LIST_HEAD(&rh->failed_recovered_regions);
  193. rh->flush_failure = 0;
  194. ret = mempool_init_kmalloc_pool(&rh->region_pool, MIN_REGIONS,
  195. sizeof(struct dm_region));
  196. if (ret) {
  197. vfree(rh->buckets);
  198. kfree(rh);
  199. rh = ERR_PTR(-ENOMEM);
  200. }
  201. return rh;
  202. }
  203. EXPORT_SYMBOL_GPL(dm_region_hash_create);
  204. void dm_region_hash_destroy(struct dm_region_hash *rh)
  205. {
  206. unsigned int h;
  207. struct dm_region *reg, *nreg;
  208. BUG_ON(!list_empty(&rh->quiesced_regions));
  209. for (h = 0; h < rh->nr_buckets; h++) {
  210. list_for_each_entry_safe(reg, nreg, rh->buckets + h,
  211. hash_list) {
  212. BUG_ON(atomic_read(&reg->pending));
  213. mempool_free(reg, &rh->region_pool);
  214. }
  215. }
  216. if (rh->log)
  217. dm_dirty_log_destroy(rh->log);
  218. mempool_exit(&rh->region_pool);
  219. vfree(rh->buckets);
  220. kfree(rh);
  221. }
  222. EXPORT_SYMBOL_GPL(dm_region_hash_destroy);
  223. struct dm_dirty_log *dm_rh_dirty_log(struct dm_region_hash *rh)
  224. {
  225. return rh->log;
  226. }
  227. EXPORT_SYMBOL_GPL(dm_rh_dirty_log);
  228. static unsigned int rh_hash(struct dm_region_hash *rh, region_t region)
  229. {
  230. return (unsigned int) ((region * rh->prime) >> rh->shift) & rh->mask;
  231. }
  232. static struct dm_region *__rh_lookup(struct dm_region_hash *rh, region_t region)
  233. {
  234. struct dm_region *reg;
  235. struct list_head *bucket = rh->buckets + rh_hash(rh, region);
  236. list_for_each_entry(reg, bucket, hash_list)
  237. if (reg->key == region)
  238. return reg;
  239. return NULL;
  240. }
  241. static void __rh_insert(struct dm_region_hash *rh, struct dm_region *reg)
  242. {
  243. list_add(&reg->hash_list, rh->buckets + rh_hash(rh, reg->key));
  244. }
  245. static struct dm_region *__rh_alloc(struct dm_region_hash *rh, region_t region)
  246. {
  247. struct dm_region *reg, *nreg;
  248. nreg = mempool_alloc(&rh->region_pool, GFP_ATOMIC);
  249. if (unlikely(!nreg))
  250. nreg = kmalloc_obj(*nreg, GFP_NOIO | __GFP_NOFAIL);
  251. nreg->state = rh->log->type->in_sync(rh->log, region, 1) ?
  252. DM_RH_CLEAN : DM_RH_NOSYNC;
  253. nreg->rh = rh;
  254. nreg->key = region;
  255. INIT_LIST_HEAD(&nreg->list);
  256. atomic_set(&nreg->pending, 0);
  257. bio_list_init(&nreg->delayed_bios);
  258. write_lock_irq(&rh->hash_lock);
  259. reg = __rh_lookup(rh, region);
  260. if (reg)
  261. /* We lost the race. */
  262. mempool_free(nreg, &rh->region_pool);
  263. else {
  264. __rh_insert(rh, nreg);
  265. if (nreg->state == DM_RH_CLEAN) {
  266. spin_lock(&rh->region_lock);
  267. list_add(&nreg->list, &rh->clean_regions);
  268. spin_unlock(&rh->region_lock);
  269. }
  270. reg = nreg;
  271. }
  272. write_unlock_irq(&rh->hash_lock);
  273. return reg;
  274. }
  275. static struct dm_region *__rh_find(struct dm_region_hash *rh, region_t region)
  276. {
  277. struct dm_region *reg;
  278. reg = __rh_lookup(rh, region);
  279. if (!reg) {
  280. read_unlock(&rh->hash_lock);
  281. reg = __rh_alloc(rh, region);
  282. read_lock(&rh->hash_lock);
  283. }
  284. return reg;
  285. }
  286. int dm_rh_get_state(struct dm_region_hash *rh, region_t region, int may_block)
  287. {
  288. int r;
  289. struct dm_region *reg;
  290. read_lock(&rh->hash_lock);
  291. reg = __rh_lookup(rh, region);
  292. read_unlock(&rh->hash_lock);
  293. if (reg)
  294. return reg->state;
  295. /*
  296. * The region wasn't in the hash, so we fall back to the
  297. * dirty log.
  298. */
  299. r = rh->log->type->in_sync(rh->log, region, may_block);
  300. /*
  301. * Any error from the dirty log (eg. -EWOULDBLOCK) gets
  302. * taken as a DM_RH_NOSYNC
  303. */
  304. return r == 1 ? DM_RH_CLEAN : DM_RH_NOSYNC;
  305. }
  306. EXPORT_SYMBOL_GPL(dm_rh_get_state);
  307. static void complete_resync_work(struct dm_region *reg, int success)
  308. {
  309. struct dm_region_hash *rh = reg->rh;
  310. rh->log->type->set_region_sync(rh->log, reg->key, success);
  311. /*
  312. * Dispatch the bios before we call 'wake_up_all'.
  313. * This is important because if we are suspending,
  314. * we want to know that recovery is complete and
  315. * the work queue is flushed. If we wake_up_all
  316. * before we dispatch_bios (queue bios and call wake()),
  317. * then we risk suspending before the work queue
  318. * has been properly flushed.
  319. */
  320. rh->dispatch_bios(rh->context, &reg->delayed_bios);
  321. if (atomic_dec_and_test(&rh->recovery_in_flight))
  322. rh->wakeup_all_recovery_waiters(rh->context);
  323. up(&rh->recovery_count);
  324. }
  325. /* dm_rh_mark_nosync
  326. * @ms
  327. * @bio
  328. *
  329. * The bio was written on some mirror(s) but failed on other mirror(s).
  330. * We can successfully endio the bio but should avoid the region being
  331. * marked clean by setting the state DM_RH_NOSYNC.
  332. *
  333. * This function is _not_ safe in interrupt context!
  334. */
  335. void dm_rh_mark_nosync(struct dm_region_hash *rh, struct bio *bio)
  336. {
  337. unsigned long flags;
  338. struct dm_dirty_log *log = rh->log;
  339. struct dm_region *reg;
  340. region_t region = dm_rh_bio_to_region(rh, bio);
  341. int recovering = 0;
  342. if (bio->bi_opf & REQ_PREFLUSH) {
  343. rh->flush_failure = 1;
  344. return;
  345. }
  346. if (bio_op(bio) == REQ_OP_DISCARD)
  347. return;
  348. /* We must inform the log that the sync count has changed. */
  349. log->type->set_region_sync(log, region, 0);
  350. read_lock(&rh->hash_lock);
  351. reg = __rh_find(rh, region);
  352. read_unlock(&rh->hash_lock);
  353. /* region hash entry should exist because write was in-flight */
  354. BUG_ON(!reg);
  355. BUG_ON(!list_empty(&reg->list));
  356. spin_lock_irqsave(&rh->region_lock, flags);
  357. /*
  358. * Possible cases:
  359. * 1) DM_RH_DIRTY
  360. * 2) DM_RH_NOSYNC: was dirty, other preceding writes failed
  361. * 3) DM_RH_RECOVERING: flushing pending writes
  362. * Either case, the region should have not been connected to list.
  363. */
  364. recovering = (reg->state == DM_RH_RECOVERING);
  365. reg->state = DM_RH_NOSYNC;
  366. BUG_ON(!list_empty(&reg->list));
  367. spin_unlock_irqrestore(&rh->region_lock, flags);
  368. if (recovering)
  369. complete_resync_work(reg, 0);
  370. }
  371. EXPORT_SYMBOL_GPL(dm_rh_mark_nosync);
  372. void dm_rh_update_states(struct dm_region_hash *rh, int errors_handled)
  373. {
  374. struct dm_region *reg, *next;
  375. LIST_HEAD(clean);
  376. LIST_HEAD(recovered);
  377. LIST_HEAD(failed_recovered);
  378. /*
  379. * Quickly grab the lists.
  380. */
  381. write_lock_irq(&rh->hash_lock);
  382. spin_lock(&rh->region_lock);
  383. if (!list_empty(&rh->clean_regions)) {
  384. list_splice_init(&rh->clean_regions, &clean);
  385. list_for_each_entry(reg, &clean, list)
  386. list_del(&reg->hash_list);
  387. }
  388. if (!list_empty(&rh->recovered_regions)) {
  389. list_splice_init(&rh->recovered_regions, &recovered);
  390. list_for_each_entry(reg, &recovered, list)
  391. list_del(&reg->hash_list);
  392. }
  393. if (!list_empty(&rh->failed_recovered_regions)) {
  394. list_splice_init(&rh->failed_recovered_regions,
  395. &failed_recovered);
  396. list_for_each_entry(reg, &failed_recovered, list)
  397. list_del(&reg->hash_list);
  398. }
  399. spin_unlock(&rh->region_lock);
  400. write_unlock_irq(&rh->hash_lock);
  401. /*
  402. * All the regions on the recovered and clean lists have
  403. * now been pulled out of the system, so no need to do
  404. * any more locking.
  405. */
  406. list_for_each_entry_safe(reg, next, &recovered, list) {
  407. rh->log->type->clear_region(rh->log, reg->key);
  408. complete_resync_work(reg, 1);
  409. mempool_free(reg, &rh->region_pool);
  410. }
  411. list_for_each_entry_safe(reg, next, &failed_recovered, list) {
  412. complete_resync_work(reg, errors_handled ? 0 : 1);
  413. mempool_free(reg, &rh->region_pool);
  414. }
  415. list_for_each_entry_safe(reg, next, &clean, list) {
  416. rh->log->type->clear_region(rh->log, reg->key);
  417. mempool_free(reg, &rh->region_pool);
  418. }
  419. rh->log->type->flush(rh->log);
  420. }
  421. EXPORT_SYMBOL_GPL(dm_rh_update_states);
  422. static void rh_inc(struct dm_region_hash *rh, region_t region)
  423. {
  424. struct dm_region *reg;
  425. read_lock(&rh->hash_lock);
  426. reg = __rh_find(rh, region);
  427. spin_lock_irq(&rh->region_lock);
  428. atomic_inc(&reg->pending);
  429. if (reg->state == DM_RH_CLEAN) {
  430. reg->state = DM_RH_DIRTY;
  431. list_del_init(&reg->list); /* take off the clean list */
  432. spin_unlock_irq(&rh->region_lock);
  433. rh->log->type->mark_region(rh->log, reg->key);
  434. } else
  435. spin_unlock_irq(&rh->region_lock);
  436. read_unlock(&rh->hash_lock);
  437. }
  438. void dm_rh_inc_pending(struct dm_region_hash *rh, struct bio_list *bios)
  439. {
  440. struct bio *bio;
  441. for (bio = bios->head; bio; bio = bio->bi_next) {
  442. if (bio->bi_opf & REQ_PREFLUSH || bio_op(bio) == REQ_OP_DISCARD)
  443. continue;
  444. rh_inc(rh, dm_rh_bio_to_region(rh, bio));
  445. }
  446. }
  447. EXPORT_SYMBOL_GPL(dm_rh_inc_pending);
  448. void dm_rh_dec(struct dm_region_hash *rh, region_t region)
  449. {
  450. unsigned long flags;
  451. struct dm_region *reg;
  452. int should_wake = 0;
  453. read_lock(&rh->hash_lock);
  454. reg = __rh_lookup(rh, region);
  455. read_unlock(&rh->hash_lock);
  456. spin_lock_irqsave(&rh->region_lock, flags);
  457. if (atomic_dec_and_test(&reg->pending)) {
  458. /*
  459. * There is no pending I/O for this region.
  460. * We can move the region to corresponding list for next action.
  461. * At this point, the region is not yet connected to any list.
  462. *
  463. * If the state is DM_RH_NOSYNC, the region should be kept off
  464. * from clean list.
  465. * The hash entry for DM_RH_NOSYNC will remain in memory
  466. * until the region is recovered or the map is reloaded.
  467. */
  468. /* do nothing for DM_RH_NOSYNC */
  469. if (unlikely(rh->flush_failure)) {
  470. /*
  471. * If a write flush failed some time ago, we
  472. * don't know whether or not this write made it
  473. * to the disk, so we must resync the device.
  474. */
  475. reg->state = DM_RH_NOSYNC;
  476. } else if (reg->state == DM_RH_RECOVERING) {
  477. list_add_tail(&reg->list, &rh->quiesced_regions);
  478. } else if (reg->state == DM_RH_DIRTY) {
  479. reg->state = DM_RH_CLEAN;
  480. list_add(&reg->list, &rh->clean_regions);
  481. }
  482. should_wake = 1;
  483. }
  484. spin_unlock_irqrestore(&rh->region_lock, flags);
  485. if (should_wake)
  486. rh->wakeup_workers(rh->context);
  487. }
  488. EXPORT_SYMBOL_GPL(dm_rh_dec);
  489. /*
  490. * Starts quiescing a region in preparation for recovery.
  491. */
  492. static int __rh_recovery_prepare(struct dm_region_hash *rh)
  493. {
  494. int r;
  495. region_t region;
  496. struct dm_region *reg;
  497. /*
  498. * Ask the dirty log what's next.
  499. */
  500. r = rh->log->type->get_resync_work(rh->log, &region);
  501. if (r <= 0)
  502. return r;
  503. /*
  504. * Get this region, and start it quiescing by setting the
  505. * recovering flag.
  506. */
  507. read_lock(&rh->hash_lock);
  508. reg = __rh_find(rh, region);
  509. read_unlock(&rh->hash_lock);
  510. spin_lock_irq(&rh->region_lock);
  511. reg->state = DM_RH_RECOVERING;
  512. /* Already quiesced ? */
  513. if (atomic_read(&reg->pending))
  514. list_del_init(&reg->list);
  515. else
  516. list_move(&reg->list, &rh->quiesced_regions);
  517. spin_unlock_irq(&rh->region_lock);
  518. return 1;
  519. }
  520. void dm_rh_recovery_prepare(struct dm_region_hash *rh)
  521. {
  522. /* Extra reference to avoid race with dm_rh_stop_recovery */
  523. atomic_inc(&rh->recovery_in_flight);
  524. while (!down_trylock(&rh->recovery_count)) {
  525. atomic_inc(&rh->recovery_in_flight);
  526. if (__rh_recovery_prepare(rh) <= 0) {
  527. atomic_dec(&rh->recovery_in_flight);
  528. up(&rh->recovery_count);
  529. break;
  530. }
  531. }
  532. /* Drop the extra reference */
  533. if (atomic_dec_and_test(&rh->recovery_in_flight))
  534. rh->wakeup_all_recovery_waiters(rh->context);
  535. }
  536. EXPORT_SYMBOL_GPL(dm_rh_recovery_prepare);
  537. /*
  538. * Returns any quiesced regions.
  539. */
  540. struct dm_region *dm_rh_recovery_start(struct dm_region_hash *rh)
  541. {
  542. struct dm_region *reg = NULL;
  543. spin_lock_irq(&rh->region_lock);
  544. if (!list_empty(&rh->quiesced_regions)) {
  545. reg = list_entry(rh->quiesced_regions.next,
  546. struct dm_region, list);
  547. list_del_init(&reg->list); /* remove from the quiesced list */
  548. }
  549. spin_unlock_irq(&rh->region_lock);
  550. return reg;
  551. }
  552. EXPORT_SYMBOL_GPL(dm_rh_recovery_start);
  553. void dm_rh_recovery_end(struct dm_region *reg, int success)
  554. {
  555. struct dm_region_hash *rh = reg->rh;
  556. spin_lock_irq(&rh->region_lock);
  557. if (success)
  558. list_add(&reg->list, &reg->rh->recovered_regions);
  559. else
  560. list_add(&reg->list, &reg->rh->failed_recovered_regions);
  561. spin_unlock_irq(&rh->region_lock);
  562. rh->wakeup_workers(rh->context);
  563. }
  564. EXPORT_SYMBOL_GPL(dm_rh_recovery_end);
  565. /* Return recovery in flight count. */
  566. int dm_rh_recovery_in_flight(struct dm_region_hash *rh)
  567. {
  568. return atomic_read(&rh->recovery_in_flight);
  569. }
  570. EXPORT_SYMBOL_GPL(dm_rh_recovery_in_flight);
  571. int dm_rh_flush(struct dm_region_hash *rh)
  572. {
  573. return rh->log->type->flush(rh->log);
  574. }
  575. EXPORT_SYMBOL_GPL(dm_rh_flush);
  576. void dm_rh_delay(struct dm_region_hash *rh, struct bio *bio)
  577. {
  578. struct dm_region *reg;
  579. read_lock(&rh->hash_lock);
  580. reg = __rh_find(rh, dm_rh_bio_to_region(rh, bio));
  581. bio_list_add(&reg->delayed_bios, bio);
  582. read_unlock(&rh->hash_lock);
  583. }
  584. EXPORT_SYMBOL_GPL(dm_rh_delay);
  585. void dm_rh_stop_recovery(struct dm_region_hash *rh)
  586. {
  587. int i;
  588. /* wait for any recovering regions */
  589. for (i = 0; i < rh->max_recovery; i++)
  590. down(&rh->recovery_count);
  591. }
  592. EXPORT_SYMBOL_GPL(dm_rh_stop_recovery);
  593. void dm_rh_start_recovery(struct dm_region_hash *rh)
  594. {
  595. int i;
  596. for (i = 0; i < rh->max_recovery; i++)
  597. up(&rh->recovery_count);
  598. rh->wakeup_workers(rh->context);
  599. }
  600. EXPORT_SYMBOL_GPL(dm_rh_start_recovery);
  601. MODULE_DESCRIPTION(DM_NAME " region hash");
  602. MODULE_AUTHOR("Joe Thornber/Heinz Mauelshagen <dm-devel@lists.linux.dev>");
  603. MODULE_LICENSE("GPL");