From patchwork Mon May 9 16:41:47 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Amir G." X-Patchwork-Id: 94819 X-Patchwork-Delegate: tytso@mit.edu Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 762B8B6EDF for ; Tue, 10 May 2011 02:44:45 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753797Ab1EIQog (ORCPT ); Mon, 9 May 2011 12:44:36 -0400 Received: from mail-wy0-f174.google.com ([74.125.82.174]:33538 "EHLO mail-wy0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753803Ab1EIQof (ORCPT ); Mon, 9 May 2011 12:44:35 -0400 Received: by mail-wy0-f174.google.com with SMTP id 21so4026020wya.19 for ; Mon, 09 May 2011 09:44:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:sender:from:to:cc:subject:date:message-id :x-mailer:in-reply-to:references; bh=7wK0/j2rfTvyLgcZoONg2tnQzF7B1cNJcdw05/MEWcg=; b=v+/f56bsjlIDYSEWUzTCbYynAXmmOxuESG4yzdLfscpa6MEuaSEXMfK2ynt/iLl4Aq MAp8y7aXrQEPQ8dl3m0zoaHMnfNDW1ZwG+a9CydwuIl0S0+Igw7Ga4HN4aq3zrCqNQ5H GlF5zY6PNdfzwPUjlbcK76wANe8EPp8d/YBYo= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=sender:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references; b=aFIgyboM4scLGXatyJC4nDJu8d2rq614A5s23c+iNMHl5Axui6KvlCBEmidlfojByu v3mgbLBueFB9SJ61UPEfiGWejBIGQQgppH4jE64/ZZXhgsRXjyheOX92rpcz0H8bpPd+ deHPlwt8T6T2PlA6+3bkhgrRBFMJe0qzyZQYA= Received: by 10.227.60.206 with SMTP id q14mr7472288wbh.111.1304959474379; Mon, 09 May 2011 09:44:34 -0700 (PDT) Received: from localhost.localdomain (bzq-79-179-43-50.red.bezeqint.net [79.179.43.50]) by mx.google.com with ESMTPS id o23sm2034877wbc.27.2011.05.09.09.44.32 (version=TLSv1/SSLv3 cipher=OTHER); Mon, 09 May 2011 09:44:33 -0700 (PDT) From: amir73il@users.sourceforge.net To: linux-ext4@vger.kernel.org Cc: tytso@mit.edu, Amir Goldstein , Yongqiang Yang Subject: [PATCH RFC 29/30] ext4: snapshot cleanup - shrink deleted snapshots Date: Mon, 9 May 2011 19:41:47 +0300 Message-Id: <1304959308-11122-30-git-send-email-amir73il@users.sourceforge.net> X-Mailer: git-send-email 1.7.0.4 In-Reply-To: <1304959308-11122-1-git-send-email-amir73il@users.sourceforge.net> References: <1304959308-11122-1-git-send-email-amir73il@users.sourceforge.net> Sender: linux-ext4-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-ext4@vger.kernel.org From: Amir Goldstein Free blocks of deleted snapshots, which are not in use by an older non-deleted snapshot. Shrinking helps reclaiming disk space while older snapshots are currently in use (enabled). We modify the indirect inode truncate helper functions so that they can be used by the snapshot cleanup functions to free blocks selectively according to a COW bitmap buffer. Signed-off-by: Amir Goldstein Signed-off-by: Yongqiang Yang --- fs/ext4/ext4.h | 10 ++++++++++ fs/ext4/inode.c | 51 +++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 47 insertions(+), 14 deletions(-) diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 7650515..07629ce 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -1905,6 +1905,16 @@ extern void ext4_free_branches(handle_t *handle, struct inode *inode, struct buffer_head *parent_bh, __le32 *first, __le32 *last, int depth); +extern void ext4_free_data_cow(handle_t *handle, struct inode *inode, + struct buffer_head *this_bh, + __le32 *first, __le32 *last, + const char *bitmap, int bit, + int *pfreed_blocks); + +#define ext4_free_data(handle, inode, bh, first, last) \ + ext4_free_data_cow(handle, inode, bh, first, last, \ + NULL, 0, NULL) + /* ioctl.c */ extern long ext4_ioctl(struct file *, unsigned int, unsigned long); extern long ext4_compat_ioctl(struct file *, unsigned int, unsigned long); diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index d46da6a..e3bfee2 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -4546,11 +4546,15 @@ no_top: * Return 0 on success, 1 on invalid block range * and < 0 on fatal error. */ -static int ext4_clear_blocks(handle_t *handle, struct inode *inode, - struct buffer_head *bh, - ext4_fsblk_t block_to_free, - unsigned long count, __le32 *first, - __le32 *last) +/* + * ext4_clear_blocks_cow - Zero a number of block pointers (consult COW bitmap) + * @bitmap: COW bitmap to consult when shrinking deleted snapshot + * @bit: bit number representing the @first block + */ +static int ext4_clear_blocks_cow(handle_t *handle, struct inode *inode, + struct buffer_head *bh, ext4_fsblk_t block_to_free, + unsigned long count, __le32 *first, __le32 *last, + const char *bitmap, int bit) { __le32 *p; int flags = EXT4_FREE_BLOCKS_FORGET | EXT4_FREE_BLOCKS_VALIDATED; @@ -4590,8 +4594,12 @@ static int ext4_clear_blocks(handle_t *handle, struct inode *inode, } } - for (p = first; p < last; p++) + for (p = first; p < last; p++) { + if (*p && bitmap && ext4_test_bit(bit + (p - first), bitmap)) + /* don't free block used by older snapshot */ + continue; *p = 0; + } ext4_free_blocks(handle, inode, NULL, block_to_free, count, flags); return 0; @@ -4619,9 +4627,17 @@ out_err: * @this_bh will be %NULL if @first and @last point into the inode's direct * block pointers. */ -static void ext4_free_data(handle_t *handle, struct inode *inode, +/* + * ext4_free_data_cow - free a list of data blocks (consult COW bitmap) + * @bitmap: COW bitmap to consult when shrinking deleted snapshot + * @bit: bit number representing the @first block + * @pfreed_blocks: return number of freed blocks + */ +void ext4_free_data_cow(handle_t *handle, struct inode *inode, struct buffer_head *this_bh, - __le32 *first, __le32 *last) + __le32 *first, __le32 *last, + const char *bitmap, int bit, + int *pfreed_blocks) { ext4_fsblk_t block_to_free = 0; /* Starting block # of a run */ unsigned long count = 0; /* Number of blocks in the run */ @@ -4645,6 +4661,11 @@ static void ext4_free_data(handle_t *handle, struct inode *inode, for (p = first; p < last; p++) { nr = le32_to_cpu(*p); + if (nr && bitmap && ext4_test_bit(bit + (p - first), bitmap)) + /* don't free block used by older snapshot */ + nr = 0; + if (nr && pfreed_blocks) + ++(*pfreed_blocks); if (nr) { /* accumulate blocks to free if they're contiguous */ if (count == 0) { @@ -4654,9 +4675,10 @@ static void ext4_free_data(handle_t *handle, struct inode *inode, } else if (nr == block_to_free + count) { count++; } else { - err = ext4_clear_blocks(handle, inode, this_bh, - block_to_free, count, - block_to_free_p, p); + err = ext4_clear_blocks_cow(handle, inode, + this_bh, block_to_free, count, + block_to_free_p, p, bitmap, + bit + (block_to_free_p - first)); if (err) break; block_to_free = nr; @@ -4666,9 +4688,10 @@ static void ext4_free_data(handle_t *handle, struct inode *inode, } } - if (!err && count > 0) - err = ext4_clear_blocks(handle, inode, this_bh, block_to_free, - count, block_to_free_p, p); + if (count > 0) + err = ext4_clear_blocks_cow(handle, inode, this_bh, + block_to_free, count, block_to_free_p, p, + bitmap, bit + (block_to_free_p - first)); if (err < 0) /* fatal error */ return;