From: Thomas Veerman Date: Sun, 20 Dec 2009 20:41:50 +0000 (+0000) Subject: Add PFS (missing in previous commit) X-Git-Tag: v3.1.6~147 X-Git-Url: http://zhaoyanbai.com/repos/%22http:/www.isc.org/icons/ddns-confgen.html?a=commitdiff_plain;h=951c5f6b7394d8704aff02e53b1f78477c1a249d;p=minix.git Add PFS (missing in previous commit) --- diff --git a/servers/pfs/Makefile b/servers/pfs/Makefile new file mode 100644 index 000000000..1af893e90 --- /dev/null +++ b/servers/pfs/Makefile @@ -0,0 +1,36 @@ +# Makefile for Pipe File System (PFS) +SERVER = pfs +NR_BUFS=256 +BS=4096 + +# directories +u = /usr +i = $u/include +s = $i/sys +h = $i/minix + +# programs, flags, etc. +CC = exec cc +CFLAGS = -I$i $(EXTRA_OPTS) $(CPROFILE) -DNR_BUFS=$(NR_BUFS) +LDFLAGS = -i +LIBS = -lsys + +OBJ = open.o table.o inode.o main.o super.o link.o \ + buffer.o read.o misc.o utility.o stadir.o + +# build local binary +install all build: $(SERVER) +$(SERVER): $(OBJ) + $(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBS) + +# clean up local files +clean: + rm -f $(SERVER) *.o *.bak + +depend: + mkdep "$(CC) -E $(CPPFLAGS)" *.c > .depend + +# Include generated dependencies. +include .depend + + diff --git a/servers/pfs/buf.h b/servers/pfs/buf.h new file mode 100644 index 000000000..143462689 --- /dev/null +++ b/servers/pfs/buf.h @@ -0,0 +1,26 @@ +/* Buffer (block) cache. + */ + +struct buf { + /* Data portion of the buffer. */ + char b_data[PIPE_BUF]; /* ordinary user data */ + + /* Header portion of the buffer. */ + struct buf *b_next; /* used to link all free bufs in a chain */ + struct buf *b_prev; /* used to link all free bufs the other way */ + ino_t b_num; /* inode number on minor device */ + dev_t b_dev; /* major | minor device where block resides */ + int b_bytes; /* Number of bytes allocated in bp */ + int b_count; /* Number of users of this buffer */ +}; + +/* A block is free if b_dev == NO_DEV. */ + +#define NIL_BUF ((struct buf *) 0) /* indicates absence of a buffer */ + +#define BUFHASH(b) ((b) % NR_BUFS) + +EXTERN struct buf *front; /* points to least recently used free block */ +EXTERN struct buf *rear; /* points to most recently used free block */ +EXTERN int bufs_in_use; /* # bufs currently in use (not on free list)*/ + diff --git a/servers/pfs/buffer.c b/servers/pfs/buffer.c new file mode 100644 index 000000000..e49b1598e --- /dev/null +++ b/servers/pfs/buffer.c @@ -0,0 +1,112 @@ +#include "fs.h" +#include "buf.h" +#include "inode.h" +#include +#include +#include +#include + + +/*===========================================================================* + * buf_pool * + *===========================================================================*/ +PUBLIC void buf_pool(void) +{ +/* Initialize the buffer pool. */ + + front = NIL_BUF; + rear = NIL_BUF; +} + + + +/*===========================================================================* + * get_block * + *===========================================================================*/ +PUBLIC struct buf *get_block(dev, inum) +Dev_t dev; +ino_t inum; +{ + struct buf *bp; + + bp = front; + while(bp != NIL_BUF) { + if (bp->b_dev == dev && bp->b_num == inum) { + bp->b_count++; + return(bp); + } + bp = bp->b_next; + } + + /* Buffer was not found. Try to allocate a new one */ + return new_block(dev, inum); +} + + +/*===========================================================================* + * new_block * + *===========================================================================*/ +PUBLIC struct buf *new_block(dev, inum) +Dev_t dev; +ino_t inum; +{ +/* Allocate a new buffer and add it to the double linked buffer list */ + struct buf *bp; + + bp = malloc(sizeof(struct buf)); + if (bp == NULL) { + err_code = ENOSPC; + return(NIL_BUF); + } + bp->b_num = inum; + bp->b_dev = dev; + bp->b_bytes = 0; + bp->b_count = 1; + memset(bp->b_data, 0 , PIPE_BUF); + + /* Add at the end of the buffer */ + if (front == NIL_BUF) { /* Empty list? */ + front = bp; + bp->b_prev = NIL_BUF; + } else { + rear->b_next = bp; + bp->b_prev = rear; + } + bp->b_next = NIL_BUF; + rear = bp; + + return(bp); +} + + +/*===========================================================================* + * put_block * + *===========================================================================*/ +PUBLIC void put_block(dev, inum) +dev_t dev; +ino_t inum; +{ + struct buf *bp; + + bp = get_block(dev, inum); + if (bp == NIL_BUF) return; /* We didn't find the block. Nothing to put. */ + + bp->b_count--; /* Compensate for above 'get_block'. */ + if (--bp->b_count > 0) return; + + /* Cut bp out of the loop */ + if (bp->b_prev == NIL_BUF) + front = bp->b_next; + else + bp->b_prev->b_next = bp->b_next; + + if (bp->b_next == NIL_BUF) + rear = bp->b_prev; + else + bp->b_next->b_prev = bp->b_prev; + + /* Buffer administration is done. Now it's safe to free up bp. */ + free(bp); +} + + diff --git a/servers/pfs/const.h b/servers/pfs/const.h new file mode 100644 index 000000000..97387cbbc --- /dev/null +++ b/servers/pfs/const.h @@ -0,0 +1,98 @@ +/* Tables sizes */ +#define V1_NR_DZONES 7 /* # direct zone numbers in a V1 inode */ +#define V1_NR_TZONES 9 /* total # zone numbers in a V1 inode */ +#define V2_NR_DZONES 7 /* # direct zone numbers in a V2 inode */ +#define V2_NR_TZONES 10 /* total # zone numbers in a V2 inode */ + +#define NR_INODES 256 /* # slots in "in core" inode table */ +#define GETDENTS_BUFSIZ 257 + +#define INODE_HASH_LOG2 7 /* 2 based logarithm of the inode hash size */ +#define INODE_HASH_SIZE ((unsigned long)1< /* MUST be first */ +#include /* MUST be second */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "const.h" +#include "proto.h" +#include "glo.h" diff --git a/servers/pfs/glo.h b/servers/pfs/glo.h new file mode 100644 index 000000000..202331025 --- /dev/null +++ b/servers/pfs/glo.h @@ -0,0 +1,27 @@ +/* EXTERN should be extern except for the table file */ +#ifdef _TABLE +#undef EXTERN +#define EXTERN +#endif + +#include + +/* The following variables are used for returning results to the caller. */ +EXTERN int err_code; /* temporary storage for error number */ + +EXTERN int cch[NR_INODES]; + +extern _PROTOTYPE (int (*fs_call_vec[]), (void) ); /* fs call table */ + +EXTERN message fs_m_in; +EXTERN message fs_m_out; + +EXTERN uid_t caller_uid; +EXTERN gid_t caller_gid; +EXTERN int req_nr; +EXTERN int SELF_E; +EXTERN int exitsignaled; +EXTERN int busy; + +/* Inode map. */ +EXTERN bitchunk_t inodemap[FS_BITMAP_CHUNKS(NR_INODES)]; diff --git a/servers/pfs/inc.h b/servers/pfs/inc.h new file mode 100644 index 000000000..9f22b60e9 --- /dev/null +++ b/servers/pfs/inc.h @@ -0,0 +1,31 @@ + +#define _SYSTEM 1 /* get OK and negative error codes */ +#define _MINIX 1 /* tell headers to include MINIX stuff */ + +#define VERBOSE 0 /* display diagnostics */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "proto.h" + diff --git a/servers/pfs/inode.c b/servers/pfs/inode.c new file mode 100644 index 000000000..324844198 --- /dev/null +++ b/servers/pfs/inode.c @@ -0,0 +1,352 @@ +/* This file manages the inode table. There are procedures to allocate and + * deallocate inodes, acquire, erase, and release them, and read and write + * them from the disk. + * + * The entry points into this file are + * get_inode: search inode table for a given inode; if not there, + * read it + * put_inode: indicate that an inode is no longer needed in memory + * alloc_inode: allocate a new, unused inode + * wipe_inode: erase some fields of a newly allocated inode + * free_inode: mark an inode as available for a new file + * update_times: update atime, ctime, and mtime + * dup_inode: indicate that someone else is using an inode table entry + * find_inode: retrieve pointer to inode in inode cache + * + */ + +#include "fs.h" +#include "buf.h" +#include "inode.h" +#include + +FORWARD _PROTOTYPE( int addhash_inode, (struct inode *node) ); +FORWARD _PROTOTYPE( int unhash_inode, (struct inode *node) ); + + +/*===========================================================================* + * fs_putnode * + *===========================================================================*/ +PUBLIC int fs_putnode() +{ +/* Find the inode specified by the request message and decrease its counter.*/ + + struct inode *rip; + int count; + dev_t dev; + ino_t inum; + + rip = find_inode(fs_m_in.REQ_INODE_NR); + + if(!rip) { + printf("%s:%d put_inode: inode #%d dev: %d not found\n", __FILE__, + __LINE__, fs_m_in.REQ_INODE_NR, fs_m_in.REQ_DEV); + panic(__FILE__, "fs_putnode failed", NO_NUM); + } + + count = fs_m_in.REQ_COUNT; + if (count <= 0) { + printf("%s:%d put_inode: bad value for count: %d\n", __FILE__, + __LINE__, count); + panic(__FILE__, "fs_putnode failed", NO_NUM); + } else if(count > rip->i_count) { + printf("%s:%d put_inode: count too high: %d > %d\n", __FILE__, + __LINE__, count, rip->i_count); + panic(__FILE__, "fs_putnode failed", NO_NUM); + } + + /* Decrease reference counter, but keep one reference; it will be consumed by + * put_inode(). */ + rip->i_count -= count - 1; + dev = rip->i_dev; + inum = rip->i_num; + put_inode(rip); + if (rip->i_count == 0) put_block(dev, inum); + return(OK); +} + + +/*===========================================================================* + * init_inode_cache * + *===========================================================================*/ +PUBLIC void init_inode_cache() +{ + struct inode *rip; + struct inodelist *rlp; + + /* init free/unused list */ + TAILQ_INIT(&unused_inodes); + + /* init hash lists */ + for (rlp = &hash_inodes[0]; rlp < &hash_inodes[INODE_HASH_SIZE]; ++rlp) + LIST_INIT(rlp); + + /* add free inodes to unused/free list */ + for (rip = &inode[0]; rip < &inode[NR_INODES]; ++rip) { + rip->i_num = 0; + TAILQ_INSERT_HEAD(&unused_inodes, rip, i_unused); + } + + /* Reserve the first inode (bit 0) to prevent it from being allocated later*/ + if (alloc_bit() != NO_BIT) printf("PFS could not reserve NO_BIT\n"); + busy = 0; /* This bit does not make the server 'in use/busy'. */ +} + + +/*===========================================================================* + * addhash_inode * + *===========================================================================*/ +PRIVATE int addhash_inode(struct inode *node) +{ + int hashi = node->i_num & INODE_HASH_MASK; + + /* insert into hash table */ + LIST_INSERT_HEAD(&hash_inodes[hashi], node, i_hash); + return(OK); +} + + +/*===========================================================================* + * unhash_inode * + *===========================================================================*/ +PRIVATE int unhash_inode(struct inode *node) +{ + /* remove from hash table */ + LIST_REMOVE(node, i_hash); + return(OK); +} + + +/*===========================================================================* + * get_inode * + *===========================================================================*/ +PUBLIC struct inode *get_inode(dev, numb) +dev_t dev; /* device on which inode resides */ +int numb; /* inode number (ANSI: may not be unshort) */ +{ +/* Find the inode in the hash table. If it is not there, get a free inode + * load it from the disk if it's necessary and put on the hash list + */ + register struct inode *rip, *xp; + int hashi; + + hashi = numb & INODE_HASH_MASK; + + /* Search inode in the hash table */ + LIST_FOREACH(rip, &hash_inodes[hashi], i_hash) { + if (rip->i_num == numb && rip->i_dev == dev) { + /* If unused, remove it from the unused/free list */ + if (rip->i_count == 0) { + TAILQ_REMOVE(&unused_inodes, rip, i_unused); + } + ++rip->i_count; + + return(rip); + } + } + + /* Inode is not on the hash, get a free one */ + if (TAILQ_EMPTY(&unused_inodes)) { + err_code = ENFILE; + return(NIL_INODE); + } + rip = TAILQ_FIRST(&unused_inodes); + + /* If not free unhash it */ + if (rip->i_num != 0) unhash_inode(rip); + + /* Inode is not unused any more */ + TAILQ_REMOVE(&unused_inodes, rip, i_unused); + + /* Load the inode. */ + rip->i_dev = dev; + rip->i_num = numb; + rip->i_count = 1; + rip->i_update = 0; /* all the times are initially up-to-date */ + + /* Add to hash */ + addhash_inode(rip); + + + return(rip); +} + + +/*===========================================================================* + * find_inode * + *===========================================================================*/ +PUBLIC struct inode *find_inode(numb) +int numb; /* inode number (ANSI: may not be unshort) */ +{ +/* Find the inode specified by the inode and device number. + */ + struct inode *rip; + int hashi; + + hashi = numb & INODE_HASH_MASK; + + /* Search inode in the hash table */ + LIST_FOREACH(rip, &hash_inodes[hashi], i_hash) { + if (rip->i_count > 0 && rip->i_num == numb) { + return(rip); + } + } + + return(NIL_INODE); +} + + +/*===========================================================================* + * put_inode * + *===========================================================================*/ +PUBLIC void put_inode(rip) +register struct inode *rip; /* pointer to inode to be released */ +{ +/* The caller is no longer using this inode. If no one else is using it either + * write it back to the disk immediately. If it has no links, truncate it and + * return it to the pool of available inodes. + */ + + if (rip == NIL_INODE) return; /* checking here is easier than in caller */ + + if (rip->i_count < 1) + panic(__FILE__, "put_inode: i_count already below 1", rip->i_count); + + if (--rip->i_count == 0) { /* i_count == 0 means no one is using it now */ + if (rip->i_nlinks == 0) { + /* i_nlinks == 0 means free the inode. */ + truncate_inode(rip, 0); /* return all the disk blocks */ + rip->i_mode = I_NOT_ALLOC; /* clear I_TYPE field */ + free_inode(rip); + } else { + truncate_inode(rip, 0); + } + + if (rip->i_nlinks == 0) { + /* free, put at the front of the LRU list */ + unhash_inode(rip); + rip->i_num = 0; + TAILQ_INSERT_HEAD(&unused_inodes, rip, i_unused); + } else { + /* unused, put at the back of the LRU (cache it) */ + TAILQ_INSERT_TAIL(&unused_inodes, rip, i_unused); + } + } +} + + +/*===========================================================================* + * alloc_inode * + *===========================================================================*/ +PUBLIC struct inode *alloc_inode(dev_t dev, mode_t bits) +{ +/* Allocate a free inode on 'dev', and return a pointer to it. */ + + register struct inode *rip; + int major, minor; + bit_t b; + ino_t i_num; + + b = alloc_bit(); + if (b == NO_BIT) { + err_code = ENOSPC; + printf("PipeFS is out of inodes\n"); + return(NIL_INODE); + } + i_num = (ino_t) b; + + + /* Try to acquire a slot in the inode table. */ + if ((rip = get_inode(dev, i_num)) == NIL_INODE) { + /* No inode table slots available. Free the inode if just allocated.*/ + if (dev == NO_DEV) free_bit(b); + } else { + /* An inode slot is available. */ + + rip->i_mode = bits; /* set up RWX bits */ + rip->i_nlinks = 0; /* initial no links */ + rip->i_uid = caller_uid; /* file's uid is owner's */ + rip->i_gid = caller_gid; /* ditto group id */ + + /* Fields not cleared already are cleared in wipe_inode(). They have + * been put there because truncate() needs to clear the same fields if + * the file happens to be open while being truncated. It saves space + * not to repeat the code twice. + */ + wipe_inode(rip); + } + + return(rip); +} + + +/*===========================================================================* + * wipe_inode * + *===========================================================================*/ +PUBLIC void wipe_inode(rip) +register struct inode *rip; /* the inode to be erased */ +{ +/* Erase some fields in the inode. This function is called from alloc_inode() + * when a new inode is to be allocated, and from truncate(), when an existing + * inode is to be truncated. + */ + + register int i; + + rip->i_size = 0; + rip->i_update = ATIME | CTIME | MTIME; /* update all times later */ +} + + +/*===========================================================================* + * free_inode * + *===========================================================================*/ +PUBLIC void free_inode(rip) +struct inode *rip; +{ +/* Return an inode to the pool of unallocated inodes. */ + + bit_t b; + + if (rip->i_num <= 0 || rip->i_num >= NR_INODES) return; + b = rip->i_num; + free_bit(b); +} + + +/*===========================================================================* + * dup_inode * + *===========================================================================*/ +PUBLIC void dup_inode(ip) +struct inode *ip; /* The inode to be duplicated. */ +{ +/* This routine is a simplified form of get_inode() for the case where + * the inode pointer is already known. + */ + + ip->i_count++; +} + + +/*===========================================================================* + * update_times * + *===========================================================================*/ +PUBLIC void update_times(rip) +register struct inode *rip; /* pointer to inode to be read/written */ +{ +/* Various system calls are required by the standard to update atime, ctime, + * or mtime. Since updating a time requires sending a message to the clock + * task--an expensive business--the times are marked for update by setting + * bits in i_update. When a stat, fstat, or sync is done, or an inode is + * released, update_times() may be called to actually fill in the times. + */ + + time_t cur_time; + + cur_time = clock_time(); + if (rip->i_update & ATIME) rip->i_atime = cur_time; + if (rip->i_update & CTIME) rip->i_ctime = cur_time; + if (rip->i_update & MTIME) rip->i_mtime = cur_time; + rip->i_update = 0; /* they are all up-to-date now */ +} + diff --git a/servers/pfs/inode.h b/servers/pfs/inode.h new file mode 100644 index 000000000..40805fbe1 --- /dev/null +++ b/servers/pfs/inode.h @@ -0,0 +1,35 @@ +/* Inode table. This table holds inodes that are currently in use. + */ + +#include + +EXTERN struct inode { + mode_t i_mode; /* file type, protection, etc. */ + nlink_t i_nlinks; /* how many links to this file */ + uid_t i_uid; /* user id of the file's owner */ + gid_t i_gid; /* group number */ + off_t i_size; /* current file size in bytes */ + time_t i_atime; /* time of last access (V2 only) */ + time_t i_mtime; /* when was file data last changed */ + time_t i_ctime; /* when was inode itself changed (V2 only)*/ + + /* The following items are not present on the disk. */ + dev_t i_dev; /* which device is the inode on */ + ino_t i_num; /* inode number on its (minor) device */ + int i_count; /* # times inode used; 0 means slot is free */ + char i_update; /* the ATIME, CTIME, and MTIME bits are here */ + + LIST_ENTRY(inode) i_hash; /* hash list */ + TAILQ_ENTRY(inode) i_unused; /* free and unused list */ + + +} inode[NR_INODES]; + +/* list of unused/free inodes */ +EXTERN TAILQ_HEAD(unused_inodes_t, inode) unused_inodes; + +/* inode hashtable */ +EXTERN LIST_HEAD(inodelist, inode) hash_inodes[INODE_HASH_SIZE]; + +#define NIL_INODE (struct inode *) 0 /* indicates absence of inode slot */ + diff --git a/servers/pfs/link.c b/servers/pfs/link.c new file mode 100644 index 000000000..12c8285ee --- /dev/null +++ b/servers/pfs/link.c @@ -0,0 +1,57 @@ +#include "fs.h" +#include +#include +#include +#include +#include "buf.h" +#include "inode.h" +#include + +/*===========================================================================* + * fs_ftrunc * + *===========================================================================*/ +PUBLIC int fs_ftrunc(void) +{ + struct inode *rip; + off_t start, end; + int r; + ino_t inumb; + + inumb = fs_m_in.REQ_INODE_NR; + + if( (rip = find_inode(inumb)) == NIL_INODE) return(EINVAL); + + start = fs_m_in.REQ_TRC_START_LO; + end = fs_m_in.REQ_TRC_END_LO; + + return truncate_inode(rip, start); +} + + +/*===========================================================================* + * truncate_inode * + *===========================================================================*/ +PUBLIC int truncate_inode(rip, newsize) +register struct inode *rip; /* pointer to inode to be truncated */ +off_t newsize; /* inode must become this size */ +{ +/* Set inode to a certain size, freeing any zones no longer referenced + * and updating the size in the inode. If the inode is extended, the + * extra space is a hole that reads as zeroes. + * + * Nothing special has to happen to file pointers if inode is opened in + * O_APPEND mode, as this is different per fd and is checked when + * writing is done. + */ + int scale; + + /* Pipes can shrink, so adjust size to make sure all zones are removed. */ + if(newsize != 0) return(EINVAL); /* Only truncate pipes to 0. */ + rip->i_size = newsize; + + /* Next correct the inode size. */ + wipe_inode(rip); /* Pipes can only be truncated to 0. */ + + return(OK); +} + diff --git a/servers/pfs/main.c b/servers/pfs/main.c new file mode 100644 index 000000000..f57220da3 --- /dev/null +++ b/servers/pfs/main.c @@ -0,0 +1,137 @@ +#include "fs.h" +#include +#include +#include +#include +#include "buf.h" +#include "inode.h" +#include "drivers.h" + +FORWARD _PROTOTYPE(void init_server, (void) ); +FORWARD _PROTOTYPE(void get_work, (message *m_in) ); + +/*===========================================================================* + * main * + *===========================================================================*/ +PUBLIC int main(int argc, char *argv[]) +{ +/* This is the main routine of this service. The main loop consists of + * three major activities: getting new work, processing the work, and + * sending the reply. The loop never terminates, unless a panic occurs. + */ + int error, ind; + message m; + + /* Initialize the server, then go to work. */ + init_server(); + + while(!exitsignaled || busy) { + endpoint_t src; + + /* Wait for request message. */ + get_work(&fs_m_in); + + src = fs_m_in.m_source; + error = OK; + caller_uid = -1; /* To trap errors */ + caller_gid = -1; + + if (src == PM_PROC_NR) continue; /* Exit signal */ + assert(src == VFS_PROC_NR); /* Otherwise this must be VFS talking */ + req_nr = fs_m_in.m_type; + if (req_nr < VFS_BASE) { + fs_m_in.m_type += VFS_BASE; + req_nr = fs_m_in.m_type; + } + ind = req_nr - VFS_BASE; + + if (ind < 0 || ind >= NREQS) { + printf("mfs: bad request %d\n", req_nr); + printf("ind = %d\n", ind); + error = EINVAL; + } else { + error = (*fs_call_vec[ind])(); + } + + fs_m_out.m_type = error; + reply(src, &fs_m_out); + + } + return(OK); +} + + +/*===========================================================================* + * init_server * + *===========================================================================*/ +PRIVATE void init_server(void) +{ + int i; + + /* Initialize main loop parameters. */ + exitsignaled = 0; /* No exit request seen yet. */ + busy = 0; /* Server is not 'busy' (i.e., inodes in use). */ + + /* Init inode table */ + for (i = 0; i < NR_INODES; ++i) { + inode[i].i_count = 0; + cch[i] = 0; + } + + init_inode_cache(); + + /* Init driver mapping */ + for (i = 0; i < NR_DEVICES; ++i) + driver_endpoints[i].driver_e = NONE; + + SELF_E = getprocnr(); + buf_pool(); +} + + +/*===========================================================================* + * get_work * + *===========================================================================*/ +PRIVATE void get_work(m_in) +message *m_in; /* pointer to message */ +{ + int r, srcok = 0; + endpoint_t src; + + do { + if ((r = receive(ANY, m_in)) != OK) /* wait for message */ + panic("PFS","receive failed", r); + src = fs_m_in.m_source; + + if (src != VFS_PROC_NR) { + if(src == PM_PROC_NR) { + if(is_notify(fs_m_in.m_type)) { + exitsignaled = 1; /* Normal exit request. */ + srcok = 1; + } else + printf("PFS: unexpected message from PM\n"); + } else + printf("PFS: unexpected source %d\n", src); + } else if(src == VFS_PROC_NR) { + srcok = 1; /* Normal FS request. */ + } else + printf("PFS: unexpected source %d\n", src); + } while(!srcok); + + assert( src == VFS_PROC_NR || + (src == PM_PROC_NR && is_notify(fs_m_in.m_type)) + ); +} + + +/*===========================================================================* + * reply * + *===========================================================================*/ +PUBLIC void reply(who, m_out) +int who; +message *m_out; /* report result */ +{ + if (OK != send(who, m_out)) /* send the message */ + printf("PFS(%d) was unable to send reply\n", SELF_E); +} + diff --git a/servers/pfs/misc.c b/servers/pfs/misc.c new file mode 100644 index 000000000..efb0245fa --- /dev/null +++ b/servers/pfs/misc.c @@ -0,0 +1,18 @@ +#include "fs.h" +#include +#include +#include "buf.h" +#include "inode.h" + + +/*===========================================================================* + * fs_sync * + *===========================================================================*/ +PUBLIC int fs_sync() +{ +/* Perform the sync() system call. No-op on this FS. */ + + return(OK); /* sync() can't fail */ +} + + diff --git a/servers/pfs/open.c b/servers/pfs/open.c new file mode 100644 index 000000000..39026241c --- /dev/null +++ b/servers/pfs/open.c @@ -0,0 +1,48 @@ +#include "fs.h" +#include +#include +#include +#include +#include "buf.h" +#include "inode.h" +#include + + +/*===========================================================================* + * fs_newnode * + *===========================================================================*/ +PUBLIC int fs_newnode() +{ + register int r = OK; + mode_t bits; + struct inode *rip; + dev_t dev; + + caller_uid = fs_m_in.REQ_UID; + caller_gid = fs_m_in.REQ_GID; + bits = fs_m_in.REQ_MODE; + dev = fs_m_in.REQ_DEV; + + /* Try to allocate the inode */ + if( (rip = alloc_inode(dev, bits) ) == NIL_INODE) return(err_code); + + if (bits & S_IFMT != S_IFIFO) { + r = EIO; /* We only support pipes */ + } else if ((get_block(dev, rip->i_num)) == NIL_BUF) + r = EIO; + + if (r != OK) { + free_inode(rip); + } else { + /* Fill in the fields of the response message */ + fs_m_out.RES_INODE_NR = rip->i_num; + fs_m_out.RES_MODE = rip->i_mode; + fs_m_out.RES_FILE_SIZE_LO = rip->i_size; + fs_m_out.RES_UID = rip->i_uid; + fs_m_out.RES_GID = rip->i_gid; + fs_m_out.RES_DEV = dev; + } + + return(r); +} + diff --git a/servers/pfs/proto.h b/servers/pfs/proto.h new file mode 100644 index 000000000..0c4ede038 --- /dev/null +++ b/servers/pfs/proto.h @@ -0,0 +1,56 @@ +/* Function prototypes. */ + +/* Structs used in prototypes must be declared as such first. */ +struct buf; +struct filp; +struct inode; + +/* buffer.c */ +_PROTOTYPE( struct buf *get_block, (Dev_t dev, ino_t inum) ); +_PROTOTYPE( struct buf *new_block, (Dev_t dev, ino_t inum) ); +_PROTOTYPE( void put_block, (Dev_t dev, ino_t inum) ); + +/* cache.c */ +_PROTOTYPE( void buf_pool, (void) ); + +/* inode.c */ +_PROTOTYPE( struct inode *alloc_inode, (dev_t dev, mode_t mode) ); +_PROTOTYPE( void dup_inode, (struct inode *ip) ); +_PROTOTYPE( struct inode *find_inode, (int numb) ); +_PROTOTYPE( void free_inode, (struct inode *rip) ); +_PROTOTYPE( int fs_putnode, (void) ); +_PROTOTYPE( void init_inode_cache, (void) ); +_PROTOTYPE( struct inode *get_inode, (Dev_t dev, int numb) ); +_PROTOTYPE( void put_inode, (struct inode *rip) ); +_PROTOTYPE( void update_times, (struct inode *rip) ); +_PROTOTYPE( void wipe_inode, (struct inode *rip) ); + +/* link.c */ +_PROTOTYPE( int fs_ftrunc, (void) ); +_PROTOTYPE( int truncate_inode, (struct inode *rip, off_t newsize) ); + + +/* main.c */ +_PROTOTYPE( void reply, (int who, message *m_out) ); + +/* misc.c */ +_PROTOTYPE( int fs_sync, (void) ); + +/* open.c */ +_PROTOTYPE( int fs_newnode, (void) ); + +/* read.c */ +_PROTOTYPE( int fs_readwrite, (void) ); +_PROTOTYPE( block_t read_map, (struct inode *rip, off_t pos) ); +_PROTOTYPE( int read_write, (int rw_flag) ); + +/* utility.c */ +_PROTOTYPE( time_t clock_time, (void) ); +_PROTOTYPE( int no_sys, (void) ); + +/* stadir.c */ +_PROTOTYPE( int fs_stat, (void) ); + +/* super.c */ +_PROTOTYPE( bit_t alloc_bit, (void) ); +_PROTOTYPE( void free_bit, (bit_t bit_returned) ); diff --git a/servers/pfs/read.c b/servers/pfs/read.c new file mode 100644 index 000000000..54bd1f934 --- /dev/null +++ b/servers/pfs/read.c @@ -0,0 +1,92 @@ +#include "fs.h" +#include "buf.h" +#include +#include +#include +#include "inode.h" + + +/*===========================================================================* + * fs_readwrite * + *===========================================================================*/ +PUBLIC int fs_readwrite(void) +{ + int r, rw_flag; + block_t b; + struct buf *bp; + cp_grant_id_t gid; + off_t position, f_size; + unsigned int nrbytes, cum_io; + mode_t mode_word; + struct inode *rip; + ino_t inumb; + + r = OK; + cum_io = 0; + inumb = fs_m_in.REQ_INODE_NR; + rw_flag = (fs_m_in.m_type == REQ_READ ? READING : WRITING); +#if 0 + printf("PFS: going to %s inode %d\n", (rw_flag == READING? "read from": "write to"), inumb); +#endif + + /* Find the inode referred */ + if ((rip = find_inode(inumb)) == NIL_INODE) return(EINVAL); + + mode_word = rip->i_mode & I_TYPE; + if (mode_word != I_NAMED_PIPE) return(EIO); + f_size = rip->i_size; + + /* Get the values from the request message */ + rw_flag = (fs_m_in.m_type == REQ_READ ? READING : WRITING); + gid = fs_m_in.REQ_GRANT; + position = fs_m_in.REQ_SEEK_POS_LO; + nrbytes = (unsigned) fs_m_in.REQ_NBYTES; + + if (rw_flag == WRITING) { + /* Check in advance to see if file will grow too big. */ + if (position > PIPE_BUF - nrbytes) return(EFBIG); + } + + /* Mark inode in use */ + if ((get_inode(rip->i_dev, rip->i_num)) == NIL_INODE) return(err_code); + if ((bp = get_block(rip->i_dev, rip->i_num)) == NIL_BUF) return(err_code); + + if (rw_flag == READING) { + /* Copy a chunk from the block buffer to user space. */ + r = sys_safecopyto(FS_PROC_NR, gid, 0, + (vir_bytes) (bp->b_data+position), (phys_bytes) nrbytes, D); + } else { + /* Copy a chunk from user space to the block buffer. */ + r = sys_safecopyfrom(FS_PROC_NR, gid, 0, + (vir_bytes) (bp->b_data+position), (phys_bytes) nrbytes, D); + } + + if (r == OK) { + position += nrbytes; /* Update position */ + cum_io += nrbytes; + } + + fs_m_out.RES_SEEK_POS_LO = position; /* It might change later and the VFS + has to know this value */ + + /* On write, update file size and access time. */ + if (rw_flag == WRITING) { + if (position > f_size) rip->i_size = position; + } else { + if(position >= rip->i_size) { + /* All data in the pipe is read, so reset pipe pointers */ + rip->i_size = 0; /* no data left */ + position = 0; /* reset reader(s) */ + } + } + + bp->b_bytes = position; + if (rw_flag == READING) rip->i_update |= ATIME; + if (rw_flag == WRITING) rip->i_update |= CTIME | MTIME; + fs_m_out.RES_NBYTES = cum_io; + put_inode(rip); + put_block(rip->i_dev, rip->i_num); + + return(r); +} + diff --git a/servers/pfs/stadir.c b/servers/pfs/stadir.c new file mode 100644 index 000000000..500d0f827 --- /dev/null +++ b/servers/pfs/stadir.c @@ -0,0 +1,60 @@ +#include "fs.h" +#include "inode.h" +#include + +FORWARD _PROTOTYPE( int stat_inode, (struct inode *rip, int who_e, + cp_grant_id_t gid) ); + + +/*===========================================================================* + * stat_inode * + *===========================================================================*/ +PRIVATE int stat_inode(rip, who_e, gid) +register struct inode *rip; /* pointer to inode to stat */ +int who_e; /* Caller endpoint */ +cp_grant_id_t gid; /* grant for the stat buf */ +{ +/* Common code for stat and fstat system calls. */ + + struct stat statbuf; + int r, s; + + /* Update the atime, ctime, and mtime fields in the inode, if need be. */ + if (rip->i_update) update_times(rip); + + statbuf.st_dev = rip->i_dev; + statbuf.st_ino = rip->i_num; + statbuf.st_mode = rip->i_mode; + statbuf.st_nlink = rip->i_nlinks; + statbuf.st_uid = rip->i_uid; + statbuf.st_gid = rip->i_gid; + statbuf.st_rdev = (dev_t) 0; + statbuf.st_size = rip->i_size; + statbuf.st_mode &= ~I_REGULAR; /* wipe out I_REGULAR bit for pipes */ + statbuf.st_atime = rip->i_atime; + statbuf.st_mtime = rip->i_mtime; + statbuf.st_ctime = rip->i_ctime; + + /* Copy the struct to user space. */ + r = sys_safecopyto(who_e, gid, 0, (vir_bytes) &statbuf, + (phys_bytes) sizeof(statbuf), D); + + return(r); +} + + +/*===========================================================================* + * fs_stat * + *===========================================================================*/ +PUBLIC int fs_stat() +{ + register int r; /* return value */ + register struct inode *rip; /* target inode */ + + if( (rip = find_inode(fs_m_in.REQ_INODE_NR)) == NIL_INODE) return(EINVAL); + get_inode(rip->i_dev, rip->i_num); /* mark inode in use */ + r = stat_inode(rip, fs_m_in.m_source, fs_m_in.REQ_GRANT); + put_inode(rip); /* release the inode */ + return(r); +} + diff --git a/servers/pfs/super.c b/servers/pfs/super.c new file mode 100644 index 000000000..845af9f43 --- /dev/null +++ b/servers/pfs/super.c @@ -0,0 +1,80 @@ +/* This file manages the super block table and the related data structures, + * namely, the bit maps that keep track of which zones and which inodes are + * allocated and which are free. When a new inode or zone is needed, the + * appropriate bit map is searched for a free entry. + * + * The entry points into this file are + * alloc_bit: somebody wants to allocate a zone or inode; find one + * free_bit: indicate that a zone or inode is available for allocation + */ + +#include "fs.h" +#include +#include +#include +#include "buf.h" +#include "inode.h" +#include "const.h" + + +/*===========================================================================* + * alloc_bit * + *===========================================================================*/ +PUBLIC bit_t alloc_bit(void) +{ +/* Allocate a bit from a bit map and return its bit number. */ + bitchunk_t *wptr, *wlim; + bit_t b; + int i, bcount; + + bcount = FS_BITMAP_CHUNKS(NR_INODES); /* Inode map has this many chunks. */ + wlim = &inodemap[bcount]; /* Point to last chunk in inodemap. */ + + for (wptr = &inodemap[0]; wptr < wlim; wptr++) { + /* Does this word contain a free bit? */ + if (*wptr == (bitchunk_t) ~0) continue; /* No. Go to next word */ + + /* Find and allocate the free bit. */ + for (i = 0; (*wptr & (1 << i)) != 0; ++i) {} + + /* Get inode number */ + b = (wptr - &inodemap[0]) * FS_BITCHUNK_BITS + i; + + /* Don't allocate bits beyond end of map. */ + if (b >= NR_INODES) break; + + /* Allocate and return bit number. */ + *wptr |= 1 << i; + + /* Mark server 'busy' */ + busy++; + return(b); + } + + return(NO_BIT); /* no bit could be allocated */ +} + + +/*===========================================================================* + * free_bit * + *===========================================================================*/ +PUBLIC void free_bit(bit_returned) +bit_t bit_returned; /* number of bit to insert into the inode map*/ +{ + bitchunk_t *k, mask; + bit_t bit; + unsigned word; + + /* Get word offset and bit within offset */ + word = bit_returned / FS_BITCHUNK_BITS; + bit = bit_returned % FS_BITCHUNK_BITS; + + /* Unset bit */ + k = &inodemap[word]; + mask = 1 << bit; + *k &= ~mask; + + busy--; /* One inode less in use. */ +} + + diff --git a/servers/pfs/table.c b/servers/pfs/table.c new file mode 100644 index 000000000..ddc269f20 --- /dev/null +++ b/servers/pfs/table.c @@ -0,0 +1,49 @@ + +/* This file contains the table used to map system call numbers onto the + * routines that perform them. + */ + +#define _TABLE + +#include "fs.h" +#include +#include +#include "inode.h" +#include "buf.h" +#include "drivers.h" + +PUBLIC _PROTOTYPE (int (*fs_call_vec[]), (void) ) = { + no_sys, /* 0 not used */ + no_sys, /* 1 */ + fs_putnode, /* 2 */ + no_sys, /* 3 */ + fs_ftrunc, /* 4 */ + no_sys, /* 5 */ + no_sys, /* 6 */ + no_sys, /* 7 */ + fs_stat, /* 8 */ + no_sys, /* 9 */ + no_sys, /* 10 */ + no_sys, /* 11 */ + no_sys, /* 12 */ + no_sys, /* 13 */ + no_sys, /* 14 */ + no_sys, /* 15 */ + fs_sync, /* 16 */ + no_sys, /* 17 */ + no_sys, /* 18 */ + fs_readwrite, /* 19 */ + fs_readwrite, /* 20 */ + no_sys, /* 21 */ + no_sys, /* 22 */ + no_sys, /* 23 */ + no_sys, /* 24 */ + no_sys, /* 25 */ + no_sys, /* 26 */ + no_sys, /* 27 */ + no_sys, /* 28 */ + fs_newnode, /* 29 */ + no_sys, /* 30 */ + no_sys, /* 31 */ +}; + diff --git a/servers/pfs/type.h b/servers/pfs/type.h new file mode 100644 index 000000000..693aecfe9 --- /dev/null +++ b/servers/pfs/type.h @@ -0,0 +1,16 @@ + +struct buf { + /* Data portion of the buffer. */ + union fsdata_u *bp; + + /* Header portion of the buffer. */ + struct buf *b_next; /* used to link all free bufs in a chain */ + struct buf *b_prev; /* used to link all free bufs the other way */ + struct buf *b_hash; /* used to link bufs on hash chains */ + block_t b_blocknr; /* block number of its (minor) device */ + dev_t b_dev; /* major | minor device where block resides */ + char b_dirt; /* CLEAN or DIRTY */ + char b_count; /* number of users of this buffer */ + int b_bytes; /* Number of bytes allocated in bp */ +}; + diff --git a/servers/pfs/utility.c b/servers/pfs/utility.c new file mode 100644 index 000000000..2956a0cd9 --- /dev/null +++ b/servers/pfs/utility.c @@ -0,0 +1,33 @@ +#include "fs.h" + + +/*===========================================================================* + * no_sys * + *===========================================================================*/ +PUBLIC int no_sys() +{ +/* Somebody has used an illegal system call number */ + printf("no_sys: invalid call %d\n", req_nr); + return(EINVAL); +} + + +/*===========================================================================* + * clock_time * + *===========================================================================*/ +PUBLIC time_t clock_time() +{ +/* This routine returns the time in seconds since 1.1.1970. MINIX is an + * astrophysically naive system that assumes the earth rotates at a constant + * rate and that such things as leap seconds do not exist. + */ + + int r; + clock_t uptime, boottime; + + if ((r = getuptime2(&uptime,&boottime)) != OK) + panic(__FILE__,"clock_time: getuptme2 failed", r); + + return( (time_t) (boottime + (uptime/sys_hz()))); +} +