@@ -4137,36 +4137,52 @@ static const struct vm_operations_struct packet_mmap_ops = {
4137
4137
.close = packet_mm_close ,
4138
4138
};
4139
4139
4140
- static void free_pg_vec (struct pgv * pg_vec , unsigned int len )
4140
+ static void free_pg_vec (struct pgv * pg_vec , unsigned int order ,
4141
+ unsigned int len )
4141
4142
{
4142
4143
int i ;
4143
4144
4144
4145
for (i = 0 ; i < len ; i ++ ) {
4145
4146
if (likely (pg_vec [i ].buffer )) {
4146
- kvfree (pg_vec [i ].buffer );
4147
+ if (is_vmalloc_addr (pg_vec [i ].buffer ))
4148
+ vfree (pg_vec [i ].buffer );
4149
+ else
4150
+ free_pages ((unsigned long )pg_vec [i ].buffer ,
4151
+ order );
4147
4152
pg_vec [i ].buffer = NULL ;
4148
4153
}
4149
4154
}
4150
4155
kfree (pg_vec );
4151
4156
}
4152
4157
4153
- static char * alloc_one_pg_vec_page (unsigned long size )
4158
+ static char * alloc_one_pg_vec_page (unsigned long order )
4154
4159
{
4155
4160
char * buffer ;
4161
+ gfp_t gfp_flags = GFP_KERNEL | __GFP_COMP |
4162
+ __GFP_ZERO | __GFP_NOWARN | __GFP_NORETRY ;
4156
4163
4157
- buffer = kvzalloc ( size , GFP_KERNEL );
4164
+ buffer = ( char * ) __get_free_pages ( gfp_flags , order );
4158
4165
if (buffer )
4159
4166
return buffer ;
4160
4167
4161
- buffer = kvzalloc (size , GFP_KERNEL | __GFP_RETRY_MAYFAIL );
4168
+ /* __get_free_pages failed, fall back to vmalloc */
4169
+ buffer = vzalloc (array_size ((1 << order ), PAGE_SIZE ));
4170
+ if (buffer )
4171
+ return buffer ;
4162
4172
4163
- return buffer ;
4173
+ /* vmalloc failed, lets dig into swap here */
4174
+ gfp_flags &= ~__GFP_NORETRY ;
4175
+ buffer = (char * ) __get_free_pages (gfp_flags , order );
4176
+ if (buffer )
4177
+ return buffer ;
4178
+
4179
+ /* complete and utter failure */
4180
+ return NULL ;
4164
4181
}
4165
4182
4166
- static struct pgv * alloc_pg_vec (struct tpacket_req * req )
4183
+ static struct pgv * alloc_pg_vec (struct tpacket_req * req , int order )
4167
4184
{
4168
4185
unsigned int block_nr = req -> tp_block_nr ;
4169
- unsigned long size = req -> tp_block_size ;
4170
4186
struct pgv * pg_vec ;
4171
4187
int i ;
4172
4188
@@ -4175,7 +4191,7 @@ static struct pgv *alloc_pg_vec(struct tpacket_req *req)
4175
4191
goto out ;
4176
4192
4177
4193
for (i = 0 ; i < block_nr ; i ++ ) {
4178
- pg_vec [i ].buffer = alloc_one_pg_vec_page (size );
4194
+ pg_vec [i ].buffer = alloc_one_pg_vec_page (order );
4179
4195
if (unlikely (!pg_vec [i ].buffer ))
4180
4196
goto out_free_pgvec ;
4181
4197
}
@@ -4184,7 +4200,7 @@ static struct pgv *alloc_pg_vec(struct tpacket_req *req)
4184
4200
return pg_vec ;
4185
4201
4186
4202
out_free_pgvec :
4187
- free_pg_vec (pg_vec , block_nr );
4203
+ free_pg_vec (pg_vec , order , block_nr );
4188
4204
pg_vec = NULL ;
4189
4205
goto out ;
4190
4206
}
@@ -4194,9 +4210,9 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
4194
4210
{
4195
4211
struct pgv * pg_vec = NULL ;
4196
4212
struct packet_sock * po = pkt_sk (sk );
4213
+ int was_running , order = 0 ;
4197
4214
struct packet_ring_buffer * rb ;
4198
4215
struct sk_buff_head * rb_queue ;
4199
- int was_running ;
4200
4216
__be16 num ;
4201
4217
int err = - EINVAL ;
4202
4218
/* Added to avoid minimal code churn */
@@ -4258,7 +4274,8 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
4258
4274
goto out ;
4259
4275
4260
4276
err = - ENOMEM ;
4261
- pg_vec = alloc_pg_vec (req );
4277
+ order = get_order (req -> tp_block_size );
4278
+ pg_vec = alloc_pg_vec (req , order );
4262
4279
if (unlikely (!pg_vec ))
4263
4280
goto out ;
4264
4281
switch (po -> tp_version ) {
@@ -4312,6 +4329,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
4312
4329
rb -> frame_size = req -> tp_frame_size ;
4313
4330
spin_unlock_bh (& rb_queue -> lock );
4314
4331
4332
+ swap (rb -> pg_vec_order , order );
4315
4333
swap (rb -> pg_vec_len , req -> tp_block_nr );
4316
4334
4317
4335
rb -> pg_vec_pages = req -> tp_block_size /PAGE_SIZE ;
@@ -4337,7 +4355,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
4337
4355
}
4338
4356
4339
4357
if (pg_vec )
4340
- free_pg_vec (pg_vec , req -> tp_block_nr );
4358
+ free_pg_vec (pg_vec , order , req -> tp_block_nr );
4341
4359
out :
4342
4360
return err ;
4343
4361
}
0 commit comments