Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1488983 > unrolled thread
| Started by | Vlastimil Babka <vbabka@suse.cz> |
|---|---|
| First post | 2016-09-22 17:30 +0200 |
| Last post | 2016-09-23 09:30 +0200 |
| Articles | 5 — 4 participants |
Back to article view | Back to linux.kernel
[PATCH] fs/select: add vmalloc fallback for select(2) Vlastimil Babka <vbabka@suse.cz> - 2016-09-22 17:30 +0200
Re: [PATCH] fs/select: add vmalloc fallback for select(2) Eric Dumazet <eric.dumazet@gmail.com> - 2016-09-22 18:30 +0200
Re: [PATCH] fs/select: add vmalloc fallback for select(2) Vlastimil Babka <vbabka@suse.cz> - 2016-09-22 18:50 +0200
Re: [PATCH] fs/select: add vmalloc fallback for select(2) "Hillf Danton" <hillf.zj@alibaba-inc.com> - 2016-09-23 08:50 +0200
Re: [PATCH] fs/select: add vmalloc fallback for select(2) Nicholas Piggin <npiggin@gmail.com> - 2016-09-23 09:30 +0200
| From | Vlastimil Babka <vbabka@suse.cz> |
|---|---|
| Date | 2016-09-22 17:30 +0200 |
| Subject | [PATCH] fs/select: add vmalloc fallback for select(2) |
| Message-ID | <ske6J-86C-9@gated-at.bofh.it> |
The select(2) syscall performs a kmalloc(size, GFP_KERNEL) where size grows
with the number of fds passed. We had a customer report page allocation
failures of order-4 for this allocation. This is a costly order, so it might
easily fail, as the VM expects such allocation to have a lower-order fallback.
Such trivial fallback is vmalloc(), as the memory doesn't have to be
physically contiguous. Also the allocation is temporary for the duration of the
syscall, so it's unlikely to stress vmalloc too much.
Note that the poll(2) syscall seems to use a linked list of order-0 pages, so
it doesn't need this kind of fallback.
Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
---
fs/select.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/fs/select.c b/fs/select.c
index 8ed9da50896a..8fe5bddbe99b 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -29,6 +29,7 @@
#include <linux/sched/rt.h>
#include <linux/freezer.h>
#include <net/busy_poll.h>
+#include <linux/vmalloc.h>
#include <asm/uaccess.h>
@@ -558,6 +559,7 @@ int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
struct fdtable *fdt;
/* Allocate small arguments on the stack to save memory and be faster */
long stack_fds[SELECT_STACK_ALLOC/sizeof(long)];
+ unsigned long alloc_size;
ret = -EINVAL;
if (n < 0)
@@ -580,10 +582,15 @@ int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
bits = stack_fds;
if (size > sizeof(stack_fds) / 6) {
/* Not enough space in on-stack array; must use kmalloc */
+ alloc_size = 6 * size;
ret = -ENOMEM;
- bits = kmalloc(6 * size, GFP_KERNEL);
- if (!bits)
- goto out_nofds;
+ bits = kmalloc(alloc_size, GFP_KERNEL|__GFP_NOWARN);
+ if (!bits && alloc_size > PAGE_SIZE) {
+ bits = vmalloc(alloc_size);
+
+ if (!bits)
+ goto out_nofds;
+ }
}
fds.in = bits;
fds.out = bits + size;
@@ -618,7 +625,7 @@ int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
out:
if (bits != stack_fds)
- kfree(bits);
+ kvfree(bits);
out_nofds:
return ret;
}
--
2.10.0
[toc] | [next] | [standalone]
| From | Eric Dumazet <eric.dumazet@gmail.com> |
|---|---|
| Date | 2016-09-22 18:30 +0200 |
| Message-ID | <skf2O-eA-19@gated-at.bofh.it> |
| In reply to | #1488983 |
On Thu, 2016-09-22 at 17:28 +0200, Vlastimil Babka wrote:
> The select(2) syscall performs a kmalloc(size, GFP_KERNEL) where size grows
> with the number of fds passed. We had a customer report page allocation
> failures of order-4 for this allocation. This is a costly order, so it might
> easily fail, as the VM expects such allocation to have a lower-order fallback.
>
> Such trivial fallback is vmalloc(), as the memory doesn't have to be
> physically contiguous. Also the allocation is temporary for the duration of the
> syscall, so it's unlikely to stress vmalloc too much.
>
> Note that the poll(2) syscall seems to use a linked list of order-0 pages, so
> it doesn't need this kind of fallback.
>
> Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
> ---
> fs/select.c | 15 +++++++++++----
> 1 file changed, 11 insertions(+), 4 deletions(-)
>
> diff --git a/fs/select.c b/fs/select.c
> index 8ed9da50896a..8fe5bddbe99b 100644
> --- a/fs/select.c
> +++ b/fs/select.c
> @@ -29,6 +29,7 @@
> #include <linux/sched/rt.h>
> #include <linux/freezer.h>
> #include <net/busy_poll.h>
> +#include <linux/vmalloc.h>
>
> #include <asm/uaccess.h>
>
> @@ -558,6 +559,7 @@ int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
> struct fdtable *fdt;
> /* Allocate small arguments on the stack to save memory and be faster */
> long stack_fds[SELECT_STACK_ALLOC/sizeof(long)];
> + unsigned long alloc_size;
>
> ret = -EINVAL;
> if (n < 0)
> @@ -580,10 +582,15 @@ int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
> bits = stack_fds;
> if (size > sizeof(stack_fds) / 6) {
> /* Not enough space in on-stack array; must use kmalloc */
> + alloc_size = 6 * size;
> ret = -ENOMEM;
> - bits = kmalloc(6 * size, GFP_KERNEL);
> - if (!bits)
> - goto out_nofds;
> + bits = kmalloc(alloc_size, GFP_KERNEL|__GFP_NOWARN);
> + if (!bits && alloc_size > PAGE_SIZE) {
> + bits = vmalloc(alloc_size);
> +
> + if (!bits)
> + goto out_nofds;
Test should happen if alloc_size <= PAGE_SIZE
> + }
if (!bits && alloc_size > PAGE_SIZE)
bits = vmalloc(alloc_size);
if (!bits)
goto out_nofds;
> }
> fds.in = bits;
> fds.out = bits + size;
> @@ -618,7 +625,7 @@ int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
>
> out:
> if (bits != stack_fds)
> - kfree(bits);
> + kvfree(bits);
> out_nofds:
> return ret;
> }
[toc] | [prev] | [next] | [standalone]
| From | Vlastimil Babka <vbabka@suse.cz> |
|---|---|
| Date | 2016-09-22 18:50 +0200 |
| Message-ID | <skfm9-lq-1@gated-at.bofh.it> |
| In reply to | #1489077 |
On 09/22/2016 06:24 PM, Eric Dumazet wrote:
>> + bits = kmalloc(alloc_size, GFP_KERNEL|__GFP_NOWARN);
>> + if (!bits && alloc_size > PAGE_SIZE) {
>> + bits = vmalloc(alloc_size);
>> +
>> + if (!bits)
>> + goto out_nofds;
>
> Test should happen if alloc_size <= PAGE_SIZE
>
>> + }
>
> if (!bits && alloc_size > PAGE_SIZE)
> bits = vmalloc(alloc_size);
>
> if (!bits)
> goto out_nofds;
>
Thanks... stupid last-minute changes.
[toc] | [prev] | [next] | [standalone]
| From | "Hillf Danton" <hillf.zj@alibaba-inc.com> |
|---|---|
| Date | 2016-09-23 08:50 +0200 |
| Message-ID | <skst4-eu-19@gated-at.bofh.it> |
| In reply to | #1488983 |
>
> The select(2) syscall performs a kmalloc(size, GFP_KERNEL) where size grows
> with the number of fds passed. We had a customer report page allocation
> failures of order-4 for this allocation. This is a costly order, so it might
> easily fail, as the VM expects such allocation to have a lower-order fallback.
>
> Such trivial fallback is vmalloc(), as the memory doesn't have to be
> physically contiguous. Also the allocation is temporary for the duration of the
> syscall, so it's unlikely to stress vmalloc too much.
>
> Note that the poll(2) syscall seems to use a linked list of order-0 pages, so
> it doesn't need this kind of fallback.
>
> Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
> ---
> fs/select.c | 15 +++++++++++----
> 1 file changed, 11 insertions(+), 4 deletions(-)
>
> diff --git a/fs/select.c b/fs/select.c
> index 8ed9da50896a..8fe5bddbe99b 100644
> --- a/fs/select.c
> +++ b/fs/select.c
> @@ -29,6 +29,7 @@
> #include <linux/sched/rt.h>
> #include <linux/freezer.h>
> #include <net/busy_poll.h>
> +#include <linux/vmalloc.h>
>
> #include <asm/uaccess.h>
>
> @@ -558,6 +559,7 @@ int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
> struct fdtable *fdt;
> /* Allocate small arguments on the stack to save memory and be faster */
> long stack_fds[SELECT_STACK_ALLOC/sizeof(long)];
> + unsigned long alloc_size;
>
> ret = -EINVAL;
> if (n < 0)
> @@ -580,10 +582,15 @@ int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
> bits = stack_fds;
> if (size > sizeof(stack_fds) / 6) {
> /* Not enough space in on-stack array; must use kmalloc */
> + alloc_size = 6 * size;
> ret = -ENOMEM;
> - bits = kmalloc(6 * size, GFP_KERNEL);
> - if (!bits)
> - goto out_nofds;
> + bits = kmalloc(alloc_size, GFP_KERNEL|__GFP_NOWARN);
> + if (!bits && alloc_size > PAGE_SIZE) {
> + bits = vmalloc(alloc_size);
> +
> + if (!bits)
> + goto out_nofds;
> + }
Looks like we also have to bail out if kmalloc fails with
alloc_size less than PAGE_SIZE.
thanks
Hillf
> }
> fds.in = bits;
> fds.out = bits + size;
> @@ -618,7 +625,7 @@ int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
>
> out:
> if (bits != stack_fds)
> - kfree(bits);
> + kvfree(bits);
> out_nofds:
> return ret;
> }
> --
> 2.10.0
[toc] | [prev] | [next] | [standalone]
| From | Nicholas Piggin <npiggin@gmail.com> |
|---|---|
| Date | 2016-09-23 09:30 +0200 |
| Message-ID | <skt5L-GK-9@gated-at.bofh.it> |
| In reply to | #1489792 |
On Fri, 23 Sep 2016 14:42:53 +0800
"Hillf Danton" <hillf.zj@alibaba-inc.com> wrote:
> >
> > The select(2) syscall performs a kmalloc(size, GFP_KERNEL) where size grows
> > with the number of fds passed. We had a customer report page allocation
> > failures of order-4 for this allocation. This is a costly order, so it might
> > easily fail, as the VM expects such allocation to have a lower-order fallback.
> >
> > Such trivial fallback is vmalloc(), as the memory doesn't have to be
> > physically contiguous. Also the allocation is temporary for the duration of the
> > syscall, so it's unlikely to stress vmalloc too much.
> >
> > Note that the poll(2) syscall seems to use a linked list of order-0 pages, so
> > it doesn't need this kind of fallback.
How about something like this? (untested)
Eric isn't wrong about vmalloc sucking :)
Thanks,
Nick
---
fs/select.c | 57 +++++++++++++++++++++++++++++++++++++++++++--------------
1 file changed, 43 insertions(+), 14 deletions(-)
diff --git a/fs/select.c b/fs/select.c
index 8ed9da5..3b4834c 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -555,6 +555,7 @@ int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
void *bits;
int ret, max_fds;
unsigned int size;
+ size_t nr_bytes;
struct fdtable *fdt;
/* Allocate small arguments on the stack to save memory and be faster */
long stack_fds[SELECT_STACK_ALLOC/sizeof(long)];
@@ -576,21 +577,39 @@ int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
* since we used fdset we need to allocate memory in units of
* long-words.
*/
- size = FDS_BYTES(n);
+ ret = -ENOMEM;
bits = stack_fds;
- if (size > sizeof(stack_fds) / 6) {
- /* Not enough space in on-stack array; must use kmalloc */
+ size = FDS_BYTES(n);
+ nr_bytes = 6 * size;
+
+ if (unlikely(nr_bytes > PAGE_SIZE)) {
+ /* Avoid multi-page allocation if possible */
ret = -ENOMEM;
- bits = kmalloc(6 * size, GFP_KERNEL);
- if (!bits)
- goto out_nofds;
+ fds.in = kmalloc(size, GFP_KERNEL);
+ fds.out = kmalloc(size, GFP_KERNEL);
+ fds.ex = kmalloc(size, GFP_KERNEL);
+ fds.res_in = kmalloc(size, GFP_KERNEL);
+ fds.res_out = kmalloc(size, GFP_KERNEL);
+ fds.res_ex = kmalloc(size, GFP_KERNEL);
+
+ if (!(fds.in && fds.out && fds.ex &&
+ fds.res_in && fds.res_out && fds.res_ex))
+ goto out;
+ } else {
+ if (nr_bytes > sizeof(stack_fds)) {
+ /* Not enough space in on-stack array */
+ if (nr_bytes > PAGE_SIZE * 2)
+ bits = kmalloc(nr_bytes, GFP_KERNEL);
+ if (!bits)
+ goto out_nofds;
+ }
+ fds.in = bits;
+ fds.out = bits + size;
+ fds.ex = bits + 2*size;
+ fds.res_in = bits + 3*size;
+ fds.res_out = bits + 4*size;
+ fds.res_ex = bits + 5*size;
}
- fds.in = bits;
- fds.out = bits + size;
- fds.ex = bits + 2*size;
- fds.res_in = bits + 3*size;
- fds.res_out = bits + 4*size;
- fds.res_ex = bits + 5*size;
if ((ret = get_fd_set(n, inp, fds.in)) ||
(ret = get_fd_set(n, outp, fds.out)) ||
@@ -617,8 +636,18 @@ int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
ret = -EFAULT;
out:
- if (bits != stack_fds)
- kfree(bits);
+ if (unlikely(nr_bytes > PAGE_SIZE)) {
+ kfree(fds.in);
+ kfree(fds.out);
+ kfree(fds.ex);
+ kfree(fds.res_in);
+ kfree(fds.res_out);
+ kfree(fds.res_ex);
+ } else {
+ if (bits != stack_fds)
+ kfree(bits);
+ }
+
out_nofds:
return ret;
}
--
2.9.3
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web