diff --git a/kernel/tools/perf/files/patches/linux/patch-5.7.14.xz b/kernel/tools/perf/files/patches/linux/patch-5.7.14.xz new file mode 100644 index 0000000000..dd75bd00db Binary files /dev/null and b/kernel/tools/perf/files/patches/linux/patch-5.7.14.xz differ diff --git a/kernel/tools/perf/files/patches/mageia/fs-MAINTAINERS-add-exfat-filesystem.patch b/kernel/tools/perf/files/patches/mageia/fs-MAINTAINERS-add-exfat-filesystem.patch deleted file mode 100644 index 750af05704..0000000000 --- a/kernel/tools/perf/files/patches/mageia/fs-MAINTAINERS-add-exfat-filesystem.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 88ab55f16aae90e2e974eb67cc2380edb92b0661 Mon Sep 17 00:00:00 2001 -From: Namjae Jeon -Date: Mon, 2 Mar 2020 15:21:43 +0900 -Subject: [PATCH 12/14] MAINTAINERS: add exfat filesystem -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Add myself and Sungjong Seo as exfat maintainer. - -Signed-off-by: Namjae Jeon -Signed-off-by: Sungjong Seo -Reviewed-by: Pali Rohár -Reviewed-by: Christoph Hellwig -Signed-off-by: Al Viro ---- - MAINTAINERS | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/MAINTAINERS b/MAINTAINERS -index 38fe2f3f7b6f..27d912bc5ae2 100644 ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -6240,6 +6240,13 @@ F: include/trace/events/mdio.h - F: include/uapi/linux/mdio.h - F: include/uapi/linux/mii.h - -+EXFAT FILE SYSTEM -+M: Namjae Jeon -+M: Sungjong Seo -+L: linux-fsdevel@vger.kernel.org -+S: Maintained -+F: fs/exfat/ -+ - EXT2 FILE SYSTEM - M: Jan Kara - L: linux-ext4@vger.kernel.org --- -2.25.1 diff --git a/kernel/tools/perf/files/patches/mageia/fs-exfat-add-Kconfig-and-Makefile.patch b/kernel/tools/perf/files/patches/mageia/fs-exfat-add-Kconfig-and-Makefile.patch deleted file mode 100644 index 674116ff3b..0000000000 --- a/kernel/tools/perf/files/patches/mageia/fs-exfat-add-Kconfig-and-Makefile.patch +++ /dev/null @@ -1,96 +0,0 @@ -From b9d1e2e6265f5dc25e9f5dbfbde3e53d8a4958ac Mon Sep 17 00:00:00 2001 -From: Namjae Jeon -Date: Mon, 2 Mar 2020 15:21:42 +0900 -Subject: [PATCH 11/14] exfat: add Kconfig and Makefile -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This adds the Kconfig and Makefile for exfat. - -Signed-off-by: Namjae Jeon -Signed-off-by: Sungjong Seo -Reviewed-by: Pali Rohár -Reviewed-by: Christoph Hellwig -Signed-off-by: Al Viro ---- - fs/Kconfig | 3 ++- - fs/Makefile | 1 + - fs/exfat/Kconfig | 21 +++++++++++++++++++++ - fs/exfat/Makefile | 8 ++++++++ - 4 files changed, 32 insertions(+), 1 deletion(-) - create mode 100644 fs/exfat/Kconfig - create mode 100644 fs/exfat/Makefile - -diff --git a/fs/Kconfig b/fs/Kconfig -index 708ba336e689..f08fbbfafd9a 100644 ---- a/fs/Kconfig -+++ b/fs/Kconfig -@@ -140,9 +140,10 @@ endmenu - endif # BLOCK - - if BLOCK --menu "DOS/FAT/NT Filesystems" -+menu "DOS/FAT/EXFAT/NT Filesystems" - - source "fs/fat/Kconfig" -+source "fs/exfat/Kconfig" - source "fs/ntfs/Kconfig" - - endmenu -diff --git a/fs/Makefile b/fs/Makefile -index 505e51166973..2ce5112b02c8 100644 ---- a/fs/Makefile -+++ b/fs/Makefile -@@ -83,6 +83,7 @@ obj-$(CONFIG_HUGETLBFS) += hugetlbfs/ - obj-$(CONFIG_CODA_FS) += coda/ - obj-$(CONFIG_MINIX_FS) += minix/ - obj-$(CONFIG_FAT_FS) += fat/ -+obj-$(CONFIG_EXFAT_FS) += exfat/ - obj-$(CONFIG_BFS_FS) += bfs/ - obj-$(CONFIG_ISO9660_FS) += isofs/ - obj-$(CONFIG_HFSPLUS_FS) += hfsplus/ # Before hfs to find wrapped HFS+ -diff --git a/fs/exfat/Kconfig b/fs/exfat/Kconfig -new file mode 100644 -index 000000000000..2d3636dc5b8c ---- /dev/null -+++ b/fs/exfat/Kconfig -@@ -0,0 +1,21 @@ -+# SPDX-License-Identifier: GPL-2.0-or-later -+ -+config EXFAT_FS -+ tristate "exFAT filesystem support" -+ select NLS -+ help -+ This allows you to mount devices formatted with the exFAT file system. -+ exFAT is typically used on SD-Cards or USB sticks. -+ -+ To compile this as a module, choose M here: the module will be called -+ exfat. -+ -+config EXFAT_DEFAULT_IOCHARSET -+ string "Default iocharset for exFAT" -+ default "utf8" -+ depends on EXFAT_FS -+ help -+ Set this to the default input/output character set to use for -+ converting between the encoding is used for user visible filename and -+ UTF-16 character that exfat filesystem use, and can be overridden with -+ the "iocharset" mount option for exFAT filesystems. -diff --git a/fs/exfat/Makefile b/fs/exfat/Makefile -new file mode 100644 -index 000000000000..ed51926a4971 ---- /dev/null -+++ b/fs/exfat/Makefile -@@ -0,0 +1,8 @@ -+# SPDX-License-Identifier: GPL-2.0-or-later -+# -+# Makefile for the linux exFAT filesystem support. -+# -+obj-$(CONFIG_EXFAT_FS) += exfat.o -+ -+exfat-y := inode.o namei.o dir.o super.o fatent.o cache.o nls.o misc.o \ -+ file.o balloc.o --- -2.25.1 - diff --git a/kernel/tools/perf/files/patches/mageia/fs-exfat-add-bitmap-operations.patch b/kernel/tools/perf/files/patches/mageia/fs-exfat-add-bitmap-operations.patch deleted file mode 100644 index 5505b30868..0000000000 --- a/kernel/tools/perf/files/patches/mageia/fs-exfat-add-bitmap-operations.patch +++ /dev/null @@ -1,309 +0,0 @@ -From 1e49a94cf707204b66a3fb242f2814712c941f52 Mon Sep 17 00:00:00 2001 -From: Namjae Jeon -Date: Mon, 2 Mar 2020 15:21:38 +0900 -Subject: [PATCH 07/14] exfat: add bitmap operations -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This adds the implementation of bitmap operations for exfat. - -Signed-off-by: Namjae Jeon -Signed-off-by: Sungjong Seo -Reviewed-by: Pali Rohár -Reviewed-by: Christoph Hellwig -Signed-off-by: Al Viro ---- - fs/exfat/balloc.c | 280 ++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 280 insertions(+) - create mode 100644 fs/exfat/balloc.c - -diff --git a/fs/exfat/balloc.c b/fs/exfat/balloc.c -new file mode 100644 -index 000000000000..6a04cc02565a ---- /dev/null -+++ b/fs/exfat/balloc.c -@@ -0,0 +1,280 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -+ */ -+ -+#include -+#include -+#include -+ -+#include "exfat_raw.h" -+#include "exfat_fs.h" -+ -+static const unsigned char free_bit[] = { -+ 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2,/* 0 ~ 19*/ -+ 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3,/* 20 ~ 39*/ -+ 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2,/* 40 ~ 59*/ -+ 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,/* 60 ~ 79*/ -+ 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2,/* 80 ~ 99*/ -+ 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3,/*100 ~ 119*/ -+ 0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2,/*120 ~ 139*/ -+ 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5,/*140 ~ 159*/ -+ 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2,/*160 ~ 179*/ -+ 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3,/*180 ~ 199*/ -+ 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2,/*200 ~ 219*/ -+ 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,/*220 ~ 239*/ -+ 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 /*240 ~ 254*/ -+}; -+ -+static const unsigned char used_bit[] = { -+ 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3,/* 0 ~ 19*/ -+ 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4,/* 20 ~ 39*/ -+ 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5,/* 40 ~ 59*/ -+ 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,/* 60 ~ 79*/ -+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4,/* 80 ~ 99*/ -+ 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6,/*100 ~ 119*/ -+ 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4,/*120 ~ 139*/ -+ 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,/*140 ~ 159*/ -+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5,/*160 ~ 179*/ -+ 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5,/*180 ~ 199*/ -+ 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6,/*200 ~ 219*/ -+ 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,/*220 ~ 239*/ -+ 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 /*240 ~ 255*/ -+}; -+ -+/* -+ * Allocation Bitmap Management Functions -+ */ -+static int exfat_allocate_bitmap(struct super_block *sb, -+ struct exfat_dentry *ep) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ long long map_size; -+ unsigned int i, need_map_size; -+ sector_t sector; -+ -+ sbi->map_clu = le32_to_cpu(ep->dentry.bitmap.start_clu); -+ map_size = le64_to_cpu(ep->dentry.bitmap.size); -+ need_map_size = ((EXFAT_DATA_CLUSTER_COUNT(sbi) - 1) / BITS_PER_BYTE) -+ + 1; -+ if (need_map_size != map_size) { -+ exfat_msg(sb, KERN_ERR, -+ "bogus allocation bitmap size(need : %u, cur : %lld)", -+ need_map_size, map_size); -+ /* -+ * Only allowed when bogus allocation -+ * bitmap size is large -+ */ -+ if (need_map_size > map_size) -+ return -EIO; -+ } -+ sbi->map_sectors = ((need_map_size - 1) >> -+ (sb->s_blocksize_bits)) + 1; -+ sbi->vol_amap = kmalloc_array(sbi->map_sectors, -+ sizeof(struct buffer_head *), GFP_KERNEL); -+ if (!sbi->vol_amap) -+ return -ENOMEM; -+ -+ sector = exfat_cluster_to_sector(sbi, sbi->map_clu); -+ for (i = 0; i < sbi->map_sectors; i++) { -+ sbi->vol_amap[i] = sb_bread(sb, sector + i); -+ if (!sbi->vol_amap[i]) { -+ /* release all buffers and free vol_amap */ -+ int j = 0; -+ -+ while (j < i) -+ brelse(sbi->vol_amap[j++]); -+ -+ kfree(sbi->vol_amap); -+ sbi->vol_amap = NULL; -+ return -EIO; -+ } -+ } -+ -+ sbi->pbr_bh = NULL; -+ return 0; -+} -+ -+int exfat_load_bitmap(struct super_block *sb) -+{ -+ unsigned int i, type; -+ struct exfat_chain clu; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ -+ exfat_chain_set(&clu, sbi->root_dir, 0, ALLOC_FAT_CHAIN); -+ while (clu.dir != EXFAT_EOF_CLUSTER) { -+ for (i = 0; i < sbi->dentries_per_clu; i++) { -+ struct exfat_dentry *ep; -+ struct buffer_head *bh; -+ -+ ep = exfat_get_dentry(sb, &clu, i, &bh, NULL); -+ if (!ep) -+ return -EIO; -+ -+ type = exfat_get_entry_type(ep); -+ if (type == TYPE_UNUSED) -+ break; -+ if (type != TYPE_BITMAP) -+ continue; -+ if (ep->dentry.bitmap.flags == 0x0) { -+ int err; -+ -+ err = exfat_allocate_bitmap(sb, ep); -+ brelse(bh); -+ return err; -+ } -+ brelse(bh); -+ } -+ -+ if (exfat_get_next_cluster(sb, &clu.dir)) -+ return -EIO; -+ } -+ -+ return -EINVAL; -+} -+ -+void exfat_free_bitmap(struct exfat_sb_info *sbi) -+{ -+ int i; -+ -+ brelse(sbi->pbr_bh); -+ -+ for (i = 0; i < sbi->map_sectors; i++) -+ __brelse(sbi->vol_amap[i]); -+ -+ kfree(sbi->vol_amap); -+} -+ -+/* -+ * If the value of "clu" is 0, it means cluster 2 which is the first cluster of -+ * the cluster heap. -+ */ -+int exfat_set_bitmap(struct inode *inode, unsigned int clu) -+{ -+ int i, b; -+ unsigned int ent_idx; -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ -+ WARN_ON(clu < EXFAT_FIRST_CLUSTER); -+ ent_idx = CLUSTER_TO_BITMAP_ENT(clu); -+ i = BITMAP_OFFSET_SECTOR_INDEX(sb, ent_idx); -+ b = BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent_idx); -+ -+ set_bit_le(b, sbi->vol_amap[i]->b_data); -+ exfat_update_bh(sb, sbi->vol_amap[i], IS_DIRSYNC(inode)); -+ return 0; -+} -+ -+/* -+ * If the value of "clu" is 0, it means cluster 2 which is the first cluster of -+ * the cluster heap. -+ */ -+void exfat_clear_bitmap(struct inode *inode, unsigned int clu) -+{ -+ int i, b; -+ unsigned int ent_idx; -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct exfat_mount_options *opts = &sbi->options; -+ -+ WARN_ON(clu < EXFAT_FIRST_CLUSTER); -+ ent_idx = CLUSTER_TO_BITMAP_ENT(clu); -+ i = BITMAP_OFFSET_SECTOR_INDEX(sb, ent_idx); -+ b = BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent_idx); -+ -+ clear_bit_le(b, sbi->vol_amap[i]->b_data); -+ exfat_update_bh(sb, sbi->vol_amap[i], IS_DIRSYNC(inode)); -+ -+ if (opts->discard) { -+ int ret_discard; -+ -+ ret_discard = sb_issue_discard(sb, -+ exfat_cluster_to_sector(sbi, clu + -+ EXFAT_RESERVED_CLUSTERS), -+ (1 << sbi->sect_per_clus_bits), GFP_NOFS, 0); -+ -+ if (ret_discard == -EOPNOTSUPP) { -+ exfat_msg(sb, KERN_ERR, -+ "discard not supported by device, disabling"); -+ opts->discard = 0; -+ } -+ } -+} -+ -+/* -+ * If the value of "clu" is 0, it means cluster 2 which is the first cluster of -+ * the cluster heap. -+ */ -+unsigned int exfat_find_free_bitmap(struct super_block *sb, unsigned int clu) -+{ -+ unsigned int i, map_i, map_b, ent_idx; -+ unsigned int clu_base, clu_free; -+ unsigned char k, clu_mask; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ -+ WARN_ON(clu < EXFAT_FIRST_CLUSTER); -+ ent_idx = CLUSTER_TO_BITMAP_ENT(clu); -+ clu_base = BITMAP_ENT_TO_CLUSTER(ent_idx & ~(BITS_PER_BYTE_MASK)); -+ clu_mask = IGNORED_BITS_REMAINED(clu, clu_base); -+ -+ map_i = BITMAP_OFFSET_SECTOR_INDEX(sb, ent_idx); -+ map_b = BITMAP_OFFSET_BYTE_IN_SECTOR(sb, ent_idx); -+ -+ for (i = EXFAT_FIRST_CLUSTER; i < sbi->num_clusters; -+ i += BITS_PER_BYTE) { -+ k = *(sbi->vol_amap[map_i]->b_data + map_b); -+ if (clu_mask > 0) { -+ k |= clu_mask; -+ clu_mask = 0; -+ } -+ if (k < 0xFF) { -+ clu_free = clu_base + free_bit[k]; -+ if (clu_free < sbi->num_clusters) -+ return clu_free; -+ } -+ clu_base += BITS_PER_BYTE; -+ -+ if (++map_b >= sb->s_blocksize || -+ clu_base >= sbi->num_clusters) { -+ if (++map_i >= sbi->map_sectors) { -+ clu_base = EXFAT_FIRST_CLUSTER; -+ map_i = 0; -+ } -+ map_b = 0; -+ } -+ } -+ -+ return EXFAT_EOF_CLUSTER; -+} -+ -+int exfat_count_used_clusters(struct super_block *sb, unsigned int *ret_count) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ unsigned int count = 0; -+ unsigned int i, map_i = 0, map_b = 0; -+ unsigned int total_clus = EXFAT_DATA_CLUSTER_COUNT(sbi); -+ unsigned int last_mask = total_clus & BITS_PER_BYTE_MASK; -+ unsigned char clu_bits; -+ const unsigned char last_bit_mask[] = {0, 0b00000001, 0b00000011, -+ 0b00000111, 0b00001111, 0b00011111, 0b00111111, 0b01111111}; -+ -+ total_clus &= ~last_mask; -+ for (i = 0; i < total_clus; i += BITS_PER_BYTE) { -+ clu_bits = *(sbi->vol_amap[map_i]->b_data + map_b); -+ count += used_bit[clu_bits]; -+ if (++map_b >= (unsigned int)sb->s_blocksize) { -+ map_i++; -+ map_b = 0; -+ } -+ } -+ -+ if (last_mask) { -+ clu_bits = *(sbi->vol_amap[map_i]->b_data + map_b); -+ clu_bits &= last_bit_mask[last_mask]; -+ count += used_bit[clu_bits]; -+ } -+ -+ *ret_count = count; -+ return 0; -+} --- -2.25.1 - diff --git a/kernel/tools/perf/files/patches/mageia/fs-exfat-add-directory-operations.patch b/kernel/tools/perf/files/patches/mageia/fs-exfat-add-directory-operations.patch deleted file mode 100644 index 857c1dbb66..0000000000 --- a/kernel/tools/perf/files/patches/mageia/fs-exfat-add-directory-operations.patch +++ /dev/null @@ -1,1267 +0,0 @@ -From ca06197382bde0a3bc20215595d1c9ce20c6e341 Mon Sep 17 00:00:00 2001 -From: Namjae Jeon -Date: Mon, 2 Mar 2020 15:21:35 +0900 -Subject: [PATCH 04/14] exfat: add directory operations -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This adds the implementation of directory operations for exfat. - -Signed-off-by: Namjae Jeon -Signed-off-by: Sungjong Seo -Reviewed-by: Pali Rohár -Reviewed-by: Christoph Hellwig -Signed-off-by: Al Viro ---- - fs/exfat/dir.c | 1238 ++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 1238 insertions(+) - create mode 100644 fs/exfat/dir.c - -diff --git a/fs/exfat/dir.c b/fs/exfat/dir.c -new file mode 100644 -index 000000000000..4b91afb0f051 ---- /dev/null -+++ b/fs/exfat/dir.c -@@ -0,0 +1,1238 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -+ */ -+ -+#include -+#include -+#include -+ -+#include "exfat_raw.h" -+#include "exfat_fs.h" -+ -+static int exfat_extract_uni_name(struct exfat_dentry *ep, -+ unsigned short *uniname) -+{ -+ int i, len = 0; -+ -+ for (i = 0; i < EXFAT_FILE_NAME_LEN; i++) { -+ *uniname = le16_to_cpu(ep->dentry.name.unicode_0_14[i]); -+ if (*uniname == 0x0) -+ return len; -+ uniname++; -+ len++; -+ } -+ -+ *uniname = 0x0; -+ return len; -+ -+} -+ -+static void exfat_get_uniname_from_ext_entry(struct super_block *sb, -+ struct exfat_chain *p_dir, int entry, unsigned short *uniname) -+{ -+ int i; -+ struct exfat_dentry *ep; -+ struct exfat_entry_set_cache *es; -+ -+ es = exfat_get_dentry_set(sb, p_dir, entry, ES_ALL_ENTRIES, &ep); -+ if (!es) -+ return; -+ -+ if (es->num_entries < 3) -+ goto free_es; -+ -+ ep += 2; -+ -+ /* -+ * First entry : file entry -+ * Second entry : stream-extension entry -+ * Third entry : first file-name entry -+ * So, the index of first file-name dentry should start from 2. -+ */ -+ for (i = 2; i < es->num_entries; i++, ep++) { -+ /* end of name entry */ -+ if (exfat_get_entry_type(ep) != TYPE_EXTEND) -+ goto free_es; -+ -+ exfat_extract_uni_name(ep, uniname); -+ uniname += EXFAT_FILE_NAME_LEN; -+ } -+ -+free_es: -+ kfree(es); -+} -+ -+/* read a directory entry from the opened directory */ -+static int exfat_readdir(struct inode *inode, struct exfat_dir_entry *dir_entry) -+{ -+ int i, dentries_per_clu, dentries_per_clu_bits = 0; -+ unsigned int type, clu_offset; -+ sector_t sector; -+ struct exfat_chain dir, clu; -+ struct exfat_uni_name uni_name; -+ struct exfat_dentry *ep; -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ unsigned int dentry = ei->rwoffset & 0xFFFFFFFF; -+ struct buffer_head *bh; -+ -+ /* check if the given file ID is opened */ -+ if (ei->type != TYPE_DIR) -+ return -EPERM; -+ -+ if (ei->entry == -1) -+ exfat_chain_set(&dir, sbi->root_dir, 0, ALLOC_FAT_CHAIN); -+ else -+ exfat_chain_set(&dir, ei->start_clu, -+ EXFAT_B_TO_CLU(i_size_read(inode), sbi), ei->flags); -+ -+ dentries_per_clu = sbi->dentries_per_clu; -+ dentries_per_clu_bits = ilog2(dentries_per_clu); -+ -+ clu_offset = dentry >> dentries_per_clu_bits; -+ exfat_chain_dup(&clu, &dir); -+ -+ if (clu.flags == ALLOC_NO_FAT_CHAIN) { -+ clu.dir += clu_offset; -+ clu.size -= clu_offset; -+ } else { -+ /* hint_information */ -+ if (clu_offset > 0 && ei->hint_bmap.off != EXFAT_EOF_CLUSTER && -+ ei->hint_bmap.off > 0 && clu_offset >= ei->hint_bmap.off) { -+ clu_offset -= ei->hint_bmap.off; -+ clu.dir = ei->hint_bmap.clu; -+ } -+ -+ while (clu_offset > 0) { -+ if (exfat_get_next_cluster(sb, &(clu.dir))) -+ return -EIO; -+ -+ clu_offset--; -+ } -+ } -+ -+ while (clu.dir != EXFAT_EOF_CLUSTER) { -+ i = dentry & (dentries_per_clu - 1); -+ -+ for ( ; i < dentries_per_clu; i++, dentry++) { -+ ep = exfat_get_dentry(sb, &clu, i, &bh, §or); -+ if (!ep) -+ return -EIO; -+ -+ type = exfat_get_entry_type(ep); -+ if (type == TYPE_UNUSED) { -+ brelse(bh); -+ break; -+ } -+ -+ if (type != TYPE_FILE && type != TYPE_DIR) { -+ brelse(bh); -+ continue; -+ } -+ -+ dir_entry->attr = le16_to_cpu(ep->dentry.file.attr); -+ exfat_get_entry_time(sbi, &dir_entry->crtime, -+ ep->dentry.file.create_tz, -+ ep->dentry.file.create_time, -+ ep->dentry.file.create_date, -+ ep->dentry.file.create_time_ms); -+ exfat_get_entry_time(sbi, &dir_entry->mtime, -+ ep->dentry.file.modify_tz, -+ ep->dentry.file.modify_time, -+ ep->dentry.file.modify_date, -+ ep->dentry.file.modify_time_ms); -+ exfat_get_entry_time(sbi, &dir_entry->atime, -+ ep->dentry.file.access_tz, -+ ep->dentry.file.access_time, -+ ep->dentry.file.access_date, -+ 0); -+ -+ *uni_name.name = 0x0; -+ exfat_get_uniname_from_ext_entry(sb, &dir, dentry, -+ uni_name.name); -+ exfat_utf16_to_nls(sb, &uni_name, -+ dir_entry->namebuf.lfn, -+ dir_entry->namebuf.lfnbuf_len); -+ brelse(bh); -+ -+ ep = exfat_get_dentry(sb, &clu, i + 1, &bh, NULL); -+ if (!ep) -+ return -EIO; -+ dir_entry->size = -+ le64_to_cpu(ep->dentry.stream.valid_size); -+ brelse(bh); -+ -+ ei->hint_bmap.off = dentry >> dentries_per_clu_bits; -+ ei->hint_bmap.clu = clu.dir; -+ -+ ei->rwoffset = ++dentry; -+ return 0; -+ } -+ -+ if (clu.flags == ALLOC_NO_FAT_CHAIN) { -+ if (--clu.size > 0) -+ clu.dir++; -+ else -+ clu.dir = EXFAT_EOF_CLUSTER; -+ } else { -+ if (exfat_get_next_cluster(sb, &(clu.dir))) -+ return -EIO; -+ } -+ } -+ -+ dir_entry->namebuf.lfn[0] = '\0'; -+ ei->rwoffset = dentry; -+ return 0; -+} -+ -+static void exfat_init_namebuf(struct exfat_dentry_namebuf *nb) -+{ -+ nb->lfn = NULL; -+ nb->lfnbuf_len = 0; -+} -+ -+static int exfat_alloc_namebuf(struct exfat_dentry_namebuf *nb) -+{ -+ nb->lfn = __getname(); -+ if (!nb->lfn) -+ return -ENOMEM; -+ nb->lfnbuf_len = MAX_VFSNAME_BUF_SIZE; -+ return 0; -+} -+ -+static void exfat_free_namebuf(struct exfat_dentry_namebuf *nb) -+{ -+ if (!nb->lfn) -+ return; -+ -+ __putname(nb->lfn); -+ exfat_init_namebuf(nb); -+} -+ -+/* skip iterating emit_dots when dir is empty */ -+#define ITER_POS_FILLED_DOTS (2) -+static int exfat_iterate(struct file *filp, struct dir_context *ctx) -+{ -+ struct inode *inode = filp->f_path.dentry->d_inode; -+ struct super_block *sb = inode->i_sb; -+ struct inode *tmp; -+ struct exfat_dir_entry de; -+ struct exfat_dentry_namebuf *nb = &(de.namebuf); -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ unsigned long inum; -+ loff_t cpos, i_pos; -+ int err = 0, fake_offset = 0; -+ -+ exfat_init_namebuf(nb); -+ mutex_lock(&EXFAT_SB(sb)->s_lock); -+ -+ cpos = ctx->pos; -+ if (!dir_emit_dots(filp, ctx)) -+ goto unlock; -+ -+ if (ctx->pos == ITER_POS_FILLED_DOTS) { -+ cpos = 0; -+ fake_offset = 1; -+ } -+ -+ if (cpos & (DENTRY_SIZE - 1)) { -+ err = -ENOENT; -+ goto unlock; -+ } -+ -+ /* name buffer should be allocated before use */ -+ err = exfat_alloc_namebuf(nb); -+ if (err) -+ goto unlock; -+get_new: -+ ei->rwoffset = EXFAT_B_TO_DEN(cpos); -+ -+ if (cpos >= i_size_read(inode)) -+ goto end_of_dir; -+ -+ err = exfat_readdir(inode, &de); -+ if (err) { -+ /* -+ * At least we tried to read a sector. Move cpos to next sector -+ * position (should be aligned). -+ */ -+ if (err == -EIO) { -+ cpos += 1 << (sb->s_blocksize_bits); -+ cpos &= ~(sb->s_blocksize - 1); -+ } -+ -+ err = -EIO; -+ goto end_of_dir; -+ } -+ -+ cpos = EXFAT_DEN_TO_B(ei->rwoffset); -+ -+ if (!nb->lfn[0]) -+ goto end_of_dir; -+ -+ i_pos = ((loff_t)ei->start_clu << 32) | -+ ((ei->rwoffset - 1) & 0xffffffff); -+ tmp = exfat_iget(sb, i_pos); -+ if (tmp) { -+ inum = tmp->i_ino; -+ iput(tmp); -+ } else { -+ inum = iunique(sb, EXFAT_ROOT_INO); -+ } -+ -+ /* -+ * Before calling dir_emit(), sb_lock should be released. -+ * Because page fault can occur in dir_emit() when the size -+ * of buffer given from user is larger than one page size. -+ */ -+ mutex_unlock(&EXFAT_SB(sb)->s_lock); -+ if (!dir_emit(ctx, nb->lfn, strlen(nb->lfn), inum, -+ (de.attr & ATTR_SUBDIR) ? DT_DIR : DT_REG)) -+ goto out_unlocked; -+ mutex_lock(&EXFAT_SB(sb)->s_lock); -+ ctx->pos = cpos; -+ goto get_new; -+ -+end_of_dir: -+ if (!cpos && fake_offset) -+ cpos = ITER_POS_FILLED_DOTS; -+ ctx->pos = cpos; -+unlock: -+ mutex_unlock(&EXFAT_SB(sb)->s_lock); -+out_unlocked: -+ /* -+ * To improve performance, free namebuf after unlock sb_lock. -+ * If namebuf is not allocated, this function do nothing -+ */ -+ exfat_free_namebuf(nb); -+ return err; -+} -+ -+const struct file_operations exfat_dir_operations = { -+ .llseek = generic_file_llseek, -+ .read = generic_read_dir, -+ .iterate = exfat_iterate, -+ .fsync = generic_file_fsync, -+}; -+ -+int exfat_alloc_new_dir(struct inode *inode, struct exfat_chain *clu) -+{ -+ int ret; -+ -+ exfat_chain_set(clu, EXFAT_EOF_CLUSTER, 0, ALLOC_NO_FAT_CHAIN); -+ -+ ret = exfat_alloc_cluster(inode, 1, clu); -+ if (ret) -+ return ret; -+ -+ return exfat_zeroed_cluster(inode, clu->dir); -+} -+ -+int exfat_calc_num_entries(struct exfat_uni_name *p_uniname) -+{ -+ int len; -+ -+ len = p_uniname->name_len; -+ if (len == 0) -+ return -EINVAL; -+ -+ /* 1 file entry + 1 stream entry + name entries */ -+ return ((len - 1) / EXFAT_FILE_NAME_LEN + 3); -+} -+ -+unsigned int exfat_get_entry_type(struct exfat_dentry *ep) -+{ -+ if (ep->type == EXFAT_UNUSED) -+ return TYPE_UNUSED; -+ if (IS_EXFAT_DELETED(ep->type)) -+ return TYPE_DELETED; -+ if (ep->type == EXFAT_INVAL) -+ return TYPE_INVALID; -+ if (IS_EXFAT_CRITICAL_PRI(ep->type)) { -+ if (ep->type == EXFAT_BITMAP) -+ return TYPE_BITMAP; -+ if (ep->type == EXFAT_UPCASE) -+ return TYPE_UPCASE; -+ if (ep->type == EXFAT_VOLUME) -+ return TYPE_VOLUME; -+ if (ep->type == EXFAT_FILE) { -+ if (le16_to_cpu(ep->dentry.file.attr) & ATTR_SUBDIR) -+ return TYPE_DIR; -+ return TYPE_FILE; -+ } -+ return TYPE_CRITICAL_PRI; -+ } -+ if (IS_EXFAT_BENIGN_PRI(ep->type)) { -+ if (ep->type == EXFAT_GUID) -+ return TYPE_GUID; -+ if (ep->type == EXFAT_PADDING) -+ return TYPE_PADDING; -+ if (ep->type == EXFAT_ACLTAB) -+ return TYPE_ACLTAB; -+ return TYPE_BENIGN_PRI; -+ } -+ if (IS_EXFAT_CRITICAL_SEC(ep->type)) { -+ if (ep->type == EXFAT_STREAM) -+ return TYPE_STREAM; -+ if (ep->type == EXFAT_NAME) -+ return TYPE_EXTEND; -+ if (ep->type == EXFAT_ACL) -+ return TYPE_ACL; -+ return TYPE_CRITICAL_SEC; -+ } -+ return TYPE_BENIGN_SEC; -+} -+ -+static void exfat_set_entry_type(struct exfat_dentry *ep, unsigned int type) -+{ -+ if (type == TYPE_UNUSED) { -+ ep->type = EXFAT_UNUSED; -+ } else if (type == TYPE_DELETED) { -+ ep->type &= EXFAT_DELETE; -+ } else if (type == TYPE_STREAM) { -+ ep->type = EXFAT_STREAM; -+ } else if (type == TYPE_EXTEND) { -+ ep->type = EXFAT_NAME; -+ } else if (type == TYPE_BITMAP) { -+ ep->type = EXFAT_BITMAP; -+ } else if (type == TYPE_UPCASE) { -+ ep->type = EXFAT_UPCASE; -+ } else if (type == TYPE_VOLUME) { -+ ep->type = EXFAT_VOLUME; -+ } else if (type == TYPE_DIR) { -+ ep->type = EXFAT_FILE; -+ ep->dentry.file.attr = cpu_to_le16(ATTR_SUBDIR); -+ } else if (type == TYPE_FILE) { -+ ep->type = EXFAT_FILE; -+ ep->dentry.file.attr = cpu_to_le16(ATTR_ARCHIVE); -+ } -+} -+ -+static void exfat_init_stream_entry(struct exfat_dentry *ep, -+ unsigned char flags, unsigned int start_clu, -+ unsigned long long size) -+{ -+ exfat_set_entry_type(ep, TYPE_STREAM); -+ ep->dentry.stream.flags = flags; -+ ep->dentry.stream.start_clu = cpu_to_le32(start_clu); -+ ep->dentry.stream.valid_size = cpu_to_le64(size); -+ ep->dentry.stream.size = cpu_to_le64(size); -+} -+ -+static void exfat_init_name_entry(struct exfat_dentry *ep, -+ unsigned short *uniname) -+{ -+ int i; -+ -+ exfat_set_entry_type(ep, TYPE_EXTEND); -+ ep->dentry.name.flags = 0x0; -+ -+ for (i = 0; i < EXFAT_FILE_NAME_LEN; i++) { -+ ep->dentry.name.unicode_0_14[i] = cpu_to_le16(*uniname); -+ if (*uniname == 0x0) -+ break; -+ uniname++; -+ } -+} -+ -+int exfat_init_dir_entry(struct inode *inode, struct exfat_chain *p_dir, -+ int entry, unsigned int type, unsigned int start_clu, -+ unsigned long long size) -+{ -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct timespec64 ts = current_time(inode); -+ sector_t sector; -+ struct exfat_dentry *ep; -+ struct buffer_head *bh; -+ -+ /* -+ * We cannot use exfat_get_dentry_set here because file ep is not -+ * initialized yet. -+ */ -+ ep = exfat_get_dentry(sb, p_dir, entry, &bh, §or); -+ if (!ep) -+ return -EIO; -+ -+ exfat_set_entry_type(ep, type); -+ exfat_set_entry_time(sbi, &ts, -+ &ep->dentry.file.create_tz, -+ &ep->dentry.file.create_time, -+ &ep->dentry.file.create_date, -+ &ep->dentry.file.create_time_ms); -+ exfat_set_entry_time(sbi, &ts, -+ &ep->dentry.file.modify_tz, -+ &ep->dentry.file.modify_time, -+ &ep->dentry.file.modify_date, -+ &ep->dentry.file.modify_time_ms); -+ exfat_set_entry_time(sbi, &ts, -+ &ep->dentry.file.access_tz, -+ &ep->dentry.file.access_time, -+ &ep->dentry.file.access_date, -+ NULL); -+ -+ exfat_update_bh(sb, bh, IS_DIRSYNC(inode)); -+ brelse(bh); -+ -+ ep = exfat_get_dentry(sb, p_dir, entry + 1, &bh, §or); -+ if (!ep) -+ return -EIO; -+ -+ exfat_init_stream_entry(ep, -+ (type == TYPE_FILE) ? ALLOC_FAT_CHAIN : ALLOC_NO_FAT_CHAIN, -+ start_clu, size); -+ exfat_update_bh(sb, bh, IS_DIRSYNC(inode)); -+ brelse(bh); -+ -+ return 0; -+} -+ -+int exfat_update_dir_chksum(struct inode *inode, struct exfat_chain *p_dir, -+ int entry) -+{ -+ struct super_block *sb = inode->i_sb; -+ int ret = 0; -+ int i, num_entries; -+ sector_t sector; -+ unsigned short chksum; -+ struct exfat_dentry *ep, *fep; -+ struct buffer_head *fbh, *bh; -+ -+ fep = exfat_get_dentry(sb, p_dir, entry, &fbh, §or); -+ if (!fep) -+ return -EIO; -+ -+ num_entries = fep->dentry.file.num_ext + 1; -+ chksum = exfat_calc_chksum_2byte(fep, DENTRY_SIZE, 0, CS_DIR_ENTRY); -+ -+ for (i = 1; i < num_entries; i++) { -+ ep = exfat_get_dentry(sb, p_dir, entry + i, &bh, NULL); -+ if (!ep) { -+ ret = -EIO; -+ goto release_fbh; -+ } -+ chksum = exfat_calc_chksum_2byte(ep, DENTRY_SIZE, chksum, -+ CS_DEFAULT); -+ brelse(bh); -+ } -+ -+ fep->dentry.file.checksum = cpu_to_le16(chksum); -+ exfat_update_bh(sb, fbh, IS_DIRSYNC(inode)); -+release_fbh: -+ brelse(fbh); -+ return ret; -+} -+ -+int exfat_init_ext_entry(struct inode *inode, struct exfat_chain *p_dir, -+ int entry, int num_entries, struct exfat_uni_name *p_uniname) -+{ -+ struct super_block *sb = inode->i_sb; -+ int i; -+ sector_t sector; -+ unsigned short *uniname = p_uniname->name; -+ struct exfat_dentry *ep; -+ struct buffer_head *bh; -+ int sync = IS_DIRSYNC(inode); -+ -+ ep = exfat_get_dentry(sb, p_dir, entry, &bh, §or); -+ if (!ep) -+ return -EIO; -+ -+ ep->dentry.file.num_ext = (unsigned char)(num_entries - 1); -+ exfat_update_bh(sb, bh, sync); -+ brelse(bh); -+ -+ ep = exfat_get_dentry(sb, p_dir, entry + 1, &bh, §or); -+ if (!ep) -+ return -EIO; -+ -+ ep->dentry.stream.name_len = p_uniname->name_len; -+ ep->dentry.stream.name_hash = cpu_to_le16(p_uniname->name_hash); -+ exfat_update_bh(sb, bh, sync); -+ brelse(bh); -+ -+ for (i = EXFAT_FIRST_CLUSTER; i < num_entries; i++) { -+ ep = exfat_get_dentry(sb, p_dir, entry + i, &bh, §or); -+ if (!ep) -+ return -EIO; -+ -+ exfat_init_name_entry(ep, uniname); -+ exfat_update_bh(sb, bh, sync); -+ brelse(bh); -+ uniname += EXFAT_FILE_NAME_LEN; -+ } -+ -+ exfat_update_dir_chksum(inode, p_dir, entry); -+ return 0; -+} -+ -+int exfat_remove_entries(struct inode *inode, struct exfat_chain *p_dir, -+ int entry, int order, int num_entries) -+{ -+ struct super_block *sb = inode->i_sb; -+ int i; -+ sector_t sector; -+ struct exfat_dentry *ep; -+ struct buffer_head *bh; -+ -+ for (i = order; i < num_entries; i++) { -+ ep = exfat_get_dentry(sb, p_dir, entry + i, &bh, §or); -+ if (!ep) -+ return -EIO; -+ -+ exfat_set_entry_type(ep, TYPE_DELETED); -+ exfat_update_bh(sb, bh, IS_DIRSYNC(inode)); -+ brelse(bh); -+ } -+ -+ return 0; -+} -+ -+int exfat_update_dir_chksum_with_entry_set(struct super_block *sb, -+ struct exfat_entry_set_cache *es, int sync) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct buffer_head *bh; -+ sector_t sec = es->sector; -+ unsigned int off = es->offset; -+ int chksum_type = CS_DIR_ENTRY, i, num_entries = es->num_entries; -+ unsigned int buf_off = (off - es->offset); -+ unsigned int remaining_byte_in_sector, copy_entries, clu; -+ unsigned short chksum = 0; -+ -+ for (i = 0; i < num_entries; i++) { -+ chksum = exfat_calc_chksum_2byte(&es->entries[i], DENTRY_SIZE, -+ chksum, chksum_type); -+ chksum_type = CS_DEFAULT; -+ } -+ -+ es->entries[0].dentry.file.checksum = cpu_to_le16(chksum); -+ -+ while (num_entries) { -+ /* write per sector base */ -+ remaining_byte_in_sector = (1 << sb->s_blocksize_bits) - off; -+ copy_entries = min_t(int, -+ EXFAT_B_TO_DEN(remaining_byte_in_sector), -+ num_entries); -+ bh = sb_bread(sb, sec); -+ if (!bh) -+ goto err_out; -+ memcpy(bh->b_data + off, -+ (unsigned char *)&es->entries[0] + buf_off, -+ EXFAT_DEN_TO_B(copy_entries)); -+ exfat_update_bh(sb, bh, sync); -+ brelse(bh); -+ num_entries -= copy_entries; -+ -+ if (num_entries) { -+ /* get next sector */ -+ if (exfat_is_last_sector_in_cluster(sbi, sec)) { -+ clu = exfat_sector_to_cluster(sbi, sec); -+ if (es->alloc_flag == ALLOC_NO_FAT_CHAIN) -+ clu++; -+ else if (exfat_get_next_cluster(sb, &clu)) -+ goto err_out; -+ sec = exfat_cluster_to_sector(sbi, clu); -+ } else { -+ sec++; -+ } -+ off = 0; -+ buf_off += EXFAT_DEN_TO_B(copy_entries); -+ } -+ } -+ -+ return 0; -+err_out: -+ return -EIO; -+} -+ -+static int exfat_walk_fat_chain(struct super_block *sb, -+ struct exfat_chain *p_dir, unsigned int byte_offset, -+ unsigned int *clu) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ unsigned int clu_offset; -+ unsigned int cur_clu; -+ -+ clu_offset = EXFAT_B_TO_CLU(byte_offset, sbi); -+ cur_clu = p_dir->dir; -+ -+ if (p_dir->flags == ALLOC_NO_FAT_CHAIN) { -+ cur_clu += clu_offset; -+ } else { -+ while (clu_offset > 0) { -+ if (exfat_get_next_cluster(sb, &cur_clu)) -+ return -EIO; -+ if (cur_clu == EXFAT_EOF_CLUSTER) { -+ exfat_fs_error(sb, -+ "invalid dentry access beyond EOF (clu : %u, eidx : %d)", -+ p_dir->dir, -+ EXFAT_B_TO_DEN(byte_offset)); -+ return -EIO; -+ } -+ clu_offset--; -+ } -+ } -+ -+ *clu = cur_clu; -+ return 0; -+} -+ -+int exfat_find_location(struct super_block *sb, struct exfat_chain *p_dir, -+ int entry, sector_t *sector, int *offset) -+{ -+ int ret; -+ unsigned int off, clu = 0; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ -+ off = EXFAT_DEN_TO_B(entry); -+ -+ ret = exfat_walk_fat_chain(sb, p_dir, off, &clu); -+ if (ret) -+ return ret; -+ -+ /* byte offset in cluster */ -+ off = EXFAT_CLU_OFFSET(off, sbi); -+ -+ /* byte offset in sector */ -+ *offset = EXFAT_BLK_OFFSET(off, sb); -+ -+ /* sector offset in cluster */ -+ *sector = EXFAT_B_TO_BLK(off, sb); -+ *sector += exfat_cluster_to_sector(sbi, clu); -+ return 0; -+} -+ -+#define EXFAT_MAX_RA_SIZE (128*1024) -+static int exfat_dir_readahead(struct super_block *sb, sector_t sec) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct buffer_head *bh; -+ unsigned int max_ra_count = EXFAT_MAX_RA_SIZE >> sb->s_blocksize_bits; -+ unsigned int page_ra_count = PAGE_SIZE >> sb->s_blocksize_bits; -+ unsigned int adj_ra_count = max(sbi->sect_per_clus, page_ra_count); -+ unsigned int ra_count = min(adj_ra_count, max_ra_count); -+ -+ /* Read-ahead is not required */ -+ if (sbi->sect_per_clus == 1) -+ return 0; -+ -+ if (sec < sbi->data_start_sector) { -+ exfat_msg(sb, KERN_ERR, -+ "requested sector is invalid(sect:%llu, root:%llu)", -+ (unsigned long long)sec, sbi->data_start_sector); -+ return -EIO; -+ } -+ -+ /* Not sector aligned with ra_count, resize ra_count to page size */ -+ if ((sec - sbi->data_start_sector) & (ra_count - 1)) -+ ra_count = page_ra_count; -+ -+ bh = sb_find_get_block(sb, sec); -+ if (!bh || !buffer_uptodate(bh)) { -+ unsigned int i; -+ -+ for (i = 0; i < ra_count; i++) -+ sb_breadahead(sb, (sector_t)(sec + i)); -+ } -+ brelse(bh); -+ return 0; -+} -+ -+struct exfat_dentry *exfat_get_dentry(struct super_block *sb, -+ struct exfat_chain *p_dir, int entry, struct buffer_head **bh, -+ sector_t *sector) -+{ -+ unsigned int dentries_per_page = EXFAT_B_TO_DEN(PAGE_SIZE); -+ int off; -+ sector_t sec; -+ -+ if (p_dir->dir == DIR_DELETED) { -+ exfat_msg(sb, KERN_ERR, "abnormal access to deleted dentry\n"); -+ return NULL; -+ } -+ -+ if (exfat_find_location(sb, p_dir, entry, &sec, &off)) -+ return NULL; -+ -+ if (p_dir->dir != EXFAT_FREE_CLUSTER && -+ !(entry & (dentries_per_page - 1))) -+ exfat_dir_readahead(sb, sec); -+ -+ *bh = sb_bread(sb, sec); -+ if (!*bh) -+ return NULL; -+ -+ if (sector) -+ *sector = sec; -+ return (struct exfat_dentry *)((*bh)->b_data + off); -+} -+ -+enum exfat_validate_dentry_mode { -+ ES_MODE_STARTED, -+ ES_MODE_GET_FILE_ENTRY, -+ ES_MODE_GET_STRM_ENTRY, -+ ES_MODE_GET_NAME_ENTRY, -+ ES_MODE_GET_CRITICAL_SEC_ENTRY, -+}; -+ -+static bool exfat_validate_entry(unsigned int type, -+ enum exfat_validate_dentry_mode *mode) -+{ -+ if (type == TYPE_UNUSED || type == TYPE_DELETED) -+ return false; -+ -+ switch (*mode) { -+ case ES_MODE_STARTED: -+ if (type != TYPE_FILE && type != TYPE_DIR) -+ return false; -+ *mode = ES_MODE_GET_FILE_ENTRY; -+ return true; -+ case ES_MODE_GET_FILE_ENTRY: -+ if (type != TYPE_STREAM) -+ return false; -+ *mode = ES_MODE_GET_STRM_ENTRY; -+ return true; -+ case ES_MODE_GET_STRM_ENTRY: -+ if (type != TYPE_EXTEND) -+ return false; -+ *mode = ES_MODE_GET_NAME_ENTRY; -+ return true; -+ case ES_MODE_GET_NAME_ENTRY: -+ if (type == TYPE_STREAM) -+ return false; -+ if (type != TYPE_EXTEND) { -+ if (!(type & TYPE_CRITICAL_SEC)) -+ return false; -+ *mode = ES_MODE_GET_CRITICAL_SEC_ENTRY; -+ } -+ return true; -+ case ES_MODE_GET_CRITICAL_SEC_ENTRY: -+ if (type == TYPE_EXTEND || type == TYPE_STREAM) -+ return false; -+ if ((type & TYPE_CRITICAL_SEC) != TYPE_CRITICAL_SEC) -+ return false; -+ return true; -+ default: -+ WARN_ON_ONCE(1); -+ return false; -+ } -+} -+ -+/* -+ * 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() to apply changes made in this entry set -+ * to the real device. -+ * -+ * in: -+ * sb+p_dir+entry: indicates a file/dir -+ * type: specifies how many dentries should be included. -+ * out: -+ * file_ep: will point the first dentry(= file dentry) on success -+ * return: -+ * pointer of entry set on success, -+ * NULL on failure. -+ */ -+struct exfat_entry_set_cache *exfat_get_dentry_set(struct super_block *sb, -+ struct exfat_chain *p_dir, int entry, unsigned int type, -+ struct exfat_dentry **file_ep) -+{ -+ int ret; -+ unsigned int off, byte_offset, clu = 0; -+ unsigned int entry_type; -+ sector_t sec; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct exfat_entry_set_cache *es; -+ struct exfat_dentry *ep, *pos; -+ unsigned char num_entries; -+ enum exfat_validate_dentry_mode mode = ES_MODE_STARTED; -+ struct buffer_head *bh; -+ -+ if (p_dir->dir == DIR_DELETED) { -+ exfat_msg(sb, KERN_ERR, "access to deleted dentry\n"); -+ return NULL; -+ } -+ -+ byte_offset = EXFAT_DEN_TO_B(entry); -+ ret = exfat_walk_fat_chain(sb, p_dir, byte_offset, &clu); -+ if (ret) -+ return NULL; -+ -+ /* byte offset in cluster */ -+ byte_offset = EXFAT_CLU_OFFSET(byte_offset, sbi); -+ -+ /* byte offset in sector */ -+ off = EXFAT_BLK_OFFSET(byte_offset, sb); -+ -+ /* sector offset in cluster */ -+ sec = EXFAT_B_TO_BLK(byte_offset, sb); -+ sec += exfat_cluster_to_sector(sbi, clu); -+ -+ bh = sb_bread(sb, sec); -+ if (!bh) -+ return NULL; -+ -+ ep = (struct exfat_dentry *)(bh->b_data + off); -+ entry_type = exfat_get_entry_type(ep); -+ -+ if (entry_type != TYPE_FILE && entry_type != TYPE_DIR) -+ goto release_bh; -+ -+ num_entries = type == ES_ALL_ENTRIES ? -+ ep->dentry.file.num_ext + 1 : type; -+ es = kmalloc(struct_size(es, entries, num_entries), GFP_KERNEL); -+ if (!es) -+ goto release_bh; -+ -+ es->num_entries = num_entries; -+ es->sector = sec; -+ es->offset = off; -+ es->alloc_flag = p_dir->flags; -+ -+ pos = &es->entries[0]; -+ -+ while (num_entries) { -+ if (!exfat_validate_entry(exfat_get_entry_type(ep), &mode)) -+ goto free_es; -+ -+ /* copy dentry */ -+ memcpy(pos, ep, sizeof(struct exfat_dentry)); -+ -+ if (--num_entries == 0) -+ break; -+ -+ if (((off + DENTRY_SIZE) & (sb->s_blocksize - 1)) < -+ (off & (sb->s_blocksize - 1))) { -+ /* get the next sector */ -+ if (exfat_is_last_sector_in_cluster(sbi, sec)) { -+ if (es->alloc_flag == ALLOC_NO_FAT_CHAIN) -+ clu++; -+ else if (exfat_get_next_cluster(sb, &clu)) -+ goto free_es; -+ sec = exfat_cluster_to_sector(sbi, clu); -+ } else { -+ sec++; -+ } -+ -+ brelse(bh); -+ bh = sb_bread(sb, sec); -+ if (!bh) -+ goto free_es; -+ off = 0; -+ ep = (struct exfat_dentry *)bh->b_data; -+ } else { -+ ep++; -+ off += DENTRY_SIZE; -+ } -+ pos++; -+ } -+ -+ if (file_ep) -+ *file_ep = &es->entries[0]; -+ brelse(bh); -+ return es; -+ -+free_es: -+ kfree(es); -+release_bh: -+ brelse(bh); -+ return NULL; -+} -+ -+enum { -+ DIRENT_STEP_FILE, -+ DIRENT_STEP_STRM, -+ DIRENT_STEP_NAME, -+ DIRENT_STEP_SECD, -+}; -+ -+/* -+ * return values: -+ * >= 0 : return dir entiry position with the name in dir -+ * -EEXIST : (root dir, ".") it is the root dir itself -+ * -ENOENT : entry with the name does not exist -+ * -EIO : I/O error -+ */ -+int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei, -+ struct exfat_chain *p_dir, struct exfat_uni_name *p_uniname, -+ int num_entries, unsigned int type) -+{ -+ int i, rewind = 0, dentry = 0, end_eidx = 0, num_ext = 0, len; -+ int order, step, name_len = 0; -+ int dentries_per_clu, num_empty = 0; -+ unsigned int entry_type; -+ unsigned short *uniname = NULL; -+ struct exfat_chain clu; -+ struct exfat_hint *hint_stat = &ei->hint_stat; -+ struct exfat_hint_femp candi_empty; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ -+ dentries_per_clu = sbi->dentries_per_clu; -+ -+ exfat_chain_dup(&clu, p_dir); -+ -+ if (hint_stat->eidx) { -+ clu.dir = hint_stat->clu; -+ dentry = hint_stat->eidx; -+ end_eidx = dentry; -+ } -+ -+ candi_empty.eidx = EXFAT_HINT_NONE; -+rewind: -+ order = 0; -+ step = DIRENT_STEP_FILE; -+ while (clu.dir != EXFAT_EOF_CLUSTER) { -+ i = dentry & (dentries_per_clu - 1); -+ for (; i < dentries_per_clu; i++, dentry++) { -+ struct exfat_dentry *ep; -+ struct buffer_head *bh; -+ -+ if (rewind && dentry == end_eidx) -+ goto not_found; -+ -+ ep = exfat_get_dentry(sb, &clu, i, &bh, NULL); -+ if (!ep) -+ return -EIO; -+ -+ entry_type = exfat_get_entry_type(ep); -+ -+ if (entry_type == TYPE_UNUSED || -+ entry_type == TYPE_DELETED) { -+ step = DIRENT_STEP_FILE; -+ -+ num_empty++; -+ if (candi_empty.eidx == EXFAT_HINT_NONE && -+ num_empty == 1) { -+ exfat_chain_set(&candi_empty.cur, -+ clu.dir, clu.size, clu.flags); -+ } -+ -+ if (candi_empty.eidx == EXFAT_HINT_NONE && -+ num_empty >= num_entries) { -+ candi_empty.eidx = -+ dentry - (num_empty - 1); -+ WARN_ON(candi_empty.eidx < 0); -+ candi_empty.count = num_empty; -+ -+ if (ei->hint_femp.eidx == -+ EXFAT_HINT_NONE || -+ candi_empty.eidx <= -+ ei->hint_femp.eidx) { -+ memcpy(&ei->hint_femp, -+ &candi_empty, -+ sizeof(candi_empty)); -+ } -+ } -+ -+ brelse(bh); -+ if (entry_type == TYPE_UNUSED) -+ goto not_found; -+ continue; -+ } -+ -+ num_empty = 0; -+ candi_empty.eidx = EXFAT_HINT_NONE; -+ -+ if (entry_type == TYPE_FILE || entry_type == TYPE_DIR) { -+ step = DIRENT_STEP_FILE; -+ if (type == TYPE_ALL || type == entry_type) { -+ num_ext = ep->dentry.file.num_ext; -+ step = DIRENT_STEP_STRM; -+ } -+ brelse(bh); -+ continue; -+ } -+ -+ if (entry_type == TYPE_STREAM) { -+ unsigned short name_hash; -+ -+ if (step != DIRENT_STEP_STRM) { -+ step = DIRENT_STEP_FILE; -+ brelse(bh); -+ continue; -+ } -+ step = DIRENT_STEP_FILE; -+ name_hash = le16_to_cpu( -+ ep->dentry.stream.name_hash); -+ if (p_uniname->name_hash == name_hash && -+ p_uniname->name_len == -+ ep->dentry.stream.name_len) { -+ step = DIRENT_STEP_NAME; -+ order = 1; -+ name_len = 0; -+ } -+ brelse(bh); -+ continue; -+ } -+ -+ brelse(bh); -+ if (entry_type == TYPE_EXTEND) { -+ unsigned short entry_uniname[16], unichar; -+ -+ if (step != DIRENT_STEP_NAME) { -+ step = DIRENT_STEP_FILE; -+ continue; -+ } -+ -+ if (++order == 2) -+ uniname = p_uniname->name; -+ else -+ uniname += EXFAT_FILE_NAME_LEN; -+ -+ len = exfat_extract_uni_name(ep, entry_uniname); -+ name_len += len; -+ -+ unichar = *(uniname+len); -+ *(uniname+len) = 0x0; -+ -+ if (exfat_uniname_ncmp(sb, uniname, -+ entry_uniname, len)) { -+ step = DIRENT_STEP_FILE; -+ } else if (p_uniname->name_len == name_len) { -+ if (order == num_ext) -+ goto found; -+ step = DIRENT_STEP_SECD; -+ } -+ -+ *(uniname+len) = unichar; -+ continue; -+ } -+ -+ if (entry_type & -+ (TYPE_CRITICAL_SEC | TYPE_BENIGN_SEC)) { -+ if (step == DIRENT_STEP_SECD) { -+ if (++order == num_ext) -+ goto found; -+ continue; -+ } -+ } -+ step = DIRENT_STEP_FILE; -+ } -+ -+ if (clu.flags == ALLOC_NO_FAT_CHAIN) { -+ if (--clu.size > 0) -+ clu.dir++; -+ else -+ clu.dir = EXFAT_EOF_CLUSTER; -+ } else { -+ if (exfat_get_next_cluster(sb, &clu.dir)) -+ return -EIO; -+ } -+ } -+ -+not_found: -+ /* -+ * We started at not 0 index,so we should try to find target -+ * from 0 index to the index we started at. -+ */ -+ if (!rewind && end_eidx) { -+ rewind = 1; -+ dentry = 0; -+ clu.dir = p_dir->dir; -+ /* reset empty hint */ -+ num_empty = 0; -+ candi_empty.eidx = EXFAT_HINT_NONE; -+ goto rewind; -+ } -+ -+ /* initialized hint_stat */ -+ hint_stat->clu = p_dir->dir; -+ hint_stat->eidx = 0; -+ return -ENOENT; -+ -+found: -+ /* next dentry we'll find is out of this cluster */ -+ if (!((dentry + 1) & (dentries_per_clu - 1))) { -+ int ret = 0; -+ -+ if (clu.flags == ALLOC_NO_FAT_CHAIN) { -+ if (--clu.size > 0) -+ clu.dir++; -+ else -+ clu.dir = EXFAT_EOF_CLUSTER; -+ } else { -+ ret = exfat_get_next_cluster(sb, &clu.dir); -+ } -+ -+ if (ret || clu.dir != EXFAT_EOF_CLUSTER) { -+ /* just initialized hint_stat */ -+ hint_stat->clu = p_dir->dir; -+ hint_stat->eidx = 0; -+ return (dentry - num_ext); -+ } -+ } -+ -+ hint_stat->clu = clu.dir; -+ hint_stat->eidx = dentry + 1; -+ return dentry - num_ext; -+} -+ -+int exfat_count_ext_entries(struct super_block *sb, struct exfat_chain *p_dir, -+ int entry, struct exfat_dentry *ep) -+{ -+ int i, count = 0; -+ unsigned int type; -+ struct exfat_dentry *ext_ep; -+ struct buffer_head *bh; -+ -+ for (i = 0, entry++; i < ep->dentry.file.num_ext; i++, entry++) { -+ ext_ep = exfat_get_dentry(sb, p_dir, entry, &bh, NULL); -+ if (!ext_ep) -+ return -EIO; -+ -+ type = exfat_get_entry_type(ext_ep); -+ brelse(bh); -+ if (type == TYPE_EXTEND || type == TYPE_STREAM) -+ count++; -+ else -+ break; -+ } -+ return count; -+} -+ -+int exfat_count_dir_entries(struct super_block *sb, struct exfat_chain *p_dir) -+{ -+ int i, count = 0; -+ int dentries_per_clu; -+ unsigned int entry_type; -+ struct exfat_chain clu; -+ struct exfat_dentry *ep; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct buffer_head *bh; -+ -+ dentries_per_clu = sbi->dentries_per_clu; -+ -+ exfat_chain_dup(&clu, p_dir); -+ -+ while (clu.dir != EXFAT_EOF_CLUSTER) { -+ for (i = 0; i < dentries_per_clu; i++) { -+ ep = exfat_get_dentry(sb, &clu, i, &bh, NULL); -+ if (!ep) -+ return -EIO; -+ entry_type = exfat_get_entry_type(ep); -+ brelse(bh); -+ -+ if (entry_type == TYPE_UNUSED) -+ return count; -+ if (entry_type != TYPE_DIR) -+ continue; -+ count++; -+ } -+ -+ if (clu.flags == ALLOC_NO_FAT_CHAIN) { -+ if (--clu.size > 0) -+ clu.dir++; -+ else -+ clu.dir = EXFAT_EOF_CLUSTER; -+ } else { -+ if (exfat_get_next_cluster(sb, &(clu.dir))) -+ return -EIO; -+ } -+ } -+ -+ return count; -+} --- -2.25.1 - diff --git a/kernel/tools/perf/files/patches/mageia/fs-exfat-add-exfat-cache.patch b/kernel/tools/perf/files/patches/mageia/fs-exfat-add-exfat-cache.patch deleted file mode 100644 index 179a1226ea..0000000000 --- a/kernel/tools/perf/files/patches/mageia/fs-exfat-add-exfat-cache.patch +++ /dev/null @@ -1,354 +0,0 @@ -From c35b6810c4952ae5776607e2c1d6a587425d5834 Mon Sep 17 00:00:00 2001 -From: Namjae Jeon -Date: Mon, 2 Mar 2020 15:21:39 +0900 -Subject: [PATCH 08/14] exfat: add exfat cache -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This adds the implementation of exfat cache. - -Signed-off-by: Namjae Jeon -Signed-off-by: Sungjong Seo -Reviewed-by: Pali Rohár -Reviewed-by: Christoph Hellwig -Signed-off-by: Al Viro ---- - fs/exfat/cache.c | 325 +++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 325 insertions(+) - create mode 100644 fs/exfat/cache.c - -diff --git a/fs/exfat/cache.c b/fs/exfat/cache.c -new file mode 100644 -index 000000000000..03d0824fc368 ---- /dev/null -+++ b/fs/exfat/cache.c -@@ -0,0 +1,325 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * linux/fs/fat/cache.c -+ * -+ * Written 1992,1993 by Werner Almesberger -+ * -+ * Mar 1999. AV. Changed cache, so that it uses the starting cluster instead -+ * of inode number. -+ * May 1999. AV. Fixed the bogosity with FAT32 (read "FAT28"). Fscking lusers. -+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -+ */ -+ -+#include -+#include -+#include -+ -+#include "exfat_raw.h" -+#include "exfat_fs.h" -+ -+#define EXFAT_CACHE_VALID 0 -+#define EXFAT_MAX_CACHE 16 -+ -+struct exfat_cache { -+ struct list_head cache_list; -+ unsigned int nr_contig; /* number of contiguous clusters */ -+ unsigned int fcluster; /* cluster number in the file. */ -+ unsigned int dcluster; /* cluster number on disk. */ -+}; -+ -+struct exfat_cache_id { -+ unsigned int id; -+ unsigned int nr_contig; -+ unsigned int fcluster; -+ unsigned int dcluster; -+}; -+ -+static struct kmem_cache *exfat_cachep; -+ -+static void exfat_cache_init_once(void *c) -+{ -+ struct exfat_cache *cache = (struct exfat_cache *)c; -+ -+ INIT_LIST_HEAD(&cache->cache_list); -+} -+ -+int exfat_cache_init(void) -+{ -+ exfat_cachep = kmem_cache_create("exfat_cache", -+ sizeof(struct exfat_cache), -+ 0, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, -+ exfat_cache_init_once); -+ if (!exfat_cachep) -+ return -ENOMEM; -+ return 0; -+} -+ -+void exfat_cache_shutdown(void) -+{ -+ if (!exfat_cachep) -+ return; -+ kmem_cache_destroy(exfat_cachep); -+} -+ -+void exfat_cache_init_inode(struct inode *inode) -+{ -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ -+ spin_lock_init(&ei->cache_lru_lock); -+ ei->nr_caches = 0; -+ ei->cache_valid_id = EXFAT_CACHE_VALID + 1; -+ INIT_LIST_HEAD(&ei->cache_lru); -+} -+ -+static inline struct exfat_cache *exfat_cache_alloc(void) -+{ -+ return kmem_cache_alloc(exfat_cachep, GFP_NOFS); -+} -+ -+static inline void exfat_cache_free(struct exfat_cache *cache) -+{ -+ WARN_ON(!list_empty(&cache->cache_list)); -+ kmem_cache_free(exfat_cachep, cache); -+} -+ -+static inline void exfat_cache_update_lru(struct inode *inode, -+ struct exfat_cache *cache) -+{ -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ -+ if (ei->cache_lru.next != &cache->cache_list) -+ list_move(&cache->cache_list, &ei->cache_lru); -+} -+ -+static unsigned int exfat_cache_lookup(struct inode *inode, -+ unsigned int fclus, struct exfat_cache_id *cid, -+ unsigned int *cached_fclus, unsigned int *cached_dclus) -+{ -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ static struct exfat_cache nohit = { .fcluster = 0, }; -+ struct exfat_cache *hit = &nohit, *p; -+ unsigned int offset = EXFAT_EOF_CLUSTER; -+ -+ spin_lock(&ei->cache_lru_lock); -+ list_for_each_entry(p, &ei->cache_lru, cache_list) { -+ /* Find the cache of "fclus" or nearest cache. */ -+ if (p->fcluster <= fclus && hit->fcluster < p->fcluster) { -+ hit = p; -+ if (hit->fcluster + hit->nr_contig < fclus) { -+ offset = hit->nr_contig; -+ } else { -+ offset = fclus - hit->fcluster; -+ break; -+ } -+ } -+ } -+ if (hit != &nohit) { -+ exfat_cache_update_lru(inode, hit); -+ -+ cid->id = ei->cache_valid_id; -+ cid->nr_contig = hit->nr_contig; -+ cid->fcluster = hit->fcluster; -+ cid->dcluster = hit->dcluster; -+ *cached_fclus = cid->fcluster + offset; -+ *cached_dclus = cid->dcluster + offset; -+ } -+ spin_unlock(&ei->cache_lru_lock); -+ -+ return offset; -+} -+ -+static struct exfat_cache *exfat_cache_merge(struct inode *inode, -+ struct exfat_cache_id *new) -+{ -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ struct exfat_cache *p; -+ -+ list_for_each_entry(p, &ei->cache_lru, cache_list) { -+ /* Find the same part as "new" in cluster-chain. */ -+ if (p->fcluster == new->fcluster) { -+ if (new->nr_contig > p->nr_contig) -+ p->nr_contig = new->nr_contig; -+ return p; -+ } -+ } -+ return NULL; -+} -+ -+static void exfat_cache_add(struct inode *inode, -+ struct exfat_cache_id *new) -+{ -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ struct exfat_cache *cache, *tmp; -+ -+ if (new->fcluster == EXFAT_EOF_CLUSTER) /* dummy cache */ -+ return; -+ -+ spin_lock(&ei->cache_lru_lock); -+ if (new->id != EXFAT_CACHE_VALID && -+ new->id != ei->cache_valid_id) -+ goto unlock; /* this cache was invalidated */ -+ -+ cache = exfat_cache_merge(inode, new); -+ if (cache == NULL) { -+ if (ei->nr_caches < EXFAT_MAX_CACHE) { -+ ei->nr_caches++; -+ spin_unlock(&ei->cache_lru_lock); -+ -+ tmp = exfat_cache_alloc(); -+ if (!tmp) { -+ spin_lock(&ei->cache_lru_lock); -+ ei->nr_caches--; -+ spin_unlock(&ei->cache_lru_lock); -+ return; -+ } -+ -+ spin_lock(&ei->cache_lru_lock); -+ cache = exfat_cache_merge(inode, new); -+ if (cache != NULL) { -+ ei->nr_caches--; -+ exfat_cache_free(tmp); -+ goto out_update_lru; -+ } -+ cache = tmp; -+ } else { -+ struct list_head *p = ei->cache_lru.prev; -+ -+ cache = list_entry(p, -+ struct exfat_cache, cache_list); -+ } -+ cache->fcluster = new->fcluster; -+ cache->dcluster = new->dcluster; -+ cache->nr_contig = new->nr_contig; -+ } -+out_update_lru: -+ exfat_cache_update_lru(inode, cache); -+unlock: -+ spin_unlock(&ei->cache_lru_lock); -+} -+ -+/* -+ * Cache invalidation occurs rarely, thus the LRU chain is not updated. It -+ * fixes itself after a while. -+ */ -+static void __exfat_cache_inval_inode(struct inode *inode) -+{ -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ struct exfat_cache *cache; -+ -+ while (!list_empty(&ei->cache_lru)) { -+ cache = list_entry(ei->cache_lru.next, -+ struct exfat_cache, cache_list); -+ list_del_init(&cache->cache_list); -+ ei->nr_caches--; -+ exfat_cache_free(cache); -+ } -+ /* Update. The copy of caches before this id is discarded. */ -+ ei->cache_valid_id++; -+ if (ei->cache_valid_id == EXFAT_CACHE_VALID) -+ ei->cache_valid_id++; -+} -+ -+void exfat_cache_inval_inode(struct inode *inode) -+{ -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ -+ spin_lock(&ei->cache_lru_lock); -+ __exfat_cache_inval_inode(inode); -+ spin_unlock(&ei->cache_lru_lock); -+} -+ -+static inline int cache_contiguous(struct exfat_cache_id *cid, -+ unsigned int dclus) -+{ -+ cid->nr_contig++; -+ return cid->dcluster + cid->nr_contig == dclus; -+} -+ -+static inline void cache_init(struct exfat_cache_id *cid, -+ unsigned int fclus, unsigned int dclus) -+{ -+ cid->id = EXFAT_CACHE_VALID; -+ cid->fcluster = fclus; -+ cid->dcluster = dclus; -+ cid->nr_contig = 0; -+} -+ -+int exfat_get_cluster(struct inode *inode, unsigned int cluster, -+ unsigned int *fclus, unsigned int *dclus, -+ unsigned int *last_dclus, int allow_eof) -+{ -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ unsigned int limit = sbi->num_clusters; -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ struct exfat_cache_id cid; -+ unsigned int content; -+ -+ if (ei->start_clu == EXFAT_FREE_CLUSTER) { -+ exfat_fs_error(sb, -+ "invalid access to exfat cache (entry 0x%08x)", -+ ei->start_clu); -+ return -EIO; -+ } -+ -+ *fclus = 0; -+ *dclus = ei->start_clu; -+ *last_dclus = *dclus; -+ -+ /* -+ * Don`t use exfat_cache if zero offset or non-cluster allocation -+ */ -+ if (cluster == 0 || *dclus == EXFAT_EOF_CLUSTER) -+ return 0; -+ -+ cache_init(&cid, EXFAT_EOF_CLUSTER, EXFAT_EOF_CLUSTER); -+ -+ if (exfat_cache_lookup(inode, cluster, &cid, fclus, dclus) == -+ EXFAT_EOF_CLUSTER) { -+ /* -+ * dummy, always not contiguous -+ * This is reinitialized by cache_init(), later. -+ */ -+ WARN_ON(cid.id != EXFAT_CACHE_VALID || -+ cid.fcluster != EXFAT_EOF_CLUSTER || -+ cid.dcluster != EXFAT_EOF_CLUSTER || -+ cid.nr_contig != 0); -+ } -+ -+ if (*fclus == cluster) -+ return 0; -+ -+ while (*fclus < cluster) { -+ /* prevent the infinite loop of cluster chain */ -+ if (*fclus > limit) { -+ exfat_fs_error(sb, -+ "detected the cluster chain loop (i_pos %u)", -+ (*fclus)); -+ return -EIO; -+ } -+ -+ if (exfat_ent_get(sb, *dclus, &content)) -+ return -EIO; -+ -+ *last_dclus = *dclus; -+ *dclus = content; -+ (*fclus)++; -+ -+ if (content == EXFAT_EOF_CLUSTER) { -+ if (!allow_eof) { -+ exfat_fs_error(sb, -+ "invalid cluster chain (i_pos %u, last_clus 0x%08x is EOF)", -+ *fclus, (*last_dclus)); -+ return -EIO; -+ } -+ -+ break; -+ } -+ -+ if (!cache_contiguous(&cid, *dclus)) -+ cache_init(&cid, *fclus, *dclus); -+ } -+ -+ exfat_cache_add(inode, &cid); -+ return 0; -+} --- -2.25.1 - diff --git a/kernel/tools/perf/files/patches/mageia/fs-exfat-add-fat-entry-operations.patch b/kernel/tools/perf/files/patches/mageia/fs-exfat-add-fat-entry-operations.patch deleted file mode 100644 index 5d0f4f3553..0000000000 --- a/kernel/tools/perf/files/patches/mageia/fs-exfat-add-fat-entry-operations.patch +++ /dev/null @@ -1,492 +0,0 @@ -From 31023864e67a5f390cefbe92f72343027dc3aa33 Mon Sep 17 00:00:00 2001 -From: Namjae Jeon -Date: Mon, 2 Mar 2020 15:21:37 +0900 -Subject: [PATCH 06/14] exfat: add fat entry operations -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This adds the implementation of fat entry operations for exfat. - -Signed-off-by: Namjae Jeon -Signed-off-by: Sungjong Seo -Reviewed-by: Pali Rohár -Reviewed-by: Christoph Hellwig -Signed-off-by: Al Viro ---- - fs/exfat/fatent.c | 463 ++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 463 insertions(+) - create mode 100644 fs/exfat/fatent.c - -diff --git a/fs/exfat/fatent.c b/fs/exfat/fatent.c -new file mode 100644 -index 000000000000..a855b1769a96 ---- /dev/null -+++ b/fs/exfat/fatent.c -@@ -0,0 +1,463 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -+ */ -+ -+#include -+#include -+#include -+ -+#include "exfat_raw.h" -+#include "exfat_fs.h" -+ -+static int exfat_mirror_bh(struct super_block *sb, sector_t sec, -+ struct buffer_head *bh) -+{ -+ struct buffer_head *c_bh; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ sector_t sec2; -+ int err = 0; -+ -+ if (sbi->FAT2_start_sector != sbi->FAT1_start_sector) { -+ sec2 = sec - sbi->FAT1_start_sector + sbi->FAT2_start_sector; -+ c_bh = sb_getblk(sb, sec2); -+ if (!c_bh) -+ return -ENOMEM; -+ memcpy(c_bh->b_data, bh->b_data, sb->s_blocksize); -+ set_buffer_uptodate(c_bh); -+ mark_buffer_dirty(c_bh); -+ if (sb->s_flags & SB_SYNCHRONOUS) -+ err = sync_dirty_buffer(c_bh); -+ brelse(c_bh); -+ } -+ -+ return err; -+} -+ -+static int __exfat_ent_get(struct super_block *sb, unsigned int loc, -+ unsigned int *content) -+{ -+ unsigned int off; -+ sector_t sec; -+ struct buffer_head *bh; -+ -+ sec = FAT_ENT_OFFSET_SECTOR(sb, loc); -+ off = FAT_ENT_OFFSET_BYTE_IN_SECTOR(sb, loc); -+ -+ bh = sb_bread(sb, sec); -+ if (!bh) -+ return -EIO; -+ -+ *content = le32_to_cpu(*(__le32 *)(&bh->b_data[off])); -+ -+ /* remap reserved clusters to simplify code */ -+ if (*content > EXFAT_BAD_CLUSTER) -+ *content = EXFAT_EOF_CLUSTER; -+ -+ brelse(bh); -+ return 0; -+} -+ -+int exfat_ent_set(struct super_block *sb, unsigned int loc, -+ unsigned int content) -+{ -+ unsigned int off; -+ sector_t sec; -+ __le32 *fat_entry; -+ struct buffer_head *bh; -+ -+ sec = FAT_ENT_OFFSET_SECTOR(sb, loc); -+ off = FAT_ENT_OFFSET_BYTE_IN_SECTOR(sb, loc); -+ -+ bh = sb_bread(sb, sec); -+ if (!bh) -+ return -EIO; -+ -+ fat_entry = (__le32 *)&(bh->b_data[off]); -+ *fat_entry = cpu_to_le32(content); -+ exfat_update_bh(sb, bh, sb->s_flags & SB_SYNCHRONOUS); -+ exfat_mirror_bh(sb, sec, bh); -+ brelse(bh); -+ return 0; -+} -+ -+static inline bool is_valid_cluster(struct exfat_sb_info *sbi, -+ unsigned int clus) -+{ -+ if (clus < EXFAT_FIRST_CLUSTER || sbi->num_clusters <= clus) -+ return false; -+ return true; -+} -+ -+int exfat_ent_get(struct super_block *sb, unsigned int loc, -+ unsigned int *content) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ int err; -+ -+ if (!is_valid_cluster(sbi, loc)) { -+ exfat_fs_error(sb, "invalid access to FAT (entry 0x%08x)", -+ loc); -+ return -EIO; -+ } -+ -+ err = __exfat_ent_get(sb, loc, content); -+ if (err) { -+ exfat_fs_error(sb, -+ "failed to access to FAT (entry 0x%08x, err:%d)", -+ loc, err); -+ return err; -+ } -+ -+ if (*content == EXFAT_FREE_CLUSTER) { -+ exfat_fs_error(sb, -+ "invalid access to FAT free cluster (entry 0x%08x)", -+ loc); -+ return -EIO; -+ } -+ -+ if (*content == EXFAT_BAD_CLUSTER) { -+ exfat_fs_error(sb, -+ "invalid access to FAT bad cluster (entry 0x%08x)", -+ loc); -+ return -EIO; -+ } -+ -+ if (*content != EXFAT_EOF_CLUSTER && !is_valid_cluster(sbi, *content)) { -+ exfat_fs_error(sb, -+ "invalid access to FAT (entry 0x%08x) bogus content (0x%08x)", -+ loc, *content); -+ return -EIO; -+ } -+ -+ return 0; -+} -+ -+int exfat_chain_cont_cluster(struct super_block *sb, unsigned int chain, -+ unsigned int len) -+{ -+ if (!len) -+ return 0; -+ -+ while (len > 1) { -+ if (exfat_ent_set(sb, chain, chain + 1)) -+ return -EIO; -+ chain++; -+ len--; -+ } -+ -+ if (exfat_ent_set(sb, chain, EXFAT_EOF_CLUSTER)) -+ return -EIO; -+ return 0; -+} -+ -+int exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain) -+{ -+ unsigned int num_clusters = 0; -+ unsigned int clu; -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ -+ /* invalid cluster number */ -+ if (p_chain->dir == EXFAT_FREE_CLUSTER || -+ p_chain->dir == EXFAT_EOF_CLUSTER || -+ p_chain->dir < EXFAT_FIRST_CLUSTER) -+ return 0; -+ -+ /* no cluster to truncate */ -+ if (p_chain->size == 0) -+ return 0; -+ -+ /* check cluster validation */ -+ if (p_chain->dir < 2 && p_chain->dir >= sbi->num_clusters) { -+ exfat_msg(sb, KERN_ERR, "invalid start cluster (%u)", -+ p_chain->dir); -+ return -EIO; -+ } -+ -+ set_bit(EXFAT_SB_DIRTY, &sbi->s_state); -+ clu = p_chain->dir; -+ -+ if (p_chain->flags == ALLOC_NO_FAT_CHAIN) { -+ do { -+ exfat_clear_bitmap(inode, clu); -+ clu++; -+ -+ num_clusters++; -+ } while (num_clusters < p_chain->size); -+ } else { -+ do { -+ exfat_clear_bitmap(inode, clu); -+ -+ if (exfat_get_next_cluster(sb, &clu)) -+ goto dec_used_clus; -+ -+ num_clusters++; -+ } while (clu != EXFAT_EOF_CLUSTER); -+ } -+ -+dec_used_clus: -+ sbi->used_clusters -= num_clusters; -+ return 0; -+} -+ -+int exfat_find_last_cluster(struct super_block *sb, struct exfat_chain *p_chain, -+ unsigned int *ret_clu) -+{ -+ unsigned int clu, next; -+ unsigned int count = 0; -+ -+ next = p_chain->dir; -+ if (p_chain->flags == ALLOC_NO_FAT_CHAIN) { -+ *ret_clu = next + p_chain->size - 1; -+ return 0; -+ } -+ -+ do { -+ count++; -+ clu = next; -+ if (exfat_ent_get(sb, clu, &next)) -+ return -EIO; -+ } while (next != EXFAT_EOF_CLUSTER); -+ -+ if (p_chain->size != count) { -+ exfat_fs_error(sb, -+ "bogus directory size (clus : ondisk(%d) != counted(%d))", -+ p_chain->size, count); -+ return -EIO; -+ } -+ -+ *ret_clu = clu; -+ return 0; -+} -+ -+static inline int exfat_sync_bhs(struct buffer_head **bhs, int nr_bhs) -+{ -+ int i, err = 0; -+ -+ for (i = 0; i < nr_bhs; i++) -+ write_dirty_buffer(bhs[i], 0); -+ -+ for (i = 0; i < nr_bhs; i++) { -+ wait_on_buffer(bhs[i]); -+ if (!err && !buffer_uptodate(bhs[i])) -+ err = -EIO; -+ } -+ return err; -+} -+ -+int exfat_zeroed_cluster(struct inode *dir, unsigned int clu) -+{ -+ struct super_block *sb = dir->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct buffer_head *bhs[MAX_BUF_PER_PAGE]; -+ int nr_bhs = MAX_BUF_PER_PAGE; -+ sector_t blknr, last_blknr; -+ int err, i, n; -+ -+ blknr = exfat_cluster_to_sector(sbi, clu); -+ last_blknr = blknr + sbi->sect_per_clus; -+ -+ if (last_blknr > sbi->num_sectors && sbi->num_sectors > 0) { -+ exfat_fs_error_ratelimit(sb, -+ "%s: out of range(sect:%llu len:%u)", -+ __func__, (unsigned long long)blknr, -+ sbi->sect_per_clus); -+ return -EIO; -+ } -+ -+ /* Zeroing the unused blocks on this cluster */ -+ n = 0; -+ while (blknr < last_blknr) { -+ bhs[n] = sb_getblk(sb, blknr); -+ if (!bhs[n]) { -+ err = -ENOMEM; -+ goto release_bhs; -+ } -+ memset(bhs[n]->b_data, 0, sb->s_blocksize); -+ exfat_update_bh(sb, bhs[n], 0); -+ -+ n++; -+ blknr++; -+ -+ if (n == nr_bhs) { -+ if (IS_DIRSYNC(dir)) { -+ err = exfat_sync_bhs(bhs, n); -+ if (err) -+ goto release_bhs; -+ } -+ -+ for (i = 0; i < n; i++) -+ brelse(bhs[i]); -+ n = 0; -+ } -+ } -+ -+ if (IS_DIRSYNC(dir)) { -+ err = exfat_sync_bhs(bhs, n); -+ if (err) -+ goto release_bhs; -+ } -+ -+ for (i = 0; i < n; i++) -+ brelse(bhs[i]); -+ -+ return 0; -+ -+release_bhs: -+ exfat_msg(sb, KERN_ERR, "failed zeroed sect %llu\n", -+ (unsigned long long)blknr); -+ for (i = 0; i < n; i++) -+ bforget(bhs[i]); -+ return err; -+} -+ -+int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc, -+ struct exfat_chain *p_chain) -+{ -+ int ret = -ENOSPC; -+ unsigned int num_clusters = 0, total_cnt; -+ unsigned int hint_clu, new_clu, last_clu = EXFAT_EOF_CLUSTER; -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ -+ total_cnt = EXFAT_DATA_CLUSTER_COUNT(sbi); -+ -+ if (unlikely(total_cnt < sbi->used_clusters)) { -+ exfat_fs_error_ratelimit(sb, -+ "%s: invalid used clusters(t:%u,u:%u)\n", -+ __func__, total_cnt, sbi->used_clusters); -+ return -EIO; -+ } -+ -+ if (num_alloc > total_cnt - sbi->used_clusters) -+ return -ENOSPC; -+ -+ hint_clu = p_chain->dir; -+ /* find new cluster */ -+ if (hint_clu == EXFAT_EOF_CLUSTER) { -+ if (sbi->clu_srch_ptr < EXFAT_FIRST_CLUSTER) { -+ exfat_msg(sb, KERN_ERR, -+ "sbi->clu_srch_ptr is invalid (%u)\n", -+ sbi->clu_srch_ptr); -+ sbi->clu_srch_ptr = EXFAT_FIRST_CLUSTER; -+ } -+ -+ hint_clu = exfat_find_free_bitmap(sb, sbi->clu_srch_ptr); -+ if (hint_clu == EXFAT_EOF_CLUSTER) -+ return -ENOSPC; -+ } -+ -+ /* check cluster validation */ -+ if (hint_clu < EXFAT_FIRST_CLUSTER && hint_clu >= sbi->num_clusters) { -+ exfat_msg(sb, KERN_ERR, "hint_cluster is invalid (%u)\n", -+ hint_clu); -+ hint_clu = EXFAT_FIRST_CLUSTER; -+ if (p_chain->flags == ALLOC_NO_FAT_CHAIN) { -+ if (exfat_chain_cont_cluster(sb, p_chain->dir, -+ num_clusters)) -+ return -EIO; -+ p_chain->flags = ALLOC_FAT_CHAIN; -+ } -+ } -+ -+ set_bit(EXFAT_SB_DIRTY, &sbi->s_state); -+ -+ p_chain->dir = EXFAT_EOF_CLUSTER; -+ -+ while ((new_clu = exfat_find_free_bitmap(sb, hint_clu)) != -+ EXFAT_EOF_CLUSTER) { -+ if (new_clu != hint_clu && -+ p_chain->flags == ALLOC_NO_FAT_CHAIN) { -+ if (exfat_chain_cont_cluster(sb, p_chain->dir, -+ num_clusters)) { -+ ret = -EIO; -+ goto free_cluster; -+ } -+ p_chain->flags = ALLOC_FAT_CHAIN; -+ } -+ -+ /* update allocation bitmap */ -+ if (exfat_set_bitmap(inode, new_clu)) { -+ ret = -EIO; -+ goto free_cluster; -+ } -+ -+ num_clusters++; -+ -+ /* update FAT table */ -+ if (p_chain->flags == ALLOC_FAT_CHAIN) { -+ if (exfat_ent_set(sb, new_clu, EXFAT_EOF_CLUSTER)) { -+ ret = -EIO; -+ goto free_cluster; -+ } -+ } -+ -+ if (p_chain->dir == EXFAT_EOF_CLUSTER) { -+ p_chain->dir = new_clu; -+ } else if (p_chain->flags == ALLOC_FAT_CHAIN) { -+ if (exfat_ent_set(sb, last_clu, new_clu)) { -+ ret = -EIO; -+ goto free_cluster; -+ } -+ } -+ last_clu = new_clu; -+ -+ if (--num_alloc == 0) { -+ sbi->clu_srch_ptr = hint_clu; -+ sbi->used_clusters += num_clusters; -+ -+ p_chain->size += num_clusters; -+ return 0; -+ } -+ -+ hint_clu = new_clu + 1; -+ if (hint_clu >= sbi->num_clusters) { -+ hint_clu = EXFAT_FIRST_CLUSTER; -+ -+ if (p_chain->flags == ALLOC_NO_FAT_CHAIN) { -+ if (exfat_chain_cont_cluster(sb, p_chain->dir, -+ num_clusters)) { -+ ret = -EIO; -+ goto free_cluster; -+ } -+ p_chain->flags = ALLOC_FAT_CHAIN; -+ } -+ } -+ } -+free_cluster: -+ if (num_clusters) -+ exfat_free_cluster(inode, p_chain); -+ return ret; -+} -+ -+int exfat_count_num_clusters(struct super_block *sb, -+ struct exfat_chain *p_chain, unsigned int *ret_count) -+{ -+ unsigned int i, count; -+ unsigned int clu; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ -+ if (!p_chain->dir || p_chain->dir == EXFAT_EOF_CLUSTER) { -+ *ret_count = 0; -+ return 0; -+ } -+ -+ if (p_chain->flags == ALLOC_NO_FAT_CHAIN) { -+ *ret_count = p_chain->size; -+ return 0; -+ } -+ -+ clu = p_chain->dir; -+ count = 0; -+ for (i = EXFAT_FIRST_CLUSTER; i < sbi->num_clusters; i++) { -+ count++; -+ if (exfat_ent_get(sb, clu, &clu)) -+ return -EIO; -+ if (clu == EXFAT_EOF_CLUSTER) -+ break; -+ } -+ -+ *ret_count = count; -+ return 0; -+} --- -2.25.1 - diff --git a/kernel/tools/perf/files/patches/mageia/fs-exfat-add-file-operations.patch b/kernel/tools/perf/files/patches/mageia/fs-exfat-add-file-operations.patch deleted file mode 100644 index 49fd0d8357..0000000000 --- a/kernel/tools/perf/files/patches/mageia/fs-exfat-add-file-operations.patch +++ /dev/null @@ -1,390 +0,0 @@ -From 98d917047e8b7f4bb2ff61d81b0ccd94a00444f9 Mon Sep 17 00:00:00 2001 -From: Namjae Jeon -Date: Mon, 2 Mar 2020 15:21:36 +0900 -Subject: [PATCH 05/14] exfat: add file operations -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This adds the implementation of file operations for exfat. - -Signed-off-by: Namjae Jeon -Signed-off-by: Sungjong Seo -Reviewed-by: Pali Rohár -Reviewed-by: Christoph Hellwig -Reviewed-by: Arnd Bergmann -Signed-off-by: Al Viro ---- - fs/exfat/file.c | 360 ++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 360 insertions(+) - create mode 100644 fs/exfat/file.c - -diff --git a/fs/exfat/file.c b/fs/exfat/file.c -new file mode 100644 -index 000000000000..483f683757aa ---- /dev/null -+++ b/fs/exfat/file.c -@@ -0,0 +1,360 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -+ */ -+ -+#include -+#include -+#include -+ -+#include "exfat_raw.h" -+#include "exfat_fs.h" -+ -+static int exfat_cont_expand(struct inode *inode, loff_t size) -+{ -+ struct address_space *mapping = inode->i_mapping; -+ loff_t start = i_size_read(inode), count = size - i_size_read(inode); -+ int err, err2; -+ -+ err = generic_cont_expand_simple(inode, size); -+ if (err) -+ return err; -+ -+ inode->i_ctime = inode->i_mtime = current_time(inode); -+ mark_inode_dirty(inode); -+ -+ if (!IS_SYNC(inode)) -+ return 0; -+ -+ err = filemap_fdatawrite_range(mapping, start, start + count - 1); -+ err2 = sync_mapping_buffers(mapping); -+ if (!err) -+ err = err2; -+ err2 = write_inode_now(inode, 1); -+ if (!err) -+ err = err2; -+ if (err) -+ return err; -+ -+ return filemap_fdatawait_range(mapping, start, start + count - 1); -+} -+ -+static bool exfat_allow_set_time(struct exfat_sb_info *sbi, struct inode *inode) -+{ -+ mode_t allow_utime = sbi->options.allow_utime; -+ -+ if (!uid_eq(current_fsuid(), inode->i_uid)) { -+ if (in_group_p(inode->i_gid)) -+ allow_utime >>= 3; -+ if (allow_utime & MAY_WRITE) -+ return true; -+ } -+ -+ /* use a default check */ -+ return false; -+} -+ -+static int exfat_sanitize_mode(const struct exfat_sb_info *sbi, -+ struct inode *inode, umode_t *mode_ptr) -+{ -+ mode_t i_mode, mask, perm; -+ -+ i_mode = inode->i_mode; -+ -+ mask = (S_ISREG(i_mode) || S_ISLNK(i_mode)) ? -+ sbi->options.fs_fmask : sbi->options.fs_dmask; -+ perm = *mode_ptr & ~(S_IFMT | mask); -+ -+ /* Of the r and x bits, all (subject to umask) must be present.*/ -+ if ((perm & 0555) != (i_mode & 0555)) -+ return -EPERM; -+ -+ if (exfat_mode_can_hold_ro(inode)) { -+ /* -+ * Of the w bits, either all (subject to umask) or none must -+ * be present. -+ */ -+ if ((perm & 0222) && ((perm & 0222) != (0222 & ~mask))) -+ return -EPERM; -+ } else { -+ /* -+ * If exfat_mode_can_hold_ro(inode) is false, can't change -+ * w bits. -+ */ -+ if ((perm & 0222) != (0222 & ~mask)) -+ return -EPERM; -+ } -+ -+ *mode_ptr &= S_IFMT | perm; -+ -+ return 0; -+} -+ -+/* resize the file length */ -+int __exfat_truncate(struct inode *inode, loff_t new_size) -+{ -+ unsigned int num_clusters_new, num_clusters_phys; -+ unsigned int last_clu = EXFAT_FREE_CLUSTER; -+ struct exfat_chain clu; -+ struct exfat_dentry *ep, *ep2; -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ struct exfat_entry_set_cache *es = NULL; -+ int evict = (ei->dir.dir == DIR_DELETED) ? 1 : 0; -+ -+ /* check if the given file ID is opened */ -+ if (ei->type != TYPE_FILE && ei->type != TYPE_DIR) -+ return -EPERM; -+ -+ exfat_set_vol_flags(sb, VOL_DIRTY); -+ -+ num_clusters_new = EXFAT_B_TO_CLU_ROUND_UP(i_size_read(inode), sbi); -+ num_clusters_phys = -+ EXFAT_B_TO_CLU_ROUND_UP(EXFAT_I(inode)->i_size_ondisk, sbi); -+ -+ exfat_chain_set(&clu, ei->start_clu, num_clusters_phys, ei->flags); -+ -+ if (new_size > 0) { -+ /* -+ * Truncate FAT chain num_clusters after the first cluster -+ * num_clusters = min(new, phys); -+ */ -+ unsigned int num_clusters = -+ min(num_clusters_new, num_clusters_phys); -+ -+ /* -+ * Follow FAT chain -+ * (defensive coding - works fine even with corrupted FAT table -+ */ -+ if (clu.flags == ALLOC_NO_FAT_CHAIN) { -+ clu.dir += num_clusters; -+ clu.size -= num_clusters; -+ } else { -+ while (num_clusters > 0) { -+ last_clu = clu.dir; -+ if (exfat_get_next_cluster(sb, &(clu.dir))) -+ return -EIO; -+ -+ num_clusters--; -+ clu.size--; -+ } -+ } -+ } else { -+ ei->flags = ALLOC_NO_FAT_CHAIN; -+ ei->start_clu = EXFAT_EOF_CLUSTER; -+ } -+ -+ i_size_write(inode, new_size); -+ -+ if (ei->type == TYPE_FILE) -+ ei->attr |= ATTR_ARCHIVE; -+ -+ /* update the directory entry */ -+ if (!evict) { -+ struct timespec64 ts; -+ -+ es = exfat_get_dentry_set(sb, &(ei->dir), ei->entry, -+ ES_ALL_ENTRIES, &ep); -+ if (!es) -+ return -EIO; -+ ep2 = ep + 1; -+ -+ ts = current_time(inode); -+ exfat_set_entry_time(sbi, &ts, -+ &ep->dentry.file.modify_tz, -+ &ep->dentry.file.modify_time, -+ &ep->dentry.file.modify_date, -+ &ep->dentry.file.modify_time_ms); -+ ep->dentry.file.attr = cpu_to_le16(ei->attr); -+ -+ /* File size should be zero if there is no cluster allocated */ -+ if (ei->start_clu == EXFAT_EOF_CLUSTER) { -+ ep->dentry.stream.valid_size = 0; -+ ep->dentry.stream.size = 0; -+ } else { -+ ep->dentry.stream.valid_size = cpu_to_le64(new_size); -+ ep->dentry.stream.size = ep->dentry.stream.valid_size; -+ } -+ -+ if (new_size == 0) { -+ /* Any directory can not be truncated to zero */ -+ WARN_ON(ei->type != TYPE_FILE); -+ -+ ep2->dentry.stream.flags = ALLOC_FAT_CHAIN; -+ ep2->dentry.stream.start_clu = EXFAT_FREE_CLUSTER; -+ } -+ -+ if (exfat_update_dir_chksum_with_entry_set(sb, es, -+ inode_needs_sync(inode))) -+ return -EIO; -+ kfree(es); -+ } -+ -+ /* cut off from the FAT chain */ -+ if (ei->flags == ALLOC_FAT_CHAIN && last_clu != EXFAT_FREE_CLUSTER && -+ last_clu != EXFAT_EOF_CLUSTER) { -+ if (exfat_ent_set(sb, last_clu, EXFAT_EOF_CLUSTER)) -+ return -EIO; -+ } -+ -+ /* invalidate cache and free the clusters */ -+ /* clear exfat cache */ -+ exfat_cache_inval_inode(inode); -+ -+ /* hint information */ -+ ei->hint_bmap.off = EXFAT_EOF_CLUSTER; -+ ei->hint_bmap.clu = EXFAT_EOF_CLUSTER; -+ if (ei->rwoffset > new_size) -+ ei->rwoffset = new_size; -+ -+ /* hint_stat will be used if this is directory. */ -+ ei->hint_stat.eidx = 0; -+ ei->hint_stat.clu = ei->start_clu; -+ ei->hint_femp.eidx = EXFAT_HINT_NONE; -+ -+ /* free the clusters */ -+ if (exfat_free_cluster(inode, &clu)) -+ return -EIO; -+ -+ exfat_set_vol_flags(sb, VOL_CLEAN); -+ -+ return 0; -+} -+ -+void exfat_truncate(struct inode *inode, loff_t size) -+{ -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ unsigned int blocksize = 1 << inode->i_blkbits; -+ loff_t aligned_size; -+ int err; -+ -+ mutex_lock(&sbi->s_lock); -+ if (EXFAT_I(inode)->start_clu == 0) { -+ /* -+ * Empty start_clu != ~0 (not allocated) -+ */ -+ exfat_fs_error(sb, "tried to truncate zeroed cluster."); -+ goto write_size; -+ } -+ -+ err = __exfat_truncate(inode, i_size_read(inode)); -+ if (err) -+ goto write_size; -+ -+ inode->i_ctime = inode->i_mtime = current_time(inode); -+ if (IS_DIRSYNC(inode)) -+ exfat_sync_inode(inode); -+ else -+ mark_inode_dirty(inode); -+ -+ inode->i_blocks = ((i_size_read(inode) + (sbi->cluster_size - 1)) & -+ ~(sbi->cluster_size - 1)) >> inode->i_blkbits; -+write_size: -+ aligned_size = i_size_read(inode); -+ if (aligned_size & (blocksize - 1)) { -+ aligned_size |= (blocksize - 1); -+ aligned_size++; -+ } -+ -+ if (EXFAT_I(inode)->i_size_ondisk > i_size_read(inode)) -+ EXFAT_I(inode)->i_size_ondisk = aligned_size; -+ -+ if (EXFAT_I(inode)->i_size_aligned > i_size_read(inode)) -+ EXFAT_I(inode)->i_size_aligned = aligned_size; -+ mutex_unlock(&sbi->s_lock); -+} -+ -+int exfat_getattr(const struct path *path, struct kstat *stat, -+ unsigned int request_mask, unsigned int query_flags) -+{ -+ struct inode *inode = d_backing_inode(path->dentry); -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ -+ generic_fillattr(inode, stat); -+ stat->result_mask |= STATX_BTIME; -+ stat->btime.tv_sec = ei->i_crtime.tv_sec; -+ stat->btime.tv_nsec = ei->i_crtime.tv_nsec; -+ stat->blksize = EXFAT_SB(inode->i_sb)->cluster_size; -+ return 0; -+} -+ -+int exfat_setattr(struct dentry *dentry, struct iattr *attr) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(dentry->d_sb); -+ struct inode *inode = dentry->d_inode; -+ unsigned int ia_valid; -+ int error; -+ -+ if ((attr->ia_valid & ATTR_SIZE) && -+ attr->ia_size > i_size_read(inode)) { -+ error = exfat_cont_expand(inode, attr->ia_size); -+ if (error || attr->ia_valid == ATTR_SIZE) -+ return error; -+ attr->ia_valid &= ~ATTR_SIZE; -+ } -+ -+ /* Check for setting the inode time. */ -+ ia_valid = attr->ia_valid; -+ if ((ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)) && -+ exfat_allow_set_time(sbi, inode)) { -+ attr->ia_valid &= ~(ATTR_MTIME_SET | ATTR_ATIME_SET | -+ ATTR_TIMES_SET); -+ } -+ -+ error = setattr_prepare(dentry, attr); -+ attr->ia_valid = ia_valid; -+ if (error) -+ goto out; -+ -+ if (((attr->ia_valid & ATTR_UID) && -+ !uid_eq(attr->ia_uid, sbi->options.fs_uid)) || -+ ((attr->ia_valid & ATTR_GID) && -+ !gid_eq(attr->ia_gid, sbi->options.fs_gid)) || -+ ((attr->ia_valid & ATTR_MODE) && -+ (attr->ia_mode & ~(S_IFREG | S_IFLNK | S_IFDIR | 0777)))) { -+ error = -EPERM; -+ goto out; -+ } -+ -+ /* -+ * We don't return -EPERM here. Yes, strange, but this is too -+ * old behavior. -+ */ -+ if (attr->ia_valid & ATTR_MODE) { -+ if (exfat_sanitize_mode(sbi, inode, &attr->ia_mode) < 0) -+ attr->ia_valid &= ~ATTR_MODE; -+ } -+ -+ if (attr->ia_valid & ATTR_SIZE) { -+ error = exfat_block_truncate_page(inode, attr->ia_size); -+ if (error) -+ goto out; -+ -+ down_write(&EXFAT_I(inode)->truncate_lock); -+ truncate_setsize(inode, attr->ia_size); -+ exfat_truncate(inode, attr->ia_size); -+ up_write(&EXFAT_I(inode)->truncate_lock); -+ } -+ -+ setattr_copy(inode, attr); -+ mark_inode_dirty(inode); -+ -+out: -+ return error; -+} -+ -+const struct file_operations exfat_file_operations = { -+ .llseek = generic_file_llseek, -+ .read_iter = generic_file_read_iter, -+ .write_iter = generic_file_write_iter, -+ .mmap = generic_file_mmap, -+ .fsync = generic_file_fsync, -+ .splice_read = generic_file_splice_read, -+}; -+ -+const struct inode_operations exfat_file_inode_operations = { -+ .setattr = exfat_setattr, -+ .getattr = exfat_getattr, -+}; --- -2.25.1 - diff --git a/kernel/tools/perf/files/patches/mageia/fs-exfat-add-in-memory-and-on-disk-structures-and-heade.patch b/kernel/tools/perf/files/patches/mageia/fs-exfat-add-in-memory-and-on-disk-structures-and-heade.patch deleted file mode 100644 index e347a9eec6..0000000000 --- a/kernel/tools/perf/files/patches/mageia/fs-exfat-add-in-memory-and-on-disk-structures-and-heade.patch +++ /dev/null @@ -1,740 +0,0 @@ -From 1acf1a564b6034b5af1e7fb23cb98cb3bb4f6003 Mon Sep 17 00:00:00 2001 -From: Namjae Jeon -Date: Mon, 2 Mar 2020 15:21:32 +0900 -Subject: [PATCH 01/14] exfat: add in-memory and on-disk structures and headers -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This adds in-memory and on-disk structures and headers. - -Signed-off-by: Namjae Jeon -Signed-off-by: Sungjong Seo -Reviewed-by: Pali Rohár -Reviewed-by: Christoph Hellwig -Signed-off-by: Al Viro ---- - fs/exfat/exfat_fs.h | 519 +++++++++++++++++++++++++++++++++++++++++++ - fs/exfat/exfat_raw.h | 184 +++++++++++++++ - 2 files changed, 703 insertions(+) - create mode 100644 fs/exfat/exfat_fs.h - create mode 100644 fs/exfat/exfat_raw.h - -diff --git a/fs/exfat/exfat_fs.h b/fs/exfat/exfat_fs.h -new file mode 100644 -index 000000000000..67d4e46fb810 ---- /dev/null -+++ b/fs/exfat/exfat_fs.h -@@ -0,0 +1,519 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -+ */ -+ -+#ifndef _EXFAT_FS_H -+#define _EXFAT_FS_H -+ -+#include -+#include -+#include -+ -+#define EXFAT_SUPER_MAGIC 0x2011BAB0UL -+#define EXFAT_ROOT_INO 1 -+ -+#define EXFAT_SB_DIRTY 0 -+ -+#define EXFAT_CLUSTERS_UNTRACKED (~0u) -+ -+/* -+ * exfat error flags -+ */ -+enum exfat_error_mode { -+ EXFAT_ERRORS_CONT, /* ignore error and continue */ -+ EXFAT_ERRORS_PANIC, /* panic on error */ -+ EXFAT_ERRORS_RO, /* remount r/o on error */ -+}; -+ -+/* -+ * exfat nls lossy flag -+ */ -+enum { -+ NLS_NAME_NO_LOSSY, /* no lossy */ -+ NLS_NAME_LOSSY, /* just detected incorrect filename(s) */ -+ NLS_NAME_OVERLEN, /* the length is over than its limit */ -+}; -+ -+#define EXFAT_HASH_BITS 8 -+#define EXFAT_HASH_SIZE (1UL << EXFAT_HASH_BITS) -+ -+/* -+ * Type Definitions -+ */ -+#define ES_2_ENTRIES 2 -+#define ES_ALL_ENTRIES 0 -+ -+#define DIR_DELETED 0xFFFF0321 -+ -+/* type values */ -+#define TYPE_UNUSED 0x0000 -+#define TYPE_DELETED 0x0001 -+#define TYPE_INVALID 0x0002 -+#define TYPE_CRITICAL_PRI 0x0100 -+#define TYPE_BITMAP 0x0101 -+#define TYPE_UPCASE 0x0102 -+#define TYPE_VOLUME 0x0103 -+#define TYPE_DIR 0x0104 -+#define TYPE_FILE 0x011F -+#define TYPE_CRITICAL_SEC 0x0200 -+#define TYPE_STREAM 0x0201 -+#define TYPE_EXTEND 0x0202 -+#define TYPE_ACL 0x0203 -+#define TYPE_BENIGN_PRI 0x0400 -+#define TYPE_GUID 0x0401 -+#define TYPE_PADDING 0x0402 -+#define TYPE_ACLTAB 0x0403 -+#define TYPE_BENIGN_SEC 0x0800 -+#define TYPE_ALL 0x0FFF -+ -+#define MAX_CHARSET_SIZE 6 /* max size of multi-byte character */ -+#define MAX_NAME_LENGTH 255 /* max len of file name excluding NULL */ -+#define MAX_VFSNAME_BUF_SIZE ((MAX_NAME_LENGTH + 1) * MAX_CHARSET_SIZE) -+ -+#define FAT_CACHE_SIZE 128 -+#define FAT_CACHE_HASH_SIZE 64 -+#define BUF_CACHE_SIZE 256 -+#define BUF_CACHE_HASH_SIZE 64 -+ -+#define EXFAT_HINT_NONE -1 -+#define EXFAT_MIN_SUBDIR 2 -+ -+/* -+ * helpers for cluster size to byte conversion. -+ */ -+#define EXFAT_CLU_TO_B(b, sbi) ((b) << (sbi)->cluster_size_bits) -+#define EXFAT_B_TO_CLU(b, sbi) ((b) >> (sbi)->cluster_size_bits) -+#define EXFAT_B_TO_CLU_ROUND_UP(b, sbi) \ -+ (((b - 1) >> (sbi)->cluster_size_bits) + 1) -+#define EXFAT_CLU_OFFSET(off, sbi) ((off) & ((sbi)->cluster_size - 1)) -+ -+/* -+ * helpers for block size to byte conversion. -+ */ -+#define EXFAT_BLK_TO_B(b, sb) ((b) << (sb)->s_blocksize_bits) -+#define EXFAT_B_TO_BLK(b, sb) ((b) >> (sb)->s_blocksize_bits) -+#define EXFAT_B_TO_BLK_ROUND_UP(b, sb) \ -+ (((b - 1) >> (sb)->s_blocksize_bits) + 1) -+#define EXFAT_BLK_OFFSET(off, sb) ((off) & ((sb)->s_blocksize - 1)) -+ -+/* -+ * helpers for block size to dentry size conversion. -+ */ -+#define EXFAT_B_TO_DEN_IDX(b, sbi) \ -+ ((b) << ((sbi)->cluster_size_bits - DENTRY_SIZE_BITS)) -+#define EXFAT_B_TO_DEN(b) ((b) >> DENTRY_SIZE_BITS) -+#define EXFAT_DEN_TO_B(b) ((b) << DENTRY_SIZE_BITS) -+ -+/* -+ * helpers for fat entry. -+ */ -+#define FAT_ENT_SIZE (4) -+#define FAT_ENT_SIZE_BITS (2) -+#define FAT_ENT_OFFSET_SECTOR(sb, loc) (EXFAT_SB(sb)->FAT1_start_sector + \ -+ (((u64)loc << FAT_ENT_SIZE_BITS) >> sb->s_blocksize_bits)) -+#define FAT_ENT_OFFSET_BYTE_IN_SECTOR(sb, loc) \ -+ ((loc << FAT_ENT_SIZE_BITS) & (sb->s_blocksize - 1)) -+ -+/* -+ * helpers for bitmap. -+ */ -+#define CLUSTER_TO_BITMAP_ENT(clu) ((clu) - EXFAT_RESERVED_CLUSTERS) -+#define BITMAP_ENT_TO_CLUSTER(ent) ((ent) + EXFAT_RESERVED_CLUSTERS) -+#define BITS_PER_SECTOR(sb) ((sb)->s_blocksize * BITS_PER_BYTE) -+#define BITS_PER_SECTOR_MASK(sb) (BITS_PER_SECTOR(sb) - 1) -+#define BITMAP_OFFSET_SECTOR_INDEX(sb, ent) \ -+ ((ent / BITS_PER_BYTE) >> (sb)->s_blocksize_bits) -+#define BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent) (ent & BITS_PER_SECTOR_MASK(sb)) -+#define BITMAP_OFFSET_BYTE_IN_SECTOR(sb, ent) \ -+ ((ent / BITS_PER_BYTE) & ((sb)->s_blocksize - 1)) -+#define BITS_PER_BYTE_MASK 0x7 -+#define IGNORED_BITS_REMAINED(clu, clu_base) ((1 << ((clu) - (clu_base))) - 1) -+ -+struct exfat_dentry_namebuf { -+ char *lfn; -+ int lfnbuf_len; /* usally MAX_UNINAME_BUF_SIZE */ -+}; -+ -+/* unicode name structure */ -+struct exfat_uni_name { -+ /* +3 for null and for converting */ -+ unsigned short name[MAX_NAME_LENGTH + 3]; -+ unsigned short name_hash; -+ unsigned char name_len; -+}; -+ -+/* directory structure */ -+struct exfat_chain { -+ unsigned int dir; -+ unsigned int size; -+ unsigned char flags; -+}; -+ -+/* first empty entry hint information */ -+struct exfat_hint_femp { -+ /* entry index of a directory */ -+ int eidx; -+ /* count of continuous empty entry */ -+ int count; -+ /* the cluster that first empty slot exists in */ -+ struct exfat_chain cur; -+}; -+ -+/* hint structure */ -+struct exfat_hint { -+ unsigned int clu; -+ union { -+ unsigned int off; /* cluster offset */ -+ int eidx; /* entry index */ -+ }; -+}; -+ -+struct exfat_entry_set_cache { -+ /* sector number that contains file_entry */ -+ sector_t sector; -+ /* byte offset in the sector */ -+ unsigned int offset; -+ /* flag in stream entry. 01 for cluster chain, 03 for contig. */ -+ int alloc_flag; -+ unsigned int num_entries; -+ struct exfat_dentry entries[]; -+}; -+ -+struct exfat_dir_entry { -+ struct exfat_chain dir; -+ int entry; -+ unsigned int type; -+ unsigned int start_clu; -+ unsigned char flags; -+ unsigned short attr; -+ loff_t size; -+ unsigned int num_subdirs; -+ struct timespec64 atime; -+ struct timespec64 mtime; -+ struct timespec64 crtime; -+ struct exfat_dentry_namebuf namebuf; -+}; -+ -+/* -+ * exfat mount in-memory data -+ */ -+struct exfat_mount_options { -+ kuid_t fs_uid; -+ kgid_t fs_gid; -+ unsigned short fs_fmask; -+ unsigned short fs_dmask; -+ /* permission for setting the [am]time */ -+ unsigned short allow_utime; -+ /* charset for filename input/display */ -+ char *iocharset; -+ /* on error: continue, panic, remount-ro */ -+ enum exfat_error_mode errors; -+ unsigned utf8:1, /* Use of UTF-8 character set */ -+ discard:1; /* Issue discard requests on deletions */ -+ int time_offset; /* Offset of timestamps from UTC (in minutes) */ -+}; -+ -+/* -+ * EXFAT file system superblock in-memory data -+ */ -+struct exfat_sb_info { -+ unsigned long long num_sectors; /* num of sectors in volume */ -+ unsigned int num_clusters; /* num of clusters in volume */ -+ unsigned int cluster_size; /* cluster size in bytes */ -+ unsigned int cluster_size_bits; -+ unsigned int sect_per_clus; /* cluster size in sectors */ -+ unsigned int sect_per_clus_bits; -+ unsigned long long FAT1_start_sector; /* FAT1 start sector */ -+ unsigned long long FAT2_start_sector; /* FAT2 start sector */ -+ unsigned long long data_start_sector; /* data area start sector */ -+ unsigned int num_FAT_sectors; /* num of FAT sectors */ -+ unsigned int root_dir; /* root dir cluster */ -+ unsigned int dentries_per_clu; /* num of dentries per cluster */ -+ unsigned int vol_flag; /* volume dirty flag */ -+ struct buffer_head *pbr_bh; /* buffer_head of PBR sector */ -+ -+ unsigned int map_clu; /* allocation bitmap start cluster */ -+ unsigned int map_sectors; /* num of allocation bitmap sectors */ -+ struct buffer_head **vol_amap; /* allocation bitmap */ -+ -+ unsigned short *vol_utbl; /* upcase table */ -+ -+ unsigned int clu_srch_ptr; /* cluster search pointer */ -+ unsigned int used_clusters; /* number of used clusters */ -+ -+ unsigned long s_state; -+ struct mutex s_lock; /* superblock lock */ -+ struct exfat_mount_options options; -+ struct nls_table *nls_io; /* Charset used for input and display */ -+ struct ratelimit_state ratelimit; -+ -+ spinlock_t inode_hash_lock; -+ struct hlist_head inode_hashtable[EXFAT_HASH_SIZE]; -+ -+ struct rcu_head rcu; -+}; -+ -+/* -+ * EXFAT file system inode in-memory data -+ */ -+struct exfat_inode_info { -+ struct exfat_chain dir; -+ int entry; -+ unsigned int type; -+ unsigned short attr; -+ unsigned int start_clu; -+ unsigned char flags; -+ /* -+ * the copy of low 32bit of i_version to check -+ * the validation of hint_stat. -+ */ -+ unsigned int version; -+ /* file offset or dentry index for readdir */ -+ loff_t rwoffset; -+ -+ /* hint for cluster last accessed */ -+ struct exfat_hint hint_bmap; -+ /* hint for entry index we try to lookup next time */ -+ struct exfat_hint hint_stat; -+ /* hint for first empty entry */ -+ struct exfat_hint_femp hint_femp; -+ -+ spinlock_t cache_lru_lock; -+ struct list_head cache_lru; -+ int nr_caches; -+ /* for avoiding the race between alloc and free */ -+ unsigned int cache_valid_id; -+ -+ /* -+ * NOTE: i_size_ondisk is 64bits, so must hold ->inode_lock to access. -+ * physically allocated size. -+ */ -+ loff_t i_size_ondisk; -+ /* block-aligned i_size (used in cont_write_begin) */ -+ loff_t i_size_aligned; -+ /* on-disk position of directory entry or 0 */ -+ loff_t i_pos; -+ /* hash by i_location */ -+ struct hlist_node i_hash_fat; -+ /* protect bmap against truncate */ -+ struct rw_semaphore truncate_lock; -+ struct inode vfs_inode; -+ /* File creation time */ -+ struct timespec64 i_crtime; -+}; -+ -+static inline struct exfat_sb_info *EXFAT_SB(struct super_block *sb) -+{ -+ return sb->s_fs_info; -+} -+ -+static inline struct exfat_inode_info *EXFAT_I(struct inode *inode) -+{ -+ return container_of(inode, struct exfat_inode_info, vfs_inode); -+} -+ -+/* -+ * If ->i_mode can't hold 0222 (i.e. ATTR_RO), we use ->i_attrs to -+ * save ATTR_RO instead of ->i_mode. -+ * -+ * If it's directory and !sbi->options.rodir, ATTR_RO isn't read-only -+ * bit, it's just used as flag for app. -+ */ -+static inline int exfat_mode_can_hold_ro(struct inode *inode) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); -+ -+ if (S_ISDIR(inode->i_mode)) -+ return 0; -+ -+ if ((~sbi->options.fs_fmask) & 0222) -+ return 1; -+ return 0; -+} -+ -+/* Convert attribute bits and a mask to the UNIX mode. */ -+static inline mode_t exfat_make_mode(struct exfat_sb_info *sbi, -+ unsigned short attr, mode_t mode) -+{ -+ if ((attr & ATTR_READONLY) && !(attr & ATTR_SUBDIR)) -+ mode &= ~0222; -+ -+ if (attr & ATTR_SUBDIR) -+ return (mode & ~sbi->options.fs_dmask) | S_IFDIR; -+ -+ return (mode & ~sbi->options.fs_fmask) | S_IFREG; -+} -+ -+/* Return the FAT attribute byte for this inode */ -+static inline unsigned short exfat_make_attr(struct inode *inode) -+{ -+ unsigned short attr = EXFAT_I(inode)->attr; -+ -+ if (S_ISDIR(inode->i_mode)) -+ attr |= ATTR_SUBDIR; -+ if (exfat_mode_can_hold_ro(inode) && !(inode->i_mode & 0222)) -+ attr |= ATTR_READONLY; -+ return attr; -+} -+ -+static inline void exfat_save_attr(struct inode *inode, unsigned short attr) -+{ -+ if (exfat_mode_can_hold_ro(inode)) -+ EXFAT_I(inode)->attr = attr & (ATTR_RWMASK | ATTR_READONLY); -+ else -+ EXFAT_I(inode)->attr = attr & ATTR_RWMASK; -+} -+ -+static inline bool exfat_is_last_sector_in_cluster(struct exfat_sb_info *sbi, -+ sector_t sec) -+{ -+ return ((sec - sbi->data_start_sector + 1) & -+ ((1 << sbi->sect_per_clus_bits) - 1)) == 0; -+} -+ -+static inline sector_t exfat_cluster_to_sector(struct exfat_sb_info *sbi, -+ unsigned int clus) -+{ -+ return ((clus - EXFAT_RESERVED_CLUSTERS) << sbi->sect_per_clus_bits) + -+ sbi->data_start_sector; -+} -+ -+static inline int exfat_sector_to_cluster(struct exfat_sb_info *sbi, -+ sector_t sec) -+{ -+ return ((sec - sbi->data_start_sector) >> sbi->sect_per_clus_bits) + -+ EXFAT_RESERVED_CLUSTERS; -+} -+ -+/* super.c */ -+int exfat_set_vol_flags(struct super_block *sb, unsigned short new_flag); -+ -+/* fatent.c */ -+#define exfat_get_next_cluster(sb, pclu) exfat_ent_get(sb, *(pclu), pclu) -+ -+int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc, -+ struct exfat_chain *p_chain); -+int exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain); -+int exfat_ent_get(struct super_block *sb, unsigned int loc, -+ unsigned int *content); -+int exfat_ent_set(struct super_block *sb, unsigned int loc, -+ unsigned int content); -+int exfat_count_ext_entries(struct super_block *sb, struct exfat_chain *p_dir, -+ int entry, struct exfat_dentry *p_entry); -+int exfat_chain_cont_cluster(struct super_block *sb, unsigned int chain, -+ unsigned int len); -+int exfat_zeroed_cluster(struct inode *dir, unsigned int clu); -+int exfat_find_last_cluster(struct super_block *sb, struct exfat_chain *p_chain, -+ unsigned int *ret_clu); -+int exfat_count_num_clusters(struct super_block *sb, -+ struct exfat_chain *p_chain, unsigned int *ret_count); -+ -+/* balloc.c */ -+int exfat_load_bitmap(struct super_block *sb); -+void exfat_free_bitmap(struct exfat_sb_info *sbi); -+int exfat_set_bitmap(struct inode *inode, unsigned int clu); -+void exfat_clear_bitmap(struct inode *inode, unsigned int clu); -+unsigned int exfat_find_free_bitmap(struct super_block *sb, unsigned int clu); -+int exfat_count_used_clusters(struct super_block *sb, unsigned int *ret_count); -+ -+/* file.c */ -+extern const struct file_operations exfat_file_operations; -+int __exfat_truncate(struct inode *inode, loff_t new_size); -+void exfat_truncate(struct inode *inode, loff_t size); -+int exfat_setattr(struct dentry *dentry, struct iattr *attr); -+int exfat_getattr(const struct path *path, struct kstat *stat, -+ unsigned int request_mask, unsigned int query_flags); -+ -+/* namei.c */ -+extern const struct dentry_operations exfat_dentry_ops; -+extern const struct dentry_operations exfat_utf8_dentry_ops; -+ -+/* cache.c */ -+int exfat_cache_init(void); -+void exfat_cache_shutdown(void); -+void exfat_cache_init_inode(struct inode *inode); -+void exfat_cache_inval_inode(struct inode *inode); -+int exfat_get_cluster(struct inode *inode, unsigned int cluster, -+ unsigned int *fclus, unsigned int *dclus, -+ unsigned int *last_dclus, int allow_eof); -+ -+/* dir.c */ -+extern const struct inode_operations exfat_dir_inode_operations; -+extern const struct file_operations exfat_dir_operations; -+unsigned int exfat_get_entry_type(struct exfat_dentry *p_entry); -+int exfat_init_dir_entry(struct inode *inode, struct exfat_chain *p_dir, -+ int entry, unsigned int type, unsigned int start_clu, -+ unsigned long long size); -+int exfat_init_ext_entry(struct inode *inode, struct exfat_chain *p_dir, -+ int entry, int num_entries, struct exfat_uni_name *p_uniname); -+int exfat_remove_entries(struct inode *inode, struct exfat_chain *p_dir, -+ int entry, int order, int num_entries); -+int exfat_update_dir_chksum(struct inode *inode, struct exfat_chain *p_dir, -+ int entry); -+int exfat_update_dir_chksum_with_entry_set(struct super_block *sb, -+ struct exfat_entry_set_cache *es, int sync); -+int exfat_calc_num_entries(struct exfat_uni_name *p_uniname); -+int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei, -+ struct exfat_chain *p_dir, struct exfat_uni_name *p_uniname, -+ int num_entries, unsigned int type); -+int exfat_alloc_new_dir(struct inode *inode, struct exfat_chain *clu); -+int exfat_find_location(struct super_block *sb, struct exfat_chain *p_dir, -+ int entry, sector_t *sector, int *offset); -+struct exfat_dentry *exfat_get_dentry(struct super_block *sb, -+ struct exfat_chain *p_dir, int entry, struct buffer_head **bh, -+ sector_t *sector); -+struct exfat_entry_set_cache *exfat_get_dentry_set(struct super_block *sb, -+ struct exfat_chain *p_dir, int entry, unsigned int type, -+ struct exfat_dentry **file_ep); -+int exfat_count_dir_entries(struct super_block *sb, struct exfat_chain *p_dir); -+ -+/* inode.c */ -+extern const struct inode_operations exfat_file_inode_operations; -+void exfat_sync_inode(struct inode *inode); -+struct inode *exfat_build_inode(struct super_block *sb, -+ struct exfat_dir_entry *info, loff_t i_pos); -+void exfat_hash_inode(struct inode *inode, loff_t i_pos); -+void exfat_unhash_inode(struct inode *inode); -+struct inode *exfat_iget(struct super_block *sb, loff_t i_pos); -+int exfat_write_inode(struct inode *inode, struct writeback_control *wbc); -+void exfat_evict_inode(struct inode *inode); -+int exfat_block_truncate_page(struct inode *inode, loff_t from); -+ -+/* exfat/nls.c */ -+unsigned short exfat_toupper(struct super_block *sb, unsigned short a); -+int exfat_uniname_ncmp(struct super_block *sb, unsigned short *a, -+ unsigned short *b, unsigned int len); -+int exfat_utf16_to_nls(struct super_block *sb, -+ struct exfat_uni_name *uniname, unsigned char *p_cstring, -+ int len); -+int exfat_nls_to_utf16(struct super_block *sb, -+ const unsigned char *p_cstring, const int len, -+ struct exfat_uni_name *uniname, int *p_lossy); -+int exfat_create_upcase_table(struct super_block *sb); -+void exfat_free_upcase_table(struct exfat_sb_info *sbi); -+unsigned short exfat_high_surrogate(unicode_t u); -+unsigned short exfat_low_surrogate(unicode_t u); -+ -+/* exfat/misc.c */ -+void __exfat_fs_error(struct super_block *sb, int report, const char *fmt, ...) -+ __printf(3, 4) __cold; -+#define exfat_fs_error(sb, fmt, args...) \ -+ __exfat_fs_error(sb, 1, fmt, ## args) -+#define exfat_fs_error_ratelimit(sb, fmt, args...) \ -+ __exfat_fs_error(sb, __ratelimit(&EXFAT_SB(sb)->ratelimit), \ -+ fmt, ## args) -+void exfat_msg(struct super_block *sb, const char *lv, const char *fmt, ...) -+ __printf(3, 4) __cold; -+void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, -+ u8 tz, __le16 time, __le16 date, u8 time_ms); -+void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, -+ u8 *tz, __le16 *time, __le16 *date, u8 *time_ms); -+unsigned short exfat_calc_chksum_2byte(void *data, int len, -+ unsigned short chksum, int type); -+void exfat_update_bh(struct super_block *sb, struct buffer_head *bh, int sync); -+void exfat_chain_set(struct exfat_chain *ec, unsigned int dir, -+ unsigned int size, unsigned char flags); -+void exfat_chain_dup(struct exfat_chain *dup, struct exfat_chain *ec); -+ -+#endif /* !_EXFAT_FS_H */ -diff --git a/fs/exfat/exfat_raw.h b/fs/exfat/exfat_raw.h -new file mode 100644 -index 000000000000..2a841010e649 ---- /dev/null -+++ b/fs/exfat/exfat_raw.h -@@ -0,0 +1,184 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -+ */ -+ -+#ifndef _EXFAT_RAW_H -+#define _EXFAT_RAW_H -+ -+#include -+ -+#define PBR_SIGNATURE 0xAA55 -+ -+#define EXFAT_MAX_FILE_LEN 255 -+ -+#define VOL_CLEAN 0x0000 -+#define VOL_DIRTY 0x0002 -+ -+#define EXFAT_EOF_CLUSTER 0xFFFFFFFFu -+#define EXFAT_BAD_CLUSTER 0xFFFFFFF7u -+#define EXFAT_FREE_CLUSTER 0 -+/* Cluster 0, 1 are reserved, the first cluster is 2 in the cluster heap. */ -+#define EXFAT_RESERVED_CLUSTERS 2 -+#define EXFAT_FIRST_CLUSTER 2 -+#define EXFAT_DATA_CLUSTER_COUNT(sbi) \ -+ ((sbi)->num_clusters - EXFAT_RESERVED_CLUSTERS) -+ -+/* AllocationPossible and NoFatChain field in GeneralSecondaryFlags Field */ -+#define ALLOC_FAT_CHAIN 0x01 -+#define ALLOC_NO_FAT_CHAIN 0x03 -+ -+#define DENTRY_SIZE 32 /* directory entry size */ -+#define DENTRY_SIZE_BITS 5 -+/* exFAT allows 8388608(256MB) directory entries */ -+#define MAX_EXFAT_DENTRIES 8388608 -+ -+/* dentry types */ -+#define EXFAT_UNUSED 0x00 /* end of directory */ -+#define EXFAT_DELETE (~0x80) -+#define IS_EXFAT_DELETED(x) ((x) < 0x80) /* deleted file (0x01~0x7F) */ -+#define EXFAT_INVAL 0x80 /* invalid value */ -+#define EXFAT_BITMAP 0x81 /* allocation bitmap */ -+#define EXFAT_UPCASE 0x82 /* upcase table */ -+#define EXFAT_VOLUME 0x83 /* volume label */ -+#define EXFAT_FILE 0x85 /* file or dir */ -+#define EXFAT_GUID 0xA0 -+#define EXFAT_PADDING 0xA1 -+#define EXFAT_ACLTAB 0xA2 -+#define EXFAT_STREAM 0xC0 /* stream entry */ -+#define EXFAT_NAME 0xC1 /* file name entry */ -+#define EXFAT_ACL 0xC2 /* stream entry */ -+ -+#define IS_EXFAT_CRITICAL_PRI(x) (x < 0xA0) -+#define IS_EXFAT_BENIGN_PRI(x) (x < 0xC0) -+#define IS_EXFAT_CRITICAL_SEC(x) (x < 0xE0) -+ -+/* checksum types */ -+#define CS_DIR_ENTRY 0 -+#define CS_PBR_SECTOR 1 -+#define CS_DEFAULT 2 -+ -+/* file attributes */ -+#define ATTR_READONLY 0x0001 -+#define ATTR_HIDDEN 0x0002 -+#define ATTR_SYSTEM 0x0004 -+#define ATTR_VOLUME 0x0008 -+#define ATTR_SUBDIR 0x0010 -+#define ATTR_ARCHIVE 0x0020 -+ -+#define ATTR_RWMASK (ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME | \ -+ ATTR_SUBDIR | ATTR_ARCHIVE) -+ -+#define PBR64_JUMP_BOOT_LEN 3 -+#define PBR64_OEM_NAME_LEN 8 -+#define PBR64_RESERVED_LEN 53 -+ -+#define EXFAT_FILE_NAME_LEN 15 -+ -+/* EXFAT BIOS parameter block (64 bytes) */ -+struct bpb64 { -+ __u8 jmp_boot[PBR64_JUMP_BOOT_LEN]; -+ __u8 oem_name[PBR64_OEM_NAME_LEN]; -+ __u8 res_zero[PBR64_RESERVED_LEN]; -+} __packed; -+ -+/* EXFAT EXTEND BIOS parameter block (56 bytes) */ -+struct bsx64 { -+ __le64 vol_offset; -+ __le64 vol_length; -+ __le32 fat_offset; -+ __le32 fat_length; -+ __le32 clu_offset; -+ __le32 clu_count; -+ __le32 root_cluster; -+ __le32 vol_serial; -+ __u8 fs_version[2]; -+ __le16 vol_flags; -+ __u8 sect_size_bits; -+ __u8 sect_per_clus_bits; -+ __u8 num_fats; -+ __u8 phy_drv_no; -+ __u8 perc_in_use; -+ __u8 reserved2[7]; -+} __packed; -+ -+/* EXFAT PBR[BPB+BSX] (120 bytes) */ -+struct pbr64 { -+ struct bpb64 bpb; -+ struct bsx64 bsx; -+} __packed; -+ -+/* Common PBR[Partition Boot Record] (512 bytes) */ -+struct pbr { -+ union { -+ __u8 raw[64]; -+ struct bpb64 f64; -+ } bpb; -+ union { -+ __u8 raw[56]; -+ struct bsx64 f64; -+ } bsx; -+ __u8 boot_code[390]; -+ __le16 signature; -+} __packed; -+ -+struct exfat_dentry { -+ __u8 type; -+ union { -+ struct { -+ __u8 num_ext; -+ __le16 checksum; -+ __le16 attr; -+ __le16 reserved1; -+ __le16 create_time; -+ __le16 create_date; -+ __le16 modify_time; -+ __le16 modify_date; -+ __le16 access_time; -+ __le16 access_date; -+ __u8 create_time_ms; -+ __u8 modify_time_ms; -+ __u8 create_tz; -+ __u8 modify_tz; -+ __u8 access_tz; -+ __u8 reserved2[7]; -+ } __packed file; /* file directory entry */ -+ struct { -+ __u8 flags; -+ __u8 reserved1; -+ __u8 name_len; -+ __le16 name_hash; -+ __le16 reserved2; -+ __le64 valid_size; -+ __le32 reserved3; -+ __le32 start_clu; -+ __le64 size; -+ } __packed stream; /* stream extension directory entry */ -+ struct { -+ __u8 flags; -+ __le16 unicode_0_14[EXFAT_FILE_NAME_LEN]; -+ } __packed name; /* file name directory entry */ -+ struct { -+ __u8 flags; -+ __u8 reserved[18]; -+ __le32 start_clu; -+ __le64 size; -+ } __packed bitmap; /* allocation bitmap directory entry */ -+ struct { -+ __u8 reserved1[3]; -+ __le32 checksum; -+ __u8 reserved2[12]; -+ __le32 start_clu; -+ __le64 size; -+ } __packed upcase; /* up-case table directory entry */ -+ } __packed dentry; -+} __packed; -+ -+#define EXFAT_TZ_VALID (1 << 7) -+ -+/* Jan 1 GMT 00:00:00 1980 */ -+#define EXFAT_MIN_TIMESTAMP_SECS 315532800LL -+/* Dec 31 GMT 23:59:59 2107 */ -+#define EXFAT_MAX_TIMESTAMP_SECS 4354819199LL -+ -+#endif /* !_EXFAT_RAW_H */ --- -2.25.1 - diff --git a/kernel/tools/perf/files/patches/mageia/fs-exfat-add-inode-operations.patch b/kernel/tools/perf/files/patches/mageia/fs-exfat-add-inode-operations.patch deleted file mode 100644 index 0b47e8a9b6..0000000000 --- a/kernel/tools/perf/files/patches/mageia/fs-exfat-add-inode-operations.patch +++ /dev/null @@ -1,2156 +0,0 @@ -From 5f2aa075070cf5b2e6aae011d5a3390408d7d913 Mon Sep 17 00:00:00 2001 -From: Namjae Jeon -Date: Mon, 2 Mar 2020 15:21:34 +0900 -Subject: [PATCH 03/14] exfat: add inode operations -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This adds the implementation of inode operations for exfat. - -Signed-off-by: Namjae Jeon -Signed-off-by: Sungjong Seo -Reviewed-by: Pali Rohár -Reviewed-by: Christoph Hellwig -Signed-off-by: Al Viro ---- - fs/exfat/inode.c | 671 +++++++++++++++++++++ - fs/exfat/namei.c | 1448 ++++++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 2119 insertions(+) - create mode 100644 fs/exfat/inode.c - create mode 100644 fs/exfat/namei.c - -diff --git a/fs/exfat/inode.c b/fs/exfat/inode.c -new file mode 100644 -index 000000000000..06887492f54b ---- /dev/null -+++ b/fs/exfat/inode.c -@@ -0,0 +1,671 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "exfat_raw.h" -+#include "exfat_fs.h" -+ -+static int __exfat_write_inode(struct inode *inode, int sync) -+{ -+ int ret = -EIO; -+ unsigned long long on_disk_size; -+ struct exfat_dentry *ep, *ep2; -+ struct exfat_entry_set_cache *es = NULL; -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ bool is_dir = (ei->type == TYPE_DIR) ? true : false; -+ -+ if (inode->i_ino == EXFAT_ROOT_INO) -+ return 0; -+ -+ /* -+ * If the indode is already unlinked, there is no need for updating it. -+ */ -+ if (ei->dir.dir == DIR_DELETED) -+ return 0; -+ -+ if (is_dir && ei->dir.dir == sbi->root_dir && ei->entry == -1) -+ return 0; -+ -+ exfat_set_vol_flags(sb, VOL_DIRTY); -+ -+ /* get the directory entry of given file or directory */ -+ es = exfat_get_dentry_set(sb, &(ei->dir), ei->entry, ES_ALL_ENTRIES, -+ &ep); -+ if (!es) -+ return -EIO; -+ ep2 = ep + 1; -+ -+ ep->dentry.file.attr = cpu_to_le16(exfat_make_attr(inode)); -+ -+ /* set FILE_INFO structure using the acquired struct exfat_dentry */ -+ exfat_set_entry_time(sbi, &ei->i_crtime, -+ &ep->dentry.file.create_tz, -+ &ep->dentry.file.create_time, -+ &ep->dentry.file.create_date, -+ &ep->dentry.file.create_time_ms); -+ exfat_set_entry_time(sbi, &inode->i_mtime, -+ &ep->dentry.file.modify_tz, -+ &ep->dentry.file.modify_time, -+ &ep->dentry.file.modify_date, -+ &ep->dentry.file.modify_time_ms); -+ exfat_set_entry_time(sbi, &inode->i_atime, -+ &ep->dentry.file.access_tz, -+ &ep->dentry.file.access_time, -+ &ep->dentry.file.access_date, -+ NULL); -+ -+ /* File size should be zero if there is no cluster allocated */ -+ on_disk_size = i_size_read(inode); -+ -+ if (ei->start_clu == EXFAT_EOF_CLUSTER) -+ on_disk_size = 0; -+ -+ ep2->dentry.stream.valid_size = cpu_to_le64(on_disk_size); -+ ep2->dentry.stream.size = ep2->dentry.stream.valid_size; -+ -+ ret = exfat_update_dir_chksum_with_entry_set(sb, es, sync); -+ kfree(es); -+ return ret; -+} -+ -+int exfat_write_inode(struct inode *inode, struct writeback_control *wbc) -+{ -+ int ret; -+ -+ mutex_lock(&EXFAT_SB(inode->i_sb)->s_lock); -+ ret = __exfat_write_inode(inode, wbc->sync_mode == WB_SYNC_ALL); -+ mutex_unlock(&EXFAT_SB(inode->i_sb)->s_lock); -+ -+ return ret; -+} -+ -+void exfat_sync_inode(struct inode *inode) -+{ -+ lockdep_assert_held(&EXFAT_SB(inode->i_sb)->s_lock); -+ __exfat_write_inode(inode, 1); -+} -+ -+/* -+ * Input: inode, (logical) clu_offset, target allocation area -+ * Output: errcode, cluster number -+ * *clu = (~0), if it's unable to allocate a new cluster -+ */ -+static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset, -+ unsigned int *clu, int create) -+{ -+ int ret, modified = false; -+ unsigned int last_clu; -+ struct exfat_chain new_clu; -+ struct exfat_dentry *ep; -+ struct exfat_entry_set_cache *es = NULL; -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ unsigned int local_clu_offset = clu_offset; -+ unsigned int num_to_be_allocated = 0, num_clusters = 0; -+ -+ ei->rwoffset = EXFAT_CLU_TO_B(clu_offset, sbi); -+ -+ if (EXFAT_I(inode)->i_size_ondisk > 0) -+ num_clusters = -+ EXFAT_B_TO_CLU_ROUND_UP(EXFAT_I(inode)->i_size_ondisk, -+ sbi); -+ -+ if (clu_offset >= num_clusters) -+ num_to_be_allocated = clu_offset - num_clusters + 1; -+ -+ if (!create && (num_to_be_allocated > 0)) { -+ *clu = EXFAT_EOF_CLUSTER; -+ return 0; -+ } -+ -+ *clu = last_clu = ei->start_clu; -+ -+ if (ei->flags == ALLOC_NO_FAT_CHAIN) { -+ if (clu_offset > 0 && *clu != EXFAT_EOF_CLUSTER) { -+ last_clu += clu_offset - 1; -+ -+ if (clu_offset == num_clusters) -+ *clu = EXFAT_EOF_CLUSTER; -+ else -+ *clu += clu_offset; -+ } -+ } else if (ei->type == TYPE_FILE) { -+ unsigned int fclus = 0; -+ int err = exfat_get_cluster(inode, clu_offset, -+ &fclus, clu, &last_clu, 1); -+ if (err) -+ return -EIO; -+ -+ clu_offset -= fclus; -+ } else { -+ /* hint information */ -+ if (clu_offset > 0 && ei->hint_bmap.off != EXFAT_EOF_CLUSTER && -+ ei->hint_bmap.off > 0 && clu_offset >= ei->hint_bmap.off) { -+ clu_offset -= ei->hint_bmap.off; -+ /* hint_bmap.clu should be valid */ -+ WARN_ON(ei->hint_bmap.clu < 2); -+ *clu = ei->hint_bmap.clu; -+ } -+ -+ while (clu_offset > 0 && *clu != EXFAT_EOF_CLUSTER) { -+ last_clu = *clu; -+ if (exfat_get_next_cluster(sb, clu)) -+ return -EIO; -+ clu_offset--; -+ } -+ } -+ -+ if (*clu == EXFAT_EOF_CLUSTER) { -+ exfat_set_vol_flags(sb, VOL_DIRTY); -+ -+ new_clu.dir = (last_clu == EXFAT_EOF_CLUSTER) ? -+ EXFAT_EOF_CLUSTER : last_clu + 1; -+ new_clu.size = 0; -+ new_clu.flags = ei->flags; -+ -+ /* allocate a cluster */ -+ if (num_to_be_allocated < 1) { -+ /* Broken FAT (i_sze > allocated FAT) */ -+ exfat_fs_error(sb, "broken FAT chain."); -+ return -EIO; -+ } -+ -+ ret = exfat_alloc_cluster(inode, num_to_be_allocated, &new_clu); -+ if (ret) -+ return ret; -+ -+ if (new_clu.dir == EXFAT_EOF_CLUSTER || -+ new_clu.dir == EXFAT_FREE_CLUSTER) { -+ exfat_fs_error(sb, -+ "bogus cluster new allocated (last_clu : %u, new_clu : %u)", -+ last_clu, new_clu.dir); -+ return -EIO; -+ } -+ -+ /* append to the FAT chain */ -+ if (last_clu == EXFAT_EOF_CLUSTER) { -+ if (new_clu.flags == ALLOC_FAT_CHAIN) -+ ei->flags = ALLOC_FAT_CHAIN; -+ ei->start_clu = new_clu.dir; -+ modified = true; -+ } else { -+ if (new_clu.flags != ei->flags) { -+ /* no-fat-chain bit is disabled, -+ * so fat-chain should be synced with -+ * alloc-bitmap -+ */ -+ exfat_chain_cont_cluster(sb, ei->start_clu, -+ num_clusters); -+ ei->flags = ALLOC_FAT_CHAIN; -+ modified = true; -+ } -+ if (new_clu.flags == ALLOC_FAT_CHAIN) -+ if (exfat_ent_set(sb, last_clu, new_clu.dir)) -+ return -EIO; -+ } -+ -+ num_clusters += num_to_be_allocated; -+ *clu = new_clu.dir; -+ -+ if (ei->dir.dir != DIR_DELETED) { -+ es = exfat_get_dentry_set(sb, &(ei->dir), ei->entry, -+ ES_ALL_ENTRIES, &ep); -+ if (!es) -+ return -EIO; -+ /* get stream entry */ -+ ep++; -+ -+ /* update directory entry */ -+ if (modified) { -+ if (ep->dentry.stream.flags != ei->flags) -+ ep->dentry.stream.flags = ei->flags; -+ -+ if (le32_to_cpu(ep->dentry.stream.start_clu) != -+ ei->start_clu) -+ ep->dentry.stream.start_clu = -+ cpu_to_le32(ei->start_clu); -+ -+ ep->dentry.stream.valid_size = -+ cpu_to_le64(i_size_read(inode)); -+ ep->dentry.stream.size = -+ ep->dentry.stream.valid_size; -+ } -+ -+ if (exfat_update_dir_chksum_with_entry_set(sb, es, -+ inode_needs_sync(inode))) -+ return -EIO; -+ kfree(es); -+ -+ } /* end of if != DIR_DELETED */ -+ -+ inode->i_blocks += -+ num_to_be_allocated << sbi->sect_per_clus_bits; -+ -+ /* -+ * Move *clu pointer along FAT chains (hole care) because the -+ * caller of this function expect *clu to be the last cluster. -+ * This only works when num_to_be_allocated >= 2, -+ * *clu = (the first cluster of the allocated chain) => -+ * (the last cluster of ...) -+ */ -+ if (ei->flags == ALLOC_NO_FAT_CHAIN) { -+ *clu += num_to_be_allocated - 1; -+ } else { -+ while (num_to_be_allocated > 1) { -+ if (exfat_get_next_cluster(sb, clu)) -+ return -EIO; -+ num_to_be_allocated--; -+ } -+ } -+ -+ } -+ -+ /* hint information */ -+ ei->hint_bmap.off = local_clu_offset; -+ ei->hint_bmap.clu = *clu; -+ -+ return 0; -+} -+ -+static int exfat_map_new_buffer(struct exfat_inode_info *ei, -+ struct buffer_head *bh, loff_t pos) -+{ -+ if (buffer_delay(bh) && pos > ei->i_size_aligned) -+ return -EIO; -+ set_buffer_new(bh); -+ -+ /* -+ * Adjust i_size_aligned if i_size_ondisk is bigger than it. -+ */ -+ if (ei->i_size_ondisk > ei->i_size_aligned) -+ ei->i_size_aligned = ei->i_size_ondisk; -+ return 0; -+} -+ -+static int exfat_get_block(struct inode *inode, sector_t iblock, -+ struct buffer_head *bh_result, int create) -+{ -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits; -+ int err = 0; -+ unsigned long mapped_blocks = 0; -+ unsigned int cluster, sec_offset; -+ sector_t last_block; -+ sector_t phys = 0; -+ loff_t pos; -+ -+ mutex_lock(&sbi->s_lock); -+ last_block = EXFAT_B_TO_BLK_ROUND_UP(i_size_read(inode), sb); -+ if (iblock >= last_block && !create) -+ goto done; -+ -+ /* Is this block already allocated? */ -+ err = exfat_map_cluster(inode, iblock >> sbi->sect_per_clus_bits, -+ &cluster, create); -+ if (err) { -+ if (err != -ENOSPC) -+ exfat_fs_error_ratelimit(sb, -+ "failed to bmap (inode : %p iblock : %llu, err : %d)", -+ inode, (unsigned long long)iblock, err); -+ goto unlock_ret; -+ } -+ -+ if (cluster == EXFAT_EOF_CLUSTER) -+ goto done; -+ -+ /* sector offset in cluster */ -+ sec_offset = iblock & (sbi->sect_per_clus - 1); -+ -+ phys = exfat_cluster_to_sector(sbi, cluster) + sec_offset; -+ mapped_blocks = sbi->sect_per_clus - sec_offset; -+ max_blocks = min(mapped_blocks, max_blocks); -+ -+ /* Treat newly added block / cluster */ -+ if (iblock < last_block) -+ create = 0; -+ -+ if (create || buffer_delay(bh_result)) { -+ pos = EXFAT_BLK_TO_B((iblock + 1), sb); -+ if (ei->i_size_ondisk < pos) -+ ei->i_size_ondisk = pos; -+ } -+ -+ if (create) { -+ err = exfat_map_new_buffer(ei, bh_result, pos); -+ if (err) { -+ exfat_fs_error(sb, -+ "requested for bmap out of range(pos : (%llu) > i_size_aligned(%llu)\n", -+ pos, ei->i_size_aligned); -+ goto unlock_ret; -+ } -+ } -+ -+ if (buffer_delay(bh_result)) -+ clear_buffer_delay(bh_result); -+ map_bh(bh_result, sb, phys); -+done: -+ bh_result->b_size = EXFAT_BLK_TO_B(max_blocks, sb); -+unlock_ret: -+ mutex_unlock(&sbi->s_lock); -+ return err; -+} -+ -+static int exfat_readpage(struct file *file, struct page *page) -+{ -+ return mpage_readpage(page, exfat_get_block); -+} -+ -+static int exfat_readpages(struct file *file, struct address_space *mapping, -+ struct list_head *pages, unsigned int nr_pages) -+{ -+ return mpage_readpages(mapping, pages, nr_pages, exfat_get_block); -+} -+ -+static int exfat_writepage(struct page *page, struct writeback_control *wbc) -+{ -+ return block_write_full_page(page, exfat_get_block, wbc); -+} -+ -+static int exfat_writepages(struct address_space *mapping, -+ struct writeback_control *wbc) -+{ -+ return mpage_writepages(mapping, wbc, exfat_get_block); -+} -+ -+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, i_size_read(inode)); -+ exfat_truncate(inode, EXFAT_I(inode)->i_size_aligned); -+ } -+} -+ -+static int exfat_write_begin(struct file *file, struct address_space *mapping, -+ loff_t pos, unsigned int len, unsigned int 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)->i_size_ondisk); -+ -+ if (ret < 0) -+ exfat_write_failed(mapping, pos+len); -+ -+ return ret; -+} -+ -+static int exfat_write_end(struct file *file, struct address_space *mapping, -+ loff_t pos, unsigned int len, unsigned int copied, -+ struct page *pagep, void *fsdata) -+{ -+ struct inode *inode = mapping->host; -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ int err; -+ -+ err = generic_write_end(file, mapping, pos, len, copied, pagep, fsdata); -+ -+ if (EXFAT_I(inode)->i_size_aligned < i_size_read(inode)) { -+ exfat_fs_error(inode->i_sb, -+ "invalid size(size(%llu) > aligned(%llu)\n", -+ i_size_read(inode), EXFAT_I(inode)->i_size_aligned); -+ return -EIO; -+ } -+ -+ if (err < len) -+ exfat_write_failed(mapping, pos+len); -+ -+ if (!(err < 0) && !(ei->attr & ATTR_ARCHIVE)) { -+ inode->i_mtime = inode->i_ctime = current_time(inode); -+ ei->attr |= ATTR_ARCHIVE; -+ mark_inode_dirty(inode); -+ } -+ -+ return err; -+} -+ -+static ssize_t exfat_direct_IO(struct kiocb *iocb, struct iov_iter *iter) -+{ -+ struct address_space *mapping = iocb->ki_filp->f_mapping; -+ struct inode *inode = mapping->host; -+ loff_t size = iocb->ki_pos + iov_iter_count(iter); -+ int rw = iov_iter_rw(iter); -+ ssize_t ret; -+ -+ if (rw == WRITE) { -+ /* -+ * FIXME: blockdev_direct_IO() doesn't use ->write_begin(), -+ * so we need to update the ->i_size_aligned to block boundary. -+ * -+ * But we must fill the remaining area or hole by nul for -+ * updating ->i_size_aligned -+ * -+ * Return 0, and fallback to normal buffered write. -+ */ -+ if (EXFAT_I(inode)->i_size_aligned < size) -+ return 0; -+ } -+ -+ /* -+ * Need to use the DIO_LOCKING for avoiding the race -+ * condition of exfat_get_block() and ->truncate(). -+ */ -+ ret = blockdev_direct_IO(iocb, inode, iter, exfat_get_block); -+ if (ret < 0 && (rw & WRITE)) -+ exfat_write_failed(mapping, size); -+ return ret; -+} -+ -+static sector_t exfat_aop_bmap(struct address_space *mapping, sector_t block) -+{ -+ sector_t blocknr; -+ -+ /* exfat_get_cluster() assumes the requested blocknr isn't truncated. */ -+ 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); -+ return blocknr; -+} -+ -+/* -+ * exfat_block_truncate_page() zeroes out a mapping from file offset `from' -+ * up to the end of the block which corresponds to `from'. -+ * This is required during truncate to physically zeroout the tail end -+ * of that block so it doesn't yield old data if the file is later grown. -+ * Also, avoid causing failure from fsx for cases of "data past EOF" -+ */ -+int exfat_block_truncate_page(struct inode *inode, loff_t from) -+{ -+ return block_truncate_page(inode->i_mapping, from, exfat_get_block); -+} -+ -+static const struct address_space_operations exfat_aops = { -+ .readpage = exfat_readpage, -+ .readpages = exfat_readpages, -+ .writepage = exfat_writepage, -+ .writepages = exfat_writepages, -+ .write_begin = exfat_write_begin, -+ .write_end = exfat_write_end, -+ .direct_IO = exfat_direct_IO, -+ .bmap = exfat_aop_bmap -+}; -+ -+static inline unsigned long exfat_hash(loff_t i_pos) -+{ -+ return hash_32(i_pos, EXFAT_HASH_BITS); -+} -+ -+void exfat_hash_inode(struct inode *inode, loff_t 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_hash_fat, head); -+ spin_unlock(&sbi->inode_hash_lock); -+} -+ -+void exfat_unhash_inode(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; -+ spin_unlock(&sbi->inode_hash_lock); -+} -+ -+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 inode *inode = NULL; -+ -+ spin_lock(&sbi->inode_hash_lock); -+ hlist_for_each_entry(info, head, i_hash_fat) { -+ WARN_ON(info->vfs_inode.i_sb != sb); -+ -+ if (i_pos != info->i_pos) -+ continue; -+ inode = igrab(&info->vfs_inode); -+ if (inode) -+ break; -+ } -+ spin_unlock(&sbi->inode_hash_lock); -+ return inode; -+} -+ -+/* doesn't deal with root inode */ -+static int exfat_fill_inode(struct inode *inode, struct exfat_dir_entry *info) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ loff_t size = info->size; -+ -+ memcpy(&ei->dir, &info->dir, sizeof(struct exfat_chain)); -+ ei->entry = info->entry; -+ ei->attr = info->attr; -+ ei->start_clu = info->start_clu; -+ ei->flags = info->flags; -+ ei->type = info->type; -+ -+ ei->version = 0; -+ ei->hint_stat.eidx = 0; -+ ei->hint_stat.clu = info->start_clu; -+ ei->hint_femp.eidx = EXFAT_HINT_NONE; -+ ei->rwoffset = 0; -+ ei->hint_bmap.off = EXFAT_EOF_CLUSTER; -+ ei->i_pos = 0; -+ -+ inode->i_uid = sbi->options.fs_uid; -+ inode->i_gid = sbi->options.fs_gid; -+ inode_inc_iversion(inode); -+ inode->i_generation = prandom_u32(); -+ -+ if (info->attr & ATTR_SUBDIR) { /* directory */ -+ inode->i_generation &= ~1; -+ inode->i_mode = exfat_make_mode(sbi, info->attr, 0777); -+ inode->i_op = &exfat_dir_inode_operations; -+ inode->i_fop = &exfat_dir_operations; -+ set_nlink(inode, info->num_subdirs); -+ } else { /* regular file */ -+ inode->i_generation |= 1; -+ inode->i_mode = exfat_make_mode(sbi, info->attr, 0777); -+ inode->i_op = &exfat_file_inode_operations; -+ inode->i_fop = &exfat_file_operations; -+ inode->i_mapping->a_ops = &exfat_aops; -+ inode->i_mapping->nrpages = 0; -+ } -+ -+ i_size_write(inode, size); -+ -+ /* ondisk and aligned size should be aligned with block size */ -+ if (size & (inode->i_sb->s_blocksize - 1)) { -+ size |= (inode->i_sb->s_blocksize - 1); -+ size++; -+ } -+ -+ ei->i_size_aligned = size; -+ ei->i_size_ondisk = size; -+ -+ exfat_save_attr(inode, info->attr); -+ -+ inode->i_blocks = ((i_size_read(inode) + (sbi->cluster_size - 1)) & -+ ~(sbi->cluster_size - 1)) >> inode->i_blkbits; -+ inode->i_mtime = info->mtime; -+ inode->i_ctime = info->mtime; -+ ei->i_crtime = info->crtime; -+ inode->i_atime = info->atime; -+ -+ exfat_cache_init_inode(inode); -+ -+ return 0; -+} -+ -+struct inode *exfat_build_inode(struct super_block *sb, -+ struct exfat_dir_entry *info, loff_t i_pos) -+{ -+ struct inode *inode; -+ int err; -+ -+ inode = exfat_iget(sb, i_pos); -+ if (inode) -+ goto out; -+ inode = new_inode(sb); -+ if (!inode) { -+ inode = ERR_PTR(-ENOMEM); -+ goto out; -+ } -+ inode->i_ino = iunique(sb, EXFAT_ROOT_INO); -+ inode_set_iversion(inode, 1); -+ err = exfat_fill_inode(inode, info); -+ if (err) { -+ iput(inode); -+ inode = ERR_PTR(err); -+ goto out; -+ } -+ exfat_hash_inode(inode, i_pos); -+ insert_inode_hash(inode); -+out: -+ return inode; -+} -+ -+void exfat_evict_inode(struct inode *inode) -+{ -+ truncate_inode_pages(&inode->i_data, 0); -+ -+ if (!inode->i_nlink) { -+ i_size_write(inode, 0); -+ mutex_lock(&EXFAT_SB(inode->i_sb)->s_lock); -+ __exfat_truncate(inode, 0); -+ mutex_unlock(&EXFAT_SB(inode->i_sb)->s_lock); -+ } -+ -+ invalidate_inode_buffers(inode); -+ clear_inode(inode); -+ exfat_cache_inval_inode(inode); -+ exfat_unhash_inode(inode); -+} -diff --git a/fs/exfat/namei.c b/fs/exfat/namei.c -new file mode 100644 -index 000000000000..a8681d91f569 ---- /dev/null -+++ b/fs/exfat/namei.c -@@ -0,0 +1,1448 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "exfat_raw.h" -+#include "exfat_fs.h" -+ -+static inline unsigned long exfat_d_version(struct dentry *dentry) -+{ -+ return (unsigned long) dentry->d_fsdata; -+} -+ -+static inline void exfat_d_version_set(struct dentry *dentry, -+ unsigned long version) -+{ -+ dentry->d_fsdata = (void *) version; -+} -+ -+/* -+ * If new entry was created in the parent, it could create the 8.3 alias (the -+ * shortname of logname). So, the parent may have the negative-dentry which -+ * matches the created 8.3 alias. -+ * -+ * If it happened, the negative dentry isn't actually negative anymore. So, -+ * drop it. -+ */ -+static int exfat_d_revalidate(struct dentry *dentry, unsigned int flags) -+{ -+ int ret; -+ -+ if (flags & LOOKUP_RCU) -+ return -ECHILD; -+ -+ /* -+ * This is not negative dentry. Always valid. -+ * -+ * Note, rename() to existing directory entry will have ->d_inode, and -+ * will use existing name which isn't specified name by user. -+ * -+ * We may be able to drop this positive dentry here. But dropping -+ * positive dentry isn't good idea. So it's unsupported like -+ * rename("filename", "FILENAME") for now. -+ */ -+ if (d_really_is_positive(dentry)) -+ return 1; -+ -+ /* -+ * Drop the negative dentry, in order to make sure to use the case -+ * sensitive name which is specified by user if this is for creation. -+ */ -+ if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) -+ return 0; -+ -+ spin_lock(&dentry->d_lock); -+ ret = inode_eq_iversion(d_inode(dentry->d_parent), -+ exfat_d_version(dentry)); -+ spin_unlock(&dentry->d_lock); -+ return ret; -+} -+ -+/* returns the length of a struct qstr, ignoring trailing dots */ -+static unsigned int exfat_striptail_len(unsigned int len, const char *name) -+{ -+ while (len && name[len - 1] == '.') -+ len--; -+ return len; -+} -+ -+/* -+ * Compute the hash for the exfat name corresponding to the dentry. If the name -+ * is invalid, we leave the hash code unchanged so that the existing dentry can -+ * be used. The exfat fs routines will return ENOENT or EINVAL as appropriate. -+ */ -+static int exfat_d_hash(const struct dentry *dentry, struct qstr *qstr) -+{ -+ struct super_block *sb = dentry->d_sb; -+ struct nls_table *t = EXFAT_SB(sb)->nls_io; -+ const unsigned char *name = qstr->name; -+ unsigned int len = exfat_striptail_len(qstr->len, qstr->name); -+ unsigned long hash = init_name_hash(dentry); -+ int i, charlen; -+ wchar_t c; -+ -+ for (i = 0; i < len; i += charlen) { -+ charlen = t->char2uni(&name[i], len - i, &c); -+ if (charlen < 0) -+ return charlen; -+ hash = partial_name_hash(exfat_toupper(sb, c), hash); -+ } -+ -+ qstr->hash = end_name_hash(hash); -+ return 0; -+} -+ -+static int exfat_d_cmp(const struct dentry *dentry, unsigned int len, -+ const char *str, const struct qstr *name) -+{ -+ struct super_block *sb = dentry->d_sb; -+ struct nls_table *t = EXFAT_SB(sb)->nls_io; -+ unsigned int alen = exfat_striptail_len(name->len, name->name); -+ unsigned int blen = exfat_striptail_len(len, str); -+ wchar_t c1, c2; -+ int charlen, i; -+ -+ if (alen != blen) -+ return 1; -+ -+ for (i = 0; i < len; i += charlen) { -+ charlen = t->char2uni(&name->name[i], alen - i, &c1); -+ if (charlen < 0) -+ return 1; -+ if (charlen != t->char2uni(&str[i], blen - i, &c2)) -+ return 1; -+ -+ if (exfat_toupper(sb, c1) != exfat_toupper(sb, c2)) -+ return 1; -+ } -+ -+ return 0; -+} -+ -+const struct dentry_operations exfat_dentry_ops = { -+ .d_revalidate = exfat_d_revalidate, -+ .d_hash = exfat_d_hash, -+ .d_compare = exfat_d_cmp, -+}; -+ -+static int exfat_utf8_d_hash(const struct dentry *dentry, struct qstr *qstr) -+{ -+ struct super_block *sb = dentry->d_sb; -+ const unsigned char *name = qstr->name; -+ unsigned int len = exfat_striptail_len(qstr->len, qstr->name); -+ unsigned long hash = init_name_hash(dentry); -+ int i, charlen; -+ unicode_t u; -+ -+ for (i = 0; i < len; i += charlen) { -+ charlen = utf8_to_utf32(&name[i], len - i, &u); -+ if (charlen < 0) -+ return charlen; -+ -+ /* -+ * Convert to UTF-16: code points above U+FFFF are encoded as -+ * surrogate pairs. -+ * exfat_toupper() works only for code points up to the U+FFFF. -+ */ -+ if (u > 0xFFFF) { -+ hash = partial_name_hash(exfat_high_surrogate(u), hash); -+ hash = partial_name_hash(exfat_low_surrogate(u), hash); -+ } else { -+ hash = partial_name_hash(exfat_toupper(sb, u), hash); -+ } -+ } -+ -+ qstr->hash = end_name_hash(hash); -+ return 0; -+} -+ -+static int exfat_utf8_d_cmp(const struct dentry *dentry, unsigned int len, -+ const char *str, const struct qstr *name) -+{ -+ struct super_block *sb = dentry->d_sb; -+ unsigned int alen = exfat_striptail_len(name->len, name->name); -+ unsigned int blen = exfat_striptail_len(len, str); -+ unicode_t u_a, u_b; -+ int charlen, i; -+ -+ if (alen != blen) -+ return 1; -+ -+ for (i = 0; i < alen; i += charlen) { -+ charlen = utf8_to_utf32(&name->name[i], alen - i, &u_a); -+ if (charlen < 0) -+ return 1; -+ if (charlen != utf8_to_utf32(&str[i], blen - i, &u_b)) -+ return 1; -+ -+ if (u_a <= 0xFFFF && u_b <= 0xFFFF) { -+ if (exfat_toupper(sb, u_a) != exfat_toupper(sb, u_b)) -+ return 1; -+ } else if (u_a > 0xFFFF && u_b > 0xFFFF) { -+ if (exfat_low_surrogate(u_a) != -+ exfat_low_surrogate(u_b) || -+ exfat_high_surrogate(u_a) != -+ exfat_high_surrogate(u_b)) -+ return 1; -+ } else { -+ return 1; -+ } -+ } -+ -+ return 0; -+} -+ -+const struct dentry_operations exfat_utf8_dentry_ops = { -+ .d_revalidate = exfat_d_revalidate, -+ .d_hash = exfat_utf8_d_hash, -+ .d_compare = exfat_utf8_d_cmp, -+}; -+ -+/* used only in search empty_slot() */ -+#define CNT_UNUSED_NOHIT (-1) -+#define CNT_UNUSED_HIT (-2) -+/* search EMPTY CONTINUOUS "num_entries" entries */ -+static int exfat_search_empty_slot(struct super_block *sb, -+ struct exfat_hint_femp *hint_femp, struct exfat_chain *p_dir, -+ int num_entries) -+{ -+ int i, dentry, num_empty = 0; -+ int dentries_per_clu; -+ unsigned int type; -+ struct exfat_chain clu; -+ struct exfat_dentry *ep; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct buffer_head *bh; -+ -+ dentries_per_clu = sbi->dentries_per_clu; -+ -+ if (hint_femp->eidx != EXFAT_HINT_NONE) { -+ dentry = hint_femp->eidx; -+ if (num_entries <= hint_femp->count) { -+ hint_femp->eidx = EXFAT_HINT_NONE; -+ return dentry; -+ } -+ -+ exfat_chain_dup(&clu, &hint_femp->cur); -+ } else { -+ exfat_chain_dup(&clu, p_dir); -+ dentry = 0; -+ } -+ -+ while (clu.dir != EXFAT_EOF_CLUSTER) { -+ i = dentry & (dentries_per_clu - 1); -+ -+ for (; i < dentries_per_clu; i++, dentry++) { -+ ep = exfat_get_dentry(sb, &clu, i, &bh, NULL); -+ if (!ep) -+ return -EIO; -+ type = exfat_get_entry_type(ep); -+ brelse(bh); -+ -+ if (type == TYPE_UNUSED || type == TYPE_DELETED) { -+ num_empty++; -+ if (hint_femp->eidx == EXFAT_HINT_NONE) { -+ hint_femp->eidx = dentry; -+ hint_femp->count = CNT_UNUSED_NOHIT; -+ exfat_chain_set(&hint_femp->cur, -+ clu.dir, clu.size, clu.flags); -+ } -+ -+ if (type == TYPE_UNUSED && -+ hint_femp->count != CNT_UNUSED_HIT) -+ hint_femp->count = CNT_UNUSED_HIT; -+ } else { -+ if (hint_femp->eidx != EXFAT_HINT_NONE && -+ hint_femp->count == CNT_UNUSED_HIT) { -+ /* unused empty group means -+ * an empty group which includes -+ * unused dentry -+ */ -+ exfat_fs_error(sb, -+ "found bogus dentry(%d) beyond unused empty group(%d) (start_clu : %u, cur_clu : %u)", -+ dentry, hint_femp->eidx, -+ p_dir->dir, clu.dir); -+ return -EIO; -+ } -+ -+ num_empty = 0; -+ hint_femp->eidx = EXFAT_HINT_NONE; -+ } -+ -+ if (num_empty >= num_entries) { -+ /* found and invalidate hint_femp */ -+ hint_femp->eidx = EXFAT_HINT_NONE; -+ return (dentry - (num_entries - 1)); -+ } -+ } -+ -+ if (clu.flags == ALLOC_NO_FAT_CHAIN) { -+ if (--clu.size > 0) -+ clu.dir++; -+ else -+ clu.dir = EXFAT_EOF_CLUSTER; -+ } else { -+ if (exfat_get_next_cluster(sb, &clu.dir)) -+ return -EIO; -+ } -+ } -+ -+ return -ENOSPC; -+} -+ -+static int exfat_check_max_dentries(struct inode *inode) -+{ -+ if (EXFAT_B_TO_DEN(i_size_read(inode)) >= MAX_EXFAT_DENTRIES) { -+ /* -+ * exFAT spec allows a dir to grow upto 8388608(256MB) -+ * dentries -+ */ -+ return -ENOSPC; -+ } -+ return 0; -+} -+ -+/* find empty directory entry. -+ * if there isn't any empty slot, expand cluster chain. -+ */ -+static int exfat_find_empty_entry(struct inode *inode, -+ struct exfat_chain *p_dir, int num_entries) -+{ -+ int dentry; -+ unsigned int ret, last_clu; -+ sector_t sector; -+ loff_t size = 0; -+ struct exfat_chain clu; -+ struct exfat_dentry *ep = NULL; -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ struct exfat_hint_femp hint_femp; -+ -+ hint_femp.eidx = EXFAT_HINT_NONE; -+ -+ if (ei->hint_femp.eidx != EXFAT_HINT_NONE) { -+ memcpy(&hint_femp, &ei->hint_femp, -+ sizeof(struct exfat_hint_femp)); -+ ei->hint_femp.eidx = EXFAT_HINT_NONE; -+ } -+ -+ while ((dentry = exfat_search_empty_slot(sb, &hint_femp, p_dir, -+ num_entries)) < 0) { -+ if (dentry == -EIO) -+ break; -+ -+ if (exfat_check_max_dentries(inode)) -+ return -ENOSPC; -+ -+ /* we trust p_dir->size regardless of FAT type */ -+ if (exfat_find_last_cluster(sb, p_dir, &last_clu)) -+ return -EIO; -+ -+ /* -+ * Allocate new cluster to this directory -+ */ -+ exfat_chain_set(&clu, last_clu + 1, 0, p_dir->flags); -+ -+ /* allocate a cluster */ -+ ret = exfat_alloc_cluster(inode, 1, &clu); -+ if (ret) -+ return ret; -+ -+ if (exfat_zeroed_cluster(inode, clu.dir)) -+ return -EIO; -+ -+ /* append to the FAT chain */ -+ if (clu.flags != p_dir->flags) { -+ /* no-fat-chain bit is disabled, -+ * so fat-chain should be synced with alloc-bitmap -+ */ -+ exfat_chain_cont_cluster(sb, p_dir->dir, p_dir->size); -+ p_dir->flags = ALLOC_FAT_CHAIN; -+ hint_femp.cur.flags = ALLOC_FAT_CHAIN; -+ } -+ -+ if (clu.flags == ALLOC_FAT_CHAIN) -+ if (exfat_ent_set(sb, last_clu, clu.dir)) -+ return -EIO; -+ -+ if (hint_femp.eidx == EXFAT_HINT_NONE) { -+ /* the special case that new dentry -+ * should be allocated from the start of new cluster -+ */ -+ hint_femp.eidx = EXFAT_B_TO_DEN_IDX(p_dir->size, sbi); -+ hint_femp.count = sbi->dentries_per_clu; -+ -+ exfat_chain_set(&hint_femp.cur, clu.dir, 0, clu.flags); -+ } -+ hint_femp.cur.size++; -+ p_dir->size++; -+ size = EXFAT_CLU_TO_B(p_dir->size, sbi); -+ -+ /* update the directory entry */ -+ if (p_dir->dir != sbi->root_dir) { -+ struct buffer_head *bh; -+ -+ ep = exfat_get_dentry(sb, -+ &(ei->dir), ei->entry + 1, &bh, §or); -+ if (!ep) -+ return -EIO; -+ -+ ep->dentry.stream.valid_size = cpu_to_le64(size); -+ ep->dentry.stream.size = ep->dentry.stream.valid_size; -+ ep->dentry.stream.flags = p_dir->flags; -+ exfat_update_bh(sb, bh, IS_DIRSYNC(inode)); -+ brelse(bh); -+ if (exfat_update_dir_chksum(inode, &(ei->dir), -+ ei->entry)) -+ return -EIO; -+ } -+ -+ /* directory inode should be updated in here */ -+ i_size_write(inode, size); -+ EXFAT_I(inode)->i_size_ondisk += sbi->cluster_size; -+ EXFAT_I(inode)->i_size_aligned += sbi->cluster_size; -+ EXFAT_I(inode)->flags = p_dir->flags; -+ inode->i_blocks += 1 << sbi->sect_per_clus_bits; -+ } -+ -+ return dentry; -+} -+ -+/* -+ * Name Resolution Functions : -+ * Zero if it was successful; otherwise nonzero. -+ */ -+static int __exfat_resolve_path(struct inode *inode, const unsigned char *path, -+ struct exfat_chain *p_dir, struct exfat_uni_name *p_uniname, -+ int lookup) -+{ -+ int namelen; -+ int lossy = NLS_NAME_NO_LOSSY; -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ -+ /* strip all trailing periods */ -+ namelen = exfat_striptail_len(strlen(path), path); -+ if (!namelen) -+ return -ENOENT; -+ -+ if (strlen(path) > (MAX_NAME_LENGTH * MAX_CHARSET_SIZE)) -+ return -ENAMETOOLONG; -+ -+ /* -+ * strip all leading spaces : -+ * "MS windows 7" supports leading spaces. -+ * So we should skip this preprocessing for compatibility. -+ */ -+ -+ /* file name conversion : -+ * If lookup case, we allow bad-name for compatibility. -+ */ -+ namelen = exfat_nls_to_utf16(sb, path, namelen, p_uniname, -+ &lossy); -+ if (namelen < 0) -+ return namelen; /* return error value */ -+ -+ if ((lossy && !lookup) || !namelen) -+ return -EINVAL; -+ -+ exfat_chain_set(p_dir, ei->start_clu, -+ EXFAT_B_TO_CLU(i_size_read(inode), sbi), ei->flags); -+ -+ return 0; -+} -+ -+static inline int exfat_resolve_path(struct inode *inode, -+ const unsigned char *path, struct exfat_chain *dir, -+ struct exfat_uni_name *uni) -+{ -+ return __exfat_resolve_path(inode, path, dir, uni, 0); -+} -+ -+static inline int exfat_resolve_path_for_lookup(struct inode *inode, -+ const unsigned char *path, struct exfat_chain *dir, -+ struct exfat_uni_name *uni) -+{ -+ return __exfat_resolve_path(inode, path, dir, uni, 1); -+} -+ -+static inline loff_t exfat_make_i_pos(struct exfat_dir_entry *info) -+{ -+ return ((loff_t) info->dir.dir << 32) | (info->entry & 0xffffffff); -+} -+ -+static int exfat_add_entry(struct inode *inode, const char *path, -+ struct exfat_chain *p_dir, unsigned int type, -+ struct exfat_dir_entry *info) -+{ -+ int ret, dentry, num_entries; -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct exfat_uni_name uniname; -+ struct exfat_chain clu; -+ int clu_size = 0; -+ unsigned int start_clu = EXFAT_FREE_CLUSTER; -+ -+ ret = exfat_resolve_path(inode, path, p_dir, &uniname); -+ if (ret) -+ goto out; -+ -+ num_entries = exfat_calc_num_entries(&uniname); -+ if (num_entries < 0) { -+ ret = num_entries; -+ goto out; -+ } -+ -+ /* exfat_find_empty_entry must be called before alloc_cluster() */ -+ dentry = exfat_find_empty_entry(inode, p_dir, num_entries); -+ if (dentry < 0) { -+ ret = dentry; /* -EIO or -ENOSPC */ -+ goto out; -+ } -+ -+ if (type == TYPE_DIR) { -+ ret = exfat_alloc_new_dir(inode, &clu); -+ if (ret) -+ goto out; -+ start_clu = clu.dir; -+ clu_size = sbi->cluster_size; -+ } -+ -+ /* update the directory entry */ -+ /* fill the dos name directory entry information of the created file. -+ * the first cluster is not determined yet. (0) -+ */ -+ ret = exfat_init_dir_entry(inode, p_dir, dentry, type, -+ start_clu, clu_size); -+ if (ret) -+ goto out; -+ -+ ret = exfat_init_ext_entry(inode, p_dir, dentry, num_entries, &uniname); -+ if (ret) -+ goto out; -+ -+ memcpy(&info->dir, p_dir, sizeof(struct exfat_chain)); -+ info->entry = dentry; -+ info->flags = ALLOC_NO_FAT_CHAIN; -+ info->type = type; -+ -+ if (type == TYPE_FILE) { -+ info->attr = ATTR_ARCHIVE; -+ info->start_clu = EXFAT_EOF_CLUSTER; -+ info->size = 0; -+ info->num_subdirs = 0; -+ } else { -+ int count; -+ struct exfat_chain cdir; -+ -+ info->attr = ATTR_SUBDIR; -+ info->start_clu = start_clu; -+ info->size = clu_size; -+ -+ exfat_chain_set(&cdir, info->start_clu, -+ EXFAT_B_TO_CLU(info->size, sbi), info->flags); -+ count = exfat_count_dir_entries(sb, &cdir); -+ if (count < 0) -+ return -EIO; -+ info->num_subdirs = count + EXFAT_MIN_SUBDIR; -+ } -+ memset(&info->crtime, 0, sizeof(info->crtime)); -+ memset(&info->mtime, 0, sizeof(info->mtime)); -+ memset(&info->atime, 0, sizeof(info->atime)); -+out: -+ return ret; -+} -+ -+static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, -+ bool excl) -+{ -+ struct super_block *sb = dir->i_sb; -+ struct inode *inode; -+ struct exfat_chain cdir; -+ struct exfat_dir_entry info; -+ loff_t i_pos; -+ int err; -+ -+ mutex_lock(&EXFAT_SB(sb)->s_lock); -+ exfat_set_vol_flags(sb, VOL_DIRTY); -+ err = exfat_add_entry(dir, dentry->d_name.name, &cdir, TYPE_FILE, -+ &info); -+ exfat_set_vol_flags(sb, VOL_CLEAN); -+ if (err) -+ goto unlock; -+ -+ inode_inc_iversion(dir); -+ dir->i_ctime = dir->i_mtime = current_time(dir); -+ if (IS_DIRSYNC(dir)) -+ exfat_sync_inode(dir); -+ else -+ mark_inode_dirty(dir); -+ -+ i_pos = exfat_make_i_pos(&info); -+ inode = exfat_build_inode(sb, &info, i_pos); -+ if (IS_ERR(inode)) -+ goto unlock; -+ -+ inode_inc_iversion(inode); -+ inode->i_mtime = inode->i_atime = inode->i_ctime = -+ EXFAT_I(inode)->i_crtime = current_time(inode); -+ /* timestamp is already written, so mark_inode_dirty() is unneeded. */ -+ -+ d_instantiate(dentry, inode); -+unlock: -+ mutex_unlock(&EXFAT_SB(sb)->s_lock); -+ return err; -+} -+ -+/* lookup a file */ -+static int exfat_find(struct inode *dir, struct qstr *qname, -+ struct exfat_dir_entry *info) -+{ -+ int ret, dentry, num_entries, count; -+ struct exfat_chain cdir; -+ struct exfat_uni_name uni_name; -+ struct exfat_dentry *ep, *ep2; -+ struct exfat_entry_set_cache *es = NULL; -+ struct super_block *sb = dir->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct exfat_inode_info *ei = EXFAT_I(dir); -+ -+ if (qname->len == 0) -+ return -ENOENT; -+ -+ /* check the validity of directory name in the given pathname */ -+ ret = exfat_resolve_path_for_lookup(dir, qname->name, &cdir, &uni_name); -+ if (ret) -+ return ret; -+ -+ num_entries = exfat_calc_num_entries(&uni_name); -+ if (num_entries < 0) -+ return num_entries; -+ -+ /* check the validation of hint_stat and initialize it if required */ -+ if (ei->version != (inode_peek_iversion_raw(dir) & 0xffffffff)) { -+ ei->hint_stat.clu = cdir.dir; -+ ei->hint_stat.eidx = 0; -+ ei->version = (inode_peek_iversion_raw(dir) & 0xffffffff); -+ ei->hint_femp.eidx = EXFAT_HINT_NONE; -+ } -+ -+ /* search the file name for directories */ -+ dentry = exfat_find_dir_entry(sb, ei, &cdir, &uni_name, -+ num_entries, TYPE_ALL); -+ -+ if ((dentry < 0) && (dentry != -EEXIST)) -+ return dentry; /* -error value */ -+ -+ memcpy(&info->dir, &cdir.dir, sizeof(struct exfat_chain)); -+ info->entry = dentry; -+ info->num_subdirs = 0; -+ -+ /* root directory itself */ -+ if (unlikely(dentry == -EEXIST)) { -+ int num_clu = 0; -+ -+ info->type = TYPE_DIR; -+ info->attr = ATTR_SUBDIR; -+ info->flags = ALLOC_FAT_CHAIN; -+ info->start_clu = sbi->root_dir; -+ memset(&info->crtime, 0, sizeof(info->crtime)); -+ memset(&info->mtime, 0, sizeof(info->mtime)); -+ memset(&info->atime, 0, sizeof(info->atime)); -+ -+ exfat_chain_set(&cdir, sbi->root_dir, 0, ALLOC_FAT_CHAIN); -+ if (exfat_count_num_clusters(sb, &cdir, &num_clu)) -+ return -EIO; -+ info->size = num_clu << sbi->cluster_size_bits; -+ -+ count = exfat_count_dir_entries(sb, &cdir); -+ if (count < 0) -+ return -EIO; -+ -+ info->num_subdirs = count; -+ } else { -+ es = exfat_get_dentry_set(sb, &cdir, dentry, ES_2_ENTRIES, &ep); -+ if (!es) -+ return -EIO; -+ ep2 = ep + 1; -+ -+ info->type = exfat_get_entry_type(ep); -+ info->attr = le16_to_cpu(ep->dentry.file.attr); -+ info->size = le64_to_cpu(ep2->dentry.stream.valid_size); -+ if ((info->type == TYPE_FILE) && (info->size == 0)) { -+ info->flags = ALLOC_NO_FAT_CHAIN; -+ info->start_clu = EXFAT_EOF_CLUSTER; -+ } else { -+ info->flags = ep2->dentry.stream.flags; -+ info->start_clu = -+ le32_to_cpu(ep2->dentry.stream.start_clu); -+ } -+ -+ if (ei->start_clu == EXFAT_FREE_CLUSTER) { -+ exfat_fs_error(sb, -+ "non-zero size file starts with zero cluster (size : %llu, p_dir : %u, entry : 0x%08x)", -+ i_size_read(dir), ei->dir.dir, ei->entry); -+ return -EIO; -+ } -+ -+ exfat_get_entry_time(sbi, &info->crtime, -+ ep->dentry.file.create_tz, -+ ep->dentry.file.create_time, -+ ep->dentry.file.create_date, -+ ep->dentry.file.create_time_ms); -+ exfat_get_entry_time(sbi, &info->mtime, -+ ep->dentry.file.modify_tz, -+ ep->dentry.file.modify_time, -+ ep->dentry.file.modify_date, -+ ep->dentry.file.modify_time_ms); -+ exfat_get_entry_time(sbi, &info->atime, -+ ep->dentry.file.access_tz, -+ ep->dentry.file.access_time, -+ ep->dentry.file.access_date, -+ 0); -+ kfree(es); -+ -+ if (info->type == TYPE_DIR) { -+ exfat_chain_set(&cdir, info->start_clu, -+ EXFAT_B_TO_CLU(info->size, sbi), info->flags); -+ count = exfat_count_dir_entries(sb, &cdir); -+ if (count < 0) -+ return -EIO; -+ -+ info->num_subdirs = count + EXFAT_MIN_SUBDIR; -+ } -+ } -+ return 0; -+} -+ -+static int exfat_d_anon_disconn(struct dentry *dentry) -+{ -+ return IS_ROOT(dentry) && (dentry->d_flags & DCACHE_DISCONNECTED); -+} -+ -+static struct dentry *exfat_lookup(struct inode *dir, struct dentry *dentry, -+ unsigned int flags) -+{ -+ struct super_block *sb = dir->i_sb; -+ struct inode *inode; -+ struct dentry *alias; -+ struct exfat_dir_entry info; -+ int err; -+ loff_t i_pos; -+ mode_t i_mode; -+ -+ mutex_lock(&EXFAT_SB(sb)->s_lock); -+ err = exfat_find(dir, &dentry->d_name, &info); -+ if (err) { -+ if (err == -ENOENT) { -+ inode = NULL; -+ goto out; -+ } -+ goto unlock; -+ } -+ -+ i_pos = exfat_make_i_pos(&info); -+ inode = exfat_build_inode(sb, &info, i_pos); -+ if (IS_ERR(inode)) { -+ err = PTR_ERR(inode); -+ goto unlock; -+ } -+ -+ i_mode = inode->i_mode; -+ alias = d_find_alias(inode); -+ -+ /* -+ * Checking "alias->d_parent == dentry->d_parent" to make sure -+ * FS is not corrupted (especially double linked dir). -+ */ -+ if (alias && alias->d_parent == dentry->d_parent && -+ !exfat_d_anon_disconn(alias)) { -+ -+ /* -+ * Unhashed alias is able to exist because of revalidate() -+ * called by lookup_fast. You can easily make this status -+ * by calling create and lookup concurrently -+ * In such case, we reuse an alias instead of new dentry -+ */ -+ if (d_unhashed(alias)) { -+ WARN_ON(alias->d_name.hash_len != -+ dentry->d_name.hash_len); -+ exfat_msg(sb, KERN_INFO, -+ "rehashed a dentry(%p) in read lookup", alias); -+ d_drop(dentry); -+ d_rehash(alias); -+ } else if (!S_ISDIR(i_mode)) { -+ /* -+ * This inode has non anonymous-DCACHE_DISCONNECTED -+ * dentry. This means, the user did ->lookup() by an -+ * another name (longname vs 8.3 alias of it) in past. -+ * -+ * Switch to new one for reason of locality if possible. -+ */ -+ d_move(alias, dentry); -+ } -+ iput(inode); -+ mutex_unlock(&EXFAT_SB(sb)->s_lock); -+ return alias; -+ } -+ dput(alias); -+out: -+ mutex_unlock(&EXFAT_SB(sb)->s_lock); -+ if (!inode) -+ exfat_d_version_set(dentry, inode_query_iversion(dir)); -+ -+ return d_splice_alias(inode, dentry); -+unlock: -+ mutex_unlock(&EXFAT_SB(sb)->s_lock); -+ return ERR_PTR(err); -+} -+ -+/* remove an entry, BUT don't truncate */ -+static int exfat_unlink(struct inode *dir, struct dentry *dentry) -+{ -+ struct exfat_chain cdir; -+ struct exfat_dentry *ep; -+ struct super_block *sb = dir->i_sb; -+ struct inode *inode = dentry->d_inode; -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ struct buffer_head *bh; -+ sector_t sector; -+ int num_entries, entry, err = 0; -+ -+ mutex_lock(&EXFAT_SB(sb)->s_lock); -+ exfat_chain_dup(&cdir, &ei->dir); -+ entry = ei->entry; -+ if (ei->dir.dir == DIR_DELETED) { -+ exfat_msg(sb, KERN_ERR, "abnormal access to deleted dentry"); -+ err = -ENOENT; -+ goto unlock; -+ } -+ -+ ep = exfat_get_dentry(sb, &cdir, entry, &bh, §or); -+ if (!ep) { -+ err = -EIO; -+ goto unlock; -+ } -+ num_entries = exfat_count_ext_entries(sb, &cdir, entry, ep); -+ if (num_entries < 0) { -+ err = -EIO; -+ brelse(bh); -+ goto unlock; -+ } -+ num_entries++; -+ brelse(bh); -+ -+ exfat_set_vol_flags(sb, VOL_DIRTY); -+ /* update the directory entry */ -+ if (exfat_remove_entries(dir, &cdir, entry, 0, num_entries)) { -+ err = -EIO; -+ goto unlock; -+ } -+ -+ /* This doesn't modify ei */ -+ ei->dir.dir = DIR_DELETED; -+ exfat_set_vol_flags(sb, VOL_CLEAN); -+ -+ inode_inc_iversion(dir); -+ dir->i_mtime = dir->i_atime = current_time(dir); -+ if (IS_DIRSYNC(dir)) -+ exfat_sync_inode(dir); -+ else -+ mark_inode_dirty(dir); -+ -+ clear_nlink(inode); -+ inode->i_mtime = inode->i_atime = current_time(inode); -+ exfat_unhash_inode(inode); -+ exfat_d_version_set(dentry, inode_query_iversion(dir)); -+unlock: -+ mutex_unlock(&EXFAT_SB(sb)->s_lock); -+ return err; -+} -+ -+static int exfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) -+{ -+ struct super_block *sb = dir->i_sb; -+ struct inode *inode; -+ struct exfat_dir_entry info; -+ struct exfat_chain cdir; -+ loff_t i_pos; -+ int err; -+ -+ mutex_lock(&EXFAT_SB(sb)->s_lock); -+ exfat_set_vol_flags(sb, VOL_DIRTY); -+ err = exfat_add_entry(dir, dentry->d_name.name, &cdir, TYPE_DIR, -+ &info); -+ exfat_set_vol_flags(sb, VOL_CLEAN); -+ if (err) -+ goto unlock; -+ -+ inode_inc_iversion(dir); -+ dir->i_ctime = dir->i_mtime = current_time(dir); -+ if (IS_DIRSYNC(dir)) -+ exfat_sync_inode(dir); -+ else -+ mark_inode_dirty(dir); -+ inc_nlink(dir); -+ -+ i_pos = exfat_make_i_pos(&info); -+ inode = exfat_build_inode(sb, &info, i_pos); -+ if (IS_ERR(inode)) { -+ err = PTR_ERR(inode); -+ goto unlock; -+ } -+ -+ inode_inc_iversion(inode); -+ inode->i_mtime = inode->i_atime = inode->i_ctime = -+ EXFAT_I(inode)->i_crtime = current_time(inode); -+ /* timestamp is already written, so mark_inode_dirty() is unneeded. */ -+ -+ d_instantiate(dentry, inode); -+ -+unlock: -+ mutex_unlock(&EXFAT_SB(sb)->s_lock); -+ return err; -+} -+ -+static int exfat_check_dir_empty(struct super_block *sb, -+ struct exfat_chain *p_dir) -+{ -+ int i, dentries_per_clu; -+ unsigned int type; -+ struct exfat_chain clu; -+ struct exfat_dentry *ep; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct buffer_head *bh; -+ -+ dentries_per_clu = sbi->dentries_per_clu; -+ -+ exfat_chain_dup(&clu, p_dir); -+ -+ while (clu.dir != EXFAT_EOF_CLUSTER) { -+ for (i = 0; i < dentries_per_clu; i++) { -+ ep = exfat_get_dentry(sb, &clu, i, &bh, NULL); -+ if (!ep) -+ return -EIO; -+ type = exfat_get_entry_type(ep); -+ brelse(bh); -+ if (type == TYPE_UNUSED) -+ return 0; -+ -+ if (type != TYPE_FILE && type != TYPE_DIR) -+ continue; -+ -+ return -ENOTEMPTY; -+ } -+ -+ if (clu.flags == ALLOC_NO_FAT_CHAIN) { -+ if (--clu.size > 0) -+ clu.dir++; -+ else -+ clu.dir = EXFAT_EOF_CLUSTER; -+ } else { -+ if (exfat_get_next_cluster(sb, &(clu.dir))) -+ return -EIO; -+ } -+ } -+ -+ return 0; -+} -+ -+static int exfat_rmdir(struct inode *dir, struct dentry *dentry) -+{ -+ struct inode *inode = dentry->d_inode; -+ struct exfat_dentry *ep; -+ struct exfat_chain cdir, clu_to_free; -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ struct buffer_head *bh; -+ sector_t sector; -+ int num_entries, entry, err; -+ -+ mutex_lock(&EXFAT_SB(inode->i_sb)->s_lock); -+ -+ exfat_chain_dup(&cdir, &ei->dir); -+ entry = ei->entry; -+ -+ if (ei->dir.dir == DIR_DELETED) { -+ exfat_msg(sb, KERN_ERR, "abnormal access to deleted dentry"); -+ err = -ENOENT; -+ goto unlock; -+ } -+ -+ exfat_set_vol_flags(sb, VOL_DIRTY); -+ exfat_chain_set(&clu_to_free, ei->start_clu, -+ EXFAT_B_TO_CLU_ROUND_UP(i_size_read(inode), sbi), ei->flags); -+ -+ err = exfat_check_dir_empty(sb, &clu_to_free); -+ if (err) { -+ if (err == -EIO) -+ exfat_msg(sb, KERN_ERR, -+ "failed to exfat_check_dir_empty : err(%d)", -+ err); -+ goto unlock; -+ } -+ -+ ep = exfat_get_dentry(sb, &cdir, entry, &bh, §or); -+ if (!ep) { -+ err = -EIO; -+ goto unlock; -+ } -+ -+ num_entries = exfat_count_ext_entries(sb, &cdir, entry, ep); -+ if (num_entries < 0) { -+ err = -EIO; -+ brelse(bh); -+ goto unlock; -+ } -+ num_entries++; -+ brelse(bh); -+ -+ err = exfat_remove_entries(dir, &cdir, entry, 0, num_entries); -+ if (err) { -+ exfat_msg(sb, KERN_ERR, -+ "failed to exfat_remove_entries : err(%d)", -+ err); -+ goto unlock; -+ } -+ ei->dir.dir = DIR_DELETED; -+ exfat_set_vol_flags(sb, VOL_CLEAN); -+ -+ inode_inc_iversion(dir); -+ dir->i_mtime = dir->i_atime = current_time(dir); -+ if (IS_DIRSYNC(dir)) -+ exfat_sync_inode(dir); -+ else -+ mark_inode_dirty(dir); -+ drop_nlink(dir); -+ -+ clear_nlink(inode); -+ inode->i_mtime = inode->i_atime = current_time(inode); -+ exfat_unhash_inode(inode); -+ exfat_d_version_set(dentry, inode_query_iversion(dir)); -+unlock: -+ mutex_unlock(&EXFAT_SB(inode->i_sb)->s_lock); -+ return err; -+} -+ -+static int exfat_rename_file(struct inode *inode, struct exfat_chain *p_dir, -+ int oldentry, struct exfat_uni_name *p_uniname, -+ struct exfat_inode_info *ei) -+{ -+ int ret, num_old_entries, num_new_entries; -+ sector_t sector_old, sector_new; -+ struct exfat_dentry *epold, *epnew; -+ struct super_block *sb = inode->i_sb; -+ struct buffer_head *new_bh, *old_bh; -+ int sync = IS_DIRSYNC(inode); -+ -+ epold = exfat_get_dentry(sb, p_dir, oldentry, &old_bh, §or_old); -+ if (!epold) -+ return -EIO; -+ -+ num_old_entries = exfat_count_ext_entries(sb, p_dir, oldentry, epold); -+ if (num_old_entries < 0) -+ return -EIO; -+ num_old_entries++; -+ -+ num_new_entries = exfat_calc_num_entries(p_uniname); -+ if (num_new_entries < 0) -+ return num_new_entries; -+ -+ if (num_old_entries < num_new_entries) { -+ int newentry; -+ -+ newentry = -+ exfat_find_empty_entry(inode, p_dir, num_new_entries); -+ if (newentry < 0) -+ return newentry; /* -EIO or -ENOSPC */ -+ -+ epnew = exfat_get_dentry(sb, p_dir, newentry, &new_bh, -+ §or_new); -+ if (!epnew) -+ return -EIO; -+ -+ memcpy(epnew, epold, DENTRY_SIZE); -+ if (exfat_get_entry_type(epnew) == TYPE_FILE) { -+ epnew->dentry.file.attr |= cpu_to_le16(ATTR_ARCHIVE); -+ ei->attr |= ATTR_ARCHIVE; -+ } -+ exfat_update_bh(sb, new_bh, sync); -+ brelse(old_bh); -+ brelse(new_bh); -+ -+ epold = exfat_get_dentry(sb, p_dir, oldentry + 1, &old_bh, -+ §or_old); -+ epnew = exfat_get_dentry(sb, p_dir, newentry + 1, &new_bh, -+ §or_new); -+ if (!epold || !epnew) -+ return -EIO; -+ -+ memcpy(epnew, epold, DENTRY_SIZE); -+ exfat_update_bh(sb, new_bh, sync); -+ brelse(old_bh); -+ brelse(new_bh); -+ -+ ret = exfat_init_ext_entry(inode, p_dir, newentry, -+ num_new_entries, p_uniname); -+ if (ret) -+ return ret; -+ -+ exfat_remove_entries(inode, p_dir, oldentry, 0, -+ num_old_entries); -+ ei->entry = newentry; -+ } else { -+ if (exfat_get_entry_type(epold) == TYPE_FILE) { -+ epold->dentry.file.attr |= cpu_to_le16(ATTR_ARCHIVE); -+ ei->attr |= ATTR_ARCHIVE; -+ } -+ exfat_update_bh(sb, old_bh, sync); -+ brelse(old_bh); -+ ret = exfat_init_ext_entry(inode, p_dir, oldentry, -+ num_new_entries, p_uniname); -+ if (ret) -+ return ret; -+ -+ exfat_remove_entries(inode, p_dir, oldentry, num_new_entries, -+ num_old_entries); -+ } -+ return 0; -+} -+ -+static int exfat_move_file(struct inode *inode, struct exfat_chain *p_olddir, -+ int oldentry, struct exfat_chain *p_newdir, -+ struct exfat_uni_name *p_uniname, struct exfat_inode_info *ei) -+{ -+ int ret, newentry, num_new_entries, num_old_entries; -+ sector_t sector_mov, sector_new; -+ struct exfat_dentry *epmov, *epnew; -+ struct super_block *sb = inode->i_sb; -+ struct buffer_head *mov_bh, *new_bh; -+ -+ epmov = exfat_get_dentry(sb, p_olddir, oldentry, &mov_bh, §or_mov); -+ if (!epmov) -+ return -EIO; -+ -+ /* check if the source and target directory is the same */ -+ if (exfat_get_entry_type(epmov) == TYPE_DIR && -+ le32_to_cpu(epmov->dentry.stream.start_clu) == p_newdir->dir) -+ return -EINVAL; -+ -+ num_old_entries = exfat_count_ext_entries(sb, p_olddir, oldentry, -+ epmov); -+ if (num_old_entries < 0) -+ return -EIO; -+ num_old_entries++; -+ -+ num_new_entries = exfat_calc_num_entries(p_uniname); -+ if (num_new_entries < 0) -+ return num_new_entries; -+ -+ newentry = exfat_find_empty_entry(inode, p_newdir, num_new_entries); -+ if (newentry < 0) -+ return newentry; /* -EIO or -ENOSPC */ -+ -+ epnew = exfat_get_dentry(sb, p_newdir, newentry, &new_bh, §or_new); -+ if (!epnew) -+ return -EIO; -+ -+ memcpy(epnew, epmov, DENTRY_SIZE); -+ if (exfat_get_entry_type(epnew) == TYPE_FILE) { -+ epnew->dentry.file.attr |= cpu_to_le16(ATTR_ARCHIVE); -+ ei->attr |= ATTR_ARCHIVE; -+ } -+ exfat_update_bh(sb, new_bh, IS_DIRSYNC(inode)); -+ brelse(mov_bh); -+ brelse(new_bh); -+ -+ epmov = exfat_get_dentry(sb, p_olddir, oldentry + 1, &mov_bh, -+ §or_mov); -+ epnew = exfat_get_dentry(sb, p_newdir, newentry + 1, &new_bh, -+ §or_new); -+ if (!epmov || !epnew) -+ return -EIO; -+ -+ memcpy(epnew, epmov, DENTRY_SIZE); -+ exfat_update_bh(sb, new_bh, IS_DIRSYNC(inode)); -+ brelse(mov_bh); -+ brelse(new_bh); -+ -+ ret = exfat_init_ext_entry(inode, p_newdir, newentry, num_new_entries, -+ p_uniname); -+ if (ret) -+ return ret; -+ -+ exfat_remove_entries(inode, p_olddir, oldentry, 0, num_old_entries); -+ -+ exfat_chain_set(&ei->dir, p_newdir->dir, p_newdir->size, -+ p_newdir->flags); -+ -+ ei->entry = newentry; -+ return 0; -+} -+ -+static void exfat_update_parent_info(struct exfat_inode_info *ei, -+ struct inode *parent_inode) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(parent_inode->i_sb); -+ struct exfat_inode_info *parent_ei = EXFAT_I(parent_inode); -+ loff_t parent_isize = i_size_read(parent_inode); -+ -+ /* -+ * the problem that struct exfat_inode_info caches wrong parent info. -+ * -+ * because of flag-mismatch of ei->dir, -+ * there is abnormal traversing cluster chain. -+ */ -+ if (unlikely(parent_ei->flags != ei->dir.flags || -+ parent_isize != EXFAT_CLU_TO_B(ei->dir.size, sbi) || -+ parent_ei->start_clu != ei->dir.dir)) { -+ exfat_chain_set(&ei->dir, parent_ei->start_clu, -+ EXFAT_B_TO_CLU_ROUND_UP(parent_isize, sbi), -+ parent_ei->flags); -+ } -+} -+ -+/* rename or move a old file into a new file */ -+static int __exfat_rename(struct inode *old_parent_inode, -+ struct exfat_inode_info *ei, struct inode *new_parent_inode, -+ struct dentry *new_dentry) -+{ -+ int ret; -+ int dentry; -+ struct exfat_chain olddir, newdir; -+ struct exfat_chain *p_dir = NULL; -+ struct exfat_uni_name uni_name; -+ struct exfat_dentry *ep; -+ struct super_block *sb = old_parent_inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ const unsigned char *new_path = new_dentry->d_name.name; -+ struct inode *new_inode = new_dentry->d_inode; -+ int num_entries; -+ struct exfat_inode_info *new_ei = NULL; -+ unsigned int new_entry_type = TYPE_UNUSED; -+ int new_entry = 0; -+ struct buffer_head *old_bh, *new_bh = NULL; -+ -+ /* check the validity of pointer parameters */ -+ if (new_path == NULL || strlen(new_path) == 0) -+ return -EINVAL; -+ -+ if (ei->dir.dir == DIR_DELETED) { -+ exfat_msg(sb, KERN_ERR, -+ "abnormal access to deleted source dentry"); -+ return -ENOENT; -+ } -+ -+ exfat_update_parent_info(ei, old_parent_inode); -+ -+ exfat_chain_dup(&olddir, &ei->dir); -+ dentry = ei->entry; -+ -+ ep = exfat_get_dentry(sb, &olddir, dentry, &old_bh, NULL); -+ if (!ep) { -+ ret = -EIO; -+ goto out; -+ } -+ brelse(old_bh); -+ -+ /* check whether new dir is existing directory and empty */ -+ if (new_inode) { -+ ret = -EIO; -+ new_ei = EXFAT_I(new_inode); -+ -+ if (new_ei->dir.dir == DIR_DELETED) { -+ exfat_msg(sb, KERN_ERR, -+ "abnormal access to deleted target dentry"); -+ goto out; -+ } -+ -+ exfat_update_parent_info(new_ei, new_parent_inode); -+ -+ p_dir = &(new_ei->dir); -+ new_entry = new_ei->entry; -+ ep = exfat_get_dentry(sb, p_dir, new_entry, &new_bh, NULL); -+ if (!ep) -+ goto out; -+ -+ new_entry_type = exfat_get_entry_type(ep); -+ brelse(new_bh); -+ -+ /* if new_inode exists, update ei */ -+ if (new_entry_type == TYPE_DIR) { -+ struct exfat_chain new_clu; -+ -+ new_clu.dir = new_ei->start_clu; -+ new_clu.size = -+ EXFAT_B_TO_CLU_ROUND_UP(i_size_read(new_inode), -+ sbi); -+ new_clu.flags = new_ei->flags; -+ -+ ret = exfat_check_dir_empty(sb, &new_clu); -+ if (ret) -+ goto out; -+ } -+ } -+ -+ /* check the validity of directory name in the given new pathname */ -+ ret = exfat_resolve_path(new_parent_inode, new_path, &newdir, -+ &uni_name); -+ if (ret) -+ goto out; -+ -+ exfat_set_vol_flags(sb, VOL_DIRTY); -+ -+ if (olddir.dir == newdir.dir) -+ ret = exfat_rename_file(new_parent_inode, &olddir, dentry, -+ &uni_name, ei); -+ else -+ ret = exfat_move_file(new_parent_inode, &olddir, dentry, -+ &newdir, &uni_name, ei); -+ -+ if (!ret && new_inode) { -+ /* delete entries of new_dir */ -+ ep = exfat_get_dentry(sb, p_dir, new_entry, &new_bh, NULL); -+ if (!ep) { -+ ret = -EIO; -+ goto del_out; -+ } -+ -+ num_entries = exfat_count_ext_entries(sb, p_dir, new_entry, ep); -+ if (num_entries < 0) { -+ ret = -EIO; -+ goto del_out; -+ } -+ brelse(new_bh); -+ -+ if (exfat_remove_entries(new_inode, p_dir, new_entry, 0, -+ num_entries + 1)) { -+ ret = -EIO; -+ goto del_out; -+ } -+ -+ /* Free the clusters if new_inode is a dir(as if exfat_rmdir) */ -+ if (new_entry_type == TYPE_DIR) { -+ /* new_ei, new_clu_to_free */ -+ struct exfat_chain new_clu_to_free; -+ -+ exfat_chain_set(&new_clu_to_free, new_ei->start_clu, -+ EXFAT_B_TO_CLU_ROUND_UP(i_size_read(new_inode), -+ sbi), new_ei->flags); -+ -+ if (exfat_free_cluster(new_inode, &new_clu_to_free)) { -+ /* just set I/O error only */ -+ ret = -EIO; -+ } -+ -+ i_size_write(new_inode, 0); -+ new_ei->start_clu = EXFAT_EOF_CLUSTER; -+ new_ei->flags = ALLOC_NO_FAT_CHAIN; -+ } -+del_out: -+ /* Update new_inode ei -+ * Prevent syncing removed new_inode -+ * (new_ei is already initialized above code ("if (new_inode)") -+ */ -+ new_ei->dir.dir = DIR_DELETED; -+ } -+ exfat_set_vol_flags(sb, VOL_CLEAN); -+out: -+ return ret; -+} -+ -+static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry, -+ struct inode *new_dir, struct dentry *new_dentry, -+ unsigned int flags) -+{ -+ struct inode *old_inode, *new_inode; -+ struct super_block *sb = old_dir->i_sb; -+ loff_t i_pos; -+ int err; -+ -+ /* -+ * The VFS already checks for existence, so for local filesystems -+ * the RENAME_NOREPLACE implementation is equivalent to plain rename. -+ * Don't support any other flags -+ */ -+ if (flags & ~RENAME_NOREPLACE) -+ return -EINVAL; -+ -+ mutex_lock(&EXFAT_SB(sb)->s_lock); -+ old_inode = old_dentry->d_inode; -+ new_inode = new_dentry->d_inode; -+ -+ err = __exfat_rename(old_dir, EXFAT_I(old_inode), new_dir, new_dentry); -+ if (err) -+ goto unlock; -+ -+ inode_inc_iversion(new_dir); -+ new_dir->i_ctime = new_dir->i_mtime = new_dir->i_atime = -+ EXFAT_I(new_dir)->i_crtime = current_time(new_dir); -+ if (IS_DIRSYNC(new_dir)) -+ exfat_sync_inode(new_dir); -+ else -+ mark_inode_dirty(new_dir); -+ -+ i_pos = ((loff_t)EXFAT_I(old_inode)->dir.dir << 32) | -+ (EXFAT_I(old_inode)->entry & 0xffffffff); -+ exfat_unhash_inode(old_inode); -+ exfat_hash_inode(old_inode, i_pos); -+ if (IS_DIRSYNC(new_dir)) -+ exfat_sync_inode(old_inode); -+ else -+ mark_inode_dirty(old_inode); -+ -+ if (S_ISDIR(old_inode->i_mode) && old_dir != new_dir) { -+ drop_nlink(old_dir); -+ if (!new_inode) -+ inc_nlink(new_dir); -+ } -+ -+ inode_inc_iversion(old_dir); -+ old_dir->i_ctime = old_dir->i_mtime = current_time(old_dir); -+ if (IS_DIRSYNC(old_dir)) -+ exfat_sync_inode(old_dir); -+ else -+ mark_inode_dirty(old_dir); -+ -+ if (new_inode) { -+ exfat_unhash_inode(new_inode); -+ -+ /* skip drop_nlink if new_inode already has been dropped */ -+ if (new_inode->i_nlink) { -+ drop_nlink(new_inode); -+ if (S_ISDIR(new_inode->i_mode)) -+ drop_nlink(new_inode); -+ } else { -+ exfat_msg(sb, KERN_WARNING, -+ "abnormal access to an inode dropped"); -+ WARN_ON(new_inode->i_nlink == 0); -+ } -+ new_inode->i_ctime = EXFAT_I(new_inode)->i_crtime = -+ current_time(new_inode); -+ } -+ -+unlock: -+ mutex_unlock(&EXFAT_SB(sb)->s_lock); -+ return err; -+} -+ -+const struct inode_operations exfat_dir_inode_operations = { -+ .create = exfat_create, -+ .lookup = exfat_lookup, -+ .unlink = exfat_unlink, -+ .mkdir = exfat_mkdir, -+ .rmdir = exfat_rmdir, -+ .rename = exfat_rename, -+ .setattr = exfat_setattr, -+ .getattr = exfat_getattr, -+}; --- -2.25.1 - diff --git a/kernel/tools/perf/files/patches/mageia/fs-exfat-add-misc-operations.patch b/kernel/tools/perf/files/patches/mageia/fs-exfat-add-misc-operations.patch deleted file mode 100644 index 5d461d199f..0000000000 --- a/kernel/tools/perf/files/patches/mageia/fs-exfat-add-misc-operations.patch +++ /dev/null @@ -1,193 +0,0 @@ -From 772b29cca528fcb21374bb3e597d848779938d16 Mon Sep 17 00:00:00 2001 -From: Namjae Jeon -Date: Mon, 2 Mar 2020 15:21:40 +0900 -Subject: [PATCH 09/14] exfat: add misc operations -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This adds the implementation of misc operations for exfat. - -Signed-off-by: Namjae Jeon -Signed-off-by: Sungjong Seo -Reviewed-by: Arnd Bergmann -Reviewed-by: Pali Rohár -Reviewed-by: Christoph Hellwig -Signed-off-by: Al Viro ---- - fs/exfat/misc.c | 163 ++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 163 insertions(+) - create mode 100644 fs/exfat/misc.c - -diff --git a/fs/exfat/misc.c b/fs/exfat/misc.c -new file mode 100644 -index 000000000000..14a3300848f6 ---- /dev/null -+++ b/fs/exfat/misc.c -@@ -0,0 +1,163 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * 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. -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include "exfat_raw.h" -+#include "exfat_fs.h" -+ -+/* -+ * exfat_fs_error reports a file system problem that might indicate fa data -+ * corruption/inconsistency. Depending on 'errors' mount option the -+ * panic() is called, or error message is printed FAT and nothing is done, -+ * or filesystem is remounted read-only (default behavior). -+ * In case the file system is remounted read-only, it can be made writable -+ * again by remounting it. -+ */ -+void __exfat_fs_error(struct super_block *sb, int report, const char *fmt, ...) -+{ -+ struct exfat_mount_options *opts = &EXFAT_SB(sb)->options; -+ va_list args; -+ struct va_format vaf; -+ -+ if (report) { -+ va_start(args, fmt); -+ vaf.fmt = fmt; -+ vaf.va = &args; -+ exfat_msg(sb, KERN_ERR, "error, %pV\n", &vaf); -+ va_end(args); -+ } -+ -+ if (opts->errors == EXFAT_ERRORS_PANIC) { -+ panic("exFAT-fs (%s): fs panic from previous error\n", -+ sb->s_id); -+ } else if (opts->errors == EXFAT_ERRORS_RO && !sb_rdonly(sb)) { -+ sb->s_flags |= SB_RDONLY; -+ exfat_msg(sb, KERN_ERR, "Filesystem has been set read-only"); -+ } -+} -+ -+/* -+ * exfat_msg() - print preformated EXFAT specific messages. -+ * All logs except what uses exfat_fs_error() should be written by exfat_msg() -+ */ -+void exfat_msg(struct super_block *sb, const char *level, const char *fmt, ...) -+{ -+ struct va_format vaf; -+ va_list args; -+ -+ va_start(args, fmt); -+ vaf.fmt = fmt; -+ vaf.va = &args; -+ /* level means KERN_ pacility level */ -+ printk("%sexFAT-fs (%s): %pV\n", level, sb->s_id, &vaf); -+ va_end(args); -+} -+ -+#define SECS_PER_MIN (60) -+#define TIMEZONE_SEC(x) ((x) * 15 * SECS_PER_MIN) -+ -+static void exfat_adjust_tz(struct timespec64 *ts, u8 tz_off) -+{ -+ if (tz_off <= 0x3F) -+ ts->tv_sec -= TIMEZONE_SEC(tz_off); -+ else /* 0x40 <= (tz_off & 0x7F) <=0x7F */ -+ ts->tv_sec += TIMEZONE_SEC(0x80 - tz_off); -+} -+ -+/* Convert a EXFAT time/date pair to a UNIX date (seconds since 1 1 70). */ -+void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, -+ u8 tz, __le16 time, __le16 date, u8 time_ms) -+{ -+ u16 t = le16_to_cpu(time); -+ u16 d = le16_to_cpu(date); -+ -+ ts->tv_sec = mktime64(1980 + (d >> 9), d >> 5 & 0x000F, d & 0x001F, -+ t >> 11, (t >> 5) & 0x003F, (t & 0x001F) << 1); -+ -+ -+ /* time_ms field represent 0 ~ 199(1990 ms) */ -+ if (time_ms) { -+ ts->tv_sec += time_ms / 100; -+ ts->tv_nsec = (time_ms % 100) * 10 * NSEC_PER_MSEC; -+ } -+ -+ if (tz & EXFAT_TZ_VALID) -+ /* Adjust timezone to UTC0. */ -+ exfat_adjust_tz(ts, tz & ~EXFAT_TZ_VALID); -+ else -+ /* Convert from local time to UTC using time_offset. */ -+ ts->tv_sec -= sbi->options.time_offset * SECS_PER_MIN; -+} -+ -+/* Convert linear UNIX date to a EXFAT time/date pair. */ -+void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, -+ u8 *tz, __le16 *time, __le16 *date, u8 *time_ms) -+{ -+ struct tm tm; -+ u16 t, d; -+ -+ time64_to_tm(ts->tv_sec, 0, &tm); -+ t = (tm.tm_hour << 11) | (tm.tm_min << 5) | (tm.tm_sec >> 1); -+ d = ((tm.tm_year - 80) << 9) | ((tm.tm_mon + 1) << 5) | tm.tm_mday; -+ -+ *time = cpu_to_le16(t); -+ *date = cpu_to_le16(d); -+ -+ /* time_ms field represent 0 ~ 199(1990 ms) */ -+ if (time_ms) -+ *time_ms = (tm.tm_sec & 1) * 100 + -+ ts->tv_nsec / (10 * NSEC_PER_MSEC); -+ -+ /* -+ * Record 00h value for OffsetFromUtc field and 1 value for OffsetValid -+ * to indicate that local time and UTC are the same. -+ */ -+ *tz = EXFAT_TZ_VALID; -+} -+ -+unsigned short exfat_calc_chksum_2byte(void *data, int len, -+ unsigned short chksum, int type) -+{ -+ int i; -+ unsigned char *c = (unsigned char *)data; -+ -+ for (i = 0; i < len; i++, c++) { -+ if (((i == 2) || (i == 3)) && (type == CS_DIR_ENTRY)) -+ continue; -+ chksum = (((chksum & 1) << 15) | ((chksum & 0xFFFE) >> 1)) + -+ (unsigned short)*c; -+ } -+ return chksum; -+} -+ -+void exfat_update_bh(struct super_block *sb, struct buffer_head *bh, int sync) -+{ -+ set_bit(EXFAT_SB_DIRTY, &EXFAT_SB(sb)->s_state); -+ set_buffer_uptodate(bh); -+ mark_buffer_dirty(bh); -+ -+ if (sync) -+ sync_dirty_buffer(bh); -+} -+ -+void exfat_chain_set(struct exfat_chain *ec, unsigned int dir, -+ unsigned int size, unsigned char flags) -+{ -+ ec->dir = dir; -+ ec->size = size; -+ ec->flags = flags; -+} -+ -+void exfat_chain_dup(struct exfat_chain *dup, struct exfat_chain *ec) -+{ -+ return exfat_chain_set(dup, ec->dir, ec->size, ec->flags); -+} --- -2.25.1 - diff --git a/kernel/tools/perf/files/patches/mageia/fs-exfat-add-module_alias_fs.patch b/kernel/tools/perf/files/patches/mageia/fs-exfat-add-module_alias_fs.patch deleted file mode 100644 index 6232c18b72..0000000000 --- a/kernel/tools/perf/files/patches/mageia/fs-exfat-add-module_alias_fs.patch +++ /dev/null @@ -1,30 +0,0 @@ -From c37f83b424911f9bb6c9f17a4543c9c77cd73282 Mon Sep 17 00:00:00 2001 -From: Thomas Backlund -Date: Sat, 4 Apr 2020 23:00:31 +0300 -Subject: [PATCH v2] exfat: add missing MODULE_ALIAS_FS() - -This adds the necessary MODULE_ALIAS_FS() to exfat so the module gets -automatically loaded when an exfat filesystem is mounted. - -Signed-off-by: Thomas Backlund -Cc: Namjae Jeon -Cc: Sungjong Seo ---- - fs/exfat/super.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/fs/exfat/super.c b/fs/exfat/super.c -index 16ed202ef527..b4a4063a0272 100644 ---- a/fs/exfat/super.c -+++ b/fs/exfat/super.c -@@ -717,6 +717,7 @@ static void __exit exit_exfat_fs(void) - module_init(init_exfat_fs); - module_exit(exit_exfat_fs); - -+MODULE_ALIAS_FS("exfat"); - MODULE_LICENSE("GPL"); - MODULE_DESCRIPTION("exFAT filesystem support"); - MODULE_AUTHOR("Samsung Electronics Co., Ltd."); --- -2.26.0 - diff --git a/kernel/tools/perf/files/patches/mageia/fs-exfat-add-nls-operations.patch b/kernel/tools/perf/files/patches/mageia/fs-exfat-add-nls-operations.patch deleted file mode 100644 index 5c5792d53e..0000000000 --- a/kernel/tools/perf/files/patches/mageia/fs-exfat-add-nls-operations.patch +++ /dev/null @@ -1,860 +0,0 @@ -From 370e812b3ec190fa492c9fd5a80c38b086d105c0 Mon Sep 17 00:00:00 2001 -From: Namjae Jeon -Date: Mon, 2 Mar 2020 15:21:41 +0900 -Subject: [PATCH 10/14] exfat: add nls operations -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This adds the implementation of nls operations for exfat. - -Signed-off-by: Namjae Jeon -Signed-off-by: Sungjong Seo -Reviewed-by: Pali Rohár -Reviewed-by: Christoph Hellwig -Signed-off-by: Al Viro ---- - fs/exfat/nls.c | 831 +++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 831 insertions(+) - create mode 100644 fs/exfat/nls.c - -diff --git a/fs/exfat/nls.c b/fs/exfat/nls.c -new file mode 100644 -index 000000000000..6d1c3ae130ff ---- /dev/null -+++ b/fs/exfat/nls.c -@@ -0,0 +1,831 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include "exfat_raw.h" -+#include "exfat_fs.h" -+ -+/* Upcase tabel macro */ -+#define EXFAT_NUM_UPCASE (2918) -+#define UTBL_COUNT (0x10000) -+ -+/* -+ * Upcase table in compressed format (7.2.5.1 Recommended Up-case Table -+ * in exfat specification, See: -+ * https://docs.microsoft.com/en-us/windows/win32/fileio/exfat-specification). -+ */ -+static const unsigned short uni_def_upcase[EXFAT_NUM_UPCASE] = { -+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, -+ 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, -+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, -+ 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, -+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, -+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, -+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, -+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, -+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, -+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, -+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, -+ 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, -+ 0x0060, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, -+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, -+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, -+ 0x0058, 0x0059, 0x005a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, -+ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, -+ 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, -+ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, -+ 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, -+ 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, -+ 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, -+ 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, -+ 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf, -+ 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, -+ 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, -+ 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, -+ 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df, -+ 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, -+ 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, -+ 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00f7, -+ 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x0178, -+ 0x0100, 0x0100, 0x0102, 0x0102, 0x0104, 0x0104, 0x0106, 0x0106, -+ 0x0108, 0x0108, 0x010a, 0x010a, 0x010c, 0x010c, 0x010e, 0x010e, -+ 0x0110, 0x0110, 0x0112, 0x0112, 0x0114, 0x0114, 0x0116, 0x0116, -+ 0x0118, 0x0118, 0x011a, 0x011a, 0x011c, 0x011c, 0x011e, 0x011e, -+ 0x0120, 0x0120, 0x0122, 0x0122, 0x0124, 0x0124, 0x0126, 0x0126, -+ 0x0128, 0x0128, 0x012a, 0x012a, 0x012c, 0x012c, 0x012e, 0x012e, -+ 0x0130, 0x0131, 0x0132, 0x0132, 0x0134, 0x0134, 0x0136, 0x0136, -+ 0x0138, 0x0139, 0x0139, 0x013b, 0x013b, 0x013d, 0x013d, 0x013f, -+ 0x013f, 0x0141, 0x0141, 0x0143, 0x0143, 0x0145, 0x0145, 0x0147, -+ 0x0147, 0x0149, 0x014a, 0x014a, 0x014c, 0x014c, 0x014e, 0x014e, -+ 0x0150, 0x0150, 0x0152, 0x0152, 0x0154, 0x0154, 0x0156, 0x0156, -+ 0x0158, 0x0158, 0x015a, 0x015a, 0x015c, 0x015c, 0x015e, 0x015e, -+ 0x0160, 0x0160, 0x0162, 0x0162, 0x0164, 0x0164, 0x0166, 0x0166, -+ 0x0168, 0x0168, 0x016a, 0x016a, 0x016c, 0x016c, 0x016e, 0x016e, -+ 0x0170, 0x0170, 0x0172, 0x0172, 0x0174, 0x0174, 0x0176, 0x0176, -+ 0x0178, 0x0179, 0x0179, 0x017b, 0x017b, 0x017d, 0x017d, 0x017f, -+ 0x0243, 0x0181, 0x0182, 0x0182, 0x0184, 0x0184, 0x0186, 0x0187, -+ 0x0187, 0x0189, 0x018a, 0x018b, 0x018b, 0x018d, 0x018e, 0x018f, -+ 0x0190, 0x0191, 0x0191, 0x0193, 0x0194, 0x01f6, 0x0196, 0x0197, -+ 0x0198, 0x0198, 0x023d, 0x019b, 0x019c, 0x019d, 0x0220, 0x019f, -+ 0x01a0, 0x01a0, 0x01a2, 0x01a2, 0x01a4, 0x01a4, 0x01a6, 0x01a7, -+ 0x01a7, 0x01a9, 0x01aa, 0x01ab, 0x01ac, 0x01ac, 0x01ae, 0x01af, -+ 0x01af, 0x01b1, 0x01b2, 0x01b3, 0x01b3, 0x01b5, 0x01b5, 0x01b7, -+ 0x01b8, 0x01b8, 0x01ba, 0x01bb, 0x01bc, 0x01bc, 0x01be, 0x01f7, -+ 0x01c0, 0x01c1, 0x01c2, 0x01c3, 0x01c4, 0x01c5, 0x01c4, 0x01c7, -+ 0x01c8, 0x01c7, 0x01ca, 0x01cb, 0x01ca, 0x01cd, 0x01cd, 0x01cf, -+ 0x01cf, 0x01d1, 0x01d1, 0x01d3, 0x01d3, 0x01d5, 0x01d5, 0x01d7, -+ 0x01d7, 0x01d9, 0x01d9, 0x01db, 0x01db, 0x018e, 0x01de, 0x01de, -+ 0x01e0, 0x01e0, 0x01e2, 0x01e2, 0x01e4, 0x01e4, 0x01e6, 0x01e6, -+ 0x01e8, 0x01e8, 0x01ea, 0x01ea, 0x01ec, 0x01ec, 0x01ee, 0x01ee, -+ 0x01f0, 0x01f1, 0x01f2, 0x01f1, 0x01f4, 0x01f4, 0x01f6, 0x01f7, -+ 0x01f8, 0x01f8, 0x01fa, 0x01fa, 0x01fc, 0x01fc, 0x01fe, 0x01fe, -+ 0x0200, 0x0200, 0x0202, 0x0202, 0x0204, 0x0204, 0x0206, 0x0206, -+ 0x0208, 0x0208, 0x020a, 0x020a, 0x020c, 0x020c, 0x020e, 0x020e, -+ 0x0210, 0x0210, 0x0212, 0x0212, 0x0214, 0x0214, 0x0216, 0x0216, -+ 0x0218, 0x0218, 0x021a, 0x021a, 0x021c, 0x021c, 0x021e, 0x021e, -+ 0x0220, 0x0221, 0x0222, 0x0222, 0x0224, 0x0224, 0x0226, 0x0226, -+ 0x0228, 0x0228, 0x022a, 0x022a, 0x022c, 0x022c, 0x022e, 0x022e, -+ 0x0230, 0x0230, 0x0232, 0x0232, 0x0234, 0x0235, 0x0236, 0x0237, -+ 0x0238, 0x0239, 0x2c65, 0x023b, 0x023b, 0x023d, 0x2c66, 0x023f, -+ 0x0240, 0x0241, 0x0241, 0x0243, 0x0244, 0x0245, 0x0246, 0x0246, -+ 0x0248, 0x0248, 0x024a, 0x024a, 0x024c, 0x024c, 0x024e, 0x024e, -+ 0x0250, 0x0251, 0x0252, 0x0181, 0x0186, 0x0255, 0x0189, 0x018a, -+ 0x0258, 0x018f, 0x025a, 0x0190, 0x025c, 0x025d, 0x025e, 0x025f, -+ 0x0193, 0x0261, 0x0262, 0x0194, 0x0264, 0x0265, 0x0266, 0x0267, -+ 0x0197, 0x0196, 0x026a, 0x2c62, 0x026c, 0x026d, 0x026e, 0x019c, -+ 0x0270, 0x0271, 0x019d, 0x0273, 0x0274, 0x019f, 0x0276, 0x0277, -+ 0x0278, 0x0279, 0x027a, 0x027b, 0x027c, 0x2c64, 0x027e, 0x027f, -+ 0x01a6, 0x0281, 0x0282, 0x01a9, 0x0284, 0x0285, 0x0286, 0x0287, -+ 0x01ae, 0x0244, 0x01b1, 0x01b2, 0x0245, 0x028d, 0x028e, 0x028f, -+ 0x0290, 0x0291, 0x01b7, 0x0293, 0x0294, 0x0295, 0x0296, 0x0297, -+ 0x0298, 0x0299, 0x029a, 0x029b, 0x029c, 0x029d, 0x029e, 0x029f, -+ 0x02a0, 0x02a1, 0x02a2, 0x02a3, 0x02a4, 0x02a5, 0x02a6, 0x02a7, -+ 0x02a8, 0x02a9, 0x02aa, 0x02ab, 0x02ac, 0x02ad, 0x02ae, 0x02af, -+ 0x02b0, 0x02b1, 0x02b2, 0x02b3, 0x02b4, 0x02b5, 0x02b6, 0x02b7, -+ 0x02b8, 0x02b9, 0x02ba, 0x02bb, 0x02bc, 0x02bd, 0x02be, 0x02bf, -+ 0x02c0, 0x02c1, 0x02c2, 0x02c3, 0x02c4, 0x02c5, 0x02c6, 0x02c7, -+ 0x02c8, 0x02c9, 0x02ca, 0x02cb, 0x02cc, 0x02cd, 0x02ce, 0x02cf, -+ 0x02d0, 0x02d1, 0x02d2, 0x02d3, 0x02d4, 0x02d5, 0x02d6, 0x02d7, -+ 0x02d8, 0x02d9, 0x02da, 0x02db, 0x02dc, 0x02dd, 0x02de, 0x02df, -+ 0x02e0, 0x02e1, 0x02e2, 0x02e3, 0x02e4, 0x02e5, 0x02e6, 0x02e7, -+ 0x02e8, 0x02e9, 0x02ea, 0x02eb, 0x02ec, 0x02ed, 0x02ee, 0x02ef, -+ 0x02f0, 0x02f1, 0x02f2, 0x02f3, 0x02f4, 0x02f5, 0x02f6, 0x02f7, -+ 0x02f8, 0x02f9, 0x02fa, 0x02fb, 0x02fc, 0x02fd, 0x02fe, 0x02ff, -+ 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307, -+ 0x0308, 0x0309, 0x030a, 0x030b, 0x030c, 0x030d, 0x030e, 0x030f, -+ 0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317, -+ 0x0318, 0x0319, 0x031a, 0x031b, 0x031c, 0x031d, 0x031e, 0x031f, -+ 0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0325, 0x0326, 0x0327, -+ 0x0328, 0x0329, 0x032a, 0x032b, 0x032c, 0x032d, 0x032e, 0x032f, -+ 0x0330, 0x0331, 0x0332, 0x0333, 0x0334, 0x0335, 0x0336, 0x0337, -+ 0x0338, 0x0339, 0x033a, 0x033b, 0x033c, 0x033d, 0x033e, 0x033f, -+ 0x0340, 0x0341, 0x0342, 0x0343, 0x0344, 0x0345, 0x0346, 0x0347, -+ 0x0348, 0x0349, 0x034a, 0x034b, 0x034c, 0x034d, 0x034e, 0x034f, -+ 0x0350, 0x0351, 0x0352, 0x0353, 0x0354, 0x0355, 0x0356, 0x0357, -+ 0x0358, 0x0359, 0x035a, 0x035b, 0x035c, 0x035d, 0x035e, 0x035f, -+ 0x0360, 0x0361, 0x0362, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367, -+ 0x0368, 0x0369, 0x036a, 0x036b, 0x036c, 0x036d, 0x036e, 0x036f, -+ 0x0370, 0x0371, 0x0372, 0x0373, 0x0374, 0x0375, 0x0376, 0x0377, -+ 0x0378, 0x0379, 0x037a, 0x03fd, 0x03fe, 0x03ff, 0x037e, 0x037f, -+ 0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x0386, 0x0387, -+ 0x0388, 0x0389, 0x038a, 0x038b, 0x038c, 0x038d, 0x038e, 0x038f, -+ 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, -+ 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f, -+ 0x03a0, 0x03a1, 0x03a2, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7, -+ 0x03a8, 0x03a9, 0x03aa, 0x03ab, 0x0386, 0x0388, 0x0389, 0x038a, -+ 0x03b0, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, -+ 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f, -+ 0x03a0, 0x03a1, 0x03a3, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7, -+ 0x03a8, 0x03a9, 0x03aa, 0x03ab, 0x038c, 0x038e, 0x038f, 0x03cf, -+ 0x03d0, 0x03d1, 0x03d2, 0x03d3, 0x03d4, 0x03d5, 0x03d6, 0x03d7, -+ 0x03d8, 0x03d8, 0x03da, 0x03da, 0x03dc, 0x03dc, 0x03de, 0x03de, -+ 0x03e0, 0x03e0, 0x03e2, 0x03e2, 0x03e4, 0x03e4, 0x03e6, 0x03e6, -+ 0x03e8, 0x03e8, 0x03ea, 0x03ea, 0x03ec, 0x03ec, 0x03ee, 0x03ee, -+ 0x03f0, 0x03f1, 0x03f9, 0x03f3, 0x03f4, 0x03f5, 0x03f6, 0x03f7, -+ 0x03f7, 0x03f9, 0x03fa, 0x03fa, 0x03fc, 0x03fd, 0x03fe, 0x03ff, -+ 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, -+ 0x0408, 0x0409, 0x040a, 0x040b, 0x040c, 0x040d, 0x040e, 0x040f, -+ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, -+ 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f, -+ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, -+ 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, -+ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, -+ 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f, -+ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, -+ 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, -+ 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, -+ 0x0408, 0x0409, 0x040a, 0x040b, 0x040c, 0x040d, 0x040e, 0x040f, -+ 0x0460, 0x0460, 0x0462, 0x0462, 0x0464, 0x0464, 0x0466, 0x0466, -+ 0x0468, 0x0468, 0x046a, 0x046a, 0x046c, 0x046c, 0x046e, 0x046e, -+ 0x0470, 0x0470, 0x0472, 0x0472, 0x0474, 0x0474, 0x0476, 0x0476, -+ 0x0478, 0x0478, 0x047a, 0x047a, 0x047c, 0x047c, 0x047e, 0x047e, -+ 0x0480, 0x0480, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, -+ 0x0488, 0x0489, 0x048a, 0x048a, 0x048c, 0x048c, 0x048e, 0x048e, -+ 0x0490, 0x0490, 0x0492, 0x0492, 0x0494, 0x0494, 0x0496, 0x0496, -+ 0x0498, 0x0498, 0x049a, 0x049a, 0x049c, 0x049c, 0x049e, 0x049e, -+ 0x04a0, 0x04a0, 0x04a2, 0x04a2, 0x04a4, 0x04a4, 0x04a6, 0x04a6, -+ 0x04a8, 0x04a8, 0x04aa, 0x04aa, 0x04ac, 0x04ac, 0x04ae, 0x04ae, -+ 0x04b0, 0x04b0, 0x04b2, 0x04b2, 0x04b4, 0x04b4, 0x04b6, 0x04b6, -+ 0x04b8, 0x04b8, 0x04ba, 0x04ba, 0x04bc, 0x04bc, 0x04be, 0x04be, -+ 0x04c0, 0x04c1, 0x04c1, 0x04c3, 0x04c3, 0x04c5, 0x04c5, 0x04c7, -+ 0x04c7, 0x04c9, 0x04c9, 0x04cb, 0x04cb, 0x04cd, 0x04cd, 0x04c0, -+ 0x04d0, 0x04d0, 0x04d2, 0x04d2, 0x04d4, 0x04d4, 0x04d6, 0x04d6, -+ 0x04d8, 0x04d8, 0x04da, 0x04da, 0x04dc, 0x04dc, 0x04de, 0x04de, -+ 0x04e0, 0x04e0, 0x04e2, 0x04e2, 0x04e4, 0x04e4, 0x04e6, 0x04e6, -+ 0x04e8, 0x04e8, 0x04ea, 0x04ea, 0x04ec, 0x04ec, 0x04ee, 0x04ee, -+ 0x04f0, 0x04f0, 0x04f2, 0x04f2, 0x04f4, 0x04f4, 0x04f6, 0x04f6, -+ 0x04f8, 0x04f8, 0x04fa, 0x04fa, 0x04fc, 0x04fc, 0x04fe, 0x04fe, -+ 0x0500, 0x0500, 0x0502, 0x0502, 0x0504, 0x0504, 0x0506, 0x0506, -+ 0x0508, 0x0508, 0x050a, 0x050a, 0x050c, 0x050c, 0x050e, 0x050e, -+ 0x0510, 0x0510, 0x0512, 0x0512, 0x0514, 0x0515, 0x0516, 0x0517, -+ 0x0518, 0x0519, 0x051a, 0x051b, 0x051c, 0x051d, 0x051e, 0x051f, -+ 0x0520, 0x0521, 0x0522, 0x0523, 0x0524, 0x0525, 0x0526, 0x0527, -+ 0x0528, 0x0529, 0x052a, 0x052b, 0x052c, 0x052d, 0x052e, 0x052f, -+ 0x0530, 0x0531, 0x0532, 0x0533, 0x0534, 0x0535, 0x0536, 0x0537, -+ 0x0538, 0x0539, 0x053a, 0x053b, 0x053c, 0x053d, 0x053e, 0x053f, -+ 0x0540, 0x0541, 0x0542, 0x0543, 0x0544, 0x0545, 0x0546, 0x0547, -+ 0x0548, 0x0549, 0x054a, 0x054b, 0x054c, 0x054d, 0x054e, 0x054f, -+ 0x0550, 0x0551, 0x0552, 0x0553, 0x0554, 0x0555, 0x0556, 0x0557, -+ 0x0558, 0x0559, 0x055a, 0x055b, 0x055c, 0x055d, 0x055e, 0x055f, -+ 0x0560, 0x0531, 0x0532, 0x0533, 0x0534, 0x0535, 0x0536, 0x0537, -+ 0x0538, 0x0539, 0x053a, 0x053b, 0x053c, 0x053d, 0x053e, 0x053f, -+ 0x0540, 0x0541, 0x0542, 0x0543, 0x0544, 0x0545, 0x0546, 0x0547, -+ 0x0548, 0x0549, 0x054a, 0x054b, 0x054c, 0x054d, 0x054e, 0x054f, -+ 0x0550, 0x0551, 0x0552, 0x0553, 0x0554, 0x0555, 0x0556, 0xffff, -+ 0x17f6, 0x2c63, 0x1d7e, 0x1d7f, 0x1d80, 0x1d81, 0x1d82, 0x1d83, -+ 0x1d84, 0x1d85, 0x1d86, 0x1d87, 0x1d88, 0x1d89, 0x1d8a, 0x1d8b, -+ 0x1d8c, 0x1d8d, 0x1d8e, 0x1d8f, 0x1d90, 0x1d91, 0x1d92, 0x1d93, -+ 0x1d94, 0x1d95, 0x1d96, 0x1d97, 0x1d98, 0x1d99, 0x1d9a, 0x1d9b, -+ 0x1d9c, 0x1d9d, 0x1d9e, 0x1d9f, 0x1da0, 0x1da1, 0x1da2, 0x1da3, -+ 0x1da4, 0x1da5, 0x1da6, 0x1da7, 0x1da8, 0x1da9, 0x1daa, 0x1dab, -+ 0x1dac, 0x1dad, 0x1dae, 0x1daf, 0x1db0, 0x1db1, 0x1db2, 0x1db3, -+ 0x1db4, 0x1db5, 0x1db6, 0x1db7, 0x1db8, 0x1db9, 0x1dba, 0x1dbb, -+ 0x1dbc, 0x1dbd, 0x1dbe, 0x1dbf, 0x1dc0, 0x1dc1, 0x1dc2, 0x1dc3, -+ 0x1dc4, 0x1dc5, 0x1dc6, 0x1dc7, 0x1dc8, 0x1dc9, 0x1dca, 0x1dcb, -+ 0x1dcc, 0x1dcd, 0x1dce, 0x1dcf, 0x1dd0, 0x1dd1, 0x1dd2, 0x1dd3, -+ 0x1dd4, 0x1dd5, 0x1dd6, 0x1dd7, 0x1dd8, 0x1dd9, 0x1dda, 0x1ddb, -+ 0x1ddc, 0x1ddd, 0x1dde, 0x1ddf, 0x1de0, 0x1de1, 0x1de2, 0x1de3, -+ 0x1de4, 0x1de5, 0x1de6, 0x1de7, 0x1de8, 0x1de9, 0x1dea, 0x1deb, -+ 0x1dec, 0x1ded, 0x1dee, 0x1def, 0x1df0, 0x1df1, 0x1df2, 0x1df3, -+ 0x1df4, 0x1df5, 0x1df6, 0x1df7, 0x1df8, 0x1df9, 0x1dfa, 0x1dfb, -+ 0x1dfc, 0x1dfd, 0x1dfe, 0x1dff, 0x1e00, 0x1e00, 0x1e02, 0x1e02, -+ 0x1e04, 0x1e04, 0x1e06, 0x1e06, 0x1e08, 0x1e08, 0x1e0a, 0x1e0a, -+ 0x1e0c, 0x1e0c, 0x1e0e, 0x1e0e, 0x1e10, 0x1e10, 0x1e12, 0x1e12, -+ 0x1e14, 0x1e14, 0x1e16, 0x1e16, 0x1e18, 0x1e18, 0x1e1a, 0x1e1a, -+ 0x1e1c, 0x1e1c, 0x1e1e, 0x1e1e, 0x1e20, 0x1e20, 0x1e22, 0x1e22, -+ 0x1e24, 0x1e24, 0x1e26, 0x1e26, 0x1e28, 0x1e28, 0x1e2a, 0x1e2a, -+ 0x1e2c, 0x1e2c, 0x1e2e, 0x1e2e, 0x1e30, 0x1e30, 0x1e32, 0x1e32, -+ 0x1e34, 0x1e34, 0x1e36, 0x1e36, 0x1e38, 0x1e38, 0x1e3a, 0x1e3a, -+ 0x1e3c, 0x1e3c, 0x1e3e, 0x1e3e, 0x1e40, 0x1e40, 0x1e42, 0x1e42, -+ 0x1e44, 0x1e44, 0x1e46, 0x1e46, 0x1e48, 0x1e48, 0x1e4a, 0x1e4a, -+ 0x1e4c, 0x1e4c, 0x1e4e, 0x1e4e, 0x1e50, 0x1e50, 0x1e52, 0x1e52, -+ 0x1e54, 0x1e54, 0x1e56, 0x1e56, 0x1e58, 0x1e58, 0x1e5a, 0x1e5a, -+ 0x1e5c, 0x1e5c, 0x1e5e, 0x1e5e, 0x1e60, 0x1e60, 0x1e62, 0x1e62, -+ 0x1e64, 0x1e64, 0x1e66, 0x1e66, 0x1e68, 0x1e68, 0x1e6a, 0x1e6a, -+ 0x1e6c, 0x1e6c, 0x1e6e, 0x1e6e, 0x1e70, 0x1e70, 0x1e72, 0x1e72, -+ 0x1e74, 0x1e74, 0x1e76, 0x1e76, 0x1e78, 0x1e78, 0x1e7a, 0x1e7a, -+ 0x1e7c, 0x1e7c, 0x1e7e, 0x1e7e, 0x1e80, 0x1e80, 0x1e82, 0x1e82, -+ 0x1e84, 0x1e84, 0x1e86, 0x1e86, 0x1e88, 0x1e88, 0x1e8a, 0x1e8a, -+ 0x1e8c, 0x1e8c, 0x1e8e, 0x1e8e, 0x1e90, 0x1e90, 0x1e92, 0x1e92, -+ 0x1e94, 0x1e94, 0x1e96, 0x1e97, 0x1e98, 0x1e99, 0x1e9a, 0x1e9b, -+ 0x1e9c, 0x1e9d, 0x1e9e, 0x1e9f, 0x1ea0, 0x1ea0, 0x1ea2, 0x1ea2, -+ 0x1ea4, 0x1ea4, 0x1ea6, 0x1ea6, 0x1ea8, 0x1ea8, 0x1eaa, 0x1eaa, -+ 0x1eac, 0x1eac, 0x1eae, 0x1eae, 0x1eb0, 0x1eb0, 0x1eb2, 0x1eb2, -+ 0x1eb4, 0x1eb4, 0x1eb6, 0x1eb6, 0x1eb8, 0x1eb8, 0x1eba, 0x1eba, -+ 0x1ebc, 0x1ebc, 0x1ebe, 0x1ebe, 0x1ec0, 0x1ec0, 0x1ec2, 0x1ec2, -+ 0x1ec4, 0x1ec4, 0x1ec6, 0x1ec6, 0x1ec8, 0x1ec8, 0x1eca, 0x1eca, -+ 0x1ecc, 0x1ecc, 0x1ece, 0x1ece, 0x1ed0, 0x1ed0, 0x1ed2, 0x1ed2, -+ 0x1ed4, 0x1ed4, 0x1ed6, 0x1ed6, 0x1ed8, 0x1ed8, 0x1eda, 0x1eda, -+ 0x1edc, 0x1edc, 0x1ede, 0x1ede, 0x1ee0, 0x1ee0, 0x1ee2, 0x1ee2, -+ 0x1ee4, 0x1ee4, 0x1ee6, 0x1ee6, 0x1ee8, 0x1ee8, 0x1eea, 0x1eea, -+ 0x1eec, 0x1eec, 0x1eee, 0x1eee, 0x1ef0, 0x1ef0, 0x1ef2, 0x1ef2, -+ 0x1ef4, 0x1ef4, 0x1ef6, 0x1ef6, 0x1ef8, 0x1ef8, 0x1efa, 0x1efb, -+ 0x1efc, 0x1efd, 0x1efe, 0x1eff, 0x1f08, 0x1f09, 0x1f0a, 0x1f0b, -+ 0x1f0c, 0x1f0d, 0x1f0e, 0x1f0f, 0x1f08, 0x1f09, 0x1f0a, 0x1f0b, -+ 0x1f0c, 0x1f0d, 0x1f0e, 0x1f0f, 0x1f18, 0x1f19, 0x1f1a, 0x1f1b, -+ 0x1f1c, 0x1f1d, 0x1f16, 0x1f17, 0x1f18, 0x1f19, 0x1f1a, 0x1f1b, -+ 0x1f1c, 0x1f1d, 0x1f1e, 0x1f1f, 0x1f28, 0x1f29, 0x1f2a, 0x1f2b, -+ 0x1f2c, 0x1f2d, 0x1f2e, 0x1f2f, 0x1f28, 0x1f29, 0x1f2a, 0x1f2b, -+ 0x1f2c, 0x1f2d, 0x1f2e, 0x1f2f, 0x1f38, 0x1f39, 0x1f3a, 0x1f3b, -+ 0x1f3c, 0x1f3d, 0x1f3e, 0x1f3f, 0x1f38, 0x1f39, 0x1f3a, 0x1f3b, -+ 0x1f3c, 0x1f3d, 0x1f3e, 0x1f3f, 0x1f48, 0x1f49, 0x1f4a, 0x1f4b, -+ 0x1f4c, 0x1f4d, 0x1f46, 0x1f47, 0x1f48, 0x1f49, 0x1f4a, 0x1f4b, -+ 0x1f4c, 0x1f4d, 0x1f4e, 0x1f4f, 0x1f50, 0x1f59, 0x1f52, 0x1f5b, -+ 0x1f54, 0x1f5d, 0x1f56, 0x1f5f, 0x1f58, 0x1f59, 0x1f5a, 0x1f5b, -+ 0x1f5c, 0x1f5d, 0x1f5e, 0x1f5f, 0x1f68, 0x1f69, 0x1f6a, 0x1f6b, -+ 0x1f6c, 0x1f6d, 0x1f6e, 0x1f6f, 0x1f68, 0x1f69, 0x1f6a, 0x1f6b, -+ 0x1f6c, 0x1f6d, 0x1f6e, 0x1f6f, 0x1fba, 0x1fbb, 0x1fc8, 0x1fc9, -+ 0x1fca, 0x1fcb, 0x1fda, 0x1fdb, 0x1ff8, 0x1ff9, 0x1fea, 0x1feb, -+ 0x1ffa, 0x1ffb, 0x1f7e, 0x1f7f, 0x1f88, 0x1f89, 0x1f8a, 0x1f8b, -+ 0x1f8c, 0x1f8d, 0x1f8e, 0x1f8f, 0x1f88, 0x1f89, 0x1f8a, 0x1f8b, -+ 0x1f8c, 0x1f8d, 0x1f8e, 0x1f8f, 0x1f98, 0x1f99, 0x1f9a, 0x1f9b, -+ 0x1f9c, 0x1f9d, 0x1f9e, 0x1f9f, 0x1f98, 0x1f99, 0x1f9a, 0x1f9b, -+ 0x1f9c, 0x1f9d, 0x1f9e, 0x1f9f, 0x1fa8, 0x1fa9, 0x1faa, 0x1fab, -+ 0x1fac, 0x1fad, 0x1fae, 0x1faf, 0x1fa8, 0x1fa9, 0x1faa, 0x1fab, -+ 0x1fac, 0x1fad, 0x1fae, 0x1faf, 0x1fb8, 0x1fb9, 0x1fb2, 0x1fbc, -+ 0x1fb4, 0x1fb5, 0x1fb6, 0x1fb7, 0x1fb8, 0x1fb9, 0x1fba, 0x1fbb, -+ 0x1fbc, 0x1fbd, 0x1fbe, 0x1fbf, 0x1fc0, 0x1fc1, 0x1fc2, 0x1fc3, -+ 0x1fc4, 0x1fc5, 0x1fc6, 0x1fc7, 0x1fc8, 0x1fc9, 0x1fca, 0x1fcb, -+ 0x1fc3, 0x1fcd, 0x1fce, 0x1fcf, 0x1fd8, 0x1fd9, 0x1fd2, 0x1fd3, -+ 0x1fd4, 0x1fd5, 0x1fd6, 0x1fd7, 0x1fd8, 0x1fd9, 0x1fda, 0x1fdb, -+ 0x1fdc, 0x1fdd, 0x1fde, 0x1fdf, 0x1fe8, 0x1fe9, 0x1fe2, 0x1fe3, -+ 0x1fe4, 0x1fec, 0x1fe6, 0x1fe7, 0x1fe8, 0x1fe9, 0x1fea, 0x1feb, -+ 0x1fec, 0x1fed, 0x1fee, 0x1fef, 0x1ff0, 0x1ff1, 0x1ff2, 0x1ff3, -+ 0x1ff4, 0x1ff5, 0x1ff6, 0x1ff7, 0x1ff8, 0x1ff9, 0x1ffa, 0x1ffb, -+ 0x1ff3, 0x1ffd, 0x1ffe, 0x1fff, 0x2000, 0x2001, 0x2002, 0x2003, -+ 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200a, 0x200b, -+ 0x200c, 0x200d, 0x200e, 0x200f, 0x2010, 0x2011, 0x2012, 0x2013, -+ 0x2014, 0x2015, 0x2016, 0x2017, 0x2018, 0x2019, 0x201a, 0x201b, -+ 0x201c, 0x201d, 0x201e, 0x201f, 0x2020, 0x2021, 0x2022, 0x2023, -+ 0x2024, 0x2025, 0x2026, 0x2027, 0x2028, 0x2029, 0x202a, 0x202b, -+ 0x202c, 0x202d, 0x202e, 0x202f, 0x2030, 0x2031, 0x2032, 0x2033, -+ 0x2034, 0x2035, 0x2036, 0x2037, 0x2038, 0x2039, 0x203a, 0x203b, -+ 0x203c, 0x203d, 0x203e, 0x203f, 0x2040, 0x2041, 0x2042, 0x2043, -+ 0x2044, 0x2045, 0x2046, 0x2047, 0x2048, 0x2049, 0x204a, 0x204b, -+ 0x204c, 0x204d, 0x204e, 0x204f, 0x2050, 0x2051, 0x2052, 0x2053, -+ 0x2054, 0x2055, 0x2056, 0x2057, 0x2058, 0x2059, 0x205a, 0x205b, -+ 0x205c, 0x205d, 0x205e, 0x205f, 0x2060, 0x2061, 0x2062, 0x2063, -+ 0x2064, 0x2065, 0x2066, 0x2067, 0x2068, 0x2069, 0x206a, 0x206b, -+ 0x206c, 0x206d, 0x206e, 0x206f, 0x2070, 0x2071, 0x2072, 0x2073, -+ 0x2074, 0x2075, 0x2076, 0x2077, 0x2078, 0x2079, 0x207a, 0x207b, -+ 0x207c, 0x207d, 0x207e, 0x207f, 0x2080, 0x2081, 0x2082, 0x2083, -+ 0x2084, 0x2085, 0x2086, 0x2087, 0x2088, 0x2089, 0x208a, 0x208b, -+ 0x208c, 0x208d, 0x208e, 0x208f, 0x2090, 0x2091, 0x2092, 0x2093, -+ 0x2094, 0x2095, 0x2096, 0x2097, 0x2098, 0x2099, 0x209a, 0x209b, -+ 0x209c, 0x209d, 0x209e, 0x209f, 0x20a0, 0x20a1, 0x20a2, 0x20a3, -+ 0x20a4, 0x20a5, 0x20a6, 0x20a7, 0x20a8, 0x20a9, 0x20aa, 0x20ab, -+ 0x20ac, 0x20ad, 0x20ae, 0x20af, 0x20b0, 0x20b1, 0x20b2, 0x20b3, -+ 0x20b4, 0x20b5, 0x20b6, 0x20b7, 0x20b8, 0x20b9, 0x20ba, 0x20bb, -+ 0x20bc, 0x20bd, 0x20be, 0x20bf, 0x20c0, 0x20c1, 0x20c2, 0x20c3, -+ 0x20c4, 0x20c5, 0x20c6, 0x20c7, 0x20c8, 0x20c9, 0x20ca, 0x20cb, -+ 0x20cc, 0x20cd, 0x20ce, 0x20cf, 0x20d0, 0x20d1, 0x20d2, 0x20d3, -+ 0x20d4, 0x20d5, 0x20d6, 0x20d7, 0x20d8, 0x20d9, 0x20da, 0x20db, -+ 0x20dc, 0x20dd, 0x20de, 0x20df, 0x20e0, 0x20e1, 0x20e2, 0x20e3, -+ 0x20e4, 0x20e5, 0x20e6, 0x20e7, 0x20e8, 0x20e9, 0x20ea, 0x20eb, -+ 0x20ec, 0x20ed, 0x20ee, 0x20ef, 0x20f0, 0x20f1, 0x20f2, 0x20f3, -+ 0x20f4, 0x20f5, 0x20f6, 0x20f7, 0x20f8, 0x20f9, 0x20fa, 0x20fb, -+ 0x20fc, 0x20fd, 0x20fe, 0x20ff, 0x2100, 0x2101, 0x2102, 0x2103, -+ 0x2104, 0x2105, 0x2106, 0x2107, 0x2108, 0x2109, 0x210a, 0x210b, -+ 0x210c, 0x210d, 0x210e, 0x210f, 0x2110, 0x2111, 0x2112, 0x2113, -+ 0x2114, 0x2115, 0x2116, 0x2117, 0x2118, 0x2119, 0x211a, 0x211b, -+ 0x211c, 0x211d, 0x211e, 0x211f, 0x2120, 0x2121, 0x2122, 0x2123, -+ 0x2124, 0x2125, 0x2126, 0x2127, 0x2128, 0x2129, 0x212a, 0x212b, -+ 0x212c, 0x212d, 0x212e, 0x212f, 0x2130, 0x2131, 0x2132, 0x2133, -+ 0x2134, 0x2135, 0x2136, 0x2137, 0x2138, 0x2139, 0x213a, 0x213b, -+ 0x213c, 0x213d, 0x213e, 0x213f, 0x2140, 0x2141, 0x2142, 0x2143, -+ 0x2144, 0x2145, 0x2146, 0x2147, 0x2148, 0x2149, 0x214a, 0x214b, -+ 0x214c, 0x214d, 0x2132, 0x214f, 0x2150, 0x2151, 0x2152, 0x2153, -+ 0x2154, 0x2155, 0x2156, 0x2157, 0x2158, 0x2159, 0x215a, 0x215b, -+ 0x215c, 0x215d, 0x215e, 0x215f, 0x2160, 0x2161, 0x2162, 0x2163, -+ 0x2164, 0x2165, 0x2166, 0x2167, 0x2168, 0x2169, 0x216a, 0x216b, -+ 0x216c, 0x216d, 0x216e, 0x216f, 0x2160, 0x2161, 0x2162, 0x2163, -+ 0x2164, 0x2165, 0x2166, 0x2167, 0x2168, 0x2169, 0x216a, 0x216b, -+ 0x216c, 0x216d, 0x216e, 0x216f, 0x2180, 0x2181, 0x2182, 0x2183, -+ 0x2183, 0xffff, 0x034b, 0x24b6, 0x24b7, 0x24b8, 0x24b9, 0x24ba, -+ 0x24bb, 0x24bc, 0x24bd, 0x24be, 0x24bf, 0x24c0, 0x24c1, 0x24c2, -+ 0x24c3, 0x24c4, 0x24c5, 0x24c6, 0x24c7, 0x24c8, 0x24c9, 0x24ca, -+ 0x24cb, 0x24cc, 0x24cd, 0x24ce, 0x24cf, 0xffff, 0x0746, 0x2c00, -+ 0x2c01, 0x2c02, 0x2c03, 0x2c04, 0x2c05, 0x2c06, 0x2c07, 0x2c08, -+ 0x2c09, 0x2c0a, 0x2c0b, 0x2c0c, 0x2c0d, 0x2c0e, 0x2c0f, 0x2c10, -+ 0x2c11, 0x2c12, 0x2c13, 0x2c14, 0x2c15, 0x2c16, 0x2c17, 0x2c18, -+ 0x2c19, 0x2c1a, 0x2c1b, 0x2c1c, 0x2c1d, 0x2c1e, 0x2c1f, 0x2c20, -+ 0x2c21, 0x2c22, 0x2c23, 0x2c24, 0x2c25, 0x2c26, 0x2c27, 0x2c28, -+ 0x2c29, 0x2c2a, 0x2c2b, 0x2c2c, 0x2c2d, 0x2c2e, 0x2c5f, 0x2c60, -+ 0x2c60, 0x2c62, 0x2c63, 0x2c64, 0x2c65, 0x2c66, 0x2c67, 0x2c67, -+ 0x2c69, 0x2c69, 0x2c6b, 0x2c6b, 0x2c6d, 0x2c6e, 0x2c6f, 0x2c70, -+ 0x2c71, 0x2c72, 0x2c73, 0x2c74, 0x2c75, 0x2c75, 0x2c77, 0x2c78, -+ 0x2c79, 0x2c7a, 0x2c7b, 0x2c7c, 0x2c7d, 0x2c7e, 0x2c7f, 0x2c80, -+ 0x2c80, 0x2c82, 0x2c82, 0x2c84, 0x2c84, 0x2c86, 0x2c86, 0x2c88, -+ 0x2c88, 0x2c8a, 0x2c8a, 0x2c8c, 0x2c8c, 0x2c8e, 0x2c8e, 0x2c90, -+ 0x2c90, 0x2c92, 0x2c92, 0x2c94, 0x2c94, 0x2c96, 0x2c96, 0x2c98, -+ 0x2c98, 0x2c9a, 0x2c9a, 0x2c9c, 0x2c9c, 0x2c9e, 0x2c9e, 0x2ca0, -+ 0x2ca0, 0x2ca2, 0x2ca2, 0x2ca4, 0x2ca4, 0x2ca6, 0x2ca6, 0x2ca8, -+ 0x2ca8, 0x2caa, 0x2caa, 0x2cac, 0x2cac, 0x2cae, 0x2cae, 0x2cb0, -+ 0x2cb0, 0x2cb2, 0x2cb2, 0x2cb4, 0x2cb4, 0x2cb6, 0x2cb6, 0x2cb8, -+ 0x2cb8, 0x2cba, 0x2cba, 0x2cbc, 0x2cbc, 0x2cbe, 0x2cbe, 0x2cc0, -+ 0x2cc0, 0x2cc2, 0x2cc2, 0x2cc4, 0x2cc4, 0x2cc6, 0x2cc6, 0x2cc8, -+ 0x2cc8, 0x2cca, 0x2cca, 0x2ccc, 0x2ccc, 0x2cce, 0x2cce, 0x2cd0, -+ 0x2cd0, 0x2cd2, 0x2cd2, 0x2cd4, 0x2cd4, 0x2cd6, 0x2cd6, 0x2cd8, -+ 0x2cd8, 0x2cda, 0x2cda, 0x2cdc, 0x2cdc, 0x2cde, 0x2cde, 0x2ce0, -+ 0x2ce0, 0x2ce2, 0x2ce2, 0x2ce4, 0x2ce5, 0x2ce6, 0x2ce7, 0x2ce8, -+ 0x2ce9, 0x2cea, 0x2ceb, 0x2cec, 0x2ced, 0x2cee, 0x2cef, 0x2cf0, -+ 0x2cf1, 0x2cf2, 0x2cf3, 0x2cf4, 0x2cf5, 0x2cf6, 0x2cf7, 0x2cf8, -+ 0x2cf9, 0x2cfa, 0x2cfb, 0x2cfc, 0x2cfd, 0x2cfe, 0x2cff, 0x10a0, -+ 0x10a1, 0x10a2, 0x10a3, 0x10a4, 0x10a5, 0x10a6, 0x10a7, 0x10a8, -+ 0x10a9, 0x10aa, 0x10ab, 0x10ac, 0x10ad, 0x10ae, 0x10af, 0x10b0, -+ 0x10b1, 0x10b2, 0x10b3, 0x10b4, 0x10b5, 0x10b6, 0x10b7, 0x10b8, -+ 0x10b9, 0x10ba, 0x10bb, 0x10bc, 0x10bd, 0x10be, 0x10bf, 0x10c0, -+ 0x10c1, 0x10c2, 0x10c3, 0x10c4, 0x10c5, 0xffff, 0xd21b, 0xff21, -+ 0xff22, 0xff23, 0xff24, 0xff25, 0xff26, 0xff27, 0xff28, 0xff29, -+ 0xff2a, 0xff2b, 0xff2c, 0xff2d, 0xff2e, 0xff2f, 0xff30, 0xff31, -+ 0xff32, 0xff33, 0xff34, 0xff35, 0xff36, 0xff37, 0xff38, 0xff39, -+ 0xff3a, 0xff5b, 0xff5c, 0xff5d, 0xff5e, 0xff5f, 0xff60, 0xff61, -+ 0xff62, 0xff63, 0xff64, 0xff65, 0xff66, 0xff67, 0xff68, 0xff69, -+ 0xff6a, 0xff6b, 0xff6c, 0xff6d, 0xff6e, 0xff6f, 0xff70, 0xff71, -+ 0xff72, 0xff73, 0xff74, 0xff75, 0xff76, 0xff77, 0xff78, 0xff79, -+ 0xff7a, 0xff7b, 0xff7c, 0xff7d, 0xff7e, 0xff7f, 0xff80, 0xff81, -+ 0xff82, 0xff83, 0xff84, 0xff85, 0xff86, 0xff87, 0xff88, 0xff89, -+ 0xff8a, 0xff8b, 0xff8c, 0xff8d, 0xff8e, 0xff8f, 0xff90, 0xff91, -+ 0xff92, 0xff93, 0xff94, 0xff95, 0xff96, 0xff97, 0xff98, 0xff99, -+ 0xff9a, 0xff9b, 0xff9c, 0xff9d, 0xff9e, 0xff9f, 0xffa0, 0xffa1, -+ 0xffa2, 0xffa3, 0xffa4, 0xffa5, 0xffa6, 0xffa7, 0xffa8, 0xffa9, -+ 0xffaa, 0xffab, 0xffac, 0xffad, 0xffae, 0xffaf, 0xffb0, 0xffb1, -+ 0xffb2, 0xffb3, 0xffb4, 0xffb5, 0xffb6, 0xffb7, 0xffb8, 0xffb9, -+ 0xffba, 0xffbb, 0xffbc, 0xffbd, 0xffbe, 0xffbf, 0xffc0, 0xffc1, -+ 0xffc2, 0xffc3, 0xffc4, 0xffc5, 0xffc6, 0xffc7, 0xffc8, 0xffc9, -+ 0xffca, 0xffcb, 0xffcc, 0xffcd, 0xffce, 0xffcf, 0xffd0, 0xffd1, -+ 0xffd2, 0xffd3, 0xffd4, 0xffd5, 0xffd6, 0xffd7, 0xffd8, 0xffd9, -+ 0xffda, 0xffdb, 0xffdc, 0xffdd, 0xffde, 0xffdf, 0xffe0, 0xffe1, -+ 0xffe2, 0xffe3, 0xffe4, 0xffe5, 0xffe6, 0xffe7, 0xffe8, 0xffe9, -+ 0xffea, 0xffeb, 0xffec, 0xffed, 0xffee, 0xffef, 0xfff0, 0xfff1, -+ 0xfff2, 0xfff3, 0xfff4, 0xfff5, 0xfff6, 0xfff7, 0xfff8, 0xfff9, -+ 0xfffa, 0xfffb, 0xfffc, 0xfffd, 0xfffe, 0xffff, -+}; -+ -+/* -+ * Allow full-width illegal characters : -+ * "MS windows 7" supports full-width-invalid-name-characters. -+ * So we should check half-width-invalid-name-characters(ASCII) only -+ * for compatibility. -+ * -+ * " * / : < > ? \ | -+ */ -+static unsigned short bad_uni_chars[] = { -+ 0x0022, 0x002A, 0x002F, 0x003A, -+ 0x003C, 0x003E, 0x003F, 0x005C, 0x007C, -+ 0 -+}; -+ -+static int exfat_convert_char_to_ucs2(struct nls_table *nls, -+ const unsigned char *ch, int ch_len, unsigned short *ucs2, -+ int *lossy) -+{ -+ int len; -+ -+ *ucs2 = 0x0; -+ -+ if (ch[0] < 0x80) { -+ *ucs2 = ch[0]; -+ return 1; -+ } -+ -+ len = nls->char2uni(ch, ch_len, ucs2); -+ if (len < 0) { -+ /* conversion failed */ -+ if (lossy != NULL) -+ *lossy |= NLS_NAME_LOSSY; -+ *ucs2 = '_'; -+ return 1; -+ } -+ return len; -+} -+ -+static int exfat_convert_ucs2_to_char(struct nls_table *nls, -+ unsigned short ucs2, unsigned char *ch, int *lossy) -+{ -+ int len; -+ -+ ch[0] = 0x0; -+ -+ if (ucs2 < 0x0080) { -+ ch[0] = ucs2; -+ return 1; -+ } -+ -+ len = nls->uni2char(ucs2, ch, MAX_CHARSET_SIZE); -+ if (len < 0) { -+ /* conversion failed */ -+ if (lossy != NULL) -+ *lossy |= NLS_NAME_LOSSY; -+ ch[0] = '_'; -+ return 1; -+ } -+ return len; -+} -+ -+unsigned short exfat_toupper(struct super_block *sb, unsigned short a) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ -+ return sbi->vol_utbl[a] ? sbi->vol_utbl[a] : a; -+} -+ -+static unsigned short *exfat_wstrchr(unsigned short *str, unsigned short wchar) -+{ -+ while (*str) { -+ if (*(str++) == wchar) -+ return str; -+ } -+ return NULL; -+} -+ -+int exfat_uniname_ncmp(struct super_block *sb, unsigned short *a, -+ unsigned short *b, unsigned int len) -+{ -+ int i; -+ -+ for (i = 0; i < len; i++, a++, b++) -+ if (exfat_toupper(sb, *a) != exfat_toupper(sb, *b)) -+ return 1; -+ return 0; -+} -+ -+static int exfat_utf16_to_utf8(struct super_block *sb, -+ struct exfat_uni_name *p_uniname, unsigned char *p_cstring, -+ int buflen) -+{ -+ int len; -+ const unsigned short *uniname = p_uniname->name; -+ -+ /* always len >= 0 */ -+ len = utf16s_to_utf8s(uniname, MAX_NAME_LENGTH, UTF16_HOST_ENDIAN, -+ p_cstring, buflen); -+ p_cstring[len] = '\0'; -+ return len; -+} -+ -+static int exfat_utf8_to_utf16(struct super_block *sb, -+ const unsigned char *p_cstring, const int len, -+ struct exfat_uni_name *p_uniname, int *p_lossy) -+{ -+ int i, unilen, lossy = NLS_NAME_NO_LOSSY; -+ unsigned short upname[MAX_NAME_LENGTH + 1]; -+ unsigned short *uniname = p_uniname->name; -+ -+ WARN_ON(!len); -+ -+ unilen = utf8s_to_utf16s(p_cstring, len, UTF16_HOST_ENDIAN, -+ (wchar_t *)uniname, MAX_NAME_LENGTH + 2); -+ if (unilen < 0) { -+ exfat_msg(sb, KERN_ERR, -+ "failed to %s (err : %d) nls len : %d", -+ __func__, unilen, len); -+ return unilen; -+ } -+ -+ if (unilen > MAX_NAME_LENGTH) { -+ exfat_msg(sb, KERN_ERR, -+ "failed to %s (estr:ENAMETOOLONG) nls len : %d, unilen : %d > %d", -+ __func__, len, unilen, MAX_NAME_LENGTH); -+ return -ENAMETOOLONG; -+ } -+ -+ p_uniname->name_len = unilen & 0xFF; -+ -+ for (i = 0; i < unilen; i++) { -+ if (*uniname < 0x0020 || -+ exfat_wstrchr(bad_uni_chars, *uniname)) -+ lossy |= NLS_NAME_LOSSY; -+ -+ upname[i] = exfat_toupper(sb, *uniname); -+ uniname++; -+ } -+ -+ *uniname = '\0'; -+ p_uniname->name_len = unilen; -+ p_uniname->name_hash = exfat_calc_chksum_2byte(upname, unilen << 1, 0, -+ CS_DEFAULT); -+ -+ if (p_lossy) -+ *p_lossy = lossy; -+ return unilen; -+} -+ -+#define PLANE_SIZE 0x00010000 -+#define SURROGATE_MASK 0xfffff800 -+#define SURROGATE_PAIR 0x0000d800 -+#define SURROGATE_LOW 0x00000400 -+#define SURROGATE_BITS 0x000003ff -+ -+unsigned short exfat_high_surrogate(unicode_t u) -+{ -+ return ((u - PLANE_SIZE) >> 10) + SURROGATE_PAIR; -+} -+ -+unsigned short exfat_low_surrogate(unicode_t u) -+{ -+ return ((u - PLANE_SIZE) & SURROGATE_BITS) | SURROGATE_PAIR | -+ SURROGATE_LOW; -+} -+ -+static int __exfat_utf16_to_nls(struct super_block *sb, -+ struct exfat_uni_name *p_uniname, unsigned char *p_cstring, -+ int buflen) -+{ -+ int i, j, len, out_len = 0; -+ unsigned char buf[MAX_CHARSET_SIZE]; -+ const unsigned short *uniname = p_uniname->name; -+ struct nls_table *nls = EXFAT_SB(sb)->nls_io; -+ -+ i = 0; -+ while (i < MAX_NAME_LENGTH && out_len < (buflen - 1)) { -+ if (*uniname == '\0') -+ break; -+ if ((*uniname & SURROGATE_MASK) != SURROGATE_PAIR) { -+ len = exfat_convert_ucs2_to_char(nls, *uniname, buf, -+ NULL); -+ } else { -+ /* Process UTF-16 surrogate pair as one character */ -+ if (!(*uniname & SURROGATE_LOW) && -+ i+1 < MAX_NAME_LENGTH && -+ (*(uniname+1) & SURROGATE_MASK) == SURROGATE_PAIR && -+ (*(uniname+1) & SURROGATE_LOW)) { -+ uniname++; -+ i++; -+ } -+ -+ /* -+ * UTF-16 surrogate pair encodes code points above -+ * U+FFFF. Code points above U+FFFF are not supported -+ * by kernel NLS framework therefore use replacement -+ * character -+ */ -+ len = 1; -+ buf[0] = '_'; -+ } -+ -+ if (out_len + len >= buflen) -+ len = buflen - 1 - out_len; -+ out_len += len; -+ -+ if (len > 1) { -+ for (j = 0; j < len; j++) -+ *p_cstring++ = buf[j]; -+ } else { /* len == 1 */ -+ *p_cstring++ = *buf; -+ } -+ -+ uniname++; -+ i++; -+ } -+ -+ *p_cstring = '\0'; -+ return out_len; -+} -+ -+static int exfat_nls_to_ucs2(struct super_block *sb, -+ const unsigned char *p_cstring, const int len, -+ struct exfat_uni_name *p_uniname, int *p_lossy) -+{ -+ int i = 0, unilen = 0, lossy = NLS_NAME_NO_LOSSY; -+ unsigned short upname[MAX_NAME_LENGTH + 1]; -+ unsigned short *uniname = p_uniname->name; -+ struct nls_table *nls = EXFAT_SB(sb)->nls_io; -+ -+ WARN_ON(!len); -+ -+ while (unilen < MAX_NAME_LENGTH && i < len) { -+ i += exfat_convert_char_to_ucs2(nls, p_cstring + i, len - i, -+ uniname, &lossy); -+ -+ if (*uniname < 0x0020 || -+ exfat_wstrchr(bad_uni_chars, *uniname)) -+ lossy |= NLS_NAME_LOSSY; -+ -+ upname[unilen] = exfat_toupper(sb, *uniname); -+ uniname++; -+ unilen++; -+ } -+ -+ if (p_cstring[i] != '\0') -+ lossy |= NLS_NAME_OVERLEN; -+ -+ *uniname = '\0'; -+ p_uniname->name_len = unilen; -+ p_uniname->name_hash = exfat_calc_chksum_2byte(upname, unilen << 1, 0, -+ CS_DEFAULT); -+ -+ if (p_lossy) -+ *p_lossy = lossy; -+ return unilen; -+} -+ -+int exfat_utf16_to_nls(struct super_block *sb, struct exfat_uni_name *uniname, -+ unsigned char *p_cstring, int buflen) -+{ -+ if (EXFAT_SB(sb)->options.utf8) -+ return exfat_utf16_to_utf8(sb, uniname, p_cstring, -+ buflen); -+ return __exfat_utf16_to_nls(sb, uniname, p_cstring, buflen); -+} -+ -+int exfat_nls_to_utf16(struct super_block *sb, const unsigned char *p_cstring, -+ const int len, struct exfat_uni_name *uniname, int *p_lossy) -+{ -+ if (EXFAT_SB(sb)->options.utf8) -+ return exfat_utf8_to_utf16(sb, p_cstring, len, -+ uniname, p_lossy); -+ return exfat_nls_to_ucs2(sb, p_cstring, len, uniname, p_lossy); -+} -+ -+static int exfat_load_upcase_table(struct super_block *sb, -+ sector_t sector, unsigned long long num_sectors, -+ unsigned int utbl_checksum) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ unsigned int sect_size = sb->s_blocksize; -+ unsigned int i, index = 0, checksum = 0; -+ int ret; -+ unsigned char skip = false; -+ unsigned short *upcase_table; -+ -+ upcase_table = kcalloc(UTBL_COUNT, sizeof(unsigned short), GFP_KERNEL); -+ if (!upcase_table) -+ return -ENOMEM; -+ -+ sbi->vol_utbl = upcase_table; -+ num_sectors += sector; -+ -+ while (sector < num_sectors) { -+ struct buffer_head *bh; -+ -+ bh = sb_bread(sb, sector); -+ if (!bh) { -+ exfat_msg(sb, KERN_ERR, -+ "failed to read sector(0x%llx)\n", -+ (unsigned long long)sector); -+ ret = -EIO; -+ goto free_table; -+ } -+ sector++; -+ for (i = 0; i < sect_size && index <= 0xFFFF; i += 2) { -+ unsigned short uni = get_unaligned_le16(bh->b_data + i); -+ -+ checksum = ((checksum & 1) ? 0x80000000 : 0) + -+ (checksum >> 1) + -+ *(((unsigned char *)bh->b_data) + i); -+ checksum = ((checksum & 1) ? 0x80000000 : 0) + -+ (checksum >> 1) + -+ *(((unsigned char *)bh->b_data) + (i + 1)); -+ -+ if (skip) { -+ index += uni; -+ skip = false; -+ } else if (uni == index) { -+ index++; -+ } else if (uni == 0xFFFF) { -+ skip = true; -+ } else { /* uni != index , uni != 0xFFFF */ -+ upcase_table[index] = uni; -+ index++; -+ } -+ } -+ brelse(bh); -+ } -+ -+ if (index >= 0xFFFF && utbl_checksum == checksum) -+ return 0; -+ -+ exfat_msg(sb, KERN_ERR, -+ "failed to load upcase table (idx : 0x%08x, chksum : 0x%08x, utbl_chksum : 0x%08x)\n", -+ index, checksum, utbl_checksum); -+ ret = -EINVAL; -+free_table: -+ exfat_free_upcase_table(sbi); -+ return ret; -+} -+ -+static int exfat_load_default_upcase_table(struct super_block *sb) -+{ -+ int i, ret = -EIO; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ unsigned char skip = false; -+ unsigned short uni = 0, *upcase_table; -+ unsigned int index = 0; -+ -+ upcase_table = kcalloc(UTBL_COUNT, sizeof(unsigned short), GFP_KERNEL); -+ if (!upcase_table) -+ return -ENOMEM; -+ -+ sbi->vol_utbl = upcase_table; -+ -+ for (i = 0; index <= 0xFFFF && i < EXFAT_NUM_UPCASE; i++) { -+ uni = uni_def_upcase[i]; -+ if (skip) { -+ index += uni; -+ skip = false; -+ } else if (uni == index) { -+ index++; -+ } else if (uni == 0xFFFF) { -+ skip = true; -+ } else { -+ upcase_table[index] = uni; -+ index++; -+ } -+ } -+ -+ if (index >= 0xFFFF) -+ return 0; -+ -+ /* FATAL error: default upcase table has error */ -+ exfat_free_upcase_table(sbi); -+ return ret; -+} -+ -+int exfat_create_upcase_table(struct super_block *sb) -+{ -+ int i, ret; -+ unsigned int tbl_clu, type; -+ sector_t sector; -+ unsigned long long tbl_size, num_sectors; -+ unsigned char blksize_bits = sb->s_blocksize_bits; -+ struct exfat_chain clu; -+ struct exfat_dentry *ep; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct buffer_head *bh; -+ -+ clu.dir = sbi->root_dir; -+ clu.flags = ALLOC_FAT_CHAIN; -+ -+ while (clu.dir != EXFAT_EOF_CLUSTER) { -+ for (i = 0; i < sbi->dentries_per_clu; i++) { -+ ep = exfat_get_dentry(sb, &clu, i, &bh, NULL); -+ if (!ep) -+ return -EIO; -+ -+ type = exfat_get_entry_type(ep); -+ if (type == TYPE_UNUSED) { -+ brelse(bh); -+ break; -+ } -+ -+ if (type != TYPE_UPCASE) { -+ brelse(bh); -+ continue; -+ } -+ -+ tbl_clu = le32_to_cpu(ep->dentry.upcase.start_clu); -+ tbl_size = le64_to_cpu(ep->dentry.upcase.size); -+ -+ sector = exfat_cluster_to_sector(sbi, tbl_clu); -+ num_sectors = ((tbl_size - 1) >> blksize_bits) + 1; -+ ret = exfat_load_upcase_table(sb, sector, num_sectors, -+ le32_to_cpu(ep->dentry.upcase.checksum)); -+ -+ brelse(bh); -+ if (ret && ret != -EIO) -+ goto load_default; -+ -+ /* load successfully */ -+ return ret; -+ } -+ -+ if (exfat_get_next_cluster(sb, &(clu.dir))) -+ return -EIO; -+ } -+ -+load_default: -+ /* load default upcase table */ -+ return exfat_load_default_upcase_table(sb); -+} -+ -+void exfat_free_upcase_table(struct exfat_sb_info *sbi) -+{ -+ kfree(sbi->vol_utbl); -+} --- -2.25.1 - diff --git a/kernel/tools/perf/files/patches/mageia/fs-exfat-add-super-block-operations.patch b/kernel/tools/perf/files/patches/mageia/fs-exfat-add-super-block-operations.patch deleted file mode 100644 index f51a251870..0000000000 --- a/kernel/tools/perf/files/patches/mageia/fs-exfat-add-super-block-operations.patch +++ /dev/null @@ -1,758 +0,0 @@ -From 719c1e1829166da399903b13da6dcc5344e73449 Mon Sep 17 00:00:00 2001 -From: Namjae Jeon -Date: Mon, 2 Mar 2020 15:21:33 +0900 -Subject: [PATCH 02/14] exfat: add super block operations -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This adds the implementation of superblock operations for exfat. - -Signed-off-by: Namjae Jeon -Signed-off-by: Sungjong Seo -Reviewed-by: Pali Rohár -Reviewed-by: Christoph Hellwig -Reviewed-by: Arnd Bergmann -Signed-off-by: Al Viro ---- - fs/exfat/super.c | 728 +++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 728 insertions(+) - create mode 100644 fs/exfat/super.c - -diff --git a/fs/exfat/super.c b/fs/exfat/super.c -new file mode 100644 -index 000000000000..f06e0b53e393 ---- /dev/null -+++ b/fs/exfat/super.c -@@ -0,0 +1,728 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "exfat_raw.h" -+#include "exfat_fs.h" -+ -+static char exfat_default_iocharset[] = CONFIG_EXFAT_DEFAULT_IOCHARSET; -+static struct kmem_cache *exfat_inode_cachep; -+ -+static void exfat_free_iocharset(struct exfat_sb_info *sbi) -+{ -+ if (sbi->options.iocharset != exfat_default_iocharset) -+ kfree(sbi->options.iocharset); -+} -+ -+static void exfat_delayed_free(struct rcu_head *p) -+{ -+ struct exfat_sb_info *sbi = container_of(p, struct exfat_sb_info, rcu); -+ -+ unload_nls(sbi->nls_io); -+ exfat_free_iocharset(sbi); -+ exfat_free_upcase_table(sbi); -+ kfree(sbi); -+} -+ -+static void exfat_put_super(struct super_block *sb) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ -+ mutex_lock(&sbi->s_lock); -+ if (test_and_clear_bit(EXFAT_SB_DIRTY, &sbi->s_state)) -+ sync_blockdev(sb->s_bdev); -+ exfat_set_vol_flags(sb, VOL_CLEAN); -+ exfat_free_bitmap(sbi); -+ mutex_unlock(&sbi->s_lock); -+ -+ call_rcu(&sbi->rcu, exfat_delayed_free); -+} -+ -+static int exfat_sync_fs(struct super_block *sb, int wait) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ int err = 0; -+ -+ /* If there are some dirty buffers in the bdev inode */ -+ mutex_lock(&sbi->s_lock); -+ if (test_and_clear_bit(EXFAT_SB_DIRTY, &sbi->s_state)) { -+ sync_blockdev(sb->s_bdev); -+ if (exfat_set_vol_flags(sb, VOL_CLEAN)) -+ err = -EIO; -+ } -+ mutex_unlock(&sbi->s_lock); -+ return err; -+} -+ -+static int exfat_statfs(struct dentry *dentry, struct kstatfs *buf) -+{ -+ struct super_block *sb = dentry->d_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ unsigned long long id = huge_encode_dev(sb->s_bdev->bd_dev); -+ -+ if (sbi->used_clusters == EXFAT_CLUSTERS_UNTRACKED) { -+ mutex_lock(&sbi->s_lock); -+ if (exfat_count_used_clusters(sb, &sbi->used_clusters)) { -+ mutex_unlock(&sbi->s_lock); -+ return -EIO; -+ } -+ mutex_unlock(&sbi->s_lock); -+ } -+ -+ buf->f_type = sb->s_magic; -+ buf->f_bsize = sbi->cluster_size; -+ buf->f_blocks = sbi->num_clusters - 2; /* clu 0 & 1 */ -+ buf->f_bfree = buf->f_blocks - sbi->used_clusters; -+ buf->f_bavail = buf->f_bfree; -+ buf->f_fsid.val[0] = (unsigned int)id; -+ buf->f_fsid.val[1] = (unsigned int)(id >> 32); -+ /* Unicode utf16 255 characters */ -+ buf->f_namelen = EXFAT_MAX_FILE_LEN * NLS_MAX_CHARSET_SIZE; -+ return 0; -+} -+ -+int exfat_set_vol_flags(struct super_block *sb, unsigned short new_flag) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct pbr64 *bpb; -+ bool sync = 0; -+ -+ /* flags are not changed */ -+ if (sbi->vol_flag == new_flag) -+ return 0; -+ -+ sbi->vol_flag = new_flag; -+ -+ /* skip updating volume dirty flag, -+ * if this volume has been mounted with read-only -+ */ -+ if (sb_rdonly(sb)) -+ return 0; -+ -+ if (!sbi->pbr_bh) { -+ sbi->pbr_bh = sb_bread(sb, 0); -+ if (!sbi->pbr_bh) { -+ exfat_msg(sb, KERN_ERR, "failed to read boot sector"); -+ return -ENOMEM; -+ } -+ } -+ -+ bpb = (struct pbr64 *)sbi->pbr_bh->b_data; -+ bpb->bsx.vol_flags = cpu_to_le16(new_flag); -+ -+ if (new_flag == VOL_DIRTY && !buffer_dirty(sbi->pbr_bh)) -+ sync = true; -+ else -+ sync = false; -+ -+ set_buffer_uptodate(sbi->pbr_bh); -+ mark_buffer_dirty(sbi->pbr_bh); -+ -+ if (sync) -+ sync_dirty_buffer(sbi->pbr_bh); -+ return 0; -+} -+ -+static int exfat_show_options(struct seq_file *m, struct dentry *root) -+{ -+ struct super_block *sb = root->d_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct exfat_mount_options *opts = &sbi->options; -+ -+ /* Show partition info */ -+ if (!uid_eq(opts->fs_uid, GLOBAL_ROOT_UID)) -+ seq_printf(m, ",uid=%u", -+ from_kuid_munged(&init_user_ns, opts->fs_uid)); -+ if (!gid_eq(opts->fs_gid, GLOBAL_ROOT_GID)) -+ seq_printf(m, ",gid=%u", -+ from_kgid_munged(&init_user_ns, opts->fs_gid)); -+ seq_printf(m, ",fmask=%04o,dmask=%04o", opts->fs_fmask, opts->fs_dmask); -+ if (opts->allow_utime) -+ seq_printf(m, ",allow_utime=%04o", opts->allow_utime); -+ if (opts->utf8) -+ seq_puts(m, ",iocharset=utf8"); -+ else if (sbi->nls_io) -+ seq_printf(m, ",iocharset=%s", sbi->nls_io->charset); -+ seq_printf(m, ",bps=%ld", sb->s_blocksize); -+ if (opts->errors == EXFAT_ERRORS_CONT) -+ seq_puts(m, ",errors=continue"); -+ else if (opts->errors == EXFAT_ERRORS_PANIC) -+ seq_puts(m, ",errors=panic"); -+ else -+ seq_puts(m, ",errors=remount-ro"); -+ if (opts->discard) -+ seq_puts(m, ",discard"); -+ if (opts->time_offset) -+ seq_printf(m, ",time_offset=%d", opts->time_offset); -+ return 0; -+} -+ -+static struct inode *exfat_alloc_inode(struct super_block *sb) -+{ -+ struct exfat_inode_info *ei; -+ -+ ei = kmem_cache_alloc(exfat_inode_cachep, GFP_NOFS); -+ if (!ei) -+ return NULL; -+ -+ init_rwsem(&ei->truncate_lock); -+ return &ei->vfs_inode; -+} -+ -+static void exfat_free_inode(struct inode *inode) -+{ -+ kmem_cache_free(exfat_inode_cachep, EXFAT_I(inode)); -+} -+ -+static const struct super_operations exfat_sops = { -+ .alloc_inode = exfat_alloc_inode, -+ .free_inode = exfat_free_inode, -+ .write_inode = exfat_write_inode, -+ .evict_inode = exfat_evict_inode, -+ .put_super = exfat_put_super, -+ .sync_fs = exfat_sync_fs, -+ .statfs = exfat_statfs, -+ .show_options = exfat_show_options, -+}; -+ -+enum { -+ Opt_uid, -+ Opt_gid, -+ Opt_umask, -+ Opt_dmask, -+ Opt_fmask, -+ Opt_allow_utime, -+ Opt_charset, -+ Opt_errors, -+ Opt_discard, -+ Opt_time_offset, -+}; -+ -+static const struct fs_parameter_spec exfat_param_specs[] = { -+ fsparam_u32("uid", Opt_uid), -+ fsparam_u32("gid", Opt_gid), -+ fsparam_u32oct("umask", Opt_umask), -+ fsparam_u32oct("dmask", Opt_dmask), -+ fsparam_u32oct("fmask", Opt_fmask), -+ fsparam_u32oct("allow_utime", Opt_allow_utime), -+ fsparam_string("iocharset", Opt_charset), -+ fsparam_enum("errors", Opt_errors), -+ fsparam_flag("discard", Opt_discard), -+ fsparam_s32("time_offset", Opt_time_offset), -+ {} -+}; -+ -+static const struct fs_parameter_enum exfat_param_enums[] = { -+ { Opt_errors, "continue", EXFAT_ERRORS_CONT }, -+ { Opt_errors, "panic", EXFAT_ERRORS_PANIC }, -+ { Opt_errors, "remount-ro", EXFAT_ERRORS_RO }, -+ {} -+}; -+ -+static const struct fs_parameter_description exfat_parameters = { -+ .name = "exfat", -+ .specs = exfat_param_specs, -+ .enums = exfat_param_enums, -+}; -+ -+static int exfat_parse_param(struct fs_context *fc, struct fs_parameter *param) -+{ -+ struct exfat_sb_info *sbi = fc->s_fs_info; -+ struct exfat_mount_options *opts = &sbi->options; -+ struct fs_parse_result result; -+ int opt; -+ -+ opt = fs_parse(fc, &exfat_parameters, param, &result); -+ if (opt < 0) -+ return opt; -+ -+ switch (opt) { -+ case Opt_uid: -+ opts->fs_uid = make_kuid(current_user_ns(), result.uint_32); -+ break; -+ case Opt_gid: -+ opts->fs_gid = make_kgid(current_user_ns(), result.uint_32); -+ break; -+ case Opt_umask: -+ opts->fs_fmask = result.uint_32; -+ opts->fs_dmask = result.uint_32; -+ break; -+ case Opt_dmask: -+ opts->fs_dmask = result.uint_32; -+ break; -+ case Opt_fmask: -+ opts->fs_fmask = result.uint_32; -+ break; -+ case Opt_allow_utime: -+ opts->allow_utime = result.uint_32 & 0022; -+ break; -+ case Opt_charset: -+ exfat_free_iocharset(sbi); -+ opts->iocharset = kstrdup(param->string, GFP_KERNEL); -+ if (!opts->iocharset) -+ return -ENOMEM; -+ break; -+ case Opt_errors: -+ opts->errors = result.uint_32; -+ break; -+ case Opt_discard: -+ opts->discard = 1; -+ break; -+ case Opt_time_offset: -+ /* -+ * Make the limit 24 just in case someone invents something -+ * unusual. -+ */ -+ if (result.int_32 < -24 * 60 || result.int_32 > 24 * 60) -+ return -EINVAL; -+ opts->time_offset = result.int_32; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static void exfat_hash_init(struct super_block *sb) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ int i; -+ -+ spin_lock_init(&sbi->inode_hash_lock); -+ for (i = 0; i < EXFAT_HASH_SIZE; i++) -+ INIT_HLIST_HEAD(&sbi->inode_hashtable[i]); -+} -+ -+static int exfat_read_root(struct inode *inode) -+{ -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ struct exfat_chain cdir; -+ int num_subdirs, num_clu = 0; -+ -+ exfat_chain_set(&ei->dir, sbi->root_dir, 0, ALLOC_FAT_CHAIN); -+ ei->entry = -1; -+ ei->start_clu = sbi->root_dir; -+ ei->flags = ALLOC_FAT_CHAIN; -+ ei->type = TYPE_DIR; -+ ei->version = 0; -+ ei->rwoffset = 0; -+ ei->hint_bmap.off = EXFAT_EOF_CLUSTER; -+ ei->hint_stat.eidx = 0; -+ ei->hint_stat.clu = sbi->root_dir; -+ ei->hint_femp.eidx = EXFAT_HINT_NONE; -+ -+ exfat_chain_set(&cdir, sbi->root_dir, 0, ALLOC_FAT_CHAIN); -+ if (exfat_count_num_clusters(sb, &cdir, &num_clu)) -+ return -EIO; -+ i_size_write(inode, num_clu << sbi->cluster_size_bits); -+ -+ num_subdirs = exfat_count_dir_entries(sb, &cdir); -+ if (num_subdirs < 0) -+ return -EIO; -+ set_nlink(inode, num_subdirs + EXFAT_MIN_SUBDIR); -+ -+ inode->i_uid = sbi->options.fs_uid; -+ inode->i_gid = sbi->options.fs_gid; -+ inode_inc_iversion(inode); -+ inode->i_generation = 0; -+ inode->i_mode = exfat_make_mode(sbi, ATTR_SUBDIR, 0777); -+ inode->i_op = &exfat_dir_inode_operations; -+ inode->i_fop = &exfat_dir_operations; -+ -+ inode->i_blocks = ((i_size_read(inode) + (sbi->cluster_size - 1)) -+ & ~(sbi->cluster_size - 1)) >> inode->i_blkbits; -+ EXFAT_I(inode)->i_pos = ((loff_t)sbi->root_dir << 32) | 0xffffffff; -+ EXFAT_I(inode)->i_size_aligned = i_size_read(inode); -+ EXFAT_I(inode)->i_size_ondisk = i_size_read(inode); -+ -+ exfat_save_attr(inode, ATTR_SUBDIR); -+ inode->i_mtime = inode->i_atime = inode->i_ctime = ei->i_crtime = -+ current_time(inode); -+ exfat_cache_init_inode(inode); -+ return 0; -+} -+ -+static struct pbr *exfat_read_pbr_with_logical_sector(struct super_block *sb, -+ struct buffer_head **prev_bh) -+{ -+ struct pbr *p_pbr = (struct pbr *) (*prev_bh)->b_data; -+ unsigned short logical_sect = 0; -+ -+ logical_sect = 1 << p_pbr->bsx.f64.sect_size_bits; -+ -+ if (!is_power_of_2(logical_sect) || -+ logical_sect < 512 || logical_sect > 4096) { -+ exfat_msg(sb, KERN_ERR, "bogus logical sector size %u", -+ logical_sect); -+ return NULL; -+ } -+ -+ if (logical_sect < sb->s_blocksize) { -+ exfat_msg(sb, KERN_ERR, -+ "logical sector size too small for device (logical sector size = %u)", -+ logical_sect); -+ return NULL; -+ } -+ -+ if (logical_sect > sb->s_blocksize) { -+ struct buffer_head *bh = NULL; -+ -+ __brelse(*prev_bh); -+ *prev_bh = NULL; -+ -+ if (!sb_set_blocksize(sb, logical_sect)) { -+ exfat_msg(sb, KERN_ERR, -+ "unable to set blocksize %u", logical_sect); -+ return NULL; -+ } -+ bh = sb_bread(sb, 0); -+ if (!bh) { -+ exfat_msg(sb, KERN_ERR, -+ "unable to read boot sector (logical sector size = %lu)", -+ sb->s_blocksize); -+ return NULL; -+ } -+ -+ *prev_bh = bh; -+ p_pbr = (struct pbr *) bh->b_data; -+ } -+ return p_pbr; -+} -+ -+/* mount the file system volume */ -+static int __exfat_fill_super(struct super_block *sb) -+{ -+ int ret; -+ struct pbr *p_pbr; -+ struct pbr64 *p_bpb; -+ struct buffer_head *bh; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ -+ /* set block size to read super block */ -+ sb_min_blocksize(sb, 512); -+ -+ /* read boot sector */ -+ bh = sb_bread(sb, 0); -+ if (!bh) { -+ exfat_msg(sb, KERN_ERR, "unable to read boot sector"); -+ return -EIO; -+ } -+ -+ /* PRB is read */ -+ p_pbr = (struct pbr *)bh->b_data; -+ -+ /* check the validity of PBR */ -+ if (le16_to_cpu((p_pbr->signature)) != PBR_SIGNATURE) { -+ exfat_msg(sb, KERN_ERR, "invalid boot record signature"); -+ ret = -EINVAL; -+ goto free_bh; -+ } -+ -+ -+ /* check logical sector size */ -+ p_pbr = exfat_read_pbr_with_logical_sector(sb, &bh); -+ if (!p_pbr) { -+ ret = -EIO; -+ goto free_bh; -+ } -+ -+ /* -+ * res_zero field must be filled with zero to prevent mounting -+ * from FAT volume. -+ */ -+ if (memchr_inv(p_pbr->bpb.f64.res_zero, 0, -+ sizeof(p_pbr->bpb.f64.res_zero))) { -+ ret = -EINVAL; -+ goto free_bh; -+ } -+ -+ p_bpb = (struct pbr64 *)p_pbr; -+ if (!p_bpb->bsx.num_fats) { -+ exfat_msg(sb, KERN_ERR, "bogus number of FAT structure"); -+ ret = -EINVAL; -+ goto free_bh; -+ } -+ -+ sbi->sect_per_clus = 1 << p_bpb->bsx.sect_per_clus_bits; -+ sbi->sect_per_clus_bits = p_bpb->bsx.sect_per_clus_bits; -+ sbi->cluster_size_bits = sbi->sect_per_clus_bits + sb->s_blocksize_bits; -+ sbi->cluster_size = 1 << sbi->cluster_size_bits; -+ sbi->num_FAT_sectors = le32_to_cpu(p_bpb->bsx.fat_length); -+ sbi->FAT1_start_sector = le32_to_cpu(p_bpb->bsx.fat_offset); -+ sbi->FAT2_start_sector = p_bpb->bsx.num_fats == 1 ? -+ sbi->FAT1_start_sector : -+ sbi->FAT1_start_sector + sbi->num_FAT_sectors; -+ sbi->data_start_sector = le32_to_cpu(p_bpb->bsx.clu_offset); -+ sbi->num_sectors = le64_to_cpu(p_bpb->bsx.vol_length); -+ /* because the cluster index starts with 2 */ -+ sbi->num_clusters = le32_to_cpu(p_bpb->bsx.clu_count) + -+ EXFAT_RESERVED_CLUSTERS; -+ -+ sbi->root_dir = le32_to_cpu(p_bpb->bsx.root_cluster); -+ sbi->dentries_per_clu = 1 << -+ (sbi->cluster_size_bits - DENTRY_SIZE_BITS); -+ -+ sbi->vol_flag = le16_to_cpu(p_bpb->bsx.vol_flags); -+ sbi->clu_srch_ptr = EXFAT_FIRST_CLUSTER; -+ sbi->used_clusters = EXFAT_CLUSTERS_UNTRACKED; -+ -+ if (le16_to_cpu(p_bpb->bsx.vol_flags) & VOL_DIRTY) { -+ sbi->vol_flag |= VOL_DIRTY; -+ exfat_msg(sb, KERN_WARNING, -+ "Volume was not properly unmounted. Some data may be corrupt. Please run fsck."); -+ } -+ -+ /* exFAT file size is limited by a disk volume size */ -+ sb->s_maxbytes = (u64)(sbi->num_clusters - EXFAT_RESERVED_CLUSTERS) << -+ sbi->cluster_size_bits; -+ -+ ret = exfat_create_upcase_table(sb); -+ if (ret) { -+ exfat_msg(sb, KERN_ERR, "failed to load upcase table"); -+ goto free_bh; -+ } -+ -+ ret = exfat_load_bitmap(sb); -+ if (ret) { -+ exfat_msg(sb, KERN_ERR, "failed to load alloc-bitmap"); -+ goto free_upcase_table; -+ } -+ -+ ret = exfat_count_used_clusters(sb, &sbi->used_clusters); -+ if (ret) { -+ exfat_msg(sb, KERN_ERR, "failed to scan clusters"); -+ goto free_alloc_bitmap; -+ } -+ -+ return 0; -+ -+free_alloc_bitmap: -+ exfat_free_bitmap(sbi); -+free_upcase_table: -+ exfat_free_upcase_table(sbi); -+free_bh: -+ brelse(bh); -+ return ret; -+} -+ -+static int exfat_fill_super(struct super_block *sb, struct fs_context *fc) -+{ -+ struct exfat_sb_info *sbi = sb->s_fs_info; -+ struct exfat_mount_options *opts = &sbi->options; -+ struct inode *root_inode; -+ int err; -+ -+ if (opts->allow_utime == (unsigned short)-1) -+ opts->allow_utime = ~opts->fs_dmask & 0022; -+ -+ if (opts->discard) { -+ struct request_queue *q = bdev_get_queue(sb->s_bdev); -+ -+ if (!blk_queue_discard(q)) -+ exfat_msg(sb, KERN_WARNING, -+ "mounting with \"discard\" option, but the device does not support discard"); -+ opts->discard = 0; -+ } -+ -+ sb->s_flags |= SB_NODIRATIME; -+ sb->s_magic = EXFAT_SUPER_MAGIC; -+ sb->s_op = &exfat_sops; -+ -+ sb->s_time_gran = 1; -+ sb->s_time_min = EXFAT_MIN_TIMESTAMP_SECS; -+ sb->s_time_max = EXFAT_MAX_TIMESTAMP_SECS; -+ -+ err = __exfat_fill_super(sb); -+ if (err) { -+ exfat_msg(sb, KERN_ERR, "failed to recognize exfat type"); -+ goto check_nls_io; -+ } -+ -+ /* set up enough so that it can read an inode */ -+ exfat_hash_init(sb); -+ -+ if (!strcmp(sbi->options.iocharset, "utf8")) -+ opts->utf8 = 1; -+ else { -+ sbi->nls_io = load_nls(sbi->options.iocharset); -+ if (!sbi->nls_io) { -+ exfat_msg(sb, KERN_ERR, "IO charset %s not found", -+ sbi->options.iocharset); -+ err = -EINVAL; -+ goto free_table; -+ } -+ } -+ -+ if (sbi->options.utf8) -+ sb->s_d_op = &exfat_utf8_dentry_ops; -+ else -+ sb->s_d_op = &exfat_dentry_ops; -+ -+ root_inode = new_inode(sb); -+ if (!root_inode) { -+ exfat_msg(sb, KERN_ERR, "failed to allocate root inode."); -+ err = -ENOMEM; -+ goto free_table; -+ } -+ -+ root_inode->i_ino = EXFAT_ROOT_INO; -+ inode_set_iversion(root_inode, 1); -+ err = exfat_read_root(root_inode); -+ if (err) { -+ exfat_msg(sb, KERN_ERR, "failed to initialize root inode."); -+ goto put_inode; -+ } -+ -+ exfat_hash_inode(root_inode, EXFAT_I(root_inode)->i_pos); -+ insert_inode_hash(root_inode); -+ -+ sb->s_root = d_make_root(root_inode); -+ if (!sb->s_root) { -+ exfat_msg(sb, KERN_ERR, "failed to get the root dentry"); -+ err = -ENOMEM; -+ goto put_inode; -+ } -+ -+ return 0; -+ -+put_inode: -+ iput(root_inode); -+ sb->s_root = NULL; -+ -+free_table: -+ exfat_free_upcase_table(sbi); -+ exfat_free_bitmap(sbi); -+ -+check_nls_io: -+ unload_nls(sbi->nls_io); -+ exfat_free_iocharset(sbi); -+ sb->s_fs_info = NULL; -+ kfree(sbi); -+ return err; -+} -+ -+static int exfat_get_tree(struct fs_context *fc) -+{ -+ return get_tree_bdev(fc, exfat_fill_super); -+} -+ -+static void exfat_free(struct fs_context *fc) -+{ -+ kfree(fc->s_fs_info); -+} -+ -+static const struct fs_context_operations exfat_context_ops = { -+ .parse_param = exfat_parse_param, -+ .get_tree = exfat_get_tree, -+ .free = exfat_free, -+}; -+ -+static int exfat_init_fs_context(struct fs_context *fc) -+{ -+ struct exfat_sb_info *sbi; -+ -+ sbi = kzalloc(sizeof(struct exfat_sb_info), GFP_KERNEL); -+ if (!sbi) -+ return -ENOMEM; -+ -+ mutex_init(&sbi->s_lock); -+ ratelimit_state_init(&sbi->ratelimit, DEFAULT_RATELIMIT_INTERVAL, -+ DEFAULT_RATELIMIT_BURST); -+ -+ sbi->options.fs_uid = current_uid(); -+ sbi->options.fs_gid = current_gid(); -+ sbi->options.fs_fmask = current->fs->umask; -+ sbi->options.fs_dmask = current->fs->umask; -+ sbi->options.allow_utime = -1; -+ sbi->options.iocharset = exfat_default_iocharset; -+ sbi->options.errors = EXFAT_ERRORS_RO; -+ -+ fc->s_fs_info = sbi; -+ fc->ops = &exfat_context_ops; -+ return 0; -+} -+ -+static struct file_system_type exfat_fs_type = { -+ .owner = THIS_MODULE, -+ .name = "exfat", -+ .init_fs_context = exfat_init_fs_context, -+ .parameters = &exfat_parameters, -+ .kill_sb = kill_block_super, -+ .fs_flags = FS_REQUIRES_DEV, -+}; -+ -+static void exfat_inode_init_once(void *foo) -+{ -+ struct exfat_inode_info *ei = (struct exfat_inode_info *)foo; -+ -+ INIT_HLIST_NODE(&ei->i_hash_fat); -+ inode_init_once(&ei->vfs_inode); -+} -+ -+static int __init init_exfat_fs(void) -+{ -+ int err; -+ -+ err = exfat_cache_init(); -+ if (err) -+ return err; -+ -+ exfat_inode_cachep = kmem_cache_create("exfat_inode_cache", -+ sizeof(struct exfat_inode_info), -+ 0, SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD, -+ exfat_inode_init_once); -+ if (!exfat_inode_cachep) { -+ err = -ENOMEM; -+ goto shutdown_cache; -+ } -+ -+ err = register_filesystem(&exfat_fs_type); -+ if (err) -+ goto destroy_cache; -+ -+ return 0; -+ -+destroy_cache: -+ kmem_cache_destroy(exfat_inode_cachep); -+shutdown_cache: -+ exfat_cache_shutdown(); -+ return err; -+} -+ -+static void __exit exit_exfat_fs(void) -+{ -+ /* -+ * Make sure all delayed rcu free inodes are flushed before we -+ * destroy cache. -+ */ -+ rcu_barrier(); -+ kmem_cache_destroy(exfat_inode_cachep); -+ unregister_filesystem(&exfat_fs_type); -+ exfat_cache_shutdown(); -+} -+ -+module_init(init_exfat_fs); -+module_exit(exit_exfat_fs); -+ -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("exFAT filesystem support"); -+MODULE_AUTHOR("Samsung Electronics Co., Ltd."); --- -2.25.1 - diff --git a/kernel/tools/perf/files/patches/mageia/fs-exfat-fix-discard-support.patch b/kernel/tools/perf/files/patches/mageia/fs-exfat-fix-discard-support.patch deleted file mode 100644 index 5de9917c40..0000000000 --- a/kernel/tools/perf/files/patches/mageia/fs-exfat-fix-discard-support.patch +++ /dev/null @@ -1,32 +0,0 @@ -From: =?UTF-8?q?Pali=20Roh=C3=A1r?= -Subject: [PATCH 4/4] exfat: Fix discard support -Date: Tue, 17 Mar 2020 23:25:55 +0100 - -Discard support was always unconditionally disabled. Now it is disabled -only in the case when blk_queue_discard() returns false. - -Signed-off-by: Pali Rohár ---- - fs/exfat/super.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/fs/exfat/super.c b/fs/exfat/super.c -index 16ed202ef527..30e914ad17b5 100644 ---- a/fs/exfat/super.c -+++ b/fs/exfat/super.c -@@ -531,10 +531,11 @@ static int exfat_fill_super(struct super_block *sb, struct fs_context *fc) - if (opts->discard) { - struct request_queue *q = bdev_get_queue(sb->s_bdev); - -- if (!blk_queue_discard(q)) -+ if (!blk_queue_discard(q)) { - exfat_msg(sb, KERN_WARNING, - "mounting with \"discard\" option, but the device does not support discard"); -- opts->discard = 0; -+ opts->discard = 0; -+ } - } - - sb->s_flags |= SB_NODIRATIME; --- -2.20.1 diff --git a/kernel/tools/perf/files/patches/mageia/fs-exfat-remove-from-staging.patch b/kernel/tools/perf/files/patches/mageia/fs-exfat-remove-from-staging.patch deleted file mode 100644 index 252683728e..0000000000 --- a/kernel/tools/perf/files/patches/mageia/fs-exfat-remove-from-staging.patch +++ /dev/null @@ -1,9152 +0,0 @@ - -This removes the staging driver in favour of the one being merged upstream in 5.7 - -Signed-off-by: Thomas Backlund - ---- - MAINTAINERS | 6 - drivers/staging/Kconfig | 2 - drivers/staging/Makefile | 1 - drivers/staging/exfat/Kconfig | 41 -- - drivers/staging/exfat/Makefile | 10 - drivers/staging/exfat/TODO | 69 --- - drivers/staging/exfat/exfat.h | 824 ---------------------------------------- - drivers/staging/exfat/exfat_blkdev.c | 136 ------ - drivers/staging/exfat/exfat_cache.c | 555 --------------------------- - drivers/staging/exfat/exfat_core.c | 2582 -------------------------------------------------------------------------------------------------------------------------------- - drivers/staging/exfat/exfat_nls.c | 212 ---------- - drivers/staging/exfat/exfat_super.c | 3883 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - drivers/staging/exfat/exfat_upcase.c | 740 ------------------------------------ - 13 files changed, 9061 deletions(-) - -diff -Nurp linux-5.6.3.orig/drivers/staging/exfat/exfat_blkdev.c linux-5.6.3/drivers/staging/exfat/exfat_blkdev.c ---- linux-5.6.3.orig/drivers/staging/exfat/exfat_blkdev.c 2020-03-30 01:25:41.000000000 +0300 -+++ linux-5.6.3/drivers/staging/exfat/exfat_blkdev.c 1970-01-01 02:00:00.000000000 +0200 -@@ -1,136 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0-or-later --/* -- * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -- */ -- --#include --#include --#include --#include "exfat.h" -- --void exfat_bdev_open(struct super_block *sb) --{ -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- -- if (p_bd->opened) -- return; -- -- p_bd->sector_size = bdev_logical_block_size(sb->s_bdev); -- p_bd->sector_size_bits = ilog2(p_bd->sector_size); -- p_bd->sector_size_mask = p_bd->sector_size - 1; -- p_bd->num_sectors = i_size_read(sb->s_bdev->bd_inode) >> -- p_bd->sector_size_bits; -- p_bd->opened = true; --} -- --void exfat_bdev_close(struct super_block *sb) --{ -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- -- p_bd->opened = false; --} -- --int exfat_bdev_read(struct super_block *sb, sector_t secno, struct buffer_head **bh, -- u32 num_secs, bool read) --{ -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); --#ifdef CONFIG_STAGING_EXFAT_KERNEL_DEBUG -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- long flags = sbi->debug_flags; -- -- if (flags & EXFAT_DEBUGFLAGS_ERROR_RW) -- return -EIO; --#endif /* CONFIG_STAGING_EXFAT_KERNEL_DEBUG */ -- -- if (!p_bd->opened) -- return -ENODEV; -- -- if (*bh) -- __brelse(*bh); -- -- if (read) -- *bh = __bread(sb->s_bdev, secno, -- num_secs << p_bd->sector_size_bits); -- else -- *bh = __getblk(sb->s_bdev, secno, -- num_secs << p_bd->sector_size_bits); -- -- if (*bh) -- return 0; -- -- WARN(!p_fs->dev_ejected, -- "[EXFAT] No bh, device seems wrong or to be ejected.\n"); -- -- return -EIO; --} -- --int exfat_bdev_write(struct super_block *sb, sector_t secno, struct buffer_head *bh, -- u32 num_secs, bool sync) --{ -- s32 count; -- struct buffer_head *bh2; -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); --#ifdef CONFIG_STAGING_EXFAT_KERNEL_DEBUG -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- long flags = sbi->debug_flags; -- -- if (flags & EXFAT_DEBUGFLAGS_ERROR_RW) -- return -EIO; --#endif /* CONFIG_STAGING_EXFAT_KERNEL_DEBUG */ -- -- if (!p_bd->opened) -- return -ENODEV; -- -- if (secno == bh->b_blocknr) { -- lock_buffer(bh); -- set_buffer_uptodate(bh); -- mark_buffer_dirty(bh); -- unlock_buffer(bh); -- if (sync && (sync_dirty_buffer(bh) != 0)) -- return -EIO; -- } else { -- count = num_secs << p_bd->sector_size_bits; -- -- bh2 = __getblk(sb->s_bdev, secno, count); -- if (!bh2) -- goto no_bh; -- -- lock_buffer(bh2); -- memcpy(bh2->b_data, bh->b_data, count); -- set_buffer_uptodate(bh2); -- mark_buffer_dirty(bh2); -- unlock_buffer(bh2); -- if (sync && (sync_dirty_buffer(bh2) != 0)) { -- __brelse(bh2); -- goto no_bh; -- } -- __brelse(bh2); -- } -- -- return 0; -- --no_bh: -- WARN(!p_fs->dev_ejected, -- "[EXFAT] No bh, device seems wrong or to be ejected.\n"); -- -- return -EIO; --} -- --int exfat_bdev_sync(struct super_block *sb) --{ -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); --#ifdef CONFIG_STAGING_EXFAT_KERNEL_DEBUG -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- long flags = sbi->debug_flags; -- -- if (flags & EXFAT_DEBUGFLAGS_ERROR_RW) -- return -EIO; --#endif /* CONFIG_STAGING_EXFAT_KERNEL_DEBUG */ -- -- if (!p_bd->opened) -- return -ENODEV; -- -- return sync_blockdev(sb->s_bdev); --} -diff -Nurp linux-5.6.3.orig/drivers/staging/exfat/exfat_cache.c linux-5.6.3/drivers/staging/exfat/exfat_cache.c ---- linux-5.6.3.orig/drivers/staging/exfat/exfat_cache.c 2020-03-30 01:25:41.000000000 +0300 -+++ linux-5.6.3/drivers/staging/exfat/exfat_cache.c 1970-01-01 02:00:00.000000000 +0200 -@@ -1,555 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0-or-later --/* -- * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -- */ -- --#include --#include --#include --#include "exfat.h" -- --#define LOCKBIT 0x01 --#define DIRTYBIT 0x02 -- --/* Local variables */ --static DEFINE_MUTEX(f_mutex); --static DEFINE_MUTEX(b_mutex); -- --static struct buf_cache_t *FAT_cache_find(struct super_block *sb, sector_t sec) --{ -- s32 off; -- struct buf_cache_t *bp, *hp; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- off = (sec + -- (sec >> p_fs->sectors_per_clu_bits)) & (FAT_CACHE_HASH_SIZE - 1); -- -- 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; -- } -- } -- return NULL; --} -- --static void push_to_mru(struct buf_cache_t *bp, struct buf_cache_t *list) --{ -- bp->next = list->next; -- bp->prev = list; -- list->next->prev = bp; -- list->next = bp; --} -- --static void push_to_lru(struct buf_cache_t *bp, struct buf_cache_t *list) --{ -- bp->prev = list->prev; -- bp->next = list; -- list->prev->next = bp; -- list->prev = bp; --} -- --static void move_to_mru(struct buf_cache_t *bp, struct buf_cache_t *list) --{ -- bp->prev->next = bp->next; -- bp->next->prev = bp->prev; -- push_to_mru(bp, list); --} -- --static void move_to_lru(struct buf_cache_t *bp, struct buf_cache_t *list) --{ -- bp->prev->next = bp->next; -- bp->next->prev = bp->prev; -- push_to_lru(bp, list); --} -- --static struct buf_cache_t *FAT_cache_get(struct super_block *sb, sector_t sec) --{ -- struct buf_cache_t *bp; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- bp = p_fs->FAT_cache_lru_list.prev; -- -- move_to_mru(bp, &p_fs->FAT_cache_lru_list); -- return bp; --} -- --static void FAT_cache_insert_hash(struct super_block *sb, -- struct buf_cache_t *bp) --{ -- s32 off; -- struct buf_cache_t *hp; -- struct fs_info_t *p_fs; -- -- p_fs = &(EXFAT_SB(sb)->fs_info); -- off = (bp->sec + -- (bp->sec >> p_fs->sectors_per_clu_bits)) & -- (FAT_CACHE_HASH_SIZE - 1); -- -- hp = &p_fs->FAT_cache_hash_list[off]; -- bp->hash_next = hp->hash_next; -- bp->hash_prev = hp; -- hp->hash_next->hash_prev = bp; -- hp->hash_next = bp; --} -- --static void FAT_cache_remove_hash(struct buf_cache_t *bp) --{ -- (bp->hash_prev)->hash_next = bp->hash_next; -- (bp->hash_next)->hash_prev = bp->hash_prev; --} -- --static void buf_cache_insert_hash(struct super_block *sb, -- struct buf_cache_t *bp) --{ -- s32 off; -- struct buf_cache_t *hp; -- struct fs_info_t *p_fs; -- -- p_fs = &(EXFAT_SB(sb)->fs_info); -- off = (bp->sec + -- (bp->sec >> p_fs->sectors_per_clu_bits)) & -- (BUF_CACHE_HASH_SIZE - 1); -- -- hp = &p_fs->buf_cache_hash_list[off]; -- bp->hash_next = hp->hash_next; -- bp->hash_prev = hp; -- hp->hash_next->hash_prev = bp; -- hp->hash_next = bp; --} -- --static void buf_cache_remove_hash(struct buf_cache_t *bp) --{ -- (bp->hash_prev)->hash_next = bp->hash_next; -- (bp->hash_next)->hash_prev = bp->hash_prev; --} -- --void exfat_buf_init(struct super_block *sb) --{ -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- int i; -- -- /* LRU list */ -- p_fs->FAT_cache_lru_list.next = &p_fs->FAT_cache_lru_list; -- p_fs->FAT_cache_lru_list.prev = &p_fs->FAT_cache_lru_list; -- -- for (i = 0; i < FAT_CACHE_SIZE; i++) { -- p_fs->FAT_cache_array[i].drv = -1; -- p_fs->FAT_cache_array[i].sec = ~0; -- p_fs->FAT_cache_array[i].flag = 0; -- p_fs->FAT_cache_array[i].buf_bh = NULL; -- p_fs->FAT_cache_array[i].prev = NULL; -- p_fs->FAT_cache_array[i].next = NULL; -- push_to_mru(&p_fs->FAT_cache_array[i], -- &p_fs->FAT_cache_lru_list); -- } -- -- p_fs->buf_cache_lru_list.next = &p_fs->buf_cache_lru_list; -- p_fs->buf_cache_lru_list.prev = &p_fs->buf_cache_lru_list; -- -- for (i = 0; i < BUF_CACHE_SIZE; i++) { -- p_fs->buf_cache_array[i].drv = -1; -- p_fs->buf_cache_array[i].sec = ~0; -- p_fs->buf_cache_array[i].flag = 0; -- p_fs->buf_cache_array[i].buf_bh = NULL; -- p_fs->buf_cache_array[i].prev = NULL; -- p_fs->buf_cache_array[i].next = NULL; -- push_to_mru(&p_fs->buf_cache_array[i], -- &p_fs->buf_cache_lru_list); -- } -- -- /* HASH list */ -- for (i = 0; i < FAT_CACHE_HASH_SIZE; i++) { -- p_fs->FAT_cache_hash_list[i].drv = -1; -- p_fs->FAT_cache_hash_list[i].sec = ~0; -- p_fs->FAT_cache_hash_list[i].hash_next = -- &p_fs->FAT_cache_hash_list[i]; -- p_fs->FAT_cache_hash_list[i].hash_prev = -- &p_fs->FAT_cache_hash_list[i]; -- } -- -- for (i = 0; i < FAT_CACHE_SIZE; i++) -- FAT_cache_insert_hash(sb, &p_fs->FAT_cache_array[i]); -- -- for (i = 0; i < BUF_CACHE_HASH_SIZE; i++) { -- p_fs->buf_cache_hash_list[i].drv = -1; -- p_fs->buf_cache_hash_list[i].sec = ~0; -- p_fs->buf_cache_hash_list[i].hash_next = -- &p_fs->buf_cache_hash_list[i]; -- p_fs->buf_cache_hash_list[i].hash_prev = -- &p_fs->buf_cache_hash_list[i]; -- } -- -- for (i = 0; i < BUF_CACHE_SIZE; i++) -- buf_cache_insert_hash(sb, &p_fs->buf_cache_array[i]); --} -- --void exfat_buf_shutdown(struct super_block *sb) --{ --} -- --static int __exfat_fat_read(struct super_block *sb, u32 loc, u32 *content) --{ -- s32 off; -- u32 _content; -- sector_t sec; -- u8 *fat_sector, *fat_entry; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- -- sec = p_fs->FAT1_start_sector + -- (loc >> (p_bd->sector_size_bits - 2)); -- off = (loc << 2) & p_bd->sector_size_mask; -- -- fat_sector = exfat_fat_getblk(sb, sec); -- if (!fat_sector) -- return -1; -- -- fat_entry = &fat_sector[off]; -- _content = GET32_A(fat_entry); -- -- if (_content >= CLUSTER_32(0xFFFFFFF8)) { -- *content = CLUSTER_32(~0); -- return 0; -- } -- *content = CLUSTER_32(_content); -- return 0; --} -- --/* in : sb, loc -- * out: content -- * returns 0 on success -- * -1 on error -- */ --int exfat_fat_read(struct super_block *sb, u32 loc, u32 *content) --{ -- s32 ret; -- -- mutex_lock(&f_mutex); -- ret = __exfat_fat_read(sb, loc, content); -- mutex_unlock(&f_mutex); -- -- return ret; --} -- --static s32 __exfat_fat_write(struct super_block *sb, u32 loc, u32 content) --{ -- s32 off; -- sector_t sec; -- u8 *fat_sector, *fat_entry; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- -- sec = p_fs->FAT1_start_sector + (loc >> -- (p_bd->sector_size_bits - 2)); -- off = (loc << 2) & p_bd->sector_size_mask; -- -- fat_sector = exfat_fat_getblk(sb, sec); -- if (!fat_sector) -- return -1; -- -- fat_entry = &fat_sector[off]; -- -- SET32_A(fat_entry, content); -- -- exfat_fat_modify(sb, sec); -- return 0; --} -- --int exfat_fat_write(struct super_block *sb, u32 loc, u32 content) --{ -- s32 ret; -- -- mutex_lock(&f_mutex); -- ret = __exfat_fat_write(sb, loc, content); -- mutex_unlock(&f_mutex); -- -- return ret; --} -- --u8 *exfat_fat_getblk(struct super_block *sb, sector_t sec) --{ -- struct buf_cache_t *bp; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- bp = FAT_cache_find(sb, sec); -- if (bp) { -- move_to_mru(bp, &p_fs->FAT_cache_lru_list); -- return bp->buf_bh->b_data; -- } -- -- bp = FAT_cache_get(sb, sec); -- -- FAT_cache_remove_hash(bp); -- -- bp->drv = p_fs->drv; -- bp->sec = sec; -- bp->flag = 0; -- -- FAT_cache_insert_hash(sb, bp); -- -- if (sector_read(sb, sec, &bp->buf_bh, 1) != 0) { -- 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; --} -- --void exfat_fat_modify(struct super_block *sb, sector_t sec) --{ -- struct buf_cache_t *bp; -- -- bp = FAT_cache_find(sb, sec); -- if (bp) -- sector_write(sb, sec, bp->buf_bh, 0); --} -- --void exfat_fat_release_all(struct super_block *sb) --{ -- struct buf_cache_t *bp; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- mutex_lock(&f_mutex); -- -- bp = p_fs->FAT_cache_lru_list.next; -- while (bp != &p_fs->FAT_cache_lru_list) { -- if (bp->drv == p_fs->drv) { -- bp->drv = -1; -- bp->sec = ~0; -- bp->flag = 0; -- -- if (bp->buf_bh) { -- __brelse(bp->buf_bh); -- bp->buf_bh = NULL; -- } -- } -- bp = bp->next; -- } -- -- mutex_unlock(&f_mutex); --} -- --void exfat_fat_sync(struct super_block *sb) --{ -- struct buf_cache_t *bp; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- mutex_lock(&f_mutex); -- -- bp = p_fs->FAT_cache_lru_list.next; -- while (bp != &p_fs->FAT_cache_lru_list) { -- if ((bp->drv == p_fs->drv) && (bp->flag & DIRTYBIT)) { -- sync_dirty_buffer(bp->buf_bh); -- bp->flag &= ~(DIRTYBIT); -- } -- bp = bp->next; -- } -- -- mutex_unlock(&f_mutex); --} -- --static struct buf_cache_t *buf_cache_find(struct super_block *sb, sector_t sec) --{ -- s32 off; -- struct buf_cache_t *bp, *hp; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- off = (sec + (sec >> p_fs->sectors_per_clu_bits)) & -- (BUF_CACHE_HASH_SIZE - 1); -- -- hp = &p_fs->buf_cache_hash_list[off]; -- for (bp = hp->hash_next; bp != hp; bp = bp->hash_next) { -- if ((bp->drv == p_fs->drv) && (bp->sec == sec)) { -- touch_buffer(bp->buf_bh); -- return bp; -- } -- } -- return NULL; --} -- --static struct buf_cache_t *buf_cache_get(struct super_block *sb, sector_t sec) --{ -- struct buf_cache_t *bp; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- bp = p_fs->buf_cache_lru_list.prev; -- while (bp->flag & LOCKBIT) -- bp = bp->prev; -- -- move_to_mru(bp, &p_fs->buf_cache_lru_list); -- return bp; --} -- --static u8 *__exfat_buf_getblk(struct super_block *sb, sector_t sec) --{ -- struct buf_cache_t *bp; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- bp = buf_cache_find(sb, sec); -- if (bp) { -- move_to_mru(bp, &p_fs->buf_cache_lru_list); -- return bp->buf_bh->b_data; -- } -- -- bp = buf_cache_get(sb, sec); -- -- buf_cache_remove_hash(bp); -- -- bp->drv = p_fs->drv; -- bp->sec = sec; -- bp->flag = 0; -- -- buf_cache_insert_hash(sb, bp); -- -- if (sector_read(sb, sec, &bp->buf_bh, 1) != 0) { -- buf_cache_remove_hash(bp); -- bp->drv = -1; -- bp->sec = ~0; -- bp->flag = 0; -- bp->buf_bh = NULL; -- -- move_to_lru(bp, &p_fs->buf_cache_lru_list); -- return NULL; -- } -- -- return bp->buf_bh->b_data; --} -- --u8 *exfat_buf_getblk(struct super_block *sb, sector_t sec) --{ -- u8 *buf; -- -- mutex_lock(&b_mutex); -- buf = __exfat_buf_getblk(sb, sec); -- mutex_unlock(&b_mutex); -- -- return buf; --} -- --void exfat_buf_modify(struct super_block *sb, sector_t sec) --{ -- struct buf_cache_t *bp; -- -- mutex_lock(&b_mutex); -- -- bp = buf_cache_find(sb, sec); -- if (likely(bp)) -- sector_write(sb, sec, bp->buf_bh, 0); -- -- WARN(!bp, "[EXFAT] failed to find buffer_cache(sector:%llu).\n", -- (unsigned long long)sec); -- -- mutex_unlock(&b_mutex); --} -- --void exfat_buf_lock(struct super_block *sb, sector_t sec) --{ -- struct buf_cache_t *bp; -- -- mutex_lock(&b_mutex); -- -- bp = buf_cache_find(sb, sec); -- if (likely(bp)) -- bp->flag |= LOCKBIT; -- -- WARN(!bp, "[EXFAT] failed to find buffer_cache(sector:%llu).\n", -- (unsigned long long)sec); -- -- mutex_unlock(&b_mutex); --} -- --void exfat_buf_unlock(struct super_block *sb, sector_t sec) --{ -- struct buf_cache_t *bp; -- -- mutex_lock(&b_mutex); -- -- bp = buf_cache_find(sb, sec); -- if (likely(bp)) -- bp->flag &= ~(LOCKBIT); -- -- WARN(!bp, "[EXFAT] failed to find buffer_cache(sector:%llu).\n", -- (unsigned long long)sec); -- -- mutex_unlock(&b_mutex); --} -- --void exfat_buf_release(struct super_block *sb, sector_t sec) --{ -- struct buf_cache_t *bp; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- mutex_lock(&b_mutex); -- -- bp = buf_cache_find(sb, sec); -- if (likely(bp)) { -- bp->drv = -1; -- bp->sec = ~0; -- bp->flag = 0; -- -- if (bp->buf_bh) { -- __brelse(bp->buf_bh); -- bp->buf_bh = NULL; -- } -- -- move_to_lru(bp, &p_fs->buf_cache_lru_list); -- } -- -- mutex_unlock(&b_mutex); --} -- --void exfat_buf_release_all(struct super_block *sb) --{ -- struct buf_cache_t *bp; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- mutex_lock(&b_mutex); -- -- bp = p_fs->buf_cache_lru_list.next; -- while (bp != &p_fs->buf_cache_lru_list) { -- if (bp->drv == p_fs->drv) { -- bp->drv = -1; -- bp->sec = ~0; -- bp->flag = 0; -- -- if (bp->buf_bh) { -- __brelse(bp->buf_bh); -- bp->buf_bh = NULL; -- } -- } -- bp = bp->next; -- } -- -- mutex_unlock(&b_mutex); --} -- --void exfat_buf_sync(struct super_block *sb) --{ -- struct buf_cache_t *bp; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- mutex_lock(&b_mutex); -- -- bp = p_fs->buf_cache_lru_list.next; -- while (bp != &p_fs->buf_cache_lru_list) { -- if ((bp->drv == p_fs->drv) && (bp->flag & DIRTYBIT)) { -- sync_dirty_buffer(bp->buf_bh); -- bp->flag &= ~(DIRTYBIT); -- } -- bp = bp->next; -- } -- -- mutex_unlock(&b_mutex); --} -diff -Nurp linux-5.6.3.orig/drivers/staging/exfat/exfat_core.c linux-5.6.3/drivers/staging/exfat/exfat_core.c ---- linux-5.6.3.orig/drivers/staging/exfat/exfat_core.c 2020-03-30 01:25:41.000000000 +0300 -+++ linux-5.6.3/drivers/staging/exfat/exfat_core.c 1970-01-01 02:00:00.000000000 +0200 -@@ -1,2582 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0-or-later --/* -- * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -- */ -- --#include --#include --#include --#include --#include --#include --#include "exfat.h" -- --static void __set_sb_dirty(struct super_block *sb) --{ -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- -- sbi->s_dirt = 1; --} -- --static u8 name_buf[MAX_PATH_LENGTH * MAX_CHARSET_SIZE]; -- --static u8 free_bit[] = { -- 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, /* 0 ~ 19 */ -- 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, /* 20 ~ 39 */ -- 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, /* 40 ~ 59 */ -- 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, /* 60 ~ 79 */ -- 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, /* 80 ~ 99 */ -- 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, /* 100 ~ 119 */ -- 0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, /* 120 ~ 139 */ -- 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, /* 140 ~ 159 */ -- 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, /* 160 ~ 179 */ -- 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, /* 180 ~ 199 */ -- 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, /* 200 ~ 219 */ -- 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, /* 220 ~ 239 */ -- 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 /* 240 ~ 254 */ --}; -- --static u8 used_bit[] = { -- 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, /* 0 ~ 19 */ -- 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, /* 20 ~ 39 */ -- 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, /* 40 ~ 59 */ -- 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, /* 60 ~ 79 */ -- 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, /* 80 ~ 99 */ -- 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, /* 100 ~ 119 */ -- 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, /* 120 ~ 139 */ -- 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 140 ~ 159 */ -- 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, /* 160 ~ 179 */ -- 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, /* 180 ~ 199 */ -- 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, /* 200 ~ 219 */ -- 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 220 ~ 239 */ -- 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 /* 240 ~ 255 */ --}; -- --#define BITMAP_LOC(v) ((v) >> 3) --#define BITMAP_SHIFT(v) ((v) & 0x07) -- --static inline s32 exfat_bitmap_test(u8 *bitmap, int i) --{ -- u8 data; -- -- data = bitmap[BITMAP_LOC(i)]; -- if ((data >> BITMAP_SHIFT(i)) & 0x01) -- return 1; -- return 0; --} -- --static inline void exfat_bitmap_set(u8 *bitmap, int i) --{ -- bitmap[BITMAP_LOC(i)] |= (0x01 << BITMAP_SHIFT(i)); --} -- --static inline void exfat_bitmap_clear(u8 *bitmap, int i) --{ -- bitmap[BITMAP_LOC(i)] &= ~(0x01 << BITMAP_SHIFT(i)); --} -- --/* -- * File System Management Functions -- */ -- --void fs_set_vol_flags(struct super_block *sb, u32 new_flag) --{ -- struct pbr_sector_t *p_pbr; -- struct bpbex_t *p_bpb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- if (p_fs->vol_flag == new_flag) -- return; -- -- p_fs->vol_flag = new_flag; -- -- if (!p_fs->pbr_bh) { -- if (sector_read(sb, p_fs->PBR_sector, -- &p_fs->pbr_bh, 1) != 0) -- return; -- } -- -- p_pbr = (struct pbr_sector_t *)p_fs->pbr_bh->b_data; -- p_bpb = (struct bpbex_t *)p_pbr->bpb; -- SET16(p_bpb->vol_flags, (u16)new_flag); -- -- /* XXX duyoung -- * what can we do here? (cuz fs_set_vol_flags() is void) -- */ -- if ((new_flag == VOL_DIRTY) && (!buffer_dirty(p_fs->pbr_bh))) -- sector_write(sb, p_fs->PBR_sector, p_fs->pbr_bh, 1); -- else -- sector_write(sb, p_fs->PBR_sector, p_fs->pbr_bh, 0); --} -- --void fs_error(struct super_block *sb) --{ -- struct exfat_mount_options *opts = &EXFAT_SB(sb)->options; -- -- if (opts->errors == EXFAT_ERRORS_PANIC) { -- panic("[EXFAT] Filesystem panic from previous error\n"); -- } else if ((opts->errors == EXFAT_ERRORS_RO) && !sb_rdonly(sb)) { -- sb->s_flags |= SB_RDONLY; -- pr_err("[EXFAT] Filesystem has been set read-only\n"); -- } --} -- --/* -- * Cluster Management Functions -- */ -- --static s32 clear_cluster(struct super_block *sb, u32 clu) --{ -- sector_t s, n; -- s32 ret = 0; -- struct buffer_head *tmp_bh = NULL; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- -- if (clu == CLUSTER_32(0)) { /* FAT16 root_dir */ -- s = p_fs->root_start_sector; -- n = p_fs->data_start_sector; -- } else { -- s = START_SECTOR(clu); -- n = s + p_fs->sectors_per_clu; -- } -- -- for (; s < n; s++) { -- ret = sector_read(sb, s, &tmp_bh, 0); -- if (ret != 0) -- return ret; -- -- memset((char *)tmp_bh->b_data, 0x0, p_bd->sector_size); -- ret = sector_write(sb, s, tmp_bh, 0); -- if (ret != 0) -- break; -- } -- -- brelse(tmp_bh); -- return ret; --} -- --static s32 set_alloc_bitmap(struct super_block *sb, u32 clu) --{ -- int i, b; -- sector_t sector; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- -- i = clu >> (p_bd->sector_size_bits + 3); -- b = clu & ((p_bd->sector_size << 3) - 1); -- -- sector = START_SECTOR(p_fs->map_clu) + i; -- -- exfat_bitmap_set((u8 *)p_fs->vol_amap[i]->b_data, b); -- -- return sector_write(sb, sector, p_fs->vol_amap[i], 0); --} -- --static s32 clr_alloc_bitmap(struct super_block *sb, u32 clu) --{ -- int i, b; -- sector_t sector; --#ifdef CONFIG_STAGING_EXFAT_DISCARD -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- struct exfat_mount_options *opts = &sbi->options; -- int ret; --#endif /* CONFIG_STAGING_EXFAT_DISCARD */ -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- -- i = clu >> (p_bd->sector_size_bits + 3); -- b = clu & ((p_bd->sector_size << 3) - 1); -- -- sector = START_SECTOR(p_fs->map_clu) + i; -- -- exfat_bitmap_clear((u8 *)p_fs->vol_amap[i]->b_data, b); -- --#ifdef CONFIG_STAGING_EXFAT_DISCARD -- if (opts->discard) { -- ret = sb_issue_discard(sb, START_SECTOR(clu), -- (1 << p_fs->sectors_per_clu_bits), -- GFP_NOFS, 0); -- if (ret == -EOPNOTSUPP) { -- pr_warn("discard not supported by device, disabling"); -- opts->discard = 0; -- } else { -- return ret; -- } -- } --#endif /* CONFIG_STAGING_EXFAT_DISCARD */ -- -- return sector_write(sb, sector, p_fs->vol_amap[i], 0); --} -- --static u32 test_alloc_bitmap(struct super_block *sb, u32 clu) --{ -- int i, map_i, map_b; -- u32 clu_base, clu_free; -- u8 k, clu_mask; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- -- clu_base = (clu & ~(0x7)) + 2; -- clu_mask = (1 << (clu - clu_base + 2)) - 1; -- -- map_i = clu >> (p_bd->sector_size_bits + 3); -- map_b = (clu >> 3) & p_bd->sector_size_mask; -- -- for (i = 2; i < p_fs->num_clusters; i += 8) { -- k = *(((u8 *)p_fs->vol_amap[map_i]->b_data) + map_b); -- if (clu_mask > 0) { -- k |= clu_mask; -- clu_mask = 0; -- } -- if (k < 0xFF) { -- clu_free = clu_base + free_bit[k]; -- if (clu_free < p_fs->num_clusters) -- return clu_free; -- } -- clu_base += 8; -- -- if (((++map_b) >= p_bd->sector_size) || -- (clu_base >= p_fs->num_clusters)) { -- if ((++map_i) >= p_fs->map_sectors) { -- clu_base = 2; -- map_i = 0; -- } -- map_b = 0; -- } -- } -- -- return CLUSTER_32(~0); --} -- --s32 exfat_alloc_cluster(struct super_block *sb, s32 num_alloc, -- struct chain_t *p_chain) --{ -- s32 num_clusters = 0; -- u32 hint_clu, new_clu, last_clu = CLUSTER_32(~0); -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- hint_clu = p_chain->dir; -- if (hint_clu == CLUSTER_32(~0)) { -- hint_clu = test_alloc_bitmap(sb, p_fs->clu_srch_ptr - 2); -- if (hint_clu == CLUSTER_32(~0)) -- return 0; -- } else if (hint_clu >= p_fs->num_clusters) { -- hint_clu = 2; -- p_chain->flags = 0x01; -- } -- -- __set_sb_dirty(sb); -- -- p_chain->dir = CLUSTER_32(~0); -- -- while ((new_clu = test_alloc_bitmap(sb, hint_clu - 2)) != CLUSTER_32(~0)) { -- if (new_clu != hint_clu) { -- if (p_chain->flags == 0x03) { -- exfat_chain_cont_cluster(sb, p_chain->dir, -- num_clusters); -- p_chain->flags = 0x01; -- } -- } -- -- if (set_alloc_bitmap(sb, new_clu - 2) != 0) -- return -EIO; -- -- num_clusters++; -- -- if (p_chain->flags == 0x01) { -- if (exfat_fat_write(sb, new_clu, CLUSTER_32(~0)) < 0) -- return -EIO; -- } -- -- if (p_chain->dir == CLUSTER_32(~0)) { -- p_chain->dir = new_clu; -- } else { -- if (p_chain->flags == 0x01) { -- if (exfat_fat_write(sb, last_clu, new_clu) < 0) -- return -EIO; -- } -- } -- last_clu = new_clu; -- -- if ((--num_alloc) == 0) { -- p_fs->clu_srch_ptr = hint_clu; -- if (p_fs->used_clusters != UINT_MAX) -- p_fs->used_clusters += num_clusters; -- -- p_chain->size += num_clusters; -- return num_clusters; -- } -- -- hint_clu = new_clu + 1; -- if (hint_clu >= p_fs->num_clusters) { -- hint_clu = 2; -- -- if (p_chain->flags == 0x03) { -- exfat_chain_cont_cluster(sb, p_chain->dir, -- num_clusters); -- p_chain->flags = 0x01; -- } -- } -- } -- -- p_fs->clu_srch_ptr = hint_clu; -- if (p_fs->used_clusters != UINT_MAX) -- p_fs->used_clusters += num_clusters; -- -- p_chain->size += num_clusters; -- return num_clusters; --} -- --void exfat_free_cluster(struct super_block *sb, struct chain_t *p_chain, -- s32 do_relse) --{ -- s32 num_clusters = 0; -- u32 clu; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- int i; -- sector_t sector; -- -- if ((p_chain->dir == CLUSTER_32(0)) || (p_chain->dir == CLUSTER_32(~0))) -- return; -- -- if (p_chain->size <= 0) { -- pr_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) { -- do { -- if (do_relse) { -- sector = START_SECTOR(clu); -- for (i = 0; i < p_fs->sectors_per_clu; i++) -- exfat_buf_release(sb, sector + i); -- } -- -- if (clr_alloc_bitmap(sb, clu - 2) != 0) -- break; -- clu++; -- -- num_clusters++; -- } while (num_clusters < p_chain->size); -- } else { -- do { -- if (p_fs->dev_ejected) -- break; -- -- if (do_relse) { -- sector = START_SECTOR(clu); -- for (i = 0; i < p_fs->sectors_per_clu; i++) -- exfat_buf_release(sb, sector + i); -- } -- -- if (clr_alloc_bitmap(sb, clu - 2) != 0) -- break; -- -- if (exfat_fat_read(sb, clu, &clu) == -1) -- break; -- num_clusters++; -- } while ((clu != CLUSTER_32(0)) && (clu != CLUSTER_32(~0))); -- } -- -- if (p_fs->used_clusters != UINT_MAX) -- p_fs->used_clusters -= num_clusters; --} -- --static u32 find_last_cluster(struct super_block *sb, struct chain_t *p_chain) --{ -- u32 clu, next; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- clu = p_chain->dir; -- -- if (p_chain->flags == 0x03) { -- clu += p_chain->size - 1; -- } else { -- while ((exfat_fat_read(sb, clu, &next) == 0) && -- (next != CLUSTER_32(~0))) { -- if (p_fs->dev_ejected) -- break; -- clu = next; -- } -- } -- -- return clu; --} -- --s32 count_num_clusters(struct super_block *sb, struct chain_t *p_chain) --{ -- int i, count = 0; -- u32 clu; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- if ((p_chain->dir == CLUSTER_32(0)) || (p_chain->dir == CLUSTER_32(~0))) -- return 0; -- -- clu = p_chain->dir; -- -- if (p_chain->flags == 0x03) { -- count = p_chain->size; -- } else { -- for (i = 2; i < p_fs->num_clusters; i++) { -- count++; -- if (exfat_fat_read(sb, clu, &clu) != 0) -- return 0; -- if (clu == CLUSTER_32(~0)) -- break; -- } -- } -- -- return count; --} -- --s32 exfat_count_used_clusters(struct super_block *sb) --{ -- int i, map_i, map_b, count = 0; -- u8 k; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- -- map_i = 0; -- map_b = 0; -- -- for (i = 2; i < p_fs->num_clusters; i += 8) { -- k = *(((u8 *)p_fs->vol_amap[map_i]->b_data) + map_b); -- count += used_bit[k]; -- -- if ((++map_b) >= p_bd->sector_size) { -- map_i++; -- map_b = 0; -- } -- } -- -- return count; --} -- --void exfat_chain_cont_cluster(struct super_block *sb, u32 chain, s32 len) --{ -- if (len == 0) -- return; -- -- while (len > 1) { -- if (exfat_fat_write(sb, chain, chain + 1) < 0) -- break; -- chain++; -- len--; -- } -- exfat_fat_write(sb, chain, CLUSTER_32(~0)); --} -- --/* -- * Allocation Bitmap Management Functions -- */ -- --s32 load_alloc_bitmap(struct super_block *sb) --{ -- int i, j, ret; -- u32 map_size; -- u32 type; -- sector_t sector; -- struct chain_t clu; -- struct bmap_dentry_t *ep; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- -- clu.dir = p_fs->root_dir; -- clu.flags = 0x01; -- -- while (clu.dir != CLUSTER_32(~0)) { -- if (p_fs->dev_ejected) -- break; -- -- for (i = 0; i < p_fs->dentries_per_clu; i++) { -- ep = (struct bmap_dentry_t *)get_entry_in_dir(sb, &clu, -- i, NULL); -- if (!ep) -- return -ENOENT; -- -- type = exfat_get_entry_type((struct dentry_t *)ep); -- -- if (type == TYPE_UNUSED) -- break; -- if (type != TYPE_BITMAP) -- continue; -- -- if (ep->flags == 0x0) { -- p_fs->map_clu = GET32_A(ep->start_clu); -- map_size = (u32)GET64_A(ep->size); -- -- p_fs->map_sectors = ((map_size - 1) >> p_bd->sector_size_bits) + 1; -- -- p_fs->vol_amap = kmalloc_array(p_fs->map_sectors, -- sizeof(struct buffer_head *), -- GFP_KERNEL); -- if (!p_fs->vol_amap) -- return -ENOMEM; -- -- sector = START_SECTOR(p_fs->map_clu); -- -- for (j = 0; j < p_fs->map_sectors; j++) { -- p_fs->vol_amap[j] = NULL; -- ret = sector_read(sb, sector + j, &p_fs->vol_amap[j], 1); -- if (ret != 0) { -- /* release all buffers and free vol_amap */ -- i = 0; -- while (i < j) -- brelse(p_fs->vol_amap[i++]); -- -- kfree(p_fs->vol_amap); -- p_fs->vol_amap = NULL; -- return ret; -- } -- } -- -- p_fs->pbr_bh = NULL; -- return 0; -- } -- } -- -- if (exfat_fat_read(sb, clu.dir, &clu.dir) != 0) -- return -EIO; -- } -- -- return -EFSCORRUPTED; --} -- --void free_alloc_bitmap(struct super_block *sb) --{ -- int i; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- brelse(p_fs->pbr_bh); -- -- for (i = 0; i < p_fs->map_sectors; i++) -- __brelse(p_fs->vol_amap[i]); -- -- kfree(p_fs->vol_amap); -- p_fs->vol_amap = NULL; --} -- --void sync_alloc_bitmap(struct super_block *sb) --{ -- int i; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- if (!p_fs->vol_amap) -- return; -- -- for (i = 0; i < p_fs->map_sectors; i++) -- sync_dirty_buffer(p_fs->vol_amap[i]); --} -- --/* -- * Upcase table Management Functions -- */ --static s32 __load_upcase_table(struct super_block *sb, sector_t sector, -- u32 num_sectors, u32 utbl_checksum) --{ -- int i, ret = -EINVAL; -- u32 j; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- struct buffer_head *tmp_bh = NULL; -- sector_t end_sector = num_sectors + sector; -- -- bool skip = false; -- u32 index = 0; -- u16 uni = 0; -- u16 **upcase_table; -- -- u32 checksum = 0; -- -- upcase_table = kmalloc_array(UTBL_COL_COUNT, sizeof(u16 *), GFP_KERNEL); -- p_fs->vol_utbl = upcase_table; -- if (!upcase_table) -- return -ENOMEM; -- memset(upcase_table, 0, UTBL_COL_COUNT * sizeof(u16 *)); -- -- while (sector < end_sector) { -- ret = sector_read(sb, sector, &tmp_bh, 1); -- if (ret != 0) { -- pr_debug("sector read (0x%llX)fail\n", -- (unsigned long long)sector); -- goto error; -- } -- sector++; -- -- for (i = 0; i < p_bd->sector_size && index <= 0xFFFF; i += 2) { -- uni = GET16(((u8 *)tmp_bh->b_data) + i); -- -- checksum = ((checksum & 1) ? 0x80000000 : 0) + -- (checksum >> 1) + *(((u8 *)tmp_bh->b_data) + -- i); -- checksum = ((checksum & 1) ? 0x80000000 : 0) + -- (checksum >> 1) + *(((u8 *)tmp_bh->b_data) + -- (i + 1)); -- -- if (skip) { -- pr_debug("skip from 0x%X ", index); -- index += uni; -- pr_debug("to 0x%X (amount of 0x%X)\n", -- index, uni); -- skip = false; -- } else if (uni == index) { -- index++; -- } else if (uni == 0xFFFF) { -- skip = true; -- } else { /* uni != index , uni != 0xFFFF */ -- u16 col_index = get_col_index(index); -- -- if (!upcase_table[col_index]) { -- pr_debug("alloc = 0x%X\n", col_index); -- upcase_table[col_index] = kmalloc_array(UTBL_ROW_COUNT, -- sizeof(u16), GFP_KERNEL); -- if (!upcase_table[col_index]) { -- ret = -ENOMEM; -- goto error; -- } -- -- for (j = 0; j < UTBL_ROW_COUNT; j++) -- upcase_table[col_index][j] = (col_index << LOW_INDEX_BIT) | j; -- } -- -- upcase_table[col_index][get_row_index(index)] = uni; -- index++; -- } -- } -- } -- if (index >= 0xFFFF && utbl_checksum == checksum) { -- if (tmp_bh) -- brelse(tmp_bh); -- return 0; -- } -- ret = -EINVAL; --error: -- if (tmp_bh) -- brelse(tmp_bh); -- free_upcase_table(sb); -- return ret; --} -- --static s32 __load_default_upcase_table(struct super_block *sb) --{ -- int i, ret = -EINVAL; -- u32 j; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- bool skip = false; -- u32 index = 0; -- u16 uni = 0; -- u16 **upcase_table; -- -- upcase_table = kmalloc_array(UTBL_COL_COUNT, sizeof(u16 *), GFP_KERNEL); -- p_fs->vol_utbl = upcase_table; -- if (!upcase_table) -- return -ENOMEM; -- memset(upcase_table, 0, UTBL_COL_COUNT * sizeof(u16 *)); -- -- for (i = 0; index <= 0xFFFF && i < NUM_UPCASE * 2; i += 2) { -- uni = GET16(uni_upcase + i); -- if (skip) { -- pr_debug("skip from 0x%X ", index); -- index += uni; -- pr_debug("to 0x%X (amount of 0x%X)\n", index, uni); -- skip = false; -- } else if (uni == index) { -- index++; -- } else if (uni == 0xFFFF) { -- skip = true; -- } else { /* uni != index , uni != 0xFFFF */ -- u16 col_index = get_col_index(index); -- -- if (!upcase_table[col_index]) { -- pr_debug("alloc = 0x%X\n", col_index); -- upcase_table[col_index] = kmalloc_array(UTBL_ROW_COUNT, -- sizeof(u16), -- GFP_KERNEL); -- if (!upcase_table[col_index]) { -- ret = -ENOMEM; -- goto error; -- } -- -- for (j = 0; j < UTBL_ROW_COUNT; j++) -- upcase_table[col_index][j] = (col_index << LOW_INDEX_BIT) | j; -- } -- -- upcase_table[col_index][get_row_index(index)] = uni; -- index++; -- } -- } -- -- if (index >= 0xFFFF) -- return 0; -- --error: -- /* FATAL error: default upcase table has error */ -- free_upcase_table(sb); -- return ret; --} -- --s32 load_upcase_table(struct super_block *sb) --{ -- int i; -- u32 tbl_clu, tbl_size; -- sector_t sector; -- u32 type, num_sectors; -- struct chain_t clu; -- struct case_dentry_t *ep; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- -- clu.dir = p_fs->root_dir; -- clu.flags = 0x01; -- -- if (p_fs->dev_ejected) -- return -EIO; -- -- while (clu.dir != CLUSTER_32(~0)) { -- for (i = 0; i < p_fs->dentries_per_clu; i++) { -- ep = (struct case_dentry_t *)get_entry_in_dir(sb, &clu, -- i, NULL); -- if (!ep) -- return -ENOENT; -- -- type = exfat_get_entry_type((struct dentry_t *)ep); -- -- if (type == TYPE_UNUSED) -- break; -- if (type != TYPE_UPCASE) -- continue; -- -- tbl_clu = GET32_A(ep->start_clu); -- tbl_size = (u32)GET64_A(ep->size); -- -- sector = START_SECTOR(tbl_clu); -- num_sectors = ((tbl_size - 1) >> p_bd->sector_size_bits) + 1; -- if (__load_upcase_table(sb, sector, num_sectors, -- GET32_A(ep->checksum)) != 0) -- break; -- return 0; -- } -- if (exfat_fat_read(sb, clu.dir, &clu.dir) != 0) -- return -EIO; -- } -- /* load default upcase table */ -- return __load_default_upcase_table(sb); --} -- --void free_upcase_table(struct super_block *sb) --{ -- u32 i; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- u16 **upcase_table; -- -- upcase_table = p_fs->vol_utbl; -- for (i = 0; i < UTBL_COL_COUNT; i++) -- kfree(upcase_table[i]); -- -- kfree(p_fs->vol_utbl); -- p_fs->vol_utbl = NULL; --} -- --/* -- * Directory Entry Management Functions -- */ -- --u32 exfat_get_entry_type(struct dentry_t *p_entry) --{ -- struct file_dentry_t *ep = (struct file_dentry_t *)p_entry; -- -- if (ep->type == 0x0) { -- return TYPE_UNUSED; -- } else if (ep->type < 0x80) { -- return TYPE_DELETED; -- } else if (ep->type == 0x80) { -- return TYPE_INVALID; -- } else if (ep->type < 0xA0) { -- if (ep->type == 0x81) { -- return TYPE_BITMAP; -- } else if (ep->type == 0x82) { -- return TYPE_UPCASE; -- } else if (ep->type == 0x83) { -- return TYPE_VOLUME; -- } else if (ep->type == 0x85) { -- if (GET16_A(ep->attr) & ATTR_SUBDIR) -- return TYPE_DIR; -- else -- return TYPE_FILE; -- } -- return TYPE_CRITICAL_PRI; -- } else if (ep->type < 0xC0) { -- if (ep->type == 0xA0) -- return TYPE_GUID; -- else if (ep->type == 0xA1) -- return TYPE_PADDING; -- else if (ep->type == 0xA2) -- return TYPE_ACLTAB; -- return TYPE_BENIGN_PRI; -- } else if (ep->type < 0xE0) { -- if (ep->type == 0xC0) -- return TYPE_STREAM; -- else if (ep->type == 0xC1) -- return TYPE_EXTEND; -- else if (ep->type == 0xC2) -- return TYPE_ACL; -- return TYPE_CRITICAL_SEC; -- } -- -- return TYPE_BENIGN_SEC; --} -- --static void exfat_set_entry_type(struct dentry_t *p_entry, u32 type) --{ -- struct file_dentry_t *ep = (struct file_dentry_t *)p_entry; -- -- if (type == TYPE_UNUSED) { -- ep->type = 0x0; -- } else if (type == TYPE_DELETED) { -- ep->type &= ~0x80; -- } else if (type == TYPE_STREAM) { -- ep->type = 0xC0; -- } else if (type == TYPE_EXTEND) { -- ep->type = 0xC1; -- } else if (type == TYPE_BITMAP) { -- ep->type = 0x81; -- } else if (type == TYPE_UPCASE) { -- ep->type = 0x82; -- } else if (type == TYPE_VOLUME) { -- ep->type = 0x83; -- } else if (type == TYPE_DIR) { -- ep->type = 0x85; -- SET16_A(ep->attr, ATTR_SUBDIR); -- } else if (type == TYPE_FILE) { -- ep->type = 0x85; -- SET16_A(ep->attr, ATTR_ARCHIVE); -- } else if (type == TYPE_SYMLINK) { -- ep->type = 0x85; -- SET16_A(ep->attr, ATTR_ARCHIVE | ATTR_SYMLINK); -- } --} -- --u32 exfat_get_entry_attr(struct dentry_t *p_entry) --{ -- struct file_dentry_t *ep = (struct file_dentry_t *)p_entry; -- -- return (u32)GET16_A(ep->attr); --} -- --void exfat_set_entry_attr(struct dentry_t *p_entry, u32 attr) --{ -- struct file_dentry_t *ep = (struct file_dentry_t *)p_entry; -- -- SET16_A(ep->attr, (u16)attr); --} -- --u8 exfat_get_entry_flag(struct dentry_t *p_entry) --{ -- struct strm_dentry_t *ep = (struct strm_dentry_t *)p_entry; -- -- return ep->flags; --} -- --void exfat_set_entry_flag(struct dentry_t *p_entry, u8 flags) --{ -- struct strm_dentry_t *ep = (struct strm_dentry_t *)p_entry; -- -- ep->flags = flags; --} -- --u32 exfat_get_entry_clu0(struct dentry_t *p_entry) --{ -- struct strm_dentry_t *ep = (struct strm_dentry_t *)p_entry; -- -- return GET32_A(ep->start_clu); --} -- --void exfat_set_entry_clu0(struct dentry_t *p_entry, u32 start_clu) --{ -- struct strm_dentry_t *ep = (struct strm_dentry_t *)p_entry; -- -- SET32_A(ep->start_clu, start_clu); --} -- --u64 exfat_get_entry_size(struct dentry_t *p_entry) --{ -- struct strm_dentry_t *ep = (struct strm_dentry_t *)p_entry; -- -- return GET64_A(ep->valid_size); --} -- --void exfat_set_entry_size(struct dentry_t *p_entry, u64 size) --{ -- struct strm_dentry_t *ep = (struct strm_dentry_t *)p_entry; -- -- SET64_A(ep->valid_size, size); -- SET64_A(ep->size, size); --} -- --void exfat_get_entry_time(struct dentry_t *p_entry, struct timestamp_t *tp, -- u8 mode) --{ -- u16 t = 0x00, d = 0x21; -- struct file_dentry_t *ep = (struct file_dentry_t *)p_entry; -- -- switch (mode) { -- case TM_CREATE: -- t = GET16_A(ep->create_time); -- d = GET16_A(ep->create_date); -- break; -- case TM_MODIFY: -- t = GET16_A(ep->modify_time); -- d = GET16_A(ep->modify_date); -- break; -- case TM_ACCESS: -- t = GET16_A(ep->access_time); -- d = GET16_A(ep->access_date); -- break; -- } -- -- tp->sec = (t & 0x001F) << 1; -- tp->min = (t >> 5) & 0x003F; -- tp->hour = (t >> 11); -- tp->day = (d & 0x001F); -- tp->mon = (d >> 5) & 0x000F; -- tp->year = (d >> 9); --} -- --void exfat_set_entry_time(struct dentry_t *p_entry, struct timestamp_t *tp, -- u8 mode) --{ -- u16 t, d; -- struct file_dentry_t *ep = (struct file_dentry_t *)p_entry; -- -- t = (tp->hour << 11) | (tp->min << 5) | (tp->sec >> 1); -- d = (tp->year << 9) | (tp->mon << 5) | tp->day; -- -- switch (mode) { -- case TM_CREATE: -- SET16_A(ep->create_time, t); -- SET16_A(ep->create_date, d); -- break; -- case TM_MODIFY: -- SET16_A(ep->modify_time, t); -- SET16_A(ep->modify_date, d); -- break; -- case TM_ACCESS: -- SET16_A(ep->access_time, t); -- SET16_A(ep->access_date, d); -- break; -- } --} -- --static void init_file_entry(struct file_dentry_t *ep, u32 type) --{ -- struct timestamp_t tm, *tp; -- -- exfat_set_entry_type((struct dentry_t *)ep, type); -- -- tp = tm_current(&tm); -- exfat_set_entry_time((struct dentry_t *)ep, tp, TM_CREATE); -- exfat_set_entry_time((struct dentry_t *)ep, tp, TM_MODIFY); -- exfat_set_entry_time((struct dentry_t *)ep, tp, TM_ACCESS); -- ep->create_time_ms = 0; -- ep->modify_time_ms = 0; -- ep->access_time_ms = 0; --} -- --static void init_strm_entry(struct strm_dentry_t *ep, u8 flags, u32 start_clu, u64 size) --{ -- exfat_set_entry_type((struct dentry_t *)ep, TYPE_STREAM); -- ep->flags = flags; -- SET32_A(ep->start_clu, start_clu); -- SET64_A(ep->valid_size, size); -- SET64_A(ep->size, size); --} -- --static void init_name_entry(struct name_dentry_t *ep, u16 *uniname) --{ -- int i; -- -- exfat_set_entry_type((struct dentry_t *)ep, TYPE_EXTEND); -- ep->flags = 0x0; -- -- for (i = 0; i < 30; i++, i++) { -- SET16_A(ep->unicode_0_14 + i, *uniname); -- if (*uniname == 0x0) -- break; -- uniname++; -- } --} -- --static s32 exfat_init_dir_entry(struct super_block *sb, struct chain_t *p_dir, -- s32 entry, u32 type, u32 start_clu, u64 size) --{ -- sector_t sector; -- u8 flags; -- struct file_dentry_t *file_ep; -- struct strm_dentry_t *strm_ep; -- -- flags = (type == TYPE_FILE) ? 0x01 : 0x03; -- -- /* we cannot use get_entry_set_in_dir here because file ep is not initialized yet */ -- file_ep = (struct file_dentry_t *)get_entry_in_dir(sb, p_dir, entry, -- §or); -- if (!file_ep) -- return -ENOENT; -- -- strm_ep = (struct strm_dentry_t *)get_entry_in_dir(sb, p_dir, entry + 1, -- §or); -- if (!strm_ep) -- return -ENOENT; -- -- init_file_entry(file_ep, type); -- exfat_buf_modify(sb, sector); -- -- init_strm_entry(strm_ep, flags, start_clu, size); -- exfat_buf_modify(sb, sector); -- -- return 0; --} -- --static s32 exfat_init_ext_entry(struct super_block *sb, struct chain_t *p_dir, -- s32 entry, s32 num_entries, -- struct uni_name_t *p_uniname, -- struct dos_name_t *p_dosname) --{ -- int i; -- sector_t sector; -- u16 *uniname = p_uniname->name; -- struct file_dentry_t *file_ep; -- struct strm_dentry_t *strm_ep; -- struct name_dentry_t *name_ep; -- -- file_ep = (struct file_dentry_t *)get_entry_in_dir(sb, p_dir, entry, -- §or); -- if (!file_ep) -- return -ENOENT; -- -- file_ep->num_ext = (u8)(num_entries - 1); -- exfat_buf_modify(sb, sector); -- -- strm_ep = (struct strm_dentry_t *)get_entry_in_dir(sb, p_dir, entry + 1, -- §or); -- if (!strm_ep) -- return -ENOENT; -- -- strm_ep->name_len = p_uniname->name_len; -- SET16_A(strm_ep->name_hash, p_uniname->name_hash); -- exfat_buf_modify(sb, sector); -- -- for (i = 2; i < num_entries; i++) { -- name_ep = (struct name_dentry_t *)get_entry_in_dir(sb, p_dir, -- entry + i, -- §or); -- if (!name_ep) -- return -ENOENT; -- -- init_name_entry(name_ep, uniname); -- exfat_buf_modify(sb, sector); -- uniname += 15; -- } -- -- update_dir_checksum(sb, p_dir, entry); -- -- return 0; --} -- --void exfat_delete_dir_entry(struct super_block *sb, struct chain_t *p_dir, -- s32 entry, s32 order, s32 num_entries) --{ -- int i; -- sector_t sector; -- struct dentry_t *ep; -- -- for (i = order; i < num_entries; i++) { -- ep = get_entry_in_dir(sb, p_dir, entry + i, §or); -- if (!ep) -- return; -- -- exfat_set_entry_type(ep, TYPE_DELETED); -- exfat_buf_modify(sb, sector); -- } --} -- --void update_dir_checksum(struct super_block *sb, struct chain_t *p_dir, -- s32 entry) --{ -- int i, num_entries; -- sector_t sector; -- u16 chksum; -- struct file_dentry_t *file_ep; -- struct dentry_t *ep; -- -- file_ep = (struct file_dentry_t *)get_entry_in_dir(sb, p_dir, entry, -- §or); -- if (!file_ep) -- return; -- -- exfat_buf_lock(sb, sector); -- -- num_entries = (s32)file_ep->num_ext + 1; -- chksum = calc_checksum_2byte((void *)file_ep, DENTRY_SIZE, 0, -- CS_DIR_ENTRY); -- -- for (i = 1; i < num_entries; i++) { -- ep = get_entry_in_dir(sb, p_dir, entry + i, NULL); -- if (!ep) { -- exfat_buf_unlock(sb, sector); -- return; -- } -- -- chksum = calc_checksum_2byte((void *)ep, DENTRY_SIZE, chksum, -- CS_DEFAULT); -- } -- -- SET16_A(file_ep->checksum, chksum); -- exfat_buf_modify(sb, sector); -- exfat_buf_unlock(sb, sector); --} -- --static s32 __write_partial_entries_in_entry_set(struct super_block *sb, -- struct entry_set_cache_t *es, -- sector_t sec, s32 off, u32 count) --{ -- s32 num_entries, buf_off = (off - es->offset); -- u32 remaining_byte_in_sector, copy_entries; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- u32 clu; -- u8 *buf, *esbuf = (u8 *)&es->__buf; -- -- pr_debug("%s entered es %p sec %llu off %d count %d\n", -- __func__, es, (unsigned long long)sec, off, count); -- num_entries = count; -- -- while (num_entries) { -- /* white per sector base */ -- remaining_byte_in_sector = (1 << p_bd->sector_size_bits) - off; -- copy_entries = min_t(s32, -- remaining_byte_in_sector >> DENTRY_SIZE_BITS, -- num_entries); -- buf = exfat_buf_getblk(sb, sec); -- if (!buf) -- goto err_out; -- pr_debug("es->buf %p buf_off %u\n", esbuf, buf_off); -- pr_debug("copying %d entries from %p to sector %llu\n", -- copy_entries, (esbuf + buf_off), -- (unsigned long long)sec); -- memcpy(buf + off, esbuf + buf_off, -- copy_entries << DENTRY_SIZE_BITS); -- exfat_buf_modify(sb, sec); -- num_entries -= copy_entries; -- -- if (num_entries) { -- /* get next sector */ -- if (IS_LAST_SECTOR_IN_CLUSTER(sec)) { -- clu = GET_CLUSTER_FROM_SECTOR(sec); -- if (es->alloc_flag == 0x03) { -- clu++; -- } else { -- if (exfat_fat_read(sb, clu, &clu) == -1) -- goto err_out; -- } -- sec = START_SECTOR(clu); -- } else { -- sec++; -- } -- off = 0; -- buf_off += copy_entries << DENTRY_SIZE_BITS; -- } -- } -- -- pr_debug("%s exited successfully\n", __func__); -- return 0; --err_out: -- pr_debug("%s failed\n", __func__); -- return -EINVAL; --} -- --/* write back all entries in entry set */ --static s32 write_whole_entry_set(struct super_block *sb, struct entry_set_cache_t *es) --{ -- return __write_partial_entries_in_entry_set(sb, es, es->sector, -- es->offset, -- es->num_entries); --} -- --void update_dir_checksum_with_entry_set(struct super_block *sb, -- struct entry_set_cache_t *es) --{ -- struct dentry_t *ep; -- u16 chksum = 0; -- s32 chksum_type = CS_DIR_ENTRY, i; -- -- ep = (struct dentry_t *)&es->__buf; -- for (i = 0; i < es->num_entries; i++) { -- pr_debug("%s ep %p\n", __func__, ep); -- chksum = calc_checksum_2byte((void *)ep, DENTRY_SIZE, chksum, -- chksum_type); -- ep++; -- chksum_type = CS_DEFAULT; -- } -- -- ep = (struct dentry_t *)&es->__buf; -- SET16_A(((struct file_dentry_t *)ep)->checksum, chksum); -- write_whole_entry_set(sb, es); --} -- --static s32 _walk_fat_chain(struct super_block *sb, struct chain_t *p_dir, -- s32 byte_offset, u32 *clu) --{ -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- s32 clu_offset; -- u32 cur_clu; -- -- clu_offset = byte_offset >> p_fs->cluster_size_bits; -- cur_clu = p_dir->dir; -- -- if (p_dir->flags == 0x03) { -- cur_clu += clu_offset; -- } else { -- while (clu_offset > 0) { -- if (exfat_fat_read(sb, cur_clu, &cur_clu) == -1) -- return -EIO; -- clu_offset--; -- } -- } -- -- if (clu) -- *clu = cur_clu; -- return 0; --} -- --static s32 find_location(struct super_block *sb, struct chain_t *p_dir, s32 entry, -- sector_t *sector, s32 *offset) --{ -- s32 off, ret; -- u32 clu = 0; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- -- off = entry << DENTRY_SIZE_BITS; -- -- if (p_dir->dir == CLUSTER_32(0)) { /* FAT16 root_dir */ -- *offset = off & p_bd->sector_size_mask; -- *sector = off >> p_bd->sector_size_bits; -- *sector += p_fs->root_start_sector; -- } else { -- ret = _walk_fat_chain(sb, p_dir, off, &clu); -- if (ret != 0) -- return ret; -- -- /* byte offset in cluster */ -- off &= p_fs->cluster_size - 1; -- -- /* byte offset in sector */ -- *offset = off & p_bd->sector_size_mask; -- -- /* sector offset in cluster */ -- *sector = off >> p_bd->sector_size_bits; -- *sector += START_SECTOR(clu); -- } -- return 0; --} -- --struct dentry_t *get_entry_in_dir(struct super_block *sb, struct chain_t *p_dir, -- s32 entry, sector_t *sector) --{ -- s32 off; -- sector_t sec; -- u8 *buf; -- -- if (find_location(sb, p_dir, entry, &sec, &off) != 0) -- return NULL; -- -- buf = exfat_buf_getblk(sb, sec); -- -- if (!buf) -- return NULL; -- -- if (sector) -- *sector = sec; -- return (struct dentry_t *)(buf + off); --} -- --/* 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() -- * to apply changes made in this entry set to the real device. -- * in: -- * sb+p_dir+entry: indicates a file/dir -- * type: specifies how many dentries should be included. -- * out: -- * file_ep: will point the first dentry(= file dentry) on success -- * return: -- * pointer of entry set on success, -- * NULL on failure. -- */ -- --#define ES_MODE_STARTED 0 --#define ES_MODE_GET_FILE_ENTRY 1 --#define ES_MODE_GET_STRM_ENTRY 2 --#define ES_MODE_GET_NAME_ENTRY 3 --#define ES_MODE_GET_CRITICAL_SEC_ENTRY 4 --struct entry_set_cache_t *get_entry_set_in_dir(struct super_block *sb, -- struct chain_t *p_dir, s32 entry, -- u32 type, -- struct dentry_t **file_ep) --{ -- s32 off, ret, byte_offset; -- u32 clu = 0; -- sector_t sec; -- u32 entry_type; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- struct entry_set_cache_t *es = NULL; -- struct dentry_t *ep, *pos; -- u8 *buf; -- u8 num_entries; -- s32 mode = ES_MODE_STARTED; -- size_t bufsize; -- -- pr_debug("%s entered p_dir dir %u flags %x size %d\n", -- __func__, p_dir->dir, p_dir->flags, p_dir->size); -- -- byte_offset = entry << DENTRY_SIZE_BITS; -- ret = _walk_fat_chain(sb, p_dir, byte_offset, &clu); -- if (ret != 0) -- return NULL; -- -- /* byte offset in cluster */ -- byte_offset &= p_fs->cluster_size - 1; -- -- /* byte offset in sector */ -- off = byte_offset & p_bd->sector_size_mask; -- -- /* sector offset in cluster */ -- sec = byte_offset >> p_bd->sector_size_bits; -- sec += START_SECTOR(clu); -- -- buf = exfat_buf_getblk(sb, sec); -- if (!buf) -- goto err_out; -- -- ep = (struct dentry_t *)(buf + off); -- entry_type = exfat_get_entry_type(ep); -- -- if ((entry_type != TYPE_FILE) && (entry_type != TYPE_DIR)) -- goto err_out; -- -- if (type == ES_ALL_ENTRIES) -- num_entries = ((struct file_dentry_t *)ep)->num_ext + 1; -- else -- num_entries = type; -- -- bufsize = offsetof(struct entry_set_cache_t, __buf) + (num_entries) * -- sizeof(struct dentry_t); -- pr_debug("%s: trying to kmalloc %zx bytes for %d entries\n", __func__, -- bufsize, num_entries); -- es = kmalloc(bufsize, GFP_KERNEL); -- if (!es) -- goto err_out; -- -- es->num_entries = num_entries; -- es->sector = sec; -- es->offset = off; -- es->alloc_flag = p_dir->flags; -- -- pos = (struct dentry_t *)&es->__buf; -- -- while (num_entries) { -- /* -- * instead of copying whole sector, we will check every entry. -- * this will provide minimum stablity and consistency. -- */ -- entry_type = exfat_get_entry_type(ep); -- -- if ((entry_type == TYPE_UNUSED) || (entry_type == TYPE_DELETED)) -- goto err_out; -- -- switch (mode) { -- case ES_MODE_STARTED: -- if ((entry_type == TYPE_FILE) || (entry_type == TYPE_DIR)) -- mode = ES_MODE_GET_FILE_ENTRY; -- else -- goto err_out; -- break; -- case ES_MODE_GET_FILE_ENTRY: -- if (entry_type == TYPE_STREAM) -- mode = ES_MODE_GET_STRM_ENTRY; -- else -- goto err_out; -- break; -- case ES_MODE_GET_STRM_ENTRY: -- if (entry_type == TYPE_EXTEND) -- mode = ES_MODE_GET_NAME_ENTRY; -- else -- goto err_out; -- break; -- case ES_MODE_GET_NAME_ENTRY: -- if (entry_type == TYPE_EXTEND) -- break; -- else if (entry_type == TYPE_STREAM) -- goto err_out; -- else if (entry_type & TYPE_CRITICAL_SEC) -- mode = ES_MODE_GET_CRITICAL_SEC_ENTRY; -- else -- goto err_out; -- break; -- case ES_MODE_GET_CRITICAL_SEC_ENTRY: -- if ((entry_type == TYPE_EXTEND) || -- (entry_type == TYPE_STREAM)) -- goto err_out; -- else if ((entry_type & TYPE_CRITICAL_SEC) != -- TYPE_CRITICAL_SEC) -- goto err_out; -- break; -- } -- -- memcpy(pos, ep, sizeof(struct dentry_t)); -- -- if (--num_entries == 0) -- break; -- -- if (((off + DENTRY_SIZE) & p_bd->sector_size_mask) < -- (off & p_bd->sector_size_mask)) { -- /* get the next sector */ -- if (IS_LAST_SECTOR_IN_CLUSTER(sec)) { -- if (es->alloc_flag == 0x03) { -- clu++; -- } else { -- if (exfat_fat_read(sb, clu, &clu) == -1) -- goto err_out; -- } -- sec = START_SECTOR(clu); -- } else { -- sec++; -- } -- buf = exfat_buf_getblk(sb, sec); -- if (!buf) -- goto err_out; -- off = 0; -- ep = (struct dentry_t *)(buf); -- } else { -- ep++; -- off += DENTRY_SIZE; -- } -- pos++; -- } -- -- if (file_ep) -- *file_ep = (struct dentry_t *)&es->__buf; -- -- pr_debug("%s exiting es %p sec %llu offset %d flags %d, num_entries %u buf ptr %p\n", -- __func__, es, (unsigned long long)es->sector, es->offset, -- es->alloc_flag, es->num_entries, &es->__buf); -- return es; --err_out: -- pr_debug("%s exited NULL (es %p)\n", __func__, es); -- kfree(es); -- return NULL; --} -- --void release_entry_set(struct entry_set_cache_t *es) --{ -- pr_debug("%s es=%p\n", __func__, es); -- kfree(es); --} -- --/* search EMPTY CONTINUOUS "num_entries" entries */ --static s32 search_deleted_or_unused_entry(struct super_block *sb, -- struct chain_t *p_dir, -- s32 num_entries) --{ -- int i, dentry, num_empty = 0; -- s32 dentries_per_clu; -- u32 type; -- struct chain_t clu; -- struct dentry_t *ep; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ -- dentries_per_clu = p_fs->dentries_in_root; -- else -- dentries_per_clu = p_fs->dentries_per_clu; -- -- if (p_fs->hint_uentry.dir == p_dir->dir) { -- if (p_fs->hint_uentry.entry == -1) -- return -1; -- -- clu.dir = p_fs->hint_uentry.clu.dir; -- clu.size = p_fs->hint_uentry.clu.size; -- clu.flags = p_fs->hint_uentry.clu.flags; -- -- dentry = p_fs->hint_uentry.entry; -- } else { -- p_fs->hint_uentry.entry = -1; -- -- clu.dir = p_dir->dir; -- clu.size = p_dir->size; -- clu.flags = p_dir->flags; -- -- dentry = 0; -- } -- -- while (clu.dir != CLUSTER_32(~0)) { -- if (p_fs->dev_ejected) -- break; -- -- if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ -- i = dentry % dentries_per_clu; -- else -- i = dentry & (dentries_per_clu - 1); -- -- for (; i < dentries_per_clu; i++, dentry++) { -- ep = get_entry_in_dir(sb, &clu, i, NULL); -- if (!ep) -- return -1; -- -- type = exfat_get_entry_type(ep); -- -- if (type == TYPE_UNUSED) { -- num_empty++; -- if (p_fs->hint_uentry.entry == -1) { -- p_fs->hint_uentry.dir = p_dir->dir; -- p_fs->hint_uentry.entry = dentry; -- -- p_fs->hint_uentry.clu.dir = clu.dir; -- p_fs->hint_uentry.clu.size = clu.size; -- p_fs->hint_uentry.clu.flags = clu.flags; -- } -- } else if (type == TYPE_DELETED) { -- num_empty++; -- } else { -- num_empty = 0; -- } -- -- if (num_empty >= num_entries) { -- p_fs->hint_uentry.dir = CLUSTER_32(~0); -- p_fs->hint_uentry.entry = -1; -- -- if (p_fs->vol_type == EXFAT) -- return dentry - (num_entries - 1); -- else -- return dentry; -- } -- } -- -- if (p_dir->dir == CLUSTER_32(0)) -- break; /* FAT16 root_dir */ -- -- if (clu.flags == 0x03) { -- if ((--clu.size) > 0) -- clu.dir++; -- else -- clu.dir = CLUSTER_32(~0); -- } else { -- if (exfat_fat_read(sb, clu.dir, &clu.dir) != 0) -- return -1; -- } -- } -- -- return -1; --} -- --static s32 find_empty_entry(struct inode *inode, struct chain_t *p_dir, s32 num_entries) --{ -- s32 ret, dentry; -- u32 last_clu; -- sector_t sector; -- u64 size = 0; -- struct chain_t clu; -- struct dentry_t *ep = NULL; -- struct super_block *sb = inode->i_sb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct file_id_t *fid = &(EXFAT_I(inode)->fid); -- -- if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ -- return search_deleted_or_unused_entry(sb, p_dir, num_entries); -- -- while ((dentry = search_deleted_or_unused_entry(sb, p_dir, num_entries)) < 0) { -- if (p_fs->dev_ejected) -- break; -- -- if (p_dir->dir != p_fs->root_dir) -- size = i_size_read(inode); -- -- last_clu = find_last_cluster(sb, p_dir); -- clu.dir = last_clu + 1; -- clu.size = 0; -- clu.flags = p_dir->flags; -- -- /* (1) allocate a cluster */ -- ret = exfat_alloc_cluster(sb, 1, &clu); -- if (ret < 1) -- return -EIO; -- -- if (clear_cluster(sb, clu.dir) != 0) -- return -EIO; -- -- /* (2) append to the FAT chain */ -- if (clu.flags != p_dir->flags) { -- exfat_chain_cont_cluster(sb, p_dir->dir, p_dir->size); -- p_dir->flags = 0x01; -- p_fs->hint_uentry.clu.flags = 0x01; -- } -- if (clu.flags == 0x01) -- if (exfat_fat_write(sb, last_clu, clu.dir) < 0) -- return -EIO; -- -- if (p_fs->hint_uentry.entry == -1) { -- p_fs->hint_uentry.dir = p_dir->dir; -- p_fs->hint_uentry.entry = p_dir->size << (p_fs->cluster_size_bits - DENTRY_SIZE_BITS); -- -- p_fs->hint_uentry.clu.dir = clu.dir; -- p_fs->hint_uentry.clu.size = 0; -- p_fs->hint_uentry.clu.flags = clu.flags; -- } -- p_fs->hint_uentry.clu.size++; -- p_dir->size++; -- -- /* (3) update the directory entry */ -- if (p_dir->dir != p_fs->root_dir) { -- size += p_fs->cluster_size; -- -- ep = get_entry_in_dir(sb, &fid->dir, -- fid->entry + 1, §or); -- if (!ep) -- return -ENOENT; -- exfat_set_entry_size(ep, size); -- exfat_set_entry_flag(ep, p_dir->flags); -- exfat_buf_modify(sb, sector); -- -- update_dir_checksum(sb, &fid->dir, -- fid->entry); -- } -- -- i_size_write(inode, i_size_read(inode) + p_fs->cluster_size); -- EXFAT_I(inode)->mmu_private += p_fs->cluster_size; -- EXFAT_I(inode)->fid.size += p_fs->cluster_size; -- EXFAT_I(inode)->fid.flags = p_dir->flags; -- inode->i_blocks += 1 << (p_fs->cluster_size_bits - 9); -- } -- -- return dentry; --} -- --static s32 extract_uni_name_from_name_entry(struct name_dentry_t *ep, u16 *uniname, -- s32 order) --{ -- int i, len = 0; -- -- for (i = 0; i < 30; i += 2) { -- *uniname = GET16_A(ep->unicode_0_14 + i); -- if (*uniname == 0x0) -- return len; -- uniname++; -- len++; -- } -- -- *uniname = 0x0; -- return len; --} -- --/* return values of exfat_find_dir_entry() -- * >= 0 : return dir entiry position with the name in dir -- * -1 : (root dir, ".") it is the root dir itself -- * -2 : entry with the name does not exist -- */ --s32 exfat_find_dir_entry(struct super_block *sb, struct chain_t *p_dir, -- struct uni_name_t *p_uniname, s32 num_entries, -- struct dos_name_t *p_dosname, u32 type) --{ -- int i = 0, dentry = 0, num_ext_entries = 0, len, step; -- s32 order = 0; -- bool is_feasible_entry = false; -- s32 dentries_per_clu, num_empty = 0; -- u32 entry_type; -- u16 entry_uniname[16], *uniname = NULL, unichar; -- struct chain_t clu; -- struct dentry_t *ep; -- struct file_dentry_t *file_ep; -- struct strm_dentry_t *strm_ep; -- struct name_dentry_t *name_ep; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- if (p_dir->dir == p_fs->root_dir) { -- if ((!nls_uniname_cmp(sb, p_uniname->name, -- (u16 *)UNI_CUR_DIR_NAME)) || -- (!nls_uniname_cmp(sb, p_uniname->name, -- (u16 *)UNI_PAR_DIR_NAME))) -- return -1; // special case, root directory itself -- } -- -- if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ -- dentries_per_clu = p_fs->dentries_in_root; -- else -- dentries_per_clu = p_fs->dentries_per_clu; -- -- clu.dir = p_dir->dir; -- clu.size = p_dir->size; -- clu.flags = p_dir->flags; -- -- p_fs->hint_uentry.dir = p_dir->dir; -- p_fs->hint_uentry.entry = -1; -- -- while (clu.dir != CLUSTER_32(~0)) { -- if (p_fs->dev_ejected) -- break; -- -- while (i < dentries_per_clu) { -- ep = get_entry_in_dir(sb, &clu, i, NULL); -- if (!ep) -- return -2; -- -- entry_type = exfat_get_entry_type(ep); -- step = 1; -- -- if ((entry_type == TYPE_UNUSED) || (entry_type == TYPE_DELETED)) { -- is_feasible_entry = false; -- -- if (p_fs->hint_uentry.entry == -1) { -- num_empty++; -- -- if (num_empty == 1) { -- p_fs->hint_uentry.clu.dir = clu.dir; -- p_fs->hint_uentry.clu.size = clu.size; -- p_fs->hint_uentry.clu.flags = clu.flags; -- } -- if ((num_empty >= num_entries) || (entry_type == TYPE_UNUSED)) -- p_fs->hint_uentry.entry = dentry - (num_empty - 1); -- } -- -- if (entry_type == TYPE_UNUSED) -- return -2; -- } else { -- num_empty = 0; -- -- if ((entry_type == TYPE_FILE) || (entry_type == TYPE_DIR)) { -- file_ep = (struct file_dentry_t *)ep; -- if ((type == TYPE_ALL) || (type == entry_type)) { -- num_ext_entries = file_ep->num_ext; -- is_feasible_entry = true; -- } else { -- is_feasible_entry = false; -- step = file_ep->num_ext + 1; -- } -- } else if (entry_type == TYPE_STREAM) { -- if (is_feasible_entry) { -- strm_ep = (struct strm_dentry_t *)ep; -- if (p_uniname->name_hash == GET16_A(strm_ep->name_hash) && -- p_uniname->name_len == strm_ep->name_len) { -- order = 1; -- } else { -- is_feasible_entry = false; -- step = num_ext_entries; -- } -- } -- } else if (entry_type == TYPE_EXTEND) { -- if (is_feasible_entry) { -- name_ep = (struct name_dentry_t *)ep; -- -- if ((++order) == 2) -- uniname = p_uniname->name; -- else -- uniname += 15; -- -- len = extract_uni_name_from_name_entry(name_ep, -- entry_uniname, order); -- -- unichar = *(uniname + len); -- *(uniname + len) = 0x0; -- -- if (nls_uniname_cmp(sb, uniname, entry_uniname)) { -- is_feasible_entry = false; -- step = num_ext_entries - order + 1; -- } else if (order == num_ext_entries) { -- p_fs->hint_uentry.dir = CLUSTER_32(~0); -- p_fs->hint_uentry.entry = -1; -- return dentry - (num_ext_entries); -- } -- -- *(uniname + len) = unichar; -- } -- } else { -- is_feasible_entry = false; -- } -- } -- -- i += step; -- dentry += step; -- } -- -- i -= dentries_per_clu; -- -- if (p_dir->dir == CLUSTER_32(0)) -- break; /* FAT16 root_dir */ -- -- if (clu.flags == 0x03) { -- if ((--clu.size) > 0) -- clu.dir++; -- else -- clu.dir = CLUSTER_32(~0); -- } else { -- if (exfat_fat_read(sb, clu.dir, &clu.dir) != 0) -- return -2; -- } -- } -- -- return -2; --} -- --s32 exfat_count_ext_entries(struct super_block *sb, struct chain_t *p_dir, -- s32 entry, struct dentry_t *p_entry) --{ -- int i, count = 0; -- u32 type; -- struct file_dentry_t *file_ep = (struct file_dentry_t *)p_entry; -- struct dentry_t *ext_ep; -- -- for (i = 0, entry++; i < file_ep->num_ext; i++, entry++) { -- ext_ep = get_entry_in_dir(sb, p_dir, entry, NULL); -- if (!ext_ep) -- return -1; -- -- type = exfat_get_entry_type(ext_ep); -- if ((type == TYPE_EXTEND) || (type == TYPE_STREAM)) -- count++; -- else -- return count; -- } -- -- return count; --} -- --s32 count_dos_name_entries(struct super_block *sb, struct chain_t *p_dir, -- u32 type) --{ -- int i, count = 0; -- s32 dentries_per_clu; -- u32 entry_type; -- struct chain_t clu; -- struct dentry_t *ep; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ -- dentries_per_clu = p_fs->dentries_in_root; -- else -- dentries_per_clu = p_fs->dentries_per_clu; -- -- clu.dir = p_dir->dir; -- clu.size = p_dir->size; -- clu.flags = p_dir->flags; -- -- while (clu.dir != CLUSTER_32(~0)) { -- if (p_fs->dev_ejected) -- break; -- -- for (i = 0; i < dentries_per_clu; i++) { -- ep = get_entry_in_dir(sb, &clu, i, NULL); -- if (!ep) -- return -ENOENT; -- -- entry_type = exfat_get_entry_type(ep); -- -- if (entry_type == TYPE_UNUSED) -- return count; -- if (!(type & TYPE_CRITICAL_PRI) && -- !(type & TYPE_BENIGN_PRI)) -- continue; -- -- if ((type == TYPE_ALL) || (type == entry_type)) -- count++; -- } -- -- if (p_dir->dir == CLUSTER_32(0)) -- break; /* FAT16 root_dir */ -- -- if (clu.flags == 0x03) { -- if ((--clu.size) > 0) -- clu.dir++; -- else -- clu.dir = CLUSTER_32(~0); -- } else { -- if (exfat_fat_read(sb, clu.dir, &clu.dir) != 0) -- return -EIO; -- } -- } -- -- return count; --} -- --bool is_dir_empty(struct super_block *sb, struct chain_t *p_dir) --{ -- int i, count = 0; -- s32 dentries_per_clu; -- u32 type; -- struct chain_t clu; -- struct dentry_t *ep; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ -- dentries_per_clu = p_fs->dentries_in_root; -- else -- dentries_per_clu = p_fs->dentries_per_clu; -- -- clu.dir = p_dir->dir; -- clu.size = p_dir->size; -- clu.flags = p_dir->flags; -- -- while (clu.dir != CLUSTER_32(~0)) { -- if (p_fs->dev_ejected) -- break; -- -- for (i = 0; i < dentries_per_clu; i++) { -- ep = get_entry_in_dir(sb, &clu, i, NULL); -- if (!ep) -- break; -- -- type = exfat_get_entry_type(ep); -- -- if (type == TYPE_UNUSED) -- return true; -- if ((type != TYPE_FILE) && (type != TYPE_DIR)) -- continue; -- -- if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ -- return false; -- -- if (p_fs->vol_type == EXFAT) -- return false; -- if ((p_dir->dir == p_fs->root_dir) || ((++count) > 2)) -- return false; -- } -- -- if (p_dir->dir == CLUSTER_32(0)) -- break; /* FAT16 root_dir */ -- -- if (clu.flags == 0x03) { -- if ((--clu.size) > 0) -- clu.dir++; -- else -- clu.dir = CLUSTER_32(~0); -- } -- if (exfat_fat_read(sb, clu.dir, &clu.dir) != 0) -- break; -- } -- -- return true; --} -- --/* -- * Name Conversion Functions -- */ -- --/* input : dir, uni_name -- * output : num_of_entry, dos_name(format : aaaaaa~1.bbb) -- */ --s32 get_num_entries_and_dos_name(struct super_block *sb, struct chain_t *p_dir, -- struct uni_name_t *p_uniname, s32 *entries, -- struct dos_name_t *p_dosname) --{ -- s32 num_entries; -- -- num_entries = exfat_calc_num_entries(p_uniname); -- if (num_entries == 0) -- return -EINVAL; -- -- *entries = num_entries; -- -- return 0; --} -- --void exfat_get_uni_name_from_ext_entry(struct super_block *sb, -- struct chain_t *p_dir, s32 entry, -- u16 *uniname) --{ -- int i; -- struct dentry_t *ep; -- struct entry_set_cache_t *es; -- -- es = get_entry_set_in_dir(sb, p_dir, entry, ES_ALL_ENTRIES, &ep); -- if (!es || es->num_entries < 3) { -- if (es) -- release_entry_set(es); -- return; -- } -- -- ep += 2; -- -- /* -- * First entry : file entry -- * Second entry : stream-extension entry -- * Third entry : first file-name entry -- * So, the index of first file-name dentry should start from 2. -- */ -- for (i = 2; i < es->num_entries; i++, ep++) { -- if (exfat_get_entry_type(ep) == TYPE_EXTEND) -- extract_uni_name_from_name_entry((struct name_dentry_t *) -- ep, uniname, i); -- else -- goto out; -- uniname += 15; -- } -- --out: -- release_entry_set(es); --} -- --s32 exfat_calc_num_entries(struct uni_name_t *p_uniname) --{ -- s32 len; -- -- len = p_uniname->name_len; -- if (len == 0) -- return 0; -- -- /* 1 file entry + 1 stream entry + name entries */ -- return (len - 1) / 15 + 3; --} -- --u16 calc_checksum_2byte(void *data, s32 len, u16 chksum, s32 type) --{ -- int i; -- u8 *c = (u8 *)data; -- -- switch (type) { -- case CS_DIR_ENTRY: -- for (i = 0; i < len; i++, c++) { -- if ((i == 2) || (i == 3)) -- continue; -- chksum = (((chksum & 1) << 15) | -- ((chksum & 0xFFFE) >> 1)) + (u16)*c; -- } -- break; -- default -- : -- for (i = 0; i < len; i++, c++) -- chksum = (((chksum & 1) << 15) | -- ((chksum & 0xFFFE) >> 1)) + (u16)*c; -- } -- -- return chksum; --} -- --/* -- * Name Resolution Functions -- */ -- --/* return values of resolve_path() -- * > 0 : return the length of the path -- * < 0 : return error -- */ --s32 resolve_path(struct inode *inode, char *path, struct chain_t *p_dir, -- struct uni_name_t *p_uniname) --{ -- bool lossy = false; -- struct super_block *sb = inode->i_sb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct file_id_t *fid = &(EXFAT_I(inode)->fid); -- -- if (strscpy(name_buf, path, sizeof(name_buf)) < 0) -- return -EINVAL; -- -- nls_cstring_to_uniname(sb, p_uniname, name_buf, &lossy); -- if (lossy) -- return -EINVAL; -- -- fid->size = i_size_read(inode); -- -- p_dir->dir = fid->start_clu; -- p_dir->size = (s32)(fid->size >> p_fs->cluster_size_bits); -- p_dir->flags = fid->flags; -- -- return 0; --} -- --s32 exfat_mount(struct super_block *sb, struct pbr_sector_t *p_pbr) --{ -- struct bpbex_t *p_bpb = (struct bpbex_t *)p_pbr->bpb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- -- if (p_bpb->num_fats == 0) -- return -EFSCORRUPTED; -- -- p_fs->sectors_per_clu = 1 << p_bpb->sectors_per_clu_bits; -- p_fs->sectors_per_clu_bits = p_bpb->sectors_per_clu_bits; -- p_fs->cluster_size_bits = p_fs->sectors_per_clu_bits + -- p_bd->sector_size_bits; -- p_fs->cluster_size = 1 << p_fs->cluster_size_bits; -- -- p_fs->num_FAT_sectors = GET32(p_bpb->fat_length); -- -- p_fs->FAT1_start_sector = p_fs->PBR_sector + GET32(p_bpb->fat_offset); -- if (p_bpb->num_fats == 1) -- p_fs->FAT2_start_sector = p_fs->FAT1_start_sector; -- else -- p_fs->FAT2_start_sector = p_fs->FAT1_start_sector + -- p_fs->num_FAT_sectors; -- -- p_fs->root_start_sector = p_fs->PBR_sector + GET32(p_bpb->clu_offset); -- p_fs->data_start_sector = p_fs->root_start_sector; -- -- p_fs->num_sectors = GET64(p_bpb->vol_length); -- p_fs->num_clusters = GET32(p_bpb->clu_count) + 2; -- /* because the cluster index starts with 2 */ -- -- p_fs->vol_type = EXFAT; -- p_fs->vol_id = GET32(p_bpb->vol_serial); -- -- p_fs->root_dir = GET32(p_bpb->root_cluster); -- p_fs->dentries_in_root = 0; -- p_fs->dentries_per_clu = 1 << (p_fs->cluster_size_bits - -- DENTRY_SIZE_BITS); -- -- p_fs->vol_flag = (u32)GET16(p_bpb->vol_flags); -- p_fs->clu_srch_ptr = 2; -- p_fs->used_clusters = UINT_MAX; -- -- return 0; --} -- --s32 create_dir(struct inode *inode, struct chain_t *p_dir, -- struct uni_name_t *p_uniname, struct file_id_t *fid) --{ -- s32 ret, dentry, num_entries; -- u64 size; -- struct chain_t clu; -- struct dos_name_t dos_name; -- struct super_block *sb = inode->i_sb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- ret = get_num_entries_and_dos_name(sb, p_dir, p_uniname, &num_entries, -- &dos_name); -- if (ret) -- return ret; -- -- /* find_empty_entry must be called before alloc_cluster */ -- dentry = find_empty_entry(inode, p_dir, num_entries); -- if (dentry < 0) -- return -ENOSPC; -- -- clu.dir = CLUSTER_32(~0); -- clu.size = 0; -- clu.flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; -- -- /* (1) allocate a cluster */ -- ret = exfat_alloc_cluster(sb, 1, &clu); -- if (ret < 0) -- return ret; -- else if (ret == 0) -- return -ENOSPC; -- -- ret = clear_cluster(sb, clu.dir); -- if (ret != 0) -- return ret; -- -- size = p_fs->cluster_size; -- -- /* (2) update the directory entry */ -- /* make sub-dir entry in parent directory */ -- ret = exfat_init_dir_entry(sb, p_dir, dentry, TYPE_DIR, clu.dir, -- size); -- if (ret != 0) -- return ret; -- -- ret = exfat_init_ext_entry(sb, p_dir, dentry, num_entries, p_uniname, -- &dos_name); -- if (ret != 0) -- return ret; -- -- fid->dir.dir = p_dir->dir; -- fid->dir.size = p_dir->size; -- fid->dir.flags = p_dir->flags; -- fid->entry = dentry; -- -- fid->attr = ATTR_SUBDIR; -- fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; -- fid->size = size; -- fid->start_clu = clu.dir; -- -- fid->type = TYPE_DIR; -- fid->rwoffset = 0; -- fid->hint_last_off = -1; -- -- return 0; --} -- --s32 create_file(struct inode *inode, struct chain_t *p_dir, -- struct uni_name_t *p_uniname, u8 mode, struct file_id_t *fid) --{ -- s32 ret, dentry, num_entries; -- struct dos_name_t dos_name; -- struct super_block *sb = inode->i_sb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- ret = get_num_entries_and_dos_name(sb, p_dir, p_uniname, &num_entries, -- &dos_name); -- if (ret) -- return ret; -- -- /* find_empty_entry must be called before alloc_cluster() */ -- dentry = find_empty_entry(inode, p_dir, num_entries); -- if (dentry < 0) -- return -ENOSPC; -- -- /* (1) update the directory entry */ -- /* fill the dos name directory entry information of the created file. -- * the first cluster is not determined yet. (0) -- */ -- ret = exfat_init_dir_entry(sb, p_dir, dentry, TYPE_FILE | mode, -- CLUSTER_32(0), 0); -- if (ret != 0) -- return ret; -- -- ret = exfat_init_ext_entry(sb, p_dir, dentry, num_entries, p_uniname, -- &dos_name); -- if (ret != 0) -- return ret; -- -- fid->dir.dir = p_dir->dir; -- fid->dir.size = p_dir->size; -- fid->dir.flags = p_dir->flags; -- fid->entry = dentry; -- -- fid->attr = ATTR_ARCHIVE | mode; -- fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; -- fid->size = 0; -- fid->start_clu = CLUSTER_32(~0); -- -- fid->type = TYPE_FILE; -- fid->rwoffset = 0; -- fid->hint_last_off = -1; -- -- return 0; --} -- --void remove_file(struct inode *inode, struct chain_t *p_dir, s32 entry) --{ -- s32 num_entries; -- sector_t sector; -- struct dentry_t *ep; -- struct super_block *sb = inode->i_sb; -- -- ep = get_entry_in_dir(sb, p_dir, entry, §or); -- if (!ep) -- return; -- -- exfat_buf_lock(sb, sector); -- -- /* exfat_buf_lock() before call count_ext_entries() */ -- num_entries = exfat_count_ext_entries(sb, p_dir, entry, ep); -- if (num_entries < 0) { -- exfat_buf_unlock(sb, sector); -- return; -- } -- num_entries++; -- -- exfat_buf_unlock(sb, sector); -- -- /* (1) update the directory entry */ -- exfat_delete_dir_entry(sb, p_dir, entry, 0, num_entries); --} -- --s32 exfat_rename_file(struct inode *inode, struct chain_t *p_dir, s32 oldentry, -- struct uni_name_t *p_uniname, struct file_id_t *fid) --{ -- s32 ret, newentry = -1, num_old_entries, num_new_entries; -- sector_t sector_old, sector_new; -- struct dos_name_t dos_name; -- struct dentry_t *epold, *epnew; -- struct super_block *sb = inode->i_sb; -- -- epold = get_entry_in_dir(sb, p_dir, oldentry, §or_old); -- if (!epold) -- return -ENOENT; -- -- exfat_buf_lock(sb, sector_old); -- -- /* exfat_buf_lock() before call count_ext_entries() */ -- num_old_entries = exfat_count_ext_entries(sb, p_dir, oldentry, -- epold); -- if (num_old_entries < 0) { -- exfat_buf_unlock(sb, sector_old); -- return -ENOENT; -- } -- num_old_entries++; -- -- ret = get_num_entries_and_dos_name(sb, p_dir, p_uniname, -- &num_new_entries, &dos_name); -- if (ret) { -- exfat_buf_unlock(sb, sector_old); -- return ret; -- } -- -- if (num_old_entries < num_new_entries) { -- newentry = find_empty_entry(inode, p_dir, num_new_entries); -- if (newentry < 0) { -- exfat_buf_unlock(sb, sector_old); -- return -ENOSPC; -- } -- -- epnew = get_entry_in_dir(sb, p_dir, newentry, §or_new); -- if (!epnew) { -- exfat_buf_unlock(sb, sector_old); -- return -ENOENT; -- } -- -- memcpy((void *)epnew, (void *)epold, DENTRY_SIZE); -- if (exfat_get_entry_type(epnew) == TYPE_FILE) { -- exfat_set_entry_attr(epnew, -- exfat_get_entry_attr(epnew) | -- ATTR_ARCHIVE); -- fid->attr |= ATTR_ARCHIVE; -- } -- exfat_buf_modify(sb, sector_new); -- exfat_buf_unlock(sb, sector_old); -- -- epold = get_entry_in_dir(sb, p_dir, oldentry + 1, -- §or_old); -- exfat_buf_lock(sb, sector_old); -- epnew = get_entry_in_dir(sb, p_dir, newentry + 1, -- §or_new); -- -- if (!epold || !epnew) { -- exfat_buf_unlock(sb, sector_old); -- return -ENOENT; -- } -- -- memcpy((void *)epnew, (void *)epold, DENTRY_SIZE); -- exfat_buf_modify(sb, sector_new); -- exfat_buf_unlock(sb, sector_old); -- -- ret = exfat_init_ext_entry(sb, p_dir, newentry, -- num_new_entries, p_uniname, -- &dos_name); -- if (ret != 0) -- return ret; -- -- exfat_delete_dir_entry(sb, p_dir, oldentry, 0, -- num_old_entries); -- fid->entry = newentry; -- } else { -- if (exfat_get_entry_type(epold) == TYPE_FILE) { -- exfat_set_entry_attr(epold, -- exfat_get_entry_attr(epold) | -- ATTR_ARCHIVE); -- fid->attr |= ATTR_ARCHIVE; -- } -- exfat_buf_modify(sb, sector_old); -- exfat_buf_unlock(sb, sector_old); -- -- ret = exfat_init_ext_entry(sb, p_dir, oldentry, -- num_new_entries, p_uniname, -- &dos_name); -- if (ret != 0) -- return ret; -- -- exfat_delete_dir_entry(sb, p_dir, oldentry, num_new_entries, -- num_old_entries); -- } -- -- return 0; --} -- --s32 move_file(struct inode *inode, struct chain_t *p_olddir, s32 oldentry, -- struct chain_t *p_newdir, struct uni_name_t *p_uniname, -- struct file_id_t *fid) --{ -- s32 ret, newentry, num_new_entries, num_old_entries; -- sector_t sector_mov, sector_new; -- struct dos_name_t dos_name; -- struct dentry_t *epmov, *epnew; -- struct super_block *sb = inode->i_sb; -- -- epmov = get_entry_in_dir(sb, p_olddir, oldentry, §or_mov); -- if (!epmov) -- return -ENOENT; -- -- /* check if the source and target directory is the same */ -- if (exfat_get_entry_type(epmov) == TYPE_DIR && -- exfat_get_entry_clu0(epmov) == p_newdir->dir) -- return -EINVAL; -- -- exfat_buf_lock(sb, sector_mov); -- -- /* exfat_buf_lock() before call count_ext_entries() */ -- num_old_entries = exfat_count_ext_entries(sb, p_olddir, oldentry, -- epmov); -- if (num_old_entries < 0) { -- exfat_buf_unlock(sb, sector_mov); -- return -ENOENT; -- } -- num_old_entries++; -- -- ret = get_num_entries_and_dos_name(sb, p_newdir, p_uniname, -- &num_new_entries, &dos_name); -- if (ret) { -- exfat_buf_unlock(sb, sector_mov); -- return ret; -- } -- -- newentry = find_empty_entry(inode, p_newdir, num_new_entries); -- if (newentry < 0) { -- exfat_buf_unlock(sb, sector_mov); -- return -ENOSPC; -- } -- -- epnew = get_entry_in_dir(sb, p_newdir, newentry, §or_new); -- if (!epnew) { -- exfat_buf_unlock(sb, sector_mov); -- return -ENOENT; -- } -- -- memcpy((void *)epnew, (void *)epmov, DENTRY_SIZE); -- if (exfat_get_entry_type(epnew) == TYPE_FILE) { -- exfat_set_entry_attr(epnew, exfat_get_entry_attr(epnew) | -- ATTR_ARCHIVE); -- fid->attr |= ATTR_ARCHIVE; -- } -- exfat_buf_modify(sb, sector_new); -- exfat_buf_unlock(sb, sector_mov); -- -- epmov = get_entry_in_dir(sb, p_olddir, oldentry + 1, -- §or_mov); -- exfat_buf_lock(sb, sector_mov); -- epnew = get_entry_in_dir(sb, p_newdir, newentry + 1, -- §or_new); -- if (!epmov || !epnew) { -- exfat_buf_unlock(sb, sector_mov); -- return -ENOENT; -- } -- -- memcpy((void *)epnew, (void *)epmov, DENTRY_SIZE); -- exfat_buf_modify(sb, sector_new); -- exfat_buf_unlock(sb, sector_mov); -- -- ret = exfat_init_ext_entry(sb, p_newdir, newentry, num_new_entries, -- p_uniname, &dos_name); -- if (ret != 0) -- return ret; -- -- exfat_delete_dir_entry(sb, p_olddir, oldentry, 0, num_old_entries); -- -- fid->dir.dir = p_newdir->dir; -- fid->dir.size = p_newdir->size; -- fid->dir.flags = p_newdir->flags; -- -- fid->entry = newentry; -- -- return 0; --} -- --/* -- * Sector Read/Write Functions -- */ -- --int sector_read(struct super_block *sb, sector_t sec, struct buffer_head **bh, -- bool read) --{ -- s32 ret = -EIO; -- struct 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)) { -- pr_err("[EXFAT] %s: out of range error! (sec = %llu)\n", -- __func__, (unsigned long long)sec); -- fs_error(sb); -- return ret; -- } -- -- if (!p_fs->dev_ejected) { -- ret = exfat_bdev_read(sb, sec, bh, 1, read); -- if (ret != 0) -- p_fs->dev_ejected = 1; -- } -- -- return ret; --} -- --int sector_write(struct super_block *sb, sector_t sec, struct buffer_head *bh, -- bool sync) --{ -- s32 ret = -EIO; -- struct 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)) { -- pr_err("[EXFAT] %s: out of range error! (sec = %llu)\n", -- __func__, (unsigned long long)sec); -- fs_error(sb); -- return ret; -- } -- -- if (!bh) { -- pr_err("[EXFAT] %s: bh is NULL!\n", __func__); -- fs_error(sb); -- return ret; -- } -- -- if (!p_fs->dev_ejected) { -- ret = exfat_bdev_write(sb, sec, bh, 1, sync); -- if (ret != 0) -- p_fs->dev_ejected = 1; -- } -- -- return ret; --} -- --int multi_sector_read(struct super_block *sb, sector_t sec, -- struct buffer_head **bh, s32 num_secs, bool read) --{ -- s32 ret = -EIO; -- struct 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)) { -- pr_err("[EXFAT] %s: out of range error! (sec = %llu, num_secs = %d)\n", -- __func__, (unsigned long long)sec, num_secs); -- fs_error(sb); -- return ret; -- } -- -- if (!p_fs->dev_ejected) { -- ret = exfat_bdev_read(sb, sec, bh, num_secs, read); -- if (ret != 0) -- p_fs->dev_ejected = 1; -- } -- -- return ret; --} -- --int multi_sector_write(struct super_block *sb, sector_t sec, -- struct buffer_head *bh, s32 num_secs, bool sync) --{ -- s32 ret = -EIO; -- struct 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)) { -- pr_err("[EXFAT] %s: out of range error! (sec = %llu, num_secs = %d)\n", -- __func__, (unsigned long long)sec, num_secs); -- fs_error(sb); -- return ret; -- } -- if (!bh) { -- pr_err("[EXFAT] %s: bh is NULL!\n", __func__); -- fs_error(sb); -- return ret; -- } -- -- if (!p_fs->dev_ejected) { -- ret = exfat_bdev_write(sb, sec, bh, num_secs, sync); -- if (ret != 0) -- p_fs->dev_ejected = 1; -- } -- -- return ret; --} -diff -Nurp linux-5.6.3.orig/drivers/staging/exfat/exfat.h linux-5.6.3/drivers/staging/exfat/exfat.h ---- linux-5.6.3.orig/drivers/staging/exfat/exfat.h 2020-03-30 01:25:41.000000000 +0300 -+++ linux-5.6.3/drivers/staging/exfat/exfat.h 1970-01-01 02:00:00.000000000 +0200 -@@ -1,824 +0,0 @@ --/* SPDX-License-Identifier: GPL-2.0-or-later */ --/* -- * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -- */ -- --#ifndef _EXFAT_H --#define _EXFAT_H -- --#include --#include -- --#ifdef CONFIG_STAGING_EXFAT_KERNEL_DEBUG -- /* For Debugging Purpose */ -- /* IOCTL code 'f' used by -- * - file systems typically #0~0x1F -- * - embedded terminal devices #128~ -- * - exts for debugging purpose #99 -- * number 100 and 101 is available now but has possible conflicts -- */ --#define EXFAT_IOC_GET_DEBUGFLAGS _IOR('f', 100, long) --#define EXFAT_IOC_SET_DEBUGFLAGS _IOW('f', 101, long) -- --#define EXFAT_DEBUGFLAGS_INVALID_UMOUNT 0x01 --#define EXFAT_DEBUGFLAGS_ERROR_RW 0x02 --#endif /* CONFIG_STAGING_EXFAT_KERNEL_DEBUG */ -- --#ifdef CONFIG_STAGING_EXFAT_DEBUG_MSG --#define DEBUG 1 --#else --#undef DEBUG --#endif -- --#define EFSCORRUPTED EUCLEAN /* Filesystem is corrupted */ -- --#define DENTRY_SIZE 32 /* dir entry size */ --#define DENTRY_SIZE_BITS 5 -- --/* PBR entries */ --#define PBR_SIGNATURE 0xAA55 --#define EXT_SIGNATURE 0xAA550000 --#define VOL_LABEL "NO NAME " /* size should be 11 */ --#define OEM_NAME "MSWIN4.1" /* size should be 8 */ --#define STR_FAT12 "FAT12 " /* size should be 8 */ --#define STR_FAT16 "FAT16 " /* size should be 8 */ --#define STR_FAT32 "FAT32 " /* size should be 8 */ --#define STR_EXFAT "EXFAT " /* size should be 8 */ --#define VOL_CLEAN 0x0000 --#define VOL_DIRTY 0x0002 -- --/* max number of clusters */ --#define FAT12_THRESHOLD 4087 /* 2^12 - 1 + 2 (clu 0 & 1) */ --#define FAT16_THRESHOLD 65527 /* 2^16 - 1 + 2 */ --#define FAT32_THRESHOLD 268435457 /* 2^28 - 1 + 2 */ --#define EXFAT_THRESHOLD 268435457 /* 2^28 - 1 + 2 */ -- --/* file types */ --#define TYPE_UNUSED 0x0000 --#define TYPE_DELETED 0x0001 --#define TYPE_INVALID 0x0002 --#define TYPE_CRITICAL_PRI 0x0100 --#define TYPE_BITMAP 0x0101 --#define TYPE_UPCASE 0x0102 --#define TYPE_VOLUME 0x0103 --#define TYPE_DIR 0x0104 --#define TYPE_FILE 0x011F --#define TYPE_SYMLINK 0x015F --#define TYPE_CRITICAL_SEC 0x0200 --#define TYPE_STREAM 0x0201 --#define TYPE_EXTEND 0x0202 --#define TYPE_ACL 0x0203 --#define TYPE_BENIGN_PRI 0x0400 --#define TYPE_GUID 0x0401 --#define TYPE_PADDING 0x0402 --#define TYPE_ACLTAB 0x0403 --#define TYPE_BENIGN_SEC 0x0800 --#define TYPE_ALL 0x0FFF -- --/* time modes */ --#define TM_CREATE 0 --#define TM_MODIFY 1 --#define TM_ACCESS 2 -- --/* checksum types */ --#define CS_DIR_ENTRY 0 --#define CS_PBR_SECTOR 1 --#define CS_DEFAULT 2 -- --#define CLUSTER_16(x) ((u16)(x)) --#define CLUSTER_32(x) ((u32)(x)) -- --#define START_SECTOR(x) \ -- ((((sector_t)((x) - 2)) << p_fs->sectors_per_clu_bits) + \ -- p_fs->data_start_sector) -- --#define IS_LAST_SECTOR_IN_CLUSTER(sec) \ -- ((((sec) - p_fs->data_start_sector + 1) & \ -- ((1 << p_fs->sectors_per_clu_bits) - 1)) == 0) -- --#define GET_CLUSTER_FROM_SECTOR(sec) \ -- ((u32)((((sec) - p_fs->data_start_sector) >> \ -- p_fs->sectors_per_clu_bits) + 2)) -- --#define GET16(p_src) \ -- (((u16)(p_src)[0]) | (((u16)(p_src)[1]) << 8)) --#define GET32(p_src) \ -- (((u32)(p_src)[0]) | (((u32)(p_src)[1]) << 8) | \ -- (((u32)(p_src)[2]) << 16) | (((u32)(p_src)[3]) << 24)) --#define GET64(p_src) \ -- (((u64)(p_src)[0]) | (((u64)(p_src)[1]) << 8) | \ -- (((u64)(p_src)[2]) << 16) | (((u64)(p_src)[3]) << 24) | \ -- (((u64)(p_src)[4]) << 32) | (((u64)(p_src)[5]) << 40) | \ -- (((u64)(p_src)[6]) << 48) | (((u64)(p_src)[7]) << 56)) -- --#define SET16(p_dst, src) \ -- do { \ -- (p_dst)[0] = (u8)(src); \ -- (p_dst)[1] = (u8)(((u16)(src)) >> 8); \ -- } while (0) --#define SET32(p_dst, src) \ -- do { \ -- (p_dst)[0] = (u8)(src); \ -- (p_dst)[1] = (u8)(((u32)(src)) >> 8); \ -- (p_dst)[2] = (u8)(((u32)(src)) >> 16); \ -- (p_dst)[3] = (u8)(((u32)(src)) >> 24); \ -- } while (0) --#define SET64(p_dst, src) \ -- do { \ -- (p_dst)[0] = (u8)(src); \ -- (p_dst)[1] = (u8)(((u64)(src)) >> 8); \ -- (p_dst)[2] = (u8)(((u64)(src)) >> 16); \ -- (p_dst)[3] = (u8)(((u64)(src)) >> 24); \ -- (p_dst)[4] = (u8)(((u64)(src)) >> 32); \ -- (p_dst)[5] = (u8)(((u64)(src)) >> 40); \ -- (p_dst)[6] = (u8)(((u64)(src)) >> 48); \ -- (p_dst)[7] = (u8)(((u64)(src)) >> 56); \ -- } while (0) -- --#ifdef __LITTLE_ENDIAN --#define GET16_A(p_src) (*((u16 *)(p_src))) --#define GET32_A(p_src) (*((u32 *)(p_src))) --#define GET64_A(p_src) (*((u64 *)(p_src))) --#define SET16_A(p_dst, src) (*((u16 *)(p_dst)) = (u16)(src)) --#define SET32_A(p_dst, src) (*((u32 *)(p_dst)) = (u32)(src)) --#define SET64_A(p_dst, src) (*((u64 *)(p_dst)) = (u64)(src)) --#else /* BIG_ENDIAN */ --#define GET16_A(p_src) GET16(p_src) --#define GET32_A(p_src) GET32(p_src) --#define GET64_A(p_src) GET64(p_src) --#define SET16_A(p_dst, src) SET16(p_dst, src) --#define SET32_A(p_dst, src) SET32(p_dst, src) --#define SET64_A(p_dst, src) SET64(p_dst, src) --#endif -- --/* cache size (in number of sectors) */ --/* (should be an exponential value of 2) */ --#define FAT_CACHE_SIZE 128 --#define FAT_CACHE_HASH_SIZE 64 --#define BUF_CACHE_SIZE 256 --#define BUF_CACHE_HASH_SIZE 64 -- --/* Upcase table macro */ --#define HIGH_INDEX_BIT (8) --#define HIGH_INDEX_MASK (0xFF00) --#define LOW_INDEX_BIT (16 - HIGH_INDEX_BIT) --#define UTBL_ROW_COUNT BIT(LOW_INDEX_BIT) --#define UTBL_COL_COUNT BIT(HIGH_INDEX_BIT) -- --static inline u16 get_col_index(u16 i) --{ -- return i >> LOW_INDEX_BIT; --} -- --static inline u16 get_row_index(u16 i) --{ -- return i & ~HIGH_INDEX_MASK; --} -- --#define EXFAT_SUPER_MAGIC (0x2011BAB0L) --#define EXFAT_ROOT_INO 1 -- --/* FAT types */ --#define FAT12 0x01 /* FAT12 */ --#define FAT16 0x0E /* Win95 FAT16 (LBA) */ --#define FAT32 0x0C /* Win95 FAT32 (LBA) */ --#define EXFAT 0x07 /* exFAT */ -- --/* file name lengths */ --#define MAX_CHARSET_SIZE 3 /* max size of multi-byte character */ --#define MAX_PATH_DEPTH 15 /* max depth of path name */ --#define MAX_NAME_LENGTH 256 /* max len of filename including NULL */ --#define MAX_PATH_LENGTH 260 /* max len of pathname including NULL */ --#define DOS_NAME_LENGTH 11 /* DOS filename length excluding NULL */ --#define DOS_PATH_LENGTH 80 /* DOS pathname length excluding NULL */ -- --/* file attributes */ --#define ATTR_NORMAL 0x0000 --#define ATTR_READONLY 0x0001 --#define ATTR_HIDDEN 0x0002 --#define ATTR_SYSTEM 0x0004 --#define ATTR_VOLUME 0x0008 --#define ATTR_SUBDIR 0x0010 --#define ATTR_ARCHIVE 0x0020 --#define ATTR_SYMLINK 0x0040 --#define ATTR_EXTEND 0x000F --#define ATTR_RWMASK 0x007E -- --/* file creation modes */ --#define FM_REGULAR 0x00 --#define FM_SYMLINK 0x40 -- --#define NUM_UPCASE 2918 -- --#define DOS_CUR_DIR_NAME ". " --#define DOS_PAR_DIR_NAME ".. " -- --#ifdef __LITTLE_ENDIAN --#define UNI_CUR_DIR_NAME ".\0" --#define UNI_PAR_DIR_NAME ".\0.\0" --#else --#define UNI_CUR_DIR_NAME "\0." --#define UNI_PAR_DIR_NAME "\0.\0." --#endif -- --struct date_time_t { -- u16 Year; -- u16 Month; -- u16 Day; -- u16 Hour; -- u16 Minute; -- u16 Second; -- u16 MilliSecond; --}; -- --struct part_info_t { -- u32 Offset; /* start sector number of the partition */ -- u32 Size; /* in sectors */ --}; -- --struct dev_info_t { -- u32 SecSize; /* sector size in bytes */ -- u32 DevSize; /* block device size in sectors */ --}; -- --struct vol_info_t { -- u32 FatType; -- u32 ClusterSize; -- u32 NumClusters; -- u32 FreeClusters; -- u32 UsedClusters; --}; -- --/* directory structure */ --struct chain_t { -- u32 dir; -- s32 size; -- u8 flags; --}; -- --struct file_id_t { -- struct chain_t dir; -- s32 entry; -- u32 type; -- u32 attr; -- u32 start_clu; -- u64 size; -- u8 flags; -- s64 rwoffset; -- s32 hint_last_off; -- u32 hint_last_clu; --}; -- --struct dir_entry_t { -- char Name[MAX_NAME_LENGTH * MAX_CHARSET_SIZE]; -- -- /* used only for FAT12/16/32, not used for exFAT */ -- char ShortName[DOS_NAME_LENGTH + 2]; -- -- u32 Attr; -- u64 Size; -- u32 NumSubdirs; -- struct date_time_t CreateTimestamp; -- struct date_time_t ModifyTimestamp; -- struct date_time_t AccessTimestamp; --}; -- --struct timestamp_t { -- u16 sec; /* 0 ~ 59 */ -- u16 min; /* 0 ~ 59 */ -- u16 hour; /* 0 ~ 23 */ -- u16 day; /* 1 ~ 31 */ -- u16 mon; /* 1 ~ 12 */ -- u16 year; /* 0 ~ 127 (since 1980) */ --}; -- --/* MS_DOS FAT partition boot record (512 bytes) */ --struct pbr_sector_t { -- u8 jmp_boot[3]; -- u8 oem_name[8]; -- u8 bpb[109]; -- u8 boot_code[390]; -- u8 signature[2]; --}; -- --/* MS-DOS FAT12/16 BIOS parameter block (51 bytes) */ --struct bpb16_t { -- u8 sector_size[2]; -- u8 sectors_per_clu; -- u8 num_reserved[2]; -- u8 num_fats; -- u8 num_root_entries[2]; -- u8 num_sectors[2]; -- u8 media_type; -- u8 num_fat_sectors[2]; -- u8 sectors_in_track[2]; -- u8 num_heads[2]; -- u8 num_hid_sectors[4]; -- u8 num_huge_sectors[4]; -- -- u8 phy_drv_no; -- u8 reserved; -- u8 ext_signature; -- u8 vol_serial[4]; -- u8 vol_label[11]; -- u8 vol_type[8]; --}; -- --/* MS-DOS FAT32 BIOS parameter block (79 bytes) */ --struct bpb32_t { -- u8 sector_size[2]; -- u8 sectors_per_clu; -- u8 num_reserved[2]; -- u8 num_fats; -- u8 num_root_entries[2]; -- u8 num_sectors[2]; -- u8 media_type; -- u8 num_fat_sectors[2]; -- u8 sectors_in_track[2]; -- u8 num_heads[2]; -- u8 num_hid_sectors[4]; -- u8 num_huge_sectors[4]; -- u8 num_fat32_sectors[4]; -- u8 ext_flags[2]; -- u8 fs_version[2]; -- u8 root_cluster[4]; -- u8 fsinfo_sector[2]; -- u8 backup_sector[2]; -- u8 reserved[12]; -- -- u8 phy_drv_no; -- u8 ext_reserved; -- u8 ext_signature; -- u8 vol_serial[4]; -- u8 vol_label[11]; -- u8 vol_type[8]; --}; -- --/* MS-DOS EXFAT BIOS parameter block (109 bytes) */ --struct bpbex_t { -- u8 reserved1[53]; -- u8 vol_offset[8]; -- u8 vol_length[8]; -- u8 fat_offset[4]; -- u8 fat_length[4]; -- u8 clu_offset[4]; -- u8 clu_count[4]; -- u8 root_cluster[4]; -- u8 vol_serial[4]; -- u8 fs_version[2]; -- u8 vol_flags[2]; -- u8 sector_size_bits; -- u8 sectors_per_clu_bits; -- u8 num_fats; -- u8 phy_drv_no; -- u8 perc_in_use; -- u8 reserved2[7]; --}; -- --/* MS-DOS FAT file system information sector (512 bytes) */ --struct fsi_sector_t { -- u8 signature1[4]; -- u8 reserved1[480]; -- u8 signature2[4]; -- u8 free_cluster[4]; -- u8 next_cluster[4]; -- u8 reserved2[14]; -- u8 signature3[2]; --}; -- --/* MS-DOS FAT directory entry (32 bytes) */ --struct dentry_t { -- u8 dummy[32]; --}; -- --struct dos_dentry_t { -- u8 name[DOS_NAME_LENGTH]; -- u8 attr; -- u8 lcase; -- u8 create_time_ms; -- u8 create_time[2]; -- u8 create_date[2]; -- u8 access_date[2]; -- u8 start_clu_hi[2]; -- u8 modify_time[2]; -- u8 modify_date[2]; -- u8 start_clu_lo[2]; -- u8 size[4]; --}; -- --/* MS-DOS FAT extended directory entry (32 bytes) */ --struct ext_dentry_t { -- u8 order; -- u8 unicode_0_4[10]; -- u8 attr; -- u8 sysid; -- u8 checksum; -- u8 unicode_5_10[12]; -- u8 start_clu[2]; -- u8 unicode_11_12[4]; --}; -- --/* MS-DOS EXFAT file directory entry (32 bytes) */ --struct file_dentry_t { -- u8 type; -- u8 num_ext; -- u8 checksum[2]; -- u8 attr[2]; -- u8 reserved1[2]; -- u8 create_time[2]; -- u8 create_date[2]; -- u8 modify_time[2]; -- u8 modify_date[2]; -- u8 access_time[2]; -- u8 access_date[2]; -- u8 create_time_ms; -- u8 modify_time_ms; -- u8 access_time_ms; -- u8 reserved2[9]; --}; -- --/* MS-DOS EXFAT stream extension directory entry (32 bytes) */ --struct strm_dentry_t { -- u8 type; -- u8 flags; -- u8 reserved1; -- u8 name_len; -- u8 name_hash[2]; -- u8 reserved2[2]; -- u8 valid_size[8]; -- u8 reserved3[4]; -- u8 start_clu[4]; -- u8 size[8]; --}; -- --/* MS-DOS EXFAT file name directory entry (32 bytes) */ --struct name_dentry_t { -- u8 type; -- u8 flags; -- u8 unicode_0_14[30]; --}; -- --/* MS-DOS EXFAT allocation bitmap directory entry (32 bytes) */ --struct bmap_dentry_t { -- u8 type; -- u8 flags; -- u8 reserved[18]; -- u8 start_clu[4]; -- u8 size[8]; --}; -- --/* MS-DOS EXFAT up-case table directory entry (32 bytes) */ --struct case_dentry_t { -- u8 type; -- u8 reserved1[3]; -- u8 checksum[4]; -- u8 reserved2[12]; -- u8 start_clu[4]; -- u8 size[8]; --}; -- --/* MS-DOS EXFAT volume label directory entry (32 bytes) */ --struct volm_dentry_t { -- u8 type; -- u8 label_len; -- u8 unicode_0_10[22]; -- u8 reserved[8]; --}; -- --/* unused entry hint information */ --struct uentry_t { -- u32 dir; -- s32 entry; -- struct chain_t clu; --}; -- --/* DOS name structure */ --struct dos_name_t { -- u8 name[DOS_NAME_LENGTH]; -- u8 name_case; --}; -- --/* unicode name structure */ --struct uni_name_t { -- u16 name[MAX_NAME_LENGTH]; -- u16 name_hash; -- u8 name_len; --}; -- --struct buf_cache_t { -- struct buf_cache_t *next; -- struct buf_cache_t *prev; -- struct buf_cache_t *hash_next; -- struct buf_cache_t *hash_prev; -- s32 drv; -- sector_t sec; -- u32 flag; -- struct buffer_head *buf_bh; --}; -- --struct fs_info_t { -- u32 drv; /* drive ID */ -- u32 vol_type; /* volume FAT type */ -- u32 vol_id; /* volume serial number */ -- -- u64 num_sectors; /* num of sectors in volume */ -- u32 num_clusters; /* num of clusters in volume */ -- u32 cluster_size; /* cluster size in bytes */ -- u32 cluster_size_bits; -- u32 sectors_per_clu; /* cluster size in sectors */ -- u32 sectors_per_clu_bits; -- -- u32 PBR_sector; /* PBR sector */ -- u32 FAT1_start_sector; /* FAT1 start sector */ -- u32 FAT2_start_sector; /* FAT2 start sector */ -- u32 root_start_sector; /* root dir start sector */ -- u32 data_start_sector; /* data area start sector */ -- u32 num_FAT_sectors; /* num of FAT sectors */ -- -- u32 root_dir; /* root dir cluster */ -- u32 dentries_in_root; /* num of dentries in root dir */ -- u32 dentries_per_clu; /* num of dentries per cluster */ -- -- u32 vol_flag; /* volume dirty flag */ -- struct buffer_head *pbr_bh; /* PBR sector */ -- -- u32 map_clu; /* allocation bitmap start cluster */ -- u32 map_sectors; /* num of allocation bitmap sectors */ -- struct buffer_head **vol_amap; /* allocation bitmap */ -- -- u16 **vol_utbl; /* upcase table */ -- -- u32 clu_srch_ptr; /* cluster search pointer */ -- u32 used_clusters; /* number of used clusters */ -- struct uentry_t hint_uentry; /* unused entry hint information */ -- -- u32 dev_ejected; /* block device operation error flag */ -- -- struct mutex v_mutex; -- -- /* FAT cache */ -- struct buf_cache_t FAT_cache_array[FAT_CACHE_SIZE]; -- struct buf_cache_t FAT_cache_lru_list; -- struct buf_cache_t FAT_cache_hash_list[FAT_CACHE_HASH_SIZE]; -- -- /* buf cache */ -- struct buf_cache_t buf_cache_array[BUF_CACHE_SIZE]; -- struct buf_cache_t buf_cache_lru_list; -- struct buf_cache_t buf_cache_hash_list[BUF_CACHE_HASH_SIZE]; --}; -- --#define ES_2_ENTRIES 2 --#define ES_3_ENTRIES 3 --#define ES_ALL_ENTRIES 0 -- --struct entry_set_cache_t { -- /* sector number that contains file_entry */ -- sector_t sector; -- -- /* byte offset in the sector */ -- s32 offset; -- -- /* -- * flag in stream entry. -- * 01 for cluster chain, -- * 03 for contig. clusteres. -- */ -- s32 alloc_flag; -- -- u32 num_entries; -- -- /* __buf should be the last member */ -- void *__buf; --}; -- --#define EXFAT_ERRORS_CONT 1 /* ignore error and continue */ --#define EXFAT_ERRORS_PANIC 2 /* panic on error */ --#define EXFAT_ERRORS_RO 3 /* remount r/o on error */ -- --/* ioctl command */ --#define EXFAT_IOCTL_GET_VOLUME_ID _IOR('r', 0x12, __u32) -- --struct exfat_mount_options { -- kuid_t fs_uid; -- kgid_t fs_gid; -- unsigned short fs_fmask; -- unsigned short fs_dmask; -- -- /* permission for setting the [am]time */ -- unsigned short allow_utime; -- -- /* codepage for shortname conversions */ -- unsigned short codepage; -- -- /* charset for filename input/display */ -- char *iocharset; -- -- unsigned char casesensitive; -- -- /* on error: continue, panic, remount-ro */ -- unsigned char errors; --#ifdef CONFIG_STAGING_EXFAT_DISCARD -- /* flag on if -o dicard specified and device support discard() */ -- unsigned char discard; --#endif /* CONFIG_STAGING_EXFAT_DISCARD */ --}; -- --#define EXFAT_HASH_BITS 8 --#define EXFAT_HASH_SIZE BIT(EXFAT_HASH_BITS) -- --/* -- * EXFAT file system in-core superblock data -- */ --struct bd_info_t { -- s32 sector_size; /* in bytes */ -- s32 sector_size_bits; -- s32 sector_size_mask; -- -- /* total number of sectors in this block device */ -- s32 num_sectors; -- -- /* opened or not */ -- bool opened; --}; -- --struct exfat_sb_info { -- struct fs_info_t fs_info; -- struct bd_info_t bd_info; -- -- struct exfat_mount_options options; -- -- int s_dirt; -- struct mutex s_lock; -- struct nls_table *nls_disk; /* Codepage used on disk */ -- struct nls_table *nls_io; /* Charset used for input and display */ -- -- struct inode *fat_inode; -- -- spinlock_t inode_hash_lock; -- struct hlist_head inode_hashtable[EXFAT_HASH_SIZE]; --#ifdef CONFIG_STAGING_EXFAT_KERNEL_DEBUG -- long debug_flags; --#endif /* CONFIG_STAGING_EXFAT_KERNEL_DEBUG */ --}; -- --/* -- * EXFAT file system inode data in memory -- */ --struct exfat_inode_info { -- struct file_id_t fid; -- char *target; -- /* 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_hash_fat; /* hash by i_location */ -- struct rw_semaphore truncate_lock; -- struct inode vfs_inode; -- struct rw_semaphore i_alloc_sem; /* protect bmap against truncate */ --}; -- --#define EXFAT_SB(sb) ((struct exfat_sb_info *)((sb)->s_fs_info)) -- --static inline struct exfat_inode_info *EXFAT_I(struct inode *inode) --{ -- return container_of(inode, struct exfat_inode_info, vfs_inode); --} -- --/* NLS management function */ --u16 nls_upper(struct super_block *sb, u16 a); --int nls_uniname_cmp(struct super_block *sb, u16 *a, u16 *b); --void nls_uniname_to_cstring(struct super_block *sb, u8 *p_cstring, -- struct uni_name_t *p_uniname); --void nls_cstring_to_uniname(struct super_block *sb, -- struct uni_name_t *p_uniname, u8 *p_cstring, -- bool *p_lossy); -- --/* buffer cache management */ --void exfat_buf_init(struct super_block *sb); --void exfat_buf_shutdown(struct super_block *sb); --int exfat_fat_read(struct super_block *sb, u32 loc, u32 *content); --s32 exfat_fat_write(struct super_block *sb, u32 loc, u32 content); --u8 *exfat_fat_getblk(struct super_block *sb, sector_t sec); --void exfat_fat_modify(struct super_block *sb, sector_t sec); --void exfat_fat_release_all(struct super_block *sb); --void exfat_fat_sync(struct super_block *sb); --u8 *exfat_buf_getblk(struct super_block *sb, sector_t sec); --void exfat_buf_modify(struct super_block *sb, sector_t sec); --void exfat_buf_lock(struct super_block *sb, sector_t sec); --void exfat_buf_unlock(struct super_block *sb, sector_t sec); --void exfat_buf_release(struct super_block *sb, sector_t sec); --void exfat_buf_release_all(struct super_block *sb); --void exfat_buf_sync(struct super_block *sb); -- --/* fs management functions */ --void fs_set_vol_flags(struct super_block *sb, u32 new_flag); --void fs_error(struct super_block *sb); -- --/* cluster management functions */ --s32 count_num_clusters(struct super_block *sb, struct chain_t *dir); --void exfat_chain_cont_cluster(struct super_block *sb, u32 chain, s32 len); -- --/* allocation bitmap management functions */ --s32 load_alloc_bitmap(struct super_block *sb); --void free_alloc_bitmap(struct super_block *sb); --void sync_alloc_bitmap(struct super_block *sb); -- --/* upcase table management functions */ --s32 load_upcase_table(struct super_block *sb); --void free_upcase_table(struct super_block *sb); -- --/* dir entry management functions */ --struct timestamp_t *tm_current(struct timestamp_t *tm); -- --struct dentry_t *get_entry_in_dir(struct super_block *sb, struct chain_t *p_dir, -- s32 entry, sector_t *sector); --struct entry_set_cache_t *get_entry_set_in_dir(struct super_block *sb, -- struct chain_t *p_dir, s32 entry, -- u32 type, -- struct dentry_t **file_ep); --void release_entry_set(struct entry_set_cache_t *es); --s32 count_dos_name_entries(struct super_block *sb, struct chain_t *p_dir, -- u32 type); --void update_dir_checksum(struct super_block *sb, struct chain_t *p_dir, -- s32 entry); --void update_dir_checksum_with_entry_set(struct super_block *sb, -- struct entry_set_cache_t *es); --bool is_dir_empty(struct super_block *sb, struct chain_t *p_dir); -- --/* name conversion functions */ --s32 get_num_entries_and_dos_name(struct super_block *sb, struct chain_t *p_dir, -- struct uni_name_t *p_uniname, s32 *entries, -- struct dos_name_t *p_dosname); --u16 calc_checksum_2byte(void *data, s32 len, u16 chksum, s32 type); -- --/* name resolution functions */ --s32 resolve_path(struct inode *inode, char *path, struct chain_t *p_dir, -- struct uni_name_t *p_uniname); -- --/* file operation functions */ --s32 exfat_mount(struct super_block *sb, struct pbr_sector_t *p_pbr); --s32 create_dir(struct inode *inode, struct chain_t *p_dir, -- struct uni_name_t *p_uniname, struct file_id_t *fid); --s32 create_file(struct inode *inode, struct chain_t *p_dir, -- struct uni_name_t *p_uniname, u8 mode, struct file_id_t *fid); --void remove_file(struct inode *inode, struct chain_t *p_dir, s32 entry); --s32 exfat_rename_file(struct inode *inode, struct chain_t *p_dir, s32 old_entry, -- struct uni_name_t *p_uniname, struct file_id_t *fid); --s32 move_file(struct inode *inode, struct chain_t *p_olddir, s32 oldentry, -- struct chain_t *p_newdir, struct uni_name_t *p_uniname, -- struct file_id_t *fid); -- --/* sector read/write functions */ --int sector_read(struct super_block *sb, sector_t sec, -- struct buffer_head **bh, bool read); --int sector_write(struct super_block *sb, sector_t sec, -- struct buffer_head *bh, bool sync); --int multi_sector_read(struct super_block *sb, sector_t sec, -- struct buffer_head **bh, s32 num_secs, bool read); --int multi_sector_write(struct super_block *sb, sector_t sec, -- struct buffer_head *bh, s32 num_secs, bool sync); -- --void exfat_bdev_open(struct super_block *sb); --void exfat_bdev_close(struct super_block *sb); --int exfat_bdev_read(struct super_block *sb, sector_t secno, -- struct buffer_head **bh, u32 num_secs, bool read); --int exfat_bdev_write(struct super_block *sb, sector_t secno, -- struct buffer_head *bh, u32 num_secs, bool sync); --int exfat_bdev_sync(struct super_block *sb); -- --/* cluster operation functions */ --s32 exfat_alloc_cluster(struct super_block *sb, s32 num_alloc, -- struct chain_t *p_chain); --void exfat_free_cluster(struct super_block *sb, struct chain_t *p_chain, -- s32 do_relse); --s32 exfat_count_used_clusters(struct super_block *sb); -- --/* dir operation functions */ --s32 exfat_find_dir_entry(struct super_block *sb, struct chain_t *p_dir, -- struct uni_name_t *p_uniname, s32 num_entries, -- struct dos_name_t *p_dosname, u32 type); --void exfat_delete_dir_entry(struct super_block *sb, struct chain_t *p_dir, -- s32 entry, s32 order, s32 num_entries); --void exfat_get_uni_name_from_ext_entry(struct super_block *sb, -- struct chain_t *p_dir, s32 entry, -- u16 *uniname); --s32 exfat_count_ext_entries(struct super_block *sb, struct chain_t *p_dir, -- s32 entry, struct dentry_t *p_entry); --s32 exfat_calc_num_entries(struct uni_name_t *p_uniname); -- --/* dir entry getter/setter */ --u32 exfat_get_entry_type(struct dentry_t *p_entry); --u32 exfat_get_entry_attr(struct dentry_t *p_entry); --void exfat_set_entry_attr(struct dentry_t *p_entry, u32 attr); --u8 exfat_get_entry_flag(struct dentry_t *p_entry); --void exfat_set_entry_flag(struct dentry_t *p_entry, u8 flags); --u32 exfat_get_entry_clu0(struct dentry_t *p_entry); --void exfat_set_entry_clu0(struct dentry_t *p_entry, u32 start_clu); --u64 exfat_get_entry_size(struct dentry_t *p_entry); --void exfat_set_entry_size(struct dentry_t *p_entry, u64 size); --void exfat_get_entry_time(struct dentry_t *p_entry, struct timestamp_t *tp, -- u8 mode); --void exfat_set_entry_time(struct dentry_t *p_entry, struct timestamp_t *tp, -- u8 mode); -- --extern const u8 uni_upcase[]; --#endif /* _EXFAT_H */ -diff -Nurp linux-5.6.3.orig/drivers/staging/exfat/exfat_nls.c linux-5.6.3/drivers/staging/exfat/exfat_nls.c ---- linux-5.6.3.orig/drivers/staging/exfat/exfat_nls.c 2020-03-30 01:25:41.000000000 +0300 -+++ linux-5.6.3/drivers/staging/exfat/exfat_nls.c 1970-01-01 02:00:00.000000000 +0200 -@@ -1,212 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0-or-later --/* -- * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -- */ -- --#include --#include --#include "exfat.h" -- --static u16 bad_uni_chars[] = { -- /* " * / : < > ? \ | */ -- 0x0022, 0x002A, 0x002F, 0x003A, -- 0x003C, 0x003E, 0x003F, 0x005C, 0x007C, -- 0 --}; -- --static int convert_ch_to_uni(struct nls_table *nls, u16 *uni, u8 *ch, -- bool *lossy) --{ -- int len; -- -- *uni = 0x0; -- -- if (ch[0] < 0x80) { -- *uni = (u16)ch[0]; -- return 1; -- } -- -- len = nls->char2uni(ch, NLS_MAX_CHARSET_SIZE, uni); -- if (len < 0) { -- /* conversion failed */ -- pr_info("%s: fail to use nls\n", __func__); -- if (lossy) -- *lossy = true; -- *uni = (u16)'_'; -- if (!strcmp(nls->charset, "utf8")) -- return 1; -- else -- return 2; -- } -- -- return len; --} -- --static int convert_uni_to_ch(struct nls_table *nls, u8 *ch, u16 uni, -- bool *lossy) --{ -- int len; -- -- ch[0] = 0x0; -- -- if (uni < 0x0080) { -- ch[0] = (u8)uni; -- return 1; -- } -- -- len = nls->uni2char(uni, ch, NLS_MAX_CHARSET_SIZE); -- if (len < 0) { -- /* conversion failed */ -- pr_info("%s: fail to use nls\n", __func__); -- if (lossy) -- *lossy = true; -- ch[0] = '_'; -- return 1; -- } -- -- return len; --} -- --u16 nls_upper(struct super_block *sb, u16 a) --{ -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- if (EXFAT_SB(sb)->options.casesensitive) -- return a; -- if (p_fs->vol_utbl && p_fs->vol_utbl[get_col_index(a)]) -- return p_fs->vol_utbl[get_col_index(a)][get_row_index(a)]; -- else -- return a; --} -- --static u16 *nls_wstrchr(u16 *str, u16 wchar) --{ -- while (*str) { -- if (*(str++) == wchar) -- return str; -- } -- -- return NULL; --} -- --int nls_uniname_cmp(struct super_block *sb, u16 *a, u16 *b) --{ -- int i; -- -- for (i = 0; i < MAX_NAME_LENGTH; i++, a++, b++) { -- if (nls_upper(sb, *a) != nls_upper(sb, *b)) -- return 1; -- if (*a == 0x0) -- return 0; -- } -- return 0; --} -- --void nls_uniname_to_cstring(struct super_block *sb, u8 *p_cstring, -- struct uni_name_t *p_uniname) --{ -- int i, j, len; -- u8 buf[MAX_CHARSET_SIZE]; -- u16 *uniname = p_uniname->name; -- struct nls_table *nls = EXFAT_SB(sb)->nls_io; -- -- if (!nls) { -- len = utf16s_to_utf8s(uniname, MAX_NAME_LENGTH, -- UTF16_HOST_ENDIAN, p_cstring, -- MAX_NAME_LENGTH); -- p_cstring[len] = 0; -- return; -- } -- -- i = 0; -- while (i < (MAX_NAME_LENGTH - 1)) { -- if (*uniname == (u16)'\0') -- break; -- -- len = convert_uni_to_ch(nls, buf, *uniname, NULL); -- -- if (len > 1) { -- for (j = 0; j < len; j++) -- *p_cstring++ = (char)*(buf + j); -- } else { /* len == 1 */ -- *p_cstring++ = (char)*buf; -- } -- -- uniname++; -- i++; -- } -- -- *p_cstring = '\0'; --} -- --void nls_cstring_to_uniname(struct super_block *sb, -- struct uni_name_t *p_uniname, u8 *p_cstring, -- bool *p_lossy) --{ -- int i, j; -- bool lossy = false; -- u8 *end_of_name; -- u8 upname[MAX_NAME_LENGTH * 2]; -- u16 *uniname = p_uniname->name; -- struct nls_table *nls = EXFAT_SB(sb)->nls_io; -- -- /* strip all trailing spaces */ -- end_of_name = p_cstring + strlen(p_cstring); -- -- while (*(--end_of_name) == ' ') { -- if (end_of_name < p_cstring) -- break; -- } -- *(++end_of_name) = '\0'; -- -- if (strcmp(p_cstring, ".") && strcmp(p_cstring, "..")) { -- /* strip all trailing periods */ -- while (*(--end_of_name) == '.') { -- if (end_of_name < p_cstring) -- break; -- } -- *(++end_of_name) = '\0'; -- } -- -- if (*p_cstring == '\0') -- lossy = true; -- -- if (!nls) { -- i = utf8s_to_utf16s(p_cstring, MAX_NAME_LENGTH, -- UTF16_HOST_ENDIAN, uniname, -- MAX_NAME_LENGTH); -- for (j = 0; j < i; j++) -- SET16_A(upname + j * 2, nls_upper(sb, uniname[j])); -- uniname[i] = '\0'; -- } else { -- i = 0; -- j = 0; -- while (j < (MAX_NAME_LENGTH - 1)) { -- if (*(p_cstring + i) == '\0') -- break; -- -- i += convert_ch_to_uni(nls, uniname, -- (u8 *)(p_cstring + i), &lossy); -- -- if ((*uniname < 0x0020) || -- nls_wstrchr(bad_uni_chars, *uniname)) -- lossy = true; -- -- SET16_A(upname + j * 2, nls_upper(sb, *uniname)); -- -- uniname++; -- j++; -- } -- -- if (*(p_cstring + i) != '\0') -- lossy = true; -- *uniname = (u16)'\0'; -- } -- -- p_uniname->name_len = j; -- p_uniname->name_hash = calc_checksum_2byte(upname, j << 1, 0, -- CS_DEFAULT); -- -- if (p_lossy) -- *p_lossy = lossy; --} -diff -Nurp linux-5.6.3.orig/drivers/staging/exfat/exfat_super.c linux-5.6.3/drivers/staging/exfat/exfat_super.c ---- linux-5.6.3.orig/drivers/staging/exfat/exfat_super.c 2020-03-30 01:25:41.000000000 +0300 -+++ linux-5.6.3/drivers/staging/exfat/exfat_super.c 1970-01-01 02:00:00.000000000 +0200 -@@ -1,3883 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0-or-later --/* -- * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -- */ -- --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include -- --#define EXFAT_VERSION "1.3.0" -- --#include "exfat.h" -- --static struct kmem_cache *exfat_inode_cachep; -- --static int exfat_default_codepage = CONFIG_STAGING_EXFAT_DEFAULT_CODEPAGE; --static char exfat_default_iocharset[] = CONFIG_STAGING_EXFAT_DEFAULT_IOCHARSET; -- --#define INC_IVERSION(x) (inode_inc_iversion(x)) --#define GET_IVERSION(x) (inode_peek_iversion_raw(x)) --#define SET_IVERSION(x, y) (inode_set_iversion(x, y)) -- --static struct inode *exfat_iget(struct super_block *sb, loff_t i_pos); --static int exfat_sync_inode(struct inode *inode); --static struct inode *exfat_build_inode(struct super_block *sb, -- struct file_id_t *fid, 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); -- --#define UNIX_SECS_1980 315532800L --#define UNIX_SECS_2108 4354819200L -- --/* Convert a FAT time/date pair to a UNIX date (seconds since 1 1 70). */ --static void exfat_time_fat2unix(struct timespec64 *ts, struct date_time_t *tp) --{ -- ts->tv_sec = mktime64(tp->Year + 1980, tp->Month + 1, tp->Day, -- tp->Hour, tp->Minute, tp->Second); -- -- ts->tv_nsec = tp->MilliSecond * NSEC_PER_MSEC; --} -- --/* Convert linear UNIX date to a FAT time/date pair. */ --static void exfat_time_unix2fat(struct timespec64 *ts, struct date_time_t *tp) --{ -- time64_t second = ts->tv_sec; -- struct tm tm; -- -- time64_to_tm(second, 0, &tm); -- -- if (second < UNIX_SECS_1980) { -- tp->MilliSecond = 0; -- tp->Second = 0; -- tp->Minute = 0; -- tp->Hour = 0; -- tp->Day = 1; -- tp->Month = 1; -- tp->Year = 0; -- return; -- } -- -- if (second >= UNIX_SECS_2108) { -- tp->MilliSecond = 999; -- tp->Second = 59; -- tp->Minute = 59; -- tp->Hour = 23; -- tp->Day = 31; -- tp->Month = 12; -- tp->Year = 127; -- return; -- } -- -- tp->MilliSecond = ts->tv_nsec / NSEC_PER_MSEC; -- tp->Second = tm.tm_sec; -- tp->Minute = tm.tm_min; -- tp->Hour = tm.tm_hour; -- tp->Day = tm.tm_mday; -- tp->Month = tm.tm_mon + 1; -- tp->Year = tm.tm_year + 1900 - 1980; --} -- --struct timestamp_t *tm_current(struct timestamp_t *tp) --{ -- time64_t second = ktime_get_real_seconds(); -- struct tm tm; -- -- time64_to_tm(second, 0, &tm); -- -- if (second < UNIX_SECS_1980) { -- tp->sec = 0; -- tp->min = 0; -- tp->hour = 0; -- tp->day = 1; -- tp->mon = 1; -- tp->year = 0; -- return tp; -- } -- -- if (second >= UNIX_SECS_2108) { -- tp->sec = 59; -- tp->min = 59; -- tp->hour = 23; -- tp->day = 31; -- tp->mon = 12; -- tp->year = 127; -- return tp; -- } -- -- tp->sec = tm.tm_sec; -- tp->min = tm.tm_min; -- tp->hour = tm.tm_hour; -- tp->day = tm.tm_mday; -- tp->mon = tm.tm_mon + 1; -- tp->year = tm.tm_year + 1900 - 1980; -- -- return tp; --} -- --static void __lock_super(struct super_block *sb) --{ -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- -- mutex_lock(&sbi->s_lock); --} -- --static void __unlock_super(struct super_block *sb) --{ -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- -- mutex_unlock(&sbi->s_lock); --} -- --static int __is_sb_dirty(struct super_block *sb) --{ -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- -- return sbi->s_dirt; --} -- --static void __set_sb_clean(struct super_block *sb) --{ -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- -- sbi->s_dirt = 0; --} -- --static int __exfat_revalidate(struct dentry *dentry) --{ -- return 0; --} -- --static int exfat_revalidate(struct dentry *dentry, unsigned int flags) --{ -- if (flags & LOOKUP_RCU) -- return -ECHILD; -- -- if (dentry->d_inode) -- return 1; -- return __exfat_revalidate(dentry); --} -- --static int exfat_revalidate_ci(struct dentry *dentry, unsigned int flags) --{ -- if (flags & LOOKUP_RCU) -- return -ECHILD; -- -- if (dentry->d_inode) -- return 1; -- -- if (!flags) -- return 0; -- -- if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) -- return 0; -- -- return __exfat_revalidate(dentry); --} -- --static unsigned int __exfat_striptail_len(unsigned int len, const char *name) --{ -- while (len && name[len - 1] == '.') -- len--; -- return len; --} -- --static unsigned int exfat_striptail_len(const struct qstr *qstr) --{ -- return __exfat_striptail_len(qstr->len, qstr->name); --} -- --static int exfat_d_hash(const struct dentry *dentry, struct qstr *qstr) --{ -- qstr->hash = full_name_hash(dentry, qstr->name, -- exfat_striptail_len(qstr)); -- return 0; --} -- --static int exfat_d_hashi(const struct dentry *dentry, struct qstr *qstr) --{ -- struct super_block *sb = dentry->d_sb; -- const unsigned char *name; -- unsigned int len; -- unsigned long hash; -- -- name = qstr->name; -- len = exfat_striptail_len(qstr); -- -- hash = init_name_hash(dentry); -- while (len--) -- hash = partial_name_hash(nls_upper(sb, *name++), hash); -- qstr->hash = end_name_hash(hash); -- -- return 0; --} -- --static int exfat_cmpi(const struct dentry *dentry, unsigned int len, -- const char *str, const struct qstr *name) --{ -- struct nls_table *t = EXFAT_SB(dentry->d_sb)->nls_io; -- unsigned int alen, blen; -- -- alen = exfat_striptail_len(name); -- blen = __exfat_striptail_len(len, str); -- if (alen == blen) { -- if (!t) { -- if (strncasecmp(name->name, str, alen) == 0) -- return 0; -- } else { -- if (nls_strnicmp(t, name->name, str, alen) == 0) -- return 0; -- } -- } -- return 1; --} -- --static int exfat_cmp(const struct dentry *dentry, unsigned int len, -- const char *str, const struct qstr *name) --{ -- unsigned int alen, blen; -- -- alen = exfat_striptail_len(name); -- blen = __exfat_striptail_len(len, str); -- if (alen == blen) { -- if (strncmp(name->name, str, alen) == 0) -- return 0; -- } -- return 1; --} -- --static const struct dentry_operations exfat_ci_dentry_ops = { -- .d_revalidate = exfat_revalidate_ci, -- .d_hash = exfat_d_hashi, -- .d_compare = exfat_cmpi, --}; -- --static const struct dentry_operations exfat_dentry_ops = { -- .d_revalidate = exfat_revalidate, -- .d_hash = exfat_d_hash, -- .d_compare = exfat_cmp, --}; -- --static DEFINE_MUTEX(z_mutex); -- --static inline void fs_sync(struct super_block *sb, bool do_sync) --{ -- if (do_sync) -- exfat_bdev_sync(sb); --} -- --/* -- * If ->i_mode can't hold S_IWUGO (i.e. ATTR_RO), we use ->i_attrs to -- * save ATTR_RO instead of ->i_mode. -- * -- * If it's directory and !sbi->options.rodir, ATTR_RO isn't read-only -- * bit, it's just used as flag for app. -- */ --static inline int exfat_mode_can_hold_ro(struct inode *inode) --{ -- struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); -- -- if (S_ISDIR(inode->i_mode)) -- return 0; -- -- if ((~sbi->options.fs_fmask) & 0222) -- return 1; -- return 0; --} -- --/* Convert attribute bits and a mask to the UNIX mode. */ --static inline mode_t exfat_make_mode(struct exfat_sb_info *sbi, u32 attr, -- mode_t mode) --{ -- if ((attr & ATTR_READONLY) && !(attr & ATTR_SUBDIR)) -- mode &= ~0222; -- -- if (attr & ATTR_SUBDIR) -- return (mode & ~sbi->options.fs_dmask) | S_IFDIR; -- else if (attr & ATTR_SYMLINK) -- return (mode & ~sbi->options.fs_dmask) | S_IFLNK; -- else -- return (mode & ~sbi->options.fs_fmask) | S_IFREG; --} -- --/* Return the FAT attribute byte for this inode */ --static inline u32 exfat_make_attr(struct inode *inode) --{ -- if (exfat_mode_can_hold_ro(inode) && !(inode->i_mode & 0222)) -- return (EXFAT_I(inode)->fid.attr) | ATTR_READONLY; -- else -- return EXFAT_I(inode)->fid.attr; --} -- --static inline void exfat_save_attr(struct inode *inode, u32 attr) --{ -- if (exfat_mode_can_hold_ro(inode)) -- EXFAT_I(inode)->fid.attr = attr & ATTR_RWMASK; -- else -- EXFAT_I(inode)->fid.attr = attr & (ATTR_RWMASK | ATTR_READONLY); --} -- --static int ffsMountVol(struct super_block *sb) --{ -- int i, ret; -- struct pbr_sector_t *p_pbr; -- struct buffer_head *tmp_bh = NULL; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- -- pr_info("[EXFAT] trying to mount...\n"); -- -- mutex_lock(&z_mutex); -- -- exfat_buf_init(sb); -- -- mutex_init(&p_fs->v_mutex); -- p_fs->dev_ejected = 0; -- -- /* open the block device */ -- exfat_bdev_open(sb); -- -- if (p_bd->sector_size < sb->s_blocksize) { -- printk(KERN_INFO "EXFAT: mount failed - sector size %d less than blocksize %ld\n", -- p_bd->sector_size, sb->s_blocksize); -- ret = -EINVAL; -- goto out; -- } -- if (p_bd->sector_size > sb->s_blocksize) -- sb_set_blocksize(sb, p_bd->sector_size); -- -- /* read Sector 0 */ -- if (sector_read(sb, 0, &tmp_bh, 1) != 0) { -- ret = -EIO; -- goto out; -- } -- -- p_fs->PBR_sector = 0; -- -- p_pbr = (struct pbr_sector_t *)tmp_bh->b_data; -- -- /* check the validity of PBR */ -- if (GET16_A(p_pbr->signature) != PBR_SIGNATURE) { -- brelse(tmp_bh); -- exfat_bdev_close(sb); -- ret = -EFSCORRUPTED; -- goto out; -- } -- -- /* fill fs_struct */ -- for (i = 0; i < 53; i++) -- if (p_pbr->bpb[i]) -- break; -- -- if (i < 53) { -- /* Not sure how we'd get here, but complain if it does */ -- ret = -EINVAL; -- pr_info("EXFAT: Attempted to mount VFAT filesystem\n"); -- goto out; -- } else { -- ret = exfat_mount(sb, p_pbr); -- } -- -- brelse(tmp_bh); -- -- if (ret) { -- exfat_bdev_close(sb); -- goto out; -- } -- -- ret = load_alloc_bitmap(sb); -- if (ret) { -- exfat_bdev_close(sb); -- goto out; -- } -- ret = load_upcase_table(sb); -- if (ret) { -- free_alloc_bitmap(sb); -- exfat_bdev_close(sb); -- goto out; -- } -- -- if (p_fs->dev_ejected) { -- free_upcase_table(sb); -- free_alloc_bitmap(sb); -- exfat_bdev_close(sb); -- ret = -EIO; -- goto out; -- } -- -- pr_info("[EXFAT] mounted successfully\n"); -- --out: -- mutex_unlock(&z_mutex); -- -- return ret; --} -- --static int ffsUmountVol(struct super_block *sb) --{ -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- int err = 0; -- -- pr_info("[EXFAT] trying to unmount...\n"); -- -- mutex_lock(&z_mutex); -- -- /* acquire the lock for file system critical section */ -- mutex_lock(&p_fs->v_mutex); -- -- fs_sync(sb, true); -- fs_set_vol_flags(sb, VOL_CLEAN); -- -- free_upcase_table(sb); -- free_alloc_bitmap(sb); -- -- exfat_fat_release_all(sb); -- exfat_buf_release_all(sb); -- -- /* close the block device */ -- exfat_bdev_close(sb); -- -- if (p_fs->dev_ejected) { -- pr_info("[EXFAT] unmounted with media errors. Device is already ejected.\n"); -- err = -EIO; -- } -- -- exfat_buf_shutdown(sb); -- -- /* release the lock for file system critical section */ -- mutex_unlock(&p_fs->v_mutex); -- mutex_unlock(&z_mutex); -- -- pr_info("[EXFAT] unmounted successfully\n"); -- -- return err; --} -- --static int ffsGetVolInfo(struct super_block *sb, struct vol_info_t *info) --{ -- int err = 0; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- /* check the validity of pointer parameters */ -- if (!info) -- return -EINVAL; -- -- /* acquire the lock for file system critical section */ -- mutex_lock(&p_fs->v_mutex); -- -- if (p_fs->used_clusters == UINT_MAX) -- p_fs->used_clusters = exfat_count_used_clusters(sb); -- -- info->FatType = p_fs->vol_type; -- info->ClusterSize = p_fs->cluster_size; -- info->NumClusters = p_fs->num_clusters - 2; /* clu 0 & 1 */ -- info->UsedClusters = p_fs->used_clusters; -- info->FreeClusters = info->NumClusters - info->UsedClusters; -- -- if (p_fs->dev_ejected) -- err = -EIO; -- -- /* release the lock for file system critical section */ -- mutex_unlock(&p_fs->v_mutex); -- -- return err; --} -- --static int ffsSyncVol(struct super_block *sb, bool do_sync) --{ -- int err = 0; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- /* acquire the lock for file system critical section */ -- mutex_lock(&p_fs->v_mutex); -- -- /* synchronize the file system */ -- fs_sync(sb, do_sync); -- fs_set_vol_flags(sb, VOL_CLEAN); -- -- if (p_fs->dev_ejected) -- err = -EIO; -- -- /* release the lock for file system critical section */ -- mutex_unlock(&p_fs->v_mutex); -- -- return err; --} -- --/*----------------------------------------------------------------------*/ --/* File Operation Functions */ --/*----------------------------------------------------------------------*/ -- --static int ffsLookupFile(struct inode *inode, char *path, struct file_id_t *fid) --{ -- int ret, dentry, num_entries; -- struct chain_t dir; -- struct uni_name_t uni_name; -- struct dos_name_t dos_name; -- struct dentry_t *ep, *ep2; -- struct entry_set_cache_t *es = NULL; -- struct super_block *sb = inode->i_sb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- pr_debug("%s entered\n", __func__); -- -- /* check the validity of pointer parameters */ -- if (!fid || !path || (*path == '\0')) -- return -EINVAL; -- -- /* acquire the lock for file system critical section */ -- mutex_lock(&p_fs->v_mutex); -- -- /* check the validity of directory name in the given pathname */ -- ret = resolve_path(inode, path, &dir, &uni_name); -- if (ret) -- goto out; -- -- ret = get_num_entries_and_dos_name(sb, &dir, &uni_name, &num_entries, -- &dos_name); -- if (ret) -- goto out; -- -- /* search the file name for directories */ -- dentry = exfat_find_dir_entry(sb, &dir, &uni_name, num_entries, -- &dos_name, TYPE_ALL); -- if (dentry < -1) { -- ret = -ENOENT; -- goto out; -- } -- -- fid->dir.dir = dir.dir; -- fid->dir.size = dir.size; -- fid->dir.flags = dir.flags; -- fid->entry = dentry; -- -- if (dentry == -1) { -- fid->type = TYPE_DIR; -- fid->rwoffset = 0; -- fid->hint_last_off = -1; -- -- fid->attr = ATTR_SUBDIR; -- fid->flags = 0x01; -- fid->size = 0; -- fid->start_clu = p_fs->root_dir; -- } else { -- es = get_entry_set_in_dir(sb, &dir, dentry, -- ES_2_ENTRIES, &ep); -- if (!es) { -- ret = -ENOENT; -- goto out; -- } -- ep2 = ep + 1; -- -- fid->type = exfat_get_entry_type(ep); -- fid->rwoffset = 0; -- fid->hint_last_off = -1; -- fid->attr = exfat_get_entry_attr(ep); -- -- fid->size = exfat_get_entry_size(ep2); -- if ((fid->type == TYPE_FILE) && (fid->size == 0)) { -- fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; -- fid->start_clu = CLUSTER_32(~0); -- } else { -- fid->flags = exfat_get_entry_flag(ep2); -- fid->start_clu = exfat_get_entry_clu0(ep2); -- } -- -- release_entry_set(es); -- } -- -- if (p_fs->dev_ejected) -- ret = -EIO; --out: -- /* release the lock for file system critical section */ -- mutex_unlock(&p_fs->v_mutex); -- -- return ret; --} -- --static int ffsCreateFile(struct inode *inode, char *path, u8 mode, -- struct file_id_t *fid) --{ -- struct chain_t dir; -- struct uni_name_t uni_name; -- struct super_block *sb = inode->i_sb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- int ret = 0; -- -- /* check the validity of pointer parameters */ -- if (!fid || !path || (*path == '\0')) -- return -EINVAL; -- -- /* acquire the lock for file system critical section */ -- mutex_lock(&p_fs->v_mutex); -- -- /* check the validity of directory name in the given pathname */ -- ret = resolve_path(inode, path, &dir, &uni_name); -- if (ret) -- goto out; -- -- fs_set_vol_flags(sb, VOL_DIRTY); -- -- /* create a new file */ -- ret = create_file(inode, &dir, &uni_name, mode, fid); -- --#ifndef CONFIG_STAGING_EXFAT_DELAYED_SYNC -- fs_sync(sb, true); -- fs_set_vol_flags(sb, VOL_CLEAN); --#endif -- -- if (p_fs->dev_ejected) -- ret = -EIO; -- --out: -- /* release the lock for file system critical section */ -- mutex_unlock(&p_fs->v_mutex); -- -- return ret; --} -- --static int ffsReadFile(struct inode *inode, struct file_id_t *fid, void *buffer, -- u64 count, u64 *rcount) --{ -- s32 offset, sec_offset, clu_offset; -- u32 clu; -- int ret = 0; -- sector_t LogSector; -- u64 oneblkread, read_bytes; -- struct buffer_head *tmp_bh = NULL; -- struct super_block *sb = inode->i_sb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- -- /* check the validity of the given file id */ -- if (!fid) -- return -EINVAL; -- -- /* check the validity of pointer parameters */ -- if (!buffer) -- return -EINVAL; -- -- /* acquire the lock for file system critical section */ -- mutex_lock(&p_fs->v_mutex); -- -- /* check if the given file ID is opened */ -- if (fid->type != TYPE_FILE) { -- ret = -EPERM; -- goto out; -- } -- -- if (fid->rwoffset > fid->size) -- fid->rwoffset = fid->size; -- -- if (count > (fid->size - fid->rwoffset)) -- count = fid->size - fid->rwoffset; -- -- if (count == 0) { -- if (rcount) -- *rcount = 0; -- ret = 0; -- goto out; -- } -- -- read_bytes = 0; -- -- while (count > 0) { -- clu_offset = (s32)(fid->rwoffset >> p_fs->cluster_size_bits); -- clu = fid->start_clu; -- -- if (fid->flags == 0x03) { -- clu += clu_offset; -- } else { -- /* hint information */ -- if ((clu_offset > 0) && (fid->hint_last_off > 0) && -- (clu_offset >= fid->hint_last_off)) { -- clu_offset -= fid->hint_last_off; -- clu = fid->hint_last_clu; -- } -- -- while (clu_offset > 0) { -- /* clu = exfat_fat_read(sb, clu); */ -- if (exfat_fat_read(sb, clu, &clu) == -1) { -- ret = -EIO; -- goto out; -- } -- -- clu_offset--; -- } -- } -- -- /* hint information */ -- fid->hint_last_off = (s32)(fid->rwoffset >> -- p_fs->cluster_size_bits); -- fid->hint_last_clu = clu; -- -- /* byte offset in cluster */ -- offset = (s32)(fid->rwoffset & (p_fs->cluster_size - 1)); -- -- /* sector offset in cluster */ -- sec_offset = offset >> p_bd->sector_size_bits; -- -- /* byte offset in sector */ -- offset &= p_bd->sector_size_mask; -- -- LogSector = START_SECTOR(clu) + sec_offset; -- -- oneblkread = (u64)(p_bd->sector_size - offset); -- if (oneblkread > count) -- oneblkread = count; -- -- if ((offset == 0) && (oneblkread == p_bd->sector_size)) { -- if (sector_read(sb, LogSector, &tmp_bh, 1) != -- 0) -- goto err_out; -- memcpy((char *)buffer + read_bytes, -- (char *)tmp_bh->b_data, (s32)oneblkread); -- } else { -- if (sector_read(sb, LogSector, &tmp_bh, 1) != -- 0) -- goto err_out; -- memcpy((char *)buffer + read_bytes, -- (char *)tmp_bh->b_data + offset, -- (s32)oneblkread); -- } -- count -= oneblkread; -- read_bytes += oneblkread; -- fid->rwoffset += oneblkread; -- } -- brelse(tmp_bh); -- --/* How did this ever work and not leak a brlse()?? */ --err_out: -- /* set the size of read bytes */ -- if (rcount) -- *rcount = read_bytes; -- -- if (p_fs->dev_ejected) -- ret = -EIO; -- --out: -- /* release the lock for file system critical section */ -- mutex_unlock(&p_fs->v_mutex); -- -- return ret; --} -- --static int ffsWriteFile(struct inode *inode, struct file_id_t *fid, -- void *buffer, u64 count, u64 *wcount) --{ -- bool modified = false; -- s32 offset, sec_offset, clu_offset; -- s32 num_clusters, num_alloc, num_alloced = (s32)~0; -- int ret = 0; -- u32 clu, last_clu; -- sector_t LogSector; -- u64 oneblkwrite, write_bytes; -- struct chain_t new_clu; -- struct timestamp_t tm; -- struct dentry_t *ep, *ep2; -- struct entry_set_cache_t *es = NULL; -- struct buffer_head *tmp_bh = NULL; -- struct super_block *sb = inode->i_sb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- -- /* check the validity of the given file id */ -- if (!fid) -- return -EINVAL; -- -- /* check the validity of pointer parameters */ -- if (!buffer) -- return -EINVAL; -- -- /* acquire the lock for file system critical section */ -- mutex_lock(&p_fs->v_mutex); -- -- /* check if the given file ID is opened */ -- if (fid->type != TYPE_FILE) { -- ret = -EPERM; -- goto out; -- } -- -- if (fid->rwoffset > fid->size) -- fid->rwoffset = fid->size; -- -- if (count == 0) { -- if (wcount) -- *wcount = 0; -- ret = 0; -- goto out; -- } -- -- fs_set_vol_flags(sb, VOL_DIRTY); -- -- if (fid->size == 0) -- num_clusters = 0; -- else -- num_clusters = (s32)((fid->size - 1) >> -- p_fs->cluster_size_bits) + 1; -- -- write_bytes = 0; -- -- while (count > 0) { -- clu_offset = (s32)(fid->rwoffset >> p_fs->cluster_size_bits); -- clu = fid->start_clu; -- last_clu = fid->start_clu; -- -- if (fid->flags == 0x03) { -- if ((clu_offset > 0) && (clu != CLUSTER_32(~0))) { -- last_clu += clu_offset - 1; -- -- if (clu_offset == num_clusters) -- clu = CLUSTER_32(~0); -- else -- clu += clu_offset; -- } -- } else { -- /* hint information */ -- if ((clu_offset > 0) && (fid->hint_last_off > 0) && -- (clu_offset >= fid->hint_last_off)) { -- clu_offset -= fid->hint_last_off; -- clu = fid->hint_last_clu; -- } -- -- while ((clu_offset > 0) && (clu != CLUSTER_32(~0))) { -- last_clu = clu; -- /* clu = exfat_fat_read(sb, clu); */ -- if (exfat_fat_read(sb, clu, &clu) == -1) { -- ret = -EIO; -- goto out; -- } -- clu_offset--; -- } -- } -- -- if (clu == CLUSTER_32(~0)) { -- num_alloc = (s32)((count - 1) >> -- p_fs->cluster_size_bits) + 1; -- new_clu.dir = (last_clu == CLUSTER_32(~0)) ? -- CLUSTER_32(~0) : last_clu + 1; -- new_clu.size = 0; -- new_clu.flags = fid->flags; -- -- /* (1) allocate a chain of clusters */ -- num_alloced = exfat_alloc_cluster(sb, -- num_alloc, -- &new_clu); -- if (num_alloced == 0) -- break; -- if (num_alloced < 0) { -- ret = num_alloced; -- goto out; -- } -- -- /* (2) append to the FAT chain */ -- if (last_clu == CLUSTER_32(~0)) { -- if (new_clu.flags == 0x01) -- fid->flags = 0x01; -- fid->start_clu = new_clu.dir; -- modified = true; -- } else { -- if (new_clu.flags != fid->flags) { -- exfat_chain_cont_cluster(sb, -- fid->start_clu, -- num_clusters); -- fid->flags = 0x01; -- modified = true; -- } -- if (new_clu.flags == 0x01) -- exfat_fat_write(sb, last_clu, new_clu.dir); -- } -- -- num_clusters += num_alloced; -- clu = new_clu.dir; -- } -- -- /* hint information */ -- fid->hint_last_off = (s32)(fid->rwoffset >> -- p_fs->cluster_size_bits); -- fid->hint_last_clu = clu; -- -- /* byte offset in cluster */ -- offset = (s32)(fid->rwoffset & (p_fs->cluster_size - 1)); -- -- /* sector offset in cluster */ -- sec_offset = offset >> p_bd->sector_size_bits; -- -- /* byte offset in sector */ -- offset &= p_bd->sector_size_mask; -- -- LogSector = START_SECTOR(clu) + sec_offset; -- -- oneblkwrite = (u64)(p_bd->sector_size - offset); -- if (oneblkwrite > count) -- oneblkwrite = count; -- -- if ((offset == 0) && (oneblkwrite == p_bd->sector_size)) { -- if (sector_read(sb, LogSector, &tmp_bh, 0) != -- 0) -- goto err_out; -- memcpy((char *)tmp_bh->b_data, -- (char *)buffer + write_bytes, (s32)oneblkwrite); -- if (sector_write(sb, LogSector, tmp_bh, 0) != -- 0) { -- brelse(tmp_bh); -- goto err_out; -- } -- } else { -- if ((offset > 0) || -- ((fid->rwoffset + oneblkwrite) < fid->size)) { -- if (sector_read(sb, LogSector, &tmp_bh, 1) != -- 0) -- goto err_out; -- } else { -- if (sector_read(sb, LogSector, &tmp_bh, 0) != -- 0) -- goto err_out; -- } -- -- memcpy((char *)tmp_bh->b_data + offset, -- (char *)buffer + write_bytes, (s32)oneblkwrite); -- if (sector_write(sb, LogSector, tmp_bh, 0) != -- 0) { -- brelse(tmp_bh); -- goto err_out; -- } -- } -- -- count -= oneblkwrite; -- write_bytes += oneblkwrite; -- fid->rwoffset += oneblkwrite; -- -- fid->attr |= ATTR_ARCHIVE; -- -- if (fid->size < fid->rwoffset) { -- fid->size = fid->rwoffset; -- modified = true; -- } -- } -- -- brelse(tmp_bh); -- -- /* (3) update the direcoty entry */ -- es = get_entry_set_in_dir(sb, &fid->dir, fid->entry, -- ES_ALL_ENTRIES, &ep); -- if (!es) -- goto err_out; -- ep2 = ep + 1; -- -- exfat_set_entry_time(ep, tm_current(&tm), TM_MODIFY); -- exfat_set_entry_attr(ep, fid->attr); -- -- if (modified) { -- if (exfat_get_entry_flag(ep2) != fid->flags) -- exfat_set_entry_flag(ep2, fid->flags); -- -- if (exfat_get_entry_size(ep2) != fid->size) -- exfat_set_entry_size(ep2, fid->size); -- -- if (exfat_get_entry_clu0(ep2) != fid->start_clu) -- exfat_set_entry_clu0(ep2, fid->start_clu); -- } -- -- update_dir_checksum_with_entry_set(sb, es); -- release_entry_set(es); -- --#ifndef CONFIG_STAGING_EXFAT_DELAYED_SYNC -- fs_sync(sb, true); -- fs_set_vol_flags(sb, VOL_CLEAN); --#endif -- --err_out: -- /* set the size of written bytes */ -- if (wcount) -- *wcount = write_bytes; -- -- if (num_alloced == 0) -- ret = -ENOSPC; -- -- else if (p_fs->dev_ejected) -- ret = -EIO; -- --out: -- /* release the lock for file system critical section */ -- mutex_unlock(&p_fs->v_mutex); -- -- return ret; --} -- --static int ffsTruncateFile(struct inode *inode, u64 old_size, u64 new_size) --{ -- s32 num_clusters; -- u32 last_clu = CLUSTER_32(0); -- int ret = 0; -- struct chain_t clu; -- struct timestamp_t tm; -- struct dentry_t *ep, *ep2; -- struct super_block *sb = inode->i_sb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct file_id_t *fid = &(EXFAT_I(inode)->fid); -- struct entry_set_cache_t *es = NULL; -- -- pr_debug("%s entered (inode %p size %llu)\n", __func__, inode, -- new_size); -- -- /* acquire the lock for file system critical section */ -- mutex_lock(&p_fs->v_mutex); -- -- /* check if the given file ID is opened */ -- if (fid->type != TYPE_FILE) { -- ret = -EPERM; -- goto out; -- } -- -- if (fid->size != old_size) { -- pr_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) { -- ret = 0; -- goto out; -- } -- -- fs_set_vol_flags(sb, VOL_DIRTY); -- -- clu.dir = fid->start_clu; -- clu.size = (s32)((old_size - 1) >> p_fs->cluster_size_bits) + 1; -- clu.flags = fid->flags; -- -- if (new_size > 0) { -- num_clusters = (s32)((new_size - 1) >> -- p_fs->cluster_size_bits) + 1; -- -- if (clu.flags == 0x03) { -- clu.dir += num_clusters; -- } else { -- while (num_clusters > 0) { -- last_clu = clu.dir; -- if (exfat_fat_read(sb, clu.dir, &clu.dir) == -1) { -- ret = -EIO; -- goto out; -- } -- num_clusters--; -- } -- } -- -- clu.size -= num_clusters; -- } -- -- fid->size = new_size; -- fid->attr |= ATTR_ARCHIVE; -- if (new_size == 0) { -- fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; -- fid->start_clu = CLUSTER_32(~0); -- } -- -- /* (1) update the directory entry */ -- es = get_entry_set_in_dir(sb, &fid->dir, fid->entry, -- ES_ALL_ENTRIES, &ep); -- if (!es) { -- ret = -ENOENT; -- goto out; -- } -- ep2 = ep + 1; -- -- exfat_set_entry_time(ep, tm_current(&tm), TM_MODIFY); -- exfat_set_entry_attr(ep, fid->attr); -- -- exfat_set_entry_size(ep2, new_size); -- if (new_size == 0) { -- exfat_set_entry_flag(ep2, 0x01); -- exfat_set_entry_clu0(ep2, CLUSTER_32(0)); -- } -- -- update_dir_checksum_with_entry_set(sb, es); -- release_entry_set(es); -- -- /* (2) cut off from the FAT chain */ -- if (last_clu != CLUSTER_32(0)) { -- if (fid->flags == 0x01) -- exfat_fat_write(sb, last_clu, CLUSTER_32(~0)); -- } -- -- /* (3) free the clusters */ -- exfat_free_cluster(sb, &clu, 0); -- -- /* hint information */ -- fid->hint_last_off = -1; -- if (fid->rwoffset > fid->size) -- fid->rwoffset = fid->size; -- --#ifndef CONFIG_STAGING_EXFAT_DELAYED_SYNC -- fs_sync(sb, true); -- fs_set_vol_flags(sb, VOL_CLEAN); --#endif -- -- if (p_fs->dev_ejected) -- ret = -EIO; -- --out: -- pr_debug("%s exited (%d)\n", __func__, ret); -- /* release the lock for file system critical section */ -- mutex_unlock(&p_fs->v_mutex); -- -- return ret; --} -- --static void update_parent_info(struct file_id_t *fid, -- struct inode *parent_inode) --{ -- struct fs_info_t *p_fs = &(EXFAT_SB(parent_inode->i_sb)->fs_info); -- struct file_id_t *parent_fid = &(EXFAT_I(parent_inode)->fid); -- -- if (unlikely((parent_fid->flags != fid->dir.flags) || -- (parent_fid->size != -- (fid->dir.size << p_fs->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); -- } --} -- --static int ffsMoveFile(struct inode *old_parent_inode, struct file_id_t *fid, -- struct inode *new_parent_inode, struct dentry *new_dentry) --{ -- s32 ret; -- s32 dentry; -- struct chain_t olddir, newdir; -- struct chain_t *p_dir = NULL; -- struct uni_name_t uni_name; -- struct dentry_t *ep; -- struct super_block *sb = old_parent_inode->i_sb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- u8 *new_path = (u8 *)new_dentry->d_name.name; -- struct inode *new_inode = new_dentry->d_inode; -- int num_entries; -- struct file_id_t *new_fid = NULL; -- s32 new_entry = 0; -- -- /* check the validity of the given file id */ -- if (!fid) -- return -EINVAL; -- -- /* check the validity of pointer parameters */ -- if (!new_path || (*new_path == '\0')) -- return -EINVAL; -- -- /* acquire the lock for file system critical section */ -- mutex_lock(&p_fs->v_mutex); -- -- update_parent_info(fid, old_parent_inode); -- -- olddir.dir = fid->dir.dir; -- olddir.size = fid->dir.size; -- olddir.flags = fid->dir.flags; -- -- dentry = fid->entry; -- -- /* check if the old file is "." or ".." */ -- if (p_fs->vol_type != EXFAT) { -- if ((olddir.dir != p_fs->root_dir) && (dentry < 2)) { -- ret = -EPERM; -- goto out2; -- } -- } -- -- ep = get_entry_in_dir(sb, &olddir, dentry, NULL); -- if (!ep) { -- ret = -ENOENT; -- goto out2; -- } -- -- if (exfat_get_entry_attr(ep) & ATTR_READONLY) { -- ret = -EPERM; -- goto out2; -- } -- -- /* check whether new dir is existing directory and empty */ -- if (new_inode) { -- u32 entry_type; -- -- ret = -ENOENT; -- 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); -- if (!ep) -- goto out; -- -- entry_type = exfat_get_entry_type(ep); -- -- if (entry_type == TYPE_DIR) { -- struct chain_t new_clu; -- -- new_clu.dir = new_fid->start_clu; -- new_clu.size = (s32)((new_fid->size - 1) >> -- p_fs->cluster_size_bits) + 1; -- new_clu.flags = new_fid->flags; -- -- if (!is_dir_empty(sb, &new_clu)) { -- ret = -EEXIST; -- goto out; -- } -- } -- } -- -- /* check the validity of directory name in the given new pathname */ -- ret = resolve_path(new_parent_inode, new_path, &newdir, &uni_name); -- if (ret) -- goto out2; -- -- fs_set_vol_flags(sb, VOL_DIRTY); -- -- if (olddir.dir == newdir.dir) -- ret = exfat_rename_file(new_parent_inode, &olddir, dentry, -- &uni_name, fid); -- else -- ret = move_file(new_parent_inode, &olddir, dentry, &newdir, -- &uni_name, fid); -- -- if ((ret == 0) && new_inode) { -- /* delete entries of new_dir */ -- ep = get_entry_in_dir(sb, p_dir, new_entry, NULL); -- if (!ep) -- goto out; -- -- num_entries = exfat_count_ext_entries(sb, p_dir, -- new_entry, ep); -- if (num_entries < 0) -- goto out; -- exfat_delete_dir_entry(sb, p_dir, new_entry, 0, -- num_entries + 1); -- } --out: --#ifndef CONFIG_STAGING_EXFAT_DELAYED_SYNC -- fs_sync(sb, true); -- fs_set_vol_flags(sb, VOL_CLEAN); --#endif -- -- if (p_fs->dev_ejected) -- ret = -EIO; --out2: -- /* release the lock for file system critical section */ -- mutex_unlock(&p_fs->v_mutex); -- -- return ret; --} -- --static int ffsRemoveFile(struct inode *inode, struct file_id_t *fid) --{ -- s32 dentry; -- int ret = 0; -- struct chain_t dir, clu_to_free; -- struct dentry_t *ep; -- struct super_block *sb = inode->i_sb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- /* check the validity of the given file id */ -- if (!fid) -- return -EINVAL; -- -- /* acquire the lock for file system critical section */ -- mutex_lock(&p_fs->v_mutex); -- -- dir.dir = fid->dir.dir; -- dir.size = fid->dir.size; -- dir.flags = fid->dir.flags; -- -- dentry = fid->entry; -- -- ep = get_entry_in_dir(sb, &dir, dentry, NULL); -- if (!ep) { -- ret = -ENOENT; -- goto out; -- } -- -- if (exfat_get_entry_attr(ep) & ATTR_READONLY) { -- ret = -EPERM; -- goto out; -- } -- fs_set_vol_flags(sb, VOL_DIRTY); -- -- /* (1) update the directory entry */ -- remove_file(inode, &dir, dentry); -- -- clu_to_free.dir = fid->start_clu; -- clu_to_free.size = (s32)((fid->size - 1) >> p_fs->cluster_size_bits) + 1; -- clu_to_free.flags = fid->flags; -- -- /* (2) free the clusters */ -- exfat_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; -- --#ifndef CONFIG_STAGING_EXFAT_DELAYED_SYNC -- fs_sync(sb, true); -- fs_set_vol_flags(sb, VOL_CLEAN); --#endif -- -- if (p_fs->dev_ejected) -- ret = -EIO; --out: -- /* release the lock for file system critical section */ -- mutex_unlock(&p_fs->v_mutex); -- -- return ret; --} -- --#if 0 --/* Not currently wired up */ --static int ffsSetAttr(struct inode *inode, u32 attr) --{ -- u32 type; -- int ret = 0; -- sector_t sector = 0; -- struct dentry_t *ep; -- struct super_block *sb = inode->i_sb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct file_id_t *fid = &(EXFAT_I(inode)->fid); -- u8 is_dir = (fid->type == TYPE_DIR) ? 1 : 0; -- struct entry_set_cache_t *es = NULL; -- -- if (fid->attr == attr) { -- if (p_fs->dev_ejected) -- return -EIO; -- return 0; -- } -- -- if (is_dir) { -- if ((fid->dir.dir == p_fs->root_dir) && -- (fid->entry == -1)) { -- if (p_fs->dev_ejected) -- return -EIO; -- return 0; -- } -- } -- -- /* acquire the lock for file system critical section */ -- mutex_lock(&p_fs->v_mutex); -- -- /* get the directory entry of given file */ -- es = get_entry_set_in_dir(sb, &fid->dir, fid->entry, -- ES_ALL_ENTRIES, &ep); -- if (!es) { -- ret = -ENOENT; -- goto out; -- } -- -- type = exfat_get_entry_type(ep); -- -- if (((type == TYPE_FILE) && (attr & ATTR_SUBDIR)) || -- ((type == TYPE_DIR) && (!(attr & ATTR_SUBDIR)))) { -- if (p_fs->dev_ejected) -- ret = -EIO; -- else -- ret = -EINVAL; -- -- release_entry_set(es); -- goto out; -- } -- -- fs_set_vol_flags(sb, VOL_DIRTY); -- -- /* set the file attribute */ -- fid->attr = attr; -- exfat_set_entry_attr(ep, attr); -- -- update_dir_checksum_with_entry_set(sb, es); -- release_entry_set(es); -- --#ifndef CONFIG_STAGING_EXFAT_DELAYED_SYNC -- fs_sync(sb, true); -- fs_set_vol_flags(sb, VOL_CLEAN); --#endif -- -- if (p_fs->dev_ejected) -- ret = -EIO; --out: -- /* release the lock for file system critical section */ -- mutex_unlock(&p_fs->v_mutex); -- -- return ret; --} --#endif -- --static int ffsReadStat(struct inode *inode, struct dir_entry_t *info) --{ -- s32 count; -- int ret = 0; -- struct chain_t dir; -- struct uni_name_t uni_name; -- struct timestamp_t tm; -- struct dentry_t *ep, *ep2; -- struct super_block *sb = inode->i_sb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct file_id_t *fid = &(EXFAT_I(inode)->fid); -- struct entry_set_cache_t *es = NULL; -- u8 is_dir = (fid->type == TYPE_DIR) ? 1 : 0; -- -- pr_debug("%s entered\n", __func__); -- -- /* acquire the lock for file system critical section */ -- mutex_lock(&p_fs->v_mutex); -- -- if (is_dir) { -- if ((fid->dir.dir == p_fs->root_dir) && -- (fid->entry == -1)) { -- info->Attr = ATTR_SUBDIR; -- memset((char *)&info->CreateTimestamp, 0, -- sizeof(struct date_time_t)); -- memset((char *)&info->ModifyTimestamp, 0, -- sizeof(struct date_time_t)); -- memset((char *)&info->AccessTimestamp, 0, -- sizeof(struct date_time_t)); -- strcpy(info->ShortName, "."); -- strcpy(info->Name, "."); -- -- dir.dir = p_fs->root_dir; -- dir.flags = 0x01; -- -- if (p_fs->root_dir == CLUSTER_32(0)) { -- /* FAT16 root_dir */ -- info->Size = p_fs->dentries_in_root << -- DENTRY_SIZE_BITS; -- } else { -- info->Size = count_num_clusters(sb, &dir) << -- p_fs->cluster_size_bits; -- } -- -- count = count_dos_name_entries(sb, &dir, TYPE_DIR); -- if (count < 0) { -- ret = count; /* propagate error upward */ -- goto out; -- } -- info->NumSubdirs = count; -- -- if (p_fs->dev_ejected) -- ret = -EIO; -- goto out; -- } -- } -- -- /* get the directory entry of given file or directory */ -- es = get_entry_set_in_dir(sb, &fid->dir, fid->entry, -- ES_2_ENTRIES, &ep); -- if (!es) { -- ret = -ENOENT; -- goto out; -- } -- ep2 = ep + 1; -- -- /* set FILE_INFO structure using the acquired struct dentry_t */ -- info->Attr = exfat_get_entry_attr(ep); -- -- exfat_get_entry_time(ep, &tm, TM_CREATE); -- info->CreateTimestamp.Year = tm.year; -- info->CreateTimestamp.Month = tm.mon; -- info->CreateTimestamp.Day = tm.day; -- info->CreateTimestamp.Hour = tm.hour; -- info->CreateTimestamp.Minute = tm.min; -- info->CreateTimestamp.Second = tm.sec; -- info->CreateTimestamp.MilliSecond = 0; -- -- exfat_get_entry_time(ep, &tm, TM_MODIFY); -- info->ModifyTimestamp.Year = tm.year; -- info->ModifyTimestamp.Month = tm.mon; -- info->ModifyTimestamp.Day = tm.day; -- info->ModifyTimestamp.Hour = tm.hour; -- info->ModifyTimestamp.Minute = tm.min; -- info->ModifyTimestamp.Second = tm.sec; -- info->ModifyTimestamp.MilliSecond = 0; -- -- memset((char *)&info->AccessTimestamp, 0, sizeof(struct date_time_t)); -- -- *uni_name.name = 0x0; -- /* XXX this is very bad for exfat cuz name is already included in es. -- * API should be revised -- */ -- exfat_get_uni_name_from_ext_entry(sb, &fid->dir, fid->entry, -- uni_name.name); -- nls_uniname_to_cstring(sb, info->Name, &uni_name); -- -- info->NumSubdirs = 2; -- -- info->Size = exfat_get_entry_size(ep2); -- -- release_entry_set(es); -- -- if (is_dir) { -- dir.dir = fid->start_clu; -- dir.flags = 0x01; -- -- if (info->Size == 0) -- info->Size = (u64)count_num_clusters(sb, &dir) << -- p_fs->cluster_size_bits; -- -- count = count_dos_name_entries(sb, &dir, TYPE_DIR); -- if (count < 0) { -- ret = count; /* propagate error upward */ -- goto out; -- } -- info->NumSubdirs += count; -- } -- -- if (p_fs->dev_ejected) -- ret = -EIO; -- --out: -- /* release the lock for file system critical section */ -- mutex_unlock(&p_fs->v_mutex); -- -- pr_debug("%s exited successfully\n", __func__); -- return ret; --} -- --static int ffsWriteStat(struct inode *inode, struct dir_entry_t *info) --{ -- int ret = 0; -- struct timestamp_t tm; -- struct dentry_t *ep, *ep2; -- struct entry_set_cache_t *es = NULL; -- struct super_block *sb = inode->i_sb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct file_id_t *fid = &(EXFAT_I(inode)->fid); -- u8 is_dir = (fid->type == TYPE_DIR) ? 1 : 0; -- -- pr_debug("%s entered (inode %p info %p\n", __func__, inode, info); -- -- /* acquire the lock for file system critical section */ -- mutex_lock(&p_fs->v_mutex); -- -- if (is_dir) { -- if ((fid->dir.dir == p_fs->root_dir) && -- (fid->entry == -1)) { -- if (p_fs->dev_ejected) -- ret = -EIO; -- ret = 0; -- goto out; -- } -- } -- -- fs_set_vol_flags(sb, VOL_DIRTY); -- -- /* get the directory entry of given file or directory */ -- es = get_entry_set_in_dir(sb, &fid->dir, fid->entry, -- ES_ALL_ENTRIES, &ep); -- if (!es) { -- ret = -ENOENT; -- goto out; -- } -- ep2 = ep + 1; -- -- exfat_set_entry_attr(ep, info->Attr); -- -- /* set FILE_INFO structure using the acquired struct dentry_t */ -- tm.sec = info->CreateTimestamp.Second; -- tm.min = info->CreateTimestamp.Minute; -- tm.hour = info->CreateTimestamp.Hour; -- tm.day = info->CreateTimestamp.Day; -- tm.mon = info->CreateTimestamp.Month; -- tm.year = info->CreateTimestamp.Year; -- exfat_set_entry_time(ep, &tm, TM_CREATE); -- -- tm.sec = info->ModifyTimestamp.Second; -- tm.min = info->ModifyTimestamp.Minute; -- tm.hour = info->ModifyTimestamp.Hour; -- tm.day = info->ModifyTimestamp.Day; -- tm.mon = info->ModifyTimestamp.Month; -- tm.year = info->ModifyTimestamp.Year; -- exfat_set_entry_time(ep, &tm, TM_MODIFY); -- -- exfat_set_entry_size(ep2, info->Size); -- -- update_dir_checksum_with_entry_set(sb, es); -- release_entry_set(es); -- -- if (p_fs->dev_ejected) -- ret = -EIO; -- --out: -- /* release the lock for file system critical section */ -- mutex_unlock(&p_fs->v_mutex); -- -- pr_debug("%s exited (%d)\n", __func__, ret); -- -- return ret; --} -- --static int ffsMapCluster(struct inode *inode, s32 clu_offset, u32 *clu) --{ -- s32 num_clusters, num_alloced; -- bool modified = false; -- u32 last_clu; -- int ret = 0; -- struct chain_t new_clu; -- struct dentry_t *ep; -- struct entry_set_cache_t *es = NULL; -- struct super_block *sb = inode->i_sb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct file_id_t *fid = &(EXFAT_I(inode)->fid); -- -- /* check the validity of pointer parameters */ -- if (!clu) -- return -EINVAL; -- -- /* acquire the lock for file system critical section */ -- mutex_lock(&p_fs->v_mutex); -- -- fid->rwoffset = (s64)(clu_offset) << p_fs->cluster_size_bits; -- -- if (EXFAT_I(inode)->mmu_private == 0) -- num_clusters = 0; -- else -- num_clusters = (s32)((EXFAT_I(inode)->mmu_private - 1) >> -- p_fs->cluster_size_bits) + 1; -- -- *clu = last_clu = fid->start_clu; -- -- if (fid->flags == 0x03) { -- if ((clu_offset > 0) && (*clu != CLUSTER_32(~0))) { -- last_clu += clu_offset - 1; -- -- if (clu_offset == num_clusters) -- *clu = CLUSTER_32(~0); -- else -- *clu += clu_offset; -- } -- } else { -- /* hint information */ -- if ((clu_offset > 0) && (fid->hint_last_off > 0) && -- (clu_offset >= fid->hint_last_off)) { -- clu_offset -= fid->hint_last_off; -- *clu = fid->hint_last_clu; -- } -- -- while ((clu_offset > 0) && (*clu != CLUSTER_32(~0))) { -- last_clu = *clu; -- if (exfat_fat_read(sb, *clu, clu) == -1) { -- ret = -EIO; -- goto out; -- } -- clu_offset--; -- } -- } -- -- if (*clu == CLUSTER_32(~0)) { -- fs_set_vol_flags(sb, VOL_DIRTY); -- -- new_clu.dir = (last_clu == CLUSTER_32(~0)) ? CLUSTER_32(~0) : -- last_clu + 1; -- new_clu.size = 0; -- new_clu.flags = fid->flags; -- -- /* (1) allocate a cluster */ -- num_alloced = exfat_alloc_cluster(sb, 1, &new_clu); -- if (num_alloced < 0) { -- ret = -EIO; -- goto out; -- } else if (num_alloced == 0) { -- ret = -ENOSPC; -- goto out; -- } -- -- /* (2) append to the FAT chain */ -- if (last_clu == CLUSTER_32(~0)) { -- if (new_clu.flags == 0x01) -- fid->flags = 0x01; -- fid->start_clu = new_clu.dir; -- modified = true; -- } else { -- if (new_clu.flags != fid->flags) { -- exfat_chain_cont_cluster(sb, fid->start_clu, -- num_clusters); -- fid->flags = 0x01; -- modified = true; -- } -- if (new_clu.flags == 0x01) -- exfat_fat_write(sb, last_clu, new_clu.dir); -- } -- -- num_clusters += num_alloced; -- *clu = new_clu.dir; -- -- es = get_entry_set_in_dir(sb, &fid->dir, fid->entry, -- ES_ALL_ENTRIES, &ep); -- if (!es) { -- ret = -ENOENT; -- goto out; -- } -- /* get stream entry */ -- ep++; -- -- /* (3) update directory entry */ -- if (modified) { -- if (exfat_get_entry_flag(ep) != fid->flags) -- exfat_set_entry_flag(ep, fid->flags); -- -- if (exfat_get_entry_clu0(ep) != fid->start_clu) -- exfat_set_entry_clu0(ep, fid->start_clu); -- } -- -- update_dir_checksum_with_entry_set(sb, es); -- release_entry_set(es); -- -- /* add number of new blocks to inode */ -- inode->i_blocks += num_alloced << (p_fs->cluster_size_bits - 9); -- } -- -- /* hint information */ -- fid->hint_last_off = (s32)(fid->rwoffset >> p_fs->cluster_size_bits); -- fid->hint_last_clu = *clu; -- -- if (p_fs->dev_ejected) -- ret = -EIO; -- --out: -- /* release the lock for file system critical section */ -- mutex_unlock(&p_fs->v_mutex); -- -- return ret; --} -- --/*----------------------------------------------------------------------*/ --/* Directory Operation Functions */ --/*----------------------------------------------------------------------*/ -- --static int ffsCreateDir(struct inode *inode, char *path, struct file_id_t *fid) --{ -- int ret = 0; -- struct chain_t dir; -- struct uni_name_t uni_name; -- struct super_block *sb = inode->i_sb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- pr_debug("%s entered\n", __func__); -- -- /* check the validity of pointer parameters */ -- if (!fid || !path || (*path == '\0')) -- return -EINVAL; -- -- /* acquire the lock for file system critical section */ -- mutex_lock(&p_fs->v_mutex); -- -- /* check the validity of directory name in the given old pathname */ -- ret = resolve_path(inode, path, &dir, &uni_name); -- if (ret) -- goto out; -- -- fs_set_vol_flags(sb, VOL_DIRTY); -- -- ret = create_dir(inode, &dir, &uni_name, fid); -- --#ifndef CONFIG_STAGING_EXFAT_DELAYED_SYNC -- fs_sync(sb, true); -- fs_set_vol_flags(sb, VOL_CLEAN); --#endif -- -- if (p_fs->dev_ejected) -- ret = -EIO; --out: -- /* release the lock for file system critical section */ -- mutex_unlock(&p_fs->v_mutex); -- -- return ret; --} -- --static int ffsReadDir(struct inode *inode, struct dir_entry_t *dir_entry) --{ -- int i, dentry, clu_offset; -- int ret = 0; -- s32 dentries_per_clu, dentries_per_clu_bits = 0; -- u32 type; -- sector_t sector; -- struct chain_t dir, clu; -- struct uni_name_t uni_name; -- struct timestamp_t tm; -- struct dentry_t *ep; -- struct super_block *sb = inode->i_sb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct file_id_t *fid = &(EXFAT_I(inode)->fid); -- -- /* check the validity of pointer parameters */ -- if (!dir_entry) -- return -EINVAL; -- -- /* check if the given file ID is opened */ -- if (fid->type != TYPE_DIR) -- return -ENOTDIR; -- -- /* acquire the lock for file system critical section */ -- mutex_lock(&p_fs->v_mutex); -- -- if (fid->entry == -1) { -- dir.dir = p_fs->root_dir; -- dir.flags = 0x01; -- } else { -- dir.dir = fid->start_clu; -- dir.size = (s32)(fid->size >> p_fs->cluster_size_bits); -- dir.flags = fid->flags; -- } -- -- dentry = (s32)fid->rwoffset; -- -- if (dir.dir == CLUSTER_32(0)) { -- /* FAT16 root_dir */ -- dentries_per_clu = p_fs->dentries_in_root; -- -- if (dentry == dentries_per_clu) { -- clu.dir = CLUSTER_32(~0); -- } else { -- clu.dir = dir.dir; -- clu.size = dir.size; -- clu.flags = dir.flags; -- } -- } else { -- dentries_per_clu = p_fs->dentries_per_clu; -- dentries_per_clu_bits = ilog2(dentries_per_clu); -- -- clu_offset = dentry >> dentries_per_clu_bits; -- clu.dir = dir.dir; -- clu.size = dir.size; -- clu.flags = dir.flags; -- -- if (clu.flags == 0x03) { -- clu.dir += clu_offset; -- clu.size -= clu_offset; -- } else { -- /* hint_information */ -- if ((clu_offset > 0) && (fid->hint_last_off > 0) && -- (clu_offset >= fid->hint_last_off)) { -- clu_offset -= fid->hint_last_off; -- clu.dir = fid->hint_last_clu; -- } -- -- while (clu_offset > 0) { -- /* clu.dir = exfat_fat_read(sb, clu.dir); */ -- if (exfat_fat_read(sb, clu.dir, &clu.dir) == -1) { -- ret = -EIO; -- goto out; -- } -- clu_offset--; -- } -- } -- } -- -- while (clu.dir != CLUSTER_32(~0)) { -- if (p_fs->dev_ejected) -- break; -- -- if (dir.dir == CLUSTER_32(0)) /* FAT16 root_dir */ -- i = dentry % dentries_per_clu; -- else -- i = dentry & (dentries_per_clu - 1); -- -- for ( ; i < dentries_per_clu; i++, dentry++) { -- ep = get_entry_in_dir(sb, &clu, i, §or); -- if (!ep) { -- ret = -ENOENT; -- goto out; -- } -- type = exfat_get_entry_type(ep); -- -- if (type == TYPE_UNUSED) -- break; -- -- if ((type != TYPE_FILE) && (type != TYPE_DIR)) -- continue; -- -- exfat_buf_lock(sb, sector); -- dir_entry->Attr = exfat_get_entry_attr(ep); -- -- exfat_get_entry_time(ep, &tm, TM_CREATE); -- dir_entry->CreateTimestamp.Year = tm.year; -- dir_entry->CreateTimestamp.Month = tm.mon; -- dir_entry->CreateTimestamp.Day = tm.day; -- dir_entry->CreateTimestamp.Hour = tm.hour; -- dir_entry->CreateTimestamp.Minute = tm.min; -- dir_entry->CreateTimestamp.Second = tm.sec; -- dir_entry->CreateTimestamp.MilliSecond = 0; -- -- exfat_get_entry_time(ep, &tm, TM_MODIFY); -- dir_entry->ModifyTimestamp.Year = tm.year; -- dir_entry->ModifyTimestamp.Month = tm.mon; -- dir_entry->ModifyTimestamp.Day = tm.day; -- dir_entry->ModifyTimestamp.Hour = tm.hour; -- dir_entry->ModifyTimestamp.Minute = tm.min; -- dir_entry->ModifyTimestamp.Second = tm.sec; -- dir_entry->ModifyTimestamp.MilliSecond = 0; -- -- memset((char *)&dir_entry->AccessTimestamp, 0, -- sizeof(struct date_time_t)); -- -- *uni_name.name = 0x0; -- exfat_get_uni_name_from_ext_entry(sb, &dir, dentry, -- uni_name.name); -- nls_uniname_to_cstring(sb, dir_entry->Name, &uni_name); -- exfat_buf_unlock(sb, sector); -- -- ep = get_entry_in_dir(sb, &clu, i + 1, NULL); -- if (!ep) { -- ret = -ENOENT; -- goto out; -- } -- -- dir_entry->Size = exfat_get_entry_size(ep); -- -- /* hint information */ -- if (dir.dir == CLUSTER_32(0)) { /* FAT16 root_dir */ -- } else { -- fid->hint_last_off = dentry >> -- dentries_per_clu_bits; -- fid->hint_last_clu = clu.dir; -- } -- -- fid->rwoffset = (s64)(++dentry); -- -- if (p_fs->dev_ejected) -- ret = -EIO; -- goto out; -- } -- -- if (dir.dir == CLUSTER_32(0)) -- break; /* FAT16 root_dir */ -- -- if (clu.flags == 0x03) { -- if ((--clu.size) > 0) -- clu.dir++; -- else -- clu.dir = CLUSTER_32(~0); -- } else { -- /* clu.dir = exfat_fat_read(sb, clu.dir); */ -- if (exfat_fat_read(sb, clu.dir, &clu.dir) == -1) { -- ret = -EIO; -- goto out; -- } -- } -- } -- -- *dir_entry->Name = '\0'; -- -- fid->rwoffset = (s64)(++dentry); -- -- if (p_fs->dev_ejected) -- ret = -EIO; -- --out: -- /* release the lock for file system critical section */ -- mutex_unlock(&p_fs->v_mutex); -- -- return ret; --} -- --static int ffsRemoveDir(struct inode *inode, struct file_id_t *fid) --{ -- s32 dentry; -- int ret = 0; -- struct chain_t dir, clu_to_free; -- struct super_block *sb = inode->i_sb; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- /* check the validity of the given file id */ -- if (!fid) -- return -EINVAL; -- -- dir.dir = fid->dir.dir; -- dir.size = fid->dir.size; -- dir.flags = fid->dir.flags; -- -- dentry = fid->entry; -- -- /* check if the file is "." or ".." */ -- if (p_fs->vol_type != EXFAT) { -- if ((dir.dir != p_fs->root_dir) && (dentry < 2)) -- return -EPERM; -- } -- -- /* acquire the lock for file system critical section */ -- mutex_lock(&p_fs->v_mutex); -- -- clu_to_free.dir = fid->start_clu; -- clu_to_free.size = (s32)((fid->size - 1) >> p_fs->cluster_size_bits) + 1; -- clu_to_free.flags = fid->flags; -- -- if (!is_dir_empty(sb, &clu_to_free)) { -- ret = -ENOTEMPTY; -- goto out; -- } -- -- fs_set_vol_flags(sb, VOL_DIRTY); -- -- /* (1) update the directory entry */ -- remove_file(inode, &dir, dentry); -- -- /* (2) free the clusters */ -- exfat_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; -- --#ifndef CONFIG_STAGING_EXFAT_DELAYED_SYNC -- fs_sync(sb, true); -- fs_set_vol_flags(sb, VOL_CLEAN); --#endif -- -- if (p_fs->dev_ejected) -- ret = -EIO; -- --out: -- /* release the lock for file system critical section */ -- mutex_unlock(&p_fs->v_mutex); -- -- return ret; --} -- --/*======================================================================*/ --/* Directory Entry Operations */ --/*======================================================================*/ -- --static int exfat_readdir(struct file *filp, struct dir_context *ctx) --{ -- struct inode *inode = file_inode(filp); -- struct super_block *sb = inode->i_sb; -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- struct fs_info_t *p_fs = &sbi->fs_info; -- struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -- struct dir_entry_t de; -- unsigned long inum; -- loff_t cpos; -- int err = 0; -- -- __lock_super(sb); -- -- cpos = ctx->pos; -- /* Fake . and .. for the root directory. */ -- if ((p_fs->vol_type == EXFAT) || (inode->i_ino == EXFAT_ROOT_INO)) { -- while (cpos < 2) { -- if (inode->i_ino == EXFAT_ROOT_INO) -- inum = EXFAT_ROOT_INO; -- else if (cpos == 0) -- inum = inode->i_ino; -- else /* (cpos == 1) */ -- inum = parent_ino(filp->f_path.dentry); -- -- if (!dir_emit_dots(filp, ctx)) -- goto out; -- cpos++; -- ctx->pos++; -- } -- if (cpos == 2) -- cpos = 0; -- } -- if (cpos & (DENTRY_SIZE - 1)) { -- err = -ENOENT; -- goto out; -- } -- --get_new: -- EXFAT_I(inode)->fid.size = i_size_read(inode); -- EXFAT_I(inode)->fid.rwoffset = cpos >> DENTRY_SIZE_BITS; -- -- err = ffsReadDir(inode, &de); -- if (err) { -- /* at least we tried to read a sector -- * move cpos to next sector position (should be aligned) -- */ -- if (err == -EIO) { -- cpos += 1 << p_bd->sector_size_bits; -- cpos &= ~((1 << p_bd->sector_size_bits) - 1); -- } -- -- goto end_of_dir; -- } -- -- cpos = EXFAT_I(inode)->fid.rwoffset << DENTRY_SIZE_BITS; -- -- if (!de.Name[0]) -- goto end_of_dir; -- -- if (!memcmp(de.ShortName, DOS_CUR_DIR_NAME, DOS_NAME_LENGTH)) { -- inum = inode->i_ino; -- } else if (!memcmp(de.ShortName, DOS_PAR_DIR_NAME, DOS_NAME_LENGTH)) { -- inum = parent_ino(filp->f_path.dentry); -- } else { -- loff_t i_pos = ((loff_t)EXFAT_I(inode)->fid.start_clu << 32) | -- ((EXFAT_I(inode)->fid.rwoffset - 1) & 0xffffffff); -- struct inode *tmp = exfat_iget(sb, i_pos); -- -- if (tmp) { -- inum = tmp->i_ino; -- iput(tmp); -- } else { -- inum = iunique(sb, EXFAT_ROOT_INO); -- } -- } -- -- if (!dir_emit(ctx, de.Name, strlen(de.Name), inum, -- (de.Attr & ATTR_SUBDIR) ? DT_DIR : DT_REG)) -- goto out; -- -- ctx->pos = cpos; -- goto get_new; -- --end_of_dir: -- ctx->pos = cpos; --out: -- __unlock_super(sb); -- return err; --} -- --static int exfat_ioctl_volume_id(struct inode *dir) --{ -- struct super_block *sb = dir->i_sb; -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- struct fs_info_t *p_fs = &sbi->fs_info; -- -- return p_fs->vol_id; --} -- --static long exfat_generic_ioctl(struct file *filp, unsigned int cmd, -- unsigned long arg) --{ -- struct inode *inode = filp->f_path.dentry->d_inode; --#ifdef CONFIG_STAGING_EXFAT_KERNEL_DEBUG -- unsigned int flags; --#endif /* CONFIG_STAGING_EXFAT_KERNEL_DEBUG */ -- -- switch (cmd) { -- case EXFAT_IOCTL_GET_VOLUME_ID: -- return exfat_ioctl_volume_id(inode); --#ifdef CONFIG_STAGING_EXFAT_KERNEL_DEBUG -- case EXFAT_IOC_GET_DEBUGFLAGS: { -- struct super_block *sb = inode->i_sb; -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- -- flags = sbi->debug_flags; -- return put_user(flags, (int __user *)arg); -- } -- case EXFAT_IOC_SET_DEBUGFLAGS: { -- struct super_block *sb = inode->i_sb; -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- -- if (!capable(CAP_SYS_ADMIN)) -- return -EPERM; -- -- if (get_user(flags, (int __user *)arg)) -- return -EFAULT; -- -- __lock_super(sb); -- sbi->debug_flags = flags; -- __unlock_super(sb); -- -- return 0; -- } --#endif /* CONFIG_STAGING_EXFAT_KERNEL_DEBUG */ -- default: -- return -ENOTTY; /* Inappropriate ioctl for device */ -- } --} -- --static const struct file_operations exfat_dir_operations = { -- .llseek = generic_file_llseek, -- .read = generic_read_dir, -- .iterate = exfat_readdir, -- .unlocked_ioctl = exfat_generic_ioctl, -- .fsync = generic_file_fsync, --}; -- --static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, -- bool excl) --{ -- struct super_block *sb = dir->i_sb; -- struct timespec64 curtime; -- struct inode *inode; -- struct file_id_t fid; -- loff_t i_pos; -- int err; -- -- __lock_super(sb); -- -- pr_debug("%s entered\n", __func__); -- -- err = ffsCreateFile(dir, (u8 *)dentry->d_name.name, FM_REGULAR, &fid); -- if (err) -- goto out; -- -- INC_IVERSION(dir); -- curtime = current_time(dir); -- dir->i_ctime = curtime; -- dir->i_mtime = curtime; -- dir->i_atime = curtime; -- if (IS_DIRSYNC(dir)) -- (void)exfat_sync_inode(dir); -- else -- mark_inode_dirty(dir); -- -- 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); -- goto out; -- } -- INC_IVERSION(inode); -- curtime = current_time(inode); -- inode->i_mtime = curtime; -- inode->i_atime = curtime; -- inode->i_ctime = curtime; -- /* -- * timestamp is already written, so mark_inode_dirty() is unnecessary. -- */ -- -- dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode); -- d_instantiate(dentry, inode); -- --out: -- __unlock_super(sb); -- pr_debug("%s exited\n", __func__); -- return err; --} -- --static int exfat_find(struct inode *dir, struct qstr *qname, -- struct file_id_t *fid) --{ -- int err; -- -- if (qname->len == 0) -- return -ENOENT; -- -- err = ffsLookupFile(dir, (u8 *)qname->name, fid); -- if (err) -- return -ENOENT; -- -- return 0; --} -- --static int exfat_d_anon_disconn(struct dentry *dentry) --{ -- return IS_ROOT(dentry) && (dentry->d_flags & DCACHE_DISCONNECTED); --} -- --static struct dentry *exfat_lookup(struct inode *dir, struct dentry *dentry, -- unsigned int flags) --{ -- struct super_block *sb = dir->i_sb; -- struct inode *inode; -- struct dentry *alias; -- int err; -- struct file_id_t fid; -- loff_t i_pos; -- u64 ret; -- mode_t i_mode; -- -- __lock_super(sb); -- pr_debug("%s entered\n", __func__); -- err = exfat_find(dir, &dentry->d_name, &fid); -- if (err) { -- if (err == -ENOENT) { -- inode = NULL; -- goto out; -- } -- goto error; -- } -- -- 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); -- goto error; -- } -- -- i_mode = inode->i_mode; -- if (S_ISLNK(i_mode) && !EXFAT_I(inode)->target) { -- EXFAT_I(inode)->target = kmalloc(i_size_read(inode) + 1, -- GFP_KERNEL); -- if (!EXFAT_I(inode)->target) { -- err = -ENOMEM; -- goto error; -- } -- ffsReadFile(dir, &fid, EXFAT_I(inode)->target, -- i_size_read(inode), &ret); -- *(EXFAT_I(inode)->target + i_size_read(inode)) = '\0'; -- } -- -- alias = d_find_alias(inode); -- if (alias && !exfat_d_anon_disconn(alias)) { -- BUG_ON(d_unhashed(alias)); -- if (!S_ISDIR(i_mode)) -- d_move(alias, dentry); -- iput(inode); -- __unlock_super(sb); -- pr_debug("%s exited 1\n", __func__); -- return alias; -- } -- dput(alias); --out: -- __unlock_super(sb); -- dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode); -- dentry = d_splice_alias(inode, dentry); -- if (dentry) -- dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode); -- pr_debug("%s exited 2\n", __func__); -- return dentry; -- --error: -- __unlock_super(sb); -- pr_debug("%s exited 3\n", __func__); -- return ERR_PTR(err); --} -- --static inline unsigned long exfat_hash(loff_t i_pos) --{ -- return hash_32(i_pos, EXFAT_HASH_BITS); --} -- --static void exfat_attach(struct inode *inode, loff_t 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_hash_fat, head); -- spin_unlock(&sbi->inode_hash_lock); --} -- --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; -- spin_unlock(&sbi->inode_hash_lock); --} -- --static int exfat_unlink(struct inode *dir, struct dentry *dentry) --{ -- struct inode *inode = dentry->d_inode; -- struct super_block *sb = dir->i_sb; -- struct timespec64 curtime; -- int err; -- -- __lock_super(sb); -- -- pr_debug("%s entered\n", __func__); -- -- EXFAT_I(inode)->fid.size = i_size_read(inode); -- -- err = ffsRemoveFile(dir, &(EXFAT_I(inode)->fid)); -- if (err) -- goto out; -- -- INC_IVERSION(dir); -- curtime = current_time(dir); -- dir->i_mtime = curtime; -- dir->i_atime = curtime; -- if (IS_DIRSYNC(dir)) -- (void)exfat_sync_inode(dir); -- else -- mark_inode_dirty(dir); -- -- clear_nlink(inode); -- curtime = current_time(inode); -- inode->i_mtime = curtime; -- inode->i_atime = curtime; -- exfat_detach(inode); -- remove_inode_hash(inode); -- --out: -- __unlock_super(sb); -- pr_debug("%s exited\n", __func__); -- return err; --} -- --static int exfat_symlink(struct inode *dir, struct dentry *dentry, -- const char *target) --{ -- struct super_block *sb = dir->i_sb; -- struct timespec64 curtime; -- struct inode *inode; -- struct file_id_t fid; -- loff_t i_pos; -- int err; -- u64 len = (u64)strlen(target); -- u64 ret; -- -- __lock_super(sb); -- -- pr_debug("%s entered\n", __func__); -- -- err = ffsCreateFile(dir, (u8 *)dentry->d_name.name, FM_SYMLINK, &fid); -- if (err) -- goto out; -- -- -- err = ffsWriteFile(dir, &fid, (char *)target, len, &ret); -- -- if (err) { -- ffsRemoveFile(dir, &fid); -- goto out; -- } -- -- INC_IVERSION(dir); -- curtime = current_time(dir); -- dir->i_ctime = curtime; -- dir->i_mtime = curtime; -- dir->i_atime = curtime; -- if (IS_DIRSYNC(dir)) -- (void)exfat_sync_inode(dir); -- else -- mark_inode_dirty(dir); -- -- 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); -- goto out; -- } -- INC_IVERSION(inode); -- curtime = current_time(inode); -- inode->i_mtime = curtime; -- inode->i_atime = curtime; -- inode->i_ctime = curtime; -- /* timestamp is already written, so mark_inode_dirty() is unneeded. */ -- -- EXFAT_I(inode)->target = kmemdup(target, len + 1, GFP_KERNEL); -- if (!EXFAT_I(inode)->target) { -- err = -ENOMEM; -- goto out; -- } -- -- dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode); -- d_instantiate(dentry, inode); -- --out: -- __unlock_super(sb); -- pr_debug("%s exited\n", __func__); -- return err; --} -- --static int exfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) --{ -- struct super_block *sb = dir->i_sb; -- struct timespec64 curtime; -- struct inode *inode; -- struct file_id_t fid; -- loff_t i_pos; -- int err; -- -- __lock_super(sb); -- -- pr_debug("%s entered\n", __func__); -- -- err = ffsCreateDir(dir, (u8 *)dentry->d_name.name, &fid); -- if (err) -- goto out; -- -- INC_IVERSION(dir); -- curtime = current_time(dir); -- dir->i_ctime = curtime; -- dir->i_mtime = curtime; -- dir->i_atime = curtime; -- if (IS_DIRSYNC(dir)) -- (void)exfat_sync_inode(dir); -- else -- mark_inode_dirty(dir); -- inc_nlink(dir); -- -- 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); -- goto out; -- } -- INC_IVERSION(inode); -- curtime = current_time(inode); -- inode->i_mtime = curtime; -- inode->i_atime = curtime; -- inode->i_ctime = curtime; -- /* timestamp is already written, so mark_inode_dirty() is unneeded. */ -- -- dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode); -- d_instantiate(dentry, inode); -- --out: -- __unlock_super(sb); -- pr_debug("%s exited\n", __func__); -- return err; --} -- --static int exfat_rmdir(struct inode *dir, struct dentry *dentry) --{ -- struct inode *inode = dentry->d_inode; -- struct super_block *sb = dir->i_sb; -- struct timespec64 curtime; -- int err; -- -- __lock_super(sb); -- -- pr_debug("%s entered\n", __func__); -- -- EXFAT_I(inode)->fid.size = i_size_read(inode); -- -- err = ffsRemoveDir(dir, &(EXFAT_I(inode)->fid)); -- if (err) -- goto out; -- -- INC_IVERSION(dir); -- curtime = current_time(dir); -- dir->i_mtime = curtime; -- dir->i_atime = curtime; -- if (IS_DIRSYNC(dir)) -- (void)exfat_sync_inode(dir); -- else -- mark_inode_dirty(dir); -- drop_nlink(dir); -- -- clear_nlink(inode); -- curtime = current_time(inode); -- inode->i_mtime = curtime; -- inode->i_atime = curtime; -- exfat_detach(inode); -- remove_inode_hash(inode); -- --out: -- __unlock_super(sb); -- pr_debug("%s exited\n", __func__); -- return err; --} -- --static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry, -- struct inode *new_dir, struct dentry *new_dentry, -- unsigned int flags) --{ -- struct inode *old_inode, *new_inode; -- struct super_block *sb = old_dir->i_sb; -- struct timespec64 curtime; -- loff_t i_pos; -- int err; -- -- if (flags) -- return -EINVAL; -- -- __lock_super(sb); -- -- pr_debug("%s entered\n", __func__); -- -- old_inode = old_dentry->d_inode; -- new_inode = new_dentry->d_inode; -- -- EXFAT_I(old_inode)->fid.size = i_size_read(old_inode); -- -- err = ffsMoveFile(old_dir, &(EXFAT_I(old_inode)->fid), new_dir, -- new_dentry); -- if (err) -- goto out; -- -- INC_IVERSION(new_dir); -- curtime = current_time(new_dir); -- new_dir->i_ctime = curtime; -- new_dir->i_mtime = curtime; -- new_dir->i_atime = curtime; -- -- if (IS_DIRSYNC(new_dir)) -- (void)exfat_sync_inode(new_dir); -- else -- mark_inode_dirty(new_dir); -- -- i_pos = ((loff_t)EXFAT_I(old_inode)->fid.dir.dir << 32) | -- (EXFAT_I(old_inode)->fid.entry & 0xffffffff); -- -- exfat_detach(old_inode); -- exfat_attach(old_inode, i_pos); -- if (IS_DIRSYNC(new_dir)) -- (void)exfat_sync_inode(old_inode); -- else -- mark_inode_dirty(old_inode); -- -- if ((S_ISDIR(old_inode->i_mode)) && (old_dir != new_dir)) { -- drop_nlink(old_dir); -- if (!new_inode) -- inc_nlink(new_dir); -- } -- INC_IVERSION(old_dir); -- curtime = current_time(old_dir); -- old_dir->i_ctime = curtime; -- old_dir->i_mtime = curtime; -- if (IS_DIRSYNC(old_dir)) -- (void)exfat_sync_inode(old_dir); -- else -- mark_inode_dirty(old_dir); -- -- if (new_inode) { -- exfat_detach(new_inode); -- drop_nlink(new_inode); -- if (S_ISDIR(new_inode->i_mode)) -- drop_nlink(new_inode); -- new_inode->i_ctime = current_time(new_inode); -- } -- --out: -- __unlock_super(sb); -- pr_debug("%s exited\n", __func__); -- return err; --} -- --static int exfat_cont_expand(struct inode *inode, loff_t size) --{ -- struct address_space *mapping = inode->i_mapping; -- loff_t start = i_size_read(inode), count = size - i_size_read(inode); -- struct timespec64 curtime; -- int err, err2; -- -- err = generic_cont_expand_simple(inode, size); -- if (err != 0) -- return err; -- -- curtime = current_time(inode); -- inode->i_ctime = curtime; -- inode->i_mtime = curtime; -- mark_inode_dirty(inode); -- -- if (IS_SYNC(inode)) { -- err = filemap_fdatawrite_range(mapping, start, -- start + count - 1); -- err2 = sync_mapping_buffers(mapping); -- err = (err) ? (err) : (err2); -- err2 = write_inode_now(inode, 1); -- err = (err) ? (err) : (err2); -- if (!err) -- err = filemap_fdatawait_range(mapping, start, -- start + count - 1); -- } -- return err; --} -- --static int exfat_allow_set_time(struct exfat_sb_info *sbi, struct inode *inode) --{ -- mode_t allow_utime = sbi->options.allow_utime; -- -- if (!uid_eq(current_fsuid(), inode->i_uid)) { -- if (in_group_p(inode->i_gid)) -- allow_utime >>= 3; -- if (allow_utime & MAY_WRITE) -- return 1; -- } -- -- /* use a default check */ -- return 0; --} -- --static int exfat_sanitize_mode(const struct exfat_sb_info *sbi, -- struct inode *inode, umode_t *mode_ptr) --{ -- mode_t i_mode, mask, perm; -- -- i_mode = inode->i_mode; -- -- if (S_ISREG(i_mode) || S_ISLNK(i_mode)) -- mask = sbi->options.fs_fmask; -- else -- mask = sbi->options.fs_dmask; -- -- perm = *mode_ptr & ~(S_IFMT | mask); -- -- /* Of the r and x bits, all (subject to umask) must be present.*/ -- if ((perm & 0555) != (i_mode & 0555)) -- return -EPERM; -- -- if (exfat_mode_can_hold_ro(inode)) { -- /* -- * Of the w bits, either all (subject to umask) or none must be -- * present. -- */ -- if ((perm & 0222) && ((perm & 0222) != (0222 & ~mask))) -- return -EPERM; -- } else { -- /* -- * If exfat_mode_can_hold_ro(inode) is false, can't change w -- * bits. -- */ -- if ((perm & 0222) != (0222 & ~mask)) -- return -EPERM; -- } -- -- *mode_ptr &= S_IFMT | perm; -- -- return 0; --} -- --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); -- struct fs_info_t *p_fs = &sbi->fs_info; -- struct timespec64 curtime; -- int err; -- -- __lock_super(sb); -- -- /* -- * This protects against truncating a file bigger than it was then -- * trying to write into the hole. -- */ -- if (EXFAT_I(inode)->mmu_private > i_size_read(inode)) -- EXFAT_I(inode)->mmu_private = i_size_read(inode); -- -- if (EXFAT_I(inode)->fid.start_clu == 0) -- goto out; -- -- err = ffsTruncateFile(inode, old_size, i_size_read(inode)); -- if (err) -- goto out; -- -- curtime = current_time(inode); -- inode->i_ctime = curtime; -- inode->i_mtime = curtime; -- if (IS_DIRSYNC(inode)) -- (void)exfat_sync_inode(inode); -- else -- mark_inode_dirty(inode); -- -- inode->i_blocks = ((i_size_read(inode) + (p_fs->cluster_size - 1)) & -- ~((loff_t)p_fs->cluster_size - 1)) >> 9; --out: -- __unlock_super(sb); --} -- --static int exfat_setattr(struct dentry *dentry, struct iattr *attr) --{ -- struct exfat_sb_info *sbi = EXFAT_SB(dentry->d_sb); -- struct inode *inode = dentry->d_inode; -- unsigned int ia_valid; -- int error; -- loff_t old_size; -- -- pr_debug("%s entered\n", __func__); -- -- if ((attr->ia_valid & ATTR_SIZE) && -- attr->ia_size > i_size_read(inode)) { -- error = exfat_cont_expand(inode, attr->ia_size); -- if (error || attr->ia_valid == ATTR_SIZE) -- return error; -- attr->ia_valid &= ~ATTR_SIZE; -- } -- -- ia_valid = attr->ia_valid; -- -- if ((ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)) && -- exfat_allow_set_time(sbi, inode)) { -- attr->ia_valid &= ~(ATTR_MTIME_SET | -- ATTR_ATIME_SET | -- ATTR_TIMES_SET); -- } -- -- error = setattr_prepare(dentry, attr); -- attr->ia_valid = ia_valid; -- if (error) -- return error; -- -- if (((attr->ia_valid & ATTR_UID) && -- (!uid_eq(attr->ia_uid, sbi->options.fs_uid))) || -- ((attr->ia_valid & ATTR_GID) && -- (!gid_eq(attr->ia_gid, sbi->options.fs_gid))) || -- ((attr->ia_valid & ATTR_MODE) && -- (attr->ia_mode & ~(S_IFREG | S_IFLNK | S_IFDIR | 0777)))) { -- return -EPERM; -- } -- -- /* -- * We don't return -EPERM here. Yes, strange, but this is too -- * old behavior. -- */ -- if (attr->ia_valid & ATTR_MODE) { -- if (exfat_sanitize_mode(sbi, inode, &attr->ia_mode) < 0) -- attr->ia_valid &= ~ATTR_MODE; -- } -- -- EXFAT_I(inode)->fid.size = i_size_read(inode); -- -- if (attr->ia_valid & ATTR_SIZE) { -- old_size = i_size_read(inode); -- down_write(&EXFAT_I(inode)->truncate_lock); -- truncate_setsize(inode, attr->ia_size); -- exfat_truncate(inode, old_size); -- up_write(&EXFAT_I(inode)->truncate_lock); -- } -- setattr_copy(inode, attr); -- mark_inode_dirty(inode); -- -- pr_debug("%s exited\n", __func__); -- return error; --} -- --static int exfat_getattr(const struct path *path, struct kstat *stat, -- u32 request_mask, unsigned int flags) --{ -- struct inode *inode = path->dentry->d_inode; -- -- pr_debug("%s entered\n", __func__); -- -- generic_fillattr(inode, stat); -- stat->blksize = EXFAT_SB(inode->i_sb)->fs_info.cluster_size; -- -- pr_debug("%s exited\n", __func__); -- return 0; --} -- --static const struct inode_operations exfat_dir_inode_operations = { -- .create = exfat_create, -- .lookup = exfat_lookup, -- .unlink = exfat_unlink, -- .symlink = exfat_symlink, -- .mkdir = exfat_mkdir, -- .rmdir = exfat_rmdir, -- .rename = exfat_rename, -- .setattr = exfat_setattr, -- .getattr = exfat_getattr, --}; -- --/*======================================================================*/ --/* File Operations */ --/*======================================================================*/ --static const char *exfat_get_link(struct dentry *dentry, struct inode *inode, -- struct delayed_call *done) --{ -- struct exfat_inode_info *ei = EXFAT_I(inode); -- -- if (ei->target) { -- char *cookie = ei->target; -- -- if (cookie) -- return (char *)(ei->target); -- } -- return NULL; --} -- --static const struct inode_operations exfat_symlink_inode_operations = { -- .get_link = exfat_get_link, --}; -- --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); -- ffsSyncVol(sb, false); -- return 0; --} -- --static const struct file_operations exfat_file_operations = { -- .llseek = generic_file_llseek, -- .read_iter = generic_file_read_iter, -- .write_iter = generic_file_write_iter, -- .mmap = generic_file_mmap, -- .release = exfat_file_release, -- .unlocked_ioctl = exfat_generic_ioctl, -- .fsync = generic_file_fsync, -- .splice_read = generic_file_splice_read, --}; -- --static const struct inode_operations exfat_file_inode_operations = { -- .setattr = exfat_setattr, -- .getattr = exfat_getattr, --}; -- --/*======================================================================*/ --/* Address Space Operations */ --/*======================================================================*/ -- --static int exfat_bmap(struct inode *inode, sector_t sector, sector_t *phys, -- unsigned long *mapped_blocks, int *create) --{ -- struct super_block *sb = inode->i_sb; -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- struct fs_info_t *p_fs = &sbi->fs_info; -- const unsigned long blocksize = sb->s_blocksize; -- const unsigned char blocksize_bits = sb->s_blocksize_bits; -- sector_t last_block; -- int err, clu_offset, sec_offset; -- unsigned int cluster; -- -- *phys = 0; -- *mapped_blocks = 0; -- -- last_block = (i_size_read(inode) + (blocksize - 1)) >> blocksize_bits; -- if (sector >= last_block) { -- if (*create == 0) -- return 0; -- } else { -- *create = 0; -- } -- -- /* cluster offset */ -- clu_offset = sector >> p_fs->sectors_per_clu_bits; -- -- /* sector offset in cluster */ -- sec_offset = sector & (p_fs->sectors_per_clu - 1); -- -- EXFAT_I(inode)->fid.size = i_size_read(inode); -- -- err = ffsMapCluster(inode, clu_offset, &cluster); -- -- if (!err && (cluster != CLUSTER_32(~0))) { -- *phys = START_SECTOR(cluster) + sec_offset; -- *mapped_blocks = p_fs->sectors_per_clu - sec_offset; -- } -- -- return 0; --} -- --static int exfat_get_block(struct inode *inode, sector_t iblock, -- struct buffer_head *bh_result, int create) --{ -- struct super_block *sb = inode->i_sb; -- unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits; -- int err; -- unsigned long mapped_blocks; -- sector_t phys; -- -- __lock_super(sb); -- -- err = exfat_bmap(inode, iblock, &phys, &mapped_blocks, &create); -- if (err) { -- __unlock_super(sb); -- return err; -- } -- -- if (phys) { -- max_blocks = min(mapped_blocks, max_blocks); -- if (create) { -- EXFAT_I(inode)->mmu_private += max_blocks << -- sb->s_blocksize_bits; -- set_buffer_new(bh_result); -- } -- map_bh(bh_result, sb, phys); -- } -- -- bh_result->b_size = max_blocks << sb->s_blocksize_bits; -- __unlock_super(sb); -- -- return 0; --} -- --static int exfat_readpage(struct file *file, struct page *page) --{ -- return mpage_readpage(page, exfat_get_block); --} -- --static int exfat_readpages(struct file *file, struct address_space *mapping, -- struct list_head *pages, unsigned int nr_pages) --{ -- return mpage_readpages(mapping, pages, nr_pages, exfat_get_block); --} -- --static int exfat_writepage(struct page *page, struct writeback_control *wbc) --{ -- return block_write_full_page(page, exfat_get_block, wbc); --} -- --static int exfat_writepages(struct address_space *mapping, -- struct writeback_control *wbc) --{ -- return mpage_writepages(mapping, wbc, exfat_get_block); --} -- --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, i_size_read(inode)); -- EXFAT_I(inode)->fid.size = i_size_read(inode); -- exfat_truncate(inode, i_size_read(inode)); -- } --} -- --static int exfat_write_begin(struct file *file, struct address_space *mapping, -- loff_t pos, unsigned int len, unsigned int 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); -- -- if (ret < 0) -- exfat_write_failed(mapping, pos + len); -- return ret; --} -- --static int exfat_write_end(struct file *file, struct address_space *mapping, -- loff_t pos, unsigned int len, unsigned int copied, -- struct page *pagep, void *fsdata) --{ -- struct inode *inode = mapping->host; -- struct file_id_t *fid = &(EXFAT_I(inode)->fid); -- struct timespec64 curtime; -- int err; -- -- err = generic_write_end(file, mapping, pos, len, copied, pagep, fsdata); -- -- if (err < len) -- exfat_write_failed(mapping, pos + len); -- -- if (!(err < 0) && !(fid->attr & ATTR_ARCHIVE)) { -- curtime = current_time(inode); -- inode->i_mtime = curtime; -- inode->i_ctime = curtime; -- fid->attr |= ATTR_ARCHIVE; -- mark_inode_dirty(inode); -- } -- return err; --} -- --static ssize_t exfat_direct_IO(struct kiocb *iocb, struct iov_iter *iter) --{ -- struct inode *inode = iocb->ki_filp->f_mapping->host; -- struct address_space *mapping = iocb->ki_filp->f_mapping; -- ssize_t ret; -- int rw; -- -- rw = iov_iter_rw(iter); -- -- if (rw == WRITE) { -- if (EXFAT_I(inode)->mmu_private < iov_iter_count(iter)) -- return 0; -- } -- ret = blockdev_direct_IO(iocb, inode, iter, exfat_get_block); -- -- if ((ret < 0) && (rw & WRITE)) -- exfat_write_failed(mapping, iov_iter_count(iter)); -- return ret; --} -- --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. */ -- 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); -- -- return blocknr; --} -- --static const struct address_space_operations exfat_aops = { -- .readpage = exfat_readpage, -- .readpages = exfat_readpages, -- .writepage = exfat_writepage, -- .writepages = exfat_writepages, -- .write_begin = exfat_write_begin, -- .write_end = exfat_write_end, -- .direct_IO = exfat_direct_IO, -- .bmap = _exfat_bmap --}; -- --/*======================================================================*/ --/* Super Operations */ --/*======================================================================*/ -- --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 inode *inode = NULL; -- -- spin_lock(&sbi->inode_hash_lock); -- hlist_for_each_entry(info, head, i_hash_fat) { -- BUG_ON(info->vfs_inode.i_sb != sb); -- -- if (i_pos != info->i_pos) -- continue; -- inode = igrab(&info->vfs_inode); -- if (inode) -- break; -- } -- spin_unlock(&sbi->inode_hash_lock); -- return inode; --} -- --/* doesn't deal with root inode */ --static int exfat_fill_inode(struct inode *inode, struct file_id_t *fid) --{ -- struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); -- struct fs_info_t *p_fs = &sbi->fs_info; -- struct dir_entry_t info; -- -- memcpy(&(EXFAT_I(inode)->fid), fid, sizeof(struct file_id_t)); -- -- ffsReadStat(inode, &info); -- -- EXFAT_I(inode)->i_pos = 0; -- EXFAT_I(inode)->target = NULL; -- inode->i_uid = sbi->options.fs_uid; -- inode->i_gid = sbi->options.fs_gid; -- INC_IVERSION(inode); -- inode->i_generation = prandom_u32(); -- -- if (info.Attr & ATTR_SUBDIR) { /* directory */ -- inode->i_generation &= ~1; -- inode->i_mode = exfat_make_mode(sbi, info.Attr, 0777); -- inode->i_op = &exfat_dir_inode_operations; -- inode->i_fop = &exfat_dir_operations; -- -- i_size_write(inode, info.Size); -- EXFAT_I(inode)->mmu_private = i_size_read(inode); -- set_nlink(inode, info.NumSubdirs); -- } else if (info.Attr & ATTR_SYMLINK) { /* symbolic link */ -- inode->i_generation |= 1; -- inode->i_mode = exfat_make_mode(sbi, info.Attr, 0777); -- inode->i_op = &exfat_symlink_inode_operations; -- -- i_size_write(inode, info.Size); -- EXFAT_I(inode)->mmu_private = i_size_read(inode); -- } else { /* regular file */ -- inode->i_generation |= 1; -- inode->i_mode = exfat_make_mode(sbi, info.Attr, 0777); -- inode->i_op = &exfat_file_inode_operations; -- inode->i_fop = &exfat_file_operations; -- inode->i_mapping->a_ops = &exfat_aops; -- inode->i_mapping->nrpages = 0; -- -- i_size_write(inode, info.Size); -- EXFAT_I(inode)->mmu_private = i_size_read(inode); -- } -- exfat_save_attr(inode, info.Attr); -- -- inode->i_blocks = ((i_size_read(inode) + (p_fs->cluster_size - 1)) -- & ~((loff_t)p_fs->cluster_size - 1)) >> 9; -- -- exfat_time_fat2unix(&inode->i_mtime, &info.ModifyTimestamp); -- exfat_time_fat2unix(&inode->i_ctime, &info.CreateTimestamp); -- exfat_time_fat2unix(&inode->i_atime, &info.AccessTimestamp); -- -- return 0; --} -- --static struct inode *exfat_build_inode(struct super_block *sb, -- struct file_id_t *fid, loff_t i_pos) --{ -- struct inode *inode; -- int err; -- -- inode = exfat_iget(sb, i_pos); -- if (inode) -- goto out; -- inode = new_inode(sb); -- if (!inode) { -- inode = ERR_PTR(-ENOMEM); -- goto out; -- } -- inode->i_ino = iunique(sb, EXFAT_ROOT_INO); -- SET_IVERSION(inode, 1); -- err = exfat_fill_inode(inode, fid); -- if (err) { -- iput(inode); -- inode = ERR_PTR(err); -- goto out; -- } -- exfat_attach(inode, i_pos); -- insert_inode_hash(inode); --out: -- return inode; --} -- --static int exfat_sync_inode(struct inode *inode) --{ -- return exfat_write_inode(inode, NULL); --} -- --static struct inode *exfat_alloc_inode(struct super_block *sb) --{ -- struct exfat_inode_info *ei; -- -- ei = kmem_cache_alloc(exfat_inode_cachep, GFP_NOFS); -- if (!ei) -- return NULL; -- -- init_rwsem(&ei->truncate_lock); -- -- return &ei->vfs_inode; --} -- --static void exfat_destroy_inode(struct inode *inode) --{ -- kfree(EXFAT_I(inode)->target); -- EXFAT_I(inode)->target = NULL; -- -- kmem_cache_free(exfat_inode_cachep, EXFAT_I(inode)); --} -- --static int exfat_write_inode(struct inode *inode, struct writeback_control *wbc) --{ -- struct dir_entry_t info; -- -- if (inode->i_ino == EXFAT_ROOT_INO) -- return 0; -- -- info.Attr = exfat_make_attr(inode); -- info.Size = i_size_read(inode); -- -- exfat_time_unix2fat(&inode->i_mtime, &info.ModifyTimestamp); -- exfat_time_unix2fat(&inode->i_ctime, &info.CreateTimestamp); -- exfat_time_unix2fat(&inode->i_atime, &info.AccessTimestamp); -- -- ffsWriteStat(inode, &info); -- -- return 0; --} -- --static void exfat_evict_inode(struct inode *inode) --{ -- truncate_inode_pages(&inode->i_data, 0); -- -- if (!inode->i_nlink) -- i_size_write(inode, 0); -- invalidate_inode_buffers(inode); -- clear_inode(inode); -- exfat_detach(inode); -- -- remove_inode_hash(inode); --} -- --static void exfat_free_super(struct exfat_sb_info *sbi) --{ -- if (sbi->nls_disk) -- unload_nls(sbi->nls_disk); -- if (sbi->nls_io) -- unload_nls(sbi->nls_io); -- if (sbi->options.iocharset != exfat_default_iocharset) -- kfree(sbi->options.iocharset); -- /* mutex_init is in exfat_fill_super function. only for 3.7+ */ -- mutex_destroy(&sbi->s_lock); -- kvfree(sbi); --} -- --static void exfat_put_super(struct super_block *sb) --{ -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- -- if (__is_sb_dirty(sb)) -- exfat_write_super(sb); -- -- ffsUmountVol(sb); -- -- sb->s_fs_info = NULL; -- exfat_free_super(sbi); --} -- --static void exfat_write_super(struct super_block *sb) --{ -- __lock_super(sb); -- -- __set_sb_clean(sb); -- -- if (!sb_rdonly(sb)) -- ffsSyncVol(sb, true); -- -- __unlock_super(sb); --} -- --static int exfat_sync_fs(struct super_block *sb, int wait) --{ -- int err = 0; -- -- if (__is_sb_dirty(sb)) { -- __lock_super(sb); -- __set_sb_clean(sb); -- err = ffsSyncVol(sb, true); -- __unlock_super(sb); -- } -- -- return err; --} -- --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); -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- struct vol_info_t info; -- -- if (p_fs->used_clusters == UINT_MAX) { -- if (ffsGetVolInfo(sb, &info) == -EIO) -- 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) -- pr_info("[EXFAT] statfs on device that is ejected\n"); -- } -- -- buf->f_type = sb->s_magic; -- buf->f_bsize = info.ClusterSize; -- buf->f_blocks = info.NumClusters; -- buf->f_bfree = info.FreeClusters; -- buf->f_bavail = info.FreeClusters; -- buf->f_fsid.val[0] = (u32)id; -- buf->f_fsid.val[1] = (u32)(id >> 32); -- buf->f_namelen = 260; -- -- return 0; --} -- --static int exfat_remount(struct super_block *sb, int *flags, char *data) --{ -- *flags |= SB_NODIRATIME; -- return 0; --} -- --static int exfat_show_options(struct seq_file *m, struct dentry *root) --{ -- struct exfat_sb_info *sbi = EXFAT_SB(root->d_sb); -- struct exfat_mount_options *opts = &sbi->options; -- -- if (__kuid_val(opts->fs_uid)) -- seq_printf(m, ",uid=%u", __kuid_val(opts->fs_uid)); -- if (__kgid_val(opts->fs_gid)) -- seq_printf(m, ",gid=%u", __kgid_val(opts->fs_gid)); -- 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=%04o", opts->allow_utime); -- if (sbi->nls_disk) -- seq_printf(m, ",codepage=%s", sbi->nls_disk->charset); -- if (sbi->nls_io) -- seq_printf(m, ",iocharset=%s", sbi->nls_io->charset); -- seq_printf(m, ",namecase=%u", opts->casesensitive); -- if (opts->errors == EXFAT_ERRORS_CONT) -- seq_puts(m, ",errors=continue"); -- else if (opts->errors == EXFAT_ERRORS_PANIC) -- seq_puts(m, ",errors=panic"); -- else -- seq_puts(m, ",errors=remount-ro"); --#ifdef CONFIG_STAGING_EXFAT_DISCARD -- if (opts->discard) -- seq_puts(m, ",discard"); --#endif -- return 0; --} -- --static const struct super_operations exfat_sops = { -- .alloc_inode = exfat_alloc_inode, -- .destroy_inode = exfat_destroy_inode, -- .write_inode = exfat_write_inode, -- .evict_inode = exfat_evict_inode, -- .put_super = exfat_put_super, -- .sync_fs = exfat_sync_fs, -- .statfs = exfat_statfs, -- .remount_fs = exfat_remount, -- .show_options = exfat_show_options, --}; -- --/*======================================================================*/ --/* Export Operations */ --/*======================================================================*/ -- --static struct inode *exfat_nfs_get_inode(struct super_block *sb, u64 ino, -- u32 generation) --{ -- struct inode *inode = NULL; -- -- if (ino < EXFAT_ROOT_INO) -- return inode; -- inode = ilookup(sb, ino); -- -- if (inode && generation && (inode->i_generation != generation)) { -- iput(inode); -- inode = NULL; -- } -- -- return inode; --} -- --static struct dentry *exfat_fh_to_dentry(struct super_block *sb, -- struct fid *fid, int fh_len, -- int fh_type) --{ -- return generic_fh_to_dentry(sb, fid, fh_len, fh_type, -- exfat_nfs_get_inode); --} -- --static struct dentry *exfat_fh_to_parent(struct super_block *sb, -- struct fid *fid, int fh_len, -- int fh_type) --{ -- return generic_fh_to_parent(sb, fid, fh_len, fh_type, -- exfat_nfs_get_inode); --} -- --static const struct export_operations exfat_export_ops = { -- .fh_to_dentry = exfat_fh_to_dentry, -- .fh_to_parent = exfat_fh_to_parent, --}; -- --/*======================================================================*/ --/* Super Block Read Operations */ --/*======================================================================*/ -- --enum { -- Opt_uid, -- Opt_gid, -- Opt_umask, -- Opt_dmask, -- Opt_fmask, -- Opt_allow_utime, -- Opt_codepage, -- Opt_charset, -- Opt_namecase, -- Opt_debug, -- Opt_err_cont, -- Opt_err_panic, -- Opt_err_ro, -- Opt_utf8_hack, -- Opt_err, --#ifdef CONFIG_STAGING_EXFAT_DISCARD -- Opt_discard, --#endif /* EXFAT_CONFIG_DISCARD */ --}; -- --static const match_table_t exfat_tokens = { -- {Opt_uid, "uid=%u"}, -- {Opt_gid, "gid=%u"}, -- {Opt_umask, "umask=%o"}, -- {Opt_dmask, "dmask=%o"}, -- {Opt_fmask, "fmask=%o"}, -- {Opt_allow_utime, "allow_utime=%o"}, -- {Opt_codepage, "codepage=%u"}, -- {Opt_charset, "iocharset=%s"}, -- {Opt_namecase, "namecase=%u"}, -- {Opt_debug, "debug"}, -- {Opt_err_cont, "errors=continue"}, -- {Opt_err_panic, "errors=panic"}, -- {Opt_err_ro, "errors=remount-ro"}, -- {Opt_utf8_hack, "utf8"}, --#ifdef CONFIG_STAGING_EXFAT_DISCARD -- {Opt_discard, "discard"}, --#endif /* CONFIG_STAGING_EXFAT_DISCARD */ -- {Opt_err, NULL} --}; -- --static int parse_options(char *options, int silent, int *debug, -- struct exfat_mount_options *opts) --{ -- char *p; -- substring_t args[MAX_OPT_ARGS]; -- int option; -- char *iocharset; -- -- opts->fs_uid = current_uid(); -- opts->fs_gid = current_gid(); -- opts->fs_fmask = current->fs->umask; -- opts->fs_dmask = current->fs->umask; -- opts->allow_utime = U16_MAX; -- opts->codepage = exfat_default_codepage; -- opts->iocharset = exfat_default_iocharset; -- opts->casesensitive = 0; -- opts->errors = EXFAT_ERRORS_RO; --#ifdef CONFIG_STAGING_EXFAT_DISCARD -- opts->discard = 0; --#endif -- *debug = 0; -- -- if (!options) -- goto out; -- -- while ((p = strsep(&options, ","))) { -- int token; -- -- if (!*p) -- continue; -- -- token = match_token(p, exfat_tokens, args); -- switch (token) { -- case Opt_uid: -- if (match_int(&args[0], &option)) -- return 0; -- opts->fs_uid = KUIDT_INIT(option); -- break; -- case Opt_gid: -- if (match_int(&args[0], &option)) -- return 0; -- opts->fs_gid = KGIDT_INIT(option); -- break; -- case Opt_umask: -- case Opt_dmask: -- case Opt_fmask: -- if (match_octal(&args[0], &option)) -- return 0; -- if (token != Opt_dmask) -- opts->fs_fmask = option; -- if (token != Opt_fmask) -- opts->fs_dmask = option; -- break; -- case Opt_allow_utime: -- if (match_octal(&args[0], &option)) -- return 0; -- opts->allow_utime = option & 0022; -- break; -- case Opt_codepage: -- if (match_int(&args[0], &option)) -- return 0; -- opts->codepage = option; -- break; -- case Opt_charset: -- if (opts->iocharset != exfat_default_iocharset) -- kfree(opts->iocharset); -- iocharset = match_strdup(&args[0]); -- if (!iocharset) -- return -ENOMEM; -- opts->iocharset = iocharset; -- break; -- case Opt_namecase: -- if (match_int(&args[0], &option)) -- return 0; -- opts->casesensitive = option; -- break; -- case Opt_err_cont: -- opts->errors = EXFAT_ERRORS_CONT; -- break; -- case Opt_err_panic: -- opts->errors = EXFAT_ERRORS_PANIC; -- break; -- case Opt_err_ro: -- opts->errors = EXFAT_ERRORS_RO; -- break; -- case Opt_debug: -- *debug = 1; -- break; --#ifdef CONFIG_STAGING_EXFAT_DISCARD -- case Opt_discard: -- opts->discard = 1; -- break; --#endif /* CONFIG_STAGING_EXFAT_DISCARD */ -- case Opt_utf8_hack: -- break; -- default: -- if (!silent) -- pr_err("[EXFAT] Unrecognized mount option %s or missing value\n", -- p); -- return -EINVAL; -- } -- } -- --out: -- if (opts->allow_utime == U16_MAX) -- opts->allow_utime = ~opts->fs_dmask & 0022; -- -- return 0; --} -- --static void exfat_hash_init(struct super_block *sb) --{ -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- int i; -- -- spin_lock_init(&sbi->inode_hash_lock); -- for (i = 0; i < EXFAT_HASH_SIZE; i++) -- INIT_HLIST_HEAD(&sbi->inode_hashtable[i]); --} -- --static int exfat_read_root(struct inode *inode) --{ -- struct super_block *sb = inode->i_sb; -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- struct fs_info_t *p_fs = &sbi->fs_info; -- struct timespec64 curtime; -- struct dir_entry_t info; -- -- EXFAT_I(inode)->fid.dir.dir = p_fs->root_dir; -- EXFAT_I(inode)->fid.dir.flags = 0x01; -- EXFAT_I(inode)->fid.entry = -1; -- EXFAT_I(inode)->fid.start_clu = p_fs->root_dir; -- EXFAT_I(inode)->fid.flags = 0x01; -- EXFAT_I(inode)->fid.type = TYPE_DIR; -- EXFAT_I(inode)->fid.rwoffset = 0; -- EXFAT_I(inode)->fid.hint_last_off = -1; -- -- EXFAT_I(inode)->target = NULL; -- -- ffsReadStat(inode, &info); -- -- inode->i_uid = sbi->options.fs_uid; -- inode->i_gid = sbi->options.fs_gid; -- INC_IVERSION(inode); -- inode->i_generation = 0; -- inode->i_mode = exfat_make_mode(sbi, ATTR_SUBDIR, 0777); -- inode->i_op = &exfat_dir_inode_operations; -- inode->i_fop = &exfat_dir_operations; -- -- i_size_write(inode, info.Size); -- inode->i_blocks = ((i_size_read(inode) + (p_fs->cluster_size - 1)) -- & ~((loff_t)p_fs->cluster_size - 1)) >> 9; -- EXFAT_I(inode)->i_pos = ((loff_t)p_fs->root_dir << 32) | 0xffffffff; -- EXFAT_I(inode)->mmu_private = i_size_read(inode); -- -- exfat_save_attr(inode, ATTR_SUBDIR); -- curtime = current_time(inode); -- inode->i_mtime = curtime; -- inode->i_atime = curtime; -- inode->i_ctime = curtime; -- set_nlink(inode, info.NumSubdirs + 2); -- -- return 0; --} -- --static void setup_dops(struct super_block *sb) --{ -- if (EXFAT_SB(sb)->options.casesensitive == 0) -- sb->s_d_op = &exfat_ci_dentry_ops; -- else -- sb->s_d_op = &exfat_dentry_ops; --} -- --static int exfat_fill_super(struct super_block *sb, void *data, int silent) --{ -- struct inode *root_inode = NULL; -- struct exfat_sb_info *sbi; -- int debug, ret; -- long error; -- -- /* -- * GFP_KERNEL is ok here, because while we do hold the -- * supeblock lock, memory pressure can't call back into -- * the filesystem, since we're only just about to mount -- * it and have no inodes etc active! -- */ -- sbi = kvzalloc(sizeof(*sbi), GFP_KERNEL); -- if (!sbi) -- return -ENOMEM; -- mutex_init(&sbi->s_lock); -- sb->s_fs_info = sbi; -- sb->s_flags |= SB_NODIRATIME; -- sb->s_magic = EXFAT_SUPER_MAGIC; -- sb->s_op = &exfat_sops; -- sb->s_export_op = &exfat_export_ops; -- -- error = parse_options(data, silent, &debug, &sbi->options); -- if (error) -- goto out_fail; -- -- setup_dops(sb); -- -- error = -EIO; -- sb_min_blocksize(sb, 512); -- sb->s_maxbytes = 0x7fffffffffffffffLL; /* maximum file size */ -- -- ret = ffsMountVol(sb); -- if (ret) { -- if (!silent) -- pr_err("[EXFAT] ffsMountVol failed\n"); -- -- goto out_fail; -- } -- -- /* set up enough so that it can read an inode */ -- exfat_hash_init(sb); -- -- /* -- * The low byte of FAT's first entry must have same value with -- * media-field. But in real world, too many devices is -- * writing wrong value. So, removed that validity check. -- * -- * if (FAT_FIRST_ENT(sb, media) != first) -- */ -- -- sbi->nls_io = load_nls(sbi->options.iocharset); -- -- error = -ENOMEM; -- root_inode = new_inode(sb); -- if (!root_inode) -- goto out_fail2; -- root_inode->i_ino = EXFAT_ROOT_INO; -- SET_IVERSION(root_inode, 1); -- -- error = exfat_read_root(root_inode); -- if (error < 0) -- goto out_fail2; -- error = -ENOMEM; -- exfat_attach(root_inode, EXFAT_I(root_inode)->i_pos); -- insert_inode_hash(root_inode); -- sb->s_root = d_make_root(root_inode); -- if (!sb->s_root) { -- pr_err("[EXFAT] Getting the root inode failed\n"); -- goto out_fail2; -- } -- -- return 0; -- --out_fail2: -- ffsUmountVol(sb); --out_fail: -- if (root_inode) -- iput(root_inode); -- sb->s_fs_info = NULL; -- exfat_free_super(sbi); -- return error; --} -- --static struct dentry *exfat_fs_mount(struct file_system_type *fs_type, -- int flags, const char *dev_name, -- void *data) --{ -- return mount_bdev(fs_type, flags, dev_name, data, exfat_fill_super); --} -- --static void init_once(void *foo) --{ -- struct exfat_inode_info *ei = (struct exfat_inode_info *)foo; -- -- INIT_HLIST_NODE(&ei->i_hash_fat); -- inode_init_once(&ei->vfs_inode); --} -- --static int __init exfat_init_inodecache(void) --{ -- exfat_inode_cachep = kmem_cache_create("exfat_inode_cache", -- sizeof(struct exfat_inode_info), -- 0, -- (SLAB_RECLAIM_ACCOUNT | -- SLAB_MEM_SPREAD), -- init_once); -- if (!exfat_inode_cachep) -- return -ENOMEM; -- return 0; --} -- --static void __exit exfat_destroy_inodecache(void) --{ -- /* -- * Make sure all delayed rcu free inodes are flushed before we -- * destroy cache. -- */ -- rcu_barrier(); -- kmem_cache_destroy(exfat_inode_cachep); --} -- --#ifdef CONFIG_STAGING_EXFAT_KERNEL_DEBUG --static void exfat_debug_kill_sb(struct super_block *sb) --{ -- struct exfat_sb_info *sbi = EXFAT_SB(sb); -- struct block_device *bdev = sb->s_bdev; -- struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -- -- long flags; -- -- if (sbi) { -- flags = sbi->debug_flags; -- -- if (flags & EXFAT_DEBUGFLAGS_INVALID_UMOUNT) { -- /* -- * invalidate_bdev drops all device cache include -- * dirty. We use this to simulate device removal. -- */ -- mutex_lock(&p_fs->v_mutex); -- exfat_fat_release_all(sb); -- exfat_buf_release_all(sb); -- mutex_unlock(&p_fs->v_mutex); -- -- invalidate_bdev(bdev); -- } -- } -- -- kill_block_super(sb); --} --#endif /* CONFIG_STAGING_EXFAT_KERNEL_DEBUG */ -- --static struct file_system_type exfat_fs_type = { -- .owner = THIS_MODULE, -- .name = "exfat", -- .mount = exfat_fs_mount, --#ifdef CONFIG_STAGING_EXFAT_KERNEL_DEBUG -- .kill_sb = exfat_debug_kill_sb, --#else -- .kill_sb = kill_block_super, --#endif /* CONFIG_STAGING_EXFAT_KERNEL_DEBUG */ -- .fs_flags = FS_REQUIRES_DEV, --}; -- --static int __init init_exfat(void) --{ -- int err; -- -- BUILD_BUG_ON(sizeof(struct dentry_t) != DENTRY_SIZE); -- BUILD_BUG_ON(sizeof(struct dos_dentry_t) != DENTRY_SIZE); -- BUILD_BUG_ON(sizeof(struct ext_dentry_t) != DENTRY_SIZE); -- BUILD_BUG_ON(sizeof(struct file_dentry_t) != DENTRY_SIZE); -- BUILD_BUG_ON(sizeof(struct strm_dentry_t) != DENTRY_SIZE); -- BUILD_BUG_ON(sizeof(struct name_dentry_t) != DENTRY_SIZE); -- BUILD_BUG_ON(sizeof(struct bmap_dentry_t) != DENTRY_SIZE); -- BUILD_BUG_ON(sizeof(struct case_dentry_t) != DENTRY_SIZE); -- BUILD_BUG_ON(sizeof(struct volm_dentry_t) != DENTRY_SIZE); -- -- pr_info("exFAT: Version %s\n", EXFAT_VERSION); -- -- err = exfat_init_inodecache(); -- if (err) -- return err; -- -- err = register_filesystem(&exfat_fs_type); -- if (err) -- return err; -- -- return 0; --} -- --static void __exit exit_exfat(void) --{ -- exfat_destroy_inodecache(); -- unregister_filesystem(&exfat_fs_type); --} -- --module_init(init_exfat); --module_exit(exit_exfat); -- --MODULE_LICENSE("GPL"); --MODULE_DESCRIPTION("exFAT Filesystem Driver"); --MODULE_ALIAS_FS("exfat"); -diff -Nurp linux-5.6.3.orig/drivers/staging/exfat/exfat_upcase.c linux-5.6.3/drivers/staging/exfat/exfat_upcase.c ---- linux-5.6.3.orig/drivers/staging/exfat/exfat_upcase.c 2020-03-30 01:25:41.000000000 +0300 -+++ linux-5.6.3/drivers/staging/exfat/exfat_upcase.c 1970-01-01 02:00:00.000000000 +0200 -@@ -1,740 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0-or-later --/* -- * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -- */ -- --#include --#include "exfat.h" -- --const u8 uni_upcase[NUM_UPCASE << 1] = { -- 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, -- 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, -- 0x08, 0x00, 0x09, 0x00, 0x0A, 0x00, 0x0B, 0x00, -- 0x0C, 0x00, 0x0D, 0x00, 0x0E, 0x00, 0x0F, 0x00, -- 0x10, 0x00, 0x11, 0x00, 0x12, 0x00, 0x13, 0x00, -- 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x17, 0x00, -- 0x18, 0x00, 0x19, 0x00, 0x1A, 0x00, 0x1B, 0x00, -- 0x1C, 0x00, 0x1D, 0x00, 0x1E, 0x00, 0x1F, 0x00, -- 0x20, 0x00, 0x21, 0x00, 0x22, 0x00, 0x23, 0x00, -- 0x24, 0x00, 0x25, 0x00, 0x26, 0x00, 0x27, 0x00, -- 0x28, 0x00, 0x29, 0x00, 0x2A, 0x00, 0x2B, 0x00, -- 0x2C, 0x00, 0x2D, 0x00, 0x2E, 0x00, 0x2F, 0x00, -- 0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, -- 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x37, 0x00, -- 0x38, 0x00, 0x39, 0x00, 0x3A, 0x00, 0x3B, 0x00, -- 0x3C, 0x00, 0x3D, 0x00, 0x3E, 0x00, 0x3F, 0x00, -- 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, -- 0x44, 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00, -- 0x48, 0x00, 0x49, 0x00, 0x4A, 0x00, 0x4B, 0x00, -- 0x4C, 0x00, 0x4D, 0x00, 0x4E, 0x00, 0x4F, 0x00, -- 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00, -- 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00, -- 0x58, 0x00, 0x59, 0x00, 0x5A, 0x00, 0x5B, 0x00, -- 0x5C, 0x00, 0x5D, 0x00, 0x5E, 0x00, 0x5F, 0x00, -- 0x60, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, -- 0x44, 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00, -- 0x48, 0x00, 0x49, 0x00, 0x4A, 0x00, 0x4B, 0x00, -- 0x4C, 0x00, 0x4D, 0x00, 0x4E, 0x00, 0x4F, 0x00, -- 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00, -- 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00, -- 0x58, 0x00, 0x59, 0x00, 0x5A, 0x00, 0x7B, 0x00, -- 0x7C, 0x00, 0x7D, 0x00, 0x7E, 0x00, 0x7F, 0x00, -- 0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83, 0x00, -- 0x84, 0x00, 0x85, 0x00, 0x86, 0x00, 0x87, 0x00, -- 0x88, 0x00, 0x89, 0x00, 0x8A, 0x00, 0x8B, 0x00, -- 0x8C, 0x00, 0x8D, 0x00, 0x8E, 0x00, 0x8F, 0x00, -- 0x90, 0x00, 0x91, 0x00, 0x92, 0x00, 0x93, 0x00, -- 0x94, 0x00, 0x95, 0x00, 0x96, 0x00, 0x97, 0x00, -- 0x98, 0x00, 0x99, 0x00, 0x9A, 0x00, 0x9B, 0x00, -- 0x9C, 0x00, 0x9D, 0x00, 0x9E, 0x00, 0x9F, 0x00, -- 0xA0, 0x00, 0xA1, 0x00, 0xA2, 0x00, 0xA3, 0x00, -- 0xA4, 0x00, 0xA5, 0x00, 0xA6, 0x00, 0xA7, 0x00, -- 0xA8, 0x00, 0xA9, 0x00, 0xAA, 0x00, 0xAB, 0x00, -- 0xAC, 0x00, 0xAD, 0x00, 0xAE, 0x00, 0xAF, 0x00, -- 0xB0, 0x00, 0xB1, 0x00, 0xB2, 0x00, 0xB3, 0x00, -- 0xB4, 0x00, 0xB5, 0x00, 0xB6, 0x00, 0xB7, 0x00, -- 0xB8, 0x00, 0xB9, 0x00, 0xBA, 0x00, 0xBB, 0x00, -- 0xBC, 0x00, 0xBD, 0x00, 0xBE, 0x00, 0xBF, 0x00, -- 0xC0, 0x00, 0xC1, 0x00, 0xC2, 0x00, 0xC3, 0x00, -- 0xC4, 0x00, 0xC5, 0x00, 0xC6, 0x00, 0xC7, 0x00, -- 0xC8, 0x00, 0xC9, 0x00, 0xCA, 0x00, 0xCB, 0x00, -- 0xCC, 0x00, 0xCD, 0x00, 0xCE, 0x00, 0xCF, 0x00, -- 0xD0, 0x00, 0xD1, 0x00, 0xD2, 0x00, 0xD3, 0x00, -- 0xD4, 0x00, 0xD5, 0x00, 0xD6, 0x00, 0xD7, 0x00, -- 0xD8, 0x00, 0xD9, 0x00, 0xDA, 0x00, 0xDB, 0x00, -- 0xDC, 0x00, 0xDD, 0x00, 0xDE, 0x00, 0xDF, 0x00, -- 0xC0, 0x00, 0xC1, 0x00, 0xC2, 0x00, 0xC3, 0x00, -- 0xC4, 0x00, 0xC5, 0x00, 0xC6, 0x00, 0xC7, 0x00, -- 0xC8, 0x00, 0xC9, 0x00, 0xCA, 0x00, 0xCB, 0x00, -- 0xCC, 0x00, 0xCD, 0x00, 0xCE, 0x00, 0xCF, 0x00, -- 0xD0, 0x00, 0xD1, 0x00, 0xD2, 0x00, 0xD3, 0x00, -- 0xD4, 0x00, 0xD5, 0x00, 0xD6, 0x00, 0xF7, 0x00, -- 0xD8, 0x00, 0xD9, 0x00, 0xDA, 0x00, 0xDB, 0x00, -- 0xDC, 0x00, 0xDD, 0x00, 0xDE, 0x00, 0x78, 0x01, -- 0x00, 0x01, 0x00, 0x01, 0x02, 0x01, 0x02, 0x01, -- 0x04, 0x01, 0x04, 0x01, 0x06, 0x01, 0x06, 0x01, -- 0x08, 0x01, 0x08, 0x01, 0x0A, 0x01, 0x0A, 0x01, -- 0x0C, 0x01, 0x0C, 0x01, 0x0E, 0x01, 0x0E, 0x01, -- 0x10, 0x01, 0x10, 0x01, 0x12, 0x01, 0x12, 0x01, -- 0x14, 0x01, 0x14, 0x01, 0x16, 0x01, 0x16, 0x01, -- 0x18, 0x01, 0x18, 0x01, 0x1A, 0x01, 0x1A, 0x01, -- 0x1C, 0x01, 0x1C, 0x01, 0x1E, 0x01, 0x1E, 0x01, -- 0x20, 0x01, 0x20, 0x01, 0x22, 0x01, 0x22, 0x01, -- 0x24, 0x01, 0x24, 0x01, 0x26, 0x01, 0x26, 0x01, -- 0x28, 0x01, 0x28, 0x01, 0x2A, 0x01, 0x2A, 0x01, -- 0x2C, 0x01, 0x2C, 0x01, 0x2E, 0x01, 0x2E, 0x01, -- 0x30, 0x01, 0x31, 0x01, 0x32, 0x01, 0x32, 0x01, -- 0x34, 0x01, 0x34, 0x01, 0x36, 0x01, 0x36, 0x01, -- 0x38, 0x01, 0x39, 0x01, 0x39, 0x01, 0x3B, 0x01, -- 0x3B, 0x01, 0x3D, 0x01, 0x3D, 0x01, 0x3F, 0x01, -- 0x3F, 0x01, 0x41, 0x01, 0x41, 0x01, 0x43, 0x01, -- 0x43, 0x01, 0x45, 0x01, 0x45, 0x01, 0x47, 0x01, -- 0x47, 0x01, 0x49, 0x01, 0x4A, 0x01, 0x4A, 0x01, -- 0x4C, 0x01, 0x4C, 0x01, 0x4E, 0x01, 0x4E, 0x01, -- 0x50, 0x01, 0x50, 0x01, 0x52, 0x01, 0x52, 0x01, -- 0x54, 0x01, 0x54, 0x01, 0x56, 0x01, 0x56, 0x01, -- 0x58, 0x01, 0x58, 0x01, 0x5A, 0x01, 0x5A, 0x01, -- 0x5C, 0x01, 0x5C, 0x01, 0x5E, 0x01, 0x5E, 0x01, -- 0x60, 0x01, 0x60, 0x01, 0x62, 0x01, 0x62, 0x01, -- 0x64, 0x01, 0x64, 0x01, 0x66, 0x01, 0x66, 0x01, -- 0x68, 0x01, 0x68, 0x01, 0x6A, 0x01, 0x6A, 0x01, -- 0x6C, 0x01, 0x6C, 0x01, 0x6E, 0x01, 0x6E, 0x01, -- 0x70, 0x01, 0x70, 0x01, 0x72, 0x01, 0x72, 0x01, -- 0x74, 0x01, 0x74, 0x01, 0x76, 0x01, 0x76, 0x01, -- 0x78, 0x01, 0x79, 0x01, 0x79, 0x01, 0x7B, 0x01, -- 0x7B, 0x01, 0x7D, 0x01, 0x7D, 0x01, 0x7F, 0x01, -- 0x43, 0x02, 0x81, 0x01, 0x82, 0x01, 0x82, 0x01, -- 0x84, 0x01, 0x84, 0x01, 0x86, 0x01, 0x87, 0x01, -- 0x87, 0x01, 0x89, 0x01, 0x8A, 0x01, 0x8B, 0x01, -- 0x8B, 0x01, 0x8D, 0x01, 0x8E, 0x01, 0x8F, 0x01, -- 0x90, 0x01, 0x91, 0x01, 0x91, 0x01, 0x93, 0x01, -- 0x94, 0x01, 0xF6, 0x01, 0x96, 0x01, 0x97, 0x01, -- 0x98, 0x01, 0x98, 0x01, 0x3D, 0x02, 0x9B, 0x01, -- 0x9C, 0x01, 0x9D, 0x01, 0x20, 0x02, 0x9F, 0x01, -- 0xA0, 0x01, 0xA0, 0x01, 0xA2, 0x01, 0xA2, 0x01, -- 0xA4, 0x01, 0xA4, 0x01, 0xA6, 0x01, 0xA7, 0x01, -- 0xA7, 0x01, 0xA9, 0x01, 0xAA, 0x01, 0xAB, 0x01, -- 0xAC, 0x01, 0xAC, 0x01, 0xAE, 0x01, 0xAF, 0x01, -- 0xAF, 0x01, 0xB1, 0x01, 0xB2, 0x01, 0xB3, 0x01, -- 0xB3, 0x01, 0xB5, 0x01, 0xB5, 0x01, 0xB7, 0x01, -- 0xB8, 0x01, 0xB8, 0x01, 0xBA, 0x01, 0xBB, 0x01, -- 0xBC, 0x01, 0xBC, 0x01, 0xBE, 0x01, 0xF7, 0x01, -- 0xC0, 0x01, 0xC1, 0x01, 0xC2, 0x01, 0xC3, 0x01, -- 0xC4, 0x01, 0xC5, 0x01, 0xC4, 0x01, 0xC7, 0x01, -- 0xC8, 0x01, 0xC7, 0x01, 0xCA, 0x01, 0xCB, 0x01, -- 0xCA, 0x01, 0xCD, 0x01, 0xCD, 0x01, 0xCF, 0x01, -- 0xCF, 0x01, 0xD1, 0x01, 0xD1, 0x01, 0xD3, 0x01, -- 0xD3, 0x01, 0xD5, 0x01, 0xD5, 0x01, 0xD7, 0x01, -- 0xD7, 0x01, 0xD9, 0x01, 0xD9, 0x01, 0xDB, 0x01, -- 0xDB, 0x01, 0x8E, 0x01, 0xDE, 0x01, 0xDE, 0x01, -- 0xE0, 0x01, 0xE0, 0x01, 0xE2, 0x01, 0xE2, 0x01, -- 0xE4, 0x01, 0xE4, 0x01, 0xE6, 0x01, 0xE6, 0x01, -- 0xE8, 0x01, 0xE8, 0x01, 0xEA, 0x01, 0xEA, 0x01, -- 0xEC, 0x01, 0xEC, 0x01, 0xEE, 0x01, 0xEE, 0x01, -- 0xF0, 0x01, 0xF1, 0x01, 0xF2, 0x01, 0xF1, 0x01, -- 0xF4, 0x01, 0xF4, 0x01, 0xF6, 0x01, 0xF7, 0x01, -- 0xF8, 0x01, 0xF8, 0x01, 0xFA, 0x01, 0xFA, 0x01, -- 0xFC, 0x01, 0xFC, 0x01, 0xFE, 0x01, 0xFE, 0x01, -- 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, -- 0x04, 0x02, 0x04, 0x02, 0x06, 0x02, 0x06, 0x02, -- 0x08, 0x02, 0x08, 0x02, 0x0A, 0x02, 0x0A, 0x02, -- 0x0C, 0x02, 0x0C, 0x02, 0x0E, 0x02, 0x0E, 0x02, -- 0x10, 0x02, 0x10, 0x02, 0x12, 0x02, 0x12, 0x02, -- 0x14, 0x02, 0x14, 0x02, 0x16, 0x02, 0x16, 0x02, -- 0x18, 0x02, 0x18, 0x02, 0x1A, 0x02, 0x1A, 0x02, -- 0x1C, 0x02, 0x1C, 0x02, 0x1E, 0x02, 0x1E, 0x02, -- 0x20, 0x02, 0x21, 0x02, 0x22, 0x02, 0x22, 0x02, -- 0x24, 0x02, 0x24, 0x02, 0x26, 0x02, 0x26, 0x02, -- 0x28, 0x02, 0x28, 0x02, 0x2A, 0x02, 0x2A, 0x02, -- 0x2C, 0x02, 0x2C, 0x02, 0x2E, 0x02, 0x2E, 0x02, -- 0x30, 0x02, 0x30, 0x02, 0x32, 0x02, 0x32, 0x02, -- 0x34, 0x02, 0x35, 0x02, 0x36, 0x02, 0x37, 0x02, -- 0x38, 0x02, 0x39, 0x02, 0x65, 0x2C, 0x3B, 0x02, -- 0x3B, 0x02, 0x3D, 0x02, 0x66, 0x2C, 0x3F, 0x02, -- 0x40, 0x02, 0x41, 0x02, 0x41, 0x02, 0x43, 0x02, -- 0x44, 0x02, 0x45, 0x02, 0x46, 0x02, 0x46, 0x02, -- 0x48, 0x02, 0x48, 0x02, 0x4A, 0x02, 0x4A, 0x02, -- 0x4C, 0x02, 0x4C, 0x02, 0x4E, 0x02, 0x4E, 0x02, -- 0x50, 0x02, 0x51, 0x02, 0x52, 0x02, 0x81, 0x01, -- 0x86, 0x01, 0x55, 0x02, 0x89, 0x01, 0x8A, 0x01, -- 0x58, 0x02, 0x8F, 0x01, 0x5A, 0x02, 0x90, 0x01, -- 0x5C, 0x02, 0x5D, 0x02, 0x5E, 0x02, 0x5F, 0x02, -- 0x93, 0x01, 0x61, 0x02, 0x62, 0x02, 0x94, 0x01, -- 0x64, 0x02, 0x65, 0x02, 0x66, 0x02, 0x67, 0x02, -- 0x97, 0x01, 0x96, 0x01, 0x6A, 0x02, 0x62, 0x2C, -- 0x6C, 0x02, 0x6D, 0x02, 0x6E, 0x02, 0x9C, 0x01, -- 0x70, 0x02, 0x71, 0x02, 0x9D, 0x01, 0x73, 0x02, -- 0x74, 0x02, 0x9F, 0x01, 0x76, 0x02, 0x77, 0x02, -- 0x78, 0x02, 0x79, 0x02, 0x7A, 0x02, 0x7B, 0x02, -- 0x7C, 0x02, 0x64, 0x2C, 0x7E, 0x02, 0x7F, 0x02, -- 0xA6, 0x01, 0x81, 0x02, 0x82, 0x02, 0xA9, 0x01, -- 0x84, 0x02, 0x85, 0x02, 0x86, 0x02, 0x87, 0x02, -- 0xAE, 0x01, 0x44, 0x02, 0xB1, 0x01, 0xB2, 0x01, -- 0x45, 0x02, 0x8D, 0x02, 0x8E, 0x02, 0x8F, 0x02, -- 0x90, 0x02, 0x91, 0x02, 0xB7, 0x01, 0x93, 0x02, -- 0x94, 0x02, 0x95, 0x02, 0x96, 0x02, 0x97, 0x02, -- 0x98, 0x02, 0x99, 0x02, 0x9A, 0x02, 0x9B, 0x02, -- 0x9C, 0x02, 0x9D, 0x02, 0x9E, 0x02, 0x9F, 0x02, -- 0xA0, 0x02, 0xA1, 0x02, 0xA2, 0x02, 0xA3, 0x02, -- 0xA4, 0x02, 0xA5, 0x02, 0xA6, 0x02, 0xA7, 0x02, -- 0xA8, 0x02, 0xA9, 0x02, 0xAA, 0x02, 0xAB, 0x02, -- 0xAC, 0x02, 0xAD, 0x02, 0xAE, 0x02, 0xAF, 0x02, -- 0xB0, 0x02, 0xB1, 0x02, 0xB2, 0x02, 0xB3, 0x02, -- 0xB4, 0x02, 0xB5, 0x02, 0xB6, 0x02, 0xB7, 0x02, -- 0xB8, 0x02, 0xB9, 0x02, 0xBA, 0x02, 0xBB, 0x02, -- 0xBC, 0x02, 0xBD, 0x02, 0xBE, 0x02, 0xBF, 0x02, -- 0xC0, 0x02, 0xC1, 0x02, 0xC2, 0x02, 0xC3, 0x02, -- 0xC4, 0x02, 0xC5, 0x02, 0xC6, 0x02, 0xC7, 0x02, -- 0xC8, 0x02, 0xC9, 0x02, 0xCA, 0x02, 0xCB, 0x02, -- 0xCC, 0x02, 0xCD, 0x02, 0xCE, 0x02, 0xCF, 0x02, -- 0xD0, 0x02, 0xD1, 0x02, 0xD2, 0x02, 0xD3, 0x02, -- 0xD4, 0x02, 0xD5, 0x02, 0xD6, 0x02, 0xD7, 0x02, -- 0xD8, 0x02, 0xD9, 0x02, 0xDA, 0x02, 0xDB, 0x02, -- 0xDC, 0x02, 0xDD, 0x02, 0xDE, 0x02, 0xDF, 0x02, -- 0xE0, 0x02, 0xE1, 0x02, 0xE2, 0x02, 0xE3, 0x02, -- 0xE4, 0x02, 0xE5, 0x02, 0xE6, 0x02, 0xE7, 0x02, -- 0xE8, 0x02, 0xE9, 0x02, 0xEA, 0x02, 0xEB, 0x02, -- 0xEC, 0x02, 0xED, 0x02, 0xEE, 0x02, 0xEF, 0x02, -- 0xF0, 0x02, 0xF1, 0x02, 0xF2, 0x02, 0xF3, 0x02, -- 0xF4, 0x02, 0xF5, 0x02, 0xF6, 0x02, 0xF7, 0x02, -- 0xF8, 0x02, 0xF9, 0x02, 0xFA, 0x02, 0xFB, 0x02, -- 0xFC, 0x02, 0xFD, 0x02, 0xFE, 0x02, 0xFF, 0x02, -- 0x00, 0x03, 0x01, 0x03, 0x02, 0x03, 0x03, 0x03, -- 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x07, 0x03, -- 0x08, 0x03, 0x09, 0x03, 0x0A, 0x03, 0x0B, 0x03, -- 0x0C, 0x03, 0x0D, 0x03, 0x0E, 0x03, 0x0F, 0x03, -- 0x10, 0x03, 0x11, 0x03, 0x12, 0x03, 0x13, 0x03, -- 0x14, 0x03, 0x15, 0x03, 0x16, 0x03, 0x17, 0x03, -- 0x18, 0x03, 0x19, 0x03, 0x1A, 0x03, 0x1B, 0x03, -- 0x1C, 0x03, 0x1D, 0x03, 0x1E, 0x03, 0x1F, 0x03, -- 0x20, 0x03, 0x21, 0x03, 0x22, 0x03, 0x23, 0x03, -- 0x24, 0x03, 0x25, 0x03, 0x26, 0x03, 0x27, 0x03, -- 0x28, 0x03, 0x29, 0x03, 0x2A, 0x03, 0x2B, 0x03, -- 0x2C, 0x03, 0x2D, 0x03, 0x2E, 0x03, 0x2F, 0x03, -- 0x30, 0x03, 0x31, 0x03, 0x32, 0x03, 0x33, 0x03, -- 0x34, 0x03, 0x35, 0x03, 0x36, 0x03, 0x37, 0x03, -- 0x38, 0x03, 0x39, 0x03, 0x3A, 0x03, 0x3B, 0x03, -- 0x3C, 0x03, 0x3D, 0x03, 0x3E, 0x03, 0x3F, 0x03, -- 0x40, 0x03, 0x41, 0x03, 0x42, 0x03, 0x43, 0x03, -- 0x44, 0x03, 0x45, 0x03, 0x46, 0x03, 0x47, 0x03, -- 0x48, 0x03, 0x49, 0x03, 0x4A, 0x03, 0x4B, 0x03, -- 0x4C, 0x03, 0x4D, 0x03, 0x4E, 0x03, 0x4F, 0x03, -- 0x50, 0x03, 0x51, 0x03, 0x52, 0x03, 0x53, 0x03, -- 0x54, 0x03, 0x55, 0x03, 0x56, 0x03, 0x57, 0x03, -- 0x58, 0x03, 0x59, 0x03, 0x5A, 0x03, 0x5B, 0x03, -- 0x5C, 0x03, 0x5D, 0x03, 0x5E, 0x03, 0x5F, 0x03, -- 0x60, 0x03, 0x61, 0x03, 0x62, 0x03, 0x63, 0x03, -- 0x64, 0x03, 0x65, 0x03, 0x66, 0x03, 0x67, 0x03, -- 0x68, 0x03, 0x69, 0x03, 0x6A, 0x03, 0x6B, 0x03, -- 0x6C, 0x03, 0x6D, 0x03, 0x6E, 0x03, 0x6F, 0x03, -- 0x70, 0x03, 0x71, 0x03, 0x72, 0x03, 0x73, 0x03, -- 0x74, 0x03, 0x75, 0x03, 0x76, 0x03, 0x77, 0x03, -- 0x78, 0x03, 0x79, 0x03, 0x7A, 0x03, 0xFD, 0x03, -- 0xFE, 0x03, 0xFF, 0x03, 0x7E, 0x03, 0x7F, 0x03, -- 0x80, 0x03, 0x81, 0x03, 0x82, 0x03, 0x83, 0x03, -- 0x84, 0x03, 0x85, 0x03, 0x86, 0x03, 0x87, 0x03, -- 0x88, 0x03, 0x89, 0x03, 0x8A, 0x03, 0x8B, 0x03, -- 0x8C, 0x03, 0x8D, 0x03, 0x8E, 0x03, 0x8F, 0x03, -- 0x90, 0x03, 0x91, 0x03, 0x92, 0x03, 0x93, 0x03, -- 0x94, 0x03, 0x95, 0x03, 0x96, 0x03, 0x97, 0x03, -- 0x98, 0x03, 0x99, 0x03, 0x9A, 0x03, 0x9B, 0x03, -- 0x9C, 0x03, 0x9D, 0x03, 0x9E, 0x03, 0x9F, 0x03, -- 0xA0, 0x03, 0xA1, 0x03, 0xA2, 0x03, 0xA3, 0x03, -- 0xA4, 0x03, 0xA5, 0x03, 0xA6, 0x03, 0xA7, 0x03, -- 0xA8, 0x03, 0xA9, 0x03, 0xAA, 0x03, 0xAB, 0x03, -- 0x86, 0x03, 0x88, 0x03, 0x89, 0x03, 0x8A, 0x03, -- 0xB0, 0x03, 0x91, 0x03, 0x92, 0x03, 0x93, 0x03, -- 0x94, 0x03, 0x95, 0x03, 0x96, 0x03, 0x97, 0x03, -- 0x98, 0x03, 0x99, 0x03, 0x9A, 0x03, 0x9B, 0x03, -- 0x9C, 0x03, 0x9D, 0x03, 0x9E, 0x03, 0x9F, 0x03, -- 0xA0, 0x03, 0xA1, 0x03, 0xA3, 0x03, 0xA3, 0x03, -- 0xA4, 0x03, 0xA5, 0x03, 0xA6, 0x03, 0xA7, 0x03, -- 0xA8, 0x03, 0xA9, 0x03, 0xAA, 0x03, 0xAB, 0x03, -- 0x8C, 0x03, 0x8E, 0x03, 0x8F, 0x03, 0xCF, 0x03, -- 0xD0, 0x03, 0xD1, 0x03, 0xD2, 0x03, 0xD3, 0x03, -- 0xD4, 0x03, 0xD5, 0x03, 0xD6, 0x03, 0xD7, 0x03, -- 0xD8, 0x03, 0xD8, 0x03, 0xDA, 0x03, 0xDA, 0x03, -- 0xDC, 0x03, 0xDC, 0x03, 0xDE, 0x03, 0xDE, 0x03, -- 0xE0, 0x03, 0xE0, 0x03, 0xE2, 0x03, 0xE2, 0x03, -- 0xE4, 0x03, 0xE4, 0x03, 0xE6, 0x03, 0xE6, 0x03, -- 0xE8, 0x03, 0xE8, 0x03, 0xEA, 0x03, 0xEA, 0x03, -- 0xEC, 0x03, 0xEC, 0x03, 0xEE, 0x03, 0xEE, 0x03, -- 0xF0, 0x03, 0xF1, 0x03, 0xF9, 0x03, 0xF3, 0x03, -- 0xF4, 0x03, 0xF5, 0x03, 0xF6, 0x03, 0xF7, 0x03, -- 0xF7, 0x03, 0xF9, 0x03, 0xFA, 0x03, 0xFA, 0x03, -- 0xFC, 0x03, 0xFD, 0x03, 0xFE, 0x03, 0xFF, 0x03, -- 0x00, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x04, -- 0x04, 0x04, 0x05, 0x04, 0x06, 0x04, 0x07, 0x04, -- 0x08, 0x04, 0x09, 0x04, 0x0A, 0x04, 0x0B, 0x04, -- 0x0C, 0x04, 0x0D, 0x04, 0x0E, 0x04, 0x0F, 0x04, -- 0x10, 0x04, 0x11, 0x04, 0x12, 0x04, 0x13, 0x04, -- 0x14, 0x04, 0x15, 0x04, 0x16, 0x04, 0x17, 0x04, -- 0x18, 0x04, 0x19, 0x04, 0x1A, 0x04, 0x1B, 0x04, -- 0x1C, 0x04, 0x1D, 0x04, 0x1E, 0x04, 0x1F, 0x04, -- 0x20, 0x04, 0x21, 0x04, 0x22, 0x04, 0x23, 0x04, -- 0x24, 0x04, 0x25, 0x04, 0x26, 0x04, 0x27, 0x04, -- 0x28, 0x04, 0x29, 0x04, 0x2A, 0x04, 0x2B, 0x04, -- 0x2C, 0x04, 0x2D, 0x04, 0x2E, 0x04, 0x2F, 0x04, -- 0x10, 0x04, 0x11, 0x04, 0x12, 0x04, 0x13, 0x04, -- 0x14, 0x04, 0x15, 0x04, 0x16, 0x04, 0x17, 0x04, -- 0x18, 0x04, 0x19, 0x04, 0x1A, 0x04, 0x1B, 0x04, -- 0x1C, 0x04, 0x1D, 0x04, 0x1E, 0x04, 0x1F, 0x04, -- 0x20, 0x04, 0x21, 0x04, 0x22, 0x04, 0x23, 0x04, -- 0x24, 0x04, 0x25, 0x04, 0x26, 0x04, 0x27, 0x04, -- 0x28, 0x04, 0x29, 0x04, 0x2A, 0x04, 0x2B, 0x04, -- 0x2C, 0x04, 0x2D, 0x04, 0x2E, 0x04, 0x2F, 0x04, -- 0x00, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x04, -- 0x04, 0x04, 0x05, 0x04, 0x06, 0x04, 0x07, 0x04, -- 0x08, 0x04, 0x09, 0x04, 0x0A, 0x04, 0x0B, 0x04, -- 0x0C, 0x04, 0x0D, 0x04, 0x0E, 0x04, 0x0F, 0x04, -- 0x60, 0x04, 0x60, 0x04, 0x62, 0x04, 0x62, 0x04, -- 0x64, 0x04, 0x64, 0x04, 0x66, 0x04, 0x66, 0x04, -- 0x68, 0x04, 0x68, 0x04, 0x6A, 0x04, 0x6A, 0x04, -- 0x6C, 0x04, 0x6C, 0x04, 0x6E, 0x04, 0x6E, 0x04, -- 0x70, 0x04, 0x70, 0x04, 0x72, 0x04, 0x72, 0x04, -- 0x74, 0x04, 0x74, 0x04, 0x76, 0x04, 0x76, 0x04, -- 0x78, 0x04, 0x78, 0x04, 0x7A, 0x04, 0x7A, 0x04, -- 0x7C, 0x04, 0x7C, 0x04, 0x7E, 0x04, 0x7E, 0x04, -- 0x80, 0x04, 0x80, 0x04, 0x82, 0x04, 0x83, 0x04, -- 0x84, 0x04, 0x85, 0x04, 0x86, 0x04, 0x87, 0x04, -- 0x88, 0x04, 0x89, 0x04, 0x8A, 0x04, 0x8A, 0x04, -- 0x8C, 0x04, 0x8C, 0x04, 0x8E, 0x04, 0x8E, 0x04, -- 0x90, 0x04, 0x90, 0x04, 0x92, 0x04, 0x92, 0x04, -- 0x94, 0x04, 0x94, 0x04, 0x96, 0x04, 0x96, 0x04, -- 0x98, 0x04, 0x98, 0x04, 0x9A, 0x04, 0x9A, 0x04, -- 0x9C, 0x04, 0x9C, 0x04, 0x9E, 0x04, 0x9E, 0x04, -- 0xA0, 0x04, 0xA0, 0x04, 0xA2, 0x04, 0xA2, 0x04, -- 0xA4, 0x04, 0xA4, 0x04, 0xA6, 0x04, 0xA6, 0x04, -- 0xA8, 0x04, 0xA8, 0x04, 0xAA, 0x04, 0xAA, 0x04, -- 0xAC, 0x04, 0xAC, 0x04, 0xAE, 0x04, 0xAE, 0x04, -- 0xB0, 0x04, 0xB0, 0x04, 0xB2, 0x04, 0xB2, 0x04, -- 0xB4, 0x04, 0xB4, 0x04, 0xB6, 0x04, 0xB6, 0x04, -- 0xB8, 0x04, 0xB8, 0x04, 0xBA, 0x04, 0xBA, 0x04, -- 0xBC, 0x04, 0xBC, 0x04, 0xBE, 0x04, 0xBE, 0x04, -- 0xC0, 0x04, 0xC1, 0x04, 0xC1, 0x04, 0xC3, 0x04, -- 0xC3, 0x04, 0xC5, 0x04, 0xC5, 0x04, 0xC7, 0x04, -- 0xC7, 0x04, 0xC9, 0x04, 0xC9, 0x04, 0xCB, 0x04, -- 0xCB, 0x04, 0xCD, 0x04, 0xCD, 0x04, 0xC0, 0x04, -- 0xD0, 0x04, 0xD0, 0x04, 0xD2, 0x04, 0xD2, 0x04, -- 0xD4, 0x04, 0xD4, 0x04, 0xD6, 0x04, 0xD6, 0x04, -- 0xD8, 0x04, 0xD8, 0x04, 0xDA, 0x04, 0xDA, 0x04, -- 0xDC, 0x04, 0xDC, 0x04, 0xDE, 0x04, 0xDE, 0x04, -- 0xE0, 0x04, 0xE0, 0x04, 0xE2, 0x04, 0xE2, 0x04, -- 0xE4, 0x04, 0xE4, 0x04, 0xE6, 0x04, 0xE6, 0x04, -- 0xE8, 0x04, 0xE8, 0x04, 0xEA, 0x04, 0xEA, 0x04, -- 0xEC, 0x04, 0xEC, 0x04, 0xEE, 0x04, 0xEE, 0x04, -- 0xF0, 0x04, 0xF0, 0x04, 0xF2, 0x04, 0xF2, 0x04, -- 0xF4, 0x04, 0xF4, 0x04, 0xF6, 0x04, 0xF6, 0x04, -- 0xF8, 0x04, 0xF8, 0x04, 0xFA, 0x04, 0xFA, 0x04, -- 0xFC, 0x04, 0xFC, 0x04, 0xFE, 0x04, 0xFE, 0x04, -- 0x00, 0x05, 0x00, 0x05, 0x02, 0x05, 0x02, 0x05, -- 0x04, 0x05, 0x04, 0x05, 0x06, 0x05, 0x06, 0x05, -- 0x08, 0x05, 0x08, 0x05, 0x0A, 0x05, 0x0A, 0x05, -- 0x0C, 0x05, 0x0C, 0x05, 0x0E, 0x05, 0x0E, 0x05, -- 0x10, 0x05, 0x10, 0x05, 0x12, 0x05, 0x12, 0x05, -- 0x14, 0x05, 0x15, 0x05, 0x16, 0x05, 0x17, 0x05, -- 0x18, 0x05, 0x19, 0x05, 0x1A, 0x05, 0x1B, 0x05, -- 0x1C, 0x05, 0x1D, 0x05, 0x1E, 0x05, 0x1F, 0x05, -- 0x20, 0x05, 0x21, 0x05, 0x22, 0x05, 0x23, 0x05, -- 0x24, 0x05, 0x25, 0x05, 0x26, 0x05, 0x27, 0x05, -- 0x28, 0x05, 0x29, 0x05, 0x2A, 0x05, 0x2B, 0x05, -- 0x2C, 0x05, 0x2D, 0x05, 0x2E, 0x05, 0x2F, 0x05, -- 0x30, 0x05, 0x31, 0x05, 0x32, 0x05, 0x33, 0x05, -- 0x34, 0x05, 0x35, 0x05, 0x36, 0x05, 0x37, 0x05, -- 0x38, 0x05, 0x39, 0x05, 0x3A, 0x05, 0x3B, 0x05, -- 0x3C, 0x05, 0x3D, 0x05, 0x3E, 0x05, 0x3F, 0x05, -- 0x40, 0x05, 0x41, 0x05, 0x42, 0x05, 0x43, 0x05, -- 0x44, 0x05, 0x45, 0x05, 0x46, 0x05, 0x47, 0x05, -- 0x48, 0x05, 0x49, 0x05, 0x4A, 0x05, 0x4B, 0x05, -- 0x4C, 0x05, 0x4D, 0x05, 0x4E, 0x05, 0x4F, 0x05, -- 0x50, 0x05, 0x51, 0x05, 0x52, 0x05, 0x53, 0x05, -- 0x54, 0x05, 0x55, 0x05, 0x56, 0x05, 0x57, 0x05, -- 0x58, 0x05, 0x59, 0x05, 0x5A, 0x05, 0x5B, 0x05, -- 0x5C, 0x05, 0x5D, 0x05, 0x5E, 0x05, 0x5F, 0x05, -- 0x60, 0x05, 0x31, 0x05, 0x32, 0x05, 0x33, 0x05, -- 0x34, 0x05, 0x35, 0x05, 0x36, 0x05, 0x37, 0x05, -- 0x38, 0x05, 0x39, 0x05, 0x3A, 0x05, 0x3B, 0x05, -- 0x3C, 0x05, 0x3D, 0x05, 0x3E, 0x05, 0x3F, 0x05, -- 0x40, 0x05, 0x41, 0x05, 0x42, 0x05, 0x43, 0x05, -- 0x44, 0x05, 0x45, 0x05, 0x46, 0x05, 0x47, 0x05, -- 0x48, 0x05, 0x49, 0x05, 0x4A, 0x05, 0x4B, 0x05, -- 0x4C, 0x05, 0x4D, 0x05, 0x4E, 0x05, 0x4F, 0x05, -- 0x50, 0x05, 0x51, 0x05, 0x52, 0x05, 0x53, 0x05, -- 0x54, 0x05, 0x55, 0x05, 0x56, 0x05, 0xFF, 0xFF, -- 0xF6, 0x17, 0x63, 0x2C, 0x7E, 0x1D, 0x7F, 0x1D, -- 0x80, 0x1D, 0x81, 0x1D, 0x82, 0x1D, 0x83, 0x1D, -- 0x84, 0x1D, 0x85, 0x1D, 0x86, 0x1D, 0x87, 0x1D, -- 0x88, 0x1D, 0x89, 0x1D, 0x8A, 0x1D, 0x8B, 0x1D, -- 0x8C, 0x1D, 0x8D, 0x1D, 0x8E, 0x1D, 0x8F, 0x1D, -- 0x90, 0x1D, 0x91, 0x1D, 0x92, 0x1D, 0x93, 0x1D, -- 0x94, 0x1D, 0x95, 0x1D, 0x96, 0x1D, 0x97, 0x1D, -- 0x98, 0x1D, 0x99, 0x1D, 0x9A, 0x1D, 0x9B, 0x1D, -- 0x9C, 0x1D, 0x9D, 0x1D, 0x9E, 0x1D, 0x9F, 0x1D, -- 0xA0, 0x1D, 0xA1, 0x1D, 0xA2, 0x1D, 0xA3, 0x1D, -- 0xA4, 0x1D, 0xA5, 0x1D, 0xA6, 0x1D, 0xA7, 0x1D, -- 0xA8, 0x1D, 0xA9, 0x1D, 0xAA, 0x1D, 0xAB, 0x1D, -- 0xAC, 0x1D, 0xAD, 0x1D, 0xAE, 0x1D, 0xAF, 0x1D, -- 0xB0, 0x1D, 0xB1, 0x1D, 0xB2, 0x1D, 0xB3, 0x1D, -- 0xB4, 0x1D, 0xB5, 0x1D, 0xB6, 0x1D, 0xB7, 0x1D, -- 0xB8, 0x1D, 0xB9, 0x1D, 0xBA, 0x1D, 0xBB, 0x1D, -- 0xBC, 0x1D, 0xBD, 0x1D, 0xBE, 0x1D, 0xBF, 0x1D, -- 0xC0, 0x1D, 0xC1, 0x1D, 0xC2, 0x1D, 0xC3, 0x1D, -- 0xC4, 0x1D, 0xC5, 0x1D, 0xC6, 0x1D, 0xC7, 0x1D, -- 0xC8, 0x1D, 0xC9, 0x1D, 0xCA, 0x1D, 0xCB, 0x1D, -- 0xCC, 0x1D, 0xCD, 0x1D, 0xCE, 0x1D, 0xCF, 0x1D, -- 0xD0, 0x1D, 0xD1, 0x1D, 0xD2, 0x1D, 0xD3, 0x1D, -- 0xD4, 0x1D, 0xD5, 0x1D, 0xD6, 0x1D, 0xD7, 0x1D, -- 0xD8, 0x1D, 0xD9, 0x1D, 0xDA, 0x1D, 0xDB, 0x1D, -- 0xDC, 0x1D, 0xDD, 0x1D, 0xDE, 0x1D, 0xDF, 0x1D, -- 0xE0, 0x1D, 0xE1, 0x1D, 0xE2, 0x1D, 0xE3, 0x1D, -- 0xE4, 0x1D, 0xE5, 0x1D, 0xE6, 0x1D, 0xE7, 0x1D, -- 0xE8, 0x1D, 0xE9, 0x1D, 0xEA, 0x1D, 0xEB, 0x1D, -- 0xEC, 0x1D, 0xED, 0x1D, 0xEE, 0x1D, 0xEF, 0x1D, -- 0xF0, 0x1D, 0xF1, 0x1D, 0xF2, 0x1D, 0xF3, 0x1D, -- 0xF4, 0x1D, 0xF5, 0x1D, 0xF6, 0x1D, 0xF7, 0x1D, -- 0xF8, 0x1D, 0xF9, 0x1D, 0xFA, 0x1D, 0xFB, 0x1D, -- 0xFC, 0x1D, 0xFD, 0x1D, 0xFE, 0x1D, 0xFF, 0x1D, -- 0x00, 0x1E, 0x00, 0x1E, 0x02, 0x1E, 0x02, 0x1E, -- 0x04, 0x1E, 0x04, 0x1E, 0x06, 0x1E, 0x06, 0x1E, -- 0x08, 0x1E, 0x08, 0x1E, 0x0A, 0x1E, 0x0A, 0x1E, -- 0x0C, 0x1E, 0x0C, 0x1E, 0x0E, 0x1E, 0x0E, 0x1E, -- 0x10, 0x1E, 0x10, 0x1E, 0x12, 0x1E, 0x12, 0x1E, -- 0x14, 0x1E, 0x14, 0x1E, 0x16, 0x1E, 0x16, 0x1E, -- 0x18, 0x1E, 0x18, 0x1E, 0x1A, 0x1E, 0x1A, 0x1E, -- 0x1C, 0x1E, 0x1C, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, -- 0x20, 0x1E, 0x20, 0x1E, 0x22, 0x1E, 0x22, 0x1E, -- 0x24, 0x1E, 0x24, 0x1E, 0x26, 0x1E, 0x26, 0x1E, -- 0x28, 0x1E, 0x28, 0x1E, 0x2A, 0x1E, 0x2A, 0x1E, -- 0x2C, 0x1E, 0x2C, 0x1E, 0x2E, 0x1E, 0x2E, 0x1E, -- 0x30, 0x1E, 0x30, 0x1E, 0x32, 0x1E, 0x32, 0x1E, -- 0x34, 0x1E, 0x34, 0x1E, 0x36, 0x1E, 0x36, 0x1E, -- 0x38, 0x1E, 0x38, 0x1E, 0x3A, 0x1E, 0x3A, 0x1E, -- 0x3C, 0x1E, 0x3C, 0x1E, 0x3E, 0x1E, 0x3E, 0x1E, -- 0x40, 0x1E, 0x40, 0x1E, 0x42, 0x1E, 0x42, 0x1E, -- 0x44, 0x1E, 0x44, 0x1E, 0x46, 0x1E, 0x46, 0x1E, -- 0x48, 0x1E, 0x48, 0x1E, 0x4A, 0x1E, 0x4A, 0x1E, -- 0x4C, 0x1E, 0x4C, 0x1E, 0x4E, 0x1E, 0x4E, 0x1E, -- 0x50, 0x1E, 0x50, 0x1E, 0x52, 0x1E, 0x52, 0x1E, -- 0x54, 0x1E, 0x54, 0x1E, 0x56, 0x1E, 0x56, 0x1E, -- 0x58, 0x1E, 0x58, 0x1E, 0x5A, 0x1E, 0x5A, 0x1E, -- 0x5C, 0x1E, 0x5C, 0x1E, 0x5E, 0x1E, 0x5E, 0x1E, -- 0x60, 0x1E, 0x60, 0x1E, 0x62, 0x1E, 0x62, 0x1E, -- 0x64, 0x1E, 0x64, 0x1E, 0x66, 0x1E, 0x66, 0x1E, -- 0x68, 0x1E, 0x68, 0x1E, 0x6A, 0x1E, 0x6A, 0x1E, -- 0x6C, 0x1E, 0x6C, 0x1E, 0x6E, 0x1E, 0x6E, 0x1E, -- 0x70, 0x1E, 0x70, 0x1E, 0x72, 0x1E, 0x72, 0x1E, -- 0x74, 0x1E, 0x74, 0x1E, 0x76, 0x1E, 0x76, 0x1E, -- 0x78, 0x1E, 0x78, 0x1E, 0x7A, 0x1E, 0x7A, 0x1E, -- 0x7C, 0x1E, 0x7C, 0x1E, 0x7E, 0x1E, 0x7E, 0x1E, -- 0x80, 0x1E, 0x80, 0x1E, 0x82, 0x1E, 0x82, 0x1E, -- 0x84, 0x1E, 0x84, 0x1E, 0x86, 0x1E, 0x86, 0x1E, -- 0x88, 0x1E, 0x88, 0x1E, 0x8A, 0x1E, 0x8A, 0x1E, -- 0x8C, 0x1E, 0x8C, 0x1E, 0x8E, 0x1E, 0x8E, 0x1E, -- 0x90, 0x1E, 0x90, 0x1E, 0x92, 0x1E, 0x92, 0x1E, -- 0x94, 0x1E, 0x94, 0x1E, 0x96, 0x1E, 0x97, 0x1E, -- 0x98, 0x1E, 0x99, 0x1E, 0x9A, 0x1E, 0x9B, 0x1E, -- 0x9C, 0x1E, 0x9D, 0x1E, 0x9E, 0x1E, 0x9F, 0x1E, -- 0xA0, 0x1E, 0xA0, 0x1E, 0xA2, 0x1E, 0xA2, 0x1E, -- 0xA4, 0x1E, 0xA4, 0x1E, 0xA6, 0x1E, 0xA6, 0x1E, -- 0xA8, 0x1E, 0xA8, 0x1E, 0xAA, 0x1E, 0xAA, 0x1E, -- 0xAC, 0x1E, 0xAC, 0x1E, 0xAE, 0x1E, 0xAE, 0x1E, -- 0xB0, 0x1E, 0xB0, 0x1E, 0xB2, 0x1E, 0xB2, 0x1E, -- 0xB4, 0x1E, 0xB4, 0x1E, 0xB6, 0x1E, 0xB6, 0x1E, -- 0xB8, 0x1E, 0xB8, 0x1E, 0xBA, 0x1E, 0xBA, 0x1E, -- 0xBC, 0x1E, 0xBC, 0x1E, 0xBE, 0x1E, 0xBE, 0x1E, -- 0xC0, 0x1E, 0xC0, 0x1E, 0xC2, 0x1E, 0xC2, 0x1E, -- 0xC4, 0x1E, 0xC4, 0x1E, 0xC6, 0x1E, 0xC6, 0x1E, -- 0xC8, 0x1E, 0xC8, 0x1E, 0xCA, 0x1E, 0xCA, 0x1E, -- 0xCC, 0x1E, 0xCC, 0x1E, 0xCE, 0x1E, 0xCE, 0x1E, -- 0xD0, 0x1E, 0xD0, 0x1E, 0xD2, 0x1E, 0xD2, 0x1E, -- 0xD4, 0x1E, 0xD4, 0x1E, 0xD6, 0x1E, 0xD6, 0x1E, -- 0xD8, 0x1E, 0xD8, 0x1E, 0xDA, 0x1E, 0xDA, 0x1E, -- 0xDC, 0x1E, 0xDC, 0x1E, 0xDE, 0x1E, 0xDE, 0x1E, -- 0xE0, 0x1E, 0xE0, 0x1E, 0xE2, 0x1E, 0xE2, 0x1E, -- 0xE4, 0x1E, 0xE4, 0x1E, 0xE6, 0x1E, 0xE6, 0x1E, -- 0xE8, 0x1E, 0xE8, 0x1E, 0xEA, 0x1E, 0xEA, 0x1E, -- 0xEC, 0x1E, 0xEC, 0x1E, 0xEE, 0x1E, 0xEE, 0x1E, -- 0xF0, 0x1E, 0xF0, 0x1E, 0xF2, 0x1E, 0xF2, 0x1E, -- 0xF4, 0x1E, 0xF4, 0x1E, 0xF6, 0x1E, 0xF6, 0x1E, -- 0xF8, 0x1E, 0xF8, 0x1E, 0xFA, 0x1E, 0xFB, 0x1E, -- 0xFC, 0x1E, 0xFD, 0x1E, 0xFE, 0x1E, 0xFF, 0x1E, -- 0x08, 0x1F, 0x09, 0x1F, 0x0A, 0x1F, 0x0B, 0x1F, -- 0x0C, 0x1F, 0x0D, 0x1F, 0x0E, 0x1F, 0x0F, 0x1F, -- 0x08, 0x1F, 0x09, 0x1F, 0x0A, 0x1F, 0x0B, 0x1F, -- 0x0C, 0x1F, 0x0D, 0x1F, 0x0E, 0x1F, 0x0F, 0x1F, -- 0x18, 0x1F, 0x19, 0x1F, 0x1A, 0x1F, 0x1B, 0x1F, -- 0x1C, 0x1F, 0x1D, 0x1F, 0x16, 0x1F, 0x17, 0x1F, -- 0x18, 0x1F, 0x19, 0x1F, 0x1A, 0x1F, 0x1B, 0x1F, -- 0x1C, 0x1F, 0x1D, 0x1F, 0x1E, 0x1F, 0x1F, 0x1F, -- 0x28, 0x1F, 0x29, 0x1F, 0x2A, 0x1F, 0x2B, 0x1F, -- 0x2C, 0x1F, 0x2D, 0x1F, 0x2E, 0x1F, 0x2F, 0x1F, -- 0x28, 0x1F, 0x29, 0x1F, 0x2A, 0x1F, 0x2B, 0x1F, -- 0x2C, 0x1F, 0x2D, 0x1F, 0x2E, 0x1F, 0x2F, 0x1F, -- 0x38, 0x1F, 0x39, 0x1F, 0x3A, 0x1F, 0x3B, 0x1F, -- 0x3C, 0x1F, 0x3D, 0x1F, 0x3E, 0x1F, 0x3F, 0x1F, -- 0x38, 0x1F, 0x39, 0x1F, 0x3A, 0x1F, 0x3B, 0x1F, -- 0x3C, 0x1F, 0x3D, 0x1F, 0x3E, 0x1F, 0x3F, 0x1F, -- 0x48, 0x1F, 0x49, 0x1F, 0x4A, 0x1F, 0x4B, 0x1F, -- 0x4C, 0x1F, 0x4D, 0x1F, 0x46, 0x1F, 0x47, 0x1F, -- 0x48, 0x1F, 0x49, 0x1F, 0x4A, 0x1F, 0x4B, 0x1F, -- 0x4C, 0x1F, 0x4D, 0x1F, 0x4E, 0x1F, 0x4F, 0x1F, -- 0x50, 0x1F, 0x59, 0x1F, 0x52, 0x1F, 0x5B, 0x1F, -- 0x54, 0x1F, 0x5D, 0x1F, 0x56, 0x1F, 0x5F, 0x1F, -- 0x58, 0x1F, 0x59, 0x1F, 0x5A, 0x1F, 0x5B, 0x1F, -- 0x5C, 0x1F, 0x5D, 0x1F, 0x5E, 0x1F, 0x5F, 0x1F, -- 0x68, 0x1F, 0x69, 0x1F, 0x6A, 0x1F, 0x6B, 0x1F, -- 0x6C, 0x1F, 0x6D, 0x1F, 0x6E, 0x1F, 0x6F, 0x1F, -- 0x68, 0x1F, 0x69, 0x1F, 0x6A, 0x1F, 0x6B, 0x1F, -- 0x6C, 0x1F, 0x6D, 0x1F, 0x6E, 0x1F, 0x6F, 0x1F, -- 0xBA, 0x1F, 0xBB, 0x1F, 0xC8, 0x1F, 0xC9, 0x1F, -- 0xCA, 0x1F, 0xCB, 0x1F, 0xDA, 0x1F, 0xDB, 0x1F, -- 0xF8, 0x1F, 0xF9, 0x1F, 0xEA, 0x1F, 0xEB, 0x1F, -- 0xFA, 0x1F, 0xFB, 0x1F, 0x7E, 0x1F, 0x7F, 0x1F, -- 0x88, 0x1F, 0x89, 0x1F, 0x8A, 0x1F, 0x8B, 0x1F, -- 0x8C, 0x1F, 0x8D, 0x1F, 0x8E, 0x1F, 0x8F, 0x1F, -- 0x88, 0x1F, 0x89, 0x1F, 0x8A, 0x1F, 0x8B, 0x1F, -- 0x8C, 0x1F, 0x8D, 0x1F, 0x8E, 0x1F, 0x8F, 0x1F, -- 0x98, 0x1F, 0x99, 0x1F, 0x9A, 0x1F, 0x9B, 0x1F, -- 0x9C, 0x1F, 0x9D, 0x1F, 0x9E, 0x1F, 0x9F, 0x1F, -- 0x98, 0x1F, 0x99, 0x1F, 0x9A, 0x1F, 0x9B, 0x1F, -- 0x9C, 0x1F, 0x9D, 0x1F, 0x9E, 0x1F, 0x9F, 0x1F, -- 0xA8, 0x1F, 0xA9, 0x1F, 0xAA, 0x1F, 0xAB, 0x1F, -- 0xAC, 0x1F, 0xAD, 0x1F, 0xAE, 0x1F, 0xAF, 0x1F, -- 0xA8, 0x1F, 0xA9, 0x1F, 0xAA, 0x1F, 0xAB, 0x1F, -- 0xAC, 0x1F, 0xAD, 0x1F, 0xAE, 0x1F, 0xAF, 0x1F, -- 0xB8, 0x1F, 0xB9, 0x1F, 0xB2, 0x1F, 0xBC, 0x1F, -- 0xB4, 0x1F, 0xB5, 0x1F, 0xB6, 0x1F, 0xB7, 0x1F, -- 0xB8, 0x1F, 0xB9, 0x1F, 0xBA, 0x1F, 0xBB, 0x1F, -- 0xBC, 0x1F, 0xBD, 0x1F, 0xBE, 0x1F, 0xBF, 0x1F, -- 0xC0, 0x1F, 0xC1, 0x1F, 0xC2, 0x1F, 0xC3, 0x1F, -- 0xC4, 0x1F, 0xC5, 0x1F, 0xC6, 0x1F, 0xC7, 0x1F, -- 0xC8, 0x1F, 0xC9, 0x1F, 0xCA, 0x1F, 0xCB, 0x1F, -- 0xC3, 0x1F, 0xCD, 0x1F, 0xCE, 0x1F, 0xCF, 0x1F, -- 0xD8, 0x1F, 0xD9, 0x1F, 0xD2, 0x1F, 0xD3, 0x1F, -- 0xD4, 0x1F, 0xD5, 0x1F, 0xD6, 0x1F, 0xD7, 0x1F, -- 0xD8, 0x1F, 0xD9, 0x1F, 0xDA, 0x1F, 0xDB, 0x1F, -- 0xDC, 0x1F, 0xDD, 0x1F, 0xDE, 0x1F, 0xDF, 0x1F, -- 0xE8, 0x1F, 0xE9, 0x1F, 0xE2, 0x1F, 0xE3, 0x1F, -- 0xE4, 0x1F, 0xEC, 0x1F, 0xE6, 0x1F, 0xE7, 0x1F, -- 0xE8, 0x1F, 0xE9, 0x1F, 0xEA, 0x1F, 0xEB, 0x1F, -- 0xEC, 0x1F, 0xED, 0x1F, 0xEE, 0x1F, 0xEF, 0x1F, -- 0xF0, 0x1F, 0xF1, 0x1F, 0xF2, 0x1F, 0xF3, 0x1F, -- 0xF4, 0x1F, 0xF5, 0x1F, 0xF6, 0x1F, 0xF7, 0x1F, -- 0xF8, 0x1F, 0xF9, 0x1F, 0xFA, 0x1F, 0xFB, 0x1F, -- 0xF3, 0x1F, 0xFD, 0x1F, 0xFE, 0x1F, 0xFF, 0x1F, -- 0x00, 0x20, 0x01, 0x20, 0x02, 0x20, 0x03, 0x20, -- 0x04, 0x20, 0x05, 0x20, 0x06, 0x20, 0x07, 0x20, -- 0x08, 0x20, 0x09, 0x20, 0x0A, 0x20, 0x0B, 0x20, -- 0x0C, 0x20, 0x0D, 0x20, 0x0E, 0x20, 0x0F, 0x20, -- 0x10, 0x20, 0x11, 0x20, 0x12, 0x20, 0x13, 0x20, -- 0x14, 0x20, 0x15, 0x20, 0x16, 0x20, 0x17, 0x20, -- 0x18, 0x20, 0x19, 0x20, 0x1A, 0x20, 0x1B, 0x20, -- 0x1C, 0x20, 0x1D, 0x20, 0x1E, 0x20, 0x1F, 0x20, -- 0x20, 0x20, 0x21, 0x20, 0x22, 0x20, 0x23, 0x20, -- 0x24, 0x20, 0x25, 0x20, 0x26, 0x20, 0x27, 0x20, -- 0x28, 0x20, 0x29, 0x20, 0x2A, 0x20, 0x2B, 0x20, -- 0x2C, 0x20, 0x2D, 0x20, 0x2E, 0x20, 0x2F, 0x20, -- 0x30, 0x20, 0x31, 0x20, 0x32, 0x20, 0x33, 0x20, -- 0x34, 0x20, 0x35, 0x20, 0x36, 0x20, 0x37, 0x20, -- 0x38, 0x20, 0x39, 0x20, 0x3A, 0x20, 0x3B, 0x20, -- 0x3C, 0x20, 0x3D, 0x20, 0x3E, 0x20, 0x3F, 0x20, -- 0x40, 0x20, 0x41, 0x20, 0x42, 0x20, 0x43, 0x20, -- 0x44, 0x20, 0x45, 0x20, 0x46, 0x20, 0x47, 0x20, -- 0x48, 0x20, 0x49, 0x20, 0x4A, 0x20, 0x4B, 0x20, -- 0x4C, 0x20, 0x4D, 0x20, 0x4E, 0x20, 0x4F, 0x20, -- 0x50, 0x20, 0x51, 0x20, 0x52, 0x20, 0x53, 0x20, -- 0x54, 0x20, 0x55, 0x20, 0x56, 0x20, 0x57, 0x20, -- 0x58, 0x20, 0x59, 0x20, 0x5A, 0x20, 0x5B, 0x20, -- 0x5C, 0x20, 0x5D, 0x20, 0x5E, 0x20, 0x5F, 0x20, -- 0x60, 0x20, 0x61, 0x20, 0x62, 0x20, 0x63, 0x20, -- 0x64, 0x20, 0x65, 0x20, 0x66, 0x20, 0x67, 0x20, -- 0x68, 0x20, 0x69, 0x20, 0x6A, 0x20, 0x6B, 0x20, -- 0x6C, 0x20, 0x6D, 0x20, 0x6E, 0x20, 0x6F, 0x20, -- 0x70, 0x20, 0x71, 0x20, 0x72, 0x20, 0x73, 0x20, -- 0x74, 0x20, 0x75, 0x20, 0x76, 0x20, 0x77, 0x20, -- 0x78, 0x20, 0x79, 0x20, 0x7A, 0x20, 0x7B, 0x20, -- 0x7C, 0x20, 0x7D, 0x20, 0x7E, 0x20, 0x7F, 0x20, -- 0x80, 0x20, 0x81, 0x20, 0x82, 0x20, 0x83, 0x20, -- 0x84, 0x20, 0x85, 0x20, 0x86, 0x20, 0x87, 0x20, -- 0x88, 0x20, 0x89, 0x20, 0x8A, 0x20, 0x8B, 0x20, -- 0x8C, 0x20, 0x8D, 0x20, 0x8E, 0x20, 0x8F, 0x20, -- 0x90, 0x20, 0x91, 0x20, 0x92, 0x20, 0x93, 0x20, -- 0x94, 0x20, 0x95, 0x20, 0x96, 0x20, 0x97, 0x20, -- 0x98, 0x20, 0x99, 0x20, 0x9A, 0x20, 0x9B, 0x20, -- 0x9C, 0x20, 0x9D, 0x20, 0x9E, 0x20, 0x9F, 0x20, -- 0xA0, 0x20, 0xA1, 0x20, 0xA2, 0x20, 0xA3, 0x20, -- 0xA4, 0x20, 0xA5, 0x20, 0xA6, 0x20, 0xA7, 0x20, -- 0xA8, 0x20, 0xA9, 0x20, 0xAA, 0x20, 0xAB, 0x20, -- 0xAC, 0x20, 0xAD, 0x20, 0xAE, 0x20, 0xAF, 0x20, -- 0xB0, 0x20, 0xB1, 0x20, 0xB2, 0x20, 0xB3, 0x20, -- 0xB4, 0x20, 0xB5, 0x20, 0xB6, 0x20, 0xB7, 0x20, -- 0xB8, 0x20, 0xB9, 0x20, 0xBA, 0x20, 0xBB, 0x20, -- 0xBC, 0x20, 0xBD, 0x20, 0xBE, 0x20, 0xBF, 0x20, -- 0xC0, 0x20, 0xC1, 0x20, 0xC2, 0x20, 0xC3, 0x20, -- 0xC4, 0x20, 0xC5, 0x20, 0xC6, 0x20, 0xC7, 0x20, -- 0xC8, 0x20, 0xC9, 0x20, 0xCA, 0x20, 0xCB, 0x20, -- 0xCC, 0x20, 0xCD, 0x20, 0xCE, 0x20, 0xCF, 0x20, -- 0xD0, 0x20, 0xD1, 0x20, 0xD2, 0x20, 0xD3, 0x20, -- 0xD4, 0x20, 0xD5, 0x20, 0xD6, 0x20, 0xD7, 0x20, -- 0xD8, 0x20, 0xD9, 0x20, 0xDA, 0x20, 0xDB, 0x20, -- 0xDC, 0x20, 0xDD, 0x20, 0xDE, 0x20, 0xDF, 0x20, -- 0xE0, 0x20, 0xE1, 0x20, 0xE2, 0x20, 0xE3, 0x20, -- 0xE4, 0x20, 0xE5, 0x20, 0xE6, 0x20, 0xE7, 0x20, -- 0xE8, 0x20, 0xE9, 0x20, 0xEA, 0x20, 0xEB, 0x20, -- 0xEC, 0x20, 0xED, 0x20, 0xEE, 0x20, 0xEF, 0x20, -- 0xF0, 0x20, 0xF1, 0x20, 0xF2, 0x20, 0xF3, 0x20, -- 0xF4, 0x20, 0xF5, 0x20, 0xF6, 0x20, 0xF7, 0x20, -- 0xF8, 0x20, 0xF9, 0x20, 0xFA, 0x20, 0xFB, 0x20, -- 0xFC, 0x20, 0xFD, 0x20, 0xFE, 0x20, 0xFF, 0x20, -- 0x00, 0x21, 0x01, 0x21, 0x02, 0x21, 0x03, 0x21, -- 0x04, 0x21, 0x05, 0x21, 0x06, 0x21, 0x07, 0x21, -- 0x08, 0x21, 0x09, 0x21, 0x0A, 0x21, 0x0B, 0x21, -- 0x0C, 0x21, 0x0D, 0x21, 0x0E, 0x21, 0x0F, 0x21, -- 0x10, 0x21, 0x11, 0x21, 0x12, 0x21, 0x13, 0x21, -- 0x14, 0x21, 0x15, 0x21, 0x16, 0x21, 0x17, 0x21, -- 0x18, 0x21, 0x19, 0x21, 0x1A, 0x21, 0x1B, 0x21, -- 0x1C, 0x21, 0x1D, 0x21, 0x1E, 0x21, 0x1F, 0x21, -- 0x20, 0x21, 0x21, 0x21, 0x22, 0x21, 0x23, 0x21, -- 0x24, 0x21, 0x25, 0x21, 0x26, 0x21, 0x27, 0x21, -- 0x28, 0x21, 0x29, 0x21, 0x2A, 0x21, 0x2B, 0x21, -- 0x2C, 0x21, 0x2D, 0x21, 0x2E, 0x21, 0x2F, 0x21, -- 0x30, 0x21, 0x31, 0x21, 0x32, 0x21, 0x33, 0x21, -- 0x34, 0x21, 0x35, 0x21, 0x36, 0x21, 0x37, 0x21, -- 0x38, 0x21, 0x39, 0x21, 0x3A, 0x21, 0x3B, 0x21, -- 0x3C, 0x21, 0x3D, 0x21, 0x3E, 0x21, 0x3F, 0x21, -- 0x40, 0x21, 0x41, 0x21, 0x42, 0x21, 0x43, 0x21, -- 0x44, 0x21, 0x45, 0x21, 0x46, 0x21, 0x47, 0x21, -- 0x48, 0x21, 0x49, 0x21, 0x4A, 0x21, 0x4B, 0x21, -- 0x4C, 0x21, 0x4D, 0x21, 0x32, 0x21, 0x4F, 0x21, -- 0x50, 0x21, 0x51, 0x21, 0x52, 0x21, 0x53, 0x21, -- 0x54, 0x21, 0x55, 0x21, 0x56, 0x21, 0x57, 0x21, -- 0x58, 0x21, 0x59, 0x21, 0x5A, 0x21, 0x5B, 0x21, -- 0x5C, 0x21, 0x5D, 0x21, 0x5E, 0x21, 0x5F, 0x21, -- 0x60, 0x21, 0x61, 0x21, 0x62, 0x21, 0x63, 0x21, -- 0x64, 0x21, 0x65, 0x21, 0x66, 0x21, 0x67, 0x21, -- 0x68, 0x21, 0x69, 0x21, 0x6A, 0x21, 0x6B, 0x21, -- 0x6C, 0x21, 0x6D, 0x21, 0x6E, 0x21, 0x6F, 0x21, -- 0x60, 0x21, 0x61, 0x21, 0x62, 0x21, 0x63, 0x21, -- 0x64, 0x21, 0x65, 0x21, 0x66, 0x21, 0x67, 0x21, -- 0x68, 0x21, 0x69, 0x21, 0x6A, 0x21, 0x6B, 0x21, -- 0x6C, 0x21, 0x6D, 0x21, 0x6E, 0x21, 0x6F, 0x21, -- 0x80, 0x21, 0x81, 0x21, 0x82, 0x21, 0x83, 0x21, -- 0x83, 0x21, 0xFF, 0xFF, 0x4B, 0x03, 0xB6, 0x24, -- 0xB7, 0x24, 0xB8, 0x24, 0xB9, 0x24, 0xBA, 0x24, -- 0xBB, 0x24, 0xBC, 0x24, 0xBD, 0x24, 0xBE, 0x24, -- 0xBF, 0x24, 0xC0, 0x24, 0xC1, 0x24, 0xC2, 0x24, -- 0xC3, 0x24, 0xC4, 0x24, 0xC5, 0x24, 0xC6, 0x24, -- 0xC7, 0x24, 0xC8, 0x24, 0xC9, 0x24, 0xCA, 0x24, -- 0xCB, 0x24, 0xCC, 0x24, 0xCD, 0x24, 0xCE, 0x24, -- 0xCF, 0x24, 0xFF, 0xFF, 0x46, 0x07, 0x00, 0x2C, -- 0x01, 0x2C, 0x02, 0x2C, 0x03, 0x2C, 0x04, 0x2C, -- 0x05, 0x2C, 0x06, 0x2C, 0x07, 0x2C, 0x08, 0x2C, -- 0x09, 0x2C, 0x0A, 0x2C, 0x0B, 0x2C, 0x0C, 0x2C, -- 0x0D, 0x2C, 0x0E, 0x2C, 0x0F, 0x2C, 0x10, 0x2C, -- 0x11, 0x2C, 0x12, 0x2C, 0x13, 0x2C, 0x14, 0x2C, -- 0x15, 0x2C, 0x16, 0x2C, 0x17, 0x2C, 0x18, 0x2C, -- 0x19, 0x2C, 0x1A, 0x2C, 0x1B, 0x2C, 0x1C, 0x2C, -- 0x1D, 0x2C, 0x1E, 0x2C, 0x1F, 0x2C, 0x20, 0x2C, -- 0x21, 0x2C, 0x22, 0x2C, 0x23, 0x2C, 0x24, 0x2C, -- 0x25, 0x2C, 0x26, 0x2C, 0x27, 0x2C, 0x28, 0x2C, -- 0x29, 0x2C, 0x2A, 0x2C, 0x2B, 0x2C, 0x2C, 0x2C, -- 0x2D, 0x2C, 0x2E, 0x2C, 0x5F, 0x2C, 0x60, 0x2C, -- 0x60, 0x2C, 0x62, 0x2C, 0x63, 0x2C, 0x64, 0x2C, -- 0x65, 0x2C, 0x66, 0x2C, 0x67, 0x2C, 0x67, 0x2C, -- 0x69, 0x2C, 0x69, 0x2C, 0x6B, 0x2C, 0x6B, 0x2C, -- 0x6D, 0x2C, 0x6E, 0x2C, 0x6F, 0x2C, 0x70, 0x2C, -- 0x71, 0x2C, 0x72, 0x2C, 0x73, 0x2C, 0x74, 0x2C, -- 0x75, 0x2C, 0x75, 0x2C, 0x77, 0x2C, 0x78, 0x2C, -- 0x79, 0x2C, 0x7A, 0x2C, 0x7B, 0x2C, 0x7C, 0x2C, -- 0x7D, 0x2C, 0x7E, 0x2C, 0x7F, 0x2C, 0x80, 0x2C, -- 0x80, 0x2C, 0x82, 0x2C, 0x82, 0x2C, 0x84, 0x2C, -- 0x84, 0x2C, 0x86, 0x2C, 0x86, 0x2C, 0x88, 0x2C, -- 0x88, 0x2C, 0x8A, 0x2C, 0x8A, 0x2C, 0x8C, 0x2C, -- 0x8C, 0x2C, 0x8E, 0x2C, 0x8E, 0x2C, 0x90, 0x2C, -- 0x90, 0x2C, 0x92, 0x2C, 0x92, 0x2C, 0x94, 0x2C, -- 0x94, 0x2C, 0x96, 0x2C, 0x96, 0x2C, 0x98, 0x2C, -- 0x98, 0x2C, 0x9A, 0x2C, 0x9A, 0x2C, 0x9C, 0x2C, -- 0x9C, 0x2C, 0x9E, 0x2C, 0x9E, 0x2C, 0xA0, 0x2C, -- 0xA0, 0x2C, 0xA2, 0x2C, 0xA2, 0x2C, 0xA4, 0x2C, -- 0xA4, 0x2C, 0xA6, 0x2C, 0xA6, 0x2C, 0xA8, 0x2C, -- 0xA8, 0x2C, 0xAA, 0x2C, 0xAA, 0x2C, 0xAC, 0x2C, -- 0xAC, 0x2C, 0xAE, 0x2C, 0xAE, 0x2C, 0xB0, 0x2C, -- 0xB0, 0x2C, 0xB2, 0x2C, 0xB2, 0x2C, 0xB4, 0x2C, -- 0xB4, 0x2C, 0xB6, 0x2C, 0xB6, 0x2C, 0xB8, 0x2C, -- 0xB8, 0x2C, 0xBA, 0x2C, 0xBA, 0x2C, 0xBC, 0x2C, -- 0xBC, 0x2C, 0xBE, 0x2C, 0xBE, 0x2C, 0xC0, 0x2C, -- 0xC0, 0x2C, 0xC2, 0x2C, 0xC2, 0x2C, 0xC4, 0x2C, -- 0xC4, 0x2C, 0xC6, 0x2C, 0xC6, 0x2C, 0xC8, 0x2C, -- 0xC8, 0x2C, 0xCA, 0x2C, 0xCA, 0x2C, 0xCC, 0x2C, -- 0xCC, 0x2C, 0xCE, 0x2C, 0xCE, 0x2C, 0xD0, 0x2C, -- 0xD0, 0x2C, 0xD2, 0x2C, 0xD2, 0x2C, 0xD4, 0x2C, -- 0xD4, 0x2C, 0xD6, 0x2C, 0xD6, 0x2C, 0xD8, 0x2C, -- 0xD8, 0x2C, 0xDA, 0x2C, 0xDA, 0x2C, 0xDC, 0x2C, -- 0xDC, 0x2C, 0xDE, 0x2C, 0xDE, 0x2C, 0xE0, 0x2C, -- 0xE0, 0x2C, 0xE2, 0x2C, 0xE2, 0x2C, 0xE4, 0x2C, -- 0xE5, 0x2C, 0xE6, 0x2C, 0xE7, 0x2C, 0xE8, 0x2C, -- 0xE9, 0x2C, 0xEA, 0x2C, 0xEB, 0x2C, 0xEC, 0x2C, -- 0xED, 0x2C, 0xEE, 0x2C, 0xEF, 0x2C, 0xF0, 0x2C, -- 0xF1, 0x2C, 0xF2, 0x2C, 0xF3, 0x2C, 0xF4, 0x2C, -- 0xF5, 0x2C, 0xF6, 0x2C, 0xF7, 0x2C, 0xF8, 0x2C, -- 0xF9, 0x2C, 0xFA, 0x2C, 0xFB, 0x2C, 0xFC, 0x2C, -- 0xFD, 0x2C, 0xFE, 0x2C, 0xFF, 0x2C, 0xA0, 0x10, -- 0xA1, 0x10, 0xA2, 0x10, 0xA3, 0x10, 0xA4, 0x10, -- 0xA5, 0x10, 0xA6, 0x10, 0xA7, 0x10, 0xA8, 0x10, -- 0xA9, 0x10, 0xAA, 0x10, 0xAB, 0x10, 0xAC, 0x10, -- 0xAD, 0x10, 0xAE, 0x10, 0xAF, 0x10, 0xB0, 0x10, -- 0xB1, 0x10, 0xB2, 0x10, 0xB3, 0x10, 0xB4, 0x10, -- 0xB5, 0x10, 0xB6, 0x10, 0xB7, 0x10, 0xB8, 0x10, -- 0xB9, 0x10, 0xBA, 0x10, 0xBB, 0x10, 0xBC, 0x10, -- 0xBD, 0x10, 0xBE, 0x10, 0xBF, 0x10, 0xC0, 0x10, -- 0xC1, 0x10, 0xC2, 0x10, 0xC3, 0x10, 0xC4, 0x10, -- 0xC5, 0x10, 0xFF, 0xFF, 0x1B, 0xD2, 0x21, 0xFF, -- 0x22, 0xFF, 0x23, 0xFF, 0x24, 0xFF, 0x25, 0xFF, -- 0x26, 0xFF, 0x27, 0xFF, 0x28, 0xFF, 0x29, 0xFF, -- 0x2A, 0xFF, 0x2B, 0xFF, 0x2C, 0xFF, 0x2D, 0xFF, -- 0x2E, 0xFF, 0x2F, 0xFF, 0x30, 0xFF, 0x31, 0xFF, -- 0x32, 0xFF, 0x33, 0xFF, 0x34, 0xFF, 0x35, 0xFF, -- 0x36, 0xFF, 0x37, 0xFF, 0x38, 0xFF, 0x39, 0xFF, -- 0x3A, 0xFF, 0x5B, 0xFF, 0x5C, 0xFF, 0x5D, 0xFF, -- 0x5E, 0xFF, 0x5F, 0xFF, 0x60, 0xFF, 0x61, 0xFF, -- 0x62, 0xFF, 0x63, 0xFF, 0x64, 0xFF, 0x65, 0xFF, -- 0x66, 0xFF, 0x67, 0xFF, 0x68, 0xFF, 0x69, 0xFF, -- 0x6A, 0xFF, 0x6B, 0xFF, 0x6C, 0xFF, 0x6D, 0xFF, -- 0x6E, 0xFF, 0x6F, 0xFF, 0x70, 0xFF, 0x71, 0xFF, -- 0x72, 0xFF, 0x73, 0xFF, 0x74, 0xFF, 0x75, 0xFF, -- 0x76, 0xFF, 0x77, 0xFF, 0x78, 0xFF, 0x79, 0xFF, -- 0x7A, 0xFF, 0x7B, 0xFF, 0x7C, 0xFF, 0x7D, 0xFF, -- 0x7E, 0xFF, 0x7F, 0xFF, 0x80, 0xFF, 0x81, 0xFF, -- 0x82, 0xFF, 0x83, 0xFF, 0x84, 0xFF, 0x85, 0xFF, -- 0x86, 0xFF, 0x87, 0xFF, 0x88, 0xFF, 0x89, 0xFF, -- 0x8A, 0xFF, 0x8B, 0xFF, 0x8C, 0xFF, 0x8D, 0xFF, -- 0x8E, 0xFF, 0x8F, 0xFF, 0x90, 0xFF, 0x91, 0xFF, -- 0x92, 0xFF, 0x93, 0xFF, 0x94, 0xFF, 0x95, 0xFF, -- 0x96, 0xFF, 0x97, 0xFF, 0x98, 0xFF, 0x99, 0xFF, -- 0x9A, 0xFF, 0x9B, 0xFF, 0x9C, 0xFF, 0x9D, 0xFF, -- 0x9E, 0xFF, 0x9F, 0xFF, 0xA0, 0xFF, 0xA1, 0xFF, -- 0xA2, 0xFF, 0xA3, 0xFF, 0xA4, 0xFF, 0xA5, 0xFF, -- 0xA6, 0xFF, 0xA7, 0xFF, 0xA8, 0xFF, 0xA9, 0xFF, -- 0xAA, 0xFF, 0xAB, 0xFF, 0xAC, 0xFF, 0xAD, 0xFF, -- 0xAE, 0xFF, 0xAF, 0xFF, 0xB0, 0xFF, 0xB1, 0xFF, -- 0xB2, 0xFF, 0xB3, 0xFF, 0xB4, 0xFF, 0xB5, 0xFF, -- 0xB6, 0xFF, 0xB7, 0xFF, 0xB8, 0xFF, 0xB9, 0xFF, -- 0xBA, 0xFF, 0xBB, 0xFF, 0xBC, 0xFF, 0xBD, 0xFF, -- 0xBE, 0xFF, 0xBF, 0xFF, 0xC0, 0xFF, 0xC1, 0xFF, -- 0xC2, 0xFF, 0xC3, 0xFF, 0xC4, 0xFF, 0xC5, 0xFF, -- 0xC6, 0xFF, 0xC7, 0xFF, 0xC8, 0xFF, 0xC9, 0xFF, -- 0xCA, 0xFF, 0xCB, 0xFF, 0xCC, 0xFF, 0xCD, 0xFF, -- 0xCE, 0xFF, 0xCF, 0xFF, 0xD0, 0xFF, 0xD1, 0xFF, -- 0xD2, 0xFF, 0xD3, 0xFF, 0xD4, 0xFF, 0xD5, 0xFF, -- 0xD6, 0xFF, 0xD7, 0xFF, 0xD8, 0xFF, 0xD9, 0xFF, -- 0xDA, 0xFF, 0xDB, 0xFF, 0xDC, 0xFF, 0xDD, 0xFF, -- 0xDE, 0xFF, 0xDF, 0xFF, 0xE0, 0xFF, 0xE1, 0xFF, -- 0xE2, 0xFF, 0xE3, 0xFF, 0xE4, 0xFF, 0xE5, 0xFF, -- 0xE6, 0xFF, 0xE7, 0xFF, 0xE8, 0xFF, 0xE9, 0xFF, -- 0xEA, 0xFF, 0xEB, 0xFF, 0xEC, 0xFF, 0xED, 0xFF, -- 0xEE, 0xFF, 0xEF, 0xFF, 0xF0, 0xFF, 0xF1, 0xFF, -- 0xF2, 0xFF, 0xF3, 0xFF, 0xF4, 0xFF, 0xF5, 0xFF, -- 0xF6, 0xFF, 0xF7, 0xFF, 0xF8, 0xFF, 0xF9, 0xFF, -- 0xFA, 0xFF, 0xFB, 0xFF, 0xFC, 0xFF, 0xFD, 0xFF, -- 0xFE, 0xFF, 0xFF, 0xFF --}; -diff -Nurp linux-5.6.3.orig/drivers/staging/exfat/Kconfig linux-5.6.3/drivers/staging/exfat/Kconfig ---- linux-5.6.3.orig/drivers/staging/exfat/Kconfig 2020-03-30 01:25:41.000000000 +0300 -+++ linux-5.6.3/drivers/staging/exfat/Kconfig 1970-01-01 02:00:00.000000000 +0200 -@@ -1,41 +0,0 @@ --# SPDX-License-Identifier: GPL-2.0 --config STAGING_EXFAT_FS -- tristate "exFAT fs support" -- depends on BLOCK -- select NLS -- help -- This adds support for the exFAT file system. -- --config STAGING_EXFAT_DISCARD -- bool "enable discard support" -- depends on STAGING_EXFAT_FS -- default y -- --config STAGING_EXFAT_DELAYED_SYNC -- bool "enable delayed sync" -- depends on STAGING_EXFAT_FS -- default n -- --config STAGING_EXFAT_KERNEL_DEBUG -- bool "enable kernel debug features via ioctl" -- depends on STAGING_EXFAT_FS -- default n -- --config STAGING_EXFAT_DEBUG_MSG -- bool "print debug messages" -- depends on STAGING_EXFAT_FS -- default n -- --config STAGING_EXFAT_DEFAULT_CODEPAGE -- int "Default codepage for exFAT" -- default 437 -- depends on STAGING_EXFAT_FS -- help -- This option should be set to the codepage of your exFAT filesystems. -- --config STAGING_EXFAT_DEFAULT_IOCHARSET -- string "Default iocharset for exFAT" -- default "utf8" -- depends on STAGING_EXFAT_FS -- help -- Set this to the default input/output character set you'd like exFAT to use. -diff -Nurp linux-5.6.3.orig/drivers/staging/exfat/Makefile linux-5.6.3/drivers/staging/exfat/Makefile ---- linux-5.6.3.orig/drivers/staging/exfat/Makefile 2020-03-30 01:25:41.000000000 +0300 -+++ linux-5.6.3/drivers/staging/exfat/Makefile 1970-01-01 02:00:00.000000000 +0200 -@@ -1,10 +0,0 @@ --# SPDX-License-Identifier: GPL-2.0-or-later -- --obj-$(CONFIG_STAGING_EXFAT_FS) += exfat.o -- --exfat-y := exfat_core.o \ -- exfat_super.o \ -- exfat_blkdev.o \ -- exfat_cache.o \ -- exfat_nls.o \ -- exfat_upcase.o -diff -Nurp linux-5.6.3.orig/drivers/staging/exfat/TODO linux-5.6.3/drivers/staging/exfat/TODO ---- linux-5.6.3.orig/drivers/staging/exfat/TODO 2020-03-30 01:25:41.000000000 +0300 -+++ linux-5.6.3/drivers/staging/exfat/TODO 1970-01-01 02:00:00.000000000 +0200 -@@ -1,69 +0,0 @@ --A laundry list of things that need looking at, most of which will --require more work than the average checkpatch cleanup... -- --Note that some of these entries may not be bugs - they're things --that need to be looked at, and *possibly* fixed. -- --Clean up the ffsCamelCase function names. -- --Fix (thing)->flags to not use magic numbers - multiple offenders -- --Sort out all the s32/u32/u8 nonsense - most of these should be plain int. -- --exfat_core.c - ffsReadFile - the goto err_out seem to leak a brelse(). --same for ffsWriteFile. -- --All the calls to fs_sync() need to be looked at, particularly in the --context of EXFAT_DELAYED_SYNC. Currently, if that's defined, we only --flush to disk when sync() gets called. We should be doing at least --metadata flushes at appropriate times. -- --ffsTruncateFile - if (old_size <= new_size) { --That doesn't look right. How did it ever work? Are they relying on lazy --block allocation when actual writes happen? If nothing else, it never --does the 'fid->size = new_size' and do the inode update.... -- --ffsSetAttr() is just dangling in the breeze, not wired up at all... -- --Convert global mutexes to a per-superblock mutex. -- --Right now, we load exactly one UTF-8 table. Check to see --if that plays nice with different codepage and iocharset values --for simultanous mounts of different devices -- --exfat_rmdir() checks for -EBUSY but ffsRemoveDir() doesn't return it. --In fact, there's a complete lack of -EBUSY testing anywhere. -- --There's probably a few missing checks for -EEXIST -- --check return codes of sync_dirty_buffer() -- --Why is remove_file doing a num_entries++?? -- --Double check a lot of can't-happen parameter checks (for null pointers for --things that have only one call site and can't pass a null, etc). -- --All the DEBUG stuff can probably be tossed, including the ioctl(). Either --that, or convert to a proper fault-injection system. -- --exfat_remount does exactly one thing. Fix to actually deal with remount --options, particularly handling R/O correctly. For that matter, allow --R/O mounts in the first place. -- --Figure out why the VFAT code used multi_sector_(read|write) but the --exfat code doesn't use it. The difference matters on SSDs with wear leveling. -- --exfat_fat_sync(), exfat_buf_sync(), and sync_alloc_bitmap() --aren't called anyplace.... -- --Create helper function for exfat_set_entry_time() and exfat_set_entry_type() --because it's sort of ugly to be calling the same functionn directly and --other code calling through the fs_func struc ponters... -- --clean up the remaining vol_type checks, which are of two types: --some are ?: operators with magic numbers, and the rest are places --where we're doing stuff with '.' and '..'. -- --Patches to: -- Greg Kroah-Hartman -- Valdis Kletnieks -diff -Nurp linux-5.6.3.orig/drivers/staging/Kconfig linux-5.6.3/drivers/staging/Kconfig ---- linux-5.6.3.orig/drivers/staging/Kconfig 2020-03-30 01:25:41.000000000 +0300 -+++ linux-5.6.3/drivers/staging/Kconfig 2020-04-10 13:23:50.104394573 +0300 -@@ -115,8 +115,6 @@ source "drivers/staging/kpc2000/Kconfig" - source "drivers/staging/wusbcore/Kconfig" - source "drivers/staging/uwb/Kconfig" - --source "drivers/staging/exfat/Kconfig" -- - source "drivers/staging/qlge/Kconfig" - - source "drivers/staging/hp/Kconfig" -diff -Nurp linux-5.6.3.orig/drivers/staging/Makefile linux-5.6.3/drivers/staging/Makefile ---- linux-5.6.3.orig/drivers/staging/Makefile 2020-03-30 01:25:41.000000000 +0300 -+++ linux-5.6.3/drivers/staging/Makefile 2020-04-10 13:23:55.703656045 +0300 -@@ -48,7 +48,6 @@ obj-$(CONFIG_FIELDBUS_DEV) += fieldb - obj-$(CONFIG_KPC2000) += kpc2000/ - obj-$(CONFIG_UWB) += uwb/ - obj-$(CONFIG_USB_WUSB) += wusbcore/ --obj-$(CONFIG_STAGING_EXFAT_FS) += exfat/ - obj-$(CONFIG_QLGE) += qlge/ - obj-$(CONFIG_NET_VENDOR_HP) += hp/ - obj-$(CONFIG_WFX) += wfx/ -diff -Nurp linux-5.6.3.orig/MAINTAINERS linux-5.6.3/MAINTAINERS ---- linux-5.6.3.orig/MAINTAINERS 2020-03-30 01:25:41.000000000 +0300 -+++ linux-5.6.3/MAINTAINERS 2020-04-10 13:23:25.806260135 +0300 -@@ -6304,12 +6304,6 @@ F: include/trace/events/mdio.h - F: include/uapi/linux/mdio.h - F: include/uapi/linux/mii.h - --EXFAT FILE SYSTEM --M: Valdis Kletnieks --L: linux-fsdevel@vger.kernel.org --S: Maintained --F: drivers/staging/exfat/ -- - EXT2 FILE SYSTEM - M: Jan Kara - L: linux-ext4@vger.kernel.org diff --git a/kernel/tools/perf/files/patches/mageia/fs-exfat-update-file-system-parameter-handling.patch b/kernel/tools/perf/files/patches/mageia/fs-exfat-update-file-system-parameter-handling.patch deleted file mode 100644 index 9e07cd45a6..0000000000 --- a/kernel/tools/perf/files/patches/mageia/fs-exfat-update-file-system-parameter-handling.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 9acd0d53800c55c6e2186e29b6433daf24617451 Mon Sep 17 00:00:00 2001 -From: Valdis Kletnieks -Date: Mon, 2 Mar 2020 15:21:45 +0900 -Subject: [PATCH] exfat: update file system parameter handling - -Al Viro recently reworked the way file system parameters are handled -Update super.c to work with it in linux-next 20200203. - -Signed-off-by: Valdis Kletnieks -Reviewed-by: Christoph Hellwig -Acked-by: Namjae Jeon -Signed-off-by: Al Viro ---- - fs/exfat/super.c | 28 +++++++++++----------------- - 1 file changed, 11 insertions(+), 17 deletions(-) - -diff --git a/fs/exfat/super.c b/fs/exfat/super.c -index f06e0b53e393..16ed202ef527 100644 ---- a/fs/exfat/super.c -+++ b/fs/exfat/super.c -@@ -214,7 +214,14 @@ enum { - Opt_time_offset, - }; - --static const struct fs_parameter_spec exfat_param_specs[] = { -+static const struct constant_table exfat_param_enums[] = { -+ { "continue", EXFAT_ERRORS_CONT }, -+ { "panic", EXFAT_ERRORS_PANIC }, -+ { "remount-ro", EXFAT_ERRORS_RO }, -+ {} -+}; -+ -+static const struct fs_parameter_spec exfat_parameters[] = { - fsparam_u32("uid", Opt_uid), - fsparam_u32("gid", Opt_gid), - fsparam_u32oct("umask", Opt_umask), -@@ -222,25 +229,12 @@ static const struct fs_parameter_spec exfat_param_specs[] = { - fsparam_u32oct("fmask", Opt_fmask), - fsparam_u32oct("allow_utime", Opt_allow_utime), - fsparam_string("iocharset", Opt_charset), -- fsparam_enum("errors", Opt_errors), -+ fsparam_enum("errors", Opt_errors, exfat_param_enums), - fsparam_flag("discard", Opt_discard), - fsparam_s32("time_offset", Opt_time_offset), - {} - }; - --static const struct fs_parameter_enum exfat_param_enums[] = { -- { Opt_errors, "continue", EXFAT_ERRORS_CONT }, -- { Opt_errors, "panic", EXFAT_ERRORS_PANIC }, -- { Opt_errors, "remount-ro", EXFAT_ERRORS_RO }, -- {} --}; -- --static const struct fs_parameter_description exfat_parameters = { -- .name = "exfat", -- .specs = exfat_param_specs, -- .enums = exfat_param_enums, --}; -- - static int exfat_parse_param(struct fs_context *fc, struct fs_parameter *param) - { - struct exfat_sb_info *sbi = fc->s_fs_info; -@@ -248,7 +242,7 @@ static int exfat_parse_param(struct fs_context *fc, struct fs_parameter *param) - struct fs_parse_result result; - int opt; - -- opt = fs_parse(fc, &exfat_parameters, param, &result); -+ opt = fs_parse(fc, exfat_parameters, param, &result); - if (opt < 0) - return opt; - -@@ -665,7 +659,7 @@ static struct file_system_type exfat_fs_type = { - .owner = THIS_MODULE, - .name = "exfat", - .init_fs_context = exfat_init_fs_context, -- .parameters = &exfat_parameters, -+ .parameters = exfat_parameters, - .kill_sb = kill_block_super, - .fs_flags = FS_REQUIRES_DEV, - }; --- -2.26.0 - diff --git a/kernel/tools/perf/pspec.xml b/kernel/tools/perf/pspec.xml index c2d0b3e691..e1c4e8c139 100644 --- a/kernel/tools/perf/pspec.xml +++ b/kernel/tools/perf/pspec.xml @@ -12,7 +12,7 @@ app:gui Performance analyser tool that makes full use of the Linux performance counter subsystem perf is a new tool which is used to optimize, validate and measure applications, workloads or the full system through the Linux performance counter subsystem. - https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/linux-5.6.tar.gz + https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/linux-5.7.tar.gz libunwind-devel audit-devel @@ -42,27 +42,11 @@ - patches/linux/patch-5.6.19.xz + patches/linux/patch-5.7.14.xz patches/mageia/fs-aufs-5.6.patch patches/mageia/fs-aufs-5.6-modular.patch patches/mageia/fs-aufs-5.6-fix.patch - patches/mageia/fs-exfat-remove-from-staging.patch - patches/mageia/fs-exfat-add-in-memory-and-on-disk-structures-and-heade.patch - patches/mageia/fs-exfat-add-super-block-operations.patch - patches/mageia/fs-exfat-add-inode-operations.patch - patches/mageia/fs-exfat-add-directory-operations.patch - patches/mageia/fs-exfat-add-file-operations.patch - patches/mageia/fs-exfat-add-fat-entry-operations.patch - patches/mageia/fs-exfat-add-bitmap-operations.patch - patches/mageia/fs-exfat-add-exfat-cache.patch - patches/mageia/fs-exfat-add-misc-operations.patch - patches/mageia/fs-exfat-add-nls-operations.patch - patches/mageia/fs-exfat-add-Kconfig-and-Makefile.patch - patches/mageia/fs-MAINTAINERS-add-exfat-filesystem.patch - patches/mageia/fs-exfat-update-file-system-parameter-handling.patch - patches/mageia/fs-exfat-add-module_alias_fs.patch - patches/mageia/fs-exfat-fix-discard-support.patch patches/mageia/CVE-2019-12379.patch @@ -97,6 +81,13 @@ + + 2020-08-07 + 5.7.14 + Version bump. + Idris Kalp + idriskalp@gmail.com + 2020-06-18 5.6.19