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