/* * Create a new, normal inode. This function will create the inode, * the media chains, but will not insert the chains onto the media topology * (doing so would require a flush transaction and cause long stalls). * * Caller must be in a normal transaction. */ hammer2_inode_t * hammer2_inode_create_normal(hammer2_inode_t *pip, struct vattr *vap, struct ucred *cred, hammer2_key_t inum, int *errorp) { hammer2_xop_create_t *xop; hammer2_inode_t *dip; hammer2_inode_t *nip; int error; uid_t xuid; 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; uint8_t type; dip = pip->pmp->iroot; KKASSERT(dip != NULL); *errorp = 0; /*hammer2_inode_lock(dip, 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; /* * Create the in-memory hammer2_inode structure for the specified * inode. */ nip = hammer2_inode_get(dip->pmp, NULL, inum, -1); nip->comp_heuristic = 0; KKASSERT((nip->flags & HAMMER2_INODE_CREATING) == 0 && nip->cluster.nchains == 0); atomic_set_int(&nip->flags, HAMMER2_INODE_CREATING); /* * Setup the inode meta-data */ nip->meta.type = hammer2_get_obj_type(vap->va_type); switch (nip->meta.type) { case HAMMER2_OBJTYPE_CDEV: case HAMMER2_OBJTYPE_BDEV: nip->meta.rmajor = vap->va_rmajor; nip->meta.rminor = vap->va_rminor; break; default: break; } type = nip->meta.type; KKASSERT(nip->meta.inum == inum); nip->meta.iparent = pip_inum; /* Inherit parent's inode compression mode. */ nip->meta.comp_algo = pip_comp_algo; nip->meta.check_algo = pip_check_algo; nip->meta.version = HAMMER2_INODE_VERSION_ONE; hammer2_update_time(&nip->meta.ctime); nip->meta.mtime = nip->meta.ctime; nip->meta.mode = vap->va_mode; nip->meta.nlinks = 1; xuid = hammer2_to_unix_xid(&pip_uid); xuid = vop_helper_create_uid(dip->pmp->mp, pip_mode, xuid, cred, &vap->va_mode); if (vap->va_vaflags & VA_UID_UUID_VALID) nip->meta.uid = vap->va_uid_uuid; else if (vap->va_uid != (uid_t)VNOVAL) hammer2_guid_to_uuid(&nip->meta.uid, vap->va_uid); else hammer2_guid_to_uuid(&nip->meta.uid, xuid); if (vap->va_vaflags & VA_GID_UUID_VALID) nip->meta.gid = vap->va_gid_uuid; else if (vap->va_gid != (gid_t)VNOVAL) hammer2_guid_to_uuid(&nip->meta.gid, vap->va_gid); else nip->meta.gid = pip_gid; /* * 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 (nip->meta.type == HAMMER2_OBJTYPE_REGFILE || nip->meta.type == HAMMER2_OBJTYPE_SOFTLINK) { nip->meta.op_flags |= HAMMER2_OPFLAG_DIRECTDATA; } /* * Create the inode using (inum) as the key. Pass pip for * method inheritance. */ xop = hammer2_xop_alloc(pip, HAMMER2_XOP_MODIFYING); xop->lhc = inum; xop->flags = 0; xop->meta = nip->meta; KKASSERT(vap); xop->meta.name_len = hammer2_xop_setname_inum(&xop->head, inum); xop->meta.name_key = inum; nip->meta.name_len = xop->meta.name_len; nip->meta.name_key = xop->meta.name_key; hammer2_inode_modify(nip); /* * Create the inode media chains but leave them detached. We are * not in a flush transaction so we can't mess with media topology * above normal inodes (i.e. the index of the inodes themselves). * * We've already set the INODE_CREATING flag. The inode's media * chains will be inserted onto the media topology on the next * filesystem sync. */ hammer2_xop_start(&xop->head, &hammer2_inode_create_det_desc); error = hammer2_xop_collect(&xop->head, 0); #if INODE_DEBUG kprintf("create inode type %d error %d\n", nip->meta.type, error); #endif if (error) { *errorp = error; goto done; } /* * Associate the media chains created by the backend with the * frontend inode. */ hammer2_inode_repoint(nip, NULL, &xop->head.cluster); done: hammer2_xop_retire(&xop->head, HAMMER2_XOPMASK_VOP); /*hammer2_inode_unlock(dip);*/ return (nip); }
/* * Create a new inode in the specified directory using the vattr to * figure out the type of inode. * * If no error occurs the new inode with its chain locked is returned in * *nipp, otherwise an error is returned and *nipp is set to NULL. * * If vap and/or cred are NULL the related fields are not set and the * inode type defaults to a directory. This is used when creating PFSs * under the super-root, so the inode number is set to 1 in this case. * * dip is not locked on entry. */ hammer2_inode_t * hammer2_inode_create(hammer2_trans_t *trans, hammer2_inode_t *dip, struct vattr *vap, struct ucred *cred, const uint8_t *name, size_t name_len, hammer2_chain_t **chainp, int *errorp) { hammer2_inode_data_t *dipdata; hammer2_inode_data_t *nipdata; hammer2_chain_t *chain; hammer2_chain_t *parent; hammer2_inode_t *nip; hammer2_key_t key_dummy; hammer2_key_t lhc; int error; uid_t xuid; uuid_t dip_uid; uuid_t dip_gid; uint32_t dip_mode; uint8_t dip_algo; int cache_index = -1; 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. * * NOTE: hidden inodes do not have iterators. */ retry: parent = hammer2_inode_lock_ex(dip); dipdata = &dip->chain->data->ipdata; dip_uid = dipdata->uid; dip_gid = dipdata->gid; dip_mode = dipdata->mode; dip_algo = dipdata->comp_algo; error = 0; while (error == 0) { chain = hammer2_chain_lookup(&parent, &key_dummy, lhc, lhc, &cache_index, 0); if (chain == NULL) break; if ((lhc & HAMMER2_DIRHASH_VISIBLE) == 0) error = ENOSPC; if ((lhc & HAMMER2_DIRHASH_LOMASK) == HAMMER2_DIRHASH_LOMASK) error = ENOSPC; hammer2_chain_unlock(chain); chain = NULL; ++lhc; } if (error == 0) { error = hammer2_chain_create(trans, &parent, &chain, lhc, 0, HAMMER2_BREF_TYPE_INODE, HAMMER2_INODE_BYTES); } /* * Cleanup and handle retries. */ if (error == EAGAIN) { hammer2_chain_ref(parent); hammer2_inode_unlock_ex(dip, parent); hammer2_chain_wait(parent); hammer2_chain_drop(parent); goto retry; } hammer2_inode_unlock_ex(dip, parent); if (error) { KKASSERT(chain == NULL); *errorp = error; return (NULL); } /* * Set up the new inode. * * 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. */ chain->data->ipdata.inum = trans->inode_tid; nip = hammer2_inode_get(dip->pmp, dip, chain); nipdata = &chain->data->ipdata; if (vap) { KKASSERT(trans->inodes_created == 0); nipdata->type = hammer2_get_obj_type(vap->va_type); nipdata->inum = trans->inode_tid; ++trans->inodes_created; switch (nipdata->type) { case HAMMER2_OBJTYPE_CDEV: case HAMMER2_OBJTYPE_BDEV: nipdata->rmajor = vap->va_rmajor; nipdata->rminor = vap->va_rminor; break; default: break; } } else { nipdata->type = HAMMER2_OBJTYPE_DIRECTORY; nipdata->inum = 1; } /* Inherit parent's inode compression mode. */ nip->comp_heuristic = 0; nipdata->comp_algo = dip_algo; nipdata->version = HAMMER2_INODE_VERSION_ONE; hammer2_update_time(&nipdata->ctime); nipdata->mtime = nipdata->ctime; if (vap) nipdata->mode = vap->va_mode; nipdata->nlinks = 1; if (vap) { if (dip && dip->pmp) { xuid = hammer2_to_unix_xid(&dip_uid); xuid = vop_helper_create_uid(dip->pmp->mp, dip_mode, xuid, cred, &vap->va_mode); } else { /* super-root has no dip and/or pmp */ xuid = 0; } if (vap->va_vaflags & VA_UID_UUID_VALID) nipdata->uid = vap->va_uid_uuid; else if (vap->va_uid != (uid_t)VNOVAL) hammer2_guid_to_uuid(&nipdata->uid, vap->va_uid); else hammer2_guid_to_uuid(&nipdata->uid, xuid); if (vap->va_vaflags & VA_GID_UUID_VALID) nipdata->gid = vap->va_gid_uuid; else if (vap->va_gid != (gid_t)VNOVAL) hammer2_guid_to_uuid(&nipdata->gid, vap->va_gid); else if (dip) nipdata->gid = dip_gid; } /* * 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 (nipdata->type == HAMMER2_OBJTYPE_REGFILE || nipdata->type == HAMMER2_OBJTYPE_SOFTLINK) { nipdata->op_flags |= HAMMER2_OPFLAG_DIRECTDATA; } KKASSERT(name_len < HAMMER2_INODE_MAXNAME); bcopy(name, nipdata->filename, name_len); nipdata->name_key = lhc; nipdata->name_len = name_len; *chainp = chain; return (nip); }
/* * Create a new inode in the specified directory using the vattr to * figure out the type of inode. * * If no error occurs the new inode with its chain locked is returned in * *nipp, otherwise an error is returned and *nipp is set to NULL. * * If vap and/or cred are NULL the related fields are not set and the * inode type defaults to a directory. This is used when creating PFSs * under the super-root, so the inode number is set to 1 in this case. */ int hammer2_inode_create(hammer2_inode_t *dip, struct vattr *vap, struct ucred *cred, const uint8_t *name, size_t name_len, hammer2_inode_t **nipp) { hammer2_mount_t *hmp = dip->hmp; hammer2_chain_t *chain; hammer2_chain_t *parent; hammer2_inode_t *nip; hammer2_key_t lhc; int error; uid_t xuid; 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. */ parent = &dip->chain; hammer2_chain_lock(hmp, parent, HAMMER2_RESOLVE_ALWAYS); error = 0; while (error == 0) { chain = hammer2_chain_lookup(hmp, &parent, lhc, lhc, 0); if (chain == NULL) break; if ((lhc & HAMMER2_DIRHASH_VISIBLE) == 0) error = ENOSPC; if ((lhc & HAMMER2_DIRHASH_LOMASK) == HAMMER2_DIRHASH_LOMASK) error = ENOSPC; hammer2_chain_unlock(hmp, chain); chain = NULL; ++lhc; } if (error == 0) { chain = hammer2_chain_create(hmp, parent, NULL, lhc, 0, HAMMER2_BREF_TYPE_INODE, HAMMER2_INODE_BYTES); if (chain == NULL) error = EIO; } hammer2_chain_unlock(hmp, parent); /* * Handle the error case */ if (error) { KKASSERT(chain == NULL); *nipp = NULL; return (error); } /* * Set up the new inode */ nip = chain->u.ip; *nipp = nip; hammer2_voldata_lock(hmp); if (vap) { nip->ip_data.type = hammer2_get_obj_type(vap->va_type); nip->ip_data.inum = hmp->voldata.alloc_tid++; /* XXX modify/lock */ } else { nip->ip_data.type = HAMMER2_OBJTYPE_DIRECTORY; nip->ip_data.inum = 1; } hammer2_voldata_unlock(hmp); nip->ip_data.version = HAMMER2_INODE_VERSION_ONE; hammer2_update_time(&nip->ip_data.ctime); nip->ip_data.mtime = nip->ip_data.ctime; if (vap) nip->ip_data.mode = vap->va_mode; nip->ip_data.nlinks = 1; if (vap) { if (dip) { xuid = hammer2_to_unix_xid(&dip->ip_data.uid); xuid = vop_helper_create_uid(dip->pmp->mp, dip->ip_data.mode, xuid, cred, &vap->va_mode); } else { xuid = 0; } /* XXX if (vap->va_vaflags & VA_UID_UUID_VALID) nip->ip_data.uid = vap->va_uid_uuid; else if (vap->va_uid != (uid_t)VNOVAL) hammer2_guid_to_uuid(&nip->ip_data.uid, vap->va_uid); else */ hammer2_guid_to_uuid(&nip->ip_data.uid, xuid); /* XXX if (vap->va_vaflags & VA_GID_UUID_VALID) nip->ip_data.gid = vap->va_gid_uuid; else if (vap->va_gid != (gid_t)VNOVAL) hammer2_guid_to_uuid(&nip->ip_data.gid, vap->va_gid); else */ if (dip) nip->ip_data.gid = dip->ip_data.gid; } /* * 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 (nip->ip_data.type == HAMMER2_OBJTYPE_REGFILE || nip->ip_data.type == HAMMER2_OBJTYPE_SOFTLINK) { nip->ip_data.op_flags |= HAMMER2_OPFLAG_DIRECTDATA; } KKASSERT(name_len < HAMMER2_INODE_MAXNAME); bcopy(name, nip->ip_data.filename, name_len); nip->ip_data.name_key = lhc; nip->ip_data.name_len = name_len; return (0); }