return rc;
}
+/**
+ * make page ready for ASYNC write
+ * \param data - pointer to llap cookie
+ * \param cmd - is OBD_BRW_* macroses
+ *
+ * \retval 0 is page successfully prepared to send
+ * \retval -EAGAIN is page not need to send
+ */
static int ll_ap_make_ready(void *data, int cmd)
{
struct ll_async_page *llap;
llap = LLAP_FROM_COOKIE(data);
page = llap->llap_page;
- LASSERTF(!(cmd & OBD_BRW_READ), "cmd %x page %p ino %lu index %lu\n", cmd, page,
- page->mapping->host->i_ino, page->index);
-
/* we're trying to write, but the page is locked.. come back later */
if (TryLockPage(page))
RETURN(-EAGAIN);
- LASSERT(!PageWriteback(page));
+ LASSERTF(!(cmd & OBD_BRW_READ) || !PageWriteback(page),
+ "cmd %x page %p ino %lu index %lu fl %lx\n", cmd, page,
+ page->mapping->host->i_ino, page->index, page->flags);
/* if we left PageDirty we might get another writepage call
* in the future. list walkers are bright enough
* cli lock */
LASSERTF(!PageWriteback(page),"cmd %x page %p ino %lu index %lu\n", cmd, page,
page->mapping->host->i_ino, page->index);
- clear_page_dirty_for_io(page);
+ if(!clear_page_dirty_for_io(page)) {
+ unlock_page(page);
+ RETURN(-EAGAIN);
+ }
/* This actually clears the dirty bit in the radix tree.*/
set_page_writeback(page);
if (!rc && async_flags & ASYNC_READY) {
unlock_page(llap->llap_page);
- if (PageWriteback(llap->llap_page)) {
+ if (PageWriteback(llap->llap_page))
end_page_writeback(llap->llap_page);
- }
}
if (rc == 0 && llap_write_complete(inode, llap))
set_bit(AS_EIO, &page->mapping->flags);
}
+ /* be carefull about clear WB.
+ * if WB will cleared after page lock is released - paralel IO can be
+ * started before ap_make_ready is finished - so we will be have page
+ * with PG_Writeback set from ->writepage() and completed READ which
+ * clear this flag */
+ if ((cmd & OBD_BRW_WRITE) && PageWriteback(page))
+ end_page_writeback(page);
+
unlock_page(page);
if (cmd & OBD_BRW_WRITE) {
ll_queue_done_writing(page->mapping->host, 0);
}
- if (PageWriteback(page)) {
- end_page_writeback(page);
- }
page_cache_release(page);
RETURN(ret);
rc = queue_or_sync_write(exp, inode, llap, CFS_PAGE_SIZE,
ASYNC_READY | ASYNC_URGENT);
}
- if (rc)
- page_cache_release(page);
-out:
if (rc) {
- if (!lli->lli_async_rc)
- lli->lli_async_rc = rc;
/* re-dirty page on error so it retries write */
- if (PageWriteback(page)) {
+ if (PageWriteback(page))
end_page_writeback(page);
- }
+
/* resend page only for not started IO*/
if (!PageError(page))
ll_redirty_page(page);
+
+ page_cache_release(page);
+ }
+out:
+ if (rc) {
+ if (!lli->lli_async_rc)
+ lli->lli_async_rc = rc;
+ /* resend page only for not started IO*/
unlock_page(page);
}
RETURN(rc);
/* the loi lock is held across this function but it's allowed to release
* and reacquire it during its work */
+/**
+ * prepare pages for ASYNC io and put pages in send queue.
+ *
+ * \param cli -
+ * \param loi -
+ * \param cmd - OBD_BRW_* macroses
+ * \param lop - pending pages
+ *
+ * \return zero if pages successfully add to send queue.
+ * \return not zere if error occurring.
+ */
static int osc_send_oap_rpc(struct client_obd *cli, struct lov_oinfo *loi,
int cmd, struct loi_oap_pages *lop)
{
/*
* Page submitted for IO has to be locked. Either by
* ->ap_make_ready() or by higher layers.
- *
- * XXX nikita: this assertion should be adjusted when lustre
- * starts using PG_writeback for pages being written out.
*/
#if defined(__KERNEL__) && defined(__linux__)
- LASSERT(PageLocked(oap->oap_page));
+ if(!(PageLocked(oap->oap_page) &&
+ (CheckWriteback(oap->oap_page, cmd) || oap->oap_oig !=NULL))) {
+ CDEBUG(D_PAGE, "page %p lost wb %lx/%x\n",
+ oap->oap_page, (long)oap->oap_page->flags, oap->oap_async_flags);
+ LBUG();
+ }
#endif
/* If there is a gap at the start of this page, it can't merge
* with any previous page, so we'll hand the network a