1515 */
1616
1717#include "kerncompat.h"
18- #include <errno.h>
1918#include <stddef.h>
2019#include "kernel-shared/accessors.h"
2120#include "kernel-shared/uapi/btrfs_tree.h"
2221#include "kernel-shared/ctree.h"
2322#include "kernel-shared/disk-io.h"
24- #include "kernel-shared/file-item.h"
2523#include "kernel-shared/transaction.h"
26- #include "kernel-shared/free-space-tree.h"
27- #include "common/internal.h"
2824#include "common/extent-tree-utils.h"
29- #include "common/messages.h"
3025
3126/*
3227 * Search in extent tree to found next meta/data extent. Caller needs to check
@@ -50,238 +45,3 @@ int btrfs_next_extent_item(struct btrfs_root *root, struct btrfs_path *path,
5045 return 0 ;
5146 }
5247}
53-
54- static void __get_extent_size (struct btrfs_root * root , struct btrfs_path * path ,
55- u64 * start , u64 * len )
56- {
57- struct btrfs_key key ;
58-
59- btrfs_item_key_to_cpu (path -> nodes [0 ], & key , path -> slots [0 ]);
60- BUG_ON (!(key .type == BTRFS_EXTENT_ITEM_KEY ||
61- key .type == BTRFS_METADATA_ITEM_KEY ));
62- * start = key .objectid ;
63- if (key .type == BTRFS_EXTENT_ITEM_KEY )
64- * len = key .offset ;
65- else
66- * len = root -> fs_info -> nodesize ;
67- }
68-
69- /*
70- * Find first overlap extent for range [bytenr, bytenr + len).
71- *
72- * Return 0 for found and point path to it.
73- * Return >0 for not found.
74- * Return <0 for err
75- */
76- static int btrfs_search_overlap_extent (struct btrfs_root * root ,
77- struct btrfs_path * path , u64 bytenr , u64 len )
78- {
79- struct btrfs_key key ;
80- u64 cur_start ;
81- u64 cur_len ;
82- int ret ;
83-
84- key .objectid = bytenr ;
85- key .type = BTRFS_EXTENT_DATA_KEY ;
86- key .offset = (u64 )- 1 ;
87-
88- ret = btrfs_search_slot (NULL , root , & key , path , 0 , 0 );
89- if (ret < 0 )
90- return ret ;
91- if (ret == 0 ) {
92- error_msg (ERROR_MSG_UNEXPECTED , "EXTENT_DATA found at %llu" , bytenr );
93- return - EUCLEAN ;
94- }
95-
96- ret = btrfs_previous_extent_item (root , path , 0 );
97- if (ret < 0 )
98- return ret ;
99- /* No previous, check next extent. */
100- if (ret > 0 )
101- goto next ;
102- __get_extent_size (root , path , & cur_start , & cur_len );
103- /* Tail overlap. */
104- if (cur_start + cur_len > bytenr )
105- return 1 ;
106-
107- next :
108- ret = btrfs_next_extent_item (root , path , bytenr + len );
109- if (ret < 0 )
110- return ret ;
111- /* No next, prev already checked, no overlap. */
112- if (ret > 0 )
113- return 0 ;
114- __get_extent_size (root , path , & cur_start , & cur_len );
115- /* Head overlap.*/
116- if (cur_start < bytenr + len )
117- return 1 ;
118- return 0 ;
119- }
120-
121- static int __btrfs_record_file_extent (struct btrfs_trans_handle * trans ,
122- struct btrfs_root * root , u64 objectid ,
123- struct btrfs_inode_item * inode ,
124- u64 file_pos , u64 disk_bytenr ,
125- u64 * ret_num_bytes )
126- {
127- int ret ;
128- struct btrfs_fs_info * info = root -> fs_info ;
129- struct btrfs_root * extent_root = btrfs_extent_root (info , disk_bytenr );
130- struct extent_buffer * leaf ;
131- struct btrfs_file_extent_item * fi ;
132- struct btrfs_key ins_key ;
133- struct btrfs_path * path ;
134- struct btrfs_extent_item * ei ;
135- u64 nbytes ;
136- u64 extent_num_bytes ;
137- u64 extent_bytenr ;
138- u64 extent_offset ;
139- u64 num_bytes = * ret_num_bytes ;
140-
141- /*
142- * @objectid should be an inode number, thus it must not be smaller
143- * than BTRFS_FIRST_FREE_OBJECTID.
144- */
145- UASSERT (objectid >= BTRFS_FIRST_FREE_OBJECTID );
146-
147- /*
148- * All supported file system should not use its 0 extent. As it's for
149- * hole. And hole extent has no size limit, no need to loop.
150- */
151- if (disk_bytenr == 0 ) {
152- ret = btrfs_insert_file_extent (trans , root , objectid ,
153- file_pos , disk_bytenr ,
154- num_bytes , num_bytes );
155- return ret ;
156- }
157- num_bytes = min_t (u64 , num_bytes , BTRFS_MAX_EXTENT_SIZE );
158-
159- path = btrfs_alloc_path ();
160- if (!path )
161- return - ENOMEM ;
162-
163- /* First to check extent overlap. */
164- ret = btrfs_search_overlap_extent (extent_root , path , disk_bytenr , num_bytes );
165- if (ret < 0 )
166- goto fail ;
167- if (ret > 0 ) {
168- /* Found overlap. */
169- u64 cur_start ;
170- u64 cur_len ;
171-
172- __get_extent_size (extent_root , path , & cur_start , & cur_len );
173- /* For convert case, this extent should be a subset of existing one. */
174- if (disk_bytenr < cur_start ) {
175- error_msg (ERROR_MSG_UNEXPECTED ,
176- "invalid range disk_bytenr < cur_start: %llu < %llu" ,
177- disk_bytenr , cur_start );
178- ret = - EUCLEAN ;
179- goto fail ;
180- }
181-
182- extent_bytenr = cur_start ;
183- extent_num_bytes = cur_len ;
184- extent_offset = disk_bytenr - extent_bytenr ;
185- } else {
186- /* No overlap, create new extent. */
187- btrfs_release_path (path );
188- ins_key .objectid = disk_bytenr ;
189- ins_key .type = BTRFS_EXTENT_ITEM_KEY ;
190- ins_key .offset = num_bytes ;
191-
192- ret = btrfs_insert_empty_item (trans , extent_root , path ,
193- & ins_key , sizeof (* ei ));
194- if (ret == 0 ) {
195- leaf = path -> nodes [0 ];
196- ei = btrfs_item_ptr (leaf , path -> slots [0 ],
197- struct btrfs_extent_item );
198-
199- btrfs_set_extent_refs (leaf , ei , 0 );
200- btrfs_set_extent_generation (leaf , ei , trans -> transid );
201- btrfs_set_extent_flags (leaf , ei ,
202- BTRFS_EXTENT_FLAG_DATA );
203- btrfs_mark_buffer_dirty (leaf );
204-
205- ret = btrfs_update_block_group (trans , disk_bytenr ,
206- num_bytes , 1 , 0 );
207- if (ret )
208- goto fail ;
209- } else if (ret != - EEXIST ) {
210- goto fail ;
211- }
212-
213- ret = remove_from_free_space_tree (trans , disk_bytenr , num_bytes );
214- if (ret )
215- goto fail ;
216-
217- btrfs_run_delayed_refs (trans , -1 );
218- extent_bytenr = disk_bytenr ;
219- extent_num_bytes = num_bytes ;
220- extent_offset = 0 ;
221- }
222- btrfs_release_path (path );
223- ins_key .objectid = objectid ;
224- ins_key .type = BTRFS_EXTENT_DATA_KEY ;
225- ins_key .offset = file_pos ;
226- ret = btrfs_insert_empty_item (trans , root , path , & ins_key , sizeof (* fi ));
227- if (ret )
228- goto fail ;
229- leaf = path -> nodes [0 ];
230- fi = btrfs_item_ptr (leaf , path -> slots [0 ], struct btrfs_file_extent_item );
231- btrfs_set_file_extent_generation (leaf , fi , trans -> transid );
232- btrfs_set_file_extent_type (leaf , fi , BTRFS_FILE_EXTENT_REG );
233- btrfs_set_file_extent_disk_bytenr (leaf , fi , extent_bytenr );
234- btrfs_set_file_extent_disk_num_bytes (leaf , fi , extent_num_bytes );
235- btrfs_set_file_extent_offset (leaf , fi , extent_offset );
236- btrfs_set_file_extent_num_bytes (leaf , fi , num_bytes );
237- btrfs_set_file_extent_ram_bytes (leaf , fi , extent_num_bytes );
238- btrfs_set_file_extent_compression (leaf , fi , 0 );
239- btrfs_set_file_extent_encryption (leaf , fi , 0 );
240- btrfs_set_file_extent_other_encoding (leaf , fi , 0 );
241- btrfs_mark_buffer_dirty (leaf );
242-
243- nbytes = btrfs_stack_inode_nbytes (inode ) + num_bytes ;
244- btrfs_set_stack_inode_nbytes (inode , nbytes );
245- btrfs_release_path (path );
246-
247- ret = btrfs_inc_extent_ref (trans , extent_bytenr , extent_num_bytes ,
248- 0 , root -> root_key .objectid , objectid ,
249- file_pos - extent_offset );
250- if (ret )
251- goto fail ;
252- ret = 0 ;
253- * ret_num_bytes = min (extent_num_bytes - extent_offset , num_bytes );
254- fail :
255- btrfs_free_path (path );
256- return ret ;
257- }
258-
259- /*
260- * Record a file extent. Do all the required works, such as inserting file
261- * extent item, inserting extent item and backref item into extent tree and
262- * updating block accounting.
263- */
264- int btrfs_record_file_extent (struct btrfs_trans_handle * trans ,
265- struct btrfs_root * root , u64 objectid ,
266- struct btrfs_inode_item * inode ,
267- u64 file_pos , u64 disk_bytenr ,
268- u64 num_bytes )
269- {
270- u64 cur_disk_bytenr = disk_bytenr ;
271- u64 cur_file_pos = file_pos ;
272- u64 cur_num_bytes = num_bytes ;
273- int ret = 0 ;
274-
275- while (num_bytes > 0 ) {
276- ret = __btrfs_record_file_extent (trans , root , objectid ,
277- inode , cur_file_pos ,
278- cur_disk_bytenr ,
279- & cur_num_bytes );
280- if (ret < 0 )
281- break ;
282- cur_disk_bytenr += cur_num_bytes ;
283- cur_file_pos += cur_num_bytes ;
284- num_bytes -= cur_num_bytes ;
285- }
286- return ret ;
287- }
0 commit comments