aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
Diffstat (limited to 'mm')
-rw-r--r--mm/zsmalloc.c14
1 files changed, 13 insertions, 1 deletions
diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c
index e7414cec220b..2d7c4c11fc63 100644
--- a/mm/zsmalloc.c
+++ b/mm/zsmalloc.c
@@ -309,7 +309,12 @@ static void free_handle(struct zs_pool *pool, unsigned long handle)
309 309
310static void record_obj(unsigned long handle, unsigned long obj) 310static void record_obj(unsigned long handle, unsigned long obj)
311{ 311{
312 *(unsigned long *)handle = obj; 312 /*
313 * lsb of @obj represents handle lock while other bits
314 * represent object value the handle is pointing so
315 * updating shouldn't do store tearing.
316 */
317 WRITE_ONCE(*(unsigned long *)handle, obj);
313} 318}
314 319
315/* zpool driver */ 320/* zpool driver */
@@ -1635,6 +1640,13 @@ static int migrate_zspage(struct zs_pool *pool, struct size_class *class,
1635 free_obj = obj_malloc(d_page, class, handle); 1640 free_obj = obj_malloc(d_page, class, handle);
1636 zs_object_copy(free_obj, used_obj, class); 1641 zs_object_copy(free_obj, used_obj, class);
1637 index++; 1642 index++;
1643 /*
1644 * record_obj updates handle's value to free_obj and it will
1645 * invalidate lock bit(ie, HANDLE_PIN_BIT) of handle, which
1646 * breaks synchronization using pin_tag(e,g, zs_free) so
1647 * let's keep the lock bit.
1648 */
1649 free_obj |= BIT(HANDLE_PIN_BIT);
1638 record_obj(handle, free_obj); 1650 record_obj(handle, free_obj);
1639 unpin_tag(handle); 1651 unpin_tag(handle);
1640 obj_free(pool, class, used_obj); 1652 obj_free(pool, class, used_obj);