mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-22 10:37:35 +03:00
Initial pass at a file API getf/releasef hooks
git-svn-id: https://outreach.scidac.gov/svn/spl/trunk@50 7e1ea52c-4ff2-0310-8f11-9dd32ca42a1c
This commit is contained in:
@@ -17,6 +17,7 @@ spl-objs += spl-vnode.o
|
||||
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
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
#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() */
|
||||
+10
-17
@@ -1,6 +1,7 @@
|
||||
#include <sys/sysmacros.h>
|
||||
#include <sys/vmsystm.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/kmem.h>
|
||||
#include "config.h"
|
||||
|
||||
@@ -60,35 +61,27 @@ static int __init spl_init(void)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -272,3 +272,27 @@ __kmem_reap(void) {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -43,7 +43,6 @@ vn_alloc(int flag)
|
||||
vnode_t *vp;
|
||||
|
||||
vp = kmem_cache_alloc(vn_cache, flag);
|
||||
|
||||
if (vp != NULL) {
|
||||
vp->v_fp = NULL;
|
||||
vp->v_type = 0;
|
||||
@@ -411,8 +410,9 @@ vn_cache_destructor(void *buf, void *cdrarg)
|
||||
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() */
|
||||
|
||||
@@ -23,6 +23,7 @@ splat-objs += splat-rwlock.o
|
||||
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/
|
||||
|
||||
@@ -593,6 +593,7 @@ splat_init(void)
|
||||
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")))
|
||||
@@ -654,6 +655,7 @@ splat_fini(void)
|
||||
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);
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
#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() */
|
||||
@@ -172,6 +172,7 @@ 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);
|
||||
splat_subsystem_t * splat_file_init(void);
|
||||
|
||||
void splat_condvar_fini(splat_subsystem_t *);
|
||||
void splat_kmem_fini(splat_subsystem_t *);
|
||||
@@ -183,6 +184,7 @@ 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 *);
|
||||
void splat_file_fini(splat_subsystem_t *);
|
||||
|
||||
int splat_condvar_id(void);
|
||||
int splat_kmem_id(void);
|
||||
@@ -194,5 +196,6 @@ int splat_thread_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 */
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
|
||||
#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"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user