summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRyo Nakamura <upa@haeena.net>2022-11-12 17:30:51 +0900
committerRyo Nakamura <upa@haeena.net>2022-11-12 17:30:51 +0900
commit756e0759f9539b9dab5556c7cd7873396b429834 (patch)
tree0e1a3112162d0015100f8867905db22a8bab167c /src
parent71d827d613452db00bad1fea8bc272f788e6e649 (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.c46
-rw-r--r--src/main.c5
2 files changed, 36 insertions, 15 deletions
diff --git a/src/file.c b/src/file.c
index 6b6e6e0..caebcc6 100644
--- a/src/file.c
+++ b/src/file.c
@@ -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;
diff --git a/src/main.c b/src/main.c
index fdde0e1..b8b2247 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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"