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 #include <sys/param.h>
29 #include <sys/types.h>
30 #include <sys/systm.h>
31 #include <sys/cred.h>
32 #include <sys/proc.h>
33 #include <sys/user.h>
34 #include <sys/vfs.h>
35 #include <sys/vfs_opreg.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/stat.h>
46 #include <sys/errno.h>
47 #include <sys/debug.h>
48 #include <sys/cmn_err.h>
49 #include <sys/utsname.h>
50 #include <sys/bootconf.h>
51 #include <sys/reboot.h>
52 #include <sys/modctl.h>
53 #include <rpc/types.h>
54
55 #include <sys/fs/cachefs_fs.h>
56 #include <sys/fs/cachefs_log.h>
57 #include <sys/mkdev.h>
58 #include <sys/dnlc.h>
59 #include <sys/policy.h>
60 #include "fs/fs_subr.h"
61
62 extern kmutex_t cachefs_kmem_lock;
63 kmutex_t cachefs_kstat_key_lock;
64
65 /* forward declarations */
66 static int cachefs_remount(struct vfs *, struct mounta *);
67 static void cachefs_delete_cachep(cachefscache_t *);
68
69 #define CFS_MAPSIZE 256
70
71 kmutex_t cachefs_cachelock; /* Cache list mutex */
72 cachefscache_t *cachefs_cachelist = NULL; /* Cache struct list */
73
74 int cachefs_mount_retries = 3;
75 kmutex_t cachefs_minor_lock; /* Lock for minor device map */
76 major_t cachefs_major = 0;
77 minor_t cachefs_minor = 0;
78 cachefs_kstat_key_t *cachefs_kstat_key = NULL;
79 int cachefs_kstat_key_n = 0;
80 static uint32_t cachefs_nfsv4_warnmsg = FALSE;
81
82 /*
83 * cachefs vfs operations.
84 */
85 static int cachefs_mount(vfs_t *, vnode_t *, struct mounta *, cred_t *);
86 static int cachefs_unmount(vfs_t *, int, cred_t *);
87 static int cachefs_root(vfs_t *, vnode_t **);
88 static int cachefs_statvfs(register vfs_t *, struct statvfs64 *);
89 static int cachefs_sync(vfs_t *, short, cred_t *);
90
91 /*
92 * Initialize the vfs structure
93 */
94 int cachefsfstyp;
95 int cnodesize = 0;
96
97 int
cachefs_init_vfsops(int fstype)98 cachefs_init_vfsops(int fstype)
99 {
100 static const fs_operation_def_t cachefs_vfsops_template[] = {
101 VFSNAME_MOUNT, { .vfs_mount = cachefs_mount },
102 VFSNAME_UNMOUNT, { .vfs_unmount = cachefs_unmount },
103 VFSNAME_ROOT, { .vfs_root = cachefs_root },
104 VFSNAME_STATVFS, { .vfs_statvfs = cachefs_statvfs },
105 VFSNAME_SYNC, { .vfs_sync = cachefs_sync },
106 NULL, NULL
107 };
108 int error;
109
110 error = vfs_setfsops(fstype, cachefs_vfsops_template, NULL);
111 if (error != 0)
112 return (error);
113
114 cachefsfstyp = fstype;
115
116 return (0);
117 }
118
119 dev_t
cachefs_mkmntdev(void)120 cachefs_mkmntdev(void)
121 {
122 dev_t cachefs_dev;
123
124 mutex_enter(&cachefs_minor_lock);
125 do {
126 cachefs_minor = (cachefs_minor + 1) & MAXMIN32;
127 cachefs_dev = makedevice(cachefs_major, cachefs_minor);
128 } while (vfs_devismounted(cachefs_dev));
129 mutex_exit(&cachefs_minor_lock);
130
131 return (cachefs_dev);
132 }
133
134 /*
135 * vfs operations
136 */
137 static int
cachefs_mount(vfs_t * vfsp,vnode_t * mvp,struct mounta * uap,cred_t * cr)138 cachefs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
139 {
140 char *data = uap->dataptr;
141 STRUCT_DECL(cachefs_mountargs, map);
142 struct cachefsoptions *cfs_options;
143 char *backfs, *cacheid, *cachedir;
144 vnode_t *cachedirvp = NULL;
145 vnode_t *backrootvp = NULL;
146 cachefscache_t *cachep = NULL;
147 fscache_t *fscp = NULL;
148 cnode_t *cp;
149 struct fid *cookiep = NULL;
150 struct vattr *attrp = NULL;
151 dev_t cachefs_dev; /* devid for this mount */
152 int error = 0;
153 int retries = cachefs_mount_retries;
154 ino64_t fsid;
155 cfs_cid_t cid;
156 char *backmntpt;
157 ino64_t backfileno;
158 struct vfs *backvfsp;
159 size_t strl;
160 char tmpstr[MAXPATHLEN];
161 vnode_t *tmpdirvp = NULL;
162 ulong_t maxfilesizebits;
163 uint32_t valid_fid;
164
165 #ifdef CFSDEBUG
166 CFS_DEBUG(CFSDEBUG_VFSOP)
167 printf("cachefs_mount: ENTER cachefs_mntargs %p\n", data);
168 #endif
169
170 /*
171 * Make sure we have sufficient privileges.
172 */
173 if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0)
174 goto out;
175
176 /*
177 * make sure we're mounting on a directory
178 */
179 if (mvp->v_type != VDIR) {
180 error = ENOTDIR;
181 goto out;
182 }
183
184 /*
185 * Determine the zone we're being mounted into, and make sure it's the
186 * global zone.
187 */
188 if (getzoneid() == GLOBAL_ZONEID) {
189 zone_t *mntzone;
190
191 mntzone = zone_find_by_path(refstr_value(vfsp->vfs_mntpt));
192 ASSERT(mntzone != NULL);
193 zone_rele(mntzone);
194 if (mntzone != curproc->p_zone) {
195 error = EBUSY;
196 goto out;
197 }
198 } else {
199 error = EPERM;
200 goto out;
201 }
202
203 if (uap->flags & MS_REMOUNT) {
204 error = cachefs_remount(vfsp, uap);
205 goto out;
206 }
207
208 /*
209 * Assign a unique device id to the mount
210 */
211 cachefs_dev = cachefs_mkmntdev();
212 #ifdef _LP64
213 /*
214 * It's not a good idea to make fsid bigger since that'll
215 * have adverse effects on nfs filehandles. For now assume that
216 * cachefs be used on devices that fit into dev32_t's.
217 */
218 if (cachefs_dev == NODEV) {
219 error = EOVERFLOW;
220 goto out;
221 }
222 #endif
223
224 /*
225 * Copy in the arguments
226 */
227 STRUCT_INIT(map, get_udatamodel());
228 error = copyin(data, STRUCT_BUF(map),
229 SIZEOF_STRUCT(cachefs_mountargs, DATAMODEL_NATIVE));
230 if (error) {
231 goto out;
232 }
233
234 cfs_options = (struct cachefsoptions *)STRUCT_FADDR(map, cfs_options);
235 cacheid = (char *)STRUCT_FGETP(map, cfs_cacheid);
236 if ((cfs_options->opt_flags &
237 (CFS_WRITE_AROUND|CFS_NONSHARED|CFS_BACKFS_NFSV4)) == 0) {
238 error = EINVAL;
239 goto out;
240 }
241 if ((cfs_options->opt_popsize % MAXBSIZE) != 0) {
242 error = EINVAL;
243 goto out;
244 }
245 /*
246 * Get the cache directory vp
247 */
248 /*LINTED 32-bit pointer casting okay*/
249 cachedir = (char *)STRUCT_FGETP(map, cfs_cachedir);
250 error = lookupname(cachedir, UIO_USERSPACE, FOLLOW,
251 NULLVPP, &cachedirvp);
252 if (error)
253 goto out;
254
255 /*
256 * Make sure the thing we just looked up is a directory
257 */
258 if (cachedirvp->v_type != VDIR) {
259 cmn_err(CE_WARN, "cachefs_mount: cachedir not a directory\n");
260 error = EINVAL;
261 goto out;
262 }
263
264 /*
265 * Make sure the cache doesn't live in cachefs!
266 */
267 if (vn_matchops(cachedirvp, cachefs_getvnodeops())) {
268 cmn_err(CE_WARN, "cachefs_mount: cachedir in cachefs!\n");
269 error = EINVAL;
270 goto out;
271 }
272
273 /* if the backfs is mounted */
274 /*LINTED 32-bit pointer casting okay*/
275 if ((backfs = STRUCT_FGETP(map, cfs_backfs)) != NULL) {
276 /*
277 * Get the back file system root vp
278 */
279 error = lookupname(backfs, UIO_USERSPACE, FOLLOW,
280 NULLVPP, &backrootvp);
281 if (error)
282 goto out;
283
284 /*
285 * Make sure the thing we just looked up is a directory
286 * and a root of a file system
287 */
288 if (backrootvp->v_type != VDIR ||
289 !(backrootvp->v_flag & VROOT)) {
290 cmn_err(CE_WARN,
291 "cachefs_mount: backpath not a directory\n");
292 error = EINVAL;
293 goto out;
294 }
295
296 /*
297 * Get the fid and attributes for the root of the
298 * backfilesystem, except if NFSv4 is in use,
299 * in which case we get the attributes only (the
300 * (VOP_FID() operation called by cachefs_get_cookie()
301 * is not supported in NFSv4).
302 */
303 cookiep = cachefs_kmem_alloc(sizeof (struct fid), KM_SLEEP);
304 attrp = cachefs_kmem_alloc(sizeof (struct vattr), KM_SLEEP);
305
306 if ((cfs_options->opt_flags & CFS_BACKFS_NFSV4)) {
307 valid_fid = FALSE;
308 } else {
309 valid_fid = TRUE;
310 }
311 error = cachefs_getcookie(backrootvp, cookiep, attrp, cr,
312 valid_fid);
313
314 if (error)
315 goto out;
316
317 backmntpt = backfs;
318 backfileno = attrp->va_nodeid;
319 backvfsp = backrootvp->v_vfsp;
320 } else {
321 backmntpt = NULL;
322 backfileno = 0;
323 backvfsp = NULL;
324 }
325
326 again:
327
328 /*
329 * In SVR4 it's not acceptable to stack up mounts
330 * unless MS_OVERLAY specified.
331 */
332 mutex_enter(&mvp->v_lock);
333 if (((uap->flags & MS_OVERLAY) == 0) &&
334 ((mvp->v_count != 1) || (mvp->v_flag & VROOT))) {
335 mutex_exit(&mvp->v_lock);
336 error = EBUSY;
337 goto out;
338 }
339 mutex_exit(&mvp->v_lock);
340
341 /*
342 * Lock out other mounts and unmounts until we safely have
343 * a mounted fscache object.
344 */
345 mutex_enter(&cachefs_cachelock);
346
347 /*
348 * Find the cache structure
349 */
350 for (cachep = cachefs_cachelist; cachep != NULL;
351 cachep = cachep->c_next) {
352 if (cachep->c_dirvp == cachedirvp)
353 break;
354 }
355
356 /* if the cache object does not exist, then create it */
357 if (cachep == NULL) {
358 cachep = cachefs_cache_create();
359 error = cachefs_cache_activate_ro(cachep, cachedirvp);
360 if (error) {
361 cachefs_cache_destroy(cachep);
362 cachep = NULL;
363 goto out;
364 }
365 if ((cfs_options->opt_flags & CFS_NOFILL) == 0)
366 cachefs_cache_activate_rw(cachep);
367 else
368 cfs_options->opt_flags &= ~CFS_NOFILL;
369
370 cachep->c_next = cachefs_cachelist;
371 cachefs_cachelist = cachep;
372 } else if (cfs_options->opt_flags & CFS_NOFILL) {
373 cmn_err(CE_WARN,
374 "CacheFS: attempt to convert nonempty cache "
375 "to NOFILL mode");
376 error = EINVAL;
377 goto out;
378 }
379
380 /* get the fscache id for this name */
381 error = fscache_name_to_fsid(cachep, cacheid, &fsid);
382 if (error) {
383 fsid = 0;
384 }
385
386 /* find the fscache object for this mount point or create it */
387 mutex_enter(&cachep->c_fslistlock);
388 fscp = fscache_list_find(cachep, fsid);
389 if (fscp == NULL) {
390 fscp = fscache_create(cachep);
391 error = fscache_activate(fscp, fsid, cacheid,
392 cfs_options, backfileno);
393 if (error) {
394 fscache_destroy(fscp);
395 fscp = NULL;
396 mutex_exit(&cachep->c_fslistlock);
397 if ((error == ENOSPC) && (retries-- > 0)) {
398 mutex_exit(&cachefs_cachelock);
399 delay(6 * hz);
400 goto again;
401 }
402 goto out;
403 }
404 fscache_list_add(cachep, fscp);
405 } else {
406 /* compare the options to make sure they are compatible */
407 error = fscache_compare_options(fscp, cfs_options);
408 if (error) {
409 cmn_err(CE_WARN,
410 "CacheFS: mount failed, options do not match.");
411 fscp = NULL;
412 mutex_exit(&cachep->c_fslistlock);
413 goto out;
414 }
415
416 /* copy options into the fscache */
417 mutex_enter(&fscp->fs_fslock);
418 fscp->fs_info.fi_mntflags = cfs_options->opt_flags;
419 fscp->fs_info.fi_popsize = cfs_options->opt_popsize;
420 fscp->fs_info.fi_fgsize = cfs_options->opt_fgsize;
421 fscp->fs_flags |= CFS_FS_DIRTYINFO;
422 mutex_exit(&fscp->fs_fslock);
423 }
424 fscache_hold(fscp);
425
426 error = 0;
427 if (fscp->fs_fscdirvp) {
428 error = VOP_LOOKUP(fscp->fs_fscdirvp, CACHEFS_DLOG_FILE,
429 &tmpdirvp, NULL, 0, NULL, kcred, NULL, NULL, NULL);
430
431 /*
432 * If a log file exists and the cache is being mounted without
433 * the snr (aka disconnectable) option, return an error.
434 */
435 if ((error == 0) &&
436 !(cfs_options->opt_flags & CFS_DISCONNECTABLE)) {
437 mutex_exit(&cachep->c_fslistlock);
438 cmn_err(CE_WARN, "cachefs: log exists and "
439 "disconnectable option not specified\n");
440 error = EINVAL;
441 goto out;
442 }
443 }
444
445 /*
446 * Acquire the name of the mount point
447 */
448 if (fscp->fs_mntpt == NULL) {
449 /*
450 * the string length returned by copystr includes the
451 * terminating NULL character, unless a NULL string is
452 * passed in, then the string length is unchanged.
453 */
454 strl = 0;
455 tmpstr[0] = '\0';
456 (void) copyinstr(uap->dir, tmpstr, MAXPATHLEN, &strl);
457 if (strl > 1) {
458 fscp->fs_mntpt = kmem_alloc(strl, KM_SLEEP);
459 (void) strncpy(fscp->fs_mntpt, tmpstr, strl);
460 }
461 /*
462 * else fscp->fs_mntpt is unchanged(still NULL) try again
463 * next time
464 */
465 }
466
467 /*
468 * Acquire the name of the server
469 */
470 if (fscp->fs_hostname == NULL) {
471 strl = 0;
472 tmpstr[0] = '\0';
473 /*LINTED 32-bit pointer casting okay*/
474 (void) copyinstr((char *)STRUCT_FGETP(map, cfs_hostname),
475 tmpstr, MAXPATHLEN, &strl);
476 if (strl > 1) {
477 fscp->fs_hostname = kmem_alloc(strl, KM_SLEEP);
478 (void) strncpy(fscp->fs_hostname, tmpstr, strl);
479 }
480 /*
481 * else fscp->fs_hostname remains unchanged (is still NULL)
482 */
483 }
484
485 /*
486 * Acquire name of the back filesystem
487 */
488 if (fscp->fs_backfsname == NULL) {
489 strl = 0;
490 tmpstr[0] = '\0';
491 /*LINTED 32-bit pointer casting okay*/
492 (void) copyinstr((char *)STRUCT_FGETP(map, cfs_backfsname),
493 tmpstr, MAXPATHLEN, &strl);
494 if (strl > 1) {
495 fscp->fs_backfsname = kmem_alloc(strl, KM_SLEEP);
496 (void) strncpy(fscp->fs_backfsname, tmpstr, strl);
497 }
498 /*
499 * else fscp->fs_backfsname remains unchanged (is still NULL)
500 */
501 }
502
503 backfileno = fscp->fs_info.fi_root;
504 mutex_exit(&cachep->c_fslistlock);
505
506 /* see if fscache object is already mounted, it not, make it so */
507 error = fscache_mounted(fscp, vfsp, backvfsp);
508 if (error) {
509 /* fs cache was already mounted */
510 error = EBUSY;
511 goto out;
512 }
513
514 cachefs_kstat_mount(fscp, uap->dir, backmntpt, cachedir, cacheid);
515
516 /* set nfs style time out parameters */
517 fscache_acset(fscp, STRUCT_FGET(map, cfs_acregmin),
518 STRUCT_FGET(map, cfs_acregmax),
519 STRUCT_FGET(map, cfs_acdirmin), STRUCT_FGET(map, cfs_acdirmax));
520
521 vfsp->vfs_dev = cachefs_dev;
522 vfsp->vfs_data = (caddr_t)fscp;
523 vfs_make_fsid(&vfsp->vfs_fsid, cachefs_dev, cachefsfstyp);
524 vfsp->vfs_fstype = cachefsfstyp;
525 if (backvfsp)
526 vfsp->vfs_bsize = backvfsp->vfs_bsize;
527 else
528 vfsp->vfs_bsize = MAXBSIZE; /* XXX */
529
530 /* make a cnode for the root of the file system */
531 cid.cid_flags = 0;
532 cid.cid_fileno = backfileno;
533 error = cachefs_cnode_make(&cid, fscp, (valid_fid ? cookiep : NULL),
534 attrp, backrootvp, cr, CN_ROOT, &cp);
535
536 if (error) {
537 cmn_err(CE_WARN, "cachefs_mount: can't create root cnode\n");
538 goto out;
539 }
540
541 /* stick the root cnode in the fscache object */
542 mutex_enter(&fscp->fs_fslock);
543 fscp->fs_rootvp = CTOV(cp);
544 fscp->fs_rootvp->v_flag |= VROOT;
545 fscp->fs_rootvp->v_type |= cp->c_attr.va_type;
546 ASSERT(fscp->fs_rootvp->v_type == VDIR);
547
548 /*
549 * Get the maxfilesize bits of the back file system.
550 */
551
552 error = VOP_PATHCONF(backrootvp, _PC_FILESIZEBITS, &maxfilesizebits,
553 kcred, NULL);
554
555 if (error) {
556 cmn_err(CE_WARN,
557 "cachefs_mount: Can't get the FILESIZEBITS of the back root vnode \n");
558 goto out;
559 }
560
561 fscp->fs_offmax = (1LL << (maxfilesizebits - 1)) - 1;
562 mutex_exit(&fscp->fs_fslock);
563
564 /* remove the unmount file if it is there */
565 (void) VOP_REMOVE(fscp->fs_fscdirvp, CACHEFS_UNMNT_FILE, kcred, NULL,
566 0);
567
568 /* wake up the cache worker if ANY packed pending work */
569 mutex_enter(&cachep->c_contentslock);
570 if (cachep->c_flags & CACHE_PACKED_PENDING)
571 cv_signal(&cachep->c_cwcv);
572 mutex_exit(&cachep->c_contentslock);
573
574 /*
575 * Warn that caching is disabled with NFSv4 first time around.
576 */
577 if (!cachefs_nfsv4_warnmsg && CFS_ISFS_BACKFS_NFSV4(fscp)) {
578 cmn_err(CE_WARN,
579 "Cachefs has detected a mount with NFSv4: caching will"
580 " be disabled for this and other NFSv4 mounts\n");
581 cachefs_nfsv4_warnmsg = TRUE;
582 }
583
584 out:
585 /*
586 * make a log entry, if appropriate
587 */
588
589 if ((cachep != NULL) &&
590 CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_MOUNT))
591 cachefs_log_mount(cachep, error, vfsp, fscp,
592 uap->dir, UIO_USERSPACE,
593 (STRUCT_BUF(map) != NULL) ? cacheid : NULL);
594
595 /*
596 * Cleanup our mess
597 */
598 if (cookiep != NULL)
599 cachefs_kmem_free(cookiep, sizeof (struct fid));
600 if (cachedirvp != NULL)
601 VN_RELE(cachedirvp);
602 if (backrootvp != NULL)
603 VN_RELE(backrootvp);
604 if (fscp)
605 fscache_rele(fscp);
606 if (attrp)
607 cachefs_kmem_free(attrp, sizeof (struct vattr));
608
609 if (error) {
610 if (cachep) {
611 int xx;
612
613 /* lock the cachep's fslist */
614 mutex_enter(&cachep->c_fslistlock);
615
616 /*
617 * gc isn't necessary for list_mounted(), but
618 * we want to do it anyway.
619 */
620
621 fscache_list_gc(cachep);
622 xx = fscache_list_mounted(cachep);
623
624 mutex_exit(&cachep->c_fslistlock);
625
626 /* if no more references to this cachep, punt it. */
627 if (xx == 0)
628 cachefs_delete_cachep(cachep);
629 mutex_exit(&cachefs_cachelock);
630 }
631 } else {
632 mutex_exit(&cachefs_cachelock);
633 }
634
635 #ifdef CFSDEBUG
636 CFS_DEBUG(CFSDEBUG_VFSOP)
637 printf("cachefs_mount: EXIT\n");
638 #endif
639 return (error);
640 }
641
642 void
cachefs_kstat_mount(struct fscache * fscp,char * umountpoint,char * ubackfs,char * ucachedir,char * cacheid)643 cachefs_kstat_mount(struct fscache *fscp,
644 char *umountpoint, char *ubackfs, char *ucachedir, char *cacheid)
645 {
646 cachefscache_t *cachep = fscp->fs_cache;
647 cachefs_kstat_key_t *key;
648 char *mountpoint = NULL, *backfs = NULL, *cachedir = NULL;
649 size_t len;
650 kstat_t *ksp;
651 int i, rc;
652
653 mountpoint = cachefs_kmem_alloc(MAXPATHLEN, KM_SLEEP);
654 if (copyinstr(umountpoint, mountpoint, MAXPATHLEN, &len) != 0)
655 goto out;
656
657 cachedir = cachefs_kmem_alloc(MAXPATHLEN, KM_SLEEP);
658 if (copyinstr(ucachedir, cachedir, MAXPATHLEN, &len) != 0)
659 goto out;
660
661 backfs = cachefs_kmem_alloc(MAXPATHLEN, KM_SLEEP);
662 if (backfs) {
663 if (copyinstr(ubackfs, backfs, MAXPATHLEN, &len) != 0)
664 goto out;
665 } else {
666 (void) strcpy(backfs, "no back file system");
667 }
668
669 ASSERT(strlen(mountpoint) < MAXPATHLEN);
670 ASSERT(strlen(backfs) < MAXPATHLEN);
671 ASSERT(strlen(cachedir) < MAXPATHLEN);
672
673 /* protect cachefs_kstat_key */
674 mutex_enter(&cachefs_kstat_key_lock);
675 /*
676 * XXXX If already there, why not go straight to it?
677 * We know that fscp->fs_kstat_id == i + 1
678 */
679 i = fscp->fs_kstat_id - 1;
680 if ((i >= 0) && (i < cachefs_kstat_key_n))
681 rc = 1;
682 else
683 rc = i = 0;
684 for (; i < cachefs_kstat_key_n; i++) {
685 key = cachefs_kstat_key + i;
686 if (strcmp((char *)(uintptr_t)key->ks_mountpoint,
687 mountpoint) == 0 &&
688 strcmp((char *)(uintptr_t)key->ks_cachedir,
689 cachedir) == 0 &&
690 strcmp((char *)(uintptr_t)key->ks_cacheid, cacheid) == 0)
691 break;
692 if (rc) { /* direct key did not work - check all */
693 i = -1; /* will increment to zero in loop */
694 rc = 0;
695 }
696 }
697
698 if (i >= cachefs_kstat_key_n) {
699 key = cachefs_kmem_alloc((cachefs_kstat_key_n + 1) *
700 sizeof (cachefs_kstat_key_t), KM_SLEEP);
701 if (cachefs_kstat_key != NULL) {
702 bcopy(cachefs_kstat_key, key,
703 cachefs_kstat_key_n * sizeof (*key));
704 cachefs_kmem_free(cachefs_kstat_key,
705 cachefs_kstat_key_n * sizeof (*key));
706 }
707 cachefs_kstat_key = key;
708 key = cachefs_kstat_key + cachefs_kstat_key_n;
709 ++cachefs_kstat_key_n;
710 rc = key->ks_id = cachefs_kstat_key_n; /* offset + 1 */
711
712 key->ks_mountpoint = (uint64_t)(uintptr_t)
713 cachefs_strdup(mountpoint);
714 key->ks_backfs = (uint64_t)(uintptr_t)cachefs_strdup(backfs);
715 key->ks_cachedir = (uint64_t)(uintptr_t)
716 cachefs_strdup(cachedir);
717 key->ks_cacheid = (uint64_t)(uintptr_t)cachefs_strdup(cacheid);
718 } else
719 rc = key->ks_id;
720
721 mutex_enter(&fscp->fs_fslock); /* protect fscp */
722
723 fscp->fs_kstat_id = rc;
724
725 mutex_exit(&fscp->fs_fslock); /* finished with fscp */
726 /* finished cachefs_kstat_key */
727 mutex_exit(&cachefs_kstat_key_lock);
728
729 key->ks_vfsp = (uint64_t)(uintptr_t)fscp->fs_cfsvfsp;
730 key->ks_mounted = 1;
731
732 /*
733 * we must not be holding any mutex that is a ks_lock field
734 * for one of the kstats when we invoke kstat_create,
735 * kstat_install, and friends.
736 */
737 ASSERT(MUTEX_NOT_HELD(&cachefs_kstat_key_lock));
738 /* really should be EVERY cachep's c_log_mutex */
739 ASSERT(MUTEX_NOT_HELD(&cachep->c_log_mutex));
740
741 /* cachefs.#.log */
742 ksp = kstat_create("cachefs", fscp->fs_kstat_id, "log",
743 "misc", KSTAT_TYPE_RAW, 1,
744 KSTAT_FLAG_WRITABLE | KSTAT_FLAG_VIRTUAL);
745 if (ksp != NULL) {
746 ksp->ks_data = cachep->c_log_ctl;
747 ksp->ks_data_size = sizeof (cachefs_log_control_t);
748 ksp->ks_lock = &cachep->c_log_mutex;
749 ksp->ks_snapshot = cachefs_log_kstat_snapshot;
750 kstat_install(ksp);
751 }
752 /* cachefs.#.stats */
753 ksp = kstat_create("cachefs", fscp->fs_kstat_id, "stats",
754 "misc", KSTAT_TYPE_RAW, 1,
755 KSTAT_FLAG_WRITABLE | KSTAT_FLAG_VIRTUAL);
756 if (ksp != NULL) {
757 ksp->ks_data = fscp;
758 ksp->ks_data_size = sizeof (cachefs_stats_t);
759 ksp->ks_snapshot = cachefs_stats_kstat_snapshot;
760 kstat_install(ksp);
761 }
762
763 out:
764 if (mountpoint != NULL)
765 cachefs_kmem_free(mountpoint, MAXPATHLEN);
766 if (backfs != NULL)
767 cachefs_kmem_free(backfs, MAXPATHLEN);
768 if (cachedir != NULL)
769 cachefs_kmem_free(cachedir, MAXPATHLEN);
770 }
771
772 void
cachefs_kstat_umount(int ksid)773 cachefs_kstat_umount(int ksid)
774 {
775 cachefs_kstat_key_t *k = cachefs_kstat_key + (ksid - 1);
776
777 ASSERT(k->ks_id == ksid);
778
779 k->ks_mounted = 0;
780
781 kstat_delete_byname("cachefs", ksid, "stats");
782 kstat_delete_byname("cachefs", ksid, "log");
783 }
784
785 int
cachefs_kstat_key_update(kstat_t * ksp,int rw)786 cachefs_kstat_key_update(kstat_t *ksp, int rw)
787 {
788 cachefs_kstat_key_t *key = *((cachefs_kstat_key_t **)ksp->ks_data);
789 cachefs_kstat_key_t *k;
790 int i;
791
792 if (rw == KSTAT_WRITE)
793 return (EIO);
794 if (key == NULL)
795 return (EIO);
796
797 ksp->ks_data_size = cachefs_kstat_key_n * sizeof (*key);
798 for (i = 0; i < cachefs_kstat_key_n; i++) {
799 k = key + i;
800
801 ksp->ks_data_size +=
802 strlen((char *)(uintptr_t)k->ks_mountpoint) + 1;
803 ksp->ks_data_size +=
804 strlen((char *)(uintptr_t)k->ks_backfs) + 1;
805 ksp->ks_data_size +=
806 strlen((char *)(uintptr_t)k->ks_cachedir) + 1;
807 ksp->ks_data_size +=
808 strlen((char *)(uintptr_t)k->ks_cacheid) + 1;
809 }
810
811 ksp->ks_ndata = cachefs_kstat_key_n;
812
813 return (0);
814 }
815
816 int
cachefs_kstat_key_snapshot(kstat_t * ksp,void * buf,int rw)817 cachefs_kstat_key_snapshot(kstat_t *ksp, void *buf, int rw)
818 {
819 cachefs_kstat_key_t *key = *((cachefs_kstat_key_t **)ksp->ks_data);
820 cachefs_kstat_key_t *k;
821 caddr_t s;
822 int i;
823
824 if (rw == KSTAT_WRITE)
825 return (EIO);
826
827 if (key == NULL)
828 return (0); /* paranoid */
829
830 bcopy(key, buf, cachefs_kstat_key_n * sizeof (*key));
831 key = buf;
832 s = (caddr_t)(key + cachefs_kstat_key_n);
833
834 for (i = 0; i < cachefs_kstat_key_n; i++) {
835 k = key + i;
836
837 (void) strcpy(s, (char *)(uintptr_t)k->ks_mountpoint);
838 k->ks_mountpoint = (uint64_t)(uintptr_t)(s - (uintptr_t)buf);
839 s += strlen(s) + 1;
840 (void) strcpy(s, (char *)(uintptr_t)k->ks_backfs);
841 k->ks_backfs = (uint64_t)(uintptr_t)(s - (uintptr_t)buf);
842 s += strlen(s) + 1;
843 (void) strcpy(s, (char *)(uintptr_t)k->ks_cachedir);
844 k->ks_cachedir = (uint64_t)(uintptr_t)(s - (uintptr_t)buf);
845 s += strlen(s) + 1;
846 (void) strcpy(s, (char *)(uintptr_t)k->ks_cacheid);
847 k->ks_cacheid = (uint64_t)(uintptr_t)(s - (uintptr_t)buf);
848 s += strlen(s) + 1;
849 }
850
851 return (0);
852 }
853
854 extern void cachefs_inactivate();
855
856 static int
cachefs_unmount(vfs_t * vfsp,int flag,cred_t * cr)857 cachefs_unmount(vfs_t *vfsp, int flag, cred_t *cr)
858 {
859 fscache_t *fscp = VFS_TO_FSCACHE(vfsp);
860 struct cachefscache *cachep = fscp->fs_cache;
861 int error;
862 int xx;
863 vnode_t *nmvp;
864 struct vattr attr;
865
866 #ifdef CFSDEBUG
867 CFS_DEBUG(CFSDEBUG_VFSOP)
868 printf("cachefs_unmount: ENTER fscp %p\n", fscp);
869 #endif
870
871 if ((error = secpolicy_fs_unmount(cr, vfsp)) != 0)
872 goto out;
873
874 /*
875 * forced unmount is not supported by this file system
876 * and thus, ENOTSUP, is being returned.
877 */
878 if (flag & MS_FORCE) {
879 error = ENOTSUP;
880 goto out;
881 }
882 /* if a log file exists don't allow the unmount */
883 if (fscp->fs_dlogfile) {
884 error = EBUSY;
885 goto out;
886 }
887
888 /*
889 * wait for the cache-wide async queue to drain. Someone
890 * here may be trying to sync our fscache...
891 */
892 while (cachefs_async_halt(&fscp->fs_cache->c_workq, 0) == EBUSY) {
893 #ifdef CFSDEBUG
894 CFS_DEBUG(CFSDEBUG_VFSOP)
895 printf("unmount: waiting for cache async queue...\n");
896 #endif
897 }
898
899 error = cachefs_async_halt(&fscp->fs_workq, 1);
900 if (error) {
901 #ifdef CFSDEBUG
902 CFS_DEBUG(CFSDEBUG_VFSOP)
903 printf("cachefs_unmount: "
904 "cachefs_async_halt error %d\n", error);
905 #endif
906 goto out;
907 }
908
909 /*
910 * No active cnodes on this cache && rootvp refcnt == 1
911 */
912 mutex_enter(&fscp->fs_fslock);
913 xx = fscp->fs_cnodecnt - fscp->fs_idlecnt;
914 ASSERT(xx >= 1);
915 if (xx > 1 || fscp->fs_rootvp->v_count != 1) {
916 mutex_exit(&fscp->fs_fslock);
917 #ifdef CFSDEBUG
918 CFS_DEBUG(CFSDEBUG_VFSOP)
919 printf("cachefs_unmount: busy (cnodes active %d, idle "
920 "%d)\n", fscp->fs_cnodecnt, fscp->fs_idlecnt);
921 #endif
922 error = EBUSY;
923 goto out;
924 }
925 mutex_exit(&fscp->fs_fslock);
926
927 /* get rid of anything on the idle list */
928 ASSERT(fscp->fs_idleclean == 0);
929 cachefs_cnode_idleclean(fscp, 1);
930 if (fscp->fs_cnodecnt > 1) {
931 #ifdef CFSDEBUG
932 CFS_DEBUG(CFSDEBUG_VFSOP)
933 printf("cachefs_unmount: busy (cnode count %d)\n",
934 fscp->fs_cnodecnt);
935 #endif
936 error = EBUSY;
937 goto out;
938 }
939
940 fscache_hold(fscp);
941
942 /* get rid of the root cnode */
943 if (cachefs_cnode_inactive(fscp->fs_rootvp, cr) == EBUSY) {
944 fscache_rele(fscp);
945 #ifdef CFSDEBUG
946 CFS_DEBUG(CFSDEBUG_VFSOP)
947 printf("cachefs_unmount: busy (inactive failed)\n");
948 #endif
949 error = EBUSY;
950 goto out;
951 }
952
953 /* create the file indicating not mounted */
954 attr.va_mode = S_IFREG | 0666;
955 attr.va_uid = 0;
956 attr.va_gid = 0;
957 attr.va_type = VREG;
958 attr.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
959 if (fscp->fs_fscdirvp != NULL)
960 xx = VOP_CREATE(fscp->fs_fscdirvp, CACHEFS_UNMNT_FILE, &attr,
961 NONEXCL, 0600, &nmvp, kcred, 0, NULL, NULL);
962 else
963 xx = ENOENT; /* for unmounting when NOCACHE */
964 if (xx == 0) {
965 VN_RELE(nmvp);
966 } else {
967 printf("could not create %s %d\n", CACHEFS_UNMNT_FILE, xx);
968 }
969
970 ASSERT(fscp->fs_cnodecnt == 0);
971
972 /* sync the file system just in case */
973 fscache_sync(fscp);
974
975 /* lock out other unmounts and mount */
976 mutex_enter(&cachefs_cachelock);
977
978 /* mark the file system as not mounted */
979 mutex_enter(&fscp->fs_fslock);
980 fscp->fs_flags &= ~CFS_FS_MOUNTED;
981 fscp->fs_rootvp = NULL;
982 if (fscp->fs_kstat_id > 0)
983 cachefs_kstat_umount(fscp->fs_kstat_id);
984 fscp->fs_kstat_id = 0;
985
986 /* drop the inum translation table */
987 if (fscp->fs_inum_size > 0) {
988 cachefs_kmem_free(fscp->fs_inum_trans,
989 fscp->fs_inum_size * sizeof (cachefs_inum_trans_t));
990 fscp->fs_inum_size = 0;
991 fscp->fs_inum_trans = NULL;
992 fscp->fs_flags &= ~CFS_FS_HASHPRINT;
993 }
994 mutex_exit(&fscp->fs_fslock);
995
996 fscache_rele(fscp);
997
998 /* get rid of any unused fscache objects */
999 mutex_enter(&cachep->c_fslistlock);
1000 fscache_list_gc(cachep);
1001 mutex_exit(&cachep->c_fslistlock);
1002
1003 /* get the number of mounts on this cache */
1004 mutex_enter(&cachep->c_fslistlock);
1005 xx = fscache_list_mounted(cachep);
1006 mutex_exit(&cachep->c_fslistlock);
1007
1008 if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_UMOUNT))
1009 cachefs_log_umount(cachep, 0, vfsp);
1010
1011 /* if no mounts left, deactivate the cache */
1012 if (xx == 0)
1013 cachefs_delete_cachep(cachep);
1014
1015 mutex_exit(&cachefs_cachelock);
1016
1017 out:
1018 if (error) {
1019 if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_UMOUNT))
1020 cachefs_log_umount(cachep, error, vfsp);
1021 }
1022 #ifdef CFSDEBUG
1023 CFS_DEBUG(CFSDEBUG_VFSOP)
1024 printf("cachefs_unmount: EXIT\n");
1025 #endif
1026 return (error);
1027 }
1028
1029 /*
1030 * remove the cache from the list of caches
1031 */
1032
1033 static void
cachefs_delete_cachep(cachefscache_t * cachep)1034 cachefs_delete_cachep(cachefscache_t *cachep)
1035 {
1036 struct cachefscache **cachepp;
1037 int found = 0;
1038
1039 ASSERT(MUTEX_HELD(&cachefs_cachelock));
1040
1041 for (cachepp = &cachefs_cachelist;
1042 *cachepp != NULL;
1043 cachepp = &(*cachepp)->c_next) {
1044 if (*cachepp == cachep) {
1045 *cachepp = cachep->c_next;
1046 found++;
1047 break;
1048 }
1049 }
1050 ASSERT(found);
1051
1052 /* shut down the cache */
1053 cachefs_cache_destroy(cachep);
1054 }
1055
1056 static int
cachefs_root(vfs_t * vfsp,vnode_t ** vpp)1057 cachefs_root(vfs_t *vfsp, vnode_t **vpp)
1058 {
1059 /*LINTED alignment okay*/
1060 struct fscache *fscp = (struct fscache *)vfsp->vfs_data;
1061
1062 ASSERT(fscp != NULL);
1063 ASSERT(fscp->fs_rootvp != NULL);
1064
1065 if (getzoneid() != GLOBAL_ZONEID)
1066 return (EPERM);
1067 *vpp = fscp->fs_rootvp;
1068 VN_HOLD(*vpp);
1069 return (0);
1070 }
1071
1072 /*
1073 * Get file system statistics.
1074 */
1075 static int
cachefs_statvfs(register vfs_t * vfsp,struct statvfs64 * sbp)1076 cachefs_statvfs(register vfs_t *vfsp, struct statvfs64 *sbp)
1077 {
1078 struct fscache *fscp = VFS_TO_FSCACHE(vfsp);
1079 struct cache_label *lp = &fscp->fs_cache->c_label;
1080 struct cache_usage *up = &fscp->fs_cache->c_usage;
1081 int error;
1082
1083 if (getzoneid() != GLOBAL_ZONEID)
1084 return (EPERM);
1085 error = cachefs_cd_access(fscp, 0, 0);
1086 if (error)
1087 return (error);
1088
1089 if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
1090 /*
1091 * When connected return backfs stats
1092 */
1093 error = VFS_STATVFS(fscp->fs_backvfsp, sbp);
1094 } else {
1095 /*
1096 * Otherwise, just return the frontfs stats
1097 */
1098 ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
1099 error = VFS_STATVFS(fscp->fs_fscdirvp->v_vfsp, sbp);
1100 if (!error) {
1101 dev32_t d32;
1102
1103 sbp->f_frsize = MAXBSIZE;
1104 sbp->f_blocks = lp->cl_maxblks;
1105 sbp->f_bfree = sbp->f_bavail =
1106 lp->cl_maxblks - up->cu_blksused;
1107 sbp->f_files = lp->cl_maxinodes;
1108 sbp->f_ffree = sbp->f_favail =
1109 lp->cl_maxinodes - up->cu_filesused;
1110 (void) cmpldev(&d32, vfsp->vfs_dev);
1111 sbp->f_fsid = d32;
1112 }
1113 }
1114 cachefs_cd_release(fscp);
1115 if (error)
1116 return (error);
1117
1118 /*
1119 * Make sure fstype is CFS.
1120 */
1121 (void) strcpy(sbp->f_basetype, vfssw[vfsp->vfs_fstype].vsw_name);
1122 bzero(sbp->f_fstr, sizeof (sbp->f_fstr));
1123
1124 return (0);
1125 }
1126
1127 /*
1128 * queue a request to sync the given fscache
1129 */
1130 static void
queue_sync(struct cachefscache * cachep,cred_t * cr)1131 queue_sync(struct cachefscache *cachep, cred_t *cr)
1132 {
1133 struct cachefs_req *rp;
1134
1135 rp = kmem_cache_alloc(cachefs_req_cache, KM_SLEEP);
1136 rp->cfs_cmd = CFS_CACHE_SYNC;
1137 rp->cfs_cr = cr;
1138 rp->cfs_req_u.cu_fs_sync.cf_cachep = cachep;
1139 crhold(rp->cfs_cr);
1140 cachefs_addqueue(rp, &cachep->c_workq);
1141 }
1142
1143 /*ARGSUSED*/
1144 static int
cachefs_sync(vfs_t * vfsp,short flag,cred_t * cr)1145 cachefs_sync(vfs_t *vfsp, short flag, cred_t *cr)
1146 {
1147 struct fscache *fscp;
1148 struct cachefscache *cachep;
1149
1150 if (getzoneid() != GLOBAL_ZONEID)
1151 return (EPERM);
1152 if (!(flag & SYNC_ATTR)) {
1153 /*
1154 * queue an async request to do the sync.
1155 * We always sync an entire cache (as opposed to an
1156 * individual fscache) so that we have an opportunity
1157 * to set the clean flag.
1158 */
1159 if (vfsp) {
1160 /*LINTED alignment okay*/
1161 fscp = (struct fscache *)vfsp->vfs_data;
1162 queue_sync(fscp->fs_cache, cr);
1163 } else {
1164 mutex_enter(&cachefs_cachelock);
1165 for (cachep = cachefs_cachelist; cachep != NULL;
1166 cachep = cachep->c_next) {
1167 queue_sync(cachep, cr);
1168 }
1169 mutex_exit(&cachefs_cachelock);
1170 }
1171 }
1172 return (0);
1173 }
1174
1175 static int
cachefs_remount(struct vfs * vfsp,struct mounta * uap)1176 cachefs_remount(struct vfs *vfsp, struct mounta *uap)
1177 {
1178 fscache_t *fscp = VFS_TO_FSCACHE(vfsp);
1179 cachefscache_t *cachep = fscp->fs_cache;
1180 int error = 0;
1181 STRUCT_DECL(cachefs_mountargs, map);
1182 struct cachefsoptions *cfs_options;
1183 char *backfs, *cacheid, *cachedir;
1184 struct vnode *cachedirvp = NULL;
1185 ino64_t fsid;
1186 vnode_t *backrootvp = NULL;
1187 struct vnode *tmpdirvp = NULL;
1188
1189 STRUCT_INIT(map, get_udatamodel());
1190 error = copyin(uap->dataptr, STRUCT_BUF(map),
1191 SIZEOF_STRUCT(cachefs_mountargs, DATAMODEL_NATIVE));
1192 if (error)
1193 goto out;
1194
1195 /*
1196 * get cache directory vp
1197 */
1198 cachedir = (char *)STRUCT_FGETP(map, cfs_cachedir);
1199 error = lookupname(cachedir, UIO_USERSPACE, FOLLOW,
1200 NULLVPP, &cachedirvp);
1201 if (error)
1202 goto out;
1203 if (cachedirvp->v_type != VDIR) {
1204 error = EINVAL;
1205 goto out;
1206 }
1207
1208 error = 0;
1209 if (cachedirvp) {
1210 error = VOP_LOOKUP(cachedirvp, CACHEFS_DLOG_FILE,
1211 &tmpdirvp, NULL, 0, NULL, kcred, NULL, NULL, NULL);
1212 }
1213 cfs_options = (struct cachefsoptions *)STRUCT_FADDR(map, cfs_options);
1214 cacheid = (char *)STRUCT_FGETP(map, cfs_cacheid);
1215 /* XXX not quite right */
1216 #if 0
1217 /*
1218 * If a log file exists and the cache is being mounted without
1219 * the snr (aka disconnectable) option, return an error.
1220 */
1221 if ((error == 0) &&
1222 !(cfs_options->opt_flags & CFS_DISCONNECTABLE)) {
1223 cmn_err(CE_WARN,
1224 "cachefs_mount: log exists and disconnectable"
1225 "option not specified\n");
1226 error = EINVAL;
1227 goto out;
1228 }
1229 #endif
1230 error = 0;
1231
1232 /*
1233 * If the user is using NFSv4 and there are other options
1234 * specified, make sure we ignore the other options.
1235 */
1236 if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
1237 cfs_options->opt_flags = CFS_BACKFS_NFSV4;
1238 }
1239
1240 /* XXX need mount options "nocache" and "nofill" */
1241
1242 /* if nocache is being turned off */
1243 if (cachep->c_flags & CACHE_NOCACHE) {
1244 error = cachefs_cache_activate_ro(cachep, cachedirvp);
1245 if (error)
1246 goto out;
1247 cachefs_cache_activate_rw(cachep);
1248
1249 /* get the fsid for the fscache */
1250 error = fscache_name_to_fsid(cachep, cacheid, &fsid);
1251 if (error)
1252 fsid = 0;
1253
1254 /* activate the fscache */
1255 mutex_enter(&cachep->c_fslistlock);
1256 error = fscache_enable(fscp, fsid, cacheid,
1257 cfs_options, fscp->fs_info.fi_root);
1258 mutex_exit(&cachep->c_fslistlock);
1259 if (error) {
1260 cmn_err(CE_WARN, "cachefs: cannot remount %s\n",
1261 cacheid);
1262 goto out;
1263 }
1264
1265 /* enable the cache */
1266 cachefs_enable_caching(fscp);
1267 fscache_activate_rw(fscp);
1268 }
1269
1270 /* else if nofill is being turn off */
1271 else if (cachep->c_flags & CACHE_NOFILL) {
1272 ASSERT(cachep->c_flags & CACHE_NOFILL);
1273 cachefs_cache_activate_rw(cachep);
1274
1275 /* enable the cache */
1276 cachefs_enable_caching(fscp);
1277 fscache_activate_rw(fscp);
1278 }
1279
1280 fscache_acset(fscp, STRUCT_FGET(map, cfs_acregmin),
1281 STRUCT_FGET(map, cfs_acregmax),
1282 STRUCT_FGET(map, cfs_acdirmin), STRUCT_FGET(map, cfs_acdirmax));
1283
1284 /* if the backfs is mounted now or we have a new backfs */
1285 backfs = (char *)STRUCT_FGETP(map, cfs_backfs);
1286 if (backfs && (cfs_options->opt_flags & CFS_SLIDE)) {
1287 /* get the back file system root vp */
1288 error = lookupname(backfs, UIO_USERSPACE, FOLLOW,
1289 NULLVPP, &backrootvp);
1290 if (error)
1291 goto out;
1292
1293 /*
1294 * Make sure the thing we just looked up is a directory
1295 * and a root of a file system
1296 */
1297 if (backrootvp->v_type != VDIR ||
1298 !(backrootvp->v_flag & VROOT)) {
1299 cmn_err(CE_WARN,
1300 "cachefs_mount: backpath not a directory\n");
1301 error = EINVAL;
1302 goto out;
1303 }
1304
1305 /*
1306 * XXX
1307 * Kind of dangerous to just set this but we do
1308 * not have locks around usage of fs_backvfsp.
1309 * Hope for the best for now.
1310 * Probably should also spin through vnodes and fix them up.
1311 * Krishna - fixed c_backvp to reflect the change.
1312 */
1313 fscp->fs_backvfsp = backrootvp->v_vfsp;
1314 ((cnode_t *)(fscp->fs_rootvp->v_data))->c_backvp = backrootvp;
1315
1316 /*
1317 * Now the root cnode structure is an owner of
1318 * the opened back root vnode structure; we must
1319 * clear the pointer to back root vnode here as
1320 * we don't need it since now, and the root cnode
1321 * structure will control the vnode
1322 */
1323 backrootvp = (vnode_t *)NULL;
1324 }
1325
1326 if (fscp->fs_kstat_id > 0)
1327 cachefs_kstat_umount(fscp->fs_kstat_id);
1328 fscp->fs_kstat_id = 0;
1329 cachefs_kstat_mount(fscp, uap->dir, backfs, cachedir, cacheid);
1330
1331 if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_MOUNT))
1332 cachefs_log_mount(cachep, error, vfsp, fscp,
1333 uap->dir, UIO_USERSPACE,
1334 (STRUCT_BUF(map) != NULL) ? cacheid : NULL);
1335
1336 out:
1337 if (cachedirvp)
1338 VN_RELE(cachedirvp);
1339 if (backrootvp)
1340 VN_RELE(backrootvp);
1341 return (error);
1342 }
1343