diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/erofs/Kconfig | 15 | ||||
-rw-r--r-- | fs/erofs/decompress.c | 83 | ||||
-rw-r--r-- | fs/erofs/erofs_fs.h | 1 | ||||
-rw-r--r-- | fs/fat/fat.c | 2 | ||||
-rw-r--r-- | fs/fat/fat_write.c | 44 | ||||
-rw-r--r-- | fs/zfs/dev.c | 2 | ||||
-rw-r--r-- | fs/zfs/zfs.c | 30 |
7 files changed, 171 insertions, 6 deletions
diff --git a/fs/erofs/Kconfig b/fs/erofs/Kconfig index ee4e777c5c8..c8463357ca2 100644 --- a/fs/erofs/Kconfig +++ b/fs/erofs/Kconfig @@ -19,3 +19,18 @@ config FS_EROFS_ZIP help Enable fixed-sized output compression for EROFS. If you don't want to enable compression feature, say N. + +config FS_EROFS_ZIP_DEFLATE + bool "EROFS DEFLATE compressed data support" + depends on FS_EROFS_ZIP + select ZLIB + help + Saying Y here includes support for reading EROFS file systems + containing DEFLATE compressed data. It gives better compression + ratios than the default LZ4 format, while it costs more CPU + overhead. + + DEFLATE support is an experimental feature for now and so most + file systems will be readable without selecting this option. + + If unsure, say N. diff --git a/fs/erofs/decompress.c b/fs/erofs/decompress.c index e04e5c34a8d..ec74816534c 100644 --- a/fs/erofs/decompress.c +++ b/fs/erofs/decompress.c @@ -1,6 +1,85 @@ // SPDX-License-Identifier: GPL-2.0+ #include "decompress.h" +#if IS_ENABLED(CONFIG_ZLIB) +#include <u-boot/zlib.h> + +/* report a zlib or i/o error */ +static int zerr(int ret) +{ + switch (ret) { + case Z_STREAM_ERROR: + return -EINVAL; + case Z_DATA_ERROR: + return -EIO; + case Z_MEM_ERROR: + return -ENOMEM; + case Z_ERRNO: + default: + return -EFAULT; + } +} + +static int z_erofs_decompress_deflate(struct z_erofs_decompress_req *rq) +{ + u8 *dest = (u8 *)rq->out; + u8 *src = (u8 *)rq->in; + u8 *buff = NULL; + unsigned int inputmargin = 0; + z_stream strm; + int ret; + + while (!src[inputmargin & (erofs_blksiz() - 1)]) + if (!(++inputmargin & (erofs_blksiz() - 1))) + break; + + if (inputmargin >= rq->inputsize) + return -EFSCORRUPTED; + + if (rq->decodedskip) { + buff = malloc(rq->decodedlength); + if (!buff) + return -ENOMEM; + dest = buff; + } + + /* allocate inflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit2(&strm, -15); + if (ret != Z_OK) { + free(buff); + return zerr(ret); + } + + strm.next_in = src + inputmargin; + strm.avail_in = rq->inputsize - inputmargin; + strm.next_out = dest; + strm.avail_out = rq->decodedlength; + + ret = inflate(&strm, rq->partial_decoding ? Z_SYNC_FLUSH : Z_FINISH); + if (ret != Z_STREAM_END || strm.total_out != rq->decodedlength) { + if (ret != Z_OK || !rq->partial_decoding) { + ret = zerr(ret); + goto out_inflate_end; + } + } + + if (rq->decodedskip) + memcpy(rq->out, dest + rq->decodedskip, + rq->decodedlength - rq->decodedskip); + +out_inflate_end: + inflateEnd(&strm); + if (buff) + free(buff); + return ret; +} +#endif + #if IS_ENABLED(CONFIG_LZ4) #include <u-boot/lz4.h> static int z_erofs_decompress_lz4(struct z_erofs_decompress_req *rq) @@ -94,5 +173,9 @@ int z_erofs_decompress(struct z_erofs_decompress_req *rq) if (rq->alg == Z_EROFS_COMPRESSION_LZ4) return z_erofs_decompress_lz4(rq); #endif +#if IS_ENABLED(CONFIG_ZLIB) + if (rq->alg == Z_EROFS_COMPRESSION_DEFLATE) + return z_erofs_decompress_deflate(rq); +#endif return -EOPNOTSUPP; } diff --git a/fs/erofs/erofs_fs.h b/fs/erofs/erofs_fs.h index 158e2c68a1a..5bac4fe1a1d 100644 --- a/fs/erofs/erofs_fs.h +++ b/fs/erofs/erofs_fs.h @@ -304,6 +304,7 @@ enum { enum { Z_EROFS_COMPRESSION_LZ4 = 0, Z_EROFS_COMPRESSION_LZMA = 1, + Z_EROFS_COMPRESSION_DEFLATE = 2, Z_EROFS_COMPRESSION_MAX }; diff --git a/fs/fat/fat.c b/fs/fat/fat.c index 14e53cf2d5a..2dd9d4e72dc 100644 --- a/fs/fat/fat.c +++ b/fs/fat/fat.c @@ -1254,7 +1254,7 @@ out: static void __maybe_unused fat2rtc(u16 date, u16 time, struct rtc_time *tm) { tm->tm_mday = date & 0x1f; - tm->tm_mon = (date & 0x1e0) >> 4; + tm->tm_mon = (date & 0x1e0) >> 5; tm->tm_year = (date >> 9) + 1980; tm->tm_sec = (time & 0x1f) << 1; diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c index 8b5d669b005..c8e0fbf1a3b 100644 --- a/fs/fat/fat_write.c +++ b/fs/fat/fat_write.c @@ -18,6 +18,7 @@ #include <rand.h> #include <asm/byteorder.h> #include <asm/cache.h> +#include <dm/uclass.h> #include <linux/ctype.h> #include <linux/math64.h> #include "fat.c" @@ -1152,6 +1153,41 @@ getit: } /** + * dentry_set_time() - set change time + * + * @dentptr: directory entry + */ +static void dentry_set_time(dir_entry *dentptr) +{ + if (CONFIG_IS_ENABLED(DM_RTC)) { + struct udevice *dev; + struct rtc_time tm; + u16 date; + u16 time; + + uclass_first_device(UCLASS_RTC, &dev); + if (!dev) + goto err; + if (dm_rtc_get(dev, &tm)) + goto err; + if (tm.tm_year < 1980 || tm.tm_year > 2107) + goto err; + date = (tm.tm_mday & 0x1f) | + ((tm.tm_mon & 0xf) << 5) | + ((tm.tm_year - 1980) << 9); + time = (tm.tm_sec > 1) | + ((tm.tm_min & 0x3f) << 5) | + (tm.tm_hour << 11); + dentptr->date = date; + dentptr->time = time; + return; + } +err: + dentptr->date = 0x2821; /* 2000-01-01 */ + dentptr->time = 0; +} + +/** * fill_dentry() - fill directory entry with shortname * * @mydata: private filesystem parameters @@ -1171,6 +1207,12 @@ static void fill_dentry(fsdata *mydata, dir_entry *dentptr, dentptr->attr = attr; + /* Set change date */ + dentry_set_time(dentptr); + /* Set creation date */ + dentptr->cdate = dentptr->date; + dentptr->ctime = dentptr->time; + memcpy(&dentptr->nameext, shortname, SHORT_NAME_SIZE); } @@ -1376,6 +1418,8 @@ int file_fat_write_at(const char *filename, loff_t pos, void *buffer, /* Update file size in a directory entry */ retdent->size = cpu_to_le32(pos + size); + /* Update change date */ + dentry_set_time(retdent); } else { /* Create a new file */ char shortname[SHORT_NAME_SIZE]; diff --git a/fs/zfs/dev.c b/fs/zfs/dev.c index 251e7d1f74f..fcd9893b3ac 100644 --- a/fs/zfs/dev.c +++ b/fs/zfs/dev.c @@ -26,5 +26,5 @@ void zfs_set_blk_dev(struct blk_desc *rbdd, struct disk_partition *info) int zfs_devread(int sector, int byte_offset, int byte_len, char *buf) { return fs_devread(zfs_blk_desc, part_info, sector, byte_offset, - byte_len, buf); + byte_len, buf) ? 0 : 1; } diff --git a/fs/zfs/zfs.c b/fs/zfs/zfs.c index 1fec96cd5ce..bfc11fa6676 100644 --- a/fs/zfs/zfs.c +++ b/fs/zfs/zfs.c @@ -655,7 +655,7 @@ dmu_read(dnode_end_t *dn, uint64_t blkid, void **buf, dn->endian) << SPA_MINBLOCKSHIFT; *buf = malloc(size); - if (*buf) { + if (!*buf) { err = ZFS_ERR_OUT_OF_MEMORY; break; } @@ -1559,6 +1559,10 @@ nvlist_find_value(char *nvlist, char *name, int valtype, char **val, return 0; } +int is_word_aligned_ptr(void *ptr) { + return ((uintptr_t)ptr & (sizeof(void *) - 1)) == 0; +} + int zfs_nvlist_lookup_uint64(char *nvlist, char *name, uint64_t *out) { @@ -1574,6 +1578,20 @@ zfs_nvlist_lookup_uint64(char *nvlist, char *name, uint64_t *out) return ZFS_ERR_BAD_FS; } + /* On arm64, calling be64_to_cpu() on a value stored at a memory address + * that's not 8-byte aligned causes the CPU to reset. Avoid that by copying the + * value somewhere else if needed. + */ + if (!is_word_aligned_ptr((void *)nvpair)) { + uint64_t *alignedptr = malloc(sizeof(uint64_t)); + if (!alignedptr) + return 0; + memcpy(alignedptr, nvpair, sizeof(uint64_t)); + *out = be64_to_cpu(*alignedptr); + free(alignedptr); + return 1; + } + *out = be64_to_cpu(*(uint64_t *) nvpair); return 1; } @@ -1617,6 +1635,11 @@ zfs_nvlist_lookup_nvlist(char *nvlist, char *name) &size, 0); if (!found) return 0; + + /* Allocate 12 bytes in addition to the nvlist size: One uint32 before the + * nvlist to hold the encoding method, and two zero uint32's after the + * nvlist as the NULL terminator. + */ ret = calloc(1, size + 3 * sizeof(uint32_t)); if (!ret) return 0; @@ -2112,7 +2135,7 @@ zfs_read(zfs_file_t file, char *buf, uint64_t len) * Find requested blkid and the offset within that block. */ uint64_t blkid = file->offset + red; - blkid = do_div(blkid, blksz); + uint64_t blkoff = do_div(blkid, blksz); free(data->file_buf); data->file_buf = 0; @@ -2127,8 +2150,7 @@ zfs_read(zfs_file_t file, char *buf, uint64_t len) movesize = min(length, data->file_end - (int)file->offset - red); - memmove(buf, data->file_buf + file->offset + red - - data->file_start, movesize); + memmove(buf, data->file_buf + blkoff, movesize); buf += movesize; length -= movesize; red += movesize; |