2 * Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/types.h>
28 #include <sys/param.h>
29 #include <sys/kernel.h>
30 #include <sys/systm.h>
33 #include <sys/mutex.h>
35 #include <sys/malloc.h>
36 #include <sys/queue.h>
42 #include <sys/policy.h>
44 static MALLOC_DEFINE(M_ZONES
, "zones_data", "Zones data");
47 * Structure to record list of ZFS datasets exported to a zone.
49 typedef struct zone_dataset
{
50 LIST_ENTRY(zone_dataset
) zd_next
;
54 LIST_HEAD(zone_dataset_head
, zone_dataset
);
59 zone_dataset_attach(struct ucred
*cred
, const char *dataset
, int jailid
)
61 struct zone_dataset_head
*head
;
62 zone_dataset_t
*zd
, *zd2
;
66 if ((error
= priv_check_cred(cred
, PRIV_ZFS_JAIL
)) != 0)
69 /* Allocate memory before we grab prison's mutex. */
70 zd
= malloc(sizeof (*zd
) + strlen(dataset
) + 1, M_ZONES
, M_WAITOK
);
72 sx_slock(&allprison_lock
);
73 pr
= prison_find(jailid
); /* Locks &pr->pr_mtx. */
74 sx_sunlock(&allprison_lock
);
80 head
= osd_jail_get(pr
, zone_slot
);
83 LIST_FOREACH(zd2
, head
, zd_next
) {
84 if (strcmp(dataset
, zd2
->zd_dataset
) == 0) {
92 prison_hold_locked(pr
);
93 mtx_unlock(&pr
->pr_mtx
);
94 head
= malloc(sizeof (*head
), M_ZONES
, M_WAITOK
);
96 mtx_lock(&pr
->pr_mtx
);
97 error
= osd_jail_set(pr
, zone_slot
, head
);
98 KASSERT(error
== 0, ("osd_jail_set() failed (error=%d)",
101 strcpy(zd
->zd_dataset
, dataset
);
102 LIST_INSERT_HEAD(head
, zd
, zd_next
);
105 prison_free_locked(pr
);
107 mtx_unlock(&pr
->pr_mtx
);
112 zone_dataset_detach(struct ucred
*cred
, const char *dataset
, int jailid
)
114 struct zone_dataset_head
*head
;
119 if ((error
= priv_check_cred(cred
, PRIV_ZFS_JAIL
)) != 0)
122 sx_slock(&allprison_lock
);
123 pr
= prison_find(jailid
);
124 sx_sunlock(&allprison_lock
);
127 head
= osd_jail_get(pr
, zone_slot
);
132 LIST_FOREACH(zd
, head
, zd_next
) {
133 if (strcmp(dataset
, zd
->zd_dataset
) == 0)
139 LIST_REMOVE(zd
, zd_next
);
141 if (LIST_EMPTY(head
))
142 osd_jail_del(pr
, zone_slot
);
146 mtx_unlock(&pr
->pr_mtx
);
151 * Returns true if the named dataset is visible in the current zone.
152 * The 'write' parameter is set to 1 if the dataset is also writable.
155 zone_dataset_visible(const char *dataset
, int *write
)
157 struct zone_dataset_head
*head
;
163 if (dataset
[0] == '\0')
165 if (INGLOBALZONE(curproc
)) {
170 pr
= curthread
->td_ucred
->cr_prison
;
171 mtx_lock(&pr
->pr_mtx
);
172 head
= osd_jail_get(pr
, zone_slot
);
177 * Walk the list once, looking for datasets which match exactly, or
178 * specify a dataset underneath an exported dataset. If found, return
179 * true and note that it is writable.
181 LIST_FOREACH(zd
, head
, zd_next
) {
182 len
= strlen(zd
->zd_dataset
);
183 if (strlen(dataset
) >= len
&&
184 memcmp(dataset
, zd
->zd_dataset
, len
) == 0 &&
185 (dataset
[len
] == '\0' || dataset
[len
] == '/' ||
186 dataset
[len
] == '@')) {
195 * Walk the list a second time, searching for datasets which are parents
196 * of exported datasets. These should be visible, but read-only.
198 * Note that we also have to support forms such as 'pool/dataset/', with
201 LIST_FOREACH(zd
, head
, zd_next
) {
202 len
= strlen(dataset
);
203 if (dataset
[len
- 1] == '/')
204 len
--; /* Ignore trailing slash */
205 if (len
< strlen(zd
->zd_dataset
) &&
206 memcmp(dataset
, zd
->zd_dataset
, len
) == 0 &&
207 zd
->zd_dataset
[len
] == '/') {
215 mtx_unlock(&pr
->pr_mtx
);
220 zone_destroy(void *arg
)
222 struct zone_dataset_head
*head
;
226 while ((zd
= LIST_FIRST(head
)) != NULL
) {
227 LIST_REMOVE(zd
, zd_next
);
234 zone_get_hostid(void *ptr
)
237 KASSERT(ptr
== NULL
, ("only NULL pointer supported in %s", __func__
));
239 return ((uint32_t)curthread
->td_ucred
->cr_prison
->pr_hostid
);
243 zone_sysinit(void *arg __unused
)
246 zone_slot
= osd_jail_register(zone_destroy
, NULL
);
250 zone_sysuninit(void *arg __unused
)
253 osd_jail_deregister(zone_slot
);
256 SYSINIT(zone_sysinit
, SI_SUB_DRIVERS
, SI_ORDER_ANY
, zone_sysinit
, NULL
);
257 SYSUNINIT(zone_sysuninit
, SI_SUB_DRIVERS
, SI_ORDER_ANY
, zone_sysuninit
, NULL
);