Minix1.1/usr/src/fs/main.c
/* This file contains the main program of the File System. It consists of
* a loop that gets messages requesting work, carries out the work, and sends
* replies.
*
* The entry points into this file are
* main: main program of the File System
* reply: send a reply to a process after the requested work is done
*/
#include "../h/const.h"
#include "../h/type.h"
#include "../h/callnr.h"
#include "../h/com.h"
#include "../h/error.h"
#include "const.h"
#include "type.h"
#include "buf.h"
#include "file.h"
#include "fproc.h"
#include "glo.h"
#include "inode.h"
#include "param.h"
#include "super.h"
#define M64K 0xFFFF0000L /* 16 bit mask for DMA check */
#define INFO 2 /* where in data_org is info from build */
#define MAX_RAM 512 /* maxium RAM disk size in blocks */
/*===========================================================================*
* main *
*===========================================================================*/
PUBLIC main()
{
/* This is the main program of the file system. The main loop consists of
* three major activities: getting new work, processing the work, and sending
* the reply. This loop never terminates as long as the file system runs.
*/
int error;
extern int (*call_vector[NCALLS])();
fs_init();
/* This is the main loop that gets work, processes it, and sends replies. */
while (TRUE) {
get_work(); /* sets who and fs_call */
fp = &fproc[who]; /* pointer to proc table struct */
super_user = (fp->fp_effuid == SU_UID ? TRUE : FALSE); /* su? */
dont_reply = FALSE; /* in other words, do reply is default */
/* Call the internal function that does the work. */
if (fs_call < 0 || fs_call >= NCALLS)
error = E_BAD_CALL;
else
error = (*call_vector[fs_call])();
/* Copy the results back to the user and send reply. */
if (dont_reply) continue;
reply(who, error);
if (rdahed_inode != NIL_INODE) read_ahead(); /* do block read ahead */
}
}
/*===========================================================================*
* get_work *
*===========================================================================*/
PRIVATE get_work()
{
/* Normally wait for new input. However, if 'reviving' is
* nonzero, a suspended process must be awakened.
*/
register struct fproc *rp;
if (reviving != 0) {
/* Revive a suspended process. */
for (rp = &fproc[0]; rp < &fproc[NR_PROCS]; rp++)
if (rp->fp_revived == REVIVING) {
who = rp - fproc;
fs_call = rp->fp_fd & BYTE;
fd = (rp->fp_fd >>8) & BYTE;
buffer = rp->fp_buffer;
nbytes = rp->fp_nbytes;
rp->fp_suspended = NOT_SUSPENDED; /* no longer hanging*/
rp->fp_revived = NOT_REVIVING;
reviving--;
return;
}
panic("get_work couldn't revive anyone", NO_NUM);
}
/* Normal case. No one to revive. */
if (receive(ANY, &m) != OK) panic("fs receive error", NO_NUM);
who = m.m_source;
fs_call = m.m_type;
}
/*===========================================================================*
* reply *
*===========================================================================*/
PUBLIC reply(whom, result)
int whom; /* process to reply to */
int result; /* result of the call (usually OK or error #) */
{
/* Send a reply to a user process. It may fail (if the process has just
* been killed by a signal, so don't check the return code. If the send
* fails, just ignore it.
*/
reply_type = result;
send(whom, &m1);
}
/*===========================================================================*
* fs_init *
*===========================================================================*/
PRIVATE fs_init()
{
/* Initialize global variables, tables, etc. */
register struct inode *rip;
int i;
extern struct inode *get_inode();
buf_pool(); /* initialize buffer pool */
load_ram(); /* Load RAM disk from root diskette. */
load_super(); /* Load super block for root device */
/* Initialize the 'fproc' fields for process 0 and process 2. */
for (i = 0; i < 3; i+= 2) {
fp = &fproc[i];
rip = get_inode(ROOT_DEV, ROOT_INODE);
fp->fp_rootdir = rip;
dup_inode(rip);
fp->fp_workdir = rip;
fp->fp_realuid = (uid) SYS_UID;
fp->fp_effuid = (uid) SYS_UID;
fp->fp_realgid = (gid) SYS_GID;
fp->fp_effgid = (gid) SYS_GID;
fp->fp_umask = ~0;
}
/* Certain relations must hold for the file system to work at all. */
if (ZONE_NUM_SIZE != 2) panic("ZONE_NUM_SIZE != 2", NO_NUM);
if (SUPER_SIZE > BLOCK_SIZE) panic("SUPER_SIZE > BLOCK_SIZE", NO_NUM);
if(BLOCK_SIZE % INODE_SIZE != 0)panic("BLOCK_SIZE % INODE_SIZE != 0", NO_NUM);
if (NR_FDS > 127) panic("NR_FDS > 127", NO_NUM);
if (NR_BUFS < 6) panic("NR_BUFS < 6", NO_NUM);
if (sizeof(d_inode) != 32) panic("inode size != 32", NO_NUM);
}
/*===========================================================================*
* buf_pool *
*===========================================================================*/
PRIVATE buf_pool()
{
/* Initialize the buffer pool. On the IBM PC, the hardware DMA chip is
* not able to cross 64K boundaries, so any buffer that happens to lie
* across such a boundary is not used. This is not very elegant, but all
* the alternative solutions are as bad, if not worse. The fault lies with
* the PC hardware.
*/
register struct buf *bp;
vir_bytes low_off, high_off;
phys_bytes org;
extern phys_clicks get_base();
bufs_in_use = 0;
front = &buf[0];
rear = &buf[NR_BUFS - 1];
for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++) {
bp->b_blocknr = NO_BLOCK;
bp->b_dev = NO_DEV;
bp->b_next = bp + 1;
bp->b_prev = bp - 1;
}
buf[0].b_prev = NIL_BUF;
buf[NR_BUFS - 1].b_next = NIL_BUF;
/* Delete any buffers that span a 64K boundary. */
#ifdef i8088
for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++) {
org = get_base() << CLICK_SHIFT; /* phys addr where FS is */
low_off = (vir_bytes) bp->b_data;
high_off = low_off + BLOCK_SIZE - 1;
if (((org + low_off) & M64K) != ((org + high_off) & M64K)) {
if (bp == &buf[0]) {
front = &buf[1];
buf[1].b_prev = NIL_BUF;
} else if (bp == &buf[NR_BUFS - 1]) {
rear = &buf[NR_BUFS - 2];
buf[NR_BUFS - 2].b_next = NIL_BUF;
} else {
/* Delete a buffer in the middle. */
bp->b_prev->b_next = bp + 1;
bp->b_next->b_prev = bp - 1;
}
}
}
#endif
for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++) bp->b_hash = bp->b_next;
buf_hash[NO_BLOCK & (NR_BUF_HASH - 1)] = front;
}
/*===========================================================================*
* load_ram *
*===========================================================================*/
PRIVATE load_ram()
{
/* The root diskette contains a block-by-block image of the root file system
* starting at 0. Go get it and copy it to the RAM disk.
*/
register struct buf *bp, *bp1;
int count;
long k_loaded;
struct super_block *sp;
block_nr i;
phys_clicks ram_clicks, init_org, init_text_clicks, init_data_clicks;
extern phys_clicks data_org[INFO + 2];
extern struct buf *get_block();
/* Get size of INIT by reading block on diskette where 'build' put it. */
init_org = data_org[INFO];
init_text_clicks = data_org[INFO + 1];
init_data_clicks = data_org[INFO + 2];
/* Get size of RAM disk by reading root file system's super block */
bp = get_block(BOOT_DEV, SUPER_BLOCK, NORMAL); /* get RAM super block */
copy(super_block, bp->b_data, sizeof(struct super_block));
sp = &super_block[0];
if (sp->s_magic != SUPER_MAGIC)
panic("Diskette in drive 0 is not root file system", NO_NUM);
count = sp->s_nzones << sp->s_log_zone_size; /* # blocks on root dev */
if (count > MAX_RAM) panic("RAM disk is too big. # blocks = ", count);
ram_clicks = count * (BLOCK_SIZE/CLICK_SIZE);
put_block(bp, FULL_DATA_BLOCK);
/* Tell MM the origin and size of INIT, and the amount of memory used for the
* system plus RAM disk combined, so it can remove all of it from the map.
*/
m1.m_type = BRK2;
m1.m1_i1 = init_text_clicks;
m1.m1_i2 = init_data_clicks;
m1.m1_i3 = init_org + init_text_clicks + init_data_clicks + ram_clicks;
m1.m1_p1 = (char *) init_org;
if (sendrec(MM_PROC_NR, &m1) != OK) panic("FS Can't report to MM", NO_NUM);
/* Tell RAM driver where RAM disk is and how big it is. */
m1.m_type = DISK_IOCTL;
m1.DEVICE = RAM_DEV;
m1.POSITION = (long) init_org + (long) init_text_clicks + init_data_clicks;
m1.POSITION = m1.POSITION << CLICK_SHIFT;
m1.COUNT = count;
if (sendrec(MEM, &m1) != OK) panic("Can't report size to MEM", NO_NUM);
/* Copy the blocks one at a time from the root diskette to the RAM */
printf("Loading RAM disk from root diskette. Loaded: 0K ");
for (i = 0; i < count; i++) {
bp = get_block(BOOT_DEV, (block_nr) i, NORMAL);
bp1 = get_block(ROOT_DEV, i, NO_READ);
copy(bp1->b_data, bp->b_data, BLOCK_SIZE);
bp1->b_dirt = DIRTY;
put_block(bp, I_MAP_BLOCK);
put_block(bp1, I_MAP_BLOCK);
k_loaded = ( (long) i * BLOCK_SIZE)/1024L; /* K loaded so far */
if (k_loaded % 5 == 0) printf("\b\b\b\b\b%3DK %c", k_loaded, 0);
}
printf("\rRAM disk loaded. Please remove root diskette. \n\n");
}
/*===========================================================================*
* load_super *
*===========================================================================*/
PRIVATE load_super()
{
register struct super_block *sp;
register struct inode *rip;
extern struct inode *get_inode();
/* Initialize the super_block table. */
for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++)
sp->s_dev = NO_DEV;
/* Read in super_block for the root file system. */
sp = &super_block[0];
sp->s_dev = ROOT_DEV;
rw_super(sp,READING);
rip = get_inode(ROOT_DEV, ROOT_INODE); /* inode for root dir */
/* Check super_block for consistency (is it the right diskette?). */
if ( (rip->i_mode & I_TYPE) != I_DIRECTORY || rip->i_nlinks < 3 ||
sp->s_magic != SUPER_MAGIC)
panic("Root file system corrupted. Possibly wrong diskette.", NO_NUM);
sp->s_imount = rip;
dup_inode(rip);
sp->s_isup = rip;
sp->s_rd_only = 0;
if (load_bit_maps(ROOT_DEV) != OK)
panic("init: can't load root bit maps", NO_NUM);
}