Commit 46c7f254543dedcf134ad05091ed2b935a9a597d
Committed by
Theodore Ts'o
1 parent
67cf5b09a4
Exists in
master
and in
20 other branches
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>
Showing 3 changed files with 98 additions and 1 deletions Side-by-side Diff
fs/ext4/inline.c
... | ... | @@ -454,6 +454,67 @@ |
454 | 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 | 518 | int ext4_destroy_inline_data(handle_t *handle, struct inode *inode) |
458 | 519 | { |
459 | 520 | int ret; |
fs/ext4/inode.c
... | ... | @@ -649,6 +649,9 @@ |
649 | 649 | int ret = 0, started = 0; |
650 | 650 | int dio_credits; |
651 | 651 | |
652 | + if (ext4_has_inline_data(inode)) | |
653 | + return -ERANGE; | |
654 | + | |
652 | 655 | map.m_lblk = iblock; |
653 | 656 | map.m_len = bh->b_size >> inode->i_blkbits; |
654 | 657 | |
... | ... | @@ -2687,6 +2690,12 @@ |
2687 | 2690 | journal_t *journal; |
2688 | 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 | 2699 | if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY) && |
2691 | 2700 | test_opt(inode->i_sb, DELALLOC)) { |
2692 | 2701 | /* |
2693 | 2702 | |
2694 | 2703 | |
... | ... | @@ -2732,14 +2741,30 @@ |
2732 | 2741 | |
2733 | 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 | 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 | 2758 | static int |
2740 | 2759 | ext4_readpages(struct file *file, struct address_space *mapping, |
2741 | 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 | 2768 | return mpage_readpages(mapping, pages, nr_pages, ext4_get_block); |
2744 | 2769 | } |
2745 | 2770 | |
... | ... | @@ -3076,6 +3101,10 @@ |
3076 | 3101 | * If we are doing data journalling we don't support O_DIRECT |
3077 | 3102 | */ |
3078 | 3103 | if (ext4_should_journal_data(inode)) |
3104 | + return 0; | |
3105 | + | |
3106 | + /* Let buffer I/O handle the inline data case. */ | |
3107 | + if (ext4_has_inline_data(inode)) | |
3079 | 3108 | return 0; |
3080 | 3109 | |
3081 | 3110 | trace_ext4_direct_IO_enter(inode, offset, iov_length(iov, nr_segs), rw); |
fs/ext4/xattr.h
... | ... | @@ -139,6 +139,8 @@ |
139 | 139 | extern int ext4_init_inline_data(handle_t *handle, struct inode *inode, |
140 | 140 | unsigned int len); |
141 | 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 | 144 | # else /* CONFIG_EXT4_FS_XATTR */ |
143 | 145 | |
144 | 146 | static inline int |
... | ... | @@ -252,6 +254,11 @@ |
252 | 254 | |
253 | 255 | static inline int ext4_destroy_inline_data(handle_t *handle, |
254 | 256 | struct inode *inode) |
257 | +{ | |
258 | + return 0; | |
259 | +} | |
260 | + | |
261 | +static inline int ext4_readpage_inline(struct inode *inode, struct page *page) | |
255 | 262 | { |
256 | 263 | return 0; |
257 | 264 | } |