diff --git a/include/sys/file.h b/include/sys/file.h deleted file mode 100644 index 8b135c4b1..000000000 --- a/include/sys/file.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef _SPL_FILE_H -#define _SPL_FILE_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include -#include -#include - -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 */ diff --git a/include/sys/kmem.h b/include/sys/kmem.h index 39c547185..46322105d 100644 --- a/include/sys/kmem.h +++ b/include/sys/kmem.h @@ -198,7 +198,7 @@ __kmem_cache_create(char *name, size_t size, size_t align, kmem_reclaim_t reclaim, void *priv, void *vmp, int flags); -void +int extern __kmem_cache_destroy(kmem_cache_t *cache); void diff --git a/include/sys/vnode.h b/include/sys/vnode.h index 74a09b9b6..1b9c3b671 100644 --- a/include/sys/vnode.h +++ b/include/sys/vnode.h @@ -12,6 +12,7 @@ extern "C" { #include #include #include +#include #include #include #include @@ -133,7 +134,7 @@ typedef struct vsecattr { } vsecattr_t; typedef struct vnode { - struct file *v_fp; + struct file *v_file; kmutex_t v_lock; /* protects vnode fields */ uint_t v_flag; /* vnode flags (see below) */ uint_t v_count; /* reference count */ @@ -144,6 +145,16 @@ typedef struct vnode { dev_t v_rdev; /* device (VCHR, VBLK) */ } vnode_t; +typedef struct vn_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 vnode_t *vn_alloc(int flag); void vn_free(vnode_t *vp); extern int vn_open(const char *path, uio_seg_t seg, int flags, int mode, @@ -158,6 +169,8 @@ extern int vn_remove(const char *path, uio_seg_t seg, int flags); extern int vn_rename(const char *path1, const char *path2, int x1); extern int vn_getattr(vnode_t *vp, vattr_t *vap, int flags, void *x3, void *x4); extern int vn_fsync(vnode_t *vp, int flags, void *x3, void *x4); +extern file_t *vn_getf(int fd); +extern void vn_releasef(int fd); int vn_init(void); void vn_fini(void); @@ -180,6 +193,8 @@ vn_putpage(vnode_t *vp, offset_t off, ssize_t size, #define VOP_FSYNC vn_fsync #define VOP_PUTPAGE vn_putpage #define vn_is_readonly(vp) 0 +#define getf vn_getf +#define releasef vn_releasef extern void *rootdir; diff --git a/modules/spl/Makefile.in b/modules/spl/Makefile.in index 7508a3ebf..1005d100b 100644 --- a/modules/spl/Makefile.in +++ b/modules/spl/Makefile.in @@ -17,7 +17,6 @@ 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 diff --git a/modules/spl/spl-file.c b/modules/spl/spl-file.c deleted file mode 100644 index bce421432..000000000 --- a/modules/spl/spl-file.c +++ /dev/null @@ -1,169 +0,0 @@ -#include -#include -#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() */ diff --git a/modules/spl/spl-generic.c b/modules/spl/spl-generic.c index ee107d045..2773ff689 100644 --- a/modules/spl/spl-generic.c +++ b/modules/spl/spl-generic.c @@ -1,7 +1,6 @@ #include #include #include -#include #include #include "config.h" @@ -61,15 +60,12 @@ static int __init spl_init(void) { int rc; - if ((rc = vn_init())) - return rc; - - if ((rc = file_init())) - return rc; - if ((rc = kmem_init())) return rc; + if ((rc = vn_init())) + return rc; + strcpy(hw_serial, "007f0100"); /* loopback */ printk(KERN_INFO "spl: Loaded Solaris Porting Layer v%s\n", VERSION); @@ -78,9 +74,8 @@ static int __init spl_init(void) static void spl_fini(void) { - kmem_fini(); - file_fini(); vn_fini(); + kmem_fini(); return; } diff --git a/modules/spl/spl-kmem.c b/modules/spl/spl-kmem.c index 50eeec132..a1f3b54e2 100644 --- a/modules/spl/spl-kmem.c +++ b/modules/spl/spl-kmem.c @@ -238,21 +238,23 @@ __kmem_cache_create(char *name, size_t size, size_t align, } EXPORT_SYMBOL(__kmem_cache_create); -/* Return codes discarded because Solaris implementation has void return */ -void +/* Return code provided despite Solaris's void return. There should be no + * harm here since the Solaris versions will ignore it anyway. */ +int __kmem_cache_destroy(kmem_cache_t *cache) { kmem_cache_cb_t *kcc; char *name; + int rc; spin_lock(&kmem_cache_cb_lock); kcc = kmem_cache_find_cache_cb(cache); spin_unlock(&kmem_cache_cb_lock); if (kcc == NULL) - return; + return -EINVAL; name = (char *)kmem_cache_name(cache); - kmem_cache_destroy(cache); + rc = kmem_cache_destroy(cache); kmem_cache_remove_cache_cb(kcc); kfree(name); @@ -262,6 +264,7 @@ __kmem_cache_destroy(kmem_cache_t *cache) remove_shrinker(kmem_cache_shrinker); spin_unlock(&kmem_cache_cb_lock); + return rc; } EXPORT_SYMBOL(__kmem_cache_destroy); diff --git a/modules/spl/spl-vnode.c b/modules/spl/spl-vnode.c index 65cde885d..4ed59d32e 100644 --- a/modules/spl/spl-vnode.c +++ b/modules/spl/spl-vnode.c @@ -5,7 +5,11 @@ void *rootdir = NULL; EXPORT_SYMBOL(rootdir); -kmem_cache_t *vn_cache; +static kmem_cache_t *vn_cache; +static kmem_cache_t *vn_file_cache; + +static spinlock_t vn_file_lock = SPIN_LOCK_UNLOCKED; +static LIST_HEAD(vn_file_list); static vtype_t vn_get_sol_type(umode_t mode) @@ -44,7 +48,7 @@ vn_alloc(int flag) vp = kmem_cache_alloc(vn_cache, flag); if (vp != NULL) { - vp->v_fp = NULL; + vp->v_file = NULL; vp->v_type = 0; } @@ -106,9 +110,11 @@ vn_open(const char *path, uio_seg_t seg, int flags, int mode, return -ENOMEM; } + mutex_enter(&vp->v_lock); vp->v_type = vn_get_sol_type(stat.mode); - vp->v_fp = fp; + vp->v_file = fp; *vpp = vp; + mutex_exit(&vp->v_lock); return 0; } /* vn_open() */ @@ -147,13 +153,13 @@ vn_rdwr(uio_rw_t uio, vnode_t *vp, void *addr, ssize_t len, offset_t off, BUG_ON(!(uio == UIO_WRITE || uio == UIO_READ)); BUG_ON(!vp); - BUG_ON(!vp->v_fp); + BUG_ON(!vp->v_file); BUG_ON(seg != UIO_SYSSPACE); BUG_ON(x1 != 0); BUG_ON(x2 != RLIM64_INFINITY); offset = off; - fp = vp->v_fp; + fp = vp->v_file; /* Writable user data segment must be briefly increased for this * process so we can use the user space read call paths to write @@ -188,9 +194,9 @@ vn_close(vnode_t *vp, int flags, int x1, int x2, void *x3, void *x4) int rc; BUG_ON(!vp); - BUG_ON(!vp->v_fp); + BUG_ON(!vp->v_file); - rc = filp_close(vp->v_fp, 0); + rc = filp_close(vp->v_file, 0); vn_free(vp); return rc; @@ -344,10 +350,10 @@ vn_getattr(vnode_t *vp, vattr_t *vap, int flags, void *x3, void *x4) int rc; BUG_ON(!vp); - BUG_ON(!vp->v_fp); + BUG_ON(!vp->v_file); BUG_ON(!vap); - fp = vp->v_fp; + fp = vp->v_file; rc = vfs_getattr(fp->f_vfsmnt, fp->f_dentry, &stat); if (rc) @@ -380,15 +386,143 @@ int vn_fsync(vnode_t *vp, int flags, void *x3, void *x4) int datasync = 0; BUG_ON(!vp); - BUG_ON(!vp->v_fp); + BUG_ON(!vp->v_file); if (flags & FDSYNC) datasync = 1; - return file_fsync(vp->v_fp, vp->v_fp->f_dentry, datasync); + return file_fsync(vp->v_file, vp->v_file->f_dentry, datasync); } /* vn_fsync() */ EXPORT_SYMBOL(vn_fsync); +/* Function must be called while holding the vn_file_lock */ +static file_t * +file_find(int fd) +{ + file_t *fp; + + BUG_ON(!spin_is_locked(&vn_file_lock)); + + list_for_each_entry(fp, &vn_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 * +vn_getf(int fd) +{ + struct kstat stat; + struct file *lfp; + file_t *fp; + vnode_t *vp; + + /* Already open just take an extra reference */ + spin_lock(&vn_file_lock); + + fp = file_find(fd); + if (fp) { + atomic_inc(&fp->f_ref); + spin_unlock(&vn_file_lock); + printk("found file\n"); + return fp; + } + + spin_unlock(&vn_file_lock); + + /* File was not yet opened create the object and setup */ + fp = kmem_cache_alloc(vn_file_cache, 0); + if (fp == NULL) + goto out; + + mutex_enter(&fp->f_lock); + + fp->f_fd = fd; + fp->f_offset = 0; + atomic_inc(&fp->f_ref); + + lfp = fget(fd); + if (lfp == NULL) + goto out_mutex; + + vp = vn_alloc(KM_SLEEP); + if (vp == NULL) + goto out_fget; + + if (vfs_getattr(lfp->f_vfsmnt, lfp->f_dentry, &stat)) + goto out_vnode; + + mutex_enter(&vp->v_lock); + vp->v_type = vn_get_sol_type(stat.mode); + vp->v_file = lfp; + mutex_exit(&vp->v_lock); + + fp->f_vnode = vp; + fp->f_file = lfp; + + /* Put it on the tracking list */ + spin_lock(&vn_file_lock); + list_add(&fp->f_list, &vn_file_list); + spin_unlock(&vn_file_lock); + + mutex_exit(&fp->f_lock); + return fp; + +out_vnode: + printk("out_vnode\n"); + vn_free(vp); +out_fget: + printk("out_fget\n"); + fput(lfp); +out_mutex: + printk("out_mutex\n"); + mutex_exit(&fp->f_lock); + kmem_cache_free(vn_file_cache, fp); +out: + printk("out\n"); + 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(vn_file_cache, fp); +} + +void +vn_releasef(int fd) +{ + file_t *fp; + + spin_lock(&vn_file_lock); + fp = file_find(fd); + if (fp) { + atomic_dec(&fp->f_ref); + if (atomic_read(&fp->f_ref) > 0) { + spin_unlock(&vn_file_lock); + return; + } + + list_del(&fp->f_list); + releasef_locked(fp); + } + spin_unlock(&vn_file_lock); + + return; +} /* releasef() */ +EXPORT_SYMBOL(releasef); + static int vn_cache_constructor(void *buf, void *cdrarg, int kmflags) { @@ -407,6 +541,25 @@ vn_cache_destructor(void *buf, void *cdrarg) mutex_destroy(&vp->v_lock); } /* vn_cache_destructor() */ +static int +vn_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 +vn_file_cache_destructor(void *buf, void *cdrarg) +{ + file_t *fp = buf; + + mutex_destroy(&fp->f_lock); +} /* vn_file_cache_destructor() */ + int vn_init(void) { @@ -414,11 +567,42 @@ vn_init(void) vn_cache_constructor, vn_cache_destructor, NULL, NULL, NULL, 0); + + vn_file_cache = kmem_cache_create("spl_vn_file_cache", + sizeof(file_t), 64, + vn_file_cache_constructor, + vn_file_cache_destructor, + NULL, NULL, NULL, 0); return 0; } /* vn_init() */ void vn_fini(void) { - kmem_cache_destroy(vn_cache); + file_t *fp, *next_fp; + int rc, leaked = 0; + + spin_lock(&vn_file_lock); + + list_for_each_entry_safe(fp, next_fp, &vn_file_list, f_list) { + list_del(&fp->f_list); + releasef_locked(fp); + leaked++; + } + + rc = kmem_cache_destroy(vn_file_cache); + if (rc) + printk("Warning leaked vn_file_cache objects\n"); + + vn_file_cache = NULL; + spin_unlock(&vn_file_lock); + + if (leaked > 0) + printk("Warning: %d files leaked\n", leaked); + + rc = kmem_cache_destroy(vn_cache); + if (rc) + printk("Warning leaked vn_cache objects\n"); + + return; } /* vn_fini() */ diff --git a/modules/splat/Makefile.in b/modules/splat/Makefile.in index b437331ad..69f38b1f5 100644 --- a/modules/splat/Makefile.in +++ b/modules/splat/Makefile.in @@ -23,7 +23,6 @@ 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/ diff --git a/modules/splat/splat-ctl.c b/modules/splat/splat-ctl.c index 8c853fca5..e9026cd8d 100644 --- a/modules/splat/splat-ctl.c +++ b/modules/splat/splat-ctl.c @@ -593,7 +593,6 @@ 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"))) @@ -655,7 +654,6 @@ 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); diff --git a/modules/splat/splat-file.c b/modules/splat/splat-file.c deleted file mode 100644 index e05f1c5d7..000000000 --- a/modules/splat/splat-file.c +++ /dev/null @@ -1,57 +0,0 @@ -#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() */ diff --git a/modules/splat/splat-internal.h b/modules/splat/splat-internal.h index 4286a9571..aca4b3d38 100644 --- a/modules/splat/splat-internal.h +++ b/modules/splat/splat-internal.h @@ -172,7 +172,6 @@ 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 *); @@ -184,7 +183,6 @@ 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); @@ -196,6 +194,5 @@ 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 */ diff --git a/modules/splat/splat-kobj.c b/modules/splat/splat-kobj.c index ad6c8a06c..f6bfa6d00 100644 --- a/modules/splat/splat-kobj.c +++ b/modules/splat/splat-kobj.c @@ -55,7 +55,7 @@ splat_kobj_test2(struct file *file, void *arg) goto out; } - buf = kmalloc(size, GFP_KERNEL); + buf = kmalloc(size + 1, GFP_KERNEL); if (!buf) { rc = -ENOMEM; splat_vprint(file, SPLAT_KOBJ_TEST2_NAME, "Failed to alloc " @@ -63,6 +63,7 @@ splat_kobj_test2(struct file *file, void *arg) goto out; } + memset(buf, 0, size + 1); rc = kobj_read_file(f, buf, size, 0); if (rc < 0) { splat_vprint(file, SPLAT_KOBJ_TEST2_NAME, "Failed read of " @@ -74,7 +75,7 @@ splat_kobj_test2(struct file *file, void *arg) * 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; + 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)); diff --git a/modules/splat/splat-vnode.c b/modules/splat/splat-vnode.c index 402872d6b..92bbbfc74 100644 --- a/modules/splat/splat-vnode.c +++ b/modules/splat/splat-vnode.c @@ -1,4 +1,5 @@ #include "splat-internal.h" +#include #define SPLAT_SUBSYSTEM_VNODE 0x0900 #define SPLAT_VNODE_NAME "vnode" @@ -28,6 +29,10 @@ #define SPLAT_VNODE_TEST6_NAME "vn_sync" #define SPLAT_VNODE_TEST6_DESC "Vn_sync Test" +#define SPLAT_VNODE_TEST7_ID 0x0907 +#define SPLAT_VNODE_TEST7_NAME "getf" +#define SPLAT_VNODE_TEST7_DESC "getf/releasef 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" @@ -130,7 +135,7 @@ splat_vnode_test3(struct file *file, void *arg) } if (strncmp(buf1, buf2, strlen(buf1))) { - rc = EINVAL; + rc = -EINVAL; splat_vprint(file, SPLAT_VNODE_TEST3_NAME, "Failed strncmp data written does not match " "data read\nWrote: %sRead: %s\n", buf1, buf2); @@ -315,7 +320,120 @@ out: vn_remove(SPLAT_VNODE_TEST_FILE_RW, UIO_SYSSPACE, RMFILE); return rc; -} /* splat_vnode_test4() */ +} /* splat_vnode_test6() */ + +/* Basically a slightly modified version of sys_close() */ +static int +fd_uninstall(int fd) +{ + struct file *fp; + struct files_struct *files = current->files; + struct fdtable *fdt; + + spin_lock(&files->file_lock); + fdt = files_fdtable(files); + + if (fd >= fdt->max_fds) + goto out_unlock; + + fp = fdt->fd[fd]; + if (!fp) + goto out_unlock; + + rcu_assign_pointer(fdt->fd[fd], NULL); + FD_CLR(fd, fdt->close_on_exec); + + /* Dropping the lock here exposes a minor race but it allows me + * to use the existing kernel interfaces for this, and for a test + * case I think that's reasonable. */ + spin_unlock(&files->file_lock); + put_unused_fd(fd); + +out_unlock: + spin_unlock(&files->file_lock); + return -EBADF; +} /* fd_uninstall() */ + +static int +splat_vnode_test7(struct file *file, void *arg) +{ + char buf1[32] = "SPL VNode Interface Test File\n"; + char buf2[32] = ""; + struct file *lfp; + file_t *fp; + int rc, fd; + + /* Prep work needed to test getf/releasef */ + fd = get_unused_fd(); + if (fd < 0) { + splat_vprint(file, SPLAT_VNODE_TEST7_NAME, + "Failed to get unused fd (%d)\n", fd); + return fd; + } + + lfp = filp_open(SPLAT_VNODE_TEST_FILE_RW, O_RDWR|O_CREAT|O_EXCL, 0644); + if (IS_ERR(lfp)) { + put_unused_fd(fd); + rc = PTR_ERR(lfp); + splat_vprint(file, SPLAT_VNODE_TEST7_NAME, + "Failed to filp_open: %s (%d)\n", + SPLAT_VNODE_TEST_FILE_RW, rc); + return rc; + } + + /* Pair up the new fd and lfp in the current context, this allows + * getf to lookup the file struct simply by the known open fd */ + fd_install(fd, lfp); + + /* Actual getf()/releasef() test */ + fp = vn_getf(fd); + if (fp == NULL) { + rc = -EINVAL; + splat_vprint(file, SPLAT_VNODE_TEST7_NAME, + "Failed to getf fd %d: (%d)\n", fd, rc); + goto out; + } + + rc = vn_rdwr(UIO_WRITE, fp->f_vnode, buf1, strlen(buf1), 0, + UIO_SYSSPACE, 0, RLIM64_INFINITY, 0, NULL); + if (rc < 0) { + splat_vprint(file, SPLAT_VNODE_TEST7_NAME, + "Failed vn_rdwr write of test file: %s (%d)\n", + SPLAT_VNODE_TEST_FILE_RW, rc); + goto out; + } + + rc = vn_rdwr(UIO_READ, fp->f_vnode, buf2, strlen(buf1), 0, + UIO_SYSSPACE, 0, RLIM64_INFINITY, 0, NULL); + if (rc < 0) { + splat_vprint(file, SPLAT_VNODE_TEST7_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_TEST7_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: + vn_releasef(fd); + fd_uninstall(fd); + filp_close(lfp, 0); + vn_remove(SPLAT_VNODE_TEST_FILE_RW, UIO_SYSSPACE, RMFILE); + + return rc; +} /* splat_vnode_test7() */ splat_subsystem_t * splat_vnode_init(void) @@ -346,6 +464,8 @@ splat_vnode_init(void) 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); + SPLAT_TEST_INIT(sub, SPLAT_VNODE_TEST7_NAME, SPLAT_VNODE_TEST7_DESC, + SPLAT_VNODE_TEST7_ID, splat_vnode_test7); return sub; } /* splat_vnode_init() */ @@ -355,6 +475,7 @@ splat_vnode_fini(splat_subsystem_t *sub) { ASSERT(sub); + SPLAT_TEST_FINI(sub, SPLAT_VNODE_TEST7_ID); SPLAT_TEST_FINI(sub, SPLAT_VNODE_TEST6_ID); SPLAT_TEST_FINI(sub, SPLAT_VNODE_TEST5_ID); SPLAT_TEST_FINI(sub, SPLAT_VNODE_TEST4_ID);