This source file includes following definitions.
- TAILQ_HEAD
- ufsdirhash_free
- ufsdirhash_lookup
- ufsdirhash_findfree
- ufsdirhash_enduseful
- ufsdirhash_add
- ufsdirhash_remove
- ufsdirhash_move
- ufsdirhash_newblk
- ufsdirhash_dirtrunc
- ufsdirhash_checkblock
- ufsdirhash_hash
- ufsdirhash_adjfree
- ufsdirhash_findslot
- ufsdirhash_delslot
- ufsdirhash_getprev
- ufsdirhash_recycle
- ufsdirhash_init
- ufsdirhash_uninit
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 #if 0
32 __FBSDID("$FreeBSD: src/sys/ufs/ufs/ufs_dirhash.c,v 1.18 2004/02/15 21:39:35 dwmalone Exp $");
33 #endif
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/lock.h>
39 #include <sys/rwlock.h>
40 #include <sys/malloc.h>
41 #include <sys/pool.h>
42 #include <sys/proc.h>
43 #include <sys/buf.h>
44 #include <sys/vnode.h>
45 #include <sys/mount.h>
46 #include <sys/sysctl.h>
47 #include <sys/hash.h>
48
49 #include <ufs/ufs/quota.h>
50 #include <ufs/ufs/inode.h>
51 #include <ufs/ufs/dir.h>
52 #include <ufs/ufs/dirhash.h>
53 #include <ufs/ufs/ufsmount.h>
54 #include <ufs/ufs/ufs_extern.h>
55
56 #define WRAPINCR(val, limit) (((val) + 1 == (limit)) ? 0 : ((val) + 1))
57 #define WRAPDECR(val, limit) (((val) == 0) ? ((limit) - 1) : ((val) - 1))
58 #define OFSFMT(vp) ((vp)->v_mount->mnt_maxsymlinklen <= 0)
59 #define BLKFREE2IDX(n) ((n) > DH_NFSTATS ? DH_NFSTATS : (n))
60
61 int ufs_mindirhashsize;
62 int ufs_dirhashmaxmem;
63 int ufs_dirhashmem;
64 int ufs_dirhashcheck;
65
66
67 int ufsdirhash_hash(struct dirhash *dh, char *name, int namelen);
68 void ufsdirhash_adjfree(struct dirhash *dh, doff_t offset, int diff);
69 void ufsdirhash_delslot(struct dirhash *dh, int slot);
70 int ufsdirhash_findslot(struct dirhash *dh, char *name, int namelen,
71 doff_t offset);
72 doff_t ufsdirhash_getprev(struct direct *dp, doff_t offset);
73 int ufsdirhash_recycle(int wanted);
74
75 struct pool ufsdirhash_pool;
76
77 #define DIRHASHLIST_LOCK()
78 #define DIRHASHLIST_UNLOCK()
79 #define DIRHASH_LOCK(dh)
80 #define DIRHASH_UNLOCK(dh)
81 #define DIRHASH_BLKALLOC() pool_get(&ufsdirhash_pool, PR_NOWAIT)
82 #define DIRHASH_BLKFREE(v) pool_put(&ufsdirhash_pool, v)
83
84 #define mtx_assert(l, f)
85 #define DIRHASH_ASSERT(e, m) KASSERT((e))
86
87
88 TAILQ_HEAD(, dirhash) ufsdirhash_list;
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106 int
107 ufsdirhash_build(struct inode *ip)
108 {
109 struct dirhash *dh;
110 struct buf *bp = NULL;
111 struct direct *ep;
112 struct vnode *vp;
113 doff_t bmask, pos;
114 int dirblocks, i, j, memreqd, nblocks, narrays, nslots, slot;
115
116
117 if (ip->i_dirhash == NULL) {
118 if (DIP(ip, size) < ufs_mindirhashsize || OFSFMT(ip->i_vnode))
119 return (-1);
120 } else {
121
122 if (DIP(ip, size) < ufs_mindirhashsize ||
123 ufs_dirhashmem > ufs_dirhashmaxmem) {
124 ufsdirhash_free(ip);
125 return (-1);
126 }
127
128 if (ip->i_dirhash->dh_hash != NULL)
129 return (0);
130
131 ufsdirhash_free(ip);
132 }
133
134
135 if (ip->i_effnlink == 0)
136 return (-1);
137
138 vp = ip->i_vnode;
139
140 DIRHASH_ASSERT(DIP(ip, size) >= DIRBLKSIZ, ("ufsdirhash_build size"));
141 nslots = DIP(ip, size) / DIRECTSIZ(1);
142 nslots = (nslots * 3 + 1) / 2;
143 narrays = howmany(nslots, DH_NBLKOFF);
144 nslots = narrays * DH_NBLKOFF;
145 dirblocks = howmany(DIP(ip, size), DIRBLKSIZ);
146 nblocks = (dirblocks * 3 + 1) / 2;
147
148 memreqd = sizeof(*dh) + narrays * sizeof(*dh->dh_hash) +
149 narrays * DH_NBLKOFF * sizeof(**dh->dh_hash) +
150 nblocks * sizeof(*dh->dh_blkfree);
151 DIRHASHLIST_LOCK();
152 if (memreqd + ufs_dirhashmem > ufs_dirhashmaxmem) {
153 DIRHASHLIST_UNLOCK();
154 if (memreqd > ufs_dirhashmaxmem / 2)
155 return (-1);
156
157
158 if (ufsdirhash_recycle(memreqd) != 0)
159 return (-1);
160
161 }
162 ufs_dirhashmem += memreqd;
163 DIRHASHLIST_UNLOCK();
164
165
166
167
168
169 MALLOC(dh, struct dirhash *, sizeof *dh, M_DIRHASH, M_NOWAIT);
170 if (dh == NULL) {
171 DIRHASHLIST_LOCK();
172 ufs_dirhashmem -= memreqd;
173 DIRHASHLIST_UNLOCK();
174 return (-1);
175 }
176 memset(dh, 0, sizeof *dh);
177 dh->dh_hash = malloc(narrays * sizeof(dh->dh_hash[0]),
178 M_DIRHASH, M_NOWAIT);
179 dh->dh_blkfree = malloc(nblocks * sizeof(dh->dh_blkfree[0]),
180 M_DIRHASH, M_NOWAIT);
181 if (dh->dh_hash == NULL || dh->dh_blkfree == NULL)
182 goto fail;
183 memset(dh->dh_hash, 0, narrays * sizeof(dh->dh_hash[0]));
184 for (i = 0; i < narrays; i++) {
185 if ((dh->dh_hash[i] = DIRHASH_BLKALLOC()) == NULL)
186 goto fail;
187 for (j = 0; j < DH_NBLKOFF; j++)
188 dh->dh_hash[i][j] = DIRHASH_EMPTY;
189 }
190
191
192 dh->dh_narrays = narrays;
193 dh->dh_hlen = nslots;
194 dh->dh_nblk = nblocks;
195 dh->dh_dirblks = dirblocks;
196 for (i = 0; i < dirblocks; i++)
197 dh->dh_blkfree[i] = DIRBLKSIZ / DIRALIGN;
198 for (i = 0; i < DH_NFSTATS; i++)
199 dh->dh_firstfree[i] = -1;
200 dh->dh_firstfree[DH_NFSTATS] = 0;
201 dh->dh_seqopt = 0;
202 dh->dh_seqoff = 0;
203 dh->dh_score = DH_SCOREINIT;
204 ip->i_dirhash = dh;
205
206 bmask = VFSTOUFS(vp->v_mount)->um_mountp->mnt_stat.f_iosize - 1;
207 pos = 0;
208 while (pos < DIP(ip, size)) {
209
210 if ((pos & bmask) == 0) {
211 if (bp != NULL)
212 brelse(bp);
213 if (UFS_BUFATOFF(ip, (off_t)pos, NULL, &bp) != 0)
214 goto fail;
215 }
216
217
218 ep = (struct direct *)((char *)bp->b_data + (pos & bmask));
219 if (ep->d_reclen == 0 || ep->d_reclen >
220 DIRBLKSIZ - (pos & (DIRBLKSIZ - 1))) {
221
222 brelse(bp);
223 goto fail;
224 }
225 if (ep->d_ino != 0) {
226
227 slot = ufsdirhash_hash(dh, ep->d_name, ep->d_namlen);
228 while (DH_ENTRY(dh, slot) != DIRHASH_EMPTY)
229 slot = WRAPINCR(slot, dh->dh_hlen);
230 dh->dh_hused++;
231 DH_ENTRY(dh, slot) = pos;
232 ufsdirhash_adjfree(dh, pos, -DIRSIZ(0, ep));
233 }
234 pos += ep->d_reclen;
235 }
236
237 if (bp != NULL)
238 brelse(bp);
239 DIRHASHLIST_LOCK();
240 TAILQ_INSERT_TAIL(&ufsdirhash_list, dh, dh_list);
241 dh->dh_onlist = 1;
242 DIRHASHLIST_UNLOCK();
243 return (0);
244
245 fail:
246 if (dh->dh_hash != NULL) {
247 for (i = 0; i < narrays; i++)
248 if (dh->dh_hash[i] != NULL)
249 DIRHASH_BLKFREE(dh->dh_hash[i]);
250 free(dh->dh_hash, M_DIRHASH);
251 }
252 if (dh->dh_blkfree != NULL)
253 free(dh->dh_blkfree, M_DIRHASH);
254 FREE(dh, M_DIRHASH);
255 ip->i_dirhash = NULL;
256 DIRHASHLIST_LOCK();
257 ufs_dirhashmem -= memreqd;
258 DIRHASHLIST_UNLOCK();
259 return (-1);
260 }
261
262
263
264
265 void
266 ufsdirhash_free(struct inode *ip)
267 {
268 struct dirhash *dh;
269 int i, mem;
270
271 if ((dh = ip->i_dirhash) == NULL)
272 return;
273 DIRHASHLIST_LOCK();
274 DIRHASH_LOCK(dh);
275 if (dh->dh_onlist)
276 TAILQ_REMOVE(&ufsdirhash_list, dh, dh_list);
277 DIRHASH_UNLOCK(dh);
278 DIRHASHLIST_UNLOCK();
279
280
281
282 mem = sizeof(*dh);
283 if (dh->dh_hash != NULL) {
284 for (i = 0; i < dh->dh_narrays; i++)
285 DIRHASH_BLKFREE(dh->dh_hash[i]);
286 free(dh->dh_hash, M_DIRHASH);
287 free(dh->dh_blkfree, M_DIRHASH);
288 mem += dh->dh_narrays * sizeof(*dh->dh_hash) +
289 dh->dh_narrays * DH_NBLKOFF * sizeof(**dh->dh_hash) +
290 dh->dh_nblk * sizeof(*dh->dh_blkfree);
291 }
292 FREE(dh, M_DIRHASH);
293 ip->i_dirhash = NULL;
294
295 DIRHASHLIST_LOCK();
296 ufs_dirhashmem -= mem;
297 DIRHASHLIST_UNLOCK();
298 }
299
300
301
302
303
304
305
306
307
308
309
310
311 int
312 ufsdirhash_lookup(struct inode *ip, char *name, int namelen, doff_t *offp,
313 struct buf **bpp, doff_t *prevoffp)
314 {
315 struct dirhash *dh, *dh_next;
316 struct direct *dp;
317 struct vnode *vp;
318 struct buf *bp;
319 doff_t blkoff, bmask, offset, prevoff;
320 int i, slot;
321
322 if ((dh = ip->i_dirhash) == NULL)
323 return (EJUSTRETURN);
324
325
326
327
328
329
330
331
332 if (TAILQ_NEXT(dh, dh_list) != NULL) {
333 DIRHASHLIST_LOCK();
334 DIRHASH_LOCK(dh);
335
336
337
338
339
340
341 if (dh->dh_hash != NULL &&
342 (dh_next = TAILQ_NEXT(dh, dh_list)) != NULL &&
343 dh->dh_score >= dh_next->dh_score) {
344 DIRHASH_ASSERT(dh->dh_onlist, ("dirhash: not on list"));
345 TAILQ_REMOVE(&ufsdirhash_list, dh, dh_list);
346 TAILQ_INSERT_AFTER(&ufsdirhash_list, dh_next, dh,
347 dh_list);
348 }
349 DIRHASHLIST_UNLOCK();
350 } else {
351
352 DIRHASH_LOCK(dh);
353 }
354 if (dh->dh_hash == NULL) {
355 DIRHASH_UNLOCK(dh);
356 ufsdirhash_free(ip);
357 return (EJUSTRETURN);
358 }
359
360
361 if (dh->dh_score < DH_SCOREMAX)
362 dh->dh_score++;
363
364 vp = ip->i_vnode;
365 bmask = VFSTOUFS(vp->v_mount)->um_mountp->mnt_stat.f_iosize - 1;
366 blkoff = -1;
367 bp = NULL;
368 restart:
369 slot = ufsdirhash_hash(dh, name, namelen);
370
371 if (dh->dh_seqopt) {
372
373
374
375
376
377
378 for (i = slot; (offset = DH_ENTRY(dh, i)) != DIRHASH_EMPTY;
379 i = WRAPINCR(i, dh->dh_hlen))
380 if (offset == dh->dh_seqoff)
381 break;
382 if (offset == dh->dh_seqoff) {
383
384
385
386
387
388 slot = i;
389 } else
390 dh->dh_seqopt = 0;
391 }
392
393 for (; (offset = DH_ENTRY(dh, slot)) != DIRHASH_EMPTY;
394 slot = WRAPINCR(slot, dh->dh_hlen)) {
395 if (offset == DIRHASH_DEL)
396 continue;
397 DIRHASH_UNLOCK(dh);
398
399 if (offset < 0 || offset >= DIP(ip, size))
400 panic("ufsdirhash_lookup: bad offset in hash array");
401 if ((offset & ~bmask) != blkoff) {
402 if (bp != NULL)
403 brelse(bp);
404 blkoff = offset & ~bmask;
405 if (UFS_BUFATOFF(ip, (off_t)blkoff, NULL, &bp) != 0)
406 return (EJUSTRETURN);
407 }
408 dp = (struct direct *)(bp->b_data + (offset & bmask));
409 if (dp->d_reclen == 0 || dp->d_reclen >
410 DIRBLKSIZ - (offset & (DIRBLKSIZ - 1))) {
411
412 brelse(bp);
413 return (EJUSTRETURN);
414 }
415 if (dp->d_namlen == namelen &&
416 bcmp(dp->d_name, name, namelen) == 0) {
417
418 if (prevoffp != NULL) {
419 if (offset & (DIRBLKSIZ - 1)) {
420 prevoff = ufsdirhash_getprev(dp,
421 offset);
422 if (prevoff == -1) {
423 brelse(bp);
424 return (EJUSTRETURN);
425 }
426 } else
427 prevoff = offset;
428 *prevoffp = prevoff;
429 }
430
431
432 if (dh->dh_seqopt == 0 && dh->dh_seqoff == offset)
433 dh->dh_seqopt = 1;
434 dh->dh_seqoff = offset + DIRSIZ(0, dp);
435
436 *bpp = bp;
437 *offp = offset;
438 return (0);
439 }
440
441 DIRHASH_LOCK(dh);
442 if (dh->dh_hash == NULL) {
443 DIRHASH_UNLOCK(dh);
444 if (bp != NULL)
445 brelse(bp);
446 ufsdirhash_free(ip);
447 return (EJUSTRETURN);
448 }
449
450
451
452
453 if (dh->dh_seqopt) {
454 dh->dh_seqopt = 0;
455 goto restart;
456 }
457 }
458 DIRHASH_UNLOCK(dh);
459 if (bp != NULL)
460 brelse(bp);
461 return (ENOENT);
462 }
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480 doff_t
481 ufsdirhash_findfree(struct inode *ip, int slotneeded, int *slotsize)
482 {
483 struct direct *dp;
484 struct dirhash *dh;
485 struct buf *bp;
486 doff_t pos, slotstart;
487 int dirblock, error, freebytes, i;
488
489 if ((dh = ip->i_dirhash) == NULL)
490 return (-1);
491 DIRHASH_LOCK(dh);
492 if (dh->dh_hash == NULL) {
493 DIRHASH_UNLOCK(dh);
494 ufsdirhash_free(ip);
495 return (-1);
496 }
497
498
499 dirblock = -1;
500 for (i = howmany(slotneeded, DIRALIGN); i <= DH_NFSTATS; i++)
501 if ((dirblock = dh->dh_firstfree[i]) != -1)
502 break;
503 if (dirblock == -1) {
504 DIRHASH_UNLOCK(dh);
505 return (-1);
506 }
507
508 DIRHASH_ASSERT(dirblock < dh->dh_nblk &&
509 dh->dh_blkfree[dirblock] >= howmany(slotneeded, DIRALIGN),
510 ("ufsdirhash_findfree: bad stats"));
511 DIRHASH_UNLOCK(dh);
512 pos = dirblock * DIRBLKSIZ;
513 error = UFS_BUFATOFF(ip, (off_t)pos, (char **)&dp, &bp);
514 if (error)
515 return (-1);
516
517
518 for (i = 0; i < DIRBLKSIZ; ) {
519 if (dp->d_reclen == 0) {
520 brelse(bp);
521 return (-1);
522 }
523 if (dp->d_ino == 0 || dp->d_reclen > DIRSIZ(0, dp))
524 break;
525 i += dp->d_reclen;
526 dp = (struct direct *)((char *)dp + dp->d_reclen);
527 }
528 if (i > DIRBLKSIZ) {
529 brelse(bp);
530 return (-1);
531 }
532 slotstart = pos + i;
533
534
535 freebytes = 0;
536 while (i < DIRBLKSIZ && freebytes < slotneeded) {
537 freebytes += dp->d_reclen;
538 if (dp->d_ino != 0)
539 freebytes -= DIRSIZ(0, dp);
540 if (dp->d_reclen == 0) {
541 brelse(bp);
542 return (-1);
543 }
544 i += dp->d_reclen;
545 dp = (struct direct *)((char *)dp + dp->d_reclen);
546 }
547 if (i > DIRBLKSIZ) {
548 brelse(bp);
549 return (-1);
550 }
551 if (freebytes < slotneeded)
552 panic("ufsdirhash_findfree: free mismatch");
553 brelse(bp);
554 *slotsize = pos + i - slotstart;
555 return (slotstart);
556 }
557
558
559
560
561
562 doff_t
563 ufsdirhash_enduseful(struct inode *ip)
564 {
565
566 struct dirhash *dh;
567 int i;
568
569 if ((dh = ip->i_dirhash) == NULL)
570 return (-1);
571 DIRHASH_LOCK(dh);
572 if (dh->dh_hash == NULL) {
573 DIRHASH_UNLOCK(dh);
574 ufsdirhash_free(ip);
575 return (-1);
576 }
577
578 if (dh->dh_blkfree[dh->dh_dirblks - 1] != DIRBLKSIZ / DIRALIGN) {
579 DIRHASH_UNLOCK(dh);
580 return (-1);
581 }
582
583 for (i = dh->dh_dirblks - 1; i >= 0; i--)
584 if (dh->dh_blkfree[i] != DIRBLKSIZ / DIRALIGN)
585 break;
586 DIRHASH_UNLOCK(dh);
587 return ((doff_t)(i + 1) * DIRBLKSIZ);
588 }
589
590
591
592
593
594
595 void
596 ufsdirhash_add(struct inode *ip, struct direct *dirp, doff_t offset)
597 {
598 struct dirhash *dh;
599 int slot;
600
601 if ((dh = ip->i_dirhash) == NULL)
602 return;
603 DIRHASH_LOCK(dh);
604 if (dh->dh_hash == NULL) {
605 DIRHASH_UNLOCK(dh);
606 ufsdirhash_free(ip);
607 return;
608 }
609
610 DIRHASH_ASSERT(offset < dh->dh_dirblks * DIRBLKSIZ,
611 ("ufsdirhash_add: bad offset"));
612
613
614
615
616 if (dh->dh_hused >= (dh->dh_hlen * 3) / 4) {
617 DIRHASH_UNLOCK(dh);
618 ufsdirhash_free(ip);
619 return;
620 }
621
622
623 slot = ufsdirhash_hash(dh, dirp->d_name, dirp->d_namlen);
624 while (DH_ENTRY(dh, slot) >= 0)
625 slot = WRAPINCR(slot, dh->dh_hlen);
626 if (DH_ENTRY(dh, slot) == DIRHASH_EMPTY)
627 dh->dh_hused++;
628 DH_ENTRY(dh, slot) = offset;
629
630
631 ufsdirhash_adjfree(dh, offset, -DIRSIZ(0, dirp));
632 DIRHASH_UNLOCK(dh);
633 }
634
635
636
637
638
639
640 void
641 ufsdirhash_remove(struct inode *ip, struct direct *dirp, doff_t offset)
642 {
643 struct dirhash *dh;
644 int slot;
645
646 if ((dh = ip->i_dirhash) == NULL)
647 return;
648 DIRHASH_LOCK(dh);
649 if (dh->dh_hash == NULL) {
650 DIRHASH_UNLOCK(dh);
651 ufsdirhash_free(ip);
652 return;
653 }
654
655 DIRHASH_ASSERT(offset < dh->dh_dirblks * DIRBLKSIZ,
656 ("ufsdirhash_remove: bad offset"));
657
658 slot = ufsdirhash_findslot(dh, dirp->d_name, dirp->d_namlen, offset);
659
660
661 ufsdirhash_delslot(dh, slot);
662
663
664 ufsdirhash_adjfree(dh, offset, DIRSIZ(0, dirp));
665 DIRHASH_UNLOCK(dh);
666 }
667
668
669
670
671
672 void
673 ufsdirhash_move(struct inode *ip, struct direct *dirp, doff_t oldoff,
674 doff_t newoff)
675 {
676 struct dirhash *dh;
677 int slot;
678
679 if ((dh = ip->i_dirhash) == NULL)
680 return;
681 DIRHASH_LOCK(dh);
682 if (dh->dh_hash == NULL) {
683 DIRHASH_UNLOCK(dh);
684 ufsdirhash_free(ip);
685 return;
686 }
687
688 DIRHASH_ASSERT(oldoff < dh->dh_dirblks * DIRBLKSIZ &&
689 newoff < dh->dh_dirblks * DIRBLKSIZ,
690 ("ufsdirhash_move: bad offset"));
691
692 slot = ufsdirhash_findslot(dh, dirp->d_name, dirp->d_namlen, oldoff);
693 DH_ENTRY(dh, slot) = newoff;
694 DIRHASH_UNLOCK(dh);
695 }
696
697
698
699
700
701 void
702 ufsdirhash_newblk(struct inode *ip, doff_t offset)
703 {
704 struct dirhash *dh;
705 int block;
706
707 if ((dh = ip->i_dirhash) == NULL)
708 return;
709 DIRHASH_LOCK(dh);
710 if (dh->dh_hash == NULL) {
711 DIRHASH_UNLOCK(dh);
712 ufsdirhash_free(ip);
713 return;
714 }
715
716 DIRHASH_ASSERT(offset == dh->dh_dirblks * DIRBLKSIZ,
717 ("ufsdirhash_newblk: bad offset"));
718 block = offset / DIRBLKSIZ;
719 if (block >= dh->dh_nblk) {
720
721 DIRHASH_UNLOCK(dh);
722 ufsdirhash_free(ip);
723 return;
724 }
725 dh->dh_dirblks = block + 1;
726
727
728 dh->dh_blkfree[block] = DIRBLKSIZ / DIRALIGN;
729 if (dh->dh_firstfree[DH_NFSTATS] == -1)
730 dh->dh_firstfree[DH_NFSTATS] = block;
731 DIRHASH_UNLOCK(dh);
732 }
733
734
735
736
737 void
738 ufsdirhash_dirtrunc(struct inode *ip, doff_t offset)
739 {
740 struct dirhash *dh;
741 int block, i;
742
743 if ((dh = ip->i_dirhash) == NULL)
744 return;
745 DIRHASH_LOCK(dh);
746 if (dh->dh_hash == NULL) {
747 DIRHASH_UNLOCK(dh);
748 ufsdirhash_free(ip);
749 return;
750 }
751
752 DIRHASH_ASSERT(offset <= dh->dh_dirblks * DIRBLKSIZ,
753 ("ufsdirhash_dirtrunc: bad offset"));
754 block = howmany(offset, DIRBLKSIZ);
755
756
757
758
759
760
761 if (block < dh->dh_nblk / 8 && dh->dh_narrays > 1) {
762 DIRHASH_UNLOCK(dh);
763 ufsdirhash_free(ip);
764 return;
765 }
766
767
768
769
770
771
772 if (dh->dh_firstfree[DH_NFSTATS] >= block)
773 dh->dh_firstfree[DH_NFSTATS] = -1;
774 for (i = block; i < dh->dh_dirblks; i++)
775 if (dh->dh_blkfree[i] != DIRBLKSIZ / DIRALIGN)
776 panic("ufsdirhash_dirtrunc: blocks in use");
777 for (i = 0; i < DH_NFSTATS; i++)
778 if (dh->dh_firstfree[i] >= block)
779 panic("ufsdirhash_dirtrunc: first free corrupt");
780 dh->dh_dirblks = block;
781 DIRHASH_UNLOCK(dh);
782 }
783
784
785
786
787
788
789
790
791
792
793 void
794 ufsdirhash_checkblock(struct inode *ip, char *buf, doff_t offset)
795 {
796 struct dirhash *dh;
797 struct direct *dp;
798 int block, ffslot, i, nfree;
799
800 if (!ufs_dirhashcheck)
801 return;
802 if ((dh = ip->i_dirhash) == NULL)
803 return;
804 DIRHASH_LOCK(dh);
805 if (dh->dh_hash == NULL) {
806 DIRHASH_UNLOCK(dh);
807 ufsdirhash_free(ip);
808 return;
809 }
810
811 block = offset / DIRBLKSIZ;
812 if ((offset & (DIRBLKSIZ - 1)) != 0 || block >= dh->dh_dirblks)
813 panic("ufsdirhash_checkblock: bad offset");
814
815 nfree = 0;
816 for (i = 0; i < DIRBLKSIZ; i += dp->d_reclen) {
817 dp = (struct direct *)(buf + i);
818 if (dp->d_reclen == 0 || i + dp->d_reclen > DIRBLKSIZ)
819 panic("ufsdirhash_checkblock: bad dir");
820
821 if (dp->d_ino == 0) {
822 #if 0
823
824
825
826
827
828
829 if (i != 0)
830 panic("ufsdirhash_checkblock: bad dir inode");
831 #endif
832 nfree += dp->d_reclen;
833 continue;
834 }
835
836
837 ufsdirhash_findslot(dh, dp->d_name, dp->d_namlen, offset + i);
838
839 nfree += dp->d_reclen - DIRSIZ(0, dp);
840 }
841 if (i != DIRBLKSIZ)
842 panic("ufsdirhash_checkblock: bad dir end");
843
844 if (dh->dh_blkfree[block] * DIRALIGN != nfree)
845 panic("ufsdirhash_checkblock: bad free count");
846
847 ffslot = BLKFREE2IDX(nfree / DIRALIGN);
848 for (i = 0; i <= DH_NFSTATS; i++)
849 if (dh->dh_firstfree[i] == block && i != ffslot)
850 panic("ufsdirhash_checkblock: bad first-free");
851 if (dh->dh_firstfree[ffslot] == -1)
852 panic("ufsdirhash_checkblock: missing first-free entry");
853 DIRHASH_UNLOCK(dh);
854 }
855
856
857
858
859 int
860 ufsdirhash_hash(struct dirhash *dh, char *name, int namelen)
861 {
862 u_int32_t hash;
863
864
865
866
867
868
869
870 hash = hash32_buf(name, namelen, HASHINIT);
871 hash = hash32_buf(&dh, sizeof(dh), hash);
872 return (hash % dh->dh_hlen);
873 }
874
875
876
877
878
879
880
881
882
883 void
884 ufsdirhash_adjfree(struct dirhash *dh, doff_t offset, int diff)
885 {
886 int block, i, nfidx, ofidx;
887
888
889 block = offset / DIRBLKSIZ;
890 DIRHASH_ASSERT(block < dh->dh_nblk && block < dh->dh_dirblks,
891 ("dirhash bad offset"));
892 ofidx = BLKFREE2IDX(dh->dh_blkfree[block]);
893 dh->dh_blkfree[block] = (int)dh->dh_blkfree[block] + (diff / DIRALIGN);
894 nfidx = BLKFREE2IDX(dh->dh_blkfree[block]);
895
896
897 if (ofidx != nfidx) {
898
899 if (dh->dh_firstfree[ofidx] == block) {
900 for (i = block + 1; i < dh->dh_dirblks; i++)
901 if (BLKFREE2IDX(dh->dh_blkfree[i]) == ofidx)
902 break;
903 dh->dh_firstfree[ofidx] = (i < dh->dh_dirblks) ? i : -1;
904 }
905
906
907 if (dh->dh_firstfree[nfidx] > block ||
908 dh->dh_firstfree[nfidx] == -1)
909 dh->dh_firstfree[nfidx] = block;
910 }
911 }
912
913
914
915
916
917
918
919 int
920 ufsdirhash_findslot(struct dirhash *dh, char *name, int namelen, doff_t offset)
921 {
922 int slot;
923
924 mtx_assert(&dh->dh_mtx, MA_OWNED);
925
926
927 DIRHASH_ASSERT(dh->dh_hused < dh->dh_hlen, ("dirhash find full"));
928 slot = ufsdirhash_hash(dh, name, namelen);
929 while (DH_ENTRY(dh, slot) != offset &&
930 DH_ENTRY(dh, slot) != DIRHASH_EMPTY)
931 slot = WRAPINCR(slot, dh->dh_hlen);
932 if (DH_ENTRY(dh, slot) != offset)
933 panic("ufsdirhash_findslot: '%.*s' not found", namelen, name);
934
935 return (slot);
936 }
937
938
939
940
941
942
943 void
944 ufsdirhash_delslot(struct dirhash *dh, int slot)
945 {
946 int i;
947
948 mtx_assert(&dh->dh_mtx, MA_OWNED);
949
950
951 DH_ENTRY(dh, slot) = DIRHASH_DEL;
952
953
954 for (i = slot; DH_ENTRY(dh, i) == DIRHASH_DEL; )
955 i = WRAPINCR(i, dh->dh_hlen);
956 if (DH_ENTRY(dh, i) == DIRHASH_EMPTY) {
957 i = WRAPDECR(i, dh->dh_hlen);
958 while (DH_ENTRY(dh, i) == DIRHASH_DEL) {
959 DH_ENTRY(dh, i) = DIRHASH_EMPTY;
960 dh->dh_hused--;
961 i = WRAPDECR(i, dh->dh_hlen);
962 }
963 DIRHASH_ASSERT(dh->dh_hused >= 0, ("ufsdirhash_delslot neg hlen"));
964 }
965 }
966
967
968
969
970
971
972
973 doff_t
974 ufsdirhash_getprev(struct direct *dirp, doff_t offset)
975 {
976 struct direct *dp;
977 char *blkbuf;
978 doff_t blkoff, prevoff;
979 int entrypos, i;
980
981 blkoff = offset & ~(DIRBLKSIZ - 1);
982 entrypos = offset & (DIRBLKSIZ - 1);
983 blkbuf = (char *)dirp - entrypos;
984 prevoff = blkoff;
985
986
987 if (entrypos == 0)
988 return (-1);
989
990
991 for (i = 0; i < entrypos; i += dp->d_reclen) {
992 dp = (struct direct *)(blkbuf + i);
993 if (dp->d_reclen == 0 || i + dp->d_reclen > entrypos)
994 return (-1);
995 prevoff = blkoff + i;
996 }
997 return (prevoff);
998 }
999
1000
1001
1002
1003
1004 int
1005 ufsdirhash_recycle(int wanted)
1006 {
1007 struct dirhash *dh;
1008 doff_t **hash;
1009 u_int8_t *blkfree;
1010 int i, mem, narrays;
1011
1012 DIRHASHLIST_LOCK();
1013 while (wanted + ufs_dirhashmem > ufs_dirhashmaxmem) {
1014
1015 if ((dh = TAILQ_FIRST(&ufsdirhash_list)) == NULL) {
1016 DIRHASHLIST_UNLOCK();
1017 return (-1);
1018 }
1019 DIRHASH_LOCK(dh);
1020 DIRHASH_ASSERT(dh->dh_hash != NULL, ("dirhash: NULL hash on list"));
1021
1022
1023 if (--dh->dh_score > 0) {
1024 DIRHASH_UNLOCK(dh);
1025 DIRHASHLIST_UNLOCK();
1026 return (-1);
1027 }
1028
1029
1030 TAILQ_REMOVE(&ufsdirhash_list, dh, dh_list);
1031 dh->dh_onlist = 0;
1032 hash = dh->dh_hash;
1033 dh->dh_hash = NULL;
1034 blkfree = dh->dh_blkfree;
1035 dh->dh_blkfree = NULL;
1036 narrays = dh->dh_narrays;
1037 mem = narrays * sizeof(*dh->dh_hash) +
1038 narrays * DH_NBLKOFF * sizeof(**dh->dh_hash) +
1039 dh->dh_nblk * sizeof(*dh->dh_blkfree);
1040
1041
1042 DIRHASH_UNLOCK(dh);
1043 DIRHASHLIST_UNLOCK();
1044 for (i = 0; i < narrays; i++)
1045 DIRHASH_BLKFREE(hash[i]);
1046 free(hash, M_DIRHASH);
1047 free(blkfree, M_DIRHASH);
1048
1049
1050 DIRHASHLIST_LOCK();
1051 ufs_dirhashmem -= mem;
1052 }
1053
1054 return (0);
1055 }
1056
1057
1058 void
1059 ufsdirhash_init()
1060 {
1061 pool_init(&ufsdirhash_pool, DH_NBLKOFF * sizeof(doff_t), 0, 0, 0,
1062 "dirhash", &pool_allocator_nointr);
1063 pool_sethiwat(&ufsdirhash_pool, 512);
1064 TAILQ_INIT(&ufsdirhash_list);
1065 #if defined (__sparc__) && !defined (__sparc64__)
1066 if (!CPU_ISSUN4OR4C)
1067 #elif defined (__vax__)
1068 if (0)
1069 #endif
1070 ufs_dirhashmaxmem = 2 * 1024 * 1024;
1071 ufs_mindirhashsize = 5 * DIRBLKSIZ;
1072 }
1073
1074 void
1075 ufsdirhash_uninit()
1076 {
1077 DIRHASH_ASSERT(TAILQ_EMPTY(&ufsdirhash_list), ("ufsdirhash_uninit"));
1078 pool_destroy(&ufsdirhash_pool);
1079 }