From patchwork Tue Jul 20 15:16:06 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Amir Goldstein X-Patchwork-Id: 59325 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 72EF4B6EEA for ; Wed, 21 Jul 2010 01:17:35 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932326Ab0GTPRd (ORCPT ); Tue, 20 Jul 2010 11:17:33 -0400 Received: from mail-ww0-f44.google.com ([74.125.82.44]:42770 "EHLO mail-ww0-f44.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932328Ab0GTPRc (ORCPT ); Tue, 20 Jul 2010 11:17:32 -0400 Received: by mail-ww0-f44.google.com with SMTP id 40so968910wwj.1 for ; Tue, 20 Jul 2010 08:17:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:from:to:cc:subject:date :message-id:x-mailer:in-reply-to:references; bh=ZdlCXa1uFjdfZuNFPdFlZCS1/Pm0Sb466mzsE6PVVrc=; b=iIcy5F3OaOpY9YnDVN0ZQ8OMd8oK//FacUgIC95IrWcydirYBBfJRDXvDuuBBcAaSy 9yvBRC6hQh/w6PCtH2NnNDZcZGII3XdH9Los4LZ6BqectrDvL3tQYSwZqFAsDE6j0Dvn Uekz2JEQWHPcPLLFq7HoICm8ZEMSyzne7xQpM= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; b=ZRFjjs4kcsDhKTDO1Yw4Tfb0uL+cNt37efl6RKP0fp9RQI/mDb6QjJ3f2CnXv9P8Fg Be4TpIO2xpW/3Mtx0LAAcrA8vI1TOPJDftHDd6ivO7Kte+OSzre04iLa+xmCWeBblJDh jPiT05GHWnb77D+3tt3iM/ZrAMHVTQ/E7OE4o= Received: by 10.227.156.200 with SMTP id y8mr4059013wbw.120.1279639047964; Tue, 20 Jul 2010 08:17:27 -0700 (PDT) Received: from localhost.localdomain (bzq-218-153-66.cablep.bezeqint.net [81.218.153.66]) by mx.google.com with ESMTPS id b18sm47610461wbb.19.2010.07.20.08.17.26 (version=TLSv1/SSLv3 cipher=RC4-MD5); Tue, 20 Jul 2010 08:17:27 -0700 (PDT) From: Amir Goldstein To: tytso@mit.edu, andreas.dilger@oracle.com, jack@suse.cz Cc: linux-ext4@vger.kernel.org, Amir Goldstein Subject: [PATCH 05/12] e2fsprogs: Avoid offline modifications to a file system with snapshots Date: Tue, 20 Jul 2010 18:16:06 +0300 Message-Id: <1279638973-14561-6-git-send-email-amir73il@users.sf.net> X-Mailer: git-send-email 1.6.6 In-Reply-To: <1279638973-14561-1-git-send-email-amir73il@users.sf.net> References: <1279638973-14561-1-git-send-email-amir73il@users.sf.net> Sender: linux-ext4-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-ext4@vger.kernel.org Next3 sets the read-only compatible feature 'has_snapshot', so the file system could be mounted with Ext3 only in read-only mode to protect the snapshots. Fsck displays a warning about possible corruption of the snapshots in interactive mode and avoids freeing blocks in preen mode. Signed-off-by: Amir Goldstein --- e2fsck/e2fsck.h | 1 + e2fsck/pass1.c | 11 +++++++++++ e2fsck/pass5.c | 4 ++++ e2fsck/rehash.c | 7 +++++++ e2fsck/super.c | 41 +++++++++++++++++++++++++++++++++++++++++ e2fsck/unix.c | 1 + misc/mke2fs.c | 1 + misc/tune2fs.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ resize/main.c | 11 +++++++++++ 9 files changed, 131 insertions(+), 0 deletions(-) diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h index 0f23751..13d4161 100644 --- a/e2fsck/e2fsck.h +++ b/e2fsck/e2fsck.h @@ -477,6 +477,7 @@ void check_super_block(e2fsck_t ctx); int check_backup_super_block(e2fsck_t ctx); void check_resize_inode(e2fsck_t ctx); void check_exclude_inode(e2fsck_t ctx); +void check_snapshots(e2fsck_t ctx); /* util.c */ extern void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size, diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c index 5793467..43ca2e6 100644 --- a/e2fsck/pass1.c +++ b/e2fsck/pass1.c @@ -1668,6 +1668,17 @@ void e2fsck_clear_inode(e2fsck_t ctx, ext2_ino_t ino, struct ext2_inode *inode, int restart_flag, const char *source) { + /* don't clear inode with blocks when preening volume with active snapshot */ + if ((ctx->fs->super->s_feature_ro_compat & + EXT4_FEATURE_RO_COMPAT_HAS_SNAPSHOT) && + ctx->fs->super->s_snapshot_inum) { + int i; + for (i = 0; i < EXT2_N_BLOCKS; i++) + if (inode->i_block[i]) + /* if we don't halt, inode blocks will be freed */ + preenhalt(ctx); + } + inode->i_flags = 0; inode->i_links_count = 0; ext2fs_icount_store(ctx->inode_link_info, ino, 0); diff --git a/e2fsck/pass5.c b/e2fsck/pass5.c index cbc12f3..fa14b19 100644 --- a/e2fsck/pass5.c +++ b/e2fsck/pass5.c @@ -334,6 +334,10 @@ redo_counts: } else if (fixit == 0) ext2fs_unmark_valid(fs); + if (fs->super->s_flags & EXT2_FLAGS_IS_SNAPSHOT) + /* ignore free block counts in next3 snapshot image */ + goto errout; + for (i = 0; i < fs->group_desc_count; i++) { if (free_array[i] != ext2fs_bg_free_blocks_count(fs, i)) { pctx.group = i; diff --git a/e2fsck/rehash.c b/e2fsck/rehash.c index 5543134..e045fd1 100644 --- a/e2fsck/rehash.c +++ b/e2fsck/rehash.c @@ -829,6 +829,13 @@ void e2fsck_rehash_directories(e2fsck_t ctx) int cur, max, all_dirs, dir_index, first = 1; init_resource_track(&rtrack, ctx->fs->io); + + /* never rehash directories when scanning volume with active snapshot */ + if ((ctx->fs->super->s_feature_ro_compat & + EXT4_FEATURE_RO_COMPAT_HAS_SNAPSHOT) && + ctx->fs->super->s_snapshot_inum) + return; + all_dirs = ctx->options & E2F_OPT_COMPRESS_DIRS; if (!ctx->dirs_to_hash && !all_dirs) diff --git a/e2fsck/super.c b/e2fsck/super.c index c155949..a9cf0d9 100644 --- a/e2fsck/super.c +++ b/e2fsck/super.c @@ -231,6 +231,12 @@ static int release_orphan_inodes(e2fsck_t ctx) struct problem_context pctx; char *block_buf; + /* never release orphans when scanning volume with active snapshot */ + if ((fs->super->s_feature_ro_compat & + EXT4_FEATURE_RO_COMPAT_HAS_SNAPSHOT) && + fs->super->s_snapshot_inum) + return 0; + if ((ino = fs->super->s_last_orphan) == 0) return 0; @@ -510,6 +516,41 @@ void check_exclude_inode(e2fsck_t ctx) } /* + * This function checks if the file system has snapshots + */ +void check_snapshots(e2fsck_t ctx) +{ + struct ext2_super_block *sb = ctx->fs->super; + struct problem_context pctx; + int cont; + + if (!(sb->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_HAS_SNAPSHOT)) + /* no snapshots */ + return; + + if (!sb->s_snapshot_inum) + /* no active snapshot */ + return; + + if ((ctx->options & E2F_OPT_PREEN) || + (ctx->options & E2F_OPT_NO)) + /* preen and readonly modes are snapshot friendly */ + return; + + printf(_("%s has snapshots. "), ctx->filesystem_name); + if (!ctx->interactive) + fatal_error(ctx, _("Cannot continue, aborting.\n\n")); + printf(_("\n\n\007\007\007\007WARNING!!! " + "Running e2fsck on filesystem with snapshots may\n" + "damage the snapshots.\007\007\007\n\n")); + cont = ask_yn(_("Do you really want to continue"), -1); + if (!cont) { + printf (_("check aborted.\n")); + exit (0); + } +} + +/* * This function checks the dirhash signed/unsigned hint if necessary. */ static void e2fsck_fix_dirhash_hint(e2fsck_t ctx) diff --git a/e2fsck/unix.c b/e2fsck/unix.c index 71e563d..43b0197 100644 --- a/e2fsck/unix.c +++ b/e2fsck/unix.c @@ -1319,6 +1319,7 @@ print_unsupp_features: fatal_error(ctx, 0); check_if_skip(ctx); check_resize_inode(ctx); + check_snapshots(ctx); check_exclude_inode(ctx); if (bad_blocks_file) read_bad_blocks_file(ctx, bad_blocks_file, replace_bad_blocks); diff --git a/misc/mke2fs.c b/misc/mke2fs.c index 6894945..f383f82 100644 --- a/misc/mke2fs.c +++ b/misc/mke2fs.c @@ -801,6 +801,7 @@ static __u32 ok_features[3] = { EXT4_FEATURE_INCOMPAT_64BIT, /* R/O compat */ EXT2_FEATURE_RO_COMPAT_LARGE_FILE| + EXT4_FEATURE_RO_COMPAT_HAS_SNAPSHOT|\ EXT4_FEATURE_RO_COMPAT_HUGE_FILE| EXT4_FEATURE_RO_COMPAT_DIR_NLINK| EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE| diff --git a/misc/tune2fs.c b/misc/tune2fs.c index 596b384..47d2754 100644 --- a/misc/tune2fs.c +++ b/misc/tune2fs.c @@ -127,6 +127,7 @@ static __u32 ok_features[3] = { EXT4_FEATURE_INCOMPAT_FLEX_BG, /* R/O compat */ EXT2_FEATURE_RO_COMPAT_LARGE_FILE | + EXT4_FEATURE_RO_COMPAT_HAS_SNAPSHOT|\ EXT4_FEATURE_RO_COMPAT_HUGE_FILE| EXT4_FEATURE_RO_COMPAT_DIR_NLINK| EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE| @@ -145,6 +146,7 @@ static __u32 clear_ok_features[3] = { EXT4_FEATURE_INCOMPAT_FLEX_BG, /* R/O compat */ EXT2_FEATURE_RO_COMPAT_LARGE_FILE | + EXT4_FEATURE_RO_COMPAT_HAS_SNAPSHOT|\ EXT4_FEATURE_RO_COMPAT_HUGE_FILE| EXT4_FEATURE_RO_COMPAT_DIR_NLINK| EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE| @@ -448,6 +450,23 @@ static void update_feature_set(ext2_filsys fs, char *features) old_features[E2P_FEATURE_INCOMPAT] = sb->s_feature_incompat; old_features[E2P_FEATURE_RO_INCOMPAT] = sb->s_feature_ro_compat; + /* disallow changing features when filesystem has snapshots */ + if (sb->s_feature_ro_compat & + EXT4_FEATURE_RO_COMPAT_HAS_SNAPSHOT) { + fputs(_("The filesystem has snapshots. " + "Please clear the has_snapshot flag\n" + "before clearing/setting other filesystem flags.\n"), + stderr); + ok_features[E2P_FEATURE_COMPAT] = 0; + ok_features[E2P_FEATURE_INCOMPAT] = 0; + ok_features[E2P_FEATURE_RO_INCOMPAT] = + EXT4_FEATURE_RO_COMPAT_HAS_SNAPSHOT; + clear_ok_features[E2P_FEATURE_COMPAT] = 0; + clear_ok_features[E2P_FEATURE_INCOMPAT] = 0; + clear_ok_features[E2P_FEATURE_RO_INCOMPAT] = + EXT4_FEATURE_RO_COMPAT_HAS_SNAPSHOT; + } + if (e2p_edit_feature2(features, &sb->s_feature_compat, ok_features, clear_ok_features, &type_err, &mask_err)) { @@ -516,6 +535,41 @@ static void update_feature_set(ext2_filsys fs, char *features) } } + if (FEATURE_ON_SAFE(E2P_FEATURE_RO_INCOMPAT, + EXT4_FEATURE_RO_COMPAT_HAS_SNAPSHOT)) { + int big_journal = 0; + + if ((sb->s_feature_compat & + EXT3_FEATURE_COMPAT_HAS_JOURNAL)) { + /* update 'big_journal' flag */ + big_journal = (ext2fs_check_journal_size(fs) >= + NEXT3_MIN_JOURNAL_BLOCKS); + } else if (!journal_size || journal_size == -1) { + /* Create a big journal for Next3 */ + journal_size = -NEXT3_MAX_COW_CREDITS; + big_journal = 1; + } + + if (!big_journal) + fprintf(stderr, + _("Warning: journal size is not big enough.\n" + "For best operation of Next3, try re-creating " + "the journal with '-J big' before setting the " + "'has_snapshot' flag.\n")); + + /* allocate/reset exclude bitmap blocks */ + retval = ext2fs_create_exclude_inode(fs, EXCLUDE_CREATE); + if (!retval) + sb->s_feature_compat |= + EXT2_FEATURE_COMPAT_EXCLUDE_INODE; + else + fprintf(stderr, + _("Warning: failed to create exclude inode.\n" + "For best operation of Next3, try re-creating " + "the exclude inode before setting the " + "'has_snapshot' flag.\n")); + } + if (FEATURE_ON(E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_INDEX)) { if (!sb->s_def_hash_version) sb->s_def_hash_version = EXT2_HASH_HALF_MD4; diff --git a/resize/main.c b/resize/main.c index 7d8b287..ab5515f 100644 --- a/resize/main.c +++ b/resize/main.c @@ -444,6 +444,17 @@ int main (int argc, char ** argv) if (mount_flags & EXT2_MF_MOUNTED) { retval = online_resize_fs(fs, mtpt, &new_size, flags); } else { + /* do not offline resize a volume with active snapshot */ + if (!force && (fs->super->s_feature_ro_compat & + EXT4_FEATURE_RO_COMPAT_HAS_SNAPSHOT) && + fs->super->s_snapshot_inum) { + fprintf(stderr, + _("offline resize will damage next3 snapshots " + "on %s - Please mount the filesystem " + "for online resize.\n\n"), + device_name); + exit(1); + } if (!force && ((fs->super->s_lastcheck < fs->super->s_mtime) || (fs->super->s_state & EXT2_ERROR_FS) || ((fs->super->s_state & EXT2_VALID_FS) == 0))) {