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

📄 dlmglue.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	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);	}	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_vote_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_meta_lockres, 1, 0);	if (ret) {		mlog_errno(ret);		goto bail;	}	ret = ocfs2_create_new_lock(osb, &OCFS2_I(inode)->ip_data_lockres, 1, 1);	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;	lockres = &OCFS2_I(inode)->ip_open_lockres;	level = write ? LKM_EXMODE : LKM_PRMODE;	/*	 * The file system may already holding a PRMODE/EXMODE open lock.	 * Since we pass LKM_NOQUEUE, the request won't block waiting on	 * other nodes and the -EAGAIN will indicate to the caller that	 * this inode is still in use.	 */	status = ocfs2_cluster_lock(OCFS2_SB(inode->i_sb), lockres,				    level, LKM_NOQUEUE, 0);out:	mlog_exit(status);	return status;}/* * ocfs2_open_unlock unlock PR and EX mode open locks. */void ocfs2_open_unlock(struct inode *inode){	struct ocfs2_lock_res *lockres = &OCFS2_I(inode)->ip_open_lockres;	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);	mlog_entry_void();	mlog(0, "inode %llu drop open lock\n",	     (unsigned long long)OCFS2_I(inode)->ip_blkno);	if (ocfs2_mount_local(osb))		goto out;	if(lockres->l_ro_holders)		ocfs2_cluster_unlock(OCFS2_SB(inode->i_sb), lockres,				     LKM_PRMODE);	if(lockres->l_ex_holders)		ocfs2_cluster_unlock(OCFS2_SB(inode->i_sb), lockres,				     LKM_EXMODE);out:	mlog_exit_void();}int ocfs2_data_lock_full(struct inode *inode,			 int write,			 int arg_flags){	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 take %s DATA lock\n",	     (unsigned long long)OCFS2_I(inode)->ip_blkno,	     write ? "EXMODE" : "PRMODE");	/* We'll allow faking a readonly data lock for	 * rodevices. */	if (ocfs2_is_hard_readonly(OCFS2_SB(inode->i_sb))) {		if (write) {			status = -EROFS;			mlog_errno(status);		}		goto out;	}	if (ocfs2_mount_local(osb))		goto out;	lockres = &OCFS2_I(inode)->ip_data_lockres;	level = write ? LKM_EXMODE : LKM_PRMODE;	status = ocfs2_cluster_lock(OCFS2_SB(inode->i_sb), lockres, level,				    0, arg_flags);	if (status < 0 && status != -EAGAIN)		mlog_errno(status);out:	mlog_exit(status);	return status;}/* see ocfs2_meta_lock_with_page() */int ocfs2_data_lock_with_page(struct inode *inode,			      int write,			      struct page *page){	int ret;	ret = ocfs2_data_lock_full(inode, write, OCFS2_LOCK_NONBLOCK);	if (ret == -EAGAIN) {		unlock_page(page);		if (ocfs2_data_lock(inode, write) == 0)			ocfs2_data_unlock(inode, write);		ret = AOP_TRUNCATED_PAGE;	}	return ret;}static void ocfs2_vote_on_unlock(struct ocfs2_super *osb,				 struct ocfs2_lock_res *lockres){	int kick = 0;	mlog_entry_void();	/* If we know that another node is waiting on our lock, kick	 * the vote thread * pre-emptively when we reach a release	 * condition. */	if (lockres->l_flags & OCFS2_LOCK_BLOCKED) {		switch(lockres->l_blocking) {		case LKM_EXMODE:			if (!lockres->l_ex_holders && !lockres->l_ro_holders)				kick = 1;			break;		case LKM_PRMODE:			if (!lockres->l_ex_holders)				kick = 1;			break;		default:			BUG();		}	}	if (kick)		ocfs2_kick_vote_thread(osb);	mlog_exit_void();}void ocfs2_data_unlock(struct inode *inode,		       int write){	int level = write ? LKM_EXMODE : LKM_PRMODE;	struct ocfs2_lock_res *lockres = &OCFS2_I(inode)->ip_data_lockres;	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);	mlog_entry_void();	mlog(0, "inode %llu drop %s DATA lock\n",	     (unsigned long long)OCFS2_I(inode)->ip_blkno,	     write ? "EXMODE" : "PRMODE");	if (!ocfs2_is_hard_readonly(OCFS2_SB(inode->i_sb)) &&	    !ocfs2_mount_local(osb))		ocfs2_cluster_unlock(OCFS2_SB(inode->i_sb), lockres, level);	mlog_exit_void();}#define OCFS2_SEC_BITS   34#define OCFS2_SEC_SHIFT  (64 - 34)#define OCFS2_NSEC_MASK  ((1ULL << OCFS2_SEC_SHIFT) - 1)/* LVB only has room for 64 bits of time here so we pack it for * now. */static u64 ocfs2_pack_timespec(struct timespec *spec){	u64 res;	u64 sec = spec->tv_sec;	u32 nsec = spec->tv_nsec;	res = (sec << OCFS2_SEC_SHIFT) | (nsec & OCFS2_NSEC_MASK);	return res;}/* Call this with the lockres locked. I am reasonably sure we don't * need ip_lock in this function as anyone who would be changing those * values is supposed to be blocked in ocfs2_meta_lock right now. */static void __ocfs2_stuff_meta_lvb(struct inode *inode){	struct ocfs2_inode_info *oi = OCFS2_I(inode);	struct ocfs2_lock_res *lockres = &oi->ip_meta_lockres;	struct ocfs2_meta_lvb *lvb;	mlog_entry_void();	lvb = (struct ocfs2_meta_lvb *) lockres->l_lksb.lvb;	/*	 * Invalidate the LVB of a deleted inode - this way other	 * nodes are forced to go to disk and discover the new inode	 * status.	 */	if (oi->ip_flags & OCFS2_INODE_DELETED) {		lvb->lvb_version = 0;		goto out;	}	lvb->lvb_version   = OCFS2_LVB_VERSION;	lvb->lvb_isize	   = cpu_to_be64(i_size_read(inode));	lvb->lvb_iclusters = cpu_to_be32(oi->ip_clusters);	lvb->lvb_iuid      = cpu_to_be32(inode->i_uid);	lvb->lvb_igid      = cpu_to_be32(inode->i_gid);	lvb->lvb_imode     = cpu_to_be16(inode->i_mode);	lvb->lvb_inlink    = cpu_to_be16(inode->i_nlink);	lvb->lvb_iatime_packed  =

⌨️ 快捷键说明

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