4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
30 * Implements routines to create a cache resource file.
33 #pragma ident "%Z%%M% %I% %E% SMI"
40 #include <sys/param.h>
41 #include <sys/fcntl.h>
43 #include <sys/fs/cachefs_fs.h>
47 int p_magic
; /* magic number */
48 int p_done
:1; /* 1 if res_done called */
49 int p_verbose
:1; /* 1 means print errors */
50 void *p_addrp
; /* address of mapped file */
51 long p_size
; /* size of mapped file */
52 struct cache_usage
*p_cusagep
; /* ptr to cache_usage */
53 struct cachefs_rl_info
*p_linfop
; /* ptr to rl_info */
54 rl_entry_t
*p_rlentp
; /* ptr to first rl_entry */
55 int p_totentries
; /* max number of rl entries */
56 char p_name
[MAXPATHLEN
]; /* name of resource file */
60 #define precond(A) assert(A)
63 #define RL_HEAD(resp, type) \
64 (&(resp->p_linfop->rl_items[CACHEFS_RL_INDEX(type)]))
65 #define CVBLKS(nbytes) ((nbytes + MAXBSIZE - 1) / MAXBSIZE)
67 /* forward references */
68 void res_rlent_moveto(res
*resp
, enum cachefs_rl_type type
, uint_t entno
,
70 void res_reset(res
*resp
);
71 void res_clear(res
*resp
);
72 int res_listcheck(res
*, enum cachefs_rl_type
);
79 * Creates a res object and returns a pointer to it.
80 * The specified file is used to store resource file data.
82 * namep name of the resource file
83 * entries max number of rl entries in the file
84 * verbose 1 means print out error messages
86 * Returns a pointer to the object or NULL if an error occurred.
89 * precond(entries > 3)
90 * precond(strlen(namep) < MAXPATHLEN)
94 res_create(char *namep
, int entries
, int verbose
)
105 struct stat64 statinfo
;
108 precond(entries
> MININDEX
);
110 /* determine the size needed for the resource file */
112 size
+= MAXBSIZE
* (entries
/ CACHEFS_RLPMBS
);
113 if ((entries
% CACHEFS_RLPMBS
) != 0)
116 /* if the file does not exist or is the wrong size/type */
117 xx
= lstat64(namep
, &statinfo
);
118 /* resource file will be <2GB */
119 if ((xx
== -1) || (statinfo
.st_size
!= (offset_t
)size
) ||
120 !(S_ISREG(statinfo
.st_mode
))) {
122 /* remove the resource file */
124 if ((xx
== -1) && (errno
!= ENOENT
))
127 /* create and open the file */
128 fd
= open(namep
, O_CREAT
| O_RDWR
, 0600);
132 /* fill the file with zeros */
133 memset(buf
, 0, sizeof (buf
));
134 for (cnt
= size
; cnt
> 0; cnt
-= result
) {
138 result
= write(fd
, buf
, amt
);
146 /* else open the file */
148 fd
= open(namep
, O_RDWR
);
153 /* mmap the file into our address space */
154 addrp
= mmap(NULL
, size
, PROT_READ
| PROT_WRITE
, MAP_SHARED
, fd
, 0);
155 if (addrp
== (void *)-1) {
160 /* close the file descriptor, we do not need it anymore */
163 /* allocate memory for the res object */
164 resp
= malloc(sizeof (res
));
170 /* initialize the object */
171 resp
->p_magic
= MAGIC
;
173 resp
->p_addrp
= addrp
;
175 resp
->p_verbose
= verbose
;
176 resp
->p_cusagep
= (struct cache_usage
*)addrp
;
177 resp
->p_linfop
= (struct cachefs_rl_info
*)((char *)addrp
+
178 sizeof (struct cache_usage
));
179 resp
->p_rlentp
= (rl_entry_t
*)((char *)addrp
+ MAXBSIZE
);
180 resp
->p_totentries
= entries
;
181 strcpy(resp
->p_name
, namep
);
183 /* reset the resource file in preperation to rebuild it */
186 /* return the object */
195 * Destroys the specifed res object.
196 * If res_done has not been called on the object or if res_done
197 * failed, then the resource file will be deleted.
199 * resp object to destroy
202 * precond(resp is a valid res object)
206 res_destroy(res
*resp
)
209 precond(resp
->p_magic
== MAGIC
);
212 munmap(resp
->p_addrp
, resp
->p_size
);
214 /* if res_done not performed */
215 if (resp
->p_done
== 0) {
216 /* remove the resource file */
217 unlink(resp
->p_name
);
220 /* destroy the object */
221 resp
->p_magic
= -MAGIC
;
226 res_rlent_get(res
*resp
, uint_t entno
)
228 rl_entry_t
*rlentp
, *window
;
229 uint_t whichwindow
, winoffset
;
231 precond((entno
>= MININDEX
) && (entno
< resp
->p_totentries
));
233 whichwindow
= entno
/ CACHEFS_RLPMBS
;
234 winoffset
= entno
% CACHEFS_RLPMBS
;
236 window
= (rl_entry_t
*)
237 (((caddr_t
)resp
->p_rlentp
) + (MAXBSIZE
* whichwindow
));
238 rlentp
= window
+ winoffset
;
248 * Resets the resource file in preparation to rebuild it.
253 * precond(resp is a valid res object)
262 cachefs_rl_listhead_t
*lhp
;
265 precond(resp
->p_magic
== MAGIC
);
267 resp
->p_cusagep
->cu_blksused
= 0;
268 resp
->p_cusagep
->cu_filesused
= 0;
269 resp
->p_cusagep
->cu_flags
= CUSAGE_ACTIVE
; /* dirty cache */
271 /* clear out the non-pointer info */
272 for (index
= MININDEX
; index
< resp
->p_totentries
; index
++) {
273 rlentp
= res_rlent_get(resp
, index
);
275 rlentp
->rl_attrc
= 0;
277 rlentp
->rl_local
= 0;
278 rlentp
->rl_fsid
= 0LL;
279 rlentp
->rl_fileno
= 0;
282 /* verify validity of the various lists */
283 ret
= res_listcheck(resp
, CACHEFS_RL_GC
);
285 ret
= res_listcheck(resp
, CACHEFS_RL_ATTRFILE
);
287 ret
= res_listcheck(resp
, CACHEFS_RL_MODIFIED
);
289 ret
= res_listcheck(resp
, CACHEFS_RL_PACKED
);
291 ret
= res_listcheck(resp
,
292 CACHEFS_RL_PACKED_PENDING
);
298 /* if an error occurred on one of the lists */
304 /* zero out total sizes, they get fixed up as we add items */
305 RL_HEAD(resp
, CACHEFS_RL_GC
)->rli_blkcnt
= 0;
306 RL_HEAD(resp
, CACHEFS_RL_ATTRFILE
)->rli_blkcnt
= 0;
307 RL_HEAD(resp
, CACHEFS_RL_MODIFIED
)->rli_blkcnt
= 0;
308 RL_HEAD(resp
, CACHEFS_RL_PACKED
)->rli_blkcnt
= 0;
309 RL_HEAD(resp
, CACHEFS_RL_PACKED_PENDING
)->rli_blkcnt
= 0;
311 /* null out the heads of the lists we do not want to preserve */
312 lhp
= RL_HEAD(resp
, CACHEFS_RL_FREE
);
313 memset(lhp
, 0, sizeof (cachefs_rl_listhead_t
));
314 lhp
= RL_HEAD(resp
, CACHEFS_RL_NONE
);
315 memset(lhp
, 0, sizeof (cachefs_rl_listhead_t
));
316 lhp
= RL_HEAD(resp
, CACHEFS_RL_MF
);
317 memset(lhp
, 0, sizeof (cachefs_rl_listhead_t
));
318 lhp
= RL_HEAD(resp
, CACHEFS_RL_ACTIVE
);
319 memset(lhp
, 0, sizeof (cachefs_rl_listhead_t
));
327 * Checks the specified list.
332 * Returns 1 if the list is ok, 0 if there is a problem.
334 * precond(resp is a valid res object)
338 res_listcheck(res
*resp
, enum cachefs_rl_type type
)
341 int previndex
, index
;
342 cachefs_rl_listhead_t
*lhp
;
345 lhp
= RL_HEAD(resp
, type
);
346 index
= lhp
->rli_front
;
353 /* make sure offset is in bounds */
354 if ((index
< MININDEX
) || (index
>= resp
->p_totentries
)) {
356 pr_err("index out of bounds %d", index
);
360 /* get pointer to rl_entry object */
361 rlentp
= res_rlent_get(resp
, index
);
363 /* check forward pointer */
364 if (rlentp
->rl_fwd_idx
!= previndex
) {
365 /* bad back pointer in rl list */
367 pr_err(gettext("bad forward pointer %d %d"),
368 rlentp
->rl_fwd_idx
, previndex
);
372 /* check for cycle */
373 if (rlentp
->rl_fsck
) {
374 /* cycle found in list */
376 pr_err(gettext("cycle found in list %d"),
382 if (rlentp
->rl_current
!= type
) {
383 /* entry doesn't belong here */
386 "bad entry %d type %d in list type %d"),
387 index
, (int)rlentp
->rl_current
, (int)type
);
391 /* indicate we have seen this pointer */
394 index
= rlentp
->rl_bkwd_idx
;
397 /* verify number of items match */
398 if (itemcnt
!= lhp
->rli_itemcnt
) {
400 pr_err(gettext("itemcnt wrong old %d new %d"),
401 lhp
->rli_itemcnt
, itemcnt
);
413 * Deletes all information from the resource file.
418 * precond(resp is a valid res object)
424 memset(resp
->p_addrp
, 0, resp
->p_size
);
433 * Called when through performing res_addfile and res_addident
434 * to complete the resource file and flush the contents to
439 * Returns 0 for success, -1 for an error with errno set
442 * precond(resp is a valid res object)
454 precond(resp
->p_magic
== MAGIC
);
456 /* scan the ident list to find the max allocated entry */
457 resp
->p_linfop
->rl_entries
= 0;
458 for (index
= MININDEX
; index
< resp
->p_totentries
; index
++) {
459 rlentp
= res_rlent_get(resp
, index
);
460 if (rlentp
->rl_fsid
&& (ino64_t
)rlentp
->rl_fsck
) {
461 resp
->p_linfop
->rl_entries
= index
;
465 /* scan the ident list to fix up the free list */
466 for (index
= MININDEX
; index
< resp
->p_totentries
; index
++) {
467 rlentp
= res_rlent_get(resp
, index
);
469 /* if entry is not valid */
470 if ((rlentp
->rl_fsid
== 0LL) || (rlentp
->rl_fsck
== 0)) {
471 /* if entry should appear on the free list */
472 if (index
<= resp
->p_linfop
->rl_entries
) {
473 res_rlent_moveto(resp
,
474 CACHEFS_RL_FREE
, index
, 0);
477 rlentp
->rl_fsck
= 0; /* prepare to re-check */
481 * Sanity check that we do not have an internal error in
482 * fsck. Eventually turn this stuff off.
485 ret
= res_listcheck(resp
, CACHEFS_RL_GC
);
487 ret
= res_listcheck(resp
, CACHEFS_RL_ATTRFILE
);
489 ret
= res_listcheck(resp
, CACHEFS_RL_MODIFIED
);
491 ret
= res_listcheck(resp
, CACHEFS_RL_PACKED
);
493 ret
= res_listcheck(resp
, CACHEFS_RL_PACKED_PENDING
);
495 ret
= res_listcheck(resp
, CACHEFS_RL_FREE
);
497 ret
= res_listcheck(resp
, CACHEFS_RL_NONE
);
499 ret
= res_listcheck(resp
, CACHEFS_RL_MF
);
501 ret
= res_listcheck(resp
, CACHEFS_RL_ACTIVE
);
505 /* indicate the cache is clean */
506 resp
->p_cusagep
->cu_flags
&= ~CUSAGE_ACTIVE
;
508 /* sync the data to the file */
509 xx
= msync(resp
->p_addrp
, resp
->p_size
, MS_SYNC
);
524 * Increments the number of files and blocks resource counts.
527 * nbytes number of bytes in the file
530 * precond(resp is a valid res object)
534 res_addfile(res
*resp
, long nbytes
)
537 precond(resp
->p_magic
== MAGIC
);
539 /* update resource counts */
540 resp
->p_cusagep
->cu_blksused
+= CVBLKS(nbytes
);
541 resp
->p_cusagep
->cu_filesused
+= 1;
549 * Adds the specified file to the ident list.
550 * Updates resource counts.
553 * index index into idents/pointers tables
554 * dp ident information
555 * nbytes number of bytes of item
556 * file number of files of item
558 * Returns 0 for success or -1 if the index is already in use
561 * precond(resp is a valid res object)
566 res_addident(res
*resp
, int index
, rl_entry_t
*dp
, long nbytes
, int file
)
571 precond(resp
->p_magic
== MAGIC
);
574 /* check index for sanity */
575 if ((index
< MININDEX
) || (index
>= resp
->p_totentries
)) {
579 /* get pointer to ident */
580 rlentp
= res_rlent_get(resp
, index
);
582 /* if something already there */
583 if (rlentp
->rl_fsid
!= 0LL) {
587 /* if not on the right list, move it there */
588 if ((rlentp
->rl_fsck
== 0) || (rlentp
->rl_current
!= dp
->rl_current
))
589 res_rlent_moveto(resp
, dp
->rl_current
, index
, CVBLKS(nbytes
));
592 rlentp
->rl_local
= dp
->rl_local
;
593 rlentp
->rl_attrc
= dp
->rl_attrc
;
594 rlentp
->rl_fsid
= dp
->rl_fsid
;
595 rlentp
->rl_fileno
= dp
->rl_fileno
;
597 /* update resource counts */
598 resp
->p_cusagep
->cu_blksused
+= CVBLKS(nbytes
);
599 resp
->p_cusagep
->cu_filesused
+= file
;
610 * Removes the specified file from the ident list.
611 * Updates resource counts.
614 * index index into idents/pointers tables
615 * nbytes number of bytes in the file
616 * file number of files
620 * precond(resp is a valid res object)
621 * precond(index is valid)
622 * precond(ident is in use)
626 res_clearident(res
*resp
, int index
, int nbytes
, int file
)
631 precond(resp
->p_magic
== MAGIC
);
632 precond((index
>= MININDEX
) && (index
< resp
->p_totentries
));
634 /* get pointer to ident */
635 rlentp
= res_rlent_get(resp
, index
);
636 precond(rlentp
->rl_fsid
!= 0LL);
638 /* clear the ident */
639 rlentp
->rl_fsid
= 0LL;
640 rlentp
->rl_fileno
= 0;
641 rlentp
->rl_attrc
= 0;
642 rlentp
->rl_local
= 0;
644 /* update resource counts */
645 resp
->p_cusagep
->cu_blksused
-= CVBLKS(nbytes
);
646 resp
->p_cusagep
->cu_filesused
-= file
;
647 assert(resp
->p_cusagep
->cu_blksused
>= 0);
651 * This function moves an RL entry from whereever it currently is to
652 * the requested list.
656 res_rlent_moveto(res
*resp
, enum cachefs_rl_type type
, uint_t entno
, long blks
)
660 cachefs_rl_listhead_t
*lhp
;
661 enum cachefs_rl_type otype
;
663 precond((CACHEFS_RL_START
<= type
) && (type
<= CACHEFS_RL_END
));
664 precond((entno
>= MININDEX
) && (entno
< resp
->p_totentries
));
666 rl_ent
= res_rlent_get(resp
, entno
);
667 if (rl_ent
->rl_fsck
) {
668 /* remove entry from its previous list */
670 next
= rl_ent
->rl_fwd_idx
;
671 prev
= rl_ent
->rl_bkwd_idx
;
672 otype
= rl_ent
->rl_current
;
673 assert((CACHEFS_RL_START
<= otype
) &&
674 (otype
<= CACHEFS_RL_END
));
676 lhp
= RL_HEAD(resp
, otype
);
677 if ((lhp
->rli_back
== 0) || (lhp
->rli_front
== 0))
678 assert((lhp
->rli_back
== 0) && (lhp
->rli_front
== 0));
680 if (lhp
->rli_back
== entno
)
681 lhp
->rli_back
= next
;
682 if (lhp
->rli_front
== entno
)
683 lhp
->rli_front
= prev
;
685 rl_ent
= res_rlent_get(resp
, prev
);
686 rl_ent
->rl_fwd_idx
= next
;
689 rl_ent
= res_rlent_get(resp
, next
);
690 rl_ent
->rl_bkwd_idx
= prev
;
692 lhp
->rli_blkcnt
-= blks
;
696 /* add entry to its new list */
698 lhp
= RL_HEAD(resp
, type
);
699 rl_ent
= res_rlent_get(resp
, entno
);
700 rl_ent
->rl_current
= type
;
701 rl_ent
->rl_bkwd_idx
= 0;
702 rl_ent
->rl_fwd_idx
= lhp
->rli_back
;
704 if (lhp
->rli_back
!= 0) {
705 assert(lhp
->rli_front
!= 0);
706 rl_ent
= res_rlent_get(resp
, lhp
->rli_back
);
707 rl_ent
->rl_bkwd_idx
= entno
;
709 assert(lhp
->rli_front
== 0);
710 lhp
->rli_front
= entno
;
712 lhp
->rli_back
= entno
;
713 lhp
->rli_blkcnt
+= blks
;
716 rl_ent
= res_rlent_get(resp
, entno
);
717 rl_ent
->rl_current
= type
;