xref: /openbmc/qemu/include/block/graph-lock.h (revision 6d00c6f982562222adbd0613966285792125abe5)
1  /*
2   * Graph lock: rwlock to protect block layer graph manipulations (add/remove
3   * edges and nodes)
4   *
5   *  Copyright (c) 2022 Red Hat
6   *
7   * This library is free software; you can redistribute it and/or
8   * modify it under the terms of the GNU Lesser General Public
9   * License as published by the Free Software Foundation; either
10   * version 2.1 of the License, or (at your option) any later version.
11   *
12   * This library is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15   * Lesser General Public License for more details.
16   *
17   * You should have received a copy of the GNU Lesser General Public
18   * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19   */
20  #ifndef GRAPH_LOCK_H
21  #define GRAPH_LOCK_H
22  
23  #include "qemu/clang-tsa.h"
24  
25  /**
26   * Graph Lock API
27   * This API provides a rwlock used to protect block layer
28   * graph modifications like edge (BdrvChild) and node (BlockDriverState)
29   * addition and removal.
30   * Currently we have 1 writer only, the Main loop, and many
31   * readers, mostly coroutines running in other AioContext thus other threads.
32   *
33   * We distinguish between writer (main loop, under BQL) that modifies the
34   * graph, and readers (all other coroutines running in various AioContext),
35   * that go through the graph edges, reading
36   * BlockDriverState ->parents and->children.
37   *
38   * The writer (main loop)  has an "exclusive" access, so it first waits for
39   * current read to finish, and then prevents incoming ones from
40   * entering while it has the exclusive access.
41   *
42   * The readers (coroutines in multiple AioContext) are free to
43   * access the graph as long the writer is not modifying the graph.
44   * In case it is, they go in a CoQueue and sleep until the writer
45   * is done.
46   *
47   * If a coroutine changes AioContext, the counter in the original and new
48   * AioContext are left intact, since the writer does not care where is the
49   * reader, but only if there is one.
50   * As a result, some AioContexts might have a negative reader count, to
51   * balance the positive count of the AioContext that took the lock.
52   * This also means that when an AioContext is deleted it may have a nonzero
53   * reader count. In that case we transfer the count to a global shared counter
54   * so that the writer is always aware of all readers.
55   */
56  typedef struct BdrvGraphRWlock BdrvGraphRWlock;
57  
58  /* Dummy lock object to use for Thread Safety Analysis (TSA) */
59  typedef struct TSA_CAPABILITY("mutex") BdrvGraphLock {
60  } BdrvGraphLock;
61  
62  extern BdrvGraphLock graph_lock;
63  
64  /*
65   * clang doesn't check consistency in locking annotations between forward
66   * declarations and the function definition. Having the annotation on the
67   * definition, but not the declaration in a header file, may give the reader
68   * a false sense of security because the condition actually remains unchecked
69   * for callers in other source files.
70   *
71   * Therefore, as a convention, for public functions, GRAPH_RDLOCK and
72   * GRAPH_WRLOCK annotations should be present only in the header file.
73   */
74  #define GRAPH_WRLOCK TSA_REQUIRES(graph_lock)
75  #define GRAPH_RDLOCK TSA_REQUIRES_SHARED(graph_lock)
76  #define GRAPH_UNLOCKED TSA_EXCLUDES(graph_lock)
77  
78  /*
79   * TSA annotations are not part of function types, so checks are defeated when
80   * using a function pointer. As a workaround, annotate function pointers with
81   * this macro that will require that the lock is at least taken while reading
82   * the pointer. In most cases this is equivalent to actually protecting the
83   * function call.
84   */
85  #define GRAPH_RDLOCK_PTR TSA_GUARDED_BY(graph_lock)
86  #define GRAPH_WRLOCK_PTR TSA_GUARDED_BY(graph_lock)
87  #define GRAPH_UNLOCKED_PTR
88  
89  /*
90   * register_aiocontext:
91   * Add AioContext @ctx to the list of AioContext.
92   * This list is used to obtain the total number of readers
93   * currently running the graph.
94   */
95  void register_aiocontext(AioContext *ctx);
96  
97  /*
98   * unregister_aiocontext:
99   * Removes AioContext @ctx to the list of AioContext.
100   */
101  void unregister_aiocontext(AioContext *ctx);
102  
103  /*
104   * bdrv_graph_wrlock:
105   * Start an exclusive write operation to modify the graph. This means we are
106   * adding or removing an edge or a node in the block layer graph. Nobody else
107   * is allowed to access the graph.
108   *
109   * Must only be called from outside bdrv_graph_co_rdlock.
110   *
111   * The wrlock can only be taken from the main loop, with BQL held, as only the
112   * main loop is allowed to modify the graph.
113   */
114  void no_coroutine_fn TSA_ACQUIRE(graph_lock) TSA_NO_TSA
115  bdrv_graph_wrlock(void);
116  
117  /*
118   * bdrv_graph_wrunlock:
119   * Write finished, reset global has_writer to 0 and restart
120   * all readers that are waiting.
121   */
122  void no_coroutine_fn TSA_RELEASE(graph_lock) TSA_NO_TSA
123  bdrv_graph_wrunlock(void);
124  
125  /*
126   * bdrv_graph_co_rdlock:
127   * Read the bs graph. This usually means traversing all nodes in
128   * the graph, therefore it can't happen while another thread is
129   * modifying it.
130   * Increases the reader counter of the current aiocontext,
131   * and if has_writer is set, it means that the writer is modifying
132   * the graph, therefore wait in a coroutine queue.
133   * The writer will then wake this coroutine once it is done.
134   *
135   * This lock should be taken from Iothreads (IO_CODE() class of functions)
136   * because it signals the writer that there are some
137   * readers currently running, or waits until the current
138   * write is finished before continuing.
139   * Calling this function from the Main Loop with BQL held
140   * is not necessary, since the Main Loop itself is the only
141   * writer, thus won't be able to read and write at the same time.
142   * The only exception to that is when we can't take the lock in the
143   * function/coroutine itself, and need to delegate the caller (usually main
144   * loop) to take it and wait that the coroutine ends, so that
145   * we always signal that a reader is running.
146   */
147  void coroutine_fn TSA_ACQUIRE_SHARED(graph_lock) TSA_NO_TSA
148  bdrv_graph_co_rdlock(void);
149  
150  /*
151   * bdrv_graph_rdunlock:
152   * Read terminated, decrease the count of readers in the current aiocontext.
153   * If the writer is waiting for reads to finish (has_writer == 1), signal
154   * the writer that we are done via aio_wait_kick() to let it continue.
155   */
156  void coroutine_fn TSA_RELEASE_SHARED(graph_lock) TSA_NO_TSA
157  bdrv_graph_co_rdunlock(void);
158  
159  /*
160   * bdrv_graph_rd{un}lock_main_loop:
161   * Just a placeholder to mark where the graph rdlock should be taken
162   * in the main loop. It is just asserting that we are not
163   * in a coroutine and in GLOBAL_STATE_CODE.
164   */
165  void TSA_ACQUIRE_SHARED(graph_lock) TSA_NO_TSA
166  bdrv_graph_rdlock_main_loop(void);
167  
168  void TSA_RELEASE_SHARED(graph_lock) TSA_NO_TSA
169  bdrv_graph_rdunlock_main_loop(void);
170  
171  /*
172   * assert_bdrv_graph_readable:
173   * Make sure that the reader is either the main loop,
174   * or there is at least a reader helding the rdlock.
175   * In this way an incoming writer is aware of the read and waits.
176   */
177  void GRAPH_RDLOCK assert_bdrv_graph_readable(void);
178  
179  /*
180   * assert_bdrv_graph_writable:
181   * Make sure that the writer is the main loop and has set @has_writer,
182   * so that incoming readers will pause.
183   */
184  void GRAPH_WRLOCK assert_bdrv_graph_writable(void);
185  
186  /*
187   * Calling this function tells TSA that we know that the lock is effectively
188   * taken even though we cannot prove it (yet) with GRAPH_RDLOCK. This can be
189   * useful in intermediate stages of a conversion to using the GRAPH_RDLOCK
190   * macro.
191   */
TSA_ASSERT_SHARED(graph_lock)192  static inline void TSA_ASSERT_SHARED(graph_lock) TSA_NO_TSA
193  assume_graph_lock(void)
194  {
195  }
196  
197  typedef struct GraphLockable { } GraphLockable;
198  
199  /*
200   * In C, compound literals have the lifetime of an automatic variable.
201   * In C++ it would be different, but then C++ wouldn't need QemuLockable
202   * either...
203   */
204  #define GML_OBJ_() (&(GraphLockable) { })
205  
206  /*
207   * This is not marked as TSA_ACQUIRE_SHARED() because TSA doesn't understand the
208   * cleanup attribute and would therefore complain that the graph is never
209   * unlocked. TSA_ASSERT_SHARED() makes sure that the following calls know that
210   * we hold the lock while unlocking is left unchecked.
211   */
TSA_ACQUIRE_SHARED(graph_lock)212  static inline GraphLockable * TSA_ACQUIRE_SHARED(graph_lock) coroutine_fn
213  graph_lockable_auto_lock(GraphLockable *x)
214  {
215      bdrv_graph_co_rdlock();
216      return x;
217  }
218  
TSA_RELEASE_SHARED(graph_lock)219  static inline void TSA_RELEASE_SHARED(graph_lock) coroutine_fn
220  graph_lockable_auto_unlock(GraphLockable **x)
221  {
222      bdrv_graph_co_rdunlock();
223  }
224  
225  #define GRAPH_AUTO_UNLOCK __attribute__((cleanup(graph_lockable_auto_unlock)))
226  
227  /*
228   * @var is only used to break the loop after the first iteration.
229   * @unlock_var can't be unlocked and then set to NULL because TSA wants the lock
230   * to be held at the start of every iteration of the loop.
231   */
232  #define WITH_GRAPH_RDLOCK_GUARD_(var)                                         \
233      for (GraphLockable *unlock_var GRAPH_AUTO_UNLOCK =                        \
234              graph_lockable_auto_lock(GML_OBJ_()),                             \
235              *var = unlock_var;                                                \
236           var;                                                                 \
237           var = NULL)
238  
239  #define WITH_GRAPH_RDLOCK_GUARD() \
240      WITH_GRAPH_RDLOCK_GUARD_(glue(graph_lockable_auto, __COUNTER__))
241  
242  #define GRAPH_RDLOCK_GUARD(x)                                       \
243      GraphLockable * GRAPH_AUTO_UNLOCK                               \
244      glue(graph_lockable_auto, __COUNTER__) G_GNUC_UNUSED =          \
245              graph_lockable_auto_lock(GML_OBJ_())
246  
247  
248  typedef struct GraphLockableMainloop { } GraphLockableMainloop;
249  
250  /*
251   * In C, compound literals have the lifetime of an automatic variable.
252   * In C++ it would be different, but then C++ wouldn't need QemuLockable
253   * either...
254   */
255  #define GMLML_OBJ_() (&(GraphLockableMainloop) { })
256  
257  /*
258   * This is not marked as TSA_ACQUIRE_SHARED() because TSA doesn't understand the
259   * cleanup attribute and would therefore complain that the graph is never
260   * unlocked. TSA_ASSERT_SHARED() makes sure that the following calls know that
261   * we hold the lock while unlocking is left unchecked.
262   */
TSA_ASSERT_SHARED(graph_lock)263  static inline GraphLockableMainloop * TSA_ASSERT_SHARED(graph_lock) TSA_NO_TSA
264  graph_lockable_auto_lock_mainloop(GraphLockableMainloop *x)
265  {
266      bdrv_graph_rdlock_main_loop();
267      return x;
268  }
269  
270  static inline void TSA_NO_TSA
graph_lockable_auto_unlock_mainloop(GraphLockableMainloop * x)271  graph_lockable_auto_unlock_mainloop(GraphLockableMainloop *x)
272  {
273      bdrv_graph_rdunlock_main_loop();
274  }
275  
276  G_DEFINE_AUTOPTR_CLEANUP_FUNC(GraphLockableMainloop,
277                                graph_lockable_auto_unlock_mainloop)
278  
279  #define GRAPH_RDLOCK_GUARD_MAINLOOP(x)                              \
280      g_autoptr(GraphLockableMainloop)                                \
281      glue(graph_lockable_auto, __COUNTER__) G_GNUC_UNUSED =          \
282              graph_lockable_auto_lock_mainloop(GMLML_OBJ_())
283  
284  #endif /* GRAPH_LOCK_H */
285  
286