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