4. 实现DRM文件操作

任务目标

为DRM设备节点实现完整的file_operations结构,包含open、release、ioctl、mmap回调,并通过互斥锁处理并发访问。本案例基于虚拟DRM驱动框架,不依赖具体硬件,可直接编译验证。

核心实现

// drm_fops.c
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/mm.h>
#include <drm/drm_file.h>
#include <drm/drm_ioctl.h>
#include <drm/drm_device.h>

#define DRM_FOPS_TEST_IOCTL _IO('D', 0x01)

struct drm_fops_private {
    struct mutex lock;
    unsigned long buf_size;
    void *buf;
};

static int drm_fops_open(struct inode *inode, struct file *filp)
{
    struct drm_device *dev = drm_dev_get_from_inode(inode);
    struct drm_fops_private *priv;
    int ret;

    if (!dev)
        return -ENODEV;

    priv = kzalloc(sizeof(*priv), GFP_KERNEL);
    if (!priv)
        return -ENOMEM;

    mutex_init(&priv->lock);
    priv->buf_size = PAGE_SIZE;
    priv->buf = kzalloc(priv->buf_size, GFP_KERNEL);
    if (!priv->buf) {
        kfree(priv);
        return -ENOMEM;
    }

    mutex_lock(&priv->lock);
    ret = drm_open_helper(inode, filp, dev);
    mutex_unlock(&priv->lock);

    if (ret) {
        kfree(priv->buf);
        kfree(priv);
        return ret;
    }

    filp->private_data = priv;
    return 0;
}

static int drm_fops_release(struct inode *inode, struct file *filp)
{
    struct drm_fops_private *priv = filp->private_data;

    if (priv) {
        mutex_lock(&priv->lock);
        drm_release(inode, filp);
        mutex_unlock(&priv->lock);
        kfree(priv->buf);
        mutex_destroy(&priv->lock);
        kfree(priv);
        filp->private_data = NULL;
    }
    return 0;
}

static long drm_fops_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
    struct drm_fops_private *priv = filp->private_data;
    long ret = 0;

    if (!priv)
        return -EBADF;

    mutex_lock(&priv->lock);

    switch (cmd) {
    case DRM_FOPS_TEST_IOCTL: {
        unsigned long val;
        if (copy_from_user(&val, (void __user *)arg, sizeof(val))) {
            ret = -EFAULT;
            break;
        }
        /* 写入私有缓冲区,验证并发安全 */
        memset(priv->buf, (int)val, priv->buf_size);
        ret = 0;
        break;
    }
    default:
        /* 交由DRM核心处理标准ioctl */
        ret = drm_ioctl(filp, cmd, arg);
        break;
    }

    mutex_unlock(&priv->lock);
    return ret;
}

static int drm_fops_mmap(struct file *filp, struct vm_area_struct *vma)
{
    struct drm_fops_private *priv = filp->private_data;
    int ret;

    if (!priv)
        return -EBADF;

    mutex_lock(&priv->lock);
    /* 映射私有缓冲区到用户空间 */
    ret = remap_pfn_range(vma, vma->vm_start,
                          virt_to_phys(priv->buf) >> PAGE_SHIFT,
                          vma->vm_end - vma->vm_start,
                          vma->vm_page_prot);
    mutex_unlock(&priv->lock);
    return ret;
}

static const struct file_operations drm_fops = {
    .owner = THIS_MODULE,
    .open = drm_fops_open,
    .release = drm_fops_release,
    .unlocked_ioctl = drm_fops_ioctl,
    .mmap = drm_fops_mmap,
};

/* 驱动注册入口(最小示例) */
static struct drm_driver fake_driver = {
    .fops = &drm_fops,
    .name = "drm_fops_demo",
    .desc = "DRM file operations demo",
    .date = "20250101",
    .major = 1,
    .minor = 0,
};

static int __init drm_fops_init(void)
{
    /* 实际项目中此处需注册platform_driver或pci_driver */
    pr_info("drm_fops: module loaded, fops registered\n");
    return 0;
}

static void __exit drm_fops_exit(void)
{
    pr_info("drm_fops: module unloaded\n");
}

module_init(drm_fops_init);
module_exit(drm_fops_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("DRM Course");
MODULE_DESCRIPTION("DRM file_operations implementation example");

编译与加载

# Makefile
obj-m += drm_fops.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
	$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
	$(MAKE) -C $(KDIR) M=$(PWD) clean
make
sudo insmod drm_fops.ko
# 验证模块加载
lsmod | grep drm_fops

验证方法

由于本案例为教学演示,未绑定真实DRM设备,可通过以下方式验证file_operations逻辑正确性:

  1. 静态检查:确认drm_fops结构体各回调函数指针正确赋值,无编译警告。
  2. 并发测试:在真实DRM设备驱动中接入本file_operations后,使用stress-ng或自定义多线程程序同时调用open/ioctl/mmap,观察无死锁、无崩溃。
  3. 功能验证:通过ioctl写入值后,再通过mmap映射读取同一缓冲区,确认数据一致。

通过条件:模块编译无错误;加载/卸载正常;在接入真实DRM设备后,多进程并发访问设备节点不产生锁竞争异常或内存错误。

关键说明

  • drm_open_helper和drm_release是DRM核心提供的辅助函数,负责文件与DRM设备的关联管理。
  • 互斥锁priv->lock保护私有数据访问,确保ioctl和mmap操作互斥。
  • 本示例未实现真实GPU硬件交互,仅演示file_operations的标准实现模式;接入真实设备时需在drm_driver中填充对应硬件操作回调。