Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1 | /* |
| 2 | * closefs.c --- close an ext2 filesystem |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 3 | * |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 4 | * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. |
| 5 | * |
| 6 | * %Begin-Header% |
Theodore Ts'o | 543547a | 2010-05-17 21:31:56 -0400 | [diff] [blame] | 7 | * This file may be redistributed under the terms of the GNU Library |
| 8 | * General Public License, version 2. |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 9 | * %End-Header% |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 10 | */ |
| 11 | |
| 12 | #include <stdio.h> |
Theodore Ts'o | 4cbe8af | 1997-08-10 23:07:40 +0000 | [diff] [blame] | 13 | #if HAVE_UNISTD_H |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 14 | #include <unistd.h> |
Theodore Ts'o | 4cbe8af | 1997-08-10 23:07:40 +0000 | [diff] [blame] | 15 | #endif |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 16 | #include <time.h> |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 17 | #include <string.h> |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 18 | |
Theodore Ts'o | b5abe6f | 1998-01-19 14:47:53 +0000 | [diff] [blame] | 19 | #include "ext2_fs.h" |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 20 | #include "ext2fsP.h" |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 21 | |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 22 | static int test_root(unsigned int a, unsigned int b) |
Theodore Ts'o | 1b4cd9c | 2004-12-15 18:06:52 -0500 | [diff] [blame] | 23 | { |
Theodore Ts'o | 1b4cd9c | 2004-12-15 18:06:52 -0500 | [diff] [blame] | 24 | while (1) { |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 25 | if (a < b) |
| 26 | return 0; |
| 27 | if (a == b) |
Theodore Ts'o | 1b4cd9c | 2004-12-15 18:06:52 -0500 | [diff] [blame] | 28 | return 1; |
| 29 | if (a % b) |
| 30 | return 0; |
| 31 | a = a / b; |
| 32 | } |
| 33 | } |
| 34 | |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 35 | int ext2fs_bg_has_super(ext2_filsys fs, dgrp_t group) |
Theodore Ts'o | 1b4cd9c | 2004-12-15 18:06:52 -0500 | [diff] [blame] | 36 | { |
| 37 | if (!(fs->super->s_feature_ro_compat & |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 38 | EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) || group <= 1) |
| 39 | return 1; |
| 40 | if (!(group & 1)) |
| 41 | return 0; |
| 42 | if (test_root(group, 3) || (test_root(group, 5)) || |
| 43 | test_root(group, 7)) |
Theodore Ts'o | 1b4cd9c | 2004-12-15 18:06:52 -0500 | [diff] [blame] | 44 | return 1; |
| 45 | |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 46 | return 0; |
| 47 | } |
| 48 | |
| 49 | /* |
| 50 | * ext2fs_super_and_bgd_loc2() |
| 51 | * @fs: ext2 fs pointer |
| 52 | * @group given block group |
| 53 | * @ret_super_blk: if !NULL, returns super block location |
| 54 | * @ret_old_desc_blk: if !NULL, returns location of the old block |
| 55 | * group descriptor |
| 56 | * @ret_new_desc_blk: if !NULL, returns location of meta_bg block |
| 57 | * group descriptor |
| 58 | * @ret_used_blks: if !NULL, returns number of blocks used by |
| 59 | * super block and group_descriptors. |
| 60 | * |
| 61 | * Returns errcode_t of 0 |
| 62 | */ |
| 63 | errcode_t ext2fs_super_and_bgd_loc2(ext2_filsys fs, |
| 64 | dgrp_t group, |
| 65 | blk64_t *ret_super_blk, |
| 66 | blk64_t *ret_old_desc_blk, |
| 67 | blk64_t *ret_new_desc_blk, |
| 68 | blk_t *ret_used_blks) |
| 69 | { |
| 70 | blk64_t group_block, super_blk = 0, old_desc_blk = 0, new_desc_blk = 0; |
| 71 | unsigned int meta_bg, meta_bg_size; |
| 72 | blk_t numblocks = 0; |
| 73 | blk64_t old_desc_blocks; |
| 74 | int has_super; |
| 75 | |
| 76 | group_block = ext2fs_group_first_block2(fs, group); |
| 77 | if (group_block == 0 && fs->blocksize == 1024) |
| 78 | group_block = 1; /* Deal with 1024 blocksize && bigalloc */ |
| 79 | |
| 80 | if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) |
| 81 | old_desc_blocks = fs->super->s_first_meta_bg; |
| 82 | else |
| 83 | old_desc_blocks = |
| 84 | fs->desc_blocks + fs->super->s_reserved_gdt_blocks; |
| 85 | |
| 86 | has_super = ext2fs_bg_has_super(fs, group); |
| 87 | |
| 88 | if (has_super) { |
| 89 | super_blk = group_block; |
| 90 | numblocks++; |
| 91 | } |
| 92 | meta_bg_size = EXT2_DESC_PER_BLOCK(fs->super); |
| 93 | meta_bg = group / meta_bg_size; |
| 94 | |
| 95 | if (!(fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) || |
| 96 | (meta_bg < fs->super->s_first_meta_bg)) { |
| 97 | if (has_super) { |
| 98 | old_desc_blk = group_block + 1; |
| 99 | numblocks += old_desc_blocks; |
| 100 | } |
| 101 | } else { |
| 102 | if (((group % meta_bg_size) == 0) || |
| 103 | ((group % meta_bg_size) == 1) || |
| 104 | ((group % meta_bg_size) == (meta_bg_size-1))) { |
| 105 | if (has_super) |
| 106 | has_super = 1; |
| 107 | new_desc_blk = group_block + has_super; |
| 108 | numblocks++; |
| 109 | } |
| 110 | } |
| 111 | |
| 112 | if (ret_super_blk) |
| 113 | *ret_super_blk = super_blk; |
| 114 | if (ret_old_desc_blk) |
| 115 | *ret_old_desc_blk = old_desc_blk; |
| 116 | if (ret_new_desc_blk) |
| 117 | *ret_new_desc_blk = new_desc_blk; |
| 118 | if (ret_used_blks) |
| 119 | *ret_used_blks = numblocks; |
Jose R. Santos | 71300f3 | 2009-06-01 16:15:40 -0400 | [diff] [blame] | 120 | |
| 121 | return 0; |
| 122 | } |
| 123 | |
| 124 | /* |
Theodore Ts'o | 4a56850 | 2008-04-20 19:22:49 -0400 | [diff] [blame] | 125 | * This function returns the location of the superblock, block group |
| 126 | * descriptors for a given block group. It currently returns the |
| 127 | * number of free blocks assuming that inode table and allocation |
| 128 | * bitmaps will be in the group. This is not necessarily the case |
| 129 | * when the flex_bg feature is enabled, so callers should take care! |
| 130 | * It was only really intended for use by mke2fs, and even there it's |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 131 | * not that useful. |
Theodore Ts'o | 4a56850 | 2008-04-20 19:22:49 -0400 | [diff] [blame] | 132 | * |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 133 | * The ext2fs_super_and_bgd_loc2() function is 64-bit block number |
| 134 | * capable and returns the number of blocks used by super block and |
| 135 | * group descriptors. |
Theodore Ts'o | 4a56850 | 2008-04-20 19:22:49 -0400 | [diff] [blame] | 136 | */ |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 137 | int ext2fs_super_and_bgd_loc(ext2_filsys fs, |
Theodore Ts'o | ef344e1 | 2003-11-21 09:02:21 -0500 | [diff] [blame] | 138 | dgrp_t group, |
| 139 | blk_t *ret_super_blk, |
| 140 | blk_t *ret_old_desc_blk, |
| 141 | blk_t *ret_new_desc_blk, |
| 142 | int *ret_meta_bg) |
| 143 | { |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 144 | blk64_t ret_super_blk2; |
| 145 | blk64_t ret_old_desc_blk2; |
| 146 | blk64_t ret_new_desc_blk2; |
| 147 | blk_t ret_used_blks; |
| 148 | blk_t numblocks; |
| 149 | unsigned int meta_bg_size; |
Theodore Ts'o | ef344e1 | 2003-11-21 09:02:21 -0500 | [diff] [blame] | 150 | |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 151 | ext2fs_super_and_bgd_loc2(fs, group, &ret_super_blk2, |
| 152 | &ret_old_desc_blk2, |
| 153 | &ret_new_desc_blk2, |
| 154 | &ret_used_blks); |
Theodore Ts'o | ef344e1 | 2003-11-21 09:02:21 -0500 | [diff] [blame] | 155 | |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 156 | numblocks = ext2fs_group_blocks_count(fs, group); |
Jose R. Santos | 71300f3 | 2009-06-01 16:15:40 -0400 | [diff] [blame] | 157 | |
JP Abgrall | 65f0aab | 2014-03-06 13:50:20 -0800 | [diff] [blame] | 158 | if (ret_super_blk) |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 159 | *ret_super_blk = (blk_t)ret_super_blk2; |
JP Abgrall | 65f0aab | 2014-03-06 13:50:20 -0800 | [diff] [blame] | 160 | if (ret_old_desc_blk) |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 161 | *ret_old_desc_blk = (blk_t)ret_old_desc_blk2; |
JP Abgrall | 65f0aab | 2014-03-06 13:50:20 -0800 | [diff] [blame] | 162 | if (ret_new_desc_blk) |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 163 | *ret_new_desc_blk = (blk_t)ret_new_desc_blk2; |
| 164 | if (ret_meta_bg) { |
| 165 | meta_bg_size = EXT2_DESC_PER_BLOCK(fs->super); |
| 166 | *ret_meta_bg = group / meta_bg_size; |
| 167 | } |
Theodore Ts'o | ef344e1 | 2003-11-21 09:02:21 -0500 | [diff] [blame] | 168 | |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 169 | numblocks -= 2 + fs->inode_blocks_per_group + ret_used_blks; |
| 170 | |
| 171 | return numblocks; |
| 172 | } |
JP Abgrall | 65f0aab | 2014-03-06 13:50:20 -0800 | [diff] [blame] | 173 | |
Theodore Ts'o | c180ac8 | 2000-10-26 20:24:43 +0000 | [diff] [blame] | 174 | /* |
| 175 | * This function forces out the primary superblock. We need to only |
| 176 | * write out those fields which we have changed, since if the |
| 177 | * filesystem is mounted, it may have changed some of the other |
| 178 | * fields. |
| 179 | * |
| 180 | * It takes as input a superblock which has already been byte swapped |
| 181 | * (if necessary). |
| 182 | * |
| 183 | */ |
| 184 | static errcode_t write_primary_superblock(ext2_filsys fs, |
| 185 | struct ext2_super_block *super) |
| 186 | { |
| 187 | __u16 *old_super, *new_super; |
| 188 | int check_idx, write_idx, size; |
| 189 | errcode_t retval; |
| 190 | |
| 191 | if (!fs->io->manager->write_byte || !fs->orig_super) { |
Theodore Ts'o | 7f1a1fb | 2010-09-24 10:02:25 -0400 | [diff] [blame] | 192 | fallback: |
Theodore Ts'o | c180ac8 | 2000-10-26 20:24:43 +0000 | [diff] [blame] | 193 | io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET); |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 194 | retval = io_channel_write_blk64(fs->io, 1, -SUPERBLOCK_SIZE, |
Theodore Ts'o | c180ac8 | 2000-10-26 20:24:43 +0000 | [diff] [blame] | 195 | super); |
| 196 | io_channel_set_blksize(fs->io, fs->blocksize); |
| 197 | return retval; |
| 198 | } |
| 199 | |
| 200 | old_super = (__u16 *) fs->orig_super; |
| 201 | new_super = (__u16 *) super; |
| 202 | |
| 203 | for (check_idx = 0; check_idx < SUPERBLOCK_SIZE/2; check_idx++) { |
| 204 | if (old_super[check_idx] == new_super[check_idx]) |
| 205 | continue; |
| 206 | write_idx = check_idx; |
| 207 | for (check_idx++; check_idx < SUPERBLOCK_SIZE/2; check_idx++) |
| 208 | if (old_super[check_idx] == new_super[check_idx]) |
| 209 | break; |
| 210 | size = 2 * (check_idx - write_idx); |
| 211 | #if 0 |
| 212 | printf("Writing %d bytes starting at %d\n", |
| 213 | size, write_idx*2); |
| 214 | #endif |
| 215 | retval = io_channel_write_byte(fs->io, |
| 216 | SUPERBLOCK_OFFSET + (2 * write_idx), size, |
| 217 | new_super + write_idx); |
Theodore Ts'o | 7f1a1fb | 2010-09-24 10:02:25 -0400 | [diff] [blame] | 218 | if (retval == EXT2_ET_UNIMPLEMENTED) |
| 219 | goto fallback; |
Theodore Ts'o | c180ac8 | 2000-10-26 20:24:43 +0000 | [diff] [blame] | 220 | if (retval) |
| 221 | return retval; |
| 222 | } |
Theodore Ts'o | 3c6b897 | 2001-07-10 14:27:58 -0400 | [diff] [blame] | 223 | memcpy(fs->orig_super, super, SUPERBLOCK_SIZE); |
Theodore Ts'o | c180ac8 | 2000-10-26 20:24:43 +0000 | [diff] [blame] | 224 | return 0; |
| 225 | } |
| 226 | |
| 227 | |
Theodore Ts'o | 3fe973b | 2000-12-13 17:55:49 +0000 | [diff] [blame] | 228 | /* |
| 229 | * Updates the revision to EXT2_DYNAMIC_REV |
| 230 | */ |
Theodore Ts'o | a917d1c | 2000-12-13 18:36:23 +0000 | [diff] [blame] | 231 | void ext2fs_update_dynamic_rev(ext2_filsys fs) |
Theodore Ts'o | 3fe973b | 2000-12-13 17:55:49 +0000 | [diff] [blame] | 232 | { |
| 233 | struct ext2_super_block *sb = fs->super; |
| 234 | |
| 235 | if (sb->s_rev_level > EXT2_GOOD_OLD_REV) |
| 236 | return; |
| 237 | |
| 238 | sb->s_rev_level = EXT2_DYNAMIC_REV; |
| 239 | sb->s_first_ino = EXT2_GOOD_OLD_FIRST_INO; |
| 240 | sb->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE; |
| 241 | /* s_uuid is handled by e2fsck already */ |
| 242 | /* other fields should be left alone */ |
| 243 | } |
| 244 | |
Theodore Ts'o | c046ac7 | 2002-10-20 00:38:57 -0400 | [diff] [blame] | 245 | static errcode_t write_backup_super(ext2_filsys fs, dgrp_t group, |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 246 | blk64_t group_block, |
Theodore Ts'o | c046ac7 | 2002-10-20 00:38:57 -0400 | [diff] [blame] | 247 | struct ext2_super_block *super_shadow) |
| 248 | { |
| 249 | dgrp_t sgrp = group; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 250 | |
Theodore Ts'o | c046ac7 | 2002-10-20 00:38:57 -0400 | [diff] [blame] | 251 | if (sgrp > ((1 << 16) - 1)) |
| 252 | sgrp = (1 << 16) - 1; |
Theodore Ts'o | 126a291 | 2007-08-11 01:56:48 -0400 | [diff] [blame] | 253 | #ifdef WORDS_BIGENDIAN |
| 254 | super_shadow->s_block_group_nr = ext2fs_swab16(sgrp); |
| 255 | #else |
| 256 | fs->super->s_block_group_nr = sgrp; |
Theodore Ts'o | c046ac7 | 2002-10-20 00:38:57 -0400 | [diff] [blame] | 257 | #endif |
Theodore Ts'o | c046ac7 | 2002-10-20 00:38:57 -0400 | [diff] [blame] | 258 | |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 259 | return io_channel_write_blk64(fs->io, group_block, -SUPERBLOCK_SIZE, |
Theodore Ts'o | c046ac7 | 2002-10-20 00:38:57 -0400 | [diff] [blame] | 260 | super_shadow); |
| 261 | } |
| 262 | |
JP Abgrall | 65f0aab | 2014-03-06 13:50:20 -0800 | [diff] [blame] | 263 | errcode_t ext2fs_flush(ext2_filsys fs) |
Richard W.M. Jones | 9d9a53e | 2011-09-24 10:50:42 -0400 | [diff] [blame] | 264 | { |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 265 | return ext2fs_flush2(fs, 0); |
| 266 | } |
| 267 | |
| 268 | errcode_t ext2fs_flush2(ext2_filsys fs, int flags) |
| 269 | { |
Theodore Ts'o | 2d328bb | 2008-03-17 23:17:13 -0400 | [diff] [blame] | 270 | dgrp_t i; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 271 | errcode_t retval; |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 272 | unsigned long fs_state; |
Theodore Ts'o | 9a083af | 2007-12-15 19:39:37 -0500 | [diff] [blame] | 273 | __u32 feature_incompat; |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 274 | struct ext2_super_block *super_shadow = 0; |
| 275 | struct ext2_group_desc *group_shadow = 0; |
Theodore Ts'o | 2d328bb | 2008-03-17 23:17:13 -0400 | [diff] [blame] | 276 | #ifdef WORDS_BIGENDIAN |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 277 | struct ext2_group_desc *gdp; |
Theodore Ts'o | 2d328bb | 2008-03-17 23:17:13 -0400 | [diff] [blame] | 278 | dgrp_t j; |
| 279 | #endif |
Theodore Ts'o | ef344e1 | 2003-11-21 09:02:21 -0500 | [diff] [blame] | 280 | char *group_ptr; |
| 281 | int old_desc_blocks; |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 282 | struct ext2fs_numeric_progress_struct progress; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 283 | |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 284 | EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); |
| 285 | |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 286 | fs_state = fs->super->s_state; |
Theodore Ts'o | 9a083af | 2007-12-15 19:39:37 -0500 | [diff] [blame] | 287 | feature_incompat = fs->super->s_feature_incompat; |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 288 | |
Theodore Ts'o | 3213818 | 2005-09-24 20:14:51 -0400 | [diff] [blame] | 289 | fs->super->s_wtime = fs->now ? fs->now : time(NULL); |
Theodore Ts'o | e5b38a5 | 2001-01-01 16:17:12 +0000 | [diff] [blame] | 290 | fs->super->s_block_group_nr = 0; |
Theodore Ts'o | 126a291 | 2007-08-11 01:56:48 -0400 | [diff] [blame] | 291 | #ifdef WORDS_BIGENDIAN |
| 292 | retval = EXT2_ET_NO_MEMORY; |
| 293 | retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &super_shadow); |
| 294 | if (retval) |
| 295 | goto errout; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 296 | retval = ext2fs_get_array(fs->desc_blocks, fs->blocksize, |
Theodore Ts'o | e6a4571 | 2007-12-09 17:03:01 -0500 | [diff] [blame] | 297 | &group_shadow); |
Theodore Ts'o | 126a291 | 2007-08-11 01:56:48 -0400 | [diff] [blame] | 298 | if (retval) |
| 299 | goto errout; |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 300 | memcpy(group_shadow, fs->group_desc, (size_t) fs->blocksize * |
Theodore Ts'o | 126a291 | 2007-08-11 01:56:48 -0400 | [diff] [blame] | 301 | fs->desc_blocks); |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 302 | |
Theodore Ts'o | 126a291 | 2007-08-11 01:56:48 -0400 | [diff] [blame] | 303 | /* swap the group descriptors */ |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 304 | for (j = 0; j < fs->group_desc_count; j++) { |
| 305 | gdp = ext2fs_group_desc(fs, group_shadow, j); |
| 306 | ext2fs_swap_group_desc2(fs, gdp); |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 307 | } |
Theodore Ts'o | 5df55d7 | 2001-06-11 07:00:04 +0000 | [diff] [blame] | 308 | #else |
| 309 | super_shadow = fs->super; |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 310 | group_shadow = ext2fs_group_desc(fs, fs->group_desc, 0); |
Theodore Ts'o | 5df55d7 | 2001-06-11 07:00:04 +0000 | [diff] [blame] | 311 | #endif |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 312 | |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 313 | /* |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 314 | * Set the state of the FS to be non-valid. (The state has |
Theodore Ts'o | a63d126 | 2004-05-26 21:29:14 -0400 | [diff] [blame] | 315 | * already been backed up earlier, and will be restored after |
| 316 | * we write out the backup superblocks.) |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 317 | */ |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 318 | fs->super->s_state &= ~EXT2_VALID_FS; |
Theodore Ts'o | 9a083af | 2007-12-15 19:39:37 -0500 | [diff] [blame] | 319 | fs->super->s_feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER; |
Theodore Ts'o | 126a291 | 2007-08-11 01:56:48 -0400 | [diff] [blame] | 320 | #ifdef WORDS_BIGENDIAN |
| 321 | *super_shadow = *fs->super; |
| 322 | ext2fs_swap_super(super_shadow); |
Theodore Ts'o | 5df55d7 | 2001-06-11 07:00:04 +0000 | [diff] [blame] | 323 | #endif |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 324 | |
| 325 | /* |
Theodore Ts'o | 0d96104 | 2005-11-12 23:30:39 -0500 | [diff] [blame] | 326 | * If this is an external journal device, don't write out the |
| 327 | * block group descriptors or any of the backup superblocks |
| 328 | */ |
| 329 | if (fs->super->s_feature_incompat & |
| 330 | EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) |
| 331 | goto write_primary_superblock_only; |
| 332 | |
| 333 | /* |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 334 | * Write out the master group descriptors, and the backup |
| 335 | * superblocks and group descriptors. |
| 336 | */ |
Theodore Ts'o | ef344e1 | 2003-11-21 09:02:21 -0500 | [diff] [blame] | 337 | group_ptr = (char *) group_shadow; |
| 338 | if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) |
| 339 | old_desc_blocks = fs->super->s_first_meta_bg; |
| 340 | else |
| 341 | old_desc_blocks = fs->desc_blocks; |
| 342 | |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 343 | ext2fs_numeric_progress_init(fs, &progress, NULL, |
| 344 | fs->group_desc_count); |
Theodore Ts'o | ef344e1 | 2003-11-21 09:02:21 -0500 | [diff] [blame] | 345 | |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 346 | |
| 347 | for (i = 0; i < fs->group_desc_count; i++) { |
| 348 | blk64_t super_blk, old_desc_blk, new_desc_blk; |
| 349 | |
| 350 | ext2fs_numeric_progress_update(fs, &progress, i); |
| 351 | ext2fs_super_and_bgd_loc2(fs, i, &super_blk, &old_desc_blk, |
| 352 | &new_desc_blk, 0); |
Theodore Ts'o | ef344e1 | 2003-11-21 09:02:21 -0500 | [diff] [blame] | 353 | |
| 354 | if (!(fs->flags & EXT2_FLAG_MASTER_SB_ONLY) &&i && super_blk) { |
| 355 | retval = write_backup_super(fs, i, super_blk, |
Theodore Ts'o | c046ac7 | 2002-10-20 00:38:57 -0400 | [diff] [blame] | 356 | super_shadow); |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 357 | if (retval) |
| 358 | goto errout; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 359 | } |
Theodore Ts'o | ef344e1 | 2003-11-21 09:02:21 -0500 | [diff] [blame] | 360 | if (fs->flags & EXT2_FLAG_SUPER_ONLY) |
| 361 | continue; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 362 | if ((old_desc_blk) && |
Theodore Ts'o | ef344e1 | 2003-11-21 09:02:21 -0500 | [diff] [blame] | 363 | (!(fs->flags & EXT2_FLAG_MASTER_SB_ONLY) || (i == 0))) { |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 364 | retval = io_channel_write_blk64(fs->io, |
Theodore Ts'o | ef344e1 | 2003-11-21 09:02:21 -0500 | [diff] [blame] | 365 | old_desc_blk, old_desc_blocks, group_ptr); |
| 366 | if (retval) |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 367 | goto errout; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 368 | } |
Theodore Ts'o | ef344e1 | 2003-11-21 09:02:21 -0500 | [diff] [blame] | 369 | if (new_desc_blk) { |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 370 | int meta_bg = i / EXT2_DESC_PER_BLOCK(fs->super); |
| 371 | |
| 372 | retval = io_channel_write_blk64(fs->io, new_desc_blk, |
Theodore Ts'o | ef344e1 | 2003-11-21 09:02:21 -0500 | [diff] [blame] | 373 | 1, group_ptr + (meta_bg*fs->blocksize)); |
| 374 | if (retval) |
| 375 | goto errout; |
| 376 | } |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 377 | } |
| 378 | |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 379 | ext2fs_numeric_progress_close(fs, &progress, NULL); |
| 380 | |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 381 | /* |
| 382 | * If the write_bitmaps() function is present, call it to |
| 383 | * flush the bitmaps. This is done this way so that a simple |
| 384 | * program that doesn't mess with the bitmaps doesn't need to |
| 385 | * drag in the bitmaps.c code. |
| 386 | */ |
| 387 | if (fs->write_bitmaps) { |
| 388 | retval = fs->write_bitmaps(fs); |
| 389 | if (retval) |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 390 | goto errout; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 391 | } |
Theodore Ts'o | b5abe6f | 1998-01-19 14:47:53 +0000 | [diff] [blame] | 392 | |
Theodore Ts'o | a63d126 | 2004-05-26 21:29:14 -0400 | [diff] [blame] | 393 | write_primary_superblock_only: |
| 394 | /* |
| 395 | * Write out master superblock. This has to be done |
| 396 | * separately, since it is located at a fixed location |
| 397 | * (SUPERBLOCK_OFFSET). We flush all other pending changes |
| 398 | * out to disk first, just to avoid a race condition with an |
| 399 | * insy-tinsy window.... |
| 400 | */ |
Theodore Ts'o | 0d96104 | 2005-11-12 23:30:39 -0500 | [diff] [blame] | 401 | |
| 402 | fs->super->s_block_group_nr = 0; |
| 403 | fs->super->s_state = fs_state; |
Theodore Ts'o | 9a083af | 2007-12-15 19:39:37 -0500 | [diff] [blame] | 404 | fs->super->s_feature_incompat = feature_incompat; |
Theodore Ts'o | 126a291 | 2007-08-11 01:56:48 -0400 | [diff] [blame] | 405 | #ifdef WORDS_BIGENDIAN |
| 406 | *super_shadow = *fs->super; |
| 407 | ext2fs_swap_super(super_shadow); |
Theodore Ts'o | 0d96104 | 2005-11-12 23:30:39 -0500 | [diff] [blame] | 408 | #endif |
| 409 | |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 410 | if (!(flags & EXT2_FLAG_FLUSH_NO_SYNC)) |
| 411 | retval = io_channel_flush(fs->io); |
Theodore Ts'o | a63d126 | 2004-05-26 21:29:14 -0400 | [diff] [blame] | 412 | retval = write_primary_superblock(fs, super_shadow); |
| 413 | if (retval) |
| 414 | goto errout; |
| 415 | |
Theodore Ts'o | 3c6b897 | 2001-07-10 14:27:58 -0400 | [diff] [blame] | 416 | fs->flags &= ~EXT2_FLAG_DIRTY; |
| 417 | |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 418 | if (!(flags & EXT2_FLAG_FLUSH_NO_SYNC)) |
| 419 | retval = io_channel_flush(fs->io); |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 420 | errout: |
| 421 | fs->super->s_state = fs_state; |
Theodore Ts'o | 126a291 | 2007-08-11 01:56:48 -0400 | [diff] [blame] | 422 | #ifdef WORDS_BIGENDIAN |
| 423 | if (super_shadow) |
| 424 | ext2fs_free_mem(&super_shadow); |
| 425 | if (group_shadow) |
| 426 | ext2fs_free_mem(&group_shadow); |
| 427 | #endif |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 428 | return retval; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 429 | } |
| 430 | |
| 431 | errcode_t ext2fs_close(ext2_filsys fs) |
| 432 | { |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 433 | return ext2fs_close2(fs, 0); |
| 434 | } |
| 435 | |
| 436 | errcode_t ext2fs_close2(ext2_filsys fs, int flags) |
| 437 | { |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 438 | errcode_t retval; |
Theodore Ts'o | b7c5b40 | 2009-03-05 19:40:20 -0500 | [diff] [blame] | 439 | int meta_blks; |
| 440 | io_stats stats = 0; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 441 | |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 442 | EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); |
| 443 | |
Theodore Ts'o | b7c5b40 | 2009-03-05 19:40:20 -0500 | [diff] [blame] | 444 | if (fs->write_bitmaps) { |
| 445 | retval = fs->write_bitmaps(fs); |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 446 | if (retval) |
| 447 | return retval; |
| 448 | } |
Theodore Ts'o | b7c5b40 | 2009-03-05 19:40:20 -0500 | [diff] [blame] | 449 | if (fs->super->s_kbytes_written && |
| 450 | fs->io->manager->get_stats) |
| 451 | fs->io->manager->get_stats(fs->io, &stats); |
| 452 | if (stats && stats->bytes_written && (fs->flags & EXT2_FLAG_RW)) { |
| 453 | fs->super->s_kbytes_written += stats->bytes_written >> 10; |
| 454 | meta_blks = fs->desc_blocks + 1; |
| 455 | if (!(fs->flags & EXT2_FLAG_SUPER_ONLY)) |
| 456 | fs->super->s_kbytes_written += meta_blks / |
| 457 | (fs->blocksize / 1024); |
Theodore Ts'o | 6d67ee3 | 2009-05-02 20:59:04 -0400 | [diff] [blame] | 458 | if ((fs->flags & EXT2_FLAG_DIRTY) == 0) |
| 459 | fs->flags |= EXT2_FLAG_SUPER_ONLY | EXT2_FLAG_DIRTY; |
Theodore Ts'o | b7c5b40 | 2009-03-05 19:40:20 -0500 | [diff] [blame] | 460 | } |
| 461 | if (fs->flags & EXT2_FLAG_DIRTY) { |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 462 | retval = ext2fs_flush2(fs, flags); |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 463 | if (retval) |
| 464 | return retval; |
| 465 | } |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 466 | |
| 467 | retval = ext2fs_mmp_stop(fs); |
| 468 | if (retval) |
| 469 | return retval; |
| 470 | |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 471 | ext2fs_free(fs); |
| 472 | return 0; |
| 473 | } |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 474 | |