diff options
author | Marek BehĂșn <marek.behun@nic.cz> | 2017-09-03 17:00:28 +0200 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2017-10-02 21:52:17 -0400 |
commit | 21a14facb1494592c3ad4874c6a00539d15a29cf (patch) | |
tree | 96b0f5d1bfcbddff721717c6609ec401bd594ccf /fs/btrfs/extent-io.c | |
parent | 597b4aff7b5d85946d2028ab9498116f53357dbc (diff) |
fs: btrfs: Add single-device read-only BTRFS implementation
This adds the proper implementation for the BTRFS filesystem.
The implementation currently supports only read-only mode and
the filesystem can be only on a single device.
Checksums of data chunks is unimplemented.
Compression is implemented (ZLIB + LZO).
Signed-off-by: Marek Behun <marek.behun@nic.cz>
create mode 100644 fs/btrfs/btrfs.h
create mode 100644 fs/btrfs/chunk-map.c
create mode 100644 fs/btrfs/compression.c
create mode 100644 fs/btrfs/ctree.c
create mode 100644 fs/btrfs/dev.c
create mode 100644 fs/btrfs/dir-item.c
create mode 100644 fs/btrfs/extent-io.c
create mode 100644 fs/btrfs/hash.c
create mode 100644 fs/btrfs/inode.c
create mode 100644 fs/btrfs/root.c
create mode 100644 fs/btrfs/subvolume.c
create mode 100644 fs/btrfs/super.c
Diffstat (limited to 'fs/btrfs/extent-io.c')
-rw-r--r-- | fs/btrfs/extent-io.c | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/fs/btrfs/extent-io.c b/fs/btrfs/extent-io.c new file mode 100644 index 0000000000..feb91432e9 --- /dev/null +++ b/fs/btrfs/extent-io.c @@ -0,0 +1,120 @@ +/* + * BTRFS filesystem implementation for U-Boot + * + * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "btrfs.h" +#include <malloc.h> + +u64 btrfs_read_extent_inline(struct btrfs_path *path, + struct btrfs_file_extent_item *extent, u64 offset, + u64 size, char *out) +{ + u32 clen, dlen, orig_size = size, res; + const char *cbuf; + char *dbuf; + const int data_off = offsetof(struct btrfs_file_extent_item, + disk_bytenr); + + clen = btrfs_path_item_size(path) - data_off; + cbuf = (const char *) extent + data_off; + dlen = extent->ram_bytes; + + if (offset > dlen) + return -1ULL; + + if (size > dlen - offset) + size = dlen - offset; + + if (extent->compression == BTRFS_COMPRESS_NONE) { + memcpy(out, cbuf + offset, size); + return size; + } + + if (dlen > orig_size) { + dbuf = malloc(dlen); + if (!dbuf) + return -1ULL; + } else { + dbuf = out; + } + + res = btrfs_decompress(extent->compression, cbuf, clen, dbuf, dlen); + if (res == -1 || res != dlen) + goto err; + + if (dlen > orig_size) { + memcpy(out, dbuf + offset, size); + free(dbuf); + } else if (offset) { + memmove(out, dbuf + offset, size); + } + + return size; + +err: + if (dlen > orig_size) + free(dbuf); + return -1ULL; +} + +u64 btrfs_read_extent_reg(struct btrfs_path *path, + struct btrfs_file_extent_item *extent, u64 offset, + u64 size, char *out) +{ + u64 physical, clen, dlen, orig_size = size; + u32 res; + char *cbuf, *dbuf; + + clen = extent->disk_num_bytes; + dlen = extent->num_bytes; + + if (offset > dlen) + return -1ULL; + + if (size > dlen - offset) + size = dlen - offset; + + physical = btrfs_map_logical_to_physical(extent->disk_bytenr); + if (physical == -1ULL) + return -1ULL; + + if (extent->compression == BTRFS_COMPRESS_NONE) { + physical += extent->offset + offset; + if (!btrfs_devread(physical, size, out)) + return -1ULL; + + return size; + } + + cbuf = malloc(dlen > size ? clen + dlen : clen); + if (!cbuf) + return -1ULL; + + if (dlen > orig_size) + dbuf = cbuf + clen; + else + dbuf = out; + + if (!btrfs_devread(physical, clen, cbuf)) + goto err; + + res = btrfs_decompress(extent->compression, cbuf, clen, dbuf, dlen); + if (res == -1) + goto err; + + if (dlen > orig_size) + memcpy(out, dbuf + offset, size); + else + memmove(out, dbuf + offset, size); + + free(cbuf); + return res; + +err: + free(cbuf); + return -1ULL; +} |