• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
14 atomic64_t spc_mem = ATOMIC64_INIT(0);
15 
space_memory(void)16 u64 space_memory(void)
17 {
18 	return atomic64_read(&spc_mem);
19 }
20 
deinit_space(struct hp_space * spc)21 void 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 
init_space(struct hp_space * spc,u64 dev_size,u32 ext_size)33 bool 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 
alloc_eid(struct hp_space * spc)60 int alloc_eid(struct hp_space *spc)
61 {
62 	u32 bit;
63 	u32 last_bit;
64 
65 retry:
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;
81 full:
82 	pr_err("hyperhold space is full.\n");
83 
84 	return -ENOSPC;
85 }
86 
free_eid(struct hp_space * spc,u32 eid)87 void 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 
dump_space(struct hp_space * spc)101 static 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 
wait_for_space_empty(struct hp_space * spc,bool force)111 bool 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