diff options
| author | Karol Lewandowski <k.lewandowsk@samsung.com> | 2016-10-06 14:20:24 +0200 |
|---|---|---|
| committer | Seung-Woo Kim <sw0312.kim@samsung.com> | 2016-12-14 13:53:39 +0900 |
| commit | d8934e9b05b82e73a3c78421f372197801c1785e (patch) | |
| tree | 24981389ae0ca646a7997f6e32ea7a39aea147b7 /ipc/kdbus/queue.c | |
| parent | ea4654706ad61bc7afc47e6321c5cbee8c175688 (diff) | |
kdbus: Upgrade driver to newer upstream version
This commit upgrades kdbus ipc driver from v4 patchset, as posted on lkml
for review by Greg Kroah-Hartman on Mar 09 2015 to commit 0c05fbdc82f from
new upstream kdbus repository (git://github.com/systemd/kdbus).
Summary of major changes:
* message importer rewritten - considerably reduces internal message
processing overhead,
* name registration reworked to follow DBus Specification precisely,
* attached metadata now follow /proc access checks
* reduced in-kernel stack buffer to 256 bytes for small messages
Change-Id: I6d849173b4289e1b684ed1a9b48e6e0b361e5d53
Diffstat (limited to 'ipc/kdbus/queue.c')
| -rw-r--r-- | ipc/kdbus/queue.c | 361 |
1 files changed, 23 insertions, 338 deletions
diff --git a/ipc/kdbus/queue.c b/ipc/kdbus/queue.c index a449464a3975..f9c44d7bae6d 100644 --- a/ipc/kdbus/queue.c +++ b/ipc/kdbus/queue.c @@ -171,242 +171,43 @@ static void kdbus_queue_entry_unlink(struct kdbus_queue_entry *entry) /** * kdbus_queue_entry_new() - allocate a queue entry - * @conn_dst: destination connection - * @kmsg: kmsg object the queue entry should track - * @user: user to account message on (or NULL for kernel messages) + * @src: source connection, or NULL + * @dst: destination connection + * @s: staging object carrying the message * - * Allocates a queue entry based on a given kmsg and allocate space for + * Allocates a queue entry based on a given msg and allocate space for * the message payload and the requested metadata in the connection's pool. * The entry is not actually added to the queue's lists at this point. * * Return: the allocated entry on success, or an ERR_PTR on failures. */ -struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *conn_dst, - const struct kdbus_kmsg *kmsg, - struct kdbus_user *user) +struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *src, + struct kdbus_conn *dst, + struct kdbus_staging *s) { - struct kdbus_msg_resources *res = kmsg->res; - const struct kdbus_msg *msg = &kmsg->msg; struct kdbus_queue_entry *entry; - size_t memfd_cnt = 0; - struct kvec kvec[2]; - size_t meta_size; - size_t msg_size; - u64 payload_off; - u64 size = 0; - int ret = 0; + int ret; entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return ERR_PTR(-ENOMEM); INIT_LIST_HEAD(&entry->entry); - entry->priority = msg->priority; - entry->dst_name_id = kmsg->dst_name_id; - entry->msg_res = kdbus_msg_resources_ref(res); - entry->proc_meta = kdbus_meta_proc_ref(kmsg->proc_meta); - entry->conn_meta = kdbus_meta_conn_ref(kmsg->conn_meta); - entry->conn = kdbus_conn_ref(conn_dst); - - if (kmsg->msg.src_id == KDBUS_SRC_ID_KERNEL) - msg_size = msg->size; - else - msg_size = offsetof(struct kdbus_msg, items); - - /* sum up the size of the needed slice */ - size = msg_size; - - if (res) { - size += res->vec_count * - KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec)); - - if (res->memfd_count) { - entry->memfd_offset = - kcalloc(res->memfd_count, sizeof(size_t), - GFP_KERNEL); - if (!entry->memfd_offset) { - ret = -ENOMEM; - goto exit_free_entry; - } - - size += res->memfd_count * - KDBUS_ITEM_SIZE(sizeof(struct kdbus_memfd)); - } - - if (res->fds_count) - size += KDBUS_ITEM_SIZE(sizeof(int) * res->fds_count); - - if (res->dst_name) - size += KDBUS_ITEM_SIZE(strlen(res->dst_name) + 1); - } - - /* - * Remember the offset of the metadata part, so we can override - * this part later during kdbus_queue_entry_install(). - */ - entry->meta_offset = size; - - if (entry->proc_meta || entry->conn_meta) { - entry->attach_flags = - atomic64_read(&conn_dst->attach_flags_recv); - - ret = kdbus_meta_export_prepare(entry->proc_meta, - entry->conn_meta, - &entry->attach_flags, - &meta_size); - if (ret < 0) - goto exit_free_entry; + entry->priority = s->msg->priority; + entry->conn = kdbus_conn_ref(dst); + entry->gaps = kdbus_gaps_ref(s->gaps); - size += meta_size; - } - - payload_off = size; - size += kmsg->pool_size; - size = KDBUS_ALIGN8(size); - - ret = kdbus_conn_quota_inc(conn_dst, user, size, - res ? res->fds_count : 0); - if (ret < 0) - goto exit_free_entry; - - entry->slice = kdbus_pool_slice_alloc(conn_dst->pool, size, true); + entry->slice = kdbus_staging_emit(s, src, dst); if (IS_ERR(entry->slice)) { ret = PTR_ERR(entry->slice); entry->slice = NULL; - kdbus_conn_quota_dec(conn_dst, user, size, - res ? res->fds_count : 0); - goto exit_free_entry; - } - - /* we accounted for exactly 'size' bytes, make sure it didn't grow */ - WARN_ON(kdbus_pool_slice_size(entry->slice) != size); - entry->user = kdbus_user_ref(user); - - /* copy message header */ - kvec[0].iov_base = (char *)msg; - kvec[0].iov_len = msg_size; - - ret = kdbus_pool_slice_copy_kvec(entry->slice, 0, kvec, 1, msg_size); - if (ret < 0) - goto exit_free_entry; - - /* 'size' will now track the write position */ - size = msg_size; - - /* create message payload items */ - if (res) { - size_t dst_name_len = 0; - unsigned int i; - size_t sz = 0; - - if (res->dst_name) { - dst_name_len = strlen(res->dst_name) + 1; - sz += KDBUS_ITEM_SIZE(dst_name_len); - } - - for (i = 0; i < res->data_count; ++i) { - struct kdbus_vec v; - struct kdbus_memfd m; - - switch (res->data[i].type) { - case KDBUS_MSG_DATA_VEC: - sz += KDBUS_ITEM_SIZE(sizeof(v)); - break; - - case KDBUS_MSG_DATA_MEMFD: - sz += KDBUS_ITEM_SIZE(sizeof(m)); - break; - } - } - - if (sz) { - struct kdbus_item *items, *item; - - items = kmalloc(sz, GFP_KERNEL); - if (!items) { - ret = -ENOMEM; - goto exit_free_entry; - } - - item = items; - - if (res->dst_name) - item = kdbus_item_set(item, KDBUS_ITEM_DST_NAME, - res->dst_name, - dst_name_len); - - for (i = 0; i < res->data_count; ++i) { - struct kdbus_msg_data *d = res->data + i; - struct kdbus_memfd m = {}; - struct kdbus_vec v = {}; - - switch (d->type) { - case KDBUS_MSG_DATA_VEC: - v.size = d->size; - v.offset = d->vec.off; - if (v.offset != ~0ULL) - v.offset += payload_off; - - item = kdbus_item_set(item, - KDBUS_ITEM_PAYLOAD_OFF, - &v, sizeof(v)); - break; - - case KDBUS_MSG_DATA_MEMFD: - /* - * Remember the location of memfds, so - * we can override the content from - * kdbus_queue_entry_install(). - */ - entry->memfd_offset[memfd_cnt++] = - msg_size + - (char *)item - (char *)items + - offsetof(struct kdbus_item, - memfd); - - item = kdbus_item_set(item, - KDBUS_ITEM_PAYLOAD_MEMFD, - &m, sizeof(m)); - break; - } - } - - kvec[0].iov_base = items; - kvec[0].iov_len = sz; - - ret = kdbus_pool_slice_copy_kvec(entry->slice, size, - kvec, 1, sz); - kfree(items); - - if (ret < 0) - goto exit_free_entry; - - size += sz; - } - - /* - * Remember the location of the FD part, so we can override the - * content in kdbus_queue_entry_install(). - */ - if (res->fds_count) { - entry->fds_offset = size; - size += KDBUS_ITEM_SIZE(sizeof(int) * res->fds_count); - } - } - - /* finally, copy over the actual message payload */ - if (kmsg->iov_count) { - ret = kdbus_pool_slice_copy_iovec(entry->slice, payload_off, - kmsg->iov, - kmsg->iov_count, - kmsg->pool_size); - if (ret < 0) - goto exit_free_entry; + goto error; } + entry->user = src ? kdbus_user_ref(src->user) : NULL; return entry; -exit_free_entry: +error: kdbus_queue_entry_free(entry); return ERR_PTR(ret); } @@ -431,17 +232,13 @@ void kdbus_queue_entry_free(struct kdbus_queue_entry *entry) if (entry->slice) { kdbus_conn_quota_dec(entry->conn, entry->user, kdbus_pool_slice_size(entry->slice), - entry->msg_res ? - entry->msg_res->fds_count : 0); + entry->gaps ? entry->gaps->n_fds : 0); kdbus_pool_slice_release(entry->slice); - kdbus_user_unref(entry->user); } - kdbus_msg_resources_unref(entry->msg_res); - kdbus_meta_conn_unref(entry->conn_meta); - kdbus_meta_proc_unref(entry->proc_meta); + kdbus_user_unref(entry->user); + kdbus_gaps_unref(entry->gaps); kdbus_conn_unref(entry->conn); - kfree(entry->memfd_offset); kfree(entry); } @@ -452,134 +249,22 @@ void kdbus_queue_entry_free(struct kdbus_queue_entry *entry) * @return_flags: Pointer to store the return flags for userspace * @install_fds: Whether or not to install associated file descriptors * - * This function will create a slice to transport the message header, the - * metadata items and other items for information stored in @entry, and - * store it as entry->slice. - * - * If @install_fds is %true, file descriptors will as well be installed. - * This function must always be called from the task context of the receiver. - * * Return: 0 on success. */ int kdbus_queue_entry_install(struct kdbus_queue_entry *entry, u64 *return_flags, bool install_fds) { - u64 msg_size = entry->meta_offset; - struct kdbus_conn *conn_dst = entry->conn; - struct kdbus_msg_resources *res; bool incomplete_fds = false; - struct kvec kvec[2]; - size_t memfds = 0; - int i, ret; - - lockdep_assert_held(&conn_dst->lock); - - if (entry->proc_meta || entry->conn_meta) { - size_t meta_size; - - ret = kdbus_meta_export(entry->proc_meta, - entry->conn_meta, - entry->attach_flags, - entry->slice, - entry->meta_offset, - &meta_size); - if (ret < 0) - return ret; - - msg_size += meta_size; - } + int ret; - /* Update message size at offset 0 */ - kvec[0].iov_base = &msg_size; - kvec[0].iov_len = sizeof(msg_size); + lockdep_assert_held(&entry->conn->lock); - ret = kdbus_pool_slice_copy_kvec(entry->slice, 0, kvec, 1, - sizeof(msg_size)); + ret = kdbus_gaps_install(entry->gaps, entry->slice, &incomplete_fds); if (ret < 0) return ret; - res = entry->msg_res; - - if (!res) - return 0; - - if (res->fds_count) { - struct kdbus_item_header hdr; - size_t off; - int *fds; - - fds = kmalloc_array(res->fds_count, sizeof(int), GFP_KERNEL); - if (!fds) - return -ENOMEM; - - for (i = 0; i < res->fds_count; i++) { - if (install_fds) { - fds[i] = get_unused_fd_flags(O_CLOEXEC); - if (fds[i] >= 0) - fd_install(fds[i], - get_file(res->fds[i])); - else - incomplete_fds = true; - } else { - fds[i] = -1; - } - } - - off = entry->fds_offset; - - hdr.type = KDBUS_ITEM_FDS; - hdr.size = KDBUS_ITEM_HEADER_SIZE + - sizeof(int) * res->fds_count; - - kvec[0].iov_base = &hdr; - kvec[0].iov_len = sizeof(hdr); - - kvec[1].iov_base = fds; - kvec[1].iov_len = sizeof(int) * res->fds_count; - - ret = kdbus_pool_slice_copy_kvec(entry->slice, off, - kvec, 2, hdr.size); - kfree(fds); - - if (ret < 0) - return ret; - } - - for (i = 0; i < res->data_count; ++i) { - struct kdbus_msg_data *d = res->data + i; - struct kdbus_memfd m; - - if (d->type != KDBUS_MSG_DATA_MEMFD) - continue; - - m.start = d->memfd.start; - m.size = d->size; - m.fd = -1; - - if (install_fds) { - m.fd = get_unused_fd_flags(O_CLOEXEC); - if (m.fd < 0) { - m.fd = -1; - incomplete_fds = true; - } else { - fd_install(m.fd, - get_file(d->memfd.file)); - } - } - - kvec[0].iov_base = &m; - kvec[0].iov_len = sizeof(m); - - ret = kdbus_pool_slice_copy_kvec(entry->slice, - entry->memfd_offset[memfds++], - kvec, 1, sizeof(m)); - if (ret < 0) - return ret; - } - if (incomplete_fds) *return_flags |= KDBUS_RECV_RETURN_INCOMPLETE_FDS; - return 0; } @@ -637,13 +322,13 @@ int kdbus_queue_entry_move(struct kdbus_queue_entry *e, lockdep_assert_held(&src->lock); lockdep_assert_held(&dst->lock); - if (WARN_ON(IS_ERR(e->user)) || WARN_ON(list_empty(&e->entry))) + if (WARN_ON(list_empty(&e->entry))) return -EINVAL; if (src == dst) return 0; size = kdbus_pool_slice_size(e->slice); - fds = e->msg_res ? e->msg_res->fds_count : 0; + fds = e->gaps ? e->gaps->n_fds : 0; ret = kdbus_conn_quota_inc(dst, e->user, size, fds); if (ret < 0) |
