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