Re: [RFC v2 6/6] android: binder: Add a buffer flag to relinquish ownership of fds

From: Suren Baghdasaryan
Date: Mon Feb 14 2022 - 16:35:33 EST


On Mon, Feb 14, 2022 at 10:33 AM Todd Kjos <tkjos@xxxxxxxxxx> wrote:
>
> On Fri, Feb 11, 2022 at 11:19 PM Greg Kroah-Hartman
> <gregkh@xxxxxxxxxxxxxxxxxxx> wrote:
> >
> > On Fri, Feb 11, 2022 at 04:18:29PM +0000, T.J. Mercier wrote:
>
> Title: "android: binder: Add a buffer flag to relinquish ownership of fds"
>
> Please drop the "android:" from the title.
>
> > > 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 up to 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.
> > >
> > > From: Hridya Valsaraju <hridya@xxxxxxxxxx>
> > > Signed-off-by: Hridya Valsaraju <hridya@xxxxxxxxxx>
> > > Co-developed-by: T.J. Mercier <tjmercier@xxxxxxxxxx>
> > > Signed-off-by: T.J. Mercier <tjmercier@xxxxxxxxxx>
> > > ---
> > > changes in v2
> > > - Move dma-buf cgroup charge transfer from a dma_buf_op defined by every
> > > heap to a single dma-buf function for all heaps per Daniel Vetter and
> > > Christian König.
> > >
> > > drivers/android/binder.c | 26 ++++++++++++++++++++++++++
> > > include/uapi/linux/android/binder.h | 1 +
> > > 2 files changed, 27 insertions(+)
> > >
> > > diff --git a/drivers/android/binder.c b/drivers/android/binder.c
> > > index 8351c5638880..f50d88ded188 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,10 @@ 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;
> > > @@ -2521,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);
> > >
> > > @@ -2532,6 +2542,22 @@ 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;
> > > +
> > > + gpucg = gpucg_get(target_proc->tsk);
> > > + ret = dma_buf_charge_transfer(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);
> > > + }
> > > + dma_buf_put(dmabuf);
>
> Since we are creating a new gpu cgroup abstraction, couldn't this
> "transfer" be done in userspace by the target instead of in the kernel
> driver? Then this patch would reduce to just a flag on the buffer
> object.

Are you suggesting to have a userspace accessible cgroup interface for
transferring buffer charges and the target process to use that
interface for requesting the buffer to be charged to its cgroup?
I'm worried about the case when the target process does not request
the transfer after receiving the buffer with this flag set. The charge
would stay with the wrong process and accounting will be invalid.

Technically, since the proposed cgroup supports charge transfer from
the very beginning, the userspace can check if the cgroup is mounted
and if so then it knows this feature is supported.

> This also solves the issue that Greg brought up about
> userspace needing to know whether the kernel implements this feature
> (older kernel running with newer userspace). I think we could just
> reserve some flags for userspace to use (and since those flags are
> "reserved" for older kernels, this would enable this feature even for
> old kernels)
>
> > > }
> > > return 0;
> > > }
> > > diff --git a/include/uapi/linux/android/binder.h b/include/uapi/linux/android/binder.h
> > > index 3246f2c74696..169fd5069a1a 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.35.1.265.g69c8d7142f-goog
> > >
> >
> > How does userspace know that binder supports this new flag? And where
> > is the userspace test for this new feature? Isn't there a binder test
> > framework somewhere?
> >
> > thanks,
> >
> > greg k-h