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
hs_parse_dirdate(dp,tvp)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
hs_parse_longdate(dp,tvp)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
hs_date_to_gmtime(year,mon,day,gmtoff)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
hsfs_valid_dir(hd)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
hs_log_bogus_disk_warning(fsp,errtype,data)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
hsfs_kstats_update(kstat_t * ksp,int flag)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 *
hsfs_setup_named_kstats(struct hsfs * fsp,int fsid,char * name,const hsfs_ksindex_t * ksip,int (* update)(kstat_t *,int))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
hsfs_init_kstats(struct hsfs * fsp,int fsid)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
hsfs_fini_kstats(struct hsfs * fsp)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 }
447