2 * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 /************************************************************************/
21 /* PROJECT : exFAT & FAT12/16/32 File System */
22 /* FILE : exfat_cache.c */
23 /* PURPOSE : exFAT Cache Manager */
24 /* (FAT Cache & Buffer Cache) */
26 /*----------------------------------------------------------------------*/
29 /*----------------------------------------------------------------------*/
30 /* REVISION HISTORY (Ver 0.9) */
32 /* - 2010.11.15 [Sung-Kwan Kim] : first writing */
34 /************************************************************************/
36 #include "exfat_config.h"
37 #include "exfat_global.h"
38 #include "exfat_data.h"
40 #include "exfat_cache.h"
41 #include "exfat_super.h"
44 /*----------------------------------------------------------------------*/
45 /* Global Variable Definitions */
46 /*----------------------------------------------------------------------*/
48 extern FS_STRUCT_T fs_struct
[];
53 static INT32
__FAT_read(struct super_block
*sb
, UINT32 loc
, UINT32
*content
);
54 static INT32
__FAT_write(struct super_block
*sb
, UINT32 loc
, UINT32 content
);
56 static BUF_CACHE_T
*FAT_cache_find(struct super_block
*sb
, UINT32 sec
);
57 static BUF_CACHE_T
*FAT_cache_get(struct super_block
*sb
, UINT32 sec
);
58 static void FAT_cache_insert_hash(struct super_block
*sb
, BUF_CACHE_T
*bp
);
59 static void FAT_cache_remove_hash(BUF_CACHE_T
*bp
);
61 static UINT8
*__buf_getblk(struct super_block
*sb
, UINT32 sec
);
63 static BUF_CACHE_T
*buf_cache_find(struct super_block
*sb
, UINT32 sec
);
64 static BUF_CACHE_T
*buf_cache_get(struct super_block
*sb
, UINT32 sec
);
65 static void buf_cache_insert_hash(struct super_block
*sb
, BUF_CACHE_T
*bp
);
66 static void buf_cache_remove_hash(BUF_CACHE_T
*bp
);
68 static void push_to_mru(BUF_CACHE_T
*bp
, BUF_CACHE_T
*list
);
69 static void push_to_lru(BUF_CACHE_T
*bp
, BUF_CACHE_T
*list
);
70 static void move_to_mru(BUF_CACHE_T
*bp
, BUF_CACHE_T
*list
);
71 static void move_to_lru(BUF_CACHE_T
*bp
, BUF_CACHE_T
*list
);
73 /*======================================================================*/
74 /* Cache Initialization Functions */
75 /*======================================================================*/
77 INT32
buf_init(struct super_block
*sb
)
79 FS_INFO_T
*p_fs
= &(EXFAT_SB(sb
)->fs_info
);
84 p_fs
->FAT_cache_lru_list
.next
= p_fs
->FAT_cache_lru_list
.prev
= &p_fs
->FAT_cache_lru_list
;
86 for (i
= 0; i
< FAT_CACHE_SIZE
; i
++) {
87 p_fs
->FAT_cache_array
[i
].drv
= -1;
88 p_fs
->FAT_cache_array
[i
].sec
= ~0;
89 p_fs
->FAT_cache_array
[i
].flag
= 0;
90 p_fs
->FAT_cache_array
[i
].buf_bh
= NULL
;
91 p_fs
->FAT_cache_array
[i
].prev
= p_fs
->FAT_cache_array
[i
].next
= NULL
;
92 push_to_mru(&(p_fs
->FAT_cache_array
[i
]), &p_fs
->FAT_cache_lru_list
);
95 p_fs
->buf_cache_lru_list
.next
= p_fs
->buf_cache_lru_list
.prev
= &p_fs
->buf_cache_lru_list
;
97 for (i
= 0; i
< BUF_CACHE_SIZE
; i
++) {
98 p_fs
->buf_cache_array
[i
].drv
= -1;
99 p_fs
->buf_cache_array
[i
].sec
= ~0;
100 p_fs
->buf_cache_array
[i
].flag
= 0;
101 p_fs
->buf_cache_array
[i
].buf_bh
= NULL
;
102 p_fs
->buf_cache_array
[i
].prev
= p_fs
->buf_cache_array
[i
].next
= NULL
;
103 push_to_mru(&(p_fs
->buf_cache_array
[i
]), &p_fs
->buf_cache_lru_list
);
107 for (i
= 0; i
< FAT_CACHE_HASH_SIZE
; i
++) {
108 p_fs
->FAT_cache_hash_list
[i
].drv
= -1;
109 p_fs
->FAT_cache_hash_list
[i
].sec
= ~0;
110 p_fs
->FAT_cache_hash_list
[i
].hash_next
= p_fs
->FAT_cache_hash_list
[i
].hash_prev
= &(p_fs
->FAT_cache_hash_list
[i
]);
113 for (i
= 0; i
< FAT_CACHE_SIZE
; i
++) {
114 FAT_cache_insert_hash(sb
, &(p_fs
->FAT_cache_array
[i
]));
117 for (i
= 0; i
< BUF_CACHE_HASH_SIZE
; i
++) {
118 p_fs
->buf_cache_hash_list
[i
].drv
= -1;
119 p_fs
->buf_cache_hash_list
[i
].sec
= ~0;
120 p_fs
->buf_cache_hash_list
[i
].hash_next
= p_fs
->buf_cache_hash_list
[i
].hash_prev
= &(p_fs
->buf_cache_hash_list
[i
]);
123 for (i
= 0; i
< BUF_CACHE_SIZE
; i
++) {
124 buf_cache_insert_hash(sb
, &(p_fs
->buf_cache_array
[i
]));
128 } /* end of buf_init */
130 INT32
buf_shutdown(struct super_block
*sb
)
133 } /* end of buf_shutdown */
135 /*======================================================================*/
136 /* FAT Read/Write Functions */
137 /*======================================================================*/
141 * returns 0 on success
144 INT32
FAT_read(struct super_block
*sb
, UINT32 loc
, UINT32
*content
)
150 ret
= __FAT_read(sb
, loc
, content
);
155 } /* end of FAT_read */
157 INT32
FAT_write(struct super_block
*sb
, UINT32 loc
, UINT32 content
)
163 ret
= __FAT_write(sb
, loc
, content
);
168 } /* end of FAT_write */
170 static INT32
__FAT_read(struct super_block
*sb
, UINT32 loc
, UINT32
*content
)
173 UINT32 sec
, _content
;
174 UINT8
*fat_sector
, *fat_entry
;
175 FS_INFO_T
*p_fs
= &(EXFAT_SB(sb
)->fs_info
);
176 BD_INFO_T
*p_bd
= &(EXFAT_SB(sb
)->bd_info
);
178 if (p_fs
->vol_type
== FAT12
) {
179 sec
= p_fs
->FAT1_start_sector
+ ((loc
+ (loc
>> 1)) >> p_bd
->sector_size_bits
);
180 off
= (loc
+ (loc
>> 1)) & p_bd
->sector_size_mask
;
182 if (off
== (p_bd
->sector_size
-1)) {
183 fat_sector
= FAT_getblk(sb
, sec
);
187 _content
= (UINT32
) fat_sector
[off
];
189 fat_sector
= FAT_getblk(sb
, ++sec
);
193 _content
|= (UINT32
) fat_sector
[0] << 8;
195 fat_sector
= FAT_getblk(sb
, sec
);
199 fat_entry
= &(fat_sector
[off
]);
200 _content
= GET16(fat_entry
);
203 if (loc
& 1) _content
>>= 4;
205 _content
&= 0x00000FFF;
207 if (_content
>= CLUSTER_16(0x0FF8)) {
208 *content
= CLUSTER_32(~0);
211 *content
= CLUSTER_32(_content
);
214 } else if (p_fs
->vol_type
== FAT16
) {
215 sec
= p_fs
->FAT1_start_sector
+ (loc
>> (p_bd
->sector_size_bits
-1));
216 off
= (loc
<< 1) & p_bd
->sector_size_mask
;
218 fat_sector
= FAT_getblk(sb
, sec
);
222 fat_entry
= &(fat_sector
[off
]);
224 _content
= GET16_A(fat_entry
);
226 _content
&= 0x0000FFFF;
228 if (_content
>= CLUSTER_16(0xFFF8)) {
229 *content
= CLUSTER_32(~0);
232 *content
= CLUSTER_32(_content
);
235 } else if (p_fs
->vol_type
== FAT32
) {
236 sec
= p_fs
->FAT1_start_sector
+ (loc
>> (p_bd
->sector_size_bits
-2));
237 off
= (loc
<< 2) & p_bd
->sector_size_mask
;
239 fat_sector
= FAT_getblk(sb
, sec
);
243 fat_entry
= &(fat_sector
[off
]);
245 _content
= GET32_A(fat_entry
);
247 _content
&= 0x0FFFFFFF;
249 if (_content
>= CLUSTER_32(0x0FFFFFF8)) {
250 *content
= CLUSTER_32(~0);
253 *content
= CLUSTER_32(_content
);
257 sec
= p_fs
->FAT1_start_sector
+ (loc
>> (p_bd
->sector_size_bits
-2));
258 off
= (loc
<< 2) & p_bd
->sector_size_mask
;
260 fat_sector
= FAT_getblk(sb
, sec
);
264 fat_entry
= &(fat_sector
[off
]);
265 _content
= GET32_A(fat_entry
);
267 if (_content
>= CLUSTER_32(0xFFFFFFF8)) {
268 *content
= CLUSTER_32(~0);
271 *content
= CLUSTER_32(_content
);
276 *content
= CLUSTER_32(~0);
278 } /* end of __FAT_read */
280 static INT32
__FAT_write(struct super_block
*sb
, UINT32 loc
, UINT32 content
)
284 UINT8
*fat_sector
, *fat_entry
;
285 FS_INFO_T
*p_fs
= &(EXFAT_SB(sb
)->fs_info
);
286 BD_INFO_T
*p_bd
= &(EXFAT_SB(sb
)->bd_info
);
288 if (p_fs
->vol_type
== FAT12
) {
290 content
&= 0x00000FFF;
292 sec
= p_fs
->FAT1_start_sector
+ ((loc
+ (loc
>> 1)) >> p_bd
->sector_size_bits
);
293 off
= (loc
+ (loc
>> 1)) & p_bd
->sector_size_mask
;
295 fat_sector
= FAT_getblk(sb
, sec
);
299 if (loc
& 1) { /* odd */
303 if (off
== (p_bd
->sector_size
-1)) {
304 fat_sector
[off
] = (UINT8
)(content
| (fat_sector
[off
] & 0x0F));
307 fat_sector
= FAT_getblk(sb
, ++sec
);
311 fat_sector
[0] = (UINT8
)(content
>> 8);
313 fat_entry
= &(fat_sector
[off
]);
314 content
|= GET16(fat_entry
) & 0x000F;
316 SET16(fat_entry
, content
);
319 fat_sector
[off
] = (UINT8
)(content
);
321 if (off
== (p_bd
->sector_size
-1)) {
322 fat_sector
[off
] = (UINT8
)(content
);
325 fat_sector
= FAT_getblk(sb
, ++sec
);
326 fat_sector
[0] = (UINT8
)((fat_sector
[0] & 0xF0) | (content
>> 8));
328 fat_entry
= &(fat_sector
[off
]);
329 content
|= GET16(fat_entry
) & 0xF000;
331 SET16(fat_entry
, content
);
336 else if (p_fs
->vol_type
== FAT16
) {
338 content
&= 0x0000FFFF;
340 sec
= p_fs
->FAT1_start_sector
+ (loc
>> (p_bd
->sector_size_bits
-1));
341 off
= (loc
<< 1) & p_bd
->sector_size_mask
;
343 fat_sector
= FAT_getblk(sb
, sec
);
347 fat_entry
= &(fat_sector
[off
]);
349 SET16_A(fat_entry
, content
);
352 else if (p_fs
->vol_type
== FAT32
) {
354 content
&= 0x0FFFFFFF;
356 sec
= p_fs
->FAT1_start_sector
+ (loc
>> (p_bd
->sector_size_bits
-2));
357 off
= (loc
<< 2) & p_bd
->sector_size_mask
;
359 fat_sector
= FAT_getblk(sb
, sec
);
363 fat_entry
= &(fat_sector
[off
]);
365 content
|= GET32_A(fat_entry
) & 0xF0000000;
367 SET32_A(fat_entry
, content
);
370 else { /* p_fs->vol_type == EXFAT */
372 sec
= p_fs
->FAT1_start_sector
+ (loc
>> (p_bd
->sector_size_bits
-2));
373 off
= (loc
<< 2) & p_bd
->sector_size_mask
;
375 fat_sector
= FAT_getblk(sb
, sec
);
379 fat_entry
= &(fat_sector
[off
]);
381 SET32_A(fat_entry
, content
);
386 } /* end of __FAT_write */
388 UINT8
*FAT_getblk(struct super_block
*sb
, UINT32 sec
)
391 FS_INFO_T
*p_fs
= &(EXFAT_SB(sb
)->fs_info
);
393 bp
= FAT_cache_find(sb
, sec
);
395 move_to_mru(bp
, &p_fs
->FAT_cache_lru_list
);
396 return(bp
->buf_bh
->b_data
);
399 bp
= FAT_cache_get(sb
, sec
);
401 FAT_cache_remove_hash(bp
);
407 FAT_cache_insert_hash(sb
, bp
);
409 if (sector_read(sb
, sec
, &(bp
->buf_bh
), 1) != FFS_SUCCESS
) {
410 FAT_cache_remove_hash(bp
);
416 move_to_lru(bp
, &p_fs
->FAT_cache_lru_list
);
420 return(bp
->buf_bh
->b_data
);
421 } /* end of FAT_getblk */
423 void FAT_modify(struct super_block
*sb
, UINT32 sec
)
427 bp
= FAT_cache_find(sb
, sec
);
429 sector_write(sb
, sec
, bp
->buf_bh
, 0);
431 } /* end of FAT_modify */
433 void FAT_release_all(struct super_block
*sb
)
436 FS_INFO_T
*p_fs
= &(EXFAT_SB(sb
)->fs_info
);
440 bp
= p_fs
->FAT_cache_lru_list
.next
;
441 while (bp
!= &p_fs
->FAT_cache_lru_list
) {
442 if (bp
->drv
== p_fs
->drv
) {
448 __brelse(bp
->buf_bh
);
456 } /* end of FAT_release_all */
458 void FAT_sync(struct super_block
*sb
)
461 FS_INFO_T
*p_fs
= &(EXFAT_SB(sb
)->fs_info
);
465 bp
= p_fs
->FAT_cache_lru_list
.next
;
466 while (bp
!= &p_fs
->FAT_cache_lru_list
) {
467 if ((bp
->drv
== p_fs
->drv
) && (bp
->flag
& DIRTYBIT
)) {
468 sync_dirty_buffer(bp
->buf_bh
);
469 bp
->flag
&= ~(DIRTYBIT
);
475 } /* end of FAT_sync */
477 static BUF_CACHE_T
*FAT_cache_find(struct super_block
*sb
, UINT32 sec
)
480 BUF_CACHE_T
*bp
, *hp
;
481 FS_INFO_T
*p_fs
= &(EXFAT_SB(sb
)->fs_info
);
483 off
= (sec
+ (sec
>> p_fs
->sectors_per_clu_bits
)) & (FAT_CACHE_HASH_SIZE
- 1);
485 hp
= &(p_fs
->FAT_cache_hash_list
[off
]);
486 for (bp
= hp
->hash_next
; bp
!= hp
; bp
= bp
->hash_next
) {
487 if ((bp
->drv
== p_fs
->drv
) && (bp
->sec
== sec
)) {
489 WARN(!bp
->buf_bh
, "[EXFAT] FAT_cache has no bh. "
490 "It will make system panic.\n");
492 touch_buffer(bp
->buf_bh
);
497 } /* end of FAT_cache_find */
499 static BUF_CACHE_T
*FAT_cache_get(struct super_block
*sb
, UINT32 sec
)
502 FS_INFO_T
*p_fs
= &(EXFAT_SB(sb
)->fs_info
);
504 bp
= p_fs
->FAT_cache_lru_list
.prev
;
507 move_to_mru(bp
, &p_fs
->FAT_cache_lru_list
);
509 } /* end of FAT_cache_get */
511 static void FAT_cache_insert_hash(struct super_block
*sb
, BUF_CACHE_T
*bp
)
517 p_fs
= &(EXFAT_SB(sb
)->fs_info
);
518 off
= (bp
->sec
+ (bp
->sec
>> p_fs
->sectors_per_clu_bits
)) & (FAT_CACHE_HASH_SIZE
-1);
520 hp
= &(p_fs
->FAT_cache_hash_list
[off
]);
521 bp
->hash_next
= hp
->hash_next
;
523 hp
->hash_next
->hash_prev
= bp
;
525 } /* end of FAT_cache_insert_hash */
527 static void FAT_cache_remove_hash(BUF_CACHE_T
*bp
)
529 (bp
->hash_prev
)->hash_next
= bp
->hash_next
;
530 (bp
->hash_next
)->hash_prev
= bp
->hash_prev
;
531 } /* end of FAT_cache_remove_hash */
533 /*======================================================================*/
534 /* Buffer Read/Write Functions */
535 /*======================================================================*/
537 UINT8
*buf_getblk(struct super_block
*sb
, UINT32 sec
)
543 buf
= __buf_getblk(sb
, sec
);
548 } /* end of buf_getblk */
550 static UINT8
*__buf_getblk(struct super_block
*sb
, UINT32 sec
)
553 FS_INFO_T
*p_fs
= &(EXFAT_SB(sb
)->fs_info
);
555 bp
= buf_cache_find(sb
, sec
);
557 move_to_mru(bp
, &p_fs
->buf_cache_lru_list
);
558 return(bp
->buf_bh
->b_data
);
561 bp
= buf_cache_get(sb
, sec
);
563 buf_cache_remove_hash(bp
);
569 buf_cache_insert_hash(sb
, bp
);
571 if (sector_read(sb
, sec
, &(bp
->buf_bh
), 1) != FFS_SUCCESS
) {
572 buf_cache_remove_hash(bp
);
578 move_to_lru(bp
, &p_fs
->buf_cache_lru_list
);
582 return(bp
->buf_bh
->b_data
);
584 } /* end of __buf_getblk */
586 void buf_modify(struct super_block
*sb
, UINT32 sec
)
592 bp
= buf_cache_find(sb
, sec
);
593 if (likely(bp
!= NULL
)) {
594 sector_write(sb
, sec
, bp
->buf_bh
, 0);
597 WARN(!bp
, "[EXFAT] failed to find buffer_cache(sector:%u).\n", sec
);
600 } /* end of buf_modify */
602 void buf_lock(struct super_block
*sb
, UINT32 sec
)
608 bp
= buf_cache_find(sb
, sec
);
609 if (likely(bp
!= NULL
)) bp
->flag
|= LOCKBIT
;
611 WARN(!bp
, "[EXFAT] failed to find buffer_cache(sector:%u).\n", sec
);
614 } /* end of buf_lock */
616 void buf_unlock(struct super_block
*sb
, UINT32 sec
)
622 bp
= buf_cache_find(sb
, sec
);
623 if (likely(bp
!= NULL
)) bp
->flag
&= ~(LOCKBIT
);
625 WARN(!bp
, "[EXFAT] failed to find buffer_cache(sector:%u).\n", sec
);
628 } /* end of buf_unlock */
630 void buf_release(struct super_block
*sb
, UINT32 sec
)
633 FS_INFO_T
*p_fs
= &(EXFAT_SB(sb
)->fs_info
);
637 bp
= buf_cache_find(sb
, sec
);
638 if (likely(bp
!= NULL
)) {
644 __brelse(bp
->buf_bh
);
648 move_to_lru(bp
, &p_fs
->buf_cache_lru_list
);
652 } /* end of buf_release */
654 void buf_release_all(struct super_block
*sb
)
657 FS_INFO_T
*p_fs
= &(EXFAT_SB(sb
)->fs_info
);
661 bp
= p_fs
->buf_cache_lru_list
.next
;
662 while (bp
!= &p_fs
->buf_cache_lru_list
) {
663 if (bp
->drv
== p_fs
->drv
) {
669 __brelse(bp
->buf_bh
);
677 } /* end of buf_release_all */
679 void buf_sync(struct super_block
*sb
)
682 FS_INFO_T
*p_fs
= &(EXFAT_SB(sb
)->fs_info
);
686 bp
= p_fs
->buf_cache_lru_list
.next
;
687 while (bp
!= &p_fs
->buf_cache_lru_list
) {
688 if ((bp
->drv
== p_fs
->drv
) && (bp
->flag
& DIRTYBIT
)) {
689 sync_dirty_buffer(bp
->buf_bh
);
690 bp
->flag
&= ~(DIRTYBIT
);
696 } /* end of buf_sync */
698 static BUF_CACHE_T
*buf_cache_find(struct super_block
*sb
, UINT32 sec
)
701 BUF_CACHE_T
*bp
, *hp
;
702 FS_INFO_T
*p_fs
= &(EXFAT_SB(sb
)->fs_info
);
704 off
= (sec
+ (sec
>> p_fs
->sectors_per_clu_bits
)) & (BUF_CACHE_HASH_SIZE
- 1);
706 hp
= &(p_fs
->buf_cache_hash_list
[off
]);
707 for (bp
= hp
->hash_next
; bp
!= hp
; bp
= bp
->hash_next
) {
708 if ((bp
->drv
== p_fs
->drv
) && (bp
->sec
== sec
)) {
709 touch_buffer(bp
->buf_bh
);
714 } /* end of buf_cache_find */
716 static BUF_CACHE_T
*buf_cache_get(struct super_block
*sb
, UINT32 sec
)
719 FS_INFO_T
*p_fs
= &(EXFAT_SB(sb
)->fs_info
);
721 bp
= p_fs
->buf_cache_lru_list
.prev
;
722 while (bp
->flag
& LOCKBIT
) bp
= bp
->prev
;
725 move_to_mru(bp
, &p_fs
->buf_cache_lru_list
);
727 } /* end of buf_cache_get */
729 static void buf_cache_insert_hash(struct super_block
*sb
, BUF_CACHE_T
*bp
)
735 p_fs
= &(EXFAT_SB(sb
)->fs_info
);
736 off
= (bp
->sec
+ (bp
->sec
>> p_fs
->sectors_per_clu_bits
)) & (BUF_CACHE_HASH_SIZE
-1);
738 hp
= &(p_fs
->buf_cache_hash_list
[off
]);
739 bp
->hash_next
= hp
->hash_next
;
741 hp
->hash_next
->hash_prev
= bp
;
743 } /* end of buf_cache_insert_hash */
745 static void buf_cache_remove_hash(BUF_CACHE_T
*bp
)
747 (bp
->hash_prev
)->hash_next
= bp
->hash_next
;
748 (bp
->hash_next
)->hash_prev
= bp
->hash_prev
;
749 } /* end of buf_cache_remove_hash */
751 /*======================================================================*/
752 /* Local Function Definitions */
753 /*======================================================================*/
755 static void push_to_mru(BUF_CACHE_T
*bp
, BUF_CACHE_T
*list
)
757 bp
->next
= list
->next
;
759 list
->next
->prev
= bp
;
761 } /* end of buf_cache_push_to_mru */
763 static void push_to_lru(BUF_CACHE_T
*bp
, BUF_CACHE_T
*list
)
765 bp
->prev
= list
->prev
;
767 list
->prev
->next
= bp
;
769 } /* end of buf_cache_push_to_lru */
771 static void move_to_mru(BUF_CACHE_T
*bp
, BUF_CACHE_T
*list
)
773 bp
->prev
->next
= bp
->next
;
774 bp
->next
->prev
= bp
->prev
;
775 push_to_mru(bp
, list
);
776 } /* end of buf_cache_move_to_mru */
778 static void move_to_lru(BUF_CACHE_T
*bp
, BUF_CACHE_T
*list
)
780 bp
->prev
->next
= bp
->next
;
781 bp
->next
->prev
= bp
->prev
;
782 push_to_lru(bp
, list
);
783 } /* end of buf_cache_move_to_lru */
785 /* end of exfat_cache.c */