diff options
-rw-r--r-- | MAINTAINERS | 1 | ||||
-rw-r--r-- | fs/exfat/exfat_fs.h | 19 | ||||
-rw-r--r-- | fs/exfat/fatent.c | 2 | ||||
-rw-r--r-- | fs/exfat/file.c | 82 | ||||
-rw-r--r-- | fs/exfat/inode.c | 41 | ||||
-rw-r--r-- | fs/exfat/misc.c | 17 | ||||
-rw-r--r-- | fs/exfat/namei.c | 22 | ||||
-rw-r--r-- | fs/exfat/nls.c | 4 | ||||
-rw-r--r-- | fs/exfat/super.c | 4 |
9 files changed, 54 insertions, 138 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 868bbf31603d..905567a122d1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7690,6 +7690,7 @@ M: Namjae Jeon <linkinjeon@kernel.org> M: Sungjong Seo <sj1557.seo@samsung.com> L: linux-fsdevel@vger.kernel.org S: Maintained +T: git git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/exfat.git F: fs/exfat/ EXT2 FILE SYSTEM diff --git a/fs/exfat/exfat_fs.h b/fs/exfat/exfat_fs.h index 4a7a2308eb72..a8f8eee4937c 100644 --- a/fs/exfat/exfat_fs.h +++ b/fs/exfat/exfat_fs.h @@ -27,9 +27,9 @@ enum exfat_error_mode { * 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 */ + NLS_NAME_NO_LOSSY = 0, /* no lossy */ + NLS_NAME_LOSSY = 1 << 0, /* just detected incorrect filename(s) */ + NLS_NAME_OVERLEN = 1 << 1, /* the length is over than its limit */ }; #define EXFAT_HASH_BITS 8 @@ -483,6 +483,7 @@ struct inode *exfat_build_inode(struct super_block *sb, 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, int sync); 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); @@ -508,14 +509,16 @@ void __exfat_fs_error(struct super_block *sb, int report, const char *fmt, ...) #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; + +/* expand to pr_*() with prefix */ #define exfat_err(sb, fmt, ...) \ - exfat_msg(sb, KERN_ERR, fmt, ##__VA_ARGS__) + pr_err("exFAT-fs (%s): " fmt "\n", (sb)->s_id, ##__VA_ARGS__) #define exfat_warn(sb, fmt, ...) \ - exfat_msg(sb, KERN_WARNING, fmt, ##__VA_ARGS__) + pr_warn("exFAT-fs (%s): " fmt "\n", (sb)->s_id, ##__VA_ARGS__) #define exfat_info(sb, fmt, ...) \ - exfat_msg(sb, KERN_INFO, fmt, ##__VA_ARGS__) + pr_info("exFAT-fs (%s): " fmt "\n", (sb)->s_id, ##__VA_ARGS__) +#define exfat_debug(sb, fmt, ...) \ + pr_debug("exFAT-fs (%s): " fmt "\n", (sb)->s_id, ##__VA_ARGS__) void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, u8 tz, __le16 time, __le16 date, u8 time_cs); diff --git a/fs/exfat/fatent.c b/fs/exfat/fatent.c index 9de6a6b844c9..ee0b7cf51157 100644 --- a/fs/exfat/fatent.c +++ b/fs/exfat/fatent.c @@ -331,7 +331,7 @@ int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc, /* find new cluster */ if (hint_clu == EXFAT_EOF_CLUSTER) { if (sbi->clu_srch_ptr < EXFAT_FIRST_CLUSTER) { - exfat_err(sb, "sbi->clu_srch_ptr is invalid (%u)\n", + exfat_err(sb, "sbi->clu_srch_ptr is invalid (%u)", sbi->clu_srch_ptr); sbi->clu_srch_ptr = EXFAT_FIRST_CLUSTER; } diff --git a/fs/exfat/file.c b/fs/exfat/file.c index 20d4e47f57ab..4e0793f35e8f 100644 --- a/fs/exfat/file.c +++ b/fs/exfat/file.c @@ -101,7 +101,6 @@ int __exfat_truncate(struct inode *inode, loff_t new_size) struct super_block *sb = inode->i_sb; struct exfat_sb_info *sbi = EXFAT_SB(sb); struct exfat_inode_info *ei = EXFAT_I(inode); - 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) @@ -149,50 +148,19 @@ int __exfat_truncate(struct inode *inode, loff_t new_size) if (ei->type == TYPE_FILE) ei->attr |= ATTR_ARCHIVE; - /* update the directory entry */ - if (!evict) { - struct timespec64 ts; - struct exfat_dentry *ep, *ep2; - struct exfat_entry_set_cache *es; - int err; - - es = exfat_get_dentry_set(sb, &(ei->dir), ei->entry, - ES_ALL_ENTRIES); - if (!es) - return -EIO; - ep = exfat_get_dentry_cached(es, 0); - ep2 = exfat_get_dentry_cached(es, 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_cs); - 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) { - ep2->dentry.stream.valid_size = 0; - ep2->dentry.stream.size = 0; - } else { - ep2->dentry.stream.valid_size = cpu_to_le64(new_size); - ep2->dentry.stream.size = ep2->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; - } - - exfat_update_dir_chksum_with_entry_set(es); - err = exfat_free_dentry_set(es, inode_needs_sync(inode)); - if (err) - return err; - } + /* + * update the directory entry + * + * If the directory entry is updated by mark_inode_dirty(), the + * directory entry will be written after a writeback cycle of + * updating the bitmap/FAT, which may result in clusters being + * freed but referenced by the directory entry in the event of a + * sudden power failure. + * __exfat_write_inode() is called for directory entry, bitmap + * and FAT to be written in a same writeback. + */ + if (__exfat_write_inode(inode, inode_needs_sync(inode))) + return -EIO; /* cut off from the FAT chain */ if (ei->flags == ALLOC_FAT_CHAIN && last_clu != EXFAT_FREE_CLUSTER && @@ -243,12 +211,6 @@ void exfat_truncate(struct inode *inode, loff_t size) 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 = round_up(i_size_read(inode), sbi->cluster_size) >> inode->i_blkbits; write_size: @@ -330,6 +292,12 @@ int exfat_setattr(struct user_namespace *mnt_userns, struct dentry *dentry, attr->ia_valid &= ~ATTR_MODE; } + if (attr->ia_valid & ATTR_SIZE) + inode->i_mtime = inode->i_ctime = current_time(inode); + + setattr_copy(&init_user_ns, inode, attr); + exfat_truncate_atime(&inode->i_atime); + if (attr->ia_valid & ATTR_SIZE) { error = exfat_block_truncate_page(inode, attr->ia_size); if (error) @@ -337,13 +305,15 @@ int exfat_setattr(struct user_namespace *mnt_userns, struct dentry *dentry, down_write(&EXFAT_I(inode)->truncate_lock); truncate_setsize(inode, attr->ia_size); + + /* + * __exfat_write_inode() is called from exfat_truncate(), inode + * is already written by it, so mark_inode_dirty() is unneeded. + */ exfat_truncate(inode, attr->ia_size); up_write(&EXFAT_I(inode)->truncate_lock); - } - - setattr_copy(&init_user_ns, inode, attr); - exfat_truncate_atime(&inode->i_atime); - mark_inode_dirty(inode); + } else + mark_inode_dirty(inode); out: return error; diff --git a/fs/exfat/inode.c b/fs/exfat/inode.c index 0133d385d8e8..a795437b86d0 100644 --- a/fs/exfat/inode.c +++ b/fs/exfat/inode.c @@ -17,7 +17,7 @@ #include "exfat_raw.h" #include "exfat_fs.h" -static int __exfat_write_inode(struct inode *inode, int sync) +int __exfat_write_inode(struct inode *inode, int sync) { unsigned long long on_disk_size; struct exfat_dentry *ep, *ep2; @@ -75,6 +75,13 @@ static int __exfat_write_inode(struct inode *inode, int sync) ep2->dentry.stream.valid_size = cpu_to_le64(on_disk_size); ep2->dentry.stream.size = ep2->dentry.stream.valid_size; + if (on_disk_size) { + ep2->dentry.stream.flags = ei->flags; + ep2->dentry.stream.start_clu = cpu_to_le32(ei->start_clu); + } else { + ep2->dentry.stream.flags = ALLOC_FAT_CHAIN; + ep2->dentry.stream.start_clu = EXFAT_FREE_CLUSTER; + } exfat_update_dir_chksum_with_entry_set(es); return exfat_free_dentry_set(es, sync); @@ -105,7 +112,7 @@ void exfat_sync_inode(struct inode *inode) static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset, unsigned int *clu, int create) { - int ret, modified = false; + int ret; unsigned int last_clu; struct exfat_chain new_clu; struct super_block *sb = inode->i_sb; @@ -196,7 +203,6 @@ static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset, 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, @@ -206,7 +212,6 @@ static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset, 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)) @@ -216,33 +221,6 @@ static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset, num_clusters += num_to_be_allocated; *clu = new_clu.dir; - if (ei->dir.dir != DIR_DELETED && modified) { - struct exfat_dentry *ep; - struct exfat_entry_set_cache *es; - int err; - - es = exfat_get_dentry_set(sb, &(ei->dir), ei->entry, - ES_ALL_ENTRIES); - if (!es) - return -EIO; - /* get stream entry */ - ep = exfat_get_dentry_cached(es, 1); - - /* update directory entry */ - ep->dentry.stream.flags = ei->flags; - 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; - - exfat_update_dir_chksum_with_entry_set(es); - err = exfat_free_dentry_set(es, inode_needs_sync(inode)); - if (err) - return err; - } /* end of if != DIR_DELETED */ - inode->i_blocks += num_to_be_allocated << sbi->sect_per_clus_bits; @@ -384,6 +362,7 @@ static void exfat_write_failed(struct address_space *mapping, loff_t to) if (to > i_size_read(inode)) { truncate_pagecache(inode, i_size_read(inode)); + inode->i_mtime = inode->i_ctime = current_time(inode); exfat_truncate(inode, EXFAT_I(inode)->i_size_aligned); } } diff --git a/fs/exfat/misc.c b/fs/exfat/misc.c index 9380e0188b55..2e1a1a6b1021 100644 --- a/fs/exfat/misc.c +++ b/fs/exfat/misc.c @@ -46,23 +46,6 @@ void __exfat_fs_error(struct super_block *sb, int report, const char *fmt, ...) } } -/* - * 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) diff --git a/fs/exfat/namei.c b/fs/exfat/namei.c index c6eaf7e9ea74..b617bebc3d0f 100644 --- a/fs/exfat/namei.c +++ b/fs/exfat/namei.c @@ -318,7 +318,6 @@ static int exfat_find_empty_entry(struct inode *inode, unsigned int ret, last_clu; 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); @@ -383,25 +382,6 @@ static int exfat_find_empty_entry(struct inode *inode, 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); - 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(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); ei->i_size_ondisk += sbi->cluster_size; @@ -462,7 +442,7 @@ static int __exfat_resolve_path(struct inode *inode, const unsigned char *path, return namelen; /* return error value */ if ((lossy && !lookup) || !namelen) - return -EINVAL; + return (lossy & NLS_NAME_OVERLEN) ? -ENAMETOOLONG : -EINVAL; exfat_chain_set(p_dir, ei->start_clu, EXFAT_B_TO_CLU(i_size_read(inode), sbi), ei->flags); diff --git a/fs/exfat/nls.c b/fs/exfat/nls.c index ef115e673406..705710f93e2d 100644 --- a/fs/exfat/nls.c +++ b/fs/exfat/nls.c @@ -509,7 +509,7 @@ static int exfat_utf8_to_utf16(struct super_block *sb, } if (unilen > MAX_NAME_LENGTH) { - exfat_err(sb, "failed to %s (estr:ENAMETOOLONG) nls len : %d, unilen : %d > %d", + exfat_debug(sb, "failed to %s (estr:ENAMETOOLONG) nls len : %d, unilen : %d > %d", __func__, len, unilen, MAX_NAME_LENGTH); return -ENAMETOOLONG; } @@ -671,7 +671,7 @@ static int exfat_load_upcase_table(struct super_block *sb, bh = sb_bread(sb, sector); if (!bh) { - exfat_err(sb, "failed to read sector(0x%llx)\n", + exfat_err(sb, "failed to read sector(0x%llx)", (unsigned long long)sector); ret = -EIO; goto free_table; diff --git a/fs/exfat/super.c b/fs/exfat/super.c index 6a4dfe9f31ee..35f0305cd493 100644 --- a/fs/exfat/super.c +++ b/fs/exfat/super.c @@ -464,7 +464,7 @@ static int exfat_read_boot_sector(struct super_block *sb) */ if (p_boot->sect_size_bits < EXFAT_MIN_SECT_SIZE_BITS || p_boot->sect_size_bits > EXFAT_MAX_SECT_SIZE_BITS) { - exfat_err(sb, "bogus sector size bits : %u\n", + exfat_err(sb, "bogus sector size bits : %u", p_boot->sect_size_bits); return -EINVAL; } @@ -473,7 +473,7 @@ static int exfat_read_boot_sector(struct super_block *sb) * sect_per_clus_bits could be at least 0 and at most 25 - sect_size_bits. */ if (p_boot->sect_per_clus_bits > EXFAT_MAX_SECT_PER_CLUS_BITS(p_boot)) { - exfat_err(sb, "bogus sectors bits per cluster : %u\n", + exfat_err(sb, "bogus sectors bits per cluster : %u", p_boot->sect_per_clus_bits); return -EINVAL; } |