]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
UBIFS: synchronize write-buffer before switching to the next bud
authorArtem Bityutskiy <Artem.Bityutskiy@nokia.com>
Sun, 15 May 2011 11:51:54 +0000 (14:51 +0300)
committerArtem Bityutskiy <Artem.Bityutskiy@nokia.com>
Mon, 16 May 2011 07:31:41 +0000 (10:31 +0300)
Currently when UBIFS fills up the current bud (which is the last in the journal
head) and switches to the next bud, it first writes the log reference node for
the next bud and only after this synchronizes the write-buffer of the previous
bud. This is not a big deal, but an unclean power cut may lead to a situation
when we have corruption in a next-to-last bud, although it is much more logical
that we have to have corruption only in the last bud.

This patch also removes write-buffer synchronization from
'ubifs_wbuf_seek_nolock()' because this is not needed anymore (we synchronize
the write-buffer explicitly everywhere now) and also because this is just
prone to various errors.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
fs/ubifs/gc.c
fs/ubifs/io.c
fs/ubifs/journal.c

index d70937b3f8e970a24882e6fe7d68b72b08550e20..ded29f6224c27155765a366a6ec1e13644b224d6 100644 (file)
@@ -100,6 +100,10 @@ static int switch_gc_head(struct ubifs_info *c)
        if (err)
                return err;
 
+       err = ubifs_wbuf_sync_nolock(wbuf);
+       if (err)
+               return err;
+
        err = ubifs_add_bud_to_log(c, GCHD, gc_lnum, 0);
        if (err)
                return err;
index 67bbde3550cfc494d46c58292340d32918bc97ab..166951e0dcd3c7b1dc232102c74bf8b8d61e8c1e 100644 (file)
@@ -452,8 +452,8 @@ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf)
  * @dtype: data type
  *
  * This function targets the write-buffer to logical eraseblock @lnum:@offs.
- * The write-buffer is synchronized if it is not empty. Returns zero in case of
- * success and a negative error code in case of failure.
+ * The write-buffer has to be empty. Returns zero in case of success and a
+ * negative error code in case of failure.
  */
 int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs,
                           int dtype)
@@ -465,13 +465,7 @@ int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs,
        ubifs_assert(offs >= 0 && offs <= c->leb_size);
        ubifs_assert(offs % c->min_io_size == 0 && !(offs & 7));
        ubifs_assert(lnum != wbuf->lnum);
-
-       if (wbuf->used > 0) {
-               int err = ubifs_wbuf_sync_nolock(wbuf);
-
-               if (err)
-                       return err;
-       }
+       ubifs_assert(wbuf->used == 0);
 
        spin_lock(&wbuf->lock);
        wbuf->lnum = lnum;
index ce55a4807cdc4318d5f2b856e3db70bfb176326f..34b1679e6e3a671684a1f08be42e155ce4a48ded 100644 (file)
@@ -141,14 +141,8 @@ again:
         * LEB with some empty space.
         */
        lnum = ubifs_find_free_space(c, len, &offs, squeeze);
-       if (lnum >= 0) {
-               /* Found an LEB, add it to the journal head */
-               err = ubifs_add_bud_to_log(c, jhead, lnum, offs);
-               if (err)
-                       goto out_return;
-               /* A new bud was successfully allocated and added to the log */
+       if (lnum >= 0)
                goto out;
-       }
 
        err = lnum;
        if (err != -ENOSPC)
@@ -203,12 +197,23 @@ again:
                return 0;
        }
 
-       err = ubifs_add_bud_to_log(c, jhead, lnum, 0);
-       if (err)
-               goto out_return;
        offs = 0;
 
 out:
+       /*
+        * Make sure we synchronize the write-buffer before we add the new bud
+        * to the log. Otherwise we may have a power cut after the log
+        * reference node for the last bud (@lnum) is written but before the
+        * write-buffer data are written to the next-to-last bud
+        * (@wbuf->lnum). And the effect would be that the recovery would see
+        * that there is corruption in the next-to-last bud.
+        */
+       err = ubifs_wbuf_sync_nolock(wbuf);
+       if (err)
+               goto out_return;
+       err = ubifs_add_bud_to_log(c, jhead, lnum, offs);
+       if (err)
+               goto out_return;
        err = ubifs_wbuf_seek_nolock(wbuf, lnum, offs, wbuf->dtype);
        if (err)
                goto out_unlock;