Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
[safe/jmp/linux-2.6] / fs / ubifs / super.c
index 336073e..e9f7a75 100644 (file)
@@ -421,8 +421,8 @@ static int ubifs_show_options(struct seq_file *s, struct vfsmount *mnt)
                seq_printf(s, ",no_chk_data_crc");
 
        if (c->mount_opts.override_compr) {
-               seq_printf(s, ",compr=");
-               seq_printf(s, ubifs_compr_name(c->mount_opts.compr_type));
+               seq_printf(s, ",compr=%s",
+                          ubifs_compr_name(c->mount_opts.compr_type));
        }
 
        return 0;
@@ -451,16 +451,6 @@ static int ubifs_sync_fs(struct super_block *sb, int wait)
                return 0;
 
        /*
-        * Synchronize write buffers, because 'ubifs_run_commit()' does not
-        * do this if it waits for an already running commit.
-        */
-       for (i = 0; i < c->jhead_cnt; i++) {
-               err = ubifs_wbuf_sync(&c->jheads[i].wbuf);
-               if (err)
-                       return err;
-       }
-
-       /*
         * VFS calls '->sync_fs()' before synchronizing all dirty inodes and
         * pages, so synchronize them first, then commit the journal. Strictly
         * speaking, it is not necessary to commit the journal here,
@@ -471,6 +461,16 @@ static int ubifs_sync_fs(struct super_block *sb, int wait)
         */
        generic_sync_sb_inodes(sb, &wbc);
 
+       /*
+        * Synchronize write buffers, because 'ubifs_run_commit()' does not
+        * do this if it waits for an already running commit.
+        */
+       for (i = 0; i < c->jhead_cnt; i++) {
+               err = ubifs_wbuf_sync(&c->jheads[i].wbuf);
+               if (err)
+                       return err;
+       }
+
        err = ubifs_run_commit(c);
        if (err)
                return err;
@@ -700,6 +700,8 @@ static int init_constants_sb(struct ubifs_info *c)
        if (err)
                return err;
 
+       /* Initialize effective LEB size used in budgeting calculations */
+       c->idx_leb_size = c->leb_size - c->max_idx_node_sz;
        return 0;
 }
 
@@ -716,6 +718,7 @@ static void init_constants_master(struct ubifs_info *c)
        long long tmp64;
 
        c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
+       c->report_rp_size = ubifs_reported_space(c, c->rp_size);
 
        /*
         * Calculate total amount of FS blocks. This number is not used
@@ -957,13 +960,16 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options,
 
                token = match_token(p, tokens, args);
                switch (token) {
+               /*
+                * %Opt_fast_unmount and %Opt_norm_unmount options are ignored.
+                * We accepte them in order to be backware-compatible. But this
+                * should be removed at some point.
+                */
                case Opt_fast_unmount:
                        c->mount_opts.unmount_mode = 2;
-                       c->fast_unmount = 1;
                        break;
                case Opt_norm_unmount:
                        c->mount_opts.unmount_mode = 1;
-                       c->fast_unmount = 0;
                        break;
                case Opt_bulk_read:
                        c->mount_opts.bulk_read = 2;
@@ -1085,12 +1091,7 @@ static int check_free_space(struct ubifs_info *c)
                ubifs_err("insufficient free space to mount in read/write mode");
                dbg_dump_budg(c);
                dbg_dump_lprops(c);
-               /*
-                * We return %-EINVAL instead of %-ENOSPC because it seems to
-                * be the closest error code mentioned in the mount function
-                * documentation.
-                */
-               return -EINVAL;
+               return -ENOSPC;
        }
        return 0;
 }
@@ -1203,7 +1204,7 @@ static int mount_ubifs(struct ubifs_info *c)
                        goto out_cbuf;
 
                /* Create background thread */
-               c->bgt = kthread_create(ubifs_bg_thread, c, c->bgt_name);
+               c->bgt = kthread_create(ubifs_bg_thread, c, "%s", c->bgt_name);
                if (IS_ERR(c->bgt)) {
                        err = PTR_ERR(c->bgt);
                        c->bgt = NULL;
@@ -1320,20 +1321,25 @@ static int mount_ubifs(struct ubifs_info *c)
                else {
                        c->need_recovery = 0;
                        ubifs_msg("recovery completed");
+                       /*
+                        * GC LEB has to be empty and taken at this point. But
+                        * the journal head LEBs may also be accounted as
+                        * "empty taken" if they are empty.
+                        */
+                       ubifs_assert(c->lst.taken_empty_lebs > 0);
                }
-       }
+       } else
+               ubifs_assert(c->lst.taken_empty_lebs > 0);
 
-       err = dbg_debugfs_init_fs(c);
+       err = dbg_check_filesystem(c);
        if (err)
                goto out_infos;
 
-       err = dbg_check_filesystem(c);
+       err = dbg_debugfs_init_fs(c);
        if (err)
                goto out_infos;
 
        c->always_chk_crc = 0;
-       /* GC LEB has to be empty and taken at this point */
-       ubifs_assert(c->lst.taken_empty_lebs == 1);
 
        ubifs_msg("mounted UBI device %d, volume %d, name \"%s\"",
                  c->vi.ubi_num, c->vi.vol_id, c->vi.name);
@@ -1345,8 +1351,9 @@ static int mount_ubifs(struct ubifs_info *c)
        x = (long long)c->log_lebs * c->leb_size + c->max_bud_bytes;
        ubifs_msg("journal size:       %lld bytes (%lld KiB, %lld MiB, %d "
                  "LEBs)", x, x >> 10, x >> 20, c->log_lebs + c->max_bud_cnt);
-       ubifs_msg("media format:       %d (latest is %d)",
-                 c->fmt_version, UBIFS_FORMAT_VERSION);
+       ubifs_msg("media format:       w%d/r%d (latest is w%d/r%d)",
+                 c->fmt_version, c->ro_compat_version,
+                 UBIFS_FORMAT_VERSION, UBIFS_RO_COMPAT_VERSION);
        ubifs_msg("default compressor: %s", ubifs_compr_name(c->default_compr));
        ubifs_msg("reserved for root:  %llu bytes (%llu KiB)",
                c->report_rp_size, c->report_rp_size >> 10);
@@ -1363,7 +1370,6 @@ static int mount_ubifs(struct ubifs_info *c)
               c->uuid[4], c->uuid[5], c->uuid[6], c->uuid[7],
               c->uuid[8], c->uuid[9], c->uuid[10], c->uuid[11],
               c->uuid[12], c->uuid[13], c->uuid[14], c->uuid[15]);
-       dbg_msg("fast unmount:        %d", c->fast_unmount);
        dbg_msg("big_lpt              %d", c->big_lpt);
        dbg_msg("log LEBs:            %d (%d - %d)",
                c->log_lebs, UBIFS_LOG_LNUM, c->log_last);
@@ -1487,6 +1493,15 @@ static int ubifs_remount_rw(struct ubifs_info *c)
 {
        int err, lnum;
 
+       if (c->rw_incompat) {
+               ubifs_err("the file-system is not R/W-compatible");
+               ubifs_msg("on-flash format version is w%d/r%d, but software "
+                         "only supports up to version w%d/r%d", c->fmt_version,
+                         c->ro_compat_version, UBIFS_FORMAT_VERSION,
+                         UBIFS_RO_COMPAT_VERSION);
+               return -EROFS;
+       }
+
        mutex_lock(&c->umount_mutex);
        dbg_save_space_info(c);
        c->remounting_rw = 1;
@@ -1524,6 +1539,12 @@ static int ubifs_remount_rw(struct ubifs_info *c)
                err = ubifs_recover_inl_heads(c, c->sbuf);
                if (err)
                        goto out;
+       } else {
+               /* A readonly mount is not allowed to have orphans */
+               ubifs_assert(c->tot_orphans == 0);
+               err = ubifs_clear_orphans(c);
+               if (err)
+                       goto out;
        }
 
        if (!(c->mst_node->flags & cpu_to_le32(UBIFS_MST_DIRTY))) {
@@ -1550,7 +1571,7 @@ static int ubifs_remount_rw(struct ubifs_info *c)
        ubifs_create_buds_lists(c);
 
        /* Create background thread */
-       c->bgt = kthread_create(ubifs_bg_thread, c, c->bgt_name);
+       c->bgt = kthread_create(ubifs_bg_thread, c, "%s", c->bgt_name);
        if (IS_ERR(c->bgt)) {
                err = PTR_ERR(c->bgt);
                c->bgt = NULL;
@@ -1614,38 +1635,6 @@ out:
 }
 
 /**
- * commit_on_unmount - commit the journal when un-mounting.
- * @c: UBIFS file-system description object
- *
- * This function is called during un-mounting and re-mounting, and it commits
- * the journal unless the "fast unmount" mode is enabled.
- */
-static void commit_on_unmount(struct ubifs_info *c)
-{
-       long long bud_bytes;
-
-       if (!c->fast_unmount) {
-               dbg_gen("skip committing - fast unmount enabled");
-               return;
-       }
-
-       /*
-        * This function is called before the background thread is stopped, so
-        * we may race with ongoing commit, which means we have to take
-        * @c->bud_lock to access @c->bud_bytes.
-        */
-       spin_lock(&c->buds_lock);
-       bud_bytes = c->bud_bytes;
-       spin_unlock(&c->buds_lock);
-
-       if (bud_bytes) {
-               dbg_gen("run commit");
-               ubifs_run_commit(c);
-       } else
-               dbg_gen("journal is empty, do not run commit");
-}
-
-/**
  * ubifs_remount_ro - re-mount in read-only mode.
  * @c: UBIFS file-system description object
  *
@@ -1657,9 +1646,8 @@ static void ubifs_remount_ro(struct ubifs_info *c)
        int i, err;
 
        ubifs_assert(!c->need_recovery);
-       ubifs_assert(!c->ro_media);
+       ubifs_assert(!(c->vfs_sb->s_flags & MS_RDONLY));
 
-       commit_on_unmount(c);
        mutex_lock(&c->umount_mutex);
        if (c->bgt) {
                kthread_stop(c->bgt);
@@ -1680,10 +1668,6 @@ static void ubifs_remount_ro(struct ubifs_info *c)
        if (err)
                ubifs_ro_mode(c, err);
 
-       err = ubifs_destroy_idx_gc(c);
-       if (err)
-               ubifs_ro_mode(c, err);
-
        free_wbufs(c);
        vfree(c->orph_buf);
        c->orph_buf = NULL;
@@ -1786,15 +1770,19 @@ 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_media) {
-                       ubifs_msg("cannot re-mount R/W, UBIFS is working in "
-                                 "R/O mode");
-                       return -EINVAL;
+                       ubifs_msg("cannot re-mount due to prior errors");
+                       return -EROFS;
                }
                err = ubifs_remount_rw(c);
                if (err)
                        return err;
-       } else if (!(sb->s_flags & MS_RDONLY) && (*flags & MS_RDONLY))
+       } else if (!(sb->s_flags & MS_RDONLY) && (*flags & MS_RDONLY)) {
+               if (c->ro_media) {
+                       ubifs_msg("cannot re-mount due to prior errors");
+                       return -EROFS;
+               }
                ubifs_remount_ro(c);
+       }
 
        if (c->bulk_read == 1)
                bu_init(c);
@@ -1804,7 +1792,7 @@ static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data)
                c->bu.buf = NULL;
        }
 
-       ubifs_assert(c->lst.taken_empty_lebs == 1);
+       ubifs_assert(c->lst.taken_empty_lebs > 0);
        return 0;
 }
 
@@ -2063,11 +2051,11 @@ static int ubifs_get_sb(struct file_system_type *fs_type, int flags,
        /* 'fill_super()' opens ubi again so we must close it here */
        ubi_close_volume(ubi);
 
-       return simple_set_mnt(mnt, sb);
+       simple_set_mnt(mnt, sb);
+       return 0;
 
 out_deact:
-       up_write(&sb->s_umount);
-       deactivate_super(sb);
+       deactivate_locked_super(sb);
 out_close:
        ubi_close_volume(ubi);
        return err;
@@ -2075,15 +2063,6 @@ out_close:
 
 static void ubifs_kill_sb(struct super_block *sb)
 {
-       struct ubifs_info *c = sb->s_fs_info;
-
-       /*
-        * We do 'commit_on_unmount()' here instead of 'ubifs_put_super()'
-        * in order to be outside BKL.
-        */
-       if (sb->s_root && !(sb->s_flags & MS_RDONLY))
-               commit_on_unmount(c);
-       /* The un-mount routine is actually done in put_super() */
        generic_shutdown_super(sb);
 }