[PATCH v2 16/26] drbd: Make the lock context annotations compatible with Clang

Bart Van Assche
2026-03-25T21:46:43Z

Clang performs more strict checking of lock context annotations than
sparse. This patch makes the DRBD lock context annotations compatible
with Clang and enables lock context analysis in the Makefile.

Reviewed-by: Christoph Böhmwalder <christoph.boehmwalder@linbit.com>
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
drivers/block/drbd/Makefile | 3 +
drivers/block/drbd/drbd_bitmap.c | 26 ++++++---
drivers/block/drbd/drbd_int.h | 88 ++++++++++++++++++------------
drivers/block/drbd/drbd_main.c | 40 ++++++++++----
drivers/block/drbd/drbd_nl.c | 5 +-
drivers/block/drbd/drbd_receiver.c | 31 ++++++++---
drivers/block/drbd/drbd_req.c | 3 +
drivers/block/drbd/drbd_state.c | 2 +
drivers/block/drbd/drbd_state.h | 4 --
drivers/block/drbd/drbd_worker.c | 6 +-
10 files changed, 138 insertions(+), 70 deletions(-)

diff --git a/drivers/block/drbd/Makefile b/drivers/block/drbd/Makefile
index 67a8b352a1d5..8eaa83a7592b 100644
--- a/drivers/block/drbd/Makefile
+++ b/drivers/block/drbd/Makefile
@@ -1,4 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
+
+CONTEXT_ANALYSIS := y
+
drbd-y := drbd_buildtag.o drbd_bitmap.o drbd_proc.o
drbd-y += drbd_worker.o drbd_receiver.o drbd_req.o drbd_actlog.o
drbd-y += drbd_main.o drbd_strings.o drbd_nl.o
diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c
index 65ea6ec66bfd..3c521f0dc9ad 100644
--- a/drivers/block/drbd/drbd_bitmap.c
+++ b/drivers/block/drbd/drbd_bitmap.c
@@ -122,12 +122,16 @@ static void __bm_print_lock_info(struct drbd_device *device, const char *func)
}

void drbd_bm_lock(struct drbd_device *device, char *why, enum bm_flag flags)
+ __acquires(&device->bitmap->bm_change)
{
struct drbd_bitmap *b = device->bitmap;
int trylock_failed;

if (!b) {
drbd_err(device, "FIXME no bitmap in drbd_bm_lock!?\n");
+ /* Fake __acquire() to keep the compiler happy. */
+ __acquire(&b->bm_change);
+ __acquire(drbd_bitmap_lock);
return;
}

@@ -146,13 +150,18 @@ void drbd_bm_lock(struct drbd_device *device, char *why, enum bm_flag flags)

b->bm_why = why;
b->bm_task = current;
+ __acquire(drbd_bitmap_lock);
}

void drbd_bm_unlock(struct drbd_device *device)
+ __releases(&device->bitmap->bm_change)
{
struct drbd_bitmap *b = device->bitmap;
if (!b) {
drbd_err(device, "FIXME no bitmap in drbd_bm_unlock!?\n");
+ /* Fake __release() to keep the compiler happy. */
+ __release(&b->bm_change);
+ __release(drbd_bitmap_lock);
return;
}

@@ -163,6 +172,7 @@ void drbd_bm_unlock(struct drbd_device *device)
b->bm_why = NULL;
b->bm_task = NULL;
mutex_unlock(&b->bm_change);
+ __release(drbd_bitmap_lock);
}

/* we store some "meta" info about our pages in page->private */
@@ -987,7 +997,7 @@ static inline sector_t drbd_md_last_bitmap_sector(struct drbd_backing_dev *bdev)
}
}

-static void bm_page_io_async(struct drbd_bm_aio_ctx *ctx, int page_nr) __must_hold(local)
+static void bm_page_io_async(struct drbd_bm_aio_ctx *ctx, int page_nr)
{
struct drbd_device *device = ctx->device;
enum req_op op = ctx->flags & BM_AIO_READ ? REQ_OP_READ : REQ_OP_WRITE;
@@ -1060,7 +1070,7 @@ static void bm_page_io_async(struct drbd_bm_aio_ctx *ctx, int page_nr) __must_ho
/*
* bm_rw: read/write the whole bitmap from/to its on disk location.
*/
-static int bm_rw(struct drbd_device *device, const unsigned int flags, unsigned lazy_writeout_upper_idx) __must_hold(local)
+static int bm_rw(struct drbd_device *device, const unsigned int flags, unsigned lazy_writeout_upper_idx)
{
struct drbd_bm_aio_ctx *ctx;
struct drbd_bitmap *b = device->bitmap;
@@ -1215,7 +1225,7 @@ static int bm_rw(struct drbd_device *device, const unsigned int flags, unsigned
* @device: DRBD device.
*/
int drbd_bm_read(struct drbd_device *device,
- struct drbd_peer_device *peer_device) __must_hold(local)
+ struct drbd_peer_device *peer_device)

{
return bm_rw(device, BM_AIO_READ, 0);
@@ -1228,7 +1238,7 @@ int drbd_bm_read(struct drbd_device *device,
* Will only write pages that have changed since last IO.
*/
int drbd_bm_write(struct drbd_device *device,
- struct drbd_peer_device *peer_device) __must_hold(local)
+ struct drbd_peer_device *peer_device)
{
return bm_rw(device, 0, 0);
}
@@ -1240,7 +1250,7 @@ int drbd_bm_write(struct drbd_device *device,
* Will write all pages.
*/
int drbd_bm_write_all(struct drbd_device *device,
- struct drbd_peer_device *peer_device) __must_hold(local)
+ struct drbd_peer_device *peer_device)
{
return bm_rw(device, BM_AIO_WRITE_ALL_PAGES, 0);
}
@@ -1250,7 +1260,7 @@ int drbd_bm_write_all(struct drbd_device *device,
* @device: DRBD device.
* @upper_idx: 0: write all changed pages; +ve: page index to stop scanning for changed pages
*/
-int drbd_bm_write_lazy(struct drbd_device *device, unsigned upper_idx) __must_hold(local)
+int drbd_bm_write_lazy(struct drbd_device *device, unsigned upper_idx)
{
return bm_rw(device, BM_AIO_COPY_PAGES, upper_idx);
}
@@ -1267,7 +1277,7 @@ int drbd_bm_write_lazy(struct drbd_device *device, unsigned upper_idx) __must_ho
* pending resync acks are still being processed.
*/
int drbd_bm_write_copy_pages(struct drbd_device *device,
- struct drbd_peer_device *peer_device) __must_hold(local)
+ struct drbd_peer_device *peer_device)
{
return bm_rw(device, BM_AIO_COPY_PAGES, 0);
}
@@ -1276,7 +1286,7 @@ int drbd_bm_write_copy_pages(struct drbd_device *device,
* drbd_bm_write_hinted() - Write bitmap pages with "hint" marks, if they have changed.
* @device: DRBD device.
*/
-int drbd_bm_write_hinted(struct drbd_device *device) __must_hold(local)
+int drbd_bm_write_hinted(struct drbd_device *device)
{
return bm_rw(device, BM_AIO_WRITE_HINTED | BM_AIO_COPY_PAGES, 0);
}
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h
index f6d6276974ee..46546e6e9f6b 100644
--- a/drivers/block/drbd/drbd_int.h
+++ b/drivers/block/drbd/drbd_int.h
@@ -193,10 +193,14 @@ struct drbd_device_work {

#include "drbd_interval.h"

-extern int drbd_wait_misc(struct drbd_device *, struct drbd_interval *);
+/*
+ * Alias for &resources_mutex because &resources_mutex is not visible in this
+ * context.
+ */
+token_context_lock(all_drbd_resources);

-extern void lock_all_resources(void);
-extern void unlock_all_resources(void);
+extern void lock_all_resources(void) __acquires(all_drbd_resources);
+extern void unlock_all_resources(void) __releases(all_drbd_resources);

struct drbd_request {
struct drbd_work w;
@@ -1056,14 +1060,14 @@ extern void conn_md_sync(struct drbd_connection *connection);
extern void drbd_md_write(struct drbd_device *device, void *buffer);
extern void drbd_md_sync(struct drbd_device *device);
extern int drbd_md_read(struct drbd_device *device, struct drbd_backing_dev *bdev);
-extern void drbd_uuid_set(struct drbd_device *device, int idx, u64 val) __must_hold(local);
-extern void _drbd_uuid_set(struct drbd_device *device, int idx, u64 val) __must_hold(local);
-extern void drbd_uuid_new_current(struct drbd_device *device) __must_hold(local);
-extern void drbd_uuid_set_bm(struct drbd_device *device, u64 val) __must_hold(local);
-extern void drbd_uuid_move_history(struct drbd_device *device) __must_hold(local);
-extern void __drbd_uuid_set(struct drbd_device *device, int idx, u64 val) __must_hold(local);
-extern void drbd_md_set_flag(struct drbd_device *device, int flags) __must_hold(local);
-extern void drbd_md_clear_flag(struct drbd_device *device, int flags)__must_hold(local);
+extern void drbd_uuid_set(struct drbd_device *device, int idx, u64 val);
+extern void _drbd_uuid_set(struct drbd_device *device, int idx, u64 val);
+extern void drbd_uuid_new_current(struct drbd_device *device);
+extern void drbd_uuid_set_bm(struct drbd_device *device, u64 val);
+extern void drbd_uuid_move_history(struct drbd_device *device);
+extern void __drbd_uuid_set(struct drbd_device *device, int idx, u64 val);
+extern void drbd_md_set_flag(struct drbd_device *device, int flags);
+extern void drbd_md_clear_flag(struct drbd_device *device, int flags);
extern int drbd_md_test_flag(struct drbd_backing_dev *, int);
extern void drbd_md_mark_dirty(struct drbd_device *device);
extern void drbd_queue_bitmap_io(struct drbd_device *device,
@@ -1080,9 +1084,15 @@ extern int drbd_bitmap_io_from_worker(struct drbd_device *device,
char *why, enum bm_flag flags,
struct drbd_peer_device *peer_device);
extern int drbd_bmio_set_n_write(struct drbd_device *device,
- struct drbd_peer_device *peer_device) __must_hold(local);
+ struct drbd_peer_device *peer_device);
extern int drbd_bmio_clear_n_write(struct drbd_device *device,
- struct drbd_peer_device *peer_device) __must_hold(local);
+ struct drbd_peer_device *peer_device);
+extern enum drbd_state_rv
+_drbd_request_state_holding_state_mutex(struct drbd_device *device, union drbd_state,
+ union drbd_state, enum chg_state_flags)
+ __must_hold(&device->state_mutex);
+extern int drbd_wait_misc(struct drbd_device *device, struct drbd_interval *)
+ __must_hold(&device->resource->req_lock);

/* Meta data layout
*
@@ -1292,17 +1302,17 @@ extern void _drbd_bm_set_bits(struct drbd_device *device,
extern int drbd_bm_test_bit(struct drbd_device *device, unsigned long bitnr);
extern int drbd_bm_e_weight(struct drbd_device *device, unsigned long enr);
extern int drbd_bm_read(struct drbd_device *device,
- struct drbd_peer_device *peer_device) __must_hold(local);
+ struct drbd_peer_device *peer_device);
extern void drbd_bm_mark_for_writeout(struct drbd_device *device, int page_nr);
extern int drbd_bm_write(struct drbd_device *device,
- struct drbd_peer_device *peer_device) __must_hold(local);
-extern void drbd_bm_reset_al_hints(struct drbd_device *device) __must_hold(local);
-extern int drbd_bm_write_hinted(struct drbd_device *device) __must_hold(local);
-extern int drbd_bm_write_lazy(struct drbd_device *device, unsigned upper_idx) __must_hold(local);
+ struct drbd_peer_device *peer_device);
+extern void drbd_bm_reset_al_hints(struct drbd_device *device);
+extern int drbd_bm_write_hinted(struct drbd_device *device);
+extern int drbd_bm_write_lazy(struct drbd_device *device, unsigned upper_idx);
extern int drbd_bm_write_all(struct drbd_device *device,
- struct drbd_peer_device *peer_device) __must_hold(local);
+ struct drbd_peer_device *peer_device);
extern int drbd_bm_write_copy_pages(struct drbd_device *device,
- struct drbd_peer_device *peer_device) __must_hold(local);
+ struct drbd_peer_device *peer_device);
extern size_t drbd_bm_words(struct drbd_device *device);
extern unsigned long drbd_bm_bits(struct drbd_device *device);
extern sector_t drbd_bm_capacity(struct drbd_device *device);
@@ -1321,8 +1331,16 @@ extern void drbd_bm_merge_lel(struct drbd_device *device, size_t offset,
extern void drbd_bm_get_lel(struct drbd_device *device, size_t offset,
size_t number, unsigned long *buffer);

-extern void drbd_bm_lock(struct drbd_device *device, char *why, enum bm_flag flags);
-extern void drbd_bm_unlock(struct drbd_device *device);
+/*
+ * Alias for &device->bitmap->bm_change because not all type information for
+ * &device->bitmap->bm_change is available in this context.
+ */
+token_context_lock(drbd_bitmap_lock);
+
+extern void drbd_bm_lock(struct drbd_device *device, char *why, enum bm_flag flags)
+ __acquires(drbd_bitmap_lock);
+extern void drbd_bm_unlock(struct drbd_device *device)
+ __releases(drbd_bitmap_lock);
/* drbd_main.c */

extern struct kmem_cache *drbd_request_cache;
@@ -1389,7 +1407,8 @@ enum determine_dev_size {
DS_GREW_FROM_ZERO = 3,
};
extern enum determine_dev_size
-drbd_determine_dev_size(struct drbd_device *, enum dds_flags, struct resize_parms *) __must_hold(local);
+drbd_determine_dev_size(struct drbd_device *device, enum dds_flags,
+ struct resize_parms *);
extern void resync_after_online_grow(struct drbd_device *);
extern void drbd_reconsider_queue_parameters(struct drbd_device *device,
struct drbd_backing_dev *bdev, struct o_qlim *o);
@@ -1473,7 +1492,7 @@ extern int drbd_free_peer_reqs(struct drbd_device *, struct list_head *);
extern struct drbd_peer_request *drbd_alloc_peer_req(struct drbd_peer_device *, u64,
sector_t, unsigned int,
unsigned int,
- gfp_t) __must_hold(local);
+ gfp_t);
extern void drbd_free_peer_req(struct drbd_device *device, struct drbd_peer_request *req);
extern struct page *drbd_alloc_pages(struct drbd_peer_device *, unsigned int, bool);
extern void _drbd_clear_done_ee(struct drbd_device *device, struct list_head *to_be_freed);
@@ -1488,7 +1507,6 @@ void drbd_set_my_capacity(struct drbd_device *device, sector_t size);
static inline void drbd_submit_bio_noacct(struct drbd_device *device,
int fault_type, struct bio *bio)
{
- __release(local);
if (!bio->bi_bdev) {
drbd_err(device, "drbd_submit_bio_noacct: bio->bi_bdev == NULL\n");
bio->bi_status = BLK_STS_IOERR;
@@ -1839,14 +1857,18 @@ static inline void request_ping(struct drbd_connection *connection)
wake_ack_receiver(connection);
}

-extern void *conn_prepare_command(struct drbd_connection *, struct drbd_socket *);
-extern void *drbd_prepare_command(struct drbd_peer_device *, struct drbd_socket *);
-extern int conn_send_command(struct drbd_connection *, struct drbd_socket *,
+extern void *conn_prepare_command(struct drbd_connection *, struct drbd_socket *sock)
+ __cond_acquires(nonnull, sock->mutex);
+extern void *drbd_prepare_command(struct drbd_peer_device *, struct drbd_socket *sock)
+ __cond_acquires(nonnull, sock->mutex);
+extern int conn_send_command(struct drbd_connection *, struct drbd_socket *sock,
enum drbd_packet, unsigned int, void *,
- unsigned int);
-extern int drbd_send_command(struct drbd_peer_device *, struct drbd_socket *,
+ unsigned int)
+ __releases(sock->mutex);
+extern int drbd_send_command(struct drbd_peer_device *, struct drbd_socket *sock,
enum drbd_packet, unsigned int, void *,
- unsigned int);
+ unsigned int)
+ __releases(sock->mutex);

extern int drbd_send_ping(struct drbd_connection *connection);
extern int drbd_send_ping_ack(struct drbd_connection *connection);
@@ -1975,8 +1997,7 @@ static inline bool is_sync_state(enum drbd_conns connection_state)
* You have to call put_ldev() when finished working with device->ldev.
*/
#define get_ldev_if_state(_device, _min_state) \
- (_get_ldev_if_state((_device), (_min_state)) ? \
- ({ __acquire(x); true; }) : false)
+ (_get_ldev_if_state((_device), (_min_state)))
#define get_ldev(_device) get_ldev_if_state(_device, D_INCONSISTENT)

static inline void put_ldev(struct drbd_device *device)
@@ -1991,7 +2012,6 @@ static inline void put_ldev(struct drbd_device *device)
/* This may be called from some endio handler,
* so we must not sleep here. */

- __release(local);
D_ASSERT(device, i >= 0);
if (i == 0) {
if (disk_state == D_DISKLESS)
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c
index 200d464e984b..0bbee2afb7e5 100644
--- a/drivers/block/drbd/drbd_main.c
+++ b/drivers/block/drbd/drbd_main.c
@@ -3282,7 +3282,7 @@ void drbd_md_mark_dirty(struct drbd_device *device)
mod_timer(&device->md_sync_timer, jiffies + 5*HZ);
}

-void drbd_uuid_move_history(struct drbd_device *device) __must_hold(local)
+void drbd_uuid_move_history(struct drbd_device *device)
{
int i;

@@ -3290,7 +3290,7 @@ void drbd_uuid_move_history(struct drbd_device *device) __must_hold(local)
device->ldev->md.uuid[i+1] = device->ldev->md.uuid[i];
}

-void __drbd_uuid_set(struct drbd_device *device, int idx, u64 val) __must_hold(local)
+void __drbd_uuid_set(struct drbd_device *device, int idx, u64 val)
{
if (idx == UI_CURRENT) {
if (device->state.role == R_PRIMARY)
@@ -3305,7 +3305,7 @@ void __drbd_uuid_set(struct drbd_device *device, int idx, u64 val) __must_hold(l
drbd_md_mark_dirty(device);
}

-void _drbd_uuid_set(struct drbd_device *device, int idx, u64 val) __must_hold(local)
+void _drbd_uuid_set(struct drbd_device *device, int idx, u64 val)
{
unsigned long flags;
spin_lock_irqsave(&device->ldev->md.uuid_lock, flags);
@@ -3313,7 +3313,7 @@ void _drbd_uuid_set(struct drbd_device *device, int idx, u64 val) __must_hold(lo
spin_unlock_irqrestore(&device->ldev->md.uuid_lock, flags);
}

-void drbd_uuid_set(struct drbd_device *device, int idx, u64 val) __must_hold(local)
+void drbd_uuid_set(struct drbd_device *device, int idx, u64 val)
{
unsigned long flags;
spin_lock_irqsave(&device->ldev->md.uuid_lock, flags);
@@ -3332,7 +3332,7 @@ void drbd_uuid_set(struct drbd_device *device, int idx, u64 val) __must_hold(loc
* Creates a new current UUID, and rotates the old current UUID into
* the bitmap slot. Causes an incremental resync upon next connect.
*/
-void drbd_uuid_new_current(struct drbd_device *device) __must_hold(local)
+void drbd_uuid_new_current(struct drbd_device *device)
{
u64 val;
unsigned long long bm_uuid;
@@ -3354,7 +3354,7 @@ void drbd_uuid_new_current(struct drbd_device *device) __must_hold(local)
drbd_md_sync(device);
}

-void drbd_uuid_set_bm(struct drbd_device *device, u64 val) __must_hold(local)
+void drbd_uuid_set_bm(struct drbd_device *device, u64 val)
{
unsigned long flags;
spin_lock_irqsave(&device->ldev->md.uuid_lock, flags);
@@ -3387,7 +3387,7 @@ void drbd_uuid_set_bm(struct drbd_device *device, u64 val) __must_hold(local)
* Sets all bits in the bitmap and writes the whole bitmap to stable storage.
*/
int drbd_bmio_set_n_write(struct drbd_device *device,
- struct drbd_peer_device *peer_device) __must_hold(local)
+ struct drbd_peer_device *peer_device)

{
int rv = -EIO;
@@ -3414,7 +3414,7 @@ int drbd_bmio_set_n_write(struct drbd_device *device,
* Clears all bits in the bitmap and writes the whole bitmap to stable storage.
*/
int drbd_bmio_clear_n_write(struct drbd_device *device,
- struct drbd_peer_device *peer_device) __must_hold(local)
+ struct drbd_peer_device *peer_device)

{
drbd_resume_al(device);
@@ -3541,7 +3541,7 @@ int drbd_bitmap_io(struct drbd_device *device,
return rv;
}

-void drbd_md_set_flag(struct drbd_device *device, int flag) __must_hold(local)
+void drbd_md_set_flag(struct drbd_device *device, int flag)
{
if ((device->ldev->md.flags & flag) != flag) {
drbd_md_mark_dirty(device);
@@ -3549,7 +3549,7 @@ void drbd_md_set_flag(struct drbd_device *device, int flag) __must_hold(local)
}
}

-void drbd_md_clear_flag(struct drbd_device *device, int flag) __must_hold(local)
+void drbd_md_clear_flag(struct drbd_device *device, int flag)
{
if ((device->ldev->md.flags & flag) != 0) {
drbd_md_mark_dirty(device);
@@ -3678,24 +3678,44 @@ int drbd_wait_misc(struct drbd_device *device, struct drbd_interval *i)
}

void lock_all_resources(void)
+ __acquires(all_drbd_resources)
+ __acquires(&resources_mutex)
{
struct drbd_resource *resource;
int __maybe_unused i = 0;

mutex_lock(&resources_mutex);
local_irq_disable();
+ /*
+ * context_unsafe() because the thread-safety analyzer does not support
+ * locking inside loops.
+ */
+ context_unsafe(
for_each_resource(resource, &drbd_resources)
spin_lock_nested(&resource->req_lock, i++);
+ );
+
+ __acquire(all_drbd_resources);
}

void unlock_all_resources(void)
+ __releases(all_drbd_resources)
+ __releases(&resources_mutex)
{
struct drbd_resource *resource;

+ /*
+ * context_unsafe() because the thread-safety analyzer does not support
+ * locking inside loops.
+ */
+ context_unsafe(
for_each_resource(resource, &drbd_resources)
spin_unlock(&resource->req_lock);
+ );
local_irq_enable();
mutex_unlock(&resources_mutex);
+
+ __release(all_drbd_resources);
}

#ifdef CONFIG_DRBD_FAULT_INJECTION
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index 1f8ffdf9b24e..67dec3403edc 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -993,7 +993,7 @@ void drbd_resume_io(struct drbd_device *device)
* You should call drbd_md_sync() after calling this function.
*/
enum determine_dev_size
-drbd_determine_dev_size(struct drbd_device *device, enum dds_flags flags, struct resize_parms *rs) __must_hold(local)
+drbd_determine_dev_size(struct drbd_device *device, enum dds_flags flags, struct resize_parms *rs)
{
struct md_offsets_and_sizes {
u64 last_agreed_sect;
@@ -3090,7 +3090,7 @@ static int drbd_adm_simple_request_state(struct sk_buff *skb, struct genl_info *
}

static int drbd_bmio_set_susp_al(struct drbd_device *device,
- struct drbd_peer_device *peer_device) __must_hold(local)
+ struct drbd_peer_device *peer_device)
{
int rv;

@@ -3518,6 +3518,7 @@ int drbd_adm_dump_connections_done(struct netlink_callback *cb)
enum { SINGLE_RESOURCE, ITERATE_RESOURCES };

int drbd_adm_dump_connections(struct sk_buff *skb, struct netlink_callback *cb)
+ __no_context_analysis /* too complex for Clang */
{
struct nlattr *resource_filter;
struct drbd_resource *resource = NULL, *next_resource;
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c
index 58b95bf4bdca..b0ef6c5470f8 100644
--- a/drivers/block/drbd/drbd_receiver.c
+++ b/drivers/block/drbd/drbd_receiver.c
@@ -175,7 +175,7 @@ You must not have the req_lock:
* trim: payload_size == 0 */
struct drbd_peer_request *
drbd_alloc_peer_req(struct drbd_peer_device *peer_device, u64 id, sector_t sector,
- unsigned int request_size, unsigned int payload_size, gfp_t gfp_mask) __must_hold(local)
+ unsigned int request_size, unsigned int payload_size, gfp_t gfp_mask)
{
struct drbd_device *device = peer_device->device;
struct drbd_peer_request *peer_req;
@@ -287,6 +287,7 @@ static int drbd_finish_peer_reqs(struct drbd_device *device)

static void _drbd_wait_ee_list_empty(struct drbd_device *device,
struct list_head *head)
+ __must_hold(&device->resource->req_lock)
{
DEFINE_WAIT(wait);

@@ -896,6 +897,11 @@ static int conn_connect(struct drbd_connection *connection)
if (drbd_send_protocol(connection) == -EOPNOTSUPP)
return -1;

+ /*
+ * context_unsafe() because the thread-safety analyzer does not support
+ * locking inside loops.
+ */
+ context_unsafe(
/* Prevent a race between resync-handshake and
* being promoted to Primary.
*
@@ -905,14 +911,21 @@ static int conn_connect(struct drbd_connection *connection)
*/
idr_for_each_entry(&connection->peer_devices, peer_device, vnr)
mutex_lock(peer_device->device->state_mutex);
+ );

/* avoid a race with conn_request_state( C_DISCONNECTING ) */
spin_lock_irq(&connection->resource->req_lock);
set_bit(STATE_SENT, &connection->flags);
spin_unlock_irq(&connection->resource->req_lock);

+ /*
+ * context_unsafe() because the thread-safety analyzer does not support
+ * locking inside loops.
+ */
+ context_unsafe(
idr_for_each_entry(&connection->peer_devices, peer_device, vnr)
mutex_unlock(peer_device->device->state_mutex);
+ );

rcu_read_lock();
idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
@@ -1657,7 +1670,7 @@ static void drbd_csum_ee_size(struct crypto_shash *h,
*/
static struct drbd_peer_request *
read_in_block(struct drbd_peer_device *peer_device, u64 id, sector_t sector,
- struct packet_info *pi) __must_hold(local)
+ struct packet_info *pi)
{
struct drbd_device *device = peer_device->device;
const sector_t capacity = get_capacity(device->vdisk);
@@ -1869,7 +1882,7 @@ static int e_end_resync_block(struct drbd_work *w, int unused)
}

static int recv_resync_read(struct drbd_peer_device *peer_device, sector_t sector,
- struct packet_info *pi) __releases(local)
+ struct packet_info *pi)
{
struct drbd_device *device = peer_device->device;
struct drbd_peer_request *peer_req;
@@ -2230,6 +2243,7 @@ static blk_opf_t wire_flags_to_bio(struct drbd_connection *connection, u32 dpf)

static void fail_postponed_requests(struct drbd_device *device, sector_t sector,
unsigned int size)
+ __must_hold(&device->resource->req_lock)
{
struct drbd_peer_device *peer_device = first_peer_device(device);
struct drbd_interval *i;
@@ -2256,6 +2270,7 @@ static void fail_postponed_requests(struct drbd_device *device, sector_t sector,

static int handle_write_conflicts(struct drbd_device *device,
struct drbd_peer_request *peer_req)
+ __must_hold(&device->resource->req_lock)
{
struct drbd_connection *connection = peer_req->peer_device->connection;
bool resolve_conflicts = test_bit(RESOLVE_CONFLICTS, &connection->flags);
@@ -2826,7 +2841,7 @@ static int receive_DataRequest(struct drbd_connection *connection, struct packet
/*
* drbd_asb_recover_0p - Recover after split-brain with no remaining primaries
*/
-static int drbd_asb_recover_0p(struct drbd_peer_device *peer_device) __must_hold(local)
+static int drbd_asb_recover_0p(struct drbd_peer_device *peer_device)
{
struct drbd_device *device = peer_device->device;
int self, peer, rv = -100;
@@ -2909,7 +2924,7 @@ static int drbd_asb_recover_0p(struct drbd_peer_device *peer_device) __must_hold
/*
* drbd_asb_recover_1p - Recover after split-brain with one remaining primary
*/
-static int drbd_asb_recover_1p(struct drbd_peer_device *peer_device) __must_hold(local)
+static int drbd_asb_recover_1p(struct drbd_peer_device *peer_device)
{
struct drbd_device *device = peer_device->device;
int hg, rv = -100;
@@ -2966,7 +2981,7 @@ static int drbd_asb_recover_1p(struct drbd_peer_device *peer_device) __must_hold
/*
* drbd_asb_recover_2p - Recover after split-brain with two remaining primaries
*/
-static int drbd_asb_recover_2p(struct drbd_peer_device *peer_device) __must_hold(local)
+static int drbd_asb_recover_2p(struct drbd_peer_device *peer_device)
{
struct drbd_device *device = peer_device->device;
int hg, rv = -100;
@@ -3044,7 +3059,7 @@ static void drbd_uuid_dump(struct drbd_device *device, char *text, u64 *uuid,
*/

static int drbd_uuid_compare(struct drbd_peer_device *const peer_device,
- enum drbd_role const peer_role, int *rule_nr) __must_hold(local)
+ enum drbd_role const peer_role, int *rule_nr)
{
struct drbd_connection *const connection = peer_device->connection;
struct drbd_device *device = peer_device->device;
@@ -3264,7 +3279,7 @@ static int drbd_uuid_compare(struct drbd_peer_device *const peer_device,
*/
static enum drbd_conns drbd_sync_handshake(struct drbd_peer_device *peer_device,
enum drbd_role peer_role,
- enum drbd_disk_state peer_disk) __must_hold(local)
+ enum drbd_disk_state peer_disk)
{
struct drbd_device *device = peer_device->device;
enum drbd_conns rv = C_MASK;
diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c
index 70f75ef07945..a758d0f66e3f 100644
--- a/drivers/block/drbd/drbd_req.c
+++ b/drivers/block/drbd/drbd_req.c
@@ -952,6 +952,7 @@ static bool remote_due_to_read_balancing(struct drbd_device *device, sector_t se
* Only way out: remove the conflicting intervals from the tree.
*/
static void complete_conflicting_writes(struct drbd_request *req)
+ __must_hold(&req->device->resource->req_lock)
{
DEFINE_WAIT(wait);
struct drbd_device *device = req->device;
@@ -1325,6 +1326,8 @@ static void drbd_send_and_submit(struct drbd_device *device, struct drbd_request
bool submit_private_bio = false;

spin_lock_irq(&resource->req_lock);
+ /* Tell the compiler that &resource->req_lock == &req->device->resource->req_lock. */
+ __assume_ctx_lock(&req->device->resource->req_lock);
if (rw == WRITE) {
/* This may temporarily give up the req_lock,
* but will re-aquire it before it returns here.
diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c
index adcba7f1d8ea..1c18d9f81e03 100644
--- a/drivers/block/drbd/drbd_state.c
+++ b/drivers/block/drbd/drbd_state.c
@@ -562,6 +562,7 @@ _req_st_cond(struct drbd_device *device, union drbd_state mask,
static enum drbd_state_rv
drbd_req_state(struct drbd_device *device, union drbd_state mask,
union drbd_state val, enum chg_state_flags f)
+ __no_context_analysis /* conditional locking */
{
struct completion done;
unsigned long flags;
@@ -2292,6 +2293,7 @@ _conn_rq_cond(struct drbd_connection *connection, union drbd_state mask, union d
enum drbd_state_rv
_conn_request_state(struct drbd_connection *connection, union drbd_state mask, union drbd_state val,
enum chg_state_flags flags)
+ __no_context_analysis /* conditional locking */
{
enum drbd_state_rv rv = SS_SUCCESS;
struct after_conn_state_chg_work *acscw;
diff --git a/drivers/block/drbd/drbd_state.h b/drivers/block/drbd/drbd_state.h
index cbaeb8018dbf..e6fded8b14ee 100644
--- a/drivers/block/drbd/drbd_state.h
+++ b/drivers/block/drbd/drbd_state.h
@@ -123,10 +123,6 @@ extern enum drbd_state_rv _drbd_request_state(struct drbd_device *,
union drbd_state,
enum chg_state_flags);

-extern enum drbd_state_rv
-_drbd_request_state_holding_state_mutex(struct drbd_device *, union drbd_state,
- union drbd_state, enum chg_state_flags);
-
extern enum drbd_state_rv _drbd_set_state(struct drbd_device *, union drbd_state,
enum chg_state_flags,
struct completion *done);
diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c
index 0697f99fed18..6fec59bbf0e9 100644
--- a/drivers/block/drbd/drbd_worker.c
+++ b/drivers/block/drbd/drbd_worker.c
@@ -78,7 +78,7 @@ void drbd_md_endio(struct bio *bio)
/* reads on behalf of the partner,
* "submitted" by the receiver
*/
-static void drbd_endio_read_sec_final(struct drbd_peer_request *peer_req) __releases(local)
+static void drbd_endio_read_sec_final(struct drbd_peer_request *peer_req)
{
unsigned long flags = 0;
struct drbd_peer_device *peer_device = peer_req->peer_device;
@@ -99,7 +99,7 @@ static void drbd_endio_read_sec_final(struct drbd_peer_request *peer_req) __rele

/* writes on behalf of the partner, or resync writes,
* "submitted" by the receiver, final stage. */
-void drbd_endio_write_sec_final(struct drbd_peer_request *peer_req) __releases(local)
+void drbd_endio_write_sec_final(struct drbd_peer_request *peer_req)
{
unsigned long flags = 0;
struct drbd_peer_device *peer_device = peer_req->peer_device;
@@ -1923,10 +1923,8 @@ static void drbd_ldev_destroy(struct drbd_device *device)
lc_destroy(device->act_log);
device->act_log = NULL;

- __acquire(local);
drbd_backing_dev_free(device, device->ldev);
device->ldev = NULL;
- __release(local);

clear_bit(GOING_DISKLESS, &device->flags);
wake_up(&device->misc_wait);