xref: /illumos-gate/usr/src/uts/common/fs/hsfs/hsfs_subr.c (revision 2d6eb4a5e0a47d30189497241345dc5466bb68ab)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5fc1c62b8Sfrankho  * Common Development and Distribution License (the "License").
6fc1c62b8Sfrankho  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
227c478bd9Sstevel@tonic-gate  * Miscellaneous support subroutines for High Sierra filesystem
237c478bd9Sstevel@tonic-gate  *
24d10b6702Sfrankho  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
25fc1c62b8Sfrankho  * Use is subject to license terms.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <sys/types.h>
297c478bd9Sstevel@tonic-gate #include <sys/param.h>
307c478bd9Sstevel@tonic-gate #include <sys/time.h>
317c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
327c478bd9Sstevel@tonic-gate #include <sys/systm.h>
337c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
347c478bd9Sstevel@tonic-gate #include <sys/buf.h>
357c478bd9Sstevel@tonic-gate #include <sys/conf.h>
367c478bd9Sstevel@tonic-gate #include <sys/user.h>
377c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
387c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
397c478bd9Sstevel@tonic-gate #include <sys/proc.h>
407c478bd9Sstevel@tonic-gate #include <sys/debug.h>
417c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
427c478bd9Sstevel@tonic-gate #include <sys/uio.h>
437c478bd9Sstevel@tonic-gate #include <vm/hat.h>
447c478bd9Sstevel@tonic-gate #include <vm/as.h>
457c478bd9Sstevel@tonic-gate #include <vm/seg.h>
467c478bd9Sstevel@tonic-gate #include <vm/page.h>
477c478bd9Sstevel@tonic-gate #include <vm/pvn.h>
487c478bd9Sstevel@tonic-gate #include <vm/seg_map.h>
497c478bd9Sstevel@tonic-gate #include <sys/swap.h>
507c478bd9Sstevel@tonic-gate #include <vm/seg_kmem.h>
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate #include <sys/fs/hsfs_spec.h>
537c478bd9Sstevel@tonic-gate #include <sys/fs/hsfs_node.h>
547c478bd9Sstevel@tonic-gate #include <sys/fs/hsfs_impl.h>
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate #define	THE_EPOCH	1970
577c478bd9Sstevel@tonic-gate #define	END_OF_TIME	2099
5884b82766Smg147109 extern int hsfs_lostpage;
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate #ifdef __STDC__
617c478bd9Sstevel@tonic-gate static time_t hs_date_to_gmtime(int year, int mon, int day, int gmtoff);
627c478bd9Sstevel@tonic-gate #else
637c478bd9Sstevel@tonic-gate static time_t hs_date_to_gmtime();
647c478bd9Sstevel@tonic-gate #endif
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate /*
677c478bd9Sstevel@tonic-gate  * Table used in logging non-fatal errors which should be recorded
687c478bd9Sstevel@tonic-gate  * once per mount.  Indexed by HSFS_ERR values (defined in hsfs_node.h).
697c478bd9Sstevel@tonic-gate  */
707c478bd9Sstevel@tonic-gate struct hsfs_error {
717c478bd9Sstevel@tonic-gate 	char	*hdr_text;	/* msg prefix: general error type */
727c478bd9Sstevel@tonic-gate 				/* must contain %s for mnt pt */
737c478bd9Sstevel@tonic-gate 	char 	*err_text;	/* specific error message */
747c478bd9Sstevel@tonic-gate 	uchar_t	multiple;	/* > 1 such error per fs possible? */
757c478bd9Sstevel@tonic-gate 	uchar_t	n_printf_args;	/* if err_text printf-like, # addtl args */
767c478bd9Sstevel@tonic-gate } hsfs_error[] = {
777c478bd9Sstevel@tonic-gate 	/* HSFS_ERR_TRAILING_JUNK */
78fc1c62b8Sfrankho 	"hsfs: Warning: the file system mounted on %s "
797c478bd9Sstevel@tonic-gate 		"does not conform to the ISO-9660 specification:",
807c478bd9Sstevel@tonic-gate 	"trailing blanks or null characters in file or directory name.\n",
817c478bd9Sstevel@tonic-gate 	1, 0,
827c478bd9Sstevel@tonic-gate 	/* HSFS_ERR_LOWER_CASE_NM */
83fc1c62b8Sfrankho 	"hsfs: Warning: the file system mounted on %s "
847c478bd9Sstevel@tonic-gate 		"does not conform to the ISO-9660 specification:",
857c478bd9Sstevel@tonic-gate 	"lower case characters in file or directory name.\n",
867c478bd9Sstevel@tonic-gate 	1, 0,
877c478bd9Sstevel@tonic-gate 	/* HSFS_ERR_BAD_ROOT_DIR */
88fc1c62b8Sfrankho 	"hsfs: Warning: the file system mounted on %s "
897c478bd9Sstevel@tonic-gate 		"does not conform to the ISO-9660 specification:",
907c478bd9Sstevel@tonic-gate 	"invalid root directory.\n",
917c478bd9Sstevel@tonic-gate 	0,  0,
927c478bd9Sstevel@tonic-gate 	/* HSFS_ERR_UNSUP_TYPE */
93fc1c62b8Sfrankho 	"hsfs: Warning: the file system mounted on %s "
947c478bd9Sstevel@tonic-gate 		"contains a file or directory with an unsupported type:",
957c478bd9Sstevel@tonic-gate 	" 0x%x.\n",
967c478bd9Sstevel@tonic-gate 	1, 1,
977c478bd9Sstevel@tonic-gate 	/* HSFS_ERR_BAD_FILE_LEN */
98fc1c62b8Sfrankho 	"hsfs: Warning: file system mounted on %s "
997c478bd9Sstevel@tonic-gate 		"does not conform to the ISO-9660 specification:",
100fc1c62b8Sfrankho 	"file name length greater than max allowed\n",
101fc1c62b8Sfrankho 	1, 0,
102fc1c62b8Sfrankho 	/* HSFS_ERR_BAD_JOLIET_FILE_LEN */
103fc1c62b8Sfrankho 	"hsfs: Warning: file system mounted on %s "
104fc1c62b8Sfrankho 		"does not conform to the Joliet specification:",
105fc1c62b8Sfrankho 	"file name length greater than max allowed\n",
106fc1c62b8Sfrankho 	1, 0,
107fc1c62b8Sfrankho 	/* HSFS_ERR_TRUNC_JOLIET_FILE_LEN */
108fc1c62b8Sfrankho 	"hsfs: Warning: file system mounted on %s "
109fc1c62b8Sfrankho 		"does not conform to the Joliet specification:",
110fc1c62b8Sfrankho 	"file name length greater than MAXNAMELEN (truncated)\n",
111fc1c62b8Sfrankho 	1, 0,
112fc1c62b8Sfrankho 	/* HSFS_ERR_BAD_DIR_ENTRY */
113fc1c62b8Sfrankho 	"hsfs: Warning: file system mounted on %s "
114fc1c62b8Sfrankho 		"has inconsistent data:",
115fc1c62b8Sfrankho 	"invalid directory or file name length (ignored)\n",
1167c478bd9Sstevel@tonic-gate 	1, 0,
117d10b6702Sfrankho 	/* HSFS_ERR_NEG_SUA_LEN */
118d10b6702Sfrankho 	"hsfs: Warning: file system mounted on %s "
119d10b6702Sfrankho 		"has inconsistent Rock Ridge data:",
120d10b6702Sfrankho 	"negative SUA len\n",
121d10b6702Sfrankho 	1, 0,
122d10b6702Sfrankho 	/* HSFS_ERR_BAD_SUA_LEN */
123d10b6702Sfrankho 	"hsfs: Warning: file system mounted on %s "
124d10b6702Sfrankho 		"has inconsistent Rock Ridge data:",
125d10b6702Sfrankho 	"SUA len too big\n",
126d10b6702Sfrankho 	1, 0,
1277c478bd9Sstevel@tonic-gate };
1287c478bd9Sstevel@tonic-gate 
12984b82766Smg147109 /*
13084b82766Smg147109  * Local datatype for defining tables of (Offset, Name) pairs for
13184b82766Smg147109  * kstats.
13284b82766Smg147109  */
13384b82766Smg147109 typedef struct {
13484b82766Smg147109 	offset_t	index;
13584b82766Smg147109 	char		*name;
13684b82766Smg147109 } hsfs_ksindex_t;
1377c478bd9Sstevel@tonic-gate 
13884b82766Smg147109 static const hsfs_ksindex_t hsfs_kstats[] = {
13984b82766Smg147109 	{ 0,		"mountpoint"		},
14084b82766Smg147109 	{ 1,		"pages_lost"		},
14184b82766Smg147109 	{ 2,		"physical_read_pages"	},
14284b82766Smg147109 	{ 3,		"cache_read_pages"	},
14384b82766Smg147109 	{ 4,		"readahead_pages"	},
14484b82766Smg147109 	{ 5,		"coalesced_pages"	},
14584b82766Smg147109 	{ 6,		"total_pages_requested"	},
14684b82766Smg147109 	{-1,		NULL 			}
14784b82766Smg147109 };
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate /*
1507c478bd9Sstevel@tonic-gate  * hs_parse_dirdate
1517c478bd9Sstevel@tonic-gate  *
1527c478bd9Sstevel@tonic-gate  * Parse the short 'directory-format' date into a Unix timeval.
1537c478bd9Sstevel@tonic-gate  * This is the date format used in Directory Entries.
1547c478bd9Sstevel@tonic-gate  *
1557c478bd9Sstevel@tonic-gate  * If the date is not representable, make something up.
1567c478bd9Sstevel@tonic-gate  */
1577c478bd9Sstevel@tonic-gate void
hs_parse_dirdate(dp,tvp)1587c478bd9Sstevel@tonic-gate hs_parse_dirdate(dp, tvp)
1597c478bd9Sstevel@tonic-gate 	uchar_t *dp;
1607c478bd9Sstevel@tonic-gate 	struct timeval *tvp;
1617c478bd9Sstevel@tonic-gate {
1627c478bd9Sstevel@tonic-gate 	int year, month, day, hour, minute, sec, gmtoff;
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	year = HDE_DATE_YEAR(dp);
1657c478bd9Sstevel@tonic-gate 	month = HDE_DATE_MONTH(dp);
1667c478bd9Sstevel@tonic-gate 	day = HDE_DATE_DAY(dp);
1677c478bd9Sstevel@tonic-gate 	hour = HDE_DATE_HOUR(dp);
1687c478bd9Sstevel@tonic-gate 	minute = HDE_DATE_MIN(dp);
1697c478bd9Sstevel@tonic-gate 	sec = HDE_DATE_SEC(dp);
1707c478bd9Sstevel@tonic-gate 	gmtoff = HDE_DATE_GMTOFF(dp);
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 	tvp->tv_usec = 0;
1737c478bd9Sstevel@tonic-gate 	if (year < THE_EPOCH) {
1747c478bd9Sstevel@tonic-gate 		tvp->tv_sec = 0;
1757c478bd9Sstevel@tonic-gate 	} else {
1767c478bd9Sstevel@tonic-gate 		tvp->tv_sec = hs_date_to_gmtime(year, month, day, gmtoff);
1777c478bd9Sstevel@tonic-gate 		if (tvp->tv_sec != -1) {
1787c478bd9Sstevel@tonic-gate 			tvp->tv_sec += ((hour * 60) + minute) * 60 + sec;
1797c478bd9Sstevel@tonic-gate 		}
1807c478bd9Sstevel@tonic-gate 	}
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 	return;
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate }
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate /*
1877c478bd9Sstevel@tonic-gate  * hs_parse_longdate
1887c478bd9Sstevel@tonic-gate  *
1897c478bd9Sstevel@tonic-gate  * Parse the long 'user-oriented' date into a Unix timeval.
1907c478bd9Sstevel@tonic-gate  * This is the date format used in the Volume Descriptor.
1917c478bd9Sstevel@tonic-gate  *
1927c478bd9Sstevel@tonic-gate  * If the date is not representable, make something up.
1937c478bd9Sstevel@tonic-gate  */
1947c478bd9Sstevel@tonic-gate void
hs_parse_longdate(dp,tvp)1957c478bd9Sstevel@tonic-gate hs_parse_longdate(dp, tvp)
1967c478bd9Sstevel@tonic-gate 	uchar_t *dp;
1977c478bd9Sstevel@tonic-gate 	struct timeval *tvp;
1987c478bd9Sstevel@tonic-gate {
1997c478bd9Sstevel@tonic-gate 	int year, month, day, hour, minute, sec, gmtoff;
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 	year = HSV_DATE_YEAR(dp);
2027c478bd9Sstevel@tonic-gate 	month = HSV_DATE_MONTH(dp);
2037c478bd9Sstevel@tonic-gate 	day = HSV_DATE_DAY(dp);
2047c478bd9Sstevel@tonic-gate 	hour = HSV_DATE_HOUR(dp);
2057c478bd9Sstevel@tonic-gate 	minute = HSV_DATE_MIN(dp);
2067c478bd9Sstevel@tonic-gate 	sec = HSV_DATE_SEC(dp);
2077c478bd9Sstevel@tonic-gate 	gmtoff = HSV_DATE_GMTOFF(dp);
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 	tvp->tv_usec = 0;
2107c478bd9Sstevel@tonic-gate 	if (year < THE_EPOCH) {
2117c478bd9Sstevel@tonic-gate 		tvp->tv_sec = 0;
2127c478bd9Sstevel@tonic-gate 	} else {
2137c478bd9Sstevel@tonic-gate 		tvp->tv_sec = hs_date_to_gmtime(year, month, day, gmtoff);
2147c478bd9Sstevel@tonic-gate 		if (tvp->tv_sec != -1) {
2157c478bd9Sstevel@tonic-gate 			tvp->tv_sec += ((hour * 60) + minute) * 60 + sec;
2167c478bd9Sstevel@tonic-gate 			tvp->tv_usec = HSV_DATE_HSEC(dp) * 10000;
2177c478bd9Sstevel@tonic-gate 		}
2187c478bd9Sstevel@tonic-gate 	}
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate }
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate /* cumulative number of seconds per month,  non-leap and leap-year versions */
2237c478bd9Sstevel@tonic-gate static time_t cum_sec[] = {
2247c478bd9Sstevel@tonic-gate 	0x0, 0x28de80, 0x4dc880, 0x76a700, 0x9e3400, 0xc71280,
2257c478bd9Sstevel@tonic-gate 	0xee9f80, 0x1177e00, 0x1405c80, 0x167e980, 0x190c800, 0x1b85500
2267c478bd9Sstevel@tonic-gate };
2277c478bd9Sstevel@tonic-gate static time_t cum_sec_leap[] = {
2287c478bd9Sstevel@tonic-gate 	0x0, 0x28de80, 0x4f1a00, 0x77f880, 0x9f8580, 0xc86400,
2297c478bd9Sstevel@tonic-gate 	0xeff100, 0x118cf80, 0x141ae00, 0x1693b00, 0x1921980, 0x1b9a680
2307c478bd9Sstevel@tonic-gate };
2317c478bd9Sstevel@tonic-gate #define	SEC_PER_DAY	0x15180
2327c478bd9Sstevel@tonic-gate #define	SEC_PER_YEAR	0x1e13380
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate /*
2357c478bd9Sstevel@tonic-gate  * hs_date_to_gmtime
2367c478bd9Sstevel@tonic-gate  *
2377c478bd9Sstevel@tonic-gate  * Convert year(1970-2099)/month(1-12)/day(1-31) to seconds-since-1970/1/1.
2387c478bd9Sstevel@tonic-gate  *
2397c478bd9Sstevel@tonic-gate  * Returns -1 if the date is out of range.
2407c478bd9Sstevel@tonic-gate  */
2417c478bd9Sstevel@tonic-gate static time_t
hs_date_to_gmtime(year,mon,day,gmtoff)2427c478bd9Sstevel@tonic-gate hs_date_to_gmtime(year, mon, day, gmtoff)
2437c478bd9Sstevel@tonic-gate 	int year;
2447c478bd9Sstevel@tonic-gate 	int mon;
2457c478bd9Sstevel@tonic-gate 	int day;
2467c478bd9Sstevel@tonic-gate 	int gmtoff;
2477c478bd9Sstevel@tonic-gate {
2487c478bd9Sstevel@tonic-gate 	time_t sum;
2497c478bd9Sstevel@tonic-gate 	time_t *cp;
2507c478bd9Sstevel@tonic-gate 	int y;
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	if ((year < THE_EPOCH) || (year > END_OF_TIME) ||
2537c478bd9Sstevel@tonic-gate 	    (mon < 1) || (mon > 12) ||
2547c478bd9Sstevel@tonic-gate 	    (day < 1) || (day > 31))
2557c478bd9Sstevel@tonic-gate 		return (-1);
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	/*
2587c478bd9Sstevel@tonic-gate 	 * Figure seconds until this year and correct for leap years.
2597c478bd9Sstevel@tonic-gate 	 * Note: 2000 is a leap year but not 2100.
2607c478bd9Sstevel@tonic-gate 	 */
2617c478bd9Sstevel@tonic-gate 	y = year - THE_EPOCH;
2627c478bd9Sstevel@tonic-gate 	sum = y * SEC_PER_YEAR;
2637c478bd9Sstevel@tonic-gate 	sum += ((y + 1) / 4) * SEC_PER_DAY;
2647c478bd9Sstevel@tonic-gate 	/*
2657c478bd9Sstevel@tonic-gate 	 * Point to the correct table for this year and
2667c478bd9Sstevel@tonic-gate 	 * add in seconds until this month.
2677c478bd9Sstevel@tonic-gate 	 */
2687c478bd9Sstevel@tonic-gate 	cp = ((y + 2) % 4) ? cum_sec : cum_sec_leap;
2697c478bd9Sstevel@tonic-gate 	sum += cp[mon - 1];
2707c478bd9Sstevel@tonic-gate 	/*
2717c478bd9Sstevel@tonic-gate 	 * Add in seconds until 0:00 of this day.
2727c478bd9Sstevel@tonic-gate 	 * (days-per-month validation is not done here)
2737c478bd9Sstevel@tonic-gate 	 */
2747c478bd9Sstevel@tonic-gate 	sum += (day - 1) * SEC_PER_DAY;
2757c478bd9Sstevel@tonic-gate 	sum -= (gmtoff * 15 * 60);
2767c478bd9Sstevel@tonic-gate 	return (sum);
2777c478bd9Sstevel@tonic-gate }
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate /*
2807c478bd9Sstevel@tonic-gate  * Indicate whether the directory is valid.
2817c478bd9Sstevel@tonic-gate  */
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate int
hsfs_valid_dir(hd)2847c478bd9Sstevel@tonic-gate hsfs_valid_dir(hd)
2857c478bd9Sstevel@tonic-gate 	struct hs_direntry *hd;
2867c478bd9Sstevel@tonic-gate {
2877c478bd9Sstevel@tonic-gate 	/*
2887c478bd9Sstevel@tonic-gate 	 * check to see if this directory is not marked as a directory.
2897c478bd9Sstevel@tonic-gate 	 * check to see if data length is zero.
2907c478bd9Sstevel@tonic-gate 	 */
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	if (hd->ext_size == 0)
2937c478bd9Sstevel@tonic-gate 		return (0);
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 	if (hd->type != VDIR)
2967c478bd9Sstevel@tonic-gate 		return (0);
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	return (1);
2997c478bd9Sstevel@tonic-gate }
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate /*
3047c478bd9Sstevel@tonic-gate  * If we haven't complained about this error type yet, do.
3057c478bd9Sstevel@tonic-gate  */
3067c478bd9Sstevel@tonic-gate void
hs_log_bogus_disk_warning(fsp,errtype,data)3077c478bd9Sstevel@tonic-gate hs_log_bogus_disk_warning(fsp, errtype, data)
3087c478bd9Sstevel@tonic-gate 	struct hsfs	*fsp;
3097c478bd9Sstevel@tonic-gate 	int 		errtype;
3107c478bd9Sstevel@tonic-gate 	uint_t		data;
3117c478bd9Sstevel@tonic-gate {
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 	if (fsp->hsfs_err_flags & (1 << errtype))
3147c478bd9Sstevel@tonic-gate 		return;		/* already complained */
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	cmn_err(CE_NOTE, hsfs_error[errtype].hdr_text,
3177c478bd9Sstevel@tonic-gate 		fsp->hsfs_fsmnt);
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	switch (hsfs_error[errtype].n_printf_args) {
3207c478bd9Sstevel@tonic-gate 	case 0:
3217c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, hsfs_error[errtype].err_text);
3227c478bd9Sstevel@tonic-gate 		break;
3237c478bd9Sstevel@tonic-gate 	case 1:
3247c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, hsfs_error[errtype].err_text, data);
3257c478bd9Sstevel@tonic-gate 		break;
3267c478bd9Sstevel@tonic-gate 	default:
3277c478bd9Sstevel@tonic-gate 		/* don't currently handle more than 1 arg */
3287c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "unknown problem; internal error.\n");
3297c478bd9Sstevel@tonic-gate 	}
3307c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT,
3317c478bd9Sstevel@tonic-gate "Due to this error, the file system may not be correctly interpreted.\n");
3327c478bd9Sstevel@tonic-gate 	if (hsfs_error[errtype].multiple)
3337c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT,
3347c478bd9Sstevel@tonic-gate "Other such errors in this file system will be silently ignored.\n\n");
3357c478bd9Sstevel@tonic-gate 	else
3367c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "\n");
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 	fsp->hsfs_err_flags |= (1 << errtype);
3397c478bd9Sstevel@tonic-gate }
34084b82766Smg147109 
34184b82766Smg147109 /*
34284b82766Smg147109  * Callback from kstat framework. Grab a snapshot of the current hsfs
34384b82766Smg147109  * counters and populate the kstats.
34484b82766Smg147109  */
34584b82766Smg147109 static int
hsfs_kstats_update(kstat_t * ksp,int flag)34684b82766Smg147109 hsfs_kstats_update(kstat_t *ksp, int flag)
34784b82766Smg147109 {
34884b82766Smg147109 	struct hsfs *fsp;
34984b82766Smg147109 	kstat_named_t *knp;
35084b82766Smg147109 	uint64_t pages_lost;
35184b82766Smg147109 	uint64_t physical_read_bytes;
35284b82766Smg147109 	uint64_t cache_read_pages;
35384b82766Smg147109 	uint64_t readahead_bytes;
35484b82766Smg147109 	uint64_t coalesced_bytes;
35584b82766Smg147109 	uint64_t total_pages_requested;
35684b82766Smg147109 
35784b82766Smg147109 	if (flag != KSTAT_READ)
35884b82766Smg147109 		return (EACCES);
35984b82766Smg147109 
36084b82766Smg147109 	fsp = ksp->ks_private;
36184b82766Smg147109 	knp = ksp->ks_data;
36284b82766Smg147109 
36384b82766Smg147109 	mutex_enter(&(fsp->hqueue->strategy_lock));
36484b82766Smg147109 	mutex_enter(&(fsp->hqueue->hsfs_queue_lock));
36584b82766Smg147109 
36684b82766Smg147109 	cache_read_pages = fsp->cache_read_pages;
36784b82766Smg147109 	pages_lost = hsfs_lostpage;
36884b82766Smg147109 	physical_read_bytes = fsp->physical_read_bytes;
36984b82766Smg147109 	readahead_bytes =  fsp->readahead_bytes;
37084b82766Smg147109 	coalesced_bytes = fsp->coalesced_bytes;
37184b82766Smg147109 	total_pages_requested = fsp->total_pages_requested;
37284b82766Smg147109 
37384b82766Smg147109 	mutex_exit(&(fsp->hqueue->strategy_lock));
37484b82766Smg147109 	mutex_exit(&(fsp->hqueue->hsfs_queue_lock));
37584b82766Smg147109 
37684b82766Smg147109 	knp++;
37784b82766Smg147109 	(knp++)->value.ui64 = pages_lost;
37884b82766Smg147109 	(knp++)->value.ui64 = howmany(physical_read_bytes, PAGESIZE);
37984b82766Smg147109 	(knp++)->value.ui64 = cache_read_pages;
38084b82766Smg147109 	(knp++)->value.ui64 = howmany(readahead_bytes, PAGESIZE);
38184b82766Smg147109 	(knp++)->value.ui64 = howmany(coalesced_bytes, PAGESIZE);
38284b82766Smg147109 	(knp++)->value.ui64 = total_pages_requested;
38384b82766Smg147109 
38484b82766Smg147109 	return (0);
38584b82766Smg147109 }
38684b82766Smg147109 
38784b82766Smg147109 /*
38884b82766Smg147109  * Initialize hsfs kstats, which are all name value pairs with
38984b82766Smg147109  * values being various counters.
39084b82766Smg147109  */
39184b82766Smg147109 static kstat_t *
hsfs_setup_named_kstats(struct hsfs * fsp,int fsid,char * name,const hsfs_ksindex_t * ksip,int (* update)(kstat_t *,int))39284b82766Smg147109 hsfs_setup_named_kstats(struct hsfs *fsp, int fsid, char *name,
393*f9ec9c5aSmg147109     const hsfs_ksindex_t *ksip, int (*update)(kstat_t *, int))
39484b82766Smg147109 {
39584b82766Smg147109 	kstat_t *ksp;
39684b82766Smg147109 	kstat_named_t *knp;
39784b82766Smg147109 	char *np;
39884b82766Smg147109 	char *mntpt = fsp->hsfs_fsmnt;
399*f9ec9c5aSmg147109 	size_t size;
40084b82766Smg147109 
401*f9ec9c5aSmg147109 	size = (sizeof (hsfs_kstats)) / (sizeof (hsfs_ksindex_t));
40284b82766Smg147109 	ksp = kstat_create("hsfs_fs", fsid, name, "hsfs",
40384b82766Smg147109 	    KSTAT_TYPE_NAMED, size-1, KSTAT_FLAG_VIRTUAL);
40484b82766Smg147109 	if (ksp == NULL)
40584b82766Smg147109 		return (NULL);
40684b82766Smg147109 
40784b82766Smg147109 	ksp->ks_data = kmem_alloc(sizeof (kstat_named_t) * size, KM_SLEEP);
40884b82766Smg147109 	ksp->ks_private = fsp;
40984b82766Smg147109 	ksp->ks_update = update;
41084b82766Smg147109 	ksp->ks_data_size += strlen(mntpt) + 1;
41184b82766Smg147109 	knp = ksp->ks_data;
41284b82766Smg147109 	kstat_named_init(knp, ksip->name, KSTAT_DATA_STRING);
41384b82766Smg147109 	kstat_named_setstr(knp, mntpt);
41484b82766Smg147109 	knp++;
41584b82766Smg147109 	ksip++;
41684b82766Smg147109 
41784b82766Smg147109 	for (; (np = ksip->name) != NULL; ++knp, ++ksip) {
41884b82766Smg147109 		kstat_named_init(knp, np, KSTAT_DATA_UINT64);
41984b82766Smg147109 	}
42084b82766Smg147109 	kstat_install(ksp);
42184b82766Smg147109 
42284b82766Smg147109 	return (ksp);
42384b82766Smg147109 }
42484b82766Smg147109 
42584b82766Smg147109 void
hsfs_init_kstats(struct hsfs * fsp,int fsid)42684b82766Smg147109 hsfs_init_kstats(struct hsfs *fsp, int fsid)
42784b82766Smg147109 {
42884b82766Smg147109 	fsp->hsfs_kstats = hsfs_setup_named_kstats(fsp, fsid, "hsfs_read_stats",
429*f9ec9c5aSmg147109 	    hsfs_kstats, hsfs_kstats_update);
43084b82766Smg147109 }
43184b82766Smg147109 
43284b82766Smg147109 void
hsfs_fini_kstats(struct hsfs * fsp)43384b82766Smg147109 hsfs_fini_kstats(struct hsfs *fsp)
43484b82766Smg147109 {
43584b82766Smg147109 	void *data;
43684b82766Smg147109 
43784b82766Smg147109 	if (fsp->hsfs_kstats != NULL) {
43884b82766Smg147109 		data = fsp->hsfs_kstats->ks_data;
43984b82766Smg147109 		kstat_delete(fsp->hsfs_kstats);
440*f9ec9c5aSmg147109 		kmem_free(data, sizeof (kstat_named_t) *
441*f9ec9c5aSmg147109 		    (sizeof (hsfs_kstats)) / (sizeof (hsfs_ksindex_t)));
44284b82766Smg147109 	}
44384b82766Smg147109 	fsp->hsfs_kstats = NULL;
44484b82766Smg147109 }
445