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

bcachefs: bch2_lookup() gives better error message on inode not found

When a dirent points to a missing inode, we really should print out the
dirent.

This requires quite a bit of refactoring, but there's some other
benefits: we now do the entire looup (dirent and inode) in a single
btree transaction, and copy to the VFS inode with btree locks still
held, like the create path.

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

+64 -9
+64 -9
fs/bcachefs/fs.c
··· 365 365 366 366 /* methods */ 367 367 368 + static struct bch_inode_info *bch2_lookup_trans(struct btree_trans *trans, 369 + subvol_inum dir, struct bch_hash_info *dir_hash_info, 370 + const struct qstr *name) 371 + { 372 + struct bch_fs *c = trans->c; 373 + struct btree_iter dirent_iter = {}; 374 + subvol_inum inum = {}; 375 + 376 + int ret = bch2_hash_lookup(trans, &dirent_iter, bch2_dirent_hash_desc, 377 + dir_hash_info, dir, name, 0); 378 + if (ret) 379 + return ERR_PTR(ret); 380 + 381 + struct bkey_s_c k = bch2_btree_iter_peek_slot(&dirent_iter); 382 + ret = bkey_err(k); 383 + if (ret) 384 + goto err; 385 + 386 + ret = bch2_dirent_read_target(trans, dir, bkey_s_c_to_dirent(k), &inum); 387 + if (ret > 0) 388 + ret = -ENOENT; 389 + if (ret) 390 + goto err; 391 + 392 + struct bch_inode_info *inode = 393 + to_bch_ei(ilookup5_nowait(c->vfs_sb, 394 + bch2_inode_hash(inum), 395 + bch2_iget5_test, 396 + &inum)); 397 + if (inode) 398 + goto out; 399 + 400 + struct bch_subvolume subvol; 401 + struct bch_inode_unpacked inode_u; 402 + ret = bch2_subvolume_get(trans, inum.subvol, true, 0, &subvol) ?: 403 + bch2_inode_find_by_inum_nowarn_trans(trans, inum, &inode_u) ?: 404 + PTR_ERR_OR_ZERO(inode = bch2_new_inode(trans)); 405 + if (bch2_err_matches(ret, ENOENT)) { 406 + struct printbuf buf = PRINTBUF; 407 + 408 + bch2_bkey_val_to_text(&buf, c, k); 409 + bch_err(c, "%s points to missing inode", buf.buf); 410 + printbuf_exit(&buf); 411 + } 412 + if (ret) 413 + goto err; 414 + 415 + bch2_vfs_inode_init(trans, inum, inode, &inode_u, &subvol); 416 + inode = bch2_inode_insert(c, inode); 417 + out: 418 + bch2_trans_iter_exit(trans, &dirent_iter); 419 + return inode; 420 + err: 421 + inode = ERR_PTR(ret); 422 + goto out; 423 + } 424 + 368 425 static struct dentry *bch2_lookup(struct inode *vdir, struct dentry *dentry, 369 426 unsigned int flags) 370 427 { 371 428 struct bch_fs *c = vdir->i_sb->s_fs_info; 372 429 struct bch_inode_info *dir = to_bch_ei(vdir); 373 430 struct bch_hash_info hash = bch2_hash_info_init(c, &dir->ei_inode); 374 - struct inode *vinode = NULL; 375 - subvol_inum inum = { .subvol = 1 }; 376 - int ret; 377 431 378 - ret = bch2_dirent_lookup(c, inode_inum(dir), &hash, 379 - &dentry->d_name, &inum); 432 + struct bch_inode_info *inode; 433 + bch2_trans_do(c, NULL, NULL, 0, 434 + PTR_ERR_OR_ZERO(inode = bch2_lookup_trans(trans, inode_inum(dir), 435 + &hash, &dentry->d_name))); 436 + if (IS_ERR(inode)) 437 + inode = NULL; 380 438 381 - if (!ret) 382 - vinode = bch2_vfs_inode_get(c, inum); 383 - 384 - return d_splice_alias(vinode, dentry); 439 + return d_splice_alias(&inode->v, dentry); 385 440 } 386 441 387 442 static int bch2_mknod(struct mnt_idmap *idmap,