static int hammer2_ioctl_pfs_snapshot(hammer2_inode_t *ip, void *data) { hammer2_ioc_pfs_t *pfs = data; hammer2_dev_t *hmp; hammer2_chain_t *chain; hammer2_tid_t mtid; int error; if (pfs->name[0] == 0) return(EINVAL); if (pfs->name[sizeof(pfs->name)-1] != 0) return(EINVAL); hmp = ip->pmp->pfs_hmps[0]; if (hmp == NULL) return (EINVAL); hammer2_vfs_sync(ip->pmp->mp, MNT_WAIT); hammer2_trans_init(ip->pmp, HAMMER2_TRANS_ISFLUSH); mtid = hammer2_trans_sub(ip->pmp); hammer2_inode_lock(ip, 0); chain = hammer2_inode_chain(ip, 0, HAMMER2_RESOLVE_ALWAYS); error = hammer2_chain_snapshot(chain, pfs, mtid); hammer2_chain_unlock(chain); hammer2_chain_drop(chain); hammer2_inode_unlock(ip); hammer2_trans_done(ip->pmp); return (error); }
/* * Destroy an existing PFS under the super-root */ static int hammer2_ioctl_pfs_delete(hammer2_inode_t *ip, void *data) { hammer2_ioc_pfs_t *pfs = data; hammer2_dev_t *hmp; hammer2_pfs_t *spmp; hammer2_xop_unlink_t *xop; hammer2_inode_t *dip; int error; pfs->name[sizeof(pfs->name) - 1] = 0; /* ensure termination */ hmp = ip->pmp->pfs_hmps[0]; if (hmp == NULL) return (EINVAL); spmp = hmp->spmp; dip = spmp->iroot; hammer2_trans_init(spmp, 0); hammer2_inode_lock(dip, 0); xop = hammer2_xop_alloc(dip, HAMMER2_XOP_MODIFYING); hammer2_xop_setname(&xop->head, pfs->name, strlen(pfs->name)); xop->isdir = 2; xop->dopermanent = 1; hammer2_xop_start(&xop->head, hammer2_xop_unlink); error = hammer2_xop_collect(&xop->head, 0); hammer2_inode_unlock(dip); hammer2_trans_done(spmp); return (error); }
/* * Set various parameters in an inode which cannot be set through * normal filesystem VNOPS. */ static int hammer2_ioctl_inode_set(hammer2_inode_t *ip, void *data) { hammer2_ioc_inode_t *ino = data; int error = 0; hammer2_trans_init(ip->pmp, 0); hammer2_inode_lock(ip, 0); if ((ino->flags & HAMMER2IOC_INODE_FLAG_CHECK) && ip->meta.check_algo != ino->ip_data.meta.check_algo) { hammer2_inode_modify(ip); ip->meta.check_algo = ino->ip_data.meta.check_algo; } if ((ino->flags & HAMMER2IOC_INODE_FLAG_COMP) && ip->meta.comp_algo != ino->ip_data.meta.comp_algo) { hammer2_inode_modify(ip); ip->meta.comp_algo = ino->ip_data.meta.comp_algo; } ino->kdata = ip; /* Ignore these flags for now...*/ if ((ino->flags & HAMMER2IOC_INODE_FLAG_IQUOTA) && ip->meta.inode_quota != ino->ip_data.meta.inode_quota) { hammer2_inode_modify(ip); ip->meta.inode_quota = ino->ip_data.meta.inode_quota; } if ((ino->flags & HAMMER2IOC_INODE_FLAG_DQUOTA) && ip->meta.data_quota != ino->ip_data.meta.data_quota) { hammer2_inode_modify(ip); ip->meta.data_quota = ino->ip_data.meta.data_quota; } if ((ino->flags & HAMMER2IOC_INODE_FLAG_COPIES) && ip->meta.ncopies != ino->ip_data.meta.ncopies) { hammer2_inode_modify(ip); ip->meta.ncopies = ino->ip_data.meta.ncopies; } hammer2_inode_unlock(ip); hammer2_trans_done(ip->pmp); return (error); }
/* * This is called from the mount code to initialize pmp->ihidden */ void hammer2_inode_install_hidden(hammer2_pfsmount_t *pmp) { hammer2_trans_t trans; hammer2_chain_t *parent; hammer2_chain_t *chain; hammer2_chain_t *scan; hammer2_inode_data_t *ipdata; hammer2_key_t key_dummy; hammer2_key_t key_next; int cache_index; int error; int count; if (pmp->ihidden) return; /* * Find the hidden directory */ bzero(&key_dummy, sizeof(key_dummy)); hammer2_trans_init(&trans, pmp, NULL, 0); parent = hammer2_inode_lock_ex(pmp->iroot); chain = hammer2_chain_lookup(&parent, &key_dummy, HAMMER2_INODE_HIDDENDIR, HAMMER2_INODE_HIDDENDIR, &cache_index, 0); if (chain) { pmp->ihidden = hammer2_inode_get(pmp, pmp->iroot, chain); hammer2_inode_ref(pmp->ihidden); /* * Remove any unlinked files which were left open as-of * any system crash. */ count = 0; scan = hammer2_chain_lookup(&chain, &key_next, 0, HAMMER2_MAX_TID, &cache_index, HAMMER2_LOOKUP_NODATA); while (scan) { if (scan->bref.type == HAMMER2_BREF_TYPE_INODE) { hammer2_chain_delete(&trans, scan, 0); ++count; } scan = hammer2_chain_next(&chain, scan, &key_next, 0, HAMMER2_MAX_TID, &cache_index, HAMMER2_LOOKUP_NODATA); } hammer2_inode_unlock_ex(pmp->ihidden, chain); hammer2_inode_unlock_ex(pmp->iroot, parent); hammer2_trans_done(&trans); kprintf("hammer2: PFS loaded hidden dir, " "removed %d dead entries\n", count); return; } /* * Create the hidden directory */ error = hammer2_chain_create(&trans, &parent, &chain, HAMMER2_INODE_HIDDENDIR, 0, HAMMER2_BREF_TYPE_INODE, HAMMER2_INODE_BYTES); hammer2_inode_unlock_ex(pmp->iroot, parent); hammer2_chain_modify(&trans, &chain, 0); ipdata = &chain->data->ipdata; ipdata->type = HAMMER2_OBJTYPE_DIRECTORY; ipdata->inum = HAMMER2_INODE_HIDDENDIR; ipdata->nlinks = 1; kprintf("hammer2: PFS root missing hidden directory, creating\n"); pmp->ihidden = hammer2_inode_get(pmp, pmp->iroot, chain); hammer2_inode_ref(pmp->ihidden); hammer2_inode_unlock_ex(pmp->ihidden, chain); hammer2_trans_done(&trans); }
/* * 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); }
/* * Primary management thread for an element of a node. A thread will exist * for each element requiring management. * * No management threads are needed for the SPMP or for any PMP with only * a single MASTER. * * On the SPMP - handles bulkfree and dedup operations * On a PFS - handles remastering and synchronization */ void hammer2_primary_sync_thread(void *arg) { hammer2_thread_t *thr = arg; hammer2_pfs_t *pmp; hammer2_deferred_list_t list; hammer2_deferred_ip_t *defer; int error; pmp = thr->pmp; bzero(&list, sizeof(list)); lockmgr(&thr->lk, LK_EXCLUSIVE); while ((thr->flags & HAMMER2_THREAD_STOP) == 0) { /* * Handle freeze request */ if (thr->flags & HAMMER2_THREAD_FREEZE) { atomic_set_int(&thr->flags, HAMMER2_THREAD_FROZEN); atomic_clear_int(&thr->flags, HAMMER2_THREAD_FREEZE); } /* * Force idle if frozen until unfrozen or stopped. */ if (thr->flags & HAMMER2_THREAD_FROZEN) { lksleep(&thr->flags, &thr->lk, 0, "frozen", 0); continue; } /* * Reset state on REMASTER request */ if (thr->flags & HAMMER2_THREAD_REMASTER) { atomic_clear_int(&thr->flags, HAMMER2_THREAD_REMASTER); /* reset state */ } /* * Synchronization scan. */ kprintf("sync_slaves pfs %s clindex %d\n", pmp->pfs_names[thr->clindex], thr->clindex); hammer2_trans_init(pmp, 0); hammer2_inode_ref(pmp->iroot); for (;;) { int didbreak = 0; /* XXX lock synchronize pmp->modify_tid */ error = hammer2_sync_slaves(thr, pmp->iroot, &list); if (error != EAGAIN) break; while ((defer = list.base) != NULL) { hammer2_inode_t *nip; nip = defer->ip; error = hammer2_sync_slaves(thr, nip, &list); if (error && error != EAGAIN) break; if (hammer2_thr_break(thr)) { didbreak = 1; break; } /* * If no additional defers occurred we can * remove this one, otherwrise keep it on * the list and retry once the additional * defers have completed. */ if (defer == list.base) { --list.count; list.base = defer->next; kfree(defer, M_HAMMER2); defer = NULL; /* safety */ hammer2_inode_drop(nip); } } /* * If the thread is being remastered, frozen, or * stopped, clean up any left-over deferals. */ if (didbreak || (error && error != EAGAIN)) { kprintf("didbreak\n"); while ((defer = list.base) != NULL) { --list.count; hammer2_inode_drop(defer->ip); list.base = defer->next; kfree(defer, M_HAMMER2); } if (error == 0 || error == EAGAIN) error = EINPROGRESS; break; } } hammer2_inode_drop(pmp->iroot); hammer2_trans_done(pmp); if (error) kprintf("hammer2_sync_slaves: error %d\n", error); /* * Wait for event, or 5-second poll. */ lksleep(&thr->flags, &thr->lk, 0, "h2idle", hz * 5); } thr->td = NULL; wakeup(thr); lockmgr(&thr->lk, LK_RELEASE); /* thr structure can go invalid after this point */ }