diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/Kconfig | 1 | ||||
-rw-r--r-- | fs/btrfs/btrfs.c | 16 | ||||
-rw-r--r-- | fs/btrfs/btrfs_tree.h | 5 | ||||
-rw-r--r-- | fs/btrfs/compression.c | 59 | ||||
-rw-r--r-- | fs/btrfs/super.c | 11 | ||||
-rw-r--r-- | fs/fat/fat.c | 9 | ||||
-rw-r--r-- | fs/fat/fat_write.c | 165 |
7 files changed, 174 insertions, 92 deletions
diff --git a/fs/btrfs/Kconfig b/fs/btrfs/Kconfig index 22909d9fccc..f302b1fbef5 100644 --- a/fs/btrfs/Kconfig +++ b/fs/btrfs/Kconfig @@ -2,6 +2,7 @@ config FS_BTRFS bool "Enable BTRFS filesystem support" select CRC32C select LZO + select ZSTD select RBTREE help This provides a single-device read-only BTRFS support. BTRFS is a diff --git a/fs/btrfs/btrfs.c b/fs/btrfs/btrfs.c index 6f35854823e..cb7e1827422 100644 --- a/fs/btrfs/btrfs.c +++ b/fs/btrfs/btrfs.c @@ -119,17 +119,17 @@ int btrfs_ls(const char *path) if (inr == -1ULL) { printf("Cannot lookup path %s\n", path); - return 1; + return -1; } if (type != BTRFS_FT_DIR) { printf("Not a directory: %s\n", path); - return 1; + return -1; } if (btrfs_readdir(&root, inr, readdir_callback)) { printf("An error occured while listing directory %s\n", path); - return 1; + return -1; } return 0; @@ -158,12 +158,12 @@ int btrfs_size(const char *file, loff_t *size) if (inr == -1ULL) { printf("Cannot lookup file %s\n", file); - return 1; + return -1; } if (type != BTRFS_FT_REG_FILE) { printf("Not a regular file: %s\n", file); - return 1; + return -1; } *size = inode.size; @@ -183,12 +183,12 @@ int btrfs_read(const char *file, void *buf, loff_t offset, loff_t len, if (inr == -1ULL) { printf("Cannot lookup file %s\n", file); - return 1; + return -1; } if (type != BTRFS_FT_REG_FILE) { printf("Not a regular file: %s\n", file); - return 1; + return -1; } if (!len) @@ -200,7 +200,7 @@ int btrfs_read(const char *file, void *buf, loff_t offset, loff_t len, rd = btrfs_file_read(&root, inr, offset, len, buf); if (rd == -1ULL) { printf("An error occured while reading file %s\n", file); - return 1; + return -1; } *actread = rd; diff --git a/fs/btrfs/btrfs_tree.h b/fs/btrfs/btrfs_tree.h index f90fbb29514..aa0f3d6c86d 100644 --- a/fs/btrfs/btrfs_tree.h +++ b/fs/btrfs/btrfs_tree.h @@ -647,8 +647,9 @@ enum btrfs_compression_type { BTRFS_COMPRESS_NONE = 0, BTRFS_COMPRESS_ZLIB = 1, BTRFS_COMPRESS_LZO = 2, - BTRFS_COMPRESS_TYPES = 2, - BTRFS_COMPRESS_LAST = 3, + BTRFS_COMPRESS_ZSTD = 3, + BTRFS_COMPRESS_TYPES = 3, + BTRFS_COMPRESS_LAST = 4, }; struct btrfs_file_extent_item { diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index e5601b8f2bf..346875d45a1 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c @@ -6,7 +6,9 @@ */ #include "btrfs.h" +#include <malloc.h> #include <linux/lzo.h> +#include <linux/zstd.h> #include <u-boot/zlib.h> #include <asm/unaligned.h> @@ -108,6 +110,61 @@ static u32 decompress_zlib(const u8 *_cbuf, u32 clen, u8 *dbuf, u32 dlen) return res; } +#define ZSTD_BTRFS_MAX_WINDOWLOG 17 +#define ZSTD_BTRFS_MAX_INPUT (1 << ZSTD_BTRFS_MAX_WINDOWLOG) + +static u32 decompress_zstd(const u8 *cbuf, u32 clen, u8 *dbuf, u32 dlen) +{ + ZSTD_DStream *dstream; + ZSTD_inBuffer in_buf; + ZSTD_outBuffer out_buf; + void *workspace; + size_t wsize; + u32 res = -1; + + wsize = ZSTD_DStreamWorkspaceBound(ZSTD_BTRFS_MAX_INPUT); + workspace = malloc(wsize); + if (!workspace) { + debug("%s: cannot allocate workspace of size %zu\n", __func__, + wsize); + return -1; + } + + dstream = ZSTD_initDStream(ZSTD_BTRFS_MAX_INPUT, workspace, wsize); + if (!dstream) { + printf("%s: ZSTD_initDStream failed\n", __func__); + goto err_free; + } + + in_buf.src = cbuf; + in_buf.pos = 0; + in_buf.size = clen; + + out_buf.dst = dbuf; + out_buf.pos = 0; + out_buf.size = dlen; + + while (1) { + size_t ret; + + ret = ZSTD_decompressStream(dstream, &out_buf, &in_buf); + if (ZSTD_isError(ret)) { + printf("%s: ZSTD_decompressStream error %d\n", __func__, + ZSTD_getErrorCode(ret)); + goto err_free; + } + + if (in_buf.pos >= clen || !ret) + break; + } + + res = out_buf.pos; + +err_free: + free(workspace); + return res; +} + u32 btrfs_decompress(u8 type, const char *c, u32 clen, char *d, u32 dlen) { u32 res; @@ -126,6 +183,8 @@ u32 btrfs_decompress(u8 type, const char *c, u32 clen, char *d, u32 dlen) return decompress_zlib(cbuf, clen, dbuf, dlen); case BTRFS_COMPRESS_LZO: return decompress_lzo(cbuf, clen, dbuf, dlen); + case BTRFS_COMPRESS_ZSTD: + return decompress_zstd(cbuf, clen, dbuf, dlen); default: printf("%s: Unsupported compression in extent: %i\n", __func__, type); diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 7aaf8f9b0d8..2dc4a6fcd7a 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -198,17 +198,16 @@ int btrfs_read_superblock(void) break; if (btrfs_check_super_csum(raw_sb)) { - printf("%s: invalid checksum at superblock mirror %i\n", - __func__, i); + debug("%s: invalid checksum at superblock mirror %i\n", + __func__, i); continue; } btrfs_super_block_to_cpu(sb); if (sb->magic != BTRFS_MAGIC) { - printf("%s: invalid BTRFS magic 0x%016llX at " - "superblock mirror %i\n", __func__, sb->magic, - i); + debug("%s: invalid BTRFS magic 0x%016llX at " + "superblock mirror %i\n", __func__, sb->magic, i); } else if (sb->bytenr != superblock_offsets[i]) { printf("%s: invalid bytenr 0x%016llX (expected " "0x%016llX) at superblock mirror %i\n", @@ -224,7 +223,7 @@ int btrfs_read_superblock(void) } if (!btrfs_info.sb.generation) { - printf("%s: No valid BTRFS superblock found!\n", __func__); + debug("%s: No valid BTRFS superblock found!\n", __func__); return -1; } diff --git a/fs/fat/fat.c b/fs/fat/fat.c index c5997c21735..06c8ed14bda 100644 --- a/fs/fat/fat.c +++ b/fs/fat/fat.c @@ -1134,11 +1134,12 @@ int fat_size(const char *filename, loff_t *size) * expected to fail if passed a directory path: */ free(fsdata.fatbuf); - fat_itr_root(itr, &fsdata); - if (!fat_itr_resolve(itr, filename, TYPE_DIR)) { + ret = fat_itr_root(itr, &fsdata); + if (ret) + goto out_free_itr; + ret = fat_itr_resolve(itr, filename, TYPE_DIR); + if (!ret) *size = 0; - ret = 0; - } goto out_free_both; } diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c index 852f874e581..729cf39630d 100644 --- a/fs/fat/fat_write.c +++ b/fs/fat/fat_write.c @@ -209,7 +209,8 @@ name11_12: return 1; } -static int flush_dir_table(fat_itr *itr); +static int new_dir_table(fat_itr *itr); +static int flush_dir(fat_itr *itr); /* * Fill dir_slot entries with appropriate name, id, and attr @@ -242,19 +243,18 @@ fill_dir_slot(fat_itr *itr, const char *l_name) memcpy(itr->dent, slotptr, sizeof(dir_slot)); slotptr--; counter--; + + if (itr->remaining == 0) + flush_dir(itr); + + /* allocate a cluster for more entries */ if (!fat_itr_next(itr)) - if (!itr->dent && !itr->is_root && flush_dir_table(itr)) + if (!itr->dent && + (!itr->is_root || itr->fsdata->fatsize == 32) && + new_dir_table(itr)) return -1; } - if (!itr->dent && !itr->is_root) - /* - * don't care return value here because we have already - * finished completing an entry with name, only ending up - * no more entry left - */ - flush_dir_table(itr); - return 0; } @@ -388,29 +388,23 @@ static __u32 determine_fatent(fsdata *mydata, __u32 entry) } /** - * set_cluster() - write data to cluster + * set_sectors() - write data to sectors * - * Write 'size' bytes from 'buffer' into the specified cluster. + * Write 'size' bytes from 'buffer' into the specified sector. * * @mydata: data to be written - * @clustnum: cluster to be written to + * @startsect: sector to be written to * @buffer: data to be written * @size: bytes to be written (but not more than the size of a cluster) * Return: 0 on success, -1 otherwise */ static int -set_cluster(fsdata *mydata, u32 clustnum, u8 *buffer, u32 size) +set_sectors(fsdata *mydata, u32 startsect, u8 *buffer, u32 size) { - u32 idx = 0; - u32 startsect; + u32 nsects = 0; int ret; - if (clustnum > 0) - startsect = clust_to_sect(mydata, clustnum); - else - startsect = mydata->rootdir_sect; - - debug("clustnum: %d, startsect: %d\n", clustnum, startsect); + debug("startsect: %d\n", startsect); if ((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1)) { ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size); @@ -429,17 +423,16 @@ set_cluster(fsdata *mydata, u32 clustnum, u8 *buffer, u32 size) size -= mydata->sect_size; } } else if (size >= mydata->sect_size) { - idx = size / mydata->sect_size; - ret = disk_write(startsect, idx, buffer); - if (ret != idx) { + nsects = size / mydata->sect_size; + ret = disk_write(startsect, nsects, buffer); + if (ret != nsects) { debug("Error writing data (got %d)\n", ret); return -1; } - startsect += idx; - idx *= mydata->sect_size; - buffer += idx; - size -= idx; + startsect += nsects; + buffer += nsects * mydata->sect_size; + size -= nsects * mydata->sect_size; } if (size) { @@ -457,6 +450,44 @@ set_cluster(fsdata *mydata, u32 clustnum, u8 *buffer, u32 size) return 0; } +/** + * set_cluster() - write data to cluster + * + * Write 'size' bytes from 'buffer' into the specified cluster. + * + * @mydata: data to be written + * @clustnum: cluster to be written to + * @buffer: data to be written + * @size: bytes to be written (but not more than the size of a cluster) + * Return: 0 on success, -1 otherwise + */ +static int +set_cluster(fsdata *mydata, u32 clustnum, u8 *buffer, u32 size) +{ + return set_sectors(mydata, clust_to_sect(mydata, clustnum), + buffer, size); +} + +static int +flush_dir(fat_itr *itr) +{ + fsdata *mydata = itr->fsdata; + u32 startsect, sect_offset, nsects; + + if (!itr->is_root || mydata->fatsize == 32) + return set_cluster(mydata, itr->clust, itr->block, + mydata->clust_size * mydata->sect_size); + + sect_offset = itr->clust * mydata->clust_size; + startsect = mydata->rootdir_sect + sect_offset; + /* do not write past the end of rootdir */ + nsects = min_t(u32, mydata->clust_size, + mydata->rootdir_size - sect_offset); + + return set_sectors(mydata, startsect, itr->block, + nsects * mydata->sect_size); +} + static __u8 tmpbuf_cluster[MAX_CLUSTSIZE] __aligned(ARCH_DMA_MINALIGN); /* @@ -590,18 +621,14 @@ static int find_empty_cluster(fsdata *mydata) } /* - * Write directory entries in itr's buffer to block device + * Allocate a cluster for additional directory entries */ -static int flush_dir_table(fat_itr *itr) +static int new_dir_table(fat_itr *itr) { fsdata *mydata = itr->fsdata; int dir_newclust = 0; unsigned int bytesperclust = mydata->clust_size * mydata->sect_size; - if (set_cluster(mydata, itr->clust, itr->block, bytesperclust) != 0) { - printf("error: writing directory entry\n"); - return -1; - } dir_newclust = find_empty_cluster(mydata); set_fatent_value(mydata, itr->clust, dir_newclust); if (mydata->fatsize == 32) @@ -956,7 +983,10 @@ static dir_entry *find_directory_entry(fat_itr *itr, char *filename) return itr->dent; } - if (!itr->dent && !itr->is_root && flush_dir_table(itr)) + /* allocate a cluster for more entries */ + if (!itr->dent && + (!itr->is_root || itr->fsdata->fatsize == 32) && + new_dir_table(itr)) /* indicate that allocating dent failed */ itr->dent = NULL; @@ -1009,40 +1039,32 @@ again: return 0; } +/** + * normalize_longname() - check long file name and convert to lower case + * + * We assume here that the FAT file system is using an 8bit code page. + * Linux typically uses CP437, EDK2 assumes CP1250. + * + * @l_filename: preallocated buffer receiving the normalized name + * @filename: filename to normalize + * Return: 0 on success, -1 on failure + */ static int normalize_longname(char *l_filename, const char *filename) { - const char *p, legal[] = "!#$%&\'()-.@^`_{}~"; - unsigned char c; - int name_len; - - /* Check that the filename is valid */ - for (p = filename; p < filename + strlen(filename); p++) { - c = *p; - - if (('0' <= c) && (c <= '9')) - continue; - if (('A' <= c) && (c <= 'Z')) - continue; - if (('a' <= c) && (c <= 'z')) - continue; - if (strchr(legal, c)) - continue; - /* extended code */ - if ((0x80 <= c) && (c <= 0xff)) - continue; + const char *p, illegal[] = "<>:\"/\\|?*"; + if (strlen(filename) >= VFAT_MAXLEN_BYTES) return -1; - } - /* Normalize it */ - name_len = strlen(filename); - if (name_len >= VFAT_MAXLEN_BYTES) - /* should return an error? */ - name_len = VFAT_MAXLEN_BYTES - 1; + for (p = filename; *p; ++p) { + if ((unsigned char)*p < 0x20) + return -1; + if (strchr(illegal, *p)) + return -1; + } - memcpy(l_filename, filename, name_len); - l_filename[name_len] = 0; /* terminate the string */ - downcase(l_filename, INT_MAX); + strcpy(l_filename, filename); + downcase(l_filename, VFAT_MAXLEN_BYTES); return 0; } @@ -1141,14 +1163,16 @@ int file_fat_write_at(const char *filename, loff_t pos, void *buffer, memset(itr->dent, 0, sizeof(*itr->dent)); - /* Set short name to set alias checksum field in dir_slot */ + /* Calculate checksum for short name */ set_name(itr->dent, filename); + + /* Set long name entries */ if (fill_dir_slot(itr, filename)) { ret = -EIO; goto exit; } - /* Set attribute as archive for regular file */ + /* Set short name entry */ fill_dentry(itr->fsdata, itr->dent, filename, 0, size, 0x20); retdent = itr->dent; @@ -1171,8 +1195,7 @@ int file_fat_write_at(const char *filename, loff_t pos, void *buffer, } /* Write directory table to device */ - ret = set_cluster(mydata, itr->clust, itr->block, - mydata->clust_size * mydata->sect_size); + ret = flush_dir(itr); if (ret) { printf("Error: writing directory entry\n"); ret = -EIO; @@ -1249,8 +1272,7 @@ static int delete_dentry(fat_itr *itr) memset(dentptr, 0, sizeof(*dentptr)); dentptr->name[0] = 0xe5; - if (set_cluster(mydata, itr->clust, itr->block, - mydata->clust_size * mydata->sect_size) != 0) { + if (flush_dir(itr)) { printf("error: writing directory entry\n"); return -EIO; } @@ -1452,8 +1474,7 @@ int fat_mkdir(const char *new_dirname) } /* Write directory table to device */ - ret = set_cluster(mydata, itr->clust, itr->block, - mydata->clust_size * mydata->sect_size); + ret = flush_dir(itr); if (ret) printf("Error: writing directory entry\n"); |