|
@@ -23,6 +23,7 @@
|
|
|
#include <linux/rcupdate.h>
|
|
|
#include <linux/kthread.h>
|
|
|
#include <linux/slab.h>
|
|
|
+#include <linux/ratelimit.h>
|
|
|
#include "compat.h"
|
|
|
#include "hash.h"
|
|
|
#include "ctree.h"
|
|
@@ -52,6 +53,21 @@ enum {
|
|
|
CHUNK_ALLOC_LIMITED = 2,
|
|
|
};
|
|
|
|
|
|
+/*
|
|
|
+ * Control how reservations are dealt with.
|
|
|
+ *
|
|
|
+ * RESERVE_FREE - freeing a reservation.
|
|
|
+ * RESERVE_ALLOC - allocating space and we need to update bytes_may_use for
|
|
|
+ * ENOSPC accounting
|
|
|
+ * RESERVE_ALLOC_NO_ACCOUNT - allocating space and we should not update
|
|
|
+ * bytes_may_use as the ENOSPC accounting is done elsewhere
|
|
|
+ */
|
|
|
+enum {
|
|
|
+ RESERVE_FREE = 0,
|
|
|
+ RESERVE_ALLOC = 1,
|
|
|
+ RESERVE_ALLOC_NO_ACCOUNT = 2,
|
|
|
+};
|
|
|
+
|
|
|
static int update_block_group(struct btrfs_trans_handle *trans,
|
|
|
struct btrfs_root *root,
|
|
|
u64 bytenr, u64 num_bytes, int alloc);
|
|
@@ -81,6 +97,8 @@ static int find_next_key(struct btrfs_path *path, int level,
|
|
|
struct btrfs_key *key);
|
|
|
static void dump_space_info(struct btrfs_space_info *info, u64 bytes,
|
|
|
int dump_block_groups);
|
|
|
+static int btrfs_update_reserved_bytes(struct btrfs_block_group_cache *cache,
|
|
|
+ u64 num_bytes, int reserve);
|
|
|
|
|
|
static noinline int
|
|
|
block_group_cache_done(struct btrfs_block_group_cache *cache)
|
|
@@ -104,7 +122,6 @@ void btrfs_put_block_group(struct btrfs_block_group_cache *cache)
|
|
|
if (atomic_dec_and_test(&cache->count)) {
|
|
|
WARN_ON(cache->pinned > 0);
|
|
|
WARN_ON(cache->reserved > 0);
|
|
|
- WARN_ON(cache->reserved_pinned > 0);
|
|
|
kfree(cache->free_space_ctl);
|
|
|
kfree(cache);
|
|
|
}
|
|
@@ -465,7 +482,8 @@ static int cache_block_group(struct btrfs_block_group_cache *cache,
|
|
|
* we likely hold important locks.
|
|
|
*/
|
|
|
if (trans && (!trans->transaction->in_commit) &&
|
|
|
- (root && root != root->fs_info->tree_root)) {
|
|
|
+ (root && root != root->fs_info->tree_root) &&
|
|
|
+ btrfs_test_opt(root, SPACE_CACHE)) {
|
|
|
spin_lock(&cache->lock);
|
|
|
if (cache->cached != BTRFS_CACHE_NO) {
|
|
|
spin_unlock(&cache->lock);
|
|
@@ -1770,18 +1788,18 @@ static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr,
|
|
|
{
|
|
|
int ret;
|
|
|
u64 discarded_bytes = 0;
|
|
|
- struct btrfs_multi_bio *multi = NULL;
|
|
|
+ struct btrfs_bio *bbio = NULL;
|
|
|
|
|
|
|
|
|
/* Tell the block device(s) that the sectors can be discarded */
|
|
|
ret = btrfs_map_block(&root->fs_info->mapping_tree, REQ_DISCARD,
|
|
|
- bytenr, &num_bytes, &multi, 0);
|
|
|
+ bytenr, &num_bytes, &bbio, 0);
|
|
|
if (!ret) {
|
|
|
- struct btrfs_bio_stripe *stripe = multi->stripes;
|
|
|
+ struct btrfs_bio_stripe *stripe = bbio->stripes;
|
|
|
int i;
|
|
|
|
|
|
|
|
|
- for (i = 0; i < multi->num_stripes; i++, stripe++) {
|
|
|
+ for (i = 0; i < bbio->num_stripes; i++, stripe++) {
|
|
|
if (!stripe->dev->can_discard)
|
|
|
continue;
|
|
|
|
|
@@ -1800,7 +1818,7 @@ static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr,
|
|
|
*/
|
|
|
ret = 0;
|
|
|
}
|
|
|
- kfree(multi);
|
|
|
+ kfree(bbio);
|
|
|
}
|
|
|
|
|
|
if (actual_bytes)
|
|
@@ -2700,6 +2718,13 @@ again:
|
|
|
goto again;
|
|
|
}
|
|
|
|
|
|
+ /* We've already setup this transaction, go ahead and exit */
|
|
|
+ if (block_group->cache_generation == trans->transid &&
|
|
|
+ i_size_read(inode)) {
|
|
|
+ dcs = BTRFS_DC_SETUP;
|
|
|
+ goto out_put;
|
|
|
+ }
|
|
|
+
|
|
|
/*
|
|
|
* We want to set the generation to 0, that way if anything goes wrong
|
|
|
* from here on out we know not to trust this cache when we load up next
|
|
@@ -2749,12 +2774,15 @@ again:
|
|
|
if (!ret)
|
|
|
dcs = BTRFS_DC_SETUP;
|
|
|
btrfs_free_reserved_data_space(inode, num_pages);
|
|
|
+
|
|
|
out_put:
|
|
|
iput(inode);
|
|
|
out_free:
|
|
|
btrfs_release_path(path);
|
|
|
out:
|
|
|
spin_lock(&block_group->lock);
|
|
|
+ if (!ret)
|
|
|
+ block_group->cache_generation = trans->transid;
|
|
|
block_group->disk_cache_state = dcs;
|
|
|
spin_unlock(&block_group->lock);
|
|
|
|
|
@@ -3122,16 +3150,13 @@ commit_trans:
|
|
|
return -ENOSPC;
|
|
|
}
|
|
|
data_sinfo->bytes_may_use += bytes;
|
|
|
- BTRFS_I(inode)->reserved_bytes += bytes;
|
|
|
spin_unlock(&data_sinfo->lock);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * called when we are clearing an delalloc extent from the
|
|
|
- * inode's io_tree or there was an error for whatever reason
|
|
|
- * after calling btrfs_check_data_free_space
|
|
|
+ * Called if we need to clear a data reservation for this inode.
|
|
|
*/
|
|
|
void btrfs_free_reserved_data_space(struct inode *inode, u64 bytes)
|
|
|
{
|
|
@@ -3144,7 +3169,6 @@ void btrfs_free_reserved_data_space(struct inode *inode, u64 bytes)
|
|
|
data_sinfo = BTRFS_I(inode)->space_info;
|
|
|
spin_lock(&data_sinfo->lock);
|
|
|
data_sinfo->bytes_may_use -= bytes;
|
|
|
- BTRFS_I(inode)->reserved_bytes -= bytes;
|
|
|
spin_unlock(&data_sinfo->lock);
|
|
|
}
|
|
|
|
|
@@ -3165,6 +3189,7 @@ static int should_alloc_chunk(struct btrfs_root *root,
|
|
|
struct btrfs_space_info *sinfo, u64 alloc_bytes,
|
|
|
int force)
|
|
|
{
|
|
|
+ struct btrfs_block_rsv *global_rsv = &root->fs_info->global_block_rsv;
|
|
|
u64 num_bytes = sinfo->total_bytes - sinfo->bytes_readonly;
|
|
|
u64 num_allocated = sinfo->bytes_used + sinfo->bytes_reserved;
|
|
|
u64 thresh;
|
|
@@ -3172,12 +3197,19 @@ static int should_alloc_chunk(struct btrfs_root *root,
|
|
|
if (force == CHUNK_ALLOC_FORCE)
|
|
|
return 1;
|
|
|
|
|
|
+ /*
|
|
|
+ * We need to take into account the global rsv because for all intents
|
|
|
+ * and purposes it's used space. Don't worry about locking the
|
|
|
+ * global_rsv, it doesn't change except when the transaction commits.
|
|
|
+ */
|
|
|
+ num_allocated += global_rsv->size;
|
|
|
+
|
|
|
/*
|
|
|
* in limited mode, we want to have some free space up to
|
|
|
* about 1% of the FS size.
|
|
|
*/
|
|
|
if (force == CHUNK_ALLOC_LIMITED) {
|
|
|
- thresh = btrfs_super_total_bytes(&root->fs_info->super_copy);
|
|
|
+ thresh = btrfs_super_total_bytes(root->fs_info->super_copy);
|
|
|
thresh = max_t(u64, 64 * 1024 * 1024,
|
|
|
div_factor_fine(thresh, 1));
|
|
|
|
|
@@ -3199,7 +3231,7 @@ static int should_alloc_chunk(struct btrfs_root *root,
|
|
|
if (num_allocated + alloc_bytes < div_factor(num_bytes, 8))
|
|
|
return 0;
|
|
|
|
|
|
- thresh = btrfs_super_total_bytes(&root->fs_info->super_copy);
|
|
|
+ thresh = btrfs_super_total_bytes(root->fs_info->super_copy);
|
|
|
|
|
|
/* 256MB or 5% of the FS */
|
|
|
thresh = max_t(u64, 256 * 1024 * 1024, div_factor_fine(thresh, 5));
|
|
@@ -3302,24 +3334,26 @@ out:
|
|
|
/*
|
|
|
* shrink metadata reservation for delalloc
|
|
|
*/
|
|
|
-static int shrink_delalloc(struct btrfs_trans_handle *trans,
|
|
|
- struct btrfs_root *root, u64 to_reclaim, int sync)
|
|
|
+static int shrink_delalloc(struct btrfs_root *root, u64 to_reclaim,
|
|
|
+ bool wait_ordered)
|
|
|
{
|
|
|
struct btrfs_block_rsv *block_rsv;
|
|
|
struct btrfs_space_info *space_info;
|
|
|
+ struct btrfs_trans_handle *trans;
|
|
|
u64 reserved;
|
|
|
u64 max_reclaim;
|
|
|
u64 reclaimed = 0;
|
|
|
long time_left;
|
|
|
- int nr_pages = (2 * 1024 * 1024) >> PAGE_CACHE_SHIFT;
|
|
|
+ unsigned long nr_pages = (2 * 1024 * 1024) >> PAGE_CACHE_SHIFT;
|
|
|
int loops = 0;
|
|
|
unsigned long progress;
|
|
|
|
|
|
+ trans = (struct btrfs_trans_handle *)current->journal_info;
|
|
|
block_rsv = &root->fs_info->delalloc_block_rsv;
|
|
|
space_info = block_rsv->space_info;
|
|
|
|
|
|
smp_mb();
|
|
|
- reserved = space_info->bytes_reserved;
|
|
|
+ reserved = space_info->bytes_may_use;
|
|
|
progress = space_info->reservation_progress;
|
|
|
|
|
|
if (reserved == 0)
|
|
@@ -3334,7 +3368,8 @@ static int shrink_delalloc(struct btrfs_trans_handle *trans,
|
|
|
}
|
|
|
|
|
|
max_reclaim = min(reserved, to_reclaim);
|
|
|
-
|
|
|
+ nr_pages = max_t(unsigned long, nr_pages,
|
|
|
+ max_reclaim >> PAGE_CACHE_SHIFT);
|
|
|
while (loops < 1024) {
|
|
|
/* have the flusher threads jump in and do some IO */
|
|
|
smp_mb();
|
|
@@ -3344,9 +3379,9 @@ static int shrink_delalloc(struct btrfs_trans_handle *trans,
|
|
|
WB_REASON_FS_FREE_SPACE);
|
|
|
|
|
|
spin_lock(&space_info->lock);
|
|
|
- if (reserved > space_info->bytes_reserved)
|
|
|
- reclaimed += reserved - space_info->bytes_reserved;
|
|
|
- reserved = space_info->bytes_reserved;
|
|
|
+ if (reserved > space_info->bytes_may_use)
|
|
|
+ reclaimed += reserved - space_info->bytes_may_use;
|
|
|
+ reserved = space_info->bytes_may_use;
|
|
|
spin_unlock(&space_info->lock);
|
|
|
|
|
|
loops++;
|
|
@@ -3357,11 +3392,15 @@ static int shrink_delalloc(struct btrfs_trans_handle *trans,
|
|
|
if (trans && trans->transaction->blocked)
|
|
|
return -EAGAIN;
|
|
|
|
|
|
- time_left = schedule_timeout_interruptible(1);
|
|
|
+ if (wait_ordered && !trans) {
|
|
|
+ btrfs_wait_ordered_extents(root, 0, 0);
|
|
|
+ } else {
|
|
|
+ time_left = schedule_timeout_interruptible(1);
|
|
|
|
|
|
- /* We were interrupted, exit */
|
|
|
- if (time_left)
|
|
|
- break;
|
|
|
+ /* We were interrupted, exit */
|
|
|
+ if (time_left)
|
|
|
+ break;
|
|
|
+ }
|
|
|
|
|
|
/* we've kicked the IO a few times, if anything has been freed,
|
|
|
* exit. There is no sense in looping here for a long time
|
|
@@ -3376,34 +3415,90 @@ static int shrink_delalloc(struct btrfs_trans_handle *trans,
|
|
|
}
|
|
|
|
|
|
}
|
|
|
- if (reclaimed >= to_reclaim && !trans)
|
|
|
- btrfs_wait_ordered_extents(root, 0, 0);
|
|
|
+
|
|
|
return reclaimed >= to_reclaim;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * Retries tells us how many times we've called reserve_metadata_bytes. The
|
|
|
- * idea is if this is the first call (retries == 0) then we will add to our
|
|
|
- * reserved count if we can't make the allocation in order to hold our place
|
|
|
- * while we go and try and free up space. That way for retries > 1 we don't try
|
|
|
- * and add space, we just check to see if the amount of unused space is >= the
|
|
|
- * total space, meaning that our reservation is valid.
|
|
|
+/**
|
|
|
+ * maybe_commit_transaction - possibly commit the transaction if its ok to
|
|
|
+ * @root - the root we're allocating for
|
|
|
+ * @bytes - the number of bytes we want to reserve
|
|
|
+ * @force - force the commit
|
|
|
*
|
|
|
- * However if we don't intend to retry this reservation, pass -1 as retries so
|
|
|
- * that it short circuits this logic.
|
|
|
+ * This will check to make sure that committing the transaction will actually
|
|
|
+ * get us somewhere and then commit the transaction if it does. Otherwise it
|
|
|
+ * will return -ENOSPC.
|
|
|
*/
|
|
|
-static int reserve_metadata_bytes(struct btrfs_trans_handle *trans,
|
|
|
- struct btrfs_root *root,
|
|
|
+static int may_commit_transaction(struct btrfs_root *root,
|
|
|
+ struct btrfs_space_info *space_info,
|
|
|
+ u64 bytes, int force)
|
|
|
+{
|
|
|
+ struct btrfs_block_rsv *delayed_rsv = &root->fs_info->delayed_block_rsv;
|
|
|
+ struct btrfs_trans_handle *trans;
|
|
|
+
|
|
|
+ trans = (struct btrfs_trans_handle *)current->journal_info;
|
|
|
+ if (trans)
|
|
|
+ return -EAGAIN;
|
|
|
+
|
|
|
+ if (force)
|
|
|
+ goto commit;
|
|
|
+
|
|
|
+ /* See if there is enough pinned space to make this reservation */
|
|
|
+ spin_lock(&space_info->lock);
|
|
|
+ if (space_info->bytes_pinned >= bytes) {
|
|
|
+ spin_unlock(&space_info->lock);
|
|
|
+ goto commit;
|
|
|
+ }
|
|
|
+ spin_unlock(&space_info->lock);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * See if there is some space in the delayed insertion reservation for
|
|
|
+ * this reservation.
|
|
|
+ */
|
|
|
+ if (space_info != delayed_rsv->space_info)
|
|
|
+ return -ENOSPC;
|
|
|
+
|
|
|
+ spin_lock(&delayed_rsv->lock);
|
|
|
+ if (delayed_rsv->size < bytes) {
|
|
|
+ spin_unlock(&delayed_rsv->lock);
|
|
|
+ return -ENOSPC;
|
|
|
+ }
|
|
|
+ spin_unlock(&delayed_rsv->lock);
|
|
|
+
|
|
|
+commit:
|
|
|
+ trans = btrfs_join_transaction(root);
|
|
|
+ if (IS_ERR(trans))
|
|
|
+ return -ENOSPC;
|
|
|
+
|
|
|
+ return btrfs_commit_transaction(trans, root);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * reserve_metadata_bytes - try to reserve bytes from the block_rsv's space
|
|
|
+ * @root - the root we're allocating for
|
|
|
+ * @block_rsv - the block_rsv we're allocating for
|
|
|
+ * @orig_bytes - the number of bytes we want
|
|
|
+ * @flush - wether or not we can flush to make our reservation
|
|
|
+ *
|
|
|
+ * This will reserve orgi_bytes number of bytes from the space info associated
|
|
|
+ * with the block_rsv. If there is not enough space it will make an attempt to
|
|
|
+ * flush out space to make room. It will do this by flushing delalloc if
|
|
|
+ * possible or committing the transaction. If flush is 0 then no attempts to
|
|
|
+ * regain reservations will be made and this will fail if there is not enough
|
|
|
+ * space already.
|
|
|
+ */
|
|
|
+static int reserve_metadata_bytes(struct btrfs_root *root,
|
|
|
struct btrfs_block_rsv *block_rsv,
|
|
|
u64 orig_bytes, int flush)
|
|
|
{
|
|
|
struct btrfs_space_info *space_info = block_rsv->space_info;
|
|
|
- u64 unused;
|
|
|
+ u64 used;
|
|
|
u64 num_bytes = orig_bytes;
|
|
|
int retries = 0;
|
|
|
int ret = 0;
|
|
|
bool committed = false;
|
|
|
bool flushing = false;
|
|
|
+ bool wait_ordered = false;
|
|
|
|
|
|
again:
|
|
|
ret = 0;
|
|
@@ -3420,7 +3515,7 @@ again:
|
|
|
* deadlock since we are waiting for the flusher to finish, but
|
|
|
* hold the current transaction open.
|
|
|
*/
|
|
|
- if (trans)
|
|
|
+ if (current->journal_info)
|
|
|
return -EAGAIN;
|
|
|
ret = wait_event_interruptible(space_info->wait,
|
|
|
!space_info->flush);
|
|
@@ -3432,9 +3527,9 @@ again:
|
|
|
}
|
|
|
|
|
|
ret = -ENOSPC;
|
|
|
- unused = space_info->bytes_used + space_info->bytes_reserved +
|
|
|
- space_info->bytes_pinned + space_info->bytes_readonly +
|
|
|
- space_info->bytes_may_use;
|
|
|
+ used = space_info->bytes_used + space_info->bytes_reserved +
|
|
|
+ space_info->bytes_pinned + space_info->bytes_readonly +
|
|
|
+ space_info->bytes_may_use;
|
|
|
|
|
|
/*
|
|
|
* The idea here is that we've not already over-reserved the block group
|
|
@@ -3443,10 +3538,9 @@ again:
|
|
|
* lets start flushing stuff first and then come back and try to make
|
|
|
* our reservation.
|
|
|
*/
|
|
|
- if (unused <= space_info->total_bytes) {
|
|
|
- unused = space_info->total_bytes - unused;
|
|
|
- if (unused >= num_bytes) {
|
|
|
- space_info->bytes_reserved += orig_bytes;
|
|
|
+ if (used <= space_info->total_bytes) {
|
|
|
+ if (used + orig_bytes <= space_info->total_bytes) {
|
|
|
+ space_info->bytes_may_use += orig_bytes;
|
|
|
ret = 0;
|
|
|
} else {
|
|
|
/*
|
|
@@ -3462,10 +3556,64 @@ again:
|
|
|
* amount plus the amount of bytes that we need for this
|
|
|
* reservation.
|
|
|
*/
|
|
|
- num_bytes = unused - space_info->total_bytes +
|
|
|
+ wait_ordered = true;
|
|
|
+ num_bytes = used - space_info->total_bytes +
|
|
|
(orig_bytes * (retries + 1));
|
|
|
}
|
|
|
|
|
|
+ if (ret) {
|
|
|
+ u64 profile = btrfs_get_alloc_profile(root, 0);
|
|
|
+ u64 avail;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If we have a lot of space that's pinned, don't bother doing
|
|
|
+ * the overcommit dance yet and just commit the transaction.
|
|
|
+ */
|
|
|
+ avail = (space_info->total_bytes - space_info->bytes_used) * 8;
|
|
|
+ do_div(avail, 10);
|
|
|
+ if (space_info->bytes_pinned >= avail && flush && !committed) {
|
|
|
+ space_info->flush = 1;
|
|
|
+ flushing = true;
|
|
|
+ spin_unlock(&space_info->lock);
|
|
|
+ ret = may_commit_transaction(root, space_info,
|
|
|
+ orig_bytes, 1);
|
|
|
+ if (ret)
|
|
|
+ goto out;
|
|
|
+ committed = true;
|
|
|
+ goto again;
|
|
|
+ }
|
|
|
+
|
|
|
+ spin_lock(&root->fs_info->free_chunk_lock);
|
|
|
+ avail = root->fs_info->free_chunk_space;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If we have dup, raid1 or raid10 then only half of the free
|
|
|
+ * space is actually useable.
|
|
|
+ */
|
|
|
+ if (profile & (BTRFS_BLOCK_GROUP_DUP |
|
|
|
+ BTRFS_BLOCK_GROUP_RAID1 |
|
|
|
+ BTRFS_BLOCK_GROUP_RAID10))
|
|
|
+ avail >>= 1;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If we aren't flushing don't let us overcommit too much, say
|
|
|
+ * 1/8th of the space. If we can flush, let it overcommit up to
|
|
|
+ * 1/2 of the space.
|
|
|
+ */
|
|
|
+ if (flush)
|
|
|
+ avail >>= 3;
|
|
|
+ else
|
|
|
+ avail >>= 1;
|
|
|
+ spin_unlock(&root->fs_info->free_chunk_lock);
|
|
|
+
|
|
|
+ if (used + num_bytes < space_info->total_bytes + avail) {
|
|
|
+ space_info->bytes_may_use += orig_bytes;
|
|
|
+ ret = 0;
|
|
|
+ } else {
|
|
|
+ wait_ordered = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/*
|
|
|
* Couldn't make our reservation, save our place so while we're trying
|
|
|
* to reclaim space we can actually use it instead of somebody else
|
|
@@ -3485,7 +3633,7 @@ again:
|
|
|
* We do synchronous shrinking since we don't actually unreserve
|
|
|
* metadata until after the IO is completed.
|
|
|
*/
|
|
|
- ret = shrink_delalloc(trans, root, num_bytes, 1);
|
|
|
+ ret = shrink_delalloc(root, num_bytes, wait_ordered);
|
|
|
if (ret < 0)
|
|
|
goto out;
|
|
|
|
|
@@ -3497,35 +3645,17 @@ again:
|
|
|
* so go back around and try again.
|
|
|
*/
|
|
|
if (retries < 2) {
|
|
|
+ wait_ordered = true;
|
|
|
retries++;
|
|
|
goto again;
|
|
|
}
|
|
|
|
|
|
- /*
|
|
|
- * Not enough space to be reclaimed, don't bother committing the
|
|
|
- * transaction.
|
|
|
- */
|
|
|
- spin_lock(&space_info->lock);
|
|
|
- if (space_info->bytes_pinned < orig_bytes)
|
|
|
- ret = -ENOSPC;
|
|
|
- spin_unlock(&space_info->lock);
|
|
|
- if (ret)
|
|
|
- goto out;
|
|
|
-
|
|
|
- ret = -EAGAIN;
|
|
|
- if (trans)
|
|
|
- goto out;
|
|
|
-
|
|
|
ret = -ENOSPC;
|
|
|
if (committed)
|
|
|
goto out;
|
|
|
|
|
|
- trans = btrfs_join_transaction(root);
|
|
|
- if (IS_ERR(trans))
|
|
|
- goto out;
|
|
|
- ret = btrfs_commit_transaction(trans, root);
|
|
|
+ ret = may_commit_transaction(root, space_info, orig_bytes, 0);
|
|
|
if (!ret) {
|
|
|
- trans = NULL;
|
|
|
committed = true;
|
|
|
goto again;
|
|
|
}
|
|
@@ -3543,10 +3673,12 @@ out:
|
|
|
static struct btrfs_block_rsv *get_block_rsv(struct btrfs_trans_handle *trans,
|
|
|
struct btrfs_root *root)
|
|
|
{
|
|
|
- struct btrfs_block_rsv *block_rsv;
|
|
|
- if (root->ref_cows)
|
|
|
+ struct btrfs_block_rsv *block_rsv = NULL;
|
|
|
+
|
|
|
+ if (root->ref_cows || root == root->fs_info->csum_root)
|
|
|
block_rsv = trans->block_rsv;
|
|
|
- else
|
|
|
+
|
|
|
+ if (!block_rsv)
|
|
|
block_rsv = root->block_rsv;
|
|
|
|
|
|
if (!block_rsv)
|
|
@@ -3617,7 +3749,7 @@ static void block_rsv_release_bytes(struct btrfs_block_rsv *block_rsv,
|
|
|
}
|
|
|
if (num_bytes) {
|
|
|
spin_lock(&space_info->lock);
|
|
|
- space_info->bytes_reserved -= num_bytes;
|
|
|
+ space_info->bytes_may_use -= num_bytes;
|
|
|
space_info->reservation_progress++;
|
|
|
spin_unlock(&space_info->lock);
|
|
|
}
|
|
@@ -3641,9 +3773,6 @@ void btrfs_init_block_rsv(struct btrfs_block_rsv *rsv)
|
|
|
{
|
|
|
memset(rsv, 0, sizeof(*rsv));
|
|
|
spin_lock_init(&rsv->lock);
|
|
|
- atomic_set(&rsv->usage, 1);
|
|
|
- rsv->priority = 6;
|
|
|
- INIT_LIST_HEAD(&rsv->list);
|
|
|
}
|
|
|
|
|
|
struct btrfs_block_rsv *btrfs_alloc_block_rsv(struct btrfs_root *root)
|
|
@@ -3664,38 +3793,38 @@ struct btrfs_block_rsv *btrfs_alloc_block_rsv(struct btrfs_root *root)
|
|
|
void btrfs_free_block_rsv(struct btrfs_root *root,
|
|
|
struct btrfs_block_rsv *rsv)
|
|
|
{
|
|
|
- if (rsv && atomic_dec_and_test(&rsv->usage)) {
|
|
|
- btrfs_block_rsv_release(root, rsv, (u64)-1);
|
|
|
- if (!rsv->durable)
|
|
|
- kfree(rsv);
|
|
|
- }
|
|
|
+ btrfs_block_rsv_release(root, rsv, (u64)-1);
|
|
|
+ kfree(rsv);
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * make the block_rsv struct be able to capture freed space.
|
|
|
- * the captured space will re-add to the the block_rsv struct
|
|
|
- * after transaction commit
|
|
|
- */
|
|
|
-void btrfs_add_durable_block_rsv(struct btrfs_fs_info *fs_info,
|
|
|
- struct btrfs_block_rsv *block_rsv)
|
|
|
+int btrfs_block_rsv_add(struct btrfs_root *root,
|
|
|
+ struct btrfs_block_rsv *block_rsv,
|
|
|
+ u64 num_bytes)
|
|
|
{
|
|
|
- block_rsv->durable = 1;
|
|
|
- mutex_lock(&fs_info->durable_block_rsv_mutex);
|
|
|
- list_add_tail(&block_rsv->list, &fs_info->durable_block_rsv_list);
|
|
|
- mutex_unlock(&fs_info->durable_block_rsv_mutex);
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ if (num_bytes == 0)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ ret = reserve_metadata_bytes(root, block_rsv, num_bytes, 1);
|
|
|
+ if (!ret) {
|
|
|
+ block_rsv_add_bytes(block_rsv, num_bytes, 1);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
-int btrfs_block_rsv_add(struct btrfs_trans_handle *trans,
|
|
|
- struct btrfs_root *root,
|
|
|
- struct btrfs_block_rsv *block_rsv,
|
|
|
- u64 num_bytes)
|
|
|
+int btrfs_block_rsv_add_noflush(struct btrfs_root *root,
|
|
|
+ struct btrfs_block_rsv *block_rsv,
|
|
|
+ u64 num_bytes)
|
|
|
{
|
|
|
int ret;
|
|
|
|
|
|
if (num_bytes == 0)
|
|
|
return 0;
|
|
|
|
|
|
- ret = reserve_metadata_bytes(trans, root, block_rsv, num_bytes, 1);
|
|
|
+ ret = reserve_metadata_bytes(root, block_rsv, num_bytes, 0);
|
|
|
if (!ret) {
|
|
|
block_rsv_add_bytes(block_rsv, num_bytes, 1);
|
|
|
return 0;
|
|
@@ -3704,55 +3833,52 @@ int btrfs_block_rsv_add(struct btrfs_trans_handle *trans,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-int btrfs_block_rsv_check(struct btrfs_trans_handle *trans,
|
|
|
- struct btrfs_root *root,
|
|
|
- struct btrfs_block_rsv *block_rsv,
|
|
|
- u64 min_reserved, int min_factor)
|
|
|
+int btrfs_block_rsv_check(struct btrfs_root *root,
|
|
|
+ struct btrfs_block_rsv *block_rsv, int min_factor)
|
|
|
{
|
|
|
u64 num_bytes = 0;
|
|
|
- int commit_trans = 0;
|
|
|
int ret = -ENOSPC;
|
|
|
|
|
|
if (!block_rsv)
|
|
|
return 0;
|
|
|
|
|
|
spin_lock(&block_rsv->lock);
|
|
|
- if (min_factor > 0)
|
|
|
- num_bytes = div_factor(block_rsv->size, min_factor);
|
|
|
- if (min_reserved > num_bytes)
|
|
|
- num_bytes = min_reserved;
|
|
|
+ num_bytes = div_factor(block_rsv->size, min_factor);
|
|
|
+ if (block_rsv->reserved >= num_bytes)
|
|
|
+ ret = 0;
|
|
|
+ spin_unlock(&block_rsv->lock);
|
|
|
|
|
|
- if (block_rsv->reserved >= num_bytes) {
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+int btrfs_block_rsv_refill(struct btrfs_root *root,
|
|
|
+ struct btrfs_block_rsv *block_rsv,
|
|
|
+ u64 min_reserved)
|
|
|
+{
|
|
|
+ u64 num_bytes = 0;
|
|
|
+ int ret = -ENOSPC;
|
|
|
+
|
|
|
+ if (!block_rsv)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ spin_lock(&block_rsv->lock);
|
|
|
+ num_bytes = min_reserved;
|
|
|
+ if (block_rsv->reserved >= num_bytes)
|
|
|
ret = 0;
|
|
|
- } else {
|
|
|
+ else
|
|
|
num_bytes -= block_rsv->reserved;
|
|
|
- if (block_rsv->durable &&
|
|
|
- block_rsv->freed[0] + block_rsv->freed[1] >= num_bytes)
|
|
|
- commit_trans = 1;
|
|
|
- }
|
|
|
spin_unlock(&block_rsv->lock);
|
|
|
+
|
|
|
if (!ret)
|
|
|
return 0;
|
|
|
|
|
|
- if (block_rsv->refill_used) {
|
|
|
- ret = reserve_metadata_bytes(trans, root, block_rsv,
|
|
|
- num_bytes, 0);
|
|
|
- if (!ret) {
|
|
|
- block_rsv_add_bytes(block_rsv, num_bytes, 0);
|
|
|
- return 0;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (commit_trans) {
|
|
|
- if (trans)
|
|
|
- return -EAGAIN;
|
|
|
- trans = btrfs_join_transaction(root);
|
|
|
- BUG_ON(IS_ERR(trans));
|
|
|
- ret = btrfs_commit_transaction(trans, root);
|
|
|
+ ret = reserve_metadata_bytes(root, block_rsv, num_bytes, 1);
|
|
|
+ if (!ret) {
|
|
|
+ block_rsv_add_bytes(block_rsv, num_bytes, 0);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
- return -ENOSPC;
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
int btrfs_block_rsv_migrate(struct btrfs_block_rsv *src_rsv,
|
|
@@ -3784,7 +3910,7 @@ static u64 calc_global_metadata_size(struct btrfs_fs_info *fs_info)
|
|
|
u64 num_bytes;
|
|
|
u64 meta_used;
|
|
|
u64 data_used;
|
|
|
- int csum_size = btrfs_super_csum_size(&fs_info->super_copy);
|
|
|
+ int csum_size = btrfs_super_csum_size(fs_info->super_copy);
|
|
|
|
|
|
sinfo = __find_space_info(fs_info, BTRFS_BLOCK_GROUP_DATA);
|
|
|
spin_lock(&sinfo->lock);
|
|
@@ -3828,12 +3954,12 @@ static void update_global_block_rsv(struct btrfs_fs_info *fs_info)
|
|
|
if (sinfo->total_bytes > num_bytes) {
|
|
|
num_bytes = sinfo->total_bytes - num_bytes;
|
|
|
block_rsv->reserved += num_bytes;
|
|
|
- sinfo->bytes_reserved += num_bytes;
|
|
|
+ sinfo->bytes_may_use += num_bytes;
|
|
|
}
|
|
|
|
|
|
if (block_rsv->reserved >= block_rsv->size) {
|
|
|
num_bytes = block_rsv->reserved - block_rsv->size;
|
|
|
- sinfo->bytes_reserved -= num_bytes;
|
|
|
+ sinfo->bytes_may_use -= num_bytes;
|
|
|
sinfo->reservation_progress++;
|
|
|
block_rsv->reserved = block_rsv->size;
|
|
|
block_rsv->full = 1;
|
|
@@ -3849,16 +3975,13 @@ static void init_global_block_rsv(struct btrfs_fs_info *fs_info)
|
|
|
|
|
|
space_info = __find_space_info(fs_info, BTRFS_BLOCK_GROUP_SYSTEM);
|
|
|
fs_info->chunk_block_rsv.space_info = space_info;
|
|
|
- fs_info->chunk_block_rsv.priority = 10;
|
|
|
|
|
|
space_info = __find_space_info(fs_info, BTRFS_BLOCK_GROUP_METADATA);
|
|
|
fs_info->global_block_rsv.space_info = space_info;
|
|
|
- fs_info->global_block_rsv.priority = 10;
|
|
|
- fs_info->global_block_rsv.refill_used = 1;
|
|
|
fs_info->delalloc_block_rsv.space_info = space_info;
|
|
|
fs_info->trans_block_rsv.space_info = space_info;
|
|
|
fs_info->empty_block_rsv.space_info = space_info;
|
|
|
- fs_info->empty_block_rsv.priority = 10;
|
|
|
+ fs_info->delayed_block_rsv.space_info = space_info;
|
|
|
|
|
|
fs_info->extent_root->block_rsv = &fs_info->global_block_rsv;
|
|
|
fs_info->csum_root->block_rsv = &fs_info->global_block_rsv;
|
|
@@ -3866,10 +3989,6 @@ static void init_global_block_rsv(struct btrfs_fs_info *fs_info)
|
|
|
fs_info->tree_root->block_rsv = &fs_info->global_block_rsv;
|
|
|
fs_info->chunk_root->block_rsv = &fs_info->chunk_block_rsv;
|
|
|
|
|
|
- btrfs_add_durable_block_rsv(fs_info, &fs_info->global_block_rsv);
|
|
|
-
|
|
|
- btrfs_add_durable_block_rsv(fs_info, &fs_info->delalloc_block_rsv);
|
|
|
-
|
|
|
update_global_block_rsv(fs_info);
|
|
|
}
|
|
|
|
|
@@ -3882,37 +4001,8 @@ static void release_global_block_rsv(struct btrfs_fs_info *fs_info)
|
|
|
WARN_ON(fs_info->trans_block_rsv.reserved > 0);
|
|
|
WARN_ON(fs_info->chunk_block_rsv.size > 0);
|
|
|
WARN_ON(fs_info->chunk_block_rsv.reserved > 0);
|
|
|
-}
|
|
|
-
|
|
|
-int btrfs_truncate_reserve_metadata(struct btrfs_trans_handle *trans,
|
|
|
- struct btrfs_root *root,
|
|
|
- struct btrfs_block_rsv *rsv)
|
|
|
-{
|
|
|
- struct btrfs_block_rsv *trans_rsv = &root->fs_info->trans_block_rsv;
|
|
|
- u64 num_bytes;
|
|
|
- int ret;
|
|
|
-
|
|
|
- /*
|
|
|
- * Truncate should be freeing data, but give us 2 items just in case it
|
|
|
- * needs to use some space. We may want to be smarter about this in the
|
|
|
- * future.
|
|
|
- */
|
|
|
- num_bytes = btrfs_calc_trans_metadata_size(root, 2);
|
|
|
-
|
|
|
- /* We already have enough bytes, just return */
|
|
|
- if (rsv->reserved >= num_bytes)
|
|
|
- return 0;
|
|
|
-
|
|
|
- num_bytes -= rsv->reserved;
|
|
|
-
|
|
|
- /*
|
|
|
- * You should have reserved enough space before hand to do this, so this
|
|
|
- * should not fail.
|
|
|
- */
|
|
|
- ret = block_rsv_migrate_bytes(trans_rsv, rsv, num_bytes);
|
|
|
- BUG_ON(ret);
|
|
|
-
|
|
|
- return 0;
|
|
|
+ WARN_ON(fs_info->delayed_block_rsv.size > 0);
|
|
|
+ WARN_ON(fs_info->delayed_block_rsv.reserved > 0);
|
|
|
}
|
|
|
|
|
|
void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans,
|
|
@@ -3921,9 +4011,7 @@ void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans,
|
|
|
if (!trans->bytes_reserved)
|
|
|
return;
|
|
|
|
|
|
- BUG_ON(trans->block_rsv != &root->fs_info->trans_block_rsv);
|
|
|
- btrfs_block_rsv_release(root, trans->block_rsv,
|
|
|
- trans->bytes_reserved);
|
|
|
+ btrfs_block_rsv_release(root, trans->block_rsv, trans->bytes_reserved);
|
|
|
trans->bytes_reserved = 0;
|
|
|
}
|
|
|
|
|
@@ -3965,11 +4053,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--;
|
|
|
|
|
@@ -3979,19 +4075,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)
|
|
@@ -4000,9 +4147,13 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
|
|
|
struct btrfs_block_rsv *block_rsv = &root->fs_info->delalloc_block_rsv;
|
|
|
u64 to_reserve = 0;
|
|
|
unsigned nr_extents = 0;
|
|
|
+ int flush = 1;
|
|
|
int ret;
|
|
|
|
|
|
- if (btrfs_transaction_in_commit(root->fs_info))
|
|
|
+ if (btrfs_is_free_space_inode(root, inode))
|
|
|
+ flush = 0;
|
|
|
+
|
|
|
+ if (flush && btrfs_transaction_in_commit(root->fs_info))
|
|
|
schedule_timeout(1);
|
|
|
|
|
|
num_bytes = ALIGN(num_bytes, root->sectorsize);
|
|
@@ -4018,18 +4169,29 @@ 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);
|
|
|
+ ret = reserve_metadata_bytes(root, block_rsv, to_reserve, flush);
|
|
|
if (ret) {
|
|
|
+ u64 to_free = 0;
|
|
|
unsigned 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);
|
|
|
+
|
|
|
/*
|
|
|
- * We don't need the return value since our reservation failed,
|
|
|
- * we just need to clean up our counter.
|
|
|
+ * 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.
|
|
|
*/
|
|
|
- dropped = drop_outstanding_extent(inode);
|
|
|
- WARN_ON(dropped > 1);
|
|
|
+ to_free -= to_reserve;
|
|
|
+ if (to_free)
|
|
|
+ btrfs_block_rsv_release(root, block_rsv, to_free);
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -4038,6 +4200,15 @@ 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;
|
|
@@ -4045,9 +4216,11 @@ void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes)
|
|
|
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);
|
|
|
|
|
@@ -4055,6 +4228,21 @@ void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes)
|
|
|
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;
|
|
@@ -4072,6 +4260,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);
|
|
@@ -4091,12 +4292,12 @@ static int update_block_group(struct btrfs_trans_handle *trans,
|
|
|
|
|
|
/* block accounting for super block */
|
|
|
spin_lock(&info->delalloc_lock);
|
|
|
- old_val = btrfs_super_bytes_used(&info->super_copy);
|
|
|
+ old_val = btrfs_super_bytes_used(info->super_copy);
|
|
|
if (alloc)
|
|
|
old_val += num_bytes;
|
|
|
else
|
|
|
old_val -= num_bytes;
|
|
|
- btrfs_set_super_bytes_used(&info->super_copy, old_val);
|
|
|
+ btrfs_set_super_bytes_used(info->super_copy, old_val);
|
|
|
spin_unlock(&info->delalloc_lock);
|
|
|
|
|
|
while (total) {
|
|
@@ -4124,7 +4325,7 @@ static int update_block_group(struct btrfs_trans_handle *trans,
|
|
|
spin_lock(&cache->space_info->lock);
|
|
|
spin_lock(&cache->lock);
|
|
|
|
|
|
- if (btrfs_super_cache_generation(&info->super_copy) != 0 &&
|
|
|
+ if (btrfs_test_opt(root, SPACE_CACHE) &&
|
|
|
cache->disk_cache_state < BTRFS_DC_CLEAR)
|
|
|
cache->disk_cache_state = BTRFS_DC_CLEAR;
|
|
|
|
|
@@ -4136,7 +4337,6 @@ static int update_block_group(struct btrfs_trans_handle *trans,
|
|
|
btrfs_set_block_group_used(&cache->item, old_val);
|
|
|
cache->reserved -= num_bytes;
|
|
|
cache->space_info->bytes_reserved -= num_bytes;
|
|
|
- cache->space_info->reservation_progress++;
|
|
|
cache->space_info->bytes_used += num_bytes;
|
|
|
cache->space_info->disk_used += num_bytes * factor;
|
|
|
spin_unlock(&cache->lock);
|
|
@@ -4188,7 +4388,6 @@ static int pin_down_extent(struct btrfs_root *root,
|
|
|
if (reserved) {
|
|
|
cache->reserved -= num_bytes;
|
|
|
cache->space_info->bytes_reserved -= num_bytes;
|
|
|
- cache->space_info->reservation_progress++;
|
|
|
}
|
|
|
spin_unlock(&cache->lock);
|
|
|
spin_unlock(&cache->space_info->lock);
|
|
@@ -4216,45 +4415,82 @@ int btrfs_pin_extent(struct btrfs_root *root,
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * update size of reserved extents. this function may return -EAGAIN
|
|
|
- * if 'reserve' is true or 'sinfo' is false.
|
|
|
+ * this function must be called within transaction
|
|
|
+ */
|
|
|
+int btrfs_pin_extent_for_log_replay(struct btrfs_trans_handle *trans,
|
|
|
+ struct btrfs_root *root,
|
|
|
+ u64 bytenr, u64 num_bytes)
|
|
|
+{
|
|
|
+ struct btrfs_block_group_cache *cache;
|
|
|
+
|
|
|
+ cache = btrfs_lookup_block_group(root->fs_info, bytenr);
|
|
|
+ BUG_ON(!cache);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * pull in the free space cache (if any) so that our pin
|
|
|
+ * removes the free space from the cache. We have load_only set
|
|
|
+ * to one because the slow code to read in the free extents does check
|
|
|
+ * the pinned extents.
|
|
|
+ */
|
|
|
+ cache_block_group(cache, trans, root, 1);
|
|
|
+
|
|
|
+ pin_down_extent(root, cache, bytenr, num_bytes, 0);
|
|
|
+
|
|
|
+ /* remove us from the free space cache (if we're there at all) */
|
|
|
+ btrfs_remove_free_space(cache, bytenr, num_bytes);
|
|
|
+ btrfs_put_block_group(cache);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * btrfs_update_reserved_bytes - update the block_group and space info counters
|
|
|
+ * @cache: The cache we are manipulating
|
|
|
+ * @num_bytes: The number of bytes in question
|
|
|
+ * @reserve: One of the reservation enums
|
|
|
+ *
|
|
|
+ * This is called by the allocator when it reserves space, or by somebody who is
|
|
|
+ * freeing space that was never actually used on disk. For example if you
|
|
|
+ * reserve some space for a new leaf in transaction A and before transaction A
|
|
|
+ * commits you free that leaf, you call this with reserve set to 0 in order to
|
|
|
+ * clear the reservation.
|
|
|
+ *
|
|
|
+ * Metadata reservations should be called with RESERVE_ALLOC so we do the proper
|
|
|
+ * ENOSPC accounting. For data we handle the reservation through clearing the
|
|
|
+ * delalloc bits in the io_tree. We have to do this since we could end up
|
|
|
+ * allocating less disk space for the amount of data we have reserved in the
|
|
|
+ * case of compression.
|
|
|
+ *
|
|
|
+ * If this is a reservation and the block group has become read only we cannot
|
|
|
+ * make the reservation and return -EAGAIN, otherwise this function always
|
|
|
+ * succeeds.
|
|
|
*/
|
|
|
-int btrfs_update_reserved_bytes(struct btrfs_block_group_cache *cache,
|
|
|
- u64 num_bytes, int reserve, int sinfo)
|
|
|
+static int btrfs_update_reserved_bytes(struct btrfs_block_group_cache *cache,
|
|
|
+ u64 num_bytes, int reserve)
|
|
|
{
|
|
|
+ struct btrfs_space_info *space_info = cache->space_info;
|
|
|
int ret = 0;
|
|
|
- if (sinfo) {
|
|
|
- struct btrfs_space_info *space_info = cache->space_info;
|
|
|
- spin_lock(&space_info->lock);
|
|
|
- spin_lock(&cache->lock);
|
|
|
- if (reserve) {
|
|
|
- if (cache->ro) {
|
|
|
- ret = -EAGAIN;
|
|
|
- } else {
|
|
|
- cache->reserved += num_bytes;
|
|
|
- space_info->bytes_reserved += num_bytes;
|
|
|
- }
|
|
|
- } else {
|
|
|
- if (cache->ro)
|
|
|
- space_info->bytes_readonly += num_bytes;
|
|
|
- cache->reserved -= num_bytes;
|
|
|
- space_info->bytes_reserved -= num_bytes;
|
|
|
- space_info->reservation_progress++;
|
|
|
- }
|
|
|
- spin_unlock(&cache->lock);
|
|
|
- spin_unlock(&space_info->lock);
|
|
|
- } else {
|
|
|
- spin_lock(&cache->lock);
|
|
|
+ spin_lock(&space_info->lock);
|
|
|
+ spin_lock(&cache->lock);
|
|
|
+ if (reserve != RESERVE_FREE) {
|
|
|
if (cache->ro) {
|
|
|
ret = -EAGAIN;
|
|
|
} else {
|
|
|
- if (reserve)
|
|
|
- cache->reserved += num_bytes;
|
|
|
- else
|
|
|
- cache->reserved -= num_bytes;
|
|
|
+ cache->reserved += num_bytes;
|
|
|
+ space_info->bytes_reserved += num_bytes;
|
|
|
+ if (reserve == RESERVE_ALLOC) {
|
|
|
+ BUG_ON(space_info->bytes_may_use < num_bytes);
|
|
|
+ space_info->bytes_may_use -= num_bytes;
|
|
|
+ }
|
|
|
}
|
|
|
- spin_unlock(&cache->lock);
|
|
|
+ } else {
|
|
|
+ if (cache->ro)
|
|
|
+ space_info->bytes_readonly += num_bytes;
|
|
|
+ cache->reserved -= num_bytes;
|
|
|
+ space_info->bytes_reserved -= num_bytes;
|
|
|
+ space_info->reservation_progress++;
|
|
|
}
|
|
|
+ spin_unlock(&cache->lock);
|
|
|
+ spin_unlock(&space_info->lock);
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -4320,13 +4556,8 @@ static int unpin_extent_range(struct btrfs_root *root, u64 start, u64 end)
|
|
|
spin_lock(&cache->lock);
|
|
|
cache->pinned -= len;
|
|
|
cache->space_info->bytes_pinned -= len;
|
|
|
- if (cache->ro) {
|
|
|
+ if (cache->ro)
|
|
|
cache->space_info->bytes_readonly += len;
|
|
|
- } else if (cache->reserved_pinned > 0) {
|
|
|
- len = min(len, cache->reserved_pinned);
|
|
|
- cache->reserved_pinned -= len;
|
|
|
- cache->space_info->bytes_reserved += len;
|
|
|
- }
|
|
|
spin_unlock(&cache->lock);
|
|
|
spin_unlock(&cache->space_info->lock);
|
|
|
}
|
|
@@ -4341,11 +4572,8 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
|
|
|
{
|
|
|
struct btrfs_fs_info *fs_info = root->fs_info;
|
|
|
struct extent_io_tree *unpin;
|
|
|
- struct btrfs_block_rsv *block_rsv;
|
|
|
- struct btrfs_block_rsv *next_rsv;
|
|
|
u64 start;
|
|
|
u64 end;
|
|
|
- int idx;
|
|
|
int ret;
|
|
|
|
|
|
if (fs_info->pinned_extents == &fs_info->freed_extents[0])
|
|
@@ -4368,30 +4596,6 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
|
|
|
cond_resched();
|
|
|
}
|
|
|
|
|
|
- mutex_lock(&fs_info->durable_block_rsv_mutex);
|
|
|
- list_for_each_entry_safe(block_rsv, next_rsv,
|
|
|
- &fs_info->durable_block_rsv_list, list) {
|
|
|
-
|
|
|
- idx = trans->transid & 0x1;
|
|
|
- if (block_rsv->freed[idx] > 0) {
|
|
|
- block_rsv_add_bytes(block_rsv,
|
|
|
- block_rsv->freed[idx], 0);
|
|
|
- block_rsv->freed[idx] = 0;
|
|
|
- }
|
|
|
- if (atomic_read(&block_rsv->usage) == 0) {
|
|
|
- btrfs_block_rsv_release(root, block_rsv, (u64)-1);
|
|
|
-
|
|
|
- if (block_rsv->freed[0] == 0 &&
|
|
|
- block_rsv->freed[1] == 0) {
|
|
|
- list_del_init(&block_rsv->list);
|
|
|
- kfree(block_rsv);
|
|
|
- }
|
|
|
- } else {
|
|
|
- btrfs_block_rsv_release(root, block_rsv, 0);
|
|
|
- }
|
|
|
- }
|
|
|
- mutex_unlock(&fs_info->durable_block_rsv_mutex);
|
|
|
-
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -4669,7 +4873,6 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
|
|
|
struct extent_buffer *buf,
|
|
|
u64 parent, int last_ref)
|
|
|
{
|
|
|
- struct btrfs_block_rsv *block_rsv;
|
|
|
struct btrfs_block_group_cache *cache = NULL;
|
|
|
int ret;
|
|
|
|
|
@@ -4684,64 +4887,24 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
|
|
|
if (!last_ref)
|
|
|
return;
|
|
|
|
|
|
- block_rsv = get_block_rsv(trans, root);
|
|
|
cache = btrfs_lookup_block_group(root->fs_info, buf->start);
|
|
|
- if (block_rsv->space_info != cache->space_info)
|
|
|
- goto out;
|
|
|
|
|
|
if (btrfs_header_generation(buf) == trans->transid) {
|
|
|
if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) {
|
|
|
ret = check_ref_cleanup(trans, root, buf->start);
|
|
|
if (!ret)
|
|
|
- goto pin;
|
|
|
+ goto out;
|
|
|
}
|
|
|
|
|
|
if (btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN)) {
|
|
|
pin_down_extent(root, cache, buf->start, buf->len, 1);
|
|
|
- goto pin;
|
|
|
+ goto out;
|
|
|
}
|
|
|
|
|
|
WARN_ON(test_bit(EXTENT_BUFFER_DIRTY, &buf->bflags));
|
|
|
|
|
|
btrfs_add_free_space(cache, buf->start, buf->len);
|
|
|
- ret = btrfs_update_reserved_bytes(cache, buf->len, 0, 0);
|
|
|
- if (ret == -EAGAIN) {
|
|
|
- /* block group became read-only */
|
|
|
- btrfs_update_reserved_bytes(cache, buf->len, 0, 1);
|
|
|
- goto out;
|
|
|
- }
|
|
|
-
|
|
|
- ret = 1;
|
|
|
- spin_lock(&block_rsv->lock);
|
|
|
- if (block_rsv->reserved < block_rsv->size) {
|
|
|
- block_rsv->reserved += buf->len;
|
|
|
- ret = 0;
|
|
|
- }
|
|
|
- spin_unlock(&block_rsv->lock);
|
|
|
-
|
|
|
- if (ret) {
|
|
|
- spin_lock(&cache->space_info->lock);
|
|
|
- cache->space_info->bytes_reserved -= buf->len;
|
|
|
- cache->space_info->reservation_progress++;
|
|
|
- spin_unlock(&cache->space_info->lock);
|
|
|
- }
|
|
|
- goto out;
|
|
|
- }
|
|
|
-pin:
|
|
|
- if (block_rsv->durable && !cache->ro) {
|
|
|
- ret = 0;
|
|
|
- spin_lock(&cache->lock);
|
|
|
- if (!cache->ro) {
|
|
|
- cache->reserved_pinned += buf->len;
|
|
|
- ret = 1;
|
|
|
- }
|
|
|
- spin_unlock(&cache->lock);
|
|
|
-
|
|
|
- if (ret) {
|
|
|
- spin_lock(&block_rsv->lock);
|
|
|
- block_rsv->freed[trans->transid & 0x1] += buf->len;
|
|
|
- spin_unlock(&block_rsv->lock);
|
|
|
- }
|
|
|
+ btrfs_update_reserved_bytes(cache, buf->len, RESERVE_FREE);
|
|
|
}
|
|
|
out:
|
|
|
/*
|
|
@@ -4884,10 +5047,13 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans,
|
|
|
int last_ptr_loop = 0;
|
|
|
int loop = 0;
|
|
|
int index = 0;
|
|
|
+ int alloc_type = (data & BTRFS_BLOCK_GROUP_DATA) ?
|
|
|
+ RESERVE_ALLOC_NO_ACCOUNT : RESERVE_ALLOC;
|
|
|
bool found_uncached_bg = false;
|
|
|
bool failed_cluster_refill = false;
|
|
|
bool failed_alloc = false;
|
|
|
bool use_cluster = true;
|
|
|
+ bool have_caching_bg = false;
|
|
|
u64 ideal_cache_percent = 0;
|
|
|
u64 ideal_cache_offset = 0;
|
|
|
|
|
@@ -4970,6 +5136,7 @@ ideal_cache:
|
|
|
}
|
|
|
}
|
|
|
search:
|
|
|
+ have_caching_bg = false;
|
|
|
down_read(&space_info->groups_sem);
|
|
|
list_for_each_entry(block_group, &space_info->block_groups[index],
|
|
|
list) {
|
|
@@ -5178,6 +5345,8 @@ refill_cluster:
|
|
|
failed_alloc = true;
|
|
|
goto have_block_group;
|
|
|
} else if (!offset) {
|
|
|
+ if (!cached)
|
|
|
+ have_caching_bg = true;
|
|
|
goto loop;
|
|
|
}
|
|
|
checks:
|
|
@@ -5203,8 +5372,8 @@ checks:
|
|
|
search_start - offset);
|
|
|
BUG_ON(offset > search_start);
|
|
|
|
|
|
- ret = btrfs_update_reserved_bytes(block_group, num_bytes, 1,
|
|
|
- (data & BTRFS_BLOCK_GROUP_DATA));
|
|
|
+ ret = btrfs_update_reserved_bytes(block_group, num_bytes,
|
|
|
+ alloc_type);
|
|
|
if (ret == -EAGAIN) {
|
|
|
btrfs_add_free_space(block_group, offset, num_bytes);
|
|
|
goto loop;
|
|
@@ -5228,6 +5397,9 @@ loop:
|
|
|
}
|
|
|
up_read(&space_info->groups_sem);
|
|
|
|
|
|
+ if (!ins->objectid && loop >= LOOP_CACHING_WAIT && have_caching_bg)
|
|
|
+ goto search;
|
|
|
+
|
|
|
if (!ins->objectid && ++index < BTRFS_NR_RAID_TYPES)
|
|
|
goto search;
|
|
|
|
|
@@ -5326,7 +5498,8 @@ static void dump_space_info(struct btrfs_space_info *info, u64 bytes,
|
|
|
int index = 0;
|
|
|
|
|
|
spin_lock(&info->lock);
|
|
|
- printk(KERN_INFO "space_info has %llu free, is %sfull\n",
|
|
|
+ printk(KERN_INFO "space_info %llu has %llu free, is %sfull\n",
|
|
|
+ (unsigned long long)info->flags,
|
|
|
(unsigned long long)(info->total_bytes - info->bytes_used -
|
|
|
info->bytes_pinned - info->bytes_reserved -
|
|
|
info->bytes_readonly),
|
|
@@ -5412,7 +5585,8 @@ again:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-int btrfs_free_reserved_extent(struct btrfs_root *root, u64 start, u64 len)
|
|
|
+static int __btrfs_free_reserved_extent(struct btrfs_root *root,
|
|
|
+ u64 start, u64 len, int pin)
|
|
|
{
|
|
|
struct btrfs_block_group_cache *cache;
|
|
|
int ret = 0;
|
|
@@ -5427,8 +5601,12 @@ int btrfs_free_reserved_extent(struct btrfs_root *root, u64 start, u64 len)
|
|
|
if (btrfs_test_opt(root, DISCARD))
|
|
|
ret = btrfs_discard_extent(root, start, len, NULL);
|
|
|
|
|
|
- btrfs_add_free_space(cache, start, len);
|
|
|
- btrfs_update_reserved_bytes(cache, len, 0, 1);
|
|
|
+ if (pin)
|
|
|
+ pin_down_extent(root, cache, start, len, 1);
|
|
|
+ else {
|
|
|
+ btrfs_add_free_space(cache, start, len);
|
|
|
+ btrfs_update_reserved_bytes(cache, len, RESERVE_FREE);
|
|
|
+ }
|
|
|
btrfs_put_block_group(cache);
|
|
|
|
|
|
trace_btrfs_reserved_extent_free(root, start, len);
|
|
@@ -5436,6 +5614,18 @@ int btrfs_free_reserved_extent(struct btrfs_root *root, u64 start, u64 len)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+int btrfs_free_reserved_extent(struct btrfs_root *root,
|
|
|
+ u64 start, u64 len)
|
|
|
+{
|
|
|
+ return __btrfs_free_reserved_extent(root, start, len, 0);
|
|
|
+}
|
|
|
+
|
|
|
+int btrfs_free_and_pin_reserved_extent(struct btrfs_root *root,
|
|
|
+ u64 start, u64 len)
|
|
|
+{
|
|
|
+ return __btrfs_free_reserved_extent(root, start, len, 1);
|
|
|
+}
|
|
|
+
|
|
|
static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans,
|
|
|
struct btrfs_root *root,
|
|
|
u64 parent, u64 root_objectid,
|
|
@@ -5631,7 +5821,8 @@ int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans,
|
|
|
put_caching_control(caching_ctl);
|
|
|
}
|
|
|
|
|
|
- ret = btrfs_update_reserved_bytes(block_group, ins->offset, 1, 1);
|
|
|
+ ret = btrfs_update_reserved_bytes(block_group, ins->offset,
|
|
|
+ RESERVE_ALLOC_NO_ACCOUNT);
|
|
|
BUG_ON(ret);
|
|
|
btrfs_put_block_group(block_group);
|
|
|
ret = alloc_reserved_file_extent(trans, root, 0, root_objectid,
|
|
@@ -5688,8 +5879,7 @@ use_block_rsv(struct btrfs_trans_handle *trans,
|
|
|
block_rsv = get_block_rsv(trans, root);
|
|
|
|
|
|
if (block_rsv->size == 0) {
|
|
|
- ret = reserve_metadata_bytes(trans, root, block_rsv,
|
|
|
- blocksize, 0);
|
|
|
+ ret = reserve_metadata_bytes(root, block_rsv, blocksize, 0);
|
|
|
/*
|
|
|
* If we couldn't reserve metadata bytes try and use some from
|
|
|
* the global reserve.
|
|
@@ -5709,13 +5899,15 @@ use_block_rsv(struct btrfs_trans_handle *trans,
|
|
|
if (!ret)
|
|
|
return block_rsv;
|
|
|
if (ret) {
|
|
|
- WARN_ON(1);
|
|
|
- ret = reserve_metadata_bytes(trans, root, block_rsv, blocksize,
|
|
|
- 0);
|
|
|
+ static DEFINE_RATELIMIT_STATE(_rs,
|
|
|
+ DEFAULT_RATELIMIT_INTERVAL,
|
|
|
+ /*DEFAULT_RATELIMIT_BURST*/ 2);
|
|
|
+ if (__ratelimit(&_rs)) {
|
|
|
+ printk(KERN_DEBUG "btrfs: block rsv returned %d\n", ret);
|
|
|
+ WARN_ON(1);
|
|
|
+ }
|
|
|
+ ret = reserve_metadata_bytes(root, block_rsv, blocksize, 0);
|
|
|
if (!ret) {
|
|
|
- spin_lock(&block_rsv->lock);
|
|
|
- block_rsv->size += blocksize;
|
|
|
- spin_unlock(&block_rsv->lock);
|
|
|
return block_rsv;
|
|
|
} else if (ret && block_rsv != global_rsv) {
|
|
|
ret = block_rsv_use_bytes(global_rsv, blocksize);
|
|
@@ -6593,12 +6785,9 @@ static int set_block_group_ro(struct btrfs_block_group_cache *cache, int force)
|
|
|
cache->bytes_super - btrfs_block_group_used(&cache->item);
|
|
|
|
|
|
if (sinfo->bytes_used + sinfo->bytes_reserved + sinfo->bytes_pinned +
|
|
|
- sinfo->bytes_may_use + sinfo->bytes_readonly +
|
|
|
- cache->reserved_pinned + num_bytes + min_allocable_bytes <=
|
|
|
- sinfo->total_bytes) {
|
|
|
+ sinfo->bytes_may_use + sinfo->bytes_readonly + num_bytes +
|
|
|
+ min_allocable_bytes <= sinfo->total_bytes) {
|
|
|
sinfo->bytes_readonly += num_bytes;
|
|
|
- sinfo->bytes_reserved += cache->reserved_pinned;
|
|
|
- cache->reserved_pinned = 0;
|
|
|
cache->ro = 1;
|
|
|
ret = 0;
|
|
|
}
|
|
@@ -6965,7 +7154,8 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
|
|
|
struct btrfs_space_info,
|
|
|
list);
|
|
|
if (space_info->bytes_pinned > 0 ||
|
|
|
- space_info->bytes_reserved > 0) {
|
|
|
+ space_info->bytes_reserved > 0 ||
|
|
|
+ space_info->bytes_may_use > 0) {
|
|
|
WARN_ON(1);
|
|
|
dump_space_info(space_info, 0, 0);
|
|
|
}
|
|
@@ -7007,14 +7197,12 @@ int btrfs_read_block_groups(struct btrfs_root *root)
|
|
|
return -ENOMEM;
|
|
|
path->reada = 1;
|
|
|
|
|
|
- cache_gen = btrfs_super_cache_generation(&root->fs_info->super_copy);
|
|
|
- if (cache_gen != 0 &&
|
|
|
- btrfs_super_generation(&root->fs_info->super_copy) != cache_gen)
|
|
|
+ cache_gen = btrfs_super_cache_generation(root->fs_info->super_copy);
|
|
|
+ if (btrfs_test_opt(root, SPACE_CACHE) &&
|
|
|
+ btrfs_super_generation(root->fs_info->super_copy) != cache_gen)
|
|
|
need_clear = 1;
|
|
|
if (btrfs_test_opt(root, CLEAR_CACHE))
|
|
|
need_clear = 1;
|
|
|
- if (!btrfs_test_opt(root, SPACE_CACHE) && cache_gen)
|
|
|
- printk(KERN_INFO "btrfs: disk space caching is enabled\n");
|
|
|
|
|
|
while (1) {
|
|
|
ret = find_first_block_group(root, path, &key);
|
|
@@ -7253,7 +7441,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- inode = lookup_free_space_inode(root, block_group, path);
|
|
|
+ inode = lookup_free_space_inode(tree_root, block_group, path);
|
|
|
if (!IS_ERR(inode)) {
|
|
|
ret = btrfs_orphan_add(trans, inode);
|
|
|
BUG_ON(ret);
|
|
@@ -7269,7 +7457,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
|
|
|
spin_unlock(&block_group->lock);
|
|
|
}
|
|
|
/* One for our lookup ref */
|
|
|
- iput(inode);
|
|
|
+ btrfs_add_delayed_iput(inode);
|
|
|
}
|
|
|
|
|
|
key.objectid = BTRFS_FREE_SPACE_OBJECTID;
|
|
@@ -7340,7 +7528,7 @@ int btrfs_init_space_info(struct btrfs_fs_info *fs_info)
|
|
|
int mixed = 0;
|
|
|
int ret;
|
|
|
|
|
|
- disk_super = &fs_info->super_copy;
|
|
|
+ disk_super = fs_info->super_copy;
|
|
|
if (!btrfs_super_root(disk_super))
|
|
|
return 1;
|
|
|
|