Beispiel #1
0
static int raw_import_try_reflink(RawImport *i) {
        off_t p;
        int r;

        assert(i);
        assert(i->input_fd >= 0);
        assert(i->output_fd >= 0);

        if (i->compress.type != IMPORT_COMPRESS_UNCOMPRESSED)
                return 0;

        if (!S_ISREG(i->st.st_mode))
                return 0;

        p = lseek(i->input_fd, 0, SEEK_CUR);
        if (p == (off_t) -1)
                return log_error_errno(errno, "Failed to read file offset of input file: %m");

        /* Let's only try a btrfs reflink, if we are reading from the beginning of the file */
        if ((uint64_t) p != (uint64_t) i->buffer_size)
                return 0;

        r = btrfs_reflink(i->input_fd, i->output_fd);
        if (r >= 0)
                return 1;

        return 0;
}
Beispiel #2
0
static int reflink_snapshot(int fd, const char *path) {
        char *p, *d;
        int new_fd, r;

        p = strdupa(path);
        d = dirname(p);

        new_fd = open(d, O_TMPFILE|O_CLOEXEC|O_NOCTTY|O_RDWR, 0600);
        if (new_fd < 0) {
                _cleanup_free_ char *t = NULL;

                r = tempfn_random(path, NULL, &t);
                if (r < 0)
                        return r;

                new_fd = open(t, O_CLOEXEC|O_CREAT|O_NOCTTY|O_RDWR, 0600);
                if (new_fd < 0)
                        return -errno;

                (void) unlink(t);
        }

        r = btrfs_reflink(fd, new_fd);
        if (r < 0) {
                safe_close(new_fd);
                return r;
        }

        return new_fd;
}
Beispiel #3
0
static int raw_export_process(RawExport *e) {
        ssize_t l;
        int r;

        assert(e);

        if (!e->tried_reflink && e->compress.type == IMPORT_COMPRESS_UNCOMPRESSED) {

                /* If we shall take an uncompressed snapshot we can
                 * reflink source to destination directly. Let's see
                 * if this works. */

                r = btrfs_reflink(e->input_fd, e->output_fd);
                if (r >= 0) {
                        r = 0;
                        goto finish;
                }

                e->tried_reflink = true;
        }

        if (!e->tried_sendfile && e->compress.type == IMPORT_COMPRESS_UNCOMPRESSED) {

                l = sendfile(e->output_fd, e->input_fd, NULL, COPY_BUFFER_SIZE);
                if (l < 0) {
                        if (errno == EAGAIN)
                                return 0;

                        e->tried_sendfile = true;
                } else if (l == 0) {
                        r = 0;
                        goto finish;
                } else {
                        e->written_uncompressed += l;
                        e->written_compressed += l;

                        raw_export_report_progress(e);

                        return 0;
                }
        }

        while (e->buffer_size <= 0) {
                uint8_t input[COPY_BUFFER_SIZE];

                if (e->eof) {
                        r = 0;
                        goto finish;
                }

                l = read(e->input_fd, input, sizeof(input));
                if (l < 0) {
                        r = log_error_errno(errno, "Failed to read raw file: %m");
                        goto finish;
                }

                if (l == 0) {
                        e->eof = true;
                        r = import_compress_finish(&e->compress, &e->buffer, &e->buffer_size, &e->buffer_allocated);
                } else {
                        e->written_uncompressed += l;
                        r = import_compress(&e->compress, input, l, &e->buffer, &e->buffer_size, &e->buffer_allocated);
                }
                if (r < 0) {
                        r = log_error_errno(r, "Failed to encode: %m");
                        goto finish;
                }
        }

        l = write(e->output_fd, e->buffer, e->buffer_size);
        if (l < 0) {
                if (errno == EAGAIN)
                        return 0;

                r = log_error_errno(errno, "Failed to write output file: %m");
                goto finish;
        }

        assert((size_t) l <= e->buffer_size);
        memmove(e->buffer, (uint8_t*) e->buffer + l, e->buffer_size - l);
        e->buffer_size -= l;
        e->written_compressed += l;

        raw_export_report_progress(e);

        return 0;

finish:
        if (r >= 0) {
                (void) copy_times(e->input_fd, e->output_fd);
                (void) copy_xattr(e->input_fd, e->output_fd);
        }

        if (e->on_finished)
                e->on_finished(e, r, e->userdata);
        else
                sd_event_exit(e->event, r);

        return 0;
}
Beispiel #4
0
int copy_bytes(int fdf, int fdt, off_t max_bytes, bool try_reflink) {
        bool try_sendfile = true;
        int r;

        assert(fdf >= 0);
        assert(fdt >= 0);

        /* Try btrfs reflinks first. */
        if (try_reflink && max_bytes == (off_t) -1) {
                r = btrfs_reflink(fdf, fdt);
                if (r >= 0)
                        return r;
        }

        for (;;) {
                size_t m = COPY_BUFFER_SIZE;
                ssize_t n;

                if (max_bytes != (off_t) -1) {

                        if (max_bytes <= 0)
                                return -EFBIG;

                        if ((off_t) m > max_bytes)
                                m = (size_t) max_bytes;
                }

                /* First try sendfile(), unless we already tried */
                if (try_sendfile) {

                        n = sendfile(fdt, fdf, NULL, m);
                        if (n < 0) {
                                if (errno != EINVAL && errno != ENOSYS)
                                        return -errno;

                                try_sendfile = false;
                                /* use fallback below */
                        } else if (n == 0) /* EOF */
                                break;
                        else if (n > 0)
                                /* Succcess! */
                                goto next;
                }

                /* As a fallback just copy bits by hand */
                {
                        char buf[m];

                        n = read(fdf, buf, m);
                        if (n < 0)
                                return -errno;
                        if (n == 0) /* EOF */
                                break;

                        r = loop_write(fdt, buf, (size_t) n, false);
                        if (r < 0)
                                return r;
                }

        next:
                if (max_bytes != (off_t) -1) {
                        assert(max_bytes >= n);
                        max_bytes -= n;
                }
        }

        return 0;
}