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