ftruncate expend file fop
- finodelk (whole file)
- fgetxattr(get trusted.glusterfs.crypt.att.size value)
- readv(rmw readv head block)
- writev(write head block)
- writev(write full block loop )
- readv(rmw readv tail block)
- writev(write tail block)
- fsetxattr(update new file size)
- finodelk(unlock file)
finodelk: lock whole file
- Allocate GF_FOP_FTRUNCATE local datastruct
- Init local xattr dict
- Get inode info
- Set crypt algo info
- Set lock info (the lock whole file)
- lock.l_len = 0;
- lock.l_start = 0;
- lock.l_type = F_WRLCK;
- lock.l_whence = SEEK_SET;
- 呼叫STACK_WIND finodelk去加鎖整個檔案
fgetxattr: get original file size
- Get FSIZE_XATTR_PREFIX attribution value
- FSIZE_XATTR_PREFIX = trusted.glusterfs.crypt.att.size
- 呼叫STACK_WIND gsetxattr去獲得目前的file size
readv: read the head block data
- Get extract regular file size from FSIZE_XATTR_PREFIX attribution
- Determine shrink file or expand file
- Expand file
- Prepare to submit a hole for file
- Set expand file info about how many block need to expand(set_config_offsets)
- dtype = HOLE_ATOM(塞空洞進去)
- block size: 4096
- expand一段size會被分成三個部份
- head block(從原本檔案的offset所屬的block)
- full blocks (中間完整的block)
- tail block(最後expand完offset所屬的block)
- off_in_head: head block offset
- off_in_tail: tail block offset
- nr_full_blocks: full block count
- acount: total block count(head block+full block+tail block)
- Allocate and setup vector for hole
- allocate 3 blocks in pool(head, full, tail) for data
- allocate a array avec and put block into avec
- avec[0].iov_base = pool[0] 分給head block並且將off_in_head到block底這一段利用memset()設為0
- avec[2].iov_base = pool[2] 分給tail block並且從block起始到off_in_head這一段利用memset()設為0
- avec[1].iov_base = pool[1] 分給full block
- 將這些avec資訊放到&local->hole_conf中
- Sumit the hold
- 這裡有三種case要處理
- head block
- full block
- tail block
- 首先會先處理head block(submit_head)
- 利用STACK_WIND的方式呼叫crypt的readv函式(crypt_readv)
- crypt_readv中
- allocate a new local for GF_FOP_READ
- 設定要讀的head block資料的offset及相關block(通常只有tail block, head block和full block都沒有)(set_config_offsets)
- 呼叫STACK_WIND去讀從head block到off_in_head的資料
writev: write zero data per block(head block)
- Set data info from read, type: DATA_ATOM(set_config_offsets)
- Correct config params with real file size and actual amount of bytes read
- Get data from vec buffer
- allocate avec and block(放資料的地方)
- 利用memcpy將資料copy到block
- 將block放到avec[]中
- copy了超過了原本預期大小的資料
- decrypt iov data(解密依照所讀的大小)
- Fix iov len to correct len
- 利用STACK_UNWIND_STRICT回到呼叫crypt_readv的call function(rmw_hole_head)
- 此時回到GF_FOP_FTRUNCATE local datastruct
- 利用memcpy將vec[0] copy到partial[0]中(vec表示剛剛從readv讀到的資料, partial是之前在Allocate and setup vector for hole所allocate的avec)
- 對於partial[0]整個block加密(針對head block加密, 之前就已經把off_in_head之後的byte都寫0了)
- Set new file size (包含head block的block size, like 8192(2 block))
- 呼叫STACK_WIND writev將資料往下寫
writev: write zero data per block(full block)
- Update new file params(cur_file_size)
- 又回到Submit hole
- 這次是呼叫submit_full來處理full block的寫入
- 利用memset把0填入avec[1] (full block)
- 加密avec[1]
- Set new file size (包含head block的block size, like 12288(2 block))
- 呼叫STACK_WIND將資料往下寫
- 一直loop呼叫直到tail block
readv: read the tail block data
- Update new file params(cur_file_size)
- 又回到Submit hole
- 執行submit_partial(), type=TAIL_ATOM
- 利用STACK_WIND的方式呼叫crypt的readv函式(crypt_readv)
- crypt_readv中
- allocate a new local for GF_FOP_READ
- 設定要讀的head block資料的offset及相關block(通常只有tail block, head block和full block都沒有)(set_config_offsets)
- 呼叫STACK_WIND去讀從tail block到off_in_tail的資料
writev: write zero data per block(tail block)
- return 0個byte len也是0(因為檔案沒有那麼大)
- 利用STACK_UNWIND_STRICT回到呼叫crypt_readv的call function(rmw_hole_tail)
- 直接將partial[3]也就是tail block以off_in_tail的len寫到下一層(之前在init iov也就是partial的時候就將tail block起頭到offset的範圍初始成0了)
- 加密partial[3]的資料
- Set new file size
- 呼叫STACK_WIND writev將資料往下寫
fsetxattr: set new file size
- Update file size
- Set FSIZE_XATTR_PREFIX(trusted.glusterfs.crypt.att.size) new file size
- 呼叫STACK_WIND fsetxattr將新的file size往下寫
finodelk: lock whole file
- Set unlock info(unlock whole file)
- lock.l_type = F_UNLCK;
- lock.l_whence = SEEK_SET;
- lock.l_start = 0;
- lock.l_len = 0;
- 呼叫STACK_WIND finodelk去解鎖
心得:
ftruncate在linux只是一個改變file size的指令, 通常很快就結束, 因為他只需要去改變檔案的metadata就可以了. 當你去讀取大於原本file size的區塊, linux kernel通常會回傳0給你.但crypt xlator裡面就沒有那麼簡單. 因為crypt xlator是加密的xlator, 所有寫到OS的資料都會加密. 當你去讀取大於原本file size的區塊, 若linux kernel回傳0給crypt xlator, 在經過解密回傳上去就可能不是0. 所以他採用了一個很簡單的方式來解決, 他在ftruncate的時候就直接幫你寫0, 之後你若讀取他回傳解密後就會是0. 符合一般linux file system的操作.
沒有留言:
張貼留言