@@ -3388,6 +3388,181 @@ static int devlink_nl_cmd_region_del(struct sk_buff *skb,
3388
3388
return 0 ;
3389
3389
}
3390
3390
3391
+ static int devlink_nl_cmd_region_read_chunk_fill (struct sk_buff * msg ,
3392
+ struct devlink * devlink ,
3393
+ u8 * chunk , u32 chunk_size ,
3394
+ u64 addr )
3395
+ {
3396
+ struct nlattr * chunk_attr ;
3397
+ int err ;
3398
+
3399
+ chunk_attr = nla_nest_start (msg , DEVLINK_ATTR_REGION_CHUNK );
3400
+ if (!chunk_attr )
3401
+ return - EINVAL ;
3402
+
3403
+ err = nla_put (msg , DEVLINK_ATTR_REGION_CHUNK_DATA , chunk_size , chunk );
3404
+ if (err )
3405
+ goto nla_put_failure ;
3406
+
3407
+ err = nla_put_u64_64bit (msg , DEVLINK_ATTR_REGION_CHUNK_ADDR , addr ,
3408
+ DEVLINK_ATTR_PAD );
3409
+ if (err )
3410
+ goto nla_put_failure ;
3411
+
3412
+ nla_nest_end (msg , chunk_attr );
3413
+ return 0 ;
3414
+
3415
+ nla_put_failure :
3416
+ nla_nest_cancel (msg , chunk_attr );
3417
+ return err ;
3418
+ }
3419
+
3420
+ #define DEVLINK_REGION_READ_CHUNK_SIZE 256
3421
+
3422
+ static int devlink_nl_region_read_snapshot_fill (struct sk_buff * skb ,
3423
+ struct devlink * devlink ,
3424
+ struct devlink_region * region ,
3425
+ struct nlattr * * attrs ,
3426
+ u64 start_offset ,
3427
+ u64 end_offset ,
3428
+ bool dump ,
3429
+ u64 * new_offset )
3430
+ {
3431
+ struct devlink_snapshot * snapshot ;
3432
+ u64 curr_offset = start_offset ;
3433
+ u32 snapshot_id ;
3434
+ int err = 0 ;
3435
+
3436
+ * new_offset = start_offset ;
3437
+
3438
+ snapshot_id = nla_get_u32 (attrs [DEVLINK_ATTR_REGION_SNAPSHOT_ID ]);
3439
+ snapshot = devlink_region_snapshot_get_by_id (region , snapshot_id );
3440
+ if (!snapshot )
3441
+ return - EINVAL ;
3442
+
3443
+ if (end_offset > snapshot -> data_len || dump )
3444
+ end_offset = snapshot -> data_len ;
3445
+
3446
+ while (curr_offset < end_offset ) {
3447
+ u32 data_size ;
3448
+ u8 * data ;
3449
+
3450
+ if (end_offset - curr_offset < DEVLINK_REGION_READ_CHUNK_SIZE )
3451
+ data_size = end_offset - curr_offset ;
3452
+ else
3453
+ data_size = DEVLINK_REGION_READ_CHUNK_SIZE ;
3454
+
3455
+ data = & snapshot -> data [curr_offset ];
3456
+ err = devlink_nl_cmd_region_read_chunk_fill (skb , devlink ,
3457
+ data , data_size ,
3458
+ curr_offset );
3459
+ if (err )
3460
+ break ;
3461
+
3462
+ curr_offset += data_size ;
3463
+ }
3464
+ * new_offset = curr_offset ;
3465
+
3466
+ return err ;
3467
+ }
3468
+
3469
+ static int devlink_nl_cmd_region_read_dumpit (struct sk_buff * skb ,
3470
+ struct netlink_callback * cb )
3471
+ {
3472
+ u64 ret_offset , start_offset , end_offset = 0 ;
3473
+ struct nlattr * attrs [DEVLINK_ATTR_MAX + 1 ];
3474
+ const struct genl_ops * ops = cb -> data ;
3475
+ struct devlink_region * region ;
3476
+ struct nlattr * chunks_attr ;
3477
+ const char * region_name ;
3478
+ struct devlink * devlink ;
3479
+ bool dump = true;
3480
+ void * hdr ;
3481
+ int err ;
3482
+
3483
+ start_offset = * ((u64 * )& cb -> args [0 ]);
3484
+
3485
+ err = nlmsg_parse (cb -> nlh , GENL_HDRLEN + devlink_nl_family .hdrsize ,
3486
+ attrs , DEVLINK_ATTR_MAX , ops -> policy , NULL );
3487
+ if (err )
3488
+ goto out ;
3489
+
3490
+ devlink = devlink_get_from_attrs (sock_net (cb -> skb -> sk ), attrs );
3491
+ if (IS_ERR (devlink ))
3492
+ goto out ;
3493
+
3494
+ mutex_lock (& devlink_mutex );
3495
+ mutex_lock (& devlink -> lock );
3496
+
3497
+ if (!attrs [DEVLINK_ATTR_REGION_NAME ] ||
3498
+ !attrs [DEVLINK_ATTR_REGION_SNAPSHOT_ID ])
3499
+ goto out_unlock ;
3500
+
3501
+ region_name = nla_data (attrs [DEVLINK_ATTR_REGION_NAME ]);
3502
+ region = devlink_region_get_by_name (devlink , region_name );
3503
+ if (!region )
3504
+ goto out_unlock ;
3505
+
3506
+ hdr = genlmsg_put (skb , NETLINK_CB (cb -> skb ).portid , cb -> nlh -> nlmsg_seq ,
3507
+ & devlink_nl_family , NLM_F_ACK | NLM_F_MULTI ,
3508
+ DEVLINK_CMD_REGION_READ );
3509
+ if (!hdr )
3510
+ goto out_unlock ;
3511
+
3512
+ err = devlink_nl_put_handle (skb , devlink );
3513
+ if (err )
3514
+ goto nla_put_failure ;
3515
+
3516
+ err = nla_put_string (skb , DEVLINK_ATTR_REGION_NAME , region_name );
3517
+ if (err )
3518
+ goto nla_put_failure ;
3519
+
3520
+ chunks_attr = nla_nest_start (skb , DEVLINK_ATTR_REGION_CHUNKS );
3521
+ if (!chunks_attr )
3522
+ goto nla_put_failure ;
3523
+
3524
+ if (attrs [DEVLINK_ATTR_REGION_CHUNK_ADDR ] &&
3525
+ attrs [DEVLINK_ATTR_REGION_CHUNK_LEN ]) {
3526
+ if (!start_offset )
3527
+ start_offset =
3528
+ nla_get_u64 (attrs [DEVLINK_ATTR_REGION_CHUNK_ADDR ]);
3529
+
3530
+ end_offset = nla_get_u64 (attrs [DEVLINK_ATTR_REGION_CHUNK_ADDR ]);
3531
+ end_offset += nla_get_u64 (attrs [DEVLINK_ATTR_REGION_CHUNK_LEN ]);
3532
+ dump = false;
3533
+ }
3534
+
3535
+ err = devlink_nl_region_read_snapshot_fill (skb , devlink ,
3536
+ region , attrs ,
3537
+ start_offset ,
3538
+ end_offset , dump ,
3539
+ & ret_offset );
3540
+
3541
+ if (err && err != - EMSGSIZE )
3542
+ goto nla_put_failure ;
3543
+
3544
+ /* Check if there was any progress done to prevent infinite loop */
3545
+ if (ret_offset == start_offset )
3546
+ goto nla_put_failure ;
3547
+
3548
+ * ((u64 * )& cb -> args [0 ]) = ret_offset ;
3549
+
3550
+ nla_nest_end (skb , chunks_attr );
3551
+ genlmsg_end (skb , hdr );
3552
+ mutex_unlock (& devlink -> lock );
3553
+ mutex_unlock (& devlink_mutex );
3554
+
3555
+ return skb -> len ;
3556
+
3557
+ nla_put_failure :
3558
+ genlmsg_cancel (skb , hdr );
3559
+ out_unlock :
3560
+ mutex_unlock (& devlink -> lock );
3561
+ mutex_unlock (& devlink_mutex );
3562
+ out :
3563
+ return 0 ;
3564
+ }
3565
+
3391
3566
static const struct nla_policy devlink_nl_policy [DEVLINK_ATTR_MAX + 1 ] = {
3392
3567
[DEVLINK_ATTR_BUS_NAME ] = { .type = NLA_NUL_STRING },
3393
3568
[DEVLINK_ATTR_DEV_NAME ] = { .type = NLA_NUL_STRING },
@@ -3626,6 +3801,13 @@ static const struct genl_ops devlink_nl_ops[] = {
3626
3801
.flags = GENL_ADMIN_PERM ,
3627
3802
.internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK ,
3628
3803
},
3804
+ {
3805
+ .cmd = DEVLINK_CMD_REGION_READ ,
3806
+ .dumpit = devlink_nl_cmd_region_read_dumpit ,
3807
+ .policy = devlink_nl_policy ,
3808
+ .flags = GENL_ADMIN_PERM ,
3809
+ .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK ,
3810
+ },
3629
3811
};
3630
3812
3631
3813
static struct genl_family devlink_nl_family __ro_after_init = {
0 commit comments