xref: /nrf52832-nimble/rt-thread/components/dfs/filesystems/uffs/src/uffs/uffs_buf.c (revision 104654410c56c573564690304ae786df310c91fc)
1 /*
2   This file is part of UFFS, the Ultra-low-cost Flash File System.
3 
4   Copyright (C) 2005-2009 Ricky Zheng <[email protected]>
5 
6   UFFS is free software; you can redistribute it and/or modify it under
7   the GNU Library General Public License as published by the Free Software
8   Foundation; either version 2 of the License, or (at your option) any
9   later version.
10 
11   UFFS is distributed in the hope that it will be useful, but WITHOUT
12   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   or GNU Library General Public License, as applicable, for more details.
15 
16   You should have received a copy of the GNU General Public License
17   and GNU Library General Public License along with UFFS; if not, write
18   to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19   Boston, MA  02110-1301, USA.
20 
21   As a special exception, if other files instantiate templates or use
22   macros or inline functions from this file, or you compile this file
23   and link it with other works to produce a work based on this file,
24   this file does not by itself cause the resulting work to be covered
25   by the GNU General Public License. However the source code for this
26   file must still be made available in accordance with section (3) of
27   the GNU General Public License v2.
28 
29   This exception does not invalidate any other reasons why a work based
30   on this file might be covered by the GNU General Public License.
31 */
32 /**
33  * \file uffs_buf.c
34  * \brief uffs page buffers manipulations
35  * \author Ricky Zheng
36  * \note Created in 11th May, 2005
37  */
38 #include "uffs_config.h"
39 #include "uffs/uffs_types.h"
40 #include "uffs/uffs_buf.h"
41 #include "uffs/uffs_device.h"
42 #include "uffs/uffs_os.h"
43 #include "uffs/uffs_public.h"
44 #include "uffs/uffs_pool.h"
45 #include "uffs/uffs_ecc.h"
46 #include "uffs/uffs_badblock.h"
47 #include <string.h>
48 
49 #define PFX "pbuf: "
50 
51 
52 URET _BufFlush(struct uffs_DeviceSt *dev, UBOOL force_block_recover, int slot);
53 
54 
55 /**
56  * \brief inspect (print) uffs page buffers.
57  * \param[in] dev uffs device to be inspected.
58  */
uffs_BufInspect(uffs_Device * dev)59 void uffs_BufInspect(uffs_Device *dev)
60 {
61 	struct uffs_PageBufDescSt *pb = &dev->buf;
62 	uffs_Buf *buf;
63 
64 	uffs_PerrorRaw(UFFS_MSG_NORMAL,
65 					"------------- page buffer inspect ---------" TENDSTR);
66 	uffs_PerrorRaw(UFFS_MSG_NORMAL, "all buffers: " TENDSTR);
67 	for (buf = pb->head; buf; buf = buf->next) {
68 		if (buf->mark != 0) {
69 			uffs_PerrorRaw(UFFS_MSG_NORMAL,
70 				"\tF:%04x S:%04x P:%02d R:%02d D:%03d M:%c EM:%d" TENDSTR,
71 				buf->parent, buf->serial,
72 				buf->page_id, buf->ref_count,
73 				buf->data_len, buf->mark == UFFS_BUF_VALID ? 'V' : 'D',
74 				buf->ext_mark);
75 		}
76 	}
77 	uffs_PerrorRaw(UFFS_MSG_NORMAL,
78 					"--------------------------------------------"  TENDSTR);
79 }
80 
81 /**
82  * \brief initialize page buffers for device
83  * in UFFS, each device has one buffer pool
84  * \param[in] dev uffs device
85  * \param[in] buf_max maximum buffer number, normally use #MAX_PAGE_BUFFERS
86  * \param[in] dirty_buf_max maximum dirty buffer allowed,
87  *				if the dirty buffer over this number,
88  *				than need to be flush to flash
89  */
uffs_BufInit(uffs_Device * dev,int buf_max,int dirty_buf_max)90 URET uffs_BufInit(uffs_Device *dev, int buf_max, int dirty_buf_max)
91 {
92 	void *pool;
93 	u8 *data;
94 	uffs_Buf *buf;
95 	int size;
96 	int i, slot;
97 
98 	if (!dev)
99 		return U_FAIL;
100 
101 	//init device common parameters, which are needed by page buffers
102 	dev->com.pg_size = dev->attr->page_data_size;  // we use the whole page.
103 	dev->com.header_size = sizeof(struct uffs_MiniHeaderSt); // mini header
104 	dev->com.pg_data_size = dev->com.pg_size - dev->com.header_size;
105 
106 	if (dev->buf.pool != NULL) {
107 		uffs_Perror(UFFS_MSG_NORMAL,
108 					"buf.pool is not NULL, buf already inited ?");
109 		return U_FAIL;
110 	}
111 
112 	size = (sizeof(uffs_Buf) + dev->com.pg_size) * buf_max;
113 	if (dev->mem.pagebuf_pool_size == 0) {
114 		if (dev->mem.malloc) {
115 			dev->mem.pagebuf_pool_buf = dev->mem.malloc(dev, size);
116 			if (dev->mem.pagebuf_pool_buf)
117 				dev->mem.pagebuf_pool_size = size;
118 		}
119 	}
120 	if (size > dev->mem.pagebuf_pool_size) {
121 		uffs_Perror(UFFS_MSG_DEAD,
122 					"page buffers require %d but only %d available.",
123 				size, dev->mem.pagebuf_pool_size);
124 		return U_FAIL;
125 	}
126 	pool = dev->mem.pagebuf_pool_buf;
127 
128 	uffs_Perror(UFFS_MSG_NOISY, "alloc %d bytes.", size);
129 	dev->buf.pool = pool;
130 
131 	for (i = 0; i < buf_max; i++) {
132 		buf = (uffs_Buf *)((u8 *)pool + (sizeof(uffs_Buf) * i));
133 		memset(buf, 0, sizeof(uffs_Buf));
134 		data = (u8 *)pool + (sizeof(uffs_Buf) * buf_max) + (dev->com.pg_size * i);
135 		buf->header = data;
136 		buf->data = data + dev->com.header_size;
137 		buf->mark = UFFS_BUF_EMPTY;
138 		memset(buf->header, 0, dev->com.pg_size);
139 		if (i == 0) {
140 			buf->prev = NULL;
141 			dev->buf.head = buf;
142 		}
143 		else {
144 			buf->prev = (uffs_Buf *)((u8 *)buf - sizeof(uffs_Buf));
145 		}
146 
147 		if (i == (buf_max - 1)) {
148 			buf->next = NULL;
149 			dev->buf.tail = buf;
150 		}
151 		else {
152 			buf->next = (uffs_Buf *)((u8 *)buf + sizeof(uffs_Buf));
153 		}
154 	}
155 
156 	dev->buf.buf_max = buf_max;
157 	dev->buf.dirty_buf_max = (dirty_buf_max > dev->attr->pages_per_block ?
158 								dev->attr->pages_per_block : dirty_buf_max);
159 
160 	for (slot = 0; slot < dev->cfg.dirty_groups; slot++) {
161 		dev->buf.dirtyGroup[slot].dirty = NULL;
162 		dev->buf.dirtyGroup[slot].count = 0;
163 	}
164 	return U_SUCC;
165 }
166 
167 /**
168  * \brief flush all buffers
169  */
uffs_BufFlushAll(struct uffs_DeviceSt * dev)170 URET uffs_BufFlushAll(struct uffs_DeviceSt *dev)
171 {
172 	int slot;
173 	for (slot = 0; slot < dev->cfg.dirty_groups; slot++) {
174 		if(_BufFlush(dev, FALSE, slot) != U_SUCC) {
175 			uffs_Perror(UFFS_MSG_NORMAL,
176 						"fail to flush buffer(slot %d)", slot);
177 			return U_FAIL;
178 		}
179 	}
180 	return U_SUCC;
181 }
182 
183 /**
184  * \brief release all page buffer, this function should be called
185 			when unmounting a uffs device
186  * \param[in] dev uffs device
187  * \note if there are page buffers in used, it may cause fail to release
188  */
uffs_BufReleaseAll(uffs_Device * dev)189 URET uffs_BufReleaseAll(uffs_Device *dev)
190 {
191 	uffs_Buf *p;
192 
193 	if (!dev)
194 		return U_FAIL;
195 
196 	//now release all buffer
197 	p = dev->buf.head;
198 	while (p) {
199 		if (p->ref_count != 0) {
200 			uffs_Perror(UFFS_MSG_NORMAL, PFX
201 						"can't release buffers, parent:%d, serial:%d, \
202 						page_id:%d still in used.\n",
203 						p->parent, p->serial, p->page_id);
204 			return U_FAIL;
205 		}
206 		p = p->next;
207 	}
208 
209 	if (uffs_BufFlushAll(dev) != U_SUCC) {
210 		uffs_Perror(UFFS_MSG_NORMAL,
211 					"can't release buf, fail to flush buffer");
212 		return U_FAIL;
213 	}
214 
215 	if (dev->mem.free) {
216 		dev->mem.free(dev, dev->buf.pool);
217 		dev->mem.pagebuf_pool_size = 0;
218 	}
219 
220 	dev->buf.pool = NULL;
221 	dev->buf.head = dev->buf.tail = NULL;
222 
223 	return U_SUCC;
224 }
225 
226 
_BreakFromBufList(uffs_Device * dev,uffs_Buf * buf)227 static void _BreakFromBufList(uffs_Device *dev, uffs_Buf *buf)
228 {
229 	if(buf->next)
230 		buf->next->prev = buf->prev;
231 
232 	if(buf->prev)
233 		buf->prev->next = buf->next;
234 
235 	if(dev->buf.head == buf)
236 		dev->buf.head = buf->next;
237 
238 	if(dev->buf.tail == buf)
239 		dev->buf.tail = buf->prev;
240 
241 }
242 
_LinkToBufListHead(uffs_Device * dev,uffs_Buf * buf)243 static void _LinkToBufListHead(uffs_Device *dev, uffs_Buf *buf)
244 {
245 	if (buf == dev->buf.head)
246 		return;
247 
248 	buf->prev = NULL;
249 	buf->next = dev->buf.head;
250 
251 	if (dev->buf.head)
252 		dev->buf.head->prev = buf;
253 
254 	if (dev->buf.tail == NULL)
255 		dev->buf.tail = buf;
256 
257 	dev->buf.head = buf;
258 }
259 
_LinkToBufListTail(uffs_Device * dev,uffs_Buf * buf)260 static void _LinkToBufListTail(uffs_Device *dev, uffs_Buf *buf)
261 {
262 	if (dev->buf.tail == buf)
263 		return;
264 
265 	buf->prev = dev->buf.tail;
266 	buf->next = NULL;
267 
268 	if (dev->buf.tail)
269 		dev->buf.tail->next = buf;
270 
271 	if (dev->buf.head == NULL)
272 		dev->buf.head = buf;
273 
274 	dev->buf.tail = buf;
275 }
276 
277 //move a node which linked in the list to the head of list
_MoveNodeToHead(uffs_Device * dev,uffs_Buf * p)278 static void _MoveNodeToHead(uffs_Device *dev, uffs_Buf *p)
279 {
280 	if (p == dev->buf.head)
281 		return;
282 
283 	//break from list
284 	_BreakFromBufList(dev, p);
285 
286 	//link to head
287 	_LinkToBufListHead(dev, p);
288 }
289 
290 // check if the buf is already in dirty list
_IsBufInInDirtyList(uffs_Device * dev,int slot,uffs_Buf * buf)291 static UBOOL _IsBufInInDirtyList(uffs_Device *dev, int slot, uffs_Buf *buf)
292 {
293 	uffs_Buf *work;
294 	work = dev->buf.dirtyGroup[slot].dirty;
295 	while (work) {
296 		if (work == buf)
297 			return U_TRUE;
298 		work = work->next_dirty;
299 	}
300 
301 	return U_FALSE;
302 }
303 
_LinkToDirtyList(uffs_Device * dev,int slot,uffs_Buf * buf)304 static void _LinkToDirtyList(uffs_Device *dev, int slot, uffs_Buf *buf)
305 {
306 
307 	if (buf == NULL) {
308 		uffs_Perror(UFFS_MSG_SERIOUS,
309 					"Try to insert a NULL node into dirty list ?");
310 		return;
311 	}
312 
313 	buf->mark = UFFS_BUF_DIRTY;
314 	buf->prev_dirty = NULL;
315 	buf->next_dirty = dev->buf.dirtyGroup[slot].dirty;
316 
317 	if (dev->buf.dirtyGroup[slot].dirty)
318 		dev->buf.dirtyGroup[slot].dirty->prev_dirty = buf;
319 
320 	dev->buf.dirtyGroup[slot].dirty = buf;
321 	dev->buf.dirtyGroup[slot].count++;
322 }
323 
CountFreeBuf(uffs_Device * dev)324 static int CountFreeBuf(uffs_Device *dev)
325 {
326 	int count = 0;
327 
328 	uffs_Buf *buf = dev->buf.head;
329 
330 	while (buf) {
331 
332 		if (buf->ref_count == 0 &&
333 			buf->mark != UFFS_BUF_DIRTY)
334 			count++;
335 
336 		buf = buf->next;
337 	}
338 
339 	return count;
340 }
341 
_FindFreeBufEx(uffs_Device * dev,int clone)342 static uffs_Buf * _FindFreeBufEx(uffs_Device *dev, int clone)
343 {
344 	uffs_Buf *buf;
345 
346 	if (!clone && CountFreeBuf(dev) <= CLONE_BUFFERS_THRESHOLD)
347 		return NULL;
348 
349 #if 0
350 	buf = dev->buf.head;
351 	while (buf) {
352 
353 		if (buf->ref_count == 0 &&
354 			buf->mark != UFFS_BUF_DIRTY)
355 			return buf;
356 
357 		buf = buf->next;
358 	}
359 #else
360 	buf = dev->buf.tail;
361 	while (buf) {
362 
363 		if(buf->ref_count == 0 &&
364 			buf->mark != UFFS_BUF_DIRTY)
365 			return buf;
366 
367 		buf = buf->prev;
368 	}
369 #endif
370 
371 	return buf;
372 }
373 
_FindFreeBuf(uffs_Device * dev)374 static uffs_Buf * _FindFreeBuf(uffs_Device *dev)
375 {
376 	return _FindFreeBufEx(dev, 0);
377 }
378 
379 
380 /**
381  * load psychical page data into buf and do ecc check
382  * \param[in] dev uffs device
383  * \param[in] buf buf to be load in
384  * \param[in] block psychical block number
385  * \param[in] page psychical page number
386  * \return return U_SUCC if no error,
387  *	 return U_FAIL if I/O error or ecc check fail
388  */
uffs_BufLoadPhyData(uffs_Device * dev,uffs_Buf * buf,u32 block,u32 page)389 URET uffs_BufLoadPhyData(uffs_Device *dev, uffs_Buf *buf, u32 block, u32 page)
390 {
391 	int ret;
392 
393 	ret = uffs_FlashReadPage(dev, block, page, buf, U_FALSE);
394 
395 	if (UFFS_FLASH_HAVE_ERR(ret)) {
396 		buf->mark = UFFS_BUF_EMPTY;
397 		return U_FAIL;
398 	}
399 	else {
400 		buf->mark = UFFS_BUF_VALID;
401 		return U_SUCC;
402 	}
403 }
404 
405 /**
406  * \brief load psychical page data into buf and ignore ECC result
407  *
408  * \param[in] dev uffs device
409  * \param[in] buf buf to be load in
410  * \param[in] block psychical block number
411  * \param[in] page psychical page number
412  *
413  * \return return U_SUCC if no error, return U_FAIL if I/O error
414  * \note this function should be only used when doing bad block recover.
415  */
uffs_LoadPhyDataToBufEccUnCare(uffs_Device * dev,uffs_Buf * buf,u32 block,u32 page)416 URET uffs_LoadPhyDataToBufEccUnCare(uffs_Device *dev,
417 									uffs_Buf *buf, u32 block, u32 page)
418 {
419 	int ret;
420 
421 	ret = uffs_FlashReadPage(dev, block, page, buf, U_TRUE);
422 
423 	if (ret == UFFS_FLASH_IO_ERR) {
424 		buf->mark = UFFS_BUF_EMPTY;
425 		return U_FAIL;
426 	}
427 	else {
428 		buf->mark = UFFS_BUF_VALID;
429 		return U_SUCC;
430 	}
431 }
432 
433 /**
434  * find a buffer in the pool
435  * \param[in] dev uffs device
436  * \param[in] start buf to search from
437  * \param[in] parent parent serial num
438  * \param[in] serial serial num
439  * \param[in] page_id page_id (if page_id == UFFS_ALL_PAGES then any page would match)
440  * \return return found buffer, return NULL if buffer not found
441  */
uffs_BufFindFrom(uffs_Device * dev,uffs_Buf * start,u16 parent,u16 serial,u16 page_id)442 uffs_Buf * uffs_BufFindFrom(uffs_Device *dev, uffs_Buf *start,
443 						u16 parent, u16 serial, u16 page_id)
444 {
445 	uffs_Buf *p = start;
446 
447 	while (p) {
448 		if(	p->parent == parent &&
449 			p->serial == serial &&
450 			(page_id == UFFS_ALL_PAGES || p->page_id == page_id) &&
451 			p->mark != UFFS_BUF_EMPTY)
452 		{
453 			//they have match one
454 			return p;
455 		}
456 		p = p->next;
457 	}
458 
459 	return NULL; //buffer not found
460 }
461 
462 /**
463  * find a buffer in the pool
464  * \param[in] dev uffs device
465  * \param[in] parent parent serial num
466  * \param[in] serial serial num
467  * \param[in] page_id page_id (if page_id == UFFS_ALL_PAGES then any page would match)
468  * \return return found buffer, return NULL if buffer not found
469  */
uffs_BufFind(uffs_Device * dev,u16 parent,u16 serial,u16 page_id)470 uffs_Buf * uffs_BufFind(uffs_Device *dev,
471 						u16 parent, u16 serial, u16 page_id)
472 {
473 	uffs_Buf *p = dev->buf.head;
474 
475 	return uffs_BufFindFrom(dev, p, parent, serial, page_id);
476 }
477 
478 
_FindBufInDirtyList(uffs_Buf * dirty,u16 page_id)479 static uffs_Buf * _FindBufInDirtyList(uffs_Buf *dirty, u16 page_id)
480 {
481 	while(dirty) {
482 		if (dirty->page_id == page_id)
483 			return dirty;
484 		dirty = dirty->next_dirty;
485 	}
486 	return NULL;
487 }
488 
_BreakFromDirty(uffs_Device * dev,uffs_Buf * dirtyBuf)489 static URET _BreakFromDirty(uffs_Device *dev, uffs_Buf *dirtyBuf)
490 {
491 	int slot = -1;
492 
493 	if (dirtyBuf->mark != UFFS_BUF_DIRTY) {
494 		uffs_Perror(UFFS_MSG_NORMAL,
495 						"try to break a non-dirty buf from dirty list ?");
496 		return U_FAIL;
497 	}
498 
499 	slot = uffs_BufFindGroupSlot(dev, dirtyBuf->parent, dirtyBuf->serial);
500 	if (slot < 0) {
501 		uffs_Perror(UFFS_MSG_NORMAL, "no dirty list exit ?");
502 		return U_FAIL;
503 	}
504 
505 	// break from the link
506 	if (dirtyBuf->next_dirty) {
507 		dirtyBuf->next_dirty->prev_dirty = dirtyBuf->prev_dirty;
508 	}
509 
510 	if (dirtyBuf->prev_dirty) {
511 		dirtyBuf->prev_dirty->next_dirty = dirtyBuf->next_dirty;
512 	}
513 
514 	// check if it's the link head ...
515 	if (dev->buf.dirtyGroup[slot].dirty == dirtyBuf) {
516 		dev->buf.dirtyGroup[slot].dirty = dirtyBuf->next_dirty;
517 	}
518 
519 	dirtyBuf->next_dirty = dirtyBuf->prev_dirty = NULL; // clear dirty link
520 
521 	dev->buf.dirtyGroup[slot].count--;
522 
523 	return U_SUCC;
524 }
525 
_GetDirOrFileNameSum(uffs_Device * dev,uffs_Buf * buf)526 static u16 _GetDirOrFileNameSum(uffs_Device *dev, uffs_Buf *buf)
527 {
528 	u16 data_sum = 0; //default: 0
529 	uffs_FileInfo *fi;
530 
531 	dev = dev;
532 	//FIXME: We use the same schema for both dir and file.
533 	if (buf->type == UFFS_TYPE_FILE || buf->type == UFFS_TYPE_DIR) {
534 		if (buf->page_id == 0) {
535 			fi = (uffs_FileInfo *)(buf->data);
536 			data_sum = uffs_MakeSum16(fi->name, fi->name_len);
537 		}
538 	}
539 
540 	return data_sum;
541 }
542 
543 
_CheckDirtyList(uffs_Buf * dirty)544 static URET _CheckDirtyList(uffs_Buf *dirty)
545 {
546 	u16 parent;
547 	u16 serial;
548 
549 	if (dirty == NULL) {
550 		return U_SUCC;
551 	}
552 
553 	parent = dirty->parent;
554 	serial = dirty->serial;
555 	dirty = dirty->next_dirty;
556 
557 	while (dirty) {
558 		if (parent != dirty->parent ||
559 			serial != dirty->serial) {
560 			uffs_Perror(UFFS_MSG_SERIOUS,
561 					"parent or serial in dirty pages buffer are not the same ?");
562 			return U_FAIL;
563 		}
564 		if (dirty->mark != UFFS_BUF_DIRTY) {
565 			uffs_Perror(UFFS_MSG_SERIOUS,
566 					"non-dirty page buffer in dirty buffer list ?");
567 			return U_FAIL;
568 		}
569 		dirty = dirty->next_dirty;
570 	}
571 	return U_SUCC;
572 }
573 
574 /** find a page in dirty list, which has minimum page_id */
_FindMinimunPageIdFromDirtyList(uffs_Buf * dirtyList)575 uffs_Buf * _FindMinimunPageIdFromDirtyList(uffs_Buf *dirtyList)
576 {
577 	uffs_Buf * work = dirtyList;
578 	uffs_Buf * buf = dirtyList;
579 
580 	if (buf) {
581 		work = work->next_dirty;
582 		while (work) {
583 			if (work->page_id < buf->page_id)
584 				buf = work;
585 			work = work->next_dirty;
586 		}
587 
588 		uffs_Assert(buf->mark == UFFS_BUF_DIRTY,
589 					"buf (serial = %d, parent = %d, page_id = %d, type = %d) in dirty list but mark is 0x%x ?",
590 					buf->serial, buf->parent, buf->page_id, buf->type, buf->mark);
591 	}
592 
593 	return buf;
594 }
595 
596 
597 /**
598  * \brief flush buffer with block recover
599  *
600  * Scenario:
601  *	1. get a free (erased) block --> newNode <br>
602  *	2. copy from old block ---> oldNode, or copy from dirty list, <br>
603  *		sorted by page_id, to new block. Skips the invalid pages when copy pages.<br>
604  *	3. erased old block. set new info to oldNode, set newNode->block = old block,<br>
605  *		and put newNode to erased list.<br>
606  *	\note IT'S IMPORTANT TO KEEP OLD NODE IN THE LIST,
607  *		 so you don't need to update the obj->node :-)
608  */
uffs_BufFlush_Exist_With_BlockCover(uffs_Device * dev,int slot,TreeNode * node,uffs_BlockInfo * bc)609 static URET uffs_BufFlush_Exist_With_BlockCover(
610 			uffs_Device *dev,
611 			int slot,			//!< dirty group slot
612 			TreeNode *node,		//!< old data node on tree
613 			uffs_BlockInfo *bc	//!< old data block info
614 			)
615 {
616 	u16 i;
617 	u8 type, timeStamp;
618 	u16 page, parent, serial;
619 	uffs_Buf *buf;
620 	TreeNode *newNode;
621 	uffs_BlockInfo *newBc;
622 	uffs_Tags *tag, *oldTag;
623 	int x;
624 	u16 newBlock;
625 	UBOOL succRecover;			//U_TRUE: recover successful, erase old block,
626 								//U_FALSE: fail to recover, erase new block
627 	UBOOL flash_op_err;
628 	u16 data_sum = 0xFFFF;
629 
630 	UBOOL useCloneBuf;
631 
632 	type = dev->buf.dirtyGroup[slot].dirty->type;
633 	parent = dev->buf.dirtyGroup[slot].dirty->parent;
634 	serial = dev->buf.dirtyGroup[slot].dirty->serial;
635 
636 retry:
637 	uffs_BlockInfoLoad(dev, bc, UFFS_ALL_PAGES);
638 
639 	flash_op_err = UFFS_FLASH_NO_ERR;
640 	succRecover = U_FALSE;
641 
642 	newNode = uffs_TreeGetErasedNode(dev);
643 	if (newNode == NULL) {
644 		uffs_Perror(UFFS_MSG_NOISY, "no enough erased block!");
645 		goto ext;
646 	}
647 	newBlock = newNode->u.list.block;
648 	newBc = uffs_BlockInfoGet(dev, newBlock);
649 	if (newBc == NULL) {
650 		uffs_Perror(UFFS_MSG_SERIOUS, "get block info fail!");
651 		uffs_InsertToErasedListHead(dev, newNode);  //put node back to erased list
652 											//because it doesn't use, so put to head
653 		goto ext;
654 	}
655 
656 	//uffs_Perror(UFFS_MSG_NOISY, "flush buffer with block cover to %d", newBlock);
657 
658 #if 0
659 	// this assert seems not necessary ...
660 	if (!uffs_Assert(newBc->expired_count == dev->attr->pages_per_block,
661 			"We have block cache for erased block ? expired_count = %d, block = %d\n",
662 			newBc->expired_count, newBc->block)) {
663 		uffs_BlockInfoExpire(dev, newBc, UFFS_ALL_PAGES);
664 	}
665 #endif
666 
667 	uffs_BlockInfoLoad(dev, newBc, UFFS_ALL_PAGES);
668 	timeStamp = uffs_GetNextBlockTimeStamp(uffs_GetBlockTimeStamp(dev, bc));
669 
670 //	uffs_Perror(UFFS_MSG_NOISY, "Flush buffers with Block Recover, from %d to %d",
671 //					bc->block, newBc->block);
672 
673 	for (i = 0; i < dev->attr->pages_per_block; i++) {
674 		tag = GET_TAG(newBc, i);
675 		TAG_DIRTY_BIT(tag) = TAG_DIRTY;
676 		TAG_VALID_BIT(tag) = TAG_VALID;
677 		TAG_BLOCK_TS(tag) = timeStamp;
678 		TAG_PARENT(tag) = parent;
679 		TAG_SERIAL(tag) = serial;
680 		TAG_TYPE(tag) = type;
681 		TAG_PAGE_ID(tag) = (u8)(i & 0xFF);	// now, page_id = page.
682 									// FIX ME!! if more than 256 pages in a block
683 
684 		SEAL_TAG(tag);
685 
686 		buf = _FindBufInDirtyList(dev->buf.dirtyGroup[slot].dirty, i);
687 		if (buf != NULL) {
688 			if (i == 0)
689 				data_sum = _GetDirOrFileNameSum(dev, buf);
690 
691 			TAG_DATA_LEN(tag) = buf->data_len;
692 
693 			if (buf->data_len == 0 || (buf->ext_mark & UFFS_BUF_EXT_MARK_TRUNC_TAIL)) { // this only happen when truncating a file
694 
695 				// when truncating a file, the last dirty buf will be
696 				// set as UFFS_BUF_EXT_MARK_TAIL. so that we don't do page recovery
697 				// for the rest pages in the block. (file is ended at this page)
698 
699 				if (!uffs_Assert((buf->ext_mark & UFFS_BUF_EXT_MARK_TRUNC_TAIL) != 0,
700 					"buf->data == 0 but not the last page of truncating ? block = %d, page_id = %d",
701 					bc->block, i)) {
702 
703 					// We can't do more about it for now ...
704 				}
705 
706 				if (buf->data_len > 0) {
707 					flash_op_err = uffs_FlashWritePageCombine(dev, newBlock, i, buf, tag);
708 				}
709 				else {
710 					// data_len == 0, no I/O needed.
711 					flash_op_err = UFFS_FLASH_NO_ERR;
712 				}
713 				succRecover = U_TRUE;
714 				break;
715 			}
716 			else
717 				flash_op_err = uffs_FlashWritePageCombine(dev, newBlock, i, buf, tag);
718 
719 			if (flash_op_err != UFFS_FLASH_NO_ERR) {
720 				if (flash_op_err == UFFS_FLASH_BAD_BLK) {
721 					uffs_Perror(UFFS_MSG_NORMAL,
722 								"new bad block %d discovered.", newBlock);
723 					break;
724 				}
725 				else if (flash_op_err == UFFS_FLASH_IO_ERR) {
726 					uffs_Perror(UFFS_MSG_NORMAL,
727 								"writing to block %d page %d, I/O error ?",
728 								(int)newBlock, (int)i);
729 					break;
730 				}
731 				else {
732 					uffs_Perror(UFFS_MSG_SERIOUS, "Unhandled flash op result: %d", flash_op_err);
733 					break;
734 				}
735 			}
736 		}
737 		else {
738 			page = uffs_FindPageInBlockWithPageId(dev, bc, i);
739 			if (page == UFFS_INVALID_PAGE) {
740 				succRecover = U_TRUE;
741 				break;  //end of last page, normal break
742 			}
743 			page = uffs_FindBestPageInBlock(dev, bc, page);
744 
745 			if (!uffs_Assert(page != UFFS_INVALID_PAGE, "got an invalid page ?\n"))
746 				break;
747 
748 			oldTag = GET_TAG(bc, page);
749 
750 			// First, try to find existing cached buffer.
751 			// Note: do not call uffs_BufGetEx() as it may trigger buf flush and result in infinite loop
752 			buf = uffs_BufGet(dev, parent, serial, i);
753 
754 			if (buf == NULL) {  // no cached page buffer, use clone buffer.
755 				useCloneBuf = U_TRUE;
756 				buf = uffs_BufClone(dev, NULL);
757 				if (buf == NULL) {
758 					uffs_Perror(UFFS_MSG_SERIOUS, "Can't clone a new buf!");
759 					break;
760 				}
761 				x = uffs_BufLoadPhyData(dev, buf, bc->block, page);
762 				if (x == U_FAIL) {
763 					if (HAVE_BADBLOCK(dev) && dev->bad.block == bc->block) {
764 						// the old block is a bad block, we'll process it later.
765 						uffs_Perror(UFFS_MSG_SERIOUS,
766 									"the old block %d is a bad block, \
767 									but ignore it for now.",
768 									bc->block);
769 					}
770 					else {
771 						uffs_Perror(UFFS_MSG_SERIOUS, "I/O error ?");
772 						uffs_BufFreeClone(dev, buf);
773 						flash_op_err = UFFS_FLASH_IO_ERR;
774 						break;
775 					}
776 				}
777 
778 				buf->type = type;
779 				buf->parent = parent;
780 				buf->serial = serial;
781 				buf->page_id = TAG_PAGE_ID(oldTag);
782 				buf->data_len = TAG_DATA_LEN(oldTag);
783 
784 			}
785 			else {
786 				useCloneBuf = U_FALSE;
787 
788 				uffs_Assert(buf->page_id == TAG_PAGE_ID(oldTag), "buf->page_id = %d, tag page id: %d", buf->page_id, TAG_PAGE_ID(oldTag));
789 				uffs_Assert(buf->data_len == TAG_DATA_LEN(oldTag), "buf->data_len = %d, tag data len: %d", buf->data_len, TAG_DATA_LEN(oldTag));
790 			}
791 
792 			if (buf->data_len > dev->com.pg_data_size) {
793 				uffs_Perror(UFFS_MSG_NOISY, "data length over flow, truncated !");
794 				buf->data_len = dev->com.pg_data_size;
795 			}
796 
797 			if (!uffs_Assert(buf->data_len != 0, "data_len == 0 ? block %d, page %d, serial %d, parent %d",
798 				bc->block, page, buf->serial, buf->parent)) {
799 				// this could be some error on flash ? we can't do more about it for now ...
800 			}
801 
802 			TAG_DATA_LEN(tag) = buf->data_len;
803 
804 			if (i == 0)
805 				data_sum = _GetDirOrFileNameSum(dev, buf);
806 
807 			flash_op_err = uffs_FlashWritePageCombine(dev, newBlock, i, buf, tag);
808 
809 			if (buf) {
810 				if (useCloneBuf)
811 					uffs_BufFreeClone(dev, buf);
812 				else
813 					uffs_BufPut(dev, buf);
814 			}
815 
816 			if (flash_op_err == UFFS_FLASH_BAD_BLK) {
817 				uffs_Perror(UFFS_MSG_NORMAL,
818 							"new bad block %d discovered.", newBlock);
819 				break;
820 			}
821 			else if (flash_op_err == UFFS_FLASH_IO_ERR) {
822 				uffs_Perror(UFFS_MSG_NORMAL, "I/O error ?", newBlock);
823 				break;
824 			}
825 		}
826 	} //end of for
827 
828 	if (i == dev->attr->pages_per_block)
829 		succRecover = U_TRUE;
830 	else {
831 		// expire last page info cache in case the 'tag' is not written.
832 		uffs_BlockInfoExpire(dev, newBc, i);
833 	}
834 
835 	if (flash_op_err == UFFS_FLASH_BAD_BLK) {
836 		uffs_BlockInfoExpire(dev, newBc, UFFS_ALL_PAGES);
837 		uffs_BlockInfoPut(dev, newBc);
838 		if (newNode->u.list.block == dev->bad.block) {
839 			// the recovered block is a BAD block (buy me a lotto, please :-), we need to
840 			// deal with it immediately (mark it as 'bad' and put into bad block list).
841 			uffs_BadBlockProcess(dev, newNode);
842 		}
843 
844 		uffs_Perror(UFFS_MSG_NORMAL, "Retry block cover ...");
845 
846 		goto retry; // retry on a new erased block ...
847 	}
848 
849 	if (succRecover == U_TRUE) {
850 		// now it's time to clean the dirty buffers
851 		for (i = 0; i < dev->attr->pages_per_block; i++) {
852 			buf = _FindBufInDirtyList(dev->buf.dirtyGroup[slot].dirty, i);
853 			if (buf) {
854 				if (_BreakFromDirty(dev, buf) == U_SUCC) {
855 					buf->mark = UFFS_BUF_VALID;
856 					buf->ext_mark &= ~UFFS_BUF_EXT_MARK_TRUNC_TAIL;
857 					_MoveNodeToHead(dev, buf);
858 				}
859 			}
860 		}
861 
862 		// swap the old block node and new block node.
863 		// it's important that we 'swap' the block and keep the node unchanged
864 		// so that allowing someone hold the node pointer unawared.
865 		switch (type) {
866 		case UFFS_TYPE_DIR:
867 			node->u.dir.parent = parent;
868 			node->u.dir.serial = serial;
869 			node->u.dir.block = newBlock;
870 			node->u.dir.checksum = data_sum;
871 			break;
872 		case UFFS_TYPE_FILE:
873 			node->u.file.parent = parent;
874 			node->u.file.serial = serial;
875 			node->u.file.block = newBlock;
876 			node->u.file.checksum = data_sum;
877 			break;
878 		case UFFS_TYPE_DATA:
879 			node->u.data.parent = parent;
880 			node->u.data.serial = serial;
881 			node->u.data.block = newBlock;
882 			break;
883 		default:
884 			uffs_Perror(UFFS_MSG_SERIOUS, "UNKNOW TYPE");
885 			break;
886 		}
887 
888 		newNode->u.list.block = bc->block;
889 
890 		// if the recovered block is a bad block, it's time to process it.
891 		if (HAVE_BADBLOCK(dev) && dev->bad.block == newNode->u.list.block) {
892 			//uffs_Perror(UFFS_MSG_SERIOUS, "Still have bad block ?");
893 			uffs_BadBlockProcess(dev, newNode);
894 		}
895 		else {
896 			// erase recovered block, put it back to erased block list.
897 			if (uffs_IsThisBlockUsed(dev, bc)) {
898 				uffs_FlashEraseBlock(dev, bc->block);
899 			}
900 			if (HAVE_BADBLOCK(dev))
901 				uffs_BadBlockProcess(dev, newNode);
902 			else
903 				uffs_TreeInsertToErasedListTail(dev, newNode);
904 		}
905 	}
906 	else {
907 
908 		uffs_BlockInfoExpire(dev, bc, UFFS_ALL_PAGES);  // FIXME: this might not be necessary ...
909 
910 		uffs_FlashEraseBlock(dev, newBlock);
911 		newNode->u.list.block = newBlock;
912 		if (HAVE_BADBLOCK(dev))
913 			uffs_BadBlockProcess(dev, newNode);
914 		else
915 			uffs_TreeInsertToErasedListTail(dev, newNode);
916 	}
917 
918 	if (dev->buf.dirtyGroup[slot].dirty != NULL ||
919 			dev->buf.dirtyGroup[slot].count != 0) {
920 		uffs_Perror(UFFS_MSG_NORMAL, "still have dirty buffer ?");
921 	}
922 
923 	uffs_BlockInfoPut(dev, newBc);
924 
925 ext:
926 	return (succRecover == U_TRUE ? U_SUCC : U_FAIL);
927 
928 }
929 
930 
931 
932 /**
933  * \brief flush buffer to a new block which is not registered in tree
934  *
935  * Scenario:
936  *		1. get a new block
937  *		2. write pages in dirty list to new block, sorted by page_id
938  *		3. insert new block to tree
939  */
_BufFlush_NewBlock(uffs_Device * dev,int slot)940 static URET _BufFlush_NewBlock(uffs_Device *dev, int slot)
941 {
942 	u8 type;
943 	TreeNode *node;
944 	uffs_BlockInfo *bc;
945 	URET ret;
946 
947 	ret = U_FAIL;
948 
949 	node = uffs_TreeGetErasedNode(dev);
950 	if (node == NULL) {
951 		uffs_Perror(UFFS_MSG_NOISY, "no erased block!");
952 		goto ext;
953 	}
954 	bc = uffs_BlockInfoGet(dev, node->u.list.block);
955 	if (bc == NULL) {
956 		uffs_Perror(UFFS_MSG_SERIOUS, "get block info fail!");
957 		uffs_InsertToErasedListHead(dev, node); //put node back to erased list
958 		goto ext;
959 	}
960 
961 	type = dev->buf.dirtyGroup[slot].dirty->type;
962 
963 	ret = uffs_BufFlush_Exist_With_BlockCover(dev, slot, node, bc);
964 
965 	if (ret == U_SUCC)
966 		uffs_InsertNodeToTree(dev, type, node);
967 	else {
968 		uffs_FlashEraseBlock(dev, bc->block);
969 		uffs_TreeInsertToErasedListTail(dev, node);
970 	}
971 
972 	uffs_BlockInfoPut(dev, bc);
973 ext:
974 	return ret;
975 }
976 
977 
978 /**
979  * \brief flush buffer to a block with enough free pages
980  *
981  *  pages in dirty list must be sorted by page_id to write to flash
982  */
983 static
984 URET
uffs_BufFlush_Exist_With_Enough_FreePage(uffs_Device * dev,int slot,TreeNode * node,uffs_BlockInfo * bc)985  uffs_BufFlush_Exist_With_Enough_FreePage(
986 		uffs_Device *dev,
987 		int slot,			//!< dirty group slot
988 		TreeNode *node,		//!< tree node
989 		uffs_BlockInfo *bc	//!< block info (Source, also destination)
990 		)
991 {
992 	u16 page;
993 	uffs_Buf *buf;
994 	uffs_Tags *tag;
995 	URET ret = U_FAIL;
996 	int x;
997 
998 //	uffs_Perror(UFFS_MSG_NOISY,
999 //					"Flush buffers with Enough Free Page to block %d",
1000 //					bc->block);
1001 
1002 	for (page = 1;	// page 0 won't be a free page, so we start from 1.
1003 			page < dev->attr->pages_per_block &&
1004 			dev->buf.dirtyGroup[slot].count > 0;		//still has dirty pages?
1005 			page++) {
1006 
1007 		// locate to the free page (make sure the page is a erased page, so an unclean page won't sneak in)
1008 		for (; page < dev->attr->pages_per_block; page++) {
1009 			if (uffs_IsPageErased(dev, bc, page))
1010 				break;
1011 		}
1012 
1013 		if (!uffs_Assert(page < dev->attr->pages_per_block, "no free page? buf flush not finished."))
1014 			break;
1015 
1016 		buf = _FindMinimunPageIdFromDirtyList(dev->buf.dirtyGroup[slot].dirty);
1017 		if (buf == NULL) {
1018 			uffs_Perror(UFFS_MSG_SERIOUS,
1019 						"count > 0, but no dirty pages in list ?");
1020 			goto ext;
1021 		}
1022 
1023 		//write the dirty page (id: buf->page_id) to page (free page)
1024 		tag = GET_TAG(bc, page);
1025 		TAG_DIRTY_BIT(tag) = TAG_DIRTY;
1026 		TAG_VALID_BIT(tag) = TAG_VALID;
1027 		TAG_BLOCK_TS(tag) = uffs_GetBlockTimeStamp(dev, bc);
1028 		TAG_DATA_LEN(tag) = buf->data_len;
1029 		TAG_TYPE(tag) = buf->type;
1030 		TAG_PARENT(tag) = buf->parent;
1031 		TAG_SERIAL(tag) = buf->serial;
1032 		TAG_PAGE_ID(tag) = (u8)(buf->page_id);
1033 
1034 		SEAL_TAG(tag);
1035 
1036 		x = uffs_FlashWritePageCombine(dev, bc->block, page, buf, tag);
1037 		if (x == UFFS_FLASH_IO_ERR) {
1038 			uffs_Perror(UFFS_MSG_NORMAL, "I/O error <1>?");
1039 			goto ext;
1040 		}
1041 		else if (x == UFFS_FLASH_BAD_BLK) {
1042 			uffs_Perror(UFFS_MSG_NORMAL, "Bad blcok found, start block cover ...");
1043 			ret = uffs_BufFlush_Exist_With_BlockCover(dev, slot, node, bc);
1044 			goto ext;
1045 		}
1046 		else {
1047 			if(_BreakFromDirty(dev, buf) == U_SUCC) {
1048 				buf->mark = UFFS_BUF_VALID;
1049 				_MoveNodeToHead(dev, buf);
1050 			}
1051 		}
1052 	} //end of for
1053 
1054 	if (dev->buf.dirtyGroup[slot].dirty != NULL ||
1055 			dev->buf.dirtyGroup[slot].count != 0) {
1056 		uffs_Perror(UFFS_MSG_NORMAL, "still has dirty buffer ?");
1057 	}
1058 	else {
1059 		ret = U_SUCC;
1060 	}
1061 
1062 ext:
1063 	return ret;
1064 }
1065 
1066 
_BufFlush(struct uffs_DeviceSt * dev,UBOOL force_block_recover,int slot)1067 URET _BufFlush(struct uffs_DeviceSt *dev,
1068 			   UBOOL force_block_recover, int slot)
1069 {
1070 	uffs_Buf *dirty;
1071 	TreeNode *node;
1072 	uffs_BlockInfo *bc;
1073 	u16 n;
1074 	URET ret;
1075 	u8 type;
1076 	u16 parent;
1077 	u16 serial;
1078 	int block;
1079 
1080 	if (dev->buf.dirtyGroup[slot].count == 0) {
1081 		return U_SUCC;
1082 	}
1083 
1084 	dirty = dev->buf.dirtyGroup[slot].dirty;
1085 
1086 	if (_CheckDirtyList(dirty) == U_FAIL)
1087 		return U_FAIL;
1088 
1089 	type = dirty->type;
1090 	parent = dirty->parent;
1091 	serial = dirty->serial;
1092 
1093 	switch (type) {
1094 	case UFFS_TYPE_DIR:
1095 		node = uffs_TreeFindDirNode(dev, serial);
1096 		break;
1097 	case UFFS_TYPE_FILE:
1098 		node = uffs_TreeFindFileNode(dev, serial);
1099 		break;
1100 	case UFFS_TYPE_DATA:
1101 		node = uffs_TreeFindDataNode(dev, parent, serial);
1102 		break;
1103 	default:
1104 		uffs_Perror(UFFS_MSG_SERIOUS, "unknown type");
1105 		return U_FAIL;
1106 	}
1107 
1108 	if (node == NULL) {
1109 		//not found in the tree, need to generate a new block
1110 		ret = _BufFlush_NewBlock(dev, slot);
1111 	}
1112 	else {
1113 		switch (type) {
1114 		case UFFS_TYPE_DIR:
1115 			block = node->u.dir.block;
1116 			break;
1117 		case UFFS_TYPE_FILE:
1118 			block = node->u.file.block;
1119 			break;
1120 		case UFFS_TYPE_DATA:
1121 			block = node->u.data.block;
1122 			break;
1123 		default:
1124 			uffs_Perror(UFFS_MSG_SERIOUS, "unknown type.");
1125 			return U_FAIL;
1126 		}
1127 		bc = uffs_BlockInfoGet(dev, block);
1128 		if(bc == NULL) {
1129 			uffs_Perror(UFFS_MSG_SERIOUS, "get block info fail.");
1130 			return U_FAIL;
1131 		}
1132 
1133 		ret = uffs_BlockInfoLoad(dev, bc, UFFS_ALL_PAGES);
1134 		if (ret == U_SUCC) {
1135 
1136 			n = uffs_GetFreePagesCount(dev, bc);
1137 
1138 			if (n >= dev->buf.dirtyGroup[slot].count && !force_block_recover) {
1139 				//The free pages are enough for the dirty pages
1140 				ret = uffs_BufFlush_Exist_With_Enough_FreePage(dev,	slot, node, bc);
1141 			}
1142 			else {
1143 				ret = uffs_BufFlush_Exist_With_BlockCover(dev, slot, node, bc);
1144 			}
1145 		}
1146 		uffs_BlockInfoPut(dev, bc);
1147 	}
1148 
1149 	return ret;
1150 }
1151 
_FindMostDirtyGroup(struct uffs_DeviceSt * dev)1152 static int _FindMostDirtyGroup(struct uffs_DeviceSt *dev)
1153 {
1154 	int i, slot = -1;
1155 	int max_count = 0;
1156 
1157 	for (i = 0; i < dev->cfg.dirty_groups; i++) {
1158 		if (dev->buf.dirtyGroup[i].dirty &&
1159 				dev->buf.dirtyGroup[i].lock == 0) {
1160 			if (dev->buf.dirtyGroup[i].count > max_count) {
1161 				max_count = dev->buf.dirtyGroup[i].count;
1162 				slot = i;
1163 			}
1164 		}
1165 	}
1166 
1167 	return slot;
1168 }
1169 
1170 /** lock dirty group */
uffs_BufLockGroup(struct uffs_DeviceSt * dev,int slot)1171 URET uffs_BufLockGroup(struct uffs_DeviceSt *dev, int slot)
1172 {
1173 	URET ret = U_FAIL;
1174 	if (slot >= 0 && slot < dev->cfg.dirty_groups) {
1175 		dev->buf.dirtyGroup[slot].lock++;
1176 		ret = U_SUCC;
1177 	}
1178 	return ret;
1179 }
1180 
1181 /** unlock dirty group */
uffs_BufUnLockGroup(struct uffs_DeviceSt * dev,int slot)1182 URET uffs_BufUnLockGroup(struct uffs_DeviceSt *dev, int slot)
1183 {
1184 	URET ret = U_FAIL;
1185 
1186 	if (slot >= 0 && slot < dev->cfg.dirty_groups) {
1187 		if (dev->buf.dirtyGroup[slot].lock > 0)
1188 			dev->buf.dirtyGroup[slot].lock--;
1189 		else {
1190 			uffs_Perror(UFFS_MSG_SERIOUS, "Try to unlock an unlocked group ?");
1191 		}
1192 		ret = U_SUCC;
1193 	}
1194 	return ret;
1195 }
1196 
1197 
1198 /**
1199  * flush buffers to flash.
1200  * this will flush all dirty groups.
1201  * \param[in] dev uffs device
1202  */
uffs_BufFlush(struct uffs_DeviceSt * dev)1203 URET uffs_BufFlush(struct uffs_DeviceSt *dev)
1204 {
1205 	int slot;
1206 
1207 	slot = uffs_BufFindFreeGroupSlot(dev);
1208 	if (slot >= 0)
1209 		return U_SUCC;	// do nothing if there is free slot
1210 	else
1211 		return uffs_BufFlushMostDirtyGroup(dev);
1212 }
1213 
1214 /**
1215  * flush most dirty group
1216  * \param[in] dev uffs device
1217  */
uffs_BufFlushMostDirtyGroup(struct uffs_DeviceSt * dev)1218 URET uffs_BufFlushMostDirtyGroup(struct uffs_DeviceSt *dev)
1219 {
1220 	int slot;
1221 
1222 	slot = _FindMostDirtyGroup(dev);
1223 	if (slot >= 0) {
1224 		return _BufFlush(dev, U_FALSE, slot);
1225 	}
1226 	return U_SUCC;
1227 }
1228 
1229 /**
1230  * flush buffers to flash
1231  * this will pick up a most dirty group,
1232  * and flush it if there is no free dirty group slot.
1233  *
1234  * \param[in] dev uffs device
1235  * \param[in] force_block_recover #U_TRUE: force a block recover
1236  *				 even there are enough free pages
1237  */
uffs_BufFlushEx(struct uffs_DeviceSt * dev,UBOOL force_block_recover)1238 URET uffs_BufFlushEx(struct uffs_DeviceSt *dev, UBOOL force_block_recover)
1239 {
1240 	int slot;
1241 
1242 	slot = uffs_BufFindFreeGroupSlot(dev);
1243 	if (slot >= 0) {
1244 		return U_SUCC;  //there is free slot, do nothing.
1245 	}
1246 	else {
1247 		slot = _FindMostDirtyGroup(dev);
1248 		return _BufFlush(dev, force_block_recover, slot);
1249 	}
1250 }
1251 
1252 /**
1253  * flush buffer group with given parent/serial num.
1254  *
1255  * \param[in] dev uffs device
1256  * \param[in] parent parent num of the group
1257  * \param[in] serial serial num of the group
1258  */
uffs_BufFlushGroup(struct uffs_DeviceSt * dev,u16 parent,u16 serial)1259 URET uffs_BufFlushGroup(struct uffs_DeviceSt *dev, u16 parent, u16 serial)
1260 {
1261 	int slot;
1262 
1263 	slot = uffs_BufFindGroupSlot(dev, parent, serial);
1264 	if (slot >= 0) {
1265 		return _BufFlush(dev, U_FALSE, slot);
1266 	}
1267 
1268 	return U_SUCC;
1269 }
1270 
1271 /**
1272  * flush buffer group with given parent/serial num
1273  * and force_block_recover indicator.
1274  *
1275  * \param[in] dev uffs device
1276  * \param[in] parent parent num of the group
1277  * \param[in] serial serial num of group
1278  * \param[in] force_block_recover indicator
1279  */
uffs_BufFlushGroupEx(struct uffs_DeviceSt * dev,u16 parent,u16 serial,UBOOL force_block_recover)1280 URET uffs_BufFlushGroupEx(struct uffs_DeviceSt *dev,
1281 						  u16 parent, u16 serial, UBOOL force_block_recover)
1282 {
1283 	int slot;
1284 
1285 	slot = uffs_BufFindGroupSlot(dev, parent, serial);
1286 	if (slot >= 0) {
1287 		return _BufFlush(dev, force_block_recover, slot);
1288 	}
1289 
1290 	return U_SUCC;
1291 }
1292 
1293 
1294 /**
1295  * flush buffer group/groups which match given parent num.
1296  *
1297  * \param[in] dev uffs device
1298  * \param[in] parent parent num of the group
1299  * \param[in] serial serial num of group
1300  * \param[in] force_block_recover indicator
1301  */
uffs_BufFlushGroupMatchParent(struct uffs_DeviceSt * dev,u16 parent)1302 URET uffs_BufFlushGroupMatchParent(struct uffs_DeviceSt *dev, u16 parent)
1303 {
1304 	int slot;
1305 	uffs_Buf *buf;
1306 	URET ret = U_SUCC;
1307 
1308 	for (slot = 0; slot < dev->cfg.dirty_groups && ret == U_SUCC; slot++) {
1309 		if (dev->buf.dirtyGroup[slot].dirty) {
1310 			buf = dev->buf.dirtyGroup[slot].dirty;
1311 			if (buf->parent == parent) {
1312 				ret = _BufFlush(dev, U_FALSE, slot);
1313 			}
1314 		}
1315 	}
1316 
1317 	return ret;
1318 }
1319 
1320 /**
1321  * find a free dirty group slot
1322  *
1323  * \param[in] dev uffs device
1324  * \return slot index (0 to MAX_DIRTY_BUF_GROUPS - 1) if found one,
1325  *			 otherwise return -1.
1326  */
uffs_BufFindFreeGroupSlot(struct uffs_DeviceSt * dev)1327 int uffs_BufFindFreeGroupSlot(struct uffs_DeviceSt *dev)
1328 {
1329 	int i, slot = -1;
1330 
1331 	for (i = 0; i < dev->cfg.dirty_groups; i++) {
1332 		if (dev->buf.dirtyGroup[i].dirty == NULL) {
1333 			slot = i;
1334 			break;
1335 		}
1336 	}
1337 	return slot;
1338 }
1339 
1340 /**
1341  * find a dirty group slot with given parent/serial num.
1342  *
1343  * \param[in] dev uffs device
1344  * \param[in] parent parent num of the group
1345  * \param[in] serial serial num of group
1346  * \return slot index (0 to MAX_DIRTY_BUF_GROUPS - 1) if found one,
1347  *			otherwise return -1.
1348  */
uffs_BufFindGroupSlot(struct uffs_DeviceSt * dev,u16 parent,u16 serial)1349 int uffs_BufFindGroupSlot(struct uffs_DeviceSt *dev, u16 parent, u16 serial)
1350 {
1351 	uffs_Buf *buf;
1352 	int i, slot = -1;
1353 
1354 	for (i = 0; i < dev->cfg.dirty_groups; i++) {
1355 		if (dev->buf.dirtyGroup[i].dirty) {
1356 			buf = dev->buf.dirtyGroup[i].dirty;
1357 			if (buf->parent == parent && buf->serial == serial) {
1358 				slot = i;
1359 				break;
1360 			}
1361 		}
1362 	}
1363 	return slot;
1364 }
1365 
1366 /**
1367  * \brief get a page buffer
1368  * \param[in] dev uffs device
1369  * \param[in] parent parent serial num
1370  * \param[in] serial serial num
1371  * \param[in] page_id page_id
1372  * \return return the buffer found in buffer list, if not found, return NULL.
1373  */
uffs_BufGet(struct uffs_DeviceSt * dev,u16 parent,u16 serial,u16 page_id)1374 uffs_Buf * uffs_BufGet(struct uffs_DeviceSt *dev,
1375 					   u16 parent, u16 serial, u16 page_id)
1376 {
1377 	uffs_Buf *p;
1378 
1379 	//first, check whether the buffer exist in buf list ?
1380 	p = uffs_BufFind(dev, parent, serial, page_id);
1381 
1382 	if (p) {
1383 		p->ref_count++;
1384 		_MoveNodeToHead(dev, p);
1385 	}
1386 
1387 	return p;
1388 }
1389 
1390 /**
1391  * New generate a buffer
1392  */
uffs_BufNew(struct uffs_DeviceSt * dev,u8 type,u16 parent,u16 serial,u16 page_id)1393 uffs_Buf *uffs_BufNew(struct uffs_DeviceSt *dev,
1394 					  u8 type, u16 parent, u16 serial, u16 page_id)
1395 {
1396 	uffs_Buf *buf;
1397 
1398 	buf = uffs_BufGet(dev, parent, serial, page_id);
1399 	if (buf) {
1400 		if (buf->ref_count > 1) {
1401 			uffs_Perror(UFFS_MSG_SERIOUS, "When create new buf, \
1402 						an exist buffer has ref count %d, possibly bug!",
1403 						buf->ref_count);
1404 		}
1405 		else {
1406 			buf->data_len = 0;
1407 		}
1408 		_MoveNodeToHead(dev, buf);
1409 		return buf;
1410 	}
1411 
1412 	buf = _FindFreeBuf(dev);
1413 	if (buf == NULL) {
1414 		uffs_BufFlushMostDirtyGroup(dev);
1415 		buf = _FindFreeBuf(dev);
1416 		if (buf == NULL) {
1417 			uffs_Perror(UFFS_MSG_SERIOUS, "no free page buf!");
1418 			return NULL;
1419 		}
1420 	}
1421 
1422 	buf->mark = UFFS_BUF_EMPTY;
1423 	buf->type = type;
1424 	buf->parent = parent;
1425 	buf->serial = serial;
1426 	buf->page_id = page_id;
1427 	buf->data_len = 0;
1428 	buf->ref_count++;
1429 	memset(buf->data, 0xff, dev->com.pg_data_size);
1430 
1431 	_MoveNodeToHead(dev, buf);
1432 
1433 	return buf;
1434 }
1435 
1436 
1437 
1438 /**
1439  * get a page buffer
1440  * \param[in] dev uffs device
1441  * \param[in] type dir, file or data ?
1442  * \param[in] node node on the tree
1443  * \param[in] page_id page_id
1444  * \param[in] oflag the open flag of current file/dir object
1445  * \return return the buffer if found in buffer list, if not found in
1446  *		buffer list, it will get a free buffer, and load data from flash.
1447  *		return NULL if not free buffer.
1448  */
uffs_BufGetEx(struct uffs_DeviceSt * dev,u8 type,TreeNode * node,u16 page_id,int oflag)1449 uffs_Buf *uffs_BufGetEx(struct uffs_DeviceSt *dev,
1450 						u8 type, TreeNode *node, u16 page_id, int oflag)
1451 {
1452 	uffs_Buf *buf;
1453 	u16 parent, serial, block, page;
1454 	uffs_BlockInfo *bc;
1455 
1456 	switch (type) {
1457 	case UFFS_TYPE_DIR:
1458 		parent = node->u.dir.parent;
1459 		serial = node->u.dir.serial;
1460 		block = node->u.dir.block;
1461 		break;
1462 	case UFFS_TYPE_FILE:
1463 		parent = node->u.file.parent;
1464 		serial = node->u.file.serial;
1465 		block = node->u.file.block;
1466 		break;
1467 	case UFFS_TYPE_DATA:
1468 		parent = node->u.data.parent;
1469 		serial = node->u.data.serial;
1470 		block = node->u.data.block;
1471 		break;
1472 	default:
1473 		uffs_Perror(UFFS_MSG_SERIOUS, "unknown type");
1474 		return NULL;
1475 	}
1476 
1477 	buf = uffs_BufFind(dev, parent, serial, page_id);
1478 	if (buf) {
1479 		buf->ref_count++;
1480 		return buf;
1481 	}
1482 
1483 	buf = _FindFreeBuf(dev);
1484 	if (buf == NULL) {
1485 		uffs_BufFlushMostDirtyGroup(dev);
1486 		buf = _FindFreeBuf(dev);
1487 		if (buf == NULL) {
1488 			uffs_Perror(UFFS_MSG_SERIOUS, "no free page buf!");
1489 			return NULL;
1490 		}
1491 
1492 		/* Note: if uffs_BufFlushMostDirtyGroup() flush the same block as we'll write to,
1493 		 *	the block will be changed to a new one! (and the content of 'node' is changed).
1494 		 *	So here we need to update block number from the new 'node'.
1495 		 */
1496 		switch (type) {
1497 		case UFFS_TYPE_DIR:
1498 			block = node->u.dir.block;
1499 			break;
1500 		case UFFS_TYPE_FILE:
1501 			block = node->u.file.block;
1502 			break;
1503 		case UFFS_TYPE_DATA:
1504 			block = node->u.data.block;
1505 			break;
1506 		default:
1507 			uffs_Perror(UFFS_MSG_SERIOUS, "unknown type");
1508 			return NULL;
1509 		}
1510 	}
1511 
1512 	bc = uffs_BlockInfoGet(dev, block);
1513 	if (bc == NULL) {
1514 		uffs_Perror(UFFS_MSG_SERIOUS, "Can't get block info!");
1515 		return NULL;
1516 	}
1517 
1518 	page = uffs_FindPageInBlockWithPageId(dev, bc, page_id);
1519 	if (page == UFFS_INVALID_PAGE) {
1520 		uffs_BlockInfoPut(dev, bc);
1521 		uffs_Perror(UFFS_MSG_SERIOUS, "can't find right page ? block %d page_id %d", bc->block, page_id);
1522 		return NULL;
1523 	}
1524 	page = uffs_FindBestPageInBlock(dev, bc, page);
1525 	if (!uffs_Assert(page != UFFS_INVALID_PAGE, "got an invalid page?\n"))
1526 		return NULL;
1527 
1528 	uffs_BlockInfoPut(dev, bc);
1529 
1530 	buf->mark = UFFS_BUF_EMPTY;
1531 	buf->type = type;
1532 	buf->parent = parent;
1533 	buf->serial = serial;
1534 	buf->page_id = page_id;
1535 
1536 	if (UFFS_FLASH_HAVE_ERR(uffs_FlashReadPage(dev, block, page, buf, oflag & UO_NOECC ? U_TRUE : U_FALSE))) {
1537 		uffs_Perror(UFFS_MSG_SERIOUS, "can't load page from flash !");
1538 		return NULL;
1539 	}
1540 
1541 	buf->data_len = TAG_DATA_LEN(GET_TAG(bc, page));
1542 	buf->mark = UFFS_BUF_VALID;
1543 	buf->ref_count++;
1544 
1545 	_MoveNodeToHead(dev, buf);
1546 
1547 	return buf;
1548 
1549 }
1550 
1551 /**
1552  * \brief Put back a page buffer, make reference count decrease by one
1553  * \param[in] dev uffs device
1554  * \param[in] buf buffer to be put back
1555  */
uffs_BufPut(uffs_Device * dev,uffs_Buf * buf)1556 URET uffs_BufPut(uffs_Device *dev, uffs_Buf *buf)
1557 {
1558 	URET ret = U_FAIL;
1559 
1560 	dev = dev;
1561 	if (buf == NULL) {
1562 		uffs_Perror(UFFS_MSG_NORMAL,  "Can't put an NULL buffer!");
1563 	}
1564 	else if (buf->ref_count == 0) {
1565 		uffs_Perror(UFFS_MSG_NORMAL,  "Putting an unused page buffer ? ");
1566 	}
1567 	else if (buf->ref_count == CLONE_BUF_MARK) {
1568 		uffs_Perror(UFFS_MSG_NORMAL, "Putting an cloned page buffer ? ");
1569 		ret = uffs_BufFreeClone(dev, buf);
1570 	}
1571 	else {
1572 		buf->ref_count--;
1573 		ret = U_SUCC;
1574 	}
1575 
1576 	return ret;
1577 }
1578 
1579 
1580 /**
1581  * \brief clone from an exist buffer.
1582 		allocate memory for new buffer, and copy data from original buffer if
1583 		original buffer is not NULL.
1584  * \param[in] dev uffs device
1585  * \param[in] buf page buffer to be clone from.
1586  *				if NULL presented here, data copy will not be processed
1587  * \return return the cloned page buffer, all data copied from source
1588  * \note the cloned buffer is not linked in page buffer list in uffs device,
1589  *			so you should use #uffs_BufFreeClone instead of #uffs_BufPut
1590  *			when you put back or release buffer
1591  */
uffs_BufClone(uffs_Device * dev,uffs_Buf * buf)1592 uffs_Buf * uffs_BufClone(uffs_Device *dev, uffs_Buf *buf)
1593 {
1594 	uffs_Buf *p;
1595 
1596 	p = _FindFreeBufEx(dev, 1);
1597 	if (p == NULL) {
1598 		uffs_Perror(UFFS_MSG_SERIOUS,
1599 					"no enough free pages for clone! " \
1600 					"Please increase Clone Buffer Count threshold.");
1601 	}
1602 	else {
1603 		_BreakFromBufList(dev, p);
1604 
1605 		if (buf) {
1606 			p->parent = buf->parent;
1607 			p->type = buf->type;
1608 			p->serial = buf->serial;
1609 			p->page_id = buf->page_id;
1610 
1611 			p->data_len = buf->data_len;
1612 			//athough the valid data length is .data_len,
1613 			//but we still need copy the whole buffer, include header
1614 			memcpy(p->header, buf->header, dev->com.pg_size);
1615 		}
1616 		p->next = p->prev = NULL; // the cloned one is not linked to device buffer
1617 		p->next_dirty = p->prev_dirty = NULL;
1618 		p->ref_count = CLONE_BUF_MARK;	// CLONE_BUF_MARK indicates that
1619 										// this is an cloned buffer
1620 	}
1621 
1622 	return p;
1623 }
1624 
1625 /**
1626  * \brief release cloned buffer
1627  * \param[in] dev uffs device
1628  * \param[in] buf cloned buffer
1629  */
uffs_BufFreeClone(uffs_Device * dev,uffs_Buf * buf)1630 URET uffs_BufFreeClone(uffs_Device *dev, uffs_Buf *buf)
1631 {
1632 	dev = dev; //make compiler happy
1633 	if (!buf)
1634 		return U_FAIL;
1635 
1636 	if (buf->ref_count != CLONE_BUF_MARK) {
1637 		/* a cloned buffer must have a ref_count of CLONE_BUF_MARK */
1638 		uffs_Perror(UFFS_MSG_SERIOUS,
1639 					"Try to release a non-cloned page buffer ?");
1640 		return U_FAIL;
1641 	}
1642 
1643 	buf->ref_count = 0;
1644 	buf->mark = UFFS_BUF_EMPTY;
1645 	_LinkToBufListTail(dev, buf);
1646 
1647 	return U_SUCC;
1648 }
1649 
1650 
1651 
uffs_BufIsAllFree(struct uffs_DeviceSt * dev)1652 UBOOL uffs_BufIsAllFree(struct uffs_DeviceSt *dev)
1653 {
1654 	uffs_Buf *buf = dev->buf.head;
1655 
1656 	while (buf) {
1657 		if(buf->ref_count != 0) return U_FALSE;
1658 		buf = buf->next;
1659 	}
1660 
1661 	return U_TRUE;
1662 }
1663 
uffs_BufIsAllEmpty(struct uffs_DeviceSt * dev)1664 UBOOL uffs_BufIsAllEmpty(struct uffs_DeviceSt *dev)
1665 {
1666 	uffs_Buf *buf = dev->buf.head;
1667 
1668 	while (buf) {
1669 		if(buf->mark != UFFS_BUF_EMPTY) return U_FALSE;
1670 		buf = buf->next;
1671 	}
1672 
1673 	return U_TRUE;
1674 }
1675 
1676 
uffs_BufSetAllEmpty(struct uffs_DeviceSt * dev)1677 URET uffs_BufSetAllEmpty(struct uffs_DeviceSt *dev)
1678 {
1679 	uffs_Buf *buf = dev->buf.head;
1680 
1681 	while (buf) {
1682 		buf->mark = UFFS_BUF_EMPTY;
1683 		buf = buf->next;
1684 	}
1685 	return U_SUCC;
1686 }
1687 
1688 
uffs_BufIncRef(uffs_Buf * buf)1689 void uffs_BufIncRef(uffs_Buf *buf)
1690 {
1691 	buf->ref_count++;
1692 }
1693 
uffs_BufDecRef(uffs_Buf * buf)1694 void uffs_BufDecRef(uffs_Buf *buf)
1695 {
1696 	if (buf->ref_count > 0)
1697 		buf->ref_count--;
1698 }
1699 
1700 /** mark buffer as #UFFS_BUF_EMPTY if ref_count == 0,
1701 	and discard all data it holds */
uffs_BufMarkEmpty(uffs_Device * dev,uffs_Buf * buf)1702 void uffs_BufMarkEmpty(uffs_Device *dev, uffs_Buf *buf)
1703 {
1704 	if (buf->mark != UFFS_BUF_EMPTY) {
1705 		if (buf->ref_count == 0) {
1706 			if (buf->mark == UFFS_BUF_DIRTY)
1707 				_BreakFromDirty(dev, buf);
1708 			buf->mark = UFFS_BUF_EMPTY;
1709 		}
1710 	}
1711 }
1712 
1713 #if 0
1714 static UBOOL _IsBufInDirtyList(struct uffs_DeviceSt *dev, uffs_Buf *buf)
1715 {
1716 	uffs_Buf *p = dev->buf.dirtyGroup[slot].dirty;
1717 
1718 	while (p) {
1719 		if(p == buf) return U_TRUE;
1720 		p = p->next_dirty;
1721 	}
1722 
1723 	return U_FALSE;
1724 }
1725 #endif
1726 
uffs_BufWrite(struct uffs_DeviceSt * dev,uffs_Buf * buf,void * data,u32 ofs,u32 len)1727 URET uffs_BufWrite(struct uffs_DeviceSt *dev,
1728 				   uffs_Buf *buf, void *data, u32 ofs, u32 len)
1729 {
1730 	int slot;
1731 
1732 	if(ofs + len > dev->com.pg_data_size) {
1733 		uffs_Perror(UFFS_MSG_SERIOUS,
1734 					"data length out of range! %d+%d", ofs, len);
1735 		return U_FAIL;
1736 	}
1737 
1738 	slot = uffs_BufFindGroupSlot(dev, buf->parent, buf->serial);
1739 
1740 	if (slot < 0) {
1741 		// need to take a free slot
1742 		slot = uffs_BufFindFreeGroupSlot(dev);
1743 		if (slot < 0) {
1744 			// no free slot ? flush buffer
1745 			if (uffs_BufFlushMostDirtyGroup(dev) != U_SUCC)
1746 				return U_FAIL;
1747 
1748 			slot = uffs_BufFindFreeGroupSlot(dev);
1749 			if (slot < 0) {
1750 				// still no free slot ??
1751 				uffs_Perror(UFFS_MSG_SERIOUS, "no free slot ?");
1752 				return U_FAIL;
1753 			}
1754 		}
1755 	}
1756 
1757 	if (data)
1758 		memcpy(buf->data + ofs, data, len);
1759 	else
1760 		memset(buf->data + ofs, 0, len);	// if data == NULL, then fill all '\0'.
1761 
1762 	if (ofs + len > buf->data_len)
1763 		buf->data_len = ofs + len;
1764 
1765 	if (_IsBufInInDirtyList(dev, slot, buf) == U_FALSE) {
1766 		_LinkToDirtyList(dev, slot, buf);
1767 	}
1768 
1769 	if (dev->buf.dirtyGroup[slot].count >= dev->buf.dirty_buf_max) {
1770 		if (uffs_BufFlushGroup(dev, buf->parent, buf->serial) != U_SUCC) {
1771 			return U_FAIL;
1772 		}
1773 	}
1774 
1775 	return U_SUCC;
1776 }
1777 
uffs_BufRead(struct uffs_DeviceSt * dev,uffs_Buf * buf,void * data,u32 ofs,u32 len)1778 URET uffs_BufRead(struct uffs_DeviceSt *dev,
1779 				  uffs_Buf *buf, void *data, u32 ofs, u32 len)
1780 {
1781 	u32 readSize;
1782 	u32 pg_data_size = dev->com.pg_data_size;
1783 
1784 	readSize = (ofs >= pg_data_size ?
1785 					0 : (ofs + len >= pg_data_size ? pg_data_size - ofs : len)
1786 				);
1787 
1788 	if (readSize > 0)
1789 		memcpy(data, buf->data + ofs, readSize);
1790 
1791 	return U_SUCC;
1792 }
1793 
1794 
1795 
1796 
1797 
1798 
1799 
1800