11
11
12
12
#include <linux/posix_acl.h>
13
13
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
+
14
19
int bch2_create_trans (struct btree_trans * trans ,
15
20
subvol_inum dir ,
16
21
struct bch_inode_unpacked * dir_u ,
@@ -19,6 +24,7 @@ int bch2_create_trans(struct btree_trans *trans,
19
24
uid_t uid , gid_t gid , umode_t mode , dev_t rdev ,
20
25
struct posix_acl * default_acl ,
21
26
struct posix_acl * acl ,
27
+ subvol_inum snapshot_src ,
22
28
unsigned flags )
23
29
{
24
30
struct bch_fs * c = trans -> c ;
@@ -27,10 +33,9 @@ int bch2_create_trans(struct btree_trans *trans,
27
33
subvol_inum new_inum = dir ;
28
34
u64 now = bch2_current_time (c );
29
35
u64 cpu = raw_smp_processor_id ();
30
- u64 dir_offset = 0 ;
31
36
u64 dir_target ;
32
37
u32 snapshot ;
33
- unsigned dir_type ;
38
+ unsigned dir_type = mode_to_type ( mode ) ;
34
39
int ret ;
35
40
36
41
ret = bch2_subvolume_get_snapshot (trans , dir .subvol , & snapshot );
@@ -41,37 +46,122 @@ int bch2_create_trans(struct btree_trans *trans,
41
46
if (ret )
42
47
goto err ;
43
48
44
- bch2_inode_init_late (new_inode , now , uid , gid , mode , rdev , dir_u );
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 );
45
52
46
- if (! name )
47
- new_inode -> bi_flags |= BCH_INODE_UNLINKED ;
53
+ if (flags & BCH_CREATE_TMPFILE )
54
+ new_inode -> bi_flags |= BCH_INODE_UNLINKED ;
48
55
49
- ret = bch2_inode_create (trans , & inode_iter , new_inode , snapshot , cpu );
50
- if (ret )
51
- goto err ;
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: */
70
+ struct btree_iter subvol_iter ;
71
+ struct bkey_s_c k ;
72
+
73
+ bch2_trans_iter_init (trans , & subvol_iter , BTREE_ID_subvolumes ,
74
+ POS (0 , snapshot_src .subvol ), 0 );
75
+ k = bch2_btree_iter_peek_slot (& subvol_iter );
76
+
77
+ ret = bkey_err (k );
78
+ if (!ret && k .k -> type != KEY_TYPE_subvolume ) {
79
+ bch_err (c , "subvolume %u not found" ,
80
+ snapshot_src .subvol );
81
+ ret = - ENOENT ;
82
+ }
83
+
84
+ if (!ret )
85
+ snapshot_src .inum = le64_to_cpu (bkey_s_c_to_subvolume (k ).v -> inode );
86
+ bch2_trans_iter_exit (trans , & subvol_iter );
87
+
88
+ if (ret )
89
+ goto err ;
90
+ }
91
+
92
+ ret = bch2_inode_peek (trans , & inode_iter , new_inode , snapshot_src ,
93
+ BTREE_ITER_INTENT );
94
+ if (ret )
95
+ goto err ;
96
+
97
+ if (new_inode -> bi_subvol != snapshot_src .subvol ) {
98
+ /* Not a subvolume root: */
99
+ ret = - EINVAL ;
100
+ goto err ;
101
+ }
102
+
103
+ /*
104
+ * If we're not root, we have to own the subvolume being
105
+ * snapshotted:
106
+ */
107
+ if (uid && new_inode -> bi_uid != uid ) {
108
+ ret = - EPERM ;
109
+ goto err ;
110
+ }
111
+
112
+ flags |= BCH_CREATE_SUBVOL ;
113
+ }
52
114
53
115
new_inum .inum = new_inode -> bi_inum ;
54
116
dir_target = new_inode -> bi_inum ;
55
- dir_type = mode_to_type (new_inode -> bi_mode );
56
117
57
- if (default_acl ) {
58
- ret = bch2_set_acl_trans (trans , new_inum , new_inode ,
59
- default_acl , ACL_TYPE_DEFAULT );
118
+ if (flags & BCH_CREATE_SUBVOL ) {
119
+ u32 new_subvol , dir_snapshot ;
120
+
121
+ ret = bch2_subvolume_create (trans , new_inode -> bi_inum ,
122
+ snapshot_src .subvol ,
123
+ & new_subvol , & snapshot ,
124
+ (flags & BCH_CREATE_SNAPSHOT_RO ) != 0 );
60
125
if (ret )
61
126
goto err ;
62
- }
63
127
64
- if (acl ) {
65
- ret = bch2_set_acl_trans (trans , new_inum , new_inode ,
66
- acl , ACL_TYPE_ACCESS );
128
+ new_inode -> bi_parent_subvol = dir .subvol ;
129
+ new_inode -> bi_subvol = new_subvol ;
130
+ new_inum .subvol = new_subvol ;
131
+ dir_target = new_subvol ;
132
+ dir_type = DT_SUBVOL ;
133
+
134
+ ret = bch2_subvolume_get_snapshot (trans , dir .subvol , & dir_snapshot );
135
+ if (ret )
136
+ goto err ;
137
+
138
+ bch2_btree_iter_set_snapshot (& dir_iter , dir_snapshot );
139
+ ret = bch2_btree_iter_traverse (& dir_iter );
67
140
if (ret )
68
141
goto err ;
69
142
}
70
143
71
- if (name ) {
144
+ if (!(flags & BCH_CREATE_SNAPSHOT )) {
145
+ if (default_acl ) {
146
+ ret = bch2_set_acl_trans (trans , new_inum , new_inode ,
147
+ default_acl , ACL_TYPE_DEFAULT );
148
+ if (ret )
149
+ goto err ;
150
+ }
151
+
152
+ if (acl ) {
153
+ ret = bch2_set_acl_trans (trans , new_inum , new_inode ,
154
+ acl , ACL_TYPE_ACCESS );
155
+ if (ret )
156
+ goto err ;
157
+ }
158
+ }
159
+
160
+ if (!(flags & BCH_CREATE_TMPFILE )) {
72
161
struct bch_hash_info dir_hash = bch2_hash_info_init (c , dir_u );
162
+ u64 dir_offset ;
73
163
74
- if (S_ISDIR (new_inode -> bi_mode ))
164
+ if (is_subdir_for_nlink (new_inode ))
75
165
dir_u -> bi_nlink ++ ;
76
166
dir_u -> bi_mtime = dir_u -> bi_ctime = now ;
77
167
@@ -87,11 +177,11 @@ int bch2_create_trans(struct btree_trans *trans,
87
177
BCH_HASH_SET_MUST_CREATE );
88
178
if (ret )
89
179
goto err ;
90
- }
91
180
92
- if (c -> sb .version >= bcachefs_metadata_version_inode_backpointers ) {
93
- new_inode -> bi_dir = dir_u -> bi_inum ;
94
- new_inode -> bi_dir_offset = dir_offset ;
181
+ if (c -> sb .version >= bcachefs_metadata_version_inode_backpointers ) {
182
+ new_inode -> bi_dir = dir_u -> bi_inum ;
183
+ new_inode -> bi_dir_offset = dir_offset ;
184
+ }
95
185
}
96
186
97
187
inode_iter .flags &= ~BTREE_ITER_ALL_SNAPSHOTS ;
@@ -160,7 +250,8 @@ int bch2_unlink_trans(struct btree_trans *trans,
160
250
subvol_inum dir ,
161
251
struct bch_inode_unpacked * dir_u ,
162
252
struct bch_inode_unpacked * inode_u ,
163
- const struct qstr * name )
253
+ const struct qstr * name ,
254
+ int deleting_snapshot )
164
255
{
165
256
struct bch_fs * c = trans -> c ;
166
257
struct btree_iter dir_iter = { NULL };
@@ -169,6 +260,7 @@ int bch2_unlink_trans(struct btree_trans *trans,
169
260
struct bch_hash_info dir_hash ;
170
261
subvol_inum inum ;
171
262
u64 now = bch2_current_time (c );
263
+ struct bkey_s_c k ;
172
264
int ret ;
173
265
174
266
ret = bch2_inode_peek (trans , & dir_iter , dir_u , dir , BTREE_ITER_INTENT );
@@ -187,29 +279,51 @@ int bch2_unlink_trans(struct btree_trans *trans,
187
279
if (ret )
188
280
goto err ;
189
281
190
- if (inode_u -> bi_dir == dirent_iter .pos .inode &&
191
- inode_u -> bi_dir_offset == dirent_iter .pos .offset ) {
192
- inode_u -> bi_dir = 0 ;
193
- inode_u -> bi_dir_offset = 0 ;
282
+ if (deleting_snapshot == 1 && !inode_u -> bi_subvol ) {
283
+ ret = - ENOENT ;
284
+ goto err ;
194
285
}
195
286
196
- if (S_ISDIR (inode_u -> bi_mode )) {
287
+ if (deleting_snapshot <= 0 && S_ISDIR (inode_u -> bi_mode )) {
197
288
ret = bch2_empty_dir_trans (trans , inum );
198
289
if (ret )
199
290
goto err ;
200
291
}
201
292
202
- if (dir .subvol != inum .subvol ) {
203
- ret = bch2_subvolume_delete (trans , inum .subvol , false);
293
+ if (inode_u -> bi_subvol ) {
294
+ ret = bch2_subvolume_delete (trans , inode_u -> bi_subvol ,
295
+ deleting_snapshot );
296
+ if (ret )
297
+ goto err ;
298
+
299
+ k = bch2_btree_iter_peek_slot (& dirent_iter );
300
+ ret = bkey_err (k );
301
+ if (ret )
302
+ goto err ;
303
+
304
+ /*
305
+ * If we're deleting a subvolume, we need to really delete the
306
+ * dirent, not just emit a whiteout in the current snapshot:
307
+ */
308
+ bch2_btree_iter_set_snapshot (& dirent_iter , k .k -> p .snapshot );
309
+ ret = bch2_btree_iter_traverse (& dirent_iter );
204
310
if (ret )
205
311
goto err ;
206
312
}
207
313
314
+ if (inode_u -> bi_dir == dirent_iter .pos .inode &&
315
+ inode_u -> bi_dir_offset == dirent_iter .pos .offset ) {
316
+ inode_u -> bi_dir = 0 ;
317
+ inode_u -> bi_dir_offset = 0 ;
318
+ }
319
+
208
320
dir_u -> bi_mtime = dir_u -> bi_ctime = inode_u -> bi_ctime = now ;
209
- dir_u -> bi_nlink -= S_ISDIR (inode_u -> bi_mode );
321
+ dir_u -> bi_nlink -= is_subdir_for_nlink (inode_u );
210
322
bch2_inode_nlink_dec (inode_u );
211
323
212
- ret = bch2_dirent_delete_at (trans , & dir_hash , & dirent_iter ) ?:
324
+ ret = bch2_hash_delete_at (trans , bch2_dirent_hash_desc ,
325
+ & dir_hash , & dirent_iter ,
326
+ BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE ) ?:
213
327
bch2_inode_write (trans , & dir_iter , dir_u ) ?:
214
328
bch2_inode_write (trans , & inode_iter , inode_u );
215
329
err :
@@ -348,12 +462,12 @@ int bch2_rename_trans(struct btree_trans *trans,
348
462
goto err ;
349
463
}
350
464
351
- if (S_ISDIR (src_inode_u -> bi_mode )) {
465
+ if (is_subdir_for_nlink (src_inode_u )) {
352
466
src_dir_u -> bi_nlink -- ;
353
467
dst_dir_u -> bi_nlink ++ ;
354
468
}
355
469
356
- if (dst_inum .inum && S_ISDIR (dst_inode_u -> bi_mode )) {
470
+ if (dst_inum .inum && is_subdir_for_nlink (dst_inode_u )) {
357
471
dst_dir_u -> bi_nlink -- ;
358
472
src_dir_u -> bi_nlink += mode == BCH_RENAME_EXCHANGE ;
359
473
}
0 commit comments