aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosef Bacik <josef@redhat.com>2011-12-08 09:09:24 -0500
committerJosef Bacik <josef@redhat.com>2011-12-09 10:12:58 -0500
commit2e4634c87bd53b220f006f3d5c5552e00dde63d0 (patch)
tree69f1bcb68b5c3ad561d3f296a2b1d2bd17c7d96c
parentffda85af6138130da56ad29942da775979752e76 (diff)
downloadbtrfs-work-garbage.tar.gz
current workgarbage
what im currently working on. Signed-off-by: Josef Bacik <josef@redhat.com>
-rw-r--r--fs/btrfs/btrfs_inode.h1
-rw-r--r--fs/btrfs/delayed-inode.c53
-rw-r--r--fs/btrfs/extent-tree.c109
-rw-r--r--fs/btrfs/inode-map.c7
-rw-r--r--fs/btrfs/inode.c27
-rw-r--r--fs/btrfs/ioctl.c2
-rw-r--r--fs/btrfs/relocation.c2
-rw-r--r--fs/btrfs/transaction.c3
8 files changed, 162 insertions, 42 deletions
diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h
index 634608d2a6d03..eb51cb9b55b0e 100644
--- a/fs/btrfs/btrfs_inode.h
+++ b/fs/btrfs/btrfs_inode.h
@@ -129,6 +129,7 @@ struct btrfs_inode {
*/
u64 csum_bytes;
+ u64 reserved;
/* flags field from the on disk inode */
u32 flags;
diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c
index 6a1a6800776c9..d1b3d5c4a7ad9 100644
--- a/fs/btrfs/delayed-inode.c
+++ b/fs/btrfs/delayed-inode.c
@@ -595,8 +595,12 @@ static int btrfs_delayed_item_reserve_metadata(struct btrfs_trans_handle *trans,
num_bytes = btrfs_calc_trans_metadata_size(root, 1);
ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes);
- if (!ret)
+ if (!ret) {
+ trace_printk("%pU: delayed_item: %Lu reserved %Lu\n",
+ root->fs_info->fsid, item->key.objectid,
+ num_bytes);
item->bytes_reserved = num_bytes;
+ }
return ret;
}
@@ -610,6 +614,9 @@ static void btrfs_delayed_item_release_metadata(struct btrfs_root *root,
return;
rsv = &root->fs_info->delayed_block_rsv;
+ trace_printk("%pU: delayed_item: %Lu released %Lu\n",
+ root->fs_info->fsid, item->key.objectid,
+ item->bytes_reserved);
btrfs_block_rsv_release(root, rsv,
item->bytes_reserved);
}
@@ -624,7 +631,7 @@ static int btrfs_delayed_inode_reserve_metadata(
struct btrfs_block_rsv *dst_rsv;
u64 num_bytes;
int ret;
- int release = false;
+ bool release = false;
src_rsv = trans->block_rsv;
dst_rsv = &root->fs_info->delayed_block_rsv;
@@ -651,12 +658,18 @@ static int btrfs_delayed_inode_reserve_metadata(
*/
if (ret == -EAGAIN)
ret = -ENOSPC;
- if (!ret)
+ if (!ret) {
node->bytes_reserved = num_bytes;
+ trace_printk("%pU: delayed_inode: %Lu reserved %Lu\n",
+ root->fs_info->fsid, btrfs_ino(inode),
+ num_bytes);
+ }
return ret;
} else if (src_rsv == &root->fs_info->delalloc_block_rsv) {
spin_lock(&BTRFS_I(inode)->lock);
if (BTRFS_I(inode)->delalloc_meta_reserved) {
+ BUG_ON(BTRFS_I(inode)->reserved < num_bytes);
+ BTRFS_I(inode)->reserved -= num_bytes;
BTRFS_I(inode)->delalloc_meta_reserved = 0;
spin_unlock(&BTRFS_I(inode)->lock);
release = true;
@@ -676,9 +689,9 @@ static int btrfs_delayed_inode_reserve_metadata(
if (!ret)
goto out;
- ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes);
- if (!ret)
- goto out;
+// ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes);
+// if (!ret)
+// goto out;
/*
* Ok this is a problem, let's just steal from the global rsv
@@ -707,11 +720,17 @@ out:
* reservation here. I think it may be time for a documentation page on
* how block rsvs. work.
*/
- if (!ret)
+ if (!ret) {
+ trace_printk("%pU: delayed_inode: %Lu reserved %Lu\n",
+ root->fs_info->fsid, btrfs_ino(inode), num_bytes);
node->bytes_reserved = num_bytes;
+ }
- if (release)
+ if (release) {
+ trace_printk("%pU: delalloc: %Lu released %Lu\n",
+ root->fs_info->fsid, btrfs_ino(inode), num_bytes);
btrfs_block_rsv_release(root, src_rsv, num_bytes);
+ }
return ret;
}
@@ -725,6 +744,9 @@ static void btrfs_delayed_inode_release_metadata(struct btrfs_root *root,
return;
rsv = &root->fs_info->delayed_block_rsv;
+ trace_printk("%pU: delayed_inode: %Lu released %Lu\n",
+ root->fs_info->fsid, node->inode_id,
+ node->bytes_reserved);
btrfs_block_rsv_release(root, rsv,
node->bytes_reserved);
node->bytes_reserved = 0;
@@ -1372,13 +1394,6 @@ int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans,
goto release_node;
}
- ret = btrfs_delayed_item_reserve_metadata(trans, root, delayed_item);
- /*
- * we have reserved enough space when we start a new transaction,
- * so reserving metadata failure is impossible
- */
- BUG_ON(ret);
-
delayed_item->key.objectid = btrfs_ino(dir);
btrfs_set_key_type(&delayed_item->key, BTRFS_DIR_INDEX_KEY);
delayed_item->key.offset = index;
@@ -1391,6 +1406,14 @@ int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans,
dir_item->type = type;
memcpy((char *)(dir_item + 1), name, name_len);
+ ret = btrfs_delayed_item_reserve_metadata(trans, root, delayed_item);
+ /*
+ * we have reserved enough space when we start a new transaction,
+ * so reserving metadata failure is impossible
+ */
+ BUG_ON(ret);
+
+
mutex_lock(&delayed_node->mutex);
ret = __btrfs_add_delayed_insertion_item(delayed_node, delayed_item);
if (unlikely(ret)) {
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 24cfd10ea9cee..7f28f10e3b6ac 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -24,6 +24,7 @@
#include <linux/kthread.h>
#include <linux/slab.h>
#include <linux/ratelimit.h>
+#include <linux/kallsyms.h>
#include "compat.h"
#include "hash.h"
#include "ctree.h"
@@ -4047,6 +4048,10 @@ void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans,
if (!trans->bytes_reserved)
return;
+ WARN_ON(trans->block_rsv != &root->fs_info->trans_block_rsv);
+ BUG_ON(trans->block_rsv == &root->fs_info->delalloc_block_rsv);
+ trace_printk("%pU: transaction: %p release %Lu\n", root->fs_info->fsid,
+ trans, trans->bytes_reserved);
btrfs_block_rsv_release(root, trans->block_rsv, trans->bytes_reserved);
trans->bytes_reserved = 0;
}
@@ -4064,6 +4069,8 @@ int btrfs_orphan_reserve_metadata(struct btrfs_trans_handle *trans,
* when we are truly done with the orphan item.
*/
u64 num_bytes = btrfs_calc_trans_metadata_size(root, 1);
+ trace_printk("%pU: orphan: %Lu reserve %Lu\n", root->fs_info->fsid,
+ btrfs_ino(inode), num_bytes);
return block_rsv_migrate_bytes(src_rsv, dst_rsv, num_bytes);
}
@@ -4071,6 +4078,8 @@ void btrfs_orphan_release_metadata(struct inode *inode)
{
struct btrfs_root *root = BTRFS_I(inode)->root;
u64 num_bytes = btrfs_calc_trans_metadata_size(root, 1);
+ trace_printk("%pU: orphan: %Lu release %Lu\n", root->fs_info->fsid,
+ btrfs_ino(inode), num_bytes);
btrfs_block_rsv_release(root, root->orphan_block_rsv, num_bytes);
}
@@ -4162,6 +4171,7 @@ static u64 calc_csum_metadata_size(struct inode *inode, u64 num_bytes,
BTRFS_I(inode)->csum_bytes += num_bytes;
else
BTRFS_I(inode)->csum_bytes -= num_bytes;
+
csum_size = BTRFS_LEAF_DATA_SIZE(root) - sizeof(struct btrfs_item);
num_csums_per_leaf = (int)div64_u64(csum_size,
sizeof(struct btrfs_csum_item) +
@@ -4177,10 +4187,13 @@ static u64 calc_csum_metadata_size(struct inode *inode, u64 num_bytes,
if (old_csums == num_csums)
return 0;
- if (reserve)
+ if (reserve) {
+ BUG_ON(num_csums < old_csums);
return btrfs_calc_trans_metadata_size(root,
num_csums - old_csums);
+ }
+ BUG_ON(old_csums < num_csums);
return btrfs_calc_trans_metadata_size(root, old_csums - num_csums);
}
@@ -4189,10 +4202,16 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
struct btrfs_root *root = BTRFS_I(inode)->root;
struct btrfs_block_rsv *block_rsv = &root->fs_info->delalloc_block_rsv;
u64 to_reserve = 0;
+ u64 csum_reserve = 0;
+ u64 csum_bytes;
unsigned nr_extents = 0;
int flush = 1;
+ int delalloc_meta_reserved = 0;
int ret;
+ /* Need to be holding the i_mutex here */
+ WARN_ON(!mutex_is_locked(&inode->i_mutex));
+
if (btrfs_is_free_space_inode(root, inode))
flush = 0;
@@ -4203,13 +4222,10 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
spin_lock(&BTRFS_I(inode)->lock);
BTRFS_I(inode)->outstanding_extents++;
-
if (BTRFS_I(inode)->outstanding_extents >
- BTRFS_I(inode)->reserved_extents) {
+ BTRFS_I(inode)->reserved_extents)
nr_extents = BTRFS_I(inode)->outstanding_extents -
BTRFS_I(inode)->reserved_extents;
- BTRFS_I(inode)->reserved_extents += nr_extents;
- }
/*
* Add an item to reserve for updating the inode when we complete the
@@ -4217,36 +4233,60 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
*/
if (!BTRFS_I(inode)->delalloc_meta_reserved) {
nr_extents++;
- BTRFS_I(inode)->delalloc_meta_reserved = 1;
+ delalloc_meta_reserved = 1;
}
to_reserve = btrfs_calc_trans_metadata_size(root, nr_extents);
- to_reserve += calc_csum_metadata_size(inode, num_bytes, 1);
+ csum_reserve = calc_csum_metadata_size(inode, num_bytes, 1);
+ csum_bytes = BTRFS_I(inode)->csum_bytes;
spin_unlock(&BTRFS_I(inode)->lock);
- ret = reserve_metadata_bytes(root, block_rsv, to_reserve, flush);
+ ret = reserve_metadata_bytes(root, block_rsv, to_reserve + csum_reserve, flush);
if (ret) {
u64 to_free = 0;
- unsigned dropped;
+ int dropped;
spin_lock(&BTRFS_I(inode)->lock);
dropped = drop_outstanding_extent(inode);
- to_free = calc_csum_metadata_size(inode, num_bytes, 0);
- spin_unlock(&BTRFS_I(inode)->lock);
- to_free += btrfs_calc_trans_metadata_size(root, dropped);
/*
- * Somebody could have come in and twiddled with the
- * reservation, so if we have to free more than we would have
- * reserved from this reservation go ahead and release those
- * bytes.
+ * If the inode's csum_bytes is the same as the original
+ * csum_bytes then we know we haven't raced with any free()ers
+ * so we can just reduce our inode's csum bytes and carry on.
+ * Otherwise we have to do the normal free thing to account for
+ * the case that the free side didn't free up it's reserve
+ * because of this outstanding reservation.
*/
- to_free -= to_reserve;
+ if (BTRFS_I(inode)->csum_bytes == csum_bytes)
+ calc_csum_metadata_size(inode, num_bytes, 0);
+ else
+ to_free = calc_csum_metadata_size(inode, num_bytes, 0);
+ if (dropped > 0)
+ to_free += btrfs_calc_trans_metadata_size(root, dropped);
+// BUG_ON(BTRFS_I(inode)->reserved < to_free);
+ // BTRFS_I(inode)->reserved -= to_free;
+ spin_unlock(&BTRFS_I(inode)->lock);
if (to_free)
btrfs_block_rsv_release(root, block_rsv, to_free);
+ trace_printk("%pU: delalloc: %Lu released %Lu\n", root->fs_info->fsid,
+ btrfs_ino(inode), to_free);
return ret;
}
+ to_reserve += csum_reserve;
+ spin_lock(&BTRFS_I(inode)->lock);
+ if (delalloc_meta_reserved) {
+ BTRFS_I(inode)->delalloc_meta_reserved = 1;
+ nr_extents--;
+ }
+ BTRFS_I(inode)->reserved_extents += nr_extents;
+ BTRFS_I(inode)->reserved += to_reserve;
+// trace_printk("delalloc: %Lu to_reserve=%Lu, csum_reserve=%Lu, nr_extents=%u, outstanding_extents=%u, reserved_extents=%u, delalloc_meta_reserved=%d, reserved=%Lu, csum_bytes=%Lu\n",
+// btrfs_ino(inode), to_reserve, csum_reserve, nr_extents, BTRFS_I(inode)->outstanding_extents, BTRFS_I(inode)->reserved_extents, delalloc_meta_reserved, BTRFS_I(inode)->reserved, BTRFS_I(inode)->csum_bytes);
+ spin_unlock(&BTRFS_I(inode)->lock);
+
+ trace_printk("%pU: delalloc: %Lu reserved %Lu\n", root->fs_info->fsid,
+ btrfs_ino(inode), to_reserve);
block_rsv_add_bytes(block_rsv, to_reserve, 1);
return 0;
@@ -4265,17 +4305,46 @@ void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes)
{
struct btrfs_root *root = BTRFS_I(inode)->root;
u64 to_free = 0;
+ u64 extent_free = 0;
+ u64 csum_free = 0;
unsigned dropped;
+ unsigned dropping_reserve = 0;
+// char symname[KSYM_NAME_LEN];
+// sprint_symbol(symname, (unsigned long)__builtin_return_address(0));
num_bytes = ALIGN(num_bytes, root->sectorsize);
spin_lock(&BTRFS_I(inode)->lock);
+
+ if (BTRFS_I(inode)->delalloc_meta_reserved)
+ dropping_reserve = 1;
+
dropped = drop_outstanding_extent(inode);
- to_free = calc_csum_metadata_size(inode, num_bytes, 0);
+ if (BTRFS_I(inode)->delalloc_meta_reserved)
+ dropping_reserve = 0;
+
+ csum_free = to_free = calc_csum_metadata_size(inode, num_bytes, 0);
+ if (dropped > 0) {
+ extent_free = btrfs_calc_trans_metadata_size(root, dropped);
+ to_free += extent_free;
+ }
+// BUG_ON(BTRFS_I(inode)->reserved < to_free);
+ /*
+ if (BTRFS_I(inode)->reserved < to_free)
+ trace_printk("inode %Lu has %Lu want to free %Lu, dropped reserve %d\n",
+ btrfs_ino(inode), BTRFS_I(inode)->reserved, to_free, dropping_reserve);
+ */
+ BTRFS_I(inode)->reserved -= to_free;
+ /*
+ trace_printk("delalloc: %Lu to_free=%Lu, csum_free=%Lu, dropped=%u, outstanding_extents=%u, reserved_extents=%u, drop_reserved=%u, reserved=%Lu, csum_bytes=%Lu\n",
+ btrfs_ino(inode), extent_free, csum_free, dropped, BTRFS_I(inode)->outstanding_extents, BTRFS_I(inode)->reserved_extents, dropping_reserve, BTRFS_I(inode)->reserved, BTRFS_I(inode)->csum_bytes);
+ */
spin_unlock(&BTRFS_I(inode)->lock);
- if (dropped > 0)
- to_free += btrfs_calc_trans_metadata_size(root, dropped);
+ trace_printk("%pU: delalloc: %Lu released %Lu\n", root->fs_info->fsid,
+ btrfs_ino(inode), to_free);
+// trace_printk("%pU: delalloc: %s: %Lu released %Lu\n", root->fs_info->fsid,
+// symname, btrfs_ino(inode), to_free);
btrfs_block_rsv_release(root, &root->fs_info->delalloc_block_rsv,
to_free);
}
diff --git a/fs/btrfs/inode-map.c b/fs/btrfs/inode-map.c
index f8962a957d656..48a59ebbd0dd0 100644
--- a/fs/btrfs/inode-map.c
+++ b/fs/btrfs/inode-map.c
@@ -438,6 +438,8 @@ int btrfs_save_ino_cache(struct btrfs_root *root,
trans->bytes_reserved);
if (ret)
goto out;
+ trace_printk("%pU: ino_cache: %p reserved %Lu\n",
+ root->fs_info->fsid, trans, trans->bytes_reserved);
again:
inode = lookup_free_ino_inode(root, path);
if (IS_ERR(inode) && PTR_ERR(inode) != -ENOENT) {
@@ -482,7 +484,10 @@ again:
/* Just to make sure we have enough space */
prealloc += 8 * PAGE_CACHE_SIZE;
+ /* Not really needed but for correctness sake */
+ mutex_lock(&inode->i_mutex);
ret = btrfs_delalloc_reserve_space(inode, prealloc);
+ mutex_unlock(&inode->i_mutex);
if (ret)
goto out_put;
@@ -498,6 +503,8 @@ again:
out_put:
iput(inode);
out_release:
+ trace_printk("%pU: ino_cache: %p released %Lu\n", root->fs_info->fsid,
+ trans, trans->bytes_reserved);
btrfs_block_rsv_release(root, trans->block_rsv, trans->bytes_reserved);
out:
trans->block_rsv = rsv;
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 9de15f1323766..0b8e6afbe0b54 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -630,7 +630,6 @@ retry:
trans = btrfs_join_transaction(root);
BUG_ON(IS_ERR(trans));
- trans->block_rsv = &root->fs_info->delalloc_block_rsv;
ret = btrfs_reserve_extent(trans, root,
async_extent->compressed_size,
async_extent->compressed_size,
@@ -1375,13 +1374,10 @@ static void btrfs_clear_bit_hook(struct inode *inode,
u64 len = state->end + 1 - state->start;
bool do_list = !btrfs_is_free_space_inode(root, inode);
- if (*bits & EXTENT_FIRST_DELALLOC) {
+ if (*bits & EXTENT_FIRST_DELALLOC)
*bits &= ~EXTENT_FIRST_DELALLOC;
- } else if (!(*bits & EXTENT_DO_ACCOUNTING)) {
- spin_lock(&BTRFS_I(inode)->lock);
- BTRFS_I(inode)->outstanding_extents--;
- spin_unlock(&BTRFS_I(inode)->lock);
- }
+ else if (!(*bits & EXTENT_DO_ACCOUNTING))
+ WARN_ON(1);
if (*bits & EXTENT_DO_ACCOUNTING)
btrfs_delalloc_release_metadata(inode, len);
@@ -2207,7 +2203,13 @@ int btrfs_orphan_cleanup(struct btrfs_root *root)
continue;
}
nr_truncate++;
+ /* Need to hold the imutex for reservation purposes, not
+ * a huge deal here but I've got a WARN_ON in
+ * btrfs_delalloc_reserve_space to catch offenders.
+ */
+ mutex_lock(&inode->i_mutex);
ret = btrfs_truncate(inode);
+ mutex_unlock(&inode->i_mutex);
} else {
nr_unlink++;
}
@@ -6127,7 +6129,10 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
lockend = offset + count - 1;
if (writing) {
+ /* Need this to keep space reservations serialized. */
+ mutex_lock(&inode->i_mutex);
ret = btrfs_delalloc_reserve_space(inode, count);
+ mutex_unlock(&inode->i_mutex);
if (ret)
goto out;
}
@@ -6357,7 +6362,13 @@ int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
u64 page_start;
u64 page_end;
+ /*
+ * Reservation code has to be gaurded by the i_mutex to keep multiple
+ * reservations from happening at the same time.
+ */
+ mutex_lock(&inode->i_mutex);
ret = btrfs_delalloc_reserve_space(inode, PAGE_CACHE_SIZE);
+ mutex_unlock(&inode->i_mutex);
if (!ret)
ret = btrfs_update_time(vma->vm_file);
if (ret) {
@@ -6685,6 +6696,7 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
spin_lock_init(&ei->lock);
ei->outstanding_extents = 0;
ei->reserved_extents = 0;
+ ei->reserved = 0;
ei->ordered_data_close = 0;
ei->orphan_meta_reserved = 0;
@@ -6727,6 +6739,7 @@ void btrfs_destroy_inode(struct inode *inode)
WARN_ON(BTRFS_I(inode)->reserved_extents);
WARN_ON(BTRFS_I(inode)->delalloc_bytes);
WARN_ON(BTRFS_I(inode)->csum_bytes);
+ WARN_ON(BTRFS_I(inode)->reserved);
/*
* This can happen where we create an inode, but somebody else also
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 4a34c472f1261..2551a0139f551 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -858,8 +858,10 @@ static int cluster_pages_for_defrag(struct inode *inode,
return 0;
file_end = (isize - 1) >> PAGE_CACHE_SHIFT;
+ mutex_lock(&inode->i_mutex);
ret = btrfs_delalloc_reserve_space(inode,
num_pages << PAGE_CACHE_SHIFT);
+ mutex_unlock(&inode->i_mutex);
if (ret)
return ret;
again:
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index dff29d5e151a3..cfb55434a4698 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -2947,7 +2947,9 @@ static int relocate_file_extent_cluster(struct inode *inode,
index = (cluster->start - offset) >> PAGE_CACHE_SHIFT;
last_index = (cluster->end - offset) >> PAGE_CACHE_SHIFT;
while (index <= last_index) {
+ mutex_lock(&inode->i_mutex);
ret = btrfs_delalloc_reserve_metadata(inode, PAGE_CACHE_SIZE);
+ mutex_unlock(&inode->i_mutex);
if (ret)
goto out;
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 81376d94cd3c6..8f1430c1c0b90 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -314,6 +314,9 @@ again:
h->block_rsv = NULL;
h->orig_rsv = NULL;
+ if (num_bytes)
+ trace_printk("%pU: transaction: %p reserve %Lu\n",
+ root->fs_info->fsid, h, num_bytes);
smp_mb();
if (cur_trans->blocked && may_wait_transaction(root, type)) {
btrfs_commit_transaction(h, root);