Skip to content

Commit 46c7f25

Browse files
taoma-tmtytso
authored andcommitted
ext4: add read support for inline data
Let readpage and readpages handle the case when we want to read an inlined file. Signed-off-by: Tao Ma <[email protected]> Signed-off-by: "Theodore Ts'o" <[email protected]>
1 parent 67cf5b0 commit 46c7f25

File tree

3 files changed

+98
-1
lines changed

3 files changed

+98
-1
lines changed

fs/ext4/inline.c

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,67 @@ static int ext4_destroy_inline_data_nolock(handle_t *handle,
454454
return error;
455455
}
456456

457+
static int ext4_read_inline_page(struct inode *inode, struct page *page)
458+
{
459+
void *kaddr;
460+
int ret = 0;
461+
size_t len;
462+
struct ext4_iloc iloc;
463+
464+
BUG_ON(!PageLocked(page));
465+
BUG_ON(!ext4_has_inline_data(inode));
466+
BUG_ON(page->index);
467+
468+
if (!EXT4_I(inode)->i_inline_off) {
469+
ext4_warning(inode->i_sb, "inode %lu doesn't have inline data.",
470+
inode->i_ino);
471+
goto out;
472+
}
473+
474+
ret = ext4_get_inode_loc(inode, &iloc);
475+
if (ret)
476+
goto out;
477+
478+
len = min_t(size_t, ext4_get_inline_size(inode), i_size_read(inode));
479+
kaddr = kmap_atomic(page);
480+
ret = ext4_read_inline_data(inode, kaddr, len, &iloc);
481+
flush_dcache_page(page);
482+
kunmap_atomic(kaddr);
483+
zero_user_segment(page, len, PAGE_CACHE_SIZE);
484+
SetPageUptodate(page);
485+
brelse(iloc.bh);
486+
487+
out:
488+
return ret;
489+
}
490+
491+
int ext4_readpage_inline(struct inode *inode, struct page *page)
492+
{
493+
int ret = 0;
494+
495+
down_read(&EXT4_I(inode)->xattr_sem);
496+
if (!ext4_has_inline_data(inode)) {
497+
up_read(&EXT4_I(inode)->xattr_sem);
498+
return -EAGAIN;
499+
}
500+
501+
/*
502+
* Current inline data can only exist in the 1st page,
503+
* So for all the other pages, just set them uptodate.
504+
*/
505+
if (!page->index)
506+
ret = ext4_read_inline_page(inode, page);
507+
else if (!PageUptodate(page)) {
508+
zero_user_segment(page, 0, PAGE_CACHE_SIZE);
509+
SetPageUptodate(page);
510+
}
511+
512+
up_read(&EXT4_I(inode)->xattr_sem);
513+
514+
unlock_page(page);
515+
return ret >= 0 ? 0 : ret;
516+
}
517+
457518
int ext4_destroy_inline_data(handle_t *handle, struct inode *inode)
458519
{
459520
int ret;

fs/ext4/inode.c

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,9 @@ static int _ext4_get_block(struct inode *inode, sector_t iblock,
649649
int ret = 0, started = 0;
650650
int dio_credits;
651651

652+
if (ext4_has_inline_data(inode))
653+
return -ERANGE;
654+
652655
map.m_lblk = iblock;
653656
map.m_len = bh->b_size >> inode->i_blkbits;
654657

@@ -2687,6 +2690,12 @@ static sector_t ext4_bmap(struct address_space *mapping, sector_t block)
26872690
journal_t *journal;
26882691
int err;
26892692

2693+
/*
2694+
* We can get here for an inline file via the FIBMAP ioctl
2695+
*/
2696+
if (ext4_has_inline_data(inode))
2697+
return 0;
2698+
26902699
if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY) &&
26912700
test_opt(inode->i_sb, DELALLOC)) {
26922701
/*
@@ -2732,14 +2741,30 @@ static sector_t ext4_bmap(struct address_space *mapping, sector_t block)
27322741

27332742
static int ext4_readpage(struct file *file, struct page *page)
27342743
{
2744+
int ret = -EAGAIN;
2745+
struct inode *inode = page->mapping->host;
2746+
27352747
trace_ext4_readpage(page);
2736-
return mpage_readpage(page, ext4_get_block);
2748+
2749+
if (ext4_has_inline_data(inode))
2750+
ret = ext4_readpage_inline(inode, page);
2751+
2752+
if (ret == -EAGAIN)
2753+
return mpage_readpage(page, ext4_get_block);
2754+
2755+
return ret;
27372756
}
27382757

27392758
static int
27402759
ext4_readpages(struct file *file, struct address_space *mapping,
27412760
struct list_head *pages, unsigned nr_pages)
27422761
{
2762+
struct inode *inode = mapping->host;
2763+
2764+
/* If the file has inline data, no need to do readpages. */
2765+
if (ext4_has_inline_data(inode))
2766+
return 0;
2767+
27432768
return mpage_readpages(mapping, pages, nr_pages, ext4_get_block);
27442769
}
27452770

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

3106+
/* Let buffer I/O handle the inline data case. */
3107+
if (ext4_has_inline_data(inode))
3108+
return 0;
3109+
30813110
trace_ext4_direct_IO_enter(inode, offset, iov_length(iov, nr_segs), rw);
30823111
if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
30833112
ret = ext4_ext_direct_IO(rw, iocb, iov, offset, nr_segs);

fs/ext4/xattr.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ extern int ext4_prepare_inline_data(handle_t *handle, struct inode *inode,
139139
extern int ext4_init_inline_data(handle_t *handle, struct inode *inode,
140140
unsigned int len);
141141
extern int ext4_destroy_inline_data(handle_t *handle, struct inode *inode);
142+
143+
extern int ext4_readpage_inline(struct inode *inode, struct page *page);
142144
# else /* CONFIG_EXT4_FS_XATTR */
143145

144146
static inline int
@@ -255,6 +257,11 @@ static inline int ext4_destroy_inline_data(handle_t *handle,
255257
{
256258
return 0;
257259
}
260+
261+
static inline int ext4_readpage_inline(struct inode *inode, struct page *page)
262+
{
263+
return 0;
264+
}
258265
# endif /* CONFIG_EXT4_FS_XATTR */
259266

260267
#ifdef CONFIG_EXT4_FS_SECURITY

0 commit comments

Comments
 (0)