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

📄 svclock.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 2 页
字号:
					       * is a NLMv1,3 request */#else			/* no applicable NLM status */#endif		case EAGAIN:			return nlm_lck_denied;		default:			/* includes ENOLCK */			return nlm_lck_denied_nolocks;		}	}	if (!wait) {		up(&file->f_sema);		return nlm_lck_denied;	}	/* If we don't have a block, create and initialize it. Then	 * retry because we may have slept in kmalloc. */	if (block == NULL) {		dprintk("lockd: blocking on this lock (allocating).\n");		if (!(block = nlmsvc_create_block(rqstp, file, lock, cookie)))			return nlm_lck_denied_nolocks;		goto again;	}	/* Append to list of blocked */	nlmsvc_insert_block(block, NLM_NEVER);	if (list_empty(&block->b_call.a_args.lock.fl.fl_block)) {		/* Now add block to block list of the conflicting lock		   if we haven't done so. */		dprintk("lockd: blocking on this lock.\n");		posix_block_lock(conflock, &block->b_call.a_args.lock.fl);	}	up(&file->f_sema);	return nlm_lck_blocked;}/* * Test for presence of a conflicting lock. */u32nlmsvc_testlock(struct nlm_file *file, struct nlm_lock *lock,				       struct nlm_lock *conflock){	struct file_lock	*fl;	dprintk("lockd: nlmsvc_testlock(%04x/%ld, ty=%d, %Ld-%Ld)\n",				file->f_file.f_dentry->d_inode->i_dev,				file->f_file.f_dentry->d_inode->i_ino,				lock->fl.fl_type,				(long long)lock->fl.fl_start,				(long long)lock->fl.fl_end);	if ((fl = posix_test_lock(&file->f_file, &lock->fl)) != NULL) {		dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n",				fl->fl_type, (long long)fl->fl_start,				(long long)fl->fl_end);		conflock->caller = "somehost";	/* FIXME */		conflock->oh.len = 0;		/* don't return OH info */		conflock->fl = *fl;		return nlm_lck_denied;	}	return nlm_granted;}/* * Remove a lock. * This implies a CANCEL call: We send a GRANT_MSG, the client replies * with a GRANT_RES call which gets lost, and calls UNLOCK immediately * afterwards. In this case the block will still be there, and hence * must be removed. */u32nlmsvc_unlock(struct nlm_file *file, struct nlm_lock *lock){	int	error;	dprintk("lockd: nlmsvc_unlock(%04x/%ld, pi=%d, %Ld-%Ld)\n",				file->f_file.f_dentry->d_inode->i_dev,				file->f_file.f_dentry->d_inode->i_ino,				lock->fl.fl_pid,				(long long)lock->fl.fl_start,				(long long)lock->fl.fl_end);	/* First, cancel any lock that might be there */	nlmsvc_cancel_blocked(file, lock);	lock->fl.fl_type = F_UNLCK;	error = posix_lock_file(&file->f_file, &lock->fl, 0);	return (error < 0)? nlm_lck_denied_nolocks : nlm_granted;}/* * Cancel a previously blocked request. * * A cancel request always overrides any grant that may currently * be in progress. * The calling procedure must check whether the file can be closed. */u32nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock){	struct nlm_block	*block;	dprintk("lockd: nlmsvc_cancel(%04x/%ld, pi=%d, %Ld-%Ld)\n",				file->f_file.f_dentry->d_inode->i_dev,				file->f_file.f_dentry->d_inode->i_ino,				lock->fl.fl_pid,				(long long)lock->fl.fl_start,				(long long)lock->fl.fl_end);	down(&file->f_sema);	if ((block = nlmsvc_lookup_block(file, lock, 1)) != NULL)		nlmsvc_delete_block(block, 1);	up(&file->f_sema);	return nlm_granted;}/* * Unblock a blocked lock request. This is a callback invoked from the * VFS layer when a lock on which we blocked is removed. * * This function doesn't grant the blocked lock instantly, but rather moves * the block to the head of nlm_blocked where it can be picked up by lockd. */static voidnlmsvc_notify_blocked(struct file_lock *fl){	struct nlm_block	**bp, *block;	dprintk("lockd: VFS unblock notification for block %p\n", fl);	posix_unblock_lock(fl);	for (bp = &nlm_blocked; (block = *bp); bp = &block->b_next) {		if (nlm_compare_locks(&block->b_call.a_args.lock.fl, fl)) {			nlmsvc_insert_block(block, 0);			svc_wake_up(block->b_daemon);			return;		}	}	printk(KERN_WARNING "lockd: notification for unknown block!\n");}/* * Try to claim a lock that was previously blocked. * * Note that we use both the RPC_GRANTED_MSG call _and_ an async * RPC thread when notifying the client. This seems like overkill... * Here's why: *  -	we don't want to use a synchronous RPC thread, otherwise *	we might find ourselves hanging on a dead portmapper. *  -	Some lockd implementations (e.g. HP) don't react to *	RPC_GRANTED calls; they seem to insist on RPC_GRANTED_MSG calls. */static voidnlmsvc_grant_blocked(struct nlm_block *block){	struct nlm_file		*file = block->b_file;	struct nlm_lock		*lock = &block->b_call.a_args.lock;	struct file_lock	*conflock;	int			error;	dprintk("lockd: grant blocked lock %p\n", block);	/* First thing is lock the file */	down(&file->f_sema);	/* Unlink block request from list */	nlmsvc_remove_block(block);	/* If b_granted is true this means we've been here before.	 * Just retry the grant callback, possibly refreshing the RPC	 * binding */	if (block->b_granted) {		nlm_rebind_host(block->b_host);		goto callback;	}	/* Try the lock operation again */	if ((conflock = posix_test_lock(&file->f_file, &lock->fl)) != NULL) {		/* Bummer, we blocked again */		dprintk("lockd: lock still blocked\n");		nlmsvc_insert_block(block, NLM_NEVER);		posix_block_lock(conflock, &lock->fl);		up(&file->f_sema);		return;	}	/* Alright, no conflicting lock. Now lock it for real. If the	 * following yields an error, this is most probably due to low	 * memory. Retry the lock in a few seconds.	 */	if ((error = posix_lock_file(&file->f_file, &lock->fl, 0)) < 0) {		printk(KERN_WARNING "lockd: unexpected error %d in %s!\n",				-error, __FUNCTION__);		nlmsvc_insert_block(block, 10 * HZ);		up(&file->f_sema);		return;	}callback:	/* Lock was granted by VFS. */	dprintk("lockd: GRANTing blocked lock.\n");	block->b_granted = 1;	block->b_incall  = 1;	/* Schedule next grant callback in 30 seconds */	nlmsvc_insert_block(block, 30 * HZ);	/* Call the client */	nlm_get_host(block->b_call.a_host);	if (nlmsvc_async_call(&block->b_call, NLMPROC_GRANTED_MSG,						nlmsvc_grant_callback) < 0)		nlm_release_host(block->b_call.a_host);	up(&file->f_sema);}/* * This is the callback from the RPC layer when the NLM_GRANTED_MSG * RPC call has succeeded or timed out. * Like all RPC callbacks, it is invoked by the rpciod process, so it * better not sleep. Therefore, we put the blocked lock on the nlm_blocked * chain once more in order to have it removed by lockd itself (which can * then sleep on the file semaphore without disrupting e.g. the nfs client). */static voidnlmsvc_grant_callback(struct rpc_task *task){	struct nlm_rqst		*call = (struct nlm_rqst *) task->tk_calldata;	struct nlm_block	*block;	unsigned long		timeout;	dprintk("lockd: GRANT_MSG RPC callback\n");	dprintk("callback: looking for cookie %x \n", 		*(unsigned int *)(call->a_args.cookie.data));	if (!(block = nlmsvc_find_block(&call->a_args.cookie))) {		dprintk("lockd: no block for cookie %x\n", *(u32 *)(call->a_args.cookie.data));		return;	}	/* Technically, we should down the file semaphore here. Since we	 * move the block towards the head of the queue only, no harm	 * can be done, though. */	if (task->tk_status < 0) {		/* RPC error: Re-insert for retransmission */		timeout = 10 * HZ;	} else if (block->b_done) {		/* Block already removed, kill it for real */		timeout = 0;	} else {		/* Call was successful, now wait for client callback */		timeout = 60 * HZ;	}	nlmsvc_insert_block(block, timeout);	svc_wake_up(block->b_daemon);	block->b_incall = 0;	nlm_release_host(call->a_host);}/* * We received a GRANT_RES callback. Try to find the corresponding * block. */voidnlmsvc_grant_reply(struct nlm_cookie *cookie, u32 status){	struct nlm_block	*block;	struct nlm_file		*file;	if (!(block = nlmsvc_find_block(cookie)))		return;	file = block->b_file;	file->f_count++;	down(&file->f_sema);	if ((block = nlmsvc_find_block(cookie)) != NULL) {		if (status == NLM_LCK_DENIED_GRACE_PERIOD) {			/* Try again in a couple of seconds */			nlmsvc_insert_block(block, 10 * HZ);			block = NULL;		} else {			/* Lock is now held by client, or has been rejected.			 * In both cases, the block should be removed. */			file->f_count++;			up(&file->f_sema);			if (status == NLM_LCK_GRANTED)				nlmsvc_delete_block(block, 0);			else				nlmsvc_delete_block(block, 1);		}	}	if (!block)		up(&file->f_sema);	nlm_release_file(file);}/* * Retry all blocked locks that have been notified. This is where lockd * picks up locks that can be granted, or grant notifications that must * be retransmitted. */unsigned longnlmsvc_retry_blocked(void){	struct nlm_block	*block;	dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n",			nlm_blocked,			nlm_blocked? nlm_blocked->b_when : 0);	while ((block = nlm_blocked)) {		if (block->b_when == NLM_NEVER)			break;	        if (time_after(block->b_when,jiffies))			break;		dprintk("nlmsvc_retry_blocked(%p, when=%ld, done=%d)\n",			block, block->b_when, block->b_done);		if (block->b_done)			nlmsvc_delete_block(block, 0);		else			nlmsvc_grant_blocked(block);	}	if ((block = nlm_blocked) && block->b_when != NLM_NEVER)		return (block->b_when - jiffies);	return MAX_SCHEDULE_TIMEOUT;}

⌨️ 快捷键说明

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