forked from mirrors/linux
		
	ext4: factor out xattr moving
Factor out function for moving xattrs from inode into external xattr block from ext4_expand_extra_isize_ea(). That function is already quite long and factoring out this rather standalone functionality helps readability. Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
This commit is contained in:
		
							parent
							
								
									9440571388
								
							
						
					
					
						commit
						3f2571c1f9
					
				
					 1 changed files with 85 additions and 74 deletions
				
			
		
							
								
								
									
										159
									
								
								fs/ext4/xattr.c
									
									
									
									
									
								
							
							
						
						
									
										159
									
								
								fs/ext4/xattr.c
									
									
									
									
									
								
							| 
						 | 
					@ -1339,6 +1339,84 @@ static void ext4_xattr_shift_entries(struct ext4_xattr_entry *entry,
 | 
				
			||||||
	memmove(to, from, n);
 | 
						memmove(to, from, n);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Move xattr pointed to by 'entry' from inode into external xattr block
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int ext4_xattr_move_to_block(handle_t *handle, struct inode *inode,
 | 
				
			||||||
 | 
									    struct ext4_inode *raw_inode,
 | 
				
			||||||
 | 
									    struct ext4_xattr_entry *entry)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ext4_xattr_ibody_find *is = NULL;
 | 
				
			||||||
 | 
						struct ext4_xattr_block_find *bs = NULL;
 | 
				
			||||||
 | 
						char *buffer = NULL, *b_entry_name = NULL;
 | 
				
			||||||
 | 
						size_t value_offs, value_size;
 | 
				
			||||||
 | 
						struct ext4_xattr_info i = {
 | 
				
			||||||
 | 
							.value = NULL,
 | 
				
			||||||
 | 
							.value_len = 0,
 | 
				
			||||||
 | 
							.name_index = entry->e_name_index,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						struct ext4_xattr_ibody_header *header = IHDR(inode, raw_inode);
 | 
				
			||||||
 | 
						int error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						value_offs = le16_to_cpu(entry->e_value_offs);
 | 
				
			||||||
 | 
						value_size = le32_to_cpu(entry->e_value_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						is = kzalloc(sizeof(struct ext4_xattr_ibody_find), GFP_NOFS);
 | 
				
			||||||
 | 
						bs = kzalloc(sizeof(struct ext4_xattr_block_find), GFP_NOFS);
 | 
				
			||||||
 | 
						buffer = kmalloc(value_size, GFP_NOFS);
 | 
				
			||||||
 | 
						b_entry_name = kmalloc(entry->e_name_len + 1, GFP_NOFS);
 | 
				
			||||||
 | 
						if (!is || !bs || !buffer || !b_entry_name) {
 | 
				
			||||||
 | 
							error = -ENOMEM;
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						is->s.not_found = -ENODATA;
 | 
				
			||||||
 | 
						bs->s.not_found = -ENODATA;
 | 
				
			||||||
 | 
						is->iloc.bh = NULL;
 | 
				
			||||||
 | 
						bs->bh = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Save the entry name and the entry value */
 | 
				
			||||||
 | 
						memcpy(buffer, (void *)IFIRST(header) + value_offs, value_size);
 | 
				
			||||||
 | 
						memcpy(b_entry_name, entry->e_name, entry->e_name_len);
 | 
				
			||||||
 | 
						b_entry_name[entry->e_name_len] = '\0';
 | 
				
			||||||
 | 
						i.name = b_entry_name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						error = ext4_get_inode_loc(inode, &is->iloc);
 | 
				
			||||||
 | 
						if (error)
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						error = ext4_xattr_ibody_find(inode, &i, is);
 | 
				
			||||||
 | 
						if (error)
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Remove the chosen entry from the inode */
 | 
				
			||||||
 | 
						error = ext4_xattr_ibody_set(handle, inode, &i, is);
 | 
				
			||||||
 | 
						if (error)
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						i.name = b_entry_name;
 | 
				
			||||||
 | 
						i.value = buffer;
 | 
				
			||||||
 | 
						i.value_len = value_size;
 | 
				
			||||||
 | 
						error = ext4_xattr_block_find(inode, &i, bs);
 | 
				
			||||||
 | 
						if (error)
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Add entry which was removed from the inode into the block */
 | 
				
			||||||
 | 
						error = ext4_xattr_block_set(handle, inode, &i, bs);
 | 
				
			||||||
 | 
						if (error)
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
						error = 0;
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
 | 
						kfree(b_entry_name);
 | 
				
			||||||
 | 
						kfree(buffer);
 | 
				
			||||||
 | 
						if (is)
 | 
				
			||||||
 | 
							brelse(is->iloc.bh);
 | 
				
			||||||
 | 
						kfree(is);
 | 
				
			||||||
 | 
						kfree(bs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return error;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Expand an inode by new_extra_isize bytes when EAs are present.
 | 
					 * Expand an inode by new_extra_isize bytes when EAs are present.
 | 
				
			||||||
 * Returns 0 on success or negative error number on failure.
 | 
					 * Returns 0 on success or negative error number on failure.
 | 
				
			||||||
| 
						 | 
					@ -1349,9 +1427,6 @@ int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
 | 
				
			||||||
	struct ext4_xattr_ibody_header *header;
 | 
						struct ext4_xattr_ibody_header *header;
 | 
				
			||||||
	struct ext4_xattr_entry *entry, *last, *first;
 | 
						struct ext4_xattr_entry *entry, *last, *first;
 | 
				
			||||||
	struct buffer_head *bh = NULL;
 | 
						struct buffer_head *bh = NULL;
 | 
				
			||||||
	struct ext4_xattr_ibody_find *is = NULL;
 | 
					 | 
				
			||||||
	struct ext4_xattr_block_find *bs = NULL;
 | 
					 | 
				
			||||||
	char *buffer = NULL, *b_entry_name = NULL;
 | 
					 | 
				
			||||||
	size_t min_offs;
 | 
						size_t min_offs;
 | 
				
			||||||
	size_t ifree, bfree;
 | 
						size_t ifree, bfree;
 | 
				
			||||||
	int total_ino;
 | 
						int total_ino;
 | 
				
			||||||
| 
						 | 
					@ -1427,27 +1502,11 @@ int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while (isize_diff > ifree) {
 | 
						while (isize_diff > ifree) {
 | 
				
			||||||
		size_t offs, size, entry_size;
 | 
					 | 
				
			||||||
		struct ext4_xattr_entry *small_entry = NULL;
 | 
							struct ext4_xattr_entry *small_entry = NULL;
 | 
				
			||||||
		struct ext4_xattr_info i = {
 | 
							unsigned int entry_size;	/* EA entry size */
 | 
				
			||||||
			.value = NULL,
 | 
							unsigned int total_size;	/* EA entry size + value size */
 | 
				
			||||||
			.value_len = 0,
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
		unsigned int total_size;  /* EA entry size + value size */
 | 
					 | 
				
			||||||
		unsigned int min_total_size = ~0U;
 | 
							unsigned int min_total_size = ~0U;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		is = kzalloc(sizeof(struct ext4_xattr_ibody_find), GFP_NOFS);
 | 
					 | 
				
			||||||
		bs = kzalloc(sizeof(struct ext4_xattr_block_find), GFP_NOFS);
 | 
					 | 
				
			||||||
		if (!is || !bs) {
 | 
					 | 
				
			||||||
			error = -ENOMEM;
 | 
					 | 
				
			||||||
			goto cleanup;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		is->s.not_found = -ENODATA;
 | 
					 | 
				
			||||||
		bs->s.not_found = -ENODATA;
 | 
					 | 
				
			||||||
		is->iloc.bh = NULL;
 | 
					 | 
				
			||||||
		bs->bh = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		last = IFIRST(header);
 | 
							last = IFIRST(header);
 | 
				
			||||||
		/* Find the entry best suited to be pushed into EA block */
 | 
							/* Find the entry best suited to be pushed into EA block */
 | 
				
			||||||
		entry = NULL;
 | 
							entry = NULL;
 | 
				
			||||||
| 
						 | 
					@ -1474,8 +1533,6 @@ int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
 | 
				
			||||||
				    s_min_extra_isize) {
 | 
									    s_min_extra_isize) {
 | 
				
			||||||
					tried_min_extra_isize++;
 | 
										tried_min_extra_isize++;
 | 
				
			||||||
					new_extra_isize = s_min_extra_isize;
 | 
										new_extra_isize = s_min_extra_isize;
 | 
				
			||||||
					kfree(is); is = NULL;
 | 
					 | 
				
			||||||
					kfree(bs); bs = NULL;
 | 
					 | 
				
			||||||
					brelse(bh);
 | 
										brelse(bh);
 | 
				
			||||||
					goto retry;
 | 
										goto retry;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
| 
						 | 
					@ -1483,58 +1540,18 @@ int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
 | 
				
			||||||
				goto cleanup;
 | 
									goto cleanup;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		offs = le16_to_cpu(entry->e_value_offs);
 | 
					
 | 
				
			||||||
		size = le32_to_cpu(entry->e_value_size);
 | 
					 | 
				
			||||||
		entry_size = EXT4_XATTR_LEN(entry->e_name_len);
 | 
							entry_size = EXT4_XATTR_LEN(entry->e_name_len);
 | 
				
			||||||
		total_size = entry_size + EXT4_XATTR_SIZE(size);
 | 
							total_size = entry_size +
 | 
				
			||||||
		i.name_index = entry->e_name_index,
 | 
								EXT4_XATTR_SIZE(le32_to_cpu(entry->e_value_size));
 | 
				
			||||||
		buffer = kmalloc(EXT4_XATTR_SIZE(size), GFP_NOFS);
 | 
							error = ext4_xattr_move_to_block(handle, inode, raw_inode,
 | 
				
			||||||
		b_entry_name = kmalloc(entry->e_name_len + 1, GFP_NOFS);
 | 
											 entry);
 | 
				
			||||||
		if (!buffer || !b_entry_name) {
 | 
					 | 
				
			||||||
			error = -ENOMEM;
 | 
					 | 
				
			||||||
			goto cleanup;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		/* Save the entry name and the entry value */
 | 
					 | 
				
			||||||
		memcpy(buffer, (void *)IFIRST(header) + offs,
 | 
					 | 
				
			||||||
		       EXT4_XATTR_SIZE(size));
 | 
					 | 
				
			||||||
		memcpy(b_entry_name, entry->e_name, entry->e_name_len);
 | 
					 | 
				
			||||||
		b_entry_name[entry->e_name_len] = '\0';
 | 
					 | 
				
			||||||
		i.name = b_entry_name;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		error = ext4_get_inode_loc(inode, &is->iloc);
 | 
					 | 
				
			||||||
		if (error)
 | 
							if (error)
 | 
				
			||||||
			goto cleanup;
 | 
								goto cleanup;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		error = ext4_xattr_ibody_find(inode, &i, is);
 | 
					 | 
				
			||||||
		if (error)
 | 
					 | 
				
			||||||
			goto cleanup;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* Remove the chosen entry from the inode */
 | 
					 | 
				
			||||||
		error = ext4_xattr_ibody_set(handle, inode, &i, is);
 | 
					 | 
				
			||||||
		if (error)
 | 
					 | 
				
			||||||
			goto cleanup;
 | 
					 | 
				
			||||||
		total_ino -= entry_size;
 | 
							total_ino -= entry_size;
 | 
				
			||||||
		ifree += total_size;
 | 
							ifree += total_size;
 | 
				
			||||||
		bfree -= total_size;
 | 
							bfree -= total_size;
 | 
				
			||||||
 | 
					 | 
				
			||||||
		i.name = b_entry_name;
 | 
					 | 
				
			||||||
		i.value = buffer;
 | 
					 | 
				
			||||||
		i.value_len = size;
 | 
					 | 
				
			||||||
		error = ext4_xattr_block_find(inode, &i, bs);
 | 
					 | 
				
			||||||
		if (error)
 | 
					 | 
				
			||||||
			goto cleanup;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* Add entry which was removed from the inode into the block */
 | 
					 | 
				
			||||||
		error = ext4_xattr_block_set(handle, inode, &i, bs);
 | 
					 | 
				
			||||||
		if (error)
 | 
					 | 
				
			||||||
			goto cleanup;
 | 
					 | 
				
			||||||
		kfree(b_entry_name);
 | 
					 | 
				
			||||||
		kfree(buffer);
 | 
					 | 
				
			||||||
		b_entry_name = NULL;
 | 
					 | 
				
			||||||
		buffer = NULL;
 | 
					 | 
				
			||||||
		brelse(is->iloc.bh);
 | 
					 | 
				
			||||||
		kfree(is);
 | 
					 | 
				
			||||||
		kfree(bs);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
shift:
 | 
					shift:
 | 
				
			||||||
| 
						 | 
					@ -1552,12 +1569,6 @@ int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cleanup:
 | 
					cleanup:
 | 
				
			||||||
	kfree(b_entry_name);
 | 
					 | 
				
			||||||
	kfree(buffer);
 | 
					 | 
				
			||||||
	if (is)
 | 
					 | 
				
			||||||
		brelse(is->iloc.bh);
 | 
					 | 
				
			||||||
	kfree(is);
 | 
					 | 
				
			||||||
	kfree(bs);
 | 
					 | 
				
			||||||
	brelse(bh);
 | 
						brelse(bh);
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * We deliberately leave EXT4_STATE_NO_EXPAND set here since inode
 | 
						 * We deliberately leave EXT4_STATE_NO_EXPAND set here since inode
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue