content: Report inotify modifications before close

MERGED2026contentfile_system_accessfix
2026. 9. 2.zbnerd 프로필 이미지zbnerd

Linux의 FilePathWatcher가 파일 디스크립터를 닫기 전에도 파일 쓰기를 감지하도록 inotify 이벤트 구독을 수정하고, 열린 파일에 대한 변경 알림을 검증하는 회귀 테스트를 추가했습니다.

문제 설명

기존 구현은 쓰기 가능한 파일 디스크립터가 닫힐 때 발생하는 IN_CLOSE_WRITE를 구독하고 있었습니다. 따라서 네이티브 프로그램이 파일 디스크립터를 오랫동안 열어 둔 채 write()를 호출하면, 실제 파일 내용이 바뀌어도 닫기 전까지 관찰자에게 변경 알림이 전달되지 않았습니다.

  • 이벤트 처리 코드에는 IN_MODIFY를 수정 이벤트로 분류하는 분기가 있었지만, inotify_add_watch()의 구독 마스크에는 해당 이벤트가 빠져 있었습니다.
  • 기존 ModifiedFile 단위 테스트는 파일을 쓴 뒤 디스크립터를 닫는 WriteFile()을 사용하므로, IN_CLOSE_WRITE만 구독해도 통과했습니다.
  • 리뷰에서 확인한 WPT의 writable stream 테스트도 스트림을 닫은 뒤의 변경 알림을 검증하므로, 네이티브 쓰기 이후 디스크립터를 계속 열어 두는 상황을 포착하지 못했습니다.

해결 내용

최신 Patch Set 5에서는 다음 두 파일을 수정했습니다.

  1. content/browser/file_system_access/file_path_watcher/file_path_watcher_inotify.cc

    감시 이벤트를 IN_CLOSE_WRITE에서 IN_MODIFY로 바꾸어 파일 쓰기 시점에 알림을 받을 수 있도록 했습니다. 수정 이벤트를 분류하는 조건에서도 IN_CLOSE_WRITE를 제거하여, 쓰기 후 파일을 닫을 때 추가 수정 알림이 발생하는 것을 방지했습니다.

    -      IN_CREATE | IN_DELETE | IN_CLOSE_WRITE | IN_MOVE | IN_ONLYDIR);
    +      IN_CREATE | IN_DELETE | IN_MODIFY | IN_MOVE | IN_ONLYDIR);
    
    -  } else if (event_mask & (IN_MODIFY | IN_CLOSE_WRITE)) {
    +  } else if (event_mask & IN_MODIFY) {
  2. content/browser/file_system_access/file_path_watcher/file_path_watcher_unittest.cc

    Linux와 ChromeOS에서 실행하는 FilePathWatcherWithChangeInfoTest.ModifiedFileWhileOpen 테스트를 추가했습니다. base::File로 파일을 열어 쓰고, 파일을 닫기 전에 수정 알림을 기다리도록 구성했습니다. 이를 위해 base/containers/span.hbase/files/file.h도 추가했습니다.

리뷰에서는 IN_MODIFYIN_CLOSE_WRITE를 함께 구독하는 방안도 논의했습니다. 작성자의 확인에 따르면 일반적인 쓰기 후 닫기 순서에서 두 번의 수정 알림이 발생할 수 있고, 현재 FSA 관찰 경로에는 이를 일반적으로 제거하는 중복 제거 처리가 없습니다. 최신 패치는 IN_MODIFY만 구독하는 형태를 유지합니다.

또한 IN_CLOSE_WRITE 제거가 writable mmap의 기존 닫기 기반 알림에 영향을 줄 수 있다는 점을 논의했습니다. 작성자는 이를 별도 변경 경로로 구분하여 후속 이슈와 회귀 테스트로 다루겠다고 밝혔으며, 이 CL에서 해결된 범위에는 포함하지 않았습니다.

테스트 방법

아래 내용은 Gerrit에 올라온 회귀 테스트와 리뷰·CQ 기록을 기준으로 정리했습니다. 보고서 작성 과정에서 Chromium 빌드나 해당 테스트를 새로 실행한 것은 아닙니다.

  1. 파일을 닫기 전 수정 알림 검증

    ModifiedFileWhileOpen은 초기 파일을 생성하고 감시를 등록한 뒤, base::File을 쓰기 모드로 열어 내용을 변경합니다. writer.Close()보다 먼저 RunUntilEventsMatch(matcher)를 호출하여, 열린 디스크립터에 대한 쓰기만으로 수정 알림이 도착하는지 검증합니다.

  2. 닫기 시 추가 알림 검증

    쓰기 알림을 받은 뒤 남아 있는 이벤트를 처리하고 파일을 닫습니다. 이어서 SpinAndExpectNoEvents()로 닫기 때문에 추가 알림이 발생하지 않는지 확인합니다. 최신 테스트는 알림 지연 문제뿐 아니라 패치가 선택한 중복 알림 방지 동작도 검증합니다.

  3. 리뷰 중 수동 확인

    작성자는 Linux의 실제 FilePathWatcher와 FSA 관찰 경로에서 열린 디스크립터에 대한 쓰기 알림 및 반복 쓰기에 따른 반복 콜백을 확인했다고 보고했습니다. writable mmap에 대한 관찰은 기존 회귀 테스트 결과가 아니라 별도의 수동 테스트 결과라고 명시했습니다.

  4. Chromium CQ 결과

    Gerrit 기록상 Patch Set 5는 2026년 9월 2일과 9월 11일의 CQ dry run을 통과했으며, 9월 12일 UTC에 CQ full run이 시작되었습니다.

배운 점

  • 이벤트를 처리하는 분기가 존재하더라도, 운영체제에 해당 이벤트를 구독하지 않으면 알림을 받을 수 없습니다. 감시 등록과 이벤트 분류를 함께 확인해야 합니다.
  • 회귀 테스트에서는 파일 쓰기뿐 아니라 파일 디스크립터의 수명도 중요합니다. 자동으로 파일을 닫는 헬퍼만 사용하면 닫기 이전의 알림 누락을 놓칠 수 있습니다.
  • 웹의 writable stream 테스트와 네이티브 파일 쓰기 테스트는 검증하는 경로가 다릅니다. 리뷰에서는 네이티브 쓰기를 수행하는 테스트 API의 필요성도 제기되었고, 관련 후속 이슈가 공유되었습니다.
  • 알림 시점을 앞당길 때는 반복 콜백과 닫기 시 중복 알림도 함께 고려해야 합니다. 디바운싱이나 플랫폼 간 알림 정책까지 바꾸는 작업은 별도 범위로 검토할 필요가 있습니다.
  • CQ dry run 통과와 최종 병합은 별개의 단계이므로, 기여 기록의 상태는 실제 Gerrit 상태에 맞춰 관리해야 합니다.

참고 자료