|
@@ -1764,14 +1764,9 @@ static int nilfs_segctor_prepare_write(struct nilfs_sc_info *sci,
|
|
|
static int nilfs_segctor_write(struct nilfs_sc_info *sci,
|
|
|
struct the_nilfs *nilfs)
|
|
|
{
|
|
|
- struct nilfs_segment_buffer *segbuf;
|
|
|
- int ret = 0;
|
|
|
+ int ret;
|
|
|
|
|
|
- list_for_each_entry(segbuf, &sci->sc_segbufs, sb_list) {
|
|
|
- ret = nilfs_segbuf_write(segbuf, nilfs);
|
|
|
- if (ret)
|
|
|
- break;
|
|
|
- }
|
|
|
+ ret = nilfs_write_logs(&sci->sc_segbufs, nilfs);
|
|
|
list_splice_tail_init(&sci->sc_segbufs, &sci->sc_write_logs);
|
|
|
return ret;
|
|
|
}
|
|
@@ -1937,8 +1932,7 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci)
|
|
|
{
|
|
|
struct nilfs_segment_buffer *segbuf;
|
|
|
struct page *bd_page = NULL, *fs_page = NULL;
|
|
|
- struct nilfs_sb_info *sbi = sci->sc_sbi;
|
|
|
- struct the_nilfs *nilfs = sbi->s_nilfs;
|
|
|
+ struct the_nilfs *nilfs = sci->sc_sbi->s_nilfs;
|
|
|
int update_sr = (sci->sc_super_root != NULL);
|
|
|
|
|
|
list_for_each_entry(segbuf, &sci->sc_write_logs, sb_list) {
|
|
@@ -2020,7 +2014,7 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci)
|
|
|
if (update_sr) {
|
|
|
nilfs_set_last_segment(nilfs, segbuf->sb_pseg_start,
|
|
|
segbuf->sb_sum.seg_seq, nilfs->ns_cno++);
|
|
|
- sbi->s_super->s_dirt = 1;
|
|
|
+ set_nilfs_sb_dirty(nilfs);
|
|
|
|
|
|
clear_bit(NILFS_SC_HAVE_DELTA, &sci->sc_flags);
|
|
|
clear_bit(NILFS_SC_DIRTY, &sci->sc_flags);
|
|
@@ -2425,43 +2419,43 @@ int nilfs_construct_dsync_segment(struct super_block *sb, struct inode *inode,
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
-struct nilfs_segctor_req {
|
|
|
- int mode;
|
|
|
- __u32 seq_accepted;
|
|
|
- int sc_err; /* construction failure */
|
|
|
- int sb_err; /* super block writeback failure */
|
|
|
-};
|
|
|
-
|
|
|
#define FLUSH_FILE_BIT (0x1) /* data file only */
|
|
|
#define FLUSH_DAT_BIT (1 << NILFS_DAT_INO) /* DAT only */
|
|
|
|
|
|
-static void nilfs_segctor_accept(struct nilfs_sc_info *sci,
|
|
|
- struct nilfs_segctor_req *req)
|
|
|
+/**
|
|
|
+ * nilfs_segctor_accept - record accepted sequence count of log-write requests
|
|
|
+ * @sci: segment constructor object
|
|
|
+ */
|
|
|
+static void nilfs_segctor_accept(struct nilfs_sc_info *sci)
|
|
|
{
|
|
|
- req->sc_err = req->sb_err = 0;
|
|
|
spin_lock(&sci->sc_state_lock);
|
|
|
- req->seq_accepted = sci->sc_seq_request;
|
|
|
+ sci->sc_seq_accepted = sci->sc_seq_request;
|
|
|
spin_unlock(&sci->sc_state_lock);
|
|
|
|
|
|
if (sci->sc_timer)
|
|
|
del_timer_sync(sci->sc_timer);
|
|
|
}
|
|
|
|
|
|
-static void nilfs_segctor_notify(struct nilfs_sc_info *sci,
|
|
|
- struct nilfs_segctor_req *req)
|
|
|
+/**
|
|
|
+ * nilfs_segctor_notify - notify the result of request to caller threads
|
|
|
+ * @sci: segment constructor object
|
|
|
+ * @mode: mode of log forming
|
|
|
+ * @err: error code to be notified
|
|
|
+ */
|
|
|
+static void nilfs_segctor_notify(struct nilfs_sc_info *sci, int mode, int err)
|
|
|
{
|
|
|
/* Clear requests (even when the construction failed) */
|
|
|
spin_lock(&sci->sc_state_lock);
|
|
|
|
|
|
- if (req->mode == SC_LSEG_SR) {
|
|
|
+ if (mode == SC_LSEG_SR) {
|
|
|
sci->sc_state &= ~NILFS_SEGCTOR_COMMIT;
|
|
|
- sci->sc_seq_done = req->seq_accepted;
|
|
|
- nilfs_segctor_wakeup(sci, req->sc_err ? : req->sb_err);
|
|
|
+ sci->sc_seq_done = sci->sc_seq_accepted;
|
|
|
+ nilfs_segctor_wakeup(sci, err);
|
|
|
sci->sc_flush_request = 0;
|
|
|
} else {
|
|
|
- if (req->mode == SC_FLUSH_FILE)
|
|
|
+ if (mode == SC_FLUSH_FILE)
|
|
|
sci->sc_flush_request &= ~FLUSH_FILE_BIT;
|
|
|
- else if (req->mode == SC_FLUSH_DAT)
|
|
|
+ else if (mode == SC_FLUSH_DAT)
|
|
|
sci->sc_flush_request &= ~FLUSH_DAT_BIT;
|
|
|
|
|
|
/* re-enable timer if checkpoint creation was not done */
|
|
@@ -2472,30 +2466,37 @@ static void nilfs_segctor_notify(struct nilfs_sc_info *sci,
|
|
|
spin_unlock(&sci->sc_state_lock);
|
|
|
}
|
|
|
|
|
|
-static int nilfs_segctor_construct(struct nilfs_sc_info *sci,
|
|
|
- struct nilfs_segctor_req *req)
|
|
|
+/**
|
|
|
+ * nilfs_segctor_construct - form logs and write them to disk
|
|
|
+ * @sci: segment constructor object
|
|
|
+ * @mode: mode of log forming
|
|
|
+ */
|
|
|
+static int nilfs_segctor_construct(struct nilfs_sc_info *sci, int mode)
|
|
|
{
|
|
|
struct nilfs_sb_info *sbi = sci->sc_sbi;
|
|
|
struct the_nilfs *nilfs = sbi->s_nilfs;
|
|
|
int err = 0;
|
|
|
|
|
|
+ nilfs_segctor_accept(sci);
|
|
|
+
|
|
|
if (nilfs_discontinued(nilfs))
|
|
|
- req->mode = SC_LSEG_SR;
|
|
|
- if (!nilfs_segctor_confirm(sci)) {
|
|
|
- err = nilfs_segctor_do_construct(sci, req->mode);
|
|
|
- req->sc_err = err;
|
|
|
- }
|
|
|
+ mode = SC_LSEG_SR;
|
|
|
+ if (!nilfs_segctor_confirm(sci))
|
|
|
+ err = nilfs_segctor_do_construct(sci, mode);
|
|
|
+
|
|
|
if (likely(!err)) {
|
|
|
- if (req->mode != SC_FLUSH_DAT)
|
|
|
+ if (mode != SC_FLUSH_DAT)
|
|
|
atomic_set(&nilfs->ns_ndirtyblks, 0);
|
|
|
if (test_bit(NILFS_SC_SUPER_ROOT, &sci->sc_flags) &&
|
|
|
nilfs_discontinued(nilfs)) {
|
|
|
down_write(&nilfs->ns_sem);
|
|
|
- req->sb_err = nilfs_commit_super(sbi,
|
|
|
- nilfs_altsb_need_update(nilfs));
|
|
|
+ err = nilfs_commit_super(
|
|
|
+ sbi, nilfs_altsb_need_update(nilfs));
|
|
|
up_write(&nilfs->ns_sem);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ nilfs_segctor_notify(sci, mode, err);
|
|
|
return err;
|
|
|
}
|
|
|
|
|
@@ -2526,7 +2527,6 @@ int nilfs_clean_segments(struct super_block *sb, struct nilfs_argv *argv,
|
|
|
struct nilfs_sc_info *sci = NILFS_SC(sbi);
|
|
|
struct the_nilfs *nilfs = sbi->s_nilfs;
|
|
|
struct nilfs_transaction_info ti;
|
|
|
- struct nilfs_segctor_req req = { .mode = SC_LSEG_SR };
|
|
|
int err;
|
|
|
|
|
|
if (unlikely(!sci))
|
|
@@ -2547,10 +2547,8 @@ int nilfs_clean_segments(struct super_block *sb, struct nilfs_argv *argv,
|
|
|
list_splice_tail_init(&nilfs->ns_gc_inodes, &sci->sc_gc_inodes);
|
|
|
|
|
|
for (;;) {
|
|
|
- nilfs_segctor_accept(sci, &req);
|
|
|
- err = nilfs_segctor_construct(sci, &req);
|
|
|
+ err = nilfs_segctor_construct(sci, SC_LSEG_SR);
|
|
|
nilfs_remove_written_gcinodes(nilfs, &sci->sc_gc_inodes);
|
|
|
- nilfs_segctor_notify(sci, &req);
|
|
|
|
|
|
if (likely(!err))
|
|
|
break;
|
|
@@ -2560,6 +2558,16 @@ int nilfs_clean_segments(struct super_block *sb, struct nilfs_argv *argv,
|
|
|
set_current_state(TASK_INTERRUPTIBLE);
|
|
|
schedule_timeout(sci->sc_interval);
|
|
|
}
|
|
|
+ if (nilfs_test_opt(sbi, DISCARD)) {
|
|
|
+ int ret = nilfs_discard_segments(nilfs, sci->sc_freesegs,
|
|
|
+ sci->sc_nfreesegs);
|
|
|
+ if (ret) {
|
|
|
+ printk(KERN_WARNING
|
|
|
+ "NILFS warning: error %d on discard request, "
|
|
|
+ "turning discards off for the device\n", ret);
|
|
|
+ nilfs_clear_opt(sbi, DISCARD);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
out_unlock:
|
|
|
sci->sc_freesegs = NULL;
|
|
@@ -2573,13 +2581,9 @@ static void nilfs_segctor_thread_construct(struct nilfs_sc_info *sci, int mode)
|
|
|
{
|
|
|
struct nilfs_sb_info *sbi = sci->sc_sbi;
|
|
|
struct nilfs_transaction_info ti;
|
|
|
- struct nilfs_segctor_req req = { .mode = mode };
|
|
|
|
|
|
nilfs_transaction_lock(sbi, &ti, 0);
|
|
|
-
|
|
|
- nilfs_segctor_accept(sci, &req);
|
|
|
- nilfs_segctor_construct(sci, &req);
|
|
|
- nilfs_segctor_notify(sci, &req);
|
|
|
+ nilfs_segctor_construct(sci, mode);
|
|
|
|
|
|
/*
|
|
|
* Unclosed segment should be retried. We do this using sc_timer.
|
|
@@ -2635,6 +2639,7 @@ static int nilfs_segctor_flush_mode(struct nilfs_sc_info *sci)
|
|
|
static int nilfs_segctor_thread(void *arg)
|
|
|
{
|
|
|
struct nilfs_sc_info *sci = (struct nilfs_sc_info *)arg;
|
|
|
+ struct the_nilfs *nilfs = sci->sc_sbi->s_nilfs;
|
|
|
struct timer_list timer;
|
|
|
int timeout = 0;
|
|
|
|
|
@@ -2680,7 +2685,6 @@ static int nilfs_segctor_thread(void *arg)
|
|
|
} else {
|
|
|
DEFINE_WAIT(wait);
|
|
|
int should_sleep = 1;
|
|
|
- struct the_nilfs *nilfs;
|
|
|
|
|
|
prepare_to_wait(&sci->sc_wait_daemon, &wait,
|
|
|
TASK_INTERRUPTIBLE);
|
|
@@ -2701,8 +2705,8 @@ static int nilfs_segctor_thread(void *arg)
|
|
|
finish_wait(&sci->sc_wait_daemon, &wait);
|
|
|
timeout = ((sci->sc_state & NILFS_SEGCTOR_COMMIT) &&
|
|
|
time_after_eq(jiffies, sci->sc_timer->expires));
|
|
|
- nilfs = sci->sc_sbi->s_nilfs;
|
|
|
- if (sci->sc_super->s_dirt && nilfs_sb_need_update(nilfs))
|
|
|
+
|
|
|
+ if (nilfs_sb_dirty(nilfs) && nilfs_sb_need_update(nilfs))
|
|
|
set_nilfs_discontinued(nilfs);
|
|
|
}
|
|
|
goto loop;
|
|
@@ -2797,12 +2801,9 @@ static void nilfs_segctor_write_out(struct nilfs_sc_info *sci)
|
|
|
do {
|
|
|
struct nilfs_sb_info *sbi = sci->sc_sbi;
|
|
|
struct nilfs_transaction_info ti;
|
|
|
- struct nilfs_segctor_req req = { .mode = SC_LSEG_SR };
|
|
|
|
|
|
nilfs_transaction_lock(sbi, &ti, 0);
|
|
|
- nilfs_segctor_accept(sci, &req);
|
|
|
- ret = nilfs_segctor_construct(sci, &req);
|
|
|
- nilfs_segctor_notify(sci, &req);
|
|
|
+ ret = nilfs_segctor_construct(sci, SC_LSEG_SR);
|
|
|
nilfs_transaction_unlock(sbi);
|
|
|
|
|
|
} while (ret && retrycount-- > 0);
|
|
@@ -2865,8 +2866,15 @@ int nilfs_attach_segment_constructor(struct nilfs_sb_info *sbi)
|
|
|
struct the_nilfs *nilfs = sbi->s_nilfs;
|
|
|
int err;
|
|
|
|
|
|
- /* Each field of nilfs_segctor is cleared through the initialization
|
|
|
- of super-block info */
|
|
|
+ if (NILFS_SC(sbi)) {
|
|
|
+ /*
|
|
|
+ * This happens if the filesystem was remounted
|
|
|
+ * read/write after nilfs_error degenerated it into a
|
|
|
+ * read-only mount.
|
|
|
+ */
|
|
|
+ nilfs_detach_segment_constructor(sbi);
|
|
|
+ }
|
|
|
+
|
|
|
sbi->s_sc_info = nilfs_segctor_new(sbi);
|
|
|
if (!sbi->s_sc_info)
|
|
|
return -ENOMEM;
|