Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 
0003 #include <linux/ptrace.h>
0004 #include <stddef.h>
0005 #include <linux/bpf.h>
0006 #include <bpf/bpf_helpers.h>
0007 #include <bpf/bpf_tracing.h>
0008 
0009 char _license[] SEC("license") = "GPL";
0010 
0011 /* typically virtio scsi has max SGs of 6 */
0012 #define VIRTIO_MAX_SGS  6
0013 
0014 /* Verifier will fail with SG_MAX = 128. The failure can be
0015  * workarounded with a smaller SG_MAX, e.g. 10.
0016  */
0017 #define WORKAROUND
0018 #ifdef WORKAROUND
0019 #define SG_MAX      10
0020 #else
0021 /* typically virtio blk has max SEG of 128 */
0022 #define SG_MAX      128
0023 #endif
0024 
0025 #define SG_CHAIN    0x01UL
0026 #define SG_END      0x02UL
0027 
0028 struct scatterlist {
0029     unsigned long   page_link;
0030     unsigned int    offset;
0031     unsigned int    length;
0032 };
0033 
0034 #define sg_is_chain(sg)     ((sg)->page_link & SG_CHAIN)
0035 #define sg_is_last(sg)      ((sg)->page_link & SG_END)
0036 #define sg_chain_ptr(sg)    \
0037     ((struct scatterlist *) ((sg)->page_link & ~(SG_CHAIN | SG_END)))
0038 
0039 static inline struct scatterlist *__sg_next(struct scatterlist *sgp)
0040 {
0041     struct scatterlist sg;
0042 
0043     bpf_probe_read_kernel(&sg, sizeof(sg), sgp);
0044     if (sg_is_last(&sg))
0045         return NULL;
0046 
0047     sgp++;
0048 
0049     bpf_probe_read_kernel(&sg, sizeof(sg), sgp);
0050     if (sg_is_chain(&sg))
0051         sgp = sg_chain_ptr(&sg);
0052 
0053     return sgp;
0054 }
0055 
0056 static inline struct scatterlist *get_sgp(struct scatterlist **sgs, int i)
0057 {
0058     struct scatterlist *sgp;
0059 
0060     bpf_probe_read_kernel(&sgp, sizeof(sgp), sgs + i);
0061     return sgp;
0062 }
0063 
0064 int config = 0;
0065 int result = 0;
0066 
0067 SEC("kprobe/virtqueue_add_sgs")
0068 int BPF_KPROBE(trace_virtqueue_add_sgs, void *unused, struct scatterlist **sgs,
0069            unsigned int out_sgs, unsigned int in_sgs)
0070 {
0071     struct scatterlist *sgp = NULL;
0072     __u64 length1 = 0, length2 = 0;
0073     unsigned int i, n, len;
0074 
0075     if (config != 0)
0076         return 0;
0077 
0078     for (i = 0; (i < VIRTIO_MAX_SGS) && (i < out_sgs); i++) {
0079         for (n = 0, sgp = get_sgp(sgs, i); sgp && (n < SG_MAX);
0080              sgp = __sg_next(sgp)) {
0081             bpf_probe_read_kernel(&len, sizeof(len), &sgp->length);
0082             length1 += len;
0083             n++;
0084         }
0085     }
0086 
0087     for (i = 0; (i < VIRTIO_MAX_SGS) && (i < in_sgs); i++) {
0088         for (n = 0, sgp = get_sgp(sgs, i); sgp && (n < SG_MAX);
0089              sgp = __sg_next(sgp)) {
0090             bpf_probe_read_kernel(&len, sizeof(len), &sgp->length);
0091             length2 += len;
0092             n++;
0093         }
0094     }
0095 
0096     config = 1;
0097     result = length2 - length1;
0098     return 0;
0099 }