@@ -63,15 +63,15 @@ static bool selem_linked_to_map(const struct bpf_local_storage_elem *selem)
6363
6464struct bpf_local_storage_elem *
6565bpf_selem_alloc (struct bpf_local_storage_map * smap , void * owner ,
66- void * value , bool charge_mem )
66+ void * value , bool charge_mem , gfp_t gfp_flags )
6767{
6868 struct bpf_local_storage_elem * selem ;
6969
7070 if (charge_mem && mem_charge (smap , owner , smap -> elem_size ))
7171 return NULL ;
7272
7373 selem = bpf_map_kzalloc (& smap -> map , smap -> elem_size ,
74- GFP_ATOMIC | __GFP_NOWARN );
74+ gfp_flags | __GFP_NOWARN );
7575 if (selem ) {
7676 if (value )
7777 memcpy (SDATA (selem )-> data , value , smap -> map .value_size );
@@ -282,7 +282,8 @@ static int check_flags(const struct bpf_local_storage_data *old_sdata,
282282
283283int bpf_local_storage_alloc (void * owner ,
284284 struct bpf_local_storage_map * smap ,
285- struct bpf_local_storage_elem * first_selem )
285+ struct bpf_local_storage_elem * first_selem ,
286+ gfp_t gfp_flags )
286287{
287288 struct bpf_local_storage * prev_storage , * storage ;
288289 struct bpf_local_storage * * owner_storage_ptr ;
@@ -293,7 +294,7 @@ int bpf_local_storage_alloc(void *owner,
293294 return err ;
294295
295296 storage = bpf_map_kzalloc (& smap -> map , sizeof (* storage ),
296- GFP_ATOMIC | __GFP_NOWARN );
297+ gfp_flags | __GFP_NOWARN );
297298 if (!storage ) {
298299 err = - ENOMEM ;
299300 goto uncharge ;
@@ -350,10 +351,10 @@ int bpf_local_storage_alloc(void *owner,
350351 */
351352struct bpf_local_storage_data *
352353bpf_local_storage_update (void * owner , struct bpf_local_storage_map * smap ,
353- void * value , u64 map_flags )
354+ void * value , u64 map_flags , gfp_t gfp_flags )
354355{
355356 struct bpf_local_storage_data * old_sdata = NULL ;
356- struct bpf_local_storage_elem * selem ;
357+ struct bpf_local_storage_elem * selem = NULL ;
357358 struct bpf_local_storage * local_storage ;
358359 unsigned long flags ;
359360 int err ;
@@ -365,6 +366,9 @@ bpf_local_storage_update(void *owner, struct bpf_local_storage_map *smap,
365366 !map_value_has_spin_lock (& smap -> map )))
366367 return ERR_PTR (- EINVAL );
367368
369+ if (gfp_flags == GFP_KERNEL && (map_flags & ~BPF_F_LOCK ) != BPF_NOEXIST )
370+ return ERR_PTR (- EINVAL );
371+
368372 local_storage = rcu_dereference_check (* owner_storage (smap , owner ),
369373 bpf_rcu_lock_held ());
370374 if (!local_storage || hlist_empty (& local_storage -> list )) {
@@ -373,11 +377,11 @@ bpf_local_storage_update(void *owner, struct bpf_local_storage_map *smap,
373377 if (err )
374378 return ERR_PTR (err );
375379
376- selem = bpf_selem_alloc (smap , owner , value , true);
380+ selem = bpf_selem_alloc (smap , owner , value , true, gfp_flags );
377381 if (!selem )
378382 return ERR_PTR (- ENOMEM );
379383
380- err = bpf_local_storage_alloc (owner , smap , selem );
384+ err = bpf_local_storage_alloc (owner , smap , selem , gfp_flags );
381385 if (err ) {
382386 kfree (selem );
383387 mem_uncharge (smap , owner , smap -> elem_size );
@@ -404,6 +408,12 @@ bpf_local_storage_update(void *owner, struct bpf_local_storage_map *smap,
404408 }
405409 }
406410
411+ if (gfp_flags == GFP_KERNEL ) {
412+ selem = bpf_selem_alloc (smap , owner , value , true, gfp_flags );
413+ if (!selem )
414+ return ERR_PTR (- ENOMEM );
415+ }
416+
407417 raw_spin_lock_irqsave (& local_storage -> lock , flags );
408418
409419 /* Recheck local_storage->list under local_storage->lock */
@@ -429,19 +439,21 @@ bpf_local_storage_update(void *owner, struct bpf_local_storage_map *smap,
429439 goto unlock ;
430440 }
431441
432- /* local_storage->lock is held. Hence, we are sure
433- * we can unlink and uncharge the old_sdata successfully
434- * later. Hence, instead of charging the new selem now
435- * and then uncharge the old selem later (which may cause
436- * a potential but unnecessary charge failure), avoid taking
437- * a charge at all here (the "!old_sdata" check) and the
438- * old_sdata will not be uncharged later during
439- * bpf_selem_unlink_storage_nolock().
440- */
441- selem = bpf_selem_alloc (smap , owner , value , !old_sdata );
442- if (!selem ) {
443- err = - ENOMEM ;
444- goto unlock_err ;
442+ if (gfp_flags != GFP_KERNEL ) {
443+ /* local_storage->lock is held. Hence, we are sure
444+ * we can unlink and uncharge the old_sdata successfully
445+ * later. Hence, instead of charging the new selem now
446+ * and then uncharge the old selem later (which may cause
447+ * a potential but unnecessary charge failure), avoid taking
448+ * a charge at all here (the "!old_sdata" check) and the
449+ * old_sdata will not be uncharged later during
450+ * bpf_selem_unlink_storage_nolock().
451+ */
452+ selem = bpf_selem_alloc (smap , owner , value , !old_sdata , gfp_flags );
453+ if (!selem ) {
454+ err = - ENOMEM ;
455+ goto unlock_err ;
456+ }
445457 }
446458
447459 /* First, link the new selem to the map */
@@ -463,6 +475,10 @@ bpf_local_storage_update(void *owner, struct bpf_local_storage_map *smap,
463475
464476unlock_err :
465477 raw_spin_unlock_irqrestore (& local_storage -> lock , flags );
478+ if (selem ) {
479+ mem_uncharge (smap , owner , smap -> elem_size );
480+ kfree (selem );
481+ }
466482 return ERR_PTR (err );
467483}
468484
0 commit comments