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

📄 plock.c

📁 linux内核源码
💻 C
字号:
/* * Copyright (C) 2005 Red Hat, Inc.  All rights reserved. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU General Public License version 2. */#include <linux/miscdevice.h>#include <linux/lock_dlm_plock.h>#include <linux/poll.h>#include "lock_dlm.h"static spinlock_t ops_lock;static struct list_head send_list;static struct list_head recv_list;static wait_queue_head_t send_wq;static wait_queue_head_t recv_wq;struct plock_op {	struct list_head list;	int done;	struct gdlm_plock_info info;};struct plock_xop {	struct plock_op xop;	void *callback;	void *fl;	void *file;	struct file_lock flc;};static inline void set_version(struct gdlm_plock_info *info){	info->version[0] = GDLM_PLOCK_VERSION_MAJOR;	info->version[1] = GDLM_PLOCK_VERSION_MINOR;	info->version[2] = GDLM_PLOCK_VERSION_PATCH;}static int check_version(struct gdlm_plock_info *info){	if ((GDLM_PLOCK_VERSION_MAJOR != info->version[0]) ||	    (GDLM_PLOCK_VERSION_MINOR < info->version[1])) {		log_error("plock device version mismatch: "			  "kernel (%u.%u.%u), user (%u.%u.%u)",			  GDLM_PLOCK_VERSION_MAJOR,			  GDLM_PLOCK_VERSION_MINOR,			  GDLM_PLOCK_VERSION_PATCH,			  info->version[0],			  info->version[1],			  info->version[2]);		return -EINVAL;	}	return 0;}static void send_op(struct plock_op *op){	set_version(&op->info);	INIT_LIST_HEAD(&op->list);	spin_lock(&ops_lock);	list_add_tail(&op->list, &send_list);	spin_unlock(&ops_lock);	wake_up(&send_wq);}int gdlm_plock(void *lockspace, struct lm_lockname *name,	       struct file *file, int cmd, struct file_lock *fl){	struct gdlm_ls *ls = lockspace;	struct plock_op *op;	struct plock_xop *xop;	int rv;	xop = kzalloc(sizeof(*xop), GFP_KERNEL);	if (!xop)		return -ENOMEM;	op = &xop->xop;	op->info.optype		= GDLM_PLOCK_OP_LOCK;	op->info.pid		= fl->fl_pid;	op->info.ex		= (fl->fl_type == F_WRLCK);	op->info.wait		= IS_SETLKW(cmd);	op->info.fsid		= ls->id;	op->info.number		= name->ln_number;	op->info.start		= fl->fl_start;	op->info.end		= fl->fl_end;	op->info.owner		= (__u64)(long) fl->fl_owner;	if (fl->fl_lmops && fl->fl_lmops->fl_grant) {		xop->callback	= fl->fl_lmops->fl_grant;		locks_init_lock(&xop->flc);		locks_copy_lock(&xop->flc, fl);		xop->fl		= fl;		xop->file	= file;	} else		xop->callback	= NULL;	send_op(op);	if (xop->callback == NULL)		wait_event(recv_wq, (op->done != 0));	else		return -EINPROGRESS;	spin_lock(&ops_lock);	if (!list_empty(&op->list)) {		printk(KERN_INFO "plock op on list\n");		list_del(&op->list);	}	spin_unlock(&ops_lock);	rv = op->info.rv;	if (!rv) {		if (posix_lock_file_wait(file, fl) < 0)			log_error("gdlm_plock: vfs lock error %x,%llx",				  name->ln_type,				  (unsigned long long)name->ln_number);	}	kfree(xop);	return rv;}/* Returns failure iff a succesful lock operation should be canceled */static int gdlm_plock_callback(struct plock_op *op){	struct file *file;	struct file_lock *fl;	struct file_lock *flc;	int (*notify)(void *, void *, int) = NULL;	struct plock_xop *xop = (struct plock_xop *)op;	int rv = 0;	spin_lock(&ops_lock);	if (!list_empty(&op->list)) {		printk(KERN_INFO "plock op on list\n");		list_del(&op->list);	}	spin_unlock(&ops_lock);	/* check if the following 2 are still valid or make a copy */	file = xop->file;	flc = &xop->flc;	fl = xop->fl;	notify = xop->callback;	if (op->info.rv) {		notify(flc, NULL, op->info.rv);		goto out;	}	/* got fs lock; bookkeep locally as well: */	flc->fl_flags &= ~FL_SLEEP;	if (posix_lock_file(file, flc, NULL)) {		/*		 * This can only happen in the case of kmalloc() failure.		 * The filesystem's own lock is the authoritative lock,		 * so a failure to get the lock locally is not a disaster.		 * As long as GFS cannot reliably cancel locks (especially		 * in a low-memory situation), we're better off ignoring		 * this failure than trying to recover.		 */		log_error("gdlm_plock: vfs lock error file %p fl %p",				file, fl);	}	rv = notify(flc, NULL, 0);	if (rv) {		/* XXX: We need to cancel the fs lock here: */		printk("gfs2 lock granted after lock request failed;"						" dangling lock!\n");		goto out;	}out:	kfree(xop);	return rv;}int gdlm_punlock(void *lockspace, struct lm_lockname *name,		 struct file *file, struct file_lock *fl){	struct gdlm_ls *ls = lockspace;	struct plock_op *op;	int rv;	op = kzalloc(sizeof(*op), GFP_KERNEL);	if (!op)		return -ENOMEM;	if (posix_lock_file_wait(file, fl) < 0)		log_error("gdlm_punlock: vfs unlock error %x,%llx",			  name->ln_type, (unsigned long long)name->ln_number);	op->info.optype		= GDLM_PLOCK_OP_UNLOCK;	op->info.pid		= fl->fl_pid;	op->info.fsid		= ls->id;	op->info.number		= name->ln_number;	op->info.start		= fl->fl_start;	op->info.end		= fl->fl_end;	op->info.owner		= (__u64)(long) fl->fl_owner;	send_op(op);	wait_event(recv_wq, (op->done != 0));	spin_lock(&ops_lock);	if (!list_empty(&op->list)) {		printk(KERN_INFO "punlock op on list\n");		list_del(&op->list);	}	spin_unlock(&ops_lock);	rv = op->info.rv;	if (rv == -ENOENT)		rv = 0;	kfree(op);	return rv;}int gdlm_plock_get(void *lockspace, struct lm_lockname *name,		   struct file *file, struct file_lock *fl){	struct gdlm_ls *ls = lockspace;	struct plock_op *op;	int rv;	op = kzalloc(sizeof(*op), GFP_KERNEL);	if (!op)		return -ENOMEM;	op->info.optype		= GDLM_PLOCK_OP_GET;	op->info.pid		= fl->fl_pid;	op->info.ex		= (fl->fl_type == F_WRLCK);	op->info.fsid		= ls->id;	op->info.number		= name->ln_number;	op->info.start		= fl->fl_start;	op->info.end		= fl->fl_end;	op->info.owner		= (__u64)(long) fl->fl_owner;	send_op(op);	wait_event(recv_wq, (op->done != 0));	spin_lock(&ops_lock);	if (!list_empty(&op->list)) {		printk(KERN_INFO "plock_get op on list\n");		list_del(&op->list);	}	spin_unlock(&ops_lock);	/* info.rv from userspace is 1 for conflict, 0 for no-conflict,	   -ENOENT if there are no locks on the file */	rv = op->info.rv;	fl->fl_type = F_UNLCK;	if (rv == -ENOENT)		rv = 0;	else if (rv > 0) {		fl->fl_type = (op->info.ex) ? F_WRLCK : F_RDLCK;		fl->fl_pid = op->info.pid;		fl->fl_start = op->info.start;		fl->fl_end = op->info.end;		rv = 0;	}	kfree(op);	return rv;}/* a read copies out one plock request from the send list */static ssize_t dev_read(struct file *file, char __user *u, size_t count,			loff_t *ppos){	struct gdlm_plock_info info;	struct plock_op *op = NULL;	if (count < sizeof(info))		return -EINVAL;	spin_lock(&ops_lock);	if (!list_empty(&send_list)) {		op = list_entry(send_list.next, struct plock_op, list);		list_move(&op->list, &recv_list);		memcpy(&info, &op->info, sizeof(info));	}	spin_unlock(&ops_lock);	if (!op)		return -EAGAIN;	if (copy_to_user(u, &info, sizeof(info)))		return -EFAULT;	return sizeof(info);}/* a write copies in one plock result that should match a plock_op   on the recv list */static ssize_t dev_write(struct file *file, const char __user *u, size_t count,			 loff_t *ppos){	struct gdlm_plock_info info;	struct plock_op *op;	int found = 0;	if (count != sizeof(info))		return -EINVAL;	if (copy_from_user(&info, u, sizeof(info)))		return -EFAULT;	if (check_version(&info))		return -EINVAL;	spin_lock(&ops_lock);	list_for_each_entry(op, &recv_list, list) {		if (op->info.fsid == info.fsid && op->info.number == info.number &&		    op->info.owner == info.owner) {			list_del_init(&op->list);			found = 1;			op->done = 1;			memcpy(&op->info, &info, sizeof(info));			break;		}	}	spin_unlock(&ops_lock);	if (found) {		struct plock_xop *xop;		xop = (struct plock_xop *)op;		if (xop->callback)			count = gdlm_plock_callback(op);		else			wake_up(&recv_wq);	} else		printk(KERN_INFO "gdlm dev_write no op %x %llx\n", info.fsid,			(unsigned long long)info.number);	return count;}static unsigned int dev_poll(struct file *file, poll_table *wait){	unsigned int mask = 0;	poll_wait(file, &send_wq, wait);	spin_lock(&ops_lock);	if (!list_empty(&send_list))		mask = POLLIN | POLLRDNORM;	spin_unlock(&ops_lock);	return mask;}static const struct file_operations dev_fops = {	.read    = dev_read,	.write   = dev_write,	.poll    = dev_poll,	.owner   = THIS_MODULE};static struct miscdevice plock_dev_misc = {	.minor = MISC_DYNAMIC_MINOR,	.name = GDLM_PLOCK_MISC_NAME,	.fops = &dev_fops};int gdlm_plock_init(void){	int rv;	spin_lock_init(&ops_lock);	INIT_LIST_HEAD(&send_list);	INIT_LIST_HEAD(&recv_list);	init_waitqueue_head(&send_wq);	init_waitqueue_head(&recv_wq);	rv = misc_register(&plock_dev_misc);	if (rv)		printk(KERN_INFO "gdlm_plock_init: misc_register failed %d",		       rv);	return rv;}void gdlm_plock_exit(void){	if (misc_deregister(&plock_dev_misc) < 0)		printk(KERN_INFO "gdlm_plock_exit: misc_deregister failed");}

⌨️ 快捷键说明

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