1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2015 Nexenta Inc. All rights reserved.
14 */
15
16 #include <sys/sunddi.h>
17 #include <sys/dkio.h>
18 #include <sys/dkioc_free_util.h>
19
20 #ifdef _KERNEL
21
22 #include <sys/sysmacros.h>
23 #include <sys/file.h>
24
25 #define DFL_COPYIN_MAX_EXTS (1024 * 1024)
26
27 /*
28 * Copy-in convenience function for variable-length dkioc_free_list_t
29 * structures. The pointer to copied from is in `arg' (may be a pointer
30 * to userspace), `ddi_flags' indicate whether the pointer is from user-
31 * or kernelspace (FKIOCTL) and `kmflags' are the flags passed to
32 * kmem_zalloc when allocating the new structure.
33 * Returns the copied structure on success and NULL on copy failure.
34 */
35 dkioc_free_list_t *
36 dfl_copyin(void *arg, int ddi_flags, int kmflags)
37 {
38 dkioc_free_list_t *dfl;
39
40 if (ddi_flags & FKIOCTL) {
41 dkioc_free_list_t *dfl_in = arg;
42 dfl = kmem_zalloc(DFL_SZ(dfl_in->dfl_num_exts), kmflags);
43 if (dfl == NULL)
44 return (NULL);
45 bcopy(dfl_in, dfl, DFL_SZ(dfl_in->dfl_num_exts));
46 } else {
47 uint64_t num_exts;
48
49 if (ddi_copyin(((uint8_t *)arg) + offsetof(dkioc_free_list_t,
50 dfl_num_exts), &num_exts, sizeof (num_exts), ddi_flags) ||
51 num_exts > DFL_COPYIN_MAX_EXTS)
52 return (NULL);
53
54 dfl = kmem_zalloc(DFL_SZ(num_exts), kmflags);
55 if (dfl == NULL)
56 return (NULL);
57 if (ddi_copyin(arg, dfl, DFL_SZ(num_exts), ddi_flags)) {
58 dfl_free(dfl);
59 return (NULL);
60 }
61
62 /* not valid from userspace */
63 dfl->dfl_ck_func = NULL;
64 dfl->dfl_ck_arg = NULL;
65 }
66
67 return (dfl);
68 }
69
70 /* Frees a variable-length dkioc_free_list_t structure. */
71 void
72 dfl_free(dkioc_free_list_t *dfl)
73 {
74 kmem_free(dfl, DFL_SZ(dfl->dfl_num_exts));
75 }
76
77 #else /* !KERNEL */
78
79 #include <stdlib.h>
80 #include <strings.h>
81
82 dkioc_free_list_t *
83 dfl_copyin(void *arg, int ddi_flags, int kmflags)
84 /*ARGSUSED*/
85 {
86 dkioc_free_list_t *dfl, *dfl_in = arg;
87 dfl = malloc(DFL_SZ(dfl_in->dfl_num_exts));
88 if (dfl == NULL)
89 return (NULL);
90 bcopy(dfl_in, dfl, DFL_SZ(dfl_in->dfl_num_exts));
91 return (dfl);
92 }
93
94 void
95 dfl_free(dkioc_free_list_t *dfl)
96 {
97 free(dfl);
98 }
99
100 #endif /* !KERNEL */