Merge branch 'vendor/OPENSSL' into HEAD
[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         dmv->is_open = 0;
250
251         dm_table_head_init(&dmv->table_head);
252
253         lockinit(&dmv->dev_mtx, "dmdev", 0, LK_CANRECURSE);
254         lockinit(&dmv->diskp_mtx, "dmdisk", 0, LK_CANRECURSE);
255         cv_init(&dmv->dev_cv, "dm_dev");
256
257         if (flags & DM_READONLY_FLAG)
258                 dmv->flags |= DM_READONLY_FLAG;
259
260         aprint_debug("Creating device dm/%s\n", name);
261         ksnprintf(name_buf, sizeof(name_buf), "mapper/%s", dmv->name);
262
263         devstat_add_entry(&dmv->stats, name, 0, DEV_BSIZE,
264             DEVSTAT_NO_ORDERED_TAGS,
265             DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_OTHER,
266             DEVSTAT_PRIORITY_DISK);
267
268         dmv->devt = disk_create_named(name_buf, dm_minor, dmv->diskp, &dm_ops);
269         reference_dev(dmv->devt);
270
271         dmv->minor = minor(dmv->devt);
272         prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
273         udev_dict_set_cstr(dmv->devt, "subsystem", "disk");
274
275         if ((r = dm_dev_insert(dmv)) != 0)
276                 dm_dev_free(dmv);
277
278         DM_ADD_FLAG(flags, DM_EXISTS_FLAG);
279         DM_REMOVE_FLAG(flags, DM_INACTIVE_PRESENT_FLAG);
280
281         /* Increment device counter After creating device */
282         ++dm_dev_counter; /* XXX: was atomic 64 */
283
284         return r;
285 }
286 /*
287  * Get list of created device-mapper devices fromglobal list and
288  * send it to kernel.
289  *
290  * Output dictionary:
291  *
292  * <key>cmd_data</key>
293  *  <array>
294  *   <dict>
295  *    <key>name<key>
296  *    <string>...</string>
297  *
298  *    <key>dev</key>
299  *    <integer>...</integer>
300  *   </dict>
301  *  </array>
302  *
303  */
304 int
305 dm_dev_list_ioctl(prop_dictionary_t dm_dict)
306 {
307         prop_array_t dev_list;
308
309         uint32_t flags;
310
311         flags = 0;
312
313         prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
314
315         dm_dbg_print_flags(flags);
316
317         dev_list = dm_dev_prop_list();
318
319         prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, dev_list);
320         prop_object_release(dev_list);
321
322         return 0;
323 }
324 /*
325  * Rename selected devices old name is in struct dm_ioctl.
326  * newname is taken from dictionary
327  *
328  * <key>cmd_data</key>
329  *  <array>
330  *   <string>...</string>
331  *  </array>
332  */
333 int
334 dm_dev_rename_ioctl(prop_dictionary_t dm_dict)
335 {
336         prop_array_t cmd_array;
337         dm_dev_t *dmv;
338
339         const char *name, *uuid, *n_name;
340         uint32_t flags, minor;
341
342         name = NULL;
343         uuid = NULL;
344         minor = 0;
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         cmd_array = prop_dictionary_get(dm_dict, DM_IOCTL_CMD_DATA);
355
356         prop_array_get_cstring_nocopy(cmd_array, 0, &n_name);
357
358         if (strlen(n_name) + 1 > DM_NAME_LEN)
359                 return EINVAL;
360
361         if ((dmv = dm_dev_rem(name, uuid, minor)) == NULL) {
362                 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
363                 return ENOENT;
364         }
365         /* change device name */
366         /*
367          * XXX How to deal with this change, name only used in
368          * dm_dev_routines, should I add dm_dev_change_name which will run
369          * under the dm_dev_list mutex ?
370          */
371         strlcpy(dmv->name, n_name, DM_NAME_LEN);
372
373         prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt);
374         prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
375         prop_dictionary_set_cstring(dm_dict, DM_IOCTL_UUID, dmv->uuid);
376
377         dm_dev_insert(dmv);
378
379         return 0;
380 }
381 /*
382  * Remove device from global list I have to remove active
383  * and inactive tables first.
384  */
385 int
386 dm_dev_remove_ioctl(prop_dictionary_t dm_dict)
387 {
388         dm_dev_t *dmv;
389         const char *name, *uuid;
390         uint32_t flags, minor;
391
392         flags = 0;
393         name = NULL;
394         uuid = NULL;
395
396         /* Get needed values from dictionary. */
397         prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
398         prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
399         prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
400         prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
401
402         dm_dbg_print_flags(flags);
403
404         /*
405          * This seems as hack to me, probably use routine dm_dev_get_devt to
406          * atomicaly get devt from device.
407          */
408         if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) {
409                 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
410                 return ENOENT;
411         }
412
413         dm_dev_unbusy(dmv);
414
415         if (dmv->is_open)
416                 return EBUSY;
417
418         /*
419          * This will call dm_detach routine which will actually removes
420          * device.
421          */
422         return dm_detach(dmv);
423 }
424 /*
425  * Return actual state of device to libdevmapper.
426  */
427 int
428 dm_dev_status_ioctl(prop_dictionary_t dm_dict)
429 {
430         dm_dev_t *dmv;
431         const char *name, *uuid;
432         uint32_t flags, j, minor;
433
434         name = NULL;
435         uuid = NULL;
436         flags = 0;
437         j = 0;
438
439         prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
440         prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
441         prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
442         prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
443
444         if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) {
445                 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
446                 return ENOENT;
447         }
448         dm_dbg_print_flags(dmv->flags);
449
450         prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt);
451         prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
452         prop_dictionary_set_cstring(dm_dict, DM_IOCTL_UUID, dmv->uuid);
453
454         if (dmv->flags & DM_SUSPEND_FLAG)
455                 DM_ADD_FLAG(flags, DM_SUSPEND_FLAG);
456
457         /*
458          * Add status flags for tables I have to check both active and
459          * inactive tables.
460          */
461         if ((j = dm_table_get_target_count(&dmv->table_head, DM_TABLE_ACTIVE))) {
462                 DM_ADD_FLAG(flags, DM_ACTIVE_PRESENT_FLAG);
463         } else
464                 DM_REMOVE_FLAG(flags, DM_ACTIVE_PRESENT_FLAG);
465
466         prop_dictionary_set_uint32(dm_dict, DM_IOCTL_TARGET_COUNT, j);
467
468         if (dm_table_get_target_count(&dmv->table_head, DM_TABLE_INACTIVE))
469                 DM_ADD_FLAG(flags, DM_INACTIVE_PRESENT_FLAG);
470         else
471                 DM_REMOVE_FLAG(flags, DM_INACTIVE_PRESENT_FLAG);
472
473         dm_dev_unbusy(dmv);
474
475         return 0;
476 }
477 /*
478  * Set only flag to suggest that device is suspended. This call is
479  * not supported in NetBSD.
480  *
481  */
482 int
483 dm_dev_suspend_ioctl(prop_dictionary_t dm_dict)
484 {
485         dm_dev_t *dmv;
486         const char *name, *uuid;
487         uint32_t flags, minor;
488
489         name = NULL;
490         uuid = NULL;
491         flags = 0;
492
493         prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
494         prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
495         prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
496         prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
497
498         if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) {
499                 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
500                 return ENOENT;
501         }
502         atomic_set_int(&dmv->flags, DM_SUSPEND_FLAG);
503
504         dm_dbg_print_flags(dmv->flags);
505
506         prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt);
507         prop_dictionary_set_uint32(dm_dict, DM_IOCTL_FLAGS, dmv->flags);
508         prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
509
510         dm_dev_unbusy(dmv);
511
512         /* Add flags to dictionary flag after dmv -> dict copy */
513         DM_ADD_FLAG(flags, DM_EXISTS_FLAG);
514
515         return 0;
516 }
517 /*
518  * Simulate Linux behaviour better and switch tables here and not in
519  * dm_table_load_ioctl.
520  */
521 int
522 dm_dev_resume_ioctl(prop_dictionary_t dm_dict)
523 {
524         dm_dev_t *dmv;
525         const char *name, *uuid;
526         uint32_t flags, minor;
527
528         name = NULL;
529         uuid = NULL;
530         flags = 0;
531
532         /*
533          * char *xml; xml = prop_dictionary_externalize(dm_dict);
534          * printf("%s\n",xml);
535          */
536
537         prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
538         prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
539         prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
540         prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
541
542         /* Remove device from global device list */
543         if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) {
544                 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
545                 return ENOENT;
546         }
547         atomic_clear_int(&dmv->flags, (DM_SUSPEND_FLAG | DM_INACTIVE_PRESENT_FLAG));
548         atomic_set_int(&dmv->flags, DM_ACTIVE_PRESENT_FLAG);
549
550         dm_table_switch_tables(&dmv->table_head);
551
552         DM_ADD_FLAG(flags, DM_EXISTS_FLAG);
553
554         dmsetdiskinfo(dmv->diskp, &dmv->table_head);
555
556         prop_dictionary_set_uint32(dm_dict, DM_IOCTL_OPEN, dmv->table_head.io_cnt);
557         prop_dictionary_set_uint32(dm_dict, DM_IOCTL_FLAGS, flags);
558         prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
559
560         dm_dev_unbusy(dmv);
561
562         /* Destroy inactive table after resume. */
563         dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE);
564
565         return 0;
566 }
567 /*
568  * Table management routines
569  * lvm2tools doens't send name/uuid to kernel with table
570  * for lookup I have to use minor number.
571  */
572
573 /*
574  * Remove inactive table from device. Routines which work's with inactive tables
575  * doesn't need to synchronise with dmstrategy. They can synchronise themselves with mutex?.
576  *
577  */
578 int
579 dm_table_clear_ioctl(prop_dictionary_t dm_dict)
580 {
581         dm_dev_t *dmv;
582         const char *name, *uuid;
583         uint32_t flags, minor;
584
585         dmv = NULL;
586         name = NULL;
587         uuid = NULL;
588         flags = 0;
589         minor = 0;
590
591         prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
592         prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
593         prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
594         prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
595
596         aprint_debug("Clearing inactive table from device: %s--%s\n",
597             name, uuid);
598
599         if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) {
600                 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
601                 return ENOENT;
602         }
603         /* Select unused table */
604         dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE);
605
606         atomic_clear_int(&dmv->flags, DM_INACTIVE_PRESENT_FLAG);
607
608         dm_dev_unbusy(dmv);
609
610         return 0;
611 }
612 /*
613  * Get list of physical devices for active table.
614  * Get dev_t from pdev vnode and insert it into cmd_array.
615  *
616  * XXX. This function is called from lvm2tools to get information
617  *      about physical devices, too e.g. during vgcreate.
618  */
619 int
620 dm_table_deps_ioctl(prop_dictionary_t dm_dict)
621 {
622         dm_dev_t *dmv;
623         dm_table_t *tbl;
624         dm_table_entry_t *table_en;
625
626         prop_array_t cmd_array;
627         const char *name, *uuid;
628         uint32_t flags, minor;
629
630         int table_type;
631         size_t i;
632
633         name = NULL;
634         uuid = NULL;
635         dmv = NULL;
636         flags = 0;
637
638         i = 0;
639
640         prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
641         prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
642         prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
643         prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
644
645         /* create array for dev_t's */
646         cmd_array = prop_array_create();
647
648         if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) {
649                 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
650                 return ENOENT;
651         }
652         prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
653         prop_dictionary_set_cstring(dm_dict, DM_IOCTL_NAME, dmv->name);
654         prop_dictionary_set_cstring(dm_dict, DM_IOCTL_UUID, dmv->uuid);
655
656         aprint_debug("Getting table deps for device: %s\n", dmv->name);
657
658         /*
659          * if DM_QUERY_INACTIVE_TABLE_FLAG is passed we need to query
660          * INACTIVE TABLE
661          */
662         if (flags & DM_QUERY_INACTIVE_TABLE_FLAG)
663                 table_type = DM_TABLE_INACTIVE;
664         else
665                 table_type = DM_TABLE_ACTIVE;
666
667         tbl = dm_table_get_entry(&dmv->table_head, table_type);
668
669         SLIST_FOREACH(table_en, tbl, next)
670             table_en->target->deps(table_en, cmd_array);
671
672         dm_table_release(&dmv->table_head, table_type);
673         dm_dev_unbusy(dmv);
674
675         prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, cmd_array);
676         prop_object_release(cmd_array);
677
678         return 0;
679 }
680 /*
681  * Load new table/tables to device.
682  * Call apropriate target init routine open all physical pdev's and
683  * link them to device. For other targets mirror, strip, snapshot
684  * etc. also add dependency devices to upcalls list.
685  *
686  * Load table to inactive slot table are switched in dm_device_resume_ioctl.
687  * This simulates Linux behaviour better there should not be any difference.
688  *
689  */
690 int
691 dm_table_load_ioctl(prop_dictionary_t dm_dict)
692 {
693         dm_dev_t *dmv;
694         dm_table_entry_t *table_en, *last_table;
695         dm_table_t *tbl;
696         dm_target_t *target;
697
698         prop_object_iterator_t iter;
699         prop_array_t cmd_array;
700         prop_dictionary_t target_dict;
701
702         const char *name, *uuid, *type;
703
704         uint32_t flags, ret, minor;
705
706         char *str;
707
708         ret = 0;
709         flags = 0;
710         name = NULL;
711         uuid = NULL;
712         dmv = NULL;
713         last_table = NULL;
714         str = NULL;
715
716         /*
717          * char *xml; xml = prop_dictionary_externalize(dm_dict);
718          * printf("%s\n",xml);
719          */
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         dm_dbg_print_flags(flags);
729
730         if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) {
731                 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
732                 return ENOENT;
733         }
734         aprint_debug("Loading table to device: %s--%d\n", name,
735             dmv->table_head.cur_active_table);
736
737         /*
738          * I have to check if this table slot is not used by another table list.
739          * if it is used I should free them.
740          */
741         if (dmv->flags & DM_INACTIVE_PRESENT_FLAG)
742                 dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE);
743
744         dm_dbg_print_flags(dmv->flags);
745         tbl = dm_table_get_entry(&dmv->table_head, DM_TABLE_INACTIVE);
746
747         aprint_debug("dmv->name = %s\n", dmv->name);
748
749         prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
750
751         while ((target_dict = prop_object_iterator_next(iter)) != NULL) {
752                 prop_dictionary_get_cstring_nocopy(target_dict,
753                     DM_TABLE_TYPE, &type);
754                 /*
755                  * If we want to deny table with 2 or more different
756                  * target we should do it here
757                  */
758                 if (((target = dm_target_lookup(type)) == NULL) &&
759                     ((target = dm_target_autoload(type)) == NULL)) {
760                         dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE);
761                         dm_dev_unbusy(dmv);
762                         return ENOENT;
763                 }
764                 if ((table_en = kmalloc(sizeof(dm_table_entry_t),
765                             M_DM, M_WAITOK)) == NULL) {
766                         dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE);
767                         dm_dev_unbusy(dmv);
768                         return ENOMEM;
769                 }
770                 prop_dictionary_get_uint64(target_dict, DM_TABLE_START,
771                     &table_en->start);
772                 prop_dictionary_get_uint64(target_dict, DM_TABLE_LENGTH,
773                     &table_en->length);
774
775                 aprint_debug("dm_ioctl.c... table_en->start = %ju, "
776                              "table_en->length = %ju\n",
777                              (uintmax_t)table_en->start,
778                              (uintmax_t)table_en->length);
779
780                 table_en->target = target;
781                 table_en->dm_dev = dmv;
782                 table_en->target_config = NULL;
783
784                 /*
785                  * There is a parameter string after dm_target_spec
786                  * structure which  points to /dev/wd0a 284 part of
787                  * table. String str points to this text. This can be
788                  * null and therefore it should be checked before we try to
789                  * use it.
790                  */
791                 prop_dictionary_get_cstring(target_dict,
792                     DM_TABLE_PARAMS, (char **) &str);
793
794                 if (SLIST_EMPTY(tbl))
795                         /* insert this table to head */
796                         SLIST_INSERT_HEAD(tbl, table_en, next);
797                 else
798                         SLIST_INSERT_AFTER(last_table, table_en, next);
799
800                 /*
801                  * Params string is different for every target,
802                  * therfore I have to pass it to target init
803                  * routine and parse parameters there.
804                  */
805                 aprint_debug("DM: str passed in is: %s", str);
806                 if ((ret = target->init(dmv, &table_en->target_config,
807                             str)) != 0) {
808
809                         dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE);
810                         dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE);
811                         kfree(str, M_TEMP);
812
813                         dm_dev_unbusy(dmv);
814                         return ret;
815                 }
816                 last_table = table_en;
817                 kfree(str, M_TEMP);
818         }
819         prop_object_iterator_release(iter);
820
821         DM_ADD_FLAG(flags, DM_INACTIVE_PRESENT_FLAG);
822         atomic_set_int(&dmv->flags, DM_INACTIVE_PRESENT_FLAG);
823
824         dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE);
825
826         dm_dev_unbusy(dmv);
827 #if 0
828         dmsetdiskinfo(dmv->diskp, &dmv->table_head);
829 #endif
830         return 0;
831 }
832 /*
833  * Get description of all tables loaded to device from kernel
834  * and send it to libdevmapper.
835  *
836  * Output dictionary for every table:
837  *
838  * <key>cmd_data</key>
839  * <array>
840  *   <dict>
841  *    <key>type<key>
842  *    <string>...</string>
843  *
844  *    <key>start</key>
845  *    <integer>...</integer>
846  *
847  *    <key>length</key>
848  *    <integer>...</integer>
849  *
850  *    <key>params</key>
851  *    <string>...</string>
852  *   </dict>
853  * </array>
854  *
855  */
856 int
857 dm_table_status_ioctl(prop_dictionary_t dm_dict)
858 {
859         dm_dev_t *dmv;
860         dm_table_t *tbl;
861         dm_table_entry_t *table_en;
862
863         prop_array_t cmd_array;
864         prop_dictionary_t target_dict;
865
866         uint32_t rec_size, minor;
867
868         const char *name, *uuid;
869         char *params;
870         int flags;
871         int table_type;
872
873         dmv = NULL;
874         uuid = NULL;
875         name = NULL;
876         params = NULL;
877         flags = 0;
878         rec_size = 0;
879
880         prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
881         prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
882         prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
883         prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);
884
885         cmd_array = prop_array_create();
886
887         if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) {
888                 DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
889                 return ENOENT;
890         }
891         /*
892          * if DM_QUERY_INACTIVE_TABLE_FLAG is passed we need to query
893          * INACTIVE TABLE
894          */
895         if (flags & DM_QUERY_INACTIVE_TABLE_FLAG)
896                 table_type = DM_TABLE_INACTIVE;
897         else
898                 table_type = DM_TABLE_ACTIVE;
899
900         if (dm_table_get_target_count(&dmv->table_head, DM_TABLE_ACTIVE))
901                 DM_ADD_FLAG(flags, DM_ACTIVE_PRESENT_FLAG);
902         else {
903                 DM_REMOVE_FLAG(flags, DM_ACTIVE_PRESENT_FLAG);
904
905                 if (dm_table_get_target_count(&dmv->table_head, DM_TABLE_INACTIVE))
906                         DM_ADD_FLAG(flags, DM_INACTIVE_PRESENT_FLAG);
907                 else {
908                         DM_REMOVE_FLAG(flags, DM_INACTIVE_PRESENT_FLAG);
909                 }
910         }
911
912         if (dmv->flags & DM_SUSPEND_FLAG)
913                 DM_ADD_FLAG(flags, DM_SUSPEND_FLAG);
914
915         prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);
916
917         aprint_debug("Status of device tables: %s--%d\n",
918             name, dmv->table_head.cur_active_table);
919
920         tbl = dm_table_get_entry(&dmv->table_head, table_type);
921
922         SLIST_FOREACH(table_en, tbl, next) {
923                 target_dict = prop_dictionary_create();
924                 aprint_debug("%016" PRIu64 ", length %016" PRIu64
925                     ", target %s\n", table_en->start, table_en->length,
926                     table_en->target->name);
927
928                 prop_dictionary_set_uint64(target_dict, DM_TABLE_START,
929                     table_en->start);
930                 prop_dictionary_set_uint64(target_dict, DM_TABLE_LENGTH,
931                     table_en->length);
932
933                 prop_dictionary_set_cstring(target_dict, DM_TABLE_TYPE,
934                     table_en->target->name);
935
936                 /* dm_table_get_cur_actv.table ?? */
937                 prop_dictionary_set_int32(target_dict, DM_TABLE_STAT,
938                     dmv->table_head.cur_active_table);
939
940                 if (flags |= DM_STATUS_TABLE_FLAG) {
941                         params = table_en->target->status
942                             (table_en->target_config);
943
944                         if (params != NULL) {
945                                 prop_dictionary_set_cstring(target_dict,
946                                     DM_TABLE_PARAMS, params);
947
948                                 kfree(params, M_DM);
949                         }
950                 }
951                 prop_array_add(cmd_array, target_dict);
952                 prop_object_release(target_dict);
953         }
954
955         dm_table_release(&dmv->table_head, table_type);
956         dm_dev_unbusy(dmv);
957
958         prop_dictionary_set_uint32(dm_dict, DM_IOCTL_FLAGS, flags);
959         prop_dictionary_set(dm_dict, DM_IOCTL_CMD_DATA, cmd_array);
960         prop_object_release(cmd_array);
961
962         return 0;
963 }
964
965
966 /*
967  * For every call I have to set kernel driver version.
968  * Because I can have commands supported only in other
969  * newer/later version. This routine is called for every
970  * ioctl command.
971  */
972 int
973 dm_check_version(prop_dictionary_t dm_dict)
974 {
975         size_t i;
976         int dm_version[3];
977         prop_array_t ver;
978
979         ver = prop_dictionary_get(dm_dict, DM_IOCTL_VERSION);
980
981         for (i = 0; i < 3; i++)
982                 prop_array_get_uint32(ver, i, &dm_version[i]);
983
984         if (DM_VERSION_MAJOR != dm_version[0] || DM_VERSION_MINOR < dm_version[1]) {
985                 aprint_debug("libdevmapper/kernel version mismatch "
986                     "kernel: %d.%d.%d libdevmapper: %d.%d.%d\n",
987                     DM_VERSION_MAJOR, DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL,
988                     dm_version[0], dm_version[1], dm_version[2]);
989
990                 return EIO;
991         }
992         prop_array_set_uint32(ver, 0, DM_VERSION_MAJOR);
993         prop_array_set_uint32(ver, 1, DM_VERSION_MINOR);
994         prop_array_set_uint32(ver, 2, DM_VERSION_PATCHLEVEL);
995
996         prop_dictionary_set(dm_dict, DM_IOCTL_VERSION, ver);
997
998         return 0;
999 }