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, | 				    __u32 minor_hash, | ||||||
| 				    struct ext4_dir_entry_2 *dirent); | 				    struct ext4_dir_entry_2 *dirent); | ||||||
| extern void ext4_htree_free_dir_info(struct dir_private_info *p); | 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 */ | /* fsync.c */ | ||||||
| extern int ext4_sync_file(struct file *, loff_t, loff_t, int); | 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); | 	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. |  * NOTE! unlike strncmp, ext4_match returns 1 for success, 0 for failure. | ||||||
|  * |  * | ||||||
|  | @ -1614,6 +1607,63 @@ errout: | ||||||
| 	return NULL; | 	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, |  * 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 |  * 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; | 	struct inode	*dir = dentry->d_parent->d_inode; | ||||||
| 	const char	*name = dentry->d_name.name; | 	const char	*name = dentry->d_name.name; | ||||||
| 	int		namelen = dentry->d_name.len; | 	int		namelen = dentry->d_name.len; | ||||||
| 	unsigned int	offset = 0; |  | ||||||
| 	unsigned int	blocksize = dir->i_sb->s_blocksize; | 	unsigned int	blocksize = dir->i_sb->s_blocksize; | ||||||
| 	unsigned short	reclen; | 	unsigned short	reclen; | ||||||
| 	int		nlen, rlen, err; |  | ||||||
| 	char		*top; |  | ||||||
| 	int		csum_size = 0; | 	int		csum_size = 0; | ||||||
|  | 	int		err; | ||||||
| 
 | 
 | ||||||
| 	if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, | 	if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, | ||||||
| 				       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | 				       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); | 	reclen = EXT4_DIR_REC_LEN(namelen); | ||||||
| 	if (!de) { | 	if (!de) { | ||||||
| 		de = (struct ext4_dir_entry_2 *)bh->b_data; | 		err = ext4_find_dest_de(dir, inode, | ||||||
| 		top = bh->b_data + (blocksize - csum_size) - reclen; | 					bh, bh->b_data, blocksize - csum_size, | ||||||
| 		while ((char *) de <= top) { | 					name, namelen, &de); | ||||||
| 			if (ext4_check_dir_entry(dir, NULL, de, bh, bh->b_data, | 		if (err) | ||||||
| 						 bh->b_size, offset)) | 			return err; | ||||||
| 				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; |  | ||||||
| 	} | 	} | ||||||
| 	BUFFER_TRACE(bh, "get_write_access"); | 	BUFFER_TRACE(bh, "get_write_access"); | ||||||
| 	err = ext4_journal_get_write_access(handle, bh); | 	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 */ | 	/* By now the buffer is marked for journaling */ | ||||||
| 	nlen = EXT4_DIR_REC_LEN(de->name_len); | 	ext4_insert_dentry(inode, de, blocksize, name, namelen); | ||||||
| 	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); |  | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * XXX shouldn't update any times until successful | 	 * XXX shouldn't update any times until successful | ||||||
| 	 * completion of syscall, but too many callers depend | 	 * completion of syscall, but too many callers depend | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Tao Ma
				Tao Ma