void fsw_dnode_release(struct fsw_dnode *dno) { struct fsw_volume *vol = dno->vol; struct fsw_dnode *parent_dno; dno->refcount--; if (dno->refcount == 0) { parent_dno = dno->parent; // de-register from volume's list if (dno->next) dno->next->prev = dno->prev; if (dno->prev) dno->prev->next = dno->next; if (vol->dnode_head == dno) vol->dnode_head = dno->next; // run fstype-specific cleanup vol->fstype_table->dnode_free(vol, dno); fsw_strfree(&dno->name); fsw_free(dno); // release our pointer to the parent, possibly deallocating it, too if (parent_dno) fsw_dnode_release(parent_dno); } }
void fsw_unmount(struct fsw_volume *vol) { if (vol->root) fsw_dnode_release(vol->root); /// @todo check that no other dnodes are still around vol->fstype_table->volume_free(vol); fsw_blockcache_free(vol); fsw_strfree(&vol->label); fsw_free(vol); }
fsw_status_t fsw_dnode_resolve(struct fsw_dnode *dno, struct fsw_dnode **target_dno_out) { fsw_status_t status; struct fsw_string target_name; struct fsw_dnode *target_dno; /* Linux kernel max link count is 40 */ int link_count = 40; fsw_dnode_retain(dno); while (--link_count > 0) { // get full information status = fsw_dnode_fill(dno); if (status) goto errorexit; if (dno->type != FSW_DNODE_TYPE_SYMLINK) { // found a non-symlink target, return it *target_dno_out = dno; return FSW_SUCCESS; } if (dno->parent == NULL) { // safety measure, cannot happen in theory status = FSW_NOT_FOUND; goto errorexit; } // read the link's target status = fsw_dnode_readlink(dno, &target_name); if (status) goto errorexit; // resolve it status = fsw_dnode_lookup_path(dno->parent, &target_name, '/', &target_dno); fsw_strfree(&target_name); if (status) goto errorexit; // target_dno becomes the new dno fsw_dnode_release(dno); dno = target_dno; // is already retained } if(link_count == 0) status = FSW_NOT_FOUND; errorexit: fsw_dnode_release(dno); return status; }