xref: /dragonfly/sys/vfs/hammer2/hammer2_ioctl.c (revision dc71b7ab)
1 /*
2  * Copyright (c) 2011-2013 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 
45 static int hammer2_ioctl_version_get(hammer2_inode_t *ip, void *data);
46 static int hammer2_ioctl_recluster(hammer2_inode_t *ip, void *data);
47 static int hammer2_ioctl_remote_scan(hammer2_inode_t *ip, void *data);
48 static int hammer2_ioctl_remote_add(hammer2_inode_t *ip, void *data);
49 static int hammer2_ioctl_remote_del(hammer2_inode_t *ip, void *data);
50 static int hammer2_ioctl_remote_rep(hammer2_inode_t *ip, void *data);
51 static int hammer2_ioctl_socket_get(hammer2_inode_t *ip, void *data);
52 static int hammer2_ioctl_socket_set(hammer2_inode_t *ip, void *data);
53 static int hammer2_ioctl_pfs_get(hammer2_inode_t *ip, void *data);
54 static int hammer2_ioctl_pfs_lookup(hammer2_inode_t *ip, void *data);
55 static int hammer2_ioctl_pfs_create(hammer2_inode_t *ip, void *data);
56 static int hammer2_ioctl_pfs_snapshot(hammer2_inode_t *ip, void *data);
57 static int hammer2_ioctl_pfs_delete(hammer2_inode_t *ip, void *data);
58 static int hammer2_ioctl_inode_get(hammer2_inode_t *ip, void *data);
59 static int hammer2_ioctl_inode_set(hammer2_inode_t *ip, void *data);
60 
61 int
62 hammer2_ioctl(hammer2_inode_t *ip, u_long com, void *data, int fflag,
63 	      struct ucred *cred)
64 {
65 	int error;
66 
67 	/*
68 	 * Standard root cred checks, will be selectively ignored below
69 	 * for ioctls that do not require root creds.
70 	 */
71 	error = priv_check_cred(cred, PRIV_HAMMER_IOCTL, 0);
72 
73 	switch(com) {
74 	case HAMMER2IOC_VERSION_GET:
75 		error = hammer2_ioctl_version_get(ip, data);
76 		break;
77 	case HAMMER2IOC_RECLUSTER:
78 		if (error == 0)
79 			error = hammer2_ioctl_recluster(ip, data);
80 		break;
81 	case HAMMER2IOC_REMOTE_SCAN:
82 		if (error == 0)
83 			error = hammer2_ioctl_remote_scan(ip, data);
84 		break;
85 	case HAMMER2IOC_REMOTE_ADD:
86 		if (error == 0)
87 			error = hammer2_ioctl_remote_add(ip, data);
88 		break;
89 	case HAMMER2IOC_REMOTE_DEL:
90 		if (error == 0)
91 			error = hammer2_ioctl_remote_del(ip, data);
92 		break;
93 	case HAMMER2IOC_REMOTE_REP:
94 		if (error == 0)
95 			error = hammer2_ioctl_remote_rep(ip, data);
96 		break;
97 	case HAMMER2IOC_SOCKET_GET:
98 		if (error == 0)
99 			error = hammer2_ioctl_socket_get(ip, data);
100 		break;
101 	case HAMMER2IOC_SOCKET_SET:
102 		if (error == 0)
103 			error = hammer2_ioctl_socket_set(ip, data);
104 		break;
105 	case HAMMER2IOC_PFS_GET:
106 		if (error == 0)
107 			error = hammer2_ioctl_pfs_get(ip, data);
108 		break;
109 	case HAMMER2IOC_PFS_LOOKUP:
110 		if (error == 0)
111 			error = hammer2_ioctl_pfs_lookup(ip, data);
112 		break;
113 	case HAMMER2IOC_PFS_CREATE:
114 		if (error == 0)
115 			error = hammer2_ioctl_pfs_create(ip, data);
116 		break;
117 	case HAMMER2IOC_PFS_DELETE:
118 		if (error == 0)
119 			error = hammer2_ioctl_pfs_delete(ip, data);
120 		break;
121 	case HAMMER2IOC_PFS_SNAPSHOT:
122 		if (error == 0)
123 			error = hammer2_ioctl_pfs_snapshot(ip, data);
124 		break;
125 	case HAMMER2IOC_INODE_GET:
126 		error = hammer2_ioctl_inode_get(ip, data);
127 		break;
128 	case HAMMER2IOC_INODE_SET:
129 		if (error == 0)
130 			error = hammer2_ioctl_inode_set(ip, data);
131 		break;
132 	default:
133 		error = EOPNOTSUPP;
134 		break;
135 	}
136 	return (error);
137 }
138 
139 /*
140  * Retrieve version and basic info
141  */
142 static int
143 hammer2_ioctl_version_get(hammer2_inode_t *ip, void *data)
144 {
145 	hammer2_mount_t *hmp = ip->hmp;
146 	hammer2_ioc_version_t *version = data;
147 
148 	version->version = hmp->voldata.version;
149 	return 0;
150 }
151 
152 static int
153 hammer2_ioctl_recluster(hammer2_inode_t *ip, void *data)
154 {
155 	hammer2_ioc_recluster_t *recl = data;
156 	struct file *fp;
157 
158 	fp = holdfp(curproc->p_fd, recl->fd, -1);
159 	if (fp) {
160 		kprintf("reconnect to cluster\n");
161 		hammer2_cluster_reconnect(ip->pmp, fp);
162 		return 0;
163 	} else {
164 		return EINVAL;
165 	}
166 }
167 
168 /*
169  * Retrieve information about a remote
170  */
171 static int
172 hammer2_ioctl_remote_scan(hammer2_inode_t *ip, void *data)
173 {
174 	hammer2_mount_t *hmp = ip->hmp;
175 	hammer2_ioc_remote_t *remote = data;
176 	int copyid = remote->copyid;
177 
178 	if (copyid < 0 || copyid >= HAMMER2_COPYID_COUNT)
179 		return (EINVAL);
180 
181 	hammer2_voldata_lock(hmp);
182 	remote->copy1 = hmp->voldata.copyinfo[copyid];
183 	hammer2_voldata_unlock(hmp, 0);
184 
185 	/*
186 	 * Adjust nextid (GET only)
187 	 */
188 	while (++copyid < HAMMER2_COPYID_COUNT &&
189 	       hmp->voldata.copyinfo[copyid].copyid == 0) {
190 		;
191 	}
192 	if (copyid == HAMMER2_COPYID_COUNT)
193 		remote->nextid = -1;
194 	else
195 		remote->nextid = copyid;
196 
197 	return(0);
198 }
199 
200 /*
201  * Add new remote entry
202  */
203 static int
204 hammer2_ioctl_remote_add(hammer2_inode_t *ip, void *data)
205 {
206 	hammer2_mount_t *hmp = ip->hmp;
207 	hammer2_pfsmount_t *pmp = ip->pmp;
208 	hammer2_ioc_remote_t *remote = data;
209 	int copyid = remote->copyid;
210 	int error = 0;
211 
212 	if (copyid >= HAMMER2_COPYID_COUNT)
213 		return (EINVAL);
214 
215 	hammer2_voldata_lock(hmp);
216 	if (copyid < 0) {
217 		for (copyid = 1; copyid < HAMMER2_COPYID_COUNT; ++copyid) {
218 			if (hmp->voldata.copyinfo[copyid].copyid == 0)
219 				break;
220 		}
221 		if (copyid == HAMMER2_COPYID_COUNT) {
222 			error = ENOSPC;
223 			goto failed;
224 		}
225 	}
226 	hammer2_modify_volume(hmp);
227 	remote->copy1.copyid = copyid;
228 	hmp->voldata.copyinfo[copyid] = remote->copy1;
229 	hammer2_volconf_update(pmp, copyid);
230 failed:
231 	hammer2_voldata_unlock(hmp, 1);
232 	return (error);
233 }
234 
235 /*
236  * Delete existing remote entry
237  */
238 static int
239 hammer2_ioctl_remote_del(hammer2_inode_t *ip, void *data)
240 {
241 	hammer2_mount_t *hmp = ip->hmp;
242 	hammer2_pfsmount_t *pmp = ip->pmp;
243 	hammer2_ioc_remote_t *remote = data;
244 	int copyid = remote->copyid;
245 	int error = 0;
246 
247 	if (copyid >= HAMMER2_COPYID_COUNT)
248 		return (EINVAL);
249 	remote->copy1.path[sizeof(remote->copy1.path) - 1] = 0;
250 	hammer2_voldata_lock(hmp);
251 	if (copyid < 0) {
252 		for (copyid = 1; copyid < HAMMER2_COPYID_COUNT; ++copyid) {
253 			if (hmp->voldata.copyinfo[copyid].copyid == 0)
254 				continue;
255 			if (strcmp(remote->copy1.path,
256 			    hmp->voldata.copyinfo[copyid].path) == 0) {
257 				break;
258 			}
259 		}
260 		if (copyid == HAMMER2_COPYID_COUNT) {
261 			error = ENOENT;
262 			goto failed;
263 		}
264 	}
265 	hammer2_modify_volume(hmp);
266 	hmp->voldata.copyinfo[copyid].copyid = 0;
267 	hammer2_volconf_update(pmp, copyid);
268 failed:
269 	hammer2_voldata_unlock(hmp, 1);
270 	return (error);
271 }
272 
273 /*
274  * Replace existing remote entry
275  */
276 static int
277 hammer2_ioctl_remote_rep(hammer2_inode_t *ip, void *data)
278 {
279 	hammer2_mount_t *hmp = ip->hmp;
280 	hammer2_ioc_remote_t *remote = data;
281 	int copyid = remote->copyid;
282 
283 	if (copyid < 0 || copyid >= HAMMER2_COPYID_COUNT)
284 		return (EINVAL);
285 
286 	hammer2_voldata_lock(hmp);
287 	/*hammer2_volconf_update(pmp, copyid);*/
288 	hammer2_voldata_unlock(hmp, 1);
289 
290 	return(0);
291 }
292 
293 /*
294  * Retrieve communications socket
295  */
296 static int
297 hammer2_ioctl_socket_get(hammer2_inode_t *ip, void *data)
298 {
299 	return (EOPNOTSUPP);
300 }
301 
302 /*
303  * Set communications socket for connection
304  */
305 static int
306 hammer2_ioctl_socket_set(hammer2_inode_t *ip, void *data)
307 {
308 	hammer2_mount_t *hmp = ip->hmp;
309 	hammer2_ioc_remote_t *remote = data;
310 	int copyid = remote->copyid;
311 
312 	if (copyid < 0 || copyid >= HAMMER2_COPYID_COUNT)
313 		return (EINVAL);
314 
315 	hammer2_voldata_lock(hmp);
316 	hammer2_voldata_unlock(hmp, 0);
317 
318 	return(0);
319 }
320 
321 /*
322  * Used to scan and retrieve PFS information.  PFS's are directories under
323  * the super-root.
324  *
325  * To scan PFSs pass name_key=0.  The function will scan for the next
326  * PFS and set all fields, as well as set name_next to the next key.
327  * When no PFSs remain, name_next is set to (hammer2_key_t)-1.
328  *
329  * To retrieve the PFS associated with the file descriptor, pass
330  * name_key set to (hammer2_key_t)-1.
331  */
332 static int
333 hammer2_ioctl_pfs_get(hammer2_inode_t *ip, void *data)
334 {
335 	hammer2_inode_data_t *ipdata;
336 	hammer2_mount_t *hmp;
337 	hammer2_ioc_pfs_t *pfs;
338 	hammer2_chain_t *parent;
339 	hammer2_chain_t *chain;
340 	hammer2_chain_t *rchain;
341 	int error;
342 
343 	error = 0;
344 	hmp = ip->hmp;
345 	pfs = data;
346 	parent = hammer2_chain_lookup_init(hmp->schain, 0);
347 	rchain = ip->pmp->rchain;
348 
349 	/*
350 	 * Search for the first key or specific key.  Remember that keys
351 	 * can be returned in any order.
352 	 */
353 	if (pfs->name_key == 0) {
354 		chain = hammer2_chain_lookup(&parent,
355 					     0, (hammer2_key_t)-1, 0);
356 	} else if (pfs->name_key == (hammer2_key_t)-1) {
357 		chain = hammer2_chain_lookup(&parent,
358 					     rchain->data->ipdata.name_key,
359 					     rchain->data->ipdata.name_key,
360 					     0);
361 	} else {
362 		chain = hammer2_chain_lookup(&parent,
363 					     pfs->name_key, pfs->name_key, 0);
364 	}
365 	while (chain && chain->bref.type != HAMMER2_BREF_TYPE_INODE) {
366 		chain = hammer2_chain_next(&parent, chain,
367 					   0, (hammer2_key_t)-1, 0);
368 	}
369 	if (chain) {
370 		/*
371 		 * Load the data being returned by the ioctl.
372 		 */
373 		ipdata = &chain->data->ipdata;
374 		pfs->name_key = ipdata->name_key;
375 		pfs->pfs_type = ipdata->pfs_type;
376 		pfs->pfs_clid = ipdata->pfs_clid;
377 		pfs->pfs_fsid = ipdata->pfs_fsid;
378 		KKASSERT(ipdata->name_len < sizeof(pfs->name));
379 		bcopy(ipdata->filename, pfs->name, ipdata->name_len);
380 		pfs->name[ipdata->name_len] = 0;
381 		ipdata = NULL;	/* safety */
382 
383 		/*
384 		 * Calculate the next field
385 		 */
386 		do {
387 			chain = hammer2_chain_next(&parent, chain,
388 						   0, (hammer2_key_t)-1, 0);
389 		} while (chain && chain->bref.type != HAMMER2_BREF_TYPE_INODE);
390 		if (chain) {
391 			pfs->name_next = chain->data->ipdata.name_key;
392 			hammer2_chain_unlock(chain);
393 		} else {
394 			pfs->name_next = (hammer2_key_t)-1;
395 		}
396 	} else {
397 		pfs->name_next = (hammer2_key_t)-1;
398 		error = ENOENT;
399 	}
400 	hammer2_chain_lookup_done(parent);
401 
402 	return (error);
403 }
404 
405 /*
406  * Find a specific PFS by name
407  */
408 static int
409 hammer2_ioctl_pfs_lookup(hammer2_inode_t *ip, void *data)
410 {
411 	hammer2_inode_data_t *ipdata;
412 	hammer2_mount_t *hmp;
413 	hammer2_ioc_pfs_t *pfs;
414 	hammer2_chain_t *parent;
415 	hammer2_chain_t *chain;
416 	hammer2_key_t lhc;
417 	int error;
418 	size_t len;
419 
420 	error = 0;
421 	hmp = ip->hmp;
422 	pfs = data;
423 	parent = hammer2_chain_lookup_init(hmp->schain, HAMMER2_LOOKUP_SHARED);
424 
425 	pfs->name[sizeof(pfs->name) - 1] = 0;
426 	len = strlen(pfs->name);
427 	lhc = hammer2_dirhash(pfs->name, len);
428 
429 	chain = hammer2_chain_lookup(&parent,
430 				     lhc, lhc + HAMMER2_DIRHASH_LOMASK,
431 				     HAMMER2_LOOKUP_SHARED);
432 	while (chain) {
433 		if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
434 		    len == chain->data->ipdata.name_len &&
435 		    bcmp(pfs->name, chain->data->ipdata.filename, len) == 0) {
436 			break;
437 		}
438 		chain = hammer2_chain_next(&parent, chain,
439 					   lhc, lhc + HAMMER2_DIRHASH_LOMASK,
440 					   HAMMER2_LOOKUP_SHARED);
441 	}
442 
443 	/*
444 	 * Load the data being returned by the ioctl.
445 	 */
446 	if (chain) {
447 		ipdata = &chain->data->ipdata;
448 		pfs->name_key = ipdata->name_key;
449 		pfs->pfs_type = ipdata->pfs_type;
450 		pfs->pfs_clid = ipdata->pfs_clid;
451 		pfs->pfs_fsid = ipdata->pfs_fsid;
452 		ipdata = NULL;
453 
454 		hammer2_chain_unlock(chain);
455 	} else {
456 		error = ENOENT;
457 	}
458 	hammer2_chain_lookup_done(parent);
459 	return (error);
460 }
461 
462 /*
463  * Create a new PFS under the super-root
464  */
465 static int
466 hammer2_ioctl_pfs_create(hammer2_inode_t *ip, void *data)
467 {
468 	hammer2_inode_data_t *nipdata;
469 	hammer2_mount_t *hmp;
470 	hammer2_ioc_pfs_t *pfs;
471 	hammer2_inode_t *nip;
472 	hammer2_chain_t *nchain;
473 	hammer2_trans_t trans;
474 	int error;
475 
476 	hmp = ip->hmp;
477 	pfs = data;
478 	nip = NULL;
479 
480 	if (pfs->name[0] == 0)
481 		return(EINVAL);
482 	pfs->name[sizeof(pfs->name) - 1] = 0;	/* ensure 0-termination */
483 
484 	hammer2_trans_init(&trans, hmp, ip, 0);
485 	nip = hammer2_inode_create(&trans, hmp->sroot, NULL, NULL,
486 				     pfs->name, strlen(pfs->name),
487 				     &nchain, &error);
488 	if (error == 0) {
489 		nipdata = hammer2_chain_modify_ip(&trans, nip, &nchain,
490 						  HAMMER2_MODIFY_ASSERTNOCOPY);
491 		nipdata->pfs_type = pfs->pfs_type;
492 		nipdata->pfs_clid = pfs->pfs_clid;
493 		nipdata->pfs_fsid = pfs->pfs_fsid;
494 		hammer2_inode_unlock_ex(nip, nchain);
495 	}
496 	hammer2_trans_done(&trans);
497 	return (error);
498 }
499 
500 /*
501  * Destroy an existing PFS under the super-root
502  */
503 static int
504 hammer2_ioctl_pfs_delete(hammer2_inode_t *ip, void *data)
505 {
506 	hammer2_mount_t *hmp = ip->hmp;
507 	hammer2_ioc_pfs_t *pfs = data;
508 	hammer2_trans_t trans;
509 	int error;
510 
511 	hammer2_trans_init(&trans, hmp, ip, 0);
512 	error = hammer2_unlink_file(&trans, hmp->sroot,
513 				    pfs->name, strlen(pfs->name),
514 				    2, NULL);
515 	hammer2_trans_done(&trans);
516 
517 	return (error);
518 }
519 
520 static int
521 hammer2_ioctl_pfs_snapshot(hammer2_inode_t *ip, void *data)
522 {
523 	hammer2_mount_t *hmp = ip->hmp;
524 	hammer2_ioc_pfs_t *pfs = data;
525 	hammer2_trans_t trans;
526 	hammer2_chain_t *parent;
527 	int error;
528 
529 	if (pfs->name[0] == 0)
530 		return(EINVAL);
531 	if (pfs->name[sizeof(pfs->name)-1] != 0)
532 		return(EINVAL);
533 
534 	hammer2_trans_init(&trans, hmp, ip, 0);
535 	parent = hammer2_inode_lock_ex(ip);
536 	error = hammer2_chain_snapshot(&trans, ip, pfs);
537 	hammer2_inode_unlock_ex(ip, parent);
538 	hammer2_trans_done(&trans);
539 
540 	return (error);
541 }
542 
543 /*
544  * Retrieve the raw inode structure
545  */
546 static int
547 hammer2_ioctl_inode_get(hammer2_inode_t *ip, void *data)
548 {
549 	hammer2_ioc_inode_t *ino = data;
550 	hammer2_chain_t *parent;
551 
552 	parent = hammer2_inode_lock_sh(ip);
553 	ino->ip_data = ip->chain->data->ipdata;
554 	ino->kdata = ip;
555 	hammer2_inode_unlock_sh(ip, parent);
556 
557 	return (0);
558 }
559 
560 static int
561 hammer2_ioctl_inode_set(hammer2_inode_t *ip, void *data)
562 {
563 	hammer2_ioc_inode_t *ino = data;
564 	hammer2_chain_t *parent;
565 	int error = EINVAL;
566 
567 	parent = hammer2_inode_lock_ex(ip);
568 	if (ino->flags & HAMMER2IOC_INODE_FLAG_IQUOTA) {
569 	}
570 	if (ino->flags & HAMMER2IOC_INODE_FLAG_DQUOTA) {
571 	}
572 	if (ino->flags & HAMMER2IOC_INODE_FLAG_COPIES) {
573 	}
574 	hammer2_inode_unlock_ex(ip, parent);
575 
576 	return (error);
577 }
578