551 lines · c
1// SPDX-License-Identifier: GPL-2.02 3#include "bcachefs.h"4#include "acl.h"5#include "btree_update.h"6#include "dirent.h"7#include "fs-common.h"8#include "inode.h"9#include "subvolume.h"10#include "xattr.h"11 12#include <linux/posix_acl.h>13 14static inline int is_subdir_for_nlink(struct bch_inode_unpacked *inode)15{16 return S_ISDIR(inode->bi_mode) && !inode->bi_subvol;17}18 19int bch2_create_trans(struct btree_trans *trans,20 subvol_inum dir,21 struct bch_inode_unpacked *dir_u,22 struct bch_inode_unpacked *new_inode,23 const struct qstr *name,24 uid_t uid, gid_t gid, umode_t mode, dev_t rdev,25 struct posix_acl *default_acl,26 struct posix_acl *acl,27 subvol_inum snapshot_src,28 unsigned flags)29{30 struct bch_fs *c = trans->c;31 struct btree_iter dir_iter = { NULL };32 struct btree_iter inode_iter = { NULL };33 subvol_inum new_inum = dir;34 u64 now = bch2_current_time(c);35 u64 cpu = raw_smp_processor_id();36 u64 dir_target;37 u32 snapshot;38 unsigned dir_type = mode_to_type(mode);39 int ret;40 41 ret = bch2_subvolume_get_snapshot(trans, dir.subvol, &snapshot);42 if (ret)43 goto err;44 45 ret = bch2_inode_peek(trans, &dir_iter, dir_u, dir,46 BTREE_ITER_intent|BTREE_ITER_with_updates);47 if (ret)48 goto err;49 50 if (!(flags & BCH_CREATE_SNAPSHOT)) {51 /* Normal create path - allocate a new inode: */52 bch2_inode_init_late(new_inode, now, uid, gid, mode, rdev, dir_u);53 54 if (flags & BCH_CREATE_TMPFILE)55 new_inode->bi_flags |= BCH_INODE_unlinked;56 57 ret = bch2_inode_create(trans, &inode_iter, new_inode, snapshot, cpu);58 if (ret)59 goto err;60 61 snapshot_src = (subvol_inum) { 0 };62 } else {63 /*64 * Creating a snapshot - we're not allocating a new inode, but65 * we do have to lookup the root inode of the subvolume we're66 * snapshotting and update it (in the new snapshot):67 */68 69 if (!snapshot_src.inum) {70 /* Inode wasn't specified, just snapshot: */71 struct bch_subvolume s;72 73 ret = bch2_subvolume_get(trans, snapshot_src.subvol, true,74 BTREE_ITER_cached, &s);75 if (ret)76 goto err;77 78 snapshot_src.inum = le64_to_cpu(s.inode);79 }80 81 ret = bch2_inode_peek(trans, &inode_iter, new_inode, snapshot_src,82 BTREE_ITER_intent);83 if (ret)84 goto err;85 86 if (new_inode->bi_subvol != snapshot_src.subvol) {87 /* Not a subvolume root: */88 ret = -EINVAL;89 goto err;90 }91 92 /*93 * If we're not root, we have to own the subvolume being94 * snapshotted:95 */96 if (uid && new_inode->bi_uid != uid) {97 ret = -EPERM;98 goto err;99 }100 101 flags |= BCH_CREATE_SUBVOL;102 }103 104 new_inum.inum = new_inode->bi_inum;105 dir_target = new_inode->bi_inum;106 107 if (flags & BCH_CREATE_SUBVOL) {108 u32 new_subvol, dir_snapshot;109 110 ret = bch2_subvolume_create(trans, new_inode->bi_inum,111 dir.subvol,112 snapshot_src.subvol,113 &new_subvol, &snapshot,114 (flags & BCH_CREATE_SNAPSHOT_RO) != 0);115 if (ret)116 goto err;117 118 new_inode->bi_parent_subvol = dir.subvol;119 new_inode->bi_subvol = new_subvol;120 new_inum.subvol = new_subvol;121 dir_target = new_subvol;122 dir_type = DT_SUBVOL;123 124 ret = bch2_subvolume_get_snapshot(trans, dir.subvol, &dir_snapshot);125 if (ret)126 goto err;127 128 bch2_btree_iter_set_snapshot(&dir_iter, dir_snapshot);129 ret = bch2_btree_iter_traverse(&dir_iter);130 if (ret)131 goto err;132 }133 134 if (!(flags & BCH_CREATE_SNAPSHOT)) {135 if (default_acl) {136 ret = bch2_set_acl_trans(trans, new_inum, new_inode,137 default_acl, ACL_TYPE_DEFAULT);138 if (ret)139 goto err;140 }141 142 if (acl) {143 ret = bch2_set_acl_trans(trans, new_inum, new_inode,144 acl, ACL_TYPE_ACCESS);145 if (ret)146 goto err;147 }148 }149 150 if (!(flags & BCH_CREATE_TMPFILE)) {151 struct bch_hash_info dir_hash = bch2_hash_info_init(c, dir_u);152 u64 dir_offset;153 154 if (is_subdir_for_nlink(new_inode))155 dir_u->bi_nlink++;156 dir_u->bi_mtime = dir_u->bi_ctime = now;157 158 ret = bch2_inode_write(trans, &dir_iter, dir_u);159 if (ret)160 goto err;161 162 ret = bch2_dirent_create(trans, dir, &dir_hash,163 dir_type,164 name,165 dir_target,166 &dir_offset,167 STR_HASH_must_create|BTREE_ITER_with_updates);168 if (ret)169 goto err;170 171 new_inode->bi_dir = dir_u->bi_inum;172 new_inode->bi_dir_offset = dir_offset;173 }174 175 inode_iter.flags &= ~BTREE_ITER_all_snapshots;176 bch2_btree_iter_set_snapshot(&inode_iter, snapshot);177 178 ret = bch2_btree_iter_traverse(&inode_iter) ?:179 bch2_inode_write(trans, &inode_iter, new_inode);180err:181 bch2_trans_iter_exit(trans, &inode_iter);182 bch2_trans_iter_exit(trans, &dir_iter);183 return ret;184}185 186int bch2_link_trans(struct btree_trans *trans,187 subvol_inum dir, struct bch_inode_unpacked *dir_u,188 subvol_inum inum, struct bch_inode_unpacked *inode_u,189 const struct qstr *name)190{191 struct bch_fs *c = trans->c;192 struct btree_iter dir_iter = { NULL };193 struct btree_iter inode_iter = { NULL };194 struct bch_hash_info dir_hash;195 u64 now = bch2_current_time(c);196 u64 dir_offset = 0;197 int ret;198 199 if (dir.subvol != inum.subvol)200 return -EXDEV;201 202 ret = bch2_inode_peek(trans, &inode_iter, inode_u, inum, BTREE_ITER_intent);203 if (ret)204 return ret;205 206 inode_u->bi_ctime = now;207 ret = bch2_inode_nlink_inc(inode_u);208 if (ret)209 goto err;210 211 ret = bch2_inode_peek(trans, &dir_iter, dir_u, dir, BTREE_ITER_intent);212 if (ret)213 goto err;214 215 if (bch2_reinherit_attrs(inode_u, dir_u)) {216 ret = -EXDEV;217 goto err;218 }219 220 dir_u->bi_mtime = dir_u->bi_ctime = now;221 222 dir_hash = bch2_hash_info_init(c, dir_u);223 224 ret = bch2_dirent_create(trans, dir, &dir_hash,225 mode_to_type(inode_u->bi_mode),226 name, inum.inum, &dir_offset,227 STR_HASH_must_create);228 if (ret)229 goto err;230 231 inode_u->bi_dir = dir.inum;232 inode_u->bi_dir_offset = dir_offset;233 234 ret = bch2_inode_write(trans, &dir_iter, dir_u) ?:235 bch2_inode_write(trans, &inode_iter, inode_u);236err:237 bch2_trans_iter_exit(trans, &dir_iter);238 bch2_trans_iter_exit(trans, &inode_iter);239 return ret;240}241 242int bch2_unlink_trans(struct btree_trans *trans,243 subvol_inum dir,244 struct bch_inode_unpacked *dir_u,245 struct bch_inode_unpacked *inode_u,246 const struct qstr *name,247 bool deleting_subvol)248{249 struct bch_fs *c = trans->c;250 struct btree_iter dir_iter = { NULL };251 struct btree_iter dirent_iter = { NULL };252 struct btree_iter inode_iter = { NULL };253 struct bch_hash_info dir_hash;254 subvol_inum inum;255 u64 now = bch2_current_time(c);256 struct bkey_s_c k;257 int ret;258 259 ret = bch2_inode_peek(trans, &dir_iter, dir_u, dir, BTREE_ITER_intent);260 if (ret)261 goto err;262 263 dir_hash = bch2_hash_info_init(c, dir_u);264 265 ret = bch2_dirent_lookup_trans(trans, &dirent_iter, dir, &dir_hash,266 name, &inum, BTREE_ITER_intent);267 if (ret)268 goto err;269 270 ret = bch2_inode_peek(trans, &inode_iter, inode_u, inum,271 BTREE_ITER_intent);272 if (ret)273 goto err;274 275 if (!deleting_subvol && S_ISDIR(inode_u->bi_mode)) {276 ret = bch2_empty_dir_trans(trans, inum);277 if (ret)278 goto err;279 }280 281 if (deleting_subvol && !inode_u->bi_subvol) {282 ret = -BCH_ERR_ENOENT_not_subvol;283 goto err;284 }285 286 if (inode_u->bi_subvol) {287 /* Recursive subvolume destroy not allowed (yet?) */288 ret = bch2_subvol_has_children(trans, inode_u->bi_subvol);289 if (ret)290 goto err;291 }292 293 if (deleting_subvol || inode_u->bi_subvol) {294 ret = bch2_subvolume_unlink(trans, inode_u->bi_subvol);295 if (ret)296 goto err;297 298 k = bch2_btree_iter_peek_slot(&dirent_iter);299 ret = bkey_err(k);300 if (ret)301 goto err;302 303 /*304 * If we're deleting a subvolume, we need to really delete the305 * dirent, not just emit a whiteout in the current snapshot:306 */307 bch2_btree_iter_set_snapshot(&dirent_iter, k.k->p.snapshot);308 ret = bch2_btree_iter_traverse(&dirent_iter);309 if (ret)310 goto err;311 } else {312 bch2_inode_nlink_dec(trans, inode_u);313 }314 315 if (inode_u->bi_dir == dirent_iter.pos.inode &&316 inode_u->bi_dir_offset == dirent_iter.pos.offset) {317 inode_u->bi_dir = 0;318 inode_u->bi_dir_offset = 0;319 }320 321 dir_u->bi_mtime = dir_u->bi_ctime = inode_u->bi_ctime = now;322 dir_u->bi_nlink -= is_subdir_for_nlink(inode_u);323 324 ret = bch2_hash_delete_at(trans, bch2_dirent_hash_desc,325 &dir_hash, &dirent_iter,326 BTREE_UPDATE_internal_snapshot_node) ?:327 bch2_inode_write(trans, &dir_iter, dir_u) ?:328 bch2_inode_write(trans, &inode_iter, inode_u);329err:330 bch2_trans_iter_exit(trans, &inode_iter);331 bch2_trans_iter_exit(trans, &dirent_iter);332 bch2_trans_iter_exit(trans, &dir_iter);333 return ret;334}335 336bool bch2_reinherit_attrs(struct bch_inode_unpacked *dst_u,337 struct bch_inode_unpacked *src_u)338{339 u64 src, dst;340 unsigned id;341 bool ret = false;342 343 for (id = 0; id < Inode_opt_nr; id++) {344 /* Skip attributes that were explicitly set on this inode */345 if (dst_u->bi_fields_set & (1 << id))346 continue;347 348 src = bch2_inode_opt_get(src_u, id);349 dst = bch2_inode_opt_get(dst_u, id);350 351 if (src == dst)352 continue;353 354 bch2_inode_opt_set(dst_u, id, src);355 ret = true;356 }357 358 return ret;359}360 361static int subvol_update_parent(struct btree_trans *trans, u32 subvol, u32 new_parent)362{363 struct btree_iter iter;364 struct bkey_i_subvolume *s =365 bch2_bkey_get_mut_typed(trans, &iter,366 BTREE_ID_subvolumes, POS(0, subvol),367 BTREE_ITER_cached, subvolume);368 int ret = PTR_ERR_OR_ZERO(s);369 if (ret)370 return ret;371 372 s->v.fs_path_parent = cpu_to_le32(new_parent);373 bch2_trans_iter_exit(trans, &iter);374 return 0;375}376 377int bch2_rename_trans(struct btree_trans *trans,378 subvol_inum src_dir, struct bch_inode_unpacked *src_dir_u,379 subvol_inum dst_dir, struct bch_inode_unpacked *dst_dir_u,380 struct bch_inode_unpacked *src_inode_u,381 struct bch_inode_unpacked *dst_inode_u,382 const struct qstr *src_name,383 const struct qstr *dst_name,384 enum bch_rename_mode mode)385{386 struct bch_fs *c = trans->c;387 struct btree_iter src_dir_iter = { NULL };388 struct btree_iter dst_dir_iter = { NULL };389 struct btree_iter src_inode_iter = { NULL };390 struct btree_iter dst_inode_iter = { NULL };391 struct bch_hash_info src_hash, dst_hash;392 subvol_inum src_inum, dst_inum;393 u64 src_offset, dst_offset;394 u64 now = bch2_current_time(c);395 int ret;396 397 ret = bch2_inode_peek(trans, &src_dir_iter, src_dir_u, src_dir,398 BTREE_ITER_intent);399 if (ret)400 goto err;401 402 src_hash = bch2_hash_info_init(c, src_dir_u);403 404 if (dst_dir.inum != src_dir.inum ||405 dst_dir.subvol != src_dir.subvol) {406 ret = bch2_inode_peek(trans, &dst_dir_iter, dst_dir_u, dst_dir,407 BTREE_ITER_intent);408 if (ret)409 goto err;410 411 dst_hash = bch2_hash_info_init(c, dst_dir_u);412 } else {413 dst_dir_u = src_dir_u;414 dst_hash = src_hash;415 }416 417 ret = bch2_dirent_rename(trans,418 src_dir, &src_hash,419 dst_dir, &dst_hash,420 src_name, &src_inum, &src_offset,421 dst_name, &dst_inum, &dst_offset,422 mode);423 if (ret)424 goto err;425 426 ret = bch2_inode_peek(trans, &src_inode_iter, src_inode_u, src_inum,427 BTREE_ITER_intent);428 if (ret)429 goto err;430 431 if (dst_inum.inum) {432 ret = bch2_inode_peek(trans, &dst_inode_iter, dst_inode_u, dst_inum,433 BTREE_ITER_intent);434 if (ret)435 goto err;436 }437 438 if (src_inode_u->bi_subvol &&439 dst_dir.subvol != src_inode_u->bi_parent_subvol) {440 ret = subvol_update_parent(trans, src_inode_u->bi_subvol, dst_dir.subvol);441 if (ret)442 goto err;443 }444 445 if (mode == BCH_RENAME_EXCHANGE &&446 dst_inode_u->bi_subvol &&447 src_dir.subvol != dst_inode_u->bi_parent_subvol) {448 ret = subvol_update_parent(trans, dst_inode_u->bi_subvol, src_dir.subvol);449 if (ret)450 goto err;451 }452 453 /* Can't move across subvolumes, unless it's a subvolume root: */454 if (src_dir.subvol != dst_dir.subvol &&455 (!src_inode_u->bi_subvol ||456 (dst_inum.inum && !dst_inode_u->bi_subvol))) {457 ret = -EXDEV;458 goto err;459 }460 461 if (src_inode_u->bi_parent_subvol)462 src_inode_u->bi_parent_subvol = dst_dir.subvol;463 464 if ((mode == BCH_RENAME_EXCHANGE) &&465 dst_inode_u->bi_parent_subvol)466 dst_inode_u->bi_parent_subvol = src_dir.subvol;467 468 src_inode_u->bi_dir = dst_dir_u->bi_inum;469 src_inode_u->bi_dir_offset = dst_offset;470 471 if (mode == BCH_RENAME_EXCHANGE) {472 dst_inode_u->bi_dir = src_dir_u->bi_inum;473 dst_inode_u->bi_dir_offset = src_offset;474 }475 476 if (mode == BCH_RENAME_OVERWRITE &&477 dst_inode_u->bi_dir == dst_dir_u->bi_inum &&478 dst_inode_u->bi_dir_offset == src_offset) {479 dst_inode_u->bi_dir = 0;480 dst_inode_u->bi_dir_offset = 0;481 }482 483 if (mode == BCH_RENAME_OVERWRITE) {484 if (S_ISDIR(src_inode_u->bi_mode) !=485 S_ISDIR(dst_inode_u->bi_mode)) {486 ret = -ENOTDIR;487 goto err;488 }489 490 if (S_ISDIR(dst_inode_u->bi_mode)) {491 ret = bch2_empty_dir_trans(trans, dst_inum);492 if (ret)493 goto err;494 }495 }496 497 if (bch2_reinherit_attrs(src_inode_u, dst_dir_u) &&498 S_ISDIR(src_inode_u->bi_mode)) {499 ret = -EXDEV;500 goto err;501 }502 503 if (mode == BCH_RENAME_EXCHANGE &&504 bch2_reinherit_attrs(dst_inode_u, src_dir_u) &&505 S_ISDIR(dst_inode_u->bi_mode)) {506 ret = -EXDEV;507 goto err;508 }509 510 if (is_subdir_for_nlink(src_inode_u)) {511 src_dir_u->bi_nlink--;512 dst_dir_u->bi_nlink++;513 }514 515 if (dst_inum.inum && is_subdir_for_nlink(dst_inode_u)) {516 dst_dir_u->bi_nlink--;517 src_dir_u->bi_nlink += mode == BCH_RENAME_EXCHANGE;518 }519 520 if (mode == BCH_RENAME_OVERWRITE)521 bch2_inode_nlink_dec(trans, dst_inode_u);522 523 src_dir_u->bi_mtime = now;524 src_dir_u->bi_ctime = now;525 526 if (src_dir.inum != dst_dir.inum) {527 dst_dir_u->bi_mtime = now;528 dst_dir_u->bi_ctime = now;529 }530 531 src_inode_u->bi_ctime = now;532 533 if (dst_inum.inum)534 dst_inode_u->bi_ctime = now;535 536 ret = bch2_inode_write(trans, &src_dir_iter, src_dir_u) ?:537 (src_dir.inum != dst_dir.inum538 ? bch2_inode_write(trans, &dst_dir_iter, dst_dir_u)539 : 0) ?:540 bch2_inode_write(trans, &src_inode_iter, src_inode_u) ?:541 (dst_inum.inum542 ? bch2_inode_write(trans, &dst_inode_iter, dst_inode_u)543 : 0);544err:545 bch2_trans_iter_exit(trans, &dst_inode_iter);546 bch2_trans_iter_exit(trans, &src_inode_iter);547 bch2_trans_iter_exit(trans, &dst_dir_iter);548 bch2_trans_iter_exit(trans, &src_dir_iter);549 return ret;550}551