summaryrefslogtreecommitdiff
path: root/liblogfs/format.c
diff options
context:
space:
mode:
Diffstat (limited to 'liblogfs/format.c')
-rw-r--r--liblogfs/format.c109
1 files changed, 109 insertions, 0 deletions
diff --git a/liblogfs/format.c b/liblogfs/format.c
new file mode 100644
index 00000000..f270c84f
--- /dev/null
+++ b/liblogfs/format.c
@@ -0,0 +1,109 @@
+#include "lib9.h"
+#include "logfs.h"
+#include "local.h"
+#include "mp.h"
+#include "libsec.h"
+
+char *
+logfsformat(LogfsLowLevel *ll, long base, long limit, long bootsize, int trace)
+{
+ long bootblocksdone, logblocksdone;
+ long u;
+ long baseblock, limitblock, bootblocks, sizeinblocks;
+ int magicfound;
+ void *llsave;
+
+ if(trace > 1)
+ print("logfsformat: base %ld limit %ld bootsize %lud\n", base, limit, bootsize);
+
+ if((*ll->getopenstatus)(ll))
+ return Eperm;
+
+ if(!(*ll->calcformat)(ll, base, limit, bootsize, &baseblock, &limitblock, &bootblocks))
+ return Ebadarg;
+
+ if(trace > 0)
+ print("logfsformat: baseblock %ld limitblock %ld bootblocks %ld\n", baseblock, limitblock, bootblocks);
+
+ bootblocksdone = 0;
+ logblocksdone = 0;
+ /*
+ * we need to create some fs blocks, and some boot blocks
+ * the number of boot blocks is fixed; the number of fs blocks
+ * occupies the remainder
+ * the layout is randomised to:
+ * 1) test the software
+ * 2) spread wear around if a lot of format commands are issued by
+ * the bootloader
+ */
+
+ sizeinblocks = limitblock - baseblock;
+
+ for(u = 0; u < sizeinblocks; u++) {
+ int r;
+ uchar tag;
+ long path;
+ LogfsLowLevelReadResult e;
+ char *errmsg;
+ int markedbad;
+
+ if(trace > 1)
+ print("block %lud:", u);
+ llsave = nil;
+ errmsg = (*ll->getblockstatus)(ll, u + baseblock, &magicfound, &llsave, &e);
+ if(errmsg)
+ return errmsg;
+ if(e == LogfsLowLevelReadResultBad) {
+ if(trace > 1)
+ print(" marked bad\n");
+ continue;
+ }
+ errmsg = (*ll->eraseblock)(ll, u + baseblock, nil, &markedbad);
+ if(errmsg)
+ return errmsg;
+ if(markedbad) {
+ if(trace > 1)
+ print(" marked bad\n");
+ continue;
+ }
+ if(e != LogfsLowLevelReadResultHardError && magicfound) {
+ if(trace > 1)
+ print(" previously formatted");
+ }
+ r = rand() % (sizeinblocks - u);
+ if(bootblocksdone < bootblocks && r < (bootblocks - bootblocksdone)) {
+ tag = LogfsTboot;
+ path = mkdatapath(bootblocksdone, 0);
+ }
+ else {
+ tag = LogfsTnone;
+ path = ~0;
+ }
+ if(trace > 1)
+ print(" tag %s path %ld", logfstagname(tag), path);
+ errmsg = (*ll->formatblock)(ll, u + baseblock, tag, path, baseblock, sizeinblocks, 1, &bootblocks, llsave, &markedbad);
+ logfsfreemem(llsave);
+ if(errmsg)
+ return errmsg;
+ if(markedbad) {
+ if(trace > 1)
+ print(" marked bad\n");
+ continue;
+ }
+ switch(tag) {
+ case LogfsTboot:
+ bootblocksdone++;
+ break;
+ case LogfsTnone:
+ logblocksdone++;
+ break;
+ }
+ if(trace > 1)
+ print("\n");
+ }
+ if(bootblocksdone < bootblocks)
+ return "not enough capacity left for boot";
+ if(trace > 0)
+ print("log blocks %lud\n", logblocksdone);
+ return nil;
+}