]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
smb: client: split cached_fid bitfields to avoid shared-byte RMW races
authorHenrique Carvalho <henrique.carvalho@suse.com>
Tue, 27 Jan 2026 16:01:28 +0000 (13:01 -0300)
committerSteve French <stfrench@microsoft.com>
Sun, 8 Feb 2026 23:07:43 +0000 (17:07 -0600)
is_open, has_lease and on_list are stored in the same bitfield byte in
struct cached_fid but are updated in different code paths that may run
concurrently. Bitfield assignments generate byte read–modify–write
operations (e.g. `orb $mask, addr` on x86_64), so updating one flag can
restore stale values of the others.

A possible interleaving is:
    CPU1: load old byte (has_lease=1, on_list=1)
    CPU2: clear both flags (store 0)
    CPU1: RMW store (old | IS_OPEN) -> reintroduces cleared bits

To avoid this class of races, convert these flags to separate bool
fields.

Cc: stable@vger.kernel.org
Fixes: ebe98f1447bbc ("cifs: enable caching of directories for which a lease is held")
Signed-off-by: Henrique Carvalho <henrique.carvalho@suse.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/client/cached_dir.h

index 1e383db7c33743281ce7fce78fa365f6fc6e8157..5091bf45345e81486b956deb39895ccd0bccf166 100644 (file)
@@ -36,10 +36,10 @@ struct cached_fid {
        struct list_head entry;
        struct cached_fids *cfids;
        const char *path;
-       bool has_lease:1;
-       bool is_open:1;
-       bool on_list:1;
-       bool file_all_info_is_valid:1;
+       bool has_lease;
+       bool is_open;
+       bool on_list;
+       bool file_all_info_is_valid;
        unsigned long time; /* jiffies of when lease was taken */
        unsigned long last_access_time; /* jiffies of when last accessed */
        struct kref refcount;