最近在linux上做软raid时,需要检测raid的相关事件的发生。比如:添加备用盘、移除磁盘、raid降级等事件。最开始的时候是采用定时器
方式,每隔一段时间就扫描raid superblock的更新时间,如果发生变化就检测一次。先不说superblock的updatetime是否准确,单单使用定时器
轮询方式就感觉不好,希望能找到一种类似于中断的方式来处理。
最开始时是想到raid事件的发生,内核肯定会知道然后会改变/proc/mdstat。所以如果检测/proc/mdstat就可以实现这个功能。查看md驱动
也发现有类似说明:
/*
* We have a system wide 'event count' that is incremented on any 'interesting' event, and readers of /proc/mdstat can use 'poll' or 'select' to find out when the event
* count increases.
* Events are:
* start array, stop array, error, add device, remove device,
* start build, activate spare
*/
但是对于如何检测/proc/mdstat的改变。我最开始是想到inotify。一是我们的内核已经支持(2.6.13 and later);二是没有用过inotify想试试。
所以我使用inotify来检测/proc/mdstat发现,进行raid事情发生,但是inotify却没有返回事件。于是我走读内核发现,inotify所谓的事件发生
是基于用户空间访问、修改的动作。对于procfs/sysfs这种内存文件系统,如果用户程序不访问文件,那么inotify是不能实现。
inotify为什么不实现procfs/sysfs的主动推的动作,诱发inotify事件的发生。
查看代码发现(2.6.18)中sysfs实现了sysfs_update_file来主动诱发inotify,但是在最新内核中没有发现该函数。
看来只能是使用poll或者select来完成这个功能了。例子如下:
int main()
{
struct pollfd fds;
int fd;
char buff[4096];
while(1){
fd = open("/proc/mdstat",O_RDONLY);
if(fd < 0){
printf("open error %s/n",strerror(errno));
return errno;
} memset(&fds,0,sizeof(struct pollfd));
fds.fd = fd;
fds.events = POLLERR;
if(poll(&fds,fd+1,-1) == -1)
printf("poll error %s/n",strerror(errno));
else{
printf("poll return/n");
//memset(buff,0,sizeof(buff));
//read(fd,buff,sizeof(buff));
}
close(fd);
}
return 0;}
对于events查看内核函数:mdstat_poll只能是POLLERR 和POLLPRI。
顺便将poll/select的内核实现看了看,下面以mdstat_poll为例讲解:
static unsigned int mdstat_poll(struct file *filp, poll_table *wait)
{
struct seq_file *m = filp->private_data;
struct mdstat_info *mi = m->private;
int mask;
//这句话必须有
poll_wait(filp, &md_event_waiters, wait); /* always allow read */
//无论何时使用POLLIN都会返回
mask = POLLIN | POLLRDNORM;
//只有这个条件成立,才会返回POLLERR | POLLPRI
if (mi->event != atomic_read(&md_event_count)){
mask |= POLLERR | POLLPRI;
}
return mask;
}
如果执行mdstat_poll没有返回POLLERR那么线程会休眠,等待poll的时间结束或者等待有人wait_up。
在函数:
void md_new_event(mddev_t *mddev)
{
atomic_inc(&md_event_count);
wake_up(&md_event_waiters);
sysfs_notify(&mddev->kobj, NULL, "sync_action");
}
EXPORT_SYMBOL_GPL(md_new_event);/* Alternate version that can be called from interrupts
* when calling sysfs_notify isn't needed.
*/
static void md_new_event_inintr(mddev_t *mddev)
{
atomic_inc(&md_event_count);
wake_up(&md_event_waiters);
}
只要有事件发生,调用上面两个函数,就会执行wake_up(&md_event_waiters);那么就会将等待POLLERR、POLLPRI事件的进程从休眠状态
唤醒到可执行状态,进而返回用户控件。
对于检测时间POLLIN,会立马返回的,因为没有任何条件需要。
对于检测procfs/sysfs中的文件的变化,目前看来只能是使用poll/select(没有实现的可以自己实现),使用inotify看来不行。
在测试中发现对于添加备用盘和拔出备用盘(物理拔出),raid都不会检测到事件的发生。
查看最新内核中的add_new_disk都没有调用md_new_event。这不知道是为什么?
而且raid组成盘移除,如果没有读写操作,md是发现不了的,这也是个问题,不知道在最新内核中是否添加这个功能。
问题
1:添加备用盘是没有事件发生的(在2.6.18内核中也不更新superblock,在后面内核中更新superblock)
2:没有读写操作下,物理移除raid盘,md层驱动是不感知的
3:查看最新内核中是否实现了procfs/sysfs中的主动推inotify动作,如果实现那么是如何实现的