Merge branches 'hammer2' and 'master' of ssh://crater.dragonflybsd.org/repository...
[dragonfly.git] / sys / vfs / hammer2 / hammer2_ioctl.c
... / ...
CommitLineData
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
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_lookup(hammer2_inode_t *ip, void *data);
54static int hammer2_ioctl_pfs_create(hammer2_inode_t *ip, void *data);
55static int hammer2_ioctl_pfs_delete(hammer2_inode_t *ip, void *data);
56static int hammer2_ioctl_inode_get(hammer2_inode_t *ip, void *data);
57static int hammer2_ioctl_inode_set(hammer2_inode_t *ip, void *data);
58
59int
60hammer2_ioctl(hammer2_inode_t *ip, u_long com, void *data, int fflag,
61 struct ucred *cred)
62{
63 int error;
64
65 /*
66 * Standard root cred checks, will be selectively ignored below
67 * for ioctls that do not require root creds.
68 */
69 error = priv_check_cred(cred, PRIV_HAMMER_IOCTL, 0);
70
71 switch(com) {
72 case HAMMER2IOC_VERSION_GET:
73 error = hammer2_ioctl_version_get(ip, data);
74 break;
75 case HAMMER2IOC_REMOTE_GET:
76 if (error == 0)
77 error = hammer2_ioctl_remote_get(ip, data);
78 break;
79 case HAMMER2IOC_REMOTE_ADD:
80 if (error == 0)
81 error = hammer2_ioctl_remote_add(ip, data);
82 break;
83 case HAMMER2IOC_REMOTE_DEL:
84 if (error == 0)
85 error = hammer2_ioctl_remote_del(ip, data);
86 break;
87 case HAMMER2IOC_REMOTE_REP:
88 if (error == 0)
89 error = hammer2_ioctl_remote_rep(ip, data);
90 break;
91 case HAMMER2IOC_SOCKET_GET:
92 if (error == 0)
93 error = hammer2_ioctl_socket_get(ip, data);
94 break;
95 case HAMMER2IOC_SOCKET_SET:
96 if (error == 0)
97 error = hammer2_ioctl_socket_set(ip, data);
98 break;
99 case HAMMER2IOC_PFS_GET:
100 if (error == 0)
101 error = hammer2_ioctl_pfs_get(ip, data);
102 break;
103 case HAMMER2IOC_PFS_LOOKUP:
104 if (error == 0)
105 error = hammer2_ioctl_pfs_lookup(ip, data);
106 break;
107 case HAMMER2IOC_PFS_CREATE:
108 if (error == 0)
109 error = hammer2_ioctl_pfs_create(ip, data);
110 break;
111 case HAMMER2IOC_PFS_DELETE:
112 if (error == 0)
113 error = hammer2_ioctl_pfs_delete(ip, data);
114 break;
115 case HAMMER2IOC_INODE_GET:
116 error = hammer2_ioctl_inode_get(ip, data);
117 break;
118 case HAMMER2IOC_INODE_SET:
119 if (error == 0)
120 error = hammer2_ioctl_inode_set(ip, data);
121 break;
122 default:
123 error = EOPNOTSUPP;
124 break;
125 }
126 return (error);
127}
128
129/*
130 * Retrieve version and basic info
131 */
132static int
133hammer2_ioctl_version_get(hammer2_inode_t *ip, void *data)
134{
135 hammer2_mount_t *hmp = ip->hmp;
136 hammer2_ioc_version_t *version = data;
137
138 version->version = hmp->voldata.version;
139 return 0;
140}
141
142/*
143 * Retrieve information about a remote
144 */
145static int
146hammer2_ioctl_remote_get(hammer2_inode_t *ip, void *data)
147{
148 hammer2_mount_t *hmp = ip->hmp;
149 hammer2_ioc_remote_t *remote = data;
150 int copyid = remote->copyid;
151
152 if (copyid < 0 || copyid >= HAMMER2_COPYID_COUNT)
153 return (EINVAL);
154
155 hammer2_voldata_lock(hmp);
156 remote->copy1 = hmp->voldata.copyinfo[copyid];
157 hammer2_voldata_unlock(hmp);
158
159 /*
160 * Adjust nextid (GET only)
161 */
162 while (++copyid < HAMMER2_COPYID_COUNT &&
163 hmp->voldata.copyinfo[copyid].copyid == 0) {
164 ++copyid;
165 }
166 if (copyid == HAMMER2_COPYID_COUNT)
167 remote->nextid = -1;
168 else
169 remote->nextid = copyid;
170
171 return(0);
172}
173
174/*
175 * Add new remote entry
176 */
177static int
178hammer2_ioctl_remote_add(hammer2_inode_t *ip, void *data)
179{
180 hammer2_mount_t *hmp = ip->hmp;
181 hammer2_ioc_remote_t *remote = data;
182 int copyid = remote->copyid;
183 int error = 0;
184
185 if (copyid >= HAMMER2_COPYID_COUNT)
186 return (EINVAL);
187
188 hammer2_voldata_lock(hmp);
189 if (copyid < 0) {
190 for (copyid = 1; copyid < HAMMER2_COPYID_COUNT; ++copyid) {
191 if (hmp->voldata.copyinfo[copyid].copyid == 0)
192 break;
193 }
194 if (copyid == HAMMER2_COPYID_COUNT) {
195 error = ENOSPC;
196 goto failed;
197 }
198 }
199 hammer2_modify_volume(hmp);
200 kprintf("copyid %d\n", copyid);
201 remote->copy1.copyid = copyid;
202 hmp->voldata.copyinfo[copyid] = remote->copy1;
203failed:
204 hammer2_voldata_unlock(hmp);
205 return (error);
206}
207
208/*
209 * Delete existing remote entry
210 */
211static int
212hammer2_ioctl_remote_del(hammer2_inode_t *ip, void *data)
213{
214 hammer2_mount_t *hmp = ip->hmp;
215 hammer2_ioc_remote_t *remote = data;
216 int copyid = remote->copyid;
217 int error = 0;
218
219 if (copyid >= HAMMER2_COPYID_COUNT)
220 return (EINVAL);
221 remote->copy1.path[sizeof(remote->copy1.path) - 1] = 0;
222 hammer2_voldata_lock(hmp);
223 if (copyid < 0) {
224 for (copyid = 1; copyid < HAMMER2_COPYID_COUNT; ++copyid) {
225 if (hmp->voldata.copyinfo[copyid].copyid == 0)
226 continue;
227 if (strcmp(remote->copy1.path,
228 hmp->voldata.copyinfo[copyid].path) == 0) {
229 break;
230 }
231 }
232 if (copyid == HAMMER2_COPYID_COUNT) {
233 error = ENOENT;
234 goto failed;
235 }
236 }
237 hammer2_modify_volume(hmp);
238 hmp->voldata.copyinfo[copyid].copyid = 0;
239failed:
240 hammer2_voldata_unlock(hmp);
241 return (error);
242}
243
244/*
245 * Replace existing remote entry
246 */
247static int
248hammer2_ioctl_remote_rep(hammer2_inode_t *ip, void *data)
249{
250 hammer2_mount_t *hmp = ip->hmp;
251 hammer2_ioc_remote_t *remote = data;
252 int copyid = remote->copyid;
253
254 if (copyid < 0 || copyid >= HAMMER2_COPYID_COUNT)
255 return (EINVAL);
256
257 hammer2_voldata_lock(hmp);
258 hammer2_voldata_unlock(hmp);
259
260 return(0);
261}
262
263/*
264 * Retrieve communications socket
265 */
266static int
267hammer2_ioctl_socket_get(hammer2_inode_t *ip, void *data)
268{
269 return (EOPNOTSUPP);
270}
271
272/*
273 * Set communications socket for connection
274 */
275static int
276hammer2_ioctl_socket_set(hammer2_inode_t *ip, void *data)
277{
278 hammer2_mount_t *hmp = ip->hmp;
279 hammer2_ioc_remote_t *remote = data;
280 int copyid = remote->copyid;
281
282 if (copyid < 0 || copyid >= HAMMER2_COPYID_COUNT)
283 return (EINVAL);
284
285 hammer2_voldata_lock(hmp);
286 hammer2_voldata_unlock(hmp);
287
288 return(0);
289}
290
291/*
292 * Used to scan PFSs, which are directories under the super-root.
293 */
294static int
295hammer2_ioctl_pfs_get(hammer2_inode_t *ip, void *data)
296{
297 hammer2_mount_t *hmp = ip->hmp;
298 hammer2_ioc_pfs_t *pfs = data;
299 hammer2_chain_t *parent;
300 hammer2_chain_t *chain;
301 hammer2_inode_t *xip;
302 int error = 0;
303
304 parent = hmp->schain;
305 error = hammer2_chain_lock(hmp, parent, HAMMER2_RESOLVE_ALWAYS);
306 if (error)
307 goto done;
308
309 /*
310 * Search for the first key or specific key. Remember that keys
311 * can be returned in any order.
312 */
313 if (pfs->name_key == 0) {
314 chain = hammer2_chain_lookup(hmp, &parent,
315 0, (hammer2_key_t)-1, 0);
316 } else {
317 chain = hammer2_chain_lookup(hmp, &parent,
318 pfs->name_key, pfs->name_key, 0);
319 }
320 while (chain && chain->bref.type != HAMMER2_BREF_TYPE_INODE) {
321 chain = hammer2_chain_next(hmp, &parent, chain,
322 0, (hammer2_key_t)-1, 0);
323 }
324 if (chain) {
325 /*
326 * Load the data being returned by the ioctl.
327 */
328 xip = chain->u.ip;
329 pfs->name_key = xip->ip_data.name_key;
330 pfs->pfs_type = xip->ip_data.pfs_type;
331 pfs->pfs_clid = xip->ip_data.pfs_clid;
332 pfs->pfs_fsid = xip->ip_data.pfs_fsid;
333 KKASSERT(xip->ip_data.name_len < sizeof(pfs->name));
334 bcopy(xip->ip_data.filename, pfs->name,
335 xip->ip_data.name_len);
336 pfs->name[xip->ip_data.name_len] = 0;
337
338 /*
339 * Calculate the next field
340 */
341 do {
342 chain = hammer2_chain_next(hmp, &parent, chain,
343 0, (hammer2_key_t)-1, 0);
344 } while (chain && chain->bref.type != HAMMER2_BREF_TYPE_INODE);
345 if (chain) {
346 pfs->name_next = chain->u.ip->ip_data.name_key;
347 hammer2_chain_unlock(hmp, chain);
348 } else {
349 pfs->name_next = (hammer2_key_t)-1;
350 }
351 } else {
352 pfs->name_next = (hammer2_key_t)-1;
353 error = ENOENT;
354 }
355done:
356 hammer2_chain_unlock(hmp, parent);
357 return (error);
358}
359
360/*
361 * Find a specific PFS by name
362 */
363static int
364hammer2_ioctl_pfs_lookup(hammer2_inode_t *ip, void *data)
365{
366 hammer2_mount_t *hmp = ip->hmp;
367 hammer2_ioc_pfs_t *pfs = data;
368 hammer2_chain_t *parent;
369 hammer2_chain_t *chain;
370 hammer2_inode_t *xip;
371 hammer2_key_t lhc;
372 int error = 0;
373 size_t len;
374
375 parent = hmp->schain;
376 error = hammer2_chain_lock(hmp, parent, HAMMER2_RESOLVE_ALWAYS |
377 HAMMER2_RESOLVE_SHARED);
378 if (error)
379 goto done;
380
381 pfs->name[sizeof(pfs->name) - 1] = 0;
382 len = strlen(pfs->name);
383 lhc = hammer2_dirhash(pfs->name, len);
384
385 chain = hammer2_chain_lookup(hmp, &parent,
386 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
387 HAMMER2_LOOKUP_SHARED);
388 while (chain) {
389 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
390 chain->u.ip &&
391 len == chain->data->ipdata.name_len &&
392 bcmp(pfs->name, chain->data->ipdata.filename, len) == 0) {
393 break;
394 }
395 chain = hammer2_chain_next(hmp, &parent, chain,
396 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
397 HAMMER2_LOOKUP_SHARED);
398 }
399
400 /*
401 * Load the data being returned by the ioctl.
402 */
403 if (chain) {
404 xip = chain->u.ip;
405 pfs->name_key = xip->ip_data.name_key;
406 pfs->pfs_type = xip->ip_data.pfs_type;
407 pfs->pfs_clid = xip->ip_data.pfs_clid;
408 pfs->pfs_fsid = xip->ip_data.pfs_fsid;
409
410 hammer2_chain_unlock(hmp, chain);
411 } else {
412 error = ENOENT;
413 }
414done:
415 hammer2_chain_unlock(hmp, parent);
416 return (error);
417}
418
419/*
420 * Create a new PFS under the super-root
421 */
422static int
423hammer2_ioctl_pfs_create(hammer2_inode_t *ip, void *data)
424{
425 hammer2_mount_t *hmp = ip->hmp;
426 hammer2_ioc_pfs_t *pfs = data;
427 hammer2_inode_t *nip = NULL;
428 int error;
429
430 pfs->name[sizeof(pfs->name) - 1] = 0; /* ensure 0-termination */
431 error = hammer2_inode_create(hmp->schain->u.ip, NULL, NULL,
432 pfs->name, strlen(pfs->name),
433 &nip);
434 if (error == 0) {
435 hammer2_chain_modify(hmp, &nip->chain, 0);
436 nip->ip_data.pfs_type = pfs->pfs_type;
437 nip->ip_data.pfs_clid = pfs->pfs_clid;
438 nip->ip_data.pfs_fsid = pfs->pfs_fsid;
439 hammer2_chain_unlock(hmp, &nip->chain);
440 }
441 return (error);
442}
443
444/*
445 * Destroy an existing PFS under the super-root
446 */
447static int
448hammer2_ioctl_pfs_delete(hammer2_inode_t *ip, void *data)
449{
450 hammer2_mount_t *hmp = ip->hmp;
451 hammer2_ioc_pfs_t *pfs = data;
452 int error;
453
454 error = hammer2_unlink_file(hmp->schain->u.ip,
455 pfs->name, strlen(pfs->name),
456 0, NULL);
457 return (error);
458}
459
460/*
461 * Retrieve the raw inode structure
462 */
463static int
464hammer2_ioctl_inode_get(hammer2_inode_t *ip, void *data)
465{
466 hammer2_ioc_inode_t *ino = data;
467
468 hammer2_inode_lock_sh(ip);
469 ino->ip_data = ip->ip_data;
470 ino->kdata = ip;
471 hammer2_inode_unlock_sh(ip);
472 return (0);
473}
474
475static int
476hammer2_ioctl_inode_set(hammer2_inode_t *ip, void *data)
477{
478 hammer2_ioc_inode_t *ino = data;
479 int error = EINVAL;
480
481 hammer2_inode_lock_ex(ip);
482 if (ino->flags & HAMMER2IOC_INODE_FLAG_IQUOTA) {
483 }
484 if (ino->flags & HAMMER2IOC_INODE_FLAG_DQUOTA) {
485 }
486 if (ino->flags & HAMMER2IOC_INODE_FLAG_COPIES) {
487 }
488 hammer2_inode_unlock_ex(ip);
489 return (error);
490}