diff options
author | Brian Behlendorf <[email protected]> | 2014-08-04 13:30:20 -0700 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2014-08-11 16:11:43 -0700 |
commit | 0a50679ce9eb8ded7bf20685e9d32724ded9cb8d (patch) | |
tree | 0087b2570d24eb85e710051c4c3721bc22469069 | |
parent | 4dd18932ba4cfdcf9b16609f6a80c2d6c239cb15 (diff) |
Add zfs_iput_async() interface
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 <[email protected]>
Signed-off-by: Richard Yao <[email protected]>
Closes #457
-rw-r--r-- | include/sys/zfs_vnops.h | 1 | ||||
-rw-r--r-- | module/zfs/zfs_dir.c | 7 | ||||
-rw-r--r-- | module/zfs/zfs_vnops.c | 18 | ||||
-rw-r--r-- | module/zfs/zfs_znode.c | 2 |
4 files changed, 17 insertions, 11 deletions
diff --git a/include/sys/zfs_vnops.h b/include/sys/zfs_vnops.h index c9fecf8ba..c331035c5 100644 --- a/include/sys/zfs_vnops.h +++ b/include/sys/zfs_vnops.h @@ -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 } diff --git a/module/zfs/zfs_dir.c b/module/zfs/zfs_dir.c index 448a8727e..d2b5bc408 100644 --- a/module/zfs/zfs_dir.c +++ b/module/zfs/zfs_dir.c @@ -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 diff --git a/module/zfs/zfs_vnops.c b/module/zfs/zfs_vnops.c index 4f531733e..18b2564a2 100644 --- a/module/zfs/zfs_vnops.c +++ b/module/zfs/zfs_vnops.c @@ -101,7 +101,7 @@ * 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)); } diff --git a/module/zfs/zfs_znode.c b/module/zfs/zfs_znode.c index 4403e3289..5fcb9e930 100644 --- a/module/zfs/zfs_znode.c +++ b/module/zfs/zfs_znode.c @@ -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; } |