// Open inode number 'inum'. // A pointer to the inode is stored in '*ino_store'. // The inode is locked exclusively, and its 'i_opencount' is incremented. // On the first read from disk, the memory-only fields are initialized // to sensible values. // Every inode_open() must be balanced by an inode_close(). // Returns 0 on success, < 0 on failure. // static int inode_open(int inum, struct Inode **ino_store) { int r; struct Inode *ino; // Always make sure our pagefault handler is installed. add_pgfault_handler(bcache_pgfault_handler); ino = get_inode(inum); r = bcache_ipc(ino, BCREQ_MAP_WLOCK); if (r < 0) { *ino_store = 0; return r; } // Initialize memory-only fields when an inode is first read from disk. if (r == 0) { // i.e., the block has not been INITIALIZEd ino->i_inum = inum; ino->i_opencount = 0; bcache_ipc(ino, BCREQ_INITIALIZE); } // Account for our reservation and return. ++ino->i_opencount; *ino_store = ino; return 0; }
void umain(int argc, char **argv) { add_pgfault_handler(handler); cprintf("%s\n", (char*)0xDeadBeef); cprintf("%s\n", (char*)0xCafeBffe); }
// Checks file system structures. // Checks all file system invariants hold and prints out any errors it finds. // Does no locking, so if run in parallel with other environments, it can // get confused and report transient "errors." // Returns 0 if the file system is OK, -E_INVAL if any errors were found. // int fsck(void) { blocknum_t min_nblocks; int i, j, k; int errors = 0; add_pgfault_handler(bcache_pgfault_handler); // superblock checks if (super->s_magic != FS_MAGIC) panic("fsck: file system magic number %08x should be %08x", super->s_magic, FS_MAGIC); if (super->s_nblocks < 4) panic("fsck: file system must have at least 4 blocks"); if (super->s_ninodes < 1) panic("fsck: file system must have at least 1 inode"); min_nblocks = 2 /* boot sector, superblock */ + ROUNDUP(super->s_nblocks, BLKSIZE) / BLKSIZE /* freemap */ + (super->s_ninodes - 1); /* inodes */ if (super->s_nblocks < min_nblocks) panic("fsck: file system with %d inodes has %d blocks, needs at least %d", super->s_ninodes, super->s_nblocks, min_nblocks); // basic freemap checks: initial blocks not free, free blocks marked // with 1 (later checks will overwrite freemap) for (i = 0; i < super->s_nblocks; ++i) if (i < min_nblocks && freemap[i] != 0) { cprintf("fsck: freemap[%d]: should be 0 (allocated), is %d\n", i, freemap[i]); ++errors; } else if (freemap[i] != 0 && freemap[i] != 1) { cprintf("fsck: freemap[%d]: should be 0 or 1, is %d\n", i, freemap[i]); ++errors; freemap[i] = (freemap[i] > 0 ? 1 : 0); } // inode checks: inode 1 is referenced, unreferenced inodes // have no data pointers, ftype makes sense, no data pointer overlap for (i = 1; i < super->s_ninodes; ++i) { struct Inode *ino = get_inode(i); off_t true_size; // check for open-but-unreferenced inode; be careful of // uninitialized inodes (use bcache_ipc to check) bool active = ino->i_refcount != 0; if (!active && ino->i_opencount != 0 && bcache_ipc(ino, BCREQ_MAP) != 0) active = true; if (active && ino->i_ftype != FTYPE_REG && ino->i_ftype != FTYPE_DIR) { cprintf("fsck: inode[%d]: odd i_ftype %d\n", i, ino->i_ftype); ++errors; } if (i == 1 && ino->i_refcount == 0) { cprintf("fsck: inode[1]: root inode should be referenced\n"); ++errors; } else if (i == 1 && ino->i_ftype != FTYPE_DIR) { cprintf("fsck: inode[1]: root inode should be directory\n"); ++errors; } if (active && ino->i_size > MAXFILESIZE) { cprintf("fsck: inode[%d]: size %d too large\n", i, ino->i_size); ++errors; } if (active && ino->i_inum != i) { cprintf("fsck: inode[%d]: wrong inumber %d\n", i, ino->i_inum); ++errors; } true_size = active ? ino->i_size : 0; for (j = 0; j < NDIRECT; ++j) { blocknum_t b = ino->i_direct[j]; if (j * BLKSIZE < true_size && !b) { cprintf("fsck: inode[%d]: direct block %d is null, though file size is %d\n", i, j, true_size); ++errors; } else if (j * BLKSIZE >= true_size && b && active) { cprintf("fsck: inode[%d]: direct block %d exists, though file size is %d\n", i, j, true_size); ++errors; } if (b && active) { if (b < min_nblocks) { cprintf("fsck: inode[%d]: direct block %d == %d is in special block range\n", i, j, b); ++errors; } else if (freemap[b] == 1) { cprintf("fsck: inode[%d]: direct block %d == %d is marked as free\n", i, j, b); ++errors; } else if (freemap[b] == -1) { cprintf("fsck: inode[%d]: direct block %d == %d used more than once\n", i, j, b); ++errors; } else freemap[b] = -1; } } ino->i_fsck_refcount = (i == 1 ? 1 : 0); ino->i_fsck_checked = 0; } // directory checks while (1) { struct Inode *ino; for (i = 1; i < super->s_ninodes; ++i) { ino = get_inode(i); if (ino->i_fsck_refcount > 0 && !ino->i_fsck_checked && ino->i_ftype == FTYPE_DIR) goto check_directory_inode; } break; check_directory_inode: ino->i_fsck_checked = 1; if (ino->i_size % sizeof(struct Direntry) != 0) { cprintf("inode[%d]: directory size %d not multiple of %d\n", i, ino->i_size, sizeof(struct Direntry)); ++errors; } for (j = 0; (off_t) (j + sizeof(struct Direntry)) <= ino->i_size; j += sizeof(struct Direntry)) { struct Direntry *de = (struct Direntry *) inode_data(ino, j); char name[MAXNAMELEN]; int namelen; if (de->de_inum == 0) continue; if (de->de_namelen <= 0 || de->de_namelen >= MAXNAMELEN) { cprintf("inode[%d] de@%d: bad filename length %d\n", i, j, de->de_namelen); ++errors; } else if (de->de_name[de->de_namelen] != 0) { cprintf("inode[%d] de@%d: filename is not null terminated\n", i, j); ++errors; } memcpy(name, de->de_name, MAXNAMELEN); namelen = MAX(MIN(de->de_namelen, MAXNAMELEN - 1), 0); name[namelen] = 0; if (de->de_inum >= super->s_ninodes) { cprintf("inode[%d] de@%d (%s): inode %d out of range\n", i, j, name, de->de_inum); ++errors; } else { struct Inode *refed = get_inode(de->de_inum); ++refed->i_fsck_refcount; if (refed->i_refcount == 0) { cprintf("inode[%d] de@%d (%s): refers to free inode %d\n", i, j, name, de->de_inum); ++errors; } } for (k = 0; k < j && de->de_namelen < MAXNAMELEN; k += sizeof(struct Direntry)) { struct Direntry *xde = (struct Direntry *) inode_data(ino, k); if (xde->de_inum != 0 && xde->de_namelen == namelen && memcmp(xde->de_name, name, namelen) == 0) { cprintf("inode[%d] de@%d (%s): same filename as de@%d\n", i, j, name, k); ++errors; } } } } // refcount consistency for (i = 1; i < super->s_ninodes; ++i) { struct Inode *ino = get_inode(i); if (ino->i_refcount != ino->i_fsck_refcount) { cprintf("fsck: inode[%d]: refcount %d should be %d\n", i, ino->i_refcount, ino->i_fsck_refcount); ++errors; } } // clean up freemap for (i = 0; i < super->s_nblocks; ++i) if (freemap[i] == -1) freemap[i] = 0; else if (freemap[i] == 0 && i >= min_nblocks) { cprintf("fsck: freemap[%d]: unreferenced block is not free\n", i); ++errors; } return errors ? -E_INVAL : 0; }