From 1bf47346d75790ebd2563d909d48046961c7ffd5 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 6 Feb 2008 01:37:56 -0800 Subject: kernel/sys.c: get rid of expensive divides in groups_sort() groups_sort() can be quite long if user loads a large gid table. This is because GROUP_AT(group_info, some_integer) uses an integer divide. So having to do XXX thousand divides during one syscall can lead to very high latencies. (NGROUPS_MAX=65536) In the past (25 Mar 2006), an analog problem was found in groups_search() (commit d74beb9f33a5f16d2965f11b275e401f225c949d ) and at that time I changed some variables to unsigned int. I believe that a more generic fix is to make sure NGROUPS_PER_BLOCK is unsigned. Signed-off-by: Eric Dumazet Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/sys.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'kernel/sys.c') diff --git a/kernel/sys.c b/kernel/sys.c index 2b8e2daa9d95..e3c08d4324de 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -1145,16 +1145,16 @@ static int groups_to_user(gid_t __user *grouplist, struct group_info *group_info) { int i; - int count = group_info->ngroups; + unsigned int count = group_info->ngroups; for (i = 0; i < group_info->nblocks; i++) { - int cp_count = min(NGROUPS_PER_BLOCK, count); - int off = i * NGROUPS_PER_BLOCK; - int len = cp_count * sizeof(*grouplist); + unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); + unsigned int len = cp_count * sizeof(*grouplist); - if (copy_to_user(grouplist+off, group_info->blocks[i], len)) + if (copy_to_user(grouplist, group_info->blocks[i], len)) return -EFAULT; + grouplist += NGROUPS_PER_BLOCK; count -= cp_count; } return 0; @@ -1165,16 +1165,16 @@ static int groups_from_user(struct group_info *group_info, gid_t __user *grouplist) { int i; - int count = group_info->ngroups; + unsigned int count = group_info->ngroups; for (i = 0; i < group_info->nblocks; i++) { - int cp_count = min(NGROUPS_PER_BLOCK, count); - int off = i * NGROUPS_PER_BLOCK; - int len = cp_count * sizeof(*grouplist); + unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); + unsigned int len = cp_count * sizeof(*grouplist); - if (copy_from_user(group_info->blocks[i], grouplist+off, len)) + if (copy_from_user(group_info->blocks[i], grouplist, len)) return -EFAULT; + grouplist += NGROUPS_PER_BLOCK; count -= cp_count; } return 0; -- cgit v1.2.3