-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
staging: erofs: add a generic z_erofs VLE decompressor
Currently, this patch only simply implements LZ4 decompressor due to its development priority. In the future, erofs will support more compression algorithm and format other than LZ4, thus a generic decompressor interface will be needed. Signed-off-by: Gao Xiang <gaoxiang25@huawei.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
- Loading branch information
Gao Xiang
authored and
Greg Kroah-Hartman
committed
Jul 27, 2018
1 parent
366c96a
commit 0d40d6e
Showing
5 changed files
with
264 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
/* SPDX-License-Identifier: GPL-2.0 | ||
* | ||
* linux/drivers/staging/erofs/unzip_vle.h | ||
* | ||
* Copyright (C) 2018 HUAWEI, Inc. | ||
* http://www.huawei.com/ | ||
* Created by Gao Xiang <gaoxiang25@huawei.com> | ||
* | ||
* This file is subject to the terms and conditions of the GNU General Public | ||
* License. See the file COPYING in the main directory of the Linux | ||
* distribution for more details. | ||
*/ | ||
#ifndef __EROFS_FS_UNZIP_VLE_H | ||
#define __EROFS_FS_UNZIP_VLE_H | ||
|
||
#include "internal.h" | ||
|
||
#define Z_EROFS_VLE_INLINE_PAGEVECS 3 | ||
|
||
/* unzip_vle_lz4.c */ | ||
extern int z_erofs_vle_plain_copy(struct page **compressed_pages, | ||
unsigned clusterpages, struct page **pages, | ||
unsigned nr_pages, unsigned short pageofs); | ||
|
||
extern int z_erofs_vle_unzip_fast_percpu(struct page **compressed_pages, | ||
unsigned clusterpages, struct page **pages, | ||
unsigned outlen, unsigned short pageofs, | ||
void (*endio)(struct page *)); | ||
|
||
extern int z_erofs_vle_unzip_vmap(struct page **compressed_pages, | ||
unsigned clusterpages, void *vaddr, unsigned llen, | ||
unsigned short pageofs, bool overlapped); | ||
|
||
#endif | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,209 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
/* | ||
* linux/drivers/staging/erofs/unzip_vle_lz4.c | ||
* | ||
* Copyright (C) 2018 HUAWEI, Inc. | ||
* http://www.huawei.com/ | ||
* Created by Gao Xiang <gaoxiang25@huawei.com> | ||
* | ||
* This file is subject to the terms and conditions of the GNU General Public | ||
* License. See the file COPYING in the main directory of the Linux | ||
* distribution for more details. | ||
*/ | ||
#include "unzip_vle.h" | ||
|
||
#if Z_EROFS_CLUSTER_MAX_PAGES > Z_EROFS_VLE_INLINE_PAGEVECS | ||
#define EROFS_PERCPU_NR_PAGES Z_EROFS_CLUSTER_MAX_PAGES | ||
#else | ||
#define EROFS_PERCPU_NR_PAGES Z_EROFS_VLE_INLINE_PAGEVECS | ||
#endif | ||
|
||
static struct { | ||
char data[PAGE_SIZE * EROFS_PERCPU_NR_PAGES]; | ||
} erofs_pcpubuf[NR_CPUS]; | ||
|
||
int z_erofs_vle_plain_copy(struct page **compressed_pages, | ||
unsigned clusterpages, | ||
struct page **pages, | ||
unsigned nr_pages, | ||
unsigned short pageofs) | ||
{ | ||
unsigned i, j; | ||
void *src = NULL; | ||
const unsigned righthalf = PAGE_SIZE - pageofs; | ||
char *percpu_data; | ||
bool mirrored[Z_EROFS_CLUSTER_MAX_PAGES] = { 0 }; | ||
|
||
preempt_disable(); | ||
percpu_data = erofs_pcpubuf[smp_processor_id()].data; | ||
|
||
j = 0; | ||
for (i = 0; i < nr_pages; j = i++) { | ||
struct page *page = pages[i]; | ||
void *dst; | ||
|
||
if (page == NULL) { | ||
if (src != NULL) { | ||
if (!mirrored[j]) | ||
kunmap_atomic(src); | ||
src = NULL; | ||
} | ||
continue; | ||
} | ||
|
||
dst = kmap_atomic(page); | ||
|
||
for (; j < clusterpages; ++j) { | ||
if (compressed_pages[j] != page) | ||
continue; | ||
|
||
BUG_ON(mirrored[j]); | ||
memcpy(percpu_data + j * PAGE_SIZE, dst, PAGE_SIZE); | ||
mirrored[j] = true; | ||
break; | ||
} | ||
|
||
if (i) { | ||
if (src == NULL) | ||
src = mirrored[i-1] ? | ||
percpu_data + (i-1) * PAGE_SIZE : | ||
kmap_atomic(compressed_pages[i-1]); | ||
|
||
memcpy(dst, src + righthalf, pageofs); | ||
|
||
if (!mirrored[i-1]) | ||
kunmap_atomic(src); | ||
|
||
if (unlikely(i >= clusterpages)) { | ||
kunmap_atomic(dst); | ||
break; | ||
} | ||
} | ||
|
||
if (!righthalf) | ||
src = NULL; | ||
else { | ||
src = mirrored[i] ? percpu_data + i * PAGE_SIZE : | ||
kmap_atomic(compressed_pages[i]); | ||
|
||
memcpy(dst + pageofs, src, righthalf); | ||
} | ||
|
||
kunmap_atomic(dst); | ||
} | ||
|
||
if (src != NULL && !mirrored[j]) | ||
kunmap_atomic(src); | ||
|
||
preempt_enable(); | ||
return 0; | ||
} | ||
|
||
extern int z_erofs_unzip_lz4(void *in, void *out, size_t inlen, size_t outlen); | ||
|
||
int z_erofs_vle_unzip_fast_percpu(struct page **compressed_pages, | ||
unsigned clusterpages, | ||
struct page **pages, | ||
unsigned outlen, | ||
unsigned short pageofs, | ||
void (*endio)(struct page *)) | ||
{ | ||
void *vin, *vout; | ||
unsigned nr_pages, i, j; | ||
int ret; | ||
|
||
if (outlen + pageofs > EROFS_PERCPU_NR_PAGES * PAGE_SIZE) | ||
return -ENOTSUPP; | ||
|
||
nr_pages = DIV_ROUND_UP(outlen + pageofs, PAGE_SIZE); | ||
|
||
if (clusterpages == 1) | ||
vin = kmap_atomic(compressed_pages[0]); | ||
else | ||
vin = erofs_vmap(compressed_pages, clusterpages); | ||
|
||
preempt_disable(); | ||
vout = erofs_pcpubuf[smp_processor_id()].data; | ||
|
||
ret = z_erofs_unzip_lz4(vin, vout + pageofs, | ||
clusterpages * PAGE_SIZE, outlen); | ||
|
||
if (ret >= 0) { | ||
outlen = ret; | ||
ret = 0; | ||
} | ||
|
||
for (i = 0; i < nr_pages; ++i) { | ||
j = min((unsigned)PAGE_SIZE - pageofs, outlen); | ||
|
||
if (pages[i] != NULL) { | ||
if (ret < 0) | ||
SetPageError(pages[i]); | ||
else if (clusterpages == 1 && pages[i] == compressed_pages[0]) | ||
memcpy(vin + pageofs, vout + pageofs, j); | ||
else { | ||
void *dst = kmap_atomic(pages[i]); | ||
|
||
memcpy(dst + pageofs, vout + pageofs, j); | ||
kunmap_atomic(dst); | ||
} | ||
endio(pages[i]); | ||
} | ||
vout += PAGE_SIZE; | ||
outlen -= j; | ||
pageofs = 0; | ||
} | ||
preempt_enable(); | ||
|
||
if (clusterpages == 1) | ||
kunmap_atomic(vin); | ||
else | ||
erofs_vunmap(vin, clusterpages); | ||
|
||
return ret; | ||
} | ||
|
||
int z_erofs_vle_unzip_vmap(struct page **compressed_pages, | ||
unsigned clusterpages, | ||
void *vout, | ||
unsigned llen, | ||
unsigned short pageofs, | ||
bool overlapped) | ||
{ | ||
void *vin; | ||
unsigned i; | ||
int ret; | ||
|
||
if (overlapped) { | ||
preempt_disable(); | ||
vin = erofs_pcpubuf[smp_processor_id()].data; | ||
|
||
for (i = 0; i < clusterpages; ++i) { | ||
void *t = kmap_atomic(compressed_pages[i]); | ||
|
||
memcpy(vin + PAGE_SIZE *i, t, PAGE_SIZE); | ||
kunmap_atomic(t); | ||
} | ||
} else if (clusterpages == 1) | ||
vin = kmap_atomic(compressed_pages[0]); | ||
else { | ||
vin = erofs_vmap(compressed_pages, clusterpages); | ||
} | ||
|
||
ret = z_erofs_unzip_lz4(vin, vout + pageofs, | ||
clusterpages * PAGE_SIZE, llen); | ||
if (ret > 0) | ||
ret = 0; | ||
|
||
if (!overlapped) { | ||
if (clusterpages == 1) | ||
kunmap_atomic(vin); | ||
else { | ||
erofs_vunmap(vin, clusterpages); | ||
} | ||
} else | ||
preempt_enable(); | ||
|
||
return ret; | ||
} | ||
|