uboot/fs/yaffs2/yaffs_packedtags2.c
<<
>>
Prefs
   1/*
   2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
   3 *
   4 * Copyright (C) 2002-2011 Aleph One Ltd.
   5 *   for Toby Churchill Ltd and Brightstar Engineering
   6 *
   7 * Created by Charles Manning <charles@aleph1.co.uk>
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License version 2 as
  11 * published by the Free Software Foundation.
  12 */
  13
  14#include "yaffs_packedtags2.h"
  15#include "yportenv.h"
  16#include "yaffs_trace.h"
  17
  18/* This code packs a set of extended tags into a binary structure for
  19 * NAND storage
  20 */
  21
  22/* Some of the information is "extra" struff which can be packed in to
  23 * speed scanning
  24 * This is defined by having the EXTRA_HEADER_INFO_FLAG set.
  25 */
  26
  27/* Extra flags applied to chunk_id */
  28
  29#define EXTRA_HEADER_INFO_FLAG  0x80000000
  30#define EXTRA_SHRINK_FLAG       0x40000000
  31#define EXTRA_SHADOWS_FLAG      0x20000000
  32#define EXTRA_SPARE_FLAGS       0x10000000
  33
  34#define ALL_EXTRA_FLAGS         0xf0000000
  35
  36/* Also, the top 4 bits of the object Id are set to the object type. */
  37#define EXTRA_OBJECT_TYPE_SHIFT (28)
  38#define EXTRA_OBJECT_TYPE_MASK  ((0x0f) << EXTRA_OBJECT_TYPE_SHIFT)
  39
  40static void yaffs_dump_packed_tags2_tags_only(
  41                                const struct yaffs_packed_tags2_tags_only *ptt)
  42{
  43        yaffs_trace(YAFFS_TRACE_MTD,
  44                "packed tags obj %d chunk %d byte %d seq %d",
  45                ptt->obj_id, ptt->chunk_id, ptt->n_bytes, ptt->seq_number);
  46}
  47
  48static void yaffs_dump_packed_tags2(const struct yaffs_packed_tags2 *pt)
  49{
  50        yaffs_dump_packed_tags2_tags_only(&pt->t);
  51}
  52
  53static void yaffs_dump_tags2(const struct yaffs_ext_tags *t)
  54{
  55        yaffs_trace(YAFFS_TRACE_MTD,
  56                "ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d",
  57                t->ecc_result, t->block_bad, t->chunk_used, t->obj_id,
  58                t->chunk_id, t->n_bytes, t->is_deleted, t->serial_number,
  59                t->seq_number);
  60
  61}
  62
  63static int yaffs_check_tags_extra_packable(const struct yaffs_ext_tags *t)
  64{
  65        if (t->chunk_id != 0 || !t->extra_available)
  66                return 0;
  67
  68        /* Check if the file size is too long to store */
  69        if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE &&
  70            (t->extra_file_size >> 31) != 0)
  71                return 0;
  72        return 1;
  73}
  74
  75void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *ptt,
  76                                const struct yaffs_ext_tags *t)
  77{
  78        ptt->chunk_id = t->chunk_id;
  79        ptt->seq_number = t->seq_number;
  80        ptt->n_bytes = t->n_bytes;
  81        ptt->obj_id = t->obj_id;
  82
  83        /* Only store extra tags for object headers.
  84         * If it is a file then only store  if the file size is short\
  85         * enough to fit.
  86         */
  87        if (yaffs_check_tags_extra_packable(t)) {
  88                /* Store the extra header info instead */
  89                /* We save the parent object in the chunk_id */
  90                ptt->chunk_id = EXTRA_HEADER_INFO_FLAG | t->extra_parent_id;
  91                if (t->extra_is_shrink)
  92                        ptt->chunk_id |= EXTRA_SHRINK_FLAG;
  93                if (t->extra_shadows)
  94                        ptt->chunk_id |= EXTRA_SHADOWS_FLAG;
  95
  96                ptt->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
  97                ptt->obj_id |= (t->extra_obj_type << EXTRA_OBJECT_TYPE_SHIFT);
  98
  99                if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
 100                        ptt->n_bytes = t->extra_equiv_id;
 101                else if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE)
 102                        ptt->n_bytes = (unsigned) t->extra_file_size;
 103                else
 104                        ptt->n_bytes = 0;
 105        }
 106
 107        yaffs_dump_packed_tags2_tags_only(ptt);
 108        yaffs_dump_tags2(t);
 109}
 110
 111void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
 112                      const struct yaffs_ext_tags *t, int tags_ecc)
 113{
 114        yaffs_pack_tags2_tags_only(&pt->t, t);
 115
 116        if (tags_ecc)
 117                yaffs_ecc_calc_other((unsigned char *)&pt->t,
 118                                    sizeof(struct yaffs_packed_tags2_tags_only),
 119                                    &pt->ecc);
 120}
 121
 122void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,
 123                                  struct yaffs_packed_tags2_tags_only *ptt)
 124{
 125        memset(t, 0, sizeof(struct yaffs_ext_tags));
 126
 127        if (ptt->seq_number == 0xffffffff)
 128                return;
 129
 130        t->block_bad = 0;
 131        t->chunk_used = 1;
 132        t->obj_id = ptt->obj_id;
 133        t->chunk_id = ptt->chunk_id;
 134        t->n_bytes = ptt->n_bytes;
 135        t->is_deleted = 0;
 136        t->serial_number = 0;
 137        t->seq_number = ptt->seq_number;
 138
 139        /* Do extra header info stuff */
 140        if (ptt->chunk_id & EXTRA_HEADER_INFO_FLAG) {
 141                t->chunk_id = 0;
 142                t->n_bytes = 0;
 143
 144                t->extra_available = 1;
 145                t->extra_parent_id = ptt->chunk_id & (~(ALL_EXTRA_FLAGS));
 146                t->extra_is_shrink = ptt->chunk_id & EXTRA_SHRINK_FLAG ? 1 : 0;
 147                t->extra_shadows = ptt->chunk_id & EXTRA_SHADOWS_FLAG ? 1 : 0;
 148                t->extra_obj_type = ptt->obj_id >> EXTRA_OBJECT_TYPE_SHIFT;
 149                t->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
 150
 151                if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
 152                        t->extra_equiv_id = ptt->n_bytes;
 153                else
 154                        t->extra_file_size = ptt->n_bytes;
 155        }
 156        yaffs_dump_packed_tags2_tags_only(ptt);
 157        yaffs_dump_tags2(t);
 158}
 159
 160void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
 161                        int tags_ecc)
 162{
 163        enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
 164
 165        if (pt->t.seq_number != 0xffffffff && tags_ecc) {
 166                /* Chunk is in use and we need to do ECC */
 167
 168                struct yaffs_ecc_other ecc;
 169                int result;
 170                yaffs_ecc_calc_other((unsigned char *)&pt->t,
 171                                sizeof(struct yaffs_packed_tags2_tags_only),
 172                                &ecc);
 173                result =
 174                    yaffs_ecc_correct_other((unsigned char *)&pt->t,
 175                                sizeof(struct yaffs_packed_tags2_tags_only),
 176                                &pt->ecc, &ecc);
 177                switch (result) {
 178                case 0:
 179                        ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
 180                        break;
 181                case 1:
 182                        ecc_result = YAFFS_ECC_RESULT_FIXED;
 183                        break;
 184                case -1:
 185                        ecc_result = YAFFS_ECC_RESULT_UNFIXED;
 186                        break;
 187                default:
 188                        ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
 189                }
 190        }
 191        yaffs_unpack_tags2_tags_only(t, &pt->t);
 192
 193        t->ecc_result = ecc_result;
 194
 195        yaffs_dump_packed_tags2(pt);
 196        yaffs_dump_tags2(t);
 197}
 198