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