aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYan, Zheng <zyan@redhat.com>2017-09-02 12:04:31 -0400
committerIlya Dryomov <idryomov@gmail.com>2017-09-06 13:56:57 -0400
commit590e9d9861f5f21fbbb0266e40e6a17bc5084dd0 (patch)
tree57665da237483343bc23163aedfc23123e3820e0
parent0e5ecac7168366500af1fa9a70fa9ce573f891f3 (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.c41
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
828retry: 829retry:
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
1137release_pvec_pages: 1142release_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 }