3 Star 1 Fork 0

Gitee 极速下载 / PuzzleFS

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
此仓库是为了提升国内下载速度的镜像仓库,每日同步一次。 原始仓库: https://github.com/anuvu/puzzlefs
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
Apache-2.0

PuzzleFS Build Status

PuzzleFS is a next-generation container filesystem.

Design Goals

  • Do computation when we want to, i.e.:
    • Image building should be fast
    • Image mounting/reading should be fast
    • Optional "canonicalization" step in the middle
  • No full-tree walk required
    • mtree style walks of filesystems are not necessary with clever use of overlay
    • casync style generate-a-tar-then-diff is more for general purpose use where you don't want to have a special filesystem setup
  • Be simple enough to decode in the kernel
    • A primary motivator for our working on this at Cisco is direct-mount support

Abstract

Puzzlefs is a container filesystem designed to address the limitations of the existing OCI format. The main goals of the project are reduced duplication, reproducible image builds, direct mounting support and memory safety guarantees, some inspired by the OCIv2 design document.

Reduced duplication is achieved using the content defined chunking algorithm FastCDC. This implementation allows chunks to be shared among layers. Building a new layer starting from an existing one allows reusing most of the chunks.

Another goal of the project is reproducible image builds, which is achieved by defining a canonical representation of the image format.

Direct mounting support is a key feature of puzzlefs and, together with fs-verity, it provides data integrity. Currently, puzzlefs is implemented as a userspace filesystem (FUSE). A read-only kernel filesystem driver is underway.

Lastly, memory safety is critical to puzzlefs, leading to the decision to implement it in Rust. Another goal is to share the same code between user space and kernel space in order to provide one secure implementation.

OCIv2 Design doc

https://hackmd.io/@cyphar/ociv2-brainstorm

For the most part, I think this addresses things there except for two:

  • Explicit Minimal Metadata: this is mostly unaddressed because I didn't think about it very hard; there's no reason we couldn't just drop e.g. block devices from the spec, or at least add a note about discouraging their use. Perhaps we should make mtimes and such optional? But then canonicalization would be harder. Maybe this should be specified at image build time, sort of like the chunking algorithm is in our design.

  • Lazy fetch support: this seems directly at odds with the "direct mount" support at least if the direct mount code is to live in the kernel; we probably don't want to implement lazy fetch directly in the kernel, because it involves the network and lots of other stuff. However, this would be relatively easy to do using fuse, which suggests that perhaps we should choose a good language (e.g. rust :) for the implementation so that we could use the same code in the kernel and userspace, thus easily supporting this one.

Getting started

Build dependencies

Puzzlefs is written in rust, which you can download from https://www.rust-lang.org/tools/install. It requires a nightly toolchain which you can add with rustup toolchain install nightly.

The capnp tool is required for autogenerating rust code from the capnproto schema language. This is done at build time using the capnpc crate.

How to build

Run make (or cargo build) for the debug build and make release (cargo build --release) for the release build. The resulting binaries are in target/debug/puzzlefs and target/release/puzzlefs, respectively.

Running tests

To run the tests, run make check.

The tests require skopeo and umoci to be installed. It also requires root to run the test_fs_verity test.

Building a puzzlefs image

To build a puzzlefs image, you need to specify a directory with the root filesystem you want included in your image. For example:

$ tree /tmp/example-rootfs
/tmp/example-rootfs
├── algorithms
│   └── binary-search.txt
└── lorem_ipsum.txt

2 directories, 2 files

Then run:

$ cargo run --release -- build /tmp/example-rootfs /tmp/puzzlefs-image puzzlefs_example
puzzlefs image manifest digest: 9ac9abc098870c55cc61431dae8635806273d8f61274d34bec062560e79dc2f5

This builds a puzzlefs image with the above root filesystem in /tmp/puzzlefs-image, with the tag puzzlefs_example. It also outputs the image's manifest digest, which is useful for verifying the integrity of the image using fs-verity.

For additional build options, run puzzlefs build -h.

Mounting a puzzlefs image

To mount the above puzlefs image, first we need to create a mountpoint:

mkdir /tmp/mounted-image

Then run puzzlefs mount with the location of the puzzlefs image, the image tag and the mountpoint:

$ cargo run --release -- mount /tmp/puzzlefs-image puzzlefs_example /tmp/mounted-image

If everything was successful, you will see a fuse entry in the output of mount:

$ mount
...
/dev/fuse on /tmp/mounted-image type fuse (rw,nosuid,nodev,relatime,user_id=1000,group_id=1000)

and the following message in the journal:

$ journalctl --since "2 min ago" | grep puzzlefs
Aug 14 10:30:27 archlinux-cisco puzzlefs[55544]: Mounting /tmp/mounted-image

The mountpoint also contains the rootfs:

$ tree /tmp/mounted-image
/tmp/mounted-image
├── algorithms
│   └── binary-search.txt
└── lorem_ipsum.txt

2 directories, 2 files

For additional mount options, run cargo run -- mount -h.

Mounting with fs-verity enabled

If you want to mount the filesystem with fs-verity authenticity protection, first enable fs-verity by running:

$ cargo run --release -- enable-fs-verity /tmp/puzzlefs-image puzzlefs_example 9ac9abc098870c55cc61431dae8635806273d8f61274d34bec062560e79dc2f5

This makes the data and metadata files readonly. Any reads of corrupted data will fail.

Then run mount with the --digest option:

$ cargo run --release -- mount --digest 9ac9abc098870c55cc61431dae8635806273d8f61274d34bec062560e79dc2f5 /tmp/puzzlefs-image puzzlefs_example /tmp/mounted-image

PuzzleFS now ensures that each file it opens has fs-verity enabled and that the fs-verity measurement matches the fs-verity data stored in the manifest. The image manifest's fs-verity digest is compared with the digest passed on the command line via the --digest option.

This only works if fsverity is supported and enabled in the underlying filesystem on which the puzzlefs image resides. Otherwise you might get an error like this when running enable-fs-verity:

Error: fs error: Inappropriate ioctl for device (os error 25)

Caused by:
    Inappropriate ioctl for device (os error 25)

To check wheter fs-verity is enabled, use tune2fs:

$ mount | grep -w '/'
/dev/mapper/MyVolGroup-root on / type ext4 (rw,relatime)

$ sudo tune2fs -l /dev/mapper/MyVolGroup-root | grep verity
Filesystem features:      has_journal ext_attr resize_inode dir_index filetype needs_recovery extent 64bit flex_bg sparse_super large_file huge_file dir_nlink extra_isize metadata_csum verity

To set up an 1MB loop device with an ext4 filesystem which supports fs-verity and mount it under /mnt, run:

$ mktemp -u
/tmp/tmp.2CDDHVPLXp

$ touch /tmp/tmp.2CDDHVPLXp

$ dd if=/dev/zero of=/tmp/tmp.2CDDHVPLXp bs=1k count=1024
1024+0 records in
1024+0 records out
1048576 bytes (1.0 MB, 1.0 MiB) copied, 0.00203188 s, 516 MB/s

$ sudo losetup -f --show /tmp/tmp.2CDDHVPLXp
/dev/loop1

$ sudo mkfs -t ext4 -F -b4096 -O verity /dev/loop1
mke2fs 1.47.0 (5-Feb-2023)

Filesystem too small for a journal
Discarding device blocks: done
Creating filesystem with 256 4k blocks and 128 inodes

Allocating group tables: done
Writing inode tables: done
Writing superblocks and filesystem accounting information: done

$ sudo mount /dev/loop1 /mnt

$ sudo chown -R $(id -u):$(id -g) /mnt

$ sudo tune2fs -l /dev/loop1 | grep verity
Filesystem features:      ext_attr resize_inode dir_index filetype extent 64bit flex_bg metadata_csum_seed sparse_super large_file huge_file dir_nlink extra_isize metadata_csum verity

Now copy the puzzlefs image to /mnt and try the verity setup commands again.

Debugging mount issues

When mounting a puzzlefs filesystem in the background (i.e. without -f flag), then errors are logged into the journal, e.g.:

$ journalctl --since "2 min ago" | grep puzzlefs
Jul 13 18:37:30 archlinux-cisco puzzlefs[305462]: mount_background failed: fs error: fs error: Inappropriate ioctl for device (os error 25)

For debugging purposes you can use the RUST_LOG environment variable together with -f flag of mount:

$ RUST_LOG=DEBUG cargo run --release -- mount -f /tmp/puzzlefs-image puzzlefs_example /tmp/mounted-image
[2023-07-13T16:08:27Z INFO  fuser::session] Mounting /tmp/mounted-image
[2023-07-13T16:08:27Z DEBUG fuser::mnt::fuse_pure] fusermount:
[2023-07-13T16:08:27Z DEBUG fuser::mnt::fuse_pure] fusermount:
[2023-07-13T16:08:27Z DEBUG fuser::request] FUSE(  2) ino 0x0000000000000000 INIT kernel ABI 7.38, capabilities 0x73fffffb, max readahead 131072
[2023-07-13T16:08:27Z DEBUG fuser::request] INIT response: ABI 7.8, flags 0x1, max readahead 131072, max write 16777216
...

Notification when the mountpoint is ready

Foreground mount (mount -f)

A named pipe can be passed to the mount command. Reading from this pipe is blocking operation, waiting until puzzlefs signals that the mountpoint is ready. If the mount operation is successful, the s character is written to the pipe, otherwise f is written. It is inspired by this squashfuse issue.

The following script shows how to wait until the puzzlefs mountpoint is ready. The script assumes there is puzzlefs image available at /tmp/puzzlefs-image and the directory /tmp/mounted-image already exists.

#!/bin/bash
FIFO=$(mktemp -u)
mkfifo "$FIFO"
cargo run --release -- mount -i "$FIFO" -f /tmp/puzzlefs-image puzzlefs_example /tmp/mounted-image&
STATUS=$(head -c1 "$FIFO")
if [ "$STATUS" = "s" ]; then
	echo "Mountpoint contains:"
	ls /tmp/mounted-image
else
	echo "Mounting puzzlefs on /tmp/mounted-image failed"
fi

Background mount

When mounting in the background, puzzlefs uses an anonymous pipe to communicate between its original process and the daemon it spawns in order to wait until the mountpoint is available. This means that the puzzlefs mount command finishes its execution only after the mountpoint becomes ready.

Umounting a puzzlefs image

If you have specified the -f flag to mount, simply press Ctrl-C.

Otherwise, run fusermount -u /tmp/mounted-image. You will need to have fuse package installed.

Inspecting a puzzlefs image

$ cd /tmp/puzzlefs-image
$ cat index.json | jq .
{
  "schemaVersion": -1,
  "manifests": [
    {
      "digest": "sha256:0efa2a4b490abb02a5b9b5f2d43c8262643dba48c67f14b236df0a6f1ea745d8",
      "size": 272,
      "media_type": "application/vnd.puzzlefs.image.rootfs.v1",
      "annotations": {
        "org.opencontainers.image.ref.name": "puzzlefs_example"
      }
    }
  ],
  "annotations": {}
}

The digest specifies the puzzlefs image manifest, which needs to be decoded using the capnp tool and the manifest schema (assuming you've cloned puzzlefs in ~/puzzlefs):

$ capnp convert binary:json ~/puzzlefs/format/manifest.capnp Rootfs < blobs/sha256/0efa2a4b490abb02a5b9b5f2d43c8262643dba48c67f14b236df0a6f1ea745d8

{ "metadatas": [{ "digest": [102, 197, 227, 96, 136, 156, 147, 144, 139, 154, 248, 228, 29, 161, 252, 228, 118, 222, 21, 44, 132, 0, 214, 164, 80, 74, 121, 156, 26, 85, 123, 57],
    "offset": "0",
    "compressed": false }],
  "fsVerityData": [
    { "digest": [102, 197, 227, 96, 136, 156, 147, 144, 139, 154, 248, 228, 29, 161, 252, 228, 118, 222, 21, 44, 132, 0, 214, 164, 80, 74, 121, 156, 26, 85, 123, 57],
      "verity": [224, 180, 63, 193, 142, 198, 24, 175, 78, 42, 126, 227, 253, 187, 102, 162, 31, 77, 85, 252, 205, 137, 198, 216, 26, 213, 113, 238, 144, 79, 93, 244] },
    { "digest": [239, 32, 68, 39, 210, 105, 37, 83, 131, 158, 224, 24, 162, 25, 96, 90, 140, 95, 158, 194, 97, 2, 153, 175, 54, 197, 216, 193, 115, 121, 62, 22],
      "verity": [196, 54, 71, 79, 3, 104, 3, 253, 163, 243, 85, 213, 67, 235, 144, 210, 20, 206, 160, 209, 75, 164, 93, 22, 79, 84, 41, 119, 20, 84, 64, 164] } ],
  "manifestVersion": "1" }

metadatas contains a list of layers (in this case only one) which can be further decoded (the sha of the blob is obtained by a decimal to hexadecimal conversion):

$ capnp convert binary:json ~/puzzlefs/format/metadata.capnp InodeVector < blobs/sha256/66c5e360889c93908b9af8e41da1fce476de152c8400d6a4504a799c1a557b39

{"inodes": [
  { "ino": "1",
    "mode": {"dir": {
      "entries": [
        { "ino": "2",
          "name": [97, 108, 103, 111, 114, 105, 116, 104, 109, 115] },
        { "ino": "3",
          "name": [108, 111, 114, 101, 109, 95, 105, 112, 115, 117, 109, 46, 116, 120, 116] } ],
      "lookBelow": false }},
    "uid": 1000,
    "gid": 1000,
    "permissions": 493 },
  { "ino": "2",
    "mode": {"dir": {
      "entries": [{ "ino": "4",
        "name": [98, 105, 110, 97, 114, 121, 45, 115, 101, 97, 114, 99, 104, 46, 116, 120, 116] }],
      "lookBelow": false }},
    "uid": 1000,
    "gid": 1000,
    "permissions": 493 },
  { "ino": "3",
    "mode": {"file": {"chunks": [{ "blob": {
        "digest": [239, 32, 68, 39, 210, 105, 37, 83, 131, 158, 224, 24, 162, 25, 96, 90, 140, 95, 158, 194, 97, 2, 153, 175, 54, 197, 216, 193, 115, 121, 62, 22],
        "offset": "0",
        "compressed": false },
      "len": "865" }]}},
    "uid": 1000,
    "gid": 1000,
    "permissions": 420 },
  { "ino": "4",
    "mode": {"file": {"chunks": [{ "blob": {
        "digest": [239, 32, 68, 39, 210, 105, 37, 83, 131, 158, 224, 24, 162, 25, 96, 90, 140, 95, 158, 194, 97, 2, 153, 175, 54, 197, 216, 193, 115, 121, 62, 22],
        "offset": "865",
        "compressed": false },
      "len": "278" }]}},
    "uid": 1000,
    "gid": 1000,
    "permissions": 420 } ]}

Implementation

This workspace contains a library and an executable crate:

  • puzzlefs-lib is the library crate
    • format is the module for serializing/de-serializing the puzzlefs format
    • builder is the module for building a puzzlefs image
    • extractor is the module for extracting a puzzlefs image
    • reader is the module for fuse mounting a puzzlefs image
  • exe/ is the executable frontend for the above

Contributing

Contributions need to pass all static analysis.

In addition, all commits must include a Signed-off-by: line in their description. This indicates that you certify the following statement, known as the Developer Certificate of Origin). You can automatically add this line to your commits by using git commit -s --amend.

Developer Certificate of Origin
Version 1.1

Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
1 Letterman Drive
Suite D4700
San Francisco, CA, 94129

Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.


Developer's Certificate of Origin 1.1

By making a contribution to this project, I certify that:

(a) The contribution was created in whole or in part by me and I
    have the right to submit it under the open source license
    indicated in the file; or

(b) The contribution is based upon previous work that, to the best
    of my knowledge, is covered under an appropriate open source
    license and I have the right under that license to submit that
    work with modifications, whether created in whole or in part
    by me, under the same open source license (unless I am
    permitted to submit under a different license), as indicated
    in the file; or

(c) The contribution was provided directly to me by some other
    person who certified (a), (b) or (c) and I have not modified
    it.

(d) I understand and agree that this project and the contribution
    are public and that a record of the contribution (including all
    personal information I submit with it, including my sign-off) is
    maintained indefinitely and may be redistributed consistent with
    this project or the open source license(s) involved.

License

puzzlefs is released under the Apache License, Version 2.0, and is:

Copyright (C) 2020-2021 Cisco Systems, Inc.

Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS

简介

PuzzleFS 是下一代容器文件系统 展开 收起
Rust 等 3 种语言
Apache-2.0
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
Rust
1
https://gitee.com/mirrors/PuzzleFS.git
git@gitee.com:mirrors/PuzzleFS.git
mirrors
PuzzleFS
PuzzleFS
master

搜索帮助

53164aa7 5694891 3bd8fe86 5694891