Skip to content

Commit 05455e1

Browse files
ukernelidryomov
authored andcommitted
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" <[email protected]> Signed-off-by: Ilya Dryomov <[email protected]>
1 parent 1f934b0 commit 05455e1

File tree

1 file changed

+32
-18
lines changed

1 file changed

+32
-18
lines changed

fs/ceph/addr.c

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,8 @@ struct ceph_writeback_ctl
476476
* only snap context we are allowed to write back.
477477
*/
478478
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)
480481
{
481482
struct ceph_inode_info *ci = ceph_inode(inode);
482483
struct ceph_snap_context *snapc = NULL;
@@ -486,21 +487,33 @@ get_oldest_context(struct inode *inode, struct ceph_writeback_ctl *ctl)
486487
list_for_each_entry(capsnap, &ci->i_cap_snaps, ci_item) {
487488
dout(" cap_snap %p snapc %p has %d dirty pages\n", capsnap,
488489
capsnap->context, capsnap->dirty_pages);
489-
if (capsnap->dirty_pages) {
490-
snapc = ceph_get_snap_context(capsnap->context);
491-
if (ctl) {
492-
if (capsnap->writing) {
493-
ctl->i_size = i_size_read(inode);
494-
ctl->size_stable = false;
495-
} else {
496-
ctl->i_size = capsnap->size;
497-
ctl->size_stable = true;
498-
}
499-
ctl->truncate_size = capsnap->truncate_size;
500-
ctl->truncate_seq = capsnap->truncate_seq;
490+
if (!capsnap->dirty_pages)
491+
continue;
492+
493+
/* get i_size, truncate_{seq,size} for page_snapc? */
494+
if (snapc && capsnap->context != page_snapc)
495+
continue;
496+
497+
if (ctl) {
498+
if (capsnap->writing) {
499+
ctl->i_size = i_size_read(inode);
500+
ctl->size_stable = false;
501+
} else {
502+
ctl->i_size = capsnap->size;
503+
ctl->size_stable = true;
501504
}
502-
break;
505+
ctl->truncate_size = capsnap->truncate_size;
506+
ctl->truncate_seq = capsnap->truncate_seq;
503507
}
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;
504517
}
505518
if (!snapc && ci->i_wrbuffer_ref_head) {
506519
snapc = ceph_get_snap_context(ci->i_head_snapc);
@@ -573,7 +586,7 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc)
573586
dout("writepage %p page %p not dirty?\n", inode, page);
574587
return 0;
575588
}
576-
oldest = get_oldest_context(inode, &ceph_wbc);
589+
oldest = get_oldest_context(inode, &ceph_wbc, snapc);
577590
if (snapc->seq > oldest->seq) {
578591
dout("writepage %p page %p snapc %p not writeable - noop\n",
579592
inode, page, snapc);
@@ -588,6 +601,7 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc)
588601
/* is this a partial page at end of file? */
589602
if (page_off >= ceph_wbc.i_size) {
590603
dout("%p page eof %llu\n", page, ceph_wbc.i_size);
604+
page->mapping->a_ops->invalidatepage(page, 0, PAGE_SIZE);
591605
return 0;
592606
}
593607

@@ -816,7 +830,7 @@ static int ceph_writepages_start(struct address_space *mapping,
816830
retry:
817831
/* find oldest snap context with dirty data */
818832
ceph_put_snap_context(snapc);
819-
snapc = get_oldest_context(inode, &ceph_wbc);
833+
snapc = get_oldest_context(inode, &ceph_wbc, NULL);
820834
if (!snapc) {
821835
/* hmm, why does writepages get called when there
822836
is no dirty data? */
@@ -1162,7 +1176,7 @@ static int ceph_writepages_start(struct address_space *mapping,
11621176
static int context_is_writeable_or_written(struct inode *inode,
11631177
struct ceph_snap_context *snapc)
11641178
{
1165-
struct ceph_snap_context *oldest = get_oldest_context(inode, NULL);
1179+
struct ceph_snap_context *oldest = get_oldest_context(inode, NULL, NULL);
11661180
int ret = !oldest || snapc->seq <= oldest->seq;
11671181

11681182
ceph_put_snap_context(oldest);
@@ -1207,7 +1221,7 @@ static int ceph_update_writeable_page(struct file *file,
12071221
* this page is already dirty in another (older) snap
12081222
* context! is it writeable now?
12091223
*/
1210-
oldest = get_oldest_context(inode, NULL);
1224+
oldest = get_oldest_context(inode, NULL, NULL);
12111225
if (snapc->seq > oldest->seq) {
12121226
ceph_put_snap_context(oldest);
12131227
dout(" page %p snapc %p not current or oldest\n",

0 commit comments

Comments
 (0)