diff --git a/include/sys/zfs_ctldir.h b/include/sys/zfs_ctldir.h index 0a3c142eb..1ff23a298 100644 --- a/include/sys/zfs_ctldir.h +++ b/include/sys/zfs_ctldir.h @@ -50,7 +50,7 @@ typedef struct { char *se_name; char *se_path; struct inode *se_inode; - struct delayed_work se_work; + taskqid_t se_taskqid; avl_node_t se_node; } zfs_snapentry_t; diff --git a/module/zfs/zfs_ctldir.c b/module/zfs/zfs_ctldir.c index d139b8613..a667340c8 100644 --- a/module/zfs/zfs_ctldir.c +++ b/module/zfs/zfs_ctldir.c @@ -90,6 +90,11 @@ */ int zfs_expire_snapshot = ZFSCTL_EXPIRE_SNAPSHOT; +/* + * Dedicated task queue for unmounting snapshots. + */ +static taskq_t *zfs_expire_taskq; + static zfs_snapentry_t * zfsctl_sep_alloc(void) { @@ -112,16 +117,15 @@ zfsctl_sep_free(zfs_snapentry_t *sep) static void zfsctl_expire_snapshot(void *data) { - zfs_snapentry_t *sep; - zfs_sb_t *zsb; + zfs_snapentry_t *sep = (zfs_snapentry_t *)data; + zfs_sb_t *zsb = ITOZSB(sep->se_inode); int error; - sep = spl_get_work_data(data, zfs_snapentry_t, se_work.work); - zsb = ITOZSB(sep->se_inode); - error = zfsctl_unmount_snapshot(zsb, sep->se_name, MNT_EXPIRE); if (error == EBUSY) - schedule_delayed_work(&sep->se_work, zfs_expire_snapshot * HZ); + sep->se_taskqid = taskq_dispatch_delay(zfs_expire_taskq, + zfsctl_expire_snapshot, sep, TQ_SLEEP, + ddi_get_lbolt() + zfs_expire_snapshot * HZ); } int @@ -661,7 +665,7 @@ zfsctl_snapdir_inactive(struct inode *ip) if (sep->se_inode == ip) { avl_remove(&zsb->z_ctldir_snaps, sep); - cancel_delayed_work_sync(&sep->se_work); + taskq_cancel_id(zfs_expire_taskq, sep->se_taskqid); zfsctl_sep_free(sep); break; } @@ -708,7 +712,8 @@ __zfsctl_unmount_snapshot(zfs_snapentry_t *sep, int flags) * to prevent zfsctl_expire_snapshot() from attempting a unmount. */ if ((error == 0) && !(flags & MNT_EXPIRE)) - cancel_delayed_work(&sep->se_work); + taskq_cancel_id(zfs_expire_taskq, sep->se_taskqid); + return (error); } @@ -837,7 +842,7 @@ zfsctl_mount_snapshot(struct path *path, int flags) sep = avl_find(&zsb->z_ctldir_snaps, &search, NULL); if (sep) { avl_remove(&zsb->z_ctldir_snaps, sep); - cancel_delayed_work_sync(&sep->se_work); + taskq_cancel_id(zfs_expire_taskq, sep->se_taskqid); zfsctl_sep_free(sep); } @@ -847,8 +852,9 @@ zfsctl_mount_snapshot(struct path *path, int flags) sep->se_inode = ip; avl_add(&zsb->z_ctldir_snaps, sep); - spl_init_delayed_work(&sep->se_work, zfsctl_expire_snapshot, sep); - schedule_delayed_work(&sep->se_work, zfs_expire_snapshot * HZ); + sep->se_taskqid = taskq_dispatch_delay(zfs_expire_taskq, + zfsctl_expire_snapshot, sep, TQ_SLEEP, + ddi_get_lbolt() + zfs_expire_snapshot * HZ); mutex_exit(&zsb->z_ctldir_lock); error: @@ -977,6 +983,8 @@ zfsctl_shares_lookup(struct inode *dip, char *name, struct inode **ipp, void zfsctl_init(void) { + zfs_expire_taskq = taskq_create("z_unmount", 1, maxclsyspri, + 1, 8, TASKQ_PREPOPULATE); } /* @@ -986,6 +994,7 @@ zfsctl_init(void) void zfsctl_fini(void) { + taskq_destroy(zfs_expire_taskq); } module_param(zfs_expire_snapshot, int, 0644);