diff --git a/kmod/src/super.c b/kmod/src/super.c index e22a0420..63e82259 100644 --- a/kmod/src/super.c +++ b/kmod/src/super.c @@ -569,12 +569,8 @@ static int scoutfs_fill_super(struct super_block *sb, void *data, int silent) return ret; spin_lock_init(&sbi->next_ino_lock); - init_waitqueue_head(&sbi->trans_hold_wq); spin_lock_init(&sbi->data_wait_root.lock); sbi->data_wait_root.root = RB_ROOT; - spin_lock_init(&sbi->trans_write_lock); - INIT_DELAYED_WORK(&sbi->trans_write_work, scoutfs_trans_write_func); - init_waitqueue_head(&sbi->trans_write_wq); scoutfs_sysfs_init_attrs(sb, &sbi->mopts_ssa); ret = scoutfs_parse_options(sb, data, &opts); diff --git a/kmod/src/super.h b/kmod/src/super.h index 32fba8d6..4ca4b88f 100644 --- a/kmod/src/super.h +++ b/kmod/src/super.h @@ -57,20 +57,11 @@ struct scoutfs_sb_info { struct item_cache_info *item_cache_info; struct fence_info *fence_info; - wait_queue_head_t trans_hold_wq; - struct task_struct *trans_task; - /* tracks tasks waiting for data extents */ struct scoutfs_data_wait_root data_wait_root; - spinlock_t trans_write_lock; - u64 trans_write_count; + /* set as transaction opens with trans holders excluded */ u64 trans_seq; - int trans_write_ret; - struct delayed_work trans_write_work; - wait_queue_head_t trans_write_wq; - struct workqueue_struct *trans_write_workq; - bool trans_deadline_expired; struct trans_info *trans_info; struct lock_info *lock_info; diff --git a/kmod/src/trans.c b/kmod/src/trans.c index 1c17c631..f5980778 100644 --- a/kmod/src/trans.c +++ b/kmod/src/trans.c @@ -53,15 +53,24 @@ /* sync dirty data at least this often */ #define TRANS_SYNC_DELAY (HZ * 10) -/* - * XXX move the rest of the super trans_ fields here. - */ struct trans_info { + struct super_block *sb; + atomic_t holders; struct scoutfs_log_trees lt; struct scoutfs_alloc alloc; struct scoutfs_block_writer wri; + + wait_queue_head_t hold_wq; + struct task_struct *task; + spinlock_t write_lock; + u64 write_count; + int write_ret; + struct delayed_work write_work; + wait_queue_head_t write_wq; + struct workqueue_struct *write_workq; + bool deadline_expired; }; #define DECLARE_TRANS_INFO(sb, name) \ @@ -120,13 +129,12 @@ bool scoutfs_trans_has_dirty(struct super_block *sb) */ static void sub_holders_and_wake(struct super_block *sb, int val) { - struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb); DECLARE_TRANS_INFO(sb, tri); atomic_sub(val, &tri->holders); smp_mb(); /* make sure sub is visible before we wake */ - if (waitqueue_active(&sbi->trans_hold_wq)) - wake_up(&sbi->trans_hold_wq); + if (waitqueue_active(&tri->hold_wq)) + wake_up(&tri->hold_wq); } /* @@ -170,20 +178,19 @@ static bool drained_holders(struct trans_info *tri) */ void scoutfs_trans_write_func(struct work_struct *work) { - struct scoutfs_sb_info *sbi = container_of(work, struct scoutfs_sb_info, - trans_write_work.work); - struct super_block *sb = sbi->sb; - DECLARE_TRANS_INFO(sb, tri); + struct trans_info *tri = container_of(work, struct trans_info, write_work.work); + struct super_block *sb = tri->sb; + struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb); u64 trans_seq = sbi->trans_seq; char *s = NULL; int ret = 0; - sbi->trans_task = current; + tri->task = current; /* mark that we're writing so holders wait for us to finish and clear our bit */ atomic_add(TRANS_HOLDERS_WRITE_FUNC_BIT, &tri->holders); - wait_event(sbi->trans_hold_wq, drained_holders(tri)); + wait_event(tri->hold_wq, drained_holders(tri)); if (scoutfs_forcing_unmount(sb)) { ret = -EIO; @@ -193,7 +200,7 @@ void scoutfs_trans_write_func(struct work_struct *work) trace_scoutfs_trans_write_func(sb, scoutfs_block_writer_dirty_bytes(sb, &tri->wri), scoutfs_item_dirty_pages(sb)); - if (sbi->trans_deadline_expired) + if (tri->deadline_expired) scoutfs_inc_counter(sb, trans_commit_timer); scoutfs_inc_counter(sb, trans_commit_written); @@ -213,17 +220,17 @@ void scoutfs_trans_write_func(struct work_struct *work) s, ret); out: - spin_lock(&sbi->trans_write_lock); - sbi->trans_write_count++; - sbi->trans_write_ret = ret; + spin_lock(&tri->write_lock); + tri->write_count++; + tri->write_ret = ret; sbi->trans_seq = trans_seq; - spin_unlock(&sbi->trans_write_lock); - wake_up(&sbi->trans_write_wq); + spin_unlock(&tri->write_lock); + wake_up(&tri->write_wq); /* we're done, wake waiting holders */ sub_holders_and_wake(sb, TRANS_HOLDERS_WRITE_FUNC_BIT); - sbi->trans_task = NULL; + tri->task = NULL; scoutfs_trans_restart_sync_deadline(sb); } @@ -234,17 +241,17 @@ struct write_attempt { }; /* this is called as a wait_event() condition so it can't change task state */ -static int write_attempted(struct scoutfs_sb_info *sbi, - struct write_attempt *attempt) +static int write_attempted(struct super_block *sb, struct write_attempt *attempt) { + DECLARE_TRANS_INFO(sb, tri); int done = 1; - spin_lock(&sbi->trans_write_lock); - if (sbi->trans_write_count > attempt->count) - attempt->ret = sbi->trans_write_ret; + spin_lock(&tri->write_lock); + if (tri->write_count > attempt->count) + attempt->ret = tri->write_ret; else done = 0; - spin_unlock(&sbi->trans_write_lock); + spin_unlock(&tri->write_lock); return done; } @@ -254,10 +261,12 @@ static int write_attempted(struct scoutfs_sb_info *sbi, * We always have delayed sync work pending but the caller wants it * to execute immediately. */ -static void queue_trans_work(struct scoutfs_sb_info *sbi) +static void queue_trans_work(struct super_block *sb) { - sbi->trans_deadline_expired = false; - mod_delayed_work(sbi->trans_write_workq, &sbi->trans_write_work, 0); + DECLARE_TRANS_INFO(sb, tri); + + tri->deadline_expired = false; + mod_delayed_work(tri->write_workq, &tri->write_work, 0); } /* @@ -270,23 +279,23 @@ static void queue_trans_work(struct scoutfs_sb_info *sbi) */ int scoutfs_trans_sync(struct super_block *sb, int wait) { - struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb); + DECLARE_TRANS_INFO(sb, tri); struct write_attempt attempt = { .ret = 0 }; int ret; if (!wait) { - queue_trans_work(sbi); + queue_trans_work(sb); return 0; } - spin_lock(&sbi->trans_write_lock); - attempt.count = sbi->trans_write_count; - spin_unlock(&sbi->trans_write_lock); + spin_lock(&tri->write_lock); + attempt.count = tri->write_count; + spin_unlock(&tri->write_lock); - queue_trans_work(sbi); + queue_trans_work(sb); - wait_event(sbi->trans_write_wq, write_attempted(sbi, &attempt)); + wait_event(tri->write_wq, write_attempted(sb, &attempt)); ret = attempt.ret; return ret; @@ -303,10 +312,10 @@ int scoutfs_file_fsync(struct file *file, loff_t start, loff_t end, void scoutfs_trans_restart_sync_deadline(struct super_block *sb) { - struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb); + DECLARE_TRANS_INFO(sb, tri); - sbi->trans_deadline_expired = true; - mod_delayed_work(sbi->trans_write_workq, &sbi->trans_write_work, + tri->deadline_expired = true; + mod_delayed_work(tri->write_workq, &tri->write_work, TRANS_SYNC_DELAY); } @@ -455,12 +464,11 @@ static bool holders_no_writer(struct trans_info *tri) */ int scoutfs_hold_trans(struct super_block *sb, bool allocing) { - struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb); DECLARE_TRANS_INFO(sb, tri); u64 seq; int ret; - if (current == sbi->trans_task) + if (current == tri->task) return 0; for (;;) { @@ -474,7 +482,7 @@ int scoutfs_hold_trans(struct super_block *sb, bool allocing) /* wait until the writer work is finished */ if (!inc_holders_unless_writer(tri)) { dec_journal_info_holders(); - wait_event(sbi->trans_hold_wq, holders_no_writer(tri)); + wait_event(tri->hold_wq, holders_no_writer(tri)); continue; } @@ -489,8 +497,8 @@ int scoutfs_hold_trans(struct super_block *sb, bool allocing) if (commit_before_hold(sb, tri)) { seq = scoutfs_trans_sample_seq(sb); release_holders(sb); - queue_trans_work(sbi); - wait_event(sbi->trans_hold_wq, scoutfs_trans_sample_seq(sb) != seq); + queue_trans_work(sb); + wait_event(tri->hold_wq, scoutfs_trans_sample_seq(sb) != seq); continue; } @@ -516,10 +524,9 @@ bool scoutfs_trans_held(void) void scoutfs_release_trans(struct super_block *sb) { - struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb); DECLARE_TRANS_INFO(sb, tri); - if (current == sbi->trans_task) + if (current == tri->task) return; release_holders(sb); @@ -534,12 +541,13 @@ void scoutfs_release_trans(struct super_block *sb) */ u64 scoutfs_trans_sample_seq(struct super_block *sb) { + DECLARE_TRANS_INFO(sb, tri); struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb); u64 ret; - spin_lock(&sbi->trans_write_lock); + spin_lock(&tri->write_lock); ret = sbi->trans_seq; - spin_unlock(&sbi->trans_write_lock); + spin_unlock(&tri->write_lock); return ret; } @@ -553,12 +561,17 @@ int scoutfs_setup_trans(struct super_block *sb) if (!tri) return -ENOMEM; + tri->sb = sb; atomic_set(&tri->holders, 0); scoutfs_block_writer_init(sb, &tri->wri); - sbi->trans_write_workq = alloc_workqueue("scoutfs_trans", - WQ_UNBOUND, 1); - if (!sbi->trans_write_workq) { + spin_lock_init(&tri->write_lock); + INIT_DELAYED_WORK(&tri->write_work, scoutfs_trans_write_func); + init_waitqueue_head(&tri->write_wq); + init_waitqueue_head(&tri->hold_wq); + + tri->write_workq = alloc_workqueue("scoutfs_trans", WQ_UNBOUND, 1); + if (!tri->write_workq) { kfree(tri); return -ENOMEM; } @@ -585,14 +598,14 @@ void scoutfs_shutdown_trans(struct super_block *sb) DECLARE_TRANS_INFO(sb, tri); if (tri) { - if (sbi->trans_write_workq) { + if (tri->write_workq) { /* immediately queues pending timer */ - flush_delayed_work(&sbi->trans_write_work); + flush_delayed_work(&tri->write_work); /* prevents re-arming if it has to wait */ - cancel_delayed_work_sync(&sbi->trans_write_work); - destroy_workqueue(sbi->trans_write_workq); + cancel_delayed_work_sync(&tri->write_work); + destroy_workqueue(tri->write_workq); /* trans work schedules after shutdown see null */ - sbi->trans_write_workq = NULL; + tri->write_workq = NULL; } scoutfs_block_writer_forget_all(sb, &tri->wri);