@@ -740,43 +740,54 @@ static bool xfrm_policy_mark_match(struct xfrm_policy *policy,
740740 return false;
741741}
742742
743- int xfrm_policy_insert (int dir , struct xfrm_policy * policy , int excl )
743+ static struct xfrm_policy * xfrm_policy_insert_list (struct hlist_head * chain ,
744+ struct xfrm_policy * policy ,
745+ bool excl )
744746{
745- struct net * net = xp_net (policy );
746- struct xfrm_policy * pol ;
747- struct xfrm_policy * delpol ;
748- struct hlist_head * chain ;
749- struct hlist_node * newpos ;
747+ struct xfrm_policy * pol , * newpos = NULL , * delpol = NULL ;
750748
751- spin_lock_bh (& net -> xfrm .xfrm_policy_lock );
752- chain = policy_hash_bysel (net , & policy -> selector , policy -> family , dir );
753- delpol = NULL ;
754- newpos = NULL ;
755749 hlist_for_each_entry (pol , chain , bydst ) {
756750 if (pol -> type == policy -> type &&
757751 pol -> if_id == policy -> if_id &&
758752 !selector_cmp (& pol -> selector , & policy -> selector ) &&
759753 xfrm_policy_mark_match (policy , pol ) &&
760754 xfrm_sec_ctx_match (pol -> security , policy -> security ) &&
761755 !WARN_ON (delpol )) {
762- if (excl ) {
763- spin_unlock_bh (& net -> xfrm .xfrm_policy_lock );
764- return - EEXIST ;
765- }
756+ if (excl )
757+ return ERR_PTR (- EEXIST );
766758 delpol = pol ;
767759 if (policy -> priority > pol -> priority )
768760 continue ;
769761 } else if (policy -> priority >= pol -> priority ) {
770- newpos = & pol -> bydst ;
762+ newpos = pol ;
771763 continue ;
772764 }
773765 if (delpol )
774766 break ;
775767 }
776768 if (newpos )
777- hlist_add_behind_rcu (& policy -> bydst , newpos );
769+ hlist_add_behind_rcu (& policy -> bydst , & newpos -> bydst );
778770 else
779771 hlist_add_head_rcu (& policy -> bydst , chain );
772+
773+ return delpol ;
774+ }
775+
776+ int xfrm_policy_insert (int dir , struct xfrm_policy * policy , int excl )
777+ {
778+ struct net * net = xp_net (policy );
779+ struct xfrm_policy * delpol ;
780+ struct hlist_head * chain ;
781+
782+ spin_lock_bh (& net -> xfrm .xfrm_policy_lock );
783+ chain = policy_hash_bysel (net , & policy -> selector , policy -> family , dir );
784+ delpol = xfrm_policy_insert_list (chain , policy , excl );
785+
786+ if (IS_ERR (delpol )) {
787+ spin_unlock_bh (& net -> xfrm .xfrm_policy_lock );
788+ return PTR_ERR (delpol );
789+ }
790+
780791 __xfrm_policy_link (policy , dir );
781792
782793 /* After previous checking, family can either be AF_INET or AF_INET6 */
0 commit comments