]> granicus.if.org Git - zfs/commitdiff
Add zfs_iput_async() interface
authorBrian Behlendorf <behlendorf1@llnl.gov>
Mon, 4 Aug 2014 20:30:20 +0000 (13:30 -0700)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Mon, 11 Aug 2014 23:11:43 +0000 (16:11 -0700)
Handle all iputs in zfs_purgedir() and zfs_inode_destroy()
asynchronously to prevent deadlocks.  When the iputs are allowed
to run synchronously in the destroy call path deadlocks between
xattr directory inodes and their parent file inodes are possible.

Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Richard Yao <ryao@gentoo.org>
Closes #457

include/sys/zfs_vnops.h
module/zfs/zfs_dir.c
module/zfs/zfs_vnops.c
module/zfs/zfs_znode.c

index c9fecf8ba98e54a94ad98b551890ddb225808816..c331035c544a71475912be9d4beb36a75356b922 100644 (file)
@@ -79,6 +79,7 @@ extern int zfs_putpage(struct inode *ip, struct page *pp,
 extern int zfs_dirty_inode(struct inode *ip, int flags);
 extern int zfs_map(struct inode *ip, offset_t off, caddr_t *addrp,
     size_t len, unsigned long vm_flags);
+extern void zfs_iput_async(struct inode *ip);
 
 #ifdef __cplusplus
 }
index 448a8727ebbbd02edc21db70f9adbe64c39c376e..d2b5bc4088faa6966ba05a041bee96faaa0b9688 100644 (file)
@@ -46,6 +46,7 @@
 #include <sys/policy.h>
 #include <sys/zfs_dir.h>
 #include <sys/zfs_acl.h>
+#include <sys/zfs_vnops.h>
 #include <sys/fs/zfs.h>
 #include "fs/fs_subr.h"
 #include <sys/zap.h>
@@ -528,7 +529,7 @@ zfs_purgedir(znode_t *dzp)
                error = dmu_tx_assign(tx, TXG_WAIT);
                if (error) {
                        dmu_tx_abort(tx);
-                       iput(ZTOI(xzp));
+                       zfs_iput_async(ZTOI(xzp));
                        skipped += 1;
                        continue;
                }
@@ -541,7 +542,7 @@ zfs_purgedir(znode_t *dzp)
                        skipped += 1;
                dmu_tx_commit(tx);
 
-               iput(ZTOI(xzp));
+               zfs_iput_async(ZTOI(xzp));
        }
        zap_cursor_fini(&zc);
        if (error != ENOENT)
@@ -729,7 +730,7 @@ zfs_rmnode(znode_t *zp)
        dmu_tx_commit(tx);
 out:
        if (xzp)
-               iput(ZTOI(xzp));
+               zfs_iput_async(ZTOI(xzp));
 }
 
 static uint64_t
index 4f531733e42f9300cd591ee6dbd7ad309151f529..18b2564a270dda6f517ceeb7f242e830f609eacf 100644 (file)
  *     pushing cached pages (which acquires range locks) and syncing out
  *     cached atime changes.  Third, zfs_zinactive() may require a new tx,
  *     which could deadlock the system if you were already holding one.
- *     If you must call iput() within a tx then use iput_ASYNC().
+ *     If you must call iput() within a tx then use zfs_iput_async().
  *
  *  (3)        All range locks must be grabbed before calling dmu_tx_assign(),
  *     as they can span dmu_tx_assign() calls.
@@ -927,12 +927,17 @@ zfs_write(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
 }
 EXPORT_SYMBOL(zfs_write);
 
-static void
-iput_async(struct inode *ip, taskq_t *taskq)
+void
+zfs_iput_async(struct inode *ip)
 {
+       objset_t *os = ITOZSB(ip)->z_os;
+
        ASSERT(atomic_read(&ip->i_count) > 0);
+       ASSERT(os != NULL);
+
        if (atomic_read(&ip->i_count) == 1)
-               taskq_dispatch(taskq, (task_func_t *)iput, ip, TQ_PUSHPAGE);
+               taskq_dispatch(dsl_pool_iput_taskq(dmu_objset_pool(os)),
+                   (task_func_t *)iput, ip, TQ_PUSHPAGE);
        else
                iput(ip);
 }
@@ -941,7 +946,6 @@ void
 zfs_get_done(zgd_t *zgd, int error)
 {
        znode_t *zp = zgd->zgd_private;
-       objset_t *os = ZTOZSB(zp)->z_os;
 
        if (zgd->zgd_db)
                dmu_buf_rele(zgd->zgd_db, zgd);
@@ -952,7 +956,7 @@ zfs_get_done(zgd_t *zgd, int error)
         * Release the vnode asynchronously as we currently have the
         * txg stopped from syncing.
         */
-       iput_async(ZTOI(zp), dsl_pool_iput_taskq(dmu_objset_pool(os)));
+       zfs_iput_async(ZTOI(zp));
 
        if (error == 0 && zgd->zgd_bp)
                zil_add_block(zgd->zgd_zilog, zgd->zgd_bp);
@@ -994,7 +998,7 @@ zfs_get_data(void *arg, lr_write_t *lr, char *buf, zio_t *zio)
                 * Release the vnode asynchronously as we currently have the
                 * txg stopped from syncing.
                 */
-               iput_async(ZTOI(zp), dsl_pool_iput_taskq(dmu_objset_pool(os)));
+               zfs_iput_async(ZTOI(zp));
                return (SET_ERROR(ENOENT));
        }
 
index 4403e3289c9c90266295fddf7b37c6b567c7d5cf..5fcb9e930f745054e66cd3a25ca6dee23384efaa 100644 (file)
@@ -292,7 +292,7 @@ zfs_inode_destroy(struct inode *ip)
        }
 
        if (zp->z_xattr_parent) {
-               iput(ZTOI(zp->z_xattr_parent));
+               zfs_iput_async(ZTOI(zp->z_xattr_parent));
                zp->z_xattr_parent = NULL;
        }