E235
E235

Reputation: 13440

XV6 crashes when trying to implement triple indirection in xv6 operating system

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:
enter image description here

For some reason when I am trying to create file with size of 8.5MB it fails: enter image description here
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();
}

Upvotes: 1

Views: 2684

Answers (1)

Avner Schwartz
Avner Schwartz

Reputation: 68

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.

Upvotes: 3

Related Questions