]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - mm/zsmalloc.c
Merge branch 'drm-rockchip-next-fixes-2016-01-22' of https://github.com/markyzq/kerne...
[karo-tx-linux.git] / mm / zsmalloc.c
index 9f15bdd9163c2360edf2e070023b6099b683a85c..2d7c4c11fc635d3822d64e8b2d796414945305f7 100644 (file)
@@ -213,10 +213,10 @@ struct size_class {
        int size;
        unsigned int index;
 
-       /* Number of PAGE_SIZE sized pages to combine to form a 'zspage' */
-       int pages_per_zspage;
        struct zs_size_stat stats;
 
+       /* Number of PAGE_SIZE sized pages to combine to form a 'zspage' */
+       int pages_per_zspage;
        /* huge object: pages_per_zspage == 1 && maxobj_per_zspage == 1 */
        bool huge;
 };
@@ -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);