select IP_SCTP if DLM_SCTP
        select FS_POSIX_ACL
        select CRC32
-       select SLOW_WORK
        select QUOTACTL
        help
          A cluster filesystem.
 
 
 #include <linux/fs.h>
 #include <linux/workqueue.h>
-#include <linux/slow-work.h>
 #include <linux/dlm.h>
 #include <linux/buffer_head.h>
 
 struct gfs2_jdesc {
        struct list_head jd_list;
        struct list_head extent_list;
-       struct slow_work jd_work;
+       struct work_struct jd_work;
        struct inode *jd_inode;
        unsigned long jd_flags;
 #define JDF_RECOVERY 1
 
 #include <linux/init.h>
 #include <linux/gfs2_ondisk.h>
 #include <asm/atomic.h>
-#include <linux/slow-work.h>
 
 #include "gfs2.h"
 #include "incore.h"
 #include "util.h"
 #include "glock.h"
 #include "quota.h"
+#include "recovery.h"
 
 static struct shrinker qd_shrinker = {
        .shrink = gfs2_shrink_qd_memory,
        if (error)
                goto fail_unregister;
 
-       error = slow_work_register_user(THIS_MODULE);
-       if (error)
-               goto fail_slow;
+       error = -ENOMEM;
+       gfs_recovery_wq = alloc_workqueue("gfs_recovery",
+                                         WQ_NON_REENTRANT | WQ_RESCUER, 0);
+       if (!gfs_recovery_wq)
+               goto fail_wq;
 
        gfs2_register_debugfs();
 
 
        return 0;
 
-fail_slow:
+fail_wq:
        unregister_filesystem(&gfs2meta_fs_type);
 fail_unregister:
        unregister_filesystem(&gfs2_fs_type);
        gfs2_unregister_debugfs();
        unregister_filesystem(&gfs2_fs_type);
        unregister_filesystem(&gfs2meta_fs_type);
-       slow_work_unregister_user(THIS_MODULE);
+       destroy_workqueue(gfs_recovery_wq);
 
        kmem_cache_destroy(gfs2_quotad_cachep);
        kmem_cache_destroy(gfs2_rgrpd_cachep);
 
 #include <linux/namei.h>
 #include <linux/mount.h>
 #include <linux/gfs2_ondisk.h>
-#include <linux/slow-work.h>
 #include <linux/quotaops.h>
 
 #include "gfs2.h"
                        break;
 
                INIT_LIST_HEAD(&jd->extent_list);
-               slow_work_init(&jd->jd_work, &gfs2_recover_ops);
+               INIT_WORK(&jd->jd_work, gfs2_recover_func);
                jd->jd_inode = gfs2_lookupi(sdp->sd_jindex, &name, 1);
                if (!jd->jd_inode || IS_ERR(jd->jd_inode)) {
                        if (!jd->jd_inode)
        if (sdp->sd_lockstruct.ls_first) {
                unsigned int x;
                for (x = 0; x < sdp->sd_journals; x++) {
-                       error = gfs2_recover_journal(gfs2_jdesc_find(sdp, x));
+                       error = gfs2_recover_journal(gfs2_jdesc_find(sdp, x),
+                                                    true);
                        if (error) {
                                fs_err(sdp, "error recovering journal %u: %d\n",
                                       x, error);
 
                gfs2_others_may_mount(sdp);
        } else if (!sdp->sd_args.ar_spectator) {
-               error = gfs2_recover_journal(sdp->sd_jdesc);
+               error = gfs2_recover_journal(sdp->sd_jdesc, true);
                if (error) {
                        fs_err(sdp, "error recovering my journal: %d\n", error);
                        goto fail_jinode_gh;
 
 #include <linux/buffer_head.h>
 #include <linux/gfs2_ondisk.h>
 #include <linux/crc32.h>
-#include <linux/slow-work.h>
 
 #include "gfs2.h"
 #include "incore.h"
 #include "util.h"
 #include "dir.h"
 
+struct workqueue_struct *gfs_recovery_wq;
+
 int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk,
                           struct buffer_head **bh)
 {
         kobject_uevent_env(&sdp->sd_kobj, KOBJ_CHANGE, envp);
 }
 
-static int gfs2_recover_get_ref(struct slow_work *work)
-{
-       struct gfs2_jdesc *jd = container_of(work, struct gfs2_jdesc, jd_work);
-       if (test_and_set_bit(JDF_RECOVERY, &jd->jd_flags))
-               return -EBUSY;
-       return 0;
-}
-
-static void gfs2_recover_put_ref(struct slow_work *work)
-{
-       struct gfs2_jdesc *jd = container_of(work, struct gfs2_jdesc, jd_work);
-       clear_bit(JDF_RECOVERY, &jd->jd_flags);
-       smp_mb__after_clear_bit();
-       wake_up_bit(&jd->jd_flags, JDF_RECOVERY);
-}
-
-static void gfs2_recover_work(struct slow_work *work)
+void gfs2_recover_func(struct work_struct *work)
 {
        struct gfs2_jdesc *jd = container_of(work, struct gfs2_jdesc, jd_work);
        struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
                gfs2_glock_dq_uninit(&j_gh);
 
        fs_info(sdp, "jid=%u: Done\n", jd->jd_jid);
-       return;
+       goto done;
 
 fail_gunlock_tr:
        gfs2_glock_dq_uninit(&t_gh);
        }
 
        fs_info(sdp, "jid=%u: %s\n", jd->jd_jid, (error) ? "Failed" : "Done");
-
 fail:
        gfs2_recovery_done(sdp, jd->jd_jid, LM_RD_GAVEUP);
+done:
+       clear_bit(JDF_RECOVERY, &jd->jd_flags);
+       smp_mb__after_clear_bit();
+       wake_up_bit(&jd->jd_flags, JDF_RECOVERY);
 }
 
-struct slow_work_ops gfs2_recover_ops = {
-       .owner   = THIS_MODULE,
-       .get_ref = gfs2_recover_get_ref,
-       .put_ref = gfs2_recover_put_ref,
-       .execute = gfs2_recover_work,
-};
-
-
 static int gfs2_recovery_wait(void *word)
 {
        schedule();
        return 0;
 }
 
-int gfs2_recover_journal(struct gfs2_jdesc *jd)
+int gfs2_recover_journal(struct gfs2_jdesc *jd, bool wait)
 {
        int rv;
-       rv = slow_work_enqueue(&jd->jd_work);
-       if (rv)
-               return rv;
-       wait_on_bit(&jd->jd_flags, JDF_RECOVERY, gfs2_recovery_wait, TASK_UNINTERRUPTIBLE);
+
+       if (test_and_set_bit(JDF_RECOVERY, &jd->jd_flags))
+               return -EBUSY;
+
+       /* we have JDF_RECOVERY, queue should always succeed */
+       rv = queue_work(gfs_recovery_wq, &jd->jd_work);
+       BUG_ON(!rv);
+
+       if (wait)
+               wait_on_bit(&jd->jd_flags, JDF_RECOVERY, gfs2_recovery_wait,
+                           TASK_UNINTERRUPTIBLE);
+
        return 0;
 }
 
 
 
 #include "incore.h"
 
+extern struct workqueue_struct *gfs_recovery_wq;
+
 static inline void gfs2_replay_incr_blk(struct gfs2_sbd *sdp, unsigned int *blk)
 {
        if (++*blk == sdp->sd_jdesc->jd_blocks)
 
 extern int gfs2_find_jhead(struct gfs2_jdesc *jd,
                    struct gfs2_log_header_host *head);
-extern int gfs2_recover_journal(struct gfs2_jdesc *gfs2_jd);
-extern struct slow_work_ops gfs2_recover_ops;
+extern int gfs2_recover_journal(struct gfs2_jdesc *gfs2_jd, bool wait);
+extern void gfs2_recover_func(struct work_struct *work);
 
 #endif /* __RECOVERY_DOT_H__ */
 
 
 #include "quota.h"
 #include "util.h"
 #include "glops.h"
+#include "recovery.h"
 
 struct gfs2_attr {
        struct attribute attr;
        list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) {
                if (jd->jd_jid != jid)
                        continue;
-               rv = slow_work_enqueue(&jd->jd_work);
+               rv = gfs2_recover_journal(jd, false);
                break;
        }
 out: