1: /*
2: * mkfs.c - make a linux (minix) file-system.
3: *
4: * (C) 1991 Linus Torvalds. This file may be redistributed as per
5: * the Linux copyright.
6: */
7:
8: /*
9: * 24.11.91 - time began. Used the fsck sources to get started.
10: *
11: * 25.11.91 - corrected some bugs. Added support for ".badblocks"
12: * The algorithm for ".badblocks" is a bit weird, but
13: * it should work. Oh, well.
14: *
15: * Usuage: mkfs [-c] device size-in-blocks
16: *
17: * -c for readablility checking (SLOW!)
18: *
19: * The device may be a block device or a image of one, but this isn't
20: * enforced (but it's not much fun on a character device :-).
21: */
22: /*--hgl--该程序用于创建MINIX1.0文件系统(即通常所说的格式化)
23: //--hgl--相当于fdisk
24: //--hgl--主要功能:
25: //--hgl-- 1,建立超级块,位图区域,inode区域和数据区
26: //--hgl-- 2,检测磁盘的坏块
27: --hgl--*/
28:
29: #include <unistd.h>
30: #include <fcntl.h>
31: #include <ctype.h>
32: #include <termios.h>
33: #include <sys/stat.h>
34:
35: #include <linux/fs.h>
36:
37: #ifndef __GNUC__
38: #error "needs gcc for the bitop-__asm__'s"
39: #endif
40:
41: #ifndef __linux__
42: #define volatile
43: #endif
44:
45: #define ROOT_INO 1 //--hgl--根inode号
46: #define BAD_INO 2
47:
48: #define TEST_BUFFER_BLOCKS 32 //--hgl--测试时的步进长度
49: #define MAX_GOOD_BLOCKS 512 //--hgl--
50:
51: #define UPPER(size,n) ((size+((n)-1))/(n)) //--hgl--向上取整
52: #define INODE_SIZE (sizeof(struct d_inode)) //--hgl--
53: #define INODE_BLOCKS UPPER(INODES,INODES_PER_BLOCK)
54: #define INODE_BUFFER_SIZE (INODE_BLOCKS * BLOCK_SIZE) //--hgl--inode区域的大小
55:
56: #define BITS_PER_BLOCK (BLOCK_SIZE<<3) //--hgl--每block的bit数目
57:
58: static char * program_name = "mkfs"; //--hgl--默认的程序名称
59: static char * device_name = NULL;
60: static int DEV = -1; //--hgl--该块设备的文件句柄(其实就是current->filp[]中的下标)
61: static long BLOCKS = 0; //--hgl--逻辑块数目
62: static int check = 0;
63: static int badblocks = 0; //--hgl--坏块的数目
64:
65: #define ROOT_INO_STRING "\001\000" //--hgl--第一数据块位根节点
66: #define BAD_INO_STRING "\002\000" //--hgl--第二数据块位坏块的记录
67:
68: //--hgl--根的目录项
69: static char root_block[BLOCK_SIZE] =
70: ROOT_INO_STRING ".\0\0\0\0\0\0\0\0\0\0\0\0\0"
71: ROOT_INO_STRING "..\0\0\0\0\0\0\0\0\0\0\0\0"
72: BAD_INO_STRING ".badblocks\0\0\0\0";
73:
74: static char * inode_buffer = NULL; //--hgl--inode区域
75: //--hgl--这里减1,可能是因为inode是1为起始的,所以预先减1了
76: #define Inode (((struct d_inode *) inode_buffer)-1)
77: static char super_block_buffer[BLOCK_SIZE];
78: #define Super (*(struct super_block *)super_block_buffer)
79: #define INODES ((unsigned long)Super.s_ninodes) //--hgl--inode数目
80: #define ZONES ((unsigned long)Super.s_nzones) //--hgl--逻辑块总数
81: #define IMAPS ((unsigned long)Super.s_imap_blocks) //--hgl--inode位图的block数目
82: #define ZMAPS ((unsigned long)Super.s_zmap_blocks) //--hgl--逻辑块位图的blk数目
83: #define FIRSTZONE ((unsigned long)Super.s_firstdatazone) //--hgl--第一个数据块的逻辑块号
84: #define ZONESIZE ((unsigned long)Super.s_log_zone_size)
85: #define MAXSIZE ((unsigned long)Super.s_max_size)
86: #define MAGIC (Super.s_magic)
87: //--hgl--2=1+1,boot和sb
88: #define NORM_FIRSTZONE (2+IMAPS+ZMAPS+INODE_BLOCKS) //--hgl--数据区的起始逻辑块号
89:
90: static char inode_map[BLOCK_SIZE * I_MAP_SLOTS]; //--hgl--inode位图
91: static char zone_map[BLOCK_SIZE * Z_MAP_SLOTS]; //--hgl--逻辑块位图
92: //--hgl--因为在格式化的时候,先检测磁盘,如果发现坏块
93: //--hgl--则在blk位图中标记占用,所以正常的逻辑块的使用
94: //--hgl--情况不能在blk位图中标记了,所以就引入good_blocks_table[]
95: //--hgl--来保存正常逻辑块的占用情况
96: static unsigned short good_blocks_table[MAX_GOOD_BLOCKS]; //--hgl--已经使用的逻辑块数组,
97: static int used_good_blocks = 0; //--hgl--已经使用的好的逻辑块
98:
99: #define bitop(name,op) \
100: static inline int name(char * addr,unsigned int nr) \
101: { \
102: int __res; \
103: __asm__ __volatile__("bt" op " %1,%2; adcl $0,%0" \
104: :"=g" (__res) \
105: :"r" (nr),"m" (*(addr)),"0" (0)); \
106: return __res; \
107: }
108:
109: bitop(bit,"")
110: bitop(setbit,"s")
111: bitop(clrbit,"r")
112:
113: #define inode_in_use(x) (bit(inode_map,(x)))
114: #define zone_in_use(x) (bit(zone_map,(x)-FIRSTZONE+1)) //--hgl--询问该位的值
115: //--hgl--标记inode号为x的位图为1
116: #define mark_inode(x) (setbit(inode_map,(x)))
117: #define unmark_inode(x) (clrbit(inode_map,(x)))
118:
119: #define mark_zone(x) (setbit(zone_map,(x)-FIRSTZONE+1))
120: #define unmark_zone(x) (clrbit(zone_map,(x)-FIRSTZONE+1))
121:
122: /*
123: * Volatile to let gcc know that this doesn't return. When trying
124: * to compile this under minix, volatile gives a warning, as
125: * exit() isn't defined as volatile under minix.
126: */
127: volatile void fatal_error(const char * fmt_string)
128: {
129: printf(fmt_string);
130: exit(1);
131: }
132:
133: #define usage() fatal_error("Usage: %s [-c] /dev/name blocks\n")
134: #define die(str) fatal_error(": " str "\n")
135:
136: void write_tables(void)
137: //--hgl--P--将前面的几个过程中建立的buffer 回写到块设备
138: {
139: //--hgl--跳过boot块
140: if (BLOCK_SIZE != lseek(DEV, BLOCK_SIZE, SEEK_SET))
141: die("seek failed in write_tables");
142: //--hgl--填写sb
143: if (BLOCK_SIZE != write(DEV, super_block_buffer, BLOCK_SIZE))
144: die("unable to write super-block");
145: //--hgl--填写inode位图域
146: if (IMAPS*BLOCK_SIZE != write(DEV,inode_map,IMAPS*BLOCK_SIZE))
147: die("Unable to write inode map");
148: //--hgl--填写blk位图域
149: if (ZMAPS*BLOCK_SIZE != write(DEV,zone_map,ZMAPS*BLOCK_SIZE))
150: die("Unable to write zone map");
151: //--hgl--填写inode缓冲区
152: if (INODE_BUFFER_SIZE != write(DEV,inode_buffer,INODE_BUFFER_SIZE))
153: die("Unable to write inodes");
154: }
155: //--hgl--blk 目标逻辑块
156: //--hgl--buffer 源缓冲区
157: void write_block(int blk, char * buffer)
158: //--hgl--P--填写逻辑块
159: //--hgl--???????????????????
160: {
161: //--hgl--因为它是一个应用程序,所以不能
162: //--hgl--将该文件(其实是块设备)的文件指针指向blk
163: if (blk*BLOCK_SIZE != lseek(DEV, blk*BLOCK_SIZE, SEEK_SET))
164: die("seek failed in write_block");
165: //--hgl--
166: if (BLOCK_SIZE != write(DEV, buffer, BLOCK_SIZE))
167: die("write failed in write_block");
168: }
169:
170: int get_free_block(void)
171: //--hgl--P--获得空闲的逻辑块,并在good_block_table中标记该blk已经被使用
172: //--hgl--将正常的逻辑块(但被使用了,不直接标记在inode用,)而是保存在
173: //--hgl--used_good_blocks[]中,因为这时只有坏块才在inode位图中标记,
174: //--hgl--以免混淆
175: {
176: int blk;
177: //--hgl--??????????????好像和坏块的数目没有关系呀
178: if (used_good_blocks+1 >= MAX_GOOD_BLOCKS)
179: die("too many bad blocks");
180: //--hgl--获得查找的起始逻辑块号
181: if (used_good_blocks)
182: blk = good_blocks_table[used_good_blocks-1]+1;
183: else
184: blk = FIRSTZONE;
185: //--hgl--找到没有被占用的blk
186: while (blk < ZONES && zone_in_use(blk))
187: blk++;
188:
189: if (blk >= ZONES)
190: die("not enough good blocks");
191: //--hgl--将该逻辑块号添加到
192: good_blocks_table[used_good_blocks] = blk;
193: used_good_blocks++;
194: return blk;
195: }
196:
197: void mark_good_blocks(void)
198: //--hgl--P--标记已经使用的好的逻辑块(在blk位图中标记)
199: {
200: int blk;
201:
202: for (blk=0 ; blk < used_good_blocks ; blk++)
203: mark_zone(good_blocks_table[blk]);
204: }
205: //--hgl--zone 逻辑块号
206: inline int next(int zone)
207: //--hgl--P--
208: {
209: //--hgl--zone==0表示为第一次搜索
210: if (!zone)
211: zone = FIRSTZONE-1; //--hgl--减1,因为后面是先++zone
212: //--hgl--搜索整个数据区,如果被占用了,则表示是坏块
213: while (++zone < ZONES)
214: if (zone_in_use(zone))
215: return zone;
216: return 0;
217: }
218:
219: void make_bad_inode(void)
220: //--hgl--P--将坏的逻辑块都连接到第二ionde
221: {
222: struct d_inode * inode = &Inode[BAD_INO];
223: int i,j,zone;
224: int ind=0,dind=0;
225: unsigned short ind_block[BLOCK_SIZE>>1];
226: unsigned short dind_block[BLOCK_SIZE>>1];
227:
228: #define NEXT_BAD (zone = next(zone))
229: //--hgl--看是否有坏块
230: if (!badblocks)
231: return;
232: //--hgl--如果有,则占用坏块节点
233: mark_inode(BAD_INO);
234: inode->i_nlinks = 1;
235: inode->i_time = time(NULL);
236: inode->i_mode = S_IFREG + 0000;
237: inode->i_size = badblocks*BLOCK_SIZE; //--hgl--确定坏块文件的大小
238: //--hgl--填写直接块号
239: zone = next(0);
240: for (i=0 ; i<7 ; i++) {
241: inode->i_zone[i] = zone;
242: if (!NEXT_BAD)
243: goto end_bad;
244: }
245: //--hgl--填写一次间接块的缓冲区
246: //--hgl--获得一次间接块
247: inode->i_zone[7] = ind = get_free_block();
248: //--hgl--清空该一次间接块
249: memset(ind_block,0,BLOCK_SIZE);
250: //--hgl--填写一次间接块缓冲区
251: for (i=0 ; i<512 ; i++) {
252: ind_block[i] = zone;
253: if (!NEXT_BAD)
254: goto end_bad;
255: }
256: //--hgl--填写二次间接块
257: inode->i_zone[8] = dind = get_free_block();
258: memset(dind_block,0,BLOCK_SIZE);
259: for (i=0 ; i<512 ; i++) {
260: //--hgl--回写到快设备
261: write_block(ind,(char *) ind_block);
262: //--hgl--
263: dind_block[i] = ind = get_free_block();
264: memset(ind_block,0,BLOCK_SIZE);
265: for (j=0 ; j<512 ; j++) {
266: ind_block[j] = zone;
267: if (!NEXT_BAD)
268: goto end_bad;
269: }
270: }
271: die("too many bad blocks");
272: end_bad:
273: //--hgl--回写到块设备
274: if (ind)
275: write_block(ind, (char *) ind_block);
276: if (dind)
277: write_block(dind, (char *) dind_block);
278: }
279:
280: void make_root_inode(void)
281: //--hgl--P--创建根inode
282: {
283: //--hgl--获得第一个inode,
284: struct d_inode * inode = &Inode[ROOT_INO];
285: //--hgl--标记根inode已经被占用
286: mark_inode(ROOT_INO);
287: //--hgl--填写该inode
288: inode->i_zone[0] = get_free_block();
289: inode->i_nlinks = 2;
290: inode->i_time = time(NULL);
291: //--hgl--确定文件大小
292: if (badblocks)
293: inode->i_size = 48;
294: else
295: inode->i_size = 32;
296: inode->i_mode = S_IFDIR + 0755;
297: //--hgl--填写根inode的目录项
298: write_block(inode->i_zone[0],root_block);
299: }
300:
301: void setup_tables(void)
302: //--hgl--P--填写缓冲区
303: {
304: int i;
305: //--hgl--???????????为何填写0xff(表示都被占用???)
306: //--hgl--它可能是将整个磁盘当成一个大文件,由根inode来控制
307: memset(inode_map,0xff,sizeof(inode_map));
308: memset(zone_map,0xff,sizeof(zone_map));
309: memset(super_block_buffer,0,BLOCK_SIZE);
310: //--hgl--填写超级块
311: MAGIC = SUPER_MAGIC;
312: ZONESIZE = 0;
313: MAXSIZE = (7+512+512*512)*1024;
314: ZONES = BLOCKS;
315: /* some magic nrs: 1 inode / 3 blocks */
316: //--hgl--***block和inode不是1:1的比例*********
317: INODES = BLOCKS/3; //--hgl--inode的数目
318: /* I don't want some off-by-one errors, so this hack... */
319: //--hgl--????????干吗要减去5呢????
320: if ((INODES & 8191) > 8188)
321: INODES -= 5;
322: //--hgl--如果是n块还多几个(<10)个比特,则放弃最后几个比特位
323: if ((INODES & 8191) < 10)
324: INODES -= 20;
325: //--hgl--确定inode位图区域的大小
326: IMAPS = UPPER(INODES,BITS_PER_BLOCK); //--hgl--向上取整
327: //--hgl--确定数据区位图区域的大小
328: ZMAPS = 0;
329: while (ZMAPS != UPPER(BLOCKS - NORM_FIRSTZONE,BITS_PER_BLOCK))
330: ZMAPS = UPPER(BLOCKS - NORM_FIRSTZONE,BITS_PER_BLOCK);
331: FIRSTZONE = NORM_FIRSTZONE;
332: //--hgl--清空位图
333: //--hgl--清空所有数据区位图
334: for (i = FIRSTZONE ; i<ZONES ; i++)
335: unmark_zone(i);
336: //--hgl--清空所有inode位图
337: for (i = ROOT_INO ; i<INODES ; i++)
338: unmark_inode(i);
339: //--hgl--清空inode区域
340: inode_buffer = malloc(INODE_BUFFER_SIZE);
341: if (!inode_buffer)
342: die("Unable to allocate buffer for inodes");
343: memset(inode_buffer,0,INODE_BUFFER_SIZE);
344: //--hgl--打印消息
345: printf("%d inodes\n",INODES);
346: printf("%d blocks\n",ZONES);
347: printf("Firstdatazone=%d (%d)\n",FIRSTZONE,NORM_FIRSTZONE);
348: printf("Zonesize=%d\n",BLOCK_SIZE<<ZONESIZE);
349: printf("Maxsize=%d\n\n",MAXSIZE);
350: }
351:
352: void check_blocks(void)
353: //--hgl--P--统计磁盘的坏块数目,并标记
354: {
355: unsigned int current_block=0; //--hgl--当前的逻辑块号
356: int try,got;
357: static char buffer[BLOCK_SIZE * TEST_BUFFER_BLOCKS];
358:
359: while (current_block < ZONES) {
360: if (lseek(DEV,current_block*BLOCK_SIZE,SEEK_SET) !=
361: current_block*BLOCK_SIZE)
362: die("seek failed in check_blocks");
363: //--hgl--连续读取TEST_BUFFER_BLOCKS长的数据
364: try = TEST_BUFFER_BLOCKS;
365: if (current_block + try > ZONES)
366: try = ZONES-current_block;
367: got = read(DEV, buffer, try * BLOCK_SIZE);
368: //--hgl--看是否被正确的读取
369: if (got<0)
370: got = 0;
371: if (got & (BLOCK_SIZE-1))
372: printf("Weird values in check_blocks: probably bugs\n");
373:
374: got /= BLOCK_SIZE;
375: current_block += got;
376: //--hgl--
377: if (got == try) //--hgl--正确,则终止本次循环
378: continue;
379: if (current_block < FIRSTZONE)
380: die("bad blocks before data-area: cannot make fs");
381: //--hgl--出错,则标志当前块被占用,(以防止该块被使用)
382: //--hgl--?????没有完全标记呀???因为每次测试的块数n(1<n<TEST_BUFFER_BLOCKS)
383:
384: mark_zone(current_block);
385: badblocks++;
386: current_block++;
387: }
388: //--hgl--打印坏块的数目
389: if (badblocks)
390: printf("%d bad block%s\n",badblocks,(badblocks>1)?"s":"");
391: }
392:
393: //--hgl--Usage: mkfs [-c] device size-in-blocks
394: //--hgl--第一个参数为程序名称
395: //--hgl--第二个为设备名
396: //--hgl--第三个为块数目
397: int main(int argc, char ** argv)
398: {
399: char * tmp;
400: struct stat statbuf; //--hgl--inode的状态
401: //--hgl--?????????????
402: if (argc && *argv)
403: program_name = *argv;
404: //--hgl--验证
405: if (INODE_SIZE * INODES_PER_BLOCK != BLOCK_SIZE)
406: die("bad inode size");
407: //--hgl--<>解析参数
408: while (argc-- > 1) {
409: argv++;
410: //--hgl--?????????
411: if (argv[0][0] != '-')
412: if (device_name) {
413: BLOCKS = strtol(argv[0],&tmp,0);
414: if (*tmp)
415: usage();
416: } else
417: device_name = argv[0];
418: //--hgl--如果有参数"-c"
419: else
420: while (*++argv[0])
421: switch (argv[0][0]) {
422: case 'c': check=1; break;
423: default: usage();
424: }
425: }
426: if (!device_name || BLOCKS<10 || BLOCKS > 65536)
427: usage();
428: //--hgl--打开设备device_name ,
429: //--hgl--因为在unix中设备也是当作文件来访问的
430: DEV = open(device_name,O_RDWR);
431: if (DEV<0)
432: die("unable to open %s");
433: //--hgl--获的该文件的inode状态
434: if (fstat(DEV,&statbuf)<0)
435: die("unable to stat %s");
436: //--hgl--检测该设备是否为块设备
437: if (!S_ISBLK(statbuf.st_mode))
438: check=0;
439: else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0305)
440: die("Will not try to make filesystem on '%s'");
441: //--hgl--
442: setup_tables();
443: //--hgl--统计快设备的坏块,并在blk位图中标记
444: if (check)
445: check_blocks();
446: //--hgl--创建根节点(即第一inode)
447: make_root_inode();
448: //--hgl--创建第二inode,将坏块都归为第二inode的数据块,以免被使用
449: make_bad_inode();
450: //--hgl--标记已经被占用的正常的逻辑块
451: mark_good_blocks();
452: //--hgl--回写到快设备
453: write_tables();
454: return 0;
455: }