ring_log环形日志-6M缓冲区_proc接口
文章目录
- log_tools.c
- log.c
- spin_lock
- seq_puts
- seq_read
- seq_write
- single_open
- makefile
- test.sh
- 测试:
- 运行./test.sh
- 读取日志
- 插入日志
- echo cat测试
- 参考:
log_tools.c
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>#define MYLOG_PROC_PATH "/proc/mylog"
#define TMP_BUF_SIZE 1024
#define BUF_SIEZ 256
#define PER_LOG_SIZE 128#define LOG_LEVEL_EMERG 1
#define LOG_LEVEL_ALERT 2
#define LOG_LEVEL_CRIT 3
#define LOG_LEVEL_ERR 4
#define LOG_LEVEL_WARNING 5
#define LOG_LEVEL_NOTICE 6
#define LOG_LEVEL_INFO 7
#define LOG_LEVEL_DEBUG 8static FILE *fp;static void print_help(void)
{printf("-H --help 显示帮助\n");printf("-h --help 显示帮助\n");printf("-r --readall 读取日志\n");printf("-i --insert 插入日志\n");printf("-i <log_level> <log_message>\n");
}
void print_log_level(void)
{printf("log level must be range 1 to 8\n");printf("LOG_LEVEL_EMERG 1\n");printf("LOG_LEVEL_ALERT 2\n");printf("LOG_LEVEL_CRIT 3\n");printf("LOG_LEVEL_ERR 4\n");printf("LOG_LEVEL_WARNING 5\n");printf("LOG_LEVEL_NOTICE 6\n");printf("LOG_LEVEL_INFO 7\n");printf("LOG_LEVEL_DEBUG 8\n");
}int insert_log(int argc,char const *argv[])
{const char *log_message = NULL;int log_level = -1;char tmpbuf[TMP_BUF_SIZE] = {0};if(argc != 4) {printf("Usage: %s -i <log_level> <log_message>\n",argv[0]);goto ERROR;}log_level = atoi(argv[2]);if (log_level < 1 || log_level > LOG_LEVEL_DEBUG) {printf("error log_level");goto ERROR;}log_message = argv[3];if(strlen(log_message) > PER_LOG_SIZE){goto ERROR;}fseek(fp,0,SEEK_END);sprintf(tmpbuf,"%d %s\n",log_level,log_message);if(fwrite(tmpbuf,strlen(tmpbuf),1,fp) < 0) {perror("fwrite");}printf("insert %d %s\n",log_level,log_message);ERROR:return 0;
}
int read_all_log(void)
{char buf[BUF_SIEZ] = {0};fseek(fp,0,SEEK_SET);while (fgets(buf, sizeof(buf), fp)) {printf("%s", buf);}return 0;
}int main(int argc, char const *argv[])
{int res = -1;int index = -1;struct option argarr[] = {{"read",0,NULL,'r'},{"insert",1,NULL,'i'},{"help",0,NULL,'h'},{"help",0,NULL,'H'},{NULL, 0, NULL, 0}};if(argc < 2) {print_help();goto ERROR;}fp = fopen("/proc/mylog", "r+");if (!fp) {printf("Failed to open /proc/mylog\n");goto ERROR;}res = getopt_long(argc,(char **)argv,"H:i:h:r",argarr,&index);if(res < 0) {goto ERROR;}switch(res){case 'r':if (fp != NULL) {read_all_log();} else {printf("Failed to open /proc/mylog\n");}break;case 'i':if (optarg) {insert_log(argc,argv);} else {printf("Error: no log message specified\n");print_help();}break;case 'h':print_help();break;case 'H':print_help();print_log_level();break;default:printf("Unknown option: %c\n", optopt);print_help();break;}ERROR:if(fp != NULL) {fclose(fp);fp = NULL;}return 0;
}
log.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/uaccess.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/seq_file.h>#define LOG_PROC_NAME "mylog"
#define LOG_BUF_SIZE (6 * 1024 * 1024)
#define PER_LOG_SIZE 128
#define STR_TIME_LEN 32struct log_entry {struct list_head list;char *msg;size_t len;
};struct log_buffer {struct list_head head;size_t size;size_t used;
};static struct log_buffer buffer;
static spinlock_t log_buf_lock;static ssize_t log_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
{char *msg = NULL;struct log_entry *entry = NULL;size_t msg_pos = 0;size_t len = 0;size_t i = 0;struct timespec ts = {.tv_sec = 0,.tv_nsec = 0};if(count + STR_TIME_LEN > PER_LOG_SIZE) {// count = PER_LOG_SIZE;goto ERROR;}msg = kmalloc(count + STR_TIME_LEN + 1, GFP_KERNEL);if (!msg) {goto ERROR;}memset(msg,0,count + STR_TIME_LEN + 1);ktime_get_ts(&ts);sprintf(msg, "[%ld.%09ld] ", ts.tv_sec, ts.tv_nsec);msg_pos = 0;msg_pos += strlen(msg);if (copy_from_user(msg + msg_pos, buf, count)) {goto COPY_ERROR;}msg[count + STR_TIME_LEN] = '\0';len = 0;len = strlen(msg) + 1;if (buffer.used + len > buffer.size) {i = buffer.used;while(buffer.used > i/2) {entry = list_first_entry(&buffer.head, struct log_entry, list);buffer.used -= entry->len;list_del(&entry->list);kfree(entry->msg);entry->msg = NULL;kfree(entry);entry = NULL;}}entry = NULL;entry = kmalloc(sizeof(struct log_entry), GFP_KERNEL);if (!entry) {goto COPY_ERROR;}entry->msg = msg;entry->len = len;list_add_tail(&entry->list, &buffer.head);buffer.used += len;return count;COPY_ERROR:if(msg != NULL) {kfree(msg);msg = NULL;}
ERROR:return -1;}
static int log_list_show(struct seq_file *m, void *v)
{struct log_entry *entry = NULL;struct log_entry *n = NULL;spin_lock(&log_buf_lock);list_for_each_entry_safe(entry,n,&buffer.head,list) {seq_printf(m, "%s", entry->msg);}spin_unlock(&log_buf_lock);return 0;
}static int log_list_open(struct inode *inode, struct file *file)
{return single_open(file, log_list_show, NULL);
}static const struct file_operations log_fops = {.owner = THIS_MODULE,.open = log_list_open,.read = seq_read,.write = log_write,
};static int __init log_init(void)
{INIT_LIST_HEAD(&buffer.head);buffer.size = LOG_BUF_SIZE;buffer.used = 0;if (!proc_create(LOG_PROC_NAME, 0666, NULL, &log_fops)) {printk(KERN_ERR "Failed to create /proc/%s\n", LOG_PROC_NAME);return -ENOMEM;}spin_lock_init(&log_buf_lock);printk(KERN_INFO "log module loaded\n");return 0;
}static void __exit log_exit(void)
{struct log_entry *entry = NULL;struct list_head *pos = NULL, *next = NULL;list_for_each_safe(pos, next, &buffer.head) {entry = list_entry(pos, struct log_entry, list);list_del(&entry->list);kfree(entry->msg);kfree(entry);}remove_proc_entry(LOG_PROC_NAME, NULL);printk(KERN_INFO "log module unloaded\n");
}module_init(log_init);
module_exit(log_exit);
MODULE_LICENSE("GPL");
spin_lock
spin_lock是Linux内核中的一种自旋锁,用于保护共享资源的访问。与mutex不同,spin_lock在获取锁时并不会进入睡眠状态,而是使用循环不断尝试获取锁,直到获取到锁才会退出循环,因此也称为自旋锁。
spin_lock的使用方法如下:
-
在需要保护的代码段前调用spin_lock函数获取锁。
-
在代码段结束时调用spin_unlock函数释放锁。
seq相关头文件linux/seq_file.h,seq相关函数的实现在fs/seq_file.c。seq函数最早是在2001年就引入了,但以前内核中一直用得不多,而到了2.6内核后,许多/proc的只读文件中大量使用了seq函数处理。
由于procfs的默认操作函数只使用一页的缓存,在处理较大的proc文件时就有点麻烦,并且在输出一系列结构体中的数据时也比较不灵活,需要自己在read_proc函数中实现迭代,容易出现Bug。所以内核黑客们对一些/proc代码做了研究,抽象出共性,最终形成了seq_file(Sequence file:序列文件)接口。 这个接口提供了一套简单的函数来解决以上proc接口编程时存在的问题,使得编程更加容易,降低了Bug出现的机会。
在需要创建一个由一系列数据顺序组合而成的虚拟文件或一个较大的虚拟文件时,推荐使用seq_file接口。但是我个人认为,并不是只有procfs才可以使用这个seq_file接口,因为其实seq_file是实现的是一个操作函数集,这个函数集并不是与proc绑定的,同样可以用在其他的地方。
seq_puts
是Linux内核中的一个函数,用于将字符串写入序列文件的缓冲区。序列文件是用于顺序访问数据流的特殊文件。seq_puts函数接受两个参数:指向序列文件的指针(m)和要写入文件的字符串。
seq_read
是一个Linux内核函数,用于从序列文件中读取数据并将其放入用户空间缓冲区中
seq_write
是一个Linux内核中的函数,它用于将数据写入到顺序访问的设备中
seq_write 是一个辅助函数,用于在 proc 文件系统中创建一个支持顺序写入的文件。它的原型定义如下:
ssize_t seq_write(struct seq_file *, const char *, size_t);
第一个参数是一个指向 seq_file 的指针,第二个参数是一个指向数据缓冲区的指针,第三个参数是数据的长度。
seq_write 函数的返回值是一个 ssize_t 类型的整数,表示写入的字节数。如果返回值小于 0,则表示写入失败。
在创建一个支持顺序写入的 proc 文件时,可以使用 seq_write 函数来向文件中写入数据。通常需要在文件的 write 函数中调用 seq_write 函数来实现写入操作。
single_open
single_open 是一个辅助函数,用于在 proc 文件系统中创建一个仅支持顺序读取的文件。它的原型定义如下:
int single_open(struct file , int ()(struct seq_file *, void *), void *);
第一个参数是一个指向文件的指针,第二个参数是一个回调函数,用于向 seq_file 中写入数据,第三个参数是一个指向私有数据的指针,可用于传递一些上下文信息给回调函数。
single_open 函数的返回值是一个整数,表示函数执行的状态。如果返回值小于 0,则表示创建文件失败,否则表示创建文件成功。
在创建一个支持顺序读取的 proc 文件时,通常可以使用 single_open 函数来创建文件,然后将回调函数和私有数据传递给它。在回调函数中,可以使用 seq_puts、seq_printf 等函数向 seq_file 中写入数据。最后,使用 single_release 函数来释放资源。
makefile
obj-m := log.o # ubuntu16CC=gccLD=ldKDIR := /usr/src/linux-headers-$(shell uname -r)PWD := $(shell pwd)all:$(MAKE) -C $(KDIR) M=$(PWD) modules CC=$(CC) LD=$(LD)clean:$(MAKE) -C $(KDIR) M=$(PWD) clean
test.sh
#!/bin/shsudo makesudo rmmod log.kosudo insmod log.koecho 1 2 > /proc/mylogcat /proc/mylog./test.sh
测试:

运行./test.sh
读取日志

插入日志

echo cat测试

参考:
linux 在 /proc 里实现文件 - 樊伟胜 - 博客园 (cnblogs.com)
https://www.cnblogs.com/fanweisheng/p/11141527.html
linux内核seq_file接口
https://www.cnblogs.com/embedded-linux/p/9751995.html
相关文章:
ring_log环形日志-6M缓冲区_proc接口
文章目录log_tools.clog.cspin_lockseq_putsseq_readseq_writesingle_openmakefiletest.sh测试:运行./test.sh读取日志插入日志echo cat测试参考:log_tools.c #include <stdlib.h> #include <stdio.h> #include <sys/types.h> #includ…...
Linux内核进程管理几种CPU调度策略
CPU调度我们知道,程序需要获得CPU的资源才能被调度和执行,那么当一个进程由于某种原因放弃CPU然后进入阻塞状态,下一个获得CPU资源去被调度执行的进程会是谁呢?下图中,进程1因为阻塞放弃CPU资源,此时&#…...
SpringBoot整合Flink(施耐德PLC物联网信息采集)
SpringBoot整合Flink(施耐德PLC物联网信息采集)Linux环境安装kafka前情:施耐德PLC设备(TM200C16R)设置好信息采集程序,连接局域网,SpringBoot订阅MQTT主题,消息转至kafka,…...
DFS(深度优先搜索)和BFS(宽度优先搜索)
目录 DFS(深度优先搜索) 全排列的DFS解法 利用DFS递归构建二进制串和递归树的结构剖析 DFS--剪枝 DFS例题--整数划分 BFS(宽度优先搜索) 全排列的BFS解法 DFS(深度优先搜索) 深度优先搜索(Depth First Search&…...
Redis缓存穿透、击穿、雪崩问题及解决方法
系列文章目录 Spring Cache的使用–快速上手篇 分页查询–Java项目实战篇 全局异常处理–Java实战项目篇 完善登录功能–过滤器的使用 上述只是部分文章,对该系列文章感兴趣的可以查看我的主页哦 文章目录系列文章目录前言一、缓存穿透1.1 问题引入1.2 解决方法1.…...
HAL库 STM32 串口通信
一、实验条件将STM32的PA9复用为串口1的TX,PA10复用为串口1的RX。STM32芯片的输出TX和接收RX与CH340的接收RX和发送TX相连(收发交叉且PCB上默认没有相连,所以需要用P3跳线帽进行手动连接),CH340的另一端通过USB口引出与…...
2023-第十四届蓝桥杯冲刺计划!
💬前言 💡本文以目录形式列举大纲,可根据题目点击跳转 🌈冲刺阶段目的:把握高频重点,结合基础算法和常考题型总结,用真题进行模拟练习 根据自己的能力熟练目前已掌握的算法,不会的还可以暴力 ⏳最后三个星期大家一起冲…...
内网渗透基础知识
一、内网概述 内网也指局域网,是指在某一区域内又多台计算机互联成的计算机组。一般是方圆几千米内,局域网可以实现文件管理,应用软件共享,打印机共享,工作组内的历程安排,电子邮件和传真通信服务等功能。…...
鸟哥的Linux私房菜 正则表示法与文件格式化处理
第十一章、正则表示法与文件格式化处理 https://linux.vbird.org/linux_basic/centos7/0330regularex.php 简体版 http://cn.linux.vbird.org/linux_basic/0330regularex.php 11.2.2 grep的一些高级选项 例题一、搜索特定字符串 例题二、利用中括号 [] 来搜寻集合字符 例题四…...
1630.等差子数组
1630. 等差子数组 难度中等 如果一个数列由至少两个元素组成,且每两个连续元素之间的差值都相同,那么这个序列就是 等差数列 。更正式地,数列 s 是等差数列,只需要满足:对于每个有效的 i , s[i1] - s[i] …...
CSS 属性计算过程
CSS 属性计算过程 你是否了解 CSS 的属性计算过程呢? 有的同学可能会讲,CSS属性我倒是知道,例如: p{color : red; }上面的 CSS 代码中,p 是元素选择器,color 就是其中的一个 CSS 属性。 但是要说 CSS 属…...
ThinkPHP02:路由
ThinkPHP02:路由一、路由定义二、变量规则三、路由地址四、路由参数五、路由分组六、MISS七、资源路由八、注解路由九、URL生成一、路由定义 路由默认开启,在 config/app.php 中可以关闭路由。 路由配置在 config/route.php 中,路由定义在 r…...
制作简单进销存管理系统(C#)
实验三:制作简单进销存管理系统 任务要求: 在进销存管理系统中,商品的库存信息有很多种类,比如商品型号、商品名称、商品库存量等。在面向对象编程中,这些商品的信息可以存储到属性中,然后当需要使用这些…...
css总结9(过渡和2D变换)
目录 过渡 2D变换 3D变换 过渡 属性结构图 过渡补充 ### 过渡多个元素样式属性 transition:style1 duration , style2 duration,...; ### 过渡所有属性 transition: all duration; 简单示例 ### 移入时改变长度且加入过渡效果 div { width:100px; height:100px; …...
SpringBoot 结合RabbitMQ与Redis实现商品的并发下单【SpringBoot系列12】
SpringCloud 大型系列课程正在制作中,欢迎大家关注与提意见。 程序员每天的CV 与 板砖,也要知其所以然,本系列课程可以帮助初学者学习 SpringBooot 项目开发 与 SpringCloud 微服务系列项目开发 1 项目准备 SpringBoot 整合 RabbitMQ 消息队…...
【python进阶】序列切片还能这么用?切片的强大比你了解的多太多
📚引言 🙋♂️作者简介:生鱼同学,大数据科学与技术专业硕士在读👨🎓,曾获得华为杯数学建模国家二等奖🏆,MathorCup 数学建模竞赛国家二等奖🏅,…...
[数据结构]直接插入排序、希尔排序
文章目录排序的概念和运用排序的概念排序运用常见的排序算法常见的排序算法直接插入排序希尔排序性能对比排序的概念和运用 排序的概念 排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操…...
CNN、LeNet、AlexNet、VGG、GoogLeNet、RCNN、Fast RCNN、Faster RCNN、YOLO、YOLOv2、SSD等的关系
卷积神经网络的现状1943年美国数学家提出人工智能1949年心理学家建立神经元模型1957年弗兰克提出 感知器人工神经网络模型1980年建立多层感知器模型1984日本学者提出卷积神经网络原始模型神经感知机1998年提出LeNet-5卷积神经网络,并发展了其在音符和字符上的优势20…...
IO-day1-(fscanf、fprintf.........)
作业一、有一个usr.txt的文件,其中存储着用户的账户和密码,格式如下:zhangsan aaaalisi bbbbb空格前面是账户,空格后面是密码,一行一个账户、密码要求如下:从终端获取一个账户名和密码判断是否能够登录成功…...
C++类和对象(上篇)
目录 1.类的定义 2.类的访问限定符及封装 2.1类的访问限定符 2.2封装 3.类的作用域 4.类的实例化 5.类的大小 6.this 指针 1.类的定义 class className {// 类体:由成员函数和成员变量组成}; // 一定要注意后面的分号 class为定义类的关键字,Clas…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...
简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...
【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
linux arm系统烧录
1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...
PAN/FPN
import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...
排序算法总结(C++)
目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指:同样大小的样本 **(同样大小的数据)**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...
Mysql8 忘记密码重置,以及问题解决
1.使用免密登录 找到配置MySQL文件,我的文件路径是/etc/mysql/my.cnf,有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...
Elastic 获得 AWS 教育 ISV 合作伙伴资质,进一步增强教育解决方案产品组合
作者:来自 Elastic Udayasimha Theepireddy (Uday), Brian Bergholm, Marianna Jonsdottir 通过搜索 AI 和云创新推动教育领域的数字化转型。 我们非常高兴地宣布,Elastic 已获得 AWS 教育 ISV 合作伙伴资质。这一重要认证表明,Elastic 作为 …...
在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南
在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南 背景介绍完整操作步骤1. 创建Docker容器环境2. 验证GUI显示功能3. 安装ROS Noetic4. 配置环境变量5. 创建ROS节点(小球运动模拟)6. 配置RVIZ默认视图7. 创建启动脚本8. 运行可视化系统效果展示与交互技术解析ROS节点通…...
