Commit a8549fb5abb2b372e46d5de0d23ff8b24f4a61af
Committed by
Mark Fasheh
1 parent
970e4936d7
Exists in
master
and in
7 other branches
ocfs2: Wrap virtual block reads in ocfs2_read_virt_blocks()
The ocfs2_read_dir_block() function really maps an inode's virtual blocks to physical ones before calling ocfs2_read_blocks(). Let's extract that to common code, because other places might want to do that. Other than the block number being virtual, ocfs2_read_virt_blocks() takes the same arguments as ocfs2_read_blocks(). It converts those virtual block numbers to physical before calling ocfs2_read_blocks() directly. If the blocks asked for are discontiguous, this can mean multiple calls to ocfs2_read_blocks(), but this is mostly hidden from the caller. Like ocfs2_read_blocks(), the caller can pass in an existing buffer_head. This is usually done to pick up some readahead I/O. ocfs2_read_virt_blocks() checks the buffer_head's block number against the extent map - it must match. Signed-off-by: Joel Becker <joel.becker@oracle.com> Signed-off-by: Mark Fasheh <mfasheh@suse.com>
Showing 2 changed files with 95 additions and 0 deletions Side-by-side Diff
fs/ocfs2/extent_map.c
... | ... | @@ -806,4 +806,73 @@ |
806 | 806 | |
807 | 807 | return ret; |
808 | 808 | } |
809 | + | |
810 | +int ocfs2_read_virt_blocks(struct inode *inode, u64 v_block, int nr, | |
811 | + struct buffer_head *bhs[], int flags, | |
812 | + int (*validate)(struct super_block *sb, | |
813 | + struct buffer_head *bh)) | |
814 | +{ | |
815 | + int rc = 0; | |
816 | + u64 p_block, p_count; | |
817 | + int i, count, done = 0; | |
818 | + | |
819 | + mlog_entry("(inode = %p, v_block = %llu, nr = %d, bhs = %p, " | |
820 | + "flags = %x, validate = %p)\n", | |
821 | + inode, (unsigned long long)v_block, nr, bhs, flags, | |
822 | + validate); | |
823 | + | |
824 | + if (((v_block + nr - 1) << inode->i_sb->s_blocksize_bits) >= | |
825 | + i_size_read(inode)) { | |
826 | + BUG_ON(!(flags & OCFS2_BH_READAHEAD)); | |
827 | + goto out; | |
828 | + } | |
829 | + | |
830 | + while (done < nr) { | |
831 | + down_read(&OCFS2_I(inode)->ip_alloc_sem); | |
832 | + rc = ocfs2_extent_map_get_blocks(inode, v_block + done, | |
833 | + &p_block, &p_count, NULL); | |
834 | + up_read(&OCFS2_I(inode)->ip_alloc_sem); | |
835 | + if (rc) { | |
836 | + mlog_errno(rc); | |
837 | + break; | |
838 | + } | |
839 | + | |
840 | + if (!p_block) { | |
841 | + rc = -EIO; | |
842 | + mlog(ML_ERROR, | |
843 | + "Inode #%llu contains a hole at offset %llu\n", | |
844 | + (unsigned long long)OCFS2_I(inode)->ip_blkno, | |
845 | + (unsigned long long)(v_block + done) << | |
846 | + inode->i_sb->s_blocksize_bits); | |
847 | + break; | |
848 | + } | |
849 | + | |
850 | + count = nr - done; | |
851 | + if (p_count < count) | |
852 | + count = p_count; | |
853 | + | |
854 | + /* | |
855 | + * If the caller passed us bhs, they should have come | |
856 | + * from a previous readahead call to this function. Thus, | |
857 | + * they should have the right b_blocknr. | |
858 | + */ | |
859 | + for (i = 0; i < count; i++) { | |
860 | + if (!bhs[done + i]) | |
861 | + continue; | |
862 | + BUG_ON(bhs[done + i]->b_blocknr != (p_block + i)); | |
863 | + } | |
864 | + | |
865 | + rc = ocfs2_read_blocks(inode, p_block, count, bhs + done, | |
866 | + flags, validate); | |
867 | + if (rc) { | |
868 | + mlog_errno(rc); | |
869 | + break; | |
870 | + } | |
871 | + done += count; | |
872 | + } | |
873 | + | |
874 | +out: | |
875 | + mlog_exit(rc); | |
876 | + return rc; | |
877 | +} |
fs/ocfs2/extent_map.h
... | ... | @@ -57,5 +57,29 @@ |
57 | 57 | u32 *p_cluster, u32 *num_clusters, |
58 | 58 | struct ocfs2_extent_list *el); |
59 | 59 | |
60 | +int ocfs2_read_virt_blocks(struct inode *inode, u64 v_block, int nr, | |
61 | + struct buffer_head *bhs[], int flags, | |
62 | + int (*validate)(struct super_block *sb, | |
63 | + struct buffer_head *bh)); | |
64 | +static inline int ocfs2_read_virt_block(struct inode *inode, u64 v_block, | |
65 | + struct buffer_head **bh, | |
66 | + int (*validate)(struct super_block *sb, | |
67 | + struct buffer_head *bh)) | |
68 | +{ | |
69 | + int status = 0; | |
70 | + | |
71 | + if (bh == NULL) { | |
72 | + printk("ocfs2: bh == NULL\n"); | |
73 | + status = -EINVAL; | |
74 | + goto bail; | |
75 | + } | |
76 | + | |
77 | + status = ocfs2_read_virt_blocks(inode, v_block, 1, bh, 0, validate); | |
78 | + | |
79 | +bail: | |
80 | + return status; | |
81 | +} | |
82 | + | |
83 | + | |
60 | 84 | #endif /* _EXTENT_MAP_H */ |