]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
copy: return immediately on fs-verity failures
authorAllison Karlitskaya <allison.karlitskaya@redhat.com>
Thu, 20 Mar 2025 12:13:13 +0000 (13:13 +0100)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 4 Jun 2025 13:32:52 +0000 (22:32 +0900)
Since 8065d02e263a ("copy: Fix error handling in fd_copy_directory()")
we immediately abort recursive copy operations on ENOSPC.  Let's also
abort on the common case of filesystems not supporting fs-verity: if
it's unsupported for one file, it's unlikely to work for the 1000s that
follow it.

We do this by mapping the two fs-verity "not supported" errors (ENOTTY,
EOPNOTSUPP) to ESOCKTNOSUPPORT as a special "fs-verity not supported
here" error.  When we see that error at the top level we exit
immediately.

This prevents us from having to see the same error message literally
thousands of time when using fsverity=copy with systemd-repart on a
filesystem which lacks the proper support.

Adjust the test-copy test case to expect the new errno.  Previously this
test case would output multiple failure lines per `copy_tree_at()`
invocation (for the failing cases) but now it only outputs one.

src/shared/copy.c
src/test/test-copy.c

index 0c79121b68eb26482d0f4d071c9b00c3a571b655..17268387569fa57ef188ed4a3b3ef44029aaf75c 100644 (file)
@@ -817,7 +817,11 @@ static int copy_fs_verity(int fdf, int *fdt) {
                  * so the correct thing to do is to do nothing at all. */
                 if (errno == ENODATA)
                         return 0;
-                return log_error_errno(errno, "Failed to read fs-verity metadata from source file: %m");
+                log_error_errno(errno, "Failed to read fs-verity metadata from source file: %m");
+                /* For cases where fs-verity is unsupported we return a special error code */
+                if (ERRNO_IS_NOT_SUPPORTED(errno))
+                        return -ESOCKTNOSUPPORT;
+                return -errno;
         }
 
         /* Make sure that the descriptor is completely initialized */
@@ -844,8 +848,13 @@ static int copy_fs_verity(int fdf, int *fdt) {
                 .salt_ptr = (uintptr_t) &desc.salt,
         };
 
-        if (ioctl(*fdt, FS_IOC_ENABLE_VERITY, &enable_arg) < 0)
-                return log_error_errno(errno, "Failed to set fs-verity metadata: %m");
+        if (ioctl(*fdt, FS_IOC_ENABLE_VERITY, &enable_arg) < 0) {
+                log_error_errno(errno, "Failed to set fs-verity metadata: %m");
+                /* For cases where fs-verity is unsupported we return a special error code */
+                if (ERRNO_IS_NOT_SUPPORTED(errno))
+                        return -ESOCKTNOSUPPORT;
+                return -errno;
+        }
 
         return 0;
 }
@@ -1222,7 +1231,8 @@ static int fd_copy_directory(
                                          denylist, subvolumes, hardlink_context, child_display_path, progress_path,
                                          progress_bytes, userdata);
 
-                if (IN_SET(r, -EINTR, -ENOSPC)) /* Propagate SIGINT/SIGTERM and ENOSPC up instantly */
+                /* Propagate SIGINT/SIGTERM, ENOSPC, and fs-verity fails up instantly */
+                if (IN_SET(r, -EINTR, -ENOSPC, -ESOCKTNOSUPPORT))
                         return r;
                 if (r == -EEXIST && (copy_flags & COPY_MERGE))
                         r = 0;
index 9da7778655170a283a739bd76edc5a0b97bedcdf..86de5c4b633b196f8b692e4b5f8b51510f0cd3d6 100644 (file)
@@ -676,7 +676,7 @@ TEST_RET(copy_with_verity) {
 
         /* Copy *with* fs-verity enabled and make sure it works properly */
         int r = copy_tree_at(src, ".", dst, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_MERGE|COPY_PRESERVE_FS_VERITY, NULL, NULL);
-        if (r == -ENOTTY)
+        if (r == -ESOCKTNOSUPPORT)
                 /* This can happen on some versions of btrfs, for example */
                 return log_tests_skipped_errno(errno, "/var/tmp: fs-verity supported, but not reading metadata");
         ASSERT_OK(r);
@@ -697,14 +697,14 @@ TEST_RET(copy_with_verity) {
 
         /* Copy from our non-verity filesystem into dst, requesting verity and making sure we notice that
          * we failed to read verity from the source. */
-        ASSERT_ERROR(copy_tree_at(badsrc, ".", dst, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_MERGE|COPY_PRESERVE_FS_VERITY, NULL, NULL), ENOTTY);
+        ASSERT_ERROR(copy_tree_at(badsrc, ".", dst, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_MERGE|COPY_PRESERVE_FS_VERITY, NULL, NULL), ESOCKTNOSUPPORT);
 
         /* Copy from our verity filesystem into our baddst, requesting verity and making sure we notice that
          * we failed to set verity on the destination. */
-        ASSERT_ERROR(copy_tree_at(src, ".", baddst, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_MERGE|COPY_PRESERVE_FS_VERITY, NULL, NULL), ENOTTY);
+        ASSERT_ERROR(copy_tree_at(src, ".", baddst, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_MERGE|COPY_PRESERVE_FS_VERITY, NULL, NULL), ESOCKTNOSUPPORT);
 
         /* Of course this should fail too... */
-        ASSERT_ERROR(copy_tree_at(badsrc, ".", baddst, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_MERGE|COPY_PRESERVE_FS_VERITY, NULL, NULL), ENOTTY);
+        ASSERT_ERROR(copy_tree_at(badsrc, ".", baddst, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_MERGE|COPY_PRESERVE_FS_VERITY, NULL, NULL), ESOCKTNOSUPPORT);
 
         return 0;
 }