|
@@ -309,7 +309,12 @@ static void free_handle(struct zs_pool *pool, unsigned long handle)
|
|
|
|
|
|
static void record_obj(unsigned long handle, unsigned long obj)
|
|
|
{
|
|
|
- *(unsigned long *)handle = obj;
|
|
|
+ /*
|
|
|
+ * lsb of @obj represents handle lock while other bits
|
|
|
+ * represent object value the handle is pointing so
|
|
|
+ * updating shouldn't do store tearing.
|
|
|
+ */
|
|
|
+ WRITE_ONCE(*(unsigned long *)handle, obj);
|
|
|
}
|
|
|
|
|
|
/* zpool driver */
|
|
@@ -1635,6 +1640,13 @@ static int migrate_zspage(struct zs_pool *pool, struct size_class *class,
|
|
|
free_obj = obj_malloc(d_page, class, handle);
|
|
|
zs_object_copy(free_obj, used_obj, class);
|
|
|
index++;
|
|
|
+ /*
|
|
|
+ * record_obj updates handle's value to free_obj and it will
|
|
|
+ * invalidate lock bit(ie, HANDLE_PIN_BIT) of handle, which
|
|
|
+ * breaks synchronization using pin_tag(e,g, zs_free) so
|
|
|
+ * let's keep the lock bit.
|
|
|
+ */
|
|
|
+ free_obj |= BIT(HANDLE_PIN_BIT);
|
|
|
record_obj(handle, free_obj);
|
|
|
unpin_tag(handle);
|
|
|
obj_free(pool, class, used_obj);
|