geom_journal.c revision 168304
1163838Spjd/*- 2163838Spjd * Copyright (c) 2005-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3163838Spjd * All rights reserved. 4163838Spjd * 5163838Spjd * Redistribution and use in source and binary forms, with or without 6163838Spjd * modification, are permitted provided that the following conditions 7163838Spjd * are met: 8163838Spjd * 1. Redistributions of source code must retain the above copyright 9163838Spjd * notice, this list of conditions and the following disclaimer. 10163838Spjd * 2. Redistributions in binary form must reproduce the above copyright 11163838Spjd * notice, this list of conditions and the following disclaimer in the 12163838Spjd * documentation and/or other materials provided with the distribution. 13163838Spjd * 14163838Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15163838Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16163838Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17163838Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18163838Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19163838Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20163838Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21163838Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22163838Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23163838Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24163838Spjd * SUCH DAMAGE. 25163838Spjd */ 26163838Spjd 27163838Spjd#include <sys/cdefs.h> 28163838Spjd__FBSDID("$FreeBSD: head/sbin/geom/class/journal/geom_journal.c 168304 2007-04-03 15:29:16Z pjd $"); 29163838Spjd 30163838Spjd#include <sys/types.h> 31163838Spjd#include <errno.h> 32163838Spjd#include <paths.h> 33163838Spjd#include <stdio.h> 34163838Spjd#include <stdlib.h> 35163838Spjd#include <stdint.h> 36163838Spjd#include <string.h> 37163838Spjd#include <strings.h> 38163838Spjd#include <assert.h> 39163838Spjd#include <libgeom.h> 40163838Spjd#include <geom/journal/g_journal.h> 41163838Spjd#include <core/geom.h> 42163838Spjd#include <misc/subr.h> 43163838Spjd 44163838Spjd#include "geom_journal.h" 45163838Spjd 46163838Spjd 47163838Spjduint32_t lib_version = G_LIB_VERSION; 48163838Spjduint32_t version = G_JOURNAL_VERSION; 49163838Spjd 50163838Spjdstatic intmax_t default_jsize = -1; 51163838Spjd 52163838Spjdstatic void journal_main(struct gctl_req *req, unsigned flags); 53163838Spjdstatic void journal_clear(struct gctl_req *req); 54163838Spjdstatic void journal_dump(struct gctl_req *req); 55163838Spjdstatic void journal_label(struct gctl_req *req); 56163838Spjd 57163838Spjdstruct g_command class_commands[] = { 58163838Spjd { "clear", G_FLAG_VERBOSE, journal_main, G_NULL_OPTS, 59163838Spjd "[-v] prov ..." 60163838Spjd }, 61163838Spjd { "dump", 0, journal_main, G_NULL_OPTS, 62163838Spjd "prov ..." 63163838Spjd }, 64163838Spjd { "label", G_FLAG_VERBOSE, journal_main, 65163838Spjd { 66163838Spjd { 'c', "checksum", NULL, G_TYPE_BOOL }, 67163838Spjd { 'f', "force", NULL, G_TYPE_BOOL }, 68163838Spjd { 'h', "hardcode", NULL, G_TYPE_BOOL }, 69163838Spjd { 's', "jsize", &default_jsize, G_TYPE_NUMBER }, 70163838Spjd G_OPT_SENTINEL 71163838Spjd }, 72163838Spjd "[-cfhv] [-s jsize] dataprov [jprov]" 73163838Spjd }, 74163838Spjd { "stop", G_FLAG_VERBOSE, NULL, 75163838Spjd { 76163838Spjd { 'f', "force", NULL, G_TYPE_BOOL }, 77163838Spjd G_OPT_SENTINEL 78163838Spjd }, 79163838Spjd "[-fv] name ..." 80163838Spjd }, 81163838Spjd { "sync", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, 82163838Spjd "[-v]" 83163838Spjd }, 84163838Spjd G_CMD_SENTINEL 85163838Spjd}; 86163838Spjd 87163838Spjdstatic int verbose = 0; 88163838Spjd 89163838Spjdstatic void 90163838Spjdjournal_main(struct gctl_req *req, unsigned flags) 91163838Spjd{ 92163838Spjd const char *name; 93163838Spjd 94163838Spjd if ((flags & G_FLAG_VERBOSE) != 0) 95163838Spjd verbose = 1; 96163838Spjd 97163838Spjd name = gctl_get_ascii(req, "verb"); 98163838Spjd if (name == NULL) { 99163838Spjd gctl_error(req, "No '%s' argument.", "verb"); 100163838Spjd return; 101163838Spjd } 102163838Spjd if (strcmp(name, "label") == 0) 103163838Spjd journal_label(req); 104163838Spjd else if (strcmp(name, "clear") == 0) 105163838Spjd journal_clear(req); 106163838Spjd else if (strcmp(name, "dump") == 0) 107163838Spjd journal_dump(req); 108163838Spjd else 109163838Spjd gctl_error(req, "Unknown command: %s.", name); 110163838Spjd} 111163838Spjd 112163838Spjdstatic int 113163838Spjdg_journal_fs_exists(const char *prov) 114163838Spjd{ 115163838Spjd 116163838Spjd if (g_journal_ufs_exists(prov)) 117163838Spjd return (1); 118163838Spjd#if 0 119163838Spjd if (g_journal_otherfs_exists(prov)) 120163838Spjd return (1); 121163838Spjd#endif 122163838Spjd return (0); 123163838Spjd} 124163838Spjd 125163838Spjdstatic int 126163838Spjdg_journal_fs_using_last_sector(const char *prov) 127163838Spjd{ 128163838Spjd 129163838Spjd if (g_journal_ufs_using_last_sector(prov)) 130163838Spjd return (1); 131163838Spjd#if 0 132163838Spjd if (g_journal_otherfs_using_last_sector(prov)) 133163838Spjd return (1); 134163838Spjd#endif 135163838Spjd return (0); 136163838Spjd} 137163838Spjd 138163838Spjdstatic void 139163838Spjdjournal_label(struct gctl_req *req) 140163838Spjd{ 141163838Spjd struct g_journal_metadata md; 142163838Spjd const char *data, *journal, *str; 143163838Spjd u_char sector[512]; 144163838Spjd intmax_t jsize, msize, ssize; 145163838Spjd int error, force, i, nargs, checksum, hardcode; 146163838Spjd 147163838Spjd nargs = gctl_get_int(req, "nargs"); 148163864Spjd str = NULL; /* gcc */ 149163838Spjd 150163838Spjd strlcpy(md.md_magic, G_JOURNAL_MAGIC, sizeof(md.md_magic)); 151163838Spjd md.md_version = G_JOURNAL_VERSION; 152163838Spjd md.md_id = arc4random(); 153163838Spjd md.md_joffset = 0; 154163838Spjd md.md_jid = 0; 155163838Spjd md.md_flags = GJ_FLAG_CLEAN; 156163838Spjd checksum = gctl_get_int(req, "checksum"); 157163838Spjd if (checksum) 158163838Spjd md.md_flags |= GJ_FLAG_CHECKSUM; 159163838Spjd force = gctl_get_int(req, "force"); 160163838Spjd hardcode = gctl_get_int(req, "hardcode"); 161163838Spjd 162163838Spjd if (nargs != 1 && nargs != 2) { 163163838Spjd gctl_error(req, "Invalid number of arguments."); 164163838Spjd return; 165163838Spjd } 166163838Spjd 167163838Spjd /* Verify the given providers. */ 168163838Spjd for (i = 0; i < nargs; i++) { 169163838Spjd str = gctl_get_ascii(req, "arg%d", i); 170163838Spjd if (g_get_mediasize(str) == 0) { 171163838Spjd gctl_error(req, "Invalid provider %s.", str); 172163838Spjd return; 173163838Spjd } 174163838Spjd } 175163838Spjd 176163838Spjd data = gctl_get_ascii(req, "arg0"); 177163838Spjd jsize = gctl_get_intmax(req, "jsize"); 178163838Spjd journal = NULL; 179163838Spjd switch (nargs) { 180163838Spjd case 1: 181163838Spjd if (!force && g_journal_fs_exists(data)) { 182163838Spjd gctl_error(req, "File system exists on %s and this " 183168304Spjd "operation would destroy it.\nUse -f if you " 184163838Spjd "really want to do it.", data); 185163838Spjd return; 186163838Spjd } 187163838Spjd journal = data; 188168304Spjd msize = g_get_mediasize(data); 189168304Spjd ssize = g_get_sectorsize(data); 190163838Spjd if (jsize == -1) { 191163838Spjd /* 192163838Spjd * No journal size specified. 1GB should be safe 193163838Spjd * default. 194163838Spjd */ 195163838Spjd jsize = 1073741824ULL; 196168304Spjd } else { 197168304Spjd if (jsize < 104857600) { 198168304Spjd gctl_error(req, "Journal too small."); 199168304Spjd return; 200168304Spjd } 201168304Spjd if ((jsize % ssize) != 0) { 202168304Spjd gctl_error(req, "Invalid journal size."); 203168304Spjd return; 204168304Spjd } 205163838Spjd } 206163838Spjd if (jsize + ssize >= msize) { 207163838Spjd gctl_error(req, "Provider too small for journalling. " 208163838Spjd "You can try smaller jsize (default is %jd).", 209163838Spjd jsize); 210163838Spjd return; 211163838Spjd } 212163838Spjd md.md_jstart = msize - ssize - jsize; 213163838Spjd md.md_jend = msize - ssize; 214163838Spjd break; 215163838Spjd case 2: 216163838Spjd if (!force && g_journal_fs_using_last_sector(data)) { 217163838Spjd gctl_error(req, "File system on %s is using the last " 218163838Spjd "sector and this operation is going to overwrite " 219163838Spjd "it. Use -f if you really want to do it.", data); 220163838Spjd return; 221163838Spjd } 222163838Spjd journal = gctl_get_ascii(req, "arg1"); 223163838Spjd if (jsize != -1) { 224163838Spjd gctl_error(req, "jsize argument is valid only for " 225163838Spjd "all-in-one configuration."); 226163838Spjd return; 227163838Spjd } 228163838Spjd msize = g_get_mediasize(journal); 229163838Spjd ssize = g_get_sectorsize(journal); 230163838Spjd md.md_jstart = 0; 231163838Spjd md.md_jend = msize - ssize; 232163838Spjd break; 233163838Spjd } 234163838Spjd 235163838Spjd if (g_get_sectorsize(data) != g_get_sectorsize(journal)) { 236163838Spjd gctl_error(req, "Not equal sector sizes."); 237163838Spjd return; 238163838Spjd } 239163838Spjd 240163838Spjd /* 241163838Spjd * Clear last sector first, to spoil all components if device exists. 242163838Spjd */ 243163838Spjd for (i = 0; i < nargs; i++) { 244163838Spjd str = gctl_get_ascii(req, "arg%d", i); 245163838Spjd error = g_metadata_clear(str, NULL); 246163838Spjd if (error != 0) { 247163838Spjd gctl_error(req, "Cannot clear metadata on %s: %s.", str, 248163838Spjd strerror(error)); 249163838Spjd return; 250163838Spjd } 251163838Spjd } 252163838Spjd 253163838Spjd /* 254163838Spjd * Ok, store metadata. 255163838Spjd */ 256163838Spjd for (i = 0; i < nargs; i++) { 257163838Spjd switch (i) { 258163838Spjd case 0: 259163838Spjd str = data; 260163838Spjd md.md_type = GJ_TYPE_DATA; 261163838Spjd if (nargs == 1) 262163838Spjd md.md_type |= GJ_TYPE_JOURNAL; 263163838Spjd break; 264163838Spjd case 1: 265163838Spjd str = journal; 266163838Spjd md.md_type = GJ_TYPE_JOURNAL; 267163838Spjd break; 268163838Spjd } 269163838Spjd md.md_provsize = g_get_mediasize(str); 270163838Spjd assert(md.md_provsize != 0); 271163838Spjd if (!hardcode) 272163838Spjd bzero(md.md_provider, sizeof(md.md_provider)); 273163838Spjd else { 274163838Spjd if (strncmp(str, _PATH_DEV, strlen(_PATH_DEV)) == 0) 275163838Spjd str += strlen(_PATH_DEV); 276163838Spjd strlcpy(md.md_provider, str, sizeof(md.md_provider)); 277163838Spjd } 278163838Spjd journal_metadata_encode(&md, sector); 279163838Spjd error = g_metadata_store(str, sector, sizeof(sector)); 280163838Spjd if (error != 0) { 281163838Spjd fprintf(stderr, "Cannot store metadata on %s: %s.\n", 282163838Spjd str, strerror(error)); 283163838Spjd gctl_error(req, "Not fully done."); 284163838Spjd continue; 285163838Spjd } 286163838Spjd if (verbose) 287163838Spjd printf("Metadata value stored on %s.\n", str); 288163838Spjd } 289163838Spjd} 290163838Spjd 291163838Spjdstatic void 292163838Spjdjournal_clear(struct gctl_req *req) 293163838Spjd{ 294163838Spjd const char *name; 295163838Spjd int error, i, nargs; 296163838Spjd 297163838Spjd nargs = gctl_get_int(req, "nargs"); 298163838Spjd if (nargs < 1) { 299163838Spjd gctl_error(req, "Too few arguments."); 300163838Spjd return; 301163838Spjd } 302163838Spjd 303163838Spjd for (i = 0; i < nargs; i++) { 304163838Spjd name = gctl_get_ascii(req, "arg%d", i); 305163838Spjd error = g_metadata_clear(name, G_JOURNAL_MAGIC); 306163838Spjd if (error != 0) { 307163838Spjd fprintf(stderr, "Cannot clear metadata on %s: %s.\n", 308163838Spjd name, strerror(error)); 309163838Spjd gctl_error(req, "Not fully done."); 310163838Spjd continue; 311163838Spjd } 312163838Spjd if (verbose) 313163838Spjd printf("Metadata cleared on %s.\n", name); 314163838Spjd } 315163838Spjd} 316163838Spjd 317163838Spjdstatic void 318163838Spjdjournal_dump(struct gctl_req *req) 319163838Spjd{ 320163838Spjd struct g_journal_metadata md, tmpmd; 321163838Spjd const char *name; 322163838Spjd int error, i, nargs; 323163838Spjd 324163838Spjd nargs = gctl_get_int(req, "nargs"); 325163838Spjd if (nargs < 1) { 326163838Spjd gctl_error(req, "Too few arguments."); 327163838Spjd return; 328163838Spjd } 329163838Spjd 330163838Spjd for (i = 0; i < nargs; i++) { 331163838Spjd name = gctl_get_ascii(req, "arg%d", i); 332163838Spjd error = g_metadata_read(name, (u_char *)&tmpmd, sizeof(tmpmd), 333163838Spjd G_JOURNAL_MAGIC); 334163838Spjd if (error != 0) { 335163838Spjd fprintf(stderr, "Cannot read metadata from %s: %s.\n", 336163838Spjd name, strerror(error)); 337163838Spjd gctl_error(req, "Not fully done."); 338163838Spjd continue; 339163838Spjd } 340163838Spjd if (journal_metadata_decode((u_char *)&tmpmd, &md) != 0) { 341163838Spjd fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n", 342163838Spjd name); 343163838Spjd gctl_error(req, "Not fully done."); 344163838Spjd continue; 345163838Spjd } 346163838Spjd printf("Metadata on %s:\n", name); 347163838Spjd journal_metadata_dump(&md); 348163838Spjd printf("\n"); 349163838Spjd } 350163838Spjd} 351