#ifndef _SPL_FILE_H
#define _SPL_FILE_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <linux/module.h>
+#include <linux/file.h>
+#include <sys/kmem.h>
+#include <sys/mutex.h>
+#include <sys/vnode.h>
+
+typedef struct spl_file {
+ int f_fd; /* linux fd for lookup */
+ struct file *f_file; /* linux file struct */
+ atomic_t f_ref; /* ref count */
+ kmutex_t f_lock; /* struct lock */
+ loff_t f_offset; /* offset */
+ vnode_t *f_vnode; /* vnode */
+ struct list_head f_list; /* list of referenced file_t's */
+} file_t;
+
+extern file_t *getf(int fd);
+extern void releasef(int fd);
+
+int file_init(void);
+void file_fini(void);
+
+#ifdef __cplusplus
+}
+#endif
+
#endif /* SPL_FILE_H */
void
extern __kmem_reap(void);
+int kmem_init(void);
+void kmem_fini(void);
+
#define kmem_cache_create(name,size,align,ctor,dtor,rclm,priv,vmp,flags) \
__kmem_cache_create(name,size,align,ctor,dtor,rclm,priv,vmp,flags)
#define kmem_cache_destroy(cache) __kmem_cache_destroy(cache)
typedef ushort_t o_mode_t;
typedef uint_t major_t;
typedef uint_t minor_t;
+typedef uint_t ldi_ident_t;
+typedef dev_t dev_info_t;
#endif /* _SPL_TYPES_H */
#ifndef _SPL_VNODE_H
#define _SPL_VNODE_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#include <linux/module.h>
#include <linux/syscalls.h>
#include <linux/fcntl.h>
#define FRSYNC O_RSYNC
#define FEXCL O_EXCL
#define FDIRECT O_DIRECT
+#define FAPPEND O_APPEND
#define FNODSYNC 0x10000 /* fsync pseudo flag */
#define FNOFOLLOW 0x20000 /* don't follow symlinks */
extern void *rootdir;
+#ifdef __cplusplus
+}
+#endif
+
#endif /* SPL_VNODE_H */
spl-objs += spl-err.o
spl-objs += spl-time.o
spl-objs += spl-kobj.o
+spl-objs += spl-file.o
spl-objs += spl-generic.o
splmodule := spl.ko
--- /dev/null
+#include <sys/sysmacros.h>
+#include <sys/file.h>
+#include "config.h"
+
+/* File interface */
+
+static spinlock_t file_lock = SPIN_LOCK_UNLOCKED;
+static LIST_HEAD(file_list);
+static kmem_cache_t *file_cache;
+
+/* Function must be called while holding the file_lock */
+static file_t *
+file_find(int fd)
+{
+ file_t *fp;
+
+ BUG_ON(!spin_is_locked(&file_lock));
+
+ list_for_each_entry(fp, &file_list, f_list) {
+ if (fd == fp->f_fd) {
+ BUG_ON(atomic_read(&fp->f_ref) == 0);
+ return fp;
+ }
+ }
+
+ return NULL;
+} /* file_find() */
+
+file_t *
+getf(int fd)
+{
+ file_t *fp;
+
+ /* Already open just take an extra reference */
+ spin_lock(&file_lock);
+
+ fp = file_find(fd);
+ if (fp) {
+ atomic_inc(&fp->f_ref);
+ spin_unlock(&file_lock);
+ return fp;
+ }
+
+ spin_unlock(&file_lock);
+
+ /* File was not yet opened via the SPL layer create needed bits */
+ fp = kmem_cache_alloc(file_cache, 0);
+ if (fp == NULL)
+ goto out;
+
+ mutex_enter(&fp->f_lock);
+
+ fp->f_vnode = vn_alloc(KM_SLEEP);
+ if (fp->f_vnode == NULL)
+ goto out_mutex;
+
+ /* XXX: Setup needed vnode stop, open file etc */
+
+ fp->f_file = fget(fd);
+ if (fp->f_file == NULL)
+ goto out_vnode;
+
+ fp->f_fd = fd;
+ atomic_inc(&fp->f_ref);
+
+ spin_lock(&file_lock);
+ list_add(&fp->f_list, &file_list);
+ spin_unlock(&file_lock);
+
+ mutex_exit(&fp->f_lock);
+ return fp;
+
+out_vnode:
+ vn_free(fp->f_vnode);
+out_mutex:
+ mutex_exit(&fp->f_lock);
+ kmem_cache_free(file_cache, fp);
+out:
+ return NULL;
+} /* getf() */
+EXPORT_SYMBOL(getf);
+
+static void releasef_locked(file_t *fp)
+{
+ BUG_ON(fp->f_file == NULL);
+ BUG_ON(fp->f_vnode == NULL);
+
+ /* Unlinked from list, no refs, safe to free outside mutex */
+ fput(fp->f_file);
+ vn_free(fp->f_vnode);
+
+ kmem_cache_free(file_cache, fp);
+}
+
+void
+releasef(int fd)
+{
+ file_t *fp;
+
+ spin_lock(&file_lock);
+
+ fp = file_find(fd);
+ if (fp) {
+ atomic_dec(&fp->f_ref);
+
+ if (atomic_read(&fp->f_ref) > 0) {
+ spin_unlock(&file_lock);
+ return;
+ }
+
+ list_del(&fp->f_list);
+ spin_unlock(&file_lock);
+ releasef_locked(fp);
+ }
+
+ return;
+} /* releasef() */
+EXPORT_SYMBOL(releasef);
+
+static int
+file_cache_constructor(void *buf, void *cdrarg, int kmflags)
+{
+ file_t *fp = buf;
+
+ atomic_set(&fp->f_ref, 0);
+ mutex_init(&fp->f_lock, NULL, MUTEX_DEFAULT, NULL);
+
+ return (0);
+} /* file_cache_constructor() */
+
+static void
+file_cache_destructor(void *buf, void *cdrarg)
+{
+ file_t *fp = buf;
+
+ mutex_destroy(&fp->f_lock);
+} /* file_cache_destructor() */
+
+int
+file_init(void)
+{
+ file_cache = kmem_cache_create("spl_file_cache", sizeof(file_t), 64,
+ file_cache_constructor,
+ file_cache_destructor,
+ NULL, NULL, NULL, 0);
+ return 0;
+} /* file_init() */
+
+void file_fini(void)
+{
+ file_t *fp, *next_fp;
+ int leaked = 0;
+
+ spin_lock(&file_lock);
+
+ list_for_each_entry_safe(fp, next_fp, &file_list, f_list) {
+ list_del(&fp->f_list);
+ releasef_locked(fp);
+ leaked++;
+ }
+
+ kmem_cache_destroy(file_cache);
+ file_cache = NULL;
+ spin_unlock(&file_lock);
+
+ if (leaked > 0)
+ printk("Warning: %d files leaked\n", leaked);
+
+} /* file_fini() */
#include <sys/sysmacros.h>
#include <sys/vmsystm.h>
#include <sys/vnode.h>
+#include <sys/file.h>
#include <sys/kmem.h>
#include "config.h"
{
int rc;
- rc = vn_init();
- if (rc)
+ if ((rc = vn_init()))
+ return rc;
+
+ if ((rc = file_init()))
+ return rc;
+
+ if ((rc = kmem_init()))
return rc;
strcpy(hw_serial, "007f0100"); /* loopback */
printk(KERN_INFO "spl: Loaded Solaris Porting Layer v%s\n", VERSION);
-#ifdef DEBUG_KMEM
- atomic64_set(&kmem_alloc_used, 0);
- atomic64_set(&vmem_alloc_used, 0);
-#endif
-
return 0;
}
static void spl_fini(void)
{
+ kmem_fini();
+ file_fini();
vn_fini();
-#ifdef DEBUG_KMEM
- if (atomic64_read(&kmem_alloc_used) != 0)
- printk("Warning: kmem leaked %ld/%ld bytes\n",
- atomic_read(&kmem_alloc_used), kmem_alloc_max);
-
- if (atomic64_read(&vmem_alloc_used) != 0)
- printk("Warning: vmem leaked %ld/%ld bytes\n",
- atomic_read(&vmem_alloc_used), vmem_alloc_max);
-#endif
-
return;
}
kmem_cache_generic_shrinker(KMC_REAP_CHUNK, GFP_KERNEL);
}
EXPORT_SYMBOL(__kmem_reap);
+
+int
+kmem_init(void)
+{
+#ifdef DEBUG_KMEM
+ atomic64_set(&kmem_alloc_used, 0);
+ atomic64_set(&vmem_alloc_used, 0);
+#endif
+ return 0;
+}
+
+void
+kmem_fini(void)
+{
+#ifdef DEBUG_KMEM
+ if (atomic64_read(&kmem_alloc_used) != 0)
+ printk("Warning: kmem leaked %ld/%ld bytes\n",
+ atomic_read(&kmem_alloc_used), kmem_alloc_max);
+
+ if (atomic64_read(&vmem_alloc_used) != 0)
+ printk("Warning: vmem leaked %ld/%ld bytes\n",
+ atomic_read(&vmem_alloc_used), vmem_alloc_max);
+#endif
+}
vnode_t *vp;
vp = kmem_cache_alloc(vn_cache, flag);
-
if (vp != NULL) {
vp->v_fp = NULL;
vp->v_type = 0;
int
vn_init(void)
{
- vn_cache = kmem_cache_create("vn_cache", sizeof(struct vnode), 64,
- vn_cache_constructor, vn_cache_destructor,
+ vn_cache = kmem_cache_create("spl_vn_cache", sizeof(struct vnode), 64,
+ vn_cache_constructor,
+ vn_cache_destructor,
NULL, NULL, NULL, 0);
return 0;
} /* vn_init() */
splat-objs += splat-time.o
splat-objs += splat-vnode.o
splat-objs += splat-kobj.o
+splat-objs += splat-file.o
splatmodule := splat.ko
splatmoduledir := @kmoduledir@/kernel/lib/
SPLAT_SUBSYSTEM_INIT(time);
SPLAT_SUBSYSTEM_INIT(vnode);
SPLAT_SUBSYSTEM_INIT(kobj);
+ SPLAT_SUBSYSTEM_INIT(file);
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(file);
SPLAT_SUBSYSTEM_FINI(kobj);
SPLAT_SUBSYSTEM_FINI(vnode);
SPLAT_SUBSYSTEM_FINI(time);
--- /dev/null
+#include "splat-internal.h"
+
+#define SPLAT_SUBSYSTEM_FILE 0x0b00
+#define SPLAT_FILE_NAME "file"
+#define SPLAT_FILE_DESC "Kernel File Tests"
+
+#define SPLAT_FILE_TEST1_ID 0x0b01
+#define SPLAT_FILE_TEST1_NAME "getf"
+#define SPLAT_FILE_TEST1_DESC "File getf/releasef Test"
+
+static int
+splat_file_test1(struct file *file, void *arg)
+{
+ splat_vprint(file, SPLAT_FILE_TEST1_NAME, "WRITE A TEST, %d\n", 0);
+
+ return 0;
+} /* splat_file_test1() */
+
+
+splat_subsystem_t *
+splat_file_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_FILE_NAME, SPLAT_NAME_SIZE);
+ strncpy(sub->desc.desc, SPLAT_FILE_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_FILE;
+
+ SPLAT_TEST_INIT(sub, SPLAT_FILE_TEST1_NAME, SPLAT_FILE_TEST1_DESC,
+ SPLAT_FILE_TEST1_ID, splat_file_test1);
+
+ return sub;
+} /* splat_file_init() */
+
+void
+splat_file_fini(splat_subsystem_t *sub)
+{
+ ASSERT(sub);
+
+ SPLAT_TEST_FINI(sub, SPLAT_FILE_TEST1_ID);
+
+ kfree(sub);
+} /* splat_file_fini() */
+
+int
+splat_file_id(void)
+{
+ return SPLAT_SUBSYSTEM_FILE;
+} /* splat_file_id() */
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_file_init(void);
void splat_condvar_fini(splat_subsystem_t *);
void splat_kmem_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_file_fini(splat_subsystem_t *);
int splat_condvar_id(void);
int splat_kmem_id(void);
int splat_time_id(void);
int splat_vnode_id(void);
int splat_kobj_id(void);
+int splat_file_id(void);
#endif /* _SPLAT_INTERNAL_H */
#define SPLAT_SUBSYSTEM_KOBJ 0x0a00
#define SPLAT_KOBJ_NAME "kobj"
-#define SPLAT_KOBJ_DESC "Kernel File Tests"
+#define SPLAT_KOBJ_DESC "Kernel Kobj Tests"
#define SPLAT_KOBJ_TEST1_ID 0x0a01
#define SPLAT_KOBJ_TEST1_NAME "open"
-#define SPLAT_KOBJ_TEST1_DESC "File Open/Close Test"
+#define SPLAT_KOBJ_TEST1_DESC "Kobj Open/Close Test"
#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_TEST2_DESC "Kobj Size/Read Test"
#define SPLAT_KOBJ_TEST_FILE "/etc/fstab"