static enum xp_retval xpc_send_payload_uv(struct xpc_channel *ch, u32 flags, void *payload, u16 payload_size, u8 notify_type, xpc_notify_func func, void *key) { enum xp_retval ret = xpSuccess; struct xpc_send_msg_slot_uv *msg_slot = NULL; struct xpc_notify_mq_msg_uv *msg; u8 msg_buffer[XPC_NOTIFY_MSG_SIZE_UV]; size_t msg_size; DBUG_ON(notify_type != XPC_N_CALL); msg_size = sizeof(struct xpc_notify_mq_msghdr_uv) + payload_size; if (msg_size > ch->entry_size) return xpPayloadTooBig; xpc_msgqueue_ref(ch); if (ch->flags & XPC_C_DISCONNECTING) { ret = ch->reason; goto out_1; } if (!(ch->flags & XPC_C_CONNECTED)) { ret = xpNotConnected; goto out_1; } ret = xpc_allocate_msg_slot_uv(ch, flags, &msg_slot); if (ret != xpSuccess) goto out_1; if (func != NULL) { atomic_inc(&ch->n_to_notify); msg_slot->key = key; smp_wmb(); /* a non-NULL func must hit memory after the key */ msg_slot->func = func; if (ch->flags & XPC_C_DISCONNECTING) { ret = ch->reason; goto out_2; } } msg = (struct xpc_notify_mq_msg_uv *)&msg_buffer; msg->hdr.partid = xp_partition_id; msg->hdr.ch_number = ch->number; msg->hdr.size = msg_size; msg->hdr.msg_slot_number = msg_slot->msg_slot_number; memcpy(&msg->payload, payload, payload_size); ret = xpc_send_gru_msg(ch->sn.uv.cached_notify_gru_mq_desc, msg, msg_size); if (ret == xpSuccess) goto out_1; XPC_DEACTIVATE_PARTITION(&xpc_partitions[ch->partid], ret); out_2: if (func != NULL) { /* * Try to NULL the msg_slot's func field. If we fail, then * xpc_notify_senders_of_disconnect_uv() beat us to it, in which * case we need to pretend we succeeded to send the message * since the user will get a callout for the disconnect error * by xpc_notify_senders_of_disconnect_uv(), and to also get an * error returned here will confuse them. Additionally, since * in this case the channel is being disconnected we don't need * to put the the msg_slot back on the free list. */ if (cmpxchg(&msg_slot->func, func, NULL) != func) { ret = xpSuccess; goto out_1; } msg_slot->key = NULL; atomic_dec(&ch->n_to_notify); } xpc_free_msg_slot_uv(ch, msg_slot); out_1: xpc_msgqueue_deref(ch); return ret; }
static enum xp_retval xpc_send_payload_uv(struct xpc_channel *ch, u32 flags, void *payload, u16 payload_size, u8 notify_type, xpc_notify_func func, void *key) { enum xp_retval ret = xpSuccess; struct xpc_send_msg_slot_uv *msg_slot = NULL; struct xpc_notify_mq_msg_uv *msg; u8 msg_buffer[XPC_NOTIFY_MSG_SIZE_UV]; size_t msg_size; DBUG_ON(notify_type != XPC_N_CALL); msg_size = sizeof(struct xpc_notify_mq_msghdr_uv) + payload_size; if (msg_size > ch->entry_size) return xpPayloadTooBig; xpc_msgqueue_ref(ch); if (ch->flags & XPC_C_DISCONNECTING) { ret = ch->reason; goto out_1; } if (!(ch->flags & XPC_C_CONNECTED)) { ret = xpNotConnected; goto out_1; } ret = xpc_allocate_msg_slot_uv(ch, flags, &msg_slot); if (ret != xpSuccess) goto out_1; if (func != NULL) { atomic_inc(&ch->n_to_notify); msg_slot->key = key; smp_wmb(); msg_slot->func = func; if (ch->flags & XPC_C_DISCONNECTING) { ret = ch->reason; goto out_2; } } msg = (struct xpc_notify_mq_msg_uv *)&msg_buffer; msg->hdr.partid = xp_partition_id; msg->hdr.ch_number = ch->number; msg->hdr.size = msg_size; msg->hdr.msg_slot_number = msg_slot->msg_slot_number; memcpy(&msg->payload, payload, payload_size); ret = xpc_send_gru_msg(ch->sn.uv.cached_notify_gru_mq_desc, msg, msg_size); if (ret == xpSuccess) goto out_1; XPC_DEACTIVATE_PARTITION(&xpc_partitions[ch->partid], ret); out_2: if (func != NULL) { if (cmpxchg(&msg_slot->func, func, NULL) != func) { ret = xpSuccess; goto out_1; } msg_slot->key = NULL; atomic_dec(&ch->n_to_notify); } xpc_free_msg_slot_uv(ch, msg_slot); out_1: xpc_msgqueue_deref(ch); return ret; }