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"