Skip to content

Commit

Permalink
ext4: add read support for inline data
Browse files Browse the repository at this point in the history
Let readpage and readpages handle the case when we want to read an
inlined file.

Signed-off-by: Tao Ma <boyu.mt@taobao.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
  • Loading branch information
Tao Ma authored and Theodore Ts'o committed Dec 10, 2012
1 parent 67cf5b0 commit 46c7f25
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 1 deletion.
61 changes: 61 additions & 0 deletions fs/ext4/inline.c
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,67 @@ static int ext4_destroy_inline_data_nolock(handle_t *handle,
return error;
}

static int ext4_read_inline_page(struct inode *inode, struct page *page)
{
void *kaddr;
int ret = 0;
size_t len;
struct ext4_iloc iloc;

BUG_ON(!PageLocked(page));
BUG_ON(!ext4_has_inline_data(inode));
BUG_ON(page->index);

if (!EXT4_I(inode)->i_inline_off) {
ext4_warning(inode->i_sb, "inode %lu doesn't have inline data.",
inode->i_ino);
goto out;
}

ret = ext4_get_inode_loc(inode, &iloc);
if (ret)
goto out;

len = min_t(size_t, ext4_get_inline_size(inode), i_size_read(inode));
kaddr = kmap_atomic(page);
ret = ext4_read_inline_data(inode, kaddr, len, &iloc);
flush_dcache_page(page);
kunmap_atomic(kaddr);
zero_user_segment(page, len, PAGE_CACHE_SIZE);
SetPageUptodate(page);
brelse(iloc.bh);

out:
return ret;
}

int ext4_readpage_inline(struct inode *inode, struct page *page)
{
int ret = 0;

down_read(&EXT4_I(inode)->xattr_sem);
if (!ext4_has_inline_data(inode)) {
up_read(&EXT4_I(inode)->xattr_sem);
return -EAGAIN;
}

/*
* Current inline data can only exist in the 1st page,
* So for all the other pages, just set them uptodate.
*/
if (!page->index)
ret = ext4_read_inline_page(inode, page);
else if (!PageUptodate(page)) {
zero_user_segment(page, 0, PAGE_CACHE_SIZE);
SetPageUptodate(page);
}

up_read(&EXT4_I(inode)->xattr_sem);

unlock_page(page);
return ret >= 0 ? 0 : ret;
}

int ext4_destroy_inline_data(handle_t *handle, struct inode *inode)
{
int ret;
Expand Down
31 changes: 30 additions & 1 deletion fs/ext4/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,9 @@ static int _ext4_get_block(struct inode *inode, sector_t iblock,
int ret = 0, started = 0;
int dio_credits;

if (ext4_has_inline_data(inode))
return -ERANGE;

map.m_lblk = iblock;
map.m_len = bh->b_size >> inode->i_blkbits;

Expand Down Expand Up @@ -2687,6 +2690,12 @@ static sector_t ext4_bmap(struct address_space *mapping, sector_t block)
journal_t *journal;
int err;

/*
* We can get here for an inline file via the FIBMAP ioctl
*/
if (ext4_has_inline_data(inode))
return 0;

if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY) &&
test_opt(inode->i_sb, DELALLOC)) {
/*
Expand Down Expand Up @@ -2732,14 +2741,30 @@ static sector_t ext4_bmap(struct address_space *mapping, sector_t block)

static int ext4_readpage(struct file *file, struct page *page)
{
int ret = -EAGAIN;
struct inode *inode = page->mapping->host;

trace_ext4_readpage(page);
return mpage_readpage(page, ext4_get_block);

if (ext4_has_inline_data(inode))
ret = ext4_readpage_inline(inode, page);

if (ret == -EAGAIN)
return mpage_readpage(page, ext4_get_block);

return ret;
}

static int
ext4_readpages(struct file *file, struct address_space *mapping,
struct list_head *pages, unsigned nr_pages)
{
struct inode *inode = mapping->host;

/* If the file has inline data, no need to do readpages. */
if (ext4_has_inline_data(inode))
return 0;

return mpage_readpages(mapping, pages, nr_pages, ext4_get_block);
}

Expand Down Expand Up @@ -3078,6 +3103,10 @@ static ssize_t ext4_direct_IO(int rw, struct kiocb *iocb,
if (ext4_should_journal_data(inode))
return 0;

/* Let buffer I/O handle the inline data case. */
if (ext4_has_inline_data(inode))
return 0;

trace_ext4_direct_IO_enter(inode, offset, iov_length(iov, nr_segs), rw);
if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
ret = ext4_ext_direct_IO(rw, iocb, iov, offset, nr_segs);
Expand Down
7 changes: 7 additions & 0 deletions fs/ext4/xattr.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ extern int ext4_prepare_inline_data(handle_t *handle, struct inode *inode,
extern int ext4_init_inline_data(handle_t *handle, struct inode *inode,
unsigned int len);
extern int ext4_destroy_inline_data(handle_t *handle, struct inode *inode);

extern int ext4_readpage_inline(struct inode *inode, struct page *page);
# else /* CONFIG_EXT4_FS_XATTR */

static inline int
Expand Down Expand Up @@ -255,6 +257,11 @@ static inline int ext4_destroy_inline_data(handle_t *handle,
{
return 0;
}

static inline int ext4_readpage_inline(struct inode *inode, struct page *page)
{
return 0;
}
# endif /* CONFIG_EXT4_FS_XATTR */

#ifdef CONFIG_EXT4_FS_SECURITY
Expand Down

0 comments on commit 46c7f25

Please sign in to comment.