Skip to content

Commit 040c0f6

Browse files
committed
Merge tag 'bcachefs-2025-05-22' of git://evilpiepirate.org/bcachefs
Pull bcachefs fixes from Kent Overstreet: "Small stuff, main ones users will be interested in: - Couple more casefolding fixes; we can now detect and repair casefolded dirents in non-casefolded dir and vice versa - Fix for massive write inflation with mmapped io, which hit certain databases" * tag 'bcachefs-2025-05-22' of git://evilpiepirate.org/bcachefs: bcachefs: Check for casefolded dirents in non casefolded dirs bcachefs: Fix bch2_dirent_create_snapshot() for casefolding bcachefs: Fix casefold opt via xattr interface bcachefs: mkwrite() now only dirties one page bcachefs: fix extent_has_stripe_ptr() bcachefs: Fix bch2_btree_path_traverse_cached() when paths realloced
2 parents 94305e8 + 010c894 commit 040c0f6

File tree

15 files changed

+143
-86
lines changed

15 files changed

+143
-86
lines changed

fs/bcachefs/btree_iter.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1162,7 +1162,7 @@ int bch2_btree_path_traverse_one(struct btree_trans *trans,
11621162
}
11631163

11641164
if (path->cached) {
1165-
ret = bch2_btree_path_traverse_cached(trans, path, flags);
1165+
ret = bch2_btree_path_traverse_cached(trans, path_idx, flags);
11661166
goto out;
11671167
}
11681168

fs/bcachefs/btree_key_cache.c

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -301,9 +301,11 @@ static noinline_for_stack void do_trace_key_cache_fill(struct btree_trans *trans
301301
}
302302

303303
static noinline int btree_key_cache_fill(struct btree_trans *trans,
304-
struct btree_path *ck_path,
304+
btree_path_idx_t ck_path_idx,
305305
unsigned flags)
306306
{
307+
struct btree_path *ck_path = trans->paths + ck_path_idx;
308+
307309
if (flags & BTREE_ITER_cached_nofill) {
308310
ck_path->l[0].b = NULL;
309311
return 0;
@@ -325,6 +327,7 @@ static noinline int btree_key_cache_fill(struct btree_trans *trans,
325327
goto err;
326328

327329
/* Recheck after btree lookup, before allocating: */
330+
ck_path = trans->paths + ck_path_idx;
328331
ret = bch2_btree_key_cache_find(c, ck_path->btree_id, ck_path->pos) ? -EEXIST : 0;
329332
if (unlikely(ret))
330333
goto out;
@@ -344,10 +347,11 @@ static noinline int btree_key_cache_fill(struct btree_trans *trans,
344347
}
345348

346349
static inline int btree_path_traverse_cached_fast(struct btree_trans *trans,
347-
struct btree_path *path)
350+
btree_path_idx_t path_idx)
348351
{
349352
struct bch_fs *c = trans->c;
350353
struct bkey_cached *ck;
354+
struct btree_path *path = trans->paths + path_idx;
351355
retry:
352356
ck = bch2_btree_key_cache_find(c, path->btree_id, path->pos);
353357
if (!ck)
@@ -373,27 +377,32 @@ static inline int btree_path_traverse_cached_fast(struct btree_trans *trans,
373377
return 0;
374378
}
375379

376-
int bch2_btree_path_traverse_cached(struct btree_trans *trans, struct btree_path *path,
380+
int bch2_btree_path_traverse_cached(struct btree_trans *trans,
381+
btree_path_idx_t path_idx,
377382
unsigned flags)
378383
{
379-
EBUG_ON(path->level);
380-
381-
path->l[1].b = NULL;
384+
EBUG_ON(trans->paths[path_idx].level);
382385

383386
int ret;
384387
do {
385-
ret = btree_path_traverse_cached_fast(trans, path);
388+
ret = btree_path_traverse_cached_fast(trans, path_idx);
386389
if (unlikely(ret == -ENOENT))
387-
ret = btree_key_cache_fill(trans, path, flags);
390+
ret = btree_key_cache_fill(trans, path_idx, flags);
388391
} while (ret == -EEXIST);
389392

393+
struct btree_path *path = trans->paths + path_idx;
394+
390395
if (unlikely(ret)) {
391396
path->uptodate = BTREE_ITER_NEED_TRAVERSE;
392397
if (!bch2_err_matches(ret, BCH_ERR_transaction_restart)) {
393398
btree_node_unlock(trans, path, 0);
394399
path->l[0].b = ERR_PTR(ret);
395400
}
401+
} else {
402+
BUG_ON(path->uptodate);
403+
BUG_ON(!path->nodes_locked);
396404
}
405+
397406
return ret;
398407
}
399408

fs/bcachefs/btree_key_cache.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,7 @@ int bch2_btree_key_cache_journal_flush(struct journal *,
4040
struct bkey_cached *
4141
bch2_btree_key_cache_find(struct bch_fs *, enum btree_id, struct bpos);
4242

43-
int bch2_btree_path_traverse_cached(struct btree_trans *, struct btree_path *,
44-
unsigned);
43+
int bch2_btree_path_traverse_cached(struct btree_trans *, btree_path_idx_t, unsigned);
4544

4645
bool bch2_btree_insert_key_cached(struct btree_trans *, unsigned,
4746
struct btree_insert_entry *);

fs/bcachefs/dirent.c

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -288,17 +288,27 @@ static void dirent_init_casefolded_name(struct bkey_i_dirent *dirent,
288288
}
289289

290290
static struct bkey_i_dirent *dirent_create_key(struct btree_trans *trans,
291+
const struct bch_hash_info *hash_info,
291292
subvol_inum dir,
292293
u8 type,
293294
const struct qstr *name,
294295
const struct qstr *cf_name,
295296
u64 dst)
296297
{
297298
struct bkey_i_dirent *dirent;
299+
struct qstr _cf_name;
298300

299301
if (name->len > BCH_NAME_MAX)
300302
return ERR_PTR(-ENAMETOOLONG);
301303

304+
if (hash_info->cf_encoding && !cf_name) {
305+
int ret = bch2_casefold(trans, hash_info, name, &_cf_name);
306+
if (ret)
307+
return ERR_PTR(ret);
308+
309+
cf_name = &_cf_name;
310+
}
311+
302312
dirent = dirent_alloc_key(trans, dir, type, name->len, cf_name ? cf_name->len : 0, dst);
303313
if (IS_ERR(dirent))
304314
return dirent;
@@ -324,7 +334,7 @@ int bch2_dirent_create_snapshot(struct btree_trans *trans,
324334
struct bkey_i_dirent *dirent;
325335
int ret;
326336

327-
dirent = dirent_create_key(trans, dir_inum, type, name, NULL, dst_inum);
337+
dirent = dirent_create_key(trans, hash_info, dir_inum, type, name, NULL, dst_inum);
328338
ret = PTR_ERR_OR_ZERO(dirent);
329339
if (ret)
330340
return ret;
@@ -333,8 +343,7 @@ int bch2_dirent_create_snapshot(struct btree_trans *trans,
333343
dirent->k.p.snapshot = snapshot;
334344

335345
ret = bch2_hash_set_in_snapshot(trans, bch2_dirent_hash_desc, hash_info,
336-
dir_inum, snapshot, &dirent->k_i,
337-
flags|BTREE_UPDATE_internal_snapshot_node);
346+
dir_inum, snapshot, &dirent->k_i, flags);
338347
*dir_offset = dirent->k.p.offset;
339348

340349
return ret;
@@ -344,28 +353,16 @@ int bch2_dirent_create(struct btree_trans *trans, subvol_inum dir,
344353
const struct bch_hash_info *hash_info,
345354
u8 type, const struct qstr *name, u64 dst_inum,
346355
u64 *dir_offset,
347-
u64 *i_size,
348356
enum btree_iter_update_trigger_flags flags)
349357
{
350358
struct bkey_i_dirent *dirent;
351359
int ret;
352360

353-
if (hash_info->cf_encoding) {
354-
struct qstr cf_name;
355-
ret = bch2_casefold(trans, hash_info, name, &cf_name);
356-
if (ret)
357-
return ret;
358-
dirent = dirent_create_key(trans, dir, type, name, &cf_name, dst_inum);
359-
} else {
360-
dirent = dirent_create_key(trans, dir, type, name, NULL, dst_inum);
361-
}
362-
361+
dirent = dirent_create_key(trans, hash_info, dir, type, name, NULL, dst_inum);
363362
ret = PTR_ERR_OR_ZERO(dirent);
364363
if (ret)
365364
return ret;
366365

367-
*i_size += bkey_bytes(&dirent->k);
368-
369366
ret = bch2_hash_set(trans, bch2_dirent_hash_desc, hash_info,
370367
dir, &dirent->k_i, flags);
371368
*dir_offset = dirent->k.p.offset;
@@ -466,7 +463,7 @@ int bch2_dirent_rename(struct btree_trans *trans,
466463
*src_offset = dst_iter.pos.offset;
467464

468465
/* Create new dst key: */
469-
new_dst = dirent_create_key(trans, dst_dir, 0, dst_name,
466+
new_dst = dirent_create_key(trans, dst_hash, dst_dir, 0, dst_name,
470467
dst_hash->cf_encoding ? &dst_name_lookup : NULL, 0);
471468
ret = PTR_ERR_OR_ZERO(new_dst);
472469
if (ret)
@@ -477,7 +474,7 @@ int bch2_dirent_rename(struct btree_trans *trans,
477474

478475
/* Create new src key: */
479476
if (mode == BCH_RENAME_EXCHANGE) {
480-
new_src = dirent_create_key(trans, src_dir, 0, src_name,
477+
new_src = dirent_create_key(trans, src_hash, src_dir, 0, src_name,
481478
src_hash->cf_encoding ? &src_name_lookup : NULL, 0);
482479
ret = PTR_ERR_OR_ZERO(new_src);
483480
if (ret)

fs/bcachefs/dirent.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ int bch2_dirent_create_snapshot(struct btree_trans *, u32, u64, u32,
6565
enum btree_iter_update_trigger_flags);
6666
int bch2_dirent_create(struct btree_trans *, subvol_inum,
6767
const struct bch_hash_info *, u8,
68-
const struct qstr *, u64, u64 *, u64 *,
68+
const struct qstr *, u64, u64 *,
6969
enum btree_iter_update_trigger_flags);
7070

7171
static inline unsigned vfs_d_type(unsigned type)

fs/bcachefs/ec.c

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -507,20 +507,14 @@ static const struct bch_extent_ptr *bkey_matches_stripe(struct bch_stripe *s,
507507

508508
static bool extent_has_stripe_ptr(struct bkey_s_c k, u64 idx)
509509
{
510-
switch (k.k->type) {
511-
case KEY_TYPE_extent: {
512-
struct bkey_s_c_extent e = bkey_s_c_to_extent(k);
513-
const union bch_extent_entry *entry;
514-
515-
extent_for_each_entry(e, entry)
516-
if (extent_entry_type(entry) ==
517-
BCH_EXTENT_ENTRY_stripe_ptr &&
518-
entry->stripe_ptr.idx == idx)
519-
return true;
510+
struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(k);
511+
const union bch_extent_entry *entry;
520512

521-
break;
522-
}
523-
}
513+
bkey_extent_entry_for_each(ptrs, entry)
514+
if (extent_entry_type(entry) ==
515+
BCH_EXTENT_ENTRY_stripe_ptr &&
516+
entry->stripe_ptr.idx == idx)
517+
return true;
524518

525519
return false;
526520
}

fs/bcachefs/extents.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -380,13 +380,6 @@ out: \
380380

381381
/* Iterate over pointers in KEY_TYPE_extent: */
382382

383-
#define extent_for_each_entry_from(_e, _entry, _start) \
384-
__bkey_extent_entry_for_each_from(_start, \
385-
extent_entry_last(_e), _entry)
386-
387-
#define extent_for_each_entry(_e, _entry) \
388-
extent_for_each_entry_from(_e, _entry, (_e).v->start)
389-
390383
#define extent_ptr_next(_e, _ptr) \
391384
__bkey_ptr_next(_ptr, extent_entry_last(_e))
392385

fs/bcachefs/fs-io-pagecache.c

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -605,10 +605,14 @@ vm_fault_t bch2_page_mkwrite(struct vm_fault *vmf)
605605
struct address_space *mapping = file->f_mapping;
606606
struct bch_fs *c = inode->v.i_sb->s_fs_info;
607607
struct bch2_folio_reservation res;
608-
unsigned len;
609-
loff_t isize;
610608
vm_fault_t ret;
611609

610+
loff_t file_offset = round_down(vmf->pgoff << PAGE_SHIFT, block_bytes(c));
611+
unsigned offset = file_offset - folio_pos(folio);
612+
unsigned len = max(PAGE_SIZE, block_bytes(c));
613+
614+
BUG_ON(offset + len > folio_size(folio));
615+
612616
bch2_folio_reservation_init(c, inode, &res);
613617

614618
sb_start_pagefault(inode->v.i_sb);
@@ -623,24 +627,24 @@ vm_fault_t bch2_page_mkwrite(struct vm_fault *vmf)
623627
bch2_pagecache_add_get(inode);
624628

625629
folio_lock(folio);
626-
isize = i_size_read(&inode->v);
630+
u64 isize = i_size_read(&inode->v);
627631

628-
if (folio->mapping != mapping || folio_pos(folio) >= isize) {
632+
if (folio->mapping != mapping || file_offset >= isize) {
629633
folio_unlock(folio);
630634
ret = VM_FAULT_NOPAGE;
631635
goto out;
632636
}
633637

634-
len = min_t(loff_t, folio_size(folio), isize - folio_pos(folio));
638+
len = min_t(unsigned, len, isize - file_offset);
635639

636640
if (bch2_folio_set(c, inode_inum(inode), &folio, 1) ?:
637-
bch2_folio_reservation_get(c, inode, folio, &res, 0, len)) {
641+
bch2_folio_reservation_get(c, inode, folio, &res, offset, len)) {
638642
folio_unlock(folio);
639643
ret = VM_FAULT_SIGBUS;
640644
goto out;
641645
}
642646

643-
bch2_set_folio_dirty(c, inode, folio, &res, 0, len);
647+
bch2_set_folio_dirty(c, inode, folio, &res, offset, len);
644648
bch2_folio_reservation_put(c, inode, &res);
645649

646650
folio_wait_stable(folio);

fs/bcachefs/fs.c

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1664,33 +1664,9 @@ static int fssetxattr_inode_update_fn(struct btree_trans *trans,
16641664
return -EINVAL;
16651665

16661666
if (s->casefold != bch2_inode_casefold(c, bi)) {
1667-
#ifdef CONFIG_UNICODE
1668-
int ret = 0;
1669-
/* Not supported on individual files. */
1670-
if (!S_ISDIR(bi->bi_mode))
1671-
return -EOPNOTSUPP;
1672-
1673-
/*
1674-
* Make sure the dir is empty, as otherwise we'd need to
1675-
* rehash everything and update the dirent keys.
1676-
*/
1677-
ret = bch2_empty_dir_trans(trans, inode_inum(inode));
1678-
if (ret < 0)
1679-
return ret;
1680-
1681-
ret = bch2_request_incompat_feature(c, bcachefs_metadata_version_casefolding);
1667+
int ret = bch2_inode_set_casefold(trans, inode_inum(inode), bi, s->casefold);
16821668
if (ret)
16831669
return ret;
1684-
1685-
bch2_check_set_feature(c, BCH_FEATURE_casefolding);
1686-
1687-
bi->bi_casefold = s->casefold + 1;
1688-
bi->bi_fields_set |= BIT(Inode_opt_casefold);
1689-
1690-
#else
1691-
printk(KERN_ERR "Cannot use casefolding on a kernel without CONFIG_UNICODE\n");
1692-
return -EOPNOTSUPP;
1693-
#endif
16941670
}
16951671

16961672
if (s->set_project) {

fs/bcachefs/fsck.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,7 @@ static int lookup_lostfound(struct btree_trans *trans, u32 snapshot,
306306
&lostfound_str,
307307
lostfound->bi_inum,
308308
&lostfound->bi_dir_offset,
309+
BTREE_UPDATE_internal_snapshot_node|
309310
STR_HASH_must_create) ?:
310311
bch2_inode_write_flags(trans, &lostfound_iter, lostfound,
311312
BTREE_UPDATE_internal_snapshot_node);
@@ -431,6 +432,7 @@ static int reattach_inode(struct btree_trans *trans, struct bch_inode_unpacked *
431432
&name,
432433
inode->bi_subvol ?: inode->bi_inum,
433434
&inode->bi_dir_offset,
435+
BTREE_UPDATE_internal_snapshot_node|
434436
STR_HASH_must_create);
435437
if (ret) {
436438
bch_err_msg(c, ret, "error creating dirent");
@@ -2188,6 +2190,41 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter,
21882190

21892191
struct bkey_s_c_dirent d = bkey_s_c_to_dirent(k);
21902192

2193+
/* check casefold */
2194+
if (fsck_err_on(d.v->d_casefold != !!hash_info->cf_encoding,
2195+
trans, dirent_casefold_mismatch,
2196+
"dirent casefold does not match dir casefold\n%s",
2197+
(printbuf_reset(&buf),
2198+
bch2_bkey_val_to_text(&buf, c, k),
2199+
buf.buf))) {
2200+
struct qstr name = bch2_dirent_get_name(d);
2201+
u32 subvol = d.v->d_type == DT_SUBVOL
2202+
? d.v->d_parent_subvol
2203+
: 0;
2204+
u64 target = d.v->d_type == DT_SUBVOL
2205+
? d.v->d_child_subvol
2206+
: d.v->d_inum;
2207+
u64 dir_offset;
2208+
2209+
ret = bch2_hash_delete_at(trans,
2210+
bch2_dirent_hash_desc, hash_info, iter,
2211+
BTREE_UPDATE_internal_snapshot_node) ?:
2212+
bch2_dirent_create_snapshot(trans, subvol,
2213+
d.k->p.inode, d.k->p.snapshot,
2214+
hash_info,
2215+
d.v->d_type,
2216+
&name,
2217+
target,
2218+
&dir_offset,
2219+
BTREE_ITER_with_updates|
2220+
BTREE_UPDATE_internal_snapshot_node|
2221+
STR_HASH_must_create) ?:
2222+
bch2_trans_commit(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc);
2223+
2224+
/* might need another check_dirents pass */
2225+
goto out;
2226+
}
2227+
21912228
if (d.v->d_type == DT_SUBVOL) {
21922229
ret = check_dirent_to_subvol(trans, iter, d);
21932230
if (ret)

0 commit comments

Comments
 (0)