2 * Copyright (c) 2011-2012 The DragonFly Project. All rights reserved.
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>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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
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.
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
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.
45 static int hammer2_ioctl_version_get(hammer2_inode_t *ip, void *data);
46 static int hammer2_ioctl_remote_get(hammer2_inode_t *ip, void *data);
47 static int hammer2_ioctl_remote_add(hammer2_inode_t *ip, void *data);
48 static int hammer2_ioctl_remote_del(hammer2_inode_t *ip, void *data);
49 static int hammer2_ioctl_remote_rep(hammer2_inode_t *ip, void *data);
50 static int hammer2_ioctl_socket_get(hammer2_inode_t *ip, void *data);
51 static int hammer2_ioctl_socket_set(hammer2_inode_t *ip, void *data);
52 static int hammer2_ioctl_pfs_get(hammer2_inode_t *ip, void *data);
53 static int hammer2_ioctl_pfs_create(hammer2_inode_t *ip, void *data);
54 static int hammer2_ioctl_pfs_delete(hammer2_inode_t *ip, void *data);
55 static int hammer2_ioctl_inode_get(hammer2_inode_t *ip, void *data);
56 static int hammer2_ioctl_inode_set(hammer2_inode_t *ip, void *data);
59 hammer2_ioctl(hammer2_inode_t *ip, u_long com, void *data, int fflag,
65 * Standard root cred checks, will be selectively ignored below
66 * for ioctls that do not require root creds.
68 error = priv_check_cred(cred, PRIV_HAMMER_IOCTL, 0);
71 case HAMMER2IOC_VERSION_GET:
72 error = hammer2_ioctl_version_get(ip, data);
74 case HAMMER2IOC_REMOTE_GET:
76 error = hammer2_ioctl_remote_get(ip, data);
78 case HAMMER2IOC_REMOTE_ADD:
80 error = hammer2_ioctl_remote_add(ip, data);
82 case HAMMER2IOC_REMOTE_DEL:
84 error = hammer2_ioctl_remote_del(ip, data);
86 case HAMMER2IOC_REMOTE_REP:
88 error = hammer2_ioctl_remote_rep(ip, data);
90 case HAMMER2IOC_SOCKET_GET:
92 error = hammer2_ioctl_socket_get(ip, data);
94 case HAMMER2IOC_SOCKET_SET:
96 error = hammer2_ioctl_socket_set(ip, data);
98 case HAMMER2IOC_PFS_GET:
100 error = hammer2_ioctl_pfs_get(ip, data);
102 case HAMMER2IOC_PFS_CREATE:
104 error = hammer2_ioctl_pfs_create(ip, data);
106 case HAMMER2IOC_PFS_DELETE:
108 error = hammer2_ioctl_pfs_delete(ip, data);
110 case HAMMER2IOC_INODE_GET:
111 error = hammer2_ioctl_inode_get(ip, data);
113 case HAMMER2IOC_INODE_SET:
115 error = hammer2_ioctl_inode_set(ip, data);
125 * Retrieve version and basic info
128 hammer2_ioctl_version_get(hammer2_inode_t *ip, void *data)
130 hammer2_mount_t *hmp = ip->hmp;
131 hammer2_ioc_version_t *version = data;
133 version->version = hmp->voldata.version;
138 * Retrieve information about a remote
141 hammer2_ioctl_remote_get(hammer2_inode_t *ip, void *data)
143 hammer2_mount_t *hmp = ip->hmp;
144 hammer2_ioc_remote_t *remote = data;
145 int copyid = remote->copyid;
147 if (copyid < 0 || copyid >= HAMMER2_COPYID_COUNT)
150 hammer2_voldata_lock(hmp);
151 remote->copy1 = hmp->voldata.copyinfo[copyid];
152 hammer2_voldata_unlock(hmp);
155 * Adjust nextid (GET only)
157 while (++copyid < HAMMER2_COPYID_COUNT &&
158 hmp->voldata.copyinfo[copyid].copyid == 0) {
161 if (copyid == HAMMER2_COPYID_COUNT)
164 remote->nextid = copyid;
170 * Add new remote entry
173 hammer2_ioctl_remote_add(hammer2_inode_t *ip, void *data)
175 hammer2_mount_t *hmp = ip->hmp;
176 hammer2_ioc_remote_t *remote = data;
177 int copyid = remote->copyid;
180 if (copyid >= HAMMER2_COPYID_COUNT)
183 hammer2_voldata_lock(hmp);
185 for (copyid = 1; copyid < HAMMER2_COPYID_COUNT; ++copyid) {
186 if (hmp->voldata.copyinfo[copyid].copyid == 0)
189 if (copyid == HAMMER2_COPYID_COUNT) {
194 hammer2_modify_volume(hmp);
195 kprintf("copyid %d\n", copyid);
196 remote->copy1.copyid = copyid;
197 hmp->voldata.copyinfo[copyid] = remote->copy1;
199 hammer2_voldata_unlock(hmp);
204 * Delete existing remote entry
207 hammer2_ioctl_remote_del(hammer2_inode_t *ip, void *data)
209 hammer2_mount_t *hmp = ip->hmp;
210 hammer2_ioc_remote_t *remote = data;
211 int copyid = remote->copyid;
214 if (copyid >= HAMMER2_COPYID_COUNT)
216 remote->copy1.path[sizeof(remote->copy1.path) - 1] = 0;
217 hammer2_voldata_lock(hmp);
219 for (copyid = 1; copyid < HAMMER2_COPYID_COUNT; ++copyid) {
220 if (hmp->voldata.copyinfo[copyid].copyid == 0)
222 if (strcmp(remote->copy1.path,
223 hmp->voldata.copyinfo[copyid].path) == 0) {
227 if (copyid == HAMMER2_COPYID_COUNT) {
232 hammer2_modify_volume(hmp);
233 hmp->voldata.copyinfo[copyid].copyid = 0;
235 hammer2_voldata_unlock(hmp);
240 * Replace existing remote entry
243 hammer2_ioctl_remote_rep(hammer2_inode_t *ip, void *data)
245 hammer2_mount_t *hmp = ip->hmp;
246 hammer2_ioc_remote_t *remote = data;
247 int copyid = remote->copyid;
249 if (copyid < 0 || copyid >= HAMMER2_COPYID_COUNT)
252 hammer2_voldata_lock(hmp);
253 hammer2_voldata_unlock(hmp);
259 * Retrieve communications socket
262 hammer2_ioctl_socket_get(hammer2_inode_t *ip, void *data)
268 * Set communications socket for connection
271 hammer2_ioctl_socket_set(hammer2_inode_t *ip, void *data)
273 hammer2_mount_t *hmp = ip->hmp;
274 hammer2_ioc_remote_t *remote = data;
275 int copyid = remote->copyid;
277 if (copyid < 0 || copyid >= HAMMER2_COPYID_COUNT)
280 hammer2_voldata_lock(hmp);
281 hammer2_voldata_unlock(hmp);
287 * Used to scan PFSs, which are directories under the super-root.
290 hammer2_ioctl_pfs_get(hammer2_inode_t *ip, void *data)
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;
299 parent = hmp->schain;
300 error = hammer2_chain_lock(hmp, parent, HAMMER2_RESOLVE_ALWAYS);
305 * Search for the first key or specific key. Remember that keys
306 * can be returned in any order.
308 if (pfs->name_key == 0) {
309 chain = hammer2_chain_lookup(hmp, &parent,
310 0, (hammer2_key_t)-1, 0);
312 chain = hammer2_chain_lookup(hmp, &parent,
313 pfs->name_key, pfs->name_key, 0);
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);
321 * Load the data being returned by the ioctl.
324 pfs->name_key = xip->ip_data.name_key;
325 pfs->pfs_type = xip->ip_data.pfs_type;
326 pfs->pfs_id = xip->ip_data.pfs_id;
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;
334 * Calculate the next field
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);
341 pfs->name_next = chain->u.ip->ip_data.name_key;
342 hammer2_chain_unlock(hmp, chain);
344 pfs->name_next = (hammer2_key_t)-1;
347 pfs->name_next = (hammer2_key_t)-1;
351 hammer2_chain_unlock(hmp, parent);
356 * Create a new PFS under the super-root
359 hammer2_ioctl_pfs_create(hammer2_inode_t *ip, void *data)
361 hammer2_mount_t *hmp = ip->hmp;
362 hammer2_ioc_pfs_t *pfs = data;
363 hammer2_inode_t *nip = NULL;
366 pfs->name[sizeof(pfs->name) - 1] = 0; /* ensure 0-termination */
367 error = hammer2_inode_create(hmp->schain->u.ip, NULL, NULL,
368 pfs->name, strlen(pfs->name),
371 hammer2_chain_modify(hmp, &nip->chain, 0);
372 nip->ip_data.pfs_type = pfs->pfs_type;
373 nip->ip_data.pfs_id = pfs->pfs_id;
374 nip->ip_data.pfs_fsid = pfs->pfs_fsid;
375 hammer2_chain_unlock(hmp, &nip->chain);
381 * Destroy an existing PFS under the super-root
384 hammer2_ioctl_pfs_delete(hammer2_inode_t *ip, void *data)
386 hammer2_mount_t *hmp = ip->hmp;
387 hammer2_ioc_pfs_t *pfs = data;
390 error = hammer2_unlink_file(hmp->schain->u.ip,
391 pfs->name, strlen(pfs->name),
397 * Retrieve the raw inode structure
400 hammer2_ioctl_inode_get(hammer2_inode_t *ip, void *data)
402 hammer2_ioc_inode_t *ino = data;
404 hammer2_inode_lock_sh(ip);
405 ino->ip_data = ip->ip_data;
407 hammer2_inode_unlock_sh(ip);
412 hammer2_ioctl_inode_set(hammer2_inode_t *ip, void *data)
414 hammer2_ioc_inode_t *ino = data;
417 hammer2_inode_lock_ex(ip);
418 if (ino->flags & HAMMER2IOC_INODE_FLAG_IQUOTA) {
420 if (ino->flags & HAMMER2IOC_INODE_FLAG_DQUOTA) {
422 if (ino->flags & HAMMER2IOC_INODE_FLAG_COPIES) {
424 hammer2_inode_unlock_ex(ip);