]> git.sesse.net Git - bcachefs-tools-debian/blob - libbcachefs/fs-common.c
Add upstream files
[bcachefs-tools-debian] / libbcachefs / fs-common.c
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"
9 #include "xattr.h"
10
11 #include <linux/posix_acl.h>
12
13 int bch2_create_trans(struct btree_trans *trans, u64 dir_inum,
14                       struct bch_inode_unpacked *dir_u,
15                       struct bch_inode_unpacked *new_inode,
16                       const struct qstr *name,
17                       uid_t uid, gid_t gid, umode_t mode, dev_t rdev,
18                       struct posix_acl *default_acl,
19                       struct posix_acl *acl)
20 {
21         struct bch_fs *c = trans->c;
22         struct btree_iter *dir_iter = NULL;
23         struct bch_hash_info hash = bch2_hash_info_init(c, new_inode);
24         u64 now = bch2_current_time(trans->c);
25         int ret;
26
27         dir_iter = bch2_inode_peek(trans, dir_u, dir_inum, BTREE_ITER_INTENT);
28         ret = PTR_ERR_OR_ZERO(dir_iter);
29         if (ret)
30                 goto err;
31
32         bch2_inode_init_late(new_inode, now, uid, gid, mode, rdev, dir_u);
33
34         if (!name)
35                 new_inode->bi_flags |= BCH_INODE_UNLINKED;
36
37         ret = bch2_inode_create(trans, new_inode,
38                                 BLOCKDEV_INODE_MAX, 0,
39                                 &c->unused_inode_hint);
40         if (ret)
41                 goto err;
42
43         if (default_acl) {
44                 ret = bch2_set_acl_trans(trans, new_inode, &hash,
45                                          default_acl, ACL_TYPE_DEFAULT);
46                 if (ret)
47                         goto err;
48         }
49
50         if (acl) {
51                 ret = bch2_set_acl_trans(trans, new_inode, &hash,
52                                          acl, ACL_TYPE_ACCESS);
53                 if (ret)
54                         goto err;
55         }
56
57         if (name) {
58                 struct bch_hash_info dir_hash = bch2_hash_info_init(c, dir_u);
59                 dir_u->bi_mtime = dir_u->bi_ctime = now;
60
61                 if (S_ISDIR(new_inode->bi_mode))
62                         dir_u->bi_nlink++;
63
64                 ret = bch2_inode_write(trans, dir_iter, dir_u);
65                 if (ret)
66                         goto err;
67
68                 ret = bch2_dirent_create(trans, dir_inum, &dir_hash,
69                                          mode_to_type(new_inode->bi_mode),
70                                          name, new_inode->bi_inum,
71                                          BCH_HASH_SET_MUST_CREATE);
72                 if (ret)
73                         goto err;
74         }
75 err:
76         bch2_trans_iter_put(trans, dir_iter);
77         return ret;
78 }
79
80 int bch2_link_trans(struct btree_trans *trans, u64 dir_inum,
81                     u64 inum, struct bch_inode_unpacked *dir_u,
82                     struct bch_inode_unpacked *inode_u, const struct qstr *name)
83 {
84         struct btree_iter *dir_iter = NULL, *inode_iter = NULL;
85         struct bch_hash_info dir_hash;
86         u64 now = bch2_current_time(trans->c);
87         int ret;
88
89         inode_iter = bch2_inode_peek(trans, inode_u, inum, BTREE_ITER_INTENT);
90         ret = PTR_ERR_OR_ZERO(inode_iter);
91         if (ret)
92                 goto err;
93
94         inode_u->bi_ctime = now;
95         bch2_inode_nlink_inc(inode_u);
96
97         dir_iter = bch2_inode_peek(trans, dir_u, dir_inum, 0);
98         ret = PTR_ERR_OR_ZERO(dir_iter);
99         if (ret)
100                 goto err;
101
102         dir_u->bi_mtime = dir_u->bi_ctime = now;
103
104         dir_hash = bch2_hash_info_init(trans->c, dir_u);
105
106         ret =   bch2_dirent_create(trans, dir_inum, &dir_hash,
107                                   mode_to_type(inode_u->bi_mode),
108                                   name, inum, BCH_HASH_SET_MUST_CREATE) ?:
109                 bch2_inode_write(trans, dir_iter, dir_u) ?:
110                 bch2_inode_write(trans, inode_iter, inode_u);
111 err:
112         bch2_trans_iter_put(trans, dir_iter);
113         bch2_trans_iter_put(trans, inode_iter);
114         return ret;
115 }
116
117 int bch2_unlink_trans(struct btree_trans *trans,
118                       u64 dir_inum, struct bch_inode_unpacked *dir_u,
119                       struct bch_inode_unpacked *inode_u,
120                       const struct qstr *name)
121 {
122         struct btree_iter *dir_iter = NULL, *dirent_iter = NULL,
123                           *inode_iter = NULL;
124         struct bch_hash_info dir_hash;
125         u64 inum, now = bch2_current_time(trans->c);
126         struct bkey_s_c k;
127         int ret;
128
129         dir_iter = bch2_inode_peek(trans, dir_u, dir_inum, BTREE_ITER_INTENT);
130         ret = PTR_ERR_OR_ZERO(dir_iter);
131         if (ret)
132                 goto err;
133
134         dir_hash = bch2_hash_info_init(trans->c, dir_u);
135
136         dirent_iter = __bch2_dirent_lookup_trans(trans, dir_inum, &dir_hash,
137                                                  name, BTREE_ITER_INTENT);
138         ret = PTR_ERR_OR_ZERO(dirent_iter);
139         if (ret)
140                 goto err;
141
142         k = bch2_btree_iter_peek_slot(dirent_iter);
143         inum = le64_to_cpu(bkey_s_c_to_dirent(k).v->d_inum);
144
145         inode_iter = bch2_inode_peek(trans, inode_u, inum, BTREE_ITER_INTENT);
146         ret = PTR_ERR_OR_ZERO(inode_iter);
147         if (ret)
148                 goto err;
149
150         dir_u->bi_mtime = dir_u->bi_ctime = inode_u->bi_ctime = now;
151         dir_u->bi_nlink -= S_ISDIR(inode_u->bi_mode);
152         bch2_inode_nlink_dec(inode_u);
153
154         ret =   (S_ISDIR(inode_u->bi_mode)
155                  ? bch2_empty_dir_trans(trans, inum)
156                  : 0) ?:
157                 bch2_dirent_delete_at(trans, &dir_hash, dirent_iter) ?:
158                 bch2_inode_write(trans, dir_iter, dir_u) ?:
159                 bch2_inode_write(trans, inode_iter, inode_u);
160 err:
161         bch2_trans_iter_put(trans, inode_iter);
162         bch2_trans_iter_put(trans, dirent_iter);
163         bch2_trans_iter_put(trans, dir_iter);
164         return ret;
165 }
166
167 bool bch2_reinherit_attrs(struct bch_inode_unpacked *dst_u,
168                           struct bch_inode_unpacked *src_u)
169 {
170         u64 src, dst;
171         unsigned id;
172         bool ret = false;
173
174         for (id = 0; id < Inode_opt_nr; id++) {
175                 if (dst_u->bi_fields_set & (1 << id))
176                         continue;
177
178                 src = bch2_inode_opt_get(src_u, id);
179                 dst = bch2_inode_opt_get(dst_u, id);
180
181                 if (src == dst)
182                         continue;
183
184                 bch2_inode_opt_set(dst_u, id, src);
185                 ret = true;
186         }
187
188         return ret;
189 }
190
191 int bch2_rename_trans(struct btree_trans *trans,
192                       u64 src_dir, struct bch_inode_unpacked *src_dir_u,
193                       u64 dst_dir, struct bch_inode_unpacked *dst_dir_u,
194                       struct bch_inode_unpacked *src_inode_u,
195                       struct bch_inode_unpacked *dst_inode_u,
196                       const struct qstr *src_name,
197                       const struct qstr *dst_name,
198                       enum bch_rename_mode mode)
199 {
200         struct btree_iter *src_dir_iter = NULL, *dst_dir_iter = NULL;
201         struct btree_iter *src_inode_iter = NULL, *dst_inode_iter = NULL;
202         struct bch_hash_info src_hash, dst_hash;
203         u64 src_inode, dst_inode, now = bch2_current_time(trans->c);
204         int ret;
205
206         src_dir_iter = bch2_inode_peek(trans, src_dir_u, src_dir,
207                                        BTREE_ITER_INTENT);
208         ret = PTR_ERR_OR_ZERO(src_dir_iter);
209         if (ret)
210                 goto err;
211
212         src_hash = bch2_hash_info_init(trans->c, src_dir_u);
213
214         if (dst_dir != src_dir) {
215                 dst_dir_iter = bch2_inode_peek(trans, dst_dir_u, dst_dir,
216                                                BTREE_ITER_INTENT);
217                 ret = PTR_ERR_OR_ZERO(dst_dir_iter);
218                 if (ret)
219                         goto err;
220
221                 dst_hash = bch2_hash_info_init(trans->c, dst_dir_u);
222         } else {
223                 dst_dir_u = src_dir_u;
224                 dst_hash = src_hash;
225         }
226
227         ret = bch2_dirent_rename(trans,
228                                  src_dir, &src_hash,
229                                  dst_dir, &dst_hash,
230                                  src_name, &src_inode,
231                                  dst_name, &dst_inode,
232                                  mode);
233         if (ret)
234                 goto err;
235
236         src_inode_iter = bch2_inode_peek(trans, src_inode_u, src_inode,
237                                          BTREE_ITER_INTENT);
238         ret = PTR_ERR_OR_ZERO(src_inode_iter);
239         if (ret)
240                 goto err;
241
242         if (dst_inode) {
243                 dst_inode_iter = bch2_inode_peek(trans, dst_inode_u, dst_inode,
244                                                  BTREE_ITER_INTENT);
245                 ret = PTR_ERR_OR_ZERO(dst_inode_iter);
246                 if (ret)
247                         goto err;
248         }
249
250         if (mode == BCH_RENAME_OVERWRITE) {
251                 if (S_ISDIR(src_inode_u->bi_mode) !=
252                     S_ISDIR(dst_inode_u->bi_mode)) {
253                         ret = -ENOTDIR;
254                         goto err;
255                 }
256
257                 if (S_ISDIR(dst_inode_u->bi_mode) &&
258                     bch2_empty_dir_trans(trans, dst_inode)) {
259                         ret = -ENOTEMPTY;
260                         goto err;
261                 }
262         }
263
264         if (bch2_reinherit_attrs(src_inode_u, dst_dir_u) &&
265             S_ISDIR(src_inode_u->bi_mode)) {
266                 ret = -EXDEV;
267                 goto err;
268         }
269
270         if (mode == BCH_RENAME_EXCHANGE &&
271             bch2_reinherit_attrs(dst_inode_u, src_dir_u) &&
272             S_ISDIR(dst_inode_u->bi_mode)) {
273                 ret = -EXDEV;
274                 goto err;
275         }
276
277         if (S_ISDIR(src_inode_u->bi_mode)) {
278                 src_dir_u->bi_nlink--;
279                 dst_dir_u->bi_nlink++;
280         }
281
282         if (dst_inode && S_ISDIR(dst_inode_u->bi_mode)) {
283                 dst_dir_u->bi_nlink--;
284                 src_dir_u->bi_nlink += mode == BCH_RENAME_EXCHANGE;
285         }
286
287         if (mode == BCH_RENAME_OVERWRITE)
288                 bch2_inode_nlink_dec(dst_inode_u);
289
290         src_dir_u->bi_mtime             = now;
291         src_dir_u->bi_ctime             = now;
292
293         if (src_dir != dst_dir) {
294                 dst_dir_u->bi_mtime     = now;
295                 dst_dir_u->bi_ctime     = now;
296         }
297
298         src_inode_u->bi_ctime           = now;
299
300         if (dst_inode)
301                 dst_inode_u->bi_ctime   = now;
302
303         ret =   bch2_inode_write(trans, src_dir_iter, src_dir_u) ?:
304                 (src_dir != dst_dir
305                  ? bch2_inode_write(trans, dst_dir_iter, dst_dir_u)
306                  : 0 ) ?:
307                 bch2_inode_write(trans, src_inode_iter, src_inode_u) ?:
308                 (dst_inode
309                  ? bch2_inode_write(trans, dst_inode_iter, dst_inode_u)
310                  : 0 );
311 err:
312         bch2_trans_iter_put(trans, dst_inode_iter);
313         bch2_trans_iter_put(trans, src_inode_iter);
314         bch2_trans_iter_put(trans, dst_dir_iter);
315         bch2_trans_iter_put(trans, src_dir_iter);
316         return ret;
317 }