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 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); |