#endif
#include <linux/module.h>
-#include <linux/types.h>
+#include <sys/types.h>
/* XXX - Portions commented out because we really just want to have the type
* defined and the contents aren't nearly so important at the moment. */
--- /dev/null
+#ifndef _SPL_KIDMAP_H
+#define _SPL_KIDMAP_H
+
+#endif /* SPL_KIDMAP_H */
--- /dev/null
+#ifndef _SPL_KOBJ_H
+#define _SPL_KOBJ_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <sys/types.h>
+#include <sys/kmem.h>
+
+typedef struct _buf {
+ struct file *fp;
+} _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);
+extern int kobj_get_filesize(struct _buf *file, uint64_t *size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SPL_KOBJ_H */
struct task_struct *rw_owner; /* holder of the write lock */
} krwlock_t;
+#ifdef CONFIG_RWSEM_GENERIC_SPINLOCK
+struct rwsem_waiter {
+ struct list_head list;
+ struct task_struct *task;
+ unsigned int flags;
+#define RWSEM_WAITING_FOR_READ 0x00000001
+#define RWSEM_WAITING_FOR_WRITE 0x00000002
+};
+
+/*
+ * wake a single writer
+ */
+static inline struct rw_semaphore *
+__rwsem_wake_one_writer_locked(struct rw_semaphore *sem)
+{
+ struct rwsem_waiter *waiter;
+ struct task_struct *tsk;
+
+ sem->activity = -1;
+
+ waiter = list_entry(sem->wait_list.next, struct rwsem_waiter, list);
+ list_del(&waiter->list);
+
+ tsk = waiter->task;
+ smp_mb();
+ waiter->task = NULL;
+ wake_up_process(tsk);
+ put_task_struct(tsk);
+ return sem;
+}
+
+/*
+ * release a read lock on the semaphore
+ */
+static void fastcall
+__up_read_locked(struct rw_semaphore *sem)
+{
+ if (--sem->activity == 0 && !list_empty(&sem->wait_list))
+ sem = __rwsem_wake_one_writer_locked(sem);
+}
+
+/*
+ * trylock for writing -- returns 1 if successful, 0 if contention
+ */
+static int fastcall
+__down_write_trylock_locked(struct rw_semaphore *sem)
+{
+ int ret = 0;
+
+ if (sem->activity == 0 && list_empty(&sem->wait_list)) {
+ /* granted */
+ sem->activity = -1;
+ ret = 1;
+ }
+
+ return ret;
+}
+#endif
+
extern int __rw_read_held(krwlock_t *rwlp);
extern int __rw_write_held(krwlock_t *rwlp);
extern int __rw_lock_held(krwlock_t *rwlp);
static __inline__ int
rw_tryupgrade(krwlock_t *rwlp)
{
- int result;
+ int result = 0;
BUG_ON(rwlp->rw_magic != RW_MAGIC);
spin_lock(&rwlp->rw_sem.wait_lock);
return 0;
}
+#ifdef CONFIG_RWSEM_GENERIC_SPINLOCK
+ /* Here it should be safe to drop the
+ * read lock and reacquire it for writing since
+ * we know there are no waiters */
+ __up_read_locked(&rwlp->rw_sem);
+
+ /* returns 1 if success, 0 if contention */
+ result = __down_write_trylock_locked(&rwlp->rw_sem);
+#else
/* Here it should be safe to drop the
* read lock and reacquire it for writing since
* we know there are no waiters */
/* returns 1 if success, 0 if contention */
result = down_write_trylock(&rwlp->rw_sem);
+#endif
/* Check if upgrade failed. Should not ever happen
* if we got to this point */
--- /dev/null
+#ifndef _SPL_SID_H
+#define _SPL_SID_H
+
+#endif /* SPL_SID_H */
#define makedevice(maj,min) makedev(maj,min)
#define zone_dataset_visible(x, y) (1)
#define INGLOBALZONE(z) (1)
-#define utsname system_utsname
/* XXX - Borrowed from zfs project libsolcompat/include/sys/sysmacros.h */
/* common macros */
--- /dev/null
+#ifndef _SPL_UTSNAME_H
+#define _SPL_UTSNAME_H
+
+#include <linux/utsname.h>
+
+#define utsname system_utsname
+
+#endif /* SPL_UTSNAME_H */
#ifndef _SPL_ZFS_H
#define _SPL_ZFS_H
+typedef struct vfs_s {
+ int foo;
+} vfs_t;
+
#endif /* SPL_ZFS_H */
spl-objs += spl-vnode.o
spl-objs += spl-err.o
spl-objs += spl-time.o
+spl-objs += spl-kobj.o
spl-objs += spl-generic.o
splmodule := spl.ko
--- /dev/null
+#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;
+
+ fp = filp_open(name, O_RDONLY, 0644);
+ if (IS_ERR(fp))
+ return ((_buf_t *)-1UL);
+
+ file = kmem_zalloc(sizeof(_buf_t), KM_SLEEP);
+ file->fp = fp;
+
+ return file;
+} /* kobj_open_file() */
+EXPORT_SYMBOL(kobj_open_file);
+
+void
+kobj_close_file(struct _buf *file)
+{
+ filp_close(file->fp, 0);
+ kmem_free(file, sizeof(_buf_t));
+
+ return;
+} /* kobj_close_file() */
+EXPORT_SYMBOL(kobj_close_file);
+
+int
+kobj_read_file(struct _buf *file, char *buf, unsigned size, unsigned 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;
+} /* kobj_read_file() */
+EXPORT_SYMBOL(kobj_read_file);
+
+int
+kobj_get_filesize(struct _buf *file, uint64_t *size)
+{
+ struct kstat stat;
+ int rc;
+
+ if (!file || !file->fp || !size)
+ return -EINVAL;
+
+ rc = vfs_getattr(file->fp->f_vfsmnt, file->fp->f_dentry, &stat);
+ if (rc)
+ return rc;
+
+ *size = stat.size;
+ return rc;
+} /* kobj_get_filesize() */
+EXPORT_SYMBOL(kobj_get_filesize);
splat-objs += splat-thread.o
splat-objs += splat-rwlock.o
splat-objs += splat-time.o
+splat-objs += splat-kobj.o
splatmodule := splat.ko
splatmoduledir := @kmoduledir@/kernel/lib/
SPLAT_SUBSYSTEM_INIT(thread);
SPLAT_SUBSYSTEM_INIT(rwlock);
SPLAT_SUBSYSTEM_INIT(time);
+ SPLAT_SUBSYSTEM_INIT(kobj);
dev = MKDEV(SPLAT_MAJOR, 0);
if ((rc = register_chrdev_region(dev, SPLAT_MINORS, "splatctl")))
cdev_del(&splat_cdev);
unregister_chrdev_region(dev, SPLAT_MINORS);
+ SPLAT_SUBSYSTEM_FINI(kobj);
SPLAT_SUBSYSTEM_FINI(time);
SPLAT_SUBSYSTEM_FINI(rwlock);
SPLAT_SUBSYSTEM_FINI(thread);
#include <sys/time.h>
#include <sys/timer.h>
#include <sys/types.h>
+#include <sys/kobj.h>
#include "splat-ctl.h"
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_kobj_init(void);
void splat_condvar_fini(splat_subsystem_t *);
void splat_kmem_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_kobj_fini(splat_subsystem_t *);
int splat_condvar_id(void);
int splat_kmem_id(void);
int splat_taskq_id(void);
int splat_thread_id(void);
int splat_time_id(void);
+int splat_kobj_id(void);
#endif /* _SPLAT_INTERNAL_H */
--- /dev/null
+#include "splat-internal.h"
+
+#define SPLAT_SUBSYSTEM_KOBJ 0x0900
+#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_DESC "File Open/Close Test"
+
+#define SPLAT_KOBJ_TEST2_ID 0x0902
+#define SPLAT_KOBJ_TEST2_NAME "kobj2"
+#define SPLAT_KOBJ_TEST2_DESC "File Size/Read Test"
+
+#define SPLAT_KOBJ_TEST_FILE "/etc/fstab"
+
+static int
+splat_kobj_test1(struct file *file, void *arg)
+{
+ struct _buf *f;
+
+ f = kobj_open_file(SPLAT_KOBJ_TEST_FILE);
+ if (f == (struct _buf *)-1) {
+ splat_vprint(file, SPLAT_KOBJ_TEST1_NAME, "Failed to open "
+ "test file: %s\n", SPLAT_KOBJ_TEST_FILE);
+ return -ENOENT;
+ }
+
+ kobj_close_file(f);
+ splat_vprint(file, SPLAT_KOBJ_TEST1_NAME, "Successfully opened and "
+ "closed test file: %s\n", SPLAT_KOBJ_TEST_FILE);
+
+ return 0;
+} /* splat_kobj_test1() */
+
+static int
+splat_kobj_test2(struct file *file, void *arg)
+{
+ struct _buf *f;
+ char *buf;
+ uint64_t size;
+ int rc;
+
+ f = kobj_open_file(SPLAT_KOBJ_TEST_FILE);
+ if (f == (struct _buf *)-1) {
+ splat_vprint(file, SPLAT_KOBJ_TEST2_NAME, "Failed to open "
+ "test file: %s\n", SPLAT_KOBJ_TEST_FILE);
+ return -ENOENT;
+ }
+
+ rc = kobj_get_filesize(f, &size);
+ if (rc) {
+ splat_vprint(file, SPLAT_KOBJ_TEST2_NAME, "Failed stat of "
+ "test file: %s (%d)\n", SPLAT_KOBJ_TEST_FILE, rc);
+ goto out;
+ }
+
+ buf = kmalloc(size, GFP_KERNEL);
+ if (!buf) {
+ rc = -ENOMEM;
+ splat_vprint(file, SPLAT_KOBJ_TEST2_NAME, "Failed to alloc "
+ "%lld bytes for tmp buffer (%d)\n", size, rc);
+ goto out;
+ }
+
+ rc = kobj_read_file(f, buf, size, 0);
+ if (rc < 0) {
+ splat_vprint(file, SPLAT_KOBJ_TEST2_NAME, "Failed read of "
+ "test file: %s (%d)\n", SPLAT_KOBJ_TEST_FILE, rc);
+ goto out2;
+ }
+
+ /* Validate we read as many bytes as expected based on the stat. This
+ * isn't a perfect test since we didn't create the file however it is
+ * pretty unlikely there are garbage characters in your /etc/fstab */
+ if (size != (uint64_t)strlen(buf)) {
+ rc = EFBIG;
+ splat_vprint(file, SPLAT_KOBJ_TEST2_NAME, "Stat'ed size "
+ "(%lld) does not match number of bytes read "
+ "(%lld)\n", size, (uint64_t)strlen(buf));
+ goto out2;
+ }
+
+ rc = 0;
+ splat_vprint(file, SPLAT_KOBJ_TEST2_NAME, "\n%s\n", buf);
+ splat_vprint(file, SPLAT_KOBJ_TEST2_NAME, "Successfully stat'ed "
+ "and read expected number of bytes (%lld) from test "
+ "file: %s\n", size, SPLAT_KOBJ_TEST_FILE);
+out2:
+ kfree(buf);
+out:
+ kobj_close_file(f);
+
+ return rc;
+} /* splat_kobj_test2() */
+
+splat_subsystem_t *
+splat_kobj_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_KOBJ_NAME, SPLAT_NAME_SIZE);
+ strncpy(sub->desc.desc, SPLAT_KOBJ_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_KOBJ;
+
+ SPLAT_TEST_INIT(sub, SPLAT_KOBJ_TEST1_NAME, SPLAT_KOBJ_TEST1_DESC,
+ SPLAT_KOBJ_TEST1_ID, splat_kobj_test1);
+ SPLAT_TEST_INIT(sub, SPLAT_KOBJ_TEST2_NAME, SPLAT_KOBJ_TEST2_DESC,
+ SPLAT_KOBJ_TEST2_ID, splat_kobj_test2);
+
+ return sub;
+} /* splat_kobj_init() */
+
+void
+splat_kobj_fini(splat_subsystem_t *sub)
+{
+ ASSERT(sub);
+
+ SPLAT_TEST_FINI(sub, SPLAT_KOBJ_TEST2_ID);
+ SPLAT_TEST_FINI(sub, SPLAT_KOBJ_TEST1_ID);
+
+ kfree(sub);
+} /* splat_kobj_fini() */
+
+int
+splat_kobj_id(void)
+{
+ return SPLAT_SUBSYSTEM_KOBJ;
+} /* splat_kobj_id() */
spl_module=../modules/spl/spl.ko
splat_module=../modules/splat/splat.ko
splat_cmd=../cmd/splat
+verbose=
die() {
echo "${prog}: $1" >&2
echo "${prog}: $1" >&2
}
+if [ -n "$V" ]; then
+ verbose="-v"
+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 5
-$splat_cmd -a
+sleep 3
+$splat_cmd -a $verbose
echo "Unloading ${splat_module}"
/sbin/rmmod ${splat_module} || die "Failed to unload ${splat_module}"