uboot/fs/ubifs/master.c
<<
>>
Prefs
   1/*
   2 * This file is part of UBIFS.
   3 *
   4 * Copyright (C) 2006-2008 Nokia Corporation.
   5 *
   6 * SPDX-License-Identifier:     GPL-2.0+
   7 *
   8 * Authors: Artem Bityutskiy (Битюцкий Артём)
   9 *          Adrian Hunter
  10 */
  11
  12/* This file implements reading and writing the master node */
  13
  14#include "ubifs.h"
  15#ifdef __UBOOT__
  16#include <linux/compat.h>
  17#include <linux/err.h>
  18#include <ubi_uboot.h>
  19#endif
  20
  21/**
  22 * scan_for_master - search the valid master node.
  23 * @c: UBIFS file-system description object
  24 *
  25 * This function scans the master node LEBs and search for the latest master
  26 * node. Returns zero in case of success, %-EUCLEAN if there master area is
  27 * corrupted and requires recovery, and a negative error code in case of
  28 * failure.
  29 */
  30static int scan_for_master(struct ubifs_info *c)
  31{
  32        struct ubifs_scan_leb *sleb;
  33        struct ubifs_scan_node *snod;
  34        int lnum, offs = 0, nodes_cnt;
  35
  36        lnum = UBIFS_MST_LNUM;
  37
  38        sleb = ubifs_scan(c, lnum, 0, c->sbuf, 1);
  39        if (IS_ERR(sleb))
  40                return PTR_ERR(sleb);
  41        nodes_cnt = sleb->nodes_cnt;
  42        if (nodes_cnt > 0) {
  43                snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node,
  44                                  list);
  45                if (snod->type != UBIFS_MST_NODE)
  46                        goto out_dump;
  47                memcpy(c->mst_node, snod->node, snod->len);
  48                offs = snod->offs;
  49        }
  50        ubifs_scan_destroy(sleb);
  51
  52        lnum += 1;
  53
  54        sleb = ubifs_scan(c, lnum, 0, c->sbuf, 1);
  55        if (IS_ERR(sleb))
  56                return PTR_ERR(sleb);
  57        if (sleb->nodes_cnt != nodes_cnt)
  58                goto out;
  59        if (!sleb->nodes_cnt)
  60                goto out;
  61        snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node, list);
  62        if (snod->type != UBIFS_MST_NODE)
  63                goto out_dump;
  64        if (snod->offs != offs)
  65                goto out;
  66        if (memcmp((void *)c->mst_node + UBIFS_CH_SZ,
  67                   (void *)snod->node + UBIFS_CH_SZ,
  68                   UBIFS_MST_NODE_SZ - UBIFS_CH_SZ))
  69                goto out;
  70        c->mst_offs = offs;
  71        ubifs_scan_destroy(sleb);
  72        return 0;
  73
  74out:
  75        ubifs_scan_destroy(sleb);
  76        return -EUCLEAN;
  77
  78out_dump:
  79        ubifs_err(c, "unexpected node type %d master LEB %d:%d",
  80                  snod->type, lnum, snod->offs);
  81        ubifs_scan_destroy(sleb);
  82        return -EINVAL;
  83}
  84
  85/**
  86 * validate_master - validate master node.
  87 * @c: UBIFS file-system description object
  88 *
  89 * This function validates data which was read from master node. Returns zero
  90 * if the data is all right and %-EINVAL if not.
  91 */
  92static int validate_master(const struct ubifs_info *c)
  93{
  94        long long main_sz;
  95        int err;
  96
  97        if (c->max_sqnum >= SQNUM_WATERMARK) {
  98                err = 1;
  99                goto out;
 100        }
 101
 102        if (c->cmt_no >= c->max_sqnum) {
 103                err = 2;
 104                goto out;
 105        }
 106
 107        if (c->highest_inum >= INUM_WATERMARK) {
 108                err = 3;
 109                goto out;
 110        }
 111
 112        if (c->lhead_lnum < UBIFS_LOG_LNUM ||
 113            c->lhead_lnum >= UBIFS_LOG_LNUM + c->log_lebs ||
 114            c->lhead_offs < 0 || c->lhead_offs >= c->leb_size ||
 115            c->lhead_offs & (c->min_io_size - 1)) {
 116                err = 4;
 117                goto out;
 118        }
 119
 120        if (c->zroot.lnum >= c->leb_cnt || c->zroot.lnum < c->main_first ||
 121            c->zroot.offs >= c->leb_size || c->zroot.offs & 7) {
 122                err = 5;
 123                goto out;
 124        }
 125
 126        if (c->zroot.len < c->ranges[UBIFS_IDX_NODE].min_len ||
 127            c->zroot.len > c->ranges[UBIFS_IDX_NODE].max_len) {
 128                err = 6;
 129                goto out;
 130        }
 131
 132        if (c->gc_lnum >= c->leb_cnt || c->gc_lnum < c->main_first) {
 133                err = 7;
 134                goto out;
 135        }
 136
 137        if (c->ihead_lnum >= c->leb_cnt || c->ihead_lnum < c->main_first ||
 138            c->ihead_offs % c->min_io_size || c->ihead_offs < 0 ||
 139            c->ihead_offs > c->leb_size || c->ihead_offs & 7) {
 140                err = 8;
 141                goto out;
 142        }
 143
 144        main_sz = (long long)c->main_lebs * c->leb_size;
 145        if (c->bi.old_idx_sz & 7 || c->bi.old_idx_sz >= main_sz) {
 146                err = 9;
 147                goto out;
 148        }
 149
 150        if (c->lpt_lnum < c->lpt_first || c->lpt_lnum > c->lpt_last ||
 151            c->lpt_offs < 0 || c->lpt_offs + c->nnode_sz > c->leb_size) {
 152                err = 10;
 153                goto out;
 154        }
 155
 156        if (c->nhead_lnum < c->lpt_first || c->nhead_lnum > c->lpt_last ||
 157            c->nhead_offs < 0 || c->nhead_offs % c->min_io_size ||
 158            c->nhead_offs > c->leb_size) {
 159                err = 11;
 160                goto out;
 161        }
 162
 163        if (c->ltab_lnum < c->lpt_first || c->ltab_lnum > c->lpt_last ||
 164            c->ltab_offs < 0 ||
 165            c->ltab_offs + c->ltab_sz > c->leb_size) {
 166                err = 12;
 167                goto out;
 168        }
 169
 170        if (c->big_lpt && (c->lsave_lnum < c->lpt_first ||
 171            c->lsave_lnum > c->lpt_last || c->lsave_offs < 0 ||
 172            c->lsave_offs + c->lsave_sz > c->leb_size)) {
 173                err = 13;
 174                goto out;
 175        }
 176
 177        if (c->lscan_lnum < c->main_first || c->lscan_lnum >= c->leb_cnt) {
 178                err = 14;
 179                goto out;
 180        }
 181
 182        if (c->lst.empty_lebs < 0 || c->lst.empty_lebs > c->main_lebs - 2) {
 183                err = 15;
 184                goto out;
 185        }
 186
 187        if (c->lst.idx_lebs < 0 || c->lst.idx_lebs > c->main_lebs - 1) {
 188                err = 16;
 189                goto out;
 190        }
 191
 192        if (c->lst.total_free < 0 || c->lst.total_free > main_sz ||
 193            c->lst.total_free & 7) {
 194                err = 17;
 195                goto out;
 196        }
 197
 198        if (c->lst.total_dirty < 0 || (c->lst.total_dirty & 7)) {
 199                err = 18;
 200                goto out;
 201        }
 202
 203        if (c->lst.total_used < 0 || (c->lst.total_used & 7)) {
 204                err = 19;
 205                goto out;
 206        }
 207
 208        if (c->lst.total_free + c->lst.total_dirty +
 209            c->lst.total_used > main_sz) {
 210                err = 20;
 211                goto out;
 212        }
 213
 214        if (c->lst.total_dead + c->lst.total_dark +
 215            c->lst.total_used + c->bi.old_idx_sz > main_sz) {
 216                err = 21;
 217                goto out;
 218        }
 219
 220        if (c->lst.total_dead < 0 ||
 221            c->lst.total_dead > c->lst.total_free + c->lst.total_dirty ||
 222            c->lst.total_dead & 7) {
 223                err = 22;
 224                goto out;
 225        }
 226
 227        if (c->lst.total_dark < 0 ||
 228            c->lst.total_dark > c->lst.total_free + c->lst.total_dirty ||
 229            c->lst.total_dark & 7) {
 230                err = 23;
 231                goto out;
 232        }
 233
 234        return 0;
 235
 236out:
 237        ubifs_err(c, "bad master node at offset %d error %d", c->mst_offs, err);
 238        ubifs_dump_node(c, c->mst_node);
 239        return -EINVAL;
 240}
 241
 242/**
 243 * ubifs_read_master - read master node.
 244 * @c: UBIFS file-system description object
 245 *
 246 * This function finds and reads the master node during file-system mount. If
 247 * the flash is empty, it creates default master node as well. Returns zero in
 248 * case of success and a negative error code in case of failure.
 249 */
 250int ubifs_read_master(struct ubifs_info *c)
 251{
 252        int err, old_leb_cnt;
 253
 254        c->mst_node = kzalloc(c->mst_node_alsz, GFP_KERNEL);
 255        if (!c->mst_node)
 256                return -ENOMEM;
 257
 258        err = scan_for_master(c);
 259        if (err) {
 260                if (err == -EUCLEAN)
 261                        err = ubifs_recover_master_node(c);
 262                if (err)
 263                        /*
 264                         * Note, we do not free 'c->mst_node' here because the
 265                         * unmount routine will take care of this.
 266                         */
 267                        return err;
 268        }
 269
 270        /* Make sure that the recovery flag is clear */
 271        c->mst_node->flags &= cpu_to_le32(~UBIFS_MST_RCVRY);
 272
 273        c->max_sqnum       = le64_to_cpu(c->mst_node->ch.sqnum);
 274        c->highest_inum    = le64_to_cpu(c->mst_node->highest_inum);
 275        c->cmt_no          = le64_to_cpu(c->mst_node->cmt_no);
 276        c->zroot.lnum      = le32_to_cpu(c->mst_node->root_lnum);
 277        c->zroot.offs      = le32_to_cpu(c->mst_node->root_offs);
 278        c->zroot.len       = le32_to_cpu(c->mst_node->root_len);
 279        c->lhead_lnum      = le32_to_cpu(c->mst_node->log_lnum);
 280        c->gc_lnum         = le32_to_cpu(c->mst_node->gc_lnum);
 281        c->ihead_lnum      = le32_to_cpu(c->mst_node->ihead_lnum);
 282        c->ihead_offs      = le32_to_cpu(c->mst_node->ihead_offs);
 283        c->bi.old_idx_sz   = le64_to_cpu(c->mst_node->index_size);
 284        c->lpt_lnum        = le32_to_cpu(c->mst_node->lpt_lnum);
 285        c->lpt_offs        = le32_to_cpu(c->mst_node->lpt_offs);
 286        c->nhead_lnum      = le32_to_cpu(c->mst_node->nhead_lnum);
 287        c->nhead_offs      = le32_to_cpu(c->mst_node->nhead_offs);
 288        c->ltab_lnum       = le32_to_cpu(c->mst_node->ltab_lnum);
 289        c->ltab_offs       = le32_to_cpu(c->mst_node->ltab_offs);
 290        c->lsave_lnum      = le32_to_cpu(c->mst_node->lsave_lnum);
 291        c->lsave_offs      = le32_to_cpu(c->mst_node->lsave_offs);
 292        c->lscan_lnum      = le32_to_cpu(c->mst_node->lscan_lnum);
 293        c->lst.empty_lebs  = le32_to_cpu(c->mst_node->empty_lebs);
 294        c->lst.idx_lebs    = le32_to_cpu(c->mst_node->idx_lebs);
 295        old_leb_cnt        = le32_to_cpu(c->mst_node->leb_cnt);
 296        c->lst.total_free  = le64_to_cpu(c->mst_node->total_free);
 297        c->lst.total_dirty = le64_to_cpu(c->mst_node->total_dirty);
 298        c->lst.total_used  = le64_to_cpu(c->mst_node->total_used);
 299        c->lst.total_dead  = le64_to_cpu(c->mst_node->total_dead);
 300        c->lst.total_dark  = le64_to_cpu(c->mst_node->total_dark);
 301
 302        c->calc_idx_sz = c->bi.old_idx_sz;
 303
 304        if (c->mst_node->flags & cpu_to_le32(UBIFS_MST_NO_ORPHS))
 305                c->no_orphs = 1;
 306
 307        if (old_leb_cnt != c->leb_cnt) {
 308                /* The file system has been resized */
 309                int growth = c->leb_cnt - old_leb_cnt;
 310
 311                if (c->leb_cnt < old_leb_cnt ||
 312                    c->leb_cnt < UBIFS_MIN_LEB_CNT) {
 313                        ubifs_err(c, "bad leb_cnt on master node");
 314                        ubifs_dump_node(c, c->mst_node);
 315                        return -EINVAL;
 316                }
 317
 318                dbg_mnt("Auto resizing (master) from %d LEBs to %d LEBs",
 319                        old_leb_cnt, c->leb_cnt);
 320                c->lst.empty_lebs += growth;
 321                c->lst.total_free += growth * (long long)c->leb_size;
 322                c->lst.total_dark += growth * (long long)c->dark_wm;
 323
 324                /*
 325                 * Reflect changes back onto the master node. N.B. the master
 326                 * node gets written immediately whenever mounting (or
 327                 * remounting) in read-write mode, so we do not need to write it
 328                 * here.
 329                 */
 330                c->mst_node->leb_cnt = cpu_to_le32(c->leb_cnt);
 331                c->mst_node->empty_lebs = cpu_to_le32(c->lst.empty_lebs);
 332                c->mst_node->total_free = cpu_to_le64(c->lst.total_free);
 333                c->mst_node->total_dark = cpu_to_le64(c->lst.total_dark);
 334        }
 335
 336        err = validate_master(c);
 337        if (err)
 338                return err;
 339
 340#ifndef __UBOOT__
 341        err = dbg_old_index_check_init(c, &c->zroot);
 342#endif
 343
 344        return err;
 345}
 346
 347#ifndef __UBOOT__
 348/**
 349 * ubifs_write_master - write master node.
 350 * @c: UBIFS file-system description object
 351 *
 352 * This function writes the master node. Returns zero in case of success and a
 353 * negative error code in case of failure. The master node is written twice to
 354 * enable recovery.
 355 */
 356int ubifs_write_master(struct ubifs_info *c)
 357{
 358        int err, lnum, offs, len;
 359
 360        ubifs_assert(!c->ro_media && !c->ro_mount);
 361        if (c->ro_error)
 362                return -EROFS;
 363
 364        lnum = UBIFS_MST_LNUM;
 365        offs = c->mst_offs + c->mst_node_alsz;
 366        len = UBIFS_MST_NODE_SZ;
 367
 368        if (offs + UBIFS_MST_NODE_SZ > c->leb_size) {
 369                err = ubifs_leb_unmap(c, lnum);
 370                if (err)
 371                        return err;
 372                offs = 0;
 373        }
 374
 375        c->mst_offs = offs;
 376        c->mst_node->highest_inum = cpu_to_le64(c->highest_inum);
 377
 378        err = ubifs_write_node(c, c->mst_node, len, lnum, offs);
 379        if (err)
 380                return err;
 381
 382        lnum += 1;
 383
 384        if (offs == 0) {
 385                err = ubifs_leb_unmap(c, lnum);
 386                if (err)
 387                        return err;
 388        }
 389        err = ubifs_write_node(c, c->mst_node, len, lnum, offs);
 390
 391        return err;
 392}
 393#endif
 394