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
					
				
			
		
					 2 changed files with 80 additions and 40 deletions
				
			
		|  | @ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Tao Ma
				Tao Ma