mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2024-12-26 03:09:34 +03:00
- Implemented vnode interfaces and 6 test cases to the test suite.
- Re-implmented kobj support based on the vnode support. - Add TESTS option to check.sh, and removed delay after module load. git-svn-id: https://outreach.scidac.gov/svn/spl/trunk@39 7e1ea52c-4ff2-0310-8f11-9dd32ca42a1c
This commit is contained in:
parent
9490c14835
commit
4b17158506
6
FIXME
6
FIXME
@ -11,8 +11,4 @@ sys/u8_textprep_data - AlL borrowed from libsolcompat
|
|||||||
sys/acl.h _ All borrowed from libsolcompat
|
sys/acl.h _ All borrowed from libsolcompat
|
||||||
sys/acl_impl.h _ All borrowed from libsolcompat
|
sys/acl_impl.h _ All borrowed from libsolcompat
|
||||||
|
|
||||||
* Fix failure in rw lock test 6
|
* Implement solaris style atomic interfaces
|
||||||
|
|
||||||
* Non-atomic 64bit support for kstat.h
|
|
||||||
|
|
||||||
* Write vnode interface
|
|
||||||
|
@ -5,21 +5,16 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <sys/vnode.h>
|
||||||
#include <linux/uaccess.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/kmem.h>
|
|
||||||
|
|
||||||
typedef struct _buf {
|
typedef struct _buf {
|
||||||
struct file *fp;
|
vnode_t *vp;
|
||||||
} _buf_t;
|
} _buf_t;
|
||||||
|
|
||||||
extern void *rootdir;
|
|
||||||
|
|
||||||
extern struct _buf *kobj_open_file(const char *name);
|
extern struct _buf *kobj_open_file(const char *name);
|
||||||
extern void kobj_close_file(struct _buf *file);
|
extern void kobj_close_file(struct _buf *file);
|
||||||
extern int kobj_read_file(struct _buf *file, char *buf,
|
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);
|
extern int kobj_get_filesize(struct _buf *file, uint64_t *size);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -56,21 +56,6 @@ extern "C" {
|
|||||||
#define NICE_TO_PRIO(nice) (MAX_RT_PRIO + (nice) + 20)
|
#define NICE_TO_PRIO(nice) (MAX_RT_PRIO + (nice) + 20)
|
||||||
#define PRIO_TO_NICE(prio) ((prio) - MAX_RT_PRIO - 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
|
/* Missing macros
|
||||||
*/
|
*/
|
||||||
#define PAGESIZE PAGE_SIZE
|
#define PAGESIZE PAGE_SIZE
|
||||||
@ -136,7 +121,6 @@ extern int highbit(unsigned long i);
|
|||||||
#define zone_dataset_visible(x, y) (1)
|
#define zone_dataset_visible(x, y) (1)
|
||||||
#define INGLOBALZONE(z) (1)
|
#define INGLOBALZONE(z) (1)
|
||||||
|
|
||||||
/* XXX - Borrowed from zfs project libsolcompat/include/sys/sysmacros.h */
|
|
||||||
/* common macros */
|
/* common macros */
|
||||||
#ifndef MIN
|
#ifndef MIN
|
||||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
#ifndef _SPL_UIO_H
|
#ifndef _SPL_UIO_H
|
||||||
#define _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
|
#define UIO_SYSSPACE 1
|
||||||
|
|
||||||
|
@ -1,11 +1,56 @@
|
|||||||
#ifndef _SPL_VNODE_H
|
#ifndef _SPL_VNODE_H
|
||||||
#define _SPL_VNODE_H
|
#define _SPL_VNODE_H
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
#include <linux/syscalls.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_MAPSIZE 3
|
||||||
#define XVA_MAGIC 0x78766174
|
#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 {
|
typedef enum vtype {
|
||||||
VNON = 0,
|
VNON = 0,
|
||||||
VREG = 1,
|
VREG = 1,
|
||||||
@ -22,14 +67,28 @@ typedef enum vtype {
|
|||||||
} vtype_t;
|
} vtype_t;
|
||||||
|
|
||||||
typedef struct vnode {
|
typedef struct vnode {
|
||||||
uint64_t v_size;
|
struct file *v_fp;
|
||||||
int v_fd;
|
|
||||||
mode_t v_mode;
|
|
||||||
char *v_path;
|
|
||||||
vtype_t v_type;
|
vtype_t v_type;
|
||||||
} vnode_t;
|
} 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 {
|
typedef struct xoptattr {
|
||||||
timestruc_t xoa_createtime; /* Create time of file */
|
timestruc_t xoa_createtime; /* Create time of file */
|
||||||
uint8_t xoa_archive;
|
uint8_t xoa_archive;
|
||||||
@ -46,12 +105,6 @@ typedef struct xoptattr {
|
|||||||
uint8_t xoa_av_modified;
|
uint8_t xoa_av_modified;
|
||||||
} xoptattr_t;
|
} 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 {
|
typedef struct xvattr {
|
||||||
vattr_t xva_vattr; /* Embedded vattr structure */
|
vattr_t xva_vattr; /* Embedded vattr structure */
|
||||||
uint32_t xva_magic; /* Magic Number */
|
uint32_t xva_magic; /* Magic Number */
|
||||||
@ -70,46 +123,28 @@ typedef struct vsecattr {
|
|||||||
void *vsa_dfaclentp; /* pointer to default ACL entries */
|
void *vsa_dfaclentp; /* pointer to default ACL entries */
|
||||||
size_t vsa_aclentsz; /* ACE size in bytes of vsa_aclentp */
|
size_t vsa_aclentsz; /* ACE size in bytes of vsa_aclentp */
|
||||||
} vsecattr_t;
|
} vsecattr_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
#define AT_TYPE 0x00001
|
extern int vn_open(const char *path, int seg, int flags, int mode,
|
||||||
#define AT_MODE 0x00002
|
vnode_t **vpp, int x1, void *x2);
|
||||||
// #define AT_UID 0x00004 /* Conflicts with linux/auxvec.h */
|
extern int vn_openat(const char *path, int seg, int flags, int mode,
|
||||||
// #define AT_GID 0x00008 /* Conflicts with linux/auxvec.h */
|
vnode_t **vpp, int x1, void *x2, vnode_t *vp, int fd);
|
||||||
#define AT_FSID 0x00010
|
extern int vn_rdwr(uio_rw_t uio, vnode_t *vp, void *addr, ssize_t len,
|
||||||
#define AT_NODEID 0x00020
|
offset_t off, int seg, int x1, rlim64_t x2,
|
||||||
#define AT_NLINK 0x00040
|
void *x3, ssize_t *residp);
|
||||||
#define AT_SIZE 0x00080
|
extern int vn_close(vnode_t *vp, int flags, int x1, int x2, int x3, int x4);
|
||||||
#define AT_ATIME 0x00100
|
extern int vn_remove(const char *path, int x1, int x2);
|
||||||
#define AT_MTIME 0x00200
|
extern int vn_rename(const char *path1, const char *path2, int x1);
|
||||||
#define AT_CTIME 0x00400
|
extern int vn_getattr(vnode_t *vp, vattr_t *vap, int flags, int x3, void *x4);
|
||||||
#define AT_RDEV 0x00800
|
extern int vn_fsync(vnode_t *vp, int flags, int x3, int x4);
|
||||||
#define AT_BLKSIZE 0x01000
|
|
||||||
#define AT_NBLOCKS 0x02000
|
|
||||||
#define AT_SEQ 0x08000
|
|
||||||
#define AT_XVATTR 0x10000
|
|
||||||
|
|
||||||
#define CRCREAT 0
|
#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
|
||||||
|
|
||||||
#define VOP_CLOSE(vp, f, c, o, cr, ct) 0
|
extern void *rootdir;
|
||||||
#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 /* SPL_VNODE_H */
|
#endif /* SPL_VNODE_H */
|
||||||
|
@ -1,21 +1,18 @@
|
|||||||
#include <sys/kobj.h>
|
#include <sys/kobj.h>
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
void *rootdir = NULL;
|
|
||||||
EXPORT_SYMBOL(rootdir);
|
|
||||||
|
|
||||||
struct _buf *
|
struct _buf *
|
||||||
kobj_open_file(const char *name)
|
kobj_open_file(const char *name)
|
||||||
{
|
{
|
||||||
struct _buf *file;
|
struct _buf *file;
|
||||||
struct file *fp;
|
vnode_t *vp;
|
||||||
|
int rc;
|
||||||
|
|
||||||
fp = filp_open(name, O_RDONLY, 0644);
|
if ((rc = vn_open(name, UIO_SYSSPACE, FREAD, 0644, &vp, 0, 0)))
|
||||||
if (IS_ERR(fp))
|
|
||||||
return ((_buf_t *)-1UL);
|
return ((_buf_t *)-1UL);
|
||||||
|
|
||||||
file = kmem_zalloc(sizeof(_buf_t), KM_SLEEP);
|
file = kmalloc(sizeof(_buf_t), GFP_KERNEL);
|
||||||
file->fp = fp;
|
file->vp = vp;
|
||||||
|
|
||||||
return file;
|
return file;
|
||||||
} /* kobj_open_file() */
|
} /* kobj_open_file() */
|
||||||
@ -24,52 +21,34 @@ EXPORT_SYMBOL(kobj_open_file);
|
|||||||
void
|
void
|
||||||
kobj_close_file(struct _buf *file)
|
kobj_close_file(struct _buf *file)
|
||||||
{
|
{
|
||||||
filp_close(file->fp, 0);
|
VOP_CLOSE(file->vp, 0, 0, 0, 0, 0);
|
||||||
kmem_free(file, sizeof(_buf_t));
|
VN_RELE(file->vp);
|
||||||
|
kfree(file);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
} /* kobj_close_file() */
|
} /* kobj_close_file() */
|
||||||
EXPORT_SYMBOL(kobj_close_file);
|
EXPORT_SYMBOL(kobj_close_file);
|
||||||
|
|
||||||
int
|
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;
|
return vn_rdwr(UIO_READ, file->vp, buf, size, off,
|
||||||
mm_segment_t saved_fs;
|
UIO_SYSSPACE, 0, RLIM64_INFINITY, 0, NULL);
|
||||||
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;
|
|
||||||
} /* kobj_read_file() */
|
} /* kobj_read_file() */
|
||||||
EXPORT_SYMBOL(kobj_read_file);
|
EXPORT_SYMBOL(kobj_read_file);
|
||||||
|
|
||||||
int
|
int
|
||||||
kobj_get_filesize(struct _buf *file, uint64_t *size)
|
kobj_get_filesize(struct _buf *file, uint64_t *size)
|
||||||
{
|
{
|
||||||
struct kstat stat;
|
vattr_t vap;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (!file || !file->fp || !size)
|
rc = VOP_GETATTR(file->vp, &vap, 0, 0, NULL);
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
rc = vfs_getattr(file->fp->f_vfsmnt, file->fp->f_dentry, &stat);
|
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
*size = stat.size;
|
*size = vap.va_size;
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
} /* kobj_get_filesize() */
|
} /* kobj_get_filesize() */
|
||||||
EXPORT_SYMBOL(kobj_get_filesize);
|
EXPORT_SYMBOL(kobj_get_filesize);
|
||||||
|
@ -1,168 +1,358 @@
|
|||||||
#include <sys/sysmacros.h>
|
#include <sys/sysmacros.h>
|
||||||
|
#include <sys/vnode.h>
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
/*
|
void *rootdir = NULL;
|
||||||
* XXX: currently borrrowed from libsolcompat until this
|
EXPORT_SYMBOL(rootdir);
|
||||||
* 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*/
|
static vtype_t
|
||||||
int
|
vn_get_sol_type(umode_t mode)
|
||||||
vn_open(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2, int x3)
|
|
||||||
{
|
{
|
||||||
int fd;
|
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(const char *path, int seg, int flags, int mode,
|
||||||
|
vnode_t **vpp, int x1, void *x2)
|
||||||
|
{
|
||||||
|
struct file *fp;
|
||||||
|
struct kstat stat;
|
||||||
|
int rc, saved_umask, flags_rw;
|
||||||
vnode_t *vp;
|
vnode_t *vp;
|
||||||
int old_umask;
|
|
||||||
char realpath[MAXPATHLEN];
|
|
||||||
struct stat64 st;
|
|
||||||
|
|
||||||
/*
|
BUG_ON(seg != UIO_SYSSPACE);
|
||||||
* If we're accessing a real disk from userland, we need to use
|
BUG_ON(!vpp);
|
||||||
* the character interface to avoid caching. This is particularly
|
*vpp = NULL;
|
||||||
* 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) && (flags & FWRITE))
|
||||||
if (!(flags & FCREAT) && S_ISBLK(st.st_mode)) {
|
flags |= FEXCL;
|
||||||
flags |= O_DIRECT;
|
|
||||||
if (flags & FWRITE)
|
flags_rw = flags & (FWRITE | FREAD);
|
||||||
flags |= O_EXCL;
|
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)
|
if (flags & FCREAT)
|
||||||
old_umask = umask(0);
|
saved_umask = xchg(¤t->fs->umask, 0);
|
||||||
|
|
||||||
/*
|
fp = filp_open(path, flags, mode);
|
||||||
* 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);
|
|
||||||
|
|
||||||
if (flags & FCREAT)
|
if (flags & FCREAT)
|
||||||
(void) umask(old_umask);
|
(void)xchg(¤t->fs->umask, saved_umask);
|
||||||
|
|
||||||
if (fd == -1)
|
if (IS_ERR(fp))
|
||||||
return (errno);
|
return PTR_ERR(fp);
|
||||||
|
|
||||||
if (fstat64(fd, &st) == -1) {
|
rc = vfs_getattr(fp->f_vfsmnt, fp->f_dentry, &stat);
|
||||||
close(fd);
|
if (rc) {
|
||||||
return (errno);
|
filp_close(fp, 0);
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
|
vp = kmalloc(sizeof(vnode_t), GFP_ATOMIC);
|
||||||
|
if (!vp) {
|
||||||
*vpp = vp = umem_zalloc(sizeof (vnode_t), UMEM_NOFAIL);
|
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);
|
|
||||||
|
|
||||||
return (0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*ARGSUSED*/
|
vp->v_type = vn_get_sol_type(stat.mode);
|
||||||
|
vp->v_fp = fp;
|
||||||
|
*vpp = vp;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
} /* vn_open() */
|
||||||
|
EXPORT_SYMBOL(vn_open);
|
||||||
|
|
||||||
int
|
int
|
||||||
vn_openat(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2,
|
vn_openat(const char *path, int seg, int flags, int mode,
|
||||||
int x3, vnode_t *startvp, int fd)
|
vnode_t **vpp, int x1, void *x2, vnode_t *vp, int fd)
|
||||||
{
|
{
|
||||||
char *realpath = umem_alloc(strlen(path) + 2, UMEM_NOFAIL);
|
char *realpath;
|
||||||
int ret;
|
int rc;
|
||||||
|
|
||||||
ASSERT(startvp == rootdir);
|
BUG_ON(vp != rootdir);
|
||||||
(void) sprintf(realpath, "/%s", path);
|
|
||||||
|
|
||||||
/* fd ignored for now, need if want to simulate nbmand support */
|
realpath = kmalloc(strlen(path) + 2, GFP_KERNEL);
|
||||||
ret = vn_open(realpath, x1, flags, mode, vpp, x2, x3);
|
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
|
int
|
||||||
vn_rdwr(int uio, vnode_t *vp, void *addr, ssize_t len, offset_t offset,
|
vn_rdwr(uio_rw_t uio, vnode_t *vp, void *addr, ssize_t len, offset_t off,
|
||||||
int x1, int x2, rlim64_t x3, void *x4, ssize_t *residp)
|
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;
|
||||||
|
|
||||||
if (uio == UIO_READ) {
|
BUG_ON(!(uio == UIO_WRITE || uio == UIO_READ));
|
||||||
iolen = pread64(vp->v_fd, addr, len, offset);
|
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 (residp) {
|
||||||
|
*residp = len - rc;
|
||||||
} else {
|
} else {
|
||||||
/*
|
if (rc != len)
|
||||||
* To simulate partial disk writes, we split writes into two
|
return -EIO;
|
||||||
* 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 (iolen < 0)
|
return 0;
|
||||||
return (errno);
|
} /* vn_rdwr() */
|
||||||
if (residp)
|
EXPORT_SYMBOL(vn_rdwr);
|
||||||
*residp = len - iolen;
|
|
||||||
else if (iolen != len)
|
|
||||||
return (EIO);
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
int
|
||||||
vn_close(vnode_t *vp)
|
vn_close(vnode_t *vp, int flags, int x1, int x2, int x3, int x4)
|
||||||
{
|
{
|
||||||
close(vp->v_fd);
|
int rc;
|
||||||
spa_strfree(vp->v_path);
|
|
||||||
umem_free(vp, sizeof (vnode_t));
|
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);
|
||||||
}
|
}
|
||||||
#endif
|
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);
|
||||||
|
|
||||||
|
int
|
||||||
|
vn_getattr(vnode_t *vp, vattr_t *vap, int flags, int x3, void *x4)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
@ -21,6 +21,7 @@ splat-objs += splat-condvar.o
|
|||||||
splat-objs += splat-thread.o
|
splat-objs += splat-thread.o
|
||||||
splat-objs += splat-rwlock.o
|
splat-objs += splat-rwlock.o
|
||||||
splat-objs += splat-time.o
|
splat-objs += splat-time.o
|
||||||
|
splat-objs += splat-vnode.o
|
||||||
splat-objs += splat-kobj.o
|
splat-objs += splat-kobj.o
|
||||||
|
|
||||||
splatmodule := splat.ko
|
splatmodule := splat.ko
|
||||||
|
@ -591,6 +591,7 @@ splat_init(void)
|
|||||||
SPLAT_SUBSYSTEM_INIT(thread);
|
SPLAT_SUBSYSTEM_INIT(thread);
|
||||||
SPLAT_SUBSYSTEM_INIT(rwlock);
|
SPLAT_SUBSYSTEM_INIT(rwlock);
|
||||||
SPLAT_SUBSYSTEM_INIT(time);
|
SPLAT_SUBSYSTEM_INIT(time);
|
||||||
|
SPLAT_SUBSYSTEM_INIT(vnode);
|
||||||
SPLAT_SUBSYSTEM_INIT(kobj);
|
SPLAT_SUBSYSTEM_INIT(kobj);
|
||||||
|
|
||||||
dev = MKDEV(SPLAT_MAJOR, 0);
|
dev = MKDEV(SPLAT_MAJOR, 0);
|
||||||
@ -654,6 +655,7 @@ splat_fini(void)
|
|||||||
unregister_chrdev_region(dev, SPLAT_MINORS);
|
unregister_chrdev_region(dev, SPLAT_MINORS);
|
||||||
|
|
||||||
SPLAT_SUBSYSTEM_FINI(kobj);
|
SPLAT_SUBSYSTEM_FINI(kobj);
|
||||||
|
SPLAT_SUBSYSTEM_FINI(vnode);
|
||||||
SPLAT_SUBSYSTEM_FINI(time);
|
SPLAT_SUBSYSTEM_FINI(time);
|
||||||
SPLAT_SUBSYSTEM_FINI(rwlock);
|
SPLAT_SUBSYSTEM_FINI(rwlock);
|
||||||
SPLAT_SUBSYSTEM_FINI(thread);
|
SPLAT_SUBSYSTEM_FINI(thread);
|
||||||
|
@ -170,6 +170,7 @@ splat_subsystem_t * splat_rwlock_init(void);
|
|||||||
splat_subsystem_t * splat_taskq_init(void);
|
splat_subsystem_t * splat_taskq_init(void);
|
||||||
splat_subsystem_t * splat_thread_init(void);
|
splat_subsystem_t * splat_thread_init(void);
|
||||||
splat_subsystem_t * splat_time_init(void);
|
splat_subsystem_t * splat_time_init(void);
|
||||||
|
splat_subsystem_t * splat_vnode_init(void);
|
||||||
splat_subsystem_t * splat_kobj_init(void);
|
splat_subsystem_t * splat_kobj_init(void);
|
||||||
|
|
||||||
void splat_condvar_fini(splat_subsystem_t *);
|
void splat_condvar_fini(splat_subsystem_t *);
|
||||||
@ -180,6 +181,7 @@ void splat_rwlock_fini(splat_subsystem_t *);
|
|||||||
void splat_taskq_fini(splat_subsystem_t *);
|
void splat_taskq_fini(splat_subsystem_t *);
|
||||||
void splat_thread_fini(splat_subsystem_t *);
|
void splat_thread_fini(splat_subsystem_t *);
|
||||||
void splat_time_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 *);
|
void splat_kobj_fini(splat_subsystem_t *);
|
||||||
|
|
||||||
int splat_condvar_id(void);
|
int splat_condvar_id(void);
|
||||||
@ -190,6 +192,7 @@ int splat_rwlock_id(void);
|
|||||||
int splat_taskq_id(void);
|
int splat_taskq_id(void);
|
||||||
int splat_thread_id(void);
|
int splat_thread_id(void);
|
||||||
int splat_time_id(void);
|
int splat_time_id(void);
|
||||||
|
int splat_vnode_id(void);
|
||||||
int splat_kobj_id(void);
|
int splat_kobj_id(void);
|
||||||
|
|
||||||
#endif /* _SPLAT_INTERNAL_H */
|
#endif /* _SPLAT_INTERNAL_H */
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
#include "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_NAME "kobj"
|
||||||
#define SPLAT_KOBJ_DESC "Kernel File Tests"
|
#define SPLAT_KOBJ_DESC "Kernel File Tests"
|
||||||
|
|
||||||
#define SPLAT_KOBJ_TEST1_ID 0x0901
|
#define SPLAT_KOBJ_TEST1_ID 0x0a01
|
||||||
#define SPLAT_KOBJ_TEST1_NAME "kobj1"
|
#define SPLAT_KOBJ_TEST1_NAME "open"
|
||||||
#define SPLAT_KOBJ_TEST1_DESC "File Open/Close Test"
|
#define SPLAT_KOBJ_TEST1_DESC "File Open/Close Test"
|
||||||
|
|
||||||
#define SPLAT_KOBJ_TEST2_ID 0x0902
|
#define SPLAT_KOBJ_TEST2_ID 0x0a02
|
||||||
#define SPLAT_KOBJ_TEST2_NAME "kobj2"
|
#define SPLAT_KOBJ_TEST2_NAME "size/read"
|
||||||
#define SPLAT_KOBJ_TEST2_DESC "File Size/Read Test"
|
#define SPLAT_KOBJ_TEST2_DESC "File Size/Read Test"
|
||||||
|
|
||||||
#define SPLAT_KOBJ_TEST_FILE "/etc/fstab"
|
#define SPLAT_KOBJ_TEST_FILE "/etc/fstab"
|
||||||
|
372
modules/splat/splat-vnode.c
Normal file
372
modules/splat/splat-vnode.c
Normal file
@ -0,0 +1,372 @@
|
|||||||
|
#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() */
|
@ -19,6 +19,12 @@ if [ -n "$V" ]; then
|
|||||||
verbose="-v"
|
verbose="-v"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ -n "$TESTS" ]; then
|
||||||
|
tests="$TESTS"
|
||||||
|
else
|
||||||
|
tests="-a"
|
||||||
|
fi
|
||||||
|
|
||||||
if [ $(id -u) != 0 ]; then
|
if [ $(id -u) != 0 ]; then
|
||||||
die "Must run as root"
|
die "Must run as root"
|
||||||
fi
|
fi
|
||||||
@ -37,8 +43,8 @@ echo "Loading ${spl_module}"
|
|||||||
echo "Loading ${splat_module}"
|
echo "Loading ${splat_module}"
|
||||||
/sbin/insmod ${splat_module} || die "Unable to load ${splat_module}"
|
/sbin/insmod ${splat_module} || die "Unable to load ${splat_module}"
|
||||||
|
|
||||||
sleep 3
|
while [ ! -c /dev/splatctl ]; do sleep 0.1; done
|
||||||
$splat_cmd -a $verbose
|
$splat_cmd $tests $verbose
|
||||||
|
|
||||||
echo "Unloading ${splat_module}"
|
echo "Unloading ${splat_module}"
|
||||||
/sbin/rmmod ${splat_module} || die "Failed to unload ${splat_module}"
|
/sbin/rmmod ${splat_module} || die "Failed to unload ${splat_module}"
|
||||||
|
Loading…
Reference in New Issue
Block a user