diff options
| -rw-r--r-- | defs.h | 6 | ||||
| -rw-r--r-- | fs.c | 170 | ||||
| -rw-r--r-- | proc.c | 13 | ||||
| -rw-r--r-- | sysfile.c | 67 | 
4 files changed, 135 insertions, 121 deletions
@@ -128,12 +128,14 @@ void itrunc(struct inode*);  void idecref(struct inode*);  struct inode* iincref(struct inode*);  void iput(struct inode*); -struct inode* namei(char*, int, uint*, char**, struct inode**); +struct inode* namei(char*); +struct inode* nameiparent(char*, char**, int*);  void stati(struct inode*, struct stat*);  int readi(struct inode*, char*, uint, uint);  int writei(struct inode*, char*, uint, uint);  struct inode* mknod(char*, short, short, short); -struct inode* mknod1(struct inode*, char*, short, short, short); +struct inode* dircreat(struct inode*, char*, int, short, short, short); +int dirlookup(struct inode*, char*, int, uint*, uint*);  int unlink(char*);  void iupdate(struct inode*);  int link(char*, char*); @@ -465,7 +465,7 @@ writei(struct inode *ip, char *src, uint off, uint n)  //   set *poff to the byte offset of the directory entry  //   set *pinum to the inode number  //   return 0. -static int +int  dirlookup(struct inode *dp, char *name, int namelen, uint *poff, uint *pinum)  {    uint off; @@ -485,8 +485,10 @@ dirlookup(struct inode *dp, char *name, int namelen, uint *poff, uint *pinum)        if(memcmp(name, de->name, namelen) == 0 &&           (namelen == DIRSIZ || de->name[namelen]== 0)){          // entry matches path element -        *poff = off + (uchar*)de - bp->data; -        *pinum = de->inum; +        if(poff) +          *poff = off + (uchar*)de - bp->data; +        if(pinum) +          *pinum = de->inum;          brelse(bp);          return 0;        } @@ -499,9 +501,9 @@ dirlookup(struct inode *dp, char *name, int namelen, uint *poff, uint *pinum)  // Write a new directory entry (name, ino) into the directory dp.  // Caller must have locked dp.  void -dirwrite(struct inode *dp, char *name, uint ino) +dirwrite(struct inode *dp, char *name, int namelen, uint ino)  { -  int i, off; +  int off;    struct dirent de;    // Look for an empty dirent. @@ -513,15 +515,37 @@ dirwrite(struct inode *dp, char *name, uint ino)    }    de.inum = ino; -  for(i = 0; i < DIRSIZ && name[i]; i++) -    de.name[i] = name[i]; -  for(; i < DIRSIZ; i++) -    de.name[i] = '\0'; +  if(namelen > DIRSIZ) +    namelen = DIRSIZ; +  memmove(de.name, name, namelen); +  memset(de.name+namelen, 0, DIRSIZ-namelen);    if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de))      panic("dirwrite");  } +// Create a new inode named name inside dp +// and return its locked inode structure. +// If name already exists, return 0. +struct inode* +dircreat(struct inode *dp, char *name, int namelen, short type, short major, short minor) +{ +  struct inode *ip; + +  ip = ialloc(dp->dev, type); +  if(ip == 0) +    return 0; +  ip->major = major; +  ip->minor = minor; +  ip->size = 0; +  ip->nlink = 1; +  iupdate(ip); + +  dirwrite(dp, name, namelen, ip->inum); + +  return ip; +} +  // Paths  // Skip over the next path element in path,  @@ -564,21 +588,13 @@ skipelem(char *path, char **name, int *len)  // NAMEI_DELETE: return locked parent inode, offset of dirent in *ret_off.  //   return 0 if name doesn't exist.  struct inode* -namei(char *path, int mode, uint *ret_off, -      char **ret_last, struct inode **ret_ip) +_namei(char *path, int parent, char **pname, int *pnamelen)  {    struct inode *dp;    char *name;    int namelen;    uint off, dev, inum; -  if(ret_off) -    *ret_off = 0xffffffff; -  if(ret_last) -    *ret_last = 0; -  if(ret_ip) -    *ret_ip = 0; -    if(*path == '/')      dp = igetroot();    else { @@ -593,83 +609,63 @@ namei(char *path, int mode, uint *ret_off,      if(dp->type != T_DIR)        goto fail; - -    if(dirlookup(dp, name, namelen, &off, &inum) < 0){ -      if(mode == NAMEI_CREATE && *path == '\0'){ -        *ret_last = name; -        return dp; -      } -      goto fail; -    } - -    if(mode == NAMEI_DELETE && *path == '\0'){ -      // can't unlink . and .. -      if((namelen == 1 && memcmp(name, ".", 1) == 0) || -         (namelen == 2 && memcmp(name, "..", 2) == 0)){ -        goto fail; -      } -      *ret_off = off; +     +    if(parent && *path == '\0'){ +      // Stop one level early. +      *pname = name; +      *pnamelen = namelen;        return dp;      } +    if(dirlookup(dp, name, namelen, &off, &inum) < 0) +      goto fail; +      dev = dp->dev;      iput(dp);      dp = iget(dev, inum);      if(dp->type == 0 || dp->nlink < 1)        panic("namei");    } - -  if(mode == NAMEI_LOOKUP) -    return dp; -  if(mode == NAMEI_CREATE && ret_ip){ -    *ret_ip = dp; +  if(parent)      return 0; -  } -  goto fail; +  return dp;  fail:    iput(dp);    return 0;  } -// Create the path and return its locked inode structure. -// If cp already exists, return 0.  struct inode* -mknod(char *path, short type, short major, short minor) +namei(char *path)  { -  struct inode *ip, *dp; -  char *last; - -  if((dp = namei(path, NAMEI_CREATE, 0, &last, 0)) == 0) -    return 0; - -  ip = mknod1(dp, last, type, major, minor); - -  iput(dp); - -  return ip; +  return _namei(path, 0, 0, 0);  } -// Create a new inode named name inside dp -// and return its locked inode structure. -// If name already exists, return 0.  struct inode* -mknod1(struct inode *dp, char *name, short type, short major, short minor) +nameiparent(char *path, char **name, int *namelen)  { -  struct inode *ip; +  return _namei(path, 1, name, namelen); +} -  ip = ialloc(dp->dev, type); -  if(ip == 0) -    return 0; -  ip->major = major; -  ip->minor = minor; -  ip->size = 0; -  ip->nlink = 1; -  iupdate(ip);  // write new inode to disk -  dirwrite(dp, name, ip->inum); +// Create the path and return its locked inode structure. +// If cp already exists, return 0. +struct inode* +mknod(char *path, short type, short major, short minor) +{ +  struct inode *ip, *dp; +  char *name; +  int namelen; +  if((dp = nameiparent(path, &name, &namelen)) == 0) +    return 0; +  if(dirlookup(dp, name, namelen, 0, 0) >= 0){ +    iput(dp); +    return 0; +  } +  ip = dircreat(dp, name, namelen, type, major, minor); +  iput(dp);    return ip;  } @@ -680,12 +676,15 @@ unlink(char *path)    struct inode *ip, *dp;    struct dirent de;    uint off, inum, dev; +  char *name; +  int namelen; -  dp = namei(path, NAMEI_DELETE, &off, 0, 0); -  if(dp == 0) +  if((dp = nameiparent(path, &name, &namelen)) == 0)      return -1; - -  dev = dp->dev; +  if(dirlookup(dp, name, namelen, &off, 0) < 0){ +    iput(dp); +    return -1; +  }    if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de) || de.inum == 0)      panic("unlink no entry"); @@ -702,16 +701,13 @@ unlink(char *path)    if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de))      panic("unlink dir write"); -  iupdate(dp); +  dev = dp->dev;    iput(dp);    ip = iget(dev, inum); -    if(ip->nlink < 1)      panic("unlink nlink < 1"); -    ip->nlink--; -    iupdate(ip);    iput(ip); @@ -720,21 +716,26 @@ unlink(char *path)  // Create the path new as a link to the same inode as old.  int -link(char *name1, char *name2) +link(char *old, char *new)  {    struct inode *ip, *dp; -  char *last; +  char *name; +  int namelen; -  if((ip = namei(name1, NAMEI_LOOKUP, 0, 0, 0)) == 0) +  if((ip = namei(old)) == 0)      return -1;    if(ip->type == T_DIR){      iput(ip);      return -1;    } -    iunlock(ip); - -  if((dp = namei(name2, NAMEI_CREATE, 0, &last, 0)) == 0) { +   +  if((dp = nameiparent(new, &name, &namelen)) == 0){ +    idecref(ip); +    return -1; +  } +  if(dirlookup(dp, name, namelen, 0, 0) >= 0){ +    iput(dp);      idecref(ip);      return -1;    } @@ -744,11 +745,12 @@ link(char *name1, char *name2)      return -1;    } +  // LOCKING ERROR HERE!  TWO LOCKS HELD AT ONCE.    ilock(ip);    ip->nlink++;    iupdate(ip); -  dirwrite(dp, last, ip->inum); +  dirwrite(dp, name, namelen, ip->inum);    iput(dp);    iput(ip); @@ -203,7 +203,6 @@ scheduler(void)  void  sched(void)  { -    if(cp->state == RUNNING)      panic("sched running");    if(!holding(&proc_table_lock)) @@ -219,7 +218,6 @@ sched(void)  void  yield(void)  { -    acquire(&proc_table_lock);    cp->state = RUNNABLE;    sched(); @@ -422,9 +420,10 @@ procdump(void)    [RUNNING]   "run   ",    [ZOMBIE]    "zombie"    }; -  int i; +  int i, j;    struct proc *p;    char *state; +  uint pc[10];    for(i = 0; i < NPROC; i++) {      p = &proc[i]; @@ -434,7 +433,13 @@ procdump(void)        state = states[p->state];      else        state = "???"; -    cprintf("%d %s %s\n", p->pid, state, p->name); +    cprintf("%d %s %s", p->pid, state, p->name); +    if(p->state == SLEEPING) { +      getcallerpcs((uint*)p->jmpbuf.ebp+2, pc); +      for(j=0; j<10 && pc[j] != 0; j++) +        cprintf(" %p", pc[j]); +    } +    cprintf("\n");    }  } @@ -115,34 +115,41 @@ int  sys_open(void)  {    struct inode *ip, *dp; -  char *path; +  char *path, *name; +  int namelen;    int omode; -  int fd; +  int fd, dev; +  uint inum;    struct file *f; -  char *last;    if(argstr(0, &path) < 0 || argint(1, &omode) < 0)      return -1; -  if(omode & O_CREATE){ -    dp = namei(path, NAMEI_CREATE, 0, &last, &ip); -    if(dp){ -      ip = mknod1(dp, last, T_FILE, 0, 0); -      iput(dp); -      if(ip == 0) -        return -1; -    } else if(ip == 0){ +  switch(omode & O_CREATE){ +  default: +  case 0: // regular open +    if((ip = namei(path)) == 0)        return -1; -    } else if(ip->type == T_DIR){ -      iput(ip); +    break; +   +  case O_CREATE: +    if((dp = nameiparent(path, &name, &namelen)) == 0)        return -1; +    if(dirlookup(dp, name, namelen, 0, &inum) >= 0){ +      dev = dp->dev; +      iput(dp); +      ip = iget(dev, inum); +    }else{ +      if((ip = dircreat(dp, name, namelen, T_FILE, 0, 0)) == 0){ +        iput(dp); +        return -1; +      } +      iput(dp);      } -  } else { -    ip = namei(path, NAMEI_LOOKUP, 0, 0, 0); -    if(ip == 0) -      return -1; +    break;    } -  if(ip->type == T_DIR && ((omode & O_RDWR) || (omode & O_WRONLY))){ + +  if(ip->type == T_DIR && (omode & (O_RDWR|O_WRONLY|O_CREATE))){      iput(ip);      return -1;    } @@ -201,18 +208,22 @@ sys_mkdir(void)  {    struct inode *nip;    struct inode *dp; -  char *path; +  char *name, *path;    struct dirent de; -  char *last; +  int namelen;    if(argstr(0, &path) < 0)      return -1; -  dp = namei(path, NAMEI_CREATE, 0, &last, 0); +  dp = nameiparent(path, &name, &namelen);    if(dp == 0)      return -1; +  if(dirlookup(dp, name, namelen, 0, 0) >= 0){ +    iput(dp); +    return -1; +  } -  nip = mknod1(dp, last, T_DIR, 0, 0); +  nip = dircreat(dp, name, namelen, T_DIR, 0, 0);    if(nip == 0){      iput(dp);      return -1; @@ -245,22 +256,17 @@ sys_chdir(void)    if(argstr(0, &path) < 0)      return -1; -  if((ip = namei(path, NAMEI_LOOKUP, 0, 0, 0)) == 0) +  if((ip = namei(path)) == 0)      return -1; -  if(ip == cp->cwd) { -    iput(ip); -    return 0; -  } -    if(ip->type != T_DIR) {      iput(ip);      return -1;    } +  iunlock(ip);    idecref(cp->cwd);    cp->cwd = ip; -  iunlock(cp->cwd);    return 0;  } @@ -324,8 +330,7 @@ sys_exec(void)    if(argstr(0, &path) < 0 || argint(1, (int*)&argv) < 0)      return -1; -  ip = namei(path, NAMEI_LOOKUP, 0, 0, 0); -  if(ip == 0) +  if((ip = namei(path)) == 0)      return -1;    if(readi(ip, (char*)&elf, 0, sizeof(elf)) < sizeof(elf))  | 
