avoid deadlock by calling begin_trans() before locking any inodes
This commit is contained in:
		
							parent
							
								
									c95ce31c59
								
							
						
					
					
						commit
						5053dd6a6d
					
				
					 5 changed files with 66 additions and 15 deletions
				
			
		
							
								
								
									
										6
									
								
								file.c
									
										
									
									
									
								
							
							
						
						
									
										6
									
								
								file.c
									
										
									
									
									
								
							|  | @ -118,7 +118,6 @@ filewrite(struct file *f, char *addr, int n) | ||||||
|   if(f->type == FD_PIPE) |   if(f->type == FD_PIPE) | ||||||
|     return pipewrite(f->pipe, addr, n); |     return pipewrite(f->pipe, addr, n); | ||||||
|   if(f->type == FD_INODE){ |   if(f->type == FD_INODE){ | ||||||
|     ilock(f->ip); |  | ||||||
|     // write a few blocks at a time to avoid exceeding
 |     // write a few blocks at a time to avoid exceeding
 | ||||||
|     // the maximum log transaction size, including
 |     // the maximum log transaction size, including
 | ||||||
|     // i-node, indirect block, allocation blocks,
 |     // i-node, indirect block, allocation blocks,
 | ||||||
|  | @ -131,9 +130,13 @@ filewrite(struct file *f, char *addr, int n) | ||||||
|       int n1 = n - i; |       int n1 = n - i; | ||||||
|       if(n1 > max) |       if(n1 > max) | ||||||
|         n1 = max; |         n1 = max; | ||||||
|  | 
 | ||||||
|       begin_trans(); |       begin_trans(); | ||||||
|  |       ilock(f->ip); | ||||||
|       r = writei(f->ip, addr + i, f->off, n1); |       r = writei(f->ip, addr + i, f->off, n1); | ||||||
|  |       iunlock(f->ip); | ||||||
|       commit_trans(); |       commit_trans(); | ||||||
|  | 
 | ||||||
|       if(r < 0) |       if(r < 0) | ||||||
|         break; |         break; | ||||||
|       if(r != n1) |       if(r != n1) | ||||||
|  | @ -141,7 +144,6 @@ filewrite(struct file *f, char *addr, int n) | ||||||
|       f->off += r; |       f->off += r; | ||||||
|       i += r; |       i += r; | ||||||
|     } |     } | ||||||
|     iunlock(f->ip); |  | ||||||
|     return i == n ? n : -1; |     return i == n ? n : -1; | ||||||
|   } |   } | ||||||
|   panic("filewrite"); |   panic("filewrite"); | ||||||
|  |  | ||||||
							
								
								
									
										7
									
								
								fs.c
									
										
									
									
									
								
							
							
						
						
									
										7
									
								
								fs.c
									
										
									
									
									
								
							|  | @ -43,13 +43,13 @@ bzero(int dev, int bno) | ||||||
|    |    | ||||||
|   bp = bread(dev, bno); |   bp = bread(dev, bno); | ||||||
|   memset(bp->data, 0, BSIZE); |   memset(bp->data, 0, BSIZE); | ||||||
|   bwrite(bp); |   log_write(bp); | ||||||
|   brelse(bp); |   brelse(bp); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Blocks. 
 | // Blocks. 
 | ||||||
| 
 | 
 | ||||||
| // Allocate a disk block.
 | // Allocate a zeroed disk block.
 | ||||||
| static uint | static uint | ||||||
| balloc(uint dev) | balloc(uint dev) | ||||||
| { | { | ||||||
|  | @ -67,6 +67,7 @@ balloc(uint dev) | ||||||
|         bp->data[bi/8] |= m;  // Mark block in use on disk.
 |         bp->data[bi/8] |= m;  // Mark block in use on disk.
 | ||||||
|         log_write(bp); |         log_write(bp); | ||||||
|         brelse(bp); |         brelse(bp); | ||||||
|  |         bzero(dev, b + bi); | ||||||
|         return b + bi; |         return b + bi; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  | @ -83,8 +84,6 @@ bfree(int dev, uint b) | ||||||
|   struct superblock sb; |   struct superblock sb; | ||||||
|   int bi, m; |   int bi, m; | ||||||
| 
 | 
 | ||||||
|   bzero(dev, b); |  | ||||||
| 
 |  | ||||||
|   readsb(dev, &sb); |   readsb(dev, &sb); | ||||||
|   bp = bread(dev, BBLOCK(b, sb.ninodes)); |   bp = bread(dev, BBLOCK(b, sb.ninodes)); | ||||||
|   bi = b % BPB; |   bi = b % BPB; | ||||||
|  |  | ||||||
							
								
								
									
										4
									
								
								log.c
									
										
									
									
									
								
							
							
						
						
									
										4
									
								
								log.c
									
										
									
									
									
								
							|  | @ -124,9 +124,9 @@ static void | ||||||
| recover_from_log(void) | recover_from_log(void) | ||||||
| { | { | ||||||
|   read_head();       |   read_head();       | ||||||
|   install_trans();  // Install all transactions till head
 |   install_trans(); // if committed, copy from log to disk
 | ||||||
|   log.lh.n = 0; |   log.lh.n = 0; | ||||||
|   write_head();     //  Reclaim log
 |   write_head(); // clear the log
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void | void | ||||||
|  |  | ||||||
							
								
								
									
										14
									
								
								sysfile.c
									
										
									
									
									
								
							
							
						
						
									
										14
									
								
								sysfile.c
									
										
									
									
									
								
							|  | @ -116,14 +116,16 @@ sys_link(void) | ||||||
|     return -1; |     return -1; | ||||||
|   if((ip = namei(old)) == 0) |   if((ip = namei(old)) == 0) | ||||||
|     return -1; |     return -1; | ||||||
|  | 
 | ||||||
|  |   begin_trans(); | ||||||
|  | 
 | ||||||
|   ilock(ip); |   ilock(ip); | ||||||
|   if(ip->type == T_DIR){ |   if(ip->type == T_DIR){ | ||||||
|     iunlockput(ip); |     iunlockput(ip); | ||||||
|  |     commit_trans(); | ||||||
|     return -1; |     return -1; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   begin_trans(); |  | ||||||
| 
 |  | ||||||
|   ip->nlink++; |   ip->nlink++; | ||||||
|   iupdate(ip); |   iupdate(ip); | ||||||
|   iunlock(ip); |   iunlock(ip); | ||||||
|  | @ -180,16 +182,21 @@ sys_unlink(void) | ||||||
|     return -1; |     return -1; | ||||||
|   if((dp = nameiparent(path, name)) == 0) |   if((dp = nameiparent(path, name)) == 0) | ||||||
|     return -1; |     return -1; | ||||||
|  | 
 | ||||||
|  |   begin_trans(); | ||||||
|  | 
 | ||||||
|   ilock(dp); |   ilock(dp); | ||||||
| 
 | 
 | ||||||
|   // Cannot unlink "." or "..".
 |   // Cannot unlink "." or "..".
 | ||||||
|   if(namecmp(name, ".") == 0 || namecmp(name, "..") == 0){ |   if(namecmp(name, ".") == 0 || namecmp(name, "..") == 0){ | ||||||
|     iunlockput(dp); |     iunlockput(dp); | ||||||
|  |     commit_trans(); | ||||||
|     return -1; |     return -1; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   if((ip = dirlookup(dp, name, &off)) == 0){ |   if((ip = dirlookup(dp, name, &off)) == 0){ | ||||||
|     iunlockput(dp); |     iunlockput(dp); | ||||||
|  |     commit_trans(); | ||||||
|     return -1; |     return -1; | ||||||
|   } |   } | ||||||
|   ilock(ip); |   ilock(ip); | ||||||
|  | @ -199,11 +206,10 @@ sys_unlink(void) | ||||||
|   if(ip->type == T_DIR && !isdirempty(ip)){ |   if(ip->type == T_DIR && !isdirempty(ip)){ | ||||||
|     iunlockput(ip); |     iunlockput(ip); | ||||||
|     iunlockput(dp); |     iunlockput(dp); | ||||||
|  |     commit_trans(); | ||||||
|     return -1; |     return -1; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   begin_trans(); |  | ||||||
| 
 |  | ||||||
|   memset(&de, 0, sizeof(de)); |   memset(&de, 0, sizeof(de)); | ||||||
|   if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) |   if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) | ||||||
|     panic("unlink: writei"); |     panic("unlink: writei"); | ||||||
|  |  | ||||||
							
								
								
									
										50
									
								
								usertests.c
									
										
									
									
									
								
							
							
						
						
									
										50
									
								
								usertests.c
									
										
									
									
									
								
							|  | @ -364,6 +364,8 @@ sharedfd(void) | ||||||
|   int fd, pid, i, n, nc, np; |   int fd, pid, i, n, nc, np; | ||||||
|   char buf[10]; |   char buf[10]; | ||||||
| 
 | 
 | ||||||
|  |   printf(1, "sharedfd test\n"); | ||||||
|  | 
 | ||||||
|   unlink("sharedfd"); |   unlink("sharedfd"); | ||||||
|   fd = open("sharedfd", O_CREATE|O_RDWR); |   fd = open("sharedfd", O_CREATE|O_RDWR); | ||||||
|   if(fd < 0){ |   if(fd < 0){ | ||||||
|  | @ -655,7 +657,7 @@ linktest(void) | ||||||
|   printf(1, "linktest ok\n"); |   printf(1, "linktest ok\n"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // test concurrent create and unlink of the same file
 | // test concurrent create/link/unlink of the same file
 | ||||||
| void | void | ||||||
| concreate(void) | concreate(void) | ||||||
| { | { | ||||||
|  | @ -728,10 +730,15 @@ concreate(void) | ||||||
|     } |     } | ||||||
|     if(((i % 3) == 0 && pid == 0) || |     if(((i % 3) == 0 && pid == 0) || | ||||||
|        ((i % 3) == 1 && pid != 0)){ |        ((i % 3) == 1 && pid != 0)){ | ||||||
|       fd = open(file, 0); |       close(open(file, 0)); | ||||||
|       close(fd); |       close(open(file, 0)); | ||||||
|  |       close(open(file, 0)); | ||||||
|  |       close(open(file, 0)); | ||||||
|     } else { |     } else { | ||||||
|       unlink(file); |       unlink(file); | ||||||
|  |       unlink(file); | ||||||
|  |       unlink(file); | ||||||
|  |       unlink(file); | ||||||
|     } |     } | ||||||
|     if(pid == 0) |     if(pid == 0) | ||||||
|       exit(); |       exit(); | ||||||
|  | @ -742,6 +749,42 @@ concreate(void) | ||||||
|   printf(1, "concreate ok\n"); |   printf(1, "concreate ok\n"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // another concurrent link/unlink/create test,
 | ||||||
|  | // to look for deadlocks.
 | ||||||
|  | void | ||||||
|  | linkunlink() | ||||||
|  | { | ||||||
|  |   int pid, i; | ||||||
|  | 
 | ||||||
|  |   printf(1, "linkunlink test\n"); | ||||||
|  | 
 | ||||||
|  |   unlink("x"); | ||||||
|  |   pid = fork(); | ||||||
|  |   if(pid < 0){ | ||||||
|  |     printf(1, "fork failed\n"); | ||||||
|  |     exit(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   unsigned int x = (pid ? 1 : 97); | ||||||
|  |   for(i = 0; i < 100; i++){ | ||||||
|  |     x = x * 1103515245 + 12345; | ||||||
|  |     if((x % 3) == 0){ | ||||||
|  |       close(open("x", O_RDWR | O_CREATE)); | ||||||
|  |     } else if((x % 3) == 1){ | ||||||
|  |       link("cat", "x"); | ||||||
|  |     } else { | ||||||
|  |       unlink("x"); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   if(pid) | ||||||
|  |     wait(); | ||||||
|  |   else  | ||||||
|  |     exit(); | ||||||
|  | 
 | ||||||
|  |   printf(1, "linkunlink ok\n"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // directory that uses indirect blocks
 | // directory that uses indirect blocks
 | ||||||
| void | void | ||||||
| bigdir(void) | bigdir(void) | ||||||
|  | @ -1518,6 +1561,7 @@ main(int argc, char *argv[]) | ||||||
|   bigfile(); |   bigfile(); | ||||||
|   subdir(); |   subdir(); | ||||||
|   concreate(); |   concreate(); | ||||||
|  |   linkunlink(); | ||||||
|   linktest(); |   linktest(); | ||||||
|   unlinkread(); |   unlinkread(); | ||||||
|   createdelete(); |   createdelete(); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Robert Morris
						Robert Morris