1 /* vi: set sw=4 ts=4: */
3 * closefs.c --- close an ext2 filesystem
5 * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
8 * This file may be redistributed under the terms of the GNU Public
23 static int test_root(int a
, int b
)
36 int ext2fs_bg_has_super(ext2_filsys fs
, int group_block
)
38 if (!(fs
->super
->s_feature_ro_compat
&
39 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER
))
42 if (test_root(group_block
, 3) || (test_root(group_block
, 5)) ||
43 test_root(group_block
, 7))
49 int ext2fs_super_and_bgd_loc(ext2_filsys fs
,
52 blk_t
*ret_old_desc_blk
,
53 blk_t
*ret_new_desc_blk
,
56 blk_t group_block
, super_blk
= 0, old_desc_blk
= 0, new_desc_blk
= 0;
57 unsigned int meta_bg
, meta_bg_size
;
58 int numblocks
, has_super
;
61 group_block
= fs
->super
->s_first_data_block
+
62 (group
* fs
->super
->s_blocks_per_group
);
64 if (fs
->super
->s_feature_incompat
& EXT2_FEATURE_INCOMPAT_META_BG
)
65 old_desc_blocks
= fs
->super
->s_first_meta_bg
;
68 fs
->desc_blocks
+ fs
->super
->s_reserved_gdt_blocks
;
70 if (group
== fs
->group_desc_count
-1) {
71 numblocks
= (fs
->super
->s_blocks_count
-
72 fs
->super
->s_first_data_block
) %
73 fs
->super
->s_blocks_per_group
;
75 numblocks
= fs
->super
->s_blocks_per_group
;
77 numblocks
= fs
->super
->s_blocks_per_group
;
79 has_super
= ext2fs_bg_has_super(fs
, group
);
82 super_blk
= group_block
;
85 meta_bg_size
= (fs
->blocksize
/ sizeof (struct ext2_group_desc
));
86 meta_bg
= group
/ meta_bg_size
;
88 if (!(fs
->super
->s_feature_incompat
& EXT2_FEATURE_INCOMPAT_META_BG
) ||
89 (meta_bg
< fs
->super
->s_first_meta_bg
)) {
91 old_desc_blk
= group_block
+ 1;
92 numblocks
-= old_desc_blocks
;
95 if (((group
% meta_bg_size
) == 0) ||
96 ((group
% meta_bg_size
) == 1) ||
97 ((group
% meta_bg_size
) == (meta_bg_size
-1))) {
100 new_desc_blk
= group_block
+ has_super
;
105 numblocks
-= 2 + fs
->inode_blocks_per_group
;
108 *ret_super_blk
= super_blk
;
109 if (ret_old_desc_blk
)
110 *ret_old_desc_blk
= old_desc_blk
;
111 if (ret_new_desc_blk
)
112 *ret_new_desc_blk
= new_desc_blk
;
114 *ret_meta_bg
= meta_bg
;
120 * This function forces out the primary superblock. We need to only
121 * write out those fields which we have changed, since if the
122 * filesystem is mounted, it may have changed some of the other
125 * It takes as input a superblock which has already been byte swapped
129 static errcode_t
write_primary_superblock(ext2_filsys fs
,
130 struct ext2_super_block
*super
)
132 __u16
*old_super
, *new_super
;
133 int check_idx
, write_idx
, size
;
136 if (!fs
->io
->manager
->write_byte
|| !fs
->orig_super
) {
137 io_channel_set_blksize(fs
->io
, SUPERBLOCK_OFFSET
);
138 retval
= io_channel_write_blk(fs
->io
, 1, -SUPERBLOCK_SIZE
,
140 io_channel_set_blksize(fs
->io
, fs
->blocksize
);
144 old_super
= (__u16
*) fs
->orig_super
;
145 new_super
= (__u16
*) super
;
147 for (check_idx
= 0; check_idx
< SUPERBLOCK_SIZE
/2; check_idx
++) {
148 if (old_super
[check_idx
] == new_super
[check_idx
])
150 write_idx
= check_idx
;
151 for (check_idx
++; check_idx
< SUPERBLOCK_SIZE
/2; check_idx
++)
152 if (old_super
[check_idx
] == new_super
[check_idx
])
154 size
= 2 * (check_idx
- write_idx
);
155 retval
= io_channel_write_byte(fs
->io
,
156 SUPERBLOCK_OFFSET
+ (2 * write_idx
), size
,
157 new_super
+ write_idx
);
161 memcpy(fs
->orig_super
, super
, SUPERBLOCK_SIZE
);
167 * Updates the revision to EXT2_DYNAMIC_REV
169 void ext2fs_update_dynamic_rev(ext2_filsys fs
)
171 struct ext2_super_block
*sb
= fs
->super
;
173 if (sb
->s_rev_level
> EXT2_GOOD_OLD_REV
)
176 sb
->s_rev_level
= EXT2_DYNAMIC_REV
;
177 sb
->s_first_ino
= EXT2_GOOD_OLD_FIRST_INO
;
178 sb
->s_inode_size
= EXT2_GOOD_OLD_INODE_SIZE
;
179 /* s_uuid is handled by e2fsck already */
180 /* other fields should be left alone */
183 static errcode_t
write_backup_super(ext2_filsys fs
, dgrp_t group
,
185 struct ext2_super_block
*super_shadow
)
189 if (sgrp
> ((1 << 16) - 1))
190 sgrp
= (1 << 16) - 1;
192 if (fs
->flags
& EXT2_FLAG_SWAP_BYTES
)
193 super_shadow
->s_block_group_nr
= ext2fs_swab16(sgrp
);
196 fs
->super
->s_block_group_nr
= sgrp
;
198 return io_channel_write_blk(fs
->io
, group_block
, -SUPERBLOCK_SIZE
,
203 errcode_t
ext2fs_flush(ext2_filsys fs
)
208 unsigned long fs_state
;
209 struct ext2_super_block
*super_shadow
= NULL
;
210 struct ext2_group_desc
*group_shadow
= NULL
;
215 struct ext2_group_desc
*s
, *t
;
218 EXT2_CHECK_MAGIC(fs
, EXT2_ET_MAGIC_EXT2FS_FILSYS
);
220 fs_state
= fs
->super
->s_state
;
222 fs
->super
->s_wtime
= time(NULL
);
223 fs
->super
->s_block_group_nr
= 0;
225 if (fs
->flags
& EXT2_FLAG_SWAP_BYTES
) {
226 retval
= EXT2_ET_NO_MEMORY
;
227 retval
= ext2fs_get_mem(SUPERBLOCK_SIZE
, &super_shadow
);
230 retval
= ext2fs_get_mem((size_t)(fs
->blocksize
*
235 memset(group_shadow
, 0, (size_t) fs
->blocksize
*
238 /* swap the group descriptors */
239 for (j
=0, s
=fs
->group_desc
, t
=group_shadow
;
240 j
< fs
->group_desc_count
; j
++, t
++, s
++) {
242 ext2fs_swap_group_desc(t
);
245 super_shadow
= fs
->super
;
246 group_shadow
= fs
->group_desc
;
249 super_shadow
= fs
->super
;
250 group_shadow
= fs
->group_desc
;
254 * If this is an external journal device, don't write out the
255 * block group descriptors or any of the backup superblocks
257 if (fs
->super
->s_feature_incompat
&
258 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV
)
259 goto write_primary_superblock_only
;
262 * Set the state of the FS to be non-valid. (The state has
263 * already been backed up earlier, and will be restored after
264 * we write out the backup superblocks.)
266 fs
->super
->s_state
&= ~EXT2_VALID_FS
;
268 if (fs
->flags
& EXT2_FLAG_SWAP_BYTES
) {
269 *super_shadow
= *fs
->super
;
270 ext2fs_swap_super(super_shadow
);
275 * Write out the master group descriptors, and the backup
276 * superblocks and group descriptors.
278 group_block
= fs
->super
->s_first_data_block
;
279 group_ptr
= (char *) group_shadow
;
280 if (fs
->super
->s_feature_incompat
& EXT2_FEATURE_INCOMPAT_META_BG
)
281 old_desc_blocks
= fs
->super
->s_first_meta_bg
;
283 old_desc_blocks
= fs
->desc_blocks
;
285 for (i
= 0; i
< fs
->group_desc_count
; i
++) {
286 blk_t super_blk
, old_desc_blk
, new_desc_blk
;
289 ext2fs_super_and_bgd_loc(fs
, i
, &super_blk
, &old_desc_blk
,
290 &new_desc_blk
, &meta_bg
);
292 if (!(fs
->flags
& EXT2_FLAG_MASTER_SB_ONLY
) &&i
&& super_blk
) {
293 retval
= write_backup_super(fs
, i
, super_blk
,
298 if (fs
->flags
& EXT2_FLAG_SUPER_ONLY
)
300 if ((old_desc_blk
) &&
301 (!(fs
->flags
& EXT2_FLAG_MASTER_SB_ONLY
) || (i
== 0))) {
302 retval
= io_channel_write_blk(fs
->io
,
303 old_desc_blk
, old_desc_blocks
, group_ptr
);
308 retval
= io_channel_write_blk(fs
->io
, new_desc_blk
,
309 1, group_ptr
+ (meta_bg
*fs
->blocksize
));
314 fs
->super
->s_block_group_nr
= 0;
315 fs
->super
->s_state
= fs_state
;
317 if (fs
->flags
& EXT2_FLAG_SWAP_BYTES
) {
318 *super_shadow
= *fs
->super
;
319 ext2fs_swap_super(super_shadow
);
324 * If the write_bitmaps() function is present, call it to
325 * flush the bitmaps. This is done this way so that a simple
326 * program that doesn't mess with the bitmaps doesn't need to
327 * drag in the bitmaps.c code.
329 if (fs
->write_bitmaps
) {
330 retval
= fs
->write_bitmaps(fs
);
335 write_primary_superblock_only
:
337 * Write out master superblock. This has to be done
338 * separately, since it is located at a fixed location
339 * (SUPERBLOCK_OFFSET). We flush all other pending changes
340 * out to disk first, just to avoid a race condition with an
341 * insy-tinsy window....
343 retval
= io_channel_flush(fs
->io
);
344 retval
= write_primary_superblock(fs
, super_shadow
);
348 fs
->flags
&= ~EXT2_FLAG_DIRTY
;
350 retval
= io_channel_flush(fs
->io
);
352 fs
->super
->s_state
= fs_state
;
353 if (fs
->flags
& EXT2_FLAG_SWAP_BYTES
) {
355 ext2fs_free_mem(&super_shadow
);
357 ext2fs_free_mem(&group_shadow
);
362 errcode_t
ext2fs_close(ext2_filsys fs
)
366 EXT2_CHECK_MAGIC(fs
, EXT2_ET_MAGIC_EXT2FS_FILSYS
);
368 if (fs
->flags
& EXT2_FLAG_DIRTY
) {
369 retval
= ext2fs_flush(fs
);
373 if (fs
->write_bitmaps
) {
374 retval
= fs
->write_bitmaps(fs
);