[PATCH v2] afs: Add barriers by using clear_and_wake_up_bit()

Arnaud Bonnet abo at medichon.fr
Wed Oct 21 07:52:32 PDT 2026


The wake_up_bit() function requires a full memory barrier between the
bit operation and itself. For atomic operations such as
clear_bit_unlock(), it is enough to use a smp_mb__after_atomic()
barrier.

Insert the smp_mb__after_atomic() barrier where missing. When
appropriate, use the clear_and_wake_up_bit() helper which is a wrapper
for the clear_bit_unlock() -> smp_mb__after_atomic() -> wake_up_bit()
sequence.

Fixes: 3bf0fb6f33dd5 ("afs: Probe multiple fileservers simultaneously")
Fixes: d2ddc776a4581 ("afs: Overhaul volume and server record caching and fileserver rotation")
Signed-off-by: Arnaud Bonnet <abo at medichon.fr>
---
Tested by building and manually checking generated assembly.
Depending on the architecture it may:
        1) have no effect,
        2) supplement the release atomic with a full barrier, or
        3) add a redundant but harmless full barrier.
This fixes the second case.

Example in server.c function afs_check_server_record():

- x86: no change in generated code

- arm64(lse):
        mov     x0, 2           # AFS_SERVER_FL_UPDATING (bit 1)
        add     x1, x20, 232    # &server->flags 
        .arch_extension lse
        ldclrl  x0, x0, [x1]    # clear_bit_unlock(), release barrier
.L264:
+       dmb ish                 # full barrier from smp_mb__after_atomic()
        mov     w1, 1
        mov     x0, x19
        bl      wake_up_bit     # wake_up_bit()
        b       .L258           # return success

- rv64(a):
        li      a5,-3                   # ~AFS_SERVER_FL_UPDATING
        addi    a4,s3,232               # &server->flags
        amoand.d.rl zero, a5, 0(a4)     # clear_bit_unlock(), acquire-release
+               fence rw,rw             # redundant smp_mb__after_atomic()
        li      a1,1
        mv      a0,s5
        call    wake_up_bit             # wake_up_bit()
        j       .L279                   # return success

v2) Changes from v1:
        * Added missing smp_mb__after_atomic() in fs/afs/volume.c.
        * Reworked commit message.
        * Added testing procedure description outside of commit message.

 fs/afs/server.c   | 3 +--
 fs/afs/vl_probe.c | 3 +--
 fs/afs/volume.c   | 5 +++++
 3 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/fs/afs/server.c b/fs/afs/server.c
index 189138bd6d71..6953877c25b2 100644
--- a/fs/afs/server.c
+++ b/fs/afs/server.c
@@ -604,8 +604,7 @@ bool afs_check_server_record(struct afs_operation *op, struct afs_server *server
 	if (!test_and_set_bit_lock(AFS_SERVER_FL_UPDATING, &server->flags)) {
 		clear_bit(AFS_SERVER_FL_NEEDS_UPDATE, &server->flags);
 		success = afs_update_server_record(op, server, key);
-		clear_bit_unlock(AFS_SERVER_FL_UPDATING, &server->flags);
-		wake_up_bit(&server->flags, AFS_SERVER_FL_UPDATING);
+		clear_and_wake_up_bit(AFS_SERVER_FL_UPDATING, &server->flags);
 		_leave(" = %d", success);
 		return success;
 	}
diff --git a/fs/afs/vl_probe.c b/fs/afs/vl_probe.c
index 3d2e0c925460..9850e028c44b 100644
--- a/fs/afs/vl_probe.c
+++ b/fs/afs/vl_probe.c
@@ -22,8 +22,7 @@ static void afs_finished_vl_probe(struct afs_vlserver *server)
 		clear_bit(AFS_VLSERVER_FL_RESPONDING, &server->flags);
 	}
 
-	clear_bit_unlock(AFS_VLSERVER_FL_PROBING, &server->flags);
-	wake_up_bit(&server->flags, AFS_VLSERVER_FL_PROBING);
+	clear_and_wake_up_bit(AFS_VLSERVER_FL_PROBING, &server->flags);
 }
 
 /*
diff --git a/fs/afs/volume.c b/fs/afs/volume.c
index 4f79d25ec37f..ca8fec87a01b 100644
--- a/fs/afs/volume.c
+++ b/fs/afs/volume.c
@@ -444,6 +444,11 @@ int afs_check_volume_status(struct afs_volume *volume, struct afs_operation *op)
 			set_bit(AFS_VOLUME_NEEDS_UPDATE, &volume->flags);
 		clear_bit_unlock(AFS_VOLUME_WAIT, &volume->flags);
 		clear_bit_unlock(AFS_VOLUME_UPDATING, &volume->flags);
+		/* Memory barrier must be set between clearing AFS_VOLUME_WAIT and
+		 * wake_up_bit() since clear_bit_unlock() is not a full barrier.
+		 * See wake_up_bit() description for more information.
+		 */
+		smp_mb__after_atomic();
 		wake_up_bit(&volume->flags, AFS_VOLUME_WAIT);
 		_leave(" = %d", ret);
 		return ret;
-- 
2.53.0




More information about the linux-afs mailing list