]> git.proxmox.com Git - mirror_spl.git/blobdiff - module/spl/spl-vnode.c
Use kernel slab for vn_cache and vn_file_cache
[mirror_spl.git] / module / spl / spl-vnode.c
index 97eb4ef731ed253fb6fcf70ccc96698c35b8f893..cd276b5c847d6e9622eb9c222c230d6ccf323d48 100644 (file)
@@ -63,9 +63,6 @@ vn_mode_to_vtype(mode_t mode)
        if (S_ISSOCK(mode))
                return VSOCK;
 
-       if (S_ISCHR(mode))
-               return VCHR;
-
        return VNON;
 } /* vn_mode_to_vtype() */
 EXPORT_SYMBOL(vn_mode_to_vtype);
@@ -196,7 +193,7 @@ vn_openat(const char *path, uio_seg_t seg, int flags, int mode,
        ASSERT(vp == rootdir);
 
        len = strlen(path) + 2;
-       realpath = kmalloc(len, GFP_KERNEL);
+       realpath = kmalloc(len, kmem_flags_convert(KM_SLEEP));
        if (!realpath)
                return (ENOMEM);
 
@@ -222,7 +219,6 @@ vn_rdwr(uio_rw_t uio, vnode_t *vp, void *addr, ssize_t len, offset_t off,
        ASSERT(vp->v_file);
        ASSERT(seg == UIO_SYSSPACE);
        ASSERT((ioflag & ~FAPPEND) == 0);
-       ASSERT(x2 == RLIM64_INFINITY);
 
        fp = vp->v_file;
 
@@ -353,7 +349,8 @@ spl_kern_path_locked(const char *name, struct path *path)
        if (rc)
                return (ERR_PTR(rc));
 
-       spl_inode_lock(parent.dentry->d_inode);
+       /* use I_MUTEX_PARENT because vfs_unlink needs it */
+       spl_inode_lock_nested(parent.dentry->d_inode, I_MUTEX_PARENT);
 
        dentry = lookup_one_len(basename, parent.dentry, len);
        if (IS_ERR(dentry)) {
@@ -543,6 +540,8 @@ EXPORT_SYMBOL(vn_getattr);
 int vn_fsync(vnode_t *vp, int flags, void *x3, void *x4)
 {
        int datasync = 0;
+       int error;
+       int fstrans;
 
        ASSERT(vp);
        ASSERT(vp->v_file);
@@ -550,7 +549,19 @@ int vn_fsync(vnode_t *vp, int flags, void *x3, void *x4)
        if (flags & FDSYNC)
                datasync = 1;
 
-       return (-spl_filp_fsync(vp->v_file, datasync));
+       /*
+        * May enter XFS which generates a warning when PF_FSTRANS is set.
+        * To avoid this the flag is cleared over vfs_sync() and then reset.
+        */
+       fstrans = spl_fstrans_check();
+       if (fstrans)
+               current->flags &= ~(PF_FSTRANS);
+
+       error = -spl_filp_fsync(vp->v_file, datasync);
+       if (fstrans)
+               current->flags |= PF_FSTRANS;
+
+       return (error);
 } /* vn_fsync() */
 EXPORT_SYMBOL(vn_fsync);
 
@@ -558,6 +569,9 @@ int vn_space(vnode_t *vp, int cmd, struct flock *bfp, int flag,
     offset_t offset, void *x6, void *x7)
 {
        int error = EOPNOTSUPP;
+#ifdef FALLOC_FL_PUNCH_HOLE
+       int fstrans;
+#endif
 
        if (cmd != F_FREESP || bfp->l_whence != 0)
                return (EOPNOTSUPP);
@@ -567,6 +581,14 @@ int vn_space(vnode_t *vp, int cmd, struct flock *bfp, int flag,
        ASSERT(bfp->l_start >= 0 && bfp->l_len > 0);
 
 #ifdef FALLOC_FL_PUNCH_HOLE
+       /*
+        * May enter XFS which generates a warning when PF_FSTRANS is set.
+        * To avoid this the flag is cleared over vfs_sync() and then reset.
+        */
+       fstrans = spl_fstrans_check();
+       if (fstrans)
+               current->flags &= ~(PF_FSTRANS);
+
        /*
         * When supported by the underlying file system preferentially
         * use the fallocate() callback to preallocate the space.
@@ -574,6 +596,10 @@ int vn_space(vnode_t *vp, int cmd, struct flock *bfp, int flag,
        error = -spl_filp_fallocate(vp->v_file,
            FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
            bfp->l_start, bfp->l_len);
+
+       if (fstrans)
+               current->flags |= PF_FSTRANS;
+
        if (error == 0)
                return (0);
 #endif
@@ -609,14 +635,14 @@ EXPORT_SYMBOL(vn_space);
 
 /* Function must be called while holding the vn_file_lock */
 static file_t *
-file_find(int fd)
+file_find(int fd, struct task_struct *task)
 {
         file_t *fp;
 
        ASSERT(spin_is_locked(&vn_file_lock));
 
         list_for_each_entry(fp, &vn_file_list,  f_list) {
-               if (fd == fp->f_fd && fp->f_task == current) {
+               if (fd == fp->f_fd && fp->f_task == task) {
                        ASSERT(atomic_read(&fp->f_ref) != 0);
                         return fp;
                }
@@ -634,11 +660,27 @@ vn_getf(int fd)
        vnode_t *vp;
        int rc = 0;
 
+       if (fd < 0)
+               return (NULL);
+
        /* Already open just take an extra reference */
        spin_lock(&vn_file_lock);
 
-       fp = file_find(fd);
+       fp = file_find(fd, current);
        if (fp) {
+               lfp = fget(fd);
+               fput(fp->f_file);
+               /*
+                * areleasef() can cause us to see a stale reference when
+                * userspace has reused a file descriptor before areleasef()
+                * has run. fput() the stale reference and replace it. We
+                * retain the original reference count such that the concurrent
+                * areleasef() will decrement its reference and terminate.
+                */
+               if (lfp != fp->f_file) {
+                       fp->f_file = lfp;
+                       fp->f_vnode->v_file = lfp;
+               }
                atomic_inc(&fp->f_ref);
                spin_unlock(&vn_file_lock);
                return (fp);
@@ -716,11 +758,22 @@ static void releasef_locked(file_t *fp)
 
 void
 vn_releasef(int fd)
+{
+       areleasef(fd, P_FINFO(current));
+}
+EXPORT_SYMBOL(releasef);
+
+void
+vn_areleasef(int fd, uf_info_t *fip)
 {
        file_t *fp;
+       struct task_struct *task = (struct task_struct *)fip;
+
+       if (fd < 0)
+               return;
 
        spin_lock(&vn_file_lock);
-       fp = file_find(fd);
+       fp = file_find(fd, task);
        if (fp) {
                atomic_dec(&fp->f_ref);
                if (atomic_read(&fp->f_ref) > 0) {
@@ -735,7 +788,8 @@ vn_releasef(int fd)
 
        return;
 } /* releasef() */
-EXPORT_SYMBOL(releasef);
+EXPORT_SYMBOL(areleasef);
+
 
 static void
 #ifdef HAVE_SET_FS_PWD_WITH_CONST
@@ -843,13 +897,13 @@ spl_vn_init(void)
                                     sizeof(struct vnode), 64,
                                     vn_cache_constructor,
                                     vn_cache_destructor,
-                                    NULL, NULL, NULL, KMC_KMEM);
+                                    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, KMC_KMEM);
+                                         NULL, NULL, NULL, 0);
        return (0);
 } /* vn_init() */