dlmglue.c
来自「ocfs1.4.1 oracle分布式文件系统」· C语言 代码 · 共 2,359 行 · 第 1/5 页
C
2,359 行
int ret = 0; enum dlm_status status = DLM_NORMAL; unsigned long flags; mlog_entry_void(); mlog(0, "lock %s, level = %d, flags = %d\n", lockres->l_name, level, dlm_flags); spin_lock_irqsave(&lockres->l_lock, flags); if ((lockres->l_flags & OCFS2_LOCK_ATTACHED) || (lockres->l_flags & OCFS2_LOCK_BUSY)) { spin_unlock_irqrestore(&lockres->l_lock, flags); goto bail; } lockres->l_action = OCFS2_AST_ATTACH; lockres->l_requested = level; lockres_or_flags(lockres, OCFS2_LOCK_BUSY); spin_unlock_irqrestore(&lockres->l_lock, flags); status = dlmlock(osb->dlm, level, &lockres->l_lksb, dlm_flags, lockres->l_name, OCFS2_LOCK_ID_MAX_LEN - 1, ocfs2_locking_ast, lockres, ocfs2_blocking_ast); if (status != DLM_NORMAL) { ocfs2_log_dlm_error("dlmlock", status, lockres); ret = -EINVAL; ocfs2_recover_from_dlm_error(lockres, 1); } mlog(0, "lock %s, successfull return from dlmlock\n", lockres->l_name);bail: mlog_exit(ret); return ret;}static inline int ocfs2_check_wait_flag(struct ocfs2_lock_res *lockres, int flag){ unsigned long flags; int ret; spin_lock_irqsave(&lockres->l_lock, flags); ret = lockres->l_flags & flag; spin_unlock_irqrestore(&lockres->l_lock, flags); return ret;}static inline void ocfs2_wait_on_busy_lock(struct ocfs2_lock_res *lockres){ wait_event(lockres->l_event, !ocfs2_check_wait_flag(lockres, OCFS2_LOCK_BUSY));}static inline void ocfs2_wait_on_refreshing_lock(struct ocfs2_lock_res *lockres){ wait_event(lockres->l_event, !ocfs2_check_wait_flag(lockres, OCFS2_LOCK_REFRESHING));}/* predict what lock level we'll be dropping down to on behalf * of another node, and return true if the currently wanted * level will be compatible with it. */static inline int ocfs2_may_continue_on_blocked_lock(struct ocfs2_lock_res *lockres, int wanted){ BUG_ON(!(lockres->l_flags & OCFS2_LOCK_BLOCKED)); return wanted <= ocfs2_highest_compat_lock_level(lockres->l_blocking);}static void ocfs2_init_mask_waiter(struct ocfs2_mask_waiter *mw){ INIT_LIST_HEAD(&mw->mw_item); init_completion(&mw->mw_complete); ocfs2_init_start_time(mw);}static int ocfs2_wait_for_mask(struct ocfs2_mask_waiter *mw){ wait_for_completion(&mw->mw_complete); /* Re-arm the completion in case we want to wait on it again */ INIT_COMPLETION(mw->mw_complete); return mw->mw_status;}static void lockres_add_mask_waiter(struct ocfs2_lock_res *lockres, struct ocfs2_mask_waiter *mw, unsigned long mask, unsigned long goal){ BUG_ON(!list_empty(&mw->mw_item)); assert_spin_locked(&lockres->l_lock); list_add_tail(&mw->mw_item, &lockres->l_mask_waiters); mw->mw_mask = mask; mw->mw_goal = goal;}/* returns 0 if the mw that was removed was already satisfied, -EBUSY * if the mask still hadn't reached its goal */static int lockres_remove_mask_waiter(struct ocfs2_lock_res *lockres, struct ocfs2_mask_waiter *mw){ unsigned long flags; int ret = 0; spin_lock_irqsave(&lockres->l_lock, flags); if (!list_empty(&mw->mw_item)) { if ((lockres->l_flags & mw->mw_mask) != mw->mw_goal) ret = -EBUSY; list_del_init(&mw->mw_item); init_completion(&mw->mw_complete); } spin_unlock_irqrestore(&lockres->l_lock, flags); return ret;}static int ocfs2_wait_for_mask_interruptible(struct ocfs2_mask_waiter *mw, struct ocfs2_lock_res *lockres){ int ret; ret = wait_for_completion_interruptible(&mw->mw_complete); if (ret) lockres_remove_mask_waiter(lockres, mw); else ret = mw->mw_status; /* Re-arm the completion in case we want to wait on it again */ INIT_COMPLETION(mw->mw_complete); return ret;}static int ocfs2_cluster_lock(struct ocfs2_super *osb, struct ocfs2_lock_res *lockres, int level, int lkm_flags, int arg_flags){ struct ocfs2_mask_waiter mw; enum dlm_status status; int wait, catch_signals = !(osb->s_mount_opt & OCFS2_MOUNT_NOINTR); int ret = 0; /* gcc doesn't realize wait = 1 guarantees ret is set */ unsigned long flags; mlog_entry_void(); ocfs2_init_mask_waiter(&mw); if (lockres->l_ops->flags & LOCK_TYPE_USES_LVB) lkm_flags |= LKM_VALBLK;again: wait = 0; if (catch_signals && signal_pending(current)) { ret = -ERESTARTSYS; goto out; } spin_lock_irqsave(&lockres->l_lock, flags); mlog_bug_on_msg(lockres->l_flags & OCFS2_LOCK_FREEING, "Cluster lock called on freeing lockres %s! flags " "0x%lx\n", lockres->l_name, lockres->l_flags); /* We only compare against the currently granted level * here. If the lock is blocked waiting on a downconvert, * we'll get caught below. */ if (lockres->l_flags & OCFS2_LOCK_BUSY && level > lockres->l_level) { /* is someone sitting in dlm_lock? If so, wait on * them. */ lockres_add_mask_waiter(lockres, &mw, OCFS2_LOCK_BUSY, 0); wait = 1; goto unlock; } if (lockres->l_flags & OCFS2_LOCK_BLOCKED && !ocfs2_may_continue_on_blocked_lock(lockres, level)) { /* is the lock is currently blocked on behalf of * another node */ lockres_add_mask_waiter(lockres, &mw, OCFS2_LOCK_BLOCKED, 0); wait = 1; goto unlock; } if (level > lockres->l_level) { if (lockres->l_action != OCFS2_AST_INVALID) mlog(ML_ERROR, "lockres %s has action %u pending\n", lockres->l_name, lockres->l_action); if (!(lockres->l_flags & OCFS2_LOCK_ATTACHED)) { lockres->l_action = OCFS2_AST_ATTACH; lkm_flags &= ~LKM_CONVERT; } else { lockres->l_action = OCFS2_AST_CONVERT; lkm_flags |= LKM_CONVERT; } lockres->l_requested = level; lockres_or_flags(lockres, OCFS2_LOCK_BUSY); spin_unlock_irqrestore(&lockres->l_lock, flags); BUG_ON(level == LKM_IVMODE); BUG_ON(level == LKM_NLMODE); mlog(0, "lock %s, convert from %d to level = %d\n", lockres->l_name, lockres->l_level, level); /* call dlm_lock to upgrade lock now */ status = dlmlock(osb->dlm, level, &lockres->l_lksb, lkm_flags, lockres->l_name, OCFS2_LOCK_ID_MAX_LEN - 1, ocfs2_locking_ast, lockres, ocfs2_blocking_ast); if (status != DLM_NORMAL) { if ((lkm_flags & LKM_NOQUEUE) && (status == DLM_NOTQUEUED)) ret = -EAGAIN; else { ocfs2_log_dlm_error("dlmlock", status, lockres); ret = -EINVAL; } ocfs2_recover_from_dlm_error(lockres, 1); goto out; } mlog(0, "lock %s, successfull return from dlmlock\n", lockres->l_name); /* At this point we've gone inside the dlm and need to * complete our work regardless. */ catch_signals = 0; /* wait for busy to clear and carry on */ goto again; } /* Ok, if we get here then we're good to go. */ ocfs2_inc_holders(lockres, level); ret = 0;unlock: spin_unlock_irqrestore(&lockres->l_lock, flags);out: /* * This is helping work around a lock inversion between the page lock * and dlm locks. One path holds the page lock while calling aops * which block acquiring dlm locks. The voting thread holds dlm * locks while acquiring page locks while down converting data locks. * This block is helping an aop path notice the inversion and back * off to unlock its page lock before trying the dlm lock again. */ if (wait && arg_flags & OCFS2_LOCK_NONBLOCK && mw.mw_mask & (OCFS2_LOCK_BUSY|OCFS2_LOCK_BLOCKED)) { wait = 0; if (lockres_remove_mask_waiter(lockres, &mw)) ret = -EAGAIN; else goto again; } if (wait) { ret = ocfs2_wait_for_mask(&mw); if (ret == 0) goto again; mlog_errno(ret); } ocfs2_update_lock_stats(lockres, level, &mw, ret); mlog_exit(ret); return ret;}static void ocfs2_cluster_unlock(struct ocfs2_super *osb, struct ocfs2_lock_res *lockres, int level){ unsigned long flags; mlog_entry_void(); spin_lock_irqsave(&lockres->l_lock, flags); ocfs2_dec_holders(lockres, level); ocfs2_downconvert_on_unlock(osb, lockres); spin_unlock_irqrestore(&lockres->l_lock, flags); mlog_exit_void();}static int ocfs2_create_new_lock(struct ocfs2_super *osb, struct ocfs2_lock_res *lockres, int ex, int local){ int level = ex ? LKM_EXMODE : LKM_PRMODE; unsigned long flags; int lkm_flags = local ? LKM_LOCAL : 0; spin_lock_irqsave(&lockres->l_lock, flags); BUG_ON(lockres->l_flags & OCFS2_LOCK_ATTACHED); lockres_or_flags(lockres, OCFS2_LOCK_LOCAL); spin_unlock_irqrestore(&lockres->l_lock, flags); return ocfs2_lock_create(osb, lockres, level, lkm_flags);}/* Grants us an EX lock on the data and metadata resources, skipping * the normal cluster directory lookup. Use this ONLY on newly created * inodes which other nodes can't possibly see, and which haven't been * hashed in the inode hash yet. This can give us a good performance * increase as it'll skip the network broadcast normally associated * with creating a new lock resource. */int ocfs2_create_new_inode_locks(struct inode *inode){ int ret; struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); BUG_ON(!inode); BUG_ON(!ocfs2_inode_is_new(inode)); mlog_entry_void(); mlog(0, "Inode %llu\n", (unsigned long long)OCFS2_I(inode)->ip_blkno); /* NOTE: That we don't increment any of the holder counts, nor * do we add anything to a journal handle. Since this is * supposed to be a new inode which the cluster doesn't know * about yet, there is no need to. As far as the LVB handling * is concerned, this is basically like acquiring an EX lock * on a resource which has an invalid one -- we'll set it * valid when we release the EX. */ ret = ocfs2_create_new_lock(osb, &OCFS2_I(inode)->ip_rw_lockres, 1, 1); if (ret) { mlog_errno(ret); goto bail; } /* * We don't want to use LKM_LOCAL on a meta data lock as they * don't use a generation in their lock names. */ ret = ocfs2_create_new_lock(osb, &OCFS2_I(inode)->ip_inode_lockres, 1, 0); if (ret) { mlog_errno(ret); goto bail; } ret = ocfs2_create_new_lock(osb, &OCFS2_I(inode)->ip_open_lockres, 0, 0); if (ret) { mlog_errno(ret); goto bail; }bail: mlog_exit(ret); return ret;}int ocfs2_rw_lock(struct inode *inode, int write){ int status, level; struct ocfs2_lock_res *lockres; struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); BUG_ON(!inode); mlog_entry_void(); mlog(0, "inode %llu take %s RW lock\n", (unsigned long long)OCFS2_I(inode)->ip_blkno, write ? "EXMODE" : "PRMODE"); if (ocfs2_mount_local(osb)) return 0; lockres = &OCFS2_I(inode)->ip_rw_lockres; level = write ? LKM_EXMODE : LKM_PRMODE; status = ocfs2_cluster_lock(OCFS2_SB(inode->i_sb), lockres, level, 0, 0); if (status < 0) mlog_errno(status); mlog_exit(status); return status;}void ocfs2_rw_unlock(struct inode *inode, int write){ int level = write ? LKM_EXMODE : LKM_PRMODE; struct ocfs2_lock_res *lockres = &OCFS2_I(inode)->ip_rw_lockres; struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); mlog_entry_void(); mlog(0, "inode %llu drop %s RW lock\n", (unsigned long long)OCFS2_I(inode)->ip_blkno, write ? "EXMODE" : "PRMODE"); if (!ocfs2_mount_local(osb)) ocfs2_cluster_unlock(OCFS2_SB(inode->i_sb), lockres, level); mlog_exit_void();}/* * ocfs2_open_lock always get PR mode lock. */int ocfs2_open_lock(struct inode *inode){ int status = 0; struct ocfs2_lock_res *lockres; struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); BUG_ON(!inode); mlog_entry_void(); mlog(0, "inode %llu take PRMODE open lock\n", (unsigned long long)OCFS2_I(inode)->ip_blkno); if (ocfs2_mount_local(osb)) goto out; lockres = &OCFS2_I(inode)->ip_open_lockres; status = ocfs2_cluster_lock(OCFS2_SB(inode->i_sb), lockres, LKM_PRMODE, 0, 0); if (status < 0) mlog_errno(status);out: mlog_exit(status); return status;}int ocfs2_try_open_lock(struct inode *inode, int write){ int status = 0, level; struct ocfs2_lock_res *lockres; struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); BUG_ON(!inode); mlog_entry_void(); mlog(0, "inode %llu try to take %s open lock\n", (unsigned long long)OCFS2_I(inode)->ip_blkno, write ? "EXMODE" : "PRMODE"); if (ocfs2_mount_local(osb)) goto out;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?