From 1cb9aba6ea86e27bf349a7658b36c0daa4a70908 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Fri, 27 Jan 2006 12:49:14 +0000 Subject: fix --- .cvsignore | 2 ++ ChangeLog | 12 +++++++++ Makefile.am | 13 +++++++-- bin2c.c | 36 +++++++++++++++++++++++++ sshfs.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------ sshnodelay.c | 17 ++++++++++++ 6 files changed, 157 insertions(+), 10 deletions(-) create mode 100644 bin2c.c create mode 100644 sshnodelay.c diff --git a/.cvsignore b/.cvsignore index 3a39ae6..a91f036 100644 --- a/.cvsignore +++ b/.cvsignore @@ -14,3 +14,5 @@ missing sshfs stamp* .deps +bin2c +sshnodelay_so.c diff --git a/ChangeLog b/ChangeLog index b422a5c..849d4df 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2006-01-27 Miklos Szeredi + + * Add workaround (enabled by default) for ssh clients not setting + TCP_NODELAY on the network connection. Currently this is all + known versions of openssh. This may improve download speed in + some circumstances + + * Change the rename workaround to be enabled by default + + * Make it possible to idividually disable workarounds with a "no" + prefix + 2006-01-25 Miklos Szeredi * Use TCP_NODELAY socket option for direct connection. This may diff --git a/Makefile.am b/Makefile.am index dc4befc..8869467 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,9 +2,18 @@ bin_PROGRAMS = sshfs +sshfs_SOURCES = sshfs.c cache.c cache.h sshnodelay_so.c if FUSE_OPT_COMPAT -compat_sources = compat/fuse_opt.c compat/fuse_opt.h +sshfs_SOURCES += compat/fuse_opt.c compat/fuse_opt.h endif -sshfs_SOURCES = sshfs.c cache.c cache.h $(compat_sources) sshfs_CPPFLAGS = -DFUSE_USE_VERSION=26 + +EXTRA_DIST = sshnodelay.c bin2c.c +CLEANFILES = sshnodelay.so sshnodelay_so.c bin2c + +sshnodelay_so.c: bin2c sshnodelay.so + ./bin2c sshnodelay_so < sshnodelay.so > sshnodelay_so.c + +sshnodelay.so: + $(CC) -Wall -W -s --shared -ldl sshnodelay.c -o sshnodelay.so diff --git a/bin2c.c b/bin2c.c new file mode 100644 index 0000000..96dd2bc --- /dev/null +++ b/bin2c.c @@ -0,0 +1,36 @@ +/* + * Unloved program to convert a binary on stdin to a C include on stdout + * + * Jan 1999 Matt Mackall + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + */ + +#include + +int main(int argc, char *argv[]) +{ + int ch, total=0; + + if (argc > 1) + printf("const char %s[] %s=\n", + argv[1], argc > 2 ? argv[2] : ""); + + do { + printf("\t\""); + while ((ch = getchar()) != EOF) + { + total++; + printf("\\x%02x",ch); + if (total % 16 == 0) + break; + } + printf("\"\n"); + } while (ch != EOF); + + if (argc > 1) + printf("\t;\n\nconst int %s_size = %d;\n", argv[1], total); + + return 0; +} diff --git a/sshfs.c b/sshfs.c index bf4fae8..fa1b6a5 100644 --- a/sshfs.c +++ b/sshfs.c @@ -149,7 +149,9 @@ struct sshfs { char *sftp_server; char *mountpoint; struct fuse_args ssh_args; + char *workarounds; int rename_workaround; + int nodelay_workaround; int transform_symlinks; int detect_uid; unsigned max_read; @@ -237,9 +239,7 @@ static struct fuse_opt sshfs_opts[] = { SSHFS_OPT("max_read=%u", max_read, 0), SSHFS_OPT("ssh_protocol=%u", ssh_ver, 0), SSHFS_OPT("-1", ssh_ver, 1), - SSHFS_OPT("workaround=none", rename_workaround, 0), - SSHFS_OPT("workaround=rename", rename_workaround, 1), - SSHFS_OPT("workaround=all", rename_workaround, 1), + SSHFS_OPT("workaround=%s", workarounds, 0), SSHFS_OPT("idmap=none", detect_uid, 0), SSHFS_OPT("idmap=user", detect_uid, 1), SSHFS_OPT("sshfs_sync", sync_write, 1), @@ -257,6 +257,18 @@ static struct fuse_opt sshfs_opts[] = { FUSE_OPT_END }; +static struct fuse_opt workaround_opts[] = { + SSHFS_OPT("none", rename_workaround, 0), + SSHFS_OPT("none", nodelay_workaround, 0), + SSHFS_OPT("all", rename_workaround, 1), + SSHFS_OPT("all", nodelay_workaround, 1), + SSHFS_OPT("rename", rename_workaround, 1), + SSHFS_OPT("norename", rename_workaround, 0), + SSHFS_OPT("nodelay", nodelay_workaround, 1), + SSHFS_OPT("nonodelay", nodelay_workaround, 0), + FUSE_OPT_END +}; + #define DEBUG(format, args...) \ do { if (sshfs.debug) fprintf(stderr, format, args); } while(0) @@ -600,6 +612,32 @@ static void ssh_add_arg(const char *arg) _exit(1); } +static void do_ssh_nodelay_workaround(void) +{ + FILE *tmp = tmpfile(); + int fd = tmp ? dup(fileno(tmp)) : -1; + extern const char sshnodelay_so[]; + extern const int sshnodelay_so_size; + char *oldpreload = getenv("LD_PRELOAD"); + char *newpreload; + + fclose(tmp); + if (fd == -1 || write(fd, sshnodelay_so, sshnodelay_so_size) == -1) { + fprintf(stderr, "warning: failed to write file for ssh nodelay workaround\n"); + return; + } + + newpreload = g_strdup_printf("%s%s/proc/self/fd/%i", + oldpreload ? oldpreload : "", + oldpreload ? " " : "", fd); + + if (!newpreload || setenv("LD_PRELOAD", newpreload, 1) == -1) { + fprintf(stderr, "warning: failed set LD_PRELOAD for ssh nodelay workaround\n"); + close(fd); + } + g_free(newpreload); +} + static int start_ssh(void) { int inpipe[2]; @@ -620,6 +658,9 @@ static int start_ssh(void) } else if (pid == 0) { int devnull; + if (sshfs.nodelay_workaround) + do_ssh_nodelay_workaround(); + devnull = open("/dev/null", O_WRONLY); if (dup2(outpipe[0], 0) == -1 || dup2(inpipe[1], 1) == -1) { @@ -1960,9 +2001,10 @@ static void usage(const char *progname) " -o cache_timeout=N sets timeout for caches in seconds (default: 20)\n" " -o cache_X_timeout=N sets timeout for {stat,dir,link} cache\n" " -o workaround=LIST colon separated list of workarounds\n" -" none no workarounds enabled (default)\n" -" all all workarounds enabled\n" -" rename work around problem renaming to existing file\n" +" none no workarounds enabled\n" +" all all workarounds enabled (default)\n" +" [no]rename fix renaming to existing file\n" +" [no]nodelay set nodelay tcp flag in ssh\n" " -o idmap=TYPE user/group ID mapping, possible types are:\n" " none no translation of the ID space (default)\n" " user only translate UID of connecting user\n" @@ -1970,7 +2012,7 @@ static void usage(const char *progname) " -o ssh_protocol=N ssh protocol to use (default: 2)\n" " -o sftp_server=SERV path to sftp server or subsystem (default: sftp)\n" " -o directport=PORT directly connect to PORT bypassing ssh\n" -" -o transform_symlinks prepend mountpoint to absolute symlink targets\n" +" -o transform_symlinks transform absolute symlinks to relative\n" " -o SSHOPT=VAL ssh options (see man ssh_config)\n" "\n", progname); } @@ -2044,6 +2086,32 @@ static int sshfs_opt_proc(void *data, const char *arg, int key, } } +static int workaround_opt_proc(void *data, const char *arg, int key, + struct fuse_args *outargs) +{ + (void) data; (void) key; (void) outargs; + fprintf(stderr, "unknown workaround: '%s'\n", arg); + return -1; +} + +int parse_workarounds(void) +{ + int res; + char *argv[] = { "", "-o", sshfs.workarounds, NULL }; + struct fuse_args args = FUSE_ARGS_INIT(3, argv); + char *s = sshfs.workarounds; + if (!s) + return 0; + + while ((s = strchr(s, ':'))) + *s = ','; + + res = fuse_opt_parse(&args, &sshfs, workaround_opts, workaround_opt_proc); + fuse_opt_free_args(&args); + + return res; +} + int main(int argc, char *argv[]) { int res; @@ -2055,13 +2123,16 @@ int main(int argc, char *argv[]) sshfs.blksize = 4096; sshfs.max_read = 65536; + sshfs.nodelay_workaround = 1; + sshfs.rename_workaround = 1; sshfs.ssh_ver = 2; ssh_add_arg("ssh"); ssh_add_arg("-x"); ssh_add_arg("-a"); ssh_add_arg("-oClearAllForwardings=yes"); - if (fuse_opt_parse(&args, &sshfs, sshfs_opts, sshfs_opt_proc) == -1) + if (fuse_opt_parse(&args, &sshfs, sshfs_opts, sshfs_opt_proc) == -1 || + parse_workarounds() == -1) exit(1); if (!sshfs.host) { diff --git a/sshnodelay.c b/sshnodelay.c new file mode 100644 index 0000000..9e30f27 --- /dev/null +++ b/sshnodelay.c @@ -0,0 +1,17 @@ +#define _GNU_SOURCE +#include +#include +#include +#include + +int connect(int sock, const struct sockaddr *addr, socklen_t addrlen) +{ + int (*next_connect)(int, const struct sockaddr *, socklen_t) = + dlsym(RTLD_NEXT, "connect"); + int res = next_connect(sock, addr, addrlen); + if (!res && addr->sa_family == AF_INET) { + int opt = 1; + setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)); + } + return res; +} -- cgit v1.2.3