xref: /illumos-gate/usr/src/uts/common/fs/hsfs/hsfs_vnops.c (revision 76716eaced8d7659d4594350eb3f343c31fe2806)
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  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * Vnode operations for the High Sierra filesystem
30  */
31 
32 #include <sys/types.h>
33 #include <sys/t_lock.h>
34 #include <sys/param.h>
35 #include <sys/time.h>
36 #include <sys/systm.h>
37 #include <sys/sysmacros.h>
38 #include <sys/resource.h>
39 #include <sys/signal.h>
40 #include <sys/cred.h>
41 #include <sys/user.h>
42 #include <sys/buf.h>
43 #include <sys/vfs.h>
44 #include <sys/stat.h>
45 #include <sys/vnode.h>
46 #include <sys/mode.h>
47 #include <sys/proc.h>
48 #include <sys/disp.h>
49 #include <sys/file.h>
50 #include <sys/fcntl.h>
51 #include <sys/flock.h>
52 #include <sys/kmem.h>
53 #include <sys/uio.h>
54 #include <sys/conf.h>
55 #include <sys/errno.h>
56 #include <sys/mman.h>
57 #include <sys/pathname.h>
58 #include <sys/debug.h>
59 #include <sys/vmsystm.h>
60 #include <sys/cmn_err.h>
61 #include <sys/fbuf.h>
62 #include <sys/dirent.h>
63 #include <sys/errno.h>
64 
65 #include <vm/hat.h>
66 #include <vm/page.h>
67 #include <vm/pvn.h>
68 #include <vm/as.h>
69 #include <vm/seg.h>
70 #include <vm/seg_map.h>
71 #include <vm/seg_kmem.h>
72 #include <vm/seg_vn.h>
73 #include <vm/rm.h>
74 #include <vm/page.h>
75 #include <sys/swap.h>
76 
77 #include <sys/fs/hsfs_spec.h>
78 #include <sys/fs/hsfs_node.h>
79 #include <sys/fs/hsfs_impl.h>
80 #include <sys/fs/hsfs_susp.h>
81 #include <sys/fs/hsfs_rrip.h>
82 
83 #include <fs/fs_subr.h>
84 
85 /* ARGSUSED */
86 static int
87 hsfs_fsync(vnode_t *cp, int syncflag, cred_t *cred)
88 {
89 	return (0);
90 }
91 
92 
93 /*ARGSUSED*/
94 static int
95 hsfs_read(struct vnode *vp, struct uio *uiop, int ioflag, struct cred *cred,
96 	struct caller_context *ct)
97 {
98 	caddr_t base;
99 	offset_t diff;
100 	int error;
101 	struct hsnode *hp;
102 	uint_t filesize;
103 
104 	hp = VTOH(vp);
105 	/*
106 	 * if vp is of type VDIR, make sure dirent
107 	 * is filled up with all info (because of ptbl)
108 	 */
109 	if (vp->v_type == VDIR) {
110 		if (hp->hs_dirent.ext_size == 0)
111 			hs_filldirent(vp, &hp->hs_dirent);
112 	}
113 	filesize = hp->hs_dirent.ext_size;
114 
115 	/* Sanity checks. */
116 	if (uiop->uio_resid == 0 ||		/* No data wanted. */
117 	    uiop->uio_loffset > HS_MAXFILEOFF ||	/* Offset too big. */
118 	    uiop->uio_loffset >= filesize)	/* Past EOF. */
119 		return (0);
120 
121 	do {
122 		/*
123 		 * We want to ask for only the "right" amount of data.
124 		 * In this case that means:-
125 		 *
126 		 * We can't get data from beyond our EOF. If asked,
127 		 * we will give a short read.
128 		 *
129 		 * segmap_getmapflt returns buffers of MAXBSIZE bytes.
130 		 * These buffers are always MAXBSIZE aligned.
131 		 * If our starting offset is not MAXBSIZE aligned,
132 		 * we can only ask for less than MAXBSIZE bytes.
133 		 *
134 		 * If our requested offset and length are such that
135 		 * they belong in different MAXBSIZE aligned slots
136 		 * then we'll be making more than one call on
137 		 * segmap_getmapflt.
138 		 *
139 		 * This diagram shows the variables we use and their
140 		 * relationships.
141 		 *
142 		 * |<-----MAXBSIZE----->|
143 		 * +--------------------------...+
144 		 * |.....mapon->|<--n-->|....*...|EOF
145 		 * +--------------------------...+
146 		 * uio_loffset->|
147 		 * uio_resid....|<---------->|
148 		 * diff.........|<-------------->|
149 		 *
150 		 * So, in this case our offset is not aligned
151 		 * and our request takes us outside of the
152 		 * MAXBSIZE window. We will break this up into
153 		 * two segmap_getmapflt calls.
154 		 */
155 		size_t nbytes;
156 		offset_t mapon;
157 		size_t n;
158 		uint_t flags;
159 
160 		mapon = uiop->uio_loffset & MAXBOFFSET;
161 		diff = filesize - uiop->uio_loffset;
162 		nbytes = (size_t)MIN(MAXBSIZE - mapon, uiop->uio_resid);
163 		n = MIN(diff, nbytes);
164 		if (n <= 0) {
165 			/* EOF or request satisfied. */
166 			return (0);
167 		}
168 
169 		base = segmap_getmapflt(segkmap, vp,
170 		    (u_offset_t)uiop->uio_loffset, n, 1, S_READ);
171 
172 		error = uiomove(base + mapon, n, UIO_READ, uiop);
173 
174 		if (error == 0) {
175 			/*
176 			 * if read a whole block, or read to eof,
177 			 *  won't need this buffer again soon.
178 			 */
179 			if (n + mapon == MAXBSIZE ||
180 			    uiop->uio_loffset == filesize)
181 				flags = SM_DONTNEED;
182 			else
183 				flags = 0;
184 			error = segmap_release(segkmap, base, flags);
185 		} else
186 			(void) segmap_release(segkmap, base, 0);
187 	} while (error == 0 && uiop->uio_resid > 0);
188 
189 	return (error);
190 }
191 
192 /*ARGSUSED2*/
193 static int
194 hsfs_getattr(
195 	struct vnode *vp,
196 	struct vattr *vap,
197 	int flags,
198 	struct cred *cred)
199 {
200 	struct hsnode *hp;
201 	struct vfs *vfsp;
202 	struct hsfs *fsp;
203 
204 	hp = VTOH(vp);
205 	fsp = VFS_TO_HSFS(vp->v_vfsp);
206 	vfsp = vp->v_vfsp;
207 
208 	if ((hp->hs_dirent.ext_size == 0) && (vp->v_type == VDIR)) {
209 		hs_filldirent(vp, &hp->hs_dirent);
210 	}
211 	vap->va_type = IFTOVT(hp->hs_dirent.mode);
212 	vap->va_mode = hp->hs_dirent.mode;
213 	vap->va_uid = hp->hs_dirent.uid;
214 	vap->va_gid = hp->hs_dirent.gid;
215 
216 	vap->va_fsid = vfsp->vfs_dev;
217 	vap->va_nodeid = (ino64_t)hp->hs_nodeid;
218 	vap->va_nlink = hp->hs_dirent.nlink;
219 	vap->va_size =	(offset_t)hp->hs_dirent.ext_size;
220 
221 	vap->va_atime.tv_sec = hp->hs_dirent.adate.tv_sec;
222 	vap->va_atime.tv_nsec = hp->hs_dirent.adate.tv_usec*1000;
223 	vap->va_mtime.tv_sec = hp->hs_dirent.mdate.tv_sec;
224 	vap->va_mtime.tv_nsec = hp->hs_dirent.mdate.tv_usec*1000;
225 	vap->va_ctime.tv_sec = hp->hs_dirent.cdate.tv_sec;
226 	vap->va_ctime.tv_nsec = hp->hs_dirent.cdate.tv_usec*1000;
227 	if (vp->v_type == VCHR || vp->v_type == VBLK)
228 		vap->va_rdev = hp->hs_dirent.r_dev;
229 	else
230 		vap->va_rdev = 0;
231 	vap->va_blksize = vfsp->vfs_bsize;
232 	/* no. of blocks = no. of data blocks + no. of xar blocks */
233 	vap->va_nblocks = (fsblkcnt64_t)howmany(vap->va_size + (u_longlong_t)
234 	    (hp->hs_dirent.xar_len << fsp->hsfs_vol.lbn_shift), DEV_BSIZE);
235 	vap->va_seq = hp->hs_seq;
236 	return (0);
237 }
238 
239 /*ARGSUSED*/
240 static int
241 hsfs_readlink(struct vnode *vp, struct uio *uiop, struct cred *cred)
242 {
243 	struct hsnode *hp;
244 
245 	if (vp->v_type != VLNK)
246 		return (EINVAL);
247 
248 	hp = VTOH(vp);
249 
250 	if (hp->hs_dirent.sym_link == (char *)NULL)
251 		return (ENOENT);
252 
253 	return (uiomove(hp->hs_dirent.sym_link,
254 	    (size_t)MIN(hp->hs_dirent.ext_size,
255 	    uiop->uio_resid), UIO_READ, uiop));
256 }
257 
258 /*ARGSUSED*/
259 static void
260 hsfs_inactive(struct vnode *vp, struct cred *cred)
261 {
262 	struct hsnode *hp;
263 	struct hsfs *fsp;
264 
265 	int nopage;
266 
267 	hp = VTOH(vp);
268 	fsp = VFS_TO_HSFS(vp->v_vfsp);
269 	/*
270 	 * Note: acquiring and holding v_lock for quite a while
271 	 * here serializes on the vnode; this is unfortunate, but
272 	 * likely not to overly impact performance, as the underlying
273 	 * device (CDROM drive) is quite slow.
274 	 */
275 	rw_enter(&fsp->hsfs_hash_lock, RW_WRITER);
276 	mutex_enter(&hp->hs_contents_lock);
277 	mutex_enter(&vp->v_lock);
278 
279 	if (vp->v_count < 1) {
280 		panic("hsfs_inactive: v_count < 1");
281 		/*NOTREACHED*/
282 	}
283 
284 	if (vp->v_count > 1 || (hp->hs_flags & HREF) == 0) {
285 		vp->v_count--;	/* release hold from vn_rele */
286 		mutex_exit(&vp->v_lock);
287 		mutex_exit(&hp->hs_contents_lock);
288 		rw_exit(&fsp->hsfs_hash_lock);
289 		return;
290 	}
291 	vp->v_count--;	/* release hold from vn_rele */
292 	if (vp->v_count == 0) {
293 		/*
294 		 * Free the hsnode.
295 		 * If there are no pages associated with the
296 		 * hsnode, give it back to the kmem_cache,
297 		 * else put at the end of this file system's
298 		 * internal free list.
299 		 */
300 		nopage = !vn_has_cached_data(vp);
301 		hp->hs_flags = 0;
302 		/*
303 		 * exit these locks now, since hs_freenode may
304 		 * kmem_free the hsnode and embedded vnode
305 		 */
306 		mutex_exit(&vp->v_lock);
307 		mutex_exit(&hp->hs_contents_lock);
308 		hs_freenode(vp, fsp, nopage);
309 	} else {
310 		mutex_exit(&vp->v_lock);
311 		mutex_exit(&hp->hs_contents_lock);
312 	}
313 	rw_exit(&fsp->hsfs_hash_lock);
314 }
315 
316 
317 /*ARGSUSED*/
318 static int
319 hsfs_lookup(
320 	struct vnode *dvp,
321 	char *nm,
322 	struct vnode **vpp,
323 	struct pathname *pnp,
324 	int flags,
325 	struct vnode *rdir,
326 	struct cred *cred)
327 {
328 	int error;
329 	int namelen = (int)strlen(nm);
330 
331 	if (*nm == '\0') {
332 		VN_HOLD(dvp);
333 		*vpp = dvp;
334 		return (0);
335 	}
336 
337 	/*
338 	 * If we're looking for ourself, life is simple.
339 	 */
340 	if (namelen == 1 && *nm == '.') {
341 		if (error = hs_access(dvp, (mode_t)VEXEC, cred))
342 			return (error);
343 		VN_HOLD(dvp);
344 		*vpp = dvp;
345 		return (0);
346 	}
347 
348 	return (hs_dirlook(dvp, nm, namelen, vpp, cred));
349 }
350 
351 
352 /*ARGSUSED*/
353 static int
354 hsfs_readdir(
355 	struct vnode	*vp,
356 	struct uio	*uiop,
357 	struct cred	*cred,
358 	int		*eofp)
359 {
360 	struct hsnode	*dhp;
361 	struct hsfs	*fsp;
362 	struct hs_direntry hd;
363 	struct dirent64	*nd;
364 	int		error;
365 	uint_t		offset;		/* real offset in directory */
366 	uint_t		dirsiz;		/* real size of directory */
367 	uchar_t		*blkp;
368 	int		hdlen;		/* length of hs directory entry */
369 	long		ndlen;		/* length of dirent entry */
370 	int		bytes_wanted;
371 	size_t		bufsize;	/* size of dirent buffer */
372 	char		*outbuf;	/* ptr to dirent buffer */
373 	char		*dname;
374 	int		dnamelen;
375 	size_t		dname_size;
376 	struct fbuf	*fbp;
377 	uint_t		last_offset;	/* last index into current dir block */
378 	ulong_t		dir_lbn;	/* lbn of directory */
379 	ino64_t		dirino;	/* temporary storage before storing in dirent */
380 	off_t		diroff;
381 
382 	dhp = VTOH(vp);
383 	fsp = VFS_TO_HSFS(vp->v_vfsp);
384 	if (dhp->hs_dirent.ext_size == 0)
385 		hs_filldirent(vp, &dhp->hs_dirent);
386 	dirsiz = dhp->hs_dirent.ext_size;
387 	dir_lbn = dhp->hs_dirent.ext_lbn;
388 	if (uiop->uio_loffset >= dirsiz) {	/* at or beyond EOF */
389 		if (eofp)
390 			*eofp = 1;
391 		return (0);
392 	}
393 	ASSERT(uiop->uio_loffset <= HS_MAXFILEOFF);
394 	offset = uiop->uio_loffset;
395 
396 	dname_size = fsp->hsfs_namemax + 1;	/* 1 for the ending NUL */
397 	dname = kmem_alloc(dname_size, KM_SLEEP);
398 	bufsize = uiop->uio_resid + sizeof (struct dirent64);
399 
400 	outbuf = kmem_alloc(bufsize, KM_SLEEP);
401 	nd = (struct dirent64 *)outbuf;
402 
403 	while (offset < dirsiz) {
404 		bytes_wanted = MIN(MAXBSIZE, dirsiz - (offset & MAXBMASK));
405 
406 		error = fbread(vp, (offset_t)(offset & MAXBMASK),
407 			(unsigned int)bytes_wanted, S_READ, &fbp);
408 		if (error)
409 			goto done;
410 
411 		blkp = (uchar_t *)fbp->fb_addr;
412 		last_offset = (offset & MAXBMASK) + fbp->fb_count;
413 
414 #define	rel_offset(offset) ((offset) & MAXBOFFSET)	/* index into blkp */
415 
416 		while (offset < last_offset) {
417 			/*
418 			 * Very similar validation code is found in
419 			 * process_dirblock(), hsfs_node.c.
420 			 * For an explanation, see there.
421 			 * It may make sense for the future to
422 			 * "consolidate" the code in hs_parsedir(),
423 			 * process_dirblock() and hsfs_readdir() into
424 			 * a single utility function.
425 			 */
426 			hdlen = (int)((uchar_t)
427 				HDE_DIR_LEN(&blkp[rel_offset(offset)]));
428 			if (hdlen < HDE_ROOT_DIR_REC_SIZE ||
429 			    offset + hdlen > last_offset) {
430 				/*
431 				 * advance to next sector boundary
432 				 */
433 				offset = roundup(offset + 1, HS_SECTOR_SIZE);
434 				if (hdlen)
435 					hs_log_bogus_disk_warning(fsp,
436 					    HSFS_ERR_TRAILING_JUNK, 0);
437 
438 				continue;
439 			}
440 
441 			bzero(&hd, sizeof (hd));
442 
443 			/*
444 			 * Just ignore invalid directory entries.
445 			 * XXX - maybe hs_parsedir() will detect EXISTENCE bit
446 			 */
447 			if (!hs_parsedir(fsp, &blkp[rel_offset(offset)],
448 				&hd, dname, &dnamelen)) {
449 				/*
450 				 * Determine if there is enough room
451 				 */
452 				ndlen = (long)DIRENT64_RECLEN((dnamelen));
453 
454 				if ((ndlen + ((char *)nd - outbuf)) >
455 				    uiop->uio_resid) {
456 					fbrelse(fbp, S_READ);
457 					goto done; /* output buffer full */
458 				}
459 
460 				diroff = offset + hdlen;
461 				/*
462 				 * Generate nodeid.
463 				 * If a directory, nodeid points to the
464 				 * canonical dirent describing the directory:
465 				 * the dirent of the "." entry for the
466 				 * directory, which is pointed to by all
467 				 * dirents for that directory.
468 				 * Otherwise, nodeid points to dirent of file.
469 				 */
470 				if (hd.type == VDIR) {
471 					dirino = (ino64_t)
472 					    MAKE_NODEID(hd.ext_lbn, 0,
473 					    vp->v_vfsp);
474 				} else {
475 					struct hs_volume *hvp;
476 					offset_t lbn, off;
477 
478 					/*
479 					 * Normalize lbn and off
480 					 */
481 					hvp = &fsp->hsfs_vol;
482 					lbn = dir_lbn +
483 					    (offset >> hvp->lbn_shift);
484 					off = offset & hvp->lbn_maxoffset;
485 					dirino = (ino64_t)MAKE_NODEID(lbn,
486 					    off, vp->v_vfsp);
487 				}
488 
489 
490 				/* strncpy(9f) will zero uninitialized bytes */
491 
492 				ASSERT(strlen(dname) + 1 <=
493 				    DIRENT64_NAMELEN(ndlen));
494 				(void) strncpy(nd->d_name, dname,
495 				    DIRENT64_NAMELEN(ndlen));
496 				nd->d_reclen = (ushort_t)ndlen;
497 				nd->d_off = (offset_t)diroff;
498 				nd->d_ino = dirino;
499 				nd = (struct dirent64 *)((char *)nd + ndlen);
500 
501 				/*
502 				 * free up space allocated for symlink
503 				 */
504 				if (hd.sym_link != (char *)NULL) {
505 					kmem_free(hd.sym_link,
506 					    (size_t)(hd.ext_size+1));
507 					hd.sym_link = (char *)NULL;
508 				}
509 			}
510 			offset += hdlen;
511 		}
512 		fbrelse(fbp, S_READ);
513 	}
514 
515 	/*
516 	 * Got here for one of the following reasons:
517 	 *	1) outbuf is full (error == 0)
518 	 *	2) end of directory reached (error == 0)
519 	 *	3) error reading directory sector (error != 0)
520 	 *	4) directory entry crosses sector boundary (error == 0)
521 	 *
522 	 * If any directory entries have been copied, don't report
523 	 * case 4.  Instead, return the valid directory entries.
524 	 *
525 	 * If no entries have been copied, report the error.
526 	 * If case 4, this will be indistiguishable from EOF.
527 	 */
528 done:
529 	ndlen = ((char *)nd - outbuf);
530 	if (ndlen != 0) {
531 		error = uiomove(outbuf, (size_t)ndlen, UIO_READ, uiop);
532 		uiop->uio_loffset = offset;
533 	}
534 	kmem_free(dname, dname_size);
535 	kmem_free(outbuf, bufsize);
536 	if (eofp && error == 0)
537 		*eofp = (uiop->uio_loffset >= dirsiz);
538 	return (error);
539 }
540 
541 static int
542 hsfs_fid(struct vnode *vp, struct fid *fidp)
543 {
544 	struct hsnode *hp;
545 	struct hsfid *fid;
546 
547 	if (fidp->fid_len < (sizeof (*fid) - sizeof (fid->hf_len))) {
548 		fidp->fid_len = sizeof (*fid) - sizeof (fid->hf_len);
549 		return (ENOSPC);
550 	}
551 
552 	fid = (struct hsfid *)fidp;
553 	fid->hf_len = sizeof (*fid) - sizeof (fid->hf_len);
554 	hp = VTOH(vp);
555 	mutex_enter(&hp->hs_contents_lock);
556 	fid->hf_dir_lbn = hp->hs_dir_lbn;
557 	fid->hf_dir_off = (ushort_t)hp->hs_dir_off;
558 	mutex_exit(&hp->hs_contents_lock);
559 	return (0);
560 }
561 
562 /*ARGSUSED*/
563 static int
564 hsfs_open(struct vnode **vpp, int flag, struct cred *cred)
565 {
566 	return (0);
567 }
568 
569 /*ARGSUSED*/
570 static int
571 hsfs_close(
572 	struct vnode *vp,
573 	int flag,
574 	int count,
575 	offset_t offset,
576 	struct cred *cred)
577 {
578 	(void) cleanlocks(vp, ttoproc(curthread)->p_pid, 0);
579 	cleanshares(vp, ttoproc(curthread)->p_pid);
580 	return (0);
581 }
582 
583 /*ARGSUSED2*/
584 static int
585 hsfs_access(struct vnode *vp, int mode, int flags, cred_t *cred)
586 {
587 	return (hs_access(vp, (mode_t)mode, cred));
588 }
589 
590 /*
591  * the seek time of a CD-ROM is very slow, and data transfer
592  * rate is even worse (max. 150K per sec).  The design
593  * decision is to reduce access to cd-rom as much as possible,
594  * and to transfer a sizable block (read-ahead) of data at a time.
595  * UFS style of read ahead one block at a time is not appropriate,
596  * and is not supported
597  */
598 
599 /*
600  * KLUSTSIZE should be a multiple of PAGESIZE and <= MAXPHYS.
601  */
602 #define	KLUSTSIZE	(56 * 1024)
603 /* we don't support read ahead */
604 int hsfs_lostpage;	/* no. of times we lost original page */
605 
606 /*
607  * Used to prevent biodone() from releasing buf resources that
608  * we didn't allocate in quite the usual way.
609  */
610 /*ARGSUSED*/
611 int
612 hsfs_iodone(struct buf *bp)
613 {
614 	sema_v(&bp->b_io);
615 	return (0);
616 }
617 
618 /*
619  * Each file may have a different interleaving on disk.  This makes
620  * things somewhat interesting.  The gist is that there are some
621  * number of contiguous data sectors, followed by some other number
622  * of contiguous skip sectors.  The sum of those two sets of sectors
623  * defines the interleave size.  Unfortunately, it means that we generally
624  * can't simply read N sectors starting at a given offset to satisfy
625  * any given request.
626  *
627  * What we do is get the relevant memory pages via pvn_read_kluster(),
628  * then stride through the interleaves, setting up a buf for each
629  * sector that needs to be brought in.  Instead of kmem_alloc'ing
630  * space for the sectors, though, we just point at the appropriate
631  * spot in the relevant page for each of them.  This saves us a bunch
632  * of copying.
633  */
634 /*ARGSUSED*/
635 static int
636 hsfs_getapage(
637 	struct vnode *vp,
638 	u_offset_t off,
639 	size_t len,
640 	uint_t *protp,
641 	struct page *pl[],
642 	size_t plsz,
643 	struct seg *seg,
644 	caddr_t addr,
645 	enum seg_rw rw,
646 	struct cred *cred)
647 {
648 	struct hsnode *hp;
649 	struct hsfs *fsp;
650 	int	err;
651 	struct buf *bufs;
652 	caddr_t *vas;
653 	caddr_t va;
654 	struct page *pp, *searchp, *lastp;
655 	page_t	*pagefound;
656 	offset_t	bof;
657 	struct vnode *devvp;
658 	ulong_t	byte_offset;
659 	size_t	io_len_tmp;
660 	uint_t	io_off, io_len;
661 	uint_t	xlen;
662 	uint_t	filsiz;
663 	uint_t	secsize;
664 	uint_t	bufcnt;
665 	uint_t	bufsused;
666 	uint_t	count;
667 	uint_t	io_end;
668 	uint_t	which_chunk_lbn;
669 	uint_t	offset_lbn;
670 	uint_t	offset_extra;
671 	offset_t	offset_bytes;
672 	uint_t	remaining_bytes;
673 	uint_t	extension;
674 	int	remainder;	/* must be signed */
675 	int	chunk_lbn_count;
676 	int	chunk_data_bytes;
677 	int	xarsiz;
678 	diskaddr_t driver_block;
679 	u_offset_t io_off_tmp;
680 
681 	/*
682 	 * We don't support asynchronous operation at the moment, so
683 	 * just pretend we did it.  If the pages are ever actually
684 	 * needed, they'll get brought in then.
685 	 */
686 	if (pl == NULL)
687 		return (0);
688 
689 	hp = VTOH(vp);
690 	fsp = VFS_TO_HSFS(vp->v_vfsp);
691 	devvp = fsp->hsfs_devvp;
692 	secsize = fsp->hsfs_vol.lbn_size;  /* bytes per logical block */
693 
694 	/* file data size */
695 	filsiz = hp->hs_dirent.ext_size;
696 
697 	/* disk addr for start of file */
698 	bof = LBN_TO_BYTE((offset_t)hp->hs_dirent.ext_lbn, vp->v_vfsp);
699 
700 	/* xarsiz byte must be skipped for data */
701 	xarsiz = hp->hs_dirent.xar_len << fsp->hsfs_vol.lbn_shift;
702 
703 	/* how many logical blocks in an interleave (data+skip) */
704 	chunk_lbn_count = hp->hs_dirent.intlf_sz + hp->hs_dirent.intlf_sk;
705 
706 	if (chunk_lbn_count == 0) {
707 		chunk_lbn_count = 1;
708 	}
709 
710 	/*
711 	 * Convert interleaving size into bytes.  The zero case
712 	 * (no interleaving) optimization is handled as a side-
713 	 * effect of the read-ahead logic.
714 	 */
715 	if (hp->hs_dirent.intlf_sz == 0) {
716 		chunk_data_bytes = LBN_TO_BYTE(1, vp->v_vfsp);
717 	} else {
718 		chunk_data_bytes = LBN_TO_BYTE(hp->hs_dirent.intlf_sz,
719 			vp->v_vfsp);
720 	}
721 
722 reread:
723 	err = 0;
724 	pagefound = 0;
725 
726 	/*
727 	 * Do some read-ahead.  This mostly saves us a bit of
728 	 * system cpu time more than anything else when doing
729 	 * sequential reads.  At some point, could do the
730 	 * read-ahead asynchronously which might gain us something
731 	 * on wall time, but it seems unlikely....
732 	 *
733 	 * We do the easy case here, which is to read through
734 	 * the end of the chunk, minus whatever's at the end that
735 	 * won't exactly fill a page.
736 	 */
737 	which_chunk_lbn = (off + len) / chunk_data_bytes;
738 	extension = ((which_chunk_lbn + 1) * chunk_data_bytes) - off;
739 	extension -= (extension % PAGESIZE);
740 	if (extension != 0 && extension < filsiz - off) {
741 		len = extension;
742 	} else {
743 		len = PAGESIZE;
744 	}
745 	/*
746 	 * Some cd writers don't write sectors that aren't used.  Also,
747 	 * there's no point in reading sectors we'll never look at.  So,
748 	 * if we're asked to go beyond the end of a file, truncate to the
749 	 * length of that file.
750 	 *
751 	 * Additionally, this behaviour is required by section 6.4.5 of
752 	 * ISO 9660:1988(E).
753 	 */
754 	if (len > (filsiz - off)) {
755 		len = filsiz - off;
756 	}
757 
758 	/* A little paranoia. */
759 	ASSERT(len > 0);
760 
761 	/*
762 	 * After all that, make sure we're asking for things in units
763 	 * that bdev_strategy() will understand (see bug 4202551).
764 	 */
765 	len = roundup(len, DEV_BSIZE);
766 
767 	pp = NULL;
768 again:
769 	/* search for page in buffer */
770 	if ((pagefound = page_exists(vp, off)) == 0) {
771 		/*
772 		 * Need to really do disk IO to get the page.
773 		 */
774 		pp = pvn_read_kluster(vp, off, seg, addr, &io_off_tmp,
775 		    &io_len_tmp, off, len, 0);
776 
777 		if (pp == NULL)
778 			goto again;
779 
780 		io_off = (uint_t)io_off_tmp;
781 		io_len = (uint_t)io_len_tmp;
782 
783 		/* check for truncation */
784 		/*
785 		 * xxx Clean up and return EIO instead?
786 		 * xxx Ought to go to u_offset_t for everything, but we
787 		 * xxx call lots of things that want uint_t arguments.
788 		 */
789 		ASSERT(io_off == io_off_tmp);
790 
791 		/*
792 		 * get enough buffers for worst-case scenario
793 		 * (i.e., no coalescing possible).
794 		 */
795 		bufcnt = (len + secsize - 1) / secsize;
796 		bufs = kmem_zalloc(bufcnt * sizeof (struct buf), KM_SLEEP);
797 		vas = kmem_alloc(bufcnt * sizeof (caddr_t), KM_SLEEP);
798 		for (count = 0; count < bufcnt; count++) {
799 			bufs[count].b_edev = devvp->v_rdev;
800 			bufs[count].b_dev = cmpdev(devvp->v_rdev);
801 			bufs[count].b_flags = B_NOCACHE|B_BUSY|B_READ;
802 			bufs[count].b_iodone = hsfs_iodone;
803 			bufs[count].b_vp = vp;
804 			bufs[count].b_file = vp;
805 			sema_init(&bufs[count].b_io, 0, NULL,
806 			    SEMA_DEFAULT, NULL);
807 			sema_init(&bufs[count].b_sem, 0, NULL,
808 			    SEMA_DEFAULT, NULL);
809 		}
810 
811 		/*
812 		 * If our filesize is not an integer multiple of PAGESIZE,
813 		 * we zero that part of the last page that's between EOF and
814 		 * the PAGESIZE boundary.
815 		 */
816 		xlen = io_len & PAGEOFFSET;
817 		if (xlen != 0)
818 			pagezero(pp->p_prev, xlen, PAGESIZE - xlen);
819 
820 		va = NULL;
821 		lastp = NULL;
822 		searchp = pp;
823 		io_end = io_off + io_len;
824 		for (count = 0, byte_offset = io_off;
825 			byte_offset < io_end;
826 			count++) {
827 			ASSERT(count < bufcnt);
828 
829 			/* Compute disk address for interleaving. */
830 
831 			/* considered without skips */
832 			which_chunk_lbn = byte_offset / chunk_data_bytes;
833 
834 			/* factor in skips */
835 			offset_lbn = which_chunk_lbn * chunk_lbn_count;
836 
837 			/* convert to physical byte offset for lbn */
838 			offset_bytes = LBN_TO_BYTE(offset_lbn, vp->v_vfsp);
839 
840 			/* don't forget offset into lbn */
841 			offset_extra = byte_offset % chunk_data_bytes;
842 
843 			/* get virtual block number for driver */
844 			driver_block = lbtodb(bof + xarsiz
845 				+ offset_bytes + offset_extra);
846 
847 			if (lastp != searchp) {
848 				/* this branch taken first time through loop */
849 				va = vas[count]
850 					= ppmapin(searchp, PROT_WRITE,
851 						(caddr_t)-1);
852 				/* ppmapin() guarantees not to return NULL */
853 			} else {
854 				vas[count] = NULL;
855 			}
856 
857 			bufs[count].b_un.b_addr = va + byte_offset % PAGESIZE;
858 			bufs[count].b_offset =
859 			    (offset_t)(byte_offset - io_off + off);
860 
861 			/*
862 			 * We specifically use the b_lblkno member here
863 			 * as even in the 32 bit world driver_block can
864 			 * get very large in line with the ISO9660 spec.
865 			 */
866 
867 			bufs[count].b_lblkno = driver_block;
868 
869 			remaining_bytes = ((which_chunk_lbn + 1)
870 				* chunk_data_bytes)
871 				- byte_offset;
872 
873 			/*
874 			 * remaining_bytes can't be zero, as we derived
875 			 * which_chunk_lbn directly from byte_offset.
876 			 */
877 			if ((remaining_bytes + byte_offset) < (off + len)) {
878 				/* coalesce-read the rest of the chunk */
879 				bufs[count].b_bcount = remaining_bytes;
880 			} else {
881 				/* get the final bits */
882 				bufs[count].b_bcount = off + len - byte_offset;
883 			}
884 
885 			/*
886 			 * It would be nice to do multiple pages'
887 			 * worth at once here when the opportunity
888 			 * arises, as that has been shown to improve
889 			 * our wall time.  However, to do that
890 			 * requires that we use the pageio subsystem,
891 			 * which doesn't mix well with what we're
892 			 * already using here.  We can't use pageio
893 			 * all the time, because that subsystem
894 			 * assumes that a page is stored in N
895 			 * contiguous blocks on the device.
896 			 * Interleaving violates that assumption.
897 			 */
898 
899 			remainder = PAGESIZE - (byte_offset % PAGESIZE);
900 			if (bufs[count].b_bcount > remainder) {
901 				bufs[count].b_bcount = remainder;
902 			}
903 
904 			bufs[count].b_bufsize = bufs[count].b_bcount;
905 			if (((offset_t)byte_offset + bufs[count].b_bcount) >
906 				HS_MAXFILEOFF) {
907 				break;
908 			}
909 			byte_offset += bufs[count].b_bcount;
910 
911 			(void) bdev_strategy(&bufs[count]);
912 
913 			lwp_stat_update(LWP_STAT_INBLK, 1);
914 			lastp = searchp;
915 			if ((remainder - bufs[count].b_bcount) < 1) {
916 				searchp = searchp->p_next;
917 			}
918 		}
919 
920 		bufsused = count;
921 		/* Now wait for everything to come in */
922 		for (count = 0; count < bufsused; count++) {
923 			if (err == 0) {
924 				err = biowait(&bufs[count]);
925 			} else
926 				(void) biowait(&bufs[count]);
927 		}
928 
929 		/* Don't leak resources */
930 		for (count = 0; count < bufcnt; count++) {
931 			sema_destroy(&bufs[count].b_io);
932 			sema_destroy(&bufs[count].b_sem);
933 			if (count < bufsused && vas[count] != NULL) {
934 				ppmapout(vas[count]);
935 			}
936 		}
937 
938 		kmem_free(vas, bufcnt * sizeof (caddr_t));
939 		kmem_free(bufs, bufcnt * sizeof (struct buf));
940 	}
941 
942 	if (err) {
943 		pvn_read_done(pp, B_ERROR);
944 		return (err);
945 	}
946 
947 	/*
948 	 * Lock the requested page, and the one after it if possible.
949 	 * Don't bother if our caller hasn't given us a place to stash
950 	 * the page pointers, since otherwise we'd lock pages that would
951 	 * never get unlocked.
952 	 */
953 	if (pagefound) {
954 		int index;
955 		ulong_t soff;
956 
957 		/*
958 		 * Make sure it's in memory before we say it's here.
959 		 */
960 		if ((pp = page_lookup(vp, off, SE_SHARED)) == NULL) {
961 			hsfs_lostpage++;
962 			goto reread;
963 		}
964 
965 		pl[0] = pp;
966 		index = 1;
967 
968 		/*
969 		 * Try to lock the next page, if it exists, without
970 		 * blocking.
971 		 */
972 		plsz -= PAGESIZE;
973 		/* LINTED (plsz is unsigned) */
974 		for (soff = off + PAGESIZE; plsz > 0;
975 		    soff += PAGESIZE, plsz -= PAGESIZE) {
976 			pp = page_lookup_nowait(vp, (u_offset_t)soff,
977 					SE_SHARED);
978 			if (pp == NULL)
979 				break;
980 			pl[index++] = pp;
981 		}
982 		pl[index] = NULL;
983 		return (0);
984 	}
985 
986 	if (pp != NULL) {
987 		pvn_plist_init(pp, pl, plsz, off, io_len, rw);
988 	}
989 
990 	return (err);
991 }
992 
993 static int
994 hsfs_getpage(
995 	struct vnode *vp,
996 	offset_t off,
997 	size_t len,
998 	uint_t *protp,
999 	struct page *pl[],
1000 	size_t plsz,
1001 	struct seg *seg,
1002 	caddr_t addr,
1003 	enum seg_rw rw,
1004 	struct cred *cred)
1005 {
1006 	int err;
1007 	uint_t filsiz;
1008 	struct hsnode *hp = VTOH(vp);
1009 
1010 	/* does not support write */
1011 	if (rw == S_WRITE) {
1012 		panic("write attempt on READ ONLY HSFS");
1013 		/*NOTREACHED*/
1014 	}
1015 
1016 	if (vp->v_flag & VNOMAP) {
1017 		return (ENOSYS);
1018 	}
1019 
1020 	ASSERT(off <= HS_MAXFILEOFF);
1021 
1022 	/*
1023 	 * Determine file data size for EOF check.
1024 	 */
1025 	filsiz = hp->hs_dirent.ext_size;
1026 	if ((off + len) > (offset_t)(filsiz + PAGEOFFSET) && seg != segkmap)
1027 		return (EFAULT);	/* beyond EOF */
1028 
1029 	if (protp != NULL)
1030 		*protp = PROT_ALL;
1031 
1032 	if (len <= PAGESIZE)
1033 		err = hsfs_getapage(vp, (u_offset_t)off, len, protp, pl, plsz,
1034 		    seg, addr, rw, cred);
1035 	else
1036 		err = pvn_getpages(hsfs_getapage, vp, off, len, protp,
1037 		    pl, plsz, seg, addr, rw, cred);
1038 
1039 	return (err);
1040 }
1041 
1042 
1043 
1044 /*
1045  * This function should never be called. We need to have it to pass
1046  * it as an argument to other functions.
1047  */
1048 /*ARGSUSED*/
1049 int
1050 hsfs_putapage(
1051 	vnode_t		*vp,
1052 	page_t		*pp,
1053 	u_offset_t	*offp,
1054 	size_t		*lenp,
1055 	int		flags,
1056 	cred_t		*cr)
1057 {
1058 	/* should never happen - just destroy it */
1059 	cmn_err(CE_NOTE, "hsfs_putapage: dirty HSFS page");
1060 	pvn_write_done(pp, B_ERROR | B_WRITE | B_INVAL | B_FORCE | flags);
1061 	return (0);
1062 }
1063 
1064 
1065 /*
1066  * The only flags we support are B_INVAL, B_FREE and B_DONTNEED.
1067  * B_INVAL is set by:
1068  *
1069  *	1) the MC_SYNC command of memcntl(2) to support the MS_INVALIDATE flag.
1070  *	2) the MC_ADVISE command of memcntl(2) with the MADV_DONTNEED advice
1071  *	   which translates to an MC_SYNC with the MS_INVALIDATE flag.
1072  *
1073  * The B_FREE (as well as the B_DONTNEED) flag is set when the
1074  * MADV_SEQUENTIAL advice has been used. VOP_PUTPAGE is invoked
1075  * from SEGVN to release pages behind a pagefault.
1076  */
1077 /*ARGSUSED*/
1078 static int
1079 hsfs_putpage(
1080 	struct vnode	*vp,
1081 	offset_t	off,
1082 	size_t		len,
1083 	int		flags,
1084 	struct cred	*cr)
1085 {
1086 	int error = 0;
1087 
1088 	if (vp->v_count == 0) {
1089 		panic("hsfs_putpage: bad v_count");
1090 		/*NOTREACHED*/
1091 	}
1092 
1093 	if (vp->v_flag & VNOMAP)
1094 		return (ENOSYS);
1095 
1096 	ASSERT(off <= HS_MAXFILEOFF);
1097 
1098 	if (!vn_has_cached_data(vp))	/* no pages mapped */
1099 		return (0);
1100 
1101 	if (len == 0)		/* from 'off' to EOF */
1102 		error = pvn_vplist_dirty(vp, off,
1103 					hsfs_putapage, flags, cr);
1104 	else {
1105 		offset_t end_off = off + len;
1106 		offset_t file_size = VTOH(vp)->hs_dirent.ext_size;
1107 		offset_t io_off;
1108 
1109 		file_size = (file_size + PAGESIZE - 1) & PAGEMASK;
1110 		if (end_off > file_size)
1111 			end_off = file_size;
1112 
1113 		for (io_off = off; io_off < end_off; io_off += PAGESIZE) {
1114 			page_t *pp;
1115 
1116 			/*
1117 			 * We insist on getting the page only if we are
1118 			 * about to invalidate, free or write it and
1119 			 * the B_ASYNC flag is not set.
1120 			 */
1121 			if ((flags & B_INVAL) || ((flags & B_ASYNC) == 0)) {
1122 				pp = page_lookup(vp, io_off,
1123 					(flags & (B_INVAL | B_FREE)) ?
1124 					    SE_EXCL : SE_SHARED);
1125 			} else {
1126 				pp = page_lookup_nowait(vp, io_off,
1127 					(flags & B_FREE) ? SE_EXCL : SE_SHARED);
1128 			}
1129 
1130 			if (pp == NULL)
1131 				continue;
1132 			/*
1133 			 * Normally pvn_getdirty() should return 0, which
1134 			 * impies that it has done the job for us.
1135 			 * The shouldn't-happen scenario is when it returns 1.
1136 			 * This means that the page has been modified and
1137 			 * needs to be put back.
1138 			 * Since we can't write on a CD, we fake a failed
1139 			 * I/O and force pvn_write_done() to destroy the page.
1140 			 */
1141 			if (pvn_getdirty(pp, flags) == 1) {
1142 				cmn_err(CE_NOTE,
1143 					"hsfs_putpage: dirty HSFS page");
1144 				pvn_write_done(pp, flags |
1145 				    B_ERROR | B_WRITE | B_INVAL | B_FORCE);
1146 			}
1147 		}
1148 	}
1149 	return (error);
1150 }
1151 
1152 
1153 /*ARGSUSED*/
1154 static int
1155 hsfs_map(
1156 	struct vnode *vp,
1157 	offset_t off,
1158 	struct as *as,
1159 	caddr_t *addrp,
1160 	size_t len,
1161 	uchar_t prot,
1162 	uchar_t maxprot,
1163 	uint_t flags,
1164 	struct cred *cred)
1165 {
1166 	struct segvn_crargs vn_a;
1167 	int error;
1168 
1169 	/* VFS_RECORD(vp->v_vfsp, VS_MAP, VS_CALL); */
1170 
1171 	if (vp->v_flag & VNOMAP)
1172 		return (ENOSYS);
1173 
1174 	if (off > HS_MAXFILEOFF || off < 0 ||
1175 	    (off + len) < 0 || (off + len) > HS_MAXFILEOFF)
1176 		return (ENXIO);
1177 
1178 	if (vp->v_type != VREG) {
1179 		return (ENODEV);
1180 	}
1181 
1182 	/*
1183 	 * If file is being locked, disallow mapping.
1184 	 */
1185 	if (vn_has_mandatory_locks(vp, VTOH(vp)->hs_dirent.mode))
1186 		return (EAGAIN);
1187 
1188 	as_rangelock(as);
1189 
1190 	if ((flags & MAP_FIXED) == 0) {
1191 		map_addr(addrp, len, off, 1, flags);
1192 		if (*addrp == NULL) {
1193 			as_rangeunlock(as);
1194 			return (ENOMEM);
1195 		}
1196 	} else {
1197 		/*
1198 		 * User specified address - blow away any previous mappings
1199 		 */
1200 		(void) as_unmap(as, *addrp, len);
1201 	}
1202 
1203 	vn_a.vp = vp;
1204 	vn_a.offset = off;
1205 	vn_a.type = flags & MAP_TYPE;
1206 	vn_a.prot = prot;
1207 	vn_a.maxprot = maxprot;
1208 	vn_a.flags = flags & ~MAP_TYPE;
1209 	vn_a.cred = cred;
1210 	vn_a.amp = NULL;
1211 	vn_a.szc = 0;
1212 	vn_a.lgrp_mem_policy_flags = 0;
1213 
1214 	error = as_map(as, *addrp, len, segvn_create, &vn_a);
1215 	as_rangeunlock(as);
1216 	return (error);
1217 }
1218 
1219 /* ARGSUSED */
1220 static int
1221 hsfs_addmap(
1222 	struct vnode *vp,
1223 	offset_t off,
1224 	struct as *as,
1225 	caddr_t addr,
1226 	size_t len,
1227 	uchar_t prot,
1228 	uchar_t maxprot,
1229 	uint_t flags,
1230 	struct cred *cr)
1231 {
1232 	struct hsnode *hp;
1233 
1234 	if (vp->v_flag & VNOMAP)
1235 		return (ENOSYS);
1236 
1237 	hp = VTOH(vp);
1238 	mutex_enter(&hp->hs_contents_lock);
1239 	hp->hs_mapcnt += btopr(len);
1240 	mutex_exit(&hp->hs_contents_lock);
1241 	return (0);
1242 }
1243 
1244 /*ARGSUSED*/
1245 static int
1246 hsfs_delmap(
1247 	struct vnode *vp,
1248 	offset_t off,
1249 	struct as *as,
1250 	caddr_t addr,
1251 	size_t len,
1252 	uint_t prot,
1253 	uint_t maxprot,
1254 	uint_t flags,
1255 	struct cred *cr)
1256 {
1257 	struct hsnode *hp;
1258 
1259 	if (vp->v_flag & VNOMAP)
1260 		return (ENOSYS);
1261 
1262 	hp = VTOH(vp);
1263 	mutex_enter(&hp->hs_contents_lock);
1264 	hp->hs_mapcnt -= btopr(len);	/* Count released mappings */
1265 	ASSERT(hp->hs_mapcnt >= 0);
1266 	mutex_exit(&hp->hs_contents_lock);
1267 	return (0);
1268 }
1269 
1270 /* ARGSUSED */
1271 static int
1272 hsfs_seek(struct vnode *vp, offset_t ooff, offset_t *noffp)
1273 {
1274 	return ((*noffp < 0 || *noffp > MAXOFFSET_T) ? EINVAL : 0);
1275 }
1276 
1277 /* ARGSUSED */
1278 static int
1279 hsfs_frlock(
1280 	struct vnode *vp,
1281 	int cmd,
1282 	struct flock64 *bfp,
1283 	int flag,
1284 	offset_t offset,
1285 	struct flk_callback *flk_cbp,
1286 	cred_t *cr)
1287 {
1288 	struct hsnode *hp = VTOH(vp);
1289 
1290 	/*
1291 	 * If the file is being mapped, disallow fs_frlock.
1292 	 * We are not holding the hs_contents_lock while checking
1293 	 * hs_mapcnt because the current locking strategy drops all
1294 	 * locks before calling fs_frlock.
1295 	 * So, hs_mapcnt could change before we enter fs_frlock making
1296 	 * it meaningless to have held hs_contents_lock in the first place.
1297 	 */
1298 	if (hp->hs_mapcnt > 0 && MANDLOCK(vp, hp->hs_dirent.mode))
1299 		return (EAGAIN);
1300 
1301 	return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr));
1302 }
1303 
1304 const fs_operation_def_t hsfs_vnodeops_template[] = {
1305 	VOPNAME_OPEN, hsfs_open,
1306 	VOPNAME_CLOSE, hsfs_close,
1307 	VOPNAME_READ, hsfs_read,
1308 	VOPNAME_GETATTR, hsfs_getattr,
1309 	VOPNAME_ACCESS, hsfs_access,
1310 	VOPNAME_LOOKUP, hsfs_lookup,
1311 	VOPNAME_READDIR, hsfs_readdir,
1312 	VOPNAME_READLINK, hsfs_readlink,
1313 	VOPNAME_FSYNC, hsfs_fsync,
1314 	VOPNAME_INACTIVE, (fs_generic_func_p) hsfs_inactive,
1315 	VOPNAME_FID, hsfs_fid,
1316 	VOPNAME_SEEK, hsfs_seek,
1317 	VOPNAME_FRLOCK, hsfs_frlock,
1318 	VOPNAME_GETPAGE, hsfs_getpage,
1319 	VOPNAME_PUTPAGE, hsfs_putpage,
1320 	VOPNAME_MAP, (fs_generic_func_p) hsfs_map,
1321 	VOPNAME_ADDMAP, (fs_generic_func_p) hsfs_addmap,
1322 	VOPNAME_DELMAP, hsfs_delmap,
1323 	NULL, NULL
1324 };
1325 
1326 struct vnodeops *hsfs_vnodeops;
1327