Skip to content

Commit

Permalink
Merge drbd-9.1/ef44e55d5 'drbd: protect caching pointers from being a…
Browse files Browse the repository at this point in the history
…dvanced concurrently'
  • Loading branch information
Philipp-Reisner committed Jun 1, 2023
2 parents c7edc89 + ef44e55 commit e03a389
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 5 deletions.
2 changes: 2 additions & 0 deletions drbd/drbd_int.h
Original file line number Diff line number Diff line change
Expand Up @@ -1159,6 +1159,8 @@ struct drbd_connection {
/* The oldest request that is or was queued for this peer, but is not
* done towards it. */
struct drbd_request *req_not_net_done;
/* Protects the caching pointers from being advanced concurrently. */
spinlock_t advance_cache_ptr_lock;

unsigned int s_cb_nr; /* keeps counting up */
unsigned int r_cb_nr; /* keeps counting up */
Expand Down
2 changes: 2 additions & 0 deletions drbd/drbd_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -3708,6 +3708,8 @@ struct drbd_connection *drbd_create_connection(struct drbd_resource *resource,
INIT_LIST_HEAD(&connection->send_dagtag_work.list);
connection->send_dagtag_work.cb = w_send_dagtag;

spin_lock_init(&connection->advance_cache_ptr_lock);

kref_get(&resource->kref);
kref_debug_get(&resource->kref_debug, 3);
connection->resource = resource;
Expand Down
18 changes: 13 additions & 5 deletions drbd/drbd_req.c
Original file line number Diff line number Diff line change
Expand Up @@ -769,11 +769,7 @@ static void advance_conn_req_next(struct drbd_connection *connection, struct drb
* this will advance it to the next request fulfilling the condition.
*
* set_cache_ptr_if_null() may be called concurrently with itself and with
* advance_cache_ptr(). However, advance_cache_ptr() must not be called
* concurrently for a given caching pointer. If it were, the call for the older
* request may advance the pointer to the newer request, although the newer
* request has concurrently been modified such that it no longer fulfils the
* condition.
* advance_cache_ptr().
*/
static void set_cache_ptr_if_null(struct drbd_request **cache_ptr, struct drbd_request *req)
{
Expand All @@ -798,10 +794,20 @@ static void advance_cache_ptr(struct drbd_connection *connection,
struct drbd_request *old_req;
struct drbd_request *found_req = NULL;

/*
* Prevent concurrent updates of the same caching pointer. Otherwise if
* this function is called concurrently for a given caching pointer,
* the call for the older request may advance the pointer to the newer
* request, although the newer request has concurrently been modified
* such that it no longer fulfils the condition.
*/
spin_lock(&connection->advance_cache_ptr_lock); /* local IRQ already disabled */

rcu_read_lock();
old_req = rcu_dereference(*cache_ptr);
if (old_req != req) {
rcu_read_unlock();
spin_unlock(&connection->advance_cache_ptr_lock);
return;
}
list_for_each_entry_continue_rcu(req, &connection->resource->transfer_log, tl_requests) {
Expand All @@ -816,6 +822,8 @@ static void advance_cache_ptr(struct drbd_connection *connection,

cmpxchg(cache_ptr, old_req, found_req);
rcu_read_unlock();

spin_unlock(&connection->advance_cache_ptr_lock);
}

/* for wsame, discard, and zero-out requests, the payload (amount of data we
Expand Down

0 comments on commit e03a389

Please sign in to comment.