closefs.c revision d323f8fb369089b97d6f3bf0f8d64ceeab0b10f5
1/* 2 * closefs.c --- close an ext2 filesystem 3 * 4 * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. 5 * 6 * %Begin-Header% 7 * This file may be redistributed under the terms of the GNU Public 8 * License. 9 * %End-Header% 10 */ 11 12#include <stdio.h> 13#if HAVE_UNISTD_H 14#include <unistd.h> 15#endif 16#include <time.h> 17#include <string.h> 18 19#include "ext2_fs.h" 20#include "ext2fsP.h" 21 22int ext2fs_super_and_bgd_loc(ext2_filsys fs, 23 dgrp_t group, 24 blk_t *ret_super_blk, 25 blk_t *ret_old_desc_blk, 26 blk_t *ret_new_desc_blk, 27 int *ret_meta_bg) 28{ 29 blk_t group_block, super_blk = 0, old_desc_blk = 0, new_desc_blk = 0; 30 unsigned int meta_bg, meta_bg_size; 31 int numblocks, has_super; 32 int old_desc_blocks; 33 34 group_block = fs->super->s_first_data_block + 35 (group * fs->super->s_blocks_per_group); 36 37 if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) 38 old_desc_blocks = fs->super->s_first_meta_bg; 39 else 40 old_desc_blocks = 41 fs->desc_blocks + fs->super->s_reserved_gdt_blocks; 42 43 if (group == fs->group_desc_count-1) { 44 numblocks = (fs->super->s_blocks_count - 45 fs->super->s_first_data_block) % 46 fs->super->s_blocks_per_group; 47 if (!numblocks) 48 numblocks = fs->super->s_blocks_per_group; 49 } else 50 numblocks = fs->super->s_blocks_per_group; 51 52 has_super = ext2fs_bg_has_super(fs, group); 53 54 if (has_super) { 55 super_blk = group_block; 56 numblocks--; 57 } 58 meta_bg_size = (fs->blocksize / sizeof (struct ext2_group_desc)); 59 meta_bg = group / meta_bg_size; 60 61 if (!(fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) || 62 (meta_bg < fs->super->s_first_meta_bg)) { 63 if (has_super) { 64 old_desc_blk = group_block + 1; 65 numblocks -= old_desc_blocks; 66 } 67 } else { 68 if (((group % meta_bg_size) == 0) || 69 ((group % meta_bg_size) == 1) || 70 ((group % meta_bg_size) == (meta_bg_size-1))) { 71 if (has_super) 72 has_super = 1; 73 new_desc_blk = group_block + has_super; 74 numblocks--; 75 } 76 } 77 78 numblocks -= 2 + fs->inode_blocks_per_group; 79 80 if (ret_super_blk) 81 *ret_super_blk = super_blk; 82 if (ret_old_desc_blk) 83 *ret_old_desc_blk = old_desc_blk; 84 if (ret_new_desc_blk) 85 *ret_new_desc_blk = new_desc_blk; 86 if (ret_meta_bg) 87 *ret_meta_bg = meta_bg; 88 return (numblocks); 89} 90 91 92/* 93 * This function forces out the primary superblock. We need to only 94 * write out those fields which we have changed, since if the 95 * filesystem is mounted, it may have changed some of the other 96 * fields. 97 * 98 * It takes as input a superblock which has already been byte swapped 99 * (if necessary). 100 * 101 */ 102static errcode_t write_primary_superblock(ext2_filsys fs, 103 struct ext2_super_block *super) 104{ 105 __u16 *old_super, *new_super; 106 int check_idx, write_idx, size; 107 errcode_t retval; 108 109 if (!fs->io->manager->write_byte || !fs->orig_super) { 110 io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET); 111 retval = io_channel_write_blk(fs->io, 1, -SUPERBLOCK_SIZE, 112 super); 113 io_channel_set_blksize(fs->io, fs->blocksize); 114 return retval; 115 } 116 117 old_super = (__u16 *) fs->orig_super; 118 new_super = (__u16 *) super; 119 120 for (check_idx = 0; check_idx < SUPERBLOCK_SIZE/2; check_idx++) { 121 if (old_super[check_idx] == new_super[check_idx]) 122 continue; 123 write_idx = check_idx; 124 for (check_idx++; check_idx < SUPERBLOCK_SIZE/2; check_idx++) 125 if (old_super[check_idx] == new_super[check_idx]) 126 break; 127 size = 2 * (check_idx - write_idx); 128#if 0 129 printf("Writing %d bytes starting at %d\n", 130 size, write_idx*2); 131#endif 132 retval = io_channel_write_byte(fs->io, 133 SUPERBLOCK_OFFSET + (2 * write_idx), size, 134 new_super + write_idx); 135 if (retval) 136 return retval; 137 } 138 memcpy(fs->orig_super, super, SUPERBLOCK_SIZE); 139 return 0; 140} 141 142 143/* 144 * Updates the revision to EXT2_DYNAMIC_REV 145 */ 146void ext2fs_update_dynamic_rev(ext2_filsys fs) 147{ 148 struct ext2_super_block *sb = fs->super; 149 150 if (sb->s_rev_level > EXT2_GOOD_OLD_REV) 151 return; 152 153 sb->s_rev_level = EXT2_DYNAMIC_REV; 154 sb->s_first_ino = EXT2_GOOD_OLD_FIRST_INO; 155 sb->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE; 156 /* s_uuid is handled by e2fsck already */ 157 /* other fields should be left alone */ 158} 159 160static errcode_t write_backup_super(ext2_filsys fs, dgrp_t group, 161 blk_t group_block, 162 struct ext2_super_block *super_shadow) 163{ 164 dgrp_t sgrp = group; 165 166 if (sgrp > ((1 << 16) - 1)) 167 sgrp = (1 << 16) - 1; 168#ifdef EXT2FS_ENABLE_SWAPFS 169 if (fs->flags & EXT2_FLAG_SWAP_BYTES) 170 super_shadow->s_block_group_nr = ext2fs_swab16(sgrp); 171 else 172#endif 173 fs->super->s_block_group_nr = sgrp; 174 175 return io_channel_write_blk(fs->io, group_block, -SUPERBLOCK_SIZE, 176 super_shadow); 177} 178 179 180errcode_t ext2fs_flush(ext2_filsys fs) 181{ 182 dgrp_t i,j; 183 blk_t group_block; 184 errcode_t retval; 185 unsigned long fs_state; 186 struct ext2_super_block *super_shadow = 0; 187 struct ext2_group_desc *group_shadow = 0; 188 struct ext2_group_desc *s, *t; 189 char *group_ptr; 190 int old_desc_blocks; 191 192 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 193 194 fs_state = fs->super->s_state; 195 196 fs->super->s_wtime = time(NULL); 197 fs->super->s_block_group_nr = 0; 198#ifdef EXT2FS_ENABLE_SWAPFS 199 if (fs->flags & EXT2_FLAG_SWAP_BYTES) { 200 retval = EXT2_ET_NO_MEMORY; 201 retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &super_shadow); 202 if (retval) 203 goto errout; 204 retval = ext2fs_get_mem((size_t)(fs->blocksize * 205 fs->desc_blocks), 206 &group_shadow); 207 if (retval) 208 goto errout; 209 memset(group_shadow, 0, (size_t) fs->blocksize * 210 fs->desc_blocks); 211 212 /* swap the group descriptors */ 213 for (j=0, s=fs->group_desc, t=group_shadow; 214 j < fs->group_desc_count; j++, t++, s++) { 215 *t = *s; 216 ext2fs_swap_group_desc(t); 217 } 218 } else { 219 super_shadow = fs->super; 220 group_shadow = fs->group_desc; 221 } 222#else 223 super_shadow = fs->super; 224 group_shadow = fs->group_desc; 225#endif 226 227 /* 228 * If this is an external journal device, don't write out the 229 * block group descriptors or any of the backup superblocks 230 */ 231 if (fs->super->s_feature_incompat & 232 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) 233 goto write_primary_superblock_only; 234 235 /* 236 * Set the state of the FS to be non-valid. (The state has 237 * already been backed up earlier, and will be restored after 238 * we write out the backup superblocks.) 239 */ 240 fs->super->s_state &= ~EXT2_VALID_FS; 241#ifdef EXT2FS_ENABLE_SWAPFS 242 if (fs->flags & EXT2_FLAG_SWAP_BYTES) { 243 *super_shadow = *fs->super; 244 ext2fs_swap_super(super_shadow); 245 } 246#endif 247 248 /* 249 * Write out the master group descriptors, and the backup 250 * superblocks and group descriptors. 251 */ 252 group_block = fs->super->s_first_data_block; 253 group_ptr = (char *) group_shadow; 254 if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) 255 old_desc_blocks = fs->super->s_first_meta_bg; 256 else 257 old_desc_blocks = fs->desc_blocks; 258 259 for (i = 0; i < fs->group_desc_count; i++) { 260 blk_t super_blk, old_desc_blk, new_desc_blk; 261 int meta_bg; 262 263 ext2fs_super_and_bgd_loc(fs, i, &super_blk, &old_desc_blk, 264 &new_desc_blk, &meta_bg); 265 266 if (!(fs->flags & EXT2_FLAG_MASTER_SB_ONLY) &&i && super_blk) { 267 retval = write_backup_super(fs, i, super_blk, 268 super_shadow); 269 if (retval) 270 goto errout; 271 } 272 if (fs->flags & EXT2_FLAG_SUPER_ONLY) 273 continue; 274 if ((old_desc_blk) && 275 (!(fs->flags & EXT2_FLAG_MASTER_SB_ONLY) || (i == 0))) { 276 retval = io_channel_write_blk(fs->io, 277 old_desc_blk, old_desc_blocks, group_ptr); 278 if (retval) 279 goto errout; 280 } 281 if (new_desc_blk) { 282 retval = io_channel_write_blk(fs->io, new_desc_blk, 283 1, group_ptr + (meta_bg*fs->blocksize)); 284 if (retval) 285 goto errout; 286 } 287 } 288 fs->super->s_block_group_nr = 0; 289 fs->super->s_state = fs_state; 290#ifdef EXT2FS_ENABLE_SWAPFS 291 if (fs->flags & EXT2_FLAG_SWAP_BYTES) { 292 *super_shadow = *fs->super; 293 ext2fs_swap_super(super_shadow); 294 } 295#endif 296 297 /* 298 * If the write_bitmaps() function is present, call it to 299 * flush the bitmaps. This is done this way so that a simple 300 * program that doesn't mess with the bitmaps doesn't need to 301 * drag in the bitmaps.c code. 302 */ 303 if (fs->write_bitmaps) { 304 retval = fs->write_bitmaps(fs); 305 if (retval) 306 goto errout; 307 } 308 309write_primary_superblock_only: 310 /* 311 * Write out master superblock. This has to be done 312 * separately, since it is located at a fixed location 313 * (SUPERBLOCK_OFFSET). We flush all other pending changes 314 * out to disk first, just to avoid a race condition with an 315 * insy-tinsy window.... 316 */ 317 retval = io_channel_flush(fs->io); 318 retval = write_primary_superblock(fs, super_shadow); 319 if (retval) 320 goto errout; 321 322 fs->flags &= ~EXT2_FLAG_DIRTY; 323 324 retval = io_channel_flush(fs->io); 325errout: 326 fs->super->s_state = fs_state; 327 if (fs->flags & EXT2_FLAG_SWAP_BYTES) { 328 if (super_shadow) 329 ext2fs_free_mem(&super_shadow); 330 if (group_shadow) 331 ext2fs_free_mem(&group_shadow); 332 } 333 return retval; 334} 335 336errcode_t ext2fs_close(ext2_filsys fs) 337{ 338 errcode_t retval; 339 340 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 341 342 if (fs->flags & EXT2_FLAG_DIRTY) { 343 retval = ext2fs_flush(fs); 344 if (retval) 345 return retval; 346 } 347 if (fs->write_bitmaps) { 348 retval = fs->write_bitmaps(fs); 349 if (retval) 350 return retval; 351 } 352 ext2fs_free(fs); 353 return 0; 354} 355 356