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