2012-08-06 20 views

Respuesta

14

Nada - la llamada para registrar el archivo fd (al menos para los sistemas de archivos Linux comunes) falla con EPERM.

He probado esto con el siguiente programa de demostración:

#include <sys/epoll.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <stdio.h> 

int main(void) { 
    int ep = epoll_create1(0); 
    int fd = open("/tmp", O_RDONLY|O_DIRECTORY); 
    struct epoll_event evt = { 
     .events = EPOLLIN 
    }; 

    if (ep < 0 || fd < 0) { 
     printf("Error opening fds.\n"); 
     return -1; 
    } 

    if (epoll_ctl(ep, EPOLL_CTL_ADD, fd, &evt) < 0) { 
     perror("epoll_ctl"); 
     return -1; 
    } 
    return 0; 
} 

con el siguiente resultado:

[[email protected]:/tmp]$ make epoll 
cc  epoll.c -o epoll 
[[email protected]:/tmp]$ ./epoll 
epoll_ctl: Operation not permitted 

Para averiguar lo que estaba pasando aquí, fui a la fuente. I happen to know que la mayoría del comportamiento de epoll está determinado por la función ->poll en el struct file_operations correspondiente al archivo de destino, que depende del sistema de archivos en cuestión. Cogí ext4 como un ejemplo típico, y miré fs/ext4/dir.c, que definesext4_dir_operations de la siguiente manera:

const struct file_operations ext4_dir_operations = { 
    .llseek  = ext4_dir_llseek, 
    .read  = generic_read_dir, 
    .readdir = ext4_readdir, 
    .unlocked_ioctl = ext4_ioctl, 
#ifdef CONFIG_COMPAT 
    .compat_ioctl = ext4_compat_ioctl, 
#endif 
    .fsync  = ext4_sync_file, 
    .release = ext4_release_dir, 
}; 

nota la falta de una definición .poll, lo que significa que será inicializado a NULL. Así, haciendo pivotar de nuevo a epoll, que se define en fs/eventpoll.c, buscamos cheques por poll ser NULL, y nos encontramos con uno early on en la definición epoll_ctl syscall:

/* The target file descriptor must support poll */ 
error = -EPERM; 
if (!tfile->f_op || !tfile->f_op->poll) 
    goto error_tgt_fput; 

Como se indica nuestra prueba, si el archivo de destino doesn no es compatible con poll, el intento de inserción simplemente fallará con EPERM.

Es posible que otros sistemas de archivos definan .poll métodos en sus objetos de archivos de directorio, pero dudo que muchos lo hagan.

+0

Es 'dirfd (opendir ("/tmp "))' preferido sobre 'abierto (ruta, O_RDONLY | O_DIRECTORY);'? Solo una pregunta de estilo. Usar 'opendir' no hace mágicamente que la encuesta de soporte fs. – schmichael

+0

'dirfd (opendir (" ... "))' es más portátil, por lo que probablemente se prefiera en general. Soy un pirata informático del kernel de Linux, por lo que, en general, prefiero utilizar la interfaz de llamada al sistema incluso cuando no es la más adecuada, porque lo sé mejor. Obviamente, aquí no importa, ya que 'epoll' también es específico de Linux. – nelhage

Cuestiones relacionadas