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 <behlendorf1@llnl.gov>
Closes #1053
char *se_name;
char *se_path;
struct inode *se_inode;
char *se_name;
char *se_path;
struct inode *se_inode;
- struct delayed_work se_work;
avl_node_t se_node;
} zfs_snapentry_t;
avl_node_t se_node;
} zfs_snapentry_t;
*/
int zfs_expire_snapshot = ZFSCTL_EXPIRE_SNAPSHOT;
*/
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)
{
static zfs_snapentry_t *
zfsctl_sep_alloc(void)
{
static void
zfsctl_expire_snapshot(void *data)
{
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);
- 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)
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);
if (sep->se_inode == ip) {
avl_remove(&zsb->z_ctldir_snaps, sep);
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;
}
zfsctl_sep_free(sep);
break;
}
* to prevent zfsctl_expire_snapshot() from attempting a unmount.
*/
if ((error == 0) && !(flags & MNT_EXPIRE))
* 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);
+
sep = avl_find(&zsb->z_ctldir_snaps, &search, NULL);
if (sep) {
avl_remove(&zsb->z_ctldir_snaps, sep);
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);
sep->se_inode = ip;
avl_add(&zsb->z_ctldir_snaps, sep);
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:
mutex_exit(&zsb->z_ctldir_lock);
error:
+ zfs_expire_taskq = taskq_create("z_unmount", 1, maxclsyspri,
+ 1, 8, TASKQ_PREPOPULATE);
+ taskq_destroy(zfs_expire_taskq);
}
module_param(zfs_expire_snapshot, int, 0644);
}
module_param(zfs_expire_snapshot, int, 0644);