Linux · POSIX C · 파일시스템 지원 여부 확인

파일 크기와 디스크 공간 확보는 다릅니다

ftruncate와 posix_fallocate를 구분하고, 반환값에 들어 있는 오류 번호를 올바르게 처리합니다.

파일을 크게 만드는 것만으로 공간이 확보되지는 않습니다

ftruncate로 파일 길이를 늘려도 확장된 영역이 실제 디스크 블록으로 모두 할당된다는 보장은 없습니다. 희소 파일을 지원하는 파일시스템에서는 hole로 남을 수 있습니다. 파일의 논리적인 길이와 저장 장치에 확보한 공간은 구분해야 합니다.

작업기대할 수 있는 결과
ftruncate(fd, size)파일의 논리적인 길이를 조절합니다. 길이를 늘렸다고 전체 영역의 블록을 미리 예약하는 것은 아닙니다.
posix_fallocate(fd, offset, len)지정 범위에 필요한 공간을 확보합니다. 성공하면 그 범위의 쓰기가 디스크 공간 부족 때문에 실패하지 않도록 합니다.
fsync(fd)변경 내용을 저장 장치에 반영하는 동작입니다. 공간 예약과는 목적이 다릅니다.

공간을 예약해도 장치 I/O 오류, 잘못된 파일 디스크립터, 신호로 인한 중단 등 다른 쓰기 실패가 모두 사라지는 것은 아닙니다. 데이터가 영구 저장되었다는 보장도 별도로 다뤄야 합니다.

posix_fallocate는 오류 번호를 직접 반환합니다

int error = posix_fallocate(fd, 0, length);
if (error != 0) {
    fprintf(stderr, "posix_fallocate: %s\n", strerror(error));
}

성공하면 0이고, 실패하면 ENOSPC 등의 오류 번호가 반환값입니다. 일반적인 시스템 호출처럼 == -1로 검사하거나 곧바로 perror를 호출하면 다른 오류를 설명할 수 있습니다. errno를 설정하는 fallocate(2)와도 반환 규칙이 다릅니다.

반환값을 확인하는 두 방식
  1. posix_fallocate반환값 0: 성공 / 0이 아님: 그 값이 오류 번호
  2. 일반적인 -1·errno 방식반환값 -1을 확인한 뒤 errno를 읽습니다.

상자는 실행 순서가 아니라 API 반환 규칙의 비교입니다. 같은 파일 할당 작업이라도 함수별 규칙을 확인해야 합니다.

새 임시 파일에 1MiB를 확보합니다

#define _POSIX_C_SOURCE 200809L
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>

int main(void)
{
    char name[] = "./preallocate-XXXXXX";
    int fd = mkstemp(name);
    if (fd == -1) { perror("mkstemp"); return 1; }
    if (unlink(name) == -1) {
        perror("unlink"); close(fd); return 1;
    }
    int error = posix_fallocate(fd, 0, 1024 * 1024);
    if (error != 0) {
        fprintf(stderr, "posix_fallocate: %s\n", strerror(error));
        close(fd);
        return 1;
    }
    struct stat st;
    if (fstat(fd, &st) == -1) {
        perror("fstat"); close(fd); return 1;
    }
    printf("logical size=%lld bytes\n", (long long)st.st_size);
    if (close(fd) == -1) { perror("close"); return 1; }
    return 0;
}

cc -std=c17 -Wall -Wextra preallocate.c -o preallocate로 빌드합니다. 실행하는 디렉터리의 파일시스템에 임시 파일을 만듭니다. 성공하면 논리 크기 1048576바이트를 출력하고, 마지막 열린 참조를 닫을 때 파일 공간을 회수합니다.

코드상태 변화
mkstemp기존 파일을 덮어쓰지 않고 새 임시 파일을 만듭니다. 수정 가능한 문자 배열로 이름을 전달합니다.
unlink디렉터리의 이름을 제거합니다. fd가 열려 있으므로 파일 객체는 계속 사용할 수 있습니다.
posix_fallocate빈 파일의 처음 1MiB에 공간을 확보합니다. 파일 크기도 그 범위까지 늘어납니다.
fstatfd가 가리키는 파일의 크기를 읽습니다.
close이 예제의 마지막 열린 참조를 닫습니다.

파일시스템과 C 라이브러리의 차이를 확인합니다

파일시스템이 직접 할당 기능을 지원하지 않을 때 일부 C 라이브러리는 다른 방식으로 동작을 흉내 낼 수 있습니다. glibc의 대체 구현에는 동시 쓰기·크기 변경과의 경쟁 문제가 있으므로, 여러 스레드가 이미 쓰는 파일에 무조건 안전하다고 설명하면 안 됩니다. 위 예제는 새 파일을 만든 한 프로세스가 먼저 공간을 확보합니다.

Linux 전용 fallocate는 KEEP_SIZE 등 추가 동작을 제공하지만, 지원하는 모드는 파일시스템마다 다릅니다. 지원하지 않는다는 오류를 받았을 때의 처리도 정해야 합니다.

확인한 문서

Linux · POSIX C · 파일시스템 지원 여부 확인