]> git.proxmox.com Git - mirror_spl-debian.git/blobdiff - module/spl/spl-vnode.c
Imported Upstream version 0.6.2
[mirror_spl-debian.git] / module / spl / spl-vnode.c
index 9bfead8cf44a0c431d1106ebdd341981e9e0882c..0784ff2611096304b532901b01b2559c4ae1453b 100644 (file)
@@ -6,7 +6,7 @@
  *  UCRL-CODE-235197
  *
  *  This file is part of the SPL, Solaris Porting Layer.
- *  For details, see <http://github.com/behlendorf/spl/>.
+ *  For details, see <http://zfsonlinux.org/>.
  *
  *  The SPL is free software; you can redistribute it and/or modify it
  *  under the terms of the GNU General Public License as published by the
@@ -24,7 +24,9 @@
  *  Solaris Porting Layer (SPL) Vnode Implementation.
 \*****************************************************************************/
 
+#include <sys/cred.h>
 #include <sys/vnode.h>
+#include <linux/falloc.h>
 #include <spl-debug.h>
 
 #ifdef SS_DEBUG_SUBSYS
@@ -39,11 +41,22 @@ EXPORT_SYMBOL(rootdir);
 static spl_kmem_cache_t *vn_cache;
 static spl_kmem_cache_t *vn_file_cache;
 
-static spinlock_t vn_file_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(vn_file_lock);
 static LIST_HEAD(vn_file_list);
 
-static vtype_t
-vn_get_sol_type(umode_t mode)
+#ifdef HAVE_KERN_PATH_PARENT_HEADER
+#ifndef HAVE_KERN_PATH_PARENT_SYMBOL
+kern_path_parent_t kern_path_parent_fn = SYMBOL_POISON;
+EXPORT_SYMBOL(kern_path_parent_fn);
+#endif /* HAVE_KERN_PATH_PARENT_SYMBOL */
+#endif /* HAVE_KERN_PATH_PARENT_HEADER */
+
+#ifdef HAVE_KERN_PATH_LOCKED
+kern_path_locked_t kern_path_locked_fn = SYMBOL_POISON;
+#endif /* HAVE_KERN_PATH_LOCKED */
+
+vtype_t
+vn_mode_to_vtype(mode_t mode)
 {
        if (S_ISREG(mode))
                return VREG;
@@ -70,7 +83,36 @@ vn_get_sol_type(umode_t mode)
                return VCHR;
 
        return VNON;
-} /* vn_get_sol_type() */
+} /* vn_mode_to_vtype() */
+EXPORT_SYMBOL(vn_mode_to_vtype);
+
+mode_t
+vn_vtype_to_mode(vtype_t vtype)
+{
+       if (vtype == VREG)
+               return S_IFREG;
+
+       if (vtype == VDIR)
+               return S_IFDIR;
+
+       if (vtype == VCHR)
+               return S_IFCHR;
+
+       if (vtype == VBLK)
+               return S_IFBLK;
+
+       if (vtype == VFIFO)
+               return S_IFIFO;
+
+       if (vtype == VLNK)
+               return S_IFLNK;
+
+       if (vtype == VSOCK)
+               return S_IFSOCK;
+
+       return VNON;
+} /* vn_vtype_to_mode() */
+EXPORT_SYMBOL(vn_vtype_to_mode);
 
 vnode_t *
 vn_alloc(int flag)
@@ -104,6 +146,7 @@ vn_open(const char *path, uio_seg_t seg, int flags, int mode,
        struct file *fp;
        struct kstat stat;
        int rc, saved_umask = 0;
+       gfp_t saved_gfp;
        vnode_t *vp;
        SENTRY;
 
@@ -133,7 +176,11 @@ vn_open(const char *path, uio_seg_t seg, int flags, int mode,
        if (IS_ERR(fp))
                SRETURN(-PTR_ERR(fp));
 
-       rc = vfs_getattr(fp->f_vfsmnt, fp->f_dentry, &stat);
+#ifdef HAVE_2ARGS_VFS_GETATTR
+       rc = vfs_getattr(&fp->f_path, &stat);
+#else
+       rc = vfs_getattr(fp->f_path.mnt, fp->f_dentry, &stat);
+#endif
        if (rc) {
                filp_close(fp, 0);
                SRETURN(-rc);
@@ -145,9 +192,13 @@ vn_open(const char *path, uio_seg_t seg, int flags, int mode,
                SRETURN(ENOMEM);
        }
 
+       saved_gfp = mapping_gfp_mask(fp->f_mapping);
+       mapping_set_gfp_mask(fp->f_mapping, saved_gfp & ~(__GFP_IO|__GFP_FS));
+
        mutex_enter(&vp->v_lock);
-       vp->v_type = vn_get_sol_type(stat.mode);
+       vp->v_type = vn_mode_to_vtype(stat.mode);
        vp->v_file = fp;
+       vp->v_gfp_mask = saved_gfp;
        *vpp = vp;
        mutex_exit(&vp->v_lock);
 
@@ -213,6 +264,7 @@ vn_rdwr(uio_rw_t uio, vnode_t *vp, void *addr, ssize_t len, offset_t off,
                rc = vfs_read(fp, addr, len, &offset);
 
        set_fs(saved_fs);
+       fp->f_pos = offset;
 
        if (rc < 0)
                SRETURN(-rc);
@@ -237,6 +289,7 @@ vn_close(vnode_t *vp, int flags, int x1, int x2, void *x3, void *x4)
        ASSERT(vp);
        ASSERT(vp->v_file);
 
+       mapping_set_gfp_mask(vp->v_file->f_mapping, vp->v_gfp_mask);
        rc = filp_close(vp->v_file, 0);
        vn_free(vp);
 
@@ -248,16 +301,141 @@ EXPORT_SYMBOL(vn_close);
  * proposed seek.  We perform minimal checking and allow vn_rdwr() to catch
  * anything more serious. */
 int
-vn_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
+vn_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, void *ct)
 {
        return ((*noffp < 0 || *noffp > MAXOFFSET_T) ? EINVAL : 0);
 }
 EXPORT_SYMBOL(vn_seek);
 
+#ifdef HAVE_KERN_PATH_LOCKED
+/* Based on do_unlinkat() from linux/fs/namei.c */
+int
+vn_remove(const char *path, uio_seg_t seg, int flags)
+{
+       struct dentry *dentry;
+       struct path parent;
+       struct inode *inode = NULL;
+       int rc = 0;
+       SENTRY;
+
+       ASSERT(seg == UIO_SYSSPACE);
+       ASSERT(flags == RMFILE);
+
+       dentry = spl_kern_path_locked(path, &parent);
+       rc = PTR_ERR(dentry);
+       if (!IS_ERR(dentry)) {
+               if (parent.dentry->d_name.name[parent.dentry->d_name.len])
+                       SGOTO(slashes, rc = 0);
+
+               inode = dentry->d_inode;
+               if (!inode)
+                       SGOTO(slashes, rc = 0);
+
+               if (inode)
+                       ihold(inode);
+
+               rc = vfs_unlink(parent.dentry->d_inode, dentry);
+exit1:
+               dput(dentry);
+       } else {
+               return (-rc);
+       }
+
+       spl_inode_unlock(parent.dentry->d_inode);
+       if (inode)
+               iput(inode);    /* truncate the inode here */
+
+       path_put(&parent);
+       SRETURN(-rc);
+
+slashes:
+       rc = !dentry->d_inode ? -ENOENT :
+           S_ISDIR(dentry->d_inode->i_mode) ? -EISDIR : -ENOTDIR;
+       SGOTO(exit1, rc);
+} /* vn_remove() */
+EXPORT_SYMBOL(vn_remove);
+
+/* Based on do_rename() from linux/fs/namei.c */
+int
+vn_rename(const char *oldname, const char *newname, int x1)
+{
+       struct dentry *old_dir, *new_dir;
+       struct dentry *old_dentry, *new_dentry;
+       struct dentry *trap;
+       struct path old_parent, new_parent;
+       int rc = 0;
+       SENTRY;
+
+       old_dentry = spl_kern_path_locked(oldname, &old_parent);
+       if (IS_ERR(old_dentry))
+               SGOTO(exit, rc = PTR_ERR(old_dentry));
+
+       spl_inode_unlock(old_parent.dentry->d_inode);
+
+       new_dentry = spl_kern_path_locked(newname, &new_parent);
+       if (IS_ERR(new_dentry))
+               SGOTO(exit2, rc = PTR_ERR(new_dentry));
+
+       spl_inode_unlock(new_parent.dentry->d_inode);
+
+       rc = -EXDEV;
+       if (old_parent.mnt != new_parent.mnt)
+               SGOTO(exit3, rc);
+
+       old_dir = old_parent.dentry;
+       new_dir = new_parent.dentry;
+       trap = lock_rename(new_dir, old_dir);
+
+       /* source should not be ancestor of target */
+       rc = -EINVAL;
+       if (old_dentry == trap)
+               SGOTO(exit4, rc);
+
+       /* target should not be an ancestor of source */
+       rc = -ENOTEMPTY;
+       if (new_dentry == trap)
+               SGOTO(exit4, rc);
+
+       /* source must exist */
+       rc = -ENOENT;
+       if (!old_dentry->d_inode)
+               SGOTO(exit4, rc);
+
+       /* unless the source is a directory trailing slashes give -ENOTDIR */
+       if (!S_ISDIR(old_dentry->d_inode->i_mode)) {
+               rc = -ENOTDIR;
+               if (old_dentry->d_name.name[old_dentry->d_name.len])
+                       SGOTO(exit4, rc);
+               if (new_dentry->d_name.name[new_dentry->d_name.len])
+                       SGOTO(exit4, rc);
+       }
+
+#ifdef HAVE_4ARGS_VFS_RENAME
+       rc = vfs_rename(old_dir->d_inode, old_dentry,
+                       new_dir->d_inode, new_dentry);
+#else
+       rc = vfs_rename(old_dir->d_inode, old_dentry, oldnd.nd_mnt,
+                       new_dir->d_inode, new_dentry, newnd.nd_mnt);
+#endif /* HAVE_4ARGS_VFS_RENAME */
+exit4:
+       unlock_rename(new_dir, old_dir);
+exit3:
+       dput(new_dentry);
+       path_put(&new_parent);
+exit2:
+       dput(old_dentry);
+       path_put(&old_parent);
+exit:
+       SRETURN(-rc);
+}
+EXPORT_SYMBOL(vn_rename);
+
+#else
 static struct dentry *
 vn_lookup_hash(struct nameidata *nd)
 {
-       return lookup_one_len(nd->last.name, nd->nd_dentry, nd->last.len);
+       return lookup_one_len((const char *)nd->last.name,
+                             nd->nd_dentry, nd->last.len);
 } /* lookup_hash() */
 
 static void
@@ -280,7 +458,7 @@ vn_remove(const char *path, uio_seg_t seg, int flags)
         ASSERT(seg == UIO_SYSSPACE);
         ASSERT(flags == RMFILE);
 
-        rc = path_lookup(path, LOOKUP_PARENT, &nd);
+       rc = spl_kern_path_parent(path, &nd);
         if (rc)
                 SGOTO(exit, rc);
 
@@ -288,11 +466,7 @@ vn_remove(const char *path, uio_seg_t seg, int flags)
         if (nd.last_type != LAST_NORM)
                 SGOTO(exit1, rc);
 
-#ifdef HAVE_INODE_I_MUTEX
-        mutex_lock_nested(&nd.nd_dentry->d_inode->i_mutex, I_MUTEX_PARENT);
-#else
-        down(&nd.nd_dentry->d_inode->i_sem);
-#endif /* HAVE_INODE_I_MUTEX */
+        spl_inode_lock_nested(nd.nd_dentry->d_inode, I_MUTEX_PARENT);
         dentry = vn_lookup_hash(&nd);
         rc = PTR_ERR(dentry);
         if (!IS_ERR(dentry)) {
@@ -311,11 +485,8 @@ vn_remove(const char *path, uio_seg_t seg, int flags)
 exit2:
                 dput(dentry);
         }
-#ifdef HAVE_INODE_I_MUTEX
-        mutex_unlock(&nd.nd_dentry->d_inode->i_mutex);
-#else
-        up(&nd.nd_dentry->d_inode->i_sem);
-#endif /* HAVE_INODE_I_MUTEX */
+
+        spl_inode_unlock(nd.nd_dentry->d_inode);
         if (inode)
                 iput(inode);    /* truncate the inode here */
 exit1:
@@ -341,11 +512,11 @@ vn_rename(const char *oldname, const char *newname, int x1)
         int rc = 0;
        SENTRY;
 
-        rc = path_lookup(oldname, LOOKUP_PARENT, &oldnd);
+        rc = spl_kern_path_parent(oldname, &oldnd);
         if (rc)
                 SGOTO(exit, rc);
 
-        rc = path_lookup(newname, LOOKUP_PARENT, &newnd);
+        rc = spl_kern_path_parent(newname, &newnd);
         if (rc)
                 SGOTO(exit1, rc);
 
@@ -420,12 +591,13 @@ exit:
         SRETURN(-rc);
 }
 EXPORT_SYMBOL(vn_rename);
+#endif /* HAVE_KERN_PATH_LOCKED */
 
 int
 vn_getattr(vnode_t *vp, vattr_t *vap, int flags, void *x3, void *x4)
 {
        struct file *fp;
-        struct kstat stat;
+       struct kstat stat;
        int rc;
        SENTRY;
 
@@ -435,29 +607,30 @@ vn_getattr(vnode_t *vp, vattr_t *vap, int flags, void *x3, void *x4)
 
        fp = vp->v_file;
 
-        rc = vfs_getattr(fp->f_vfsmnt, fp->f_dentry, &stat);
+#ifdef HAVE_2ARGS_VFS_GETATTR
+       rc = vfs_getattr(&fp->f_path, &stat);
+#else
+       rc = vfs_getattr(fp->f_path.mnt, fp->f_dentry, &stat);
+#endif
        if (rc)
                SRETURN(-rc);
 
-       vap->va_type          = vn_get_sol_type(stat.mode);
+       vap->va_type          = vn_mode_to_vtype(stat.mode);
        vap->va_mode          = stat.mode;
-       vap->va_uid           = stat.uid;
-       vap->va_gid           = stat.gid;
+       vap->va_uid           = KUID_TO_SUID(stat.uid);
+       vap->va_gid           = KGID_TO_SGID(stat.gid);
        vap->va_fsid          = 0;
        vap->va_nodeid        = stat.ino;
        vap->va_nlink         = stat.nlink;
         vap->va_size          = stat.size;
-       vap->va_blocksize     = stat.blksize;
-       vap->va_atime.tv_sec  = stat.atime.tv_sec;
-       vap->va_atime.tv_usec = stat.atime.tv_nsec / NSEC_PER_USEC;
-       vap->va_mtime.tv_sec  = stat.mtime.tv_sec;
-       vap->va_mtime.tv_usec = stat.mtime.tv_nsec / NSEC_PER_USEC;
-       vap->va_ctime.tv_sec  = stat.ctime.tv_sec;
-       vap->va_ctime.tv_usec = stat.ctime.tv_nsec / NSEC_PER_USEC;
+       vap->va_blksize       = stat.blksize;
+       vap->va_atime         = stat.atime;
+       vap->va_mtime         = stat.mtime;
+       vap->va_ctime         = stat.ctime;
        vap->va_rdev          = stat.rdev;
-       vap->va_blocks        = stat.blocks;
+       vap->va_nblocks       = stat.blocks;
 
-        SRETURN(0);
+       SRETURN(0);
 }
 EXPORT_SYMBOL(vn_getattr);
 
@@ -476,6 +649,60 @@ int vn_fsync(vnode_t *vp, int flags, void *x3, void *x4)
 } /* vn_fsync() */
 EXPORT_SYMBOL(vn_fsync);
 
+int vn_space(vnode_t *vp, int cmd, struct flock *bfp, int flag,
+    offset_t offset, void *x6, void *x7)
+{
+       int error = EOPNOTSUPP;
+       SENTRY;
+
+       if (cmd != F_FREESP || bfp->l_whence != 0)
+               SRETURN(EOPNOTSUPP);
+
+       ASSERT(vp);
+       ASSERT(vp->v_file);
+       ASSERT(bfp->l_start >= 0 && bfp->l_len > 0);
+
+#ifdef FALLOC_FL_PUNCH_HOLE
+       /*
+        * When supported by the underlying file system preferentially
+        * use the fallocate() callback to preallocate the space.
+        */
+       error = -spl_filp_fallocate(vp->v_file,
+           FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
+           bfp->l_start, bfp->l_len);
+       if (error == 0)
+               SRETURN(0);
+#endif
+
+#ifdef HAVE_INODE_TRUNCATE_RANGE
+       if (vp->v_file->f_dentry && vp->v_file->f_dentry->d_inode &&
+           vp->v_file->f_dentry->d_inode->i_op &&
+           vp->v_file->f_dentry->d_inode->i_op->truncate_range) {
+               off_t end = bfp->l_start + bfp->l_len;
+               /*
+                * Judging from the code in shmem_truncate_range(),
+                * it seems the kernel expects the end offset to be
+                * inclusive and aligned to the end of a page.
+                */
+               if (end % PAGE_SIZE != 0) {
+                       end &= ~(off_t)(PAGE_SIZE - 1);
+                       if (end <= bfp->l_start)
+                               SRETURN(0);
+               }
+               --end;
+
+               vp->v_file->f_dentry->d_inode->i_op->truncate_range(
+                       vp->v_file->f_dentry->d_inode,
+                       bfp->l_start, end
+               );
+               SRETURN(0);
+       }
+#endif
+
+       SRETURN(error);
+}
+EXPORT_SYMBOL(vn_space);
+
 /* Function must be called while holding the vn_file_lock */
 static file_t *
 file_find(int fd)
@@ -485,7 +712,7 @@ file_find(int fd)
        ASSERT(spin_is_locked(&vn_file_lock));
 
         list_for_each_entry(fp, &vn_file_list,  f_list) {
-               if (fd == fp->f_fd) {
+               if (fd == fp->f_fd && fp->f_task == current) {
                        ASSERT(atomic_read(&fp->f_ref) != 0);
                         return fp;
                }
@@ -524,6 +751,7 @@ vn_getf(int fd)
        mutex_enter(&fp->f_lock);
 
        fp->f_fd = fd;
+       fp->f_task = current;
        fp->f_offset = 0;
        atomic_inc(&fp->f_ref);
 
@@ -535,11 +763,16 @@ vn_getf(int fd)
        if (vp == NULL)
                SGOTO(out_fget, rc);
 
-        if (vfs_getattr(lfp->f_vfsmnt, lfp->f_dentry, &stat))
+#ifdef HAVE_2ARGS_VFS_GETATTR
+       rc = vfs_getattr(&lfp->f_path, &stat);
+#else
+       rc = vfs_getattr(lfp->f_path.mnt, lfp->f_dentry, &stat);
+#endif
+        if (rc)
                SGOTO(out_vnode, rc);
 
        mutex_enter(&vp->v_lock);
-       vp->v_type = vn_get_sol_type(stat.mode);
+       vp->v_type = vn_mode_to_vtype(stat.mode);
        vp->v_file = lfp;
        mutex_exit(&vp->v_lock);
 
@@ -605,53 +838,42 @@ vn_releasef(int fd)
 EXPORT_SYMBOL(releasef);
 
 #ifndef HAVE_SET_FS_PWD
-# ifdef HAVE_2ARGS_SET_FS_PWD
-/* Used from 2.6.25 - 2.6.31+ */
 void
+#  ifdef HAVE_SET_FS_PWD_WITH_CONST
+set_fs_pwd(struct fs_struct *fs, const struct path *path)
+#  else
 set_fs_pwd(struct fs_struct *fs, struct path *path)
+#  endif
 {
-        struct path old_pwd;
-
-        write_lock(&fs->lock);
-        old_pwd = fs->pwd;
-        fs->pwd = *path;
-        path_get(path);
-        write_unlock(&fs->lock);
-
-        if (old_pwd.dentry)
-                path_put(&old_pwd);
-}
-# else
-/* Used from 2.6.11 - 2.6.24 */
-void
-set_fs_pwd(struct fs_struct *fs, struct vfsmount *mnt, struct dentry *dentry)
-{
-        struct dentry *old_pwd;
-        struct vfsmount *old_pwdmnt;
-
-        write_lock(&fs->lock);
-        old_pwd = fs->pwd;
-        old_pwdmnt = fs->pwdmnt;
-        fs->pwdmnt = mntget(mnt);
-        fs->pwd = dget(dentry);
-        write_unlock(&fs->lock);
-
-        if (old_pwd) {
-                dput(old_pwd);
-                mntput(old_pwdmnt);
-        }
+       struct path old_pwd;
+
+#  ifdef HAVE_FS_STRUCT_SPINLOCK
+       spin_lock(&fs->lock);
+       old_pwd = fs->pwd;
+       fs->pwd = *path;
+       path_get(path);
+       spin_unlock(&fs->lock);
+#  else
+       write_lock(&fs->lock);
+       old_pwd = fs->pwd;
+       fs->pwd = *path;
+       path_get(path);
+       write_unlock(&fs->lock);
+#  endif /* HAVE_FS_STRUCT_SPINLOCK */
+
+       if (old_pwd.dentry)
+               path_put(&old_pwd);
 }
-# endif /* HAVE_2ARGS_SET_FS_PWD */
 #endif /* HAVE_SET_FS_PWD */
 
 int
 vn_set_pwd(const char *filename)
 {
-#if defined(HAVE_2ARGS_SET_FS_PWD) && defined(HAVE_USER_PATH_DIR)
+#ifdef HAVE_USER_PATH_DIR
         struct path path;
 #else
         struct nameidata nd;
-#endif /* HAVE_2ARGS_SET_FS_PWD */
+#endif /* HAVE_USER_PATH_DIR */
         mm_segment_t saved_fs;
         int rc;
         SENTRY;
@@ -664,7 +886,6 @@ vn_set_pwd(const char *filename)
         saved_fs = get_fs();
         set_fs(get_ds());
 
-#ifdef HAVE_2ARGS_SET_FS_PWD
 # ifdef HAVE_USER_PATH_DIR
         rc = user_path_dir(filename, &path);
         if (rc)
@@ -693,21 +914,6 @@ dput_and_out:
 dput_and_out:
         path_put(&nd.path);
 # endif /* HAVE_USER_PATH_DIR */
-#else
-        rc = __user_walk(filename,
-                         LOOKUP_FOLLOW|LOOKUP_DIRECTORY|LOOKUP_CHDIR, &nd);
-        if (rc)
-                SGOTO(out, rc);
-
-        rc = vfs_permission(&nd, MAY_EXEC);
-        if (rc)
-                SGOTO(dput_and_out, rc);
-
-        set_fs_pwd(current->fs, nd.nd_mnt, nd.nd_dentry);
-
-dput_and_out:
-        vn_path_release(&nd);
-#endif /* HAVE_2ARGS_SET_FS_PWD */
 out:
        set_fs(saved_fs);
 
@@ -753,26 +959,51 @@ vn_file_cache_destructor(void *buf, void *cdrarg)
        mutex_destroy(&fp->f_lock);
 } /* vn_file_cache_destructor() */
 
+int spl_vn_init_kallsyms_lookup(void)
+{
+#ifdef HAVE_KERN_PATH_PARENT_HEADER
+#ifndef HAVE_KERN_PATH_PARENT_SYMBOL
+       kern_path_parent_fn = (kern_path_parent_t)
+               spl_kallsyms_lookup_name("kern_path_parent");
+       if (!kern_path_parent_fn) {
+               printk(KERN_ERR "Error: Unknown symbol kern_path_parent\n");
+               return -EFAULT;
+       }
+#endif /* HAVE_KERN_PATH_PARENT_SYMBOL */
+#endif /* HAVE_KERN_PATH_PARENT_HEADER */
+
+#ifdef HAVE_KERN_PATH_LOCKED
+        kern_path_locked_fn = (kern_path_locked_t)
+                spl_kallsyms_lookup_name("kern_path_locked");
+        if (!kern_path_locked_fn) {
+                printk(KERN_ERR "Error: Unknown symbol kern_path_locked\n");
+                return -EFAULT;
+        }
+#endif
+
+       return (0);
+}
+
 int
-vn_init(void)
+spl_vn_init(void)
 {
        SENTRY;
        vn_cache = kmem_cache_create("spl_vn_cache",
                                     sizeof(struct vnode), 64,
                                     vn_cache_constructor,
                                     vn_cache_destructor,
-                                    NULL, NULL, NULL, 0);
+                                    NULL, NULL, NULL, KMC_KMEM);
 
        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);
+                                         NULL, NULL, NULL, KMC_KMEM);
        SRETURN(0);
 } /* vn_init() */
 
 void
-vn_fini(void)
+spl_vn_fini(void)
 {
         file_t *fp, *next_fp;
        int leaked = 0;
@@ -786,13 +1017,12 @@ vn_fini(void)
                leaked++;
        }
 
-       kmem_cache_destroy(vn_file_cache);
-       vn_file_cache = NULL;
        spin_unlock(&vn_file_lock);
 
        if (leaked > 0)
                SWARN("Warning %d files leaked\n", leaked);
 
+       kmem_cache_destroy(vn_file_cache);
        kmem_cache_destroy(vn_cache);
 
        SEXIT;