Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 274607
b: refs/heads/master
c: 7709cde
h: refs/heads/master
i:
  274605: e402270
  274603: 3cc4c6e
  274599: e419719
  274591: 4ac8daa
v: v3
  • Loading branch information
Josef Bacik committed Oct 19, 2011
1 parent 2be62d0 commit acc4c54
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 9 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: 9e4871070b5f070cacf26525389d56e0345ba156
refs/heads/master: 7709cde33f12db71efb377fae4ae7aab6c94ebc6
6 changes: 6 additions & 0 deletions trunk/fs/btrfs/btrfs_inode.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,12 @@ struct btrfs_inode {
*/
u64 last_unlink_trans;

/*
* Number of bytes outstanding that are going to need csums. This is
* used in ENOSPC accounting.
*/
u64 csum_bytes;

/* flags field from the on disk inode */
u32 flags;

Expand Down
117 changes: 109 additions & 8 deletions trunk/fs/btrfs/extent-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -3984,11 +3984,19 @@ int btrfs_snap_reserve_metadata(struct btrfs_trans_handle *trans,
return block_rsv_migrate_bytes(src_rsv, dst_rsv, num_bytes);
}

/**
* drop_outstanding_extent - drop an outstanding extent
* @inode: the inode we're dropping the extent for
*
* This is called when we are freeing up an outstanding extent, either called
* after an error or after an extent is written. This will return the number of
* reserved extents that need to be freed. This must be called with
* BTRFS_I(inode)->lock held.
*/
static unsigned drop_outstanding_extent(struct inode *inode)
{
unsigned dropped_extents = 0;

spin_lock(&BTRFS_I(inode)->lock);
BUG_ON(!BTRFS_I(inode)->outstanding_extents);
BTRFS_I(inode)->outstanding_extents--;

Expand All @@ -3998,19 +4006,70 @@ static unsigned drop_outstanding_extent(struct inode *inode)
*/
if (BTRFS_I(inode)->outstanding_extents >=
BTRFS_I(inode)->reserved_extents)
goto out;
return 0;

dropped_extents = BTRFS_I(inode)->reserved_extents -
BTRFS_I(inode)->outstanding_extents;
BTRFS_I(inode)->reserved_extents -= dropped_extents;
out:
spin_unlock(&BTRFS_I(inode)->lock);
return dropped_extents;
}

static u64 calc_csum_metadata_size(struct inode *inode, u64 num_bytes)
/**
* calc_csum_metadata_size - return the amount of metada space that must be
* reserved/free'd for the given bytes.
* @inode: the inode we're manipulating
* @num_bytes: the number of bytes in question
* @reserve: 1 if we are reserving space, 0 if we are freeing space
*
* This adjusts the number of csum_bytes in the inode and then returns the
* correct amount of metadata that must either be reserved or freed. We
* calculate how many checksums we can fit into one leaf and then divide the
* number of bytes that will need to be checksumed by this value to figure out
* how many checksums will be required. If we are adding bytes then the number
* may go up and we will return the number of additional bytes that must be
* reserved. If it is going down we will return the number of bytes that must
* be freed.
*
* This must be called with BTRFS_I(inode)->lock held.
*/
static u64 calc_csum_metadata_size(struct inode *inode, u64 num_bytes,
int reserve)
{
return num_bytes >>= 3;
struct btrfs_root *root = BTRFS_I(inode)->root;
u64 csum_size;
int num_csums_per_leaf;
int num_csums;
int old_csums;

if (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM &&
BTRFS_I(inode)->csum_bytes == 0)
return 0;

old_csums = (int)div64_u64(BTRFS_I(inode)->csum_bytes, root->sectorsize);
if (reserve)
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) +
sizeof(struct btrfs_disk_key));
num_csums = (int)div64_u64(BTRFS_I(inode)->csum_bytes, root->sectorsize);
num_csums = num_csums + num_csums_per_leaf - 1;
num_csums = num_csums / num_csums_per_leaf;

old_csums = old_csums + num_csums_per_leaf - 1;
old_csums = old_csums / num_csums_per_leaf;

/* No change, no need to reserve more */
if (old_csums == num_csums)
return 0;

if (reserve)
return btrfs_calc_trans_metadata_size(root,
num_csums - old_csums);

return btrfs_calc_trans_metadata_size(root, old_csums - num_csums);
}

int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
Expand All @@ -4037,18 +4096,21 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)

to_reserve = btrfs_calc_trans_metadata_size(root, nr_extents);
}
to_reserve += calc_csum_metadata_size(inode, num_bytes, 1);
spin_unlock(&BTRFS_I(inode)->lock);

to_reserve += calc_csum_metadata_size(inode, num_bytes);
ret = reserve_metadata_bytes(NULL, root, block_rsv, to_reserve, 1);
if (ret) {
unsigned dropped;
/*
* We don't need the return value since our reservation failed,
* we just need to clean up our counter.
*/
spin_lock(&BTRFS_I(inode)->lock);
dropped = drop_outstanding_extent(inode);
WARN_ON(dropped > 1);
BTRFS_I(inode)->csum_bytes -= num_bytes;
spin_unlock(&BTRFS_I(inode)->lock);
return ret;
}

Expand All @@ -4057,23 +4119,49 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
return 0;
}

/**
* btrfs_delalloc_release_metadata - release a metadata reservation for an inode
* @inode: the inode to release the reservation for
* @num_bytes: the number of bytes we're releasing
*
* This will release the metadata reservation for an inode. This can be called
* once we complete IO for a given set of bytes to release their metadata
* reservations.
*/
void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes)
{
struct btrfs_root *root = BTRFS_I(inode)->root;
u64 to_free = 0;
unsigned dropped;

num_bytes = ALIGN(num_bytes, root->sectorsize);
spin_lock(&BTRFS_I(inode)->lock);
dropped = drop_outstanding_extent(inode);

to_free = calc_csum_metadata_size(inode, num_bytes);
to_free = calc_csum_metadata_size(inode, num_bytes, 0);
spin_unlock(&BTRFS_I(inode)->lock);
if (dropped > 0)
to_free += btrfs_calc_trans_metadata_size(root, dropped);

btrfs_block_rsv_release(root, &root->fs_info->delalloc_block_rsv,
to_free);
}

/**
* btrfs_delalloc_reserve_space - reserve data and metadata space for delalloc
* @inode: inode we're writing to
* @num_bytes: the number of bytes we want to allocate
*
* This will do the following things
*
* o reserve space in the data space info for num_bytes
* o reserve space in the metadata space info based on number of outstanding
* extents and how much csums will be needed
* o add to the inodes ->delalloc_bytes
* o add it to the fs_info's delalloc inodes list.
*
* This will return 0 for success and -ENOSPC if there is no space left.
*/
int btrfs_delalloc_reserve_space(struct inode *inode, u64 num_bytes)
{
int ret;
Expand All @@ -4091,6 +4179,19 @@ int btrfs_delalloc_reserve_space(struct inode *inode, u64 num_bytes)
return 0;
}

/**
* btrfs_delalloc_release_space - release data and metadata space for delalloc
* @inode: inode we're releasing space for
* @num_bytes: the number of bytes we want to free up
*
* This must be matched with a call to btrfs_delalloc_reserve_space. This is
* called in the case that we don't need the metadata AND data reservations
* anymore. So if there is an error or we insert an inline extent.
*
* This function will release the metadata space that was not used and will
* decrement ->delalloc_bytes and remove it from the fs_info delalloc_inodes
* list if there are no delalloc bytes left.
*/
void btrfs_delalloc_release_space(struct inode *inode, u64 num_bytes)
{
btrfs_delalloc_release_metadata(inode, num_bytes);
Expand Down
3 changes: 3 additions & 0 deletions trunk/fs/btrfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -6757,6 +6757,7 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
ei->delalloc_bytes = 0;
ei->disk_i_size = 0;
ei->flags = 0;
ei->csum_bytes = 0;
ei->index_cnt = (u64)-1;
ei->last_unlink_trans = 0;

Expand Down Expand Up @@ -6802,6 +6803,8 @@ void btrfs_destroy_inode(struct inode *inode)
WARN_ON(inode->i_data.nrpages);
WARN_ON(BTRFS_I(inode)->outstanding_extents);
WARN_ON(BTRFS_I(inode)->reserved_extents);
WARN_ON(BTRFS_I(inode)->delalloc_bytes);
WARN_ON(BTRFS_I(inode)->csum_bytes);

/*
* This can happen where we create an inode, but somebody else also
Expand Down

0 comments on commit acc4c54

Please sign in to comment.