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