예제 #1
0
파일: file.c 프로젝트: huangrui/Thunix
int tfs_read(struct file *file, void *buf, int blocks)
{
	struct tfs_sb_info *sbi = TFS_SBI(file->fs);
	struct cache_struct *cs;
	uint32_t block;
	int index  = file->offset >> sbi->s_block_shift;
	int bytes_read = 0;

	TFS_DEBUG("rbuf: %p, blocks: %d, offset: %d\n", buf, blocks, file->offset);

	if (!blocks)
		return 0;
	if (file->offset >= file->inode->i_size)
		return -1;

	while (blocks--) {
		block = tfs_bmap(file->inode, index++);
		if (!block)
			break;
		cs = get_cache_block(file->fs, block);
		if (!cs)
			return -EIO;
		memcpy(buf, cs->data, sbi->s_block_size);
		bytes_read   += sbi->s_block_size;
		buf          += sbi->s_block_size;
	}

	return bytes_read;
}
예제 #2
0
파일: dir.c 프로젝트: huangrui/Thunix
/*
 * Returns:
 * 	NULL, entry not found
 * 	ERROR, errors happend.
 * 	cs,   entry found
 */
struct cache_struct * tfs_find_entry(struct inode *inode, const char *dname, struct tfs_dir_entry **res)
{
    uint32_t block;
    int index = 0;
    struct tfs_dir_entry *de;
    struct cache_struct *cs;
    struct tfs_sb_info *sbi = TFS_SBI(inode->i_fs);

    block = inode->i_data[index++];
    if (!block)
        return NULL;
    cs = get_cache_block(inode->i_fs, block);
    if (!cs)
        return ERR_PTR(-EIO);
    de = (struct tfs_dir_entry *)cs->data;

    while(1) {
        if ((char *)de >= (char *)cs->data + sbi->s_block_size) {
            if ((block = inode->i_data[index++]) < sbi->s_data_area)
                return NULL;
            cs = get_cache_block(inode->i_fs, block);
            if (!cs)
                return ERR_PTR(-EIO);
            de = (struct tfs_dir_entry *)cs->data;
        }
        if (de->d_inode == 0) {
            de++;
            continue;
        }
        if (tfs_match_entry(dname, de)) {
            *res = de;
            return cs;
        }

        de++;
    }

    return NULL;
}
예제 #3
0
파일: dir.c 프로젝트: huangrui/Thunix
/* read one directry entry at a time */
struct dirent * tfs_readdir(struct file *file)
{
    struct dirent *dirent;
    struct tfs_dir_entry *de;
    struct cache_struct *cs;
    struct inode *inode = file->inode;
    struct tfs_sb_info *sbi  = TFS_SBI(file->fs);
    int index = file->offset >> sbi->s_block_shift;
    uint32_t block;

    if (!(block = tfs_bmap(inode, index)))
        return NULL;
    cs = get_cache_block(file->fs, block);
    de = (struct tfs_dir_entry *)(cs->data + (file->offset & (sbi->s_block_size- 1)));

    if (!(dirent = malloc(sizeof(*dirent)))) {
        printk("malloc dirent structure in tfs_readdir error!\n");
        return NULL;
    }
    memset(dirent, 0, sizeof(*dirent));
    dirent->d_ino = de->d_inode;
    dirent->d_off = file->offset;
    dirent->d_reclen = sizeof(struct tfs_dir_entry);
    dirent->d_type = 0;
    memcpy(dirent->d_name, de->d_name, TFS_NAME_LEN);

    file->offset += sizeof(struct tfs_dir_entry);

    /* Skip the invalid one */
    if (de->d_inode == 0) {
        free(dirent);
        return tfs_readdir(file);
    }


    return dirent;
}
예제 #4
0
파일: dir.c 프로젝트: huangrui/Thunix
int tfs_add_entry(struct inode *dir, const char *name, int inr, int * dirty)
{
    uint32_t block;
    int index = 0;
    struct cache_struct *cs;
    struct tfs_dir_entry *de;
    struct tfs_sb_info *sbi = TFS_SBI(dir->i_fs);

    if (strlen(name) > TFS_NAME_LEN)
        return -ENAMETOOLONG;

    if (!(block = dir->i_data[index++]))
        goto alloc_new_block;
    cs = get_cache_block(dir->i_fs, block);
    if (!cs)
        return -EIO;
    de = (struct tfs_dir_entry *)cs->data;
    while (1) {
        if ((void *)de >= cs->data + sbi->s_block_size) {
            if (!(block = dir->i_data[index++]))
                break;
            cs = get_cache_block(dir->i_fs, block);
            if (!cs)
                return -EIO;
            de = (struct tfs_dir_entry *)cs->data;
        }
        if (!de->d_inode)
            break;
        de++;
    }

    *dirty = 0;

alloc_new_block:
    /* allocate a new block to hold the new entry */
    if (!block) {
        block = tfs_alloc_block(sbi, sbi->s_data_area);
        if (block < 0)
            return -ENOSPC;
        if (index > TFS_N_BLOCKS)
            return -EFBIG;

        dir->i_data[index - 1] = block;
        cs = get_cache_block(dir->i_fs, block);
        if (!cs)
            return -EIO;
        de = (struct tfs_dir_entry *)cs->data;
        memset(cs->data, 0, sbi->s_block_size);
    }

    /* Add a new entry at last */
    dir->i_size += sizeof(struct tfs_dir_entry);
    /* tell the caller to update this inode */
    *dirty = 1;

    memset(de, 0, sizeof(*de));
    de->d_inode = inr;
    memcpy(de->d_name, name, strlen(name));

    /* write the entry back to disk */
    if (tfs_bwrite(sbi, block, cs->data))
        return -EIO;

    return 0;
}
예제 #5
0
/** Write to an AFS file
 * \par Description:
 * Write from the given buffer into the given file starting at the given offset for
 * the given length.  First, if the offset is not block aligned, read the first
 * block/extent, write from the buffer into it starting at offset, and write it back
 * out.  Next, for all the complete blocks/extents, in the range, write to them from
 * the buffer.  Finally, if there is more to write, read the last extent/buffer,
 * write from the buffer into the beginning of the block/extent, and write it out.
 * \par Note: Directory data does not appear to be cached. This could be a huge slowdown.
 * \par Warning:
 * \param psVolume	AFS filesystem pointer
 * \param psInode	AFS Inode to write to
 * \param pBuffer	Buffer to write from
 * \param nPos		Start position in file to write at
 * \param a_nSize	Number of octets to write
 * \return 0 on success, negative error code on failure
 * \sa
 *****************************************************************************/
int afs_do_write( AfsVolume_s * psVolume, AfsInode_s * psInode, const char *pBuffer, off_t nPos, size_t a_nSize )
{
	const int nBlockSize = psVolume->av_psSuperBlock->as_nBlockSize;
	int nSize = a_nSize;
	off_t nFirstBlock = nPos / nBlockSize;
	off_t nLastBlock =( nPos + nSize + nBlockSize - 1 ) / nBlockSize;
	off_t nNumBlocks = nLastBlock - nFirstBlock + 1;
	int nOffset = nPos % nBlockSize;
	off_t nBlockAddr;
	char *pBlock = NULL;
	int nRunLength;
	int nError;

	if( ( nPos + nSize ) > ( afs_get_inode_block_count( psInode ) * nBlockSize ) )
	{
		if( S_ISDIR( psInode->ai_nMode ) )
		{
			printk( "Panic: afs_do_write() dir to small!!\n" );
		}
		else
		{
			printk( "Panic: afs_do_write() file to small!!\n" );
		}
		return( -ENOSPC );
	}

	if( S_ISDIR( psInode->ai_nMode ) )
	{
		pBlock = afs_alloc_block_buffer( psVolume );
		if( pBlock == NULL )
		{
			printk( "Error: afs_do_write() no memory for data buffer\n" );
			return( -ENOMEM );
		}
	}

	nError = afs_get_stream_blocks( psVolume, &psInode->ai_sData, nFirstBlock, nNumBlocks, &nBlockAddr, &nRunLength );

	if( nError < 0 )
	{
		printk( "Error: afs_do_write() 1 afs_get_stream_blocks() failed with code %d\n", nError );
	}

	if( nError >= 0 && nOffset != 0 )
	{
		if( S_ISDIR( psInode->ai_nMode ) )
		{
			nError = afs_logged_read( psVolume, pBlock, nBlockAddr );
		}
		else
		{
			pBlock =( char * )get_cache_block( psVolume->av_nDevice, nBlockAddr, nBlockSize );
			if( pBlock == NULL )
			{
				nError = -EIO;
			}
		}
		if( nError >= 0 )
		{
			off_t nLen = min( nSize, nBlockSize - nOffset );

			memcpy( pBlock + nOffset, pBuffer, nLen );
			if( S_ISDIR( psInode->ai_nMode ) )
			{
				nError = afs_logged_write( psVolume, pBlock, nBlockAddr );
			}
			else
			{
				mark_blocks_dirty( psVolume->av_nDevice, nBlockAddr, 1 );
				release_cache_block( psVolume->av_nDevice, nBlockAddr );
			}
			if( nError >= 0 )
			{
				pBuffer += nLen;
				nSize -= nLen;
				nBlockAddr++;
				nFirstBlock++;
				nRunLength--;
				nNumBlocks--;
			}
		}
	}
	while( nSize >= nBlockSize && nError >= 0 )
	{
		off_t nLen;

		if( nRunLength == 0 )
		{
			nError = afs_get_stream_blocks( psVolume, &psInode->ai_sData, nFirstBlock, nNumBlocks, &nBlockAddr, &nRunLength );
			if( nError < 0 )
			{
				printk( "Error: afs_do_write() 2 afs_get_stream_blocks() failed with code %d\n", nError );
			}
		}
		if( nError >= 0 )
		{
			int i;

			nLen = min( nSize / nBlockSize, nRunLength );
			if( S_ISDIR( psInode->ai_nMode ) )
			{
				nError = 0;
				for( i = 0; i < nLen; ++i )
				{
					nError = afs_logged_write( psVolume, pBuffer, nBlockAddr );
					if( nError < 0 )
					{
						printk( "Error: afs_do_write() failed to write directory data block\n" );
						break;
					}
					nRunLength--;
					nNumBlocks--;
					nFirstBlock++;
					nBlockAddr++;
					nSize -= nBlockSize;
					pBuffer += nBlockSize;
					kassertw( nRunLength >= 0 );
					kassertw( nSize >= 0 );
				}
			}
			else
			{
				nError = cached_write( psVolume->av_nDevice, nBlockAddr, pBuffer, nLen, nBlockSize );
				if( nError >= 0 )
				{
					nRunLength -= nLen;
					nNumBlocks -= nLen;
					nFirstBlock += nLen;
					nBlockAddr += nLen;
					nSize -= nLen * nBlockSize;
					pBuffer += nLen * nBlockSize;

					kassertw( nRunLength >= 0 );
					kassertw( nSize >= 0 );
				}
			}
		}
	}
	if( nSize > 0 && nError >= 0 )
	{
		if( nRunLength == 0 )
		{
			nError = afs_get_stream_blocks( psVolume, &psInode->ai_sData, nFirstBlock, nNumBlocks, &nBlockAddr, &nRunLength );
			if( nError < 0 )
			{
				printk( "Error: afs_do_write() 3 afs_get_stream_blocks() failed with code %d\n", nError );
			}
		}
		if( nError >= 0 )
		{
			if( S_ISDIR( psInode->ai_nMode ) )
			{
				if( psInode->ai_sData.ds_nSize > ( nPos + a_nSize ) )
				{
					nError = afs_logged_read( psVolume, pBlock, nBlockAddr );
				}
			}
			else
			{
				if( psInode->ai_sData.ds_nSize > ( nPos + a_nSize ) )
				{
					pBlock =( char * )get_cache_block( psVolume->av_nDevice, nBlockAddr, nBlockSize );
				}
				else
				{
					pBlock =( char * )get_empty_block( psVolume->av_nDevice, nBlockAddr, nBlockSize );
				}
				if( pBlock == NULL )
				{
					nError = -EIO;
				}
			}
			kassertw( nSize < nBlockSize );
			if( nError >= 0 )
			{
				off_t nLen = min( nSize, nBlockSize );

				memcpy( pBlock, pBuffer, nSize );
				pBuffer += nLen;
				nSize -= nLen;
				if( S_ISDIR( psInode->ai_nMode ) )
				{
					nError = afs_logged_write( psVolume, pBlock, nBlockAddr );
					if( nError < 0 )
					{
						printk( "Error: afs_do_write() failed to write last partial block to directory\n" );
					}
				}
				else
				{
					mark_blocks_dirty( psVolume->av_nDevice, nBlockAddr, 1 );
					release_cache_block( psVolume->av_nDevice, nBlockAddr );
				}
			}
		}
	}

	if( S_ISDIR( psInode->ai_nMode ) )
	{
		afs_free_block_buffer( psVolume, pBlock );
	}

	if( nError >= 0 )
	{
		if( ( nPos + a_nSize ) > psInode->ai_sData.ds_nSize )
		{
			psInode->ai_sData.ds_nSize = nPos + a_nSize;
		}
		psInode->ai_nModifiedTime = get_real_time();
		psInode->ai_nFlags |= INF_WAS_WRITTEN | INF_STAT_CHANGED;
	}

	return( nError );
}
예제 #6
0
/** Read from an AFS file
 * \par Description:
 * Read from the given file into the given buffer starting at the given offset for
 * the given length.  First, if the start position is not block aligned, read the
 * first block/extant and copy from it into the destination buffer.  Next, loop
 * through the blocks/extants, reading until there are no more full blocks, copying
 * into the destination buffer.  Finally, if there's any data left to read, read the
 * last block/extant and copy the correct data into the destination buffer.
 * \par Note: Directory data does not appear to be cached. This could be a huge slowdown.
 * \par Warning: Does not check for a read past the end of the file.  Use afs_read_pos
 * \param psVolume	AFS filesystem pointer
 * \param psInode	AFS Inode to read from
 * \param pBuffer	Destination buffer for the data
 * \param nPos		Start position in file
 * \param nSize		Number of octets to read
 * \return 0 on success, negative error code on failure
 * \sa
 *****************************************************************************/
static int afs_do_read( AfsVolume_s * psVolume, AfsInode_s * psInode, char *pBuffer, off_t nPos, size_t nSize )
{
	const int nBlockSize = psVolume->av_psSuperBlock->as_nBlockSize;
	off_t nFirstBlock = nPos / nBlockSize;
	off_t nLastBlock =( nPos + nSize + nBlockSize - 1 ) / nBlockSize;
	off_t nNumBlocks = nLastBlock - nFirstBlock + 1;
	int nOffset = nPos % nBlockSize;
	off_t nBlockAddr;
	char *pBlock = NULL;
	int nRunLength;
	int nError;

	if( S_ISDIR( psInode->ai_nMode ) )
	{
		pBlock = afs_alloc_block_buffer( psVolume );
		if( pBlock == NULL )
		{
			printk( "Error: afs_do_read() no memory for data buffer\n" );
			return( -ENOMEM );
		}
	}

	nError = afs_get_stream_blocks( psVolume, &psInode->ai_sData, nFirstBlock, nNumBlocks, &nBlockAddr, &nRunLength );

	if( nError < 0 )
	{
		printk( "Error: afs_do_read() 1 afs_get_stream_blocks() failed with code %d\n", nError );
	}
	if( nError >= 0 && nOffset != 0 )
	{
		if( S_ISDIR( psInode->ai_nMode ) )
		{
			nError = afs_logged_read( psVolume, pBlock, nBlockAddr );
		}
		else
		{
			pBlock =( char * )get_cache_block( psVolume->av_nDevice, nBlockAddr, nBlockSize );
			if( pBlock == NULL )
			{
				nError = -EIO;
			}
		}
		if( nError >= 0 )
		{
			off_t nLen = min( nSize, nBlockSize - nOffset );

			memcpy( pBuffer, pBlock + nOffset, nLen );
			pBuffer += nLen;
			nSize -= nLen;
			if( S_ISDIR( psInode->ai_nMode ) == false )
			{
				release_cache_block( psVolume->av_nDevice, nBlockAddr );
			}
		}
		nBlockAddr++;
		nFirstBlock++;
		nRunLength--;
		nNumBlocks--;
	}

	for( ; nSize >= nBlockSize && nError >= 0; )
	{
		if( nRunLength == 0 )
		{
			nError = afs_get_stream_blocks( psVolume, &psInode->ai_sData, nFirstBlock, nNumBlocks, &nBlockAddr, &nRunLength );
			if( nError < 0 )
			{
				printk( "Error: afs_do_read() 2 afs_get_stream_blocks( %Ld, %Ld ) failed with code %d\n", nFirstBlock, nNumBlocks, nError );
			}
		}
		if( nError >= 0 )
		{
			off_t nLen = min( nSize / nBlockSize, nRunLength );

			if( S_ISDIR( psInode->ai_nMode ) )
			{
				int i;

				nError = 0;
				for( i = 0; i < nLen; ++i )
				{
					nError = afs_logged_read( psVolume, pBuffer, nBlockAddr );
					if( nError < 0 )
					{
						printk( "Error: afs_do_read() failed to read directory data block\n" );
						break;
					}
					nRunLength--;
					nNumBlocks--;
					nFirstBlock++;
					nBlockAddr++;
					nSize -= nBlockSize;
					pBuffer += nBlockSize;
					kassertw( nRunLength >= 0 );
					kassertw( nSize >= 0 );
				}
			}
			else
			{
				nError = cached_read( psVolume->av_nDevice, nBlockAddr, pBuffer, nLen, nBlockSize );
				if( nError >= 0 )
				{
					nRunLength -= nLen;
					nNumBlocks -= nLen;
					nFirstBlock += nLen;
					nBlockAddr += nLen;
					nSize -= nLen * nBlockSize;
					pBuffer += nLen * nBlockSize;

					kassertw( nRunLength >= 0 );
					kassertw( nSize >= 0 );
				}
			}
		}
	}
	if( nSize > 0 && nError >= 0 )
	{
		if( nRunLength == 0 )
		{
			nError = afs_get_stream_blocks( psVolume, &psInode->ai_sData, nFirstBlock, nNumBlocks, &nBlockAddr, &nRunLength );
			if( nError < 0 )
			{
				printk( "Error: afs_do_read() 3 afs_get_stream_blocks() failed with code %d\n", nError );
			}
		}
		if( nError >= 0 )
		{
			if( S_ISDIR( psInode->ai_nMode ) )
			{
				nError = afs_logged_read( psVolume, pBlock, nBlockAddr );
			}
			else
			{
				pBlock =( char * )get_cache_block( psVolume->av_nDevice, nBlockAddr, nBlockSize );

//      printk( "read:3 %d:%d -> %d blocks at %d\n",
//              psInode->ai_sInodeNum.group, psInode->ai_sInodeNum.start, 1, nBlockAddr);

				if( pBlock == NULL )
				{
					nError = -EIO;
				}
			}
			kassertw( nSize < nBlockSize );
			if( nError >= 0 )
			{
				off_t nLen = min( nSize, nBlockSize );

				memcpy( pBuffer, pBlock, nSize );

				pBuffer += nLen;
				nSize -= nLen;
				if( S_ISDIR( psInode->ai_nMode ) == false )
				{
					release_cache_block( psVolume->av_nDevice, nBlockAddr );
				}
			}
		}
		else
		{
			printk( "Error : afs_do_read() Failed to locate last data block\n" );
		}
	}
	if( S_ISDIR( psInode->ai_nMode ) )
	{
		afs_free_block_buffer( psVolume, pBlock );
	}
	return( nError );
}
예제 #7
0
파일: file.c 프로젝트: huangrui/Thunix
int tfs_write(struct file *file, void *buf, int blocks)
{
	struct tfs_sb_info *sbi = TFS_SBI(file->fs);
	struct cache_struct *cs;
	int index  = file->offset >> sbi->s_block_shift;
	int block;
	int bufoff = file->offset & (sbi->s_block_size - 1);
	int bytes_written = 0;

	TFS_DEBUG("wbuf: %p, blocks: %d, offset: %d\n", buf, blocks, file->offset);

	if (!blocks)
		return 0;

	block  = tfs_bmap(file->inode, index++);
	if (!block) {
		if (index - 1 < TFS_N_BLOCKS) {
			block = tfs_alloc_block(sbi, sbi->s_data_area);
			if (block < 0)
				return -ENOSPC;
			file->inode->i_data[index - 1] = block;
		} else  {
			/* file too big */
			return -EFBIG;
		}
	}
	cs = get_cache_block(file->fs, block);
	if (!cs)
		return -EIO;
	bytes_written = sbi->s_block_size - bufoff;
	memmove(cs->data + bufoff, buf, bytes_written);
	buf	     += bytes_written;
	file->inode->i_size += MAX(0, file->offset + bytes_written - file->inode->i_size);
	/* write back to disk */
	if (tfs_bwrite(sbi, block, cs->data))
		return -EIO;
		
	blocks--;
	while (blocks--) {
		int bytes_need;
		block = tfs_bmap(file->inode, index++);
		if (!block) {
			if (index - 1 < TFS_N_BLOCKS) {
				block = tfs_alloc_block(sbi, sbi->s_data_area);
				if (block < 0)
					return -ENOSPC;
				file->inode->i_data[index - 1] = block;
			} else { 
				/* fle too big */
				return -EFBIG;
			}
		}
		bytes_need = sbi->s_block_size;
		cs = get_cache_block(file->fs, block);
		if (!cs)
			return -EIO;
		memcpy(cs->data, buf, bytes_need);
		bytes_written += bytes_need;
		buf           += bytes_need;
		file->inode->i_size += MAX(0, file->offset + bytes_written - file->inode->i_size);
		if (tfs_bwrite(sbi, block, cs->data))
			return -EIO;
	}

	if (tfs_iwrite(file->inode))
		return -EIO;
	
	return bytes_written;
}