196385742SKent Overstreet // SPDX-License-Identifier: GPL-2.0 296385742SKent Overstreet 396385742SKent Overstreet #include "bcachefs.h" 496385742SKent Overstreet #include "acl.h" 596385742SKent Overstreet #include "btree_update.h" 696385742SKent Overstreet #include "dirent.h" 796385742SKent Overstreet #include "fs-common.h" 896385742SKent Overstreet #include "inode.h" 96fed42bbSKent Overstreet #include "subvolume.h" 1096385742SKent Overstreet #include "xattr.h" 1196385742SKent Overstreet 1296385742SKent Overstreet #include <linux/posix_acl.h> 1396385742SKent Overstreet 1442d23732SKent Overstreet static inline int is_subdir_for_nlink(struct bch_inode_unpacked *inode) 1542d23732SKent Overstreet { 1642d23732SKent Overstreet return S_ISDIR(inode->bi_mode) && !inode->bi_subvol; 1742d23732SKent Overstreet } 1842d23732SKent Overstreet 196fed42bbSKent Overstreet int bch2_create_trans(struct btree_trans *trans, 206fed42bbSKent Overstreet subvol_inum dir, 2196385742SKent Overstreet struct bch_inode_unpacked *dir_u, 2296385742SKent Overstreet struct bch_inode_unpacked *new_inode, 2396385742SKent Overstreet const struct qstr *name, 2496385742SKent Overstreet uid_t uid, gid_t gid, umode_t mode, dev_t rdev, 2596385742SKent Overstreet struct posix_acl *default_acl, 266fed42bbSKent Overstreet struct posix_acl *acl, 2742d23732SKent Overstreet subvol_inum snapshot_src, 286fed42bbSKent Overstreet unsigned flags) 2996385742SKent Overstreet { 3096385742SKent Overstreet struct bch_fs *c = trans->c; 3167e0dd8fSKent Overstreet struct btree_iter dir_iter = { NULL }; 3267e0dd8fSKent Overstreet struct btree_iter inode_iter = { NULL }; 336fed42bbSKent Overstreet subvol_inum new_inum = dir; 34ab2a29ccSKent Overstreet u64 now = bch2_current_time(c); 35bff796aeSKent Overstreet u64 cpu = raw_smp_processor_id(); 366fed42bbSKent Overstreet u64 dir_target; 376fed42bbSKent Overstreet u32 snapshot; 3842d23732SKent Overstreet unsigned dir_type = mode_to_type(mode); 3996385742SKent Overstreet int ret; 4096385742SKent Overstreet 416fed42bbSKent Overstreet ret = bch2_subvolume_get_snapshot(trans, dir.subvol, &snapshot); 426fed42bbSKent Overstreet if (ret) 436fed42bbSKent Overstreet goto err; 446fed42bbSKent Overstreet 455dd8c60eSKent Overstreet ret = bch2_inode_peek(trans, &dir_iter, dir_u, dir, BTREE_ITER_intent); 468b53852dSKent Overstreet if (ret) 478b53852dSKent Overstreet goto err; 4896385742SKent Overstreet 4942d23732SKent Overstreet if (!(flags & BCH_CREATE_SNAPSHOT)) { 5042d23732SKent Overstreet /* Normal create path - allocate a new inode: */ 5196385742SKent Overstreet bch2_inode_init_late(new_inode, now, uid, gid, mode, rdev, dir_u); 5296385742SKent Overstreet 5342d23732SKent Overstreet if (flags & BCH_CREATE_TMPFILE) 54103ffe9aSKent Overstreet new_inode->bi_flags |= BCH_INODE_unlinked; 5596385742SKent Overstreet 566fed42bbSKent Overstreet ret = bch2_inode_create(trans, &inode_iter, new_inode, snapshot, cpu); 5796385742SKent Overstreet if (ret) 588b53852dSKent Overstreet goto err; 5996385742SKent Overstreet 6042d23732SKent Overstreet snapshot_src = (subvol_inum) { 0 }; 6142d23732SKent Overstreet } else { 6242d23732SKent Overstreet /* 6342d23732SKent Overstreet * Creating a snapshot - we're not allocating a new inode, but 6442d23732SKent Overstreet * we do have to lookup the root inode of the subvolume we're 6542d23732SKent Overstreet * snapshotting and update it (in the new snapshot): 6642d23732SKent Overstreet */ 6742d23732SKent Overstreet 6842d23732SKent Overstreet if (!snapshot_src.inum) { 6942d23732SKent Overstreet /* Inode wasn't specified, just snapshot: */ 7097996ddfSKent Overstreet struct bch_subvolume s; 7142d23732SKent Overstreet 7297996ddfSKent Overstreet ret = bch2_subvolume_get(trans, snapshot_src.subvol, true, 735dd8c60eSKent Overstreet BTREE_ITER_cached, &s); 7442d23732SKent Overstreet if (ret) 7542d23732SKent Overstreet goto err; 7697996ddfSKent Overstreet 7797996ddfSKent Overstreet snapshot_src.inum = le64_to_cpu(s.inode); 7842d23732SKent Overstreet } 7942d23732SKent Overstreet 8042d23732SKent Overstreet ret = bch2_inode_peek(trans, &inode_iter, new_inode, snapshot_src, 815dd8c60eSKent Overstreet BTREE_ITER_intent); 8242d23732SKent Overstreet if (ret) 8342d23732SKent Overstreet goto err; 8442d23732SKent Overstreet 8542d23732SKent Overstreet if (new_inode->bi_subvol != snapshot_src.subvol) { 8642d23732SKent Overstreet /* Not a subvolume root: */ 8742d23732SKent Overstreet ret = -EINVAL; 8842d23732SKent Overstreet goto err; 8942d23732SKent Overstreet } 9042d23732SKent Overstreet 9142d23732SKent Overstreet /* 9242d23732SKent Overstreet * If we're not root, we have to own the subvolume being 9342d23732SKent Overstreet * snapshotted: 9442d23732SKent Overstreet */ 9542d23732SKent Overstreet if (uid && new_inode->bi_uid != uid) { 9642d23732SKent Overstreet ret = -EPERM; 9742d23732SKent Overstreet goto err; 9842d23732SKent Overstreet } 9942d23732SKent Overstreet 10042d23732SKent Overstreet flags |= BCH_CREATE_SUBVOL; 10142d23732SKent Overstreet } 10242d23732SKent Overstreet 1036fed42bbSKent Overstreet new_inum.inum = new_inode->bi_inum; 1046fed42bbSKent Overstreet dir_target = new_inode->bi_inum; 1056fed42bbSKent Overstreet 10642d23732SKent Overstreet if (flags & BCH_CREATE_SUBVOL) { 10742d23732SKent Overstreet u32 new_subvol, dir_snapshot; 10842d23732SKent Overstreet 10942d23732SKent Overstreet ret = bch2_subvolume_create(trans, new_inode->bi_inum, 110b8628a25SKent Overstreet dir.subvol, 11142d23732SKent Overstreet snapshot_src.subvol, 11242d23732SKent Overstreet &new_subvol, &snapshot, 11342d23732SKent Overstreet (flags & BCH_CREATE_SNAPSHOT_RO) != 0); 11442d23732SKent Overstreet if (ret) 11542d23732SKent Overstreet goto err; 11642d23732SKent Overstreet 11742d23732SKent Overstreet new_inode->bi_parent_subvol = dir.subvol; 11842d23732SKent Overstreet new_inode->bi_subvol = new_subvol; 11942d23732SKent Overstreet new_inum.subvol = new_subvol; 12042d23732SKent Overstreet dir_target = new_subvol; 12142d23732SKent Overstreet dir_type = DT_SUBVOL; 12242d23732SKent Overstreet 12342d23732SKent Overstreet ret = bch2_subvolume_get_snapshot(trans, dir.subvol, &dir_snapshot); 12442d23732SKent Overstreet if (ret) 12542d23732SKent Overstreet goto err; 12642d23732SKent Overstreet 12742d23732SKent Overstreet bch2_btree_iter_set_snapshot(&dir_iter, dir_snapshot); 12842d23732SKent Overstreet ret = bch2_btree_iter_traverse(&dir_iter); 12942d23732SKent Overstreet if (ret) 13042d23732SKent Overstreet goto err; 13142d23732SKent Overstreet } 13242d23732SKent Overstreet 13342d23732SKent Overstreet if (!(flags & BCH_CREATE_SNAPSHOT)) { 13496385742SKent Overstreet if (default_acl) { 1356fed42bbSKent Overstreet ret = bch2_set_acl_trans(trans, new_inum, new_inode, 13696385742SKent Overstreet default_acl, ACL_TYPE_DEFAULT); 13796385742SKent Overstreet if (ret) 1388b53852dSKent Overstreet goto err; 13996385742SKent Overstreet } 14096385742SKent Overstreet 14196385742SKent Overstreet if (acl) { 1426fed42bbSKent Overstreet ret = bch2_set_acl_trans(trans, new_inum, new_inode, 14396385742SKent Overstreet acl, ACL_TYPE_ACCESS); 14496385742SKent Overstreet if (ret) 1458b53852dSKent Overstreet goto err; 14696385742SKent Overstreet } 14742d23732SKent Overstreet } 14896385742SKent Overstreet 14942d23732SKent Overstreet if (!(flags & BCH_CREATE_TMPFILE)) { 15096385742SKent Overstreet struct bch_hash_info dir_hash = bch2_hash_info_init(c, dir_u); 15142d23732SKent Overstreet u64 dir_offset; 15296385742SKent Overstreet 15342d23732SKent Overstreet if (is_subdir_for_nlink(new_inode)) 15496385742SKent Overstreet dir_u->bi_nlink++; 1556fed42bbSKent Overstreet dir_u->bi_mtime = dir_u->bi_ctime = now; 15696385742SKent Overstreet 15767e0dd8fSKent Overstreet ret = bch2_inode_write(trans, &dir_iter, dir_u); 15896385742SKent Overstreet if (ret) 1598b53852dSKent Overstreet goto err; 16096385742SKent Overstreet 1616fed42bbSKent Overstreet ret = bch2_dirent_create(trans, dir, &dir_hash, 1626fed42bbSKent Overstreet dir_type, 1636fed42bbSKent Overstreet name, 1646fed42bbSKent Overstreet dir_target, 165ab2a29ccSKent Overstreet &dir_offset, 1665dd8c60eSKent Overstreet STR_HASH_must_create); 16796385742SKent Overstreet if (ret) 1688b53852dSKent Overstreet goto err; 169ab2a29ccSKent Overstreet 170ab2a29ccSKent Overstreet new_inode->bi_dir = dir_u->bi_inum; 171ab2a29ccSKent Overstreet new_inode->bi_dir_offset = dir_offset; 172ab2a29ccSKent Overstreet } 173ab2a29ccSKent Overstreet 1745dd8c60eSKent Overstreet inode_iter.flags &= ~BTREE_ITER_all_snapshots; 1756fed42bbSKent Overstreet bch2_btree_iter_set_snapshot(&inode_iter, snapshot); 176e6ae2727SKent Overstreet 17767e0dd8fSKent Overstreet ret = bch2_btree_iter_traverse(&inode_iter) ?: 17867e0dd8fSKent Overstreet bch2_inode_write(trans, &inode_iter, new_inode); 1798b53852dSKent Overstreet err: 18067e0dd8fSKent Overstreet bch2_trans_iter_exit(trans, &inode_iter); 18167e0dd8fSKent Overstreet bch2_trans_iter_exit(trans, &dir_iter); 1828b53852dSKent Overstreet return ret; 18396385742SKent Overstreet } 18496385742SKent Overstreet 1856fed42bbSKent Overstreet int bch2_link_trans(struct btree_trans *trans, 1866fed42bbSKent Overstreet subvol_inum dir, struct bch_inode_unpacked *dir_u, 1876fed42bbSKent Overstreet subvol_inum inum, struct bch_inode_unpacked *inode_u, 1886fed42bbSKent Overstreet const struct qstr *name) 18996385742SKent Overstreet { 190ab2a29ccSKent Overstreet struct bch_fs *c = trans->c; 19167e0dd8fSKent Overstreet struct btree_iter dir_iter = { NULL }; 19267e0dd8fSKent Overstreet struct btree_iter inode_iter = { NULL }; 19396385742SKent Overstreet struct bch_hash_info dir_hash; 194ab2a29ccSKent Overstreet u64 now = bch2_current_time(c); 195ab2a29ccSKent Overstreet u64 dir_offset = 0; 1968b53852dSKent Overstreet int ret; 19796385742SKent Overstreet 1986fed42bbSKent Overstreet if (dir.subvol != inum.subvol) 1996fed42bbSKent Overstreet return -EXDEV; 2006fed42bbSKent Overstreet 2015dd8c60eSKent Overstreet ret = bch2_inode_peek(trans, &inode_iter, inode_u, inum, BTREE_ITER_intent); 2028b53852dSKent Overstreet if (ret) 203*9862022dSYouling Tang return ret; 20496385742SKent Overstreet 20596385742SKent Overstreet inode_u->bi_ctime = now; 206962ad1a7SKent Overstreet ret = bch2_inode_nlink_inc(inode_u); 207962ad1a7SKent Overstreet if (ret) 208*9862022dSYouling Tang goto err; 20996385742SKent Overstreet 2105dd8c60eSKent Overstreet ret = bch2_inode_peek(trans, &dir_iter, dir_u, dir, BTREE_ITER_intent); 2118b53852dSKent Overstreet if (ret) 2128b53852dSKent Overstreet goto err; 21363fbf458SKent Overstreet 214bf9cb250SKent Overstreet if (bch2_reinherit_attrs(inode_u, dir_u)) { 215bf9cb250SKent Overstreet ret = -EXDEV; 216bf9cb250SKent Overstreet goto err; 217bf9cb250SKent Overstreet } 218bf9cb250SKent Overstreet 219184b1dc1SJustin Husted dir_u->bi_mtime = dir_u->bi_ctime = now; 22063fbf458SKent Overstreet 221ab2a29ccSKent Overstreet dir_hash = bch2_hash_info_init(c, dir_u); 22263fbf458SKent Overstreet 2236fed42bbSKent Overstreet ret = bch2_dirent_create(trans, dir, &dir_hash, 22496385742SKent Overstreet mode_to_type(inode_u->bi_mode), 2256fed42bbSKent Overstreet name, inum.inum, &dir_offset, 2265dd8c60eSKent Overstreet STR_HASH_must_create); 227ab2a29ccSKent Overstreet if (ret) 228ab2a29ccSKent Overstreet goto err; 229ab2a29ccSKent Overstreet 2306fed42bbSKent Overstreet inode_u->bi_dir = dir.inum; 231ab2a29ccSKent Overstreet inode_u->bi_dir_offset = dir_offset; 232ab2a29ccSKent Overstreet 23367e0dd8fSKent Overstreet ret = bch2_inode_write(trans, &dir_iter, dir_u) ?: 23467e0dd8fSKent Overstreet bch2_inode_write(trans, &inode_iter, inode_u); 2358b53852dSKent Overstreet err: 23667e0dd8fSKent Overstreet bch2_trans_iter_exit(trans, &dir_iter); 23767e0dd8fSKent Overstreet bch2_trans_iter_exit(trans, &inode_iter); 2388b53852dSKent Overstreet return ret; 23996385742SKent Overstreet } 24096385742SKent Overstreet 24196385742SKent Overstreet int bch2_unlink_trans(struct btree_trans *trans, 2426fed42bbSKent Overstreet subvol_inum dir, 2436fed42bbSKent Overstreet struct bch_inode_unpacked *dir_u, 24496385742SKent Overstreet struct bch_inode_unpacked *inode_u, 24542d23732SKent Overstreet const struct qstr *name, 246835cd3e1SKent Overstreet bool deleting_subvol) 24796385742SKent Overstreet { 248ab2a29ccSKent Overstreet struct bch_fs *c = trans->c; 24967e0dd8fSKent Overstreet struct btree_iter dir_iter = { NULL }; 25067e0dd8fSKent Overstreet struct btree_iter dirent_iter = { NULL }; 25167e0dd8fSKent Overstreet struct btree_iter inode_iter = { NULL }; 25296385742SKent Overstreet struct bch_hash_info dir_hash; 2536fed42bbSKent Overstreet subvol_inum inum; 2546fed42bbSKent Overstreet u64 now = bch2_current_time(c); 25542d23732SKent Overstreet struct bkey_s_c k; 2568b53852dSKent Overstreet int ret; 25796385742SKent Overstreet 2585dd8c60eSKent Overstreet ret = bch2_inode_peek(trans, &dir_iter, dir_u, dir, BTREE_ITER_intent); 2598b53852dSKent Overstreet if (ret) 2608b53852dSKent Overstreet goto err; 26196385742SKent Overstreet 262ab2a29ccSKent Overstreet dir_hash = bch2_hash_info_init(c, dir_u); 26396385742SKent Overstreet 2645b6271b5SKent Overstreet ret = bch2_dirent_lookup_trans(trans, &dirent_iter, dir, &dir_hash, 2655dd8c60eSKent Overstreet name, &inum, BTREE_ITER_intent); 2668b53852dSKent Overstreet if (ret) 2678b53852dSKent Overstreet goto err; 26896385742SKent Overstreet 2696fed42bbSKent Overstreet ret = bch2_inode_peek(trans, &inode_iter, inode_u, inum, 2705dd8c60eSKent Overstreet BTREE_ITER_intent); 2718b53852dSKent Overstreet if (ret) 2728b53852dSKent Overstreet goto err; 27396385742SKent Overstreet 274835cd3e1SKent Overstreet if (!deleting_subvol && S_ISDIR(inode_u->bi_mode)) { 27542d23732SKent Overstreet ret = bch2_empty_dir_trans(trans, inum); 27642d23732SKent Overstreet if (ret) 27742d23732SKent Overstreet goto err; 27842d23732SKent Overstreet } 27942d23732SKent Overstreet 280835cd3e1SKent Overstreet if (deleting_subvol && !inode_u->bi_subvol) { 281e47a390aSKent Overstreet ret = -BCH_ERR_ENOENT_not_subvol; 2827bd68c73SKent Overstreet goto err; 2837bd68c73SKent Overstreet } 2847bd68c73SKent Overstreet 285835cd3e1SKent Overstreet if (inode_u->bi_subvol) { 286835cd3e1SKent Overstreet /* Recursive subvolume destroy not allowed (yet?) */ 287835cd3e1SKent Overstreet ret = bch2_subvol_has_children(trans, inode_u->bi_subvol); 288835cd3e1SKent Overstreet if (ret) 289835cd3e1SKent Overstreet goto err; 290835cd3e1SKent Overstreet } 291835cd3e1SKent Overstreet 292835cd3e1SKent Overstreet if (deleting_subvol || inode_u->bi_subvol) { 2932027875bSKent Overstreet ret = bch2_subvolume_unlink(trans, inode_u->bi_subvol); 29442d23732SKent Overstreet if (ret) 29542d23732SKent Overstreet goto err; 29642d23732SKent Overstreet 29742d23732SKent Overstreet k = bch2_btree_iter_peek_slot(&dirent_iter); 29842d23732SKent Overstreet ret = bkey_err(k); 29942d23732SKent Overstreet if (ret) 30042d23732SKent Overstreet goto err; 30142d23732SKent Overstreet 30242d23732SKent Overstreet /* 30342d23732SKent Overstreet * If we're deleting a subvolume, we need to really delete the 30442d23732SKent Overstreet * dirent, not just emit a whiteout in the current snapshot: 30542d23732SKent Overstreet */ 30642d23732SKent Overstreet bch2_btree_iter_set_snapshot(&dirent_iter, k.k->p.snapshot); 30742d23732SKent Overstreet ret = bch2_btree_iter_traverse(&dirent_iter); 30842d23732SKent Overstreet if (ret) 30942d23732SKent Overstreet goto err; 3107bd68c73SKent Overstreet } else { 311962ad1a7SKent Overstreet bch2_inode_nlink_dec(trans, inode_u); 31242d23732SKent Overstreet } 31342d23732SKent Overstreet 3146fed42bbSKent Overstreet if (inode_u->bi_dir == dirent_iter.pos.inode && 3156fed42bbSKent Overstreet inode_u->bi_dir_offset == dirent_iter.pos.offset) { 316d3ff7fecSKent Overstreet inode_u->bi_dir = 0; 317d3ff7fecSKent Overstreet inode_u->bi_dir_offset = 0; 318d3ff7fecSKent Overstreet } 319d3ff7fecSKent Overstreet 32096385742SKent Overstreet dir_u->bi_mtime = dir_u->bi_ctime = inode_u->bi_ctime = now; 32142d23732SKent Overstreet dir_u->bi_nlink -= is_subdir_for_nlink(inode_u); 32296385742SKent Overstreet 32342d23732SKent Overstreet ret = bch2_hash_delete_at(trans, bch2_dirent_hash_desc, 32442d23732SKent Overstreet &dir_hash, &dirent_iter, 3255dd8c60eSKent Overstreet BTREE_UPDATE_internal_snapshot_node) ?: 32667e0dd8fSKent Overstreet bch2_inode_write(trans, &dir_iter, dir_u) ?: 32767e0dd8fSKent Overstreet bch2_inode_write(trans, &inode_iter, inode_u); 3288b53852dSKent Overstreet err: 32967e0dd8fSKent Overstreet bch2_trans_iter_exit(trans, &inode_iter); 33067e0dd8fSKent Overstreet bch2_trans_iter_exit(trans, &dirent_iter); 33167e0dd8fSKent Overstreet bch2_trans_iter_exit(trans, &dir_iter); 3328b53852dSKent Overstreet return ret; 33396385742SKent Overstreet } 33496385742SKent Overstreet 33596385742SKent Overstreet bool bch2_reinherit_attrs(struct bch_inode_unpacked *dst_u, 33696385742SKent Overstreet struct bch_inode_unpacked *src_u) 33796385742SKent Overstreet { 33896385742SKent Overstreet u64 src, dst; 33996385742SKent Overstreet unsigned id; 34096385742SKent Overstreet bool ret = false; 34196385742SKent Overstreet 34296385742SKent Overstreet for (id = 0; id < Inode_opt_nr; id++) { 343991ba021SKent Overstreet /* Skip attributes that were explicitly set on this inode */ 34496385742SKent Overstreet if (dst_u->bi_fields_set & (1 << id)) 34596385742SKent Overstreet continue; 34696385742SKent Overstreet 34796385742SKent Overstreet src = bch2_inode_opt_get(src_u, id); 34896385742SKent Overstreet dst = bch2_inode_opt_get(dst_u, id); 34996385742SKent Overstreet 35096385742SKent Overstreet if (src == dst) 35196385742SKent Overstreet continue; 35296385742SKent Overstreet 35396385742SKent Overstreet bch2_inode_opt_set(dst_u, id, src); 35496385742SKent Overstreet ret = true; 35596385742SKent Overstreet } 35696385742SKent Overstreet 35796385742SKent Overstreet return ret; 35896385742SKent Overstreet } 35996385742SKent Overstreet 360b8628a25SKent Overstreet static int subvol_update_parent(struct btree_trans *trans, u32 subvol, u32 new_parent) 361b8628a25SKent Overstreet { 362b8628a25SKent Overstreet struct btree_iter iter; 363b8628a25SKent Overstreet struct bkey_i_subvolume *s = 364b8628a25SKent Overstreet bch2_bkey_get_mut_typed(trans, &iter, 365b8628a25SKent Overstreet BTREE_ID_subvolumes, POS(0, subvol), 3665dd8c60eSKent Overstreet BTREE_ITER_cached, subvolume); 367b8628a25SKent Overstreet int ret = PTR_ERR_OR_ZERO(s); 368b8628a25SKent Overstreet if (ret) 369b8628a25SKent Overstreet return ret; 370b8628a25SKent Overstreet 371b8628a25SKent Overstreet s->v.fs_path_parent = cpu_to_le32(new_parent); 372b8628a25SKent Overstreet bch2_trans_iter_exit(trans, &iter); 373b8628a25SKent Overstreet return 0; 374b8628a25SKent Overstreet } 375b8628a25SKent Overstreet 37696385742SKent Overstreet int bch2_rename_trans(struct btree_trans *trans, 3776fed42bbSKent Overstreet subvol_inum src_dir, struct bch_inode_unpacked *src_dir_u, 3786fed42bbSKent Overstreet subvol_inum dst_dir, struct bch_inode_unpacked *dst_dir_u, 37996385742SKent Overstreet struct bch_inode_unpacked *src_inode_u, 38096385742SKent Overstreet struct bch_inode_unpacked *dst_inode_u, 38196385742SKent Overstreet const struct qstr *src_name, 38296385742SKent Overstreet const struct qstr *dst_name, 38396385742SKent Overstreet enum bch_rename_mode mode) 38496385742SKent Overstreet { 385ab2a29ccSKent Overstreet struct bch_fs *c = trans->c; 38667e0dd8fSKent Overstreet struct btree_iter src_dir_iter = { NULL }; 38767e0dd8fSKent Overstreet struct btree_iter dst_dir_iter = { NULL }; 38867e0dd8fSKent Overstreet struct btree_iter src_inode_iter = { NULL }; 38967e0dd8fSKent Overstreet struct btree_iter dst_inode_iter = { NULL }; 39096385742SKent Overstreet struct bch_hash_info src_hash, dst_hash; 3916fed42bbSKent Overstreet subvol_inum src_inum, dst_inum; 3926fed42bbSKent Overstreet u64 src_offset, dst_offset; 393ab2a29ccSKent Overstreet u64 now = bch2_current_time(c); 39496385742SKent Overstreet int ret; 39596385742SKent Overstreet 39667e0dd8fSKent Overstreet ret = bch2_inode_peek(trans, &src_dir_iter, src_dir_u, src_dir, 3975dd8c60eSKent Overstreet BTREE_ITER_intent); 3988b53852dSKent Overstreet if (ret) 3998b53852dSKent Overstreet goto err; 40096385742SKent Overstreet 401ab2a29ccSKent Overstreet src_hash = bch2_hash_info_init(c, src_dir_u); 40296385742SKent Overstreet 4036fed42bbSKent Overstreet if (dst_dir.inum != src_dir.inum || 4046fed42bbSKent Overstreet dst_dir.subvol != src_dir.subvol) { 40567e0dd8fSKent Overstreet ret = bch2_inode_peek(trans, &dst_dir_iter, dst_dir_u, dst_dir, 4065dd8c60eSKent Overstreet BTREE_ITER_intent); 4078b53852dSKent Overstreet if (ret) 4088b53852dSKent Overstreet goto err; 40996385742SKent Overstreet 410ab2a29ccSKent Overstreet dst_hash = bch2_hash_info_init(c, dst_dir_u); 41196385742SKent Overstreet } else { 41296385742SKent Overstreet dst_dir_u = src_dir_u; 41396385742SKent Overstreet dst_hash = src_hash; 41496385742SKent Overstreet } 41596385742SKent Overstreet 41696385742SKent Overstreet ret = bch2_dirent_rename(trans, 41796385742SKent Overstreet src_dir, &src_hash, 41896385742SKent Overstreet dst_dir, &dst_hash, 4196fed42bbSKent Overstreet src_name, &src_inum, &src_offset, 4206fed42bbSKent Overstreet dst_name, &dst_inum, &dst_offset, 42196385742SKent Overstreet mode); 42296385742SKent Overstreet if (ret) 4238b53852dSKent Overstreet goto err; 42496385742SKent Overstreet 4256fed42bbSKent Overstreet ret = bch2_inode_peek(trans, &src_inode_iter, src_inode_u, src_inum, 4265dd8c60eSKent Overstreet BTREE_ITER_intent); 4278b53852dSKent Overstreet if (ret) 4288b53852dSKent Overstreet goto err; 42996385742SKent Overstreet 4306fed42bbSKent Overstreet if (dst_inum.inum) { 4316fed42bbSKent Overstreet ret = bch2_inode_peek(trans, &dst_inode_iter, dst_inode_u, dst_inum, 4325dd8c60eSKent Overstreet BTREE_ITER_intent); 4338b53852dSKent Overstreet if (ret) 4348b53852dSKent Overstreet goto err; 43596385742SKent Overstreet } 43696385742SKent Overstreet 437b8628a25SKent Overstreet if (src_inode_u->bi_subvol && 438b8628a25SKent Overstreet dst_dir.subvol != src_inode_u->bi_parent_subvol) { 439b8628a25SKent Overstreet ret = subvol_update_parent(trans, src_inode_u->bi_subvol, dst_dir.subvol); 440b8628a25SKent Overstreet if (ret) 441b8628a25SKent Overstreet goto err; 442b8628a25SKent Overstreet } 443b8628a25SKent Overstreet 444b8628a25SKent Overstreet if (mode == BCH_RENAME_EXCHANGE && 445b8628a25SKent Overstreet dst_inode_u->bi_subvol && 446b8628a25SKent Overstreet src_dir.subvol != dst_inode_u->bi_parent_subvol) { 447b8628a25SKent Overstreet ret = subvol_update_parent(trans, dst_inode_u->bi_subvol, src_dir.subvol); 448b8628a25SKent Overstreet if (ret) 449b8628a25SKent Overstreet goto err; 450b8628a25SKent Overstreet } 451b8628a25SKent Overstreet 4527f76b08aSKent Overstreet /* Can't move across subvolumes, unless it's a subvolume root: */ 4537f76b08aSKent Overstreet if (src_dir.subvol != dst_dir.subvol && 4547f76b08aSKent Overstreet (!src_inode_u->bi_subvol || 4557f76b08aSKent Overstreet (dst_inum.inum && !dst_inode_u->bi_subvol))) { 4567f76b08aSKent Overstreet ret = -EXDEV; 4577f76b08aSKent Overstreet goto err; 4587f76b08aSKent Overstreet } 4597f76b08aSKent Overstreet 4607f76b08aSKent Overstreet if (src_inode_u->bi_parent_subvol) 4617f76b08aSKent Overstreet src_inode_u->bi_parent_subvol = dst_dir.subvol; 4627f76b08aSKent Overstreet 4637f76b08aSKent Overstreet if ((mode == BCH_RENAME_EXCHANGE) && 4647f76b08aSKent Overstreet dst_inode_u->bi_parent_subvol) 4657f76b08aSKent Overstreet dst_inode_u->bi_parent_subvol = src_dir.subvol; 4667f76b08aSKent Overstreet 467ab2a29ccSKent Overstreet src_inode_u->bi_dir = dst_dir_u->bi_inum; 468ab2a29ccSKent Overstreet src_inode_u->bi_dir_offset = dst_offset; 469ab2a29ccSKent Overstreet 470ab2a29ccSKent Overstreet if (mode == BCH_RENAME_EXCHANGE) { 471ab2a29ccSKent Overstreet dst_inode_u->bi_dir = src_dir_u->bi_inum; 472ab2a29ccSKent Overstreet dst_inode_u->bi_dir_offset = src_offset; 473ab2a29ccSKent Overstreet } 47416ac8c95SKent Overstreet 47516ac8c95SKent Overstreet if (mode == BCH_RENAME_OVERWRITE && 47616ac8c95SKent Overstreet dst_inode_u->bi_dir == dst_dir_u->bi_inum && 47716ac8c95SKent Overstreet dst_inode_u->bi_dir_offset == src_offset) { 47816ac8c95SKent Overstreet dst_inode_u->bi_dir = 0; 47916ac8c95SKent Overstreet dst_inode_u->bi_dir_offset = 0; 48016ac8c95SKent Overstreet } 481ab2a29ccSKent Overstreet 48296385742SKent Overstreet if (mode == BCH_RENAME_OVERWRITE) { 48396385742SKent Overstreet if (S_ISDIR(src_inode_u->bi_mode) != 4848b53852dSKent Overstreet S_ISDIR(dst_inode_u->bi_mode)) { 4858b53852dSKent Overstreet ret = -ENOTDIR; 4868b53852dSKent Overstreet goto err; 4878b53852dSKent Overstreet } 48896385742SKent Overstreet 489835cd3e1SKent Overstreet if (S_ISDIR(dst_inode_u->bi_mode)) { 490835cd3e1SKent Overstreet ret = bch2_empty_dir_trans(trans, dst_inum); 491835cd3e1SKent Overstreet if (ret) 4928b53852dSKent Overstreet goto err; 4938b53852dSKent Overstreet } 49496385742SKent Overstreet } 49596385742SKent Overstreet 49696385742SKent Overstreet if (bch2_reinherit_attrs(src_inode_u, dst_dir_u) && 4978b53852dSKent Overstreet S_ISDIR(src_inode_u->bi_mode)) { 4988b53852dSKent Overstreet ret = -EXDEV; 4998b53852dSKent Overstreet goto err; 5008b53852dSKent Overstreet } 50196385742SKent Overstreet 50296385742SKent Overstreet if (mode == BCH_RENAME_EXCHANGE && 50396385742SKent Overstreet bch2_reinherit_attrs(dst_inode_u, src_dir_u) && 5048b53852dSKent Overstreet S_ISDIR(dst_inode_u->bi_mode)) { 5058b53852dSKent Overstreet ret = -EXDEV; 5068b53852dSKent Overstreet goto err; 5078b53852dSKent Overstreet } 50896385742SKent Overstreet 50942d23732SKent Overstreet if (is_subdir_for_nlink(src_inode_u)) { 51096385742SKent Overstreet src_dir_u->bi_nlink--; 51196385742SKent Overstreet dst_dir_u->bi_nlink++; 51296385742SKent Overstreet } 51396385742SKent Overstreet 51442d23732SKent Overstreet if (dst_inum.inum && is_subdir_for_nlink(dst_inode_u)) { 51596385742SKent Overstreet dst_dir_u->bi_nlink--; 51696385742SKent Overstreet src_dir_u->bi_nlink += mode == BCH_RENAME_EXCHANGE; 51796385742SKent Overstreet } 51896385742SKent Overstreet 51996385742SKent Overstreet if (mode == BCH_RENAME_OVERWRITE) 520962ad1a7SKent Overstreet bch2_inode_nlink_dec(trans, dst_inode_u); 52196385742SKent Overstreet 52296385742SKent Overstreet src_dir_u->bi_mtime = now; 52396385742SKent Overstreet src_dir_u->bi_ctime = now; 52496385742SKent Overstreet 5256fed42bbSKent Overstreet if (src_dir.inum != dst_dir.inum) { 52696385742SKent Overstreet dst_dir_u->bi_mtime = now; 52796385742SKent Overstreet dst_dir_u->bi_ctime = now; 52896385742SKent Overstreet } 52996385742SKent Overstreet 53096385742SKent Overstreet src_inode_u->bi_ctime = now; 53196385742SKent Overstreet 5326fed42bbSKent Overstreet if (dst_inum.inum) 53396385742SKent Overstreet dst_inode_u->bi_ctime = now; 53496385742SKent Overstreet 53567e0dd8fSKent Overstreet ret = bch2_inode_write(trans, &src_dir_iter, src_dir_u) ?: 5366fed42bbSKent Overstreet (src_dir.inum != dst_dir.inum 53767e0dd8fSKent Overstreet ? bch2_inode_write(trans, &dst_dir_iter, dst_dir_u) 53896385742SKent Overstreet : 0) ?: 53967e0dd8fSKent Overstreet bch2_inode_write(trans, &src_inode_iter, src_inode_u) ?: 5406fed42bbSKent Overstreet (dst_inum.inum 54167e0dd8fSKent Overstreet ? bch2_inode_write(trans, &dst_inode_iter, dst_inode_u) 54296385742SKent Overstreet : 0); 5438b53852dSKent Overstreet err: 54467e0dd8fSKent Overstreet bch2_trans_iter_exit(trans, &dst_inode_iter); 54567e0dd8fSKent Overstreet bch2_trans_iter_exit(trans, &src_inode_iter); 54667e0dd8fSKent Overstreet bch2_trans_iter_exit(trans, &dst_dir_iter); 54767e0dd8fSKent Overstreet bch2_trans_iter_exit(trans, &src_dir_iter); 5488b53852dSKent Overstreet return ret; 54996385742SKent Overstreet } 550