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); }
/* * Retrieve the raw inode structure, non-inclusive of node-specific data. */ static int hammer2_ioctl_inode_get(hammer2_inode_t *ip, void *data) { hammer2_ioc_inode_t *ino; hammer2_chain_t *chain; int error; int i; ino = data; error = 0; hammer2_inode_lock(ip, HAMMER2_RESOLVE_SHARED); ino->data_count = 0; ino->inode_count = 0; for (i = 0; i < ip->cluster.nchains; ++i) { if ((chain = ip->cluster.array[i].chain) != NULL) { if (ino->data_count < chain->bref.data_count) ino->data_count = chain->bref.data_count; if (ino->inode_count < chain->bref.inode_count) ino->inode_count = chain->bref.inode_count; } } bzero(&ino->ip_data, sizeof(ino->ip_data)); ino->ip_data.meta = ip->meta; ino->kdata = ip; hammer2_inode_unlock(ip); 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); }
/* * 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); }
/* * Find a specific PFS by name */ static int hammer2_ioctl_pfs_lookup(hammer2_inode_t *ip, void *data) { const hammer2_inode_data_t *ripdata; hammer2_dev_t *hmp; hammer2_ioc_pfs_t *pfs; hammer2_chain_t *parent; hammer2_chain_t *chain; hammer2_key_t key_next; hammer2_key_t lhc; int cache_index = -1; int error; size_t len; hmp = ip->pmp->pfs_hmps[0]; if (hmp == NULL) return (EINVAL); pfs = data; error = 0; hammer2_inode_lock(hmp->spmp->iroot, HAMMER2_RESOLVE_SHARED); parent = hammer2_inode_chain(hmp->spmp->iroot, 0, HAMMER2_RESOLVE_ALWAYS | HAMMER2_RESOLVE_SHARED); pfs->name[sizeof(pfs->name) - 1] = 0; len = strlen(pfs->name); lhc = hammer2_dirhash(pfs->name, len); chain = hammer2_chain_lookup(&parent, &key_next, lhc, lhc + HAMMER2_DIRHASH_LOMASK, &cache_index, HAMMER2_LOOKUP_SHARED); while (chain) { if (chain->bref.type == HAMMER2_BREF_TYPE_INODE) { ripdata = &chain->data->ipdata; if (ripdata->meta.name_len == len && bcmp(ripdata->filename, pfs->name, len) == 0) { break; } ripdata = NULL; /* safety */ } chain = hammer2_chain_next(&parent, chain, &key_next, key_next, lhc + HAMMER2_DIRHASH_LOMASK, &cache_index, HAMMER2_LOOKUP_SHARED); } /* * Load the data being returned by the ioctl. */ if (chain) { ripdata = &chain->data->ipdata; pfs->name_key = ripdata->meta.name_key; pfs->pfs_type = ripdata->meta.pfs_type; pfs->pfs_subtype = ripdata->meta.pfs_subtype; pfs->pfs_clid = ripdata->meta.pfs_clid; pfs->pfs_fsid = ripdata->meta.pfs_fsid; ripdata = NULL; hammer2_chain_unlock(chain); hammer2_chain_drop(chain); } else { error = ENOENT; } if (parent) { hammer2_chain_unlock(parent); hammer2_chain_drop(parent); } hammer2_inode_unlock(hmp->spmp->iroot); return (error); }
/* * Used to scan and retrieve PFS information. PFS's are directories under * the super-root. * * To scan PFSs pass name_key=0. The function will scan for the next * PFS and set all fields, as well as set name_next to the next key. * When no PFSs remain, name_next is set to (hammer2_key_t)-1. * * To retrieve a particular PFS by key, specify the key but note that * the ioctl will return the lowest key >= specified_key, so the caller * must verify the key. * * To retrieve the PFS associated with the file descriptor, pass * name_key set to (hammer2_key_t)-1. */ static int hammer2_ioctl_pfs_get(hammer2_inode_t *ip, void *data) { const hammer2_inode_data_t *ripdata; hammer2_dev_t *hmp; hammer2_ioc_pfs_t *pfs; hammer2_chain_t *parent; hammer2_chain_t *chain; hammer2_key_t key_next; hammer2_key_t save_key; int cache_index = -1; int error; hmp = ip->pmp->pfs_hmps[0]; if (hmp == NULL) return (EINVAL); pfs = data; save_key = pfs->name_key; error = 0; /* * Setup */ if (save_key == (hammer2_key_t)-1) { hammer2_inode_lock(ip->pmp->iroot, 0); parent = NULL; chain = hammer2_inode_chain(hmp->spmp->iroot, 0, HAMMER2_RESOLVE_ALWAYS | HAMMER2_RESOLVE_SHARED); } else { hammer2_inode_lock(hmp->spmp->iroot, 0); parent = hammer2_inode_chain(hmp->spmp->iroot, 0, HAMMER2_RESOLVE_ALWAYS | HAMMER2_RESOLVE_SHARED); chain = hammer2_chain_lookup(&parent, &key_next, pfs->name_key, HAMMER2_KEY_MAX, &cache_index, HAMMER2_LOOKUP_SHARED); } /* * Locate next PFS */ while (chain) { if (chain->bref.type == HAMMER2_BREF_TYPE_INODE) break; if (parent == NULL) { hammer2_chain_unlock(chain); hammer2_chain_drop(chain); chain = NULL; break; } chain = hammer2_chain_next(&parent, chain, &key_next, key_next, HAMMER2_KEY_MAX, &cache_index, HAMMER2_LOOKUP_SHARED); } /* * Load the data being returned by the ioctl. */ if (chain) { ripdata = &chain->data->ipdata; pfs->name_key = ripdata->meta.name_key; pfs->pfs_type = ripdata->meta.pfs_type; pfs->pfs_subtype = ripdata->meta.pfs_subtype; pfs->pfs_clid = ripdata->meta.pfs_clid; pfs->pfs_fsid = ripdata->meta.pfs_fsid; KKASSERT(ripdata->meta.name_len < sizeof(pfs->name)); bcopy(ripdata->filename, pfs->name, ripdata->meta.name_len); pfs->name[ripdata->meta.name_len] = 0; ripdata = NULL; /* safety */ /* * Calculate name_next, if any. */ if (parent == NULL) { pfs->name_next = (hammer2_key_t)-1; } else { chain = hammer2_chain_next(&parent, chain, &key_next, key_next, HAMMER2_KEY_MAX, &cache_index, HAMMER2_LOOKUP_SHARED); if (chain) pfs->name_next = chain->bref.key; else pfs->name_next = (hammer2_key_t)-1; } } else { pfs->name_next = (hammer2_key_t)-1; error = ENOENT; } /* * Cleanup */ if (chain) { hammer2_chain_unlock(chain); hammer2_chain_drop(chain); } if (parent) { hammer2_chain_unlock(parent); hammer2_chain_drop(parent); } if (save_key == (hammer2_key_t)-1) { hammer2_inode_unlock(ip->pmp->iroot); } else { hammer2_inode_unlock(hmp->spmp->iroot); } return (error); }
/* * Each out of sync node sync-thread must issue an all-nodes XOP scan of * the inode. This creates a multiplication effect since the XOP scan itself * issues to all nodes. However, this is the only way we can safely * synchronize nodes which might have disparate I/O bandwidths and the only * way we can safely deal with stalled nodes. */ static int hammer2_sync_slaves(hammer2_thread_t *thr, hammer2_inode_t *ip, hammer2_deferred_list_t *list) { hammer2_xop_scanall_t *xop; hammer2_chain_t *parent; hammer2_chain_t *chain; hammer2_pfs_t *pmp; hammer2_key_t key_next; hammer2_tid_t sync_tid; int cache_index = -1; int needrescan; int wantupdate; int error; int nerror; int idx; int n; pmp = ip->pmp; idx = thr->clindex; /* cluster node we are responsible for */ needrescan = 0; wantupdate = 0; if (ip->cluster.focus == NULL) return (EINPROGRESS); sync_tid = ip->cluster.focus->bref.modify_tid; #if 0 /* * Nothing to do if all slaves are synchronized. * Nothing to do if cluster not authoritatively readable. */ if (pmp->cluster_flags & HAMMER2_CLUSTER_SSYNCED) return(0); if ((pmp->cluster_flags & HAMMER2_CLUSTER_RDHARD) == 0) return(HAMMER2_ERROR_INCOMPLETE); #endif error = 0; /* * The inode is left unlocked during the scan. Issue a XOP * that does *not* include our cluster index to iterate * properly synchronized elements and resolve our cluster index * against it. */ hammer2_inode_lock(ip, HAMMER2_RESOLVE_SHARED); xop = hammer2_xop_alloc(ip, HAMMER2_XOP_MODIFYING); xop->key_beg = HAMMER2_KEY_MIN; xop->key_end = HAMMER2_KEY_MAX; hammer2_xop_start_except(&xop->head, hammer2_xop_scanall, idx); parent = hammer2_inode_chain(ip, idx, HAMMER2_RESOLVE_ALWAYS | HAMMER2_RESOLVE_SHARED); if (parent->bref.modify_tid != sync_tid) wantupdate = 1; hammer2_inode_unlock(ip); chain = hammer2_chain_lookup(&parent, &key_next, HAMMER2_KEY_MIN, HAMMER2_KEY_MAX, &cache_index, HAMMER2_LOOKUP_SHARED | HAMMER2_LOOKUP_NODIRECT | HAMMER2_LOOKUP_NODATA); error = hammer2_xop_collect(&xop->head, 0); kprintf("XOP_INITIAL xop=%p clindex %d on %s\n", xop, thr->clindex, pmp->pfs_names[thr->clindex]); for (;;) { /* * We are done if our scan is done and the XOP scan is done. * We are done if the XOP scan failed (that is, we don't * have authoritative data to synchronize with). */ int advance_local = 0; int advance_xop = 0; int dodefer = 0; hammer2_chain_t *focus; kprintf("loop xop=%p chain[1]=%p lockcnt=%d\n", xop, xop->head.cluster.array[1].chain, (xop->head.cluster.array[1].chain ? xop->head.cluster.array[1].chain->lockcnt : -1) ); if (chain == NULL && error == ENOENT) break; if (error && error != ENOENT) break; /* * Compare */ if (chain && error == ENOENT) { /* * If we have local chains but the XOP scan is done, * the chains need to be deleted. */ n = -1; focus = NULL; } else if (chain == NULL) { /* * If our local scan is done but the XOP scan is not, * we need to create the missing chain(s). */ n = 1; focus = xop->head.cluster.focus; } else { /* * Otherwise compare to determine the action * needed. */ focus = xop->head.cluster.focus; n = hammer2_chain_cmp(chain, focus); } /* * Take action based on comparison results. */ if (n < 0) { /* * Delete extranious local data. This will * automatically advance the chain. */ nerror = hammer2_sync_destroy(thr, &parent, &chain, 0, idx); } else if (n == 0 && chain->bref.modify_tid != focus->bref.modify_tid) { /* * Matching key but local data or meta-data requires * updating. If we will recurse, we still need to * update to compatible content first but we do not * synchronize modify_tid until the entire recursion * has completed successfully. */ if (focus->bref.type == HAMMER2_BREF_TYPE_INODE) { nerror = hammer2_sync_replace( thr, parent, chain, 0, idx, focus); dodefer = 1; } else { nerror = hammer2_sync_replace( thr, parent, chain, focus->bref.modify_tid, idx, focus); } } else if (n == 0) { /* * 100% match, advance both */ advance_local = 1; advance_xop = 1; nerror = 0; } else if (n > 0) { /* * Insert missing local data. * * If we will recurse, we still need to update to * compatible content first but we do not synchronize * modify_tid until the entire recursion has * completed successfully. */ if (focus->bref.type == HAMMER2_BREF_TYPE_INODE) { nerror = hammer2_sync_insert( thr, &parent, &chain, 0, idx, focus); dodefer = 2; } else { nerror = hammer2_sync_insert( thr, &parent, &chain, focus->bref.modify_tid, idx, focus); } advance_local = 1; advance_xop = 1; } /* * We cannot recurse depth-first because the XOP is still * running in node threads for this scan. Create a placemarker * by obtaining and record the hammer2_inode. * * We excluded our node from the XOP so we must temporarily * add it to xop->head.cluster so it is properly incorporated * into the inode. * * The deferral is pushed onto a LIFO list for bottom-up * synchronization. */ if (error == 0 && dodefer) { hammer2_inode_t *nip; hammer2_deferred_ip_t *defer; KKASSERT(focus->bref.type == HAMMER2_BREF_TYPE_INODE); defer = kmalloc(sizeof(*defer), M_HAMMER2, M_WAITOK | M_ZERO); KKASSERT(xop->head.cluster.array[idx].chain == NULL); xop->head.cluster.array[idx].flags = HAMMER2_CITEM_INVALID; xop->head.cluster.array[idx].chain = chain; nip = hammer2_inode_get(pmp, ip, &xop->head.cluster, idx); xop->head.cluster.array[idx].chain = NULL; hammer2_inode_ref(nip); hammer2_inode_unlock(nip); defer->next = list->base; defer->ip = nip; list->base = defer; ++list->count; needrescan = 1; } /* * If at least one deferral was added and the deferral * list has grown too large, stop adding more. This * will trigger an EAGAIN return. */ if (needrescan && list->count > 1000) break; /* * Advancements for iteration. */ if (advance_xop) { error = hammer2_xop_collect(&xop->head, 0); } if (advance_local) { chain = hammer2_chain_next(&parent, chain, &key_next, key_next, HAMMER2_KEY_MAX, &cache_index, HAMMER2_LOOKUP_SHARED | HAMMER2_LOOKUP_NODIRECT | HAMMER2_LOOKUP_NODATA); } } hammer2_xop_retire(&xop->head, HAMMER2_XOPMASK_VOP); if (chain) { hammer2_chain_unlock(chain); hammer2_chain_drop(chain); } if (parent) { hammer2_chain_unlock(parent); hammer2_chain_drop(parent); } /* * If we added deferrals we want the caller to synchronize them * and then call us again. * * NOTE: In this situation we do not yet want to synchronize our * inode, setting the error code also has that effect. */ if (error == 0 && needrescan) error = EAGAIN; /* * If no error occurred and work was performed, synchronize the * inode meta-data itself. * * XXX inode lock was lost */ if (error == 0 && wantupdate) { hammer2_xop_ipcluster_t *xop2; hammer2_chain_t *focus; xop2 = hammer2_xop_alloc(ip, HAMMER2_XOP_MODIFYING); hammer2_xop_start_except(&xop2->head, hammer2_xop_ipcluster, idx); error = hammer2_xop_collect(&xop2->head, 0); if (error == 0) { focus = xop2->head.cluster.focus; kprintf("syncthr: update inode %p (%s)\n", focus, (focus ? (char *)focus->data->ipdata.filename : "?")); chain = hammer2_inode_chain_and_parent(ip, idx, &parent, HAMMER2_RESOLVE_ALWAYS | HAMMER2_RESOLVE_SHARED); KKASSERT(parent != NULL); nerror = hammer2_sync_replace( thr, parent, chain, sync_tid, idx, focus); hammer2_chain_unlock(chain); hammer2_chain_drop(chain); hammer2_chain_unlock(parent); hammer2_chain_drop(parent); /* XXX */ } hammer2_xop_retire(&xop2->head, HAMMER2_XOPMASK_VOP); } return error; }
/* * Create a PFS inode under the superroot. This function will create the * inode, its media chains, and also insert it into the media. * * Caller must be in a flush transaction because we are inserting the inode * onto the media. */ hammer2_inode_t * hammer2_inode_create_pfs(hammer2_pfs_t *spmp, const uint8_t *name, size_t name_len, int *errorp) { hammer2_xop_create_t *xop; hammer2_inode_t *pip; hammer2_inode_t *nip; int error; uuid_t pip_uid; uuid_t pip_gid; uint32_t pip_mode; uint8_t pip_comp_algo; uint8_t pip_check_algo; hammer2_tid_t pip_inum; hammer2_key_t lhc; pip = spmp->iroot; nip = NULL; lhc = hammer2_dirhash(name, name_len); *errorp = 0; /* * Locate the inode or indirect block to create the new * entry in. At the same time check for key collisions * and iterate until we don't get one. * * Lock the directory exclusively for now to guarantee that * we can find an unused lhc for the name. Due to collisions, * two different creates can end up with the same lhc so we * cannot depend on the OS to prevent the collision. */ hammer2_inode_lock(pip, 0); pip_uid = pip->meta.uid; pip_gid = pip->meta.gid; pip_mode = pip->meta.mode; pip_comp_algo = pip->meta.comp_algo; pip_check_algo = pip->meta.check_algo; pip_inum = (pip == pip->pmp->iroot) ? 1 : pip->meta.inum; /* * Locate an unused key in the collision space. */ { hammer2_xop_scanlhc_t *sxop; hammer2_key_t lhcbase; lhcbase = lhc; sxop = hammer2_xop_alloc(pip, HAMMER2_XOP_MODIFYING); sxop->lhc = lhc; hammer2_xop_start(&sxop->head, &hammer2_scanlhc_desc); while ((error = hammer2_xop_collect(&sxop->head, 0)) == 0) { if (lhc != sxop->head.cluster.focus->bref.key) break; ++lhc; } hammer2_xop_retire(&sxop->head, HAMMER2_XOPMASK_VOP); if (error) { if (error != HAMMER2_ERROR_ENOENT) goto done2; ++lhc; error = 0; } if ((lhcbase ^ lhc) & ~HAMMER2_DIRHASH_LOMASK) { error = HAMMER2_ERROR_ENOSPC; goto done2; } } /* * Create the inode with the lhc as the key. */ xop = hammer2_xop_alloc(pip, HAMMER2_XOP_MODIFYING); xop->lhc = lhc; xop->flags = HAMMER2_INSERT_PFSROOT; bzero(&xop->meta, sizeof(xop->meta)); xop->meta.type = HAMMER2_OBJTYPE_DIRECTORY; xop->meta.inum = 1; xop->meta.iparent = pip_inum; /* Inherit parent's inode compression mode. */ xop->meta.comp_algo = pip_comp_algo; xop->meta.check_algo = pip_check_algo; xop->meta.version = HAMMER2_INODE_VERSION_ONE; hammer2_update_time(&xop->meta.ctime); xop->meta.mtime = xop->meta.ctime; xop->meta.mode = 0755; xop->meta.nlinks = 1; /* * Regular files and softlinks allow a small amount of data to be * directly embedded in the inode. This flag will be cleared if * the size is extended past the embedded limit. */ if (xop->meta.type == HAMMER2_OBJTYPE_REGFILE || xop->meta.type == HAMMER2_OBJTYPE_SOFTLINK) { xop->meta.op_flags |= HAMMER2_OPFLAG_DIRECTDATA; } hammer2_xop_setname(&xop->head, name, name_len); xop->meta.name_len = name_len; xop->meta.name_key = lhc; KKASSERT(name_len < HAMMER2_INODE_MAXNAME); hammer2_xop_start(&xop->head, &hammer2_inode_create_desc); error = hammer2_xop_collect(&xop->head, 0); #if INODE_DEBUG kprintf("CREATE INODE %*.*s\n", (int)name_len, (int)name_len, name); #endif if (error) { *errorp = error; goto done; } /* * Set up the new inode if not a hardlink pointer. * * NOTE: *_get() integrates chain's lock into the inode lock. * * NOTE: Only one new inode can currently be created per * transaction. If the need arises we can adjust * hammer2_trans_init() to allow more. * * NOTE: nipdata will have chain's blockset data. */ nip = hammer2_inode_get(pip->pmp, &xop->head, -1, -1); nip->comp_heuristic = 0; done: hammer2_xop_retire(&xop->head, HAMMER2_XOPMASK_VOP); done2: hammer2_inode_unlock(pip); return (nip); }
/* * Update LNK_SPAN state */ static void hammer2_update_spans(hammer2_dev_t *hmp, kdmsg_state_t *state) { const hammer2_inode_data_t *ripdata; hammer2_chain_t *parent; hammer2_chain_t *chain; hammer2_pfs_t *spmp; hammer2_key_t key_next; kdmsg_msg_t *rmsg; size_t name_len; int cache_index = -1; /* * Lookup mount point under the media-localized super-root. * * cluster->pmp will incorrectly point to spmp and must be fixed * up later on. */ spmp = hmp->spmp; hammer2_inode_lock(spmp->iroot, 0); parent = hammer2_inode_chain(spmp->iroot, 0, HAMMER2_RESOLVE_ALWAYS); chain = NULL; if (parent == NULL) goto done; chain = hammer2_chain_lookup(&parent, &key_next, HAMMER2_KEY_MIN, HAMMER2_KEY_MAX, &cache_index, 0); while (chain) { if (chain->bref.type != HAMMER2_BREF_TYPE_INODE) continue; ripdata = &chain->data->ipdata; kprintf("UPDATE SPANS: %s\n", ripdata->filename); rmsg = kdmsg_msg_alloc(&hmp->iocom.state0, DMSG_LNK_SPAN | DMSGF_CREATE, hammer2_lnk_span_reply, NULL); rmsg->any.lnk_span.peer_id = ripdata->meta.pfs_clid; rmsg->any.lnk_span.pfs_id = ripdata->meta.pfs_fsid; rmsg->any.lnk_span.pfs_type = ripdata->meta.pfs_type; rmsg->any.lnk_span.peer_type = DMSG_PEER_HAMMER2; rmsg->any.lnk_span.proto_version = DMSG_SPAN_PROTO_1; name_len = ripdata->meta.name_len; if (name_len >= sizeof(rmsg->any.lnk_span.peer_label)) name_len = sizeof(rmsg->any.lnk_span.peer_label) - 1; bcopy(ripdata->filename, rmsg->any.lnk_span.peer_label, name_len); kdmsg_msg_write(rmsg); chain = hammer2_chain_next(&parent, chain, &key_next, key_next, HAMMER2_KEY_MAX, &cache_index, 0); } hammer2_inode_unlock(spmp->iroot); done: if (chain) { hammer2_chain_unlock(chain); hammer2_chain_drop(chain); } if (parent) { hammer2_chain_unlock(parent); hammer2_chain_drop(parent); } }