1*0349ff28SPasha Tatashin // SPDX-License-Identifier: GPL-2.0 2*0349ff28SPasha Tatashin 3*0349ff28SPasha Tatashin /* 4*0349ff28SPasha Tatashin * Copyright (c) 2026, Google LLC. 5*0349ff28SPasha Tatashin * Pasha Tatashin <pasha.tatashin@soleen.com> 6*0349ff28SPasha Tatashin */ 7*0349ff28SPasha Tatashin 8*0349ff28SPasha Tatashin /** 9*0349ff28SPasha Tatashin * DOC: KHO Serialization Blocks 10*0349ff28SPasha Tatashin * 11*0349ff28SPasha Tatashin * KHO provides a mechanism to preserve stateful data across a kexec handover 12*0349ff28SPasha Tatashin * by serializing it into memory blocks, and provides the common 13*0349ff28SPasha Tatashin * infrastructure for managing these blocks. 14*0349ff28SPasha Tatashin * 15*0349ff28SPasha Tatashin * Each block consists of a header (struct kho_block_header_ser) followed by an 16*0349ff28SPasha Tatashin * array of serialized entries. Multiple blocks are linked together via a 17*0349ff28SPasha Tatashin * physical pointer in the header, forming a linked list that can be easily 18*0349ff28SPasha Tatashin * traversed in both the current and the next kernel. 19*0349ff28SPasha Tatashin */ 20*0349ff28SPasha Tatashin 21*0349ff28SPasha Tatashin #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 22*0349ff28SPasha Tatashin 23*0349ff28SPasha Tatashin #include <linux/io.h> 24*0349ff28SPasha Tatashin #include <linux/kexec_handover.h> 25*0349ff28SPasha Tatashin #include <linux/kho/abi/block.h> 26*0349ff28SPasha Tatashin #include <linux/kho_block.h> 27*0349ff28SPasha Tatashin #include <linux/slab.h> 28*0349ff28SPasha Tatashin 29*0349ff28SPasha Tatashin /* 30*0349ff28SPasha Tatashin * Safeguard limit for the number of serialization blocks. This is used to 31*0349ff28SPasha Tatashin * prevent infinite loops and excessive memory allocation in case of memory 32*0349ff28SPasha Tatashin * corruption in the preserved state. 33*0349ff28SPasha Tatashin * 34*0349ff28SPasha Tatashin * With a 4KB page size, 10k blocks is about 40MB. For 32-byte entries 35*0349ff28SPasha Tatashin * (e.g. 4 u64s), each block holds up to 127 entries (accounting for the 36*0349ff28SPasha Tatashin * 16-byte header), allowing the block set to hold up to 1.27M entries. 37*0349ff28SPasha Tatashin */ 38*0349ff28SPasha Tatashin #define KHO_MAX_BLOCKS 10000 39*0349ff28SPasha Tatashin 40*0349ff28SPasha Tatashin /** 41*0349ff28SPasha Tatashin * kho_block_set_init - Initialize a block set. 42*0349ff28SPasha Tatashin * @bs: The block set to initialize. 43*0349ff28SPasha Tatashin * @entry_size: The size of each entry in the blocks. 44*0349ff28SPasha Tatashin */ 45*0349ff28SPasha Tatashin void kho_block_set_init(struct kho_block_set *bs, size_t entry_size) 46*0349ff28SPasha Tatashin { 47*0349ff28SPasha Tatashin *bs = (struct kho_block_set)KHO_BLOCK_SET_INIT(*bs, entry_size); 48*0349ff28SPasha Tatashin WARN_ON_ONCE(!bs->count_per_block); 49*0349ff28SPasha Tatashin } 50*0349ff28SPasha Tatashin 51*0349ff28SPasha Tatashin /* Serialized entries start immediately after the block header */ 52*0349ff28SPasha Tatashin static void *kho_block_entries(struct kho_block *block) 53*0349ff28SPasha Tatashin { 54*0349ff28SPasha Tatashin return (void *)(block->ser + 1); 55*0349ff28SPasha Tatashin } 56*0349ff28SPasha Tatashin 57*0349ff28SPasha Tatashin /* Get the address of the serialized entry at the specified index */ 58*0349ff28SPasha Tatashin static void *kho_block_entry(struct kho_block_set_it *it, u64 index) 59*0349ff28SPasha Tatashin { 60*0349ff28SPasha Tatashin return kho_block_entries(it->block) + (index * it->bs->entry_size); 61*0349ff28SPasha Tatashin } 62*0349ff28SPasha Tatashin 63*0349ff28SPasha Tatashin /* Free serialized data */ 64*0349ff28SPasha Tatashin static void kho_block_free_ser(struct kho_block_set *bs, 65*0349ff28SPasha Tatashin struct kho_block_header_ser *ser) 66*0349ff28SPasha Tatashin { 67*0349ff28SPasha Tatashin if (bs->incoming) 68*0349ff28SPasha Tatashin kho_restore_free(ser); 69*0349ff28SPasha Tatashin else 70*0349ff28SPasha Tatashin kho_unpreserve_free(ser); 71*0349ff28SPasha Tatashin } 72*0349ff28SPasha Tatashin 73*0349ff28SPasha Tatashin static struct kho_block_header_ser *kho_block_alloc_ser(struct kho_block_set *bs) 74*0349ff28SPasha Tatashin { 75*0349ff28SPasha Tatashin WARN_ON_ONCE(bs->incoming); 76*0349ff28SPasha Tatashin return kho_alloc_preserve(KHO_BLOCK_SIZE); 77*0349ff28SPasha Tatashin } 78*0349ff28SPasha Tatashin 79*0349ff28SPasha Tatashin static int kho_block_add(struct kho_block_set *bs, 80*0349ff28SPasha Tatashin struct kho_block_header_ser *ser) 81*0349ff28SPasha Tatashin { 82*0349ff28SPasha Tatashin struct kho_block *block, *last; 83*0349ff28SPasha Tatashin 84*0349ff28SPasha Tatashin if (bs->nblocks >= KHO_MAX_BLOCKS) 85*0349ff28SPasha Tatashin return -ENOSPC; 86*0349ff28SPasha Tatashin 87*0349ff28SPasha Tatashin block = kzalloc_obj(*block); 88*0349ff28SPasha Tatashin if (!block) 89*0349ff28SPasha Tatashin return -ENOMEM; 90*0349ff28SPasha Tatashin 91*0349ff28SPasha Tatashin block->ser = ser; 92*0349ff28SPasha Tatashin last = list_last_entry_or_null(&bs->blocks, struct kho_block, list); 93*0349ff28SPasha Tatashin list_add_tail(&block->list, &bs->blocks); 94*0349ff28SPasha Tatashin bs->nblocks++; 95*0349ff28SPasha Tatashin 96*0349ff28SPasha Tatashin if (last) 97*0349ff28SPasha Tatashin last->ser->next = virt_to_phys(ser); 98*0349ff28SPasha Tatashin else 99*0349ff28SPasha Tatashin bs->head_pa = virt_to_phys(ser); 100*0349ff28SPasha Tatashin 101*0349ff28SPasha Tatashin return 0; 102*0349ff28SPasha Tatashin } 103*0349ff28SPasha Tatashin 104*0349ff28SPasha Tatashin static int kho_block_set_grow_one(struct kho_block_set *bs) 105*0349ff28SPasha Tatashin { 106*0349ff28SPasha Tatashin struct kho_block_header_ser *ser; 107*0349ff28SPasha Tatashin int err; 108*0349ff28SPasha Tatashin 109*0349ff28SPasha Tatashin ser = kho_block_alloc_ser(bs); 110*0349ff28SPasha Tatashin if (IS_ERR(ser)) 111*0349ff28SPasha Tatashin return PTR_ERR(ser); 112*0349ff28SPasha Tatashin 113*0349ff28SPasha Tatashin err = kho_block_add(bs, ser); 114*0349ff28SPasha Tatashin if (err) { 115*0349ff28SPasha Tatashin kho_block_free_ser(bs, ser); 116*0349ff28SPasha Tatashin return err; 117*0349ff28SPasha Tatashin } 118*0349ff28SPasha Tatashin 119*0349ff28SPasha Tatashin return 0; 120*0349ff28SPasha Tatashin } 121*0349ff28SPasha Tatashin 122*0349ff28SPasha Tatashin static void kho_block_set_shrink_one(struct kho_block_set *bs) 123*0349ff28SPasha Tatashin { 124*0349ff28SPasha Tatashin struct kho_block *last, *new_last; 125*0349ff28SPasha Tatashin 126*0349ff28SPasha Tatashin if (list_empty(&bs->blocks)) 127*0349ff28SPasha Tatashin return; 128*0349ff28SPasha Tatashin 129*0349ff28SPasha Tatashin last = list_last_entry(&bs->blocks, struct kho_block, list); 130*0349ff28SPasha Tatashin list_del(&last->list); 131*0349ff28SPasha Tatashin bs->nblocks--; 132*0349ff28SPasha Tatashin kho_block_free_ser(bs, last->ser); 133*0349ff28SPasha Tatashin kfree(last); 134*0349ff28SPasha Tatashin 135*0349ff28SPasha Tatashin new_last = list_last_entry_or_null(&bs->blocks, struct kho_block, list); 136*0349ff28SPasha Tatashin if (new_last) 137*0349ff28SPasha Tatashin new_last->ser->next = 0; 138*0349ff28SPasha Tatashin else 139*0349ff28SPasha Tatashin bs->head_pa = 0; 140*0349ff28SPasha Tatashin } 141*0349ff28SPasha Tatashin 142*0349ff28SPasha Tatashin /** 143*0349ff28SPasha Tatashin * kho_block_set_grow - Expand the block set to accommodate the target count. 144*0349ff28SPasha Tatashin * @bs: The block set. 145*0349ff28SPasha Tatashin * @count: The target number of valid entries to accommodate. 146*0349ff28SPasha Tatashin * 147*0349ff28SPasha Tatashin * Dynamically preallocates and links preserved memory blocks if the target 148*0349ff28SPasha Tatashin * entry count exceeds the current total capacity of the set, ensuring they 149*0349ff28SPasha Tatashin * are available during serialization/deserialization. 150*0349ff28SPasha Tatashin * 151*0349ff28SPasha Tatashin * Context: Caller must hold a lock protecting the block set. 152*0349ff28SPasha Tatashin * Return: 0 on success, or a negative errno on failure. 153*0349ff28SPasha Tatashin */ 154*0349ff28SPasha Tatashin int kho_block_set_grow(struct kho_block_set *bs, u64 count) 155*0349ff28SPasha Tatashin { 156*0349ff28SPasha Tatashin long orig_nblocks = bs->nblocks; 157*0349ff28SPasha Tatashin int err; 158*0349ff28SPasha Tatashin 159*0349ff28SPasha Tatashin if (WARN_ON_ONCE(bs->incoming)) 160*0349ff28SPasha Tatashin return -EINVAL; 161*0349ff28SPasha Tatashin 162*0349ff28SPasha Tatashin while (count > bs->nblocks * bs->count_per_block) { 163*0349ff28SPasha Tatashin err = kho_block_set_grow_one(bs); 164*0349ff28SPasha Tatashin if (err) 165*0349ff28SPasha Tatashin goto err_shrink; 166*0349ff28SPasha Tatashin } 167*0349ff28SPasha Tatashin 168*0349ff28SPasha Tatashin return 0; 169*0349ff28SPasha Tatashin 170*0349ff28SPasha Tatashin err_shrink: 171*0349ff28SPasha Tatashin while (bs->nblocks > orig_nblocks) 172*0349ff28SPasha Tatashin kho_block_set_shrink_one(bs); 173*0349ff28SPasha Tatashin return err; 174*0349ff28SPasha Tatashin } 175*0349ff28SPasha Tatashin 176*0349ff28SPasha Tatashin /** 177*0349ff28SPasha Tatashin * kho_block_set_shrink - Shrink the block set to accommodate the target count. 178*0349ff28SPasha Tatashin * @bs: The block set. 179*0349ff28SPasha Tatashin * @count: The target number of valid entries to accommodate. 180*0349ff28SPasha Tatashin * 181*0349ff28SPasha Tatashin * Releases and unallocates redundant preserved memory blocks. Checks if the 182*0349ff28SPasha Tatashin * last block in the set can be removed because the remaining entry count is 183*0349ff28SPasha Tatashin * fully accommodated by the preceding blocks. 184*0349ff28SPasha Tatashin * 185*0349ff28SPasha Tatashin * Note: It is the caller's responsibility to ensure that entries are removed 186*0349ff28SPasha Tatashin * in the reverse order of their insertion. Because shrinking destroys the last 187*0349ff28SPasha Tatashin * block in the set, removing entries in any other order would corrupt active 188*0349ff28SPasha Tatashin * data. 189*0349ff28SPasha Tatashin * 190*0349ff28SPasha Tatashin * Context: Caller must hold a lock protecting the block set. 191*0349ff28SPasha Tatashin */ 192*0349ff28SPasha Tatashin void kho_block_set_shrink(struct kho_block_set *bs, u64 count) 193*0349ff28SPasha Tatashin { 194*0349ff28SPasha Tatashin while (bs->nblocks > 0 && count <= (bs->nblocks - 1) * bs->count_per_block) 195*0349ff28SPasha Tatashin kho_block_set_shrink_one(bs); 196*0349ff28SPasha Tatashin } 197*0349ff28SPasha Tatashin 198*0349ff28SPasha Tatashin /* 199*0349ff28SPasha Tatashin * kho_block_set_is_cyclic - Check for cycles in a linked list of blocks. 200*0349ff28SPasha Tatashin * Uses Floyd's cycle-finding algorithm to ensure sanity of the incoming list. 201*0349ff28SPasha Tatashin * 202*0349ff28SPasha Tatashin * Return: true if a cycle or corruption is detected, false otherwise. 203*0349ff28SPasha Tatashin */ 204*0349ff28SPasha Tatashin static bool kho_block_set_is_cyclic(struct kho_block_set *bs) 205*0349ff28SPasha Tatashin { 206*0349ff28SPasha Tatashin struct kho_block_header_ser *fast; 207*0349ff28SPasha Tatashin struct kho_block_header_ser *slow; 208*0349ff28SPasha Tatashin int count = 0; 209*0349ff28SPasha Tatashin 210*0349ff28SPasha Tatashin fast = phys_to_virt(bs->head_pa); 211*0349ff28SPasha Tatashin slow = fast; 212*0349ff28SPasha Tatashin 213*0349ff28SPasha Tatashin while (fast) { 214*0349ff28SPasha Tatashin if (count++ >= KHO_MAX_BLOCKS) { 215*0349ff28SPasha Tatashin pr_err("Block set is corrupted\n"); 216*0349ff28SPasha Tatashin return true; 217*0349ff28SPasha Tatashin } 218*0349ff28SPasha Tatashin 219*0349ff28SPasha Tatashin if (!fast->next) 220*0349ff28SPasha Tatashin break; 221*0349ff28SPasha Tatashin 222*0349ff28SPasha Tatashin fast = phys_to_virt(fast->next); 223*0349ff28SPasha Tatashin if (!fast->next) 224*0349ff28SPasha Tatashin break; 225*0349ff28SPasha Tatashin 226*0349ff28SPasha Tatashin fast = phys_to_virt(fast->next); 227*0349ff28SPasha Tatashin slow = phys_to_virt(slow->next); 228*0349ff28SPasha Tatashin 229*0349ff28SPasha Tatashin if (slow == fast) { 230*0349ff28SPasha Tatashin pr_err("Block set is corrupted\n"); 231*0349ff28SPasha Tatashin return true; 232*0349ff28SPasha Tatashin } 233*0349ff28SPasha Tatashin } 234*0349ff28SPasha Tatashin 235*0349ff28SPasha Tatashin return false; 236*0349ff28SPasha Tatashin } 237*0349ff28SPasha Tatashin 238*0349ff28SPasha Tatashin /** 239*0349ff28SPasha Tatashin * kho_block_set_restore - Restore a block set from a physical address. 240*0349ff28SPasha Tatashin * @bs: The block set to restore. 241*0349ff28SPasha Tatashin * @head_pa: Physical address of the first block header. 242*0349ff28SPasha Tatashin * 243*0349ff28SPasha Tatashin * Restores a serialized block set from a given physical address. The caller is 244*0349ff28SPasha Tatashin * responsible for ensuring that the block set @bs has been allocated and 245*0349ff28SPasha Tatashin * initialized prior to calling this function. 246*0349ff28SPasha Tatashin * 247*0349ff28SPasha Tatashin * Return: 0 on success, or a negative errno on failure. 248*0349ff28SPasha Tatashin */ 249*0349ff28SPasha Tatashin int kho_block_set_restore(struct kho_block_set *bs, u64 head_pa) 250*0349ff28SPasha Tatashin { 251*0349ff28SPasha Tatashin struct kho_block_header_ser *ser; 252*0349ff28SPasha Tatashin u64 next_pa = head_pa; 253*0349ff28SPasha Tatashin int err; 254*0349ff28SPasha Tatashin 255*0349ff28SPasha Tatashin /* Restored block sets use size from the previous kernel */ 256*0349ff28SPasha Tatashin bs->incoming = true; 257*0349ff28SPasha Tatashin if (!head_pa) 258*0349ff28SPasha Tatashin return 0; 259*0349ff28SPasha Tatashin 260*0349ff28SPasha Tatashin bs->head_pa = head_pa; 261*0349ff28SPasha Tatashin if (kho_block_set_is_cyclic(bs)) { 262*0349ff28SPasha Tatashin bs->head_pa = 0; 263*0349ff28SPasha Tatashin return -EINVAL; 264*0349ff28SPasha Tatashin } 265*0349ff28SPasha Tatashin 266*0349ff28SPasha Tatashin while (next_pa) { 267*0349ff28SPasha Tatashin ser = phys_to_virt(next_pa); 268*0349ff28SPasha Tatashin if (!ser->count || ser->count > bs->count_per_block) { 269*0349ff28SPasha Tatashin pr_warn("Block contains invalid entry count: %llu\n", 270*0349ff28SPasha Tatashin ser->count); 271*0349ff28SPasha Tatashin err = -EINVAL; 272*0349ff28SPasha Tatashin goto err_destroy; 273*0349ff28SPasha Tatashin } 274*0349ff28SPasha Tatashin err = kho_block_add(bs, ser); 275*0349ff28SPasha Tatashin if (err) 276*0349ff28SPasha Tatashin goto err_destroy; 277*0349ff28SPasha Tatashin next_pa = ser->next; 278*0349ff28SPasha Tatashin } 279*0349ff28SPasha Tatashin 280*0349ff28SPasha Tatashin return 0; 281*0349ff28SPasha Tatashin 282*0349ff28SPasha Tatashin err_destroy: 283*0349ff28SPasha Tatashin kho_block_set_destroy(bs); 284*0349ff28SPasha Tatashin 285*0349ff28SPasha Tatashin /* Free the remaining un-restored blocks in the physical chain */ 286*0349ff28SPasha Tatashin while (next_pa) { 287*0349ff28SPasha Tatashin struct kho_block_header_ser *next_ser = phys_to_virt(next_pa); 288*0349ff28SPasha Tatashin 289*0349ff28SPasha Tatashin next_pa = next_ser->next; 290*0349ff28SPasha Tatashin kho_block_free_ser(bs, next_ser); 291*0349ff28SPasha Tatashin } 292*0349ff28SPasha Tatashin return err; 293*0349ff28SPasha Tatashin } 294*0349ff28SPasha Tatashin 295*0349ff28SPasha Tatashin /** 296*0349ff28SPasha Tatashin * kho_block_set_destroy - Destroy all blocks in a block set. 297*0349ff28SPasha Tatashin * @bs: The block set. 298*0349ff28SPasha Tatashin */ 299*0349ff28SPasha Tatashin void kho_block_set_destroy(struct kho_block_set *bs) 300*0349ff28SPasha Tatashin { 301*0349ff28SPasha Tatashin struct kho_block *block, *tmp; 302*0349ff28SPasha Tatashin 303*0349ff28SPasha Tatashin list_for_each_entry_safe(block, tmp, &bs->blocks, list) { 304*0349ff28SPasha Tatashin list_del(&block->list); 305*0349ff28SPasha Tatashin kho_block_free_ser(bs, block->ser); 306*0349ff28SPasha Tatashin kfree(block); 307*0349ff28SPasha Tatashin } 308*0349ff28SPasha Tatashin bs->nblocks = 0; 309*0349ff28SPasha Tatashin bs->head_pa = 0; 310*0349ff28SPasha Tatashin } 311*0349ff28SPasha Tatashin 312*0349ff28SPasha Tatashin /** 313*0349ff28SPasha Tatashin * kho_block_set_clear - Clear all serialized data in a block set. 314*0349ff28SPasha Tatashin * @bs: The block set to clear. 315*0349ff28SPasha Tatashin */ 316*0349ff28SPasha Tatashin void kho_block_set_clear(struct kho_block_set *bs) 317*0349ff28SPasha Tatashin { 318*0349ff28SPasha Tatashin struct kho_block *block; 319*0349ff28SPasha Tatashin 320*0349ff28SPasha Tatashin list_for_each_entry(block, &bs->blocks, list) { 321*0349ff28SPasha Tatashin block->ser->count = 0; 322*0349ff28SPasha Tatashin memset(block->ser + 1, 0, KHO_BLOCK_SIZE - sizeof(*block->ser)); 323*0349ff28SPasha Tatashin } 324*0349ff28SPasha Tatashin } 325*0349ff28SPasha Tatashin 326*0349ff28SPasha Tatashin /** 327*0349ff28SPasha Tatashin * kho_block_set_it_init - Initialize a block set iterator. 328*0349ff28SPasha Tatashin * @it: The iterator to initialize. 329*0349ff28SPasha Tatashin * @bs: The block set to iterate over. 330*0349ff28SPasha Tatashin */ 331*0349ff28SPasha Tatashin void kho_block_set_it_init(struct kho_block_set_it *it, struct kho_block_set *bs) 332*0349ff28SPasha Tatashin { 333*0349ff28SPasha Tatashin it->bs = bs; 334*0349ff28SPasha Tatashin it->block = list_first_entry_or_null(&bs->blocks, struct kho_block, list); 335*0349ff28SPasha Tatashin it->i = 0; 336*0349ff28SPasha Tatashin } 337*0349ff28SPasha Tatashin 338*0349ff28SPasha Tatashin /** 339*0349ff28SPasha Tatashin * kho_block_set_it_reserve_entry - Reserve and return the next available slot for writing. 340*0349ff28SPasha Tatashin * @it: The block iterator. 341*0349ff28SPasha Tatashin * 342*0349ff28SPasha Tatashin * Reserves a slot in the current block during state serialization to add a new 343*0349ff28SPasha Tatashin * entry, advancing the internal index. If the current block is full, it 344*0349ff28SPasha Tatashin * automatically moves to the next block in the set. 345*0349ff28SPasha Tatashin * 346*0349ff28SPasha Tatashin * Return: A pointer to the reserved entry slot, or NULL if the block set's 347*0349ff28SPasha Tatashin * capacity is fully exhausted. 348*0349ff28SPasha Tatashin */ 349*0349ff28SPasha Tatashin void *kho_block_set_it_reserve_entry(struct kho_block_set_it *it) 350*0349ff28SPasha Tatashin { 351*0349ff28SPasha Tatashin void *entry; 352*0349ff28SPasha Tatashin 353*0349ff28SPasha Tatashin if (!it->block) 354*0349ff28SPasha Tatashin return NULL; 355*0349ff28SPasha Tatashin 356*0349ff28SPasha Tatashin if (it->i == it->bs->count_per_block) { 357*0349ff28SPasha Tatashin if (list_is_last(&it->block->list, &it->bs->blocks)) 358*0349ff28SPasha Tatashin return NULL; 359*0349ff28SPasha Tatashin it->block = list_next_entry(it->block, list); 360*0349ff28SPasha Tatashin it->i = 0; 361*0349ff28SPasha Tatashin } 362*0349ff28SPasha Tatashin 363*0349ff28SPasha Tatashin entry = kho_block_entry(it, it->i++); 364*0349ff28SPasha Tatashin it->block->ser->count = it->i; 365*0349ff28SPasha Tatashin return entry; 366*0349ff28SPasha Tatashin } 367*0349ff28SPasha Tatashin 368*0349ff28SPasha Tatashin /** 369*0349ff28SPasha Tatashin * kho_block_set_it_read_entry - Read the next serialized entry from the block set. 370*0349ff28SPasha Tatashin * @it: The block iterator. 371*0349ff28SPasha Tatashin * 372*0349ff28SPasha Tatashin * Iterates through previously written entries during state deserialization, 373*0349ff28SPasha Tatashin * respecting the actual count stored in each block's header. 374*0349ff28SPasha Tatashin * 375*0349ff28SPasha Tatashin * Return: A pointer to the next serialized entry, or NULL if all serialized 376*0349ff28SPasha Tatashin * entries have been read. 377*0349ff28SPasha Tatashin */ 378*0349ff28SPasha Tatashin void *kho_block_set_it_read_entry(struct kho_block_set_it *it) 379*0349ff28SPasha Tatashin { 380*0349ff28SPasha Tatashin if (!it->block) 381*0349ff28SPasha Tatashin return NULL; 382*0349ff28SPasha Tatashin 383*0349ff28SPasha Tatashin if (it->i == it->block->ser->count) { 384*0349ff28SPasha Tatashin if (list_is_last(&it->block->list, &it->bs->blocks)) 385*0349ff28SPasha Tatashin return NULL; 386*0349ff28SPasha Tatashin it->block = list_next_entry(it->block, list); 387*0349ff28SPasha Tatashin it->i = 0; 388*0349ff28SPasha Tatashin } 389*0349ff28SPasha Tatashin 390*0349ff28SPasha Tatashin return kho_block_entry(it, it->i++); 391*0349ff28SPasha Tatashin } 392*0349ff28SPasha Tatashin 393*0349ff28SPasha Tatashin /** 394*0349ff28SPasha Tatashin * kho_block_set_it_prev - Return the previous entry slot in the block set. 395*0349ff28SPasha Tatashin * @it: The block iterator. 396*0349ff28SPasha Tatashin * 397*0349ff28SPasha Tatashin * If the current index is at the start of a block, it automatically moves to 398*0349ff28SPasha Tatashin * the end of the previous block. 399*0349ff28SPasha Tatashin * 400*0349ff28SPasha Tatashin * Return: A pointer to the previous entry slot, or NULL if at the very 401*0349ff28SPasha Tatashin * beginning of the block set. 402*0349ff28SPasha Tatashin */ 403*0349ff28SPasha Tatashin void *kho_block_set_it_prev(struct kho_block_set_it *it) 404*0349ff28SPasha Tatashin { 405*0349ff28SPasha Tatashin if (!it->block) 406*0349ff28SPasha Tatashin return NULL; 407*0349ff28SPasha Tatashin 408*0349ff28SPasha Tatashin if (it->i == 0) { 409*0349ff28SPasha Tatashin if (list_is_first(&it->block->list, &it->bs->blocks)) 410*0349ff28SPasha Tatashin return NULL; 411*0349ff28SPasha Tatashin it->block = list_prev_entry(it->block, list); 412*0349ff28SPasha Tatashin it->i = it->bs->count_per_block; 413*0349ff28SPasha Tatashin } 414*0349ff28SPasha Tatashin 415*0349ff28SPasha Tatashin return kho_block_entry(it, --it->i); 416*0349ff28SPasha Tatashin } 417