dm_ioctl.c revision 1.1.2.5 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_normal("dbg_print --- %d\n",flags);
71
72 if (flags & DM_READONLY_FLAG)
73 aprint_normal("dbg_flags: DM_READONLY_FLAG set In/Out\n");
74
75 if (flags & DM_SUSPEND_FLAG)
76 aprint_normal("dbg_flags: DM_SUSPEND_FLAG set In/Out \n");
77
78 if (flags & DM_PERSISTENT_DEV_FLAG)
79 aprint_normal("db_flags: DM_PERSISTENT_DEV_FLAG set In\n");
80
81 if (flags & DM_STATUS_TABLE_FLAG)
82 aprint_normal("dbg_flags: DM_STATUS_TABLE_FLAG set In\n");
83
84 if (flags & DM_ACTIVE_PRESENT_FLAG)
85 aprint_normal("dbg_flags: DM_ACTIVE_PRESENT_FLAG set Out\n");
86
87 if (flags & DM_INACTIVE_PRESENT_FLAG)
88 aprint_normal("dbg_flags: DM_INACTIVE_PRESENT_FLAG set Out\n");
89
90 if (flags & DM_BUFFER_FULL_FLAG)
91 aprint_normal("dbg_flags: DM_BUFFER_FULL_FLAG set Out\n");
92
93 if (flags & DM_SKIP_BDGET_FLAG)
94 aprint_normal("dbg_flags: DM_SKIP_BDGET_FLAG set In\n");
95
96 if (flags & DM_SKIP_LOCKFS_FLAG)
97 aprint_normal("dbg_flags: DM_SKIP_LOCKFS_FLAG set In\n");
98
99 if (flags & DM_NOFLUSH_FLAG)
100 aprint_normal("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 flags = 0;
134 r = 0;
135
136 aprint_verbose("dm_list_versions_ioctl called\n");
137
138 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
139
140 dm_dbg_print_flags(flags);
141
142 target_list = dm_target_prop_list();
143
144 prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, target_list);
145
146 return r;
147 }
148
149 /*
150 * Create in-kernel entry for device. Device attributes such as name, uuid are
151 * taken from proplib dictionary.
152 */
153 int
154 dm_dev_create_ioctl(prop_dictionary_t dm_dict)
155 {
156 struct dm_dev *dmv;
157 const char *name, *uuid;
158 int r,flags;
159
160 r = 0;
161 flags = 0;
162 name = NULL;
163 uuid = NULL;
164
165 /* Get needed values from dictionary. */
166 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
167 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
168 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
169
170 dm_dbg_print_flags(flags);
171
172 /* Lookup name and uuid if device already exist quit. */
173 if ((dm_dev_lookup_name(name) != NULL) &&
174 (dm_dev_lookup_uuid(uuid) != NULL)) {
175 DM_ADD_FLAG(flags, DM_EXISTS_FLAG); /* Device already exists */
176 return EEXIST;
177 }
178
179
180 if ((dmv = dm_dev_alloc()) == NULL)
181 return ENOMEM;
182 /* printf("%d---%d\n",sizeof(dmv->uuid),DM_UUID_LEN);
183 printf("%s\n",uuid);
184 if (uuid)
185 memcpy(dmv->uuid,uuid,DM_UUID_LEN);*/
186 printf("%s\n",name);
187 if (name)
188 strlcpy(dmv->name, name, DM_NAME_LEN);
189
190 dmv->flags = flags;
191
192 dmv->minor = ++(dm_sc->sc_minor_num);
193
194 dmv->ref_cnt = 0;
195 dmv->event_nr = 0;
196 dmv->cur_active_table = 0;
197
198 dmv->dev_type = 0;
199 dmv->dm_dklabel = NULL;
200
201 /* Initialize tables. */
202 SLIST_INIT(&dmv->tables[0]);
203 SLIST_INIT(&dmv->tables[1]);
204
205 /* init device list of physical devices. */
206 SLIST_INIT(&dmv->pdevs);
207 /*
208 * Locking strategy here is this: this is per device mutex lock
209 * and it should be taken when we work with device. Almost all
210 * ioctl callbacks for tables and devices must acquire this lock.
211 */
212
213 prop_dictionary_set_uint64(dm_dict, DM_IOCTL_DEV, dmv->minor);
214
215 mutex_init(&dmv->dev_mtx, MUTEX_DEFAULT, IPL_NONE);
216
217 /* Test readonly flag change anything only if it is not set*/
218 if (flags & DM_READONLY_FLAG)
219 dm_dev_free(dmv);
220 else {
221 r = dm_dev_insert(dmv);
222 DM_ADD_FLAG(flags, DM_EXISTS_FLAG);
223 }
224
225
226 return r;
227 }
228
229 /*
230 * Get list of created device-mapper devices fromglobal list and
231 * send it to kernel.
232 *
233 * Output dictionary:
234 *
235 * <key>cmd_data</key>
236 * <array>
237 * <dict>
238 * <key>name<key>
239 * <string>...</string>
240 *
241 * <key>dev</key>
242 * <integer>...</integer>
243 * </dict>
244 * </array>
245 *
246 */
247 int
248 dm_dev_list_ioctl(prop_dictionary_t dm_dict)
249 {
250 prop_array_t dev_list;
251
252 int r;
253 uint32_t flags;
254
255 r = 0;
256 flags = 0;
257
258 aprint_verbose("dm_dev_list called\n");
259
260 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
261
262 dm_dbg_print_flags(flags);
263
264 dev_list = dm_dev_prop_list();
265
266 prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, dev_list);
267
268 return 0;
269 }
270
271 /*
272 * Rename selected devices old name is in struct dm_ioctl.
273 * newname is taken from dictionary
274 *
275 * <key>cmd_data</key>
276 * <array>
277 * <string>...</string>
278 * </array>
279 */
280 int
281 dm_dev_rename_ioctl(prop_dictionary_t dm_dict)
282 {
283 prop_array_t cmd_array;
284 struct dm_dev *dmv;
285
286 const char *name,*uuid,*n_name;
287 uint32_t flags;
288
289 name = NULL;
290 uuid = NULL;
291
292 /* Get needed values from dictionary. */
293 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
294 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
295 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
296 cmd_array = prop_dictionary_get(dm_dict, DM_IOCTL_CMD_DATA);
297
298 prop_array_get_cstring_nocopy(cmd_array, 0, &n_name);
299
300 if (strlen(n_name) + 1 > DM_NAME_LEN)
301 return EINVAL;
302
303 if (((dmv = dm_dev_lookup_uuid(uuid)) == NULL) ||
304 (dmv = dm_dev_lookup_name(name)) == NULL) {
305 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
306 return ENOENT;
307 }
308
309 /* Test readonly flag change anything only if it is not set*/
310 if (!(flags & DM_READONLY_FLAG))
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 and decrement reference_counters
319 * for used pdevs.
320 */
321 int
322 dm_dev_remove_ioctl(prop_dictionary_t dm_dict)
323 {
324 struct dm_dev *dmv;
325
326 const char *name, *uuid;
327 uint32_t flags;
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
338 dm_dbg_print_flags(flags);
339
340 if (((dmv = dm_dev_lookup_uuid(uuid)) == NULL) &&
341 (dmv = dm_dev_lookup_name(name)) == NULL) {
342 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
343 return ENOENT;
344 }
345
346 if (!(flags & DM_READONLY_FLAG)) {
347 if (dmv->ref_cnt == 0){
348 /* Destroy active table first. */
349 dm_table_destroy(&dmv->tables[dmv->cur_active_table]);
350
351 /* Destroy unactive table if exits, too. */
352 if (!SLIST_EMPTY(&dmv->tables[1 - dmv->cur_active_table]))
353 dm_table_destroy(&dmv->tables[1 - dmv->cur_active_table]);
354
355 /* Decrement reference counters for all pdevs from this
356 device if they are unused close vnode and remove them
357 from global pdev list, too. */
358 dm_pdev_decr(&dmv->pdevs);
359
360 /* Test readonly flag change anything only if it is not set*/
361
362 dm_dev_rem(name); /* XXX. try to use uuid, too */
363 }
364
365 }
366 return 0;
367 }
368
369 /*
370 * Return actual state of device to libdevmapper.
371 */
372 int
373 dm_dev_status_ioctl(prop_dictionary_t dm_dict)
374 {
375 struct dm_table *tbl;
376 struct dm_dev *dmv;
377 const char *name, *uuid;
378 uint32_t flags;
379
380 name = NULL;
381 uuid = NULL;
382 flags = 0;
383
384 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
385 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
386 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
387
388 if (((dmv = dm_dev_lookup_name(name)) == NULL) &&
389 ((dmv = dm_dev_lookup_uuid(uuid)) == NULL)) {
390 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
391 return 0;
392 }
393
394 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->ref_cnt);
395 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_FLAGS, dmv->flags);
396
397 prop_dictionary_set_uint64(dm_dict, DM_IOCTL_DEV, dmv->minor);
398
399 tbl = &dmv->tables[dmv->cur_active_table];
400
401 if (tbl != NULL)
402 DM_ADD_FLAG(flags, DM_ACTIVE_PRESENT_FLAG);
403 else
404 DM_REMOVE_FLAG(flags, DM_ACTIVE_PRESENT_FLAG);
405
406 return 0;
407 }
408
409 /*
410 * Unsupported on NetBSD.
411 */
412 int
413 dm_dev_suspend_ioctl(prop_dictionary_t dm_dict)
414 {
415 struct dm_dev *dmv;
416 const char *name, *uuid;
417 uint32_t flags;
418
419 name = NULL;
420 uuid = NULL;
421 flags = 0;
422
423 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
424 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
425 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
426
427 if (((dmv = dm_dev_lookup_name(name)) == NULL) &&
428 ((dmv = dm_dev_lookup_uuid(uuid)) == NULL)) {
429 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
430 return 0;
431 }
432
433 dmv->flags |= DM_SUSPEND_FLAG;
434
435 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->ref_cnt);
436 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_FLAGS, dmv->flags);
437
438 prop_dictionary_set_uint64(dm_dict, DM_IOCTL_DEV, dmv->minor);
439
440 return 0;
441 }
442
443 /*
444 * Unsupported on NetBSD.
445 */
446 int
447 dm_dev_resume_ioctl(prop_dictionary_t dm_dict)
448 {
449 struct dm_dev *dmv;
450 const char *name, *uuid;
451 uint32_t flags;
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
461 if (((dmv = dm_dev_lookup_name(name)) == NULL) &&
462 ((dmv = dm_dev_lookup_uuid(uuid)) == NULL)) {
463 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
464 return 0;
465 }
466
467 dmv->flags &= ~DM_SUSPEND_FLAG;
468
469 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->ref_cnt);
470 prop_dictionary_set_uint32(dm_dict, DM_IOCTL_FLAGS, dmv->flags);
471
472 prop_dictionary_set_uint64(dm_dict, DM_IOCTL_DEV, dmv->minor);
473
474 return 0;
475 }
476
477 /*
478 * Table management routines
479 * lvm2tools doens't send name/uuid to kernel with table for lookup I have to use minor number.
480 */
481
482
483 /*
484 * Remove active table from device.
485 */
486 int
487 dm_table_clear_ioctl(prop_dictionary_t dm_dict)
488 {
489 struct dm_dev *dmv;
490 struct dm_table *tbl;
491
492 const char *name, *uuid;
493 int flags;
494
495 dmv = NULL;
496 name = NULL;
497 uuid = NULL;
498
499 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
500 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
501 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
502
503 aprint_verbose("Clearing inactive table from device: %s--%s\n",
504 name, uuid);
505
506 if (((dmv = dm_dev_lookup_name(name)) == NULL) &&
507 ((dmv = dm_dev_lookup_uuid(uuid)) == NULL)) {
508 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
509 return ENOENT;
510 }
511
512 /* Select unused table */
513 tbl = &dmv->tables[1-dmv->cur_active_table];
514
515 /* Test readonly flag change anything only if it is not set*/
516 if (!(flags & DM_READONLY_FLAG))
517 dm_table_destroy(tbl);
518
519 dmv->dev_type = 0;
520
521 return 0;
522 }
523
524 /*
525 * Get list of physical devices for active table.
526 * Get dev_t from pdev vnode and insert it into cmd_array.
527 *
528 * XXX. This function is called from lvm2tools to get information
529 * about physical devices, too e.g. during vgcreate.
530 */
531 int
532 dm_table_deps_ioctl(prop_dictionary_t dm_dict)
533 {
534 int error;
535 struct dm_dev *dmv;
536 struct dm_pdev *dmp;
537 struct vattr va;
538
539 prop_array_t cmd_array;
540
541 const char *name, *uuid;
542 int flags;
543 uint64_t dev;
544
545 size_t i;
546
547 name = NULL;
548 uuid = NULL;
549 dmv = NULL;
550 flags = 0;
551
552 i=0;
553
554 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
555 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
556 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
557 prop_dictionary_get_uint64(dm_dict, DM_IOCTL_DEV, &dev);
558
559 cmd_array = prop_dictionary_get(dm_dict,DM_IOCTL_CMD_DATA);
560
561 if (((dmv = dm_dev_lookup_name(name)) == NULL) &&
562 ((dmv = dm_dev_lookup_uuid(uuid)) == NULL) &&
563 ((dmv = dm_dev_lookup_minor(minor(dev))) == NULL)) {
564 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
565 return ENOENT;
566 }
567
568 aprint_verbose("Getting table deps for device: %s\n", dmv->name);
569
570 SLIST_FOREACH(dmp, &dmv->pdevs, next_pdev){
571
572 if ((error = VOP_GETATTR(dmp->pdev_vnode, &va, curlwp->l_cred))
573 != 0)
574 return (error);
575
576 prop_array_set_uint64(cmd_array, i, (uint64_t)va.va_rdev);
577
578 i++;
579 }
580
581 char *xml;
582 xml = prop_dictionary_externalize(dm_dict);
583 printf("%s\n",xml);
584
585 return 0;
586 }
587
588 /*
589 * Load new table/tables to device.
590 * Call apropriate target init routine open all physical pdev's and
591 * link them to device. For other targets mirror, strip, snapshot
592 * etc. also add dependency devices to upcalls list.
593 *
594 */
595 int
596 dm_table_load_ioctl(prop_dictionary_t dm_dict)
597 {
598 struct dm_dev *dmv;
599 struct dm_pdev *dmp;
600 struct dm_table_entry *table_en, *last_table;
601 struct dm_table *tbl;
602 struct dm_target *target;
603
604 prop_object_iterator_t iter;
605 prop_array_t cmd_array;
606 prop_dictionary_t target_dict;
607
608 const char *name, *uuid, *type;
609
610 uint32_t flags, ret;
611
612 uint64_t dev;
613
614 char *str;
615
616 ret = 0;
617 flags = 0;
618 name = NULL;
619 uuid = NULL;
620 dmv = NULL;
621 dmp = NULL;
622 last_table = NULL;
623
624 char *xml;
625 xml = prop_dictionary_externalize(dm_dict);
626 printf("%s\n",xml);
627
628 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
629 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
630 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
631 prop_dictionary_get_uint64(dm_dict, DM_IOCTL_DEV, &dev);
632
633 cmd_array = prop_dictionary_get(dm_dict, DM_IOCTL_CMD_DATA);
634 iter = prop_array_iterator(cmd_array);
635
636 dm_dbg_print_flags(flags);
637
638 aprint_verbose("Loading table to device: %s--%s\n",name,uuid);
639
640 if (((dmv = dm_dev_lookup_name(name)) == NULL) &&
641 ((dmv = dm_dev_lookup_uuid(uuid)) == NULL) &&
642 ((dmv = dm_dev_lookup_minor(minor(dev))) == NULL)) {
643 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
644 return ENOENT;
645 }
646
647 /* Select unused table */
648 tbl = &dmv->tables[1-dmv->cur_active_table];
649
650 /*
651 * I have to check if this table slot is not used by another table list.
652 * if it is used I should free them.
653 */
654
655 dm_table_destroy(tbl);
656
657 while((target_dict = prop_object_iterator_next(iter)) != NULL){
658
659 prop_dictionary_get_cstring_nocopy(target_dict,
660 DM_TABLE_TYPE, &type);
661
662 /*
663 * If we want to deny table with 2 or more different
664 * target we should do it here
665 */
666 if ((target = dm_target_lookup_name(type)) == NULL)
667 return ENOENT;
668
669 if ((table_en=kmem_alloc(sizeof(struct dm_table_entry),
670 KM_NOSLEEP)) == NULL)
671 return ENOMEM;
672
673 prop_dictionary_get_uint64(target_dict, DM_TABLE_START,
674 &table_en->start);
675 prop_dictionary_get_uint64(target_dict, DM_TABLE_LENGTH,
676 &table_en->length);
677
678 table_en->target=target;
679 table_en->dm_dev=dmv;
680
681 /*
682 * There is a parameter string after dm_target_spec
683 * structure which points to /dev/wd0a 284 part of
684 * table. String str points to this text.
685 */
686
687 prop_dictionary_get_cstring(target_dict,
688 DM_TABLE_PARAMS, (char**)&str);
689
690 /* Test readonly flag change anything only if it is not set*/
691 if (!(flags & DM_READONLY_FLAG)){
692
693 if (SLIST_EMPTY(tbl))
694 /* insert this table to head */
695 SLIST_INSERT_HEAD(tbl, table_en, next);
696 else
697 SLIST_INSERT_AFTER(last_table, table_en, next);
698
699 /*
700 * Params string is different for every target,
701 * therfore I have to pass it to target init
702 * routine and parse parameters there.
703 */
704 if (target->init != NULL && strlen(str) != 0)
705 ret = target->init(dmv, &table_en->target_config,
706 str);
707
708 if (ret != 0)
709 return ret;
710
711 last_table = table_en;
712
713 } else {
714 kmem_free(table_en, sizeof(struct dm_table_entry));
715 dm_pdev_destroy(dmp);
716 }
717
718 prop_object_release(str);
719 }
720
721 dmv->cur_active_table = 1 - dmv->cur_active_table;
722
723 prop_object_release(cmd_array);
724
725 DM_ADD_FLAG(flags, DM_ACTIVE_PRESENT_FLAG);
726
727 return 0;
728 }
729
730 /*
731 * Get description of all tables loaded to device from kernel
732 * and send it to libdevmapper.
733 *
734 * Output dictionary for every table:
735 *
736 * <key>cmd_data</key>
737 * <array>
738 * <dict>
739 * <key>type<key>
740 * <string>...</string>
741 *
742 * <key>start</key>
743 * <integer>...</integer>
744 *
745 * <key>length</key>
746 * <integer>...</integer>
747 *
748 * <key>params</key>
749 * <string>...</string>
750 * </dict>
751 * </array>
752 *
753 */
754 int
755 dm_table_status_ioctl(prop_dictionary_t dm_dict)
756 {
757 struct dm_dev *dmv;
758 struct dm_table *tbl;
759 struct dm_table_entry *table_en;
760
761 prop_array_t cmd_array;
762 prop_dictionary_t target_dict;
763
764 uint32_t rec_size;
765 uint64_t dev;
766
767 const char *name, *uuid;
768 char *params;
769 int flags,i;
770
771 dmv = NULL;
772 uuid = NULL;
773 name = NULL;
774
775 flags = 0;
776 rec_size = 0;
777 i=0;
778
779 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
780 prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
781 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
782 prop_dictionary_get_uint64(dm_dict, DM_IOCTL_DEV, &dev);
783
784 cmd_array = prop_dictionary_get(dm_dict, DM_IOCTL_CMD_DATA);
785
786 if (((dmv = dm_dev_lookup_name(name)) == NULL) &&
787 ((dmv = dm_dev_lookup_uuid(uuid)) == NULL) &&
788 ((dmv = dm_dev_lookup_minor(minor(dev)))) == NULL) {
789 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
790 return ENOENT;
791 }
792
793 aprint_verbose("Status of device tables: %s--%d\n",
794 name, dmv->cur_active_table);
795
796 tbl = &dmv->tables[dmv->cur_active_table];
797
798 if (tbl != NULL)
799 DM_ADD_FLAG(flags, DM_ACTIVE_PRESENT_FLAG);
800 else
801 DM_REMOVE_FLAG(flags, DM_ACTIVE_PRESENT_FLAG);
802
803 SLIST_FOREACH(table_en,tbl,next)
804 {
805 target_dict = prop_dictionary_create();
806 aprint_verbose("%016" PRIu64 ", length %016" PRIu64
807 ", target %s\n", table_en->start, table_en->length,
808 table_en->target->name);
809
810 prop_dictionary_set_uint64(target_dict, DM_TABLE_START,
811 table_en->start);
812 prop_dictionary_set_uint64(target_dict, DM_TABLE_LENGTH,
813 table_en->length);
814
815 prop_dictionary_set_cstring(target_dict, DM_TABLE_TYPE,
816 table_en->target->name);
817
818 prop_dictionary_set_int32(target_dict, DM_TABLE_STAT,
819 dmv->cur_active_table);
820
821 if ( flags |= DM_STATUS_TABLE_FLAG ) {
822 params = table_en->target->status
823 (table_en->target_config);
824
825 if(params != NULL){
826 prop_dictionary_set_cstring(target_dict,
827 DM_TABLE_PARAMS, params);
828
829 kmem_free(params,strlen(params)+1);
830 }
831 }
832 prop_array_set(cmd_array, i, target_dict);
833
834 prop_object_release(target_dict);
835
836 i++;
837 }
838
839 return 0;
840 }
841
842
843 /*
844 * For every call I have to set kernel driver version.
845 * Because I can have commands supported only in other
846 * newer/later version. This routine is called for every
847 * ioctl command.
848 */
849 int
850 dm_check_version(prop_dictionary_t dm_dict)
851 {
852 size_t i;
853 int dm_version[3];
854 prop_array_t ver;
855 int r;
856
857 r = 0;
858
859 ver = prop_dictionary_get(dm_dict, DM_IOCTL_VERSION);
860
861 for(i=0; i < 3; i++)
862 prop_array_get_uint32(ver, i, &dm_version[i]);
863
864
865 if (DM_VERSION_MAJOR != dm_version[0] ||
866 DM_VERSION_MINOR < dm_version[1])
867 {
868 aprint_verbose("libdevmapper/kernel version mismatch "
869 "kernel: %d.%d.%d libdevmapper: %d.%d.%d\n",
870 DM_VERSION_MAJOR, DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL,
871 dm_version[0], dm_version[1], dm_version[2]);
872
873 r = EIO;
874 goto out;
875 }
876
877 prop_array_set_uint32(ver, 0, DM_VERSION_MAJOR);
878 prop_array_set_uint32(ver, 1, DM_VERSION_MINOR);
879 prop_array_set_uint32(ver, 2, DM_VERSION_PATCHLEVEL);
880
881 out:
882 return r;
883 }
884