Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 260886
b: refs/heads/master
c: 2f35612
h: refs/heads/master
v: v3
  • Loading branch information
Josef Bacik committed Jul 11, 2011
1 parent 1e54868 commit 21468b5
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 111 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: fdb5effd5c2a7e01dc3a4217bb194e2d3a5b160f
refs/heads/master: 2f356126c589d562f98e2287f9c7b983388dc62f
169 changes: 59 additions & 110 deletions trunk/fs/btrfs/free-space-cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@ struct inode *lookup_free_space_inode(struct btrfs_root *root,
return inode;

spin_lock(&block_group->lock);
if (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM) {
printk(KERN_INFO "Old style space inode found, converting.\n");
BTRFS_I(inode)->flags &= ~BTRFS_INODE_NODATASUM;
block_group->disk_cache_state = BTRFS_DC_CLEAR;
}

if (!btrfs_fs_closing(root->fs_info)) {
block_group->inode = igrab(inode);
block_group->iref = 1;
Expand Down Expand Up @@ -135,7 +141,7 @@ int __create_free_space_inode(struct btrfs_root *root,
btrfs_set_inode_gid(leaf, inode_item, 0);
btrfs_set_inode_mode(leaf, inode_item, S_IFREG | 0600);
btrfs_set_inode_flags(leaf, inode_item, BTRFS_INODE_NOCOMPRESS |
BTRFS_INODE_PREALLOC | BTRFS_INODE_NODATASUM);
BTRFS_INODE_PREALLOC);
btrfs_set_inode_nlink(leaf, inode_item, 1);
btrfs_set_inode_transid(leaf, inode_item, trans->transid);
btrfs_set_inode_block_group(leaf, inode_item, offset);
Expand Down Expand Up @@ -239,17 +245,12 @@ int __load_free_space_cache(struct btrfs_root *root, struct inode *inode,
struct btrfs_free_space_header *header;
struct extent_buffer *leaf;
struct page *page;
u32 *checksums = NULL, *crc;
char *disk_crcs = NULL;
struct btrfs_key key;
struct list_head bitmaps;
u64 num_entries;
u64 num_bitmaps;
u64 generation;
u32 cur_crc = ~(u32)0;
pgoff_t index = 0;
unsigned long first_page_offset;
int num_checksums;
int ret = 0;

INIT_LIST_HEAD(&bitmaps);
Expand Down Expand Up @@ -292,16 +293,6 @@ int __load_free_space_cache(struct btrfs_root *root, struct inode *inode,
if (!num_entries)
goto out;

/* Setup everything for doing checksumming */
num_checksums = i_size_read(inode) / PAGE_CACHE_SIZE;
checksums = crc = kzalloc(sizeof(u32) * num_checksums, GFP_NOFS);
if (!checksums)
goto out;
first_page_offset = (sizeof(u32) * num_checksums) + sizeof(u64);
disk_crcs = kzalloc(first_page_offset, GFP_NOFS);
if (!disk_crcs)
goto out;

ret = readahead_cache(inode);
if (ret)
goto out;
Expand All @@ -311,17 +302,11 @@ int __load_free_space_cache(struct btrfs_root *root, struct inode *inode,
struct btrfs_free_space *e;
void *addr;
unsigned long offset = 0;
unsigned long start_offset = 0;
int need_loop = 0;

if (!num_entries && !num_bitmaps)
break;

if (index == 0) {
start_offset = first_page_offset;
offset = start_offset;
}

page = grab_cache_page(inode->i_mapping, index);
if (!page)
goto free_cache;
Expand All @@ -342,8 +327,15 @@ int __load_free_space_cache(struct btrfs_root *root, struct inode *inode,
if (index == 0) {
u64 *gen;

memcpy(disk_crcs, addr, first_page_offset);
gen = addr + (sizeof(u32) * num_checksums);
/*
* We put a bogus crc in the front of the first page in
* case old kernels try to mount a fs with the new
* format to make sure they discard the cache.
*/
addr += sizeof(u64);
offset += sizeof(u64);

gen = addr;
if (*gen != BTRFS_I(inode)->generation) {
printk(KERN_ERR "btrfs: space cache generation"
" (%llu) does not match inode (%llu)\n",
Expand All @@ -355,24 +347,10 @@ int __load_free_space_cache(struct btrfs_root *root, struct inode *inode,
page_cache_release(page);
goto free_cache;
}
crc = (u32 *)disk_crcs;
}
entry = addr + start_offset;

/* First lets check our crc before we do anything fun */
cur_crc = ~(u32)0;
cur_crc = btrfs_csum_data(root, addr + start_offset, cur_crc,
PAGE_CACHE_SIZE - start_offset);
btrfs_csum_final(cur_crc, (char *)&cur_crc);
if (cur_crc != *crc) {
printk(KERN_ERR "btrfs: crc mismatch for page %lu\n",
index);
kunmap(page);
unlock_page(page);
page_cache_release(page);
goto free_cache;
addr += sizeof(u64);
offset += sizeof(u64);
}
crc++;
entry = addr;

while (1) {
if (!num_entries)
Expand Down Expand Up @@ -470,8 +448,6 @@ int __load_free_space_cache(struct btrfs_root *root, struct inode *inode,

ret = 1;
out:
kfree(checksums);
kfree(disk_crcs);
return ret;
free_cache:
__btrfs_remove_free_space_cache(ctl);
Expand Down Expand Up @@ -569,8 +545,7 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
struct btrfs_key key;
u64 start, end, len;
u64 bytes = 0;
u32 *crc, *checksums;
unsigned long first_page_offset;
u32 crc = ~(u32)0;
int index = 0, num_pages = 0;
int entries = 0;
int bitmaps = 0;
Expand All @@ -590,34 +565,13 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
num_pages = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
PAGE_CACHE_SHIFT;

/* Since the first page has all of our checksums and our generation we
* need to calculate the offset into the page that we can start writing
* our entries.
*/
first_page_offset = (sizeof(u32) * num_pages) + sizeof(u64);

filemap_write_and_wait(inode->i_mapping);
btrfs_wait_ordered_range(inode, inode->i_size &
~(root->sectorsize - 1), (u64)-1);

/* make sure we don't overflow that first page */
if (first_page_offset + sizeof(struct btrfs_free_space_entry) >= PAGE_CACHE_SIZE) {
/* this is really the same as running out of space, where we also return 0 */
printk(KERN_CRIT "Btrfs: free space cache was too big for the crc page\n");
ret = 0;
goto out_update;
}

/* We need a checksum per page. */
crc = checksums = kzalloc(sizeof(u32) * num_pages, GFP_NOFS);
if (!crc)
return -1;

pages = kzalloc(sizeof(struct page *) * num_pages, GFP_NOFS);
if (!pages) {
kfree(crc);
if (!pages)
return -1;
}

/* Get the cluster for this block_group if it exists */
if (block_group && !list_empty(&block_group->cluster_list))
Expand Down Expand Up @@ -648,7 +602,7 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
unlock_page(pages[i]);
page_cache_release(pages[i]);
}
goto out_free;
goto out;
}
pages[index] = page;
index++;
Expand All @@ -668,28 +622,38 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
/* Write out the extent entries */
do {
struct btrfs_free_space_entry *entry;
void *addr;
void *addr, *orig;
unsigned long offset = 0;
unsigned long start_offset = 0;

next_page = false;

if (index == 0) {
start_offset = first_page_offset;
offset = start_offset;
}

if (index >= num_pages) {
out_of_space = true;
break;
}

page = pages[index];

addr = kmap(page);
entry = addr + start_offset;
orig = addr = kmap(page);
if (index == 0) {
u64 *gen;

memset(addr, 0, PAGE_CACHE_SIZE);
/*
* We're going to put in a bogus crc for this page to
* make sure that old kernels who aren't aware of this
* format will be sure to discard the cache.
*/
addr += sizeof(u64);
offset += sizeof(u64);

gen = addr;
*gen = trans->transid;
addr += sizeof(u64);
offset += sizeof(u64);
}
entry = addr;

memset(addr, 0, PAGE_CACHE_SIZE - offset);
while (node && !next_page) {
struct btrfs_free_space *e;

Expand Down Expand Up @@ -752,13 +716,19 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
next_page = true;
entry++;
}
*crc = ~(u32)0;
*crc = btrfs_csum_data(root, addr + start_offset, *crc,
PAGE_CACHE_SIZE - start_offset);
kunmap(page);

btrfs_csum_final(*crc, (char *)crc);
crc++;
/* Generate bogus crc value */
if (index == 0) {
u32 *tmp;
crc = btrfs_csum_data(root, orig + sizeof(u64), crc,
PAGE_CACHE_SIZE - sizeof(u64));
btrfs_csum_final(crc, (char *)&crc);
crc++;
tmp = orig;
*tmp = crc;
}

kunmap(page);

bytes += PAGE_CACHE_SIZE;

Expand All @@ -779,11 +749,7 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,

addr = kmap(page);
memcpy(addr, entry->bitmap, PAGE_CACHE_SIZE);
*crc = ~(u32)0;
*crc = btrfs_csum_data(root, addr, *crc, PAGE_CACHE_SIZE);
kunmap(page);
btrfs_csum_final(*crc, (char *)crc);
crc++;
bytes += PAGE_CACHE_SIZE;

list_del_init(&entry->list);
Expand All @@ -796,7 +762,7 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
i_size_read(inode) - 1, &cached_state,
GFP_NOFS);
ret = 0;
goto out_free;
goto out;
}

/* Zero out the rest of the pages just to make sure */
Expand All @@ -811,20 +777,6 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
index++;
}

/* Write the checksums and trans id to the first page */
{
void *addr;
u64 *gen;

page = pages[0];

addr = kmap(page);
memcpy(addr, checksums, sizeof(u32) * num_pages);
gen = addr + (sizeof(u32) * num_pages);
*gen = trans->transid;
kunmap(page);
}

ret = btrfs_dirty_pages(root, inode, pages, num_pages, 0,
bytes, &cached_state);
btrfs_drop_pages(pages, num_pages);
Expand All @@ -833,7 +785,7 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,

if (ret) {
ret = 0;
goto out_free;
goto out;
}

BTRFS_I(inode)->generation = trans->transid;
Expand All @@ -850,7 +802,7 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, bytes - 1,
EXTENT_DIRTY | EXTENT_DELALLOC |
EXTENT_DO_ACCOUNTING, 0, 0, NULL, GFP_NOFS);
goto out_free;
goto out;
}
leaf = path->nodes[0];
if (ret > 0) {
Expand All @@ -866,7 +818,7 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
EXTENT_DO_ACCOUNTING, 0, 0, NULL,
GFP_NOFS);
btrfs_release_path(path);
goto out_free;
goto out;
}
}
header = btrfs_item_ptr(leaf, path->slots[0],
Expand All @@ -879,11 +831,8 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,

ret = 1;

out_free:
kfree(checksums);
out:
kfree(pages);

out_update:
if (ret != 1) {
invalidate_inode_pages2_range(inode->i_mapping, 0, index);
BTRFS_I(inode)->generation = 0;
Expand Down

0 comments on commit 21468b5

Please sign in to comment.