#include <linux/rbtree.h>
 #include <linux/hash.h>
 #include <linux/prefetch.h>
+#include <linux/vmalloc.h>
 #include <net/netlink.h>
 #include <net/pkt_sched.h>
 #include <net/sock.h>
        q->stat_gc_flows += fcnt;
 }
 
-static int fq_resize(struct fq_sched_data *q, u32 log)
+static void *fq_alloc_node(size_t sz, int node)
 {
+       void *ptr;
+
+       ptr = kmalloc_node(sz, GFP_KERNEL | __GFP_REPEAT | __GFP_NOWARN, node);
+       if (!ptr)
+               ptr = vmalloc_node(sz, node);
+       return ptr;
+}
+
+static void fq_free(void *addr)
+{
+       if (addr && is_vmalloc_addr(addr))
+               vfree(addr);
+       else
+               kfree(addr);
+}
+
+static int fq_resize(struct Qdisc *sch, u32 log)
+{
+       struct fq_sched_data *q = qdisc_priv(sch);
        struct rb_root *array;
        u32 idx;
 
        if (q->fq_root && log == q->fq_trees_log)
                return 0;
 
-       array = kmalloc(sizeof(struct rb_root) << log, GFP_KERNEL);
+       /* If XPS was setup, we can allocate memory on right NUMA node */
+       array = fq_alloc_node(sizeof(struct rb_root) << log,
+                             netdev_queue_numa_node_read(sch->dev_queue));
        if (!array)
                return -ENOMEM;
 
 
        if (q->fq_root) {
                fq_rehash(q, q->fq_root, q->fq_trees_log, array, log);
-               kfree(q->fq_root);
+               fq_free(q->fq_root);
        }
        q->fq_root = array;
        q->fq_trees_log = log;
        }
 
        if (!err)
-               err = fq_resize(q, fq_log);
+               err = fq_resize(sch, fq_log);
 
        while (sch->q.qlen > sch->limit) {
                struct sk_buff *skb = fq_dequeue(sch);
        struct fq_sched_data *q = qdisc_priv(sch);
 
        fq_reset(sch);
-       kfree(q->fq_root);
+       fq_free(q->fq_root);
        qdisc_watchdog_cancel(&q->watchdog);
 }
 
        if (opt)
                err = fq_change(sch, opt);
        else
-               err = fq_resize(q, q->fq_trees_log);
+               err = fq_resize(sch, q->fq_trees_log);
 
        return err;
 }