LCOV - code coverage report
Current view: top level - import - export-raw.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 0 156 0.0 %
Date: 2019-08-23 13:36:53 Functions: 0 8 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 106 0.0 %

           Branch data     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