|
@@ -912,6 +912,29 @@ void add_page_wait_queue(struct page *page, wait_queue_t *waiter)
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(add_page_wait_queue);
|
|
EXPORT_SYMBOL_GPL(add_page_wait_queue);
|
|
|
|
|
|
|
|
+#ifndef clear_bit_unlock_is_negative_byte
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * PG_waiters is the high bit in the same byte as PG_lock.
|
|
|
|
+ *
|
|
|
|
+ * On x86 (and on many other architectures), we can clear PG_lock and
|
|
|
|
+ * test the sign bit at the same time. But if the architecture does
|
|
|
|
+ * not support that special operation, we just do this all by hand
|
|
|
|
+ * instead.
|
|
|
|
+ *
|
|
|
|
+ * The read of PG_waiters has to be after (or concurrently with) PG_locked
|
|
|
|
+ * being cleared, but a memory barrier should be unneccssary since it is
|
|
|
|
+ * in the same byte as PG_locked.
|
|
|
|
+ */
|
|
|
|
+static inline bool clear_bit_unlock_is_negative_byte(long nr, volatile void *mem)
|
|
|
|
+{
|
|
|
|
+ clear_bit_unlock(nr, mem);
|
|
|
|
+ /* smp_mb__after_atomic(); */
|
|
|
|
+ return test_bit(PG_waiters);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#endif
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* unlock_page - unlock a locked page
|
|
* unlock_page - unlock a locked page
|
|
* @page: the page
|
|
* @page: the page
|
|
@@ -921,16 +944,19 @@ EXPORT_SYMBOL_GPL(add_page_wait_queue);
|
|
* mechanism between PageLocked pages and PageWriteback pages is shared.
|
|
* mechanism between PageLocked pages and PageWriteback pages is shared.
|
|
* But that's OK - sleepers in wait_on_page_writeback() just go back to sleep.
|
|
* But that's OK - sleepers in wait_on_page_writeback() just go back to sleep.
|
|
*
|
|
*
|
|
- * The mb is necessary to enforce ordering between the clear_bit and the read
|
|
|
|
- * of the waitqueue (to avoid SMP races with a parallel wait_on_page_locked()).
|
|
|
|
|
|
+ * Note that this depends on PG_waiters being the sign bit in the byte
|
|
|
|
+ * that contains PG_locked - thus the BUILD_BUG_ON(). That allows us to
|
|
|
|
+ * clear the PG_locked bit and test PG_waiters at the same time fairly
|
|
|
|
+ * portably (architectures that do LL/SC can test any bit, while x86 can
|
|
|
|
+ * test the sign bit).
|
|
*/
|
|
*/
|
|
void unlock_page(struct page *page)
|
|
void unlock_page(struct page *page)
|
|
{
|
|
{
|
|
|
|
+ BUILD_BUG_ON(PG_waiters != 7);
|
|
page = compound_head(page);
|
|
page = compound_head(page);
|
|
VM_BUG_ON_PAGE(!PageLocked(page), page);
|
|
VM_BUG_ON_PAGE(!PageLocked(page), page);
|
|
- clear_bit_unlock(PG_locked, &page->flags);
|
|
|
|
- smp_mb__after_atomic();
|
|
|
|
- wake_up_page(page, PG_locked);
|
|
|
|
|
|
+ if (clear_bit_unlock_is_negative_byte(PG_locked, &page->flags))
|
|
|
|
+ wake_up_page_bit(page, PG_locked);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(unlock_page);
|
|
EXPORT_SYMBOL(unlock_page);
|
|
|
|
|