/** * Finds first free physical page and marks it reserved. * * @return Address of first free physical page, zero if no free pages * are available. */ physaddr_t physmem_allocblock(void) { interrupt_status_t intr_status; int i; intr_status = _interrupt_disable(); spinlock_acquire(&physmem_slock); if (physmem_num_free_pages > 0) { i = bitmap_findnset(physmem_free_pages,physmem_num_pages); physmem_num_free_pages--; /* There should have been a free page. Check that the physmem internal variables are in synch. */ KERNEL_ASSERT(i >= 0 && physmem_num_free_pages >= 0); } else { i = 0; } spinlock_release(&physmem_slock); _interrupt_set_state(intr_status); return i*PAGE_SIZE; }
/** * Creates file of given size. Implements fs.create(). Checks that * file name doesn't allready exist in directory block.Allocates * enough blocks from the allocation block for the file (1 for inode * and then enough for the file of given size). Reserved blocks are zeroed. * * @param fs Pointer to fs data structure of the device. * @param filename File name of the file to be created * @param size Size of the file to be created * * @return If file allready exists or not enough space return VFS_ERROR, * otherwise return VFS_OK. */ int tfs_create(fs_t *fs, char *filename, int size) { tfs_t *tfs = (tfs_t *)fs->internal; gbd_request_t req; uint32_t i; uint32_t numblocks = (size + TFS_BLOCK_SIZE - 1)/TFS_BLOCK_SIZE; int index = -1; int r; semaphore_P(tfs->lock); if(numblocks > (TFS_BLOCK_SIZE / 4 - 1)) { semaphore_V(tfs->lock); return VFS_ERROR; } /* Read directory block. Check that file doesn't allready exist and there is space left for the file in directory block. */ req.block = TFS_DIRECTORY_BLOCK; req.buf = ADDR_KERNEL_TO_PHYS((uint32_t)tfs->buffer_md); req.sem = NULL; r = tfs->disk->read_block(tfs->disk, &req); if(r == 0) { /* An error occured. */ semaphore_V(tfs->lock); return VFS_ERROR; } for(i=0;i<TFS_MAX_FILES;i++) { if(stringcmp(tfs->buffer_md[i].name, filename) == 0) { semaphore_V(tfs->lock); return VFS_ERROR; } if(tfs->buffer_md[i].inode == 0) { /* found free slot from directory */ index = i; } } if(index == -1) { /* there was no space in directory, because index is not set */ semaphore_V(tfs->lock); return VFS_ERROR; } stringcopy(tfs->buffer_md[index].name,filename, TFS_FILENAME_MAX); /* Read allocation block and... */ req.block = TFS_ALLOCATION_BLOCK; req.buf = ADDR_KERNEL_TO_PHYS((uint32_t)tfs->buffer_bat); req.sem = NULL; r = tfs->disk->read_block(tfs->disk, &req); if(r==0) { /* An error occured. */ semaphore_V(tfs->lock); return VFS_ERROR; } /* ...find space for inode... */ tfs->buffer_md[index].inode = bitmap_findnset(tfs->buffer_bat, tfs->totalblocks); if((int)tfs->buffer_md[index].inode == -1) { semaphore_V(tfs->lock); return VFS_ERROR; } /* ...and the rest of the blocks. Mark found block numbers in inode.*/ tfs->buffer_inode->filesize = size; for(i=0; i<numblocks; i++) { tfs->buffer_inode->block[i] = bitmap_findnset(tfs->buffer_bat, tfs->totalblocks); if((int)tfs->buffer_inode->block[i] == -1) { /* Disk full. No free block found. */ semaphore_V(tfs->lock); return VFS_ERROR; } } /* Mark rest of the blocks in inode as unused. */ while(i < (TFS_BLOCK_SIZE / 4 - 1)) tfs->buffer_inode->block[i++] = 0; req.block = TFS_ALLOCATION_BLOCK; req.buf = ADDR_KERNEL_TO_PHYS((uint32_t)tfs->buffer_bat); req.sem = NULL; r = tfs->disk->write_block(tfs->disk, &req); if(r==0) { /* An error occured. */ semaphore_V(tfs->lock); return VFS_ERROR; } req.block = TFS_DIRECTORY_BLOCK; req.buf = ADDR_KERNEL_TO_PHYS((uint32_t)tfs->buffer_md); req.sem = NULL; r = tfs->disk->write_block(tfs->disk, &req); if(r==0) { /* An error occured. */ semaphore_V(tfs->lock); return VFS_ERROR; } req.block = tfs->buffer_md[index].inode; req.buf = ADDR_KERNEL_TO_PHYS((uint32_t)tfs->buffer_inode); req.sem = NULL; r = tfs->disk->write_block(tfs->disk, &req); if(r==0) { /* An error occured. */ semaphore_V(tfs->lock); return VFS_ERROR; } /* Write zeros to the reserved blocks. Buffer for allocation block is no longer needed, so lets use it as zero buffer. */ memoryset(tfs->buffer_bat, 0, TFS_BLOCK_SIZE); for(i=0;i<numblocks;i++) { req.block = tfs->buffer_inode->block[i]; req.buf = ADDR_KERNEL_TO_PHYS((uint32_t)tfs->buffer_bat); req.sem = NULL; r = tfs->disk->write_block(tfs->disk, &req); if(r==0) { /* An error occured. */ semaphore_V(tfs->lock); return VFS_ERROR; } } semaphore_V(tfs->lock); return VFS_OK; }