aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorSage Weil <sage@newdream.net>2010-04-01 01:01:38 -0400
committerSage Weil <sage@newdream.net>2010-04-01 12:34:37 -0400
commit6298a33757ba7361bb8f506c106daad77e5ac8cf (patch)
treeebd8e7cab86a66c00c0bd4f411c335ed4d0fda9f /fs
parent80e755fedebc8de0599a79efad2c656503df2e62 (diff)
ceph: fix snap context reference leaks
The get_oldest_context() helper takes a reference to the returned snap context, but most callers weren't dropping that reference. Fix them. Also drop the unused locked __get_oldest_context() variant. Signed-off-by: Sage Weil <sage@newdream.net>
Diffstat (limited to 'fs')
-rw-r--r--fs/ceph/addr.c37
1 files changed, 17 insertions, 20 deletions
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
index a313e9baeed0..41f1f713b7ba 100644
--- a/fs/ceph/addr.c
+++ b/fs/ceph/addr.c
@@ -336,16 +336,15 @@ out:
336/* 336/*
337 * Get ref for the oldest snapc for an inode with dirty data... that is, the 337 * Get ref for the oldest snapc for an inode with dirty data... that is, the
338 * only snap context we are allowed to write back. 338 * only snap context we are allowed to write back.
339 *
340 * Caller holds i_lock.
341 */ 339 */
342static struct ceph_snap_context *__get_oldest_context(struct inode *inode, 340static struct ceph_snap_context *get_oldest_context(struct inode *inode,
343 u64 *snap_size) 341 u64 *snap_size)
344{ 342{
345 struct ceph_inode_info *ci = ceph_inode(inode); 343 struct ceph_inode_info *ci = ceph_inode(inode);
346 struct ceph_snap_context *snapc = NULL; 344 struct ceph_snap_context *snapc = NULL;
347 struct ceph_cap_snap *capsnap = NULL; 345 struct ceph_cap_snap *capsnap = NULL;
348 346
347 spin_lock(&inode->i_lock);
349 list_for_each_entry(capsnap, &ci->i_cap_snaps, ci_item) { 348 list_for_each_entry(capsnap, &ci->i_cap_snaps, ci_item) {
350 dout(" cap_snap %p snapc %p has %d dirty pages\n", capsnap, 349 dout(" cap_snap %p snapc %p has %d dirty pages\n", capsnap,
351 capsnap->context, capsnap->dirty_pages); 350 capsnap->context, capsnap->dirty_pages);
@@ -361,16 +360,6 @@ static struct ceph_snap_context *__get_oldest_context(struct inode *inode,
361 dout(" head snapc %p has %d dirty pages\n", 360 dout(" head snapc %p has %d dirty pages\n",
362 snapc, ci->i_wrbuffer_ref_head); 361 snapc, ci->i_wrbuffer_ref_head);
363 } 362 }
364 return snapc;
365}
366
367static struct ceph_snap_context *get_oldest_context(struct inode *inode,
368 u64 *snap_size)
369{
370 struct ceph_snap_context *snapc = NULL;
371
372 spin_lock(&inode->i_lock);
373 snapc = __get_oldest_context(inode, snap_size);
374 spin_unlock(&inode->i_lock); 363 spin_unlock(&inode->i_lock);
375 return snapc; 364 return snapc;
376} 365}
@@ -391,7 +380,7 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc)
391 int len = PAGE_CACHE_SIZE; 380 int len = PAGE_CACHE_SIZE;
392 loff_t i_size; 381 loff_t i_size;
393 int err = 0; 382 int err = 0;
394 struct ceph_snap_context *snapc; 383 struct ceph_snap_context *snapc, *oldest;
395 u64 snap_size = 0; 384 u64 snap_size = 0;
396 long writeback_stat; 385 long writeback_stat;
397 386
@@ -412,13 +401,16 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc)
412 dout("writepage %p page %p not dirty?\n", inode, page); 401 dout("writepage %p page %p not dirty?\n", inode, page);
413 goto out; 402 goto out;
414 } 403 }
415 if (snapc->seq > get_oldest_context(inode, &snap_size)->seq) { 404 oldest = get_oldest_context(inode, &snap_size);
405 if (snapc->seq > oldest->seq) {
416 dout("writepage %p page %p snapc %p not writeable - noop\n", 406 dout("writepage %p page %p snapc %p not writeable - noop\n",
417 inode, page, (void *)page->private); 407 inode, page, (void *)page->private);
418 /* we should only noop if called by kswapd */ 408 /* we should only noop if called by kswapd */
419 WARN_ON((current->flags & PF_MEMALLOC) == 0); 409 WARN_ON((current->flags & PF_MEMALLOC) == 0);
410 ceph_put_snap_context(oldest);
420 goto out; 411 goto out;
421 } 412 }
413 ceph_put_snap_context(oldest);
422 414
423 /* is this a partial page at end of file? */ 415 /* is this a partial page at end of file? */
424 if (snap_size) 416 if (snap_size)
@@ -457,7 +449,7 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc)
457 ClearPagePrivate(page); 449 ClearPagePrivate(page);
458 end_page_writeback(page); 450 end_page_writeback(page);
459 ceph_put_wrbuffer_cap_refs(ci, 1, snapc); 451 ceph_put_wrbuffer_cap_refs(ci, 1, snapc);
460 ceph_put_snap_context(snapc); 452 ceph_put_snap_context(snapc); /* page's reference */
461out: 453out:
462 return err; 454 return err;
463} 455}
@@ -914,7 +906,10 @@ static int context_is_writeable_or_written(struct inode *inode,
914 struct ceph_snap_context *snapc) 906 struct ceph_snap_context *snapc)
915{ 907{
916 struct ceph_snap_context *oldest = get_oldest_context(inode, NULL); 908 struct ceph_snap_context *oldest = get_oldest_context(inode, NULL);
917 return !oldest || snapc->seq <= oldest->seq; 909 int ret = !oldest || snapc->seq <= oldest->seq;
910
911 ceph_put_snap_context(oldest);
912 return ret;
918} 913}
919 914
920/* 915/*
@@ -957,13 +952,14 @@ retry_locked:
957 up_read(&mdsc->snap_rwsem); 952 up_read(&mdsc->snap_rwsem);
958 953
959 if (snapc->seq > oldest->seq) { 954 if (snapc->seq > oldest->seq) {
955 ceph_put_snap_context(oldest);
960 dout(" page %p snapc %p not current or oldest\n", 956 dout(" page %p snapc %p not current or oldest\n",
961 page, (void *)page->private); 957 page, snapc);
962 /* 958 /*
963 * queue for writeback, and wait for snapc to 959 * queue for writeback, and wait for snapc to
964 * be writeable or written 960 * be writeable or written
965 */ 961 */
966 snapc = ceph_get_snap_context((void *)page->private); 962 snapc = ceph_get_snap_context(snapc);
967 unlock_page(page); 963 unlock_page(page);
968 ceph_queue_writeback(inode); 964 ceph_queue_writeback(inode);
969 r = wait_event_interruptible(ci->i_cap_wq, 965 r = wait_event_interruptible(ci->i_cap_wq,
@@ -973,6 +969,7 @@ retry_locked:
973 return r; 969 return r;
974 return -EAGAIN; 970 return -EAGAIN;
975 } 971 }
972 ceph_put_snap_context(oldest);
976 973
977 /* yay, writeable, do it now (without dropping page lock) */ 974 /* yay, writeable, do it now (without dropping page lock) */
978 dout(" page %p snapc %p not current, but oldest\n", 975 dout(" page %p snapc %p not current, but oldest\n",