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 60*5312Smg147109 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 131*5312Smg147109 /* 132*5312Smg147109 * Local datatype for defining tables of (Offset, Name) pairs for 133*5312Smg147109 * kstats. 134*5312Smg147109 */ 135*5312Smg147109 typedef struct { 136*5312Smg147109 offset_t index; 137*5312Smg147109 char *name; 138*5312Smg147109 } hsfs_ksindex_t; 1390Sstevel@tonic-gate 140*5312Smg147109 static const hsfs_ksindex_t hsfs_kstats[] = { 141*5312Smg147109 { 0, "mountpoint" }, 142*5312Smg147109 { 1, "pages_lost" }, 143*5312Smg147109 { 2, "physical_read_pages" }, 144*5312Smg147109 { 3, "cache_read_pages" }, 145*5312Smg147109 { 4, "readahead_pages" }, 146*5312Smg147109 { 5, "coalesced_pages" }, 147*5312Smg147109 { 6, "total_pages_requested" }, 148*5312Smg147109 {-1, NULL } 149*5312Smg147109 }; 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 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 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 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 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 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 } 342*5312Smg147109 343*5312Smg147109 /* 344*5312Smg147109 * Callback from kstat framework. Grab a snapshot of the current hsfs 345*5312Smg147109 * counters and populate the kstats. 346*5312Smg147109 */ 347*5312Smg147109 static int 348*5312Smg147109 hsfs_kstats_update(kstat_t *ksp, int flag) 349*5312Smg147109 { 350*5312Smg147109 struct hsfs *fsp; 351*5312Smg147109 kstat_named_t *knp; 352*5312Smg147109 uint64_t pages_lost; 353*5312Smg147109 uint64_t physical_read_bytes; 354*5312Smg147109 uint64_t cache_read_pages; 355*5312Smg147109 uint64_t readahead_bytes; 356*5312Smg147109 uint64_t coalesced_bytes; 357*5312Smg147109 uint64_t total_pages_requested; 358*5312Smg147109 359*5312Smg147109 if (flag != KSTAT_READ) 360*5312Smg147109 return (EACCES); 361*5312Smg147109 362*5312Smg147109 fsp = ksp->ks_private; 363*5312Smg147109 knp = ksp->ks_data; 364*5312Smg147109 365*5312Smg147109 mutex_enter(&(fsp->hqueue->strategy_lock)); 366*5312Smg147109 mutex_enter(&(fsp->hqueue->hsfs_queue_lock)); 367*5312Smg147109 368*5312Smg147109 cache_read_pages = fsp->cache_read_pages; 369*5312Smg147109 pages_lost = hsfs_lostpage; 370*5312Smg147109 physical_read_bytes = fsp->physical_read_bytes; 371*5312Smg147109 readahead_bytes = fsp->readahead_bytes; 372*5312Smg147109 coalesced_bytes = fsp->coalesced_bytes; 373*5312Smg147109 total_pages_requested = fsp->total_pages_requested; 374*5312Smg147109 375*5312Smg147109 mutex_exit(&(fsp->hqueue->strategy_lock)); 376*5312Smg147109 mutex_exit(&(fsp->hqueue->hsfs_queue_lock)); 377*5312Smg147109 378*5312Smg147109 knp++; 379*5312Smg147109 (knp++)->value.ui64 = pages_lost; 380*5312Smg147109 (knp++)->value.ui64 = howmany(physical_read_bytes, PAGESIZE); 381*5312Smg147109 (knp++)->value.ui64 = cache_read_pages; 382*5312Smg147109 (knp++)->value.ui64 = howmany(readahead_bytes, PAGESIZE); 383*5312Smg147109 (knp++)->value.ui64 = howmany(coalesced_bytes, PAGESIZE); 384*5312Smg147109 (knp++)->value.ui64 = total_pages_requested; 385*5312Smg147109 386*5312Smg147109 return (0); 387*5312Smg147109 } 388*5312Smg147109 389*5312Smg147109 /* 390*5312Smg147109 * Initialize hsfs kstats, which are all name value pairs with 391*5312Smg147109 * values being various counters. 392*5312Smg147109 */ 393*5312Smg147109 static kstat_t * 394*5312Smg147109 hsfs_setup_named_kstats(struct hsfs *fsp, int fsid, char *name, 395*5312Smg147109 const hsfs_ksindex_t *ksip, size_t size, int (*update)(kstat_t *, int)) 396*5312Smg147109 { 397*5312Smg147109 kstat_t *ksp; 398*5312Smg147109 kstat_named_t *knp; 399*5312Smg147109 char *np; 400*5312Smg147109 char *mntpt = fsp->hsfs_fsmnt; 401*5312Smg147109 402*5312Smg147109 size /= sizeof (hsfs_ksindex_t); 403*5312Smg147109 ksp = kstat_create("hsfs_fs", fsid, name, "hsfs", 404*5312Smg147109 KSTAT_TYPE_NAMED, size-1, KSTAT_FLAG_VIRTUAL); 405*5312Smg147109 if (ksp == NULL) 406*5312Smg147109 return (NULL); 407*5312Smg147109 408*5312Smg147109 ksp->ks_data = kmem_alloc(sizeof (kstat_named_t) * size, KM_SLEEP); 409*5312Smg147109 ksp->ks_private = fsp; 410*5312Smg147109 ksp->ks_update = update; 411*5312Smg147109 ksp->ks_data_size += strlen(mntpt) + 1; 412*5312Smg147109 knp = ksp->ks_data; 413*5312Smg147109 kstat_named_init(knp, ksip->name, KSTAT_DATA_STRING); 414*5312Smg147109 kstat_named_setstr(knp, mntpt); 415*5312Smg147109 knp++; 416*5312Smg147109 ksip++; 417*5312Smg147109 418*5312Smg147109 for (; (np = ksip->name) != NULL; ++knp, ++ksip) { 419*5312Smg147109 kstat_named_init(knp, np, KSTAT_DATA_UINT64); 420*5312Smg147109 } 421*5312Smg147109 kstat_install(ksp); 422*5312Smg147109 423*5312Smg147109 return (ksp); 424*5312Smg147109 } 425*5312Smg147109 426*5312Smg147109 void 427*5312Smg147109 hsfs_init_kstats(struct hsfs *fsp, int fsid) 428*5312Smg147109 { 429*5312Smg147109 fsp->hsfs_kstats = hsfs_setup_named_kstats(fsp, fsid, "hsfs_read_stats", 430*5312Smg147109 hsfs_kstats, sizeof (hsfs_kstats), hsfs_kstats_update); 431*5312Smg147109 } 432*5312Smg147109 433*5312Smg147109 void 434*5312Smg147109 hsfs_fini_kstats(struct hsfs *fsp) 435*5312Smg147109 { 436*5312Smg147109 void *data; 437*5312Smg147109 438*5312Smg147109 if (fsp->hsfs_kstats != NULL) { 439*5312Smg147109 data = fsp->hsfs_kstats->ks_data; 440*5312Smg147109 kstat_delete(fsp->hsfs_kstats); 441*5312Smg147109 kmem_free(data, (sizeof (hsfs_kstats)) / \ 442*5312Smg147109 (sizeof (hsfs_ksindex_t))); 443*5312Smg147109 } 444*5312Smg147109 fsp->hsfs_kstats = NULL; 445*5312Smg147109 } 446