summaryrefslogtreecommitdiff
path: root/fs/ceph/snap.c
diff options
context:
space:
mode:
authorSage Weil <sage@newdream.net>2010-04-01 09:33:46 -0700
committerSage Weil <sage@newdream.net>2010-04-01 09:34:38 -0700
commit819ccbfa448403992ceafc05d6d7097aaa74d4c3 (patch)
treee6b3592fd85fbb35a63d6d10c84a8d01913eddab /fs/ceph/snap.c
parent6298a33757ba7361bb8f506c106daad77e5ac8cf (diff)
downloadlinux-3.10-819ccbfa448403992ceafc05d6d7097aaa74d4c3.tar.gz
linux-3.10-819ccbfa448403992ceafc05d6d7097aaa74d4c3.tar.bz2
linux-3.10-819ccbfa448403992ceafc05d6d7097aaa74d4c3.zip
ceph: fix leaked inode ref due to snap metadata writeback race
We create a ceph_cap_snap if there is dirty cap metadata (for writeback to mds) OR dirty pages (for writeback to osd). It is thus possible that the metadata has been written back to the MDS but the OSD data has not when the cap_snap is created. This results in a cap_snap with dirty(caps) == 0. The problem is that cap writeback to the MDS isn't necessary, and a FLUSHSNAP cap op gets no ack from the MDS. This leaves the cap_snap attached to the inode along with its inode reference. Fix the problem by dropping the cap_snap if it becomes 'complete' (all pages written out) and dirty(caps) == 0 in ceph_put_wrbuffer_cap_refs(). Also, BUG() in __ceph_flush_snaps() if we encounter a cap_snap with dirty(caps) == 0. Signed-off-by: Sage Weil <sage@newdream.net>
Diffstat (limited to 'fs/ceph/snap.c')
-rw-r--r--fs/ceph/snap.c10
1 files changed, 6 insertions, 4 deletions
diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c
index df04e210a05..7e3e5f9edaa 100644
--- a/fs/ceph/snap.c
+++ b/fs/ceph/snap.c
@@ -521,15 +521,17 @@ int __ceph_finish_cap_snap(struct ceph_inode_info *ci,
capsnap->ctime = inode->i_ctime;
capsnap->time_warp_seq = ci->i_time_warp_seq;
if (capsnap->dirty_pages) {
- dout("finish_cap_snap %p cap_snap %p snapc %p %llu s=%llu "
+ dout("finish_cap_snap %p cap_snap %p snapc %p %llu %s s=%llu "
"still has %d dirty pages\n", inode, capsnap,
capsnap->context, capsnap->context->seq,
- capsnap->size, capsnap->dirty_pages);
+ ceph_cap_string(capsnap->dirty), capsnap->size,
+ capsnap->dirty_pages);
return 0;
}
- dout("finish_cap_snap %p cap_snap %p snapc %p %llu s=%llu clean\n",
+ dout("finish_cap_snap %p cap_snap %p snapc %p %llu %s s=%llu\n",
inode, capsnap, capsnap->context,
- capsnap->context->seq, capsnap->size);
+ capsnap->context->seq, ceph_cap_string(capsnap->dirty),
+ capsnap->size);
spin_lock(&mdsc->snap_flush_lock);
list_add_tail(&ci->i_snap_flush_item, &mdsc->snap_flush_list);