diff options
Diffstat (limited to 'fs')
| -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 49a20d549216..47798fe46d72 100644 --- a/fs/dlm/device.c +++ b/fs/dlm/device.c | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | ******************************************************************************* | 2 | ******************************************************************************* |
| 3 | ** | 3 | ** |
| 4 | ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. | 4 | ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. |
| 5 | ** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. | 5 | ** Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. |
| 6 | ** | 6 | ** |
| 7 | ** This copyrighted material is made available to anyone wishing to use, | 7 | ** This copyrighted material is made available to anyone wishing to use, |
| 8 | ** modify, copy, or redistribute it subject to the terms and conditions | 8 | ** modify, copy, or redistribute it subject to the terms and conditions |
| @@ -59,6 +59,9 @@ static rwlock_t lockinfo_lock; | |||
| 59 | #define LS_FLAG_DELETED 1 | 59 | #define LS_FLAG_DELETED 1 |
| 60 | #define LS_FLAG_AUTOFREE 2 | 60 | #define LS_FLAG_AUTOFREE 2 |
| 61 | 61 | ||
| 62 | /* flags in ls_flags*/ | ||
| 63 | #define FI_FLAG_OPEN 1 | ||
| 64 | #define FI_FLAG_COMPAT 2 | ||
| 62 | 65 | ||
| 63 | #define LOCKINFO_MAGIC 0x53595324 | 66 | #define LOCKINFO_MAGIC 0x53595324 |
| 64 | 67 | ||
| @@ -117,9 +120,110 @@ struct file_info { | |||
| 117 | wait_queue_head_t fi_wait; | 120 | wait_queue_head_t fi_wait; |
| 118 | struct user_ls *fi_ls; | 121 | struct user_ls *fi_ls; |
| 119 | atomic_t fi_refcnt; /* Number of users */ | 122 | atomic_t fi_refcnt; /* Number of users */ |
| 120 | unsigned long fi_flags; /* Bit 1 means the device is open */ | 123 | unsigned long fi_flags; |
| 124 | }; | ||
| 125 | |||
| 126 | #ifdef CONFIG_COMPAT | ||
| 127 | |||
| 128 | struct dlm_lock_params32 { | ||
| 129 | __u8 mode; | ||
| 130 | __u8 namelen; | ||
| 131 | __u16 flags; | ||
| 132 | __u32 lkid; | ||
| 133 | __u32 parent; | ||
| 134 | |||
| 135 | __u32 castparam; | ||
| 136 | __u32 castaddr; | ||
| 137 | __u32 bastparam; | ||
| 138 | __u32 bastaddr; | ||
| 139 | __u32 lksb; | ||
| 140 | |||
| 141 | char lvb[DLM_USER_LVB_LEN]; | ||
| 142 | char name[0]; | ||
| 121 | }; | 143 | }; |
| 122 | 144 | ||
| 145 | struct dlm_write_request32 { | ||
| 146 | __u32 version[3]; | ||
| 147 | __u8 cmd; | ||
| 148 | __u8 is64bit; | ||
| 149 | __u8 unused[2]; | ||
| 150 | |||
| 151 | union { | ||
| 152 | struct dlm_lock_params32 lock; | ||
| 153 | struct dlm_lspace_params lspace; | ||
| 154 | } i; | ||
| 155 | }; | ||
| 156 | |||
| 157 | struct dlm_lksb32 { | ||
| 158 | __u32 sb_status; | ||
| 159 | __u32 sb_lkid; | ||
| 160 | __u8 sb_flags; | ||
| 161 | __u32 sb_lvbptr; | ||
| 162 | }; | ||
| 163 | |||
| 164 | struct dlm_lock_result32 { | ||
| 165 | __u32 length; | ||
| 166 | __u32 user_astaddr; | ||
| 167 | __u32 user_astparam; | ||
| 168 | __u32 user_lksb; | ||
| 169 | struct dlm_lksb32 lksb; | ||
| 170 | __u8 bast_mode; | ||
| 171 | __u8 unused[3]; | ||
| 172 | /* Offsets may be zero if no data is present */ | ||
| 173 | __u32 lvb_offset; | ||
| 174 | }; | ||
| 175 | |||
| 176 | |||
| 177 | static void compat_input(struct dlm_write_request *kparams, struct dlm_write_request32 *k32params) | ||
| 178 | { | ||
| 179 | |||
| 180 | kparams->version[0] = k32params->version[0]; | ||
| 181 | kparams->version[1] = k32params->version[1]; | ||
| 182 | kparams->version[2] = k32params->version[2]; | ||
| 183 | |||
| 184 | kparams->cmd = k32params->cmd; | ||
| 185 | kparams->is64bit = k32params->is64bit; | ||
| 186 | if (kparams->cmd == DLM_USER_CREATE_LOCKSPACE || | ||
| 187 | kparams->cmd == DLM_USER_REMOVE_LOCKSPACE) { | ||
| 188 | |||
| 189 | kparams->i.lspace.flags = k32params->i.lspace.flags; | ||
| 190 | kparams->i.lspace.minor = k32params->i.lspace.minor; | ||
| 191 | strcpy(kparams->i.lspace.name, k32params->i.lspace.name); | ||
| 192 | } | ||
| 193 | else { | ||
| 194 | kparams->i.lock.mode = k32params->i.lock.mode; | ||
| 195 | kparams->i.lock.namelen = k32params->i.lock.namelen; | ||
| 196 | kparams->i.lock.flags = k32params->i.lock.flags; | ||
| 197 | kparams->i.lock.lkid = k32params->i.lock.lkid; | ||
| 198 | kparams->i.lock.parent = k32params->i.lock.parent; | ||
| 199 | kparams->i.lock.castparam = (void *)(long)k32params->i.lock.castparam; | ||
| 200 | kparams->i.lock.castaddr = (void *)(long)k32params->i.lock.castaddr; | ||
| 201 | kparams->i.lock.bastparam = (void *)(long)k32params->i.lock.bastparam; | ||
| 202 | kparams->i.lock.bastaddr = (void *)(long)k32params->i.lock.bastaddr; | ||
| 203 | kparams->i.lock.lksb = (void *)(long)k32params->i.lock.lksb; | ||
| 204 | memcpy(kparams->i.lock.lvb, k32params->i.lock.lvb, DLM_USER_LVB_LEN); | ||
| 205 | memcpy(kparams->i.lock.name, k32params->i.lock.name, kparams->i.lock.namelen); | ||
| 206 | } | ||
| 207 | } | ||
| 208 | |||
| 209 | void compat_output(struct dlm_lock_result *res, struct dlm_lock_result32 *res32) | ||
| 210 | { | ||
| 211 | res32->length = res->length - (sizeof(struct dlm_lock_result) - sizeof(struct dlm_lock_result32)); | ||
| 212 | res32->user_astaddr = (__u32)(long)res->user_astaddr; | ||
| 213 | res32->user_astparam = (__u32)(long)res->user_astparam; | ||
| 214 | res32->user_lksb = (__u32)(long)res->user_lksb; | ||
| 215 | res32->bast_mode = res->bast_mode; | ||
| 216 | |||
| 217 | res32->lvb_offset = res->lvb_offset; | ||
| 218 | res32->length = res->length; | ||
| 219 | |||
| 220 | res32->lksb.sb_status = res->lksb.sb_status; | ||
| 221 | res32->lksb.sb_flags = res->lksb.sb_flags; | ||
| 222 | res32->lksb.sb_lkid = res->lksb.sb_lkid; | ||
| 223 | res32->lksb.sb_lvbptr = (__u32)(long)res->lksb.sb_lvbptr; | ||
| 224 | } | ||
| 225 | #endif | ||
| 226 | |||
| 123 | 227 | ||
| 124 | /* get and put ops for file_info. | 228 | /* get and put ops for file_info. |
| 125 | Actually I don't really like "get" and "put", but everyone | 229 | Actually I don't really like "get" and "put", but everyone |
| @@ -364,7 +468,7 @@ static void ast_routine(void *param) | |||
| 364 | li->li_grmode = li->li_rqmode; | 468 | li->li_grmode = li->li_rqmode; |
| 365 | 469 | ||
| 366 | /* Only queue AST if the device is still open */ | 470 | /* Only queue AST if the device is still open */ |
| 367 | if (test_bit(1, &li->li_file->fi_flags)) | 471 | if (test_bit(FI_FLAG_OPEN, &li->li_file->fi_flags)) |
| 368 | add_to_astqueue(li, li->li_castaddr, li->li_castparam, | 472 | add_to_astqueue(li, li->li_castaddr, li->li_castparam, |
| 369 | lvb_updated); | 473 | lvb_updated); |
| 370 | 474 | ||
| @@ -449,7 +553,7 @@ static int dlm_open(struct inode *inode, struct file *file) | |||
| 449 | f->fi_ls = lsinfo; | 553 | f->fi_ls = lsinfo; |
| 450 | f->fi_flags = 0; | 554 | f->fi_flags = 0; |
| 451 | get_file_info(f); | 555 | get_file_info(f); |
| 452 | set_bit(1, &f->fi_flags); | 556 | set_bit(FI_FLAG_OPEN, &f->fi_flags); |
| 453 | 557 | ||
| 454 | file->private_data = f; | 558 | file->private_data = f; |
| 455 | 559 | ||
| @@ -494,7 +598,7 @@ static int dlm_close(struct inode *inode, struct file *file) | |||
| 494 | return -ENOENT; | 598 | return -ENOENT; |
| 495 | 599 | ||
| 496 | /* Mark this closed so that ASTs will not be delivered any more */ | 600 | /* Mark this closed so that ASTs will not be delivered any more */ |
| 497 | clear_bit(1, &f->fi_flags); | 601 | clear_bit(FI_FLAG_OPEN, &f->fi_flags); |
| 498 | 602 | ||
| 499 | /* Block signals while we are doing this */ | 603 | /* Block signals while we are doing this */ |
| 500 | sigfillset(&allsigs); | 604 | sigfillset(&allsigs); |
| @@ -643,11 +747,18 @@ static ssize_t dlm_read(struct file *file, char __user *buffer, size_t count, | |||
| 643 | { | 747 | { |
| 644 | struct file_info *fi = file->private_data; | 748 | struct file_info *fi = file->private_data; |
| 645 | struct ast_info *ast; | 749 | struct ast_info *ast; |
| 750 | void *data; | ||
| 646 | int data_size; | 751 | int data_size; |
| 752 | int struct_size; | ||
| 647 | int offset; | 753 | int offset; |
| 648 | DECLARE_WAITQUEUE(wait, current); | 754 | DECLARE_WAITQUEUE(wait, current); |
| 755 | #ifdef CONFIG_COMPAT | ||
| 756 | struct dlm_lock_result32 result32; | ||
| 649 | 757 | ||
| 758 | if (count < sizeof(struct dlm_lock_result32)) | ||
| 759 | #else | ||
| 650 | if (count < sizeof(struct dlm_lock_result)) | 760 | if (count < sizeof(struct dlm_lock_result)) |
| 761 | #endif | ||
| 651 | return -EINVAL; | 762 | return -EINVAL; |
| 652 | 763 | ||
| 653 | spin_lock(&fi->fi_ast_lock); | 764 | spin_lock(&fi->fi_ast_lock); |
| @@ -691,11 +802,21 @@ static ssize_t dlm_read(struct file *file, char __user *buffer, size_t count, | |||
| 691 | spin_unlock(&fi->fi_ast_lock); | 802 | spin_unlock(&fi->fi_ast_lock); |
| 692 | 803 | ||
| 693 | /* Work out the size of the returned data */ | 804 | /* Work out the size of the returned data */ |
| 694 | data_size = sizeof(struct dlm_lock_result); | 805 | #ifdef CONFIG_COMPAT |
| 806 | if (test_bit(FI_FLAG_COMPAT, &fi->fi_flags)) { | ||
| 807 | data_size = struct_size = sizeof(struct dlm_lock_result32); | ||
| 808 | data = &result32; | ||
| 809 | } | ||
| 810 | else | ||
| 811 | #endif | ||
| 812 | { | ||
| 813 | data_size = struct_size = sizeof(struct dlm_lock_result); | ||
| 814 | data = &ast->result; | ||
| 815 | } | ||
| 695 | if (ast->lvb_updated && ast->result.lksb.sb_lvbptr) | 816 | if (ast->lvb_updated && ast->result.lksb.sb_lvbptr) |
| 696 | data_size += DLM_USER_LVB_LEN; | 817 | data_size += DLM_USER_LVB_LEN; |
| 697 | 818 | ||
| 698 | offset = sizeof(struct dlm_lock_result); | 819 | offset = struct_size; |
| 699 | 820 | ||
| 700 | /* Room for the extended data ? */ | 821 | /* Room for the extended data ? */ |
| 701 | if (count >= data_size) { | 822 | if (count >= data_size) { |
| @@ -711,8 +832,13 @@ static ssize_t dlm_read(struct file *file, char __user *buffer, size_t count, | |||
| 711 | } | 832 | } |
| 712 | 833 | ||
| 713 | ast->result.length = data_size; | 834 | ast->result.length = data_size; |
| 835 | |||
| 836 | #ifdef CONFIG_COMPAT | ||
| 837 | compat_output(&ast->result, &result32); | ||
| 838 | #endif | ||
| 839 | |||
| 714 | /* Copy the header now it has all the offsets in it */ | 840 | /* Copy the header now it has all the offsets in it */ |
| 715 | if (copy_to_user(buffer, &ast->result, sizeof(struct dlm_lock_result))) | 841 | if (copy_to_user(buffer, data, struct_size)) |
| 716 | offset = -EFAULT; | 842 | offset = -EFAULT; |
| 717 | 843 | ||
| 718 | /* If we only returned a header and there's more to come then put it | 844 | /* 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, | |||
| 970 | sigset_t allsigs; | 1096 | sigset_t allsigs; |
| 971 | int status; | 1097 | int status; |
| 972 | 1098 | ||
| 973 | /* -1 because lock name is optional */ | 1099 | #ifdef CONFIG_COMPAT |
| 974 | if (count < sizeof(struct dlm_write_request)-1) | 1100 | if (count < sizeof(struct dlm_write_request32)) |
| 1101 | #else | ||
| 1102 | if (count < sizeof(struct dlm_write_request)) | ||
| 1103 | #endif | ||
| 1104 | return -EINVAL; | ||
| 1105 | |||
| 1106 | if (count > sizeof(struct dlm_write_request) + DLM_RESNAME_MAXLEN) | ||
| 975 | return -EINVAL; | 1107 | return -EINVAL; |
| 976 | 1108 | ||
| 977 | /* Has the lockspace been deleted */ | 1109 | /* Has the lockspace been deleted */ |
| @@ -991,6 +1123,20 @@ static ssize_t dlm_write(struct file *file, const char __user *buffer, | |||
| 991 | if (check_version(kparams)) | 1123 | if (check_version(kparams)) |
| 992 | goto out_free; | 1124 | goto out_free; |
| 993 | 1125 | ||
| 1126 | #ifdef CONFIG_COMPAT | ||
| 1127 | if (!kparams->is64bit) { | ||
| 1128 | struct dlm_write_request32 *k32params = (struct dlm_write_request32 *)kparams; | ||
| 1129 | kparams = kmalloc(count + (sizeof(struct dlm_write_request) - sizeof(struct dlm_write_request32)), GFP_KERNEL); | ||
| 1130 | if (!kparams) | ||
| 1131 | return -ENOMEM; | ||
| 1132 | |||
| 1133 | if (fi) | ||
| 1134 | set_bit(FI_FLAG_COMPAT, &fi->fi_flags); | ||
| 1135 | compat_input(kparams, k32params); | ||
| 1136 | kfree(k32params); | ||
| 1137 | } | ||
| 1138 | #endif | ||
| 1139 | |||
| 994 | /* Block signals while we are doing this */ | 1140 | /* Block signals while we are doing this */ |
| 995 | sigfillset(&allsigs); | 1141 | sigfillset(&allsigs); |
| 996 | sigprocmask(SIG_BLOCK, &allsigs, &tmpsig); | 1142 | sigprocmask(SIG_BLOCK, &allsigs, &tmpsig); |
