最近在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动作,如果实现那么是如何实现的