LCOV - code coverage report
Current view: top level - import - export-raw.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 0 156 0.0 %
Date: 2019-08-22 15:41:25 Functions: 0 8 0.0 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <sys/sendfile.h>
       4             : 
       5             : /* When we include libgen.h because we need dirname() we immediately
       6             :  * undefine basename() since libgen.h defines it as a macro to the POSIX
       7             :  * version which is really broken. We prefer GNU basename(). */
       8             : #include <libgen.h>
       9             : #undef basename
      10             : 
      11             : #include "sd-daemon.h"
      12             : 
      13             : #include "alloc-util.h"
      14             : #include "btrfs-util.h"
      15             : #include "copy.h"
      16             : #include "export-raw.h"
      17             : #include "fd-util.h"
      18             : #include "fs-util.h"
      19             : #include "import-common.h"
      20             : #include "missing.h"
      21             : #include "ratelimit.h"
      22             : #include "stat-util.h"
      23             : #include "string-util.h"
      24             : #include "tmpfile-util.h"
      25             : #include "util.h"
      26             : 
      27             : #define COPY_BUFFER_SIZE (16*1024)
      28             : 
      29             : struct RawExport {
      30             :         sd_event *event;
      31             : 
      32             :         RawExportFinished on_finished;
      33             :         void *userdata;
      34             : 
      35             :         char *path;
      36             : 
      37             :         int input_fd;
      38             :         int output_fd;
      39             : 
      40             :         ImportCompress compress;
      41             : 
      42             :         sd_event_source *output_event_source;
      43             : 
      44             :         void *buffer;
      45             :         size_t buffer_size;
      46             :         size_t buffer_allocated;
      47             : 
      48             :         uint64_t written_compressed;
      49             :         uint64_t written_uncompressed;
      50             : 
      51             :         unsigned last_percent;
      52             :         RateLimit progress_rate_limit;
      53             : 
      54             :         struct stat st;
      55             : 
      56             :         bool eof;
      57             :         bool tried_reflink;
      58             :         bool tried_sendfile;
      59             : };
      60             : 
      61           0 : RawExport *raw_export_unref(RawExport *e) {
      62           0 :         if (!e)
      63           0 :                 return NULL;
      64             : 
      65           0 :         sd_event_source_unref(e->output_event_source);
      66             : 
      67           0 :         import_compress_free(&e->compress);
      68             : 
      69           0 :         sd_event_unref(e->event);
      70             : 
      71           0 :         safe_close(e->input_fd);
      72             : 
      73           0 :         free(e->buffer);
      74           0 :         free(e->path);
      75           0 :         return mfree(e);
      76             : }
      77             : 
      78           0 : int raw_export_new(
      79             :                 RawExport **ret,
      80             :                 sd_event *event,
      81             :                 RawExportFinished on_finished,
      82             :                 void *userdata) {
      83             : 
      84           0 :         _cleanup_(raw_export_unrefp) RawExport *e = NULL;
      85             :         int r;
      86             : 
      87           0 :         assert(ret);
      88             : 
      89           0 :         e = new(RawExport, 1);
      90           0 :         if (!e)
      91           0 :                 return -ENOMEM;
      92             : 
      93           0 :         *e = (RawExport) {
      94             :                 .output_fd = -1,
      95             :                 .input_fd = -1,
      96             :                 .on_finished = on_finished,
      97             :                 .userdata = userdata,
      98             :                 .last_percent = (unsigned) -1,
      99             :         };
     100             : 
     101           0 :         RATELIMIT_INIT(e->progress_rate_limit, 100 * USEC_PER_MSEC, 1);
     102             : 
     103           0 :         if (event)
     104           0 :                 e->event = sd_event_ref(event);
     105             :         else {
     106           0 :                 r = sd_event_default(&e->event);
     107           0 :                 if (r < 0)
     108           0 :                         return r;
     109             :         }
     110             : 
     111           0 :         *ret = TAKE_PTR(e);
     112             : 
     113           0 :         return 0;
     114             : }
     115             : 
     116           0 : static void raw_export_report_progress(RawExport *e) {
     117             :         unsigned percent;
     118           0 :         assert(e);
     119             : 
     120           0 :         if (e->written_uncompressed >= (uint64_t) e->st.st_size)
     121           0 :                 percent = 100;
     122             :         else
     123           0 :                 percent = (unsigned) ((e->written_uncompressed * UINT64_C(100)) / (uint64_t) e->st.st_size);
     124             : 
     125           0 :         if (percent == e->last_percent)
     126           0 :                 return;
     127             : 
     128           0 :         if (!ratelimit_below(&e->progress_rate_limit))
     129           0 :                 return;
     130             : 
     131           0 :         sd_notifyf(false, "X_IMPORT_PROGRESS=%u", percent);
     132           0 :         log_info("Exported %u%%.", percent);
     133             : 
     134           0 :         e->last_percent = percent;
     135             : }
     136             : 
     137           0 : static int raw_export_process(RawExport *e) {
     138             :         ssize_t l;
     139             :         int r;
     140             : 
     141           0 :         assert(e);
     142             : 
     143           0 :         if (!e->tried_reflink && e->compress.type == IMPORT_COMPRESS_UNCOMPRESSED) {
     144             : 
     145             :                 /* If we shall take an uncompressed snapshot we can
     146             :                  * reflink source to destination directly. Let's see
     147             :                  * if this works. */
     148             : 
     149           0 :                 r = btrfs_reflink(e->input_fd, e->output_fd);
     150           0 :                 if (r >= 0) {
     151           0 :                         r = 0;
     152           0 :                         goto finish;
     153             :                 }
     154             : 
     155           0 :                 e->tried_reflink = true;
     156             :         }
     157             : 
     158           0 :         if (!e->tried_sendfile && e->compress.type == IMPORT_COMPRESS_UNCOMPRESSED) {
     159             : 
     160           0 :                 l = sendfile(e->output_fd, e->input_fd, NULL, COPY_BUFFER_SIZE);
     161           0 :                 if (l < 0) {
     162           0 :                         if (errno == EAGAIN)
     163           0 :                                 return 0;
     164             : 
     165           0 :                         e->tried_sendfile = true;
     166           0 :                 } else if (l == 0) {
     167           0 :                         r = 0;
     168           0 :                         goto finish;
     169             :                 } else {
     170           0 :                         e->written_uncompressed += l;
     171           0 :                         e->written_compressed += l;
     172             : 
     173           0 :                         raw_export_report_progress(e);
     174             : 
     175           0 :                         return 0;
     176             :                 }
     177             :         }
     178             : 
     179           0 :         while (e->buffer_size <= 0) {
     180             :                 uint8_t input[COPY_BUFFER_SIZE];
     181             : 
     182           0 :                 if (e->eof) {
     183           0 :                         r = 0;
     184           0 :                         goto finish;
     185             :                 }
     186             : 
     187           0 :                 l = read(e->input_fd, input, sizeof(input));
     188           0 :                 if (l < 0) {
     189           0 :                         r = log_error_errno(errno, "Failed to read raw file: %m");
     190           0 :                         goto finish;
     191             :                 }
     192             : 
     193           0 :                 if (l == 0) {
     194           0 :                         e->eof = true;
     195           0 :                         r = import_compress_finish(&e->compress, &e->buffer, &e->buffer_size, &e->buffer_allocated);
     196             :                 } else {
     197           0 :                         e->written_uncompressed += l;
     198           0 :                         r = import_compress(&e->compress, input, l, &e->buffer, &e->buffer_size, &e->buffer_allocated);
     199             :                 }
     200           0 :                 if (r < 0) {
     201           0 :                         r = log_error_errno(r, "Failed to encode: %m");
     202           0 :                         goto finish;
     203             :                 }
     204             :         }
     205             : 
     206           0 :         l = write(e->output_fd, e->buffer, e->buffer_size);
     207           0 :         if (l < 0) {
     208           0 :                 if (errno == EAGAIN)
     209           0 :                         return 0;
     210             : 
     211           0 :                 r = log_error_errno(errno, "Failed to write output file: %m");
     212           0 :                 goto finish;
     213             :         }
     214             : 
     215           0 :         assert((size_t) l <= e->buffer_size);
     216           0 :         memmove(e->buffer, (uint8_t*) e->buffer + l, e->buffer_size - l);
     217           0 :         e->buffer_size -= l;
     218           0 :         e->written_compressed += l;
     219             : 
     220           0 :         raw_export_report_progress(e);
     221             : 
     222           0 :         return 0;
     223             : 
     224           0 : finish:
     225           0 :         if (r >= 0) {
     226           0 :                 (void) copy_times(e->input_fd, e->output_fd, COPY_CRTIME);
     227           0 :                 (void) copy_xattr(e->input_fd, e->output_fd);
     228             :         }
     229             : 
     230           0 :         if (e->on_finished)
     231           0 :                 e->on_finished(e, r, e->userdata);
     232             :         else
     233           0 :                 sd_event_exit(e->event, r);
     234             : 
     235           0 :         return 0;
     236             : }
     237             : 
     238           0 : static int raw_export_on_output(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
     239           0 :         RawExport *i = userdata;
     240             : 
     241           0 :         return raw_export_process(i);
     242             : }
     243             : 
     244           0 : static int raw_export_on_defer(sd_event_source *s, void *userdata) {
     245           0 :         RawExport *i = userdata;
     246             : 
     247           0 :         return raw_export_process(i);
     248             : }
     249             : 
     250           0 : static int reflink_snapshot(int fd, const char *path) {
     251             :         int new_fd, r;
     252             : 
     253           0 :         new_fd = open_parent(path, O_TMPFILE|O_CLOEXEC|O_RDWR, 0600);
     254           0 :         if (new_fd < 0) {
     255           0 :                 _cleanup_free_ char *t = NULL;
     256             : 
     257           0 :                 r = tempfn_random(path, NULL, &t);
     258           0 :                 if (r < 0)
     259           0 :                         return r;
     260             : 
     261           0 :                 new_fd = open(t, O_CLOEXEC|O_CREAT|O_NOCTTY|O_RDWR, 0600);
     262           0 :                 if (new_fd < 0)
     263           0 :                         return -errno;
     264             : 
     265           0 :                 (void) unlink(t);
     266             :         }
     267             : 
     268           0 :         r = btrfs_reflink(fd, new_fd);
     269           0 :         if (r < 0) {
     270           0 :                 safe_close(new_fd);
     271           0 :                 return r;
     272             :         }
     273             : 
     274           0 :         return new_fd;
     275             : }
     276             : 
     277           0 : int raw_export_start(RawExport *e, const char *path, int fd, ImportCompressType compress) {
     278           0 :         _cleanup_close_ int sfd = -1, tfd = -1;
     279             :         int r;
     280             : 
     281           0 :         assert(e);
     282           0 :         assert(path);
     283           0 :         assert(fd >= 0);
     284           0 :         assert(compress < _IMPORT_COMPRESS_TYPE_MAX);
     285           0 :         assert(compress != IMPORT_COMPRESS_UNKNOWN);
     286             : 
     287           0 :         if (e->output_fd >= 0)
     288           0 :                 return -EBUSY;
     289             : 
     290           0 :         r = fd_nonblock(fd, true);
     291           0 :         if (r < 0)
     292           0 :                 return r;
     293             : 
     294           0 :         r = free_and_strdup(&e->path, path);
     295           0 :         if (r < 0)
     296           0 :                 return r;
     297             : 
     298           0 :         sfd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
     299           0 :         if (sfd < 0)
     300           0 :                 return -errno;
     301             : 
     302           0 :         if (fstat(sfd, &e->st) < 0)
     303           0 :                 return -errno;
     304           0 :         r = stat_verify_regular(&e->st);
     305           0 :         if (r < 0)
     306           0 :                 return r;
     307             : 
     308             :         /* Try to take a reflink snapshot of the file, if we can t make the export atomic */
     309           0 :         tfd = reflink_snapshot(sfd, path);
     310           0 :         if (tfd >= 0)
     311           0 :                 e->input_fd = TAKE_FD(tfd);
     312             :         else
     313           0 :                 e->input_fd = TAKE_FD(sfd);
     314             : 
     315           0 :         r = import_compress_init(&e->compress, compress);
     316           0 :         if (r < 0)
     317           0 :                 return r;
     318             : 
     319           0 :         r = sd_event_add_io(e->event, &e->output_event_source, fd, EPOLLOUT, raw_export_on_output, e);
     320           0 :         if (r == -EPERM) {
     321           0 :                 r = sd_event_add_defer(e->event, &e->output_event_source, raw_export_on_defer, e);
     322           0 :                 if (r < 0)
     323           0 :                         return r;
     324             : 
     325           0 :                 r = sd_event_source_set_enabled(e->output_event_source, SD_EVENT_ON);
     326             :         }
     327           0 :         if (r < 0)
     328           0 :                 return r;
     329             : 
     330           0 :         e->output_fd = fd;
     331           0 :         return r;
     332             : }

Generated by: LCOV version 1.14