From ea2909b6b5ceb54383ab23fd195ebae29cfdb7ca Mon Sep 17 00:00:00 2001 From: kaashoek Date: Thu, 24 Aug 2006 02:44:41 +0000 Subject: [PATCH] user-level malloc (untested) nit in sbrk indirect block fix dup to share fd struct --- Makefile | 2 +- defs.h | 2 +- fs.c | 86 ++++++++++++++++++++++++++++++++++++++++++---------- fs.h | 8 +++-- mkfs.c | 32 ++++++++++++++++---- proc.c | 9 +++--- syscall.c | 24 ++++----------- umalloc.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ user.h | 3 ++ userfs.c | 6 ++-- 10 files changed, 210 insertions(+), 52 deletions(-) create mode 100644 umalloc.c diff --git a/Makefile b/Makefile index a40289f..4a890a9 100644 --- a/Makefile +++ b/Makefile @@ -57,7 +57,7 @@ kernel : $(OBJS) bootother.S init vectors.S : vectors.pl perl vectors.pl > vectors.S -ULIB = ulib.o usys.o printf.o +ULIB = ulib.o usys.o printf.o umalloc.o user1 : user1.o $(ULIB) $(LD) -N -e main -Ttext 0 -o user1 user1.o $(ULIB) diff --git a/defs.h b/defs.h index b8b7b84..cb5175d 100644 --- a/defs.h +++ b/defs.h @@ -16,7 +16,7 @@ struct jmpbuf; void setupsegs(struct proc *); struct proc * copyproc(struct proc*); struct spinlock; -int growproc(int); +char *growproc(int); void sleep(void *, struct spinlock *); void wakeup(void *); void scheduler(void); diff --git a/fs.c b/fs.c index ed62970..6a1c1d0 100644 --- a/fs.c +++ b/fs.c @@ -231,24 +231,46 @@ uint bmap(struct inode *ip, uint bn) { unsigned x; + uint *a; + struct buf *inbp; - if(bn >= NDIRECT) + if(bn >= MAXFILE) panic("bmap 1"); - x = ip->addrs[bn]; - if(x == 0) - panic("bmap 2"); + if (bn < NDIRECT) { + x = ip->addrs[bn]; + if (x == 0) + panic("bmap 2"); + } else { + cprintf("indirect block read\n"); + inbp = bread(ip->dev, INDIRECT); + a = (uint *) inbp->data; + x = a[bn - NDIRECT]; + brelse(inbp); + if (x == 0) + panic("bmap 3"); + } return x; } void iunlink(struct inode *ip) { - int i; + int i, j; // free inode, its blocks, and remove dir entry - for (i = 0; i < NDIRECT; i++) { + for (i = 0; i < NADDRS; i++) { if (ip->addrs[i] != 0) { - bfree(ip->dev, ip->addrs[i]); + if (i == INDIRECT) { + for (j = 0; j < NINDIRECT; j++) { + uint *a = (uint *) (ip->addrs[i]); + if (a[j] != 0) { + bfree(ip->dev, a[j]); + a[j] = 0; + } + } + } + else + bfree(ip->dev, ip->addrs[i]); ip->addrs[i] = 0; } } @@ -332,6 +354,40 @@ readi(struct inode *ip, char *dst, uint off, uint n) return target - n; } +int +newblock(struct inode *ip, uint lbn) +{ + struct buf *inbp; + uint *inaddrs; + uint b; + + if (lbn < NDIRECT) { + if (ip->addrs[lbn] == 0) { + b = balloc(ip->dev); + if (b <= 0) return -1; + ip->addrs[lbn] = b; + } + } else { + cprintf("newblock: use indirect block\n"); + if (ip->addrs[INDIRECT] == 0) { + cprintf("newblock: allocate indirect block\n"); + b = balloc(ip->dev); + if (b <= 0) return -1; + ip->addrs[INDIRECT] = b; + } + inbp = bread(ip->dev, bmap(ip, INDIRECT)); + inaddrs = (uint *) inbp->data; + if (inaddrs[lbn - NDIRECT] == 0) { + b = balloc(ip->dev); + if (b <= 0) return -1; + inaddrs[lbn - NDIRECT] = b; + bwrite(inbp, INDIRECT); + } + brelse(inbp); + } + return 0; +} + int writei(struct inode *ip, char *addr, uint off, uint n) { @@ -339,24 +395,22 @@ writei(struct inode *ip, char *addr, uint off, uint n) if (ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].d_write) return -1; return devsw[ip->major].d_write (ip->minor, addr, n); - } else if (ip->type == T_FILE || ip->type == T_DIR) { // XXX dir here too? + } else if (ip->type == T_FILE || ip->type == T_DIR) { struct buf *bp; int r = 0; int m; int lbn; - uint b; while (r < n) { lbn = off / BSIZE; - if (lbn >= NDIRECT) return r; - if (ip->addrs[lbn] == 0) { - b = balloc(ip->dev); - if (b <= 0) return r; - ip->addrs[lbn] = b; + if (lbn >= MAXFILE) return r; + if (newblock(ip, lbn) < 0) { + cprintf("newblock failed\n"); + return r; } m = min(BSIZE - off % BSIZE, n-r); - bp = bread(ip->dev, bmap(ip, off / BSIZE)); + bp = bread(ip->dev, bmap(ip, lbn)); memmove (bp->data + off % BSIZE, addr, m); - bwrite (bp, bmap(ip, off/BSIZE)); + bwrite (bp, bmap(ip, lbn)); brelse (bp); r += m; off += m; diff --git a/fs.h b/fs.h index 2112c25..de81e81 100644 --- a/fs.h +++ b/fs.h @@ -9,7 +9,11 @@ struct superblock{ uint ninodes; }; -#define NDIRECT 13 +#define NADDRS NDIRECT+1 +#define NDIRECT 12 +#define INDIRECT 12 +#define NINDIRECT (BSIZE / sizeof(uint)) +#define MAXFILE (NDIRECT + NINDIRECT) struct dinode { short type; @@ -17,7 +21,7 @@ struct dinode { short minor; short nlink; uint size; - uint addrs[NDIRECT]; + uint addrs[NADDRS]; }; #define T_DIR 1 diff --git a/mkfs.c b/mkfs.c index 15870d9..2d84610 100644 --- a/mkfs.c +++ b/mkfs.c @@ -106,6 +106,7 @@ main(int argc, char *argv[]) for(i = 2; i < argc; i++){ assert(index(argv[i], '/') == 0); + if((fd = open(argv[i], 0)) < 0){ perror(argv[i]); exit(1); @@ -234,21 +235,40 @@ iappend(uint inum, void *xp, int n) uint fbn, off, n1; struct dinode din; char buf[512]; + uint indirect[NINDIRECT]; + uint x; rinode(inum, &din); off = xint(din.size); while(n > 0){ fbn = off / 512; - assert(fbn < NDIRECT); - if(din.addrs[fbn] == 0) { - din.addrs[fbn] = xint(freeblock++); - usedblocks++; + assert(fbn < MAXFILE); + if (fbn < NDIRECT) { + if(xint(din.addrs[fbn]) == 0) { + din.addrs[fbn] = xint(freeblock++); + usedblocks++; + } + x = xint(din.addrs[fbn]); + } else { + if(xint(din.addrs[INDIRECT]) == 0) { + printf("allocate indirect block\n"); + din.addrs[INDIRECT] = xint(freeblock++); + usedblocks++; + } + printf("read indirect block\n"); + rsect(xint(din.addrs[INDIRECT]), (char *) indirect); + if (indirect[fbn - NDIRECT] == 0) { + indirect[fbn - NDIRECT] = xint(freeblock++); + usedblocks++; + wsect(INDIRECT, (char *) indirect); + } + x = xint(indirect[fbn-NDIRECT]); } n1 = min(n, (fbn + 1) * 512 - off); - rsect(xint(din.addrs[fbn]), buf); + rsect(x, buf); bcopy(p, buf + off - (fbn * 512), n1); - wsect(xint(din.addrs[fbn]), buf); + wsect(x, buf); n -= n1; off += n1; p += n1; diff --git a/proc.c b/proc.c index 7382add..b65bb70 100644 --- a/proc.c +++ b/proc.c @@ -138,22 +138,23 @@ copyproc(struct proc* p) return np; } -int +char * growproc(int n) { struct proc *cp = curproc[cpu()]; char *newmem, *oldmem; newmem = kalloc(cp->sz + n); - if(newmem == 0) return -1; + if(newmem == 0) return (char *) -1; memmove(newmem, cp->mem, cp->sz); memset(newmem + cp->sz, 0, n); oldmem = cp->mem; cp->mem = newmem; kfree(oldmem, cp->sz); cp->sz += n; - cprintf("growproc: added %d bytes\n", n); - return 0; + cprintf("growproc: added %d bytes starting at address 0x%x\n", n, + newmem + cp->sz - n); + return newmem + cp->sz - n; } // Per-CPU process scheduler. diff --git a/syscall.c b/syscall.c index 39c6821..39cd107 100644 --- a/syscall.c +++ b/syscall.c @@ -404,7 +404,6 @@ sys_dup(void) { struct proc *cp = curproc[cpu()]; uint fd, ufd1; - struct fd *fd1; if(fetcharg(0, &fd) < 0) return -1; @@ -414,25 +413,11 @@ sys_dup(void) return -1; if (cp->fds[fd]->type != FD_PIPE && cp->fds[fd]->type != FD_FILE) return -1; - - if ((fd1 = fd_alloc()) == 0) { - return -1; - } if ((ufd1 = fd_ualloc()) < 0) { - fd_close(fd1); return -1; } - cp->fds[ufd1] = fd1; - fd1->type = cp->fds[fd]->type; - fd1->readable = cp->fds[fd]->readable; - fd1->writeable = cp->fds[fd]->writeable; - if (cp->fds[fd]->type == FD_FILE) { - fd1->ip = cp->fds[fd]->ip; - iincref(fd1->ip); - } else if (cp->fds[fd]->type == FD_PIPE) { - fd1->pipe = cp->fds[fd]->pipe; - } - fd1->off = cp->fds[fd]->off; + cp->fds[ufd1] = cp->fds[fd]; + fd_incref(cp->fds[ufd1]); return ufd1; } @@ -462,14 +447,15 @@ sys_getpid(void) int sys_sbrk(void) { - int r, n; + char *r; + int n; struct proc *cp = curproc[cpu()]; if(fetcharg(0, &n) < 0) return -1; r = growproc(n); setupsegs(cp); - return r; + return (int) r; } int diff --git a/umalloc.c b/umalloc.c new file mode 100644 index 0000000..c0fc4ca --- /dev/null +++ b/umalloc.c @@ -0,0 +1,90 @@ +#include "types.h" +#include "stat.h" +#include "user.h" +#include "param.h" + +// Memory allocator by Kernighan and Ritchie, The C programming Language, +// 2nd ed. Section 8.7. + +typedef long Align; + +union header { + struct { + union header *ptr; + uint size; + } s; + Align x; +}; + +typedef union header Header; + +static Header base; +static Header *freep = 0; + +void +free(void *ap) +{ + Header *bp, *p; + + bp = (Header *) ap - 1; + for (p = freep; !(bp > p && bp < p->s.ptr); p = p->s.ptr) + if (p >= p->s.ptr && (bp > p || bp < p->s.ptr)) + break; + if (bp + bp->s.size == p->s.ptr) { + bp->s.size += p->s.ptr->s.size; + bp->s.ptr = p->s.ptr->s.ptr; + } else + bp->s.ptr = p->s.ptr; + if (p + p->s.size == bp) { + p->s.size += bp->s.size; + p->s.ptr = bp->s.ptr; + } else + p->s.ptr = bp; + freep = p; +} + +static Header * +morecore(uint nu) +{ + char *cp; + Header *up; + + if (nu < PAGE) + nu = PAGE; + cp = sbrk(nu * sizeof(Header)); + if (cp == (char *) -1) + return 0; + up = (Header *) cp; + up->s.size = nu; + free((void *)(up + 1)); + return freep; +} + +void * +malloc(uint nbytes) +{ + Header *p, *prevp; + uint nunits; + + nunits = (nbytes + sizeof(Header) - 1)/sizeof(Header) + 1; + if ((prevp = freep) == 0) { + base.s.ptr = freep = prevp = &base; + base.s.size = 0; + } + for (p = prevp->s.ptr; ; prevp = p, p = p->s.ptr) { + if (p->s.size >= nunits) { + if (p->s.size == nunits) + prevp->s.ptr = p->s.ptr; + else { + p->s.size -= nunits; + p += p->s.size; + p->s.size = nunits; + } + freep = prevp; + return (void *) (p + 1); + } + if (p == freep) + if ((p = morecore(nunits)) == 0) + return 0; + } +} diff --git a/user.h b/user.h index cc82ccf..b5ea91d 100644 --- a/user.h +++ b/user.h @@ -19,6 +19,7 @@ int mkdir(char *); int chdir(char *); int dup(int); int getpid(); +char *sbrk(int); int stat(char *, struct stat *stat); int puts(char*); @@ -29,3 +30,5 @@ void printf(int fd, char *fmt, ...); char *gets(char *, int max); unsigned int strlen(char *); void * memset(void *dst, int c, unsigned int n); +void *mallic(uint); +void free(void *); diff --git a/userfs.c b/userfs.c index d1cd49e..54bc334 100644 --- a/userfs.c +++ b/userfs.c @@ -21,7 +21,7 @@ main(void) printf(stdout, "userfs is running\n"); if (sbrk(4096) < 0) { - printf(stdout, "sbrk failed\n"); + printf(stdout, "sbrk failed\n"); } fd = open("echo", 0); @@ -46,10 +46,10 @@ main(void) } for (i = 0; i < 100; i++) { if (write (fd, "aaaaaaaaaa", 10) != 10) { - printf(stdout, "error: write new file failed\n"); + printf(stdout, "error: write aa %d new file failed\n", i); } if (write (fd, "bbbbbbbbbb", 10) != 10) { - printf(stdout, "error: write new file failed\n"); + printf(stdout, "error: write bb %d new file failed\n", i); } } printf(stdout, "writes done\n");