- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我使用这个 fanotify 示例来监控整个文件系统的打开/访问权限 (/):http://git.infradead.org/users/eparis/fanotify-example.git .
然后我有一个多线程的测试程序,每个线程迭代示例文件夹并打开/关闭其中的文件,有时我的程序卡在 open()。
操作系统:Ubuntu 2.6.38-11 x86_64。
不支持多线程开启是不是fanotify的bug?
我的测试程序代码:
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <ctype.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <dirent.h>
//open file function
void open_file( char* file )
{
int fd = -1;
fd = open( file, O_WRONLY, 0x666 );
if( fd >= 0 )
{
printf("open:%s\n", file );
close( fd );
}
}
//iterate directory function
void printdir(char *dir, int depth)
{
DIR *dp;
struct stat statbuf;
char pathbuf[2048] = {0};
struct dirent entry;
struct dirent *entryPtr = NULL;
//printf("opendir %s\n", dir );
usleep( 300 );
if((dp = opendir(dir)) == NULL) {
if( errno != ENOTDIR )
{
fprintf(stderr,"cannot open directory: %s\n", dir);
perror("open fial");
}
return;
}
readdir_r( dp, &entry, &entryPtr );
while( entryPtr != NULL)
{
snprintf(pathbuf,2000, "%s/%s\0", dir, entry.d_name );
printf("iteraotr:%s\n", pathbuf );
lstat( pathbuf, &statbuf );
if(S_ISDIR( statbuf.st_mode ))
{
/* Found a directory, but ignore . and .. */
if(strcmp(".",entry.d_name) == 0 ||
strcmp("..",entry.d_name) == 0)
{
}
else
{
//printf("%d,%s\n",depth, entry->d_name);
printdir( pathbuf, depth+1);
}
}
else
{
//printf("%*s%s\n",depth,"",entry->d_name);
open_file( pathbuf );
}
readdir_r( dp, &entry, &entryPtr );
}
closedir(dp);
}
//thread function
void* iterator_dir( void* data )
{
char* path = (char*)data;
printf("In iterator_dir(): %s\n", path );
printdir( path, 0 );
return NULL;
}
pthread_t threadID[10] = {0};
//main function
int main( int argc, char** argv )
{
if( argc < 3 )
{
printf("Usage: %s <thread_num> <file>\n", argv[0] );
exit(0);
}
if( isdigit( (char)*argv[1] ) == 0 )
{
printf(" Thread num is 0 - 9\n");
exit(0);
}
int thread_num = atoi( argv[1] );
char* res;
pthread_attr_t attr;
pthread_attr_init(&attr);
int i = 0;
for( i = 0; i < thread_num; ++i )
{
pthread_create( &threadID[i], &attr, &iterator_dir, argv[2]);
}
for( i = 0; i < thread_num; ++i )
{
pthread_join( threadID[i] , &res );
}
}
2011-09-28 编辑:
我注释掉打开文件操作,只保留迭代目录部分。该应用程序仍然挂起。这是 strace 的输出:
enter code here
pid 10692] open("/home/byang//.config/menus", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC <unfinished ...>
[pid 10691] write(1, "1213966080 opendir /home/byang//"..., 56) = 56
…………
[pid 10689] madvise(0x7f3c48dbc000, 8368128, MADV_DONTNEED) = 0
[pid 10689] _exit(0) = ?
Process 10689 detached
[pid 10688] <... futex resumed> ) = 0
[pid 10688] futex(0x7f3c47db99d0, FUTEX_WAIT, 10692, NULL <unfinished ...>
它卡在这里,当我关闭 fanotify 时,它继续...
[pid 10692] <... open resumed> ) = 11
[pid 10692] getdents(11, /* 4 entries */, 32768) = 128
[pid 10692] lstat("/home/byang//.config/menus/applications.menu", {st_mode=S_IFREG|0644, st_size=233, ...}) = 0
10688是父线程; 10689、10691、10692是迭代目录的子线程。好像10692在等fanotify的回复?
最佳答案
这是内核的 fanotify 的一个错误。我发布了 Linux-Kernel 的补丁:当多个线程访问同一个目录时,一些线程会挂起。这个补丁让 fanotify 区分不同的访问事件线程,防止 fanotify 合并来自不同线程的访问事件线程。
http://marc.info/?l=linux-kernel&m=131822913806350&w=2
-------------------------------
diff -r -u linux-3.1-rc4_orig/fs/notify/fanotify/fanotify.c
linux-3.1-rc4/fs/notify/fanotify/fanotify.c
--- linux-3.1-rc4_orig/fs/notify/fanotify/fanotify.c 2011-08-29
12:16:01.000000000 +0800
+++ linux-3.1-rc4/fs/notify/fanotify/fanotify.c 2011-10-10
12:28:23.276847000 +0800
@@ -15,7 +15,8 @@
if (old->to_tell == new->to_tell &&
old->data_type == new->data_type &&
- old->tgid == new->tgid) {
+ old->tgid == new->tgid &&
+ old->pid == new->pid) {
switch (old->data_type) {
case (FSNOTIFY_EVENT_PATH):
if ((old->path.mnt == new->path.mnt) &&
@@ -144,11 +145,19 @@
return PTR_ERR(notify_event);
#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
- if (event->mask & FAN_ALL_PERM_EVENTS) {
- /* if we merged we need to wait on the new event */
- if (notify_event)
- event = notify_event;
- ret = fanotify_get_response_from_access(group, event);
+ //if overflow, do not wait for response
+ if(fsnotify_isoverflow(event))
+ {
+ pr_debug("fanotify overflow!\n");
+ }
+ else
+ {
+ if (event->mask & FAN_ALL_PERM_EVENTS) {
+ /* if we merged we need to wait on the new event */
+ if (notify_event)
+ event = notify_event;
+ ret = fanotify_get_response_from_access(group, event);
+ }
}
#endif
diff -r -u linux-3.1-rc4_orig/fs/notify/notification.c
linux-3.1-rc4/fs/notify/notification.c
--- linux-3.1-rc4_orig/fs/notify/notification.c 2011-08-29
12:16:01.000000000 +0800
+++ linux-3.1-rc4/fs/notify/notification.c 2011-10-10 12:27:09.331787000 +0800
@@ -95,6 +95,7 @@
BUG_ON(!list_empty(&event->private_data_list));
kfree(event->file_name);
+ put_pid(event->pid);
put_pid(event->tgid);
kmem_cache_free(fsnotify_event_cachep, event);
}
@@ -132,6 +133,14 @@
return priv;
}
+bool fsnotify_isoverflow(struct fsnotify_event *event)
+{
+ if(event==q_overflow_event)
+ {
+ return true;
+ }
+ return false;
+}
/*
* Add an event to the group notification queue. The group can later pull this
* event off the queue to deal with. If the event is successfully added to the
@@ -374,6 +383,7 @@
return NULL;
}
}
+ event->pid = get_pid(old_event->pid);
event->tgid = get_pid(old_event->tgid);
if (event->data_type == FSNOTIFY_EVENT_PATH)
path_get(&event->path);
@@ -417,6 +427,7 @@
event->name_len = strlen(event->file_name);
}
+ event->pid = get_pid(task_pid(current));
event->tgid = get_pid(task_tgid(current));
event->sync_cookie = cookie;
event->to_tell = to_tell;
diff -r -u linux-3.1-rc4_orig/include/linux/fsnotify_backend.h
linux-3.1-rc4/include/linux/fsnotify_backend.h
--- linux-3.1-rc4_orig/include/linux/fsnotify_backend.h 2011-08-29
12:16:01.000000000 +0800
+++ linux-3.1-rc4/include/linux/fsnotify_backend.h 2011-10-10
12:27:48.587369000 +0800
@@ -238,6 +238,7 @@
u32 sync_cookie; /* used to corrolate events, namely inotify mv events */
const unsigned char *file_name;
size_t name_len;
+ struct pid *pid;
struct pid *tgid;
#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
@@ -378,6 +379,8 @@
struct fsnotify_event_private_data *priv,
struct fsnotify_event *(*merge)(struct list_head *,
struct fsnotify_event *));
+/*true if the event is an overflow event*/
+extern bool fsnotify_isoverflow(struct fsnotify_event *event);
/* true if the group notification queue is empty */
extern bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group);
/* return, but do not dequeue the first event on the notification queue */
关于linux - 开启 fanotify 时多线程打开文件挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7566755/
我正在使用如下代码来监控整个文件系统: fanotify_mark(fd, FAN_MARK_ADD | FAN_MARK_MOUNT, FAN_OPEN |
亲爱的 Linux C 程序员: 在linux fanotify 工具中,我知道如何监视文件打开(FAN_OPEN)。如果我监视直到关闭,我还可以了解打开是“读”还是“写”,因为有一个 FAN_CLO
我使用了 example fanotify 联机帮助页以获取发生文件访问的所有路径。但我只希望从一个特定文件夹监视文件访问,例如/tmp/我的文件夹。 为此,我添加了我的特定文件夹“/tmp/myfo
我使用这个 fanotify 示例来监控整个文件系统的打开/访问权限 (/):http://git.infradead.org/users/eparis/fanotify-example.git .
我想找出哪些文件在我的系统上以何种顺序打开,以便从磁盘中预取它们。似乎fanotify应该非常适合监控整个系统的开放事件。但据我所知,fanotify_event_metadata 结构没有包含路径的
是否有类似 fanotify 的设施,但用于 exec() 操作?类似于 kauth in MacOS ,但在用户空间。 fanotify 似乎只通知(并允许/拒绝)文件打开/关闭/读/写。 我见过可
我需要使用开源软件对 docker 容器内的文件实现防病毒访问扫描解决方案。 Clamav On-Access工作正常,但有一些要求和限制: 需要 CAP_SYS_ADMIN 功能才能在容器内工作 需
我让我的守护进程使用 fanotify API 来控制对文件的访问。这是工作线程: void * threadProc( void * data ) { if( data == NULL )
从内核 5.1 开始,新标志 FAN_ATTRIB、FAN_CREATE、FAN_DELETE、FAN_DELETE_SELF、FAN_MOVED_FROM、FAN_MOVED_TO 和 FAN_MO
fanotify 建立在 fsnotify 之上,应该取代 inotify,后者取代了 dnotify。是否有一些好的编程示例或现有实用程序使用 fanotify 来监视文件系统中的更改? fanot
我是一名优秀的程序员,十分优秀!