diff options
| -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", |
