안녕하세요? 오늘은 centos7에서 mount 시 Function not implemented 에러에 대해 어떤 이슈 인지 확인 하는 시간을 가져 보도록 하겠습니다.

재현 방법은 새로운 디스크를 할당 받은 후, mkfs.xfs에서 block size에 대해서 64K로 지정을 한 다음, block size가 64K로 구성된 디스크에 대해서 마운트를 시도 합니다.

​ mount 시 Function not implemented 라는 에러를 확인 할수 있습니다.

# mkfs.xfs -b size=64k /dev/xvdb
meta-data=/dev/xvdb              isize=512    agcount=4, agsize=2048000 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=0, sparse=0
data     =                       bsize=65536  blocks=8192000, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=65536  ascii-ci=0 ftype=1
log      =internal log           bsize=65536  blocks=4000, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=65536  blocks=0, rtextents=0
 
 
[root@leo-lab ~]# mount -t xfs /dev/xvdb /mnt/
mount: mount /dev/xvdb on /mnt failed: Function not implemented

에러 내용이 궁금하여, 아래와 같이 흐름을 따라 가면서 분석을 해보았습니다. dmesg를 통해서, 아래와 같은 메세지가 출력되는 것을 확인 할수 있습니다.

# dmesg
...
[6037019.890621] XFS (xvdb): File system with blocksize 65536 bytes. Only pagesize (4096) or less will currently work.
[6037019.890648] XFS (xvdb): SB validate failed with error -38.
....

메세지의 의미를 파악 하기 위해서, linux-3.10.0-1127.13.1.el7.x86_64 의 커널 기준으로 확인 결과, xfs를 mount 하려고 할때, xfs_mount_validate_sb 라는 함수가 호출이 되며, 리눅스 시스템의 PAGE_SIZE 와 비교 하는 구문이 포함이 되어있습니다. 메세지 의미는 파일 시스템은 65535(64K) 이지만, PAGE 크기가 4096 이니 4096 혹은 그 이하로 낮게 해라는 커널에서 출력 하는 메세지를 확인이 가능 합니다.

# vim fs/xfs/libxfs/xfs_sb.c
....
/*
 * Check the validity of the SB found.
 */
STATIC int
xfs_mount_validate_sb(
        xfs_mount_t     *mp,
        xfs_sb_t        *sbp,
        bool            check_inprogress,
        bool            check_version)
{
....
        /*
         * Until this is fixed only page-sized or smaller data blocks work.
         */
        if (unlikely(sbp->sb_blocksize > PAGE_SIZE)) { /* <---------- */
 
                xfs_warn(mp,
                "File system with blocksize %d bytes. "
                "Only pagesize (%ld) or less will currently work.",
                                sbp->sb_blocksize, PAGE_SIZE);
                return -ENOSYS; /*
                                 * #define ENOSYS          38  Function not implemented
                                */
 
        }
....
}
....

x86_64 기준으로 페이지 크기 (PAGE_SIZE)는 (1 « PAGE_SHIFT) 즉, 2 ^ 12 = 4096 의 값이 나오는 것이 확인 가능 하였습니다

# vim include/asm-generic/page.h
....
/* PAGE_SHIFT determines the page size */
....
#define PAGE_SHIFT      12
#ifdef __ASSEMBLY__
/* 따라서 실제로 비트를 왼쪽 (1 << PAGE_SHIFT)으로 이동하면 2 ^ 12 = 4096 값이 나옵니다.*/
/* echo "2^12" | bc */
#define PAGE_SIZE       (1 << PAGE_SHIFT)
#else
#define PAGE_SIZE       (1UL << PAGE_SHIFT)
#endif
#define PAGE_MASK       (~(PAGE_SIZE-1))
....

아래와 같이 쉘에서 리눅스 쉘 계산기 bc 를 이용 하여 계산이 가능합니다.

# bc --version
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.

# rpm -qf /usr/bin/bc
bc-1.06.95-13.el7.x86_64

# echo "2^12" | bc
4096

사용중인 시스템에서는 아래와 같이 PAGESIZE를 확인이 가능 합니다. 현재 제가 사용중인 VM 인스턴스는 x86_64 이며 PAGESIZE는 4096 입니다.

# uname -m
x86_64
# getconf PAGESIZE
4096