FreeBSD内核之一 ALQ机制的使用

背景:

笔者因为一个项目,这段时间在使用FreeBSD进行内核模块的编程。之前做过一段时间的Linux下驱动模块编程,对Linux下的模块编程还算熟悉。现在突然转到FreeBSD下,虽然Linux和FreeBSD两者都是类Unix系统,在实现机制上还是差别很大的,多少有点不习惯。笔者的项目要在一个插入进内核的模块里,将log信息写入到磁盘的中。在用户层可以用读写文件的形式;在内核模块中,与Linux不同的是,并不推荐用户使用将这种方法移植到内核模块中。但是FreeBSD却提供了一种ALQ机制。ALQ机制依赖于ALQ模块,在sys/conf/files中,可以看到它是可选的。

简介:

ALQ(Asynchronous Logging Queues) 异步日志队列,提供了一种异步的定长和变长的record机制。它能够记录任何vnode。因此能对日志、字符设备及普通文件进行操作。所有的功能函数接受一个struct alq的参数,struct alq是一种隐含类型,维护一个ALQ的状态信息。这种logging机制作为一个独立的内核线程来运行的,可以为系统所有的log请求服务。每一个ale(asynchronous log entry)定义成一个struct ale,结构如下:

<span style="font-size:12px;"><span style="font-size:10px;">	   struct ale {
		   intptr_t	   ae_bytesused;   /* #	bytes written to ALE. */
		   char		   *ae_data;	   /* Write ptr. */
		   int		   ae_pad;	   /* Unused, compat. */
	   };</span></span>
一个alq可以以定长或变长的两种模式创建。可变长度的alq适应alq_writen()alq_getn()使用时写的长度。 而定长的alq在队列创建时就已经指定好了。定长模式现在已经被弃用,可以使用变模式来代替它。

函数:

#include <sys/alq.h>

int alq_open_flags(struct alq **app, const char *file, struct ucred *cred, int cmode, int size, int flags);  创建一个可变长的alq。file为文件名。如果文件不存在,alq_open()会试图创建它,并且cmode参数会被传递给alq_open()作为创建文件的属性。 对多数用户来说这个cmdode应被指定为ALQ_DEFAULT_CMODE。当打开文件和进行I/O操作时,cred参数指定信任证书。size设置队列的大小(单位为字节)。最后一个参数flag通常被设置成ALQ_ORDERED来  指明写线程等待忙碌的alq释放资源的顺序应该被保留。成功返回0,否则返回错误码(open(2))。
int alq_open(struct alq **app,const char *file,struct ucred *cred, int cmode, int size, int count);被弃用的alq_open()封装在alq_open_flags()中,为了兼容老版本。所有的         参数都是通过alq_open_flags()间接传递的。具体的我在此不作介绍,有兴趣的读者可以参考alq
int alq_writen(struct alq *alq, void *data, int len, int flags);从data把len字节的数据写入到设置地可变长模式的alq中。如果alq_write()不能立即写  入这个数据,同时flags参    数又设置了ALQ_WAITOK,那么它将使用msleep_spin(9)睡眠等待数据。一个写操作会自动调度队列alq使     之写入磁盘。这种行为可以通过给flags参数传递
ALQ_NOACTIVATE,来控制它不会被写入磁盘。如果设置ALQ_NOWAIT或队列已满或系统关机,返回EWOULDBLOCK。
int alq_write(struct alq *alq, void *data, int flags);被弃用的alq_write()封闭在alq_writen()中,有兴趣的读者可以参考alq
void alq_flush(struct alq *alq);刷新alq到log文件。如果alq有数据可被刷新,并且没有没有进行在刷新,那么它将会阻塞,去进行IO操作。否则立即返回。
void alq_close(struct alq *alq);关闭alq,刷新所有的挂起的写请求到log文件。释放申请的所有资源。
struct ale * alq_getn(struct alq *alq, int len, int flags);从alq队列中返回一个ale。它会让alq处于锁定状态直到子alq_post()或alq_post_flags被调用。如果
alq_getn()不能立即获取到len长度字节数据,并且在flags中设置了ALQ_WAITOK,它将会阻塞等待数据。调用者可以通过事先设置struct ale中的 ae_bytesused域,选择返回小于len字节到ale中。如果设置ALQ_NOWAIT或队列已满或系统关机,返回NULL。
struct ale * alq_get(struct alq *alq, int flags); 被弃用,封装于alq_getn()中。
void alq_post_flags(struct alq *alq, struct ale *ale, int flags);调度ale(从alq_getn()或alq_get()中获取)用于写alq。可以在flags参数中设置ALQ_NOACTIVATE指明队列不会立即被刷新到磁盘。 会对alq进行解锁。

参考文献:

    ALQ
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值