|
@@ -24,6 +24,7 @@
|
|
#include "free-space-cache.h"
|
|
#include "free-space-cache.h"
|
|
#include "transaction.h"
|
|
#include "transaction.h"
|
|
#include "disk-io.h"
|
|
#include "disk-io.h"
|
|
|
|
+#include "extent_io.h"
|
|
|
|
|
|
#define BITS_PER_BITMAP (PAGE_CACHE_SIZE * 8)
|
|
#define BITS_PER_BITMAP (PAGE_CACHE_SIZE * 8)
|
|
#define MAX_CACHE_BYTES_PER_GIG (32 * 1024)
|
|
#define MAX_CACHE_BYTES_PER_GIG (32 * 1024)
|
|
@@ -224,6 +225,7 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info,
|
|
u64 num_entries;
|
|
u64 num_entries;
|
|
u64 num_bitmaps;
|
|
u64 num_bitmaps;
|
|
u64 generation;
|
|
u64 generation;
|
|
|
|
+ u64 used = btrfs_block_group_used(&block_group->item);
|
|
u32 cur_crc = ~(u32)0;
|
|
u32 cur_crc = ~(u32)0;
|
|
pgoff_t index = 0;
|
|
pgoff_t index = 0;
|
|
unsigned long first_page_offset;
|
|
unsigned long first_page_offset;
|
|
@@ -469,6 +471,17 @@ next:
|
|
index++;
|
|
index++;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ spin_lock(&block_group->tree_lock);
|
|
|
|
+ if (block_group->free_space != (block_group->key.offset - used -
|
|
|
|
+ block_group->bytes_super)) {
|
|
|
|
+ spin_unlock(&block_group->tree_lock);
|
|
|
|
+ printk(KERN_ERR "block group %llu has an wrong amount of free "
|
|
|
|
+ "space\n", block_group->key.objectid);
|
|
|
|
+ ret = 0;
|
|
|
|
+ goto free_cache;
|
|
|
|
+ }
|
|
|
|
+ spin_unlock(&block_group->tree_lock);
|
|
|
|
+
|
|
ret = 1;
|
|
ret = 1;
|
|
out:
|
|
out:
|
|
kfree(checksums);
|
|
kfree(checksums);
|
|
@@ -497,8 +510,11 @@ int btrfs_write_out_cache(struct btrfs_root *root,
|
|
struct list_head *pos, *n;
|
|
struct list_head *pos, *n;
|
|
struct page *page;
|
|
struct page *page;
|
|
struct extent_state *cached_state = NULL;
|
|
struct extent_state *cached_state = NULL;
|
|
|
|
+ struct btrfs_free_cluster *cluster = NULL;
|
|
|
|
+ struct extent_io_tree *unpin = NULL;
|
|
struct list_head bitmap_list;
|
|
struct list_head bitmap_list;
|
|
struct btrfs_key key;
|
|
struct btrfs_key key;
|
|
|
|
+ u64 start, end, len;
|
|
u64 bytes = 0;
|
|
u64 bytes = 0;
|
|
u32 *crc, *checksums;
|
|
u32 *crc, *checksums;
|
|
pgoff_t index = 0, last_index = 0;
|
|
pgoff_t index = 0, last_index = 0;
|
|
@@ -507,6 +523,7 @@ int btrfs_write_out_cache(struct btrfs_root *root,
|
|
int entries = 0;
|
|
int entries = 0;
|
|
int bitmaps = 0;
|
|
int bitmaps = 0;
|
|
int ret = 0;
|
|
int ret = 0;
|
|
|
|
+ bool next_page = false;
|
|
|
|
|
|
root = root->fs_info->tree_root;
|
|
root = root->fs_info->tree_root;
|
|
|
|
|
|
@@ -553,6 +570,18 @@ int btrfs_write_out_cache(struct btrfs_root *root,
|
|
*/
|
|
*/
|
|
first_page_offset = (sizeof(u32) * num_checksums) + sizeof(u64);
|
|
first_page_offset = (sizeof(u32) * num_checksums) + sizeof(u64);
|
|
|
|
|
|
|
|
+ /* Get the cluster for this block_group if it exists */
|
|
|
|
+ if (!list_empty(&block_group->cluster_list))
|
|
|
|
+ cluster = list_entry(block_group->cluster_list.next,
|
|
|
|
+ struct btrfs_free_cluster,
|
|
|
|
+ block_group_list);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * We shouldn't have switched the pinned extents yet so this is the
|
|
|
|
+ * right one
|
|
|
|
+ */
|
|
|
|
+ unpin = root->fs_info->pinned_extents;
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* Lock all pages first so we can lock the extent safely.
|
|
* Lock all pages first so we can lock the extent safely.
|
|
*
|
|
*
|
|
@@ -582,6 +611,12 @@ int btrfs_write_out_cache(struct btrfs_root *root,
|
|
lock_extent_bits(&BTRFS_I(inode)->io_tree, 0, i_size_read(inode) - 1,
|
|
lock_extent_bits(&BTRFS_I(inode)->io_tree, 0, i_size_read(inode) - 1,
|
|
0, &cached_state, GFP_NOFS);
|
|
0, &cached_state, GFP_NOFS);
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * When searching for pinned extents, we need to start at our start
|
|
|
|
+ * offset.
|
|
|
|
+ */
|
|
|
|
+ start = block_group->key.objectid;
|
|
|
|
+
|
|
/* Write out the extent entries */
|
|
/* Write out the extent entries */
|
|
do {
|
|
do {
|
|
struct btrfs_free_space_entry *entry;
|
|
struct btrfs_free_space_entry *entry;
|
|
@@ -589,6 +624,8 @@ int btrfs_write_out_cache(struct btrfs_root *root,
|
|
unsigned long offset = 0;
|
|
unsigned long offset = 0;
|
|
unsigned long start_offset = 0;
|
|
unsigned long start_offset = 0;
|
|
|
|
|
|
|
|
+ next_page = false;
|
|
|
|
+
|
|
if (index == 0) {
|
|
if (index == 0) {
|
|
start_offset = first_page_offset;
|
|
start_offset = first_page_offset;
|
|
offset = start_offset;
|
|
offset = start_offset;
|
|
@@ -600,7 +637,7 @@ int btrfs_write_out_cache(struct btrfs_root *root,
|
|
entry = addr + start_offset;
|
|
entry = addr + start_offset;
|
|
|
|
|
|
memset(addr, 0, PAGE_CACHE_SIZE);
|
|
memset(addr, 0, PAGE_CACHE_SIZE);
|
|
- while (1) {
|
|
|
|
|
|
+ while (node && !next_page) {
|
|
struct btrfs_free_space *e;
|
|
struct btrfs_free_space *e;
|
|
|
|
|
|
e = rb_entry(node, struct btrfs_free_space, offset_index);
|
|
e = rb_entry(node, struct btrfs_free_space, offset_index);
|
|
@@ -616,12 +653,49 @@ int btrfs_write_out_cache(struct btrfs_root *root,
|
|
entry->type = BTRFS_FREE_SPACE_EXTENT;
|
|
entry->type = BTRFS_FREE_SPACE_EXTENT;
|
|
}
|
|
}
|
|
node = rb_next(node);
|
|
node = rb_next(node);
|
|
- if (!node)
|
|
|
|
- break;
|
|
|
|
|
|
+ if (!node && cluster) {
|
|
|
|
+ node = rb_first(&cluster->root);
|
|
|
|
+ cluster = NULL;
|
|
|
|
+ }
|
|
offset += sizeof(struct btrfs_free_space_entry);
|
|
offset += sizeof(struct btrfs_free_space_entry);
|
|
if (offset + sizeof(struct btrfs_free_space_entry) >=
|
|
if (offset + sizeof(struct btrfs_free_space_entry) >=
|
|
PAGE_CACHE_SIZE)
|
|
PAGE_CACHE_SIZE)
|
|
|
|
+ next_page = true;
|
|
|
|
+ entry++;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * We want to add any pinned extents to our free space cache
|
|
|
|
+ * so we don't leak the space
|
|
|
|
+ */
|
|
|
|
+ while (!next_page && (start < block_group->key.objectid +
|
|
|
|
+ block_group->key.offset)) {
|
|
|
|
+ ret = find_first_extent_bit(unpin, start, &start, &end,
|
|
|
|
+ EXTENT_DIRTY);
|
|
|
|
+ if (ret) {
|
|
|
|
+ ret = 0;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* This pinned extent is out of our range */
|
|
|
|
+ if (start >= block_group->key.objectid +
|
|
|
|
+ block_group->key.offset)
|
|
break;
|
|
break;
|
|
|
|
+
|
|
|
|
+ len = block_group->key.objectid +
|
|
|
|
+ block_group->key.offset - start;
|
|
|
|
+ len = min(len, end + 1 - start);
|
|
|
|
+
|
|
|
|
+ entries++;
|
|
|
|
+ entry->offset = cpu_to_le64(start);
|
|
|
|
+ entry->bytes = cpu_to_le64(len);
|
|
|
|
+ entry->type = BTRFS_FREE_SPACE_EXTENT;
|
|
|
|
+
|
|
|
|
+ start = end + 1;
|
|
|
|
+ offset += sizeof(struct btrfs_free_space_entry);
|
|
|
|
+ if (offset + sizeof(struct btrfs_free_space_entry) >=
|
|
|
|
+ PAGE_CACHE_SIZE)
|
|
|
|
+ next_page = true;
|
|
entry++;
|
|
entry++;
|
|
}
|
|
}
|
|
*crc = ~(u32)0;
|
|
*crc = ~(u32)0;
|
|
@@ -652,7 +726,7 @@ int btrfs_write_out_cache(struct btrfs_root *root,
|
|
page_cache_release(page);
|
|
page_cache_release(page);
|
|
|
|
|
|
index++;
|
|
index++;
|
|
- } while (node);
|
|
|
|
|
|
+ } while (node || next_page);
|
|
|
|
|
|
/* Write out the bitmaps */
|
|
/* Write out the bitmaps */
|
|
list_for_each_safe(pos, n, &bitmap_list) {
|
|
list_for_each_safe(pos, n, &bitmap_list) {
|