存储笔记--块设备驱动的操作

1。块设备的open

static int sbull_open(struct inode *inode, struct file *filp)
{
struct sbull_dev *dev = inode->i_bdev->bd_disk->private_data;
del_timer_sync(&dev->timer);
filp->private_data = dev;
spin_lock(&dev->lock)
;
if (! dev->users)
check_disk_change(inode->i_bdev);
dev->users++;
spin_unlock(&dev->lock)
;
return 0;
}

一旦 sbull_open 有它的设备结构指针, 它调用 del_timer_sync 来去掉”介质移出”定时器, 如果有一个是活的. 注意我们不加锁设备自旋锁, 直到定时器被删除后; 如果定时器函数在我们可删除它之前运行, 反过来做会有死锁. 在设备加锁下, 我们调用一个内核函数, 称为 check_disk_change, 来检查是否已发生一个介质改变. 可能有人争论说内核应当做这个调用, 但是标准模式是为驱动来在打开时处理它.

2。块设备的release

释放方法的任务是, 相反, 来递减用户计数, 以及, 如果被指示了, 启动介质移出定时器:

static int sbull_release(struct inode *inode, struct file *filp)
{
struct sbull_dev *dev = inode->i_bdev->bd_disk->private_data;
spin_lock(&dev->lock);
dev->users–;
if (!dev->users)
{
dev->timer.expires = jiffies + INVALIDATE_DELAY;
add_timer(&dev->timer);
}
spin_unlock(&dev->lock);
return 0;
}

3。块设备的热插拔

block_device_operations 结构包含 2 个方法来支持可移出介质. 如果你为一个非可移出设备编写一个驱动, 你可安全地忽略这些方法. 它们的实现是相对直接的.

media_changed 方法被调用( 从 check_disk_change ) 来看是否介质已经被改变; 它应当返回一个非零值, 如果已经发生. sbull 实现是简单的; 它查询一个已被设置的标志, 如果介质移出定时器已超时:

int sbull_media_changed(struct gendisk *gd)
{
struct sbull_dev *dev = gd->private_data;
return dev->media_change;
}

revalidate 方法在介质改变后被调用; 它的工作是做任何需要的事情来准备驱动对新介质的操作, 如果有. 在调用 revalidate 之后, 内核试图重新读分区表并且启动这个设备. sbull 的实现仅仅复位 media_change 标志并且清零设备内存来模拟一个空盘插入.

int sbull_revalidate(struct gendisk *gd)
{
struct sbull_dev *dev = gd->private_data;
if (dev->media_change)
{
dev->media_change = 0;
memset (dev->data, 0, dev->size);
}
return 0;
}

块设备自定义ioctl

块设备可提供一个 ioctl 方法来进行设备控制函数. 高层的块子系统代码在你的驱动能见到它们之前解释许多的 ioctl 命令, 但是( 全部内容见 drivers/block/ioctl.c , 在内核源码中). 实际上, 一个现代的块驱动根本不必实现许多的 ioctl 命令.

sbull ioctl 方法只处理一个命令 – 一个对设备的结构的请求:

int sbull_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
long size;
struct hd_geometry geo;
struct sbull_dev *dev = filp->private_data;
switch(cmd)
{
case HDIO_GETGEO:
/*
* Get geometry: since we are a virtual device, we have to make
* up something plausible. So we claim 16 sectors, four heads,
* and calculate the corresponding number of cylinders. We set the
* start of data at sector four.
*/
size = dev->size*(hardsect_size/KERNEL_SECTOR_SIZE);
geo.cylinders = (size & ~0x3f) >> 6;
geo.heads = 4;
geo.sectors = 16;
geo.start = 4;
if (copy_to_user((void __user *) arg, &geo, sizeof(geo)))
return -EFAULT;
return 0;
}
return -ENOTTY; /* unknown command */
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值