Beispiel #1
0
/**
   Assumes ino is an opened inode and loads a block list cache for it.
   If !ino->first_block then this function does nothing but returns
   whefs_rc.OK, otherwise...

   For each block in the chain starting at ino->first_block,
   the block is loaded and appended to ino->blocks.list.

   On success ino->blocks.list contains ino->blocks.count
   whefs_block items representing ino's block chain. To add
   items to the list use whefs_inode_block_list_append().
   To remove them, change ino->blocks.count, empty out
   the now-unused entries, and update the on-disk blocks.

   ino->blocks.count should be 0 when this function is called. If not,
   it may emit a warning debug message but will return a success
   value.
*/
static int whefs_inode_block_list_load( whefs_fs * fs,
					whefs_inode * ino )
{
    if( ! whefs_inode_is_valid(fs,ino) ) return whefs_rc.ArgError;
    if( ! ino->first_block ) return whefs_rc.OK;
    if( ino->blocks.count )
    {
	WHEFS_DBG_WARN("this function shouldn't be called when ino->blocks.count is !0. inode=#%u",
		       ino->id);
	return whefs_rc.OK;
    }
    whefs_block bl = whefs_block_empty;
    int rc = whefs_block_read( fs, ino->first_block, &bl );
    if( whefs_rc.OK != rc ) return rc;
#if 0
    if( ! ino->blocks.list )
    {
	rc = whefs_inode_block_list_reserve( fs, ino, 5 /* arbitrarily chosen */ );
	if( whefs_rc.OK != rc ) return rc;
    }
#endif
    rc = whefs_inode_block_list_append( fs, ino, &bl );
    if( whefs_rc.OK != rc ) return rc;
    while( bl.next_block )
    {
	rc = whefs_block_read_next( fs, &bl, &bl );
	if( whefs_rc.OK != rc ) return rc;
        rc = whefs_inode_block_list_append( fs, ino, &bl );
	if( whefs_rc.OK != rc ) return rc;
    }
    //WHEFS_DBG("Loaded block chain of %u block(s) for inode #%u[%s].", ino->blocks.count, ino->id, ino->name );
    return whefs_rc.OK;
}
Beispiel #2
0
/**
   This function is the heart of the pseudofile i/o beast...

   It tries to map a logical file position to a data block
   associated with an inode.

   It starts with ino's first block and increments blocks until the
   block in which pos would land is found. If ino doesn't have enough
   blocks, the behaviour is defined by the expands parameter:

   If expands is true then it will add blocks to the inode's chain in
   order to reach the destination pos, if necessary. If expands is
   false and pos is not within the inode's current data size then the
   function fails.

   On success, tgt is populated with the block associated with the
   given position and inode, and ino *may* be updated (if it had no
   blocks associated with it beforehand). To figure out the proper
   offset of pos to use within the block use
   (pos%whefs_fs_options_get(fs)->block_size).

   This function never actually changes the logical size of the inode,
   but may allocate new blocks to it.

   On success whefs_rc.OK is returned, else some other error
   value. Some possibilities include:

   - whefs_rc.RangeError = pos it past EOF and expands is false.
   - whefs_rc.FSFull = ran out of blocks while trying to expand.
   - whefs_rc.ArgEror = !fs, !tgt, or ino is not valid

   BIG FAT HAIRY WARNING:

   It is intended that the ino argument be an inode which has been
   opened via whefs_inode_open(), but this function does not check
   that because doing so is relatively costly and this routine is
   called from the i/o device implementation for every read and write.

   Because the ino argument *may* be updated, it is imperative that if
   ino refers to an opened inode, that the ino argument actually be a
   pointer to that object, as opposed to being a copy of it. Failure
   to follow this may result in mis-synchronization of the node's
   state or a memory leak. Specifically, if the inode previously had
   no blocks, and this function adds at least one, then ino must be
   updated. If ino has the same ID as an opened inode but is not that
   opened inode object (see whefs_inode_search_opened()), then ino
   will be updated but the opened inode will not, which will probably
   lead to any new blocks allocated by this call to become lost the
   next time the opened inode is flushed.


   BIGGER, FATTER, HAIRIER WARNING:

   Because profiling has shown that this function spends a significant
   amount of time validating fs and ino (by calling
   whefs_inode_is_valid()), that check has been removed. Since this
   function "can only" be called from the whefs_nodedev
   implementation, we're relying on that to do the validation (which
   it does).

*/
static int whefs_block_for_pos( whefs_fs * fs, whefs_inode * ino, whio_size_t pos, whefs_block * tgt, bool expand )
{
    whefs_id_type bc;
    whio_size_t bs;
    int rc = whefs_rc.OK;
    whefs_block bl = whefs_block_empty;
    whefs_block * blP = 0;
    /*if(  !tgt || !whefs_inode_is_valid( fs, ino ) ) return whefs_rc.ArgError; */
    if( (ino->data_size <= pos) && !expand )
    {
	/*WHEFS_DBG("return whefs_rc.RangeError"); */
	return whefs_rc.RangeError;
    }
    bs = whefs_fs_options_get(fs)->block_size;
    bc = /* how many blocks will we need? */
        1+(pos/bs)
        ;
    if(0) WHEFS_DBG("pos=%"WHIO_SIZE_T_PFMT" bs=%"WHIO_SIZE_T_PFMT" bc=%"WHEFS_ID_TYPE_PFMT,pos,bs,bc);
    /** ^^^ does this leave us with one too many blocks when we truncate() to
        an exact multiple of blocksize? */
    if( bc > whefs_fs_options_get(fs)->block_count )
    {
        WHEFS_DBG_WARN("VFS doesn't have enough blocks "
                       "(%"WHEFS_ID_TYPE_PFMT") to satisfy the "
                       "request for position %"WHIO_SIZE_T_PFMT
                       " of inode #%"WHEFS_ID_TYPE_PFMT,
                       whefs_fs_options_get(fs)->block_count, pos, ino->id );
        return whefs_rc.RangeError;
    }
    if( ! ino->blocks.list )
    {
	rc = whefs_inode_block_list_load( fs, ino );
	if( whefs_rc.OK != rc ) return rc;
    }
    if( !expand && (ino->blocks.count < bc) )
    { /* can't grow list for this request. */
	return whefs_rc.RangeError;
    }
    /* TODO: check number of available inodes here, and don't try to expand if we can't reach the end */
    /*WHEFS_DBG("About to search inode #%u for %u block(s) (size=%u) to find position %u", ino->id, bc, bs, pos ); */
    rc = whefs_rc.OK;
    if( bc <= ino->blocks.count)
    {
	blP = &ino->blocks.list[bc-1]; /* jump right to it */;
    }
    else
    { /* expand the list */
        whefs_id_type i;
	if( ! expand )
	{
	    if(0) WHEFS_DBG("Cannot expand to %"WHEFS_ID_TYPE_PFMT" blocks for position %"WHIO_SIZE_T_PFMT" because [expand] parameter is false.",
			    bc, pos );
	    return whefs_rc.RangeError;
	}
	/*bl = ino->blocks.list[ino->blocks.count-1]; */
	i = ino->blocks.count;
	blP = NULL;
	for( ; i < bc; ++i )
	{
	    rc = whefs_block_next_free( fs, &bl, true );
	    if( whefs_rc.OK == rc ) rc = whefs_inode_block_list_append( fs, ino, &bl );
	    if( whefs_rc.OK != rc ) return rc;
	    /**
	       We "might" want to truncate the inode back to its
	       previous length, but why add room for yet another error
	       on top of the one we just encountered?
	    */
	}
	blP = &bl;
    }
    if( whefs_rc.OK == rc )
    {
	*tgt = *blP;
    }
    /*WHEFS_DBG("Using block id #%u for pos %u of inode #%u", blP->id, pos, ino->id ); */
    return rc;
}