2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
7 * Created by Charles Manning <charles@aleph1.co.uk>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
14 #include "yaffs_trace.h"
16 #include "yaffsinterface.h"
17 #include "yaffs_guts.h"
18 #include "yaffs_tagsvalidity.h"
19 #include "yaffs_getblockinfo.h"
21 #include "yaffs_tagscompat.h"
23 #include "yaffs_nand.h"
25 #include "yaffs_yaffs1.h"
26 #include "yaffs_yaffs2.h"
27 #include "yaffs_bitmap.h"
28 #include "yaffs_verify.h"
30 #include "yaffs_nand.h"
31 #include "yaffs_packedtags2.h"
33 #include "yaffs_nameval.h"
34 #include "yaffs_allocator.h"
36 /* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */
37 #define YAFFS_GC_GOOD_ENOUGH 2
38 #define YAFFS_GC_PASSIVE_THRESHOLD 4
40 #include "yaffs_ecc.h"
44 /* Robustification (if it ever comes about...) */
45 static void yaffs_retire_block(yaffs_dev_t
*dev
, int flash_block
);
46 static void yaffs_handle_chunk_wr_error(yaffs_dev_t
*dev
, int nand_chunk
,
48 static void yaffs_handle_chunk_wr_ok(yaffs_dev_t
*dev
, int nand_chunk
,
50 const yaffs_ext_tags
*tags
);
51 static void yaffs_handle_chunk_update(yaffs_dev_t
*dev
, int nand_chunk
,
52 const yaffs_ext_tags
*tags
);
54 /* Other local prototypes */
55 static void yaffs_update_parent(yaffs_obj_t
*obj
);
56 static int yaffs_unlink_obj(yaffs_obj_t
*obj
);
57 static int yaffs_obj_cache_dirty(yaffs_obj_t
*obj
);
59 static int yaffs_write_new_chunk(yaffs_dev_t
*dev
,
65 static yaffs_obj_t
*yaffs_new_obj(yaffs_dev_t
*dev
, int number
,
69 static int yaffs_apply_xattrib_mod(yaffs_obj_t
*obj
, char *buffer
, yaffs_xattr_mod
*xmod
);
71 static void yaffs_remove_obj_from_dir(yaffs_obj_t
*obj
);
72 static int yaffs_check_structures(void);
73 static int yaffs_generic_obj_del(yaffs_obj_t
*in
);
75 static int yaffs_check_chunk_erased(struct yaffs_dev_s
*dev
,
78 static int yaffs_unlink_worker(yaffs_obj_t
*obj
);
80 static int yaffs_tags_match(const yaffs_ext_tags
*tags
, int obj_id
,
83 static int yaffs_alloc_chunk(yaffs_dev_t
*dev
, int useReserve
,
84 yaffs_block_info_t
**blockUsedPtr
);
86 static void yaffs_check_obj_details_loaded(yaffs_obj_t
*in
);
88 static void yaffs_invalidate_whole_cache(yaffs_obj_t
*in
);
89 static void yaffs_invalidate_chunk_cache(yaffs_obj_t
*object
, int chunk_id
);
91 static int yaffs_find_chunk_in_file(yaffs_obj_t
*in
, int inode_chunk
,
92 yaffs_ext_tags
*tags
);
94 static int yaffs_verify_chunk_written(yaffs_dev_t
*dev
,
97 yaffs_ext_tags
*tags
);
100 static void yaffs_load_name_from_oh(yaffs_dev_t
*dev
,YCHAR
*name
, const YCHAR
*ohName
, int bufferSize
);
101 static void yaffs_load_oh_from_name(yaffs_dev_t
*dev
,YCHAR
*ohName
, const YCHAR
*name
);
104 /* Function to calculate chunk and offset */
106 static void yaffs_addr_to_chunk(yaffs_dev_t
*dev
, loff_t addr
, int *chunkOut
,
112 chunk
= (__u32
)(addr
>> dev
->chunk_shift
);
114 if (dev
->chunk_div
== 1) {
115 /* easy power of 2 case */
116 offset
= (__u32
)(addr
& dev
->chunk_mask
);
118 /* Non power-of-2 case */
122 chunk
/= dev
->chunk_div
;
124 chunkBase
= ((loff_t
)chunk
) * dev
->data_bytes_per_chunk
;
125 offset
= (__u32
)(addr
- chunkBase
);
132 /* Function to return the number of shifts for a power of 2 greater than or
133 * equal to the given number
134 * Note we don't try to cater for all possible numbers and this does not have to
135 * be hellishly efficient.
138 static __u32
ShiftsGE(__u32 x
)
143 nShifts
= extraBits
= 0;
158 /* Function to return the number of shifts to get a 1 in bit 0
161 static __u32
Shifts(__u32 x
)
181 * Temporary buffer manipulations.
184 static int yaffs_init_tmp_buffers(yaffs_dev_t
*dev
)
187 __u8
*buf
= (__u8
*)1;
189 memset(dev
->temp_buffer
, 0, sizeof(dev
->temp_buffer
));
191 for (i
= 0; buf
&& i
< YAFFS_N_TEMP_BUFFERS
; i
++) {
192 dev
->temp_buffer
[i
].line
= 0; /* not in use */
193 dev
->temp_buffer
[i
].buffer
= buf
=
194 YMALLOC_DMA(dev
->param
.total_bytes_per_chunk
);
197 return buf
? YAFFS_OK
: YAFFS_FAIL
;
200 __u8
*yaffs_get_temp_buffer(yaffs_dev_t
*dev
, int line_no
)
205 if (dev
->temp_in_use
> dev
->max_temp
)
206 dev
->max_temp
= dev
->temp_in_use
;
208 for (i
= 0; i
< YAFFS_N_TEMP_BUFFERS
; i
++) {
209 if (dev
->temp_buffer
[i
].line
== 0) {
210 dev
->temp_buffer
[i
].line
= line_no
;
211 if ((i
+ 1) > dev
->max_temp
) {
212 dev
->max_temp
= i
+ 1;
213 for (j
= 0; j
<= i
; j
++)
214 dev
->temp_buffer
[j
].max_line
=
215 dev
->temp_buffer
[j
].line
;
218 return dev
->temp_buffer
[i
].buffer
;
222 T(YAFFS_TRACE_BUFFERS
,
223 (TSTR("Out of temp buffers at line %d, other held by lines:"),
225 for (i
= 0; i
< YAFFS_N_TEMP_BUFFERS
; i
++)
226 T(YAFFS_TRACE_BUFFERS
, (TSTR(" %d "), dev
->temp_buffer
[i
].line
));
228 T(YAFFS_TRACE_BUFFERS
, (TSTR(" " TENDSTR
)));
231 * If we got here then we have to allocate an unmanaged one
235 dev
->unmanaged_buffer_allocs
++;
236 return YMALLOC(dev
->data_bytes_per_chunk
);
240 void yaffs_release_temp_buffer(yaffs_dev_t
*dev
, __u8
*buffer
,
247 for (i
= 0; i
< YAFFS_N_TEMP_BUFFERS
; i
++) {
248 if (dev
->temp_buffer
[i
].buffer
== buffer
) {
249 dev
->temp_buffer
[i
].line
= 0;
255 /* assume it is an unmanaged one. */
256 T(YAFFS_TRACE_BUFFERS
,
257 (TSTR("Releasing unmanaged temp buffer in line %d" TENDSTR
),
260 dev
->unmanaged_buffer_deallocs
++;
266 * Determine if we have a managed buffer.
268 int yaffs_is_managed_tmp_buffer(yaffs_dev_t
*dev
, const __u8
*buffer
)
272 for (i
= 0; i
< YAFFS_N_TEMP_BUFFERS
; i
++) {
273 if (dev
->temp_buffer
[i
].buffer
== buffer
)
277 for (i
= 0; i
< dev
->param
.n_caches
; i
++) {
278 if (dev
->cache
[i
].data
== buffer
)
282 if (buffer
== dev
->checkpt_buffer
)
285 T(YAFFS_TRACE_ALWAYS
,
286 (TSTR("yaffs: unmaged buffer detected.\n" TENDSTR
)));
298 * Simple hash function. Needs to have a reasonable spread
301 static Y_INLINE
int yaffs_hash_fn(int n
)
304 return n
% YAFFS_NOBJECT_BUCKETS
;
308 * Access functions to useful fake objects.
309 * Note that root might have a presence in NAND if permissions are set.
312 yaffs_obj_t
*yaffs_root(yaffs_dev_t
*dev
)
314 return dev
->root_dir
;
317 yaffs_obj_t
*yaffs_lost_n_found(yaffs_dev_t
*dev
)
319 return dev
->lost_n_found
;
324 * Erased NAND checking functions
327 int yaffs_check_ff(__u8
*buffer
, int n_bytes
)
329 /* Horrible, slow implementation */
338 static int yaffs_check_chunk_erased(struct yaffs_dev_s
*dev
,
341 int retval
= YAFFS_OK
;
342 __u8
*data
= yaffs_get_temp_buffer(dev
, __LINE__
);
346 result
= yaffs_rd_chunk_tags_nand(dev
, nand_chunk
, data
, &tags
);
348 if (tags
.ecc_result
> YAFFS_ECC_RESULT_NO_ERROR
)
351 if (!yaffs_check_ff(data
, dev
->data_bytes_per_chunk
) || tags
.chunk_used
) {
352 T(YAFFS_TRACE_NANDACCESS
,
353 (TSTR("Chunk %d not erased" TENDSTR
), nand_chunk
));
357 yaffs_release_temp_buffer(dev
, data
, __LINE__
);
364 static int yaffs_verify_chunk_written(yaffs_dev_t
*dev
,
367 yaffs_ext_tags
*tags
)
369 int retval
= YAFFS_OK
;
370 yaffs_ext_tags tempTags
;
371 __u8
*buffer
= yaffs_get_temp_buffer(dev
,__LINE__
);
374 result
= yaffs_rd_chunk_tags_nand(dev
,nand_chunk
,buffer
,&tempTags
);
375 if(memcmp(buffer
,data
,dev
->data_bytes_per_chunk
) ||
376 tempTags
.obj_id
!= tags
->obj_id
||
377 tempTags
.chunk_id
!= tags
->chunk_id
||
378 tempTags
.n_bytes
!= tags
->n_bytes
)
381 yaffs_release_temp_buffer(dev
, buffer
, __LINE__
);
386 static int yaffs_write_new_chunk(struct yaffs_dev_s
*dev
,
388 yaffs_ext_tags
*tags
,
395 yaffs2_checkpt_invalidate(dev
);
398 yaffs_block_info_t
*bi
= 0;
401 chunk
= yaffs_alloc_chunk(dev
, useReserve
, &bi
);
407 /* First check this chunk is erased, if it needs
408 * checking. The checking policy (unless forced
409 * always on) is as follows:
411 * Check the first page we try to write in a block.
412 * If the check passes then we don't need to check any
413 * more. If the check fails, we check again...
414 * If the block has been erased, we don't need to check.
416 * However, if the block has been prioritised for gc,
417 * then we think there might be something odd about
418 * this block and stop using it.
420 * Rationale: We should only ever see chunks that have
421 * not been erased if there was a partially written
422 * chunk due to power loss. This checking policy should
423 * catch that case with very few checks and thus save a
424 * lot of checks that are most likely not needed.
427 * If an erase check fails or the write fails we skip the
431 /* let's give it a try */
434 if(dev
->param
.always_check_erased
)
435 bi
->skip_erased_check
= 0;
437 if (!bi
->skip_erased_check
) {
438 erasedOk
= yaffs_check_chunk_erased(dev
, chunk
);
439 if (erasedOk
!= YAFFS_OK
) {
441 (TSTR("**>> yaffs chunk %d was not erased"
444 /* If not erased, delete this one,
445 * skip rest of block and
446 * try another chunk */
447 yaffs_chunk_del(dev
,chunk
,1,__LINE__
);
448 yaffs_skip_rest_of_block(dev
);
453 writeOk
= yaffs_wr_chunk_tags_nand(dev
, chunk
,
456 if(!bi
->skip_erased_check
)
457 writeOk
= yaffs_verify_chunk_written(dev
, chunk
, data
, tags
);
459 if (writeOk
!= YAFFS_OK
) {
460 /* Clean up aborted write, skip to next block and
461 * try another chunk */
462 yaffs_handle_chunk_wr_error(dev
, chunk
, erasedOk
);
466 bi
->skip_erased_check
= 1;
468 /* Copy the data into the robustification buffer */
469 yaffs_handle_chunk_wr_ok(dev
, chunk
, data
, tags
);
471 } while (writeOk
!= YAFFS_OK
&&
472 (yaffs_wr_attempts
<= 0 || attempts
<= yaffs_wr_attempts
));
479 (TSTR("**>> yaffs write required %d attempts" TENDSTR
),
482 dev
->n_retired_writes
+= (attempts
- 1);
491 * Block retiring for handling a broken block.
494 static void yaffs_retire_block(yaffs_dev_t
*dev
, int flash_block
)
496 yaffs_block_info_t
*bi
= yaffs_get_block_info(dev
, flash_block
);
498 yaffs2_checkpt_invalidate(dev
);
500 yaffs2_clear_oldest_dirty_seq(dev
,bi
);
502 if (yaffs_mark_bad(dev
, flash_block
) != YAFFS_OK
) {
503 if (yaffs_erase_block(dev
, flash_block
) != YAFFS_OK
) {
504 T(YAFFS_TRACE_ALWAYS
, (TSTR(
505 "yaffs: Failed to mark bad and erase block %d"
506 TENDSTR
), flash_block
));
509 int chunk_id
= flash_block
* dev
->param
.chunks_per_block
;
511 __u8
*buffer
= yaffs_get_temp_buffer(dev
, __LINE__
);
513 memset(buffer
, 0xff, dev
->data_bytes_per_chunk
);
514 yaffs_init_tags(&tags
);
515 tags
.seq_number
= YAFFS_SEQUENCE_BAD_BLOCK
;
516 if (dev
->param
.write_chunk_tags_fn(dev
, chunk_id
-
517 dev
->chunk_offset
, buffer
, &tags
) != YAFFS_OK
)
518 T(YAFFS_TRACE_ALWAYS
, (TSTR("yaffs: Failed to "
519 TCONT("write bad block marker to block %d")
520 TENDSTR
), flash_block
));
522 yaffs_release_temp_buffer(dev
, buffer
, __LINE__
);
526 bi
->block_state
= YAFFS_BLOCK_STATE_DEAD
;
527 bi
->gc_prioritise
= 0;
528 bi
->needs_retiring
= 0;
530 dev
->n_retired_blocks
++;
534 * Functions for robustisizing TODO
538 static void yaffs_handle_chunk_wr_ok(yaffs_dev_t
*dev
, int nand_chunk
,
540 const yaffs_ext_tags
*tags
)
543 nand_chunk
=nand_chunk
;
548 static void yaffs_handle_chunk_update(yaffs_dev_t
*dev
, int nand_chunk
,
549 const yaffs_ext_tags
*tags
)
552 nand_chunk
=nand_chunk
;
556 void yaffs_handle_chunk_error(yaffs_dev_t
*dev
, yaffs_block_info_t
*bi
)
558 if (!bi
->gc_prioritise
) {
559 bi
->gc_prioritise
= 1;
560 dev
->has_pending_prioritised_gc
= 1;
561 bi
->chunk_error_strikes
++;
563 if (bi
->chunk_error_strikes
> 3) {
564 bi
->needs_retiring
= 1; /* Too many stikes, so retire this */
565 T(YAFFS_TRACE_ALWAYS
, (TSTR("yaffs: Block struck out" TENDSTR
)));
571 static void yaffs_handle_chunk_wr_error(yaffs_dev_t
*dev
, int nand_chunk
,
574 int flash_block
= nand_chunk
/ dev
->param
.chunks_per_block
;
575 yaffs_block_info_t
*bi
= yaffs_get_block_info(dev
, flash_block
);
577 yaffs_handle_chunk_error(dev
, bi
);
580 /* Was an actual write failure, so mark the block for retirement */
581 bi
->needs_retiring
= 1;
582 T(YAFFS_TRACE_ERROR
| YAFFS_TRACE_BAD_BLOCKS
,
583 (TSTR("**>> Block %d needs retiring" TENDSTR
), flash_block
));
586 /* Delete the chunk */
587 yaffs_chunk_del(dev
, nand_chunk
, 1, __LINE__
);
588 yaffs_skip_rest_of_block(dev
);
592 /*---------------- Name handling functions ------------*/
594 static __u16
yaffs_calc_name_sum(const YCHAR
*name
)
599 const YUCHAR
*bname
= (const YUCHAR
*) name
;
601 while ((*bname
) && (i
< (YAFFS_MAX_NAME_LENGTH
/2))) {
603 #ifdef CONFIG_YAFFS_CASE_INSENSITIVE
604 sum
+= yaffs_toupper(*bname
) * i
;
615 void yaffs_set_obj_name(yaffs_obj_t
*obj
, const YCHAR
*name
)
617 #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
618 memset(obj
->short_name
, 0, sizeof(YCHAR
) * (YAFFS_SHORT_NAME_LENGTH
+1));
619 if (name
&& yaffs_strnlen(name
,YAFFS_SHORT_NAME_LENGTH
+1) <= YAFFS_SHORT_NAME_LENGTH
)
620 yaffs_strcpy(obj
->short_name
, name
);
622 obj
->short_name
[0] = _Y('\0');
624 obj
->sum
= yaffs_calc_name_sum(name
);
627 void yaffs_set_obj_name_from_oh(yaffs_obj_t
*obj
, const yaffs_obj_header
*oh
)
629 #ifdef CONFIG_YAFFS_AUTO_UNICODE
630 YCHAR tmpName
[YAFFS_MAX_NAME_LENGTH
+1];
631 memset(tmpName
,0,sizeof(tmpName
));
632 yaffs_load_name_from_oh(obj
->my_dev
,tmpName
,oh
->name
,YAFFS_MAX_NAME_LENGTH
+1);
633 yaffs_set_obj_name(obj
,tmpName
);
635 yaffs_set_obj_name(obj
,oh
->name
);
639 /*-------------------- TNODES -------------------
641 * List of spare tnodes
642 * The list is hooked together using the first pointer
647 yaffs_tnode_t
*yaffs_get_tnode(yaffs_dev_t
*dev
)
649 yaffs_tnode_t
*tn
= yaffs_alloc_raw_tnode(dev
);
651 memset(tn
, 0, dev
->tnode_size
);
655 dev
->checkpoint_blocks_required
= 0; /* force recalculation*/
660 /* FreeTnode frees up a tnode and puts it back on the free list */
661 static void yaffs_free_tnode(yaffs_dev_t
*dev
, yaffs_tnode_t
*tn
)
663 yaffs_free_raw_tnode(dev
,tn
);
665 dev
->checkpoint_blocks_required
= 0; /* force recalculation*/
668 static void yaffs_deinit_tnodes_and_objs(yaffs_dev_t
*dev
)
670 yaffs_deinit_raw_tnodes_and_objs(dev
);
676 void yaffs_load_tnode_0(yaffs_dev_t
*dev
, yaffs_tnode_t
*tn
, unsigned pos
,
679 __u32
*map
= (__u32
*)tn
;
685 pos
&= YAFFS_TNODES_LEVEL0_MASK
;
686 val
>>= dev
->chunk_grp_bits
;
688 bitInMap
= pos
* dev
->tnode_width
;
689 wordInMap
= bitInMap
/ 32;
690 bitInWord
= bitInMap
& (32 - 1);
692 mask
= dev
->tnode_mask
<< bitInWord
;
694 map
[wordInMap
] &= ~mask
;
695 map
[wordInMap
] |= (mask
& (val
<< bitInWord
));
697 if (dev
->tnode_width
> (32 - bitInWord
)) {
698 bitInWord
= (32 - bitInWord
);
700 mask
= dev
->tnode_mask
>> (/*dev->tnode_width -*/ bitInWord
);
701 map
[wordInMap
] &= ~mask
;
702 map
[wordInMap
] |= (mask
& (val
>> bitInWord
));
706 __u32
yaffs_get_group_base(yaffs_dev_t
*dev
, yaffs_tnode_t
*tn
,
709 __u32
*map
= (__u32
*)tn
;
715 pos
&= YAFFS_TNODES_LEVEL0_MASK
;
717 bitInMap
= pos
* dev
->tnode_width
;
718 wordInMap
= bitInMap
/ 32;
719 bitInWord
= bitInMap
& (32 - 1);
721 val
= map
[wordInMap
] >> bitInWord
;
723 if (dev
->tnode_width
> (32 - bitInWord
)) {
724 bitInWord
= (32 - bitInWord
);
726 val
|= (map
[wordInMap
] << bitInWord
);
729 val
&= dev
->tnode_mask
;
730 val
<<= dev
->chunk_grp_bits
;
735 /* ------------------- End of individual tnode manipulation -----------------*/
737 /* ---------Functions to manipulate the look-up tree (made up of tnodes) ------
738 * The look up tree is represented by the top tnode and the number of top_level
739 * in the tree. 0 means only the level 0 tnode is in the tree.
742 /* FindLevel0Tnode finds the level 0 tnode, if one exists. */
743 yaffs_tnode_t
*yaffs_find_tnode_0(yaffs_dev_t
*dev
,
744 yaffs_file_s
*file_struct
,
747 yaffs_tnode_t
*tn
= file_struct
->top
;
749 int requiredTallness
;
750 int level
= file_struct
->top_level
;
754 /* Check sane level and chunk Id */
755 if (level
< 0 || level
> YAFFS_TNODES_MAX_LEVEL
)
758 if (chunk_id
> YAFFS_MAX_CHUNK_ID
)
761 /* First check we're tall enough (ie enough top_level) */
763 i
= chunk_id
>> YAFFS_TNODES_LEVEL0_BITS
;
764 requiredTallness
= 0;
766 i
>>= YAFFS_TNODES_INTERNAL_BITS
;
770 if (requiredTallness
> file_struct
->top_level
)
771 return NULL
; /* Not tall enough, so we can't find it */
773 /* Traverse down to level 0 */
774 while (level
> 0 && tn
) {
775 tn
= tn
->internal
[(chunk_id
>>
776 (YAFFS_TNODES_LEVEL0_BITS
+
778 YAFFS_TNODES_INTERNAL_BITS
)) &
779 YAFFS_TNODES_INTERNAL_MASK
];
786 /* AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree.
787 * This happens in two steps:
788 * 1. If the tree isn't tall enough, then make it taller.
789 * 2. Scan down the tree towards the level 0 tnode adding tnodes if required.
791 * Used when modifying the tree.
793 * If the tn argument is NULL, then a fresh tnode will be added otherwise the specified tn will
794 * be plugged into the ttree.
797 yaffs_tnode_t
*yaffs_add_find_tnode_0(yaffs_dev_t
*dev
,
798 yaffs_file_s
*file_struct
,
800 yaffs_tnode_t
*passed_tn
)
802 int requiredTallness
;
810 /* Check sane level and page Id */
811 if (file_struct
->top_level
< 0 || file_struct
->top_level
> YAFFS_TNODES_MAX_LEVEL
)
814 if (chunk_id
> YAFFS_MAX_CHUNK_ID
)
817 /* First check we're tall enough (ie enough top_level) */
819 x
= chunk_id
>> YAFFS_TNODES_LEVEL0_BITS
;
820 requiredTallness
= 0;
822 x
>>= YAFFS_TNODES_INTERNAL_BITS
;
827 if (requiredTallness
> file_struct
->top_level
) {
828 /* Not tall enough, gotta make the tree taller */
829 for (i
= file_struct
->top_level
; i
< requiredTallness
; i
++) {
831 tn
= yaffs_get_tnode(dev
);
834 tn
->internal
[0] = file_struct
->top
;
835 file_struct
->top
= tn
;
836 file_struct
->top_level
++;
839 (TSTR("yaffs: no more tnodes" TENDSTR
)));
845 /* Traverse down to level 0, adding anything we need */
847 l
= file_struct
->top_level
;
848 tn
= file_struct
->top
;
851 while (l
> 0 && tn
) {
853 (YAFFS_TNODES_LEVEL0_BITS
+
854 (l
- 1) * YAFFS_TNODES_INTERNAL_BITS
)) &
855 YAFFS_TNODES_INTERNAL_MASK
;
858 if ((l
> 1) && !tn
->internal
[x
]) {
859 /* Add missing non-level-zero tnode */
860 tn
->internal
[x
] = yaffs_get_tnode(dev
);
864 /* Looking from level 1 at level 0 */
866 /* If we already have one, then release it.*/
868 yaffs_free_tnode(dev
, tn
->internal
[x
]);
869 tn
->internal
[x
] = passed_tn
;
871 } else if (!tn
->internal
[x
]) {
872 /* Don't have one, none passed in */
873 tn
->internal
[x
] = yaffs_get_tnode(dev
);
879 tn
= tn
->internal
[x
];
885 memcpy(tn
, passed_tn
, (dev
->tnode_width
* YAFFS_NTNODES_LEVEL0
)/8);
886 yaffs_free_tnode(dev
, passed_tn
);
893 static int yaffs_find_chunk_in_group(yaffs_dev_t
*dev
, int theChunk
,
894 yaffs_ext_tags
*tags
, int obj_id
,
899 for (j
= 0; theChunk
&& j
< dev
->chunk_grp_size
; j
++) {
900 if (yaffs_check_chunk_bit(dev
, theChunk
/ dev
->param
.chunks_per_block
,
901 theChunk
% dev
->param
.chunks_per_block
)) {
903 if(dev
->chunk_grp_size
== 1)
906 yaffs_rd_chunk_tags_nand(dev
, theChunk
, NULL
,
908 if (yaffs_tags_match(tags
, obj_id
, inode_chunk
)) {
920 /* Experimental code not being used yet. Might speed up file deletion */
921 /* DeleteWorker scans backwards through the tnode tree and deletes all the
922 * chunks and tnodes in the file.
923 * Returns 1 if the tree was deleted.
924 * Returns 0 if it stopped early due to hitting the limit and the delete is incomplete.
927 static int yaffs_del_worker(yaffs_obj_t
*in
, yaffs_tnode_t
*tn
, __u32 level
,
928 int chunk_offset
, int *limit
)
935 yaffs_dev_t
*dev
= in
->my_dev
;
941 for (i
= YAFFS_NTNODES_INTERNAL
- 1; allDone
&& i
>= 0;
943 if (tn
->internal
[i
]) {
944 if (limit
&& (*limit
) < 0) {
956 YAFFS_TNODES_INTERNAL_BITS
)
961 yaffs_free_tnode(dev
,
964 tn
->internal
[i
] = NULL
;
968 return (allDone
) ? 1 : 0;
969 } else if (level
== 0) {
972 for (i
= YAFFS_NTNODES_LEVEL0
- 1; i
>= 0 && !hitLimit
;
974 theChunk
= yaffs_get_group_base(dev
, tn
, i
);
977 inode_chunk
= (chunk_offset
<<
978 YAFFS_TNODES_LEVEL0_BITS
) + i
;
981 yaffs_find_chunk_in_group(dev
,
987 if (foundChunk
> 0) {
1000 yaffs_load_tnode_0(dev
, tn
, i
, 0);
1004 return (i
< 0) ? 1 : 0;
1016 static void yaffs_soft_del_chunk(yaffs_dev_t
*dev
, int chunk
)
1018 yaffs_block_info_t
*theBlock
;
1021 T(YAFFS_TRACE_DELETION
, (TSTR("soft delete chunk %d" TENDSTR
), chunk
));
1023 block_no
= chunk
/ dev
->param
.chunks_per_block
;
1024 theBlock
= yaffs_get_block_info(dev
, block_no
);
1026 theBlock
->soft_del_pages
++;
1027 dev
->n_free_chunks
++;
1028 yaffs2_update_oldest_dirty_seq(dev
, block_no
, theBlock
);
1032 /* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file.
1033 * All soft deleting does is increment the block's softdelete count and pulls the chunk out
1035 * Thus, essentially this is the same as DeleteWorker except that the chunks are soft deleted.
1038 static int yaffs_soft_del_worker(yaffs_obj_t
*in
, yaffs_tnode_t
*tn
,
1039 __u32 level
, int chunk_offset
)
1044 yaffs_dev_t
*dev
= in
->my_dev
;
1049 for (i
= YAFFS_NTNODES_INTERNAL
- 1; allDone
&& i
>= 0;
1051 if (tn
->internal
[i
]) {
1053 yaffs_soft_del_worker(in
,
1059 YAFFS_TNODES_INTERNAL_BITS
)
1062 yaffs_free_tnode(dev
,
1065 tn
->internal
[i
] = NULL
;
1067 /* Hoosterman... how could this happen? */
1071 return (allDone
) ? 1 : 0;
1072 } else if (level
== 0) {
1074 for (i
= YAFFS_NTNODES_LEVEL0
- 1; i
>= 0; i
--) {
1075 theChunk
= yaffs_get_group_base(dev
, tn
, i
);
1077 /* Note this does not find the real chunk, only the chunk group.
1078 * We make an assumption that a chunk group is not larger than
1081 yaffs_soft_del_chunk(dev
, theChunk
);
1082 yaffs_load_tnode_0(dev
, tn
, i
, 0);
1096 static void yaffs_soft_del_file(yaffs_obj_t
*obj
)
1099 obj
->variant_type
== YAFFS_OBJECT_TYPE_FILE
&& !obj
->soft_del
) {
1100 if (obj
->n_data_chunks
<= 0) {
1101 /* Empty file with no duplicate object headers, just delete it immediately */
1102 yaffs_free_tnode(obj
->my_dev
,
1103 obj
->variant
.file_variant
.top
);
1104 obj
->variant
.file_variant
.top
= NULL
;
1105 T(YAFFS_TRACE_TRACING
,
1106 (TSTR("yaffs: Deleting empty file %d" TENDSTR
),
1108 yaffs_generic_obj_del(obj
);
1110 yaffs_soft_del_worker(obj
,
1111 obj
->variant
.file_variant
.top
,
1112 obj
->variant
.file_variant
.
1119 /* Pruning removes any part of the file structure tree that is beyond the
1120 * bounds of the file (ie that does not point to chunks).
1122 * A file should only get pruned when its size is reduced.
1124 * Before pruning, the chunks must be pulled from the tree and the
1125 * level 0 tnode entries must be zeroed out.
1126 * Could also use this for file deletion, but that's probably better handled
1127 * by a special case.
1129 * This function is recursive. For levels > 0 the function is called again on
1130 * any sub-tree. For level == 0 we just check if the sub-tree has data.
1131 * If there is no data in a subtree then it is pruned.
1134 static yaffs_tnode_t
*yaffs_prune_worker(yaffs_dev_t
*dev
, yaffs_tnode_t
*tn
,
1135 __u32 level
, int del0
)
1144 for (i
= 0; i
< YAFFS_NTNODES_INTERNAL
; i
++) {
1145 if (tn
->internal
[i
]) {
1147 yaffs_prune_worker(dev
, tn
->internal
[i
],
1149 (i
== 0) ? del0
: 1);
1152 if (tn
->internal
[i
])
1156 int tnode_size_u32
= dev
->tnode_size
/sizeof(__u32
);
1157 __u32
*map
= (__u32
*)tn
;
1159 for(i
= 0; !hasData
&& i
< tnode_size_u32
; i
++){
1165 if (hasData
== 0 && del0
) {
1166 /* Free and return NULL */
1168 yaffs_free_tnode(dev
, tn
);
1178 static int yaffs_prune_tree(yaffs_dev_t
*dev
,
1179 yaffs_file_s
*file_struct
)
1186 if (file_struct
->top_level
> 0) {
1188 yaffs_prune_worker(dev
, file_struct
->top
, file_struct
->top_level
, 0);
1190 /* Now we have a tree with all the non-zero branches NULL but the height
1191 * is the same as it was.
1192 * Let's see if we can trim internal tnodes to shorten the tree.
1193 * We can do this if only the 0th element in the tnode is in use
1194 * (ie all the non-zero are NULL)
1197 while (file_struct
->top_level
&& !done
) {
1198 tn
= file_struct
->top
;
1201 for (i
= 1; i
< YAFFS_NTNODES_INTERNAL
; i
++) {
1202 if (tn
->internal
[i
])
1207 file_struct
->top
= tn
->internal
[0];
1208 file_struct
->top_level
--;
1209 yaffs_free_tnode(dev
, tn
);
1219 /*-------------------- End of File Structure functions.-------------------*/
1222 /* AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out */
1223 static yaffs_obj_t
*yaffs_alloc_empty_obj(yaffs_dev_t
*dev
)
1225 yaffs_obj_t
*obj
= yaffs_alloc_raw_obj(dev
);
1230 /* Now sweeten it up... */
1232 memset(obj
, 0, sizeof(yaffs_obj_t
));
1233 obj
->being_created
= 1;
1237 obj
->variant_type
= YAFFS_OBJECT_TYPE_UNKNOWN
;
1238 YINIT_LIST_HEAD(&(obj
->hard_links
));
1239 YINIT_LIST_HEAD(&(obj
->hash_link
));
1240 YINIT_LIST_HEAD(&obj
->siblings
);
1243 /* Now make the directory sane */
1244 if (dev
->root_dir
) {
1245 obj
->parent
= dev
->root_dir
;
1246 ylist_add(&(obj
->siblings
), &dev
->root_dir
->variant
.dir_variant
.children
);
1249 /* Add it to the lost and found directory.
1250 * NB Can't put root or lostNFound in lostNFound so
1251 * check if lostNFound exists first
1253 if (dev
->lost_n_found
)
1254 yaffs_add_obj_to_dir(dev
->lost_n_found
, obj
);
1256 obj
->being_created
= 0;
1259 dev
->checkpoint_blocks_required
= 0; /* force recalculation*/
1264 static yaffs_obj_t
*yaffs_create_fake_dir(yaffs_dev_t
*dev
, int number
,
1269 yaffs_new_obj(dev
, number
, YAFFS_OBJECT_TYPE_DIRECTORY
);
1271 obj
->fake
= 1; /* it is fake so it might have no NAND presence... */
1272 obj
->rename_allowed
= 0; /* ... and we're not allowed to rename it... */
1273 obj
->unlink_allowed
= 0; /* ... or unlink it */
1276 obj
->yst_mode
= mode
;
1278 obj
->hdr_chunk
= 0; /* Not a valid chunk. */
1285 static void yaffs_unhash_obj(yaffs_obj_t
*obj
)
1288 yaffs_dev_t
*dev
= obj
->my_dev
;
1290 /* If it is still linked into the bucket list, free from the list */
1291 if (!ylist_empty(&obj
->hash_link
)) {
1292 ylist_del_init(&obj
->hash_link
);
1293 bucket
= yaffs_hash_fn(obj
->obj_id
);
1294 dev
->obj_bucket
[bucket
].count
--;
1298 /* FreeObject frees up a Object and puts it back on the free list */
1299 static void yaffs_free_obj(yaffs_obj_t
*obj
)
1301 yaffs_dev_t
*dev
= obj
->my_dev
;
1303 T(YAFFS_TRACE_OS
, (TSTR("FreeObject %p inode %p"TENDSTR
), obj
, obj
->my_inode
));
1309 if (!ylist_empty(&obj
->siblings
))
1313 if (obj
->my_inode
) {
1314 /* We're still hooked up to a cached inode.
1315 * Don't delete now, but mark for later deletion
1317 obj
->defered_free
= 1;
1321 yaffs_unhash_obj(obj
);
1323 yaffs_free_raw_obj(dev
,obj
);
1325 dev
->checkpoint_blocks_required
= 0; /* force recalculation*/
1329 void yaffs_handle_defered_free(yaffs_obj_t
*obj
)
1331 if (obj
->defered_free
)
1332 yaffs_free_obj(obj
);
1335 static void yaffs_init_tnodes_and_objs(yaffs_dev_t
*dev
)
1342 yaffs_init_raw_tnodes_and_objs(dev
);
1344 for (i
= 0; i
< YAFFS_NOBJECT_BUCKETS
; i
++) {
1345 YINIT_LIST_HEAD(&dev
->obj_bucket
[i
].list
);
1346 dev
->obj_bucket
[i
].count
= 0;
1350 static int yaffs_find_nice_bucket(yaffs_dev_t
*dev
)
1354 int lowest
= 999999;
1357 /* Search for the shortest list or one that
1361 for (i
= 0; i
< 10 && lowest
> 4; i
++) {
1362 dev
->bucket_finder
++;
1363 dev
->bucket_finder
%= YAFFS_NOBJECT_BUCKETS
;
1364 if (dev
->obj_bucket
[dev
->bucket_finder
].count
< lowest
) {
1365 lowest
= dev
->obj_bucket
[dev
->bucket_finder
].count
;
1366 l
= dev
->bucket_finder
;
1374 static int yaffs_new_obj_id(yaffs_dev_t
*dev
)
1376 int bucket
= yaffs_find_nice_bucket(dev
);
1378 /* Now find an object value that has not already been taken
1379 * by scanning the list.
1383 struct ylist_head
*i
;
1385 __u32 n
= (__u32
) bucket
;
1387 /* yaffs_check_obj_hash_sane(); */
1391 n
+= YAFFS_NOBJECT_BUCKETS
;
1392 if (1 || dev
->obj_bucket
[bucket
].count
> 0) {
1393 ylist_for_each(i
, &dev
->obj_bucket
[bucket
].list
) {
1394 /* If there is already one in the list */
1395 if (i
&& ylist_entry(i
, yaffs_obj_t
,
1396 hash_link
)->obj_id
== n
) {
1406 static void yaffs_hash_obj(yaffs_obj_t
*in
)
1408 int bucket
= yaffs_hash_fn(in
->obj_id
);
1409 yaffs_dev_t
*dev
= in
->my_dev
;
1411 ylist_add(&in
->hash_link
, &dev
->obj_bucket
[bucket
].list
);
1412 dev
->obj_bucket
[bucket
].count
++;
1415 yaffs_obj_t
*yaffs_find_by_number(yaffs_dev_t
*dev
, __u32 number
)
1417 int bucket
= yaffs_hash_fn(number
);
1418 struct ylist_head
*i
;
1421 ylist_for_each(i
, &dev
->obj_bucket
[bucket
].list
) {
1422 /* Look if it is in the list */
1424 in
= ylist_entry(i
, yaffs_obj_t
, hash_link
);
1425 if (in
->obj_id
== number
) {
1427 /* Don't tell the VFS about this one if it is defered free */
1428 if (in
->defered_free
)
1439 yaffs_obj_t
*yaffs_new_obj(yaffs_dev_t
*dev
, int number
,
1440 yaffs_obj_type type
)
1442 yaffs_obj_t
*theObject
=NULL
;
1443 yaffs_tnode_t
*tn
= NULL
;
1446 number
= yaffs_new_obj_id(dev
);
1448 if (type
== YAFFS_OBJECT_TYPE_FILE
) {
1449 tn
= yaffs_get_tnode(dev
);
1454 theObject
= yaffs_alloc_empty_obj(dev
);
1457 yaffs_free_tnode(dev
,tn
);
1463 theObject
->fake
= 0;
1464 theObject
->rename_allowed
= 1;
1465 theObject
->unlink_allowed
= 1;
1466 theObject
->obj_id
= number
;
1467 yaffs_hash_obj(theObject
);
1468 theObject
->variant_type
= type
;
1469 #ifdef CONFIG_YAFFS_WINCE
1470 yfsd_win_file_time_now(theObject
->win_atime
);
1471 theObject
->win_ctime
[0] = theObject
->win_mtime
[0] =
1472 theObject
->win_atime
[0];
1473 theObject
->win_ctime
[1] = theObject
->win_mtime
[1] =
1474 theObject
->win_atime
[1];
1478 theObject
->yst_atime
= theObject
->yst_mtime
=
1479 theObject
->yst_ctime
= Y_CURRENT_TIME
;
1482 case YAFFS_OBJECT_TYPE_FILE
:
1483 theObject
->variant
.file_variant
.file_size
= 0;
1484 theObject
->variant
.file_variant
.scanned_size
= 0;
1485 theObject
->variant
.file_variant
.shrink_size
= 0xFFFFFFFF; /* max __u32 */
1486 theObject
->variant
.file_variant
.top_level
= 0;
1487 theObject
->variant
.file_variant
.top
= tn
;
1489 case YAFFS_OBJECT_TYPE_DIRECTORY
:
1490 YINIT_LIST_HEAD(&theObject
->variant
.dir_variant
.
1492 YINIT_LIST_HEAD(&theObject
->variant
.dir_variant
.
1495 case YAFFS_OBJECT_TYPE_SYMLINK
:
1496 case YAFFS_OBJECT_TYPE_HARDLINK
:
1497 case YAFFS_OBJECT_TYPE_SPECIAL
:
1498 /* No action required */
1500 case YAFFS_OBJECT_TYPE_UNKNOWN
:
1501 /* todo this should not happen */
1509 yaffs_obj_t
*yaffs_find_or_create_by_number(yaffs_dev_t
*dev
,
1511 yaffs_obj_type type
)
1513 yaffs_obj_t
*theObject
= NULL
;
1516 theObject
= yaffs_find_by_number(dev
, number
);
1519 theObject
= yaffs_new_obj(dev
, number
, type
);
1526 YCHAR
*yaffs_clone_str(const YCHAR
*str
)
1528 YCHAR
*newStr
= NULL
;
1534 len
= yaffs_strnlen(str
,YAFFS_MAX_ALIAS_LENGTH
);
1535 newStr
= YMALLOC((len
+ 1) * sizeof(YCHAR
));
1537 yaffs_strncpy(newStr
, str
,len
);
1545 * Mknod (create) a new object.
1546 * equiv_obj only has meaning for a hard link;
1547 * aliasString only has meaning for a symlink.
1548 * rdev only has meaning for devices (a subset of special objects)
1551 static yaffs_obj_t
*yaffs_create_obj(yaffs_obj_type type
,
1552 yaffs_obj_t
*parent
,
1557 yaffs_obj_t
*equiv_obj
,
1558 const YCHAR
*aliasString
, __u32 rdev
)
1563 yaffs_dev_t
*dev
= parent
->my_dev
;
1565 /* Check if the entry exists. If it does then fail the call since we don't want a dup.*/
1566 if (yaffs_find_by_name(parent
, name
))
1569 if (type
== YAFFS_OBJECT_TYPE_SYMLINK
) {
1570 str
= yaffs_clone_str(aliasString
);
1575 in
= yaffs_new_obj(dev
, -1, type
);
1590 in
->variant_type
= type
;
1592 in
->yst_mode
= mode
;
1594 #ifdef CONFIG_YAFFS_WINCE
1595 yfsd_win_file_time_now(in
->win_atime
);
1596 in
->win_ctime
[0] = in
->win_mtime
[0] = in
->win_atime
[0];
1597 in
->win_ctime
[1] = in
->win_mtime
[1] = in
->win_atime
[1];
1600 in
->yst_atime
= in
->yst_mtime
= in
->yst_ctime
= Y_CURRENT_TIME
;
1602 in
->yst_rdev
= rdev
;
1606 in
->n_data_chunks
= 0;
1608 yaffs_set_obj_name(in
, name
);
1611 yaffs_add_obj_to_dir(parent
, in
);
1613 in
->my_dev
= parent
->my_dev
;
1616 case YAFFS_OBJECT_TYPE_SYMLINK
:
1617 in
->variant
.symlink_variant
.alias
= str
;
1619 case YAFFS_OBJECT_TYPE_HARDLINK
:
1620 in
->variant
.hardlink_variant
.equiv_obj
=
1622 in
->variant
.hardlink_variant
.equiv_id
=
1624 ylist_add(&in
->hard_links
, &equiv_obj
->hard_links
);
1626 case YAFFS_OBJECT_TYPE_FILE
:
1627 case YAFFS_OBJECT_TYPE_DIRECTORY
:
1628 case YAFFS_OBJECT_TYPE_SPECIAL
:
1629 case YAFFS_OBJECT_TYPE_UNKNOWN
:
1634 if (yaffs_update_oh(in
, name
, 0, 0, 0, NULL
) < 0) {
1635 /* Could not create the object header, fail the creation */
1640 yaffs_update_parent(parent
);
1646 yaffs_obj_t
*yaffs_create_file(yaffs_obj_t
*parent
, const YCHAR
*name
,
1647 __u32 mode
, __u32 uid
, __u32 gid
)
1649 return yaffs_create_obj(YAFFS_OBJECT_TYPE_FILE
, parent
, name
, mode
,
1650 uid
, gid
, NULL
, NULL
, 0);
1653 yaffs_obj_t
*yaffs_create_dir(yaffs_obj_t
*parent
, const YCHAR
*name
,
1654 __u32 mode
, __u32 uid
, __u32 gid
)
1656 return yaffs_create_obj(YAFFS_OBJECT_TYPE_DIRECTORY
, parent
, name
,
1657 mode
, uid
, gid
, NULL
, NULL
, 0);
1660 yaffs_obj_t
*yaffs_create_special(yaffs_obj_t
*parent
, const YCHAR
*name
,
1661 __u32 mode
, __u32 uid
, __u32 gid
, __u32 rdev
)
1663 return yaffs_create_obj(YAFFS_OBJECT_TYPE_SPECIAL
, parent
, name
, mode
,
1664 uid
, gid
, NULL
, NULL
, rdev
);
1667 yaffs_obj_t
*yaffs_create_symlink(yaffs_obj_t
*parent
, const YCHAR
*name
,
1668 __u32 mode
, __u32 uid
, __u32 gid
,
1671 return yaffs_create_obj(YAFFS_OBJECT_TYPE_SYMLINK
, parent
, name
, mode
,
1672 uid
, gid
, NULL
, alias
, 0);
1675 /* yaffs_link_obj returns the object id of the equivalent object.*/
1676 yaffs_obj_t
*yaffs_link_obj(yaffs_obj_t
*parent
, const YCHAR
*name
,
1677 yaffs_obj_t
*equiv_obj
)
1679 /* Get the real object in case we were fed a hard link as an equivalent object */
1680 equiv_obj
= yaffs_get_equivalent_obj(equiv_obj
);
1682 if (yaffs_create_obj
1683 (YAFFS_OBJECT_TYPE_HARDLINK
, parent
, name
, 0, 0, 0,
1684 equiv_obj
, NULL
, 0)) {
1692 static int yaffs_change_obj_name(yaffs_obj_t
*obj
, yaffs_obj_t
*new_dir
,
1693 const YCHAR
*new_name
, int force
, int shadows
)
1698 yaffs_obj_t
*existingTarget
;
1700 if (new_dir
== NULL
)
1701 new_dir
= obj
->parent
; /* use the old directory */
1703 if (new_dir
->variant_type
!= YAFFS_OBJECT_TYPE_DIRECTORY
) {
1704 T(YAFFS_TRACE_ALWAYS
,
1706 ("tragedy: yaffs_change_obj_name: new_dir is not a directory"
1711 /* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */
1712 if (obj
->my_dev
->param
.is_yaffs2
)
1713 unlinkOp
= (new_dir
== obj
->my_dev
->unlinked_dir
);
1715 unlinkOp
= (new_dir
== obj
->my_dev
->unlinked_dir
1716 && obj
->variant_type
== YAFFS_OBJECT_TYPE_FILE
);
1718 deleteOp
= (new_dir
== obj
->my_dev
->del_dir
);
1720 existingTarget
= yaffs_find_by_name(new_dir
, new_name
);
1722 /* If the object is a file going into the unlinked directory,
1723 * then it is OK to just stuff it in since duplicate names are allowed.
1724 * else only proceed if the new name does not exist and if we're putting
1725 * it into a directory.
1732 new_dir
->variant_type
== YAFFS_OBJECT_TYPE_DIRECTORY
) {
1733 yaffs_set_obj_name(obj
, new_name
);
1736 yaffs_add_obj_to_dir(new_dir
, obj
);
1741 /* If it is a deletion then we mark it as a shrink for gc purposes. */
1742 if (yaffs_update_oh(obj
, new_name
, 0, deleteOp
, shadows
, NULL
) >= 0)
1749 int yaffs_rename_obj(yaffs_obj_t
*old_dir
, const YCHAR
*old_name
,
1750 yaffs_obj_t
*new_dir
, const YCHAR
*new_name
)
1752 yaffs_obj_t
*obj
= NULL
;
1753 yaffs_obj_t
*existingTarget
= NULL
;
1759 if (!old_dir
|| old_dir
->variant_type
!= YAFFS_OBJECT_TYPE_DIRECTORY
)
1761 if (!new_dir
|| new_dir
->variant_type
!= YAFFS_OBJECT_TYPE_DIRECTORY
)
1764 dev
= old_dir
->my_dev
;
1766 #ifdef CONFIG_YAFFS_CASE_INSENSITIVE
1767 /* Special case for case insemsitive systems (eg. WinCE).
1768 * While look-up is case insensitive, the name isn't.
1769 * Therefore we might want to change x.txt to X.txt
1771 if (old_dir
== new_dir
&& yaffs_strcmp(old_name
, new_name
) == 0)
1775 if(yaffs_strnlen(new_name
,YAFFS_MAX_NAME_LENGTH
+1) > YAFFS_MAX_NAME_LENGTH
)
1779 obj
= yaffs_find_by_name(old_dir
, old_name
);
1781 if (obj
&& obj
->rename_allowed
) {
1783 /* Now do the handling for an existing target, if there is one */
1785 existingTarget
= yaffs_find_by_name(new_dir
, new_name
);
1786 if (existingTarget
&&
1787 existingTarget
->variant_type
== YAFFS_OBJECT_TYPE_DIRECTORY
&&
1788 !ylist_empty(&existingTarget
->variant
.dir_variant
.children
)) {
1789 /* There is a target that is a non-empty directory, so we fail */
1790 return YAFFS_FAIL
; /* EEXIST or ENOTEMPTY */
1791 } else if (existingTarget
&& existingTarget
!= obj
) {
1792 /* Nuke the target first, using shadowing,
1793 * but only if it isn't the same object.
1795 * Note we must disable gc otherwise it can mess up the shadowing.
1799 yaffs_change_obj_name(obj
, new_dir
, new_name
, force
,
1800 existingTarget
->obj_id
);
1801 existingTarget
->is_shadowed
= 1;
1802 yaffs_unlink_obj(existingTarget
);
1806 result
= yaffs_change_obj_name(obj
, new_dir
, new_name
, 1, 0);
1808 yaffs_update_parent(old_dir
);
1809 if(new_dir
!= old_dir
)
1810 yaffs_update_parent(new_dir
);
1817 /*------------------------- Block Management and Page Allocation ----------------*/
1819 static int yaffs_init_blocks(yaffs_dev_t
*dev
)
1821 int nBlocks
= dev
->internal_end_block
- dev
->internal_start_block
+ 1;
1823 dev
->block_info
= NULL
;
1824 dev
->chunk_bits
= NULL
;
1826 dev
->alloc_block
= -1; /* force it to get a new one */
1828 /* If the first allocation strategy fails, thry the alternate one */
1829 dev
->block_info
= YMALLOC(nBlocks
* sizeof(yaffs_block_info_t
));
1830 if (!dev
->block_info
) {
1831 dev
->block_info
= YMALLOC_ALT(nBlocks
* sizeof(yaffs_block_info_t
));
1832 dev
->block_info_alt
= 1;
1834 dev
->block_info_alt
= 0;
1836 if (dev
->block_info
) {
1837 /* Set up dynamic blockinfo stuff. */
1838 dev
->chunk_bit_stride
= (dev
->param
.chunks_per_block
+ 7) / 8; /* round up bytes */
1839 dev
->chunk_bits
= YMALLOC(dev
->chunk_bit_stride
* nBlocks
);
1840 if (!dev
->chunk_bits
) {
1841 dev
->chunk_bits
= YMALLOC_ALT(dev
->chunk_bit_stride
* nBlocks
);
1842 dev
->chunk_bits_alt
= 1;
1844 dev
->chunk_bits_alt
= 0;
1847 if (dev
->block_info
&& dev
->chunk_bits
) {
1848 memset(dev
->block_info
, 0, nBlocks
* sizeof(yaffs_block_info_t
));
1849 memset(dev
->chunk_bits
, 0, dev
->chunk_bit_stride
* nBlocks
);
1856 static void yaffs_deinit_blocks(yaffs_dev_t
*dev
)
1858 if (dev
->block_info_alt
&& dev
->block_info
)
1859 YFREE_ALT(dev
->block_info
);
1860 else if (dev
->block_info
)
1861 YFREE(dev
->block_info
);
1863 dev
->block_info_alt
= 0;
1865 dev
->block_info
= NULL
;
1867 if (dev
->chunk_bits_alt
&& dev
->chunk_bits
)
1868 YFREE_ALT(dev
->chunk_bits
);
1869 else if (dev
->chunk_bits
)
1870 YFREE(dev
->chunk_bits
);
1871 dev
->chunk_bits_alt
= 0;
1872 dev
->chunk_bits
= NULL
;
1875 void yaffs_block_became_dirty(yaffs_dev_t
*dev
, int block_no
)
1877 yaffs_block_info_t
*bi
= yaffs_get_block_info(dev
, block_no
);
1881 /* If the block is still healthy erase it and mark as clean.
1882 * If the block has had a data failure, then retire it.
1885 T(YAFFS_TRACE_GC
| YAFFS_TRACE_ERASE
,
1886 (TSTR("yaffs_block_became_dirty block %d state %d %s"TENDSTR
),
1887 block_no
, bi
->block_state
, (bi
->needs_retiring
) ? "needs retiring" : ""));
1889 yaffs2_clear_oldest_dirty_seq(dev
,bi
);
1891 bi
->block_state
= YAFFS_BLOCK_STATE_DIRTY
;
1893 /* If this is the block being garbage collected then stop gc'ing this block */
1894 if(block_no
== dev
->gc_block
)
1897 /* If this block is currently the best candidate for gc then drop as a candidate */
1898 if(block_no
== dev
->gc_dirtiest
){
1899 dev
->gc_dirtiest
= 0;
1900 dev
->gc_pages_in_use
= 0;
1903 if (!bi
->needs_retiring
) {
1904 yaffs2_checkpt_invalidate(dev
);
1905 erasedOk
= yaffs_erase_block(dev
, block_no
);
1907 dev
->n_erase_failures
++;
1908 T(YAFFS_TRACE_ERROR
| YAFFS_TRACE_BAD_BLOCKS
,
1909 (TSTR("**>> Erasure failed %d" TENDSTR
), block_no
));
1914 ((yaffs_trace_mask
& YAFFS_TRACE_ERASE
) || !yaffs_skip_verification(dev
))) {
1916 for (i
= 0; i
< dev
->param
.chunks_per_block
; i
++) {
1917 if (!yaffs_check_chunk_erased
1918 (dev
, block_no
* dev
->param
.chunks_per_block
+ i
)) {
1919 T(YAFFS_TRACE_ERROR
,
1921 (">>Block %d erasure supposedly OK, but chunk %d not erased"
1922 TENDSTR
), block_no
, i
));
1928 /* Clean it up... */
1929 bi
->block_state
= YAFFS_BLOCK_STATE_EMPTY
;
1931 dev
->n_erased_blocks
++;
1932 bi
->pages_in_use
= 0;
1933 bi
->soft_del_pages
= 0;
1934 bi
->has_shrink_hdr
= 0;
1935 bi
->skip_erased_check
= 1; /* This is clean, so no need to check */
1936 bi
->gc_prioritise
= 0;
1937 yaffs_clear_chunk_bits(dev
, block_no
);
1939 T(YAFFS_TRACE_ERASE
,
1940 (TSTR("Erased block %d" TENDSTR
), block_no
));
1942 dev
->n_free_chunks
-= dev
->param
.chunks_per_block
; /* We lost a block of free space */
1944 yaffs_retire_block(dev
, block_no
);
1945 T(YAFFS_TRACE_ERROR
| YAFFS_TRACE_BAD_BLOCKS
,
1946 (TSTR("**>> Block %d retired" TENDSTR
), block_no
));
1950 static int yaffs_find_alloc_block(yaffs_dev_t
*dev
)
1954 yaffs_block_info_t
*bi
;
1956 if (dev
->n_erased_blocks
< 1) {
1957 /* Hoosterman we've got a problem.
1958 * Can't get space to gc
1960 T(YAFFS_TRACE_ERROR
,
1961 (TSTR("yaffs tragedy: no more erased blocks" TENDSTR
)));
1966 /* Find an empty block. */
1968 for (i
= dev
->internal_start_block
; i
<= dev
->internal_end_block
; i
++) {
1969 dev
->alloc_block_finder
++;
1970 if (dev
->alloc_block_finder
< dev
->internal_start_block
1971 || dev
->alloc_block_finder
> dev
->internal_end_block
) {
1972 dev
->alloc_block_finder
= dev
->internal_start_block
;
1975 bi
= yaffs_get_block_info(dev
, dev
->alloc_block_finder
);
1977 if (bi
->block_state
== YAFFS_BLOCK_STATE_EMPTY
) {
1978 bi
->block_state
= YAFFS_BLOCK_STATE_ALLOCATING
;
1980 bi
->seq_number
= dev
->seq_number
;
1981 dev
->n_erased_blocks
--;
1982 T(YAFFS_TRACE_ALLOCATE
,
1983 (TSTR("Allocated block %d, seq %d, %d left" TENDSTR
),
1984 dev
->alloc_block_finder
, dev
->seq_number
,
1985 dev
->n_erased_blocks
));
1986 return dev
->alloc_block_finder
;
1990 T(YAFFS_TRACE_ALWAYS
,
1992 ("yaffs tragedy: no more erased blocks, but there should have been %d"
1993 TENDSTR
), dev
->n_erased_blocks
));
2000 * Check if there's space to allocate...
2001 * Thinks.... do we need top make this ths same as yaffs_get_free_chunks()?
2003 int yaffs_check_alloc_available(yaffs_dev_t
*dev
, int n_chunks
)
2006 int reservedBlocks
= dev
->param
.n_reserved_blocks
;
2007 int checkpointBlocks
;
2009 checkpointBlocks
= yaffs_calc_checkpt_blocks_required(dev
);
2011 reservedChunks
= ((reservedBlocks
+ checkpointBlocks
) * dev
->param
.chunks_per_block
);
2013 return (dev
->n_free_chunks
> (reservedChunks
+ n_chunks
));
2016 static int yaffs_alloc_chunk(yaffs_dev_t
*dev
, int useReserve
,
2017 yaffs_block_info_t
**blockUsedPtr
)
2020 yaffs_block_info_t
*bi
;
2022 if (dev
->alloc_block
< 0) {
2023 /* Get next block to allocate off */
2024 dev
->alloc_block
= yaffs_find_alloc_block(dev
);
2025 dev
->alloc_page
= 0;
2028 if (!useReserve
&& !yaffs_check_alloc_available(dev
, 1)) {
2029 /* Not enough space to allocate unless we're allowed to use the reserve. */
2033 if (dev
->n_erased_blocks
< dev
->param
.n_reserved_blocks
2034 && dev
->alloc_page
== 0) {
2035 T(YAFFS_TRACE_ALLOCATE
, (TSTR("Allocating reserve" TENDSTR
)));
2038 /* Next page please.... */
2039 if (dev
->alloc_block
>= 0) {
2040 bi
= yaffs_get_block_info(dev
, dev
->alloc_block
);
2042 retVal
= (dev
->alloc_block
* dev
->param
.chunks_per_block
) +
2045 yaffs_set_chunk_bit(dev
, dev
->alloc_block
,
2050 dev
->n_free_chunks
--;
2052 /* If the block is full set the state to full */
2053 if (dev
->alloc_page
>= dev
->param
.chunks_per_block
) {
2054 bi
->block_state
= YAFFS_BLOCK_STATE_FULL
;
2055 dev
->alloc_block
= -1;
2064 T(YAFFS_TRACE_ERROR
,
2065 (TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR
)));
2070 static int yaffs_get_erased_chunks(yaffs_dev_t
*dev
)
2074 n
= dev
->n_erased_blocks
* dev
->param
.chunks_per_block
;
2076 if (dev
->alloc_block
> 0)
2077 n
+= (dev
->param
.chunks_per_block
- dev
->alloc_page
);
2084 * yaffs_skip_rest_of_block() skips over the rest of the allocation block
2085 * if we don't want to write to it.
2087 void yaffs_skip_rest_of_block(yaffs_dev_t
*dev
)
2089 if(dev
->alloc_block
> 0){
2090 yaffs_block_info_t
*bi
= yaffs_get_block_info(dev
, dev
->alloc_block
);
2091 if(bi
->block_state
== YAFFS_BLOCK_STATE_ALLOCATING
){
2092 bi
->block_state
= YAFFS_BLOCK_STATE_FULL
;
2093 dev
->alloc_block
= -1;
2099 static int yaffs_gc_block(yaffs_dev_t
*dev
, int block
,
2105 int retVal
= YAFFS_OK
;
2107 int isCheckpointBlock
;
2111 int chunksBefore
= yaffs_get_erased_chunks(dev
);
2114 yaffs_ext_tags tags
;
2116 yaffs_block_info_t
*bi
= yaffs_get_block_info(dev
, block
);
2118 yaffs_obj_t
*object
;
2120 isCheckpointBlock
= (bi
->block_state
== YAFFS_BLOCK_STATE_CHECKPOINT
);
2123 T(YAFFS_TRACE_TRACING
,
2124 (TSTR("Collecting block %d, in use %d, shrink %d, wholeBlock %d" TENDSTR
),
2130 /*yaffs_verify_free_chunks(dev); */
2132 if(bi
->block_state
== YAFFS_BLOCK_STATE_FULL
)
2133 bi
->block_state
= YAFFS_BLOCK_STATE_COLLECTING
;
2135 bi
->has_shrink_hdr
= 0; /* clear the flag so that the block can erase */
2137 dev
->gc_disable
= 1;
2139 if (isCheckpointBlock
||
2140 !yaffs_still_some_chunks(dev
, block
)) {
2141 T(YAFFS_TRACE_TRACING
,
2143 ("Collecting block %d that has no chunks in use" TENDSTR
),
2145 yaffs_block_became_dirty(dev
, block
);
2148 __u8
*buffer
= yaffs_get_temp_buffer(dev
, __LINE__
);
2150 yaffs_verify_blk(dev
, bi
, block
);
2152 maxCopies
= (wholeBlock
) ? dev
->param
.chunks_per_block
: 5;
2153 oldChunk
= block
* dev
->param
.chunks_per_block
+ dev
->gc_chunk
;
2155 for (/* init already done */;
2156 retVal
== YAFFS_OK
&&
2157 dev
->gc_chunk
< dev
->param
.chunks_per_block
&&
2158 (bi
->block_state
== YAFFS_BLOCK_STATE_COLLECTING
) &&
2160 dev
->gc_chunk
++, oldChunk
++) {
2161 if (yaffs_check_chunk_bit(dev
, block
, dev
->gc_chunk
)) {
2163 /* This page is in use and might need to be copied off */
2169 yaffs_init_tags(&tags
);
2171 yaffs_rd_chunk_tags_nand(dev
, oldChunk
,
2175 yaffs_find_by_number(dev
,
2178 T(YAFFS_TRACE_GC_DETAIL
,
2180 ("Collecting chunk in block %d, %d %d %d " TENDSTR
),
2181 dev
->gc_chunk
, tags
.obj_id
, tags
.chunk_id
,
2184 if (object
&& !yaffs_skip_verification(dev
)) {
2185 if (tags
.chunk_id
== 0)
2186 matchingChunk
= object
->hdr_chunk
;
2187 else if (object
->soft_del
)
2188 matchingChunk
= oldChunk
; /* Defeat the test */
2190 matchingChunk
= yaffs_find_chunk_in_file(object
, tags
.chunk_id
, NULL
);
2192 if (oldChunk
!= matchingChunk
)
2193 T(YAFFS_TRACE_ERROR
,
2194 (TSTR("gc: page in gc mismatch: %d %d %d %d"TENDSTR
),
2195 oldChunk
, matchingChunk
, tags
.obj_id
, tags
.chunk_id
));
2200 T(YAFFS_TRACE_ERROR
,
2202 ("page %d in gc has no object: %d %d %d "
2204 tags
.obj_id
, tags
.chunk_id
, tags
.n_bytes
));
2210 tags
.chunk_id
!= 0) {
2211 /* Data chunk in a soft deleted file, throw it away
2212 * It's a soft deleted data chunk,
2213 * No need to copy this, just forget about it and
2214 * fix up the object.
2217 /* Free chunks already includes softdeleted chunks.
2218 * How ever this chunk is going to soon be really deleted
2219 * which will increment free chunks.
2220 * We have to decrement free chunks so this works out properly.
2222 dev
->n_free_chunks
--;
2223 bi
->soft_del_pages
--;
2225 object
->n_data_chunks
--;
2227 if (object
->n_data_chunks
<= 0) {
2228 /* remeber to clean up the object */
2229 dev
->gc_cleanup_list
[dev
->n_clean_ups
] =
2235 /* Todo object && object->deleted && object->n_data_chunks == 0 */
2236 /* Deleted object header with no data chunks.
2237 * Can be discarded and the file deleted.
2239 object
->hdr_chunk
= 0;
2240 yaffs_free_tnode(object
->my_dev
,
2243 object
->variant
.file_variant
.top
= NULL
;
2244 yaffs_generic_obj_del(object
);
2246 } else if (object
) {
2247 /* It's either a data chunk in a live file or
2248 * an ObjectHeader, so we're interested in it.
2249 * NB Need to keep the ObjectHeaders of deleted files
2250 * until the whole file has been deleted off
2252 tags
.serial_number
++;
2256 if (tags
.chunk_id
== 0) {
2257 /* It is an object Id,
2258 * We need to nuke the shrinkheader flags first
2259 * Also need to clean up shadowing.
2260 * We no longer want the shrinkHeader flag since its work is done
2261 * and if it is left in place it will mess up scanning.
2264 yaffs_obj_header
*oh
;
2265 oh
= (yaffs_obj_header
*)buffer
;
2268 tags
.extra_is_shrink
= 0;
2270 oh
->shadows_obj
= 0;
2271 oh
->inband_shadowed_obj_id
= 0;
2272 tags
.extra_shadows
= 0;
2274 /* Update file size */
2275 if(object
->variant_type
== YAFFS_OBJECT_TYPE_FILE
){
2276 oh
->file_size
= object
->variant
.file_variant
.file_size
;
2277 tags
.extra_length
= oh
->file_size
;
2280 yaffs_verify_oh(object
, oh
, &tags
, 1);
2282 yaffs_write_new_chunk(dev
,(__u8
*) oh
, &tags
, 1);
2285 yaffs_write_new_chunk(dev
, buffer
, &tags
, 1);
2288 retVal
= YAFFS_FAIL
;
2291 /* Ok, now fix up the Tnodes etc. */
2293 if (tags
.chunk_id
== 0) {
2295 object
->hdr_chunk
= newChunk
;
2296 object
->serial
= tags
.serial_number
;
2298 /* It's a data chunk */
2300 ok
= yaffs_put_chunk_in_file
2308 if (retVal
== YAFFS_OK
)
2309 yaffs_chunk_del(dev
, oldChunk
, mark_flash
, __LINE__
);
2314 yaffs_release_temp_buffer(dev
, buffer
, __LINE__
);
2320 yaffs_verify_collected_blk(dev
, bi
, block
);
2324 if (bi
->block_state
== YAFFS_BLOCK_STATE_COLLECTING
) {
2326 * The gc did not complete. Set block state back to FULL
2327 * because checkpointing does not restore gc.
2329 bi
->block_state
= YAFFS_BLOCK_STATE_FULL
;
2331 /* The gc completed. */
2332 /* Do any required cleanups */
2333 for (i
= 0; i
< dev
->n_clean_ups
; i
++) {
2334 /* Time to delete the file too */
2336 yaffs_find_by_number(dev
,
2337 dev
->gc_cleanup_list
[i
]);
2339 yaffs_free_tnode(dev
,
2340 object
->variant
.file_variant
.
2342 object
->variant
.file_variant
.top
= NULL
;
2345 ("yaffs: About to finally delete object %d"
2346 TENDSTR
), object
->obj_id
));
2347 yaffs_generic_obj_del(object
);
2348 object
->my_dev
->n_deleted_files
--;
2354 chunksAfter
= yaffs_get_erased_chunks(dev
);
2355 if (chunksBefore
>= chunksAfter
) {
2358 ("gc did not increase free chunks before %d after %d"
2359 TENDSTR
), chunksBefore
, chunksAfter
));
2363 dev
->n_clean_ups
= 0;
2366 dev
->gc_disable
= 0;
2372 * FindBlockForgarbageCollection is used to select the dirtiest block (or close enough)
2373 * for garbage collection.
2376 static unsigned yaffs_find_gc_block(yaffs_dev_t
*dev
,
2382 unsigned selected
= 0;
2383 int prioritised
= 0;
2384 int prioritisedExists
= 0;
2385 yaffs_block_info_t
*bi
;
2388 /* First let's see if we need to grab a prioritised block */
2389 if (dev
->has_pending_prioritised_gc
&& !aggressive
) {
2390 dev
->gc_dirtiest
= 0;
2391 bi
= dev
->block_info
;
2392 for (i
= dev
->internal_start_block
;
2393 i
<= dev
->internal_end_block
&& !selected
;
2396 if (bi
->gc_prioritise
) {
2397 prioritisedExists
= 1;
2398 if (bi
->block_state
== YAFFS_BLOCK_STATE_FULL
&&
2399 yaffs_block_ok_for_gc(dev
, bi
)) {
2408 * If there is a prioritised block and none was selected then
2409 * this happened because there is at least one old dirty block gumming
2410 * up the works. Let's gc the oldest dirty block.
2413 if(prioritisedExists
&&
2415 dev
->oldest_dirty_block
> 0)
2416 selected
= dev
->oldest_dirty_block
;
2418 if (!prioritisedExists
) /* None found, so we can clear this */
2419 dev
->has_pending_prioritised_gc
= 0;
2422 /* If we're doing aggressive GC then we are happy to take a less-dirty block, and
2424 * else (we're doing a leasurely gc), then we only bother to do this if the
2425 * block has only a few pages in use.
2430 int nBlocks
= dev
->internal_end_block
- dev
->internal_start_block
+ 1;
2432 threshold
= dev
->param
.chunks_per_block
;
2433 iterations
= nBlocks
;
2438 maxThreshold
= dev
->param
.chunks_per_block
/2;
2440 maxThreshold
= dev
->param
.chunks_per_block
/8;
2442 if(maxThreshold
< YAFFS_GC_PASSIVE_THRESHOLD
)
2443 maxThreshold
= YAFFS_GC_PASSIVE_THRESHOLD
;
2445 threshold
= background
?
2446 (dev
->gc_not_done
+ 2) * 2 : 0;
2447 if(threshold
<YAFFS_GC_PASSIVE_THRESHOLD
)
2448 threshold
= YAFFS_GC_PASSIVE_THRESHOLD
;
2449 if(threshold
> maxThreshold
)
2450 threshold
= maxThreshold
;
2452 iterations
= nBlocks
/ 16 + 1;
2453 if (iterations
> 100)
2459 (dev
->gc_dirtiest
< 1 ||
2460 dev
->gc_pages_in_use
> YAFFS_GC_GOOD_ENOUGH
);
2462 dev
->gc_block_finder
++;
2463 if (dev
->gc_block_finder
< dev
->internal_start_block
||
2464 dev
->gc_block_finder
> dev
->internal_end_block
)
2465 dev
->gc_block_finder
= dev
->internal_start_block
;
2467 bi
= yaffs_get_block_info(dev
, dev
->gc_block_finder
);
2469 pagesUsed
= bi
->pages_in_use
- bi
->soft_del_pages
;
2471 if (bi
->block_state
== YAFFS_BLOCK_STATE_FULL
&&
2472 pagesUsed
< dev
->param
.chunks_per_block
&&
2473 (dev
->gc_dirtiest
< 1 || pagesUsed
< dev
->gc_pages_in_use
) &&
2474 yaffs_block_ok_for_gc(dev
, bi
)) {
2475 dev
->gc_dirtiest
= dev
->gc_block_finder
;
2476 dev
->gc_pages_in_use
= pagesUsed
;
2480 if(dev
->gc_dirtiest
> 0 && dev
->gc_pages_in_use
<= threshold
)
2481 selected
= dev
->gc_dirtiest
;
2485 * If nothing has been selected for a while, try selecting the oldest dirty
2486 * because that's gumming up the works.
2489 if(!selected
&& dev
->param
.is_yaffs2
&&
2490 dev
->gc_not_done
>= ( background
? 10 : 20)){
2491 yaffs2_find_oldest_dirty_seq(dev
);
2492 if(dev
->oldest_dirty_block
> 0) {
2493 selected
= dev
->oldest_dirty_block
;
2494 dev
->gc_dirtiest
= selected
;
2495 dev
->oldest_dirty_gc_count
++;
2496 bi
= yaffs_get_block_info(dev
, selected
);
2497 dev
->gc_pages_in_use
= bi
->pages_in_use
- bi
->soft_del_pages
;
2499 dev
->gc_not_done
= 0;
2504 (TSTR("GC Selected block %d with %d free, prioritised:%d" TENDSTR
),
2506 dev
->param
.chunks_per_block
- dev
->gc_pages_in_use
,
2513 dev
->gc_dirtiest
= 0;
2514 dev
->gc_pages_in_use
= 0;
2515 dev
->gc_not_done
= 0;
2516 if(dev
->refresh_skip
> 0)
2517 dev
->refresh_skip
--;
2521 (TSTR("GC none: finder %d skip %d threshold %d dirtiest %d using %d oldest %d%s" TENDSTR
),
2522 dev
->gc_block_finder
, dev
->gc_not_done
,
2524 dev
->gc_dirtiest
, dev
->gc_pages_in_use
,
2525 dev
->oldest_dirty_block
,
2526 background
? " bg" : ""));
2532 /* New garbage collector
2533 * If we're very low on erased blocks then we do aggressive garbage collection
2534 * otherwise we do "leasurely" garbage collection.
2535 * Aggressive gc looks further (whole array) and will accept less dirty blocks.
2536 * Passive gc only inspects smaller areas and will only accept more dirty blocks.
2538 * The idea is to help clear out space in a more spread-out manner.
2539 * Dunno if it really does anything useful.
2541 static int yaffs_check_gc(yaffs_dev_t
*dev
, int background
)
2544 int gcOk
= YAFFS_OK
;
2548 int checkpointBlockAdjust
;
2550 if(dev
->param
.gc_control
&&
2551 (dev
->param
.gc_control(dev
) & 1) == 0)
2554 if (dev
->gc_disable
) {
2555 /* Bail out so we don't get recursive gc */
2559 /* This loop should pass the first time.
2560 * We'll only see looping here if the collection does not increase space.
2566 checkpointBlockAdjust
= yaffs_calc_checkpt_blocks_required(dev
);
2568 minErased
= dev
->param
.n_reserved_blocks
+ checkpointBlockAdjust
+ 1;
2569 erasedChunks
= dev
->n_erased_blocks
* dev
->param
.chunks_per_block
;
2571 /* If we need a block soon then do aggressive gc.*/
2572 if (dev
->n_erased_blocks
< minErased
)
2575 if(!background
&& erasedChunks
> (dev
->n_free_chunks
/ 4))
2578 if(dev
->gc_skip
> 20)
2580 if(erasedChunks
< dev
->n_free_chunks
/2 ||
2592 /* If we don't already have a block being gc'd then see if we should start another */
2594 if (dev
->gc_block
< 1 && !aggressive
) {
2595 dev
->gc_block
= yaffs2_find_refresh_block(dev
);
2599 if (dev
->gc_block
< 1) {
2600 dev
->gc_block
= yaffs_find_gc_block(dev
, aggressive
, background
);
2605 if (dev
->gc_block
> 0) {
2608 dev
->passive_gc_count
++;
2612 ("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR
),
2613 dev
->n_erased_blocks
, aggressive
));
2615 gcOk
= yaffs_gc_block(dev
, dev
->gc_block
, aggressive
);
2618 if (dev
->n_erased_blocks
< (dev
->param
.n_reserved_blocks
) && dev
->gc_block
> 0) {
2621 ("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d"
2622 TENDSTR
), dev
->n_erased_blocks
, maxTries
, dev
->gc_block
));
2624 } while ((dev
->n_erased_blocks
< dev
->param
.n_reserved_blocks
) &&
2625 (dev
->gc_block
> 0) &&
2628 return aggressive
? gcOk
: YAFFS_OK
;
2633 * Garbage collects. Intended to be called from a background thread.
2634 * Returns non-zero if at least half the free chunks are erased.
2636 int yaffs_bg_gc(yaffs_dev_t
*dev
, unsigned urgency
)
2638 int erasedChunks
= dev
->n_erased_blocks
* dev
->param
.chunks_per_block
;
2640 T(YAFFS_TRACE_BACKGROUND
, (TSTR("Background gc %u" TENDSTR
),urgency
));
2642 yaffs_check_gc(dev
, 1);
2643 return erasedChunks
> dev
->n_free_chunks
/2;
2646 /*------------------------- TAGS --------------------------------*/
2648 static int yaffs_tags_match(const yaffs_ext_tags
*tags
, int obj_id
,
2651 return (tags
->chunk_id
== chunkInObject
&&
2652 tags
->obj_id
== obj_id
&& !tags
->is_deleted
) ? 1 : 0;
2657 /*-------------------- Data file manipulation -----------------*/
2659 static int yaffs_find_chunk_in_file(yaffs_obj_t
*in
, int inode_chunk
,
2660 yaffs_ext_tags
*tags
)
2662 /*Get the Tnode, then get the level 0 offset chunk offset */
2665 yaffs_ext_tags localTags
;
2668 yaffs_dev_t
*dev
= in
->my_dev
;
2671 /* Passed a NULL, so use our own tags space */
2675 tn
= yaffs_find_tnode_0(dev
, &in
->variant
.file_variant
, inode_chunk
);
2678 theChunk
= yaffs_get_group_base(dev
, tn
, inode_chunk
);
2681 yaffs_find_chunk_in_group(dev
, theChunk
, tags
, in
->obj_id
,
2687 static int yaffs_find_del_file_chunk(yaffs_obj_t
*in
, int inode_chunk
,
2688 yaffs_ext_tags
*tags
)
2690 /* Get the Tnode, then get the level 0 offset chunk offset */
2693 yaffs_ext_tags localTags
;
2695 yaffs_dev_t
*dev
= in
->my_dev
;
2699 /* Passed a NULL, so use our own tags space */
2703 tn
= yaffs_find_tnode_0(dev
, &in
->variant
.file_variant
, inode_chunk
);
2707 theChunk
= yaffs_get_group_base(dev
, tn
, inode_chunk
);
2710 yaffs_find_chunk_in_group(dev
, theChunk
, tags
, in
->obj_id
,
2713 /* Delete the entry in the filestructure (if found) */
2715 yaffs_load_tnode_0(dev
, tn
, inode_chunk
, 0);
2722 int yaffs_put_chunk_in_file(yaffs_obj_t
*in
, int inode_chunk
,
2723 int nand_chunk
, int in_scan
)
2725 /* NB in_scan is zero unless scanning.
2726 * For forward scanning, in_scan is > 0;
2727 * for backward scanning in_scan is < 0
2729 * nand_chunk = 0 is a dummy insert to make sure the tnodes are there.
2733 yaffs_dev_t
*dev
= in
->my_dev
;
2735 yaffs_ext_tags existingTags
;
2736 yaffs_ext_tags newTags
;
2737 unsigned existingSerial
, newSerial
;
2739 if (in
->variant_type
!= YAFFS_OBJECT_TYPE_FILE
) {
2740 /* Just ignore an attempt at putting a chunk into a non-file during scanning
2741 * If it is not during Scanning then something went wrong!
2744 T(YAFFS_TRACE_ERROR
,
2746 ("yaffs tragedy:attempt to put data chunk into a non-file"
2751 yaffs_chunk_del(dev
, nand_chunk
, 1, __LINE__
);
2755 tn
= yaffs_add_find_tnode_0(dev
,
2756 &in
->variant
.file_variant
,
2763 /* Dummy insert, bail now */
2766 existingChunk
= yaffs_get_group_base(dev
, tn
, inode_chunk
);
2769 /* If we're scanning then we need to test for duplicates
2770 * NB This does not need to be efficient since it should only ever
2771 * happen when the power fails during a write, then only one
2772 * chunk should ever be affected.
2774 * Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO
2775 * Update: For backward scanning we don't need to re-read tags so this is quite cheap.
2778 if (existingChunk
> 0) {
2779 /* NB Right now existing chunk will not be real chunk_id if the chunk group size > 1
2780 * thus we have to do a FindChunkInFile to get the real chunk id.
2782 * We have a duplicate now we need to decide which one to use:
2784 * Backwards scanning YAFFS2: The old one is what we use, dump the new one.
2785 * Forward scanning YAFFS2: The new one is what we use, dump the old one.
2786 * YAFFS1: Get both sets of tags and compare serial numbers.
2790 /* Only do this for forward scanning */
2791 yaffs_rd_chunk_tags_nand(dev
,
2795 /* Do a proper find */
2797 yaffs_find_chunk_in_file(in
, inode_chunk
,
2801 if (existingChunk
<= 0) {
2802 /*Hoosterman - how did this happen? */
2804 T(YAFFS_TRACE_ERROR
,
2806 ("yaffs tragedy: existing chunk < 0 in scan"
2811 /* NB The deleted flags should be false, otherwise the chunks will
2812 * not be loaded during a scan
2816 newSerial
= newTags
.serial_number
;
2817 existingSerial
= existingTags
.serial_number
;
2820 if ((in_scan
> 0) &&
2821 (existingChunk
<= 0 ||
2822 ((existingSerial
+ 1) & 3) == newSerial
)) {
2823 /* Forward scanning.
2825 * Delete the old one and drop through to update the tnode
2827 yaffs_chunk_del(dev
, existingChunk
, 1,
2830 /* Backward scanning or we want to use the existing one
2832 * Delete the new one and return early so that the tnode isn't changed
2834 yaffs_chunk_del(dev
, nand_chunk
, 1,
2842 if (existingChunk
== 0)
2843 in
->n_data_chunks
++;
2845 yaffs_load_tnode_0(dev
, tn
, inode_chunk
, nand_chunk
);
2850 static int yaffs_rd_data_obj(yaffs_obj_t
*in
, int inode_chunk
,
2853 int nand_chunk
= yaffs_find_chunk_in_file(in
, inode_chunk
, NULL
);
2855 if (nand_chunk
>= 0)
2856 return yaffs_rd_chunk_tags_nand(in
->my_dev
, nand_chunk
,
2859 T(YAFFS_TRACE_NANDACCESS
,
2860 (TSTR("Chunk %d not found zero instead" TENDSTR
),
2862 /* get sane (zero) data if you read a hole */
2863 memset(buffer
, 0, in
->my_dev
->data_bytes_per_chunk
);
2869 void yaffs_chunk_del(yaffs_dev_t
*dev
, int chunk_id
, int mark_flash
, int lyn
)
2873 yaffs_ext_tags tags
;
2874 yaffs_block_info_t
*bi
;
2880 block
= chunk_id
/ dev
->param
.chunks_per_block
;
2881 page
= chunk_id
% dev
->param
.chunks_per_block
;
2884 if (!yaffs_check_chunk_bit(dev
, block
, page
))
2885 T(YAFFS_TRACE_VERIFY
,
2886 (TSTR("Deleting invalid chunk %d"TENDSTR
),
2889 bi
= yaffs_get_block_info(dev
, block
);
2891 yaffs2_update_oldest_dirty_seq(dev
, block
, bi
);
2893 T(YAFFS_TRACE_DELETION
,
2894 (TSTR("line %d delete of chunk %d" TENDSTR
), lyn
, chunk_id
));
2896 if (!dev
->param
.is_yaffs2
&& mark_flash
&&
2897 bi
->block_state
!= YAFFS_BLOCK_STATE_COLLECTING
) {
2899 yaffs_init_tags(&tags
);
2901 tags
.is_deleted
= 1;
2903 yaffs_wr_chunk_tags_nand(dev
, chunk_id
, NULL
, &tags
);
2904 yaffs_handle_chunk_update(dev
, chunk_id
, &tags
);
2906 dev
->n_unmarked_deletions
++;
2909 /* Pull out of the management area.
2910 * If the whole block became dirty, this will kick off an erasure.
2912 if (bi
->block_state
== YAFFS_BLOCK_STATE_ALLOCATING
||
2913 bi
->block_state
== YAFFS_BLOCK_STATE_FULL
||
2914 bi
->block_state
== YAFFS_BLOCK_STATE_NEEDS_SCANNING
||
2915 bi
->block_state
== YAFFS_BLOCK_STATE_COLLECTING
) {
2916 dev
->n_free_chunks
++;
2918 yaffs_clear_chunk_bit(dev
, block
, page
);
2922 if (bi
->pages_in_use
== 0 &&
2923 !bi
->has_shrink_hdr
&&
2924 bi
->block_state
!= YAFFS_BLOCK_STATE_ALLOCATING
&&
2925 bi
->block_state
!= YAFFS_BLOCK_STATE_NEEDS_SCANNING
) {
2926 yaffs_block_became_dirty(dev
, block
);
2933 static int yaffs_wr_data_obj(yaffs_obj_t
*in
, int inode_chunk
,
2934 const __u8
*buffer
, int n_bytes
,
2937 /* Find old chunk Need to do this to get serial number
2938 * Write new one and patch into tree.
2939 * Invalidate old tags.
2943 yaffs_ext_tags prevTags
;
2946 yaffs_ext_tags newTags
;
2948 yaffs_dev_t
*dev
= in
->my_dev
;
2950 yaffs_check_gc(dev
,0);
2952 /* Get the previous chunk at this location in the file if it exists.
2953 * If it does not exist then put a zero into the tree. This creates
2954 * the tnode now, rather than later when it is harder to clean up.
2956 prevChunkId
= yaffs_find_chunk_in_file(in
, inode_chunk
, &prevTags
);
2957 if(prevChunkId
< 1 &&
2958 !yaffs_put_chunk_in_file(in
, inode_chunk
, 0, 0))
2961 /* Set up new tags */
2962 yaffs_init_tags(&newTags
);
2964 newTags
.chunk_id
= inode_chunk
;
2965 newTags
.obj_id
= in
->obj_id
;
2966 newTags
.serial_number
=
2967 (prevChunkId
> 0) ? prevTags
.serial_number
+ 1 : 1;
2968 newTags
.n_bytes
= n_bytes
;
2970 if (n_bytes
< 1 || n_bytes
> dev
->param
.total_bytes_per_chunk
) {
2971 T(YAFFS_TRACE_ERROR
,
2972 (TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR
), n_bytes
));
2978 yaffs_write_new_chunk(dev
, buffer
, &newTags
,
2981 if (newChunkId
> 0) {
2982 yaffs_put_chunk_in_file(in
, inode_chunk
, newChunkId
, 0);
2984 if (prevChunkId
> 0)
2985 yaffs_chunk_del(dev
, prevChunkId
, 1, __LINE__
);
2987 yaffs_verify_file_sane(in
);
2993 /* UpdateObjectHeader updates the header on NAND for an object.
2994 * If name is not NULL, then that new name is used.
2996 int yaffs_update_oh(yaffs_obj_t
*in
, const YCHAR
*name
, int force
,
2997 int is_shrink
, int shadows
, yaffs_xattr_mod
*xmod
)
3000 yaffs_block_info_t
*bi
;
3002 yaffs_dev_t
*dev
= in
->my_dev
;
3009 yaffs_ext_tags newTags
;
3010 yaffs_ext_tags oldTags
;
3011 const YCHAR
*alias
= NULL
;
3013 __u8
*buffer
= NULL
;
3014 YCHAR old_name
[YAFFS_MAX_NAME_LENGTH
+ 1];
3016 yaffs_obj_header
*oh
= NULL
;
3018 yaffs_strcpy(old_name
, _Y("silly old name"));
3022 in
== dev
->root_dir
|| /* The root_dir should also be saved */
3025 yaffs_check_gc(dev
,0);
3026 yaffs_check_obj_details_loaded(in
);
3028 buffer
= yaffs_get_temp_buffer(in
->my_dev
, __LINE__
);
3029 oh
= (yaffs_obj_header
*) buffer
;
3031 prevChunkId
= in
->hdr_chunk
;
3033 if (prevChunkId
> 0) {
3034 result
= yaffs_rd_chunk_tags_nand(dev
, prevChunkId
,
3037 yaffs_verify_oh(in
, oh
, &oldTags
, 0);
3039 memcpy(old_name
, oh
->name
, sizeof(oh
->name
));
3040 memset(buffer
, 0xFF, sizeof(yaffs_obj_header
));
3042 memset(buffer
, 0xFF, dev
->data_bytes_per_chunk
);
3044 oh
->type
= in
->variant_type
;
3045 oh
->yst_mode
= in
->yst_mode
;
3046 oh
->shadows_obj
= oh
->inband_shadowed_obj_id
= shadows
;
3048 #ifdef CONFIG_YAFFS_WINCE
3049 oh
->win_atime
[0] = in
->win_atime
[0];
3050 oh
->win_ctime
[0] = in
->win_ctime
[0];
3051 oh
->win_mtime
[0] = in
->win_mtime
[0];
3052 oh
->win_atime
[1] = in
->win_atime
[1];
3053 oh
->win_ctime
[1] = in
->win_ctime
[1];
3054 oh
->win_mtime
[1] = in
->win_mtime
[1];
3056 oh
->yst_uid
= in
->yst_uid
;
3057 oh
->yst_gid
= in
->yst_gid
;
3058 oh
->yst_atime
= in
->yst_atime
;
3059 oh
->yst_mtime
= in
->yst_mtime
;
3060 oh
->yst_ctime
= in
->yst_ctime
;
3061 oh
->yst_rdev
= in
->yst_rdev
;
3064 oh
->parent_obj_id
= in
->parent
->obj_id
;
3066 oh
->parent_obj_id
= 0;
3068 if (name
&& *name
) {
3069 memset(oh
->name
, 0, sizeof(oh
->name
));
3070 yaffs_load_oh_from_name(dev
,oh
->name
,name
);
3071 } else if (prevChunkId
> 0)
3072 memcpy(oh
->name
, old_name
, sizeof(oh
->name
));
3074 memset(oh
->name
, 0, sizeof(oh
->name
));
3076 oh
->is_shrink
= is_shrink
;
3078 switch (in
->variant_type
) {
3079 case YAFFS_OBJECT_TYPE_UNKNOWN
:
3080 /* Should not happen */
3082 case YAFFS_OBJECT_TYPE_FILE
:
3084 (oh
->parent_obj_id
== YAFFS_OBJECTID_DELETED
3085 || oh
->parent_obj_id
==
3086 YAFFS_OBJECTID_UNLINKED
) ? 0 : in
->variant
.
3087 file_variant
.file_size
;
3089 case YAFFS_OBJECT_TYPE_HARDLINK
:
3091 in
->variant
.hardlink_variant
.equiv_id
;
3093 case YAFFS_OBJECT_TYPE_SPECIAL
:
3096 case YAFFS_OBJECT_TYPE_DIRECTORY
:
3099 case YAFFS_OBJECT_TYPE_SYMLINK
:
3100 alias
= in
->variant
.symlink_variant
.alias
;
3102 alias
= _Y("no alias");
3103 yaffs_strncpy(oh
->alias
,
3105 YAFFS_MAX_ALIAS_LENGTH
);
3106 oh
->alias
[YAFFS_MAX_ALIAS_LENGTH
] = 0;
3110 /* process any xattrib modifications */
3112 yaffs_apply_xattrib_mod(in
, (char *)buffer
, xmod
);
3116 yaffs_init_tags(&newTags
);
3118 newTags
.chunk_id
= 0;
3119 newTags
.obj_id
= in
->obj_id
;
3120 newTags
.serial_number
= in
->serial
;
3122 /* Add extra info for file header */
3124 newTags
.extra_available
= 1;
3125 newTags
.extra_parent_id
= oh
->parent_obj_id
;
3126 newTags
.extra_length
= oh
->file_size
;
3127 newTags
.extra_is_shrink
= oh
->is_shrink
;
3128 newTags
.extra_equiv_id
= oh
->equiv_id
;
3129 newTags
.extra_shadows
= (oh
->shadows_obj
> 0) ? 1 : 0;
3130 newTags
.extra_obj_type
= in
->variant_type
;
3132 yaffs_verify_oh(in
, oh
, &newTags
, 1);
3134 /* Create new chunk in NAND */
3136 yaffs_write_new_chunk(dev
, buffer
, &newTags
,
3137 (prevChunkId
> 0) ? 1 : 0);
3139 if (newChunkId
>= 0) {
3141 in
->hdr_chunk
= newChunkId
;
3143 if (prevChunkId
> 0) {
3144 yaffs_chunk_del(dev
, prevChunkId
, 1,
3148 if (!yaffs_obj_cache_dirty(in
))
3151 /* If this was a shrink, then mark the block that the chunk lives on */
3153 bi
= yaffs_get_block_info(in
->my_dev
,
3154 newChunkId
/ in
->my_dev
->param
.chunks_per_block
);
3155 bi
->has_shrink_hdr
= 1;
3160 retVal
= newChunkId
;
3165 yaffs_release_temp_buffer(dev
, buffer
, __LINE__
);
3170 /*------------------------ Short Operations Cache ----------------------------------------
3171 * In many situations where there is no high level buffering (eg WinCE) a lot of
3172 * reads might be short sequential reads, and a lot of writes may be short
3173 * sequential writes. eg. scanning/writing a jpeg file.
3174 * In these cases, a short read/write cache can provide a huge perfomance benefit
3175 * with dumb-as-a-rock code.
3176 * In Linux, the page cache provides read buffering aand the short op cache provides write
3179 * There are a limited number (~10) of cache chunks per device so that we don't
3180 * need a very intelligent search.
3183 static int yaffs_obj_cache_dirty(yaffs_obj_t
*obj
)
3185 yaffs_dev_t
*dev
= obj
->my_dev
;
3187 yaffs_cache_t
*cache
;
3188 int nCaches
= obj
->my_dev
->param
.n_caches
;
3190 for (i
= 0; i
< nCaches
; i
++) {
3191 cache
= &dev
->cache
[i
];
3192 if (cache
->object
== obj
&&
3201 static void yaffs_flush_file_cache(yaffs_obj_t
*obj
)
3203 yaffs_dev_t
*dev
= obj
->my_dev
;
3204 int lowest
= -99; /* Stop compiler whining. */
3206 yaffs_cache_t
*cache
;
3207 int chunkWritten
= 0;
3208 int nCaches
= obj
->my_dev
->param
.n_caches
;
3214 /* Find the dirty cache for this object with the lowest chunk id. */
3215 for (i
= 0; i
< nCaches
; i
++) {
3216 if (dev
->cache
[i
].object
== obj
&&
3217 dev
->cache
[i
].dirty
) {
3219 || dev
->cache
[i
].chunk_id
<
3221 cache
= &dev
->cache
[i
];
3222 lowest
= cache
->chunk_id
;
3227 if (cache
&& !cache
->locked
) {
3228 /* Write it out and free it up */
3231 yaffs_wr_data_obj(cache
->object
,
3237 cache
->object
= NULL
;
3240 } while (cache
&& chunkWritten
> 0);
3243 /* Hoosterman, disk full while writing cache out. */
3244 T(YAFFS_TRACE_ERROR
,
3245 (TSTR("yaffs tragedy: no space during cache write" TENDSTR
)));
3252 /*yaffs_flush_whole_cache(dev)
3257 void yaffs_flush_whole_cache(yaffs_dev_t
*dev
)
3260 int nCaches
= dev
->param
.n_caches
;
3263 /* Find a dirty object in the cache and flush it...
3264 * until there are no further dirty objects.
3268 for (i
= 0; i
< nCaches
&& !obj
; i
++) {
3269 if (dev
->cache
[i
].object
&&
3270 dev
->cache
[i
].dirty
)
3271 obj
= dev
->cache
[i
].object
;
3275 yaffs_flush_file_cache(obj
);
3282 /* Grab us a cache chunk for use.
3283 * First look for an empty one.
3284 * Then look for the least recently used non-dirty one.
3285 * Then look for the least recently used dirty one...., flush and look again.
3287 static yaffs_cache_t
*yaffs_grab_chunk_worker(yaffs_dev_t
*dev
)
3291 if (dev
->param
.n_caches
> 0) {
3292 for (i
= 0; i
< dev
->param
.n_caches
; i
++) {
3293 if (!dev
->cache
[i
].object
)
3294 return &dev
->cache
[i
];
3301 static yaffs_cache_t
*yaffs_grab_chunk_cache(yaffs_dev_t
*dev
)
3303 yaffs_cache_t
*cache
;
3304 yaffs_obj_t
*theObj
;
3309 if (dev
->param
.n_caches
> 0) {
3310 /* Try find a non-dirty one... */
3312 cache
= yaffs_grab_chunk_worker(dev
);
3315 /* They were all dirty, find the last recently used object and flush
3316 * its cache, then find again.
3317 * NB what's here is not very accurate, we actually flush the object
3318 * the last recently used page.
3321 /* With locking we can't assume we can use entry zero */
3328 for (i
= 0; i
< dev
->param
.n_caches
; i
++) {
3329 if (dev
->cache
[i
].object
&&
3330 !dev
->cache
[i
].locked
&&
3331 (dev
->cache
[i
].last_use
< usage
|| !cache
)) {
3332 usage
= dev
->cache
[i
].last_use
;
3333 theObj
= dev
->cache
[i
].object
;
3334 cache
= &dev
->cache
[i
];
3339 if (!cache
|| cache
->dirty
) {
3340 /* Flush and try again */
3341 yaffs_flush_file_cache(theObj
);
3342 cache
= yaffs_grab_chunk_worker(dev
);
3352 /* Find a cached chunk */
3353 static yaffs_cache_t
*yaffs_find_chunk_cache(const yaffs_obj_t
*obj
,
3356 yaffs_dev_t
*dev
= obj
->my_dev
;
3358 if (dev
->param
.n_caches
> 0) {
3359 for (i
= 0; i
< dev
->param
.n_caches
; i
++) {
3360 if (dev
->cache
[i
].object
== obj
&&
3361 dev
->cache
[i
].chunk_id
== chunk_id
) {
3364 return &dev
->cache
[i
];
3371 /* Mark the chunk for the least recently used algorithym */
3372 static void yaffs_use_cache(yaffs_dev_t
*dev
, yaffs_cache_t
*cache
,
3376 if (dev
->param
.n_caches
> 0) {
3377 if (dev
->cache_last_use
< 0 || dev
->cache_last_use
> 100000000) {
3378 /* Reset the cache usages */
3380 for (i
= 1; i
< dev
->param
.n_caches
; i
++)
3381 dev
->cache
[i
].last_use
= 0;
3383 dev
->cache_last_use
= 0;
3386 dev
->cache_last_use
++;
3388 cache
->last_use
= dev
->cache_last_use
;
3395 /* Invalidate a single cache page.
3396 * Do this when a whole page gets written,
3397 * ie the short cache for this page is no longer valid.
3399 static void yaffs_invalidate_chunk_cache(yaffs_obj_t
*object
, int chunk_id
)
3401 if (object
->my_dev
->param
.n_caches
> 0) {
3402 yaffs_cache_t
*cache
= yaffs_find_chunk_cache(object
, chunk_id
);
3405 cache
->object
= NULL
;
3409 /* Invalidate all the cache pages associated with this object
3410 * Do this whenever ther file is deleted or resized.
3412 static void yaffs_invalidate_whole_cache(yaffs_obj_t
*in
)
3415 yaffs_dev_t
*dev
= in
->my_dev
;
3417 if (dev
->param
.n_caches
> 0) {
3418 /* Invalidate it. */
3419 for (i
= 0; i
< dev
->param
.n_caches
; i
++) {
3420 if (dev
->cache
[i
].object
== in
)
3421 dev
->cache
[i
].object
= NULL
;
3427 /*--------------------- File read/write ------------------------
3428 * Read and write have very similar structures.
3429 * In general the read/write has three parts to it
3430 * An incomplete chunk to start with (if the read/write is not chunk-aligned)
3431 * Some complete chunks
3432 * An incomplete chunk to end off with
3434 * Curve-balls: the first chunk might also be the last chunk.
3437 int yaffs_file_rd(yaffs_obj_t
*in
, __u8
*buffer
, loff_t offset
,
3446 yaffs_cache_t
*cache
;
3453 /* chunk = offset / dev->data_bytes_per_chunk + 1; */
3454 /* start = offset % dev->data_bytes_per_chunk; */
3455 yaffs_addr_to_chunk(dev
, offset
, &chunk
, &start
);
3458 /* OK now check for the curveball where the start and end are in
3461 if ((start
+ n
) < dev
->data_bytes_per_chunk
)
3464 nToCopy
= dev
->data_bytes_per_chunk
- start
;
3466 cache
= yaffs_find_chunk_cache(in
, chunk
);
3468 /* If the chunk is already in the cache or it is less than a whole chunk
3469 * or we're using inband tags then use the cache (if there is caching)
3470 * else bypass the cache.
3472 if (cache
|| nToCopy
!= dev
->data_bytes_per_chunk
|| dev
->param
.inband_tags
) {
3473 if (dev
->param
.n_caches
> 0) {
3475 /* If we can't find the data in the cache, then load it up. */
3478 cache
= yaffs_grab_chunk_cache(in
->my_dev
);
3480 cache
->chunk_id
= chunk
;
3483 yaffs_rd_data_obj(in
, chunk
,
3489 yaffs_use_cache(dev
, cache
, 0);
3494 memcpy(buffer
, &cache
->data
[start
], nToCopy
);
3498 /* Read into the local buffer then copy..*/
3501 yaffs_get_temp_buffer(dev
, __LINE__
);
3502 yaffs_rd_data_obj(in
, chunk
,
3505 memcpy(buffer
, &localBuffer
[start
], nToCopy
);
3508 yaffs_release_temp_buffer(dev
, localBuffer
,
3514 /* A full chunk. Read directly into the supplied buffer. */
3515 yaffs_rd_data_obj(in
, chunk
, buffer
);
3529 int yaffs_do_file_wr(yaffs_obj_t
*in
, const __u8
*buffer
, loff_t offset
,
3530 int n_bytes
, int write_trhrough
)
3539 int startOfWrite
= offset
;
3540 int chunkWritten
= 0;
3548 while (n
> 0 && chunkWritten
>= 0) {
3549 yaffs_addr_to_chunk(dev
, offset
, &chunk
, &start
);
3551 if (chunk
* dev
->data_bytes_per_chunk
+ start
!= offset
||
3552 start
>= dev
->data_bytes_per_chunk
) {
3553 T(YAFFS_TRACE_ERROR
, (
3554 TSTR("AddrToChunk of offset %d gives chunk %d start %d"
3556 (int)offset
, chunk
, start
));
3558 chunk
++; /* File pos to chunk in file offset */
3560 /* OK now check for the curveball where the start and end are in
3564 if ((start
+ n
) < dev
->data_bytes_per_chunk
) {
3567 /* Now folks, to calculate how many bytes to write back....
3568 * If we're overwriting and not writing to then end of file then
3569 * we need to write back as much as was there before.
3572 chunkStart
= ((chunk
- 1) * dev
->data_bytes_per_chunk
);
3574 if (chunkStart
> in
->variant
.file_variant
.file_size
)
3575 n_bytesRead
= 0; /* Past end of file */
3577 n_bytesRead
= in
->variant
.file_variant
.file_size
- chunkStart
;
3579 if (n_bytesRead
> dev
->data_bytes_per_chunk
)
3580 n_bytesRead
= dev
->data_bytes_per_chunk
;
3584 (start
+ n
)) ? n_bytesRead
: (start
+ n
);
3586 if (nToWriteBack
< 0 || nToWriteBack
> dev
->data_bytes_per_chunk
)
3590 nToCopy
= dev
->data_bytes_per_chunk
- start
;
3591 nToWriteBack
= dev
->data_bytes_per_chunk
;
3594 if (nToCopy
!= dev
->data_bytes_per_chunk
|| dev
->param
.inband_tags
) {
3595 /* An incomplete start or end chunk (or maybe both start and end chunk),
3596 * or we're using inband tags, so we want to use the cache buffers.
3598 if (dev
->param
.n_caches
> 0) {
3599 yaffs_cache_t
*cache
;
3600 /* If we can't find the data in the cache, then load the cache */
3601 cache
= yaffs_find_chunk_cache(in
, chunk
);
3604 && yaffs_check_alloc_available(dev
, 1)) {
3605 cache
= yaffs_grab_chunk_cache(dev
);
3607 cache
->chunk_id
= chunk
;
3610 yaffs_rd_data_obj(in
, chunk
,
3614 !yaffs_check_alloc_available(dev
, 1)) {
3615 /* Drop the cache if it was a read cache item and
3616 * no space check has been made for it.
3622 yaffs_use_cache(dev
, cache
, 1);
3626 memcpy(&cache
->data
[start
], buffer
,
3631 cache
->n_bytes
= nToWriteBack
;
3633 if (write_trhrough
) {
3638 cache
->data
, cache
->n_bytes
,
3644 chunkWritten
= -1; /* fail the write */
3647 /* An incomplete start or end chunk (or maybe both start and end chunk)
3648 * Read into the local buffer then copy, then copy over and write back.
3652 yaffs_get_temp_buffer(dev
, __LINE__
);
3654 yaffs_rd_data_obj(in
, chunk
,
3659 memcpy(&localBuffer
[start
], buffer
, nToCopy
);
3662 yaffs_wr_data_obj(in
, chunk
,
3667 yaffs_release_temp_buffer(dev
, localBuffer
,
3673 /* A full chunk. Write directly from the supplied buffer. */
3678 yaffs_wr_data_obj(in
, chunk
, buffer
,
3679 dev
->data_bytes_per_chunk
,
3682 /* Since we've overwritten the cached data, we better invalidate it. */
3683 yaffs_invalidate_chunk_cache(in
, chunk
);
3686 if (chunkWritten
>= 0) {
3695 /* Update file object */
3697 if ((startOfWrite
+ nDone
) > in
->variant
.file_variant
.file_size
)
3698 in
->variant
.file_variant
.file_size
= (startOfWrite
+ nDone
);
3705 int yaffs_wr_file(yaffs_obj_t
*in
, const __u8
*buffer
, loff_t offset
,
3706 int n_bytes
, int write_trhrough
)
3708 yaffs2_handle_hole(in
,offset
);
3709 return yaffs_do_file_wr(in
,buffer
,offset
,n_bytes
,write_trhrough
);
3714 /* ---------------------- File resizing stuff ------------------ */
3716 static void yaffs_prune_chunks(yaffs_obj_t
*in
, int new_size
)
3719 yaffs_dev_t
*dev
= in
->my_dev
;
3720 int oldFileSize
= in
->variant
.file_variant
.file_size
;
3722 int lastDel
= 1 + (oldFileSize
- 1) / dev
->data_bytes_per_chunk
;
3724 int startDel
= 1 + (new_size
+ dev
->data_bytes_per_chunk
- 1) /
3725 dev
->data_bytes_per_chunk
;
3729 /* Delete backwards so that we don't end up with holes if
3730 * power is lost part-way through the operation.
3732 for (i
= lastDel
; i
>= startDel
; i
--) {
3733 /* NB this could be optimised somewhat,
3734 * eg. could retrieve the tags and write them without
3735 * using yaffs_chunk_del
3738 chunk_id
= yaffs_find_del_file_chunk(in
, i
, NULL
);
3741 (dev
->internal_start_block
* dev
->param
.chunks_per_block
)
3743 ((dev
->internal_end_block
+
3744 1) * dev
->param
.chunks_per_block
)) {
3745 T(YAFFS_TRACE_ALWAYS
,
3746 (TSTR("Found daft chunk_id %d for %d" TENDSTR
),
3749 in
->n_data_chunks
--;
3750 yaffs_chunk_del(dev
, chunk_id
, 1, __LINE__
);
3758 void yaffs_resize_file_down( yaffs_obj_t
*obj
, loff_t new_size
)
3761 __u32 new_sizeOfPartialChunk
;
3762 yaffs_dev_t
*dev
= obj
->my_dev
;
3764 yaffs_addr_to_chunk(dev
, new_size
, &newFullChunks
, &new_sizeOfPartialChunk
);
3766 yaffs_prune_chunks(obj
, new_size
);
3768 if (new_sizeOfPartialChunk
!= 0) {
3769 int lastChunk
= 1 + newFullChunks
;
3770 __u8
*localBuffer
= yaffs_get_temp_buffer(dev
, __LINE__
);
3772 /* Got to read and rewrite the last chunk with its new size and zero pad */
3773 yaffs_rd_data_obj(obj
, lastChunk
, localBuffer
);
3774 memset(localBuffer
+ new_sizeOfPartialChunk
, 0,
3775 dev
->data_bytes_per_chunk
- new_sizeOfPartialChunk
);
3777 yaffs_wr_data_obj(obj
, lastChunk
, localBuffer
,
3778 new_sizeOfPartialChunk
, 1);
3780 yaffs_release_temp_buffer(dev
, localBuffer
, __LINE__
);
3783 obj
->variant
.file_variant
.file_size
= new_size
;
3785 yaffs_prune_tree(dev
, &obj
->variant
.file_variant
);
3789 int yaffs_resize_file(yaffs_obj_t
*in
, loff_t new_size
)
3791 yaffs_dev_t
*dev
= in
->my_dev
;
3792 int oldFileSize
= in
->variant
.file_variant
.file_size
;
3794 yaffs_flush_file_cache(in
);
3795 yaffs_invalidate_whole_cache(in
);
3797 yaffs_check_gc(dev
,0);
3799 if (in
->variant_type
!= YAFFS_OBJECT_TYPE_FILE
)
3802 if (new_size
== oldFileSize
)
3805 if(new_size
> oldFileSize
){
3806 yaffs2_handle_hole(in
,new_size
);
3807 in
->variant
.file_variant
.file_size
= new_size
;
3809 /* new_size < oldFileSize */
3810 yaffs_resize_file_down(in
, new_size
);
3813 /* Write a new object header to reflect the resize.
3814 * show we've shrunk the file, if need be
3815 * Do this only if the file is not in the deleted directories
3816 * and is not shadowed.
3820 in
->parent
->obj_id
!= YAFFS_OBJECTID_UNLINKED
&&
3821 in
->parent
->obj_id
!= YAFFS_OBJECTID_DELETED
)
3822 yaffs_update_oh(in
, NULL
, 0, 0, 0, NULL
);
3828 loff_t
yaffs_get_file_size(yaffs_obj_t
*obj
)
3830 YCHAR
*alias
= NULL
;
3831 obj
= yaffs_get_equivalent_obj(obj
);
3833 switch (obj
->variant_type
) {
3834 case YAFFS_OBJECT_TYPE_FILE
:
3835 return obj
->variant
.file_variant
.file_size
;
3836 case YAFFS_OBJECT_TYPE_SYMLINK
:
3837 alias
= obj
->variant
.symlink_variant
.alias
;
3840 return yaffs_strnlen(alias
,YAFFS_MAX_ALIAS_LENGTH
);
3848 int yaffs_flush_file(yaffs_obj_t
*in
, int update_time
, int data_sync
)
3852 yaffs_flush_file_cache(in
);
3853 if(data_sync
) /* Only sync data */
3857 #ifdef CONFIG_YAFFS_WINCE
3858 yfsd_win_file_time_now(in
->win_mtime
);
3861 in
->yst_mtime
= Y_CURRENT_TIME
;
3866 retVal
= (yaffs_update_oh(in
, NULL
, 0, 0, 0, NULL
) >=
3867 0) ? YAFFS_OK
: YAFFS_FAIL
;
3877 static int yaffs_generic_obj_del(yaffs_obj_t
*in
)
3880 /* First off, invalidate the file's data in the cache, without flushing. */
3881 yaffs_invalidate_whole_cache(in
);
3883 if (in
->my_dev
->param
.is_yaffs2
&& (in
->parent
!= in
->my_dev
->del_dir
)) {
3884 /* Move to the unlinked directory so we have a record that it was deleted. */
3885 yaffs_change_obj_name(in
, in
->my_dev
->del_dir
, _Y("deleted"), 0, 0);
3889 yaffs_remove_obj_from_dir(in
);
3890 yaffs_chunk_del(in
->my_dev
, in
->hdr_chunk
, 1, __LINE__
);
3898 /* yaffs_del_file deletes the whole file data
3899 * and the inode associated with the file.
3900 * It does not delete the links associated with the file.
3902 static int yaffs_unlink_file_if_needed(yaffs_obj_t
*in
)
3906 int immediateDeletion
= 0;
3907 yaffs_dev_t
*dev
= in
->my_dev
;
3910 immediateDeletion
= 1;
3912 if (immediateDeletion
) {
3914 yaffs_change_obj_name(in
, in
->my_dev
->del_dir
,
3915 _Y("deleted"), 0, 0);
3916 T(YAFFS_TRACE_TRACING
,
3917 (TSTR("yaffs: immediate deletion of file %d" TENDSTR
),
3920 in
->my_dev
->n_deleted_files
++;
3921 if (dev
->param
.disable_soft_del
|| dev
->param
.is_yaffs2
)
3922 yaffs_resize_file(in
, 0);
3923 yaffs_soft_del_file(in
);
3926 yaffs_change_obj_name(in
, in
->my_dev
->unlinked_dir
,
3927 _Y("unlinked"), 0, 0);
3934 int yaffs_del_file(yaffs_obj_t
*in
)
3936 int retVal
= YAFFS_OK
;
3937 int deleted
; /* Need to cache value on stack if in is freed */
3938 yaffs_dev_t
*dev
= in
->my_dev
;
3940 if (dev
->param
.disable_soft_del
|| dev
->param
.is_yaffs2
)
3941 yaffs_resize_file(in
, 0);
3943 if (in
->n_data_chunks
> 0) {
3944 /* Use soft deletion if there is data in the file.
3945 * That won't be the case if it has been resized to zero.
3948 retVal
= yaffs_unlink_file_if_needed(in
);
3950 deleted
= in
->deleted
;
3952 if (retVal
== YAFFS_OK
&& in
->unlinked
&& !in
->deleted
) {
3955 in
->my_dev
->n_deleted_files
++;
3956 yaffs_soft_del_file(in
);
3958 return deleted
? YAFFS_OK
: YAFFS_FAIL
;
3960 /* The file has no data chunks so we toss it immediately */
3961 yaffs_free_tnode(in
->my_dev
, in
->variant
.file_variant
.top
);
3962 in
->variant
.file_variant
.top
= NULL
;
3963 yaffs_generic_obj_del(in
);
3969 static int yaffs_is_non_empty_dir(yaffs_obj_t
*obj
)
3971 return (obj
->variant_type
== YAFFS_OBJECT_TYPE_DIRECTORY
) &&
3972 !(ylist_empty(&obj
->variant
.dir_variant
.children
));
3975 static int yaffs_del_dir(yaffs_obj_t
*obj
)
3977 /* First check that the directory is empty. */
3978 if (yaffs_is_non_empty_dir(obj
))
3981 return yaffs_generic_obj_del(obj
);
3984 static int yaffs_del_symlink(yaffs_obj_t
*in
)
3986 if(in
->variant
.symlink_variant
.alias
)
3987 YFREE(in
->variant
.symlink_variant
.alias
);
3988 in
->variant
.symlink_variant
.alias
=NULL
;
3990 return yaffs_generic_obj_del(in
);
3993 static int yaffs_del_link(yaffs_obj_t
*in
)
3995 /* remove this hardlink from the list assocaited with the equivalent
3998 ylist_del_init(&in
->hard_links
);
3999 return yaffs_generic_obj_del(in
);
4002 int yaffs_del_obj(yaffs_obj_t
*obj
)
4005 switch (obj
->variant_type
) {
4006 case YAFFS_OBJECT_TYPE_FILE
:
4007 retVal
= yaffs_del_file(obj
);
4009 case YAFFS_OBJECT_TYPE_DIRECTORY
:
4010 if(!ylist_empty(&obj
->variant
.dir_variant
.dirty
)){
4011 T(YAFFS_TRACE_BACKGROUND
, (TSTR("Remove object %d from dirty directories" TENDSTR
),obj
->obj_id
));
4012 ylist_del_init(&obj
->variant
.dir_variant
.dirty
);
4014 return yaffs_del_dir(obj
);
4016 case YAFFS_OBJECT_TYPE_SYMLINK
:
4017 retVal
= yaffs_del_symlink(obj
);
4019 case YAFFS_OBJECT_TYPE_HARDLINK
:
4020 retVal
= yaffs_del_link(obj
);
4022 case YAFFS_OBJECT_TYPE_SPECIAL
:
4023 retVal
= yaffs_generic_obj_del(obj
);
4025 case YAFFS_OBJECT_TYPE_UNKNOWN
:
4027 break; /* should not happen. */
4033 static int yaffs_unlink_worker(yaffs_obj_t
*obj
)
4036 int immediateDeletion
= 0;
4039 immediateDeletion
= 1;
4042 yaffs_update_parent(obj
->parent
);
4044 if (obj
->variant_type
== YAFFS_OBJECT_TYPE_HARDLINK
) {
4045 return yaffs_del_link(obj
);
4046 } else if (!ylist_empty(&obj
->hard_links
)) {
4047 /* Curve ball: We're unlinking an object that has a hardlink.
4049 * This problem arises because we are not strictly following
4050 * The Linux link/inode model.
4052 * We can't really delete the object.
4053 * Instead, we do the following:
4054 * - Select a hardlink.
4055 * - Unhook it from the hard links
4056 * - Move it from its parent directory (so that the rename can work)
4057 * - Rename the object to the hardlink's name.
4058 * - Delete the hardlink
4062 yaffs_obj_t
*parent
;
4064 YCHAR name
[YAFFS_MAX_NAME_LENGTH
+ 1];
4066 hl
= ylist_entry(obj
->hard_links
.next
, yaffs_obj_t
, hard_links
);
4068 yaffs_get_obj_name(hl
, name
, YAFFS_MAX_NAME_LENGTH
+ 1);
4069 parent
= hl
->parent
;
4071 ylist_del_init(&hl
->hard_links
);
4073 yaffs_add_obj_to_dir(obj
->my_dev
->unlinked_dir
, hl
);
4075 retVal
= yaffs_change_obj_name(obj
,parent
, name
, 0, 0);
4077 if (retVal
== YAFFS_OK
)
4078 retVal
= yaffs_generic_obj_del(hl
);
4082 } else if (immediateDeletion
) {
4083 switch (obj
->variant_type
) {
4084 case YAFFS_OBJECT_TYPE_FILE
:
4085 return yaffs_del_file(obj
);
4087 case YAFFS_OBJECT_TYPE_DIRECTORY
:
4088 ylist_del_init(&obj
->variant
.dir_variant
.dirty
);
4089 return yaffs_del_dir(obj
);
4091 case YAFFS_OBJECT_TYPE_SYMLINK
:
4092 return yaffs_del_symlink(obj
);
4094 case YAFFS_OBJECT_TYPE_SPECIAL
:
4095 return yaffs_generic_obj_del(obj
);
4097 case YAFFS_OBJECT_TYPE_HARDLINK
:
4098 case YAFFS_OBJECT_TYPE_UNKNOWN
:
4102 } else if(yaffs_is_non_empty_dir(obj
))
4105 return yaffs_change_obj_name(obj
, obj
->my_dev
->unlinked_dir
,
4106 _Y("unlinked"), 0, 0);
4110 static int yaffs_unlink_obj(yaffs_obj_t
*obj
)
4113 if (obj
&& obj
->unlink_allowed
)
4114 return yaffs_unlink_worker(obj
);
4119 int yaffs_unlinker(yaffs_obj_t
*dir
, const YCHAR
*name
)
4123 obj
= yaffs_find_by_name(dir
, name
);
4124 return yaffs_unlink_obj(obj
);
4127 /*----------------------- Initialisation Scanning ---------------------- */
4129 void yaffs_handle_shadowed_obj(yaffs_dev_t
*dev
, int obj_id
,
4130 int backward_scanning
)
4134 if (!backward_scanning
) {
4135 /* Handle YAFFS1 forward scanning case
4136 * For YAFFS1 we always do the deletion
4140 /* Handle YAFFS2 case (backward scanning)
4141 * If the shadowed object exists then ignore.
4143 obj
= yaffs_find_by_number(dev
, obj_id
);
4148 /* Let's create it (if it does not exist) assuming it is a file so that it can do shrinking etc.
4149 * We put it in unlinked dir to be cleaned up after the scanning
4152 yaffs_find_or_create_by_number(dev
, obj_id
,
4153 YAFFS_OBJECT_TYPE_FILE
);
4156 obj
->is_shadowed
= 1;
4157 yaffs_add_obj_to_dir(dev
->unlinked_dir
, obj
);
4158 obj
->variant
.file_variant
.shrink_size
= 0;
4159 obj
->valid
= 1; /* So that we don't read any other info for this file */
4164 void yaffs_link_fixup(yaffs_dev_t
*dev
, yaffs_obj_t
*hard_list
)
4171 hard_list
= (yaffs_obj_t
*) (hard_list
->hard_links
.next
);
4173 in
= yaffs_find_by_number(dev
,
4174 hl
->variant
.hardlink_variant
.
4178 /* Add the hardlink pointers */
4179 hl
->variant
.hardlink_variant
.equiv_obj
= in
;
4180 ylist_add(&hl
->hard_links
, &in
->hard_links
);
4182 /* Todo Need to report/handle this better.
4183 * Got a problem... hardlink to a non-existant object
4185 hl
->variant
.hardlink_variant
.equiv_obj
= NULL
;
4186 YINIT_LIST_HEAD(&hl
->hard_links
);
4193 static void yaffs_strip_deleted_objs(yaffs_dev_t
*dev
)
4196 * Sort out state of unlinked and deleted objects after scanning.
4198 struct ylist_head
*i
;
4199 struct ylist_head
*n
;
4205 /* Soft delete all the unlinked files */
4206 ylist_for_each_safe(i
, n
,
4207 &dev
->unlinked_dir
->variant
.dir_variant
.children
) {
4209 l
= ylist_entry(i
, yaffs_obj_t
, siblings
);
4214 ylist_for_each_safe(i
, n
,
4215 &dev
->del_dir
->variant
.dir_variant
.children
) {
4217 l
= ylist_entry(i
, yaffs_obj_t
, siblings
);
4225 * This code iterates through all the objects making sure that they are rooted.
4226 * Any unrooted objects are re-rooted in lost+found.
4227 * An object needs to be in one of:
4228 * - Directly under deleted, unlinked
4229 * - Directly or indirectly under root.
4232 * This code assumes that we don't ever change the current relationships between
4234 * root_dir->parent == unlinked_dir->parent == del_dir->parent == NULL
4235 * lostNfound->parent == root_dir
4237 * This fixes the problem where directories might have inadvertently been deleted
4238 * leaving the object "hanging" without being rooted in the directory tree.
4241 static int yaffs_has_null_parent(yaffs_dev_t
*dev
, yaffs_obj_t
*obj
)
4243 return (obj
== dev
->del_dir
||
4244 obj
== dev
->unlinked_dir
||
4245 obj
== dev
->root_dir
);
4248 static void yaffs_fix_hanging_objs(yaffs_dev_t
*dev
)
4251 yaffs_obj_t
*parent
;
4253 struct ylist_head
*lh
;
4254 struct ylist_head
*n
;
4261 /* Iterate through the objects in each hash entry,
4262 * looking at each object.
4263 * Make sure it is rooted.
4266 for (i
= 0; i
< YAFFS_NOBJECT_BUCKETS
; i
++) {
4267 ylist_for_each_safe(lh
, n
, &dev
->obj_bucket
[i
].list
) {
4269 obj
= ylist_entry(lh
, yaffs_obj_t
, hash_link
);
4270 parent
= obj
->parent
;
4272 if(yaffs_has_null_parent(dev
,obj
)){
4273 /* These directories are not hanging */
4276 else if(!parent
|| parent
->variant_type
!= YAFFS_OBJECT_TYPE_DIRECTORY
)
4278 else if(yaffs_has_null_parent(dev
,parent
))
4282 * Need to follow the parent chain to see if it is hanging.
4287 while(parent
!= dev
->root_dir
&&
4289 parent
->parent
->variant_type
== YAFFS_OBJECT_TYPE_DIRECTORY
&&
4291 parent
= parent
->parent
;
4294 if(parent
!= dev
->root_dir
)
4299 (TSTR("Hanging object %d moved to lost and found" TENDSTR
),
4301 yaffs_add_obj_to_dir(dev
->lost_n_found
,obj
);
4310 * Delete directory contents for cleaning up lost and found.
4312 static void yaffs_del_dir_contents(yaffs_obj_t
*dir
)
4315 struct ylist_head
*lh
;
4316 struct ylist_head
*n
;
4318 if(dir
->variant_type
!= YAFFS_OBJECT_TYPE_DIRECTORY
)
4321 ylist_for_each_safe(lh
, n
, &dir
->variant
.dir_variant
.children
) {
4323 obj
= ylist_entry(lh
, yaffs_obj_t
, siblings
);
4324 if(obj
->variant_type
== YAFFS_OBJECT_TYPE_DIRECTORY
)
4325 yaffs_del_dir_contents(obj
);
4328 (TSTR("Deleting lost_found object %d" TENDSTR
),
4331 /* Need to use UnlinkObject since Delete would not handle
4332 * hardlinked objects correctly.
4334 yaffs_unlink_obj(obj
);
4340 static void yaffs_empty_l_n_f(yaffs_dev_t
*dev
)
4342 yaffs_del_dir_contents(dev
->lost_n_found
);
4345 static void yaffs_check_obj_details_loaded(yaffs_obj_t
*in
)
4348 yaffs_obj_header
*oh
;
4350 yaffs_ext_tags tags
;
4352 int alloc_failed
= 0;
4360 T(YAFFS_TRACE_SCAN
, (TSTR("details for object %d %s loaded" TENDSTR
),
4362 in
->lazy_loaded
? "not yet" : "already"));
4365 if (in
->lazy_loaded
&& in
->hdr_chunk
> 0) {
4366 in
->lazy_loaded
= 0;
4367 chunkData
= yaffs_get_temp_buffer(dev
, __LINE__
);
4369 result
= yaffs_rd_chunk_tags_nand(dev
, in
->hdr_chunk
, chunkData
, &tags
);
4370 oh
= (yaffs_obj_header
*) chunkData
;
4372 in
->yst_mode
= oh
->yst_mode
;
4373 #ifdef CONFIG_YAFFS_WINCE
4374 in
->win_atime
[0] = oh
->win_atime
[0];
4375 in
->win_ctime
[0] = oh
->win_ctime
[0];
4376 in
->win_mtime
[0] = oh
->win_mtime
[0];
4377 in
->win_atime
[1] = oh
->win_atime
[1];
4378 in
->win_ctime
[1] = oh
->win_ctime
[1];
4379 in
->win_mtime
[1] = oh
->win_mtime
[1];
4381 in
->yst_uid
= oh
->yst_uid
;
4382 in
->yst_gid
= oh
->yst_gid
;
4383 in
->yst_atime
= oh
->yst_atime
;
4384 in
->yst_mtime
= oh
->yst_mtime
;
4385 in
->yst_ctime
= oh
->yst_ctime
;
4386 in
->yst_rdev
= oh
->yst_rdev
;
4389 yaffs_set_obj_name_from_oh(in
, oh
);
4391 if (in
->variant_type
== YAFFS_OBJECT_TYPE_SYMLINK
) {
4392 in
->variant
.symlink_variant
.alias
=
4393 yaffs_clone_str(oh
->alias
);
4394 if (!in
->variant
.symlink_variant
.alias
)
4395 alloc_failed
= 1; /* Not returned to caller */
4398 yaffs_release_temp_buffer(dev
, chunkData
, __LINE__
);
4402 /*------------------------------ Directory Functions ----------------------------- */
4405 *yaffs_update_parent() handles fixing a directories mtime and ctime when a new
4406 * link (ie. name) is created or deleted in the directory.
4409 * create dir/a : update dir's mtime/ctime
4410 * rm dir/a: update dir's mtime/ctime
4411 * modify dir/a: don't update dir's mtimme/ctime
4413 * This can be handled immediately or defered. Defering helps reduce the number
4414 * of updates when many files in a directory are changed within a brief period.
4416 * If the directory updating is defered then yaffs_update_dirty_dirs must be
4417 * called periodically.
4420 static void yaffs_update_parent(yaffs_obj_t
*obj
)
4425 #ifndef CONFIG_YAFFS_WINCE
4429 obj
->yst_mtime
= obj
->yst_ctime
= Y_CURRENT_TIME
;
4430 if(dev
->param
.defered_dir_update
){
4431 struct ylist_head
*link
= &obj
->variant
.dir_variant
.dirty
;
4433 if(ylist_empty(link
)){
4434 ylist_add(link
,&dev
->dirty_dirs
);
4435 T(YAFFS_TRACE_BACKGROUND
, (TSTR("Added object %d to dirty directories" TENDSTR
),obj
->obj_id
));
4439 yaffs_update_oh(obj
, NULL
, 0, 0, 0, NULL
);
4443 void yaffs_update_dirty_dirs(yaffs_dev_t
*dev
)
4445 struct ylist_head
*link
;
4448 yaffs_obj_variant
*oV
;
4450 T(YAFFS_TRACE_BACKGROUND
, (TSTR("Update dirty directories" TENDSTR
)));
4452 while(!ylist_empty(&dev
->dirty_dirs
)){
4453 link
= dev
->dirty_dirs
.next
;
4454 ylist_del_init(link
);
4456 dS
=ylist_entry(link
,yaffs_dir_s
,dirty
);
4457 oV
= ylist_entry(dS
,yaffs_obj_variant
,dir_variant
);
4458 obj
= ylist_entry(oV
,yaffs_obj_t
,variant
);
4460 T(YAFFS_TRACE_BACKGROUND
, (TSTR("Update directory %d" TENDSTR
), obj
->obj_id
));
4463 yaffs_update_oh(obj
, NULL
, 0, 0, 0, NULL
);
4467 static void yaffs_remove_obj_from_dir(yaffs_obj_t
*obj
)
4469 yaffs_dev_t
*dev
= obj
->my_dev
;
4470 yaffs_obj_t
*parent
;
4472 yaffs_verify_obj_in_dir(obj
);
4473 parent
= obj
->parent
;
4475 yaffs_verify_dir(parent
);
4477 if (dev
&& dev
->param
.remove_obj_fn
)
4478 dev
->param
.remove_obj_fn(obj
);
4481 ylist_del_init(&obj
->siblings
);
4484 yaffs_verify_dir(parent
);
4487 void yaffs_add_obj_to_dir(yaffs_obj_t
*directory
,
4491 T(YAFFS_TRACE_ALWAYS
,
4493 ("tragedy: Trying to add an object to a null pointer directory"
4498 if (directory
->variant_type
!= YAFFS_OBJECT_TYPE_DIRECTORY
) {
4499 T(YAFFS_TRACE_ALWAYS
,
4501 ("tragedy: Trying to add an object to a non-directory"
4506 if (obj
->siblings
.prev
== NULL
) {
4507 /* Not initialised */
4512 yaffs_verify_dir(directory
);
4514 yaffs_remove_obj_from_dir(obj
);
4518 ylist_add(&obj
->siblings
, &directory
->variant
.dir_variant
.children
);
4519 obj
->parent
= directory
;
4521 if (directory
== obj
->my_dev
->unlinked_dir
4522 || directory
== obj
->my_dev
->del_dir
) {
4524 obj
->my_dev
->n_unlinked_files
++;
4525 obj
->rename_allowed
= 0;
4528 yaffs_verify_dir(directory
);
4529 yaffs_verify_obj_in_dir(obj
);
4532 yaffs_obj_t
*yaffs_find_by_name(yaffs_obj_t
*directory
,
4537 struct ylist_head
*i
;
4538 YCHAR buffer
[YAFFS_MAX_NAME_LENGTH
+ 1];
4546 T(YAFFS_TRACE_ALWAYS
,
4548 ("tragedy: yaffs_find_by_name: null pointer directory"
4553 if (directory
->variant_type
!= YAFFS_OBJECT_TYPE_DIRECTORY
) {
4554 T(YAFFS_TRACE_ALWAYS
,
4556 ("tragedy: yaffs_find_by_name: non-directory" TENDSTR
)));
4560 sum
= yaffs_calc_name_sum(name
);
4562 ylist_for_each(i
, &directory
->variant
.dir_variant
.children
) {
4564 l
= ylist_entry(i
, yaffs_obj_t
, siblings
);
4566 if (l
->parent
!= directory
)
4569 yaffs_check_obj_details_loaded(l
);
4571 /* Special case for lost-n-found */
4572 if (l
->obj_id
== YAFFS_OBJECTID_LOSTNFOUND
) {
4573 if (yaffs_strcmp(name
, YAFFS_LOSTNFOUND_NAME
) == 0)
4575 } else if (yaffs_sum_cmp(l
->sum
, sum
) || l
->hdr_chunk
<= 0) {
4576 /* LostnFound chunk called Objxxx
4579 yaffs_get_obj_name(l
, buffer
,
4580 YAFFS_MAX_NAME_LENGTH
+ 1);
4581 if (yaffs_strncmp(name
, buffer
, YAFFS_MAX_NAME_LENGTH
) == 0)
4592 int yaffs_ApplyToDirectoryChildren(yaffs_obj_t
*the_dir
,
4593 int (*fn
) (yaffs_obj_t
*))
4595 struct ylist_head
*i
;
4599 T(YAFFS_TRACE_ALWAYS
,
4601 ("tragedy: yaffs_find_by_name: null pointer directory"
4606 if (the_dir
->variant_type
!= YAFFS_OBJECT_TYPE_DIRECTORY
) {
4607 T(YAFFS_TRACE_ALWAYS
,
4609 ("tragedy: yaffs_find_by_name: non-directory" TENDSTR
)));
4614 ylist_for_each(i
, &the_dir
->variant
.dir_variant
.children
) {
4616 l
= ylist_entry(i
, yaffs_obj_t
, siblings
);
4627 /* GetEquivalentObject dereferences any hard links to get to the
4631 yaffs_obj_t
*yaffs_get_equivalent_obj(yaffs_obj_t
*obj
)
4633 if (obj
&& obj
->variant_type
== YAFFS_OBJECT_TYPE_HARDLINK
) {
4634 /* We want the object id of the equivalent object, not this one */
4635 obj
= obj
->variant
.hardlink_variant
.equiv_obj
;
4636 yaffs_check_obj_details_loaded(obj
);
4642 * A note or two on object names.
4643 * * If the object name is missing, we then make one up in the form objnnn
4645 * * ASCII names are stored in the object header's name field from byte zero
4646 * * Unicode names are historically stored starting from byte zero.
4648 * Then there are automatic Unicode names...
4649 * The purpose of these is to save names in a way that can be read as
4650 * ASCII or Unicode names as appropriate, thus allowing a Unicode and ASCII
4651 * system to share files.
4653 * These automatic unicode are stored slightly differently...
4654 * - If the name can fit in the ASCII character space then they are saved as
4655 * ascii names as per above.
4656 * - If the name needs Unicode then the name is saved in Unicode
4657 * starting at oh->name[1].
4660 static void yaffs_fix_null_name(yaffs_obj_t
* obj
,YCHAR
* name
, int buffer_size
)
4662 /* Create an object name if we could not find one. */
4663 if(yaffs_strnlen(name
,YAFFS_MAX_NAME_LENGTH
) == 0){
4665 YCHAR numString
[20];
4666 YCHAR
*x
= &numString
[19];
4667 unsigned v
= obj
->obj_id
;
4671 *x
= '0' + (v
% 10);
4674 /* make up a name */
4675 yaffs_strcpy(locName
, YAFFS_LOSTNFOUND_PREFIX
);
4676 yaffs_strcat(locName
,x
);
4677 yaffs_strncpy(name
, locName
, buffer_size
- 1);
4681 static void yaffs_load_name_from_oh(yaffs_dev_t
*dev
,YCHAR
*name
, const YCHAR
*ohName
, int bufferSize
)
4683 #ifdef CONFIG_YAFFS_AUTO_UNICODE
4684 if(dev
->param
.auto_unicode
){
4686 /* It is an ASCII name, so do an ASCII to unicode conversion */
4687 const char *asciiOhName
= (const char *)ohName
;
4688 int n
= bufferSize
- 1;
4689 while(n
> 0 && *asciiOhName
){
4690 *name
= *asciiOhName
;
4696 yaffs_strncpy(name
,ohName
+1, bufferSize
-1);
4699 yaffs_strncpy(name
, ohName
, bufferSize
- 1);
4703 static void yaffs_load_oh_from_name(yaffs_dev_t
*dev
, YCHAR
*ohName
, const YCHAR
*name
)
4705 #ifdef CONFIG_YAFFS_AUTO_UNICODE
4710 if(dev
->param
.auto_unicode
){
4715 /* Figure out if the name will fit in ascii character set */
4716 while(isAscii
&& *w
){
4723 /* It is an ASCII name, so do a unicode to ascii conversion */
4724 char *asciiOhName
= (char *)ohName
;
4725 int n
= YAFFS_MAX_NAME_LENGTH
- 1;
4726 while(n
> 0 && *name
){
4727 *asciiOhName
= *name
;
4733 /* It is a unicode name, so save starting at the second YCHAR */
4735 yaffs_strncpy(ohName
+1,name
, YAFFS_MAX_NAME_LENGTH
-2);
4740 yaffs_strncpy(ohName
,name
, YAFFS_MAX_NAME_LENGTH
- 1);
4744 int yaffs_get_obj_name(yaffs_obj_t
* obj
, YCHAR
* name
, int buffer_size
)
4746 memset(name
, 0, buffer_size
* sizeof(YCHAR
));
4748 yaffs_check_obj_details_loaded(obj
);
4750 if (obj
->obj_id
== YAFFS_OBJECTID_LOSTNFOUND
) {
4751 yaffs_strncpy(name
, YAFFS_LOSTNFOUND_NAME
, buffer_size
- 1);
4753 #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
4754 else if (obj
->short_name
[0]) {
4755 yaffs_strcpy(name
, obj
->short_name
);
4758 else if(obj
->hdr_chunk
> 0) {
4760 __u8
*buffer
= yaffs_get_temp_buffer(obj
->my_dev
, __LINE__
);
4762 yaffs_obj_header
*oh
= (yaffs_obj_header
*) buffer
;
4764 memset(buffer
, 0, obj
->my_dev
->data_bytes_per_chunk
);
4766 if (obj
->hdr_chunk
> 0) {
4767 result
= yaffs_rd_chunk_tags_nand(obj
->my_dev
,
4768 obj
->hdr_chunk
, buffer
,
4771 yaffs_load_name_from_oh(obj
->my_dev
,name
,oh
->name
,buffer_size
);
4773 yaffs_release_temp_buffer(obj
->my_dev
, buffer
, __LINE__
);
4776 yaffs_fix_null_name(obj
,name
,buffer_size
);
4778 return yaffs_strnlen(name
,YAFFS_MAX_NAME_LENGTH
);
4782 int yaffs_get_obj_length(yaffs_obj_t
*obj
)
4784 /* Dereference any hard linking */
4785 obj
= yaffs_get_equivalent_obj(obj
);
4787 if (obj
->variant_type
== YAFFS_OBJECT_TYPE_FILE
)
4788 return obj
->variant
.file_variant
.file_size
;
4789 if (obj
->variant_type
== YAFFS_OBJECT_TYPE_SYMLINK
){
4790 if(!obj
->variant
.symlink_variant
.alias
)
4792 return yaffs_strnlen(obj
->variant
.symlink_variant
.alias
,YAFFS_MAX_ALIAS_LENGTH
);
4794 /* Only a directory should drop through to here */
4795 return obj
->my_dev
->data_bytes_per_chunk
;
4799 int yaffs_get_obj_link_count(yaffs_obj_t
*obj
)
4802 struct ylist_head
*i
;
4805 count
++; /* the object itself */
4807 ylist_for_each(i
, &obj
->hard_links
)
4808 count
++; /* add the hard links; */
4813 int yaffs_get_obj_inode(yaffs_obj_t
*obj
)
4815 obj
= yaffs_get_equivalent_obj(obj
);
4820 unsigned yaffs_get_obj_type(yaffs_obj_t
*obj
)
4822 obj
= yaffs_get_equivalent_obj(obj
);
4824 switch (obj
->variant_type
) {
4825 case YAFFS_OBJECT_TYPE_FILE
:
4828 case YAFFS_OBJECT_TYPE_DIRECTORY
:
4831 case YAFFS_OBJECT_TYPE_SYMLINK
:
4834 case YAFFS_OBJECT_TYPE_HARDLINK
:
4837 case YAFFS_OBJECT_TYPE_SPECIAL
:
4838 if (S_ISFIFO(obj
->yst_mode
))
4840 if (S_ISCHR(obj
->yst_mode
))
4842 if (S_ISBLK(obj
->yst_mode
))
4844 if (S_ISSOCK(obj
->yst_mode
))
4852 YCHAR
*yaffs_get_symlink_alias(yaffs_obj_t
*obj
)
4854 obj
= yaffs_get_equivalent_obj(obj
);
4855 if (obj
->variant_type
== YAFFS_OBJECT_TYPE_SYMLINK
)
4856 return yaffs_clone_str(obj
->variant
.symlink_variant
.alias
);
4858 return yaffs_clone_str(_Y(""));
4861 #ifndef CONFIG_YAFFS_WINCE
4863 int yaffs_set_attribs(yaffs_obj_t
*obj
, struct iattr
*attr
)
4865 unsigned int valid
= attr
->ia_valid
;
4867 if (valid
& ATTR_MODE
)
4868 obj
->yst_mode
= attr
->ia_mode
;
4869 if (valid
& ATTR_UID
)
4870 obj
->yst_uid
= attr
->ia_uid
;
4871 if (valid
& ATTR_GID
)
4872 obj
->yst_gid
= attr
->ia_gid
;
4874 if (valid
& ATTR_ATIME
)
4875 obj
->yst_atime
= Y_TIME_CONVERT(attr
->ia_atime
);
4876 if (valid
& ATTR_CTIME
)
4877 obj
->yst_ctime
= Y_TIME_CONVERT(attr
->ia_ctime
);
4878 if (valid
& ATTR_MTIME
)
4879 obj
->yst_mtime
= Y_TIME_CONVERT(attr
->ia_mtime
);
4881 if (valid
& ATTR_SIZE
)
4882 yaffs_resize_file(obj
, attr
->ia_size
);
4884 yaffs_update_oh(obj
, NULL
, 1, 0, 0, NULL
);
4889 int yaffs_get_attribs(yaffs_obj_t
*obj
, struct iattr
*attr
)
4891 unsigned int valid
= 0;
4893 attr
->ia_mode
= obj
->yst_mode
;
4895 attr
->ia_uid
= obj
->yst_uid
;
4897 attr
->ia_gid
= obj
->yst_gid
;
4900 Y_TIME_CONVERT(attr
->ia_atime
) = obj
->yst_atime
;
4901 valid
|= ATTR_ATIME
;
4902 Y_TIME_CONVERT(attr
->ia_ctime
) = obj
->yst_ctime
;
4903 valid
|= ATTR_CTIME
;
4904 Y_TIME_CONVERT(attr
->ia_mtime
) = obj
->yst_mtime
;
4905 valid
|= ATTR_MTIME
;
4907 attr
->ia_size
= yaffs_get_file_size(obj
);
4910 attr
->ia_valid
= valid
;
4918 static int yaffs_do_xattrib_mod(yaffs_obj_t
*obj
, int set
, const YCHAR
*name
, const void *value
, int size
, int flags
)
4920 yaffs_xattr_mod xmod
;
4929 xmod
.result
= -ENOSPC
;
4931 result
= yaffs_update_oh(obj
, NULL
, 0, 0, 0, &xmod
);
4939 static int yaffs_apply_xattrib_mod(yaffs_obj_t
*obj
, char *buffer
, yaffs_xattr_mod
*xmod
)
4942 int x_offs
= sizeof(yaffs_obj_header
);
4943 yaffs_dev_t
*dev
= obj
->my_dev
;
4944 int x_size
= dev
->data_bytes_per_chunk
- sizeof(yaffs_obj_header
);
4946 char * x_buffer
= buffer
+ x_offs
;
4949 retval
= nval_set(x_buffer
, x_size
, xmod
->name
, xmod
->data
, xmod
->size
, xmod
->flags
);
4951 retval
= nval_del(x_buffer
, x_size
, xmod
->name
);
4953 obj
->has_xattr
= nval_hasvalues(x_buffer
, x_size
);
4954 obj
->xattr_known
= 1;
4956 xmod
->result
= retval
;
4961 static int yaffs_do_xattrib_fetch(yaffs_obj_t
*obj
, const YCHAR
*name
, void *value
, int size
)
4963 char *buffer
= NULL
;
4965 yaffs_ext_tags tags
;
4966 yaffs_dev_t
*dev
= obj
->my_dev
;
4967 int x_offs
= sizeof(yaffs_obj_header
);
4968 int x_size
= dev
->data_bytes_per_chunk
- sizeof(yaffs_obj_header
);
4974 if(obj
->hdr_chunk
< 1)
4977 /* If we know that the object has no xattribs then don't do all the
4978 * reading and parsing.
4980 if(obj
->xattr_known
&& !obj
->has_xattr
){
4987 buffer
= (char *) yaffs_get_temp_buffer(dev
, __LINE__
);
4991 result
= yaffs_rd_chunk_tags_nand(dev
,obj
->hdr_chunk
, (__u8
*)buffer
, &tags
);
4993 if(result
!= YAFFS_OK
)
4996 x_buffer
= buffer
+ x_offs
;
4998 if (!obj
->xattr_known
){
4999 obj
->has_xattr
= nval_hasvalues(x_buffer
, x_size
);
5000 obj
->xattr_known
= 1;
5004 retval
= nval_get(x_buffer
, x_size
, name
, value
, size
);
5006 retval
= nval_list(x_buffer
, x_size
, value
,size
);
5008 yaffs_release_temp_buffer(dev
,(__u8
*)buffer
,__LINE__
);
5012 int yaffs_set_xattrib(yaffs_obj_t
*obj
, const YCHAR
*name
, const void * value
, int size
, int flags
)
5014 return yaffs_do_xattrib_mod(obj
, 1, name
, value
, size
, flags
);
5017 int yaffs_remove_xattrib(yaffs_obj_t
*obj
, const YCHAR
*name
)
5019 return yaffs_do_xattrib_mod(obj
, 0, name
, NULL
, 0, 0);
5022 int yaffs_get_xattrib(yaffs_obj_t
*obj
, const YCHAR
*name
, void *value
, int size
)
5024 return yaffs_do_xattrib_fetch(obj
, name
, value
, size
);
5027 int yaffs_list_xattrib(yaffs_obj_t
*obj
, char *buffer
, int size
)
5029 return yaffs_do_xattrib_fetch(obj
, NULL
, buffer
,size
);
5035 int yaffs_dump_obj(yaffs_obj_t
*obj
)
5039 yaffs_get_obj_name(obj
, name
, YAFFS_MAX_NAME_LENGTH
+ 1);
5041 T(YAFFS_TRACE_ALWAYS
,
5043 ("Object %d, inode %d \"%s\"\n dirty %d valid %d serial %d sum %d"
5044 " chunk %d type %d size %d\n"
5045 TENDSTR
), obj
->obj_id
, yaffs_get_obj_inode(obj
), name
,
5046 obj
->dirty
, obj
->valid
, obj
->serial
, obj
->sum
, obj
->hdr_chunk
,
5047 yaffs_get_obj_type(obj
), yaffs_get_obj_length(obj
)));
5053 /*---------------------------- Initialisation code -------------------------------------- */
5055 static int yaffs_cehck_dev_fns(const yaffs_dev_t
*dev
)
5058 /* Common functions, gotta have */
5059 if (!dev
->param
.erase_fn
|| !dev
->param
.initialise_flash_fn
)
5062 #ifdef CONFIG_YAFFS_YAFFS2
5064 /* Can use the "with tags" style interface for yaffs1 or yaffs2 */
5065 if (dev
->param
.write_chunk_tags_fn
&&
5066 dev
->param
.read_chunk_tags_fn
&&
5067 !dev
->param
.write_chunk_fn
&&
5068 !dev
->param
.read_chunk_fn
&&
5069 dev
->param
.bad_block_fn
&&
5070 dev
->param
.query_block_fn
)
5074 /* Can use the "spare" style interface for yaffs1 */
5075 if (!dev
->param
.is_yaffs2
&&
5076 !dev
->param
.write_chunk_tags_fn
&&
5077 !dev
->param
.read_chunk_tags_fn
&&
5078 dev
->param
.write_chunk_fn
&&
5079 dev
->param
.read_chunk_fn
&&
5080 !dev
->param
.bad_block_fn
&&
5081 !dev
->param
.query_block_fn
)
5088 static int yaffs_create_initial_dir(yaffs_dev_t
*dev
)
5090 /* Initialise the unlinked, deleted, root and lost and found directories */
5092 dev
->lost_n_found
= dev
->root_dir
= NULL
;
5093 dev
->unlinked_dir
= dev
->del_dir
= NULL
;
5096 yaffs_create_fake_dir(dev
, YAFFS_OBJECTID_UNLINKED
, S_IFDIR
);
5099 yaffs_create_fake_dir(dev
, YAFFS_OBJECTID_DELETED
, S_IFDIR
);
5102 yaffs_create_fake_dir(dev
, YAFFS_OBJECTID_ROOT
,
5103 YAFFS_ROOT_MODE
| S_IFDIR
);
5105 yaffs_create_fake_dir(dev
, YAFFS_OBJECTID_LOSTNFOUND
,
5106 YAFFS_LOSTNFOUND_MODE
| S_IFDIR
);
5108 if (dev
->lost_n_found
&& dev
->root_dir
&& dev
->unlinked_dir
&& dev
->del_dir
) {
5109 yaffs_add_obj_to_dir(dev
->root_dir
, dev
->lost_n_found
);
5116 int yaffs_guts_initialise(yaffs_dev_t
*dev
)
5118 int init_failed
= 0;
5122 T(YAFFS_TRACE_TRACING
, (TSTR("yaffs: yaffs_guts_initialise()" TENDSTR
)));
5124 /* Check stuff that must be set */
5127 T(YAFFS_TRACE_ALWAYS
, (TSTR("yaffs: Need a device" TENDSTR
)));
5131 dev
->internal_start_block
= dev
->param
.start_block
;
5132 dev
->internal_end_block
= dev
->param
.end_block
;
5133 dev
->block_offset
= 0;
5134 dev
->chunk_offset
= 0;
5135 dev
->n_free_chunks
= 0;
5139 if (dev
->param
.start_block
== 0) {
5140 dev
->internal_start_block
= dev
->param
.start_block
+ 1;
5141 dev
->internal_end_block
= dev
->param
.end_block
+ 1;
5142 dev
->block_offset
= 1;
5143 dev
->chunk_offset
= dev
->param
.chunks_per_block
;
5146 /* Check geometry parameters. */
5148 if ((!dev
->param
.inband_tags
&& dev
->param
.is_yaffs2
&& dev
->param
.total_bytes_per_chunk
< 1024) ||
5149 (!dev
->param
.is_yaffs2
&& dev
->param
.total_bytes_per_chunk
< 512) ||
5150 (dev
->param
.inband_tags
&& !dev
->param
.is_yaffs2
) ||
5151 dev
->param
.chunks_per_block
< 2 ||
5152 dev
->param
.n_reserved_blocks
< 2 ||
5153 dev
->internal_start_block
<= 0 ||
5154 dev
->internal_end_block
<= 0 ||
5155 dev
->internal_end_block
<= (dev
->internal_start_block
+ dev
->param
.n_reserved_blocks
+ 2)) { /* otherwise it is too small */
5156 T(YAFFS_TRACE_ALWAYS
,
5158 ("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s, inband_tags %d "
5159 TENDSTR
), dev
->param
.total_bytes_per_chunk
, dev
->param
.is_yaffs2
? "2" : "", dev
->param
.inband_tags
));
5163 if (yaffs_init_nand(dev
) != YAFFS_OK
) {
5164 T(YAFFS_TRACE_ALWAYS
,
5165 (TSTR("yaffs: InitialiseNAND failed" TENDSTR
)));
5169 /* Sort out space for inband tags, if required */
5170 if (dev
->param
.inband_tags
)
5171 dev
->data_bytes_per_chunk
= dev
->param
.total_bytes_per_chunk
- sizeof(yaffs_PackedTags2TagsPart
);
5173 dev
->data_bytes_per_chunk
= dev
->param
.total_bytes_per_chunk
;
5175 /* Got the right mix of functions? */
5176 if (!yaffs_cehck_dev_fns(dev
)) {
5177 /* Function missing */
5178 T(YAFFS_TRACE_ALWAYS
,
5180 ("yaffs: device function(s) missing or wrong\n" TENDSTR
)));
5185 /* This is really a compilation check. */
5186 if (!yaffs_check_structures()) {
5187 T(YAFFS_TRACE_ALWAYS
,
5188 (TSTR("yaffs_check_structures failed\n" TENDSTR
)));
5192 if (dev
->is_mounted
) {
5193 T(YAFFS_TRACE_ALWAYS
,
5194 (TSTR("yaffs: device already mounted\n" TENDSTR
)));
5198 /* Finished with most checks. One or two more checks happen later on too. */
5200 dev
->is_mounted
= 1;
5202 /* OK now calculate a few things for the device */
5205 * Calculate all the chunk size manipulation numbers:
5207 x
= dev
->data_bytes_per_chunk
;
5208 /* We always use dev->chunk_shift and dev->chunk_div */
5209 dev
->chunk_shift
= Shifts(x
);
5210 x
>>= dev
->chunk_shift
;
5212 /* We only use chunk mask if chunk_div is 1 */
5213 dev
->chunk_mask
= (1<<dev
->chunk_shift
) - 1;
5216 * Calculate chunk_grp_bits.
5217 * We need to find the next power of 2 > than internal_end_block
5220 x
= dev
->param
.chunks_per_block
* (dev
->internal_end_block
+ 1);
5224 /* Set up tnode width if wide tnodes are enabled. */
5225 if (!dev
->param
.wide_tnodes_disabled
) {
5226 /* bits must be even so that we end up with 32-bit words */
5230 dev
->tnode_width
= 16;
5232 dev
->tnode_width
= bits
;
5234 dev
->tnode_width
= 16;
5236 dev
->tnode_mask
= (1<<dev
->tnode_width
)-1;
5238 /* Level0 Tnodes are 16 bits or wider (if wide tnodes are enabled),
5239 * so if the bitwidth of the
5240 * chunk range we're using is greater than 16 we need
5241 * to figure out chunk shift and chunk_grp_size
5244 if (bits
<= dev
->tnode_width
)
5245 dev
->chunk_grp_bits
= 0;
5247 dev
->chunk_grp_bits
= bits
- dev
->tnode_width
;
5249 dev
->tnode_size
= (dev
->tnode_width
* YAFFS_NTNODES_LEVEL0
)/8;
5250 if(dev
->tnode_size
< sizeof(yaffs_tnode_t
))
5251 dev
->tnode_size
= sizeof(yaffs_tnode_t
);
5253 dev
->chunk_grp_size
= 1 << dev
->chunk_grp_bits
;
5255 if (dev
->param
.chunks_per_block
< dev
->chunk_grp_size
) {
5256 /* We have a problem because the soft delete won't work if
5257 * the chunk group size > chunks per block.
5258 * This can be remedied by using larger "virtual blocks".
5260 T(YAFFS_TRACE_ALWAYS
,
5261 (TSTR("yaffs: chunk group too large\n" TENDSTR
)));
5266 /* OK, we've finished verifying the device, lets continue with initialisation */
5268 /* More device initialisation */
5270 dev
->passive_gc_count
= 0;
5271 dev
->oldest_dirty_gc_count
= 0;
5273 dev
->gc_block_finder
= 0;
5274 dev
->buffered_block
= -1;
5275 dev
->doing_buffered_block_rewrite
= 0;
5276 dev
->n_deleted_files
= 0;
5277 dev
->n_bg_deletions
= 0;
5278 dev
->n_unlinked_files
= 0;
5279 dev
->n_ecc_fixed
= 0;
5280 dev
->n_ecc_unfixed
= 0;
5281 dev
->n_tags_ecc_fixed
= 0;
5282 dev
->n_tags_ecc_unfixed
= 0;
5283 dev
->n_erase_failures
= 0;
5284 dev
->n_erased_blocks
= 0;
5286 dev
->has_pending_prioritised_gc
= 1; /* Assume the worst for now, will get fixed on first GC */
5287 YINIT_LIST_HEAD(&dev
->dirty_dirs
);
5288 dev
->oldest_dirty_seq
= 0;
5289 dev
->oldest_dirty_block
= 0;
5291 /* Initialise temporary buffers and caches. */
5292 if (!yaffs_init_tmp_buffers(dev
))
5296 dev
->gc_cleanup_list
= NULL
;
5300 dev
->param
.n_caches
> 0) {
5303 int cacheBytes
= dev
->param
.n_caches
* sizeof(yaffs_cache_t
);
5305 if (dev
->param
.n_caches
> YAFFS_MAX_SHORT_OP_CACHES
)
5306 dev
->param
.n_caches
= YAFFS_MAX_SHORT_OP_CACHES
;
5308 dev
->cache
= YMALLOC(cacheBytes
);
5310 buf
= (__u8
*) dev
->cache
;
5313 memset(dev
->cache
, 0, cacheBytes
);
5315 for (i
= 0; i
< dev
->param
.n_caches
&& buf
; i
++) {
5316 dev
->cache
[i
].object
= NULL
;
5317 dev
->cache
[i
].last_use
= 0;
5318 dev
->cache
[i
].dirty
= 0;
5319 dev
->cache
[i
].data
= buf
= YMALLOC_DMA(dev
->param
.total_bytes_per_chunk
);
5324 dev
->cache_last_use
= 0;
5327 dev
->cache_hits
= 0;
5330 dev
->gc_cleanup_list
= YMALLOC(dev
->param
.chunks_per_block
* sizeof(__u32
));
5331 if (!dev
->gc_cleanup_list
)
5335 if (dev
->param
.is_yaffs2
)
5336 dev
->param
.use_header_file_size
= 1;
5338 if (!init_failed
&& !yaffs_init_blocks(dev
))
5341 yaffs_init_tnodes_and_objs(dev
);
5343 if (!init_failed
&& !yaffs_create_initial_dir(dev
))
5348 /* Now scan the flash. */
5349 if (dev
->param
.is_yaffs2
) {
5350 if (yaffs2_checkpt_restore(dev
)) {
5351 yaffs_check_obj_details_loaded(dev
->root_dir
);
5352 T(YAFFS_TRACE_ALWAYS
,
5353 (TSTR("yaffs: restored from checkpoint" TENDSTR
)));
5356 /* Clean up the mess caused by an aborted checkpoint load
5357 * and scan backwards.
5359 yaffs_deinit_blocks(dev
);
5361 yaffs_deinit_tnodes_and_objs(dev
);
5363 dev
->n_erased_blocks
= 0;
5364 dev
->n_free_chunks
= 0;
5365 dev
->alloc_block
= -1;
5366 dev
->alloc_page
= -1;
5367 dev
->n_deleted_files
= 0;
5368 dev
->n_unlinked_files
= 0;
5369 dev
->n_bg_deletions
= 0;
5371 if (!init_failed
&& !yaffs_init_blocks(dev
))
5374 yaffs_init_tnodes_and_objs(dev
);
5376 if (!init_failed
&& !yaffs_create_initial_dir(dev
))
5379 if (!init_failed
&& !yaffs2_scan_backwards(dev
))
5382 } else if (!yaffs1_scan(dev
))
5385 yaffs_strip_deleted_objs(dev
);
5386 yaffs_fix_hanging_objs(dev
);
5387 if(dev
->param
.empty_lost_n_found
)
5388 yaffs_empty_l_n_f(dev
);
5392 /* Clean up the mess */
5393 T(YAFFS_TRACE_TRACING
,
5394 (TSTR("yaffs: yaffs_guts_initialise() aborted.\n" TENDSTR
)));
5396 yaffs_deinitialise(dev
);
5400 /* Zero out stats */
5401 dev
->n_page_reads
= 0;
5402 dev
->n_page_writes
= 0;
5403 dev
->n_erasures
= 0;
5404 dev
->n_gc_copies
= 0;
5405 dev
->n_retired_writes
= 0;
5407 dev
->n_retired_blocks
= 0;
5409 yaffs_verify_free_chunks(dev
);
5410 yaffs_verify_blocks(dev
);
5412 /* Clean up any aborted checkpoint data */
5413 if(!dev
->is_checkpointed
&& dev
->blocks_in_checkpt
> 0)
5414 yaffs2_checkpt_invalidate(dev
);
5416 T(YAFFS_TRACE_TRACING
,
5417 (TSTR("yaffs: yaffs_guts_initialise() done.\n" TENDSTR
)));
5422 void yaffs_deinitialise(yaffs_dev_t
*dev
)
5424 if (dev
->is_mounted
) {
5427 yaffs_deinit_blocks(dev
);
5428 yaffs_deinit_tnodes_and_objs(dev
);
5429 if (dev
->param
.n_caches
> 0 &&
5432 for (i
= 0; i
< dev
->param
.n_caches
; i
++) {
5433 if (dev
->cache
[i
].data
)
5434 YFREE(dev
->cache
[i
].data
);
5435 dev
->cache
[i
].data
= NULL
;
5442 YFREE(dev
->gc_cleanup_list
);
5444 for (i
= 0; i
< YAFFS_N_TEMP_BUFFERS
; i
++)
5445 YFREE(dev
->temp_buffer
[i
].buffer
);
5447 dev
->is_mounted
= 0;
5449 if (dev
->param
.deinitialise_flash_fn
)
5450 dev
->param
.deinitialise_flash_fn(dev
);
5454 int yaffs_count_free_chunks(yaffs_dev_t
*dev
)
5459 yaffs_block_info_t
*blk
;
5461 blk
= dev
->block_info
;
5462 for (b
= dev
->internal_start_block
; b
<= dev
->internal_end_block
; b
++) {
5463 switch (blk
->block_state
) {
5464 case YAFFS_BLOCK_STATE_EMPTY
:
5465 case YAFFS_BLOCK_STATE_ALLOCATING
:
5466 case YAFFS_BLOCK_STATE_COLLECTING
:
5467 case YAFFS_BLOCK_STATE_FULL
:
5469 (dev
->param
.chunks_per_block
- blk
->pages_in_use
+
5470 blk
->soft_del_pages
);
5481 int yaffs_get_n_free_chunks(yaffs_dev_t
*dev
)
5483 /* This is what we report to the outside world */
5486 int nDirtyCacheChunks
;
5487 int blocksForCheckpoint
;
5491 nFree
= dev
->n_free_chunks
;
5493 nFree
= yaffs_count_free_chunks(dev
);
5496 nFree
+= dev
->n_deleted_files
;
5498 /* Now count the number of dirty chunks in the cache and subtract those */
5500 for (nDirtyCacheChunks
= 0, i
= 0; i
< dev
->param
.n_caches
; i
++) {
5501 if (dev
->cache
[i
].dirty
)
5502 nDirtyCacheChunks
++;
5505 nFree
-= nDirtyCacheChunks
;
5507 nFree
-= ((dev
->param
.n_reserved_blocks
+ 1) * dev
->param
.chunks_per_block
);
5509 /* Now we figure out how much to reserve for the checkpoint and report that... */
5510 blocksForCheckpoint
= yaffs_calc_checkpt_blocks_required(dev
);
5512 nFree
-= (blocksForCheckpoint
* dev
->param
.chunks_per_block
);
5522 /*---------------------------------------- YAFFS test code ----------------------*/
5524 #define yaffs_check_struct(structure, syze, name) \
5526 if (sizeof(structure) != syze) { \
5527 T(YAFFS_TRACE_ALWAYS, (TSTR("%s should be %d but is %d\n" TENDSTR),\
5528 name, syze, (int) sizeof(structure))); \
5529 return YAFFS_FAIL; \
5533 static int yaffs_check_structures(void)
5535 /* yaffs_check_struct(yaffs_tags_t,8,"yaffs_tags_t"); */
5536 /* yaffs_check_struct(yaffs_tags_union_t,8,"yaffs_tags_union_t"); */
5537 /* yaffs_check_struct(yaffs_spare,16,"yaffs_spare"); */
5538 /* yaffs_check_struct(yaffs_tnode_t, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_tnode_t"); */
5540 #ifndef CONFIG_YAFFS_WINCE
5541 yaffs_check_struct(yaffs_obj_header
, 512, "yaffs_obj_header");