mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 14:53:58 -04:00
btrfs: check type flags in alloc_ordered_extent()
Unlike other flags used in btrfs, BTRFS_ORDERED_* macros are different as
they cannot be directly used as flags.
They are defined as bit values, thus they should be utilized with
bit operations, not directly with logical operations.
Unfortunately sometimes I forgot this and passed the incorrect flags
to alloc_ordered_extent() and hit weird bugs.
Enhance the type checks in alloc_ordered_extent():
- Make sure there is one and only one bit set for exclusive type flags
There are four exclusive type flags, REGULAR, NOCOW, PREALLOC and
COMPRESSED.
So introduce a new macro, BTRFS_ORDERED_EXCLUSIVE_FLAGS, to cover
above flags.
Add an ASSERT() to check one and only one of those exclusive flags can
be set for alloc_ordered_extent().
- Re-order the type bit numbers to the end of the enum
This is make it much harder to get a valid false negative.
E.g., with the old code BTRFS_ORDERED_REGULAR starts at zero, we can
have the following flags passing the bit uniqueness check:
* BTRFS_ORDERED_NOCOW
Be treated as BTRFS_ORDERED_REGULAR (1 == 1UL << 0).
* BTRFS_ORDERED_PREALLOC
Be treated as BTRFS_ORDERED_NOCOW (2 == 1UL << 1).
* BTRFS_ORDERED_DIRECT
Be treated as BTRFS_ORDERED_PREALLOC (4 == 1UL << 2).
Now all those types start at 8, passing any of those bit numbers as
flags directly will not pass the ASSERT().
- Add a static assert to avoid overflow
To make sure all BTRFS_ORDERED_* flags can fit into an unsigned long.
Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
@@ -156,6 +156,19 @@ static struct btrfs_ordered_extent *alloc_ordered_extent(
|
||||
const bool is_nocow = (flags &
|
||||
((1U << BTRFS_ORDERED_NOCOW) | (1U << BTRFS_ORDERED_PREALLOC)));
|
||||
|
||||
/* Only one type flag can be set. */
|
||||
ASSERT(has_single_bit_set(flags & BTRFS_ORDERED_EXCLUSIVE_FLAGS));
|
||||
|
||||
/* DIRECT cannot be set with COMPRESSED nor ENCODED. */
|
||||
if (test_bit(BTRFS_ORDERED_DIRECT, &flags)) {
|
||||
ASSERT(!test_bit(BTRFS_ORDERED_COMPRESSED, &flags));
|
||||
ASSERT(!test_bit(BTRFS_ORDERED_ENCODED, &flags));
|
||||
}
|
||||
|
||||
/* ENCODED must be set with COMPRESSED. */
|
||||
if (test_bit(BTRFS_ORDERED_ENCODED, &flags))
|
||||
ASSERT(test_bit(BTRFS_ORDERED_COMPRESSED, &flags));
|
||||
|
||||
/*
|
||||
* For a NOCOW write we can free the qgroup reserve right now. For a COW
|
||||
* one we transfer the reserved space from the inode's iotree into the
|
||||
|
||||
Reference in New Issue
Block a user