afs: Pass sideband error packet on callback failures.
[paraslash.git] / afs.c
diff --git a/afs.c b/afs.c
index 24e737b67e3995c8723cd1d7ae7f72899554c322..4bc7871cac868a45a2d487cdf5761d9509f19bfa 100644 (file)
--- a/afs.c
+++ b/afs.c
@@ -166,13 +166,8 @@ static int dispatch_result(int result_shmid, callback_result_handler *handler,
        }
        result.size = cr->result_size;
        result.data = result_shm + sizeof(*cr);
-       if (result.size) {
-               assert(handler);
-               ret = handler(&result, cr->band, private_result_data);
-               if (ret < 0)
-                       PARA_NOTICE_LOG("result handler error: %s\n",
-                               para_strerror(-ret));
-       }
+       assert(handler);
+       ret = handler(&result, cr->band, private_result_data);
        ret2 = shm_detach(result_shm);
        if (ret2 < 0) {
                PARA_ERROR_LOG("detach failed: %s\n", para_strerror(-ret2));
@@ -261,12 +256,10 @@ int send_callback_request(callback_function *f, struct osl_object *query,
                ret = *(int *) buf;
                assert(ret > 0);
                result_shmid = ret;
-               if (!dispatch_error) {
-                       ret = dispatch_result(result_shmid, result_handler,
-                               private_result_data);
-                       if (ret < 0)
-                               dispatch_error = 1;
-               }
+               ret = dispatch_result(result_shmid, result_handler,
+                       private_result_data);
+               if (ret < 0 && dispatch_error >= 0)
+                       dispatch_error = ret;
                ret = shm_destroy(result_shmid);
                if (ret < 0)
                        PARA_CRIT_LOG("destroy result failed: %s\n",
@@ -278,8 +271,11 @@ out:
                PARA_CRIT_LOG("shm destroy error\n");
        if (fd >= 0)
                close(fd);
-//     PARA_DEBUG_LOG("callback_ret: %d\n", ret);
-       return ret < 0? ret : num_dispatched;
+       if (dispatch_error < 0)
+               return dispatch_error;
+       if (ret < 0)
+               return ret;
+       return num_dispatched;
 }
 
 /**
@@ -559,9 +555,22 @@ int afs_cb_result_handler(struct osl_object *result, uint8_t band,
        struct command_context *cc = private;
 
        assert(cc);
-       if (!result->size)
-               return 1;
-       return send_sb(&cc->scc, result->data, result->size, band, true);
+       switch (band) {
+       case SBD_OUTPUT:
+       case SBD_DEBUG_LOG:
+       case SBD_INFO_LOG:
+       case SBD_NOTICE_LOG:
+       case SBD_WARNING_LOG:
+       case SBD_ERROR_LOG:
+       case SBD_CRIT_LOG:
+       case SBD_EMERG_LOG:
+               assert(result->size > 0);
+               return send_sb(&cc->scc, result->data, result->size, band, true);
+       case SBD_AFS_CB_FAILURE:
+               return *(int *)(result->data);
+       default:
+               return -E_BAD_BAND;
+       }
 }
 
 void flush_and_free_pb(struct para_buffer *pb)
@@ -808,8 +817,8 @@ int pass_buffer_as_shm(int fd, uint8_t band, const char *buf, size_t size)
        void *shm;
        struct callback_result *cr;
 
-       if (!buf || !size)
-               return 0;
+       if (size == 0)
+               assert(band != SBD_OUTPUT);
        ret = shm_new(size + sizeof(*cr));
        if (ret < 0)
                return ret;
@@ -820,7 +829,8 @@ int pass_buffer_as_shm(int fd, uint8_t band, const char *buf, size_t size)
        cr = shm;
        cr->result_size = size;
        cr->band = band;
-       memcpy(shm + sizeof(*cr), buf, size);
+       if (size > 0)
+               memcpy(shm + sizeof(*cr), buf, size);
        ret = shm_detach(shm);
        if (ret < 0)
                goto err;
@@ -838,7 +848,7 @@ static int call_callback(int fd, int query_shmid)
        void *query_shm;
        struct callback_query *cq;
        struct osl_object query;
-       int ret;
+       int ret, ret2;
 
        ret = shm_attach(query_shmid, ATTACH_RW, &query_shm);
        if (ret < 0)
@@ -846,8 +856,23 @@ static int call_callback(int fd, int query_shmid)
        cq = query_shm;
        query.data = (char *)query_shm + sizeof(*cq);
        query.size = cq->query_size;
-       cq->handler(fd, &query);
-       return shm_detach(query_shm);
+       ret = cq->handler(fd, &query);
+       ret2 = shm_detach(query_shm);
+       if (ret2 < 0) {
+               if (ret < 0) /* ignore (but log) detach error */
+                       PARA_ERROR_LOG("could not detach sma: %s\n",
+                               para_strerror(-ret2));
+               else
+                       ret = ret2;
+       }
+       if (ret < 0) {
+               ret2 = pass_buffer_as_shm(fd, SBD_AFS_CB_FAILURE,
+                       (const char *)&ret, sizeof(ret));
+               if (ret2 < 0)
+                       PARA_ERROR_LOG("could not pass cb failure packet: %s\n",
+                               para_strerror(-ret));
+       }
+       return ret;
 }
 
 static int execute_server_command(fd_set *rfds)