[PATCH 2/5] Squashfs: refactor page_actor

2017-09-22 Thread Daniel Rosenberg
From: Adrien Schildknecht 

This patch essentially does 3 things:
  1/ Always use an array of page to store the data instead of a mix of
 buffers and pages.
  2/ It is now possible to have 'holes' in a page actor, i.e. NULL
 pages in the array.
 When reading a block (default 128K), squashfs tries to grab all
 the pages covering this block. If a single page is up-to-date or
 locked, it falls back to using an intermediate buffer to do the
 read and then copy the pages in the actor. Allowing holes in the
 page actor remove the need for this intermediate buffer.
  3/ Refactor the wrappers to share code that deals with page actors.

Signed-off-by: Adrien Schildknecht 
Signed-off-by: Daniel Rosenberg 
---
 fs/squashfs/cache.c  |  73 +++---
 fs/squashfs/decompressor.c   |  55 +++---
 fs/squashfs/file_direct.c|   4 +-
 fs/squashfs/lz4_wrapper.c|  29 +--
 fs/squashfs/lzo_wrapper.c|  40 ++
 fs/squashfs/page_actor.c | 175 ---
 fs/squashfs/page_actor.h |  52 +
 fs/squashfs/squashfs_fs_sb.h |   2 +-
 fs/squashfs/xz_wrapper.c |  15 +++-
 fs/squashfs/zlib_wrapper.c   |  14 +++-
 10 files changed, 251 insertions(+), 208 deletions(-)

diff --git a/fs/squashfs/cache.c b/fs/squashfs/cache.c
index 23813c078cc9..05e42441d106 100644
--- a/fs/squashfs/cache.c
+++ b/fs/squashfs/cache.c
@@ -209,17 +209,14 @@ void squashfs_cache_put(struct squashfs_cache_entry 
*entry)
  */
 void squashfs_cache_delete(struct squashfs_cache *cache)
 {
-   int i, j;
+   int i;
 
if (cache == NULL)
return;
 
for (i = 0; i < cache->entries; i++) {
-   if (cache->entry[i].data) {
-   for (j = 0; j < cache->pages; j++)
-   kfree(cache->entry[i].data[j]);
-   kfree(cache->entry[i].data);
-   }
+   if (cache->entry[i].page)
+   free_page_array(cache->entry[i].page, cache->pages);
kfree(cache->entry[i].actor);
}
 
@@ -236,7 +233,7 @@ void squashfs_cache_delete(struct squashfs_cache *cache)
 struct squashfs_cache *squashfs_cache_init(char *name, int entries,
int block_size)
 {
-   int i, j;
+   int i;
struct squashfs_cache *cache = kzalloc(sizeof(*cache), GFP_KERNEL);
 
if (cache == NULL) {
@@ -268,22 +265,13 @@ struct squashfs_cache *squashfs_cache_init(char *name, 
int entries,
init_waitqueue_head(>entry[i].wait_queue);
entry->cache = cache;
entry->block = SQUASHFS_INVALID_BLK;
-   entry->data = kcalloc(cache->pages, sizeof(void *), GFP_KERNEL);
-   if (entry->data == NULL) {
+   entry->page = alloc_page_array(cache->pages, GFP_KERNEL);
+   if (!entry->page) {
ERROR("Failed to allocate %s cache entry\n", name);
goto cleanup;
}
-
-   for (j = 0; j < cache->pages; j++) {
-   entry->data[j] = kmalloc(PAGE_SIZE, GFP_KERNEL);
-   if (entry->data[j] == NULL) {
-   ERROR("Failed to allocate %s buffer\n", name);
-   goto cleanup;
-   }
-   }
-
-   entry->actor = squashfs_page_actor_init(entry->data,
-   cache->pages, 0);
+   entry->actor = squashfs_page_actor_init(entry->page,
+   cache->pages, 0, NULL);
if (entry->actor == NULL) {
ERROR("Failed to allocate %s cache entry\n", name);
goto cleanup;
@@ -314,18 +302,20 @@ int squashfs_copy_data(void *buffer, struct 
squashfs_cache_entry *entry,
return min(length, entry->length - offset);
 
while (offset < entry->length) {
-   void *buff = entry->data[offset / PAGE_SIZE]
-   + (offset % PAGE_SIZE);
+   void *buff = kmap_atomic(entry->page[offset / PAGE_SIZE])
++ (offset % PAGE_SIZE);
int bytes = min_t(int, entry->length - offset,
PAGE_SIZE - (offset % PAGE_SIZE));
 
if (bytes >= remaining) {
memcpy(buffer, buff, remaining);
+   kunmap_atomic(buff);
remaining = 0;
break;
}
 
memcpy(buffer, buff, bytes);
+   kunmap_atomic(buff);
buffer += bytes;
remaining -= bytes;
offset += bytes;
@@ -416,43 +406,38 @@ struct squashfs_cache_entry 
*squashfs_get_datablock(struct super_block *sb,
 void *squashfs_read_table(struct 

[PATCH 2/5] Squashfs: refactor page_actor

2017-09-22 Thread Daniel Rosenberg
From: Adrien Schildknecht 

This patch essentially does 3 things:
  1/ Always use an array of page to store the data instead of a mix of
 buffers and pages.
  2/ It is now possible to have 'holes' in a page actor, i.e. NULL
 pages in the array.
 When reading a block (default 128K), squashfs tries to grab all
 the pages covering this block. If a single page is up-to-date or
 locked, it falls back to using an intermediate buffer to do the
 read and then copy the pages in the actor. Allowing holes in the
 page actor remove the need for this intermediate buffer.
  3/ Refactor the wrappers to share code that deals with page actors.

Signed-off-by: Adrien Schildknecht 
Signed-off-by: Daniel Rosenberg 
---
 fs/squashfs/cache.c  |  73 +++---
 fs/squashfs/decompressor.c   |  55 +++---
 fs/squashfs/file_direct.c|   4 +-
 fs/squashfs/lz4_wrapper.c|  29 +--
 fs/squashfs/lzo_wrapper.c|  40 ++
 fs/squashfs/page_actor.c | 175 ---
 fs/squashfs/page_actor.h |  52 +
 fs/squashfs/squashfs_fs_sb.h |   2 +-
 fs/squashfs/xz_wrapper.c |  15 +++-
 fs/squashfs/zlib_wrapper.c   |  14 +++-
 10 files changed, 251 insertions(+), 208 deletions(-)

diff --git a/fs/squashfs/cache.c b/fs/squashfs/cache.c
index 23813c078cc9..05e42441d106 100644
--- a/fs/squashfs/cache.c
+++ b/fs/squashfs/cache.c
@@ -209,17 +209,14 @@ void squashfs_cache_put(struct squashfs_cache_entry 
*entry)
  */
 void squashfs_cache_delete(struct squashfs_cache *cache)
 {
-   int i, j;
+   int i;
 
if (cache == NULL)
return;
 
for (i = 0; i < cache->entries; i++) {
-   if (cache->entry[i].data) {
-   for (j = 0; j < cache->pages; j++)
-   kfree(cache->entry[i].data[j]);
-   kfree(cache->entry[i].data);
-   }
+   if (cache->entry[i].page)
+   free_page_array(cache->entry[i].page, cache->pages);
kfree(cache->entry[i].actor);
}
 
@@ -236,7 +233,7 @@ void squashfs_cache_delete(struct squashfs_cache *cache)
 struct squashfs_cache *squashfs_cache_init(char *name, int entries,
int block_size)
 {
-   int i, j;
+   int i;
struct squashfs_cache *cache = kzalloc(sizeof(*cache), GFP_KERNEL);
 
if (cache == NULL) {
@@ -268,22 +265,13 @@ struct squashfs_cache *squashfs_cache_init(char *name, 
int entries,
init_waitqueue_head(>entry[i].wait_queue);
entry->cache = cache;
entry->block = SQUASHFS_INVALID_BLK;
-   entry->data = kcalloc(cache->pages, sizeof(void *), GFP_KERNEL);
-   if (entry->data == NULL) {
+   entry->page = alloc_page_array(cache->pages, GFP_KERNEL);
+   if (!entry->page) {
ERROR("Failed to allocate %s cache entry\n", name);
goto cleanup;
}
-
-   for (j = 0; j < cache->pages; j++) {
-   entry->data[j] = kmalloc(PAGE_SIZE, GFP_KERNEL);
-   if (entry->data[j] == NULL) {
-   ERROR("Failed to allocate %s buffer\n", name);
-   goto cleanup;
-   }
-   }
-
-   entry->actor = squashfs_page_actor_init(entry->data,
-   cache->pages, 0);
+   entry->actor = squashfs_page_actor_init(entry->page,
+   cache->pages, 0, NULL);
if (entry->actor == NULL) {
ERROR("Failed to allocate %s cache entry\n", name);
goto cleanup;
@@ -314,18 +302,20 @@ int squashfs_copy_data(void *buffer, struct 
squashfs_cache_entry *entry,
return min(length, entry->length - offset);
 
while (offset < entry->length) {
-   void *buff = entry->data[offset / PAGE_SIZE]
-   + (offset % PAGE_SIZE);
+   void *buff = kmap_atomic(entry->page[offset / PAGE_SIZE])
++ (offset % PAGE_SIZE);
int bytes = min_t(int, entry->length - offset,
PAGE_SIZE - (offset % PAGE_SIZE));
 
if (bytes >= remaining) {
memcpy(buffer, buff, remaining);
+   kunmap_atomic(buff);
remaining = 0;
break;
}
 
memcpy(buffer, buff, bytes);
+   kunmap_atomic(buff);
buffer += bytes;
remaining -= bytes;
offset += bytes;
@@ -416,43 +406,38 @@ struct squashfs_cache_entry 
*squashfs_get_datablock(struct super_block *sb,
 void *squashfs_read_table(struct super_block *sb, u64 block, int length)
 {
int pages =