devfs: add passing of file pointer through to dev_dclose
[dragonfly.git] / sys / vfs / hammer / hammer_volume.c
1 /*
2  * Copyright (c) 2009 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com> and
6  * Michael Neumann <mneumann@ntecs.de>
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
37 #include "hammer.h"
38 #include <sys/fcntl.h>
39 #include <sys/nlookup.h>
40 #include <sys/buf.h>
41
42 #include <sys/buf2.h>
43
44 static int
45 hammer_setup_device(struct vnode **devvpp, const char *dev_path, int ronly);
46
47 static void
48 hammer_close_device(struct vnode **devvpp, int ronly);
49
50 static int
51 hammer_format_volume_header(struct hammer_mount *hmp, struct vnode *devvp,
52         const char *vol_name, int vol_no, int vol_count,
53         int64_t vol_size, int64_t boot_area_size, int64_t mem_area_size);
54
55 static int
56 hammer_clear_volume_header(struct vnode *devvp);
57
58 struct bigblock_stat {
59         uint64_t total_bigblocks;
60         uint64_t total_free_bigblocks;
61         uint64_t counter;
62 };
63
64 static int
65 hammer_format_freemap(hammer_transaction_t trans, hammer_volume_t volume,
66         struct bigblock_stat *stat);
67
68 static int
69 hammer_free_freemap(hammer_transaction_t trans, hammer_volume_t volume,
70         struct bigblock_stat *stat);
71
72 int
73 hammer_ioc_volume_add(hammer_transaction_t trans, hammer_inode_t ip,
74                 struct hammer_ioc_volume *ioc)
75 {
76         struct hammer_mount *hmp = trans->hmp;
77         struct mount *mp = hmp->mp;
78         hammer_volume_t volume;
79         int error;
80
81         if (mp->mnt_flag & MNT_RDONLY) {
82                 kprintf("Cannot add volume to read-only HAMMER filesystem\n");
83                 return (EINVAL);
84         }
85
86         if (hmp->nvolumes + 1 >= HAMMER_MAX_VOLUMES) {
87                 kprintf("Max number of HAMMER volumes exceeded\n");
88                 return (EINVAL);
89         }
90
91         if (hammer_lock_ex_try(&hmp->volume_lock) != 0) {
92                 kprintf("Another volume operation is in progress!\n");
93                 return (EAGAIN);
94         }
95
96         /*
97          * Find an unused volume number.
98          */
99         int free_vol_no = 0;
100         while (free_vol_no < HAMMER_MAX_VOLUMES &&
101                RB_LOOKUP(hammer_vol_rb_tree, &hmp->rb_vols_root, free_vol_no)) {
102                 ++free_vol_no;
103         }
104         if (free_vol_no >= HAMMER_MAX_VOLUMES) {
105                 kprintf("Max number of HAMMER volumes exceeded\n");
106                 hammer_unlock(&hmp->volume_lock);
107                 return (EINVAL);
108         }
109
110         struct vnode *devvp = NULL;
111         error = hammer_setup_device(&devvp, ioc->device_name, 0);
112         if (error)
113                 goto end;
114         KKASSERT(devvp);
115         error = hammer_format_volume_header(
116                 hmp,
117                 devvp,
118                 hmp->rootvol->ondisk->vol_name,
119                 free_vol_no,
120                 hmp->nvolumes+1,
121                 ioc->vol_size,
122                 ioc->boot_area_size,
123                 ioc->mem_area_size);
124         hammer_close_device(&devvp, 0);
125         if (error)
126                 goto end;
127
128         error = hammer_install_volume(hmp, ioc->device_name, NULL);
129         if (error)
130                 goto end;
131
132         hammer_sync_lock_sh(trans);
133         hammer_lock_ex(&hmp->blkmap_lock);
134
135         ++hmp->nvolumes;
136
137         /*
138          * Set each volumes new value of the vol_count field.
139          */
140         for (int vol_no = 0; vol_no < HAMMER_MAX_VOLUMES; ++vol_no) {
141                 volume = hammer_get_volume(hmp, vol_no, &error);
142                 if (volume == NULL && error == ENOENT) {
143                         /*
144                          * Skip unused volume numbers
145                          */
146                         error = 0;
147                         continue;
148                 }
149                 KKASSERT(volume != NULL && error == 0);
150                 hammer_modify_volume_field(trans, volume, vol_count);
151                 volume->ondisk->vol_count = hmp->nvolumes;
152                 hammer_modify_volume_done(volume);
153
154                 /*
155                  * Only changes to the header of the root volume
156                  * are automatically flushed to disk. For all
157                  * other volumes that we modify we do it here.
158                  *
159                  * No interlock is needed, volume buffers are not
160                  * messed with by bioops.
161                  */
162                 if (volume != trans->rootvol && volume->io.modified) {
163                         hammer_crc_set_volume(volume->ondisk);
164                         hammer_io_flush(&volume->io, 0);
165                 }
166
167                 hammer_rel_volume(volume, 0);
168         }
169
170         volume = hammer_get_volume(hmp, free_vol_no, &error);
171         KKASSERT(volume != NULL && error == 0);
172
173         struct bigblock_stat stat;
174         error = hammer_format_freemap(trans, volume, &stat);
175         KKASSERT(error == 0);
176
177         /*
178          * Increase the total number of bigblocks and update stat/vstat totals.
179          */
180         hammer_modify_volume_field(trans, trans->rootvol,
181                 vol0_stat_bigblocks);
182         trans->rootvol->ondisk->vol0_stat_bigblocks += stat.total_bigblocks;
183         hammer_modify_volume_done(trans->rootvol);
184         mp->mnt_stat.f_blocks += trans->rootvol->ondisk->vol0_stat_bigblocks *
185             (HAMMER_LARGEBLOCK_SIZE / HAMMER_BUFSIZE);
186         mp->mnt_vstat.f_blocks += trans->rootvol->ondisk->vol0_stat_bigblocks *
187             (HAMMER_LARGEBLOCK_SIZE / HAMMER_BUFSIZE);
188
189         /*
190          * Increase the number of free bigblocks
191          * (including the copy in hmp)
192          */
193         hammer_modify_volume_field(trans, trans->rootvol,
194                 vol0_stat_freebigblocks);
195         trans->rootvol->ondisk->vol0_stat_freebigblocks += stat.total_free_bigblocks;
196         hmp->copy_stat_freebigblocks =
197                 trans->rootvol->ondisk->vol0_stat_freebigblocks;
198         hammer_modify_volume_done(trans->rootvol);
199
200         hammer_rel_volume(volume, 0);
201
202         hammer_unlock(&hmp->blkmap_lock);
203         hammer_sync_unlock(trans);
204
205         KKASSERT(error == 0);
206 end:
207         hammer_unlock(&hmp->volume_lock);
208         if (error)
209                 kprintf("An error occurred: %d\n", error);
210         return (error);
211 }
212
213
214 /*
215  * Remove a volume.
216  */
217 int
218 hammer_ioc_volume_del(hammer_transaction_t trans, hammer_inode_t ip,
219                 struct hammer_ioc_volume *ioc)
220 {
221         struct hammer_mount *hmp = trans->hmp;
222         struct mount *mp = hmp->mp;
223         hammer_volume_t volume;
224         int error = 0;
225
226         if (mp->mnt_flag & MNT_RDONLY) {
227                 kprintf("Cannot del volume from read-only HAMMER filesystem\n");
228                 return (EINVAL);
229         }
230
231         if (hammer_lock_ex_try(&hmp->volume_lock) != 0) {
232                 kprintf("Another volume operation is in progress!\n");
233                 return (EAGAIN);
234         }
235
236         volume = NULL;
237
238         /*
239          * find volume by volname
240          */
241         for (int vol_no = 0; vol_no < HAMMER_MAX_VOLUMES; ++vol_no) {
242                 volume = hammer_get_volume(hmp, vol_no, &error);
243                 if (volume == NULL && error == ENOENT) {
244                         /*
245                          * Skip unused volume numbers
246                          */
247                         error = 0;
248                         continue;
249                 }
250                 KKASSERT(volume != NULL && error == 0);
251                 if (strcmp(volume->vol_name, ioc->device_name) == 0) {
252                         break;
253                 }
254                 hammer_rel_volume(volume, 0);
255                 volume = NULL;
256         }
257
258         if (volume == NULL) {
259                 kprintf("Couldn't find volume\n");
260                 error = EINVAL;
261                 goto end;
262         }
263
264         if (volume == trans->rootvol) {
265                 kprintf("Cannot remove root-volume\n");
266                 hammer_rel_volume(volume, 0);
267                 error = EINVAL;
268                 goto end;
269         }
270
271         /*
272          *
273          */
274
275         hmp->volume_to_remove = volume->vol_no;
276
277         struct hammer_ioc_reblock reblock;
278         bzero(&reblock, sizeof(reblock));
279
280         reblock.key_beg.localization = HAMMER_MIN_LOCALIZATION;
281         reblock.key_beg.obj_id = HAMMER_MIN_OBJID;
282         reblock.key_end.localization = HAMMER_MAX_LOCALIZATION;
283         reblock.key_end.obj_id = HAMMER_MAX_OBJID;
284         reblock.head.flags = HAMMER_IOC_DO_FLAGS;
285         reblock.free_level = 0;
286
287         error = hammer_ioc_reblock(trans, ip, &reblock);
288
289         if (reblock.head.flags & HAMMER_IOC_HEAD_INTR) {
290                 error = EINTR;
291         }
292
293         if (error) {
294                 if (error == EINTR) {
295                         kprintf("reblock was interrupted\n");
296                 } else {
297                         kprintf("reblock failed: %d\n", error);
298                 }
299                 hmp->volume_to_remove = -1;
300                 hammer_rel_volume(volume, 0);
301                 goto end;
302         }
303
304         /*
305          * Sync filesystem
306          */
307         int count = 0;
308         while (hammer_flusher_haswork(hmp)) {
309                 hammer_flusher_sync(hmp);
310                 ++count;
311                 if (count >= 5) {
312                         if (count == 5)
313                                 kprintf("HAMMER: flushing.");
314                         else
315                                 kprintf(".");
316                         tsleep(&count, 0, "hmrufl", hz);
317                 }
318                 if (count == 30) {
319                         kprintf("giving up");
320                         break;
321                 }
322         }
323         kprintf("\n");
324
325         hammer_sync_lock_sh(trans);
326         hammer_lock_ex(&hmp->blkmap_lock);
327
328         /*
329          * We use stat later to update rootvol's bigblock stats
330          */
331         struct bigblock_stat stat;
332         error = hammer_free_freemap(trans, volume, &stat);
333         if (error) {
334                 kprintf("Failed to free volume. Volume not empty!\n");
335                 hmp->volume_to_remove = -1;
336                 hammer_rel_volume(volume, 0);
337                 hammer_unlock(&hmp->blkmap_lock);
338                 hammer_sync_unlock(trans);
339                 goto end;
340         }
341
342         hmp->volume_to_remove = -1;
343
344         hammer_rel_volume(volume, 0);
345
346         /*
347          * Unload buffers
348          */
349         RB_SCAN(hammer_buf_rb_tree, &hmp->rb_bufs_root, NULL,
350                 hammer_unload_buffer, volume);
351
352         error = hammer_unload_volume(volume, NULL);
353         if (error == -1) {
354                 kprintf("Failed to unload volume\n");
355                 hammer_unlock(&hmp->blkmap_lock);
356                 hammer_sync_unlock(trans);
357                 goto end;
358         }
359
360         volume = NULL;
361         --hmp->nvolumes;
362
363         /*
364          * Set each volume's new value of the vol_count field.
365          */
366         for (int vol_no = 0; vol_no < HAMMER_MAX_VOLUMES; ++vol_no) {
367                 volume = hammer_get_volume(hmp, vol_no, &error);
368                 if (volume == NULL && error == ENOENT) {
369                         /*
370                          * Skip unused volume numbers
371                          */
372                         error = 0;
373                         continue;
374                 }
375
376                 KKASSERT(volume != NULL && error == 0);
377                 hammer_modify_volume_field(trans, volume, vol_count);
378                 volume->ondisk->vol_count = hmp->nvolumes;
379                 hammer_modify_volume_done(volume);
380
381                 /*
382                  * Only changes to the header of the root volume
383                  * are automatically flushed to disk. For all
384                  * other volumes that we modify we do it here.
385                  *
386                  * No interlock is needed, volume buffers are not
387                  * messed with by bioops.
388                  */
389                 if (volume != trans->rootvol && volume->io.modified) {
390                         hammer_crc_set_volume(volume->ondisk);
391                         hammer_io_flush(&volume->io, 0);
392                 }
393
394                 hammer_rel_volume(volume, 0);
395         }
396
397         /*
398          * Update the total number of bigblocks
399          */
400         hammer_modify_volume_field(trans, trans->rootvol,
401                 vol0_stat_bigblocks);
402         trans->rootvol->ondisk->vol0_stat_bigblocks -= stat.total_bigblocks;
403         hammer_modify_volume_done(trans->rootvol);
404
405         /*
406          * Update the number of free bigblocks
407          * (including the copy in hmp)
408          */
409         hammer_modify_volume_field(trans, trans->rootvol,
410                 vol0_stat_freebigblocks);
411         trans->rootvol->ondisk->vol0_stat_freebigblocks -= stat.total_free_bigblocks;
412         hmp->copy_stat_freebigblocks =
413                 trans->rootvol->ondisk->vol0_stat_freebigblocks;
414         hammer_modify_volume_done(trans->rootvol);
415
416
417         hammer_unlock(&hmp->blkmap_lock);
418         hammer_sync_unlock(trans);
419
420         /*
421          * Erase the volume header of the removed device.
422          *
423          * This is to not accidentally mount the volume again.
424          */
425         struct vnode *devvp = NULL;
426         error = hammer_setup_device(&devvp, ioc->device_name, 0);
427         if (error) {
428                 kprintf("Failed to open device: %s\n", ioc->device_name);
429                 goto end;
430         }
431         KKASSERT(devvp);
432         error = hammer_clear_volume_header(devvp);
433         if (error) {
434                 kprintf("Failed to clear volume header of device: %s\n",
435                         ioc->device_name);
436                 goto end;
437         }
438         hammer_close_device(&devvp, 0);
439
440         KKASSERT(error == 0);
441 end:
442         hammer_unlock(&hmp->volume_lock);
443         return (error);
444 }
445
446
447 int
448 hammer_ioc_volume_list(hammer_transaction_t trans, hammer_inode_t ip,
449     struct hammer_ioc_volume_list *ioc)
450 {
451         struct hammer_mount *hmp = trans->hmp;
452         hammer_volume_t volume;
453         int error = 0;
454         int i, cnt, len;
455
456         for (i = 0, cnt = 0; i < HAMMER_MAX_VOLUMES && cnt < ioc->nvols; i++) {
457                 volume = hammer_get_volume(hmp, i, &error);
458                 if (volume == NULL && error == ENOENT) {
459                         error = 0;
460                         continue;
461                 }
462                 KKASSERT(volume != NULL && error == 0);
463
464                 len = strlen(volume->vol_name) + 1;
465                 KKASSERT(len <= MAXPATHLEN);
466
467                 error = copyout(volume->vol_name, ioc->vols[cnt].device_name,
468                                 len);
469                 if (error) {
470                         hammer_rel_volume(volume, 0);
471                         return (error);
472                 }
473                 cnt++;
474                 hammer_rel_volume(volume, 0);
475         }
476         ioc->nvols = cnt;
477
478         return (error);
479 }
480
481 /*
482  * Iterate over all usable L1 entries of the volume and
483  * the corresponding L2 entries.
484  */
485 static int
486 hammer_iterate_l1l2_entries(hammer_transaction_t trans, hammer_volume_t volume,
487         int (*callback)(hammer_transaction_t, hammer_volume_t, hammer_buffer_t*,
488                 struct hammer_blockmap_layer1*, struct hammer_blockmap_layer2*,
489                 hammer_off_t, hammer_off_t, void*),
490         void *data)
491 {
492         struct hammer_mount *hmp = trans->hmp;
493         hammer_blockmap_t freemap = &hmp->blockmap[HAMMER_ZONE_FREEMAP_INDEX];
494         hammer_buffer_t buffer = NULL;
495         int error = 0;
496
497         hammer_off_t phys_off;
498         hammer_off_t block_off;
499         hammer_off_t layer1_off;
500         hammer_off_t layer2_off;
501         hammer_off_t aligned_buf_end_off;
502         struct hammer_blockmap_layer1 *layer1;
503         struct hammer_blockmap_layer2 *layer2;
504
505         /*
506          * Calculate the usable size of the volume, which
507          * must be aligned at a bigblock (8 MB) boundary.
508          */
509         aligned_buf_end_off = (HAMMER_ENCODE_RAW_BUFFER(volume->ondisk->vol_no,
510                 (volume->ondisk->vol_buf_end - volume->ondisk->vol_buf_beg)
511                 & ~HAMMER_LARGEBLOCK_MASK64));
512
513         /*
514          * Iterate the volume's address space in chunks of 4 TB, where each
515          * chunk consists of at least one physically available 8 MB bigblock.
516          *
517          * For each chunk we need one L1 entry and one L2 bigblock.
518          * We use the first bigblock of each chunk as L2 block.
519          */
520         for (phys_off = HAMMER_ENCODE_RAW_BUFFER(volume->ondisk->vol_no, 0);
521              phys_off < aligned_buf_end_off;
522              phys_off += HAMMER_BLOCKMAP_LAYER2) {
523                 for (block_off = 0;
524                      block_off < HAMMER_BLOCKMAP_LAYER2;
525                      block_off += HAMMER_LARGEBLOCK_SIZE) {
526                         layer2_off = phys_off +
527                                 HAMMER_BLOCKMAP_LAYER2_OFFSET(block_off);
528                         layer2 = hammer_bread(hmp, layer2_off, &error, &buffer);
529                         if (error)
530                                 goto end;
531
532                         error = callback(trans, volume, &buffer, NULL,
533                                          layer2, phys_off, block_off, data);
534                         if (error)
535                                 goto end;
536                 }
537
538                 layer1_off = freemap->phys_offset +
539                                 HAMMER_BLOCKMAP_LAYER1_OFFSET(phys_off);
540                 layer1 = hammer_bread(hmp, layer1_off, &error, &buffer);
541                 if (error)
542                         goto end;
543
544                 error = callback(trans, volume, &buffer, layer1, NULL,
545                                  phys_off, 0, data);
546                 if (error)
547                         goto end;
548         }
549
550 end:
551         if (buffer) {
552                 hammer_rel_buffer(buffer, 0);
553                 buffer = NULL;
554         }
555
556         return error;
557 }
558
559
560 static int
561 format_callback(hammer_transaction_t trans, hammer_volume_t volume,
562         hammer_buffer_t *bufferp,
563         struct hammer_blockmap_layer1 *layer1,
564         struct hammer_blockmap_layer2 *layer2,
565         hammer_off_t phys_off,
566         hammer_off_t block_off,
567         void *data)
568 {
569         struct bigblock_stat *stat = (struct bigblock_stat*)data;
570
571         /*
572          * Calculate the usable size of the volume, which must be aligned
573          * at a bigblock (8 MB) boundary.
574          */
575         hammer_off_t aligned_buf_end_off;
576         aligned_buf_end_off = (HAMMER_ENCODE_RAW_BUFFER(volume->ondisk->vol_no,
577                 (volume->ondisk->vol_buf_end - volume->ondisk->vol_buf_beg)
578                 & ~HAMMER_LARGEBLOCK_MASK64));
579
580         if (layer1) {
581                 KKASSERT(layer1->phys_offset == HAMMER_BLOCKMAP_UNAVAIL);
582
583                 hammer_modify_buffer(trans, *bufferp, layer1, sizeof(*layer1));
584                 bzero(layer1, sizeof(*layer1));
585                 layer1->phys_offset = phys_off;
586                 layer1->blocks_free = stat->counter;
587                 layer1->layer1_crc = crc32(layer1, HAMMER_LAYER1_CRCSIZE);
588                 hammer_modify_buffer_done(*bufferp);
589
590                 stat->total_free_bigblocks += stat->counter;
591                 stat->counter = 0; /* reset */
592         } else if (layer2) {
593                 hammer_modify_buffer(trans, *bufferp, layer2, sizeof(*layer2));
594                 bzero(layer2, sizeof(*layer2));
595
596                 if (block_off == 0) {
597                         /*
598                          * The first entry represents the L2 bigblock itself.
599                          */
600                         layer2->zone = HAMMER_ZONE_FREEMAP_INDEX;
601                         layer2->append_off = HAMMER_LARGEBLOCK_SIZE;
602                         layer2->bytes_free = 0;
603                         ++stat->total_bigblocks;
604                 } else if (phys_off + block_off < aligned_buf_end_off) {
605                         /*
606                          * Available bigblock
607                          */
608                         layer2->zone = 0;
609                         layer2->append_off = 0;
610                         layer2->bytes_free = HAMMER_LARGEBLOCK_SIZE;
611                         ++stat->total_bigblocks;
612                         ++stat->counter;
613                 } else {
614                         /*
615                          * Bigblock outside of physically available
616                          * space
617                          */
618                         layer2->zone = HAMMER_ZONE_UNAVAIL_INDEX;
619                         layer2->append_off = HAMMER_LARGEBLOCK_SIZE;
620                         layer2->bytes_free = 0;
621                 }
622
623                 layer2->entry_crc = crc32(layer2, HAMMER_LAYER2_CRCSIZE);
624                 hammer_modify_buffer_done(*bufferp);
625         } else {
626                 KKASSERT(0);
627         }
628
629         return 0;
630 }
631
632 static int
633 hammer_format_freemap(hammer_transaction_t trans, hammer_volume_t volume,
634         struct bigblock_stat *stat)
635 {
636         stat->total_bigblocks = 0;
637         stat->total_free_bigblocks = 0;
638         stat->counter = 0;
639         return hammer_iterate_l1l2_entries(trans, volume, format_callback, stat);
640 }
641
642 static int
643 free_callback(hammer_transaction_t trans, hammer_volume_t volume __unused,
644         hammer_buffer_t *bufferp,
645         struct hammer_blockmap_layer1 *layer1,
646         struct hammer_blockmap_layer2 *layer2,
647         hammer_off_t phys_off,
648         hammer_off_t block_off __unused,
649         void *data)
650 {
651         struct bigblock_stat *stat = (struct bigblock_stat*)data;
652
653         /*
654          * No modifications to ondisk structures
655          */
656         int testonly = (stat == NULL);
657
658         if (layer1) {
659                 if (layer1->phys_offset == HAMMER_BLOCKMAP_UNAVAIL) {
660                         /*
661                          * This layer1 entry is already free.
662                          */
663                         return 0;
664                 }
665
666                 KKASSERT((int)HAMMER_VOL_DECODE(layer1->phys_offset) ==
667                         trans->hmp->volume_to_remove);
668
669                 if (testonly)
670                         return 0;
671
672                 /*
673                  * Free the L1 entry
674                  */
675                 hammer_modify_buffer(trans, *bufferp, layer1, sizeof(*layer1));
676                 bzero(layer1, sizeof(*layer1));
677                 layer1->phys_offset = HAMMER_BLOCKMAP_UNAVAIL;
678                 layer1->layer1_crc = crc32(layer1, HAMMER_LAYER1_CRCSIZE);
679                 hammer_modify_buffer_done(*bufferp);
680
681                 return 0;
682         } else if (layer2) {
683                 if (layer2->zone == HAMMER_ZONE_UNAVAIL_INDEX) {
684                         return 0;
685                 }
686
687                 if (layer2->zone == HAMMER_ZONE_FREEMAP_INDEX) {
688                         if (stat) {
689                                 ++stat->total_bigblocks;
690                         }
691                         return 0;
692                 }
693
694                 if (layer2->append_off == 0 &&
695                     layer2->bytes_free == HAMMER_LARGEBLOCK_SIZE) {
696                         if (stat) {
697                                 ++stat->total_bigblocks;
698                                 ++stat->total_free_bigblocks;
699                         }
700                         return 0;
701                 }
702
703                 /*
704                  * We found a layer2 entry that is not empty!
705                  */
706                 return EBUSY;
707         } else {
708                 KKASSERT(0);
709         }
710
711         return EINVAL;
712 }
713
714 static int
715 hammer_free_freemap(hammer_transaction_t trans, hammer_volume_t volume,
716         struct bigblock_stat *stat)
717 {
718         int error;
719
720         stat->total_bigblocks = 0;
721         stat->total_free_bigblocks = 0;
722         stat->counter = 0;
723
724         error = hammer_iterate_l1l2_entries(trans, volume, free_callback, NULL);
725         if (error)
726                 return error;
727
728         error = hammer_iterate_l1l2_entries(trans, volume, free_callback, stat);
729         return error;
730 }
731
732 /************************************************************************
733  *                              MISC                                    *
734  ************************************************************************
735  */
736
737 static int
738 hammer_setup_device(struct vnode **devvpp, const char *dev_path, int ronly)
739 {
740         int error;
741         struct nlookupdata nd;
742
743         /*
744          * Get the device vnode
745          */
746         if (*devvpp == NULL) {
747                 error = nlookup_init(&nd, dev_path, UIO_SYSSPACE, NLC_FOLLOW);
748                 if (error == 0)
749                         error = nlookup(&nd);
750                 if (error == 0)
751                         error = cache_vref(&nd.nl_nch, nd.nl_cred, devvpp);
752                 nlookup_done(&nd);
753         } else {
754                 error = 0;
755         }
756
757         if (error == 0) {
758                 if (vn_isdisk(*devvpp, &error)) {
759                         error = vfs_mountedon(*devvpp);
760                 }
761         }
762         if (error == 0 && vcount(*devvpp) > 0)
763                 error = EBUSY;
764         if (error == 0) {
765                 vn_lock(*devvpp, LK_EXCLUSIVE | LK_RETRY);
766                 error = vinvalbuf(*devvpp, V_SAVE, 0, 0);
767                 if (error == 0) {
768                         error = VOP_OPEN(*devvpp,
769                                          (ronly ? FREAD : FREAD|FWRITE),
770                                          FSCRED, NULL);
771                 }
772                 vn_unlock(*devvpp);
773         }
774         if (error && *devvpp) {
775                 vrele(*devvpp);
776                 *devvpp = NULL;
777         }
778         return (error);
779 }
780
781 static void
782 hammer_close_device(struct vnode **devvpp, int ronly)
783 {
784         if (*devvpp) {
785                 vn_lock(*devvpp, LK_EXCLUSIVE | LK_RETRY);
786                 vinvalbuf(*devvpp, ronly ? 0 : V_SAVE, 0, 0);
787                 VOP_CLOSE(*devvpp, (ronly ? FREAD : FREAD|FWRITE), NULL);
788                 vn_unlock(*devvpp);
789                 vrele(*devvpp);
790                 *devvpp = NULL;
791         }
792 }
793
794 static int
795 hammer_format_volume_header(struct hammer_mount *hmp, struct vnode *devvp,
796         const char *vol_name, int vol_no, int vol_count,
797         int64_t vol_size, int64_t boot_area_size, int64_t mem_area_size)
798 {
799         struct buf *bp = NULL;
800         struct hammer_volume_ondisk *ondisk;
801         int error;
802
803         /*
804          * Extract the volume number from the volume header and do various
805          * sanity checks.
806          */
807         KKASSERT(HAMMER_BUFSIZE >= sizeof(struct hammer_volume_ondisk));
808         error = bread(devvp, 0LL, HAMMER_BUFSIZE, &bp);
809         if (error || bp->b_bcount < sizeof(struct hammer_volume_ondisk))
810                 goto late_failure;
811
812         ondisk = (struct hammer_volume_ondisk*) bp->b_data;
813
814         /*
815          * Note that we do NOT allow to use a device that contains
816          * a valid HAMMER signature. It has to be cleaned up with dd
817          * before.
818          */
819         if (ondisk->vol_signature == HAMMER_FSBUF_VOLUME) {
820                 kprintf("hammer_volume_add: Formatting of valid HAMMER volume "
821                         "%s denied. Erase with dd!\n", vol_name);
822                 error = EFTYPE;
823                 goto late_failure;
824         }
825
826         bzero(ondisk, sizeof(struct hammer_volume_ondisk));
827         ksnprintf(ondisk->vol_name, sizeof(ondisk->vol_name), "%s", vol_name);
828         ondisk->vol_fstype = hmp->rootvol->ondisk->vol_fstype;
829         ondisk->vol_signature = HAMMER_FSBUF_VOLUME;
830         ondisk->vol_fsid = hmp->fsid;
831         ondisk->vol_rootvol = hmp->rootvol->vol_no;
832         ondisk->vol_no = vol_no;
833         ondisk->vol_count = vol_count;
834         ondisk->vol_version = hmp->version;
835
836         /*
837          * Reserve space for (future) header junk, setup our poor-man's
838          * bigblock allocator.
839          */
840         int64_t vol_alloc = HAMMER_BUFSIZE * 16;
841
842         ondisk->vol_bot_beg = vol_alloc;
843         vol_alloc += boot_area_size;
844         ondisk->vol_mem_beg = vol_alloc;
845         vol_alloc += mem_area_size;
846
847         /*
848          * The remaining area is the zone 2 buffer allocation area.  These
849          * buffers
850          */
851         ondisk->vol_buf_beg = vol_alloc;
852         ondisk->vol_buf_end = vol_size & ~(int64_t)HAMMER_BUFMASK;
853
854         if (ondisk->vol_buf_end < ondisk->vol_buf_beg) {
855                 kprintf("volume %d %s is too small to hold the volume header",
856                      ondisk->vol_no, ondisk->vol_name);
857                 error = EFTYPE;
858                 goto late_failure;
859         }
860
861         ondisk->vol_nblocks = (ondisk->vol_buf_end - ondisk->vol_buf_beg) /
862                               HAMMER_BUFSIZE;
863         ondisk->vol_blocksize = HAMMER_BUFSIZE;
864
865         /*
866          * Write volume header to disk
867          */
868         error = bwrite(bp);
869         bp = NULL;
870
871 late_failure:
872         if (bp)
873                 brelse(bp);
874         return (error);
875 }
876
877 /*
878  * Invalidates the volume header. Used by volume-del.
879  */
880 static int
881 hammer_clear_volume_header(struct vnode *devvp)
882 {
883         struct buf *bp = NULL;
884         struct hammer_volume_ondisk *ondisk;
885         int error;
886
887         KKASSERT(HAMMER_BUFSIZE >= sizeof(struct hammer_volume_ondisk));
888         error = bread(devvp, 0LL, HAMMER_BUFSIZE, &bp);
889         if (error || bp->b_bcount < sizeof(struct hammer_volume_ondisk))
890                 goto late_failure;
891
892         ondisk = (struct hammer_volume_ondisk*) bp->b_data;
893         bzero(ondisk, sizeof(struct hammer_volume_ondisk));
894
895         error = bwrite(bp);
896         bp = NULL;
897
898 late_failure:
899         if (bp)
900                 brelse(bp);
901         return (error);
902 }