1// SPDX-License-Identifier: GPL-2.0 2/* 3 * drivers/hyperhold/hp_space.c 4 * 5 * Copyright (c) 2020-2022 Huawei Technologies Co., Ltd. 6 */ 7 8#define pr_fmt(fmt) "[HYPERHOLD]" fmt 9 10#include <linux/mm.h> 11 12#include "hp_space.h" 13 14atomic64_t spc_mem = ATOMIC64_INIT(0); 15 16u64 space_memory(void) 17{ 18 return atomic64_read(&spc_mem); 19} 20 21void deinit_space(struct hp_space *spc) 22{ 23 kvfree(spc->bitmap); 24 atomic64_sub(BITS_TO_LONGS(spc->nr_ext) * sizeof(long), &spc_mem); 25 spc->ext_size = 0; 26 spc->nr_ext = 0; 27 atomic_set(&spc->last_alloc_bit, 0); 28 atomic_set(&spc->nr_alloced, 0); 29 30 pr_info("hyperhold space deinited.\n"); 31} 32 33bool init_space(struct hp_space *spc, u64 dev_size, u32 ext_size) 34{ 35 if (ext_size & (PAGE_SIZE - 1)) { 36 pr_err("extent size %u do not align to page size %lu!", ext_size, PAGE_SIZE); 37 return false; 38 } 39 if (dev_size & (ext_size - 1)) { 40 pr_err("device size %llu do not align to extent size %u!", dev_size, ext_size); 41 return false; 42 } 43 spc->ext_size = ext_size; 44 spc->nr_ext = div_u64(dev_size, ext_size); 45 atomic_set(&spc->last_alloc_bit, 0); 46 atomic_set(&spc->nr_alloced, 0); 47 init_waitqueue_head(&spc->empty_wq); 48 spc->bitmap = kvzalloc(BITS_TO_LONGS(spc->nr_ext) * sizeof(long), GFP_KERNEL); 49 if (!spc->bitmap) { 50 pr_err("hyperhold bitmap alloc failed.\n"); 51 return false; 52 } 53 atomic64_add(BITS_TO_LONGS(spc->nr_ext) * sizeof(long), &spc_mem); 54 55 pr_info("hyperhold space init succ, capacity = %u x %u.\n", ext_size, spc->nr_ext); 56 57 return true; 58} 59 60int alloc_eid(struct hp_space *spc) 61{ 62 u32 bit; 63 u32 last_bit; 64 65retry: 66 last_bit = atomic_read(&spc->last_alloc_bit); 67 bit = find_next_zero_bit(spc->bitmap, spc->nr_ext, last_bit); 68 if (bit == spc->nr_ext) 69 bit = find_next_zero_bit(spc->bitmap, spc->nr_ext, 0); 70 if (bit == spc->nr_ext) 71 goto full; 72 if (test_and_set_bit(bit, spc->bitmap)) 73 goto retry; 74 75 atomic_set(&spc->last_alloc_bit, bit); 76 atomic_inc(&spc->nr_alloced); 77 78 pr_info("hyperhold alloc extent %u.\n", bit); 79 80 return bit; 81full: 82 pr_err("hyperhold space is full.\n"); 83 84 return -ENOSPC; 85} 86 87void free_eid(struct hp_space *spc, u32 eid) 88{ 89 if (!test_and_clear_bit(eid, spc->bitmap)) { 90 pr_err("eid is not alloced!\n"); 91 BUG(); 92 return; 93 } 94 if (atomic_dec_and_test(&spc->nr_alloced)) { 95 pr_info("notify space empty.\n"); 96 wake_up(&spc->empty_wq); 97 } 98 pr_info("hyperhold free extent %u.\n", eid); 99} 100 101static void dump_space(struct hp_space *spc) 102{ 103 u32 i = 0; 104 105 pr_info("dump alloced extent in space.\n"); 106 for (i = 0; i < spc->nr_ext; i++) 107 if (test_bit(i, spc->bitmap)) 108 pr_info("alloced eid %u.\n", i); 109} 110 111bool wait_for_space_empty(struct hp_space *spc, bool force) 112{ 113 if (!atomic_read(&spc->nr_alloced)) 114 return true; 115 if (!force) 116 return false; 117 118 dump_space(spc); 119 wait_event(spc->empty_wq, !atomic_read(&spc->nr_alloced)); 120 121 return true; 122} 123