Skip to content

Commit 9036c10

Browse files
Yan Zhengchrismason-xx
Yan Zheng
authored andcommitted
Btrfs: update hole handling v2
This patch splits the hole insertion code out of btrfs_setattr into btrfs_cont_expand and updates btrfs_get_extent to properly handle the case that file extent items are not continuous. Signed-off-by: Yan Zheng <zheng.yan@oracle.com>
1 parent 19b9bdb commit 9036c10

File tree

4 files changed

+108
-124
lines changed

4 files changed

+108
-124
lines changed

fs/btrfs/ctree.h

+1
Original file line numberDiff line numberDiff line change
@@ -1908,6 +1908,7 @@ int btrfs_update_inode(struct btrfs_trans_handle *trans,
19081908
int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode);
19091909
int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode);
19101910
void btrfs_orphan_cleanup(struct btrfs_root *root);
1911+
int btrfs_cont_expand(struct inode *inode, loff_t size);
19111912

19121913
/* ioctl.c */
19131914
long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg);

fs/btrfs/extent_map.h

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
/* bits for the flags field */
1212
#define EXTENT_FLAG_PINNED 0 /* this entry not yet on disk, don't free it */
1313
#define EXTENT_FLAG_COMPRESSED 1
14+
#define EXTENT_FLAG_VACANCY 2 /* no file extent item found */
1415

1516
struct extent_map {
1617
struct rb_node rb_node;

fs/btrfs/file.c

+6-35
Original file line numberDiff line numberDiff line change
@@ -142,40 +142,6 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans,
142142
}
143143
set_extent_uptodate(io_tree, start_pos, end_of_last_block, GFP_NOFS);
144144

145-
/* FIXME...EIEIO, ENOSPC and more */
146-
/* insert any holes we need to create */
147-
if (isize < start_pos) {
148-
u64 last_pos_in_file;
149-
u64 hole_size;
150-
u64 mask = root->sectorsize - 1;
151-
last_pos_in_file = (isize + mask) & ~mask;
152-
hole_size = (start_pos - last_pos_in_file + mask) & ~mask;
153-
if (hole_size > 0) {
154-
btrfs_wait_ordered_range(inode, last_pos_in_file,
155-
last_pos_in_file + hole_size);
156-
mutex_lock(&BTRFS_I(inode)->extent_mutex);
157-
err = btrfs_drop_extents(trans, root, inode,
158-
last_pos_in_file,
159-
last_pos_in_file + hole_size,
160-
last_pos_in_file,
161-
&hint_byte);
162-
if (err)
163-
goto failed;
164-
165-
err = btrfs_insert_file_extent(trans, root,
166-
inode->i_ino,
167-
last_pos_in_file,
168-
0, 0, hole_size, 0,
169-
hole_size, 0, 0, 0);
170-
btrfs_drop_extent_cache(inode, last_pos_in_file,
171-
last_pos_in_file + hole_size - 1, 0);
172-
mutex_unlock(&BTRFS_I(inode)->extent_mutex);
173-
btrfs_check_file(root, inode);
174-
}
175-
if (err)
176-
goto failed;
177-
}
178-
179145
/* check for reserved extents on each page, we don't want
180146
* to reset the delalloc bit on things that already have
181147
* extents reserved.
@@ -191,7 +157,6 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans,
191157
i_size_write(inode, end_pos);
192158
btrfs_update_inode(trans, root, inode);
193159
}
194-
failed:
195160
err = btrfs_end_transaction(trans, root);
196161
out_unlock:
197162
unlock_extent(io_tree, start_pos, end_of_last_block, GFP_NOFS);
@@ -697,6 +662,12 @@ static int noinline prepare_pages(struct btrfs_root *root, struct file *file,
697662
start_pos = pos & ~((u64)root->sectorsize - 1);
698663
last_pos = ((u64)index + num_pages) << PAGE_CACHE_SHIFT;
699664

665+
if (start_pos > inode->i_size) {
666+
err = btrfs_cont_expand(inode, start_pos);
667+
if (err)
668+
return err;
669+
}
670+
700671
memset(pages, 0, num_pages * sizeof(struct page *));
701672
again:
702673
for (i = 0; i < num_pages; i++) {

fs/btrfs/inode.c

+100-89
Original file line numberDiff line numberDiff line change
@@ -2296,81 +2296,91 @@ static int btrfs_truncate_page(struct address_space *mapping, loff_t from)
22962296
return ret;
22972297
}
22982298

2299-
static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
2299+
int btrfs_cont_expand(struct inode *inode, loff_t size)
23002300
{
2301-
struct inode *inode = dentry->d_inode;
2301+
struct btrfs_trans_handle *trans;
2302+
struct btrfs_root *root = BTRFS_I(inode)->root;
2303+
struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
2304+
struct extent_map *em;
2305+
u64 mask = root->sectorsize - 1;
2306+
u64 hole_start = (inode->i_size + mask) & ~mask;
2307+
u64 block_end = (size + mask) & ~mask;
2308+
u64 last_byte;
2309+
u64 cur_offset;
2310+
u64 hole_size;
23022311
int err;
23032312

2304-
err = inode_change_ok(inode, attr);
2313+
if (size <= hole_start)
2314+
return 0;
2315+
2316+
err = btrfs_check_free_space(root, 1, 0);
23052317
if (err)
23062318
return err;
23072319

2308-
if (S_ISREG(inode->i_mode) &&
2309-
attr->ia_valid & ATTR_SIZE && attr->ia_size > inode->i_size) {
2310-
struct btrfs_trans_handle *trans;
2311-
struct btrfs_root *root = BTRFS_I(inode)->root;
2312-
struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
2320+
btrfs_truncate_page(inode->i_mapping, inode->i_size);
23132321

2314-
u64 mask = root->sectorsize - 1;
2315-
u64 hole_start = (inode->i_size + mask) & ~mask;
2316-
u64 block_end = (attr->ia_size + mask) & ~mask;
2317-
u64 hole_size;
2318-
u64 alloc_hint = 0;
2322+
while (1) {
2323+
struct btrfs_ordered_extent *ordered;
2324+
btrfs_wait_ordered_range(inode, hole_start,
2325+
block_end - hole_start);
2326+
lock_extent(io_tree, hole_start, block_end - 1, GFP_NOFS);
2327+
ordered = btrfs_lookup_ordered_extent(inode, hole_start);
2328+
if (!ordered)
2329+
break;
2330+
unlock_extent(io_tree, hole_start, block_end - 1, GFP_NOFS);
2331+
btrfs_put_ordered_extent(ordered);
2332+
}
23192333

2320-
if (attr->ia_size <= hole_start)
2321-
goto out;
2334+
trans = btrfs_start_transaction(root, 1);
2335+
btrfs_set_trans_block_group(trans, inode);
23222336

2323-
err = btrfs_check_free_space(root, 1, 0);
2324-
if (err)
2325-
goto fail;
2337+
cur_offset = hole_start;
2338+
while (1) {
2339+
em = btrfs_get_extent(inode, NULL, 0, cur_offset,
2340+
block_end - cur_offset, 0);
2341+
BUG_ON(IS_ERR(em) || !em);
2342+
last_byte = min(extent_map_end(em), block_end);
2343+
last_byte = (last_byte + mask) & ~mask;
2344+
if (test_bit(EXTENT_FLAG_VACANCY, &em->flags)) {
2345+
hole_size = last_byte - cur_offset;
2346+
err = btrfs_insert_file_extent(trans, root,
2347+
inode->i_ino, cur_offset, 0,
2348+
0, hole_size, 0, hole_size,
2349+
0, 0, 0);
2350+
btrfs_drop_extent_cache(inode, hole_start,
2351+
last_byte - 1, 0);
2352+
}
2353+
free_extent_map(em);
2354+
cur_offset = last_byte;
2355+
if (err || cur_offset >= block_end)
2356+
break;
2357+
}
23262358

2327-
btrfs_truncate_page(inode->i_mapping, inode->i_size);
2359+
btrfs_end_transaction(trans, root);
2360+
unlock_extent(io_tree, hole_start, block_end - 1, GFP_NOFS);
2361+
return err;
2362+
}
23282363

2329-
hole_size = block_end - hole_start;
2330-
while(1) {
2331-
struct btrfs_ordered_extent *ordered;
2332-
btrfs_wait_ordered_range(inode, hole_start, hole_size);
2333-
2334-
lock_extent(io_tree, hole_start, block_end - 1, GFP_NOFS);
2335-
ordered = btrfs_lookup_ordered_extent(inode, hole_start);
2336-
if (ordered) {
2337-
unlock_extent(io_tree, hole_start,
2338-
block_end - 1, GFP_NOFS);
2339-
btrfs_put_ordered_extent(ordered);
2340-
} else {
2341-
break;
2342-
}
2343-
}
2364+
static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
2365+
{
2366+
struct inode *inode = dentry->d_inode;
2367+
int err;
23442368

2345-
trans = btrfs_start_transaction(root, 1);
2346-
btrfs_set_trans_block_group(trans, inode);
2347-
mutex_lock(&BTRFS_I(inode)->extent_mutex);
2348-
err = btrfs_drop_extents(trans, root, inode,
2349-
hole_start, block_end, hole_start,
2350-
&alloc_hint);
2369+
err = inode_change_ok(inode, attr);
2370+
if (err)
2371+
return err;
23512372

2352-
if (alloc_hint != EXTENT_MAP_INLINE) {
2353-
err = btrfs_insert_file_extent(trans, root,
2354-
inode->i_ino,
2355-
hole_start, 0, 0,
2356-
hole_size, 0, hole_size,
2357-
0, 0, 0);
2358-
btrfs_drop_extent_cache(inode, hole_start,
2359-
(u64)-1, 0);
2360-
btrfs_check_file(root, inode);
2361-
}
2362-
mutex_unlock(&BTRFS_I(inode)->extent_mutex);
2363-
btrfs_end_transaction(trans, root);
2364-
unlock_extent(io_tree, hole_start, block_end - 1, GFP_NOFS);
2373+
if (S_ISREG(inode->i_mode) &&
2374+
attr->ia_valid & ATTR_SIZE && attr->ia_size > inode->i_size) {
2375+
err = btrfs_cont_expand(inode, attr->ia_size);
23652376
if (err)
23662377
return err;
23672378
}
2368-
out:
2379+
23692380
err = inode_setattr(inode, attr);
23702381

23712382
if (!err && ((attr->ia_valid & ATTR_MODE)))
23722383
err = btrfs_acl_chmod(inode);
2373-
fail:
23742384
return err;
23752385
}
23762386

@@ -3456,27 +3466,44 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
34563466
if (found_type == BTRFS_FILE_EXTENT_REG) {
34573467
extent_end = extent_start +
34583468
btrfs_file_extent_num_bytes(leaf, item);
3459-
err = 0;
3460-
if (start < extent_start || start >= extent_end) {
3461-
em->start = start;
3462-
if (start < extent_start) {
3463-
if (start + len <= extent_start)
3464-
goto not_found;
3465-
em->len = extent_end - extent_start;
3466-
} else {
3467-
em->len = len;
3469+
} else if (found_type == BTRFS_FILE_EXTENT_INLINE) {
3470+
size_t size;
3471+
size = btrfs_file_extent_inline_len(leaf, item);
3472+
extent_end = (extent_start + size + root->sectorsize - 1) &
3473+
~((u64)root->sectorsize - 1);
3474+
}
3475+
3476+
if (start >= extent_end) {
3477+
path->slots[0]++;
3478+
if (path->slots[0] >= btrfs_header_nritems(leaf)) {
3479+
ret = btrfs_next_leaf(root, path);
3480+
if (ret < 0) {
3481+
err = ret;
3482+
goto out;
34683483
}
3469-
goto not_found_em;
3484+
if (ret > 0)
3485+
goto not_found;
3486+
leaf = path->nodes[0];
34703487
}
3488+
btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
3489+
if (found_key.objectid != objectid ||
3490+
found_key.type != BTRFS_EXTENT_DATA_KEY)
3491+
goto not_found;
3492+
if (start + len <= found_key.offset)
3493+
goto not_found;
3494+
em->start = start;
3495+
em->len = found_key.offset - start;
3496+
goto not_found_em;
3497+
}
3498+
3499+
if (found_type == BTRFS_FILE_EXTENT_REG) {
3500+
em->start = extent_start;
3501+
em->len = extent_end - extent_start;
34713502
bytenr = btrfs_file_extent_disk_bytenr(leaf, item);
34723503
if (bytenr == 0) {
3473-
em->start = extent_start;
3474-
em->len = extent_end - extent_start;
34753504
em->block_start = EXTENT_MAP_HOLE;
34763505
goto insert;
34773506
}
3478-
em->start = extent_start;
3479-
em->len = extent_end - extent_start;
34803507
if (compressed) {
34813508
set_bit(EXTENT_FLAG_COMPRESSED, &em->flags);
34823509
em->block_start = bytenr;
@@ -3489,38 +3516,21 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
34893516
}
34903517
goto insert;
34913518
} else if (found_type == BTRFS_FILE_EXTENT_INLINE) {
3492-
u64 page_start;
34933519
unsigned long ptr;
34943520
char *map;
34953521
size_t size;
34963522
size_t extent_offset;
34973523
size_t copy_size;
34983524

3499-
size = btrfs_file_extent_inline_len(leaf, item);
3500-
extent_end = (extent_start + size + root->sectorsize - 1) &
3501-
~((u64)root->sectorsize - 1);
3502-
if (start < extent_start || start >= extent_end) {
3503-
em->start = start;
3504-
if (start < extent_start) {
3505-
if (start + len <= extent_start)
3506-
goto not_found;
3507-
em->len = extent_end - extent_start;
3508-
} else {
3509-
em->len = len;
3510-
}
3511-
goto not_found_em;
3512-
}
35133525
em->block_start = EXTENT_MAP_INLINE;
3514-
35153526
if (!page || create) {
35163527
em->start = extent_start;
3517-
em->len = (size + root->sectorsize - 1) &
3518-
~((u64)root->sectorsize - 1);
3528+
em->len = extent_end - extent_start;
35193529
goto out;
35203530
}
35213531

3522-
page_start = page_offset(page) + pg_offset;
3523-
extent_offset = page_start - extent_start;
3532+
size = btrfs_file_extent_inline_len(leaf, item);
3533+
extent_offset = page_offset(page) + pg_offset - extent_start;
35243534
copy_size = min_t(u64, PAGE_CACHE_SIZE - pg_offset,
35253535
size - extent_offset);
35263536
em->start = extent_start + extent_offset;
@@ -3570,6 +3580,7 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
35703580
em->len = len;
35713581
not_found_em:
35723582
em->block_start = EXTENT_MAP_HOLE;
3583+
set_bit(EXTENT_FLAG_VACANCY, &em->flags);
35733584
insert:
35743585
btrfs_release_path(root, path);
35753586
if (em->start > start || extent_map_end(em) <= start) {

0 commit comments

Comments
 (0)