yaffs_packedtags2.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  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. #include "yaffs_packedtags2.h"
  14. #include "yportenv.h"
  15. #include "yaffs_trace.h"
  16. /* This code packs a set of extended tags into a binary structure for
  17. * NAND storage
  18. */
  19. /* Some of the information is "extra" struff which can be packed in to
  20. * speed scanning
  21. * This is defined by having the EXTRA_HEADER_INFO_FLAG set.
  22. */
  23. /* Extra flags applied to chunk_id */
  24. #define EXTRA_HEADER_INFO_FLAG 0x80000000
  25. #define EXTRA_SHRINK_FLAG 0x40000000
  26. #define EXTRA_SHADOWS_FLAG 0x20000000
  27. #define EXTRA_SPARE_FLAGS 0x10000000
  28. #define ALL_EXTRA_FLAGS 0xf0000000
  29. /* Also, the top 4 bits of the object Id are set to the object type. */
  30. #define EXTRA_OBJECT_TYPE_SHIFT (28)
  31. #define EXTRA_OBJECT_TYPE_MASK ((0x0f) << EXTRA_OBJECT_TYPE_SHIFT)
  32. static void yaffs_dump_packed_tags2_tags_only(
  33. const struct yaffs_packed_tags2_tags_only *ptt)
  34. {
  35. yaffs_trace(YAFFS_TRACE_MTD,
  36. "packed tags obj %d chunk %d byte %d seq %d",
  37. ptt->obj_id, ptt->chunk_id, ptt->n_bytes, ptt->seq_number);
  38. }
  39. static void yaffs_dump_packed_tags2(const struct yaffs_packed_tags2 *pt)
  40. {
  41. yaffs_dump_packed_tags2_tags_only(&pt->t);
  42. }
  43. static void yaffs_dump_tags2(const struct yaffs_ext_tags *t)
  44. {
  45. yaffs_trace(YAFFS_TRACE_MTD,
  46. "ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d",
  47. t->ecc_result, t->block_bad, t->chunk_used, t->obj_id,
  48. t->chunk_id, t->n_bytes, t->is_deleted, t->serial_number,
  49. t->seq_number);
  50. }
  51. static int yaffs_check_tags_extra_packable(const struct yaffs_ext_tags *t)
  52. {
  53. if (t->chunk_id != 0 || !t->extra_available)
  54. return 0;
  55. /* Check if the file size is too long to store */
  56. if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE &&
  57. (t->extra_file_size >> 31) != 0)
  58. return 0;
  59. return 1;
  60. }
  61. void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *ptt,
  62. const struct yaffs_ext_tags *t)
  63. {
  64. ptt->chunk_id = t->chunk_id;
  65. ptt->seq_number = t->seq_number;
  66. ptt->n_bytes = t->n_bytes;
  67. ptt->obj_id = t->obj_id;
  68. /* Only store extra tags for object headers.
  69. * If it is a file then only store if the file size is short\
  70. * enough to fit.
  71. */
  72. if (yaffs_check_tags_extra_packable(t)) {
  73. /* Store the extra header info instead */
  74. /* We save the parent object in the chunk_id */
  75. ptt->chunk_id = EXTRA_HEADER_INFO_FLAG | t->extra_parent_id;
  76. if (t->extra_is_shrink)
  77. ptt->chunk_id |= EXTRA_SHRINK_FLAG;
  78. if (t->extra_shadows)
  79. ptt->chunk_id |= EXTRA_SHADOWS_FLAG;
  80. ptt->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
  81. ptt->obj_id |= (t->extra_obj_type << EXTRA_OBJECT_TYPE_SHIFT);
  82. if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
  83. ptt->n_bytes = t->extra_equiv_id;
  84. else if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE)
  85. ptt->n_bytes = (unsigned) t->extra_file_size;
  86. else
  87. ptt->n_bytes = 0;
  88. }
  89. yaffs_dump_packed_tags2_tags_only(ptt);
  90. yaffs_dump_tags2(t);
  91. }
  92. void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
  93. const struct yaffs_ext_tags *t, int tags_ecc)
  94. {
  95. yaffs_pack_tags2_tags_only(&pt->t, t);
  96. if (tags_ecc)
  97. yaffs_ecc_calc_other((unsigned char *)&pt->t,
  98. sizeof(struct yaffs_packed_tags2_tags_only),
  99. &pt->ecc);
  100. }
  101. void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,
  102. struct yaffs_packed_tags2_tags_only *ptt)
  103. {
  104. memset(t, 0, sizeof(struct yaffs_ext_tags));
  105. if (ptt->seq_number == 0xffffffff)
  106. return;
  107. t->block_bad = 0;
  108. t->chunk_used = 1;
  109. t->obj_id = ptt->obj_id;
  110. t->chunk_id = ptt->chunk_id;
  111. t->n_bytes = ptt->n_bytes;
  112. t->is_deleted = 0;
  113. t->serial_number = 0;
  114. t->seq_number = ptt->seq_number;
  115. /* Do extra header info stuff */
  116. if (ptt->chunk_id & EXTRA_HEADER_INFO_FLAG) {
  117. t->chunk_id = 0;
  118. t->n_bytes = 0;
  119. t->extra_available = 1;
  120. t->extra_parent_id = ptt->chunk_id & (~(ALL_EXTRA_FLAGS));
  121. t->extra_is_shrink = ptt->chunk_id & EXTRA_SHRINK_FLAG ? 1 : 0;
  122. t->extra_shadows = ptt->chunk_id & EXTRA_SHADOWS_FLAG ? 1 : 0;
  123. t->extra_obj_type = ptt->obj_id >> EXTRA_OBJECT_TYPE_SHIFT;
  124. t->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
  125. if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
  126. t->extra_equiv_id = ptt->n_bytes;
  127. else
  128. t->extra_file_size = ptt->n_bytes;
  129. }
  130. yaffs_dump_packed_tags2_tags_only(ptt);
  131. yaffs_dump_tags2(t);
  132. }
  133. void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
  134. int tags_ecc)
  135. {
  136. enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
  137. if (pt->t.seq_number != 0xffffffff && tags_ecc) {
  138. /* Chunk is in use and we need to do ECC */
  139. struct yaffs_ecc_other ecc;
  140. int result;
  141. yaffs_ecc_calc_other((unsigned char *)&pt->t,
  142. sizeof(struct yaffs_packed_tags2_tags_only),
  143. &ecc);
  144. result =
  145. yaffs_ecc_correct_other((unsigned char *)&pt->t,
  146. sizeof(struct yaffs_packed_tags2_tags_only),
  147. &pt->ecc, &ecc);
  148. switch (result) {
  149. case 0:
  150. ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
  151. break;
  152. case 1:
  153. ecc_result = YAFFS_ECC_RESULT_FIXED;
  154. break;
  155. case -1:
  156. ecc_result = YAFFS_ECC_RESULT_UNFIXED;
  157. break;
  158. default:
  159. ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
  160. }
  161. }
  162. yaffs_unpack_tags2_tags_only(t, &pt->t);
  163. t->ecc_result = ecc_result;
  164. yaffs_dump_packed_tags2(pt);
  165. yaffs_dump_tags2(t);
  166. }