Merge tag 'exfat-for-6.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/linkin...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 1 Mar 2023 16:42:27 +0000 (08:42 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 1 Mar 2023 16:42:27 +0000 (08:42 -0800)
Pull exfat updates from Namjae Jeon:

 - Handle vendor extension and allocation entries as unrecognized benign
   secondary entries

 - Fix wrong ->i_blocks on devices with non-512 byte sector

 - Add the check to avoid returning -EIO from exfat_readdir() at current
   position exceeding the directory size

 - Fix a bug that reach the end of the directory stream at a position
   not aligned with the dentry size

 - Redefine DIR_DELETED as 0xFFFFFFF7, the bad cluster number

 - Two cleanup fixes and fix cluster leakage in error handling

* tag 'exfat-for-6.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/exfat:
  exfat: fix the newly allocated clusters are not freed in error handling
  exfat: don't print error log in normal case
  exfat: remove unneeded code from exfat_alloc_cluster()
  exfat: handle unreconized benign secondary entries
  exfat: fix inode->i_blocks for non-512 byte sector size device
  exfat: redefine DIR_DELETED as the bad cluster number
  exfat: fix reporting fs error when reading dir beyond EOF
  exfat: fix unexpected EOF while reading dir

fs/exfat/dir.c
fs/exfat/exfat_fs.h
fs/exfat/exfat_raw.h
fs/exfat/fatent.c
fs/exfat/file.c
fs/exfat/inode.c
fs/exfat/namei.c
fs/exfat/super.c

index 1dfa67f..9575741 100644 (file)
@@ -29,14 +29,15 @@ static int exfat_extract_uni_name(struct exfat_dentry *ep,
 
 }
 
-static void exfat_get_uniname_from_ext_entry(struct super_block *sb,
+static int exfat_get_uniname_from_ext_entry(struct super_block *sb,
                struct exfat_chain *p_dir, int entry, unsigned short *uniname)
 {
-       int i;
+       int i, err;
        struct exfat_entry_set_cache es;
 
-       if (exfat_get_dentry_set(&es, sb, p_dir, entry, ES_ALL_ENTRIES))
-               return;
+       err = exfat_get_dentry_set(&es, sb, p_dir, entry, ES_ALL_ENTRIES);
+       if (err)
+               return err;
 
        /*
         * First entry  : file entry
@@ -56,12 +57,13 @@ static void exfat_get_uniname_from_ext_entry(struct super_block *sb,
        }
 
        exfat_put_dentry_set(&es, false);
+       return 0;
 }
 
 /* read a directory entry from the opened directory */
 static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_entry *dir_entry)
 {
-       int i, dentries_per_clu, num_ext;
+       int i, dentries_per_clu, num_ext, err;
        unsigned int type, clu_offset, max_dentries;
        struct exfat_chain dir, clu;
        struct exfat_uni_name uni_name;
@@ -100,7 +102,7 @@ static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_ent
                        clu.dir = ei->hint_bmap.clu;
                }
 
-               while (clu_offset > 0) {
+               while (clu_offset > 0 && clu.dir != EXFAT_EOF_CLUSTER) {
                        if (exfat_get_next_cluster(sb, &(clu.dir)))
                                return -EIO;
 
@@ -146,8 +148,12 @@ static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_ent
                                        0);
 
                        *uni_name.name = 0x0;
-                       exfat_get_uniname_from_ext_entry(sb, &clu, i,
+                       err = exfat_get_uniname_from_ext_entry(sb, &clu, i,
                                uni_name.name);
+                       if (err) {
+                               brelse(bh);
+                               continue;
+                       }
                        exfat_utf16_to_nls(sb, &uni_name,
                                dir_entry->namebuf.lfn,
                                dir_entry->namebuf.lfnbuf_len);
@@ -234,10 +240,7 @@ static int exfat_iterate(struct file *file, struct dir_context *ctx)
                fake_offset = 1;
        }
 
-       if (cpos & (DENTRY_SIZE - 1)) {
-               err = -ENOENT;
-               goto unlock;
-       }
+       cpos = round_up(cpos, DENTRY_SIZE);
 
        /* name buffer should be allocated before use */
        err = exfat_alloc_namebuf(nb);
@@ -378,6 +381,12 @@ unsigned int exfat_get_entry_type(struct exfat_dentry *ep)
                        return TYPE_ACL;
                return TYPE_CRITICAL_SEC;
        }
+
+       if (ep->type == EXFAT_VENDOR_EXT)
+               return TYPE_VENDOR_EXT;
+       if (ep->type == EXFAT_VENDOR_ALLOC)
+               return TYPE_VENDOR_ALLOC;
+
        return TYPE_BENIGN_SEC;
 }
 
@@ -521,6 +530,25 @@ release_fbh:
        return ret;
 }
 
+static void exfat_free_benign_secondary_clusters(struct inode *inode,
+               struct exfat_dentry *ep)
+{
+       struct super_block *sb = inode->i_sb;
+       struct exfat_chain dir;
+       unsigned int start_clu =
+               le32_to_cpu(ep->dentry.generic_secondary.start_clu);
+       u64 size = le64_to_cpu(ep->dentry.generic_secondary.size);
+       unsigned char flags = ep->dentry.generic_secondary.flags;
+
+       if (!(flags & ALLOC_POSSIBLE) || !start_clu || !size)
+               return;
+
+       exfat_chain_set(&dir, start_clu,
+                       EXFAT_B_TO_CLU_ROUND_UP(size, EXFAT_SB(sb)),
+                       flags);
+       exfat_free_cluster(inode, &dir);
+}
+
 int exfat_init_ext_entry(struct inode *inode, struct exfat_chain *p_dir,
                int entry, int num_entries, struct exfat_uni_name *p_uniname)
 {
@@ -553,6 +581,9 @@ int exfat_init_ext_entry(struct inode *inode, struct exfat_chain *p_dir,
                if (!ep)
                        return -EIO;
 
+               if (exfat_get_entry_type(ep) & TYPE_BENIGN_SEC)
+                       exfat_free_benign_secondary_clusters(inode, ep);
+
                exfat_init_name_entry(ep, uniname);
                exfat_update_bh(bh, sync);
                brelse(bh);
@@ -576,6 +607,9 @@ int exfat_remove_entries(struct inode *inode, struct exfat_chain *p_dir,
                if (!ep)
                        return -EIO;
 
+               if (exfat_get_entry_type(ep) & TYPE_BENIGN_SEC)
+                       exfat_free_benign_secondary_clusters(inode, ep);
+
                exfat_set_entry_type(ep, TYPE_DELETED);
                exfat_update_bh(bh, IS_DIRSYNC(inode));
                brelse(bh);
@@ -744,6 +778,7 @@ enum exfat_validate_dentry_mode {
        ES_MODE_GET_STRM_ENTRY,
        ES_MODE_GET_NAME_ENTRY,
        ES_MODE_GET_CRITICAL_SEC_ENTRY,
+       ES_MODE_GET_BENIGN_SEC_ENTRY,
 };
 
 static bool exfat_validate_entry(unsigned int type,
@@ -757,36 +792,33 @@ static bool exfat_validate_entry(unsigned int type,
                if  (type != TYPE_FILE && type != TYPE_DIR)
                        return false;
                *mode = ES_MODE_GET_FILE_ENTRY;
-               return true;
+               break;
        case ES_MODE_GET_FILE_ENTRY:
                if (type != TYPE_STREAM)
                        return false;
                *mode = ES_MODE_GET_STRM_ENTRY;
-               return true;
+               break;
        case ES_MODE_GET_STRM_ENTRY:
                if (type != TYPE_EXTEND)
                        return false;
                *mode = ES_MODE_GET_NAME_ENTRY;
-               return true;
+               break;
        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)
+               if (type & TYPE_BENIGN_SEC)
+                       *mode = ES_MODE_GET_BENIGN_SEC_ENTRY;
+               else if (type != TYPE_EXTEND)
                        return false;
-               if ((type & TYPE_CRITICAL_SEC) != TYPE_CRITICAL_SEC)
+               break;
+       case ES_MODE_GET_BENIGN_SEC_ENTRY:
+               /* Assume unreconized benign secondary entry */
+               if (!(type & TYPE_BENIGN_SEC))
                        return false;
-               return true;
+               break;
        default:
-               WARN_ON_ONCE(1);
                return false;
        }
+
+       return true;
 }
 
 struct exfat_dentry *exfat_get_dentry_cached(
@@ -1167,10 +1199,8 @@ int exfat_count_ext_entries(struct super_block *sb, struct exfat_chain *p_dir,
 
                type = exfat_get_entry_type(ext_ep);
                brelse(bh);
-               if (type == TYPE_EXTEND || type == TYPE_STREAM)
+               if (type & TYPE_CRITICAL_SEC || type & TYPE_BENIGN_SEC)
                        count++;
-               else
-                       break;
        }
        return count;
 }
index 1bf16ab..729ada9 100644 (file)
@@ -50,7 +50,7 @@ enum {
 #define ES_IDX_LAST_FILENAME(name_len) \
        (ES_IDX_FIRST_FILENAME + EXFAT_FILENAME_ENTRY_NUM(name_len) - 1)
 
-#define DIR_DELETED            0xFFFF0321
+#define DIR_DELETED            0xFFFFFFF7
 
 /* type values */
 #define TYPE_UNUSED            0x0000
@@ -71,6 +71,8 @@ enum {
 #define TYPE_PADDING           0x0402
 #define TYPE_ACLTAB            0x0403
 #define TYPE_BENIGN_SEC                0x0800
+#define TYPE_VENDOR_EXT                0x0801
+#define TYPE_VENDOR_ALLOC      0x0802
 
 #define MAX_CHARSET_SIZE       6 /* max size of multi-byte character */
 #define MAX_NAME_LENGTH                255 /* max len of file name excluding NULL */
index 7f39b1c..0ece2e4 100644 (file)
@@ -27,6 +27,7 @@
        ((sbi)->num_clusters - EXFAT_RESERVED_CLUSTERS)
 
 /* AllocationPossible and NoFatChain field in GeneralSecondaryFlags Field */
+#define ALLOC_POSSIBLE         0x01
 #define ALLOC_FAT_CHAIN                0x01
 #define ALLOC_NO_FAT_CHAIN     0x03
 
@@ -50,6 +51,8 @@
 #define EXFAT_STREAM           0xC0    /* stream entry */
 #define EXFAT_NAME             0xC1    /* file name entry */
 #define EXFAT_ACL              0xC2    /* stream entry */
+#define EXFAT_VENDOR_EXT       0xE0    /* vendor extension entry */
+#define EXFAT_VENDOR_ALLOC     0xE1    /* vendor allocation entry */
 
 #define IS_EXFAT_CRITICAL_PRI(x)       (x < 0xA0)
 #define IS_EXFAT_BENIGN_PRI(x)         (x < 0xC0)
@@ -155,6 +158,24 @@ struct exfat_dentry {
                        __le32 start_clu;
                        __le64 size;
                } __packed upcase; /* up-case table directory entry */
+               struct {
+                       __u8 flags;
+                       __u8 vendor_guid[16];
+                       __u8 vendor_defined[14];
+               } __packed vendor_ext; /* vendor extension directory entry */
+               struct {
+                       __u8 flags;
+                       __u8 vendor_guid[16];
+                       __u8 vendor_defined[2];
+                       __le32 start_clu;
+                       __le64 size;
+               } __packed vendor_alloc; /* vendor allocation directory entry */
+               struct {
+                       __u8 flags;
+                       __u8 custom_defined[18];
+                       __le32 start_clu;
+                       __le64 size;
+               } __packed generic_secondary; /* generic secondary directory entry */
        } __packed dentry;
 } __packed;
 
index 41ae4cc..56b870d 100644 (file)
@@ -307,7 +307,7 @@ int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc,
                struct exfat_chain *p_chain, bool sync_bmap)
 {
        int ret = -ENOSPC;
-       unsigned int num_clusters = 0, total_cnt;
+       unsigned int 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);
@@ -344,17 +344,11 @@ int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc,
 
        /* check cluster validation */
        if (!is_valid_cluster(sbi, hint_clu)) {
-               exfat_err(sb, "hint_cluster is invalid (%u)",
-                       hint_clu);
+               if (hint_clu != sbi->num_clusters)
+                       exfat_err(sb, "hint_cluster is invalid (%u), rewind to the first cluster",
+                                       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)) {
-                               ret = -EIO;
-                               goto unlock;
-                       }
-                       p_chain->flags = ALLOC_FAT_CHAIN;
-               }
+               p_chain->flags = ALLOC_FAT_CHAIN;
        }
 
        p_chain->dir = EXFAT_EOF_CLUSTER;
@@ -364,7 +358,7 @@ int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc,
                if (new_clu != hint_clu &&
                    p_chain->flags == ALLOC_NO_FAT_CHAIN) {
                        if (exfat_chain_cont_cluster(sb, p_chain->dir,
-                                       num_clusters)) {
+                                       p_chain->size)) {
                                ret = -EIO;
                                goto free_cluster;
                        }
@@ -377,8 +371,6 @@ int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc,
                        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)) {
@@ -395,13 +387,14 @@ int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc,
                                goto free_cluster;
                        }
                }
+               p_chain->size++;
+
                last_clu = new_clu;
 
-               if (--num_alloc == 0) {
+               if (p_chain->size == num_alloc) {
                        sbi->clu_srch_ptr = hint_clu;
-                       sbi->used_clusters += num_clusters;
+                       sbi->used_clusters += num_alloc;
 
-                       p_chain->size += num_clusters;
                        mutex_unlock(&sbi->bitmap_lock);
                        return 0;
                }
@@ -412,7 +405,7 @@ int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc,
 
                        if (p_chain->flags == ALLOC_NO_FAT_CHAIN) {
                                if (exfat_chain_cont_cluster(sb, p_chain->dir,
-                                               num_clusters)) {
+                                               p_chain->size)) {
                                        ret = -EIO;
                                        goto free_cluster;
                                }
@@ -421,8 +414,7 @@ int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc,
                }
        }
 free_cluster:
-       if (num_clusters)
-               __exfat_free_cluster(inode, p_chain);
+       __exfat_free_cluster(inode, p_chain);
 unlock:
        mutex_unlock(&sbi->bitmap_lock);
        return ret;
index 1fdb0a6..e99183a 100644 (file)
@@ -209,8 +209,7 @@ void exfat_truncate(struct inode *inode)
        if (err)
                goto write_size;
 
-       inode->i_blocks = round_up(i_size_read(inode), sbi->cluster_size) >>
-                               inode->i_blkbits;
+       inode->i_blocks = round_up(i_size_read(inode), sbi->cluster_size) >> 9;
 write_size:
        aligned_size = i_size_read(inode);
        if (aligned_size & (blocksize - 1)) {
index 5b644cb..481dd33 100644 (file)
@@ -220,8 +220,7 @@ static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset,
                num_clusters += num_to_be_allocated;
                *clu = new_clu.dir;
 
-               inode->i_blocks +=
-                       num_to_be_allocated << sbi->sect_per_clus_bits;
+               inode->i_blocks += EXFAT_CLU_TO_B(num_to_be_allocated, sbi) >> 9;
 
                /*
                 * Move *clu pointer along FAT chains (hole care) because the
@@ -576,8 +575,7 @@ static int exfat_fill_inode(struct inode *inode, struct exfat_dir_entry *info)
 
        exfat_save_attr(inode, info->attr);
 
-       inode->i_blocks = round_up(i_size_read(inode), sbi->cluster_size) >>
-                               inode->i_blkbits;
+       inode->i_blocks = round_up(i_size_read(inode), sbi->cluster_size) >> 9;
        inode->i_mtime = info->mtime;
        inode->i_ctime = info->mtime;
        ei->i_crtime = info->crtime;
index 02aab4c..e0ff9d1 100644 (file)
@@ -396,7 +396,7 @@ static int exfat_find_empty_entry(struct inode *inode,
                ei->i_size_ondisk += sbi->cluster_size;
                ei->i_size_aligned += sbi->cluster_size;
                ei->flags = p_dir->flags;
-               inode->i_blocks += 1 << sbi->sect_per_clus_bits;
+               inode->i_blocks += sbi->cluster_size >> 9;
        }
 
        return dentry;
index 35f0305..8c32460 100644 (file)
@@ -373,8 +373,7 @@ static int exfat_read_root(struct inode *inode)
        inode->i_op = &exfat_dir_inode_operations;
        inode->i_fop = &exfat_dir_operations;
 
-       inode->i_blocks = round_up(i_size_read(inode), sbi->cluster_size) >>
-                               inode->i_blkbits;
+       inode->i_blocks = round_up(i_size_read(inode), sbi->cluster_size) >> 9;
        ei->i_pos = ((loff_t)sbi->root_dir << 32) | 0xffffffff;
        ei->i_size_aligned = i_size_read(inode);
        ei->i_size_ondisk = i_size_read(inode);