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 */