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