diff options
Diffstat (limited to 'fs/dlm')
-rw-r--r-- | fs/dlm/device.c | 166 |
1 files changed, 156 insertions, 10 deletions
diff --git a/fs/dlm/device.c b/fs/dlm/device.c index 49a20d5..47798fe 100644 --- a/fs/dlm/device.c +++ b/fs/dlm/device.c @@ -2,7 +2,7 @@ ******************************************************************************* ** ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. -** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. +** Copyright (C) 2004-2006 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 @@ -59,6 +59,9 @@ static rwlock_t lockinfo_lock; #define LS_FLAG_DELETED 1 #define LS_FLAG_AUTOFREE 2 +/* flags in ls_flags*/ +#define FI_FLAG_OPEN 1 +#define FI_FLAG_COMPAT 2 #define LOCKINFO_MAGIC 0x53595324 @@ -117,9 +120,110 @@ struct file_info { wait_queue_head_t fi_wait; struct user_ls *fi_ls; atomic_t fi_refcnt; /* Number of users */ - unsigned long fi_flags; /* Bit 1 means the device is open */ + unsigned long fi_flags; +}; + +#ifdef CONFIG_COMPAT + +struct dlm_lock_params32 { + __u8 mode; + __u8 namelen; + __u16 flags; + __u32 lkid; + __u32 parent; + + __u32 castparam; + __u32 castaddr; + __u32 bastparam; + __u32 bastaddr; + __u32 lksb; + + char lvb[DLM_USER_LVB_LEN]; + char name[0]; }; +struct dlm_write_request32 { + __u32 version[3]; + __u8 cmd; + __u8 is64bit; + __u8 unused[2]; + + union { + struct dlm_lock_params32 lock; + struct dlm_lspace_params lspace; + } i; +}; + +struct dlm_lksb32 { + __u32 sb_status; + __u32 sb_lkid; + __u8 sb_flags; + __u32 sb_lvbptr; +}; + +struct dlm_lock_result32 { + __u32 length; + __u32 user_astaddr; + __u32 user_astparam; + __u32 user_lksb; + struct dlm_lksb32 lksb; + __u8 bast_mode; + __u8 unused[3]; + /* Offsets may be zero if no data is present */ + __u32 lvb_offset; +}; + + +static void compat_input(struct dlm_write_request *kparams, struct dlm_write_request32 *k32params) +{ + + kparams->version[0] = k32params->version[0]; + kparams->version[1] = k32params->version[1]; + kparams->version[2] = k32params->version[2]; + + kparams->cmd = k32params->cmd; + kparams->is64bit = k32params->is64bit; + if (kparams->cmd == DLM_USER_CREATE_LOCKSPACE || + kparams->cmd == DLM_USER_REMOVE_LOCKSPACE) { + + kparams->i.lspace.flags = k32params->i.lspace.flags; + kparams->i.lspace.minor = k32params->i.lspace.minor; + strcpy(kparams->i.lspace.name, k32params->i.lspace.name); + } + else { + kparams->i.lock.mode = k32params->i.lock.mode; + kparams->i.lock.namelen = k32params->i.lock.namelen; + kparams->i.lock.flags = k32params->i.lock.flags; + kparams->i.lock.lkid = k32params->i.lock.lkid; + kparams->i.lock.parent = k32params->i.lock.parent; + kparams->i.lock.castparam = (void *)(long)k32params->i.lock.castparam; + kparams->i.lock.castaddr = (void *)(long)k32params->i.lock.castaddr; + kparams->i.lock.bastparam = (void *)(long)k32params->i.lock.bastparam; + kparams->i.lock.bastaddr = (void *)(long)k32params->i.lock.bastaddr; + kparams->i.lock.lksb = (void *)(long)k32params->i.lock.lksb; + memcpy(kparams->i.lock.lvb, k32params->i.lock.lvb, DLM_USER_LVB_LEN); + memcpy(kparams->i.lock.name, k32params->i.lock.name, kparams->i.lock.namelen); + } +} + +void compat_output(struct dlm_lock_result *res, struct dlm_lock_result32 *res32) +{ + res32->length = res->length - (sizeof(struct dlm_lock_result) - sizeof(struct dlm_lock_result32)); + res32->user_astaddr = (__u32)(long)res->user_astaddr; + res32->user_astparam = (__u32)(long)res->user_astparam; + res32->user_lksb = (__u32)(long)res->user_lksb; + res32->bast_mode = res->bast_mode; + + res32->lvb_offset = res->lvb_offset; + res32->length = res->length; + + res32->lksb.sb_status = res->lksb.sb_status; + res32->lksb.sb_flags = res->lksb.sb_flags; + res32->lksb.sb_lkid = res->lksb.sb_lkid; + res32->lksb.sb_lvbptr = (__u32)(long)res->lksb.sb_lvbptr; +} +#endif + /* get and put ops for file_info. Actually I don't really like "get" and "put", but everyone @@ -364,7 +468,7 @@ static void ast_routine(void *param) li->li_grmode = li->li_rqmode; /* Only queue AST if the device is still open */ - if (test_bit(1, &li->li_file->fi_flags)) + if (test_bit(FI_FLAG_OPEN, &li->li_file->fi_flags)) add_to_astqueue(li, li->li_castaddr, li->li_castparam, lvb_updated); @@ -449,7 +553,7 @@ static int dlm_open(struct inode *inode, struct file *file) f->fi_ls = lsinfo; f->fi_flags = 0; get_file_info(f); - set_bit(1, &f->fi_flags); + set_bit(FI_FLAG_OPEN, &f->fi_flags); file->private_data = f; @@ -494,7 +598,7 @@ static int dlm_close(struct inode *inode, struct file *file) return -ENOENT; /* Mark this closed so that ASTs will not be delivered any more */ - clear_bit(1, &f->fi_flags); + clear_bit(FI_FLAG_OPEN, &f->fi_flags); /* Block signals while we are doing this */ sigfillset(&allsigs); @@ -643,11 +747,18 @@ static ssize_t dlm_read(struct file *file, char __user *buffer, size_t count, { struct file_info *fi = file->private_data; struct ast_info *ast; + void *data; int data_size; + int struct_size; int offset; DECLARE_WAITQUEUE(wait, current); +#ifdef CONFIG_COMPAT + struct dlm_lock_result32 result32; + if (count < sizeof(struct dlm_lock_result32)) +#else if (count < sizeof(struct dlm_lock_result)) +#endif return -EINVAL; spin_lock(&fi->fi_ast_lock); @@ -691,11 +802,21 @@ static ssize_t dlm_read(struct file *file, char __user *buffer, size_t count, spin_unlock(&fi->fi_ast_lock); /* Work out the size of the returned data */ - data_size = sizeof(struct dlm_lock_result); +#ifdef CONFIG_COMPAT + if (test_bit(FI_FLAG_COMPAT, &fi->fi_flags)) { + data_size = struct_size = sizeof(struct dlm_lock_result32); + data = &result32; + } + else +#endif + { + data_size = struct_size = sizeof(struct dlm_lock_result); + data = &ast->result; + } if (ast->lvb_updated && ast->result.lksb.sb_lvbptr) data_size += DLM_USER_LVB_LEN; - offset = sizeof(struct dlm_lock_result); + offset = struct_size; /* Room for the extended data ? */ if (count >= data_size) { @@ -711,8 +832,13 @@ static ssize_t dlm_read(struct file *file, char __user *buffer, size_t count, } ast->result.length = data_size; + +#ifdef CONFIG_COMPAT + compat_output(&ast->result, &result32); +#endif + /* Copy the header now it has all the offsets in it */ - if (copy_to_user(buffer, &ast->result, sizeof(struct dlm_lock_result))) + if (copy_to_user(buffer, data, struct_size)) offset = -EFAULT; /* If we only returned a header and there's more to come then put it @@ -970,8 +1096,14 @@ static ssize_t dlm_write(struct file *file, const char __user *buffer, sigset_t allsigs; int status; - /* -1 because lock name is optional */ - if (count < sizeof(struct dlm_write_request)-1) +#ifdef CONFIG_COMPAT + if (count < sizeof(struct dlm_write_request32)) +#else + if (count < sizeof(struct dlm_write_request)) +#endif + return -EINVAL; + + if (count > sizeof(struct dlm_write_request) + DLM_RESNAME_MAXLEN) return -EINVAL; /* Has the lockspace been deleted */ @@ -991,6 +1123,20 @@ static ssize_t dlm_write(struct file *file, const char __user *buffer, if (check_version(kparams)) goto out_free; +#ifdef CONFIG_COMPAT + if (!kparams->is64bit) { + struct dlm_write_request32 *k32params = (struct dlm_write_request32 *)kparams; + kparams = kmalloc(count + (sizeof(struct dlm_write_request) - sizeof(struct dlm_write_request32)), GFP_KERNEL); + if (!kparams) + return -ENOMEM; + + if (fi) + set_bit(FI_FLAG_COMPAT, &fi->fi_flags); + compat_input(kparams, k32params); + kfree(k32params); + } +#endif + /* Block signals while we are doing this */ sigfillset(&allsigs); sigprocmask(SIG_BLOCK, &allsigs, &tmpsig); |