Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

bcachefs: switch to rhashtable for vfs inodes hash

the standard vfs inode hash table suffers from painful lock contention -
this is long overdue

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>

+160 -89
+1 -1
fs/bcachefs/acl.c
··· 361 361 bch2_trans_begin(trans); 362 362 acl = _acl; 363 363 364 - ret = bch2_subvol_is_ro_trans(trans, inode->ei_subvol) ?: 364 + ret = bch2_subvol_is_ro_trans(trans, inode->ei_inum.subvol) ?: 365 365 bch2_inode_peek(trans, &inode_iter, &inode_u, inode_inum(inode), 366 366 BTREE_ITER_intent); 367 367 if (ret)
+1
fs/bcachefs/bcachefs.h
··· 1023 1023 /* fs.c */ 1024 1024 struct list_head vfs_inodes_list; 1025 1025 struct mutex vfs_inodes_lock; 1026 + struct rhashtable vfs_inodes_table; 1026 1027 1027 1028 /* VFS IO PATH - fs-io.c */ 1028 1029 struct bio_set writepage_bioset;
+1 -1
fs/bcachefs/fs-io-buffered.c
··· 486 486 op->nr_replicas = nr_replicas; 487 487 op->res.nr_replicas = nr_replicas; 488 488 op->write_point = writepoint_hashed(inode->ei_last_dirtied); 489 - op->subvol = inode->ei_subvol; 489 + op->subvol = inode->ei_inum.subvol; 490 490 op->pos = POS(inode->v.i_ino, sector); 491 491 op->end_io = bch2_writepage_io_done; 492 492 op->devs_need_flush = &inode->ei_devs_need_flush;
+1 -1
fs/bcachefs/fs-io-direct.c
··· 500 500 dio->op.target = dio->op.opts.foreground_target; 501 501 dio->op.write_point = writepoint_hashed((unsigned long) current); 502 502 dio->op.nr_replicas = dio->op.opts.data_replicas; 503 - dio->op.subvol = inode->ei_subvol; 503 + dio->op.subvol = inode->ei_inum.subvol; 504 504 dio->op.pos = POS(inode->v.i_ino, (u64) req->ki_pos >> 9); 505 505 dio->op.devs_need_flush = &inode->ei_devs_need_flush; 506 506
+3 -3
fs/bcachefs/fs-io.c
··· 267 267 * XXX: we're doing two index lookups when we end up reading the 268 268 * folio 269 269 */ 270 - ret = range_has_data(c, inode->ei_subvol, 270 + ret = range_has_data(c, inode->ei_inum.subvol, 271 271 POS(inode->v.i_ino, (index << PAGE_SECTORS_SHIFT)), 272 272 POS(inode->v.i_ino, (index << PAGE_SECTORS_SHIFT) + PAGE_SECTORS)); 273 273 if (ret <= 0) ··· 618 618 bch2_trans_begin(trans); 619 619 620 620 ret = bch2_subvolume_get_snapshot(trans, 621 - inode->ei_subvol, &snapshot); 621 + inode->ei_inum.subvol, &snapshot); 622 622 if (ret) 623 623 goto bkey_err; 624 624 ··· 823 823 retry: 824 824 bch2_trans_begin(trans); 825 825 826 - ret = bch2_subvolume_get_snapshot(trans, inode->ei_subvol, &snapshot); 826 + ret = bch2_subvolume_get_snapshot(trans, inode->ei_inum.subvol, &snapshot); 827 827 if (ret) 828 828 goto err; 829 829
+2 -2
fs/bcachefs/fs-ioctl.c
··· 100 100 } 101 101 102 102 mutex_lock(&inode->ei_update_lock); 103 - ret = bch2_subvol_is_ro(c, inode->ei_subvol) ?: 103 + ret = bch2_subvol_is_ro(c, inode->ei_inum.subvol) ?: 104 104 bch2_write_inode(c, inode, bch2_inode_flags_set, &s, 105 105 ATTR_CTIME); 106 106 mutex_unlock(&inode->ei_update_lock); ··· 184 184 } 185 185 186 186 mutex_lock(&inode->ei_update_lock); 187 - ret = bch2_subvol_is_ro(c, inode->ei_subvol) ?: 187 + ret = bch2_subvol_is_ro(c, inode->ei_inum.subvol) ?: 188 188 bch2_set_projid(c, inode, fa.fsx_projid) ?: 189 189 bch2_write_inode(c, inode, fssetxattr_inode_update_fn, &s, 190 190 ATTR_CTIME);
+133 -72
fs/bcachefs/fs.c
··· 108 108 goto retry; 109 109 110 110 bch2_fs_fatal_err_on(bch2_err_matches(ret, ENOENT), c, 111 - "%s: inode %u:%llu not found when updating", 111 + "%s: inode %llu:%llu not found when updating", 112 112 bch2_err_str(ret), 113 113 inode_inum(inode).subvol, 114 114 inode_inum(inode).inum); ··· 152 152 return ret; 153 153 } 154 154 155 - static int bch2_iget5_test(struct inode *vinode, void *p) 155 + static bool subvol_inum_eq(subvol_inum a, subvol_inum b) 156 156 { 157 - struct bch_inode_info *inode = to_bch_ei(vinode); 158 - subvol_inum *inum = p; 159 - 160 - return inode->ei_subvol == inum->subvol && 161 - inode->ei_inode.bi_inum == inum->inum; 157 + return a.subvol == b.subvol && a.inum == b.inum; 162 158 } 163 159 164 - static int bch2_iget5_set(struct inode *vinode, void *p) 160 + static int bch2_vfs_inode_cmp_fn(struct rhashtable_compare_arg *arg, 161 + const void *obj) 165 162 { 166 - struct bch_inode_info *inode = to_bch_ei(vinode); 167 - subvol_inum *inum = p; 163 + const struct bch_inode_info *inode = obj; 164 + const subvol_inum *v = arg->key; 168 165 169 - inode->v.i_ino = inum->inum; 170 - inode->ei_subvol = inum->subvol; 171 - inode->ei_inode.bi_inum = inum->inum; 172 - return 0; 166 + return !subvol_inum_eq(inode->ei_inum, *v); 173 167 } 174 168 175 - static unsigned bch2_inode_hash(subvol_inum inum) 169 + static const struct rhashtable_params bch2_vfs_inodes_params = { 170 + .head_offset = offsetof(struct bch_inode_info, hash), 171 + .key_offset = offsetof(struct bch_inode_info, ei_inum), 172 + .key_len = sizeof(subvol_inum), 173 + .obj_cmpfn = bch2_vfs_inode_cmp_fn, 174 + .automatic_shrinking = true, 175 + }; 176 + 177 + static void __wait_on_freeing_inode(struct inode *inode) 176 178 { 177 - return jhash_3words(inum.subvol, inum.inum >> 32, inum.inum, JHASH_INITVAL); 179 + wait_queue_head_t *wq; 180 + DEFINE_WAIT_BIT(wait, &inode->i_state, __I_NEW); 181 + wq = bit_waitqueue(&inode->i_state, __I_NEW); 182 + prepare_to_wait(wq, &wait.wq_entry, TASK_UNINTERRUPTIBLE); 183 + spin_unlock(&inode->i_lock); 184 + schedule(); 185 + finish_wait(wq, &wait.wq_entry); 178 186 } 179 187 180 188 struct bch_inode_info *__bch2_inode_hash_find(struct bch_fs *c, subvol_inum inum) 181 189 { 182 - return to_bch_ei(ilookup5_nowait(c->vfs_sb, 183 - bch2_inode_hash(inum), 184 - bch2_iget5_test, 185 - &inum)); 190 + return rhashtable_lookup_fast(&c->vfs_inodes_table, &inum, bch2_vfs_inodes_params); 186 191 } 187 192 188 - static struct bch_inode_info *bch2_inode_insert(struct bch_fs *c, struct bch_inode_info *inode) 193 + static struct bch_inode_info *bch2_inode_hash_find(struct bch_fs *c, subvol_inum inum) 189 194 { 190 - subvol_inum inum = inode_inum(inode); 191 - struct bch_inode_info *old = to_bch_ei(inode_insert5(&inode->v, 192 - bch2_inode_hash(inum), 193 - bch2_iget5_test, 194 - bch2_iget5_set, 195 - &inum)); 196 - BUG_ON(!old); 195 + struct bch_inode_info *inode; 196 + repeat: 197 + inode = __bch2_inode_hash_find(c, inum); 198 + if (inode) { 199 + spin_lock(&inode->v.i_lock); 200 + if (!test_bit(EI_INODE_HASHED, &inode->ei_flags)) { 201 + spin_unlock(&inode->v.i_lock); 202 + return NULL; 203 + } 204 + if ((inode->v.i_state & (I_FREEING|I_WILL_FREE))) { 205 + __wait_on_freeing_inode(&inode->v); 206 + goto repeat; 207 + } 208 + __iget(&inode->v); 209 + spin_unlock(&inode->v.i_lock); 210 + } 197 211 198 - if (unlikely(old != inode)) { 212 + return inode; 213 + } 214 + 215 + static void bch2_inode_hash_remove(struct bch_fs *c, struct bch_inode_info *inode) 216 + { 217 + spin_lock(&inode->v.i_lock); 218 + bool remove = test_and_clear_bit(EI_INODE_HASHED, &inode->ei_flags); 219 + spin_unlock(&inode->v.i_lock); 220 + 221 + if (remove) { 222 + int ret = rhashtable_remove_fast(&c->vfs_inodes_table, 223 + &inode->hash, bch2_vfs_inodes_params); 224 + BUG_ON(ret); 225 + inode->v.i_hash.pprev = NULL; 226 + } 227 + } 228 + 229 + static struct bch_inode_info *bch2_inode_hash_insert(struct bch_fs *c, struct bch_inode_info *inode) 230 + { 231 + struct bch_inode_info *old = inode; 232 + 233 + set_bit(EI_INODE_HASHED, &inode->ei_flags); 234 + retry: 235 + if (unlikely(rhashtable_lookup_insert_fast(&c->vfs_inodes_table, 236 + &inode->hash, 237 + bch2_vfs_inodes_params))) { 238 + old = bch2_inode_hash_find(c, inode->ei_inum); 239 + if (!old) 240 + goto retry; 241 + 242 + clear_bit(EI_INODE_HASHED, &inode->ei_flags); 243 + 199 244 /* 200 245 * bcachefs doesn't use I_NEW; we have no use for it since we 201 246 * only insert fully created inodes in the inode hash table. But ··· 256 211 discard_new_inode(&inode->v); 257 212 inode = old; 258 213 } else { 214 + inode_fake_hash(&inode->v); 215 + 216 + inode_sb_list_add(&inode->v); 217 + 259 218 mutex_lock(&c->vfs_inodes_lock); 260 219 list_add(&inode->ei_vfs_inode_list, &c->vfs_inodes_list); 261 220 mutex_unlock(&c->vfs_inodes_lock); 262 - /* 263 - * Again, I_NEW makes no sense for bcachefs. This is only needed 264 - * for clearing I_NEW, but since the inode was already fully 265 - * created and initialized we didn't actually want 266 - * inode_insert5() to set it for us. 267 - */ 268 - unlock_new_inode(&inode->v); 269 221 } 270 222 271 223 return inode; ··· 327 285 328 286 struct inode *bch2_vfs_inode_get(struct bch_fs *c, subvol_inum inum) 329 287 { 330 - struct bch_inode_info *inode = 331 - to_bch_ei(ilookup5_nowait(c->vfs_sb, 332 - bch2_inode_hash(inum), 333 - bch2_iget5_test, 334 - &inum)); 288 + struct bch_inode_info *inode = bch2_inode_hash_find(c, inum); 335 289 if (inode) 336 290 return &inode->v; 337 291 ··· 341 303 PTR_ERR_OR_ZERO(inode = bch2_new_inode(trans)); 342 304 if (!ret) { 343 305 bch2_vfs_inode_init(trans, inum, inode, &inode_u, &subvol); 344 - inode = bch2_inode_insert(c, inode); 306 + inode = bch2_inode_hash_insert(c, inode); 345 307 } 346 308 bch2_trans_put(trans); 347 309 ··· 389 351 retry: 390 352 bch2_trans_begin(trans); 391 353 392 - ret = bch2_subvol_is_ro_trans(trans, dir->ei_subvol) ?: 354 + ret = bch2_subvol_is_ro_trans(trans, dir->ei_inum.subvol) ?: 393 355 bch2_create_trans(trans, 394 356 inode_inum(dir), &dir_u, &inode_u, 395 357 !(flags & BCH_CREATE_TMPFILE) ··· 403 365 if (unlikely(ret)) 404 366 goto err_before_quota; 405 367 406 - inum.subvol = inode_u.bi_subvol ?: dir->ei_subvol; 368 + inum.subvol = inode_u.bi_subvol ?: dir->ei_inum.subvol; 407 369 inum.inum = inode_u.bi_inum; 408 370 409 371 ret = bch2_subvolume_get(trans, inum.subvol, true, ··· 434 396 * bch2_trans_exit() and dropping locks, else we could race with another 435 397 * thread pulling the inode in and modifying it: 436 398 */ 437 - inode = bch2_inode_insert(c, inode); 399 + inode = bch2_inode_hash_insert(c, inode); 438 400 bch2_trans_put(trans); 439 401 err: 440 402 posix_acl_release(default_acl); ··· 474 436 if (ret) 475 437 goto err; 476 438 477 - struct bch_inode_info *inode = 478 - to_bch_ei(ilookup5_nowait(c->vfs_sb, 479 - bch2_inode_hash(inum), 480 - bch2_iget5_test, 481 - &inum)); 439 + struct bch_inode_info *inode = bch2_inode_hash_find(c, inum); 482 440 if (inode) 483 441 goto out; 484 442 ··· 504 470 } 505 471 506 472 bch2_vfs_inode_init(trans, inum, inode, &inode_u, &subvol); 507 - inode = bch2_inode_insert(c, inode); 473 + inode = bch2_inode_hash_insert(c, inode); 508 474 out: 509 475 bch2_trans_iter_exit(trans, &dirent_iter); 510 476 printbuf_exit(&buf); ··· 591 557 592 558 lockdep_assert_held(&inode->v.i_rwsem); 593 559 594 - ret = bch2_subvol_is_ro(c, dir->ei_subvol) ?: 595 - bch2_subvol_is_ro(c, inode->ei_subvol) ?: 560 + ret = bch2_subvol_is_ro(c, dir->ei_inum.subvol) ?: 561 + bch2_subvol_is_ro(c, inode->ei_inum.subvol) ?: 596 562 __bch2_link(c, inode, dir, dentry); 597 563 if (unlikely(ret)) 598 564 return bch2_err_class(ret); ··· 648 614 struct bch_inode_info *dir= to_bch_ei(vdir); 649 615 struct bch_fs *c = dir->v.i_sb->s_fs_info; 650 616 651 - int ret = bch2_subvol_is_ro(c, dir->ei_subvol) ?: 617 + int ret = bch2_subvol_is_ro(c, dir->ei_inum.subvol) ?: 652 618 __bch2_unlink(vdir, dentry, false); 653 619 return bch2_err_class(ret); 654 620 } ··· 731 697 732 698 trans = bch2_trans_get(c); 733 699 734 - ret = bch2_subvol_is_ro_trans(trans, src_dir->ei_subvol) ?: 735 - bch2_subvol_is_ro_trans(trans, dst_dir->ei_subvol); 700 + ret = bch2_subvol_is_ro_trans(trans, src_dir->ei_inum.subvol) ?: 701 + bch2_subvol_is_ro_trans(trans, dst_dir->ei_inum.subvol); 736 702 if (ret) 737 703 goto err; 738 704 ··· 933 899 stat->blksize = block_bytes(c); 934 900 stat->blocks = inode->v.i_blocks; 935 901 936 - stat->subvol = inode->ei_subvol; 902 + stat->subvol = inode->ei_inum.subvol; 937 903 stat->result_mask |= STATX_SUBVOL; 938 904 939 905 if ((request_mask & STATX_DIOALIGN) && S_ISREG(inode->v.i_mode)) { ··· 975 941 976 942 lockdep_assert_held(&inode->v.i_rwsem); 977 943 978 - ret = bch2_subvol_is_ro(c, inode->ei_subvol) ?: 944 + ret = bch2_subvol_is_ro(c, inode->ei_inum.subvol) ?: 979 945 setattr_prepare(idmap, dentry, iattr); 980 946 if (ret) 981 947 return ret; ··· 1087 1053 retry: 1088 1054 bch2_trans_begin(trans); 1089 1055 1090 - ret = bch2_subvolume_get_snapshot(trans, ei->ei_subvol, &snapshot); 1056 + ret = bch2_subvolume_get_snapshot(trans, ei->ei_inum.subvol, &snapshot); 1091 1057 if (ret) 1092 1058 goto err; 1093 1059 ··· 1207 1173 struct bch_inode_info *inode = to_bch_ei(vinode); 1208 1174 struct bch_fs *c = inode->v.i_sb->s_fs_info; 1209 1175 1210 - int ret = bch2_subvol_is_ro(c, inode->ei_subvol); 1176 + int ret = bch2_subvol_is_ro(c, inode->ei_inum.subvol); 1211 1177 if (ret) 1212 1178 return ret; 1213 1179 } ··· 1339 1305 static struct bcachefs_fid bch2_inode_to_fid(struct bch_inode_info *inode) 1340 1306 { 1341 1307 return (struct bcachefs_fid) { 1342 - .inum = inode->ei_inode.bi_inum, 1343 - .subvol = inode->ei_subvol, 1308 + .inum = inode->ei_inum.inum, 1309 + .subvol = inode->ei_inum.subvol, 1344 1310 .gen = inode->ei_inode.bi_generation, 1345 1311 }; 1346 1312 } ··· 1425 1391 struct bch_fs *c = inode->v.i_sb->s_fs_info; 1426 1392 subvol_inum parent_inum = { 1427 1393 .subvol = inode->ei_inode.bi_parent_subvol ?: 1428 - inode->ei_subvol, 1394 + inode->ei_inum.subvol, 1429 1395 .inum = inode->ei_inode.bi_dir, 1430 1396 }; 1431 1397 ··· 1461 1427 retry: 1462 1428 bch2_trans_begin(trans); 1463 1429 1464 - ret = bch2_subvolume_get_snapshot(trans, dir->ei_subvol, &snapshot); 1430 + ret = bch2_subvolume_get_snapshot(trans, dir->ei_inum.subvol, &snapshot); 1465 1431 if (ret) 1466 1432 goto err; 1467 1433 ··· 1492 1458 if (ret) 1493 1459 goto err; 1494 1460 1495 - if (target.subvol == inode->ei_subvol && 1496 - target.inum == inode->ei_inode.bi_inum) 1461 + if (subvol_inum_eq(target, inode->ei_inum)) 1497 1462 goto found; 1498 1463 } else { 1499 1464 /* ··· 1513 1480 if (ret) 1514 1481 continue; 1515 1482 1516 - if (target.subvol == inode->ei_subvol && 1517 - target.inum == inode->ei_inode.bi_inum) 1483 + if (subvol_inum_eq(target, inode->ei_inum)) 1518 1484 goto found; 1519 1485 } 1520 1486 } ··· 1550 1518 struct bch_inode_unpacked *bi, 1551 1519 struct bch_subvolume *subvol) 1552 1520 { 1553 - bch2_iget5_set(&inode->v, &inum); 1521 + inode->v.i_ino = inum.inum; 1522 + inode->ei_inum = inum; 1523 + inode->ei_inode.bi_inum = inum.inum; 1554 1524 bch2_inode_update_after_write(trans, inode, bi, ~0); 1555 1525 1556 1526 inode->v.i_blocks = bi->bi_sectors; ··· 1564 1530 inode->ei_flags = 0; 1565 1531 inode->ei_quota_reserved = 0; 1566 1532 inode->ei_qid = bch_qid(bi); 1567 - inode->ei_subvol = inum.subvol; 1568 1533 1569 1534 if (BCH_SUBVOLUME_SNAP(subvol)) 1570 1535 set_bit(EI_INODE_SNAPSHOT, &inode->ei_flags); ··· 1630 1597 { 1631 1598 struct bch_fs *c = vinode->i_sb->s_fs_info; 1632 1599 struct bch_inode_info *inode = to_bch_ei(vinode); 1600 + bool delete = !inode->v.i_nlink && !is_bad_inode(&inode->v); 1601 + 1602 + /* 1603 + * evict() has waited for outstanding writeback, we'll do no more IO 1604 + * through this inode: it's safe to remove from VFS inode hashtable here 1605 + * 1606 + * Do that now so that other threads aren't blocked from pulling it back 1607 + * in, there's no reason for them to be: 1608 + */ 1609 + if (!delete) 1610 + bch2_inode_hash_remove(c, inode); 1633 1611 1634 1612 truncate_inode_pages_final(&inode->v.i_data); 1635 1613 ··· 1648 1604 1649 1605 BUG_ON(!is_bad_inode(&inode->v) && inode->ei_quota_reserved); 1650 1606 1651 - if (!inode->v.i_nlink && !is_bad_inode(&inode->v)) { 1607 + if (delete) { 1652 1608 bch2_quota_acct(c, inode->ei_qid, Q_SPC, -((s64) inode->v.i_blocks), 1653 1609 KEY_TYPE_QUOTA_WARN); 1654 1610 bch2_quota_acct(c, inode->ei_qid, Q_INO, -1, 1655 1611 KEY_TYPE_QUOTA_WARN); 1656 1612 bch2_inode_rm(c, inode_inum(inode)); 1613 + 1614 + /* 1615 + * If we are deleting, we need it present in the vfs hash table 1616 + * so that fsck can check if unlinked inodes are still open: 1617 + */ 1618 + bch2_inode_hash_remove(c, inode); 1657 1619 } 1658 1620 1659 1621 mutex_lock(&c->vfs_inodes_lock); ··· 1689 1639 1690 1640 mutex_lock(&c->vfs_inodes_lock); 1691 1641 list_for_each_entry(inode, &c->vfs_inodes_list, ei_vfs_inode_list) { 1692 - if (!snapshot_list_has_id(s, inode->ei_subvol)) 1642 + if (!snapshot_list_has_id(s, inode->ei_inum.subvol)) 1693 1643 continue; 1694 1644 1695 1645 if (!(inode->v.i_state & I_DONTCACHE) && ··· 2175 2125 fc->fs_private = opts; 2176 2126 2177 2127 return 0; 2128 + } 2129 + 2130 + void bch2_fs_vfs_exit(struct bch_fs *c) 2131 + { 2132 + if (c->vfs_inodes_table.tbl) 2133 + rhashtable_destroy(&c->vfs_inodes_table); 2134 + } 2135 + 2136 + int bch2_fs_vfs_init(struct bch_fs *c) 2137 + { 2138 + return rhashtable_init(&c->vfs_inodes_table, &bch2_vfs_inodes_params); 2178 2139 } 2179 2140 2180 2141 static struct file_system_type bcache_fs_type = {
+12 -6
fs/bcachefs/fs.h
··· 13 13 14 14 struct bch_inode_info { 15 15 struct inode v; 16 + struct rhash_head hash; 17 + subvol_inum ei_inum; 18 + 16 19 struct list_head ei_vfs_inode_list; 17 20 unsigned long ei_flags; 18 21 ··· 26 23 27 24 struct mutex ei_quota_lock; 28 25 struct bch_qid ei_qid; 29 - 30 - u32 ei_subvol; 31 26 32 27 /* 33 28 * When we've been doing nocow writes we'll need to issue flushes to the ··· 51 50 52 51 static inline subvol_inum inode_inum(struct bch_inode_info *inode) 53 52 { 54 - return (subvol_inum) { 55 - .subvol = inode->ei_subvol, 56 - .inum = inode->ei_inode.bi_inum, 57 - }; 53 + return inode->ei_inum; 58 54 } 59 55 60 56 struct bch_inode_info *__bch2_inode_hash_find(struct bch_fs *, subvol_inum); ··· 67 69 * those: 68 70 */ 69 71 #define EI_INODE_SNAPSHOT 1 72 + #define EI_INODE_HASHED 2 70 73 71 74 #define to_bch_ei(_inode) \ 72 75 container_of_or_null(_inode, struct bch_inode_info, v) ··· 188 189 189 190 void bch2_evict_subvolume_inodes(struct bch_fs *, snapshot_id_list *); 190 191 192 + void bch2_fs_vfs_exit(struct bch_fs *); 193 + int bch2_fs_vfs_init(struct bch_fs *); 194 + 191 195 void bch2_vfs_exit(void); 192 196 int bch2_vfs_init(void); 193 197 ··· 205 203 206 204 static inline void bch2_evict_subvolume_inodes(struct bch_fs *c, 207 205 snapshot_id_list *s) {} 206 + 207 + static inline void bch2_fs_vfs_exit(struct bch_fs *c) {} 208 + static inline int bch2_fs_vfs_init(struct bch_fs *c) { return 0; } 209 + 208 210 static inline void bch2_vfs_exit(void) {} 209 211 static inline int bch2_vfs_init(void) { return 0; } 210 212
+1 -1
fs/bcachefs/inode.c
··· 365 365 subvol_inum inum, unsigned flags) 366 366 { 367 367 int ret = bch2_inode_peek_nowarn(trans, iter, inode, inum, flags); 368 - bch_err_msg(trans->c, ret, "looking up inum %u:%llu:", inum.subvol, inum.inum); 368 + bch_err_msg(trans->c, ret, "looking up inum %llu:%llu:", inum.subvol, inum.inum); 369 369 return ret; 370 370 } 371 371
+2 -1
fs/bcachefs/subvolume_types.h
··· 30 30 }; 31 31 32 32 typedef struct { 33 - u32 subvol; 33 + /* we can't have padding in this struct: */ 34 + u64 subvol; 34 35 u64 inum; 35 36 } subvol_inum; 36 37
+2
fs/bcachefs/super.c
··· 543 543 bch2_fs_fs_io_direct_exit(c); 544 544 bch2_fs_fs_io_buffered_exit(c); 545 545 bch2_fs_fsio_exit(c); 546 + bch2_fs_vfs_exit(c); 546 547 bch2_fs_ec_exit(c); 547 548 bch2_fs_encryption_exit(c); 548 549 bch2_fs_nocow_locking_exit(c); ··· 927 926 bch2_fs_encryption_init(c) ?: 928 927 bch2_fs_compress_init(c) ?: 929 928 bch2_fs_ec_init(c) ?: 929 + bch2_fs_vfs_init(c) ?: 930 930 bch2_fs_fsio_init(c) ?: 931 931 bch2_fs_fs_io_buffered_init(c) ?: 932 932 bch2_fs_fs_io_direct_init(c);
+1 -1
fs/bcachefs/xattr.c
··· 306 306 bch2_trans_begin(trans); 307 307 iter = (struct btree_iter) { NULL }; 308 308 309 - ret = bch2_subvolume_get_snapshot(trans, inode->ei_subvol, &snapshot); 309 + ret = bch2_subvolume_get_snapshot(trans, inode->ei_inum.subvol, &snapshot); 310 310 if (ret) 311 311 goto err; 312 312