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 + -
显示快捷键?