高级I/O操作-定位操作

x33g5p2x  于2022-05-16 转载在 其他  
字(3.3k)|赞(0)|评价(0)|浏览(454)

定位操作

驱动代码:

  1. /* vfb.c */
  2. #include <linux/init.h>
  3. #include <linux/kernel.h>
  4. #include <linux/module.h>
  5. #include <linux/fs.h>
  6. #include <linux/mm.h>
  7. #include <linux/cdev.h>
  8. #include <linux/uaccess.h>
  9. #define VFB_MAJOR 256
  10. #define VFB_MINOR 1
  11. #define VFB_DEV_CNT 1
  12. #define VFB_DEV_NAME "vfbdev"
  13. struct vfb_dev {
  14. unsigned char *buf;
  15. struct cdev cdev;
  16. };
  17. static struct vfb_dev vfbdev;
  18. static int vfb_open(struct inode * inode, struct file * filp)
  19. {
  20. return 0;
  21. }
  22. static int vfb_release(struct inode *inode, struct file *filp)
  23. {
  24. return 0;
  25. }
  26. static int vfb_mmap(struct file *filp, struct vm_area_struct *vma)
  27. {
  28. if (remap_pfn_range(vma, vma->vm_start, virt_to_phys(vfbdev.buf) >> PAGE_SHIFT, \
  29. vma->vm_end - vma->vm_start, vma->vm_page_prot))
  30. return -EAGAIN;
  31. return 0;
  32. }
  33. ssize_t vfb_read(struct file *filp, char __user *buf, size_t count, loff_t *pos)
  34. {
  35. int ret;
  36. size_t len = (count > PAGE_SIZE) ? PAGE_SIZE : count;
  37. //判断文件访问是否超过了边界
  38. //超过了调整访问的长度
  39. if (*pos + len > PAGE_SIZE)
  40. len = PAGE_SIZE - *pos;
  41. ret = copy_to_user(buf, vfbdev.buf + *pos, len);
  42. *pos += len - ret;
  43. return len - ret;
  44. }
  45. //文件定位操作
  46. static loff_t vfb_llseek(struct file * filp, loff_t off, int whence)
  47. {
  48. loff_t newpos;
  49. switch (whence) {
  50. case SEEK_SET:
  51. newpos = off;
  52. break;
  53. case SEEK_CUR:
  54. newpos = filp->f_pos + off;
  55. break;
  56. case SEEK_END:
  57. newpos = PAGE_SIZE + off;
  58. break;
  59. default: /* can't happen */
  60. return -EINVAL;
  61. }
  62. //判断新的位置值是否合法
  63. if (newpos < 0 || newpos > PAGE_SIZE)
  64. return -EINVAL;
  65. //将新的文件位置值更新到file结构的f_pos成员中
  66. filp->f_pos = newpos;
  67. return newpos;
  68. }
  69. static struct file_operations vfb_fops = {
  70. .owner = THIS_MODULE,
  71. .open = vfb_open,
  72. .release = vfb_release,
  73. .mmap = vfb_mmap,
  74. .read = vfb_read,
  75. .llseek = vfb_llseek,
  76. };
  77. static int __init vfb_init(void)
  78. {
  79. int ret;
  80. dev_t dev;
  81. unsigned long addr;
  82. dev = MKDEV(VFB_MAJOR, VFB_MINOR);
  83. ret = register_chrdev_region(dev, VFB_DEV_CNT, VFB_DEV_NAME);
  84. if (ret)
  85. goto reg_err;
  86. cdev_init(&vfbdev.cdev, &vfb_fops);
  87. vfbdev.cdev.owner = THIS_MODULE;
  88. ret = cdev_add(&vfbdev.cdev, dev, VFB_DEV_CNT);
  89. if (ret)
  90. goto add_err;
  91. addr = __get_free_page(GFP_KERNEL);
  92. if (!addr)
  93. goto get_err;
  94. vfbdev.buf = (unsigned char *)addr;
  95. memset(vfbdev.buf, 0, PAGE_SIZE);
  96. return 0;
  97. get_err:
  98. cdev_del(&vfbdev.cdev);
  99. add_err:
  100. unregister_chrdev_region(dev, VFB_DEV_CNT);
  101. reg_err:
  102. return ret;
  103. }
  104. static void __exit vfb_exit(void)
  105. {
  106. dev_t dev;
  107. dev = MKDEV(VFB_MAJOR, VFB_MINOR);
  108. free_page((unsigned long)vfbdev.buf);
  109. cdev_del(&vfbdev.cdev);
  110. unregister_chrdev_region(dev, VFB_DEV_CNT);
  111. }
  112. module_init(vfb_init);
  113. module_exit(vfb_exit);
  114. MODULE_LICENSE("GPL");

驱动代码第45行和第46行判断文件访问是否超过了边界,如果是则调整访问的长度。

代码第48行在复制时考虑到了偏移所带来的影响

代码第49行则是更新位置值。

代码第54行至第78行是文件定位操作的实现,根据whence的不同,设置了新的文件位置值

代码第72行和第73行则是判断新的位置值是否合法

代码第75行将新的文件位置值更新到file结构的f_pos成员中

测试程序代码:

  1. /* test.c */
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <fcntl.h>
  5. #include <unistd.h>
  6. #include <sys/mman.h>
  7. #include <string.h>
  8. int main(int argc, char * argv[])
  9. {
  10. int fd;
  11. char *start;
  12. int i;
  13. char buf[32];
  14. fd = open("/dev/vfb0", O_RDWR);
  15. if (fd == -1)
  16. goto fail;
  17. start = mmap(NULL, 32, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  18. if (start == MAP_FAILED)
  19. goto fail;
  20. for (i = 0; i < 26; i++)
  21. *(start + i) = 'a' + i;
  22. *(start + i) = '\0';
  23. if(lseek(fd, 3, SEEK_SET) == -1)
  24. goto fail;
  25. if (read(fd, buf, 10) == -1)
  26. goto fail;
  27. buf[10] = '\0';
  28. puts(buf);
  29. munmap(start, 32);
  30. return 0;
  31. fail:
  32. perror("mmap test");
  33. exit(EXIT_FAILURE);
  34. }

测试程序相对于上一篇文章的变化是在读操作时候前面首先使用lseek将文件位置定位为3,那么之后的操作都从文件的第3个字节开始读取。

if(lseek(fd, 3, SEEK_SET) == -1)
        goto fail;
 
    if (read(fd, buf, 10) == -1)
        goto fail;

编译结果如下图:

abcd 对应文件位置 (数组) 0 1 2 3

因为是从第3字节开始读取 即d

读10个

read(fd, buf, 10)、

从buf缓冲区中读取10字节

defghijklm 10个

至此I/O操作结束

相关文章