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