-
Notifications
You must be signed in to change notification settings - Fork 0
/
yaffs_guts.c
6651 lines (5705 loc) · 211 KB
/
yaffs_guts.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2018 Aleph One Ltd.
*
* Created by Charles Manning <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "yportenv.h"
#include "yaffs_trace.h"
#include "yaffs_guts.h"
#include "yaffs_endian.h"
#include "yaffs_getblockinfo.h"
#include "yaffs_tagscompat.h"
#include "yaffs_tagsmarshall.h"
#include "yaffs_nand.h"
#include "yaffs_yaffs1.h"
#include "yaffs_yaffs2.h"
#include "yaffs_bitmap.h"
#include "yaffs_verify.h"
#include "yaffs_nand.h"
#include "yaffs_packedtags2.h"
#include "yaffs_nameval.h"
#include "yaffs_allocator.h"
#include "yaffs_attribs.h"
#include "yaffs_summary.h"
/* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */
#define YAFFS_GC_GOOD_ENOUGH 2
#define YAFFS_GC_PASSIVE_THRESHOLD 4
#include "yaffs_ecc.h"
/* Forward declarations */
static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk,
const u8 *buffer, int n_bytes, int use_reserve);
static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR *name,
int buffer_size);
/* Function to calculate chunk and offset */
/*********************************************************************************************************
** 函数名称: yaffs_addr_to_chunk
** 功能描述: 把文件内的地址偏移量转换成逻辑 chunk(inode_chunk) 以及在逻辑 chunk 内的偏移
** 输 入: dev - yaffs 设备
** : addr - 文件内偏移地址,从零开始
** 输 出: chunk_out - addr 对应文件的 inode_chunk 值
** : offset_out - addr 在文件第 inode_chunk 内的偏移量
** 全局变量:
** 调用模块:
*********************************************************************************************************/
void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr,
int *chunk_out, u32 *offset_out)
{
int chunk;
u32 offset;
chunk = (u32) (addr >> dev->chunk_shift);
if (dev->chunk_div == 1) {
/* easy power of 2 case */
offset = (u32) (addr & dev->chunk_mask);
} else {
/* Non power-of-2 case */
loff_t chunk_base;
chunk /= dev->chunk_div;
chunk_base = ((loff_t) chunk) * dev->data_bytes_per_chunk;
offset = (u32) (addr - chunk_base);
}
*chunk_out = chunk;
*offset_out = offset;
}
/* Function to return the number of shifts for a power of 2 greater than or
* equal to the given number
* Note we don't try to cater for all possible numbers and this does not have to
* be hellishly efficient.
*/
/*********************************************************************************************************
** 函数名称: calc_shifts_ceiling
** 功能描述: 计算出当前设备最大 nand_chunk 最少需要多少 bit 表示
** 输 入: x - 当前设备会出现的最大 nand_chunk 值
** 输 出: shifts - 表示 x 需要的最少 bit 数
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static inline u32 calc_shifts_ceiling(u32 x)
{
int extra_bits;
int shifts;
shifts = extra_bits = 0;
while (x > 1) {
if (x & 1)
extra_bits++;
x >>= 1;
shifts++;
}
if (extra_bits)
shifts++;
return shifts;
}
/* Function to return the number of shifts to get a 1 in bit 0
*/
/*********************************************************************************************************
** 函数名称: calc_shifts
** 功能描述: 计算每个 nand_chunk 存储的数据字节数、bit0 向高位开始一共有多少个连续的 0,例如每个
** : nand_chunk 存储了 10100000 个字节数据,那么计算的返回值是 5
** 输 入: x - 每个 nand_chunk 存储的数据字节数
** 输 出: shifts - 每个 nand_chunk 存储数据字节数值在低位连续 0 的个数
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static inline u32 calc_shifts(u32 x)
{
u32 shifts;
shifts = 0;
if (!x)
return 0;
while (!(x & 1)) {
x >>= 1;
shifts++;
}
return shifts;
}
/*
* Temporary buffer manipulations.
*/
/*********************************************************************************************************
** 函数名称: yaffs_init_tmp_buffers
** 功能描述: 初始化 yaffs 设备临时数据缓冲区,每个缓冲空间可存储一个 chunk 数据,默认申请 6 个缓冲空间
** 输 入: dev - 需要初始化临时数据缓冲区的 yaffs 设备
** 输 出: YAFFS_OK - 初始化成功
** : YAFFS_FAIL - 初始化失败
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static int yaffs_init_tmp_buffers(struct yaffs_dev *dev)
{
int i;
u8 *buf = (u8 *) 1;
memset(dev->temp_buffer, 0, sizeof(dev->temp_buffer));
for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) {
dev->temp_buffer[i].in_use = 0;
buf = kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
dev->temp_buffer[i].buffer = buf;
}
return buf ? YAFFS_OK : YAFFS_FAIL;
}
/*********************************************************************************************************
** 函数名称: yaffs_get_temp_buffer
** 功能描述: 获取一个 yaffs 设备临时数据缓冲区空间,如果没有可用缓冲区,则重新创建一个
** 输 入: dev - yaffs 设备
** 输 出: 申请到的临时数据缓冲区空间地址
** 全局变量:
** 调用模块:
*********************************************************************************************************/
u8 *yaffs_get_temp_buffer(struct yaffs_dev * dev)
{
int i;
dev->temp_in_use++;
if (dev->temp_in_use > dev->max_temp)
dev->max_temp = dev->temp_in_use;
for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
if (dev->temp_buffer[i].in_use == 0) {
dev->temp_buffer[i].in_use = 1;
return dev->temp_buffer[i].buffer;
}
}
yaffs_trace(YAFFS_TRACE_BUFFERS, "Out of temp buffers");
/*
* If we got here then we have to allocate an unmanaged one
* This is not good.
*/
dev->unmanaged_buffer_allocs++;
return kmalloc(dev->data_bytes_per_chunk, GFP_NOFS);
}
/*********************************************************************************************************
** 函数名称: yaffs_release_temp_buffer
** 功能描述: 释放一个 yaffs 设备临时数据缓冲区空间,如果需要释放的缓冲区在设备默认缓冲区中,则通过清除标志
** : 变量回收即可,如果需要释放的缓冲区是通过 kmalloc 额外申请的,则需要通过 kfree 释放
** 输 入: dev - yaffs 设备
** 输 出: 需要释放的临时数据缓冲区空间地址
** 全局变量:
** 调用模块:
*********************************************************************************************************/
void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer)
{
int i;
dev->temp_in_use--;
for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
if (dev->temp_buffer[i].buffer == buffer) {
dev->temp_buffer[i].in_use = 0;
return;
}
}
if (buffer) {
/* assume it is an unmanaged one. */
yaffs_trace(YAFFS_TRACE_BUFFERS,
"Releasing unmanaged temp buffer");
kfree(buffer);
dev->unmanaged_buffer_deallocs++;
}
}
/*
* Functions for robustisizing TODO
*
*/
/*********************************************************************************************************
** 函数名称: yaffs_handle_chunk_wr_ok
** 功能描述: 在 nand_chunk 成功时调用的钩子函数
** 输 入: dev - yaffs 设备
** : nand_chunk - 物理空间上的 chunk 值
** : data - 需要写入 nand_chunk 的数据
** : tags - 需要写入 nand_chunk 的 tag 信息
** 输 出:
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static void yaffs_handle_chunk_wr_ok(struct yaffs_dev *dev, int nand_chunk,
const u8 *data,
const struct yaffs_ext_tags *tags)
{
(void) dev;
(void) nand_chunk;
(void) data;
(void) tags;
}
/*********************************************************************************************************
** 函数名称: yaffs_handle_chunk_update
** 功能描述: 在更新 nand_chunk 成功时调用的钩子函数
** 输 入: dev - yaffs 设备
** : nand_chunk - 物理空间上的 chunk 值
** : tags - 需要写入 nand_chunk 的 tag 信息
** 输 出:
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static void yaffs_handle_chunk_update(struct yaffs_dev *dev, int nand_chunk,
const struct yaffs_ext_tags *tags)
{
(void) dev;
(void) nand_chunk;
(void) tags;
}
/*********************************************************************************************************
** 函数名称: yaffs_handle_chunk_error
** 功能描述: 在读写 nand_chunk 出现错误时需要调用的钩子函数
** 输 入: dev - yaffs 设备
** : bi - 读写失败的 nand_chunk 所在块的 block info
** 输 出:
** 全局变量:
** 调用模块:
*********************************************************************************************************/
void yaffs_handle_chunk_error(struct yaffs_dev *dev,
struct yaffs_block_info *bi)
{
if (!bi->gc_prioritise) {
bi->gc_prioritise = 1;
dev->has_pending_prioritised_gc = 1;
bi->chunk_error_strikes++;
if (bi->chunk_error_strikes > 3) {
bi->needs_retiring = 1; /* Too many stikes, so retire */
yaffs_trace(YAFFS_TRACE_ALWAYS,
"yaffs: Block struck out");
}
}
}
/*********************************************************************************************************
** 函数名称: yaffs_handle_chunk_wr_error
** 功能描述: 在写 nand_chunk 出现错误时需要调用的钩子函数
** 输 入: dev - yaffs 设备
** : nand_chunk - 物理空间上的 chunk 值
** : erased_ok - nand_chunk 擦除是否成功
** 输 出:
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static void yaffs_handle_chunk_wr_error(struct yaffs_dev *dev, int nand_chunk,
int erased_ok)
{
int flash_block = nand_chunk / dev->param.chunks_per_block;
struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block);
yaffs_handle_chunk_error(dev, bi);
if (erased_ok) {
/* Was an actual write failure,
* so mark the block for retirement.*/
bi->needs_retiring = 1;
yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
"**>> Block %d needs retiring", flash_block);
}
/* Delete the chunk */
yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
yaffs_skip_rest_of_block(dev);
}
/*
* Verification code
*/
/*
* Simple hash function. Needs to have a reasonable spread
*/
/*********************************************************************************************************
** 函数名称: yaffs_hash_fn
** 功能描述: 计算 obj_id 对应的 obj_bucket 数组下标
** 输 入: n - obj_id
** 输 出: obj_id 需要放在 obj_bucket 数组中的位置
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static inline int yaffs_hash_fn(int n)
{
if (n < 0)
n = -n;
return n % YAFFS_NOBJECT_BUCKETS;
}
/*
* Access functions to useful fake objects.
* Note that root might have a presence in NAND if permissions are set.
*/
/*********************************************************************************************************
** 函数名称: yaffs_root
** 功能描述: 获取当前 yaffs 设备的根目录信息
** 输 入: dev - yaffs 设备
** 输 出: 当前 yaffs 设备的根目录信息
** 全局变量:
** 调用模块:
*********************************************************************************************************/
struct yaffs_obj *yaffs_root(struct yaffs_dev *dev)
{
return dev->root_dir;
}
/*********************************************************************************************************
** 函数名称: yaffs_lost_n_found
** 功能描述: 获取当前 yaffs 设备的 lost_n_found 信息
** 输 入: dev - yaffs 设备
** 输 出: 当前 yaffs 设备的 lost_n_found 信息
** 全局变量:
** 调用模块:
*********************************************************************************************************/
struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev)
{
return dev->lost_n_found;
}
/*
* Erased NAND checking functions
*/
/*********************************************************************************************************
** 函数名称: yaffs_check_ff
** 功能描述: 校验输入缓冲区中的数据是否全是 0xFF
** 输 入: buffer - 需要校验的数据缓冲区
** : n_bytes - 需要校验的数据长度
** 输 出: 0 - 数据缓冲区不全是 0xFF
** : 1 - 数据缓冲区全是 0xFF
** 全局变量:
** 调用模块:
*********************************************************************************************************/
int yaffs_check_ff(u8 *buffer, int n_bytes)
{
/* Horrible, slow implementation */
while (n_bytes--) {
if (*buffer != 0xff)
return 0;
buffer++;
}
return 1;
}
/*********************************************************************************************************
** 函数名称: yaffs_check_chunk_erased
** 功能描述: 校验指定 nand_chunk 是否擦除成功,包括数据部分校验和 tags 中 ecc 校验
** 输 入: dev - yaffs 设备
** : nand_chunk - 物理空间上的 chunk 值
** 输 出: YAFFS_OK - 校验成功
** : YAFFS_FAIL - 校验失败
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static int yaffs_check_chunk_erased(struct yaffs_dev *dev, int nand_chunk)
{
int retval = YAFFS_OK;
u8 *data = yaffs_get_temp_buffer(dev);
struct yaffs_ext_tags tags;
int result;
result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, data, &tags);
if (result == YAFFS_FAIL ||
tags.ecc_result > YAFFS_ECC_RESULT_NO_ERROR)
retval = YAFFS_FAIL;
if (!yaffs_check_ff(data, dev->data_bytes_per_chunk) ||
tags.chunk_used) {
yaffs_trace(YAFFS_TRACE_NANDACCESS,
"Chunk %d not erased", nand_chunk);
retval = YAFFS_FAIL;
}
yaffs_release_temp_buffer(dev, data);
return retval;
}
/*********************************************************************************************************
** 函数名称: yaffs_verify_chunk_written
** 功能描述: 校验向指定 nand_chunk 的写入是否成功,包括数据部分校验和 tags 中 ecc 校验
** 输 入: dev - yaffs 设备
** : nand_chunk - 物理空间上的 chunk 值
** : data - 写入的数据内容
** : tags - 写入的 tags 信息
** 输 出: YAFFS_OK - 校验成功
** : YAFFS_FAIL - 校验失败
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static int yaffs_verify_chunk_written(struct yaffs_dev *dev,
int nand_chunk,
const u8 *data,
struct yaffs_ext_tags *tags)
{
int retval = YAFFS_OK;
struct yaffs_ext_tags temp_tags;
u8 *buffer = yaffs_get_temp_buffer(dev);
int result;
result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, buffer, &temp_tags);
if (result == YAFFS_FAIL ||
memcmp(buffer, data, dev->data_bytes_per_chunk) ||
temp_tags.obj_id != tags->obj_id ||
temp_tags.chunk_id != tags->chunk_id ||
temp_tags.n_bytes != tags->n_bytes)
retval = YAFFS_FAIL;
yaffs_release_temp_buffer(dev, buffer);
return retval;
}
/*********************************************************************************************************
** 函数名称: yaffs_check_alloc_available
** 功能描述: 检查当前设备是否可以申请指定个数的 nand_chunk 用于存储新数据的目的(checkpt_blocks 可以用来
** : 存储新数据)
** 输 入: dev - yaffs 设备
** : n_chunks - 想要申请的 nand_chunk 个数
** 输 出: 1 - 可以申请 n_chunks 个物理 chunk
** : 0 - 不可以申请
** 全局变量:
** 调用模块:
*********************************************************************************************************/
int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks)
{
int reserved_chunks;
int reserved_blocks = dev->param.n_reserved_blocks;
int checkpt_blocks;
checkpt_blocks = yaffs_calc_checkpt_blocks_required(dev);
reserved_chunks =
(reserved_blocks + checkpt_blocks) * dev->param.chunks_per_block;
return (dev->n_free_chunks > (reserved_chunks + n_chunks));
}
/*********************************************************************************************************
** 函数名称: yaffs_find_alloc_block
** 功能描述: 从当前设备找出一个空闲块用于存储新数据,同时把查找到的 nand_block 设置到
** : dev->alloc_block_finder 中并更新相关状态变量
** 输 入: dev - yaffs 设备
** 输 出: 查找到的 nand_block
** : -1 - 查找失败,没有可用的块
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static int yaffs_find_alloc_block(struct yaffs_dev *dev)
{
u32 i;
struct yaffs_block_info *bi;
if (dev->n_erased_blocks < 1) {
/* Hoosterman we've got a problem.
* Can't get space to gc
*/
yaffs_trace(YAFFS_TRACE_ERROR,
"yaffs tragedy: no more erased blocks");
return -1;
}
/* Find an empty block. */
for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
dev->alloc_block_finder++;
if (dev->alloc_block_finder < (int)dev->internal_start_block
|| dev->alloc_block_finder > (int)dev->internal_end_block) {
dev->alloc_block_finder = dev->internal_start_block;
}
bi = yaffs_get_block_info(dev, dev->alloc_block_finder);
if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
bi->block_state = YAFFS_BLOCK_STATE_ALLOCATING;
dev->seq_number++;
bi->seq_number = dev->seq_number;
dev->n_erased_blocks--;
yaffs_trace(YAFFS_TRACE_ALLOCATE,
"Allocated block %d, seq %d, %d left" ,
dev->alloc_block_finder, dev->seq_number,
dev->n_erased_blocks);
return dev->alloc_block_finder;
}
}
yaffs_trace(YAFFS_TRACE_ALWAYS,
"yaffs tragedy: no more erased blocks, but there should have been %d",
dev->n_erased_blocks);
return -1;
}
/*********************************************************************************************************
** 函数名称: yaffs_alloc_chunk
** 功能描述: 从当前设备中申请一个可用的 nand_chunk 并更新相关状态变量
** 输 入: dev - yaffs 设备
** : use_reserver - 是否可以使用 reserve 空间(reserve 空间用于垃圾回收)
** 输 出: 查找到的 nand_chunk 值
** : block_ptr - nand_chunk 所在块的块信息
** : -1 - 查找失败,没有可用的块
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static int yaffs_alloc_chunk(struct yaffs_dev *dev, int use_reserver,
struct yaffs_block_info **block_ptr)
{
int ret_val;
struct yaffs_block_info *bi;
if (dev->alloc_block < 0) {
/* Get next block to allocate off */
dev->alloc_block = yaffs_find_alloc_block(dev);
dev->alloc_page = 0;
}
if (!use_reserver && !yaffs_check_alloc_available(dev, 1)) {
/* No space unless we're allowed to use the reserve. */
return -1;
}
if (dev->n_erased_blocks < (int)dev->param.n_reserved_blocks
&& dev->alloc_page == 0)
yaffs_trace(YAFFS_TRACE_ALLOCATE, "Allocating reserve");
/* Next page please.... */
if (dev->alloc_block >= 0) {
bi = yaffs_get_block_info(dev, dev->alloc_block);
ret_val = (dev->alloc_block * dev->param.chunks_per_block) +
dev->alloc_page;
bi->pages_in_use++;
yaffs_set_chunk_bit(dev, dev->alloc_block, dev->alloc_page);
dev->alloc_page++;
dev->n_free_chunks--;
/* If the block is full set the state to full */
if (dev->alloc_page >= dev->param.chunks_per_block) {
bi->block_state = YAFFS_BLOCK_STATE_FULL;
dev->alloc_block = -1;
}
if (block_ptr)
*block_ptr = bi;
return ret_val;
}
yaffs_trace(YAFFS_TRACE_ERROR,
"!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!");
return -1;
}
/*********************************************************************************************************
** 函数名称: yaffs_get_erased_chunks
** 功能描述: 获取当前设备空闲 chunk 的个数
** 输 入: dev - yaffs 设备
** 输 出: 当前设备空闲 chunk 的个数
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static int yaffs_get_erased_chunks(struct yaffs_dev *dev)
{
int n;
n = dev->n_erased_blocks * dev->param.chunks_per_block;
if (dev->alloc_block > 0)
n += (dev->param.chunks_per_block - dev->alloc_page);
return n;
}
/*
* yaffs_skip_rest_of_block() skips over the rest of the allocation block
* if we don't want to write to it.
*/
/*********************************************************************************************************
** 函数名称: yaffs_skip_rest_of_block
** 功能描述: 跳过设备当前申请块的余下 chunk 空间,如果当前申请块有效,修改其状态为“满”
** 输 入: dev - yaffs 设备
** 输 出:
** 全局变量:
** 调用模块:
*********************************************************************************************************/
void yaffs_skip_rest_of_block(struct yaffs_dev *dev)
{
struct yaffs_block_info *bi;
if (dev->alloc_block > 0) {
bi = yaffs_get_block_info(dev, dev->alloc_block);
if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) {
bi->block_state = YAFFS_BLOCK_STATE_FULL;
dev->alloc_block = -1;
}
}
}
/*********************************************************************************************************
** 函数名称: yaffs_write_new_chunk
** 功能描述: 向设备中写入一个 chunk 的数据,在写入前会检查 chunk 是否为擦除状态,在写入后会检查写入是否成功
** : 如果写入失败则尝试重新写入,重写次数为 yaffs_wr_attempts(并擦除 checkpt 数据)
** : 1. 在写数据之前,会从设备中申请一个空闲 nand_chunk 空间用来存储数据
** 输 入: dev - yaffs 设备
** : data - 需要写入的数据
** : tags - 需要写入的 tags 信息
** : use_reserver - 是否使用 reserver 空间
** 输 出: chunk - 成功写入数据的 nand_chunk 号
** : -1 - 写入失败
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static int yaffs_write_new_chunk(struct yaffs_dev *dev,
const u8 *data,
struct yaffs_ext_tags *tags, int use_reserver)
{
u32 attempts = 0;
int write_ok = 0;
int chunk;
yaffs2_checkpt_invalidate(dev);
do {
struct yaffs_block_info *bi = 0;
int erased_ok = 0;
chunk = yaffs_alloc_chunk(dev, use_reserver, &bi);
if (chunk < 0) {
/* no space */
break;
}
/* First check this chunk is erased, if it needs
* checking. The checking policy (unless forced
* always on) is as follows:
*
* Check the first page we try to write in a block.
* If the check passes then we don't need to check any
* more. If the check fails, we check again...
* If the block has been erased, we don't need to check.
*
* However, if the block has been prioritised for gc,
* then we think there might be something odd about
* this block and stop using it.
*
* Rationale: We should only ever see chunks that have
* not been erased if there was a partially written
* chunk due to power loss. This checking policy should
* catch that case with very few checks and thus save a
* lot of checks that are most likely not needed.
*
* Mods to the above
* If an erase check fails or the write fails we skip the
* rest of the block.
*/
/* let's give it a try */
attempts++;
if (dev->param.always_check_erased)
bi->skip_erased_check = 0;
if (!bi->skip_erased_check) {
erased_ok = yaffs_check_chunk_erased(dev, chunk);
if (erased_ok != YAFFS_OK) {
yaffs_trace(YAFFS_TRACE_ERROR,
"**>> yaffs chunk %d was not erased",
chunk);
/* If not erased, delete this one,
* skip rest of block and
* try another chunk */
yaffs_chunk_del(dev, chunk, 1, __LINE__);
yaffs_skip_rest_of_block(dev);
continue;
}
}
write_ok = yaffs_wr_chunk_tags_nand(dev, chunk, data, tags);
if (!bi->skip_erased_check)
write_ok =
yaffs_verify_chunk_written(dev, chunk, data, tags);
if (write_ok != YAFFS_OK) {
/* Clean up aborted write, skip to next block and
* try another chunk */
yaffs_handle_chunk_wr_error(dev, chunk, erased_ok);
continue;
}
bi->skip_erased_check = 1;
/* Copy the data into the robustification buffer */
yaffs_handle_chunk_wr_ok(dev, chunk, data, tags);
} while (write_ok != YAFFS_OK &&
(yaffs_wr_attempts == 0 || attempts <= yaffs_wr_attempts));
if (!write_ok)
chunk = -1;
if (attempts > 1) {
yaffs_trace(YAFFS_TRACE_ERROR,
"**>> yaffs write required %d attempts",
attempts);
dev->n_retried_writes += (attempts - 1);
}
return chunk;
}
/*
* Block retiring for handling a broken block.
*/
/*********************************************************************************************************
** 函数名称: yaffs_retire_block
** 功能描述: 把指定的块标志为坏块,并擦除 checkpt 数据、更新 oldest_dirty_seq,同时更新相关状态变量。
** : 现在标志坏块有两种方式:
** : 1. 通过 dev->tagger.mark_bad_fn 函数完成
** : 2. 通过设置 tags.seq_number = YAFFS_SEQUENCE_BAD_BLOCK; 并设置其他 tags 为 0 来完成
** 输 入: dev - yaffs 设备
** : flash_block - nand_block 块号
** 输 出:
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static void yaffs_retire_block(struct yaffs_dev *dev, int flash_block)
{
struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block);
yaffs2_checkpt_invalidate(dev);
yaffs2_clear_oldest_dirty_seq(dev, bi);
if (yaffs_mark_bad(dev, flash_block) != YAFFS_OK) {
if (yaffs_erase_block(dev, flash_block) != YAFFS_OK) {
yaffs_trace(YAFFS_TRACE_ALWAYS,
"yaffs: Failed to mark bad and erase block %d",
flash_block);
} else {
struct yaffs_ext_tags tags;
int chunk_id =
flash_block * dev->param.chunks_per_block;
u8 *buffer = yaffs_get_temp_buffer(dev);
memset(buffer, 0xff, dev->data_bytes_per_chunk);
memset(&tags, 0, sizeof(tags));
tags.seq_number = YAFFS_SEQUENCE_BAD_BLOCK;
if (dev->tagger.write_chunk_tags_fn(dev, chunk_id -
dev->chunk_offset,
buffer,
&tags) != YAFFS_OK)
yaffs_trace(YAFFS_TRACE_ALWAYS,
"yaffs: Failed to write bad block marker to block %d",
flash_block);
yaffs_release_temp_buffer(dev, buffer);
}
}
bi->block_state = YAFFS_BLOCK_STATE_DEAD;
bi->gc_prioritise = 0;
bi->needs_retiring = 0;
dev->n_retired_blocks++;
}
/*---------------- Name handling functions ------------*/
/*********************************************************************************************************
** 函数名称: yaffs_load_name_from_oh
** 功能描述: 复制 obj header 中的名字到指定缓冲区(如果是ASCII name,则名字数组下标 0 位置的值为 0)
** 输 入: dev - yaffs 设备
** : name - 保存 name 的缓冲区地址
** : oh_name - obj header 中的名字
** : buff_size - obj header 长度
** 输 出:
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static void yaffs_load_name_from_oh(struct yaffs_dev *dev, YCHAR *name,
const YCHAR *oh_name, int buff_size)
{
#ifdef CONFIG_YAFFS_AUTO_UNICODE
if (dev->param.auto_unicode) {
if (*oh_name) {
/* It is an ASCII name, do an ASCII to
* unicode conversion */
const char *ascii_oh_name = (const char *)oh_name;
int n = buff_size - 1;
while (n > 0 && *ascii_oh_name) {
*name = *ascii_oh_name;
name++;
ascii_oh_name++;
n--;
}
} else {
strncpy(name, oh_name + 1, buff_size - 1);
}
} else {
#else
(void) dev;
{
#endif
strncpy(name, oh_name, buff_size - 1);
}
}
/*********************************************************************************************************
** 函数名称: yaffs_load_oh_from_name
** 功能描述: 复制指定名字到 obj header 中的名字字段中
** 输 入: dev - yaffs 设备
** : oh_name - obj header 中的名字
** : name - 保存 name 的缓冲区地址
** 输 出:
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static void yaffs_load_oh_from_name(struct yaffs_dev *dev, YCHAR *oh_name,
const YCHAR *name)
{
#ifdef CONFIG_YAFFS_AUTO_UNICODE
int is_ascii;
const YCHAR *w;
if (dev->param.auto_unicode) {
is_ascii = 1;
w = name;
/* Figure out if the name will fit in ascii character set */
while (is_ascii && *w) {
if ((*w) & 0xff00)
is_ascii = 0;
w++;
}
if (is_ascii) {
/* It is an ASCII name, so convert unicode to ascii */
char *ascii_oh_name = (char *)oh_name;
int n = YAFFS_MAX_NAME_LENGTH - 1;
while (n > 0 && *name) {
*ascii_oh_name = *name;
name++;
ascii_oh_name++;
n--;
}
} else {
/* Unicode name, so save starting at the second YCHAR */
*oh_name = 0;
strncpy(oh_name + 1, name, YAFFS_MAX_NAME_LENGTH - 2);
}
} else {
#else
dev = dev;
{
#endif
strncpy(oh_name, name, YAFFS_MAX_NAME_LENGTH - 1);
}
}
/*********************************************************************************************************
** 函数名称: yaffs_calc_name_sum
** 功能描述: 计算名字的校验和,主要为了提高通过名字搜索的速度
** 输 入: name - 需要计算校验和的名字
** 输 出: sum - 计算结果
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static u16 yaffs_calc_name_sum(const YCHAR *name)
{
u16 sum = 0;
u16 i = 1;
if (!name)
return 0;
while ((*name) && i < (YAFFS_MAX_NAME_LENGTH / 2)) {
/* 0x1f mask is case insensitive */
sum += ((*name) & 0x1f) * i;
i++;
name++;
}
return sum;
}
/*********************************************************************************************************
** 函数名称: yaffs_set_obj_name
** 功能描述: 设置 obj short_name 字段的值并更新名字校验和值,如果传入的参数为空,则自动生成个系统默认名
** 输 入: obj - 想要设置名字的 object
** 输 出: name - 想要设置的名字
** 全局变量:
** 调用模块:
*********************************************************************************************************/
void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR * name)
{
memset(obj->short_name, 0, sizeof(obj->short_name));
if (name && !name[0]) {
yaffs_fix_null_name(obj, obj->short_name,
YAFFS_SHORT_NAME_LENGTH);
name = obj->short_name;
} else if (name &&
strnlen(name, YAFFS_SHORT_NAME_LENGTH + 1) <=
YAFFS_SHORT_NAME_LENGTH) {
strcpy(obj->short_name, name);
}
obj->sum = yaffs_calc_name_sum(name);