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