diff options
author | Yan, Zheng <zyan@redhat.com> | 2017-09-01 22:50:48 -0400 |
---|---|---|
committer | Ilya Dryomov <idryomov@gmail.com> | 2017-09-06 13:56:56 -0400 |
commit | 05455e1177f76849e0a6450e8710dcb2c361f337 (patch) | |
tree | 36e9f53c9a7715c3dafd72e2981933d45f42f0c3 | |
parent | 1f934b00e907527cddb83984d0783cc4a029952a (diff) |
ceph: make writepage_nounlock() invalidate page that beyonds EOF
Otherwise, the page left in state that page is associated with a
snapc, but (PageDirty(page) || PageWriteback(page)) is false.
Signed-off-by: "Yan, Zheng" <zyan@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
-rw-r--r-- | fs/ceph/addr.c | 50 |
1 files changed, 32 insertions, 18 deletions
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index 03a1ee27b33c..8526359c08b2 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c | |||
@@ -476,7 +476,8 @@ struct ceph_writeback_ctl | |||
476 | * only snap context we are allowed to write back. | 476 | * only snap context we are allowed to write back. |
477 | */ | 477 | */ |
478 | static struct ceph_snap_context * | 478 | static struct ceph_snap_context * |
479 | get_oldest_context(struct inode *inode, struct ceph_writeback_ctl *ctl) | 479 | get_oldest_context(struct inode *inode, struct ceph_writeback_ctl *ctl, |
480 | struct ceph_snap_context *page_snapc) | ||
480 | { | 481 | { |
481 | struct ceph_inode_info *ci = ceph_inode(inode); | 482 | struct ceph_inode_info *ci = ceph_inode(inode); |
482 | struct ceph_snap_context *snapc = NULL; | 483 | struct ceph_snap_context *snapc = NULL; |
@@ -486,21 +487,33 @@ get_oldest_context(struct inode *inode, struct ceph_writeback_ctl *ctl) | |||
486 | list_for_each_entry(capsnap, &ci->i_cap_snaps, ci_item) { | 487 | list_for_each_entry(capsnap, &ci->i_cap_snaps, ci_item) { |
487 | dout(" cap_snap %p snapc %p has %d dirty pages\n", capsnap, | 488 | dout(" cap_snap %p snapc %p has %d dirty pages\n", capsnap, |
488 | capsnap->context, capsnap->dirty_pages); | 489 | capsnap->context, capsnap->dirty_pages); |
489 | if (capsnap->dirty_pages) { | 490 | if (!capsnap->dirty_pages) |
490 | snapc = ceph_get_snap_context(capsnap->context); | 491 | continue; |
491 | if (ctl) { | 492 | |
492 | if (capsnap->writing) { | 493 | /* get i_size, truncate_{seq,size} for page_snapc? */ |
493 | ctl->i_size = i_size_read(inode); | 494 | if (snapc && capsnap->context != page_snapc) |
494 | ctl->size_stable = false; | 495 | continue; |
495 | } else { | 496 | |
496 | ctl->i_size = capsnap->size; | 497 | if (ctl) { |
497 | ctl->size_stable = true; | 498 | if (capsnap->writing) { |
498 | } | 499 | ctl->i_size = i_size_read(inode); |
499 | ctl->truncate_size = capsnap->truncate_size; | 500 | ctl->size_stable = false; |
500 | ctl->truncate_seq = capsnap->truncate_seq; | 501 | } else { |
502 | ctl->i_size = capsnap->size; | ||
503 | ctl->size_stable = true; | ||
501 | } | 504 | } |
502 | break; | 505 | ctl->truncate_size = capsnap->truncate_size; |
506 | ctl->truncate_seq = capsnap->truncate_seq; | ||
503 | } | 507 | } |
508 | |||
509 | if (snapc) | ||
510 | break; | ||
511 | |||
512 | snapc = ceph_get_snap_context(capsnap->context); | ||
513 | if (!page_snapc || | ||
514 | page_snapc == snapc || | ||
515 | page_snapc->seq > snapc->seq) | ||
516 | break; | ||
504 | } | 517 | } |
505 | if (!snapc && ci->i_wrbuffer_ref_head) { | 518 | if (!snapc && ci->i_wrbuffer_ref_head) { |
506 | snapc = ceph_get_snap_context(ci->i_head_snapc); | 519 | snapc = ceph_get_snap_context(ci->i_head_snapc); |
@@ -573,7 +586,7 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc) | |||
573 | dout("writepage %p page %p not dirty?\n", inode, page); | 586 | dout("writepage %p page %p not dirty?\n", inode, page); |
574 | return 0; | 587 | return 0; |
575 | } | 588 | } |
576 | oldest = get_oldest_context(inode, &ceph_wbc); | 589 | oldest = get_oldest_context(inode, &ceph_wbc, snapc); |
577 | if (snapc->seq > oldest->seq) { | 590 | if (snapc->seq > oldest->seq) { |
578 | dout("writepage %p page %p snapc %p not writeable - noop\n", | 591 | dout("writepage %p page %p snapc %p not writeable - noop\n", |
579 | inode, page, snapc); | 592 | inode, page, snapc); |
@@ -588,6 +601,7 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc) | |||
588 | /* is this a partial page at end of file? */ | 601 | /* is this a partial page at end of file? */ |
589 | if (page_off >= ceph_wbc.i_size) { | 602 | if (page_off >= ceph_wbc.i_size) { |
590 | dout("%p page eof %llu\n", page, ceph_wbc.i_size); | 603 | dout("%p page eof %llu\n", page, ceph_wbc.i_size); |
604 | page->mapping->a_ops->invalidatepage(page, 0, PAGE_SIZE); | ||
591 | return 0; | 605 | return 0; |
592 | } | 606 | } |
593 | 607 | ||
@@ -816,7 +830,7 @@ static int ceph_writepages_start(struct address_space *mapping, | |||
816 | retry: | 830 | retry: |
817 | /* find oldest snap context with dirty data */ | 831 | /* find oldest snap context with dirty data */ |
818 | ceph_put_snap_context(snapc); | 832 | ceph_put_snap_context(snapc); |
819 | snapc = get_oldest_context(inode, &ceph_wbc); | 833 | snapc = get_oldest_context(inode, &ceph_wbc, NULL); |
820 | if (!snapc) { | 834 | if (!snapc) { |
821 | /* hmm, why does writepages get called when there | 835 | /* hmm, why does writepages get called when there |
822 | is no dirty data? */ | 836 | is no dirty data? */ |
@@ -1162,7 +1176,7 @@ out: | |||
1162 | static int context_is_writeable_or_written(struct inode *inode, | 1176 | static int context_is_writeable_or_written(struct inode *inode, |
1163 | struct ceph_snap_context *snapc) | 1177 | struct ceph_snap_context *snapc) |
1164 | { | 1178 | { |
1165 | struct ceph_snap_context *oldest = get_oldest_context(inode, NULL); | 1179 | struct ceph_snap_context *oldest = get_oldest_context(inode, NULL, NULL); |
1166 | int ret = !oldest || snapc->seq <= oldest->seq; | 1180 | int ret = !oldest || snapc->seq <= oldest->seq; |
1167 | 1181 | ||
1168 | ceph_put_snap_context(oldest); | 1182 | ceph_put_snap_context(oldest); |
@@ -1207,7 +1221,7 @@ retry_locked: | |||
1207 | * this page is already dirty in another (older) snap | 1221 | * this page is already dirty in another (older) snap |
1208 | * context! is it writeable now? | 1222 | * context! is it writeable now? |
1209 | */ | 1223 | */ |
1210 | oldest = get_oldest_context(inode, NULL); | 1224 | oldest = get_oldest_context(inode, NULL, NULL); |
1211 | if (snapc->seq > oldest->seq) { | 1225 | if (snapc->seq > oldest->seq) { |
1212 | ceph_put_snap_context(oldest); | 1226 | ceph_put_snap_context(oldest); |
1213 | dout(" page %p snapc %p not current or oldest\n", | 1227 | dout(" page %p snapc %p not current or oldest\n", |