天天看點

gluster檔案鎖的實作

  1.          主要閱讀了服務端Locks xlators的實作,由于是分布式系統,client應該對鎖應該也有一定的處理。還未深入了解,後續進一步研究後進行補充。

1.1    資料結構

  1. 鎖的類型:__posix_lock/__pl_inode_lock/__entry_lock,成員比較類似,重要的資料成員(最後三個成員用來标記加鎖的源:用戶端和程序):
  • struct list_head   list;   插入Inode的ext_list
  • short  fl_type;
  • off_t  fl_start;
  • off_t  fl_end;
  • short blocked:  鎖是否在阻塞狀态
  • fd_num;    fd對象的指針值轉換為ulong類型
  • fd_t* fd;
  • blkd_time;   進入blkd list的時間
  • granted_time; 進入active list的時間
  • transport;     表示用戶端
  • owner;
  • client_pid;    用戶端程序PID
  1. Inode資料結構__pl_inode:
      • mutex;
      • dom_list;      主機清單
      • ext_list;      fcntl鎖清單
      • rw_list;       等待的讀寫請求
      • reservelk_list;       
      • blocked_reservelks;       
      • blocked_calls; 
      • mandatory;     
      • refkeeper;    

1.2    加鎖

pl_lk

  1. pl_inode_get:從inode對象的ctx中擷取pl_inode_t對象,如果沒有,建立,并__inode_ctx_put到Inode對象中
  2. new_posix_lock建立posix_lock_t對象,指派transport/owner等,如果參數flock的l_len==0,設定fl_end=LLONG_MAX
  3. pl_setlk
  • __is_lock_grantable:周遊pl_inode的ext_list,判斷鎖的範圍是否overlap,再判斷鎖的own是否一緻(same_owner比較transport和owner),如果overlog且own不一緻,傳回否

pl_send_prelock_unlock:(Send unlock before the actual lock to prevent lockupgrade / downgrade problems only if: - it is a blocking call - it has otherconflicting locks)(can_block &&!(__is_lock_grantable(pl_inode, lock))時調用)

  • 如果鎖可以執行,__insert_and_merge:合并或拆分鎖的範圍,插入鎖
  • 如果鎖不能執行,并且can_block為true,設定lock->blocked = 1,插入inode的ext_list
  • grant_blocked_locks (this, pl_inode);
  • do_blocked_rw (pl_inode);

1.3    解鎖

pl_flush

  1. 如果調用棧參數frame->root->lk_owner.len==0(用戶端失去連結,該用戶端打開的所有fd),調用delete_locks_of_fd(删除鎖,調用do_blocked_rw從pl_inode->rw_list重新取出讀寫調用,resume),退出函數
  2. __delete_locks_of_owner:删除該owner的鎖(trans/lk_owner)
  3. grant_blocked_locks
  4. do_blocked_rw

delete_locks_of_fd

  1. 周遊pl_inode->ext_list,删除該fd的所有的鎖,根據l->blocked判斷,如果是被阻塞的鎖,還需要STACK_UNWIND錯誤碼eagain
  2. grant_blocked_locks:
  • 調用__grant_blocked_locks周遊pl_inode->ext_list中被阻塞的鎖,first_overlap(周遊ext_list)判斷加鎖區域是否交叉,如果沒有,加入tmp_list
  • 周遊tmp_list,__is_lock_grantable再次判斷鎖是否可以執行,如果可以調用__insert_and_merge插入并合并鎖

   3. do_blocked_rw

         從pl_inode->rw_list重新取出讀寫調用,__rw_allowable判斷可以恢複,調用call_resume恢複讀寫調用

1.4    檢查鎖

__rw_allowable:do_blocked_rw/pl_readv/pl_writev調用到該方法

  1. 調用locks_overlap判斷讀寫範圍和Inode上鎖的傳回是否沖突
  2. same_owner判斷鎖的owner和目前讀寫的owner是否一緻
  3. 判斷鎖的類型(讀、寫)和操作讀寫類型(GF_FOP_READ)

如果檢查失敗,如果操作是O_NONBLOCK,直接回複eagain,否則生成pl_rw_req_t對象,插入pl_inode的rw_list

1.5 Client維護鎖

  1. client3_3_lk_cbk(client-rpc-fops.c)通過調用client_add_lock_for_recovery在client端建立鎖,能夠在server重新開機時恢複鎖(目前代碼已經被注釋)
  2. client_add_lock_for_recover調用client_setlk(Client_lk.c)在client端建立鎖(__insert_and_merge)

1.6   鎖owner

  1. Gluster内部維護的owner的資料結構:

    typedef struct gf_lkowner_ {

            int  len;

            chardata[GF_MAX_LOCK_OWNER_LEN];

    } gf_lkowner_t;

  2. Fuse的owner定義,set_lk_owner_from_uint64轉換成gluster内部定義的

struct fuse_lk_in {

         __u64       fh;

         __u64       owner;

         structfuse_file_lock lk;

         __u32       lk_flags;

         __u32       padding;

};

static inline void

set_lk_owner_from_uint64 (gf_lkowner_t*lkowner, uint64_t data)

{

       int i = 0;

       int j = 0;

       lkowner->len = 8;

       for (i = 0, j = 0; i < lkowner->len; i++, j += 8) {

                lkowner->data[i] =  (char)((data >> j) & 0xff);

       }

}

  1. set_lk_owner_from_ptr

static inline void

set_lk_owner_from_ptr (gf_lkowner_t*lkowner, void *data)

{

       int i = 0;

       int j = 0;

       lkowner->len = sizeof (unsigned long);

       for (i = 0, j = 0; i < lkowner->len; i++, j += 8) {

                lkowner->data[i] =  (char)((((unsigned long)data) >> j)& 0xff);

       }

}

 

繼續閱讀