1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Miscellaneous support subroutines for High Sierra filesystem
  23  *
  24  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  25  * Use is subject to license terms.
  26  */
  27 
  28 #include <sys/types.h>
  29 #include <sys/param.h>
  30 #include <sys/time.h>
  31 #include <sys/cmn_err.h>
  32 #include <sys/systm.h>
  33 #include <sys/sysmacros.h>
  34 #include <sys/buf.h>
  35 #include <sys/conf.h>
  36 #include <sys/user.h>
  37 #include <sys/vfs.h>
  38 #include <sys/vnode.h>
  39 #include <sys/proc.h>
  40 #include <sys/debug.h>
  41 #include <sys/kmem.h>
  42 #include <sys/uio.h>
  43 #include <vm/hat.h>
  44 #include <vm/as.h>
  45 #include <vm/seg.h>
  46 #include <vm/page.h>
  47 #include <vm/pvn.h>
  48 #include <vm/seg_map.h>
  49 #include <sys/swap.h>
  50 #include <vm/seg_kmem.h>
  51 
  52 #include <sys/fs/hsfs_spec.h>
  53 #include <sys/fs/hsfs_node.h>
  54 #include <sys/fs/hsfs_impl.h>
  55 
  56 #define THE_EPOCH       1970
  57 #define END_OF_TIME     2099
  58 extern int hsfs_lostpage;
  59 
  60 #ifdef __STDC__
  61 static time_t hs_date_to_gmtime(int year, int mon, int day, int gmtoff);
  62 #else
  63 static time_t hs_date_to_gmtime();
  64 #endif
  65 
  66 /*
  67  * Table used in logging non-fatal errors which should be recorded
  68  * once per mount.  Indexed by HSFS_ERR values (defined in hsfs_node.h).
  69  */
  70 struct hsfs_error {
  71         char    *hdr_text;      /* msg prefix: general error type */
  72                                 /* must contain %s for mnt pt */
  73         char    *err_text;      /* specific error message */
  74         uchar_t multiple;       /* > 1 such error per fs possible? */
  75         uchar_t n_printf_args;  /* if err_text printf-like, # addtl args */
  76 } hsfs_error[] = {
  77         /* HSFS_ERR_TRAILING_JUNK */
  78         {   "hsfs: Warning: the file system mounted on %s "
  79                 "does not conform to the ISO-9660 specification:",
  80             "trailing blanks or null characters in file or directory name.\n",
  81             1, 0 },
  82         /* HSFS_ERR_LOWER_CASE_NM */
  83         {   "hsfs: Warning: the file system mounted on %s "
  84                 "does not conform to the ISO-9660 specification:",
  85             "lower case characters in file or directory name.\n",
  86             1, 0 },
  87         /* HSFS_ERR_BAD_ROOT_DIR */
  88         {   "hsfs: Warning: the file system mounted on %s "
  89                 "does not conform to the ISO-9660 specification:",
  90             "invalid root directory.\n",
  91             0, 0 },
  92         /* HSFS_ERR_UNSUP_TYPE */
  93         {   "hsfs: Warning: the file system mounted on %s "
  94                 "contains a file or directory with an unsupported type:",
  95             " 0x%x.\n",
  96             1, 1 },
  97         /* HSFS_ERR_BAD_FILE_LEN */
  98         {   "hsfs: Warning: file system mounted on %s "
  99                 "does not conform to the ISO-9660 specification:",
 100             "file name length greater than max allowed\n",
 101             1, 0 },
 102         /* HSFS_ERR_BAD_JOLIET_FILE_LEN */
 103         {   "hsfs: Warning: file system mounted on %s "
 104                 "does not conform to the Joliet specification:",
 105             "file name length greater than max allowed\n",
 106             1, 0 },
 107         /* HSFS_ERR_TRUNC_JOLIET_FILE_LEN */
 108         {   "hsfs: Warning: file system mounted on %s "
 109                 "does not conform to the Joliet specification:",
 110             "file name length greater than MAXNAMELEN (truncated)\n",
 111             1, 0 },
 112         /* HSFS_ERR_BAD_DIR_ENTRY */
 113         {   "hsfs: Warning: file system mounted on %s "
 114                 "has inconsistent data:",
 115             "invalid directory or file name length (ignored)\n",
 116             1, 0 },
 117         /* HSFS_ERR_NEG_SUA_LEN */
 118         {   "hsfs: Warning: file system mounted on %s "
 119                 "has inconsistent Rock Ridge data:",
 120             "negative SUA len\n",
 121             1, 0 },
 122         /* HSFS_ERR_BAD_SUA_LEN */
 123         {   "hsfs: Warning: file system mounted on %s "
 124                 "has inconsistent Rock Ridge data:",
 125             "SUA len too big\n",
 126             1, 0 }
 127 };
 128 
 129 /*
 130  * Local datatype for defining tables of (Offset, Name) pairs for
 131  * kstats.
 132  */
 133 typedef struct {
 134         offset_t        index;
 135         char            *name;
 136 } hsfs_ksindex_t;
 137 
 138 static const hsfs_ksindex_t hsfs_kstats[] = {
 139         { 0,            "mountpoint"            },
 140         { 1,            "pages_lost"            },
 141         { 2,            "physical_read_pages"   },
 142         { 3,            "cache_read_pages"      },
 143         { 4,            "readahead_pages"       },
 144         { 5,            "coalesced_pages"       },
 145         { 6,            "total_pages_requested" },
 146         {-1,            NULL                    }
 147 };
 148 
 149 /*
 150  * hs_parse_dirdate
 151  *
 152  * Parse the short 'directory-format' date into a Unix timeval.
 153  * This is the date format used in Directory Entries.
 154  *
 155  * If the date is not representable, make something up.
 156  */
 157 void
 158 hs_parse_dirdate(dp, tvp)
 159         uchar_t *dp;
 160         struct timeval *tvp;
 161 {
 162         int year, month, day, hour, minute, sec, gmtoff;
 163 
 164         year = HDE_DATE_YEAR(dp);
 165         month = HDE_DATE_MONTH(dp);
 166         day = HDE_DATE_DAY(dp);
 167         hour = HDE_DATE_HOUR(dp);
 168         minute = HDE_DATE_MIN(dp);
 169         sec = HDE_DATE_SEC(dp);
 170         gmtoff = HDE_DATE_GMTOFF(dp);
 171 
 172         tvp->tv_usec = 0;
 173         if (year < THE_EPOCH) {
 174                 tvp->tv_sec = 0;
 175         } else {
 176                 tvp->tv_sec = hs_date_to_gmtime(year, month, day, gmtoff);
 177                 if (tvp->tv_sec != -1) {
 178                         tvp->tv_sec += ((hour * 60) + minute) * 60 + sec;
 179                 }
 180         }
 181 
 182         return;
 183 
 184 }
 185 
 186 /*
 187  * hs_parse_longdate
 188  *
 189  * Parse the long 'user-oriented' date into a Unix timeval.
 190  * This is the date format used in the Volume Descriptor.
 191  *
 192  * If the date is not representable, make something up.
 193  */
 194 void
 195 hs_parse_longdate(dp, tvp)
 196         uchar_t *dp;
 197         struct timeval *tvp;
 198 {
 199         int year, month, day, hour, minute, sec, gmtoff;
 200 
 201         year = HSV_DATE_YEAR(dp);
 202         month = HSV_DATE_MONTH(dp);
 203         day = HSV_DATE_DAY(dp);
 204         hour = HSV_DATE_HOUR(dp);
 205         minute = HSV_DATE_MIN(dp);
 206         sec = HSV_DATE_SEC(dp);
 207         gmtoff = HSV_DATE_GMTOFF(dp);
 208 
 209         tvp->tv_usec = 0;
 210         if (year < THE_EPOCH) {
 211                 tvp->tv_sec = 0;
 212         } else {
 213                 tvp->tv_sec = hs_date_to_gmtime(year, month, day, gmtoff);
 214                 if (tvp->tv_sec != -1) {
 215                         tvp->tv_sec += ((hour * 60) + minute) * 60 + sec;
 216                         tvp->tv_usec = HSV_DATE_HSEC(dp) * 10000;
 217                 }
 218         }
 219 
 220 }
 221 
 222 /* cumulative number of seconds per month,  non-leap and leap-year versions */
 223 static time_t cum_sec[] = {
 224         0x0, 0x28de80, 0x4dc880, 0x76a700, 0x9e3400, 0xc71280,
 225         0xee9f80, 0x1177e00, 0x1405c80, 0x167e980, 0x190c800, 0x1b85500
 226 };
 227 static time_t cum_sec_leap[] = {
 228         0x0, 0x28de80, 0x4f1a00, 0x77f880, 0x9f8580, 0xc86400,
 229         0xeff100, 0x118cf80, 0x141ae00, 0x1693b00, 0x1921980, 0x1b9a680
 230 };
 231 #define SEC_PER_DAY     0x15180
 232 #define SEC_PER_YEAR    0x1e13380
 233 
 234 /*
 235  * hs_date_to_gmtime
 236  *
 237  * Convert year(1970-2099)/month(1-12)/day(1-31) to seconds-since-1970/1/1.
 238  *
 239  * Returns -1 if the date is out of range.
 240  */
 241 static time_t
 242 hs_date_to_gmtime(year, mon, day, gmtoff)
 243         int year;
 244         int mon;
 245         int day;
 246         int gmtoff;
 247 {
 248         time_t sum;
 249         time_t *cp;
 250         int y;
 251 
 252         if ((year < THE_EPOCH) || (year > END_OF_TIME) ||
 253             (mon < 1) || (mon > 12) ||
 254             (day < 1) || (day > 31))
 255                 return (-1);
 256 
 257         /*
 258          * Figure seconds until this year and correct for leap years.
 259          * Note: 2000 is a leap year but not 2100.
 260          */
 261         y = year - THE_EPOCH;
 262         sum = y * SEC_PER_YEAR;
 263         sum += ((y + 1) / 4) * SEC_PER_DAY;
 264         /*
 265          * Point to the correct table for this year and
 266          * add in seconds until this month.
 267          */
 268         cp = ((y + 2) % 4) ? cum_sec : cum_sec_leap;
 269         sum += cp[mon - 1];
 270         /*
 271          * Add in seconds until 0:00 of this day.
 272          * (days-per-month validation is not done here)
 273          */
 274         sum += (day - 1) * SEC_PER_DAY;
 275         sum -= (gmtoff * 15 * 60);
 276         return (sum);
 277 }
 278 
 279 /*
 280  * Indicate whether the directory is valid.
 281  */
 282 
 283 int
 284 hsfs_valid_dir(hd)
 285         struct hs_direntry *hd;
 286 {
 287         /*
 288          * check to see if this directory is not marked as a directory.
 289          * check to see if data length is zero.
 290          */
 291 
 292         if (hd->ext_size == 0)
 293                 return (0);
 294 
 295         if (hd->type != VDIR)
 296                 return (0);
 297 
 298         return (1);
 299 }
 300 
 301 
 302 
 303 /*
 304  * If we haven't complained about this error type yet, do.
 305  */
 306 void
 307 hs_log_bogus_disk_warning(fsp, errtype, data)
 308         struct hsfs     *fsp;
 309         int             errtype;
 310         uint_t          data;
 311 {
 312 
 313         if (fsp->hsfs_err_flags & (1 << errtype))
 314                 return;         /* already complained */
 315 
 316         cmn_err(CE_NOTE, hsfs_error[errtype].hdr_text,
 317                 fsp->hsfs_fsmnt);
 318 
 319         switch (hsfs_error[errtype].n_printf_args) {
 320         case 0:
 321                 cmn_err(CE_CONT, hsfs_error[errtype].err_text);
 322                 break;
 323         case 1:
 324                 cmn_err(CE_CONT, hsfs_error[errtype].err_text, data);
 325                 break;
 326         default:
 327                 /* don't currently handle more than 1 arg */
 328                 cmn_err(CE_CONT, "unknown problem; internal error.\n");
 329         }
 330         cmn_err(CE_CONT,
 331 "Due to this error, the file system may not be correctly interpreted.\n");
 332         if (hsfs_error[errtype].multiple)
 333                 cmn_err(CE_CONT,
 334 "Other such errors in this file system will be silently ignored.\n\n");
 335         else
 336                 cmn_err(CE_CONT, "\n");
 337 
 338         fsp->hsfs_err_flags |= (1 << errtype);
 339 }
 340 
 341 /*
 342  * Callback from kstat framework. Grab a snapshot of the current hsfs
 343  * counters and populate the kstats.
 344  */
 345 static int
 346 hsfs_kstats_update(kstat_t *ksp, int flag)
 347 {
 348         struct hsfs *fsp;
 349         kstat_named_t *knp;
 350         uint64_t pages_lost;
 351         uint64_t physical_read_bytes;
 352         uint64_t cache_read_pages;
 353         uint64_t readahead_bytes;
 354         uint64_t coalesced_bytes;
 355         uint64_t total_pages_requested;
 356 
 357         if (flag != KSTAT_READ)
 358                 return (EACCES);
 359 
 360         fsp = ksp->ks_private;
 361         knp = ksp->ks_data;
 362 
 363         mutex_enter(&(fsp->hqueue->strategy_lock));
 364         mutex_enter(&(fsp->hqueue->hsfs_queue_lock));
 365 
 366         cache_read_pages = fsp->cache_read_pages;
 367         pages_lost = hsfs_lostpage;
 368         physical_read_bytes = fsp->physical_read_bytes;
 369         readahead_bytes =  fsp->readahead_bytes;
 370         coalesced_bytes = fsp->coalesced_bytes;
 371         total_pages_requested = fsp->total_pages_requested;
 372 
 373         mutex_exit(&(fsp->hqueue->strategy_lock));
 374         mutex_exit(&(fsp->hqueue->hsfs_queue_lock));
 375 
 376         knp++;
 377         (knp++)->value.ui64 = pages_lost;
 378         (knp++)->value.ui64 = howmany(physical_read_bytes, PAGESIZE);
 379         (knp++)->value.ui64 = cache_read_pages;
 380         (knp++)->value.ui64 = howmany(readahead_bytes, PAGESIZE);
 381         (knp++)->value.ui64 = howmany(coalesced_bytes, PAGESIZE);
 382         (knp++)->value.ui64 = total_pages_requested;
 383 
 384         return (0);
 385 }
 386 
 387 /*
 388  * Initialize hsfs kstats, which are all name value pairs with
 389  * values being various counters.
 390  */
 391 static kstat_t *
 392 hsfs_setup_named_kstats(struct hsfs *fsp, int fsid, char *name,
 393     const hsfs_ksindex_t *ksip, int (*update)(kstat_t *, int))
 394 {
 395         kstat_t *ksp;
 396         kstat_named_t *knp;
 397         char *np;
 398         char *mntpt = fsp->hsfs_fsmnt;
 399         size_t size;
 400 
 401         size = (sizeof (hsfs_kstats)) / (sizeof (hsfs_ksindex_t));
 402         ksp = kstat_create("hsfs_fs", fsid, name, "hsfs",
 403             KSTAT_TYPE_NAMED, size-1, KSTAT_FLAG_VIRTUAL);
 404         if (ksp == NULL)
 405                 return (NULL);
 406 
 407         ksp->ks_data = kmem_alloc(sizeof (kstat_named_t) * size, KM_SLEEP);
 408         ksp->ks_private = fsp;
 409         ksp->ks_update = update;
 410         ksp->ks_data_size += strlen(mntpt) + 1;
 411         knp = ksp->ks_data;
 412         kstat_named_init(knp, ksip->name, KSTAT_DATA_STRING);
 413         kstat_named_setstr(knp, mntpt);
 414         knp++;
 415         ksip++;
 416 
 417         for (; (np = ksip->name) != NULL; ++knp, ++ksip) {
 418                 kstat_named_init(knp, np, KSTAT_DATA_UINT64);
 419         }
 420         kstat_install(ksp);
 421 
 422         return (ksp);
 423 }
 424 
 425 void
 426 hsfs_init_kstats(struct hsfs *fsp, int fsid)
 427 {
 428         fsp->hsfs_kstats = hsfs_setup_named_kstats(fsp, fsid, "hsfs_read_stats",
 429             hsfs_kstats, hsfs_kstats_update);
 430 }
 431 
 432 void
 433 hsfs_fini_kstats(struct hsfs *fsp)
 434 {
 435         void *data;
 436 
 437         if (fsp->hsfs_kstats != NULL) {
 438                 data = fsp->hsfs_kstats->ks_data;
 439                 kstat_delete(fsp->hsfs_kstats);
 440                 kmem_free(data, sizeof (kstat_named_t) *
 441                     (sizeof (hsfs_kstats)) / (sizeof (hsfs_ksindex_t)));
 442         }
 443         fsp->hsfs_kstats = NULL;
 444 }