This source file includes following definitions.
- readsb
- fsinit
- bzero
- balloc
- bfree
- iinit
- ialloc
- iupdate
- iget
- idup
- ilock
- iunlock
- iput
- iunlockput
- ireclaim
- bmap
- itrunc
- stati
- readi
- writei
- namecmp
- dirlookup
- dirlink
- skipelem
- namex
- namei
- nameiparent
1
2
3
4
5
6
7
8
9
10
11
12 #include "types.h"
13 #include "riscv.h"
14 #include "defs.h"
15 #include "param.h"
16 #include "stat.h"
17 #include "spinlock.h"
18 #include "proc.h"
19 #include "sleeplock.h"
20 #include "fs.h"
21 #include "buf.h"
22 #include "file.h"
23
24 #define min(a, b) ((a) < (b) ? (a) : (b))
25
26
27 struct superblock sb;
28
29
30 static void
31 readsb(int dev, struct superblock *sb)
32 {
33 struct buf *bp;
34
35 bp = bread(dev, 1);
36 memmove(sb, bp->data, sizeof(*sb));
37 brelse(bp);
38 }
39
40
41 void
42 fsinit(int dev) {
43 readsb(dev, &sb);
44 if(sb.magic != FSMAGIC)
45 panic("invalid file system");
46 initlog(dev, &sb);
47 ireclaim(dev);
48 }
49
50
51 static void
52 bzero(int dev, int bno)
53 {
54 struct buf *bp;
55
56 bp = bread(dev, bno);
57 memset(bp->data, 0, BSIZE);
58 log_write(bp);
59 brelse(bp);
60 }
61
62
63
64
65
66 static uint
67 balloc(uint dev)
68 {
69 int b, bi, m;
70 struct buf *bp;
71
72 bp = 0;
73 for(b = 0; b < sb.size; b += BPB){
74 bp = bread(dev, BBLOCK(b, sb));
75 for(bi = 0; bi < BPB && b + bi < sb.size; bi++){
76 m = 1 << (bi % 8);
77 if((bp->data[bi/8] & m) == 0){
78 bp->data[bi/8] |= m;
79 log_write(bp);
80 brelse(bp);
81 bzero(dev, b + bi);
82 return b + bi;
83 }
84 }
85 brelse(bp);
86 }
87 printf("balloc: out of blocks\n");
88 return 0;
89 }
90
91
92 static void
93 bfree(int dev, uint b)
94 {
95 struct buf *bp;
96 int bi, m;
97
98 bp = bread(dev, BBLOCK(b, sb));
99 bi = b % BPB;
100 m = 1 << (bi % 8);
101 if((bp->data[bi/8] & m) == 0)
102 panic("freeing free block");
103 bp->data[bi/8] &= ~m;
104 log_write(bp);
105 brelse(bp);
106 }
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177 struct {
178 struct spinlock lock;
179 struct inode inode[NINODE];
180 } itable;
181
182 void
183 iinit()
184 {
185 int i = 0;
186
187 initlock(&itable.lock, "itable");
188 for(i = 0; i < NINODE; i++) {
189 initsleeplock(&itable.inode[i].lock, "inode");
190 }
191 }
192
193 static struct inode* iget(uint dev, uint inum);
194
195
196
197
198
199 struct inode*
200 ialloc(uint dev, short type)
201 {
202 int inum;
203 struct buf *bp;
204 struct dinode *dip;
205
206 for(inum = 1; inum < sb.ninodes; inum++){
207 bp = bread(dev, IBLOCK(inum, sb));
208 dip = (struct dinode*)bp->data + inum%IPB;
209 if(dip->type == 0){
210 memset(dip, 0, sizeof(*dip));
211 dip->type = type;
212 log_write(bp);
213 brelse(bp);
214 return iget(dev, inum);
215 }
216 brelse(bp);
217 }
218 printf("ialloc: no inodes\n");
219 return 0;
220 }
221
222
223
224
225
226 void
227 iupdate(struct inode *ip)
228 {
229 struct buf *bp;
230 struct dinode *dip;
231
232 bp = bread(ip->dev, IBLOCK(ip->inum, sb));
233 dip = (struct dinode*)bp->data + ip->inum%IPB;
234 dip->type = ip->type;
235 dip->major = ip->major;
236 dip->minor = ip->minor;
237 dip->nlink = ip->nlink;
238 dip->size = ip->size;
239 memmove(dip->addrs, ip->addrs, sizeof(ip->addrs));
240 log_write(bp);
241 brelse(bp);
242 }
243
244
245
246
247 static struct inode*
248 iget(uint dev, uint inum)
249 {
250 struct inode *ip, *empty;
251
252 acquire(&itable.lock);
253
254
255 empty = 0;
256 for(ip = &itable.inode[0]; ip < &itable.inode[NINODE]; ip++){
257 if(ip->ref > 0 && ip->dev == dev && ip->inum == inum){
258 ip->ref++;
259 release(&itable.lock);
260 return ip;
261 }
262 if(empty == 0 && ip->ref == 0)
263 empty = ip;
264 }
265
266
267 if(empty == 0)
268 panic("iget: no inodes");
269
270 ip = empty;
271 ip->dev = dev;
272 ip->inum = inum;
273 ip->ref = 1;
274 ip->valid = 0;
275 release(&itable.lock);
276
277 return ip;
278 }
279
280
281
282 struct inode*
283 idup(struct inode *ip)
284 {
285 acquire(&itable.lock);
286 ip->ref++;
287 release(&itable.lock);
288 return ip;
289 }
290
291
292
293 void
294 ilock(struct inode *ip)
295 {
296 struct buf *bp;
297 struct dinode *dip;
298
299 if(ip == 0 || ip->ref < 1)
300 panic("ilock");
301
302 acquiresleep(&ip->lock);
303
304 if(ip->valid == 0){
305 bp = bread(ip->dev, IBLOCK(ip->inum, sb));
306 dip = (struct dinode*)bp->data + ip->inum%IPB;
307 ip->type = dip->type;
308 ip->major = dip->major;
309 ip->minor = dip->minor;
310 ip->nlink = dip->nlink;
311 ip->size = dip->size;
312 memmove(ip->addrs, dip->addrs, sizeof(ip->addrs));
313 brelse(bp);
314 ip->valid = 1;
315 if(ip->type == 0)
316 panic("ilock: no type");
317 }
318 }
319
320
321 void
322 iunlock(struct inode *ip)
323 {
324 if(ip == 0 || !holdingsleep(&ip->lock) || ip->ref < 1)
325 panic("iunlock");
326
327 releasesleep(&ip->lock);
328 }
329
330
331
332
333
334
335
336
337 void
338 iput(struct inode *ip)
339 {
340 acquire(&itable.lock);
341
342 if(ip->ref == 1 && ip->valid && ip->nlink == 0){
343
344
345
346
347 acquiresleep(&ip->lock);
348
349 release(&itable.lock);
350
351 itrunc(ip);
352 ip->type = 0;
353 iupdate(ip);
354 ip->valid = 0;
355
356 releasesleep(&ip->lock);
357
358 acquire(&itable.lock);
359 }
360
361 ip->ref--;
362 release(&itable.lock);
363 }
364
365
366 void
367 iunlockput(struct inode *ip)
368 {
369 iunlock(ip);
370 iput(ip);
371 }
372
373 void
374 ireclaim(int dev)
375 {
376 for (int inum = 1; inum < sb.ninodes; inum++) {
377 struct inode *ip = 0;
378 struct buf *bp = bread(dev, IBLOCK(inum, sb));
379 struct dinode *dip = (struct dinode *)bp->data + inum % IPB;
380 if (dip->type != 0 && dip->nlink == 0) {
381 printf("ireclaim: orphaned inode %d\n", inum);
382 ip = iget(dev, inum);
383 }
384 brelse(bp);
385 if (ip) {
386 begin_op();
387 ilock(ip);
388 iunlock(ip);
389 iput(ip);
390 end_op();
391 }
392 }
393 }
394
395
396
397
398
399
400
401
402
403
404
405 static uint
406 bmap(struct inode *ip, uint bn)
407 {
408 uint addr, *a;
409 struct buf *bp;
410
411 if(bn < NDIRECT){
412 if((addr = ip->addrs[bn]) == 0){
413 addr = balloc(ip->dev);
414 if(addr == 0)
415 return 0;
416 ip->addrs[bn] = addr;
417 }
418 return addr;
419 }
420 bn -= NDIRECT;
421
422 if(bn < NINDIRECT){
423
424 if((addr = ip->addrs[NDIRECT]) == 0){
425 addr = balloc(ip->dev);
426 if(addr == 0)
427 return 0;
428 ip->addrs[NDIRECT] = addr;
429 }
430 bp = bread(ip->dev, addr);
431 a = (uint*)bp->data;
432 if((addr = a[bn]) == 0){
433 addr = balloc(ip->dev);
434 if(addr){
435 a[bn] = addr;
436 log_write(bp);
437 }
438 }
439 brelse(bp);
440 return addr;
441 }
442
443 panic("bmap: out of range");
444 }
445
446
447
448 void
449 itrunc(struct inode *ip)
450 {
451 int i, j;
452 struct buf *bp;
453 uint *a;
454
455 for(i = 0; i < NDIRECT; i++){
456 if(ip->addrs[i]){
457 bfree(ip->dev, ip->addrs[i]);
458 ip->addrs[i] = 0;
459 }
460 }
461
462 if(ip->addrs[NDIRECT]){
463 bp = bread(ip->dev, ip->addrs[NDIRECT]);
464 a = (uint*)bp->data;
465 for(j = 0; j < NINDIRECT; j++){
466 if(a[j])
467 bfree(ip->dev, a[j]);
468 }
469 brelse(bp);
470 bfree(ip->dev, ip->addrs[NDIRECT]);
471 ip->addrs[NDIRECT] = 0;
472 }
473
474 ip->size = 0;
475 iupdate(ip);
476 }
477
478
479
480 void
481 stati(struct inode *ip, struct stat *st)
482 {
483 st->dev = ip->dev;
484 st->ino = ip->inum;
485 st->type = ip->type;
486 st->nlink = ip->nlink;
487 st->size = ip->size;
488 }
489
490
491
492
493
494 int
495 readi(struct inode *ip, int user_dst, uint64 dst, uint off, uint n)
496 {
497 uint tot, m;
498 struct buf *bp;
499
500 if(off > ip->size || off + n < off)
501 return 0;
502 if(off + n > ip->size)
503 n = ip->size - off;
504
505 for(tot=0; tot<n; tot+=m, off+=m, dst+=m){
506 uint addr = bmap(ip, off/BSIZE);
507 if(addr == 0)
508 break;
509 bp = bread(ip->dev, addr);
510 m = min(n - tot, BSIZE - off%BSIZE);
511 if(either_copyout(user_dst, dst, bp->data + (off % BSIZE), m) == -1) {
512 brelse(bp);
513 tot = -1;
514 break;
515 }
516 brelse(bp);
517 }
518 return tot;
519 }
520
521
522
523
524
525
526
527
528 int
529 writei(struct inode *ip, int user_src, uint64 src, uint off, uint n)
530 {
531 uint tot, m;
532 struct buf *bp;
533
534 if(off > ip->size || off + n < off)
535 return -1;
536 if(off + n > MAXFILE*BSIZE)
537 return -1;
538
539 for(tot=0; tot<n; tot+=m, off+=m, src+=m){
540 uint addr = bmap(ip, off/BSIZE);
541 if(addr == 0)
542 break;
543 bp = bread(ip->dev, addr);
544 m = min(n - tot, BSIZE - off%BSIZE);
545 if(either_copyin(bp->data + (off % BSIZE), user_src, src, m) == -1) {
546 brelse(bp);
547 break;
548 }
549 log_write(bp);
550 brelse(bp);
551 }
552
553 if(off > ip->size)
554 ip->size = off;
555
556
557
558
559 iupdate(ip);
560
561 return tot;
562 }
563
564
565
566 int
567 namecmp(const char *s, const char *t)
568 {
569 return strncmp(s, t, DIRSIZ);
570 }
571
572
573
574 struct inode*
575 dirlookup(struct inode *dp, char *name, uint *poff)
576 {
577 uint off, inum;
578 struct dirent de;
579
580 if(dp->type != T_DIR)
581 panic("dirlookup not DIR");
582
583 for(off = 0; off < dp->size; off += sizeof(de)){
584 if(readi(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))
585 panic("dirlookup read");
586 if(de.inum == 0)
587 continue;
588 if(namecmp(name, de.name) == 0){
589
590 if(poff)
591 *poff = off;
592 inum = de.inum;
593 return iget(dp->dev, inum);
594 }
595 }
596
597 return 0;
598 }
599
600
601
602 int
603 dirlink(struct inode *dp, char *name, uint inum)
604 {
605 int off;
606 struct dirent de;
607 struct inode *ip;
608
609
610 if((ip = dirlookup(dp, name, 0)) != 0){
611 iput(ip);
612 return -1;
613 }
614
615
616 for(off = 0; off < dp->size; off += sizeof(de)){
617 if(readi(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))
618 panic("dirlink read");
619 if(de.inum == 0)
620 break;
621 }
622
623 strncpy(de.name, name, DIRSIZ);
624 de.inum = inum;
625 if(writei(dp, 0, (uint64)&de, off, sizeof(de)) != sizeof(de))
626 return -1;
627
628 return 0;
629 }
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645 static char*
646 skipelem(char *path, char *name)
647 {
648 char *s;
649 int len;
650
651 while(*path == '/')
652 path++;
653 if(*path == 0)
654 return 0;
655 s = path;
656 while(*path != '/' && *path != 0)
657 path++;
658 len = path - s;
659 if(len >= DIRSIZ)
660 memmove(name, s, DIRSIZ);
661 else {
662 memmove(name, s, len);
663 name[len] = 0;
664 }
665 while(*path == '/')
666 path++;
667 return path;
668 }
669
670
671
672
673
674 static struct inode*
675 namex(char *path, int nameiparent, char *name)
676 {
677 struct inode *ip, *next;
678
679 if(*path == '/')
680 ip = iget(ROOTDEV, ROOTINO);
681 else
682 ip = idup(myproc()->cwd);
683
684 while((path = skipelem(path, name)) != 0){
685 ilock(ip);
686 if(ip->type != T_DIR){
687 iunlockput(ip);
688 return 0;
689 }
690 if(nameiparent && *path == '\0'){
691
692 iunlock(ip);
693 return ip;
694 }
695 if((next = dirlookup(ip, name, 0)) == 0){
696 iunlockput(ip);
697 return 0;
698 }
699 iunlockput(ip);
700 ip = next;
701 }
702 if(nameiparent){
703 iput(ip);
704 return 0;
705 }
706 return ip;
707 }
708
709 struct inode*
710 namei(char *path)
711 {
712 char name[DIRSIZ];
713 return namex(path, 0, name);
714 }
715
716 struct inode*
717 nameiparent(char *path, char *name)
718 {
719 return namex(path, 1, name);
720 }