dm_ioctl.c revision 1.1.2.2 1 /*
2 * Copyright (c) 1996, 1997, 1998, 1999, 2002 The NetBSD Foundation, Inc.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to The NetBSD Foundation
6 * by Adam Hamsik.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include <sys/types.h>
31 #include <sys/param.h>
32
33 #include <sys/errno.h>
34 #include <sys/ioctl.h>
35 #include <sys/ioccom.h>
36 #include <sys/kmem.h>
37 #include <sys/lkm.h>
38 #include <sys/namei.h>
39 #include <sys/vnode.h>
40
41 #include <miscfs/specfs/specdev.h>
42
43 #include <machine/int_fmtio.h>
44
45 #include "netbsd-dm.h"
46 #include "dm.h"
47
48 extern struct dm_softc *dm_sc;
49
50 #define DM_REMOVE_FLAG(flag, name) do { \
51 prop_dictionary_get_uint32(dm_dict,DM_IOCTL_FLAGS,&flag); \
52 flag &= ~name; \
53 prop_dictionary_set_uint32(dm_dict,DM_IOCTL_FLAGS,flag); \
54 } while (/*CONSTCOND*/0)
55
56 #define DM_ADD_FLAG(flag, name) do { \
57 prop_dictionary_get_uint32(dm_dict,DM_IOCTL_FLAGS,&flag); \
58 flag |= name; \
59 prop_dictionary_set_uint32(dm_dict,DM_IOCTL_FLAGS,flag); \
60 } while (/*CONSTCOND*/0)
61
62 static int dm_dbg_print_flags(int);
63
64 /*
65 * Print flags sent to the kernel from libevmapper.
66 */
67 static int
68 dm_dbg_print_flags(int flags)
69 {
70 aprint_verbose("dbg_print --- %d\n",flags);
71
72 if (flags & DM_READONLY_FLAG)
73 aprint_verbose("dbg_flags: DM_READONLY_FLAG set In/Out\n");
74
75 if (flags & DM_SUSPEND_FLAG)
76 aprint_verbose("dbg_flags: DM_SUSPEND_FLAG set In/Out \n");
77
78 if (flags & DM_PERSISTENT_DEV_FLAG)
79 aprint_verbose("dbg_flags: DM_PERSISTENT_DEV_FLAG set In\n");
80
81 if (flags & DM_STATUS_TABLE_FLAG)
82 aprint_verbose("dbg_flags: DM_STATUS_TABLE_FLAG set In\n");
83
84 if (flags & DM_ACTIVE_PRESENT_FLAG)
85 aprint_verbose("dbg_flags: DM_ACTIVE_PRESENT_FLAG set Out\n");
86
87 if (flags & DM_INACTIVE_PRESENT_FLAG)
88 aprint_verbose("dbg_flags: DM_INACTIVE_PRESENT_FLAG set Out\n");
89
90 if (flags & DM_BUFFER_FULL_FLAG)
91 aprint_verbose("dbg_flags: DM_BUFFER_FULL_FLAG set Out\n");
92
93 if (flags & DM_SKIP_BDGET_FLAG)
94 aprint_verbose("dbg_flags: DM_SKIP_BDGET_FLAG set In\n");
95
96 if (flags & DM_SKIP_LOCKFS_FLAG)
97 aprint_verbose("dbg_flags: DM_SKIP_LOCKFS_FLAG set In\n");
98
99 if (flags & DM_NOFLUSH_FLAG)
100 aprint_verbose("dbg_flags: DM_NOFLUSH_FLAG set In\n");
101
102 return 0;
103 }
104
105 /*
106 * Get version ioctl call I do it as default therefore this
107 * function is unused now.
108 */
109 int
110 dm_get_version_ioctl(prop_dictionary_t dm_dict)
111 {
112 int r;
113
114 r = 0;
115
116 aprint_verbose("dm_get_version_ioctl called\n");
117
118 return 0;
119 }
120
121 /*
122 * Get list of all available targets from global
123 * target list and sent them back to libdevmapper.
124 */
125 int
126 dm_list_versions_ioctl(prop_dictionary_t dm_dict)
127 {
128 prop_array_t target_list;
129
130 int r;
131 uint32_t flags;
132
133 r = 0;
134
135 aprint_verbose("dm_list_versions_ioctl called\n");
136
137 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
138
139 dm_dbg_print_flags(flags);
140
141 target_list = dm_target_prop_list();
142
143 prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, target_list);
144
145 return r;
146 }
147
148 /*
149 * Create in-kernel entry for device. Device attributes such as name, uuid are
150 * taken from proplib dictionary.
151 */
152 int
153 dm_dev_create_ioctl(prop_dictionary_t dm_dict)
154 {
155 struct dm_dev *dmv;
156 const char *name, *uuid;
157 int r,flags;
158
159 r = 0;
160 flags = 0;
161 name = NULL;
162 uuid = NULL;
163
164 /* Get needed values from dictionary. */
165 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
166 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
167 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
168
169 dm_dbg_print_flags(flags);
170
171 /* Lookup name and uuid if device already exist quit. */
172 if ((dm_dev_lookup_name(name) != NULL) &&
173 (dm_dev_lookup_uuid(uuid) != NULL)) {
174 DM_ADD_FLAG(flags, DM_EXISTS_FLAG); /* Device already exists */
175 return EEXIST;
176 }
177
178
179 if ((dmv = dm_dev_alloc()) == NULL)
180 return ENOMEM;
181 /* printf("%d---%d\n",sizeof(dmv->uuid),DM_UUID_LEN);
182 printf("%s\n",uuid);
183 if (uuid)
184 memcpy(dmv->uuid,uuid,DM_UUID_LEN);*/
185 printf("%s\n",name);
186 if (name)
187 strlcpy(dmv->name, name, DM_NAME_LEN);
188
189 dmv->flags = flags;
190
191 dmv->minor = ++(dm_sc->sc_minor_num);
192
193 dmv->ref_cnt = 0;
194 dmv->event_nr = 0;
195 dmv->cur_active_table = 0;
196
197 /* Initialize tables. */
198 SLIST_INIT(&dmv->tables[0]);
199 SLIST_INIT(&dmv->tables[1]);
200
201 /* init device list of physical devices. */
202 SLIST_INIT(&dmv->pdevs);
203 /*
204 * Locking strategy here is this: this is per device mutex lock
205 * and it should be taken when we work with device. Almost all
206 * ioctl callbacks for tables and devices must acquire this lock.
207 */
208
209 prop_dictionary_set_uint64(dm_dict, DM_IOCTL_DEV, dmv->minor);
210
211 mutex_init(&dmv->dev_mtx, MUTEX_DEFAULT, IPL_NONE);
212
213 /* Test readonly flag change anything only if it is not set*/
214 if (flags & DM_READONLY_FLAG)
215 dm_dev_free(dmv);
216 else
217 r = dm_dev_insert(dmv);
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 int
241 dm_dev_list_ioctl(prop_dictionary_t dm_dict)
242 {
243 prop_array_t dev_list;
244
245 int r;
246 uint32_t flags;
247
248 r = 0;
249
250 aprint_verbose("dm_dev_list called\n");
251
252 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
253
254 dm_dbg_print_flags(flags);
255
256 dev_list = dm_dev_prop_list();
257
258 prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, dev_list);
259
260 return 0;
261 }
262
263 /*
264 * Rename selected devices old name is in struct dm_ioctl.
265 * newname is taken from dictionary
266 *
267 * <key>cmd_data</key>
268 * <array>
269 * <string>...</string>
270 * </array>
271 */
272 int
273 dm_dev_rename_ioctl(prop_dictionary_t dm_dict)
274 {
275 prop_array_t cmd_array;
276 struct dm_dev *dmv;
277
278 const char *name,*uuid,*n_name;
279 uint32_t flags;
280
281 name = NULL;
282 uuid = NULL;
283
284 /* Get needed values from dictionary. */
285 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
286 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
287 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
288 cmd_array = prop_dictionary_get(dm_dict, DM_IOCTL_CMD_DATA);
289
290 prop_array_get_cstring_nocopy(cmd_array, 0, &n_name);
291
292 if (strlen(n_name) + 1 > DM_NAME_LEN)
293 return EINVAL;
294
295 if (((dmv = dm_dev_lookup_uuid(uuid)) == NULL) ||
296 (dmv = dm_dev_lookup_name(name)) == NULL) {
297 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
298 return ENOENT;
299 }
300
301 /* Test readonly flag change anything only if it is not set*/
302 if (!(flags & DM_READONLY_FLAG))
303 strlcpy(dmv->name, n_name, DM_NAME_LEN);
304
305 return 0;
306 }
307
308 /*
309 * Remove device from global list I have to remove active
310 * and inactive tables first and decrement reference_counters
311 * for used pdevs.
312 */
313 int
314 dm_dev_remove_ioctl(prop_dictionary_t dm_dict)
315 {
316 struct dm_dev *dmv;
317
318 const char *name, *uuid;
319 uint32_t flags;
320
321 name = NULL;
322 uuid = NULL;
323
324 /* Get needed values from dictionary. */
325 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
326 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
327 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
328
329 dm_dbg_print_flags(flags);
330
331 if (((dmv = dm_dev_lookup_uuid(uuid)) == NULL) &&
332 (dmv = dm_dev_lookup_name(name)) == NULL) {
333 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
334 return ENOENT;
335 }
336
337 if (!(flags & DM_READONLY_FLAG)) {
338 if (dmv->ref_cnt == 0){
339 /* Destroy active table first. */
340 dm_table_destroy(&dmv->tables[dmv->cur_active_table]);
341
342 /* Destroy unactive table if exits, too. */
343 if (!SLIST_EMPTY(&dmv->tables[1 - dmv->cur_active_table]))
344 dm_table_destroy(&dmv->tables[1 - dmv->cur_active_table]);
345
346 /* Decrement reference counters for all pdevs from this
347 device if they are unused close vnode and remove them
348 from global pdev list, too. */
349 dm_pdev_decr(&dmv->pdevs);
350
351 /* Test readonly flag change anything only if it is not set*/
352
353 dm_dev_rem(name); /* XXX. try to use uuid, too */
354 }
355
356 }
357 return 0;
358 }
359
360 /*
361 * Return actual state of device to libdevmapper.
362 */
363 int
364 dm_dev_status_ioctl(prop_dictionary_t dm_dict)
365 {
366 struct dm_dev *dmv;
367 const char *name, *uuid;
368 uint32_t flags;
369
370 name = NULL;
371 uuid = NULL;
372
373 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
374 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
375 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
376
377 if (((dmv = dm_dev_lookup_name(name)) == NULL) &&
378 ((dmv = dm_dev_lookup_uuid(uuid)) == NULL)) {
379 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
380 return 0;
381 }
382
383 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->ref_cnt);
384 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_FLAGS, dmv->flags);
385
386 prop_dictionary_set_uint64(dm_dict, DM_IOCTL_DEV, dmv->minor);
387
388 return 0;
389 }
390
391 /*
392 * Unsupported on NetBSD.
393 */
394 int
395 dm_dev_suspend_ioctl(prop_dictionary_t dm_dict)
396 {
397 return 0;
398 }
399
400 /*
401 * Unsupported on NetBSD.
402 */
403 int
404 dm_dev_resume_ioctl(prop_dictionary_t dm_dict)
405 {
406 // DM_ADD_FLAG(flags, DM_ACTIVE_PRESENT_FLAG);
407
408 return 0;
409 }
410
411 /*
412 * Table management routines
413 * lvm2tools doens't send name/uuid to kernel with table for lookup I have to use minor number.
414 */
415
416
417 /*
418 * Remove active table from device.
419 */
420 int
421 dm_table_clear_ioctl(prop_dictionary_t dm_dict)
422 {
423 struct dm_dev *dmv;
424 struct dm_table *tbl;
425
426 const char *name, *uuid;
427 int flags;
428
429 dmv = NULL;
430 name = NULL;
431 uuid = NULL;
432
433 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
434 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
435 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
436
437 aprint_verbose("Clearing inactive table from device: %s--%s\n",
438 name, uuid);
439
440 if (((dmv = dm_dev_lookup_name(name)) == NULL) &&
441 ((dmv = dm_dev_lookup_uuid(uuid)) == NULL)) {
442 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
443 return ENOENT;
444 }
445
446 /* Select unused table */
447 tbl = &dmv->tables[1-dmv->cur_active_table];
448
449 /* Test readonly flag change anything only if it is not set*/
450 if (!(flags & DM_READONLY_FLAG))
451 dm_table_destroy(tbl);
452
453 return 0;
454 }
455
456 /*
457 * Get list of physical devices for active table.
458 * Get dev_t from pdev vnode and insert it into cmd_array.
459 *
460 * XXX. This function is called from lvm2tools to get information
461 * about physical devices, too e.g. during vgcreate.
462 */
463 int
464 dm_table_deps_ioctl(prop_dictionary_t dm_dict)
465 {
466 int error;
467 struct dm_dev *dmv;
468 struct dm_pdev *dmp;
469 struct vattr va;
470
471 prop_array_t cmd_array;
472
473 const char *name, *uuid;
474 int flags;
475 uint64_t dev;
476
477 size_t i;
478
479 name = NULL;
480 uuid = NULL;
481 dmv = NULL;
482
483 i=0;
484
485 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
486 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
487 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
488 prop_dictionary_get_uint64(dm_dict, DM_IOCTL_DEV, &dev);
489
490 cmd_array = prop_dictionary_get(dm_dict,DM_IOCTL_CMD_DATA);
491
492 if (((dmv = dm_dev_lookup_name(name)) == NULL) &&
493 ((dmv = dm_dev_lookup_uuid(uuid)) == NULL) &&
494 ((dmv = dm_dev_lookup_minor(minor(dev))) == NULL)) {
495 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
496 return ENOENT;
497 }
498
499 aprint_verbose("Getting table deps for device: %s\n",name);
500
501 SLIST_FOREACH(dmp, &dmv->pdevs, next_pdev){
502
503 if ((error = VOP_GETATTR(dmp->pdev_vnode, &va, curlwp->l_cred))
504 != 0)
505 return (error);
506
507 prop_array_set_uint64(cmd_array, i, (uint64_t)va.va_rdev);
508
509 i++;
510 }
511
512 return 0;
513 }
514
515 /*
516 * Load new table/tables to device.
517 * Call apropriate target init routine open all physical pdev's and
518 * link them to device. For other targets mirror, strip, snapshot
519 * etc. also add dependency devices to upcalls list.
520 *
521 * XXX. It would be usefull to refactorize this routine to be shorter ?
522 */
523 int
524 dm_table_load_ioctl(prop_dictionary_t dm_dict)
525 {
526 struct dm_dev *dmv;
527 struct dm_pdev *dmp;
528 struct dm_table_entry *table_en, *last_table;
529 struct dm_table *tbl;
530 struct dm_target *target;
531
532 prop_object_iterator_t iter;
533 prop_array_t cmd_array;
534 prop_dictionary_t target_dict;
535
536 const char *name, *uuid, *type, *str_ptr;
537
538 uint32_t flags;
539
540 uint64_t dev;
541
542 char *dev_name,*str;
543
544 flags = 0;
545 name = NULL;
546 uuid = NULL;
547 dmv = NULL;
548 dmp = NULL;
549 last_table = NULL;
550 str_ptr = NULL;
551
552 char *xml;
553 xml = prop_dictionary_externalize(dm_dict);
554 printf("%s\n",xml);
555
556 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
557 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
558 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
559 prop_dictionary_get_uint64(dm_dict, DM_IOCTL_DEV, &dev);
560
561 cmd_array = prop_dictionary_get(dm_dict, DM_IOCTL_CMD_DATA);
562 iter = prop_array_iterator(cmd_array);
563
564 dm_dbg_print_flags(flags);
565
566 aprint_verbose("Loading table to device: %s--%s\n",name,uuid);
567
568 if (((dmv = dm_dev_lookup_name(name)) == NULL) &&
569 ((dmv = dm_dev_lookup_uuid(uuid)) == NULL) &&
570 ((dmv = dm_dev_lookup_minor(minor(dev))) == NULL)) {
571 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
572 return ENOENT;
573 }
574
575 /* Select unused table */
576 tbl = &dmv->tables[1-dmv->cur_active_table];
577
578 /*
579 * I have to check if this table slot is not used by another table list.
580 * if it is used I should free them.
581 */
582
583 dm_table_destroy(tbl);
584
585 while((target_dict = prop_object_iterator_next(iter)) != NULL){
586
587 prop_dictionary_get_cstring_nocopy(target_dict,
588 DM_TABLE_TYPE, &type);
589
590 /*
591 * If we want to deny table with 2 or more different
592 * target we should do it here
593 */
594 if ((target = dm_target_lookup_name(type)) == NULL)
595 return ENOENT;
596
597 if ((table_en=kmem_alloc(sizeof(struct dm_table_entry),
598 KM_NOSLEEP)) == NULL)
599 return ENOMEM;
600
601 prop_dictionary_get_uint64(target_dict, DM_TABLE_START,
602 &table_en->start);
603 prop_dictionary_get_uint64(target_dict, DM_TABLE_LENGTH,
604 &table_en->length);
605
606 table_en->target=target;
607 table_en->dm_dev=dmv;
608
609 /*
610 * There is a parameter string after dm_target_spec
611 * structure which points to /dev/wd0a 284 part of
612 * table. String str points to this text.
613 */
614
615 prop_dictionary_get_cstring_nocopy(target_dict,
616 DM_TABLE_PARAMS, (const char**)&str);
617
618 if (strlen(str) != 0) {
619
620 str_ptr = str; /* save pointer to start of string */
621
622 aprint_verbose("trg_str: %s\n", str);
623
624 dev_name = strsep(&str," ");
625
626 aprint_verbose("namei: %s, str: %s\n", dev_name, str);
627
628 if (!(flags & DM_READONLY_FLAG)){
629
630 if ((dmp = dm_pdev_insert(dev_name)) == NULL){
631 kmem_free(table_en,
632 sizeof(struct dm_table_entry));
633 return ENOENT;
634 }
635
636 /* insert pdev to device list */
637 SLIST_INSERT_HEAD(&dmv->pdevs, dmp, next_pdev);
638 }
639 }
640
641 /* Test readonly flag change anything only if it is not set*/
642 if (!(flags & DM_READONLY_FLAG)){
643
644 if (SLIST_EMPTY(tbl))
645 /* insert this table to head */
646 SLIST_INSERT_HEAD(tbl, table_en, next);
647 else
648 SLIST_INSERT_AFTER(last_table, table_en, next);
649
650 prop_dictionary_get_cstring(target_dict,
651 DM_TABLE_PARAMS, (char **)&table_en->params);
652
653 /*
654 * XXX I have to calculate argc
655 */
656 if (target->init != NULL)
657 target->init(dmv, &table_en->target_config,
658 2, &str_ptr);
659
660 last_table = table_en;
661
662 } else {
663 kmem_free(table_en, sizeof(struct dm_table_entry));
664 dm_pdev_destroy(dmp);
665 }
666
667 }
668
669 dmv->cur_active_table = 1 - dmv->cur_active_table;
670
671 prop_object_release(cmd_array);
672
673 DM_ADD_FLAG(flags, DM_INACTIVE_PRESENT_FLAG);
674
675 return 0;
676 }
677
678 /*
679 * Get description of all tables loaded to device from kernel
680 * and send it to libdevmapper.
681 *
682 * Output dictionary for every table:
683 *
684 * <key>cmd_data</key>
685 * <array>
686 * <dict>
687 * <key>type<key>
688 * <string>...</string>
689 *
690 * <key>start</key>
691 * <integer>...</integer>
692 *
693 * <key>length</key>
694 * <integer>...</integer>
695 *
696 * <key>params</key>
697 * <string>...</string>
698 * </dict>
699 * </array>
700 *
701 */
702 int
703 dm_table_status_ioctl(prop_dictionary_t dm_dict)
704 {
705 struct dm_dev *dmv;
706 struct dm_table *tbl;
707 struct dm_table_entry *table_en;
708
709 prop_array_t cmd_array;
710 prop_dictionary_t target_dict;
711
712 uint32_t rec_size;
713 uint64_t dev;
714
715 const char *name, *uuid;
716 int flags,i;
717
718 dmv = NULL;
719 uuid = NULL;
720 name = NULL;
721
722 flags = 0;
723 rec_size = 0;
724 i=0;
725
726 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
727 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
728 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
729 prop_dictionary_get_uint64(dm_dict, DM_IOCTL_DEV, &dev);
730
731 cmd_array = prop_dictionary_get(dm_dict, DM_IOCTL_CMD_DATA);
732
733 if (((dmv = dm_dev_lookup_name(name)) == NULL) &&
734 ((dmv = dm_dev_lookup_uuid(uuid)) == NULL) &&
735 ((dmv = dm_dev_lookup_minor(minor(dev)))) == NULL) {
736 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
737 return ENOENT;
738 }
739
740 aprint_verbose("Status of device tables: %s--%d\n",
741 name, dmv->cur_active_table);
742
743 tbl = &dmv->tables[dmv->cur_active_table];
744
745 SLIST_FOREACH(table_en,tbl,next)
746 {
747 target_dict = prop_dictionary_create();
748 aprint_verbose("%016" PRIu64 ", length %016" PRIu64
749 ", target %s\n", table_en->start, table_en->length,
750 table_en->target->name);
751
752 prop_dictionary_set_uint64(target_dict, DM_TABLE_START,
753 table_en->start);
754 prop_dictionary_set_uint64(target_dict, DM_TABLE_LENGTH,
755 table_en->length);
756
757 prop_dictionary_set_cstring(target_dict, DM_TABLE_TYPE,
758 table_en->target->name);
759 prop_dictionary_set_cstring(target_dict, DM_TABLE_PARAMS,
760 table_en->params);
761
762 prop_dictionary_set_int32(target_dict, DM_TABLE_STAT,
763 dmv->cur_active_table);
764
765 prop_array_set(cmd_array, i, target_dict);
766
767 prop_object_release(target_dict);
768
769 DM_REMOVE_FLAG(flags, DM_ACTIVE_PRESENT_FLAG);
770
771 i++;
772 }
773
774 return 0;
775 }
776
777
778 /*
779 * For every call I have to set kernel driver version.
780 * Because I can have commands supported only in other
781 * newer/later version. This routine is called for every
782 * ioctl command.
783 */
784 int
785 dm_check_version(prop_dictionary_t dm_dict)
786 {
787 size_t i;
788 int dm_version[3];
789 prop_array_t ver;
790 int r;
791
792 r = 0;
793
794 ver = prop_dictionary_get(dm_dict, DM_IOCTL_VERSION);
795
796 for(i=0; i < 3; i++)
797 prop_array_get_uint32(ver, i, &dm_version[i]);
798
799
800 if (DM_VERSION_MAJOR != dm_version[0] ||
801 DM_VERSION_MINOR < dm_version[1])
802 {
803 aprint_verbose("libdevmapper/kernel version mismatch "
804 "kernel: %d.%d.%d libdevmapper: %d.%d.%d\n",
805 DM_VERSION_MAJOR, DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL,
806 dm_version[0], dm_version[1], dm_version[2]);
807
808 r = EIO;
809 goto out;
810 }
811
812 prop_array_set_uint32(ver, 0, DM_VERSION_MAJOR);
813 prop_array_set_uint32(ver, 1, DM_VERSION_MINOR);
814 prop_array_set_uint32(ver, 2, DM_VERSION_PATCHLEVEL);
815
816 out:
817 return r;
818 }
819