1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 #ifndef CEPH_MDS_FLOCK_H
4 #define CEPH_MDS_FLOCK_H
8 #include "common/debug.h"
12 inline ostream
& operator<<(ostream
& out
, const ceph_filelock
& l
) {
13 out
<< "start: " << l
.start
<< ", length: " << l
.length
14 << ", client: " << l
.client
<< ", owner: " << l
.owner
15 << ", pid: " << l
.pid
<< ", type: " << (int)l
.type
20 inline bool ceph_filelock_owner_equal(const ceph_filelock
& l
, const ceph_filelock
& r
)
22 if (l
.client
!= r
.client
|| l
.owner
!= r
.owner
)
24 // The file lock is from old client if the most significant bit of
25 // 'owner' is not set. Old clients use both 'owner' and 'pid' to
26 // identify the owner of lock.
27 if (l
.owner
& (1ULL << 63))
29 return l
.pid
== r
.pid
;
32 inline int ceph_filelock_owner_compare(const ceph_filelock
& l
, const ceph_filelock
& r
)
34 if (l
.client
!= r
.client
)
35 return l
.client
> r
.client
? 1 : -1;
36 if (l
.owner
!= r
.owner
)
37 return l
.owner
> r
.owner
? 1 : -1;
38 if (l
.owner
& (1ULL << 63))
41 return l
.pid
> r
.pid
? 1 : -1;
45 inline int ceph_filelock_compare(const ceph_filelock
& l
, const ceph_filelock
& r
)
47 int ret
= ceph_filelock_owner_compare(l
, r
);
50 if (l
.start
!= r
.start
)
51 return l
.start
> r
.start
? 1 : -1;
52 if (l
.length
!= r
.length
)
53 return l
.length
> r
.length
? 1 : -1;
55 return l
.type
> r
.type
? 1 : -1;
59 inline bool operator<(const ceph_filelock
& l
, const ceph_filelock
& r
)
61 return ceph_filelock_compare(l
, r
) < 0;
64 inline bool operator==(const ceph_filelock
& l
, const ceph_filelock
& r
) {
65 return ceph_filelock_compare(l
, r
) == 0;
68 inline bool operator!=(const ceph_filelock
& l
, const ceph_filelock
& r
) {
69 return ceph_filelock_compare(l
, r
) != 0;
72 class ceph_lock_state_t
{
76 explicit ceph_lock_state_t(CephContext
*cct_
, int type_
) : cct(cct_
), type(type_
) {}
78 multimap
<uint64_t, ceph_filelock
> held_locks
; // current locks
79 multimap
<uint64_t, ceph_filelock
> waiting_locks
; // locks waiting for other locks
80 // both of the above are keyed by starting offset
81 map
<client_t
, int> client_held_lock_counts
;
82 map
<client_t
, int> client_waiting_lock_counts
;
85 * Check if a lock is on the waiting_locks list.
87 * @param fl The filelock to check for
88 * @returns True if the lock is waiting, false otherwise
90 bool is_waiting(const ceph_filelock
&fl
) const;
92 * Remove a lock from the waiting_locks list
94 * @param fl The filelock to remove
96 void remove_waiting(const ceph_filelock
& fl
);
98 * Try to set a new lock. If it's blocked and wait_on_fail is true,
99 * add the lock to waiting_locks.
100 * The lock needs to be of type CEPH_LOCK_EXCL or CEPH_LOCK_SHARED.
101 * This may merge previous locks, or convert the type of already-owned
104 * @param new_lock The lock to set
105 * @param wait_on_fail whether to wait until the lock can be set.
106 * Otherwise it fails immediately when blocked.
108 * @returns true if set, false if not set.
110 bool add_lock(ceph_filelock
& new_lock
, bool wait_on_fail
, bool replay
,
113 * See if a lock is blocked by existing locks. If the lock is blocked,
114 * it will be set to the value of the first blocking lock. Otherwise,
115 * it will be returned unchanged, except for setting the type field
116 * to CEPH_LOCK_UNLOCK.
118 * @param testing_lock The lock to check for conflicts on.
120 void look_for_lock(ceph_filelock
& testing_lock
);
123 * Remove lock(s) described in old_lock. This may involve splitting a
124 * previous lock or making a previous lock smaller.
126 * @param removal_lock The lock to remove
127 * @param activated_locks A return parameter, holding activated wait locks.
129 void remove_lock(const ceph_filelock removal_lock
,
130 list
<ceph_filelock
>& activated_locks
);
132 bool remove_all_from(client_t client
);
134 static const unsigned MAX_DEADLK_DEPTH
= 5;
137 * Check if adding the lock causes deadlock
139 * @param fl The blocking filelock
140 * @param overlapping_locks list of all overlapping locks
142 * @depth recursion call depth
144 bool is_deadlock(const ceph_filelock
& fl
,
145 list
<multimap
<uint64_t, ceph_filelock
>::iterator
>&
147 const ceph_filelock
*first_fl
=NULL
, unsigned depth
=0) const;
150 * Add a lock to the waiting_locks list
152 * @param fl The filelock to add
154 void add_waiting(const ceph_filelock
& fl
);
157 * Adjust old locks owned by a single process so that process can set
158 * a new lock of different type. Handle any changes needed to the old locks
159 * (and the new lock) so that once the new lock is inserted into the
160 * held_locks list the process has a coherent, non-fragmented set of lock
161 * ranges. Make sure any overlapping locks are combined, trimmed, and removed
163 * This function should only be called once you know the lock will be
164 * inserted, as it DOES adjust new_lock. You can call this function
165 * on an empty list, in which case it does nothing.
166 * This function does not remove elements from old_locks, so regard the list
167 * as bad information following function invocation.
169 * @param new_lock The new lock the process has requested.
170 * @param old_locks list of all locks currently held by same
171 * client/process that overlap new_lock.
172 * @param neighbor_locks locks owned by same process that neighbor new_lock on
173 * left or right side.
175 void adjust_locks(list
<multimap
<uint64_t, ceph_filelock
>::iterator
> old_locks
,
176 ceph_filelock
& new_lock
,
177 list
<multimap
<uint64_t, ceph_filelock
>::iterator
>
180 //get last lock prior to start position
181 multimap
<uint64_t, ceph_filelock
>::iterator
182 get_lower_bound(uint64_t start
,
183 multimap
<uint64_t, ceph_filelock
>& lock_map
);
184 //get latest-starting lock that goes over the byte "end"
185 multimap
<uint64_t, ceph_filelock
>::iterator
186 get_last_before(uint64_t end
,
187 multimap
<uint64_t, ceph_filelock
>& lock_map
);
190 * See if an iterator's lock covers any of the same bounds as a given range
191 * Rules: locks cover "length" bytes from "start", so the last covered
192 * byte is at start + length - 1.
193 * If the length is 0, the lock covers from "start" to the end of the file.
195 bool share_space(multimap
<uint64_t, ceph_filelock
>::iterator
& iter
,
196 uint64_t start
, uint64_t end
);
198 bool share_space(multimap
<uint64_t, ceph_filelock
>::iterator
& iter
,
199 const ceph_filelock
&lock
) {
200 uint64_t end
= lock
.start
;
202 end
+= lock
.length
- 1;
203 } else { // zero length means end of file
206 return share_space(iter
, lock
.start
, end
);
209 *get a list of all locks overlapping with the given lock's range
210 * lock: the lock to compare with.
211 * overlaps: an empty list, to be filled.
212 * Returns: true if at least one lock overlaps.
214 bool get_overlapping_locks(const ceph_filelock
& lock
,
215 list
<multimap
<uint64_t,
216 ceph_filelock
>::iterator
> & overlaps
,
217 list
<multimap
<uint64_t,
218 ceph_filelock
>::iterator
> *self_neighbors
);
221 bool get_overlapping_locks(const ceph_filelock
& lock
,
222 list
<multimap
<uint64_t, ceph_filelock
>::iterator
>& overlaps
) {
223 return get_overlapping_locks(lock
, overlaps
, NULL
);
227 * Get a list of all waiting locks that overlap with the given lock's range.
228 * lock: specifies the range to compare with
229 * overlaps: an empty list, to be filled
230 * Returns: true if at least one waiting_lock overlaps
232 bool get_waiting_overlaps(const ceph_filelock
& lock
,
233 list
<multimap
<uint64_t,
234 ceph_filelock
>::iterator
>& overlaps
);
236 * split a list of locks up by whether they're owned by same
237 * process as given lock
238 * owner: the owning lock
239 * locks: the list of locks (obtained from get_overlapping_locks, probably)
240 * Will have all locks owned by owner removed
241 * owned_locks: an empty list, to be filled with the locks owned by owner
243 void split_by_owner(const ceph_filelock
& owner
,
244 list
<multimap
<uint64_t,
245 ceph_filelock
>::iterator
> & locks
,
246 list
<multimap
<uint64_t,
247 ceph_filelock
>::iterator
> & owned_locks
);
249 ceph_filelock
*contains_exclusive_lock(list
<multimap
<uint64_t,
250 ceph_filelock
>::iterator
>& locks
);
253 void encode(bufferlist
& bl
) const {
254 ::encode(held_locks
, bl
);
255 ::encode(waiting_locks
, bl
);
256 ::encode(client_held_lock_counts
, bl
);
257 ::encode(client_waiting_lock_counts
, bl
);
259 void decode(bufferlist::iterator
& bl
) {
260 ::decode(held_locks
, bl
);
261 ::decode(waiting_locks
, bl
);
262 ::decode(client_held_lock_counts
, bl
);
263 ::decode(client_waiting_lock_counts
, bl
);
267 waiting_locks
.clear();
268 client_held_lock_counts
.clear();
269 client_waiting_lock_counts
.clear();
272 return held_locks
.empty() && waiting_locks
.empty() &&
273 client_held_lock_counts
.empty() &&
274 client_waiting_lock_counts
.empty();
277 WRITE_CLASS_ENCODER(ceph_lock_state_t
)
280 inline ostream
& operator<<(ostream
&out
, const ceph_lock_state_t
&l
) {
281 out
<< "ceph_lock_state_t. held_locks.size()=" << l
.held_locks
.size()
282 << ", waiting_locks.size()=" << l
.waiting_locks
.size()
283 << ", client_held_lock_counts -- " << l
.client_held_lock_counts
284 << "\n client_waiting_lock_counts -- " << l
.client_waiting_lock_counts
285 << "\n held_locks -- ";
286 for (auto iter
= l
.held_locks
.begin();
287 iter
!= l
.held_locks
.end();
290 out
<< "\n waiting_locks -- ";
291 for (auto iter
=l
.waiting_locks
.begin();
292 iter
!= l
.waiting_locks
.end();
294 out
<< iter
->second
<< "\n";