This is the old task of implementing double-indirect inodes for the xv6 system. In double indirect a file can have 16523 blocks (11 direct-pointer + 1 single-indirect-pointer*128 + 1 double-indirect-pointer*128*128), and my implementation satisfies this condition according to the usertests output (I will present it below).
The full code of the xv6 system can be found at https://github.com/mit-pdos/xv6-public, and since if you are here you probably familiar with it, I will only present the modifications I made in the implementation of bmap() and itrunc() methods at fs.c:
// NINDIRECT is 128
// NDIRECT is 11
// There is one less direct pointer to make room for the double-indirect
// Return the disk block address of the nth block in inode ip.
// If there is no such block, bmap allocates one.
static uint
bmap(struct inode *ip, uint bn)
{
uint addr, *a;
uint *indirect;
struct buf *bp;
struct buf *dbp;
// Direct Pointer
if(bn < NDIRECT){
// get direct pointer, allocate if necessary
if((addr = ip->addrs[bn]) == 0)
ip->addrs[bn] = addr = balloc(ip->dev);
return addr;
}
bn -= NDIRECT;
// Indirect Pointer
if(bn < NINDIRECT){
// load indirect block, allocate if necessary
if((addr = ip->addrs[NDIRECT]) == 0)
ip->addrs[NDIRECT] = addr = balloc(ip->dev);
bp = bread(ip->dev, addr);
a = (uint*)bp->data;
// get direct pointer, allocate if necessary
if((addr = a[bn]) == 0){
a[bn] = addr = balloc(ip->dev);
log_write(bp);
}
// release indirect block
brelse(bp);
// return disk block address
return addr;
}
bn -= NINDIRECT;
// Double-indirect Pointer
if(bn < NDINDIRECT){
// load double-indirect block, allocate if necessary
if((addr = ip->addrs[NDIRECT+1]) == 0)
ip->addrs[NDIRECT] = addr = balloc(ip->dev);
dbp = bread(ip->dev,addr);
indirect = (uint*)dbp->data;
// load indirect block, allocate if necessary
if((addr = indirect[bn/NINDIRECT]) == 0)
indirect[bn/NINDIRECT] = addr = balloc(ip->dev);
bp = bread(ip->dev,addr);
a = (uint*)bp->data;
// get direct pointer, allocate if necessary
if((addr = a[bn%NINDIRECT]) == 0){
a[bn%NINDIRECT] = addr = balloc(ip->dev);
log_write(bp);
}
// release indirect & double-indirect blocks
brelse(bp);
brelse(dbp);
// return disk block address
return addr;
}
panic("bmap: out of range");
}
// Truncate inode (discard contents).
// Only called when the inode has no links
// to it (no directory entries referring to it)
// and has no in-memory reference to it (is
// not an open file or current directory).
static void
itrunc(struct inode *ip)
{
int i, j, k;
struct buf *bp;
struct buf *dbp;
uint *a;
uint *d;
// free the direct pointers
for(i = 0; i < NDIRECT; i++){
if(ip->addrs[i]){
bfree(ip->dev, ip->addrs[i]);
ip->addrs[i] = 0;
}
}
// free the indirect pointer
if(ip->addrs[NDIRECT]){
// load the indirect block
bp = bread(ip->dev, ip->addrs[NDIRECT]);
a = (uint*)bp->data;
// iterate over the block, and free all direct pointers
for(j = 0; j < NINDIRECT; j++){
if(a[j])
bfree(ip->dev, a[j]);
}
// free the indirect pointer
brelse(bp);
bfree(ip->dev, ip->addrs[NDIRECT]);
ip->addrs[NDIRECT] = 0;
}
// free the double indirect pointer
if(ip->addrs[NDIRECT+1]){
// load the double-indirect block
dbp = bread(ip->dev, ip->addrs[NDIRECT+1]);
d = (uint*)dbp->data;
// iterate over the block, and free all indirect blocks
for(k = 0; k < NINDIRECT; k++){
// load the indirect block
bp = bread(ip->dev, d[k]);
a = (uint*)bp->data;
// iterate over the block, and free all direct pointers
for(j = 0; j < NINDIRECT; j++){
if(a[j])
bfree(ip->dev,a[j]);
}
// free the infirect pointer
brelse(bp);
bfree(ip->dev, d[k]);
d[k] = 0;
}
// free the double-indirect pointer
brelse(dbp);
bfree(ip->dev, ip->addrs[NDIRECT+1]);
ip->addrs[NDIRECT+1] = 0;
}
ip->size = 0;
iupdate(ip);
}
The output I get from the usertests utility shows that the writing part is successful, but the system panic when it attempt to read the big file:
wrote 16523 sectors
closed the file for writing
opend the file for reading
read 0 sectors
lapicid 1: panic: log_write outside of trans
80102f18 80101249 80101442 80101b67 80100f89 80104b42 8010482a 80105829 80105572 0
I modified the bigfile() test a bit, so I will post it here too:
void
bigfile(void)
{
char buf[512];
int fd, i, sectors;
unlink("big.file");
fd = open("big.file", O_CREATE | O_WRONLY);
if(fd < 0){
printf(2, "big: cannot open big.file for writing\n");
exit();
}
sectors = 0;
while(1){
*(int*)buf = sectors;
int cc = write(fd, buf, sizeof(buf));
if(cc <= 0)
break;
sectors++;
if (sectors % 100 == 0){
printf(2, ".");
printf(2,"sector: %d\n",sectors);
}
}
printf(1, "\nwrote %d sectors\n", sectors);
close(fd);
printf(1,"closed the file for writing\n");
fd = open("big.file", O_RDONLY);
if(fd < 0){
printf(2, "big: cannot re-open big.file for reading\n");
exit();
}
printf(1,"opend the file for reading\n");
for(i = 0; i < sectors; i++){
int cc = read(fd, buf, sizeof(buf));
if(cc <= 0){
printf(2, "big: read error at sector %d\n", i);
exit();
}
if(*(int*)buf != i){
printf(2, "big: read the wrong data (%d) for sector %d\n",
*(int*)buf, i);
exit();
}
if(i%100 == 0)
printf(2,"read %d sectors\n",i);
}
close(fd);
unlink("big.file");
printf(1, "bigfile test ok\n");
}
Thanks in advance for any help.
P.S: of course I modified the size of FSSIZE in the param.h file to be big enough for double indirect pointers.
Related
I'm trying to make a file system in C. I have trouble with this portion of my code when I'm printing my values in the code below:
for (int i = 0; i<NUM_POINTERS; i++) {
printf("before SB->root[%d]=%d\n", i, SB->root->pointers[i]);
}
write_blocks(0, 1, SB);
for (int i = 0; i<NUM_POINTERS; i++) {
printf("after SB->root[%d]=%d\n", i, SB->root->pointers[i]);
}
my write_blocks method:
int write_blocks(int start_address, int nblocks, void *buffer)
{
int i, e, s;
e = 0;
s = 0;
void* blockWrite = (void*) malloc(BLOCK_SIZE);
/*Checks that the data requested is within the range of addresses of the disk*/
if (start_address + nblocks > MAX_BLOCK)
{
printf("out of bound error\n");
return -1;
}
/*Goto where the data is to be written on the disk*/
fseek(fp, start_address * BLOCK_SIZE, SEEK_SET);
/*For every block requested*/
for (i = 0; i < nblocks; ++i)
{
/*Pause until the latency duration is elapsed*/
usleep(L);
memcpy(blockWrite, buffer+(i*BLOCK_SIZE), BLOCK_SIZE);
fwrite(blockWrite, BLOCK_SIZE, 1, fp);
fflush(fp);
s++;
}
free(blockWrite);
/*If no failure return the number of blocks written, else return the negative number of failures*/
if (e == 0)
return s;
else
return e;
}
And here's what gets printed:
before SB->root[0]=1
before SB->root[1]=2
before SB->root[2]=3
before SB->root[3]=4
before SB->root[4]=5
before SB->root[5]=6
before SB->root[6]=7
before SB->root[7]=8
before SB->root[8]=9
before SB->root[9]=10
before SB->root[10]=11
before SB->root[11]=12
before SB->root[12]=13
before SB->root[13]=14
after SB->root[0]=1234344888
after SB->root[1]=32688
after SB->root[2]=3
after SB->root[3]=4
after SB->root[4]=5
after SB->root[5]=6
after SB->root[6]=7
after SB->root[7]=8
after SB->root[8]=9
after SB->root[9]=10
after SB->root[10]=11
after SB->root[11]=12
after SB->root[12]=13
after SB->root[13]=14
I don't understand why my first and second pointer value change?
Some additional information: SB is a superBlock here's my structures:
typedef struct iNode
{
int id;
int size;
int pointers[NUM_POINTERS];
} iNode;
typedef struct superBlock
{
int magic_number;
int block_size;
int num_blocks;
int num_inodes;
iNode *root;
iNode jNodes[20];
} superBlock;
Is this single threaded?
Does the modified SB->root[0,1] contain the data you are trying to write?
What is your BLOCK_SIZE?
I suspect the problem is outside of write_blocks(). My best guess would be that you accidentally freed SB somewhere and malloc gave you the same address. After the malloc check (print or debugger) both buffer and blockWrite and make sure they are different and valid.
Unrelated Issues:
printf has more % than params
You should check the return of malloc
e is never set
s and i are equal. AKA redundant.
Out of bounds error causes a memory leak (since it is after the malloc)
usleep is strange perhaps you want fsync?
I am currently working on the below requirement.
Here is the requirement: On the server side a large file is divided into 4000-byte blocks (frames). Each block is in turn compressed (using zlib) and sent to client process. For instance, if a file is 12000 bytes in size then it is divided into 3 blocks.
Above file will have 3 blocks => Block-0, Block-1, Block-2
On receipt, client decompresses each block (or frame) and writes to buffer allocated on the heap.When all the blocks corresponding to the entire file is received by the client, then the uncompressed version of the resultant file is written to the disk.
I have written a routine inflateData that does the following based on the block # received:
When the first block is received,
- inflateInit
- inflate
- inflateReset
When the intermediate blocks are received,
- inflate
- inflateReset
When the last block is received,
- inflate
- inflateEnd
With the above routine, Decompression of blocks happens as expected. But the issue that I face is it consumes lots of memory and at some point entire system slows down. When checked with valgrind, memory leak is reported with inflateInit2_. This causes the system resources to be exhausted.
==30359== 57,312 bytes in 6 blocks are possibly lost in loss record 64 of 67
==30359== at 0x4A069EE: malloc (vg_replace_malloc.c:270)
==30359== by 0x3E57808F1E: inflateInit2_ (in /lib64/libz.so.1.2.3)
==30359== by 0x40C220: inflateData (productMaker.c:1668)
Below is the routine inflateData.
int inflateData(
char* const inBuf,
unsigned long inLen,
unsigned int isFirstBlk,
unsigned int isLastBlk,
const char* outBuf,
unsigned long* outLen)
{
int have;
int readsz;
int bsize;
static z_stream zstrm;
int zerr;
int flush;
char out[CHUNK_SZ];
char in[CHUNK_SZ];
int ret,nwrite,idx = -1;
int savedByteCntr=0;
unsigned char *dstBuf;
int firstCall = 1;
int totalBytesIn=0;
int inflatedBytes=0;
int decompByteCounter = 0;
int num=0;
ret = Z_OK;
readsz = 0;
bsize = CHUNK_SZ;
dstBuf = (unsigned char *) outBuf;
if(isFirstBlk){
memset(&zstrm, '\0', sizeof(z_stream));
zstrm.zalloc = Z_NULL;
zstrm.zfree = Z_NULL;
zstrm.opaque = Z_NULL;
if ((zerr = inflateInit(&zstrm)) != Z_OK) {
uerror("ERROR %d inflateInit (%s)",
zerr, decode_zlib_err(zerr));
return -1;
}
}
while(totalBytesIn < inLen ) {
int compChunkSize = ((inLen - totalBytesIn) > 5120) ? 5120 :
(inLen - totalBytesIn);
memcpy(in, inBuf + totalBytesIn, compChunkSize);
zstrm.avail_in = inLen - totalBytesIn;
zstrm.next_in = in ;
zstrm.avail_out = CHUNK_SZ;
zstrm.next_out = out;
inflatedBytes = 0;
while(ret != Z_STREAM_END) {
ret = inflate(&zstrm, Z_NO_FLUSH);
if(ret < 0) {
uerror(" Error %d inflate (%s)", ret, decode_zlib_err(ret));
(void)inflateEnd(&zstrm);
return ret;
}
inflatedBytes = CHUNK_SZ - zstrm.avail_out;
if(inflatedBytes == 0) {
unotice("\n Unable to decompress data - truncated");
break;
}
totalBytesIn += zstrm.total_in;
decompByteCounter += inflatedBytes;
memcpy(dstBuf + savedByteCntr, out, inflatedBytes);
savedByteCntr = decompByteCounter;
}
// Reset inflater for additional input
ret = inflateReset(&zstrm);
if(ret == Z_STREAM_ERROR){
uerror(" Error %d inflateReset (%s)", ret, decode_zlib_err(ret));
(void)inflateEnd(&zstrm);
return ret;
}
}
if(isLastBlk){
ret = inflateEnd(&zstrm);
if(ret < 0) {
uerror("Fail inflateEnd %d [%s] ", ret, decode_zlib_err(ret));
return (ret);
}
}
*outLen = decompByteCounter;
return 0;
}
Thanks in advance for the support.
Thanks,
Sathya.
You are making an error in your use of your inflateData() routine.
First off, using a static variable in this way is a horrible idea. If you call your inflateData() twice with isFirstBlk true without an intermediate call with isLastBlk true, then you will wipe out the reference to the first set of allocations, resulting in a memory leak.
To avoid this sort of error, you should keep track of whether zstrm is initialized or not, and reject any attempt to initialize an already initialized stream. Better still would be to not even have an isFirstBlk, and simply initialize zstrm on the first call and on any call that immediately follows a call with isLastBlk true.
So you are either doing the above, calling twice with isFirstBlk true, or failing to call with isLastBlk true.
I'm trying to put a file in a struct but I'm having problems sharing the memory as I can access the fields in the created process where the mapping happens but cannot access the arrays(can only access the int) in the other processes. I tried a lot of different things but the way I present next is the one that makes more sense to me as I'm allocating memory the right way with shmget.
For clarity: The only thing that is being shared is the integer lim_thread. The other fields are in a area of memory that I can not access. Why?
As I see the pointers are pointing to a region of memory that is shared.
configs.txt:
Threads = 5
Domains = uc.pt; edu
LocalDomain = so.local
NamedPipeEstatisticas = statistics
struct:
typedef struct configs
{
int lim_thread;
char (*valid_domains)[MAX_DOMAIN_SIZE]; //max size for valid domains
char *domain;
char *stat_pipe;
sem_t sem;
} CONFIGS;
main.c:
/*Shared memory for configs*/
CONFIGS *_configs;
int _shmid_configs;
int main(int argc, char *argv[]) {
pid_t config_pid; //will hold the configuration process id
_shmid_configs = shmget(IPC_PRIVATE, sizeof(CONFIGS), IPC_CREAT|0666);
_configs = shmat(_shmid_configs, NULL, 0);
/*Semaphores*/
sem_init( &( _configs->sem), 1, 0);
//initializes processes
if( ( config_pid = fork() ) < 0) {
perror("Failed creating configuration manager process");
num_forks++;
}
else if( config_pid == 0 ) {
init_config();
exit(0);
}
sem_wait(&(_configs->sem));
/////////////////////////DEBUG////////////////////////////////
printf("%d\n", _configs->lim_thread);
printf("%s\n", *(_configs->valid_domains+1));
printf("%s\n", _configs->domain);
printf("%s\n", _configs->stat_pipe);
//////////////////////////////////////////////////////////////
return 0;
}
configs.c
#define MAX_LINE_SIZE 1000
int init_config() {
FILE *fp;
char domains[MAX_LINE_SIZE], line[MAX_LINE_SIZE], *saveptr, *aux_char;
int count = 0, aux;
int temp_shmid;
if( ( fp = fopen( "./configs.txt", "r")) == NULL) {
perror("Failed to open configs.txt");
return -1;
}
fscanf( fp,"Threads = %d\n", &(_configs->lim_thread));
//To start reading "Domains = "
fscanf(fp, "Domains = ");
fgets(domains, MAX_LINE_SIZE, fp);
domains[strlen(domains) -1] = '\0';
//counts the number of domains
for(aux = 0; aux < strlen(domains); aux++) {
if( domains[aux] == ';' ) {
count++;
}
}
//creates shared memory for the valid domains
temp_shmid = shmget(IPC_PRIVATE, (count+1) * sizeof( char[MAX_DOMAIN_SIZE]), IPC_CREAT|0666);
_configs->valid_domains = shmat( temp_shmid, NULL, 0);
//copies all the data to the struct
strcpy( *(_configs->valid_domains), strtok_r(domains, "; ", &saveptr) );
aux = 1;
while( ( aux_char = strtok_r( NULL, "; ", &saveptr) ) != NULL) {
strcpy( *(_configs->valid_domains + aux), aux_char);
aux++;
}
fscanf(fp, "LocalDomain = %s\n", line);
temp_shmid = shmget(IPC_PRIVATE, (strlen(line) + 1) * sizeof(char), IPC_CREAT|0660);
_configs->domain = (char*)shmat(temp_shmid, NULL, 0);
strcpy(_configs->domain, line);
fscanf(fp, "NamedPipeEstatisticas = %s\n", line);
temp_shmid = shmget( IPC_PRIVATE, (strlen(line) +1) * sizeof(char), IPC_CREAT|0660);
_configs->stat_pipe = (char*)shmat(temp_shmid, NULL, 0);
strcpy(_configs->stat_pipe, line);
fclose(fp);
sem_post( &(_configs->sem));
/////////////////////////DEBUG////////////////////////////////
printf("%d\n", _configs->lim_thread);
printf("%s\n", *(_configs->valid_domains+1));
printf("%s\n", _configs->domain);
printf("%s\n", _configs->stat_pipe);
//////////////////////////////////////////////////////////////
return 0;
}
As kaylum pointed out, each process might map a shared memory block to a different virtual address. Hence pointers cannot be shared, you need to work with offsets.
Allocate a single block of shared memory that you divide in two parts: a table of content and a data area. The table of content consists of variables that contain either a value or (instead of a pointer), the offset between the start of the shared memory block and the start of a data element inside the data area.
Then to obtain the address of a data element a process simply adds its offset to the address of the shared memory block in its address space.
You can do what you want. Just do all your shmget/shmat in your main process/thread before you create any threads.
The children will inherit the pointers and the values will be the same for all threads (e.g. the pointers are global. That is, they are not using _thread and are not in thread local storage).
This works fine. I've used it in systems with 50+ threads and it works great
The original xv6-rev7 operating system contains:
12 directed blocks
1 indirect blcok(points to 128 blocks)
This means we have 140 blocks.
Each block's size is 512KB ==> 512 * 140 = 71,680 ~= 70KB is the limit of file's size in xv6.
I want to implemet triple indirect access in xv6 in order to support files with size of 40MB.
In order to do it I will need to implement double indirect before the triple indirect.
So I took 2 directed blocks from the 12 I had.
1 for the double indirect and the other for the triple indirect.
This is what I have right now:
Direct: 10 blocks
Single indirect: 128
Double indirect: 128*128
Triple indirect: 4*128*128 (I am using 4 instead of 128 because this is enough for 40MB)
This is why #define NDIRECT 10 and uint addrs[NDIRECT+3];
File's size limit = (10 + 128 + 128*128 + 4*128*128)*512kb = 42,013,696 ~= 42MB
So I understand the concept.
The implementation of the triple-indirection is in function bmap in file fs.c.
This is how it looks:
For some reason when I am trying to create file with size of 8.5MB it fails:
I am using bochs emulator
I am also not sure to what values I need to change in mkfs.c:
int nblocks = 20985;
int nlog = LOGSIZE;
int ninodes = 200;
int size = 21029;
fs.h:
// On-disk file system format.
// Both the kernel and user programs use this header file.
// Block 0 is unused.
// Block 1 is super block.
// Blocks 2 through sb.ninodes/IPB hold inodes.
// Then free bitmap blocks holding sb.size bits.
// Then sb.nblocks data blocks.
// Then sb.nlog log blocks.
#define ROOTINO 1 // root i-number
#define BSIZE 512 // block size
// File system super block
struct superblock {
uint size; // Size of file system image (blocks)
uint nblocks; // Number of data blocks
uint ninodes; // Number of inodes.
uint nlog; // Number of log blocks
};
#define NDIRECT 10
#define NINDIRECT (BSIZE / sizeof(uint))
#define MAXFILE (NDIRECT + NINDIRECT + NINDIRECT*NINDIRECT + 4*NINDIRECT*NINDIRECT)
// On-disk inode structure
struct dinode {
short type; // File type
short major; // Major device number (T_DEV only)
short minor; // Minor device number (T_DEV only)
short nlink; // Number of links to inode in file system
uint size; // Size of file (bytes)
uint addrs[NDIRECT+3]; // Data block addresses
};
// Inodes per block.
#define IPB (BSIZE / sizeof(struct dinode))
// Block containing inode i
#define IBLOCK(i) ((i) / IPB + 2)
// Bitmap bits per block
#define BPB (BSIZE*8)
// Block containing bit for block b
#define BBLOCK(b, ninodes) (b/BPB + (ninodes)/IPB + 3)
// Directory is a file containing a sequence of dirent structures.
#define DIRSIZ 14
struct dirent {
ushort inum;
char name[DIRSIZ];
};
fs.c:
// Return the disk block address of the nth block in inode ip.
// If there is no such block, bmap allocates one.
static uint
bmap(struct inode *ip, uint bn)
{
uint addr, *a;
struct buf *bp;
if(bn < NDIRECT){
if((addr = ip->addrs[bn]) == 0)
ip->addrs[bn] = addr = balloc(ip->dev);
return addr;
}
bn -= NDIRECT;
if(bn < NINDIRECT){
// Load indirect block, allocating if necessary.
if((addr = ip->addrs[NDIRECT]) == 0)
ip->addrs[NDIRECT] = addr = balloc(ip->dev);
bp = bread(ip->dev, addr);
a = (uint*)bp->data;
if((addr = a[bn]) == 0){
a[bn] = addr = balloc(ip->dev);
log_write(bp);
}
brelse(bp);
return addr;
}
/* Double indirect */
bn -= NINDIRECT;
if(bn < NINDIRECT*NINDIRECT){
// Load 2nd indirect block, allocating if necessary.
if((addr = ip->addrs[NDIRECT+1]) == 0) // 2d block. NDIRECT+1 is to get the index vector
ip->addrs[NDIRECT+1] = addr = balloc(ip->dev);
bp = bread(ip->dev, addr);
a = (uint*)bp->data;
if ((addr = a[bn/(NINDIRECT)]) == 0) { /* get index for 1st
indirection. (NINDIRECT is 128) */
a[bn/(NINDIRECT)] = addr = balloc(ip->dev);
log_write(bp);
}
brelse(bp); /* release the double indirect table
(main level) */
bp = bread(ip->dev, addr);
a = (uint*)bp->data;
if ((addr = a[bn%(NINDIRECT)]) == 0) { /* get the 2nd level table */
a[bn%(NINDIRECT)] = addr = balloc(ip->dev);
log_write(bp);
}
brelse(bp);
return addr;
}
/* Triple indirect */
bn -= NINDIRECT*NINDIRECT;
if(bn < 4*NINDIRECT*NINDIRECT){
// Load 3rd indirect block, allocating if necessary.
if((addr = ip->addrs[NDIRECT+2]) == 0) // 3d block. NDIRECT+2 is to get the index vector
ip->addrs[NDIRECT+2] = addr = balloc(ip->dev);
bp = bread(ip->dev, addr);
a = (uint*)bp->data;
if ((addr = a[bn/(NINDIRECT*4)]) == 0) { /* get index for 2st
indirection. (NINDIRECT is 128) */
a[bn/(NINDIRECT*4)] = addr = balloc(ip->dev);
log_write(bp);
}
brelse(bp);
bp = bread(ip->dev, addr);
a = (uint*)bp->data;
if ((addr = a[bn/(NINDIRECT*NINDIRECT*4)]) == 0) {
a[bn/(NINDIRECT*NINDIRECT*4)] = addr = balloc(ip->dev);
log_write(bp);
}
brelse(bp);
if ((addr = a[bn%(NINDIRECT*NINDIRECT*4)]) == 0) {
a[bn%(NINDIRECT*NINDIRECT*4)] = addr = balloc(ip->dev);
log_write(bp);
}
brelse(bp);
return addr;
}
panic("bmap: out of range");
}
mkfs.c:
#define stat xv6_stat // avoid clash with host struct stat
#include "types.h"
#include "fs.h"
#include "stat.h"
#include "param.h"
int nblocks = 20985;
int nlog = LOGSIZE;
int ninodes = 200;
int size = 21029;
bigfile.c:
#include "types.h"
#include "stat.h"
#include "user.h"
#include "fcntl.h"
void
help()
{
printf(1, "usage:\nfiles <name> <letter> <num>\n"
"e.g. nfiles foo a 40\n creates a file foo, with 40 times the letter a\n");
}
void
num2str(int i, char str[3])
{
str[2]=i%10+'0';
i=i/10;
str[1]=i%10+'0';
i=i/10;
str[0]=i%10+'0';
i=i/10;
}
#define BUF_SZ 512
int
main(int argc, char *argv[])
{
int i, count, fd, n;
// char *name;
// char c;
char buf[BUF_SZ];
if (argc !=4) {
help();
exit();
}
count = atoi(argv[3]);
if((fd=open(argv[1], O_CREATE|O_RDWR))<0) {
printf(2,"Failed to open file: %s\n", argv[1]);
exit();
}
for (i=0; i<BUF_SZ;i++)
buf[i]=argv[2][0];
for (i=0; i<count/BUF_SZ;i++)
if ((n=write(fd,buf,BUF_SZ)) != BUF_SZ)
{
printf(2,"Failed 1 to Write count=%d\n",i*BUF_SZ);
exit();
}
for (i=0; i<count%BUF_SZ;i++)
if ((n=write(fd,argv[2],1)) != 1)
{
printf(2,"Failed 2 to Write count=%d\n",count-i);
exit();
}
exit();
}
1.The number of nblocks which is defined in mkfs.c is insufficient.
int nblocks = 20985;
int nlog = LOGSIZE;
int ninodes = 200;
int size = 21029;
You have defined:
#define MAXFILE (NDIRECT + NINDIRECT + NINDIRECT*NINDIRECT + 4*NINDIRECT*NINDIRECT
which equals: 10+128+128^2+4*128^2 = 82058.
Just pick a number of nblocks which is greater than 82058, and update size accordingly.
2.In your bmap() function, in the triple indirection code, your first level of indirection is to a four-entry array (as you mentioned in your diagram).
Once you know to which of these four entries you should access, you're back with the double indirection problem, which you already solved.
So, in order to know which of the four entries you should access, you can use this:
if((addr = a[bn/(NINDIRECT*NINDIRECT)]) == 0){
a[bn/(NINDIRECT*NINDIRECT)] = addr = balloc(ip->dev);
log_write(bp);
}
You then could decrease bn like so:
bn -= ((NINDIRECT*NINDIRECT)*(bn/(NINDIRECT*NINDIRECT)));
and solve the double indirection problem again.
I create a 2D array to simulator a cache. For each cache line, I use struct to define it. When i want initialize the cahce, something is wrong when using malloc. I have marked the wrong place in the code.
Thanks!
typedef struct {
int valid;
int tag;
int lruIndex;
} Line;
Line** initCache(int s, int E){
int i, j;
//int setSize = sizeof(Line *);
//int lineSize = sizeof(Line);
/* allocate memory to cache */
//printf("%d %d\n", setSize, lineSize );
Line** cache = NULL;
cache = (Line **)malloc((1 << s) * sizeof(Line *)); //set
//check for memory error
if (!cache)
{
printf("%s\n", "allocate memory failed 1111111");
exit(-1);
}
for (i = 0; i < (1 << s); i++){
cache[i] = (Line *)malloc(E * sizeof(Line)); <<<<<<< i think here something is wrong, cache[i] returns NULL and then print "allocate memory failed 22222222"
//check for memory error
if (cache[i])
{
printf("%s\n", "allocate memory failed 22222222");
exit(-1);
}
for(j = 0; j < E; j++){
cache[i][j].valid = 0; //initial value of valid
cache[i][j].lruIndex = j; //initial value of lruIndex 0 ~ E-1
}
}
return cache;
}
if (cache[i])
{
printf("%s\n", "allocate memory failed 22222222");
exit(-1);
}
exits when cache[i] is != NULL, what means you exit when memory is allocated.
To work correct way change condition to:
(cache[i]==NULL)
which will evaluate to TRUE, when malloc fails.
malloc((1 << s) * sizeof(Line *)
can be malloc (0 * 4) too !
also you can run out of memory.