This source file includes following definitions.
- size2cqueue
- bremfree
- buf_init
- buf_stub
- buf_get
- buf_put
- bufinit
- bio_doread
- bread
- breadn
- bread_cluster_callback
- bread_cluster
- bwrite
- bdwrite
- bawrite
- buf_dirty
- buf_undirty
- brelse
- incore
- getblk
- geteblk
- getnewbuf
- buf_daemon
- biowait
- biodone
- vfs_bufstats
- vfs_bufstats
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/proc.h>
51 #include <sys/buf.h>
52 #include <sys/vnode.h>
53 #include <sys/mount.h>
54 #include <sys/malloc.h>
55 #include <sys/pool.h>
56 #include <sys/resourcevar.h>
57 #include <sys/conf.h>
58 #include <sys/kernel.h>
59
60 #include <uvm/uvm_extern.h>
61
62 #include <miscfs/specfs/specdev.h>
63
64
65
66
67 #define BUFHASH(dvp, lbn) \
68 (&bufhashtbl[((long)(dvp) / sizeof(*(dvp)) + (int)(lbn)) & bufhash])
69 LIST_HEAD(bufhashhdr, buf) *bufhashtbl, invalhash;
70 u_long bufhash;
71
72
73
74
75 #define binshash(bp, dp) LIST_INSERT_HEAD(dp, bp, b_hash)
76 #define bremhash(bp) LIST_REMOVE(bp, b_hash)
77
78
79
80
81 #define BQUEUES 6
82
83 #define BQ_DIRTY 0
84
85
86 TAILQ_HEAD(bqueues, buf) bufqueues[BQUEUES];
87 int bqpages[BQUEUES];
88 int bqpagelow;
89 int needbuffer;
90 struct bio_ops bioops;
91
92
93
94
95 struct pool bufpool;
96 struct vm_map *buf_map;
97 struct bufhead bufhead = LIST_HEAD_INITIALIZER(bufhead);
98 struct buf *buf_get(size_t);
99 struct buf *buf_stub(struct vnode *, daddr64_t);
100 void buf_put(struct buf *);
101
102
103
104
105 #define binsheadfree(bp, dp) TAILQ_INSERT_HEAD(dp, bp, b_freelist)
106 #define binstailfree(bp, dp) TAILQ_INSERT_TAIL(dp, bp, b_freelist)
107
108 struct buf *bio_doread(struct vnode *, daddr64_t, int, int);
109 struct buf *getnewbuf(size_t, int, int, int *);
110 void buf_init(struct buf *, int);
111 void bread_cluster_callback(struct buf *);
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126 long numbufpages;
127 long numdirtypages;
128 long lodirtypages;
129 long hidirtypages;
130 long numfreepages;
131 long numcleanpages;
132 long locleanpages;
133 long hicleanpages;
134 long maxcleanpages;
135
136 struct proc *cleanerproc;
137 int bd_req;
138
139 int size2cqueue(int *size);
140
141 int
142 size2cqueue(int *size)
143 {
144 int i = 0, q;
145 int s = *size;
146 s -= 1;
147 while (s > 0) {
148 s = s >> 1;
149 i++;
150 }
151 if (i < PAGE_SHIFT) {
152 i = PAGE_SHIFT;
153 }
154 *size = 1 << i;
155 q = (i + 1 - PAGE_SHIFT);
156 if (q >= BQUEUES)
157 panic("queue %d > BQUEUES %d", q, BQUEUES);
158 if (q == 0)
159 panic("can't return dirty q");
160 return(q);
161 }
162
163 void
164 bremfree(struct buf *bp)
165 {
166 struct bqueues *dp = NULL;
167 int queue;
168
169
170
171
172
173
174
175
176 if (TAILQ_NEXT(bp, b_freelist) == NULL) {
177 for (dp = bufqueues; dp < &bufqueues[BQUEUES]; dp++)
178 if (dp->tqh_last == &TAILQ_NEXT(bp, b_freelist))
179 break;
180 if (dp == &bufqueues[BQUEUES])
181 panic("bremfree: lost tail");
182 }
183 numfreepages -= btoc(bp->b_bufsize);
184 if (!ISSET(bp->b_flags, B_DELWRI)) {
185 int qs = bp->b_bufsize;
186 queue = size2cqueue(&qs);
187 numcleanpages -= btoc(bp->b_bufsize);
188 bqpages[queue] -= btoc(bp->b_bufsize);
189 } else
190 numdirtypages -= btoc(bp->b_bufsize);
191 TAILQ_REMOVE(dp, bp, b_freelist);
192 }
193
194 void
195 buf_init(struct buf *bp, int size)
196 {
197 int npages, queue;
198
199 splassert(IPL_BIO);
200
201 npages = btoc(size);
202 bzero((char *)bp, sizeof *bp);
203 bp->b_vnbufs.le_next = NOLIST;
204 bp->b_freelist.tqe_next = NOLIST;
205 bp->b_synctime = time_uptime + 300;
206 bp->b_dev = NODEV;
207 queue = size2cqueue(&size);
208 LIST_INIT(&bp->b_dep);
209 numbufpages += npages;
210 numfreepages += npages;
211 numcleanpages += npages;
212 bqpages[queue] += npages;
213 if (maxcleanpages < numcleanpages)
214 maxcleanpages = numcleanpages;
215 }
216
217
218
219
220
221 struct buf *
222 buf_stub(struct vnode *vp, daddr64_t lblkno)
223 {
224 struct buf *bp;
225 int s;
226
227 s = splbio();
228 bp = pool_get(&bufpool, PR_NOWAIT);
229 splx(s);
230
231 if (bp == NULL)
232 return (NULL);
233
234 bzero((char *)bp, sizeof *bp);
235 bp->b_vnbufs.le_next = NOLIST;
236 bp->b_freelist.tqe_next = NOLIST;
237 bp->b_synctime = time_uptime + 300;
238 bp->b_dev = NODEV;
239 bp->b_bufsize = 0;
240 bp->b_data = NULL;
241 bp->b_flags = B_BUSY;
242 bp->b_dev = NODEV;
243 bp->b_blkno = bp->b_lblkno = lblkno;
244 bp->b_iodone = NULL;
245 bp->b_error = 0;
246 bp->b_resid = 0;
247 bp->b_bcount = 0;
248 bp->b_dirtyoff = bp->b_dirtyend = 0;
249 bp->b_validoff = bp->b_validend = 0;
250
251 LIST_INIT(&bp->b_dep);
252
253 s = splbio();
254 LIST_INSERT_HEAD(&bufhead, bp, b_list);
255 bgetvp(vp, bp);
256 splx(s);
257
258 return (bp);
259 }
260
261 struct buf *
262 buf_get(size_t size)
263 {
264 struct bqueues *dp;
265 struct buf *bp;
266 int npages;
267 int queue, qs;
268 void *data;
269
270 splassert(IPL_BIO);
271
272 KASSERT(size > 0);
273
274 size = round_page(size);
275 qs = size;
276 queue = size2cqueue(&qs);
277 npages = btoc(qs);
278
279 if (numbufpages + npages > bufpages)
280 return (NULL);
281
282 bp = pool_get(&bufpool, PR_WAITOK);
283
284 data = (void *)uvm_km_alloc(buf_map, qs);
285 if (data == NULL) {
286 pool_put(&bufpool, bp);
287 return (NULL);
288 }
289 buf_init(bp, qs);
290 bp->b_flags = B_INVAL;
291 bp->b_bufsize = qs;
292 bp->b_data = data;
293 dp = &bufqueues[queue];
294 binsheadfree(bp, dp);
295 binshash(bp, &invalhash);
296 LIST_INSERT_HEAD(&bufhead, bp, b_list);
297
298 return (bp);
299 }
300
301 void
302 buf_put(struct buf *bp)
303 {
304 splassert(IPL_BIO);
305 #ifdef DIAGNOSTIC
306 if (bp->b_data != NULL)
307 KASSERT(bp->b_bufsize > 0);
308 #endif
309 #ifdef QUEUE_MACRO_DEBUG
310 if (bp->b_freelist.tqe_next != NOLIST &&
311 bp->b_freelist.tqe_next != (void *)-1)
312 panic("buf_put: still on the free list");
313
314 if (bp->b_vnbufs.le_next != NOLIST &&
315 bp->b_vnbufs.le_next != (void *)-1)
316 panic("buf_put: still on the vnode list");
317 #endif
318 #ifdef DIAGNOSTIC
319 if (!LIST_EMPTY(&bp->b_dep))
320 panic("buf_put: b_dep is not empty");
321 #endif
322 LIST_REMOVE(bp, b_list);
323
324 if (bp->b_data != NULL) {
325 bremhash(bp);
326 numbufpages -= btoc(bp->b_bufsize);
327 uvm_km_free(buf_map, (vaddr_t)bp->b_data, bp->b_bufsize);
328 }
329
330 pool_put(&bufpool, bp);
331 }
332
333
334
335
336 void
337 bufinit(void)
338 {
339 vaddr_t minaddr, maxaddr;
340 struct bqueues *dp;
341
342 pool_init(&bufpool, sizeof(struct buf), 0, 0, 0, "bufpl", NULL);
343 pool_setipl(&bufpool, IPL_BIO);
344 for (dp = bufqueues; dp < &bufqueues[BQUEUES]; dp++)
345 TAILQ_INIT(dp);
346 minaddr = vm_map_min(kernel_map);
347 buf_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
348 ptoa(bufpages), 0, FALSE, NULL);
349
350
351
352
353
354 bqpagelow = bufpages / 20;
355
356 bufhashtbl = hashinit(bufpages / 4, M_CACHE, M_WAITOK, &bufhash);
357 hidirtypages = (bufpages / 4) * 3;
358 lodirtypages = bufpages / 2;
359
360
361
362
363
364
365
366 hicleanpages = bufpages / 2;
367 locleanpages = hicleanpages / 2;
368 if (locleanpages < btoc(2 * MAXBSIZE))
369 locleanpages = btoc(2 * MAXBSIZE);
370 if (locleanpages > bufpages / 4)
371 locleanpages = bufpages / 4;
372
373 maxcleanpages = locleanpages;
374 }
375
376 struct buf *
377 bio_doread(struct vnode *vp, daddr64_t blkno, int size, int async)
378 {
379 struct buf *bp;
380
381 bp = getblk(vp, blkno, size, 0, 0);
382
383
384
385
386
387
388 if (!ISSET(bp->b_flags, (B_DONE | B_DELWRI))) {
389 SET(bp->b_flags, B_READ | async);
390 VOP_STRATEGY(bp);
391
392
393 curproc->p_stats->p_ru.ru_inblock++;
394 } else if (async) {
395 brelse(bp);
396 }
397
398 return (bp);
399 }
400
401
402
403
404
405 int
406 bread(struct vnode *vp, daddr64_t blkno, int size, struct ucred *cred,
407 struct buf **bpp)
408 {
409 struct buf *bp;
410
411
412 bp = *bpp = bio_doread(vp, blkno, size, 0);
413
414
415 return (biowait(bp));
416 }
417
418
419
420
421
422 int
423 breadn(struct vnode *vp, daddr64_t blkno, int size, daddr64_t rablks[],
424 int rasizes[], int nrablks, struct ucred *cred, struct buf **bpp)
425 {
426 struct buf *bp;
427 int i;
428
429 bp = *bpp = bio_doread(vp, blkno, size, 0);
430
431
432
433
434 for (i = 0; i < nrablks; i++) {
435
436 if (incore(vp, rablks[i]))
437 continue;
438
439
440 (void) bio_doread(vp, rablks[i], rasizes[i], B_ASYNC);
441 }
442
443
444 return (biowait(bp));
445 }
446
447
448
449
450 void
451 bread_cluster_callback(struct buf *bp)
452 {
453 int i;
454 struct buf **xbpp;
455
456 xbpp = (struct buf **)bp->b_saveaddr;
457
458 for (i = 0; xbpp[i] != 0; i++) {
459 if (ISSET(bp->b_flags, B_ERROR))
460 SET(xbpp[i]->b_flags, B_INVAL | B_ERROR);
461 biodone(xbpp[i]);
462 }
463
464 free(xbpp, M_TEMP);
465 bp->b_data = NULL;
466 buf_put(bp);
467 }
468
469 int
470 bread_cluster(struct vnode *vp, daddr64_t blkno, int size, struct buf **rbpp)
471 {
472 struct buf *bp, **xbpp;
473 int howmany, i, maxra, inc;
474 daddr64_t sblkno;
475 size_t spill;
476
477 *rbpp = bio_doread(vp, blkno, size, 0);
478
479 if (size != round_page(size))
480 return (biowait(*rbpp));
481
482 if (VOP_BMAP(vp, blkno + 1, NULL, &sblkno, &maxra))
483 return (biowait(*rbpp));
484
485 maxra++;
486 if (sblkno == -1 || maxra < 2)
487 return (biowait(*rbpp));
488
489 howmany = MAXPHYS / size;
490 if (howmany > maxra)
491 howmany = maxra;
492
493 xbpp = malloc((howmany + 1) * sizeof(struct buf *), M_TEMP, M_NOWAIT);
494 if (xbpp == NULL)
495 return (biowait(*rbpp));
496
497 for (i = 0; i < howmany; i++) {
498 if (incore(vp, blkno + i + 1)) {
499 for (--i; i >= 0; i--) {
500 SET(xbpp[i]->b_flags, B_INVAL);
501 brelse(xbpp[i]);
502 }
503 free(xbpp, M_TEMP);
504 return (biowait(*rbpp));
505 }
506 xbpp[i] = buf_stub(vp, blkno + i + 1);
507 if (xbpp[i] == NULL) {
508 for (--i; i >= 0; i--) {
509 SET(xbpp[i]->b_flags, B_INVAL);
510 brelse(xbpp[i]);
511 }
512 free(xbpp, M_TEMP);
513 return (biowait(*rbpp));
514 }
515 }
516
517 xbpp[howmany] = 0;
518
519 bp = getnewbuf(howmany * size, 0, 0, NULL);
520 if (bp == NULL) {
521 for (i = 0; i < howmany; i++) {
522 SET(xbpp[i]->b_flags, B_INVAL);
523 brelse(xbpp[i]);
524 }
525 free(xbpp, M_TEMP);
526 return (biowait(*rbpp));
527 }
528
529 inc = btodb(size);
530
531 for (i = 0; i < howmany; i++) {
532 SET(xbpp[i]->b_flags, B_READ | B_ASYNC);
533 binshash(xbpp[i], BUFHASH(vp, xbpp[i]->b_lblkno));
534 xbpp[i]->b_blkno = sblkno + (i * inc);
535 xbpp[i]->b_bufsize = xbpp[i]->b_bcount = size;
536 xbpp[i]->b_data = bp->b_data + (i * size);
537 }
538
539 bp->b_blkno = sblkno;
540 bp->b_lblkno = blkno + 1;
541 SET(bp->b_flags, B_READ | B_ASYNC | B_CALL);
542 bp->b_saveaddr = (void *)xbpp;
543 bp->b_iodone = bread_cluster_callback;
544 bp->b_vp = vp;
545 spill = bp->b_bufsize - bp->b_bcount;
546 if (spill) {
547 uvm_km_free(buf_map, (vaddr_t) bp->b_data + bp->b_bcount,
548 spill);
549 numbufpages -= atop(spill);
550 }
551 VOP_STRATEGY(bp);
552 curproc->p_stats->p_ru.ru_inblock++;
553
554 return (biowait(*rbpp));
555 }
556
557
558
559
560 int
561 bwrite(struct buf *bp)
562 {
563 int rv, async, wasdelayed, s;
564 struct vnode *vp;
565 struct mount *mp;
566
567 vp = bp->b_vp;
568 if (vp != NULL)
569 mp = vp->v_type == VBLK? vp->v_specmountpoint : vp->v_mount;
570 else
571 mp = NULL;
572
573
574
575
576
577
578
579
580 async = ISSET(bp->b_flags, B_ASYNC);
581 if (!async && mp && ISSET(mp->mnt_flag, MNT_ASYNC)) {
582 bdwrite(bp);
583 return (0);
584 }
585
586
587
588
589
590
591 if (mp != NULL) {
592 if (async)
593 mp->mnt_stat.f_asyncwrites++;
594 else
595 mp->mnt_stat.f_syncwrites++;
596 }
597
598 wasdelayed = ISSET(bp->b_flags, B_DELWRI);
599 CLR(bp->b_flags, (B_READ | B_DONE | B_ERROR | B_DELWRI));
600
601 s = splbio();
602
603
604
605
606
607
608
609 if (wasdelayed) {
610 reassignbuf(bp);
611 } else
612 curproc->p_stats->p_ru.ru_oublock++;
613
614
615
616 bp->b_vp->v_numoutput++;
617 splx(s);
618 SET(bp->b_flags, B_WRITEINPROG);
619 VOP_STRATEGY(bp);
620
621 if (async)
622 return (0);
623
624
625
626
627 rv = biowait(bp);
628
629
630 brelse(bp);
631
632 return (rv);
633 }
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649 void
650 bdwrite(struct buf *bp)
651 {
652 int s;
653
654
655
656
657
658
659
660
661 if (!ISSET(bp->b_flags, B_DELWRI)) {
662 SET(bp->b_flags, B_DELWRI);
663 bp->b_synctime = time_uptime + 35;
664 s = splbio();
665 reassignbuf(bp);
666 splx(s);
667 curproc->p_stats->p_ru.ru_oublock++;
668 } else {
669
670
671
672
673 if (bp->b_synctime < time_uptime) {
674 bawrite(bp);
675 return;
676 }
677 }
678
679
680 if (major(bp->b_dev) < nblkdev &&
681 bdevsw[major(bp->b_dev)].d_type == D_TAPE) {
682 bawrite(bp);
683 return;
684 }
685
686
687 CLR(bp->b_flags, B_NEEDCOMMIT);
688 SET(bp->b_flags, B_DONE);
689 brelse(bp);
690 }
691
692
693
694
695 void
696 bawrite(struct buf *bp)
697 {
698
699 SET(bp->b_flags, B_ASYNC);
700 VOP_BWRITE(bp);
701 }
702
703
704
705
706 void
707 buf_dirty(struct buf *bp)
708 {
709 splassert(IPL_BIO);
710
711 if (ISSET(bp->b_flags, B_DELWRI) == 0) {
712 SET(bp->b_flags, B_DELWRI);
713 bp->b_synctime = time_uptime + 35;
714 reassignbuf(bp);
715 }
716 }
717
718
719
720
721 void
722 buf_undirty(struct buf *bp)
723 {
724 splassert(IPL_BIO);
725
726 if (ISSET(bp->b_flags, B_DELWRI)) {
727 CLR(bp->b_flags, B_DELWRI);
728 reassignbuf(bp);
729 }
730 }
731
732
733
734
735
736 void
737 brelse(struct buf *bp)
738 {
739 struct bqueues *bufq;
740 int s;
741
742
743 s = splbio();
744
745 if (bp->b_data != NULL)
746 KASSERT(bp->b_bufsize > 0);
747
748
749
750
751
752
753 if (ISSET(bp->b_flags, (B_NOCACHE|B_ERROR)))
754 SET(bp->b_flags, B_INVAL);
755
756 if (ISSET(bp->b_flags, B_INVAL)) {
757 int queue, qs;
758
759
760
761
762
763 if (LIST_FIRST(&bp->b_dep) != NULL)
764 buf_deallocate(bp);
765
766 if (ISSET(bp->b_flags, B_DELWRI)) {
767 CLR(bp->b_flags, B_DELWRI);
768 }
769
770 if (bp->b_vp)
771 brelvp(bp);
772
773
774
775
776
777 if (bp->b_data == NULL) {
778 buf_put(bp);
779 splx(s);
780 return;
781 }
782
783 qs = bp->b_bufsize;
784 queue = size2cqueue(&qs);
785 numcleanpages += btoc(bp->b_bufsize);
786 bqpages[queue] += btoc(bp->b_bufsize);
787 if (maxcleanpages < numcleanpages)
788 maxcleanpages = numcleanpages;
789 binsheadfree(bp, &bufqueues[queue]);
790 } else {
791
792
793
794
795 int queue, qs;
796 numfreepages += btoc(bp->b_bufsize);
797 qs = bp->b_bufsize;
798 queue = size2cqueue(&qs);
799
800 if (!ISSET(bp->b_flags, B_DELWRI)) {
801 numcleanpages += btoc(bp->b_bufsize);
802 bqpages[queue] += btoc(bp->b_bufsize);
803 if (maxcleanpages < numcleanpages)
804 maxcleanpages = numcleanpages;
805 bufq = &bufqueues[queue];
806 } else {
807 numdirtypages += btoc(bp->b_bufsize);
808 bufq = &bufqueues[BQ_DIRTY];
809 }
810 if (ISSET(bp->b_flags, B_AGE)) {
811 binsheadfree(bp, bufq);
812 bp->b_synctime = time_uptime + 30;
813 } else {
814 binstailfree(bp, bufq);
815 bp->b_synctime = time_uptime + 300;
816 }
817 }
818
819
820 CLR(bp->b_flags, (B_AGE | B_ASYNC | B_BUSY | B_NOCACHE | B_DEFERRED));
821
822
823 if (needbuffer) {
824 needbuffer--;
825 wakeup_one(&needbuffer);
826 }
827
828
829 if (ISSET(bp->b_flags, B_WANTED)) {
830 CLR(bp->b_flags, B_WANTED);
831 wakeup(bp);
832 }
833
834 splx(s);
835 }
836
837
838
839
840
841 struct buf *
842 incore(struct vnode *vp, daddr64_t blkno)
843 {
844 struct buf *bp;
845
846
847 LIST_FOREACH(bp, BUFHASH(vp, blkno), b_hash) {
848 if (bp->b_lblkno == blkno && bp->b_vp == vp &&
849 !ISSET(bp->b_flags, B_INVAL))
850 return (bp);
851 }
852
853 return (NULL);
854 }
855
856
857
858
859
860
861
862
863
864 struct buf *
865 getblk(struct vnode *vp, daddr64_t blkno, int size, int slpflag, int slptimeo)
866 {
867 struct bufhashhdr *bh;
868 struct buf *bp, *nb = NULL;
869 int s, error;
870
871
872
873
874
875
876
877
878
879
880
881 bh = BUFHASH(vp, blkno);
882 start:
883 LIST_FOREACH(bp, BUFHASH(vp, blkno), b_hash) {
884 if (bp->b_lblkno != blkno || bp->b_vp != vp)
885 continue;
886
887 s = splbio();
888 if (ISSET(bp->b_flags, B_BUSY)) {
889 if (nb != NULL) {
890 SET(nb->b_flags, B_INVAL);
891 binshash(nb, &invalhash);
892 brelse(nb);
893 nb = NULL;
894 }
895 SET(bp->b_flags, B_WANTED);
896 error = tsleep(bp, slpflag | (PRIBIO + 1), "getblk",
897 slptimeo);
898 splx(s);
899 if (error)
900 return (NULL);
901 goto start;
902 }
903
904 if (!ISSET(bp->b_flags, B_INVAL)) {
905 SET(bp->b_flags, (B_BUSY | B_CACHE));
906 bremfree(bp);
907 splx(s);
908 break;
909 }
910 splx(s);
911 }
912 if (nb && bp) {
913 SET(nb->b_flags, B_INVAL);
914 binshash(nb, &invalhash);
915 brelse(nb);
916 nb = NULL;
917 }
918 if (bp == NULL && nb == NULL) {
919 nb = getnewbuf(size, slpflag, slptimeo, &error);
920 if (nb == NULL) {
921 if (error == ERESTART || error == EINTR)
922 return (NULL);
923 }
924 goto start;
925 }
926 if (nb) {
927 bp = nb;
928 binshash(bp, bh);
929 bp->b_blkno = bp->b_lblkno = blkno;
930 s = splbio();
931 bgetvp(vp, bp);
932 splx(s);
933 }
934 return (bp);
935 }
936
937
938
939
940 struct buf *
941 geteblk(int size)
942 {
943 struct buf *bp;
944
945 while ((bp = getnewbuf(size, 0, 0, NULL)) == NULL)
946 ;
947 SET(bp->b_flags, B_INVAL);
948 binshash(bp, &invalhash);
949
950 return (bp);
951 }
952
953
954
955
956 struct buf *
957 getnewbuf(size_t size, int slpflag, int slptimeo, int *ep)
958 {
959 struct buf *bp;
960 int s, error, queue, qs;
961
962 #if 0
963 KASSERT(curproc != syncerproc && curproc != cleanerproc);
964 #endif
965
966 s = splbio();
967
968
969
970 if (numdirtypages >= hidirtypages || numcleanpages <= locleanpages)
971 wakeup(&bd_req);
972
973
974 getsome:
975 qs = size;
976 queue = size2cqueue(&qs);
977 bp = buf_get(qs);
978 if (bp == NULL) {
979
980
981
982
983 do {
984 bp = TAILQ_FIRST(&bufqueues[queue]);
985 queue++;
986 } while (bp == NULL && queue < BQUEUES);
987 }
988 if (bp == NULL) {
989
990
991
992
993 int q, gotsome = 0;
994 int freemax = 20;
995 for (q = 1; q < BQUEUES; q++) {
996 int i = freemax;
997 while (bqpages[q] > bqpagelow
998 && (bp = TAILQ_FIRST(&bufqueues[q]))
999 && i--) {
1000 gotsome++;
1001 bremfree(bp);
1002 if (LIST_FIRST(&bp->b_dep) != NULL)
1003 buf_deallocate(bp);
1004
1005 if (ISSET(bp->b_flags, B_DELWRI)) {
1006 CLR(bp->b_flags, B_DELWRI);
1007 }
1008
1009 if (bp->b_vp)
1010 brelvp(bp);
1011
1012 buf_put(bp);
1013 }
1014 }
1015 if (gotsome)
1016 goto getsome;
1017 }
1018 if (bp == NULL) {
1019
1020 needbuffer++;
1021 error = tsleep(&needbuffer, slpflag | (PRIBIO + 1),
1022 "getnewbuf", slptimeo);
1023 if (ep != NULL) {
1024 *ep = error;
1025 if (error) {
1026 splx(s);
1027 return (NULL);
1028 }
1029 }
1030 goto getsome;
1031 }
1032
1033 bremfree(bp);
1034
1035 SET(bp->b_flags, B_BUSY);
1036
1037 #ifdef DIAGNOSTIC
1038 if (ISSET(bp->b_flags, B_DELWRI))
1039 panic("Dirty buffer on BQ_CLEAN");
1040 #endif
1041
1042
1043 if (bp->b_vp)
1044 brelvp(bp);
1045
1046 splx(s);
1047
1048 #ifdef DIAGNOSTIC
1049
1050 if (LIST_FIRST(&bp->b_dep) != NULL)
1051 panic("BQ_CLEAN has buffer with dependencies");
1052 #endif
1053
1054
1055 bp->b_flags = B_BUSY;
1056 bp->b_dev = NODEV;
1057 bp->b_blkno = bp->b_lblkno = 0;
1058 bp->b_iodone = NULL;
1059 bp->b_error = 0;
1060 bp->b_resid = 0;
1061 bp->b_bcount = size;
1062 bp->b_dirtyoff = bp->b_dirtyend = 0;
1063 bp->b_validoff = bp->b_validend = 0;
1064
1065 bremhash(bp);
1066 return (bp);
1067 }
1068
1069
1070
1071
1072 void
1073 buf_daemon(struct proc *p)
1074 {
1075 struct timeval starttime, timediff;
1076 struct buf *bp;
1077 int s;
1078
1079 cleanerproc = curproc;
1080
1081 s = splbio();
1082 for (;;) {
1083 if (!numdirtypages ||
1084 (numdirtypages < hidirtypages && !needbuffer))
1085 tsleep(&bd_req, PRIBIO - 7, "cleaner", 0);
1086
1087 getmicrouptime(&starttime);
1088
1089 while ((bp = TAILQ_FIRST(&bufqueues[BQ_DIRTY]))) {
1090 struct timeval tv;
1091
1092 if (numdirtypages < lodirtypages && !needbuffer)
1093 break;
1094
1095 bremfree(bp);
1096 SET(bp->b_flags, B_BUSY);
1097 splx(s);
1098
1099 if (ISSET(bp->b_flags, B_INVAL)) {
1100 brelse(bp);
1101 s = splbio();
1102 continue;
1103 }
1104 #ifdef DIAGNOSTIC
1105 if (!ISSET(bp->b_flags, B_DELWRI))
1106 panic("Clean buffer on BQ_DIRTY");
1107 #endif
1108 if (LIST_FIRST(&bp->b_dep) != NULL &&
1109 !ISSET(bp->b_flags, B_DEFERRED) &&
1110 buf_countdeps(bp, 0, 0)) {
1111 SET(bp->b_flags, B_DEFERRED);
1112 s = splbio();
1113 numfreepages += btoc(bp->b_bufsize);
1114 numdirtypages += btoc(bp->b_bufsize);
1115 binstailfree(bp, &bufqueues[BQ_DIRTY]);
1116 CLR(bp->b_flags, B_BUSY);
1117 continue;
1118 }
1119
1120 bawrite(bp);
1121
1122
1123 getmicrouptime(&tv);
1124 timersub(&tv, &starttime, &timediff);
1125 if (timediff.tv_sec)
1126 break;
1127
1128 s = splbio();
1129 }
1130 }
1131 }
1132
1133
1134
1135
1136
1137 int
1138 biowait(struct buf *bp)
1139 {
1140 int s;
1141
1142 s = splbio();
1143 while (!ISSET(bp->b_flags, B_DONE))
1144 tsleep(bp, PRIBIO + 1, "biowait", 0);
1145 splx(s);
1146
1147
1148 if (ISSET(bp->b_flags, B_EINTR)) {
1149 CLR(bp->b_flags, B_EINTR);
1150 return (EINTR);
1151 }
1152
1153 if (ISSET(bp->b_flags, B_ERROR))
1154 return (bp->b_error ? bp->b_error : EIO);
1155 else
1156 return (0);
1157 }
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177 void
1178 biodone(struct buf *bp)
1179 {
1180 splassert(IPL_BIO);
1181
1182 if (ISSET(bp->b_flags, B_DONE))
1183 panic("biodone already");
1184 SET(bp->b_flags, B_DONE);
1185
1186 if (LIST_FIRST(&bp->b_dep) != NULL)
1187 buf_complete(bp);
1188
1189 if (!ISSET(bp->b_flags, B_READ)) {
1190 CLR(bp->b_flags, B_WRITEINPROG);
1191 vwakeup(bp->b_vp);
1192 }
1193
1194 if (ISSET(bp->b_flags, B_CALL)) {
1195 CLR(bp->b_flags, B_CALL);
1196 (*bp->b_iodone)(bp);
1197 } else {
1198 if (ISSET(bp->b_flags, B_ASYNC)) {
1199 brelse(bp);
1200 } else {
1201 CLR(bp->b_flags, B_WANTED);
1202 wakeup(bp);
1203 }
1204 }
1205 }
1206
1207 #if 1
1208 void
1209 vfs_bufstats(void) {
1210 return;
1211 }
1212
1213 #else
1214
1215
1216
1217
1218
1219 void
1220 vfs_bufstats(void)
1221 {
1222 int s, i, j, count;
1223 struct buf *bp;
1224 struct bqueues *dp;
1225 int counts[MAXBSIZE/PAGE_SIZE+1];
1226 int totals[BQUEUES];
1227 long ptotals[BQUEUES];
1228 long pages;
1229 static char *bname[BQUEUES] = { "CLEAN", "DIRTY", "EMPTY" };
1230
1231 s = splbio();
1232 for (dp = bufqueues, i = 0; dp < &bufqueues[BQUEUES]; dp++, i++) {
1233 count = 0;
1234 pages = 0;
1235 for (j = 0; j <= MAXBSIZE/PAGE_SIZE; j++)
1236 counts[j] = 0;
1237 TAILQ_FOREACH(bp, dp, b_freelist) {
1238 counts[bp->b_bufsize/PAGE_SIZE]++;
1239 count++;
1240 pages += btoc(bp->b_bufsize);
1241 }
1242 totals[i] = count;
1243 ptotals[i] = pages;
1244 printf("%s: total-%d(%d pages)", bname[i], count, pages);
1245 for (j = 0; j <= MAXBSIZE/PAGE_SIZE; j++)
1246 if (counts[j] != 0)
1247 printf(", %d-%d", j * PAGE_SIZE, counts[j]);
1248 printf("\n");
1249 }
1250 if ((ptotals[BQ_CLEAN] + ptotals[BQ_DIRTY]) != numfreepages)
1251 printf("numfreepages counter wrong: %ld != %ld\n",
1252 numfreepages, ptotals[BQ_CLEAN] + ptotals[BQ_DIRTY]);
1253 if (ptotals[BQ_CLEAN] != numcleanpages)
1254 printf("numcleanpages counter wrong: %ld != %ld\n",
1255 numcleanpages, ptotals[<BQ_CLEAN]);
1256 else
1257 printf("numcleanpages: %ld\n", numcleanpages);
1258 if (numdirtypages != ptotals[BQ_DIRTY])
1259 printf("numdirtypages counter wrong: %ld != %ld\n",
1260 numdirtypages, ptotals[BQ_DIRTY]);
1261 else
1262 printf("numdirtypages: %ld\n", numdirtypages);
1263
1264 printf("syncer eating up to %ld pages from %ld reserved\n",
1265 maxcleanpages - hicleanpages, locleanpages);
1266 splx(s);
1267 }
1268 #endif