From patchwork Wed Oct 6 19:56:12 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Josef Bacik X-Patchwork-Id: 236901 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id o96K1j9c011850 for ; Wed, 6 Oct 2010 20:01:45 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1759525Ab0JFUBl (ORCPT ); Wed, 6 Oct 2010 16:01:41 -0400 Received: from mx1.redhat.com ([209.132.183.28]:59729 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1759452Ab0JFUBl (ORCPT ); Wed, 6 Oct 2010 16:01:41 -0400 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id o96K1fJa018923 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Wed, 6 Oct 2010 16:01:41 -0400 Received: from localhost.localdomain (test1244.test.redhat.com [10.10.10.244]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id o96K1dMx006357 for ; Wed, 6 Oct 2010 16:01:40 -0400 From: Josef Bacik To: linux-btrfs@vger.kernel.org Subject: [PATCH] Btrfs: fix some ENOSPC problems Date: Wed, 6 Oct 2010 15:56:12 -0400 Message-Id: <1286394972-26428-1-git-send-email-josef@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Wed, 06 Oct 2010 20:01:56 +0000 (UTC) diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 5343e56..439e290 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -3433,35 +3433,46 @@ static int should_retry_reserve(struct btrfs_trans_handle *trans, return 1; } +/* + * 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. + * + * However if we don't intend to retry this reservation, pass -1 as retries so + * that it short circuits this logic. + */ static int reserve_metadata_bytes(struct btrfs_block_rsv *block_rsv, - u64 num_bytes) + u64 num_bytes, int retries) { struct btrfs_space_info *space_info = block_rsv->space_info; u64 unused; int ret = -ENOSPC; + if (retries > 0) + num_bytes = 0; + spin_lock(&space_info->lock); unused = space_info->bytes_used + space_info->bytes_reserved + - space_info->bytes_pinned + space_info->bytes_readonly; + space_info->bytes_pinned + space_info->bytes_readonly + + space_info->bytes_may_use; - if (unused < space_info->total_bytes) + if (unused <= space_info->total_bytes) unused = space_info->total_bytes - unused; else - unused = 0; + unused = -1; if (unused >= num_bytes) { - if (block_rsv->priority >= 10) { + if (retries <= 0) space_info->bytes_reserved += num_bytes; - ret = 0; - } else { - if ((unused + block_rsv->reserved) * - block_rsv->priority >= - (num_bytes + block_rsv->reserved) * 10) { - space_info->bytes_reserved += num_bytes; - ret = 0; - } - } + ret = 0; + } else if (retries == 0) { + space_info->bytes_reserved += num_bytes; + ret = -EAGAIN; } + spin_unlock(&space_info->lock); return ret; @@ -3613,7 +3624,7 @@ int btrfs_block_rsv_add(struct btrfs_trans_handle *trans, if (num_bytes == 0) return 0; again: - ret = reserve_metadata_bytes(block_rsv, num_bytes); + ret = reserve_metadata_bytes(block_rsv, num_bytes, *retries); if (!ret) { block_rsv_add_bytes(block_rsv, num_bytes, 1); return 0; @@ -3623,6 +3634,10 @@ again: if (ret > 0) goto again; + spin_lock(&block_rsv->space_info->lock); + block_rsv->space_info->bytes_reserved -= num_bytes; + spin_unlock(&block_rsv->space_info->lock); + return ret; } @@ -3657,7 +3672,7 @@ int btrfs_block_rsv_check(struct btrfs_trans_handle *trans, return 0; if (block_rsv->refill_used) { - ret = reserve_metadata_bytes(block_rsv, num_bytes); + ret = reserve_metadata_bytes(block_rsv, num_bytes, -1); if (!ret) { block_rsv_add_bytes(block_rsv, num_bytes, 0); return 0; @@ -3736,6 +3751,8 @@ static u64 calc_global_metadata_size(struct btrfs_fs_info *fs_info) sinfo = __find_space_info(fs_info, BTRFS_BLOCK_GROUP_METADATA); spin_lock(&sinfo->lock); + if (sinfo->flags & BTRFS_BLOCK_GROUP_DATA) + data_used = 0; meta_used = sinfo->bytes_used; spin_unlock(&sinfo->lock); @@ -3763,7 +3780,8 @@ static void update_global_block_rsv(struct btrfs_fs_info *fs_info) block_rsv->size = num_bytes; num_bytes = sinfo->bytes_used + sinfo->bytes_pinned + - sinfo->bytes_reserved + sinfo->bytes_readonly; + sinfo->bytes_reserved + sinfo->bytes_readonly + + sinfo->bytes_may_use; if (sinfo->total_bytes > num_bytes) { num_bytes = sinfo->total_bytes - num_bytes; @@ -3937,13 +3955,16 @@ again: } to_reserve += calc_csum_metadata_size(inode, num_bytes); - ret = reserve_metadata_bytes(block_rsv, to_reserve); + ret = reserve_metadata_bytes(block_rsv, to_reserve, retries); if (ret) { spin_unlock(&BTRFS_I(inode)->accounting_lock); ret = should_retry_reserve(NULL, root, block_rsv, to_reserve, &retries); if (ret > 0) goto again; + spin_lock(&block_rsv->space_info->lock); + block_rsv->space_info->bytes_reserved -= to_reserve; + spin_unlock(&block_rsv->space_info->lock); return ret; } @@ -5575,7 +5596,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(block_rsv, blocksize); + ret = reserve_metadata_bytes(block_rsv, blocksize, -1); if (ret) return ERR_PTR(ret); return block_rsv;