diff options
author | Ryo Nakamura <upa@haeena.net> | 2022-11-12 17:30:51 +0900 |
---|---|---|
committer | Ryo Nakamura <upa@haeena.net> | 2022-11-12 17:30:51 +0900 |
commit | 756e0759f9539b9dab5556c7cd7873396b429834 (patch) | |
tree | 0e1a3112162d0015100f8867905db22a8bab167c /src | |
parent | 71d827d613452db00bad1fea8bc272f788e6e649 (diff) |
fix buf size in remote to local copy.
Too large buffer size for sftp_async_read causes unfinished copy:
sftp_async_read returns 0 althrough data remains.
Diffstat (limited to 'src')
-rw-r--r-- | src/file.c | 46 | ||||
-rw-r--r-- | src/main.c | 5 |
2 files changed, 36 insertions, 15 deletions
@@ -654,13 +654,26 @@ static int chunk_copy_internal_local_to_remote(struct chunk *c, int fd, sftp_fil } static int chunk_copy_internal_remote_to_local(struct chunk *c, int fd, sftp_file sf, - size_t sftp_buf_sz, size_t *counter) + size_t *counter) { -#define AHEAD 8 +#define AHEAD 8 +#define XFER_BUF_SIZE 16384 + ssize_t read_bytes, write_bytes, remaind, thrown; - char buf[sftp_buf_sz]; - int reqs[AHEAD]; + char buf[XFER_BUF_SIZE]; int idx; + struct { + int id; + size_t len; + } reqs[AHEAD]; + + /* TODO: sftp_buf_sz has no effect on remote to local copy. we + * always use 16384 byte buffer pointed by + * https://api.libssh.org/stable/libssh_tutor_sftp.html. The + * larget read length from sftp_async_read is 65536 byte. + * Read sizes larget than 65536 cause a situation where data + * remainds but sftp_async_read returns 0. + */ if (c->len == 0) return 0; @@ -668,26 +681,30 @@ static int chunk_copy_internal_remote_to_local(struct chunk *c, int fd, sftp_fil remaind = thrown = c->len; for (idx = 0; idx < AHEAD && thrown > 0; idx++) { - reqs[idx] = sftp_async_read_begin(sf, min(thrown, sizeof(buf))); - if (reqs[idx] < 0) { + reqs[idx].len = min(thrown, sizeof(buf)); + reqs[idx].id = sftp_async_read_begin(sf, reqs[idx].len); + if (reqs[idx].id < 0) { pr_err("sftp_async_read_begin failed: %d\n", sftp_get_error(sf->sftp)); return -1; } - thrown -= min(thrown, sizeof(buf)); + thrown -= reqs[idx].len; } - idx = 0; - do { - read_bytes = sftp_async_read(sf, buf, sizeof(buf), reqs[idx]); + for (idx = 0; remaind > 0;) { + + read_bytes = sftp_async_read(sf, buf, reqs[idx].len, reqs[idx].id); if (read_bytes == SSH_ERROR) { pr_err("sftp_async_read failed: %d\n", sftp_get_error(sf->sftp)); return -1; } + remaind -= read_bytes; - reqs[idx] = sftp_async_read_begin(sf, min(remaind, sizeof(buf))); - idx = (idx + 1) % AHEAD; + if (remaind > 0) { + reqs[idx].len = min(remaind, sizeof(buf)); + reqs[idx].id = sftp_async_read_begin(sf, reqs[idx].len); + } write_bytes = write(fd, buf, read_bytes); if (write_bytes < 0) { @@ -701,7 +718,8 @@ static int chunk_copy_internal_remote_to_local(struct chunk *c, int fd, sftp_fil } *counter += write_bytes; - } while (remaind > 0); + idx = (idx + 1) % AHEAD; + } return 0; } @@ -777,7 +795,7 @@ static int chunk_copy_remote_to_local(struct chunk *c, sftp_session sftp, goto out; } - ret = chunk_copy_internal_remote_to_local(c, fd, sf, sftp_buf_sz, counter); + ret = chunk_copy_internal_remote_to_local(c, fd, sf, counter); if (ret< 0) goto out; @@ -96,10 +96,13 @@ void usage(bool print_help) { printf(" -n NR_CONNECTIONS number of connections (default: half of # of cpu cores)\n" " -s MIN_CHUNK_SIZE min chunk size (default: 64MB)\n" " -S MAX_CHUNK_SIZE max chunk size (default: filesize / nr_conn)\n" + "\n" " -b SFTP_BUF_SIZE buf size for sftp_read/write (default 131072B)\n" " -B IO_BUF_SIZE buf size for read/write (default 131072B)\n" - " Note that this value is derived from\n" + " Note that the default value is derived from\n" " qemu/block/ssh.c. need investigation...\n" + " -b and -B affect only local to remote copy\n" + "\n" " -v increment verbose output level\n" " -q disable output\n" " -D dry run\n" |