fix
diff --git a/ChangeLog b/ChangeLog
index 7ebda65..1b5d20d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -16,6 +16,9 @@
* new exported functions: fuse_session_remove_chan(),
fuse_get_session(), fuse_daemonize()
+ * fuse_chan_recv() may now return a new channel which will be used
+ to send the reply
+
2006-03-16 Miklos Szeredi <miklos@szeredi.hu>
* Released 2.6.0-pre2
diff --git a/include/fuse_lowlevel.h b/include/fuse_lowlevel.h
index da12152..f06fca3 100644
--- a/include/fuse_lowlevel.h
+++ b/include/fuse_lowlevel.h
@@ -1102,12 +1102,12 @@
/**
* Hook for receiving a raw request
*
- * @param ch the channel
+ * @param ch pointer to the channel
* @param buf the buffer to store the request in
* @param size the size of the buffer
* @return the actual size of the raw request, or -1 on error
*/
- int (*receive)(struct fuse_chan *ch, char *buf, size_t size);
+ int (*receive)(struct fuse_chan **chp, char *buf, size_t size);
/**
* Hook for sending a raw reply
@@ -1120,8 +1120,7 @@
* @param count the number of blocks in vector
* @return zero on success, -errno on failure
*/
- int (*send)(struct fuse_chan *ch, const struct iovec iov[],
- size_t count);
+ int (*send)(struct fuse_chan *ch, const struct iovec iov[], size_t count);
/**
* Destroy the channel
@@ -1180,12 +1179,12 @@
*
* A return value of -ENODEV means, that the filesystem was unmounted
*
- * @param ch the channel
+ * @param ch pointer to the channel
* @param buf the buffer to store the request in
* @param size the size of the buffer
* @return the actual size of the raw request, or -errno on error
*/
-int fuse_chan_recv(struct fuse_chan *ch, char *buf, size_t size);
+int fuse_chan_recv(struct fuse_chan **ch, char *buf, size_t size);
/**
* Send a raw reply
@@ -1218,6 +1217,8 @@
# if FUSE_USE_VERSION == 25
# define fuse_lowlevel_ops fuse_lowlevel_ops_compat25
# define fuse_lowlevel_new fuse_lowlevel_new_compat25
+# define fuse_chan_ops fuse_chan_ops_compat25
+# define fuse_chan_new fuse_chan_new_compat25
# elif FUSE_USE_VERSION == 24
# define fuse_file_info fuse_file_info_compat
# define fuse_reply_statfs fuse_reply_statfs_compat
diff --git a/include/fuse_lowlevel_compat.h b/include/fuse_lowlevel_compat.h
index be4d4d8..c8e7673 100644
--- a/include/fuse_lowlevel_compat.h
+++ b/include/fuse_lowlevel_compat.h
@@ -88,6 +88,16 @@
const struct fuse_lowlevel_ops *op,
size_t op_size, void *userdata);
+#endif /* __FreeBSD__ */
+
+struct fuse_chan_ops_compat24 {
+ int (*receive)(struct fuse_chan *ch, char *buf, size_t size);
+ int (*send)(struct fuse_chan *ch, const struct iovec iov[], size_t count);
+ void (*destroy)(struct fuse_chan *ch);
+};
+
+struct fuse_chan *fuse_chan_new_compat24(struct fuse_chan_ops_compat24 *op,
+ int fd, size_t bufsize, void *data);
+
int fuse_chan_receive(struct fuse_chan *ch, char *buf, size_t size);
-#endif /* __FreeBSD__ */
diff --git a/lib/fuse.c b/lib/fuse.c
index 82e0e44..dc1ab10 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -1881,7 +1881,7 @@
size_t bufsize = fuse_chan_bufsize(ch);
struct fuse_cmd *cmd = fuse_alloc_cmd(bufsize);
if (cmd != NULL) {
- int res = fuse_chan_recv(ch, cmd->buf, bufsize);
+ int res = fuse_chan_recv(&ch, cmd->buf, bufsize);
if (res <= 0) {
free_cmd(cmd);
if (res < 0 && res != -EINTR && res != -EAGAIN)
diff --git a/lib/fuse_kern_chan.c b/lib/fuse_kern_chan.c
index fe7d252..45ff738 100644
--- a/lib/fuse_kern_chan.c
+++ b/lib/fuse_kern_chan.c
@@ -14,8 +14,10 @@
#include <unistd.h>
#include <assert.h>
-static int fuse_kern_chan_receive(struct fuse_chan *ch, char *buf, size_t size)
+static int fuse_kern_chan_receive(struct fuse_chan **chp, char *buf,
+ size_t size)
{
+ struct fuse_chan *ch = *chp;
int err;
ssize_t res;
struct fuse_session *se = fuse_chan_session(ch);
@@ -50,18 +52,20 @@
static int fuse_kern_chan_send(struct fuse_chan *ch, const struct iovec iov[],
size_t count)
{
- ssize_t res = writev(fuse_chan_fd(ch), iov, count);
- int err = errno;
+ if (iov) {
+ ssize_t res = writev(fuse_chan_fd(ch), iov, count);
+ int err = errno;
- if (res == -1) {
- struct fuse_session *se = fuse_chan_session(ch);
+ if (res == -1) {
+ struct fuse_session *se = fuse_chan_session(ch);
- assert(se != NULL);
+ assert(se != NULL);
- /* ENOENT means the operation was interrupted */
- if (!fuse_session_exited(se) && err != ENOENT)
- perror("fuse: writing device");
- return -err;
+ /* ENOENT means the operation was interrupted */
+ if (!fuse_session_exited(se) && err != ENOENT)
+ perror("fuse: writing device");
+ return -err;
+ }
}
return 0;
}
diff --git a/lib/fuse_loop.c b/lib/fuse_loop.c
index 6a6edaa..af85269 100644
--- a/lib/fuse_loop.c
+++ b/lib/fuse_loop.c
@@ -24,12 +24,13 @@
}
while (!fuse_session_exited(se)) {
- res = fuse_chan_recv(ch, buf, bufsize);
+ struct fuse_chan *tmpch = ch;
+ res = fuse_chan_recv(&tmpch, buf, bufsize);
if (res == -EINTR)
continue;
if (res <= 0)
break;
- fuse_session_process(se, buf, res, ch);
+ fuse_session_process(se, buf, res, tmpch);
}
free(buf);
diff --git a/lib/fuse_loop_mt.c b/lib/fuse_loop_mt.c
index 16be149..fc8f892 100644
--- a/lib/fuse_loop_mt.c
+++ b/lib/fuse_loop_mt.c
@@ -24,7 +24,6 @@
int numworker;
int numavail;
struct fuse_session *se;
- struct fuse_chan *ch;
struct fuse_chan *prevch;
pthread_t threads[FUSE_MAX_WORKERS];
pthread_t main_thread;
@@ -32,6 +31,11 @@
int error;
};
+struct fuse_wchan {
+ struct fuse_worker *w;
+ struct fuse_chan *prevch;
+};
+
#ifndef USE_UCLIBC
#define mutex_init(mut) pthread_mutex_init(mut, NULL)
#else
@@ -48,11 +52,15 @@
static int fuse_loop_mt_send(struct fuse_chan *ch, const struct iovec iov[],
size_t count)
{
- struct fuse_worker *w = (struct fuse_worker *) fuse_chan_data(ch);
- pthread_mutex_lock(&w->lock);
- w->numavail ++;
- pthread_mutex_unlock(&w->lock);
- return fuse_chan_send(w->prevch, iov, count);
+ int res;
+ struct fuse_wchan *wchan_data = (struct fuse_wchan *) fuse_chan_data(ch);
+ pthread_mutex_lock(&wchan_data->w->lock);
+ wchan_data->w->numavail ++;
+ pthread_mutex_unlock(&wchan_data->w->lock);
+ res = fuse_chan_send(wchan_data->prevch, iov, count);
+ fuse_chan_destroy(ch);
+ free(wchan_data);
+ return res;
}
static int start_thread(struct fuse_worker *w, pthread_t *thread_id);
@@ -74,7 +82,11 @@
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
while (!fuse_session_exited(w->se)) {
- int res = fuse_chan_recv(w->prevch, buf, bufsize);
+ struct fuse_chan *ch = w->prevch;
+ struct fuse_chan *wchan;
+ struct fuse_wchan *wchan_data;
+ struct fuse_chan_ops cop = { .send = fuse_loop_mt_send };
+ int res = fuse_chan_recv(&ch, buf, bufsize);
if (res == -EINTR)
continue;
if (res <= 0) {
@@ -105,7 +117,17 @@
}
}
pthread_mutex_unlock(&w->lock);
- fuse_session_process(w->se, buf, res, w->ch);
+ wchan_data = malloc(sizeof(struct fuse_wchan));
+ wchan = fuse_chan_new(&cop, -1, fuse_chan_bufsize(ch), wchan_data);
+ if (!wchan_data || !wchan) {
+ free(wchan_data);
+ fuse_session_exit(w->se);
+ w->error = -1;
+ break;
+ }
+ wchan_data->w = w;
+ wchan_data->prevch = ch;
+ fuse_session_process(w->se, buf, res, wchan);
}
pthread_cleanup_pop(1);
@@ -145,10 +167,6 @@
int i;
int err;
struct fuse_worker *w;
- struct fuse_chan_ops cop = {
- .send = fuse_loop_mt_send,
- };
-
w = (struct fuse_worker *) malloc(sizeof(struct fuse_worker));
if (w == NULL) {
fprintf(stderr, "fuse: failed to allocate worker structure\n");
@@ -157,11 +175,6 @@
memset(w, 0, sizeof(struct fuse_worker));
w->se = se;
w->prevch = fuse_session_next_chan(se, NULL);
- w->ch = fuse_chan_new(&cop, -1, fuse_chan_bufsize(w->prevch), w);
- if (w->ch == NULL) {
- free(w);
- return -1;
- }
w->error = 0;
w->numworker = 1;
w->numavail = 1;
@@ -179,7 +192,6 @@
pthread_join(w->threads[i], NULL);
pthread_mutex_destroy(&w->lock);
err = w->error;
- fuse_chan_destroy(w->ch);
free(w);
fuse_session_reset(se);
return err;
diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c
index c6b7db8..7b5cb7b 100644
--- a/lib/fuse_lowlevel.c
+++ b/lib/fuse_lowlevel.c
@@ -223,6 +223,7 @@
void fuse_reply_none(fuse_req_t req)
{
+ fuse_chan_send(req->ch, NULL, 0);
free_req(req);
}
diff --git a/lib/fuse_mt.c b/lib/fuse_mt.c
index 8a8964f..b0b31dd 100644
--- a/lib/fuse_mt.c
+++ b/lib/fuse_mt.c
@@ -104,10 +104,10 @@
return fuse_session_exited(pd->prevse);
}
-static int mt_chan_receive(struct fuse_chan *ch, char *buf, size_t size)
+static int mt_chan_receive(struct fuse_chan **chp, char *buf, size_t size)
{
struct fuse_cmd *cmd;
- struct procdata *pd = (struct procdata *) fuse_chan_data(ch);
+ struct procdata *pd = (struct procdata *) fuse_chan_data(*chp);
assert(size >= sizeof(cmd));
diff --git a/lib/fuse_session.c b/lib/fuse_session.c
index 040645b..6cfd462 100644
--- a/lib/fuse_session.c
+++ b/lib/fuse_session.c
@@ -7,6 +7,7 @@
*/
#include "fuse_lowlevel.h"
+#include "fuse_lowlevel_compat.h"
#include <stdio.h>
#include <stdlib.h>
@@ -34,6 +35,8 @@
size_t bufsize;
void *data;
+
+ int compat;
};
struct fuse_session *fuse_session_new(struct fuse_session_ops *op, void *data)
@@ -116,8 +119,8 @@
return se->exited;
}
-struct fuse_chan *fuse_chan_new(struct fuse_chan_ops *op, int fd,
- size_t bufsize, void *data)
+struct fuse_chan *fuse_chan_new_common(struct fuse_chan_ops *op, int fd,
+ size_t bufsize, void *data, int compat)
{
struct fuse_chan *ch = (struct fuse_chan *) malloc(sizeof(*ch));
if (ch == NULL) {
@@ -130,10 +133,24 @@
ch->fd = fd;
ch->bufsize = bufsize;
ch->data = data;
+ ch->compat = compat;
return ch;
}
+struct fuse_chan *fuse_chan_new(struct fuse_chan_ops *op, int fd,
+ size_t bufsize, void *data)
+{
+ return fuse_chan_new_common(op, fd, bufsize, data, 0);
+}
+
+struct fuse_chan *fuse_chan_new_compat24(struct fuse_chan_ops_compat24 *op,
+ int fd, size_t bufsize, void *data)
+{
+ return fuse_chan_new_common((struct fuse_chan_ops *) op, fd, bufsize,
+ data, 24);
+}
+
int fuse_chan_fd(struct fuse_chan *ch)
{
return ch->fd;
@@ -154,14 +171,22 @@
return ch->se;
}
-int fuse_chan_recv(struct fuse_chan *ch, char *buf, size_t size)
+int fuse_chan_recv(struct fuse_chan **chp, char *buf, size_t size)
{
- return ch->op.receive(ch, buf, size);
+ struct fuse_chan *ch = *chp;
+ if (ch->compat)
+ return ((struct fuse_chan_ops_compat24 *) &ch->op)
+ ->receive(ch, buf, size);
+ else
+ return ch->op.receive(chp, buf, size);
}
int fuse_chan_receive(struct fuse_chan *ch, char *buf, size_t size)
{
- int res = fuse_chan_recv(ch, buf, size);
+ int res;
+
+ assert(ch->compat);
+ res = fuse_chan_recv(&ch, buf, size);
return res >= 0 ? res : (res != -EINTR && res != -EAGAIN) ? -1 : 0;
}
@@ -177,3 +202,7 @@
ch->op.destroy(ch);
free(ch);
}
+
+#ifndef __FreeBSD__
+__asm__(".symver fuse_chan_new_compat24,fuse_chan_new@FUSE_2.4");
+#endif
diff --git a/lib/fuse_versionscript b/lib/fuse_versionscript
index 467d870..147067f 100644
--- a/lib/fuse_versionscript
+++ b/lib/fuse_versionscript
@@ -83,6 +83,8 @@
FUSE_2.6 {
global:
fuse_add_direntry;
+ fuse_chan_new;
+ fuse_chan_new_compat24;
fuse_daemonize;
fuse_get_session;
fuse_lowlevel_new;