Merge git://git.infradead.org/users/willy/linux-nvme
[cascardo/linux.git] / net / xfrm / xfrm_policy.c
index 0d49945..4b98b25 100644 (file)
 #define XFRM_QUEUE_TMO_MAX ((unsigned)(60*HZ))
 #define XFRM_MAX_QUEUE_LEN     100
 
-DEFINE_MUTEX(xfrm_cfg_mutex);
-EXPORT_SYMBOL(xfrm_cfg_mutex);
-
-static DEFINE_SPINLOCK(xfrm_policy_sk_bundle_lock);
 static struct dst_entry *xfrm_policy_sk_bundles;
-static DEFINE_RWLOCK(xfrm_policy_lock);
 
 static DEFINE_SPINLOCK(xfrm_policy_afinfo_lock);
 static struct xfrm_policy_afinfo __rcu *xfrm_policy_afinfo[NPROTO]
@@ -176,7 +171,7 @@ static inline unsigned long make_jiffies(long secs)
 
 static void xfrm_policy_timer(unsigned long data)
 {
-       struct xfrm_policy *xp = (struct xfrm_policy*)data;
+       struct xfrm_policy *xp = (struct xfrm_policy *)data;
        unsigned long now = get_seconds();
        long next = LONG_MAX;
        int warn = 0;
@@ -438,7 +433,7 @@ static void xfrm_bydst_resize(struct net *net, int dir)
        if (!ndst)
                return;
 
-       write_lock_bh(&xfrm_policy_lock);
+       write_lock_bh(&net->xfrm.xfrm_policy_lock);
 
        for (i = hmask; i >= 0; i--)
                xfrm_dst_hash_transfer(odst + i, ndst, nhashmask);
@@ -446,7 +441,7 @@ static void xfrm_bydst_resize(struct net *net, int dir)
        net->xfrm.policy_bydst[dir].table = ndst;
        net->xfrm.policy_bydst[dir].hmask = nhashmask;
 
-       write_unlock_bh(&xfrm_policy_lock);
+       write_unlock_bh(&net->xfrm.xfrm_policy_lock);
 
        xfrm_hash_free(odst, (hmask + 1) * sizeof(struct hlist_head));
 }
@@ -463,7 +458,7 @@ static void xfrm_byidx_resize(struct net *net, int total)
        if (!nidx)
                return;
 
-       write_lock_bh(&xfrm_policy_lock);
+       write_lock_bh(&net->xfrm.xfrm_policy_lock);
 
        for (i = hmask; i >= 0; i--)
                xfrm_idx_hash_transfer(oidx + i, nidx, nhashmask);
@@ -471,7 +466,7 @@ static void xfrm_byidx_resize(struct net *net, int total)
        net->xfrm.policy_byidx = nidx;
        net->xfrm.policy_idx_hmask = nhashmask;
 
-       write_unlock_bh(&xfrm_policy_lock);
+       write_unlock_bh(&net->xfrm.xfrm_policy_lock);
 
        xfrm_hash_free(oidx, (hmask + 1) * sizeof(struct hlist_head));
 }
@@ -504,7 +499,7 @@ static inline int xfrm_byidx_should_resize(struct net *net, int total)
 
 void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si)
 {
-       read_lock_bh(&xfrm_policy_lock);
+       read_lock_bh(&net->xfrm.xfrm_policy_lock);
        si->incnt = net->xfrm.policy_count[XFRM_POLICY_IN];
        si->outcnt = net->xfrm.policy_count[XFRM_POLICY_OUT];
        si->fwdcnt = net->xfrm.policy_count[XFRM_POLICY_FWD];
@@ -513,7 +508,7 @@ void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si)
        si->fwdscnt = net->xfrm.policy_count[XFRM_POLICY_FWD+XFRM_POLICY_MAX];
        si->spdhcnt = net->xfrm.policy_idx_hmask;
        si->spdhmcnt = xfrm_policy_hashmax;
-       read_unlock_bh(&xfrm_policy_lock);
+       read_unlock_bh(&net->xfrm.xfrm_policy_lock);
 }
 EXPORT_SYMBOL(xfrm_spd_getinfo);
 
@@ -538,7 +533,7 @@ static void xfrm_hash_resize(struct work_struct *work)
 
 /* Generate new index... KAME seems to generate them ordered by cost
  * of an absolute inpredictability of ordering of rules. This will not pass. */
-static u32 xfrm_gen_index(struct net *net, int dir)
+static u32 xfrm_gen_index(struct net *net, int dir, u32 index)
 {
        static u32 idx_generator;
 
@@ -548,8 +543,14 @@ static u32 xfrm_gen_index(struct net *net, int dir)
                u32 idx;
                int found;
 
-               idx = (idx_generator | dir);
-               idx_generator += 8;
+               if (!index) {
+                       idx = (idx_generator | dir);
+                       idx_generator += 8;
+               } else {
+                       idx = index;
+                       index = 0;
+               }
+
                if (idx == 0)
                        idx = 8;
                list = net->xfrm.policy_byidx + idx_hash(net, idx);
@@ -630,7 +631,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
        struct hlist_head *chain;
        struct hlist_node *newpos;
 
-       write_lock_bh(&xfrm_policy_lock);
+       write_lock_bh(&net->xfrm.xfrm_policy_lock);
        chain = policy_hash_bysel(net, &policy->selector, policy->family, dir);
        delpol = NULL;
        newpos = NULL;
@@ -641,7 +642,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
                    xfrm_sec_ctx_match(pol->security, policy->security) &&
                    !WARN_ON(delpol)) {
                        if (excl) {
-                               write_unlock_bh(&xfrm_policy_lock);
+                               write_unlock_bh(&net->xfrm.xfrm_policy_lock);
                                return -EEXIST;
                        }
                        delpol = pol;
@@ -672,14 +673,14 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
                xfrm_policy_requeue(delpol, policy);
                __xfrm_policy_unlink(delpol, dir);
        }
-       policy->index = delpol ? delpol->index : xfrm_gen_index(net, dir);
+       policy->index = delpol ? delpol->index : xfrm_gen_index(net, dir, policy->index);
        hlist_add_head(&policy->byidx, net->xfrm.policy_byidx+idx_hash(net, policy->index));
        policy->curlft.add_time = get_seconds();
        policy->curlft.use_time = 0;
        if (!mod_timer(&policy->timer, jiffies + HZ))
                xfrm_pol_hold(policy);
        list_add(&policy->walk.all, &net->xfrm.policy_all);
-       write_unlock_bh(&xfrm_policy_lock);
+       write_unlock_bh(&net->xfrm.xfrm_policy_lock);
 
        if (delpol)
                xfrm_policy_kill(delpol);
@@ -699,7 +700,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type,
        struct hlist_head *chain;
 
        *err = 0;
-       write_lock_bh(&xfrm_policy_lock);
+       write_lock_bh(&net->xfrm.xfrm_policy_lock);
        chain = policy_hash_bysel(net, sel, sel->family, dir);
        ret = NULL;
        hlist_for_each_entry(pol, chain, bydst) {
@@ -712,7 +713,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type,
                                *err = security_xfrm_policy_delete(
                                                                pol->security);
                                if (*err) {
-                                       write_unlock_bh(&xfrm_policy_lock);
+                                       write_unlock_bh(&net->xfrm.xfrm_policy_lock);
                                        return pol;
                                }
                                __xfrm_policy_unlink(pol, dir);
@@ -721,7 +722,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type,
                        break;
                }
        }
-       write_unlock_bh(&xfrm_policy_lock);
+       write_unlock_bh(&net->xfrm.xfrm_policy_lock);
 
        if (ret && delete)
                xfrm_policy_kill(ret);
@@ -740,7 +741,7 @@ struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type,
                return NULL;
 
        *err = 0;
-       write_lock_bh(&xfrm_policy_lock);
+       write_lock_bh(&net->xfrm.xfrm_policy_lock);
        chain = net->xfrm.policy_byidx + idx_hash(net, id);
        ret = NULL;
        hlist_for_each_entry(pol, chain, byidx) {
@@ -751,7 +752,7 @@ struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type,
                                *err = security_xfrm_policy_delete(
                                                                pol->security);
                                if (*err) {
-                                       write_unlock_bh(&xfrm_policy_lock);
+                                       write_unlock_bh(&net->xfrm.xfrm_policy_lock);
                                        return pol;
                                }
                                __xfrm_policy_unlink(pol, dir);
@@ -760,7 +761,7 @@ struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type,
                        break;
                }
        }
-       write_unlock_bh(&xfrm_policy_lock);
+       write_unlock_bh(&net->xfrm.xfrm_policy_lock);
 
        if (ret && delete)
                xfrm_policy_kill(ret);
@@ -823,7 +824,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
 {
        int dir, err = 0, cnt = 0;
 
-       write_lock_bh(&xfrm_policy_lock);
+       write_lock_bh(&net->xfrm.xfrm_policy_lock);
 
        err = xfrm_policy_flush_secctx_check(net, type, audit_info);
        if (err)
@@ -839,7 +840,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
                        if (pol->type != type)
                                continue;
                        __xfrm_policy_unlink(pol, dir);
-                       write_unlock_bh(&xfrm_policy_lock);
+                       write_unlock_bh(&net->xfrm.xfrm_policy_lock);
                        cnt++;
 
                        xfrm_audit_policy_delete(pol, 1, audit_info->loginuid,
@@ -848,7 +849,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
 
                        xfrm_policy_kill(pol);
 
-                       write_lock_bh(&xfrm_policy_lock);
+                       write_lock_bh(&net->xfrm.xfrm_policy_lock);
                        goto again1;
                }
 
@@ -860,7 +861,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
                                if (pol->type != type)
                                        continue;
                                __xfrm_policy_unlink(pol, dir);
-                               write_unlock_bh(&xfrm_policy_lock);
+                               write_unlock_bh(&net->xfrm.xfrm_policy_lock);
                                cnt++;
 
                                xfrm_audit_policy_delete(pol, 1,
@@ -869,7 +870,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
                                                         audit_info->secid);
                                xfrm_policy_kill(pol);
 
-                               write_lock_bh(&xfrm_policy_lock);
+                               write_lock_bh(&net->xfrm.xfrm_policy_lock);
                                goto again2;
                        }
                }
@@ -878,7 +879,7 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
        if (!cnt)
                err = -ESRCH;
 out:
-       write_unlock_bh(&xfrm_policy_lock);
+       write_unlock_bh(&net->xfrm.xfrm_policy_lock);
        return err;
 }
 EXPORT_SYMBOL(xfrm_policy_flush);
@@ -898,7 +899,7 @@ int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk,
        if (list_empty(&walk->walk.all) && walk->seq != 0)
                return 0;
 
-       write_lock_bh(&xfrm_policy_lock);
+       write_lock_bh(&net->xfrm.xfrm_policy_lock);
        if (list_empty(&walk->walk.all))
                x = list_first_entry(&net->xfrm.policy_all, struct xfrm_policy_walk_entry, all);
        else
@@ -924,7 +925,7 @@ int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk,
        }
        list_del_init(&walk->walk.all);
 out:
-       write_unlock_bh(&xfrm_policy_lock);
+       write_unlock_bh(&net->xfrm.xfrm_policy_lock);
        return error;
 }
 EXPORT_SYMBOL(xfrm_policy_walk);
@@ -938,14 +939,14 @@ void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type)
 }
 EXPORT_SYMBOL(xfrm_policy_walk_init);
 
-void xfrm_policy_walk_done(struct xfrm_policy_walk *walk)
+void xfrm_policy_walk_done(struct xfrm_policy_walk *walk, struct net *net)
 {
        if (list_empty(&walk->walk.all))
                return;
 
-       write_lock_bh(&xfrm_policy_lock);
+       write_lock_bh(&net->xfrm.xfrm_policy_lock); /*FIXME where is net? */
        list_del(&walk->walk.all);
-       write_unlock_bh(&xfrm_policy_lock);
+       write_unlock_bh(&net->xfrm.xfrm_policy_lock);
 }
 EXPORT_SYMBOL(xfrm_policy_walk_done);
 
@@ -990,7 +991,7 @@ static struct xfrm_policy *xfrm_policy_lookup_bytype(struct net *net, u8 type,
        if (unlikely(!daddr || !saddr))
                return NULL;
 
-       read_lock_bh(&xfrm_policy_lock);
+       read_lock_bh(&net->xfrm.xfrm_policy_lock);
        chain = policy_hash_direct(net, daddr, saddr, family, dir);
        ret = NULL;
        hlist_for_each_entry(pol, chain, bydst) {
@@ -1026,7 +1027,7 @@ static struct xfrm_policy *xfrm_policy_lookup_bytype(struct net *net, u8 type,
        if (ret)
                xfrm_pol_hold(ret);
 fail:
-       read_unlock_bh(&xfrm_policy_lock);
+       read_unlock_bh(&net->xfrm.xfrm_policy_lock);
 
        return ret;
 }
@@ -1103,8 +1104,9 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir,
                                                 const struct flowi *fl)
 {
        struct xfrm_policy *pol;
+       struct net *net = sock_net(sk);
 
-       read_lock_bh(&xfrm_policy_lock);
+       read_lock_bh(&net->xfrm.xfrm_policy_lock);
        if ((pol = sk->sk_policy[dir]) != NULL) {
                bool match = xfrm_selector_match(&pol->selector, fl,
                                                 sk->sk_family);
@@ -1128,7 +1130,7 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir,
                        pol = NULL;
        }
 out:
-       read_unlock_bh(&xfrm_policy_lock);
+       read_unlock_bh(&net->xfrm.xfrm_policy_lock);
        return pol;
 }
 
@@ -1166,9 +1168,11 @@ static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol,
 
 int xfrm_policy_delete(struct xfrm_policy *pol, int dir)
 {
-       write_lock_bh(&xfrm_policy_lock);
+       struct net *net = xp_net(pol);
+
+       write_lock_bh(&net->xfrm.xfrm_policy_lock);
        pol = __xfrm_policy_unlink(pol, dir);
-       write_unlock_bh(&xfrm_policy_lock);
+       write_unlock_bh(&net->xfrm.xfrm_policy_lock);
        if (pol) {
                xfrm_policy_kill(pol);
                return 0;
@@ -1187,12 +1191,12 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol)
                return -EINVAL;
 #endif
 
-       write_lock_bh(&xfrm_policy_lock);
+       write_lock_bh(&net->xfrm.xfrm_policy_lock);
        old_pol = sk->sk_policy[dir];
        sk->sk_policy[dir] = pol;
        if (pol) {
                pol->curlft.add_time = get_seconds();
-               pol->index = xfrm_gen_index(net, XFRM_POLICY_MAX+dir);
+               pol->index = xfrm_gen_index(net, XFRM_POLICY_MAX+dir, 0);
                __xfrm_policy_link(pol, XFRM_POLICY_MAX+dir);
        }
        if (old_pol) {
@@ -1204,7 +1208,7 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol)
                 */
                __xfrm_policy_unlink(old_pol, XFRM_POLICY_MAX+dir);
        }
-       write_unlock_bh(&xfrm_policy_lock);
+       write_unlock_bh(&net->xfrm.xfrm_policy_lock);
 
        if (old_pol) {
                xfrm_policy_kill(old_pol);
@@ -1215,6 +1219,7 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol)
 static struct xfrm_policy *clone_policy(const struct xfrm_policy *old, int dir)
 {
        struct xfrm_policy *newp = xfrm_policy_alloc(xp_net(old), GFP_ATOMIC);
+       struct net *net = xp_net(old);
 
        if (newp) {
                newp->selector = old->selector;
@@ -1233,9 +1238,9 @@ static struct xfrm_policy *clone_policy(const struct xfrm_policy *old, int dir)
                newp->type = old->type;
                memcpy(newp->xfrm_vec, old->xfrm_vec,
                       newp->xfrm_nr*sizeof(struct xfrm_tmpl));
-               write_lock_bh(&xfrm_policy_lock);
+               write_lock_bh(&net->xfrm.xfrm_policy_lock);
                __xfrm_policy_link(newp, XFRM_POLICY_MAX+dir);
-               write_unlock_bh(&xfrm_policy_lock);
+               write_unlock_bh(&net->xfrm.xfrm_policy_lock);
                xfrm_pol_put(newp);
        }
        return newp;
@@ -1281,7 +1286,7 @@ xfrm_tmpl_resolve_one(struct xfrm_policy *policy, const struct flowi *fl,
        xfrm_address_t *saddr = xfrm_flowi_saddr(fl, family);
        xfrm_address_t tmp;
 
-       for (nx=0, i = 0; i < policy->xfrm_nr; i++) {
+       for (nx = 0, i = 0; i < policy->xfrm_nr; i++) {
                struct xfrm_state *x;
                xfrm_address_t *remote = daddr;
                xfrm_address_t *local  = saddr;
@@ -1311,9 +1316,9 @@ xfrm_tmpl_resolve_one(struct xfrm_policy *policy, const struct flowi *fl,
                        error = (x->km.state == XFRM_STATE_ERROR ?
                                 -EINVAL : -EAGAIN);
                        xfrm_state_put(x);
-               }
-               else if (error == -ESRCH)
+               } else if (error == -ESRCH) {
                        error = -EAGAIN;
+               }
 
                if (!tmpl->optional)
                        goto fail;
@@ -1321,7 +1326,7 @@ xfrm_tmpl_resolve_one(struct xfrm_policy *policy, const struct flowi *fl,
        return nx;
 
 fail:
-       for (nx--; nx>=0; nx--)
+       for (nx--; nx >= 0; nx--)
                xfrm_state_put(xfrm[nx]);
        return error;
 }
@@ -1358,7 +1363,7 @@ xfrm_tmpl_resolve(struct xfrm_policy **pols, int npols, const struct flowi *fl,
        return cnx;
 
  fail:
-       for (cnx--; cnx>=0; cnx--)
+       for (cnx--; cnx >= 0; cnx--)
                xfrm_state_put(tpp[cnx]);
        return error;
 
@@ -1636,20 +1641,22 @@ free_dst:
        goto out;
 }
 
-static int inline
-xfrm_dst_alloc_copy(void **target, const void *src, int size)
+#ifdef CONFIG_XFRM_SUB_POLICY
+static int xfrm_dst_alloc_copy(void **target, const void *src, int size)
 {
        if (!*target) {
                *target = kmalloc(size, GFP_ATOMIC);
                if (!*target)
                        return -ENOMEM;
        }
+
        memcpy(*target, src, size);
        return 0;
 }
+#endif
 
-static int inline
-xfrm_dst_update_parent(struct dst_entry *dst, const struct xfrm_selector *sel)
+static int xfrm_dst_update_parent(struct dst_entry *dst,
+                                 const struct xfrm_selector *sel)
 {
 #ifdef CONFIG_XFRM_SUB_POLICY
        struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
@@ -1660,8 +1667,8 @@ xfrm_dst_update_parent(struct dst_entry *dst, const struct xfrm_selector *sel)
 #endif
 }
 
-static int inline
-xfrm_dst_update_origin(struct dst_entry *dst, const struct flowi *fl)
+static int xfrm_dst_update_origin(struct dst_entry *dst,
+                                 const struct flowi *fl)
 {
 #ifdef CONFIG_XFRM_SUB_POLICY
        struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
@@ -1699,7 +1706,7 @@ static int xfrm_expand_policies(const struct flowi *fl, u16 family,
                                xfrm_pols_put(pols, *num_pols);
                                return PTR_ERR(pols[1]);
                        }
-                       (*num_pols) ++;
+                       (*num_pols)++;
                        (*num_xfrms) += pols[1]->xfrm_nr;
                }
        }
@@ -1753,7 +1760,7 @@ xfrm_resolve_and_create_bundle(struct xfrm_policy **pols, int num_pols,
        }
 
        xdst->num_pols = num_pols;
-       memcpy(xdst->pols, pols, sizeof(struct xfrm_policy*) * num_pols);
+       memcpy(xdst->pols, pols, sizeof(struct xfrm_policy *) * num_pols);
        xdst->policy_genid = atomic_read(&pols[0]->genid);
 
        return xdst;
@@ -1896,8 +1903,7 @@ static struct xfrm_dst *xfrm_create_dummy_bundle(struct net *net,
        if (IS_ERR(xdst))
                return xdst;
 
-       if (net->xfrm.sysctl_larval_drop || num_xfrms <= 0 ||
-           (fl->flowi_flags & FLOWI_FLAG_CAN_SLEEP))
+       if (net->xfrm.sysctl_larval_drop || num_xfrms <= 0)
                return xdst;
 
        dst1 = &xdst->u.dst;
@@ -2023,7 +2029,7 @@ make_dummy_bundle:
        }
        xdst->num_pols = num_pols;
        xdst->num_xfrms = num_xfrms;
-       memcpy(xdst->pols, pols, sizeof(struct xfrm_policy*) * num_pols);
+       memcpy(xdst->pols, pols, sizeof(struct xfrm_policy *) * num_pols);
 
        dst_hold(&xdst->u.dst);
        return &xdst->flo;
@@ -2072,7 +2078,6 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,
        u8 dir = policy_to_flow_dir(XFRM_POLICY_OUT);
        int i, err, num_pols, num_xfrms = 0, drop_pols = 0;
 
-restart:
        dst = NULL;
        xdst = NULL;
        route = NULL;
@@ -2106,10 +2111,10 @@ restart:
 
                        dst_hold(&xdst->u.dst);
 
-                       spin_lock_bh(&xfrm_policy_sk_bundle_lock);
+                       spin_lock_bh(&net->xfrm.xfrm_policy_sk_bundle_lock);
                        xdst->u.dst.next = xfrm_policy_sk_bundles;
                        xfrm_policy_sk_bundles = &xdst->u.dst;
-                       spin_unlock_bh(&xfrm_policy_sk_bundle_lock);
+                       spin_unlock_bh(&net->xfrm.xfrm_policy_sk_bundle_lock);
 
                        route = xdst->route;
                }
@@ -2133,7 +2138,7 @@ restart:
 
                num_pols = xdst->num_pols;
                num_xfrms = xdst->num_xfrms;
-               memcpy(pols, xdst->pols, sizeof(struct xfrm_policy*) * num_pols);
+               memcpy(pols, xdst->pols, sizeof(struct xfrm_policy *) * num_pols);
                route = xdst->route;
        }
 
@@ -2152,23 +2157,8 @@ restart:
 
                        return make_blackhole(net, family, dst_orig);
                }
-               if (fl->flowi_flags & FLOWI_FLAG_CAN_SLEEP) {
-                       DECLARE_WAITQUEUE(wait, current);
 
-                       add_wait_queue(&net->xfrm.km_waitq, &wait);
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       schedule();
-                       set_current_state(TASK_RUNNING);
-                       remove_wait_queue(&net->xfrm.km_waitq, &wait);
-
-                       if (!signal_pending(current)) {
-                               dst_release(dst);
-                               goto restart;
-                       }
-
-                       err = -ERESTART;
-               } else
-                       err = -EAGAIN;
+               err = -EAGAIN;
 
                XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES);
                goto error;
@@ -2344,7 +2334,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
        if (skb->sp) {
                int i;
 
-               for (i=skb->sp->len-1; i>=0; i--) {
+               for (i = skb->sp->len-1; i >= 0; i--) {
                        struct xfrm_state *x = skb->sp->xvec[i];
                        if (!xfrm_selector_match(&x->sel, &fl, family)) {
                                XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMISMATCH);
@@ -2390,7 +2380,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
        pol->curlft.use_time = get_seconds();
 
        pols[0] = pol;
-       npols ++;
+       npols++;
 #ifdef CONFIG_XFRM_SUB_POLICY
        if (pols[0]->type != XFRM_POLICY_TYPE_MAIN) {
                pols[1] = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_MAIN,
@@ -2402,7 +2392,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
                                return 0;
                        }
                        pols[1]->curlft.use_time = get_seconds();
-                       npols ++;
+                       npols++;
                }
        }
 #endif
@@ -2434,7 +2424,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
                }
                xfrm_nr = ti;
                if (npols > 1) {
-                       xfrm_tmpl_sort(stp, tpp, xfrm_nr, family);
+                       xfrm_tmpl_sort(stp, tpp, xfrm_nr, family, net);
                        tpp = stp;
                }
 
@@ -2563,10 +2553,10 @@ static void __xfrm_garbage_collect(struct net *net)
 {
        struct dst_entry *head, *next;
 
-       spin_lock_bh(&xfrm_policy_sk_bundle_lock);
+       spin_lock_bh(&net->xfrm.xfrm_policy_sk_bundle_lock);
        head = xfrm_policy_sk_bundles;
        xfrm_policy_sk_bundles = NULL;
-       spin_unlock_bh(&xfrm_policy_sk_bundle_lock);
+       spin_unlock_bh(&net->xfrm.xfrm_policy_sk_bundle_lock);
 
        while (head) {
                next = head->next;
@@ -2950,6 +2940,13 @@ static int __net_init xfrm_net_init(struct net *net)
        rv = xfrm_sysctl_init(net);
        if (rv < 0)
                goto out_sysctl;
+
+       /* Initialize the per-net locks here */
+       spin_lock_init(&net->xfrm.xfrm_state_lock);
+       rwlock_init(&net->xfrm.xfrm_policy_lock);
+       spin_lock_init(&net->xfrm.xfrm_policy_sk_bundle_lock);
+       mutex_init(&net->xfrm.xfrm_cfg_mutex);
+
        return 0;
 
 out_sysctl:
@@ -2992,7 +2989,7 @@ static void xfrm_audit_common_policyinfo(struct xfrm_policy *xp,
                audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s",
                                 ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str);
 
-       switch(sel->family) {
+       switch (sel->family) {
        case AF_INET:
                audit_log_format(audit_buf, " src=%pI4", &sel->saddr.a4);
                if (sel->prefixlen_s != 32)
@@ -3069,15 +3066,15 @@ static bool xfrm_migrate_selector_match(const struct xfrm_selector *sel_cmp,
        return false;
 }
 
-static struct xfrm_policy * xfrm_migrate_policy_find(const struct xfrm_selector *sel,
-                                                    u8 dir, u8 type)
+static struct xfrm_policy *xfrm_migrate_policy_find(const struct xfrm_selector *sel,
+                                                   u8 dir, u8 type, struct net *net)
 {
        struct xfrm_policy *pol, *ret = NULL;
        struct hlist_head *chain;
        u32 priority = ~0U;
 
-       read_lock_bh(&xfrm_policy_lock);
-       chain = policy_hash_direct(&init_net, &sel->daddr, &sel->saddr, sel->family, dir);
+       read_lock_bh(&net->xfrm.xfrm_policy_lock); /*FIXME*/
+       chain = policy_hash_direct(net, &sel->daddr, &sel->saddr, sel->family, dir);
        hlist_for_each_entry(pol, chain, bydst) {
                if (xfrm_migrate_selector_match(sel, &pol->selector) &&
                    pol->type == type) {
@@ -3086,7 +3083,7 @@ static struct xfrm_policy * xfrm_migrate_policy_find(const struct xfrm_selector
                        break;
                }
        }
-       chain = &init_net.xfrm.policy_inexact[dir];
+       chain = &net->xfrm.policy_inexact[dir];
        hlist_for_each_entry(pol, chain, bydst) {
                if (xfrm_migrate_selector_match(sel, &pol->selector) &&
                    pol->type == type &&
@@ -3099,7 +3096,7 @@ static struct xfrm_policy * xfrm_migrate_policy_find(const struct xfrm_selector
        if (ret)
                xfrm_pol_hold(ret);
 
-       read_unlock_bh(&xfrm_policy_lock);
+       read_unlock_bh(&net->xfrm.xfrm_policy_lock);
 
        return ret;
 }
@@ -3210,7 +3207,7 @@ static int xfrm_migrate_check(const struct xfrm_migrate *m, int num_migrate)
 
 int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
                 struct xfrm_migrate *m, int num_migrate,
-                struct xfrm_kmaddress *k)
+                struct xfrm_kmaddress *k, struct net *net)
 {
        int i, err, nx_cur = 0, nx_new = 0;
        struct xfrm_policy *pol = NULL;
@@ -3223,14 +3220,14 @@ int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
                goto out;
 
        /* Stage 1 - find policy */
-       if ((pol = xfrm_migrate_policy_find(sel, dir, type)) == NULL) {
+       if ((pol = xfrm_migrate_policy_find(sel, dir, type, net)) == NULL) {
                err = -ENOENT;
                goto out;
        }
 
        /* Stage 2 - find and update state(s) */
        for (i = 0, mp = m; i < num_migrate; i++, mp++) {
-               if ((x = xfrm_migrate_state_find(mp))) {
+               if ((x = xfrm_migrate_state_find(mp, net))) {
                        x_cur[nx_cur] = x;
                        nx_cur++;
                        if ((xc = xfrm_state_migrate(x, mp))) {