diff --git a/Kconfig b/Kconfig new file mode 100644 index 0000000..144b6ec --- /dev/null +++ b/Kconfig @@ -0,0 +1,19 @@ +config EXFAT_FS + tristate "exFAT filesystem support" + select NLS + help + exFAT driver from Samsung + +config EXFAT_DEFAULT_CODEPAGE + int "Default codepage for exFAT" + depends on EXFAT_FS + default 437 + help + This option should be set to the codepage of your exFAT filesystems. + +config EXFAT_DEFAULT_IOCHARSET + string "Default iocharset for exFAT" + depends on EXFAT_FS + default "utf8" + help + Set this to the default input/output character set you'd like exFAT to use. diff --git a/Makefile b/Makefile index 6fd7d57..77dc36c 100644 --- a/Makefile +++ b/Makefile @@ -1,26 +1,4 @@ -# Exfat Linux kernel modules -# - -obj-m += exfat.o +obj-$(CONFIG_EXFAT_FS) += exfat.o exfat-y := exfat_core.o exfat_api.o exfat_blkdev.o exfat_cache.o exfat_super.o \ - exfat_data.o exfat_global.o exfat_nls.o exfat_oal.o exfat_upcase.o - -EXTRA_FLAGS += -I$(PWD) - -#KDIR := /usr/src/linux/ -KDIR := /lib/modules/$(shell uname -r)/build -PWD := $(shell pwd) - -all: - $(MAKE) -C $(KDIR) M=$(PWD) modules - -clean: - $(MAKE) -C $(KDIR) M=$(PWD) clean - -help: - $(MAKE) -C $(KDIR) M=$(PWD) help - -.PHONY : install -install : all - sudo $(MAKE) -C $(KDIR) M=$(PWD) modules_install; sudo depmod + exfat_data.o exfat_global.o exfat_nls.o exfat_oal.o exfat_upcase.o diff --git a/README.md b/README.md index 51ea4e1..7d07376 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,55 @@ -exfat-nofuse -============ - -Linux non-fuse read/write kernel driver for the exFAT file system.
-Originally ported from android kernel v3.0. - - -Kudos to ksv1986 for the mutex patch!
-Thanks to JackNorris for being awesome and providing the clear_inode() patch.
-
-Big thanks to lqs for completing the driver! - - -Special thanks to github user AndreiLux for spreading the word about the leak!
- - -Installation: -> make
-> make install - -To load the driver manually, run this as root: -> modprobe exfat - - -Free Software for the Free Minds! +exfat-nofuse +============ + +Linux non-fuse read/write kernel driver for the exFAT file system.
+Originally ported from android kernel v3.0. + + +Kudos to ksv1986 for the mutex patch!
+Thanks to JackNorris for being awesome and providing the clear_inode() patch.
+
+Big thanks to lqs for completing the driver! + + +Special thanks to github user AndreiLux for spreading the word about the leak!
+ +To load the driver manually, run this as root: +> modprobe exfat + + +Free Software for the Free Minds! +===================================== + +To add to kernel you need to do this: + +cd your kernel source dir + +mkdir fs/exfat + +copy all files (exept .git) from exfat-nofuse to your kernel source fs/exfat/ + +see +https://github.com/dorimanx/Dorimanx-SG2-I9100-Kernel/commit/e8fc728a68096db9ffcebff40244ebfb60a3de18 + +edit fs/Kconfig +edit fs/Makefile + +cd your kernel source +make menuconfig + +go to: File systems > DOS/FAT/NT > check the exfat as MODULE (M) + exFAT filesystem support +(437) Default codepage for exFAT +(utf8) Default iocharset for exFAT + +ESC to main menu +Save an Alternate Configuration File +ESC ESC + +build your kernel. + +and you will have new module! + +exfat.ko + +have fun. \ No newline at end of file diff --git a/exfat.h b/exfat.h index 858fb42..a37f4b1 100644 --- a/exfat.h +++ b/exfat.h @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + /************************************************************************/ /* */ /* PROJECT : exFAT & FAT12/16/32 File System */ @@ -510,7 +528,7 @@ extern "C" { INT32 ffsCreateFile(struct inode *inode, UINT8 *path, UINT8 mode, FILE_ID_T *fid); INT32 ffsReadFile(struct inode *inode, FILE_ID_T *fid, void *buffer, UINT64 count, UINT64 *rcount); INT32 ffsWriteFile(struct inode *inode, FILE_ID_T *fid, void *buffer, UINT64 count, UINT64 *wcount); - INT32 ffsTruncateFile(struct inode *inode, UINT64 new_size); + INT32 ffsTruncateFile(struct inode *inode, UINT64 old_size, UINT64 new_size); INT32 ffsMoveFile(struct inode *old_parent_inode, FILE_ID_T *fid, struct inode *new_parent_inode, struct dentry *new_dentry); INT32 ffsRemoveFile(struct inode *inode, FILE_ID_T *fid); INT32 ffsSetAttr(struct inode *inode, UINT32 attr); diff --git a/exfat_api.c b/exfat_api.c index 9d70689..abeb7a5 100644 --- a/exfat_api.c +++ b/exfat_api.c @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + /************************************************************************/ /* */ /* PROJECT : exFAT & FAT12/16/32 File System */ @@ -287,24 +305,24 @@ INT32 FsWriteFile(struct inode *inode, FILE_ID_T *fid, void *buffer, UINT64 coun } /* end of FsWriteFile */ /* FsTruncateFile : resize the file length */ -INT32 FsTruncateFile(struct inode *inode, UINT64 new_size) +INT32 FsTruncateFile(struct inode *inode, UINT64 old_size, UINT64 new_size) { INT32 err; struct super_block *sb = inode->i_sb; FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); - PRINTK("FsTruncateFile entered (inode %p size %llu\n", inode, new_size); - /* acquire the lock for file system critical section */ sm_P(&(fs_struct[p_fs->drv].v_sem)); - err = ffsTruncateFile(inode, new_size); + PRINTK("FsTruncateFile entered (inode %p size %llu)\n", inode, new_size); - /* release the lock for file system critical section */ - sm_V(&(fs_struct[p_fs->drv].v_sem)); + err = ffsTruncateFile(inode, old_size, new_size); PRINTK("FsTruncateFile exitted (%d)\n", err); + /* release the lock for file system critical section */ + sm_V(&(fs_struct[p_fs->drv].v_sem)); + return(err); } /* end of FsTruncateFile */ diff --git a/exfat_api.h b/exfat_api.h index d6ab014..c3d5d90 100644 --- a/exfat_api.h +++ b/exfat_api.h @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + /************************************************************************/ /* */ /* PROJECT : exFAT & FAT12/16/32 File System */ @@ -173,7 +191,7 @@ extern "C" { INT32 FsCreateFile(struct inode *inode, UINT8 *path, UINT8 mode, FILE_ID_T *fid); INT32 FsReadFile(struct inode *inode, FILE_ID_T *fid, void *buffer, UINT64 count, UINT64 *rcount); INT32 FsWriteFile(struct inode *inode, FILE_ID_T *fid, void *buffer, UINT64 count, UINT64 *wcount); - INT32 FsTruncateFile(struct inode *inode, UINT64 new_size); + INT32 FsTruncateFile(struct inode *inode, UINT64 old_size, UINT64 new_size); INT32 FsMoveFile(struct inode *old_parent_inode, FILE_ID_T *fid, struct inode *new_parent_inode, struct dentry *new_dentry); INT32 FsRemoveFile(struct inode *inode, FILE_ID_T *fid); INT32 FsSetAttr(struct inode *inode, UINT32 attr); diff --git a/exfat_blkdev.c b/exfat_blkdev.c index 3391a53..154b444 100644 --- a/exfat_blkdev.c +++ b/exfat_blkdev.c @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + /************************************************************************/ /* */ /* PROJECT : exFAT & FAT12/16/32 File System */ @@ -41,7 +59,7 @@ INT32 bdev_init(void) { - return(FFS_SUCCESS); + return(FFS_SUCCESS); } INT32 bdev_shutdown(void) @@ -78,6 +96,7 @@ INT32 bdev_close(struct super_block *sb) INT32 bdev_read(struct super_block *sb, UINT32 secno, struct buffer_head **bh, UINT32 num_secs, INT32 read) { BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); #if EXFAT_CONFIG_KERNEL_DEBUG struct exfat_sb_info *sbi = EXFAT_SB(sb); long flags = sbi->debug_flags; @@ -96,7 +115,8 @@ INT32 bdev_read(struct super_block *sb, UINT32 secno, struct buffer_head **bh, U if (*bh) return(FFS_SUCCESS); - WARN_ONCE(1, "EXFAT: Out of memory\n"); + WARN(!p_fs->dev_ejected, + "[EXFAT] No bh, device seems wrong or to be ejected.\n"); return(FFS_MEDIAERR); } @@ -106,6 +126,7 @@ INT32 bdev_write(struct super_block *sb, UINT32 secno, struct buffer_head *bh, U INT32 count; struct buffer_head *bh2; BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); #if EXFAT_CONFIG_KERNEL_DEBUG struct exfat_sb_info *sbi = EXFAT_SB(sb); long flags = sbi->debug_flags; @@ -128,7 +149,7 @@ INT32 bdev_write(struct super_block *sb, UINT32 secno, struct buffer_head *bh, U bh2 = __getblk(sb->s_bdev, secno, count); if (bh2 == NULL) - return (FFS_MEDIAERR); + goto no_bh; lock_buffer(bh2); MEMCPY(bh2->b_data, bh->b_data, count); @@ -137,12 +158,18 @@ INT32 bdev_write(struct super_block *sb, UINT32 secno, struct buffer_head *bh, U unlock_buffer(bh2); if (sync && (sync_dirty_buffer(bh2) != 0)) { __brelse(bh2); - return (FFS_MEDIAERR); + goto no_bh; } __brelse(bh2); } return(FFS_SUCCESS); + +no_bh: + WARN(!p_fs->dev_ejected, + "[EXFAT] No bh, device seems wrong or to be ejected.\n"); + + return (FFS_MEDIAERR); } INT32 bdev_sync(struct super_block *sb) diff --git a/exfat_blkdev.h b/exfat_blkdev.h index 4ae93cd..c1f0c28 100644 --- a/exfat_blkdev.h +++ b/exfat_blkdev.h @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + /************************************************************************/ /* */ /* PROJECT : exFAT & FAT12/16/32 File System */ diff --git a/exfat_cache.c b/exfat_cache.c index c478051..05c6136 100644 --- a/exfat_cache.c +++ b/exfat_cache.c @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + /************************************************************************/ /* */ /* PROJECT : exFAT & FAT12/16/32 File System */ @@ -29,35 +47,11 @@ extern FS_STRUCT_T fs_struct[]; -/* All buffer structures are protected w/ p_fs->v_sem */ -#if 0 -extern struct semaphore f_sem; -extern struct semaphore b_sem; -#else #define sm_P(s) #define sm_V(s) -#endif - -#if 0 -/*----------------------------------------------------------------------*/ -/* Local Variable Definitions */ -/*----------------------------------------------------------------------*/ - -extern BUF_CACHE_T FAT_cache_array[]; -extern BUF_CACHE_T FAT_cache_lru_list; -extern BUF_CACHE_T FAT_cache_hash_list[]; - -extern BUF_CACHE_T buf_cache_array[]; -extern BUF_CACHE_T buf_cache_lru_list; -extern BUF_CACHE_T buf_cache_hash_list[]; -#endif - -/*----------------------------------------------------------------------*/ -/* Local Function Declarations */ -/*----------------------------------------------------------------------*/ static INT32 __FAT_read(struct super_block *sb, UINT32 loc, UINT32 *content); -static void __FAT_write(struct super_block *sb, UINT32 loc, UINT32 content); +static INT32 __FAT_write(struct super_block *sb, UINT32 loc, UINT32 content); static BUF_CACHE_T *FAT_cache_find(struct super_block *sb, UINT32 sec); static BUF_CACHE_T *FAT_cache_get(struct super_block *sb, UINT32 sec); @@ -82,7 +76,7 @@ static void move_to_lru(BUF_CACHE_T *bp, BUF_CACHE_T *list); INT32 buf_init(struct super_block *sb) { - FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); INT32 i; @@ -160,13 +154,17 @@ INT32 FAT_read(struct super_block *sb, UINT32 loc, UINT32 *content) return(ret); } /* end of FAT_read */ -void FAT_write(struct super_block *sb, UINT32 loc, UINT32 content) +INT32 FAT_write(struct super_block *sb, UINT32 loc, UINT32 content) { + INT32 ret; + sm_P(&f_sem); - __FAT_write(sb, loc, content); + ret = __FAT_write(sb, loc, content); sm_V(&f_sem); + + return(ret); } /* end of FAT_write */ static INT32 __FAT_read(struct super_block *sb, UINT32 loc, UINT32 *content) @@ -183,22 +181,19 @@ static INT32 __FAT_read(struct super_block *sb, UINT32 loc, UINT32 *content) if (off == (p_bd->sector_size-1)) { fat_sector = FAT_getblk(sb, sec); - if - (!fat_sector) + if (!fat_sector) return -1; _content = (UINT32) fat_sector[off]; fat_sector = FAT_getblk(sb, ++sec); - if - (!fat_sector) + if (!fat_sector) return -1; _content |= (UINT32) fat_sector[0] << 8; } else { fat_sector = FAT_getblk(sb, sec); - if - (!fat_sector) + if (!fat_sector) return -1; fat_entry = &(fat_sector[off]); @@ -210,11 +205,9 @@ static INT32 __FAT_read(struct super_block *sb, UINT32 loc, UINT32 *content) _content &= 0x00000FFF; if (_content >= CLUSTER_16(0x0FF8)) { - // return(CLUSTER_32(~0)); // return 0xFFFFFFFF to simplify code *content = CLUSTER_32(~0); return 0; } else { - //return(CLUSTER_32(_content)); *content = CLUSTER_32(_content); return 0; } @@ -223,8 +216,7 @@ static INT32 __FAT_read(struct super_block *sb, UINT32 loc, UINT32 *content) off = (loc << 1) & p_bd->sector_size_mask; fat_sector = FAT_getblk(sb, sec); - if - (!fat_sector) + if (!fat_sector) return -1; fat_entry = &(fat_sector[off]); @@ -234,11 +226,9 @@ static INT32 __FAT_read(struct super_block *sb, UINT32 loc, UINT32 *content) _content &= 0x0000FFFF; if (_content >= CLUSTER_16(0xFFF8)) { - //return(CLUSTER_32(~0)); // return 0xFFFFFFFF to simplify code *content = CLUSTER_32(~0); return 0; } else { - //return(CLUSTER_32(_content)); *content = CLUSTER_32(_content); return 0; } @@ -247,8 +237,7 @@ static INT32 __FAT_read(struct super_block *sb, UINT32 loc, UINT32 *content) off = (loc << 2) & p_bd->sector_size_mask; fat_sector = FAT_getblk(sb, sec); - if - (!fat_sector) + if (!fat_sector) return -1; fat_entry = &(fat_sector[off]); @@ -258,44 +247,37 @@ static INT32 __FAT_read(struct super_block *sb, UINT32 loc, UINT32 *content) _content &= 0x0FFFFFFF; if (_content >= CLUSTER_32(0x0FFFFFF8)) { - //return(CLUSTER_32(~0)); // return 0xFFFFFFFF to simplify code *content = CLUSTER_32(~0); return 0; } else { - //return(CLUSTER_32(_content)); *content = CLUSTER_32(_content); return 0; } } else { - /* p_fs->vol_type == EXFAT */ sec = p_fs->FAT1_start_sector + (loc >> (p_bd->sector_size_bits-2)); off = (loc << 2) & p_bd->sector_size_mask; fat_sector = FAT_getblk(sb, sec); - if - (!fat_sector) + if (!fat_sector) return -1; fat_entry = &(fat_sector[off]); _content = GET32_A(fat_entry); if (_content >= CLUSTER_32(0xFFFFFFF8)) { - //return(CLUSTER_32(~0)); // return 0xFFFFFFFF to simplify code *content = CLUSTER_32(~0); return 0; } else { - //return(CLUSTER_32(_content)); *content = CLUSTER_32(_content); return 0; } } - //return(CLUSTER_32(~0)); *content = CLUSTER_32(~0); return 0; } /* end of __FAT_read */ -static void __FAT_write(struct super_block *sb, UINT32 loc, UINT32 content) +static INT32 __FAT_write(struct super_block *sb, UINT32 loc, UINT32 content) { INT32 off; UINT32 sec; @@ -311,6 +293,8 @@ static void __FAT_write(struct super_block *sb, UINT32 loc, UINT32 content) off = (loc + (loc >> 1)) & p_bd->sector_size_mask; fat_sector = FAT_getblk(sb, sec); + if (!fat_sector) + return -1; if (loc & 1) { /* odd */ @@ -321,6 +305,9 @@ static void __FAT_write(struct super_block *sb, UINT32 loc, UINT32 content) FAT_modify(sb, sec); fat_sector = FAT_getblk(sb, ++sec); + if (!fat_sector) + return -1; + fat_sector[0] = (UINT8)(content >> 8); } else { fat_entry = &(fat_sector[off]); @@ -354,6 +341,9 @@ static void __FAT_write(struct super_block *sb, UINT32 loc, UINT32 content) off = (loc << 1) & p_bd->sector_size_mask; fat_sector = FAT_getblk(sb, sec); + if (!fat_sector) + return -1; + fat_entry = &(fat_sector[off]); SET16_A(fat_entry, content); @@ -367,6 +357,9 @@ static void __FAT_write(struct super_block *sb, UINT32 loc, UINT32 content) off = (loc << 2) & p_bd->sector_size_mask; fat_sector = FAT_getblk(sb, sec); + if (!fat_sector) + return -1; + fat_entry = &(fat_sector[off]); content |= GET32_A(fat_entry) & 0xF0000000; @@ -380,12 +373,16 @@ static void __FAT_write(struct super_block *sb, UINT32 loc, UINT32 content) off = (loc << 2) & p_bd->sector_size_mask; fat_sector = FAT_getblk(sb, sec); + if (!fat_sector) + return -1; + fat_entry = &(fat_sector[off]); SET32_A(fat_entry, content); } FAT_modify(sb, sec); + return 0; } /* end of __FAT_write */ UINT8 *FAT_getblk(struct super_block *sb, UINT32 sec) @@ -409,8 +406,16 @@ UINT8 *FAT_getblk(struct super_block *sb, UINT32 sec) FAT_cache_insert_hash(sb, bp); - if (sector_read(sb, sec, &(bp->buf_bh), 1) != FFS_SUCCESS) + if (sector_read(sb, sec, &(bp->buf_bh), 1) != FFS_SUCCESS) { + FAT_cache_remove_hash(bp); + bp->drv = -1; + bp->sec = ~0; + bp->flag = 0; + bp->buf_bh = NULL; + + move_to_lru(bp, &p_fs->FAT_cache_lru_list); return NULL; + } return(bp->buf_bh->b_data); } /* end of FAT_getblk */ @@ -421,7 +426,6 @@ void FAT_modify(struct super_block *sb, UINT32 sec) bp = FAT_cache_find(sb, sec); if (bp != NULL) { -// bp->flag |= DIRTYBIT; sector_write(sb, sec, bp->buf_bh, 0); } } /* end of FAT_modify */ @@ -440,8 +444,10 @@ void FAT_release_all(struct super_block *sb) bp->sec = ~0; bp->flag = 0; - __brelse(bp->buf_bh); - bp->buf_bh = NULL; + if(bp->buf_bh) { + __brelse(bp->buf_bh); + bp->buf_bh = NULL; + } } bp = bp->next; } @@ -479,6 +485,10 @@ static BUF_CACHE_T *FAT_cache_find(struct super_block *sb, UINT32 sec) hp = &(p_fs->FAT_cache_hash_list[off]); for (bp = hp->hash_next; bp != hp; bp = bp->hash_next) { if ((bp->drv == p_fs->drv) && (bp->sec == sec)) { + + WARN(!bp->buf_bh, "[EXFAT] FAT_cache has no bh. " + "It will make system panic.\n"); + touch_buffer(bp->buf_bh); return(bp); } @@ -493,8 +503,6 @@ static BUF_CACHE_T *FAT_cache_get(struct super_block *sb, UINT32 sec) bp = p_fs->FAT_cache_lru_list.prev; -// if (bp->flag & DIRTYBIT) -// sync_dirty_buffer(bp->buf_bh); move_to_mru(bp, &p_fs->FAT_cache_lru_list); return(bp); @@ -582,11 +590,12 @@ void buf_modify(struct super_block *sb, UINT32 sec) sm_P(&b_sem); bp = buf_cache_find(sb, sec); - if (bp != NULL) { -// bp->flag |= DIRTYBIT; + if (likely(bp != NULL)) { sector_write(sb, sec, bp->buf_bh, 0); } + WARN(!bp, "[EXFAT] failed to find buffer_cache(sector:%u).\n", sec); + sm_V(&b_sem); } /* end of buf_modify */ @@ -597,7 +606,9 @@ void buf_lock(struct super_block *sb, UINT32 sec) sm_P(&b_sem); bp = buf_cache_find(sb, sec); - if (bp != NULL) bp->flag |= LOCKBIT; + if (likely(bp != NULL)) bp->flag |= LOCKBIT; + + WARN(!bp, "[EXFAT] failed to find buffer_cache(sector:%u).\n", sec); sm_V(&b_sem); } /* end of buf_lock */ @@ -609,7 +620,9 @@ void buf_unlock(struct super_block *sb, UINT32 sec) sm_P(&b_sem); bp = buf_cache_find(sb, sec); - if (bp != NULL) bp->flag &= ~(LOCKBIT); + if (likely(bp != NULL)) bp->flag &= ~(LOCKBIT); + + WARN(!bp, "[EXFAT] failed to find buffer_cache(sector:%u).\n", sec); sm_V(&b_sem); } /* end of buf_unlock */ @@ -622,13 +635,15 @@ void buf_release(struct super_block *sb, UINT32 sec) sm_P(&b_sem); bp = buf_cache_find(sb, sec); - if (bp != NULL) { + if (likely(bp != NULL)) { bp->drv = -1; bp->sec = ~0; bp->flag = 0; - __brelse(bp->buf_bh); - bp->buf_bh = NULL; + if(bp->buf_bh) { + __brelse(bp->buf_bh); + bp->buf_bh = NULL; + } move_to_lru(bp, &p_fs->buf_cache_lru_list); } @@ -650,8 +665,10 @@ void buf_release_all(struct super_block *sb) bp->sec = ~0; bp->flag = 0; - __brelse(bp->buf_bh); - bp->buf_bh = NULL; + if(bp->buf_bh) { + __brelse(bp->buf_bh); + bp->buf_bh = NULL; + } } bp = bp->next; } @@ -704,8 +721,6 @@ static BUF_CACHE_T *buf_cache_get(struct super_block *sb, UINT32 sec) bp = p_fs->buf_cache_lru_list.prev; while (bp->flag & LOCKBIT) bp = bp->prev; -// if (bp->flag & DIRTYBIT) -// sync_dirty_buffer(bp->buf_bh); move_to_mru(bp, &p_fs->buf_cache_lru_list); return(bp); diff --git a/exfat_cache.h b/exfat_cache.h index ce0f232..056636b 100644 --- a/exfat_cache.h +++ b/exfat_cache.h @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + /************************************************************************/ /* */ /* PROJECT : exFAT & FAT12/16/32 File System */ @@ -53,8 +71,8 @@ extern "C" { INT32 buf_init(struct super_block *sb); INT32 buf_shutdown(struct super_block *sb); - INT32 FAT_read(struct super_block *sb, UINT32 loc, UINT32 *content); - void FAT_write(struct super_block *sb, UINT32 loc, UINT32 content); + INT32 FAT_read(struct super_block *sb, UINT32 loc, UINT32 *content); + INT32 FAT_write(struct super_block *sb, UINT32 loc, UINT32 content); UINT8 *FAT_getblk(struct super_block *sb, UINT32 sec); void FAT_modify(struct super_block *sb, UINT32 sec); void FAT_release_all(struct super_block *sb); diff --git a/exfat_config.h b/exfat_config.h index 4086d16..d16c882 100644 --- a/exfat_config.h +++ b/exfat_config.h @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + /************************************************************************/ /* */ /* PROJECT : exFAT & FAT12/16/32 File System */ diff --git a/exfat_core.c b/exfat_core.c index 495f775..3ee43c2 100644 --- a/exfat_core.c +++ b/exfat_core.c @@ -1,3 +1,30 @@ +/* Some of the source code in this file came from "linux/fs/fat/misc.c". */ +/* + * linux/fs/fat/misc.c + * + * Written 1992,1993 by Werner Almesberger + * 22/11/2000 - Fixed fat_date_unix2dos for dates earlier than 01/01/1980 + * and date_dos2unix for date==0 by Igor Zhbanov(bsg@uniyar.ac.ru) + */ + +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + /************************************************************************/ /* */ /* PROJECT : exFAT & FAT12/16/32 File System */ @@ -51,7 +78,7 @@ set this macro to 0 */ static UINT32 __t1, __t2; static UINT32 get_current_msec(void) { - struct timeval tm; + struct timeval tm; do_gettimeofday(&tm); return (UINT32)(tm.tv_sec*1000000 + tm.tv_usec); } @@ -64,6 +91,16 @@ static UINT32 get_current_msec(void) #define PRINT_TIME(n) #endif +static void __set_sb_dirty(struct super_block *sb) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) + sb->s_dirt = 1; +#else + struct exfat_sb_info *sbi = EXFAT_SB(sb); + sbi->s_dirt = 1; +#endif +} + /*----------------------------------------------------------------------*/ /* Global Variable Definitions */ /*----------------------------------------------------------------------*/ @@ -134,12 +171,6 @@ INT32 ffsInit(void) if (ret) return ret; -/* - ret = buf_init(); - if (ret) - return ret; -*/ - return FFS_SUCCESS; } /* end of ffsInit */ @@ -147,13 +178,6 @@ INT32 ffsInit(void) INT32 ffsShutdown(void) { INT32 ret; - -/* - ret = buf_shutdown(); - if (ret) - return ret; -*/ - ret = fs_shutdown(); if (ret) return ret; @@ -178,7 +202,7 @@ INT32 ffsMountVol(struct super_block *sb, INT32 drv) FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); - PRINTK("[EXFAT] ===== ffsMountVol =====\n"); + PRINTK("[EXFAT] trying to mount...\n"); p_fs->drv = drv; p_fs->dev_ejected = FALSE; @@ -284,6 +308,7 @@ INT32 ffsMountVol(struct super_block *sb, INT32 drv) return FFS_MEDIAERR; } + PRINTK("[EXFAT] mounted successfully\n"); return FFS_SUCCESS; } /* end of ffsMountVol */ @@ -292,6 +317,8 @@ INT32 ffsUmountVol(struct super_block *sb) { FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + PRINTK("[EXFAT] trying to unmount...\n"); + fs_sync(sb, 0); fs_set_vol_flags(sb, VOL_CLEAN); @@ -306,9 +333,13 @@ INT32 ffsUmountVol(struct super_block *sb) /* close the block device */ bdev_close(sb); - if (p_fs->dev_ejected) + if (p_fs->dev_ejected) { + PRINTK( "[EXFAT] unmounted with media errors. " + "device's already ejected.\n"); return FFS_MEDIAERR; + } + PRINTK("[EXFAT] unmounted successfully\n"); return FFS_SUCCESS; } /* end of ffsUmountVol */ @@ -764,7 +795,7 @@ INT32 ffsWriteFile(struct inode *inode, FILE_ID_T *fid, void *buffer, UINT64 cou } /* end of ffsWriteFile */ /* ffsTruncateFile : resize the file length */ -INT32 ffsTruncateFile(struct inode *inode, UINT64 new_size) +INT32 ffsTruncateFile(struct inode *inode, UINT64 old_size, UINT64 new_size) { INT32 num_clusters; UINT32 last_clu = CLUSTER_32(0), sector = 0; @@ -780,13 +811,19 @@ INT32 ffsTruncateFile(struct inode *inode, UINT64 new_size) if (fid->type != TYPE_FILE) return FFS_PERMISSIONERR; - if (fid->size <= new_size) + if (fid->size != old_size) { + printk(KERN_ERR "[EXFAT] truncate : can't skip it because of " + "size-mismatch(old:%lld->fid:%lld).\n" + ,old_size, fid->size); + } + + if (old_size <= new_size) return FFS_SUCCESS; fs_set_vol_flags(sb, VOL_DIRTY); clu.dir = fid->start_clu; - clu.size = (INT32)((fid->size-1) >> p_fs->cluster_size_bits) + 1; + clu.size = (INT32)((old_size-1) >> p_fs->cluster_size_bits) + 1; clu.flags = fid->flags; if (new_size > 0) { @@ -797,7 +834,6 @@ INT32 ffsTruncateFile(struct inode *inode, UINT64 new_size) } else { while (num_clusters > 0) { last_clu = clu.dir; - /* clu.dir = FAT_read(sb, clu.dir);*/ if (FAT_read(sb, clu.dir, &(clu.dir)) == -1) return FFS_MEDIAERR; num_clusters--; @@ -830,9 +866,6 @@ INT32 ffsTruncateFile(struct inode *inode, UINT64 new_size) p_fs->fs_func->set_entry_time(ep, tm_current(&tm), TM_MODIFY); p_fs->fs_func->set_entry_attr(ep, fid->attr); - /* if (p_fs->vol_type != EXFAT) - buf_modify(sb, sector); */ - p_fs->fs_func->set_entry_size(ep2, new_size); if (new_size == 0) { p_fs->fs_func->set_entry_flag(ep2, 0x01); @@ -872,6 +905,22 @@ INT32 ffsTruncateFile(struct inode *inode, UINT64 new_size) return FFS_SUCCESS; } /* end of ffsTruncateFile */ +static void update_parent_info( FILE_ID_T *fid, struct inode *parent_inode) +{ + FS_INFO_T *p_fs = &(EXFAT_SB(parent_inode->i_sb)->fs_info); + FILE_ID_T *parent_fid = &(EXFAT_I(parent_inode)->fid); + + if (unlikely((parent_fid->flags != fid->dir.flags) + || (parent_fid->size != (fid->dir.size<cluster_size_bits)) + || (parent_fid->start_clu != fid->dir.dir))) { + + fid->dir.dir = parent_fid->start_clu; + fid->dir.flags = parent_fid->flags; + fid->dir.size = ((parent_fid->size + (p_fs->cluster_size-1)) + >> p_fs->cluster_size_bits); + } +} + /* ffsMoveFile : move(rename) a old file into a new file */ INT32 ffsMoveFile(struct inode *old_parent_inode, FILE_ID_T *fid, struct inode *new_parent_inode, struct dentry *new_dentry) { @@ -893,6 +942,8 @@ INT32 ffsMoveFile(struct inode *old_parent_inode, FILE_ID_T *fid, struct inode * if ((new_path == NULL) || (STRLEN(new_path) == 0)) return FFS_ERROR; + update_parent_info(fid, old_parent_inode); + olddir.dir = fid->dir.dir; olddir.size = fid->dir.size; olddir.flags = fid->dir.flags; @@ -918,6 +969,9 @@ INT32 ffsMoveFile(struct inode *old_parent_inode, FILE_ID_T *fid, struct inode * ret = FFS_MEDIAERR; new_fid = &EXFAT_I(new_inode)->fid; + + update_parent_info(new_fid, new_parent_inode); + p_dir = &(new_fid->dir); new_entry = new_fid->entry; ep = get_entry_in_dir(sb, p_dir, new_entry, NULL); @@ -1006,6 +1060,10 @@ INT32 ffsRemoveFile(struct inode *inode, FILE_ID_T *fid) /* (2) free the clusters */ p_fs->fs_func->free_cluster(sb, &clu_to_free, 0); + fid->size = 0; + fid->start_clu = CLUSTER_32(~0); + fid->flags = (p_fs->vol_type == EXFAT)? 0x03: 0x01; + #if (DELAYED_SYNC == 0) fs_sync(sb, 0); fs_set_vol_flags(sb, VOL_CLEAN); @@ -1285,11 +1343,6 @@ INT32 ffsSetStat(struct inode *inode, DIR_ENTRY_T *info) release_entry_set(es); } -#if (DELAYED_SYNC == 0) - /* fs_sync(sb, 0); - fs_set_vol_flags(sb, VOL_CLEAN); */ -#endif - if (p_fs->dev_ejected) return FFS_MEDIAERR; @@ -1335,7 +1388,6 @@ INT32 ffsMapCluster(struct inode *inode, INT32 clu_offset, UINT32 *clu) while ((clu_offset > 0) && (*clu != CLUSTER_32(~0))) { last_clu = *clu; - /* *clu = FAT_read(sb, *clu); */ if (FAT_read(sb, *clu, clu) == -1) return FFS_MEDIAERR; clu_offset--; @@ -1406,10 +1458,6 @@ INT32 ffsMapCluster(struct inode *inode, INT32 clu_offset, UINT32 *clu) /* add number of new blocks to inode */ inode->i_blocks += num_alloced << (p_fs->cluster_size_bits - 9); -#if (DELAYED_SYNC == 0) - /* fs_sync(sb, 0); - fs_set_vol_flags(sb, VOL_CLEAN); */ -#endif } /* hint information */ @@ -1664,6 +1712,10 @@ INT32 ffsRemoveDir(struct inode *inode, FILE_ID_T *fid) /* (2) free the clusters */ p_fs->fs_func->free_cluster(sb, &clu_to_free, 1); + fid->size = 0; + fid->start_clu = CLUSTER_32(~0); + fid->flags = (p_fs->vol_type == EXFAT)? 0x03: 0x01; + #if (DELAYED_SYNC == 0) fs_sync(sb, 0); fs_set_vol_flags(sb, VOL_CLEAN); @@ -1771,10 +1823,10 @@ void fs_error(struct super_block *sb) struct exfat_mount_options *opts = &EXFAT_SB(sb)->options; if (opts->errors == EXFAT_ERRORS_PANIC) - panic("EXFAT: fs panic from previous error\n"); + panic("[EXFAT] Filesystem panic from previous error\n"); else if ((opts->errors == EXFAT_ERRORS_RO) && !(sb->s_flags & MS_RDONLY)) { sb->s_flags |= MS_RDONLY; - printk(KERN_ERR "EXFAT: Filesystem has been set read-only\n"); + printk(KERN_ERR "[EXFAT] Filesystem has been set read-only\n"); } } @@ -1799,9 +1851,6 @@ INT32 clear_cluster(struct super_block *sb, UINT32 clu) } for ( ; s < n; s++) { - -// buf_release(sb, s); - if ((ret = sector_read(sb, s, &tmp_bh, 0)) != FFS_SUCCESS) return ret; @@ -1826,12 +1875,11 @@ INT32 fat_alloc_cluster(struct super_block *sb, INT32 num_alloc, CHAIN_T *p_chai else if (new_clu >= p_fs->num_clusters) new_clu = 2; - EXFAT_SB(sb)->s_dirt = 1; + __set_sb_dirty(sb); p_chain->dir = CLUSTER_32(~0); for (i = 2; i < p_fs->num_clusters; i++) { - /* if (FAT_read(sb, new_clu) == CLUSTER_32(0)) { */ if (FAT_read(sb, new_clu, &read_clu) != 0) return 0; @@ -1881,7 +1929,7 @@ INT32 exfat_alloc_cluster(struct super_block *sb, INT32 num_alloc, CHAIN_T *p_ch p_chain->flags = 0x01; } - EXFAT_SB(sb)->s_dirt = 1; + __set_sb_dirty(sb); p_chain->dir = CLUSTER_32(~0); @@ -1947,11 +1995,12 @@ void fat_free_cluster(struct super_block *sb, CHAIN_T *p_chain, INT32 do_relse) if ((p_chain->dir == CLUSTER_32(0)) || (p_chain->dir == CLUSTER_32(~0))) return; - - EXFAT_SB(sb)->s_dirt = 1; - + __set_sb_dirty(sb); clu = p_chain->dir; + if (p_chain->size <= 0) + return; + do { if (p_fs->dev_ejected) break; @@ -1987,8 +2036,14 @@ void exfat_free_cluster(struct super_block *sb, CHAIN_T *p_chain, INT32 do_relse if ((p_chain->dir == CLUSTER_32(0)) || (p_chain->dir == CLUSTER_32(~0))) return; - EXFAT_SB(sb)->s_dirt = 1; + if (p_chain->size <= 0) { + printk(KERN_ERR "[EXFAT] free_cluster : skip free-req clu:%u, " + "because of zero-size truncation\n" + ,p_chain->dir); + return; + } + __set_sb_dirty(sb); clu = p_chain->dir; if (p_chain->flags == 0x03) { @@ -2024,7 +2079,7 @@ void exfat_free_cluster(struct super_block *sb, CHAIN_T *p_chain, INT32 do_relse if (FAT_read(sb, clu, &clu) == -1) break; num_clusters++; - } while (clu != CLUSTER_32(~0)); + } while ((clu != CLUSTER_32(0)) && (clu != CLUSTER_32(~0))); } if (p_fs->used_clusters != (UINT32) ~0) @@ -2260,7 +2315,7 @@ INT32 clr_alloc_bitmap(struct super_block *sb, UINT32 clu) #else ret = sb_issue_discard(sb, START_SECTOR(clu), (1 << p_fs->sectors_per_clu_bits), GFP_NOFS, 0); #endif - if (ret == EOPNOTSUPP) { + if (ret == -EOPNOTSUPP) { printk(KERN_WARNING "discard not supported by device, disabling"); opts->discard = 0; } @@ -2331,7 +2386,7 @@ INT32 __load_upcase_table(struct super_block *sb, UINT32 sector, UINT32 num_sect BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); struct buffer_head *tmp_bh = NULL; - UINT8 skip = FALSE; + UINT8 skip = FALSE; UINT32 index = 0; UINT16 uni = 0; UINT16 **upcase_table; @@ -2407,7 +2462,7 @@ INT32 __load_default_upcase_table(struct super_block *sb) UINT32 j; FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); - UINT8 skip = FALSE; + UINT8 skip = FALSE; UINT32 index = 0; UINT16 uni = 0; UINT16 **upcase_table; @@ -3186,21 +3241,6 @@ INT32 find_location(struct super_block *sb, CHAIN_T *p_dir, INT32 entry, UINT32 *sector = off >> p_bd->sector_size_bits; *sector += p_fs->root_start_sector; } else { -/* - clu_offset = off >> p_fs->cluster_size_bits; - clu = p_dir->dir; - - if (p_dir->flags == 0x03) { - clu += clu_offset; - } else { - while (clu_offset > 0) { - //clu = FAT_read(sb, clu); - if (FAT_read(sb, clu, &clu) == -1) - return FFS_MEDIAERR; - clu_offset--; - } - } -*/ ret =_walk_fat_chain(sb, p_dir, off, &clu); if (ret != FFS_SUCCESS) return ret; @@ -3245,39 +3285,6 @@ DENTRY_T *get_entry_in_dir(struct super_block *sb, CHAIN_T *p_dir, INT32 entry, return((DENTRY_T *)(buf + off)); } /* end of get_entry_in_dir */ -/* -static DENTRY_T *__get_next_entry (struct super_block *sb, CHAIN_T *p_dir, INT32 entry, DENTRY_T *ep, INT32 *off) -{ - BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); - INT32 next_off, entry_off=1; - UINT32 sec; - UINT8 *buf; - - if (ep != NULL) { - next_off = (*off + sizeof(DENTRY_T)) & p_bd->sector_size_mask; - entry_off = entry + 1; - } else { - // special case: get the first ep with entry - entry_off = entry; - } - - if ((ep == NULL) || (next_off < *off)) { - // we should get next sector - if (find_location(sb, p_dir, entry_off, &sec, off) != FFS_SUCCESS) - return NULL; - buf = buf_getblk(sb, sec); - if (buf == NULL) - break; - ep = (DENTRY_T *)(buf + *off); - } else { - // next dentry is in the same sector - off += sizeof(DENTRY_T); - ep++; - } - - return ep; -} -*/ /* returns a set of dentries for a file or dir. * Note that this is a copy (dump) of dentries so that user should call write_entry_set() @@ -3312,14 +3319,12 @@ ENTRY_SET_CACHE_T *get_entry_set_in_dir (struct super_block *sb, CHAIN_T *p_dir, PRINTK("get_entry_set_in_dir entered\n"); PRINTK("p_dir dir %u flags %x size %d\n", p_dir->dir, p_dir->flags, p_dir->size); -// PRINTK("entry %d type %d\n", entry, type); byte_offset = entry << DENTRY_SIZE_BITS; ret =_walk_fat_chain(sb, p_dir, byte_offset, &clu); if (ret != FFS_SUCCESS) return NULL; -// PRINTK("clu %u\n", clu); byte_offset &= p_fs->cluster_size - 1; /* byte offset in cluster */ @@ -3331,12 +3336,10 @@ ENTRY_SET_CACHE_T *get_entry_set_in_dir (struct super_block *sb, CHAIN_T *p_dir, if (buf == NULL) goto err_out; -// PRINTK("buf %p off %d\n", buf, off); ep = (DENTRY_T *)(buf + off); entry_type = p_fs->fs_func->get_entry_type(ep); -// PRINTK("ep %p type %x\n", ep, entry_type); if ((entry_type != TYPE_FILE) && (entry_type != TYPE_DIR)) goto err_out; @@ -3358,13 +3361,12 @@ ENTRY_SET_CACHE_T *get_entry_set_in_dir (struct super_block *sb, CHAIN_T *p_dir, pos = (DENTRY_T *) &(es->__buf); -// PRINTK("entering while loop (%u)\n", num_entries); while(num_entries) { - // instead of copying whole sector, we will check every entry. - // this will provide minimum stablity and consistancy. + /* instead of copying whole sector, we will check every entry. + * this will provide minimum stablity and consistancy. + */ entry_type = p_fs->fs_func->get_entry_type(ep); -// PRINTK("ep %p entry type %x\n", ep, entry_type); if ((entry_type == TYPE_UNUSED) || (entry_type == TYPE_DELETED)) goto err_out; @@ -3412,7 +3414,7 @@ ENTRY_SET_CACHE_T *get_entry_set_in_dir (struct super_block *sb, CHAIN_T *p_dir, break; if (((off + DENTRY_SIZE) & p_bd->sector_size_mask) < (off & p_bd->sector_size_mask)) { - // get the next sector + /* get the next sector */ if (IS_LAST_SECTOR_IN_CLUSTER(sec)) { if (es->alloc_flag == 0x03) { clu++; @@ -3471,7 +3473,7 @@ static INT32 __write_partial_entries_in_entry_set (struct super_block *sb, ENTRY num_entries = count; while(num_entries) { - // white per sector base + /* white per sector base */ remaining_byte_in_sector = (1 << p_bd->sector_size_bits) - off; copy_entries = MIN(remaining_byte_in_sector>> DENTRY_SIZE_BITS , num_entries); buf = buf_getblk(sb, sec); @@ -3484,7 +3486,7 @@ static INT32 __write_partial_entries_in_entry_set (struct super_block *sb, ENTRY num_entries -= copy_entries; if (num_entries) { - // get next sector + /* get next sector */ if (IS_LAST_SECTOR_IN_CLUSTER(sec)) { clu = GET_CLUSTER_FROM_SECTOR(sec); if (es->alloc_flag == 0x03) { @@ -3524,13 +3526,13 @@ INT32 write_partial_entries_in_entry_set (struct super_block *sb, ENTRY_SET_CACH BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); CHAIN_T dir; - // vaidity check + /* vaidity check */ if (ep + count > ((DENTRY_T *)&(es->__buf)) + es->num_entries) return FFS_ERROR; dir.dir = GET_CLUSTER_FROM_SECTOR(es->sector); dir.flags = es->alloc_flag; - dir.size = 0xffffffff; // XXX + dir.size = 0xffffffff; /* XXX */ byte_offset = (es->sector - START_SECTOR(dir.dir)) << p_bd->sector_size_bits; byte_offset += ((INT32 *)ep - (INT32 *)&(es->__buf)) + es->offset; @@ -3631,7 +3633,6 @@ INT32 search_deleted_or_unused_entry(struct super_block *sb, CHAIN_T *p_dir, INT else clu.dir = CLUSTER_32(~0); } else { - //clu.dir = FAT_read(sb, clu.dir); if (FAT_read(sb, clu.dir, &(clu.dir)) != 0) return -1; } @@ -3810,7 +3811,6 @@ INT32 fat_find_dir_entry(struct super_block *sb, CHAIN_T *p_dir, UNI_NAME_T *p_u if (p_dir->dir == CLUSTER_32(0)) break; /* FAT16 root_dir */ - //clu.dir = FAT_read(sb, clu.dir); if (FAT_read(sb, clu.dir, &(clu.dir)) != 0) return -2; } @@ -3943,7 +3943,6 @@ INT32 exfat_find_dir_entry(struct super_block *sb, CHAIN_T *p_dir, UNI_NAME_T *p else clu.dir = CLUSTER_32(~0); } else { - //clu.dir = FAT_read(sb, clu.dir); if (FAT_read(sb, clu.dir, &(clu.dir)) != 0) return -2; } @@ -4054,7 +4053,6 @@ INT32 count_dos_name_entries(struct super_block *sb, CHAIN_T *p_dir, UINT32 type else clu.dir = CLUSTER_32(~0); } else { - //clu.dir = FAT_read(sb, clu.dir); if (FAT_read(sb, clu.dir, &(clu.dir)) != 0) return -1; } @@ -4116,7 +4114,6 @@ BOOL is_dir_empty(struct super_block *sb, CHAIN_T *p_dir) else clu.dir = CLUSTER_32(~0); } else { - //clu.dir = FAT_read(sb, clu.dir); if (FAT_read(sb, clu.dir, &(clu.dir)) != 0) break; } @@ -4211,8 +4208,12 @@ void exfat_get_uni_name_from_ext_entry(struct super_block *sb, CHAIN_T *p_dir, I FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); es = get_entry_set_in_dir(sb, p_dir, entry, ES_ALL_ENTRIES, &ep); - if (es == NULL || es->num_entries < 3) + if (es == NULL || es->num_entries < 3) { + if(es) { + release_entry_set(es); + } return; + } ep += 2; @@ -4226,7 +4227,7 @@ void exfat_get_uni_name_from_ext_entry(struct super_block *sb, CHAIN_T *p_dir, I if (p_fs->fs_func->get_entry_type(ep) == TYPE_EXTEND) { extract_uni_name_from_name_entry((NAME_DENTRY_T *)ep, uniname, i); } else { - // end of name entry + /* end of name entry */ goto out; } uniname += 15; @@ -4361,7 +4362,6 @@ INT32 fat_generate_dos_name(struct super_block *sb, CHAIN_T *p_dir, DOS_NAME_T * if (p_dir->dir == CLUSTER_32(0)) break; /* FAT16 root_dir */ - //clu.dir = FAT_read(sb, clu.dir); if (FAT_read(sb, clu.dir, &(clu.dir)) != 0) return FFS_MEDIAERR; } @@ -4510,32 +4510,19 @@ UINT32 calc_checksum_4byte(void *data, INT32 len, UINT32 chksum, INT32 type) < 0 : return error */ INT32 resolve_path(struct inode *inode, UINT8 *path, CHAIN_T *p_dir, UNI_NAME_T *p_uniname) { - INT32 num_names; INT32 lossy = FALSE; - UINT8 *name_ptr[MAX_PATH_DEPTH+1]; struct super_block *sb = inode->i_sb; FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); FILE_ID_T *fid = &(EXFAT_I(inode)->fid); - /* extract each names int the path */ - num_names = resolve_name(path, name_ptr); - if (num_names != 1) { - if (num_names < 0) - return ((-1) * num_names); - else - return FFS_INVALIDPATH; - } + if (STRLEN(path) >= (MAX_NAME_LENGTH * MAX_CHARSET_SIZE)) + return(FFS_INVALIDPATH); - /* the last name of the path */ - nls_cstring_to_uniname(sb, p_uniname, name_ptr[num_names-1], &lossy); - if (lossy == NLS_LOSSY_TOOLONG) - return FFS_NAMETOOLONG; - else if (lossy) - return FFS_INVALIDPATH; + STRCPY(name_buf, path); - /* check if this path name violates the name length limit */ - if (p_uniname->name_len >= MAX_NAME_LENGTH) - return FFS_NAMETOOLONG; + nls_cstring_to_uniname(sb, p_uniname, name_buf, &lossy); + if (lossy) + return(FFS_INVALIDPATH); fid->size = i_size_read(inode); @@ -4543,62 +4530,8 @@ INT32 resolve_path(struct inode *inode, UINT8 *path, CHAIN_T *p_dir, UNI_NAME_T p_dir->size = (INT32)(fid->size >> p_fs->cluster_size_bits); p_dir->flags = fid->flags; - return FFS_SUCCESS; -} /* end of resolve_path */ - -INT32 resolve_name(UINT8 *name, UINT8 **arg) -{ - INT32 i = 0, narg = 0; - UINT8 *src, *dst; - - src = name; - dst = name_buf; - - while ((*src == ' ') || (*src == '\t')) { - if ((++i) >= (MAX_PATH_LENGTH*MAX_CHARSET_SIZE)) - return -FFS_NAMETOOLONG; - src++; - } - - if (*src == '\0') - return(-FFS_INVALIDPATH); /* resolve fail */ - - if ((*src == '/') || (*src == '\\')) { - arg[narg++] = dst; - if ((++i) >= (MAX_PATH_LENGTH*MAX_CHARSET_SIZE)) - return(-FFS_NAMETOOLONG); - *dst++ = '.'; - src++; - *dst++ = '\0'; - } - - while (1) { - while ((*src == ' ') || (*src == '\t') || - (*src == '/') || (*src == '\\')) { - if ((++i) >= (MAX_PATH_LENGTH*MAX_CHARSET_SIZE)) - return(-FFS_NAMETOOLONG); - src++; - } - - if (*src == '\0') - break; - if (narg > MAX_PATH_DEPTH) - return(-FFS_INVALIDPATH); - - arg[narg++] = dst; - while ((*src != '/') && (*src != '\\') && (*src != '\0')) { - if ((++i) >= (MAX_PATH_LENGTH*MAX_CHARSET_SIZE)) - return(-FFS_NAMETOOLONG); - *dst++ = *src++; - } - - while (*(dst-1) == ' ') - dst--; - *dst++ = '\0'; - } - - return(narg); -} /* end of resolve_name */ + return(FFS_SUCCESS); +} /* * File Operation Functions @@ -5169,7 +5102,7 @@ INT32 sector_read(struct super_block *sb, UINT32 sec, struct buffer_head **bh, I FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); if ((sec >= (p_fs->PBR_sector+p_fs->num_sectors)) && (p_fs->num_sectors > 0)) { - PRINT("sector_read: out of range error! (sec = %d)\n", sec); + PRINT("[EXFAT] sector_read: out of range error! (sec = %d)\n", sec); fs_error(sb); return ret; } @@ -5189,17 +5122,19 @@ INT32 sector_write(struct super_block *sb, UINT32 sec, struct buffer_head *bh, I FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); if (sec >= (p_fs->PBR_sector+p_fs->num_sectors) && (p_fs->num_sectors > 0)) { - PRINT("sector_write: out of range error! (sec = %d)\n", sec); + PRINT("[EXFAT] sector_write: out of range error! (sec = %d)\n", sec); fs_error(sb); + return ret; } if (bh == NULL) { - PRINT("sector_write: bh is NULL!\n"); + PRINT("[EXFAT] sector_write: bh is NULL!\n"); fs_error(sb); + return ret; } if (!p_fs->dev_ejected) { ret = bdev_write(sb, sec, bh, 1, sync); - if (ret) + if (ret != FFS_SUCCESS) p_fs->dev_ejected = TRUE; } @@ -5212,8 +5147,9 @@ INT32 multi_sector_read(struct super_block *sb, UINT32 sec, struct buffer_head * FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); if (((sec+num_secs) > (p_fs->PBR_sector+p_fs->num_sectors)) && (p_fs->num_sectors > 0)) { - PRINT("multi_sector_read: out of range error! (sec = %d, num_secs = %d)\n", sec, num_secs); + PRINT("[EXFAT] multi_sector_read: out of range error! (sec = %d, num_secs = %d)\n", sec, num_secs); fs_error(sb); + return ret; } if (!p_fs->dev_ejected) { @@ -5231,12 +5167,14 @@ INT32 multi_sector_write(struct super_block *sb, UINT32 sec, struct buffer_head FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); if ((sec+num_secs) > (p_fs->PBR_sector+p_fs->num_sectors) && (p_fs->num_sectors > 0)) { - PRINT("multi_sector_write: out of range error! (sec = %d, num_secs = %d)\n", sec, num_secs); + PRINT("[EXFAT] multi_sector_write: out of range error! (sec = %d, num_secs = %d)\n", sec, num_secs); fs_error(sb); + return ret; } if (bh == NULL) { - PRINT("multi_sector_write: bh is NULL!\n"); + PRINT("[EXFAT] multi_sector_write: bh is NULL!\n"); fs_error(sb); + return ret; } if (!p_fs->dev_ejected) { @@ -5248,4 +5186,4 @@ INT32 multi_sector_write(struct super_block *sb, UINT32 sec, struct buffer_head return ret; } /* end of multi_sector_write */ -/* end of exfat.c */ +/* end of exfat_core.c */ diff --git a/exfat_data.c b/exfat_data.c index f367684..37e1932 100644 --- a/exfat_data.c +++ b/exfat_data.c @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + /************************************************************************/ /* */ /* PROJECT : exFAT & FAT12/16/32 File System */ diff --git a/exfat_data.h b/exfat_data.h index da79dff..e99551d 100644 --- a/exfat_data.h +++ b/exfat_data.h @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + /************************************************************************/ /* */ /* PROJECT : exFAT & FAT12/16/32 File System */ @@ -51,10 +69,6 @@ extern "C" { #define BUF_CACHE_SIZE 256 #define BUF_CACHE_HASH_SIZE 64 - /* default mount options */ -#define DEFAULT_CODEPAGE 437 -#define DEFAULT_IOCHARSET "utf8" - #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/exfat_global.c b/exfat_global.c index 7af55cc..036f08e 100644 --- a/exfat_global.c +++ b/exfat_global.c @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + /************************************************************************/ /* */ /* PROJECT : exFAT & FAT12/16/32 File System */ @@ -34,7 +52,7 @@ INT32 __wstrchr(UINT16 *str, UINT16 wchar) { - while (*str) { + while (*str) { if (*(str++) == wchar) return(1); } return(0); diff --git a/exfat_global.h b/exfat_global.h index 67fb26b..890bd39 100644 --- a/exfat_global.h +++ b/exfat_global.h @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + /************************************************************************/ /* */ /* PROJECT : exFAT & FAT12/16/32 File System */ @@ -139,16 +157,9 @@ extern "C" { /* EXFAT_CONFIG_DEBUG_MSG is configured in exfat_config.h */ /*----------------------------------------------------------------------*/ #if EXFAT_CONFIG_DEBUG_MSG -#if 0 -#define PRINTK(...) \ - do { \ - printk ("%u: ", dbg_count); \ - printk(__VA_ARGS__); \ - } while(0) -#endif #define PRINTK(...) \ do { \ - printk(__VA_ARGS__); \ + printk("[EXFAT] " __VA_ARGS__); \ } while(0) #else #define PRINTK(...) diff --git a/exfat_nls.c b/exfat_nls.c index 3017ab2..f80af8b 100644 --- a/exfat_nls.c +++ b/exfat_nls.c @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + /************************************************************************/ /* */ /* PROJECT : exFAT & FAT12/16/32 File System */ @@ -269,25 +287,22 @@ void nls_uniname_to_cstring(struct super_block *sb, UINT8 *p_cstring, UNI_NAME_T void nls_cstring_to_uniname(struct super_block *sb, UNI_NAME_T *p_uniname, UINT8 *p_cstring, INT32 *p_lossy) { - INT32 i, j, lossy = 0; + INT32 i, j, lossy = FALSE; UINT8 *end_of_name; UINT8 upname[MAX_NAME_LENGTH * 2]; UINT16 *uniname = p_uniname->name; struct nls_table *nls = EXFAT_SB(sb)->nls_io; - /* strip all leading spaces */ - while (*p_cstring == ' ') p_cstring++; /* strip all trailing spaces */ - end_of_name = p_cstring + STRLEN(p_cstring); + end_of_name = p_cstring + STRLEN((INT8 *) p_cstring); while (*(--end_of_name) == ' ') { if (end_of_name < p_cstring) break; } *(++end_of_name) = '\0'; - if (STRCMP(p_cstring, ".") && STRCMP(p_cstring, "..")) { - //if (*p_cstring == '.') lossy = TRUE; + if (STRCMP((INT8 *) p_cstring, ".") && STRCMP((INT8 *) p_cstring, "..")) { /* strip all trailing periods */ while (*(--end_of_name) == '.') { @@ -297,7 +312,7 @@ void nls_cstring_to_uniname(struct super_block *sb, UNI_NAME_T *p_uniname, UINT8 } if (*p_cstring == '\0') - SET_LOSSY(lossy, NLS_LOSSY_TOOSHORT); + lossy = TRUE; i = j = 0; while (j < (MAX_NAME_LENGTH-1)) { @@ -306,7 +321,7 @@ void nls_cstring_to_uniname(struct super_block *sb, UNI_NAME_T *p_uniname, UINT8 i += convert_ch_to_uni(nls, uniname, (UINT8 *)(p_cstring+i), &lossy); if ((*uniname < 0x0020) || WSTRCHR(bad_uni_chars, *uniname)) - SET_LOSSY(lossy, NLS_LOSSY_ERROR); + lossy = TRUE; SET16_A(upname + j * 2, nls_upper(sb, *uniname)); @@ -315,13 +330,14 @@ void nls_cstring_to_uniname(struct super_block *sb, UNI_NAME_T *p_uniname, UINT8 } if (*(p_cstring+i) != '\0') - SET_LOSSY(lossy, NLS_LOSSY_TOOLONG); + lossy = TRUE; *uniname = (UINT16) '\0'; p_uniname->name_len = j; p_uniname->name_hash = calc_checksum_2byte((void *) upname, j<<1, 0, CS_DEFAULT); - if (p_lossy != NULL) *p_lossy = lossy; + if (p_lossy != NULL) + *p_lossy = lossy; } /* end of nls_cstring_to_uniname */ /*======================================================================*/ @@ -343,7 +359,7 @@ static INT32 convert_ch_to_uni(struct nls_table *nls, UINT16 *uni, UINT8 *ch, IN /* conversion failed */ printk("%s: fail to use nls \n", __func__); if (lossy != NULL) - SET_LOSSY(*lossy, NLS_LOSSY_CHAR_TO_UNI_ERROR); + *lossy = TRUE; *uni = (UINT16) '_'; if (!strcmp(nls->charset, "utf8")) return(1); else return(2); diff --git a/exfat_nls.h b/exfat_nls.h index 571b9c3..5b14cef 100644 --- a/exfat_nls.h +++ b/exfat_nls.h @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + /************************************************************************/ /* */ /* PROJECT : exFAT & FAT12/16/32 File System */ @@ -44,45 +62,35 @@ extern "C" { #define UNI_PAR_DIR_NAME "\0.\0." #endif -#define NLS_LOSSY_TOOSHORT 1 -#define NLS_LOSSY_TOOLONG 2 -#define NLS_LOSSY_CHAR_TO_UNI_ERROR 3 -#define NLS_LOSSY_ERROR 4 // generic error code - -#define SET_LOSSY(lossy, value) \ - do { \ - if (lossy == 0) lossy = value; \ - } while(0) \ - - /*----------------------------------------------------------------------*/ - /* Type Definitions */ - /*----------------------------------------------------------------------*/ +/*----------------------------------------------------------------------*/ +/* Type Definitions */ +/*----------------------------------------------------------------------*/ - /* DOS name stucture */ - typedef struct { - UINT8 name[DOS_NAME_LENGTH]; - UINT8 name_case; - } DOS_NAME_T; +/* DOS name stucture */ +typedef struct { + UINT8 name[DOS_NAME_LENGTH]; + UINT8 name_case; +} DOS_NAME_T; - /* unicode name stucture */ - typedef struct { - UINT16 name[MAX_NAME_LENGTH]; - UINT16 name_hash; - UINT8 name_len; - } UNI_NAME_T; +/* unicode name stucture */ +typedef struct { + UINT16 name[MAX_NAME_LENGTH]; + UINT16 name_hash; + UINT8 name_len; +} UNI_NAME_T; - /*----------------------------------------------------------------------*/ - /* External Function Declarations */ - /*----------------------------------------------------------------------*/ +/*----------------------------------------------------------------------*/ +/* External Function Declarations */ +/*----------------------------------------------------------------------*/ - /* NLS management function */ - UINT16 nls_upper(struct super_block *sb, UINT16 a); - INT32 nls_dosname_cmp(struct super_block *sb, UINT8 *a, UINT8 *b); - INT32 nls_uniname_cmp(struct super_block *sb, UINT16 *a, UINT16 *b); - void nls_uniname_to_dosname(struct super_block *sb, DOS_NAME_T *p_dosname, UNI_NAME_T *p_uniname, INT32 *p_lossy); - void nls_dosname_to_uniname(struct super_block *sb, UNI_NAME_T *p_uniname, DOS_NAME_T *p_dosname); - void nls_uniname_to_cstring(struct super_block *sb, UINT8 *p_cstring, UNI_NAME_T *p_uniname); - void nls_cstring_to_uniname(struct super_block *sb, UNI_NAME_T *p_uniname, UINT8 *p_cstring, INT32 *p_lossy); +/* NLS management function */ +UINT16 nls_upper(struct super_block *sb, UINT16 a); +INT32 nls_dosname_cmp(struct super_block *sb, UINT8 *a, UINT8 *b); +INT32 nls_uniname_cmp(struct super_block *sb, UINT16 *a, UINT16 *b); +void nls_uniname_to_dosname(struct super_block *sb, DOS_NAME_T *p_dosname, UNI_NAME_T *p_uniname, INT32 *p_lossy); +void nls_dosname_to_uniname(struct super_block *sb, UNI_NAME_T *p_uniname, DOS_NAME_T *p_dosname); +void nls_uniname_to_cstring(struct super_block *sb, UINT8 *p_cstring, UNI_NAME_T *p_uniname); +void nls_cstring_to_uniname(struct super_block *sb, UNI_NAME_T *p_uniname, UINT8 *p_cstring, INT32 *p_lossy); #ifdef __cplusplus } diff --git a/exfat_oal.c b/exfat_oal.c index 667fc2b..8d1a9b9 100644 --- a/exfat_oal.c +++ b/exfat_oal.c @@ -1,3 +1,30 @@ +/* Some of the source code in this file came from "linux/fs/fat/misc.c". */ +/* + * linux/fs/fat/misc.c + * + * Written 1992,1993 by Werner Almesberger + * 22/11/2000 - Fixed fat_date_unix2dos for dates earlier than 01/01/1980 + * and date_dos2unix for date==0 by Igor Zhbanov(bsg@uniyar.ac.ru) + */ + +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + /************************************************************************/ /* */ /* PROJECT : exFAT & FAT12/16/32 File System */ @@ -33,7 +60,7 @@ DECLARE_MUTEX(z_sem); INT32 sm_init(struct semaphore *sm) { - sema_init(sm, 1); + sema_init(sm, 1); return(0); } /* end of sm_init */ @@ -67,21 +94,31 @@ extern struct timezone sys_tz; * time: 5 - 10: min (0 - 59) * time: 11 - 15: hour (0 - 23) */ -#define SECS_PER_MIN (60) -#define SECS_PER_HOUR (60 * 60) -#define SECS_PER_DAY (SECS_PER_HOUR * 24) #define UNIX_SECS_1980 315532800L + #if BITS_PER_LONG == 64 #define UNIX_SECS_2108 4354819200L #endif /* days between 1.1.70 and 1.1.80 (2 leap days) */ -#define DAYS_DELTA (365 * 10 + 2) +#define DAYS_DELTA_DECADE (365 * 10 + 2) /* 120 (2100 - 1980) isn't leap year */ -#define YEAR_2100 120 -#define IS_LEAP_YEAR(y) (!((y) & 3) && (y) != YEAR_2100) +#define NO_LEAP_YEAR_2100 (120) +#define IS_LEAP_YEAR(y) (!((y) & 3) && (y) != NO_LEAP_YEAR_2100) + +#define SECS_PER_MIN (60) +#define SECS_PER_HOUR (60 * SECS_PER_MIN) +#define SECS_PER_DAY (24 * SECS_PER_HOUR) + +#define MAKE_LEAP_YEAR(leap_year, year) \ + do { \ + if (unlikely(year > NO_LEAP_YEAR_2100)) \ + leap_year = ((year + 3) / 4) - 1; \ + else \ + leap_year = ((year + 3) / 4); \ + } while(0) /* Linear day numbers of the respective 1sts in non-leap years. */ -static time_t days_in_year[] = { +static time_t accum_days_in_year[] = { /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */ 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, }; @@ -116,29 +153,28 @@ TIMESTAMP_T *tm_current(TIMESTAMP_T *tp) } #endif - day = second / SECS_PER_DAY - DAYS_DELTA; + day = second / SECS_PER_DAY - DAYS_DELTA_DECADE; year = day / 365; - leap_day = (year + 3) / 4; - if (year > YEAR_2100) /* 2100 isn't leap year */ - leap_day--; + + MAKE_LEAP_YEAR(leap_day, year); if (year * 365 + leap_day > day) year--; - leap_day = (year + 3) / 4; - if (year > YEAR_2100) /* 2100 isn't leap year */ - leap_day--; + + MAKE_LEAP_YEAR(leap_day, year); + day -= year * 365 + leap_day; - if (IS_LEAP_YEAR(year) && day == days_in_year[3]) { + if (IS_LEAP_YEAR(year) && day == accum_days_in_year[3]) { month = 2; } else { - if (IS_LEAP_YEAR(year) && day > days_in_year[3]) + if (IS_LEAP_YEAR(year) && day > accum_days_in_year[3]) day--; for (month = 1; month < 12; month++) { - if (days_in_year[month + 1] > day) + if (accum_days_in_year[month + 1] > day) break; } } - day -= days_in_year[month]; + day -= accum_days_in_year[month]; tp->sec = second % SECS_PER_MIN; tp->min = (second / SECS_PER_MIN) % 60; diff --git a/exfat_oal.h b/exfat_oal.h index 6982296..ca3f956 100644 --- a/exfat_oal.h +++ b/exfat_oal.h @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + /************************************************************************/ /* */ /* PROJECT : exFAT & FAT12/16/32 File System */ diff --git a/exfat_part.h b/exfat_part.h index 269e45d..94dd886 100644 --- a/exfat_part.h +++ b/exfat_part.h @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + /************************************************************************/ /* */ /* PROJECT : exFAT & FAT12/16/32 File System */ diff --git a/exfat_super.c b/exfat_super.c index f39898b..784fb95 100644 --- a/exfat_super.c +++ b/exfat_super.c @@ -1,3 +1,50 @@ +/* Some of the source code in this file came from "linux/fs/fat/file.c","linux/fs/fat/inode.c" and "linux/fs/fat/misc.c". */ +/* + * linux/fs/fat/file.c + * + * Written 1992,1993 by Werner Almesberger + * + * regular file handling primitives for fat-based filesystems + */ + +/* + * linux/fs/fat/inode.c + * + * Written 1992,1993 by Werner Almesberger + * VFAT extensions by Gordon Chaffee, merged with msdos fs by Henrik Storner + * Rewritten for the constant inumbers support by Al Viro + * + * Fixes: + * + * Max Cohan: Fixed invalid FSINFO offset when info_sector is 0 + */ + +/* + * linux/fs/fat/misc.c + * + * Written 1992,1993 by Werner Almesberger + * 22/11/2000 - Fixed fat_date_unix2dos for dates earlier than 01/01/1980 + * and date_dos2unix for date==0 by Igor Zhbanov(bsg@uniyar.ac.ru) + */ + +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + #include #include #include @@ -45,12 +92,13 @@ static struct kmem_cache *exfat_inode_cachep; -static int exfat_default_codepage = DEFAULT_CODEPAGE; -static char exfat_default_iocharset[] = DEFAULT_IOCHARSET; +static int exfat_default_codepage = CONFIG_EXFAT_DEFAULT_CODEPAGE; +static char exfat_default_iocharset[] = CONFIG_EXFAT_DEFAULT_IOCHARSET; extern struct timezone sys_tz; -#define ELAPSED_TIME 0 +#define CHECK_ERR(x) BUG_ON(x) +#define ELAPSED_TIME 0 #if (ELAPSED_TIME == 1) #include @@ -71,46 +119,52 @@ static UINT32 get_current_msec(void) #define PRINT_TIME(n) #endif -#define SECS_PER_MIN (60) -#define SECS_PER_HOUR (SECS_PER_MIN * 60) -#define SECS_PER_DAY (SECS_PER_HOUR * 24) #define UNIX_SECS_1980 315532800L + #if BITS_PER_LONG == 64 #define UNIX_SECS_2108 4354819200L #endif /* days between 1.1.70 and 1.1.80 (2 leap days) */ -#define DAYS_DELTA (365 * 10 + 2) +#define DAYS_DELTA_DECADE (365 * 10 + 2) /* 120 (2100 - 1980) isn't leap year */ -#define YEAR_2100 120 -#define IS_LEAP_YEAR(y) (!((y) & 3) && (y) != YEAR_2100) +#define NO_LEAP_YEAR_2100 (120) +#define IS_LEAP_YEAR(y) (!((y) & 0x3) && (y) != NO_LEAP_YEAR_2100) + +#define SECS_PER_MIN (60) +#define SECS_PER_HOUR (60 * SECS_PER_MIN) +#define SECS_PER_DAY (24 * SECS_PER_HOUR) + +#define MAKE_LEAP_YEAR(leap_year, year) \ + do { \ + if (unlikely(year > NO_LEAP_YEAR_2100)) \ + leap_year = ((year + 3) / 4) - 1; \ + else \ + leap_year = ((year + 3) / 4); \ + } while(0) /* Linear day numbers of the respective 1sts in non-leap years. */ -static time_t days_in_year[] = { +static time_t accum_days_in_year[] = { /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */ 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, }; -static void exfat_truncate(struct inode *inode); +static void _exfat_truncate(struct inode *inode, loff_t old_size); /* Convert a FAT time/date pair to a UNIX date (seconds since 1 1 70). */ void exfat_time_fat2unix(struct exfat_sb_info *sbi, struct timespec *ts, DATE_TIME_T *tp) { - time_t leap_day, year = tp->Year; + time_t year = tp->Year; + time_t ld; - leap_day = (year + 3) / 4; - if (year > YEAR_2100) /* 2100 isn't leap year */ - leap_day = ((year + 3) / 4) - 1; - else - leap_day = ((year + 3) / 4); + MAKE_LEAP_YEAR(ld, year); if (IS_LEAP_YEAR(year) && (tp->Month) > 2) - leap_day++; + ld++; - ts->tv_sec = tp->Second - + tp->Minute * SECS_PER_MIN + ts->tv_sec = tp->Second + tp->Minute * SECS_PER_MIN + tp->Hour * SECS_PER_HOUR - + (year * 365 + leap_day + days_in_year[(tp->Month)] + (tp->Day - 1) + DAYS_DELTA) * SECS_PER_DAY + + (year * 365 + ld + accum_days_in_year[(tp->Month)] + (tp->Day - 1) + DAYS_DELTA_DECADE) * SECS_PER_DAY + sys_tz.tz_minuteswest * SECS_PER_MIN; ts->tv_nsec = 0; } @@ -120,7 +174,8 @@ void exfat_time_unix2fat(struct exfat_sb_info *sbi, struct timespec *ts, DATE_TIME_T *tp) { time_t second = ts->tv_sec; - time_t day, leap_day, month, year; + time_t day, month, year; + time_t ld; second -= sys_tz.tz_minuteswest * SECS_PER_MIN; @@ -134,7 +189,7 @@ void exfat_time_unix2fat(struct exfat_sb_info *sbi, struct timespec *ts, tp->Year = 0; return; } -#if BITS_PER_LONG == 64 +#if (BITS_PER_LONG == 64) if (second >= UNIX_SECS_2108) { tp->Second = 59; tp->Minute = 59; @@ -145,30 +200,26 @@ void exfat_time_unix2fat(struct exfat_sb_info *sbi, struct timespec *ts, return; } #endif - - day = second / SECS_PER_DAY - DAYS_DELTA; + day = second / SECS_PER_DAY - DAYS_DELTA_DECADE; year = day / 365; - leap_day = (year + 3) / 4; - if (year > YEAR_2100) /* 2100 isn't leap year */ - leap_day--; - if (year * 365 + leap_day > day) + MAKE_LEAP_YEAR(ld, year); + if (year * 365 + ld > day) year--; - leap_day = (year + 3) / 4; - if (year > YEAR_2100) /* 2100 isn't leap year */ - leap_day--; - day -= year * 365 + leap_day; - if (IS_LEAP_YEAR(year) && day == days_in_year[3]) { + MAKE_LEAP_YEAR(ld, year); + day -= year * 365 + ld; + + if (IS_LEAP_YEAR(year) && day == accum_days_in_year[3]) { month = 2; } else { - if (IS_LEAP_YEAR(year) && day > days_in_year[3]) + if (IS_LEAP_YEAR(year) && day > accum_days_in_year[3]) day--; for (month = 1; month < 12; month++) { - if (days_in_year[month + 1] > day) + if (accum_days_in_year[month + 1] > day) break; } } - day -= days_in_year[month]; + day -= accum_days_in_year[month]; tp->Second = second % SECS_PER_MIN; tp->Minute = (second / SECS_PER_MIN) % 60; @@ -192,6 +243,46 @@ static inline unsigned long exfat_hash(loff_t i_pos); static int exfat_write_inode(struct inode *inode, struct writeback_control *wbc); static void exfat_write_super(struct super_block *sb); +static void __lock_super(struct super_block *sb) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) + lock_super(sb); +#else + struct exfat_sb_info *sbi = EXFAT_SB(sb); + mutex_lock(&sbi->s_lock); +#endif +} + +static void __unlock_super(struct super_block *sb) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) + unlock_super(sb); +#else + struct exfat_sb_info *sbi = EXFAT_SB(sb); + mutex_unlock(&sbi->s_lock); +#endif +} + +static int __is_sb_dirty(struct super_block *sb) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) + return sb->s_dirt; +#else + struct exfat_sb_info *sbi = EXFAT_SB(sb); + return sbi->s_dirt; +#endif +} + +static void __set_sb_clean(struct super_block *sb) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) + sb->s_dirt = 0; +#else + struct exfat_sb_info *sbi = EXFAT_SB(sb); + sbi->s_dirt = 0; +#endif +} + /*======================================================================*/ /* Directory Entry Operations */ /*======================================================================*/ @@ -208,7 +299,7 @@ static int exfat_readdir(struct file *filp, void *dirent, filldir_t filldir) loff_t cpos; int err = 0; - mutex_lock(&sbi->s_lock); + __lock_super(sb); cpos = filp->f_pos; /* Fake . and .. for the root directory. */ @@ -241,8 +332,9 @@ static int exfat_readdir(struct file *filp, void *dirent, filldir_t filldir) err = FsReadDir(inode, &de); if (err) { - // at least we tried to read a sector - // move cpos to next sector position (should be aligned) + /* at least we tried to read a sector + * move cpos to next sector position (should be aligned) + */ if (err == FFS_MEDIAERR) { cpos += 1 << p_bd->sector_size_bits; cpos &= ~((1 << p_bd->sector_size_bits)-1); @@ -284,7 +376,7 @@ static int exfat_readdir(struct file *filp, void *dirent, filldir_t filldir) end_of_dir: filp->f_pos = cpos; out: - mutex_unlock(&sbi->s_lock); + __unlock_super(sb); return err; } @@ -333,9 +425,9 @@ static long exfat_generic_ioctl(struct file *filp, if (get_user(flags, (int __user *) arg)) return -EFAULT; - mutex_lock(&sbi->s_lock); + __lock_super(sb); sbi->debug_flags = flags; - mutex_unlock(&sbi->s_lock); + __unlock_super(sb); return 0; } @@ -372,8 +464,16 @@ const struct file_operations exfat_dir_operations = { #endif }; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,00) static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,00) +static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, + struct nameidata *nd) +#else +static int exfat_create(struct inode *dir, struct dentry *dentry, int mode, + struct nameidata *nd) +#endif { struct super_block *sb = dir->i_sb; struct inode *inode; @@ -382,7 +482,7 @@ static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, loff_t i_pos; int err; - mutex_lock(&EXFAT_SB(sb)->s_lock); + __lock_super(sb); PRINTK("exfat_create entered\n"); @@ -424,7 +524,7 @@ static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, d_instantiate(dentry, inode); out: - mutex_unlock(&EXFAT_SB(sb)->s_lock); + __unlock_super(sb); PRINTK("exfat_create exited\n"); return err; } @@ -444,18 +544,29 @@ static int exfat_find(struct inode *dir, struct qstr *qname, return 0; } +static int exfat_d_anon_disconn(struct dentry *dentry) +{ + return IS_ROOT(dentry) && (dentry->d_flags & DCACHE_DISCONNECTED); +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,00) +static struct dentry *exfat_lookup(struct inode *dir, struct dentry *dentry, + unsigned int flags) +#else static struct dentry *exfat_lookup(struct inode *dir, struct dentry *dentry, - unsigned int flags) { + struct nameidata *nd) +#endif +{ struct super_block *sb = dir->i_sb; struct inode *inode; struct dentry *alias; + int err; FILE_ID_T fid; loff_t i_pos; - int err; UINT64 ret; mode_t i_mode; - mutex_lock(&EXFAT_SB(sb)->s_lock); + __lock_super(sb); PRINTK("exfat_lookup entered\n"); err = exfat_find(dir, &dentry->d_name, &fid); if (err) { @@ -467,7 +578,6 @@ static struct dentry *exfat_lookup(struct inode *dir, struct dentry *dentry, } i_pos = ((loff_t) fid.dir.dir << 32) | (fid.entry & 0xffffffff); - inode = exfat_build_inode(sb, &fid, i_pos); if (IS_ERR(inode)) { err = PTR_ERR(inode); @@ -486,32 +596,37 @@ static struct dentry *exfat_lookup(struct inode *dir, struct dentry *dentry, } alias = d_find_alias(inode); - if (!alias) - goto out; - - if (!(alias->d_flags &DCACHE_DISCONNECTED)) { - BUG_ON(d_unhashed(alias)); + if (alias && !exfat_d_anon_disconn(alias)) { + CHECK_ERR(d_unhashed(alias)); if (!S_ISDIR(i_mode)) d_move(alias, dentry); iput(inode); - mutex_unlock(&EXFAT_SB(sb)->s_lock); + __unlock_super(sb); PRINTK("exfat_lookup exited 1\n"); return alias; + } else { + dput(alias); } out: - mutex_unlock(&EXFAT_SB(sb)->s_lock); + __unlock_super(sb); dentry->d_time = dentry->d_parent->d_inode->i_version; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) dentry->d_op = sb->s_root->d_op; dentry = d_splice_alias(inode, dentry); if (dentry) { dentry->d_op = sb->s_root->d_op; dentry->d_time = dentry->d_parent->d_inode->i_version; } +#else + dentry = d_splice_alias(inode, dentry); + if (dentry) + dentry->d_time = dentry->d_parent->d_inode->i_version; +#endif PRINTK("exfat_lookup exited 2\n"); return dentry; error: - mutex_unlock(&EXFAT_SB(sb)->s_lock); + __unlock_super(sb); PRINTK("exfat_lookup exited 3\n"); return ERR_PTR(err); } @@ -523,7 +638,7 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry) struct timespec ts; int err; - mutex_lock(&EXFAT_SB(sb)->s_lock); + __lock_super(sb); PRINTK("exfat_unlink entered\n"); @@ -549,20 +664,10 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry) clear_nlink(inode); inode->i_mtime = inode->i_atime = ts; exfat_detach(inode); -/* - { - struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); - - spin_lock(&sbi->inode_hash_lock); - EXFAT_I(inode)->i_pos = 0; - hlist_del_init(&EXFAT_I(inode)->i_fat_hash); - spin_unlock(&sbi->inode_hash_lock); - } -*/ remove_inode_hash(inode); out: - mutex_unlock(&EXFAT_SB(sb)->s_lock); + __unlock_super(sb); PRINTK("exfat_unlink exited\n"); return err; } @@ -578,7 +683,7 @@ static int exfat_symlink(struct inode *dir, struct dentry *dentry, const char *t UINT64 len = (UINT64) strlen(target); UINT64 ret; - mutex_lock(&EXFAT_SB(sb)->s_lock); + __lock_super(sb); PRINTK("exfat_symlink entered\n"); @@ -638,12 +743,16 @@ static int exfat_symlink(struct inode *dir, struct dentry *dentry, const char *t d_instantiate(dentry, inode); out: - mutex_unlock(&EXFAT_SB(sb)->s_lock); + __unlock_super(sb); PRINTK("exfat_symlink exited\n"); return err; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,00) static int exfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) +#else +static int exfat_mkdir(struct inode *dir, struct dentry *dentry, int mode) +#endif { struct super_block *sb = dir->i_sb; struct inode *inode; @@ -652,7 +761,7 @@ static int exfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) loff_t i_pos; int err; - mutex_lock(&EXFAT_SB(sb)->s_lock); + __lock_super(sb); PRINTK("exfat_mkdir entered\n"); @@ -695,7 +804,7 @@ static int exfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) d_instantiate(dentry, inode); out: - mutex_unlock(&EXFAT_SB(sb)->s_lock); + __unlock_super(sb); PRINTK("exfat_mkdir exited\n"); return err; } @@ -707,7 +816,7 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry) struct timespec ts; int err; - mutex_lock(&EXFAT_SB(sb)->s_lock); + __lock_super(sb); PRINTK("exfat_rmdir entered\n"); @@ -739,22 +848,11 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry) clear_nlink(inode); inode->i_mtime = inode->i_atime = ts; - exfat_detach(inode); -/* - { - struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); - - spin_lock(&sbi->inode_hash_lock); - EXFAT_I(inode)->i_pos = 0; - hlist_del_init(&EXFAT_I(inode)->i_fat_hash); - spin_unlock(&sbi->inode_hash_lock); - } -*/ remove_inode_hash(inode); out: - mutex_unlock(&EXFAT_SB(sb)->s_lock); + __unlock_super(sb); PRINTK("exfat_rmdir exited\n"); return err; } @@ -768,7 +866,7 @@ static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry, loff_t i_pos; int err; - mutex_lock(&EXFAT_SB(sb)->s_lock); + __lock_super(sb); PRINTK("exfat_rename entered\n"); @@ -806,29 +904,7 @@ static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry, (EXFAT_I(old_inode)->fid.entry & 0xffffffff); exfat_detach(old_inode); -/* - { - struct exfat_sb_info *sbi = EXFAT_SB(old_inode->i_sb); - - spin_lock(&sbi->inode_hash_lock); - EXFAT_I(old_inode)->i_pos = 0; - hlist_del_init(&EXFAT_I(old_inode)->i_fat_hash); - spin_unlock(&sbi->inode_hash_lock); - } -*/ - exfat_attach(old_inode, i_pos); -/* - { - struct exfat_sb_info *sbi = EXFAT_SB(old_inode->i_sb); - struct hlist_head *head = sbi->inode_hashtable + exfat_hash(i_pos); - - spin_lock(&sbi->inode_hash_lock); - EXFAT_I(old_inode)->i_pos = i_pos; - hlist_add_head(&EXFAT_I(old_inode)->i_fat_hash, head); - spin_unlock(&sbi->inode_hash_lock); - } -*/ if (IS_DIRSYNC(new_dir)) (void) exfat_sync_inode(old_inode); else @@ -847,27 +923,15 @@ static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry, mark_inode_dirty(old_dir); if (new_inode) { - exfat_detach(new_inode); -/* - { - struct exfat_sb_info *sbi = EXFAT_SB(new_inode->i_sb); - - spin_lock(&sbi->inode_hash_lock); - EXFAT_I(new_inode)->i_pos = 0; - hlist_del_init(&EXFAT_I(new_inode)->i_fat_hash); - spin_unlock(&sbi->inode_hash_lock); - } -*/ drop_nlink(new_inode); if (S_ISDIR(new_inode->i_mode)) drop_nlink(new_inode); new_inode->i_ctime = ts; - //(void) exfat_sync_inode(new_inode); } out: - mutex_unlock(&EXFAT_SB(sb)->s_lock); + __unlock_super(sb); PRINTK("exfat_rename exited\n"); return err; } @@ -957,6 +1021,7 @@ static int exfat_setattr(struct dentry *dentry, struct iattr *attr) struct inode *inode = dentry->d_inode; unsigned int ia_valid; int error; + loff_t old_size; PRINTK("exfat_setattr entered\n"); @@ -1012,10 +1077,16 @@ static int exfat_setattr(struct dentry *dentry, struct iattr *attr) error = inode_setattr(inode, attr); #else if (attr->ia_valid & ATTR_SIZE) { + old_size = i_size_read(inode); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,00) + down_write(&EXFAT_I(inode)->truncate_lock); truncate_setsize(inode, attr->ia_size); - - exfat_truncate(inode); - + _exfat_truncate(inode, old_size); + up_write(&EXFAT_I(inode)->truncate_lock); +#else + truncate_setsize(inode, attr->ia_size); + _exfat_truncate(inode, old_size); +#endif } setattr_copy(inode, attr); mark_inode_dirty(inode); @@ -1069,6 +1140,8 @@ const struct inode_operations exfat_symlink_inode_operations = { static int exfat_file_release(struct inode *inode, struct file *filp) { struct super_block *sb = inode->i_sb; + + EXFAT_I(inode)->fid.size = i_size_read(inode); FsSyncVol(sb, 0); return 0; } @@ -1091,14 +1164,14 @@ const struct file_operations exfat_file_operations = { .splice_read = generic_file_splice_read, }; -static void exfat_truncate(struct inode *inode) +static void _exfat_truncate(struct inode *inode, loff_t old_size) { struct super_block *sb = inode->i_sb; struct exfat_sb_info *sbi = EXFAT_SB(sb); FS_INFO_T *p_fs = &(sbi->fs_info); int err; - mutex_lock(&sbi->s_lock); + __lock_super(sb); /* * This protects against truncating a file bigger than it was then @@ -1109,7 +1182,7 @@ static void exfat_truncate(struct inode *inode) if (EXFAT_I(inode)->fid.start_clu == 0) goto out; - err = FsTruncateFile(inode, i_size_read(inode)); + err = FsTruncateFile(inode, old_size, i_size_read(inode)); if (err) goto out; inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC; @@ -1121,11 +1194,20 @@ static void exfat_truncate(struct inode *inode) inode->i_blocks = ((i_size_read(inode) + (p_fs->cluster_size - 1)) & ~((loff_t)p_fs->cluster_size - 1)) >> 9; out: - mutex_unlock(&sbi->s_lock); + __unlock_super(sb); +} + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,36) +static void exfat_truncate(struct inode *inode) +{ + _exfat_truncate(inode, i_size_read(inode)); } +#endif const struct inode_operations exfat_file_inode_operations = { - //.truncate = exfat_truncate, +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,36) + .truncate = exfat_truncate, +#endif .setattr = exfat_setattr, .getattr = exfat_getattr, }; @@ -1196,11 +1278,11 @@ static int exfat_get_block(struct inode *inode, sector_t iblock, unsigned long mapped_blocks; sector_t phys; - mutex_lock(&EXFAT_SB(sb)->s_lock); + __lock_super(sb); err = exfat_bmap(inode, iblock, &phys, &mapped_blocks, &create); if (err) { - mutex_unlock(&EXFAT_SB(sb)->s_lock); + __unlock_super(sb); return err; } @@ -1214,7 +1296,7 @@ static int exfat_get_block(struct inode *inode, sector_t iblock, } bh_result->b_size = max_blocks << sb->s_blocksize_bits; - mutex_unlock(&EXFAT_SB(sb)->s_lock); + __unlock_super(sb); return 0; } @@ -1227,7 +1309,7 @@ static int exfat_readpage(struct file *file, struct page *page) } static int exfat_readpages(struct file *file, struct address_space *mapping, - struct list_head *pages, unsigned nr_pages) + struct list_head *pages, unsigned nr_pages) { int ret; ret = mpage_readpages(mapping, pages, nr_pages, exfat_get_block); @@ -1242,28 +1324,46 @@ static int exfat_writepage(struct page *page, struct writeback_control *wbc) } static int exfat_writepages(struct address_space *mapping, - struct writeback_control *wbc) + struct writeback_control *wbc) { int ret; ret = mpage_writepages(mapping, wbc, exfat_get_block); return ret; } +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34) +static void exfat_write_failed(struct address_space *mapping, loff_t to) +{ + struct inode *inode = mapping->host; + if (to > i_size_read(inode)) { + truncate_pagecache(inode, to, i_size_read(inode)); + EXFAT_I(inode)->fid.size = i_size_read(inode); + _exfat_truncate(inode, i_size_read(inode)); + } +} +#endif + + static int exfat_write_begin(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned flags, - struct page **pagep, void **fsdata) + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) { int ret; *pagep = NULL; ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, - exfat_get_block, - &EXFAT_I(mapping->host)->mmu_private); + exfat_get_block, + &EXFAT_I(mapping->host)->mmu_private); + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34) + if (ret < 0) + exfat_write_failed(mapping, pos+len); +#endif return ret; } static int exfat_write_end(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *pagep, void *fsdata) + loff_t pos, unsigned len, unsigned copied, + struct page *pagep, void *fsdata) { struct inode *inode = mapping->host; FILE_ID_T *fid = &(EXFAT_I(inode)->fid); @@ -1271,6 +1371,11 @@ static int exfat_write_end(struct file *file, struct address_space *mapping, err = generic_write_end(file, mapping, pos, len, copied, pagep, fsdata); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34) + if (err < len) + exfat_write_failed(mapping, pos+len); +#endif + if (!(err < 0) && !(fid->attr & ATTR_ARCHIVE)) { inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; fid->attr |= ATTR_ARCHIVE; @@ -1279,18 +1384,33 @@ static int exfat_write_end(struct file *file, struct address_space *mapping, return err; } -static ssize_t exfat_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, - loff_t offset, unsigned long nr_segs) +static ssize_t exfat_direct_IO(int rw, struct kiocb *iocb, + const struct iovec *iov, + loff_t offset, unsigned long nr_segs) { struct inode *inode = iocb->ki_filp->f_mapping->host; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34) + struct address_space *mapping = iocb->ki_filp->f_mapping; +#endif + ssize_t ret; if (rw == WRITE) { if (EXFAT_I(inode)->mmu_private < (offset + iov_length(iov, nr_segs))) return 0; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,00) + ret = blockdev_direct_IO(rw, iocb, inode, iov, + offset, nr_segs, exfat_get_block); +#else + ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, + offset, nr_segs, exfat_get_block, NULL); +#endif - return blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, - exfat_get_block); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34) + if ((ret < 0) && (rw & WRITE)) + exfat_write_failed(mapping, offset+iov_length(iov, nr_segs)); +#endif + return ret; } static sector_t _exfat_bmap(struct address_space *mapping, sector_t block) @@ -1298,9 +1418,15 @@ static sector_t _exfat_bmap(struct address_space *mapping, sector_t block) sector_t blocknr; /* exfat_get_cluster() assumes the requested blocknr isn't truncated. */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,00) + down_read(&EXFAT_I(mapping->host)->truncate_lock); + blocknr = generic_block_bmap(mapping, block, exfat_get_block); + up_read(&EXFAT_I(mapping->host)->truncate_lock); +#else down_read(&EXFAT_I(mapping->host)->i_alloc_sem); blocknr = generic_block_bmap(mapping, block, exfat_get_block); up_read(&EXFAT_I(mapping->host)->i_alloc_sem); +#endif return blocknr; } @@ -1328,33 +1454,29 @@ static inline unsigned long exfat_hash(loff_t i_pos) return hash_32(i_pos, EXFAT_HASH_BITS); } - - - static struct inode *exfat_iget(struct super_block *sb, loff_t i_pos) { struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct exfat_inode_info *info; struct hlist_head *head = sbi->inode_hashtable + exfat_hash(i_pos); - struct exfat_inode_info *i; struct inode *inode = NULL; #if LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0) - struct hlist_node *_p; + struct hlist_node *node; spin_lock(&sbi->inode_hash_lock); - hlist_for_each_entry(i, _p, head, i_fat_hash) { + hlist_for_each_entry(info, node, head, i_hash_fat) { #else - spin_lock(&sbi->inode_hash_lock); - hlist_for_each_entry(i, head, i_fat_hash) { + hlist_for_each_entry(info, head, i_hash_fat) { #endif - BUG_ON(i->vfs_inode.i_sb != sb); - if (i->i_pos != i_pos) + CHECK_ERR(info->vfs_inode.i_sb != sb); + + if (i_pos != info->i_pos) continue; - inode = igrab(&i->vfs_inode); + inode = igrab(&info->vfs_inode); if (inode) break; } spin_unlock(&sbi->inode_hash_lock); - return inode; } @@ -1365,7 +1487,7 @@ static void exfat_attach(struct inode *inode, loff_t i_pos) spin_lock(&sbi->inode_hash_lock); EXFAT_I(inode)->i_pos = i_pos; - hlist_add_head(&EXFAT_I(inode)->i_fat_hash, head); + hlist_add_head(&EXFAT_I(inode)->i_hash_fat, head); spin_unlock(&sbi->inode_hash_lock); } @@ -1374,8 +1496,8 @@ static void exfat_detach(struct inode *inode) struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); spin_lock(&sbi->inode_hash_lock); + hlist_del_init(&EXFAT_I(inode)->i_hash_fat); EXFAT_I(inode)->i_pos = 0; - hlist_del_init(&EXFAT_I(inode)->i_fat_hash); spin_unlock(&sbi->inode_hash_lock); } @@ -1405,7 +1527,11 @@ static int exfat_fill_inode(struct inode *inode, FILE_ID_T *fid) i_size_write(inode, info.Size); EXFAT_I(inode)->mmu_private = i_size_read(inode); - set_nlink(inode, info.NumSubdirs); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,00) + set_nlink(inode,info.NumSubdirs); +#else + inode->i_nlink = info.NumSubdirs; +#endif } else if (info.Attr & ATTR_SYMLINK) { /* symbolic link */ inode->i_generation |= 1; inode->i_mode = exfat_make_mode(sbi, info.Attr, S_IRWXUGO); @@ -1458,18 +1584,6 @@ static struct inode *exfat_build_inode(struct super_block *sb, goto out; } exfat_attach(inode, i_pos); -/* - { - struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); - struct hlist_head *head = sbi->inode_hashtable + exfat_hash(i_pos); - - spin_lock(&sbi->inode_hash_lock); - EXFAT_I(inode)->i_pos = i_pos; - hlist_add_head(&EXFAT_I(inode)->i_fat_hash, head); - spin_unlock(&sbi->inode_hash_lock); - } -*/ - insert_inode_hash(inode); out: return inode; @@ -1486,6 +1600,11 @@ static struct inode *exfat_alloc_inode(struct super_block *sb) { ei = kmem_cache_alloc(exfat_inode_cachep, GFP_NOFS); if (!ei) return NULL; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,00) + init_rwsem(&ei->truncate_lock); +#endif + return &ei->vfs_inode; } @@ -1506,8 +1625,6 @@ static int exfat_write_inode(struct inode *inode, struct writeback_control *wbc) if (inode->i_ino == EXFAT_ROOT_INO) return 0; - EXFAT_I(inode)->fid.size = i_size_read(inode); - info.Attr = exfat_make_attr(inode); info.Size = i_size_read(inode); @@ -1530,49 +1647,24 @@ static void exfat_delete_inode(struct inode *inode) static void exfat_clear_inode(struct inode *inode) { exfat_detach(inode); -/* - struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); - - spin_lock(&sbi->inode_hash_lock); - EXFAT_I(inode)->i_pos = 0; - hlist_del_init(&EXFAT_I(inode)->i_fat_hash); - spin_unlock(&sbi->inode_hash_lock); - } -*/ - remove_inode_hash(inode); } #else static void exfat_evict_inode(struct inode *inode) { - struct super_block *sb = inode->i_sb; - mutex_lock(&EXFAT_SB(sb)->s_lock); truncate_inode_pages(&inode->i_data, 0); - if (!inode->i_nlink) { - EXFAT_I(inode)->fid.size = i_size_read(inode); - FsTruncateFile(inode, 0); + if (!inode->i_nlink) i_size_write(inode, 0); - //mark_inode_dirty(inode); - } invalidate_inode_buffers(inode); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) - clear_inode(inode); -#else +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,00) end_writeback(inode); +#else + clear_inode(inode); #endif exfat_detach(inode); -/* - struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); - - spin_lock(&sbi->inode_hash_lock); - EXFAT_I(inode)->i_pos = 0; - hlist_del_init(&EXFAT_I(inode)->i_fat_hash); - spin_unlock(&sbi->inode_hash_lock); -*/ remove_inode_hash(inode); - mutex_unlock(&EXFAT_SB(sb)->s_lock); } #endif @@ -1591,8 +1683,7 @@ static void exfat_free_super(struct exfat_sb_info *sbi) static void exfat_put_super(struct super_block *sb) { struct exfat_sb_info *sbi = EXFAT_SB(sb); - - if (&sbi->s_dirt) + if (__is_sb_dirty(sb)) exfat_write_super(sb); FsUmountVol(sb); @@ -1603,27 +1694,25 @@ static void exfat_put_super(struct super_block *sb) static void exfat_write_super(struct super_block *sb) { - struct exfat_sb_info *sbi = EXFAT_SB(sb); + __lock_super(sb); - mutex_lock(&sbi->s_lock); - sbi->s_dirt = 0; + __set_sb_clean(sb); if (!(sb->s_flags & MS_RDONLY)) FsSyncVol(sb, 1); - mutex_unlock(&sbi->s_lock); + __unlock_super(sb); } static int exfat_sync_fs(struct super_block *sb, int wait) { int err = 0; - struct exfat_sb_info *sbi = EXFAT_SB(sb); - if (sbi->s_dirt) { - mutex_lock(&sbi->s_lock); - sbi->s_dirt = 0; + if (__is_sb_dirty(sb)) { + __lock_super(sb); + __set_sb_clean(sb); err = FsSyncVol(sb, 1); - mutex_unlock(&sbi->s_lock); + __unlock_super(sb); } return err; @@ -1633,11 +1722,25 @@ static int exfat_statfs(struct dentry *dentry, struct kstatfs *buf) { struct super_block *sb = dentry->d_sb; u64 id = huge_encode_dev(sb->s_bdev->bd_dev); + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); VOL_INFO_T info; - FsGetVolInfo(dentry->d_sb, &info); + if (p_fs->used_clusters == (UINT32) ~0) { + if (FFS_MEDIAERR == FsGetVolInfo(sb, &info)) + return -EIO; + + } else { + info.FatType = p_fs->vol_type; + info.ClusterSize = p_fs->cluster_size; + info.NumClusters = p_fs->num_clusters - 2; + info.UsedClusters = p_fs->used_clusters; + info.FreeClusters = info.NumClusters - info.UsedClusters; + + if (p_fs->dev_ejected) + return -EIO; + } - buf->f_type = dentry->d_sb->s_magic; + buf->f_type = sb->s_magic; buf->f_bsize = info.ClusterSize; buf->f_blocks = info.NumClusters; buf->f_bfree = info.FreeClusters; @@ -1655,9 +1758,15 @@ static int exfat_remount(struct super_block *sb, int *flags, char *data) return 0; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,00) static int exfat_show_options(struct seq_file *m, struct dentry *root) { struct exfat_sb_info *sbi = EXFAT_SB(root->d_sb); +#else +static int exfat_show_options(struct seq_file *m, struct vfsmount *mnt) +{ + struct exfat_sb_info *sbi = EXFAT_SB(mnt->mnt_sb); +#endif struct exfat_mount_options *opts = &sbi->options; #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) if (__kuid_val(opts->fs_uid)) @@ -1665,19 +1774,15 @@ static int exfat_show_options(struct seq_file *m, struct dentry *root) if (__kgid_val(opts->fs_gid)) seq_printf(m, ",gid=%u", __kgid_val(opts->fs_gid)); #else - if (opts->fs_uid) + if (opts->fs_uid != 0) seq_printf(m, ",uid=%u", opts->fs_uid); - if (opts->fs_gid) + if (opts->fs_gid != 0) seq_printf(m, ",gid=%u", opts->fs_gid); #endif - if (opts->fs_fmask == opts->fs_dmask) - seq_printf(m, ",umask=%04o", opts->fs_fmask); - else { - seq_printf(m, ",fmask=%04o", opts->fs_fmask); - seq_printf(m, ",dmask=%04o", opts->fs_dmask); - } + seq_printf(m, ",fmask=%04o", opts->fs_fmask); + seq_printf(m, ",dmask=%04o", opts->fs_dmask); if (opts->allow_utime) - seq_printf(m, ",allow_utime=0%o", opts->allow_utime); + seq_printf(m, ",allow_utime=%04o", opts->allow_utime); if (sbi->nls_disk) seq_printf(m, ",codepage=%s", sbi->nls_disk->charset); if (sbi->nls_io) @@ -1693,7 +1798,6 @@ static int exfat_show_options(struct seq_file *m, struct dentry *root) if (opts->discard) seq_printf(m, ",discard"); #endif - return 0; } @@ -1708,7 +1812,7 @@ const struct super_operations exfat_sops = { .evict_inode = exfat_evict_inode, #endif .put_super = exfat_put_super, -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0) +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) .write_super = exfat_write_super, #endif .sync_fs = exfat_sync_fs, @@ -1862,7 +1966,7 @@ static int parse_options(char *options, int silent, int *debug, #endif /* EXFAT_CONFIG_DISCARD */ default: if (!silent) { - printk(KERN_ERR "EXFAT: Unrecognized mount option %s or missing value\n", p); + printk(KERN_ERR "[EXFAT] Unrecognized mount option %s or missing value\n", p); } return -EINVAL; } @@ -1924,7 +2028,12 @@ static int exfat_read_root(struct inode *inode) exfat_save_attr(inode, ATTR_SUBDIR); inode->i_mtime = inode->i_atime = inode->i_ctime = ts; - set_nlink(inode, info.NumSubdirs + 2); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,00) + set_nlink(inode,info.NumSubdirs + 2); +#else + inode->i_nlink = info.NumSubdirs + 2; +#endif + return 0; } @@ -1945,8 +2054,10 @@ static int exfat_fill_super(struct super_block *sb, void *data, int silent) sbi = kzalloc(sizeof(struct exfat_sb_info), GFP_KERNEL); if (!sbi) return -ENOMEM; - sb->s_fs_info = sbi; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) mutex_init(&sbi->s_lock); +#endif + sb->s_fs_info = sbi; sb->s_flags |= MS_NODIRATIME; sb->s_magic = EXFAT_SUPER_MAGIC; @@ -1963,7 +2074,7 @@ static int exfat_fill_super(struct super_block *sb, void *data, int silent) ret = FsMountVol(sb); if (ret) { if (!silent) - printk(KERN_ERR "EXFAT: FsMountVol failed\n"); + printk(KERN_ERR "[EXFAT] FsMountVol failed\n"); goto out_fail; } @@ -1984,14 +2095,14 @@ static int exfat_fill_super(struct super_block *sb, void *data, int silent) sprintf(buf, "cp%d", sbi->options.codepage); sbi->nls_disk = load_nls(buf); if (!sbi->nls_disk) { - printk(KERN_ERR "EXFAT: Codepage %s not found\n", buf); + printk(KERN_ERR "[EXFAT] Codepage %s not found\n", buf); goto out_fail2; } } sbi->nls_io = load_nls(sbi->options.iocharset); if (!sbi->nls_io) { - printk(KERN_ERR "EXFAT: IO charset %s not found\n", + printk(KERN_ERR "[EXFAT] IO charset %s not found\n", sbi->options.iocharset); goto out_fail2; } @@ -2006,28 +2117,15 @@ static int exfat_fill_super(struct super_block *sb, void *data, int silent) if (error < 0) goto out_fail2; error = -ENOMEM; - exfat_attach(root_inode, EXFAT_I(root_inode)->i_pos); -/* - { - loff_t i_pos = EXFAT_I(root_inode)->i_pos; - struct exfat_sb_info *sbi = EXFAT_SB(root_inode->i_sb); - struct hlist_head *head = sbi->inode_hashtable + exfat_hash(i_pos); - - spin_lock(&sbi->inode_hash_lock); - EXFAT_I(root_inode)->i_pos = i_pos; - hlist_add_head(&EXFAT_I(root_inode)->i_fat_hash, head); - spin_unlock(&sbi->inode_hash_lock); - } -*/ insert_inode_hash(root_inode); - #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,00) sb->s_root = d_make_root(root_inode); - #else +#else sb->s_root = d_alloc_root(root_inode); - #endif +#endif if (!sb->s_root) { - printk(KERN_ERR "EXFAT: Getting the root inode failed\n"); + printk(KERN_ERR "[EXFAT] Getting the root inode failed\n"); goto out_fail2; } @@ -2061,7 +2159,7 @@ static void init_once(void *foo) { struct exfat_inode_info *ei = (struct exfat_inode_info *)foo; - INIT_HLIST_NODE(&ei->i_fat_hash); + INIT_HLIST_NODE(&ei->i_hash_fat); inode_init_once(&ei->vfs_inode); } diff --git a/exfat_super.h b/exfat_super.h index 4552b1e..c9201dd 100644 --- a/exfat_super.h +++ b/exfat_super.h @@ -1,3 +1,23 @@ +/* Some of the source code in this file came from "linux/fs/fat/fat.h". */ + +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + #ifndef _EXFAT_LINUX_H #define _EXFAT_LINUX_H @@ -59,12 +79,14 @@ struct exfat_sb_info { struct exfat_mount_options options; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,00) + int s_dirt; + struct mutex s_lock; +#endif struct nls_table *nls_disk; /* Codepage used on disk */ struct nls_table *nls_io; /* Charset used for input and display */ struct inode *fat_inode; - struct mutex s_lock; - short s_dirt; spinlock_t inode_hash_lock; struct hlist_head inode_hashtable[EXFAT_HASH_SIZE]; @@ -82,7 +104,10 @@ struct exfat_inode_info { /* NOTE: mmu_private is 64bits, so must hold ->i_mutex to access */ loff_t mmu_private; /* physically allocated size */ loff_t i_pos; /* on-disk position of directory entry or 0 */ - struct hlist_node i_fat_hash; /* hash by i_location */ + struct hlist_node i_hash_fat; /* hash by i_location */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,00) + struct rw_semaphore truncate_lock; +#endif struct inode vfs_inode; struct rw_semaphore i_alloc_sem; /* protect bmap against truncate */ }; diff --git a/exfat_upcase.c b/exfat_upcase.c index 3354e6b..10e48d2 100644 --- a/exfat_upcase.c +++ b/exfat_upcase.c @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + /************************************************************************/ /* */ /* PROJECT : exFAT & FAT12/16/32 File System */ diff --git a/exfat_version.h b/exfat_version.h index 36b76af..4428967 100644 --- a/exfat_version.h +++ b/exfat_version.h @@ -16,4 +16,4 @@ /* */ /************************************************************************/ -#define EXFAT_VERSION "1.1.5" +#define EXFAT_VERSION "1.2.5"