Description for this pull request:

- Handle it as the empty directory if the start cluster of stream entry
   is invalid.
 - Valid size of steam entry cannot be greater than data size.
   If valid_size is invalid, Deal with data_size.
 - Move Direct-IO alignment check to before extending the valid size.
 - Fix uninit-value issue reported by syzbot.
 - Optimize to find directory entry-set in write_inode, rename, unlink.
 -----BEGIN PGP SIGNATURE-----
 
 iQJKBAABCgA0FiEE6NzKS6Uv/XAAGHgyZwv7A1FEIQgFAmdEMg0WHGxpbmtpbmpl
 b25Aa2VybmVsLm9yZwAKCRBnC/sDUUQhCKdjD/9PyXz3KQk101fMWYeW0y0Tb9WB
 StQyRr+8p8VIakb1ktatl/TxGAco7dDMdI9ITo2DvGKpRHAeLfztWPogrsRJOmgN
 bqSfGSZMTkzSTIVHuPJ+203G1jpYAwKL3yVeyDfWrUv7H3iGju/eKWUB2Mm4ICDB
 1nOfK/tCzDlX3tJ1QrSrUYNVZ58bh4bbBUkSMqMIZgZc8AgvTkZR0jCzZMh8nYn4
 B4Se9uA+SE5flYQYhs7CTM20/EBB9sg69o0mcnzCgLNQV+3DAk6u+EsignSRPYnG
 qCPVIs1LG7WePOnyaQA/5iN8ZasvZ5w/Of8RXagDnj4+OpZEVOJEPPr8uvMI4RLv
 STvBwixj6KZquMQEfroxRTaLv6rRoaAZcZISSsIcDJ9E/oGlWJQiyY4idfDpaXEI
 2vfd+qmKQASinIs/N7E4xh2ofL5dkMmRH5T7IJxhq5aZ76k/Jpc0Wnk3cEYVhib8
 gLs155acllOEVxpkZYh9BHfI7+KrvPnYQ5eO0a+QjHK3aVkWPvQVZ2mRGI5mcsOy
 m+Ku5/1juAtpr4wSZOytGEl1EjDM1GZ3UKB+HcwOsDxuo6g/E5bHVWnM79D0ada2
 DIxOKXDrVNWPI5LDVMAL8NaS6jjj1GgmmUqBf28RbQ2qcbTuQ/Gdn1YxNq5kER0z
 dEq3Csk6ht0KAwN+AQ==
 =1uEv
 -----END PGP SIGNATURE-----

Merge tag 'exfat-for-6.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/exfat

Pull exfat updates from Namjae Jeon:

 - If the start cluster of stream entry is invalid, treat it as the
   empty directory

 - Valid size of steam entry cannot be greater than data size. If
   valid_size is invalid, use data_size

 - Move Direct-IO alignment check to before extending the valid size

 - Fix uninit-value issue reported by syzbot

 - Optimize finding directory entry-set in write_inode, rename, unlink

* tag 'exfat-for-6.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/exfat:
  exfat: reduce FAT chain traversal
  exfat: code cleanup for exfat_readdir()
  exfat: remove argument 'p_dir' from exfat_add_entry()
  exfat: move exfat_chain_set() out of __exfat_resolve_path()
  exfat: add exfat_get_dentry_set_by_ei() helper
  exfat: rename argument name for exfat_move_file and exfat_rename_file
  exfat: remove unnecessary read entry in __exfat_rename()
  exfat: fix file being changed by unaligned direct write
  exfat: fix uninit-value in __exfat_get_dentry_set
  exfat: fix out-of-bounds access of directory entries
This commit is contained in:
Linus Torvalds 2024-11-28 09:18:11 -08:00
commit 8170a99c0b
5 changed files with 113 additions and 128 deletions

View File

@ -82,11 +82,8 @@ static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_ent
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);
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;
max_dentries = (unsigned int)min_t(u64, MAX_EXFAT_DENTRIES,
@ -135,21 +132,6 @@ static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_ent
num_ext = ep->dentry.file.num_ext;
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_cs);
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_cs);
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;
err = exfat_get_uniname_from_ext_entry(sb, &clu, i,
@ -166,9 +148,8 @@ static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_ent
ep = exfat_get_dentry(sb, &clu, i + 1, &bh);
if (!ep)
return -EIO;
dir_entry->size =
le64_to_cpu(ep->dentry.stream.valid_size);
dir_entry->entry = dentry;
dir_entry->entry = i;
dir_entry->dir = clu;
brelse(bh);
ei->hint_bmap.off = EXFAT_DEN_TO_CLU(dentry, sbi);
@ -276,7 +257,7 @@ static int exfat_iterate(struct file *file, struct dir_context *ctx)
if (!nb->lfn[0])
goto end_of_dir;
i_pos = ((loff_t)ei->start_clu << 32) | (de.entry & 0xffffffff);
i_pos = ((loff_t)de.dir.dir << 32) | (de.entry & 0xffffffff);
tmp = exfat_iget(sb, i_pos);
if (tmp) {
inum = tmp->i_ino;

View File

@ -204,7 +204,9 @@ struct exfat_entry_set_cache {
#define IS_DYNAMIC_ES(es) ((es)->__bh != (es)->bh)
struct exfat_dir_entry {
/* the cluster where file dentry is located */
struct exfat_chain dir;
/* the index of file dentry in ->dir */
int entry;
unsigned int type;
unsigned int start_clu;
@ -290,7 +292,9 @@ struct exfat_sb_info {
* EXFAT file system inode in-memory data
*/
struct exfat_inode_info {
/* the cluster where file dentry is located */
struct exfat_chain dir;
/* the index of file dentry in ->dir */
int entry;
unsigned int type;
unsigned short attr;
@ -508,6 +512,8 @@ struct exfat_dentry *exfat_get_dentry_cached(struct exfat_entry_set_cache *es,
int exfat_get_dentry_set(struct exfat_entry_set_cache *es,
struct super_block *sb, struct exfat_chain *p_dir, int entry,
unsigned int num_entries);
#define exfat_get_dentry_set_by_ei(es, sb, ei) \
exfat_get_dentry_set(es, sb, &(ei)->dir, (ei)->entry, ES_ALL_ENTRIES)
int exfat_get_empty_dentry_set(struct exfat_entry_set_cache *es,
struct super_block *sb, struct exfat_chain *p_dir, int entry,
unsigned int num_entries);

View File

@ -584,6 +584,16 @@ static ssize_t exfat_file_write_iter(struct kiocb *iocb, struct iov_iter *iter)
if (ret < 0)
goto unlock;
if (iocb->ki_flags & IOCB_DIRECT) {
unsigned long align = pos | iov_iter_alignment(iter);
if (!IS_ALIGNED(align, i_blocksize(inode)) &&
!IS_ALIGNED(align, bdev_logical_block_size(inode->i_sb->s_bdev))) {
ret = -EINVAL;
goto unlock;
}
}
if (pos > valid_size) {
ret = exfat_extend_valid_size(file, pos);
if (ret < 0 && ret != -ENOSPC) {

View File

@ -43,7 +43,7 @@ int __exfat_write_inode(struct inode *inode, int sync)
exfat_set_volume_dirty(sb);
/* get the directory entry of given file or directory */
if (exfat_get_dentry_set(&es, sb, &(ei->dir), ei->entry, ES_ALL_ENTRIES))
if (exfat_get_dentry_set_by_ei(&es, sb, ei))
return -EIO;
ep = exfat_get_dentry_cached(&es, ES_IDX_FILE);
ep2 = exfat_get_dentry_cached(&es, ES_IDX_STREAM);

View File

@ -288,8 +288,22 @@ static int exfat_check_max_dentries(struct inode *inode)
return 0;
}
/* find empty directory entry.
* if there isn't any empty slot, expand cluster chain.
/*
* Find an empty directory entry set.
*
* If there isn't any empty slot, expand cluster chain.
*
* in:
* inode: inode of the parent directory
* num_entries: specifies how many dentries in the empty directory entry set
*
* out:
* p_dir: the cluster where the empty directory entry set is located
* es: The found empty directory entry set
*
* return:
* the directory entry index in p_dir is returned on succeeds
* -error code is returned on failure
*/
static int exfat_find_empty_entry(struct inode *inode,
struct exfat_chain *p_dir, int num_entries,
@ -311,6 +325,9 @@ static int exfat_find_empty_entry(struct inode *inode,
ei->hint_femp.eidx = EXFAT_HINT_NONE;
}
exfat_chain_set(p_dir, ei->start_clu,
EXFAT_B_TO_CLU(i_size_read(inode), sbi), ei->flags);
while ((dentry = exfat_search_empty_slot(sb, &hint_femp, p_dir,
num_entries, es)) < 0) {
if (dentry == -EIO)
@ -345,6 +362,7 @@ static int exfat_find_empty_entry(struct inode *inode,
if (ei->start_clu == EXFAT_EOF_CLUSTER) {
ei->start_clu = clu.dir;
p_dir->dir = clu.dir;
hint_femp.eidx = 0;
}
/* append to the FAT chain */
@ -377,7 +395,10 @@ static int exfat_find_empty_entry(struct inode *inode,
inode->i_blocks += sbi->cluster_size >> 9;
}
return dentry;
p_dir->dir = exfat_sector_to_cluster(sbi, es->bh[0]->b_blocknr);
p_dir->size -= dentry / sbi->dentries_per_clu;
return dentry & (sbi->dentries_per_clu - 1);
}
/*
@ -385,14 +406,11 @@ static int exfat_find_empty_entry(struct inode *inode,
* 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)
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);
int pathlen = strlen(path);
/*
@ -431,24 +449,19 @@ static int __exfat_resolve_path(struct inode *inode, const unsigned char *path,
if ((lossy && !lookup) || !namelen)
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);
return 0;
}
static inline int exfat_resolve_path(struct inode *inode,
const unsigned char *path, struct exfat_chain *dir,
struct exfat_uni_name *uni)
const unsigned char *path, struct exfat_uni_name *uni)
{
return __exfat_resolve_path(inode, path, dir, uni, 0);
return __exfat_resolve_path(inode, path, 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)
const unsigned char *path, struct exfat_uni_name *uni)
{
return __exfat_resolve_path(inode, path, dir, uni, 1);
return __exfat_resolve_path(inode, path, uni, 1);
}
static inline loff_t exfat_make_i_pos(struct exfat_dir_entry *info)
@ -457,8 +470,7 @@ static inline loff_t exfat_make_i_pos(struct exfat_dir_entry *info)
}
static int exfat_add_entry(struct inode *inode, const char *path,
struct exfat_chain *p_dir, unsigned int type,
struct exfat_dir_entry *info)
unsigned int type, struct exfat_dir_entry *info)
{
int ret, dentry, num_entries;
struct super_block *sb = inode->i_sb;
@ -470,7 +482,7 @@ static int exfat_add_entry(struct inode *inode, const char *path,
int clu_size = 0;
unsigned int start_clu = EXFAT_FREE_CLUSTER;
ret = exfat_resolve_path(inode, path, p_dir, &uniname);
ret = exfat_resolve_path(inode, path, &uniname);
if (ret)
goto out;
@ -481,7 +493,7 @@ static int exfat_add_entry(struct inode *inode, const char *path,
}
/* exfat_find_empty_entry must be called before alloc_cluster() */
dentry = exfat_find_empty_entry(inode, p_dir, num_entries, &es);
dentry = exfat_find_empty_entry(inode, &info->dir, num_entries, &es);
if (dentry < 0) {
ret = dentry; /* -EIO or -ENOSPC */
goto out;
@ -508,7 +520,6 @@ static int exfat_add_entry(struct inode *inode, const char *path,
if (ret)
goto out;
info->dir = *p_dir;
info->entry = dentry;
info->flags = ALLOC_NO_FAT_CHAIN;
info->type = type;
@ -541,7 +552,6 @@ static int exfat_create(struct mnt_idmap *idmap, struct inode *dir,
{
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;
@ -552,8 +562,7 @@ static int exfat_create(struct mnt_idmap *idmap, struct inode *dir,
mutex_lock(&EXFAT_SB(sb)->s_lock);
exfat_set_volume_dirty(sb);
err = exfat_add_entry(dir, dentry->d_name.name, &cdir, TYPE_FILE,
&info);
err = exfat_add_entry(dir, dentry->d_name.name, TYPE_FILE, &info);
if (err)
goto unlock;
@ -601,10 +610,13 @@ static int exfat_find(struct inode *dir, struct qstr *qname,
return -ENOENT;
/* check the validity of directory name in the given pathname */
ret = exfat_resolve_path_for_lookup(dir, qname->name, &cdir, &uni_name);
ret = exfat_resolve_path_for_lookup(dir, qname->name, &uni_name);
if (ret)
return ret;
exfat_chain_set(&cdir, ei->start_clu,
EXFAT_B_TO_CLU(i_size_read(dir), sbi), ei->flags);
/* 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;
@ -618,15 +630,16 @@ static int exfat_find(struct inode *dir, struct qstr *qname,
if (dentry < 0)
return dentry; /* -error value */
info->dir = cdir;
info->entry = dentry;
info->num_subdirs = 0;
/* adjust cdir to the optimized value */
cdir.dir = hint_opt.clu;
if (cdir.flags & ALLOC_NO_FAT_CHAIN)
cdir.size -= dentry / sbi->dentries_per_clu;
dentry = hint_opt.eidx;
info->dir = cdir;
info->entry = dentry;
info->num_subdirs = 0;
if (exfat_get_dentry_set(&es, sb, &cdir, dentry, ES_2_ENTRIES))
return -EIO;
ep = exfat_get_dentry_cached(&es, ES_IDX_FILE);
@ -637,14 +650,26 @@ static int exfat_find(struct inode *dir, struct qstr *qname,
info->size = le64_to_cpu(ep2->dentry.stream.valid_size);
info->valid_size = le64_to_cpu(ep2->dentry.stream.valid_size);
info->size = le64_to_cpu(ep2->dentry.stream.size);
info->start_clu = le32_to_cpu(ep2->dentry.stream.start_clu);
if (!is_valid_cluster(sbi, info->start_clu) && info->size) {
exfat_warn(sb, "start_clu is invalid cluster(0x%x)",
info->start_clu);
info->size = 0;
info->valid_size = 0;
}
if (info->valid_size > info->size) {
exfat_warn(sb, "valid_size(%lld) is greater than size(%lld)",
info->valid_size, info->size);
info->valid_size = info->size;
}
if (info->size == 0) {
info->flags = ALLOC_NO_FAT_CHAIN;
info->start_clu = EXFAT_EOF_CLUSTER;
} else {
} else
info->flags = ep2->dentry.stream.flags;
info->start_clu =
le32_to_cpu(ep2->dentry.stream.start_clu);
}
exfat_get_entry_time(sbi, &info->crtime,
ep->dentry.file.create_tz,
@ -766,26 +791,23 @@ static struct dentry *exfat_lookup(struct inode *dir, struct dentry *dentry,
/* remove an entry, BUT don't truncate */
static int exfat_unlink(struct inode *dir, struct dentry *dentry)
{
struct exfat_chain cdir;
struct super_block *sb = dir->i_sb;
struct inode *inode = dentry->d_inode;
struct exfat_inode_info *ei = EXFAT_I(inode);
struct exfat_entry_set_cache es;
int entry, err = 0;
int err = 0;
if (unlikely(exfat_forced_shutdown(sb)))
return -EIO;
mutex_lock(&EXFAT_SB(sb)->s_lock);
exfat_chain_dup(&cdir, &ei->dir);
entry = ei->entry;
if (ei->dir.dir == DIR_DELETED) {
exfat_err(sb, "abnormal access to deleted dentry");
err = -ENOENT;
goto unlock;
}
err = exfat_get_dentry_set(&es, sb, &cdir, entry, ES_ALL_ENTRIES);
err = exfat_get_dentry_set_by_ei(&es, sb, ei);
if (err) {
err = -EIO;
goto unlock;
@ -824,7 +846,6 @@ static int exfat_mkdir(struct mnt_idmap *idmap, struct inode *dir,
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;
loff_t size = i_size_read(dir);
@ -834,8 +855,7 @@ static int exfat_mkdir(struct mnt_idmap *idmap, struct inode *dir,
mutex_lock(&EXFAT_SB(sb)->s_lock);
exfat_set_volume_dirty(sb);
err = exfat_add_entry(dir, dentry->d_name.name, &cdir, TYPE_DIR,
&info);
err = exfat_add_entry(dir, dentry->d_name.name, TYPE_DIR, &info);
if (err)
goto unlock;
@ -915,21 +935,18 @@ static int exfat_check_dir_empty(struct super_block *sb,
static int exfat_rmdir(struct inode *dir, struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
struct exfat_chain cdir, clu_to_free;
struct exfat_chain 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 exfat_entry_set_cache es;
int entry, err;
int err;
if (unlikely(exfat_forced_shutdown(sb)))
return -EIO;
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_err(sb, "abnormal access to deleted dentry");
err = -ENOENT;
@ -947,7 +964,7 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry)
goto unlock;
}
err = exfat_get_dentry_set(&es, sb, &cdir, entry, ES_ALL_ENTRIES);
err = exfat_get_dentry_set_by_ei(&es, sb, ei);
if (err) {
err = -EIO;
goto unlock;
@ -982,15 +999,14 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry)
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)
static int exfat_rename_file(struct inode *parent_inode,
struct exfat_uni_name *p_uniname, struct exfat_inode_info *ei)
{
int ret, num_new_entries;
struct exfat_dentry *epold, *epnew;
struct super_block *sb = inode->i_sb;
struct super_block *sb = parent_inode->i_sb;
struct exfat_entry_set_cache old_es, new_es;
int sync = IS_DIRSYNC(inode);
int sync = IS_DIRSYNC(parent_inode);
if (unlikely(exfat_forced_shutdown(sb)))
return -EIO;
@ -999,7 +1015,7 @@ static int exfat_rename_file(struct inode *inode, struct exfat_chain *p_dir,
if (num_new_entries < 0)
return num_new_entries;
ret = exfat_get_dentry_set(&old_es, sb, p_dir, oldentry, ES_ALL_ENTRIES);
ret = exfat_get_dentry_set_by_ei(&old_es, sb, ei);
if (ret) {
ret = -EIO;
return ret;
@ -1009,9 +1025,10 @@ static int exfat_rename_file(struct inode *inode, struct exfat_chain *p_dir,
if (old_es.num_entries < num_new_entries) {
int newentry;
struct exfat_chain dir;
newentry = exfat_find_empty_entry(inode, p_dir, num_new_entries,
&new_es);
newentry = exfat_find_empty_entry(parent_inode, &dir,
num_new_entries, &new_es);
if (newentry < 0) {
ret = newentry; /* -EIO or -ENOSPC */
goto put_old_es;
@ -1034,8 +1051,8 @@ static int exfat_rename_file(struct inode *inode, struct exfat_chain *p_dir,
if (ret)
goto put_old_es;
exfat_remove_entries(inode, &old_es, ES_IDX_FILE);
ei->dir = *p_dir;
exfat_remove_entries(parent_inode, &old_es, ES_IDX_FILE);
ei->dir = dir;
ei->entry = newentry;
} else {
if (exfat_get_entry_type(epold) == TYPE_FILE) {
@ -1043,7 +1060,7 @@ static int exfat_rename_file(struct inode *inode, struct exfat_chain *p_dir,
ei->attr |= EXFAT_ATTR_ARCHIVE;
}
exfat_remove_entries(inode, &old_es, ES_IDX_FIRST_FILENAME + 1);
exfat_remove_entries(parent_inode, &old_es, ES_IDX_FIRST_FILENAME + 1);
exfat_init_ext_entry(&old_es, num_new_entries, p_uniname);
}
return exfat_put_dentry_set(&old_es, sync);
@ -1053,26 +1070,24 @@ static int exfat_rename_file(struct inode *inode, struct exfat_chain *p_dir,
return ret;
}
static int exfat_move_file(struct inode *inode, struct exfat_chain *p_olddir,
int oldentry, struct exfat_chain *p_newdir,
static int exfat_move_file(struct inode *parent_inode,
struct exfat_uni_name *p_uniname, struct exfat_inode_info *ei)
{
int ret, newentry, num_new_entries;
struct exfat_dentry *epmov, *epnew;
struct super_block *sb = inode->i_sb;
struct exfat_entry_set_cache mov_es, new_es;
struct exfat_chain newdir;
num_new_entries = exfat_calc_num_entries(p_uniname);
if (num_new_entries < 0)
return num_new_entries;
ret = exfat_get_dentry_set(&mov_es, sb, p_olddir, oldentry,
ES_ALL_ENTRIES);
ret = exfat_get_dentry_set_by_ei(&mov_es, parent_inode->i_sb, ei);
if (ret)
return -EIO;
newentry = exfat_find_empty_entry(inode, p_newdir, num_new_entries,
&new_es);
newentry = exfat_find_empty_entry(parent_inode, &newdir,
num_new_entries, &new_es);
if (newentry < 0) {
ret = newentry; /* -EIO or -ENOSPC */
goto put_mov_es;
@ -1091,18 +1106,16 @@ static int exfat_move_file(struct inode *inode, struct exfat_chain *p_olddir,
*epnew = *epmov;
exfat_init_ext_entry(&new_es, num_new_entries, p_uniname);
exfat_remove_entries(inode, &mov_es, ES_IDX_FILE);
exfat_chain_set(&ei->dir, p_newdir->dir, p_newdir->size,
p_newdir->flags);
exfat_remove_entries(parent_inode, &mov_es, ES_IDX_FILE);
ei->dir = newdir;
ei->entry = newentry;
ret = exfat_put_dentry_set(&new_es, IS_DIRSYNC(inode));
ret = exfat_put_dentry_set(&new_es, IS_DIRSYNC(parent_inode));
if (ret)
goto put_mov_es;
return exfat_put_dentry_set(&mov_es, IS_DIRSYNC(inode));
return exfat_put_dentry_set(&mov_es, IS_DIRSYNC(parent_inode));
put_mov_es:
exfat_put_dentry_set(&mov_es, false);
@ -1116,19 +1129,12 @@ static int __exfat_rename(struct inode *old_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;
struct exfat_inode_info *new_ei = NULL;
unsigned int new_entry_type = TYPE_UNUSED;
int new_entry = 0;
struct buffer_head *new_bh = NULL;
/* check the validity of pointer parameters */
if (new_path == NULL || strlen(new_path) == 0)
@ -1139,11 +1145,6 @@ static int __exfat_rename(struct inode *old_parent_inode,
return -ENOENT;
}
exfat_chain_set(&olddir, EXFAT_I(old_parent_inode)->start_clu,
EXFAT_B_TO_CLU_ROUND_UP(i_size_read(old_parent_inode), sbi),
EXFAT_I(old_parent_inode)->flags);
dentry = ei->entry;
/* check whether new dir is existing directory and empty */
if (new_inode) {
ret = -EIO;
@ -1154,17 +1155,8 @@ static int __exfat_rename(struct inode *old_parent_inode,
goto out;
}
p_dir = &(new_ei->dir);
new_entry = new_ei->entry;
ep = exfat_get_dentry(sb, p_dir, new_entry, &new_bh);
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) {
if (S_ISDIR(new_inode->i_mode)) {
struct exfat_chain new_clu;
new_clu.dir = new_ei->start_clu;
@ -1180,26 +1172,22 @@ static int __exfat_rename(struct inode *old_parent_inode,
}
/* check the validity of directory name in the given new pathname */
ret = exfat_resolve_path(new_parent_inode, new_path, &newdir,
&uni_name);
ret = exfat_resolve_path(new_parent_inode, new_path, &uni_name);
if (ret)
goto out;
exfat_set_volume_dirty(sb);
if (olddir.dir == newdir.dir)
ret = exfat_rename_file(new_parent_inode, &olddir, dentry,
&uni_name, ei);
if (new_parent_inode == old_parent_inode)
ret = exfat_rename_file(new_parent_inode, &uni_name, ei);
else
ret = exfat_move_file(new_parent_inode, &olddir, dentry,
&newdir, &uni_name, ei);
ret = exfat_move_file(new_parent_inode, &uni_name, ei);
if (!ret && new_inode) {
struct exfat_entry_set_cache es;
/* delete entries of new_dir */
ret = exfat_get_dentry_set(&es, sb, p_dir, new_entry,
ES_ALL_ENTRIES);
ret = exfat_get_dentry_set_by_ei(&es, sb, new_ei);
if (ret) {
ret = -EIO;
goto del_out;
@ -1212,7 +1200,7 @@ static int __exfat_rename(struct inode *old_parent_inode,
goto del_out;
/* Free the clusters if new_inode is a dir(as if exfat_rmdir) */
if (new_entry_type == TYPE_DIR &&
if (S_ISDIR(new_inode->i_mode) &&
new_ei->start_clu != EXFAT_EOF_CLUSTER) {
/* new_ei, new_clu_to_free */
struct exfat_chain new_clu_to_free;