[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