Skip to content

Commit f92b71f

Browse files
committed
Merge tag 'for-6.17-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux
Pull btrfs updates from David Sterba: "A number of usability and feature updates, scattered performance improvements and fixes. Highlight of the core changes is getting closer to enabling large folios (now behind a config option). User visible changes: - update defrag ioctl, add new flag to request no compression on existing extents - restrict writes to block devices after mount - in experimental config, enable large folios for data, almost complete but not widely tested - add stats tracking duration of critical section in transaction commit to /sys/fs/btrfs/FSID/commit_stats Performance improvements: - caching of lookup results of free space bitmap (20% runtime improvement on an empty file creation benchmark) - accessors to metadata (b-tree items) simplified and optimized, minor improvement in metadata-heavy workloads - readahead on compressed data improves sequential read - the xarray for extent buffers is indexed by denser keys, leading to better packing of the nodes (50-70% reduction of leaf nodes) Notable fixes: - stricter compression mount option parsing - send properly emits fallocate command for file holes when protocol v2 is used - fix overallocation of chunks with mount option 'ssd_spread', due to interaction with size classes not finding the right chunk (workaround: manual reclaim by 'usage' balance filter) - various quota enable/disable races with rescan, more verbose notifications about inconsistent state - populate otime in tree-log during log replay - handle ENOSPC when NOCOW file is used with mmap() Core: - large data folios enabled in experimental config - improved error handling, transaction abort call sites - in zoned mode, allocate reloc block group on mount to make sure there's always one available for zone reclaim under heavy load - rework device opening, they're always open as read-only and delayed until the super block is created, allowing the restricted writes after mount - preparatory work for adding blk_holder_ops, allowing device freeze/thaw in the future Cleanups, refactoring: - type and naming unifications (int/bool, return variables) - rb-tree helper refactoring and simplifications - reorder memory allocations to less critical places - RCU string (used for device name) refactoring and API removal - replace all remaining use of strcpy()" * tag 'for-6.17-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: (209 commits) btrfs: send: use fallocate for hole punching with send stream v2 btrfs: unfold transaction aborts when writing dirty block groups btrfs: use saner variable type and name to indicate extrefs at add_inode_ref() btrfs: don't skip remaining extrefs if dir not found during log replay btrfs: don't ignore inode missing when replaying log tree btrfs: enable large data folios for data reloc inode btrfs: output more info when btrfs_subpage_assert() failed btrfs: reloc: unconditionally invalidate the page cache for each cluster btrfs: defrag: add flag to force no-compression btrfs: fix ssd_spread overallocation btrfs: zoned: requeue to unused block group list if zone finish failed btrfs: zoned: do not remove unwritten non-data block group btrfs: remove btrfs_clear_extent_bits() btrfs: use cached state when falling back from NOCoW write to CoW write btrfs: set EXTENT_NORESERVE before range unlock in btrfs_truncate_block() btrfs: don't print relocation messages from auto reclaim btrfs: remove redundant auto reclaim log message btrfs: make btrfs_check_nocow_lock() check more than one extent btrfs: assert we can NOCOW the range in btrfs_truncate_block() btrfs: update function comment for btrfs_check_nocow_lock() ...
2 parents 038d61f + 005b0a0 commit f92b71f

76 files changed

Lines changed: 2634 additions & 2620 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

fs/btrfs/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ config BTRFS_EXPERIMENTAL
114114

115115
- extent tree v2 - complex rework of extent tracking
116116

117+
- large folio support
118+
117119
If unsure, say N.
118120

119121
config BTRFS_FS_REF_VERIFY

fs/btrfs/accessors.c

Lines changed: 51 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -9,27 +9,24 @@
99
#include "fs.h"
1010
#include "accessors.h"
1111

12-
static bool check_setget_bounds(const struct extent_buffer *eb,
13-
const void *ptr, unsigned off, int size)
12+
static void __cold report_setget_bounds(const struct extent_buffer *eb,
13+
const void *ptr, unsigned off, int size)
1414
{
15-
const unsigned long member_offset = (unsigned long)ptr + off;
15+
unsigned long member_offset = (unsigned long)ptr + off;
1616

17-
if (unlikely(member_offset + size > eb->len)) {
18-
btrfs_warn(eb->fs_info,
19-
"bad eb member %s: ptr 0x%lx start %llu member offset %lu size %d",
20-
(member_offset > eb->len ? "start" : "end"),
21-
(unsigned long)ptr, eb->start, member_offset, size);
22-
return false;
23-
}
24-
25-
return true;
17+
btrfs_warn(eb->fs_info,
18+
"bad eb member %s: ptr 0x%lx start %llu member offset %lu size %d",
19+
(member_offset > eb->len ? "start" : "end"),
20+
(unsigned long)ptr, eb->start, member_offset, size);
2621
}
2722

28-
void btrfs_init_map_token(struct btrfs_map_token *token, struct extent_buffer *eb)
23+
/* Copy bytes from @src1 and @src2 to @dest. */
24+
static __always_inline void memcpy_split_src(char *dest, const char *src1,
25+
const char *src2, const size_t len1,
26+
const size_t total)
2927
{
30-
token->eb = eb;
31-
token->kaddr = folio_address(eb->folios[0]);
32-
token->offset = 0;
28+
memcpy(dest, src1, len1);
29+
memcpy(dest + len1, src2, total - len1);
3330
}
3431

3532
/*
@@ -41,11 +38,6 @@ void btrfs_init_map_token(struct btrfs_map_token *token, struct extent_buffer *e
4138
* - btrfs_set_8 (for 8/16/32/64)
4239
* - btrfs_get_8 (for 8/16/32/64)
4340
*
44-
* Generic helpers with a token (cached address of the most recently accessed
45-
* page):
46-
* - btrfs_set_token_8 (for 8/16/32/64)
47-
* - btrfs_get_token_8 (for 8/16/32/64)
48-
*
4941
* The set/get functions handle data spanning two pages transparently, in case
5042
* metadata block size is larger than page. Every pointer to metadata items is
5143
* an offset into the extent buffer page array, cast to a specific type. This
@@ -57,118 +49,66 @@ void btrfs_init_map_token(struct btrfs_map_token *token, struct extent_buffer *e
5749
*/
5850

5951
#define DEFINE_BTRFS_SETGET_BITS(bits) \
60-
u##bits btrfs_get_token_##bits(struct btrfs_map_token *token, \
61-
const void *ptr, unsigned long off) \
62-
{ \
63-
const unsigned long member_offset = (unsigned long)ptr + off; \
64-
const unsigned long idx = get_eb_folio_index(token->eb, member_offset); \
65-
const unsigned long oil = get_eb_offset_in_folio(token->eb, \
66-
member_offset);\
67-
const int unit_size = token->eb->folio_size; \
68-
const int unit_shift = token->eb->folio_shift; \
69-
const int size = sizeof(u##bits); \
70-
u8 lebytes[sizeof(u##bits)]; \
71-
const int part = unit_size - oil; \
72-
\
73-
ASSERT(token); \
74-
ASSERT(token->kaddr); \
75-
ASSERT(check_setget_bounds(token->eb, ptr, off, size)); \
76-
if (token->offset <= member_offset && \
77-
member_offset + size <= token->offset + unit_size) { \
78-
return get_unaligned_le##bits(token->kaddr + oil); \
79-
} \
80-
token->kaddr = folio_address(token->eb->folios[idx]); \
81-
token->offset = idx << unit_shift; \
82-
if (INLINE_EXTENT_BUFFER_PAGES == 1 || oil + size <= unit_size) \
83-
return get_unaligned_le##bits(token->kaddr + oil); \
84-
\
85-
memcpy(lebytes, token->kaddr + oil, part); \
86-
token->kaddr = folio_address(token->eb->folios[idx + 1]); \
87-
token->offset = (idx + 1) << unit_shift; \
88-
memcpy(lebytes + part, token->kaddr, size - part); \
89-
return get_unaligned_le##bits(lebytes); \
90-
} \
9152
u##bits btrfs_get_##bits(const struct extent_buffer *eb, \
9253
const void *ptr, unsigned long off) \
9354
{ \
9455
const unsigned long member_offset = (unsigned long)ptr + off; \
9556
const unsigned long idx = get_eb_folio_index(eb, member_offset);\
96-
const unsigned long oil = get_eb_offset_in_folio(eb, \
97-
member_offset);\
98-
const int unit_size = eb->folio_size; \
99-
char *kaddr = folio_address(eb->folios[idx]); \
100-
const int size = sizeof(u##bits); \
101-
const int part = unit_size - oil; \
102-
u8 lebytes[sizeof(u##bits)]; \
103-
\
104-
ASSERT(check_setget_bounds(eb, ptr, off, size)); \
105-
if (INLINE_EXTENT_BUFFER_PAGES == 1 || oil + size <= unit_size) \
106-
return get_unaligned_le##bits(kaddr + oil); \
107-
\
108-
memcpy(lebytes, kaddr + oil, part); \
109-
kaddr = folio_address(eb->folios[idx + 1]); \
110-
memcpy(lebytes + part, kaddr, size - part); \
111-
return get_unaligned_le##bits(lebytes); \
112-
} \
113-
void btrfs_set_token_##bits(struct btrfs_map_token *token, \
114-
const void *ptr, unsigned long off, \
115-
u##bits val) \
116-
{ \
117-
const unsigned long member_offset = (unsigned long)ptr + off; \
118-
const unsigned long idx = get_eb_folio_index(token->eb, member_offset); \
119-
const unsigned long oil = get_eb_offset_in_folio(token->eb, \
57+
const unsigned long oif = get_eb_offset_in_folio(eb, \
12058
member_offset);\
121-
const int unit_size = token->eb->folio_size; \
122-
const int unit_shift = token->eb->folio_shift; \
123-
const int size = sizeof(u##bits); \
59+
char *kaddr = folio_address(eb->folios[idx]) + oif; \
60+
const int part = eb->folio_size - oif; \
12461
u8 lebytes[sizeof(u##bits)]; \
125-
const int part = unit_size - oil; \
12662
\
127-
ASSERT(token); \
128-
ASSERT(token->kaddr); \
129-
ASSERT(check_setget_bounds(token->eb, ptr, off, size)); \
130-
if (token->offset <= member_offset && \
131-
member_offset + size <= token->offset + unit_size) { \
132-
put_unaligned_le##bits(val, token->kaddr + oil); \
133-
return; \
63+
if (unlikely(member_offset + sizeof(u##bits) > eb->len)) { \
64+
report_setget_bounds(eb, ptr, off, sizeof(u##bits)); \
65+
return 0; \
13466
} \
135-
token->kaddr = folio_address(token->eb->folios[idx]); \
136-
token->offset = idx << unit_shift; \
137-
if (INLINE_EXTENT_BUFFER_PAGES == 1 || \
138-
oil + size <= unit_size) { \
139-
put_unaligned_le##bits(val, token->kaddr + oil); \
140-
return; \
67+
if (INLINE_EXTENT_BUFFER_PAGES == 1 || sizeof(u##bits) == 1 || \
68+
likely(sizeof(u##bits) <= part)) \
69+
return get_unaligned_le##bits(kaddr); \
70+
\
71+
if (sizeof(u##bits) == 2) { \
72+
lebytes[0] = *kaddr; \
73+
kaddr = folio_address(eb->folios[idx + 1]); \
74+
lebytes[1] = *kaddr; \
75+
} else { \
76+
memcpy_split_src(lebytes, kaddr, \
77+
folio_address(eb->folios[idx + 1]), \
78+
part, sizeof(u##bits)); \
14179
} \
142-
put_unaligned_le##bits(val, lebytes); \
143-
memcpy(token->kaddr + oil, lebytes, part); \
144-
token->kaddr = folio_address(token->eb->folios[idx + 1]); \
145-
token->offset = (idx + 1) << unit_shift; \
146-
memcpy(token->kaddr, lebytes + part, size - part); \
80+
return get_unaligned_le##bits(lebytes); \
14781
} \
14882
void btrfs_set_##bits(const struct extent_buffer *eb, void *ptr, \
14983
unsigned long off, u##bits val) \
15084
{ \
15185
const unsigned long member_offset = (unsigned long)ptr + off; \
15286
const unsigned long idx = get_eb_folio_index(eb, member_offset);\
153-
const unsigned long oil = get_eb_offset_in_folio(eb, \
87+
const unsigned long oif = get_eb_offset_in_folio(eb, \
15488
member_offset);\
155-
const int unit_size = eb->folio_size; \
156-
char *kaddr = folio_address(eb->folios[idx]); \
157-
const int size = sizeof(u##bits); \
158-
const int part = unit_size - oil; \
89+
char *kaddr = folio_address(eb->folios[idx]) + oif; \
90+
const int part = eb->folio_size - oif; \
15991
u8 lebytes[sizeof(u##bits)]; \
16092
\
161-
ASSERT(check_setget_bounds(eb, ptr, off, size)); \
162-
if (INLINE_EXTENT_BUFFER_PAGES == 1 || \
163-
oil + size <= unit_size) { \
164-
put_unaligned_le##bits(val, kaddr + oil); \
93+
if (unlikely(member_offset + sizeof(u##bits) > eb->len)) { \
94+
report_setget_bounds(eb, ptr, off, sizeof(u##bits)); \
95+
return; \
96+
} \
97+
if (INLINE_EXTENT_BUFFER_PAGES == 1 || sizeof(u##bits) == 1 || \
98+
likely(sizeof(u##bits) <= part)) { \
99+
put_unaligned_le##bits(val, kaddr); \
165100
return; \
166101
} \
167-
\
168102
put_unaligned_le##bits(val, lebytes); \
169-
memcpy(kaddr + oil, lebytes, part); \
170-
kaddr = folio_address(eb->folios[idx + 1]); \
171-
memcpy(kaddr, lebytes + part, size - part); \
103+
if (sizeof(u##bits) == 2) { \
104+
*kaddr = lebytes[0]; \
105+
kaddr = folio_address(eb->folios[idx + 1]); \
106+
*kaddr = lebytes[1]; \
107+
} else { \
108+
memcpy(kaddr, lebytes, part); \
109+
kaddr = folio_address(eb->folios[idx + 1]); \
110+
memcpy(kaddr, lebytes + part, sizeof(u##bits) - part); \
111+
} \
172112
}
173113

174114
DEFINE_BTRFS_SETGET_BITS(8)

fs/btrfs/accessors.h

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,6 @@
1616

1717
struct extent_buffer;
1818

19-
struct btrfs_map_token {
20-
struct extent_buffer *eb;
21-
char *kaddr;
22-
unsigned long offset;
23-
};
24-
25-
void btrfs_init_map_token(struct btrfs_map_token *token, struct extent_buffer *eb);
26-
2719
/*
2820
* Some macros to generate set/get functions for the struct fields. This
2921
* assumes there is a lefoo_to_cpu for every type, so lets make a simple one
@@ -56,11 +48,6 @@ static inline void put_unaligned_le8(u8 val, void *p)
5648
sizeof_field(type, member)))
5749

5850
#define DECLARE_BTRFS_SETGET_BITS(bits) \
59-
u##bits btrfs_get_token_##bits(struct btrfs_map_token *token, \
60-
const void *ptr, unsigned long off); \
61-
void btrfs_set_token_##bits(struct btrfs_map_token *token, \
62-
const void *ptr, unsigned long off, \
63-
u##bits val); \
6451
u##bits btrfs_get_##bits(const struct extent_buffer *eb, \
6552
const void *ptr, unsigned long off); \
6653
void btrfs_set_##bits(const struct extent_buffer *eb, void *ptr, \
@@ -83,18 +70,6 @@ static inline void btrfs_set_##name(const struct extent_buffer *eb, type *s, \
8370
{ \
8471
static_assert(sizeof(u##bits) == sizeof_field(type, member)); \
8572
btrfs_set_##bits(eb, s, offsetof(type, member), val); \
86-
} \
87-
static inline u##bits btrfs_token_##name(struct btrfs_map_token *token, \
88-
const type *s) \
89-
{ \
90-
static_assert(sizeof(u##bits) == sizeof_field(type, member)); \
91-
return btrfs_get_token_##bits(token, s, offsetof(type, member));\
92-
} \
93-
static inline void btrfs_set_token_##name(struct btrfs_map_token *token,\
94-
type *s, u##bits val) \
95-
{ \
96-
static_assert(sizeof(u##bits) == sizeof_field(type, member)); \
97-
btrfs_set_token_##bits(token, s, offsetof(type, member), val); \
9873
}
9974

10075
#define BTRFS_SETGET_HEADER_FUNCS(name, type, member, bits) \
@@ -479,18 +454,6 @@ static inline void btrfs_set_item_##member(const struct extent_buffer *eb, \
479454
int slot, u32 val) \
480455
{ \
481456
btrfs_set_raw_item_##member(eb, btrfs_item_nr(eb, slot), val); \
482-
} \
483-
static inline u32 btrfs_token_item_##member(struct btrfs_map_token *token, \
484-
int slot) \
485-
{ \
486-
struct btrfs_item *item = btrfs_item_nr(token->eb, slot); \
487-
return btrfs_token_raw_item_##member(token, item); \
488-
} \
489-
static inline void btrfs_set_token_item_##member(struct btrfs_map_token *token, \
490-
int slot, u32 val) \
491-
{ \
492-
struct btrfs_item *item = btrfs_item_nr(token->eb, slot); \
493-
btrfs_set_token_raw_item_##member(token, item, val); \
494457
}
495458

496459
BTRFS_ITEM_SETGET_FUNCS(offset)

0 commit comments

Comments
 (0)