chiark / gitweb /
import: also set NOCOW for gpt disk images
[elogind.git] / src / import / import-gpt.c
index e1c493b..d304a39 100644 (file)
@@ -20,6 +20,7 @@
 ***/
 
 #include <sys/xattr.h>
+#include <linux/fs.h>
 #include <curl/curl.h>
 
 #include "hashmap.h"
@@ -60,6 +61,7 @@ struct GptImport {
         sd_event *event;
         CurlGlue *glue;
 
+        char *image_root;
         Hashmap *files;
 
         gpt_import_on_finished on_finished;
@@ -129,9 +131,9 @@ static int gpt_import_file_make_final_path(GptImportFile *f) {
                 if (!escaped_etag)
                         return -ENOMEM;
 
-                f->final_path = strjoin("/var/lib/container/.gpt-", escaped_url, ".", escaped_etag, ".gpt", NULL);
+                f->final_path = strjoin(f->import->image_root, "/.gpt-", escaped_url, ".", escaped_etag, ".gpt", NULL);
         } else
-                f->final_path = strjoin("/var/lib/container/.gpt-", escaped_url, ".gpt", NULL);
+                f->final_path = strjoin(f->import->image_root, "/.gpt-", escaped_url, ".gpt", NULL);
         if (!f->final_path)
                 return -ENOMEM;
 
@@ -164,12 +166,12 @@ static void gpt_import_file_success(GptImportFile *f) {
 
                         f->disk_fd = open(f->final_path, O_RDONLY|O_NOCTTY|O_CLOEXEC);
                         if (f->disk_fd < 0) {
-                                r = log_error_errno(errno, "Failed top open vendor image: %m");
+                                r = log_error_errno(errno, "Failed to open vendor image: %m");
                                 goto finish;
                         }
                 }
 
-                p = strappenda("/var/lib/container/", f->local, ".gpt");
+                p = strappenda(f->import->image_root, "/", f->local, ".gpt");
                 if (f->force_local)
                         (void) rm_rf_dangerous(p, false, true, false);
 
@@ -185,6 +187,14 @@ static void gpt_import_file_success(GptImportFile *f) {
                         goto finish;
                 }
 
+                /* Turn off COW writing. This should greatly improve
+                 * performance on COW file systems like btrfs, since it
+                 * reduces fragmentation caused by not allowing in-place
+                 * writes. */
+                r = chattr_fd(dfd, true, FS_NOCOW_FL);
+                if (r < 0)
+                        log_warning_errno(errno, "Failed to set file attributes on %s: %m", f->temp_path);
+
                 r = copy_bytes(f->disk_fd, dfd, (off_t) -1, true);
                 if (r < 0) {
                         log_error_errno(r, "Failed to make writable copy of image: %m");
@@ -469,7 +479,7 @@ static int gpt_import_file_find_old_etags(GptImportFile *f) {
         if (!escaped_url)
                 return -ENOMEM;
 
-        d = opendir("/var/lib/container/");
+        d = opendir(f->import->image_root);
         if (!d) {
                 if (errno == ENOENT)
                         return 0;
@@ -575,11 +585,12 @@ static int gpt_import_file_begin(GptImportFile *f) {
         return 0;
 }
 
-int gpt_import_new(GptImport **import, sd_event *event, gpt_import_on_finished on_finished, void *userdata) {
+int gpt_import_new(GptImport **import, sd_event *event, const char *image_root, gpt_import_on_finished on_finished, void *userdata) {
         _cleanup_(gpt_import_unrefp) GptImport *i = NULL;
         int r;
 
         assert(import);
+        assert(image_root);
 
         i = new0(GptImport, 1);
         if (!i)
@@ -588,6 +599,10 @@ int gpt_import_new(GptImport **import, sd_event *event, gpt_import_on_finished o
         i->on_finished = on_finished;
         i->userdata = userdata;
 
+        i->image_root = strdup(image_root);
+        if (!i->image_root)
+                return -ENOMEM;
+
         if (event)
                 i->event = sd_event_ref(event);
         else {
@@ -622,6 +637,7 @@ GptImport* gpt_import_unref(GptImport *import) {
         curl_glue_unref(import->glue);
         sd_event_unref(import->event);
 
+        free(import->image_root);
         free(import);
 
         return NULL;