1 /* vi: set sw=4 ts=4: */
3 * res_gdt.c --- reserve blocks for growing the group descriptor table
4 * during online resizing.
6 * Copyright (C) 2002 Andreas Dilger
9 * This file may be redistributed under the terms of the GNU Public
21 * Iterate through the groups which hold BACKUP superblock/GDT copies in an
22 * ext3 filesystem. The counters should be initialized to 1, 5, and 7 before
23 * calling this for the first time. In a sparse filesystem it will be the
24 * sequence of powers of 3, 5, and 7: 1, 3, 5, 7, 9, 25, 27, 49, 81, ...
25 * For a non-sparse filesystem it will be every group: 1, 2, 3, 4, ...
27 static unsigned int list_backups(ext2_filsys fs
, unsigned int *three
,
28 unsigned int *five
, unsigned int *seven
)
30 unsigned int *min
= three
;
34 if (!(fs
->super
->s_feature_ro_compat
&
35 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER
)) {
57 * This code assumes that the reserved blocks have already been marked in-use
58 * during ext2fs_initialize(), so that they are not allocated for other
59 * uses before we can add them to the resize inode (which has to come
60 * after the creation of the inode table).
62 errcode_t
ext2fs_create_resize_inode(ext2_filsys fs
)
64 errcode_t retval
, retval2
;
65 struct ext2_super_block
*sb
;
66 struct ext2_inode inode
;
67 __u32
*dindir_buf
, *gdt_buf
;
69 unsigned long long apb
, inode_size
;
70 blk_t dindir_blk
, rsv_off
, gdt_off
, gdt_blk
;
71 int dindir_dirty
= 0, inode_dirty
= 0;
73 EXT2_CHECK_MAGIC(fs
, EXT2_ET_MAGIC_EXT2FS_FILSYS
);
77 retval
= ext2fs_get_mem(2 * fs
->blocksize
, (void *)&dindir_buf
);
80 gdt_buf
= (__u32
*)((char *)dindir_buf
+ fs
->blocksize
);
82 retval
= ext2fs_read_inode(fs
, EXT2_RESIZE_INO
, &inode
);
86 /* Maximum possible file size (we donly use the dindirect blocks) */
87 apb
= EXT2_ADDR_PER_BLOCK(sb
);
88 rsv_add
= fs
->blocksize
/ 512;
89 if ((dindir_blk
= inode
.i_block
[EXT2_DIND_BLOCK
])) {
91 printf("reading GDT dindir %u\n", dindir_blk
);
93 retval
= ext2fs_read_ind_block(fs
, dindir_blk
, dindir_buf
);
97 blk_t goal
= 3 + sb
->s_reserved_gdt_blocks
+
98 fs
->desc_blocks
+ fs
->inode_blocks_per_group
;
100 retval
= ext2fs_alloc_block(fs
, goal
, 0, &dindir_blk
);
103 inode
.i_mode
= LINUX_S_IFREG
| 0600;
104 inode
.i_links_count
= 1;
105 inode
.i_block
[EXT2_DIND_BLOCK
] = dindir_blk
;
106 inode
.i_blocks
= rsv_add
;
107 memset(dindir_buf
, 0, fs
->blocksize
);
109 printf("allocated GDT dindir %u\n", dindir_blk
);
111 dindir_dirty
= inode_dirty
= 1;
112 inode_size
= apb
*apb
+ apb
+ EXT2_NDIR_BLOCKS
;
113 inode_size
*= fs
->blocksize
;
114 inode
.i_size
= inode_size
& 0xFFFFFFFF;
115 inode
.i_size_high
= (inode_size
>> 32) & 0xFFFFFFFF;
116 if (inode
.i_size_high
) {
117 sb
->s_feature_ro_compat
|=
118 EXT2_FEATURE_RO_COMPAT_LARGE_FILE
;
120 inode
.i_ctime
= time(NULL
);
123 for (rsv_off
= 0, gdt_off
= fs
->desc_blocks
,
124 gdt_blk
= sb
->s_first_data_block
+ 1 + fs
->desc_blocks
;
125 rsv_off
< sb
->s_reserved_gdt_blocks
;
126 rsv_off
++, gdt_off
++, gdt_blk
++) {
127 unsigned int three
= 1, five
= 5, seven
= 7;
128 unsigned int grp
, last
= 0;
132 if (!dindir_buf
[gdt_off
]) {
136 retval = ext2fs_new_block(fs, gdt_blk, 0, &new_blk);
139 if (new_blk != gdt_blk) {
144 gdt_dirty
= dindir_dirty
= inode_dirty
= 1;
145 memset(gdt_buf
, 0, fs
->blocksize
);
146 dindir_buf
[gdt_off
] = gdt_blk
;
147 inode
.i_blocks
+= rsv_add
;
149 printf("added primary GDT block %u at %u[%u]\n",
150 gdt_blk
, dindir_blk
, gdt_off
);
152 } else if (dindir_buf
[gdt_off
] == gdt_blk
) {
154 printf("reading primary GDT block %u\n", gdt_blk
);
156 retval
= ext2fs_read_ind_block(fs
, gdt_blk
, gdt_buf
);
161 printf("bad primary GDT %u != %u at %u[%u]\n",
162 dindir_buf
[gdt_off
], gdt_blk
,dindir_blk
,gdt_off
);
164 retval
= EXT2_ET_RESIZE_INODE_CORRUPT
;
168 while ((grp
= list_backups(fs
, &three
, &five
, &seven
)) <
169 fs
->group_desc_count
) {
170 blk_t expect
= gdt_blk
+ grp
* sb
->s_blocks_per_group
;
172 if (!gdt_buf
[last
]) {
174 printf("added backup GDT %u grp %u@%u[%u]\n",
175 expect
, grp
, gdt_blk
, last
);
177 gdt_buf
[last
] = expect
;
178 inode
.i_blocks
+= rsv_add
;
179 gdt_dirty
= inode_dirty
= 1;
180 } else if (gdt_buf
[last
] != expect
) {
182 printf("bad backup GDT %u != %u at %u[%u]\n",
183 gdt_buf
[last
], expect
, gdt_blk
, last
);
185 retval
= EXT2_ET_RESIZE_INODE_CORRUPT
;
192 printf("writing primary GDT block %u\n", gdt_blk
);
194 retval
= ext2fs_write_ind_block(fs
, gdt_blk
, gdt_buf
);
202 retval2
= ext2fs_write_ind_block(fs
, dindir_blk
, dindir_buf
);
208 printf("inode.i_blocks = %u, i_size = %u\n", inode
.i_blocks
,
212 inode
.i_atime
= inode
.i_mtime
= time(NULL
);
213 retval2
= ext2fs_write_inode(fs
, EXT2_RESIZE_INO
, &inode
);
218 ext2fs_free_mem((void *)&dindir_buf
);