summaryrefslogtreecommitdiffstats
path: root/module
diff options
context:
space:
mode:
authorBrian Behlendorf <[email protected]>2012-12-10 10:15:12 -0800
committerBrian Behlendorf <[email protected]>2012-12-12 10:47:05 -0800
commit2ae10319624869eef0954cdfcdb6f5e33cba2e09 (patch)
treeb7be37184aa672672dc39eef5195ad9cc0b9f3bd /module
parente4d89e9cfc605dc59df57d89818868e033e59cfb (diff)
Linux 3.7 compat, schedule_delayed_work()
Linux kernel commit d8e794d accidentally broke the delayed work APIs for non-GPL callers. While the APIs to schedule a delayed work item are still available to all callers, it is no longer possible to initialize the delayed work item. I'm cautiously optimistic we could get the delayed_work_timer_fn exported for all callers in the upstream kernel. But frankly the compatibility code to use this kernel interface has always been problematic. Therefore, this patch abandons direct use the of the Linux kernel interface in favor of the new delayed taskq interface. It provides roughly the same functionality as delayed work queues but it's a stable interface under our control. Signed-off-by: Brian Behlendorf <[email protected]> Closes #1053
Diffstat (limited to 'module')
-rw-r--r--module/zfs/zfs_ctldir.c31
1 files changed, 20 insertions, 11 deletions
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);