]> Pileus Git - ~andy/linux/blobdiff - fs/jffs2/wbuf.c
jffs2: get rid of jffs2_sync_super
[~andy/linux] / fs / jffs2 / wbuf.c
index 30e8f47e8a233f32ad7eaab70dfbf1291bcf409b..6f4529d3697fd3f97d5b018dbe9f5c0362cee034 100644 (file)
@@ -11,6 +11,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/mtd/mtd.h>
@@ -18,6 +20,7 @@
 #include <linux/mtd/nand.h>
 #include <linux/jiffies.h>
 #include <linux/sched.h>
+#include <linux/writeback.h>
 
 #include "nodelist.h"
 
@@ -83,7 +86,7 @@ static void jffs2_wbuf_dirties_inode(struct jffs2_sb_info *c, uint32_t ino)
 {
        struct jffs2_inodirty *new;
 
-       /* Mark the superblock dirty so that kupdated will flush... */
+       /* Schedule delayed write-buffer write-out */
        jffs2_dirty_trigger(c);
 
        if (jffs2_wbuf_pending_for_ino(c, ino))
@@ -91,7 +94,7 @@ static void jffs2_wbuf_dirties_inode(struct jffs2_sb_info *c, uint32_t ino)
 
        new = kmalloc(sizeof(*new), GFP_KERNEL);
        if (!new) {
-               D1(printk(KERN_DEBUG "No memory to allocate inodirty. Fallback to all considered dirty\n"));
+               jffs2_dbg(1, "No memory to allocate inodirty. Fallback to all considered dirty\n");
                jffs2_clear_wbuf_ino_list(c);
                c->wbuf_inodes = &inodirty_nomem;
                return;
@@ -113,19 +116,20 @@ static inline void jffs2_refile_wbuf_blocks(struct jffs2_sb_info *c)
        list_for_each_safe(this, next, &c->erasable_pending_wbuf_list) {
                struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
 
-               D1(printk(KERN_DEBUG "Removing eraseblock at 0x%08x from erasable_pending_wbuf_list...\n", jeb->offset));
+               jffs2_dbg(1, "Removing eraseblock at 0x%08x from erasable_pending_wbuf_list...\n",
+                         jeb->offset);
                list_del(this);
                if ((jiffies + (n++)) & 127) {
                        /* Most of the time, we just erase it immediately. Otherwise we
                           spend ages scanning it on mount, etc. */
-                       D1(printk(KERN_DEBUG "...and adding to erase_pending_list\n"));
+                       jffs2_dbg(1, "...and adding to erase_pending_list\n");
                        list_add_tail(&jeb->list, &c->erase_pending_list);
                        c->nr_erasing_blocks++;
                        jffs2_garbage_collect_trigger(c);
                } else {
                        /* Sometimes, however, we leave it elsewhere so it doesn't get
                           immediately reused, and we spread the load a bit. */
-                       D1(printk(KERN_DEBUG "...and adding to erasable_list\n"));
+                       jffs2_dbg(1, "...and adding to erasable_list\n");
                        list_add_tail(&jeb->list, &c->erasable_list);
                }
        }
@@ -136,7 +140,7 @@ static inline void jffs2_refile_wbuf_blocks(struct jffs2_sb_info *c)
 
 static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, int allow_empty)
 {
-       D1(printk("About to refile bad block at %08x\n", jeb->offset));
+       jffs2_dbg(1, "About to refile bad block at %08x\n", jeb->offset);
 
        /* File the existing block on the bad_used_list.... */
        if (c->nextblock == jeb)
@@ -144,12 +148,14 @@ static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock
        else /* Not sure this should ever happen... need more coffee */
                list_del(&jeb->list);
        if (jeb->first_node) {
-               D1(printk("Refiling block at %08x to bad_used_list\n", jeb->offset));
+               jffs2_dbg(1, "Refiling block at %08x to bad_used_list\n",
+                         jeb->offset);
                list_add(&jeb->list, &c->bad_used_list);
        } else {
                BUG_ON(allow_empty == REFILE_NOTEMPTY);
                /* It has to have had some nodes or we couldn't be here */
-               D1(printk("Refiling block at %08x to erase_pending_list\n", jeb->offset));
+               jffs2_dbg(1, "Refiling block at %08x to erase_pending_list\n",
+                         jeb->offset);
                list_add(&jeb->list, &c->erase_pending_list);
                c->nr_erasing_blocks++;
                jffs2_garbage_collect_trigger(c);
@@ -230,10 +236,12 @@ static int jffs2_verify_write(struct jffs2_sb_info *c, unsigned char *buf,
 
        ret = mtd_read(c->mtd, ofs, c->wbuf_pagesize, &retlen, c->wbuf_verify);
        if (ret && ret != -EUCLEAN && ret != -EBADMSG) {
-               printk(KERN_WARNING "jffs2_verify_write(): Read back of page at %08x failed: %d\n", c->wbuf_ofs, ret);
+               pr_warn("%s(): Read back of page at %08x failed: %d\n",
+                       __func__, c->wbuf_ofs, ret);
                return ret;
        } else if (retlen != c->wbuf_pagesize) {
-               printk(KERN_WARNING "jffs2_verify_write(): Read back of page at %08x gave short read: %zd not %d.\n", ofs, retlen, c->wbuf_pagesize);
+               pr_warn("%s(): Read back of page at %08x gave short read: %zd not %d\n",
+                       __func__, ofs, retlen, c->wbuf_pagesize);
                return -EIO;
        }
        if (!memcmp(buf, c->wbuf_verify, c->wbuf_pagesize))
@@ -246,12 +254,12 @@ static int jffs2_verify_write(struct jffs2_sb_info *c, unsigned char *buf,
        else
                eccstr = "OK or unused";
 
-       printk(KERN_WARNING "Write verify error (ECC %s) at %08x. Wrote:\n",
-              eccstr, c->wbuf_ofs);
+       pr_warn("Write verify error (ECC %s) at %08x. Wrote:\n",
+               eccstr, c->wbuf_ofs);
        print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1,
                       c->wbuf, c->wbuf_pagesize, 0);
 
-       printk(KERN_WARNING "Read back:\n");
+       pr_warn("Read back:\n");
        print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1,
                       c->wbuf_verify, c->wbuf_pagesize, 0);
 
@@ -308,7 +316,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
 
        if (!first_raw) {
                /* All nodes were obsolete. Nothing to recover. */
-               D1(printk(KERN_DEBUG "No non-obsolete nodes to be recovered. Just filing block bad\n"));
+               jffs2_dbg(1, "No non-obsolete nodes to be recovered. Just filing block bad\n");
                c->wbuf_len = 0;
                return;
        }
@@ -331,7 +339,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
 
                buf = kmalloc(end - start, GFP_KERNEL);
                if (!buf) {
-                       printk(KERN_CRIT "Malloc failure in wbuf recovery. Data loss ensues.\n");
+                       pr_crit("Malloc failure in wbuf recovery. Data loss ensues.\n");
 
                        goto read_failed;
                }
@@ -346,7 +354,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
                        ret = 0;
 
                if (ret || retlen != c->wbuf_ofs - start) {
-                       printk(KERN_CRIT "Old data are already lost in wbuf recovery. Data loss ensues.\n");
+                       pr_crit("Old data are already lost in wbuf recovery. Data loss ensues.\n");
 
                        kfree(buf);
                        buf = NULL;
@@ -380,7 +388,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
        /* ... and get an allocation of space from a shiny new block instead */
        ret = jffs2_reserve_space_gc(c, end-start, &len, JFFS2_SUMMARY_NOSUM_SIZE);
        if (ret) {
-               printk(KERN_WARNING "Failed to allocate space for wbuf recovery. Data loss ensues.\n");
+               pr_warn("Failed to allocate space for wbuf recovery. Data loss ensues.\n");
                kfree(buf);
                return;
        }
@@ -390,7 +398,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
 
        ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, nr_refile);
        if (ret) {
-               printk(KERN_WARNING "Failed to allocate node refs for wbuf recovery. Data loss ensues.\n");
+               pr_warn("Failed to allocate node refs for wbuf recovery. Data loss ensues.\n");
                kfree(buf);
                return;
        }
@@ -406,13 +414,13 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
                unsigned char *rewrite_buf = buf?:c->wbuf;
                uint32_t towrite = (end-start) - ((end-start)%c->wbuf_pagesize);
 
-               D1(printk(KERN_DEBUG "Write 0x%x bytes at 0x%08x in wbuf recover\n",
-                         towrite, ofs));
+               jffs2_dbg(1, "Write 0x%x bytes at 0x%08x in wbuf recover\n",
+                         towrite, ofs);
 
 #ifdef BREAKMEHEADER
                static int breakme;
                if (breakme++ == 20) {
-                       printk(KERN_NOTICE "Faking write error at 0x%08x\n", ofs);
+                       pr_notice("Faking write error at 0x%08x\n", ofs);
                        breakme = 0;
                        mtd_write(c->mtd, ofs, towrite, &retlen, brokenbuf);
                        ret = -EIO;
@@ -423,7 +431,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
 
                if (ret || retlen != towrite || jffs2_verify_write(c, rewrite_buf, ofs)) {
                        /* Argh. We tried. Really we did. */
-                       printk(KERN_CRIT "Recovery of wbuf failed due to a second write error\n");
+                       pr_crit("Recovery of wbuf failed due to a second write error\n");
                        kfree(buf);
 
                        if (retlen)
@@ -431,7 +439,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
 
                        return;
                }
-               printk(KERN_NOTICE "Recovery of wbuf succeeded to %08x\n", ofs);
+               pr_notice("Recovery of wbuf succeeded to %08x\n", ofs);
 
                c->wbuf_len = (end - start) - towrite;
                c->wbuf_ofs = ofs + towrite;
@@ -459,8 +467,8 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
                struct jffs2_raw_node_ref **adjust_ref = NULL;
                struct jffs2_inode_info *f = NULL;
 
-               D1(printk(KERN_DEBUG "Refiling block of %08x at %08x(%d) to %08x\n",
-                         rawlen, ref_offset(raw), ref_flags(raw), ofs));
+               jffs2_dbg(1, "Refiling block of %08x at %08x(%d) to %08x\n",
+                         rawlen, ref_offset(raw), ref_flags(raw), ofs);
 
                ic = jffs2_raw_ref_to_ic(raw);
 
@@ -540,7 +548,8 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
 
        /* Fix up the original jeb now it's on the bad_list */
        if (first_raw == jeb->first_node) {
-               D1(printk(KERN_DEBUG "Failing block at %08x is now empty. Moving to erase_pending_list\n", jeb->offset));
+               jffs2_dbg(1, "Failing block at %08x is now empty. Moving to erase_pending_list\n",
+                         jeb->offset);
                list_move(&jeb->list, &c->erase_pending_list);
                c->nr_erasing_blocks++;
                jffs2_garbage_collect_trigger(c);
@@ -554,7 +563,8 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
 
        spin_unlock(&c->erase_completion_lock);
 
-       D1(printk(KERN_DEBUG "wbuf recovery completed OK. wbuf_ofs 0x%08x, len 0x%x\n", c->wbuf_ofs, c->wbuf_len));
+       jffs2_dbg(1, "wbuf recovery completed OK. wbuf_ofs 0x%08x, len 0x%x\n",
+                 c->wbuf_ofs, c->wbuf_len);
 
 }
 
@@ -579,7 +589,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
                return 0;
 
        if (!mutex_is_locked(&c->alloc_sem)) {
-               printk(KERN_CRIT "jffs2_flush_wbuf() called with alloc_sem not locked!\n");
+               pr_crit("jffs2_flush_wbuf() called with alloc_sem not locked!\n");
                BUG();
        }
 
@@ -617,7 +627,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
 #ifdef BREAKME
        static int breakme;
        if (breakme++ == 20) {
-               printk(KERN_NOTICE "Faking write error at 0x%08x\n", c->wbuf_ofs);
+               pr_notice("Faking write error at 0x%08x\n", c->wbuf_ofs);
                breakme = 0;
                mtd_write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen,
                          brokenbuf);
@@ -629,11 +639,11 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
                                &retlen, c->wbuf);
 
        if (ret) {
-               printk(KERN_WARNING "jffs2_flush_wbuf(): Write failed with %d\n", ret);
+               pr_warn("jffs2_flush_wbuf(): Write failed with %d\n", ret);
                goto wfail;
        } else if (retlen != c->wbuf_pagesize) {
-               printk(KERN_WARNING "jffs2_flush_wbuf(): Write was short: %zd instead of %d\n",
-                      retlen, c->wbuf_pagesize);
+               pr_warn("jffs2_flush_wbuf(): Write was short: %zd instead of %d\n",
+                       retlen, c->wbuf_pagesize);
                ret = -EIO;
                goto wfail;
        } else if ((ret = jffs2_verify_write(c, c->wbuf, c->wbuf_ofs))) {
@@ -647,17 +657,18 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
        if (pad) {
                uint32_t waste = c->wbuf_pagesize - c->wbuf_len;
 
-               D1(printk(KERN_DEBUG "jffs2_flush_wbuf() adjusting free_size of %sblock at %08x\n",
-                         (wbuf_jeb==c->nextblock)?"next":"", wbuf_jeb->offset));
+               jffs2_dbg(1, "jffs2_flush_wbuf() adjusting free_size of %sblock at %08x\n",
+                         (wbuf_jeb == c->nextblock) ? "next" : "",
+                         wbuf_jeb->offset);
 
                /* wbuf_pagesize - wbuf_len is the amount of space that's to be
                   padded. If there is less free space in the block than that,
                   something screwed up */
                if (wbuf_jeb->free_size < waste) {
-                       printk(KERN_CRIT "jffs2_flush_wbuf(): Accounting error. wbuf at 0x%08x has 0x%03x bytes, 0x%03x left.\n",
-                              c->wbuf_ofs, c->wbuf_len, waste);
-                       printk(KERN_CRIT "jffs2_flush_wbuf(): But free_size for block at 0x%08x is only 0x%08x\n",
-                              wbuf_jeb->offset, wbuf_jeb->free_size);
+                       pr_crit("jffs2_flush_wbuf(): Accounting error. wbuf at 0x%08x has 0x%03x bytes, 0x%03x left.\n",
+                               c->wbuf_ofs, c->wbuf_len, waste);
+                       pr_crit("jffs2_flush_wbuf(): But free_size for block at 0x%08x is only 0x%08x\n",
+                               wbuf_jeb->offset, wbuf_jeb->free_size);
                        BUG();
                }
 
@@ -694,14 +705,14 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino)
        uint32_t old_wbuf_len;
        int ret = 0;
 
-       D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() called for ino #%u...\n", ino));
+       jffs2_dbg(1, "jffs2_flush_wbuf_gc() called for ino #%u...\n", ino);
 
        if (!c->wbuf)
                return 0;
 
        mutex_lock(&c->alloc_sem);
        if (!jffs2_wbuf_pending_for_ino(c, ino)) {
-               D1(printk(KERN_DEBUG "Ino #%d not pending in wbuf. Returning\n", ino));
+               jffs2_dbg(1, "Ino #%d not pending in wbuf. Returning\n", ino);
                mutex_unlock(&c->alloc_sem);
                return 0;
        }
@@ -711,7 +722,8 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino)
 
        if (c->unchecked_size) {
                /* GC won't make any progress for a while */
-               D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() padding. Not finished checking\n"));
+               jffs2_dbg(1, "%s(): padding. Not finished checking\n",
+                         __func__);
                down_write(&c->wbuf_sem);
                ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING);
                /* retry flushing wbuf in case jffs2_wbuf_recover
@@ -724,7 +736,7 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino)
 
                mutex_unlock(&c->alloc_sem);
 
-               D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() calls gc pass\n"));
+               jffs2_dbg(1, "%s(): calls gc pass\n", __func__);
 
                ret = jffs2_garbage_collect_pass(c);
                if (ret) {
@@ -742,7 +754,7 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino)
                mutex_lock(&c->alloc_sem);
        }
 
-       D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() ends...\n"));
+       jffs2_dbg(1, "%s(): ends...\n", __func__);
 
        mutex_unlock(&c->alloc_sem);
        return ret;
@@ -811,9 +823,8 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs,
        if (SECTOR_ADDR(to) != SECTOR_ADDR(c->wbuf_ofs)) {
                /* It's a write to a new block */
                if (c->wbuf_len) {
-                       D1(printk(KERN_DEBUG "jffs2_flash_writev() to 0x%lx "
-                                 "causes flush of wbuf at 0x%08x\n",
-                                 (unsigned long)to, c->wbuf_ofs));
+                       jffs2_dbg(1, "%s(): to 0x%lx causes flush of wbuf at 0x%08x\n",
+                                 __func__, (unsigned long)to, c->wbuf_ofs);
                        ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT);
                        if (ret)
                                goto outerr;
@@ -825,11 +836,11 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs,
 
        if (to != PAD(c->wbuf_ofs + c->wbuf_len)) {
                /* We're not writing immediately after the writebuffer. Bad. */
-               printk(KERN_CRIT "jffs2_flash_writev(): Non-contiguous write "
-                      "to %08lx\n", (unsigned long)to);
+               pr_crit("%s(): Non-contiguous write to %08lx\n",
+                       __func__, (unsigned long)to);
                if (c->wbuf_len)
-                       printk(KERN_CRIT "wbuf was previously %08x-%08x\n",
-                              c->wbuf_ofs, c->wbuf_ofs+c->wbuf_len);
+                       pr_crit("wbuf was previously %08x-%08x\n",
+                               c->wbuf_ofs, c->wbuf_ofs + c->wbuf_len);
                BUG();
        }
 
@@ -957,8 +968,8 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re
 
        if ( (ret == -EBADMSG || ret == -EUCLEAN) && (*retlen == len) ) {
                if (ret == -EBADMSG)
-                       printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx)"
-                              " returned ECC error\n", len, ofs);
+                       pr_warn("mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n",
+                               len, ofs);
                /*
                 * We have the raw data without ECC correction in the buffer,
                 * maybe we are lucky and all data or parts are correct. We
@@ -1034,9 +1045,8 @@ int jffs2_check_oob_empty(struct jffs2_sb_info *c,
 
        ret = mtd_read_oob(c->mtd, jeb->offset, &ops);
        if (ret || ops.oobretlen != ops.ooblen) {
-               printk(KERN_ERR "cannot read OOB for EB at %08x, requested %zd"
-                               " bytes, read %zd bytes, error %d\n",
-                               jeb->offset, ops.ooblen, ops.oobretlen, ret);
+               pr_err("cannot read OOB for EB at %08x, requested %zd bytes, read %zd bytes, error %d\n",
+                      jeb->offset, ops.ooblen, ops.oobretlen, ret);
                if (!ret)
                        ret = -EIO;
                return ret;
@@ -1048,8 +1058,8 @@ int jffs2_check_oob_empty(struct jffs2_sb_info *c,
                        continue;
 
                if (ops.oobbuf[i] != 0xFF) {
-                       D2(printk(KERN_DEBUG "Found %02x at %x in OOB for "
-                                 "%08x\n", ops.oobbuf[i], i, jeb->offset));
+                       jffs2_dbg(2, "Found %02x at %x in OOB for "
+                                 "%08x\n", ops.oobbuf[i], i, jeb->offset);
                        return 1;
                }
        }
@@ -1077,9 +1087,8 @@ int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c,
 
        ret = mtd_read_oob(c->mtd, jeb->offset, &ops);
        if (ret || ops.oobretlen != ops.ooblen) {
-               printk(KERN_ERR "cannot read OOB for EB at %08x, requested %zd"
-                               " bytes, read %zd bytes, error %d\n",
-                               jeb->offset, ops.ooblen, ops.oobretlen, ret);
+               pr_err("cannot read OOB for EB at %08x, requested %zd bytes, read %zd bytes, error %d\n",
+                      jeb->offset, ops.ooblen, ops.oobretlen, ret);
                if (!ret)
                        ret = -EIO;
                return ret;
@@ -1103,9 +1112,8 @@ int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c,
 
        ret = mtd_write_oob(c->mtd, jeb->offset, &ops);
        if (ret || ops.oobretlen != ops.ooblen) {
-               printk(KERN_ERR "cannot write OOB for EB at %08x, requested %zd"
-                               " bytes, read %zd bytes, error %d\n",
-                               jeb->offset, ops.ooblen, ops.oobretlen, ret);
+               pr_err("cannot write OOB for EB at %08x, requested %zd bytes, read %zd bytes, error %d\n",
+                      jeb->offset, ops.ooblen, ops.oobretlen, ret);
                if (!ret)
                        ret = -EIO;
                return ret;
@@ -1130,16 +1138,58 @@ int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *
        if( ++jeb->bad_count < MAX_ERASE_FAILURES)
                return 0;
 
-       printk(KERN_WARNING "JFFS2: marking eraseblock at %08x\n as bad", bad_offset);
+       pr_warn("marking eraseblock at %08x as bad\n", bad_offset);
        ret = mtd_block_markbad(c->mtd, bad_offset);
 
        if (ret) {
-               D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Write failed for block at %08x: error %d\n", jeb->offset, ret));
+               jffs2_dbg(1, "%s(): Write failed for block at %08x: error %d\n",
+                         __func__, jeb->offset, ret);
                return ret;
        }
        return 1;
 }
 
+static struct jffs2_sb_info *work_to_sb(struct work_struct *work)
+{
+       struct delayed_work *dwork;
+
+       dwork = container_of(work, struct delayed_work, work);
+       return container_of(dwork, struct jffs2_sb_info, wbuf_dwork);
+}
+
+static void delayed_wbuf_sync(struct work_struct *work)
+{
+       struct jffs2_sb_info *c = work_to_sb(work);
+       struct super_block *sb = OFNI_BS_2SFFJ(c);
+
+       spin_lock(&c->wbuf_dwork_lock);
+       c->wbuf_queued = 0;
+       spin_unlock(&c->wbuf_dwork_lock);
+
+       if (!(sb->s_flags & MS_RDONLY)) {
+               jffs2_dbg(1, "%s()\n", __func__);
+               jffs2_flush_wbuf_gc(c, 0);
+       }
+}
+
+void jffs2_dirty_trigger(struct jffs2_sb_info *c)
+{
+       struct super_block *sb = OFNI_BS_2SFFJ(c);
+       unsigned long delay;
+
+       if (sb->s_flags & MS_RDONLY)
+               return;
+
+       spin_lock(&c->wbuf_dwork_lock);
+       if (!c->wbuf_queued) {
+               jffs2_dbg(1, "%s()\n", __func__);
+               delay = msecs_to_jiffies(dirty_writeback_interval * 10);
+               queue_delayed_work(system_long_wq, &c->wbuf_dwork, delay);
+               c->wbuf_queued = 1;
+       }
+       spin_unlock(&c->wbuf_dwork_lock);
+}
+
 int jffs2_nand_flash_setup(struct jffs2_sb_info *c)
 {
        struct nand_ecclayout *oinfo = c->mtd->ecclayout;
@@ -1151,16 +1201,18 @@ int jffs2_nand_flash_setup(struct jffs2_sb_info *c)
        c->cleanmarker_size = 0;
 
        if (!oinfo || oinfo->oobavail == 0) {
-               printk(KERN_ERR "inconsistent device description\n");
+               pr_err("inconsistent device description\n");
                return -EINVAL;
        }
 
-       D1(printk(KERN_DEBUG "JFFS2 using OOB on NAND\n"));
+       jffs2_dbg(1, "using OOB on NAND\n");
 
        c->oobavail = oinfo->oobavail;
 
        /* Initialise write buffer */
        init_rwsem(&c->wbuf_sem);
+       spin_lock_init(&c->wbuf_dwork_lock);
+       INIT_DELAYED_WORK(&c->wbuf_dwork, delayed_wbuf_sync);
        c->wbuf_pagesize = c->mtd->writesize;
        c->wbuf_ofs = 0xFFFFFFFF;
 
@@ -1199,8 +1251,8 @@ int jffs2_dataflash_setup(struct jffs2_sb_info *c) {
 
        /* Initialize write buffer */
        init_rwsem(&c->wbuf_sem);
-
-
+       spin_lock_init(&c->wbuf_dwork_lock);
+       INIT_DELAYED_WORK(&c->wbuf_dwork, delayed_wbuf_sync);
        c->wbuf_pagesize =  c->mtd->erasesize;
 
        /* Find a suitable c->sector_size
@@ -1222,7 +1274,7 @@ int jffs2_dataflash_setup(struct jffs2_sb_info *c) {
 
        if ((c->flash_size % c->sector_size) != 0) {
                c->flash_size = (c->flash_size / c->sector_size) * c->sector_size;
-               printk(KERN_WARNING "JFFS2 flash size adjusted to %dKiB\n", c->flash_size);
+               pr_warn("flash size adjusted to %dKiB\n", c->flash_size);
        };
 
        c->wbuf_ofs = 0xFFFFFFFF;
@@ -1239,7 +1291,8 @@ int jffs2_dataflash_setup(struct jffs2_sb_info *c) {
        }
 #endif
 
-       printk(KERN_INFO "JFFS2 write-buffering enabled buffer (%d) erasesize (%d)\n", c->wbuf_pagesize, c->sector_size);
+       pr_info("write-buffering enabled buffer (%d) erasesize (%d)\n",
+               c->wbuf_pagesize, c->sector_size);
 
        return 0;
 }
@@ -1258,6 +1311,9 @@ int jffs2_nor_wbuf_flash_setup(struct jffs2_sb_info *c) {
 
        /* Initialize write buffer */
        init_rwsem(&c->wbuf_sem);
+       spin_lock_init(&c->wbuf_dwork_lock);
+       INIT_DELAYED_WORK(&c->wbuf_dwork, delayed_wbuf_sync);
+
        c->wbuf_pagesize = c->mtd->writesize;
        c->wbuf_ofs = 0xFFFFFFFF;
 
@@ -1290,6 +1346,8 @@ int jffs2_ubivol_setup(struct jffs2_sb_info *c) {
                return 0;
 
        init_rwsem(&c->wbuf_sem);
+       spin_lock_init(&c->wbuf_dwork_lock);
+       INIT_DELAYED_WORK(&c->wbuf_dwork, delayed_wbuf_sync);
 
        c->wbuf_pagesize =  c->mtd->writesize;
        c->wbuf_ofs = 0xFFFFFFFF;
@@ -1297,7 +1355,8 @@ int jffs2_ubivol_setup(struct jffs2_sb_info *c) {
        if (!c->wbuf)
                return -ENOMEM;
 
-       printk(KERN_INFO "JFFS2 write-buffering enabled buffer (%d) erasesize (%d)\n", c->wbuf_pagesize, c->sector_size);
+       pr_info("write-buffering enabled buffer (%d) erasesize (%d)\n",
+               c->wbuf_pagesize, c->sector_size);
 
        return 0;
 }