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

📄 flock.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* AFS file locking support * * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */#include <linux/smp_lock.h>#include "internal.h"#define AFS_LOCK_GRANTED	0#define AFS_LOCK_PENDING	1static void afs_fl_copy_lock(struct file_lock *new, struct file_lock *fl);static void afs_fl_release_private(struct file_lock *fl);static struct workqueue_struct *afs_lock_manager;static DEFINE_MUTEX(afs_lock_manager_mutex);static struct file_lock_operations afs_lock_ops = {	.fl_copy_lock		= afs_fl_copy_lock,	.fl_release_private	= afs_fl_release_private,};/* * initialise the lock manager thread if it isn't already running */static int afs_init_lock_manager(void){	int ret;	ret = 0;	if (!afs_lock_manager) {		mutex_lock(&afs_lock_manager_mutex);		if (!afs_lock_manager) {			afs_lock_manager =				create_singlethread_workqueue("kafs_lockd");			if (!afs_lock_manager)				ret = -ENOMEM;		}		mutex_unlock(&afs_lock_manager_mutex);	}	return ret;}/* * destroy the lock manager thread if it's running */void __exit afs_kill_lock_manager(void){	if (afs_lock_manager)		destroy_workqueue(afs_lock_manager);}/* * if the callback is broken on this vnode, then the lock may now be available */void afs_lock_may_be_available(struct afs_vnode *vnode){	_enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode);	queue_delayed_work(afs_lock_manager, &vnode->lock_work, 0);}/* * the lock will time out in 5 minutes unless we extend it, so schedule * extension in a bit less than that time */static void afs_schedule_lock_extension(struct afs_vnode *vnode){	queue_delayed_work(afs_lock_manager, &vnode->lock_work,			   AFS_LOCKWAIT * HZ / 2);}/* * grant one or more locks (readlocks are allowed to jump the queue if the * first lock in the queue is itself a readlock) * - the caller must hold the vnode lock */static void afs_grant_locks(struct afs_vnode *vnode, struct file_lock *fl){	struct file_lock *p, *_p;	list_move_tail(&fl->fl_u.afs.link, &vnode->granted_locks);	if (fl->fl_type == F_RDLCK) {		list_for_each_entry_safe(p, _p, &vnode->pending_locks,					 fl_u.afs.link) {			if (p->fl_type == F_RDLCK) {				p->fl_u.afs.state = AFS_LOCK_GRANTED;				list_move_tail(&p->fl_u.afs.link,					       &vnode->granted_locks);				wake_up(&p->fl_wait);			}		}	}}/* * do work for a lock, including: * - probing for a lock we're waiting on but didn't get immediately * - extending a lock that's close to timing out */void afs_lock_work(struct work_struct *work){	struct afs_vnode *vnode =		container_of(work, struct afs_vnode, lock_work.work);	struct file_lock *fl;	afs_lock_type_t type;	struct key *key;	int ret;	_enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode);	spin_lock(&vnode->lock);	if (test_bit(AFS_VNODE_UNLOCKING, &vnode->flags)) {		_debug("unlock");		spin_unlock(&vnode->lock);		/* attempt to release the server lock; if it fails, we just		 * wait 5 minutes and it'll time out anyway */		ret = afs_vnode_release_lock(vnode, vnode->unlock_key);		if (ret < 0)			printk(KERN_WARNING "AFS:"			       " Failed to release lock on {%x:%x} error %d\n",			       vnode->fid.vid, vnode->fid.vnode, ret);		spin_lock(&vnode->lock);		key_put(vnode->unlock_key);		vnode->unlock_key = NULL;		clear_bit(AFS_VNODE_UNLOCKING, &vnode->flags);	}	/* if we've got a lock, then it must be time to extend that lock as AFS	 * locks time out after 5 minutes */	if (!list_empty(&vnode->granted_locks)) {		_debug("extend");		if (test_and_set_bit(AFS_VNODE_LOCKING, &vnode->flags))			BUG();		fl = list_entry(vnode->granted_locks.next,				struct file_lock, fl_u.afs.link);		key = key_get(fl->fl_file->private_data);		spin_unlock(&vnode->lock);		ret = afs_vnode_extend_lock(vnode, key);		clear_bit(AFS_VNODE_LOCKING, &vnode->flags);		key_put(key);		switch (ret) {		case 0:			afs_schedule_lock_extension(vnode);			break;		default:			/* ummm... we failed to extend the lock - retry			 * extension shortly */			printk(KERN_WARNING "AFS:"			       " Failed to extend lock on {%x:%x} error %d\n",			       vnode->fid.vid, vnode->fid.vnode, ret);			queue_delayed_work(afs_lock_manager, &vnode->lock_work,					   HZ * 10);			break;		}		_leave(" [extend]");		return;	}	/* if we don't have a granted lock, then we must've been called back by	 * the server, and so if might be possible to get a lock we're	 * currently waiting for */	if (!list_empty(&vnode->pending_locks)) {		_debug("get");		if (test_and_set_bit(AFS_VNODE_LOCKING, &vnode->flags))			BUG();		fl = list_entry(vnode->pending_locks.next,				struct file_lock, fl_u.afs.link);		key = key_get(fl->fl_file->private_data);		type = (fl->fl_type == F_RDLCK) ?			AFS_LOCK_READ : AFS_LOCK_WRITE;		spin_unlock(&vnode->lock);		ret = afs_vnode_set_lock(vnode, key, type);		clear_bit(AFS_VNODE_LOCKING, &vnode->flags);		switch (ret) {		case -EWOULDBLOCK:			_debug("blocked");			break;		case 0:			_debug("acquired");			if (type == AFS_LOCK_READ)				set_bit(AFS_VNODE_READLOCKED, &vnode->flags);			else				set_bit(AFS_VNODE_WRITELOCKED, &vnode->flags);			ret = AFS_LOCK_GRANTED;		default:			spin_lock(&vnode->lock);			/* the pending lock may have been withdrawn due to a			 * signal */			if (list_entry(vnode->pending_locks.next,				       struct file_lock, fl_u.afs.link) == fl) {				fl->fl_u.afs.state = ret;				if (ret == AFS_LOCK_GRANTED)					afs_grant_locks(vnode, fl);				else					list_del_init(&fl->fl_u.afs.link);				wake_up(&fl->fl_wait);				spin_unlock(&vnode->lock);			} else {				_debug("withdrawn");				clear_bit(AFS_VNODE_READLOCKED, &vnode->flags);				clear_bit(AFS_VNODE_WRITELOCKED, &vnode->flags);				spin_unlock(&vnode->lock);				afs_vnode_release_lock(vnode, key);				if (!list_empty(&vnode->pending_locks))					afs_lock_may_be_available(vnode);			}			break;		}		key_put(key);		_leave(" [pend]");		return;	}	/* looks like the lock request was withdrawn on a signal */	spin_unlock(&vnode->lock);	_leave(" [no locks]");}/* * pass responsibility for the unlocking of a vnode on the server to the * manager thread, lest a pending signal in the calling thread interrupt * AF_RXRPC * - the caller must hold the vnode lock */static void afs_defer_unlock(struct afs_vnode *vnode, struct key *key){	cancel_delayed_work(&vnode->lock_work);	if (!test_and_clear_bit(AFS_VNODE_READLOCKED, &vnode->flags) &&	    !test_and_clear_bit(AFS_VNODE_WRITELOCKED, &vnode->flags))		BUG();	if (test_and_set_bit(AFS_VNODE_UNLOCKING, &vnode->flags))		BUG();	vnode->unlock_key = key_get(key);	afs_lock_may_be_available(vnode);}/* * request a lock on a file on the server */static int afs_do_setlk(struct file *file, struct file_lock *fl){	struct afs_vnode *vnode = AFS_FS_I(file->f_mapping->host);	afs_lock_type_t type;	struct key *key = file->private_data;	int ret;	_enter("{%x:%u},%u", vnode->fid.vid, vnode->fid.vnode, fl->fl_type);	/* only whole-file locks are supported */	if (fl->fl_start != 0 || fl->fl_end != OFFSET_MAX)		return -EINVAL;	ret = afs_init_lock_manager();	if (ret < 0)		return ret;	fl->fl_ops = &afs_lock_ops;	INIT_LIST_HEAD(&fl->fl_u.afs.link);	fl->fl_u.afs.state = AFS_LOCK_PENDING;	type = (fl->fl_type == F_RDLCK) ? AFS_LOCK_READ : AFS_LOCK_WRITE;	lock_kernel();	/* make sure we've got a callback on this file and that our view of the	 * data version is up to date */	ret = afs_vnode_fetch_status(vnode, NULL, key);	if (ret < 0)		goto error;	if (vnode->status.lock_count != 0 && !(fl->fl_flags & FL_SLEEP)) {		ret = -EAGAIN;		goto error;	}	spin_lock(&vnode->lock);	/* if we've already got a readlock on the server then we can instantly	 * grant another readlock, irrespective of whether there are any	 * pending writelocks */	if (type == AFS_LOCK_READ &&	    vnode->flags & (1 << AFS_VNODE_READLOCKED)) {

⌨️ 快捷键说明

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