include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[safe/jmp/linux-2.6] / fs / nilfs2 / segment.c
index 105b508..6a7dbd8 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/kthread.h>
 #include <linux/crc32.h>
 #include <linux/pagevec.h>
+#include <linux/slab.h>
 #include "nilfs.h"
 #include "btnode.h"
 #include "page.h"
@@ -141,7 +142,7 @@ int nilfs_init_transaction_cache(void)
 }
 
 /**
- * nilfs_detroy_transaction_cache - destroy the cache for transaction info
+ * nilfs_destroy_transaction_cache - destroy the cache for transaction info
  *
  * nilfs_destroy_transaction_cache() frees the slab cache for the struct
  * nilfs_transaction_info.
@@ -201,7 +202,7 @@ static int nilfs_prepare_segment_lock(struct nilfs_transaction_info *ti)
  * This function allocates a nilfs_transaction_info struct to keep context
  * information on it.  It is initialized and hooked onto the current task in
  * the outermost call.  If a pre-allocated struct is given to @ti, it is used
- * instead; othewise a new struct is assigned from a slab.
+ * instead; otherwise a new struct is assigned from a slab.
  *
  * When @vacancy_check flag is set, this function will check the amount of
  * free space, and will wait for the GC to reclaim disk space if low capacity.
@@ -1510,6 +1511,12 @@ static int nilfs_segctor_collect(struct nilfs_sc_info *sci,
                if (mode != SC_LSEG_SR || sci->sc_stage.scnt < NILFS_ST_CPFILE)
                        break;
 
+               nilfs_clear_logs(&sci->sc_segbufs);
+
+               err = nilfs_segctor_extend_segments(sci, nilfs, nadd);
+               if (unlikely(err))
+                       return err;
+
                if (sci->sc_stage.flags & NILFS_CF_SUFREED) {
                        err = nilfs_sufile_cancel_freev(nilfs->ns_sufile,
                                                        sci->sc_freesegs,
@@ -1517,12 +1524,6 @@ static int nilfs_segctor_collect(struct nilfs_sc_info *sci,
                                                        NULL);
                        WARN_ON(err); /* do not happen */
                }
-               nilfs_clear_logs(&sci->sc_segbufs);
-
-               err = nilfs_segctor_extend_segments(sci, nilfs, nadd);
-               if (unlikely(err))
-                       return err;
-
                nadd = min_t(int, nadd << 1, SC_MAX_SEGDELTA);
                sci->sc_stage = prev_stage;
        }
@@ -1764,14 +1765,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;
 }
@@ -1902,8 +1898,7 @@ static void nilfs_segctor_abort_construction(struct nilfs_sc_info *sci,
 
        list_splice_tail_init(&sci->sc_write_logs, &logs);
        ret = nilfs_wait_on_logs(&logs);
-       if (ret)
-               nilfs_abort_logs(&logs, NULL, sci->sc_super_root, ret);
+       nilfs_abort_logs(&logs, NULL, sci->sc_super_root, ret ? : err);
 
        list_splice_tail_init(&sci->sc_segbufs, &logs);
        nilfs_cancel_segusage(&logs, nilfs->ns_sufile);
@@ -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);
@@ -2220,7 +2214,7 @@ static int nilfs_segctor_do_construct(struct nilfs_sc_info *sci, int mode)
 }
 
 /**
- * nilfs_secgtor_start_timer - set timer of background write
+ * nilfs_segctor_start_timer - set timer of background write
  * @sci: nilfs_sc_info
  *
  * If the timer has already been set, it ignores the new request.
@@ -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);
@@ -2853,7 +2854,7 @@ static void nilfs_segctor_destroy(struct nilfs_sc_info *sci)
  * @sbi: nilfs_sb_info
  *
  * nilfs_attach_segment_constructor() allocates a struct nilfs_sc_info,
- * initilizes it, and starts the segment constructor.
+ * initializes it, and starts the segment constructor.
  *
  * Return Value: On success, 0 is returned. On error, one of the following
  * negative error code is returned.
@@ -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;