static errval_t do_single_unmap(struct pmap_arm *pmap, genvaddr_t vaddr, size_t pte_count, bool delete_cap) { errval_t err; struct vnode *pt = find_ptable(pmap, vaddr); if (pt) { // analog to do_single_map we use 10 bits for tracking pages in user space -SG struct vnode *page = find_vnode(pt, ARM_USER_L2_OFFSET(vaddr)); if (page && page->u.frame.pte_count == pte_count) { err = vnode_unmap(pt->u.vnode.cap, page->u.frame.cap, page->entry, page->u.frame.pte_count); if (err_is_fail(err)) { DEBUG_ERR(err, "vnode_unmap"); return err_push(err, LIB_ERR_VNODE_UNMAP); } // Free up the resources if (delete_cap) { err = cap_destroy(page->u.frame.cap); if (err_is_fail(err)) { return err_push(err, LIB_ERR_PMAP_DO_SINGLE_UNMAP); } } remove_vnode(pt, page); slab_free(&pmap->slab, page); } else { return LIB_ERR_PMAP_FIND_VNODE; } } return SYS_ERR_OK; }
static status_t nfs4_remove_dir(fs_volume* volume, fs_vnode* parent, const char* name) { VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(parent->private_node); TRACE("volume = %p, parent = %" B_PRIi64 ", name = %s", volume, vti->ID(), name); VnodeToInodeLocker _(vti); Inode* inode = vti->Get(); if (inode == NULL) return B_ENTRY_NOT_FOUND; ino_t id; status_t result = inode->Remove(name, NF4DIR, &id); if (result != B_OK) return result; result = acquire_vnode(volume, id); if (result == B_OK) { result = get_vnode(volume, id, reinterpret_cast<void**>(&vti)); ASSERT(result == B_OK); if (vti->Unlink(inode->fInfo.fNames, name)) remove_vnode(volume, id); put_vnode(volume, id); put_vnode(volume, id); } return B_OK; }
// RemoveVNode status_t Volume::RemoveVNode(Node *node) { if (fMounted) return remove_vnode(GetID(), node->GetID()); status_t error = NodeRemoved(node); if (error == B_OK) delete node; return error; }
status_t Inode::Unlink(Transaction& transaction) { uint32 numLinks = fNode.NumLinks(); TRACE("Inode::Unlink(): Current links: %lu\n", numLinks); if (numLinks == 0) return B_BAD_VALUE; if ((IsDirectory() && numLinks == 2) || (numLinks == 1)) { fUnlinked = true; TRACE("Inode::Unlink(): Putting inode in orphan list\n"); ino_t firstOrphanID; status_t status = fVolume->SaveOrphan(transaction, fID, firstOrphanID); if (status != B_OK) return status; if (firstOrphanID != 0) { Vnode firstOrphan(fVolume, firstOrphanID); Inode* nextOrphan; status = firstOrphan.Get(&nextOrphan); if (status != B_OK) return status; fNode.SetNextOrphan(nextOrphan->ID()); } else { // Next orphan link is stored in deletion time fNode.deletion_time = 0; } fNode.num_links = 0; status = remove_vnode(fVolume->FSVolume(), fID); if (status != B_OK) return status; } else fNode.SetNumLinks(--numLinks); return WriteBack(transaction); }
static status_t nfs4_rename(fs_volume* volume, fs_vnode* fromDir, const char* fromName, fs_vnode* toDir, const char* toName) { VnodeToInode* fromVti = reinterpret_cast<VnodeToInode*>(fromDir->private_node); VnodeToInode* toVti = reinterpret_cast<VnodeToInode*>(toDir->private_node); TRACE("volume = %p, fromDir = %" B_PRIi64 ", toDir = %" B_PRIi64 "," \ " fromName = %s, toName = %s", volume, fromVti->ID(), toVti->ID(), \ fromName, toName); VnodeToInodeLocker _from(fromVti); Inode* fromInode = fromVti->Get(); if (fromInode == NULL) return B_ENTRY_NOT_FOUND; VnodeToInodeLocker _to(toVti); Inode* toInode = toVti->Get(); if (toInode == NULL) return B_ENTRY_NOT_FOUND; ino_t id; ino_t oldID; status_t result = Inode::Rename(fromInode, toInode, fromName, toName, false, &id, &oldID); if (result != B_OK) return result; VnodeToInode* vti; if (oldID != 0) { // we have overriden an inode result = acquire_vnode(volume, oldID); if (result == B_OK) { result = get_vnode(volume, oldID, reinterpret_cast<void**>(&vti)); ASSERT(result == B_OK); if (vti->Unlink(toInode->fInfo.fNames, toName)) remove_vnode(volume, oldID); put_vnode(volume, oldID); put_vnode(volume, oldID); } } result = get_vnode(volume, id, reinterpret_cast<void**>(&vti)); if (result == B_OK) { Inode* child = vti->Get(); if (child == NULL) { put_vnode(volume, id); return B_ENTRY_NOT_FOUND; } unremove_vnode(volume, id); child->fInfo.fNames->RemoveName(fromInode->fInfo.fNames, fromName); child->fInfo.fNames->AddName(toInode->fInfo.fNames, toName); put_vnode(volume, id); } return B_OK; }
void remove_empty_vnodes(struct pmap_x86 *pmap, struct vnode *root, uint32_t entry, size_t len) { errval_t err; uint32_t end_entry = entry + len; for (struct vnode *n = root->u.vnode.children; n; n = n->next) { if (n->entry >= entry && n->entry < end_entry) { // sanity check and skip leaf entries if (!n->is_vnode) { continue; } // here we know that all vnodes we're interested in are // page tables assert(n->is_vnode); if (n->u.vnode.children) { remove_empty_vnodes(pmap, n, 0, PTABLE_SIZE); } // unmap err = vnode_unmap(root->u.vnode.cap, n->mapping); if (err_is_fail(err)) { debug_printf("remove_empty_vnodes: vnode_unmap: %s\n", err_getstring(err)); } // delete mapping cap first: underlying cap needs to exist for // this to work properly! err = cap_delete(n->mapping); if (err_is_fail(err)) { debug_printf("remove_empty_vnodes: cap_delete (mapping): %s\n", err_getstring(err)); } err = pmap->p.slot_alloc->free(pmap->p.slot_alloc, n->mapping); if (err_is_fail(err)) { debug_printf("remove_empty_vnodes: slot_free (mapping): %s\n", err_getstring(err)); } // delete capability err = cap_delete(n->u.vnode.cap); if (err_is_fail(err)) { debug_printf("remove_empty_vnodes: cap_delete (vnode): %s\n", err_getstring(err)); } if (!capcmp(n->u.vnode.cap, n->u.vnode.invokable)) { // invokable is always allocated in our cspace err = cap_destroy(n->u.vnode.invokable); if (err_is_fail(err)) { debug_printf("remove_empty_vnodes: cap_delete (vnode.invokable): %s\n", err_getstring(err)); } } err = pmap->p.slot_alloc->free(pmap->p.slot_alloc, n->u.vnode.cap); if (err_is_fail(err)) { debug_printf("remove_empty_vnodes: slot_free (vnode): %s\n", err_getstring(err)); } // remove vnode from list remove_vnode(root, n); slab_free(&pmap->slab, n); } } }
// RemoveVNode status_t Volume::RemoveVNode(vnode_id vnid) { return remove_vnode(fVolumeManager->GetID(), vnid); }
static int rootfs_rename(void *_ns, void *_olddir, const char *oldname, void *_newdir, const char *newname) { nspace *ns; vnode *olddir, *newdir; int err; vnode *vn, *nvn, *pvn, *avn; char *p; ns = (nspace *) _ns; olddir = (vnode *) _olddir; newdir = (vnode *) _newdir; LOCK(ns->lock); if (!MY_S_ISDIR(olddir->mode) || !MY_S_ISDIR(newdir->mode)) { err = ENOTDIR; goto error1; } /* find (olddir, oldname) */ if (!strcmp(oldname, ".") || !strcmp(oldname, "..")) { err = EPERM; goto error1; } vn = olddir->head; while (vn) { if (!strcmp(vn->name, oldname)) break; vn = vn->next; } if (!vn) { err = ENOENT; goto error1; } /* look for (newdir, newname) */ if (!strcmp(newname, ".") || !strcmp(newname, "..")) { err = EPERM; goto error1; } nvn = newdir->head; while (nvn) { if (!strcmp(nvn->name, newname)) break; nvn = nvn->next; } /* don't do anything if old and new are the same */ if (vn == nvn) goto exit; /* make sure new is not a subdirectory of old */ avn = newdir; while (avn != ns->root) { avn = avn->parent; if (avn == olddir) { err = EINVAL; goto error1; } } if (strlen(newname) > strlen(vn->name)) { p = (char *) realloc(vn->name, strlen(newname)+1); if (!p) { err = ENOMEM; goto error1; } } else p = vn->name; /* if (newdir, newname) exists, remove it from the name space */ if (nvn) { /* make sure it is not the root and it is not empty */ if (nvn == nvn->ns->root) { err = EBUSY; goto error1; } if (MY_S_ISDIR(nvn->mode) && nvn->head) { err = ENOTEMPTY; goto error1; } err = get_vnode(ns->nsid, nvn->vnid, (void *)&nvn); if (err) goto error1; err = remove_vnode(ns->nsid, nvn->vnid); if (err) goto error1; if (nvn->prev) nvn->prev->next = nvn->next; else nvn->parent->head = nvn->next; if (nvn->next) nvn->next->prev = nvn->prev; nvn->prev = nvn->next = NULL; put_vnode(ns->nsid, nvn->vnid); } if (vn->prev) vn->prev->next = vn->next; else vn->parent->head = vn->next; if (vn->next) vn->next->prev = vn->prev; pvn = NULL; nvn = newdir->head; while (nvn && (strcmp(newname, nvn->name) > 0)) { pvn = nvn; nvn = nvn->next; } vn->next = nvn; if (nvn) nvn->prev = vn; vn->prev = pvn; if (pvn) pvn->next = vn; else newdir->head = vn; vn->parent = newdir; newdir->mtime = olddir->mtime = time(NULL); strcpy(p, newname); vn->name = p; exit: UNLOCK(ns->lock); return 0; error1: UNLOCK(ns->lock); return err; }
static int do_unlink(nspace *ns, vnode *dir, const char *name, bool isdir) { int err; vnode *vn; LOCK(ns->lock); if (!MY_S_ISDIR(dir->mode)) { err = ENOTDIR; goto error1; } /* can't delete '..' and '.' */ if (!strcmp(name, "..") || !strcmp(name, ".")) { err = EINVAL; goto error1; } /* lookup the name in the directory */ vn = dir->head; while (vn) { if (!strcmp(vn->name, name)) break; vn = vn->next; } /* if it was not found, report an error. */ if (!vn) { err = ENOENT; goto error1; } /* ensure it is of the appropriate type. */ if (isdir && !(vn->mode & MY_S_IFDIR)) { err = ENOTDIR; goto error1; } if (!isdir && (vn->mode & MY_S_IFDIR)) { err = EISDIR; goto error1; } /* make sure it is not the root */ if (vn == vn->ns->root) { err = EBUSY; goto error1; } /* if it is a directory, make sure it is empty */ if (MY_S_ISDIR(vn->mode) && vn->head) { err = ENOTEMPTY; goto error1; } err = get_vnode(ns->nsid, vn->vnid, (void *)&vn); if (err) goto error1; err = remove_vnode(ns->nsid, vn->vnid); if (err) goto error1; if (vn->prev) vn->prev->next = vn->next; else vn->parent->head = vn->next; if (vn->next) vn->next->prev = vn->prev; vn->prev = vn->next = NULL; vn->removed = TRUE; dir->mtime = time(NULL); put_vnode(ns->nsid, vn->vnid); UNLOCK(ns->lock); return 0; error1: UNLOCK(ns->lock); return err; }