ANDROID: Account dmabufs in dup2()
Commit 5dd8a05ba11a ("ANDROID: Don't use current pointer for per-process
dmabuf accounting") introduced unaccounting calls for dmabufs in dup2(),
but neglected to add accounting. This can result in artificially low
dmabuf accounting for the process if only one of the FDs that refer to
the same dmabuf is closed.
Fixes: 5dd8a05ba11a ("ANDROID: Don't use current pointer for per-process dmabuf accounting")
Bug: 461520624
Change-Id: I255553fd22ed450f72bc9f09f12bc6e9b87c1678
Signed-off-by: T.J. Mercier <tjmercier@google.com>
diff --git a/fs/file.c b/fs/file.c
index 3505320..3402e1f 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -1109,6 +1109,27 @@ __releases(&files->file_lock)
struct file *tofree;
struct fdtable *fdt;
+ get_file(file);
+
+ /*
+ * Must be done before the dup and the file_lock is dropped at the end of the function to
+ * avoid a race with close(fd) from another thread, but we can't allocate while atomic, so
+ * account up-front and rollback upon error.
+ */
+ if (is_dma_buf_file(file)) {
+ int err;
+
+ spin_unlock(&files->file_lock);
+ err = dma_buf_account_task(file->private_data, files->dmabuf_info);
+ if (err) {
+ pr_err("dmabuf accounting failed during %s operation, err %d\n", __func__,
+ err);
+ fput(file);
+ return err;
+ }
+ spin_lock(&files->file_lock);
+ }
+
/*
* We need to detect attempts to do dup2() over allocated but still
* not finished descriptor. NB: OpenBSD avoids that at the price of
@@ -1128,7 +1149,6 @@ __releases(&files->file_lock)
tofree = rcu_dereference_raw(fdt->fd[fd]);
if (!tofree && fd_is_open(fd, fdt))
goto Ebusy;
- get_file(file);
rcu_assign_pointer(fdt->fd[fd], file);
__set_open_fd(fd, fdt);
if (flags & O_CLOEXEC)
@@ -1147,6 +1167,9 @@ __releases(&files->file_lock)
Ebusy:
spin_unlock(&files->file_lock);
+ if (is_dma_buf_file(file))
+ dma_buf_unaccount_task(file->private_data, files->dmabuf_info);
+ fput(file);
return -EBUSY;
}