13-不使用请求队列
13.6.2 不使用请求队列
使用请求队列对于一个机械的磁盘设备而言的确有助于提高系统的性能,但是对于许多块设备,如数码相机的存储卡、RAM盘等完全可真正随机访问的设备而言,无法从高级的请求队列逻辑中获益。对于这些设备,块层支持“无队列”的操作模式,为使用这个模式,驱动必须提供一个“制造请求”函数,而不是一个请求函数,“制造请求”函数的原型为:
typedef int (make_request_fn) (request_queue_t q, struct bio bio);
上述函数的第一个参数仍然是“请求队列”,但是这个“请求队列”实际不包含任何request,因为块层没有必要将bio调整为request。因此,“制造请求”函数的主要参数是bio结构体,这个bio结构体表示一个或多个要传送的缓冲区。“制造请求”函数或者直接进行传输,或者把请求重定向给其他设备。
在“制造请求”函数中处理bio的方式与13.6.1小节中讲解的完全一致,但是在处理完成后应该使用bio_endio()函数通知处理结束,如下所示:
void bio_endio(struct bio *bio, unsigned int bytes, int error);
参数bytes是已经传送的字节数,它可以比这个bio所代表的字节数少,这意味着“部分完成”,同时bio结构体中的当前缓冲区指针需要更新。当设备进一步处理这个bio后,驱动应该再次调用bio_endio(),如果不能完成这个请求,应指出一个错误,错误码赋值给error参数。
不管对应的I/O处理成功与否,“制造请求”函数都应该返回0。如果“制造请求”函数返回一个非零值,bio将被再次提交。
代码清单13.16所示为一个“制造请求”函数的例子。
代码清单13.16 “制造请求”函数例程
1 static int xxx_make_request(request_queue_t q, struct bio bio)
2 {
3 struct xxx_dev *dev = q->queuedata;
4 int status;
5 status = xxx_xfer_bio(dev, bio); / 处理bio /
6 bio_endio(bio, bio->bi_size, status); / 通告结束 /
7 return 0;
8 }
为了使用无队列的I/O请求处理,驱动模块的加载函数应遵循代码清单13.9的模板而非代码清单13.10的模板,而使用请求队列时,驱动模块的加载函数应遵循代码清单13.10的模板。