Skip to content

Commit b19e3b8

Browse files
committed
Fix memory leak in conntab
References need to be counted per-path, rather than per connection.
1 parent e910453 commit b19e3b8

1 file changed

Lines changed: 37 additions & 15 deletions

File tree

sshfs.c

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,11 @@ struct sshfs_file {
293293
int modifver;
294294
};
295295

296+
struct conntab_entry {
297+
unsigned refcount;
298+
struct conn *conn;
299+
};
300+
296301
struct sshfs {
297302
char *directport;
298303
char *ssh_command;
@@ -1062,7 +1067,7 @@ static int pty_expect_loop(struct conn *conn)
10621067
static struct conn* get_conn(const struct sshfs_file *sf,
10631068
const char *path)
10641069
{
1065-
struct conn* conn;
1070+
struct conntab_entry *ce;
10661071

10671072
if (sshfs.max_conns == 1)
10681073
return &sshfs.conns[0];
@@ -1072,11 +1077,14 @@ static struct conn* get_conn(const struct sshfs_file *sf,
10721077

10731078
if (path != NULL) {
10741079
pthread_mutex_lock(&sshfs.lock);
1075-
conn = g_hash_table_lookup(sshfs.conntab, path);
1076-
pthread_mutex_unlock(&sshfs.lock);
1080+
ce = g_hash_table_lookup(sshfs.conntab, path);
10771081

1078-
if (conn != NULL)
1082+
if (ce != NULL) {
1083+
struct conn *conn = ce->conn;
1084+
pthread_mutex_unlock(&sshfs.lock);
10791085
return conn;
1086+
}
1087+
pthread_mutex_unlock(&sshfs.lock);
10801088
}
10811089

10821090
int best_index = 0;
@@ -2470,6 +2478,7 @@ static void random_string(char *str, int length)
24702478
static int sshfs_rename(const char *from, const char *to, unsigned int flags)
24712479
{
24722480
int err;
2481+
struct conntab_entry *ce;
24732482

24742483
if(flags != 0)
24752484
return -EINVAL;
@@ -2500,9 +2509,9 @@ static int sshfs_rename(const char *from, const char *to, unsigned int flags)
25002509

25012510
if (!err && sshfs.max_conns > 1) {
25022511
pthread_mutex_lock(&sshfs.lock);
2503-
void *conn = g_hash_table_lookup(sshfs.conntab, from);
2504-
if (conn != NULL) {
2505-
g_hash_table_replace(sshfs.conntab, g_strdup(to), conn);
2512+
ce = g_hash_table_lookup(sshfs.conntab, from);
2513+
if (ce != NULL) {
2514+
g_hash_table_replace(sshfs.conntab, g_strdup(to), ce);
25062515
g_hash_table_remove(sshfs.conntab, from);
25072516
}
25082517
pthread_mutex_unlock(&sshfs.lock);
@@ -2683,6 +2692,7 @@ static int sshfs_open_common(const char *path, mode_t mode,
26832692
struct stat stbuf;
26842693
struct sshfs_file *sf;
26852694
struct request *open_req;
2695+
struct conntab_entry *ce;
26862696
uint32_t pflags = 0;
26872697
struct iovec iov;
26882698
uint8_t type;
@@ -2724,16 +2734,20 @@ static int sshfs_open_common(const char *path, mode_t mode,
27242734
pthread_mutex_lock(&sshfs.lock);
27252735
sf->modifver= sshfs.modifver;
27262736
if (sshfs.max_conns > 1) {
2727-
sf->conn = g_hash_table_lookup(sshfs.conntab, path);
2728-
if (!sf->conn) {
2729-
sf->conn = get_conn(NULL, NULL);
2730-
g_hash_table_insert(sshfs.conntab, g_strdup(path), sf->conn);
2731-
} else {
2732-
assert(sf->conn->file_count > 0);
2737+
ce = g_hash_table_lookup(sshfs.conntab, path);
2738+
if (!ce) {
2739+
ce = g_malloc(sizeof(struct conntab_entry));
2740+
ce->refcount = 0;
2741+
ce->conn = get_conn(NULL, NULL);
2742+
g_hash_table_insert(sshfs.conntab, g_strdup(path), ce);
27332743
}
2744+
sf->conn = ce->conn;
2745+
ce->refcount++;
27342746
sf->conn->file_count++;
2747+
assert(sf->conn->file_count > 0);
27352748
} else {
27362749
sf->conn = &sshfs.conns[0];
2750+
ce = NULL; // only to silence compiler warning
27372751
}
27382752
sf->connver = sf->conn->connver;
27392753
pthread_mutex_unlock(&sshfs.lock);
@@ -2772,8 +2786,11 @@ static int sshfs_open_common(const char *path, mode_t mode,
27722786
cache_invalidate(path);
27732787
if (sshfs.max_conns > 1) {
27742788
pthread_mutex_lock(&sshfs.lock);
2775-
if(--sf->conn->file_count == 0) {
2789+
sf->conn->file_count--;
2790+
ce->refcount--;
2791+
if(ce->refcount == 0) {
27762792
g_hash_table_remove(sshfs.conntab, path);
2793+
g_free(ce);
27772794
}
27782795
pthread_mutex_unlock(&sshfs.lock);
27792796
}
@@ -2844,6 +2861,7 @@ static int sshfs_release(const char *path, struct fuse_file_info *fi)
28442861
{
28452862
struct sshfs_file *sf = get_sshfs_file(fi);
28462863
struct buffer *handle = &sf->handle;
2864+
struct conntab_entry *ce;
28472865
if (sshfs_file_is_conn(sf)) {
28482866
sshfs_flush(path, fi);
28492867
sftp_request(sf->conn, SSH_FXP_CLOSE, handle, 0, NULL);
@@ -2853,8 +2871,12 @@ static int sshfs_release(const char *path, struct fuse_file_info *fi)
28532871
if (sshfs.max_conns > 1) {
28542872
pthread_mutex_lock(&sshfs.lock);
28552873
sf->conn->file_count--;
2856-
if(!sf->conn->file_count)
2874+
ce = g_hash_table_lookup(sshfs.conntab, path);
2875+
ce->refcount--;
2876+
if(ce->refcount == 0) {
28572877
g_hash_table_remove(sshfs.conntab, path);
2878+
g_free(ce);
2879+
}
28582880
pthread_mutex_unlock(&sshfs.lock);
28592881
}
28602882
g_free(sf);

0 commit comments

Comments
 (0)