xref: /onnv-gate/usr/src/uts/common/fs/hsfs/hsfs_subr.c (revision 5406:4c7dea02885f)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52900Sfrankho  * Common Development and Distribution License (the "License").
62900Sfrankho  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
220Sstevel@tonic-gate  * Miscellaneous support subroutines for High Sierra filesystem
230Sstevel@tonic-gate  *
244866Sfrankho  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
252900Sfrankho  * Use is subject to license terms.
260Sstevel@tonic-gate  */
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
290Sstevel@tonic-gate 
300Sstevel@tonic-gate #include <sys/types.h>
310Sstevel@tonic-gate #include <sys/param.h>
320Sstevel@tonic-gate #include <sys/time.h>
330Sstevel@tonic-gate #include <sys/cmn_err.h>
340Sstevel@tonic-gate #include <sys/systm.h>
350Sstevel@tonic-gate #include <sys/sysmacros.h>
360Sstevel@tonic-gate #include <sys/buf.h>
370Sstevel@tonic-gate #include <sys/conf.h>
380Sstevel@tonic-gate #include <sys/user.h>
390Sstevel@tonic-gate #include <sys/vfs.h>
400Sstevel@tonic-gate #include <sys/vnode.h>
410Sstevel@tonic-gate #include <sys/proc.h>
420Sstevel@tonic-gate #include <sys/debug.h>
430Sstevel@tonic-gate #include <sys/kmem.h>
440Sstevel@tonic-gate #include <sys/uio.h>
450Sstevel@tonic-gate #include <vm/hat.h>
460Sstevel@tonic-gate #include <vm/as.h>
470Sstevel@tonic-gate #include <vm/seg.h>
480Sstevel@tonic-gate #include <vm/page.h>
490Sstevel@tonic-gate #include <vm/pvn.h>
500Sstevel@tonic-gate #include <vm/seg_map.h>
510Sstevel@tonic-gate #include <sys/swap.h>
520Sstevel@tonic-gate #include <vm/seg_kmem.h>
530Sstevel@tonic-gate 
540Sstevel@tonic-gate #include <sys/fs/hsfs_spec.h>
550Sstevel@tonic-gate #include <sys/fs/hsfs_node.h>
560Sstevel@tonic-gate #include <sys/fs/hsfs_impl.h>
570Sstevel@tonic-gate 
580Sstevel@tonic-gate #define	THE_EPOCH	1970
590Sstevel@tonic-gate #define	END_OF_TIME	2099
605312Smg147109 extern int hsfs_lostpage;
610Sstevel@tonic-gate 
620Sstevel@tonic-gate #ifdef __STDC__
630Sstevel@tonic-gate static time_t hs_date_to_gmtime(int year, int mon, int day, int gmtoff);
640Sstevel@tonic-gate #else
650Sstevel@tonic-gate static time_t hs_date_to_gmtime();
660Sstevel@tonic-gate #endif
670Sstevel@tonic-gate 
680Sstevel@tonic-gate /*
690Sstevel@tonic-gate  * Table used in logging non-fatal errors which should be recorded
700Sstevel@tonic-gate  * once per mount.  Indexed by HSFS_ERR values (defined in hsfs_node.h).
710Sstevel@tonic-gate  */
720Sstevel@tonic-gate struct hsfs_error {
730Sstevel@tonic-gate 	char	*hdr_text;	/* msg prefix: general error type */
740Sstevel@tonic-gate 				/* must contain %s for mnt pt */
750Sstevel@tonic-gate 	char 	*err_text;	/* specific error message */
760Sstevel@tonic-gate 	uchar_t	multiple;	/* > 1 such error per fs possible? */
770Sstevel@tonic-gate 	uchar_t	n_printf_args;	/* if err_text printf-like, # addtl args */
780Sstevel@tonic-gate } hsfs_error[] = {
790Sstevel@tonic-gate 	/* HSFS_ERR_TRAILING_JUNK */
802900Sfrankho 	"hsfs: Warning: the file system mounted on %s "
810Sstevel@tonic-gate 		"does not conform to the ISO-9660 specification:",
822900Sfrankho 	"trailing blanks or null characters in file or directory name.\n",
830Sstevel@tonic-gate 	1, 0,
840Sstevel@tonic-gate 	/* HSFS_ERR_LOWER_CASE_NM */
852900Sfrankho 	"hsfs: Warning: the file system mounted on %s "
862900Sfrankho 		"does not conform to the ISO-9660 specification:",
872900Sfrankho 	"lower case characters in file or directory name.\n",
880Sstevel@tonic-gate 	1, 0,
890Sstevel@tonic-gate 	/* HSFS_ERR_BAD_ROOT_DIR */
902900Sfrankho 	"hsfs: Warning: the file system mounted on %s "
910Sstevel@tonic-gate 		"does not conform to the ISO-9660 specification:",
922900Sfrankho 	"invalid root directory.\n",
930Sstevel@tonic-gate 	0,  0,
940Sstevel@tonic-gate 	/* HSFS_ERR_UNSUP_TYPE */
952900Sfrankho 	"hsfs: Warning: the file system mounted on %s "
960Sstevel@tonic-gate 		"contains a file or directory with an unsupported type:",
970Sstevel@tonic-gate 	" 0x%x.\n",
980Sstevel@tonic-gate 	1, 1,
990Sstevel@tonic-gate 	/* HSFS_ERR_BAD_FILE_LEN */
1002900Sfrankho 	"hsfs: Warning: file system mounted on %s "
1010Sstevel@tonic-gate 		"does not conform to the ISO-9660 specification:",
1022900Sfrankho 	"file name length greater than max allowed\n",
1032900Sfrankho 	1, 0,
1042900Sfrankho 	/* HSFS_ERR_BAD_JOLIET_FILE_LEN */
1052900Sfrankho 	"hsfs: Warning: file system mounted on %s "
1062900Sfrankho 		"does not conform to the Joliet specification:",
1072900Sfrankho 	"file name length greater than max allowed\n",
1082900Sfrankho 	1, 0,
1092900Sfrankho 	/* HSFS_ERR_TRUNC_JOLIET_FILE_LEN */
1102900Sfrankho 	"hsfs: Warning: file system mounted on %s "
1112900Sfrankho 		"does not conform to the Joliet specification:",
1122900Sfrankho 	"file name length greater than MAXNAMELEN (truncated)\n",
1132900Sfrankho 	1, 0,
1142900Sfrankho 	/* HSFS_ERR_BAD_DIR_ENTRY */
1152900Sfrankho 	"hsfs: Warning: file system mounted on %s "
1162900Sfrankho 		"has inconsistent data:",
1172900Sfrankho 	"invalid directory or file name length (ignored)\n",
1180Sstevel@tonic-gate 	1, 0,
1194866Sfrankho 	/* HSFS_ERR_NEG_SUA_LEN */
1204866Sfrankho 	"hsfs: Warning: file system mounted on %s "
1214866Sfrankho 		"has inconsistent Rock Ridge data:",
1224866Sfrankho 	"negative SUA len\n",
1234866Sfrankho 	1, 0,
1244866Sfrankho 	/* HSFS_ERR_BAD_SUA_LEN */
1254866Sfrankho 	"hsfs: Warning: file system mounted on %s "
1264866Sfrankho 		"has inconsistent Rock Ridge data:",
1274866Sfrankho 	"SUA len too big\n",
1284866Sfrankho 	1, 0,
1290Sstevel@tonic-gate };
1300Sstevel@tonic-gate 
1315312Smg147109 /*
1325312Smg147109  * Local datatype for defining tables of (Offset, Name) pairs for
1335312Smg147109  * kstats.
1345312Smg147109  */
1355312Smg147109 typedef struct {
1365312Smg147109 	offset_t	index;
1375312Smg147109 	char		*name;
1385312Smg147109 } hsfs_ksindex_t;
1390Sstevel@tonic-gate 
1405312Smg147109 static const hsfs_ksindex_t hsfs_kstats[] = {
1415312Smg147109 	{ 0,		"mountpoint"		},
1425312Smg147109 	{ 1,		"pages_lost"		},
1435312Smg147109 	{ 2,		"physical_read_pages"	},
1445312Smg147109 	{ 3,		"cache_read_pages"	},
1455312Smg147109 	{ 4,		"readahead_pages"	},
1465312Smg147109 	{ 5,		"coalesced_pages"	},
1475312Smg147109 	{ 6,		"total_pages_requested"	},
1485312Smg147109 	{-1,		NULL 			}
1495312Smg147109 };
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate /*
1520Sstevel@tonic-gate  * hs_parse_dirdate
1530Sstevel@tonic-gate  *
1540Sstevel@tonic-gate  * Parse the short 'directory-format' date into a Unix timeval.
1550Sstevel@tonic-gate  * This is the date format used in Directory Entries.
1560Sstevel@tonic-gate  *
1570Sstevel@tonic-gate  * If the date is not representable, make something up.
1580Sstevel@tonic-gate  */
1590Sstevel@tonic-gate void
hs_parse_dirdate(dp,tvp)1600Sstevel@tonic-gate hs_parse_dirdate(dp, tvp)
1610Sstevel@tonic-gate 	uchar_t *dp;
1620Sstevel@tonic-gate 	struct timeval *tvp;
1630Sstevel@tonic-gate {
1640Sstevel@tonic-gate 	int year, month, day, hour, minute, sec, gmtoff;
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate 	year = HDE_DATE_YEAR(dp);
1670Sstevel@tonic-gate 	month = HDE_DATE_MONTH(dp);
1680Sstevel@tonic-gate 	day = HDE_DATE_DAY(dp);
1690Sstevel@tonic-gate 	hour = HDE_DATE_HOUR(dp);
1700Sstevel@tonic-gate 	minute = HDE_DATE_MIN(dp);
1710Sstevel@tonic-gate 	sec = HDE_DATE_SEC(dp);
1720Sstevel@tonic-gate 	gmtoff = HDE_DATE_GMTOFF(dp);
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate 	tvp->tv_usec = 0;
1750Sstevel@tonic-gate 	if (year < THE_EPOCH) {
1760Sstevel@tonic-gate 		tvp->tv_sec = 0;
1770Sstevel@tonic-gate 	} else {
1780Sstevel@tonic-gate 		tvp->tv_sec = hs_date_to_gmtime(year, month, day, gmtoff);
1790Sstevel@tonic-gate 		if (tvp->tv_sec != -1) {
1800Sstevel@tonic-gate 			tvp->tv_sec += ((hour * 60) + minute) * 60 + sec;
1810Sstevel@tonic-gate 		}
1820Sstevel@tonic-gate 	}
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate 	return;
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate }
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate /*
1890Sstevel@tonic-gate  * hs_parse_longdate
1900Sstevel@tonic-gate  *
1910Sstevel@tonic-gate  * Parse the long 'user-oriented' date into a Unix timeval.
1920Sstevel@tonic-gate  * This is the date format used in the Volume Descriptor.
1930Sstevel@tonic-gate  *
1940Sstevel@tonic-gate  * If the date is not representable, make something up.
1950Sstevel@tonic-gate  */
1960Sstevel@tonic-gate void
hs_parse_longdate(dp,tvp)1970Sstevel@tonic-gate hs_parse_longdate(dp, tvp)
1980Sstevel@tonic-gate 	uchar_t *dp;
1990Sstevel@tonic-gate 	struct timeval *tvp;
2000Sstevel@tonic-gate {
2010Sstevel@tonic-gate 	int year, month, day, hour, minute, sec, gmtoff;
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate 	year = HSV_DATE_YEAR(dp);
2040Sstevel@tonic-gate 	month = HSV_DATE_MONTH(dp);
2050Sstevel@tonic-gate 	day = HSV_DATE_DAY(dp);
2060Sstevel@tonic-gate 	hour = HSV_DATE_HOUR(dp);
2070Sstevel@tonic-gate 	minute = HSV_DATE_MIN(dp);
2080Sstevel@tonic-gate 	sec = HSV_DATE_SEC(dp);
2090Sstevel@tonic-gate 	gmtoff = HSV_DATE_GMTOFF(dp);
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate 	tvp->tv_usec = 0;
2120Sstevel@tonic-gate 	if (year < THE_EPOCH) {
2130Sstevel@tonic-gate 		tvp->tv_sec = 0;
2140Sstevel@tonic-gate 	} else {
2150Sstevel@tonic-gate 		tvp->tv_sec = hs_date_to_gmtime(year, month, day, gmtoff);
2160Sstevel@tonic-gate 		if (tvp->tv_sec != -1) {
2170Sstevel@tonic-gate 			tvp->tv_sec += ((hour * 60) + minute) * 60 + sec;
2180Sstevel@tonic-gate 			tvp->tv_usec = HSV_DATE_HSEC(dp) * 10000;
2190Sstevel@tonic-gate 		}
2200Sstevel@tonic-gate 	}
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate }
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate /* cumulative number of seconds per month,  non-leap and leap-year versions */
2250Sstevel@tonic-gate static time_t cum_sec[] = {
2260Sstevel@tonic-gate 	0x0, 0x28de80, 0x4dc880, 0x76a700, 0x9e3400, 0xc71280,
2270Sstevel@tonic-gate 	0xee9f80, 0x1177e00, 0x1405c80, 0x167e980, 0x190c800, 0x1b85500
2280Sstevel@tonic-gate };
2290Sstevel@tonic-gate static time_t cum_sec_leap[] = {
2300Sstevel@tonic-gate 	0x0, 0x28de80, 0x4f1a00, 0x77f880, 0x9f8580, 0xc86400,
2310Sstevel@tonic-gate 	0xeff100, 0x118cf80, 0x141ae00, 0x1693b00, 0x1921980, 0x1b9a680
2320Sstevel@tonic-gate };
2330Sstevel@tonic-gate #define	SEC_PER_DAY	0x15180
2340Sstevel@tonic-gate #define	SEC_PER_YEAR	0x1e13380
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate /*
2370Sstevel@tonic-gate  * hs_date_to_gmtime
2380Sstevel@tonic-gate  *
2390Sstevel@tonic-gate  * Convert year(1970-2099)/month(1-12)/day(1-31) to seconds-since-1970/1/1.
2400Sstevel@tonic-gate  *
2410Sstevel@tonic-gate  * Returns -1 if the date is out of range.
2420Sstevel@tonic-gate  */
2430Sstevel@tonic-gate static time_t
hs_date_to_gmtime(year,mon,day,gmtoff)2440Sstevel@tonic-gate hs_date_to_gmtime(year, mon, day, gmtoff)
2450Sstevel@tonic-gate 	int year;
2460Sstevel@tonic-gate 	int mon;
2470Sstevel@tonic-gate 	int day;
2480Sstevel@tonic-gate 	int gmtoff;
2490Sstevel@tonic-gate {
2500Sstevel@tonic-gate 	time_t sum;
2510Sstevel@tonic-gate 	time_t *cp;
2520Sstevel@tonic-gate 	int y;
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate 	if ((year < THE_EPOCH) || (year > END_OF_TIME) ||
2550Sstevel@tonic-gate 	    (mon < 1) || (mon > 12) ||
2560Sstevel@tonic-gate 	    (day < 1) || (day > 31))
2570Sstevel@tonic-gate 		return (-1);
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate 	/*
2600Sstevel@tonic-gate 	 * Figure seconds until this year and correct for leap years.
2610Sstevel@tonic-gate 	 * Note: 2000 is a leap year but not 2100.
2620Sstevel@tonic-gate 	 */
2630Sstevel@tonic-gate 	y = year - THE_EPOCH;
2640Sstevel@tonic-gate 	sum = y * SEC_PER_YEAR;
2650Sstevel@tonic-gate 	sum += ((y + 1) / 4) * SEC_PER_DAY;
2660Sstevel@tonic-gate 	/*
2670Sstevel@tonic-gate 	 * Point to the correct table for this year and
2680Sstevel@tonic-gate 	 * add in seconds until this month.
2690Sstevel@tonic-gate 	 */
2700Sstevel@tonic-gate 	cp = ((y + 2) % 4) ? cum_sec : cum_sec_leap;
2710Sstevel@tonic-gate 	sum += cp[mon - 1];
2720Sstevel@tonic-gate 	/*
2730Sstevel@tonic-gate 	 * Add in seconds until 0:00 of this day.
2740Sstevel@tonic-gate 	 * (days-per-month validation is not done here)
2750Sstevel@tonic-gate 	 */
2760Sstevel@tonic-gate 	sum += (day - 1) * SEC_PER_DAY;
2770Sstevel@tonic-gate 	sum -= (gmtoff * 15 * 60);
2780Sstevel@tonic-gate 	return (sum);
2790Sstevel@tonic-gate }
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate /*
2820Sstevel@tonic-gate  * Indicate whether the directory is valid.
2830Sstevel@tonic-gate  */
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate int
hsfs_valid_dir(hd)2860Sstevel@tonic-gate hsfs_valid_dir(hd)
2870Sstevel@tonic-gate 	struct hs_direntry *hd;
2880Sstevel@tonic-gate {
2890Sstevel@tonic-gate 	/*
2900Sstevel@tonic-gate 	 * check to see if this directory is not marked as a directory.
2910Sstevel@tonic-gate 	 * check to see if data length is zero.
2920Sstevel@tonic-gate 	 */
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 	if (hd->ext_size == 0)
2950Sstevel@tonic-gate 		return (0);
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 	if (hd->type != VDIR)
2980Sstevel@tonic-gate 		return (0);
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate 	return (1);
3010Sstevel@tonic-gate }
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate /*
3060Sstevel@tonic-gate  * If we haven't complained about this error type yet, do.
3070Sstevel@tonic-gate  */
3080Sstevel@tonic-gate void
hs_log_bogus_disk_warning(fsp,errtype,data)3090Sstevel@tonic-gate hs_log_bogus_disk_warning(fsp, errtype, data)
3100Sstevel@tonic-gate 	struct hsfs	*fsp;
3110Sstevel@tonic-gate 	int 		errtype;
3120Sstevel@tonic-gate 	uint_t		data;
3130Sstevel@tonic-gate {
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 	if (fsp->hsfs_err_flags & (1 << errtype))
3160Sstevel@tonic-gate 		return;		/* already complained */
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 	cmn_err(CE_NOTE, hsfs_error[errtype].hdr_text,
3190Sstevel@tonic-gate 		fsp->hsfs_fsmnt);
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 	switch (hsfs_error[errtype].n_printf_args) {
3220Sstevel@tonic-gate 	case 0:
3230Sstevel@tonic-gate 		cmn_err(CE_CONT, hsfs_error[errtype].err_text);
3240Sstevel@tonic-gate 		break;
3250Sstevel@tonic-gate 	case 1:
3260Sstevel@tonic-gate 		cmn_err(CE_CONT, hsfs_error[errtype].err_text, data);
3270Sstevel@tonic-gate 		break;
3280Sstevel@tonic-gate 	default:
3290Sstevel@tonic-gate 		/* don't currently handle more than 1 arg */
3300Sstevel@tonic-gate 		cmn_err(CE_CONT, "unknown problem; internal error.\n");
3310Sstevel@tonic-gate 	}
3320Sstevel@tonic-gate 	cmn_err(CE_CONT,
3330Sstevel@tonic-gate "Due to this error, the file system may not be correctly interpreted.\n");
3340Sstevel@tonic-gate 	if (hsfs_error[errtype].multiple)
3350Sstevel@tonic-gate 		cmn_err(CE_CONT,
3360Sstevel@tonic-gate "Other such errors in this file system will be silently ignored.\n\n");
3370Sstevel@tonic-gate 	else
3380Sstevel@tonic-gate 		cmn_err(CE_CONT, "\n");
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate 	fsp->hsfs_err_flags |= (1 << errtype);
3410Sstevel@tonic-gate }
3425312Smg147109 
3435312Smg147109 /*
3445312Smg147109  * Callback from kstat framework. Grab a snapshot of the current hsfs
3455312Smg147109  * counters and populate the kstats.
3465312Smg147109  */
3475312Smg147109 static int
hsfs_kstats_update(kstat_t * ksp,int flag)3485312Smg147109 hsfs_kstats_update(kstat_t *ksp, int flag)
3495312Smg147109 {
3505312Smg147109 	struct hsfs *fsp;
3515312Smg147109 	kstat_named_t *knp;
3525312Smg147109 	uint64_t pages_lost;
3535312Smg147109 	uint64_t physical_read_bytes;
3545312Smg147109 	uint64_t cache_read_pages;
3555312Smg147109 	uint64_t readahead_bytes;
3565312Smg147109 	uint64_t coalesced_bytes;
3575312Smg147109 	uint64_t total_pages_requested;
3585312Smg147109 
3595312Smg147109 	if (flag != KSTAT_READ)
3605312Smg147109 		return (EACCES);
3615312Smg147109 
3625312Smg147109 	fsp = ksp->ks_private;
3635312Smg147109 	knp = ksp->ks_data;
3645312Smg147109 
3655312Smg147109 	mutex_enter(&(fsp->hqueue->strategy_lock));
3665312Smg147109 	mutex_enter(&(fsp->hqueue->hsfs_queue_lock));
3675312Smg147109 
3685312Smg147109 	cache_read_pages = fsp->cache_read_pages;
3695312Smg147109 	pages_lost = hsfs_lostpage;
3705312Smg147109 	physical_read_bytes = fsp->physical_read_bytes;
3715312Smg147109 	readahead_bytes =  fsp->readahead_bytes;
3725312Smg147109 	coalesced_bytes = fsp->coalesced_bytes;
3735312Smg147109 	total_pages_requested = fsp->total_pages_requested;
3745312Smg147109 
3755312Smg147109 	mutex_exit(&(fsp->hqueue->strategy_lock));
3765312Smg147109 	mutex_exit(&(fsp->hqueue->hsfs_queue_lock));
3775312Smg147109 
3785312Smg147109 	knp++;
3795312Smg147109 	(knp++)->value.ui64 = pages_lost;
3805312Smg147109 	(knp++)->value.ui64 = howmany(physical_read_bytes, PAGESIZE);
3815312Smg147109 	(knp++)->value.ui64 = cache_read_pages;
3825312Smg147109 	(knp++)->value.ui64 = howmany(readahead_bytes, PAGESIZE);
3835312Smg147109 	(knp++)->value.ui64 = howmany(coalesced_bytes, PAGESIZE);
3845312Smg147109 	(knp++)->value.ui64 = total_pages_requested;
3855312Smg147109 
3865312Smg147109 	return (0);
3875312Smg147109 }
3885312Smg147109 
3895312Smg147109 /*
3905312Smg147109  * Initialize hsfs kstats, which are all name value pairs with
3915312Smg147109  * values being various counters.
3925312Smg147109  */
3935312Smg147109 static kstat_t *
hsfs_setup_named_kstats(struct hsfs * fsp,int fsid,char * name,const hsfs_ksindex_t * ksip,int (* update)(kstat_t *,int))3945312Smg147109 hsfs_setup_named_kstats(struct hsfs *fsp, int fsid, char *name,
395*5406Smg147109     const hsfs_ksindex_t *ksip, int (*update)(kstat_t *, int))
3965312Smg147109 {
3975312Smg147109 	kstat_t *ksp;
3985312Smg147109 	kstat_named_t *knp;
3995312Smg147109 	char *np;
4005312Smg147109 	char *mntpt = fsp->hsfs_fsmnt;
401*5406Smg147109 	size_t size;
4025312Smg147109 
403*5406Smg147109 	size = (sizeof (hsfs_kstats)) / (sizeof (hsfs_ksindex_t));
4045312Smg147109 	ksp = kstat_create("hsfs_fs", fsid, name, "hsfs",
4055312Smg147109 	    KSTAT_TYPE_NAMED, size-1, KSTAT_FLAG_VIRTUAL);
4065312Smg147109 	if (ksp == NULL)
4075312Smg147109 		return (NULL);
4085312Smg147109 
4095312Smg147109 	ksp->ks_data = kmem_alloc(sizeof (kstat_named_t) * size, KM_SLEEP);
4105312Smg147109 	ksp->ks_private = fsp;
4115312Smg147109 	ksp->ks_update = update;
4125312Smg147109 	ksp->ks_data_size += strlen(mntpt) + 1;
4135312Smg147109 	knp = ksp->ks_data;
4145312Smg147109 	kstat_named_init(knp, ksip->name, KSTAT_DATA_STRING);
4155312Smg147109 	kstat_named_setstr(knp, mntpt);
4165312Smg147109 	knp++;
4175312Smg147109 	ksip++;
4185312Smg147109 
4195312Smg147109 	for (; (np = ksip->name) != NULL; ++knp, ++ksip) {
4205312Smg147109 		kstat_named_init(knp, np, KSTAT_DATA_UINT64);
4215312Smg147109 	}
4225312Smg147109 	kstat_install(ksp);
4235312Smg147109 
4245312Smg147109 	return (ksp);
4255312Smg147109 }
4265312Smg147109 
4275312Smg147109 void
hsfs_init_kstats(struct hsfs * fsp,int fsid)4285312Smg147109 hsfs_init_kstats(struct hsfs *fsp, int fsid)
4295312Smg147109 {
4305312Smg147109 	fsp->hsfs_kstats = hsfs_setup_named_kstats(fsp, fsid, "hsfs_read_stats",
431*5406Smg147109 	    hsfs_kstats, hsfs_kstats_update);
4325312Smg147109 }
4335312Smg147109 
4345312Smg147109 void
hsfs_fini_kstats(struct hsfs * fsp)4355312Smg147109 hsfs_fini_kstats(struct hsfs *fsp)
4365312Smg147109 {
4375312Smg147109 	void *data;
4385312Smg147109 
4395312Smg147109 	if (fsp->hsfs_kstats != NULL) {
4405312Smg147109 		data = fsp->hsfs_kstats->ks_data;
4415312Smg147109 		kstat_delete(fsp->hsfs_kstats);
442*5406Smg147109 		kmem_free(data, sizeof (kstat_named_t) *
443*5406Smg147109 		    (sizeof (hsfs_kstats)) / (sizeof (hsfs_ksindex_t)));
4445312Smg147109 	}
4455312Smg147109 	fsp->hsfs_kstats = NULL;
4465312Smg147109 }
447