mirror of
https://git.proxmox.com/git/mirror_zfs
synced 2025-08-06 09:22:33 +00:00

git-svn-id: https://outreach.scidac.gov/svn/spl/trunk@50 7e1ea52c-4ff2-0310-8f11-9dd32ca42a1c
170 lines
3.0 KiB
C
170 lines
3.0 KiB
C
#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() */
|