hammer expand: Also increase number of total bigblocks
[dragonfly.git] / sys / vfs / hammer / hammer_expand.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 static int
43 hammer_format_volume_header(struct hammer_mount *hmp, const char *dev_path,
44         const char *vol_name, int vol_no, int vol_count,
45         int64_t vol_size, int64_t boot_area_size, int64_t mem_area_size,
46         uint64_t *num_layer1_entries_p, uint64_t *layer1_free_blocks);
47
48 int
49 hammer_ioc_expand(hammer_transaction_t trans, hammer_inode_t ip,
50                 struct hammer_ioc_expand *expand)
51 {
52         struct hammer_mount *hmp = trans->hmp;
53         struct mount *mp = hmp->mp;
54         int error;
55
56         if (mp->mnt_flag & MNT_RDONLY) {
57                 kprintf("Cannot expand read-only HAMMER filesystem\n");
58                 return (EINVAL);
59         }
60
61         if (hmp->nvolumes + 1 >= HAMMER_MAX_VOLUMES) {
62                 kprintf("Max number of HAMMER volumes exceeded\n");
63                 return (EINVAL);
64         }
65
66         /*
67          * Find an unused volume number.
68          */
69         int free_vol_no = 0;
70         while (free_vol_no < HAMMER_MAX_VOLUMES &&
71                RB_LOOKUP(hammer_vol_rb_tree, &hmp->rb_vols_root, free_vol_no)) {
72                 ++free_vol_no;
73         }
74         if (free_vol_no >= HAMMER_MAX_VOLUMES) {
75                 kprintf("Max number of HAMMER volumes exceeded\n");
76                 return (EINVAL);
77         }
78
79         uint64_t num_layer1_entries = 0;
80         uint64_t *layer1_free_blocks =
81                 kmalloc(1024 * sizeof(uint64_t), M_TEMP, M_WAITOK|M_ZERO);
82
83         error = hammer_format_volume_header(
84                 hmp,
85                 expand->device_name,
86                 hmp->rootvol->ondisk->vol_name,
87                 free_vol_no,
88                 hmp->nvolumes+1,
89                 expand->vol_size,
90                 expand->boot_area_size,
91                 expand->mem_area_size,
92                 &num_layer1_entries /* out param */,
93                 layer1_free_blocks);
94         KKASSERT(num_layer1_entries < 1024);
95         if (error)
96                 goto end;
97
98         error = hammer_install_volume(hmp, expand->device_name, NULL);
99         if (error)
100                 goto end;
101
102         ++hmp->nvolumes;
103
104         hammer_sync_lock_sh(trans);
105         hammer_lock_ex(&hmp->blkmap_lock);
106
107         /*
108          * Set each volumes new value of the vol_count field.
109          */
110         for (int vol_no = 0; vol_no < HAMMER_MAX_VOLUMES; ++vol_no) {
111                 hammer_volume_t volume;
112                 volume = hammer_get_volume(hmp, vol_no, &error);
113                 if (volume == NULL && error == ENOENT) {
114                         /*
115                          * Skip unused volume numbers
116                          */
117                         error = 0;
118                         continue;
119                 }
120                 KKASSERT(error == 0);
121                 hammer_modify_volume_field(trans, volume, vol_count);
122                 volume->ondisk->vol_count = hmp->nvolumes;
123                 hammer_modify_volume_done(volume);
124                 hammer_rel_volume(volume, 0);
125         }
126
127         /*
128          * Assign Layer1 entries
129          */
130
131         hammer_volume_t root_volume = NULL;
132         hammer_blockmap_t freemap;
133
134         freemap = &hmp->blockmap[HAMMER_ZONE_FREEMAP_INDEX];
135         root_volume = hammer_get_root_volume(hmp, &error);
136         KKASSERT(root_volume && error == 0);
137
138         for (uint64_t i_layer1 = 0; i_layer1 < num_layer1_entries; i_layer1++) {
139                 hammer_buffer_t buffer1 = NULL;
140                 struct hammer_blockmap_layer1 *layer1;
141                 hammer_off_t layer1_offset;
142
143                 layer1_offset = freemap->phys_offset +
144                         (free_vol_no * 1024L) *
145                         sizeof(struct hammer_blockmap_layer1) + i_layer1;
146
147                 layer1 = hammer_bread(hmp, layer1_offset, &error, &buffer1);
148                 KKASSERT(layer1 != NULL && error == 0);
149                 KKASSERT(layer1->phys_offset == HAMMER_BLOCKMAP_UNAVAIL);
150
151                 hammer_modify_buffer(trans, buffer1, layer1, sizeof(*layer1));
152                 bzero(layer1, sizeof(*layer1));
153                 layer1->phys_offset = HAMMER_ENCODE_RAW_BUFFER(free_vol_no,
154                         i_layer1 * HAMMER_LARGEBLOCK_SIZE);
155
156                 layer1->blocks_free = layer1_free_blocks[i_layer1];
157                 layer1->layer1_crc = crc32(layer1, HAMMER_LAYER1_CRCSIZE);
158
159                 hammer_modify_buffer_done(buffer1);
160                 if (buffer1)
161                         hammer_rel_buffer(buffer1, 0);
162
163                 /*
164                  * Increase the total number of bigblocks
165                  */
166                 hammer_modify_volume_field(trans, root_volume,
167                         vol0_stat_bigblocks);
168                 root_volume->ondisk->vol0_stat_bigblocks +=
169                         layer1_free_blocks[i_layer1];
170                 hammer_modify_volume_done(root_volume);
171
172                 /*
173                  * Increase the number of free bigblocks
174                  * (including the copy in hmp)
175                  */
176                 hammer_modify_volume_field(trans, root_volume,
177                         vol0_stat_freebigblocks);
178                 root_volume->ondisk->vol0_stat_freebigblocks +=
179                         layer1_free_blocks[i_layer1];
180                 hmp->copy_stat_freebigblocks =
181                         root_volume->ondisk->vol0_stat_freebigblocks;
182                 hammer_modify_volume_done(root_volume);
183         } /* for */
184
185         hammer_rel_volume(root_volume, 0);
186
187         hammer_unlock(&hmp->blkmap_lock);
188         hammer_sync_unlock(trans);
189
190 end:
191         if (error) {
192                 kprintf("An error occured: %d\n", error);
193         }
194         if (layer1_free_blocks)
195                 kfree(layer1_free_blocks, M_TEMP);
196         return (error);
197 }
198
199 static int
200 hammer_format_volume_header(struct hammer_mount *hmp, const char *dev_path,
201         const char *vol_name, int vol_no, int vol_count,
202         int64_t vol_size, int64_t boot_area_size, int64_t mem_area_size,
203         uint64_t *num_layer1_entries_p, uint64_t *layer1_free_blocks)
204 {
205         struct vnode *devvp = NULL;
206         struct buf *bp = NULL;
207         struct nlookupdata nd;
208         struct hammer_volume_ondisk *ondisk;
209         int error;
210
211         /*
212          * Get the device vnode
213          */
214         error = nlookup_init(&nd, dev_path, UIO_SYSSPACE, NLC_FOLLOW);
215         if (error == 0)
216                 error = nlookup(&nd);
217         if (error == 0)
218                 error = cache_vref(&nd.nl_nch, nd.nl_cred, &devvp);
219         nlookup_done(&nd);
220
221         if (error == 0) {
222                 if (vn_isdisk(devvp, &error)) {
223                         error = vfs_mountedon(devvp);
224                 }
225         }
226         if (error == 0 &&
227             count_udev(devvp->v_umajor, devvp->v_uminor) > 0) {
228                 error = EBUSY;
229         }
230         if (error == 0) {
231                 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
232                 error = vinvalbuf(devvp, V_SAVE, 0, 0);
233                 if (error == 0) {
234                         error = VOP_OPEN(devvp, FREAD|FWRITE, FSCRED, NULL);
235                 }
236                 vn_unlock(devvp);
237         }
238         if (error) {
239                 if (devvp)
240                         vrele(devvp);
241                 return (error);
242         }
243
244         /*
245          * Extract the volume number from the volume header and do various
246          * sanity checks.
247          */
248         KKASSERT(HAMMER_BUFSIZE >= sizeof(struct hammer_volume_ondisk));
249         error = bread(devvp, 0LL, HAMMER_BUFSIZE, &bp);
250         if (error || bp->b_bcount < sizeof(struct hammer_volume_ondisk))
251                 goto late_failure;
252
253         ondisk = (struct hammer_volume_ondisk*) bp->b_data;
254
255         /*
256          * Note that we do NOT allow to use a device that contains
257          * a valid HAMMER signature. It has to be cleaned up with dd
258          * before.
259          */
260         if (ondisk->vol_signature == HAMMER_FSBUF_VOLUME) {
261                 kprintf("hammer_expand: Formatting of valid HAMMER volume "
262                         "%s denied. Erase with dd!\n", vol_name);
263                 error = EFTYPE;
264                 goto late_failure;
265         }
266
267         bzero(ondisk, sizeof(struct hammer_volume_ondisk));
268         ksnprintf(ondisk->vol_name, sizeof(ondisk->vol_name), "%s", vol_name);
269         ondisk->vol_fstype = hmp->rootvol->ondisk->vol_fstype;
270         ondisk->vol_signature = HAMMER_FSBUF_VOLUME;
271         ondisk->vol_fsid = hmp->fsid;
272         ondisk->vol_rootvol = hmp->rootvol->vol_no;
273         ondisk->vol_no = vol_no;
274         ondisk->vol_count = vol_count;
275         ondisk->vol_version = hmp->version;
276
277         /*
278          * Reserve space for (future) header junk, setup our poor-man's
279          * bigblock allocator.
280          */
281         int64_t vol_alloc = HAMMER_BUFSIZE * 16;
282
283         ondisk->vol_bot_beg = vol_alloc;
284         vol_alloc += boot_area_size;
285         ondisk->vol_mem_beg = vol_alloc;
286         vol_alloc += mem_area_size;
287
288         /*
289          * The remaining area is the zone 2 buffer allocation area.  These
290          * buffers
291          */
292         ondisk->vol_buf_beg = vol_alloc;
293         ondisk->vol_buf_end = vol_size & ~(int64_t)HAMMER_BUFMASK;
294
295         if (ondisk->vol_buf_end < ondisk->vol_buf_beg) {
296                 kprintf("volume %d %s is too small to hold the volume header",
297                      ondisk->vol_no, ondisk->vol_name);
298                 error = EFTYPE;
299                 goto late_failure;
300         }
301
302         ondisk->vol_nblocks = (ondisk->vol_buf_end - ondisk->vol_buf_beg) /
303                               HAMMER_BUFSIZE;
304         ondisk->vol_blocksize = HAMMER_BUFSIZE;
305
306         /*
307          * Write volume header to disk
308          */
309         error = bwrite(bp);
310         bp = NULL;
311
312         /*
313          * Initialize layer2 freemap
314          */
315
316         /*
317          * Determine the number of L1 entries we need to represent the
318          * space of the whole volume. Each L1 entry covers 4 TB of space
319          * (8MB * 2**19) and we need one L2 big block for each L1 entry.
320          * L1 entries are stored in the root volume.
321          */
322         hammer_off_t off_end = (ondisk->vol_buf_end - ondisk->vol_buf_beg)
323                 & ~HAMMER_LARGEBLOCK_MASK64;
324         uint64_t num_layer1_entries = (off_end / HAMMER_BLOCKMAP_LAYER2) +
325                 ((off_end & HAMMER_BLOCKMAP_LAYER2_MASK) == 0 ? 0 : 1);
326         *num_layer1_entries_p = num_layer1_entries;
327
328         /*
329          * We allocate all L2 big blocks sequentially from the start of
330          * the volume.
331          */
332         KKASSERT(off_end / HAMMER_LARGEBLOCK_SIZE >= num_layer1_entries);
333
334         hammer_off_t layer2_end = num_layer1_entries * HAMMER_LARGEBLOCK_SIZE;
335         hammer_off_t off = 0;
336         while (off < layer2_end) {
337                 error = bread(devvp, ondisk->vol_buf_beg + off,
338                               HAMMER_BUFSIZE, &bp);
339                 if (error || bp->b_bcount != HAMMER_BUFSIZE)
340                         goto late_failure;
341                 struct hammer_blockmap_layer2 *layer2 = (void*)bp->b_data;
342
343                 for (int i = 0; i < HAMMER_BUFSIZE / sizeof(*layer2); ++i) {
344
345                         /* the bigblock described by the layer2 entry */
346                         hammer_off_t bigblock_off = HAMMER_LARGEBLOCK_SIZE *
347                                 (off / sizeof(*layer2));
348
349                         /*
350                          * To which layer1 entry does the current layer2
351                          * big block belong?
352                          *
353                          * We need this to calculate the free bigblocks
354                          * which is required for the layer1.
355                          */
356                         uint64_t i_layer1 = HAMMER_BLOCKMAP_LAYER1_OFFSET(off) /
357                                         sizeof(struct hammer_blockmap_layer1);
358                         KKASSERT(i_layer1 < 1024);
359
360                         bzero(layer2, sizeof(*layer2));
361
362                         if ((off & HAMMER_LARGEBLOCK_SIZE) == bigblock_off) {
363                                 /*
364                                  * Bigblock is part of the layer2 freemap
365                                  */
366                                 layer2->zone = HAMMER_ZONE_FREEMAP_INDEX;
367                                 layer2->append_off = HAMMER_LARGEBLOCK_SIZE;
368                                 layer2->bytes_free = 0;
369                         } else if (bigblock_off < off_end) {
370                                 layer2->zone = 0;
371                                 layer2->append_off = 0;
372                                 layer2->bytes_free = HAMMER_LARGEBLOCK_SIZE;
373                                 ++layer1_free_blocks[i_layer1];
374                         } else {
375                                 layer2->zone = HAMMER_ZONE_UNAVAIL_INDEX;
376                                 layer2->append_off = HAMMER_LARGEBLOCK_SIZE;
377                                 layer2->bytes_free = 0;
378                         }
379                         layer2->entry_crc = crc32(layer2, HAMMER_LAYER2_CRCSIZE);
380                         off += sizeof(*layer2);
381                         ++layer2;
382                 }
383
384                 error = bwrite(bp);
385                 bp = NULL;
386                 if (error)
387                         goto late_failure;
388         }
389
390 late_failure:
391         if (bp)
392                 brelse(bp);
393         VOP_CLOSE(devvp, FREAD|FWRITE);
394         if (devvp)
395                 vrele(devvp);
396         return (error);
397 }