@@ -897,6 +897,44 @@ struct sk_buff *skb_morph(struct sk_buff *dst, struct sk_buff *src)
897
897
}
898
898
EXPORT_SYMBOL_GPL (skb_morph );
899
899
900
+ static int mm_account_pinned_pages (struct mmpin * mmp , size_t size )
901
+ {
902
+ unsigned long max_pg , num_pg , new_pg , old_pg ;
903
+ struct user_struct * user ;
904
+
905
+ if (capable (CAP_IPC_LOCK ) || !size )
906
+ return 0 ;
907
+
908
+ num_pg = (size >> PAGE_SHIFT ) + 2 ; /* worst case */
909
+ max_pg = rlimit (RLIMIT_MEMLOCK ) >> PAGE_SHIFT ;
910
+ user = mmp -> user ? : current_user ();
911
+
912
+ do {
913
+ old_pg = atomic_long_read (& user -> locked_vm );
914
+ new_pg = old_pg + num_pg ;
915
+ if (new_pg > max_pg )
916
+ return - ENOBUFS ;
917
+ } while (atomic_long_cmpxchg (& user -> locked_vm , old_pg , new_pg ) !=
918
+ old_pg );
919
+
920
+ if (!mmp -> user ) {
921
+ mmp -> user = get_uid (user );
922
+ mmp -> num_pg = num_pg ;
923
+ } else {
924
+ mmp -> num_pg += num_pg ;
925
+ }
926
+
927
+ return 0 ;
928
+ }
929
+
930
+ static void mm_unaccount_pinned_pages (struct mmpin * mmp )
931
+ {
932
+ if (mmp -> user ) {
933
+ atomic_long_sub (mmp -> num_pg , & mmp -> user -> locked_vm );
934
+ free_uid (mmp -> user );
935
+ }
936
+ }
937
+
900
938
struct ubuf_info * sock_zerocopy_alloc (struct sock * sk , size_t size )
901
939
{
902
940
struct ubuf_info * uarg ;
@@ -913,6 +951,12 @@ struct ubuf_info *sock_zerocopy_alloc(struct sock *sk, size_t size)
913
951
914
952
BUILD_BUG_ON (sizeof (* uarg ) > sizeof (skb -> cb ));
915
953
uarg = (void * )skb -> cb ;
954
+ uarg -> mmp .user = NULL ;
955
+
956
+ if (mm_account_pinned_pages (& uarg -> mmp , size )) {
957
+ kfree_skb (skb );
958
+ return NULL ;
959
+ }
916
960
917
961
uarg -> callback = sock_zerocopy_callback ;
918
962
uarg -> id = ((u32 )atomic_inc_return (& sk -> sk_zckey )) - 1 ;
@@ -956,6 +1000,8 @@ struct ubuf_info *sock_zerocopy_realloc(struct sock *sk, size_t size,
956
1000
957
1001
next = (u32 )atomic_read (& sk -> sk_zckey );
958
1002
if ((u32 )(uarg -> id + uarg -> len ) == next ) {
1003
+ if (mm_account_pinned_pages (& uarg -> mmp , size ))
1004
+ return NULL ;
959
1005
uarg -> len ++ ;
960
1006
uarg -> bytelen = bytelen ;
961
1007
atomic_set (& sk -> sk_zckey , ++ next );
@@ -1038,6 +1084,8 @@ EXPORT_SYMBOL_GPL(sock_zerocopy_callback);
1038
1084
void sock_zerocopy_put (struct ubuf_info * uarg )
1039
1085
{
1040
1086
if (uarg && atomic_dec_and_test (& uarg -> refcnt )) {
1087
+ mm_unaccount_pinned_pages (& uarg -> mmp );
1088
+
1041
1089
if (uarg -> callback )
1042
1090
uarg -> callback (uarg , uarg -> zerocopy );
1043
1091
else
0 commit comments