| @@ -1,977 +1,978 @@ | | | @@ -1,977 +1,978 @@ |
1 | /* $NetBSD: dm_ioctl.c,v 1.25 2011/05/24 15:23:41 joerg Exp $ */ | | 1 | /* $NetBSD: dm_ioctl.c,v 1.26 2011/08/27 17:07:49 ahoka Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2008 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2008 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Adam Hamsik. | | 8 | * by Adam Hamsik. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright | | 15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the | | 16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. | | 17 | * documentation and/or other materials provided with the distribution. |
18 | * | | 18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. | | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | /* | | 32 | /* |
33 | * Locking is used to synchronise between ioctl calls and between dm_table's | | 33 | * Locking is used to synchronise between ioctl calls and between dm_table's |
34 | * users. | | 34 | * users. |
35 | * | | 35 | * |
36 | * ioctl locking: | | 36 | * ioctl locking: |
37 | * Simple reference counting, to count users of device will be used routines | | 37 | * Simple reference counting, to count users of device will be used routines |
38 | * dm_dev_busy/dm_dev_unbusy are used for that. | | 38 | * dm_dev_busy/dm_dev_unbusy are used for that. |
39 | * dm_dev_lookup/dm_dev_rem call dm_dev_busy before return(caller is therefore | | 39 | * dm_dev_lookup/dm_dev_rem call dm_dev_busy before return(caller is therefore |
40 | * holder of reference_counter last). | | 40 | * holder of reference_counter last). |
41 | * | | 41 | * |
42 | * ioctl routines which change/remove dm_dev parameters must wait on | | 42 | * ioctl routines which change/remove dm_dev parameters must wait on |
43 | * dm_dev::dev_cv and when last user will call dm_dev_unbusy they will wake | | 43 | * dm_dev::dev_cv and when last user will call dm_dev_unbusy they will wake |
44 | * up them. | | 44 | * up them. |
45 | * | | 45 | * |
46 | * table_head locking: | | 46 | * table_head locking: |
47 | * To access table entries dm_table_* routines must be used. | | 47 | * To access table entries dm_table_* routines must be used. |
48 | * | | 48 | * |
49 | * dm_table_get_entry will increment table users reference | | 49 | * dm_table_get_entry will increment table users reference |
50 | * counter. It will return active or inactive table depends | | 50 | * counter. It will return active or inactive table depends |
51 | * on uint8_t argument. | | 51 | * on uint8_t argument. |
52 | * | | 52 | * |
53 | * dm_table_release must be called for every table_entry from | | 53 | * dm_table_release must be called for every table_entry from |
54 | * dm_table_get_entry. Between these to calls tables can'tbe switched | | 54 | * dm_table_get_entry. Between these to calls tables can'tbe switched |
55 | * or destroyed. | | 55 | * or destroyed. |
56 | * | | 56 | * |
57 | * dm_table_head_init initialize talbe_entries SLISTS and io_cv. | | 57 | * dm_table_head_init initialize talbe_entries SLISTS and io_cv. |
58 | * | | 58 | * |
59 | * dm_table_head_destroy destroy cv. | | 59 | * dm_table_head_destroy destroy cv. |
60 | * | | 60 | * |
61 | * There are two types of users for dm_table_head first type will | | 61 | * There are two types of users for dm_table_head first type will |
62 | * only read list and try to do anything with it e.g. dmstrategy, | | 62 | * only read list and try to do anything with it e.g. dmstrategy, |
63 | * dm_table_size etc. There is another user for table_head which wants | | 63 | * dm_table_size etc. There is another user for table_head which wants |
64 | * to change table lists e.g. dm_dev_resume_ioctl, dm_dev_remove_ioctl, | | 64 | * to change table lists e.g. dm_dev_resume_ioctl, dm_dev_remove_ioctl, |
65 | * dm_table_clear_ioctl. | | 65 | * dm_table_clear_ioctl. |
66 | * | | 66 | * |
67 | * NOTE: It is not allowed to call dm_table_destroy, dm_table_switch_tables | | 67 | * NOTE: It is not allowed to call dm_table_destroy, dm_table_switch_tables |
68 | * with hold table reference counter. Table reference counter is hold | | 68 | * with hold table reference counter. Table reference counter is hold |
69 | * after calling dm_table_get_entry routine. After calling this | | 69 | * after calling dm_table_get_entry routine. After calling this |
70 | * function user must call dm_table_release before any writer table | | 70 | * function user must call dm_table_release before any writer table |
71 | * operation. | | 71 | * operation. |
72 | * | | 72 | * |
73 | * Example: dm_table_get_entry | | 73 | * Example: dm_table_get_entry |
74 | * dm_table_destroy/dm_table_switch_tables | | 74 | * dm_table_destroy/dm_table_switch_tables |
75 | * This exaple will lead to deadlock situation because after dm_table_get_entry | | 75 | * This exaple will lead to deadlock situation because after dm_table_get_entry |
76 | * table reference counter is != 0 and dm_table_destroy have to wait on cv until | | 76 | * table reference counter is != 0 and dm_table_destroy have to wait on cv until |
77 | * reference counter is 0. | | 77 | * reference counter is 0. |
78 | * | | 78 | * |
79 | */ | | 79 | */ |
80 | | | 80 | |
81 | #include <sys/types.h> | | 81 | #include <sys/types.h> |
82 | #include <sys/param.h> | | 82 | #include <sys/param.h> |
83 | | | 83 | |
84 | #include <sys/device.h> | | 84 | #include <sys/device.h> |
85 | #include <sys/disk.h> | | 85 | #include <sys/disk.h> |
86 | #include <sys/disklabel.h> | | 86 | #include <sys/disklabel.h> |
87 | #include <sys/kmem.h> | | 87 | #include <sys/kmem.h> |
88 | #include <sys/malloc.h> | | 88 | #include <sys/malloc.h> |
89 | #include <sys/vnode.h> | | 89 | #include <sys/vnode.h> |
90 | | | 90 | |
91 | #include <machine/int_fmtio.h> | | 91 | #include <machine/int_fmtio.h> |
92 | | | 92 | |
93 | #include "netbsd-dm.h" | | 93 | #include "netbsd-dm.h" |
94 | #include "dm.h" | | 94 | #include "dm.h" |
95 | | | 95 | |
96 | static uint32_t sc_minor_num; | | 96 | static uint32_t sc_minor_num; |
97 | extern const struct dkdriver dmdkdriver; | | 97 | extern const struct dkdriver dmdkdriver; |
98 | uint32_t dm_dev_counter; | | 98 | uint32_t dm_dev_counter; |
99 | | | 99 | |
100 | /* Generic cf_data for device-mapper driver */ | | 100 | /* Generic cf_data for device-mapper driver */ |
101 | static struct cfdata dm_cfdata = { | | 101 | static struct cfdata dm_cfdata = { |
102 | .cf_name = "dm", | | 102 | .cf_name = "dm", |
103 | .cf_atname = "dm", | | 103 | .cf_atname = "dm", |
104 | .cf_fstate = FSTATE_STAR, | | 104 | .cf_fstate = FSTATE_STAR, |
105 | .cf_unit = 0 | | 105 | .cf_unit = 0 |
106 | }; | | 106 | }; |
107 | #define DM_REMOVE_FLAG(flag, name) do { \ | | 107 | #define DM_REMOVE_FLAG(flag, name) do { \ |
108 | prop_dictionary_get_uint32(dm_dict,DM_IOCTL_FLAGS,&flag); \ | | 108 | prop_dictionary_get_uint32(dm_dict,DM_IOCTL_FLAGS,&flag); \ |
109 | flag &= ~name; \ | | 109 | flag &= ~name; \ |
110 | prop_dictionary_set_uint32(dm_dict,DM_IOCTL_FLAGS,flag); \ | | 110 | prop_dictionary_set_uint32(dm_dict,DM_IOCTL_FLAGS,flag); \ |
111 | } while (/*CONSTCOND*/0) | | 111 | } while (/*CONSTCOND*/0) |
112 | | | 112 | |
113 | #define DM_ADD_FLAG(flag, name) do { \ | | 113 | #define DM_ADD_FLAG(flag, name) do { \ |
114 | prop_dictionary_get_uint32(dm_dict,DM_IOCTL_FLAGS,&flag); \ | | 114 | prop_dictionary_get_uint32(dm_dict,DM_IOCTL_FLAGS,&flag); \ |
115 | flag |= name; \ | | 115 | flag |= name; \ |
116 | prop_dictionary_set_uint32(dm_dict,DM_IOCTL_FLAGS,flag); \ | | 116 | prop_dictionary_set_uint32(dm_dict,DM_IOCTL_FLAGS,flag); \ |
117 | } while (/*CONSTCOND*/0) | | 117 | } while (/*CONSTCOND*/0) |
118 | | | 118 | |
119 | static int dm_dbg_print_flags(int); | | 119 | static int dm_dbg_print_flags(int); |
120 | | | 120 | |
121 | /* | | 121 | /* |
122 | * Print flags sent to the kernel from libevmapper. | | 122 | * Print flags sent to the kernel from libevmapper. |
123 | */ | | 123 | */ |
124 | static int | | 124 | static int |
125 | dm_dbg_print_flags(int flags) | | 125 | dm_dbg_print_flags(int flags) |
126 | { | | 126 | { |
127 | aprint_debug("dbg_print --- %d\n", flags); | | 127 | aprint_debug("dbg_print --- %d\n", flags); |
128 | | | 128 | |
129 | if (flags & DM_READONLY_FLAG) | | 129 | if (flags & DM_READONLY_FLAG) |
130 | aprint_debug("dbg_flags: DM_READONLY_FLAG set In/Out\n"); | | 130 | aprint_debug("dbg_flags: DM_READONLY_FLAG set In/Out\n"); |
131 | | | 131 | |
132 | if (flags & DM_SUSPEND_FLAG) | | 132 | if (flags & DM_SUSPEND_FLAG) |
133 | aprint_debug("dbg_flags: DM_SUSPEND_FLAG set In/Out \n"); | | 133 | aprint_debug("dbg_flags: DM_SUSPEND_FLAG set In/Out \n"); |
134 | | | 134 | |
135 | if (flags & DM_PERSISTENT_DEV_FLAG) | | 135 | if (flags & DM_PERSISTENT_DEV_FLAG) |
136 | aprint_debug("db_flags: DM_PERSISTENT_DEV_FLAG set In\n"); | | 136 | aprint_debug("db_flags: DM_PERSISTENT_DEV_FLAG set In\n"); |
137 | | | 137 | |
138 | if (flags & DM_STATUS_TABLE_FLAG) | | 138 | if (flags & DM_STATUS_TABLE_FLAG) |
139 | aprint_debug("dbg_flags: DM_STATUS_TABLE_FLAG set In\n"); | | 139 | aprint_debug("dbg_flags: DM_STATUS_TABLE_FLAG set In\n"); |
140 | | | 140 | |
141 | if (flags & DM_ACTIVE_PRESENT_FLAG) | | 141 | if (flags & DM_ACTIVE_PRESENT_FLAG) |
142 | aprint_debug("dbg_flags: DM_ACTIVE_PRESENT_FLAG set Out\n"); | | 142 | aprint_debug("dbg_flags: DM_ACTIVE_PRESENT_FLAG set Out\n"); |
143 | | | 143 | |
144 | if (flags & DM_INACTIVE_PRESENT_FLAG) | | 144 | if (flags & DM_INACTIVE_PRESENT_FLAG) |
145 | aprint_debug("dbg_flags: DM_INACTIVE_PRESENT_FLAG set Out\n"); | | 145 | aprint_debug("dbg_flags: DM_INACTIVE_PRESENT_FLAG set Out\n"); |
146 | | | 146 | |
147 | if (flags & DM_BUFFER_FULL_FLAG) | | 147 | if (flags & DM_BUFFER_FULL_FLAG) |
148 | aprint_debug("dbg_flags: DM_BUFFER_FULL_FLAG set Out\n"); | | 148 | aprint_debug("dbg_flags: DM_BUFFER_FULL_FLAG set Out\n"); |
149 | | | 149 | |
150 | if (flags & DM_SKIP_BDGET_FLAG) | | 150 | if (flags & DM_SKIP_BDGET_FLAG) |
151 | aprint_debug("dbg_flags: DM_SKIP_BDGET_FLAG set In\n"); | | 151 | aprint_debug("dbg_flags: DM_SKIP_BDGET_FLAG set In\n"); |
152 | | | 152 | |
153 | if (flags & DM_SKIP_LOCKFS_FLAG) | | 153 | if (flags & DM_SKIP_LOCKFS_FLAG) |
154 | aprint_debug("dbg_flags: DM_SKIP_LOCKFS_FLAG set In\n"); | | 154 | aprint_debug("dbg_flags: DM_SKIP_LOCKFS_FLAG set In\n"); |
155 | | | 155 | |
156 | if (flags & DM_NOFLUSH_FLAG) | | 156 | if (flags & DM_NOFLUSH_FLAG) |
157 | aprint_debug("dbg_flags: DM_NOFLUSH_FLAG set In\n"); | | 157 | aprint_debug("dbg_flags: DM_NOFLUSH_FLAG set In\n"); |
158 | | | 158 | |
159 | return 0; | | 159 | return 0; |
160 | } | | 160 | } |
161 | /* | | 161 | /* |
162 | * Get version ioctl call I do it as default therefore this | | 162 | * Get version ioctl call I do it as default therefore this |
163 | * function is unused now. | | 163 | * function is unused now. |
164 | */ | | 164 | */ |
165 | int | | 165 | int |
166 | dm_get_version_ioctl(prop_dictionary_t dm_dict) | | 166 | dm_get_version_ioctl(prop_dictionary_t dm_dict) |
167 | { | | 167 | { |
168 | | | 168 | |
169 | return 0; | | 169 | return 0; |
170 | } | | 170 | } |
171 | /* | | 171 | /* |
172 | * Get list of all available targets from global | | 172 | * Get list of all available targets from global |
173 | * target list and sent them back to libdevmapper. | | 173 | * target list and sent them back to libdevmapper. |
174 | */ | | 174 | */ |
175 | int | | 175 | int |
176 | dm_list_versions_ioctl(prop_dictionary_t dm_dict) | | 176 | dm_list_versions_ioctl(prop_dictionary_t dm_dict) |
177 | { | | 177 | { |
178 | prop_array_t target_list; | | 178 | prop_array_t target_list; |
179 | uint32_t flags; | | 179 | uint32_t flags; |
180 | | | 180 | |
181 | flags = 0; | | 181 | flags = 0; |
182 | | | 182 | |
183 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); | | 183 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); |
184 | | | 184 | |
185 | dm_dbg_print_flags(flags); | | 185 | dm_dbg_print_flags(flags); |
186 | target_list = dm_target_prop_list(); | | 186 | target_list = dm_target_prop_list(); |
187 | | | 187 | |
188 | prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, target_list); | | 188 | prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, target_list); |
189 | prop_object_release(target_list); | | 189 | prop_object_release(target_list); |
190 | | | 190 | |
191 | return 0; | | 191 | return 0; |
192 | } | | 192 | } |
193 | /* | | 193 | /* |
194 | * Create in-kernel entry for device. Device attributes such as name, uuid are | | 194 | * Create in-kernel entry for device. Device attributes such as name, uuid are |
195 | * taken from proplib dictionary. | | 195 | * taken from proplib dictionary. |
196 | * | | 196 | * |
197 | */ | | 197 | */ |
198 | int | | 198 | int |
199 | dm_dev_create_ioctl(prop_dictionary_t dm_dict) | | 199 | dm_dev_create_ioctl(prop_dictionary_t dm_dict) |
200 | { | | 200 | { |
201 | dm_dev_t *dmv; | | 201 | dm_dev_t *dmv; |
202 | const char *name, *uuid; | | 202 | const char *name, *uuid; |
203 | int r, flags; | | 203 | int r, flags; |
204 | device_t devt; | | 204 | device_t devt; |
205 | | | 205 | |
206 | r = 0; | | 206 | r = 0; |
207 | flags = 0; | | 207 | flags = 0; |
208 | name = NULL; | | 208 | name = NULL; |
209 | uuid = NULL; | | 209 | uuid = NULL; |
210 | | | 210 | |
211 | /* Get needed values from dictionary. */ | | 211 | /* Get needed values from dictionary. */ |
212 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); | | 212 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); |
213 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); | | 213 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); |
214 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); | | 214 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); |
215 | | | 215 | |
216 | dm_dbg_print_flags(flags); | | 216 | dm_dbg_print_flags(flags); |
217 | | | 217 | |
218 | /* Lookup name and uuid if device already exist quit. */ | | 218 | /* Lookup name and uuid if device already exist quit. */ |
219 | if ((dmv = dm_dev_lookup(name, uuid, -1)) != NULL) { | | 219 | if ((dmv = dm_dev_lookup(name, uuid, -1)) != NULL) { |
220 | DM_ADD_FLAG(flags, DM_EXISTS_FLAG); /* Device already exists */ | | 220 | DM_ADD_FLAG(flags, DM_EXISTS_FLAG); /* Device already exists */ |
221 | dm_dev_unbusy(dmv); | | 221 | dm_dev_unbusy(dmv); |
222 | return EEXIST; | | 222 | return EEXIST; |
223 | } | | 223 | } |
224 | if ((devt = config_attach_pseudo(&dm_cfdata)) == NULL) { | | 224 | if ((devt = config_attach_pseudo(&dm_cfdata)) == NULL) { |
225 | aprint_error("Unable to attach pseudo device dm/%s\n", name); | | 225 | aprint_error("Unable to attach pseudo device dm/%s\n", name); |
226 | return (ENOMEM); | | 226 | return (ENOMEM); |
227 | } | | 227 | } |
228 | if ((dmv = dm_dev_alloc()) == NULL) | | 228 | if ((dmv = dm_dev_alloc()) == NULL) |
229 | return ENOMEM; | | 229 | return ENOMEM; |
230 | | | 230 | |
231 | if (uuid) | | 231 | if (uuid) |
232 | strncpy(dmv->uuid, uuid, DM_UUID_LEN); | | 232 | strncpy(dmv->uuid, uuid, DM_UUID_LEN); |
233 | else | | 233 | else |
234 | dmv->uuid[0] = '\0'; | | 234 | dmv->uuid[0] = '\0'; |
235 | | | 235 | |
236 | if (name) | | 236 | if (name) |
237 | strlcpy(dmv->name, name, DM_NAME_LEN); | | 237 | strlcpy(dmv->name, name, DM_NAME_LEN); |
238 | | | 238 | |
239 | dmv->minor = (uint64_t)atomic_inc_32_nv(&sc_minor_num); | | 239 | dmv->minor = (uint64_t)atomic_inc_32_nv(&sc_minor_num); |
240 | dmv->flags = 0; /* device flags are set when needed */ | | 240 | dmv->flags = 0; /* device flags are set when needed */ |
241 | dmv->ref_cnt = 0; | | 241 | dmv->ref_cnt = 0; |
242 | dmv->event_nr = 0; | | 242 | dmv->event_nr = 0; |
243 | dmv->dev_type = 0; | | 243 | dmv->dev_type = 0; |
244 | dmv->devt = devt; | | 244 | dmv->devt = devt; |
245 | | | 245 | |
246 | dm_table_head_init(&dmv->table_head); | | 246 | dm_table_head_init(&dmv->table_head); |
247 | | | 247 | |
248 | mutex_init(&dmv->dev_mtx, MUTEX_DEFAULT, IPL_NONE); | | 248 | mutex_init(&dmv->dev_mtx, MUTEX_DEFAULT, IPL_NONE); |
249 | mutex_init(&dmv->diskp_mtx, MUTEX_DEFAULT, IPL_NONE); | | 249 | mutex_init(&dmv->diskp_mtx, MUTEX_DEFAULT, IPL_NONE); |
250 | cv_init(&dmv->dev_cv, "dm_dev"); | | 250 | cv_init(&dmv->dev_cv, "dm_dev"); |
251 | | | 251 | |
252 | if (flags & DM_READONLY_FLAG) | | 252 | if (flags & DM_READONLY_FLAG) |
253 | dmv->flags |= DM_READONLY_FLAG; | | 253 | dmv->flags |= DM_READONLY_FLAG; |
254 | | | 254 | |
255 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); | | 255 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); |
256 | | | 256 | |
257 | disk_init(dmv->diskp, dmv->name, &dmdkdriver); | | 257 | disk_init(dmv->diskp, dmv->name, &dmdkdriver); |
258 | disk_attach(dmv->diskp); | | 258 | disk_attach(dmv->diskp); |
259 | | | 259 | |
260 | dmv->diskp->dk_info = NULL; | | 260 | dmv->diskp->dk_info = NULL; |
261 | | | 261 | |
262 | if ((r = dm_dev_insert(dmv)) != 0) | | 262 | if ((r = dm_dev_insert(dmv)) != 0) |
263 | dm_dev_free(dmv); | | 263 | dm_dev_free(dmv); |
264 | | | 264 | |
265 | DM_ADD_FLAG(flags, DM_EXISTS_FLAG); | | 265 | DM_ADD_FLAG(flags, DM_EXISTS_FLAG); |
266 | DM_REMOVE_FLAG(flags, DM_INACTIVE_PRESENT_FLAG); | | 266 | DM_REMOVE_FLAG(flags, DM_INACTIVE_PRESENT_FLAG); |
267 | | | 267 | |
268 | /* Increment device counter After creating device */ | | 268 | /* Increment device counter After creating device */ |
269 | atomic_inc_32(&dm_dev_counter); | | 269 | atomic_inc_32(&dm_dev_counter); |
270 | | | 270 | |
271 | return r; | | 271 | return r; |
272 | } | | 272 | } |
273 | /* | | 273 | /* |
274 | * Get list of created device-mapper devices fromglobal list and | | 274 | * Get list of created device-mapper devices fromglobal list and |
275 | * send it to kernel. | | 275 | * send it to kernel. |
276 | * | | 276 | * |
277 | * Output dictionary: | | 277 | * Output dictionary: |
278 | * | | 278 | * |
279 | * <key>cmd_data</key> | | 279 | * <key>cmd_data</key> |
280 | * <array> | | 280 | * <array> |
281 | * <dict> | | 281 | * <dict> |
282 | * <key>name<key> | | 282 | * <key>name<key> |
283 | * <string>...</string> | | 283 | * <string>...</string> |
284 | * | | 284 | * |
285 | * <key>dev</key> | | 285 | * <key>dev</key> |
286 | * <integer>...</integer> | | 286 | * <integer>...</integer> |
287 | * </dict> | | 287 | * </dict> |
288 | * </array> | | 288 | * </array> |
289 | * | | 289 | * |
290 | */ | | 290 | */ |
291 | int | | 291 | int |
292 | dm_dev_list_ioctl(prop_dictionary_t dm_dict) | | 292 | dm_dev_list_ioctl(prop_dictionary_t dm_dict) |
293 | { | | 293 | { |
294 | prop_array_t dev_list; | | 294 | prop_array_t dev_list; |
295 | | | 295 | |
296 | uint32_t flags; | | 296 | uint32_t flags; |
297 | | | 297 | |
298 | flags = 0; | | 298 | flags = 0; |
299 | | | 299 | |
300 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); | | 300 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); |
301 | | | 301 | |
302 | dm_dbg_print_flags(flags); | | 302 | dm_dbg_print_flags(flags); |
303 | | | 303 | |
304 | dev_list = dm_dev_prop_list(); | | 304 | dev_list = dm_dev_prop_list(); |
305 | | | 305 | |
306 | prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, dev_list); | | 306 | prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, dev_list); |
307 | prop_object_release(dev_list); | | 307 | prop_object_release(dev_list); |
308 | | | 308 | |
309 | return 0; | | 309 | return 0; |
310 | } | | 310 | } |
311 | /* | | 311 | /* |
312 | * Rename selected devices old name is in struct dm_ioctl. | | 312 | * Rename selected devices old name is in struct dm_ioctl. |
313 | * newname is taken from dictionary | | 313 | * newname is taken from dictionary |
314 | * | | 314 | * |
315 | * <key>cmd_data</key> | | 315 | * <key>cmd_data</key> |
316 | * <array> | | 316 | * <array> |
317 | * <string>...</string> | | 317 | * <string>...</string> |
318 | * </array> | | 318 | * </array> |
319 | */ | | 319 | */ |
320 | int | | 320 | int |
321 | dm_dev_rename_ioctl(prop_dictionary_t dm_dict) | | 321 | dm_dev_rename_ioctl(prop_dictionary_t dm_dict) |
322 | { | | 322 | { |
323 | prop_array_t cmd_array; | | 323 | prop_array_t cmd_array; |
324 | dm_dev_t *dmv; | | 324 | dm_dev_t *dmv; |
325 | | | 325 | |
326 | const char *name, *uuid, *n_name; | | 326 | const char *name, *uuid, *n_name; |
327 | uint32_t flags, minor; | | 327 | uint32_t flags, minor; |
328 | | | 328 | |
329 | name = NULL; | | 329 | name = NULL; |
330 | uuid = NULL; | | 330 | uuid = NULL; |
331 | minor = 0; | | 331 | minor = 0; |
332 | | | 332 | |
333 | /* Get needed values from dictionary. */ | | 333 | /* Get needed values from dictionary. */ |
334 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); | | 334 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); |
335 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); | | 335 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); |
336 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); | | 336 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); |
337 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); | | 337 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); |
338 | | | 338 | |
339 | dm_dbg_print_flags(flags); | | 339 | dm_dbg_print_flags(flags); |
340 | | | 340 | |
341 | cmd_array = prop_dictionary_get(dm_dict, DM_IOCTL_CMD_DATA); | | 341 | cmd_array = prop_dictionary_get(dm_dict, DM_IOCTL_CMD_DATA); |
342 | | | 342 | |
343 | prop_array_get_cstring_nocopy(cmd_array, 0, &n_name); | | 343 | prop_array_get_cstring_nocopy(cmd_array, 0, &n_name); |
344 | | | 344 | |
345 | if (strlen(n_name) + 1 > DM_NAME_LEN) | | 345 | if (strlen(n_name) + 1 > DM_NAME_LEN) |
346 | return EINVAL; | | 346 | return EINVAL; |
347 | | | 347 | |
348 | if ((dmv = dm_dev_rem(name, uuid, minor)) == NULL) { | | 348 | if ((dmv = dm_dev_rem(name, uuid, minor)) == NULL) { |
349 | DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG); | | 349 | DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG); |
350 | return ENOENT; | | 350 | return ENOENT; |
351 | } | | 351 | } |
352 | /* change device name */ | | 352 | /* change device name */ |
353 | /* | | 353 | /* |
354 | * XXX How to deal with this change, name only used in | | 354 | * XXX How to deal with this change, name only used in |
355 | * dm_dev_routines, should I add dm_dev_change_name which will run | | 355 | * dm_dev_routines, should I add dm_dev_change_name which will run |
356 | * under the dm_dev_list mutex ? | | 356 | * under the dm_dev_list mutex ? |
357 | */ | | 357 | */ |
358 | strlcpy(dmv->name, n_name, DM_NAME_LEN); | | 358 | strlcpy(dmv->name, n_name, DM_NAME_LEN); |
359 | | | 359 | |
360 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt); | | 360 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt); |
361 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); | | 361 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); |
362 | prop_dictionary_set_cstring(dm_dict, DM_IOCTL_UUID, dmv->uuid); | | 362 | prop_dictionary_set_cstring(dm_dict, DM_IOCTL_UUID, dmv->uuid); |
363 | | | 363 | |
364 | dm_dev_insert(dmv); | | 364 | dm_dev_insert(dmv); |
365 | | | 365 | |
366 | return 0; | | 366 | return 0; |
367 | } | | 367 | } |
368 | /* | | 368 | /* |
369 | * Remove device from global list I have to remove active | | 369 | * Remove device from global list I have to remove active |
370 | * and inactive tables first. | | 370 | * and inactive tables first. |
371 | */ | | 371 | */ |
372 | int | | 372 | int |
373 | dm_dev_remove_ioctl(prop_dictionary_t dm_dict) | | 373 | dm_dev_remove_ioctl(prop_dictionary_t dm_dict) |
374 | { | | 374 | { |
375 | dm_dev_t *dmv; | | 375 | dm_dev_t *dmv; |
376 | const char *name, *uuid; | | 376 | const char *name, *uuid; |
377 | uint32_t flags, minor; | | 377 | uint32_t flags, minor; |
378 | device_t devt; | | 378 | device_t devt; |
379 | | | 379 | |
380 | flags = 0; | | 380 | flags = 0; |
381 | name = NULL; | | 381 | name = NULL; |
382 | uuid = NULL; | | 382 | uuid = NULL; |
383 | | | 383 | |
384 | /* Get needed values from dictionary. */ | | 384 | /* Get needed values from dictionary. */ |
385 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); | | 385 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); |
386 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); | | 386 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); |
387 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); | | 387 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); |
388 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); | | 388 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); |
389 | | | 389 | |
390 | dm_dbg_print_flags(flags); | | 390 | dm_dbg_print_flags(flags); |
391 | | | 391 | |
392 | /* | | 392 | /* |
393 | * This seems as hack to me, probably use routine dm_dev_get_devt to | | 393 | * This seems as hack to me, probably use routine dm_dev_get_devt to |
394 | * atomicaly get devt from device. | | 394 | * atomicaly get devt from device. |
395 | */ | | 395 | */ |
396 | if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { | | 396 | if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { |
397 | DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG); | | 397 | DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG); |
398 | return ENOENT; | | 398 | return ENOENT; |
399 | } | | 399 | } |
400 | devt = dmv->devt; | | 400 | devt = dmv->devt; |
401 | | | 401 | |
402 | dm_dev_unbusy(dmv); | | 402 | dm_dev_unbusy(dmv); |
403 | | | 403 | |
404 | /* | | 404 | /* |
405 | * This will call dm_detach routine which will actually removes | | 405 | * This will call dm_detach routine which will actually removes |
406 | * device. | | 406 | * device. |
407 | */ | | 407 | */ |
408 | return config_detach(devt, DETACH_QUIET); | | 408 | return config_detach(devt, DETACH_QUIET); |
409 | } | | 409 | } |
410 | /* | | 410 | /* |
411 | * Return actual state of device to libdevmapper. | | 411 | * Return actual state of device to libdevmapper. |
412 | */ | | 412 | */ |
413 | int | | 413 | int |
414 | dm_dev_status_ioctl(prop_dictionary_t dm_dict) | | 414 | dm_dev_status_ioctl(prop_dictionary_t dm_dict) |
415 | { | | 415 | { |
416 | dm_dev_t *dmv; | | 416 | dm_dev_t *dmv; |
417 | const char *name, *uuid; | | 417 | const char *name, *uuid; |
418 | uint32_t flags, j, minor; | | 418 | uint32_t flags, j, minor; |
419 | | | 419 | |
420 | name = NULL; | | 420 | name = NULL; |
421 | uuid = NULL; | | 421 | uuid = NULL; |
422 | flags = 0; | | 422 | flags = 0; |
423 | j = 0; | | 423 | j = 0; |
424 | | | 424 | |
425 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); | | 425 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); |
426 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); | | 426 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); |
427 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); | | 427 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); |
428 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); | | 428 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); |
429 | | | 429 | |
430 | if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { | | 430 | if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { |
431 | DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG); | | 431 | DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG); |
432 | return ENOENT; | | 432 | return ENOENT; |
433 | } | | 433 | } |
434 | dm_dbg_print_flags(dmv->flags); | | 434 | dm_dbg_print_flags(dmv->flags); |
435 | | | 435 | |
436 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt); | | 436 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt); |
437 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); | | 437 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); |
438 | prop_dictionary_set_cstring(dm_dict, DM_IOCTL_UUID, dmv->uuid); | | 438 | prop_dictionary_set_cstring(dm_dict, DM_IOCTL_UUID, dmv->uuid); |
439 | | | 439 | |
440 | if (dmv->flags & DM_SUSPEND_FLAG) | | 440 | if (dmv->flags & DM_SUSPEND_FLAG) |
441 | DM_ADD_FLAG(flags, DM_SUSPEND_FLAG); | | 441 | DM_ADD_FLAG(flags, DM_SUSPEND_FLAG); |
442 | | | 442 | |
443 | /* | | 443 | /* |
444 | * Add status flags for tables I have to check both active and | | 444 | * Add status flags for tables I have to check both active and |
445 | * inactive tables. | | 445 | * inactive tables. |
446 | */ | | 446 | */ |
447 | if ((j = dm_table_get_target_count(&dmv->table_head, DM_TABLE_ACTIVE))) { | | 447 | if ((j = dm_table_get_target_count(&dmv->table_head, DM_TABLE_ACTIVE))) { |
448 | DM_ADD_FLAG(flags, DM_ACTIVE_PRESENT_FLAG); | | 448 | DM_ADD_FLAG(flags, DM_ACTIVE_PRESENT_FLAG); |
449 | } else | | 449 | } else |
450 | DM_REMOVE_FLAG(flags, DM_ACTIVE_PRESENT_FLAG); | | 450 | DM_REMOVE_FLAG(flags, DM_ACTIVE_PRESENT_FLAG); |
451 | | | 451 | |
452 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_TARGET_COUNT, j); | | 452 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_TARGET_COUNT, j); |
453 | | | 453 | |
454 | if (dm_table_get_target_count(&dmv->table_head, DM_TABLE_INACTIVE)) | | 454 | if (dm_table_get_target_count(&dmv->table_head, DM_TABLE_INACTIVE)) |
455 | DM_ADD_FLAG(flags, DM_INACTIVE_PRESENT_FLAG); | | 455 | DM_ADD_FLAG(flags, DM_INACTIVE_PRESENT_FLAG); |
456 | else | | 456 | else |
457 | DM_REMOVE_FLAG(flags, DM_INACTIVE_PRESENT_FLAG); | | 457 | DM_REMOVE_FLAG(flags, DM_INACTIVE_PRESENT_FLAG); |
458 | | | 458 | |
459 | dm_dev_unbusy(dmv); | | 459 | dm_dev_unbusy(dmv); |
460 | | | 460 | |
461 | return 0; | | 461 | return 0; |
462 | } | | 462 | } |
463 | /* | | 463 | /* |
464 | * Set only flag to suggest that device is suspended. This call is | | 464 | * Set only flag to suggest that device is suspended. This call is |
465 | * not supported in NetBSD. | | 465 | * not supported in NetBSD. |
466 | * | | 466 | * |
467 | */ | | 467 | */ |
468 | int | | 468 | int |
469 | dm_dev_suspend_ioctl(prop_dictionary_t dm_dict) | | 469 | dm_dev_suspend_ioctl(prop_dictionary_t dm_dict) |
470 | { | | 470 | { |
471 | dm_dev_t *dmv; | | 471 | dm_dev_t *dmv; |
472 | const char *name, *uuid; | | 472 | const char *name, *uuid; |
473 | uint32_t flags, minor; | | 473 | uint32_t flags, minor; |
474 | | | 474 | |
475 | name = NULL; | | 475 | name = NULL; |
476 | uuid = NULL; | | 476 | uuid = NULL; |
477 | flags = 0; | | 477 | flags = 0; |
478 | | | 478 | |
479 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); | | 479 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); |
480 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); | | 480 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); |
481 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); | | 481 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); |
482 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); | | 482 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); |
483 | | | 483 | |
484 | if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { | | 484 | if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { |
485 | DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG); | | 485 | DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG); |
486 | return ENOENT; | | 486 | return ENOENT; |
487 | } | | 487 | } |
488 | atomic_or_32(&dmv->flags, DM_SUSPEND_FLAG); | | 488 | atomic_or_32(&dmv->flags, DM_SUSPEND_FLAG); |
489 | | | 489 | |
490 | dm_dbg_print_flags(dmv->flags); | | 490 | dm_dbg_print_flags(dmv->flags); |
491 | | | 491 | |
492 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt); | | 492 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt); |
493 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_FLAGS, dmv->flags); | | 493 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_FLAGS, dmv->flags); |
494 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); | | 494 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); |
495 | | | 495 | |
496 | dm_dev_unbusy(dmv); | | 496 | dm_dev_unbusy(dmv); |
497 | | | 497 | |
498 | /* Add flags to dictionary flag after dmv -> dict copy */ | | 498 | /* Add flags to dictionary flag after dmv -> dict copy */ |
499 | DM_ADD_FLAG(flags, DM_EXISTS_FLAG); | | 499 | DM_ADD_FLAG(flags, DM_EXISTS_FLAG); |
500 | | | 500 | |
501 | return 0; | | 501 | return 0; |
502 | } | | 502 | } |
503 | /* | | 503 | /* |
504 | * Simulate Linux behaviour better and switch tables here and not in | | 504 | * Simulate Linux behaviour better and switch tables here and not in |
505 | * dm_table_load_ioctl. | | 505 | * dm_table_load_ioctl. |
506 | */ | | 506 | */ |
507 | int | | 507 | int |
508 | dm_dev_resume_ioctl(prop_dictionary_t dm_dict) | | 508 | dm_dev_resume_ioctl(prop_dictionary_t dm_dict) |
509 | { | | 509 | { |
510 | dm_dev_t *dmv; | | 510 | dm_dev_t *dmv; |
511 | const char *name, *uuid; | | 511 | const char *name, *uuid; |
512 | uint32_t flags, minor; | | 512 | uint32_t flags, minor; |
513 | | | 513 | |
514 | name = NULL; | | 514 | name = NULL; |
515 | uuid = NULL; | | 515 | uuid = NULL; |
516 | flags = 0; | | 516 | flags = 0; |
517 | | | 517 | |
518 | /* | | 518 | /* |
519 | * char *xml; xml = prop_dictionary_externalize(dm_dict); | | 519 | * char *xml; xml = prop_dictionary_externalize(dm_dict); |
520 | * printf("%s\n",xml); | | 520 | * printf("%s\n",xml); |
521 | */ | | 521 | */ |
522 | | | 522 | |
523 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); | | 523 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); |
524 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); | | 524 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); |
525 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); | | 525 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); |
526 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); | | 526 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); |
527 | | | 527 | |
528 | /* Remove device from global device list */ | | 528 | /* Remove device from global device list */ |
529 | if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { | | 529 | if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { |
530 | DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG); | | 530 | DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG); |
531 | return ENOENT; | | 531 | return ENOENT; |
532 | } | | 532 | } |
533 | atomic_and_32(&dmv->flags, ~(DM_SUSPEND_FLAG | DM_INACTIVE_PRESENT_FLAG)); | | 533 | atomic_and_32(&dmv->flags, ~(DM_SUSPEND_FLAG | DM_INACTIVE_PRESENT_FLAG)); |
534 | atomic_or_32(&dmv->flags, DM_ACTIVE_PRESENT_FLAG); | | 534 | atomic_or_32(&dmv->flags, DM_ACTIVE_PRESENT_FLAG); |
535 | | | 535 | |
536 | dm_table_switch_tables(&dmv->table_head); | | 536 | dm_table_switch_tables(&dmv->table_head); |
537 | | | 537 | |
538 | DM_ADD_FLAG(flags, DM_EXISTS_FLAG); | | 538 | DM_ADD_FLAG(flags, DM_EXISTS_FLAG); |
539 | | | 539 | |
540 | dmgetproperties(dmv->diskp, &dmv->table_head); | | 540 | dmgetproperties(dmv->diskp, &dmv->table_head); |
541 | | | 541 | |
542 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt); | | 542 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt); |
543 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_FLAGS, flags); | | 543 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_FLAGS, flags); |
544 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); | | 544 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); |
545 | | | 545 | |
546 | dm_dev_unbusy(dmv); | | 546 | dm_dev_unbusy(dmv); |
547 | | | 547 | |
548 | /* Destroy inactive table after resume. */ | | 548 | /* Destroy inactive table after resume. */ |
549 | dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE); | | 549 | dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE); |
550 | | | 550 | |
551 | return 0; | | 551 | return 0; |
552 | } | | 552 | } |
553 | /* | | 553 | /* |
554 | * Table management routines | | 554 | * Table management routines |
555 | * lvm2tools doens't send name/uuid to kernel with table | | 555 | * lvm2tools doens't send name/uuid to kernel with table |
556 | * for lookup I have to use minor number. | | 556 | * for lookup I have to use minor number. |
557 | */ | | 557 | */ |
558 | | | 558 | |
559 | /* | | 559 | /* |
560 | * Remove inactive table from device. Routines which work's with inactive tables | | 560 | * Remove inactive table from device. Routines which work's with inactive tables |
561 | * doesn't need to synchronise with dmstrategy. They can synchronise themselves with mutex?. | | 561 | * doesn't need to synchronise with dmstrategy. They can synchronise themselves with mutex?. |
562 | * | | 562 | * |
563 | */ | | 563 | */ |
564 | int | | 564 | int |
565 | dm_table_clear_ioctl(prop_dictionary_t dm_dict) | | 565 | dm_table_clear_ioctl(prop_dictionary_t dm_dict) |
566 | { | | 566 | { |
567 | dm_dev_t *dmv; | | 567 | dm_dev_t *dmv; |
568 | const char *name, *uuid; | | 568 | const char *name, *uuid; |
569 | uint32_t flags, minor; | | 569 | uint32_t flags, minor; |
570 | | | 570 | |
571 | dmv = NULL; | | 571 | dmv = NULL; |
572 | name = NULL; | | 572 | name = NULL; |
573 | uuid = NULL; | | 573 | uuid = NULL; |
574 | flags = 0; | | 574 | flags = 0; |
575 | minor = 0; | | 575 | minor = 0; |
576 | | | 576 | |
577 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); | | 577 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); |
578 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); | | 578 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); |
579 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); | | 579 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); |
580 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); | | 580 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); |
581 | | | 581 | |
582 | aprint_debug("Clearing inactive table from device: %s--%s\n", | | 582 | aprint_debug("Clearing inactive table from device: %s--%s\n", |
583 | name, uuid); | | 583 | name, uuid); |
584 | | | 584 | |
585 | if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { | | 585 | if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { |
586 | DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG); | | 586 | DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG); |
587 | return ENOENT; | | 587 | return ENOENT; |
588 | } | | 588 | } |
589 | /* Select unused table */ | | 589 | /* Select unused table */ |
590 | dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE); | | 590 | dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE); |
591 | | | 591 | |
592 | atomic_and_32(&dmv->flags, ~DM_INACTIVE_PRESENT_FLAG); | | 592 | atomic_and_32(&dmv->flags, ~DM_INACTIVE_PRESENT_FLAG); |
593 | | | 593 | |
594 | dm_dev_unbusy(dmv); | | 594 | dm_dev_unbusy(dmv); |
595 | | | 595 | |
596 | return 0; | | 596 | return 0; |
597 | } | | 597 | } |
598 | /* | | 598 | /* |
599 | * Get list of physical devices for active table. | | 599 | * Get list of physical devices for active table. |
600 | * Get dev_t from pdev vnode and insert it into cmd_array. | | 600 | * Get dev_t from pdev vnode and insert it into cmd_array. |
601 | * | | 601 | * |
602 | * XXX. This function is called from lvm2tools to get information | | 602 | * XXX. This function is called from lvm2tools to get information |
603 | * about physical devices, too e.g. during vgcreate. | | 603 | * about physical devices, too e.g. during vgcreate. |
604 | */ | | 604 | */ |
605 | int | | 605 | int |
606 | dm_table_deps_ioctl(prop_dictionary_t dm_dict) | | 606 | dm_table_deps_ioctl(prop_dictionary_t dm_dict) |
607 | { | | 607 | { |
608 | dm_dev_t *dmv; | | 608 | dm_dev_t *dmv; |
609 | dm_table_t *tbl; | | 609 | dm_table_t *tbl; |
610 | dm_table_entry_t *table_en; | | 610 | dm_table_entry_t *table_en; |
611 | | | 611 | |
612 | prop_array_t cmd_array; | | 612 | prop_array_t cmd_array; |
613 | const char *name, *uuid; | | 613 | const char *name, *uuid; |
614 | uint32_t flags, minor; | | 614 | uint32_t flags, minor; |
615 | | | 615 | |
616 | int table_type; | | 616 | int table_type; |
617 | size_t i; | | 617 | size_t i; |
618 | | | 618 | |
619 | name = NULL; | | 619 | name = NULL; |
620 | uuid = NULL; | | 620 | uuid = NULL; |
621 | dmv = NULL; | | 621 | dmv = NULL; |
622 | flags = 0; | | 622 | flags = 0; |
623 | | | 623 | |
624 | i = 0; | | 624 | i = 0; |
625 | | | 625 | |
626 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); | | 626 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); |
627 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); | | 627 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); |
628 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); | | 628 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); |
629 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); | | 629 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); |
630 | | | 630 | |
631 | /* create array for dev_t's */ | | 631 | /* create array for dev_t's */ |
632 | cmd_array = prop_array_create(); | | 632 | cmd_array = prop_array_create(); |
633 | | | 633 | |
634 | if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { | | 634 | if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { |
635 | DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG); | | 635 | DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG); |
636 | return ENOENT; | | 636 | return ENOENT; |
637 | } | | 637 | } |
638 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); | | 638 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); |
639 | prop_dictionary_set_cstring(dm_dict, DM_IOCTL_NAME, dmv->name); | | 639 | prop_dictionary_set_cstring(dm_dict, DM_IOCTL_NAME, dmv->name); |
640 | prop_dictionary_set_cstring(dm_dict, DM_IOCTL_UUID, dmv->uuid); | | 640 | prop_dictionary_set_cstring(dm_dict, DM_IOCTL_UUID, dmv->uuid); |
641 | | | 641 | |
642 | aprint_debug("Getting table deps for device: %s\n", dmv->name); | | 642 | aprint_debug("Getting table deps for device: %s\n", dmv->name); |
643 | | | 643 | |
644 | /* | | 644 | /* |
645 | * if DM_QUERY_INACTIVE_TABLE_FLAG is passed we need to query | | 645 | * if DM_QUERY_INACTIVE_TABLE_FLAG is passed we need to query |
646 | * INACTIVE TABLE | | 646 | * INACTIVE TABLE |
647 | */ | | 647 | */ |
648 | if (flags & DM_QUERY_INACTIVE_TABLE_FLAG) | | 648 | if (flags & DM_QUERY_INACTIVE_TABLE_FLAG) |
649 | table_type = DM_TABLE_INACTIVE; | | 649 | table_type = DM_TABLE_INACTIVE; |
650 | else | | 650 | else |
651 | table_type = DM_TABLE_ACTIVE; | | 651 | table_type = DM_TABLE_ACTIVE; |
652 | | | 652 | |
653 | tbl = dm_table_get_entry(&dmv->table_head, table_type); | | 653 | tbl = dm_table_get_entry(&dmv->table_head, table_type); |
654 | | | 654 | |
655 | SLIST_FOREACH(table_en, tbl, next) | | 655 | SLIST_FOREACH(table_en, tbl, next) |
656 | table_en->target->deps(table_en, cmd_array); | | 656 | table_en->target->deps(table_en, cmd_array); |
657 | | | 657 | |
658 | dm_table_release(&dmv->table_head, table_type); | | 658 | dm_table_release(&dmv->table_head, table_type); |
659 | dm_dev_unbusy(dmv); | | 659 | dm_dev_unbusy(dmv); |
660 | | | 660 | |
661 | prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, cmd_array); | | 661 | prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, cmd_array); |
662 | prop_object_release(cmd_array); | | 662 | prop_object_release(cmd_array); |
663 | | | 663 | |
664 | return 0; | | 664 | return 0; |
665 | } | | 665 | } |
666 | /* | | 666 | /* |
667 | * Load new table/tables to device. | | 667 | * Load new table/tables to device. |
668 | * Call apropriate target init routine open all physical pdev's and | | 668 | * Call apropriate target init routine open all physical pdev's and |
669 | * link them to device. For other targets mirror, strip, snapshot | | 669 | * link them to device. For other targets mirror, strip, snapshot |
670 | * etc. also add dependency devices to upcalls list. | | 670 | * etc. also add dependency devices to upcalls list. |
671 | * | | 671 | * |
672 | * Load table to inactive slot table are switched in dm_device_resume_ioctl. | | 672 | * Load table to inactive slot table are switched in dm_device_resume_ioctl. |
673 | * This simulates Linux behaviour better there should not be any difference. | | 673 | * This simulates Linux behaviour better there should not be any difference. |
674 | * | | 674 | * |
675 | */ | | 675 | */ |
676 | int | | 676 | int |
677 | dm_table_load_ioctl(prop_dictionary_t dm_dict) | | 677 | dm_table_load_ioctl(prop_dictionary_t dm_dict) |
678 | { | | 678 | { |
679 | dm_dev_t *dmv; | | 679 | dm_dev_t *dmv; |
680 | dm_table_entry_t *table_en, *last_table; | | 680 | dm_table_entry_t *table_en, *last_table; |
681 | dm_table_t *tbl; | | 681 | dm_table_t *tbl; |
682 | dm_target_t *target; | | 682 | dm_target_t *target; |
683 | | | 683 | |
684 | prop_object_iterator_t iter; | | 684 | prop_object_iterator_t iter; |
685 | prop_array_t cmd_array; | | 685 | prop_array_t cmd_array; |
686 | prop_dictionary_t target_dict; | | 686 | prop_dictionary_t target_dict; |
687 | | | 687 | |
688 | const char *name, *uuid, *type; | | 688 | const char *name, *uuid, *type; |
689 | | | 689 | |
690 | uint32_t flags, ret, minor; | | 690 | uint32_t flags, ret, minor; |
691 | | | 691 | |
692 | char *str; | | 692 | char *str; |
693 | | | 693 | |
694 | ret = 0; | | 694 | ret = 0; |
695 | flags = 0; | | 695 | flags = 0; |
696 | name = NULL; | | 696 | name = NULL; |
697 | uuid = NULL; | | 697 | uuid = NULL; |
698 | dmv = NULL; | | 698 | dmv = NULL; |
699 | last_table = NULL; | | 699 | last_table = NULL; |
700 | str = NULL; | | 700 | str = NULL; |
701 | | | 701 | |
702 | /* | | 702 | /* |
703 | * char *xml; xml = prop_dictionary_externalize(dm_dict); | | 703 | * char *xml; xml = prop_dictionary_externalize(dm_dict); |
704 | * printf("%s\n",xml); | | 704 | * printf("%s\n",xml); |
705 | */ | | 705 | */ |
706 | | | 706 | |
707 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); | | 707 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); |
708 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); | | 708 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); |
709 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); | | 709 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); |
710 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); | | 710 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); |
711 | | | 711 | |
712 | cmd_array = prop_dictionary_get(dm_dict, DM_IOCTL_CMD_DATA); | | 712 | cmd_array = prop_dictionary_get(dm_dict, DM_IOCTL_CMD_DATA); |
713 | iter = prop_array_iterator(cmd_array); | | 713 | iter = prop_array_iterator(cmd_array); |
714 | dm_dbg_print_flags(flags); | | 714 | dm_dbg_print_flags(flags); |
715 | | | 715 | |
716 | if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { | | 716 | if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { |
717 | DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG); | | 717 | DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG); |
718 | return ENOENT; | | 718 | return ENOENT; |
719 | } | | 719 | } |
720 | aprint_debug("Loading table to device: %s--%d\n", name, | | 720 | aprint_debug("Loading table to device: %s--%d\n", name, |
721 | dmv->table_head.cur_active_table); | | 721 | dmv->table_head.cur_active_table); |
722 | | | 722 | |
723 | /* | | 723 | /* |
724 | * I have to check if this table slot is not used by another table list. | | 724 | * I have to check if this table slot is not used by another table list. |
725 | * if it is used I should free them. | | 725 | * if it is used I should free them. |
726 | */ | | 726 | */ |
727 | if (dmv->flags & DM_INACTIVE_PRESENT_FLAG) | | 727 | if (dmv->flags & DM_INACTIVE_PRESENT_FLAG) |
728 | dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE); | | 728 | dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE); |
729 | | | 729 | |
730 | dm_dbg_print_flags(dmv->flags); | | 730 | dm_dbg_print_flags(dmv->flags); |
731 | tbl = dm_table_get_entry(&dmv->table_head, DM_TABLE_INACTIVE); | | 731 | tbl = dm_table_get_entry(&dmv->table_head, DM_TABLE_INACTIVE); |
732 | | | 732 | |
733 | aprint_debug("dmv->name = %s\n", dmv->name); | | 733 | aprint_debug("dmv->name = %s\n", dmv->name); |
734 | | | 734 | |
735 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); | | 735 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); |
736 | | | 736 | |
737 | while ((target_dict = prop_object_iterator_next(iter)) != NULL) { | | 737 | while ((target_dict = prop_object_iterator_next(iter)) != NULL) { |
738 | | | 738 | |
739 | prop_dictionary_get_cstring_nocopy(target_dict, | | 739 | prop_dictionary_get_cstring_nocopy(target_dict, |
740 | DM_TABLE_TYPE, &type); | | 740 | DM_TABLE_TYPE, &type); |
741 | /* | | 741 | /* |
742 | * If we want to deny table with 2 or more different | | 742 | * If we want to deny table with 2 or more different |
743 | * target we should do it here | | 743 | * target we should do it here |
744 | */ | | 744 | */ |
745 | if (((target = dm_target_lookup(type)) == NULL) && | | 745 | if (((target = dm_target_lookup(type)) == NULL) && |
746 | ((target = dm_target_autoload(type)) == NULL)) { | | 746 | ((target = dm_target_autoload(type)) == NULL)) { |
747 | dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE); | | 747 | dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE); |
748 | dm_dev_unbusy(dmv); | | 748 | dm_dev_unbusy(dmv); |
749 | return ENOENT; | | 749 | return ENOENT; |
750 | } | | 750 | } |
751 | if ((table_en = kmem_alloc(sizeof(dm_table_entry_t), | | 751 | if ((table_en = kmem_alloc(sizeof(dm_table_entry_t), |
752 | KM_SLEEP)) == NULL) { | | 752 | KM_SLEEP)) == NULL) { |
753 | dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE); | | 753 | dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE); |
754 | dm_dev_unbusy(dmv); | | 754 | dm_dev_unbusy(dmv); |
755 | return ENOMEM; | | 755 | return ENOMEM; |
756 | } | | 756 | } |
757 | prop_dictionary_get_uint64(target_dict, DM_TABLE_START, | | 757 | prop_dictionary_get_uint64(target_dict, DM_TABLE_START, |
758 | &table_en->start); | | 758 | &table_en->start); |
759 | prop_dictionary_get_uint64(target_dict, DM_TABLE_LENGTH, | | 759 | prop_dictionary_get_uint64(target_dict, DM_TABLE_LENGTH, |
760 | &table_en->length); | | 760 | &table_en->length); |
761 | | | 761 | |
762 | table_en->target = target; | | 762 | table_en->target = target; |
763 | table_en->dm_dev = dmv; | | 763 | table_en->dm_dev = dmv; |
764 | table_en->target_config = NULL; | | 764 | table_en->target_config = NULL; |
765 | | | 765 | |
766 | /* | | 766 | /* |
767 | * There is a parameter string after dm_target_spec | | 767 | * There is a parameter string after dm_target_spec |
768 | * structure which points to /dev/wd0a 284 part of | | 768 | * structure which points to /dev/wd0a 284 part of |
769 | * table. String str points to this text. This can be | | 769 | * table. String str points to this text. This can be |
770 | * null and therefore it should be checked before we try to | | 770 | * null and therefore it should be checked before we try to |
771 | * use it. | | 771 | * use it. |
772 | */ | | 772 | */ |
773 | prop_dictionary_get_cstring(target_dict, | | 773 | prop_dictionary_get_cstring(target_dict, |
774 | DM_TABLE_PARAMS, (char **) &str); | | 774 | DM_TABLE_PARAMS, (char **) &str); |
775 | | | 775 | |
776 | if (SLIST_EMPTY(tbl)) | | 776 | if (SLIST_EMPTY(tbl)) |
777 | /* insert this table to head */ | | 777 | /* insert this table to head */ |
778 | SLIST_INSERT_HEAD(tbl, table_en, next); | | 778 | SLIST_INSERT_HEAD(tbl, table_en, next); |
779 | else | | 779 | else |
780 | SLIST_INSERT_AFTER(last_table, table_en, next); | | 780 | SLIST_INSERT_AFTER(last_table, table_en, next); |
781 | | | 781 | |
782 | /* | | 782 | /* |
783 | * Params string is different for every target, | | 783 | * Params string is different for every target, |
784 | * therfore I have to pass it to target init | | 784 | * therfore I have to pass it to target init |
785 | * routine and parse parameters there. | | 785 | * routine and parse parameters there. |
786 | */ | | 786 | */ |
787 | | | 787 | |
788 | if ((ret = target->init(dmv, &table_en->target_config, | | 788 | if ((ret = target->init(dmv, &table_en->target_config, |
789 | str)) != 0) { | | 789 | str)) != 0) { |
790 | | | 790 | |
791 | dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE); | | 791 | dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE); |
792 | dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE); | | 792 | dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE); |
793 | free(str, M_TEMP); | | 793 | free(str, M_TEMP); |
794 | | | 794 | |
795 | dm_dev_unbusy(dmv); | | 795 | dm_dev_unbusy(dmv); |
| | | 796 | dm_target_unbusy(target); |
796 | return ret; | | 797 | return ret; |
797 | } | | 798 | } |
798 | last_table = table_en; | | 799 | last_table = table_en; |
799 | free(str, M_TEMP); | | 800 | free(str, M_TEMP); |
800 | } | | 801 | } |
801 | prop_object_iterator_release(iter); | | 802 | prop_object_iterator_release(iter); |
802 | | | 803 | |
803 | DM_ADD_FLAG(flags, DM_INACTIVE_PRESENT_FLAG); | | 804 | DM_ADD_FLAG(flags, DM_INACTIVE_PRESENT_FLAG); |
804 | atomic_or_32(&dmv->flags, DM_INACTIVE_PRESENT_FLAG); | | 805 | atomic_or_32(&dmv->flags, DM_INACTIVE_PRESENT_FLAG); |
805 | | | 806 | |
806 | dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE); | | 807 | dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE); |
807 | dm_dev_unbusy(dmv); | | 808 | dm_dev_unbusy(dmv); |
808 | return 0; | | 809 | return 0; |
809 | } | | 810 | } |
810 | /* | | 811 | /* |
811 | * Get description of all tables loaded to device from kernel | | 812 | * Get description of all tables loaded to device from kernel |
812 | * and send it to libdevmapper. | | 813 | * and send it to libdevmapper. |
813 | * | | 814 | * |
814 | * Output dictionary for every table: | | 815 | * Output dictionary for every table: |
815 | * | | 816 | * |
816 | * <key>cmd_data</key> | | 817 | * <key>cmd_data</key> |
817 | * <array> | | 818 | * <array> |
818 | * <dict> | | 819 | * <dict> |
819 | * <key>type<key> | | 820 | * <key>type<key> |
820 | * <string>...</string> | | 821 | * <string>...</string> |
821 | * | | 822 | * |
822 | * <key>start</key> | | 823 | * <key>start</key> |
823 | * <integer>...</integer> | | 824 | * <integer>...</integer> |
824 | * | | 825 | * |
825 | * <key>length</key> | | 826 | * <key>length</key> |
826 | * <integer>...</integer> | | 827 | * <integer>...</integer> |
827 | * | | 828 | * |
828 | * <key>params</key> | | 829 | * <key>params</key> |
829 | * <string>...</string> | | 830 | * <string>...</string> |
830 | * </dict> | | 831 | * </dict> |
831 | * </array> | | 832 | * </array> |
832 | * | | 833 | * |
833 | */ | | 834 | */ |
834 | int | | 835 | int |
835 | dm_table_status_ioctl(prop_dictionary_t dm_dict) | | 836 | dm_table_status_ioctl(prop_dictionary_t dm_dict) |
836 | { | | 837 | { |
837 | dm_dev_t *dmv; | | 838 | dm_dev_t *dmv; |
838 | dm_table_t *tbl; | | 839 | dm_table_t *tbl; |
839 | dm_table_entry_t *table_en; | | 840 | dm_table_entry_t *table_en; |
840 | | | 841 | |
841 | prop_array_t cmd_array; | | 842 | prop_array_t cmd_array; |
842 | prop_dictionary_t target_dict; | | 843 | prop_dictionary_t target_dict; |
843 | | | 844 | |
844 | uint32_t rec_size, minor; | | 845 | uint32_t rec_size, minor; |
845 | | | 846 | |
846 | const char *name, *uuid; | | 847 | const char *name, *uuid; |
847 | char *params; | | 848 | char *params; |
848 | int flags; | | 849 | int flags; |
849 | int table_type; | | 850 | int table_type; |
850 | | | 851 | |
851 | dmv = NULL; | | 852 | dmv = NULL; |
852 | uuid = NULL; | | 853 | uuid = NULL; |
853 | name = NULL; | | 854 | name = NULL; |
854 | params = NULL; | | 855 | params = NULL; |
855 | flags = 0; | | 856 | flags = 0; |
856 | rec_size = 0; | | 857 | rec_size = 0; |
857 | | | 858 | |
858 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); | | 859 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name); |
859 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); | | 860 | prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid); |
860 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); | | 861 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags); |
861 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); | | 862 | prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor); |
862 | | | 863 | |
863 | cmd_array = prop_array_create(); | | 864 | cmd_array = prop_array_create(); |
864 | | | 865 | |
865 | if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { | | 866 | if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) { |
866 | DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG); | | 867 | DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG); |
867 | return ENOENT; | | 868 | return ENOENT; |
868 | } | | 869 | } |
869 | /* | | 870 | /* |
870 | * if DM_QUERY_INACTIVE_TABLE_FLAG is passed we need to query | | 871 | * if DM_QUERY_INACTIVE_TABLE_FLAG is passed we need to query |
871 | * INACTIVE TABLE | | 872 | * INACTIVE TABLE |
872 | */ | | 873 | */ |
873 | if (flags & DM_QUERY_INACTIVE_TABLE_FLAG) | | 874 | if (flags & DM_QUERY_INACTIVE_TABLE_FLAG) |
874 | table_type = DM_TABLE_INACTIVE; | | 875 | table_type = DM_TABLE_INACTIVE; |
875 | else | | 876 | else |
876 | table_type = DM_TABLE_ACTIVE; | | 877 | table_type = DM_TABLE_ACTIVE; |
877 | | | 878 | |
878 | if (dm_table_get_target_count(&dmv->table_head, DM_TABLE_ACTIVE)) | | 879 | if (dm_table_get_target_count(&dmv->table_head, DM_TABLE_ACTIVE)) |
879 | DM_ADD_FLAG(flags, DM_ACTIVE_PRESENT_FLAG); | | 880 | DM_ADD_FLAG(flags, DM_ACTIVE_PRESENT_FLAG); |
880 | else { | | 881 | else { |
881 | DM_REMOVE_FLAG(flags, DM_ACTIVE_PRESENT_FLAG); | | 882 | DM_REMOVE_FLAG(flags, DM_ACTIVE_PRESENT_FLAG); |
882 | | | 883 | |
883 | if (dm_table_get_target_count(&dmv->table_head, DM_TABLE_INACTIVE)) | | 884 | if (dm_table_get_target_count(&dmv->table_head, DM_TABLE_INACTIVE)) |
884 | DM_ADD_FLAG(flags, DM_INACTIVE_PRESENT_FLAG); | | 885 | DM_ADD_FLAG(flags, DM_INACTIVE_PRESENT_FLAG); |
885 | else { | | 886 | else { |
886 | DM_REMOVE_FLAG(flags, DM_INACTIVE_PRESENT_FLAG); | | 887 | DM_REMOVE_FLAG(flags, DM_INACTIVE_PRESENT_FLAG); |
887 | } | | 888 | } |
888 | } | | 889 | } |
889 | | | 890 | |
890 | if (dmv->flags & DM_SUSPEND_FLAG) | | 891 | if (dmv->flags & DM_SUSPEND_FLAG) |
891 | DM_ADD_FLAG(flags, DM_SUSPEND_FLAG); | | 892 | DM_ADD_FLAG(flags, DM_SUSPEND_FLAG); |
892 | | | 893 | |
893 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); | | 894 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor); |
894 | | | 895 | |
895 | aprint_debug("Status of device tables: %s--%d\n", | | 896 | aprint_debug("Status of device tables: %s--%d\n", |
896 | name, dmv->table_head.cur_active_table); | | 897 | name, dmv->table_head.cur_active_table); |
897 | | | 898 | |
898 | tbl = dm_table_get_entry(&dmv->table_head, table_type); | | 899 | tbl = dm_table_get_entry(&dmv->table_head, table_type); |
899 | | | 900 | |
900 | SLIST_FOREACH(table_en, tbl, next) { | | 901 | SLIST_FOREACH(table_en, tbl, next) { |
901 | target_dict = prop_dictionary_create(); | | 902 | target_dict = prop_dictionary_create(); |
902 | aprint_debug("%016" PRIu64 ", length %016" PRIu64 | | 903 | aprint_debug("%016" PRIu64 ", length %016" PRIu64 |
903 | ", target %s\n", table_en->start, table_en->length, | | 904 | ", target %s\n", table_en->start, table_en->length, |
904 | table_en->target->name); | | 905 | table_en->target->name); |
905 | | | 906 | |
906 | prop_dictionary_set_uint64(target_dict, DM_TABLE_START, | | 907 | prop_dictionary_set_uint64(target_dict, DM_TABLE_START, |
907 | table_en->start); | | 908 | table_en->start); |
908 | prop_dictionary_set_uint64(target_dict, DM_TABLE_LENGTH, | | 909 | prop_dictionary_set_uint64(target_dict, DM_TABLE_LENGTH, |
909 | table_en->length); | | 910 | table_en->length); |
910 | | | 911 | |
911 | prop_dictionary_set_cstring(target_dict, DM_TABLE_TYPE, | | 912 | prop_dictionary_set_cstring(target_dict, DM_TABLE_TYPE, |
912 | table_en->target->name); | | 913 | table_en->target->name); |
913 | | | 914 | |
914 | /* dm_table_get_cur_actv.table ?? */ | | 915 | /* dm_table_get_cur_actv.table ?? */ |
915 | prop_dictionary_set_int32(target_dict, DM_TABLE_STAT, | | 916 | prop_dictionary_set_int32(target_dict, DM_TABLE_STAT, |
916 | dmv->table_head.cur_active_table); | | 917 | dmv->table_head.cur_active_table); |
917 | | | 918 | |
918 | if (flags & DM_STATUS_TABLE_FLAG) { | | 919 | if (flags & DM_STATUS_TABLE_FLAG) { |
919 | params = table_en->target->status | | 920 | params = table_en->target->status |
920 | (table_en->target_config); | | 921 | (table_en->target_config); |
921 | | | 922 | |
922 | if (params != NULL) { | | 923 | if (params != NULL) { |
923 | prop_dictionary_set_cstring(target_dict, | | 924 | prop_dictionary_set_cstring(target_dict, |
924 | DM_TABLE_PARAMS, params); | | 925 | DM_TABLE_PARAMS, params); |
925 | | | 926 | |
926 | kmem_free(params, DM_MAX_PARAMS_SIZE); | | 927 | kmem_free(params, DM_MAX_PARAMS_SIZE); |
927 | } | | 928 | } |
928 | } | | 929 | } |
929 | prop_array_add(cmd_array, target_dict); | | 930 | prop_array_add(cmd_array, target_dict); |
930 | prop_object_release(target_dict); | | 931 | prop_object_release(target_dict); |
931 | } | | 932 | } |
932 | | | 933 | |
933 | dm_table_release(&dmv->table_head, table_type); | | 934 | dm_table_release(&dmv->table_head, table_type); |
934 | dm_dev_unbusy(dmv); | | 935 | dm_dev_unbusy(dmv); |
935 | | | 936 | |
936 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_FLAGS, flags); | | 937 | prop_dictionary_set_uint32(dm_dict, DM_IOCTL_FLAGS, flags); |
937 | prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, cmd_array); | | 938 | prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, cmd_array); |
938 | prop_object_release(cmd_array); | | 939 | prop_object_release(cmd_array); |
939 | | | 940 | |
940 | return 0; | | 941 | return 0; |
941 | } | | 942 | } |
942 | | | 943 | |
943 | | | 944 | |
944 | /* | | 945 | /* |
945 | * For every call I have to set kernel driver version. | | 946 | * For every call I have to set kernel driver version. |
946 | * Because I can have commands supported only in other | | 947 | * Because I can have commands supported only in other |
947 | * newer/later version. This routine is called for every | | 948 | * newer/later version. This routine is called for every |
948 | * ioctl command. | | 949 | * ioctl command. |
949 | */ | | 950 | */ |
950 | int | | 951 | int |
951 | dm_check_version(prop_dictionary_t dm_dict) | | 952 | dm_check_version(prop_dictionary_t dm_dict) |
952 | { | | 953 | { |
953 | size_t i; | | 954 | size_t i; |
954 | int dm_version[3]; | | 955 | int dm_version[3]; |
955 | prop_array_t ver; | | 956 | prop_array_t ver; |
956 | | | 957 | |
957 | ver = prop_dictionary_get(dm_dict, DM_IOCTL_VERSION); | | 958 | ver = prop_dictionary_get(dm_dict, DM_IOCTL_VERSION); |
958 | | | 959 | |
959 | for (i = 0; i < 3; i++) | | 960 | for (i = 0; i < 3; i++) |
960 | prop_array_get_uint32(ver, i, &dm_version[i]); | | 961 | prop_array_get_uint32(ver, i, &dm_version[i]); |
961 | | | 962 | |
962 | if (DM_VERSION_MAJOR != dm_version[0] || DM_VERSION_MINOR < dm_version[1]) { | | 963 | if (DM_VERSION_MAJOR != dm_version[0] || DM_VERSION_MINOR < dm_version[1]) { |
963 | aprint_debug("libdevmapper/kernel version mismatch " | | 964 | aprint_debug("libdevmapper/kernel version mismatch " |
964 | "kernel: %d.%d.%d libdevmapper: %d.%d.%d\n", | | 965 | "kernel: %d.%d.%d libdevmapper: %d.%d.%d\n", |
965 | DM_VERSION_MAJOR, DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL, | | 966 | DM_VERSION_MAJOR, DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL, |
966 | dm_version[0], dm_version[1], dm_version[2]); | | 967 | dm_version[0], dm_version[1], dm_version[2]); |
967 | | | 968 | |
968 | return EIO; | | 969 | return EIO; |
969 | } | | 970 | } |
970 | prop_array_set_uint32(ver, 0, DM_VERSION_MAJOR); | | 971 | prop_array_set_uint32(ver, 0, DM_VERSION_MAJOR); |
971 | prop_array_set_uint32(ver, 1, DM_VERSION_MINOR); | | 972 | prop_array_set_uint32(ver, 1, DM_VERSION_MINOR); |
972 | prop_array_set_uint32(ver, 2, DM_VERSION_PATCHLEVEL); | | 973 | prop_array_set_uint32(ver, 2, DM_VERSION_PATCHLEVEL); |
973 | | | 974 | |
974 | prop_dictionary_set(dm_dict, DM_IOCTL_VERSION, ver); | | 975 | prop_dictionary_set(dm_dict, DM_IOCTL_VERSION, ver); |
975 | | | 976 | |
976 | return 0; | | 977 | return 0; |
977 | } | | 978 | } |