xref: /dflybsd-src/usr.sbin/makefs/hammer2/hammer2_ioctl.c (revision 9046282cb0de32785f628069936b116eddd42899)
1  /*
2   * SPDX-License-Identifier: BSD-3-Clause
3   *
4   * Copyright (c) 2023 Tomohiro Kusumi <tkusumi@netbsd.org>
5   * Copyright (c) 2011-2023 The DragonFly Project.  All rights reserved.
6   *
7   * This code is derived from software contributed to The DragonFly Project
8   * by Matthew Dillon <dillon@dragonflybsd.org>
9   *
10   * Redistribution and use in source and binary forms, with or without
11   * modification, are permitted provided that the following conditions
12   * are met:
13   *
14   * 1. Redistributions of source code must retain the above copyright
15   *    notice, this list of conditions and the following disclaimer.
16   * 2. Redistributions in binary form must reproduce the above copyright
17   *    notice, this list of conditions and the following disclaimer in
18   *    the documentation and/or other materials provided with the
19   *    distribution.
20   * 3. Neither the name of The DragonFly Project nor the names of its
21   *    contributors may be used to endorse or promote products derived
22   *    from this software without specific, prior written permission.
23   *
24   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25   * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27   * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
28   * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29   * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
30   * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
32   * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
34   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35   * SUCH DAMAGE.
36   */
37  /*
38   * Ioctl Functions.
39   *
40   * WARNING! The ioctl functions which manipulate the connection state need
41   *	    to be able to run without deadlock on the volume's chain lock.
42   *	    Most of these functions use a separate lock.
43   */
44  #include <sys/diskslice.h>
45  
46  #include "hammer2.h"
47  #include "makefs.h"
48  
49  #if 0
50  #include <sys/kern_syscall.h>
51  
52  static int hammer2_ioctl_version_get(hammer2_inode_t *ip, void *data);
53  static int hammer2_ioctl_recluster(hammer2_inode_t *ip, void *data);
54  static int hammer2_ioctl_remote_scan(hammer2_inode_t *ip, void *data);
55  static int hammer2_ioctl_remote_add(hammer2_inode_t *ip, void *data);
56  static int hammer2_ioctl_remote_del(hammer2_inode_t *ip, void *data);
57  static int hammer2_ioctl_remote_rep(hammer2_inode_t *ip, void *data);
58  static int hammer2_ioctl_socket_get(hammer2_inode_t *ip, void *data);
59  static int hammer2_ioctl_socket_set(hammer2_inode_t *ip, void *data);
60  static int hammer2_ioctl_pfs_get(hammer2_inode_t *ip, void *data);
61  static int hammer2_ioctl_pfs_lookup(hammer2_inode_t *ip, void *data);
62  static int hammer2_ioctl_pfs_create(hammer2_inode_t *ip, void *data);
63  static int hammer2_ioctl_pfs_snapshot(hammer2_inode_t *ip, void *data);
64  static int hammer2_ioctl_pfs_delete(hammer2_inode_t *ip, void *data);
65  static int hammer2_ioctl_inode_get(hammer2_inode_t *ip, void *data);
66  static int hammer2_ioctl_inode_set(hammer2_inode_t *ip, void *data);
67  static int hammer2_ioctl_debug_dump(hammer2_inode_t *ip, u_int flags);
68  static int hammer2_ioctl_emerg_mode(hammer2_inode_t *ip, u_int mode);
69  static int hammer2_ioctl_growfs(hammer2_inode_t *ip, void *data,
70  			struct ucred *cred);
71  //static int hammer2_ioctl_inode_comp_set(hammer2_inode_t *ip, void *data);
72  //static int hammer2_ioctl_inode_comp_rec_set(hammer2_inode_t *ip, void *data);
73  //static int hammer2_ioctl_inode_comp_rec_set2(hammer2_inode_t *ip, void *data);
74  static int hammer2_ioctl_bulkfree_scan(hammer2_inode_t *ip, void *data);
75  static int hammer2_ioctl_destroy(hammer2_inode_t *ip, void *data);
76  static int hammer2_ioctl_volume_list(hammer2_inode_t *ip, void *data);
77  
78  int
79  hammer2_ioctl(hammer2_inode_t *ip, u_long com, void *data, int fflag,
80  	      struct ucred *cred)
81  {
82  	int error;
83  
84  	/*
85  	 * Standard root cred checks, will be selectively ignored below
86  	 * for ioctls that do not require root creds.
87  	 */
88  	error = priv_check_cred(cred, PRIV_HAMMER_IOCTL, 0);
89  
90  	switch(com) {
91  	case HAMMER2IOC_VERSION_GET:
92  		error = hammer2_ioctl_version_get(ip, data);
93  		break;
94  	case HAMMER2IOC_RECLUSTER:
95  		if (error == 0)
96  			error = hammer2_ioctl_recluster(ip, data);
97  		break;
98  	case HAMMER2IOC_REMOTE_SCAN:
99  		if (error == 0)
100  			error = hammer2_ioctl_remote_scan(ip, data);
101  		break;
102  	case HAMMER2IOC_REMOTE_ADD:
103  		if (error == 0)
104  			error = hammer2_ioctl_remote_add(ip, data);
105  		break;
106  	case HAMMER2IOC_REMOTE_DEL:
107  		if (error == 0)
108  			error = hammer2_ioctl_remote_del(ip, data);
109  		break;
110  	case HAMMER2IOC_REMOTE_REP:
111  		if (error == 0)
112  			error = hammer2_ioctl_remote_rep(ip, data);
113  		break;
114  	case HAMMER2IOC_SOCKET_GET:
115  		if (error == 0)
116  			error = hammer2_ioctl_socket_get(ip, data);
117  		break;
118  	case HAMMER2IOC_SOCKET_SET:
119  		if (error == 0)
120  			error = hammer2_ioctl_socket_set(ip, data);
121  		break;
122  	case HAMMER2IOC_PFS_GET:
123  		if (error == 0)
124  			error = hammer2_ioctl_pfs_get(ip, data);
125  		break;
126  	case HAMMER2IOC_PFS_LOOKUP:
127  		if (error == 0)
128  			error = hammer2_ioctl_pfs_lookup(ip, data);
129  		break;
130  	case HAMMER2IOC_PFS_CREATE:
131  		if (error == 0)
132  			error = hammer2_ioctl_pfs_create(ip, data);
133  		break;
134  	case HAMMER2IOC_PFS_DELETE:
135  		if (error == 0)
136  			error = hammer2_ioctl_pfs_delete(ip, data);
137  		break;
138  	case HAMMER2IOC_PFS_SNAPSHOT:
139  		if (error == 0)
140  			error = hammer2_ioctl_pfs_snapshot(ip, data);
141  		break;
142  	case HAMMER2IOC_INODE_GET:
143  		error = hammer2_ioctl_inode_get(ip, data);
144  		break;
145  	case HAMMER2IOC_INODE_SET:
146  		if (error == 0)
147  			error = hammer2_ioctl_inode_set(ip, data);
148  		break;
149  	case HAMMER2IOC_BULKFREE_SCAN:
150  		error = hammer2_ioctl_bulkfree_scan(ip, data);
151  		break;
152  	case HAMMER2IOC_BULKFREE_ASYNC:
153  		error = hammer2_ioctl_bulkfree_scan(ip, NULL);
154  		break;
155  	case HAMMER2IOC_DESTROY:
156  		if (error == 0)
157  			error = hammer2_ioctl_destroy(ip, data);
158  		break;
159  	case HAMMER2IOC_DEBUG_DUMP:
160  		error = hammer2_ioctl_debug_dump(ip, *(u_int *)data);
161  		break;
162  	case HAMMER2IOC_EMERG_MODE:
163  		if (error == 0)
164  			error = hammer2_ioctl_emerg_mode(ip, *(u_int *)data);
165  		break;
166  	case HAMMER2IOC_GROWFS:
167  		if (error == 0)
168  			error = hammer2_ioctl_growfs(ip, data, cred);
169  		break;
170  	case HAMMER2IOC_VOLUME_LIST:
171  		if (error == 0)
172  			error = hammer2_ioctl_volume_list(ip, data);
173  		break;
174  	default:
175  		error = EOPNOTSUPP;
176  		break;
177  	}
178  	return (error);
179  }
180  #endif
181  
182  /*
183   * Retrieve version and basic info
184   */
185  int
186  hammer2_ioctl_version_get(hammer2_inode_t *ip, void *data)
187  {
188  	hammer2_ioc_version_t *version = data;
189  	hammer2_dev_t *hmp;
190  
191  	hmp = ip->pmp->pfs_hmps[0];
192  	if (hmp)
193  		version->version = hmp->voldata.version;
194  	else
195  		version->version = -1;
196  	return 0;
197  }
198  
199  #if 0
200  static int
201  hammer2_ioctl_recluster(hammer2_inode_t *ip, void *data)
202  {
203  	hammer2_ioc_recluster_t *recl = data;
204  	struct vnode *vproot;
205  	struct file *fp;
206  	hammer2_cluster_t *cluster;
207  	int error;
208  
209  	fp = holdfp(curthread, recl->fd, -1);
210  	if (fp) {
211  		error = VFS_ROOT(ip->pmp->mp, &vproot);
212  		if (error == 0) {
213  			cluster = &ip->pmp->iroot->cluster;
214  			kprintf("reconnect to cluster: nc=%d focus=%p\n",
215  				cluster->nchains, cluster->focus);
216  			if (cluster->nchains != 1 || cluster->focus == NULL) {
217  				kprintf("not a local device mount\n");
218  				error = EINVAL;
219  			} else {
220  				hammer2_cluster_reconnect(cluster->focus->hmp,
221  							  fp);
222  				kprintf("ok\n");
223  				error = 0;
224  			}
225  			vput(vproot);
226  		}
227  	} else {
228  		error = EINVAL;
229  	}
230  	return error;
231  }
232  
233  /*
234   * Retrieve information about a remote
235   */
236  static int
237  hammer2_ioctl_remote_scan(hammer2_inode_t *ip, void *data)
238  {
239  	hammer2_dev_t *hmp;
240  	hammer2_ioc_remote_t *remote = data;
241  	int copyid = remote->copyid;
242  
243  	hmp = ip->pmp->pfs_hmps[0];
244  	if (hmp == NULL)
245  		return (EINVAL);
246  
247  	if (copyid < 0 || copyid >= HAMMER2_COPYID_COUNT)
248  		return (EINVAL);
249  
250  	hammer2_voldata_lock(hmp);
251  	remote->copy1 = hmp->voldata.copyinfo[copyid];
252  	hammer2_voldata_unlock(hmp);
253  
254  	/*
255  	 * Adjust nextid (GET only)
256  	 */
257  	while (++copyid < HAMMER2_COPYID_COUNT &&
258  	       hmp->voldata.copyinfo[copyid].copyid == 0) {
259  		;
260  	}
261  	if (copyid == HAMMER2_COPYID_COUNT)
262  		remote->nextid = -1;
263  	else
264  		remote->nextid = copyid;
265  
266  	return(0);
267  }
268  
269  /*
270   * Add new remote entry
271   */
272  static int
273  hammer2_ioctl_remote_add(hammer2_inode_t *ip, void *data)
274  {
275  	hammer2_ioc_remote_t *remote = data;
276  	hammer2_pfs_t *pmp = ip->pmp;
277  	hammer2_dev_t *hmp;
278  	int copyid = remote->copyid;
279  	int error = 0;
280  
281  	hmp = pmp->pfs_hmps[0];
282  	if (hmp == NULL)
283  		return (EINVAL);
284  	if (copyid >= HAMMER2_COPYID_COUNT)
285  		return (EINVAL);
286  
287  	hammer2_voldata_lock(hmp);
288  	if (copyid < 0) {
289  		for (copyid = 1; copyid < HAMMER2_COPYID_COUNT; ++copyid) {
290  			if (hmp->voldata.copyinfo[copyid].copyid == 0)
291  				break;
292  		}
293  		if (copyid == HAMMER2_COPYID_COUNT) {
294  			error = ENOSPC;
295  			goto failed;
296  		}
297  	}
298  	hammer2_voldata_modify(hmp);
299  	remote->copy1.copyid = copyid;
300  	hmp->voldata.copyinfo[copyid] = remote->copy1;
301  	hammer2_volconf_update(hmp, copyid);
302  failed:
303  	hammer2_voldata_unlock(hmp);
304  	return (error);
305  }
306  
307  /*
308   * Delete existing remote entry
309   */
310  static int
311  hammer2_ioctl_remote_del(hammer2_inode_t *ip, void *data)
312  {
313  	hammer2_ioc_remote_t *remote = data;
314  	hammer2_pfs_t *pmp = ip->pmp;
315  	hammer2_dev_t *hmp;
316  	int copyid = remote->copyid;
317  	int error = 0;
318  
319  	hmp = pmp->pfs_hmps[0];
320  	if (hmp == NULL)
321  		return (EINVAL);
322  	if (copyid >= HAMMER2_COPYID_COUNT)
323  		return (EINVAL);
324  	remote->copy1.path[sizeof(remote->copy1.path) - 1] = 0;
325  	hammer2_voldata_lock(hmp);
326  	if (copyid < 0) {
327  		for (copyid = 1; copyid < HAMMER2_COPYID_COUNT; ++copyid) {
328  			if (hmp->voldata.copyinfo[copyid].copyid == 0)
329  				continue;
330  			if (strcmp(remote->copy1.path,
331  			    hmp->voldata.copyinfo[copyid].path) == 0) {
332  				break;
333  			}
334  		}
335  		if (copyid == HAMMER2_COPYID_COUNT) {
336  			error = ENOENT;
337  			goto failed;
338  		}
339  	}
340  	hammer2_voldata_modify(hmp);
341  	hmp->voldata.copyinfo[copyid].copyid = 0;
342  	hammer2_volconf_update(hmp, copyid);
343  failed:
344  	hammer2_voldata_unlock(hmp);
345  	return (error);
346  }
347  
348  /*
349   * Replace existing remote entry
350   */
351  static int
352  hammer2_ioctl_remote_rep(hammer2_inode_t *ip, void *data)
353  {
354  	hammer2_ioc_remote_t *remote = data;
355  	hammer2_dev_t *hmp;
356  	int copyid = remote->copyid;
357  
358  	hmp = ip->pmp->pfs_hmps[0];
359  	if (hmp == NULL)
360  		return (EINVAL);
361  	if (copyid < 0 || copyid >= HAMMER2_COPYID_COUNT)
362  		return (EINVAL);
363  
364  	hammer2_voldata_lock(hmp);
365  	hammer2_voldata_modify(hmp);
366  	/*hammer2_volconf_update(hmp, copyid);*/
367  	hammer2_voldata_unlock(hmp);
368  
369  	return(0);
370  }
371  
372  /*
373   * Retrieve communications socket
374   */
375  static int
376  hammer2_ioctl_socket_get(hammer2_inode_t *ip, void *data)
377  {
378  	return (EOPNOTSUPP);
379  }
380  
381  /*
382   * Set communications socket for connection
383   */
384  static int
385  hammer2_ioctl_socket_set(hammer2_inode_t *ip, void *data)
386  {
387  	hammer2_ioc_remote_t *remote = data;
388  	hammer2_dev_t *hmp;
389  	int copyid = remote->copyid;
390  
391  	hmp = ip->pmp->pfs_hmps[0];
392  	if (hmp == NULL)
393  		return (EINVAL);
394  	if (copyid < 0 || copyid >= HAMMER2_COPYID_COUNT)
395  		return (EINVAL);
396  
397  	hammer2_voldata_lock(hmp);
398  	hammer2_voldata_unlock(hmp);
399  
400  	return(0);
401  }
402  #endif
403  
404  /*
405   * Used to scan and retrieve PFS information.  PFS's are directories under
406   * the super-root.
407   *
408   * To scan PFSs pass name_key=0.  The function will scan for the next
409   * PFS and set all fields, as well as set name_next to the next key.
410   * When no PFSs remain, name_next is set to (hammer2_key_t)-1.
411   *
412   * To retrieve a particular PFS by key, specify the key but note that
413   * the ioctl will return the lowest key >= specified_key, so the caller
414   * must verify the key.
415   *
416   * To retrieve the PFS associated with the file descriptor, pass
417   * name_key set to (hammer2_key_t)-1.
418   */
419  int
420  hammer2_ioctl_pfs_get(hammer2_inode_t *ip, void *data)
421  {
422  	const hammer2_inode_data_t *ripdata;
423  	hammer2_dev_t *hmp;
424  	hammer2_ioc_pfs_t *pfs;
425  	hammer2_chain_t *parent;
426  	hammer2_chain_t *chain;
427  	hammer2_key_t key_next;
428  	hammer2_key_t save_key;
429  	int error;
430  
431  	hmp = ip->pmp->pfs_hmps[0];
432  	if (hmp == NULL)
433  		return (EINVAL);
434  
435  	pfs = data;
436  	save_key = pfs->name_key;
437  	error = 0;
438  
439  	/*
440  	 * Setup
441  	 */
442  	if (save_key == (hammer2_key_t)-1) {
443  		hammer2_inode_lock(ip->pmp->iroot, 0);
444  		parent = NULL;
445  		chain = hammer2_inode_chain(ip->pmp->iroot, 0,
446  					    HAMMER2_RESOLVE_ALWAYS |
447  					    HAMMER2_RESOLVE_SHARED);
448  	} else {
449  		hammer2_inode_lock(hmp->spmp->iroot, 0);
450  		parent = hammer2_inode_chain(hmp->spmp->iroot, 0,
451  					    HAMMER2_RESOLVE_ALWAYS |
452  					    HAMMER2_RESOLVE_SHARED);
453  		chain = hammer2_chain_lookup(&parent, &key_next,
454  					    pfs->name_key, HAMMER2_KEY_MAX,
455  					    &error,
456  					    HAMMER2_LOOKUP_SHARED);
457  	}
458  
459  	/*
460  	 * Locate next PFS
461  	 */
462  	while (chain) {
463  		if (chain->bref.type == HAMMER2_BREF_TYPE_INODE)
464  			break;
465  		if (parent == NULL) {
466  			hammer2_chain_unlock(chain);
467  			hammer2_chain_drop(chain);
468  			chain = NULL;
469  			break;
470  		}
471  		chain = hammer2_chain_next(&parent, chain, &key_next,
472  					    key_next, HAMMER2_KEY_MAX,
473  					    &error,
474  					    HAMMER2_LOOKUP_SHARED);
475  	}
476  	error = hammer2_error_to_errno(error);
477  
478  	/*
479  	 * Load the data being returned by the ioctl.
480  	 */
481  	if (chain && chain->error == 0) {
482  		ripdata = &chain->data->ipdata;
483  		pfs->name_key = ripdata->meta.name_key;
484  		pfs->pfs_type = ripdata->meta.pfs_type;
485  		pfs->pfs_subtype = ripdata->meta.pfs_subtype;
486  		pfs->pfs_clid = ripdata->meta.pfs_clid;
487  		pfs->pfs_fsid = ripdata->meta.pfs_fsid;
488  		KKASSERT(ripdata->meta.name_len < sizeof(pfs->name));
489  		bcopy(ripdata->filename, pfs->name, ripdata->meta.name_len);
490  		pfs->name[ripdata->meta.name_len] = 0;
491  		ripdata = NULL;	/* safety */
492  
493  		/*
494  		 * Calculate name_next, if any.  We are only accessing
495  		 * chain->bref so we can ignore chain->error (if the key
496  		 * is used later it will error then).
497  		 */
498  		if (parent == NULL) {
499  			pfs->name_next = (hammer2_key_t)-1;
500  		} else {
501  			chain = hammer2_chain_next(&parent, chain, &key_next,
502  						    key_next, HAMMER2_KEY_MAX,
503  						    &error,
504  						    HAMMER2_LOOKUP_SHARED);
505  			if (chain)
506  				pfs->name_next = chain->bref.key;
507  			else
508  				pfs->name_next = (hammer2_key_t)-1;
509  		}
510  	} else {
511  		pfs->name_next = (hammer2_key_t)-1;
512  		error = ENOENT;
513  	}
514  
515  	/*
516  	 * Cleanup
517  	 */
518  	if (chain) {
519  		hammer2_chain_unlock(chain);
520  		hammer2_chain_drop(chain);
521  	}
522  	if (parent) {
523  		hammer2_chain_unlock(parent);
524  		hammer2_chain_drop(parent);
525  	}
526  	if (save_key == (hammer2_key_t)-1) {
527  		hammer2_inode_unlock(ip->pmp->iroot);
528  	} else {
529  		hammer2_inode_unlock(hmp->spmp->iroot);
530  	}
531  
532  	return (error);
533  }
534  
535  /*
536   * Find a specific PFS by name
537   */
538  int
539  hammer2_ioctl_pfs_lookup(hammer2_inode_t *ip, void *data)
540  {
541  	const hammer2_inode_data_t *ripdata;
542  	hammer2_dev_t *hmp;
543  	hammer2_ioc_pfs_t *pfs;
544  	hammer2_chain_t *parent;
545  	hammer2_chain_t *chain;
546  	hammer2_key_t key_next;
547  	hammer2_key_t lhc;
548  	int error;
549  	size_t len;
550  
551  	hmp = ip->pmp->pfs_hmps[0];
552  	if (hmp == NULL)
553  		return (EINVAL);
554  
555  	pfs = data;
556  	error = 0;
557  
558  	hammer2_inode_lock(hmp->spmp->iroot, HAMMER2_RESOLVE_SHARED);
559  	parent = hammer2_inode_chain(hmp->spmp->iroot, 0,
560  				     HAMMER2_RESOLVE_ALWAYS |
561  				     HAMMER2_RESOLVE_SHARED);
562  
563  	pfs->name[sizeof(pfs->name) - 1] = 0;
564  	len = strlen(pfs->name);
565  	lhc = hammer2_dirhash(pfs->name, len);
566  
567  	chain = hammer2_chain_lookup(&parent, &key_next,
568  					 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
569  					 &error, HAMMER2_LOOKUP_SHARED);
570  	while (chain) {
571  		if (hammer2_chain_dirent_test(chain, pfs->name, len))
572  			break;
573  		chain = hammer2_chain_next(&parent, chain, &key_next,
574  					   key_next,
575  					   lhc + HAMMER2_DIRHASH_LOMASK,
576  					   &error, HAMMER2_LOOKUP_SHARED);
577  	}
578  	error = hammer2_error_to_errno(error);
579  
580  	/*
581  	 * Load the data being returned by the ioctl.
582  	 */
583  	if (chain && chain->error == 0) {
584  		KKASSERT(chain->bref.type == HAMMER2_BREF_TYPE_INODE);
585  		ripdata = &chain->data->ipdata;
586  		pfs->name_key = ripdata->meta.name_key;
587  		pfs->pfs_type = ripdata->meta.pfs_type;
588  		pfs->pfs_subtype = ripdata->meta.pfs_subtype;
589  		pfs->pfs_clid = ripdata->meta.pfs_clid;
590  		pfs->pfs_fsid = ripdata->meta.pfs_fsid;
591  		ripdata = NULL;
592  
593  		hammer2_chain_unlock(chain);
594  		hammer2_chain_drop(chain);
595  	} else if (error == 0) {
596  		error = ENOENT;
597  	}
598  	if (parent) {
599  		hammer2_chain_unlock(parent);
600  		hammer2_chain_drop(parent);
601  	}
602  	hammer2_inode_unlock(hmp->spmp->iroot);
603  
604  	return (error);
605  }
606  
607  /*
608   * Create a new PFS under the super-root
609   */
610  int
611  hammer2_ioctl_pfs_create(hammer2_inode_t *ip, void *data)
612  {
613  	hammer2_inode_data_t *nipdata;
614  	hammer2_chain_t *nchain;
615  	hammer2_dev_t *hmp;
616  	hammer2_dev_t *force_local;
617  	hammer2_ioc_pfs_t *pfs;
618  	hammer2_inode_t *nip;
619  	hammer2_tid_t mtid;
620  	int error;
621  
622  	hmp = ip->pmp->pfs_hmps[0];	/* XXX */
623  	if (hmp == NULL)
624  		return (EINVAL);
625  
626  	pfs = data;
627  	nip = NULL;
628  
629  	if (pfs->name[0] == 0)
630  		return(EINVAL);
631  	pfs->name[sizeof(pfs->name) - 1] = 0;	/* ensure 0-termination */
632  
633  	if (hammer2_ioctl_pfs_lookup(ip, pfs) == 0)
634  		return(EEXIST);
635  
636  	hammer2_trans_init(hmp->spmp, HAMMER2_TRANS_ISFLUSH);
637  	mtid = hammer2_trans_sub(hmp->spmp);
638  	nip = hammer2_inode_create_pfs(hmp->spmp, pfs->name, strlen(pfs->name),
639  				       &error);
640  	if (error == 0) {
641  		atomic_set_int(&nip->flags, HAMMER2_INODE_NOSIDEQ);
642  		hammer2_inode_modify(nip);
643  		nchain = hammer2_inode_chain(nip, 0, HAMMER2_RESOLVE_ALWAYS);
644  		error = hammer2_chain_modify(nchain, mtid, 0, 0);
645  		KKASSERT(error == 0);
646  		nipdata = &nchain->data->ipdata;
647  
648  		nip->meta.pfs_type = pfs->pfs_type;
649  		nip->meta.pfs_subtype = pfs->pfs_subtype;
650  		nip->meta.pfs_clid = pfs->pfs_clid;
651  		nip->meta.pfs_fsid = pfs->pfs_fsid;
652  		nip->meta.op_flags |= HAMMER2_OPFLAG_PFSROOT;
653  
654  		/*
655  		 * Set default compression and check algorithm.  This
656  		 * can be changed later.
657  		 *
658  		 * Do not allow compression on PFS's with the special name
659  		 * "boot", the boot loader can't decompress (yet).
660  		 */
661  		nip->meta.comp_algo =
662  			HAMMER2_ENC_ALGO(HAMMER2_COMP_DEFAULT);
663  		nip->meta.check_algo =
664  			HAMMER2_ENC_ALGO(HAMMER2_CHECK_DEFAULT);
665  
666  		if (strcasecmp(pfs->name, "boot") == 0) {
667  			nip->meta.comp_algo =
668  				HAMMER2_ENC_ALGO(HAMMER2_COMP_AUTOZERO);
669  		}
670  
671  		/*
672  		 * Super-root isn't mounted, fsync it
673  		 */
674  		hammer2_chain_unlock(nchain);
675  		hammer2_inode_ref(nip);
676  		hammer2_inode_unlock(nip);
677  		hammer2_inode_chain_sync(nip);
678  		hammer2_inode_chain_flush(nip, HAMMER2_XOP_INODE_STOP |
679  					       HAMMER2_XOP_FSSYNC);
680  		hammer2_inode_drop(nip);
681  		/* nip is dead */
682  
683  		/*
684  		 * We still have a ref on the chain, relock and associate
685  		 * with an appropriate PFS.
686  		 */
687  		force_local = (hmp->hflags & HMNT2_LOCAL) ? hmp : NULL;
688  
689  		hammer2_chain_lock(nchain, HAMMER2_RESOLVE_ALWAYS);
690  		nipdata = &nchain->data->ipdata;
691  		kprintf("ADD LOCAL PFS (IOCTL): %s\n", nipdata->filename);
692  		hammer2_pfsalloc(nchain, nipdata, force_local);
693  
694  		hammer2_chain_unlock(nchain);
695  		hammer2_chain_drop(nchain);
696  	}
697  	hammer2_trans_done(hmp->spmp, HAMMER2_TRANS_ISFLUSH |
698  				      HAMMER2_TRANS_SIDEQ);
699  
700  	return (error);
701  }
702  
703  /*
704   * Destroy an existing PFS under the super-root
705   */
706  int
707  hammer2_ioctl_pfs_delete(hammer2_inode_t *ip, void *data)
708  {
709  	hammer2_ioc_pfs_t *pfs = data;
710  	hammer2_dev_t	*hmp;
711  	hammer2_pfs_t	*spmp;
712  	hammer2_pfs_t	*pmp;
713  	hammer2_xop_unlink_t *xop;
714  	hammer2_inode_t *dip;
715  	int error;
716  	int i;
717  
718  	/*
719  	 * The PFS should be probed, so we should be able to
720  	 * locate it.  We only delete the PFS from the
721  	 * specific H2 block device (hmp), not all of
722  	 * them.  We must remove the PFS from the cluster
723  	 * before we can destroy it.
724  	 */
725  	hmp = ip->pmp->pfs_hmps[0];
726  	if (hmp == NULL)
727  		return (EINVAL);
728  
729  	pfs->name[sizeof(pfs->name) - 1] = 0;	/* ensure termination */
730  
731  	lockmgr(&hammer2_mntlk, LK_EXCLUSIVE);
732  
733  	TAILQ_FOREACH(pmp, &hammer2_pfslist, mntentry) {
734  		for (i = 0; i < HAMMER2_MAXCLUSTER; ++i) {
735  			if (pmp->pfs_hmps[i] != hmp)
736  				continue;
737  			if (pmp->pfs_names[i] &&
738  			    strcmp(pmp->pfs_names[i], pfs->name) == 0) {
739  				break;
740  			}
741  		}
742  		if (i != HAMMER2_MAXCLUSTER)
743  			break;
744  	}
745  
746  	if (pmp == NULL) {
747  		lockmgr(&hammer2_mntlk, LK_RELEASE);
748  		return ENOENT;
749  	}
750  	if (pmp->mp) {
751  		lockmgr(&hammer2_mntlk, LK_RELEASE);
752  		return EBUSY;
753  	}
754  
755  	/*
756  	 * Ok, we found the pmp and we have the index.  Permanently remove
757  	 * the PFS from the cluster
758  	 */
759  	kprintf("FOUND PFS %s CLINDEX %d\n", pfs->name, i);
760  	hammer2_pfsdealloc(pmp, i, 1);
761  
762  	lockmgr(&hammer2_mntlk, LK_RELEASE);
763  
764  	/*
765  	 * Now destroy the PFS under its device using the per-device
766  	 * super-root.
767  	 */
768  	spmp = hmp->spmp;
769  	dip = spmp->iroot;
770  	hammer2_trans_init(spmp, 0);
771  	hammer2_inode_lock(dip, 0);
772  
773  	xop = hammer2_xop_alloc(dip, HAMMER2_XOP_MODIFYING);
774  	hammer2_xop_setname(&xop->head, pfs->name, strlen(pfs->name));
775  	xop->isdir = 2;
776  	xop->dopermanent = H2DOPERM_PERMANENT | H2DOPERM_FORCE;
777  	hammer2_xop_start(&xop->head, &hammer2_unlink_desc);
778  
779  	error = hammer2_xop_collect(&xop->head, 0);
780  
781  	hammer2_inode_unlock(dip);
782  
783  #if 0
784  	if (error == 0) {
785  	        ip = hammer2_inode_get(dip->pmp, &xop->head, -1, -1);
786  	        hammer2_xop_retire(&xop->head, HAMMER2_XOPMASK_VOP);
787  	        if (ip) {
788  	                hammer2_inode_unlink_finisher(ip, NULL);
789  	                hammer2_inode_unlock(ip);
790  	        }
791  	} else {
792  	        hammer2_xop_retire(&xop->head, HAMMER2_XOPMASK_VOP);
793  	}
794  #endif
795  	hammer2_xop_retire(&xop->head, HAMMER2_XOPMASK_VOP);
796  
797  	hammer2_trans_done(spmp, HAMMER2_TRANS_SIDEQ);
798  
799  	return (hammer2_error_to_errno(error));
800  }
801  
802  int
803  hammer2_ioctl_pfs_snapshot(hammer2_inode_t *ip, void *data)
804  {
805  	hammer2_ioc_pfs_t *pfs = data;
806  	hammer2_dev_t	*hmp;
807  	hammer2_pfs_t	*pmp;
808  	hammer2_chain_t	*chain;
809  	hammer2_inode_t *nip;
810  	hammer2_tid_t	mtid;
811  	size_t name_len;
812  	int error;
813  #if 0
814  	uuid_t opfs_clid;
815  #endif
816  
817  	if (pfs->name[0] == 0)
818  		return(EINVAL);
819  	if (pfs->name[sizeof(pfs->name)-1] != 0)
820  		return(EINVAL);
821  
822  	pmp = ip->pmp;
823  	ip = pmp->iroot;
824  
825  	hmp = pmp->pfs_hmps[0];
826  	if (hmp == NULL)
827  		return (EINVAL);
828  
829  	lockmgr(&hmp->bulklk, LK_EXCLUSIVE);
830  
831  	/*
832  	 * NOSYNC is for debugging.  We skip the filesystem sync and use
833  	 * a normal transaction (which is less likely to stall).  used for
834  	 * testing filesystem consistency.
835  	 *
836  	 * In normal mode we sync the filesystem and use a flush transaction.
837  	 */
838  	if (pfs->pfs_flags & HAMMER2_PFSFLAGS_NOSYNC) {
839  		hammer2_trans_init(pmp, 0);
840  	} else {
841  		hammer2_vfs_sync(pmp->mp, MNT_WAIT);
842  		hammer2_trans_init(pmp, HAMMER2_TRANS_ISFLUSH);
843  	}
844  	mtid = hammer2_trans_sub(pmp);
845  	hammer2_inode_lock(ip, 0);
846  	hammer2_inode_modify(ip);
847  	ip->meta.pfs_lsnap_tid = mtid;
848  
849  	/* XXX cluster it! */
850  	chain = hammer2_inode_chain(ip, 0, HAMMER2_RESOLVE_ALWAYS);
851  
852  	name_len = strlen(pfs->name);
853  	hmp = chain->hmp;
854  
855  	/*
856  	 * Create the snapshot directory under the super-root
857  	 *
858  	 * Set PFS type, generate a unique filesystem id, and generate
859  	 * a cluster id.  Use the same clid when snapshotting a PFS root,
860  	 * which theoretically allows the snapshot to be used as part of
861  	 * the same cluster (perhaps as a cache).
862  	 *
863  	 * Note that pfs_lsnap_tid must be set in the snapshot as well,
864  	 * ensuring that any nocrc/nocomp file data modifications force
865  	 * a copy-on-write.
866  	 *
867  	 * Copy the (flushed) blockref array.  Theoretically we could use
868  	 * chain_duplicate() but it becomes difficult to disentangle
869  	 * the shared core so for now just brute-force it.
870  	 */
871  	hammer2_chain_unlock(chain);
872  	nip = hammer2_inode_create_pfs(hmp->spmp, pfs->name, name_len, &error);
873  	hammer2_chain_lock(chain, HAMMER2_RESOLVE_ALWAYS);
874  
875  	if (nip) {
876  		hammer2_dev_t *force_local;
877  		hammer2_chain_t *nchain;
878  		hammer2_inode_data_t *wipdata;
879  		hammer2_tid_t starting_inum;
880  
881  		atomic_set_int(&nip->flags, HAMMER2_INODE_NOSIDEQ);
882  		hammer2_inode_modify(nip);
883  		nchain = hammer2_inode_chain(nip, 0, HAMMER2_RESOLVE_ALWAYS);
884  		error = hammer2_chain_modify(nchain, mtid, 0, 0);
885  		KKASSERT(error == 0);
886  		wipdata = &nchain->data->ipdata;
887  
888  		starting_inum = ip->pmp->inode_tid + 1;
889  		nip->meta.pfs_inum = starting_inum;
890  		nip->meta.pfs_type = HAMMER2_PFSTYPE_MASTER;
891  		nip->meta.pfs_subtype = HAMMER2_PFSSUBTYPE_SNAPSHOT;
892  		nip->meta.op_flags |= HAMMER2_OPFLAG_PFSROOT;
893  		nip->meta.pfs_lsnap_tid = mtid;
894  		nchain->bref.embed.stats = chain->bref.embed.stats;
895  
896  		uuid_create(&nip->meta.pfs_fsid, NULL);
897  
898  #if 0
899  		/*
900  		 * Give the snapshot its own private cluster id.  As a
901  		 * snapshot no further synchronization with the original
902  		 * cluster will be done.
903  		 */
904  		if (chain->flags & HAMMER2_CHAIN_PFSBOUNDARY)
905  			nip->meta.pfs_clid = opfs_clid;
906  		else
907  			uuid_create(&nip->meta.pfs_clid, NULL);
908  #endif
909  		uuid_create(&nip->meta.pfs_clid, NULL);
910  		nchain->bref.flags |= HAMMER2_BREF_FLAG_PFSROOT;
911  
912  		/* XXX hack blockset copy */
913  		/* XXX doesn't work with real cluster */
914  		wipdata->meta = nip->meta;
915  		hammer2_spin_ex(&pmp->inum_spin);
916  		wipdata->u.blockset = pmp->pfs_iroot_blocksets[0];
917  		hammer2_spin_unex(&pmp->inum_spin);
918  
919  		KKASSERT(wipdata == &nchain->data->ipdata);
920  
921  		hammer2_chain_unlock(nchain);
922  		hammer2_inode_ref(nip);
923  		hammer2_inode_unlock(nip);
924  		hammer2_inode_chain_sync(nip);
925  		hammer2_inode_chain_flush(nip, HAMMER2_XOP_INODE_STOP |
926  					       HAMMER2_XOP_FSSYNC);
927  					       /* XXX | HAMMER2_XOP_VOLHDR */
928  		hammer2_inode_drop(nip);
929  		/* nip is dead */
930  
931  		force_local = (hmp->hflags & HMNT2_LOCAL) ? hmp : NULL;
932  
933  		hammer2_chain_lock(nchain, HAMMER2_RESOLVE_ALWAYS);
934  		wipdata = &nchain->data->ipdata;
935  		kprintf("SNAPSHOT LOCAL PFS (IOCTL): %s\n", wipdata->filename);
936  		hammer2_pfsalloc(nchain, wipdata, force_local);
937  		nchain->pmp->inode_tid = starting_inum;
938  
939  		hammer2_chain_unlock(nchain);
940  		hammer2_chain_drop(nchain);
941  	}
942  
943  	hammer2_chain_unlock(chain);
944  	hammer2_chain_drop(chain);
945  
946  	hammer2_inode_unlock(ip);
947  	if (pfs->pfs_flags & HAMMER2_PFSFLAGS_NOSYNC) {
948  		hammer2_trans_done(pmp, 0);
949  	} else {
950  		hammer2_trans_done(pmp, HAMMER2_TRANS_ISFLUSH |
951  					HAMMER2_TRANS_SIDEQ);
952  	}
953  
954  	lockmgr(&hmp->bulklk, LK_RELEASE);
955  
956  	return (hammer2_error_to_errno(error));
957  }
958  
959  /*
960   * Retrieve the raw inode structure, non-inclusive of node-specific data.
961   */
962  int
963  hammer2_ioctl_inode_get(hammer2_inode_t *ip, void *data)
964  {
965  	hammer2_ioc_inode_t *ino = data;
966  
967  	hammer2_inode_lock(ip, HAMMER2_RESOLVE_SHARED);
968  	ino->data_count = hammer2_inode_data_count(ip);
969  	ino->inode_count = hammer2_inode_inode_count(ip);
970  
971  	bzero(&ino->ip_data, sizeof(ino->ip_data));
972  	ino->ip_data.meta = ip->meta;
973  	hammer2_inode_unlock(ip);
974  
975  	return 0;
976  }
977  
978  /*
979   * Set various parameters in an inode which cannot be set through
980   * normal filesystem VNOPS.
981   */
982  int
983  hammer2_ioctl_inode_set(hammer2_inode_t *ip, void *data)
984  {
985  	hammer2_ioc_inode_t *ino = data;
986  
987  	hammer2_trans_init(ip->pmp, 0);
988  	hammer2_inode_lock(ip, 0);
989  
990  	if ((ino->flags & HAMMER2IOC_INODE_FLAG_CHECK) &&
991  	    ip->meta.check_algo != ino->ip_data.meta.check_algo) {
992  		hammer2_inode_modify(ip);
993  		ip->meta.check_algo = ino->ip_data.meta.check_algo;
994  	}
995  	if ((ino->flags & HAMMER2IOC_INODE_FLAG_COMP) &&
996  	    ip->meta.comp_algo != ino->ip_data.meta.comp_algo) {
997  		hammer2_inode_modify(ip);
998  		ip->meta.comp_algo = ino->ip_data.meta.comp_algo;
999  	}
1000  
1001  	/* Ignore these flags for now...*/
1002  	if ((ino->flags & HAMMER2IOC_INODE_FLAG_IQUOTA) &&
1003  	    ip->meta.inode_quota != ino->ip_data.meta.inode_quota) {
1004  		hammer2_inode_modify(ip);
1005  		ip->meta.inode_quota = ino->ip_data.meta.inode_quota;
1006  	}
1007  	if ((ino->flags & HAMMER2IOC_INODE_FLAG_DQUOTA) &&
1008  	    ip->meta.data_quota != ino->ip_data.meta.data_quota) {
1009  		hammer2_inode_modify(ip);
1010  		ip->meta.data_quota = ino->ip_data.meta.data_quota;
1011  	}
1012  	if ((ino->flags & HAMMER2IOC_INODE_FLAG_COPIES) &&
1013  	    ip->meta.ncopies != ino->ip_data.meta.ncopies) {
1014  		hammer2_inode_modify(ip);
1015  		ip->meta.ncopies = ino->ip_data.meta.ncopies;
1016  	}
1017  	hammer2_inode_unlock(ip);
1018  	hammer2_trans_done(ip->pmp, HAMMER2_TRANS_SIDEQ);
1019  
1020  	return (0);
1021  }
1022  
1023  #if 0
1024  static
1025  int
1026  hammer2_ioctl_debug_dump(hammer2_inode_t *ip, u_int flags)
1027  {
1028  	hammer2_chain_t *chain;
1029  	int count = 100000;
1030  	int i;
1031  
1032  	for (i = 0; i < ip->cluster.nchains; ++i) {
1033  		chain = ip->cluster.array[i].chain;
1034  		if (chain == NULL)
1035  			continue;
1036  		kprintf("cluster #%d\n", i);
1037  		hammer2_dump_chain(chain, 0, 0, &count, 'i', flags);
1038  	}
1039  	return 0;
1040  }
1041  #endif
1042  
1043  /*
1044   * Turn on or off emergency mode on a filesystem.
1045   */
1046  int
1047  hammer2_ioctl_emerg_mode(hammer2_inode_t *ip, u_int mode)
1048  {
1049  	hammer2_pfs_t *pmp;
1050  	hammer2_dev_t *hmp;
1051  	int i;
1052  
1053  	pmp = ip->pmp;
1054  	if (mode) {
1055  		kprintf("hammer2: WARNING: Emergency mode enabled\n");
1056  		atomic_set_int(&pmp->flags, HAMMER2_PMPF_EMERG);
1057  	} else {
1058  		kprintf("hammer2: WARNING: Emergency mode disabled\n");
1059  		atomic_clear_int(&pmp->flags, HAMMER2_PMPF_EMERG);
1060  	}
1061  	for (i = 0; i < HAMMER2_MAXCLUSTER; ++i) {
1062  		hmp = pmp->pfs_hmps[i];
1063  		if (hmp == NULL)
1064  			continue;
1065  		if (mode)
1066  			atomic_set_int(&hmp->hflags, HMNT2_EMERG);
1067  		else
1068  			atomic_clear_int(&hmp->hflags, HMNT2_EMERG);
1069  	}
1070  	return 0;
1071  }
1072  
1073  /*
1074   * Do a bulkfree scan on media related to the PFS.  This routine will
1075   * flush all PFSs associated with the media before doing the bulkfree
1076   * scan.
1077   *
1078   * This version can only run on non-clustered media.  A new ioctl or a
1079   * temporary mount of @LOCAL will be needed to run on clustered media.
1080   */
1081  int
1082  hammer2_ioctl_bulkfree_scan(hammer2_inode_t *ip, void *data)
1083  {
1084  	hammer2_ioc_bulkfree_t *bfi = data;
1085  	hammer2_dev_t	*hmp;
1086  	hammer2_pfs_t	*pmp;
1087  	hammer2_chain_t *vchain;
1088  	int error;
1089  	int didsnap;
1090  
1091  	pmp = ip->pmp;
1092  	ip = pmp->iroot;
1093  
1094  	hmp = pmp->pfs_hmps[0];
1095  	if (hmp == NULL)
1096  		return (EINVAL);
1097  	if (bfi == NULL)
1098  		return (EINVAL);
1099  
1100  	/*
1101  	 * Bulkfree has to be serialized to guarantee at least one sync
1102  	 * inbetween bulkfrees.
1103  	 */
1104  	error = lockmgr(&hmp->bflock, LK_EXCLUSIVE | LK_PCATCH);
1105  	if (error)
1106  		return error;
1107  
1108  	/*
1109  	 * Sync all mounts related to the media
1110  	 */
1111  	lockmgr(&hammer2_mntlk, LK_EXCLUSIVE);
1112  	TAILQ_FOREACH(pmp, &hammer2_pfslist, mntentry) {
1113  		int etmp;
1114  		int i;
1115  
1116  		for (i = 0; i < HAMMER2_MAXCLUSTER; ++i) {
1117  			if (pmp->pfs_hmps[i] != hmp)
1118  				continue;
1119  			etmp = hammer2_vfs_sync_pmp(pmp, MNT_WAIT);
1120  			if (etmp && (error == 0 || error == ENOSPC))
1121  				error = etmp;
1122  			break;
1123  		}
1124  	}
1125  	lockmgr(&hammer2_mntlk, LK_RELEASE);
1126  
1127  	if (error && error != ENOSPC)
1128  		goto failed;
1129  
1130  	/*
1131  	 * If we have an ENOSPC error we have to bulkfree on the live
1132  	 * topology.  Otherwise we can bulkfree on a snapshot.
1133  	 */
1134  	if (error) {
1135  		kprintf("hammer2: WARNING! Bulkfree forced to use live "
1136  			"topology due to ENOSPC\n");
1137  		vchain = &hmp->vchain;
1138  		hammer2_chain_ref(vchain);
1139  		didsnap = 0;
1140  	} else {
1141  		vchain = hammer2_chain_bulksnap(hmp);
1142  		didsnap = 1;
1143  	}
1144  
1145  	/*
1146  	 * Normal bulkfree operations do not require a transaction because
1147  	 * they operate on a snapshot, and so can run concurrently with
1148  	 * any operation except another bulkfree.
1149  	 *
1150  	 * If we are running bulkfree on the live topology we have to be
1151  	 * in a FLUSH transaction.
1152  	 */
1153  	if (didsnap == 0)
1154  		hammer2_trans_init(hmp->spmp, HAMMER2_TRANS_ISFLUSH);
1155  
1156  	if (bfi) {
1157  		hammer2_thr_freeze(&hmp->bfthr);
1158  		error = hammer2_bulkfree_pass(hmp, vchain, bfi);
1159  		hammer2_thr_unfreeze(&hmp->bfthr);
1160  	}
1161  	if (didsnap) {
1162  		hammer2_chain_bulkdrop(vchain);
1163  	} else {
1164  		hammer2_chain_drop(vchain);
1165  		hammer2_trans_done(hmp->spmp, HAMMER2_TRANS_ISFLUSH |
1166  					HAMMER2_TRANS_SIDEQ);
1167  	}
1168  	error = hammer2_error_to_errno(error);
1169  
1170  failed:
1171  	lockmgr(&hmp->bflock, LK_RELEASE);
1172  	return error;
1173  }
1174  
1175  /*
1176   * Unconditionally delete meta-data in a hammer2 filesystem
1177   */
1178  int
1179  hammer2_ioctl_destroy(hammer2_inode_t *ip, void *data)
1180  {
1181  	hammer2_ioc_destroy_t *iocd = data;
1182  	hammer2_pfs_t *pmp = ip->pmp;
1183  	int error;
1184  
1185  	if (pmp->ronly) {
1186  		error = EROFS;
1187  		return error;
1188  	}
1189  
1190  	switch(iocd->cmd) {
1191  	case HAMMER2_DELETE_FILE:
1192  		/*
1193  		 * Destroy a bad directory entry by name.  Caller must
1194  		 * pass the directory as fd.
1195  		 */
1196  		{
1197  		hammer2_xop_unlink_t *xop;
1198  
1199  		if (iocd->path[sizeof(iocd->path)-1]) {
1200  			error = EINVAL;
1201  			break;
1202  		}
1203  		if (ip->meta.type != HAMMER2_OBJTYPE_DIRECTORY) {
1204  			error = EINVAL;
1205  			break;
1206  		}
1207  		hammer2_pfs_memory_wait(pmp);
1208  		hammer2_trans_init(pmp, 0);
1209  		hammer2_inode_lock(ip, 0);
1210  
1211  		xop = hammer2_xop_alloc(ip, HAMMER2_XOP_MODIFYING);
1212  		hammer2_xop_setname(&xop->head, iocd->path, strlen(iocd->path));
1213  		xop->isdir = -1;
1214  		xop->dopermanent = H2DOPERM_PERMANENT |
1215  				   H2DOPERM_FORCE |
1216  				   H2DOPERM_IGNINO;
1217  		hammer2_xop_start(&xop->head, &hammer2_unlink_desc);
1218  
1219  		error = hammer2_xop_collect(&xop->head, 0);
1220  		error = hammer2_error_to_errno(error);
1221  		hammer2_inode_unlock(ip);
1222  		hammer2_xop_retire(&xop->head, HAMMER2_XOPMASK_VOP);
1223  		hammer2_trans_done(pmp, HAMMER2_TRANS_SIDEQ);
1224  		}
1225  		break;
1226  	case HAMMER2_DELETE_INUM:
1227  		/*
1228  		 * Destroy a bad inode by inode number.
1229  		 */
1230  		{
1231  		hammer2_xop_lookup_t *xop;
1232  
1233  		if (iocd->inum < 1) {
1234  			error = EINVAL;
1235  			break;
1236  		}
1237  		hammer2_pfs_memory_wait(pmp);
1238  		hammer2_trans_init(pmp, 0);
1239  
1240  		xop = hammer2_xop_alloc(pmp->iroot, HAMMER2_XOP_MODIFYING);
1241  		xop->lhc = iocd->inum;
1242  		hammer2_xop_start(&xop->head, &hammer2_delete_desc);
1243  		error = hammer2_xop_collect(&xop->head, 0);
1244  		error = hammer2_error_to_errno(error);
1245  		hammer2_xop_retire(&xop->head, HAMMER2_XOPMASK_VOP);
1246  		hammer2_trans_done(pmp, HAMMER2_TRANS_SIDEQ);
1247  		}
1248  		break;
1249  	default:
1250  		error = EINVAL;
1251  		break;
1252  	}
1253  	return error;
1254  }
1255  
1256  /*
1257   * Grow a filesystem into its partition size
1258   */
1259  int
1260  hammer2_ioctl_growfs(hammer2_inode_t *ip, void *data, struct ucred *cred)
1261  {
1262  	hammer2_ioc_growfs_t *grow = data;
1263  	hammer2_dev_t *hmp;
1264  	hammer2_off_t size, delta;
1265  	hammer2_tid_t mtid;
1266  	struct partinfo part;
1267  	struct stat st;
1268  	struct m_buf *bp;
1269  	int error;
1270  	int i;
1271  
1272  	hmp = ip->pmp->pfs_hmps[0];
1273  
1274  	if (hmp->nvolumes > 1) {
1275  		kprintf("hammer2: growfs currently unsupported "
1276  			"with multiple volumes\n");
1277  		return EOPNOTSUPP;
1278  	}
1279  	KKASSERT(hmp->total_size == hmp->voldata.volu_size);
1280  
1281  	/*
1282  	 * Extract from disklabel
1283  	 */
1284  	if (ioctl(hmp->devvp->fs->fd, DIOCGPART, &part) == 0) {
1285  		size = part.media_size;
1286  		kprintf("hammer2: growfs partition-auto to %016jx\n",
1287  			(intmax_t)size);
1288  	} else if (fstat(hmp->devvp->fs->fd, &st) == 0) {
1289  		size = st.st_size;
1290  		kprintf("hammer2: growfs fstat-auto to %016jx\n",
1291  			(intmax_t)size);
1292  	} else {
1293  		return EINVAL;
1294  	}
1295  
1296  	/*
1297  	 * Expand to devvp size unless specified.
1298  	 */
1299  	grow->modified = 0;
1300  	if (grow->size == 0) {
1301  		grow->size = size;
1302  	} else if (grow->size > size) {
1303  		kprintf("hammer2: growfs size %016jx exceeds device size "
1304  			"%016jx\n",
1305  			(intmax_t)grow->size, (intmax_t)size);
1306  		return EINVAL;
1307  	}
1308  
1309  	/*
1310  	 * This is typically ~8MB alignment to avoid edge cases accessing
1311  	 * reserved blocks at the base of each 2GB zone.
1312  	 */
1313  	grow->size &= ~HAMMER2_VOLUME_ALIGNMASK64;
1314  	delta = grow->size - hmp->voldata.volu_size;
1315  
1316  	/*
1317  	 * Maximum allowed size is 2^63
1318  	 */
1319  	if (grow->size > 0x7FFFFFFFFFFFFFFFLU) {
1320  		kprintf("hammer2: growfs failure, limit is 2^63 - 1 bytes\n");
1321  		return EINVAL;
1322  	}
1323  
1324  	/*
1325  	 * We can't shrink a filesystem
1326  	 */
1327  	if (grow->size < hmp->voldata.volu_size) {
1328  		kprintf("hammer2: growfs failure, "
1329  			"would shrink from %016jx to %016jx\n",
1330  			(intmax_t)hmp->voldata.volu_size,
1331  			(intmax_t)grow->size);
1332  		return EINVAL;
1333  	}
1334  
1335  	if (delta == 0) {
1336  		kprintf("hammer2: growfs - size did not change\n");
1337  		return 0;
1338  	}
1339  
1340  	/*
1341  	 * Clear any new volume header backups that we extend into.
1342  	 * Skip volume headers that are already part of the filesystem.
1343  	 */
1344  	for (i = 0; i < HAMMER2_NUM_VOLHDRS; ++i) {
1345  		if (i * HAMMER2_ZONE_BYTES64 < hmp->voldata.volu_size)
1346  			continue;
1347  		if (i * HAMMER2_ZONE_BYTES64 >= grow->size)
1348  			break;
1349  		kprintf("hammer2: growfs - clear volhdr %d ", i);
1350  		error = breadx(hmp->devvp, i * HAMMER2_ZONE_BYTES64,
1351  			      HAMMER2_VOLUME_BYTES, &bp);
1352  		if (error) {
1353  			brelse(bp);
1354  			kprintf("I/O error %d\n", error);
1355  			return EINVAL;
1356  		}
1357  		bzero(bp->b_data, HAMMER2_VOLUME_BYTES);
1358  		error = bwrite(bp);
1359  		if (error) {
1360  			kprintf("I/O error %d\n", error);
1361  			return EINVAL;
1362  		}
1363  		kprintf("\n");
1364  	}
1365  
1366  	hammer2_trans_init(hmp->spmp, HAMMER2_TRANS_ISFLUSH);
1367  	mtid = hammer2_trans_sub(hmp->spmp);
1368  
1369  	kprintf("hammer2: growfs - expand by %016jx to %016jx mtid %016jx\n",
1370  		(intmax_t)delta, (intmax_t)grow->size, (intmax_t)mtid);
1371  
1372  
1373  	hammer2_voldata_lock(hmp);
1374  	hammer2_voldata_modify(hmp);
1375  
1376  	/*
1377  	 * NOTE: Just adjusting total_size for a single-volume filesystem
1378  	 *	 or for the last volume in a multi-volume filesystem, is
1379  	 *	 fine.  But we can't grow any other partition in a multi-volume
1380  	 *	 filesystem.  For now we just punt (at the top) on any
1381  	 *	 multi-volume filesystem.
1382  	 */
1383  	hmp->voldata.volu_size = grow->size;
1384  	hmp->voldata.total_size += delta;
1385  	hmp->voldata.allocator_size += delta;
1386  	hmp->voldata.allocator_free += delta;
1387  	hmp->total_size += delta;
1388  	hmp->volumes[0].size += delta;	/* note: indexes first (only) volume */
1389  
1390  	hammer2_voldata_unlock(hmp);
1391  
1392  	hammer2_trans_done(hmp->spmp, HAMMER2_TRANS_ISFLUSH |
1393  				      HAMMER2_TRANS_SIDEQ);
1394  	grow->modified = 1;
1395  
1396  	/*
1397  	 * Flush the mess right here and now.  We could just let the
1398  	 * filesystem syncer do it, but this was a sensitive operation
1399  	 * so don't take any chances.
1400  	 */
1401  	hammer2_vfs_sync(ip->pmp->mp, MNT_WAIT);
1402  
1403  	return 0;
1404  }
1405  
1406  #if 0
1407  /*
1408   * Get a list of volumes.
1409   */
1410  static int
1411  hammer2_ioctl_volume_list(hammer2_inode_t *ip, void *data)
1412  {
1413  	hammer2_ioc_volume_list_t *vollist = data;
1414  	hammer2_ioc_volume_t entry;
1415  	hammer2_volume_t *vol;
1416  	hammer2_dev_t *hmp;
1417  	hammer2_pfs_t *pmp;
1418  	int i, error = 0, cnt = 0;
1419  
1420  	pmp = ip->pmp;
1421  	hmp = pmp->pfs_hmps[0];
1422  	if (hmp == NULL)
1423  		return (EINVAL);
1424  
1425  	hammer2_voldata_lock(hmp);
1426  	for (i = 0; i < hmp->nvolumes; ++i) {
1427  		if (cnt >= vollist->nvolumes)
1428  			break;
1429  		vol = &hmp->volumes[i];
1430  		bzero(&entry, sizeof(entry));
1431  		/* copy hammer2_volume_t fields */
1432  		entry.id = vol->id;
1433  		bcopy(vol->dev->path, entry.path, sizeof(entry.path));
1434  		entry.offset = vol->offset;
1435  		entry.size = vol->size;
1436  		error = copyout(&entry, &vollist->volumes[cnt], sizeof(entry));
1437  		if (error)
1438  			goto failed;
1439  		cnt++;
1440  	}
1441  	vollist->nvolumes = cnt;
1442  	vollist->version = hmp->voldata.version;
1443  	bcopy(pmp->pfs_names[0], vollist->pfs_name, sizeof(vollist->pfs_name));
1444  failed:
1445  	hammer2_voldata_unlock(hmp);
1446  
1447  	return error;
1448  }
1449  #endif
1450