FUSE (Filesystem in Userspace)

유저스페이스에서 파일시스템을 구현할 수 있게 해주는 FUSE 프레임워크의 아키텍처, 커널 모듈 내부, libfuse API, 프로토콜, virtiofs, 성능 최적화, 보안 모델을 종합적으로 다룹니다.

관련 표준: FUSE Protocol (커널 ↔ 유저스페이스 메시지 프로토콜), POSIX.1-2017 (파일 시맨틱) — FUSE는 사용자 공간에서 POSIX 호환 파일시스템을 구현할 수 있게 합니다. 종합 목록은 참고자료 — 표준 & 규격 섹션을 참고하세요.

FUSE 개요

FUSE(Filesystem in Userspace)는 커널 모듈을 직접 작성하지 않고도 유저스페이스 프로그램으로 파일시스템을 구현할 수 있게 해주는 프레임워크입니다. 2005년 Linux 2.6.14에서 mainline에 통합되었으며, 현재까지 수백 개의 FUSE 기반 파일시스템이 활발히 사용되고 있습니다.

유저스페이스 파일시스템이 필요한 이유

FUSE 3계층 구조

FUSE는 세 가지 핵심 컴포넌트로 구성됩니다:

계층컴포넌트역할
커널 fuse.ko 모듈 VFS 요청을 /dev/fuse 디바이스를 통해 유저스페이스로 전달
라이브러리 libfuse (libfuse3) /dev/fuse와의 통신을 추상화, high-level/low-level API 제공
유저스페이스 FUSE 데몬 실제 파일시스템 로직 구현 (sshfs, ntfs-3g 등)

FUSE 아키텍처

FUSE 요청/응답 흐름 User Space Application: open(), read() FUSE Daemon (sshfs 등) libfuse3 (fuse_operations) Kernel Space System Call Interface VFS Layer FUSE Kernel Module (fuse.ko) fuse_conn / fuse_req / /dev/fuse /dev/fuse (char device) read() write() 1. syscall 2. VFS dispatch 3. queue req 4. callback 응답: 역순으로 결과 반환
FUSE 요청/응답 흐름: 애플리케이션 syscall → VFS → FUSE 커널 모듈 → /dev/fuse → libfuse → 유저 데몬

요청/응답 흐름 상세

  1. 애플리케이션이 open(), read() 등 시스템 콜 호출
  2. VFS가 FUSE 파일시스템의 file_operations/inode_operations을 통해 FUSE 커널 모듈로 디스패치
  3. FUSE 커널 모듈이 fuse_req 구조체를 생성하여 fuse_iqueue에 큐잉
  4. 유저 데몬이 /dev/fuse에서 read()로 요청을 가져옴
  5. 유저 데몬이 요청을 처리 (파일 읽기, 네트워크 I/O 등)
  6. 유저 데몬이 /dev/fusewrite()로 응답을 기록
  7. FUSE 커널 모듈이 대기 중인 프로세스를 깨우고 결과 반환

FUSE 커널 모듈 내부

/dev/fuse 디바이스

/dev/fuse는 캐릭터 디바이스(major 10, minor 229)로, FUSE 커널 모듈과 유저스페이스 데몬 간의 통신 채널입니다. 데몬은 이 디바이스를 열어 read()로 요청을 수신하고 write()로 응답을 전송합니다.

/* fs/fuse/dev.c — /dev/fuse file operations */
const struct file_operations fuse_dev_operations = {
    .owner   = THIS_MODULE,
    .open    = fuse_dev_open,
    .read    = fuse_dev_read,      /* 유저 데몬이 요청을 읽음 */
    .write   = fuse_dev_write,     /* 유저 데몬이 응답을 기록 */
    .splice_read  = fuse_dev_splice_read,
    .splice_write = fuse_dev_splice_write,
    .poll    = fuse_dev_poll,
    .release = fuse_dev_release,
    .fasync  = fuse_dev_fasync,
};

fuse_conn (연결 관리)

struct fuse_conn은 하나의 FUSE 마운트와 연결된 유저 데몬 사이의 모든 상태를 관리하는 핵심 구조체입니다.

/* include/linux/fuse.h — 주요 필드 발췌 */
struct fuse_conn {
    unsigned max_read;               /* 최대 read 크기 */
    unsigned max_write;              /* 최대 write 크기 */
    unsigned max_pages;              /* 단일 요청 최대 페이지 수 */
    unsigned max_background;         /* 최대 배경 요청 수 */
    unsigned congestion_threshold;   /* 혼잡 시작 임계치 */
    unsigned num_background;         /* 현재 배경 요청 수 */
    struct fuse_iqueue iq;           /* 입력 큐 (pending 요청) */
    spinlock_t lock;                /* 연결 상태 보호 */
    unsigned minor;                  /* FUSE 프로토콜 마이너 버전 */
    unsigned conn_init:1;           /* FUSE_INIT 완료 여부 */
    unsigned writeback_cache:1;     /* writeback 캐시 활성화 */
    unsigned no_open:1;             /* OPEN 요청 생략 가능 */
    unsigned parallel_dirops:1;     /* 병렬 디렉토리 연산 */
};

fuse_iqueue / fuse_pqueue (요청/응답 큐)

FUSE는 두 가지 큐를 사용하여 요청을 관리합니다:

요청 라이프사이클

/* struct fuse_req 주요 필드 */
struct fuse_req {
    struct list_head list;       /* 큐 연결 */
    u64 unique;                   /* 고유 요청 ID */
    struct fuse_in_header in;     /* 요청 헤더 */
    struct fuse_out_header out;   /* 응답 헤더 */
    wait_queue_head_t waitq;     /* 완료 대기 큐 */
    struct fuse_args *args;       /* 요청/응답 인자 */
    unsigned isreply:1;           /* 응답 필요 여부 */
    unsigned force:1;             /* 연결 중단 시에도 전송 */
    unsigned background:1;        /* 배경 요청 여부 */
};

/*
 * 요청 라이프사이클:
 * 1. fuse_simple_request() / fuse_simple_background()로 생성
 * 2. fuse_iqueue의 pending 리스트에 추가
 * 3. 데몬이 /dev/fuse read()로 요청 수신 → fuse_pqueue로 이동
 * 4. 데몬이 /dev/fuse write()로 응답 → fuse_req 완료
 * 5. 대기 중인 커널 스레드 깨움 → 결과 반환
 */

FUSE 프로토콜

fuse_in_header / fuse_out_header

모든 FUSE 메시지는 헤더로 시작합니다:

/* include/uapi/linux/fuse.h */
struct fuse_in_header {
    uint32_t len;       /* 메시지 전체 길이 (헤더 포함) */
    uint32_t opcode;    /* 작업 코드 (FUSE_LOOKUP, FUSE_READ 등) */
    uint64_t unique;    /* 고유 요청 ID (응답 매칭) */
    uint64_t nodeid;    /* 대상 inode 번호 */
    uint32_t uid;       /* 요청자 UID */
    uint32_t gid;       /* 요청자 GID */
    uint32_t pid;       /* 요청자 PID */
    uint32_t padding;
};

struct fuse_out_header {
    uint32_t len;       /* 응답 전체 길이 */
    int32_t  error;     /* 에러 코드 (0 = 성공, 음수 = errno) */
    uint64_t unique;    /* 요청의 unique와 매칭 */
};

주요 opcode 테이블

Opcode설명
FUSE_LOOKUP1경로명으로 inode 탐색
FUSE_FORGET2inode 참조 카운트 감소 (응답 없음)
FUSE_GETATTR3파일 속성 조회 (stat)
FUSE_SETATTR4파일 속성 변경 (chmod, chown, truncate)
FUSE_OPEN14파일 열기
FUSE_READ15파일 읽기
FUSE_WRITE16파일 쓰기
FUSE_RELEASE18파일 닫기
FUSE_OPENDIR27디렉토리 열기
FUSE_READDIR28디렉토리 목록 읽기
FUSE_RELEASEDIR29디렉토리 닫기
FUSE_MKDIR9디렉토리 생성
FUSE_UNLINK10파일 삭제
FUSE_RMDIR11디렉토리 삭제
FUSE_RENAME12파일/디렉토리 이름 변경
FUSE_LINK13하드 링크 생성
FUSE_SYMLINK6심볼릭 링크 생성
FUSE_CREATE35파일 생성 + 열기 (atomic)
FUSE_STATFS17파일시스템 통계
FUSE_INIT26연결 초기화 (핸드셰이크)
FUSE_DESTROY38연결 종료
FUSE_NOTIFY_REPLY41비동기 알림 응답
FUSE_READDIRPLUS44readdir + lookup 결합 (성능 최적화)

FUSE_INIT 핸드셰이크

마운트 시 커널과 유저 데몬 사이에 FUSE_INIT 메시지를 교환하여 프로토콜 버전과 기능 플래그를 협상합니다:

/* FUSE_INIT 요청/응답 */
struct fuse_init_in {
    uint32_t major;      /* 커널이 지원하는 메이저 버전 (7) */
    uint32_t minor;      /* 커널이 지원하는 마이너 버전 */
    uint32_t max_readahead;
    uint32_t flags;      /* 커널 지원 기능 플래그 */
    uint32_t flags2;     /* 확장 플래그 (7.36+) */
};

struct fuse_init_out {
    uint32_t major;      /* 데몬이 선택한 메이저 버전 */
    uint32_t minor;      /* 데몬이 선택한 마이너 버전 */
    uint32_t max_readahead;
    uint32_t flags;      /* 데몬이 활성화할 기능 */
    uint32_t max_background;
    uint32_t congestion_threshold;
    uint32_t max_write;
    uint32_t max_pages;  /* 7.28+ */
};

/* 주요 기능 플래그 */
#define FUSE_WRITEBACK_CACHE   (1 << 16)  /* writeback 캐시 */
#define FUSE_PARALLEL_DIROPS   (1 << 18)  /* 병렬 디렉토리 연산 */
#define FUSE_PASSTHROUGH       (1 << 26)  /* passthrough I/O (6.9+) */
#define FUSE_DO_READDIRPLUS    (1 << 13)  /* READDIRPLUS 지원 */
#define FUSE_SPLICE_READ       (1 << 7)   /* splice로 읽기 */
#define FUSE_SPLICE_WRITE      (1 << 8)   /* splice로 쓰기 */

FUSE_NOTIFY: 커널 → 유저 비동기 알림

커널은 유저 데몬에 비동기 알림을 보낼 수 있습니다. 이는 캐시 무효화 등에 사용됩니다:

libfuse API

High-level API (경로 기반)

High-level API는 파일 경로를 기반으로 동작하며, 대부분의 FUSE 파일시스템이 이 API를 사용합니다:

/* fuse_operations: high-level API 콜백 테이블 */
struct fuse_operations {
    int  (*getattr)(const char *path, struct stat *st,
                     struct fuse_file_info *fi);
    int  (*readdir)(const char *path, void *buf,
                     fuse_fill_dir_t filler, off_t offset,
                     struct fuse_file_info *fi,
                     enum fuse_readdir_flags flags);
    int  (*open)(const char *path, struct fuse_file_info *fi);
    int  (*read)(const char *path, char *buf, size_t size,
                  off_t offset, struct fuse_file_info *fi);
    int  (*write)(const char *path, const char *buf,
                   size_t size, off_t offset,
                   struct fuse_file_info *fi);
    int  (*mkdir)(const char *path, mode_t mode);
    int  (*unlink)(const char *path);
    int  (*rmdir)(const char *path);
    int  (*rename)(const char *from, const char *to,
                    unsigned int flags);
    int  (*truncate)(const char *path, off_t size,
                      struct fuse_file_info *fi);
    int  (*create)(const char *path, mode_t mode,
                    struct fuse_file_info *fi);
    int  (*release)(const char *path, struct fuse_file_info *fi);
    int  (*fsync)(const char *path, int isdatasync,
                   struct fuse_file_info *fi);
    int  (*statfs)(const char *path, struct statvfs *st);
    void *(*init)(struct fuse_conn_info *conn,
                   struct fuse_config *cfg);
    void (*destroy)(void *private_data);
    /* ... */
};

Low-level API (inode 기반)

Low-level API는 inode 번호(nodeid)를 직접 다루며, 더 세밀한 제어가 가능합니다. 고성능 FUSE 파일시스템에서 사용합니다:

/* fuse_lowlevel_ops: low-level API 콜백 */
struct fuse_lowlevel_ops {
    void (*lookup)(fuse_req_t req, fuse_ino_t parent,
                    const char *name);
    void (*getattr)(fuse_req_t req, fuse_ino_t ino,
                     struct fuse_file_info *fi);
    void (*open)(fuse_req_t req, fuse_ino_t ino,
                  struct fuse_file_info *fi);
    void (*read)(fuse_req_t req, fuse_ino_t ino,
                  size_t size, off_t off,
                  struct fuse_file_info *fi);
    void (*write)(fuse_req_t req, fuse_ino_t ino,
                   const char *buf, size_t size,
                   off_t off, struct fuse_file_info *fi);
    void (*forget)(fuse_req_t req, fuse_ino_t ino,
                    uint64_t nlookup);
    /* ... */
};

/* Low-level API에서 응답은 명시적으로 전송해야 함 */
fuse_reply_entry(req, &entry_param);  /* LOOKUP 응답 */
fuse_reply_buf(req, buf, size);       /* READ 응답 */
fuse_reply_err(req, errno);           /* 에러 응답 */

fuse_session과 이벤트 루프

/* 싱글스레드 이벤트 루프 */
struct fuse_session *se = fuse_session_new(&args, &ops,
                                            sizeof(ops), userdata);
fuse_session_mount(se, mountpoint);
fuse_session_loop(se);               /* 싱글스레드 */

/* 멀티스레드 이벤트 루프 */
struct fuse_loop_config config = {
    .clone_fd = 1,        /* /dev/fuse fd를 복제하여 병렬 처리 */
    .max_idle_threads = 10,
};
fuse_session_loop_mt(se, &config);   /* 멀티스레드 */

FUSE 파일시스템 구현 예제

최소한의 FUSE 파일시스템 예제입니다. 읽기 전용으로 /hello 파일 하나를 제공합니다:

#define FUSE_USE_VERSION 31
#include <fuse3/fuse.h>
#include <string.h>
#include <errno.h>

static const char *hello_str = "Hello, FUSE!\n";
static const char *hello_path = "/hello";

static int hello_getattr(const char *path, struct stat *st,
                          struct fuse_file_info *fi)
{
    (void) fi;
    memset(st, 0, sizeof(struct stat));

    if (strcmp(path, "/") == 0) {
        st->st_mode = S_IFDIR | 0755;
        st->st_nlink = 2;
    } else if (strcmp(path, hello_path) == 0) {
        st->st_mode = S_IFREG | 0444;
        st->st_nlink = 1;
        st->st_size = strlen(hello_str);
    } else {
        return -ENOENT;
    }
    return 0;
}

static int hello_readdir(const char *path, void *buf,
                          fuse_fill_dir_t filler, off_t offset,
                          struct fuse_file_info *fi,
                          enum fuse_readdir_flags flags)
{
    (void) offset; (void) fi; (void) flags;
    if (strcmp(path, "/") != 0)
        return -ENOENT;

    filler(buf, ".",  NULL, 0, 0);
    filler(buf, "..", NULL, 0, 0);
    filler(buf, "hello", NULL, 0, 0);
    return 0;
}

static int hello_open(const char *path,
                       struct fuse_file_info *fi)
{
    if (strcmp(path, hello_path) != 0)
        return -ENOENT;
    if ((fi->flags & O_ACCMODE) != O_RDONLY)
        return -EACCES;
    return 0;
}

static int hello_read(const char *path, char *buf,
                       size_t size, off_t offset,
                       struct fuse_file_info *fi)
{
    size_t len;
    (void) fi;
    if (strcmp(path, hello_path) != 0)
        return -ENOENT;

    len = strlen(hello_str);
    if ((size_t)offset < len) {
        if (offset + size > len)
            size = len - offset;
        memcpy(buf, hello_str + offset, size);
    } else {
        size = 0;
    }
    return size;
}

static const struct fuse_operations hello_oper = {
    .getattr = hello_getattr,
    .readdir = hello_readdir,
    .open    = hello_open,
    .read    = hello_read,
};

int main(int argc, char *argv[])
{
    return fuse_main(argc, argv, &hello_oper, NULL);
}

빌드 및 실행

# 빌드 (libfuse3 필요)
gcc -Wall hello_fuse.c `pkg-config --cflags --libs fuse3` -o hello_fuse

# 마운트 포인트 생성 및 실행
mkdir -p /tmp/fuse_mnt
./hello_fuse /tmp/fuse_mnt

# 테스트
ls /tmp/fuse_mnt/           # hello
cat /tmp/fuse_mnt/hello     # Hello, FUSE!

# 언마운트
fusermount3 -u /tmp/fuse_mnt

마운트 메커니즘

fusermount3 / mount.fuse3

fusermount3는 non-root 사용자가 FUSE 파일시스템을 마운트/언마운트할 수 있게 해주는 setuid 헬퍼 프로그램입니다. 내부적으로 /dev/fuse를 열고, mount(2) 시스템 콜을 호출한 뒤, fd를 FUSE 데몬에 전달합니다.

/etc/fuse.conf

# /etc/fuse.conf — FUSE 전역 설정
user_allow_other    # allow_other 마운트 옵션 허용 (다른 사용자 접근)
mount_max = 1000    # 사용자당 최대 마운트 수

마운트 옵션 테이블

옵션설명기본값
allow_other마운트한 사용자 외 다른 사용자도 접근 허용비활성
allow_rootroot만 추가 접근 허용비활성
default_permissions커널이 권한 검사 수행 (데몬에 위임하지 않음)비활성
max_read=N단일 read 요청 최대 크기 (바이트)131072
max_write=N단일 write 요청 최대 크기 (바이트)131072
max_background=N최대 동시 배경 요청 수12
congestion_threshold=NBDI 혼잡 시작 임계치9
nonempty비어있지 않은 디렉토리에도 마운트 허용비활성
blkdev블록 디바이스 위에 마운트비활성
subtype=TYPE/proc/mounts에 표시할 서브타입 (예: fuse.sshfs)없음

/proc/filesystems 확인

# FUSE 커널 모듈 로드 확인
grep fuse /proc/filesystems
# nodev   fuse
# nodev   fuseblk

# 현재 FUSE 마운트 확인
mount -t fuse,fuse.sshfs,fuseblk
# 또는
grep fuse /proc/mounts

성능 특성과 최적화

유저-커널 컨텍스트 스위칭 오버헤드

FUSE의 근본적인 성능 제약은 모든 파일시스템 요청이 커널 ↔ 유저스페이스 간 컨텍스트 스위칭을 수반한다는 점입니다. 단일 read() 호출이 최소 4번의 컨텍스트 스위칭을 발생시킵니다:

  1. 애플리케이션 → 커널 (syscall)
  2. 커널 → FUSE 데몬 (/dev/fuse read)
  3. FUSE 데몬 → 커널 (/dev/fuse write)
  4. 커널 → 애플리케이션 (syscall return)

FUSE writeback cache (kernel 3.15+)

writeback cache를 활성화하면 커널이 쓰기 데이터를 페이지 캐시에 버퍼링하여 배치 처리합니다. FUSE_INITFUSE_WRITEBACK_CACHE 플래그로 활성화합니다.

💡

writeback cache는 성능을 크게 향상시키지만, 크래시 시 데이터 일관성 보장이 약해집니다. 데몬이 정상 종료하지 않으면 페이지 캐시의 더티 데이터가 유실될 수 있습니다.

splice/zero-copy 전송

splice를 사용하면 유저스페이스 버퍼 복사 없이 커널 파이프를 통해 데이터를 전달할 수 있습니다. FUSE_SPLICE_READ/FUSE_SPLICE_WRITE 플래그로 활성화합니다.

max_background / congestion_threshold 튜닝

# 높은 병렬성이 필요한 워크로드에서 배경 요청 수 증가
./my_fuse_fs -o max_background=64,congestion_threshold=48 /mnt/fuse

# sysfs를 통한 런타임 확인
cat /sys/fs/fuse/connections/<N>/max_background
cat /sys/fs/fuse/connections/<N>/congestion_threshold

FUSE passthrough (kernel 6.9+)

FUSE passthrough는 데이터 I/O를 유저스페이스 데몬을 거치지 않고 커널에서 직접 백엔드 파일에 전달하는 기능입니다. 메타데이터 연산만 데몬이 처리하고, 실제 데이터 읽기/쓰기는 커널이 직접 수행하여 네이티브 파일시스템에 근접한 성능을 달성합니다.

/* passthrough 설정 (FUSE daemon 측) */
/* FUSE_INIT에서 FUSE_PASSTHROUGH 플래그 활성화 후 */
/* OPEN 응답 시 backing file의 fd를 전달 */

struct fuse_file_info fi;
fi.passthrough_fh = backing_fd;  /* 백엔드 파일 디스크립터 */
fi.direct_io = 0;
/* 이후 READ/WRITE는 커널이 backing_fd를 통해 직접 처리 */

벤치마크 비교

항목native ext4FUSE (기본)FUSE (writeback)FUSE (passthrough)virtiofs (DAX)
순차 읽기 (MB/s) ~3,500 ~1,200 ~1,500 ~3,200 ~3,000
순차 쓰기 (MB/s) ~2,000 ~600 ~1,400 ~1,800 ~1,700
랜덤 4K IOPS (읽기) ~350K ~30K ~50K ~300K ~250K
메타데이터 ops/s ~200K ~15K ~15K ~15K ~80K

위 수치는 NVMe SSD 기준 대략적인 참고값입니다. 실제 성능은 FUSE 데몬 구현, 워크로드 패턴, 시스템 구성에 따라 크게 달라집니다.

virtiofs (가상화 환경 FUSE)

아키텍처

virtiofs는 FUSE 프로토콜을 virtio 전송 계층 위에서 사용하여, 호스트와 게스트 VM 간에 고성능 파일시스템 공유를 제공합니다. 호스트 측에서 virtiofsd 데몬이 실행되고, 게스트에서 virtio-fs 커널 드라이버가 FUSE 요청을 virtio 큐를 통해 전달합니다.

virtiofs 아키텍처 Guest VM Application VFS → FUSE Kernel Module virtio-fs driver (virtqueue) DAX window (선택적) Host QEMU / vhost-user-fs virtiofsd (FUSE daemon) Host Filesystem (ext4, XFS ...) virtio
virtiofs: 게스트 VM의 FUSE 요청을 virtio 전송으로 호스트 virtiofsd에 전달

DAX (Direct Access) 모드

DAX 모드에서는 호스트의 페이지 캐시를 게스트 VM에 직접 매핑하여 데이터 복사를 제거합니다. 메모리 매핑된 파일 접근이 네이티브에 가까운 성능을 달성합니다.

QEMU/libvirt 설정 예제

# 1. virtiofsd 데몬 실행 (Rust 구현, 권장)
/usr/libexec/virtiofsd \
    --socket-path=/tmp/virtiofs.sock \
    --shared-dir=/path/to/shared \
    --cache=always

# 2. QEMU에서 virtiofs 디바이스 추가
qemu-system-x86_64 \
    -chardev socket,id=char0,path=/tmp/virtiofs.sock \
    -device vhost-user-fs-pci,chardev=char0,tag=myfs \
    -object memory-backend-memfd,id=mem,size=4G,share=on \
    -numa node,memdev=mem \
    ...

# 3. 게스트 내부에서 마운트
mount -t virtiofs myfs /mnt/shared

컨테이너 환경 활용

Kata Containers는 virtiofs를 사용하여 컨테이너 이미지와 볼륨을 경량 VM 내부에 공유합니다. 이를 통해 컨테이너 수준의 편의성과 VM 수준의 격리를 동시에 달성합니다.

보안 모델

non-root 마운트와 보안 고려사항

FUSE는 일반 사용자가 파일시스템을 마운트할 수 있는 유일한 커널 메커니즘입니다. 이로 인해 다음과 같은 보안 고려사항이 존재합니다:

default_permissions vs 커스텀 접근 제어

모드권한 검사 위치특징
default_permissions 커널 (VFS) 표준 Unix 권한 모델 (uid/gid/mode). 안전하고 예측 가능
커스텀 (기본) FUSE 데몬 데몬이 자체 ACL/인증 로직 구현 가능. 유연하지만 데몬 버그 시 보안 취약

allow_other / allow_root

namespace 격리 (user namespace + FUSE)

Linux 4.18+에서는 user namespace 내에서 FUSE 마운트가 가능합니다. 이를 통해 비특권 컨테이너에서도 FUSE 파일시스템을 사용할 수 있습니다:

# unprivileged user namespace에서 FUSE 마운트
unshare --user --mount --map-root-user -- bash -c \
    "./my_fuse_fs /mnt/fuse"

신뢰할 수 없는 FUSE 데몬 방어

FUSE 데몬 보안 주의사항:

  • 데몬이 FUSE_LOOKUP에 대해 악의적 inode 정보를 반환할 수 있음 → default_permissions 사용 권장
  • 데몬이 응답을 지연하여 프로세스 행(hang) 유발 가능 → SIGKILL로 데몬 강제 종료 후 fusermount -u
  • 심볼릭 링크를 통한 경로 탈출 가능 → 데몬이 마운트 포인트 외부를 가리키는 symlink를 반환할 수 있음
  • ptrace 기반 공격 — FUSE 마운트에 접근하는 특권 프로세스를 악용할 수 있음

실제 FUSE 파일시스템

프로젝트용도특징API
sshfs SSH를 통한 원격 파일시스템 SFTP 프로토콜 기반, 간편한 원격 마운트 libfuse3
ntfs-3g NTFS 읽기/쓰기 Windows NTFS 파티션 완전 지원 libfuse (low-level)
s3fs-fuse Amazon S3 버킷 마운트 S3 API를 파일시스템으로 매핑 libfuse3
rclone mount 40+ 클라우드 스토리지 Google Drive, Dropbox, S3, Azure 등 통합 Go FUSE (bazil/cgofuse)
GlusterFS 분산 파일시스템 FUSE 클라이언트 + 네이티브 프로토콜 libfuse
CephFS (FUSE) 분산 파일시스템 커널 클라이언트 대안, 더 빠른 버그픽스 배포 libfuse
gocryptfs 암호화 파일시스템 파일 단위 AES-256-GCM 암호화 Go FUSE
mergerfs 디스크 풀링 여러 디스크를 하나의 마운트로 통합 libfuse3
SSHFS (Rust) SSH 원격 마운트 Rust fuse3 라이브러리 기반 재구현 fuse3 (Rust)

CephFS와 Ceph 커널 통합

Ceph는 RADOS(Reliable Autonomic Distributed Object Store) 기반의 통합 분산 스토리지 시스템으로, 오브젝트 스토리지(RADOS Gateway), 블록 스토리지(RBD), 파일시스템(CephFS)을 단일 클러스터에서 제공합니다. 리눅스 커널에는 CephFS 커널 클라이언트(fs/ceph/), RBD 블록 드라이버(drivers/block/rbd.c), 공통 RADOS 클라이언트 라이브러리(net/ceph/)가 포함되어 있습니다.

Ceph 스토리지 아키텍처

Ceph 스토리지 아키텍처 클라이언트 계층 CephFS 커널 fs/ceph/ ceph-fuse FUSE 클라이언트 RBD 커널 drivers/block/rbd.c RADOS Gateway S3/Swift API libceph (커널) — net/ceph/ librados (유저스페이스) CRUSH 알고리즘 (데이터 배치 계산) Ceph 클러스터 데몬 MON (Monitor) 클러스터 맵, Paxos 합의 MDS (Metadata Server) CephFS 메타데이터, 동적 서브트리 파티셔닝 OSD (Object Storage) 데이터 저장, 복제, 복구 BlueStore / FileStore
Ceph 아키텍처: 클라이언트(CephFS, RBD, RADOS GW)가 CRUSH로 OSD를 직접 찾아 I/O 수행. MON은 클러스터 맵, MDS는 CephFS 메타데이터 담당

핵심 컴포넌트

CRUSH 매핑 과정

/* CRUSH 데이터 배치 계산 흐름 */
파일 → 스트라이핑 → 오브젝트명 결정
  │
  ├─ object name = {inode}.{stripe_unit_number}
  │
  ▼
오브젝트 → PG(Placement Group) 매핑
  │
  ├─ pgid = hash(object_name) % pg_num
  │
  ▼
PG → OSD set 매핑 (CRUSH 알고리즘)
  │
  ├─ CRUSH(pgid, crush_map, rule) → [osd.3, osd.7, osd.12]
  │                                   primary  replicas
  ▼
클라이언트가 primary OSD에 직접 I/O 요청

CephFS 커널 클라이언트 (fs/ceph/)

CephFS 커널 클라이언트는 fs/ceph/ 디렉토리에 구현되어 있으며, VFS 계층에 직접 통합됩니다. FUSE 클라이언트와 달리 유저-커널 컨텍스트 스위칭 없이 커널 내에서 모든 I/O를 처리하므로 더 높은 성능을 제공합니다.

/* fs/ceph/super.h — CephFS 핵심 구조체 */
struct ceph_fs_client {
    struct super_block *sb;              /* VFS 슈퍼블록 */
    struct ceph_client *client;          /* libceph 클라이언트 (net/ceph/) */
    struct ceph_mds_client *mdsc;        /* MDS 클라이언트 */
    unsigned long mount_options;          /* 마운트 옵션 플래그 */
    unsigned max_file_size;               /* MDS가 허용한 최대 파일 크기 */

    struct ceph_mount_options *mount_opt;  /* 파싱된 마운트 옵션 */
    struct workqueue_struct *inode_wq;     /* inode 작업 큐 */
    struct workqueue_struct *cap_wq;       /* capability 처리 큐 */
    atomic_long_t writeback_count;        /* writeback 진행 수 */
};

/* fs/ceph/inode.c — CephFS inode 확장 정보 */
struct ceph_inode_info {
    struct inode netfs_inode.inode;       /* VFS inode (내장) */
    struct ceph_vino i_vino;             /* Ceph vino (ino + snap) */
    u64 i_version;                        /* inode 버전 */
    u64 i_max_size;                       /* MDS 허가 최대 크기 */

    struct rb_root i_caps;               /* 보유 cap 트리 */
    int i_nr_by_mode[CEPH_FILE_MODE_BITS]; /* 모드별 열린 파일 수 */
    u32 i_time_warp_seq;                  /* 타임스탬프 일관성 */

    struct ceph_file_layout i_layout;    /* 파일 레이아웃 (스트라이핑) */
    struct ceph_snap_realm *i_snap_realm; /* 스냅샷 영역 */
    struct list_head i_snap_realm_item;  /* 스냅샷 영역 연결 */
    struct list_head i_snap_flush_item;  /* 스냅샷 플러시 연결 */
};

MDS 통신과 Capability (Caps) 시스템

CephFS의 가장 독특한 특징은 capability(cap) 기반의 캐시 일관성 프로토콜입니다. MDS는 클라이언트에게 파일/디렉토리에 대한 cap을 발급하고, 클라이언트는 cap이 허용하는 범위 내에서 MDS에 요청하지 않고 로컬 캐시를 사용할 수 있습니다.

Cap 비트매크로의미
pCEPH_CAP_PINinode를 캐시에 고정 (evict 방지)
AsCEPH_CAP_AUTH_SHARED인증/권한 속성 읽기 캐시
AxCEPH_CAP_AUTH_EXCL인증/권한 속성 배타적 변경
LsCEPH_CAP_LINK_SHAREDlink count 읽기 캐시
XsCEPH_CAP_XATTR_SHAREDxattr 읽기 캐시
XxCEPH_CAP_XATTR_EXCLxattr 배타적 변경
FsCEPH_CAP_FILE_SHARED파일 크기/mtime 읽기 캐시, 페이지 캐시 사용
FxCEPH_CAP_FILE_EXCL파일 크기/mtime 배타적 변경
FrCEPH_CAP_FILE_RD파일 데이터 읽기 허용
FwCEPH_CAP_FILE_WR파일 데이터 쓰기 허용
FbCEPH_CAP_FILE_BUFFER쓰기 데이터 버퍼링(지연 플러시) 허용
FlCEPH_CAP_FILE_LAZYIOlazy I/O (일관성 완화) 허용
/* fs/ceph/caps.c — cap 메시지 처리 핵심 흐름 */

/*
 * MDS → 클라이언트: cap 발급/회수 흐름
 *
 * 1. 클라이언트가 open() → MDS에 CEPH_MDS_OP_OPEN 요청
 * 2. MDS가 cap 발급 (예: pAsLsXsFscrwb)
 * 3. 클라이언트가 cap 범위 내에서 로컬 캐시 사용
 * 4. 다른 클라이언트가 같은 파일 접근 시 MDS가 cap 회수(revoke)
 * 5. 클라이언트가 더티 데이터 플러시 후 cap 반환
 */

static void handle_cap_grant(struct inode *inode,
                              struct ceph_mds_caps *grant,
                              struct ceph_mds_session *session)
{
    struct ceph_inode_info *ci = ceph_inode(inode);
    int issued = __ceph_caps_issued(ci, NULL);
    int wanted = __ceph_caps_wanted(ci);
    int newcaps = le32_to_cpu(grant->caps);

    /* 새로 발급된 cap 확인 */
    int new_issued = ~issued & newcaps;

    /* 회수된 cap의 더티 데이터 플러시 */
    if ((issued & ~newcaps) & CEPH_CAP_FILE_BUFFER)
        ceph_queue_writeback(inode);  /* 버퍼링된 쓰기 즉시 플러시 */

    /* 페이지 캐시 무효화 (읽기 cap 회수 시) */
    if ((issued & ~newcaps) & CEPH_CAP_FILE_SHARED)
        invalidate_mapping_pages(&inode->i_data, 0, -1);

    ci->i_issued = newcaps;
    /* ... */
}

Cap 일관성 예시: 클라이언트 A가 파일을 열어 Frwb cap을 보유 중일 때, 클라이언트 B가 같은 파일을 열면 MDS는 A에게 Fb(버퍼링) cap 회수를 요청합니다. A는 버퍼링된 쓰기를 OSD로 플러시한 후 cap을 반환하고, 이후 B가 일관된 데이터를 읽을 수 있습니다.

CephFS 파일 레이아웃과 스트라이핑

/* include/linux/ceph/ceph_fs.h — 파일 레이아웃 구조체 */
struct ceph_file_layout {
    u32 stripe_unit;    /* 스트라이프 단위 크기 (기본 4MB) */
    u32 stripe_count;   /* 동시 스트라이프 수 (기본 1) */
    u32 object_size;    /* RADOS 오브젝트 크기 (기본 4MB) */
    s64 pool_id;        /* 데이터 풀 ID */
};

/*
 * 파일 → RADOS 오브젝트 매핑:
 *
 * stripe_unit=4M, stripe_count=4, object_size=4M 일 때:
 *
 * File offset:  [0-4M) [4M-8M) [8M-12M) [12M-16M) [16M-20M) ...
 * Object:        obj.0   obj.1   obj.2    obj.3     obj.0  ...
 * Stripe unit:     0       1       2        3         4    ...
 *
 * object_name = "{ino}.{objno:08x}"
 * objno = stripe_unit_num / stripe_count + (stripe_unit_num % stripe_count)
 */

CephFS 커널 마운트

# 커널 클라이언트로 CephFS 마운트 (v2 messenger 프로토콜)
mount -t ceph mon1:6789,mon2:6789,mon3:6789:/ /mnt/cephfs \
    -o name=admin,secret=AQBxxxxxxxxxxxxxxxxxxxxx==

# ceph.conf의 keyring 사용 (권장)
mount -t ceph mon1,mon2,mon3:/ /mnt/cephfs -o name=fs_client

# 주요 마운트 옵션
mount -t ceph mon1:/ /mnt/cephfs -o \
    name=admin,\
    readdir_max_entries=4096,\     # readdir 배치 크기 (기본 1024)
    rsize=16777216,\               # 최대 읽기 크기 (16MB)
    wsize=16777216,\               # 최대 쓰기 크기 (16MB)
    rasize=8388608,\               # readahead 크기 (8MB)
    caps_wanted_delay_max=60,\     # cap 요청 최대 지연 (초) 
    mds_namespace=myfs,\           # 특정 CephFS 인스턴스 지정
    recover_session=clean          # 세션 복구 모드

# 서브디렉토리만 마운트 (MDS 권한 제한 활용)
mount -t ceph mon1:/data/project /mnt/project -o name=project_user

# /etc/fstab 영속 마운트
# mon1,mon2,mon3:/  /mnt/cephfs  ceph  name=admin,noatime,_netdev  0 0

ceph-fuse (FUSE 클라이언트)

ceph-fuse는 CephFS의 유저스페이스 FUSE 클라이언트입니다. 커널 클라이언트와 같은 libcephfs 라이브러리를 사용하지만, FUSE를 통해 커널과 통신합니다. 새로운 기능이 커널에 반영되기 전에 먼저 사용할 수 있고, 커널 버전에 의존하지 않는 장점이 있습니다.

# ceph-fuse로 CephFS 마운트
ceph-fuse /mnt/cephfs --id admin

# 서브디렉토리 마운트
ceph-fuse /mnt/project --id project_user --client-mountpoint=/data/project

# 성능 튜닝 옵션
ceph-fuse /mnt/cephfs --id admin \
    --client-cache-size=16384 \          # 캐시 inode 수
    --fuse-big-writes \                  # 대용량 write 활성화
    --fuse-max-write=131072 \            # 최대 write 크기
    --client-readahead-max-bytes=8388608 # readahead 최대 크기

커널 클라이언트 vs FUSE 클라이언트 비교

항목커널 클라이언트 (mount -t ceph)ceph-fuse
성능 (순차 I/O) 네이티브에 가까움 커널 대비 30~50% 낮음 (컨텍스트 스위칭 오버헤드)
메타데이터 성능 높음 중간 (FUSE 프로토콜 오버헤드)
커널 버전 의존성 높음 — 커널 버전에 따라 기능/버그픽스 차이 낮음 — 유저스페이스 패키지로 독립 업데이트
기능 반영 속도 느림 (커널 릴리스 사이클) 빠름 (Ceph 릴리스 사이클)
안정성 버그 시 커널 패닉 가능 데몬 크래시만 발생, 시스템 안전
quotas 지원 커널 4.17+ 완전 지원
스냅샷 접근 지원 (.snap 디렉토리) 지원 (.snap 디렉토리)
non-root 마운트 불가 (root 필요) 가능 (fusermount)
권장 사용 환경 고성능 요구, 안정된 커널 버전 신기능 필요, 오래된 커널, 비특권 마운트

RBD (RADOS Block Device) 커널 모듈

RBD는 RADOS 오브젝트 위에 블록 디바이스 인터페이스를 제공하는 커널 모듈입니다. drivers/block/rbd.c에 구현되어 있으며, VM 디스크 이미지(QEMU/KVM), 컨테이너 PV(Kubernetes CSI) 등에 널리 사용됩니다.

/* drivers/block/rbd.c — RBD 핵심 구조체 */
struct rbd_device {
    struct rbd_client *rbd_client;  /* RADOS 클라이언트 연결 */
    struct rbd_spec *spec;          /* pool/image/snap 명세 */
    struct rbd_layout layout;       /* 오브젝트 레이아웃 */
    u64 header_oid;                  /* 이미지 헤더 오브젝트 */

    struct gendisk *disk;           /* 블록 디바이스 */
    struct request_queue *rq;       /* I/O 요청 큐 */

    u64 mapping_size;                /* 이미지 크기 */
    u32 stripe_unit;                 /* 스트라이프 단위 (기본 4MB) */
    u32 stripe_count;                /* 스트라이프 수 */
    u32 obj_order;                   /* 오브젝트 크기 = 2^obj_order */

    unsigned long flags;             /* read-only, exclusive lock 등 */
    struct rbd_obj_request *obj_req; /* 진행 중인 오브젝트 요청 */
};

/*
 * RBD I/O 흐름:
 * 1. 블록 I/O 요청 (struct bio) 수신
 * 2. 오브젝트 경계로 분할: offset → object_name + object_offset
 * 3. 각 오브젝트에 대해 RADOS OSD 요청 생성
 * 4. OSD가 응답하면 블록 요청 완료
 *
 * object_name = "rbd_data.{image_id}.{objnum:016x}"
 * objnum = offset >> obj_order
 */

RBD 이미지 관리 및 매핑

# RBD 이미지 생성 (100GB, format 2)
rbd create mypool/myimage --size 102400 --image-format 2

# 이미지 정보 확인
rbd info mypool/myimage
# rbd image 'myimage':
#     size 100 GiB in 25600 objects
#     order 22 (4 MiB objects)
#     stripe unit: 4 MiB  stripe count: 1
#     features: layering, exclusive-lock, object-map, fast-diff, deep-flatten

# 커널에 블록 디바이스로 매핑
rbd map mypool/myimage --id admin
# /dev/rbd0

# 파일시스템 생성 및 마운트
mkfs.ext4 /dev/rbd0
mount /dev/rbd0 /mnt/rbd

# 매핑 해제
umount /mnt/rbd
rbd unmap /dev/rbd0

# 현재 매핑된 RBD 디바이스 확인
rbd showmapped
# id  pool     image    snap  device
# 0   mypool   myimage  -     /dev/rbd0

RBD 고급 기능

기능설명커널 지원
Layering (COW Clone) 스냅샷을 기반으로 Copy-on-Write 클론 생성. VM 템플릿에서 빠른 인스턴스 생성 3.10+
Exclusive Lock 단일 클라이언트만 쓰기 가능. live migration, 자동 failover 지원 4.9+
Object Map 할당된 오브젝트 비트맵. 씬 프로비저닝, 빠른 diff/export 지원 5.3+
Deep Flatten 클론의 모든 스냅샷 데이터를 완전 독립시킴. 부모 이미지 안전 삭제 가능 5.1+
Journaling 쓰기 저널링으로 RBD Mirroring(재해복구) 지원 유저스페이스 (librbd)
Encryption LUKS 기반 클라이언트 측 블록 암호화 유저스페이스 (librbd, Reef+)
# RBD 스냅샷 및 클론 워크플로우
# 1. 스냅샷 생성
rbd snap create mypool/base-image@snap1

# 2. 스냅샷 보호 (클론 전 필수)
rbd snap protect mypool/base-image@snap1

# 3. COW 클론 생성 (즉시 완료, 데이터 복사 없음)
rbd clone mypool/base-image@snap1 mypool/vm-instance-01

# 4. 클론 독립화 (선택적: 부모 의존 제거)
rbd flatten mypool/vm-instance-01

libceph — 커널 RADOS 클라이언트 (net/ceph/)

net/ceph/에 구현된 libceph는 CephFS 커널 클라이언트와 RBD가 공통으로 사용하는 커널 내 RADOS 클라이언트 라이브러리입니다. MON/OSD 통신, CRUSH 계산, 메시지 프로토콜, 인증을 담당합니다.

/* net/ceph/ceph_common.c — libceph 핵심 구조체 */
struct ceph_client {
    struct ceph_options *options;       /* MON 주소, 인증 정보 등 */
    struct ceph_messenger msgr;         /* 메시지 전송 계층 */
    struct ceph_mon_client monc;        /* MON 클라이언트 */
    struct ceph_osd_client osdc;        /* OSD 클라이언트 */
};

/* net/ceph/osd_client.c — OSD 클라이언트 */
struct ceph_osd_client {
    struct ceph_client *client;
    struct ceph_osdmap *osdmap;        /* OSD 맵 (CRUSH 맵 포함) */
    struct rb_root osds;               /* 활성 OSD 연결 트리 */
    struct rb_root linger_requests;    /* watch/notify 요청 */
    struct list_head osd_lru;          /* OSD 연결 LRU */
    atomic64_t last_tid;               /* 마지막 요청 ID */
};

/* OSD 요청 흐름 */
struct ceph_osd_request *req;
req = ceph_osdc_new_request(&client->osdc, layout,
                             vino, offset, &len,
                             0,              /* num_ops */
                             CEPH_OSD_OP_READ,
                             CEPH_OSD_FLAG_READ,
                             NULL, 0);
ceph_osdc_start_request(&client->osdc, req);
ceph_osdc_wait_request(&client->osdc, req); /* 동기 대기 */

Messenger v2 프로토콜

Ceph Nautilus(14.x)부터 기본 사용되는 messenger v2 프로토콜은 net/ceph/messenger_v2.c에 구현되어 있습니다. v1 대비 프로토콜 협상 개선, CRC/암호화 선택, frame 기반 메시지 구조를 제공합니다.

특성Messenger v1 (legacy)Messenger v2
기본 포트6789 (MON)3300 (MON), 6800+ (OSD)
전송 암호화없음AES-128-GCM (선택적)
인증CephXCephX + mutual auth
무결성 검사CRC32CCRC32C 또는 암호화에 포함
프레임 구조단순 헤더+페이로드태그 기반 프레임 (preamble + segments)
프로토콜 협상배너 교환HELLO/AUTH/SESSION 핸드셰이크

Ceph 커널 모듈 디버깅

# debugfs를 통한 CephFS/RBD 상태 확인
mount -t debugfs none /sys/kernel/debug    # debugfs 마운트 (미마운트 시)

# CephFS 클라이언트 정보
ls /sys/kernel/debug/ceph/
# 8b3d5f2a-xxxx-xxxx-xxxx-xxxxxxxxxxxx.client12345/

# MDS 세션 및 cap 상태
cat /sys/kernel/debug/ceph/*/mdsc         # MDS 클라이언트 상태
cat /sys/kernel/debug/ceph/*/caps         # 보유 cap 수 통계
cat /sys/kernel/debug/ceph/*/mds_sessions # MDS 세션 상태

# OSD 클라이언트 상태
cat /sys/kernel/debug/ceph/*/osdc         # OSD 요청 상태
cat /sys/kernel/debug/ceph/*/osdmap       # OSD 맵 epoch
cat /sys/kernel/debug/ceph/*/monc         # MON 클라이언트 상태

# 동적 디버그 메시지 활성화
echo 'module ceph +p' > /sys/kernel/debug/dynamic_debug/control
echo 'module rbd +p' > /sys/kernel/debug/dynamic_debug/control
echo 'module libceph +p' > /sys/kernel/debug/dynamic_debug/control

# 특정 파일/함수만 디버그
echo 'file fs/ceph/caps.c +p' > /sys/kernel/debug/dynamic_debug/control
echo 'func ceph_check_caps +p' > /sys/kernel/debug/dynamic_debug/control

# dmesg에서 Ceph 관련 메시지 확인
dmesg | grep -i ceph

일반적인 문제와 해결

증상원인해결 방법
마운트 시 mount error: no mds server is up MDS 데몬 미실행 또는 standby 상태 ceph mds stat으로 MDS 상태 확인. systemctl start ceph-mds@hostname
slow requests 경고 OSD I/O 지연 또는 클라이언트 cap 플러시 지연 ceph daemon osd.N dump_ops_in_flight로 지연 op 확인. debugfs caps로 cap 상태 확인
CephFS 클라이언트 hang (I/O 블록) MDS/OSD 연결 끊김, cap 회수 타임아웃 debugfs mdsc로 진행 중 요청 확인. mount_timeout 옵션 조정
RBD rbd: sysfs write failed 커널이 이미지 feature 미지원 rbd feature disable pool/image exclusive-lock object-map 또는 커널 업그레이드
RBD rbd: image is locked by client exclusive-lock이 다른 클라이언트에 보유됨 rbd lock list pool/image로 확인. rbd lock remove 또는 --force 매핑
인증 실패 auth: error -13 CephX 키 불일치 또는 권한 부족 ceph auth get client.admin으로 키 확인. ceph auth caps로 권한 조정

커널 클라이언트 버전 호환성: Ceph 커널 클라이언트의 기능은 리눅스 커널 버전에 종속됩니다. 운영 중인 Ceph 클러스터 버전과 커널 클라이언트 버전의 호환성을 반드시 확인하세요. Ceph 공식 문서에서는 최소 커널 4.x 이상을 권장하며, 최신 기능(예: msgr2 암호화)은 5.11+ 커널이 필요합니다.

디버깅과 트러블슈팅

기본 디버깅 옵션

# -d: 디버그 모드 (모든 FUSE 메시지를 stderr에 출력, 포그라운드 실행 포함)
./my_fuse_fs -d /mnt/fuse

# -f: 포그라운드 실행 (데몬화하지 않음)
./my_fuse_fs -f /mnt/fuse

# -s: 싱글스레드 모드 (디버깅 시 유용)
./my_fuse_fs -f -s /mnt/fuse

강제 언마운트

# 정상 언마운트
fusermount3 -u /mnt/fuse

# 데몬이 응답하지 않을 때 강제 언마운트
fusermount3 -uz /mnt/fuse    # lazy unmount (-z)

# root 권한으로 강제 언마운트
umount -l /mnt/fuse          # lazy unmount
umount -f /mnt/fuse          # force unmount

strace로 /dev/fuse 트래픽 추적

# FUSE 데몬의 /dev/fuse 통신 추적
strace -f -e read,write -p <FUSE_DAEMON_PID>

# 특정 파일 디스크립터만 추적 (fd 번호 확인 후)
ls -la /proc/<PID>/fd/ | grep /dev/fuse
strace -f -e trace=read,write -e read=<fd> -e write=<fd> -p <PID>

/sys/fs/fuse/connections/ 디버그 인터페이스

# FUSE 연결 목록 확인
ls /sys/fs/fuse/connections/
# 42/  43/  ...

# 연결 상태 확인
cat /sys/fs/fuse/connections/42/waiting      # 대기 중인 요청 수
cat /sys/fs/fuse/connections/42/max_background
cat /sys/fs/fuse/connections/42/congestion_threshold

# 연결 강제 중단 (데몬 hang 시)
echo 1 > /sys/fs/fuse/connections/42/abort
💡

/sys/fs/fuse/connections/<N>/abort에 쓰기를 하면 해당 FUSE 연결의 모든 대기 중인 요청이 즉시 에러로 완료됩니다. 데몬이 행(hang)되어 마운트에 접근하는 프로세스가 블록될 때 유용합니다.