현재 액세스 중인 프로세스에서 해당 파일이 열려 있는지 확인하기 위해 요청 시 쿼리하려는 파일이 있다고 가정해 보겠습니다. 모든 PID를 반복하는 것은 /proc/{PID}/fd
리소스 집약적인 것 같습니다. 동일한 작업을 수행할 수 있는 다른 방법이 있습니까?
답변1
이 작업을 수행할 수 있는 도구는 다음과 같습니다.fuser
(출력 PID만 해당) 및lsof
(많은 옵션과 아름다운 출력).
/proc/{PID}/fd의 모든 PID를 반복하는 데 리소스가 많이 소요되는 것 같습니다.
어쨌든 이것이 Linux에서는 유일한 방법입니다. 어떤 프로세스에서 파일이 열려 있는지 쿼리하는 시스템 호출이 없습니다. 하지만 직접 이 작업을 수행하지 마세요. /proc/{PID}/fd
이는 엄밀히 말하면 파일을 여는 것뿐이고 메모리 매핑된 파일, 디렉터리 열기 등과 같은 다른 사례는 나열하지 않기 때문입니다.
이는 파일을 소유하고 있더라도 루트로 검색하지 않는 한 다른 사용자로 실행 중인 프로세스가 파일을 열 수 있는지 알 수 없음을 의미합니다. (그러나 다른 사용자가 파일을 볼 수도 없고 파일이 생성되거나 시스템이 다시 시작된 이후에도 해당 파일을 볼 수 없다면 그러한 프로세스가 존재하지 않는 것입니다.)
더 일반적으로는 사용자가 제어할 수 없는 프로세스이며, 여기에는 다른 네임스페이스에서 실행되거나 추가 권한이 있는 프로세스와 같은 다른 상황이 포함될 수 있습니다.
답변2
사용 lsof
.
예를 들어:
[root@nagios01 objects]# lsof /var/lib/mysql/ib_logfile0
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
mysqld 17699 mysql 9uW REG 8,3 5242880 4850251 /var/lib/mysql/ib_logfile0
다른 예시:
merlin@uc-s4m75657:~/Experiments/test_ifxr$ lsof -a .
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
bash 8646 merlin cwd DIR 254,2 4096 421348 .
bash 9261 merlin cwd DIR 254,2 4096 421348 .
ssh 37456 merlin cwd DIR 254,2 4096 421348 .
bash 38639 merlin cwd DIR 254,2 4096 421348 .
lsof 38679 merlin cwd DIR 254,2 4096 421348 .
lsof 38680 merlin cwd DIR 254,2 4096 421348 .
보시다시피, 이 경우 "현재 디렉터리"(즉, 점이 가리키는 곳)는 6개의 프로세스에 의해 요구됩니다.
마지막 예는 또한 "PID"가 아니라 동시에 여러 PID일 수 있음을 보여줍니다. 또 다른 예는 여러 작업자 프로세스에서 동시에 읽는 경우가 많은 PostgreSQL 데이터 파일입니다.
편집기에서 파일을 열면 lsof 출력에 표시되지 않습니다. 예를 들어, 편집자는 파일을 캐시하고 열기/저장 작업 중에만 해당 파일을 터치할 수 있으며, 이때는 lsof에서 볼 수 있습니다.
답변3
다음 질문에 대한 내 의견을 바탕으로완전히 종료되지 않은 프로세스를 확인해야 합니까?조사할 테스트 코드를 만들었습니다.
일부 스레드가 종료되었습니다.adb다른 스레드가 실행되도록 허용하면서 기본 스레드를 종료시키는 프로그램의 소스 코드입니다.
find_processes_using_file.clsof
파일 이름에 대한 참조를 검색할 수 있는 프로그램과 유사한 소스 코드입니다 . 명령줄 옵션에서 다음을 수행할 수 있습니다.
- 반복하여 PID로 검색
/proc/<pid>/fd
- 반복하여 TID로 검색
/proc/<pid>/task/<tid>/fd
테스트 하니스의 두 인스턴스가 시작되었습니다 partial_thread_exit
. 그러면 /dev/shm/IBV_MESSAGE_BW_IN_USE
.first 인스턴스라는 기본 스레드와 다른 스레드가 계속 실행됩니다.
$ ./partial_thread_exit
Blocker_Task tid 17995 running in pid 17994
Main thread in pid 17994 - press return to exit main thread only
다른 스레드 하나만 실행되도록 두 번째 인스턴스를 그대로 둡니다. 즉, 기본 스레드가 종료되었습니다.
$ ./partial_thread_exit
Blocker_Task tid 13435 running in pid 13434
Main thread in pid 13434 - press return to exit main thread only
Main thread exiting...
PID로 검색을 실행하면 일반 사용자 또는 루트로 실행하는지 여부에 관계없이 메인 스레드에서 실행 중인 프로세스만 찾을 수 있습니다.
$ time ./find_processes_using_file /dev/shm/IBV_MESSAGE_BW_IN_USE
/proc/17994/fd/3 -> /dev/shm/IBV_MESSAGE_BW_IN_USE
num_filenames_compared=2532 num_eacces_errors=260
real 0m0.019s
user 0m0.003s
sys 0m0.015s
$ time sudo ./find_processes_using_file /dev/shm/IBV_MESSAGE_BW_IN_USE
/proc/17994/fd/3 -> /dev/shm/IBV_MESSAGE_BW_IN_USE
num_filenames_compared=3435 num_eacces_errors=0
real 0m0.044s
user 0m0.011s
sys 0m0.031s
그리고 이 옵션을 사용하여 TID로 검색을 실행하면 -t
일반 사용자 또는 루트로 실행하는지 여부에 관계없이 메인 스레드가 있는 프로세스와 메인 스레드가 종료된 프로세스를 찾을 수 있습니다.
$ time ./find_processes_using_file -t /dev/shm/IBV_MESSAGE_BW_IN_USE
/proc/13434/task/13435/fd/3 -> /dev/shm/IBV_MESSAGE_BW_IN_USE
/proc/17994/task/17994/fd/3 -> /dev/shm/IBV_MESSAGE_BW_IN_USE
num_filenames_compared=68327 num_eacces_errors=317
real 0m0.254s
user 0m0.036s
sys 0m0.217s
$ time sudo ./find_processes_using_file -t /dev/shm/IBV_MESSAGE_BW_IN_USE
/proc/13434/task/13435/fd/3 -> /dev/shm/IBV_MESSAGE_BW_IN_USE
/proc/17994/task/17994/fd/3 -> /dev/shm/IBV_MESSAGE_BW_IN_USE
num_filenames_compared=69500 num_eacces_errors=0
real 0m0.280s
user 0m0.048s
sys 0m0.228s
예상대로 TID로 검색하는 것은 아래와 같이 PID로 검색하는 것보다 느립니다.
- 더 많은 실시간 보고서
time
- 보고되는 더 큰 값은
num_filenames_compared
PID/TID와 일치해야 하는 열린 파일 수입니다.
분명히 둘 사이의 절대적인 차이는 시스템에서 실행되는 총 TID/PID 수에 따라 달라집니다.
num_eacces_errors
일반 사용자로 실행할 때 PID/TID에 대한 디렉터리 열기 시도가 실패하고 표시되면 값은 0이 아닙니다. 즉, 특정 프로세스에서 어떤 파일을 열었는지 확인할 수 있는 권한이 몇 번이나 없었습니까?fd
EACCES
답변4
커널에는 직접적인 방법이 없다는 점을 고려하면 매우 원시적인 방법이 있다. 각 파일이 저장되는 파일 시스템에서는 pid가 될 수 있는 프로세스 참조와 참조 카운트를 생성해야 하며, 여기에는 struct inode를 수정하는 작업도 포함됩니다. 그러나 여기에는 참조와 카운트를 각각 채우고 삭제하는 시작 시스템 호출과 종료 시스템 호출을 수정하는 작업이 포함됩니다. 구조체 inode는 현재 마지막 액세스 및 마지막 수정 타임스탬프와 같은 타임스탬프를 유지 관리하며 이 목적을 위해 동일한 타임스탬프를 추적할 수 있습니다. fstat와 같은 시스템 호출은 나중에 이 프로세스 참조를 반환하도록 수정될 수 있습니다. 이는 파일 시스템 및 커널 시스템 호출을 수정해야 하는 등 몇 가지 단점이 있습니다. 대상에 따라(임베디드 장치인 경우) 이것이 가능할 수도 있습니다. 공개 및 종료 호출을 통한 참조 변경에는 동기화가 필요할 가능성이 높습니다. 드문 경우를 제외하고는 이는 절대 불가능합니다. 여기에는 이 패치에 대한 커널 업그레이드도 포함됩니다. 너무 많은 프로세스가 파일에 액세스하고 참조 목록이 커지는 등 고려해야 할 몇 가지 요소가 있을 수 있습니다. 이는 애플리케이션 관련 문제입니다.