Initial commit: Schunix as it stands before the SchOS rename
An x86-64 operating system built from xv6, now largely rewritten: SMP, a copy-on-write root filesystem (SchFS), PCI/USB/virtio drivers, a TTF rasteriser, and a Linux-numbered syscall ABI. No history before this point -- the tree was never under version control. This commit exists so the rename that follows has something to undo to.
This commit is contained in:
commit
d0f7acf9eb
275 changed files with 51417 additions and 0 deletions
203
include/fs.h
Normal file
203
include/fs.h
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
// SCHFS - On-disk file system format.
|
||||
// Both the kernel and user programs use this header file.
|
||||
//
|
||||
// Changes from original:
|
||||
// - struct dinode gains atime, mtime, ctime (timestamps) and checksum
|
||||
// (CRC32c). Padding reduced from 44 to 28 bytes; struct stays 128 bytes.
|
||||
// - struct superblock gains checksum field.
|
||||
// - struct fsv1_extent added for T_EXTENT inode block mapping.
|
||||
// - OVERFLOW_DIR_START / OVERFLOW_DIR_END replace the bare "113 * BSIZE"
|
||||
// magic numbers used in fs.c and mkfs.c.
|
||||
|
||||
#ifndef FS_H
|
||||
#define FS_H
|
||||
|
||||
#define ROOTINO 1 // root i-number
|
||||
#define BSIZE 1024 // block size
|
||||
|
||||
// Permission mode bits (rwmode field)
|
||||
#define RW 3 // 11 read+write
|
||||
#define W_ 1 // 01 write-only
|
||||
#define R_ 2 // 10 read-only
|
||||
#define NONE 0 // 00 no access
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Superblock
|
||||
// ---------------------------------------------------------------------------
|
||||
// Disk layout:
|
||||
// [ boot | super | log | inode-bitmap | inode-blocks | block-bitmap | data ]
|
||||
|
||||
struct superblock {
|
||||
uint magic; // Must be FSMAGIC
|
||||
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-block bitmap block
|
||||
uint ibmapstart; // Block number of first inode-bitmap block
|
||||
uint freeinodes; // Count of free inodes
|
||||
uint freeblocks; // Count of free blocks
|
||||
uint checksum; // CRC32c of this struct (field zeroed during computation)
|
||||
};
|
||||
|
||||
extern struct superblock sb;
|
||||
|
||||
#define FSMAGIC 0x10203040
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Block / inode geometry
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#define NDIRECT 12
|
||||
#define NINDIRECT (BSIZE / sizeof(uint))
|
||||
|
||||
// Maximum file size in blocks: direct + 1x + 2x + 3x indirect
|
||||
#define MAXFILE (NDIRECT \
|
||||
+ NINDIRECT \
|
||||
+ (NINDIRECT * NINDIRECT) \
|
||||
+ (NINDIRECT * NINDIRECT * NINDIRECT))
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Extent descriptor (T_EXTENT inodes only)
|
||||
//
|
||||
// Up to MAX_INLINE_EXTENTS are packed into ip->addrs[0..NDIRECT-1].
|
||||
// addrs[] = NDIRECT uints = 12*4 = 48 bytes
|
||||
// each fsv1_extent = 12 bytes → 48/12 = 4 inline extents
|
||||
// (addrs[NDIRECT], [NDIRECT+1], [NDIRECT+2] remain as indirect pointers)
|
||||
//
|
||||
// For files needing more extents, addrs[NDIRECT] points to an indirect block
|
||||
// of BSIZE/sizeof(struct fsv1_extent) = 85 additional extents.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// Renamed from "schfs_extent". The new format in include/schfs.h has its own,
|
||||
// completely different, struct of that name -- 64-bit fields and a refcount --
|
||||
// and any file including both headers hit a redefinition error. Two structs
|
||||
// with one name and two layouts is a trap worth removing rather than working
|
||||
// around; this one belongs to the v1 format and dies with it.
|
||||
struct fsv1_extent {
|
||||
uint start_block; // logical block number in the file (first of run)
|
||||
uint start_blkaddr; // physical disk block address
|
||||
uint len; // number of contiguous blocks in this run
|
||||
};
|
||||
|
||||
// Inline extents packed into addrs[0 .. NDIRECT-1] only.
|
||||
#define MAX_INLINE_EXTENTS (NDIRECT * sizeof(uint) / sizeof(struct fsv1_extent))
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// On-disk inode (exactly 128 bytes; IPB = 8 inodes per 1024-byte block)
|
||||
//
|
||||
// Byte layout:
|
||||
// 0 short type 2
|
||||
// 2 short major 2
|
||||
// 4 short minor 2
|
||||
// 6 short nlink 2
|
||||
// 8 uint size 4
|
||||
// 12 uint rwmode 4
|
||||
// 16 uint supermode 4
|
||||
// 20 uint addrs[15] 60 T_EXTENT: packed fsv1_extent[4] in [0..11], rest normal
|
||||
// 80 uint showmode 4
|
||||
// 84 uint atime 4 ← last access time (Unix seconds)
|
||||
// 88 uint mtime 4 ← last modification time
|
||||
// 92 uint ctime 4 ← last metadata-change time
|
||||
// 96 uint checksum 4 ← CRC32c (zeroed during computation)
|
||||
// 100 uchar pad[28] 28 ← was 44; reduced by 16 for the 4 new fields
|
||||
// 128 bytes total
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
struct dinode {
|
||||
short type; // file type
|
||||
short major; // major device number (T_DEVICE only)
|
||||
short minor; // minor device number (T_DEVICE only)
|
||||
short nlink; // hard-link count
|
||||
uint size; // file size in bytes
|
||||
uint rwmode; // read/write permission flags
|
||||
uint supermode; // superuser-only flag
|
||||
uint addrs[NDIRECT + 3]; // block addresses / packed extent entries
|
||||
uint showmode; // visibility flag
|
||||
uint atime; // last access time (seconds since epoch)
|
||||
uint mtime; // last modification time
|
||||
uint ctime; // last metadata-change time
|
||||
uint checksum; // CRC32c of this dinode (field = 0 when hashing)
|
||||
uchar pad[28]; // reserved padding (struct = 128 bytes)
|
||||
};
|
||||
|
||||
// Inodes per block
|
||||
#define IPB (BSIZE / sizeof(struct dinode))
|
||||
|
||||
// Block containing inode i
|
||||
#define IBLOCK(i, sb) ((i) / IPB + (sb).inodestart)
|
||||
|
||||
// Bitmap bits per block
|
||||
#define BPB (BSIZE * 8)
|
||||
|
||||
// Block of free-block bitmap containing bit for block b
|
||||
#define BBLOCK(b, sb) ((b) / BPB + (sb).bmapstart)
|
||||
|
||||
// Block of inode bitmap containing bit for inode i
|
||||
#define IBBLOCK(i, sb) ((i) / BPB + (sb).ibmapstart)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Directory entry
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// 30, not 14.
|
||||
//
|
||||
// 14 was xv6's, and the v1 filesystem truncated to it *silently*: a file called
|
||||
// JetBrainsMono-Regular.ttf was stored as "JetBrainsMono-", could not be opened
|
||||
// by its real name, and would have collided outright with
|
||||
// JetBrainsMono-Bold.ttf. Any two files sharing a 14-character prefix mapped to
|
||||
// one entry. That is data loss, not a display limit.
|
||||
//
|
||||
// The value is chosen so that `struct dirent` is exactly 32 bytes, because the
|
||||
// directory HTree below is laid out in *bytes* and a bucket must stay 256 bytes
|
||||
// (see DIRENT_BUCKET_BYTES). Going from 16-byte to 32-byte entries therefore
|
||||
// halves the slots per bucket from 16 to 8 and changes no offset anywhere else
|
||||
// -- HASHRANGE, the overflow region and MAXFSIZE all keep their values. The
|
||||
// cost is more overflow use in heavily collided directories, which is a far
|
||||
// better trade than silently mangling names.
|
||||
//
|
||||
// It is still not POSIX's 255. Getting there means reshaping the directory
|
||||
// format, which wants the on-disk version policy SchFS is getting first.
|
||||
#define DIRSIZ 30
|
||||
|
||||
struct dirent {
|
||||
ushort inum;
|
||||
char name[DIRSIZ];
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Directory HTree constants
|
||||
//
|
||||
// BKDRHash(name) returns a value in [16, 16 + HASHRANGE).
|
||||
// Each bucket is 256 bytes: 8 dirent slots of 32 bytes. It was 16 slots of 16
|
||||
// until DIRSIZ grew; the byte size is what the layout depends on, so it is the
|
||||
// thing held constant.
|
||||
//
|
||||
// With HASHRANGE=443:
|
||||
// max primary end byte = (16 + 443) * 256 = 117 504 (~114.75 blocks)
|
||||
// OVERFLOW_DIR_START = 113 * BSIZE = 115 712
|
||||
// OVERFLOW_DIR_END = 115 * BSIZE = 117 760
|
||||
// MAXFSIZE = 119 * BSIZE = 121 856
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#define DIRENT_NUM 7168
|
||||
#define FIRST_LAYER_NODE_NUM 112
|
||||
#define OVERFLOW_BLOCK (FIRST_LAYER_NODE_NUM + 1)
|
||||
#define NUM_DIRENT_PER_BLOCK (BSIZE / sizeof(struct dirent))
|
||||
#define SECOND_LAYER_NODE_NUM NUM_DIRENT_PER_BLOCK
|
||||
#define HASHRANGE 443
|
||||
|
||||
// One hash bucket, in bytes. Every offset in the HTree is derived from this, so
|
||||
// it must not change when DIRSIZ does -- see the note on DIRSIZ.
|
||||
#define DIRENT_BUCKET_BYTES 256
|
||||
#define DIRENT_PER_BUCKET (DIRENT_BUCKET_BYTES / sizeof(struct dirent))
|
||||
#define MAXFSIZE (119 * BSIZE)
|
||||
|
||||
// Overflow bucket: shared between fs.c and mkfs.c.
|
||||
// These replace the bare "113 * BSIZE" / "115 * BSIZE" literals.
|
||||
#define OVERFLOW_DIR_START (113 * BSIZE)
|
||||
#define OVERFLOW_DIR_END (115 * BSIZE)
|
||||
|
||||
#endif // FS_H
|
||||
Loading…
Reference in a new issue