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
This commit is contained in:
parent
f859061eaf
commit
30d9b70391
19 changed files with 438 additions and 1050 deletions
|
@ -1,7 +1,6 @@
|
||||||
# Makefile for Pipe File System (PFS)
|
# Makefile for Pipe File System (PFS)
|
||||||
PROG= pfs
|
PROG= pfs
|
||||||
SRCS= open.c table.c inode.c main.c super.c link.c \
|
SRCS= pfs.c
|
||||||
buffer.c read.c misc.c mount.c stadir.c
|
|
||||||
|
|
||||||
DPADD+= ${LIBFSDRIVER} ${LIBSYS}
|
DPADD+= ${LIBFSDRIVER} ${LIBSYS}
|
||||||
LDADD+= -lfsdriver -lsys
|
LDADD+= -lfsdriver -lsys
|
||||||
|
|
|
@ -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
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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<<INODE_HASH_LOG2)
|
|
||||||
#define INODE_HASH_MASK (((unsigned long)1<<INODE_HASH_LOG2)-1)
|
|
||||||
|
|
||||||
#define NO_BIT ((bit_t) 0) /* returned by alloc_bit() to signal failure */
|
|
||||||
|
|
||||||
#define ATIME 002 /* set if atime field needs updating */
|
|
||||||
#define CTIME 004 /* set if ctime field needs updating */
|
|
||||||
#define MTIME 010 /* set if mtime field needs updating */
|
|
||||||
|
|
||||||
#define FS_BITMAP_CHUNKS(b) ((b)/sizeof (bitchunk_t))/* # map chunks/blk */
|
|
||||||
#define FS_BITCHUNK_BITS (sizeof(bitchunk_t) * CHAR_BIT)
|
|
||||||
#define FS_BITS_PER_BLOCK(b) (FS_BITMAP_CHUNKS(b) * FS_BITCHUNK_BITS)
|
|
||||||
|
|
||||||
#define FS_CALL_VEC_SIZE 31
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,33 +0,0 @@
|
||||||
#ifndef __PFS_FS_H__
|
|
||||||
#define __PFS_FS_H__
|
|
||||||
|
|
||||||
/* This is the master header for fs. It includes some other files
|
|
||||||
* and defines the principal constants.
|
|
||||||
*/
|
|
||||||
#define _SYSTEM 1 /* tell headers that this is the kernel */
|
|
||||||
|
|
||||||
/* The following are so basic, all the *.c files get them automatically. */
|
|
||||||
#include <minix/config.h> /* MUST be first */
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <minix/const.h>
|
|
||||||
#include <minix/type.h>
|
|
||||||
|
|
||||||
#include <lib.h>
|
|
||||||
#include <minix/syslib.h>
|
|
||||||
#include <minix/sysutil.h>
|
|
||||||
|
|
||||||
#include <minix/fsdriver.h>
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
#include "const.h"
|
|
||||||
#include "proto.h"
|
|
||||||
#include "glo.h"
|
|
||||||
#include "buf.h"
|
|
||||||
#include "inode.h"
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -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
|
|
|
@ -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 */
|
|
||||||
}
|
|
|
@ -1,37 +0,0 @@
|
||||||
#ifndef __PFS_INODE_H__
|
|
||||||
#define __PFS_INODE_H__
|
|
||||||
|
|
||||||
/* Inode table. This table holds inodes that are currently in use.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <sys/queue.h>
|
|
||||||
|
|
||||||
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
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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 */
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
437
minix/fs/pfs/pfs.c
Normal file
437
minix/fs/pfs/pfs.c
Normal file
|
@ -0,0 +1,437 @@
|
||||||
|
/* PFS - Pipe File Server */
|
||||||
|
|
||||||
|
#include <minix/drivers.h>
|
||||||
|
#include <minix/fsdriver.h>
|
||||||
|
#include <minix/vfsif.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
|
@ -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
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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. */
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
};
|
|
Loading…
Reference in a new issue