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