xref: /titanic_44/usr/src/uts/common/fs/cachefs/cachefs_fscache.c (revision 9dd0f810214fdc8e1af881a9a5c4b6927629ff9e)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <sys/param.h>
29 #include <sys/types.h>
30 #include <sys/systm.h>
31 #include <sys/file.h>
32 #include <sys/cred.h>
33 #include <sys/proc.h>
34 #include <sys/user.h>
35 #include <sys/vfs.h>
36 #include <sys/vnode.h>
37 #include <sys/pathname.h>
38 #include <sys/uio.h>
39 #include <sys/tiuser.h>
40 #include <sys/sysmacros.h>
41 #include <sys/kmem.h>
42 #include <sys/mount.h>
43 #include <sys/ioctl.h>
44 #include <sys/statvfs.h>
45 #include <sys/errno.h>
46 #include <sys/debug.h>
47 #include <sys/cmn_err.h>
48 #include <sys/utsname.h>
49 #include <sys/modctl.h>
50 #include <sys/stat.h>
51 #include <sys/fcntl.h>
52 #include <sys/fbuf.h>
53 #include <rpc/types.h>
54 
55 #include <vm/hat.h>
56 #include <vm/as.h>
57 #include <vm/page.h>
58 #include <vm/pvn.h>
59 #include <vm/seg.h>
60 #include <vm/seg_map.h>
61 #include <vm/seg_vn.h>
62 #include <vm/rm.h>
63 #include <sys/fs/cachefs_fs.h>
64 #include <sys/fs/cachefs_dlog.h>
65 #include <sys/fs/cachefs_ioctl.h>
66 
67 /* external references */
68 extern struct cachefsops nopcfsops, strictcfsops, codcfsops;
69 
70 /* forward references */
71 int fscdir_create(cachefscache_t *cachep, char *namep, fscache_t *fscp);
72 int fscdir_find(cachefscache_t *cachep, ino64_t fsid, fscache_t *fscp);
73 static int fscache_info_sync(fscache_t *fscp);
74 
75 struct kmem_cache *cachefs_fscache_cache = NULL;
76 
77 /*
78  * ------------------------------------------------------------------
79  *
80  *		fscache_create
81  *
82  * Description:
83  *	Creates a fscache object.
84  * Arguments:
85  *	cachep		cache to create fscache object for
86  * Returns:
87  *	Returns a fscache object.
88  * Preconditions:
89  *	precond(cachep)
90  */
91 
92 fscache_t *
93 fscache_create(cachefscache_t *cachep)
94 {
95 	fscache_t *fscp;
96 
97 	/* create and initialize the fscache object */
98 	fscp = kmem_cache_alloc(cachefs_fscache_cache, KM_SLEEP);
99 
100 	bzero(fscp, sizeof (*fscp));
101 
102 	mutex_init(&fscp->fs_fslock, NULL, MUTEX_DEFAULT, NULL);
103 	mutex_init(&fscp->fs_idlelock, NULL, MUTEX_DEFAULT, NULL);
104 	mutex_init(&fscp->fs_dlock, NULL, MUTEX_DEFAULT, NULL);
105 	mutex_init(&fscp->fs_cdlock, NULL, MUTEX_DEFAULT, NULL);
106 	cv_init(&fscp->fs_cdwaitcv, NULL, CV_DEFAULT, NULL);
107 
108 	fscp->fs_cache = cachep;
109 	fscp->fs_info.fi_mntflags = CFS_WRITE_AROUND;
110 	fscp->fs_info.fi_popsize = DEF_POP_SIZE;
111 	fscp->fs_info.fi_fgsize = DEF_FILEGRP_SIZE;
112 	fscp->fs_cfsops = &nopcfsops;
113 	fscp->fs_consttype = CFS_FS_CONST_NOCONST;
114 	fscp->fs_acregmin = 30;
115 	fscp->fs_acregmax = 30;
116 	fscp->fs_acdirmin = 30;
117 	fscp->fs_acdirmax = 30;
118 	fscp->fs_cdconnected = CFS_CD_CONNECTED;
119 	fscp->fs_mntpt = NULL;
120 	fscp->fs_hostname = NULL;
121 	fscp->fs_backfsname = NULL;
122 	cachefs_workq_init(&fscp->fs_workq);
123 	return (fscp);
124 }
125 
126 /*
127  * ------------------------------------------------------------------
128  *
129  *		fscache_destroy
130  *
131  * Description:
132  *	Destroys the fscache object.
133  * Arguments:
134  *	fscp	the fscache object to destroy
135  * Returns:
136  * Preconditions:
137  *	precond(fscp)
138  *	precond(fs_ref == 0)
139  */
140 
141 void
142 fscache_destroy(fscache_t *fscp)
143 {
144 	size_t strl;
145 
146 	ASSERT(fscp->fs_ref == 0);
147 
148 	(void) fscache_info_sync(fscp);
149 
150 	if (fscp->fs_mntpt) {
151 		strl = strlen(fscp->fs_mntpt);
152 		if (strl != 0)
153 			kmem_free(fscp->fs_mntpt, strl + 1);
154 	}
155 	if (fscp->fs_hostname) {
156 		strl = strlen(fscp->fs_hostname);
157 		if (strl != 0)
158 			kmem_free(fscp->fs_hostname, strl + 1);
159 	}
160 	if (fscp->fs_backfsname) {
161 		strl = strlen(fscp->fs_backfsname);
162 		if (strl != 0)
163 			kmem_free(fscp->fs_backfsname, strl + 1);
164 	}
165 
166 	/* drop the inum translation table */
167 	if (fscp->fs_inum_size > 0)
168 		cachefs_kmem_free(fscp->fs_inum_trans,
169 		    fscp->fs_inum_size * sizeof (cachefs_inum_trans_t));
170 
171 	/* drop references to the fscache directory */
172 	if (fscp->fs_fscdirvp)
173 		VN_RELE(fscp->fs_fscdirvp);
174 	if (fscp->fs_fsattrdir)
175 		VN_RELE(fscp->fs_fsattrdir);
176 	if (fscp->fs_infovp)
177 		VN_RELE(fscp->fs_infovp);
178 
179 	/* drop logging references */
180 	cachefs_dlog_teardown(fscp);
181 
182 	mutex_destroy(&fscp->fs_fslock);
183 	mutex_destroy(&fscp->fs_idlelock);
184 	mutex_destroy(&fscp->fs_dlock);
185 	mutex_destroy(&fscp->fs_cdlock);
186 	cv_destroy(&fscp->fs_cdwaitcv);
187 
188 	kmem_cache_free(cachefs_fscache_cache, fscp);
189 }
190 
191 /*
192  * ------------------------------------------------------------------
193  *
194  *		fscache_setup
195  *
196  * Description:
197  *	Activates a fscache by associating the fscache object
198  *	with on disk data.
199  *	If the fscache directory of the specified fsid exists then
200  *	it will be used.
201  *	Otherwise a new fscache directory will be created using namep
202  *	and optp with fsid being ignored.  However if namep or optp
203  *	are not NULL or the cache is in NOFILL then this routine fails.
204  * Arguments:
205  *	fscp	the fscache object to activate
206  *	fsid	unique identifier for the cache
207  *	namep	name of the cache
208  *	optp	options for the cache
209  * Returns:
210  *	Returns 0 for success, !0 on failure.
211  * Preconditions:
212  *	precond(fscp)
213  *	precond(the cache must not be in NOCACHE mode)
214  *	precond(the cache must not alread by active)
215  */
216 
217 static int
218 fscache_setup(fscache_t *fscp, ino64_t fsid, char *namep,
219     struct cachefsoptions *optp, ino64_t backfileno, int setflags)
220 {
221 	int error;
222 	cachefscache_t *cachep = fscp->fs_cache;
223 
224 	ASSERT((cachep->c_flags & CACHE_NOCACHE) == 0);
225 
226 	/* see if the fscache directory already exists */
227 	error =	fscdir_find(cachep, fsid, fscp);
228 	if (error) {
229 		/* return error if cannot create the directory */
230 		if ((namep == NULL) || (optp == NULL) ||
231 		    (cachep->c_flags & CACHE_NOFILL)) {
232 			return (error);
233 		}
234 		if (backfileno == 0)
235 			return (EAGAIN);
236 
237 		/* remember the root back fileno for disconnected mounts */
238 		fscp->fs_info.fi_root = backfileno;
239 
240 		/* copy options into the fscache */
241 		fscp->fs_info.fi_mntflags = optp->opt_flags;
242 		fscp->fs_info.fi_popsize = optp->opt_popsize;
243 		fscp->fs_info.fi_fgsize = optp->opt_fgsize;
244 		fscp->fs_flags |= CFS_FS_DIRTYINFO;
245 
246 		/* create the directory */
247 		error = fscdir_create(cachep, namep, fscp);
248 		if (error) {
249 			if (error == ENOSPC)
250 				cmn_err(CE_WARN,
251 				    "CacheFS: not enough space to create %s",
252 				    namep);
253 			else
254 				cmn_err(CE_WARN,
255 				    "CacheFS: error %d creating %s",
256 				    error, namep);
257 			return (error);
258 		}
259 	} else if (optp) {
260 		/* compare the options to make sure they are compatable */
261 		error = fscache_compare_options(fscp, optp);
262 		if (error) {
263 			cmn_err(CE_WARN,
264 				"CacheFS: mount failed, options do not match.");
265 			return (error);
266 		}
267 
268 		/* copy options into the fscache */
269 		fscp->fs_info.fi_mntflags = optp->opt_flags;
270 		fscp->fs_info.fi_popsize = optp->opt_popsize;
271 		fscp->fs_info.fi_fgsize = optp->opt_fgsize;
272 		fscp->fs_flags |= CFS_FS_DIRTYINFO;
273 
274 		/*
275 		 * The fileid of the root of the filesystem can change
276 		 * in NFSv4, so make sure we update the fi_root
277 		 * with the new filenumber.
278 		 */
279 		if (CFS_ISFS_BACKFS_NFSV4(fscp) &&
280 		    fscp->fs_info.fi_root != backfileno) {
281 			fscp->fs_info.fi_root = backfileno;
282 		}
283 	}
284 
285 	if (setflags) {
286 		mutex_enter(&fscp->fs_fslock);
287 		fscp->fs_flags |= CFS_FS_READ;
288 		if ((cachep->c_flags & CACHE_NOFILL) == 0)
289 			fscp->fs_flags |= CFS_FS_WRITE;
290 		mutex_exit(&fscp->fs_fslock);
291 	}
292 
293 	return (0);
294 }
295 
296 /*
297  * ------------------------------------------------------------------
298  *
299  *		fscache_activate
300  *
301  * Description:
302  *	A wrapper routine for fscache_setup, telling it to setup the
303  *	fscache for general use.
304  *
305  */
306 int
307 fscache_activate(fscache_t *fscp, ino64_t fsid, char *namep,
308     struct cachefsoptions *optp, ino64_t backfileno)
309 {
310 	return (fscache_setup(fscp, fsid, namep, optp, backfileno, 1));
311 }
312 
313 /*
314  * ------------------------------------------------------------------
315  *
316  *		fscache_enable
317  *
318  * Description:
319  *	A wrapper routine for fscache_setup, telling it to create a
320  *	fscache that can be used during remount.  In this case the
321  *	fscache flags that allow general use are not yet turned on.
322  *	A later call to fscache_activate_rw will set the flags.
323  *
324  */
325 int
326 fscache_enable(fscache_t *fscp, ino64_t fsid, char *namep,
327     struct cachefsoptions *optp, ino64_t backfileno)
328 {
329 	return (fscache_setup(fscp, fsid, namep, optp, backfileno, 0));
330 }
331 
332 /*
333  * ------------------------------------------------------------------
334  *
335  *		fscache_activate_rw
336  *
337  * Description:
338  *	Makes the fscache both readable and writable.
339  * Arguments:
340  *	fscp		fscache object
341  * Returns:
342  * Preconditions:
343  *	precond(fscp)
344  */
345 
346 void
347 fscache_activate_rw(fscache_t *fscp)
348 {
349 	mutex_enter(&fscp->fs_fslock);
350 	fscp->fs_flags |= (CFS_FS_WRITE|CFS_FS_READ);
351 	mutex_exit(&fscp->fs_fslock);
352 }
353 
354 /*
355  * ------------------------------------------------------------------
356  *
357  *		fscache_hold
358  *
359  * Description:
360  *	Increments the reference count on the fscache object
361  * Arguments:
362  *	fscp		fscache object to incriment reference count on
363  * Returns:
364  * Preconditions:
365  *	precond(fscp)
366  */
367 
368 void
369 fscache_hold(fscache_t *fscp)
370 {
371 	mutex_enter(&fscp->fs_fslock);
372 	fscp->fs_ref++;
373 	ASSERT(fscp->fs_ref > 0);
374 	mutex_exit(&fscp->fs_fslock);
375 }
376 
377 /*
378  * ------------------------------------------------------------------
379  *
380  *		fscache_rele
381  *
382  * Description:
383  *	Decriments the reference count on the fscache object
384  * Arguments:
385  *	fscp		fscache object to decriment reference count on
386  * Returns:
387  * Preconditions:
388  *	precond(fscp)
389  */
390 
391 void
392 fscache_rele(fscache_t *fscp)
393 {
394 	mutex_enter(&fscp->fs_fslock);
395 	ASSERT(fscp->fs_ref > 0);
396 	fscp->fs_ref--;
397 	mutex_exit(&fscp->fs_fslock);
398 }
399 
400 /*
401  * ------------------------------------------------------------------
402  *
403  *		fscache_cnodecnt
404  *
405  * Description:
406  *	Changes the count of number of cnodes on this fscache
407  *	by the specified amount.
408  * Arguments:
409  *	fscp		fscache object to to modify count on
410  *	cnt		amount to adjust by
411  * Returns:
412  *	Returns new count of number of cnodes.
413  * Preconditions:
414  *	precond(fscp)
415  */
416 
417 int
418 fscache_cnodecnt(fscache_t *fscp, int cnt)
419 {
420 	int xx;
421 
422 	mutex_enter(&fscp->fs_fslock);
423 	fscp->fs_cnodecnt += cnt;
424 	ASSERT(fscp->fs_cnodecnt >= 0);
425 	xx = fscp->fs_cnodecnt;
426 	mutex_exit(&fscp->fs_fslock);
427 	return (xx);
428 }
429 
430 /*
431  * ------------------------------------------------------------------
432  *
433  *		fscache_mounted
434  *
435  * Description:
436  *	Called to indicate the the fscache is mounted.
437  * Arguments:
438  *	fscp		fscache object
439  *	cfsvfsp		cachefs vfsp
440  *	backvfsp	vfsp of back file system
441  * Returns:
442  *	Returns 0 for success, -1 if the cache is already mounted.
443  * Preconditions:
444  *	precond(fscp)
445  */
446 
447 int
448 fscache_mounted(fscache_t *fscp, struct vfs *cfsvfsp, struct vfs *backvfsp)
449 {
450 	int error = 0;
451 
452 	mutex_enter(&fscp->fs_fslock);
453 	if (fscp->fs_flags & CFS_FS_MOUNTED) {
454 		error = -1;
455 		goto out;
456 	}
457 
458 	fscp->fs_backvfsp = backvfsp;
459 	fscp->fs_cfsvfsp = cfsvfsp;
460 	gethrestime(&fscp->fs_cod_time);
461 	fscp->fs_flags |= CFS_FS_MOUNTED;
462 
463 	if (CFS_ISFS_SNR(fscp)) {
464 		/*
465 		 * If there is a dlog file present, then we assume the cache
466 		 * was left in disconnected mode.
467 		 * Also if the back file system was not mounted we also
468 		 * start off in disconnected mode.
469 		 */
470 		error = cachefs_dlog_setup(fscp, 0);
471 		if (!error || (backvfsp == NULL)) {
472 			mutex_enter(&fscp->fs_cdlock);
473 			fscp->fs_cdconnected = CFS_CD_DISCONNECTED;
474 			fscp->fs_cdtransition = 0;
475 			cv_broadcast(&fscp->fs_cdwaitcv);
476 			mutex_exit(&fscp->fs_cdlock);
477 		}
478 
479 		/* invalidate any local fileno mappings */
480 		fscp->fs_info.fi_resetfileno++;
481 		fscp->fs_flags |= CFS_FS_DIRTYINFO;
482 
483 		/* if connected, invalidate any local time mappings */
484 		if (backvfsp)
485 			fscp->fs_info.fi_resettimes++;
486 	}
487 
488 		error = 0;
489 
490 	/* set up the consistency mode */
491 	if (fscp->fs_info.fi_mntflags & CFS_NOCONST_MODE) {
492 		fscp->fs_cfsops = &nopcfsops;
493 		fscp->fs_consttype = CFS_FS_CONST_NOCONST;
494 	} else if (fscp->fs_info.fi_mntflags & CFS_CODCONST_MODE) {
495 		fscp->fs_cfsops = &codcfsops;
496 		fscp->fs_consttype = CFS_FS_CONST_CODCONST;
497 	} else {
498 		fscp->fs_cfsops = &strictcfsops;
499 		fscp->fs_consttype = CFS_FS_CONST_STRICT;
500 	}
501 
502 out:
503 	mutex_exit(&fscp->fs_fslock);
504 	(void) fscache_info_sync(fscp);
505 	return (error);
506 }
507 
508 /*
509  * Compares fscache state with new mount options
510  * to make sure compatable.
511  * Returns ESRCH if not compatable or 0 for success.
512  */
513 int
514 fscache_compare_options(fscache_t *fscp, struct cachefsoptions *optp)
515 {
516 	if ((fscp->fs_info.fi_popsize == optp->opt_popsize) &&
517 	    (fscp->fs_info.fi_fgsize == optp->opt_fgsize)) {
518 		return (0);
519 	} else {
520 		return (ESRCH);
521 	}
522 }
523 
524 /*
525  * ------------------------------------------------------------------
526  *
527  *		fscache_sync
528  *
529  * Description:
530  *	Syncs any data for this fscache to the front file system.
531  * Arguments:
532  *	fscp	fscache to sync
533  * Returns:
534  * Preconditions:
535  *	precond(fscp)
536  */
537 
538 void
539 fscache_sync(struct fscache *fscp)
540 {
541 	struct filegrp *fgp;
542 	int xx;
543 
544 	(void) fscache_info_sync(fscp);
545 
546 	/* sync the cnodes */
547 	cachefs_cnode_traverse(fscp, cachefs_cnode_sync);
548 
549 	mutex_enter(&fscp->fs_fslock);
550 
551 	/* sync the attrcache files */
552 	for (xx = 0; xx < CFS_FS_FGP_BUCKET_SIZE; xx++) {
553 		for (fgp = fscp->fs_filegrp[xx]; fgp != NULL;
554 			fgp = fgp->fg_next) {
555 			(void) filegrp_sync(fgp);
556 		}
557 	}
558 
559 	/* garbage collect any unused file groups */
560 	filegrp_list_gc(fscp);
561 
562 	mutex_exit(&fscp->fs_fslock);
563 }
564 
565 /*
566  * ------------------------------------------------------------------
567  *
568  *		fscache_acset
569  *
570  * Description:
571  *	Sets the ac timeout values for the fscache.
572  * Arguments:
573  *	fscp	fscache object
574  * Returns:
575  * Preconditions:
576  *	precond(fscp)
577  */
578 
579 void
580 fscache_acset(fscache_t *fscp,
581 	uint_t acregmin, uint_t acregmax, uint_t acdirmin, uint_t acdirmax)
582 {
583 	mutex_enter(&fscp->fs_fslock);
584 	if (acregmin > acregmax)
585 		acregmin = acregmax;
586 	if (acdirmin > acdirmax)
587 		acdirmin = acdirmax;
588 	if (acregmin != 0)
589 		fscp->fs_acregmin = acregmin;
590 	if (acregmax != 0)
591 		fscp->fs_acregmax = acregmax;
592 	if (acdirmin != 0)
593 		fscp->fs_acdirmin = acdirmin;
594 	if (acdirmax != 0)
595 		fscp->fs_acdirmax = acdirmax;
596 	mutex_exit(&fscp->fs_fslock);
597 }
598 
599 /*
600  * ------------------------------------------------------------------
601  *
602  *		fscache_list_find
603  *
604  * Description:
605  *	Finds the desired fscache structure on a cache's
606  *	file system list.
607  * Arguments:
608  *	cachep	holds the list of fscache objects to search
609  *	fsid	the numeric identifier of the fscache
610  * Returns:
611  *	Returns an fscache object on success or NULL on failure.
612  * Preconditions:
613  *	precond(cachep)
614  *	precond(the fslistlock must be held)
615  */
616 
617 fscache_t *
618 fscache_list_find(cachefscache_t *cachep, ino64_t fsid)
619 {
620 	fscache_t *fscp = cachep->c_fslist;
621 
622 	ASSERT(MUTEX_HELD(&cachep->c_fslistlock));
623 
624 	while (fscp != NULL) {
625 		if (fscp->fs_cfsid == fsid) {
626 			ASSERT(fscp->fs_cache == cachep);
627 			break;
628 		}
629 		fscp = fscp->fs_next;
630 	}
631 
632 	return (fscp);
633 }
634 
635 /*
636  * ------------------------------------------------------------------
637  *
638  *		fscache_list_add
639  *
640  * Description:
641  *	Adds the specified fscache object to the list on
642  *	the specified cachep.
643  * Arguments:
644  *	cachep	holds the list of fscache objects
645  *	fscp	fscache object to add to list
646  * Returns:
647  * Preconditions:
648  *	precond(cachep)
649  *	precond(fscp)
650  *	precond(fscp cannot already be on a list)
651  *	precond(the fslistlock must be held)
652  */
653 
654 void
655 fscache_list_add(cachefscache_t *cachep, fscache_t *fscp)
656 {
657 	ASSERT(MUTEX_HELD(&cachep->c_fslistlock));
658 
659 	fscp->fs_next = cachep->c_fslist;
660 	cachep->c_fslist = fscp;
661 	cachep->c_refcnt++;
662 }
663 
664 /*
665  * ------------------------------------------------------------------
666  *
667  *		fscache_list_remove
668  *
669  * Description:
670  *	Removes the specified fscache object from the list
671  *	on the specified cachep.
672  * Arguments:
673  *	cachep	holds the list of fscache objects
674  *	fscp	fscache object to remove from list
675  * Returns:
676  * Preconditions:
677  *	precond(cachep)
678  *	precond(fscp)
679  *	precond(the fslistlock must be held)
680  */
681 
682 void
683 fscache_list_remove(cachefscache_t *cachep, fscache_t *fscp)
684 {
685 	struct fscache **pfscp = &cachep->c_fslist;
686 
687 	ASSERT(MUTEX_HELD(&cachep->c_fslistlock));
688 
689 	while (*pfscp != NULL) {
690 		if (fscp == *pfscp) {
691 			*pfscp = fscp->fs_next;
692 			cachep->c_refcnt--;
693 			break;
694 		}
695 		pfscp = &(*pfscp)->fs_next;
696 	}
697 }
698 
699 /*
700  * ------------------------------------------------------------------
701  *
702  *		fscache_list_gc
703  *
704  * Description:
705  *	Traverses the list of fscache objects on the cachep
706  *	list and destroys any that are not mounted and
707  *	that are not referenced.
708  * Arguments:
709  *	cachep	holds the list of fscache objects
710  * Returns:
711  * Preconditions:
712  *	precond(cachep)
713  *	precond(the fslistlock must be held)
714  */
715 
716 void
717 fscache_list_gc(cachefscache_t *cachep)
718 {
719 	struct fscache *next, *fscp;
720 
721 	ASSERT(MUTEX_HELD(&cachep->c_fslistlock));
722 
723 	for (fscp = cachep->c_fslist; fscp != NULL; fscp = next) {
724 		next = fscp->fs_next;
725 		mutex_enter(&fscp->fs_fslock);
726 		if (((fscp->fs_flags & CFS_FS_MOUNTED) == 0) &&
727 		    (fscp->fs_ref == 0)) {
728 			mutex_exit(&fscp->fs_fslock);
729 			fscache_list_remove(cachep, fscp);
730 			fscache_destroy(fscp);
731 		} else {
732 			mutex_exit(&fscp->fs_fslock);
733 		}
734 	}
735 }
736 
737 /*
738  * ------------------------------------------------------------------
739  *
740  *		fscache_list_mounted
741  *
742  * Description:
743  *	Returns the number of fscache objects that are mounted.
744  * Arguments:
745  *	cachep	holds the list of fscache objects
746  * Returns:
747  * Preconditions:
748  *	precond(cachep)
749  *	precond(the fslistlock must be held)
750  */
751 
752 int
753 fscache_list_mounted(cachefscache_t *cachep)
754 {
755 	struct fscache *fscp;
756 	int count;
757 
758 	ASSERT(MUTEX_HELD(&cachep->c_fslistlock));
759 
760 	count = 0;
761 	for (fscp = cachep->c_fslist; fscp != NULL; fscp = fscp->fs_next) {
762 		mutex_enter(&fscp->fs_fslock);
763 		if (fscp->fs_flags & CFS_FS_MOUNTED)
764 			count++;
765 		mutex_exit(&fscp->fs_fslock);
766 	}
767 
768 	return (count);
769 }
770 
771 /*
772  * Creates the fs cache directory.
773  * The directory name is the ascii version of the fsid.
774  * Also makes a symlink to the directory using the specified name.
775  */
776 int
777 fscdir_create(cachefscache_t *cachep, char *namep, fscache_t *fscp)
778 {
779 	int error;
780 	vnode_t *fscdirvp = NULL;
781 	vnode_t *infovp = NULL;
782 	vnode_t *attrvp = NULL;
783 	struct vattr *attrp = (struct vattr *)NULL;
784 	char name[CFS_FRONTFILE_NAME_SIZE];
785 	int files;
786 	int blocks = 0;
787 	cfs_cid_t cid;
788 	ino64_t fsid;
789 
790 	ASSERT(MUTEX_HELD(&cachep->c_fslistlock));
791 	ASSERT(fscp->fs_infovp == NULL);
792 	ASSERT(fscp->fs_fscdirvp == NULL);
793 	ASSERT(fscp->fs_fsattrdir == NULL);
794 
795 	/* directory, symlink and options file + attrcache dir */
796 	files = 0;
797 	while (files < 4) {
798 		error = cachefs_allocfile(cachep);
799 		if (error)
800 			goto out;
801 		files++;
802 	}
803 	error = cachefs_allocblocks(cachep, 4, CACHEFS_RL_NONE);
804 	if (error)
805 		goto out;
806 	blocks = 4;
807 
808 	attrp = cachefs_kmem_alloc(sizeof (struct vattr), KM_SLEEP);
809 	attrp->va_mode = S_IFDIR | 0777;
810 	attrp->va_uid = 0;
811 	attrp->va_gid = 0;
812 	attrp->va_type = VDIR;
813 	attrp->va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
814 	error = VOP_MKDIR(cachep->c_dirvp, namep, attrp, &fscdirvp, kcred);
815 	if (error) {
816 		cmn_err(CE_WARN, "Can't create fs cache directory");
817 		goto out;
818 	}
819 
820 	/*
821 	 * Created the directory. Get the fileno. That'll be the cachefs_fsid.
822 	 */
823 	attrp->va_mask = AT_NODEID;
824 	error = VOP_GETATTR(fscdirvp, attrp, 0, kcred);
825 	if (error) {
826 		goto out;
827 	}
828 	fsid = attrp->va_nodeid;
829 	attrp->va_mode = S_IFREG | 0666;
830 	attrp->va_uid = 0;
831 	attrp->va_gid = 0;
832 	attrp->va_type = VREG;
833 	attrp->va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
834 	error = VOP_CREATE(fscdirvp, CACHEFS_FSINFO, attrp, EXCL,
835 			0600, &infovp, kcred, 0);
836 	if (error) {
837 		cmn_err(CE_WARN, "Can't create fs option file");
838 		goto out;
839 	}
840 	attrp->va_size = MAXBSIZE;
841 	attrp->va_mask = AT_SIZE;
842 	error = VOP_SETATTR(infovp, attrp, 0, kcred, NULL);
843 	if (error) {
844 		cmn_err(CE_WARN, "Can't set size of fsinfo file");
845 		goto out;
846 	}
847 
848 	/* write out the info file */
849 	fscp->fs_flags |= CFS_FS_DIRTYINFO;
850 	error = fscache_info_sync(fscp);
851 	if (error)
852 		goto out;
853 
854 	/*
855 	 * Install the symlink from cachefs_fsid -> directory.
856 	 */
857 	cid.cid_flags = 0;
858 	cid.cid_fileno = fsid;
859 	make_ascii_name(&cid, name);
860 	error = VOP_RENAME(cachep->c_dirvp, namep, cachep->c_dirvp,
861 		name, kcred);
862 	if (error) {
863 		cmn_err(CE_WARN, "Can't rename cache directory");
864 		goto out;
865 	}
866 	attrp->va_mask = AT_MODE | AT_TYPE;
867 	attrp->va_mode = 0777;
868 	attrp->va_type = VLNK;
869 	error = VOP_SYMLINK(cachep->c_dirvp, namep, attrp, name, kcred);
870 	if (error) {
871 		cmn_err(CE_WARN, "Can't create cache directory symlink");
872 		goto out;
873 	}
874 
875 	/*
876 	 * Finally, make the attrcache directory
877 	 */
878 	attrp->va_mode = S_IFDIR | 0777;
879 	attrp->va_uid = 0;
880 	attrp->va_gid = 0;
881 	attrp->va_type = VDIR;
882 	attrp->va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
883 	error = VOP_MKDIR(fscdirvp, ATTRCACHE_NAME, attrp, &attrvp, kcred);
884 	if (error) {
885 		cmn_err(CE_WARN, "Can't create attrcache dir for fscache");
886 		goto out;
887 	}
888 
889 	mutex_enter(&fscp->fs_fslock);
890 	fscp->fs_cfsid = fsid;
891 	fscp->fs_fscdirvp = fscdirvp;
892 	fscp->fs_fsattrdir = attrvp;
893 	fscp->fs_infovp = infovp;
894 	mutex_exit(&fscp->fs_fslock);
895 
896 out:
897 
898 	if (error) {
899 		while (files-- > 0)
900 			cachefs_freefile(cachep);
901 		if (fscdirvp)
902 			VN_RELE(fscdirvp);
903 		if (blocks)
904 			cachefs_freeblocks(cachep, blocks, CACHEFS_RL_NONE);
905 		if (attrvp)
906 			VN_RELE(attrvp);
907 		if (infovp)
908 			VN_RELE(infovp);
909 	}
910 	if (attrp)
911 		cachefs_kmem_free(attrp, sizeof (struct vattr));
912 	return (error);
913 }
914 
915 /*
916  * Tries to find the fscache directory indicated by fsid.
917  */
918 int
919 fscdir_find(cachefscache_t *cachep, ino64_t fsid, fscache_t *fscp)
920 {
921 	int error;
922 	vnode_t *infovp = NULL;
923 	vnode_t *fscdirvp = NULL;
924 	vnode_t *attrvp = NULL;
925 	char dirname[CFS_FRONTFILE_NAME_SIZE];
926 	cfs_cid_t cid;
927 	cachefs_fsinfo_t fsinfo;
928 	caddr_t addr;
929 
930 	ASSERT(MUTEX_HELD(&cachep->c_fslistlock));
931 	ASSERT(fscp->fs_infovp == NULL);
932 	ASSERT(fscp->fs_fscdirvp == NULL);
933 	ASSERT(fscp->fs_fsattrdir == NULL);
934 
935 	/* convert the fsid value to the name of the directory */
936 	cid.cid_flags = 0;
937 	cid.cid_fileno = fsid;
938 	make_ascii_name(&cid, dirname);
939 
940 	/* try to find the directory */
941 	error = VOP_LOOKUP(cachep->c_dirvp, dirname, &fscdirvp, NULL,
942 			0, NULL, kcred);
943 	if (error)
944 		goto out;
945 
946 	/* this better be a directory or we are hosed */
947 	if (fscdirvp->v_type != VDIR) {
948 		cmn_err(CE_WARN, "cachefs: fscdir_find_a: cache corruption"
949 			" run fsck, %s", dirname);
950 		error = ENOTDIR;
951 		goto out;
952 	}
953 
954 	/* try to find the info file */
955 	error = VOP_LOOKUP(fscdirvp, CACHEFS_FSINFO, &infovp,
956 	    NULL, 0, NULL, kcred);
957 	if (error) {
958 		cmn_err(CE_WARN, "cachefs: fscdir_find_b: cache corruption"
959 			" run fsck, %s", dirname);
960 		goto out;
961 	}
962 
963 	/* read in info struct */
964 	addr = segmap_getmapflt(segkmap, infovp, (offset_t)0,
965 				MAXBSIZE, 1, S_READ);
966 
967 	/*LINTED alignment okay*/
968 	fsinfo = *(cachefs_fsinfo_t *)addr;
969 	error =  segmap_release(segkmap, addr, 0);
970 	if (error) {
971 		cmn_err(CE_WARN, "cachefs: fscdir_find_c: cache corruption"
972 			" run fsck, %s", dirname);
973 		goto out;
974 	}
975 
976 	/* try to find the attrcache directory */
977 	error = VOP_LOOKUP(fscdirvp, ATTRCACHE_NAME,
978 	    &attrvp, NULL, 0, NULL, kcred);
979 	if (error) {
980 		cmn_err(CE_WARN, "cachefs: fscdir_find_d: cache corruption"
981 			" run fsck, %s", dirname);
982 		goto out;
983 	}
984 
985 	mutex_enter(&fscp->fs_fslock);
986 	fscp->fs_info = fsinfo;
987 	fscp->fs_cfsid = fsid;
988 	fscp->fs_fscdirvp = fscdirvp;
989 	fscp->fs_fsattrdir = attrvp;
990 	fscp->fs_infovp = infovp;
991 	mutex_exit(&fscp->fs_fslock);
992 
993 out:
994 	if (error) {
995 		if (infovp)
996 			VN_RELE(infovp);
997 		if (fscdirvp)
998 			VN_RELE(fscdirvp);
999 	}
1000 	return (error);
1001 }
1002 
1003 /*
1004  * fscache_info_sync
1005  * Writes out the fs_info data if necessary.
1006  */
1007 static int
1008 fscache_info_sync(fscache_t *fscp)
1009 {
1010 	caddr_t addr;
1011 	int error = 0;
1012 
1013 	mutex_enter(&fscp->fs_fslock);
1014 
1015 	if (fscp->fs_cache->c_flags & CACHE_NOFILL) {
1016 		error = EROFS;
1017 		goto out;
1018 	}
1019 
1020 	/* if the data is dirty and we have the file vnode */
1021 	if ((fscp->fs_flags & CFS_FS_DIRTYINFO) && fscp->fs_infovp) {
1022 		addr = segmap_getmapflt(segkmap, fscp->fs_infovp, 0,
1023 					MAXBSIZE, 1, S_WRITE);
1024 
1025 		/*LINTED alignment okay*/
1026 		*(cachefs_fsinfo_t *)addr = fscp->fs_info;
1027 		error = segmap_release(segkmap, addr, SM_WRITE);
1028 
1029 		if (error) {
1030 			cmn_err(CE_WARN,
1031 			    "cachefs: Can not write to info file.");
1032 		} else {
1033 			fscp->fs_flags &= ~CFS_FS_DIRTYINFO;
1034 		}
1035 	}
1036 
1037 out:
1038 
1039 	mutex_exit(&fscp->fs_fslock);
1040 
1041 	return (error);
1042 }
1043 
1044 /*
1045  * ------------------------------------------------------------------
1046  *
1047  *		fscache_name_to_fsid
1048  *
1049  * Description:
1050  *	Takes the name of a cache and determines it corresponding
1051  *	fsid.
1052  * Arguments:
1053  *	cachep	cache object to find name of fs cache in
1054  *	namep	the name of the fs cache
1055  *	fsidp	set to the fsid if found
1056  * Returns:
1057  *	Returns 0 on success, !0 on error.
1058  * Preconditions:
1059  *	precond(cachep)
1060  *	precond(namep)
1061  *	precond(fsidp)
1062  */
1063 
1064 int
1065 fscache_name_to_fsid(cachefscache_t *cachep, char *namep, ino64_t *fsidp)
1066 {
1067 	int error;
1068 	char dirname[CFS_FRONTFILE_NAME_SIZE];
1069 	vnode_t *linkvp = NULL;
1070 	struct uio uio;
1071 	struct iovec iov;
1072 	ino64_t nodeid;
1073 	char *pd;
1074 	int xx;
1075 	int c;
1076 
1077 	/* get the vnode of the name */
1078 	error = VOP_LOOKUP(cachep->c_dirvp, namep, &linkvp, NULL, 0, NULL,
1079 		kcred);
1080 	if (error)
1081 		goto out;
1082 
1083 	/* the vnode had better be a link */
1084 	if (linkvp->v_type != VLNK) {
1085 		error = EINVAL;
1086 		goto out;
1087 	}
1088 
1089 	/* read the contents of the link */
1090 	iov.iov_len = CFS_FRONTFILE_NAME_SIZE;
1091 	iov.iov_base = dirname;
1092 	uio.uio_iov = &iov;
1093 	uio.uio_iovcnt = 1;
1094 	uio.uio_resid = iov.iov_len;
1095 	uio.uio_segflg = UIO_SYSSPACE;
1096 	uio.uio_loffset = 0;
1097 	uio.uio_fmode = 0;
1098 	uio.uio_extflg = UIO_COPY_CACHED;
1099 	error = VOP_READLINK(linkvp, &uio, kcred);
1100 	if (error) {
1101 		cmn_err(CE_WARN, "cachefs: Can't read filesystem cache link");
1102 		goto out;
1103 	}
1104 
1105 	/* convert the contents of the link to a ino64_t */
1106 	nodeid = 0;
1107 	pd = dirname;
1108 	for (xx = 0; xx < (CFS_FRONTFILE_NAME_SIZE - 2); xx++) {
1109 		nodeid <<= 4;
1110 		c = *pd++;
1111 		if (c <= '9')
1112 			c -= '0';
1113 		else if (c <= 'F')
1114 			c = c - 'A' + 10;
1115 		else
1116 			c = c - 'a' + 10;
1117 		nodeid += c;
1118 	}
1119 	*fsidp = nodeid;
1120 out:
1121 	if (linkvp)
1122 		VN_RELE(linkvp);
1123 
1124 	return (error);
1125 }
1126 
1127 
1128 /*
1129  * Suspends the thread until access to the cache is granted.
1130  * If !SOFT then
1131  *	waitconnected == 1 means wait until connected
1132  *	waitconnected == 0 means wait until connected or disconnected
1133  * else then
1134  *	wait until connected or disconnected
1135  * writing is set to 1 if writing, 0 if reading
1136  * Returns 0, EINTR, or ETIMEDOUT.
1137  */
1138 int
1139 cachefs_cd_access(fscache_t *fscp, int waitconnected, int writing)
1140 {
1141 	int nosig;
1142 	int error = 0;
1143 	cachefscache_t *cachep;
1144 	int waithappens = 0;
1145 	pid_t pid;
1146 
1147 	mutex_enter(&fscp->fs_cdlock);
1148 
1149 #ifdef CFS_CD_DEBUG
1150 	ASSERT((curthread->t_flag & T_CD_HELD) == 0);
1151 #endif
1152 
1153 	for (;;) {
1154 		/* if we have to wait */
1155 		if (waithappens ||
1156 		    (waitconnected &&
1157 		    (fscp->fs_cdconnected != CFS_CD_CONNECTED))) {
1158 
1159 			/* do not make soft mounts wait until connected */
1160 			if ((waithappens == 0) && CFS_ISFS_SOFT(fscp)) {
1161 				error = ETIMEDOUT;
1162 				break;
1163 			}
1164 
1165 			/* wait for a wakeup or a signal */
1166 			nosig = cv_wait_sig(&fscp->fs_cdwaitcv,
1167 			    &fscp->fs_cdlock);
1168 
1169 			/* if we got a signal */
1170 			if (nosig == 0) {
1171 				error = EINTR;
1172 				break;
1173 			}
1174 
1175 			if (waitconnected &&
1176 			    (fscp->fs_cdconnected == CFS_CD_CONNECTED))
1177 				waitconnected = 0;
1178 
1179 			/* try again to get access */
1180 			waithappens = 0;
1181 			continue;
1182 		}
1183 
1184 		/* if transitioning modes */
1185 		if (fscp->fs_cdtransition) {
1186 			waithappens = 1;
1187 			continue;
1188 		}
1189 
1190 		/* if rolling the log */
1191 		if (fscp->fs_cdconnected == CFS_CD_RECONNECTING) {
1192 			pid = ttoproc(curthread)->p_pid;
1193 			cachep = fscp->fs_cache;
1194 
1195 			/* if writing or not the cachefsd */
1196 			if (writing ||
1197 			    ((fscp->fs_cddaemonid != pid) &&
1198 			    (cachep->c_rootdaemonid != pid))) {
1199 				waithappens = 1;
1200 				continue;
1201 			}
1202 		}
1203 
1204 		/* if the daemon is not running */
1205 		if (fscp->fs_cddaemonid == 0) {
1206 			/* if writing and not connected */
1207 			if (writing &&
1208 			    (fscp->fs_cdconnected != CFS_CD_CONNECTED)) {
1209 				waithappens = 1;
1210 				continue;
1211 			}
1212 		}
1213 
1214 		/*
1215 		 * Verify don't set wait for NFSv4 (doesn't support
1216 		 * disconnected behavior).
1217 		 */
1218 		ASSERT(!CFS_ISFS_BACKFS_NFSV4(fscp) ||
1219 				(waithappens == 0 && waitconnected == 0));
1220 
1221 		ASSERT(fscp->fs_cdrefcnt >= 0);
1222 		fscp->fs_cdrefcnt++;
1223 #ifdef CFS_CD_DEBUG
1224 		curthread->t_flag |= T_CD_HELD;
1225 #endif
1226 		break;
1227 	}
1228 	mutex_exit(&fscp->fs_cdlock);
1229 
1230 	return (error);
1231 }
1232 
1233 /*
1234  * Call to check if can have access after a cache miss has occurred.
1235  * Only read access is allowed, do not call this routine if want
1236  * to write.
1237  * Returns 1 if yes, 0 if no.
1238  */
1239 int
1240 cachefs_cd_access_miss(fscache_t *fscp)
1241 {
1242 	cachefscache_t *cachep;
1243 	pid_t pid;
1244 
1245 #ifdef CFS_CD_DEBUG
1246 	ASSERT(curthread->t_flag & T_CD_HELD);
1247 #endif
1248 
1249 	/* should not get called if connected */
1250 	ASSERT(fscp->fs_cdconnected != CFS_CD_CONNECTED);
1251 
1252 	/* if no back file system, then no */
1253 	if (fscp->fs_backvfsp == NULL)
1254 		return (0);
1255 
1256 	/* if daemon is not running, then yes */
1257 	if (fscp->fs_cddaemonid == 0) {
1258 		return (1);
1259 	}
1260 
1261 	pid = ttoproc(curthread)->p_pid;
1262 	cachep = fscp->fs_cache;
1263 
1264 	/* if daemon is running, only daemon is allowed to have access */
1265 	if ((fscp->fs_cddaemonid != pid) &&
1266 	    (cachep->c_rootdaemonid != pid)) {
1267 		return (0);
1268 	}
1269 
1270 	return (1);
1271 }
1272 
1273 /*
1274  * Releases an access to the file system.
1275  */
1276 void
1277 cachefs_cd_release(fscache_t *fscp)
1278 {
1279 	mutex_enter(&fscp->fs_cdlock);
1280 
1281 #ifdef CFS_CD_DEBUG
1282 	ASSERT(curthread->t_flag & T_CD_HELD);
1283 	curthread->t_flag &= ~T_CD_HELD;
1284 #endif
1285 	/* decriment hold on file system */
1286 	fscp->fs_cdrefcnt--;
1287 	ASSERT(fscp->fs_cdrefcnt >= 0);
1288 
1289 	/* Verify no connected state transitions for NFSv4 */
1290 	ASSERT(!CFS_ISFS_BACKFS_NFSV4(fscp) || fscp->fs_cdtransition == 0);
1291 
1292 	/* wake up cachefsd */
1293 	if ((fscp->fs_cdrefcnt == 0) && fscp->fs_cdtransition)
1294 		cv_broadcast(&fscp->fs_cdwaitcv);
1295 
1296 	mutex_exit(&fscp->fs_cdlock);
1297 }
1298 
1299 /*
1300  * Called when a network timeout error has occurred.
1301  * If connected, switches state to disconnected.
1302  */
1303 void
1304 cachefs_cd_timedout(fscache_t *fscp)
1305 {
1306 	int state;
1307 
1308 	/* nothing to do if not snr or not connected */
1309 	if (!CFS_ISFS_SNR(fscp) || (fscp->fs_cdconnected != CFS_CD_CONNECTED))
1310 		return;
1311 
1312 #ifdef CFS_CD_DEBUG
1313 	ASSERT((curthread->t_flag & T_CD_HELD) == 0);
1314 #endif
1315 
1316 	/* Verify no state changes done for NFSv4 */
1317 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
1318 
1319 	state = CFS_FS_DISCONNECTED;
1320 	(void) cachefs_io_stateset(fscp->fs_rootvp, &state, NULL);
1321 }
1322