xref: /386bsd/usr/src/kernel/isofs/isofs_node.c (revision a2142627)
1 /*
2  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  *	$Id: $
34  */
35 
36 #include "sys/param.h"
37 #include "sys/mount.h"
38 #include "sys/file.h"
39 #include "sys/errno.h"
40 #include "proc.h"
41 #include "buf.h"
42 #include "uio.h"
43 #include "malloc.h"
44 
45 #include "vnode.h"
46 #include "iso.h"
47 #include "isofs_node.h"
48 #include "iso_rrip.h"
49 #include "ufs_dinode.h"		/* XXX  */
50 
51 #include "prototypes.h"
52 
53 #define	INOHSZ	512
54 #if	((INOHSZ&(INOHSZ-1)) == 0)
55 #define	INOHASH(dev,ino)	(((dev)+(ino))&(INOHSZ-1))
56 #else
57 #define	INOHASH(dev,ino)	(((unsigned)((dev)+(ino)))%INOHSZ)
58 #endif
59 
60 union iso_ihead {
61 	union  iso_ihead *ih_head[2];
62 	struct iso_node *ih_chain[2];
63 } iso_ihead[INOHSZ];
64 
65 
66 /*
67  * Initialize hash links for inodes.
68  */
69 isofs_init()
70 {
71 	register int i;
72 	register union iso_ihead *ih = iso_ihead;
73 
74 #ifndef lint
75 	if (VN_MAXPRIVATE < sizeof(struct iso_node))
76 		panic("ihinit: too small");
77 #endif /* not lint */
78 	for (i = INOHSZ; --i >= 0; ih++) {
79 		ih->ih_head[0] = ih;
80 		ih->ih_head[1] = ih;
81 	}
82 }
83 
84 /*
85  * Look up a ISOFS dinode number to find its incore vnode.
86  * If it is not in core, read it in from the specified device.
87  * If it is in core, wait for the lock bit to clear, then
88  * return the inode locked. Detection and handling of mount
89  * points must be done by the calling routine.
90  */
91 iso_iget(xp, ino, ipp, isodir)
92 	struct iso_node *xp;
93 	ino_t ino;
94 	struct iso_node **ipp;
95 	struct iso_directory_record *isodir;
96 {
97 	dev_t dev = xp->i_dev;
98 	struct mount *mntp = ITOV(xp)->v_mount;
99 	extern struct vnodeops isofs_vnodeops, spec_isonodeops;
100 	register struct iso_node *ip, *iq;
101 	register struct vnode *vp;
102 	struct vnode *nvp;
103 	struct buf *bp;
104 	struct dinode *dp;
105 	union iso_ihead *ih;
106 	int i, error, result;
107 	struct iso_mnt *imp;
108 
109 	ih = &iso_ihead[INOHASH(dev, ino)];
110 loop:
111 	for (ip = ih->ih_chain[0];
112 	     ip != (struct iso_node *)ih;
113 	     ip = ip->i_forw) {
114 		if (ino != ip->i_number || dev != ip->i_dev)
115 			continue;
116 		if ((ip->i_flag&ILOCKED) != 0) {
117 			ip->i_flag |= IWANT;
118 			tsleep((caddr_t)ip, PINOD, "isoget", 0);
119 			goto loop;
120 		}
121 		if (vget(ITOV(ip)))
122 			goto loop;
123 		*ipp = ip;
124 		return(0);
125 	}
126 	/*
127 	 * Allocate a new inode.
128 	 */
129 #define VT_ISOFS	(VT_MFS+1)
130 	if (error = getnewvnode(VT_ISOFS, mntp, &isofs_vnodeops, &nvp)) {
131 		*ipp = 0;
132 		return (error);
133 	}
134 	ip = VTOI(nvp);
135 	ip->i_vnode = nvp;
136 	ip->i_flag = 0;
137 	ip->i_devvp = 0;
138 	ip->i_diroff = 0;
139 	ip->iso_parent = xp->i_diroff; /* Parent directory's */
140 	ip->iso_parent_ext = xp->iso_extent;
141 	ip->i_lockf = 0;
142 	/*
143 	 * Put it onto its hash chain and lock it so that other requests for
144 	 * this inode will block if they arrive while we are sleeping waiting
145 	 * for old data structures to be purged or for the contents of the
146 	 * disk portion of this inode to be read.
147 	 */
148 	ip->i_dev = dev;
149 	ip->i_number = ino;
150 	insque(ip, ih);
151 	ISO_ILOCK(ip);
152 
153 	ip->iso_reclen = isonum_711 (isodir->length);
154 	ip->iso_extlen = isonum_711 (isodir->ext_attr_length);
155 	ip->iso_extent = isonum_733 (isodir->extent);
156 	ip->i_size = isonum_733 (isodir->size);
157 	ip->iso_flags = isonum_711 (isodir->flags);
158 	ip->iso_unit_size = isonum_711 (isodir->file_unit_size);
159 	ip->iso_interleave_gap = isonum_711 (isodir->interleave);
160 	ip->iso_volume_seq = isonum_723 (isodir->volume_sequence_number);
161 	ip->iso_namelen = isonum_711 (isodir->name_len);
162 
163 	imp = VFSTOISOFS (mntp);
164 	vp = ITOV(ip);
165 	ip->inode.iso_mode = 0;
166 	ip->inode.iso_dev = 0;
167 	result = 0;
168 
169 	/*
170 	 * Setup time stamp, attribute , if CL or PL, set loc but not yet..
171 	 */
172 	switch ( imp->iso_ftype ) {
173 		case ISO_FTYPE_9660:
174 			isofs_rrip_defattr  ( isodir, &(ip->inode) );
175 			isofs_rrip_deftstamp( isodir, &(ip->inode) );
176 			goto FlameOff;
177 			break;
178 		case ISO_FTYPE_RRIP:
179 			result = isofs_rrip_analyze( isodir, &(ip->inode) );
180 			break;
181 		default:
182 			printf("unknown iso_ftype.. %d\n", imp->iso_ftype );
183 			break;
184 	}
185 #ifdef nope
186 if(ino == 6786446) {
187 /* printf("force console "); */
188 	ip->inode.iso_mode &= ~IFMT;
189 	ip->inode.iso_mode |= IFCHR;
190 	ip->inode.iso_dev = makedev(0,0);
191 	result |= ISO_SUSP_DEVICE;
192 }
193 if(ino == 6790878) {
194 /* printf("force fd0a "); */
195 	ip->inode.iso_mode &= ~IFMT;
196 	ip->inode.iso_mode |= IFBLK;
197 	ip->inode.iso_dev = makedev(2,0);
198 	result |= ISO_SUSP_DEVICE;
199 }
200 if(ino == 6979808) {
201 /* printf("force wd0a "); */
202 	ip->inode.iso_mode &= ~IFMT;
203 	ip->inode.iso_mode |= IFBLK;
204 	ip->inode.iso_dev = makedev(0,0);
205 	result |= ISO_SUSP_DEVICE;
206 }
207 if(ino == 6981968) {
208 /* printf("force wd0b "); */
209 	ip->inode.iso_mode &= ~IFMT;
210 	ip->inode.iso_mode |= IFBLK;
211 	ip->inode.iso_dev = makedev(0,1);
212 	result |= ISO_SUSP_DEVICE;
213 }
214 if(ino == 6782126) {
215 /* printf("force com1 "); */
216 	ip->inode.iso_mode &= ~IFMT;
217 	ip->inode.iso_mode |= IFCHR;
218 	ip->inode.iso_dev = makedev(8,1);
219 	result |= ISO_SUSP_DEVICE;
220 }
221 if(ino == 6942836) {
222 /* printf("force tty "); */
223 	ip->inode.iso_mode &= ~IFMT;
224 	ip->inode.iso_mode |= IFCHR;
225 	ip->inode.iso_dev = makedev(1,0);
226 	result |= ISO_SUSP_DEVICE;
227 }
228 
229 if(ino == 6977650) {
230 /* printf("force vga "); */
231 	ip->inode.iso_mode &= ~IFMT;
232 	ip->inode.iso_mode |= IFCHR;
233 	ip->inode.iso_dev = makedev(12,0);
234 	result |= ISO_SUSP_DEVICE;
235 }
236 if(ino == 6808336) {
237 /* printf("force kmem "); */
238 	ip->inode.iso_mode &= ~IFMT;
239 	ip->inode.iso_mode |= IFCHR;
240 	ip->inode.iso_dev = makedev(2,1);
241 	result |= ISO_SUSP_DEVICE;
242 }
243 if(ino == 6834176) {
244 /* printf("force mem "); */
245 	ip->inode.iso_mode &= ~IFMT;
246 	ip->inode.iso_mode |= IFCHR;
247 	ip->inode.iso_dev = makedev(2,0);
248 	result |= ISO_SUSP_DEVICE;
249 }
250 if(ino == 6836334) {
251 /* printf("force null "); */
252 	ip->inode.iso_mode &= ~IFMT;
253 	ip->inode.iso_mode |= IFCHR;
254 	ip->inode.iso_dev = makedev(2,2);
255 	result |= ISO_SUSP_DEVICE;
256 }
257 if(ino == 6927476) {
258 /* printf("force rwd0d "); */
259 	ip->inode.iso_mode &= ~IFMT;
260 	ip->inode.iso_mode |= IFCHR;
261 	ip->inode.iso_dev = makedev(3,3);
262 	result |= ISO_SUSP_DEVICE;
263 }
264 if(ino == 6920990) {
265 /* printf("force rwd0a "); */
266 	ip->inode.iso_mode &= ~IFMT;
267 	ip->inode.iso_mode |= IFCHR;
268 	ip->inode.iso_dev = makedev(3,0);
269 	result |= ISO_SUSP_DEVICE;
270 }
271 #endif
272 
273 
274 	if ((ip->inode.iso_mode & IFMT) == IFBLK)
275 		vp->v_type = VBLK;
276 	else
277 	if ((ip->inode.iso_mode & IFMT) == IFCHR)
278 		vp->v_type = VCHR;
279 	else {
280 FlameOff:
281 		if (ip->iso_flags & 2) {
282 			vp->v_type = VDIR;
283 		} else {
284 			vp->v_type = VREG;
285 		}
286 	}
287 
288 	/*
289 	 * Initialize the associated vnode
290 	 */
291 	if ( result & ISO_SUSP_SLINK ) {
292         	char    symname[NAME_MAX];
293 		int symlen;
294 
295 		vp->v_type = VLNK;	      /* Symbolic Link */
296         	isofs_rrip_getsymname(vp, isodir, symname, &symlen);
297 	        ip->i_size = symlen;
298 /*printf("SL%d mode %x ", symlen, ip->inode.iso_mode);*/
299 	}
300 	if ( result & ISO_SUSP_DEVICE ) {
301 		vp->v_op = &spec_isonodeops;
302 		if (nvp = checkalias(vp, ip->inode.iso_dev, mntp)) {
303 			/*
304 			 * Reinitialize aliased inode.
305 			 */
306 			vp = nvp;
307 			iq = VTOI(vp);
308 			iq->i_vnode = vp;
309 			iq->i_flag = 0;
310 			ISO_ILOCK(iq);
311 			iq->inode = ip->inode;
312 			iq->i_dev = dev;
313 			iq->i_number = ino;
314 			insque(iq, ih);
315 			/*
316 			 * Discard unneeded vnode
317 			 */
318 			iso_iput(ip);
319 			ip = iq;
320 		}
321 	}
322 
323 	imp = VFSTOISOFS (mntp);
324 
325 	if (ino == iso_lblktosize(imp, imp->root_extent))
326 		vp->v_flag |= VROOT;
327 	/*
328 	 * Finish inode initialization.
329 	 */
330 	ip->i_mnt = imp;
331 	ip->i_devvp = imp->im_devvp;
332 	VREF(ip->i_devvp);
333 	*ipp = ip;
334 	return (0);
335 }
336 
337 /*
338  * Unlock and decrement the reference count of an inode structure.
339  */
340 iso_iput(ip)
341 	register struct iso_node *ip;
342 {
343 
344 	if ((ip->i_flag & ILOCKED) == 0)
345 		panic("iso_iput");
346 	ISO_IUNLOCK(ip);
347 	vrele(ITOV(ip));
348 }
349 
350 /*
351  * Last reference to an inode, write the inode out and if necessary,
352  * truncate and deallocate the file.
353  */
354 isofs_inactive(vp, p)
355 	struct vnode *vp;
356 	struct proc *p;
357 {
358 	register struct iso_node *ip = VTOI(vp);
359 	int mode, error = 0;
360 	extern int prtactive;
361 
362 #ifdef DEBUG
363 	if (prtactive && vp->v_usecount != 0)
364 		vprint("isofs_inactive: pushing active", vp);
365 #endif
366 
367 	ip->i_flag = 0;
368 	/*
369 	 * If we are done with the inode, reclaim it
370 	 * so that it can be reused immediately.
371 	 */
372 
373 	/*
374 	 * Purge symlink entries since they cause problems
375 	 * when cached.  Leave other entries alone since flushing
376 	 * them every time is a major performance hit.
377 	 */
378 	if (vp->v_usecount == 0 && vp->v_type == VLNK) {
379 /*		printf("Flushing symlink entry\n");*/
380 		vgone(vp);
381 	}
382 	return (error);
383 }
384 
385 /*
386  * Reclaim an inode so that it can be used for other purposes.
387  */
388 isofs_reclaim(vp)
389 	register struct vnode *vp;
390 {
391 	register struct iso_node *ip = VTOI(vp);
392 	int i;
393 	extern int prtactive;
394 
395 #ifdef	DEBUG
396 	if (prtactive && vp->v_usecount != 0)
397 		vprint("isofs_reclaim: pushing active", vp);
398 #endif
399 	/*
400 	 * Remove the inode from its hash chain.
401 	 */
402 	remque(ip);
403 	ip->i_forw = ip;
404 	ip->i_back = ip;
405 	/*
406 	 * Purge old data structures associated with the inode.
407 	 */
408 	cache_purge(vp);
409 	if (ip->i_devvp) {
410 		vrele(ip->i_devvp);
411 		ip->i_devvp = 0;
412 	}
413 	ip->i_flag = 0;
414 	return (0);
415 }
416 
417 /*
418  * Lock an inode. If its already locked, set the WANT bit and sleep.
419  */
420 iso_ilock(ip)
421 	register struct iso_node *ip;
422 {
423 
424 	while (ip->i_flag & ILOCKED) {
425 		ip->i_flag |= IWANT;
426 		if (ip->i_spare0 == curproc->p_pid)
427 			panic("locking against myself");
428 		ip->i_spare1 = curproc->p_pid;
429 		(void) tsleep((caddr_t)ip, PINOD, "isolck", 0);
430 	}
431 	ip->i_spare1 = 0;
432 	ip->i_spare0 = curproc->p_pid;
433 	ip->i_flag |= ILOCKED;
434 }
435 
436 /*
437  * Unlock an inode.  If WANT bit is on, wakeup.
438  */
439 iso_iunlock(ip)
440 	register struct iso_node *ip;
441 {
442 
443 #ifdef DEBUG
444 	if ((ip->i_flag & ILOCKED) == 0)
445 		vprint("iso_iunlock: unlocked inode", ITOV(ip));
446 #endif
447 	ip->i_spare0 = 0;
448 	ip->i_flag &= ~ILOCKED;
449 	if (ip->i_flag&IWANT) {
450 		ip->i_flag &= ~IWANT;
451 		wakeup((caddr_t)ip);
452 	}
453 }
454