thread management fix
diff --git a/lib/fuse.c b/lib/fuse.c
index ab10df5..03f814c 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -19,6 +19,20 @@
 
 #define FUSE_KERNEL_VERSION_ENV "_FUSE_KERNEL_VERSION"
 
+static inline void inc_avail(struct fuse *f)
+{
+    pthread_mutex_lock(&f->lock);
+    f->numavail ++;
+    pthread_mutex_unlock(&f->lock);
+}
+
+static inline void dec_avail(struct fuse *f)
+{
+    pthread_mutex_lock(&f->lock);
+    f->numavail --;
+    pthread_mutex_unlock(&f->lock);
+}
+
 static struct node *__get_node(struct fuse *f, fino_t ino)
 {
     size_t hash = ino % f->ino_table_size;
@@ -321,11 +335,12 @@
                out->error, strerror(-out->error), outsize);
         fflush(stdout);
     }
-          
-    pthread_mutex_lock(&f->lock);
-    f->numavail ++;
-    pthread_mutex_unlock(&f->lock);
-      
+
+    /* This needs to be done before the reply because otherwise the
+    scheduler can tricks with us, and only let the counter be increased
+    long after the operation is done */
+    inc_avail(f);
+
     res = write(f->fd, outbuf, outsize);
     if(res == -1) {
         /* ENOENT means the operation was interrupted */
@@ -768,9 +783,7 @@
     void *inarg = cmd->buf + sizeof(struct fuse_in_header);
     size_t argsize;
 
-    pthread_mutex_lock(&f->lock);
-    f->numavail --;
-    pthread_mutex_unlock(&f->lock);
+    dec_avail(f);
 
     if((f->flags & FUSE_DEBUG)) {
         printf("unique: %i, opcode: %i, ino: %li, insize: %i\n", in->unique,
@@ -785,10 +798,6 @@
         do_lookup(f, in, (char *) inarg);
         break;
 
-    case FUSE_FORGET:
-        do_forget(f, in, (struct fuse_forget_in *) inarg);
-        break;
-
     case FUSE_GETATTR:
         do_getattr(f, in);
         break;
@@ -855,27 +864,39 @@
 {
     ssize_t res;
     struct fuse_cmd *cmd;
+    struct fuse_in_header *in;
+    void *inarg;
 
     cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
     cmd->buf = (char *) malloc(FUSE_MAX_IN);
+    in = (struct fuse_in_header *) cmd->buf;
+    inarg = cmd->buf + sizeof(struct fuse_in_header);
 
-    res = read(f->fd, cmd->buf, FUSE_MAX_IN);
-    if(res == -1) {
-        /* ENODEV means we got unmounted, so we silenty return failure */
-        if(errno != ENODEV) {
-            perror("fuse: reading device");
-            /* BAD... This will happen again */
+    do {
+        res = read(f->fd, cmd->buf, FUSE_MAX_IN);
+        if(res == -1) {
+            /* ENODEV means we got unmounted, so we silenty return failure */
+            if(errno != ENODEV) {
+                perror("fuse: reading device");
+                /* BAD... This will happen again */
+            }
+            free_cmd(cmd);
+            return NULL;
         }
-        free_cmd(cmd);
-        return NULL;
-    }
-    if((size_t) res < sizeof(struct fuse_in_header)) {
-        fprintf(stderr, "short read on fuse device\n");
-        /* Cannot happen */
-        free_cmd(cmd);
-        return NULL;
-    }
-    cmd->buflen = res;
+        if((size_t) res < sizeof(struct fuse_in_header)) {
+            fprintf(stderr, "short read on fuse device\n");
+            /* Cannot happen */
+            free_cmd(cmd);
+            return NULL;
+        }
+        cmd->buflen = res;
+        
+        /* Forget is special, it can be done without messing with threads. */
+        if(in->opcode == FUSE_FORGET)
+            do_forget(f, in, (struct fuse_forget_in *) inarg);
+
+    } while(in->opcode == FUSE_FORGET);
+
     return cmd;
 }