Add routines for pure userspace file system operation
(i.e. no kernel involvement), namely: * create, mknod, remove, mknod, rmdir, getdents, read, write, and link Still obviously missing a few, but this is a start (I'm also searching for the blessed orb of code quality, maybe someone has seen it?).
This commit is contained in:
parent
86dbc7c35c
commit
b926b490ec
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: ukfs.c,v 1.1 2007/08/14 15:56:17 pooka Exp $ */
|
||||
/* $NetBSD: ukfs.c,v 1.2 2007/08/16 19:37:18 pooka Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Antti Kantee. All Rights Reserved.
|
||||
|
@ -33,19 +33,21 @@
|
|||
* involving system calls.
|
||||
*/
|
||||
|
||||
#define __NAMEIFLAGS_EXPOSE
|
||||
#define __UIO_EXPOSE
|
||||
#define __VFSOPS_EXPOSE
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/namei.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/vnode_if.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
#define _KERNEL
|
||||
#include <errno.h>
|
||||
#undef _KERNEL
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
@ -55,7 +57,6 @@
|
|||
|
||||
struct ukfs {
|
||||
struct mount *ukfs_mp;
|
||||
struct vnode *ukfs_rvp;
|
||||
};
|
||||
|
||||
struct mount *
|
||||
|
@ -68,8 +69,14 @@ ukfs_getmp(struct ukfs *ukfs)
|
|||
struct vnode *
|
||||
ukfs_getrvp(struct ukfs *ukfs)
|
||||
{
|
||||
struct vnode *rvp;
|
||||
int rv;
|
||||
|
||||
return ukfs->ukfs_rvp;
|
||||
rv = VFS_ROOT(ukfs->ukfs_mp, &rvp);
|
||||
assert(rv == 0);
|
||||
assert(rvp->v_flag & VROOT);
|
||||
|
||||
return rvp;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -125,12 +132,6 @@ ukfs_mount(const char *vfsname, const char *devpath, const char *mountpath,
|
|||
goto out;
|
||||
}
|
||||
|
||||
rv = VFS_ROOT(mp, &fs->ukfs_rvp);
|
||||
if (rv) {
|
||||
warnx("VFS_ROOT %d", rv);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
if (rv) {
|
||||
if (fs->ukfs_mp)
|
||||
|
@ -144,7 +145,7 @@ ukfs_mount(const char *vfsname, const char *devpath, const char *mountpath,
|
|||
}
|
||||
|
||||
void
|
||||
ukfs_unmount(struct ukfs *fs, int dounmount)
|
||||
ukfs_release(struct ukfs *fs, int dounmount)
|
||||
{
|
||||
int rv;
|
||||
|
||||
|
@ -158,3 +159,333 @@ ukfs_unmount(struct ukfs *fs, int dounmount)
|
|||
|
||||
free(fs);
|
||||
}
|
||||
|
||||
/* don't need vn_lock(), since we don't have VXLOCK */
|
||||
#define VLE(a) VOP_LOCK(a, LK_EXCLUSIVE)
|
||||
#define VLS(a) VOP_LOCK(a, LK_SHARED)
|
||||
#define VUL(a) VOP_UNLOCK(a, 0);
|
||||
#define AUL(a) assert(VOP_ISLOCKED(a) == 0)
|
||||
|
||||
static void
|
||||
recycle(struct vnode *vp)
|
||||
{
|
||||
|
||||
/* XXXXX */
|
||||
if (vp == NULL || vp->v_usecount != 0)
|
||||
return;
|
||||
|
||||
VLE(vp);
|
||||
VOP_FSYNC(vp, NULL, 0, 0, 0, curlwp);
|
||||
VOP_INACTIVE(vp, curlwp);
|
||||
rump_recyclenode(vp);
|
||||
rump_putnode(vp);
|
||||
}
|
||||
|
||||
/*
|
||||
* simplo (well, horrid) namei. doesn't do symlinks & anything else
|
||||
* hard, though. (ok, ok, it's a mess, it's a messssss!)
|
||||
*
|
||||
* XXX: maybe I should just try running the kernel namei(), although
|
||||
* it would require a wrapping due to the name collision in
|
||||
* librump vfs.c
|
||||
*/
|
||||
static int
|
||||
ukfs_namei(struct vnode *rvp, const char **pnp, u_long op,
|
||||
struct vnode **dvpp, struct vnode **vpp)
|
||||
{
|
||||
struct vnode *dvp, *vp;
|
||||
struct componentname *cnp;
|
||||
const char *pn, *p_next, *p_end;
|
||||
size_t pnlen;
|
||||
u_long flags;
|
||||
int rv;
|
||||
|
||||
/* remove trailing slashes */
|
||||
pn = *pnp;
|
||||
assert(strlen(pn) > 0);
|
||||
p_end = pn + strlen(pn)-1;
|
||||
while (*p_end == '/' && p_end != *pnp)
|
||||
p_end--;
|
||||
|
||||
/* caller wanted root? */
|
||||
if (p_end == *pnp) {
|
||||
if (dvpp)
|
||||
*dvpp = rvp;
|
||||
if (vpp)
|
||||
*vpp = rvp;
|
||||
|
||||
*pnp = p_end;
|
||||
return 0;
|
||||
}
|
||||
|
||||
dvp = NULL;
|
||||
vp = rvp;
|
||||
p_end++;
|
||||
for (;;) {
|
||||
while (*pn == '/')
|
||||
pn++;
|
||||
assert(*pn != '\0');
|
||||
|
||||
flags = 0;
|
||||
dvp = vp;
|
||||
vp = NULL;
|
||||
|
||||
p_next = strchr(pn, '/');
|
||||
if (p_next == NULL || p_next == p_end) {
|
||||
p_next = p_end;
|
||||
flags |= NAMEI_ISLASTCN;
|
||||
}
|
||||
pnlen = p_next - pn;
|
||||
|
||||
if (pnlen == 2 && strcmp(pn, "..") == 0)
|
||||
flags |= NAMEI_ISDOTDOT;
|
||||
|
||||
VLE(dvp);
|
||||
cnp = rump_makecn(op, flags, pn, pnlen, curlwp);
|
||||
rv = VOP_LOOKUP(dvp, &vp, cnp);
|
||||
rump_freecn(cnp, 1);
|
||||
VUL(dvp);
|
||||
if (rv == 0)
|
||||
VUL(vp);
|
||||
|
||||
if (!((flags & NAMEI_ISLASTCN) && dvpp))
|
||||
recycle(dvp);
|
||||
|
||||
if (rv || (flags & NAMEI_ISLASTCN))
|
||||
break;
|
||||
|
||||
pn += pnlen;
|
||||
}
|
||||
assert(flags & NAMEI_ISLASTCN);
|
||||
if (vp && vpp == NULL)
|
||||
recycle(vp);
|
||||
|
||||
if (dvpp)
|
||||
*dvpp = dvp;
|
||||
if (vpp)
|
||||
*vpp = vp;
|
||||
*pnp = pn;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int
|
||||
ukfs_getdents(struct ukfs *ukfs, const char *dirname, off_t off,
|
||||
uint8_t *buf, size_t bufsize)
|
||||
{
|
||||
struct uio uio;
|
||||
struct iovec iov;
|
||||
struct vnode *vp;
|
||||
int rv, eofflag;
|
||||
|
||||
UKFS_UIOINIT(uio, iov, buf, bufsize, off, UIO_READ);
|
||||
|
||||
rv = ukfs_namei(ukfs_getrvp(ukfs), &dirname, NAMEI_LOOKUP, NULL, &vp);
|
||||
if (rv)
|
||||
goto out;
|
||||
|
||||
VLE(vp);
|
||||
rv = VOP_READDIR(vp, &uio, NULL, &eofflag, NULL, NULL);
|
||||
VUL(vp);
|
||||
|
||||
out:
|
||||
recycle(vp);
|
||||
|
||||
if (rv) {
|
||||
errno = rv;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return bufsize - uio.uio_resid;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
readwrite(struct ukfs *ukfs, const char *filename, off_t off,
|
||||
uint8_t *buf, size_t bufsize, enum uio_rw rw,
|
||||
int (*do_fn)(struct vnode *, struct uio *, int, kauth_cred_t))
|
||||
{
|
||||
struct uio uio;
|
||||
struct iovec iov;
|
||||
struct vnode *vp;
|
||||
int rv;
|
||||
|
||||
UKFS_UIOINIT(uio, iov, buf, bufsize, off, rw);
|
||||
|
||||
rv = ukfs_namei(ukfs_getrvp(ukfs), &filename, NAMEI_LOOKUP, NULL, &vp);
|
||||
if (rv)
|
||||
goto out;
|
||||
|
||||
VLS(vp);
|
||||
rv = do_fn(vp, &uio, 0, NULL);
|
||||
VUL(vp);
|
||||
|
||||
out:
|
||||
recycle(vp);
|
||||
|
||||
if (rv) {
|
||||
errno = rv;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return bufsize - uio.uio_resid;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
ukfs_read(struct ukfs *ukfs, const char *filename, off_t off,
|
||||
uint8_t *buf, size_t bufsize)
|
||||
{
|
||||
|
||||
return readwrite(ukfs, filename, off, buf, bufsize, UIO_READ, VOP_READ);
|
||||
}
|
||||
|
||||
ssize_t
|
||||
ukfs_write(struct ukfs *ukfs, const char *filename, off_t off,
|
||||
uint8_t *buf, size_t bufsize)
|
||||
{
|
||||
|
||||
return readwrite(ukfs, filename, off, buf, bufsize,UIO_WRITE,VOP_WRITE);
|
||||
}
|
||||
|
||||
static int
|
||||
create(struct ukfs *ukfs, const char *filename, mode_t mode, dev_t dev,
|
||||
int (*do_fn)(struct vnode *, struct vnode **,
|
||||
struct componentname *, struct vattr *))
|
||||
{
|
||||
struct componentname *cnp;
|
||||
struct vnode *dvp = NULL, *vp = NULL;
|
||||
struct vattr va;
|
||||
struct timeval tv_now;
|
||||
int rv;
|
||||
|
||||
rv = ukfs_namei(ukfs_getrvp(ukfs), &filename, NAMEI_CREATE, &dvp, NULL);
|
||||
if (rv == 0)
|
||||
rv = EEXIST;
|
||||
if (rv != EJUSTRETURN)
|
||||
goto out;
|
||||
|
||||
gettimeofday(&tv_now, NULL);
|
||||
|
||||
rump_vattr_null(&va);
|
||||
va.va_mode = mode;
|
||||
va.va_rdev = dev;
|
||||
|
||||
cnp = rump_makecn(NAMEI_CREATE, NAMEI_HASBUF|NAMEI_SAVENAME, filename,
|
||||
strlen(filename), curlwp);
|
||||
VLE(dvp);
|
||||
rv = do_fn(dvp, &vp, cnp, &va);
|
||||
rump_freecn(cnp, 0);
|
||||
|
||||
out:
|
||||
recycle(dvp);
|
||||
recycle(vp);
|
||||
|
||||
if (rv) {
|
||||
errno = rv;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ukfs_create(struct ukfs *ukfs, const char *filename, mode_t mode)
|
||||
{
|
||||
|
||||
return create(ukfs, filename, mode, /*XXX*/(dev_t)-1, VOP_CREATE);
|
||||
}
|
||||
|
||||
int
|
||||
ukfs_mknod(struct ukfs *ukfs, const char *filename, mode_t mode, dev_t dev)
|
||||
{
|
||||
|
||||
return create(ukfs, filename, mode, dev, VOP_MKNOD);
|
||||
}
|
||||
|
||||
int
|
||||
ukfs_mkdir(struct ukfs *ukfs, const char *filename, mode_t mode)
|
||||
{
|
||||
|
||||
return create(ukfs, filename, mode, (dev_t)-1, VOP_MKDIR);
|
||||
}
|
||||
|
||||
static int
|
||||
doremove(struct ukfs *ukfs, const char *filename,
|
||||
int (*do_fn)(struct vnode *, struct vnode *, struct componentname *))
|
||||
{
|
||||
struct componentname *cnp;
|
||||
struct vnode *dvp = NULL, *vp = NULL;
|
||||
int rv;
|
||||
|
||||
rv = ukfs_namei(ukfs_getrvp(ukfs), &filename, NAMEI_DELETE, &dvp, &vp);
|
||||
if (rv)
|
||||
goto out;
|
||||
|
||||
cnp = rump_makecn(NAMEI_DELETE, 0, filename, strlen(filename), curlwp);
|
||||
VLE(dvp);
|
||||
VLE(vp);
|
||||
rv = do_fn(dvp, vp, cnp);
|
||||
rump_freecn(cnp, 0);
|
||||
|
||||
out:
|
||||
recycle(dvp);
|
||||
recycle(vp);
|
||||
|
||||
if (rv) {
|
||||
errno = rv;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ukfs_remove(struct ukfs *ukfs, const char *filename)
|
||||
{
|
||||
|
||||
return doremove(ukfs, filename, VOP_REMOVE);
|
||||
}
|
||||
|
||||
int
|
||||
ukfs_rmdir(struct ukfs *ukfs, const char *filename)
|
||||
{
|
||||
|
||||
return doremove(ukfs, filename, VOP_RMDIR);
|
||||
}
|
||||
|
||||
int
|
||||
ukfs_link(struct ukfs *ukfs, const char *filename, const char *f_create)
|
||||
{
|
||||
struct vnode *dvp = NULL, *vp = NULL;
|
||||
struct componentname *cnp;
|
||||
int rv;
|
||||
|
||||
rv = ukfs_namei(ukfs_getrvp(ukfs), &filename, NAMEI_LOOKUP, NULL, &vp);
|
||||
if (rv)
|
||||
goto out;
|
||||
|
||||
vp->v_usecount = 1; /* XXX kludge of the year */
|
||||
rv = ukfs_namei(ukfs_getrvp(ukfs), &f_create, NAMEI_CREATE, &dvp, NULL);
|
||||
vp->v_usecount = 0; /* XXX */
|
||||
|
||||
if (rv == 0)
|
||||
rv = EEXIST;
|
||||
if (rv != EJUSTRETURN)
|
||||
goto out;
|
||||
|
||||
cnp = rump_makecn(NAMEI_CREATE, NAMEI_HASBUF | NAMEI_SAVENAME,
|
||||
f_create, strlen(f_create), curlwp);
|
||||
VLE(dvp);
|
||||
rv = VOP_LINK(dvp, vp, cnp);
|
||||
rump_freecn(cnp, 0);
|
||||
|
||||
out:
|
||||
recycle(dvp);
|
||||
recycle(vp);
|
||||
|
||||
if (rv) {
|
||||
errno = rv;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: ukfs.h,v 1.1 2007/08/14 15:56:17 pooka Exp $ */
|
||||
/* $NetBSD: ukfs.h,v 1.2 2007/08/16 19:37:18 pooka Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Antti Kantee. All Rights Reserved.
|
||||
|
@ -40,12 +40,39 @@ struct ukfs;
|
|||
int ukfs_init(void);
|
||||
struct ukfs *ukfs_mount(const char *, const char *, const char *,
|
||||
int, void *, size_t);
|
||||
void ukfs_unmount(struct ukfs *, int);
|
||||
void ukfs_release(struct ukfs *, int);
|
||||
|
||||
int ukfs_getdents(struct ukfs *, const char *, off_t,
|
||||
char *, size_t);
|
||||
uint8_t *, size_t);
|
||||
ssize_t ukfs_read(struct ukfs *, const char *, off_t,
|
||||
uint8_t *, size_t);
|
||||
ssize_t ukfs_write(struct ukfs *, const char *, off_t,
|
||||
uint8_t *, size_t);
|
||||
|
||||
int ukfs_create(struct ukfs *, const char *, mode_t);
|
||||
int ukfs_mkdir(struct ukfs *, const char *, mode_t);
|
||||
int ukfs_mknod(struct ukfs *, const char *, mode_t, dev_t);
|
||||
|
||||
int ukfs_remove(struct ukfs *, const char *);
|
||||
int ukfs_rmdir(struct ukfs *, const char *);
|
||||
|
||||
int ukfs_link(struct ukfs *, const char *, const char *);
|
||||
|
||||
|
||||
struct mount *ukfs_getmp(struct ukfs *);
|
||||
struct vnode *ukfs_getrvp(struct ukfs *);
|
||||
|
||||
#define UKFS_UIOINIT(uio, iov, buf, bufsize, offset, rw) \
|
||||
do { \
|
||||
iov.iov_base = buf; \
|
||||
iov.iov_len = bufsize; \
|
||||
uio.uio_iov = &(iov); \
|
||||
uio.uio_iovcnt = 1; \
|
||||
uio.uio_offset = offset; \
|
||||
uio.uio_resid = bufsize; \
|
||||
uio.uio_rw = UIO_READ; \
|
||||
uio.uio_vmspace = UIO_VMSPACE_SYS; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
|
||||
#endif /* _SYS_RUMPFS_UKFS_H_ */
|
||||
|
|
Loading…
Reference in New Issue