1111
1212#include <linux/posix_acl.h>
1313
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+
1419int bch2_create_trans (struct btree_trans * trans ,
1520 subvol_inum dir ,
1621 struct bch_inode_unpacked * dir_u ,
@@ -19,6 +24,7 @@ int bch2_create_trans(struct btree_trans *trans,
1924 uid_t uid , gid_t gid , umode_t mode , dev_t rdev ,
2025 struct posix_acl * default_acl ,
2126 struct posix_acl * acl ,
27+ subvol_inum snapshot_src ,
2228 unsigned flags )
2329{
2430 struct bch_fs * c = trans -> c ;
@@ -27,10 +33,9 @@ int bch2_create_trans(struct btree_trans *trans,
2733 subvol_inum new_inum = dir ;
2834 u64 now = bch2_current_time (c );
2935 u64 cpu = raw_smp_processor_id ();
30- u64 dir_offset = 0 ;
3136 u64 dir_target ;
3237 u32 snapshot ;
33- unsigned dir_type ;
38+ unsigned dir_type = mode_to_type ( mode ) ;
3439 int ret ;
3540
3641 ret = bch2_subvolume_get_snapshot (trans , dir .subvol , & snapshot );
@@ -41,37 +46,122 @@ int bch2_create_trans(struct btree_trans *trans,
4146 if (ret )
4247 goto err ;
4348
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 );
4552
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 ;
4855
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+ }
52114
53115 new_inum .inum = new_inode -> bi_inum ;
54116 dir_target = new_inode -> bi_inum ;
55- dir_type = mode_to_type (new_inode -> bi_mode );
56117
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 );
60125 if (ret )
61126 goto err ;
62- }
63127
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 );
67140 if (ret )
68141 goto err ;
69142 }
70143
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 )) {
72161 struct bch_hash_info dir_hash = bch2_hash_info_init (c , dir_u );
162+ u64 dir_offset ;
73163
74- if (S_ISDIR (new_inode -> bi_mode ))
164+ if (is_subdir_for_nlink (new_inode ))
75165 dir_u -> bi_nlink ++ ;
76166 dir_u -> bi_mtime = dir_u -> bi_ctime = now ;
77167
@@ -87,11 +177,11 @@ int bch2_create_trans(struct btree_trans *trans,
87177 BCH_HASH_SET_MUST_CREATE );
88178 if (ret )
89179 goto err ;
90- }
91180
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+ }
95185 }
96186
97187 inode_iter .flags &= ~BTREE_ITER_ALL_SNAPSHOTS ;
@@ -160,7 +250,8 @@ int bch2_unlink_trans(struct btree_trans *trans,
160250 subvol_inum dir ,
161251 struct bch_inode_unpacked * dir_u ,
162252 struct bch_inode_unpacked * inode_u ,
163- const struct qstr * name )
253+ const struct qstr * name ,
254+ int deleting_snapshot )
164255{
165256 struct bch_fs * c = trans -> c ;
166257 struct btree_iter dir_iter = { NULL };
@@ -169,6 +260,7 @@ int bch2_unlink_trans(struct btree_trans *trans,
169260 struct bch_hash_info dir_hash ;
170261 subvol_inum inum ;
171262 u64 now = bch2_current_time (c );
263+ struct bkey_s_c k ;
172264 int ret ;
173265
174266 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,
187279 if (ret )
188280 goto err ;
189281
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 ;
194285 }
195286
196- if (S_ISDIR (inode_u -> bi_mode )) {
287+ if (deleting_snapshot <= 0 && S_ISDIR (inode_u -> bi_mode )) {
197288 ret = bch2_empty_dir_trans (trans , inum );
198289 if (ret )
199290 goto err ;
200291 }
201292
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 );
204310 if (ret )
205311 goto err ;
206312 }
207313
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+
208320 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 );
210322 bch2_inode_nlink_dec (inode_u );
211323
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 ) ?:
213327 bch2_inode_write (trans , & dir_iter , dir_u ) ?:
214328 bch2_inode_write (trans , & inode_iter , inode_u );
215329err :
@@ -348,12 +462,12 @@ int bch2_rename_trans(struct btree_trans *trans,
348462 goto err ;
349463 }
350464
351- if (S_ISDIR (src_inode_u -> bi_mode )) {
465+ if (is_subdir_for_nlink (src_inode_u )) {
352466 src_dir_u -> bi_nlink -- ;
353467 dst_dir_u -> bi_nlink ++ ;
354468 }
355469
356- if (dst_inum .inum && S_ISDIR (dst_inode_u -> bi_mode )) {
470+ if (dst_inum .inum && is_subdir_for_nlink (dst_inode_u )) {
357471 dst_dir_u -> bi_nlink -- ;
358472 src_dir_u -> bi_nlink += mode == BCH_RENAME_EXCHANGE ;
359473 }
0 commit comments