Merge branches 'hammer2' and 'master' of ssh://crater.dragonflybsd.org/repository...
[dragonfly.git] / sys / vfs / hammer2 / hammer2_ioctl.c
CommitLineData
2910a90c
MD
1/*
2 * Copyright (c) 2011-2012 The DragonFly Project. All rights reserved.
3 *
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@dragonflybsd.org>
6 * by Venkatesh Srinivas <vsrinivas@dragonflybsd.org>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 * 3. Neither the name of The DragonFly Project nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific, prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35/*
36 * Ioctl Functions.
37 *
38 * WARNING! The ioctl functions which manipulate the connection state need
39 * to be able to run without deadlock on the volume's chain lock.
40 * Most of these functions use a separate lock.
41 */
42
43#include "hammer2.h"
44
ae183399
MD
45static int hammer2_ioctl_version_get(hammer2_inode_t *ip, void *data);
46static int hammer2_ioctl_remote_get(hammer2_inode_t *ip, void *data);
47static int hammer2_ioctl_remote_add(hammer2_inode_t *ip, void *data);
48static int hammer2_ioctl_remote_del(hammer2_inode_t *ip, void *data);
49static int hammer2_ioctl_remote_rep(hammer2_inode_t *ip, void *data);
50static int hammer2_ioctl_socket_get(hammer2_inode_t *ip, void *data);
51static int hammer2_ioctl_socket_set(hammer2_inode_t *ip, void *data);
52static int hammer2_ioctl_pfs_get(hammer2_inode_t *ip, void *data);
53static int hammer2_ioctl_pfs_create(hammer2_inode_t *ip, void *data);
54static int hammer2_ioctl_pfs_delete(hammer2_inode_t *ip, void *data);
2910a90c
MD
55
56int
57hammer2_ioctl(hammer2_inode_t *ip, u_long com, void *data, int fflag,
58 struct ucred *cred)
59{
60 int error;
61
62 /*
63 * Standard root cred checks, will be selectively ignored below
64 * for ioctls that do not require root creds.
65 */
66 error = priv_check_cred(cred, PRIV_HAMMER_IOCTL, 0);
67
68 switch(com) {
ae183399
MD
69 case HAMMER2IOC_VERSION_GET:
70 error = hammer2_ioctl_version_get(ip, data);
2910a90c 71 break;
ae183399 72 case HAMMER2IOC_REMOTE_GET:
2910a90c 73 if (error == 0)
ae183399 74 error = hammer2_ioctl_remote_get(ip, data);
2910a90c 75 break;
ae183399 76 case HAMMER2IOC_REMOTE_ADD:
2910a90c 77 if (error == 0)
ae183399 78 error = hammer2_ioctl_remote_add(ip, data);
2910a90c 79 break;
ae183399 80 case HAMMER2IOC_REMOTE_DEL:
2910a90c 81 if (error == 0)
ae183399 82 error = hammer2_ioctl_remote_del(ip, data);
2910a90c 83 break;
ae183399 84 case HAMMER2IOC_REMOTE_REP:
2910a90c 85 if (error == 0)
ae183399 86 error = hammer2_ioctl_remote_rep(ip, data);
2910a90c 87 break;
ae183399 88 case HAMMER2IOC_SOCKET_GET:
2910a90c 89 if (error == 0)
ae183399 90 error = hammer2_ioctl_socket_get(ip, data);
2910a90c 91 break;
ae183399
MD
92 case HAMMER2IOC_SOCKET_SET:
93 if (error == 0)
94 error = hammer2_ioctl_socket_set(ip, data);
95 break;
96 case HAMMER2IOC_PFS_GET:
2910a90c 97 if (error == 0)
ae183399
MD
98 error = hammer2_ioctl_pfs_get(ip, data);
99 break;
100 case HAMMER2IOC_PFS_CREATE:
101 if (error == 0)
102 error = hammer2_ioctl_pfs_create(ip, data);
103 break;
104 case HAMMER2IOC_PFS_DELETE:
105 if (error == 0)
106 error = hammer2_ioctl_pfs_delete(ip, data);
2910a90c
MD
107 break;
108 default:
109 error = EOPNOTSUPP;
110 break;
111 }
112 return (error);
113}
114
115/*
116 * Retrieve version and basic info
117 */
118static int
ae183399 119hammer2_ioctl_version_get(hammer2_inode_t *ip, void *data)
2910a90c
MD
120{
121 hammer2_mount_t *hmp = ip->hmp;
122 hammer2_ioc_version_t *version = data;
123
124 version->version = hmp->voldata.version;
125 return 0;
126}
127
128/*
129 * Retrieve information about a remote
130 */
131static int
ae183399 132hammer2_ioctl_remote_get(hammer2_inode_t *ip, void *data)
2910a90c
MD
133{
134 hammer2_mount_t *hmp = ip->hmp;
135 hammer2_ioc_remote_t *remote = data;
136 int copyid = remote->copyid;
137
138 if (copyid < 0 || copyid >= HAMMER2_COPYID_COUNT)
139 return (EINVAL);
140
141 hammer2_voldata_lock(hmp);
142 remote->copy1 = hmp->voldata.copyinfo[copyid];
143 hammer2_voldata_unlock(hmp);
144
145 /*
146 * Adjust nextid (GET only)
147 */
148 while (++copyid < HAMMER2_COPYID_COUNT &&
149 hmp->voldata.copyinfo[copyid].copyid == 0) {
150 ++copyid;
151 }
152 if (copyid == HAMMER2_COPYID_COUNT)
153 remote->nextid = -1;
154 else
155 remote->nextid = copyid;
156
157 return(0);
158}
159
160/*
161 * Add new remote entry
162 */
163static int
ae183399 164hammer2_ioctl_remote_add(hammer2_inode_t *ip, void *data)
2910a90c
MD
165{
166 hammer2_mount_t *hmp = ip->hmp;
167 hammer2_ioc_remote_t *remote = data;
168 int copyid = remote->copyid;
169 int error = 0;
170
171 if (copyid >= HAMMER2_COPYID_COUNT)
172 return (EINVAL);
173
174 hammer2_voldata_lock(hmp);
175 if (copyid < 0) {
176 for (copyid = 1; copyid < HAMMER2_COPYID_COUNT; ++copyid) {
177 if (hmp->voldata.copyinfo[copyid].copyid == 0)
178 break;
179 }
180 if (copyid == HAMMER2_COPYID_COUNT) {
181 error = ENOSPC;
182 goto failed;
183 }
184 }
185 hammer2_modify_volume(hmp);
186 kprintf("copyid %d\n", copyid);
187 remote->copy1.copyid = copyid;
188 hmp->voldata.copyinfo[copyid] = remote->copy1;
189failed:
190 hammer2_voldata_unlock(hmp);
191 return (error);
192}
193
194/*
195 * Delete existing remote entry
196 */
197static int
ae183399 198hammer2_ioctl_remote_del(hammer2_inode_t *ip, void *data)
2910a90c
MD
199{
200 hammer2_mount_t *hmp = ip->hmp;
201 hammer2_ioc_remote_t *remote = data;
202 int copyid = remote->copyid;
203 int error = 0;
204
205 if (copyid >= HAMMER2_COPYID_COUNT)
206 return (EINVAL);
207 remote->copy1.path[sizeof(remote->copy1.path) - 1] = 0;
208 hammer2_voldata_lock(hmp);
209 if (copyid < 0) {
210 for (copyid = 1; copyid < HAMMER2_COPYID_COUNT; ++copyid) {
211 if (hmp->voldata.copyinfo[copyid].copyid == 0)
212 continue;
213 if (strcmp(remote->copy1.path,
214 hmp->voldata.copyinfo[copyid].path) == 0) {
215 break;
216 }
217 }
218 if (copyid == HAMMER2_COPYID_COUNT) {
219 error = ENOENT;
220 goto failed;
221 }
222 }
223 hammer2_modify_volume(hmp);
224 hmp->voldata.copyinfo[copyid].copyid = 0;
225failed:
226 hammer2_voldata_unlock(hmp);
227 return (error);
228}
229
230/*
231 * Replace existing remote entry
232 */
233static int
ae183399 234hammer2_ioctl_remote_rep(hammer2_inode_t *ip, void *data)
2910a90c
MD
235{
236 hammer2_mount_t *hmp = ip->hmp;
237 hammer2_ioc_remote_t *remote = data;
238 int copyid = remote->copyid;
239
240 if (copyid < 0 || copyid >= HAMMER2_COPYID_COUNT)
241 return (EINVAL);
242
243 hammer2_voldata_lock(hmp);
244 hammer2_voldata_unlock(hmp);
245
246 return(0);
247}
248
249/*
250 * Retrieve communications socket
251 */
252static int
ae183399 253hammer2_ioctl_socket_get(hammer2_inode_t *ip, void *data)
2910a90c
MD
254{
255 return (EOPNOTSUPP);
256}
257
258/*
259 * Set communications socket for connection
260 */
261static int
ae183399 262hammer2_ioctl_socket_set(hammer2_inode_t *ip, void *data)
2910a90c
MD
263{
264 hammer2_mount_t *hmp = ip->hmp;
265 hammer2_ioc_remote_t *remote = data;
266 int copyid = remote->copyid;
267
268 if (copyid < 0 || copyid >= HAMMER2_COPYID_COUNT)
269 return (EINVAL);
270
271 hammer2_voldata_lock(hmp);
272 hammer2_voldata_unlock(hmp);
273
274 return(0);
275}
ae183399
MD
276
277/*
278 * Used to scan PFSs, which are directories under the super-root.
279 */
280static int
281hammer2_ioctl_pfs_get(hammer2_inode_t *ip, void *data)
282{
283 hammer2_mount_t *hmp = ip->hmp;
284 hammer2_ioc_pfs_t *pfs = data;
285 hammer2_chain_t *parent;
286 hammer2_chain_t *chain;
287 hammer2_inode_t *xip;
288 int error = 0;
289
290 parent = hmp->schain;
291 error = hammer2_chain_lock(hmp, parent, HAMMER2_RESOLVE_ALWAYS);
292 if (error)
293 goto done;
294
295 /*
296 * Search for the first key or specific key. Remember that keys
297 * can be returned in any order.
298 */
299 if (pfs->name_key == 0) {
300 chain = hammer2_chain_lookup(hmp, &parent,
301 0, (hammer2_key_t)-1, 0);
302 } else {
303 chain = hammer2_chain_lookup(hmp, &parent,
304 pfs->name_key, pfs->name_key, 0);
305 }
306 while (chain && chain->bref.type != HAMMER2_BREF_TYPE_INODE) {
307 chain = hammer2_chain_next(hmp, &parent, chain,
308 0, (hammer2_key_t)-1, 0);
309 }
310 if (chain) {
311 /*
312 * Load the data being returned by the ioctl.
313 */
314 xip = chain->u.ip;
315 pfs->name_key = xip->ip_data.name_key;
316 pfs->pfs_type = xip->ip_data.pfs_type;
317 pfs->pfs_id = xip->ip_data.pfs_id;
318 pfs->pfs_fsid = xip->ip_data.pfs_fsid;
319 KKASSERT(xip->ip_data.name_len < sizeof(pfs->name));
320 bcopy(xip->ip_data.filename, pfs->name,
321 xip->ip_data.name_len);
322 pfs->name[xip->ip_data.name_len] = 0;
323
324 /*
325 * Calculate the next field
326 */
327 do {
328 chain = hammer2_chain_next(hmp, &parent, chain,
329 0, (hammer2_key_t)-1, 0);
330 } while (chain && chain->bref.type != HAMMER2_BREF_TYPE_INODE);
331 if (chain) {
332 pfs->name_next = chain->u.ip->ip_data.name_key;
333 hammer2_chain_unlock(hmp, chain);
334 } else {
335 pfs->name_next = (hammer2_key_t)-1;
336 }
337 } else {
338 pfs->name_next = (hammer2_key_t)-1;
339 error = ENOENT;
340 }
341done:
342 hammer2_chain_unlock(hmp, parent);
343 return (error);
344}
345
346/*
347 * Create a new PFS under the super-root
348 */
349static int
350hammer2_ioctl_pfs_create(hammer2_inode_t *ip, void *data)
351{
352 hammer2_mount_t *hmp = ip->hmp;
353 hammer2_ioc_pfs_t *pfs = data;
354 hammer2_inode_t *nip = NULL;
355 int error;
356
357 pfs->name[sizeof(pfs->name) - 1] = 0; /* ensure 0-termination */
e4e20f48 358 error = hammer2_inode_create(hmp->schain->u.ip, NULL, NULL,
ae183399
MD
359 pfs->name, strlen(pfs->name),
360 &nip);
361 if (error == 0) {
362 hammer2_chain_modify(hmp, &nip->chain, 0);
363 nip->ip_data.pfs_type = pfs->pfs_type;
364 nip->ip_data.pfs_id = pfs->pfs_id;
e4e20f48 365 nip->ip_data.pfs_fsid = pfs->pfs_fsid;
ae183399
MD
366 hammer2_chain_unlock(hmp, &nip->chain);
367 }
368 return (error);
369}
370
371/*
372 * Destroy an existing PFS under the super-root
373 */
374static int
375hammer2_ioctl_pfs_delete(hammer2_inode_t *ip, void *data)
376{
377 hammer2_mount_t *hmp = ip->hmp;
378 hammer2_ioc_pfs_t *pfs = data;
379 int error;
380
381 error = hammer2_unlink_file(hmp->schain->u.ip,
004f88b4
MD
382 pfs->name, strlen(pfs->name),
383 0, NULL);
ae183399
MD
384 return (error);
385}