diff options
| -rw-r--r-- | Notes | 18 | ||||
| -rw-r--r-- | defs.h | 4 | ||||
| -rw-r--r-- | fs.c | 119 | ||||
| -rw-r--r-- | fs.h | 4 | ||||
| -rw-r--r-- | fsvar.h | 2 | ||||
| -rw-r--r-- | mkfs.c | 16 | ||||
| -rw-r--r-- | syscall.c | 12 | 
7 files changed, 164 insertions, 11 deletions
| @@ -142,10 +142,22 @@ systematic way to test sleep races?  do you have to be holding the mutex in order to call wakeup()? -should lock around printf, not putc -  device interrupts don't clear FL_IF    so a recursive timer interrupt is possible -the sleep/swtch/schedule code that holds over a lock is ugly +what does inode->busy mean? +  might be held across disk reads +  no-one is allowed to do anything to the inode +  protected by inode_table_lock +inode->count counts in-memory pointers to the struct +  prevents inode[] element from being re-used +  protected by inode_table_lock + +blocks and inodes have ad-hoc sleep-locks +  provide a single mechanism? + +need to lock bufs in bio between bread and brelse +test 14-character file names +and file arguments longer than 14 +and directories longer than one sector @@ -97,4 +97,8 @@ void brelse(struct buf *);  // fs.c  struct inode * iget(uint dev, uint inum); +void ilock(struct inode *ip); +void iunlock(struct inode *ip); +void iincref(struct inode *ip);  void iput(struct inode *ip); +struct inode * namei(char *path); @@ -14,6 +14,9 @@  struct inode inode[NINODE];  struct spinlock inode_table_lock; +uint rootdev = 1; + +// returns an inode with busy set and incremented reference count.  struct inode *  iget(uint dev, uint inum)  { @@ -54,15 +57,50 @@ iget(uint dev, uint inum)    nip->nlink = dip->nlink;    nip->size = dip->size;    memmove(nip->addrs, dip->addrs, sizeof(nip->addrs)); -  cprintf("bn %d off %d\n", inum / IPB + 2, (unsigned)dip - (unsigned)bp->data);    brelse(bp);    return nip;  }  void +ilock(struct inode *ip) +{ +  if(ip->count < 1) +    panic("ilock"); + +  acquire(&inode_table_lock); + +  while(ip->busy) +    sleep(ip, &inode_table_lock); +  ip->busy = 1; + +  release(&inode_table_lock); +} + +// caller is holding onto a reference to this inode, but no +// longer needs to examine or change it, so clear ip->busy. +void +iunlock(struct inode *ip) +{ +  if(ip->busy != 1) +    panic("iunlock"); + +  acquire(&inode_table_lock); + +  ip->busy = 0; +  wakeup(ip); + +  release(&inode_table_lock); +} + +// caller is releasing a reference to this inode. +// you must have the inode lock. +void  iput(struct inode *ip)  { +  if(ip->count < 1 || ip->busy != 1) +    panic("iput"); +    acquire(&inode_table_lock);    ip->count -= 1; @@ -71,3 +109,82 @@ iput(struct inode *ip)    release(&inode_table_lock);  } + +void +iincref(struct inode *ip) +{ +  acquire(&inode_table_lock); + +  ip->count += 1; + +  release(&inode_table_lock); +} + +uint +bmap(struct inode *ip, uint bn) +{ +  unsigned x; + +  if(bn >= NDIRECT) +    panic("bmap 1"); +  x = ip->addrs[bn]; +  if(x == 0) +    panic("bmap 2"); +  return x; +} + +struct inode * +namei(char *path) +{ +  struct inode *dp; +  char *cp = path; +  uint off, dev; +  struct buf *bp; +  struct dirent *ep; +  int i; +  unsigned ninum; + +  dp = iget(rootdev, 1); + +  while(*cp == '/') +    cp++; + +  while(1){ +    if(*cp == '\0') +      return dp; + +    if(dp->type != T_DIR){ +      iput(dp); +      return 0; +    } + +    for(off = 0; off < dp->size; off += 512){ +      bp = bread(dp->dev, bmap(dp, off / 512)); +      for(ep = (struct dirent *) bp->data; +          ep < (struct dirent *) (bp->data + 512); +          ep++){ +        if(ep->inum == 0)  +          continue; +        for(i = 0; i < DIRSIZ && cp[i] != '/' && cp[i]; i++) +          if(cp[i] != ep->name[i]) +            break; +        if((cp[i] == '\0' || cp[i] == '/') && (i >= DIRSIZ || ep->name[i] == '\0')){ +          ninum = ep->inum; +          brelse(bp); +          cp += i; +          goto found; +        } +      } +      brelse(bp); +    } +    iput(dp); +    return 0; + +  found: +    dev = dp->dev; +    iput(dp); +    dp = iget(dev, ninum); +    while(*cp == '/') +      cp++; +  } +} @@ -21,8 +21,10 @@ struct dinode {  #define IPB (512 / sizeof(struct dinode)) +#define DIRSIZ 14 +  struct dirent {    ushort inum; -  char name[14]; +  char name[DIRSIZ];  }; @@ -10,3 +10,5 @@ struct inode {    uint size;    uint addrs[NDIRECT];  }; + +extern uint rootdev; @@ -24,7 +24,7 @@ ushort  xshort(ushort x)  {    ushort y; -  uchar *a = &y; +  uchar *a = (uchar *) &y;    a[0] = x;    a[1] = x >> 8;    return y; @@ -34,7 +34,7 @@ uint  xint(uint x)  {    uint y; -  uchar *a = &y; +  uchar *a = (uchar *) &y;    a[0] = x;    a[1] = x >> 8;    a[2] = x >> 16; @@ -47,16 +47,21 @@ main(int argc, char *argv[])    int i;    struct dinode din;    char dbuf[512]; +  uint bn;    if(argc != 2){      fprintf(stderr, "Usage: mkfs fs.img\n");      exit(1);    } -  if(sizeof(struct dinode) * IPB != 512){ +  if((512 % sizeof(struct dinode)) != 0){      fprintf(stderr, "sizeof(dinode) must divide 512\n");      exit(1);    } +  if((512 % sizeof(struct dirent)) != 0){ +    fprintf(stderr, "sizeof(dirent) must divide 512\n"); +    exit(1); +  }    fd = open(argv[1], O_RDWR|O_CREAT|O_TRUNC, 0666);    if(fd < 0){ @@ -78,7 +83,8 @@ main(int argc, char *argv[])    din.type = xshort(T_DIR);    din.nlink = xshort(2);    din.size = xint(512); -  din.addrs[0] = xint(freeblock++); +  bn = freeblock++; +  din.addrs[0] = xint(bn);    winode(1, &din);    bzero(dbuf, sizeof(dbuf)); @@ -86,7 +92,7 @@ main(int argc, char *argv[])    strcpy(((struct dirent *) dbuf)[0].name, ".");    ((struct dirent *) dbuf)[1].inum = xshort(1);    strcpy(((struct dirent *) dbuf)[1].name, ".."); -  wsect(din.addrs[0], dbuf); +  wsect(bn, dbuf);    exit(0);  } @@ -243,11 +243,21 @@ sys_block(void)    }    ip = iget(1, 1); -  cprintf("%d %d %d %d %d %d %d %d\n", +  cprintf("iget 1: %d %d %d %d %d %d %d %d\n",            ip->dev, ip->inum, ip->count, ip->busy,            ip->type, ip->nlink, ip->size, ip->addrs[0]);    iput(ip); +  ip = namei(".././//./../"); +  if(ip){ +    cprintf("namei: %d %d %d %d %d %d %d %d\n", +            ip->dev, ip->inum, ip->count, ip->busy, +            ip->type, ip->nlink, ip->size, ip->addrs[0]); +    iput(ip); +  } else { +    cprintf("namei failed\n"); +  } +    return 0;  } | 
