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