/* * Create a new PFS under the super-root */ static int hammer2_ioctl_pfs_create(hammer2_inode_t *ip, void *data) { hammer2_inode_data_t *nipdata; hammer2_chain_t *nchain; hammer2_dev_t *hmp; hammer2_ioc_pfs_t *pfs; hammer2_inode_t *nip; hammer2_tid_t mtid; int error; hmp = ip->pmp->pfs_hmps[0]; if (hmp == NULL) return (EINVAL); pfs = data; nip = NULL; if (pfs->name[0] == 0) return(EINVAL); pfs->name[sizeof(pfs->name) - 1] = 0; /* ensure 0-termination */ if (hammer2_ioctl_pfs_lookup(ip, pfs) == 0) return(EEXIST); hammer2_trans_init(hmp->spmp, 0); mtid = hammer2_trans_sub(hmp->spmp); nip = hammer2_inode_create(hmp->spmp->iroot, NULL, NULL, pfs->name, strlen(pfs->name), 0, 1, HAMMER2_OBJTYPE_DIRECTORY, 0, HAMMER2_INSERT_PFSROOT, &error); if (error == 0) { hammer2_inode_modify(nip); nchain = hammer2_inode_chain(nip, 0, HAMMER2_RESOLVE_ALWAYS); hammer2_chain_modify(nchain, mtid, 0); nipdata = &nchain->data->ipdata; nip->meta.pfs_type = pfs->pfs_type; nip->meta.pfs_subtype = pfs->pfs_subtype; nip->meta.pfs_clid = pfs->pfs_clid; nip->meta.pfs_fsid = pfs->pfs_fsid; nip->meta.op_flags |= HAMMER2_OPFLAG_PFSROOT; /* * Set default compression and check algorithm. This * can be changed later. * * Do not allow compression on PFS's with the special name * "boot", the boot loader can't decompress (yet). */ nip->meta.comp_algo = HAMMER2_ENC_ALGO(HAMMER2_COMP_NEWFS_DEFAULT); nip->meta.check_algo = HAMMER2_ENC_ALGO( HAMMER2_CHECK_ISCSI32); if (strcasecmp(pfs->name, "boot") == 0) { nip->meta.comp_algo = HAMMER2_ENC_ALGO(HAMMER2_COMP_AUTOZERO); } #if 0 hammer2_blockref_t bref; /* XXX new PFS needs to be rescanned / added */ bref = nchain->bref; kprintf("ADD LOCAL PFS (IOCTL): %s\n", nipdata->filename); hammer2_pfsalloc(nchain, nipdata, bref.modify_tid); #endif /* XXX rescan */ hammer2_chain_unlock(nchain); hammer2_chain_drop(nchain); /* * Super-root isn't mounted, fsync it */ hammer2_inode_ref(nip); hammer2_inode_unlock(nip); hammer2_inode_fsync(nip); hammer2_inode_drop(nip); } hammer2_trans_done(hmp->spmp); return (error); }
/* * Create a snapshot of the specified {parent, ochain} with the specified * label. The originating hammer2_inode must be exclusively locked for * safety. * * The ioctl code has already synced the filesystem. */ int hammer2_cluster_snapshot(hammer2_trans_t *trans, hammer2_cluster_t *ocluster, hammer2_ioc_pfs_t *pfs) { hammer2_mount_t *hmp; hammer2_cluster_t *ncluster; const hammer2_inode_data_t *ipdata; hammer2_inode_data_t *wipdata; hammer2_inode_t *nip; size_t name_len; hammer2_key_t lhc; struct vattr vat; uuid_t opfs_clid; int error; kprintf("snapshot %s\n", pfs->name); name_len = strlen(pfs->name); lhc = hammer2_dirhash(pfs->name, name_len); ipdata = &hammer2_cluster_data(ocluster)->ipdata; opfs_clid = ipdata->pfs_clid; hmp = ocluster->focus->hmp; /* * Create the snapshot directory under the super-root * * Set PFS type, generate a unique filesystem id, and generate * a cluster id. Use the same clid when snapshotting a PFS root, * which theoretically allows the snapshot to be used as part of * the same cluster (perhaps as a cache). * * Copy the (flushed) blockref array. Theoretically we could use * chain_duplicate() but it becomes difficult to disentangle * the shared core so for now just brute-force it. */ VATTR_NULL(&vat); vat.va_type = VDIR; vat.va_mode = 0755; ncluster = NULL; nip = hammer2_inode_create(trans, hmp->spmp->iroot, &vat, proc0.p_ucred, pfs->name, name_len, &ncluster, &error); if (nip) { wipdata = hammer2_cluster_modify_ip(trans, nip, ncluster, 0); wipdata->pfs_type = HAMMER2_PFSTYPE_SNAPSHOT; kern_uuidgen(&wipdata->pfs_fsid, 1); if (ocluster->focus->flags & HAMMER2_CHAIN_PFSROOT) wipdata->pfs_clid = opfs_clid; else kern_uuidgen(&wipdata->pfs_clid, 1); hammer2_cluster_set_chainflags(ncluster, HAMMER2_CHAIN_PFSROOT); /* XXX hack blockset copy */ /* XXX doesn't work with real cluster */ KKASSERT(ocluster->nchains == 1); wipdata->u.blockset = ocluster->focus->data->ipdata.u.blockset; hammer2_cluster_modsync(ncluster); hammer2_inode_unlock_ex(nip, ncluster); } return (error); }