summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/extent_io.c27
-rw-r--r--fs/btrfs/extent_map.c4
-rw-r--r--fs/btrfs/extent_map.h3
-rw-r--r--fs/btrfs/file-item.c5
-rw-r--r--fs/btrfs/file.c14
-rw-r--r--fs/btrfs/inode.c15
6 files changed, 48 insertions, 20 deletions
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 3153b4fdd0b3..d4a63ae7ed1b 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -2000,7 +2000,7 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
struct block_device *bdev;
int ret;
int nr = 0;
- size_t page_offset = 0;
+ size_t pg_offset = 0;
size_t blocksize;
loff_t i_size = i_size_read(inode);
unsigned long end_index = i_size >> PAGE_CACHE_SHIFT;
@@ -2008,9 +2008,9 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
u64 delalloc_end;
WARN_ON(!PageLocked(page));
- page_offset = i_size & (PAGE_CACHE_SIZE - 1);
+ pg_offset = i_size & (PAGE_CACHE_SIZE - 1);
if (page->index > end_index ||
- (page->index == end_index && !page_offset)) {
+ (page->index == end_index && !pg_offset)) {
page->mapping->a_ops->invalidatepage(page, 0);
unlock_page(page);
return 0;
@@ -2020,12 +2020,12 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
char *userpage;
userpage = kmap_atomic(page, KM_USER0);
- memset(userpage + page_offset, 0,
- PAGE_CACHE_SIZE - page_offset);
+ memset(userpage + pg_offset, 0,
+ PAGE_CACHE_SIZE - pg_offset);
kunmap_atomic(userpage, KM_USER0);
flush_dcache_page(page);
}
- page_offset = 0;
+ pg_offset = 0;
set_page_extent_mapped(page);
@@ -2088,7 +2088,7 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
unlock_start = page_end + 1;
break;
}
- em = epd->get_extent(inode, page, page_offset, cur,
+ em = epd->get_extent(inode, page, pg_offset, cur,
end - cur + 1, 1);
if (IS_ERR(em) || !em) {
SetPageError(page);
@@ -2113,12 +2113,13 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
unlock_extent(tree, unlock_start, cur + iosize -1,
GFP_NOFS);
+
if (tree->ops && tree->ops->writepage_end_io_hook)
tree->ops->writepage_end_io_hook(page, cur,
cur + iosize - 1,
NULL, 1);
cur = cur + iosize;
- page_offset += iosize;
+ pg_offset += iosize;
unlock_start = cur;
continue;
}
@@ -2127,7 +2128,7 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
if (0 && !test_range_bit(tree, cur, cur + iosize - 1,
EXTENT_DIRTY, 0)) {
cur = cur + iosize;
- page_offset += iosize;
+ pg_offset += iosize;
continue;
}
clear_extent_dirty(tree, cur, cur + iosize - 1, GFP_NOFS);
@@ -2141,6 +2142,7 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
SetPageError(page);
} else {
unsigned long max_nr = end_index + 1;
+
set_range_writeback(tree, cur, cur + iosize - 1);
if (!PageWriteback(page)) {
printk("warning page %lu not writeback, "
@@ -2150,14 +2152,14 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
}
ret = submit_extent_page(WRITE, tree, page, sector,
- iosize, page_offset, bdev,
+ iosize, pg_offset, bdev,
&epd->bio, max_nr,
end_bio_extent_writepage, 0);
if (ret)
SetPageError(page);
}
cur = cur + iosize;
- page_offset += iosize;
+ pg_offset += iosize;
nr++;
}
done:
@@ -2579,7 +2581,8 @@ int try_release_extent_mapping(struct extent_map_tree *map,
spin_unlock(&map->lock);
break;
}
- if (em->start != start) {
+ if (test_bit(EXTENT_FLAG_PINNED, &em->flags) ||
+ em->start != start) {
spin_unlock(&map->lock);
free_extent_map(em);
break;
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c
index 81123277c2b8..71b1ac155355 100644
--- a/fs/btrfs/extent_map.c
+++ b/fs/btrfs/extent_map.c
@@ -173,6 +173,9 @@ static inline struct rb_node *tree_search(struct rb_root *root, u64 offset)
static int mergable_maps(struct extent_map *prev, struct extent_map *next)
{
+ if (test_bit(EXTENT_FLAG_PINNED, &prev->flags))
+ return 0;
+
if (extent_map_end(prev) == next->start &&
prev->flags == next->flags &&
prev->bdev == next->bdev &&
@@ -320,6 +323,7 @@ int remove_extent_mapping(struct extent_map_tree *tree, struct extent_map *em)
{
int ret = 0;
+ WARN_ON(test_bit(EXTENT_FLAG_PINNED, &em->flags));
BUG_ON(spin_trylock(&tree->lock));
rb_erase(&em->rb_node, &tree->map);
em->in_tree = 0;
diff --git a/fs/btrfs/extent_map.h b/fs/btrfs/extent_map.h
index 56314217cfc0..a3978ec27846 100644
--- a/fs/btrfs/extent_map.h
+++ b/fs/btrfs/extent_map.h
@@ -8,6 +8,9 @@
#define EXTENT_MAP_INLINE (u64)-2
#define EXTENT_MAP_DELALLOC (u64)-1
+/* bits for the flags field */
+#define EXTENT_FLAG_PINNED 0 /* this entry not yet on disk, don't free it */
+
struct extent_map {
struct rb_node rb_node;
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c
index e02f1e5acb0a..d9c69e16d368 100644
--- a/fs/btrfs/file-item.c
+++ b/fs/btrfs/file-item.c
@@ -192,7 +192,6 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode,
(char *)&sector_sum->sum);
sector_sum->offset = page_offset(bvec->bv_page) +
bvec->bv_offset;
-
sector_sum++;
bio_index++;
total_bytes += bvec->bv_len;
@@ -201,9 +200,6 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode,
}
btrfs_add_ordered_sum(inode, ordered, sums);
btrfs_put_ordered_extent(ordered);
- if (total_bytes != bio->bi_size) {
-printk("warning, total bytes %lu bio size %u\n", total_bytes, bio->bi_size);
- }
return 0;
}
@@ -372,6 +368,7 @@ next_sector:
write_extent_buffer(leaf, &sector_sum->sum,
(unsigned long)item, BTRFS_CRC32_SIZE);
}
+
total_bytes += root->sectorsize;
sector_sum++;
if (total_bytes < sums->len) {
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 40ad1b2958cb..eccdb9562ba8 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -358,9 +358,7 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end)
struct extent_map *split = NULL;
struct extent_map *split2 = NULL;
struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
- struct extent_map *tmp;
u64 len = end - start + 1;
- u64 next_start;
int ret;
int testend = 1;
@@ -381,8 +379,16 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end)
spin_unlock(&em_tree->lock);
break;
}
- tmp = rb_entry(&em->rb_node, struct extent_map, rb_node);
- next_start = tmp->start;
+ if (test_bit(EXTENT_FLAG_PINNED, &em->flags)) {
+ start = em->start + em->len;
+ free_extent_map(em);
+ spin_unlock(&em_tree->lock);
+ if (start < end) {
+ len = end - start + 1;
+ continue;
+ }
+ break;
+ }
remove_extent_mapping(em_tree, em);
if (em->block_start < EXTENT_MAP_LAST_BYTE &&
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 8803abc89bb8..08dbe738b512 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -144,6 +144,7 @@ static int cow_file_range(struct inode *inode, u64 start, u64 end)
em->len = ins.offset;
em->block_start = ins.objectid;
em->bdev = root->fs_info->fs_devices->latest_bdev;
+ set_bit(EXTENT_FLAG_PINNED, &em->flags);
while(1) {
spin_lock(&em_tree->lock);
ret = add_extent_mapping(em_tree, em);
@@ -483,6 +484,8 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
struct btrfs_trans_handle *trans;
struct btrfs_ordered_extent *ordered_extent;
struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
+ struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
+ struct extent_map *em;
u64 alloc_hint = 0;
struct list_head list;
struct btrfs_key ins;
@@ -524,6 +527,17 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
ordered_extent->len,
ordered_extent->len, 0);
BUG_ON(ret);
+
+
+ spin_lock(&em_tree->lock);
+ em = lookup_extent_mapping(em_tree, ordered_extent->file_offset,
+ ordered_extent->len);
+ if (em) {
+ clear_bit(EXTENT_FLAG_PINNED, &em->flags);
+ free_extent_map(em);
+ }
+ spin_unlock(&em_tree->lock);
+
btrfs_drop_extent_cache(inode, ordered_extent->file_offset,
ordered_extent->file_offset +
ordered_extent->len - 1);
@@ -538,6 +552,7 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
btrfs_ordered_update_i_size(inode, ordered_extent);
btrfs_remove_ordered_extent(inode, ordered_extent);
+
/* once for us */
btrfs_put_ordered_extent(ordered_extent);
/* once for the tree */