support read() and write() bigger than one page
This commit is contained in:
		
							parent
							
								
									cefe223bf5
								
							
						
					
					
						commit
						8baac76050
					
				
					 12 changed files with 95 additions and 62 deletions
				
			
		
							
								
								
									
										18
									
								
								console.c
									
										
									
									
									
								
							
							
						
						
									
										18
									
								
								console.c
									
										
									
									
									
								
							|  | @ -155,10 +155,11 @@ struct { | |||
| #define C(x)  ((x)-'@')  // Contro
 | ||||
| 
 | ||||
| int | ||||
| consoleread(struct inode *ip, char *dst, int n) | ||||
| consoleread(struct inode *ip, int user_dst, uint64 dst, int n) | ||||
| { | ||||
|   uint target; | ||||
|   int c; | ||||
|   char buf[1]; | ||||
| 
 | ||||
|   iunlock(ip); | ||||
|   target = n; | ||||
|  | @ -181,7 +182,10 @@ consoleread(struct inode *ip, char *dst, int n) | |||
|       } | ||||
|       break; | ||||
|     } | ||||
|     *dst++ = c; | ||||
|     buf[0] = c; | ||||
|     if(either_copyout(user_dst, dst, &buf[0], 1) == -1) | ||||
|       break; | ||||
|     dst++; | ||||
|     --n; | ||||
|     if(c == '\n') | ||||
|       break; | ||||
|  | @ -193,14 +197,18 @@ consoleread(struct inode *ip, char *dst, int n) | |||
| } | ||||
| 
 | ||||
| int | ||||
| consolewrite(struct inode *ip, char *buf, int n) | ||||
| consolewrite(struct inode *ip, int user_src, uint64 src, int n) | ||||
| { | ||||
|   int i; | ||||
| 
 | ||||
|   iunlock(ip); | ||||
|   acquire(&cons.lock); | ||||
|   for(i = 0; i < n; i++) | ||||
|     consputc(buf[i] & 0xff); | ||||
|   for(i = 0; i < n; i++){ | ||||
|     char c; | ||||
|     if(either_copyin(&c, user_src, src, 1) == -1) | ||||
|       break; | ||||
|     consputc(c); | ||||
|   } | ||||
|   release(&cons.lock); | ||||
|   ilock(ip); | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										10
									
								
								defs.h
									
										
									
									
									
								
							
							
						
						
									
										10
									
								
								defs.h
									
										
									
									
									
								
							|  | @ -50,9 +50,9 @@ void            iupdate(struct inode*); | |||
| int             namecmp(const char*, const char*); | ||||
| struct inode*   namei(char*); | ||||
| struct inode*   nameiparent(char*, char*); | ||||
| int             readi(struct inode*, char*, uint, uint); | ||||
| int             readi(struct inode*, int, uint64, uint, uint); | ||||
| void            stati(struct inode*, struct stat*); | ||||
| int             writei(struct inode*, char*, uint, uint); | ||||
| int             writei(struct inode*, int, uint64, uint, uint); | ||||
| 
 | ||||
| // ramdisk.c
 | ||||
| void            ramdiskinit(void); | ||||
|  | @ -98,8 +98,8 @@ void            picinit(void); | |||
| // pipe.c
 | ||||
| int             pipealloc(struct file**, struct file**); | ||||
| void            pipeclose(struct pipe*, int); | ||||
| int             piperead(struct pipe*, char*, int); | ||||
| int             pipewrite(struct pipe*, char*, int); | ||||
| int             piperead(struct pipe*, uint64, int); | ||||
| int             pipewrite(struct pipe*, uint64, int); | ||||
| 
 | ||||
| //PAGEBREAK: 16
 | ||||
| // proc.c
 | ||||
|  | @ -122,6 +122,8 @@ void            userinit(void); | |||
| int             wait(void); | ||||
| void            wakeup(void*); | ||||
| void            yield(void); | ||||
| int             either_copyout(int user_dst, uint64 dst, char *src, uint64 len); | ||||
| int             either_copyin(char *dst, int user_src, uint64 src, uint64 len); | ||||
| 
 | ||||
| // swtch.S
 | ||||
| void            swtch(struct context*, struct context*); | ||||
|  |  | |||
							
								
								
									
										8
									
								
								exec.c
									
										
									
									
									
								
							
							
						
						
									
										8
									
								
								exec.c
									
										
									
									
									
								
							|  | @ -30,7 +30,7 @@ exec(char *path, char **argv) | |||
|   ilock(ip); | ||||
| 
 | ||||
|   // Check ELF header
 | ||||
|   if(readi(ip, (char*)&elf, 0, sizeof(elf)) != sizeof(elf)) | ||||
|   if(readi(ip, 0, (uint64)&elf, 0, sizeof(elf)) != sizeof(elf)) | ||||
|     goto bad; | ||||
|   if(elf.magic != ELF_MAGIC) | ||||
|     goto bad; | ||||
|  | @ -41,7 +41,7 @@ exec(char *path, char **argv) | |||
|   // Load program into memory.
 | ||||
|   sz = 0; | ||||
|   for(i=0, off=elf.phoff; i<elf.phnum; i++, off+=sizeof(ph)){ | ||||
|     if(readi(ip, (char*)&ph, off, sizeof(ph)) != sizeof(ph)) | ||||
|     if(readi(ip, 0, (uint64)&ph, off, sizeof(ph)) != sizeof(ph)) | ||||
|       goto bad; | ||||
|     if(ph.type != ELF_PROG_LOAD) | ||||
|       continue; | ||||
|  | @ -128,6 +128,7 @@ loadseg(pagetable_t pagetable, uint64 va, struct inode *ip, uint offset, uint sz | |||
| 
 | ||||
|   if((va % PGSIZE) != 0) | ||||
|     panic("loadseg: va must be page aligned"); | ||||
| 
 | ||||
|   for(i = 0; i < sz; i += PGSIZE){ | ||||
|     pa = walkaddr(pagetable, va + i); | ||||
|     if(pa == 0) | ||||
|  | @ -136,8 +137,9 @@ loadseg(pagetable_t pagetable, uint64 va, struct inode *ip, uint offset, uint sz | |||
|       n = sz - i; | ||||
|     else | ||||
|       n = PGSIZE; | ||||
|     if(readi(ip, (char *)pa, offset+i, n) != n) | ||||
|     if(readi(ip, 0, (uint64)pa, offset+i, n) != n) | ||||
|       return -1; | ||||
|   } | ||||
|    | ||||
|   return 0; | ||||
| } | ||||
|  |  | |||
							
								
								
									
										36
									
								
								file.c
									
										
									
									
									
								
							
							
						
						
									
										36
									
								
								file.c
									
										
									
									
									
								
							|  | @ -113,33 +113,17 @@ fileread(struct file *f, uint64 addr, int n) | |||
|   if(f->readable == 0) | ||||
|     return -1; | ||||
| 
 | ||||
|   // XXX break into page-size pieces.
 | ||||
|   if(n > PGSIZE) | ||||
|     panic("fileread PGSIZE"); | ||||
| 
 | ||||
|   buf = kalloc(); | ||||
|   if(buf == 0) | ||||
|     panic("fileread kalloc"); | ||||
| 
 | ||||
|   if(f->type == FD_PIPE){ | ||||
|     r = piperead(f->pipe, buf, n); | ||||
|     r = piperead(f->pipe, addr, n); | ||||
|   } else if(f->type == FD_INODE){ | ||||
|     ilock(f->ip); | ||||
|     if((r = readi(f->ip, buf, f->off, n)) > 0) | ||||
|     if((r = readi(f->ip, 1, addr, f->off, n)) > 0) | ||||
|       f->off += r; | ||||
|     iunlock(f->ip); | ||||
|   } else { | ||||
|     panic("fileread"); | ||||
|   } | ||||
| 
 | ||||
|   if(r > 0){ | ||||
|     if(copyout(p->pagetable, addr, buf, n) < 0){ | ||||
|       r = -1; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   kfree(buf); | ||||
| 
 | ||||
|   return r; | ||||
| } | ||||
| 
 | ||||
|  | @ -156,18 +140,8 @@ filewrite(struct file *f, uint64 addr, int n) | |||
|   if(f->writable == 0) | ||||
|     return -1; | ||||
| 
 | ||||
|   // XXX break into pieces
 | ||||
|   if(n > PGSIZE) | ||||
|     panic("filewrite PGSIZE"); | ||||
| 
 | ||||
|   buf = kalloc(); | ||||
|   if(copyin(p->pagetable, buf, addr, n) < 0){ | ||||
|     kfree(buf); | ||||
|     return -1; | ||||
|   } | ||||
| 
 | ||||
|   if(f->type == FD_PIPE){ | ||||
|     ret = pipewrite(f->pipe, buf, n); | ||||
|     ret = pipewrite(f->pipe, addr, n); | ||||
|   } else if(f->type == FD_INODE){ | ||||
|     // write a few blocks at a time to avoid exceeding
 | ||||
|     // the maximum log transaction size, including
 | ||||
|  | @ -184,7 +158,7 @@ filewrite(struct file *f, uint64 addr, int n) | |||
| 
 | ||||
|       begin_op(); | ||||
|       ilock(f->ip); | ||||
|       if ((r = writei(f->ip, buf + i, f->off, n1)) > 0) | ||||
|       if ((r = writei(f->ip, 1, addr + i, f->off, n1)) > 0) | ||||
|         f->off += r; | ||||
|       iunlock(f->ip); | ||||
|       end_op(); | ||||
|  | @ -200,8 +174,6 @@ filewrite(struct file *f, uint64 addr, int n) | |||
|     panic("filewrite"); | ||||
|   } | ||||
| 
 | ||||
|   kfree(buf); | ||||
|    | ||||
|   return ret; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										4
									
								
								file.h
									
										
									
									
									
								
							
							
						
						
									
										4
									
								
								file.h
									
										
									
									
									
								
							|  | @ -28,8 +28,8 @@ struct inode { | |||
| // table mapping major device number to
 | ||||
| // device functions
 | ||||
| struct devsw { | ||||
|   int (*read)(struct inode*, char*, int); | ||||
|   int (*write)(struct inode*, char*, int); | ||||
|   int (*read)(struct inode*, int, uint64, int); | ||||
|   int (*write)(struct inode*, int, uint64, int); | ||||
| }; | ||||
| 
 | ||||
| extern struct devsw devsw[]; | ||||
|  |  | |||
							
								
								
									
										26
									
								
								fs.c
									
										
									
									
									
								
							
							
						
						
									
										26
									
								
								fs.c
									
										
									
									
									
								
							|  | @ -180,6 +180,8 @@ iinit(int dev) | |||
|   } | ||||
| 
 | ||||
|   readsb(dev, &sb); | ||||
|   if(sb.magic != FSMAGIC) | ||||
|     panic("invalid file system"); | ||||
|   printf("sb: size %d nblocks %d ninodes %d nlog %d logstart %d\
 | ||||
|  inodestart %d bmap start %d\n", sb.size, sb.nblocks, | ||||
|           sb.ninodes, sb.nlog, sb.logstart, sb.inodestart, | ||||
|  | @ -450,8 +452,10 @@ stati(struct inode *ip, struct stat *st) | |||
| //PAGEBREAK!
 | ||||
| // Read data from inode.
 | ||||
| // Caller must hold ip->lock.
 | ||||
| // If user_dst==1, then dst is a user virtual address;
 | ||||
| // otherwise, dst is a kernel address.
 | ||||
| int | ||||
| readi(struct inode *ip, char *dst, uint off, uint n) | ||||
| readi(struct inode *ip, int user_dst, uint64 dst, uint off, uint n) | ||||
| { | ||||
|   uint tot, m; | ||||
|   struct buf *bp; | ||||
|  | @ -459,7 +463,7 @@ readi(struct inode *ip, char *dst, uint off, uint n) | |||
|   if(ip->type == T_DEV){ | ||||
|     if(ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].read) | ||||
|       return -1; | ||||
|     return devsw[ip->major].read(ip, dst, n); | ||||
|     return devsw[ip->major].read(ip, user_dst, dst, n); | ||||
|   } | ||||
| 
 | ||||
|   if(off > ip->size || off + n < off) | ||||
|  | @ -470,7 +474,8 @@ readi(struct inode *ip, char *dst, uint off, uint n) | |||
|   for(tot=0; tot<n; tot+=m, off+=m, dst+=m){ | ||||
|     bp = bread(ip->dev, bmap(ip, off/BSIZE)); | ||||
|     m = min(n - tot, BSIZE - off%BSIZE); | ||||
|     memmove(dst, bp->data + off%BSIZE, m); | ||||
|     if(either_copyout(user_dst, dst, bp->data + (off % BSIZE), m) == -1) | ||||
|       break; | ||||
|     brelse(bp); | ||||
|   } | ||||
|   return n; | ||||
|  | @ -479,8 +484,10 @@ readi(struct inode *ip, char *dst, uint off, uint n) | |||
| // PAGEBREAK!
 | ||||
| // Write data to inode.
 | ||||
| // Caller must hold ip->lock.
 | ||||
| // If user_src==1, then src is a user virtual address;
 | ||||
| // otherwise, src is a kernel address.
 | ||||
| int | ||||
| writei(struct inode *ip, char *src, uint off, uint n) | ||||
| writei(struct inode *ip, int user_src, uint64 src, uint off, uint n) | ||||
| { | ||||
|   uint tot, m; | ||||
|   struct buf *bp; | ||||
|  | @ -489,7 +496,7 @@ writei(struct inode *ip, char *src, uint off, uint n) | |||
|     if(ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].write){ | ||||
|       return -1; | ||||
|     } | ||||
|     return devsw[ip->major].write(ip, src, n); | ||||
|     return devsw[ip->major].write(ip, user_src, src, n); | ||||
|   } | ||||
| 
 | ||||
|   if(off > ip->size || off + n < off) | ||||
|  | @ -500,7 +507,8 @@ writei(struct inode *ip, char *src, uint off, uint n) | |||
|   for(tot=0; tot<n; tot+=m, off+=m, src+=m){ | ||||
|     bp = bread(ip->dev, bmap(ip, off/BSIZE)); | ||||
|     m = min(n - tot, BSIZE - off%BSIZE); | ||||
|     memmove(bp->data + off%BSIZE, src, m); | ||||
|     if(either_copyin(bp->data + (off % BSIZE), user_src, src, m) == -1) | ||||
|       break; | ||||
|     log_write(bp); | ||||
|     brelse(bp); | ||||
|   } | ||||
|  | @ -533,7 +541,7 @@ dirlookup(struct inode *dp, char *name, uint *poff) | |||
|     panic("dirlookup not DIR"); | ||||
| 
 | ||||
|   for(off = 0; off < dp->size; off += sizeof(de)){ | ||||
|     if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) | ||||
|     if(readi(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de)) | ||||
|       panic("dirlookup read"); | ||||
|     if(de.inum == 0) | ||||
|       continue; | ||||
|  | @ -565,7 +573,7 @@ dirlink(struct inode *dp, char *name, uint inum) | |||
| 
 | ||||
|   // Look for an empty dirent.
 | ||||
|   for(off = 0; off < dp->size; off += sizeof(de)){ | ||||
|     if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) | ||||
|     if(readi(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de)) | ||||
|       panic("dirlink read"); | ||||
|     if(de.inum == 0) | ||||
|       break; | ||||
|  | @ -573,7 +581,7 @@ dirlink(struct inode *dp, char *name, uint inum) | |||
| 
 | ||||
|   strncpy(de.name, name, DIRSIZ); | ||||
|   de.inum = inum; | ||||
|   if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) | ||||
|   if(writei(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de)) | ||||
|     panic("dirlink"); | ||||
| 
 | ||||
|   return 0; | ||||
|  |  | |||
							
								
								
									
										3
									
								
								fs.h
									
										
									
									
									
								
							
							
						
						
									
										3
									
								
								fs.h
									
										
									
									
									
								
							|  | @ -12,6 +12,7 @@ | |||
| // mkfs computes the super block and builds an initial file system. The
 | ||||
| // super block describes the disk layout:
 | ||||
| struct superblock { | ||||
|   uint magic;        // Must be FSMAGIC
 | ||||
|   uint size;         // Size of file system image (blocks)
 | ||||
|   uint nblocks;      // Number of data blocks
 | ||||
|   uint ninodes;      // Number of inodes.
 | ||||
|  | @ -21,6 +22,8 @@ struct superblock { | |||
|   uint bmapstart;    // Block number of first free map block
 | ||||
| }; | ||||
| 
 | ||||
| #define FSMAGIC 0x10203040 | ||||
| 
 | ||||
| #define NDIRECT 12 | ||||
| #define NINDIRECT (BSIZE / sizeof(uint)) | ||||
| #define MAXFILE (NDIRECT + NINDIRECT) | ||||
|  |  | |||
							
								
								
									
										1
									
								
								mkfs.c
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								mkfs.c
									
										
									
									
									
								
							|  | @ -94,6 +94,7 @@ main(int argc, char *argv[]) | |||
|   nmeta = 2 + nlog + ninodeblocks + nbitmap; | ||||
|   nblocks = FSSIZE - nmeta; | ||||
| 
 | ||||
|   sb.magic = FSMAGIC; | ||||
|   sb.size = xint(FSSIZE); | ||||
|   sb.nblocks = xint(nblocks); | ||||
|   sb.ninodes = xint(NINODES); | ||||
|  |  | |||
							
								
								
									
										16
									
								
								pipe.c
									
										
									
									
									
								
							
							
						
						
									
										16
									
								
								pipe.c
									
										
									
									
									
								
							|  | @ -76,9 +76,11 @@ pipeclose(struct pipe *p, int writable) | |||
| 
 | ||||
| //PAGEBREAK: 40
 | ||||
| int | ||||
| pipewrite(struct pipe *p, char *addr, int n) | ||||
| pipewrite(struct pipe *p, uint64 addr, int n) | ||||
| { | ||||
|   int i; | ||||
|   char ch; | ||||
|   struct proc *pr = myproc(); | ||||
| 
 | ||||
|   acquire(&p->lock); | ||||
|   for(i = 0; i < n; i++){ | ||||
|  | @ -90,7 +92,9 @@ pipewrite(struct pipe *p, char *addr, int n) | |||
|       wakeup(&p->nread); | ||||
|       sleep(&p->nwrite, &p->lock);  //DOC: pipewrite-sleep
 | ||||
|     } | ||||
|     p->data[p->nwrite++ % PIPESIZE] = addr[i]; | ||||
|     if(copyin(pr->pagetable, &ch, addr + i, 1) == -1) | ||||
|       break; | ||||
|     p->data[p->nwrite++ % PIPESIZE] = ch; | ||||
|   } | ||||
|   wakeup(&p->nread);  //DOC: pipewrite-wakeup1
 | ||||
|   release(&p->lock); | ||||
|  | @ -98,9 +102,11 @@ pipewrite(struct pipe *p, char *addr, int n) | |||
| } | ||||
| 
 | ||||
| int | ||||
| piperead(struct pipe *p, char *addr, int n) | ||||
| piperead(struct pipe *p, uint64 addr, int n) | ||||
| { | ||||
|   int i; | ||||
|   struct proc *pr = myproc(); | ||||
|   char ch; | ||||
| 
 | ||||
|   acquire(&p->lock); | ||||
|   while(p->nread == p->nwrite && p->writeopen){  //DOC: pipe-empty
 | ||||
|  | @ -113,7 +119,9 @@ piperead(struct pipe *p, char *addr, int n) | |||
|   for(i = 0; i < n; i++){  //DOC: piperead-copy
 | ||||
|     if(p->nread == p->nwrite) | ||||
|       break; | ||||
|     addr[i] = p->data[p->nread++ % PIPESIZE]; | ||||
|     ch = p->data[p->nread++ % PIPESIZE]; | ||||
|     if(copyout(pr->pagetable, addr + i, &ch, 1) == -1) | ||||
|       break; | ||||
|   } | ||||
|   wakeup(&p->nwrite);  //DOC: piperead-wakeup
 | ||||
|   release(&p->lock); | ||||
|  |  | |||
							
								
								
									
										29
									
								
								proc.c
									
										
									
									
									
								
							
							
						
						
									
										29
									
								
								proc.c
									
										
									
									
									
								
							|  | @ -526,3 +526,32 @@ kill(int pid) | |||
| } | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| // Copy to either a user address, or kernel address,
 | ||||
| // depending on usr_dst.
 | ||||
| // Returns 0 on success, -1 on error.
 | ||||
| int | ||||
| either_copyout(int user_dst, uint64 dst, char *src, uint64 len) | ||||
| { | ||||
|   struct proc *p = myproc(); | ||||
|   if(user_dst){ | ||||
|     return copyout(p->pagetable, dst, src, len); | ||||
|   } else { | ||||
|     memmove((char *)dst, src, len); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| // Copy from either a user address, or kernel address,
 | ||||
| // depending on usr_src.
 | ||||
| // Returns 0 on success, -1 on error.
 | ||||
| int | ||||
| either_copyin(char *dst, int user_src, uint64 src, uint64 len) | ||||
| { | ||||
|   struct proc *p = myproc(); | ||||
|   if(user_src){ | ||||
|     return copyin(p->pagetable, dst, src, len); | ||||
|   } else { | ||||
|     memmove(dst, (char*)src, len); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -173,7 +173,7 @@ isdirempty(struct inode *dp) | |||
|   struct dirent de; | ||||
| 
 | ||||
|   for(off=2*sizeof(de); off<dp->size; off+=sizeof(de)){ | ||||
|     if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) | ||||
|     if(readi(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de)) | ||||
|       panic("isdirempty: readi"); | ||||
|     if(de.inum != 0) | ||||
|       return 0; | ||||
|  | @ -217,7 +217,7 @@ sys_unlink(void) | |||
|   } | ||||
| 
 | ||||
|   memset(&de, 0, sizeof(de)); | ||||
|   if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) | ||||
|   if(writei(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de)) | ||||
|     panic("unlink: writei"); | ||||
|   if(ip->type == T_DIR){ | ||||
|     dp->nlink--; | ||||
|  |  | |||
							
								
								
									
										2
									
								
								vm.c
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								vm.c
									
										
									
									
									
								
							|  | @ -342,7 +342,7 @@ copyin(pagetable_t pagetable, char *dst, uint64 srcva, uint64 len) | |||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| // Copy a null-terminated from user to kernel.
 | ||||
| // Copy a null-terminated string from user to kernel.
 | ||||
| // Copy bytes to dst from virtual address srcva in a given page table,
 | ||||
| // until a '\0', or max.
 | ||||
| // Return 0 on success, -1 on error.
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Robert Morris
						Robert Morris