ext4: create __ext4_insert_dentry for dir entry insertion
The old add_dirent_to_buf handles all the work related to the work of adding dir entry to a dir block. Now we have inline data, so create 2 new function __ext4_find_dest_de and __ext4_insert_dentry that do the real work and let add_dirent_to_buf call them. Signed-off-by: Tao Ma <boyu.mt@taobao.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
This commit is contained in:
parent
226ba972b0
commit
978fef914a
@ -1969,6 +1969,21 @@ extern int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,
|
||||
__u32 minor_hash,
|
||||
struct ext4_dir_entry_2 *dirent);
|
||||
extern void ext4_htree_free_dir_info(struct dir_private_info *p);
|
||||
extern int ext4_find_dest_de(struct inode *dir, struct inode *inode,
|
||||
struct buffer_head *bh,
|
||||
void *buf, int buf_size,
|
||||
const char *name, int namelen,
|
||||
struct ext4_dir_entry_2 **dest_de);
|
||||
void ext4_insert_dentry(struct inode *inode,
|
||||
struct ext4_dir_entry_2 *de,
|
||||
int buf_size,
|
||||
const char *name, int namelen);
|
||||
static inline void ext4_update_dx_flag(struct inode *inode)
|
||||
{
|
||||
if (!EXT4_HAS_COMPAT_FEATURE(inode->i_sb,
|
||||
EXT4_FEATURE_COMPAT_DIR_INDEX))
|
||||
ext4_clear_inode_flag(inode, EXT4_INODE_INDEX);
|
||||
}
|
||||
|
||||
/* fsync.c */
|
||||
extern int ext4_sync_file(struct file *, loff_t, loff_t, int);
|
||||
|
105
fs/ext4/namei.c
105
fs/ext4/namei.c
@ -1084,13 +1084,6 @@ static void dx_insert_block(struct dx_frame *frame, u32 hash, ext4_lblk_t block)
|
||||
dx_set_count(entries, count + 1);
|
||||
}
|
||||
|
||||
static void ext4_update_dx_flag(struct inode *inode)
|
||||
{
|
||||
if (!EXT4_HAS_COMPAT_FEATURE(inode->i_sb,
|
||||
EXT4_FEATURE_COMPAT_DIR_INDEX))
|
||||
ext4_clear_inode_flag(inode, EXT4_INODE_INDEX);
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE! unlike strncmp, ext4_match returns 1 for success, 0 for failure.
|
||||
*
|
||||
@ -1614,6 +1607,63 @@ errout:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ext4_find_dest_de(struct inode *dir, struct inode *inode,
|
||||
struct buffer_head *bh,
|
||||
void *buf, int buf_size,
|
||||
const char *name, int namelen,
|
||||
struct ext4_dir_entry_2 **dest_de)
|
||||
{
|
||||
struct ext4_dir_entry_2 *de;
|
||||
unsigned short reclen = EXT4_DIR_REC_LEN(namelen);
|
||||
int nlen, rlen;
|
||||
unsigned int offset = 0;
|
||||
char *top;
|
||||
|
||||
de = (struct ext4_dir_entry_2 *)buf;
|
||||
top = buf + buf_size - reclen;
|
||||
while ((char *) de <= top) {
|
||||
if (ext4_check_dir_entry(dir, NULL, de, bh,
|
||||
buf, buf_size, offset))
|
||||
return -EIO;
|
||||
if (ext4_match(namelen, name, de))
|
||||
return -EEXIST;
|
||||
nlen = EXT4_DIR_REC_LEN(de->name_len);
|
||||
rlen = ext4_rec_len_from_disk(de->rec_len, buf_size);
|
||||
if ((de->inode ? rlen - nlen : rlen) >= reclen)
|
||||
break;
|
||||
de = (struct ext4_dir_entry_2 *)((char *)de + rlen);
|
||||
offset += rlen;
|
||||
}
|
||||
if ((char *) de > top)
|
||||
return -ENOSPC;
|
||||
|
||||
*dest_de = de;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ext4_insert_dentry(struct inode *inode,
|
||||
struct ext4_dir_entry_2 *de,
|
||||
int buf_size,
|
||||
const char *name, int namelen)
|
||||
{
|
||||
|
||||
int nlen, rlen;
|
||||
|
||||
nlen = EXT4_DIR_REC_LEN(de->name_len);
|
||||
rlen = ext4_rec_len_from_disk(de->rec_len, buf_size);
|
||||
if (de->inode) {
|
||||
struct ext4_dir_entry_2 *de1 =
|
||||
(struct ext4_dir_entry_2 *)((char *)de + nlen);
|
||||
de1->rec_len = ext4_rec_len_to_disk(rlen - nlen, buf_size);
|
||||
de->rec_len = ext4_rec_len_to_disk(nlen, buf_size);
|
||||
de = de1;
|
||||
}
|
||||
de->file_type = EXT4_FT_UNKNOWN;
|
||||
de->inode = cpu_to_le32(inode->i_ino);
|
||||
ext4_set_de_type(inode->i_sb, de, inode->i_mode);
|
||||
de->name_len = namelen;
|
||||
memcpy(de->name, name, namelen);
|
||||
}
|
||||
/*
|
||||
* Add a new entry into a directory (leaf) block. If de is non-NULL,
|
||||
* it points to a directory entry which is guaranteed to be large
|
||||
@ -1629,12 +1679,10 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry,
|
||||
struct inode *dir = dentry->d_parent->d_inode;
|
||||
const char *name = dentry->d_name.name;
|
||||
int namelen = dentry->d_name.len;
|
||||
unsigned int offset = 0;
|
||||
unsigned int blocksize = dir->i_sb->s_blocksize;
|
||||
unsigned short reclen;
|
||||
int nlen, rlen, err;
|
||||
char *top;
|
||||
int csum_size = 0;
|
||||
int err;
|
||||
|
||||
if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
|
||||
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
|
||||
@ -1642,23 +1690,11 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry,
|
||||
|
||||
reclen = EXT4_DIR_REC_LEN(namelen);
|
||||
if (!de) {
|
||||
de = (struct ext4_dir_entry_2 *)bh->b_data;
|
||||
top = bh->b_data + (blocksize - csum_size) - reclen;
|
||||
while ((char *) de <= top) {
|
||||
if (ext4_check_dir_entry(dir, NULL, de, bh, bh->b_data,
|
||||
bh->b_size, offset))
|
||||
return -EIO;
|
||||
if (ext4_match(namelen, name, de))
|
||||
return -EEXIST;
|
||||
nlen = EXT4_DIR_REC_LEN(de->name_len);
|
||||
rlen = ext4_rec_len_from_disk(de->rec_len, blocksize);
|
||||
if ((de->inode? rlen - nlen: rlen) >= reclen)
|
||||
break;
|
||||
de = (struct ext4_dir_entry_2 *)((char *)de + rlen);
|
||||
offset += rlen;
|
||||
}
|
||||
if ((char *) de > top)
|
||||
return -ENOSPC;
|
||||
err = ext4_find_dest_de(dir, inode,
|
||||
bh, bh->b_data, blocksize - csum_size,
|
||||
name, namelen, &de);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
BUFFER_TRACE(bh, "get_write_access");
|
||||
err = ext4_journal_get_write_access(handle, bh);
|
||||
@ -1668,19 +1704,8 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry,
|
||||
}
|
||||
|
||||
/* By now the buffer is marked for journaling */
|
||||
nlen = EXT4_DIR_REC_LEN(de->name_len);
|
||||
rlen = ext4_rec_len_from_disk(de->rec_len, blocksize);
|
||||
if (de->inode) {
|
||||
struct ext4_dir_entry_2 *de1 = (struct ext4_dir_entry_2 *)((char *)de + nlen);
|
||||
de1->rec_len = ext4_rec_len_to_disk(rlen - nlen, blocksize);
|
||||
de->rec_len = ext4_rec_len_to_disk(nlen, blocksize);
|
||||
de = de1;
|
||||
}
|
||||
de->file_type = EXT4_FT_UNKNOWN;
|
||||
de->inode = cpu_to_le32(inode->i_ino);
|
||||
ext4_set_de_type(dir->i_sb, de, inode->i_mode);
|
||||
de->name_len = namelen;
|
||||
memcpy(de->name, name, namelen);
|
||||
ext4_insert_dentry(inode, de, blocksize, name, namelen);
|
||||
|
||||
/*
|
||||
* XXX shouldn't update any times until successful
|
||||
* completion of syscall, but too many callers depend
|
||||
|
Loading…
Reference in New Issue
Block a user