struct btrfs_inode *inode = BTRFS_I(ctx->inode);
        struct btrfs_fs_info *fs_info = inode->root->fs_info;
 
-       if (btrfs_inode_in_log(inode, fs_info->generation) &&
+       if (btrfs_inode_in_log(inode, btrfs_get_fs_generation(fs_info)) &&
            list_empty(&ctx->ordered_extents))
                return true;
 
 
 
        struct btrfs_block_rsv empty_block_rsv;
 
+       /*
+        * Updated while holding the lock 'trans_lock'. Due to the life cycle of
+        * a transaction, it can be directly read while holding a transaction
+        * handle, everywhere else must be read with btrfs_get_fs_generation().
+        * Should always be updated using btrfs_set_fs_generation().
+        */
        u64 generation;
        u64 last_trans_committed;
        /*
 #endif
 };
 
+static inline u64 btrfs_get_fs_generation(const struct btrfs_fs_info *fs_info)
+{
+       return READ_ONCE(fs_info->generation);
+}
+
+static inline void btrfs_set_fs_generation(struct btrfs_fs_info *fs_info, u64 gen)
+{
+       WRITE_ONCE(fs_info->generation, gen);
+}
+
 static inline void btrfs_set_last_root_drop_gen(struct btrfs_fs_info *fs_info,
                                                u64 gen)
 {
 
         * This is required for both inode re-read from disk and delayed inode
         * in delayed_nodes_tree.
         */
-       if (BTRFS_I(inode)->last_trans == fs_info->generation)
+       if (BTRFS_I(inode)->last_trans == btrfs_get_fs_generation(fs_info))
                set_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
                        &BTRFS_I(inode)->runtime_flags);
 
                        hole_em->orig_block_len = 0;
                        hole_em->ram_bytes = hole_size;
                        hole_em->compress_type = BTRFS_COMPRESS_NONE;
-                       hole_em->generation = fs_info->generation;
+                       hole_em->generation = btrfs_get_fs_generation(fs_info);
 
                        err = btrfs_replace_extent_map_range(inode, hole_em, true);
                        free_extent_map(hole_em);
 
        }
 
        if (flags_in & BTRFS_FS_INFO_FLAG_GENERATION) {
-               fi_args->generation = fs_info->generation;
+               fi_args->generation = btrfs_get_fs_generation(fs_info);
                fi_args->flags |= BTRFS_FS_INFO_FLAG_GENERATION;
        }
 
 
 {
        struct btrfs_fs_info *fs_info = to_fs_info(kobj);
 
-       return sysfs_emit(buf, "%llu\n", fs_info->generation);
+       return sysfs_emit(buf, "%llu\n", btrfs_get_fs_generation(fs_info));
 }
 BTRFS_ATTR(, generation, btrfs_generation_show);
 
 
                        IO_TREE_TRANS_DIRTY_PAGES);
        extent_io_tree_init(fs_info, &cur_trans->pinned_extents,
                        IO_TREE_FS_PINNED_EXTENTS);
-       fs_info->generation++;
+       btrfs_set_fs_generation(fs_info, fs_info->generation + 1);
        cur_trans->transid = fs_info->generation;
        fs_info->running_transaction = cur_trans;
        cur_trans->aborted = 0;