aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4
diff options
context:
space:
mode:
authorTakashi Sato <t-sato@yk.jp.nec.com>2009-01-09 19:40:58 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-01-09 19:54:42 -0500
commitc4be0c1dc4cdc37b175579be1460f15ac6495e9a (patch)
tree716ea88318211ed27cadcebda0fd85c1f8246edb /fs/ext4
parent69347a236b22c3962ea812511495e502dedfd50c (diff)
filesystem freeze: add error handling of write_super_lockfs/unlockfs
Currently, ext3 in mainline Linux doesn't have the freeze feature which suspends write requests. So, we cannot take a backup which keeps the filesystem's consistency with the storage device's features (snapshot and replication) while it is mounted. In many case, a commercial filesystem (e.g. VxFS) has the freeze feature and it would be used to get the consistent backup. If Linux's standard filesystem ext3 has the freeze feature, we can do it without a commercial filesystem. So I have implemented the ioctls of the freeze feature. I think we can take the consistent backup with the following steps. 1. Freeze the filesystem with the freeze ioctl. 2. Separate the replication volume or create the snapshot with the storage device's feature. 3. Unfreeze the filesystem with the unfreeze ioctl. 4. Take the backup from the separated replication volume or the snapshot. This patch: VFS: Changed the type of write_super_lockfs and unlockfs from "void" to "int" so that they can return an error. Rename write_super_lockfs and unlockfs of the super block operation freeze_fs and unfreeze_fs to avoid a confusion. ext3, ext4, xfs, gfs2, jfs: Changed the type of write_super_lockfs and unlockfs from "void" to "int" so that write_super_lockfs returns an error if needed, and unlockfs always returns 0. reiserfs: Changed the type of write_super_lockfs and unlockfs from "void" to "int" so that they always return 0 (success) to keep a current behavior. Signed-off-by: Takashi Sato <t-sato@yk.jp.nec.com> Signed-off-by: Masayuki Hamaguchi <m-hamaguchi@ys.jp.nec.com> Cc: <xfs-masters@oss.sgi.com> Cc: <linux-ext4@vger.kernel.org> Cc: Christoph Hellwig <hch@lst.de> Cc: Dave Kleikamp <shaggy@austin.ibm.com> Cc: Dave Chinner <david@fromorbit.com> Cc: Alasdair G Kergon <agk@redhat.com> Cc: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/ext4')
-rw-r--r--fs/ext4/super.c45
1 files changed, 31 insertions, 14 deletions
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 8f7e0be8ab1b..e5f06a5f045e 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -51,7 +51,7 @@ struct proc_dir_entry *ext4_proc_root;
51 51
52static int ext4_load_journal(struct super_block *, struct ext4_super_block *, 52static int ext4_load_journal(struct super_block *, struct ext4_super_block *,
53 unsigned long journal_devnum); 53 unsigned long journal_devnum);
54static void ext4_commit_super(struct super_block *sb, 54static int ext4_commit_super(struct super_block *sb,
55 struct ext4_super_block *es, int sync); 55 struct ext4_super_block *es, int sync);
56static void ext4_mark_recovery_complete(struct super_block *sb, 56static void ext4_mark_recovery_complete(struct super_block *sb,
57 struct ext4_super_block *es); 57 struct ext4_super_block *es);
@@ -62,9 +62,9 @@ static const char *ext4_decode_error(struct super_block *sb, int errno,
62 char nbuf[16]); 62 char nbuf[16]);
63static int ext4_remount(struct super_block *sb, int *flags, char *data); 63static int ext4_remount(struct super_block *sb, int *flags, char *data);
64static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf); 64static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf);
65static void ext4_unlockfs(struct super_block *sb); 65static int ext4_unfreeze(struct super_block *sb);
66static void ext4_write_super(struct super_block *sb); 66static void ext4_write_super(struct super_block *sb);
67static void ext4_write_super_lockfs(struct super_block *sb); 67static int ext4_freeze(struct super_block *sb);
68 68
69 69
70ext4_fsblk_t ext4_block_bitmap(struct super_block *sb, 70ext4_fsblk_t ext4_block_bitmap(struct super_block *sb,
@@ -978,8 +978,8 @@ static const struct super_operations ext4_sops = {
978 .put_super = ext4_put_super, 978 .put_super = ext4_put_super,
979 .write_super = ext4_write_super, 979 .write_super = ext4_write_super,
980 .sync_fs = ext4_sync_fs, 980 .sync_fs = ext4_sync_fs,
981 .write_super_lockfs = ext4_write_super_lockfs, 981 .freeze_fs = ext4_freeze,
982 .unlockfs = ext4_unlockfs, 982 .unfreeze_fs = ext4_unfreeze,
983 .statfs = ext4_statfs, 983 .statfs = ext4_statfs,
984 .remount_fs = ext4_remount, 984 .remount_fs = ext4_remount,
985 .clear_inode = ext4_clear_inode, 985 .clear_inode = ext4_clear_inode,
@@ -2888,13 +2888,14 @@ static int ext4_load_journal(struct super_block *sb,
2888 return 0; 2888 return 0;
2889} 2889}
2890 2890
2891static void ext4_commit_super(struct super_block *sb, 2891static int ext4_commit_super(struct super_block *sb,
2892 struct ext4_super_block *es, int sync) 2892 struct ext4_super_block *es, int sync)
2893{ 2893{
2894 struct buffer_head *sbh = EXT4_SB(sb)->s_sbh; 2894 struct buffer_head *sbh = EXT4_SB(sb)->s_sbh;
2895 int error = 0;
2895 2896
2896 if (!sbh) 2897 if (!sbh)
2897 return; 2898 return error;
2898 if (buffer_write_io_error(sbh)) { 2899 if (buffer_write_io_error(sbh)) {
2899 /* 2900 /*
2900 * Oh, dear. A previous attempt to write the 2901 * Oh, dear. A previous attempt to write the
@@ -2918,14 +2919,19 @@ static void ext4_commit_super(struct super_block *sb,
2918 BUFFER_TRACE(sbh, "marking dirty"); 2919 BUFFER_TRACE(sbh, "marking dirty");
2919 mark_buffer_dirty(sbh); 2920 mark_buffer_dirty(sbh);
2920 if (sync) { 2921 if (sync) {
2921 sync_dirty_buffer(sbh); 2922 error = sync_dirty_buffer(sbh);
2922 if (buffer_write_io_error(sbh)) { 2923 if (error)
2924 return error;
2925
2926 error = buffer_write_io_error(sbh);
2927 if (error) {
2923 printk(KERN_ERR "EXT4-fs: I/O error while writing " 2928 printk(KERN_ERR "EXT4-fs: I/O error while writing "
2924 "superblock for %s.\n", sb->s_id); 2929 "superblock for %s.\n", sb->s_id);
2925 clear_buffer_write_io_error(sbh); 2930 clear_buffer_write_io_error(sbh);
2926 set_buffer_uptodate(sbh); 2931 set_buffer_uptodate(sbh);
2927 } 2932 }
2928 } 2933 }
2934 return error;
2929} 2935}
2930 2936
2931 2937
@@ -3058,12 +3064,14 @@ static int ext4_sync_fs(struct super_block *sb, int wait)
3058 * LVM calls this function before a (read-only) snapshot is created. This 3064 * LVM calls this function before a (read-only) snapshot is created. This
3059 * gives us a chance to flush the journal completely and mark the fs clean. 3065 * gives us a chance to flush the journal completely and mark the fs clean.
3060 */ 3066 */
3061static void ext4_write_super_lockfs(struct super_block *sb) 3067static int ext4_freeze(struct super_block *sb)
3062{ 3068{
3069 int error = 0;
3070 journal_t *journal;
3063 sb->s_dirt = 0; 3071 sb->s_dirt = 0;
3064 3072
3065 if (!(sb->s_flags & MS_RDONLY)) { 3073 if (!(sb->s_flags & MS_RDONLY)) {
3066 journal_t *journal = EXT4_SB(sb)->s_journal; 3074 journal = EXT4_SB(sb)->s_journal;
3067 3075
3068 if (journal) { 3076 if (journal) {
3069 /* Now we set up the journal barrier. */ 3077 /* Now we set up the journal barrier. */
@@ -3073,21 +3081,29 @@ static void ext4_write_super_lockfs(struct super_block *sb)
3073 * We don't want to clear needs_recovery flag when we 3081 * We don't want to clear needs_recovery flag when we
3074 * failed to flush the journal. 3082 * failed to flush the journal.
3075 */ 3083 */
3076 if (jbd2_journal_flush(journal) < 0) 3084 error = jbd2_journal_flush(journal);
3077 return; 3085 if (error < 0)
3086 goto out;
3078 } 3087 }
3079 3088
3080 /* Journal blocked and flushed, clear needs_recovery flag. */ 3089 /* Journal blocked and flushed, clear needs_recovery flag. */
3081 EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER); 3090 EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
3082 ext4_commit_super(sb, EXT4_SB(sb)->s_es, 1); 3091 ext4_commit_super(sb, EXT4_SB(sb)->s_es, 1);
3092 error = ext4_commit_super(sb, EXT4_SB(sb)->s_es, 1);
3093 if (error)
3094 goto out;
3083 } 3095 }
3096 return 0;
3097out:
3098 jbd2_journal_unlock_updates(journal);
3099 return error;
3084} 3100}
3085 3101
3086/* 3102/*
3087 * Called by LVM after the snapshot is done. We need to reset the RECOVER 3103 * Called by LVM after the snapshot is done. We need to reset the RECOVER
3088 * flag here, even though the filesystem is not technically dirty yet. 3104 * flag here, even though the filesystem is not technically dirty yet.
3089 */ 3105 */
3090static void ext4_unlockfs(struct super_block *sb) 3106static int ext4_unfreeze(struct super_block *sb)
3091{ 3107{
3092 if (EXT4_SB(sb)->s_journal && !(sb->s_flags & MS_RDONLY)) { 3108 if (EXT4_SB(sb)->s_journal && !(sb->s_flags & MS_RDONLY)) {
3093 lock_super(sb); 3109 lock_super(sb);
@@ -3097,6 +3113,7 @@ static void ext4_unlockfs(struct super_block *sb)
3097 unlock_super(sb); 3113 unlock_super(sb);
3098 jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); 3114 jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
3099 } 3115 }
3116 return 0;
3100} 3117}
3101 3118
3102static int ext4_remount(struct super_block *sb, int *flags, char *data) 3119static int ext4_remount(struct super_block *sb, int *flags, char *data)