Annotation of /trunk/mkinitrd-magellan/busybox/e2fsprogs/old_e2fsprogs/ext2fs/res_gdt.c
Parent Directory | Revision Log
Revision 816 -
(hide annotations)
(download)
Fri Apr 24 18:33:46 2009 UTC (15 years, 1 month ago) by niro
File MIME type: text/plain
File size: 5896 byte(s)
Fri Apr 24 18:33:46 2009 UTC (15 years, 1 month ago) by niro
File MIME type: text/plain
File size: 5896 byte(s)
-updated to busybox-1.13.4
1 | niro | 532 | /* vi: set sw=4 ts=4: */ |
2 | /* | ||
3 | * res_gdt.c --- reserve blocks for growing the group descriptor table | ||
4 | * during online resizing. | ||
5 | * | ||
6 | * Copyright (C) 2002 Andreas Dilger | ||
7 | * | ||
8 | * %Begin-Header% | ||
9 | * This file may be redistributed under the terms of the GNU Public | ||
10 | * License. | ||
11 | * %End-Header% | ||
12 | */ | ||
13 | |||
14 | #include <stdio.h> | ||
15 | #include <string.h> | ||
16 | #include <time.h> | ||
17 | #include "ext2_fs.h" | ||
18 | #include "ext2fs.h" | ||
19 | |||
20 | /* | ||
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, ... | ||
26 | */ | ||
27 | static unsigned int list_backups(ext2_filsys fs, unsigned int *three, | ||
28 | unsigned int *five, unsigned int *seven) | ||
29 | { | ||
30 | unsigned int *min = three; | ||
31 | int mult = 3; | ||
32 | unsigned int ret; | ||
33 | |||
34 | if (!(fs->super->s_feature_ro_compat & | ||
35 | EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)) { | ||
36 | ret = *min; | ||
37 | *min += 1; | ||
38 | return ret; | ||
39 | } | ||
40 | |||
41 | if (*five < *min) { | ||
42 | min = five; | ||
43 | mult = 5; | ||
44 | } | ||
45 | if (*seven < *min) { | ||
46 | min = seven; | ||
47 | mult = 7; | ||
48 | } | ||
49 | |||
50 | ret = *min; | ||
51 | *min *= mult; | ||
52 | |||
53 | return ret; | ||
54 | } | ||
55 | |||
56 | /* | ||
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). | ||
61 | */ | ||
62 | errcode_t ext2fs_create_resize_inode(ext2_filsys fs) | ||
63 | { | ||
64 | errcode_t retval, retval2; | ||
65 | struct ext2_super_block *sb; | ||
66 | struct ext2_inode inode; | ||
67 | __u32 *dindir_buf, *gdt_buf; | ||
68 | int rsv_add; | ||
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; | ||
72 | |||
73 | EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); | ||
74 | |||
75 | sb = fs->super; | ||
76 | |||
77 | retval = ext2fs_get_mem(2 * fs->blocksize, (void *)&dindir_buf); | ||
78 | if (retval) | ||
79 | goto out_free; | ||
80 | gdt_buf = (__u32 *)((char *)dindir_buf + fs->blocksize); | ||
81 | |||
82 | retval = ext2fs_read_inode(fs, EXT2_RESIZE_INO, &inode); | ||
83 | if (retval) | ||
84 | goto out_free; | ||
85 | |||
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])) { | ||
90 | #ifdef RES_GDT_DEBUG | ||
91 | printf("reading GDT dindir %u\n", dindir_blk); | ||
92 | #endif | ||
93 | retval = ext2fs_read_ind_block(fs, dindir_blk, dindir_buf); | ||
94 | if (retval) | ||
95 | goto out_inode; | ||
96 | } else { | ||
97 | blk_t goal = 3 + sb->s_reserved_gdt_blocks + | ||
98 | fs->desc_blocks + fs->inode_blocks_per_group; | ||
99 | |||
100 | retval = ext2fs_alloc_block(fs, goal, 0, &dindir_blk); | ||
101 | if (retval) | ||
102 | goto out_free; | ||
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); | ||
108 | #ifdef RES_GDT_DEBUG | ||
109 | printf("allocated GDT dindir %u\n", dindir_blk); | ||
110 | #endif | ||
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 | niro | 816 | if (inode.i_size_high) { |
117 | niro | 532 | sb->s_feature_ro_compat |= |
118 | EXT2_FEATURE_RO_COMPAT_LARGE_FILE; | ||
119 | } | ||
120 | inode.i_ctime = time(0); | ||
121 | } | ||
122 | |||
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; | ||
129 | int gdt_dirty = 0; | ||
130 | |||
131 | gdt_off %= apb; | ||
132 | if (!dindir_buf[gdt_off]) { | ||
133 | /* FIXME XXX XXX | ||
134 | blk_t new_blk; | ||
135 | |||
136 | retval = ext2fs_new_block(fs, gdt_blk, 0, &new_blk); | ||
137 | if (retval) | ||
138 | goto out_free; | ||
139 | if (new_blk != gdt_blk) { | ||
140 | // XXX free block | ||
141 | retval = -1; // XXX | ||
142 | } | ||
143 | */ | ||
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; | ||
148 | #ifdef RES_GDT_DEBUG | ||
149 | printf("added primary GDT block %u at %u[%u]\n", | ||
150 | gdt_blk, dindir_blk, gdt_off); | ||
151 | #endif | ||
152 | } else if (dindir_buf[gdt_off] == gdt_blk) { | ||
153 | #ifdef RES_GDT_DEBUG | ||
154 | printf("reading primary GDT block %u\n", gdt_blk); | ||
155 | #endif | ||
156 | retval = ext2fs_read_ind_block(fs, gdt_blk, gdt_buf); | ||
157 | if (retval) | ||
158 | goto out_dindir; | ||
159 | } else { | ||
160 | #ifdef RES_GDT_DEBUG | ||
161 | printf("bad primary GDT %u != %u at %u[%u]\n", | ||
162 | dindir_buf[gdt_off], gdt_blk,dindir_blk,gdt_off); | ||
163 | #endif | ||
164 | retval = EXT2_ET_RESIZE_INODE_CORRUPT; | ||
165 | goto out_dindir; | ||
166 | } | ||
167 | |||
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; | ||
171 | |||
172 | if (!gdt_buf[last]) { | ||
173 | #ifdef RES_GDT_DEBUG | ||
174 | printf("added backup GDT %u grp %u@%u[%u]\n", | ||
175 | expect, grp, gdt_blk, last); | ||
176 | #endif | ||
177 | gdt_buf[last] = expect; | ||
178 | inode.i_blocks += rsv_add; | ||
179 | gdt_dirty = inode_dirty = 1; | ||
180 | } else if (gdt_buf[last] != expect) { | ||
181 | #ifdef RES_GDT_DEBUG | ||
182 | printf("bad backup GDT %u != %u at %u[%u]\n", | ||
183 | gdt_buf[last], expect, gdt_blk, last); | ||
184 | #endif | ||
185 | retval = EXT2_ET_RESIZE_INODE_CORRUPT; | ||
186 | goto out_dindir; | ||
187 | } | ||
188 | last++; | ||
189 | } | ||
190 | if (gdt_dirty) { | ||
191 | #ifdef RES_GDT_DEBUG | ||
192 | printf("writing primary GDT block %u\n", gdt_blk); | ||
193 | #endif | ||
194 | retval = ext2fs_write_ind_block(fs, gdt_blk, gdt_buf); | ||
195 | if (retval) | ||
196 | goto out_dindir; | ||
197 | } | ||
198 | } | ||
199 | |||
200 | out_dindir: | ||
201 | if (dindir_dirty) { | ||
202 | retval2 = ext2fs_write_ind_block(fs, dindir_blk, dindir_buf); | ||
203 | if (!retval) | ||
204 | retval = retval2; | ||
205 | } | ||
206 | out_inode: | ||
207 | #ifdef RES_GDT_DEBUG | ||
208 | printf("inode.i_blocks = %u, i_size = %u\n", inode.i_blocks, | ||
209 | inode.i_size); | ||
210 | #endif | ||
211 | if (inode_dirty) { | ||
212 | inode.i_atime = inode.i_mtime = time(0); | ||
213 | retval2 = ext2fs_write_inode(fs, EXT2_RESIZE_INO, &inode); | ||
214 | if (!retval) | ||
215 | retval = retval2; | ||
216 | } | ||
217 | out_free: | ||
218 | ext2fs_free_mem((void *)&dindir_buf); | ||
219 | return retval; | ||
220 | } | ||
221 |