diff options
author | Sage Weil <sage@newdream.net> | 2010-04-01 01:01:38 -0400 |
---|---|---|
committer | Sage Weil <sage@newdream.net> | 2010-04-01 12:34:37 -0400 |
commit | 6298a33757ba7361bb8f506c106daad77e5ac8cf (patch) | |
tree | ebd8e7cab86a66c00c0bd4f411c335ed4d0fda9f /fs/ceph | |
parent | 80e755fedebc8de0599a79efad2c656503df2e62 (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/ceph')
-rw-r--r-- | fs/ceph/addr.c | 37 |
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 | */ |
342 | static struct ceph_snap_context *__get_oldest_context(struct inode *inode, | 340 | static 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 | |||
367 | static 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 */ |
461 | out: | 453 | out: |
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", |