1/* 2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. 3 * 4 * Copyright (C) 2002-2010 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#include "yaffs_tagsvalidity.h" 18 19/* This code packs a set of extended tags into a binary structure for 20 * NAND storage 21 */ 22 23/* Some of the information is "extra" struff which can be packed in to 24 * speed scanning 25 * This is defined by having the EXTRA_HEADER_INFO_FLAG set. 26 */ 27 28/* Extra flags applied to chunk_id */ 29 30#define EXTRA_HEADER_INFO_FLAG 0x80000000 31#define EXTRA_SHRINK_FLAG 0x40000000 32#define EXTRA_SHADOWS_FLAG 0x20000000 33#define EXTRA_SPARE_FLAGS 0x10000000 34 35#define ALL_EXTRA_FLAGS 0xF0000000 36 37/* Also, the top 4 bits of the object Id are set to the object type. */ 38#define EXTRA_OBJECT_TYPE_SHIFT (28) 39#define EXTRA_OBJECT_TYPE_MASK ((0x0F) << EXTRA_OBJECT_TYPE_SHIFT) 40 41 42static void yaffs_DumpPackedTags2TagsPart(const yaffs_PackedTags2TagsPart *ptt) 43{ 44 T(YAFFS_TRACE_MTD, 45 (TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR), 46 ptt->obj_id, ptt->chunk_id, ptt->n_bytes, 47 ptt->seq_number)); 48} 49static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 *pt) 50{ 51 yaffs_DumpPackedTags2TagsPart(&pt->t); 52} 53 54static void yaffs_DumpTags2(const yaffs_ext_tags *t) 55{ 56 T(YAFFS_TRACE_MTD, 57 (TSTR 58 ("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d" 59 TENDSTR), t->ecc_result, t->block_bad, t->chunk_used, t->obj_id, 60 t->chunk_id, t->n_bytes, t->is_deleted, t->serial_number, 61 t->seq_number)); 62 63} 64 65void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *ptt, 66 const yaffs_ext_tags *t) 67{ 68 ptt->chunk_id = t->chunk_id; 69 ptt->seq_number = t->seq_number; 70 ptt->n_bytes = t->n_bytes; 71 ptt->obj_id = t->obj_id; 72 73 if (t->chunk_id == 0 && t->extra_available) { 74 /* Store the extra header info instead */ 75 /* We save the parent object in the chunk_id */ 76 ptt->chunk_id = EXTRA_HEADER_INFO_FLAG 77 | t->extra_parent_id; 78 if (t->extra_is_shrink) 79 ptt->chunk_id |= EXTRA_SHRINK_FLAG; 80 if (t->extra_shadows) 81 ptt->chunk_id |= EXTRA_SHADOWS_FLAG; 82 83 ptt->obj_id &= ~EXTRA_OBJECT_TYPE_MASK; 84 ptt->obj_id |= 85 (t->extra_obj_type << EXTRA_OBJECT_TYPE_SHIFT); 86 87 if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK) 88 ptt->n_bytes = t->extra_equiv_id; 89 else if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE) 90 ptt->n_bytes = t->extra_length; 91 else 92 ptt->n_bytes = 0; 93 } 94 95 yaffs_DumpPackedTags2TagsPart(ptt); 96 yaffs_DumpTags2(t); 97} 98 99 100void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ext_tags *t, int tagsECC) 101{ 102 yaffs_PackTags2TagsPart(&pt->t, t); 103 104 if(tagsECC) 105 yaffs_ecc_calc_other((unsigned char *)&pt->t, 106 sizeof(yaffs_PackedTags2TagsPart), 107 &pt->ecc); 108} 109 110 111void yaffs_unpack_tags2tags_part(yaffs_ext_tags *t, 112 yaffs_PackedTags2TagsPart *ptt) 113{ 114 115 memset(t, 0, sizeof(yaffs_ext_tags)); 116 117 yaffs_init_tags(t); 118 119 if (ptt->seq_number != 0xFFFFFFFF) { 120 t->block_bad = 0; 121 t->chunk_used = 1; 122 t->obj_id = ptt->obj_id; 123 t->chunk_id = ptt->chunk_id; 124 t->n_bytes = ptt->n_bytes; 125 t->is_deleted = 0; 126 t->serial_number = 0; 127 t->seq_number = ptt->seq_number; 128 129 /* Do extra header info stuff */ 130 131 if (ptt->chunk_id & EXTRA_HEADER_INFO_FLAG) { 132 t->chunk_id = 0; 133 t->n_bytes = 0; 134 135 t->extra_available = 1; 136 t->extra_parent_id = 137 ptt->chunk_id & (~(ALL_EXTRA_FLAGS)); 138 t->extra_is_shrink = 139 (ptt->chunk_id & EXTRA_SHRINK_FLAG) ? 1 : 0; 140 t->extra_shadows = 141 (ptt->chunk_id & EXTRA_SHADOWS_FLAG) ? 1 : 0; 142 t->extra_obj_type = 143 ptt->obj_id >> EXTRA_OBJECT_TYPE_SHIFT; 144 t->obj_id &= ~EXTRA_OBJECT_TYPE_MASK; 145 146 if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK) 147 t->extra_equiv_id = ptt->n_bytes; 148 else 149 t->extra_length = ptt->n_bytes; 150 } 151 } 152 153 yaffs_DumpPackedTags2TagsPart(ptt); 154 yaffs_DumpTags2(t); 155 156} 157 158 159void yaffs_unpack_tags2(yaffs_ext_tags *t, yaffs_PackedTags2 *pt, int tagsECC) 160{ 161 162 yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_NO_ERROR; 163 164 if (pt->t.seq_number != 0xFFFFFFFF && 165 tagsECC){ 166 /* Chunk is in use and we need to do ECC */ 167 168 yaffs_ECCOther ecc; 169 int result; 170 yaffs_ecc_calc_other((unsigned char *)&pt->t, 171 sizeof(yaffs_PackedTags2TagsPart), 172 &ecc); 173 result = yaffs_ecc_correct_other((unsigned char *)&pt->t, 174 sizeof(yaffs_PackedTags2TagsPart), 175 &pt->ecc, &ecc); 176 switch (result) { 177 case 0: 178 ecc_result = YAFFS_ECC_RESULT_NO_ERROR; 179 break; 180 case 1: 181 ecc_result = YAFFS_ECC_RESULT_FIXED; 182 break; 183 case -1: 184 ecc_result = YAFFS_ECC_RESULT_UNFIXED; 185 break; 186 default: 187 ecc_result = YAFFS_ECC_RESULT_UNKNOWN; 188 } 189 } 190 191 yaffs_unpack_tags2tags_part(t, &pt->t); 192 193 t->ecc_result = ecc_result; 194 195 yaffs_DumpPackedTags2(pt); 196 yaffs_DumpTags2(t); 197} 198 199