1
0
Fork 0

ceph: record truncate size/seq for snap data writeback

Dirty snapshot data needs to be flushed unconditionally. If they
were created before truncation, writeback should use old truncate
size/seq.

Signed-off-by: Yan, Zheng <zyan@redhat.com>
hifive-unleashed-5.1
Yan, Zheng 2016-11-15 16:04:37 +08:00 committed by Ilya Dryomov
parent e9e427f0a1
commit 5f743e4566
3 changed files with 22 additions and 13 deletions

View File

@ -474,7 +474,9 @@ out:
* only snap context we are allowed to write back. * only snap context we are allowed to write back.
*/ */
static struct ceph_snap_context *get_oldest_context(struct inode *inode, static struct ceph_snap_context *get_oldest_context(struct inode *inode,
loff_t *snap_size) loff_t *snap_size,
u64 *truncate_size,
u32 *truncate_seq)
{ {
struct ceph_inode_info *ci = ceph_inode(inode); struct ceph_inode_info *ci = ceph_inode(inode);
struct ceph_snap_context *snapc = NULL; struct ceph_snap_context *snapc = NULL;
@ -488,6 +490,10 @@ static struct ceph_snap_context *get_oldest_context(struct inode *inode,
snapc = ceph_get_snap_context(capsnap->context); snapc = ceph_get_snap_context(capsnap->context);
if (snap_size) if (snap_size)
*snap_size = capsnap->size; *snap_size = capsnap->size;
if (truncate_size)
*truncate_size = capsnap->truncate_size;
if (truncate_seq)
*truncate_seq = capsnap->truncate_seq;
break; break;
} }
} }
@ -495,6 +501,10 @@ static struct ceph_snap_context *get_oldest_context(struct inode *inode,
snapc = ceph_get_snap_context(ci->i_head_snapc); snapc = ceph_get_snap_context(ci->i_head_snapc);
dout(" head snapc %p has %d dirty pages\n", dout(" head snapc %p has %d dirty pages\n",
snapc, ci->i_wrbuffer_ref_head); snapc, ci->i_wrbuffer_ref_head);
if (truncate_size)
*truncate_size = capsnap->truncate_size;
if (truncate_seq)
*truncate_seq = capsnap->truncate_seq;
} }
spin_unlock(&ci->i_ceph_lock); spin_unlock(&ci->i_ceph_lock);
return snapc; return snapc;
@ -537,7 +547,8 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc)
dout("writepage %p page %p not dirty?\n", inode, page); dout("writepage %p page %p not dirty?\n", inode, page);
goto out; goto out;
} }
oldest = get_oldest_context(inode, &snap_size); oldest = get_oldest_context(inode, &snap_size,
&truncate_size, &truncate_seq);
if (snapc->seq > oldest->seq) { if (snapc->seq > oldest->seq) {
dout("writepage %p page %p snapc %p not writeable - noop\n", dout("writepage %p page %p snapc %p not writeable - noop\n",
inode, page, snapc); inode, page, snapc);
@ -548,12 +559,8 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc)
} }
ceph_put_snap_context(oldest); ceph_put_snap_context(oldest);
spin_lock(&ci->i_ceph_lock);
truncate_seq = ci->i_truncate_seq;
truncate_size = ci->i_truncate_size;
if (snap_size == -1) if (snap_size == -1)
snap_size = i_size_read(inode); snap_size = i_size_read(inode);
spin_unlock(&ci->i_ceph_lock);
/* is this a partial page at end of file? */ /* is this a partial page at end of file? */
if (page_off >= snap_size) { if (page_off >= snap_size) {
@ -800,7 +807,8 @@ retry:
/* find oldest snap context with dirty data */ /* find oldest snap context with dirty data */
ceph_put_snap_context(snapc); ceph_put_snap_context(snapc);
snap_size = -1; snap_size = -1;
snapc = get_oldest_context(inode, &snap_size); snapc = get_oldest_context(inode, &snap_size,
&truncate_size, &truncate_seq);
if (!snapc) { if (!snapc) {
/* hmm, why does writepages get called when there /* hmm, why does writepages get called when there
is no dirty data? */ is no dirty data? */
@ -810,11 +818,7 @@ retry:
dout(" oldest snapc is %p seq %lld (%d snaps)\n", dout(" oldest snapc is %p seq %lld (%d snaps)\n",
snapc, snapc->seq, snapc->num_snaps); snapc, snapc->seq, snapc->num_snaps);
spin_lock(&ci->i_ceph_lock);
truncate_seq = ci->i_truncate_seq;
truncate_size = ci->i_truncate_size;
i_size = i_size_read(inode); i_size = i_size_read(inode);
spin_unlock(&ci->i_ceph_lock);
if (last_snapc && snapc != last_snapc) { if (last_snapc && snapc != last_snapc) {
/* if we switched to a newer snapc, restart our scan at the /* if we switched to a newer snapc, restart our scan at the
@ -1160,7 +1164,8 @@ out:
static int context_is_writeable_or_written(struct inode *inode, static int context_is_writeable_or_written(struct inode *inode,
struct ceph_snap_context *snapc) struct ceph_snap_context *snapc)
{ {
struct ceph_snap_context *oldest = get_oldest_context(inode, NULL); struct ceph_snap_context *oldest = get_oldest_context(inode, NULL,
NULL, NULL);
int ret = !oldest || snapc->seq <= oldest->seq; int ret = !oldest || snapc->seq <= oldest->seq;
ceph_put_snap_context(oldest); ceph_put_snap_context(oldest);
@ -1205,7 +1210,7 @@ retry_locked:
* this page is already dirty in another (older) snap * this page is already dirty in another (older) snap
* context! is it writeable now? * context! is it writeable now?
*/ */
oldest = get_oldest_context(inode, NULL); oldest = get_oldest_context(inode, NULL, NULL, NULL);
if (snapc->seq > oldest->seq) { if (snapc->seq > oldest->seq) {
ceph_put_snap_context(oldest); ceph_put_snap_context(oldest);

View File

@ -593,6 +593,8 @@ int __ceph_finish_cap_snap(struct ceph_inode_info *ci,
capsnap->atime = inode->i_atime; capsnap->atime = inode->i_atime;
capsnap->ctime = inode->i_ctime; capsnap->ctime = inode->i_ctime;
capsnap->time_warp_seq = ci->i_time_warp_seq; capsnap->time_warp_seq = ci->i_time_warp_seq;
capsnap->truncate_size = ci->i_truncate_size;
capsnap->truncate_seq = ci->i_truncate_seq;
if (capsnap->dirty_pages) { if (capsnap->dirty_pages) {
dout("finish_cap_snap %p cap_snap %p snapc %p %llu %s s=%llu " dout("finish_cap_snap %p cap_snap %p snapc %p %llu %s s=%llu "
"still has %d dirty pages\n", inode, capsnap, "still has %d dirty pages\n", inode, capsnap,

View File

@ -181,6 +181,8 @@ struct ceph_cap_snap {
u64 size; u64 size;
struct timespec mtime, atime, ctime; struct timespec mtime, atime, ctime;
u64 time_warp_seq; u64 time_warp_seq;
u64 truncate_size;
u32 truncate_seq;
int writing; /* a sync write is still in progress */ int writing; /* a sync write is still in progress */
int dirty_pages; /* dirty pages awaiting writeback */ int dirty_pages; /* dirty pages awaiting writeback */
bool inline_data; bool inline_data;