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