xref: /inferno-os/liblogfs/format.c (revision d3641b487cf5cdc46e9b537d30eb37736e5c7b1a)
1 #include "logfsos.h"
2 #include "logfs.h"
3 #include "local.h"
4 
5 char *
6 logfsformat(LogfsLowLevel *ll, long base, long limit, long bootsize, int trace)
7 {
8 	long bootblocksdone, logblocksdone;
9 	long u;
10 	long baseblock, limitblock, bootblocks, sizeinblocks;
11 	int magicfound;
12 	void *llsave;
13 
14 	if(trace > 1)
15 		print("logfsformat: base %ld limit %ld bootsize %lud\n", base, limit, bootsize);
16 
17 	if((*ll->getopenstatus)(ll))
18 		return Eperm;
19 
20 	if(!(*ll->calcformat)(ll, base, limit, bootsize, &baseblock, &limitblock, &bootblocks))
21 		return Ebadarg;
22 
23 	if(trace > 0)
24 		print("logfsformat: baseblock %ld limitblock %ld bootblocks %ld\n", baseblock, limitblock, bootblocks);
25 
26 	bootblocksdone = 0;
27 	logblocksdone = 0;
28 	/*
29 	 * we need to create some fs blocks, and some boot blocks
30 	 * the number of boot blocks is fixed; the number of fs blocks
31 	 * occupies the remainder
32 	 * the layout is randomised to:
33 	 * 1) test the software
34 	 * 2) spread wear around if a lot of format commands are issued by
35 	 *     the bootloader
36 	 */
37 
38 	sizeinblocks = limitblock - baseblock;
39 
40 	for(u = 0; u < sizeinblocks; u++) {
41 		int r;
42 		uchar tag;
43 		long path;
44 		LogfsLowLevelReadResult e;
45 		char *errmsg;
46 		int markedbad;
47 
48 		if(trace > 1)
49 			print("block %lud:", u);
50 		llsave = nil;
51 		errmsg = (*ll->getblockstatus)(ll, u + baseblock, &magicfound, &llsave, &e);
52 		if(errmsg)
53 			return errmsg;
54 		if(e == LogfsLowLevelReadResultBad) {
55 			if(trace > 1)
56 				print(" marked bad\n");
57 			continue;
58 		}
59 		errmsg = (*ll->eraseblock)(ll, u + baseblock, nil, &markedbad);
60 		if(errmsg)
61 			return errmsg;
62 		if(markedbad) {
63 			if(trace > 1)
64 				print(" marked bad\n");
65 			continue;
66 		}
67 		if(e != LogfsLowLevelReadResultHardError && magicfound) {
68 			if(trace > 1)
69 				print(" previously formatted");
70 		}
71 		r = nrand(sizeinblocks - u);
72 		if(bootblocksdone < bootblocks && r < (bootblocks - bootblocksdone)) {
73 			tag = LogfsTboot;
74 			path = mkdatapath(bootblocksdone, 0);
75 		}
76 		else {
77 			tag = LogfsTnone;
78 			path = ~0;
79 		}
80 		if(trace > 1)
81 			print(" tag %s path %ld", logfstagname(tag), path);
82 		errmsg = (*ll->formatblock)(ll, u + baseblock, tag, path, baseblock, sizeinblocks, 1, &bootblocks, llsave, &markedbad);
83 		logfsfreemem(llsave);
84 		if(errmsg)
85 			return errmsg;
86 		if(markedbad) {
87 			if(trace > 1)
88 				print(" marked bad\n");
89 			continue;
90 		}
91 		switch(tag) {
92 		case LogfsTboot:
93 			bootblocksdone++;
94 			break;
95 		case LogfsTnone:
96 			logblocksdone++;
97 			break;
98 		}
99 		if(trace > 1)
100 			print("\n");
101 	}
102 	if(bootblocksdone < bootblocks)
103 		return "not enough capacity left for boot";
104 	if(trace > 0)
105 		print("log blocks %lud\n", logblocksdone);
106 	return nil;
107 }
108