aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2011-12-24 01:56:49 -0500
committerDavid S. Miller <davem@davemloft.net>2011-12-24 16:13:27 -0500
commit60b778ce519625102d3f72a2071ea72a05e990ce (patch)
treeecae42cc8809809287e10007643370eaed7e3055
parent035c4c16bea2814890c64c657d177e91cec1f473 (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>
-rw-r--r--include/linux/netdevice.h8
-rw-r--r--net/core/net-sysfs.c44
2 files changed, 31 insertions, 21 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 603730804da5..a776a675c0e5 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -597,7 +597,7 @@ struct rps_map {
597 struct rcu_head rcu; 597 struct rcu_head rcu;
598 u16 cpus[0]; 598 u16 cpus[0];
599}; 599};
600#define RPS_MAP_SIZE(_num) (sizeof(struct rps_map) + (_num * sizeof(u16))) 600#define RPS_MAP_SIZE(_num) (sizeof(struct rps_map) + ((_num) * sizeof(u16)))
601 601
602/* 602/*
603 * The rps_dev_flow structure contains the mapping of a flow to a CPU, the 603 * The rps_dev_flow structure contains the mapping of a flow to a CPU, the
@@ -621,7 +621,7 @@ struct rps_dev_flow_table {
621 struct rps_dev_flow flows[0]; 621 struct rps_dev_flow flows[0];
622}; 622};
623#define RPS_DEV_FLOW_TABLE_SIZE(_num) (sizeof(struct rps_dev_flow_table) + \ 623#define RPS_DEV_FLOW_TABLE_SIZE(_num) (sizeof(struct rps_dev_flow_table) + \
624 (_num * sizeof(struct rps_dev_flow))) 624 ((_num) * sizeof(struct rps_dev_flow)))
625 625
626/* 626/*
627 * The rps_sock_flow_table contains mappings of flows to the last CPU 627 * The rps_sock_flow_table contains mappings of flows to the last CPU
@@ -632,7 +632,7 @@ struct rps_sock_flow_table {
632 u16 ents[0]; 632 u16 ents[0];
633}; 633};
634#define RPS_SOCK_FLOW_TABLE_SIZE(_num) (sizeof(struct rps_sock_flow_table) + \ 634#define RPS_SOCK_FLOW_TABLE_SIZE(_num) (sizeof(struct rps_sock_flow_table) + \
635 (_num * sizeof(u16))) 635 ((_num) * sizeof(u16)))
636 636
637#define RPS_NO_CPU 0xffff 637#define RPS_NO_CPU 0xffff
638 638
@@ -684,7 +684,7 @@ struct xps_map {
684 struct rcu_head rcu; 684 struct rcu_head rcu;
685 u16 queues[0]; 685 u16 queues[0];
686}; 686};
687#define XPS_MAP_SIZE(_num) (sizeof(struct xps_map) + (_num * sizeof(u16))) 687#define XPS_MAP_SIZE(_num) (sizeof(struct xps_map) + ((_num) * sizeof(u16)))
688#define XPS_MIN_MAP_ALLOC ((L1_CACHE_BYTES - sizeof(struct xps_map)) \ 688#define XPS_MIN_MAP_ALLOC ((L1_CACHE_BYTES - sizeof(struct xps_map)) \
689 / sizeof(u16)) 689 / sizeof(u16))
690 690
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
636static void rps_dev_flow_table_release_work(struct work_struct *work) 636static 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