libvtreefs: use libfsdriver

Change-Id: I0e6446bd0ccc3b89edc237be441ebfd92585f352
This commit is contained in:
David van Moolenbroek 2014-08-24 09:55:05 +00:00
parent 81db4f2cff
commit 0dc5c83ec2
18 changed files with 192 additions and 667 deletions

View file

@ -2,8 +2,8 @@
PROG= gpio PROG= gpio
SRCS= gpio.c SRCS= gpio.c
DPADD+= ${LIBBLOCKDRIVER} ${LIBSYS} ${LIBGPIO} ${LIBCLKCONF} DPADD+= ${LIBVTREEFS} ${LIBFSDRIVER} ${LIBSYS} ${LIBGPIO} ${LIBCLKCONF}
LDADD+= -lvtreefs -lsys -lgpio -lclkconf LDADD+= -lvtreefs -lfsdriver -lsys -lgpio -lclkconf
# This is a system driver. # This is a system driver.
CPPFLAGS+= -D_SYSTEM=1 CPPFLAGS+= -D_SYSTEM=1

View file

@ -8,7 +8,7 @@ CPPFLAGS+= -I${NETBSDSRCDIR}/minix
CPPFLAGS+= -I${NETBSDSRCDIR}/minix/fs CPPFLAGS+= -I${NETBSDSRCDIR}/minix/fs
CPPFLAGS+= -I${NETBSDSRCDIR}/minix/servers CPPFLAGS+= -I${NETBSDSRCDIR}/minix/servers
DPADD+= ${LIBVTREEFS} ${LIBMINIXFS} DPADD+= ${LIBVTREEFS} ${LIBFSDRIVER}
LDADD+= -lvtreefs -lminixfs LDADD+= -lvtreefs -lfsdriver
.include <minix.service.mk> .include <minix.service.mk>

View file

@ -89,7 +89,7 @@ int main(void)
stat.size = 0; stat.size = 0;
stat.dev = NO_DEV; stat.dev = NO_DEV;
/* Start VTreeFS. This call does not return. */ /* Start VTreeFS. */
start_vtreefs(&hooks, NR_INODES, &stat, NR_PROCS + NR_TASKS); start_vtreefs(&hooks, NR_INODES, &stat, NR_PROCS + NR_TASKS);
return 0; return 0;

View file

@ -1,9 +1,9 @@
NOGCCERROR=yes
NOCLANGERROR=yes
CPPFLAGS+= -D_MINIX_SYSTEM
# Makefile for libvtreefs # Makefile for libvtreefs
NOGCCERROR=yes
CPPFLAGS+= -D_MINIX_SYSTEM
LIB= vtreefs LIB= vtreefs
CPPFLAGS+= -I${NETBSDSRCDIR}/include CPPFLAGS+= -I${NETBSDSRCDIR}/include
@ -17,7 +17,6 @@ SRCS= \
sdbm.c \ sdbm.c \
stadir.c \ stadir.c \
table.c \ table.c \
utility.c \
vtreefs.c vtreefs.c
.include <bsd.lib.mk> .include <bsd.lib.mk>

View file

@ -8,13 +8,8 @@
EXTERN struct fs_hooks *vtreefs_hooks; EXTERN struct fs_hooks *vtreefs_hooks;
EXTERN message fs_m_in;
EXTERN message fs_m_out;
EXTERN dev_t fs_dev; EXTERN dev_t fs_dev;
EXTERN int fs_mounted; extern struct fsdriver vtreefs_table;
extern int(*fs_call_vec[]) (void);
#endif /* _VTREEFS_GLO_H */ #endif /* _VTREEFS_GLO_H */

View file

@ -1,29 +1,8 @@
#define _SYSTEM 1 /* tell headers that this is the kernel */ #include <minix/drivers.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/queue.h>
#include <sys/ucred.h>
#include <limits.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <minix/config.h>
#include <minix/callnr.h>
#include <minix/type.h>
#include <minix/const.h>
#include <minix/com.h>
#include <minix/syslib.h>
#include <minix/sysutil.h>
#include <minix/bitmap.h>
#include <minix/vfsif.h>
#include <minix/endpoint.h>
#include <minix/vtreefs.h> #include <minix/vtreefs.h>
#include <minix/fsdriver.h>
#include <assert.h>
#include "glo.h" #include "glo.h"
#include "proto.h" #include "proto.h"

View file

@ -33,7 +33,7 @@ void init_inodes(unsigned int inodes, struct inode_stat *stat,
/* Initialize the inode-related state. /* Initialize the inode-related state.
*/ */
struct inode *node; struct inode *node;
int i; unsigned int i;
assert(inodes > 0); assert(inodes > 0);
assert(nr_indexed_entries >= 0); assert(nr_indexed_entries >= 0);
@ -134,7 +134,7 @@ static int parent_index_hash(struct inode *parent, index_t index)
/*===========================================================================* /*===========================================================================*
* purge_inode * * purge_inode *
*===========================================================================*/ *===========================================================================*/
void purge_inode(struct inode *parent) static void purge_inode(struct inode *parent)
{ {
/* Delete a deletable inode to make room for a new inode. /* Delete a deletable inode to make room for a new inode.
*/ */
@ -149,7 +149,7 @@ void purge_inode(struct inode *parent)
*/ */
static int last_checked = 0; static int last_checked = 0;
struct inode *node; struct inode *node;
int count; unsigned int count;
assert(TAILQ_EMPTY(&unused_inodes)); assert(TAILQ_EMPTY(&unused_inodes));
@ -484,7 +484,6 @@ void ref_inode(struct inode *node)
*/ */
CHECK_INODE(node); CHECK_INODE(node);
assert(node->i_count >= 0);
node->i_count++; node->i_count++;
} }
@ -581,7 +580,7 @@ int is_inode_deleted(struct inode *node)
/*===========================================================================* /*===========================================================================*
* fs_putnode * * fs_putnode *
*===========================================================================*/ *===========================================================================*/
int fs_putnode(void) int fs_putnode(ino_t ino_nr, unsigned int count)
{ {
/* Find the inode specified by the request message, and decrease its /* Find the inode specified by the request message, and decrease its
* reference count. * reference count.
@ -589,14 +588,13 @@ int fs_putnode(void)
struct inode *node; struct inode *node;
/* Get the inode specified by its number. */ /* Get the inode specified by its number. */
if ((node = find_inode(fs_m_in.m_vfs_fs_putnode.inode)) == NULL) if ((node = find_inode(ino_nr)) == NULL)
return EINVAL; return EINVAL;
/* Decrease the reference count. */ /* Decrease the reference count. */
node->i_count -= fs_m_in.m_vfs_fs_putnode.count - 1; assert(node->i_count >= count);
assert(node->i_count > 0);
node->i_count -= count - 1;
put_inode(node); put_inode(node);
return OK; return OK;

View file

@ -18,7 +18,7 @@ struct inode {
/* Inode metadata */ /* Inode metadata */
struct inode_stat i_stat; /* POSIX attributes */ struct inode_stat i_stat; /* POSIX attributes */
char i_name[PNAME_MAX + 1]; /* name of the inode in the parent */ char i_name[PNAME_MAX + 1]; /* name of the inode in the parent */
int i_count; /* reference count */ unsigned int i_count; /* reference count */
index_t i_index; /* index number in parent / NO_INDEX */ index_t i_index; /* index number in parent / NO_INDEX */
int i_indexed; /* number of indexed entries */ int i_indexed; /* number of indexed entries */
cbdata_t i_cbdata; /* callback data */ cbdata_t i_cbdata; /* callback data */

View file

@ -5,7 +5,7 @@
/*===========================================================================* /*===========================================================================*
* fs_rdlink * * fs_rdlink *
*===========================================================================*/ *===========================================================================*/
int fs_rdlink(void) ssize_t fs_rdlink(ino_t ino_nr, struct fsdriver_data *data, size_t bytes)
{ {
/* Retrieve symbolic link target. /* Retrieve symbolic link target.
*/ */
@ -14,7 +14,7 @@ int fs_rdlink(void)
size_t len; size_t len;
int r; int r;
if ((node = find_inode(fs_m_in.m_vfs_fs_rdlink.inode)) == NULL) if ((node = find_inode(ino_nr)) == NULL)
return EINVAL; return EINVAL;
/* Call the rdlink hook. */ /* Call the rdlink hook. */
@ -28,14 +28,12 @@ int fs_rdlink(void)
len = strlen(path); len = strlen(path);
assert(len > 0 && len < sizeof(path)); assert(len > 0 && len < sizeof(path));
if (len > fs_m_in.m_vfs_fs_rdlink.mem_size) if (len > bytes)
len = fs_m_in.m_vfs_fs_rdlink.mem_size; len = bytes;
/* Copy out the result. */ /* Copy out the result. */
r = sys_safecopyto(fs_m_in.m_source, fs_m_in.m_vfs_fs_rdlink.grant, 0, if ((r = fsdriver_copyout(data, 0, path, len)) != OK)
(vir_bytes) path, len); return r;
if (r != OK) return r;
fs_m_out.m_fs_vfs_rdlink.nbytes = len; return len;
return OK;
} }

View file

@ -1,21 +1,23 @@
/* VTreeFS - mount.c - by Alen Stojanov and David van Moolenbroek */ /* VTreeFS - mount.c - by Alen Stojanov and David van Moolenbroek */
#include "inc.h" #include "inc.h"
#include <minix/vfsif.h>
/*===========================================================================* /*===========================================================================*
* fs_readsuper * * fs_mount *
*===========================================================================*/ *===========================================================================*/
int fs_readsuper(void) int fs_mount(dev_t dev, unsigned int flags, struct fsdriver_node *root_node,
unsigned int *res_flags)
{ {
/* This function gets the root inode and sends back its details. /* This function gets the root inode and sends back its details.
*/ */
struct inode *root; struct inode *root;
/* Get the device number, for stat requests. */ /* Get the device number, for stat requests. */
fs_dev = fs_m_in.m_vfs_fs_readsuper.device; fs_dev = dev;
/* The VTreeFS must not be mounted as a root file system. */ /* The VTreeFS must not be mounted as a root file system. */
if (fs_m_in.m_vfs_fs_readsuper.flags & REQ_ISROOT) if (flags & REQ_ISROOT)
return EINVAL; return EINVAL;
/* Get the root inode and increase its reference count. */ /* Get the root inode and increase its reference count. */
@ -27,15 +29,14 @@ int fs_readsuper(void)
vtreefs_hooks->init_hook(); vtreefs_hooks->init_hook();
/* Return the root inode's properties. */ /* Return the root inode's properties. */
fs_m_out.m_fs_vfs_readsuper.inode = get_inode_number(root); root_node->fn_ino_nr = get_inode_number(root);
fs_m_out.m_fs_vfs_readsuper.mode = root->i_stat.mode; root_node->fn_mode = root->i_stat.mode;
fs_m_out.m_fs_vfs_readsuper.file_size = root->i_stat.size; root_node->fn_size = root->i_stat.size;
fs_m_out.m_fs_vfs_readsuper.uid = root->i_stat.uid; root_node->fn_uid = root->i_stat.uid;
fs_m_out.m_fs_vfs_readsuper.gid = root->i_stat.gid; root_node->fn_gid = root->i_stat.gid;
fs_m_out.m_fs_vfs_readsuper.device = NO_DEV; root_node->fn_dev = NO_DEV;
fs_m_out.m_fs_vfs_readsuper.flags = RES_NOFLAGS;
fs_mounted = TRUE; *res_flags = RES_NOFLAGS;
return OK; return OK;
} }
@ -43,7 +44,7 @@ int fs_readsuper(void)
/*===========================================================================* /*===========================================================================*
* fs_unmount * * fs_unmount *
*===========================================================================*/ *===========================================================================*/
int fs_unmount(void) void fs_unmount(void)
{ {
/* Unmount the file system. /* Unmount the file system.
*/ */
@ -57,9 +58,4 @@ int fs_unmount(void)
/* The system is unmounted. Call the cleanup hook. */ /* The system is unmounted. Call the cleanup hook. */
if (vtreefs_hooks->cleanup_hook != NULL) if (vtreefs_hooks->cleanup_hook != NULL)
vtreefs_hooks->cleanup_hook(); vtreefs_hooks->cleanup_hook();
/* We can now be shut down safely. */
fs_mounted = FALSE;
return OK;
} }

View file

@ -2,313 +2,59 @@
#include "inc.h" #include "inc.h"
/*===========================================================================*
* access_as_dir *
*===========================================================================*/
static int access_as_dir(struct inode *node, vfs_ucred_t *ucred)
{
/* Check whether the given inode may be accessed as directory.
* Return OK or an appropriate error code.
*/
mode_t mask;
int i;
/* The inode must be a directory to begin with. */
if (!S_ISDIR(node->i_stat.mode)) return ENOTDIR;
/* The caller must have search access to the directory.
* Root always does.
*/
if (ucred->vu_uid == SUPER_USER) return OK;
if (ucred->vu_uid == node->i_stat.uid) mask = S_IXUSR;
else if (ucred->vu_gid == node->i_stat.gid) mask = S_IXGRP;
else {
mask = S_IXOTH;
for (i = 0; i < ucred->vu_ngroups; i++) {
if (ucred->vu_sgroups[i] == node->i_stat.gid) {
mask = S_IXGRP;
break;
}
}
}
return (node->i_stat.mode & mask) ? OK : EACCES;
}
/*===========================================================================*
* next_name *
*===========================================================================*/
static int next_name(char **ptr, char **start, char name[PNAME_MAX+1])
{
/* Get the next path component from a path.
*/
char *p;
int i;
for (p = *ptr; *p == '/'; p++);
*start = p;
if (*p) {
for (i = 0; *p && *p != '/' && i <= PNAME_MAX; p++, i++)
name[i] = *p;
if (i > PNAME_MAX)
return ENAMETOOLONG;
name[i] = 0;
} else {
strcpy(name, ".");
}
*ptr = p;
return OK;
}
/*===========================================================================*
* go_up *
*===========================================================================*/
static int go_up(struct inode *node, struct inode **parent)
{
/* Given a directory inode, progress into the parent directory.
*/
*parent = get_parent_inode(node);
/* Trapped in a deleted directory? Should not be possible. */
if (*parent == NULL)
return ENOENT;
ref_inode(*parent);
return OK;
}
/*===========================================================================*
* go_down *
*===========================================================================*/
static int go_down(struct inode *parent, char *name, struct inode **child)
{
/* Given a directory inode and a name, progress into a directory entry.
*/
int r;
/* Call the lookup hook, if present, before doing the actual lookup. */
if (!is_inode_deleted(parent) && vtreefs_hooks->lookup_hook != NULL) {
r = vtreefs_hooks->lookup_hook(parent, name,
get_inode_cbdata(parent));
if (r != OK) return r;
}
if ((*child = get_inode_by_name(parent, name)) == NULL)
return ENOENT;
ref_inode(*child);
return OK;
}
/*===========================================================================*
* resolve_link *
*===========================================================================*/
static int resolve_link(struct inode *node, char pptr[PATH_MAX], char *tail)
{
/* Given a symbolic link, resolve and return the contents of the link.
*/
char path[PATH_MAX];
size_t len;
int r;
assert(vtreefs_hooks->rdlink_hook != NULL);
assert(!is_inode_deleted(node));
r = vtreefs_hooks->rdlink_hook(node, path, sizeof(path),
get_inode_cbdata(node));
if (r != OK) return r;
len = strlen(path);
assert(len > 0 && len < sizeof(path));
if (len + strlen(tail) >= sizeof(path))
return ENAMETOOLONG;
strlcat(path, tail, sizeof(path));
strlcpy(pptr, path, PATH_MAX);
return OK;
}
/*===========================================================================* /*===========================================================================*
* fs_lookup * * fs_lookup *
*===========================================================================*/ *===========================================================================*/
int fs_lookup(void) int fs_lookup(ino_t dir_nr, char *name, struct fsdriver_node *node_details,
int *is_mountpt)
{ {
/* Resolve a path string to an inode. /* Resolve a path string to an inode.
*/ */
ino_t dir_ino_nr, root_ino_nr; struct inode *node, *child;
struct inode *cur_ino, *next_ino, *root_ino; int r;
char path[PATH_MAX], name[PNAME_MAX+1];
char *ptr, *last;
vfs_ucred_t ucred;
size_t len;
int r, r2, symloop;
dir_ino_nr = fs_m_in.m_vfs_fs_lookup.dir_ino; if ((node = find_inode(dir_nr)) == NULL)
root_ino_nr = fs_m_in.m_vfs_fs_lookup.root_ino;
len = fs_m_in.m_vfs_fs_lookup.path_len;
/* Fetch the path name. */
if (len < 1 || len > PATH_MAX)
return EINVAL; return EINVAL;
r = sys_safecopyfrom(fs_m_in.m_source, if (!S_ISDIR(node->i_stat.mode))
fs_m_in.m_vfs_fs_lookup.grant_path, 0, (vir_bytes) path, return ENOTDIR;
(phys_bytes) len);
if (r != OK) return r;
if (path[len-1] != 0) return EINVAL; if (strlen(name) > PNAME_MAX)
return ENAMETOOLONG;
/* Fetch the caller's credentials. */ if (!strcmp(name, ".")) {
if (fs_m_in.m_vfs_fs_lookup.flags & PATH_GET_UCRED) { /* Stay in the given directory. */
assert(fs_m_in.m_vfs_fs_lookup.ucred_size == sizeof(ucred)); child = node;
} else if (!strcmp(name, "..")) {
r = sys_safecopyfrom(fs_m_in.m_source, /* Progress into the parent directory. */
fs_m_in.m_vfs_fs_lookup.grant_ucred, 0, if ((child = get_parent_inode(node)) == NULL)
(vir_bytes) &ucred, fs_m_in.m_vfs_fs_lookup.ucred_size); return ENOENT; /* deleted? should not be possible */
} else {
if (r != OK) /* Progress into a directory entry. Call the lookup hook, if
return r; * present, before doing the actual lookup.
}
else {
ucred.vu_uid = fs_m_in.m_vfs_fs_lookup.uid;
ucred.vu_gid = fs_m_in.m_vfs_fs_lookup.gid;
ucred.vu_ngroups = 0;
}
/* Start the actual lookup. */
if ((cur_ino = get_inode(dir_ino_nr)) == NULL)
return EINVAL;
/* Chroot'ed environment? */
if (root_ino_nr > 0)
root_ino = find_inode(root_ino_nr);
else
root_ino = NULL;
symloop = 0;
for (ptr = last = path; ptr[0] != 0; ) {
/* There is more path to process. That means that the current
* file is now being accessed as a directory. Check type and
* permissions.
*/ */
if ((r = access_as_dir(cur_ino, &ucred)) != OK) if (!is_inode_deleted(node) &&
break; vtreefs_hooks->lookup_hook != NULL) {
r = vtreefs_hooks->lookup_hook(node, name,
/* Get the next path component. The result is a non-empty get_inode_cbdata(node));
* string. if (r != OK) return r;
*/
if ((r = next_name(&ptr, &last, name)) != OK)
break;
if (!strcmp(name, ".") ||
(cur_ino == root_ino && !strcmp(name, "..")))
continue;
if (!strcmp(name, "..")) {
if (cur_ino == get_root_inode())
r = ELEAVEMOUNT;
else
r = go_up(cur_ino, &next_ino);
} else {
r = go_down(cur_ino, name, &next_ino);
/* Perform symlink resolution if we have to. */
if (r == OK && S_ISLNK(next_ino->i_stat.mode) &&
(ptr[0] != '\0' ||
!(fs_m_in.m_vfs_fs_lookup.flags & PATH_RET_SYMLINK))) {
if (++symloop == _POSIX_SYMLOOP_MAX) {
put_inode(next_ino);
r = ELOOP;
break;
}
/* Resolve the symlink, and append the
* remaining unresolved part of the path.
*/
r = resolve_link(next_ino, path, ptr);
put_inode(next_ino);
if (r != OK)
break;
/* If the symlink is absolute, return it to
* VFS.
*/
if (path[0] == '/') {
r = ESYMLINK;
last = path;
break;
}
ptr = path;
continue;
}
} }
if (r != OK) if ((child = get_inode_by_name(node, name)) == NULL)
break; return ENOENT;
/* We have found a new file. Continue from this file. */
assert(next_ino != NULL);
put_inode(cur_ino);
cur_ino = next_ino;
} }
/* If an error occurred, close the file and return error information. /* On success, open the resulting file and return its details. */
*/ ref_inode(child);
if (r != OK) {
put_inode(cur_ino);
/* We'd need support for this here. */ node_details->fn_ino_nr = get_inode_number(child);
assert(r != EENTERMOUNT); node_details->fn_mode = child->i_stat.mode;
node_details->fn_size = child->i_stat.size;
node_details->fn_uid = child->i_stat.uid;
node_details->fn_gid = child->i_stat.gid;
node_details->fn_dev = child->i_stat.dev;
/* Copy back the path if we resolved at least one symlink. */ *is_mountpt = FALSE;
if (symloop > 0 && (r == ELEAVEMOUNT || r == ESYMLINK)) {
r2 = sys_safecopyto(fs_m_in.m_source,
fs_m_in.m_vfs_fs_lookup.grant_path, 0,
(vir_bytes) path, strlen(path) + 1);
if (r2 != OK)
r = r2;
}
if (r == ELEAVEMOUNT || r == ESYMLINK) {
fs_m_out.m_fs_vfs_lookup.offset = (int) (last - path);
fs_m_out.m_fs_vfs_lookup.symloop = symloop;
}
return r;
}
/* On success, leave the resulting file open and return its details. */
fs_m_out.m_fs_vfs_lookup.inode = get_inode_number(cur_ino);
fs_m_out.m_fs_vfs_lookup.mode = cur_ino->i_stat.mode;
fs_m_out.m_fs_vfs_lookup.file_size = cur_ino->i_stat.size;
fs_m_out.m_fs_vfs_lookup.uid = cur_ino->i_stat.uid;
fs_m_out.m_fs_vfs_lookup.gid = cur_ino->i_stat.gid;
fs_m_out.m_fs_vfs_lookup.device = cur_ino->i_stat.dev;
return OK; return OK;
} }

View file

@ -11,31 +11,34 @@ void put_inode(struct inode *node);
void ref_inode(struct inode *node); void ref_inode(struct inode *node);
int get_inode_number(struct inode *node); int get_inode_number(struct inode *node);
int is_inode_deleted(struct inode *node); int is_inode_deleted(struct inode *node);
int fs_putnode(void); int fs_putnode(ino_t ino_nr, unsigned int count);
/* link.c */ /* link.c */
int fs_rdlink(void); ssize_t fs_rdlink(ino_t ino_nr, struct fsdriver_data *data, size_t bytes);
/* mount.c */ /* mount.c */
int fs_readsuper(void); int fs_mount(dev_t dev, unsigned int flags, struct fsdriver_node *root_node,
int fs_unmount(void); unsigned int *res_flags);
void fs_unmount(void);
/* main.c */
void fs_other(const message *m_ptr, int ipc_status);
/* path.c */ /* path.c */
int fs_lookup(void); int fs_lookup(ino_t dir_nr, char *name, struct fsdriver_node *node,
int *is_mountpt);
/* read.c */ /* read.c */
int fs_read(void); ssize_t fs_read(ino_t ino_nr, struct fsdriver_data *data, size_t bytes,
int fs_getdents(void); off_t pos, int call);
ssize_t fs_getdents(ino_t ino_nr, struct fsdriver_data *data, size_t bytes,
off_t *pos);
/* sdbm.c */ /* sdbm.c */
long sdbm_hash(char *str, int len); long sdbm_hash(char *str, int len);
/* stadir.c */ /* stadir.c */
int fs_stat(void); int fs_stat(ino_t ino_nr, struct stat *buf);
int fs_statvfs(void); int fs_statvfs(struct statvfs *buf);
/* utility.c */
int no_sys(void);
int do_noop(void);
#endif /* _VTREEFS_PROTO_H */ #endif /* _VTREEFS_PROTO_H */

View file

@ -2,40 +2,33 @@
#include "inc.h" #include "inc.h"
#include <dirent.h> #include <dirent.h>
#include <minix/minlib.h>
#define GETDENTS_BUFSIZ 4096 #define GETDENTS_BUFSIZ 4096
#define DWORD_ALIGN(len) (((len) + sizeof(long) - 1) & ~(sizeof(long) - 1))
/*===========================================================================* /*===========================================================================*
* fs_read * * fs_read *
*===========================================================================*/ *===========================================================================*/
int fs_read(void) ssize_t fs_read(ino_t ino_nr, struct fsdriver_data *data, size_t bytes,
off_t pos, int __unused call)
{ {
/* Read from a file. /* Read from a file.
*/ */
cp_grant_id_t gid;
struct inode *node; struct inode *node;
off_t pos;
size_t len; size_t len;
char *ptr; char *ptr;
int r; int r;
/* Try to get inode by to its inode number. */ /* Try to get inode by its inode number. */
if ((node = find_inode(fs_m_in.m_vfs_fs_readwrite.inode)) == NULL) if ((node = find_inode(ino_nr)) == NULL)
return EINVAL; return EINVAL;
/* Check whether the node is a regular file. */ /* Check whether the node is a regular file. */
if (!S_ISREG(node->i_stat.mode)) if (!S_ISREG(node->i_stat.mode))
return EINVAL; return EINVAL;
/* Get the values from the request message. */
gid = fs_m_in.m_vfs_fs_readwrite.grant;
pos = fs_m_in.m_vfs_fs_readwrite.seek_pos;
/* Call the read hook, if any. */ /* Call the read hook, if any. */
if (!is_inode_deleted(node) && vtreefs_hooks->read_hook != NULL) { if (!is_inode_deleted(node) && vtreefs_hooks->read_hook != NULL) {
len = fs_m_in.m_vfs_fs_readwrite.nbytes; len = bytes;
/* On success, the read hook provides us with a pointer to the /* On success, the read hook provides us with a pointer to the
* resulting data. This avoids copying overhead. * resulting data. This avoids copying overhead.
@ -43,51 +36,41 @@ int fs_read(void)
r = vtreefs_hooks->read_hook(node, pos, &ptr, &len, r = vtreefs_hooks->read_hook(node, pos, &ptr, &len,
get_inode_cbdata(node)); get_inode_cbdata(node));
assert(len <= fs_m_in.m_vfs_fs_readwrite.nbytes); assert(len <= bytes);
/* Copy the resulting data to user space. */ /* Copy the resulting data to user space. */
if (r == OK && len > 0) { if (r == OK && len > 0)
r = sys_safecopyto(fs_m_in.m_source, fs_m_in.m_vfs_fs_readwrite.grant, r = fsdriver_copyout(data, 0, ptr, len);
0, (vir_bytes) ptr, len);
}
} else { } else {
/* Feign an empty file. */ /* Feign an empty file. */
r = OK; r = OK;
len = 0; len = 0;
} }
if (r == OK) { return (r != OK) ? r : len;
fs_m_out.m_fs_vfs_readwrite.seek_pos = pos + len;
fs_m_out.m_fs_vfs_readwrite.nbytes = len;
}
return r;
} }
/*===========================================================================* /*===========================================================================*
* fs_getdents * * fs_getdents *
*===========================================================================*/ *===========================================================================*/
int fs_getdents(void) ssize_t fs_getdents(ino_t ino_nr, struct fsdriver_data *data, size_t bytes,
off_t *posp)
{ {
/* Retrieve directory entries. /* Retrieve directory entries.
*/ */
struct inode *node, *child = NULL; struct fsdriver_dentry fsdentry;
struct dirent *dent; struct inode *node, *child;
char *name; const char *name;
size_t len, off, user_off, user_left;
off_t pos; off_t pos;
int r, skip, get_next, indexed; int r, skip, get_next, indexed;
static char buf[GETDENTS_BUFSIZ]; static char buf[GETDENTS_BUFSIZ];
if (fs_m_in.m_vfs_fs_getdents.seek_pos >= ULONG_MAX) if (*posp >= ULONG_MAX)
return EIO; return EIO;
if ((node = find_inode(fs_m_in.m_vfs_fs_getdents.inode)) == NULL) if ((node = find_inode(ino_nr)) == NULL)
return EINVAL; return EINVAL;
off = 0;
user_off = 0;
user_left = fs_m_in.m_vfs_fs_getdents.mem_size;
indexed = node->i_indexed; indexed = node->i_indexed;
get_next = FALSE; get_next = FALSE;
child = NULL; child = NULL;
@ -98,8 +81,12 @@ int fs_getdents(void)
if (r != OK) return r; if (r != OK) return r;
} }
for (pos = fs_m_in.m_vfs_fs_getdents.seek_pos; ; pos++) { fsdriver_dentry_init(&fsdentry, data, bytes, buf, sizeof(buf));
do {
/* Determine which inode and name to use for this entry. */ /* Determine which inode and name to use for this entry. */
pos = (*posp)++;
if (pos == 0) { if (pos == 0) {
/* The "." entry. */ /* The "." entry. */
child = node; child = node;
@ -158,56 +145,13 @@ int fs_getdents(void)
name = child->i_name; name = child->i_name;
} }
/* record length incl. alignment. */ /* Add the directory entry to the output. */
len = _DIRENT_RECLEN(dent, strlen(name)); r = fsdriver_dentry_add(&fsdentry,
(ino_t) get_inode_number(child), name, strlen(name),
/* Is the user buffer too small to store another record? */ IFTODT(child->i_stat.mode));
if (user_off + off + len > user_left) { if (r < 0)
/* Is the user buffer too small for even a single
* record?
*/
if (user_off == 0 && off == 0)
return EINVAL;
break;
}
/* If our own buffer cannot contain the new record, copy out
* first.
*/
if (off + len > sizeof(buf)) {
r = sys_safecopyto(fs_m_in.m_source, fs_m_in.m_vfs_fs_getdents.grant,
user_off, (vir_bytes) buf, off);
if (r != OK) return r;
user_off += off;
user_left -= off;
off = 0;
}
/* Fill in the actual directory entry. */
dent = (struct dirent *) &buf[off];
dent->d_ino = (ino_t) get_inode_number(child);
dent->d_reclen = len;
dent->d_type = fs_mode_to_type(child->i_stat.mode);
dent->d_namlen = strlen(name);
strcpy(dent->d_name, name);
off += len;
}
/* If there is anything left in our own buffer, copy that out now. */
if (off > 0) {
r = sys_safecopyto(fs_m_in.m_source, fs_m_in.m_vfs_fs_getdents.grant,
user_off, (vir_bytes) buf, off);
if (r != OK)
return r; return r;
} while (r > 0);
user_off += off; return fsdriver_dentry_finish(&fsdentry);
}
fs_m_out.m_fs_vfs_getdents.seek_pos = pos;
fs_m_out.m_fs_vfs_getdents.nbytes = user_off;
return OK;
} }

View file

@ -2,37 +2,30 @@
#include "inc.h" #include "inc.h"
#include <time.h>
#include <sys/statvfs.h>
#include <string.h>
/*===========================================================================* /*===========================================================================*
* fs_stat * * fs_stat *
*===========================================================================*/ *===========================================================================*/
int fs_stat(void) int fs_stat(ino_t ino_nr, struct stat *buf)
{ {
/* Retrieve file status. /* Retrieve file status.
*/ */
char path[PATH_MAX]; char path[PATH_MAX];
struct stat statbuf;
time_t cur_time; time_t cur_time;
struct inode *node; struct inode *node;
int r; int r;
if ((node = find_inode(fs_m_in.m_vfs_fs_stat.inode)) == NULL) if ((node = find_inode(ino_nr)) == NULL)
return EINVAL; return EINVAL;
memset(&statbuf, 0, sizeof(struct stat));
/* Fill in the basic info. */ /* Fill in the basic info. */
statbuf.st_dev = fs_dev; buf->st_dev = fs_dev;
statbuf.st_ino = get_inode_number(node); buf->st_ino = get_inode_number(node);
statbuf.st_mode = node->i_stat.mode; buf->st_mode = node->i_stat.mode;
statbuf.st_nlink = !is_inode_deleted(node); buf->st_nlink = !is_inode_deleted(node);
statbuf.st_uid = node->i_stat.uid; buf->st_uid = node->i_stat.uid;
statbuf.st_gid = node->i_stat.gid; buf->st_gid = node->i_stat.gid;
statbuf.st_rdev = (dev_t) node->i_stat.dev; buf->st_rdev = (dev_t) node->i_stat.dev;
statbuf.st_size = node->i_stat.size; buf->st_size = node->i_stat.size;
/* If it is a symbolic link, return the size of the link target. */ /* If it is a symbolic link, return the size of the link target. */
if (S_ISLNK(node->i_stat.mode) && vtreefs_hooks->rdlink_hook != NULL) { if (S_ISLNK(node->i_stat.mode) && vtreefs_hooks->rdlink_hook != NULL) {
@ -40,34 +33,28 @@ int fs_stat(void)
get_inode_cbdata(node)); get_inode_cbdata(node));
if (r == OK) if (r == OK)
statbuf.st_size = strlen(path); buf->st_size = strlen(path);
} }
/* Take the current time as file time for all files. */ /* Take the current time as file time for all files. */
cur_time = time(NULL); cur_time = time(NULL);
statbuf.st_atime = cur_time; buf->st_atime = cur_time;
statbuf.st_mtime = cur_time; buf->st_mtime = cur_time;
statbuf.st_ctime = cur_time; buf->st_ctime = cur_time;
/* Copy the struct to user space. */ return OK;
return sys_safecopyto(fs_m_in.m_source, fs_m_in.m_vfs_fs_stat.grant, 0,
(vir_bytes) &statbuf, (phys_bytes) sizeof(statbuf));
} }
/*===========================================================================* /*===========================================================================*
* fs_statvfs * * fs_statvfs *
*===========================================================================*/ *===========================================================================*/
int fs_statvfs(void) int fs_statvfs(struct statvfs *buf)
{ {
/* Retrieve file system statistics. /* Retrieve file system statistics.
*/ */
struct statvfs statvfs;
memset(&statvfs, 0, sizeof(statvfs)); buf->f_flag = ST_NOTRUNC;
buf->f_namemax = PNAME_MAX;
statvfs.f_flag = ST_NOTRUNC; return OK;
statvfs.f_namemax = PNAME_MAX;
return sys_safecopyto(fs_m_in.m_source, fs_m_in.m_vfs_fs_statvfs.grant,
0, (vir_bytes) &statvfs, sizeof(statvfs));
} }

View file

@ -3,43 +3,15 @@
#define _TABLE #define _TABLE
#include "inc.h" #include "inc.h"
int (*fs_call_vec[])(void) = { struct fsdriver vtreefs_table = {
no_sys, /* 0 */ .fdr_mount = fs_mount,
no_sys, /* 1 getnode */ .fdr_unmount = fs_unmount,
fs_putnode, /* 2 putnode */ .fdr_lookup = fs_lookup,
no_sys, /* 3 slink */ .fdr_putnode = fs_putnode,
no_sys, /* 4 ftrunc */ .fdr_read = fs_read,
no_sys, /* 5 chown */ .fdr_getdents = fs_getdents,
no_sys, /* 6 chmod */ .fdr_rdlink = fs_rdlink,
do_noop, /* 7 inhibread */ .fdr_stat = fs_stat,
fs_stat, /* 8 stat */ .fdr_statvfs = fs_statvfs,
no_sys, /* 9 utime */ .fdr_other = fs_other
fs_statvfs, /* 10 statvfs */
no_sys, /* 11 bread */
no_sys, /* 12 bwrite */
no_sys, /* 13 unlink */
no_sys, /* 14 rmdir */
fs_unmount, /* 15 unmount */
do_noop, /* 16 sync */
do_noop, /* 17 new_driver */
no_sys, /* 18 flush */
fs_read, /* 19 read */
no_sys, /* 20 write */
no_sys, /* 21 mknod */
no_sys, /* 22 mkdir */
no_sys, /* 23 create */
no_sys, /* 24 link */
no_sys, /* 25 rename */
fs_lookup, /* 26 lookup */
no_sys, /* 27 mountpoint */
fs_readsuper, /* 28 readsuper */
no_sys, /* 29 newnode */
fs_rdlink, /* 30 rdlink */
fs_getdents, /* 31 getdents */
no_sys, /* 32 peek */
no_sys, /* 33 bpeek */
}; };
/* This should not fail with "array size is negative": */
extern int
dummy[sizeof(fs_call_vec) == NREQS * sizeof(fs_call_vec[0]) ? 1 : -1];

View file

@ -1,29 +0,0 @@
/* VTreeFS - utility.c - by Alen Stojanov and David van Moolenbroek */
#include "inc.h"
/*===========================================================================*
* no_sys *
*===========================================================================*/
int no_sys(void)
{
/* This call is not recognized by VTreeFS. If a message hook is
* defined, let it handle the call; otherwise return ENOSYS.
*/
if (vtreefs_hooks->message_hook != NULL)
return vtreefs_hooks->message_hook(&fs_m_in);
return ENOSYS;
}
/*===========================================================================*
* do_noop *
*===========================================================================*/
int do_noop(void)
{
/* This call has no effect.
*/
return OK;
}

View file

@ -2,10 +2,6 @@
#include "inc.h" #include "inc.h"
static int get_work(void);
static void send_reply(int err, int transid);
static void got_signal(int signal);
static unsigned int inodes; static unsigned int inodes;
static struct inode_stat *root_stat; static struct inode_stat *root_stat;
static index_t root_entries; static index_t root_entries;
@ -21,12 +17,23 @@ static int init_server(int UNUSED(type), sef_init_info_t *UNUSED(info))
/* Initialize the virtual tree. */ /* Initialize the virtual tree. */
init_inodes(inodes, root_stat, root_entries); init_inodes(inodes, root_stat, root_entries);
/* Do not yet allow any requests except REQ_READSUPER. */
fs_mounted = FALSE;
return OK; return OK;
} }
/*===========================================================================*
* got_signal *
*===========================================================================*/
static void got_signal(int signal)
{
/* We received a signal.
*/
if (signal != SIGTERM)
return;
fsdriver_terminate();
}
/*===========================================================================* /*===========================================================================*
* sef_local_startup * * sef_local_startup *
*===========================================================================*/ *===========================================================================*/
@ -42,18 +49,36 @@ static void sef_local_startup(void)
sef_startup(); sef_startup();
} }
/*===========================================================================*
* fs_other *
*===========================================================================*/
void fs_other(const message *m_ptr, int __unused ipc_status)
{
/* We received a message that is not among the recognized file system
* requests. Call the message hook, if there is one.
*/
message msg;
if (vtreefs_hooks->message_hook != NULL) {
/* Not all of vtreefs's users play nice with the message, so
* make a copy to allow it to be modified.
*/
msg = *m_ptr;
vtreefs_hooks->message_hook(&msg);
}
}
/*===========================================================================* /*===========================================================================*
* start_vtreefs * * start_vtreefs *
*===========================================================================*/ *===========================================================================*/
void start_vtreefs(struct fs_hooks *hooks, unsigned int nr_inodes, void start_vtreefs(struct fs_hooks *hooks, unsigned int nr_inodes,
struct inode_stat *stat, index_t nr_indexed_entries) struct inode_stat *stat, index_t nr_indexed_entries)
{ {
/* This is the main routine of this service. The main loop consists of /* This is the main routine of this service. It uses the main loop as
* three major activities: getting new work, processing the work, and * provided by the fsdriver library. The routine returns once the file
* sending the reply. The loop exits when the process is signaled to * system has been unmounted and the process is signaled to exit.
* exit; due to limitations of SEF, it can not return to the caller.
*/ */
int call_nr, err, transid;
/* Use global variables to work around the inability to pass parameters /* Use global variables to work around the inability to pass parameters
* through SEF to the initialization function.. * through SEF to the initialization function..
@ -65,95 +90,7 @@ void start_vtreefs(struct fs_hooks *hooks, unsigned int nr_inodes,
sef_local_startup(); sef_local_startup();
for (;;) { fsdriver_task(&vtreefs_table);
get_work();
transid = TRNS_GET_ID(fs_m_in.m_type);
fs_m_in.m_type = TRNS_DEL_ID(fs_m_in.m_type);
if (fs_m_in.m_type == 0) {
assert(!IS_VFS_FS_TRANSID(transid));
fs_m_in.m_type = transid; /* Backwards compat. */
transid = 0;
} else
assert(IS_VFS_FS_TRANSID(transid));
call_nr = fs_m_in.m_type;
if (fs_m_in.m_source != VFS_PROC_NR) {
if (vtreefs_hooks->message_hook != NULL) {
/* If the request is not among the recognized
* requests, call the message hook.
*/
vtreefs_hooks->message_hook(&fs_m_in);
}
continue;
}
if (fs_mounted || call_nr == REQ_READSUPER) {
call_nr -= FS_BASE;
if (call_nr >= 0 && call_nr < NREQS) {
err = (*fs_call_vec[call_nr])();
} else {
err = ENOSYS;
}
}
else err = EINVAL;
send_reply(err, transid);
}
}
/*===========================================================================*
* get_work *
*===========================================================================*/
static int get_work(void)
{
/* Retrieve work. Return the call number.
*/
int r;
if ((r = sef_receive(ANY, &fs_m_in)) != OK)
panic("receive failed: %d", r);
return fs_m_in.m_type;
}
/*===========================================================================*
* send_reply *
*===========================================================================*/
static void send_reply(int err, int transid)
{
/* Send a reply to the caller.
*/
int r;
fs_m_out.m_type = err;
if (IS_VFS_FS_TRANSID(transid)) {
fs_m_out.m_type = TRNS_ADD_ID(fs_m_out.m_type, transid);
}
if ((r = ipc_send(fs_m_in.m_source, &fs_m_out)) != OK)
panic("unable to send reply: %d", r);
}
/*===========================================================================*
* got_signal *
*===========================================================================*/
static void got_signal(int signal)
{
/* We received a signal. If it is a termination signal, and the file
* system has already been unmounted, clean up and exit.
*/
if (signal != SIGTERM)
return;
if (fs_mounted)
return;
cleanup_inodes(); cleanup_inodes();
exit(0);
} }

View file

@ -1,7 +1,7 @@
PROG = devman PROG = devman
SRCS = main.c device.c buf.c bind.c SRCS = main.c device.c buf.c bind.c
DPADD+= ${LIBSYS} DPADD+= ${LIBVTREEFS} ${LIBFSDRIVER} ${LIBSYS}
LDADD = -lvtreefs -lsys LDADD+= -lvtreefs -lfsdriver -lsys
.include <minix.service.mk> .include <minix.service.mk>