aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Szeredi <miklos@szeredi.hu>2006-01-27 12:49:14 +0000
committerMiklos Szeredi <miklos@szeredi.hu>2006-01-27 12:49:14 +0000
commit1cb9aba6ea86e27bf349a7658b36c0daa4a70908 (patch)
tree387f40289b74940078ffc2f4055295e9def15711
parent3883b4eb0cedb3d628a1267aa97f023cb0a2b9bd (diff)
downloadsshfs-1cb9aba6ea86e27bf349a7658b36c0daa4a70908.tar
sshfs-1cb9aba6ea86e27bf349a7658b36c0daa4a70908.tar.gz
sshfs-1cb9aba6ea86e27bf349a7658b36c0daa4a70908.tar.bz2
sshfs-1cb9aba6ea86e27bf349a7658b36c0daa4a70908.zip
fix
-rw-r--r--.cvsignore2
-rw-r--r--ChangeLog12
-rw-r--r--Makefile.am13
-rw-r--r--bin2c.c36
-rw-r--r--sshfs.c87
-rw-r--r--sshnodelay.c17
6 files changed, 157 insertions, 10 deletions
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 <miklos@szeredi.hu>
+
+ * 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 <miklos@szeredi.hu>
* 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 <mpm@selenic.com>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#include <stdio.h>
+
+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 <dlfcn.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+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;
+}