struct inode* dirlookup(struct inode*, char*, uint*);
struct inode* ialloc(uint, short);
struct inode* idup(struct inode*);
-void iinit(void);
+void iinit(int dev);
void ilock(struct inode*);
void iput(struct inode*);
void iunlock(struct inode*);
void microdelay(int);
// log.c
-void initlog(void);
+void initlog(int dev);
void log_write(struct buf*);
void begin_op();
void end_op();
#define min(a, b) ((a) < (b) ? (a) : (b))
static void itrunc(struct inode*);
+struct superblock sb; // there should be one per dev, but we run with one dev
// Read the super block.
void
{
int b, bi, m;
struct buf *bp;
- struct superblock sb;
bp = 0;
- readsb(dev, &sb);
for(b = 0; b < sb.size; b += BPB){
- bp = bread(dev, BBLOCK(b, sb.ninodes));
+ bp = bread(dev, BBLOCK(b, sb));
for(bi = 0; bi < BPB && b + bi < sb.size; bi++){
m = 1 << (bi % 8);
if((bp->data[bi/8] & m) == 0){ // Is block free?
bfree(int dev, uint b)
{
struct buf *bp;
- struct superblock sb;
int bi, m;
readsb(dev, &sb);
- bp = bread(dev, BBLOCK(b, sb.ninodes));
+ bp = bread(dev, BBLOCK(b, sb));
bi = b % BPB;
m = 1 << (bi % 8);
if((bp->data[bi/8] & m) == 0)
// its size, the number of links referring to it, and the
// list of blocks holding the file's content.
//
-// The inodes are laid out sequentially on disk immediately after
-// the superblock. Each inode has a number, indicating its
+// The inodes are laid out sequentially on disk at
+// sb.startinode. Each inode has a number, indicating its
// position on the disk.
//
// The kernel keeps a cache of in-use inodes in memory
} icache;
void
-iinit(void)
+iinit(int dev)
{
initlock(&icache.lock, "icache");
+ readsb(dev, &sb);
+ cprintf("sb: size %d nblocks %d ninodes %d nlog %d logstart %d inodestart %d bmap start %d\n", sb.size,
+ sb.nblocks, sb.ninodes, sb.nlog, sb.logstart, sb.inodestart, sb.bmapstart);
}
static struct inode* iget(uint dev, uint inum);
int inum;
struct buf *bp;
struct dinode *dip;
- struct superblock sb;
-
- readsb(dev, &sb);
for(inum = 1; inum < sb.ninodes; inum++){
- bp = bread(dev, IBLOCK(inum));
+ bp = bread(dev, IBLOCK(inum, sb));
dip = (struct dinode*)bp->data + inum%IPB;
if(dip->type == 0){ // a free inode
memset(dip, 0, sizeof(*dip));
struct buf *bp;
struct dinode *dip;
- bp = bread(ip->dev, IBLOCK(ip->inum));
+ bp = bread(ip->dev, IBLOCK(ip->inum, sb));
dip = (struct dinode*)bp->data + ip->inum%IPB;
dip->type = ip->type;
dip->major = ip->major;
release(&icache.lock);
if(!(ip->flags & I_VALID)){
- bp = bread(ip->dev, IBLOCK(ip->inum));
+ bp = bread(ip->dev, IBLOCK(ip->inum, sb));
dip = (struct dinode*)bp->data + ip->inum%IPB;
ip->type = dip->type;
ip->major = dip->major;
// On-disk file system format.
// Both the kernel and user programs use this header file.
-// Block 0 is unused.
-// Block 1 is super block.
-// Blocks 2 through sb.ninodes/IPB hold inodes.
-// Then free bitmap blocks holding sb.size bits.
-// Then sb.nblocks data blocks.
-// Then sb.nlog log blocks.
#define ROOTINO 1 // root i-number
#define BSIZE 512 // block size
-// File system super block
+// Disk layout:
+// [ boot block | super block | log | inode blocks | free bit map | data blocks ]
+//
+// mkfs computes the super block and builds an initial file system. The super describes
+// the disk layout:
struct superblock {
uint size; // Size of file system image (blocks)
uint nblocks; // Number of data blocks
uint ninodes; // Number of inodes.
uint nlog; // Number of log blocks
+ uint logstart; // Block number of first log block
+ uint inodestart; // Block number of first inode block
+ uint bmapstart; // Block number of first free map block
};
#define NDIRECT 12
#define IPB (BSIZE / sizeof(struct dinode))
// Block containing inode i
-#define IBLOCK(i) ((i) / IPB + 2)
+#define IBLOCK(i, sb) ((i) / IPB + sb.inodestart)
// Bitmap bits per block
#define BPB (BSIZE*8)
-// Block containing bit for block b
-#define BBLOCK(b, ninodes) (b/BPB + (ninodes)/IPB + 3)
+// Block of free map containing bit for block b
+#define BBLOCK(b, sb) (b/BPB + sb.bmapstart)
// Directory is a file containing a sequence of dirent structures.
#define DIRSIZ 14
static void commit();
void
-initlog(void)
+initlog(int dev)
{
if (sizeof(struct logheader) >= BSIZE)
panic("initlog: too big logheader");
struct superblock sb;
initlock(&log.lock, "log");
- readsb(ROOTDEV, &sb);
- log.start = sb.size - sb.nlog;
+ readsb(dev, &sb);
+ log.start = sb.logstart;
log.size = sb.nlog;
- log.dev = ROOTDEV;
+ log.dev = dev;
recover_from_log();
}
tvinit(); // trap vectors
binit(); // buffer cache
fileinit(); // file table
- iinit(); // inode cache
ideinit(); // disk
if(!ismp)
timerinit(); // uniprocessor timer
#define NINODES 200
// Disk layout:
-// [ boot block | sb block | inode blocks | bit map | data blocks | log ]
+// [ boot block | sb block | log | inode blocks | free bit map | data blocks ]
int nbitmap = FSSIZE/(BSIZE*8) + 1;
int ninodeblocks = NINODES / IPB + 1;
int nlog = LOGSIZE;
-int nmeta; // Number of meta blocks (inode, bitmap, and 2 extra)
+int nmeta; // Number of meta blocks (boot, sb, nlog, inode, bitmap)
int nblocks; // Number of data blocks
int fsfd;
exit(1);
}
- nmeta = 2 + ninodeblocks + nbitmap;
- nblocks = FSSIZE - nlog - nmeta;
+ // 1 fs block = 1 disk sector
+ nmeta = 2 + nlog + ninodeblocks + nbitmap;
+ nblocks = FSSIZE - nmeta;
sb.size = xint(FSSIZE);
- sb.nblocks = xint(nblocks); // so whole disk is size sectors
+ sb.nblocks = xint(nblocks);
sb.ninodes = xint(NINODES);
sb.nlog = xint(nlog);
+ sb.logstart = xint(2);
+ sb.inodestart = xint(2+nlog);
+ sb.bmapstart = xint(2+nlog+ninodeblocks);
- printf("nmeta %d (boot, super, inode blocks %u, bitmap blocks %u) blocks %d log %u total %d\n", nmeta, ninodeblocks, nbitmap, nblocks, nlog, FSSIZE);
+ printf("nmeta %d (boot, super, log blocks %u inode blocks %u, bitmap blocks %u) blocks %d total %d\n",
+ nmeta, nlog, ninodeblocks, nbitmap, nblocks, FSSIZE);
freeblock = nmeta; // the first free block that we can allocate
uint bn;
struct dinode *dip;
- bn = IBLOCK(inum);
+ bn = IBLOCK(inum, sb);
rsect(bn, buf);
dip = ((struct dinode*)buf) + (inum % IPB);
*dip = *ip;
uint bn;
struct dinode *dip;
- bn = IBLOCK(inum);
+ bn = IBLOCK(inum, sb);
rsect(bn, buf);
dip = ((struct dinode*)buf) + (inum % IPB);
*ip = *dip;
for(i = 0; i < used; i++){
buf[i/8] = buf[i/8] | (0x1 << (i%8));
}
- printf("balloc: write bitmap block at sector %d\n", ninodeblocks+2);
- wsect(ninodeblocks+2, buf);
+ printf("balloc: write bitmap block at sector %d\n", sb.bmapstart);
+ wsect(sb.bmapstart, buf);
}
#define min(a, b) ((a) < (b) ? (a) : (b))
uint x;
rinode(inum, &din);
-
off = xint(din.size);
+ // printf("append inum %d at off %d sz %d\n", inum, off, n);
while(n > 0){
fbn = off / BSIZE;
assert(fbn < MAXFILE);
x = xint(din.addrs[fbn]);
} else {
if(xint(din.addrs[NDIRECT]) == 0){
- // printf("allocate indirect block\n");
din.addrs[NDIRECT] = xint(freeblock++);
}
- // printf("read indirect block\n");
rsect(xint(din.addrs[NDIRECT]), (char*)indirect);
if(indirect[fbn - NDIRECT] == 0){
indirect[fbn - NDIRECT] = xint(freeblock++);
// of a regular process (e.g., they call sleep), and thus cannot
// be run from main().
first = 0;
- initlog();
+ iinit(ROOTDEV);
+ initlog(ROOTDEV);
}
// Return to "caller", actually trapret (see allocproc).