summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Morris <[email protected]>2019-06-04 05:57:47 -0400
committerRobert Morris <[email protected]>2019-06-04 05:57:47 -0400
commit8baac760500980d4b83e8de2e90265bfaa19df13 (patch)
treeceb59412ec44ff98c1281627fb648deaeedb0d04
parentcefe223bf5e4b68e5c1202f2f089a164ad656621 (diff)
downloadxv6-labs-8baac760500980d4b83e8de2e90265bfaa19df13.tar.gz
xv6-labs-8baac760500980d4b83e8de2e90265bfaa19df13.tar.bz2
xv6-labs-8baac760500980d4b83e8de2e90265bfaa19df13.zip
support read() and write() bigger than one page
-rw-r--r--console.c18
-rw-r--r--defs.h10
-rw-r--r--exec.c8
-rw-r--r--file.c36
-rw-r--r--file.h4
-rw-r--r--fs.c26
-rw-r--r--fs.h3
-rw-r--r--mkfs.c1
-rw-r--r--pipe.c16
-rw-r--r--proc.c29
-rw-r--r--sysfile.c4
-rw-r--r--vm.c2
12 files changed, 95 insertions, 62 deletions
diff --git a/console.c b/console.c
index 56817d8..c7e1852 100644
--- a/console.c
+++ b/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);
diff --git a/defs.h b/defs.h
index dfc7715..262da72 100644
--- a/defs.h
+++ b/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*);
diff --git a/exec.c b/exec.c
index e6a0809..4c34a51 100644
--- a/exec.c
+++ b/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;
}
diff --git a/file.c b/file.c
index 44dd538..2a903b0 100644
--- a/file.c
+++ b/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;
}
diff --git a/file.h b/file.h
index 0990c82..f28018f 100644
--- a/file.h
+++ b/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[];
diff --git a/fs.c b/fs.c
index beea46d..7cb55a9 100644
--- a/fs.c
+++ b/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;
diff --git a/fs.h b/fs.h
index 3214f1d..56f0558 100644
--- a/fs.h
+++ b/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)
diff --git a/mkfs.c b/mkfs.c
index 8e011a7..17040b7 100644
--- a/mkfs.c
+++ b/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);
diff --git a/pipe.c b/pipe.c
index 1274a3a..31bf0cc 100644
--- a/pipe.c
+++ b/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);
diff --git a/proc.c b/proc.c
index f1558d0..e9aec5d 100644
--- a/proc.c
+++ b/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);
+ }
+}
+
diff --git a/sysfile.c b/sysfile.c
index 86e734a..83bb1ed 100644
--- a/sysfile.c
+++ b/sysfile.c
@@ -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--;
diff --git a/vm.c b/vm.c
index 7f9ef14..89b1aa2 100644
--- a/vm.c
+++ b/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.