mirror of
https://github.com/adulau/aha.git
synced 2024-12-31 21:26:18 +00:00
e9fc2aa091
As per comments from Jan Engelhardt <jengelh@linux01.gwdg.de> this updates the copyright message to say "version" in full rather than "v.2". Also incore.h has been updated to remove forward structure declarations which are not required. The gfs2_quota_lvb structure has now had endianess annotations added to it. Also quota.c has been updated so that we now store the lvb data locally in endian independant format to avoid needing a structure in host endianess too. As a result the endianess conversions are done as required at various points and thus the conversion routines in lvb.[ch] are no longer required. I've moved the one remaining constant in lvb.h thats used into lm.h and removed the unused lvb.[ch]. I have not changed the HIF_ constants. That is left to a later patch which I hope will unify the gh_flags and gh_iflags fields of the struct gfs2_holder. Cc: Jan Engelhardt <jengelh@linux01.gwdg.de> Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
302 lines
6.7 KiB
C
302 lines
6.7 KiB
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 "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;
|
|
};
|
|
|
|
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(lm_lockspace_t *lockspace, struct lm_lockname *name,
|
|
struct file *file, int cmd, struct file_lock *fl)
|
|
{
|
|
struct gdlm_ls *ls = (struct gdlm_ls *) lockspace;
|
|
struct plock_op *op;
|
|
int rv;
|
|
|
|
op = kzalloc(sizeof(*op), GFP_KERNEL);
|
|
if (!op)
|
|
return -ENOMEM;
|
|
|
|
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;
|
|
|
|
send_op(op);
|
|
wait_event(recv_wq, (op->done != 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);
|
|
|
|
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(op);
|
|
return rv;
|
|
}
|
|
|
|
int gdlm_punlock(lm_lockspace_t *lockspace, struct lm_lockname *name,
|
|
struct file *file, struct file_lock *fl)
|
|
{
|
|
struct gdlm_ls *ls = (struct gdlm_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;
|
|
|
|
kfree(op);
|
|
return rv;
|
|
}
|
|
|
|
int gdlm_plock_get(lm_lockspace_t *lockspace, struct lm_lockname *name,
|
|
struct file *file, struct file_lock *fl)
|
|
{
|
|
struct gdlm_ls *ls = (struct gdlm_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;
|
|
|
|
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);
|
|
|
|
rv = op->info.rv;
|
|
|
|
if (rv == 0)
|
|
fl->fl_type = F_UNLCK;
|
|
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;
|
|
}
|
|
|
|
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)
|
|
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)
|
|
{
|
|
poll_wait(file, &send_wq, wait);
|
|
|
|
spin_lock(&ops_lock);
|
|
if (!list_empty(&send_list)) {
|
|
spin_unlock(&ops_lock);
|
|
return POLLIN | POLLRDNORM;
|
|
}
|
|
spin_unlock(&ops_lock);
|
|
return 0;
|
|
}
|
|
|
|
static 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");
|
|
}
|
|
|