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

📄 svclock.c

📁 ARM 嵌入式 系统 设计与实例开发 实验教材 二源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * linux/fs/lockd/svclock.c * * Handling of server-side locks, mostly of the blocked variety. * This is the ugliest part of lockd because we tread on very thin ice. * GRANT and CANCEL calls may get stuck, meet in mid-flight, etc. * IMNSHO introducing the grant callback into the NLM protocol was one * of the worst ideas Sun ever had. Except maybe for the idea of doing * NFS file locking at all. * * I'm trying hard to avoid race conditions by protecting most accesses * to a file's list of blocked locks through a semaphore. The global * list of blocked locks is not protected in this fashion however. * Therefore, some functions (such as the RPC callback for the async grant * call) move blocked locks towards the head of the list *while some other * process might be traversing it*. This should not be a problem in * practice, because this will only cause functions traversing the list * to visit some blocks twice. * * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> */#include <linux/config.h>#include <linux/types.h>#include <linux/errno.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/smp_lock.h>#include <linux/sunrpc/clnt.h>#include <linux/sunrpc/svc.h>#include <linux/lockd/nlm.h>#include <linux/lockd/lockd.h>#define NLMDBG_FACILITY		NLMDBG_SVCLOCK#ifdef CONFIG_LOCKD_V4#define nlm_deadlock	nlm4_deadlock#else#define nlm_deadlock	nlm_lck_denied#endifstatic void	nlmsvc_insert_block(struct nlm_block *block, unsigned long);static int	nlmsvc_remove_block(struct nlm_block *block);static void	nlmsvc_grant_callback(struct rpc_task *task);static void	nlmsvc_notify_blocked(struct file_lock *);/* * The list of blocked locks to retry */static struct nlm_block *	nlm_blocked;/* * Insert a blocked lock into the global list */static voidnlmsvc_insert_block(struct nlm_block *block, unsigned long when){	struct nlm_block **bp, *b;	dprintk("lockd: nlmsvc_insert_block(%p, %ld)\n", block, when);	if (block->b_queued)		nlmsvc_remove_block(block);	bp = &nlm_blocked;	if (when != NLM_NEVER) {		if ((when += jiffies) == NLM_NEVER)			when ++;		while ((b = *bp) && time_before_eq(b->b_when,when))			bp = &b->b_next;	} else		while ((b = *bp))			bp = &b->b_next;	block->b_queued = 1;	block->b_when = when;	block->b_next = b;	*bp = block;}/* * Remove a block from the global list */static intnlmsvc_remove_block(struct nlm_block *block){	struct nlm_block **bp, *b;	if (!block->b_queued)		return 1;	for (bp = &nlm_blocked; (b = *bp); bp = &b->b_next) {		if (b == block) {			*bp = block->b_next;			block->b_queued = 0;			return 1;		}	}	return 0;}/* * Find a block for a given lock and optionally remove it from * the list. */static struct nlm_block *nlmsvc_lookup_block(struct nlm_file *file, struct nlm_lock *lock, int remove){	struct nlm_block	**head, *block;	struct file_lock	*fl;	dprintk("lockd: nlmsvc_lookup_block f=%p pd=%d %Ld-%Ld ty=%d\n",				file, lock->fl.fl_pid,				(long long)lock->fl.fl_start,				(long long)lock->fl.fl_end, lock->fl.fl_type);	for (head = &nlm_blocked; (block = *head); head = &block->b_next) {		fl = &block->b_call.a_args.lock.fl;		dprintk("lockd: check f=%p pd=%d %Ld-%Ld ty=%d cookie=%x\n",				block->b_file, fl->fl_pid,				(long long)fl->fl_start,				(long long)fl->fl_end, fl->fl_type,				*(unsigned int*)(block->b_call.a_args.cookie.data));		if (block->b_file == file && nlm_compare_locks(fl, &lock->fl)) {			if (remove) {				*head = block->b_next;				block->b_queued = 0;			}			return block;		}	}	return NULL;}static inline int nlm_cookie_match(struct nlm_cookie *a, struct nlm_cookie *b){	if(a->len != b->len)		return 0;	if(memcmp(a->data,b->data,a->len))		return 0;	return 1;}/* * Find a block with a given NLM cookie. */static inline struct nlm_block *nlmsvc_find_block(struct nlm_cookie *cookie){	struct nlm_block *block;	for (block = nlm_blocked; block; block = block->b_next) {		dprintk("cookie: head of blocked queue %p, block %p\n", 			nlm_blocked, block);		if (nlm_cookie_match(&block->b_call.a_args.cookie,cookie))			break;	}	return block;}/* * Create a block and initialize it. * * Note: we explicitly set the cookie of the grant reply to that of * the blocked lock request. The spec explicitly mentions that the client * should _not_ rely on the callback containing the same cookie as the * request, but (as I found out later) that's because some implementations * do just this. Never mind the standards comittees, they support our * logging industries. */static inline struct nlm_block *nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file,				struct nlm_lock *lock, struct nlm_cookie *cookie){	struct nlm_block	*block;	struct nlm_host		*host;	struct nlm_rqst		*call;	/* Create host handle for callback */	host = nlmclnt_lookup_host(&rqstp->rq_addr,				rqstp->rq_prot, rqstp->rq_vers);	if (host == NULL)		return NULL;	/* Allocate memory for block, and initialize arguments */	if (!(block = (struct nlm_block *) kmalloc(sizeof(*block), GFP_KERNEL)))		goto failed;	memset(block, 0, sizeof(*block));	locks_init_lock(&block->b_call.a_args.lock.fl);	locks_init_lock(&block->b_call.a_res.lock.fl);	if (!nlmclnt_setgrantargs(&block->b_call, lock))		goto failed_free;	/* Set notifier function for VFS, and init args */	block->b_call.a_args.lock.fl.fl_notify = nlmsvc_notify_blocked;	block->b_call.a_args.cookie = *cookie;	/* see above */	dprintk("lockd: created block %p...\n", block);	/* Create and initialize the block */	block->b_daemon = rqstp->rq_server;	block->b_host   = host;	block->b_file   = file;	/* Add to file's list of blocks */	block->b_fnext  = file->f_blocks;	file->f_blocks  = block;	/* Set up RPC arguments for callback */	call = &block->b_call;	call->a_host    = host;	call->a_flags   = RPC_TASK_ASYNC;	return block;failed_free:	kfree(block);failed:	nlm_release_host(host);	return NULL;}/* * Delete a block. If the lock was cancelled or the grant callback * failed, unlock is set to 1. * It is the caller's responsibility to check whether the file * can be closed hereafter. */static voidnlmsvc_delete_block(struct nlm_block *block, int unlock){	struct file_lock	*fl = &block->b_call.a_args.lock.fl;	struct nlm_file		*file = block->b_file;	struct nlm_block	**bp;	dprintk("lockd: deleting block %p...\n", block);	/* Remove block from list */	nlmsvc_remove_block(block);	/* If granted, unlock it, else remove from inode block list */	if (unlock && block->b_granted) {		dprintk("lockd: deleting granted lock\n");		fl->fl_type = F_UNLCK;		posix_lock_file(&block->b_file->f_file, fl, 0);		block->b_granted = 0;	} else {		dprintk("lockd: unblocking blocked lock\n");		posix_unblock_lock(fl);	}	/* If the block is in the middle of a GRANT callback,	 * don't kill it yet. */	if (block->b_incall) {		nlmsvc_insert_block(block, NLM_NEVER);		block->b_done = 1;		return;	}	/* Remove block from file's list of blocks */	for (bp = &file->f_blocks; *bp; bp = &(*bp)->b_fnext) {		if (*bp == block) {			*bp = block->b_fnext;			break;		}	}	if (block->b_host)		nlm_release_host(block->b_host);	nlmclnt_freegrantargs(&block->b_call);	kfree(block);}/* * Loop over all blocks and perform the action specified. * (NLM_ACT_CHECK handled by nlmsvc_inspect_file). */intnlmsvc_traverse_blocks(struct nlm_host *host, struct nlm_file *file, int action){	struct nlm_block	*block, *next;	down(&file->f_sema);	for (block = file->f_blocks; block; block = next) {		next = block->b_fnext;		if (action == NLM_ACT_MARK)			block->b_host->h_inuse = 1;		else if (action == NLM_ACT_UNLOCK) {			if (host == NULL || host == block->b_host)				nlmsvc_delete_block(block, 1);		}	}	up(&file->f_sema);	return 0;}/* * Attempt to establish a lock, and if it can't be granted, block it * if required. */u32nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,			struct nlm_lock *lock, int wait, struct nlm_cookie *cookie){	struct file_lock	*conflock;	struct nlm_block	*block;	int			error;	dprintk("lockd: nlmsvc_lock(%04x/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n",				file->f_file.f_dentry->d_inode->i_dev,				file->f_file.f_dentry->d_inode->i_ino,				lock->fl.fl_type, lock->fl.fl_pid,				(long long)lock->fl.fl_start,				(long long)lock->fl.fl_end,				wait);	/* Lock file against concurrent access */	down(&file->f_sema);	/* Get existing block (in case client is busy-waiting) */	block = nlmsvc_lookup_block(file, lock, 0);	lock->fl.fl_flags |= FL_LOCKD;again:	if (!(conflock = posix_test_lock(&file->f_file, &lock->fl))) {		error = posix_lock_file(&file->f_file, &lock->fl, 0);		if (block)			nlmsvc_delete_block(block, 0);		up(&file->f_sema);		dprintk("lockd: posix_lock_file returned %d\n", -error);		switch(-error) {		case 0:			return nlm_granted;

⌨️ 快捷键说明

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