2020-03-02 06:28:14

by Namjae Jeon

[permalink] [raw]
Subject: [PATCH v14 00/14] add the latest exfat driver

This adds the latest Samsung exfat driver to fs/exfat. This is an
implementation of the Microsoft exFAT specification. Previous versions
of this shipped with millions of Android phones, and a random previous
snaphot has been merged in drivers/staging/.

Compared to the sdfat driver shipped on the phones the following changes
have been made:

- the support for vfat has been removed as that is already supported
by fs/fat
- driver has been renamed to exfat
- the code has been refactored and clean up to fully integrate into
the upstream Linux version and follow the Linux coding style
- metadata operations like create, lookup and readdir have been further
optimized
- various major and minor bugs have been fixed

We plan to treat this version as the future upstream for the code base
once merged, and all new features and bug fixes will go upstream first.

v14:
- update file system parameter handling.

v13:
- rcu-delay unloading nls, freeing upcase table and sbi.
- Switch to ->free_inode().
- Push rcu_barrier() from deactivate_locked_super() to filesystems.
- Remove unused variables in exfat_sb_info structure.

v12:
- Merge the #12 patch into the #11 patch.
- Remove an incorrect comment about time_offset mount option.

v11:
- Use current_time instead of ktime_get_real_ts64.
- Add i_crtime in exfat inode.
- Drop the clamping min/max timestamp.
- Merge exfat_init_file_entry into exfat_init_dir_entry.
- Initialize the msec fields in exfat_init_dir_entry.
- Change timestamps written to disk always get stored in UTC instead of
active timezone.
- Update EXFAT_DEFAULT_IOCHARSET description in Kconfig.
- exfat_get/set_entry_time() take a time_ms argument.

v10:
- Make PBR structures as packed structure.
- Fix build error on 32 bit system.
- Change L suffix of UNIX_SECS_2108 macro with LL suffix to work
on both 32/64bit system.
- Rework exfat time handling.
- Don't warp exfat specification URLs.
- Add _FS suffix to config name.
- Remove case_sensitive mount option.
- iocharset=utf8 mount option work as utf8 option.
- Rename the misleading nls names to corresponding ones.
- Fix wrong header guard name of exfat_fs.h.
- Remove the unneeded braces of macros in exfat_fs.h.
- Move the ondisk values to exfat_raw.h
- Put the operators at the previous line in exfat_cluster_to_sector().
- Braces of EXFAT_DELETE macro would outside the ~.
- Directly use exfat dentry field name.
- Add EXFAT_CLUSTERS_UNTRACKED macro.
- Remove both sets of inner braces in exfat_set_vol_flags().
- Replace is_reserved_cluster() with an explicit check
for EXFAT_EOF_CLUSTER.
- Initialize superblock s_time_gran/max/min.
- Clean-up exfat_bmap and exfat_get_block().
- Fix wrong boundlen to avoid potential buffer overflow
in exfat_convert_char_to_ucs2().
- Process length value as 1 when conversion is failed.
- Replace union exfat_timezone with masking the valid bit.
- Change exfat_cmp_uniname() with exfat_uniname_ncmp().
- Remove struct exfat_timestamp.
- Add atime update support.
- Add time_offset mount option.
- Remove unneeded CLUSTER_32 macro.
- Process utf16 surrogate pair as one character.
- Rename MUST_ZERO_LEN to PBR64_RESERVED_LEN.
- Simplify is_exfat function by just using memchr_inv().
- Remove __exfat_init_name_hash.
- Remove exfat_striptail_len.
- Split dentry ops for the utf8 vs non-utf8 cases.

v9:
- Add support time zone.
- Fix data past EOF resulting from fsx testsuite.
- Remove obsolete comments in __exfat_resolve_path().
- Remove unused file attributes macros.
- Remove unneeded #if BITS_PER_LONG.

v8:
- Rearrange the function grouping in exfat_fs.h
(exfat_count_dir_entries, exfat_get_dentry, exfat_get_dentry_set,
exfat_find_location).
- Mark exfat_extract_uni_name(), exfat_get_uniname_from_ext_entry() and
exfat_mirror_bh() as static.

v7:
- Add the helpers macros for bitmap and fat entry to improve readability.
- Rename exfat_test_bitmap to exfat_find_free_bitmap.
- Merge exfat_get_num_entries into exfat_calc_num_entries.
- Add EXFAT_DATA_CLUSTERS and EXFAT_RESERVED_CLUSTERS macro.
- Add the macros for EXFAT BIOS block(JUMP_BOOT_LEN, OEM_NAME_LEN,
MUST_BE_ZERO_LEN).
- Add the macros for EXFAT entry type (IS_EXFAT_CRITICAL_PRI,
IS_EXFAT_BENIGN_PRI, IS_EXFAT_CRITICAL_SEC).
- Add EXFAT_FILE_NAME_LEN macro.
- Change the data type of is_dir with bool in __exfat_write_inode().
- Change the data type of sync with bool in exfat_set_vol_flags().
- Merge __exfat_set_vol_flags into exfat_set_vol_flags.
- Fix wrong statfs->f_namelen.

v6:
- Fix always false comparison due to limited range of allow_utime's data
type.
- Move bh into loop in exfat_find_dir_entry().
- Move entry_uniname and unichar variables into
an if "entry_type == TYPE_EXTEND" branch.

v5:
- Remove a blank line between the message and the error code in
exfat_load_upcase_table.
- Move brelse to the end of the while loop and rename release_bh label
to free_table in exfat_load_upcase_table.
- Move an error code assignment after a failed function call.
- Rename labels and directly return instead of goto.
- Improve the exception handling in exfat_get_dentry_set().
- Remove ->d_time leftover.
- fix boolreturn.cocci warnings.

v4:
- Declare ALLOC_FAT_CHAIN and ALLOC_NO_FAT_CHAIN macros.
- Rename labels with proper name.
- Remove blank lines.
- Remove pointer check for bh.
- Move ep into loop in exfat_load_bitmap().
- Replace READ/WRITE_ONCE() with test_and_clear_bit() and set_bit().
- Change exfat_allow_set_time return type with bool.

v3:
- fix wrong sbi->s_dirt set.

v2:
- Check the bitmap count up to the total clusters.
- Rename goto labels in several places.
- Change time mode type with enumeration.
- Directly return error instead of goto at first error check.
- Combine seq_printf calls into a single one.

Namjae Jeon (13):
exfat: add in-memory and on-disk structures and headers
exfat: add super block operations
exfat: add inode operations
exfat: add directory operations
exfat: add file operations
exfat: add fat entry operations
exfat: add bitmap operations
exfat: add exfat cache
exfat: add misc operations
exfat: add nls operations
exfat: add Kconfig and Makefile
MAINTAINERS: add exfat filesystem
staging: exfat: make staging/exfat and fs/exfat mutually exclusive

Valdis Kletnieks (1):
exfat: update file system parameter handling

MAINTAINERS | 7 +
drivers/staging/exfat/Kconfig | 2 +-
fs/Kconfig | 3 +-
fs/Makefile | 1 +
fs/exfat/Kconfig | 21 +
fs/exfat/Makefile | 8 +
fs/exfat/balloc.c | 280 +++++++
fs/exfat/cache.c | 325 ++++++++
fs/exfat/dir.c | 1238 ++++++++++++++++++++++++++++
fs/exfat/exfat_fs.h | 519 ++++++++++++
fs/exfat/exfat_raw.h | 184 +++++
fs/exfat/fatent.c | 463 +++++++++++
fs/exfat/file.c | 360 ++++++++
fs/exfat/inode.c | 671 +++++++++++++++
fs/exfat/misc.c | 163 ++++
fs/exfat/namei.c | 1448 +++++++++++++++++++++++++++++++++
fs/exfat/nls.c | 831 +++++++++++++++++++
fs/exfat/super.c | 722 ++++++++++++++++
18 files changed, 7244 insertions(+), 2 deletions(-)
create mode 100644 fs/exfat/Kconfig
create mode 100644 fs/exfat/Makefile
create mode 100644 fs/exfat/balloc.c
create mode 100644 fs/exfat/cache.c
create mode 100644 fs/exfat/dir.c
create mode 100644 fs/exfat/exfat_fs.h
create mode 100644 fs/exfat/exfat_raw.h
create mode 100644 fs/exfat/fatent.c
create mode 100644 fs/exfat/file.c
create mode 100644 fs/exfat/inode.c
create mode 100644 fs/exfat/misc.c
create mode 100644 fs/exfat/namei.c
create mode 100644 fs/exfat/nls.c
create mode 100644 fs/exfat/super.c

--
2.17.1


2020-03-02 06:28:14

by Namjae Jeon

[permalink] [raw]
Subject: [PATCH v14 07/14] exfat: add bitmap operations

This adds the implementation of bitmap operations for exfat.

Signed-off-by: Namjae Jeon <[email protected]>
Signed-off-by: Sungjong Seo <[email protected]>
Reviewed-by: Pali Roh?r <[email protected]>
Reviewed-by: Christoph Hellwig <[email protected]>
---
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 <linux/blkdev.h>
+#include <linux/slab.h>
+#include <linux/buffer_head.h>
+
+#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.17.1

2020-03-02 06:28:19

by Namjae Jeon

[permalink] [raw]
Subject: [PATCH v14 11/14] exfat: add Kconfig and Makefile

This adds the Kconfig and Makefile for exfat.

Signed-off-by: Namjae Jeon <[email protected]>
Signed-off-by: Sungjong Seo <[email protected]>
Reviewed-by: Pali Roh?r <[email protected]>
Reviewed-by: Christoph Hellwig <[email protected]>
---
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.17.1

2020-03-02 06:28:44

by Namjae Jeon

[permalink] [raw]
Subject: [PATCH v14 06/14] exfat: add fat entry operations

This adds the implementation of fat entry operations for exfat.

Signed-off-by: Namjae Jeon <[email protected]>
Signed-off-by: Sungjong Seo <[email protected]>
Reviewed-by: Pali Roh?r <[email protected]>
Reviewed-by: Christoph Hellwig <[email protected]>
---
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 <linux/slab.h>
+#include <asm/unaligned.h>
+#include <linux/buffer_head.h>
+
+#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.17.1

2020-03-05 15:54:01

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH v14 00/14] add the latest exfat driver

Al,

are you going to pick this up, or should Namjae go through the pains
of setting up his own git tree to feed to Linus?

On Mon, Mar 02, 2020 at 03:21:31PM +0900, Namjae Jeon wrote:
> This adds the latest Samsung exfat driver to fs/exfat. This is an
> implementation of the Microsoft exFAT specification. Previous versions
> of this shipped with millions of Android phones, and a random previous
> snaphot has been merged in drivers/staging/.
>
> Compared to the sdfat driver shipped on the phones the following changes
> have been made:
>
> - the support for vfat has been removed as that is already supported
> by fs/fat
> - driver has been renamed to exfat
> - the code has been refactored and clean up to fully integrate into
> the upstream Linux version and follow the Linux coding style
> - metadata operations like create, lookup and readdir have been further
> optimized
> - various major and minor bugs have been fixed
>
> We plan to treat this version as the future upstream for the code base
> once merged, and all new features and bug fixes will go upstream first.
>
> v14:
> - update file system parameter handling.
>
> v13:
> - rcu-delay unloading nls, freeing upcase table and sbi.
> - Switch to ->free_inode().
> - Push rcu_barrier() from deactivate_locked_super() to filesystems.
> - Remove unused variables in exfat_sb_info structure.
>
> v12:
> - Merge the #12 patch into the #11 patch.
> - Remove an incorrect comment about time_offset mount option.
>
> v11:
> - Use current_time instead of ktime_get_real_ts64.
> - Add i_crtime in exfat inode.
> - Drop the clamping min/max timestamp.
> - Merge exfat_init_file_entry into exfat_init_dir_entry.
> - Initialize the msec fields in exfat_init_dir_entry.
> - Change timestamps written to disk always get stored in UTC instead of
> active timezone.
> - Update EXFAT_DEFAULT_IOCHARSET description in Kconfig.
> - exfat_get/set_entry_time() take a time_ms argument.
>
> v10:
> - Make PBR structures as packed structure.
> - Fix build error on 32 bit system.
> - Change L suffix of UNIX_SECS_2108 macro with LL suffix to work
> on both 32/64bit system.
> - Rework exfat time handling.
> - Don't warp exfat specification URLs.
> - Add _FS suffix to config name.
> - Remove case_sensitive mount option.
> - iocharset=utf8 mount option work as utf8 option.
> - Rename the misleading nls names to corresponding ones.
> - Fix wrong header guard name of exfat_fs.h.
> - Remove the unneeded braces of macros in exfat_fs.h.
> - Move the ondisk values to exfat_raw.h
> - Put the operators at the previous line in exfat_cluster_to_sector().
> - Braces of EXFAT_DELETE macro would outside the ~.
> - Directly use exfat dentry field name.
> - Add EXFAT_CLUSTERS_UNTRACKED macro.
> - Remove both sets of inner braces in exfat_set_vol_flags().
> - Replace is_reserved_cluster() with an explicit check
> for EXFAT_EOF_CLUSTER.
> - Initialize superblock s_time_gran/max/min.
> - Clean-up exfat_bmap and exfat_get_block().
> - Fix wrong boundlen to avoid potential buffer overflow
> in exfat_convert_char_to_ucs2().
> - Process length value as 1 when conversion is failed.
> - Replace union exfat_timezone with masking the valid bit.
> - Change exfat_cmp_uniname() with exfat_uniname_ncmp().
> - Remove struct exfat_timestamp.
> - Add atime update support.
> - Add time_offset mount option.
> - Remove unneeded CLUSTER_32 macro.
> - Process utf16 surrogate pair as one character.
> - Rename MUST_ZERO_LEN to PBR64_RESERVED_LEN.
> - Simplify is_exfat function by just using memchr_inv().
> - Remove __exfat_init_name_hash.
> - Remove exfat_striptail_len.
> - Split dentry ops for the utf8 vs non-utf8 cases.
>
> v9:
> - Add support time zone.
> - Fix data past EOF resulting from fsx testsuite.
> - Remove obsolete comments in __exfat_resolve_path().
> - Remove unused file attributes macros.
> - Remove unneeded #if BITS_PER_LONG.
>
> v8:
> - Rearrange the function grouping in exfat_fs.h
> (exfat_count_dir_entries, exfat_get_dentry, exfat_get_dentry_set,
> exfat_find_location).
> - Mark exfat_extract_uni_name(), exfat_get_uniname_from_ext_entry() and
> exfat_mirror_bh() as static.
>
> v7:
> - Add the helpers macros for bitmap and fat entry to improve readability.
> - Rename exfat_test_bitmap to exfat_find_free_bitmap.
> - Merge exfat_get_num_entries into exfat_calc_num_entries.
> - Add EXFAT_DATA_CLUSTERS and EXFAT_RESERVED_CLUSTERS macro.
> - Add the macros for EXFAT BIOS block(JUMP_BOOT_LEN, OEM_NAME_LEN,
> MUST_BE_ZERO_LEN).
> - Add the macros for EXFAT entry type (IS_EXFAT_CRITICAL_PRI,
> IS_EXFAT_BENIGN_PRI, IS_EXFAT_CRITICAL_SEC).
> - Add EXFAT_FILE_NAME_LEN macro.
> - Change the data type of is_dir with bool in __exfat_write_inode().
> - Change the data type of sync with bool in exfat_set_vol_flags().
> - Merge __exfat_set_vol_flags into exfat_set_vol_flags.
> - Fix wrong statfs->f_namelen.
>
> v6:
> - Fix always false comparison due to limited range of allow_utime's data
> type.
> - Move bh into loop in exfat_find_dir_entry().
> - Move entry_uniname and unichar variables into
> an if "entry_type == TYPE_EXTEND" branch.
>
> v5:
> - Remove a blank line between the message and the error code in
> exfat_load_upcase_table.
> - Move brelse to the end of the while loop and rename release_bh label
> to free_table in exfat_load_upcase_table.
> - Move an error code assignment after a failed function call.
> - Rename labels and directly return instead of goto.
> - Improve the exception handling in exfat_get_dentry_set().
> - Remove ->d_time leftover.
> - fix boolreturn.cocci warnings.
>
> v4:
> - Declare ALLOC_FAT_CHAIN and ALLOC_NO_FAT_CHAIN macros.
> - Rename labels with proper name.
> - Remove blank lines.
> - Remove pointer check for bh.
> - Move ep into loop in exfat_load_bitmap().
> - Replace READ/WRITE_ONCE() with test_and_clear_bit() and set_bit().
> - Change exfat_allow_set_time return type with bool.
>
> v3:
> - fix wrong sbi->s_dirt set.
>
> v2:
> - Check the bitmap count up to the total clusters.
> - Rename goto labels in several places.
> - Change time mode type with enumeration.
> - Directly return error instead of goto at first error check.
> - Combine seq_printf calls into a single one.
>
> Namjae Jeon (13):
> exfat: add in-memory and on-disk structures and headers
> exfat: add super block operations
> exfat: add inode operations
> exfat: add directory operations
> exfat: add file operations
> exfat: add fat entry operations
> exfat: add bitmap operations
> exfat: add exfat cache
> exfat: add misc operations
> exfat: add nls operations
> exfat: add Kconfig and Makefile
> MAINTAINERS: add exfat filesystem
> staging: exfat: make staging/exfat and fs/exfat mutually exclusive
>
> Valdis Kletnieks (1):
> exfat: update file system parameter handling
>
> MAINTAINERS | 7 +
> drivers/staging/exfat/Kconfig | 2 +-
> fs/Kconfig | 3 +-
> fs/Makefile | 1 +
> fs/exfat/Kconfig | 21 +
> fs/exfat/Makefile | 8 +
> fs/exfat/balloc.c | 280 +++++++
> fs/exfat/cache.c | 325 ++++++++
> fs/exfat/dir.c | 1238 ++++++++++++++++++++++++++++
> fs/exfat/exfat_fs.h | 519 ++++++++++++
> fs/exfat/exfat_raw.h | 184 +++++
> fs/exfat/fatent.c | 463 +++++++++++
> fs/exfat/file.c | 360 ++++++++
> fs/exfat/inode.c | 671 +++++++++++++++
> fs/exfat/misc.c | 163 ++++
> fs/exfat/namei.c | 1448 +++++++++++++++++++++++++++++++++
> fs/exfat/nls.c | 831 +++++++++++++++++++
> fs/exfat/super.c | 722 ++++++++++++++++
> 18 files changed, 7244 insertions(+), 2 deletions(-)
> create mode 100644 fs/exfat/Kconfig
> create mode 100644 fs/exfat/Makefile
> create mode 100644 fs/exfat/balloc.c
> create mode 100644 fs/exfat/cache.c
> create mode 100644 fs/exfat/dir.c
> create mode 100644 fs/exfat/exfat_fs.h
> create mode 100644 fs/exfat/exfat_raw.h
> create mode 100644 fs/exfat/fatent.c
> create mode 100644 fs/exfat/file.c
> create mode 100644 fs/exfat/inode.c
> create mode 100644 fs/exfat/misc.c
> create mode 100644 fs/exfat/namei.c
> create mode 100644 fs/exfat/nls.c
> create mode 100644 fs/exfat/super.c
>
> --
> 2.17.1
---end quoted text---

2020-03-05 16:14:27

by Al Viro

[permalink] [raw]
Subject: Re: [PATCH v14 00/14] add the latest exfat driver

On Thu, Mar 05, 2020 at 04:53:24PM +0100, Christoph Hellwig wrote:
> Al,
>
> are you going to pick this up, or should Namjae go through the pains
> of setting up his own git tree to feed to Linus?

I'm putting together #for-next right now, that'll go there.

Al, cursing devpts, audit, ima, fsnotify and a lot of other unsavory things
right now...

2020-03-06 12:13:53

by Namjae Jeon

[permalink] [raw]
Subject: Re: [PATCH v14 00/14] add the latest exfat driver

2020-03-06 1:12 GMT+09:00, Al Viro <[email protected]>:
> On Thu, Mar 05, 2020 at 04:53:24PM +0100, Christoph Hellwig wrote:
>> Al,
>>
>> are you going to pick this up, or should Namjae go through the pains
>> of setting up his own git tree to feed to Linus?
>
> I'm putting together #for-next right now, that'll go there.
Great, thank you!

>
> Al, cursing devpts, audit, ima, fsnotify and a lot of other unsavory things
> right now...
>

2020-03-09 12:02:46

by Markus Elfring

[permalink] [raw]
Subject: Re: [PATCH v14 00/14] add the latest exfat driver

> v14:
> - update file system parameter handling.

How long will it take until further implementation details will get
any more software development attention?

Regards,
Markus

2020-04-06 07:30:07

by Geert Uytterhoeven

[permalink] [raw]
Subject: Re: [PATCH v14 11/14] exfat: add Kconfig and Makefile

Hi Namjae,

On Mon, Mar 2, 2020 at 7:28 AM Namjae Jeon <[email protected]> wrote:
> This adds the Kconfig and Makefile for exfat.
>
> Signed-off-by: Namjae Jeon <[email protected]>
> Signed-off-by: Sungjong Seo <[email protected]>
> Reviewed-by: Pali Rohár <[email protected]>
> Reviewed-by: Christoph Hellwig <[email protected]>

This is now commit b9d1e2e6265f5dc2 ("exfat: add Kconfig and Makefile").

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

exFAT

> + the "iocharset" mount option for exFAT filesystems.

I think the above paragraph should be reworded.
I tried to do it myself:

Set this to the default input/output character set to use for
converting between the encoding that is used for user visible
filenames, and the UTF-16 character set that the exFAT filesystem
uses. This can be overridden with the "iocharset" mount option for
the exFAT filesystems.

but then I got puzzled by the _3_ encodings that are part of it:
1. the default input/output character set to use for conversion,
2. encoding that is used for user visible filenames,
3. UTF-16 character set that the exFAT filesystem uses.
I assume 1 == 2, but there may be more to it?

Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds

2020-04-06 07:36:14

by Pali Rohár

[permalink] [raw]
Subject: Re: [PATCH v14 11/14] exfat: add Kconfig and Makefile

On Monday 06 April 2020 09:27:01 Geert Uytterhoeven wrote:
> I tried to do it myself:
>
> Set this to the default input/output character set to use for
> converting between the encoding that is used for user visible
> filenames, and the UTF-16 character set that the exFAT filesystem
> uses. This can be overridden with the "iocharset" mount option for
> the exFAT filesystems.
>
> but then I got puzzled by the _3_ encodings that are part of it:
> 1. the default input/output character set to use for conversion,
> 2. encoding that is used for user visible filenames,
> 3. UTF-16 character set that the exFAT filesystem uses.
> I assume 1 == 2, but there may be more to it?

It is encoding between user visible filenames in VFS and UTF-16, so 1 == 2.