Skip to content

Commit 9590e5c

Browse files
adam900710kdave
authored andcommitted
btrfs-progs: do not call btrfs_record_file_extent() out of btrfs-convert
The function btrfs_record_file_extent() has extra handling that's specific to convert, like allowing the range to be split by block group boundary and image file extent boundary. All of these split can only lead to corruption for non-converted fs. As the only caller out of btrfs-convert is rootdir, which expects the file extent item insert to respect the reserved data extent, and never to be split. Thankfully this is not going to cause huge problem, as btrfs_record_file_extent() has extra checks if the data extent overlaps with any existing one, and if it doesn't the handling will be the same as the kernel. But to avoid abuse, change btrfs_record_file_extent() by: - Rename it to btrfs_convert_file_extent() And add extra comments on that it is specific to btrfs-convert. - Move it to convert/common.[ch] - Introduce a helper insert_reserved_file_extent() for rootdir.c Signed-off-by: Qu Wenruo <wqu@suse.com>
1 parent 85ca0a6 commit 9590e5c

File tree

8 files changed

+349
-255
lines changed

8 files changed

+349
-255
lines changed

common/extent-tree-utils.c

Lines changed: 0 additions & 240 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,13 @@
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-
}

common/extent-tree-utils.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,5 @@ struct btrfs_trans_handle;
2727

2828
int btrfs_next_extent_item(struct btrfs_root *root, struct btrfs_path *path,
2929
u64 max_objectid);
30-
int btrfs_record_file_extent(struct btrfs_trans_handle *trans,
31-
struct btrfs_root *root, u64 objectid,
32-
struct btrfs_inode_item *inode,
33-
u64 file_pos, u64 disk_bytenr,
34-
u64 num_bytes);
3530

3631
#endif

0 commit comments

Comments
 (0)