diff options
| author | rtm <rtm> | 2006-08-13 12:22:44 +0000 | 
|---|---|---|
| committer | rtm <rtm> | 2006-08-13 12:22:44 +0000 | 
| commit | 211ff0c67ea6737853cf932313cf4e27cc15f55c (patch) | |
| tree | e28f2e9f39ddc226203c16e955337216bbdab7f5 | |
| parent | c372e8dc348e4bb30aae7642db92ecbeedbc83ab (diff) | |
| download | xv6-labs-211ff0c67ea6737853cf932313cf4e27cc15f55c.tar.gz xv6-labs-211ff0c67ea6737853cf932313cf4e27cc15f55c.tar.bz2 xv6-labs-211ff0c67ea6737853cf932313cf4e27cc15f55c.zip | |
namei returns locked parent dir inode for create / unlink
don't hold fd table lock across idecref() (latter does block i/o)
idecref calls iput() in case last ref -> freeing inode
dir size is 512 * # blocks, so readi/writei &c work
unlink deletes dirent even if ip->nlink > 0
| -rw-r--r-- | Notes | 15 | ||||
| -rw-r--r-- | defs.h | 2 | ||||
| -rw-r--r-- | fd.c | 20 | ||||
| -rw-r--r-- | fs.c | 153 | ||||
| -rw-r--r-- | fsvar.h | 4 | ||||
| -rw-r--r-- | syscall.c | 6 | ||||
| -rw-r--r-- | usertests.c | 2 | 
7 files changed, 120 insertions, 82 deletions
| @@ -365,3 +365,18 @@ two bugs in unlink: don't just return if nlink > 0,    and search for name, not inum  is there a create/create race for same file name?    resulting in two entries w/ same name in directory? + +namei +  return just inode +  return offset in dir where found, w/ dir locked, for unlink +  return dir locked, for mknod + +is the offset alone useful? how do I read/write it? + +test: one process unlinks a file while another links to it +test: simultaneous create of same file +test: one process opens a file while another deletes it + +oy, mkfs wants dir size to be last written entry, but i +  want it to be nblocks*512 +  maybe fix kernel code to handle former @@ -116,7 +116,7 @@ void ilock(struct inode *ip);  void iunlock(struct inode *ip);  void idecref(struct inode *ip);  void iput(struct inode *ip); -struct inode * namei(char *path, uint *); +struct inode * namei(char *path, int, uint *);  void stati(struct inode *ip, struct stat *st);  int readi(struct inode *ip, char *xdst, uint off, uint n);  int writei(struct inode *ip, char *addr, uint off, uint n); @@ -108,18 +108,22 @@ fd_close(struct fd *fd)      panic("fd_close");    if(--fd->ref == 0){ -    if(fd->type == FD_PIPE){ -      pipe_close(fd->pipe, fd->writeable); -    } else if(fd->type == FD_FILE){ -      idecref(fd->ip); +    struct fd dummy = *fd; + +    fd->ref = 0; +    fd->type = FD_CLOSED; +    release(&fd_table_lock); + +    if(dummy.type == FD_PIPE){ +      pipe_close(dummy.pipe, dummy.writeable); +    } else if(dummy.type == FD_FILE){ +      idecref(dummy.ip);      } else {        panic("fd_close");      } -    fd->ref = 0; -    fd->type = FD_CLOSED; +  } else { +    release(&fd_table_lock);    } -   -  release(&fd_table_lock);  }  int @@ -286,14 +286,8 @@ iput(struct inode *ip)  void  idecref(struct inode *ip)  { -  acquire(&inode_table_lock); - -  if(ip->count < 1) -    panic("idecref"); - -  ip->count -= 1; - -  release(&inode_table_lock); +  ilock(ip); +  iput(ip);  }  void @@ -376,34 +370,37 @@ writei(struct inode *ip, char *addr, uint off, uint n)    }  } +// look up a path name, in one of three modes. +// NAMEI_LOOKUP: return locked target inode. +// NAMEI_CREATE: return locked parent inode. +//   but return 0 if name does exist. +// NAMEI_DELETE: return locked parent inode, offset of dirent in *ret_off. +//   return 0 if name doesn't exist.  struct inode * -namei(char *path, uint *ret_pinum) +namei(char *path, int mode, uint *ret_off)  {    struct inode *dp; -  char *cp = path; +  char *cp = path, *cp1;    uint off, dev;    struct buf *bp;    struct dirent *ep; -  int i; +  int i, atend;    unsigned ninum; -  unsigned pinum; - +      dp = iget(rootdev, 1); -  pinum = dp->inum;    while(*cp == '/')      cp++;    while(1){ -    if(*cp == '\0') { -      if (ret_pinum) -	*ret_pinum = pinum; -      return dp; +    if(*cp == '\0'){ +      if(mode == NAMEI_LOOKUP) +        return dp; +      iput(dp); +      return 0;      }      if(dp->type != T_DIR){ -      if (ret_pinum) -	*ret_pinum = pinum;        iput(dp);        return 0;      } @@ -419,6 +416,7 @@ namei(char *path, uint *ret_pinum)            if(cp[i] != ep->name[i])              break;          if((cp[i] == '\0' || cp[i] == '/') && (i >= DIRSIZ || ep->name[i] == '\0')){ +          off += (uchar*)ep - bp->data;            ninum = ep->inum;            brelse(bp);            cp += i; @@ -427,14 +425,22 @@ namei(char *path, uint *ret_pinum)        }        brelse(bp);      } +    atend = 1; +    for(cp1 = cp; *cp1; cp1++) +      if(*cp1 == '/') +        atend = 0; +    if(mode == NAMEI_CREATE && atend) +      return dp; +      iput(dp); -    if (ret_pinum) -      *ret_pinum = pinum;      return 0;    found: +    if(mode == NAMEI_DELETE && *cp == '\0'){ +      *ret_off = off; +      return dp; +    }      dev = dp->dev; -    pinum = dp->inum;      iput(dp);      dp = iget(dev, ninum);      if(dp->type == 0 || dp->nlink < 1) @@ -453,6 +459,9 @@ wdir(struct inode *dp, char *name, uint ino)    int i;    int lb; +  if(dp->size % BSIZE) +    dp->size += (BSIZE - dp->size % BSIZE); +    for(off = 0; off < dp->size; off += BSIZE) {      bp = bread(dp->dev, bmap(dp, off / BSIZE));      for(ep = (struct dirent *) bp->data; @@ -469,14 +478,16 @@ wdir(struct inode *dp, char *name, uint ino)    }    dp->addrs[lb] = balloc(dp->dev);    bp = bread(dp->dev, dp->addrs[lb]); +  memset(bp->data, 0, BSIZE);    ep = (struct dirent *) (bp->data); +  dp->size += BSIZE; +   found:    ep->inum = ino;    for(i = 0; i < DIRSIZ && name[i]; i++)      ep->name[i] = name[i];    for( ; i < DIRSIZ; i++)      ep->name[i] = '\0'; -  dp->size += sizeof(struct dirent);    bwrite (bp, bmap(dp, off/BSIZE));   // write directory block    brelse(bp);    iupdate(dp); @@ -486,15 +497,12 @@ struct inode *  mknod(char *cp, short type, short major, short minor)  {    struct inode *ip, *dp; -  uint pinum = 0;    cprintf("mknod: %s %d %d %d\n", cp, type, major, minor); -  if ((ip = namei(cp, &pinum)) != 0) { -    iput(ip); +  if ((dp = namei(cp, NAMEI_CREATE, 0)) == 0)      return 0; -  } -  dp = iget(rootdev, pinum); +    ip = ialloc(dp->dev, type);    if (ip == 0) {      iput(dp); @@ -515,74 +523,81 @@ mknod(char *cp, short type, short major, short minor)  int  unlink(char *cp)  { -  struct inode *ip; -  struct inode *dp; -  struct dirent *ep = 0; -  int off; -  struct buf *bp = 0; -  uint pinum; - +  struct inode *ip, *dp; +  struct dirent de; +  uint off, inum, cc; -  if ((ip = namei(cp, &pinum)) == 0) { +  cprintf("unlink(%s)\n", cp); + +  if ((dp = namei(cp, NAMEI_DELETE, &off)) == 0) {      cprintf("unlink(%s) it doesn't exist\n", cp);      return -1;    } -  ip->nlink--; -  if (ip->nlink > 0) { -    iput(ip); -    return 0; +  if((cc = readi(dp, (char*)&de, off, sizeof(de))) != sizeof(de) || +     de.inum == 0){ +    cprintf("off %d dp->size %d cc %d de.inum %d", +            off, dp->size, cc, de.inum); +    panic("unlink no entry");    } +  inum = de.inum; +  cprintf("dinum %d off %d de %s/%d\n",  +          dp->inum, off, de.name, de.inum); -  dp = iget(rootdev, pinum); -  for(off = 0; off < dp->size; off += BSIZE) { -    bp = bread(dp->dev, bmap(dp, off / BSIZE)); -    for(ep = (struct dirent *) bp->data; -	ep < (struct dirent *) (bp->data + BSIZE); -	ep++){ -      if(ep->inum == ip->inum) { -	goto found; -      } -    } -    brelse(bp); -  } -  panic("unlink: entry doesn't exist\n"); +  memset(&de, 0, sizeof(de)); +  if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) +    panic("unlink dir write"); - found: -  ep->inum = 0; -  memset(ep->name, '\0', DIRSIZ); -  bwrite (bp, bmap(dp, off/BSIZE));   // write directory block -  brelse(bp); -  dp->size -= sizeof(struct dirent); -  iupdate (dp); +  iupdate(dp);    iput(dp); + +  ip = iget(dp->dev, inum); +  if(ip == 0) +    panic("unlink no inode"); + +  ip->nlink--; + +  iupdate(ip);    iput(ip); +    return 0;  }  int  link(char *name1, char *name2)  { -  struct inode *ip, *dp, *xip; -  uint pinum = 0; +  struct inode *ip, *dp;    cprintf("link(%s, %s)\n", name1, name2); -  if ((xip = namei(name2, &pinum)) != 0) { -    cprintf("  failed %s exists\n", name2); -    iput(xip); +  if ((ip = namei(name1, NAMEI_LOOKUP, 0)) == 0){ +    cprintf("  failed %s does not exist\n", name1); +    return -1; +  } +  if(ip->type == T_DIR){ +    cprintf("  failed %s is a dir\n", name1); +    iput(ip);      return -1;    } -  if ((ip = namei(name1, &pinum)) == 0){ -    cprintf("  failed %s does not exist\n", name1); +  iunlock(ip); + +  if ((dp = namei(name2, NAMEI_CREATE, 0)) == 0) { +    cprintf("  failed %s exists\n", name2); +    idecref(ip); +    return -1; +  } +  if(dp->dev != ip->dev){ +    cprintf("  cross-device link\n"); +    idecref(ip); +    iput(dp);      return -1;    } +  ilock(ip);    ip->nlink += 1;    iupdate (ip); -  dp = iget(rootdev, pinum);    wdir(dp, name2, ip->inum);    iput(dp);    iput(ip); @@ -14,3 +14,7 @@ struct inode {  };  extern uint rootdev; + +#define NAMEI_LOOKUP 1 +#define NAMEI_CREATE 2 +#define NAMEI_DELETE 3 @@ -228,7 +228,7 @@ sys_open(void)      return -1;    if((l = checkstring(arg0)) < 0)      return -1; -  if((ip = namei(cp->mem + arg0, 0)) == 0) { +  if((ip = namei(cp->mem + arg0, NAMEI_LOOKUP, 0)) == 0) {      if (arg1 & O_CREATE) {        if (l >= DIRSIZ)  	return -1; @@ -356,7 +356,7 @@ sys_exec(void)      return -1;    if(checkstring(arg0) < 0)      return -1; -  ip = namei(cp->mem + arg0, 0); +  ip = namei(cp->mem + arg0, NAMEI_LOOKUP, 0);    if(ip == 0)      return -1; @@ -494,7 +494,7 @@ sys_block(void)            ip->type, ip->nlink, ip->size, ip->addrs[0]);    iput(ip); -  ip = namei(".././//./../usertests", 0); +  ip = namei(".././//./../usertests", NAMEI_LOOKUP, 0);    if(ip){      cprintf("namei(usertests): %d %d %d %d %d %d %d %d\n",              ip->dev, ip->inum, ip->count, ip->busy, diff --git a/usertests.c b/usertests.c index 2d6b065..c3e9113 100644 --- a/usertests.c +++ b/usertests.c @@ -231,7 +231,7 @@ void  createdelete()  {    int pid, i, fd; -  int n = 10; // for now, fit in one directory block +  int n = 20;    char name[32];    pid = fork(); | 
