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
This commit is contained in:
		
							parent
							
								
									c372e8dc34
								
							
						
					
					
						commit
						211ff0c67e
					
				
					 7 changed files with 122 additions and 84 deletions
				
			
		
							
								
								
									
										15
									
								
								Notes
									
										
									
									
									
								
							
							
						
						
									
										15
									
								
								Notes
									
										
									
									
									
								
							|  | @ -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 | ||||
|  |  | |||
							
								
								
									
										2
									
								
								defs.h
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								defs.h
									
										
									
									
									
								
							|  | @ -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); | ||||
|  |  | |||
							
								
								
									
										20
									
								
								fd.c
									
										
									
									
									
								
							
							
						
						
									
										20
									
								
								fd.c
									
										
									
									
									
								
							|  | @ -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 | ||||
|  |  | |||
							
								
								
									
										157
									
								
								fs.c
									
										
									
									
									
								
							
							
						
						
									
										157
									
								
								fs.c
									
										
									
									
									
								
							|  | @ -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); | ||||
|     return -1; | ||||
|   } | ||||
| 
 | ||||
|   if ((ip = namei(name1, &pinum)) == 0){ | ||||
|   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; | ||||
|   } | ||||
| 
 | ||||
|   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); | ||||
|  |  | |||
							
								
								
									
										4
									
								
								fsvar.h
									
										
									
									
									
								
							
							
						
						
									
										4
									
								
								fsvar.h
									
										
									
									
									
								
							|  | @ -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, | ||||
|  |  | |||
|  | @ -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(); | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue