sys/acl.h _ All borrowed from libsolcompat
sys/acl_impl.h _ All borrowed from libsolcompat
-* Fix failure in rw lock test 6
-
-* Non-atomic 64bit support for kstat.h
-
-* Write vnode interface
+* Implement solaris style atomic interfaces
extern "C" {
#endif
-#include <linux/module.h>
-#include <linux/uaccess.h>
-#include <sys/types.h>
-#include <sys/kmem.h>
+#include <sys/vnode.h>
typedef struct _buf {
- struct file *fp;
+ vnode_t *vp;
} _buf_t;
-extern void *rootdir;
-
extern struct _buf *kobj_open_file(const char *name);
extern void kobj_close_file(struct _buf *file);
extern int kobj_read_file(struct _buf *file, char *buf,
- unsigned size, unsigned off);
+ ssize_t size, offset_t off);
extern int kobj_get_filesize(struct _buf *file, uint64_t *size);
#ifdef __cplusplus
#define NICE_TO_PRIO(nice) (MAX_RT_PRIO + (nice) + 20)
#define PRIO_TO_NICE(prio) ((prio) - MAX_RT_PRIO - 20)
-#define kred NULL
-
-#define FREAD 1
-#define FWRITE 2
-#define FCREAT O_CREAT
-#define FTRUNC O_TRUNC
-#define FOFFMAX O_LARGEFILE
-#define FSYNC O_SYNC
-#define FDSYNC O_DSYNC
-#define FRSYNC O_RSYNC
-#define FEXCL O_EXCL
-
-#define FNODSYNC 0x10000 /* fsync pseudo flag */
-#define FNOFOLLOW 0x20000 /* don't follow symlinks */
-
/* Missing macros
*/
#define PAGESIZE PAGE_SIZE
#define zone_dataset_visible(x, y) (1)
#define INGLOBALZONE(z) (1)
-/* XXX - Borrowed from zfs project libsolcompat/include/sys/sysmacros.h */
/* common macros */
#ifndef MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#ifndef _SPL_UIO_H
#define _SPL_UIO_H
-typedef enum uio_rw { UIO_READ, UIO_WRITE } uio_rw_t;
+typedef enum uio_rw {
+ UIO_READ = 0,
+ UIO_WRITE = 1,
+} uio_rw_t;
#define UIO_SYSSPACE 1
#ifndef _SPL_VNODE_H
#define _SPL_VNODE_H
+#include <linux/module.h>
#include <linux/syscalls.h>
+#include <linux/fcntl.h>
+#include <linux/uaccess.h>
+#include <linux/buffer_head.h>
+#include <linux/dcache.h>
+#include <linux/namei.h>
+#include <linux/fs.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/uio.h>
#define XVA_MAPSIZE 3
#define XVA_MAGIC 0x78766174
+#define FREAD 1
+#define FWRITE 2
+#define FCREAT O_CREAT
+#define FTRUNC O_TRUNC
+#define FOFFMAX O_LARGEFILE
+#define FSYNC O_SYNC
+#define FDSYNC O_DSYNC
+#define FRSYNC O_RSYNC
+#define FEXCL O_EXCL
+#define FDIRECT O_DIRECT
+
+#define FNODSYNC 0x10000 /* fsync pseudo flag */
+#define FNOFOLLOW 0x20000 /* don't follow symlinks */
+
+#define AT_TYPE 0x00001
+#define AT_MODE 0x00002
+#undef AT_UID /* Conflicts with linux/auxvec.h */
+#define AT_UID 0x00004
+#undef AT_GID /* Conflicts with linux/auxvec.h */
+#define AT_GID 0x00008
+#define AT_FSID 0x00010
+#define AT_NODEID 0x00020
+#define AT_NLINK 0x00040
+#define AT_SIZE 0x00080
+#define AT_ATIME 0x00100
+#define AT_MTIME 0x00200
+#define AT_CTIME 0x00400
+#define AT_RDEV 0x00800
+#define AT_BLKSIZE 0x01000
+#define AT_NBLOCKS 0x02000
+#define AT_SEQ 0x08000
+#define AT_XVATTR 0x10000
+
+#define CRCREAT 0
+
typedef enum vtype {
- VNON = 0,
- VREG = 1,
- VDIR = 2,
- VBLK = 3,
- VCHR = 4,
- VLNK = 5,
- VFIFO = 6,
- VDOOR = 7,
- VPROC = 8,
- VSOCK = 9,
- VPORT = 10,
- VBAD = 11
+ VNON = 0,
+ VREG = 1,
+ VDIR = 2,
+ VBLK = 3,
+ VCHR = 4,
+ VLNK = 5,
+ VFIFO = 6,
+ VDOOR = 7,
+ VPROC = 8,
+ VSOCK = 9,
+ VPORT = 10,
+ VBAD = 11
} vtype_t;
typedef struct vnode {
- uint64_t v_size;
- int v_fd;
- mode_t v_mode;
- char *v_path;
+ struct file *v_fp;
vtype_t v_type;
} vnode_t;
+typedef struct vattr {
+ enum vtype va_type; /* vnode type */
+ u_short va_mode; /* acc mode */
+ short va_uid; /* owner uid */
+ short va_gid; /* owner gid */
+ long va_fsid; /* fs id */
+ long va_nodeid; /* node # */
+ short va_nlink; /* # links */
+ u_long va_size; /* file size */
+ long va_blocksize; /* block size */
+ struct timeval va_atime; /* last acc */
+ struct timeval va_mtime; /* last mod */
+ struct timeval va_ctime; /* last chg */
+ dev_t va_rdev; /* dev */
+ long va_blocks; /* space used */
+} vattr_t;
+#if 0
typedef struct xoptattr {
timestruc_t xoa_createtime; /* Create time of file */
uint8_t xoa_archive;
uint8_t xoa_av_modified;
} xoptattr_t;
-typedef struct vattr {
- uint_t va_mask; /* bit-mask of attributes */
- u_offset_t va_size; /* file size in bytes */
-} vattr_t;
-
-
typedef struct xvattr {
vattr_t xva_vattr; /* Embedded vattr structure */
uint32_t xva_magic; /* Magic Number */
void *vsa_dfaclentp; /* pointer to default ACL entries */
size_t vsa_aclentsz; /* ACE size in bytes of vsa_aclentp */
} vsecattr_t;
-
-#define AT_TYPE 0x00001
-#define AT_MODE 0x00002
-// #define AT_UID 0x00004 /* Conflicts with linux/auxvec.h */
-// #define AT_GID 0x00008 /* Conflicts with linux/auxvec.h */
-#define AT_FSID 0x00010
-#define AT_NODEID 0x00020
-#define AT_NLINK 0x00040
-#define AT_SIZE 0x00080
-#define AT_ATIME 0x00100
-#define AT_MTIME 0x00200
-#define AT_CTIME 0x00400
-#define AT_RDEV 0x00800
-#define AT_BLKSIZE 0x01000
-#define AT_NBLOCKS 0x02000
-#define AT_SEQ 0x08000
-#define AT_XVATTR 0x10000
-
-#define CRCREAT 0
-
-#define VOP_CLOSE(vp, f, c, o, cr, ct) 0
-#define VOP_PUTPAGE(vp, of, sz, fl, cr, ct) 0
-#define VOP_GETATTR(vp, vap, fl, cr, ct) ((vap)->va_size = (vp)->v_size, 0)
-
-#define VOP_FSYNC(vp, f, cr, ct) sys_fsync((vp)->v_fd)
-
-#define VN_RELE(vp) vn_close(vp)
-
-extern int vn_open(char *path, int x1, int oflags, int mode, vnode_t **vpp,
- int x2, int x3);
-extern int vn_openat(char *path, int x1, int oflags, int mode, vnode_t **vpp,
- int x2, int x3, vnode_t *vp, int fd);
-extern int vn_rdwr(int uio, vnode_t *vp, void *addr, ssize_t len,
- offset_t offset, int x1, int x2, rlim64_t x3, void *x4, ssize_t *residp);
-extern void vn_close(vnode_t *vp);
-
-#define vn_remove(path, x1, x2) remove(path)
-#define vn_rename(from, to, seg) rename((from), (to))
-#define vn_is_readonly(vp) B_FALSE
-
-extern vnode_t *rootdir;
+#endif
+
+extern int vn_open(const char *path, int seg, int flags, int mode,
+ vnode_t **vpp, int x1, void *x2);
+extern int vn_openat(const char *path, int seg, int flags, int mode,
+ vnode_t **vpp, int x1, void *x2, vnode_t *vp, int fd);
+extern int vn_rdwr(uio_rw_t uio, vnode_t *vp, void *addr, ssize_t len,
+ offset_t off, int seg, int x1, rlim64_t x2,
+ void *x3, ssize_t *residp);
+extern int vn_close(vnode_t *vp, int flags, int x1, int x2, int x3, int x4);
+extern int vn_remove(const char *path, int x1, int x2);
+extern int vn_rename(const char *path1, const char *path2, int x1);
+extern int vn_getattr(vnode_t *vp, vattr_t *vap, int flags, int x3, void *x4);
+extern int vn_fsync(vnode_t *vp, int flags, int x3, int x4);
+
+#define VOP_CLOSE vn_close
+#define VN_RELE(vp)
+#define VOP_GETATTR vn_getattr
+#define VOP_FSYNC vn_fsync
+#define VOP_PUTPAGE(vp, of, sz, fl, cr, ct)
+#define vn_is_readonly(vp) 0
+
+extern void *rootdir;
#endif /* SPL_VNODE_H */
#include <sys/kobj.h>
#include "config.h"
-void *rootdir = NULL;
-EXPORT_SYMBOL(rootdir);
-
struct _buf *
kobj_open_file(const char *name)
{
struct _buf *file;
- struct file *fp;
+ vnode_t *vp;
+ int rc;
- fp = filp_open(name, O_RDONLY, 0644);
- if (IS_ERR(fp))
+ if ((rc = vn_open(name, UIO_SYSSPACE, FREAD, 0644, &vp, 0, 0)))
return ((_buf_t *)-1UL);
- file = kmem_zalloc(sizeof(_buf_t), KM_SLEEP);
- file->fp = fp;
+ file = kmalloc(sizeof(_buf_t), GFP_KERNEL);
+ file->vp = vp;
return file;
} /* kobj_open_file() */
void
kobj_close_file(struct _buf *file)
{
- filp_close(file->fp, 0);
- kmem_free(file, sizeof(_buf_t));
+ VOP_CLOSE(file->vp, 0, 0, 0, 0, 0);
+ VN_RELE(file->vp);
+ kfree(file);
return;
} /* kobj_close_file() */
EXPORT_SYMBOL(kobj_close_file);
int
-kobj_read_file(struct _buf *file, char *buf, unsigned size, unsigned off)
+kobj_read_file(struct _buf *file, char *buf, ssize_t size, offset_t off)
{
- loff_t offset = off;
- mm_segment_t saved_fs;
- int rc;
-
- if (!file || !file->fp)
- return -EINVAL;
-
- if (!file->fp->f_op || !file->fp->f_op->read)
- return -ENOSYS;
-
- /* Writable user data segment must be briefly increased for this
- * process so we can use the user space read call paths to write
- * in to memory allocated by the kernel. */
- saved_fs = get_fs();
- set_fs(get_ds());
- rc = file->fp->f_op->read(file->fp, buf, size, &offset);
- set_fs(saved_fs);
-
- return rc;
+ return vn_rdwr(UIO_READ, file->vp, buf, size, off,
+ UIO_SYSSPACE, 0, RLIM64_INFINITY, 0, NULL);
} /* kobj_read_file() */
EXPORT_SYMBOL(kobj_read_file);
int
kobj_get_filesize(struct _buf *file, uint64_t *size)
{
- struct kstat stat;
+ vattr_t vap;
int rc;
- if (!file || !file->fp || !size)
- return -EINVAL;
-
- rc = vfs_getattr(file->fp->f_vfsmnt, file->fp->f_dentry, &stat);
+ rc = VOP_GETATTR(file->vp, &vap, 0, 0, NULL);
if (rc)
return rc;
- *size = stat.size;
+ *size = vap.va_size;
+
return rc;
} /* kobj_get_filesize() */
EXPORT_SYMBOL(kobj_get_filesize);
#include <sys/sysmacros.h>
+#include <sys/vnode.h>
#include "config.h"
-/*
- * XXX: currently borrrowed from libsolcompat until this
- * can be adapted to the linux kernel interfaces.
- */
-#if 0
-/*
- * =========================================================================
- * vnode operations
- * =========================================================================
- */
-/*
- * Note: for the xxxat() versions of these functions, we assume that the
- * starting vp is always rootdir (which is true for spa_directory.c, the only
- * ZFS consumer of these interfaces). We assert this is true, and then emulate
- * them by adding '/' in front of the path.
- */
-
-/*ARGSUSED*/
+void *rootdir = NULL;
+EXPORT_SYMBOL(rootdir);
+
+static vtype_t
+vn_get_sol_type(umode_t mode)
+{
+ if (S_ISREG(mode))
+ return VREG;
+
+ if (S_ISDIR(mode))
+ return VDIR;
+
+ if (S_ISCHR(mode))
+ return VCHR;
+
+ if (S_ISBLK(mode))
+ return VBLK;
+
+ if (S_ISFIFO(mode))
+ return VFIFO;
+
+ if (S_ISLNK(mode))
+ return VLNK;
+
+ if (S_ISSOCK(mode))
+ return VSOCK;
+
+ if (S_ISCHR(mode))
+ return VCHR;
+
+ return VNON;
+} /* vn_get_sol_type() */
+
int
-vn_open(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2, int x3)
+vn_open(const char *path, int seg, int flags, int mode,
+ vnode_t **vpp, int x1, void *x2)
{
- int fd;
+ struct file *fp;
+ struct kstat stat;
+ int rc, saved_umask, flags_rw;
vnode_t *vp;
- int old_umask;
- char realpath[MAXPATHLEN];
- struct stat64 st;
-
- /*
- * If we're accessing a real disk from userland, we need to use
- * the character interface to avoid caching. This is particularly
- * important if we're trying to look at a real in-kernel storage
- * pool from userland, e.g. via zdb, because otherwise we won't
- * see the changes occurring under the segmap cache.
- * On the other hand, the stupid character device returns zero
- * for its size. So -- gag -- we open the block device to get
- * its size, and remember it for subsequent VOP_GETATTR().
- */
-#if defined(__sun__) || defined(__sun)
- if (strncmp(path, "/dev/", 5) == 0) {
-#else
- if (0) {
-#endif
- char *dsk;
- fd = open64(path, O_RDONLY);
- if (fd == -1)
- return (errno);
- if (fstat64(fd, &st) == -1) {
- close(fd);
- return (errno);
- }
- close(fd);
- (void) sprintf(realpath, "%s", path);
- dsk = strstr(path, "/dsk/");
- if (dsk != NULL)
- (void) sprintf(realpath + (dsk - path) + 1, "r%s",
- dsk + 1);
- } else {
- (void) sprintf(realpath, "%s", path);
- if (!(flags & FCREAT) && stat64(realpath, &st) == -1)
- return (errno);
- }
-#ifdef __linux__
- if (!(flags & FCREAT) && S_ISBLK(st.st_mode)) {
- flags |= O_DIRECT;
- if (flags & FWRITE)
- flags |= O_EXCL;
+ BUG_ON(seg != UIO_SYSSPACE);
+ BUG_ON(!vpp);
+ *vpp = NULL;
+
+ if (!(flags & FCREAT) && (flags & FWRITE))
+ flags |= FEXCL;
+
+ flags_rw = flags & (FWRITE | FREAD);
+ flags &= ~(FWRITE | FREAD);
+ switch (flags_rw) {
+ case FWRITE: flags |= O_WRONLY;
+ case FREAD: flags |= O_RDONLY;
+ case (FWRITE | FREAD): flags |= O_RDWR;
}
-#endif
if (flags & FCREAT)
- old_umask = umask(0);
+ saved_umask = xchg(¤t->fs->umask, 0);
- /*
- * The construct 'flags - FREAD' conveniently maps combinations of
- * FREAD and FWRITE to the corresponding O_RDONLY, O_WRONLY, and O_RDWR.
- */
- fd = open64(realpath, flags - FREAD, mode);
+ fp = filp_open(path, flags, mode);
if (flags & FCREAT)
- (void) umask(old_umask);
+ (void)xchg(¤t->fs->umask, saved_umask);
- if (fd == -1)
- return (errno);
+ if (IS_ERR(fp))
+ return PTR_ERR(fp);
- if (fstat64(fd, &st) == -1) {
- close(fd);
- return (errno);
+ rc = vfs_getattr(fp->f_vfsmnt, fp->f_dentry, &stat);
+ if (rc) {
+ filp_close(fp, 0);
+ return rc;
}
- (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
-
- *vpp = vp = umem_zalloc(sizeof (vnode_t), UMEM_NOFAIL);
+ vp = kmalloc(sizeof(vnode_t), GFP_ATOMIC);
+ if (!vp) {
+ filp_close(fp, 0);
+ return -ENOMEM;
+ }
- vp->v_fd = fd;
- vp->v_size = st.st_size;
- vp->v_mode = st.st_mode;
- vp->v_path = spa_strdup(path);
+ vp->v_type = vn_get_sol_type(stat.mode);
+ vp->v_fp = fp;
+ *vpp = vp;
- return (0);
-}
+ return 0;
+} /* vn_open() */
+EXPORT_SYMBOL(vn_open);
-/*ARGSUSED*/
int
-vn_openat(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2,
- int x3, vnode_t *startvp, int fd)
+vn_openat(const char *path, int seg, int flags, int mode,
+ vnode_t **vpp, int x1, void *x2, vnode_t *vp, int fd)
{
- char *realpath = umem_alloc(strlen(path) + 2, UMEM_NOFAIL);
- int ret;
+ char *realpath;
+ int rc;
- ASSERT(startvp == rootdir);
- (void) sprintf(realpath, "/%s", path);
+ BUG_ON(vp != rootdir);
- /* fd ignored for now, need if want to simulate nbmand support */
- ret = vn_open(realpath, x1, flags, mode, vpp, x2, x3);
+ realpath = kmalloc(strlen(path) + 2, GFP_KERNEL);
+ if (!realpath)
+ return -ENOMEM;
- umem_free(realpath, strlen(path) + 2);
+ sprintf(realpath, "/%s", path);
+ rc = vn_open(realpath, seg, flags, mode, vpp, x1, x2);
- return (ret);
-}
+ kfree(realpath);
+
+ return rc;
+} /* vn_openat() */
+EXPORT_SYMBOL(vn_openat);
-/*ARGSUSED*/
int
-vn_rdwr(int uio, vnode_t *vp, void *addr, ssize_t len, offset_t offset,
- int x1, int x2, rlim64_t x3, void *x4, ssize_t *residp)
+vn_rdwr(uio_rw_t uio, vnode_t *vp, void *addr, ssize_t len, offset_t off,
+ int seg, int x1, rlim64_t x2, void *x3, ssize_t *residp)
{
- ssize_t iolen, split;
+ loff_t offset;
+ mm_segment_t saved_fs;
+ struct file *fp;
+ int rc;
+
+ BUG_ON(!(uio == UIO_WRITE || uio == UIO_READ));
+ BUG_ON(!vp);
+ BUG_ON(!vp->v_fp);
+ BUG_ON(seg != UIO_SYSSPACE);
+ BUG_ON(x1 != 0);
+ BUG_ON(x2 != RLIM64_INFINITY);
+
+ offset = off;
+ fp = vp->v_fp;
+
+ /* Writable user data segment must be briefly increased for this
+ * process so we can use the user space read call paths to write
+ * in to memory allocated by the kernel. */
+ saved_fs = get_fs();
+ set_fs(get_ds());
+
+ if (uio & UIO_WRITE)
+ rc = vfs_write(fp, addr, len, &offset);
+ else
+ rc = vfs_read(fp, addr, len, &offset);
+
+ set_fs(saved_fs);
+
+ if (rc < 0)
+ return rc;
- if (uio == UIO_READ) {
- iolen = pread64(vp->v_fd, addr, len, offset);
+ if (residp) {
+ *residp = len - rc;
} else {
- /*
- * To simulate partial disk writes, we split writes into two
- * system calls so that the process can be killed in between.
- */
-#ifdef ZFS_DEBUG
- if (!S_ISBLK(vp->v_mode) && !S_ISCHR(vp->v_mode)) {
- split = (len > 0 ? rand() % len : 0);
- iolen = pwrite64(vp->v_fd, addr, split, offset);
- iolen += pwrite64(vp->v_fd, (char *)addr + split,
- len - split, offset + split);
- } else
- iolen = pwrite64(vp->v_fd, addr, len, offset);
-#else
- iolen = pwrite64(vp->v_fd, addr, len, offset);
-#endif
+ if (rc != len)
+ return -EIO;
}
- if (iolen < 0)
- return (errno);
- if (residp)
- *residp = len - iolen;
- else if (iolen != len)
- return (EIO);
- return (0);
+ return 0;
+} /* vn_rdwr() */
+EXPORT_SYMBOL(vn_rdwr);
+
+int
+vn_close(vnode_t *vp, int flags, int x1, int x2, int x3, int x4)
+{
+ int rc;
+
+ BUG_ON(!vp);
+ BUG_ON(!vp->v_fp);
+
+ rc = filp_close(vp->v_fp, 0);
+ kfree(vp);
+
+ return rc;
+} /* vn_close() */
+EXPORT_SYMBOL(vn_close);
+
+static struct dentry *lookup_hash(struct nameidata *nd)
+{
+ return __lookup_hash(&nd->last, nd->dentry, nd);
+} /* lookup_hash() */
+
+/* Modified do_unlinkat() from linux/fs/namei.c, only uses exported symbols */
+int
+vn_remove(const char *path, int x1, int x2)
+{
+ struct dentry *dentry;
+ struct nameidata nd;
+ struct inode *inode = NULL;
+ int rc = 0;
+
+ rc = path_lookup(path, LOOKUP_PARENT, &nd);
+ if (rc)
+ goto exit;
+
+ rc = -EISDIR;
+ if (nd.last_type != LAST_NORM)
+ goto exit1;
+
+ mutex_lock_nested(&nd.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
+ dentry = lookup_hash(&nd);
+ rc = PTR_ERR(dentry);
+ if (!IS_ERR(dentry)) {
+ /* Why not before? Because we want correct rc value */
+ if (nd.last.name[nd.last.len])
+ goto slashes;
+ inode = dentry->d_inode;
+ if (inode)
+ atomic_inc(&inode->i_count);
+ rc = vfs_unlink(nd.dentry->d_inode, dentry);
+exit2:
+ dput(dentry);
+ }
+ mutex_unlock(&nd.dentry->d_inode->i_mutex);
+ if (inode)
+ iput(inode); /* truncate the inode here */
+exit1:
+ path_release(&nd);
+exit:
+ return rc;
+
+slashes:
+ rc = !dentry->d_inode ? -ENOENT :
+ S_ISDIR(dentry->d_inode->i_mode) ? -EISDIR : -ENOTDIR;
+ goto exit2;
+} /* vn_remove() */
+EXPORT_SYMBOL(vn_remove);
+
+/* Modified do_rename() from linux/fs/namei.c, only uses exported symbols */
+int
+vn_rename(const char *oldname, const char *newname, int x1)
+{
+ struct dentry * old_dir, * new_dir;
+ struct dentry * old_dentry, *new_dentry;
+ struct dentry * trap;
+ struct nameidata oldnd, newnd;
+ int rc = 0;
+
+ rc = path_lookup(oldname, LOOKUP_PARENT, &oldnd);
+ if (rc)
+ goto exit;
+
+ rc = path_lookup(newname, LOOKUP_PARENT, &newnd);
+ if (rc)
+ goto exit1;
+
+ rc = -EXDEV;
+ if (oldnd.mnt != newnd.mnt)
+ goto exit2;
+
+ old_dir = oldnd.dentry;
+ rc = -EBUSY;
+ if (oldnd.last_type != LAST_NORM)
+ goto exit2;
+
+ new_dir = newnd.dentry;
+ if (newnd.last_type != LAST_NORM)
+ goto exit2;
+
+ trap = lock_rename(new_dir, old_dir);
+
+ old_dentry = lookup_hash(&oldnd);
+
+ rc = PTR_ERR(old_dentry);
+ if (IS_ERR(old_dentry))
+ goto exit3;
+
+ /* source must exist */
+ rc = -ENOENT;
+ if (!old_dentry->d_inode)
+ goto exit4;
+
+ /* unless the source is a directory trailing slashes give -ENOTDIR */
+ if (!S_ISDIR(old_dentry->d_inode->i_mode)) {
+ rc = -ENOTDIR;
+ if (oldnd.last.name[oldnd.last.len])
+ goto exit4;
+ if (newnd.last.name[newnd.last.len])
+ goto exit4;
+ }
+
+ /* source should not be ancestor of target */
+ rc = -EINVAL;
+ if (old_dentry == trap)
+ goto exit4;
+
+ new_dentry = lookup_hash(&newnd);
+ rc = PTR_ERR(new_dentry);
+ if (IS_ERR(new_dentry))
+ goto exit4;
+
+ /* target should not be an ancestor of source */
+ rc = -ENOTEMPTY;
+ if (new_dentry == trap)
+ goto exit5;
+
+ rc = vfs_rename(old_dir->d_inode, old_dentry,
+ new_dir->d_inode, new_dentry);
+exit5:
+ dput(new_dentry);
+exit4:
+ dput(old_dentry);
+exit3:
+ unlock_rename(new_dir, old_dir);
+exit2:
+ path_release(&newnd);
+exit1:
+ path_release(&oldnd);
+exit:
+ return rc;
}
+EXPORT_SYMBOL(vn_rename);
-void
-vn_close(vnode_t *vp)
+int
+vn_getattr(vnode_t *vp, vattr_t *vap, int flags, int x3, void *x4)
{
- close(vp->v_fd);
- spa_strfree(vp->v_path);
- umem_free(vp, sizeof (vnode_t));
+ struct file *fp;
+ struct kstat stat;
+ int rc;
+
+ BUG_ON(!vp);
+ BUG_ON(!vp->v_fp);
+ BUG_ON(!vap);
+
+ fp = vp->v_fp;
+
+ rc = vfs_getattr(fp->f_vfsmnt, fp->f_dentry, &stat);
+ if (rc)
+ return rc;
+
+ vap->va_type = vn_get_sol_type(stat.mode);
+ vap->va_mode = stat.mode;
+ vap->va_uid = stat.uid;
+ vap->va_gid = stat.gid;
+ vap->va_fsid = 0;
+ vap->va_nodeid = stat.ino;
+ vap->va_nlink = stat.nlink;
+ vap->va_size = stat.size;
+ vap->va_blocksize = stat.blksize;
+ vap->va_atime.tv_sec = stat.atime.tv_sec;
+ vap->va_atime.tv_usec = stat.atime.tv_nsec / NSEC_PER_USEC;
+ vap->va_mtime.tv_sec = stat.mtime.tv_sec;
+ vap->va_mtime.tv_usec = stat.mtime.tv_nsec / NSEC_PER_USEC;
+ vap->va_ctime.tv_sec = stat.ctime.tv_sec;
+ vap->va_ctime.tv_usec = stat.ctime.tv_nsec / NSEC_PER_USEC;
+ vap->va_rdev = stat.rdev;
+ vap->va_blocks = stat.blocks;
+
+ return rc;
}
-#endif
+EXPORT_SYMBOL(vn_getattr);
+
+int vn_fsync(vnode_t *vp, int flags, int x3, int x4)
+{
+ BUG_ON(!vp);
+ BUG_ON(!vp->v_fp);
+
+ return file_fsync(vp->v_fp, vp->v_fp->f_dentry, 0);
+} /* vn_fsync() */
+EXPORT_SYMBOL(vn_fsync);
splat-objs += splat-thread.o
splat-objs += splat-rwlock.o
splat-objs += splat-time.o
+splat-objs += splat-vnode.o
splat-objs += splat-kobj.o
splatmodule := splat.ko
SPLAT_SUBSYSTEM_INIT(thread);
SPLAT_SUBSYSTEM_INIT(rwlock);
SPLAT_SUBSYSTEM_INIT(time);
+ SPLAT_SUBSYSTEM_INIT(vnode);
SPLAT_SUBSYSTEM_INIT(kobj);
dev = MKDEV(SPLAT_MAJOR, 0);
unregister_chrdev_region(dev, SPLAT_MINORS);
SPLAT_SUBSYSTEM_FINI(kobj);
+ SPLAT_SUBSYSTEM_FINI(vnode);
SPLAT_SUBSYSTEM_FINI(time);
SPLAT_SUBSYSTEM_FINI(rwlock);
SPLAT_SUBSYSTEM_FINI(thread);
splat_subsystem_t * splat_taskq_init(void);
splat_subsystem_t * splat_thread_init(void);
splat_subsystem_t * splat_time_init(void);
+splat_subsystem_t * splat_vnode_init(void);
splat_subsystem_t * splat_kobj_init(void);
void splat_condvar_fini(splat_subsystem_t *);
void splat_taskq_fini(splat_subsystem_t *);
void splat_thread_fini(splat_subsystem_t *);
void splat_time_fini(splat_subsystem_t *);
+void splat_vnode_fini(splat_subsystem_t *);
void splat_kobj_fini(splat_subsystem_t *);
int splat_condvar_id(void);
int splat_taskq_id(void);
int splat_thread_id(void);
int splat_time_id(void);
+int splat_vnode_id(void);
int splat_kobj_id(void);
#endif /* _SPLAT_INTERNAL_H */
#include "splat-internal.h"
-#define SPLAT_SUBSYSTEM_KOBJ 0x0900
+#define SPLAT_SUBSYSTEM_KOBJ 0x0a00
#define SPLAT_KOBJ_NAME "kobj"
#define SPLAT_KOBJ_DESC "Kernel File Tests"
-#define SPLAT_KOBJ_TEST1_ID 0x0901
-#define SPLAT_KOBJ_TEST1_NAME "kobj1"
+#define SPLAT_KOBJ_TEST1_ID 0x0a01
+#define SPLAT_KOBJ_TEST1_NAME "open"
#define SPLAT_KOBJ_TEST1_DESC "File Open/Close Test"
-#define SPLAT_KOBJ_TEST2_ID 0x0902
-#define SPLAT_KOBJ_TEST2_NAME "kobj2"
+#define SPLAT_KOBJ_TEST2_ID 0x0a02
+#define SPLAT_KOBJ_TEST2_NAME "size/read"
#define SPLAT_KOBJ_TEST2_DESC "File Size/Read Test"
#define SPLAT_KOBJ_TEST_FILE "/etc/fstab"
--- /dev/null
+#include "splat-internal.h"
+
+#define SPLAT_SUBSYSTEM_VNODE 0x0900
+#define SPLAT_VNODE_NAME "vnode"
+#define SPLAT_VNODE_DESC "Kernel Vnode Tests"
+
+#define SPLAT_VNODE_TEST1_ID 0x0901
+#define SPLAT_VNODE_TEST1_NAME "vn_open"
+#define SPLAT_VNODE_TEST1_DESC "Vn_open Test"
+
+#define SPLAT_VNODE_TEST2_ID 0x0902
+#define SPLAT_VNODE_TEST2_NAME "vn_openat"
+#define SPLAT_VNODE_TEST2_DESC "Vn_openat Test"
+
+#define SPLAT_VNODE_TEST3_ID 0x0903
+#define SPLAT_VNODE_TEST3_NAME "vn_rdwr"
+#define SPLAT_VNODE_TEST3_DESC "Vn_rdwrt Test"
+
+#define SPLAT_VNODE_TEST4_ID 0x0904
+#define SPLAT_VNODE_TEST4_NAME "vn_rename"
+#define SPLAT_VNODE_TEST4_DESC "Vn_rename Test"
+
+#define SPLAT_VNODE_TEST5_ID 0x0905
+#define SPLAT_VNODE_TEST5_NAME "vn_getattr"
+#define SPLAT_VNODE_TEST5_DESC "Vn_getattr Test"
+
+#define SPLAT_VNODE_TEST6_ID 0x0906
+#define SPLAT_VNODE_TEST6_NAME "vn_sync"
+#define SPLAT_VNODE_TEST6_DESC "Vn_sync Test"
+
+#define SPLAT_VNODE_TEST_FILE "/etc/fstab"
+#define SPLAT_VNODE_TEST_FILE_AT "etc/fstab"
+#define SPLAT_VNODE_TEST_FILE_RW "/tmp/spl.vnode.tmp"
+#define SPLAT_VNODE_TEST_FILE_RW1 "/tmp/spl.vnode.tmp.1"
+#define SPLAT_VNODE_TEST_FILE_RW2 "/tmp/spl.vnode.tmp.2"
+
+static int
+splat_vnode_test1(struct file *file, void *arg)
+{
+ vnode_t *vp;
+ int rc;
+
+ if ((rc = vn_open(SPLAT_VNODE_TEST_FILE, UIO_SYSSPACE,
+ FREAD, 0644, &vp, 0, 0))) {
+ splat_vprint(file, SPLAT_VNODE_TEST1_NAME,
+ "Failed to vn_open test file: %s (%d)\n",
+ SPLAT_VNODE_TEST_FILE, rc);
+ return rc;
+ }
+
+ rc = VOP_CLOSE(vp, 0, 0, 0, 0, 0);
+ VN_RELE(vp);
+
+ if (rc) {
+ splat_vprint(file, SPLAT_VNODE_TEST1_NAME,
+ "Failed to vn_close test file: %s (%d)\n",
+ SPLAT_VNODE_TEST_FILE, rc);
+ return rc;
+ }
+
+ splat_vprint(file, SPLAT_VNODE_TEST1_NAME, "Successfully vn_open'ed "
+ "and vn_closed test file: %s\n", SPLAT_VNODE_TEST_FILE);
+
+ return rc;
+} /* splat_vnode_test1() */
+
+static int
+splat_vnode_test2(struct file *file, void *arg)
+{
+ vnode_t *vp;
+ int rc;
+
+ if ((rc = vn_openat(SPLAT_VNODE_TEST_FILE_AT, UIO_SYSSPACE,
+ FREAD, 0644, &vp, 0, 0, rootdir, 0))) {
+ splat_vprint(file, SPLAT_VNODE_TEST2_NAME,
+ "Failed to vn_openat test file: %s (%d)\n",
+ SPLAT_VNODE_TEST_FILE, rc);
+ return rc;
+ }
+
+ rc = VOP_CLOSE(vp, 0, 0, 0, 0, 0);
+ VN_RELE(vp);
+
+ if (rc) {
+ splat_vprint(file, SPLAT_VNODE_TEST2_NAME,
+ "Failed to vn_close test file: %s (%d)\n",
+ SPLAT_VNODE_TEST_FILE, rc);
+ return rc;
+ }
+
+ splat_vprint(file, SPLAT_VNODE_TEST2_NAME, "Successfully vn_openat'ed "
+ "and vn_closed test file: %s\n", SPLAT_VNODE_TEST_FILE);
+
+ return rc;
+} /* splat_vnode_test2() */
+
+static int
+splat_vnode_test3(struct file *file, void *arg)
+{
+ vnode_t *vp;
+ char buf1[32] = "SPL VNode Interface Test File\n";
+ char buf2[32] = "";
+ int rc;
+
+ if ((rc = vn_open(SPLAT_VNODE_TEST_FILE_RW, UIO_SYSSPACE,
+ FWRITE | FREAD | FCREAT | FEXCL,
+ 0644, &vp, 0, 0))) {
+ splat_vprint(file, SPLAT_VNODE_TEST3_NAME,
+ "Failed to vn_open test file: %s (%d)\n",
+ SPLAT_VNODE_TEST_FILE_RW, rc);
+ return rc;
+ }
+
+ rc = vn_rdwr(UIO_WRITE, vp, buf1, strlen(buf1), 0,
+ UIO_SYSSPACE, 0, RLIM64_INFINITY, 0, NULL);
+ if (rc < 0) {
+ splat_vprint(file, SPLAT_VNODE_TEST3_NAME,
+ "Failed vn_rdwr write of test file: %s (%d)\n",
+ SPLAT_VNODE_TEST_FILE_RW, rc);
+ goto out;
+ }
+
+ rc = vn_rdwr(UIO_READ, vp, buf2, strlen(buf1), 0,
+ UIO_SYSSPACE, 0, RLIM64_INFINITY, 0, NULL);
+ if (rc < 0) {
+ splat_vprint(file, SPLAT_VNODE_TEST3_NAME,
+ "Failed vn_rdwr read of test file: %s (%d)\n",
+ SPLAT_VNODE_TEST_FILE_RW, rc);
+ goto out;
+ }
+
+ if (strncmp(buf1, buf2, strlen(buf1))) {
+ rc = EINVAL;
+ splat_vprint(file, SPLAT_VNODE_TEST3_NAME,
+ "Failed strncmp data written does not match "
+ "data read\nWrote: %sRead: %s\n", buf1, buf2);
+ goto out;
+ }
+
+ rc = 0;
+ splat_vprint(file, SPLAT_VNODE_TEST3_NAME, "Wrote: %s", buf1);
+ splat_vprint(file, SPLAT_VNODE_TEST3_NAME, "Read: %s", buf2);
+ splat_vprint(file, SPLAT_VNODE_TEST3_NAME, "Successfully wrote and "
+ "read expected data pattern to test file: %s\n",
+ SPLAT_VNODE_TEST_FILE_RW);
+
+out:
+ VOP_CLOSE(vp, 0, 0, 0, 0, 0);
+ VN_RELE(vp);
+ vn_remove(SPLAT_VNODE_TEST_FILE_RW, 0, 0);
+
+ return rc;
+} /* splat_vnode_test3() */
+
+static int
+splat_vnode_test4(struct file *file, void *arg)
+{
+ vnode_t *vp;
+ char buf1[32] = "SPL VNode Interface Test File\n";
+ char buf2[32] = "";
+ int rc;
+
+ if ((rc = vn_open(SPLAT_VNODE_TEST_FILE_RW1, UIO_SYSSPACE,
+ FWRITE | FREAD | FCREAT | FEXCL, 0644, &vp, 0, 0))) {
+ splat_vprint(file, SPLAT_VNODE_TEST4_NAME,
+ "Failed to vn_open test file: %s (%d)\n",
+ SPLAT_VNODE_TEST_FILE_RW1, rc);
+ goto out;
+ }
+
+ rc = vn_rdwr(UIO_WRITE, vp, buf1, strlen(buf1), 0,
+ UIO_SYSSPACE, 0, RLIM64_INFINITY, 0, NULL);
+ if (rc < 0) {
+ splat_vprint(file, SPLAT_VNODE_TEST4_NAME,
+ "Failed vn_rdwr write of test file: %s (%d)\n",
+ SPLAT_VNODE_TEST_FILE_RW1, rc);
+ goto out2;
+ }
+
+ VOP_CLOSE(vp, 0, 0, 0, 0, 0);
+ VN_RELE(vp);
+
+ rc = vn_rename(SPLAT_VNODE_TEST_FILE_RW1,SPLAT_VNODE_TEST_FILE_RW2,0);
+ if (rc) {
+ splat_vprint(file, SPLAT_VNODE_TEST4_NAME, "Failed vn_rename "
+ "%s -> %s (%d)\n",
+ SPLAT_VNODE_TEST_FILE_RW1,
+ SPLAT_VNODE_TEST_FILE_RW2, rc);
+ goto out;
+ }
+
+ if ((rc = vn_open(SPLAT_VNODE_TEST_FILE_RW2, UIO_SYSSPACE,
+ FREAD | FEXCL, 0644, &vp, 0, 0))) {
+ splat_vprint(file, SPLAT_VNODE_TEST4_NAME,
+ "Failed to vn_open test file: %s (%d)\n",
+ SPLAT_VNODE_TEST_FILE_RW2, rc);
+ goto out;
+ }
+
+ rc = vn_rdwr(UIO_READ, vp, buf2, strlen(buf1), 0,
+ UIO_SYSSPACE, 0, RLIM64_INFINITY, 0, NULL);
+ if (rc < 0) {
+ splat_vprint(file, SPLAT_VNODE_TEST4_NAME,
+ "Failed vn_rdwr read of test file: %s (%d)\n",
+ SPLAT_VNODE_TEST_FILE_RW2, rc);
+ goto out2;
+ }
+
+ if (strncmp(buf1, buf2, strlen(buf1))) {
+ rc = EINVAL;
+ splat_vprint(file, SPLAT_VNODE_TEST4_NAME,
+ "Failed strncmp data written does not match "
+ "data read\nWrote: %sRead: %s\n", buf1, buf2);
+ goto out2;
+ }
+
+ rc = 0;
+ splat_vprint(file, SPLAT_VNODE_TEST4_NAME, "Wrote to %s: %s",
+ SPLAT_VNODE_TEST_FILE_RW1, buf1);
+ splat_vprint(file, SPLAT_VNODE_TEST4_NAME, "Read from %s: %s",
+ SPLAT_VNODE_TEST_FILE_RW2, buf2);
+ splat_vprint(file, SPLAT_VNODE_TEST4_NAME, "Successfully renamed "
+ "test file %s -> %s and verified data pattern\n",
+ SPLAT_VNODE_TEST_FILE_RW1, SPLAT_VNODE_TEST_FILE_RW2);
+out2:
+ VOP_CLOSE(vp, 0, 0, 0, 0, 0);
+ VN_RELE(vp);
+out:
+ vn_remove(SPLAT_VNODE_TEST_FILE_RW1, 0, 0);
+ vn_remove(SPLAT_VNODE_TEST_FILE_RW2, 0, 0);
+
+ return rc;
+} /* splat_vnode_test4() */
+
+static int
+splat_vnode_test5(struct file *file, void *arg)
+{
+ vnode_t *vp;
+ vattr_t vap;
+ int rc;
+
+ if ((rc = vn_open(SPLAT_VNODE_TEST_FILE, UIO_SYSSPACE,
+ FREAD, 0644, &vp, 0, 0))) {
+ splat_vprint(file, SPLAT_VNODE_TEST5_NAME,
+ "Failed to vn_open test file: %s (%d)\n",
+ SPLAT_VNODE_TEST_FILE, rc);
+ return rc;
+ }
+
+ rc = VOP_GETATTR(vp, &vap, 0, 0, NULL);
+ if (rc) {
+ splat_vprint(file, SPLAT_VNODE_TEST5_NAME,
+ "Failed to vn_getattr test file: %s (%d)\n",
+ SPLAT_VNODE_TEST_FILE, rc);
+ goto out;
+ }
+
+ if (vap.va_type != VREG) {
+ rc = -EINVAL;
+ splat_vprint(file, SPLAT_VNODE_TEST5_NAME,
+ "Failed expected regular file type "
+ "(%d != VREG): %s (%d)\n", vap.va_type,
+ SPLAT_VNODE_TEST_FILE, rc);
+ goto out;
+ }
+
+ splat_vprint(file, SPLAT_VNODE_TEST1_NAME, "Successfully "
+ "vn_getattr'ed test file: %s\n", SPLAT_VNODE_TEST_FILE);
+
+out:
+ VOP_CLOSE(vp, 0, 0, 0, 0, 0);
+ VN_RELE(vp);
+
+ return rc;
+} /* splat_vnode_test5() */
+
+static int
+splat_vnode_test6(struct file *file, void *arg)
+{
+ vnode_t *vp;
+ char buf[32] = "SPL VNode Interface Test File\n";
+ int rc;
+
+ if ((rc = vn_open(SPLAT_VNODE_TEST_FILE_RW, UIO_SYSSPACE,
+ FWRITE | FREAD | FCREAT | FEXCL, 0644, &vp, 0, 0))) {
+ splat_vprint(file, SPLAT_VNODE_TEST6_NAME,
+ "Failed to vn_open test file: %s (%d)\n",
+ SPLAT_VNODE_TEST_FILE_RW, rc);
+ return rc;
+ }
+
+ rc = vn_rdwr(UIO_WRITE, vp, buf, strlen(buf), 0,
+ UIO_SYSSPACE, 0, RLIM64_INFINITY, 0, NULL);
+ if (rc < 0) {
+ splat_vprint(file, SPLAT_VNODE_TEST6_NAME,
+ "Failed vn_rdwr write of test file: %s (%d)\n",
+ SPLAT_VNODE_TEST_FILE_RW, rc);
+ goto out;
+ }
+
+ rc = vn_fsync(vp, 0, 0, 0);
+ if (rc) {
+ splat_vprint(file, SPLAT_VNODE_TEST6_NAME,
+ "Failed vn_fsync of test file: %s (%d)\n",
+ SPLAT_VNODE_TEST_FILE_RW, rc);
+ goto out;
+ }
+
+ rc = 0;
+ splat_vprint(file, SPLAT_VNODE_TEST6_NAME, "Successfully "
+ "fsync'ed test file %s\n", SPLAT_VNODE_TEST_FILE_RW);
+out:
+ VOP_CLOSE(vp, 0, 0, 0, 0, 0);
+ VN_RELE(vp);
+ vn_remove(SPLAT_VNODE_TEST_FILE_RW, 0, 0);
+
+ return rc;
+} /* splat_vnode_test4() */
+
+splat_subsystem_t *
+splat_vnode_init(void)
+{
+ splat_subsystem_t *sub;
+
+ sub = kmalloc(sizeof(*sub), GFP_KERNEL);
+ if (sub == NULL)
+ return NULL;
+
+ memset(sub, 0, sizeof(*sub));
+ strncpy(sub->desc.name, SPLAT_VNODE_NAME, SPLAT_NAME_SIZE);
+ strncpy(sub->desc.desc, SPLAT_VNODE_DESC, SPLAT_DESC_SIZE);
+ INIT_LIST_HEAD(&sub->subsystem_list);
+ INIT_LIST_HEAD(&sub->test_list);
+ spin_lock_init(&sub->test_lock);
+ sub->desc.id = SPLAT_SUBSYSTEM_VNODE;
+
+ SPLAT_TEST_INIT(sub, SPLAT_VNODE_TEST1_NAME, SPLAT_VNODE_TEST1_DESC,
+ SPLAT_VNODE_TEST1_ID, splat_vnode_test1);
+ SPLAT_TEST_INIT(sub, SPLAT_VNODE_TEST2_NAME, SPLAT_VNODE_TEST2_DESC,
+ SPLAT_VNODE_TEST2_ID, splat_vnode_test2);
+ SPLAT_TEST_INIT(sub, SPLAT_VNODE_TEST3_NAME, SPLAT_VNODE_TEST3_DESC,
+ SPLAT_VNODE_TEST3_ID, splat_vnode_test3);
+ SPLAT_TEST_INIT(sub, SPLAT_VNODE_TEST4_NAME, SPLAT_VNODE_TEST4_DESC,
+ SPLAT_VNODE_TEST4_ID, splat_vnode_test4);
+ SPLAT_TEST_INIT(sub, SPLAT_VNODE_TEST5_NAME, SPLAT_VNODE_TEST5_DESC,
+ SPLAT_VNODE_TEST5_ID, splat_vnode_test5);
+ SPLAT_TEST_INIT(sub, SPLAT_VNODE_TEST6_NAME, SPLAT_VNODE_TEST6_DESC,
+ SPLAT_VNODE_TEST6_ID, splat_vnode_test6);
+
+ return sub;
+} /* splat_vnode_init() */
+
+void
+splat_vnode_fini(splat_subsystem_t *sub)
+{
+ ASSERT(sub);
+
+ SPLAT_TEST_FINI(sub, SPLAT_VNODE_TEST6_ID);
+ SPLAT_TEST_FINI(sub, SPLAT_VNODE_TEST5_ID);
+ SPLAT_TEST_FINI(sub, SPLAT_VNODE_TEST4_ID);
+ SPLAT_TEST_FINI(sub, SPLAT_VNODE_TEST3_ID);
+ SPLAT_TEST_FINI(sub, SPLAT_VNODE_TEST2_ID);
+ SPLAT_TEST_FINI(sub, SPLAT_VNODE_TEST1_ID);
+
+ kfree(sub);
+} /* splat_vnode_fini() */
+
+int
+splat_vnode_id(void)
+{
+ return SPLAT_SUBSYSTEM_VNODE;
+} /* splat_vnode_id() */
verbose="-v"
fi
+if [ -n "$TESTS" ]; then
+ tests="$TESTS"
+else
+ tests="-a"
+fi
+
if [ $(id -u) != 0 ]; then
die "Must run as root"
fi
echo "Loading ${splat_module}"
/sbin/insmod ${splat_module} || die "Unable to load ${splat_module}"
-sleep 3
-$splat_cmd -a $verbose
+while [ ! -c /dev/splatctl ]; do sleep 0.1; done
+$splat_cmd $tests $verbose
echo "Unloading ${splat_module}"
/sbin/rmmod ${splat_module} || die "Failed to unload ${splat_module}"