diff options
author | Tao Ma <boyu.mt@taobao.com> | 2012-12-10 14:04:52 -0500 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2012-12-10 14:04:52 -0500 |
commit | 46c7f254543dedcf134ad05091ed2b935a9a597d (patch) | |
tree | dbcb8b71bfe5aebef35964a04f086e2d4eee7ad7 /fs/ext4 | |
parent | 67cf5b09a46f72e048501b84996f2f77bc42e947 (diff) |
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 <boyu.mt@taobao.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4')
-rw-r--r-- | fs/ext4/inline.c | 61 | ||||
-rw-r--r-- | fs/ext4/inode.c | 31 | ||||
-rw-r--r-- | fs/ext4/xattr.h | 7 |
3 files changed, 98 insertions, 1 deletions
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c index bec68b364832..e4a41d5d06db 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c | |||
@@ -454,6 +454,67 @@ out: | |||
454 | return error; | 454 | return error; |
455 | } | 455 | } |
456 | 456 | ||
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 | |||
457 | int ext4_destroy_inline_data(handle_t *handle, struct inode *inode) | 518 | int ext4_destroy_inline_data(handle_t *handle, struct inode *inode) |
458 | { | 519 | { |
459 | int ret; | 520 | int ret; |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index e23f114e2cfe..1668abf80549 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -649,6 +649,9 @@ static int _ext4_get_block(struct inode *inode, sector_t iblock, | |||
649 | int ret = 0, started = 0; | 649 | int ret = 0, started = 0; |
650 | int dio_credits; | 650 | int dio_credits; |
651 | 651 | ||
652 | if (ext4_has_inline_data(inode)) | ||
653 | return -ERANGE; | ||
654 | |||
652 | map.m_lblk = iblock; | 655 | map.m_lblk = iblock; |
653 | map.m_len = bh->b_size >> inode->i_blkbits; | 656 | map.m_len = bh->b_size >> inode->i_blkbits; |
654 | 657 | ||
@@ -2687,6 +2690,12 @@ static sector_t ext4_bmap(struct address_space *mapping, sector_t block) | |||
2687 | journal_t *journal; | 2690 | journal_t *journal; |
2688 | int err; | 2691 | int err; |
2689 | 2692 | ||
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 | |||
2690 | if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY) && | 2699 | if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY) && |
2691 | test_opt(inode->i_sb, DELALLOC)) { | 2700 | test_opt(inode->i_sb, DELALLOC)) { |
2692 | /* | 2701 | /* |
@@ -2732,14 +2741,30 @@ static sector_t ext4_bmap(struct address_space *mapping, sector_t block) | |||
2732 | 2741 | ||
2733 | static int ext4_readpage(struct file *file, struct page *page) | 2742 | static int ext4_readpage(struct file *file, struct page *page) |
2734 | { | 2743 | { |
2744 | int ret = -EAGAIN; | ||
2745 | struct inode *inode = page->mapping->host; | ||
2746 | |||
2735 | trace_ext4_readpage(page); | 2747 | 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; | ||
2737 | } | 2756 | } |
2738 | 2757 | ||
2739 | static int | 2758 | static int |
2740 | ext4_readpages(struct file *file, struct address_space *mapping, | 2759 | ext4_readpages(struct file *file, struct address_space *mapping, |
2741 | struct list_head *pages, unsigned nr_pages) | 2760 | struct list_head *pages, unsigned nr_pages) |
2742 | { | 2761 | { |
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 | |||
2743 | return mpage_readpages(mapping, pages, nr_pages, ext4_get_block); | 2768 | return mpage_readpages(mapping, pages, nr_pages, ext4_get_block); |
2744 | } | 2769 | } |
2745 | 2770 | ||
@@ -3078,6 +3103,10 @@ static ssize_t ext4_direct_IO(int rw, struct kiocb *iocb, | |||
3078 | if (ext4_should_journal_data(inode)) | 3103 | if (ext4_should_journal_data(inode)) |
3079 | return 0; | 3104 | return 0; |
3080 | 3105 | ||
3106 | /* Let buffer I/O handle the inline data case. */ | ||
3107 | if (ext4_has_inline_data(inode)) | ||
3108 | return 0; | ||
3109 | |||
3081 | trace_ext4_direct_IO_enter(inode, offset, iov_length(iov, nr_segs), rw); | 3110 | trace_ext4_direct_IO_enter(inode, offset, iov_length(iov, nr_segs), rw); |
3082 | if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) | 3111 | if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) |
3083 | ret = ext4_ext_direct_IO(rw, iocb, iov, offset, nr_segs); | 3112 | ret = ext4_ext_direct_IO(rw, iocb, iov, offset, nr_segs); |
diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h index 7ae0d05156e3..646c9b9be8ed 100644 --- a/fs/ext4/xattr.h +++ b/fs/ext4/xattr.h | |||
@@ -139,6 +139,8 @@ extern int ext4_prepare_inline_data(handle_t *handle, struct inode *inode, | |||
139 | extern int ext4_init_inline_data(handle_t *handle, struct inode *inode, | 139 | extern int ext4_init_inline_data(handle_t *handle, struct inode *inode, |
140 | unsigned int len); | 140 | unsigned int len); |
141 | extern int ext4_destroy_inline_data(handle_t *handle, struct inode *inode); | 141 | 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); | ||
142 | # else /* CONFIG_EXT4_FS_XATTR */ | 144 | # else /* CONFIG_EXT4_FS_XATTR */ |
143 | 145 | ||
144 | static inline int | 146 | static inline int |
@@ -255,6 +257,11 @@ static inline int ext4_destroy_inline_data(handle_t *handle, | |||
255 | { | 257 | { |
256 | return 0; | 258 | return 0; |
257 | } | 259 | } |
260 | |||
261 | static inline int ext4_readpage_inline(struct inode *inode, struct page *page) | ||
262 | { | ||
263 | return 0; | ||
264 | } | ||
258 | # endif /* CONFIG_EXT4_FS_XATTR */ | 265 | # endif /* CONFIG_EXT4_FS_XATTR */ |
259 | 266 | ||
260 | #ifdef CONFIG_EXT4_FS_SECURITY | 267 | #ifdef CONFIG_EXT4_FS_SECURITY |