diff options
author | Yan, Zheng <zyan@redhat.com> | 2017-09-02 12:04:31 -0400 |
---|---|---|
committer | Ilya Dryomov <idryomov@gmail.com> | 2017-09-06 13:56:57 -0400 |
commit | 590e9d9861f5f21fbbb0266e40e6a17bc5084dd0 (patch) | |
tree | 57665da237483343bc23163aedfc23123e3820e0 | |
parent | 0e5ecac7168366500af1fa9a70fa9ce573f891f3 (diff) |
ceph: fix "range cyclic" mode writepages
In range cyclic mode, writepages() should first write dirty pages
in range [writeback_index, (pgoff_t)-1], then write pages in range
[0, writeback_index -1]. Besides, if writepages() encounters a page
that beyond EOF, it should restart from the beginning.
Signed-off-by: "Yan, Zheng" <zyan@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
-rw-r--r-- | fs/ceph/addr.c | 41 |
1 files changed, 24 insertions, 17 deletions
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index 221df531b0c3..4a54f7369f51 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c | |||
@@ -781,16 +781,15 @@ static int ceph_writepages_start(struct address_space *mapping, | |||
781 | struct ceph_inode_info *ci = ceph_inode(inode); | 781 | struct ceph_inode_info *ci = ceph_inode(inode); |
782 | struct ceph_fs_client *fsc = ceph_inode_to_client(inode); | 782 | struct ceph_fs_client *fsc = ceph_inode_to_client(inode); |
783 | struct ceph_vino vino = ceph_vino(inode); | 783 | struct ceph_vino vino = ceph_vino(inode); |
784 | pgoff_t index, start, end; | 784 | pgoff_t index, start_index, end; |
785 | int range_whole = 0; | ||
786 | int should_loop = 1; | ||
787 | struct ceph_snap_context *snapc = NULL, *last_snapc = NULL, *pgsnapc; | 785 | struct ceph_snap_context *snapc = NULL, *last_snapc = NULL, *pgsnapc; |
788 | struct pagevec pvec; | 786 | struct pagevec pvec; |
789 | int done = 0; | ||
790 | int rc = 0; | 787 | int rc = 0; |
791 | unsigned int wsize = i_blocksize(inode); | 788 | unsigned int wsize = i_blocksize(inode); |
792 | struct ceph_osd_request *req = NULL; | 789 | struct ceph_osd_request *req = NULL; |
793 | struct ceph_writeback_ctl ceph_wbc; | 790 | struct ceph_writeback_ctl ceph_wbc; |
791 | bool should_loop, range_whole = false; | ||
792 | bool stop, done = false; | ||
794 | 793 | ||
795 | dout("writepages_start %p (mode=%s)\n", inode, | 794 | dout("writepages_start %p (mode=%s)\n", inode, |
796 | wbc->sync_mode == WB_SYNC_NONE ? "NONE" : | 795 | wbc->sync_mode == WB_SYNC_NONE ? "NONE" : |
@@ -810,20 +809,22 @@ static int ceph_writepages_start(struct address_space *mapping, | |||
810 | 809 | ||
811 | pagevec_init(&pvec, 0); | 810 | pagevec_init(&pvec, 0); |
812 | 811 | ||
812 | start_index = wbc->range_cyclic ? mapping->writeback_index : 0; | ||
813 | |||
813 | /* where to start/end? */ | 814 | /* where to start/end? */ |
814 | if (wbc->range_cyclic) { | 815 | if (wbc->range_cyclic) { |
815 | start = mapping->writeback_index; /* Start from prev offset */ | 816 | index = start_index; |
816 | end = -1; | 817 | end = -1; |
817 | dout(" cyclic, start at %lu\n", start); | 818 | should_loop = (index > 0); |
819 | dout(" cyclic, start at %lu\n", index); | ||
818 | } else { | 820 | } else { |
819 | start = wbc->range_start >> PAGE_SHIFT; | 821 | index = wbc->range_start >> PAGE_SHIFT; |
820 | end = wbc->range_end >> PAGE_SHIFT; | 822 | end = wbc->range_end >> PAGE_SHIFT; |
821 | if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) | 823 | if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) |
822 | range_whole = 1; | 824 | range_whole = true; |
823 | should_loop = 0; | 825 | should_loop = false; |
824 | dout(" not cyclic, %lu to %lu\n", start, end); | 826 | dout(" not cyclic, %lu to %lu\n", index, end); |
825 | } | 827 | } |
826 | index = start; | ||
827 | 828 | ||
828 | retry: | 829 | retry: |
829 | /* find oldest snap context with dirty data */ | 830 | /* find oldest snap context with dirty data */ |
@@ -847,7 +848,8 @@ retry: | |||
847 | } | 848 | } |
848 | last_snapc = snapc; | 849 | last_snapc = snapc; |
849 | 850 | ||
850 | while (!done && index <= end) { | 851 | stop = false; |
852 | while (!stop && index <= end) { | ||
851 | int num_ops = 0, op_idx; | 853 | int num_ops = 0, op_idx; |
852 | unsigned i, pvec_pages, max_pages, locked_pages = 0; | 854 | unsigned i, pvec_pages, max_pages, locked_pages = 0; |
853 | struct page **pages = NULL, **data_pages; | 855 | struct page **pages = NULL, **data_pages; |
@@ -885,9 +887,11 @@ get_more_pages: | |||
885 | unlock_page(page); | 887 | unlock_page(page); |
886 | continue; | 888 | continue; |
887 | } | 889 | } |
888 | if (!wbc->range_cyclic && page->index > end) { | 890 | if (page->index > end) { |
889 | dout("end of range %p\n", page); | 891 | dout("end of range %p\n", page); |
890 | done = 1; | 892 | /* can't be range_cyclic (1st pass) because |
893 | * end == -1 in that case. */ | ||
894 | stop = done = true; | ||
891 | unlock_page(page); | 895 | unlock_page(page); |
892 | break; | 896 | break; |
893 | } | 897 | } |
@@ -899,7 +903,8 @@ get_more_pages: | |||
899 | if (page_offset(page) >= ceph_wbc.i_size) { | 903 | if (page_offset(page) >= ceph_wbc.i_size) { |
900 | dout("%p page eof %llu\n", | 904 | dout("%p page eof %llu\n", |
901 | page, ceph_wbc.i_size); | 905 | page, ceph_wbc.i_size); |
902 | done = 1; | 906 | /* not done if range_cyclic */ |
907 | stop = true; | ||
903 | unlock_page(page); | 908 | unlock_page(page); |
904 | break; | 909 | break; |
905 | } | 910 | } |
@@ -1132,7 +1137,7 @@ new_request: | |||
1132 | goto new_request; | 1137 | goto new_request; |
1133 | 1138 | ||
1134 | if (wbc->nr_to_write <= 0) | 1139 | if (wbc->nr_to_write <= 0) |
1135 | done = 1; | 1140 | stop = done = true; |
1136 | 1141 | ||
1137 | release_pvec_pages: | 1142 | release_pvec_pages: |
1138 | dout("pagevec_release on %d pages (%p)\n", (int)pvec.nr, | 1143 | dout("pagevec_release on %d pages (%p)\n", (int)pvec.nr, |
@@ -1146,7 +1151,9 @@ release_pvec_pages: | |||
1146 | if (should_loop && !done) { | 1151 | if (should_loop && !done) { |
1147 | /* more to do; loop back to beginning of file */ | 1152 | /* more to do; loop back to beginning of file */ |
1148 | dout("writepages looping back to beginning of file\n"); | 1153 | dout("writepages looping back to beginning of file\n"); |
1149 | should_loop = 0; | 1154 | should_loop = false; |
1155 | end = start_index - 1; | ||
1156 | |||
1150 | index = 0; | 1157 | index = 0; |
1151 | goto retry; | 1158 | goto retry; |
1152 | } | 1159 | } |