/* * 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); }
/* * 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); }
/* * Create a directory entry under dip with the specified name, inode number, * and OBJTYPE (type). * * This returns a UNIX errno code, not a HAMMER2_ERROR_* code. * * Caller must hold dip locked. */ int hammer2_dirent_create(hammer2_inode_t *dip, const char *name, size_t name_len, hammer2_key_t inum, uint8_t type) { hammer2_xop_mkdirent_t *xop; hammer2_key_t lhc; int error; lhc = 0; error = 0; KKASSERT(name != NULL); lhc = hammer2_dirhash(name, name_len); /* * 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_modify(dip); /* * If name specified, locate an unused key in the collision space. * Otherwise use the passed-in lhc directly. */ { hammer2_xop_scanlhc_t *sxop; hammer2_key_t lhcbase; lhcbase = lhc; sxop = hammer2_xop_alloc(dip, 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 directory entry with the lhc as the key. */ xop = hammer2_xop_alloc(dip, HAMMER2_XOP_MODIFYING); xop->lhc = lhc; bzero(&xop->dirent, sizeof(xop->dirent)); xop->dirent.inum = inum; xop->dirent.type = type; xop->dirent.namlen = name_len; KKASSERT(name_len < HAMMER2_INODE_MAXNAME); hammer2_xop_setname(&xop->head, name, name_len); hammer2_xop_start(&xop->head, &hammer2_inode_mkdirent_desc); error = hammer2_xop_collect(&xop->head, 0); hammer2_xop_retire(&xop->head, HAMMER2_XOPMASK_VOP); done2: error = hammer2_error_to_errno(error); return error; }