From: David van Moolenbroek Date: Sun, 24 Aug 2014 10:20:59 +0000 (+0000) Subject: PFS: rewrite, restyle X-Git-Url: http://zhaoyanbai.com/repos/man.dig.html?a=commitdiff_plain;h=30d9b70391895c4634d4e6b11b5df9a2843be230;p=minix.git PFS: rewrite, restyle - remove the buffer pool, inode bitmap, and inode hash table, and simplify the code accordingly; - use theoretically slightly more optimal buffer management; - put the entire source in one file, instead of having many files with one or two functions each; - convert the code to KNF style. Change-Id: Ib8f6f0bd99fbc6eb9098fba718e71b8e560783d9 --- diff --git a/minix/fs/pfs/Makefile b/minix/fs/pfs/Makefile index d1841c193..4544f52ef 100644 --- a/minix/fs/pfs/Makefile +++ b/minix/fs/pfs/Makefile @@ -1,7 +1,6 @@ # Makefile for Pipe File System (PFS) PROG= pfs -SRCS= open.c table.c inode.c main.c super.c link.c \ - buffer.c read.c misc.c mount.c stadir.c +SRCS= pfs.c DPADD+= ${LIBFSDRIVER} ${LIBSYS} LDADD+= -lfsdriver -lsys diff --git a/minix/fs/pfs/buf.h b/minix/fs/pfs/buf.h deleted file mode 100644 index cd31f7e84..000000000 --- a/minix/fs/pfs/buf.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef __PFS_BUF_H__ -#define __PFS_BUF_H__ - -/* 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. */ - - -EXTERN struct buf *front; /* points to least recently used free block */ -EXTERN struct buf *rear; /* points to most recently used free block */ - -#endif diff --git a/minix/fs/pfs/buffer.c b/minix/fs/pfs/buffer.c deleted file mode 100644 index 746aebd8a..000000000 --- a/minix/fs/pfs/buffer.c +++ /dev/null @@ -1,98 +0,0 @@ -#include "fs.h" - -static struct buf *new_block(dev_t dev, ino_t inum); - -/*===========================================================================* - * buf_pool * - *===========================================================================*/ -void buf_pool(void) -{ -/* Initialize the buffer pool. */ - - front = NULL; - rear = NULL; -} - - - -/*===========================================================================* - * get_block * - *===========================================================================*/ -struct buf *get_block(dev_t dev, ino_t inum) -{ - struct buf *bp = front; - - while(bp != NULL) { - 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 * - *===========================================================================*/ -static struct buf *new_block(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(NULL); - } - 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 == NULL) { /* Empty list? */ - front = bp; - bp->b_prev = NULL; - } else { - rear->b_next = bp; - bp->b_prev = rear; - } - bp->b_next = NULL; - rear = bp; - - return(bp); -} - - -/*===========================================================================* - * put_block * - *===========================================================================*/ -void put_block(dev_t dev, ino_t inum) -{ - struct buf *bp; - - bp = get_block(dev, inum); - if (bp == NULL) 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 == NULL) - front = bp->b_next; - else - bp->b_prev->b_next = bp->b_next; - - if (bp->b_next == NULL) - 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/minix/fs/pfs/const.h b/minix/fs/pfs/const.h deleted file mode 100644 index b98e55cfc..000000000 --- a/minix/fs/pfs/const.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef __PFS_CONST_H__ -#define __PFS_CONST_H__ - -#define PFS_NR_INODES 512 /* # slots in "in core" inode table */ - -#define INODE_HASH_LOG2 7 /* 2 based logarithm of the inode hash size */ -#define INODE_HASH_SIZE ((unsigned long)1< /* MUST be first */ -#include -#include -#include - -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - -#include "const.h" -#include "proto.h" -#include "glo.h" -#include "buf.h" -#include "inode.h" - -#endif diff --git a/minix/fs/pfs/glo.h b/minix/fs/pfs/glo.h deleted file mode 100644 index 77bff50ef..000000000 --- a/minix/fs/pfs/glo.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef __PFS_GLO_H__ -#define __PFS_GLO_H__ - -/* EXTERN should be extern except for the table file */ -#ifdef _TABLE -#undef EXTERN -#define EXTERN -#endif - -/* The following variables are used for returning results to the caller. */ -EXTERN int err_code; /* temporary storage for error number */ - -extern struct fsdriver pfs_table; - -EXTERN int busy; - -/* Inode map. */ -EXTERN bitchunk_t inodemap[FS_BITMAP_CHUNKS(PFS_NR_INODES)]; - -#endif diff --git a/minix/fs/pfs/inode.c b/minix/fs/pfs/inode.c deleted file mode 100644 index b5918fbae..000000000 --- a/minix/fs/pfs/inode.c +++ /dev/null @@ -1,325 +0,0 @@ -/* 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 - * find_inode: retrieve pointer to inode in inode cache - * - */ - -#include "fs.h" - -static void addhash_inode(struct inode * const node); -static void unhash_inode(struct inode * const node); - - -/*===========================================================================* - * fs_putnode * - *===========================================================================*/ -int fs_putnode(ino_t ino_nr, unsigned int count) -{ -/* Find the inode specified by the request message and decrease its counter.*/ - struct inode *rip; - dev_t dev; - - rip = find_inode(ino_nr); - - if(!rip) { - printf("%s:%d put_inode: inode #%llu not found\n", __FILE__, - __LINE__, ino_nr); - panic("fs_putnode failed"); - } - - if (count > rip->i_count) { - printf("%s:%d put_inode: count too high: %d > %d\n", __FILE__, - __LINE__, count, rip->i_count); - panic("fs_putnode failed"); - } - - /* Decrease reference counter, but keep one reference; it will be consumed by - * put_inode(). */ - rip->i_count -= count - 1; - dev = rip->i_dev; - put_inode(rip); - if (rip->i_count == 0) put_block(dev, ino_nr); - return(OK); -} - - -/*===========================================================================* - * init_inode_cache * - *===========================================================================*/ -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[PFS_NR_INODES]; ++rip) { - rip->i_num = NO_ENTRY; - 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 * - *===========================================================================*/ -static void addhash_inode(struct inode * const node) -{ - int hashi = (int) (node->i_num & INODE_HASH_MASK); - - /* insert into hash table */ - LIST_INSERT_HEAD(&hash_inodes[hashi], node, i_hash); -} - - -/*===========================================================================* - * unhash_inode * - *===========================================================================*/ -static void unhash_inode(struct inode * const node) -{ - /* remove from hash table */ - LIST_REMOVE(node, i_hash); -} - - -/*===========================================================================* - * get_inode * - *===========================================================================*/ -struct inode *get_inode( - dev_t dev, /* device on which inode resides */ - ino_t numb /* inode number */ -) -{ -/* 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; - int hashi; - - hashi = (int) (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(NULL); - } - rip = TAILQ_FIRST(&unused_inodes); - - /* If not free unhash it */ - if (rip->i_num != NO_ENTRY) 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 * - *===========================================================================*/ -struct inode *find_inode(ino_t numb /* inode number */) -{ -/* Find the inode specified by the inode and device number. - */ - struct inode *rip; - int hashi; - - hashi = (int) (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(NULL); -} - - -/*===========================================================================* - * put_inode * - *===========================================================================*/ -void put_inode(rip) -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 == NULL) return; /* checking here is easier than in caller */ - - if (rip->i_count < 1) - panic("put_inode: i_count already below 1: %d", rip->i_count); - - if (--rip->i_count == 0) { /* i_count == 0 means no one is using it now */ - if (rip->i_nlinks == NO_LINK) { /* Are there links to this file? */ - /* no links, 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, (off_t) 0); - } - - if (rip->i_nlinks == NO_LINK) { - /* free, put at the front of the LRU list */ - unhash_inode(rip); - rip->i_num = NO_ENTRY; - rip->i_dev = NO_DEV; - rip->i_rdev = NO_DEV; - 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 * - *===========================================================================*/ -struct inode *alloc_inode(dev_t dev, mode_t bits, uid_t uid, gid_t gid) -{ -/* Allocate a free inode on 'dev', and return a pointer to it. */ - - register struct inode *rip; - bit_t b; - ino_t i_num; - int print_oos_msg = 1; - - b = alloc_bit(); - if (b == NO_BIT) { - err_code = ENOSPC; - if (print_oos_msg) - printf("PipeFS is out of inodes\n"); - print_oos_msg = 0; /* Don't repeat message */ - return(NULL); - } - i_num = (ino_t) b; - print_oos_msg = 1; - - - /* Try to acquire a slot in the inode table. */ - if ((rip = get_inode(dev, i_num)) == NULL) { - /* 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 = NO_LINK; /* initial no links */ - rip->i_uid = uid; /* set file user id */ - rip->i_gid = 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 * - *===========================================================================*/ -void wipe_inode(rip) -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. - */ - - rip->i_size = 0; - rip->i_update = ATIME | CTIME | MTIME; /* update all times later */ -} - - -/*===========================================================================* - * free_inode * - *===========================================================================*/ -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 >= PFS_NR_INODES) return; - b = (bit_t) rip->i_num; - free_bit(b); -} - - -/*===========================================================================* - * update_times * - *===========================================================================*/ -void update_times(rip) -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(NULL); - 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/minix/fs/pfs/inode.h b/minix/fs/pfs/inode.h deleted file mode 100644 index 75689c9e3..000000000 --- a/minix/fs/pfs/inode.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef __PFS_INODE_H__ -#define __PFS_INODE_H__ - -/* 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 */ - size_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)*/ - - dev_t i_dev; /* which device is the inode on */ - dev_t i_rdev; /* which special 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[PFS_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]; - -#endif diff --git a/minix/fs/pfs/link.c b/minix/fs/pfs/link.c deleted file mode 100644 index d8c7d1a77..000000000 --- a/minix/fs/pfs/link.c +++ /dev/null @@ -1,42 +0,0 @@ -#include "fs.h" - -/*===========================================================================* - * fs_trunc * - *===========================================================================*/ -int fs_trunc(ino_t ino_nr, off_t start, off_t end) -{ - struct inode *rip; - - if( (rip = find_inode(ino_nr)) == NULL) return(EINVAL); - - if (end != 0) return(EINVAL); /* creating holes is not supported */ - - return truncate_inode(rip, start); -} - - -/*===========================================================================* - * truncate_inode * - *===========================================================================*/ -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. - */ - - /* 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/minix/fs/pfs/main.c b/minix/fs/pfs/main.c deleted file mode 100644 index 09d7dde79..000000000 --- a/minix/fs/pfs/main.c +++ /dev/null @@ -1,75 +0,0 @@ -#include "fs.h" - -/* SEF functions and variables. */ -static void sef_local_startup(void); -static int sef_cb_init_fresh(int type, sef_init_info_t *info); -static void sef_cb_signal_handler(int signo); - -/*===========================================================================* - * main * - *===========================================================================*/ -int main(int argc, char *argv[]) -{ -/* This is the main routine of this service. */ - - /* SEF local startup. */ - env_setargs(argc, argv); - sef_local_startup(); - - /* The fsdriver library does the actual work here. */ - fsdriver_task(&pfs_table); - - return(OK); -} - -/*===========================================================================* - * sef_local_startup * - *===========================================================================*/ -static void sef_local_startup() -{ - /* Register init callbacks. */ - sef_setcb_init_fresh(sef_cb_init_fresh); - sef_setcb_init_restart(sef_cb_init_fail); - - /* No live update support for now. */ - - /* Register signal callbacks. */ - sef_setcb_signal_handler(sef_cb_signal_handler); - - /* Let SEF perform startup. */ - sef_startup(); -} - -/*===========================================================================* - * sef_cb_init_fresh * - *===========================================================================*/ -static int sef_cb_init_fresh(int type, sef_init_info_t *info) -{ -/* Initialize the pipe file server. */ - int i; - struct passwd *pw; - - /* Initialize main loop parameters. */ - busy = 0; /* Server is not 'busy' (i.e., inodes in use). */ - - /* Init inode table */ - for (i = 0; i < PFS_NR_INODES; ++i) { - inode[i].i_count = 0; - } - - init_inode_cache(); - buf_pool(); - - return(OK); -} - -/*===========================================================================* - * sef_cb_signal_handler * - *===========================================================================*/ -static void sef_cb_signal_handler(int signo) -{ - /* Only check for termination signal, ignore anything else. */ - if (signo != SIGTERM) return; - - fsdriver_terminate(); -} diff --git a/minix/fs/pfs/misc.c b/minix/fs/pfs/misc.c deleted file mode 100644 index 24aeb89cc..000000000 --- a/minix/fs/pfs/misc.c +++ /dev/null @@ -1,17 +0,0 @@ -#include "fs.h" - - -/*===========================================================================* - * fs_chmod * - *===========================================================================*/ -int fs_chmod(ino_t ino_nr, mode_t *mode) -{ - struct inode *rip; /* target inode */ - - if( (rip = find_inode(ino_nr)) == NULL) return(EINVAL); - - rip->i_mode = (rip->i_mode & ~ALL_MODES) | (*mode & ALL_MODES); - - *mode = rip->i_mode; /* return new mode */ - return OK; -} diff --git a/minix/fs/pfs/mount.c b/minix/fs/pfs/mount.c deleted file mode 100644 index 35636338b..000000000 --- a/minix/fs/pfs/mount.c +++ /dev/null @@ -1,35 +0,0 @@ -#include "fs.h" -#include "glo.h" - - -/*===========================================================================* - * fs_mount * - *===========================================================================*/ -int fs_mount(dev_t __unused dev, unsigned int __unused flags, - struct fsdriver_node *node, unsigned int *res_flags) -{ -/* Mount Pipe File Server. */ - - /* This function does not do much. PFS has no root node, and VFS will ignore - * the returned node details anyway. The whole idea is to provide symmetry - * with other file systems, thus keeping libfsdriver simple and free of - * special cases. Everything else (e.g., mounting PFS in VFS) is already an - * exception anyway. - */ - memset(node, 0, sizeof(*node)); - *res_flags = 0; - - return(OK); -} - - -/*===========================================================================* - * fs_unmount * - *===========================================================================*/ -void fs_unmount(void) -{ -/* Unmount Pipe File Server. */ - - if (busy) - printf("PFS: unmounting while busy!\n"); /* nothing we can do anyway */ -} diff --git a/minix/fs/pfs/open.c b/minix/fs/pfs/open.c deleted file mode 100644 index e3308fc81..000000000 --- a/minix/fs/pfs/open.c +++ /dev/null @@ -1,42 +0,0 @@ -#include "fs.h" - - -/*===========================================================================* - * fs_newnode * - *===========================================================================*/ -int fs_newnode(mode_t mode, uid_t uid, gid_t gid, dev_t dev, - struct fsdriver_node *node) -{ - register int r = OK; - struct inode *rip; - - /* Try to allocate the inode */ - if( (rip = alloc_inode(dev, mode, uid, gid) ) == NULL) return(err_code); - - switch (mode & S_IFMT) { - case S_IFBLK: - case S_IFCHR: - rip->i_rdev = dev; /* Major/minor dev numbers */ - break; - case S_IFIFO: - if ((get_block(dev, rip->i_num)) == NULL) - r = EIO; - break; - default: - r = EIO; /* Unsupported file type */ - } - - if (r != OK) { - free_inode(rip); - } else { - /* Fill in the fields of the response message */ - node->fn_ino_nr = rip->i_num; - node->fn_mode = rip->i_mode; - node->fn_size = rip->i_size; - node->fn_uid = rip->i_uid; - node->fn_gid = rip->i_gid; - node->fn_dev = dev; - } - - return(r); -} diff --git a/minix/fs/pfs/pfs.c b/minix/fs/pfs/pfs.c new file mode 100644 index 000000000..52750a728 --- /dev/null +++ b/minix/fs/pfs/pfs.c @@ -0,0 +1,437 @@ +/* PFS - Pipe File Server */ + +#include +#include +#include +#include + +/* + * The following constant defines the number of inodes in PFS, which is + * therefore the maximum number of open pipes and cloned devices that can be + * used in the entire system. If anything, it should be kept somewhat in sync + * with VFS's maximum number of inodes. In the future, inodes could be + * allocated dynamically, but this will require extra infrastructure. + */ +#define PFS_NR_INODES 512 /* maximum number of inodes in PFS */ + +/* The following bits can be combined in the inode's i_update field. */ +#define ATIME 0x1 /* update access time later */ +#define MTIME 0x2 /* update modification time later */ +#define CTIME 0x4 /* update change time later */ + +static struct inode { + ino_t i_num; /* inode number */ + + mode_t i_mode; /* file mode and permissions */ + uid_t i_uid; /* user ID of the file's owner */ + gid_t i_gid; /* group ID of the file's owner */ + size_t i_size; /* current file size in bytes */ + dev_t i_rdev; /* device number for device nodes */ + time_t i_atime; /* file access time */ + time_t i_mtime; /* file modification time */ + time_t i_ctime; /* file change time */ + + char *i_data; /* data buffer, for pipes only */ + size_t i_start; /* start of data into data buffer */ + + unsigned char i_update; /* which file times to update? */ + unsigned char i_free; /* sanity check: is the inode free? */ + + LIST_ENTRY(inode) i_next; /* next element in free list */ +} inode[PFS_NR_INODES]; + +static LIST_HEAD(, inode) free_inodes; /* list of free inodes */ + +/* + * Mount the pipe file server. + */ +static int +pfs_mount(dev_t __unused dev, unsigned int __unused flags, + struct fsdriver_node * node, unsigned int * res_flags) +{ + struct inode *rip; + unsigned int i; + + LIST_INIT(&free_inodes); /* initialize the free list */ + + /* + * Initialize the inode table. We walk backwards so that the lowest + * inode numbers end up being used first. Silly? Sure, but aesthetics + * are worth something, too.. + */ + for (i = PFS_NR_INODES; i > 0; i--) { + rip = &inode[i - 1]; + + /* Inode number 0 is reserved. See also pfs_findnode. */ + rip->i_num = i; + rip->i_free = TRUE; + + LIST_INSERT_HEAD(&free_inodes, rip, i_next); + } + + /* + * PFS has no root node, and VFS will ignore the returned node details + * anyway. The whole idea is to provide symmetry with other file + * systems, thus keeping libfsdriver simple and free of special cases. + */ + memset(node, 0, sizeof(*node)); + *res_flags = RES_64BIT; + + return OK; +} + +/* + * Unmount the pipe file server. + */ +static void +pfs_unmount(void) +{ + unsigned int i; + + /* Warn about in-use inodes. There's nothing else we can do. */ + for (i = 0; i < PFS_NR_INODES; i++) + if (inode[i].i_free == FALSE) + break; + + if (i < PFS_NR_INODES) + printf("PFS: unmounting while busy!\n"); +} + +/* + * Find the node with the corresponding inode number. It must be in use. + */ +static struct inode * +pfs_findnode(ino_t ino_nr) +{ + struct inode *rip; + + /* Inode numbers are 1-based, because inode number 0 is reserved. */ + if (ino_nr < 1 || ino_nr > PFS_NR_INODES) + return NULL; + + rip = &inode[ino_nr - 1]; + assert(rip->i_num == ino_nr); + + if (rip->i_free == TRUE) + return NULL; + + return rip; +} + +/* + * Create a new, unlinked node. It must be either a pipe or a device file. + */ +static int +pfs_newnode(mode_t mode, uid_t uid, gid_t gid, dev_t dev, + struct fsdriver_node * node) +{ + struct inode *rip; + char *data; + int isfifo, isdev; + + /* Check the file type. Do we support it at all? */ + isfifo = S_ISFIFO(mode); + isdev = S_ISBLK(mode) || S_ISCHR(mode); + + if (!isfifo && !isdev) + return EINVAL; /* this means VFS is misbehaving.. */ + + /* Is there a free inode? */ + if (LIST_EMPTY(&free_inodes)) + return ENFILE; + + /* For pipes, we need a buffer. Try to allocate one. */ + data = NULL; + if (isfifo && (data = malloc(PIPE_BUF)) == NULL) + return ENOSPC; + + /* Nothing can go wrong now. Take an inode off the free list. */ + rip = LIST_FIRST(&free_inodes); + LIST_REMOVE(rip, i_next); + + assert(rip->i_free == TRUE); + rip->i_free = FALSE; /* this is for sanity checks only */ + + /* Initialize the inode's fields. */ + rip->i_mode = mode; + rip->i_uid = uid; + rip->i_gid = gid; + rip->i_size = 0; + rip->i_update = ATIME | MTIME | CTIME; + if (isdev) + rip->i_rdev = dev; + else + rip->i_rdev = NO_DEV; + rip->i_data = data; + rip->i_start = 0; + + /* Fill in the fields of the response message. */ + node->fn_ino_nr = rip->i_num; + node->fn_mode = rip->i_mode; + node->fn_size = rip->i_size; + node->fn_uid = rip->i_uid; + node->fn_gid = rip->i_gid; + node->fn_dev = rip->i_rdev; + + return OK; +} + +/* + * Close a node. + */ +static int +pfs_putnode(ino_t ino_nr, unsigned int count) +{ + struct inode *rip; + + if ((rip = pfs_findnode(ino_nr)) == NULL) + return EINVAL; + + /* + * Since the new-node call is the only way to open an inode, and there + * is no way to increase the use count of an already-opened inode, we + * can safely assume that the reference count will only ever be one. + * That also means we are always freeing up the target inode here. + */ + if (count != 1) + return EINVAL; + + /* For pipes, free the inode data buffer. */ + if (rip->i_data != NULL) + free(rip->i_data); + + /* Return the inode to the free list. */ + rip->i_free = TRUE; + + LIST_INSERT_HEAD(&free_inodes, rip, i_next); + + return OK; +} + +/* + * Read from a pipe. + */ +static ssize_t +pfs_read(ino_t ino_nr, struct fsdriver_data * data, size_t bytes, + off_t __unused pos, int __unused call) +{ + struct inode *rip; + int r; + + /* The target node must be a pipe. */ + if ((rip = pfs_findnode(ino_nr)) == NULL || !S_ISFIFO(rip->i_mode)) + return EINVAL; + + /* We can't read beyond the maximum file position. */ + if (bytes > PIPE_BUF) + return EFBIG; + + /* Limit the request to how much is in the pipe. */ + if (bytes > rip->i_size) + bytes = rip->i_size; + + /* Copy the data to user space. */ + if ((r = fsdriver_copyout(data, 0, rip->i_data + rip->i_start, + bytes)) != OK) + return r; + + /* Update file size and access time. */ + rip->i_size -= bytes; + rip->i_start += bytes; + rip->i_update |= ATIME; + + /* Return the number of bytes transferred. */ + return bytes; +} + +/* + * Write to a pipe. + */ +static ssize_t +pfs_write(ino_t ino_nr, struct fsdriver_data * data, size_t bytes, + off_t __unused pos, int __unused call) +{ + struct inode *rip; + int r; + + /* The target node must be a pipe. */ + if ((rip = pfs_findnode(ino_nr)) == NULL || !S_ISFIFO(rip->i_mode)) + return EINVAL; + + /* Check in advance to see if file will grow too big. */ + if (rip->i_size + bytes > PIPE_BUF) + return EFBIG; + + /* + * Move any previously remaining data to the front of the buffer. + * Doing so upon writes rather than reads saves on memory moves when + * there are many small reads. Not using the buffer circularly saves + * on kernel calls. + */ + if (rip->i_start > 0) { + if (rip->i_size > 0) + memmove(rip->i_data, rip->i_data + rip->i_start, + rip->i_size); + + rip->i_start = 0; + } + + /* Copy the data from user space. */ + r = fsdriver_copyin(data, 0, rip->i_data + rip->i_size, bytes); + if (r != OK) + return r; + + /* Update file size and times. */ + rip->i_size += bytes; + rip->i_update |= CTIME | MTIME; + + /* Return the number of bytes transferred. */ + return bytes; +} + +/* + * Truncate a pipe. + */ +static int +pfs_trunc(ino_t ino_nr, off_t start_pos, off_t end_pos) +{ + struct inode *rip; + + /* The target node must be a pipe. */ + if ((rip = pfs_findnode(ino_nr)) == NULL || !S_ISFIFO(rip->i_mode)) + return EINVAL; + + /* We only support full truncation of pipes. */ + if (start_pos != 0 || end_pos != 0) + return EINVAL; + + /* Update file size and times. */ + rip->i_size = 0; + rip->i_update |= CTIME | MTIME; + + return OK; +} + +/* + * Return node status. + */ +static int +pfs_stat(ino_t ino_nr, struct stat * statbuf) +{ + struct inode *rip; + time_t now; + + if ((rip = pfs_findnode(ino_nr)) == NULL) + return EINVAL; + + /* Update the time fields in the inode, if need be. */ + if (rip->i_update != 0) { + now = clock_time(NULL); + + if (rip->i_update & ATIME) rip->i_atime = now; + if (rip->i_update & MTIME) rip->i_mtime = now; + if (rip->i_update & CTIME) rip->i_ctime = now; + + rip->i_update = 0; + } + + /* Fill the stat buffer. */ + statbuf->st_dev = rip->i_rdev; /* workaround for old socketpair bug */ + statbuf->st_ino = rip->i_num; + statbuf->st_mode = rip->i_mode; + statbuf->st_nlink = 0; + statbuf->st_uid = rip->i_uid; + statbuf->st_gid = rip->i_gid; + statbuf->st_rdev = rip->i_rdev; + statbuf->st_size = rip->i_size; + statbuf->st_atime = rip->i_atime; + statbuf->st_mtime = rip->i_mtime; + statbuf->st_ctime = rip->i_ctime; + statbuf->st_blksize = PIPE_BUF; + statbuf->st_blocks = howmany(rip->i_size, S_BLKSIZE); + + return OK; +} + +/* + * Change node permissions. + */ +static int +pfs_chmod(ino_t ino_nr, mode_t * mode) +{ + struct inode *rip; + + if ((rip = pfs_findnode(ino_nr)) == NULL) + return EINVAL; + + /* Update file mode and times. */ + rip->i_mode = (rip->i_mode & ~ALLPERMS) | (*mode & ALLPERMS); + rip->i_update |= MTIME | CTIME; + + *mode = rip->i_mode; + return OK; +} + +/* + * Process a signal. + */ +static void +pfs_signal(int signo) +{ + + /* Only check for termination signal, ignore anything else. */ + if (signo != SIGTERM) return; + + fsdriver_terminate(); +} + +/* + * Perform SEF initialization. + */ +static void +pfs_startup(void) +{ + + /* Register initialization callbacks. */ + sef_setcb_init_fresh(sef_cb_init_null); + sef_setcb_init_restart(sef_cb_init_fail); + + /* No live update support for now. */ + + /* Register signal callbacks. */ + sef_setcb_signal_handler(pfs_signal); + + /* Let SEF perform startup. */ + sef_startup(); +} + +/* + * Function call table for the fsdriver library. + */ +static struct fsdriver pfs_table = { + .fdr_mount = pfs_mount, + .fdr_unmount = pfs_unmount, + .fdr_newnode = pfs_newnode, + .fdr_putnode = pfs_putnode, + .fdr_read = pfs_read, + .fdr_write = pfs_write, + .fdr_trunc = pfs_trunc, + .fdr_stat = pfs_stat, + .fdr_chmod = pfs_chmod +}; + +/* + * The main routine of this service. + */ +int +main(void) +{ + + /* Local startup. */ + pfs_startup(); + + /* The fsdriver library does the actual work here. */ + fsdriver_task(&pfs_table); + + return EXIT_SUCCESS; +} diff --git a/minix/fs/pfs/proto.h b/minix/fs/pfs/proto.h deleted file mode 100644 index 3569551e5..000000000 --- a/minix/fs/pfs/proto.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef __PFS_PROTO_H__ -#define __PFS_PROTO_H__ - -/* Function prototypes. */ - -/* Structs used in prototypes must be declared as such first. */ -struct buf; -struct inode; - -/* buffer.c */ -struct buf *get_block(dev_t dev, ino_t inum); -void put_block(dev_t dev, ino_t inum); -void buf_pool(void); - -/* inode.c */ -struct inode *alloc_inode(dev_t dev, mode_t mode, uid_t uid, gid_t gid); -void dup_inode(struct inode *ip); -struct inode *find_inode(ino_t numb); -void free_inode(struct inode *rip); -int fs_putnode(ino_t ino_nr, unsigned int count); -void init_inode_cache(void); -struct inode *get_inode(dev_t dev, ino_t numb); -void put_inode(struct inode *rip); -void update_times(struct inode *rip); -void wipe_inode(struct inode *rip); - -/* link.c */ -int fs_trunc(ino_t ino_nr, off_t start, off_t end); -int truncate_inode(struct inode *rip, off_t newsize); - -/* misc.c */ -int fs_chmod(ino_t ino_nr, mode_t *mode); - -/* mount.c */ -int fs_mount(dev_t dev, unsigned int flags, struct fsdriver_node *node, - unsigned int *res_flags); -void fs_unmount(void); - -/* open.c */ -int fs_newnode(mode_t mode, uid_t uid, gid_t gid, dev_t dev, - struct fsdriver_node *node); - -/* read.c */ -ssize_t fs_read(ino_t ino_nr, struct fsdriver_data *data, size_t bytes, - off_t pos, int call); -ssize_t fs_write(ino_t ino_nr, struct fsdriver_data *data, size_t bytes, - off_t pos, int call); - -/* stadir.c */ -int fs_stat(ino_t ino_nr, struct stat *statbuf); - -/* super.c */ -bit_t alloc_bit(void); -void free_bit(bit_t bit_returned); - -#endif diff --git a/minix/fs/pfs/read.c b/minix/fs/pfs/read.c deleted file mode 100644 index db4b77600..000000000 --- a/minix/fs/pfs/read.c +++ /dev/null @@ -1,85 +0,0 @@ -#include "fs.h" - - -/*===========================================================================* - * fs_read * - *===========================================================================*/ -ssize_t fs_read(ino_t ino_nr, struct fsdriver_data *data, size_t bytes, - off_t __unused pos, int call) -{ - int r; - struct buf *bp; - struct inode *rip; - - /* Find the inode referred */ - if ((rip = find_inode(ino_nr)) == NULL) return(EINVAL); - - if (!S_ISFIFO(rip->i_mode)) return(EIO); - - /* We can't read or write beyond the max file position */ - if (bytes > PIPE_BUF) return(EFBIG); - - if (bytes > rip->i_size) { - /* There aren't that many bytes to read */ - bytes = rip->i_size; - } - - /* Copy a chunk from the block buffer to user space. */ - if ((bp = get_block(rip->i_dev, rip->i_num)) == NULL) return(err_code); - - r = fsdriver_copyout(data, 0, bp->b_data, bytes); - - if (r == OK && rip->i_size > bytes) { - /* Move any remaining data to the front of the buffer. */ - /* FIXME: see if this really is the optimal strategy. */ - memmove(bp->b_data, bp->b_data + bytes, rip->i_size - bytes); - } - - put_block(rip->i_dev, rip->i_num); - - if (r != OK) - return r; - - /* Update file size and access time. */ - rip->i_size -= bytes; - rip->i_update |= ATIME; - - return(bytes); -} - - -/*===========================================================================* - * fs_write * - *===========================================================================*/ -ssize_t fs_write(ino_t ino_nr, struct fsdriver_data *data, size_t bytes, - off_t __unused pos, int __unused call) -{ - int r; - struct buf *bp; - struct inode *rip; - - /* Find the inode referred */ - if ((rip = find_inode(ino_nr)) == NULL) return(EINVAL); - - if (!S_ISFIFO(rip->i_mode)) return(EIO); - - /* Check in advance to see if file will grow too big. */ - if (rip->i_size + bytes > PIPE_BUF) - return(EFBIG); - - /* Copy the data from user space to the block buffer. */ - if ((bp = get_block(rip->i_dev, rip->i_num)) == NULL) return(err_code); - - r = fsdriver_copyin(data, 0, bp->b_data + rip->i_size, bytes); - - put_block(rip->i_dev, rip->i_num); - - if (r != OK) - return r; - - /* Update file size and file times. */ - rip->i_size += bytes; - rip->i_update |= CTIME | MTIME; - - return(bytes); -} diff --git a/minix/fs/pfs/stadir.c b/minix/fs/pfs/stadir.c deleted file mode 100644 index 127ff60bf..000000000 --- a/minix/fs/pfs/stadir.c +++ /dev/null @@ -1,42 +0,0 @@ -#include "fs.h" - - -/*===========================================================================* - * fs_stat * - *===========================================================================*/ -int fs_stat(ino_t ino_nr, struct stat *statbuf) -{ - struct inode *rip; - mode_t type; - u32_t blocks; /* The unit of this is 512 */ - int s; - - if ((rip = find_inode(ino_nr)) == NULL) return(EINVAL); - - type = rip->i_mode & I_TYPE; - s = (type == I_CHAR_SPECIAL || type == I_BLOCK_SPECIAL); - - /* Update the atime, ctime, and mtime fields in the inode, if need be. */ - if (rip->i_update) update_times(rip); - - blocks = rip->i_size / S_BLKSIZE; - if (rip->i_size % S_BLKSIZE != 0) - blocks += 1; - - 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 = (short int) rip->i_gid; - statbuf->st_rdev = (s ? rip->i_rdev : NO_DEV); - statbuf->st_size = rip->i_size; - if (!s) 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; - statbuf->st_blksize = PIPE_BUF; - statbuf->st_blocks = blocks; - - return(OK); -} diff --git a/minix/fs/pfs/super.c b/minix/fs/pfs/super.c deleted file mode 100644 index d10702fa0..000000000 --- a/minix/fs/pfs/super.c +++ /dev/null @@ -1,72 +0,0 @@ -/* 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" - - -/*===========================================================================* - * alloc_bit * - *===========================================================================*/ -bit_t alloc_bit(void) -{ -/* Allocate a bit from a bit map and return its bit number. */ - bitchunk_t *wptr, *wlim; - bit_t b; - unsigned int i, bcount; - - bcount = FS_BITMAP_CHUNKS(PFS_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 = (bit_t) ((wptr - &inodemap[0]) * FS_BITCHUNK_BITS + i); - - /* Don't allocate bits beyond end of map. */ - if (b >= PFS_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 * - *===========================================================================*/ -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 = (unsigned) (bit_returned / (bit_t) FS_BITCHUNK_BITS); - bit = bit_returned % (bit_t) FS_BITCHUNK_BITS; - - /* Unset bit */ - k = &inodemap[word]; - mask = (unsigned) 1 << bit; - *k &= ~mask; - - busy--; /* One inode less in use. */ -} diff --git a/minix/fs/pfs/table.c b/minix/fs/pfs/table.c deleted file mode 100644 index 5cad1c172..000000000 --- a/minix/fs/pfs/table.c +++ /dev/null @@ -1,21 +0,0 @@ - -/* This file contains the table used to map VFS/FS call numbers onto the - * routines that perform them. - */ - -#define _TABLE - -#include "fs.h" - -/* File System Handlers (pfs) */ -struct fsdriver pfs_table = { - .fdr_mount = fs_mount, - .fdr_unmount = fs_unmount, - .fdr_newnode = fs_newnode, - .fdr_putnode = fs_putnode, - .fdr_read = fs_read, - .fdr_write = fs_write, - .fdr_trunc = fs_trunc, - .fdr_stat = fs_stat, - .fdr_chmod = fs_chmod -};