Linux kernel 将buf保存到文件

 old_fs = get_fs();
    set_fs(get_ds());
   
    filp->f_op->write(filp, buff, strlen(buff), &filp->f_pos);
   
    filp->f_op->llseek(filp,0,0);
    ret = filp->f_op->read(filp, tmp, strlen(buff), &filp->f_pos);
   
    set_fs(old_fs);

要注意filp->f_op->write 可能为空
一般用以下方法将buf保存到文件


old_fs = get_fs();
     set_fs(KERNEL_DS);
 
 
     if( first_flag==0){
     first_flag=1;
     /* open file to write */
     fp = filp_open("/data/at_log1", O_WRONLY|O_CREAT, 0640);
     if (!fp) {
         printk("%s: open file error\n", __FUNCTION__);
         ret = -1;
         goto exit;
         }
     }
     pos=(unsigned long)offset;
 
     /* Write buf to file */
     nwrite=vfs_write(fp, buf, size, &pos);

访问文件系统主要用到以下函数。
1 打开文件,与c库类似
strcut file* filp_open(const char* filename, int open_mode, int mode);
2 读写。pos为偏移,需要初始化。更需要注意的是buffer是__user* ,指用户空间地址, 如果我们直接使用内核空间的指针,则会返回-EFALUT。则需要多做一步修改内核地址检查的操作。
ssize_t vfs_read(struct file* filp, char __user* buffer, size_t len, loff_t* pos);
ssize_t vfs_write(struct file* filp, const char __user* buffer, size_t len, loff_t* pos);
get_fs()、set_fs() 的作用
内存地址检查的处理方式。这点补充有关内核地址和用户空间地址的操作。在mm_segment_t fs中只有两个值,USER_DS,KERNEL_DS,分别代表用户空间和内核空间,默认情况为USER_DS,即对用户空间地址检查并做变换。
老版本的内核用上述方法是OK的。我用的是5.15的内核,编译到get_fs、set_fs会报错。
在这里插入图片描述
5.10后的版本不能使用set_fs了。
在这里插入图片描述
看到一种方案,根据内核版本做以下调整。Linux-5.0.0前的内核使用set_fs( get_ds() ,介于linux-5.0.0和linux-5.10.0之间的内核使用set_fs( KERNEL_DS ),linux-5.10.0之后的内核使用old_fs = force_uaccess_begin();
在我用的内核下编译还是有问题,应该是我的内核版本太新了。


#if LINUX_VERSION_CODE < KERNEL_VERSION(5,0,0)
    old_fs = get_fs();
    set_fs( get_ds() );
#elif LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0)
    old_fs = get_fs();
    set_fs( KERNEL_DS );
#else
    old_fs = force_uaccess_begin();
#endif
...
        ret = fd->f_op->unlocked_ioctl(fd, TCSETS, (unsigned long int) &newtio);
...
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0)
    set_fs(old_fs);
#else
    force_uaccess_end(old_fs);
#endif

coredump保存内存到文件的方法
kernel里有大量保存内存的文件的操作,参考coredump的用法。
在这里插入图片描述
coredump中使用了__kernel_write,这个函数不依赖set_fs的操作。
一个完整的·demo


1 #include <linux/init.h>
  2 #include <linux/module.h>
  3 #include <linux/sched.h>
  4 #include <linux/dcache.h>
  5 #include <linux/fs.h>
  6 #include <linux/err.h>
  7 #include <linux/string.h>
  8 #include <linux/errno.h>
  9 #include <asm/fcntl.h>
 10 #include <asm/processor.h>
 11 #include <asm/uaccess.h>
 12 #include <linux/thread_info.h>
 13
 14 int __init hello_init(void)
 15 {
 16     unsigned char buf1[12]="hello world.";
 17     unsigned char buf2[12]="kernel file.";
 18
 19     struct file *fp;
 20     //mm_segment_t fs;
 21     loff_t pos;
 22
 23     printk("hello enter\n");
 24     fp = filp_open("/root/perf_file", O_RDWR | O_CREAT, 0644);
 25     if (IS_ERR(fp)) {
 26         printk("create file error\n");
 27         return -1;
 28     }
 29     //fs = force_uaccess_begin();
 30
 31    // current_thread_info()->addr_limit = 0;
 32     //fs = get_fs();
 33     //set_fs(KERNEL_DS);
 34
 35     pos = fp->f_pos;
 36     __kernel_write(fp, buf1, sizeof(buf1), &pos);
 37     fp->f_pos = pos;
 38
 39     pos = fp->f_pos;
 40     __kernel_write(fp, buf2, sizeof(buf2), &pos);
 41     fp->f_pos = pos;
 42
 43     //set_fs(fs);
 44     //force_uaccess_end(fs);
 45
 46     filp_close(fp, NULL);
 47     return 0;
 48 }
 49
 50 void __exit hello_exit(void)
 51 {
 52     printk("hello exit\n");
 53 }
 54
 55 module_init(hello_init);
 56 module_exit(hello_exit);
 57
 58 MODULE_LICENSE("GPL");

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Linux保存文件的命令有多种选项,根据需要选择合适的命令。下面列举了几个常用的选项: 1、wq:保存文件并退出vi编辑器; 2、w:保存文件但不退出vi编辑器; 3、w file:将修改另外保存到指定的文件中,不退出vi编辑器; 4、q:不保存文件,直接退出vi编辑器。 除了以上的命令选项,还可以在修改文件时遇到"Open Read-Only"、"(E)dit anyway"、"( R)ecover"等提示,这时可以选择相应的选项来解决问题。 另外,如果你想在Linux中使用mmap映射读取文件的功能,你可以通过以下代码实现: ```c #include <sys/mman.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> int init_in_hdfile() { struct stat filestat; size_t len = 0; void* buf = NULL; int fd = -1; // 打开文件 fd = open("./hd.img", O_RDWR, S_IRWXU|S_IRWXG|S_IRWXO); if(fd < 0) { printf("打开文件失败\n"); return -1; } // 获取文件信息,比如文件大小 fstat(fd, &filestat); // 获取文件大小 len = filestat.st_size; // 映射整个文件到进程的虚拟内存中 buf = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if(buf == NULL) { printf("映射文件失败\n"); return -2; } // 保存地址、长度、文件句柄到全局变量 hdaddr = buf; hdsize = len; hdfilefd = fd; return 0; } ``` 在上述代码中,我们使用了mmap函数将文件映射到进程的虚拟内存中,以便进行读取和修改操作。此外,还有一个函数用于获取根目录inode的地址,从而获取根目录的数据。 总结起来,Linux保存文件的命令有多种选项可供选择,同时也可以使用mmap函数实现文件的映射读取。<span class="em">1</span><span class="em">2</span><span class="em">3</span><span class="em">4</span>

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值