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 1994-2002 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * Methods of the cfsd_maptbl classes.
41 #include <sys/utsname.h>
44 #include <sys/param.h>
45 #include <sys/types.h>
48 #include <sys/fs/cachefs_fs.h>
49 #include <sys/fs/cachefs_dlog.h>
50 #include <mdbug/mdbug.h>
52 #include "cfsd_maptbl.h"
58 * Constructor for the cfsd_maptbl class.
59 * Just does some setup not much else.
64 cfsd_maptbl_object_t
*
65 cfsd_maptbl_create(void)
67 cfsd_maptbl_object_t
*maptbl_object_p
;
69 dbug_enter("cfsd_maptbl_create");
71 maptbl_object_p
= cfsd_calloc(sizeof (cfsd_maptbl_object_t
));
73 maptbl_object_p
->i_fid
= -1;
74 maptbl_object_p
->i_pa
= NULL
;
75 maptbl_object_p
->i_paoff
= 0;
76 maptbl_object_p
->i_paend
= 0;
77 maptbl_object_p
->i_palen
= 0;
78 dbug_leave("cfsd_maptbl_create");
79 return (maptbl_object_p
);
86 * Destructor for the cfsd_maptbl class.
92 cfsd_maptbl_destroy(cfsd_maptbl_object_t
*maptbl_object_p
)
94 dbug_enter("cfsd_maptbl_destroy");
95 dbug_precond(maptbl_object_p
);
96 maptbl_teardown(maptbl_object_p
);
97 cfsd_free(maptbl_object_p
);
98 dbug_leave("cfsd_maptbl_destroy");
105 * Maps in the specified section of the file.
107 * off The offset to map in. Must be i_pagesize aligned.
109 * Returns 0 for success or an errno value on failure.
113 maptbl_domap(cfsd_maptbl_object_t
*maptbl_object_p
, off_t off
)
118 dbug_enter("maptbl_domap");
119 dbug_precond(maptbl_object_p
);
120 dbug_precond(maptbl_object_p
->i_fid
>= 0);
122 len
= maptbl_object_p
->i_maplen
;
124 maptbl_object_p
->i_stat_mapmove
++;
126 /* destroy old mapping if it exists */
127 if (maptbl_object_p
->i_pa
) {
128 /* determine how far we have to move the map */
129 maptbl_object_p
->i_stat_mapdist
+=
130 abs(maptbl_object_p
->i_paoff
- off
);
133 xx
= munmap(maptbl_object_p
->i_pa
, maptbl_object_p
->i_palen
);
136 dbug_print(("error", "Could not unmap %s, %d, %p, %d",
137 maptbl_object_p
->i_name
, xx
, maptbl_object_p
->i_pa
,
138 maptbl_object_p
->i_palen
));
140 maptbl_object_p
->i_pa
= NULL
;
141 maptbl_object_p
->i_palen
= 0;
142 maptbl_object_p
->i_paoff
= 0;
143 maptbl_object_p
->i_paend
= 0;
147 maptbl_object_p
->i_pa
=
148 mmap(NULL
, len
, PROT_READ
| PROT_WRITE
, MAP_SHARED
,
149 maptbl_object_p
->i_fid
, off
);
150 if (maptbl_object_p
->i_pa
== MAP_FAILED
) {
153 "Could not map %s, error %d, off %d, len %d",
154 maptbl_object_p
->i_name
, xx
, off
, len
));
155 maptbl_object_p
->i_pa
= NULL
;
156 dbug_leave("maptbl_domap");
160 maptbl_object_p
->i_palen
= len
;
161 maptbl_object_p
->i_paoff
= off
;
162 maptbl_object_p
->i_paend
= off
+ len
- 1;
163 dbug_leave("maptbl_domap");
171 * Returns an address of a particular entry in the file.
175 * Returns NULL for a failure with the mapping file.
179 maptbl_getaddr(cfsd_maptbl_object_t
*maptbl_object_p
, int index
)
185 dbug_enter("maptbl_getaddr");
186 dbug_precond(maptbl_object_p
);
187 dbug_precond(index
< maptbl_object_p
->i_entries
);
189 /* find the boundaries of the entry */
190 start
= index
* sizeof (struct cfs_dlog_mapping_space
);
191 end
= start
+ sizeof (struct cfs_dlog_mapping_space
) - 1;
193 /* map the entry in if necessary */
194 if ((start
< maptbl_object_p
->i_paoff
) ||
195 (maptbl_object_p
->i_paend
< end
)) {
196 if (maptbl_domap(maptbl_object_p
,
197 start
& maptbl_object_p
->i_pagemask
)) {
198 dbug_leave("maptbl_getaddr");
203 /* make an address and return it */
204 pa
= maptbl_object_p
->i_pa
+ (start
- maptbl_object_p
->i_paoff
);
205 dbug_leave("maptbl_getaddr");
213 * Finds the address of the specified cid by hashing to
214 * the appropriate entry. If the cid does not already
215 * exist in the file, then the address of where it should
216 * reside is returned.
221 * Returns 0 for success, 1 if entry not found, -1 if an
222 * error occurs in the mapping file.
226 maptbl_cidhashaddr(cfsd_maptbl_object_t
*maptbl_object_p
,
235 dbug_enter("maptbl_cidhashaddr");
236 dbug_precond(maptbl_object_p
);
239 maptbl_object_p
->i_stat_requests
++;
241 /* get the index from the first hash function */
242 index
= maptbl_hash1(maptbl_object_p
, cid
);
244 maptbl_object_p
->i_stat_probes
++;
246 /* get the address of the entry */
247 pa
= (ino64_t
*)maptbl_getaddr(maptbl_object_p
, index
);
249 dbug_leave("maptbl_cidhashaddr");
254 /* check for match */
255 if (fileno
== cid
.cid_fileno
) {
256 *addrp
= (caddr_t
)pa
;
257 dbug_leave("maptbl_cidhashaddr");
261 /* check for not found */
263 *addrp
= (caddr_t
)pa
;
264 dbug_leave("maptbl_cidhashaddr");
268 /* get the index from the second hash function */
269 index
= maptbl_hash2(maptbl_object_p
, cid
, index
);
271 /* do a linear search for a match or empty entry */
274 maptbl_object_p
->i_stat_probes
++;
276 /* get the address of the entry */
277 pa
= (ino64_t
*)maptbl_getaddr(maptbl_object_p
, index
);
279 dbug_leave("maptbl_cidhashaddr");
284 /* check for match */
285 if (fileno
== cid
.cid_fileno
) {
286 *addrp
= (caddr_t
)pa
;
287 dbug_leave("maptbl_cidhashaddr");
291 /* check for not found */
293 *addrp
= (caddr_t
)pa
;
294 dbug_leave("maptbl_cidhashaddr");
298 /* move to the next entry */
300 index
= index
% maptbl_object_p
->i_entries
;
301 } while (start_index
!= index
);
303 /* table full, this is bad */
304 dbug_print(("error", "Table is full"));
305 dbug_leave("maptbl_cidhashaddr");
313 * Hashes a cid into an index into the table.
321 maptbl_hash1(cfsd_maptbl_object_t
*maptbl_object_p
, cfs_cid_t cid
)
326 dbug_precond(maptbl_object_p
);
328 xx
= cid
.cid_fileno
% i_entries
;
330 a
= cid
.cid_fileno
>> 16;
331 b
= a
^ cid
.cid_fileno
;
332 xx
= b
% maptbl_object_p
->i_entries
;
341 * Hashes a cid into an index into the table.
350 maptbl_hash2(cfsd_maptbl_object_t
*maptbl_object_p
, cfs_cid_t cid
, int index
)
353 unsigned int a
, b
, c
, d
;
355 dbug_precond(maptbl_object_p
);
357 a
= cid
.cid_fileno
& 0x0ff;
358 b
= (cid
.cid_fileno
>> 8) & 0x0ff;
359 b
= cid
.cid_fileno
^ a
^ b
;
360 xx
= b
% maptbl_object_p
->i_hash2mod
;
362 a
= cid
.cid_fileno
& 0x0ff;
363 b
= (cid
.cid_fileno
>> 8) & 0x0ff;
364 c
= (cid
.cid_fileno
>> 16) & 0x0ff;
365 d
= (cid
.cid_fileno
>> 24) & 0x0ff;
366 xx
= cid
.cid_fileno
^ (a
<< 8) ^ b
^ c
^ d
;
367 xx
= xx
% maptbl_object_p
->i_hash2mod
;
369 xx
= (index
+ xx
) % maptbl_object_p
->i_entries
;
377 * Performs setup for the cfsd_maptbl class.
378 * This routine must be called before other routines are used.
382 * Returns 0 for success or an errno value.
387 maptbl_setup(cfsd_maptbl_object_t
*maptbl_object_p
, const char *filename
)
396 dbug_enter("maptbl_setup");
397 dbug_precond(maptbl_object_p
);
398 dbug_precond(filename
);
400 /* clean up from a previous setup */
401 maptbl_teardown(maptbl_object_p
);
403 strlcpy(maptbl_object_p
->i_name
, filename
,
404 sizeof (maptbl_object_p
->i_name
));
405 dbug_print(("info", "filename %s", maptbl_object_p
->i_name
));
407 /* get the page info */
408 maptbl_object_p
->i_pagesize
= PAGESIZE
;
409 maptbl_object_p
->i_pagemask
= PAGEMASK
;
410 maptbl_object_p
->i_maplen
= maptbl_object_p
->i_pagesize
* 100;
413 maptbl_object_p
->i_fid
= open(maptbl_object_p
->i_name
,
414 O_RDWR
| O_NONBLOCK
);
415 if (maptbl_object_p
->i_fid
== -1) {
418 "Could not open %s, %d", maptbl_object_p
->i_name
, xx
));
419 dbug_leave("maptbl_setup");
423 /* get the size and type of file */
424 xx
= fstat(maptbl_object_p
->i_fid
, &sinfo
);
428 "Could not stat %s, %d", maptbl_object_p
->i_name
, xx
));
429 dbug_leave("maptbl_setup");
432 maptbl_object_p
->i_size
= sinfo
.st_size
;
434 /* sanity check, better be a regular file */
435 if (!S_ISREG(sinfo
.st_mode
)) {
438 "%s Not a regular file.", maptbl_object_p
->i_name
));
439 dbug_leave("maptbl_setup");
443 /* determine number of entries */
444 maptbl_object_p
->i_entries
=
445 maptbl_object_p
->i_size
/ sizeof (struct cfs_dlog_mapping_space
);
447 /* set up modulo value for second hash function */
448 maptbl_object_p
->i_hash2mod
= (maptbl_object_p
->i_entries
/ 2) + 1;
450 /* initialize statistic gathering */
451 maptbl_object_p
->i_stat_requests
= 0;
452 maptbl_object_p
->i_stat_probes
= 0;
453 maptbl_object_p
->i_stat_mapmove
= 0;
454 maptbl_object_p
->i_stat_mapdist
= 0;
455 maptbl_object_p
->i_stat_filled
= 0;
458 for (offset
= 0; offset
< maptbl_object_p
->i_size
;
459 offset
+= maptbl_object_p
->i_maplen
) {
460 /* map in a section of the file */
461 xx
= maptbl_domap(maptbl_object_p
, offset
);
463 dbug_leave("maptbl_setup");
466 /* zero this section of the file */
467 lp
= (long *)maptbl_object_p
->i_pa
;
468 size
= maptbl_object_p
->i_size
- offset
;
469 if (size
< maptbl_object_p
->i_palen
) {
470 cnt
= size
/ sizeof (long);
472 cnt
= maptbl_object_p
->i_palen
/ sizeof (long);
473 dbug_assert((cnt
* sizeof (long)) ==
474 maptbl_object_p
->i_palen
);
476 memset(lp
, 0, cnt
* sizeof (*lp
));
480 dbug_leave("maptbl_setup");
493 maptbl_teardown(cfsd_maptbl_object_t
*maptbl_object_p
)
497 dbug_enter("maptbl_teardown");
498 dbug_precond(maptbl_object_p
);
500 if (maptbl_object_p
->i_pa
) {
501 xx
= munmap(maptbl_object_p
->i_pa
, maptbl_object_p
->i_palen
);
504 dbug_print(("error", "Could not unmap %s, %d, %p, %d",
505 maptbl_object_p
->i_name
, xx
, maptbl_object_p
->i_pa
,
506 maptbl_object_p
->i_palen
));
508 maptbl_object_p
->i_pa
= NULL
;
510 maptbl_object_p
->i_paoff
= 0;
511 maptbl_object_p
->i_paend
= 0;
512 maptbl_object_p
->i_palen
= 0;
514 if (maptbl_object_p
->i_fid
!= -1) {
515 if (close(maptbl_object_p
->i_fid
))
516 dbug_print(("err", "cannot close maptbl fd, error %d",
518 maptbl_object_p
->i_fid
= -1;
520 dbug_leave("maptbl_teardown");
527 * Gets the mapping info for the specified cid.
532 * Returns 0 for success, 1 if entry not found, -1 if an
533 * error occurs in the mapping file.
538 maptbl_get(cfsd_maptbl_object_t
*maptbl_object_p
,
540 struct cfs_dlog_mapping_space
*valuep
)
543 struct cfs_dlog_mapping_space
*pa
;
545 dbug_enter("maptbl_get");
546 dbug_precond(maptbl_object_p
);
547 dbug_precond(valuep
);
549 if (maptbl_object_p
->i_entries
== 0) {
550 dbug_leave("maptbl_get");
553 xx
= maptbl_cidhashaddr(maptbl_object_p
, cid
, (caddr_t
*)&pa
);
556 dbug_leave("maptbl_get");
564 * Sets the mapping info for the cid.
565 * If insert is 1 then if the entry is not found it is put in the
571 * Returns 0 if mapping info placed in the table, 1 if entry
572 * is not found an insert is 0, -1 if an error occurs in the
578 maptbl_set(cfsd_maptbl_object_t
*maptbl_object_p
,
579 struct cfs_dlog_mapping_space
*valuep
,
583 struct cfs_dlog_mapping_space
*pa
;
585 dbug_enter("maptbl_set");
586 dbug_precond(maptbl_object_p
);
587 dbug_precond(valuep
);
589 dbug_assert(maptbl_object_p
->i_entries
> 0);
591 xx
= maptbl_cidhashaddr(maptbl_object_p
, valuep
->ms_cid
,
593 if ((xx
== 0) || ((xx
== 1) && insert
)) {
596 maptbl_object_p
->i_stat_filled
++;
599 dbug_leave("maptbl_set");
607 * Prints out various stats about the hashing.
613 maptbl_dumpstats(cfsd_maptbl_object_t
*maptbl_object_p
)
618 dbug_enter("maptbl_dumpstats");
619 dbug_precond(maptbl_object_p
);
621 dbug_print(("dump", "Total Entries %d", maptbl_object_p
->i_entries
));
622 dbug_print(("dump", "Filled Entries %d",
623 maptbl_object_p
->i_stat_filled
));
624 dbug_print(("dump", "Requests %d", maptbl_object_p
->i_stat_requests
));
625 dbug_print(("dump", "Probes %d", maptbl_object_p
->i_stat_probes
));
626 dbug_print(("dump", "Map Moves %d", maptbl_object_p
->i_stat_mapmove
));
627 dbug_print(("dump", "Mapping Size %d", maptbl_object_p
->i_maplen
));
628 dbug_print(("dump", "File Size %d", maptbl_object_p
->i_size
));
629 if (maptbl_object_p
->i_stat_requests
== 0) {
630 dbug_leave("maptbl_dumpstats");
633 dd
= (double)maptbl_object_p
->i_stat_probes
/
634 maptbl_object_p
->i_stat_requests
;
635 dbug_print(("dump", "Probes per Request %.2f", dd
));
637 dd
= (double)maptbl_object_p
->i_stat_mapmove
/
638 maptbl_object_p
->i_stat_requests
;
639 dbug_print(("dump", "Mmap moves per Request %.2f", dd
));
641 xx
= maptbl_object_p
->i_stat_mapdist
/ maptbl_object_p
->i_stat_mapmove
;
642 dbug_print(("dump", "Average distance per mmap moves %d", xx
));
644 xx
= ((100.0 * maptbl_object_p
->i_stat_filled
) /
645 maptbl_object_p
->i_entries
) + .5;
646 dbug_print(("dump", "Table filled %d%%", xx
));
648 dbug_leave("maptbl_dumpstats");