📄 dlmglue.c
字号:
struct ocfs2_lock_res *res, enum ocfs2_lock_type type, struct ocfs2_lock_res_ops *ops, void *priv){ res->l_type = type; res->l_ops = ops; res->l_priv = priv; res->l_level = LKM_IVMODE; res->l_requested = LKM_IVMODE; res->l_blocking = LKM_IVMODE; res->l_action = OCFS2_AST_INVALID; res->l_unlock_action = OCFS2_UNLOCK_INVALID; res->l_flags = OCFS2_LOCK_INITIALIZED; ocfs2_add_lockres_tracking(res, osb->osb_dlm_debug); ocfs2_init_lock_stats(res);}void ocfs2_lock_res_init_once(struct ocfs2_lock_res *res){ /* This also clears out the lock status block */ memset(res, 0, sizeof(struct ocfs2_lock_res)); spin_lock_init(&res->l_lock); init_waitqueue_head(&res->l_event); INIT_LIST_HEAD(&res->l_blocked_list); INIT_LIST_HEAD(&res->l_mask_waiters);}void ocfs2_inode_lock_res_init(struct ocfs2_lock_res *res, enum ocfs2_lock_type type, unsigned int generation, struct inode *inode){ struct ocfs2_lock_res_ops *ops; switch(type) { case OCFS2_LOCK_TYPE_RW: ops = &ocfs2_inode_rw_lops; break; case OCFS2_LOCK_TYPE_META: ops = &ocfs2_inode_inode_lops; break; case OCFS2_LOCK_TYPE_OPEN: ops = &ocfs2_inode_open_lops; break; default: mlog_bug_on_msg(1, "type: %d\n", type); ops = NULL; /* thanks, gcc */ break; }; ocfs2_build_lock_name(type, OCFS2_I(inode)->ip_blkno, generation, res->l_name); ocfs2_lock_res_init_common(OCFS2_SB(inode->i_sb), res, type, ops, inode);}static struct ocfs2_super *ocfs2_get_inode_osb(struct ocfs2_lock_res *lockres){ struct inode *inode = ocfs2_lock_res_inode(lockres); return OCFS2_SB(inode->i_sb);}static struct ocfs2_super *ocfs2_get_file_osb(struct ocfs2_lock_res *lockres){ struct ocfs2_file_private *fp = lockres->l_priv; return OCFS2_SB(fp->fp_file->f_mapping->host->i_sb);}static __u64 ocfs2_get_dentry_lock_ino(struct ocfs2_lock_res *lockres){ __be64 inode_blkno_be; memcpy(&inode_blkno_be, &lockres->l_name[OCFS2_DENTRY_LOCK_INO_START], sizeof(__be64)); return be64_to_cpu(inode_blkno_be);}static struct ocfs2_super *ocfs2_get_dentry_osb(struct ocfs2_lock_res *lockres){ struct ocfs2_dentry_lock *dl = lockres->l_priv; return OCFS2_SB(dl->dl_inode->i_sb);}void ocfs2_dentry_lock_res_init(struct ocfs2_dentry_lock *dl, u64 parent, struct inode *inode){ int len; u64 inode_blkno = OCFS2_I(inode)->ip_blkno; __be64 inode_blkno_be = cpu_to_be64(inode_blkno); struct ocfs2_lock_res *lockres = &dl->dl_lockres; ocfs2_lock_res_init_once(lockres); /* * Unfortunately, the standard lock naming scheme won't work * here because we have two 16 byte values to use. Instead, * we'll stuff the inode number as a binary value. We still * want error prints to show something without garbling the * display, so drop a null byte in there before the inode * number. A future version of OCFS2 will likely use all * binary lock names. The stringified names have been a * tremendous aid in debugging, but now that the debugfs * interface exists, we can mangle things there if need be. * * NOTE: We also drop the standard "pad" value (the total lock * name size stays the same though - the last part is all * zeros due to the memset in ocfs2_lock_res_init_once() */ len = snprintf(lockres->l_name, OCFS2_DENTRY_LOCK_INO_START, "%c%016llx", ocfs2_lock_type_char(OCFS2_LOCK_TYPE_DENTRY), (long long)parent); BUG_ON(len != (OCFS2_DENTRY_LOCK_INO_START - 1)); memcpy(&lockres->l_name[OCFS2_DENTRY_LOCK_INO_START], &inode_blkno_be, sizeof(__be64)); ocfs2_lock_res_init_common(OCFS2_SB(inode->i_sb), lockres, OCFS2_LOCK_TYPE_DENTRY, &ocfs2_dentry_lops, dl);}static void ocfs2_super_lock_res_init(struct ocfs2_lock_res *res, struct ocfs2_super *osb){ /* Superblock lockres doesn't come from a slab so we call init * once on it manually. */ ocfs2_lock_res_init_once(res); ocfs2_build_lock_name(OCFS2_LOCK_TYPE_SUPER, OCFS2_SUPER_BLOCK_BLKNO, 0, res->l_name); ocfs2_lock_res_init_common(osb, res, OCFS2_LOCK_TYPE_SUPER, &ocfs2_super_lops, osb);}static void ocfs2_rename_lock_res_init(struct ocfs2_lock_res *res, struct ocfs2_super *osb){ /* Rename lockres doesn't come from a slab so we call init * once on it manually. */ ocfs2_lock_res_init_once(res); ocfs2_build_lock_name(OCFS2_LOCK_TYPE_RENAME, 0, 0, res->l_name); ocfs2_lock_res_init_common(osb, res, OCFS2_LOCK_TYPE_RENAME, &ocfs2_rename_lops, osb);}void ocfs2_file_lock_res_init(struct ocfs2_lock_res *lockres, struct ocfs2_file_private *fp){ struct inode *inode = fp->fp_file->f_mapping->host; struct ocfs2_inode_info *oi = OCFS2_I(inode); ocfs2_lock_res_init_once(lockres); ocfs2_build_lock_name(OCFS2_LOCK_TYPE_FLOCK, oi->ip_blkno, inode->i_generation, lockres->l_name); ocfs2_lock_res_init_common(OCFS2_SB(inode->i_sb), lockres, OCFS2_LOCK_TYPE_FLOCK, &ocfs2_flock_lops, fp); lockres->l_flags |= OCFS2_LOCK_NOCACHE;}void ocfs2_lock_res_free(struct ocfs2_lock_res *res){ mlog_entry_void(); if (!(res->l_flags & OCFS2_LOCK_INITIALIZED)) return; ocfs2_remove_lockres_tracking(res); mlog_bug_on_msg(!list_empty(&res->l_blocked_list), "Lockres %s is on the blocked list\n", res->l_name); mlog_bug_on_msg(!list_empty(&res->l_mask_waiters), "Lockres %s has mask waiters pending\n", res->l_name); mlog_bug_on_msg(spin_is_locked(&res->l_lock), "Lockres %s is locked\n", res->l_name); mlog_bug_on_msg(res->l_ro_holders, "Lockres %s has %u ro holders\n", res->l_name, res->l_ro_holders); mlog_bug_on_msg(res->l_ex_holders, "Lockres %s has %u ex holders\n", res->l_name, res->l_ex_holders); /* Need to clear out the lock status block for the dlm */ memset(&res->l_lksb, 0, sizeof(res->l_lksb)); res->l_flags = 0UL; mlog_exit_void();}static inline void ocfs2_inc_holders(struct ocfs2_lock_res *lockres, int level){ mlog_entry_void(); BUG_ON(!lockres); switch(level) { case LKM_EXMODE: lockres->l_ex_holders++; break; case LKM_PRMODE: lockres->l_ro_holders++; break; default: BUG(); } mlog_exit_void();}static inline void ocfs2_dec_holders(struct ocfs2_lock_res *lockres, int level){ mlog_entry_void(); BUG_ON(!lockres); switch(level) { case LKM_EXMODE: BUG_ON(!lockres->l_ex_holders); lockres->l_ex_holders--; break; case LKM_PRMODE: BUG_ON(!lockres->l_ro_holders); lockres->l_ro_holders--; break; default: BUG(); } mlog_exit_void();}/* WARNING: This function lives in a world where the only three lock * levels are EX, PR, and NL. It *will* have to be adjusted when more * lock types are added. */static inline int ocfs2_highest_compat_lock_level(int level){ int new_level = LKM_EXMODE; if (level == LKM_EXMODE) new_level = LKM_NLMODE; else if (level == LKM_PRMODE) new_level = LKM_PRMODE; return new_level;}static void lockres_set_flags(struct ocfs2_lock_res *lockres, unsigned long newflags){ struct ocfs2_mask_waiter *mw, *tmp; assert_spin_locked(&lockres->l_lock); lockres->l_flags = newflags; list_for_each_entry_safe(mw, tmp, &lockres->l_mask_waiters, mw_item) { if ((lockres->l_flags & mw->mw_mask) != mw->mw_goal) continue; list_del_init(&mw->mw_item); mw->mw_status = 0; complete(&mw->mw_complete); }}static void lockres_or_flags(struct ocfs2_lock_res *lockres, unsigned long or){ lockres_set_flags(lockres, lockres->l_flags | or);}static void lockres_clear_flags(struct ocfs2_lock_res *lockres, unsigned long clear){ lockres_set_flags(lockres, lockres->l_flags & ~clear);}static inline void ocfs2_generic_handle_downconvert_action(struct ocfs2_lock_res *lockres){ mlog_entry_void(); BUG_ON(!(lockres->l_flags & OCFS2_LOCK_BUSY)); BUG_ON(!(lockres->l_flags & OCFS2_LOCK_ATTACHED)); BUG_ON(!(lockres->l_flags & OCFS2_LOCK_BLOCKED)); BUG_ON(lockres->l_blocking <= LKM_NLMODE); lockres->l_level = lockres->l_requested; if (lockres->l_level <= ocfs2_highest_compat_lock_level(lockres->l_blocking)) { lockres->l_blocking = LKM_NLMODE; lockres_clear_flags(lockres, OCFS2_LOCK_BLOCKED); } lockres_clear_flags(lockres, OCFS2_LOCK_BUSY); mlog_exit_void();}static inline void ocfs2_generic_handle_convert_action(struct ocfs2_lock_res *lockres){ mlog_entry_void(); BUG_ON(!(lockres->l_flags & OCFS2_LOCK_BUSY)); BUG_ON(!(lockres->l_flags & OCFS2_LOCK_ATTACHED)); /* Convert from RO to EX doesn't really need anything as our * information is already up to data. Convert from NL to * *anything* however should mark ourselves as needing an * update */ if (lockres->l_level == LKM_NLMODE && lockres->l_ops->flags & LOCK_TYPE_REQUIRES_REFRESH) lockres_or_flags(lockres, OCFS2_LOCK_NEEDS_REFRESH); lockres->l_level = lockres->l_requested; lockres_clear_flags(lockres, OCFS2_LOCK_BUSY); mlog_exit_void();}static inline void ocfs2_generic_handle_attach_action(struct ocfs2_lock_res *lockres){ mlog_entry_void(); BUG_ON((!(lockres->l_flags & OCFS2_LOCK_BUSY))); BUG_ON(lockres->l_flags & OCFS2_LOCK_ATTACHED); if (lockres->l_requested > LKM_NLMODE && !(lockres->l_flags & OCFS2_LOCK_LOCAL) && lockres->l_ops->flags & LOCK_TYPE_REQUIRES_REFRESH) lockres_or_flags(lockres, OCFS2_LOCK_NEEDS_REFRESH); lockres->l_level = lockres->l_requested; lockres_or_flags(lockres, OCFS2_LOCK_ATTACHED); lockres_clear_flags(lockres, OCFS2_LOCK_BUSY); mlog_exit_void();}static int ocfs2_generic_handle_bast(struct ocfs2_lock_res *lockres, int level){ int needs_downconvert = 0; mlog_entry_void(); assert_spin_locked(&lockres->l_lock); lockres_or_flags(lockres, OCFS2_LOCK_BLOCKED); if (level > lockres->l_blocking) { /* only schedule a downconvert if we haven't already scheduled * one that goes low enough to satisfy the level we're * blocking. this also catches the case where we get * duplicate BASTs */ if (ocfs2_highest_compat_lock_level(level) < ocfs2_highest_compat_lock_level(lockres->l_blocking)) needs_downconvert = 1; lockres->l_blocking = level; } mlog_exit(needs_downconvert); return needs_downconvert;}static void ocfs2_blocking_ast(void *opaque, int level){ struct ocfs2_lock_res *lockres = opaque; struct ocfs2_super *osb = ocfs2_get_lockres_osb(lockres); int needs_downconvert; unsigned long flags; BUG_ON(level <= LKM_NLMODE); mlog(0, "BAST fired for lockres %s, blocking %d, level %d type %s\n", lockres->l_name, level, lockres->l_level, ocfs2_lock_type_string(lockres->l_type)); /* * We can skip the bast for locks which don't enable caching - * they'll be dropped at the earliest possible time anyway. */ if (lockres->l_flags & OCFS2_LOCK_NOCACHE) return; spin_lock_irqsave(&lockres->l_lock, flags); needs_downconvert = ocfs2_generic_handle_bast(lockres, level); if (needs_downconvert) ocfs2_schedule_blocked_lock(osb, lockres); spin_unlock_irqrestore(&lockres->l_lock, flags); wake_up(&lockres->l_event); ocfs2_wake_downconvert_thread(osb);}static void ocfs2_locking_ast(void *opaque){ struct ocfs2_lock_res *lockres = opaque; struct dlm_lockstatus *lksb = &lockres->l_lksb; unsigned long flags; spin_lock_irqsave(&lockres->l_lock, flags); if (lksb->status != DLM_NORMAL) { mlog(ML_ERROR, "lockres %s: lksb status value of %u!\n", lockres->l_name, lksb->status); spin_unlock_irqrestore(&lockres->l_lock, flags); return; } switch(lockres->l_action) { case OCFS2_AST_ATTACH: ocfs2_generic_handle_attach_action(lockres); lockres_clear_flags(lockres, OCFS2_LOCK_LOCAL); break; case OCFS2_AST_CONVERT: ocfs2_generic_handle_convert_action(lockres); break; case OCFS2_AST_DOWNCONVERT: ocfs2_generic_handle_downconvert_action(lockres); break; default: mlog(ML_ERROR, "lockres %s: ast fired with invalid action: %u " "lockres flags = 0x%lx, unlock action: %u\n", lockres->l_name, lockres->l_action, lockres->l_flags, lockres->l_unlock_action); BUG(); } /* set it to something invalid so if we get called again we * can catch it. */ lockres->l_action = OCFS2_AST_INVALID; wake_up(&lockres->l_event); spin_unlock_irqrestore(&lockres->l_lock, flags);}static inline void ocfs2_recover_from_dlm_error(struct ocfs2_lock_res *lockres, int convert){ unsigned long flags; mlog_entry_void(); spin_lock_irqsave(&lockres->l_lock, flags); lockres_clear_flags(lockres, OCFS2_LOCK_BUSY); if (convert) lockres->l_action = OCFS2_AST_INVALID; else lockres->l_unlock_action = OCFS2_UNLOCK_INVALID; spin_unlock_irqrestore(&lockres->l_lock, flags); wake_up(&lockres->l_event); mlog_exit_void();}/* Note: If we detect another process working on the lock (i.e., * OCFS2_LOCK_BUSY), we'll bail out returning 0. It's up to the caller * to do the right thing in that case. */static int ocfs2_lock_create(struct ocfs2_super *osb, struct ocfs2_lock_res *lockres, int level, int dlm_flags){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -