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: Tejun Heo <tj@kernel.org> Acked-by: Steven Whitehouse <swhiteho@redhat.com>
This commit is contained in:
parent
991ea75cb1
commit
6ecd7c2dd9
|
@ -7,7 +7,6 @@ config GFS2_FS
|
|||
select IP_SCTP if DLM_SCTP
|
||||
select FS_POSIX_ACL
|
||||
select CRC32
|
||||
select SLOW_WORK
|
||||
select QUOTACTL
|
||||
help
|
||||
A cluster filesystem.
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/slow-work.h>
|
||||
#include <linux/dlm.h>
|
||||
#include <linux/buffer_head.h>
|
||||
|
||||
|
@ -383,7 +382,7 @@ struct gfs2_journal_extent {
|
|||
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
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/gfs2_ondisk.h>
|
||||
#include <asm/atomic.h>
|
||||
#include <linux/slow-work.h>
|
||||
|
||||
#include "gfs2.h"
|
||||
#include "incore.h"
|
||||
|
@ -24,6 +23,7 @@
|
|||
#include "util.h"
|
||||
#include "glock.h"
|
||||
#include "quota.h"
|
||||
#include "recovery.h"
|
||||
|
||||
static struct shrinker qd_shrinker = {
|
||||
.shrink = gfs2_shrink_qd_memory,
|
||||
|
@ -138,9 +138,11 @@ static int __init init_gfs2_fs(void)
|
|||
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();
|
||||
|
||||
|
@ -148,7 +150,7 @@ static int __init init_gfs2_fs(void)
|
|||
|
||||
return 0;
|
||||
|
||||
fail_slow:
|
||||
fail_wq:
|
||||
unregister_filesystem(&gfs2meta_fs_type);
|
||||
fail_unregister:
|
||||
unregister_filesystem(&gfs2_fs_type);
|
||||
|
@ -190,7 +192,7 @@ static void __exit exit_gfs2_fs(void)
|
|||
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);
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#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"
|
||||
|
@ -673,7 +672,7 @@ static int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh)
|
|||
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)
|
||||
|
@ -782,7 +781,8 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
|
|||
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);
|
||||
|
@ -792,7 +792,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
|
|||
|
||||
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;
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#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"
|
||||
|
@ -28,6 +27,8 @@
|
|||
#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)
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -578,7 +563,7 @@ static void gfs2_recover_work(struct slow_work *work)
|
|||
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);
|
||||
|
@ -590,32 +575,35 @@ fail_gunlock_j:
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
|
||||
#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)
|
||||
|
@ -27,8 +29,8 @@ extern void gfs2_revoke_clean(struct gfs2_sbd *sdp);
|
|||
|
||||
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__ */
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "quota.h"
|
||||
#include "util.h"
|
||||
#include "glops.h"
|
||||
#include "recovery.h"
|
||||
|
||||
struct gfs2_attr {
|
||||
struct attribute attr;
|
||||
|
@ -352,7 +353,7 @@ static ssize_t recover_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
|
|||
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:
|
||||
|
|
Loading…
Reference in New Issue