00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "types.h"
00014 #include "defs.h"
00015 #include "param.h"
00016 #include "stat.h"
00017 #include "mmu.h"
00018 #include "proc.h"
00019 #include "spinlock.h"
00020 #include "buf.h"
00021 #include "fs.h"
00022 #include "file.h"
00023
00024 #define min(a, b) ((a) < (b) ? (a) : (b))
00025 static void itrunc(struct inode*);
00026
00027
00028 static void
00029 readsb(int dev, struct superblock *sb)
00030 {
00031 struct buf *bp;
00032
00033 bp = bread(dev, 1);
00034 memmove(sb, bp->data, sizeof(*sb));
00035 brelse(bp);
00036 }
00037
00038
00039 static void
00040 bzero(int dev, int bno)
00041 {
00042 struct buf *bp;
00043
00044 bp = bread(dev, bno);
00045 memset(bp->data, 0, BSIZE);
00046 bwrite(bp);
00047 brelse(bp);
00048 }
00049
00050
00051
00052
00053 static uint
00054 balloc(uint dev)
00055 {
00056 int b, bi, m;
00057 struct buf *bp;
00058 struct superblock sb;
00059
00060 bp = 0;
00061 readsb(dev, &sb);
00062 for(b = 0; b < sb.size; b += BPB){
00063 bp = bread(dev, BBLOCK(b, sb.ninodes));
00064 for(bi = 0; bi < BPB; bi++){
00065 m = 1 << (bi % 8);
00066 if((bp->data[bi/8] & m) == 0){
00067 bp->data[bi/8] |= m;
00068 bwrite(bp);
00069 brelse(bp);
00070 return b + bi;
00071 }
00072 }
00073 brelse(bp);
00074 }
00075 panic("balloc: out of blocks");
00076 }
00077
00078
00079 static void
00080 bfree(int dev, uint b)
00081 {
00082 struct buf *bp;
00083 struct superblock sb;
00084 int bi, m;
00085
00086 bzero(dev, b);
00087
00088 readsb(dev, &sb);
00089 bp = bread(dev, BBLOCK(b, sb.ninodes));
00090 bi = b % BPB;
00091 m = 1 << (bi % 8);
00092 if((bp->data[bi/8] & m) == 0)
00093 panic("freeing free block");
00094 bp->data[bi/8] &= ~m;
00095 bwrite(bp);
00096 brelse(bp);
00097 }
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132 struct {
00133 struct spinlock lock;
00134 struct inode inode[NINODE];
00135 } icache;
00136
00137 void
00138 iinit(void)
00139 {
00140 initlock(&icache.lock, "icache");
00141 }
00142
00143 static struct inode* iget(uint dev, uint inum);
00144
00145
00146 struct inode*
00147 ialloc(uint dev, short type)
00148 {
00149 int inum;
00150 struct buf *bp;
00151 struct dinode *dip;
00152 struct superblock sb;
00153
00154 readsb(dev, &sb);
00155 for(inum = 1; inum < sb.ninodes; inum++){
00156 bp = bread(dev, IBLOCK(inum));
00157 dip = (struct dinode*)bp->data + inum%IPB;
00158 if(dip->type == 0){
00159 memset(dip, 0, sizeof(*dip));
00160 dip->type = type;
00161 bwrite(bp);
00162 brelse(bp);
00163 return iget(dev, inum);
00164 }
00165 brelse(bp);
00166 }
00167 panic("ialloc: no inodes");
00168 }
00169
00170
00171 void
00172 iupdate(struct inode *ip)
00173 {
00174 struct buf *bp;
00175 struct dinode *dip;
00176
00177 bp = bread(ip->dev, IBLOCK(ip->inum));
00178 dip = (struct dinode*)bp->data + ip->inum%IPB;
00179 dip->type = ip->type;
00180 dip->major = ip->major;
00181 dip->minor = ip->minor;
00182 dip->nlink = ip->nlink;
00183 dip->size = ip->size;
00184 memmove(dip->addrs, ip->addrs, sizeof(ip->addrs));
00185 bwrite(bp);
00186 brelse(bp);
00187 }
00188
00189
00190
00191 static struct inode*
00192 iget(uint dev, uint inum)
00193 {
00194 struct inode *ip, *empty;
00195
00196 acquire(&icache.lock);
00197
00198
00199 empty = 0;
00200 for(ip = &icache.inode[0]; ip < &icache.inode[NINODE]; ip++){
00201 if(ip->ref > 0 && ip->dev == dev && ip->inum == inum){
00202 ip->ref++;
00203 release(&icache.lock);
00204 return ip;
00205 }
00206 if(empty == 0 && ip->ref == 0)
00207 empty = ip;
00208 }
00209
00210
00211 if(empty == 0)
00212 panic("iget: no inodes");
00213
00214 ip = empty;
00215 ip->dev = dev;
00216 ip->inum = inum;
00217 ip->ref = 1;
00218 ip->flags = 0;
00219 release(&icache.lock);
00220
00221 return ip;
00222 }
00223
00224
00225
00226 struct inode*
00227 idup(struct inode *ip)
00228 {
00229 acquire(&icache.lock);
00230 ip->ref++;
00231 release(&icache.lock);
00232 return ip;
00233 }
00234
00235
00236 void
00237 ilock(struct inode *ip)
00238 {
00239 struct buf *bp;
00240 struct dinode *dip;
00241
00242 if(ip == 0 || ip->ref < 1)
00243 panic("ilock");
00244
00245 acquire(&icache.lock);
00246 while(ip->flags & I_BUSY)
00247 sleep(ip, &icache.lock);
00248 ip->flags |= I_BUSY;
00249 release(&icache.lock);
00250
00251 if(!(ip->flags & I_VALID)){
00252 bp = bread(ip->dev, IBLOCK(ip->inum));
00253 dip = (struct dinode*)bp->data + ip->inum%IPB;
00254 ip->type = dip->type;
00255 ip->major = dip->major;
00256 ip->minor = dip->minor;
00257 ip->nlink = dip->nlink;
00258 ip->size = dip->size;
00259 memmove(ip->addrs, dip->addrs, sizeof(ip->addrs));
00260 brelse(bp);
00261 ip->flags |= I_VALID;
00262 if(ip->type == 0)
00263 panic("ilock: no type");
00264 }
00265 }
00266
00267
00268 void
00269 iunlock(struct inode *ip)
00270 {
00271 if(ip == 0 || !(ip->flags & I_BUSY) || ip->ref < 1)
00272 panic("iunlock");
00273
00274 acquire(&icache.lock);
00275 ip->flags &= ~I_BUSY;
00276 wakeup(ip);
00277 release(&icache.lock);
00278 }
00279
00280
00281 void
00282 iput(struct inode *ip)
00283 {
00284 acquire(&icache.lock);
00285 if(ip->ref == 1 && (ip->flags & I_VALID) && ip->nlink == 0){
00286
00287 if(ip->flags & I_BUSY)
00288 panic("iput busy");
00289 ip->flags |= I_BUSY;
00290 release(&icache.lock);
00291 itrunc(ip);
00292 ip->type = 0;
00293 iupdate(ip);
00294 acquire(&icache.lock);
00295 ip->flags = 0;
00296 wakeup(ip);
00297 }
00298 ip->ref--;
00299 release(&icache.lock);
00300 }
00301
00302
00303 void
00304 iunlockput(struct inode *ip)
00305 {
00306 iunlock(ip);
00307 iput(ip);
00308 }
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319 static uint
00320 bmap(struct inode *ip, uint bn)
00321 {
00322 uint addr, *a;
00323 struct buf *bp;
00324
00325 if(bn < NDIRECT){
00326 if((addr = ip->addrs[bn]) == 0)
00327 ip->addrs[bn] = addr = balloc(ip->dev);
00328 return addr;
00329 }
00330 bn -= NDIRECT;
00331
00332 if(bn < NINDIRECT){
00333
00334 if((addr = ip->addrs[NDIRECT]) == 0)
00335 ip->addrs[NDIRECT] = addr = balloc(ip->dev);
00336 bp = bread(ip->dev, addr);
00337 a = (uint*)bp->data;
00338 if((addr = a[bn]) == 0){
00339 a[bn] = addr = balloc(ip->dev);
00340 bwrite(bp);
00341 }
00342 brelse(bp);
00343 return addr;
00344 }
00345
00346 panic("bmap: out of range");
00347 }
00348
00349
00350
00351
00352 static void
00353 itrunc(struct inode *ip)
00354 {
00355 int i, j;
00356 struct buf *bp;
00357 uint *a;
00358
00359 for(i = 0; i < NDIRECT; i++){
00360 if(ip->addrs[i]){
00361 bfree(ip->dev, ip->addrs[i]);
00362 ip->addrs[i] = 0;
00363 }
00364 }
00365
00366 if(ip->addrs[NDIRECT]){
00367 bp = bread(ip->dev, ip->addrs[NDIRECT]);
00368 a = (uint*)bp->data;
00369 for(j = 0; j < NINDIRECT; j++){
00370 if(a[j])
00371 bfree(ip->dev, a[j]);
00372 }
00373 brelse(bp);
00374 bfree(ip->dev, ip->addrs[NDIRECT]);
00375 ip->addrs[NDIRECT] = 0;
00376 }
00377
00378 ip->size = 0;
00379 iupdate(ip);
00380 }
00381
00382
00383 void
00384 stati(struct inode *ip, struct stat *st)
00385 {
00386 st->dev = ip->dev;
00387 st->ino = ip->inum;
00388 st->type = ip->type;
00389 st->nlink = ip->nlink;
00390 st->size = ip->size;
00391 }
00392
00393
00394 int
00395 readi(struct inode *ip, char *dst, uint off, uint n)
00396 {
00397 uint tot, m;
00398 struct buf *bp;
00399
00400 if(ip->type == T_DEV){
00401 if(ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].read)
00402 return -1;
00403 return devsw[ip->major].read(ip, dst, n);
00404 }
00405
00406 if(off > ip->size || off + n < off)
00407 return -1;
00408 if(off + n > ip->size)
00409 n = ip->size - off;
00410
00411 for(tot=0; tot<n; tot+=m, off+=m, dst+=m){
00412 bp = bread(ip->dev, bmap(ip, off/BSIZE));
00413 m = min(n - tot, BSIZE - off%BSIZE);
00414 memmove(dst, bp->data + off%BSIZE, m);
00415 brelse(bp);
00416 }
00417 return n;
00418 }
00419
00420
00421 int
00422 writei(struct inode *ip, char *src, uint off, uint n)
00423 {
00424 uint tot, m;
00425 struct buf *bp;
00426
00427 if(ip->type == T_DEV){
00428 if(ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].write)
00429 return -1;
00430 return devsw[ip->major].write(ip, src, n);
00431 }
00432
00433 if(off > ip->size || off + n < off)
00434 return -1;
00435 if(off + n > MAXFILE*BSIZE)
00436 n = MAXFILE*BSIZE - off;
00437
00438 for(tot=0; tot<n; tot+=m, off+=m, src+=m){
00439 bp = bread(ip->dev, bmap(ip, off/BSIZE));
00440 m = min(n - tot, BSIZE - off%BSIZE);
00441 memmove(bp->data + off%BSIZE, src, m);
00442 bwrite(bp);
00443 brelse(bp);
00444 }
00445
00446 if(n > 0 && off > ip->size){
00447 ip->size = off;
00448 iupdate(ip);
00449 }
00450 return n;
00451 }
00452
00453
00454
00455 int
00456 namecmp(const char *s, const char *t)
00457 {
00458 return strncmp(s, t, DIRSIZ);
00459 }
00460
00461
00462
00463
00464 struct inode*
00465 dirlookup(struct inode *dp, char *name, uint *poff)
00466 {
00467 uint off, inum;
00468 struct buf *bp;
00469 struct dirent *de;
00470
00471 if(dp->type != T_DIR)
00472 panic("dirlookup not DIR");
00473
00474 for(off = 0; off < dp->size; off += BSIZE){
00475 bp = bread(dp->dev, bmap(dp, off / BSIZE));
00476 for(de = (struct dirent*)bp->data;
00477 de < (struct dirent*)(bp->data + BSIZE);
00478 de++){
00479 if(de->inum == 0)
00480 continue;
00481 if(namecmp(name, de->name) == 0){
00482
00483 if(poff)
00484 *poff = off + (uchar*)de - bp->data;
00485 inum = de->inum;
00486 brelse(bp);
00487 return iget(dp->dev, inum);
00488 }
00489 }
00490 brelse(bp);
00491 }
00492 return 0;
00493 }
00494
00495
00496 int
00497 dirlink(struct inode *dp, char *name, uint inum)
00498 {
00499 int off;
00500 struct dirent de;
00501 struct inode *ip;
00502
00503
00504 if((ip = dirlookup(dp, name, 0)) != 0){
00505 iput(ip);
00506 return -1;
00507 }
00508
00509
00510 for(off = 0; off < dp->size; off += sizeof(de)){
00511 if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
00512 panic("dirlink read");
00513 if(de.inum == 0)
00514 break;
00515 }
00516
00517 strncpy(de.name, name, DIRSIZ);
00518 de.inum = inum;
00519 if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
00520 panic("dirlink");
00521
00522 return 0;
00523 }
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539 static char*
00540 skipelem(char *path, char *name)
00541 {
00542 char *s;
00543 int len;
00544
00545 while(*path == '/')
00546 path++;
00547 if(*path == 0)
00548 return 0;
00549 s = path;
00550 while(*path != '/' && *path != 0)
00551 path++;
00552 len = path - s;
00553 if(len >= DIRSIZ)
00554 memmove(name, s, DIRSIZ);
00555 else {
00556 memmove(name, s, len);
00557 name[len] = 0;
00558 }
00559 while(*path == '/')
00560 path++;
00561 return path;
00562 }
00563
00564
00565
00566
00567 static struct inode*
00568 namex(char *path, int nameiparent, char *name)
00569 {
00570 struct inode *ip, *next;
00571
00572 if(*path == '/')
00573 ip = iget(ROOTDEV, ROOTINO);
00574 else
00575 ip = idup(proc->cwd);
00576
00577 while((path = skipelem(path, name)) != 0){
00578 ilock(ip);
00579 if(ip->type != T_DIR){
00580 iunlockput(ip);
00581 return 0;
00582 }
00583 if(nameiparent && *path == '\0'){
00584
00585 iunlock(ip);
00586 return ip;
00587 }
00588 if((next = dirlookup(ip, name, 0)) == 0){
00589 iunlockput(ip);
00590 return 0;
00591 }
00592 iunlockput(ip);
00593 ip = next;
00594 }
00595 if(nameiparent){
00596 iput(ip);
00597 return 0;
00598 }
00599 return ip;
00600 }
00601
00602 struct inode*
00603 namei(char *path)
00604 {
00605 char name[DIRSIZ];
00606 return namex(path, 0, name);
00607 }
00608
00609 struct inode*
00610 nameiparent(char *path, char *name)
00611 {
00612 return namex(path, 1, name);
00613 }