nxffs_pack.c 51 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611
  1. /****************************************************************************
  2. * fs/nxffs/nxffs_pack.c
  3. *
  4. * Copyright (C) 2011, 2013 Gregory Nutt. All rights reserved.
  5. * Author: Gregory Nutt <gnutt@nuttx.org>
  6. *
  7. * References: Linux/Documentation/filesystems/romfs.txt
  8. *
  9. * Redistribution and use in source and binary forms, with or without
  10. * modification, are permitted provided that the following conditions
  11. * are met:
  12. *
  13. * 1. Redistributions of source code must retain the above copyright
  14. * notice, this list of conditions and the following disclaimer.
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in
  17. * the documentation and/or other materials provided with the
  18. * distribution.
  19. * 3. Neither the name NuttX nor the names of its contributors may be
  20. * used to endorse or promote products derived from this software
  21. * without specific prior written permission.
  22. *
  23. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  24. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  25. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  26. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  27. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  28. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  29. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  30. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  31. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  33. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  34. * POSSIBILITY OF SUCH DAMAGE.
  35. *
  36. ****************************************************************************/
  37. /****************************************************************************
  38. * Included Files
  39. ****************************************************************************/
  40. #include <nuttx/config.h>
  41. #include <string.h>
  42. #include <errno.h>
  43. #include <assert.h>
  44. #include <crc32.h>
  45. #include <debug.h>
  46. #include <nuttx/kmalloc.h>
  47. #include "nxffs.h"
  48. /****************************************************************************
  49. * Pre-processor Definitions
  50. ****************************************************************************/
  51. /****************************************************************************
  52. * Public Types
  53. ****************************************************************************/
  54. /* This structure supports access to one inode data stream */
  55. struct nxffs_packstream_s
  56. {
  57. struct nxffs_entry_s entry; /* Describes the inode header */
  58. off_t fpos; /* Current file position */
  59. off_t blkoffset; /* Offset to the current data block */
  60. uint16_t blklen; /* Size of this block */
  61. uint16_t blkpos; /* Position in block corresponding to fpos */
  62. };
  63. /* The structure supports the overall packing operation */
  64. struct nxffs_pack_s
  65. {
  66. /* These describe the source and destination streams */
  67. struct nxffs_packstream_s src;
  68. struct nxffs_packstream_s dest;
  69. /* These describe the state of the current contents of the (destination)
  70. * volume->pack buffer.
  71. */
  72. FAR uint8_t *iobuffer; /* I/O block start position */
  73. off_t ioblock; /* I/O block number */
  74. off_t block0; /* First I/O block number in the erase block */
  75. uint16_t iooffset; /* I/O block offset */
  76. };
  77. /****************************************************************************
  78. * Private Functions
  79. ****************************************************************************/
  80. /****************************************************************************
  81. * Name: nxffs_getblock
  82. *
  83. * Description:
  84. * Return the I/O block number that includes the provided offset.
  85. *
  86. * Input Parameters:
  87. * volume - Describes the NXFFS volume
  88. * offset - FLASH offset
  89. *
  90. * Returned Value:
  91. * The I/O block number.
  92. *
  93. ****************************************************************************/
  94. static off_t nxffs_getblock(FAR struct nxffs_volume_s *volume, off_t offset)
  95. {
  96. return offset / volume->geo.blocksize;
  97. }
  98. /****************************************************************************
  99. * Name: nxffs_getoffset
  100. *
  101. * Description:
  102. * Given an I/O block number return the block offset corresponding to the
  103. * FLASH offset;
  104. *
  105. * Input Parameters:
  106. * volume - Describes the NXFFS volume
  107. * offset - FLASH offset
  108. *
  109. * Returned Value:
  110. * The I/O block number.
  111. *
  112. ****************************************************************************/
  113. static off_t nxffs_getoffset(FAR struct nxffs_volume_s *volume,
  114. off_t offset, off_t block)
  115. {
  116. return offset - block * volume->geo.blocksize;
  117. }
  118. /****************************************************************************
  119. * Name: nxffs_packtell
  120. *
  121. * Description:
  122. * Report the current destination position in the pack buffer.
  123. *
  124. * Input Parameters:
  125. * volume - Describes the NXFFS volume
  126. * pack - The volume packing state structure.
  127. *
  128. * Returned Value:
  129. * The offset from the beginning of FLASH to the current seek position.
  130. *
  131. ****************************************************************************/
  132. static off_t nxffs_packtell(FAR struct nxffs_volume_s *volume,
  133. FAR struct nxffs_pack_s *pack)
  134. {
  135. return pack->ioblock * volume->geo.blocksize + pack->iooffset;
  136. }
  137. /****************************************************************************
  138. * Name: nxffs_packvalid
  139. *
  140. * Description:
  141. * Check if the current destination block is valid.
  142. *
  143. * Input Parameters:
  144. * pack - The volume packing state structure.
  145. *
  146. * Returned Value:
  147. * None
  148. *
  149. ****************************************************************************/
  150. static inline bool nxffs_packvalid(FAR struct nxffs_pack_s *pack)
  151. {
  152. FAR struct nxffs_block_s *blkhdr;
  153. blkhdr = (FAR struct nxffs_block_s *)pack->iobuffer;
  154. return (memcmp(blkhdr->magic, g_blockmagic, NXFFS_MAGICSIZE) == 0 &&
  155. blkhdr->state == BLOCK_STATE_GOOD);
  156. }
  157. /****************************************************************************
  158. * Name: nxffs_mediacheck
  159. *
  160. * Description:
  161. * Verify that there is at least one valid block and at least one valid
  162. * inode header on the media. On successful return, the volume packing
  163. * structure is initialized and contains the offset to the first valid
  164. * inode header is returned.
  165. *
  166. * Input Parameters:
  167. * volume - The volume to be packed.
  168. * pack - The volume packing state structure.
  169. *
  170. * Returned Value:
  171. * The offset to the data area on the first valid block. Zero is return
  172. * if there are no valid blocks or if there are no valid inode headers
  173. * after the first valid block.
  174. *
  175. ****************************************************************************/
  176. static inline off_t nxffs_mediacheck(FAR struct nxffs_volume_s *volume,
  177. FAR struct nxffs_pack_s *pack)
  178. {
  179. off_t froffset;
  180. int ret;
  181. /* Initialize the packing structure to all zero */
  182. memset(pack, 0, sizeof(struct nxffs_pack_s));
  183. /* Find the FLASH offset to the first valid block */
  184. volume->ioblock = 0;
  185. ret = nxffs_validblock(volume, &volume->ioblock);
  186. if (ret < 0)
  187. {
  188. /* No valid blocks? Return offset zero. */
  189. return 0;
  190. }
  191. /* The offset to the free location to pack is then just after the block
  192. * header in this block.
  193. */
  194. volume->iooffset = SIZEOF_NXFFS_BLOCK_HDR;
  195. froffset = nxffs_iotell(volume);
  196. /* Get the offset to the first valid inode entry after this free offset */
  197. ret = nxffs_nextentry(volume, froffset, &pack->src.entry);
  198. if (ret < 0)
  199. {
  200. /* No valid entries on the media -- Return offset zero */
  201. return 0;
  202. }
  203. /* Okay.. the start block and first entry have been found */
  204. return froffset;
  205. }
  206. /****************************************************************************
  207. * Name: nxffs_startpos
  208. *
  209. * Description:
  210. * Find the position in FLASH memory where we should begin packing. That
  211. * position is the place where there is a gap between the last and the next
  212. * valid inode. On entry, the volume packing structure should be as it
  213. * was initialized by nxffx_mediacheck. on successful return, the volume
  214. * packing state structure will be updated to begin the packing operation.
  215. *
  216. * Input Parameters:
  217. * volume - The volume to be packed
  218. * pack - The volume packing state structure.
  219. * froffset - On input, this is the location where we should be searching
  220. * for the location to begin packing. On successful return, froffset
  221. * will be set to the offset in FLASH where the first inode should be
  222. * copied to. If -ENOSPC is returned -- meaning that the FLASH is full
  223. * -- then no packing can be performed. In this case, then the free
  224. * flash offset is returned through this location.
  225. *
  226. * Returned Value:
  227. * Zero on success; Otherwise, a negated errno value is returned to
  228. * indicate the nature of the failure. If -ENOSPC is returned then the
  229. * free FLASH offset is also returned.
  230. *
  231. ****************************************************************************/
  232. static inline int nxffs_startpos(FAR struct nxffs_volume_s *volume,
  233. FAR struct nxffs_pack_s *pack,
  234. off_t *froffset)
  235. {
  236. struct nxffs_blkentry_s blkentry;
  237. off_t offset = *froffset;
  238. off_t wasted;
  239. off_t nbytes;
  240. int ret;
  241. /* Loop until we find a gap of unused FLASH large enough to warrant
  242. * compacting.
  243. */
  244. for (; ; )
  245. {
  246. /* Is there wasted space between the offset where the we could have
  247. * valid data and the offset to the beginning of the first valid
  248. * inode header? NOTE: The threshold check is not accurate, there
  249. * may or may not be intervening block headers making the separation
  250. * seem larger than it is.
  251. */
  252. DEBUGASSERT(pack->src.entry.hoffset >= offset);
  253. wasted = pack->src.entry.hoffset - offset;
  254. if (wasted > CONFIG_NXFFS_PACKTHRESHOLD)
  255. {
  256. /* This is where we must begin packing. Describe the destination
  257. * inode header (only non-zero entries need to be initialized).
  258. */
  259. pack->dest.entry.name = pack->src.entry.name;
  260. pack->dest.entry.utc = pack->src.entry.utc;
  261. pack->dest.entry.datlen = pack->src.entry.datlen;
  262. /* The destination entry now "owns" the name string */
  263. pack->src.entry.name = NULL;
  264. /* Return the FLASH offset to the destination inode header */
  265. *froffset = offset;
  266. return OK;
  267. }
  268. /* Free the allocated memory in the entry */
  269. nxffs_freeentry(&pack->src.entry);
  270. /* Update the offset to the first byte at the end of the last data
  271. * block.
  272. */
  273. nbytes = 0;
  274. offset = pack->src.entry.doffset;
  275. while (nbytes < pack->src.entry.datlen)
  276. {
  277. /* Read the next data block header */
  278. ret = nxffs_nextblock(volume, offset, &blkentry);
  279. if (ret < 0)
  280. {
  281. ferr("ERROR: Failed to find next data block: %d\n", -ret);
  282. return ret;
  283. }
  284. /* Get the number of blocks and pointer to where the next
  285. * data block might lie.
  286. */
  287. nbytes += blkentry.datlen;
  288. offset = blkentry.hoffset + SIZEOF_NXFFS_DATA_HDR + blkentry.datlen;
  289. }
  290. /* Make sure there is space at this location for an inode header */
  291. nxffs_ioseek(volume, offset);
  292. if (volume->iooffset + SIZEOF_NXFFS_INODE_HDR > volume->geo.blocksize)
  293. {
  294. /* No.. not enough space here. Find the next valid block */
  295. volume->ioblock++;
  296. ret = nxffs_validblock(volume, &volume->ioblock);
  297. if (ret < 0)
  298. {
  299. /* No valid blocks? Then there is nothing we can do. Return
  300. * the end-of-flash indication.
  301. */
  302. *froffset = volume->froffset;
  303. return -ENOSPC;
  304. }
  305. volume->iooffset = SIZEOF_NXFFS_BLOCK_HDR;
  306. offset = nxffs_iotell(volume);
  307. }
  308. /* Get the offset to the next valid inode entry */
  309. ret = nxffs_nextentry(volume, offset, &pack->src.entry);
  310. if (ret < 0)
  311. {
  312. /* No more valid inode entries. Just return an end-of-flash error
  313. * indication. However, there could be many deleted inodes; set
  314. * volume->froffset to indicate the true free FLASH position.
  315. */
  316. *froffset = offset;
  317. return -ENOSPC;
  318. }
  319. }
  320. /* We won't get here */
  321. return -ENOSYS;
  322. }
  323. /****************************************************************************
  324. * Name: nxffs_srcsetup
  325. *
  326. * Description:
  327. * Given a valid src inode, configure the src data stream.
  328. *
  329. * Input Parameters:
  330. * volume - The volume to be packed
  331. * pack - The volume packing state structure.
  332. * offset - FLASH offset to the data block header (will be zero for zero-
  333. * files.
  334. *
  335. * Returned Value:
  336. * Zero on success; Otherwise, a negated errno value is returned to
  337. * indicate the nature of the failure.
  338. *
  339. ****************************************************************************/
  340. static int nxffs_srcsetup(FAR struct nxffs_volume_s *volume,
  341. FAR struct nxffs_pack_s *pack, off_t offset)
  342. {
  343. /* Start with the first data block */
  344. pack->src.blkoffset = offset;
  345. pack->src.blkpos = 0;
  346. /* Zero-length files have no valid data block offset */
  347. if (offset > 0)
  348. {
  349. /* Seek to the data block header, read and verify the block header */
  350. int ret = nxffs_rdblkhdr(volume, offset, &pack->src.blklen);
  351. if (ret < 0)
  352. {
  353. ferr("ERROR: Failed to verify the data block header: %d\n", -ret);
  354. }
  355. return ret;
  356. }
  357. DEBUGASSERT(pack->src.entry.datlen == 0);
  358. return OK;
  359. }
  360. /****************************************************************************
  361. * Name: nxffs_destsetup
  362. *
  363. * Description:
  364. * Given a valid dest inode, configure the dest data stream.
  365. *
  366. * Input Parameters:
  367. * volume - The volume to be packed
  368. * pack - The volume packing state structure.
  369. *
  370. * Returned Value:
  371. * Zero on success; Otherwise, a negated errno value is returned to
  372. * indicate the nature of the failure.
  373. *
  374. ****************************************************************************/
  375. static int nxffs_destsetup(FAR struct nxffs_volume_s *volume,
  376. FAR struct nxffs_pack_s *pack)
  377. {
  378. size_t mindata;
  379. int namlen;
  380. int ret;
  381. /* The destination can be in one of three of states:
  382. *
  383. * State 1: The inode position was not yet been found. This condition can
  384. * only occur on initial entry into nxffs_packblock() when there we no space
  385. * for the inode header at the end of the previous block. We must now be
  386. * at the beginning of a shiny new I/O block, so we should always have
  387. * space for a new inode header right here.
  388. */
  389. if (pack->dest.entry.hoffset == 0)
  390. {
  391. /* Is there room for an inode structure in this block? */
  392. if (pack->iooffset + SIZEOF_NXFFS_INODE_HDR > volume->geo.blocksize)
  393. {
  394. /* No.. that inode name will not fit in this block. Return an
  395. * indication that we are at the end of the block and try again
  396. * later.
  397. */
  398. return -ENOSPC;
  399. }
  400. /* The inode header will be placed at this position (but not until
  401. * we are finished.
  402. */
  403. pack->dest.entry.hoffset = nxffs_packtell(volume, pack);
  404. /* Make sure that the initialize state of the inode header memory is
  405. * erased. This is important because we may not write to inode header
  406. * until it has already been written to FLASH.
  407. */
  408. memset(&pack->iobuffer[pack->iooffset], CONFIG_NXFFS_ERASEDSTATE,
  409. SIZEOF_NXFFS_INODE_HDR);
  410. /* Then set the new FLASH offset */
  411. pack->iooffset += SIZEOF_NXFFS_INODE_HDR;
  412. }
  413. /* State 2: inode position found, inode header not written, inode name
  414. * position not determined.
  415. */
  416. if (pack->dest.entry.noffset == 0)
  417. {
  418. /* Find the offset to the string memory. Will if fit in this block?
  419. * Note: iooffset has already been incremented to account for the
  420. * size of the inode header.
  421. */
  422. namlen = strlen(pack->dest.entry.name);
  423. if (pack->iooffset + namlen > volume->geo.blocksize)
  424. {
  425. /* No.. that inode name will not fit in this block. Return an
  426. * indication that we are at the end of the block and try again
  427. * later.
  428. */
  429. return -ENOSPC;
  430. }
  431. /* Yes.. Write the inode name to the volume packing buffer now, but do
  432. * not free the name string memory yet; it will be needed later to\
  433. * calculate the header CRC.
  434. */
  435. memcpy(&pack->iobuffer[pack->iooffset], pack->dest.entry.name, namlen);
  436. /* Reserve space for the inode name */
  437. pack->dest.entry.noffset = nxffs_packtell(volume, pack);
  438. pack->iooffset += namlen;
  439. }
  440. /* State 3: Inode header not-written, inode name written. Still need the position
  441. * of the first data block.
  442. *
  443. * Deal with the special case where the source inode is a zero length file
  444. * with no data blocks to be transferred.
  445. */
  446. if (pack->src.entry.doffset > 0)
  447. {
  448. if (pack->dest.entry.doffset == 0)
  449. {
  450. /* Will the data block header plus a minimal amount of data fit in this
  451. * block? (or the whole file if the file is very small).
  452. */
  453. mindata = MIN(NXFFS_MINDATA, pack->dest.entry.datlen);
  454. if (pack->iooffset + SIZEOF_NXFFS_DATA_HDR + mindata >
  455. volume->geo.blocksize)
  456. {
  457. /* No.. return an indication that we are at the end of the block
  458. * and try again later.
  459. */
  460. ret = -ENOSPC;
  461. goto errout;
  462. }
  463. /* Yes.. reserve space for the data block header */
  464. pack->dest.entry.doffset = nxffs_packtell(volume, pack);
  465. pack->iooffset += SIZEOF_NXFFS_DATA_HDR;
  466. /* Initialize the output data stream to start with the first data block */
  467. pack->dest.blkoffset = pack->dest.entry.doffset;
  468. pack->dest.blklen = 0;
  469. pack->dest.blkpos = 0;
  470. }
  471. /* State 4: Starting a new block. Verify that there is space in the current
  472. * block for another (minimal sized) block
  473. */
  474. if (pack->dest.blkoffset == 0)
  475. {
  476. /* Will the data block header plus a minimal amount of data fit in this
  477. * block? (or the whole file if the file is very small).
  478. */
  479. mindata = MIN(NXFFS_MINDATA, pack->dest.entry.datlen);
  480. if (pack->iooffset + SIZEOF_NXFFS_DATA_HDR + mindata >
  481. volume->geo.blocksize)
  482. {
  483. /* No.. return an indication that we are at the end of the block
  484. * and try again later.
  485. */
  486. ret = -ENOSPC;
  487. goto errout;
  488. }
  489. /* Yes.. reserve space for the data block header */
  490. pack->dest.blkoffset = nxffs_packtell(volume, pack);
  491. pack->iooffset += SIZEOF_NXFFS_DATA_HDR;
  492. pack->dest.blklen = 0;
  493. pack->dest.blkpos = 0;
  494. }
  495. }
  496. ret = OK;
  497. errout:
  498. volume->froffset = nxffs_packtell(volume, pack);
  499. return ret;
  500. }
  501. /****************************************************************************
  502. * Name: nxffs_wrinodehdr
  503. *
  504. * Description:
  505. * Write the destination inode header (only) to FLASH. Note that the inode
  506. * name has already been written to FLASH (thus greatly simplifying the
  507. * the complexity of this operation).
  508. *
  509. * Input Parameters:
  510. * volume - The volume to be packed
  511. * pack - The volume packing state structure.
  512. *
  513. * Returned Value:
  514. * Zero on success; Otherwise, a negated errno value is returned to
  515. * indicate the nature of the failure (not used).
  516. *
  517. ****************************************************************************/
  518. static int nxffs_wrinodehdr(FAR struct nxffs_volume_s *volume,
  519. FAR struct nxffs_pack_s *pack)
  520. {
  521. FAR struct nxffs_inode_s *inode;
  522. off_t ioblock;
  523. uint16_t iooffset;
  524. uint32_t crc;
  525. int namlen;
  526. int ret;
  527. /* Get seek positions corresponding to the inode header location */
  528. ioblock = nxffs_getblock(volume, pack->dest.entry.hoffset);
  529. iooffset = nxffs_getoffset(volume, pack->dest.entry.hoffset, ioblock);
  530. /* The inode header is not written until all of the inode data has been
  531. * packed into its new location. As a result, there are two possibilities:
  532. *
  533. * 1. The inode header lies in the current, unwritten erase block,
  534. * 2. The inode header resides in an earlier erase block and has already
  535. * been written to FLASH.
  536. *
  537. * Recall that the inode name has already been written to FLASH. If that
  538. * were not the case, then there would be other complex possibilities.
  539. *
  540. * Case 2: Does the inode header reside in a block before the beginning
  541. * of the current erase block?
  542. */
  543. if (ioblock < pack->block0)
  544. {
  545. /* Case 2: The inode header lies in an earlier erase block that has
  546. * already been written to FLASH. In this case, if we are very
  547. * careful, we can just use the standard routine to write the inode
  548. * header that is called during the normal file close operation:
  549. */
  550. ret = nxffs_wrinode(volume, &pack->dest.entry);
  551. }
  552. else
  553. {
  554. /* Cases 1: Both the inode header and name are in the unwritten cache
  555. * memory.
  556. *
  557. * Initialize the inode header.
  558. */
  559. iooffset += (ioblock - pack->block0) * volume->geo.blocksize;
  560. inode = (FAR struct nxffs_inode_s *)&volume->pack[iooffset];
  561. memcpy(inode->magic, g_inodemagic, NXFFS_MAGICSIZE);
  562. nxffs_wrle32(inode->noffs, pack->dest.entry.noffset);
  563. nxffs_wrle32(inode->doffs, pack->dest.entry.doffset);
  564. nxffs_wrle32(inode->utc, pack->dest.entry.utc);
  565. nxffs_wrle32(inode->crc, 0);
  566. nxffs_wrle32(inode->datlen, pack->dest.entry.datlen);
  567. /* Get the length of the inode name */
  568. namlen = strlen(pack->dest.entry.name);
  569. DEBUGASSERT(namlen < CONFIG_NXFFS_MAXNAMLEN);
  570. inode->state = CONFIG_NXFFS_ERASEDSTATE;
  571. inode->namlen = namlen;
  572. /* Calculate the CRC */
  573. crc = crc32((FAR const uint8_t *)inode, SIZEOF_NXFFS_INODE_HDR);
  574. crc = crc32part((FAR const uint8_t *)pack->dest.entry.name, namlen, crc);
  575. /* Finish the inode header */
  576. inode->state = INODE_STATE_FILE;
  577. nxffs_wrle32(inode->crc, crc);
  578. /* If any open files reference this inode, then update the open file
  579. * state.
  580. */
  581. ret = nxffs_updateinode(volume, &pack->dest.entry);
  582. if (ret < 0)
  583. {
  584. ferr("ERROR: Failed to update inode info: %s\n", -ret);
  585. }
  586. }
  587. /* Reset the dest inode information */
  588. nxffs_freeentry(&pack->dest.entry);
  589. memset(&pack->dest, 0, sizeof(struct nxffs_packstream_s));
  590. return ret;
  591. }
  592. /****************************************************************************
  593. * Name: nxffs_wrdatthdr
  594. *
  595. * Description:
  596. * Write the destination data block header to FLASH.
  597. *
  598. * Input Parameters:
  599. * volume - The volume to be packed
  600. * pack - The volume packing state structure.
  601. *
  602. * Returned Value:
  603. * Zero on success; Otherwise, a negated errno value is returned to
  604. * indicate the nature of the failure.
  605. *
  606. ****************************************************************************/
  607. static void nxffs_wrdathdr(FAR struct nxffs_volume_s *volume,
  608. FAR struct nxffs_pack_s *pack)
  609. {
  610. FAR struct nxffs_data_s *dathdr;
  611. off_t ioblock;
  612. uint16_t iooffset;
  613. uint32_t crc;
  614. if (pack->dest.blklen > 0)
  615. {
  616. /* Get the offset in the block corresponding to the location of the data
  617. * block header. NOTE: This must lie in the same block as we currently have
  618. * buffered.
  619. */
  620. ioblock = nxffs_getblock(volume, pack->dest.blkoffset);
  621. iooffset = nxffs_getoffset(volume, pack->dest.blkoffset, ioblock);
  622. DEBUGASSERT(pack->dest.blkoffset && ioblock == pack->ioblock);
  623. /* Write the data block header to memory */
  624. dathdr = (FAR struct nxffs_data_s *)&pack->iobuffer[iooffset];
  625. memcpy(dathdr->magic, g_datamagic, NXFFS_MAGICSIZE);
  626. nxffs_wrle32(dathdr->crc, 0);
  627. nxffs_wrle16(dathdr->datlen, pack->dest.blklen);
  628. /* Update the entire data block CRC (including the header) */
  629. crc = crc32(&pack->iobuffer[iooffset],
  630. pack->dest.blklen + SIZEOF_NXFFS_DATA_HDR);
  631. nxffs_wrle32(dathdr->crc, crc);
  632. }
  633. /* Setup state to allocate the next data block */
  634. pack->dest.blkoffset = 0;
  635. pack->dest.blklen = 0;
  636. pack->dest.blkpos = 0;
  637. }
  638. /****************************************************************************
  639. * Name: nxffs_packtransfer
  640. *
  641. * Description:
  642. * Transfer data from the source to the destination buffer.
  643. *
  644. * Input Parameters:
  645. * volume - The volume to be packed
  646. * pack - The volume packing state structure.
  647. *
  648. * Returned Value:
  649. * None.
  650. *
  651. ****************************************************************************/
  652. static void nxffs_packtransfer(FAR struct nxffs_volume_s *volume,
  653. FAR struct nxffs_pack_s *pack)
  654. {
  655. /* Determine how much data is available in the dest pack buffer */
  656. uint16_t destlen = volume->geo.blocksize - pack->iooffset;
  657. /* Dermined how much data is available in the src data block */
  658. uint16_t srclen = pack->src.blklen - pack->src.blkpos;
  659. /* Transfer the smaller of the two amounts data */
  660. uint16_t xfrlen = MIN(srclen, destlen);
  661. if (xfrlen > 0)
  662. {
  663. nxffs_ioseek(volume,
  664. pack->src.blkoffset + SIZEOF_NXFFS_DATA_HDR +
  665. pack->src.blkpos);
  666. memcpy(&pack->iobuffer[pack->iooffset],
  667. &volume->cache[volume->iooffset], xfrlen);
  668. /* Increment counts and offset for this data transfer */
  669. pack->src.fpos += xfrlen; /* Source data offsets */
  670. pack->src.blkpos += xfrlen;
  671. pack->dest.fpos += xfrlen; /* Destination data offsets */
  672. pack->dest.blkpos += xfrlen;
  673. pack->dest.blklen += xfrlen; /* Destination data block size */
  674. pack->iooffset += xfrlen; /* Destination I/O block offset */
  675. volume->iooffset += xfrlen; /* Source I/O block offset */
  676. volume->froffset += xfrlen; /* Free FLASH offset */
  677. }
  678. }
  679. /****************************************************************************
  680. * Name: nxffs_endsrcblock
  681. *
  682. * Description:
  683. * The end of a source data block has been encountered. Locate the next
  684. * source block and setup to continue the transfer.
  685. *
  686. * Input Parameters:
  687. * volume - The volume to be packed
  688. * pack - The volume packing state structure.
  689. *
  690. * Returned Value:
  691. * Zero on success; Otherwise, a negated errno value is returned to
  692. * indicate the nature of the failure.
  693. *
  694. ****************************************************************************/
  695. static int nxffs_endsrcblock(FAR struct nxffs_volume_s *volume,
  696. FAR struct nxffs_pack_s *pack)
  697. {
  698. struct nxffs_blkentry_s blkentry;
  699. off_t offset;
  700. int ret;
  701. /* Yes.. find the next data block in the source input stream. */
  702. offset = pack->src.blkoffset + SIZEOF_NXFFS_DATA_HDR + pack->src.blklen;
  703. ret = nxffs_nextblock(volume, offset, &blkentry);
  704. if (ret < 0)
  705. {
  706. ferr("ERROR: Failed to find next data block: %d\n", -ret);
  707. return ret;
  708. }
  709. /* Set up the source stream */
  710. pack->src.blkoffset = blkentry.hoffset;
  711. pack->src.blklen = blkentry.datlen;
  712. pack->src.blkpos = 0;
  713. return OK;
  714. }
  715. /****************************************************************************
  716. * Name: nxffs_packblock
  717. *
  718. * Description:
  719. * Resume packing from the source stream into the newly identified
  720. * destination block.
  721. *
  722. * Input Parameters:
  723. * volume - The volume to be packed
  724. * pack - The volume packing state structure.
  725. *
  726. * Returned Value:
  727. * Zero on success; Otherwise, a negated errno value is returned to
  728. * indicate the nature of the failure.
  729. *
  730. ****************************************************************************/
  731. static inline int nxffs_packblock(FAR struct nxffs_volume_s *volume,
  732. FAR struct nxffs_pack_s *pack)
  733. {
  734. off_t offset;
  735. int ret;
  736. /* Are we currently processing a block from the source stream? */
  737. if (pack->src.blkoffset == 0)
  738. {
  739. /* No.. setup the source stream */
  740. ret = nxffs_srcsetup(volume, pack, pack->src.entry.doffset);
  741. if (ret < 0)
  742. {
  743. ferr("ERROR: Failed to configure the src stream: %d\n", -ret);
  744. return ret;
  745. }
  746. }
  747. /* We enter here on a new block every time, so we always have to setup
  748. * the dest data stream. There should never be data block allocated at
  749. * this point in time.
  750. */
  751. DEBUGASSERT(pack->dest.blkoffset == 0 && pack->dest.blkpos == 0);
  752. ret = nxffs_destsetup(volume, pack);
  753. if (ret < 0)
  754. {
  755. /* -ENOSPC is a special return value which simply means that all of
  756. * the FLASH has been used up to the end of the current. We need to
  757. * return OK in this case and resume at the next block.
  758. */
  759. if (ret == -ENOSPC)
  760. {
  761. return OK;
  762. }
  763. else
  764. {
  765. ferr("ERROR: Failed to configure the dest stream: %d\n", -ret);
  766. return ret;
  767. }
  768. }
  769. /* Loop, transferring data from the source block to the destination pack
  770. * buffer until either (1) the source stream is exhausted, (2) the destination
  771. * block is full, or (3) an error occurs.
  772. */
  773. for (; ; )
  774. {
  775. /* Transfer data from the source buffer to the destination buffer */
  776. nxffs_packtransfer(volume, pack);
  777. /* Now, either the (1) src block has been fully transferred, (2) all
  778. * of the source data has been transferred, or (3) the destination
  779. * block is full, .. or all three.
  780. *
  781. * Check if all of the bytes in the source inode have been transferred.
  782. */
  783. if (pack->src.fpos >= pack->src.entry.datlen)
  784. {
  785. /* Write the final destination data block header and inode
  786. * headers.
  787. */
  788. nxffs_wrdathdr(volume, pack);
  789. nxffs_wrinodehdr(volume, pack);
  790. /* Find the next valid source inode */
  791. offset = pack->src.blkoffset + pack->src.blklen;
  792. memset(&pack->src, 0, sizeof(struct nxffs_packstream_s));
  793. ret = nxffs_nextentry(volume, offset, &pack->src.entry);
  794. if (ret < 0)
  795. {
  796. /* No more valid inode entries. Just return an end-of-flash error
  797. * indication.
  798. */
  799. return -ENOSPC;
  800. }
  801. /* Setup the new source stream */
  802. ret = nxffs_srcsetup(volume, pack, pack->src.entry.doffset);
  803. if (ret < 0)
  804. {
  805. return ret;
  806. }
  807. /* Setup the dest stream */
  808. memset(&pack->dest, 0, sizeof(struct nxffs_packstream_s));
  809. pack->dest.entry.name = pack->src.entry.name;
  810. pack->dest.entry.utc = pack->src.entry.utc;
  811. pack->dest.entry.datlen = pack->src.entry.datlen;
  812. pack->src.entry.name = NULL;
  813. /* Is there sufficient space at the end of the I/O block to hold
  814. * the inode header?
  815. */
  816. if (pack->iooffset + SIZEOF_NXFFS_INODE_HDR > volume->geo.blocksize)
  817. {
  818. /* No, just return success... we will handle this condition when
  819. * this function is called on the next I/O block.
  820. */
  821. return OK;
  822. }
  823. /* Configure the destination stream */
  824. ret = nxffs_destsetup(volume, pack);
  825. if (ret < 0)
  826. {
  827. /* -ENOSPC is a special return value which simply means that all of the
  828. * has been used up to the end. We need to return OK in this case and
  829. * resume at the next block.
  830. */
  831. if (ret == -ENOSPC)
  832. {
  833. return OK;
  834. }
  835. else
  836. {
  837. ferr("ERROR: Failed to configure the dest stream: %d\n", -ret);
  838. return ret;
  839. }
  840. }
  841. }
  842. /* Not at the end of the source data stream. Check if we are at the
  843. * end of the current source data block.
  844. */
  845. else if (pack->src.blkpos >= pack->src.blklen)
  846. {
  847. ret = nxffs_endsrcblock(volume, pack);
  848. if (ret < 0)
  849. {
  850. return ret;
  851. }
  852. }
  853. /* Check if the destination block is full */
  854. if (pack->iooffset >= volume->geo.blocksize)
  855. {
  856. /* Yes.. Write the destination data block header and return success */
  857. nxffs_wrdathdr(volume, pack);
  858. return OK;
  859. }
  860. }
  861. return -ENOSYS;
  862. }
  863. /****************************************************************************
  864. * Name: nxffs_setupwriter
  865. *
  866. * Description:
  867. * Writing is performed at the end of the free FLASH region. When we
  868. * finish packing the other inodes, we still need to pack the partially
  869. * written file at the end of FLASH. This function performs the setup
  870. * necessary to perform that packing phase.
  871. *
  872. * Input Parameters:
  873. * volume - The volume to be packed
  874. * pack - The volume packing state structure.
  875. *
  876. * Returned Value:
  877. * If there is an active writer of the volume, its open file instance is
  878. * returned. NULL is returned otherwise.
  879. *
  880. ****************************************************************************/
  881. static FAR struct nxffs_wrfile_s *
  882. nxffs_setupwriter(FAR struct nxffs_volume_s *volume,
  883. FAR struct nxffs_pack_s *pack)
  884. {
  885. FAR struct nxffs_wrfile_s *wrfile;
  886. /* Is there a writer? */
  887. wrfile = nxffs_findwriter(volume);
  888. if (wrfile)
  889. {
  890. /* Yes... It is the activity of this write that probably initiated
  891. * this packing activity. The writer may have failed in one of several
  892. * different stages:
  893. *
  894. * hoffset == 0: The write failed early before even FLASH for the inode
  895. * header was set aside.
  896. * noffset == 0: The write failed after the inode header was set aside,
  897. * but before the inode name was written.
  898. * doffset == 0: The write failed after writing the inode name, bue
  899. * before any data blocks were written to FLASH.
  900. *
  901. * If no FLASH has been set aside for the write, then we don't need to
  902. * do anything here.
  903. */
  904. if (wrfile->ofile.entry.hoffset > 0)
  905. {
  906. /* Initialize for the packing operation. */
  907. memset(&pack->dest, 0, sizeof(struct nxffs_packstream_s));
  908. pack->dest.entry.name = strdup(wrfile->ofile.entry.name);
  909. pack->dest.entry.utc = wrfile->ofile.entry.utc;
  910. pack->dest.entry.datlen = wrfile->ofile.entry.datlen;
  911. memset(&pack->src, 0, sizeof(struct nxffs_packstream_s));
  912. memcpy(&pack->src.entry, &wrfile->ofile.entry,
  913. sizeof(struct nxffs_entry_s));
  914. pack->src.entry.name = NULL;
  915. return wrfile;
  916. }
  917. }
  918. return NULL;
  919. }
  920. /****************************************************************************
  921. * Name: nxffs_packwriter
  922. *
  923. * Description:
  924. * There is a write in progress at the time that the volume is packed.
  925. * This is the normal case because it is the write failures that trigger
  926. * the packing operation to begin with.
  927. *
  928. * Writing is performed at the end of the free FLASH region and this
  929. * implementation is restricted to a single writer. The new inode is not
  930. * written to FLASH until the writer is closed and so will not be
  931. * found by nxffs_packblock().
  932. *
  933. * Input Parameters:
  934. * volume - The volume to be packed
  935. * pack - The volume packing state structure.
  936. *
  937. * Returned Value:
  938. * Zero on success; Otherwise, a negated errno value is returned to
  939. * indicate the nature of the failure.
  940. *
  941. ****************************************************************************/
  942. static inline int nxffs_packwriter(FAR struct nxffs_volume_s *volume,
  943. FAR struct nxffs_pack_s *pack,
  944. FAR struct nxffs_wrfile_s *wrfile)
  945. {
  946. int ret;
  947. /* Are we currently processing a block from the source stream? */
  948. if (pack->src.blkoffset == 0)
  949. {
  950. /* No.. setup the source stream */
  951. ret = nxffs_srcsetup(volume, pack, pack->src.entry.doffset);
  952. if (ret < 0)
  953. {
  954. ferr("ERROR: Failed to configure the src stream: %d\n", -ret);
  955. return ret;
  956. }
  957. }
  958. /* We enter here on a new block every time, so we always have to setup
  959. * the dest data stream. There should never be data block allocated at
  960. * this point in time.
  961. */
  962. DEBUGASSERT(pack->dest.blkoffset == 0 && pack->dest.blkpos == 0);
  963. ret = nxffs_destsetup(volume, pack);
  964. if (ret < 0)
  965. {
  966. /* -ENOSPC is a special return value which simply means that all of the
  967. * has been used up to the end. We need to return OK in this case and
  968. * resume at the next block.
  969. */
  970. if (ret == -ENOSPC)
  971. {
  972. return OK;
  973. }
  974. else
  975. {
  976. ferr("ERROR: Failed to configure the dest stream: %d\n", -ret);
  977. return ret;
  978. }
  979. }
  980. /* Loop, transferring data from the source block to the destination pack
  981. * buffer until either (1) the source stream is exhausted, (2) the destination
  982. * block is full, or (3) an error occurs.
  983. */
  984. for (; ; )
  985. {
  986. /* Transfer data from the source buffer to the destination buffer */
  987. nxffs_packtransfer(volume, pack);
  988. /* Now, either the (1) src block has been fully transferred, (2) all
  989. * of the source data has been transferred, or (3) the destination
  990. * block is full, .. or all three.
  991. *
  992. * Check if all of the bytes in the source inode have been transferred.
  993. */
  994. if (pack->src.fpos >= pack->src.entry.datlen)
  995. {
  996. /* Write the final destination data block header and inode
  997. * headers.
  998. */
  999. nxffs_wrdathdr(volume, pack);
  1000. /* Set the new offsets in the open file instance. */
  1001. wrfile->ofile.entry.hoffset = pack->dest.entry.hoffset;
  1002. wrfile->ofile.entry.noffset = pack->dest.entry.noffset;
  1003. wrfile->ofile.entry.doffset = pack->dest.entry.doffset;
  1004. /* Return an end-of-flash error to indicate that all of the write
  1005. * data has been transferred.
  1006. */
  1007. return -ENOSPC;
  1008. }
  1009. /* Not at the end of the source data stream. Check if we are at the
  1010. * end of the current source data block.
  1011. */
  1012. else if (pack->src.blkpos >= pack->src.blklen)
  1013. {
  1014. ret = nxffs_endsrcblock(volume, pack);
  1015. if (ret < 0)
  1016. {
  1017. return ret;
  1018. }
  1019. }
  1020. /* Check if the destination block is full */
  1021. if (pack->iooffset >= volume->geo.blocksize)
  1022. {
  1023. /* Yes.. Write the destination data block header and return success */
  1024. nxffs_wrdathdr(volume, pack);
  1025. return OK;
  1026. }
  1027. }
  1028. return -ENOSYS;
  1029. }
  1030. /****************************************************************************
  1031. * Public Functions
  1032. ****************************************************************************/
  1033. /****************************************************************************
  1034. * Name: nxffs_pack
  1035. *
  1036. * Description:
  1037. * Pack and re-write the filesystem in order to free up memory at the end
  1038. * of FLASH.
  1039. *
  1040. * Input Parameters:
  1041. * volume - The volume to be packed.
  1042. *
  1043. * Returned Value:
  1044. * Zero on success; Otherwise, a negated errno value is returned to
  1045. * indicate the nature of the failure.
  1046. *
  1047. ****************************************************************************/
  1048. int nxffs_pack(FAR struct nxffs_volume_s *volume)
  1049. {
  1050. struct nxffs_pack_s pack;
  1051. FAR struct nxffs_wrfile_s *wrfile;
  1052. off_t iooffset;
  1053. off_t eblock;
  1054. off_t block;
  1055. bool packed;
  1056. int i;
  1057. int ret = OK;
  1058. /* Get the offset to the first valid inode entry */
  1059. wrfile = NULL;
  1060. packed = false;
  1061. iooffset = nxffs_mediacheck(volume, &pack);
  1062. if (iooffset == 0)
  1063. {
  1064. /* Offset zero is only returned if no valid blocks were found on the
  1065. * FLASH media or if there are no valid inode entries on the FLASH after
  1066. * the first valid block. There are two possibilities: (1) there
  1067. * really is nothing on the FLASH, or (2) there is a file being written
  1068. * to the FLASH now.
  1069. */
  1070. /* Is there a writer? */
  1071. wrfile = nxffs_setupwriter(volume, &pack);
  1072. if (wrfile)
  1073. {
  1074. /* If there is a write, just set ioffset to the offset of data in
  1075. * first block. Setting 'packed' to true will supress normal inode
  1076. * packing operation. Then we can start compacting the FLASH.
  1077. */
  1078. iooffset = SIZEOF_NXFFS_BLOCK_HDR;
  1079. packed = true;
  1080. goto start_pack;
  1081. }
  1082. else
  1083. {
  1084. /* No, there is no write in progress. We just have an empty flash
  1085. * full of deleted files. In this case, the media needs to be re-
  1086. * formatted.
  1087. */
  1088. ret = nxffs_reformat(volume);
  1089. if (ret == OK)
  1090. {
  1091. /* The free flash offset will be in the first valid block of
  1092. * the FLASH.
  1093. */
  1094. block = 0;
  1095. ret = nxffs_validblock(volume, &block);
  1096. if (ret == OK)
  1097. {
  1098. /* Set to the offset past the block header in the first
  1099. * valid block
  1100. */
  1101. volume->froffset =
  1102. block * volume->geo.blocksize + SIZEOF_NXFFS_BLOCK_HDR;
  1103. }
  1104. }
  1105. return ret;
  1106. }
  1107. }
  1108. /* There is a valid format and valid inodes on the media.. setup up to
  1109. * begin the packing operation.
  1110. */
  1111. ret = nxffs_startpos(volume, &pack, &iooffset);
  1112. if (ret < 0)
  1113. {
  1114. /* This is a normal situation if the volume is full */
  1115. if (ret == -ENOSPC)
  1116. {
  1117. /* In the case where the volume is full, nxffs_startpos() will
  1118. * recalculate the free FLASH offset and store it in iooffset. There
  1119. * may be deleted files at the end of FLASH. In this case, we don't
  1120. * have to pack any files, we simply have to erase FLASH at the end.
  1121. * But don't do this unless there is some particularly big FLASH
  1122. * savings (otherwise, we risk wearing out these final blocks).
  1123. */
  1124. if (iooffset + CONFIG_NXFFS_TAILTHRESHOLD < volume->froffset)
  1125. {
  1126. /* Setting 'packed' to true will supress normal inode packing
  1127. * operation.
  1128. */
  1129. packed = true;
  1130. /* Writing is performed at the end of the free FLASH region.
  1131. * If we are not packing files, we could still need to pack
  1132. * the partially written file at the end of FLASH.
  1133. */
  1134. wrfile = nxffs_setupwriter(volume, &pack);
  1135. }
  1136. /* Otherwise return OK.. meaning that there is nothing more we can
  1137. * do to recover FLASH space.
  1138. */
  1139. else
  1140. {
  1141. return OK;
  1142. }
  1143. }
  1144. else
  1145. {
  1146. ferr("ERROR: Failed to find a packing position: %d\n", -ret);
  1147. return ret;
  1148. }
  1149. }
  1150. /* Otherwise, begin pack at this src/dest block combination. Initialize
  1151. * ioblock and iooffset with the position of the first inode header. In
  1152. * this case, the FLASH offset to the first inode header is return in
  1153. * iooffset.
  1154. */
  1155. start_pack:
  1156. pack.ioblock = nxffs_getblock(volume, iooffset);
  1157. pack.iooffset = nxffs_getoffset(volume, iooffset, pack.ioblock);
  1158. volume->froffset = iooffset;
  1159. /* Then pack all erase blocks starting with the erase block that contains
  1160. * the ioblock and through the final erase block on the FLASH.
  1161. */
  1162. for (eblock = pack.ioblock / volume->blkper;
  1163. eblock < volume->geo.neraseblocks;
  1164. eblock++)
  1165. {
  1166. /* Get the starting block number of the erase block */
  1167. pack.block0 = eblock * volume->blkper;
  1168. #ifndef CONFIG_NXFFS_NAND
  1169. /* Read the erase block into the pack buffer. We need to do this even
  1170. * if we are overwriting the entire block so that we skip over
  1171. * previously marked bad blocks.
  1172. */
  1173. ret = MTD_BREAD(volume->mtd, pack.block0, volume->blkper, volume->pack);
  1174. if (ret < 0)
  1175. {
  1176. ferr("ERROR: Failed to read erase block %d: %d\n", eblock, -ret);
  1177. goto errout_with_pack;
  1178. }
  1179. #else
  1180. /* Read the entire erase block into the pack buffer, one-block-at-a-
  1181. * time. We need to do this even if we are overwriting the entire
  1182. * block so that (1) we skip over previously marked bad blocks, and
  1183. * (2) we can handle individual block read failures.
  1184. *
  1185. * For most FLASH, a read failure indicates a fatal hardware failure.
  1186. * But for NAND FLASH, the read failure probably indicates a block
  1187. * with uncorrectable bit errors.
  1188. */
  1189. /* Read each I/O block */
  1190. for (i = 0, block = pack.block0, pack.iobuffer = volume->pack;
  1191. i < volume->blkper;
  1192. i++, block++, pack.iobuffer += volume->geo.blocksize)
  1193. {
  1194. /* Read the next block in the erase block */
  1195. ret = MTD_BREAD(volume->mtd, block, 1, pack.iobuffer);
  1196. if (ret < 0)
  1197. {
  1198. /* Force a the block to be an NXFFS bad block */
  1199. ferr("ERROR: Failed to read block %d: %d\n", block, ret);
  1200. nxffs_blkinit(volume, pack.iobuffer, BLOCK_STATE_BAD);
  1201. }
  1202. }
  1203. #endif
  1204. /* Now pack each I/O block */
  1205. for (i = 0, block = pack.block0, pack.iobuffer = volume->pack;
  1206. i < volume->blkper;
  1207. i++, block++, pack.iobuffer += volume->geo.blocksize)
  1208. {
  1209. /* The first time here, the ioblock may point to an offset into
  1210. * the erase block. We just need to skip over those cases.
  1211. */
  1212. if (block >= pack.ioblock)
  1213. {
  1214. /* Set the I/O position. Note on the first time we get
  1215. * pack.iooffset will hold the offset in the first I/O block
  1216. * to the first inode header. After that, it will always
  1217. * refer to the first byte after the block header.
  1218. */
  1219. pack.ioblock = block;
  1220. /* If this is not a valid block or if we have already
  1221. * finished packing the valid inode entries, then just fall
  1222. * through, reset the FLASH memory to the erase state, and
  1223. * write the reset values to FLASH. (The first block that
  1224. * we want to process will always be valid -- we have
  1225. * already verified that).
  1226. */
  1227. if (nxffs_packvalid(&pack))
  1228. {
  1229. /* Have we finished packing inodes? */
  1230. if (!packed)
  1231. {
  1232. DEBUGASSERT(wrfile == NULL);
  1233. /* Pack inode data into this block */
  1234. ret = nxffs_packblock(volume, &pack);
  1235. if (ret < 0)
  1236. {
  1237. /* The error -ENOSPC is a special value that simply
  1238. * means that there is nothing further to be packed.
  1239. */
  1240. if (ret == -ENOSPC)
  1241. {
  1242. packed = true;
  1243. /* Writing is performed at the end of the free
  1244. * FLASH region and this implementation is restricted
  1245. * to a single writer. The new inode is not
  1246. * written to FLASH until the writer is closed
  1247. * and so will not be found by nxffs_packblock().
  1248. */
  1249. wrfile = nxffs_setupwriter(volume, &pack);
  1250. }
  1251. else
  1252. {
  1253. /* Otherwise, something really bad happened */
  1254. ferr("ERROR: Failed to pack into block %d: %d\n",
  1255. block, ret);
  1256. goto errout_with_pack;
  1257. }
  1258. }
  1259. }
  1260. /* If all of the "normal" inodes have been packed, then check if
  1261. * we need to pack the current, in-progress write operation.
  1262. */
  1263. if (wrfile)
  1264. {
  1265. DEBUGASSERT(packed == true);
  1266. /* Pack write data into this block */
  1267. ret = nxffs_packwriter(volume, &pack, wrfile);
  1268. if (ret < 0)
  1269. {
  1270. /* The error -ENOSPC is a special value that simply
  1271. * means that there is nothing further to be packed.
  1272. */
  1273. if (ret == -ENOSPC)
  1274. {
  1275. wrfile = NULL;
  1276. }
  1277. else
  1278. {
  1279. /* Otherwise, something really bad happened */
  1280. ferr("ERROR: Failed to pack into block %d: %d\n",
  1281. block, ret);
  1282. goto errout_with_pack;
  1283. }
  1284. }
  1285. }
  1286. }
  1287. /* Set any unused portion at the end of the block to the
  1288. * erased state.
  1289. */
  1290. if (pack.iooffset < volume->geo.blocksize)
  1291. {
  1292. memset(&pack.iobuffer[pack.iooffset],
  1293. CONFIG_NXFFS_ERASEDSTATE,
  1294. volume->geo.blocksize - pack.iooffset);
  1295. }
  1296. /* Next time through the loop, pack.iooffset will point to the
  1297. * first byte after the block header.
  1298. */
  1299. pack.iooffset = SIZEOF_NXFFS_BLOCK_HDR;
  1300. }
  1301. }
  1302. /* We now have an in-memory image of how we want this erase block to
  1303. * appear. Now it is safe to erase the block.
  1304. */
  1305. ret = MTD_ERASE(volume->mtd, eblock, 1);
  1306. if (ret < 0)
  1307. {
  1308. ferr("ERROR: Failed to erase block %d [%d]: %d\n",
  1309. eblock, pack.block0, -ret);
  1310. goto errout_with_pack;
  1311. }
  1312. /* Write the packed I/O block to FLASH */
  1313. ret = MTD_BWRITE(volume->mtd, pack.block0, volume->blkper, volume->pack);
  1314. if (ret < 0)
  1315. {
  1316. ferr("ERROR: Failed to write erase block %d [%d]: %d\n",
  1317. eblock, pack.block0, -ret);
  1318. goto errout_with_pack;
  1319. }
  1320. }
  1321. errout_with_pack:
  1322. nxffs_freeentry(&pack.src.entry);
  1323. nxffs_freeentry(&pack.dest.entry);
  1324. return ret;
  1325. }