if (outpages > inpages) {
DBG_BUGON(!rq->out[outpages - 1]);
- if (rq->out[outpages - 1] != rq->in[inpages - 1]) {
+ if (rq->out[outpages - 1] != rq->in[inpages - 1])
memcpy_to_page(rq->out[outpages - 1], 0, src +
(interlaced_offset ? 0 : righthalf),
lefthalf);
- } else if (!interlaced_offset) {
+ else if (!interlaced_offset)
memmove(src, src + righthalf, lefthalf);
- flush_dcache_page(rq->in[inpages - 1]);
- }
}
kunmap_local(src);
return 0;
/*
* bit 30: I/O error occurred on this page
+ * bit 29: CPU has dirty data in D-cache (needs aliasing handling);
* bit 0 - 29: remaining parts to complete this page
*/
-#define Z_EROFS_PAGE_EIO (1 << 30)
+#define Z_EROFS_ONLINEPAGE_EIO 30
+#define Z_EROFS_ONLINEPAGE_DIRTY 29
static inline void z_erofs_onlinepage_init(struct page *page)
{
atomic_inc((atomic_t *)&page->private);
}
-static void z_erofs_onlinepage_endio(struct page *page, int err)
+static void z_erofs_onlinepage_end(struct page *page, int err, bool dirty)
{
int orig, v;
do {
orig = atomic_read((atomic_t *)&page->private);
- v = (orig - 1) | (err ? Z_EROFS_PAGE_EIO : 0);
+ DBG_BUGON(orig <= 0);
+ v = dirty << Z_EROFS_ONLINEPAGE_DIRTY;
+ v |= (orig - 1) | (!!err << Z_EROFS_ONLINEPAGE_EIO);
} while (atomic_cmpxchg((atomic_t *)&page->private, orig, v) != orig);
- if (!(v & ~Z_EROFS_PAGE_EIO)) {
- set_page_private(page, 0);
- ClearPagePrivate(page);
- if (!(v & Z_EROFS_PAGE_EIO))
- SetPageUptodate(page);
- unlock_page(page);
- }
+ if (v & (BIT(Z_EROFS_ONLINEPAGE_DIRTY) - 1))
+ return;
+ set_page_private(page, 0);
+ ClearPagePrivate(page);
+ if (v & BIT(Z_EROFS_ONLINEPAGE_DIRTY))
+ flush_dcache_page(page);
+ if (!(v & BIT(Z_EROFS_ONLINEPAGE_EIO)))
+ SetPageUptodate(page);
+ unlock_page(page);
}
#define Z_EROFS_ONSTACK_PAGES 32
goto repeat;
out:
- z_erofs_onlinepage_endio(page, err);
+ z_erofs_onlinepage_end(page, err, false);
return err;
}
cur += len;
}
kunmap_local(dst);
- z_erofs_onlinepage_endio(bvi->bvec.page, err);
+ z_erofs_onlinepage_end(bvi->bvec.page, err, true);
list_del(p);
kfree(bvi);
}
/* recycle all individual short-lived pages */
if (z_erofs_put_shortlivedpage(be->pagepool, page))
continue;
- z_erofs_onlinepage_endio(page, err);
+ z_erofs_onlinepage_end(page, err, true);
}
if (be->decompressed_pages != be->onstack_pages)