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