xref: /aosp_15_r20/external/ublksrv/qcow2/utils.cpp (revision 94c4a1e103eb1715230460aab379dff275992c20)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <cassert>
3 
4 #include "qcow2.h"
5 #include "ublksrv_tgt.h"
6 
IOWaiters()7 IOWaiters::IOWaiters(): io_waiters({})
8 {
9 }
10 
add_waiter(unsigned tag)11 void IOWaiters::add_waiter(unsigned tag) {
12 	__mapping_meta_add_waiter(tag, 0x3fffff);
13 }
14 
15 /* The caller is waiting on the specified entry update */
add_waiter_idx(unsigned tag,unsigned entry_idx)16 void IOWaiters::add_waiter_idx(unsigned tag, unsigned entry_idx) {
17 	__mapping_meta_add_waiter(tag, entry_idx);
18 }
19 
20 /*
21  * For wakeup other IOs waiting for this meta.
22  *
23  * qcow2_tgt_io_done() will wakeup for current IO, that isn't covered
24  * by here.
25  */
__mapping_meta_wakeup_all(const struct ublksrv_queue * q,unsigned my_tag,unsigned entry_idx,bool all)26 void IOWaiters::__mapping_meta_wakeup_all(const struct ublksrv_queue *q,
27 		unsigned my_tag, unsigned entry_idx, bool all) {
28 	std::unordered_set<unsigned> tags(move(io_waiters));
29 	std::unordered_set<unsigned>::const_iterator it = tags.cbegin();
30 
31 	ublk_dbg(UBLK_DBG_QCOW2_IO_WAITER, "%s: %d %p my tag %d enter\n",
32 			__func__, __LINE__, this, my_tag);
33 	while (it != tags.cend()) {
34 		unsigned t = *it;
35 		unsigned tag = t & (QCOW2_MAX_QUEUE_DEPTH - 1);
36 		unsigned idx = t >> QCOW2_TAG_BITS;
37 
38 		/* can't wakeup me */
39 		if (tag == my_tag) {
40 			it = tags.erase(it);
41 			continue;
42 		}
43 
44 		ublk_dbg(UBLK_DBG_QCOW2_IO_WAITER, "%s: %d my tag %d tag %d idx %x\n",
45 				__func__, __LINE__, my_tag, tag, idx);
46 		if (all || idx == entry_idx) {
47 			struct ublk_io_tgt *__io =
48 				ublk_get_io_tgt_data(q, tag);
49 
50 			it = tags.erase(it);
51 			__io->tgt_io_cqe = NULL;
52 
53 			try {
54 				((struct ublk_io_tgt *)__io)->co.resume();
55 			} catch (MetaIoException &meta_error) {
56 				io_waiters.merge(tags);
57 				throw MetaIoException();
58 			} catch (MetaUpdateException &meta_update_error) {
59 				io_waiters.merge(tags);
60 				throw MetaUpdateException();
61 			}
62 		} else {
63 			it++;
64 		}
65 		ublk_dbg(UBLK_DBG_QCOW2_IO_WAITER, "%s: %d %p my tag %d tag %d idx %x\n",
66 				__func__, __LINE__, this, my_tag, tag, idx);
67 	}
68 	io_waiters.merge(tags);
69 	ublk_dbg(UBLK_DBG_QCOW2_IO_WAITER, "%s: %d %p my tag %d exit\n",
70 			__func__, __LINE__, this, my_tag);
71 }
72 
wakeup_all(const struct ublksrv_queue * q,unsigned my_tag)73 void IOWaiters::wakeup_all(const struct ublksrv_queue *q, unsigned my_tag) {
74 	__mapping_meta_wakeup_all(q, my_tag, 0x3fffff, true);
75 }
76 
wakeup_all_idx(const struct ublksrv_queue * q,unsigned my_tag,unsigned entry_idx)77 void IOWaiters::wakeup_all_idx(const struct ublksrv_queue *q, unsigned my_tag,
78 		unsigned entry_idx) {
79 	__mapping_meta_wakeup_all(q, my_tag, entry_idx, false);
80 }
81