From patchwork Sat Jan 3 15:30:51 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lutz Euler X-Patchwork-Id: 5561961 Return-Path: X-Original-To: patchwork-linux-btrfs@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id C9D86BF6C3 for ; Sat, 3 Jan 2015 15:48:15 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id CA158201CD for ; Sat, 3 Jan 2015 15:48:14 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 80241201EC for ; Sat, 3 Jan 2015 15:48:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751053AbbACPr7 (ORCPT ); Sat, 3 Jan 2015 10:47:59 -0500 Received: from mout0.freenet.de ([195.4.92.90]:35495 "EHLO mout0.freenet.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751017AbbACPr6 (ORCPT ); Sat, 3 Jan 2015 10:47:58 -0500 X-Greylist: delayed 780 seconds by postgrey-1.27 at vger.kernel.org; Sat, 03 Jan 2015 10:47:58 EST Received: from [195.4.92.142] (helo=mjail2.freenet.de) by mout0.freenet.de with esmtpa (ID lutz.euler@freenet.de) (port 25) (Exim 4.82 #2) id 1Y7QjA-0001Ph-IJ for linux-btrfs@vger.kernel.org; Sat, 03 Jan 2015 16:34:56 +0100 Received: from localhost ([::1]:52208 helo=mjail2.freenet.de) by mjail2.freenet.de with esmtpa (ID lutz.euler@freenet.de) (Exim 4.82 #2) id 1Y7QjA-0008Hk-D0 for linux-btrfs@vger.kernel.org; Sat, 03 Jan 2015 16:34:56 +0100 Received: from mx0.freenet.de ([195.4.92.10]:38696) by mjail2.freenet.de with esmtpa (ID lutz.euler@freenet.de) (Exim 4.82 #2) id 1Y7QfE-0006id-NV for linux-btrfs@vger.kernel.org; Sat, 03 Jan 2015 16:30:52 +0100 Received: from p548f9fdd.dip0.t-ipconnect.de ([84.143.159.221]:48322 helo=lutz) by mx0.freenet.de with esmtpsa (ID lutz.euler@freenet.de) (TLSv1:AES256-SHA:256) (port 587) (Exim 4.82 #2) id 1Y7QfE-0005WW-K6 for linux-btrfs@vger.kernel.org; Sat, 03 Jan 2015 16:30:52 +0100 Received: from lutz by lutz with local (Exim 4.74) (envelope-from ) id 1Y7QfD-0001lu-Fx for linux-btrfs@vger.kernel.org; Sat, 03 Jan 2015 16:30:51 +0100 MIME-Version: 1.0 Message-ID: <21672.2859.468940.450115@localhost.localdomain> Date: Sat, 3 Jan 2015 16:30:51 +0100 From: lutz.euler@freenet.de (Lutz Euler) To: linux-btrfs@vger.kernel.org Subject: [PATCH V2] Btrfs: really fix trim 0 bytes after a device delete In-Reply-To: <20644.2675.653732.24816@localhost.localdomain> References: <20644.2272.57892.435731@localhost.localdomain> <20644.2675.653732.24816@localhost.localdomain> X-Mailer: VM 8.0.9 under XEmacs 21.5.21 (x86_64-unknown-linux) X-Originated-At: 84.143.159.221!48322 Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00,FREEMAIL_FROM, RCVD_IN_DNSWL_HI,T_RP_MATCHES_RCVD,UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Commit 2cac13e41bf5b99ffc426bd28dfd2248df1dfa67, "fix trim 0 bytes after a device delete", said: A user reported a bug of btrfs's trim, that is we will trim 0 bytes after a device delete. The commit didn't attack the root of the problem so did not fix the bug except for a special case. For block discard, btrfs_trim_fs directly compares the range passed in against the filesystem's objectids. The former is bounded by the sum of the sizes of the devices of the filesystem, the latter is a completely unrelated set of intervals of 64-bit integers. The bug reported occurred as the smallest objectid was larger than the sum of the device sizes. The above mentioned commit only fixed the case where the smallest objectid is nonzero and the largest objectid less than the sum of the device sizes, but it still trims too little if the largest objectid is larger than that, and nothing in the reported situation. The current mapping between the given range and the objectids is thus clearly broken, so, to fix the bug and as a first step towards a complete solution, simply ignore the range parameter's start and length fields and always trim the whole filesystem. (While this makes it impossible to trim a filesystem only partly, due to the broken mapping this often didn't work anyway.) V2: - Rebased onto 3.9. (still applies to and works with 3.19-rc2) - Take range->minlen into account. Reported-by: Lutz Euler Signed-off-by: Lutz Euler --- fs/btrfs/extent-tree.c | 25 +++++++++++-------------- 1 files changed, 11 insertions(+), 14 deletions(-) diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index cfb3cf7..81006c1 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -8824,26 +8824,23 @@ int btrfs_trim_fs(struct btrfs_root *root, struct fstrim_range *range) u64 start; u64 end; u64 trimmed = 0; - u64 total_bytes = btrfs_super_total_bytes(fs_info->super_copy); int ret = 0; /* - * try to trim all FS space, our block group may start from non-zero. + * The range passed in is a subinterval of the interval from 0 + * to the sum of the sizes of the devices of the filesystem. + * The objectid's used in the filesystem can span any set of + * subintervals of the interval from 0 to (u64)-1. As there is + * neither a simple nor an agreed upon mapping between these + * two ranges we ignore the range parameter's start and len + * fields and always trim the whole filesystem (that is, only + * the free space in allocated chunks). */ - if (range->len == total_bytes) - cache = btrfs_lookup_first_block_group(fs_info, range->start); - else - cache = btrfs_lookup_block_group(fs_info, range->start); + cache = btrfs_lookup_first_block_group(fs_info, 0); while (cache) { - if (cache->key.objectid >= (range->start + range->len)) { - btrfs_put_block_group(cache); - break; - } - - start = max(range->start, cache->key.objectid); - end = min(range->start + range->len, - cache->key.objectid + cache->key.offset); + start = cache->key.objectid; + end = cache->key.objectid + cache->key.offset; if (end - start >= range->minlen) { if (!block_group_cache_done(cache)) {