JFS day1

 JFS 는 DFS(distribution file system) 지원을 위해 aggregate 와 fileset 이라는 개념을 도입해

 diskspace allocation pool 과 mountable volume 을 분리하였다.


 JFS 는 파티션 위에 1개의 aggregate 와 1개 이상의 fileset 으로 구성된다.


 JFS 의 dynamic inode allocation 으로 인해, 별도의 mapping 정보가 필요하게 되어

 등장한게 Inode allcation map 과 ag free inode list 이다.


 JFS 는 file 이 사용하는 연속된 disk block 을 extents 라 부르며, AG 를 넘어가는 경우엔

 B+ tree 에 별도의 인덱싱이 들어가게 된다. 


 JFS 는 IAG(inode allocation group) 를 사용해 inode allocation map 을 기술하며, 

 forward lookup 문제를 해결하기 위해 사용하고 있다. file lookup 이 대표적인 문제이며,

 inode 번호로 on-disk inode 를 찾는 과정이다.


 JFS 는 1개의 inode allocation map 에 4096 개의 disk inode extents 의 상태 관리(0, 1)를

 하고, 최대 128개 AG 로 구분할수 있다.

 __le32 wmap[EXTSPERIAG];   // 32 x 128 /* number of disk inode extent per iag  */


 JFS 는 file layout 를 작성할때 1개의 B+ tree node 가 8개의 xad_t 를 사용해 

 물리 영역과 논리 볼륨을 연결 해준다. 현재는 "18개의 xad_t" 까지 가능하다.

 #define XTROOTMAXSLOT   18


 JFS 는 on-disk inode (dinode) 와 inode (jfs_inode_info) 양쪽에 xad_t 를 두고 있고,

 root 에 접근하는 별도의 매크로를 제공하고 있다.

 #define di_xtroot   u._file._u2._xtroot

 #define i_xtroot u.file._xtroot


 JFS 는 block allocation map 을 이용해 aggregate 내 fileset 들이 alloc / free 한

 disk block 을 추적하며, 이때 block 단위는 1k(aggregate block) 이다. 


 JFS 의 block allocation map 은 aggregate inode 2번이며, 4K bytes 를 넘어가면

 확장되거나 줄어들수 있다.


 JFS 에서 block allocation map 은 dmap tree 로 구성되어 있으며, 

 1개의 dmap 은 8k 개 (BPERDMAP) 의 aggregate block 을 갖고, leaf 로부터 위로 

 L0/L1/L2 로 구성되어 총 2^3 x 2^40 개 block 를 보유하고 있다. 

 각 레벨당 2^10 개의 노드가 존재한다.

 __le32 wmap[LPERDMAP];  // 256 /* num leaves per dmap tree */

 256 x 32 = 8196 bit  == 8196 개 aggregate block


 JFS 에서 dmap 내 alloc / free 된 disk block 은 summary tree (dp->tree) 와 

 binary buddy system (budtab) 으로 관리되며, summary tree 는 budtab 의 인덱스 정보를

 갖고 있다.


 아래는 dbFindLeaf 슈도코드와 예시이다. ( ROOT -> L2 -> L1 - > L0 -> LEAF )


 dbFindLeaf(dmtree_t *tp, int l2nb, int *leafidx)

 1. dmtree_t 에서 l2nb (number of block in log2) 가능한 leafidx 를 찾는다.

 2. l2nb > tp->dmt_stree[ROOT] 면 서비스 불가, -ENOSPC 리턴 ( ROOT:0 )

 3. leftmost leaf 부터 내려가면서 sufficient free space 를 가진 leaf node idx 를 리턴한다.


 

 JFS 는 찾은 leafidx 를 사용해, dp->wmap[leafidx] word 에 대한 binary buddy system

연산을 수행해 blkno 를 구한다. 아래는 dbFindBits 함수의 동작예시이다.



 JFS 는 file 내 특정 위치(pno) 에 xlen 만큼의 쓰기요청이 들어오면, 

 extend(xad) 가 쓸 disk block 할당 함수를 호출, block address(nxaddr) 와 실제 할당된

 block 갯수(nxlen) 가 반환된다. 만약 반환된 block address 가 extend 와 continuous 하면

 extend 를 확장하는 함수를 호출하게 된다.

 

 JFS 는 inode 를 3종류의 정보(file, dir, link) 로 구분하고, file 은 xtree page (xtpage_t), 

 dir 은 directory root page (dtroot_t) 를 두어 관리하고 있다. 전자를 xtree, 후자를 dtree

 라고 부르고 있다.


 JFS jfs_readdir 함수는 jfs_dirent 구조체 배열에 정보를 채우고, 개별 jfs_dirent 에 대해

 dir_emit 함수를 호출한다. 아래는 jfs_readdir 의 슈도코드이다.

 1. start page (dtpage_t) 와 index 를 획득한다. 이때 dir_index 가 3이상이면, 

    directory table (dir_table_slot) 을 구해서 index 로 사용한다.

 2. start page header 에서 nextindex 를 획득한다. index .... nextindex 사이를 순회하며

    head/only segment(ldtentry) 의 이름을 복사한다. 이때 순회순서는 알파벳 정렬순이다.

    ( d = p->slot[stbl[i]] )

 3. 2번 루프 안에서 dtslot next 가 없을때까지 순회하며, additional segment(dtslot) 의

    이름을 복사한다.

 3. jfs_dirent 배열을 역순회하면서 dir_emit 을 호출해준다.


 JFS 는 suffix compression 을 지원하기 위해 direcotry B+ tree (sorted by name) 을 제공

 하고, dir_table_slot 생성/삭제 시 메모리를 적게 shift 하기 위해 sorted entry index 

 table(stbl) 을 start page 에서 관리하고 있다.


 JFS 의 진입점 

 super.c:996:    rc = register_filesystem(&jfs_fs_type);


 JFS 의 file disk block allocation 함수 콜스택 및 주요 구조체

 ./kprobe -s 'p:extBalloc %di %si %dx %cx'

 echo hi > /mnt/aaa/testfile

 bash-20052   [001] .....  9206.257503: 
 extBalloc: (extBalloc+0x0/0x280 [jfs]) 
 arg1=0xffff976c2b06f880 arg2=0x1f arg3=0xffffa62a90d67ad0 arg4=0xffffa62a90d67ad8
            bash-20052   [001] .....  9206.257529: <stack trace>
 => extBalloc
 => jfs_get_block
 => nobh_write_begin
 => jfs_write_begin
 => generic_perform_write
 => __generic_file_write_iter
 => generic_file_write_iter
 => new_sync_write
 => vfs_write
 => ksys_write
 => __x64_sys_write
 => do_syscall_64
 => entry_SYSCALL_64_after_hwframe

crash> struct inode.i_sb 0xffff976c2b06f880
  i_sb = 0xffff976bcd843000,
crash> struct super_block.s_fs_info 0xffff976bcd843000
  s_fs_info = 0xffff976cbe4d4000,
crash> struct jfs_sb_info.bmap 0xffff976cbe4d4000
  bmap = 0xffff976bf3d65000,
crash> struct bmap.db_bmap.dn_maxfreebud 0xffff976bf3d65000
  db_bmap.dn_maxfreebud = 11 '\v'
crash>


 참고한 링크

 https://www.kernel.org/doc/html/latest/filesystems/vfs.html

 https://jfs.sourceforge.net/project/pub/jfslayout.pdf

 

 추가 확인할 정보

 dbSplit

 XT_GETPAGE 와 XT_PUTPAGE ( metapage 라이프사이클 )

 xtTruncate 내 xad 획득코드

댓글

  1. 1차 수정 : extent 정의 및 디테일(숫자) 추가, inode allocation map 과 block allocation map 의 차이점이 드러나게 내용수정

    답글삭제
  2. 2차 수정 : xad_t 설명 추가, 확인할 정보 추가

    답글삭제
  3. 3차 수정 : summary tree, binary buddy system 그림 추가, 동작예시 추가

    답글삭제
  4. 4차 수정 : binary buddy system 그림 오류 수정, extAlloc 시 hint 정보 추가 (extend 유무 결정)

    답글삭제
  5. 5차 수정 : readdir 및 dtree 설명 추가 ( xtree 와 dtree 의 차이점 )

    답글삭제

댓글 쓰기