ceph: queue_cap_snap should always queue dirty context

This simplifies the calling convention, and fixes a bug where we queue a
capsnap with a context other than i_head_snapc (the one that matches the
dirty pages).  The result was a BUG at fs/ceph/caps.c:2178 on writeback
completion when a capsnap matching the writeback snapc could not be found.

Signed-off-by: Sage Weil <sage@newdream.net>
This commit is contained in:
Sage Weil 2010-04-13 11:41:22 -07:00
parent f5b066287c
commit fc837c8f04
2 changed files with 8 additions and 11 deletions

View File

@ -430,8 +430,7 @@ static int dup_array(u64 **dst, __le64 *src, int num)
* Caller must hold snap_rwsem for read (i.e., the realm topology won't * Caller must hold snap_rwsem for read (i.e., the realm topology won't
* change). * change).
*/ */
void ceph_queue_cap_snap(struct ceph_inode_info *ci, void ceph_queue_cap_snap(struct ceph_inode_info *ci)
struct ceph_snap_context *snapc)
{ {
struct inode *inode = &ci->vfs_inode; struct inode *inode = &ci->vfs_inode;
struct ceph_cap_snap *capsnap; struct ceph_cap_snap *capsnap;
@ -450,10 +449,11 @@ void ceph_queue_cap_snap(struct ceph_inode_info *ci,
as no new writes are allowed to start when pending, so any as no new writes are allowed to start when pending, so any
writes in progress now were started before the previous writes in progress now were started before the previous
cap_snap. lucky us. */ cap_snap. lucky us. */
dout("queue_cap_snap %p snapc %p seq %llu used %d" dout("queue_cap_snap %p already pending\n", inode);
" already pending\n", inode, snapc, snapc->seq, used);
kfree(capsnap); kfree(capsnap);
} else if (ci->i_wrbuffer_ref_head || (used & CEPH_CAP_FILE_WR)) { } else if (ci->i_wrbuffer_ref_head || (used & CEPH_CAP_FILE_WR)) {
struct ceph_snap_context *snapc = ci->i_head_snapc;
igrab(inode); igrab(inode);
atomic_set(&capsnap->nref, 1); atomic_set(&capsnap->nref, 1);
@ -462,7 +462,6 @@ void ceph_queue_cap_snap(struct ceph_inode_info *ci,
INIT_LIST_HEAD(&capsnap->flushing_item); INIT_LIST_HEAD(&capsnap->flushing_item);
capsnap->follows = snapc->seq - 1; capsnap->follows = snapc->seq - 1;
capsnap->context = ceph_get_snap_context(snapc);
capsnap->issued = __ceph_caps_issued(ci, NULL); capsnap->issued = __ceph_caps_issued(ci, NULL);
capsnap->dirty = __ceph_caps_dirty(ci); capsnap->dirty = __ceph_caps_dirty(ci);
@ -479,7 +478,7 @@ void ceph_queue_cap_snap(struct ceph_inode_info *ci,
snapshot. */ snapshot. */
capsnap->dirty_pages = ci->i_wrbuffer_ref_head; capsnap->dirty_pages = ci->i_wrbuffer_ref_head;
ci->i_wrbuffer_ref_head = 0; ci->i_wrbuffer_ref_head = 0;
ceph_put_snap_context(ci->i_head_snapc); capsnap->context = snapc;
ci->i_head_snapc = NULL; ci->i_head_snapc = NULL;
list_add_tail(&capsnap->ci_item, &ci->i_cap_snaps); list_add_tail(&capsnap->ci_item, &ci->i_cap_snaps);
@ -603,7 +602,7 @@ int ceph_update_snap_trace(struct ceph_mds_client *mdsc,
if (lastinode) if (lastinode)
iput(lastinode); iput(lastinode);
lastinode = inode; lastinode = inode;
ceph_queue_cap_snap(ci, realm->cached_context); ceph_queue_cap_snap(ci);
spin_lock(&realm->inodes_with_caps_lock); spin_lock(&realm->inodes_with_caps_lock);
} }
spin_unlock(&realm->inodes_with_caps_lock); spin_unlock(&realm->inodes_with_caps_lock);
@ -825,8 +824,7 @@ void ceph_handle_snap(struct ceph_mds_client *mdsc,
spin_unlock(&realm->inodes_with_caps_lock); spin_unlock(&realm->inodes_with_caps_lock);
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
ceph_queue_cap_snap(ci, ceph_queue_cap_snap(ci);
ci->i_snap_realm->cached_context);
iput(inode); iput(inode);
continue; continue;

View File

@ -714,8 +714,7 @@ extern int ceph_update_snap_trace(struct ceph_mds_client *m,
extern void ceph_handle_snap(struct ceph_mds_client *mdsc, extern void ceph_handle_snap(struct ceph_mds_client *mdsc,
struct ceph_mds_session *session, struct ceph_mds_session *session,
struct ceph_msg *msg); struct ceph_msg *msg);
extern void ceph_queue_cap_snap(struct ceph_inode_info *ci, extern void ceph_queue_cap_snap(struct ceph_inode_info *ci);
struct ceph_snap_context *snapc);
extern int __ceph_finish_cap_snap(struct ceph_inode_info *ci, extern int __ceph_finish_cap_snap(struct ceph_inode_info *ci,
struct ceph_cap_snap *capsnap); struct ceph_cap_snap *capsnap);
extern void ceph_cleanup_empty_realms(struct ceph_mds_client *mdsc); extern void ceph_cleanup_empty_realms(struct ceph_mds_client *mdsc);