diff options
author | Benjamin Fleischer <fleiben@gmail.com> | 2014-02-02 23:16:13 +0100 |
---|---|---|
committer | Benjamin Fleischer <fleiben@gmail.com> | 2014-02-02 23:16:13 +0100 |
commit | b42f84218c0a463c9a708eb0eb8c9469d92c63d5 (patch) | |
tree | 560a99721bdb1ac28c7c6d06ac22331166d0cda1 | |
parent | 990f30d767063c086710ea52ad2c70237338434a (diff) | |
parent | 6b4415ada44e0cbf1924f534cd04d117a5a4dbd3 (diff) | |
download | sshfs-b42f84218c0a463c9a708eb0eb8c9469d92c63d5.tar sshfs-b42f84218c0a463c9a708eb0eb8c9469d92c63d5.tar.gz sshfs-b42f84218c0a463c9a708eb0eb8c9469d92c63d5.tar.bz2 sshfs-b42f84218c0a463c9a708eb0eb8c9469d92c63d5.zip |
Merge tag 'sshfs_2_5'
Conflicts:
sshfs.c
-rw-r--r-- | ChangeLog | 18 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | sshfs.1.in | 10 | ||||
-rw-r--r-- | sshfs.c | 143 |
4 files changed, 160 insertions, 13 deletions
@@ -1,3 +1,21 @@ +2014-01-14 Miklos Szeredi <miklos@szeredi.hu> + + * Released 2.5 + +2014-01-08 Miklos Szeredi <miklos@szeredi.hu> + + * Add -o disable_hardlink option (debian bug #670926). Reported + by Louis-David Mitterrand + + * Optimize readdir by sending multiple requests in parallel. Add + -o sync_readdir to restore old behavior. Patch by Alexander + Neumann + +2014-01-07 Miklos Szeredi <miklos@szeredi.hu> + + * Map SSH2_FX_FAILURE to ENOTEMPTY for rmdir. Reported by Ross + Lagerwall + 2012-05-14 Miklos Szeredi <miklos@szeredi.hu> * When checking root directory use LSTAT not STAT. This prevents diff --git a/configure.ac b/configure.ac index 8089111..b64b8d1 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT(sshfs-fuse, 2.4) +AC_INIT(sshfs-fuse, 2.5) AM_INIT_AUTOMAKE AM_CONFIG_HEADER(config.h) @@ -62,6 +62,9 @@ synchronous writes \fB\-o\fR no_readahead synchronous reads (no speculative readahead) .TP +\fB\-o\fR sync_readdir +synchronous readdir +.TP \fB\-o\fR sshfs_debug print some debugging information .TP @@ -156,6 +159,11 @@ communicate over stdin and stdout bypassing network \fB\-o\fR slave communicate over stdin and stdout bypassing network .TP +\fB\-o\fR disable_hardlink +link(2) will return with errno set to ENOSYS. Hard links don't currently work +perfectly on sshfs, and this confuses some programs. If that happens try +disabling hard links with this option. +.TP \fB\-o\fR transform_symlinks transform absolute symlinks to relative .TP @@ -271,7 +279,7 @@ perform reads synchronously \fB\-o\fR subdir=DIR prepend this directory to all paths (mandatory) .TP -\fB\-o\fR [no]rellinksa +\fB\-o\fR [no]rellinks transform absolute symlinks to relative .TP [iconv] @@ -135,6 +135,10 @@ #define SSHNODELAY_SO "sshnodelay.so" +/* Asynchronous readdir parameters */ +#define READDIR_START 2 +#define READDIR_MAX 32 + #ifdef __APPLE__ #ifndef LIBDIR @@ -163,6 +167,7 @@ struct request { unsigned int want_reply; sem_t ready; uint8_t reply_type; + uint32_t id; int replied; int error; struct buffer reply; @@ -230,6 +235,7 @@ struct sshfs { int detect_uid; int idmap; int nomap; + int disable_hardlink; char *uid_file; char *gid_file; GHashTable *uid_map; @@ -241,6 +247,7 @@ struct sshfs { unsigned ssh_ver; int sync_write; int sync_read; + int sync_readdir; int debug; int foreground; int reconnect; @@ -381,6 +388,7 @@ static struct fuse_opt sshfs_opts[] = { SSHFS_OPT("nomap=error", nomap, NOMAP_ERROR), SSHFS_OPT("sshfs_sync", sync_write, 1), SSHFS_OPT("no_readahead", sync_read, 1), + SSHFS_OPT("sync_readdir", sync_readdir, 1), SSHFS_OPT("sshfs_debug", debug, 1), SSHFS_OPT("reconnect", reconnect, 1), SSHFS_OPT("transform_symlinks", transform_symlinks, 1), @@ -389,6 +397,7 @@ static struct fuse_opt sshfs_opts[] = { SSHFS_OPT("password_stdin", password_stdin, 1), SSHFS_OPT("delay_connect", delay_connect, 1), SSHFS_OPT("slave", slave, 1), + SSHFS_OPT("disable_hardlink", disable_hardlink, 1), FUSE_OPT_KEY("-p ", KEY_PORT), FUSE_OPT_KEY("-C", KEY_COMPRESS), @@ -1867,6 +1876,13 @@ static int sftp_request_wait(struct request *req, uint8_t type, err = -EIO; break; + case SSH_FX_FAILURE: + if (type == SSH_FXP_RMDIR) + err = -ENOTEMPTY; + else + err = -EPERM; + break; + default: err = -sftp_error_to_errno(serr); } @@ -1904,6 +1920,7 @@ static int sftp_request_send(uint8_t type, struct iovec *iov, size_t count, if (begin_func) begin_func(req); id = sftp_get_id(); + req->id = id; err = start_processing_thread(); if (err) { pthread_mutex_unlock(&sshfs.lock); @@ -2091,6 +2108,113 @@ static int sshfs_readlink(const char *path, char *linkbuf, size_t size) return err; } +static int sftp_readdir_send(struct request **req, struct buffer *handle) +{ + struct iovec iov; + + buf_to_iov(handle, &iov); + return sftp_request_send(SSH_FXP_READDIR, &iov, 1, NULL, NULL, + SSH_FXP_NAME, NULL, req); +} + +static int sshfs_req_pending(struct request *req) +{ + if (g_hash_table_lookup(sshfs.reqtab, GUINT_TO_POINTER(req->id))) + return 1; + else + return 0; +} + +static int sftp_readdir_async(struct buffer *handle, fuse_cache_dirh_t h, + fuse_cache_dirfil_t filler) +{ + int err = 0; + int outstanding = 0; + int max = READDIR_START; + GList *list = NULL; + + int done = 0; + + while (!done || outstanding) { + struct request *req; + struct buffer name; + int tmperr; + + while (!done && outstanding < max) { + tmperr = sftp_readdir_send(&req, handle); + + if (tmperr && !done) { + err = tmperr; + done = 1; + break; + } + + list = g_list_append(list, req); + outstanding++; + } + + if (outstanding) { + GList *first; + /* wait for response to next request */ + first = g_list_first(list); + req = first->data; + list = g_list_delete_link(list, first); + outstanding--; + + if (done) { + pthread_mutex_lock(&sshfs.lock); + if (sshfs_req_pending(req)) + req->want_reply = 0; + pthread_mutex_unlock(&sshfs.lock); + if (!req->want_reply) + continue; + } + + tmperr = sftp_request_wait(req, SSH_FXP_READDIR, + SSH_FXP_NAME, &name); + + if (tmperr && !done) { + err = tmperr; + if (err == MY_EOF) + err = 0; + done = 1; + } + if (!done) { + err = buf_get_entries(&name, h, filler); + buf_free(&name); + + /* increase number of outstanding requests */ + if (max < READDIR_MAX) + max++; + + if (err) + done = 1; + } + } + } + assert(list == NULL); + + return err; +} + +static int sftp_readdir_sync(struct buffer *handle, fuse_cache_dirh_t h, + fuse_cache_dirfil_t filler) +{ + int err; + do { + struct buffer name; + err = sftp_request(SSH_FXP_READDIR, handle, SSH_FXP_NAME, &name); + if (!err) { + err = buf_get_entries(&name, h, filler); + buf_free(&name); + } + } while (!err); + if (err == MY_EOF) + err = 0; + + return err; +} + static int sshfs_getdir(const char *path, fuse_cache_dirh_t h, fuse_cache_dirfil_t filler) { @@ -2103,16 +2227,11 @@ static int sshfs_getdir(const char *path, fuse_cache_dirh_t h, if (!err) { int err2; buf_finish(&handle); - do { - struct buffer name; - err = sftp_request(SSH_FXP_READDIR, &handle, SSH_FXP_NAME, &name); - if (!err) { - err = buf_get_entries(&name, h, filler); - buf_free(&name); - } - } while (!err); - if (err == MY_EOF) - err = 0; + + if (sshfs.sync_readdir) + err = sftp_readdir_sync(&handle, h, filler); + else + err = sftp_readdir_async(&handle, h, filler); err2 = sftp_request(SSH_FXP_CLOSE, &handle, 0, NULL); if (!err) @@ -2269,7 +2388,7 @@ static int sshfs_link(const char *from, const char *to) { int err = -ENOSYS; - if (sshfs.ext_hardlink) { + if (sshfs.ext_hardlink && !sshfs.disable_hardlink) { struct buffer buf; buf_init(&buf, 0); @@ -3279,6 +3398,7 @@ static void usage(const char *progname) " -o delay_connect delay connection to server\n" " -o sshfs_sync synchronous writes\n" " -o no_readahead synchronous reads (no speculative readahead)\n" +" -o sync_readdir synchronous readdir\n" " -o sshfs_debug print some debugging information\n" " -o cache=BOOL enable caching {yes,no} (default: yes)\n" " -o cache_timeout=N sets timeout for caches in seconds (default: 20)\n" @@ -3312,6 +3432,7 @@ static void usage(const char *progname) " -o sftp_server=SERV path to sftp server or subsystem (default: sftp)\n" " -o directport=PORT directly connect to PORT bypassing ssh\n" " -o slave communicate over stdin and stdout bypassing network\n" +" -o disable_hardlink link(2) will return with errno set to ENOSYS\n" " -o transform_symlinks transform absolute symlinks to relative\n" " -o follow_symlinks follow symlinks on the server\n" " -o no_check_root don't check for existence of 'dir' on server\n" |