Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/net/devlink/region.c
26282 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* Copyright (c) 2016 Mellanox Technologies. All rights reserved.
4
* Copyright (c) 2016 Jiri Pirko <[email protected]>
5
*/
6
7
#include "devl_internal.h"
8
9
struct devlink_region {
10
struct devlink *devlink;
11
struct devlink_port *port;
12
struct list_head list;
13
union {
14
const struct devlink_region_ops *ops;
15
const struct devlink_port_region_ops *port_ops;
16
};
17
struct mutex snapshot_lock; /* protects snapshot_list,
18
* max_snapshots and cur_snapshots
19
* consistency.
20
*/
21
struct list_head snapshot_list;
22
u32 max_snapshots;
23
u32 cur_snapshots;
24
u64 size;
25
};
26
27
struct devlink_snapshot {
28
struct list_head list;
29
struct devlink_region *region;
30
u8 *data;
31
u32 id;
32
};
33
34
static struct devlink_region *
35
devlink_region_get_by_name(struct devlink *devlink, const char *region_name)
36
{
37
struct devlink_region *region;
38
39
list_for_each_entry(region, &devlink->region_list, list)
40
if (!strcmp(region->ops->name, region_name))
41
return region;
42
43
return NULL;
44
}
45
46
static struct devlink_region *
47
devlink_port_region_get_by_name(struct devlink_port *port,
48
const char *region_name)
49
{
50
struct devlink_region *region;
51
52
list_for_each_entry(region, &port->region_list, list)
53
if (!strcmp(region->ops->name, region_name))
54
return region;
55
56
return NULL;
57
}
58
59
static struct devlink_snapshot *
60
devlink_region_snapshot_get_by_id(struct devlink_region *region, u32 id)
61
{
62
struct devlink_snapshot *snapshot;
63
64
list_for_each_entry(snapshot, &region->snapshot_list, list)
65
if (snapshot->id == id)
66
return snapshot;
67
68
return NULL;
69
}
70
71
static int devlink_nl_region_snapshot_id_put(struct sk_buff *msg,
72
struct devlink *devlink,
73
struct devlink_snapshot *snapshot)
74
{
75
struct nlattr *snap_attr;
76
int err;
77
78
snap_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_REGION_SNAPSHOT);
79
if (!snap_attr)
80
return -EMSGSIZE;
81
82
err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID, snapshot->id);
83
if (err)
84
goto nla_put_failure;
85
86
nla_nest_end(msg, snap_attr);
87
return 0;
88
89
nla_put_failure:
90
nla_nest_cancel(msg, snap_attr);
91
return err;
92
}
93
94
static int devlink_nl_region_snapshots_id_put(struct sk_buff *msg,
95
struct devlink *devlink,
96
struct devlink_region *region)
97
{
98
struct devlink_snapshot *snapshot;
99
struct nlattr *snapshots_attr;
100
int err;
101
102
snapshots_attr = nla_nest_start_noflag(msg,
103
DEVLINK_ATTR_REGION_SNAPSHOTS);
104
if (!snapshots_attr)
105
return -EMSGSIZE;
106
107
list_for_each_entry(snapshot, &region->snapshot_list, list) {
108
err = devlink_nl_region_snapshot_id_put(msg, devlink, snapshot);
109
if (err)
110
goto nla_put_failure;
111
}
112
113
nla_nest_end(msg, snapshots_attr);
114
return 0;
115
116
nla_put_failure:
117
nla_nest_cancel(msg, snapshots_attr);
118
return err;
119
}
120
121
static int devlink_nl_region_fill(struct sk_buff *msg, struct devlink *devlink,
122
enum devlink_command cmd, u32 portid,
123
u32 seq, int flags,
124
struct devlink_region *region)
125
{
126
void *hdr;
127
int err;
128
129
hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
130
if (!hdr)
131
return -EMSGSIZE;
132
133
err = devlink_nl_put_handle(msg, devlink);
134
if (err)
135
goto nla_put_failure;
136
137
if (region->port) {
138
err = nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX,
139
region->port->index);
140
if (err)
141
goto nla_put_failure;
142
}
143
144
err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME, region->ops->name);
145
if (err)
146
goto nla_put_failure;
147
148
err = devlink_nl_put_u64(msg, DEVLINK_ATTR_REGION_SIZE, region->size);
149
if (err)
150
goto nla_put_failure;
151
152
err = nla_put_u32(msg, DEVLINK_ATTR_REGION_MAX_SNAPSHOTS,
153
region->max_snapshots);
154
if (err)
155
goto nla_put_failure;
156
157
err = devlink_nl_region_snapshots_id_put(msg, devlink, region);
158
if (err)
159
goto nla_put_failure;
160
161
genlmsg_end(msg, hdr);
162
return 0;
163
164
nla_put_failure:
165
genlmsg_cancel(msg, hdr);
166
return err;
167
}
168
169
static struct sk_buff *
170
devlink_nl_region_notify_build(struct devlink_region *region,
171
struct devlink_snapshot *snapshot,
172
enum devlink_command cmd, u32 portid, u32 seq)
173
{
174
struct devlink *devlink = region->devlink;
175
struct sk_buff *msg;
176
void *hdr;
177
int err;
178
179
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
180
if (!msg)
181
return ERR_PTR(-ENOMEM);
182
183
hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, 0, cmd);
184
if (!hdr) {
185
err = -EMSGSIZE;
186
goto out_free_msg;
187
}
188
189
err = devlink_nl_put_handle(msg, devlink);
190
if (err)
191
goto out_cancel_msg;
192
193
if (region->port) {
194
err = nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX,
195
region->port->index);
196
if (err)
197
goto out_cancel_msg;
198
}
199
200
err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME,
201
region->ops->name);
202
if (err)
203
goto out_cancel_msg;
204
205
if (snapshot) {
206
err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID,
207
snapshot->id);
208
if (err)
209
goto out_cancel_msg;
210
} else {
211
err = devlink_nl_put_u64(msg, DEVLINK_ATTR_REGION_SIZE,
212
region->size);
213
if (err)
214
goto out_cancel_msg;
215
}
216
genlmsg_end(msg, hdr);
217
218
return msg;
219
220
out_cancel_msg:
221
genlmsg_cancel(msg, hdr);
222
out_free_msg:
223
nlmsg_free(msg);
224
return ERR_PTR(err);
225
}
226
227
static void devlink_nl_region_notify(struct devlink_region *region,
228
struct devlink_snapshot *snapshot,
229
enum devlink_command cmd)
230
{
231
struct devlink *devlink = region->devlink;
232
struct sk_buff *msg;
233
234
WARN_ON(cmd != DEVLINK_CMD_REGION_NEW && cmd != DEVLINK_CMD_REGION_DEL);
235
236
if (!__devl_is_registered(devlink) || !devlink_nl_notify_need(devlink))
237
return;
238
239
msg = devlink_nl_region_notify_build(region, snapshot, cmd, 0, 0);
240
if (IS_ERR(msg))
241
return;
242
243
devlink_nl_notify_send(devlink, msg);
244
}
245
246
void devlink_regions_notify_register(struct devlink *devlink)
247
{
248
struct devlink_region *region;
249
250
list_for_each_entry(region, &devlink->region_list, list)
251
devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_NEW);
252
}
253
254
void devlink_regions_notify_unregister(struct devlink *devlink)
255
{
256
struct devlink_region *region;
257
258
list_for_each_entry_reverse(region, &devlink->region_list, list)
259
devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_DEL);
260
}
261
262
/**
263
* __devlink_snapshot_id_increment - Increment number of snapshots using an id
264
* @devlink: devlink instance
265
* @id: the snapshot id
266
*
267
* Track when a new snapshot begins using an id. Load the count for the
268
* given id from the snapshot xarray, increment it, and store it back.
269
*
270
* Called when a new snapshot is created with the given id.
271
*
272
* The id *must* have been previously allocated by
273
* devlink_region_snapshot_id_get().
274
*
275
* Returns 0 on success, or an error on failure.
276
*/
277
static int __devlink_snapshot_id_increment(struct devlink *devlink, u32 id)
278
{
279
unsigned long count;
280
void *p;
281
int err;
282
283
xa_lock(&devlink->snapshot_ids);
284
p = xa_load(&devlink->snapshot_ids, id);
285
if (WARN_ON(!p)) {
286
err = -EINVAL;
287
goto unlock;
288
}
289
290
if (WARN_ON(!xa_is_value(p))) {
291
err = -EINVAL;
292
goto unlock;
293
}
294
295
count = xa_to_value(p);
296
count++;
297
298
err = xa_err(__xa_store(&devlink->snapshot_ids, id, xa_mk_value(count),
299
GFP_ATOMIC));
300
unlock:
301
xa_unlock(&devlink->snapshot_ids);
302
return err;
303
}
304
305
/**
306
* __devlink_snapshot_id_decrement - Decrease number of snapshots using an id
307
* @devlink: devlink instance
308
* @id: the snapshot id
309
*
310
* Track when a snapshot is deleted and stops using an id. Load the count
311
* for the given id from the snapshot xarray, decrement it, and store it
312
* back.
313
*
314
* If the count reaches zero, erase this id from the xarray, freeing it
315
* up for future re-use by devlink_region_snapshot_id_get().
316
*
317
* Called when a snapshot using the given id is deleted, and when the
318
* initial allocator of the id is finished using it.
319
*/
320
static void __devlink_snapshot_id_decrement(struct devlink *devlink, u32 id)
321
{
322
unsigned long count;
323
void *p;
324
325
xa_lock(&devlink->snapshot_ids);
326
p = xa_load(&devlink->snapshot_ids, id);
327
if (WARN_ON(!p))
328
goto unlock;
329
330
if (WARN_ON(!xa_is_value(p)))
331
goto unlock;
332
333
count = xa_to_value(p);
334
335
if (count > 1) {
336
count--;
337
__xa_store(&devlink->snapshot_ids, id, xa_mk_value(count),
338
GFP_ATOMIC);
339
} else {
340
/* If this was the last user, we can erase this id */
341
__xa_erase(&devlink->snapshot_ids, id);
342
}
343
unlock:
344
xa_unlock(&devlink->snapshot_ids);
345
}
346
347
/**
348
* __devlink_snapshot_id_insert - Insert a specific snapshot ID
349
* @devlink: devlink instance
350
* @id: the snapshot id
351
*
352
* Mark the given snapshot id as used by inserting a zero value into the
353
* snapshot xarray.
354
*
355
* This must be called while holding the devlink instance lock. Unlike
356
* devlink_snapshot_id_get, the initial reference count is zero, not one.
357
* It is expected that the id will immediately be used before
358
* releasing the devlink instance lock.
359
*
360
* Returns zero on success, or an error code if the snapshot id could not
361
* be inserted.
362
*/
363
static int __devlink_snapshot_id_insert(struct devlink *devlink, u32 id)
364
{
365
int err;
366
367
xa_lock(&devlink->snapshot_ids);
368
if (xa_load(&devlink->snapshot_ids, id)) {
369
xa_unlock(&devlink->snapshot_ids);
370
return -EEXIST;
371
}
372
err = xa_err(__xa_store(&devlink->snapshot_ids, id, xa_mk_value(0),
373
GFP_ATOMIC));
374
xa_unlock(&devlink->snapshot_ids);
375
return err;
376
}
377
378
/**
379
* __devlink_region_snapshot_id_get - get snapshot ID
380
* @devlink: devlink instance
381
* @id: storage to return snapshot id
382
*
383
* Allocates a new snapshot id. Returns zero on success, or a negative
384
* error on failure. Must be called while holding the devlink instance
385
* lock.
386
*
387
* Snapshot IDs are tracked using an xarray which stores the number of
388
* users of the snapshot id.
389
*
390
* Note that the caller of this function counts as a 'user', in order to
391
* avoid race conditions. The caller must release its hold on the
392
* snapshot by using devlink_region_snapshot_id_put.
393
*/
394
static int __devlink_region_snapshot_id_get(struct devlink *devlink, u32 *id)
395
{
396
return xa_alloc(&devlink->snapshot_ids, id, xa_mk_value(1),
397
xa_limit_32b, GFP_KERNEL);
398
}
399
400
/**
401
* __devlink_region_snapshot_create - create a new snapshot
402
* This will add a new snapshot of a region. The snapshot
403
* will be stored on the region struct and can be accessed
404
* from devlink. This is useful for future analyses of snapshots.
405
* Multiple snapshots can be created on a region.
406
* The @snapshot_id should be obtained using the getter function.
407
*
408
* Must be called only while holding the region snapshot lock.
409
*
410
* @region: devlink region of the snapshot
411
* @data: snapshot data
412
* @snapshot_id: snapshot id to be created
413
*/
414
static int
415
__devlink_region_snapshot_create(struct devlink_region *region,
416
u8 *data, u32 snapshot_id)
417
{
418
struct devlink *devlink = region->devlink;
419
struct devlink_snapshot *snapshot;
420
int err;
421
422
lockdep_assert_held(&region->snapshot_lock);
423
424
/* check if region can hold one more snapshot */
425
if (region->cur_snapshots == region->max_snapshots)
426
return -ENOSPC;
427
428
if (devlink_region_snapshot_get_by_id(region, snapshot_id))
429
return -EEXIST;
430
431
snapshot = kzalloc(sizeof(*snapshot), GFP_KERNEL);
432
if (!snapshot)
433
return -ENOMEM;
434
435
err = __devlink_snapshot_id_increment(devlink, snapshot_id);
436
if (err)
437
goto err_snapshot_id_increment;
438
439
snapshot->id = snapshot_id;
440
snapshot->region = region;
441
snapshot->data = data;
442
443
list_add_tail(&snapshot->list, &region->snapshot_list);
444
445
region->cur_snapshots++;
446
447
devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_NEW);
448
return 0;
449
450
err_snapshot_id_increment:
451
kfree(snapshot);
452
return err;
453
}
454
455
static void devlink_region_snapshot_del(struct devlink_region *region,
456
struct devlink_snapshot *snapshot)
457
{
458
struct devlink *devlink = region->devlink;
459
460
lockdep_assert_held(&region->snapshot_lock);
461
462
devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_DEL);
463
region->cur_snapshots--;
464
list_del(&snapshot->list);
465
region->ops->destructor(snapshot->data);
466
__devlink_snapshot_id_decrement(devlink, snapshot->id);
467
kfree(snapshot);
468
}
469
470
int devlink_nl_region_get_doit(struct sk_buff *skb, struct genl_info *info)
471
{
472
struct devlink *devlink = info->user_ptr[0];
473
struct devlink_port *port = NULL;
474
struct devlink_region *region;
475
const char *region_name;
476
struct sk_buff *msg;
477
unsigned int index;
478
int err;
479
480
if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_REGION_NAME))
481
return -EINVAL;
482
483
if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) {
484
index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
485
486
port = devlink_port_get_by_index(devlink, index);
487
if (!port)
488
return -ENODEV;
489
}
490
491
region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
492
if (port)
493
region = devlink_port_region_get_by_name(port, region_name);
494
else
495
region = devlink_region_get_by_name(devlink, region_name);
496
497
if (!region)
498
return -EINVAL;
499
500
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
501
if (!msg)
502
return -ENOMEM;
503
504
err = devlink_nl_region_fill(msg, devlink, DEVLINK_CMD_REGION_GET,
505
info->snd_portid, info->snd_seq, 0,
506
region);
507
if (err) {
508
nlmsg_free(msg);
509
return err;
510
}
511
512
return genlmsg_reply(msg, info);
513
}
514
515
static int devlink_nl_cmd_region_get_port_dumpit(struct sk_buff *msg,
516
struct netlink_callback *cb,
517
struct devlink_port *port,
518
int *idx, int start, int flags)
519
{
520
struct devlink_region *region;
521
int err = 0;
522
523
list_for_each_entry(region, &port->region_list, list) {
524
if (*idx < start) {
525
(*idx)++;
526
continue;
527
}
528
err = devlink_nl_region_fill(msg, port->devlink,
529
DEVLINK_CMD_REGION_GET,
530
NETLINK_CB(cb->skb).portid,
531
cb->nlh->nlmsg_seq,
532
flags, region);
533
if (err)
534
goto out;
535
(*idx)++;
536
}
537
538
out:
539
return err;
540
}
541
542
static int devlink_nl_region_get_dump_one(struct sk_buff *msg,
543
struct devlink *devlink,
544
struct netlink_callback *cb,
545
int flags)
546
{
547
struct devlink_nl_dump_state *state = devlink_dump_state(cb);
548
struct devlink_region *region;
549
struct devlink_port *port;
550
unsigned long port_index;
551
int idx = 0;
552
int err;
553
554
list_for_each_entry(region, &devlink->region_list, list) {
555
if (idx < state->idx) {
556
idx++;
557
continue;
558
}
559
err = devlink_nl_region_fill(msg, devlink,
560
DEVLINK_CMD_REGION_GET,
561
NETLINK_CB(cb->skb).portid,
562
cb->nlh->nlmsg_seq, flags,
563
region);
564
if (err) {
565
state->idx = idx;
566
return err;
567
}
568
idx++;
569
}
570
571
xa_for_each(&devlink->ports, port_index, port) {
572
err = devlink_nl_cmd_region_get_port_dumpit(msg, cb, port, &idx,
573
state->idx, flags);
574
if (err) {
575
state->idx = idx;
576
return err;
577
}
578
}
579
580
return 0;
581
}
582
583
int devlink_nl_region_get_dumpit(struct sk_buff *skb,
584
struct netlink_callback *cb)
585
{
586
return devlink_nl_dumpit(skb, cb, devlink_nl_region_get_dump_one);
587
}
588
589
int devlink_nl_region_del_doit(struct sk_buff *skb, struct genl_info *info)
590
{
591
struct devlink *devlink = info->user_ptr[0];
592
struct devlink_snapshot *snapshot;
593
struct devlink_port *port = NULL;
594
struct devlink_region *region;
595
const char *region_name;
596
unsigned int index;
597
u32 snapshot_id;
598
599
if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_REGION_NAME) ||
600
GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_REGION_SNAPSHOT_ID))
601
return -EINVAL;
602
603
region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
604
snapshot_id = nla_get_u32(info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
605
606
if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) {
607
index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
608
609
port = devlink_port_get_by_index(devlink, index);
610
if (!port)
611
return -ENODEV;
612
}
613
614
if (port)
615
region = devlink_port_region_get_by_name(port, region_name);
616
else
617
region = devlink_region_get_by_name(devlink, region_name);
618
619
if (!region)
620
return -EINVAL;
621
622
mutex_lock(&region->snapshot_lock);
623
snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
624
if (!snapshot) {
625
mutex_unlock(&region->snapshot_lock);
626
return -EINVAL;
627
}
628
629
devlink_region_snapshot_del(region, snapshot);
630
mutex_unlock(&region->snapshot_lock);
631
return 0;
632
}
633
634
int devlink_nl_region_new_doit(struct sk_buff *skb, struct genl_info *info)
635
{
636
struct devlink *devlink = info->user_ptr[0];
637
struct devlink_snapshot *snapshot;
638
struct devlink_port *port = NULL;
639
struct nlattr *snapshot_id_attr;
640
struct devlink_region *region;
641
const char *region_name;
642
unsigned int index;
643
u32 snapshot_id;
644
u8 *data;
645
int err;
646
647
if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_REGION_NAME)) {
648
NL_SET_ERR_MSG(info->extack, "No region name provided");
649
return -EINVAL;
650
}
651
652
region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
653
654
if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) {
655
index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
656
657
port = devlink_port_get_by_index(devlink, index);
658
if (!port)
659
return -ENODEV;
660
}
661
662
if (port)
663
region = devlink_port_region_get_by_name(port, region_name);
664
else
665
region = devlink_region_get_by_name(devlink, region_name);
666
667
if (!region) {
668
NL_SET_ERR_MSG(info->extack, "The requested region does not exist");
669
return -EINVAL;
670
}
671
672
if (!region->ops->snapshot) {
673
NL_SET_ERR_MSG(info->extack, "The requested region does not support taking an immediate snapshot");
674
return -EOPNOTSUPP;
675
}
676
677
mutex_lock(&region->snapshot_lock);
678
679
if (region->cur_snapshots == region->max_snapshots) {
680
NL_SET_ERR_MSG(info->extack, "The region has reached the maximum number of stored snapshots");
681
err = -ENOSPC;
682
goto unlock;
683
}
684
685
snapshot_id_attr = info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID];
686
if (snapshot_id_attr) {
687
snapshot_id = nla_get_u32(snapshot_id_attr);
688
689
if (devlink_region_snapshot_get_by_id(region, snapshot_id)) {
690
NL_SET_ERR_MSG(info->extack, "The requested snapshot id is already in use");
691
err = -EEXIST;
692
goto unlock;
693
}
694
695
err = __devlink_snapshot_id_insert(devlink, snapshot_id);
696
if (err)
697
goto unlock;
698
} else {
699
err = __devlink_region_snapshot_id_get(devlink, &snapshot_id);
700
if (err) {
701
NL_SET_ERR_MSG(info->extack, "Failed to allocate a new snapshot id");
702
goto unlock;
703
}
704
}
705
706
if (port)
707
err = region->port_ops->snapshot(port, region->port_ops,
708
info->extack, &data);
709
else
710
err = region->ops->snapshot(devlink, region->ops,
711
info->extack, &data);
712
if (err)
713
goto err_snapshot_capture;
714
715
err = __devlink_region_snapshot_create(region, data, snapshot_id);
716
if (err)
717
goto err_snapshot_create;
718
719
if (!snapshot_id_attr) {
720
struct sk_buff *msg;
721
722
snapshot = devlink_region_snapshot_get_by_id(region,
723
snapshot_id);
724
if (WARN_ON(!snapshot)) {
725
err = -EINVAL;
726
goto unlock;
727
}
728
729
msg = devlink_nl_region_notify_build(region, snapshot,
730
DEVLINK_CMD_REGION_NEW,
731
info->snd_portid,
732
info->snd_seq);
733
err = PTR_ERR_OR_ZERO(msg);
734
if (err)
735
goto err_notify;
736
737
err = genlmsg_reply(msg, info);
738
if (err)
739
goto err_notify;
740
}
741
742
mutex_unlock(&region->snapshot_lock);
743
return 0;
744
745
err_snapshot_create:
746
region->ops->destructor(data);
747
err_snapshot_capture:
748
__devlink_snapshot_id_decrement(devlink, snapshot_id);
749
mutex_unlock(&region->snapshot_lock);
750
return err;
751
752
err_notify:
753
devlink_region_snapshot_del(region, snapshot);
754
unlock:
755
mutex_unlock(&region->snapshot_lock);
756
return err;
757
}
758
759
static int devlink_nl_cmd_region_read_chunk_fill(struct sk_buff *msg,
760
u8 *chunk, u32 chunk_size,
761
u64 addr)
762
{
763
struct nlattr *chunk_attr;
764
int err;
765
766
chunk_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_REGION_CHUNK);
767
if (!chunk_attr)
768
return -EINVAL;
769
770
err = nla_put(msg, DEVLINK_ATTR_REGION_CHUNK_DATA, chunk_size, chunk);
771
if (err)
772
goto nla_put_failure;
773
774
err = devlink_nl_put_u64(msg, DEVLINK_ATTR_REGION_CHUNK_ADDR, addr);
775
if (err)
776
goto nla_put_failure;
777
778
nla_nest_end(msg, chunk_attr);
779
return 0;
780
781
nla_put_failure:
782
nla_nest_cancel(msg, chunk_attr);
783
return err;
784
}
785
786
#define DEVLINK_REGION_READ_CHUNK_SIZE 256
787
788
typedef int devlink_chunk_fill_t(void *cb_priv, u8 *chunk, u32 chunk_size,
789
u64 curr_offset,
790
struct netlink_ext_ack *extack);
791
792
static int
793
devlink_nl_region_read_fill(struct sk_buff *skb, devlink_chunk_fill_t *cb,
794
void *cb_priv, u64 start_offset, u64 end_offset,
795
u64 *new_offset, struct netlink_ext_ack *extack)
796
{
797
u64 curr_offset = start_offset;
798
int err = 0;
799
u8 *data;
800
801
/* Allocate and re-use a single buffer */
802
data = kmalloc(DEVLINK_REGION_READ_CHUNK_SIZE, GFP_KERNEL);
803
if (!data)
804
return -ENOMEM;
805
806
*new_offset = start_offset;
807
808
while (curr_offset < end_offset) {
809
u32 data_size;
810
811
data_size = min_t(u32, end_offset - curr_offset,
812
DEVLINK_REGION_READ_CHUNK_SIZE);
813
814
err = cb(cb_priv, data, data_size, curr_offset, extack);
815
if (err)
816
break;
817
818
err = devlink_nl_cmd_region_read_chunk_fill(skb, data, data_size, curr_offset);
819
if (err)
820
break;
821
822
curr_offset += data_size;
823
}
824
*new_offset = curr_offset;
825
826
kfree(data);
827
828
return err;
829
}
830
831
static int
832
devlink_region_snapshot_fill(void *cb_priv, u8 *chunk, u32 chunk_size,
833
u64 curr_offset,
834
struct netlink_ext_ack __always_unused *extack)
835
{
836
struct devlink_snapshot *snapshot = cb_priv;
837
838
memcpy(chunk, &snapshot->data[curr_offset], chunk_size);
839
840
return 0;
841
}
842
843
static int
844
devlink_region_port_direct_fill(void *cb_priv, u8 *chunk, u32 chunk_size,
845
u64 curr_offset, struct netlink_ext_ack *extack)
846
{
847
struct devlink_region *region = cb_priv;
848
849
return region->port_ops->read(region->port, region->port_ops, extack,
850
curr_offset, chunk_size, chunk);
851
}
852
853
static int
854
devlink_region_direct_fill(void *cb_priv, u8 *chunk, u32 chunk_size,
855
u64 curr_offset, struct netlink_ext_ack *extack)
856
{
857
struct devlink_region *region = cb_priv;
858
859
return region->ops->read(region->devlink, region->ops, extack,
860
curr_offset, chunk_size, chunk);
861
}
862
863
int devlink_nl_region_read_dumpit(struct sk_buff *skb,
864
struct netlink_callback *cb)
865
{
866
const struct genl_dumpit_info *info = genl_dumpit_info(cb);
867
struct devlink_nl_dump_state *state = devlink_dump_state(cb);
868
struct nlattr *chunks_attr, *region_attr, *snapshot_attr;
869
u64 ret_offset, start_offset, end_offset = U64_MAX;
870
struct nlattr **attrs = info->info.attrs;
871
struct devlink_port *port = NULL;
872
devlink_chunk_fill_t *region_cb;
873
struct devlink_region *region;
874
const char *region_name;
875
struct devlink *devlink;
876
unsigned int index;
877
void *region_cb_priv;
878
void *hdr;
879
int err;
880
881
start_offset = state->start_offset;
882
883
devlink = devlink_get_from_attrs_lock(sock_net(cb->skb->sk), attrs,
884
false);
885
if (IS_ERR(devlink))
886
return PTR_ERR(devlink);
887
888
if (!attrs[DEVLINK_ATTR_REGION_NAME]) {
889
NL_SET_ERR_MSG(cb->extack, "No region name provided");
890
err = -EINVAL;
891
goto out_unlock;
892
}
893
894
if (attrs[DEVLINK_ATTR_PORT_INDEX]) {
895
index = nla_get_u32(attrs[DEVLINK_ATTR_PORT_INDEX]);
896
897
port = devlink_port_get_by_index(devlink, index);
898
if (!port) {
899
err = -ENODEV;
900
goto out_unlock;
901
}
902
}
903
904
region_attr = attrs[DEVLINK_ATTR_REGION_NAME];
905
region_name = nla_data(region_attr);
906
907
if (port)
908
region = devlink_port_region_get_by_name(port, region_name);
909
else
910
region = devlink_region_get_by_name(devlink, region_name);
911
912
if (!region) {
913
NL_SET_ERR_MSG_ATTR(cb->extack, region_attr, "Requested region does not exist");
914
err = -EINVAL;
915
goto out_unlock;
916
}
917
918
snapshot_attr = attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID];
919
if (!snapshot_attr) {
920
if (!nla_get_flag(attrs[DEVLINK_ATTR_REGION_DIRECT])) {
921
NL_SET_ERR_MSG(cb->extack, "No snapshot id provided");
922
err = -EINVAL;
923
goto out_unlock;
924
}
925
926
if (!region->ops->read) {
927
NL_SET_ERR_MSG(cb->extack, "Requested region does not support direct read");
928
err = -EOPNOTSUPP;
929
goto out_unlock;
930
}
931
932
if (port)
933
region_cb = &devlink_region_port_direct_fill;
934
else
935
region_cb = &devlink_region_direct_fill;
936
region_cb_priv = region;
937
} else {
938
struct devlink_snapshot *snapshot;
939
u32 snapshot_id;
940
941
if (nla_get_flag(attrs[DEVLINK_ATTR_REGION_DIRECT])) {
942
NL_SET_ERR_MSG_ATTR(cb->extack, snapshot_attr, "Direct region read does not use snapshot");
943
err = -EINVAL;
944
goto out_unlock;
945
}
946
947
snapshot_id = nla_get_u32(snapshot_attr);
948
snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
949
if (!snapshot) {
950
NL_SET_ERR_MSG_ATTR(cb->extack, snapshot_attr, "Requested snapshot does not exist");
951
err = -EINVAL;
952
goto out_unlock;
953
}
954
region_cb = &devlink_region_snapshot_fill;
955
region_cb_priv = snapshot;
956
}
957
958
if (attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR] &&
959
attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]) {
960
if (!start_offset)
961
start_offset =
962
nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
963
964
end_offset = nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
965
end_offset += nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]);
966
}
967
968
if (end_offset > region->size)
969
end_offset = region->size;
970
971
/* return 0 if there is no further data to read */
972
if (start_offset == end_offset) {
973
err = 0;
974
goto out_unlock;
975
}
976
977
hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
978
&devlink_nl_family, NLM_F_ACK | NLM_F_MULTI,
979
DEVLINK_CMD_REGION_READ);
980
if (!hdr) {
981
err = -EMSGSIZE;
982
goto out_unlock;
983
}
984
985
err = devlink_nl_put_handle(skb, devlink);
986
if (err)
987
goto nla_put_failure;
988
989
if (region->port) {
990
err = nla_put_u32(skb, DEVLINK_ATTR_PORT_INDEX,
991
region->port->index);
992
if (err)
993
goto nla_put_failure;
994
}
995
996
err = nla_put_string(skb, DEVLINK_ATTR_REGION_NAME, region_name);
997
if (err)
998
goto nla_put_failure;
999
1000
chunks_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_REGION_CHUNKS);
1001
if (!chunks_attr) {
1002
err = -EMSGSIZE;
1003
goto nla_put_failure;
1004
}
1005
1006
err = devlink_nl_region_read_fill(skb, region_cb, region_cb_priv,
1007
start_offset, end_offset, &ret_offset,
1008
cb->extack);
1009
1010
if (err && err != -EMSGSIZE)
1011
goto nla_put_failure;
1012
1013
/* Check if there was any progress done to prevent infinite loop */
1014
if (ret_offset == start_offset) {
1015
err = -EINVAL;
1016
goto nla_put_failure;
1017
}
1018
1019
state->start_offset = ret_offset;
1020
1021
nla_nest_end(skb, chunks_attr);
1022
genlmsg_end(skb, hdr);
1023
devl_unlock(devlink);
1024
devlink_put(devlink);
1025
return skb->len;
1026
1027
nla_put_failure:
1028
genlmsg_cancel(skb, hdr);
1029
out_unlock:
1030
devl_unlock(devlink);
1031
devlink_put(devlink);
1032
return err;
1033
}
1034
1035
/**
1036
* devl_region_create - create a new address region
1037
*
1038
* @devlink: devlink
1039
* @ops: region operations and name
1040
* @region_max_snapshots: Maximum supported number of snapshots for region
1041
* @region_size: size of region
1042
*/
1043
struct devlink_region *devl_region_create(struct devlink *devlink,
1044
const struct devlink_region_ops *ops,
1045
u32 region_max_snapshots,
1046
u64 region_size)
1047
{
1048
struct devlink_region *region;
1049
1050
devl_assert_locked(devlink);
1051
1052
if (WARN_ON(!ops) || WARN_ON(!ops->destructor))
1053
return ERR_PTR(-EINVAL);
1054
1055
if (devlink_region_get_by_name(devlink, ops->name))
1056
return ERR_PTR(-EEXIST);
1057
1058
region = kzalloc(sizeof(*region), GFP_KERNEL);
1059
if (!region)
1060
return ERR_PTR(-ENOMEM);
1061
1062
region->devlink = devlink;
1063
region->max_snapshots = region_max_snapshots;
1064
region->ops = ops;
1065
region->size = region_size;
1066
INIT_LIST_HEAD(&region->snapshot_list);
1067
mutex_init(&region->snapshot_lock);
1068
list_add_tail(&region->list, &devlink->region_list);
1069
devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_NEW);
1070
1071
return region;
1072
}
1073
EXPORT_SYMBOL_GPL(devl_region_create);
1074
1075
/**
1076
* devlink_region_create - create a new address region
1077
*
1078
* @devlink: devlink
1079
* @ops: region operations and name
1080
* @region_max_snapshots: Maximum supported number of snapshots for region
1081
* @region_size: size of region
1082
*
1083
* Context: Takes and release devlink->lock <mutex>.
1084
*/
1085
struct devlink_region *
1086
devlink_region_create(struct devlink *devlink,
1087
const struct devlink_region_ops *ops,
1088
u32 region_max_snapshots, u64 region_size)
1089
{
1090
struct devlink_region *region;
1091
1092
devl_lock(devlink);
1093
region = devl_region_create(devlink, ops, region_max_snapshots,
1094
region_size);
1095
devl_unlock(devlink);
1096
return region;
1097
}
1098
EXPORT_SYMBOL_GPL(devlink_region_create);
1099
1100
/**
1101
* devlink_port_region_create - create a new address region for a port
1102
*
1103
* @port: devlink port
1104
* @ops: region operations and name
1105
* @region_max_snapshots: Maximum supported number of snapshots for region
1106
* @region_size: size of region
1107
*
1108
* Context: Takes and release devlink->lock <mutex>.
1109
*/
1110
struct devlink_region *
1111
devlink_port_region_create(struct devlink_port *port,
1112
const struct devlink_port_region_ops *ops,
1113
u32 region_max_snapshots, u64 region_size)
1114
{
1115
struct devlink *devlink = port->devlink;
1116
struct devlink_region *region;
1117
int err = 0;
1118
1119
ASSERT_DEVLINK_PORT_INITIALIZED(port);
1120
1121
if (WARN_ON(!ops) || WARN_ON(!ops->destructor))
1122
return ERR_PTR(-EINVAL);
1123
1124
devl_lock(devlink);
1125
1126
if (devlink_port_region_get_by_name(port, ops->name)) {
1127
err = -EEXIST;
1128
goto unlock;
1129
}
1130
1131
region = kzalloc(sizeof(*region), GFP_KERNEL);
1132
if (!region) {
1133
err = -ENOMEM;
1134
goto unlock;
1135
}
1136
1137
region->devlink = devlink;
1138
region->port = port;
1139
region->max_snapshots = region_max_snapshots;
1140
region->port_ops = ops;
1141
region->size = region_size;
1142
INIT_LIST_HEAD(&region->snapshot_list);
1143
mutex_init(&region->snapshot_lock);
1144
list_add_tail(&region->list, &port->region_list);
1145
devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_NEW);
1146
1147
devl_unlock(devlink);
1148
return region;
1149
1150
unlock:
1151
devl_unlock(devlink);
1152
return ERR_PTR(err);
1153
}
1154
EXPORT_SYMBOL_GPL(devlink_port_region_create);
1155
1156
/**
1157
* devl_region_destroy - destroy address region
1158
*
1159
* @region: devlink region to destroy
1160
*/
1161
void devl_region_destroy(struct devlink_region *region)
1162
{
1163
struct devlink *devlink = region->devlink;
1164
struct devlink_snapshot *snapshot, *ts;
1165
1166
devl_assert_locked(devlink);
1167
1168
/* Free all snapshots of region */
1169
mutex_lock(&region->snapshot_lock);
1170
list_for_each_entry_safe(snapshot, ts, &region->snapshot_list, list)
1171
devlink_region_snapshot_del(region, snapshot);
1172
mutex_unlock(&region->snapshot_lock);
1173
1174
list_del(&region->list);
1175
mutex_destroy(&region->snapshot_lock);
1176
1177
devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_DEL);
1178
kfree(region);
1179
}
1180
EXPORT_SYMBOL_GPL(devl_region_destroy);
1181
1182
/**
1183
* devlink_region_destroy - destroy address region
1184
*
1185
* @region: devlink region to destroy
1186
*
1187
* Context: Takes and release devlink->lock <mutex>.
1188
*/
1189
void devlink_region_destroy(struct devlink_region *region)
1190
{
1191
struct devlink *devlink = region->devlink;
1192
1193
devl_lock(devlink);
1194
devl_region_destroy(region);
1195
devl_unlock(devlink);
1196
}
1197
EXPORT_SYMBOL_GPL(devlink_region_destroy);
1198
1199
/**
1200
* devlink_region_snapshot_id_get - get snapshot ID
1201
*
1202
* This callback should be called when adding a new snapshot,
1203
* Driver should use the same id for multiple snapshots taken
1204
* on multiple regions at the same time/by the same trigger.
1205
*
1206
* The caller of this function must use devlink_region_snapshot_id_put
1207
* when finished creating regions using this id.
1208
*
1209
* Returns zero on success, or a negative error code on failure.
1210
*
1211
* @devlink: devlink
1212
* @id: storage to return id
1213
*/
1214
int devlink_region_snapshot_id_get(struct devlink *devlink, u32 *id)
1215
{
1216
return __devlink_region_snapshot_id_get(devlink, id);
1217
}
1218
EXPORT_SYMBOL_GPL(devlink_region_snapshot_id_get);
1219
1220
/**
1221
* devlink_region_snapshot_id_put - put snapshot ID reference
1222
*
1223
* This should be called by a driver after finishing creating snapshots
1224
* with an id. Doing so ensures that the ID can later be released in the
1225
* event that all snapshots using it have been destroyed.
1226
*
1227
* @devlink: devlink
1228
* @id: id to release reference on
1229
*/
1230
void devlink_region_snapshot_id_put(struct devlink *devlink, u32 id)
1231
{
1232
__devlink_snapshot_id_decrement(devlink, id);
1233
}
1234
EXPORT_SYMBOL_GPL(devlink_region_snapshot_id_put);
1235
1236
/**
1237
* devlink_region_snapshot_create - create a new snapshot
1238
* This will add a new snapshot of a region. The snapshot
1239
* will be stored on the region struct and can be accessed
1240
* from devlink. This is useful for future analyses of snapshots.
1241
* Multiple snapshots can be created on a region.
1242
* The @snapshot_id should be obtained using the getter function.
1243
*
1244
* @region: devlink region of the snapshot
1245
* @data: snapshot data
1246
* @snapshot_id: snapshot id to be created
1247
*/
1248
int devlink_region_snapshot_create(struct devlink_region *region,
1249
u8 *data, u32 snapshot_id)
1250
{
1251
int err;
1252
1253
mutex_lock(&region->snapshot_lock);
1254
err = __devlink_region_snapshot_create(region, data, snapshot_id);
1255
mutex_unlock(&region->snapshot_lock);
1256
return err;
1257
}
1258
EXPORT_SYMBOL_GPL(devlink_region_snapshot_create);
1259
1260