리눅스 서버에서 Device or Resource Busy 오류가 발생하는 원인과 해결 방법

리눅스 Device or Resource Busy 오류와 프로세스 점유 확인 방법

작성자

카테고리:

리눅스 서버에서 디렉터리를 삭제하거나 디스크를 마운트 해제하려고 할 때 Device or Resource Busy 오류가 발생해 작업이 중단된 경험이 있으신가요? 특히 백업 작업이 끝난 뒤 외장 디스크를 분리하거나, Docker 컨테이너를 정리하고 디렉터리를 삭제하는 과정에서 이런 오류가 나타날 수 있습니다.

분명 사용 중인 프로그램이 없어 보이는데도 umount나 rm 명령이 실패하면 파일 권한이나 디스크 자체의 문제부터 의심하기 쉽습니다. 하지만 실제로는 다른 프로세스가 해당 경로를 열어두었거나, 현재 작업 디렉터리로 사용하거나, 하위 마운트가 남아 있는 경우가 많습니다.

이럴 때 무작정 kill -9으로 프로세스를 종료하거나 강제 마운트 해제를 시도하면 운영 중인 서비스와 데이터에 영향을 줄 수 있습니다. 따라서 먼저 어떤 자원이 사용 중인지 확인하고, 점유 원인에 맞는 방법으로 안전하게 해제해야 합니다.

이번 글에서는 Device or Resource Busy 오류가 발생하는 대표적인 상황을 구분하고, lsof, fuser, findmnt를 이용한 점검부터 프로세스 종료, 마운트 해제, Docker 환경 점검까지 실제 해결 순서대로 살펴봅니다.

Device or Resource Busy 핵심 명령어 한눈에 보기

오류가 발생한 경로가 /mnt/data라고 가정하면 다음 명령어부터 확인할 수 있습니다.

점검 목적 명령어
열린 파일 확인 sudo lsof +D /mnt/data
마운트 사용 프로세스 sudo fuser -vm /mnt/data
마운트 상태 확인 findmnt -R /mnt/data
현재 작업 위치 확인 pwd
프로세스 상세 정보 ps -fp PID

lsof +D는 지정한 디렉터리 아래를 재귀적으로 탐색하므로 파일이 많은 경로에서는 실행 시간이 길어질 수 있습니다. 마운트 해제가 목적이라면 fuser -vm과 findmnt를 먼저 확인하는 편이 효율적입니다.

Device or Resource Busy 오류 발생 후 fuser 명령어로 마운트 지점을 사용 중인 프로세스를 확인하는 예시입니다.

1. Device or Resource Busy 오류가 발생하는 이유

Device or Resource Busy는 리눅스에서 주로 EBUSY 오류에 해당합니다. 요청한 작업을 처리하려는 시점에 커널이 해당 자원을 사용 중이라고 판단해 작업을 거부하는 상황입니다.

다만 같은 오류 메시지라도 실행한 명령어에 따라 원인은 달라집니다.

  • umount 실패: 열린 파일, 작업 디렉터리, 하위 마운트 등이 남아 있는 경우
  • rm 또는 rmdir 실패: 삭제 대상이 마운트 지점이거나 커널이 사용 중인 특수 경로인 경우
  • mv 실패: 마운트 지점이나 사용 중인 특수 자원을 이동하려는 경우
  • Docker 작업 실패: 컨테이너의 볼륨이나 Bind Mount가 남아 있는 경우
  • 네트워크 스토리지: NFS 등의 연결 상태나 마운트 참조가 정리되지 않은 경우

중요한 점은 일반 파일이 다른 프로세스에서 열려 있다는 이유만으로 항상 rm이 실패하는 것은 아니라는 것입니다. 리눅스에서는 열린 일반 파일도 삭제할 수 있으며, 파일을 사용 중인 프로세스가 종료될 때까지 실제 저장 공간이 유지될 수 있습니다.

따라서 어떤 명령에서 오류가 발생했는지 먼저 구분해야 불필요한 프로세스 종료나 권한 변경을 피할 수 있습니다.

2. lsof와 fuser로 자원을 사용하는 프로세스 찾기

마운트 지점이나 디렉터리를 사용 중인 프로세스를 찾으려면 lsof와 fuser를 사용할 수 있습니다.

먼저 디렉터리 아래에 열린 파일이 있는지 확인합니다.

sudo lsof +D /mnt/data

다음은 출력 예시입니다.

COMMAND  PID   USER  FD   TYPE  NAME
bash     2451  root  cwd  DIR   /mnt/data
python3  3180  app   5r   REG   /mnt/data/report.csv

여기서 확인해야 할 부분은 COMMAND, PID, FD, NAME입니다.

  • bash / 2451 / cwd: Bash 프로세스가 해당 디렉터리를 현재 작업 위치로 사용
  • python3 / 3180 / 5r: Python 프로세스가 파일을 읽기 모드로 열어둔 상태

마운트 지점을 기준으로 사용 중인 프로세스를 확인하려면 다음 명령어도 유용합니다.

sudo fuser -vm /mnt/data

출력 결과는 환경에 따라 다음과 비슷하게 나타납니다.

                     USER   PID ACCESS COMMAND
/mnt/data:           root  2451 ..c.. bash
                     app   3180 f.... python3

ACCESS에 표시되는 c는 현재 작업 디렉터리, f는 열린 파일과 관련된 사용 상태를 의미합니다.

다만 lsof와 fuser 결과가 비어 있다고 해서 마운트가 완전히 해제 가능한 상태라고 단정할 수는 없습니다. 하위 마운트, 다른 마운트 네임스페이스, 커널 수준의 참조 등도 확인해야 합니다.

3. 현재 작업 디렉터리와 하위 마운트 확인하기

터미널에서 마운트 지점 안으로 이동한 상태라면 해당 셸 자체가 마운트 해제를 방해할 수 있습니다.

예를 들어 다음과 같은 상황입니다.

cd /mnt/data
sudo umount /mnt/data

이때 다음 오류가 발생할 수 있습니다.

umount: /mnt/data: target is busy.

먼저 현재 작업 디렉터리를 확인합니다.

pwd

현재 위치가 마운트 지점 내부라면 다른 디렉터리로 이동합니다.

cd /
sudo umount /mnt/data

단, 다른 터미널이나 프로세스가 같은 마운트를 사용 중이라면 현재 셸만 이동해도 문제가 해결되지 않을 수 있습니다.

또한 마운트 지점 아래에 다른 파일시스템이 연결되어 있다면 상위 마운트를 해제하기 전에 하위 마운트를 먼저 확인해야 합니다.

findmnt -R /mnt/data

예를 들어 다음과 같이 표시될 수 있습니다.

TARGET            SOURCE      FSTYPE
/mnt/data         /dev/sdb1   ext4
/mnt/data/backup  /dev/sdc1   ext4

이 경우 /mnt/data/backup에 연결된 파일시스템부터 안전하게 해제한 뒤 상위 마운트를 점검해야 합니다.

4. 사용 중인 프로세스를 안전하게 종료하는 방법

fuser나 lsof로 PID를 확인했다면 먼저 해당 프로세스가 무엇인지 검증해야 합니다.

ps -fp 3180

서비스로 관리되는 프로세스라면 직접 PID를 종료하기보다 해당 서비스의 상태를 확인하는 것이 우선입니다.

sudo systemctl status 서비스명

정지해도 되는 서비스인지 확인했다면 정상적인 서비스 종료를 사용합니다.

sudo systemctl stop 서비스명

직접 실행한 프로세스라면 정상 종료 신호인 SIGTERM을 보낼 수 있습니다.

sudo kill -15 3180

프로세스가 종료됐는지 확인한 뒤 다시 마운트 해제를 시도합니다.

ps -p 3180
sudo fuser -vm /mnt/data
sudo umount /mnt/data

SIGTERM으로 종료되지 않는 경우에도 바로 강제 종료하기보다는 작업 상태와 서비스 영향을 확인해야 합니다.

kill -9는 정상 종료 처리를 거치지 못하게 하므로 데이터 쓰기 작업이 진행 중인 프로세스에는 특히 주의가 필요합니다. 또한 커널의 중단 불가능한 대기 상태인 D 상태의 프로세스는 SIGKILL을 보내도 즉시 종료되지 않을 수 있습니다.

5. Docker와 NFS 환경에서 오류가 발생하는 경우

Docker 컨테이너가 호스트 디렉터리를 Bind Mount로 사용하고 있다면 호스트에서 해당 경로를 정리하려 할 때 마운트 관련 충돌이 발생할 수 있습니다.

먼저 실행 중인 컨테이너를 확인합니다.

docker ps

특정 컨테이너의 마운트 설정을 확인하려면 다음과 같이 실행합니다.

docker inspect 컨테이너명 --format '{{json .Mounts}}'

해당 경로를 사용 중인 컨테이너가 확인됐다면 실제 운영 서비스에 영향을 주지 않는지 검토한 뒤 컨테이너를 정상적으로 중지하거나 마운트 설정을 수정해야 합니다.

docker stop 컨테이너명

NFS 같은 네트워크 파일시스템에서는 서버 연결 문제, 응답 지연, 마운트 참조 등으로 해제가 어려울 수 있습니다.

findmnt -T /mnt/data
sudo fuser -vm /mnt/data

이때 마운트 해제를 무리하게 반복하거나 파일을 사용 중인 프로세스를 일괄 종료하기보다는 네트워크 파일시스템의 연결 상태와 작업 중인 서비스를 함께 확인해야 합니다.

6. umount -l 또는 강제 해제를 사용해도 될까?

일반적인 마운트 해제가 실패할 때 umount -l 또는 umount -f를 해결 방법으로 소개하는 경우가 있습니다. 하지만 두 옵션은 의미와 적용 범위가 다릅니다.

umount -l은 Lazy Unmount로, 파일시스템을 현재 마운트 계층에서 분리하고 남아 있는 참조가 해제되면 정리를 완료하는 방식입니다.

sudo umount -l /mnt/data

이는 해당 파일시스템을 사용 중인 모든 프로세스가 종료됐다는 의미가 아닙니다. 따라서 일반적인 장애 해결 방법으로 무조건 사용하는 것은 권장하지 않습니다.

umount -f는 강제 해제 옵션이지만 모든 파일시스템에서 동일하게 동작하는 것은 아니며, 특히 응답하지 않는 네트워크 파일시스템 등에서 신중하게 검토해야 합니다.

sudo umount -f /mnt/data

운영 서버에서는 프로세스 점유 확인 → 서비스 정상 종료 → 하위 마운트 확인 → 일반 umount 재시도를 먼저 수행하고, Lazy 또는 강제 해제는 위험과 복구 절차를 이해한 경우에만 검토하는 것이 안전합니다.

실전 점검 순서

예를 들어 /mnt/data를 마운트 해제할 때 target is busy 오류가 발생했다면 다음 순서로 점검합니다.

# 1. 마운트 구조 확인
findmnt -R /mnt/data

# 2. 사용 중인 프로세스 확인
sudo fuser -vm /mnt/data

# 3. 열린 파일 확인
sudo lsof +D /mnt/data

# 4. PID 확인 후 상세 정보 조회
ps -fp 3180

# 5. 현재 작업 위치 변경
cd /

# 6. 원인을 해결한 뒤 다시 마운트 해제
sudo umount /mnt/data

# 7. 마운트 해제 여부 확인
findmnt -M /mnt/data

위 명령에서 PID 3180은 예시이므로 실제 서버에서 확인한 PID로 변경해야 합니다. 또한 프로세스를 종료하거나 마운트를 해제하기 전에는 서비스 영향과 데이터 쓰기 상태를 반드시 확인해야 합니다.

정리

리눅스 서버에서 Device or Resource Busy 오류가 발생했다면 단순한 파일 권한 문제로 판단하기보다 어떤 작업에서 오류가 발생했는지와 어떤 프로세스 또는 마운트가 해당 자원을 사용 중인지 확인하는 것이 우선입니다.

마운트 해제 오류라면 findmnt로 마운트 구조를 확인하고, fuser와 lsof로 사용 중인 프로세스를 추적합니다. 그다음 서비스의 정상 종료나 작업 디렉터리 변경 등으로 원인을 해결한 뒤 umount를 다시 실행하면 됩니다.

특히 kill -9, umount -l, umount -f 같은 명령은 상황에 따라 운영 중인 서비스에 영향을 줄 수 있으므로 원인을 확인하지 않은 상태에서 바로 실행하지 않는 것이 중요합니다.

코멘트

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다