Hi Btrfs Developers,
While fuzzing btrfs I notice a potential data race on
BTRFS_I(inode)->root->last_log_commit and log_transid when an inode is
being added and fdatasync-ed at the same time. Following is the
execution trace:
[Setup]
mkdir("foo", 511) = 0;
open("foo", 65536, 511) = 3;
[Thread 1]
mkdirat(-100, "bar", 246);
__do_sys_mkdirat
do_mkdirat
vfs_mkdir
btrfs_mkdir
btrfs_new_inode
btrfs_set_inode_last_trans
[READ] BTRFS_I(inode)->last_sub_trans =
BTRFS_I(inode)->root->log_transid;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[READ] BTRFS_I(inode)->last_log_commit =
BTRFS_I(inode)->root->last_log_commit;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[Thread 2]
fdatasync(3);
__do_sys_fdatasync
do_fsync
vfs_fsync
vfs_fsync_range
btrfs_sync_file
btrfs_log_dentry_safe
btrfs_log_inode_parent
start_log_trans
btrfs_add_log_tree
[WRITE] root->log_transid = 0;
[WRITE] root->last_log_commit = 0;
The trace seems fine based on the program order. However, if adding
the memory model into consideration, i.e., the inter-leavings of the
writes and reads, it is possible that the two [READ] receives
inconsistent information about BTRFS_I(inode)->root->*. For example,
BTRFS_I(inode)->root->log_transid is 0 while
BTRFS_I(inode)->root->last_log_commit is a stale value (or the other
way round). This may have a negative impact when persisting the
mkdirat-created inode?
Best Regards,
Meng