Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6ecd7c2d authored by Tejun Heo's avatar Tejun Heo
Browse files

gfs2: use workqueue instead of slow-work



Workqueue can now handle high concurrency.  Convert gfs to use
workqueue instead of slow-work.

* Steven pointed out that recovery path might be run from allocation
  path and thus requires forward progress guarantee without memory
  allocation.  Create and use gfs_recovery_wq with rescuer.  Please
  note that forward progress wasn't guaranteed with slow-work.

* Updated to use non-reentrant workqueue.

Signed-off-by: default avatarTejun Heo <tj@kernel.org>
Acked-by: default avatarSteven Whitehouse <swhiteho@redhat.com>
parent 991ea75c
Loading
Loading
Loading
Loading
+0 −1
Original line number Original line Diff line number Diff line
@@ -7,7 +7,6 @@ config GFS2_FS
	select IP_SCTP if DLM_SCTP
	select IP_SCTP if DLM_SCTP
	select FS_POSIX_ACL
	select FS_POSIX_ACL
	select CRC32
	select CRC32
	select SLOW_WORK
	select QUOTACTL
	select QUOTACTL
	help
	help
	  A cluster filesystem.
	  A cluster filesystem.
+1 −2
Original line number Original line Diff line number Diff line
@@ -12,7 +12,6 @@


#include <linux/fs.h>
#include <linux/fs.h>
#include <linux/workqueue.h>
#include <linux/workqueue.h>
#include <linux/slow-work.h>
#include <linux/dlm.h>
#include <linux/dlm.h>
#include <linux/buffer_head.h>
#include <linux/buffer_head.h>


@@ -383,7 +382,7 @@ struct gfs2_journal_extent {
struct gfs2_jdesc {
struct gfs2_jdesc {
	struct list_head jd_list;
	struct list_head jd_list;
	struct list_head extent_list;
	struct list_head extent_list;
	struct slow_work jd_work;
	struct work_struct jd_work;
	struct inode *jd_inode;
	struct inode *jd_inode;
	unsigned long jd_flags;
	unsigned long jd_flags;
#define JDF_RECOVERY 1
#define JDF_RECOVERY 1
+8 −6
Original line number Original line Diff line number Diff line
@@ -15,7 +15,6 @@
#include <linux/init.h>
#include <linux/init.h>
#include <linux/gfs2_ondisk.h>
#include <linux/gfs2_ondisk.h>
#include <asm/atomic.h>
#include <asm/atomic.h>
#include <linux/slow-work.h>


#include "gfs2.h"
#include "gfs2.h"
#include "incore.h"
#include "incore.h"
@@ -24,6 +23,7 @@
#include "util.h"
#include "util.h"
#include "glock.h"
#include "glock.h"
#include "quota.h"
#include "quota.h"
#include "recovery.h"


static struct shrinker qd_shrinker = {
static struct shrinker qd_shrinker = {
	.shrink = gfs2_shrink_qd_memory,
	.shrink = gfs2_shrink_qd_memory,
@@ -138,9 +138,11 @@ static int __init init_gfs2_fs(void)
	if (error)
	if (error)
		goto fail_unregister;
		goto fail_unregister;


	error = slow_work_register_user(THIS_MODULE);
	error = -ENOMEM;
	if (error)
	gfs_recovery_wq = alloc_workqueue("gfs_recovery",
		goto fail_slow;
					  WQ_NON_REENTRANT | WQ_RESCUER, 0);
	if (!gfs_recovery_wq)
		goto fail_wq;


	gfs2_register_debugfs();
	gfs2_register_debugfs();


@@ -148,7 +150,7 @@ static int __init init_gfs2_fs(void)


	return 0;
	return 0;


fail_slow:
fail_wq:
	unregister_filesystem(&gfs2meta_fs_type);
	unregister_filesystem(&gfs2meta_fs_type);
fail_unregister:
fail_unregister:
	unregister_filesystem(&gfs2_fs_type);
	unregister_filesystem(&gfs2_fs_type);
@@ -190,7 +192,7 @@ static void __exit exit_gfs2_fs(void)
	gfs2_unregister_debugfs();
	gfs2_unregister_debugfs();
	unregister_filesystem(&gfs2_fs_type);
	unregister_filesystem(&gfs2_fs_type);
	unregister_filesystem(&gfs2meta_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_quotad_cachep);
	kmem_cache_destroy(gfs2_rgrpd_cachep);
	kmem_cache_destroy(gfs2_rgrpd_cachep);
+4 −4
Original line number Original line Diff line number Diff line
@@ -17,7 +17,6 @@
#include <linux/namei.h>
#include <linux/namei.h>
#include <linux/mount.h>
#include <linux/mount.h>
#include <linux/gfs2_ondisk.h>
#include <linux/gfs2_ondisk.h>
#include <linux/slow-work.h>
#include <linux/quotaops.h>
#include <linux/quotaops.h>


#include "gfs2.h"
#include "gfs2.h"
@@ -673,7 +672,7 @@ static int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh)
			break;
			break;


		INIT_LIST_HEAD(&jd->extent_list);
		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);
		jd->jd_inode = gfs2_lookupi(sdp->sd_jindex, &name, 1);
		if (!jd->jd_inode || IS_ERR(jd->jd_inode)) {
		if (!jd->jd_inode || IS_ERR(jd->jd_inode)) {
			if (!jd->jd_inode)
			if (!jd->jd_inode)
@@ -782,7 +781,8 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
	if (sdp->sd_lockstruct.ls_first) {
	if (sdp->sd_lockstruct.ls_first) {
		unsigned int x;
		unsigned int x;
		for (x = 0; x < sdp->sd_journals; 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) {
			if (error) {
				fs_err(sdp, "error recovering journal %u: %d\n",
				fs_err(sdp, "error recovering journal %u: %d\n",
				       x, error);
				       x, error);
@@ -792,7 +792,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)


		gfs2_others_may_mount(sdp);
		gfs2_others_may_mount(sdp);
	} else if (!sdp->sd_args.ar_spectator) {
	} else if (!sdp->sd_args.ar_spectator) {
		error = gfs2_recover_journal(sdp->sd_jdesc);
		error = gfs2_recover_journal(sdp->sd_jdesc, true);
		if (error) {
		if (error) {
			fs_err(sdp, "error recovering my journal: %d\n", error);
			fs_err(sdp, "error recovering my journal: %d\n", error);
			goto fail_jinode_gh;
			goto fail_jinode_gh;
+21 −33
Original line number Original line Diff line number Diff line
@@ -14,7 +14,6 @@
#include <linux/buffer_head.h>
#include <linux/buffer_head.h>
#include <linux/gfs2_ondisk.h>
#include <linux/gfs2_ondisk.h>
#include <linux/crc32.h>
#include <linux/crc32.h>
#include <linux/slow-work.h>


#include "gfs2.h"
#include "gfs2.h"
#include "incore.h"
#include "incore.h"
@@ -28,6 +27,8 @@
#include "util.h"
#include "util.h"
#include "dir.h"
#include "dir.h"


struct workqueue_struct *gfs_recovery_wq;

int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk,
int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk,
			   struct buffer_head **bh)
			   struct buffer_head **bh)
{
{
@@ -443,23 +444,7 @@ static void gfs2_recovery_done(struct gfs2_sbd *sdp, unsigned int jid,
        kobject_uevent_env(&sdp->sd_kobj, KOBJ_CHANGE, envp);
        kobject_uevent_env(&sdp->sd_kobj, KOBJ_CHANGE, envp);
}
}


static int gfs2_recover_get_ref(struct slow_work *work)
void gfs2_recover_func(struct work_struct *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)
{
{
	struct gfs2_jdesc *jd = container_of(work, struct gfs2_jdesc, jd_work);
	struct gfs2_jdesc *jd = container_of(work, struct gfs2_jdesc, jd_work);
	struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
	struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
@@ -578,7 +563,7 @@ static void gfs2_recover_work(struct slow_work *work)
		gfs2_glock_dq_uninit(&j_gh);
		gfs2_glock_dq_uninit(&j_gh);


	fs_info(sdp, "jid=%u: Done\n", jd->jd_jid);
	fs_info(sdp, "jid=%u: Done\n", jd->jd_jid);
	return;
	goto done;


fail_gunlock_tr:
fail_gunlock_tr:
	gfs2_glock_dq_uninit(&t_gh);
	gfs2_glock_dq_uninit(&t_gh);
@@ -590,32 +575,35 @@ static void gfs2_recover_work(struct slow_work *work)
	}
	}


	fs_info(sdp, "jid=%u: %s\n", jd->jd_jid, (error) ? "Failed" : "Done");
	fs_info(sdp, "jid=%u: %s\n", jd->jd_jid, (error) ? "Failed" : "Done");

fail:
fail:
	gfs2_recovery_done(sdp, jd->jd_jid, LM_RD_GAVEUP);
	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)
static int gfs2_recovery_wait(void *word)
{
{
	schedule();
	schedule();
	return 0;
	return 0;
}
}


int gfs2_recover_journal(struct gfs2_jdesc *jd)
int gfs2_recover_journal(struct gfs2_jdesc *jd, bool wait)
{
{
	int rv;
	int rv;
	rv = slow_work_enqueue(&jd->jd_work);

	if (rv)
	if (test_and_set_bit(JDF_RECOVERY, &jd->jd_flags))
		return rv;
		return -EBUSY;
	wait_on_bit(&jd->jd_flags, JDF_RECOVERY, gfs2_recovery_wait, TASK_UNINTERRUPTIBLE);

	/* 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;
	return 0;
}
}
Loading