Я заставил своего демона использовать fanotify API для управления доступом к файлам. Вот рабочая нить:
void * threadProc( void * data )
{
if( data == NULL ) return 0;
RealTimeDrvrImp & _this = *( ( RealTimeDrvrImp * )data );
const unsigned int fi_flags = FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK;
const unsigned int fi_event_f_flags = O_RDONLY | O_LARGEFILE;
_this.m_fa_fd = fanotify_init( fi_flags, fi_event_f_flags );
if (-1 == _this.m_fa_fd )
return NULL;
const unsigned int fm_flags = FAN_MARK_ADD | FAN_MARK_MOUNT;
const uint64_t fm_event_f_flags = FAN_OPEN_PERM /*| FAN_ACCESS_PERM*/ /*| FAN_CLOSE_WRITE*/;
if (-1 == fanotify_mark( _this.m_fa_fd, fm_flags, fm_event_f_flags, 0, "/" ) )
{
close( _this.m_fa_fd );
return NULL;
}
char buf[4096];
int len = 0;
struct timespec tmsp = { 0, 1000000 };//500 miliseconds
pid_t self_pid = getpid();
while( _this.m_DoAvRealtimeScanThread )
{
if(-1 == ( len = read(_this.m_fa_fd, (void *) &buf, sizeof (buf))) )
{
if( EAGAIN == errno )
{
nanosleep( & tmsp, NULL );
continue;
}
else
break;
}
const struct fanotify_event_metadata *metadata
= (struct fanotify_event_metadata *) buf;
while (FAN_EVENT_OK(metadata, len)) {
if (metadata->fd != FAN_NOFD ) {
if (metadata->fd >= 0)
{
bool bCloseFdNow = true;
if( metadata->mask & FAN_OPEN_PERM ||
metadata->mask & FAN_ACCESS_PERM )
{
bool bWriteNow = true;
struct fanotify_response response = {0,0};
response.fd = metadata->fd;
response.response = FAN_ALLOW;
if( metadata->pid == self_pid )
{//this process event, always allow
}
else if( _this.IsReplyReadyNow( response ) )
{//response.response is set in IsReplyReadyNow();
}
else //else event is added to a queue,
//will be handled and closed later in another thread
{
bCloseFdNow = false;
bWriteNow = false;
}
if( bWriteNow )
{
pthread_mutex_lock( & _this.m_faWriteMtx );
write( _this.m_fa_fd, &response, sizeof (struct fanotify_response ) );
pthread_mutex_unlock( & _this.m_faWriteMtx );
}
}
if( bCloseFdNow )
close( metadata->fd );
}
}
metadata = FAN_EVENT_NEXT(metadata, len);
}
}
close( _this.m_fa_fd );
_this.m_fa_fd = -1;
return NULL;
}
Работает правильно. Если я остановлю демон перед перезагрузкой или выключением, все в порядке. Но если я пытаюсь перезагрузить систему или завершить работу при работающем демоне, система зависнет.
Я думаю, что, возможно, система отправляет SIGSTOP своим демонам при перезагрузке / выключении, это правильно? Если так, то демон не может разрешить доступ к какому-либо файлу, и это блокирует систему?
Пожалуйста помоги.
Я использую Ubuntu 12.04 64-bit с ядром 3.11.0.
Я узнал, почему это заблокировано.
Видимо при перезагрузке linux интенсивно обращается к файлам, которые контролирует мой демон. Каждый доступ должен быть разрешен в вызове _this.IsReplyReadyNow (), который, в свою очередь, использует несколько вызовов syslog () для регистрации событий файловой системы. При перезагрузке в системном журнале после некоторых моих записей пришло это сообщение:
«imuxsock начинает отбрасывать сообщения из-за ограничения скорости»
и после этого мой демон заблокировался и остановился, чтобы разрешить или запретить доступ к файлам, и таким образом заблокировал систему.
Когда я закомментировал вызовы syslog (), система, наконец, перезагрузилась.
Других решений пока нет …