diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2011-12-24 01:56:49 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-12-24 16:13:27 -0500 |
commit | 60b778ce519625102d3f72a2071ea72a05e990ce (patch) | |
tree | ecae42cc8809809287e10007643370eaed7e3055 /net/core | |
parent | 035c4c16bea2814890c64c657d177e91cec1f473 (diff) |
rfs: better sizing of dev_flow_table
Aim of this patch is to provide full range of rps_flow_cnt on 64bit arches.
Theorical limit on number of flows is 2^32
Fix some buggy RPS/RFS macros as well.
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
CC: Tom Herbert <therbert@google.com>
CC: Xi Wang <xi.wang@gmail.com>
CC: Laurent Chavey <chavey@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core')
-rw-r--r-- | net/core/net-sysfs.c | 44 |
1 files changed, 27 insertions, 17 deletions
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 4b4d0b0a3543..abf4393a77b3 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c | |||
@@ -622,15 +622,15 @@ static ssize_t show_rps_dev_flow_table_cnt(struct netdev_rx_queue *queue, | |||
622 | char *buf) | 622 | char *buf) |
623 | { | 623 | { |
624 | struct rps_dev_flow_table *flow_table; | 624 | struct rps_dev_flow_table *flow_table; |
625 | unsigned int val = 0; | 625 | unsigned long val = 0; |
626 | 626 | ||
627 | rcu_read_lock(); | 627 | rcu_read_lock(); |
628 | flow_table = rcu_dereference(queue->rps_flow_table); | 628 | flow_table = rcu_dereference(queue->rps_flow_table); |
629 | if (flow_table) | 629 | if (flow_table) |
630 | val = flow_table->mask + 1; | 630 | val = (unsigned long)flow_table->mask + 1; |
631 | rcu_read_unlock(); | 631 | rcu_read_unlock(); |
632 | 632 | ||
633 | return sprintf(buf, "%u\n", val); | 633 | return sprintf(buf, "%lu\n", val); |
634 | } | 634 | } |
635 | 635 | ||
636 | static void rps_dev_flow_table_release_work(struct work_struct *work) | 636 | static void rps_dev_flow_table_release_work(struct work_struct *work) |
@@ -654,36 +654,46 @@ static ssize_t store_rps_dev_flow_table_cnt(struct netdev_rx_queue *queue, | |||
654 | struct rx_queue_attribute *attr, | 654 | struct rx_queue_attribute *attr, |
655 | const char *buf, size_t len) | 655 | const char *buf, size_t len) |
656 | { | 656 | { |
657 | unsigned int count; | 657 | unsigned long mask, count; |
658 | char *endp; | ||
659 | struct rps_dev_flow_table *table, *old_table; | 658 | struct rps_dev_flow_table *table, *old_table; |
660 | static DEFINE_SPINLOCK(rps_dev_flow_lock); | 659 | static DEFINE_SPINLOCK(rps_dev_flow_lock); |
660 | int rc; | ||
661 | 661 | ||
662 | if (!capable(CAP_NET_ADMIN)) | 662 | if (!capable(CAP_NET_ADMIN)) |
663 | return -EPERM; | 663 | return -EPERM; |
664 | 664 | ||
665 | count = simple_strtoul(buf, &endp, 0); | 665 | rc = kstrtoul(buf, 0, &count); |
666 | if (endp == buf) | 666 | if (rc < 0) |
667 | return -EINVAL; | 667 | return rc; |
668 | 668 | ||
669 | if (count) { | 669 | if (count) { |
670 | int i; | 670 | mask = count - 1; |
671 | 671 | /* mask = roundup_pow_of_two(count) - 1; | |
672 | if (count > INT_MAX) | 672 | * without overflows... |
673 | */ | ||
674 | while ((mask | (mask >> 1)) != mask) | ||
675 | mask |= (mask >> 1); | ||
676 | /* On 64 bit arches, must check mask fits in table->mask (u32), | ||
677 | * and on 32bit arches, must check RPS_DEV_FLOW_TABLE_SIZE(mask + 1) | ||
678 | * doesnt overflow. | ||
679 | */ | ||
680 | #if BITS_PER_LONG > 32 | ||
681 | if (mask > (unsigned long)(u32)mask) | ||
673 | return -EINVAL; | 682 | return -EINVAL; |
674 | count = roundup_pow_of_two(count); | 683 | #else |
675 | if (count > (ULONG_MAX - sizeof(struct rps_dev_flow_table)) | 684 | if (mask > (ULONG_MAX - RPS_DEV_FLOW_TABLE_SIZE(1)) |
676 | / sizeof(struct rps_dev_flow)) { | 685 | / sizeof(struct rps_dev_flow)) { |
677 | /* Enforce a limit to prevent overflow */ | 686 | /* Enforce a limit to prevent overflow */ |
678 | return -EINVAL; | 687 | return -EINVAL; |
679 | } | 688 | } |
680 | table = vmalloc(RPS_DEV_FLOW_TABLE_SIZE(count)); | 689 | #endif |
690 | table = vmalloc(RPS_DEV_FLOW_TABLE_SIZE(mask + 1)); | ||
681 | if (!table) | 691 | if (!table) |
682 | return -ENOMEM; | 692 | return -ENOMEM; |
683 | 693 | ||
684 | table->mask = count - 1; | 694 | table->mask = mask; |
685 | for (i = 0; i < count; i++) | 695 | for (count = 0; count <= mask; count++) |
686 | table->flows[i].cpu = RPS_NO_CPU; | 696 | table->flows[count].cpu = RPS_NO_CPU; |
687 | } else | 697 | } else |
688 | table = NULL; | 698 | table = NULL; |
689 | 699 | ||