/* read/write (flag) to 'buf' 'n' bytes from position 'pos' of the file 'ino' */ int copy_file(char *buf, unsigned int n, unsigned int pos, struct inode_s *ino, int flag) { unsigned int size, off; block_t blocknr; struct buf_s *block; while (n > 0) { if ( (blocknr = read_map(ino, pos, flag)) == NO_BLOCK) return ERROR; block = get_block(blocknr); off = pos % BLOCK_SIZE; size = MIN(n, BLOCK_SIZE - off); if (flag == FS_WRITE) { mymemcpy(block->b_buffer + off, buf, size); block->b_dirty = 1; } else { mymemcpy(buf, block->b_buffer + off, size); } n -= size; pos += size; buf += size; release_block(block); } return pos; }
//******** rmdir ******************** int8_t cnrmdir(const char* name) { char parent_name[512]; char entry_name[256]; dir_entry* entry; inode dir_inode; memset(&dir_inode, 0, sizeof(inode)); strcpy(parent_name, name); strcat(parent_name, "/.."); dir_ptr* parent = cnopendir(parent_name); check(parent != NULL, "Cannot open parent directory"); //Copy the entire directory minus the entry dir_ptr* new_parent = calloc(1,sizeof(dir_ptr)); new_parent->data = calloc(parent->inode_st.blocks, sizeof(block)); dir_entry* new_dir_entry = (dir_entry*)new_parent->data; new_parent->inode_st = parent->inode_st; new_parent->inode_id = parent->inode_id; new_parent->inode_st.size = 0; new_parent->index = 0; while((entry = cnreaddir(parent))) { memcpy(entry_name, entry->name, entry->name_len); entry_name[entry->name_len] = 0; if(strcmp(entry_name, name) == 0) //If this is the directory we want { inode_read(entry->inode, &dir_inode); check(dir_inode.size == 24, "Directory is not empty"); release_block(dir_inode.data0[0]); //Release target directory block release_inode(entry->inode); //Release target inode continue; } new_dir_entry->entry_len = entry->entry_len; new_dir_entry->name_len = entry->name_len; new_dir_entry->file_type = entry->file_type; new_dir_entry->inode = entry->inode; memcpy(new_dir_entry->name, entry->name, entry->name_len); new_parent->inode_st.size += entry->entry_len; new_parent->index += entry->entry_len; new_dir_entry = (dir_entry*)((uint8_t*)new_parent->data+new_parent->index); } inode_write(new_parent->inode_id, &new_parent->inode_st); llwrite(&new_parent->inode_st, new_parent->data); free(new_parent->data); free(new_parent); cnclosedir(parent); return 0; error: if(new_parent != NULL && new_parent->data != NULL) free(new_parent->data); if(new_parent != NULL) free(new_parent); if(parent != NULL) cnclosedir(parent); return -1; }
block_t *DeRefLink(block_t *volatile *link) { for(;;) { block_t *q = *link; if(q == NULL) return q; __sync_fetch_and_add(&(q->refcount), 2); if(q == *link) return q; release_block(q); } }
QUEUE_ELEMTY *dequeue(local_block_t *l) { int tail = l->threadTail; block_t *block = l->threadTailBlock; for(;;) { if(tail==BLOCK_SIZE) { block_t *oldBlock = block; block->tail = tail; block=DeRefLink(&block->next); if(block == NULL) return NULL; else { if(!oldBlock->deleted) { while(globalTailBlock != oldBlock && !oldBlock->deleted) { block_t *tailBlock= DeRefLink(&globalTailBlock); if(tailBlock->next != oldBlock) continue; if(__sync_bool_compare_and_swap(&globalTailBlock,tailBlock,oldBlock)) release_block(tailBlock); } if(__sync_bool_compare_and_swap(&oldBlock->deleted,0,1)) { if(__sync_bool_compare_and_swap(&globalTailBlock,oldBlock,block)) release_block(oldBlock); } } if(block->deleted) block=DeRefLink(&globalTailBlock); } l->threadTailBlock = block; tail = block->tail; } else { void *data = block->nodes[tail]; if(data== (void *) NULL2) tail++; else if(data==NULL && __sync_bool_compare_and_swap(&block->nodes[tail],NULL,NULL)) { l->threadTail = tail; return NULL; } else if(__sync_bool_compare_and_swap(&block->nodes[tail],data,NULL2)) { l->threadTail = tail+1; return data; } } } }
void release_block(block_t *node) { __sync_fetch_and_add(&(node->refcount),-2); if(__sync_bool_compare_and_swap(&node->refcount,0,1)) { if(node->next) release_block(node->next); block_t *q; do { q = freeList; node->next = q; } while(!__sync_bool_compare_and_swap(&freeList,q,node)); } }
void seg_pool::reg_empty_block(pool_block* p) { // keep only one largest empty block. // [TODO] use simpler structure to record empty block. PROTON_POOL_THROW_IF(!p->empty(), "try to reg a not empty block into empty_blocks:"<<p); if(_empty_blocks.empty()){ p->insert_after(&_empty_blocks); return; } else{ pool_block* ba=get_block(_empty_blocks.next()); if(ba->block_size() < p->block_size()){ release_block(ba); p->insert_after(&_empty_blocks); } else{ release_block(p); } } }
status_t csi_release_block(struct csi *csi) { status_t err; if (_validate_cs_(csi->vol, csi->cluster, csi->sector) != 0) return EINVAL; err = release_block(csi->vol->fd, _csi_to_block_(csi)); ASSERT(err == B_OK); return err; }
block_t *new_node() { for(;;) { block_t *p = freeList; if(!p) p = calloc(1, sizeof(block_t)); __sync_fetch_and_add(&(p->refcount), 2); if(__sync_bool_compare_and_swap(&freeList,p,p->next)) { __sync_fetch_and_add(&(p->refcount),-1); return p; } release_block(p); } }
// NOTE : dev unused error_t init_super_block(dev_t dev) { error_t ret = 0; zone_t pos = get_super_block_begin(dev); BlockBuffer *buffer = get_block(dev, pos); memcpy(&super_blk[0], buffer->bf_data, sizeof(super_blk)); if (super_blk[0].sb_magic != MINIX_V2 ) { printk("only minifs v2 is supported\n"); ret = -1; } release_block(buffer); return ret; }
/****************************************** * release a block of memory by removing it from the data chain * called by user * NB: p0 is pointer to the data, need to find pointer to MemHdr first */ void release_mem( void *const p0 ) { register tMemHdr *const p = ((tMemHdr*)( (uint32)p0 - offsetof(tMemHdr, data) )); /* <<< size_t */ assert( head_mem != NULL ); /* there must be a cache !! */ assert( p->magic == MAGIC ); /* must be a valid block */ assert( ISDATA(p) ); /* must be a data block */ assert( head_data != NULL ); /* data chain can't be empty */ assert( tail_data != NULL ); assert( p->next_list != NULL || p == tail_data ); assert( p->prev_list != NULL || p == head_data ); assert( check_block(p) ); release_block( p ); } /* release_mem() */
void JNIHandleBlock::release_block(JNIHandleBlock* block, Thread* thread) { assert(thread == NULL || thread == Thread::current(), "sanity check"); JNIHandleBlock* pop_frame_link = block->pop_frame_link(); // Put returned block at the beginning of the thread-local free list. // Note that if thread == NULL, we use it as an implicit argument that // we _don't_ want the block to be kept on the free_handle_block. // See for instance JavaThread::exit(). if (thread != NULL ) { if (ZapJNIHandleArea) block->zap(); JNIHandleBlock* freelist = thread->free_handle_block(); block->_pop_frame_link = NULL; thread->set_free_handle_block(block); // Add original freelist to end of chain if ( freelist != NULL ) { while ( block->_next != NULL ) block = block->_next; block->_next = freelist; } block = NULL; } if (block != NULL) { // Return blocks to free list // locking with safepoint checking introduces a potential deadlock: // - we would hold JNIHandleBlockFreeList_lock and then Threads_lock // - another would hold Threads_lock (jni_AttachCurrentThread) and then // JNIHandleBlockFreeList_lock (JNIHandleBlock::allocate_block) MutexLockerEx ml(JNIHandleBlockFreeList_lock, Mutex::_no_safepoint_check_flag); while (block != NULL) { if (ZapJNIHandleArea) block->zap(); JNIHandleBlock* next = block->_next; block->_next = _block_free_list; _block_free_list = block; block = next; } } if (pop_frame_link != NULL) { // As a sanity check we release blocks pointed to by the pop_frame_link. // This should never happen (only if PopLocalFrame is not called the // correct number of times). release_block(pop_frame_link, thread); } }
void enqueue(local_block_t *l, QUEUE_ELEMTY *item) { int head = l->threadHead; block_t *block = l->threadHeadBlock; for(;;) { if(head==BLOCK_SIZE) { block_t *oldBlock = block; block->head = head; block = DeRefLink(&block->next); if(block == NULL) { block = (block_t *) new_block(); while(globalHeadBlock != oldBlock && oldBlock->next==NULL) { block_t *headBlock = DeRefLink(&globalHeadBlock); if(headBlock->next != oldBlock) break; if(__sync_bool_compare_and_swap(&globalHeadBlock,headBlock,oldBlock)) break; } if(__sync_bool_compare_and_swap(&oldBlock->next,NULL,block)) __sync_bool_compare_and_swap(&globalHeadBlock,oldBlock,block); else { release_block(block); block = DeRefLink(&oldBlock->next); } } else if(block->head==BLOCK_SIZE && block->next!=NULL) block = DeRefLink(&globalHeadBlock); l->threadHeadBlock = block; head = block->head; } else if(block->nodes[head]==NULL) { if(__sync_bool_compare_and_swap(&block->nodes[head],NULL,item)) { l->threadHead = head+1; return; } } else head++; } }
/********************************************* * create new block of requested size by removing oldest memory blocks * block contents are not initialised * size is rounded up to exact nr longs * base for removed blocks is set to NULL * *pbase := adr of block, * or null if cache is unable to supply enough memory * return null */ void find_mem( uint32 rq_size, void **const base ) { register tMemHdr *tr; register tMemHdr *t0; register tMemHdr *t1; assert( head_mem != NULL ); /* there must be a cache !! */ assert( base != NULL ); assert( rq_size <= ((rq_size+3)&~3) ); assert( rq_size+4 > ((rq_size+3)&~3) ); rq_size = (rq_size+3)&~3; if(( rq_size > total_size) ) { /* request fails - it is too large for cache */ dprintf(( "requested mem (%ld) larger than cache size (%ld)\n", rq_size, total_size )); *base = NULL; return; } /* if */ /** loop to remove old data until there is enough free space for current request **/ dprintf(( "rq_size is %ld\n", (long)rq_size )); assert( head_free != NULL || total_free == 0 ); /* note the special case when total free == 0 (so head_free == NULL) ** and rq_size is 0. */ while( rq_size > total_free || total_free == 0 ) { dprintf(("need to remove lru data block(%ld), size (%ld)\n", (long)head_data->data[0], (long)head_data->size )); assert( head_data != NULL || rq_size <= total_free ); assert( total_free + total_used + (nr_blocks-1)*sizeof(tMemHdr) == total_size ); assert( head_data->prev_list == NULL ); release_block( head_data ); /* remove lru data block */ assert( head_data != NULL || rq_size <= total_free ); assert( head_data != NULL || total_used == 0 ); assert( head_data == NULL || head_data->prev_list == NULL); } /* while */ assert( total_free >= rq_size ); assert( head_free != NULL ); /********************************************************** * there is now enough space in the cache to fulfil the request * but it may need to be gathered together into one block * move all data blocks down to the start of the cache * this leaves one free block at the end of the cache **********************************************************/ if( head_free->size < rq_size ) { register uint32 *free_p; /** free space pointer **/ /* the memory is fragmented, so move all data down memory ** to concentrate the free mem into one block at the end ** note: fragmented ==> at least one data block & 2 free blocks */ #ifdef TEST conc++; dprintf(( "concentrating data...(this is the %ldth time)\n", conc )); #endif assert( head_data != NULL ); t1 = head_mem; while( ISDATA(t1) ) { assert( check_block(t1) ); assert( t1->next_mem != NULL ); /* there are at least two free blocks following */ t1 = t1->next_mem; } /* while */ assert( ISFREE(t1) ); free_p = (uint32*)t1; /* the first free area */ t0 = t1->prev_mem; /* the last data block so far, or NULL */ assert( t0 == NULL || check_block(t0) ); assert( t0 == NULL || ISDATA(t0) ); assert( t0 == NULL || (uint32*)free_p == (uint32*)(t0->next_mem) ); /** loop to copy data blocks down ** t1 scans thru mem blocks, ** t0 follows one behind, it is the latest concentrated block **/ do { assert( t1->magic == MAGIC ); /* t1->prev?? may have been overwritten */ if( ISDATA(t1) ) { register int32 i = t1->size + sizeof(tMemHdr); /* nr bytes to move */ register uint32 *s1 = (uint32*)t1; /* src address */ /**** ** move data block at t1 down to free_p, ** adjust t0 = new conc'd data block, adjust t1 *****/ assert( t0 == NULL || (uint32*)free_p == (uint32*)(t0->next_mem) ); tr = (tMemHdr*) free_p; /* relocate block pointer */ assert( tr != NULL ); assert( tr < t1 ); /* there is a gap between end of t0 & start of t1 */ t1 = t1->next_mem; /* data at t1 will be overwritten if data size > gap too free_p */ assert( (i&3) == 0 ); /* data & header both exact nr longs */ i >>= 2; /* nr longs */ while( --i >= 0 ) { /* copy header & data of block */ *free_p++ = *s1++; } /* if */ /* note: free_p now points to new free area, at end of tr */ assert( (uint32)tr->data + tr->size == (uint32)free_p ); *tr->pbase = tr->data; tr->next_mem = (tMemHdr*)free_p; /* adjust links */ tr->prev_mem = t0; assert( (t0 == NULL && tr == head_mem) || t0->next_mem == tr ); if( tr->next_list != NULL ) { tr->next_list->prev_list = tr; } else { tail_data = tr; } /* if */ if( tr->prev_list != NULL ) { tr->prev_list->next_list = tr; } else { head_data = tr; } /* if */ t0 = tr; assert( ISDATA(t0) ); assert( check_block(t0) ); assert( t0->prev_mem == NULL || t0->prev_mem->next_mem == t0); } else { nr_blocks--; /* removed a free block */ total_free += sizeof(tMemHdr); t1 = t1->next_mem; } /* if */ } while( t1 != NULL ); assert( t0 != NULL ); /** now create one free block at the end of the cache */ t1 = head_free = t0->next_mem; assert( head_free == (tMemHdr*)free_p ); t1->next_mem = t1->next_list = t1->prev_list = NULL; t1->prev_mem = t0; total_free -= sizeof(tMemHdr); assert( total_free == (uint32)head_mem + total_size - (uint32)t1); t1->size = total_free; t1->pbase = NULL; #ifndef NDEBUG t1->magic = MAGIC; t1->data[0] = -2; #endif nr_blocks++; assert( total_free + total_used + (nr_blocks-1)*sizeof(tMemHdr) == total_size ); } /* if */
static void ts_mem_check(void * arg) { t_mchecker mc = arg; x_thread thread = mc->thread; x_size size; x_size old_size; x_size blocks_in_use = 0; t_Block Initial; t_block initial = &Initial; t_block block; x_int command; x_size discards = 0; x_size frees = 0; x_size allocs = 0; x_size reallocs_g = 0; x_size reallocs_s = 0; /* ** Initialize our own list. */ initial->size = 1024 * 1024 * 30; x_list_init(initial); /* ** ... and check dynamic allocation and deallocation forever ... */ while (1) { /* ** Select the operation: 0 and 1 = allocation, 2 = reallocation, 3 = change owner and 4 = free or discard */ command = x_random() % 5; block = NULL; if (force_next_is_release || global_force_release) { command = 4; force_next_is_release = 0; } else if (force_next_is_allocation) { command = 0; } /* ** If we have released all our blocks due to a global force release command and ** we have no blocks left, we sleep so that other threads can start dumping their ** blocks. */ if (global_force_release && blocks_in_use == 0) { x_thread_sleep(2); } /* ** Only do allocations when we have not all blocks in use. */ if ((command == 1 || command == 0) && (blocks_in_use < max_blocks_in_use)) { size = random_size(); block = allocate_block(mc, initial, size, x_random() & 0x00000001); allocs += 1; if (block == NULL) { force_next_is_release = 1; global_force_release = 1; oempa("No more memory for %d bytes. Global force releasing enabled, %d bytes in use.\n", size, global_in_use); continue; } blocks_in_use += 1; allocations += 1; if (force_next_is_allocation) { force_next_is_allocation = 0; } } else if (command == 2) { block = initial->next; if (block != initial) { size = random_size(); old_size = block->size; block = reallocate_block(mc, initial, block, size); if (old_size < size) { reallocs_g += 1; } else { reallocs_s += 1; } allocs += 1; if (block == NULL) { force_next_is_release = 1; global_force_release = 1; continue; } reallocations += 1; } } else if (command == 3) { block = initial->next; } else { block = initial->next; if (block != initial) { if (x_random() % 5 == 0) { release_block(mc, block, true, 1); discards += 1; } else { release_block(mc, block, true, 0); frees += 1; } blocks_in_use -= 1; releases += 1; } } if (allocs > 0 && allocs % 4000 == 0) { oempa("Thread %p: A %d Rg %d Rs %d D %d F %d\n", thread, allocs, reallocs_g, reallocs_s, discards, frees); force_next_is_allocation = 1; } if (allocs > 0 && allocs % 2000 == 0) { x_thread_sleep((x_random() % 10) + 10); } } }
void seg_pool::purge_circle(list_header* lh) { while(!lh->empty()){ release_block(get_block(lh->next())); } }