logical-zone.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright 2023 Red Hat
  4. */
  5. #include "logical-zone.h"
  6. #include "logger.h"
  7. #include "memory-alloc.h"
  8. #include "permassert.h"
  9. #include "string-utils.h"
  10. #include "action-manager.h"
  11. #include "admin-state.h"
  12. #include "block-map.h"
  13. #include "completion.h"
  14. #include "constants.h"
  15. #include "data-vio.h"
  16. #include "flush.h"
  17. #include "int-map.h"
  18. #include "physical-zone.h"
  19. #include "vdo.h"
  20. #define ALLOCATIONS_PER_ZONE 128
  21. /**
  22. * as_logical_zone() - Convert a generic vdo_completion to a logical_zone.
  23. * @completion: The completion to convert.
  24. *
  25. * Return: The completion as a logical_zone.
  26. */
  27. static struct logical_zone *as_logical_zone(struct vdo_completion *completion)
  28. {
  29. vdo_assert_completion_type(completion, VDO_GENERATION_FLUSHED_COMPLETION);
  30. return container_of(completion, struct logical_zone, completion);
  31. }
  32. /* get_thread_id_for_zone() - Implements vdo_zone_thread_getter_fn. */
  33. static thread_id_t get_thread_id_for_zone(void *context, zone_count_t zone_number)
  34. {
  35. struct logical_zones *zones = context;
  36. return zones->zones[zone_number].thread_id;
  37. }
  38. /**
  39. * initialize_zone() - Initialize a logical zone.
  40. * @zones: The logical_zones to which this zone belongs.
  41. * @zone_number: The logical_zone's index.
  42. */
  43. static int initialize_zone(struct logical_zones *zones, zone_count_t zone_number)
  44. {
  45. int result;
  46. struct vdo *vdo = zones->vdo;
  47. struct logical_zone *zone = &zones->zones[zone_number];
  48. zone_count_t allocation_zone_number;
  49. result = vdo_int_map_create(VDO_LOCK_MAP_CAPACITY, &zone->lbn_operations);
  50. if (result != VDO_SUCCESS)
  51. return result;
  52. if (zone_number < vdo->thread_config.logical_zone_count - 1)
  53. zone->next = &zones->zones[zone_number + 1];
  54. vdo_initialize_completion(&zone->completion, vdo,
  55. VDO_GENERATION_FLUSHED_COMPLETION);
  56. zone->zones = zones;
  57. zone->zone_number = zone_number;
  58. zone->thread_id = vdo->thread_config.logical_threads[zone_number];
  59. zone->block_map_zone = &vdo->block_map->zones[zone_number];
  60. INIT_LIST_HEAD(&zone->write_vios);
  61. vdo_set_admin_state_code(&zone->state, VDO_ADMIN_STATE_NORMAL_OPERATION);
  62. allocation_zone_number = zone->thread_id % vdo->thread_config.physical_zone_count;
  63. zone->allocation_zone = &vdo->physical_zones->zones[allocation_zone_number];
  64. return vdo_make_default_thread(vdo, zone->thread_id);
  65. }
  66. /**
  67. * vdo_make_logical_zones() - Create a set of logical zones.
  68. * @vdo: The vdo to which the zones will belong.
  69. * @zones_ptr: A pointer to hold the new zones.
  70. *
  71. * Return: VDO_SUCCESS or an error code.
  72. */
  73. int vdo_make_logical_zones(struct vdo *vdo, struct logical_zones **zones_ptr)
  74. {
  75. struct logical_zones *zones;
  76. int result;
  77. zone_count_t zone;
  78. zone_count_t zone_count = vdo->thread_config.logical_zone_count;
  79. if (zone_count == 0)
  80. return VDO_SUCCESS;
  81. result = vdo_allocate_extended(struct logical_zones, zone_count,
  82. struct logical_zone, __func__, &zones);
  83. if (result != VDO_SUCCESS)
  84. return result;
  85. zones->vdo = vdo;
  86. zones->zone_count = zone_count;
  87. for (zone = 0; zone < zone_count; zone++) {
  88. result = initialize_zone(zones, zone);
  89. if (result != VDO_SUCCESS) {
  90. vdo_free_logical_zones(zones);
  91. return result;
  92. }
  93. }
  94. result = vdo_make_action_manager(zones->zone_count, get_thread_id_for_zone,
  95. vdo->thread_config.admin_thread, zones, NULL,
  96. vdo, &zones->manager);
  97. if (result != VDO_SUCCESS) {
  98. vdo_free_logical_zones(zones);
  99. return result;
  100. }
  101. *zones_ptr = zones;
  102. return VDO_SUCCESS;
  103. }
  104. /**
  105. * vdo_free_logical_zones() - Free a set of logical zones.
  106. * @zones: The set of zones to free.
  107. */
  108. void vdo_free_logical_zones(struct logical_zones *zones)
  109. {
  110. zone_count_t index;
  111. if (zones == NULL)
  112. return;
  113. vdo_free(vdo_forget(zones->manager));
  114. for (index = 0; index < zones->zone_count; index++)
  115. vdo_int_map_free(vdo_forget(zones->zones[index].lbn_operations));
  116. vdo_free(zones);
  117. }
  118. static inline void assert_on_zone_thread(struct logical_zone *zone, const char *what)
  119. {
  120. VDO_ASSERT_LOG_ONLY((vdo_get_callback_thread_id() == zone->thread_id),
  121. "%s() called on correct thread", what);
  122. }
  123. /**
  124. * check_for_drain_complete() - Check whether this zone has drained.
  125. * @zone: The zone to check.
  126. */
  127. static void check_for_drain_complete(struct logical_zone *zone)
  128. {
  129. if (!vdo_is_state_draining(&zone->state) || zone->notifying ||
  130. !list_empty(&zone->write_vios))
  131. return;
  132. vdo_finish_draining(&zone->state);
  133. }
  134. /**
  135. * initiate_drain() - Initiate a drain.
  136. *
  137. * Implements vdo_admin_initiator_fn.
  138. */
  139. static void initiate_drain(struct admin_state *state)
  140. {
  141. check_for_drain_complete(container_of(state, struct logical_zone, state));
  142. }
  143. /**
  144. * drain_logical_zone() - Drain a logical zone.
  145. *
  146. * Implements vdo_zone_action_fn.
  147. */
  148. static void drain_logical_zone(void *context, zone_count_t zone_number,
  149. struct vdo_completion *parent)
  150. {
  151. struct logical_zones *zones = context;
  152. vdo_start_draining(&zones->zones[zone_number].state,
  153. vdo_get_current_manager_operation(zones->manager), parent,
  154. initiate_drain);
  155. }
  156. void vdo_drain_logical_zones(struct logical_zones *zones,
  157. const struct admin_state_code *operation,
  158. struct vdo_completion *parent)
  159. {
  160. vdo_schedule_operation(zones->manager, operation, NULL, drain_logical_zone, NULL,
  161. parent);
  162. }
  163. /**
  164. * resume_logical_zone() - Resume a logical zone.
  165. *
  166. * Implements vdo_zone_action_fn.
  167. */
  168. static void resume_logical_zone(void *context, zone_count_t zone_number,
  169. struct vdo_completion *parent)
  170. {
  171. struct logical_zone *zone = &(((struct logical_zones *) context)->zones[zone_number]);
  172. vdo_fail_completion(parent, vdo_resume_if_quiescent(&zone->state));
  173. }
  174. /**
  175. * vdo_resume_logical_zones() - Resume a set of logical zones.
  176. * @zones: The logical zones to resume.
  177. * @parent: The object to notify when the zones have resumed.
  178. */
  179. void vdo_resume_logical_zones(struct logical_zones *zones, struct vdo_completion *parent)
  180. {
  181. vdo_schedule_operation(zones->manager, VDO_ADMIN_STATE_RESUMING, NULL,
  182. resume_logical_zone, NULL, parent);
  183. }
  184. /**
  185. * update_oldest_active_generation() - Update the oldest active generation.
  186. * @zone: The zone.
  187. *
  188. * Return: true if the oldest active generation has changed.
  189. */
  190. static bool update_oldest_active_generation(struct logical_zone *zone)
  191. {
  192. struct data_vio *data_vio =
  193. list_first_entry_or_null(&zone->write_vios, struct data_vio,
  194. write_entry);
  195. sequence_number_t oldest =
  196. (data_vio == NULL) ? zone->flush_generation : data_vio->flush_generation;
  197. if (oldest == zone->oldest_active_generation)
  198. return false;
  199. WRITE_ONCE(zone->oldest_active_generation, oldest);
  200. return true;
  201. }
  202. /**
  203. * vdo_increment_logical_zone_flush_generation() - Increment the flush generation in a logical
  204. * zone.
  205. * @zone: The logical zone.
  206. * @expected_generation: The expected value of the flush generation before the increment.
  207. */
  208. void vdo_increment_logical_zone_flush_generation(struct logical_zone *zone,
  209. sequence_number_t expected_generation)
  210. {
  211. assert_on_zone_thread(zone, __func__);
  212. VDO_ASSERT_LOG_ONLY((zone->flush_generation == expected_generation),
  213. "logical zone %u flush generation %llu should be %llu before increment",
  214. zone->zone_number, (unsigned long long) zone->flush_generation,
  215. (unsigned long long) expected_generation);
  216. zone->flush_generation++;
  217. zone->ios_in_flush_generation = 0;
  218. update_oldest_active_generation(zone);
  219. }
  220. /**
  221. * vdo_acquire_flush_generation_lock() - Acquire the shared lock on a flush generation by a write
  222. * data_vio.
  223. * @data_vio: The data_vio.
  224. */
  225. void vdo_acquire_flush_generation_lock(struct data_vio *data_vio)
  226. {
  227. struct logical_zone *zone = data_vio->logical.zone;
  228. assert_on_zone_thread(zone, __func__);
  229. VDO_ASSERT_LOG_ONLY(vdo_is_state_normal(&zone->state), "vdo state is normal");
  230. data_vio->flush_generation = zone->flush_generation;
  231. list_add_tail(&data_vio->write_entry, &zone->write_vios);
  232. zone->ios_in_flush_generation++;
  233. }
  234. static void attempt_generation_complete_notification(struct vdo_completion *completion);
  235. /**
  236. * notify_flusher() - Notify the flush that at least one generation no longer has active VIOs.
  237. * @completion: The zone completion.
  238. *
  239. * This callback is registered in attempt_generation_complete_notification().
  240. */
  241. static void notify_flusher(struct vdo_completion *completion)
  242. {
  243. struct logical_zone *zone = as_logical_zone(completion);
  244. vdo_complete_flushes(zone->zones->vdo->flusher);
  245. vdo_launch_completion_callback(completion,
  246. attempt_generation_complete_notification,
  247. zone->thread_id);
  248. }
  249. /**
  250. * attempt_generation_complete_notification() - Notify the flusher if some generation no
  251. * longer has active VIOs.
  252. * @completion: The zone completion.
  253. */
  254. static void attempt_generation_complete_notification(struct vdo_completion *completion)
  255. {
  256. struct logical_zone *zone = as_logical_zone(completion);
  257. assert_on_zone_thread(zone, __func__);
  258. if (zone->oldest_active_generation <= zone->notification_generation) {
  259. zone->notifying = false;
  260. check_for_drain_complete(zone);
  261. return;
  262. }
  263. zone->notifying = true;
  264. zone->notification_generation = zone->oldest_active_generation;
  265. vdo_launch_completion_callback(&zone->completion, notify_flusher,
  266. vdo_get_flusher_thread_id(zone->zones->vdo->flusher));
  267. }
  268. /**
  269. * vdo_release_flush_generation_lock() - Release the shared lock on a flush generation held by a
  270. * write data_vio.
  271. * @data_vio: The data_vio whose lock is to be released.
  272. *
  273. * If there are pending flushes, and this data_vio completes the oldest generation active in this
  274. * zone, an attempt will be made to finish any flushes which may now be complete.
  275. */
  276. void vdo_release_flush_generation_lock(struct data_vio *data_vio)
  277. {
  278. struct logical_zone *zone = data_vio->logical.zone;
  279. assert_on_zone_thread(zone, __func__);
  280. if (!data_vio_has_flush_generation_lock(data_vio))
  281. return;
  282. list_del_init(&data_vio->write_entry);
  283. VDO_ASSERT_LOG_ONLY((zone->oldest_active_generation <= data_vio->flush_generation),
  284. "data_vio releasing lock on generation %llu is not older than oldest active generation %llu",
  285. (unsigned long long) data_vio->flush_generation,
  286. (unsigned long long) zone->oldest_active_generation);
  287. if (!update_oldest_active_generation(zone) || zone->notifying)
  288. return;
  289. attempt_generation_complete_notification(&zone->completion);
  290. }
  291. struct physical_zone *vdo_get_next_allocation_zone(struct logical_zone *zone)
  292. {
  293. if (zone->allocation_count == ALLOCATIONS_PER_ZONE) {
  294. zone->allocation_count = 0;
  295. zone->allocation_zone = zone->allocation_zone->next;
  296. }
  297. zone->allocation_count++;
  298. return zone->allocation_zone;
  299. }
  300. /**
  301. * vdo_dump_logical_zone() - Dump information about a logical zone to the log for debugging.
  302. * @zone: The zone to dump
  303. *
  304. * Context: the information is dumped in a thread-unsafe fashion.
  305. *
  306. */
  307. void vdo_dump_logical_zone(const struct logical_zone *zone)
  308. {
  309. vdo_log_info("logical_zone %u", zone->zone_number);
  310. vdo_log_info(" flush_generation=%llu oldest_active_generation=%llu notification_generation=%llu notifying=%s ios_in_flush_generation=%llu",
  311. (unsigned long long) READ_ONCE(zone->flush_generation),
  312. (unsigned long long) READ_ONCE(zone->oldest_active_generation),
  313. (unsigned long long) READ_ONCE(zone->notification_generation),
  314. vdo_bool_to_string(READ_ONCE(zone->notifying)),
  315. (unsigned long long) READ_ONCE(zone->ios_in_flush_generation));
  316. }