⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dlmglue.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	 * 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_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));	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_kick_vote_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){	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);}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_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;	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -