APUE에 보니까 그 이유가 나와있네요. 테스트를 해 보기 위해서 a.out 을 a.out2 라는 파일로 복사해 보았습니다. 코드 상에 O_TRUNC 가 있어서 cp를 통해 a.out 을 a.out2 로 복사해 놓아도 open이 되면 0 byte로 변하게 되어서 여전히 Bus Error가 발생했습니다. 복사하려는 파일보다 더 큰 크기를 가지는 파일을 대상파일로 설정해 보았습니다. 이 경우도 O_TRUNC는 빼 놓았구요. % cp biggerfile cli.d 정상수행됐지만 대상파일의 크기가 이전파일크기를 그대로 유지하네요. 예상됐던 결과지요. 아마 cli.d 의 앞쪽 9888 바이트만큼은 cli와 동일하겠죠? 결론. 해당 원문입니다. 참조하세요. Program 12.14 copies a file (similar to the cp(1) command) using memory mapped I/O. We first open both files and then call fstat to obtain the size of the input file. We need this size fo the call to mmap for the input file, plus we need to set the size of the output file. We call lseek and then write one byte to set the size of the output file. If we don't set the output file's size, the call to mmap for the output file is OK, but the fist reference to the associated memory region generates SIGBUS. ...
pp. 411-413 까지에 mmap을 이용한 파일복사 예제가 나와있는데,
output 파일의 사이즈를 설정할 필요가 있다고 합니다.
파일의 사이즈를 설정한다고 하는 것이 제가 생각하기로는 그 파일을 위한 공간을 할당한다는 의미로 해석을 해야 하는 것 같습니다. (사용자가 파일연산을 통하지 않고 곧바로 stat 정보의 file size 를 변경할 수 없지 않나요?)
포인터를 사용해서 strcpy() 를 할 때, 대상 포인터가 가리키는 영역이 미리 할당되어 있어야 하는 것과 비슷한 생각이 드는데요. 여기서 포인터가 mmap한 주소가 되겠고, 실제파일영역이 mmap을 통해서 가리키는 저장공간이 되겠죠.
% cp a.out a.out2
% a.out a.out a.out2
=> Bus Error
open의 O_TRUNC를 빼고 다시 컴파일해서 수행했더니 정상수행됐습니다.
% ls -al cli cli.d
...
-rwxr-xr-x 1 ... 9888 1월 5일 1853 cli
-rw------- 1 ... 23720 3월 29일 1619 cli.d
% a.out cli cli.d
...
-rwxr-xr-x 1 ... 9888 1월 5일 1853 cli
-rw------- 1 ... 23720 3월 29일 1619 cli.d
정상 수행을 위해서는 O_TRUNC 옵션을 빼면 안 되겠고,
대상 파일크기 설정을 위해서는 대상파일이 원본파일만큼 크기를 가지도록 보장해 주어야 하겠고, lseek() 후 맨 끝에 한바이트 써주는 식으로 해주면 된다.
mmap : bus error
2011. 7. 26. 13:47