Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 344891
b: refs/heads/master
c: 0d812f7
h: refs/heads/master
i:
  344889: 900ae35
  344887: 5a08b84
v: v3
  • Loading branch information
Tao Ma authored and Theodore Ts'o committed Dec 10, 2012
1 parent a153421 commit 5922097
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 13 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 941919856c11d4dd11d4fcabb4dab58bd2b146bf
refs/heads/master: 0d812f77b36c16dff692390508155de2c7f95ea3
48 changes: 43 additions & 5 deletions trunk/fs/ext4/inline.c
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,8 @@ static int ext4_read_inline_data(struct inode *inode, void *buffer,
/*
* write the buffer to the inline inode.
* If 'create' is set, we don't need to do the extra copy in the xattr
* value since it is already handled by ext4_xattr_ibody_set. That saves
* us one memcpy.
* value since it is already handled by ext4_xattr_ibody_inline_set.
* That saves us one memcpy.
*/
void ext4_write_inline_data(struct inode *inode, struct ext4_iloc *iloc,
void *buffer, loff_t pos, unsigned int len)
Expand Down Expand Up @@ -285,7 +285,7 @@ static int ext4_create_inline_data(handle_t *handle,

BUG_ON(!is.s.not_found);

error = ext4_xattr_ibody_set(handle, inode, &i, &is);
error = ext4_xattr_ibody_inline_set(handle, inode, &i, &is);
if (error) {
if (error == -ENOSPC)
ext4_clear_inode_state(inode,
Expand Down Expand Up @@ -354,7 +354,7 @@ static int ext4_update_inline_data(handle_t *handle, struct inode *inode,
i.value = value;
i.value_len = len;

error = ext4_xattr_ibody_set(handle, inode, &i, &is);
error = ext4_xattr_ibody_inline_set(handle, inode, &i, &is);
if (error)
goto out;

Expand Down Expand Up @@ -427,7 +427,7 @@ static int ext4_destroy_inline_data_nolock(handle_t *handle,
if (error)
goto out;

error = ext4_xattr_ibody_set(handle, inode, &i, &is);
error = ext4_xattr_ibody_inline_set(handle, inode, &i, &is);
if (error)
goto out;

Expand Down Expand Up @@ -1715,3 +1715,41 @@ int ext4_inline_data_fiemap(struct inode *inode,
up_read(&EXT4_I(inode)->xattr_sem);
return (error < 0 ? error : 0);
}

/*
* Called during xattr set, and if we can sparse space 'needed',
* just create the extent tree evict the data to the outer block.
*
* We use jbd2 instead of page cache to move data to the 1st block
* so that the whole transaction can be committed as a whole and
* the data isn't lost because of the delayed page cache write.
*/
int ext4_try_to_evict_inline_data(handle_t *handle,
struct inode *inode,
int needed)
{
int error;
struct ext4_xattr_entry *entry;
struct ext4_xattr_ibody_header *header;
struct ext4_inode *raw_inode;
struct ext4_iloc iloc;

error = ext4_get_inode_loc(inode, &iloc);
if (error)
return error;

raw_inode = ext4_raw_inode(&iloc);
header = IHDR(inode, raw_inode);
entry = (struct ext4_xattr_entry *)((void *)raw_inode +
EXT4_I(inode)->i_inline_off);
if (EXT4_XATTR_LEN(entry->e_name_len) +
EXT4_XATTR_SIZE(le32_to_cpu(entry->e_value_size)) < needed) {
error = -ENOSPC;
goto out;
}

error = ext4_convert_inline_data_nolock(handle, inode, &iloc);
out:
brelse(iloc.bh);
return error;
}
54 changes: 50 additions & 4 deletions trunk/fs/ext4/xattr.c
Original file line number Diff line number Diff line change
Expand Up @@ -958,9 +958,47 @@ int ext4_xattr_ibody_find(struct inode *inode, struct ext4_xattr_info *i,
return 0;
}

int ext4_xattr_ibody_set(handle_t *handle, struct inode *inode,
struct ext4_xattr_info *i,
struct ext4_xattr_ibody_find *is)
int ext4_xattr_ibody_inline_set(handle_t *handle, struct inode *inode,
struct ext4_xattr_info *i,
struct ext4_xattr_ibody_find *is)
{
struct ext4_xattr_ibody_header *header;
struct ext4_xattr_search *s = &is->s;
int error;

if (EXT4_I(inode)->i_extra_isize == 0)
return -ENOSPC;
error = ext4_xattr_set_entry(i, s);
if (error) {
if (error == -ENOSPC &&
ext4_has_inline_data(inode)) {
error = ext4_try_to_evict_inline_data(handle, inode,
EXT4_XATTR_LEN(strlen(i->name) +
EXT4_XATTR_SIZE(i->value_len)));
if (error)
return error;
error = ext4_xattr_ibody_find(inode, i, is);
if (error)
return error;
error = ext4_xattr_set_entry(i, s);
}
if (error)
return error;
}
header = IHDR(inode, ext4_raw_inode(&is->iloc));
if (!IS_LAST_ENTRY(s->first)) {
header->h_magic = cpu_to_le32(EXT4_XATTR_MAGIC);
ext4_set_inode_state(inode, EXT4_STATE_XATTR);
} else {
header->h_magic = cpu_to_le32(0);
ext4_clear_inode_state(inode, EXT4_STATE_XATTR);
}
return 0;
}

static int ext4_xattr_ibody_set(handle_t *handle, struct inode *inode,
struct ext4_xattr_info *i,
struct ext4_xattr_ibody_find *is)
{
struct ext4_xattr_ibody_header *header;
struct ext4_xattr_search *s = &is->s;
Expand Down Expand Up @@ -1116,9 +1154,17 @@ ext4_xattr_set(struct inode *inode, int name_index, const char *name,
{
handle_t *handle;
int error, retries = 0;
int credits = EXT4_DATA_TRANS_BLOCKS(inode->i_sb);

retry:
handle = ext4_journal_start(inode, EXT4_DATA_TRANS_BLOCKS(inode->i_sb));
/*
* In case of inline data, we may push out the data to a block,
* So reserve the journal space first.
*/
if (ext4_has_inline_data(inode))
credits += ext4_writepage_trans_blocks(inode) + 1;

handle = ext4_journal_start(inode, credits);
if (IS_ERR(handle)) {
error = PTR_ERR(handle);
} else {
Expand Down
9 changes: 6 additions & 3 deletions trunk/fs/ext4/xattr.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,9 @@ extern int ext4_xattr_ibody_find(struct inode *inode, struct ext4_xattr_info *i,
extern int ext4_xattr_ibody_get(struct inode *inode, int name_index,
const char *name,
void *buffer, size_t buffer_size);
extern int ext4_xattr_ibody_set(handle_t *handle, struct inode *inode,
struct ext4_xattr_info *i,
struct ext4_xattr_ibody_find *is);
extern int ext4_xattr_ibody_inline_set(handle_t *handle, struct inode *inode,
struct ext4_xattr_info *i,
struct ext4_xattr_ibody_find *is);

extern int ext4_has_inline_data(struct inode *inode);
extern int ext4_get_inline_size(struct inode *inode);
Expand Down Expand Up @@ -187,6 +187,9 @@ extern struct buffer_head *ext4_get_first_inline_block(struct inode *inode,
extern int ext4_inline_data_fiemap(struct inode *inode,
struct fiemap_extent_info *fieinfo,
int *has_inline);
extern int ext4_try_to_evict_inline_data(handle_t *handle,
struct inode *inode,
int needed);
# else /* CONFIG_EXT4_FS_XATTR */

static inline int
Expand Down

0 comments on commit 5922097

Please sign in to comment.