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