Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-block.git] / fs / ubifs / super.c
index fec62e9dfbe6a6c639d7f61879bf21ac84ef4a6c..1fac1133dadd291b7491527802e70782ab8544e8 100644 (file)
@@ -579,6 +579,9 @@ static int init_constants_early(struct ubifs_info *c)
        c->ranges[UBIFS_REF_NODE].len  = UBIFS_REF_NODE_SZ;
        c->ranges[UBIFS_TRUN_NODE].len = UBIFS_TRUN_NODE_SZ;
        c->ranges[UBIFS_CS_NODE].len   = UBIFS_CS_NODE_SZ;
+       c->ranges[UBIFS_AUTH_NODE].min_len = UBIFS_AUTH_NODE_SZ;
+       c->ranges[UBIFS_AUTH_NODE].max_len = UBIFS_AUTH_NODE_SZ +
+                               UBIFS_MAX_HMAC_LEN;
 
        c->ranges[UBIFS_INO_NODE].min_len  = UBIFS_INO_NODE_SZ;
        c->ranges[UBIFS_INO_NODE].max_len  = UBIFS_MAX_INO_NODE_SZ;
@@ -816,6 +819,9 @@ static int alloc_wbufs(struct ubifs_info *c)
                c->jheads[i].wbuf.sync_callback = &bud_wbuf_callback;
                c->jheads[i].wbuf.jhead = i;
                c->jheads[i].grouped = 1;
+               c->jheads[i].log_hash = ubifs_hash_get_desc(c);
+               if (IS_ERR(c->jheads[i].log_hash))
+                       goto out;
        }
 
        /*
@@ -826,6 +832,12 @@ static int alloc_wbufs(struct ubifs_info *c)
        c->jheads[GCHD].grouped = 0;
 
        return 0;
+
+out:
+       while (i--)
+               kfree(c->jheads[i].log_hash);
+
+       return err;
 }
 
 /**
@@ -840,6 +852,7 @@ static void free_wbufs(struct ubifs_info *c)
                for (i = 0; i < c->jhead_cnt; i++) {
                        kfree(c->jheads[i].wbuf.buf);
                        kfree(c->jheads[i].wbuf.inodes);
+                       kfree(c->jheads[i].log_hash);
                }
                kfree(c->jheads);
                c->jheads = NULL;
@@ -924,6 +937,8 @@ static int check_volume_empty(struct ubifs_info *c)
  * Opt_no_chk_data_crc: do not check CRCs when reading data nodes
  * Opt_override_compr: override default compressor
  * Opt_assert: set ubifs_assert() action
+ * Opt_auth_key: The key name used for authentication
+ * Opt_auth_hash_name: The hash type used for authentication
  * Opt_err: just end of array marker
  */
 enum {
@@ -935,6 +950,8 @@ enum {
        Opt_no_chk_data_crc,
        Opt_override_compr,
        Opt_assert,
+       Opt_auth_key,
+       Opt_auth_hash_name,
        Opt_ignore,
        Opt_err,
 };
@@ -947,6 +964,8 @@ static const match_table_t tokens = {
        {Opt_chk_data_crc, "chk_data_crc"},
        {Opt_no_chk_data_crc, "no_chk_data_crc"},
        {Opt_override_compr, "compr=%s"},
+       {Opt_auth_key, "auth_key=%s"},
+       {Opt_auth_hash_name, "auth_hash_name=%s"},
        {Opt_ignore, "ubi=%s"},
        {Opt_ignore, "vol=%s"},
        {Opt_assert, "assert=%s"},
@@ -1070,6 +1089,16 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options,
                        kfree(act);
                        break;
                }
+               case Opt_auth_key:
+                       c->auth_key_name = kstrdup(args[0].from, GFP_KERNEL);
+                       if (!c->auth_key_name)
+                               return -ENOMEM;
+                       break;
+               case Opt_auth_hash_name:
+                       c->auth_hash_name = kstrdup(args[0].from, GFP_KERNEL);
+                       if (!c->auth_hash_name)
+                               return -ENOMEM;
+                       break;
                case Opt_ignore:
                        break;
                default:
@@ -1249,6 +1278,19 @@ static int mount_ubifs(struct ubifs_info *c)
 
        c->mounting = 1;
 
+       if (c->auth_key_name) {
+               if (IS_ENABLED(CONFIG_UBIFS_FS_AUTHENTICATION)) {
+                       err = ubifs_init_authentication(c);
+                       if (err)
+                               goto out_free;
+               } else {
+                       ubifs_err(c, "auth_key_name, but UBIFS is built without"
+                                 " authentication support");
+                       err = -EINVAL;
+                       goto out_free;
+               }
+       }
+
        err = ubifs_read_superblock(c);
        if (err)
                goto out_free;
@@ -1367,12 +1409,21 @@ static int mount_ubifs(struct ubifs_info *c)
                }
 
                if (c->need_recovery) {
-                       err = ubifs_recover_size(c);
-                       if (err)
-                               goto out_orphans;
+                       if (!ubifs_authenticated(c)) {
+                               err = ubifs_recover_size(c, true);
+                               if (err)
+                                       goto out_orphans;
+                       }
+
                        err = ubifs_rcvry_gc_commit(c);
                        if (err)
                                goto out_orphans;
+
+                       if (ubifs_authenticated(c)) {
+                               err = ubifs_recover_size(c, false);
+                               if (err)
+                                       goto out_orphans;
+                       }
                } else {
                        err = take_gc_lnum(c);
                        if (err)
@@ -1391,7 +1442,7 @@ static int mount_ubifs(struct ubifs_info *c)
                if (err)
                        goto out_orphans;
        } else if (c->need_recovery) {
-               err = ubifs_recover_size(c);
+               err = ubifs_recover_size(c, false);
                if (err)
                        goto out_orphans;
        } else {
@@ -1557,7 +1608,10 @@ static void ubifs_umount(struct ubifs_info *c)
        free_wbufs(c);
        free_orphans(c);
        ubifs_lpt_free(c, 0);
+       ubifs_exit_authentication(c);
 
+       kfree(c->auth_key_name);
+       kfree(c->auth_hash_name);
        kfree(c->cbuf);
        kfree(c->rcvrd_mst_node);
        kfree(c->mst_node);
@@ -1605,16 +1659,10 @@ static int ubifs_remount_rw(struct ubifs_info *c)
                goto out;
 
        if (c->old_leb_cnt != c->leb_cnt) {
-               struct ubifs_sb_node *sup;
+               struct ubifs_sb_node *sup = c->sup_node;
 
-               sup = ubifs_read_sb_node(c);
-               if (IS_ERR(sup)) {
-                       err = PTR_ERR(sup);
-                       goto out;
-               }
                sup->leb_cnt = cpu_to_le32(c->leb_cnt);
                err = ubifs_write_sb_node(c, sup);
-               kfree(sup);
                if (err)
                        goto out;
        }
@@ -1624,9 +1672,11 @@ static int ubifs_remount_rw(struct ubifs_info *c)
                err = ubifs_write_rcvrd_mst_node(c);
                if (err)
                        goto out;
-               err = ubifs_recover_size(c);
-               if (err)
-                       goto out;
+               if (!ubifs_authenticated(c)) {
+                       err = ubifs_recover_size(c, true);
+                       if (err)
+                               goto out;
+               }
                err = ubifs_clean_lebs(c, c->sbuf);
                if (err)
                        goto out;
@@ -1692,10 +1742,19 @@ static int ubifs_remount_rw(struct ubifs_info *c)
                        goto out;
        }
 
-       if (c->need_recovery)
+       if (c->need_recovery) {
                err = ubifs_rcvry_gc_commit(c);
-       else
+               if (err)
+                       goto out;
+
+               if (ubifs_authenticated(c)) {
+                       err = ubifs_recover_size(c, false);
+                       if (err)
+                               goto out;
+               }
+       } else {
                err = ubifs_leb_unmap(c, c->gc_lnum);
+       }
        if (err)
                goto out;