Commit 46c7f254543dedcf134ad05091ed2b935a9a597d

Authored by Tao Ma
Committed by Theodore Ts'o
1 parent 67cf5b09a4

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

... ... @@ -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;
... ... @@ -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);
... ... @@ -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 }