/* * Try to add the new entry to the inline data. * If succeeds, return 0. If not, extended the inline dir and copied data to * the new created block. */ int ext4_try_add_inline_entry(handle_t *handle, struct ext4_filename *fname, struct inode *dir, struct inode *inode) { int ret, inline_size; void *inline_start; struct ext4_iloc iloc; ret = ext4_get_inode_loc(dir, &iloc); if (ret) return ret; down_write(&EXT4_I(dir)->xattr_sem); if (!ext4_has_inline_data(dir)) goto out; inline_start = (void *)ext4_raw_inode(&iloc)->i_block + EXT4_INLINE_DOTDOT_SIZE; inline_size = EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DOTDOT_SIZE; ret = ext4_add_dirent_to_inline(handle, fname, dir, inode, &iloc, inline_start, inline_size); if (ret != -ENOSPC) goto out; /* check whether it can be inserted to inline xattr space. */ inline_size = EXT4_I(dir)->i_inline_size - EXT4_MIN_INLINE_DATA_SIZE; if (!inline_size) { /* Try to use the xattr space.*/ ret = ext4_update_inline_dir(handle, dir, &iloc); if (ret && ret != -ENOSPC) goto out; inline_size = EXT4_I(dir)->i_inline_size - EXT4_MIN_INLINE_DATA_SIZE; } if (inline_size) { inline_start = ext4_get_inline_xattr_pos(dir, &iloc); ret = ext4_add_dirent_to_inline(handle, fname, dir, inode, &iloc, inline_start, inline_size); if (ret != -ENOSPC) goto out; } /* * The inline space is filled up, so create a new block for it. * As the extent tree will be created, we have to save the inline * dir first. */ ret = ext4_convert_inline_data_nolock(handle, dir, &iloc); out: ext4_mark_inode_dirty(handle, dir); up_write(&EXT4_I(dir)->xattr_sem); brelse(iloc.bh); return ret; }
/* * Try to add the new entry to the inline data. * If succeeds, return 0. If not, extended the inline dir and copied data to * the new created block. */ int ext4_try_add_inline_entry(handle_t *handle, struct dentry *dentry, struct inode *inode) { int ret, inline_size; void *inline_start, *backup_buf = NULL; struct buffer_head *dir_block = NULL; struct ext4_iloc iloc; int blocksize = inode->i_sb->s_blocksize; struct inode *dir = dentry->d_parent->d_inode; ret = ext4_get_inode_loc(dir, &iloc); if (ret) return ret; down_write(&EXT4_I(dir)->xattr_sem); if (!ext4_has_inline_data(dir)) goto out; inline_start = ext4_raw_inode(&iloc)->i_block; inline_size = EXT4_MIN_INLINE_DATA_SIZE; ret = ext4_add_dirent_to_inline(handle, dentry, inode, &iloc, inline_start, inline_size); if (ret != -ENOSPC) goto out; /* check whether it can be inserted to inline xattr space. */ inline_size = EXT4_I(dir)->i_inline_size - EXT4_MIN_INLINE_DATA_SIZE; if (inline_size > 0) { inline_start = ext4_get_inline_xattr_pos(dir, &iloc); ret = ext4_add_dirent_to_inline(handle, dentry, inode, &iloc, inline_start, inline_size); if (ret != -ENOSPC) goto out; } /* Try to add more xattr space.*/ ret = ext4_update_inline_dir(handle, dentry, dir, &iloc); if (ret && ret != -ENOSPC) goto out; else if (!ret) { inline_size = EXT4_I(dir)->i_inline_size - EXT4_MIN_INLINE_DATA_SIZE; inline_start = ext4_get_inline_xattr_pos(dir, &iloc); ret = ext4_add_dirent_to_inline(handle, dentry, inode, &iloc, inline_start, inline_size); if (ret != -ENOSPC) goto out; } /* * The inline space is filled up, so create a new block for it. * As the extent tree will be created, we have to save the inline * dir first. */ inline_size = EXT4_I(dir)->i_inline_size; backup_buf = kmalloc(inline_size, GFP_NOFS); if (!backup_buf) { ret = -ENOMEM; goto out; } memcpy(backup_buf, (void *)ext4_raw_inode(&iloc)->i_block, EXT4_MIN_INLINE_DATA_SIZE); if (inline_size > EXT4_MIN_INLINE_DATA_SIZE) memcpy(backup_buf + EXT4_MIN_INLINE_DATA_SIZE, ext4_get_inline_xattr_pos(dir, &iloc), inline_size - EXT4_MIN_INLINE_DATA_SIZE); /* clear the entry and the flag in dir now. */ ret = ext4_destroy_inline_data_nolock(handle, dir); if (ret) goto out; dir->i_size = EXT4_I(dir)->i_disksize = blocksize; dir_block = ext4_bread(handle, dir, 0, 1, &ret); if (!dir_block) goto out; BUFFER_TRACE(dir_block, "get_write_access"); ret = ext4_journal_get_write_access(handle, dir_block); if (ret) goto out; memcpy(dir_block->b_data, backup_buf, inline_size); /* Set the final de to cover the whole block. */ ext4_update_final_de(dir_block->b_data, inline_size, blocksize); BUFFER_TRACE(dir_block, "call ext4_handle_dirty_metadata"); ret = ext4_handle_dirty_metadata(handle, dir, dir_block); out: kfree(backup_buf); brelse(dir_block); if (!ret || ret == 1) ext4_mark_inode_dirty(handle, dir); up_write(&EXT4_I(dir)->xattr_sem); brelse(iloc.bh); return ret; }