xref: /linux/drivers/md/dm-vdo/physical-zone.h (revision da5b2ad1c2f18834cb1ce429e2e5a5cf5cbdf21b)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Copyright 2023 Red Hat
4  */
5 
6 #ifndef VDO_PHYSICAL_ZONE_H
7 #define VDO_PHYSICAL_ZONE_H
8 
9 #include <linux/atomic.h>
10 
11 #include "types.h"
12 
13 /*
14  * The type of a PBN lock.
15  */
16 enum pbn_lock_type {
17 	VIO_READ_LOCK,
18 	VIO_WRITE_LOCK,
19 	VIO_BLOCK_MAP_WRITE_LOCK,
20 };
21 
22 struct pbn_lock_implementation;
23 
24 /*
25  * A PBN lock.
26  */
27 struct pbn_lock {
28 	/* The implementation of the lock */
29 	const struct pbn_lock_implementation *implementation;
30 
31 	/* The number of VIOs holding or sharing this lock */
32 	data_vio_count_t holder_count;
33 	/*
34 	 * The number of compressed block writers holding a share of this lock while they are
35 	 * acquiring a reference to the PBN.
36 	 */
37 	u8 fragment_locks;
38 
39 	/* Whether the locked PBN has been provisionally referenced on behalf of the lock holder. */
40 	bool has_provisional_reference;
41 
42 	/*
43 	 * For read locks, the number of references that were known to be available on the locked
44 	 * block at the time the lock was acquired.
45 	 */
46 	u8 increment_limit;
47 
48 	/*
49 	 * For read locks, the number of data_vios that have tried to claim one of the available
50 	 * increments during the lifetime of the lock. Each claim will first increment this
51 	 * counter, so it can exceed the increment limit.
52 	 */
53 	atomic_t increments_claimed;
54 };
55 
56 struct physical_zone {
57 	/* Which physical zone this is */
58 	zone_count_t zone_number;
59 	/* The thread ID for this zone */
60 	thread_id_t thread_id;
61 	/* In progress operations keyed by PBN */
62 	struct int_map *pbn_operations;
63 	/* Pool of unused pbn_lock instances */
64 	struct pbn_lock_pool *lock_pool;
65 	/* The block allocator for this zone */
66 	struct block_allocator *allocator;
67 	/* The next zone from which to attempt an allocation */
68 	struct physical_zone *next;
69 };
70 
71 struct physical_zones {
72 	/* The number of zones */
73 	zone_count_t zone_count;
74 	/* The physical zones themselves */
75 	struct physical_zone zones[];
76 };
77 
78 bool __must_check vdo_is_pbn_read_lock(const struct pbn_lock *lock);
79 void vdo_downgrade_pbn_write_lock(struct pbn_lock *lock, bool compressed_write);
80 bool __must_check vdo_claim_pbn_lock_increment(struct pbn_lock *lock);
81 
82 /**
83  * vdo_pbn_lock_has_provisional_reference() - Check whether a PBN lock has a provisional reference.
84  * @lock: The PBN lock.
85  */
86 static inline bool vdo_pbn_lock_has_provisional_reference(struct pbn_lock *lock)
87 {
88 	return ((lock != NULL) && lock->has_provisional_reference);
89 }
90 
91 void vdo_assign_pbn_lock_provisional_reference(struct pbn_lock *lock);
92 void vdo_unassign_pbn_lock_provisional_reference(struct pbn_lock *lock);
93 
94 int __must_check vdo_make_physical_zones(struct vdo *vdo,
95 					 struct physical_zones **zones_ptr);
96 
97 void vdo_free_physical_zones(struct physical_zones *zones);
98 
99 struct pbn_lock * __must_check vdo_get_physical_zone_pbn_lock(struct physical_zone *zone,
100 							      physical_block_number_t pbn);
101 
102 int __must_check vdo_attempt_physical_zone_pbn_lock(struct physical_zone *zone,
103 						    physical_block_number_t pbn,
104 						    enum pbn_lock_type type,
105 						    struct pbn_lock **lock_ptr);
106 
107 bool __must_check vdo_allocate_block_in_zone(struct data_vio *data_vio);
108 
109 void vdo_release_physical_zone_pbn_lock(struct physical_zone *zone,
110 					physical_block_number_t locked_pbn,
111 					struct pbn_lock *lock);
112 
113 void vdo_dump_physical_zone(const struct physical_zone *zone);
114 
115 #endif /* VDO_PHYSICAL_ZONE_H */
116