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