|
@@ -21,6 +21,7 @@
|
|
|
#include <linux/audit.h>
|
|
|
#include <linux/syscalls.h>
|
|
|
#include <linux/fcntl.h>
|
|
|
+#include <linux/memcontrol.h>
|
|
|
|
|
|
#include <asm/uaccess.h>
|
|
|
#include <asm/ioctls.h>
|
|
@@ -137,6 +138,22 @@ static void anon_pipe_buf_release(struct pipe_inode_info *pipe,
|
|
|
put_page(page);
|
|
|
}
|
|
|
|
|
|
+static int anon_pipe_buf_steal(struct pipe_inode_info *pipe,
|
|
|
+ struct pipe_buffer *buf)
|
|
|
+{
|
|
|
+ struct page *page = buf->page;
|
|
|
+
|
|
|
+ if (page_count(page) == 1) {
|
|
|
+ if (memcg_kmem_enabled()) {
|
|
|
+ memcg_kmem_uncharge(page, 0);
|
|
|
+ __ClearPageKmemcg(page);
|
|
|
+ }
|
|
|
+ __SetPageLocked(page);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* generic_pipe_buf_steal - attempt to take ownership of a &pipe_buffer
|
|
|
* @pipe: the pipe that the buffer belongs to
|
|
@@ -219,7 +236,7 @@ static const struct pipe_buf_operations anon_pipe_buf_ops = {
|
|
|
.can_merge = 1,
|
|
|
.confirm = generic_pipe_buf_confirm,
|
|
|
.release = anon_pipe_buf_release,
|
|
|
- .steal = generic_pipe_buf_steal,
|
|
|
+ .steal = anon_pipe_buf_steal,
|
|
|
.get = generic_pipe_buf_get,
|
|
|
};
|
|
|
|
|
@@ -227,7 +244,7 @@ static const struct pipe_buf_operations packet_pipe_buf_ops = {
|
|
|
.can_merge = 0,
|
|
|
.confirm = generic_pipe_buf_confirm,
|
|
|
.release = anon_pipe_buf_release,
|
|
|
- .steal = generic_pipe_buf_steal,
|
|
|
+ .steal = anon_pipe_buf_steal,
|
|
|
.get = generic_pipe_buf_get,
|
|
|
};
|
|
|
|
|
@@ -405,7 +422,7 @@ pipe_write(struct kiocb *iocb, struct iov_iter *from)
|
|
|
int copied;
|
|
|
|
|
|
if (!page) {
|
|
|
- page = alloc_page(GFP_HIGHUSER);
|
|
|
+ page = alloc_page(GFP_HIGHUSER | __GFP_ACCOUNT);
|
|
|
if (unlikely(!page)) {
|
|
|
ret = ret ? : -ENOMEM;
|
|
|
break;
|
|
@@ -611,7 +628,7 @@ struct pipe_inode_info *alloc_pipe_info(void)
|
|
|
{
|
|
|
struct pipe_inode_info *pipe;
|
|
|
|
|
|
- pipe = kzalloc(sizeof(struct pipe_inode_info), GFP_KERNEL);
|
|
|
+ pipe = kzalloc(sizeof(struct pipe_inode_info), GFP_KERNEL_ACCOUNT);
|
|
|
if (pipe) {
|
|
|
unsigned long pipe_bufs = PIPE_DEF_BUFFERS;
|
|
|
struct user_struct *user = get_current_user();
|
|
@@ -619,7 +636,9 @@ struct pipe_inode_info *alloc_pipe_info(void)
|
|
|
if (!too_many_pipe_buffers_hard(user)) {
|
|
|
if (too_many_pipe_buffers_soft(user))
|
|
|
pipe_bufs = 1;
|
|
|
- pipe->bufs = kzalloc(sizeof(struct pipe_buffer) * pipe_bufs, GFP_KERNEL);
|
|
|
+ pipe->bufs = kcalloc(pipe_bufs,
|
|
|
+ sizeof(struct pipe_buffer),
|
|
|
+ GFP_KERNEL_ACCOUNT);
|
|
|
}
|
|
|
|
|
|
if (pipe->bufs) {
|
|
@@ -1010,7 +1029,8 @@ static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long nr_pages)
|
|
|
if (nr_pages < pipe->nrbufs)
|
|
|
return -EBUSY;
|
|
|
|
|
|
- bufs = kcalloc(nr_pages, sizeof(*bufs), GFP_KERNEL | __GFP_NOWARN);
|
|
|
+ bufs = kcalloc(nr_pages, sizeof(*bufs),
|
|
|
+ GFP_KERNEL_ACCOUNT | __GFP_NOWARN);
|
|
|
if (unlikely(!bufs))
|
|
|
return -ENOMEM;
|
|
|
|