[RFC 6/6] android: binder: Add a buffer flag to relinquish ownership of fds
From: Hridya Valsaraju
Date: Fri Jan 14 2022 - 20:09:11 EST
This patch introduces a buffer flag BINDER_BUFFER_FLAG_SENDER_NO_NEED
that a process sending an fd array to another process over binder IPC
can set to relinquish ownership of the fds being sent for memory
accounting purposes. If the flag is found to be set during the fd array
translation and the fd is for a DMA-BUF, the buffer is uncharged from
the sender's cgroup and charged to the receiving process's cgroup
instead.
It is upto the sending process to ensure that it closes the fds
regardless of whether the transfer failed or succeeded.
Most graphics shared memory allocations in Android are done by the
graphics allocator HAL process. On requests from clients, the HAL process
allocates memory and sends the fds to the clients over binder IPC.
The graphics allocator HAL will not retain any references to the
buffers. When the HAL sets the BINDER_BUFFER_FLAG_SENDER_NO_NEED for fd
arrays holding DMA-BUF fds, the gpu cgroup controller will be able to
correctly charge the buffers to the client processes instead of the
graphics allocator HAL.
Signed-off-by: Hridya Valsaraju <hridya@xxxxxxxxxx>
---
drivers/android/binder.c | 32 +++++++++++++++++++++++++++++
include/uapi/linux/android/binder.h | 1 +
2 files changed, 33 insertions(+)
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index 5497797ab258..83082fd1ab6a 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -42,6 +42,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/dma-buf.h>
#include <linux/fdtable.h>
#include <linux/file.h>
#include <linux/freezer.h>
@@ -2482,8 +2483,11 @@ static int binder_translate_fd_array(struct list_head *pf_head,
{
binder_size_t fdi, fd_buf_size;
binder_size_t fda_offset;
+ bool transfer_gpu_charge = false;
const void __user *sender_ufda_base;
struct binder_proc *proc = thread->proc;
+ struct binder_proc *target_proc = t->to_proc;
+
int ret;
fd_buf_size = sizeof(u32) * fda->num_fds;
@@ -2520,8 +2524,15 @@ static int binder_translate_fd_array(struct list_head *pf_head,
if (ret)
return ret;
+ if (IS_ENABLED(CONFIG_CGROUP_GPU) &&
+ parent->flags & BINDER_BUFFER_FLAG_SENDER_NO_NEED)
+ transfer_gpu_charge = true;
+
for (fdi = 0; fdi < fda->num_fds; fdi++) {
u32 fd;
+ struct dma_buf *dmabuf;
+ struct gpucg *gpucg;
+
binder_size_t offset = fda_offset + fdi * sizeof(fd);
binder_size_t sender_uoffset = fdi * sizeof(fd);
@@ -2531,6 +2542,27 @@ static int binder_translate_fd_array(struct list_head *pf_head,
in_reply_to);
if (ret)
return ret > 0 ? -EINVAL : ret;
+
+ if (!transfer_gpu_charge)
+ continue;
+
+ dmabuf = dma_buf_get(fd);
+ if (IS_ERR(dmabuf))
+ continue;
+
+ if (dmabuf->ops->charge_to_cgroup) {
+ gpucg = gpucg_get(target_proc->tsk);
+ ret = dmabuf->ops->charge_to_cgroup(dmabuf, gpucg);
+ if (ret) {
+ pr_warn("%d:%d Unable to transfer DMA-BUF fd charge to %d",
+ proc->pid, thread->pid, target_proc->pid);
+ gpucg_put(gpucg);
+ }
+ } else {
+ pr_warn("%d:%d DMA-BUF exporter %s is not configured correctly for GPU cgroup memory accounting",
+ proc->pid, thread->pid, dmabuf->exp_name);
+ }
+ dma_buf_put(dmabuf);
}
return 0;
}
diff --git a/include/uapi/linux/android/binder.h b/include/uapi/linux/android/binder.h
index ad619623571e..c85f0014c341 100644
--- a/include/uapi/linux/android/binder.h
+++ b/include/uapi/linux/android/binder.h
@@ -137,6 +137,7 @@ struct binder_buffer_object {
enum {
BINDER_BUFFER_FLAG_HAS_PARENT = 0x01,
+ BINDER_BUFFER_FLAG_SENDER_NO_NEED = 0x02,
};
/* struct binder_fd_array_object - object describing an array of fds in a buffer
--
2.34.1.703.g22d0c6ccf7-goog