2 * Copyright (c) 2009 The DragonFly Project. All rights reserved.
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>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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
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.
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
38 #include <sys/fcntl.h>
39 #include <sys/nlookup.h>
43 hammer_format_volume_header(struct hammer_mount *hmp, const char *vol_name,
44 int vol_no, int vol_count,
45 int64_t vol_size, int64_t boot_area_size, int64_t mem_area_size);
49 hammer_ioc_expand(hammer_transaction_t trans, hammer_inode_t ip,
50 struct hammer_ioc_expand *expand)
52 struct hammer_mount *hmp = trans->hmp;
53 struct mount *mp = hmp->mp;
56 if (mp->mnt_flag & MNT_RDONLY) {
57 kprintf("Cannot expand read-only HAMMER filesystem\n");
61 if (hmp->nvolumes + 1 >= HAMMER_MAX_VOLUMES) {
62 kprintf("Max number of HAMMER volumes exceeded\n");
66 error = hammer_format_volume_header(
68 hmp->rootvol->ondisk->vol_name,
72 expand->boot_area_size,
73 expand->mem_area_size);
76 error = hammer_install_volume(hmp, expand->device_name, NULL);
81 hammer_sync_lock_sh(trans);
82 hammer_lock_ex(&hmp->blkmap_lock);
85 * Set each volumes new value of the vol_count field.
87 for (int vol_no = 0; vol_no < hmp->nvolumes; ++vol_no) {
88 hammer_volume_t volume;
89 volume = hammer_get_volume(hmp, vol_no, &error);
91 hammer_modify_volume_field(trans, volume, vol_count);
92 volume->ondisk->vol_count = hmp->nvolumes;
93 hammer_modify_volume_done(volume);
94 hammer_rel_volume(volume, 0);
97 hammer_unlock(&hmp->blkmap_lock);
98 hammer_sync_unlock(trans);
102 kprintf("An error occured: %d\n", error);
109 hammer_format_volume_header(struct hammer_mount *hmp, const char *vol_name,
110 int vol_no, int vol_count,
111 int64_t vol_size, int64_t boot_area_size, int64_t mem_area_size)
113 struct vnode *devvp = NULL;
114 struct buf *bp = NULL;
115 struct nlookupdata nd;
116 struct hammer_volume_ondisk *ondisk;
120 * Get the device vnode
122 error = nlookup_init(&nd, vol_name, UIO_SYSSPACE, NLC_FOLLOW);
124 error = nlookup(&nd);
126 error = cache_vref(&nd.nl_nch, nd.nl_cred, &devvp);
130 if (vn_isdisk(devvp, &error)) {
131 error = vfs_mountedon(devvp);
135 count_udev(devvp->v_umajor, devvp->v_uminor) > 0) {
139 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
140 error = vinvalbuf(devvp, V_SAVE, 0, 0);
142 error = VOP_OPEN(devvp, FREAD|FWRITE, FSCRED, NULL);
153 * Extract the volume number from the volume header and do various
156 KKASSERT(HAMMER_BUFSIZE >= sizeof(struct hammer_volume_ondisk));
157 error = bread(devvp, 0LL, HAMMER_BUFSIZE, &bp);
158 if (error || bp->b_bcount < sizeof(struct hammer_volume_ondisk))
161 ondisk = (struct hammer_volume_ondisk*) bp->b_data;
164 * Note that we do NOT allow to use a device that contains
165 * a valid HAMMER signature. It has to be cleaned up with dd
168 if (ondisk->vol_signature == HAMMER_FSBUF_VOLUME) {
169 kprintf("hammer_expand: Formatting of valid HAMMER volume "
170 "%s denied. Erase with dd!\n", vol_name);
175 bzero(ondisk, sizeof(struct hammer_volume_ondisk));
176 ksnprintf(ondisk->vol_name, sizeof(ondisk->vol_name), "%s", vol_name);
177 ondisk->vol_fstype = hmp->rootvol->ondisk->vol_fstype;
178 ondisk->vol_signature = HAMMER_FSBUF_VOLUME;
179 ondisk->vol_fsid = hmp->fsid;
180 ondisk->vol_rootvol = hmp->rootvol->vol_no;
181 ondisk->vol_no = vol_no;
182 ondisk->vol_count = vol_count;
183 ondisk->vol_version = hmp->version;
186 * Reserve space for (future) header junk, setup our poor-man's
187 * bigblock allocator.
189 int64_t vol_alloc = HAMMER_BUFSIZE * 16;
191 ondisk->vol_bot_beg = vol_alloc;
192 vol_alloc += boot_area_size;
193 ondisk->vol_mem_beg = vol_alloc;
194 vol_alloc += mem_area_size;
197 * The remaining area is the zone 2 buffer allocation area. These
200 ondisk->vol_buf_beg = vol_alloc;
201 ondisk->vol_buf_end = vol_size & ~(int64_t)HAMMER_BUFMASK;
203 if (ondisk->vol_buf_end < ondisk->vol_buf_beg) {
204 kprintf("volume %d %s is too small to hold the volume header",
205 ondisk->vol_no, ondisk->vol_name);
210 ondisk->vol_nblocks = (ondisk->vol_buf_end - ondisk->vol_buf_beg) /
212 ondisk->vol_blocksize = HAMMER_BUFSIZE;
215 * Write volume header to disk
223 VOP_CLOSE(devvp, FREAD|FWRITE);