UBIFS: introduce new flag for RO due to errors
authorArtem Bityutskiy <Artem.Bityutskiy@nokia.com>
Fri, 17 Sep 2010 13:44:28 +0000 (16:44 +0300)
committerArtem Bityutskiy <Artem.Bityutskiy@nokia.com>
Fri, 17 Sep 2010 14:08:09 +0000 (17:08 +0300)
The R/O state may have various reasons:

1. The UBI volume is R/O
2. The FS is mounted R/O
3. The FS switched to R/O mode because of an error

However, in UBIFS we have only one variable which represents cases
1 and 3 - 'c->ro_media'. Indeed, we set this to 1 if we switch to
R/O mode due to an error, and then we test it in many places to
make sure that we stop writing as soon as the error happens.

But this is very unclean. One consequence of this, for example, is
that in 'ubifs_remount_fs()' we use 'c->ro_media' to check whether
we are in R/O mode because on an error, and we print a message
in this case. However, if we are in R/O mode because the media
is R/O, our message is bogus.

This patch introduces new flag - 'c->ro_error' which is set when
we switch to R/O mode because of an error. It also changes all
"if (c->ro_media)" checks to "if (c->ro_error)" checks, because
this is what the checks actually mean. We do not need to check
for 'c->ro_media' because if the UBI volume is in R/O mode, we
do not allow R/W mounting, and now writes can happen. This is
guaranteed by VFS. But it is good to double-check this, so this
patch also adds many "ubifs_assert(!c->ro_media)" checks.

In the 'ubifs_remount_fs()' function this patch makes a bit more
changes - it fixes the error messages as well.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
fs/ubifs/commit.c
fs/ubifs/file.c
fs/ubifs/gc.c
fs/ubifs/io.c
fs/ubifs/journal.c
fs/ubifs/log.c
fs/ubifs/master.c
fs/ubifs/misc.h
fs/ubifs/shrinker.c
fs/ubifs/super.c
fs/ubifs/ubifs.h

index 37fa7ed062d8624fdfe6810aaacda6a6503bcd6a..712432789fb81336e560efd9e8c95372188a03db 100644 (file)
@@ -63,7 +63,9 @@ static int do_commit(struct ubifs_info *c)
        struct ubifs_lp_stats lst;
 
        dbg_cmt("start");
-       if (c->ro_media) {
+       ubifs_assert(!c->ro_media);
+
+       if (c->ro_error) {
                err = -EROFS;
                goto out_up;
        }
index 03ae894c45dea3a04181a20cb3c5b123bac083ce..c6bc51c9f07c15ea3efade42eeb93829e1655dc3 100644 (file)
@@ -433,8 +433,9 @@ static int ubifs_write_begin(struct file *file, struct address_space *mapping,
        struct page *page;
 
        ubifs_assert(ubifs_inode(inode)->ui_size == inode->i_size);
+       ubifs_assert(!c->ro_media);
 
-       if (unlikely(c->ro_media))
+       if (unlikely(c->ro_error))
                return -EROFS;
 
        /* Try out the fast-path part first */
@@ -1440,8 +1441,9 @@ static int ubifs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vm
        dbg_gen("ino %lu, pg %lu, i_size %lld", inode->i_ino, page->index,
                i_size_read(inode));
        ubifs_assert(!(inode->i_sb->s_flags & MS_RDONLY));
+       ubifs_assert(!c->ro_media);
 
-       if (unlikely(c->ro_media))
+       if (unlikely(c->ro_error))
                return VM_FAULT_SIGBUS; /* -EROFS */
 
        /*
index 396f24a30af98de54e183076c3a4a84ad61f407b..d927196d730b6a4a1e6f3c746931ef5159f794f0 100644 (file)
@@ -616,13 +616,14 @@ int ubifs_garbage_collect(struct ubifs_info *c, int anyway)
        struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf;
 
        ubifs_assert_cmt_locked(c);
+       ubifs_assert(!c->ro_media);
 
        if (ubifs_gc_should_commit(c))
                return -EAGAIN;
 
        mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead);
 
-       if (c->ro_media) {
+       if (c->ro_error) {
                ret = -EROFS;
                goto out_unlock;
        }
index 9432431bf595242a2983fe55dca9550933478c7b..18a4b8d7c84480f43de67b26009a9937e495364b 100644 (file)
@@ -61,8 +61,8 @@
  */
 void ubifs_ro_mode(struct ubifs_info *c, int err)
 {
-       if (!c->ro_media) {
-               c->ro_media = 1;
+       if (!c->ro_error) {
+               c->ro_error = 1;
                c->no_chk_data_crc = 0;
                c->vfs_sb->s_flags |= MS_RDONLY;
                ubifs_warn("switched to read-only mode, error %d", err);
@@ -359,8 +359,9 @@ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf)
        ubifs_assert(!(c->vfs_sb->s_flags & MS_RDONLY));
        ubifs_assert(!(wbuf->avail & 7));
        ubifs_assert(wbuf->offs + c->min_io_size <= c->leb_size);
+       ubifs_assert(!c->ro_media);
 
-       if (c->ro_media)
+       if (c->ro_error)
                return -EROFS;
 
        ubifs_pad(c, wbuf->buf + wbuf->used, wbuf->avail);
@@ -440,11 +441,12 @@ int ubifs_bg_wbufs_sync(struct ubifs_info *c)
 {
        int err, i;
 
+       ubifs_assert(!c->ro_media);
        if (!c->need_wbuf_sync)
                return 0;
        c->need_wbuf_sync = 0;
 
-       if (c->ro_media) {
+       if (c->ro_error) {
                err = -EROFS;
                goto out_timers;
        }
@@ -519,6 +521,7 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
        ubifs_assert(!(wbuf->offs & 7) && wbuf->offs <= c->leb_size);
        ubifs_assert(wbuf->avail > 0 && wbuf->avail <= c->min_io_size);
        ubifs_assert(mutex_is_locked(&wbuf->io_mutex));
+       ubifs_assert(!c->ro_media);
 
        if (c->leb_size - wbuf->offs - wbuf->used < aligned_len) {
                err = -ENOSPC;
@@ -527,7 +530,7 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
 
        cancel_wbuf_timer_nolock(wbuf);
 
-       if (c->ro_media)
+       if (c->ro_error)
                return -EROFS;
 
        if (aligned_len <= wbuf->avail) {
@@ -663,8 +666,9 @@ int ubifs_write_node(struct ubifs_info *c, void *buf, int len, int lnum,
               buf_len);
        ubifs_assert(lnum >= 0 && lnum < c->leb_cnt && offs >= 0);
        ubifs_assert(offs % c->min_io_size == 0 && offs < c->leb_size);
+       ubifs_assert(!c->ro_media);
 
-       if (c->ro_media)
+       if (c->ro_error)
                return -EROFS;
 
        ubifs_prepare_node(c, buf, len, 1);
index d321baeca68db65cb0bcce2fcd38ead5ee4e2e65..a6da8aa68f378834f2caba7003cec9612d6795c8 100644 (file)
@@ -122,11 +122,12 @@ static int reserve_space(struct ubifs_info *c, int jhead, int len)
         * better to try to allocate space at the ends of eraseblocks. This is
         * what the squeeze parameter does.
         */
+       ubifs_assert(!c->ro_media);
        squeeze = (jhead == BASEHD);
 again:
        mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead);
 
-       if (c->ro_media) {
+       if (c->ro_error) {
                err = -EROFS;
                goto out_unlock;
        }
index c345e125f42c5cd765229166848f97bec300d90d..a41713e2fbb394cf6205d903126e923709b18f67 100644 (file)
@@ -223,8 +223,8 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs)
        }
 
        mutex_lock(&c->log_mutex);
-
-       if (c->ro_media) {
+       ubifs_assert(!c->ro_media);
+       if (c->ro_error) {
                err = -EROFS;
                goto out_unlock;
        }
index 28beaeedadc07d5ad7c3c312d27e30d7be01ee64..0c818e855f593cba8d68bdaf1bd18379fe6999db 100644 (file)
@@ -361,7 +361,8 @@ int ubifs_write_master(struct ubifs_info *c)
 {
        int err, lnum, offs, len;
 
-       if (c->ro_media)
+       ubifs_assert(!c->ro_media);
+       if (c->ro_error)
                return -EROFS;
 
        lnum = UBIFS_MST_LNUM;
index 4fa81d867e4107cc726074a78762abb5f681ca63..5d476ba184e6ded42bf43a786ceb7d7e088a0610 100644 (file)
@@ -132,7 +132,8 @@ static inline int ubifs_leb_unmap(const struct ubifs_info *c, int lnum)
 {
        int err;
 
-       if (c->ro_media)
+       ubifs_assert(!c->ro_media);
+       if (c->ro_error)
                return -EROFS;
        err = ubi_leb_unmap(c->ubi, lnum);
        if (err) {
@@ -159,7 +160,8 @@ static inline int ubifs_leb_write(const struct ubifs_info *c, int lnum,
 {
        int err;
 
-       if (c->ro_media)
+       ubifs_assert(!c->ro_media);
+       if (c->ro_error)
                return -EROFS;
        err = ubi_leb_write(c->ubi, lnum, buf, offs, len, dtype);
        if (err) {
@@ -186,7 +188,8 @@ static inline int ubifs_leb_change(const struct ubifs_info *c, int lnum,
 {
        int err;
 
-       if (c->ro_media)
+       ubifs_assert(!c->ro_media);
+       if (c->ro_error)
                return -EROFS;
        err = ubi_leb_change(c->ubi, lnum, buf, len, dtype);
        if (err) {
index 0b201114a5adf9cfc9c04b6730442748c079fa9d..10eec87784385ebe5f5d5cdfb20f18d5bc51e44c 100644 (file)
@@ -250,7 +250,7 @@ static int kick_a_thread(void)
                        dirty_zn_cnt = atomic_long_read(&c->dirty_zn_cnt);
 
                        if (!dirty_zn_cnt || c->cmt_state == COMMIT_BROKEN ||
-                           c->ro_media) {
+                           c->ro_media || c->ro_error) {
                                mutex_unlock(&c->umount_mutex);
                                continue;
                        }
index cd5900b85d38373cc4998a562152fcbe334f541f..1cfeec56df915b74eef0598bfaf8858f1e0b9412 100644 (file)
@@ -1751,10 +1751,10 @@ static void ubifs_put_super(struct super_block *sb)
                                ubifs_wbuf_sync(&c->jheads[i].wbuf);
 
                /*
-                * On fatal errors c->ro_media is set to 1, in which case we do
+                * On fatal errors c->ro_error is set to 1, in which case we do
                 * not write the master node.
                 */
-               if (!c->ro_media) {
+               if (!c->ro_error) {
                        /*
                         * We are being cleanly unmounted which means the
                         * orphans were killed - indicate this in the master
@@ -1798,16 +1798,20 @@ static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data)
        }
 
        if ((sb->s_flags & MS_RDONLY) && !(*flags & MS_RDONLY)) {
+               if (c->ro_error) {
+                       ubifs_msg("cannot re-mount R/W due to prior errors");
+                       return -EROFS;
+               }
                if (c->ro_media) {
-                       ubifs_msg("cannot re-mount due to prior errors");
+                       ubifs_msg("cannot re-mount R/W - UBI volume is R/O");
                        return -EROFS;
                }
                err = ubifs_remount_rw(c);
                if (err)
                        return err;
        } else if (!(sb->s_flags & MS_RDONLY) && (*flags & MS_RDONLY)) {
-               if (c->ro_media) {
-                       ubifs_msg("cannot re-mount due to prior errors");
+               if (c->ro_error) {
+                       ubifs_msg("cannot re-mount R/O due to prior errors");
                        return -EROFS;
                }
                ubifs_remount_ro(c);
index c4dc9b18f73e9c236f2349dc628349d4c55d4464..f47ebb442d1ce0a8adc9f12576f3121caff638ae 100644 (file)
@@ -1032,6 +1032,7 @@ struct ubifs_debug_info;
  * @max_leb_cnt: maximum count of logical eraseblocks
  * @old_leb_cnt: count of logical eraseblocks before re-size
  * @ro_media: the underlying UBI volume is read-only
+ * @ro_error: UBIFS switched to R/O mode because an error happened
  *
  * @dirty_pg_cnt: number of dirty pages (not used)
  * @dirty_zn_cnt: number of dirty znodes
@@ -1272,7 +1273,8 @@ struct ubifs_info {
        int leb_cnt;
        int max_leb_cnt;
        int old_leb_cnt;
-       int ro_media;
+       unsigned int ro_media:1;
+       unsigned int ro_error:1;
 
        atomic_long_t dirty_pg_cnt;
        atomic_long_t dirty_zn_cnt;