Watch at Ease세상을 읽고, 일상의 답을 찾다.

기술 · 실용 가이드

Linux “Text file busy” 오류: 덮어쓰기나 재시도 전에 실행 중 inode를 확인하세요

ETXTBSY는 배포가 실행 중인 파일을 쓰려 했거나, 실행기가 아직 쓰기 모드로 열린 파일을 실행하려 했음을 뜻할 수 있습니다. 프로세스를 종료하기 전에 실패한 호출, 프로세스, inode와 네임스페이스를 보존하고 경합을 고치거나 경로를 원자적으로 교체합니다.

실행 중 inode와 차단된 제자리 덮어쓰기 도식
오리지널 일러스트: 경로를 바꾸기 전에 실행 중 inode를 증명합니다. Watch at Ease

ETXTBSY는 배포가 실행 중인 파일을 쓰려 했거나, 실행기가 아직 쓰기 모드로 열린 파일을 실행하려 했음을 뜻할 수 있습니다. 프로세스를 종료하기 전에 실패한 호출, 프로세스, inode와 네임스페이스를 보존하고 경합을 고치거나 경로를 원자적으로 교체합니다.

실행 파일이 쓰기 모드로 열려 있으면 execve()가 ETXTBSY를 반환할 수 있습니다. 같은 inode가 실행 중이면 쓰기나 truncate가 거부될 수 있습니다.

1. 방향·경로·inode를 보존하세요

전체 오류, 시각, 명령, PID, 컨테이너 또는 mount 네임스페이스와 실패한 작업을 기록합니다. exec, open, truncate, copy, rename을 구분하고 재시작 전에 stat으로 장치와 inode를 저장합니다.

재부팅, pkill -f 또는 무제한 재시도부터 하지 마세요. 교체 후 같은 경로가 다른 inode를 가리킬 수 있고 컨테이너가 호스트 소유자를 못 볼 수 있으므로 실패한 네임스페이스의 inode를 비교합니다.

2. 올바른 네임스페이스에서 실행자나 작성자를 증명하세요

실행 중 파일이 의심되면 /proc/<pid>/exe와 좁은 fuser -v 증거를 확인합니다. 실행 표시와 쓰기 표시는 서로 다른 질문에 답하므로 권한을 지키고 무관한 명령줄이나 경로를 공개하지 않습니다.

exec 실패라면 쓰기 가능한 디스크립터를 보유한 프로세스와 대상·플래그를 확인합니다. close-on-exec가 없는 디스크립터는 동시 spawn으로 자식에게 상속될 수 있으므로 부모와 자식을 보고 증명된 소유자만 중지합니다.

3. 쓰기 후 실행 경합을 숨기지 말고 고치세요

최소 순서를 재현합니다. 같은 디렉터리에 새 파일을 만들고 모두 쓴 뒤 mode를 설정하고 닫은 다음 실행합니다. 병렬 부하에서는 캐시 추출을 직렬화하거나 버전별 임시 경로를 사용합니다.

원인 지점에서 디스크립터 수명을 고치고 적절하면 close-on-exec를 사용합니다. ETXTBSY에만 적용되는 짧고 제한된 재시도는 잔여 경합을 줄일 수 있지만 작성자를 닫는 수정의 대안은 아닙니다.

4. 동일 디렉터리 새 파일로 경로를 원자 교체하세요

실행 중 파일을 제자리에서 truncate하지 마세요. 같은 파일 시스템의 새 파일에 쓰고 소유자, mode, hash를 검증해 직접 시험한 뒤 rename으로 대상을 교체합니다. 기존 프로세스는 이전 inode로 계속 실행됩니다.

충돌 내구성이 필요하면 애플리케이션이 요구하는 파일·디렉터리 동기화도 합니다. rename 뒤 대상 서비스만 재시작하거나 reload하고 롤백용 이전 산출물을 즉시 지우지 않습니다.

5. 프로세스와 inode 증거로 복구를 승인하세요

새 PID의 /proc/<pid>/exe가 기대 경로, 장치, inode와 내용 hash에 맞는지 확인합니다. 이전 PID를 배출할 때까지 둔다면 이전 inode를 계속 참조하는지도 확인합니다.

과거 ETXTBSY를 일으킨 동시 쓰기·실행 시험을 수행합니다. busy 오류 없음, 남은 쓰기 디스크립터 없음, 올바른 권한과 hash, 검증된 롤백이 승인 조건입니다. 실패하면 이전 경로를 복원합니다.

검증한 새 파일을 원자 rename하는 도식
오리지널 일러스트: 새 파일을 검증하고 원자 교체한 뒤 이전 inode를 배출합니다. Watch at Ease