int
testfs_read_data(struct inode *in, char *buf, off_t start, size_t size)
{
	char block[BLOCK_SIZE];
	long block_nr = start / BLOCK_SIZE;
	long block_ix = start % BLOCK_SIZE;
	int ret;

	assert(buf);
	if (start + (off_t) size > in->in.i_size) {
		size = in->in.i_size - start;
	}
	if (block_ix + size > BLOCK_SIZE) {
		int req_b = DIVROUNDUP(block_ix+size,BLOCK_SIZE);
		int i;
		size_t read_block_size, remaining_bytes;
		remaining_bytes = size;

		read_block_size = BLOCK_SIZE - block_ix;
		remaining_bytes -= read_block_size;
		if ((ret = testfs_read_block(in, block_nr, block)) < 0)
			return ret;
		memcpy(buf, block+block_ix, read_block_size);
		block_nr++;

		for (i=1;i<req_b; i++)
		{
			memset(&block[0],0,sizeof(block));

			if ((ret = testfs_read_block(in, block_nr, block)) < 0)
				return ret;

			if (remaining_bytes >= BLOCK_SIZE)
			{
				read_block_size = BLOCK_SIZE;
				remaining_bytes -= BLOCK_SIZE;
			}
			else if (remaining_bytes <BLOCK_SIZE)
			{
				read_block_size= remaining_bytes;
				remaining_bytes=0;
			}
			else if (remaining_bytes ==0)
			{
				break;
			}
			memcpy(buf+size - (remaining_bytes + read_block_size), block, read_block_size);
			block_nr++;
		}

		return size;

	}
	if ((ret = testfs_read_block(in, block_nr, block)) < 0)
		return ret;
	memcpy(buf, block + block_ix, size);
	/* return the number of bytes read or any error */
	return size;
}
Beispiel #2
0
int testfs_read_data(struct inode *in, char *buf, off_t start, size_t size) {
    char block[BLOCK_SIZE];
    long block_nr = start / BLOCK_SIZE;
    long block_ix = start % BLOCK_SIZE;
    int ret;

    assert(buf);
    if (start + (off_t) size > in->in.i_size) {
        size = in->in.i_size - start;
    }
    if (block_ix + size > BLOCK_SIZE) {
        if (size > 34376597504)
            return -EFBIG;
        if ((ret = testfs_read_block(in, block_nr, block)) < 0)
            return ret;
        memcpy(buf, block + block_ix, BLOCK_SIZE - block_ix); //copy the head
        long size_remaining = size - (BLOCK_SIZE - block_ix); //size left to copy
        int i = 1;
        while(size_remaining > BLOCK_SIZE){
            if ((ret = testfs_read_block(in, block_nr + i, block)) < 0)
                return ret;
            memcpy(buf + (BLOCK_SIZE * i) - block_ix, block, BLOCK_SIZE); //copy entire blocks
            i++;
            size_remaining -= BLOCK_SIZE;
        }
        if ((ret = testfs_read_block(in, block_nr + i, block)) < 0)
            return ret;
        memcpy(buf + (BLOCK_SIZE * i) - block_ix, block, size_remaining); //copy the tail
        return size;
    }
    if ((ret = testfs_read_block(in, block_nr, block)) < 0)
        return ret;
    memcpy(buf, block + block_ix, size);
    /* return the number of bytes read or any error */
    return size;
}
/* given logical block number, allocate a new physical block, if it does not
 * exist already, and return the physical block number that is allocated.
 * returns negative value on error. */
 static int
 testfs_allocate_block(struct inode *in, int log_block_nr, char *block)
 {
 	if (log_block_nr>4196361)
 		return -EFBIG;
 	// //printf("log_block_nr:%d\n",log_block_nr);
 	// }

 	int phy_block_nr;
 	char indirect[BLOCK_SIZE];
 	char dindirect[BLOCK_SIZE];
 	char dindirect2[BLOCK_SIZE];
 	int indirect_allocated = 0;
 	//int dindirect_allocated = 0;
 	
 	assert(log_block_nr >= 0);
 	phy_block_nr = testfs_read_block(in, log_block_nr, block);

	/* phy_block_nr > 0: block exists, so we don't need to allocate it, 
	   phy_block_nr < 0: some error */
 	if (phy_block_nr != 0)
 		return phy_block_nr;

	/* allocate a direct block */
 	if (log_block_nr < NR_DIRECT_BLOCKS) {
 		assert(in->in.i_block_nr[log_block_nr] == 0);
 		phy_block_nr = testfs_alloc_block_for_inode(in);
 		if (phy_block_nr >= 0) {
 			in->in.i_block_nr[log_block_nr] = phy_block_nr;
 		}
 		return phy_block_nr;
 	}

 	log_block_nr -= NR_DIRECT_BLOCKS;

 	if (log_block_nr >= NR_INDIRECT_BLOCKS)
 	{
 	
 		log_block_nr -= NR_INDIRECT_BLOCKS; //log block ranges from 0 ~ 4194303
 		
 		int level1_block = DIVROUNDUP(log_block_nr+1,2048) - 1;   // ranges 0~2047
 		
 		int level2_block= log_block_nr % 2048;

 		/* allocate an dindirect block */
 		if (in->in.i_dindirect == 0) 	
 		{	
 			bzero(dindirect, BLOCK_SIZE);
 			phy_block_nr = testfs_alloc_block_for_inode(in);
 			if (phy_block_nr < 0)
 				return phy_block_nr;
 			//dindirect_allocated = 1;
 			in->in.i_dindirect = phy_block_nr;
 			//printf("dindirect block #:%d\n",phy_block_nr);
 		}

 		else   /* read dindirect block */
 		{
 			read_blocks(in->sb, dindirect, in->in.i_dindirect, 1); 
 		}



 		// Allocate 2nd level indirect block
 		if (((int *)dindirect)[level1_block] == 0)
 		{
 			bzero(dindirect2, BLOCK_SIZE);
 			phy_block_nr = testfs_alloc_block_for_inode(in);
 			if (phy_block_nr < 0)
 				return phy_block_nr;
 			((int*)dindirect)[level1_block]=phy_block_nr;
	 		//printf("2nd dindirect block #:%d\n", ((int*)dindirect)[level1_block]);
 			write_blocks(in->sb, dindirect, in->in.i_dindirect,1);
 		}

 		// error here....
 		// Read 2nd level indirect block
 		else 
 		{	
 			read_blocks(in->sb, dindirect2, ((int*)dindirect)[level1_block], 1);
 		}


 		// allocate direct block */
 		phy_block_nr=testfs_alloc_block_for_inode(in);


	 	if (phy_block_nr >=0)  // update 2nd level indirect block
	 	{
	 		((int*)dindirect2)[level2_block]=phy_block_nr;
	 		//printf("Last direct block #:%d\n", ((int*)dindirect2)[level2_block]);
	 		write_blocks(in->sb, dindirect2, ((int*)dindirect)[level1_block], 1);
	 	}
	 	
	 	return phy_block_nr;
 		// Allocate 2nd-level indirect block

	 }

 	/**** Allocating in 1st level indirect blocks ****/

	if (in->in.i_indirect == 0) 	/* allocate an indirect block */
	 {	
	 	bzero(indirect, BLOCK_SIZE);
	 	phy_block_nr = testfs_alloc_block_for_inode(in);
	 	if (phy_block_nr < 0)
	 		return phy_block_nr;
	 	indirect_allocated = 1;
	 	in->in.i_indirect = phy_block_nr;
	 } 

	 else 
	{	/* read indirect block */
	 	read_blocks(in->sb, indirect, in->in.i_indirect, 1);
	}

	/* allocate direct block */
	assert(((int *)indirect)[log_block_nr] == 0);	
	phy_block_nr = testfs_alloc_block_for_inode(in);

	if (phy_block_nr >= 0) {
		/* update indirect block */
		((int *)indirect)[log_block_nr] = phy_block_nr;
		write_blocks(in->sb, indirect, in->in.i_indirect, 1);
	} 

	else if (indirect_allocated) 
	{
		/* free the indirect block that was allocated */
		testfs_free_block_from_inode(in, in->in.i_indirect);
	}

	return phy_block_nr;

}
Beispiel #4
0
/* given logical block number, allocate a new physical block, if it does not
 * exist already, and return the physical block number that is allocated.
 * returns negative value on error. */
static int testfs_allocate_block(struct inode *in, int log_block_nr, char *block) {
    int phy_block_nr;
    char indirect[BLOCK_SIZE];
    int indirect_allocated = 0;

    assert(log_block_nr >= 0);
    phy_block_nr = testfs_read_block(in, log_block_nr, block);

    /* phy_block_nr > 0: block exists, so we don't need to allocate it, 
       phy_block_nr < 0: some error */
    if (phy_block_nr != 0)
        return phy_block_nr;

    /* allocate a direct block */
    if (log_block_nr < NR_DIRECT_BLOCKS) {
        assert(in->in.i_block_nr[log_block_nr] == 0);
        phy_block_nr = testfs_alloc_block_for_inode(in);
        if (phy_block_nr >= 0) {
            in->in.i_block_nr[log_block_nr] = phy_block_nr;
        }
        return phy_block_nr;
    }

    log_block_nr -= NR_DIRECT_BLOCKS;
    if (log_block_nr >= NR_INDIRECT_BLOCKS) {
        log_block_nr -= NR_INDIRECT_BLOCKS;
        char dindirect[BLOCK_SIZE];
        int dindirect_allocated = 0;
        int position = log_block_nr/NR_INDIRECT_BLOCKS;
        if (log_block_nr >= NR_INDIRECT_BLOCKS * NR_INDIRECT_BLOCKS) {
            return -EFBIG;
        }
        //get the double indirect block first
        if(in->in.i_dindirect == 0){
            bzero(dindirect, BLOCK_SIZE);
            phy_block_nr = testfs_alloc_block_for_inode(in);
            if(phy_block_nr < 0)
                return phy_block_nr;
            dindirect_allocated = 1;
            in->in.i_dindirect = phy_block_nr;
        } else{
            read_blocks(in->sb, dindirect, in->in.i_dindirect, 1);
        }
        //get the indirect block in double indirect block
        if(((int*) dindirect)[position] == 0) {
            bzero(indirect, BLOCK_SIZE);
            phy_block_nr = testfs_alloc_block_for_inode(in);
            if (phy_block_nr < 0){
                if (dindirect_allocated) {
                    testfs_free_block_from_inode(in, in->in.i_dindirect);
                    return phy_block_nr;
                }
            } else{
                indirect_allocated = 1;
                ((int *) dindirect)[position] = phy_block_nr;
                write_blocks(in->sb, dindirect, in->in.i_dindirect, 1);
            }
        }else{
            read_blocks(in->sb, indirect, ((int*) dindirect)[position], 1);
        }
        //get the direct block
        assert(((int *) indirect)[log_block_nr % NR_INDIRECT_BLOCKS] == 0);
        phy_block_nr = testfs_alloc_block_for_inode(in);
        if(phy_block_nr < 0){
            if(dindirect_allocated){
                testfs_free_block_from_inode(in, ((int *)dindirect)[position]);
                testfs_free_block_from_inode(in, in->in.i_dindirect);
            }else if(indirect_allocated)
                testfs_free_block_from_inode(in, ((int *)dindirect)[position]);
            return phy_block_nr;
        }
        else if (phy_block_nr >= 0) {
            ((int *) indirect)[log_block_nr % NR_INDIRECT_BLOCKS] = phy_block_nr;
            write_blocks(in->sb, indirect, ((int *)dindirect)[position], 1);
        } 
        return phy_block_nr;
    } 
    
    
    if (in->in.i_indirect == 0) { /* allocate an indirect block */
        bzero(indirect, BLOCK_SIZE);
        phy_block_nr = testfs_alloc_block_for_inode(in);
        if (phy_block_nr < 0)
            return phy_block_nr;
        indirect_allocated = 1;
        in->in.i_indirect = phy_block_nr;
    } else { /* read indirect block */
        read_blocks(in->sb, indirect, in->in.i_indirect, 1);
    }

    /* allocate direct block */
    assert(((int *) indirect)[log_block_nr] == 0);
    phy_block_nr = testfs_alloc_block_for_inode(in);

    if (phy_block_nr >= 0) {
        /* update indirect block */
        ((int *) indirect)[log_block_nr] = phy_block_nr;
        write_blocks(in->sb, indirect, in->in.i_indirect, 1);
    } else if (indirect_allocated) {
        /* free the indirect block that was allocated */
        testfs_free_block_from_inode(in, in->in.i_indirect);
    }
    return phy_block_nr;
}