xref: /titanic_41/usr/src/uts/common/fs/cachefs/cachefs_vnops.c (revision 0bb073995ac5a95bd35f2dd790df1ea3d8c2d507)
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 2008 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/time.h>
35 #include <sys/vnode.h>
36 #include <sys/vfs.h>
37 #include <sys/vfs_opreg.h>
38 #include <sys/file.h>
39 #include <sys/filio.h>
40 #include <sys/uio.h>
41 #include <sys/buf.h>
42 #include <sys/mman.h>
43 #include <sys/tiuser.h>
44 #include <sys/pathname.h>
45 #include <sys/dirent.h>
46 #include <sys/conf.h>
47 #include <sys/debug.h>
48 #include <sys/vmsystm.h>
49 #include <sys/fcntl.h>
50 #include <sys/flock.h>
51 #include <sys/swap.h>
52 #include <sys/errno.h>
53 #include <sys/sysmacros.h>
54 #include <sys/disp.h>
55 #include <sys/kmem.h>
56 #include <sys/cmn_err.h>
57 #include <sys/vtrace.h>
58 #include <sys/mount.h>
59 #include <sys/bootconf.h>
60 #include <sys/dnlc.h>
61 #include <sys/stat.h>
62 #include <sys/acl.h>
63 #include <sys/policy.h>
64 #include <rpc/types.h>
65 
66 #include <vm/hat.h>
67 #include <vm/as.h>
68 #include <vm/page.h>
69 #include <vm/pvn.h>
70 #include <vm/seg.h>
71 #include <vm/seg_map.h>
72 #include <vm/seg_vn.h>
73 #include <vm/rm.h>
74 #include <sys/fs/cachefs_fs.h>
75 #include <sys/fs/cachefs_dir.h>
76 #include <sys/fs/cachefs_dlog.h>
77 #include <sys/fs/cachefs_ioctl.h>
78 #include <sys/fs/cachefs_log.h>
79 #include <fs/fs_subr.h>
80 
81 int cachefs_dnlc;	/* use dnlc, debugging */
82 
83 static void cachefs_attr_setup(vattr_t *srcp, vattr_t *targp, cnode_t *cp,
84     cred_t *cr);
85 static void cachefs_creategid(cnode_t *dcp, cnode_t *newcp, vattr_t *vap,
86     cred_t *cr);
87 static void cachefs_createacl(cnode_t *dcp, cnode_t *newcp);
88 static int cachefs_getaclfromcache(cnode_t *cp, vsecattr_t *vsec);
89 static int cachefs_getacldirvp(cnode_t *cp);
90 static void cachefs_acl2perm(cnode_t *cp, vsecattr_t *vsec);
91 static int cachefs_access_local(void *cp, int mode, cred_t *cr);
92 static int cachefs_acl_access(struct cnode *cp, int mode, cred_t *cr);
93 static int cachefs_push_connected(vnode_t *vp, struct buf *bp, size_t iolen,
94     u_offset_t iooff, cred_t *cr);
95 static int cachefs_push_front(vnode_t *vp, struct buf *bp, size_t iolen,
96     u_offset_t iooff, cred_t *cr);
97 static int cachefs_setattr_connected(vnode_t *vp, vattr_t *vap, int flags,
98     cred_t *cr, caller_context_t *ct);
99 static int cachefs_setattr_disconnected(vnode_t *vp, vattr_t *vap,
100     int flags, cred_t *cr, caller_context_t *ct);
101 static int cachefs_access_connected(struct vnode *vp, int mode,
102     int flags, cred_t *cr);
103 static int cachefs_lookup_back(vnode_t *dvp, char *nm, vnode_t **vpp,
104     cred_t *cr);
105 static int cachefs_symlink_connected(vnode_t *dvp, char *lnm, vattr_t *tva,
106     char *tnm, cred_t *cr);
107 static int cachefs_symlink_disconnected(vnode_t *dvp, char *lnm,
108     vattr_t *tva, char *tnm, cred_t *cr);
109 static int cachefs_link_connected(vnode_t *tdvp, vnode_t *fvp, char *tnm,
110     cred_t *cr);
111 static int cachefs_link_disconnected(vnode_t *tdvp, vnode_t *fvp,
112     char *tnm, cred_t *cr);
113 static int cachefs_mkdir_connected(vnode_t *dvp, char *nm, vattr_t *vap,
114     vnode_t **vpp, cred_t *cr);
115 static int cachefs_mkdir_disconnected(vnode_t *dvp, char *nm, vattr_t *vap,
116     vnode_t **vpp, cred_t *cr);
117 static int cachefs_stickyrmchk(struct cnode *dcp, struct cnode *cp, cred_t *cr);
118 static int cachefs_rmdir_connected(vnode_t *dvp, char *nm,
119     vnode_t *cdir, cred_t *cr, vnode_t *vp);
120 static int cachefs_rmdir_disconnected(vnode_t *dvp, char *nm,
121     vnode_t *cdir, cred_t *cr, vnode_t *vp);
122 static char *cachefs_newname(void);
123 static int cachefs_remove_dolink(vnode_t *dvp, vnode_t *vp, char *nm,
124     cred_t *cr);
125 static int cachefs_rename_connected(vnode_t *odvp, char *onm,
126     vnode_t *ndvp, char *nnm, cred_t *cr, vnode_t *delvp);
127 static int cachefs_rename_disconnected(vnode_t *odvp, char *onm,
128     vnode_t *ndvp, char *nnm, cred_t *cr, vnode_t *delvp);
129 static int cachefs_readdir_connected(vnode_t *vp, uio_t *uiop, cred_t *cr,
130     int *eofp);
131 static int cachefs_readdir_disconnected(vnode_t *vp, uio_t *uiop,
132     cred_t *cr, int *eofp);
133 static int cachefs_readback_translate(cnode_t *cp, uio_t *uiop,
134 	cred_t *cr, int *eofp);
135 
136 static int cachefs_setattr_common(vnode_t *vp, vattr_t *vap, int flags,
137     cred_t *cr, caller_context_t *ct);
138 
139 static	int	cachefs_open(struct vnode **, int, cred_t *,
140 			caller_context_t *);
141 static	int	cachefs_close(struct vnode *, int, int, offset_t,
142 			cred_t *, caller_context_t *);
143 static	int	cachefs_read(struct vnode *, struct uio *, int, cred_t *,
144 			caller_context_t *);
145 static	int	cachefs_write(struct vnode *, struct uio *, int, cred_t *,
146 			caller_context_t *);
147 static	int	cachefs_ioctl(struct vnode *, int, intptr_t, int, cred_t *,
148 			int *, caller_context_t *);
149 static	int	cachefs_getattr(struct vnode *, struct vattr *, int,
150 			cred_t *, caller_context_t *);
151 static	int	cachefs_setattr(struct vnode *, struct vattr *,
152 			int, cred_t *, caller_context_t *);
153 static	int	cachefs_access(struct vnode *, int, int, cred_t *,
154 			caller_context_t *);
155 static	int	cachefs_lookup(struct vnode *, char *, struct vnode **,
156 			struct pathname *, int, struct vnode *, cred_t *,
157 			caller_context_t *, int *, pathname_t *);
158 static	int	cachefs_create(struct vnode *, char *, struct vattr *,
159 			enum vcexcl, int, struct vnode **, cred_t *, int,
160 			caller_context_t *, vsecattr_t *);
161 static	int	cachefs_create_connected(vnode_t *dvp, char *nm,
162 			vattr_t *vap, enum vcexcl exclusive, int mode,
163 			vnode_t **vpp, cred_t *cr);
164 static	int	cachefs_create_disconnected(vnode_t *dvp, char *nm,
165 			vattr_t *vap, enum vcexcl exclusive, int mode,
166 			vnode_t **vpp, cred_t *cr);
167 static	int	cachefs_remove(struct vnode *, char *, cred_t *,
168 			caller_context_t *, int);
169 static	int	cachefs_link(struct vnode *, struct vnode *, char *,
170 			cred_t *, caller_context_t *, int);
171 static	int	cachefs_rename(struct vnode *, char *, struct vnode *,
172 			char *, cred_t *, caller_context_t *, int);
173 static	int	cachefs_mkdir(struct vnode *, char *, struct
174 			vattr *, struct vnode **, cred_t *, caller_context_t *,
175 			int, vsecattr_t *);
176 static	int	cachefs_rmdir(struct vnode *, char *, struct vnode *,
177 			cred_t *, caller_context_t *, int);
178 static	int	cachefs_readdir(struct vnode *, struct uio *,
179 			cred_t *, int *, caller_context_t *, int);
180 static	int	cachefs_symlink(struct vnode *, char *, struct vattr *,
181 			char *, cred_t *, caller_context_t *, int);
182 static	int	cachefs_readlink(struct vnode *, struct uio *, cred_t *,
183 			caller_context_t *);
184 static int cachefs_readlink_connected(vnode_t *vp, uio_t *uiop, cred_t *cr);
185 static int cachefs_readlink_disconnected(vnode_t *vp, uio_t *uiop);
186 static	int	cachefs_fsync(struct vnode *, int, cred_t *,
187 			caller_context_t *);
188 static	void	cachefs_inactive(struct vnode *, cred_t *, caller_context_t *);
189 static	int	cachefs_fid(struct vnode *, struct fid *, caller_context_t *);
190 static	int	cachefs_rwlock(struct vnode *, int, caller_context_t *);
191 static	void	cachefs_rwunlock(struct vnode *, int, caller_context_t *);
192 static	int	cachefs_seek(struct vnode *, offset_t, offset_t *,
193 			caller_context_t *);
194 static	int	cachefs_frlock(struct vnode *, int, struct flock64 *,
195 			int, offset_t, struct flk_callback *, cred_t *,
196 			caller_context_t *);
197 static	int	cachefs_space(struct vnode *, int, struct flock64 *, int,
198 			offset_t, cred_t *, caller_context_t *);
199 static	int	cachefs_realvp(struct vnode *, struct vnode **,
200 			caller_context_t *);
201 static	int	cachefs_getpage(struct vnode *, offset_t, size_t, uint_t *,
202 			struct page *[], size_t, struct seg *, caddr_t,
203 			enum seg_rw, cred_t *, caller_context_t *);
204 static	int	cachefs_getapage(struct vnode *, u_offset_t, size_t, uint_t *,
205 			struct page *[], size_t, struct seg *, caddr_t,
206 			enum seg_rw, cred_t *);
207 static	int	cachefs_getapage_back(struct vnode *, u_offset_t, size_t,
208 		uint_t *, struct page *[], size_t, struct seg *, caddr_t,
209 			enum seg_rw, cred_t *);
210 static	int	cachefs_putpage(struct vnode *, offset_t, size_t, int,
211 			cred_t *, caller_context_t *);
212 static	int	cachefs_map(struct vnode *, offset_t, struct as *,
213 			caddr_t *, size_t, uchar_t, uchar_t, uint_t, cred_t *,
214 			caller_context_t *);
215 static	int	cachefs_addmap(struct vnode *, offset_t, struct as *,
216 			caddr_t, size_t, uchar_t, uchar_t, uint_t, cred_t *,
217 			caller_context_t *);
218 static	int	cachefs_delmap(struct vnode *, offset_t, struct as *,
219 			caddr_t, size_t, uint_t, uint_t, uint_t, cred_t *,
220 			caller_context_t *);
221 static int	cachefs_setsecattr(vnode_t *vp, vsecattr_t *vsec,
222 			int flag, cred_t *cr, caller_context_t *);
223 static int	cachefs_getsecattr(vnode_t *vp, vsecattr_t *vsec,
224 			int flag, cred_t *cr, caller_context_t *);
225 static	int	cachefs_shrlock(vnode_t *, int, struct shrlock *, int,
226 			cred_t *, caller_context_t *);
227 static int cachefs_getsecattr_connected(vnode_t *vp, vsecattr_t *vsec, int flag,
228     cred_t *cr);
229 static int cachefs_getsecattr_disconnected(vnode_t *vp, vsecattr_t *vsec,
230     int flag, cred_t *cr);
231 
232 static int	cachefs_dump(struct vnode *, caddr_t, offset_t, offset_t,
233 			caller_context_t *);
234 static int	cachefs_pageio(struct vnode *, page_t *,
235 		    u_offset_t, size_t, int, cred_t *, caller_context_t *);
236 static int	cachefs_writepage(struct vnode *vp, caddr_t base,
237 		    int tcount, struct uio *uiop);
238 static int	cachefs_pathconf(vnode_t *, int, ulong_t *, cred_t *,
239 			caller_context_t *);
240 
241 static int	cachefs_read_backfs_nfsv4(vnode_t *vp, uio_t *uiop, int ioflag,
242 			cred_t *cr, caller_context_t *ct);
243 static int	cachefs_write_backfs_nfsv4(vnode_t *vp, uio_t *uiop, int ioflag,
244 			cred_t *cr, caller_context_t *ct);
245 static int	cachefs_getattr_backfs_nfsv4(vnode_t *vp, vattr_t *vap,
246 			int flags, cred_t *cr, caller_context_t *ct);
247 static int	cachefs_remove_backfs_nfsv4(vnode_t *dvp, char *nm, cred_t *cr,
248 			vnode_t *vp);
249 static int	cachefs_getpage_backfs_nfsv4(struct vnode *vp, offset_t off,
250 			size_t len, uint_t *protp, struct page *pl[],
251 			size_t plsz, struct seg *seg, caddr_t addr,
252 			enum seg_rw rw, cred_t *cr);
253 static int	cachefs_putpage_backfs_nfsv4(vnode_t *vp, offset_t off,
254 			size_t len, int flags, cred_t *cr);
255 static int	cachefs_map_backfs_nfsv4(struct vnode *vp, offset_t off,
256 			struct as *as, caddr_t *addrp, size_t len, uchar_t prot,
257 			uchar_t maxprot, uint_t flags, cred_t *cr);
258 static int	cachefs_space_backfs_nfsv4(struct vnode *vp, int cmd,
259 			struct flock64 *bfp, int flag, offset_t offset,
260 			cred_t *cr, caller_context_t *ct);
261 
262 struct vnodeops *cachefs_vnodeops;
263 
264 static const fs_operation_def_t cachefs_vnodeops_template[] = {
265 	VOPNAME_OPEN,		{ .vop_open = cachefs_open },
266 	VOPNAME_CLOSE,		{ .vop_close = cachefs_close },
267 	VOPNAME_READ,		{ .vop_read = cachefs_read },
268 	VOPNAME_WRITE,		{ .vop_write = cachefs_write },
269 	VOPNAME_IOCTL,		{ .vop_ioctl = cachefs_ioctl },
270 	VOPNAME_GETATTR,	{ .vop_getattr = cachefs_getattr },
271 	VOPNAME_SETATTR,	{ .vop_setattr = cachefs_setattr },
272 	VOPNAME_ACCESS,		{ .vop_access = cachefs_access },
273 	VOPNAME_LOOKUP,		{ .vop_lookup = cachefs_lookup },
274 	VOPNAME_CREATE,		{ .vop_create = cachefs_create },
275 	VOPNAME_REMOVE,		{ .vop_remove = cachefs_remove },
276 	VOPNAME_LINK,		{ .vop_link = cachefs_link },
277 	VOPNAME_RENAME,		{ .vop_rename = cachefs_rename },
278 	VOPNAME_MKDIR,		{ .vop_mkdir = cachefs_mkdir },
279 	VOPNAME_RMDIR,		{ .vop_rmdir = cachefs_rmdir },
280 	VOPNAME_READDIR,	{ .vop_readdir = cachefs_readdir },
281 	VOPNAME_SYMLINK,	{ .vop_symlink = cachefs_symlink },
282 	VOPNAME_READLINK,	{ .vop_readlink = cachefs_readlink },
283 	VOPNAME_FSYNC,		{ .vop_fsync = cachefs_fsync },
284 	VOPNAME_INACTIVE,	{ .vop_inactive = cachefs_inactive },
285 	VOPNAME_FID,		{ .vop_fid = cachefs_fid },
286 	VOPNAME_RWLOCK,		{ .vop_rwlock = cachefs_rwlock },
287 	VOPNAME_RWUNLOCK,	{ .vop_rwunlock = cachefs_rwunlock },
288 	VOPNAME_SEEK,		{ .vop_seek = cachefs_seek },
289 	VOPNAME_FRLOCK,		{ .vop_frlock = cachefs_frlock },
290 	VOPNAME_SPACE,		{ .vop_space = cachefs_space },
291 	VOPNAME_REALVP,		{ .vop_realvp = cachefs_realvp },
292 	VOPNAME_GETPAGE,	{ .vop_getpage = cachefs_getpage },
293 	VOPNAME_PUTPAGE,	{ .vop_putpage = cachefs_putpage },
294 	VOPNAME_MAP,		{ .vop_map = cachefs_map },
295 	VOPNAME_ADDMAP,		{ .vop_addmap = cachefs_addmap },
296 	VOPNAME_DELMAP,		{ .vop_delmap = cachefs_delmap },
297 	VOPNAME_DUMP,		{ .vop_dump = cachefs_dump },
298 	VOPNAME_PATHCONF,	{ .vop_pathconf = cachefs_pathconf },
299 	VOPNAME_PAGEIO,		{ .vop_pageio = cachefs_pageio },
300 	VOPNAME_SETSECATTR,	{ .vop_setsecattr = cachefs_setsecattr },
301 	VOPNAME_GETSECATTR,	{ .vop_getsecattr = cachefs_getsecattr },
302 	VOPNAME_SHRLOCK,	{ .vop_shrlock = cachefs_shrlock },
303 	NULL,			NULL
304 };
305 
306 /* forward declarations of statics */
307 static void cachefs_modified(cnode_t *cp);
308 static int cachefs_modified_alloc(cnode_t *cp);
309 
310 int
311 cachefs_init_vnops(char *name)
312 {
313 	return (vn_make_ops(name,
314 	    cachefs_vnodeops_template, &cachefs_vnodeops));
315 }
316 
317 struct vnodeops *
318 cachefs_getvnodeops(void)
319 {
320 	return (cachefs_vnodeops);
321 }
322 
323 static int
324 cachefs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
325 {
326 	int error = 0;
327 	cnode_t *cp = VTOC(*vpp);
328 	fscache_t *fscp = C_TO_FSCACHE(cp);
329 	int held = 0;
330 	int type;
331 	int connected = 0;
332 
333 #ifdef CFSDEBUG
334 	CFS_DEBUG(CFSDEBUG_VOPS)
335 		printf("cachefs_open: ENTER vpp %p flag %x\n",
336 		    (void *)vpp, flag);
337 #endif
338 	if (getzoneid() != GLOBAL_ZONEID) {
339 		error = EPERM;
340 		goto out;
341 	}
342 	if ((flag & FWRITE) &&
343 	    ((*vpp)->v_type == VDIR || (*vpp)->v_type == VLNK)) {
344 		error = EISDIR;
345 		goto out;
346 	}
347 
348 	/*
349 	 * Cachefs only provides pass-through support for NFSv4,
350 	 * and all vnode operations are passed through to the
351 	 * back file system. For NFSv4 pass-through to work, only
352 	 * connected operation is supported, the cnode backvp must
353 	 * exist, and cachefs optional (eg., disconnectable) flags
354 	 * are turned off. Assert these conditions to ensure that
355 	 * the backfilesystem is called for the open operation.
356 	 */
357 	CFS_BACKFS_NFSV4_ASSERT_FSCACHE(fscp);
358 	CFS_BACKFS_NFSV4_ASSERT_CNODE(cp);
359 
360 	for (;;) {
361 		/* get (or renew) access to the file system */
362 		if (held) {
363 			/* Won't loop with NFSv4 connected behavior */
364 			ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
365 			cachefs_cd_release(fscp);
366 			held = 0;
367 		}
368 		error = cachefs_cd_access(fscp, connected, 0);
369 		if (error)
370 			goto out;
371 		held = 1;
372 
373 		mutex_enter(&cp->c_statelock);
374 
375 		/* grab creds if we do not have any yet */
376 		if (cp->c_cred == NULL) {
377 			crhold(cr);
378 			cp->c_cred = cr;
379 		}
380 		cp->c_flags |= CN_NEEDOPEN;
381 
382 		/* if we are disconnected */
383 		if (fscp->fs_cdconnected != CFS_CD_CONNECTED) {
384 			/* if we cannot write to the file system */
385 			if ((flag & FWRITE) && CFS_ISFS_WRITE_AROUND(fscp)) {
386 				mutex_exit(&cp->c_statelock);
387 				connected = 1;
388 				continue;
389 			}
390 			/*
391 			 * Allow read only requests to continue
392 			 */
393 			if ((flag & (FWRITE|FREAD)) == FREAD) {
394 				/* track the flag for opening the backvp */
395 				cp->c_rdcnt++;
396 				mutex_exit(&cp->c_statelock);
397 				error = 0;
398 				break;
399 			}
400 
401 			/*
402 			 * check credentials  - if this procs
403 			 * credentials don't match the creds in the
404 			 * cnode disallow writing while disconnected.
405 			 */
406 			if (crcmp(cp->c_cred, CRED()) != 0 &&
407 			    secpolicy_vnode_access(CRED(), *vpp,
408 			    cp->c_attr.va_uid, VWRITE) != 0) {
409 				mutex_exit(&cp->c_statelock);
410 				connected = 1;
411 				continue;
412 			}
413 			/* to get here, we know that the WRITE flag is on */
414 			cp->c_wrcnt++;
415 			if (flag & FREAD)
416 				cp->c_rdcnt++;
417 		}
418 
419 		/* else if we are connected */
420 		else {
421 			/* if cannot use the cached copy of the file */
422 			if ((flag & FWRITE) && CFS_ISFS_WRITE_AROUND(fscp) &&
423 			    ((cp->c_flags & CN_NOCACHE) == 0))
424 				cachefs_nocache(cp);
425 
426 			/* pass open to the back file */
427 			if (cp->c_backvp) {
428 				cp->c_flags &= ~CN_NEEDOPEN;
429 				CFS_DPRINT_BACKFS_NFSV4(fscp,
430 				    ("cachefs_open (nfsv4): cnode %p, "
431 				    "backvp %p\n", cp, cp->c_backvp));
432 				error = VOP_OPEN(&cp->c_backvp, flag, cr, ct);
433 				if (CFS_TIMEOUT(fscp, error)) {
434 					mutex_exit(&cp->c_statelock);
435 					cachefs_cd_release(fscp);
436 					held = 0;
437 					cachefs_cd_timedout(fscp);
438 					continue;
439 				} else if (error) {
440 					mutex_exit(&cp->c_statelock);
441 					break;
442 				}
443 			} else {
444 				/* backvp will be VOP_OPEN'd later */
445 				if (flag & FREAD)
446 					cp->c_rdcnt++;
447 				if (flag & FWRITE)
448 					cp->c_wrcnt++;
449 			}
450 
451 			/*
452 			 * Now perform a consistency check on the file.
453 			 * If strict consistency then force a check to
454 			 * the backfs even if the timeout has not expired
455 			 * for close-to-open consistency.
456 			 */
457 			type = 0;
458 			if (fscp->fs_consttype == CFS_FS_CONST_STRICT)
459 				type = C_BACK_CHECK;
460 			error = CFSOP_CHECK_COBJECT(fscp, cp, type, cr);
461 			if (CFS_TIMEOUT(fscp, error)) {
462 				mutex_exit(&cp->c_statelock);
463 				cachefs_cd_release(fscp);
464 				held = 0;
465 				cachefs_cd_timedout(fscp);
466 				continue;
467 			}
468 		}
469 		mutex_exit(&cp->c_statelock);
470 		break;
471 	}
472 	if (held)
473 		cachefs_cd_release(fscp);
474 out:
475 #ifdef CFS_CD_DEBUG
476 	ASSERT((curthread->t_flag & T_CD_HELD) == 0);
477 #endif
478 #ifdef CFSDEBUG
479 	CFS_DEBUG(CFSDEBUG_VOPS)
480 		printf("cachefs_open: EXIT vpp %p error %d\n",
481 		    (void *)vpp, error);
482 #endif
483 	return (error);
484 }
485 
486 /* ARGSUSED */
487 static int
488 cachefs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
489 	caller_context_t *ct)
490 {
491 	int error = 0;
492 	cnode_t *cp = VTOC(vp);
493 	fscache_t *fscp = C_TO_FSCACHE(cp);
494 	int held = 0;
495 	int connected = 0;
496 	int close_cnt = 1;
497 	cachefscache_t *cachep;
498 
499 #ifdef CFSDEBUG
500 	CFS_DEBUG(CFSDEBUG_VOPS)
501 		printf("cachefs_close: ENTER vp %p\n", (void *)vp);
502 #endif
503 	/*
504 	 * Cachefs only provides pass-through support for NFSv4,
505 	 * and all vnode operations are passed through to the
506 	 * back file system. For NFSv4 pass-through to work, only
507 	 * connected operation is supported, the cnode backvp must
508 	 * exist, and cachefs optional (eg., disconnectable) flags
509 	 * are turned off. Assert these conditions to ensure that
510 	 * the backfilesystem is called for the close operation.
511 	 */
512 	CFS_BACKFS_NFSV4_ASSERT_FSCACHE(fscp);
513 	CFS_BACKFS_NFSV4_ASSERT_CNODE(cp);
514 
515 	/*
516 	 * File could have been passed in or inherited from the global zone, so
517 	 * we don't want to flat out reject the request; we'll just leave things
518 	 * the way they are and let the backfs (NFS) deal with it.
519 	 */
520 	/* get rid of any local locks */
521 	if (CFS_ISFS_LLOCK(fscp)) {
522 		(void) cleanlocks(vp, ttoproc(curthread)->p_pid, 0);
523 	}
524 
525 	/* clean up if this is the daemon closing down */
526 	if ((fscp->fs_cddaemonid == ttoproc(curthread)->p_pid) &&
527 	    ((ttoproc(curthread)->p_pid) != 0) &&
528 	    (vp == fscp->fs_rootvp) &&
529 	    (count == 1)) {
530 		mutex_enter(&fscp->fs_cdlock);
531 		fscp->fs_cddaemonid = 0;
532 		if (fscp->fs_dlogfile)
533 			fscp->fs_cdconnected = CFS_CD_DISCONNECTED;
534 		else
535 			fscp->fs_cdconnected = CFS_CD_CONNECTED;
536 		cv_broadcast(&fscp->fs_cdwaitcv);
537 		mutex_exit(&fscp->fs_cdlock);
538 		if (fscp->fs_flags & CFS_FS_ROOTFS) {
539 			cachep = fscp->fs_cache;
540 			mutex_enter(&cachep->c_contentslock);
541 			ASSERT(cachep->c_rootdaemonid != 0);
542 			cachep->c_rootdaemonid = 0;
543 			mutex_exit(&cachep->c_contentslock);
544 		}
545 		return (0);
546 	}
547 
548 	for (;;) {
549 		/* get (or renew) access to the file system */
550 		if (held) {
551 			/* Won't loop with NFSv4 connected behavior */
552 			ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
553 			cachefs_cd_release(fscp);
554 			held = 0;
555 		}
556 		error = cachefs_cd_access(fscp, connected, 0);
557 		if (error)
558 			goto out;
559 		held = 1;
560 		connected = 0;
561 
562 		/* if not the last close */
563 		if (count > 1) {
564 			if (fscp->fs_cdconnected != CFS_CD_CONNECTED)
565 				goto out;
566 			mutex_enter(&cp->c_statelock);
567 			if (cp->c_backvp) {
568 				CFS_DPRINT_BACKFS_NFSV4(fscp,
569 				    ("cachefs_close (nfsv4): cnode %p, "
570 				    "backvp %p\n", cp, cp->c_backvp));
571 				error = VOP_CLOSE(cp->c_backvp, flag, count,
572 				    offset, cr, ct);
573 				if (CFS_TIMEOUT(fscp, error)) {
574 					mutex_exit(&cp->c_statelock);
575 					cachefs_cd_release(fscp);
576 					held = 0;
577 					cachefs_cd_timedout(fscp);
578 					continue;
579 				}
580 			}
581 			mutex_exit(&cp->c_statelock);
582 			goto out;
583 		}
584 
585 		/*
586 		 * If the file is an unlinked file, then flush the lookup
587 		 * cache so that inactive will be called if this is
588 		 * the last reference.  It will invalidate all of the
589 		 * cached pages, without writing them out.  Writing them
590 		 * out is not required because they will be written to a
591 		 * file which will be immediately removed.
592 		 */
593 		if (cp->c_unldvp != NULL) {
594 			dnlc_purge_vp(vp);
595 			mutex_enter(&cp->c_statelock);
596 			error = cp->c_error;
597 			cp->c_error = 0;
598 			mutex_exit(&cp->c_statelock);
599 			/* always call VOP_CLOSE() for back fs vnode */
600 		}
601 
602 		/* force dirty data to stable storage */
603 		else if ((vp->v_type == VREG) && (flag & FWRITE) &&
604 		    !CFS_ISFS_BACKFS_NFSV4(fscp)) {
605 			/* clean the cachefs pages synchronously */
606 			error = cachefs_putpage_common(vp, (offset_t)0,
607 			    0, 0, cr);
608 			if (CFS_TIMEOUT(fscp, error)) {
609 				if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
610 					cachefs_cd_release(fscp);
611 					held = 0;
612 					cachefs_cd_timedout(fscp);
613 					continue;
614 				} else {
615 					connected = 1;
616 					continue;
617 				}
618 			}
619 
620 			/* if no space left in cache, wait until connected */
621 			if ((error == ENOSPC) &&
622 			    (fscp->fs_cdconnected != CFS_CD_CONNECTED)) {
623 				connected = 1;
624 				continue;
625 			}
626 
627 			/* clear the cnode error if putpage worked */
628 			if ((error == 0) && cp->c_error) {
629 				mutex_enter(&cp->c_statelock);
630 				cp->c_error = 0;
631 				mutex_exit(&cp->c_statelock);
632 			}
633 
634 			/* if any other important error */
635 			if (cp->c_error) {
636 				/* get rid of the pages */
637 				(void) cachefs_putpage_common(vp,
638 				    (offset_t)0, 0, B_INVAL | B_FORCE, cr);
639 				dnlc_purge_vp(vp);
640 			}
641 		}
642 
643 		mutex_enter(&cp->c_statelock);
644 		if (cp->c_backvp &&
645 		    (fscp->fs_cdconnected == CFS_CD_CONNECTED)) {
646 			error = VOP_CLOSE(cp->c_backvp, flag, close_cnt,
647 			    offset, cr, ct);
648 			if (CFS_TIMEOUT(fscp, error)) {
649 				mutex_exit(&cp->c_statelock);
650 				cachefs_cd_release(fscp);
651 				held = 0;
652 				cachefs_cd_timedout(fscp);
653 				/* don't decrement the vnode counts again */
654 				close_cnt = 0;
655 				continue;
656 			}
657 		}
658 		mutex_exit(&cp->c_statelock);
659 		break;
660 	}
661 
662 	mutex_enter(&cp->c_statelock);
663 	if (!error)
664 		error = cp->c_error;
665 	cp->c_error = 0;
666 	mutex_exit(&cp->c_statelock);
667 
668 out:
669 	if (held)
670 		cachefs_cd_release(fscp);
671 #ifdef CFS_CD_DEBUG
672 	ASSERT((curthread->t_flag & T_CD_HELD) == 0);
673 #endif
674 
675 #ifdef CFSDEBUG
676 	CFS_DEBUG(CFSDEBUG_VOPS)
677 		printf("cachefs_close: EXIT vp %p\n", (void *)vp);
678 #endif
679 	return (error);
680 }
681 
682 /*ARGSUSED*/
683 static int
684 cachefs_read(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr,
685 	caller_context_t *ct)
686 {
687 	struct cnode *cp = VTOC(vp);
688 	fscache_t *fscp = C_TO_FSCACHE(cp);
689 	register u_offset_t off;
690 	register int mapoff;
691 	register caddr_t base;
692 	int n;
693 	offset_t diff;
694 	uint_t flags = 0;
695 	int error = 0;
696 
697 #if 0
698 	if (vp->v_flag & VNOCACHE)
699 		flags = SM_INVAL;
700 #endif
701 	if (getzoneid() != GLOBAL_ZONEID)
702 		return (EPERM);
703 	if (vp->v_type != VREG)
704 		return (EISDIR);
705 
706 	ASSERT(RW_READ_HELD(&cp->c_rwlock));
707 
708 	if (uiop->uio_resid == 0)
709 		return (0);
710 
711 
712 	if (uiop->uio_loffset < (offset_t)0)
713 		return (EINVAL);
714 
715 	/*
716 	 * Call backfilesystem to read if NFSv4, the cachefs code
717 	 * does the read from the back filesystem asynchronously
718 	 * which is not supported by pass-through functionality.
719 	 */
720 	if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
721 		error = cachefs_read_backfs_nfsv4(vp, uiop, ioflag, cr, ct);
722 		goto out;
723 	}
724 
725 	if (MANDLOCK(vp, cp->c_attr.va_mode)) {
726 		error = chklock(vp, FREAD, (offset_t)uiop->uio_loffset,
727 		    uiop->uio_resid, uiop->uio_fmode, ct);
728 		if (error)
729 			return (error);
730 	}
731 
732 	/*
733 	 * Sit in a loop and transfer (uiomove) the data in up to
734 	 * MAXBSIZE chunks. Each chunk is mapped into the kernel's
735 	 * address space as needed and then released.
736 	 */
737 	do {
738 		/*
739 		 *	off	Offset of current MAXBSIZE chunk
740 		 *	mapoff	Offset within the current chunk
741 		 *	n	Number of bytes to move from this chunk
742 		 *	base	kernel address of mapped in chunk
743 		 */
744 		off = uiop->uio_loffset & (offset_t)MAXBMASK;
745 		mapoff = uiop->uio_loffset & MAXBOFFSET;
746 		n = MAXBSIZE - mapoff;
747 		if (n > uiop->uio_resid)
748 			n = (uint_t)uiop->uio_resid;
749 
750 		/* perform consistency check */
751 		error = cachefs_cd_access(fscp, 0, 0);
752 		if (error)
753 			break;
754 		mutex_enter(&cp->c_statelock);
755 		error = CFSOP_CHECK_COBJECT(fscp, cp, 0, cr);
756 		diff = cp->c_size - uiop->uio_loffset;
757 		mutex_exit(&cp->c_statelock);
758 		if (CFS_TIMEOUT(fscp, error)) {
759 			cachefs_cd_release(fscp);
760 			cachefs_cd_timedout(fscp);
761 			error = 0;
762 			continue;
763 		}
764 		cachefs_cd_release(fscp);
765 
766 		if (error)
767 			break;
768 
769 		if (diff <= (offset_t)0)
770 			break;
771 		if (diff < (offset_t)n)
772 			n = diff;
773 
774 		base = segmap_getmapflt(segkmap, vp, off, (uint_t)n, 1, S_READ);
775 
776 		error = segmap_fault(kas.a_hat, segkmap, base, n,
777 		    F_SOFTLOCK, S_READ);
778 		if (error) {
779 			(void) segmap_release(segkmap, base, 0);
780 			if (FC_CODE(error) == FC_OBJERR)
781 				error =  FC_ERRNO(error);
782 			else
783 				error = EIO;
784 			break;
785 		}
786 		error = uiomove(base+mapoff, n, UIO_READ, uiop);
787 		(void) segmap_fault(kas.a_hat, segkmap, base, n,
788 		    F_SOFTUNLOCK, S_READ);
789 		if (error == 0) {
790 			/*
791 			 * if we read a whole page(s), or to eof,
792 			 *  we won't need this page(s) again soon.
793 			 */
794 			if (n + mapoff == MAXBSIZE ||
795 			    uiop->uio_loffset == cp->c_size)
796 				flags |= SM_DONTNEED;
797 		}
798 		(void) segmap_release(segkmap, base, flags);
799 	} while (error == 0 && uiop->uio_resid > 0);
800 
801 out:
802 #ifdef CFSDEBUG
803 	CFS_DEBUG(CFSDEBUG_VOPS)
804 		printf("cachefs_read: EXIT error %d resid %ld\n", error,
805 		    uiop->uio_resid);
806 #endif
807 	return (error);
808 }
809 
810 /*
811  * cachefs_read_backfs_nfsv4
812  *
813  * Call NFSv4 back filesystem to handle the read (cachefs
814  * pass-through support for NFSv4).
815  */
816 static int
817 cachefs_read_backfs_nfsv4(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr,
818 			caller_context_t *ct)
819 {
820 	cnode_t *cp = VTOC(vp);
821 	fscache_t *fscp = C_TO_FSCACHE(cp);
822 	vnode_t *backvp;
823 	int error;
824 
825 	/*
826 	 * For NFSv4 pass-through to work, only connected operation
827 	 * is supported, the cnode backvp must exist, and cachefs
828 	 * optional (eg., disconnectable) flags are turned off. Assert
829 	 * these conditions for the read operation.
830 	 */
831 	CFS_BACKFS_NFSV4_ASSERT_FSCACHE(fscp);
832 	CFS_BACKFS_NFSV4_ASSERT_CNODE(cp);
833 
834 	/* Call backfs vnode op after extracting backvp */
835 	mutex_enter(&cp->c_statelock);
836 	backvp = cp->c_backvp;
837 	mutex_exit(&cp->c_statelock);
838 
839 	CFS_DPRINT_BACKFS_NFSV4(fscp, ("cachefs_read_backfs_nfsv4: cnode %p, "
840 	    "backvp %p\n", cp, backvp));
841 
842 	(void) VOP_RWLOCK(backvp, V_WRITELOCK_FALSE, ct);
843 	error = VOP_READ(backvp, uiop, ioflag, cr, ct);
844 	VOP_RWUNLOCK(backvp, V_WRITELOCK_FALSE, ct);
845 
846 	/* Increment cache miss counter */
847 	fscp->fs_stats.st_misses++;
848 
849 	return (error);
850 }
851 
852 /*ARGSUSED*/
853 static int
854 cachefs_write(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr,
855 	caller_context_t *ct)
856 {
857 	struct cnode *cp = VTOC(vp);
858 	fscache_t *fscp = C_TO_FSCACHE(cp);
859 	int error = 0;
860 	u_offset_t off;
861 	caddr_t base;
862 	uint_t bsize;
863 	uint_t flags;
864 	int n, on;
865 	rlim64_t limit = uiop->uio_llimit;
866 	ssize_t resid;
867 	offset_t offset;
868 	offset_t remainder;
869 
870 #ifdef CFSDEBUG
871 	CFS_DEBUG(CFSDEBUG_VOPS)
872 		printf(
873 		"cachefs_write: ENTER vp %p offset %llu count %ld cflags %x\n",
874 		    (void *)vp, uiop->uio_loffset, uiop->uio_resid,
875 		    cp->c_flags);
876 #endif
877 	if (getzoneid() != GLOBAL_ZONEID) {
878 		error = EPERM;
879 		goto out;
880 	}
881 	if (vp->v_type != VREG) {
882 		error = EISDIR;
883 		goto out;
884 	}
885 
886 	ASSERT(RW_WRITE_HELD(&cp->c_rwlock));
887 
888 	if (uiop->uio_resid == 0) {
889 		goto out;
890 	}
891 
892 	/* Call backfilesystem to write if NFSv4 */
893 	if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
894 		error = cachefs_write_backfs_nfsv4(vp, uiop, ioflag, cr, ct);
895 		goto out2;
896 	}
897 
898 	if (MANDLOCK(vp, cp->c_attr.va_mode)) {
899 		error = chklock(vp, FWRITE, (offset_t)uiop->uio_loffset,
900 		    uiop->uio_resid, uiop->uio_fmode, ct);
901 		if (error)
902 			goto out;
903 	}
904 
905 	if (ioflag & FAPPEND) {
906 		for (;;) {
907 			/* do consistency check to get correct file size */
908 			error = cachefs_cd_access(fscp, 0, 1);
909 			if (error)
910 				goto out;
911 			mutex_enter(&cp->c_statelock);
912 			error = CFSOP_CHECK_COBJECT(fscp, cp, 0, cr);
913 			uiop->uio_loffset = cp->c_size;
914 			mutex_exit(&cp->c_statelock);
915 			if (CFS_TIMEOUT(fscp, error)) {
916 				cachefs_cd_release(fscp);
917 				cachefs_cd_timedout(fscp);
918 				continue;
919 			}
920 			cachefs_cd_release(fscp);
921 			if (error)
922 				goto out;
923 			break;
924 		}
925 	}
926 
927 	if (limit == RLIM64_INFINITY || limit > MAXOFFSET_T)
928 		limit = MAXOFFSET_T;
929 
930 	if (uiop->uio_loffset >= limit) {
931 		proc_t *p = ttoproc(curthread);
932 
933 		mutex_enter(&p->p_lock);
934 		(void) rctl_action(rctlproc_legacy[RLIMIT_FSIZE], p->p_rctls,
935 		    p, RCA_UNSAFE_SIGINFO);
936 		mutex_exit(&p->p_lock);
937 		error = EFBIG;
938 		goto out;
939 	}
940 	if (uiop->uio_loffset > fscp->fs_offmax) {
941 		error = EFBIG;
942 		goto out;
943 	}
944 
945 	if (limit > fscp->fs_offmax)
946 		limit = fscp->fs_offmax;
947 
948 	if (uiop->uio_loffset < (offset_t)0) {
949 		error = EINVAL;
950 		goto out;
951 	}
952 
953 	offset = uiop->uio_loffset + uiop->uio_resid;
954 	/*
955 	 * Check to make sure that the process will not exceed
956 	 * its limit on file size.  It is okay to write up to
957 	 * the limit, but not beyond.  Thus, the write which
958 	 * reaches the limit will be short and the next write
959 	 * will return an error.
960 	 */
961 	remainder = 0;
962 	if (offset > limit) {
963 		remainder = (int)(offset - (u_offset_t)limit);
964 		uiop->uio_resid = limit - uiop->uio_loffset;
965 		if (uiop->uio_resid <= 0) {
966 			proc_t *p = ttoproc(curthread);
967 
968 			uiop->uio_resid += remainder;
969 			mutex_enter(&p->p_lock);
970 			(void) rctl_action(rctlproc_legacy[RLIMIT_FSIZE],
971 			    p->p_rctls, p, RCA_UNSAFE_SIGINFO);
972 			mutex_exit(&p->p_lock);
973 			error = EFBIG;
974 			goto out;
975 		}
976 	}
977 
978 	resid = uiop->uio_resid;
979 	offset = uiop->uio_loffset;
980 	bsize = vp->v_vfsp->vfs_bsize;
981 
982 	/* loop around and do the write in MAXBSIZE chunks */
983 	do {
984 		/* mapping offset */
985 		off = uiop->uio_loffset & (offset_t)MAXBMASK;
986 		on = uiop->uio_loffset & MAXBOFFSET; /* Rel. offset */
987 		n = MAXBSIZE - on;
988 		if (n > uiop->uio_resid)
989 			n = (int)uiop->uio_resid;
990 		base = segmap_getmap(segkmap, vp, off);
991 		error = cachefs_writepage(vp, (base + on), n, uiop);
992 		if (error == 0) {
993 			flags = 0;
994 			/*
995 			 * Have written a whole block.Start an
996 			 * asynchronous write and mark the buffer to
997 			 * indicate that it won't be needed again
998 			 * soon.
999 			 */
1000 			if (n + on == bsize) {
1001 				flags = SM_WRITE |SM_ASYNC |SM_DONTNEED;
1002 			}
1003 #if 0
1004 			/* XXX need to understand this */
1005 			if ((ioflag & (FSYNC|FDSYNC)) ||
1006 			    (cp->c_backvp && vn_has_flocks(cp->c_backvp))) {
1007 				flags &= ~SM_ASYNC;
1008 				flags |= SM_WRITE;
1009 			}
1010 #else
1011 			if (ioflag & (FSYNC|FDSYNC)) {
1012 				flags &= ~SM_ASYNC;
1013 				flags |= SM_WRITE;
1014 			}
1015 #endif
1016 			error = segmap_release(segkmap, base, flags);
1017 		} else {
1018 			(void) segmap_release(segkmap, base, 0);
1019 		}
1020 	} while (error == 0 && uiop->uio_resid > 0);
1021 
1022 out:
1023 	if (error == EINTR && (ioflag & (FSYNC|FDSYNC))) {
1024 		uiop->uio_resid = resid;
1025 		uiop->uio_loffset = offset;
1026 	} else
1027 		uiop->uio_resid += remainder;
1028 
1029 out2:
1030 #ifdef CFSDEBUG
1031 	CFS_DEBUG(CFSDEBUG_VOPS)
1032 		printf("cachefs_write: EXIT error %d\n", error);
1033 #endif
1034 	return (error);
1035 }
1036 
1037 /*
1038  * cachefs_write_backfs_nfsv4
1039  *
1040  * Call NFSv4 back filesystem to handle the write (cachefs
1041  * pass-through support for NFSv4).
1042  */
1043 static int
1044 cachefs_write_backfs_nfsv4(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr,
1045 			caller_context_t *ct)
1046 {
1047 	cnode_t *cp = VTOC(vp);
1048 	fscache_t *fscp = C_TO_FSCACHE(cp);
1049 	vnode_t *backvp;
1050 	int error;
1051 
1052 	/*
1053 	 * For NFSv4 pass-through to work, only connected operation
1054 	 * is supported, the cnode backvp must exist, and cachefs
1055 	 * optional (eg., disconnectable) flags are turned off. Assert
1056 	 * these conditions for the read operation.
1057 	 */
1058 	CFS_BACKFS_NFSV4_ASSERT_FSCACHE(fscp);
1059 	CFS_BACKFS_NFSV4_ASSERT_CNODE(cp);
1060 
1061 	/* Call backfs vnode op after extracting the backvp */
1062 	mutex_enter(&cp->c_statelock);
1063 	backvp = cp->c_backvp;
1064 	mutex_exit(&cp->c_statelock);
1065 
1066 	CFS_DPRINT_BACKFS_NFSV4(fscp, ("cachefs_write_backfs_nfsv4: cnode %p, "
1067 	    "backvp %p\n", cp, backvp));
1068 	(void) VOP_RWLOCK(backvp, V_WRITELOCK_TRUE, ct);
1069 	error = VOP_WRITE(backvp, uiop, ioflag, cr, ct);
1070 	VOP_RWUNLOCK(backvp, V_WRITELOCK_TRUE, ct);
1071 
1072 	return (error);
1073 }
1074 
1075 /*
1076  * see if we've charged ourselves for frontfile data at
1077  * the given offset.  If not, allocate a block for it now.
1078  */
1079 static int
1080 cachefs_charge_page(struct cnode *cp, u_offset_t offset)
1081 {
1082 	u_offset_t blockoff;
1083 	int error;
1084 	int inc;
1085 
1086 	ASSERT(MUTEX_HELD(&cp->c_statelock));
1087 	/*LINTED*/
1088 	ASSERT(PAGESIZE <= MAXBSIZE);
1089 
1090 	error = 0;
1091 	blockoff = offset & (offset_t)MAXBMASK;
1092 
1093 	/* get the front file if necessary so allocblocks works */
1094 	if ((cp->c_frontvp == NULL) &&
1095 	    ((cp->c_flags & CN_NOCACHE) == 0)) {
1096 		(void) cachefs_getfrontfile(cp);
1097 	}
1098 	if (cp->c_flags & CN_NOCACHE)
1099 		return (1);
1100 
1101 	if (cachefs_check_allocmap(cp, blockoff))
1102 		return (0);
1103 
1104 	for (inc = PAGESIZE; inc < MAXBSIZE; inc += PAGESIZE)
1105 		if (cachefs_check_allocmap(cp, blockoff+inc))
1106 			return (0);
1107 
1108 	error = cachefs_allocblocks(C_TO_FSCACHE(cp)->fs_cache, 1,
1109 	    cp->c_metadata.md_rltype);
1110 	if (error == 0) {
1111 		cp->c_metadata.md_frontblks++;
1112 		cp->c_flags |= CN_UPDATED;
1113 	}
1114 	return (error);
1115 }
1116 
1117 /*
1118  * Called only by cachefs_write to write 1 page or less of data.
1119  *	base   - base address kernel addr space
1120  *	tcount - Total bytes to move - < MAXBSIZE
1121  */
1122 static int
1123 cachefs_writepage(vnode_t *vp, caddr_t base, int tcount, uio_t *uiop)
1124 {
1125 	struct cnode *cp =  VTOC(vp);
1126 	fscache_t *fscp = C_TO_FSCACHE(cp);
1127 	register int n;
1128 	register u_offset_t offset;
1129 	int error = 0, terror;
1130 	extern struct as kas;
1131 	u_offset_t lastpage_off;
1132 	int pagecreate = 0;
1133 	int newpage;
1134 
1135 #ifdef CFSDEBUG
1136 	CFS_DEBUG(CFSDEBUG_VOPS)
1137 		printf(
1138 		    "cachefs_writepage: ENTER vp %p offset %llu len %ld\\\n",
1139 		    (void *)vp, uiop->uio_loffset, uiop->uio_resid);
1140 #endif
1141 
1142 	/*
1143 	 * Move bytes in PAGESIZE chunks. We must avoid spanning pages in
1144 	 * uiomove() because page faults may cause the cache to be invalidated
1145 	 * out from under us.
1146 	 */
1147 	do {
1148 		offset = uiop->uio_loffset;
1149 		lastpage_off = (cp->c_size - 1) & (offset_t)PAGEMASK;
1150 
1151 		/*
1152 		 * If not connected then need to make sure we have space
1153 		 * to perform the write.  We could make this check
1154 		 * a little tighter by only doing it if we are growing the file.
1155 		 */
1156 		if (fscp->fs_cdconnected != CFS_CD_CONNECTED) {
1157 			error = cachefs_allocblocks(fscp->fs_cache, 1,
1158 			    cp->c_metadata.md_rltype);
1159 			if (error)
1160 				break;
1161 			cachefs_freeblocks(fscp->fs_cache, 1,
1162 			    cp->c_metadata.md_rltype);
1163 		}
1164 
1165 		/*
1166 		 * n is the number of bytes required to satisfy the request
1167 		 * or the number of bytes to fill out the page.
1168 		 */
1169 		n = (int)(PAGESIZE - ((uintptr_t)base & PAGEOFFSET));
1170 		if (n > tcount)
1171 			n = tcount;
1172 
1173 		/*
1174 		 * The number of bytes of data in the last page can not
1175 		 * be accurately be determined while page is being
1176 		 * uiomove'd to and the size of the file being updated.
1177 		 * Thus, inform threads which need to know accurately
1178 		 * how much data is in the last page of the file.  They
1179 		 * will not do the i/o immediately, but will arrange for
1180 		 * the i/o to happen later when this modify operation
1181 		 * will have finished.
1182 		 *
1183 		 * in similar NFS code, this is done right before the
1184 		 * uiomove(), which is best.  but here in cachefs, we
1185 		 * have two uiomove()s, so we must do it here.
1186 		 */
1187 		ASSERT(!(cp->c_flags & CN_CMODINPROG));
1188 		mutex_enter(&cp->c_statelock);
1189 		cp->c_flags |= CN_CMODINPROG;
1190 		cp->c_modaddr = (offset & (offset_t)MAXBMASK);
1191 		mutex_exit(&cp->c_statelock);
1192 
1193 		/*
1194 		 * Check to see if we can skip reading in the page
1195 		 * and just allocate the memory.  We can do this
1196 		 * if we are going to rewrite the entire mapping
1197 		 * or if we are going to write to or beyond the current
1198 		 * end of file from the beginning of the mapping.
1199 		 */
1200 		if ((offset > (lastpage_off + PAGEOFFSET)) ||
1201 		    ((cp->c_size == 0) && (offset < PAGESIZE)) ||
1202 		    ((uintptr_t)base & PAGEOFFSET) == 0 && (n == PAGESIZE ||
1203 		    ((offset + n) >= cp->c_size))) {
1204 			pagecreate = 1;
1205 
1206 			/*
1207 			 * segmap_pagecreate() returns 1 if it calls
1208 			 * page_create_va() to allocate any pages.
1209 			 */
1210 			newpage = segmap_pagecreate(segkmap,
1211 			    (caddr_t)((uintptr_t)base & (uintptr_t)PAGEMASK),
1212 			    PAGESIZE, 0);
1213 			/* do not zero page if we are overwriting all of it */
1214 			if (!((((uintptr_t)base & PAGEOFFSET) == 0) &&
1215 			    (n == PAGESIZE))) {
1216 				(void) kzero((void *)
1217 				    ((uintptr_t)base & (uintptr_t)PAGEMASK),
1218 				    PAGESIZE);
1219 			}
1220 			error = uiomove(base, n, UIO_WRITE, uiop);
1221 
1222 			/*
1223 			 * Unlock the page allocated by page_create_va()
1224 			 * in segmap_pagecreate()
1225 			 */
1226 			if (newpage)
1227 				segmap_pageunlock(segkmap,
1228 				    (caddr_t)((uintptr_t)base &
1229 				    (uintptr_t)PAGEMASK),
1230 				    PAGESIZE, S_WRITE);
1231 		} else {
1232 			/*
1233 			 * KLUDGE ! Use segmap_fault instead of faulting and
1234 			 * using as_fault() to avoid a recursive readers lock
1235 			 * on kas.
1236 			 */
1237 			error = segmap_fault(kas.a_hat, segkmap, (caddr_t)
1238 			    ((uintptr_t)base & (uintptr_t)PAGEMASK),
1239 			    PAGESIZE, F_SOFTLOCK, S_WRITE);
1240 			if (error) {
1241 				if (FC_CODE(error) == FC_OBJERR)
1242 					error =  FC_ERRNO(error);
1243 				else
1244 					error = EIO;
1245 				break;
1246 			}
1247 			error = uiomove(base, n, UIO_WRITE, uiop);
1248 			(void) segmap_fault(kas.a_hat, segkmap, (caddr_t)
1249 			    ((uintptr_t)base & (uintptr_t)PAGEMASK),
1250 			    PAGESIZE, F_SOFTUNLOCK, S_WRITE);
1251 		}
1252 		n = (int)(uiop->uio_loffset - offset); /* n = # bytes written */
1253 		base += n;
1254 		tcount -= n;
1255 
1256 		/* get access to the file system */
1257 		if ((terror = cachefs_cd_access(fscp, 0, 1)) != 0) {
1258 			error = terror;
1259 			break;
1260 		}
1261 
1262 		/*
1263 		 * cp->c_attr.va_size is the maximum number of
1264 		 * bytes known to be in the file.
1265 		 * Make sure it is at least as high as the
1266 		 * last byte we just wrote into the buffer.
1267 		 */
1268 		mutex_enter(&cp->c_statelock);
1269 		if (cp->c_size < uiop->uio_loffset) {
1270 			cp->c_size = uiop->uio_loffset;
1271 		}
1272 		if (cp->c_size != cp->c_attr.va_size) {
1273 			cp->c_attr.va_size = cp->c_size;
1274 			cp->c_flags |= CN_UPDATED;
1275 		}
1276 		/* c_size is now correct, so we can clear modinprog */
1277 		cp->c_flags &= ~CN_CMODINPROG;
1278 		if (error == 0) {
1279 			cp->c_flags |= CDIRTY;
1280 			if (pagecreate && (cp->c_flags & CN_NOCACHE) == 0) {
1281 				/*
1282 				 * if we're not in NOCACHE mode
1283 				 * (i.e., single-writer), we update the
1284 				 * allocmap here rather than waiting until
1285 				 * cachefspush is called.  This prevents
1286 				 * getpage from clustering up pages from
1287 				 * the backfile and stomping over the changes
1288 				 * we make here.
1289 				 */
1290 				if (cachefs_charge_page(cp, offset) == 0) {
1291 					cachefs_update_allocmap(cp,
1292 					    offset & (offset_t)PAGEMASK,
1293 					    (size_t)PAGESIZE);
1294 				}
1295 
1296 				/* else we ran out of space */
1297 				else {
1298 					/* nocache file if connected */
1299 					if (fscp->fs_cdconnected ==
1300 					    CFS_CD_CONNECTED)
1301 						cachefs_nocache(cp);
1302 					/*
1303 					 * If disconnected then cannot
1304 					 * nocache the file.  Let it have
1305 					 * the space.
1306 					 */
1307 					else {
1308 						cp->c_metadata.md_frontblks++;
1309 						cp->c_flags |= CN_UPDATED;
1310 						cachefs_update_allocmap(cp,
1311 						    offset & (offset_t)PAGEMASK,
1312 						    (size_t)PAGESIZE);
1313 					}
1314 				}
1315 			}
1316 		}
1317 		mutex_exit(&cp->c_statelock);
1318 		cachefs_cd_release(fscp);
1319 	} while (tcount > 0 && error == 0);
1320 
1321 	if (cp->c_flags & CN_CMODINPROG) {
1322 		/* XXX assert error != 0?  FC_ERRNO() makes this more risky. */
1323 		mutex_enter(&cp->c_statelock);
1324 		cp->c_flags &= ~CN_CMODINPROG;
1325 		mutex_exit(&cp->c_statelock);
1326 	}
1327 
1328 #ifdef CFS_CD_DEBUG
1329 	ASSERT((curthread->t_flag & T_CD_HELD) == 0);
1330 #endif
1331 
1332 #ifdef CFSDEBUG
1333 	CFS_DEBUG(CFSDEBUG_VOPS)
1334 		printf("cachefs_writepage: EXIT error %d\n", error);
1335 #endif
1336 
1337 	return (error);
1338 }
1339 
1340 /*
1341  * Pushes out pages to the back and/or front file system.
1342  */
1343 static int
1344 cachefs_push(vnode_t *vp, page_t *pp, u_offset_t *offp, size_t *lenp,
1345     int flags, cred_t *cr)
1346 {
1347 	struct cnode *cp = VTOC(vp);
1348 	struct buf *bp;
1349 	int error;
1350 	fscache_t *fscp = C_TO_FSCACHE(cp);
1351 	u_offset_t iooff;
1352 	size_t iolen;
1353 	u_offset_t lbn;
1354 	u_offset_t lbn_off;
1355 	uint_t bsize;
1356 
1357 	ASSERT((flags & B_ASYNC) == 0);
1358 	ASSERT(!vn_is_readonly(vp));
1359 	ASSERT(pp != NULL);
1360 	ASSERT(cr != NULL);
1361 
1362 	bsize = MAX(vp->v_vfsp->vfs_bsize, PAGESIZE);
1363 	lbn = pp->p_offset / bsize;
1364 	lbn_off = lbn * bsize;
1365 
1366 	/*
1367 	 * Find a kluster that fits in one block, or in
1368 	 * one page if pages are bigger than blocks.  If
1369 	 * there is less file space allocated than a whole
1370 	 * page, we'll shorten the i/o request below.
1371 	 */
1372 
1373 	pp = pvn_write_kluster(vp, pp, &iooff, &iolen, lbn_off,
1374 	    roundup(bsize, PAGESIZE), flags);
1375 
1376 	/*
1377 	 * The CN_CMODINPROG flag makes sure that we use a correct
1378 	 * value of c_size, below.  CN_CMODINPROG is set in
1379 	 * cachefs_writepage().  When CN_CMODINPROG is set it
1380 	 * indicates that a uiomove() is in progress and the c_size
1381 	 * has not been made consistent with the new size of the
1382 	 * file. When the uiomove() completes the c_size is updated
1383 	 * and the CN_CMODINPROG flag is cleared.
1384 	 *
1385 	 * The CN_CMODINPROG flag makes sure that cachefs_push_front
1386 	 * and cachefs_push_connected see a consistent value of
1387 	 * c_size.  Without this handshaking, it is possible that
1388 	 * these routines will pick up the old value of c_size before
1389 	 * the uiomove() in cachefs_writepage() completes.  This will
1390 	 * result in the vn_rdwr() being too small, and data loss.
1391 	 *
1392 	 * More precisely, there is a window between the time the
1393 	 * uiomove() completes and the time the c_size is updated. If
1394 	 * a VOP_PUTPAGE() operation intervenes in this window, the
1395 	 * page will be picked up, because it is dirty; it will be
1396 	 * unlocked, unless it was pagecreate'd. When the page is
1397 	 * picked up as dirty, the dirty bit is reset
1398 	 * (pvn_getdirty()). In cachefs_push_connected(), c_size is
1399 	 * checked.  This will still be the old size.  Therefore, the
1400 	 * page will not be written out to the correct length, and the
1401 	 * page will be clean, so the data may disappear.
1402 	 */
1403 	if (cp->c_flags & CN_CMODINPROG) {
1404 		mutex_enter(&cp->c_statelock);
1405 		if ((cp->c_flags & CN_CMODINPROG) &&
1406 		    cp->c_modaddr + MAXBSIZE > iooff &&
1407 		    cp->c_modaddr < iooff + iolen) {
1408 			page_t *plist;
1409 
1410 			/*
1411 			 * A write is in progress for this region of
1412 			 * the file.  If we did not detect
1413 			 * CN_CMODINPROG here then this path through
1414 			 * cachefs_push_connected() would eventually
1415 			 * do the vn_rdwr() and may not write out all
1416 			 * of the data in the pages.  We end up losing
1417 			 * data. So we decide to set the modified bit
1418 			 * on each page in the page list and mark the
1419 			 * cnode with CDIRTY.  This push will be
1420 			 * restarted at some later time.
1421 			 */
1422 
1423 			plist = pp;
1424 			while (plist != NULL) {
1425 				pp = plist;
1426 				page_sub(&plist, pp);
1427 				hat_setmod(pp);
1428 				page_io_unlock(pp);
1429 				page_unlock(pp);
1430 			}
1431 			cp->c_flags |= CDIRTY;
1432 			mutex_exit(&cp->c_statelock);
1433 			if (offp)
1434 				*offp = iooff;
1435 			if (lenp)
1436 				*lenp = iolen;
1437 			return (0);
1438 		}
1439 		mutex_exit(&cp->c_statelock);
1440 	}
1441 
1442 	/*
1443 	 * Set the pages up for pageout.
1444 	 */
1445 	bp = pageio_setup(pp, iolen, CTOV(cp), B_WRITE | flags);
1446 	if (bp == NULL) {
1447 
1448 		/*
1449 		 * currently, there is no way for pageio_setup() to
1450 		 * return NULL, since it uses its own scheme for
1451 		 * kmem_alloc()ing that shouldn't return NULL, and
1452 		 * since pageio_setup() itself dereferences the thing
1453 		 * it's about to return.  still, we need to be ready
1454 		 * in case this ever does start happening.
1455 		 */
1456 
1457 		error = ENOMEM;
1458 		goto writedone;
1459 	}
1460 	/*
1461 	 * pageio_setup should have set b_addr to 0.  This
1462 	 * is correct since we want to do I/O on a page
1463 	 * boundary.  bp_mapin will use this addr to calculate
1464 	 * an offset, and then set b_addr to the kernel virtual
1465 	 * address it allocated for us.
1466 	 */
1467 	bp->b_edev = 0;
1468 	bp->b_dev = 0;
1469 	bp->b_lblkno = (diskaddr_t)lbtodb(iooff);
1470 	bp_mapin(bp);
1471 
1472 	iolen  = cp->c_size - ldbtob(bp->b_blkno);
1473 	if (iolen > bp->b_bcount)
1474 		iolen  = bp->b_bcount;
1475 
1476 	/* if connected */
1477 	if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
1478 		/* write to the back file first */
1479 		error = cachefs_push_connected(vp, bp, iolen, iooff, cr);
1480 
1481 		/* write to the front file if allowed */
1482 		if ((error == 0) && CFS_ISFS_NONSHARED(fscp) &&
1483 		    ((cp->c_flags & CN_NOCACHE) == 0)) {
1484 			/* try to write to the front file */
1485 			(void) cachefs_push_front(vp, bp, iolen, iooff, cr);
1486 		}
1487 	}
1488 
1489 	/* else if disconnected */
1490 	else {
1491 		/* try to write to the front file */
1492 		error = cachefs_push_front(vp, bp, iolen, iooff, cr);
1493 	}
1494 
1495 	bp_mapout(bp);
1496 	pageio_done(bp);
1497 
1498 writedone:
1499 
1500 	pvn_write_done(pp, ((error) ? B_ERROR : 0) | B_WRITE | flags);
1501 	if (offp)
1502 		*offp = iooff;
1503 	if (lenp)
1504 		*lenp = iolen;
1505 
1506 	/* XXX ask bob mastors how to fix this someday */
1507 	mutex_enter(&cp->c_statelock);
1508 	if (error) {
1509 		if (error == ENOSPC) {
1510 			if ((fscp->fs_cdconnected == CFS_CD_CONNECTED) ||
1511 			    CFS_ISFS_SOFT(fscp)) {
1512 				CFSOP_INVALIDATE_COBJECT(fscp, cp, cr);
1513 				cp->c_error = error;
1514 			}
1515 		} else if ((CFS_TIMEOUT(fscp, error) == 0) &&
1516 		    (error != EINTR)) {
1517 			CFSOP_INVALIDATE_COBJECT(fscp, cp, cr);
1518 			cp->c_error = error;
1519 		}
1520 	} else if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
1521 		CFSOP_MODIFY_COBJECT(fscp, cp, cr);
1522 	}
1523 	mutex_exit(&cp->c_statelock);
1524 
1525 	return (error);
1526 }
1527 
1528 /*
1529  * Pushes out pages to the back file system.
1530  */
1531 static int
1532 cachefs_push_connected(vnode_t *vp, struct buf *bp, size_t iolen,
1533     u_offset_t iooff, cred_t *cr)
1534 {
1535 	struct cnode *cp = VTOC(vp);
1536 	int error = 0;
1537 	int mode = 0;
1538 	fscache_t *fscp = C_TO_FSCACHE(cp);
1539 	ssize_t resid;
1540 	vnode_t *backvp;
1541 
1542 	/* get the back file if necessary */
1543 	mutex_enter(&cp->c_statelock);
1544 	if (cp->c_backvp == NULL) {
1545 		error = cachefs_getbackvp(fscp, cp);
1546 		if (error) {
1547 			mutex_exit(&cp->c_statelock);
1548 			goto out;
1549 		}
1550 	}
1551 	backvp = cp->c_backvp;
1552 	VN_HOLD(backvp);
1553 	mutex_exit(&cp->c_statelock);
1554 
1555 	if (CFS_ISFS_NONSHARED(fscp) && CFS_ISFS_SNR(fscp))
1556 		mode = FSYNC;
1557 
1558 	/* write to the back file */
1559 	error = bp->b_error = vn_rdwr(UIO_WRITE, backvp, bp->b_un.b_addr,
1560 	    iolen, iooff, UIO_SYSSPACE, mode,
1561 	    RLIM64_INFINITY, cr, &resid);
1562 	if (error) {
1563 #ifdef CFSDEBUG
1564 		CFS_DEBUG(CFSDEBUG_VOPS | CFSDEBUG_BACK)
1565 			printf("cachefspush: error %d cr %p\n",
1566 			    error, (void *)cr);
1567 #endif
1568 		bp->b_flags |= B_ERROR;
1569 	}
1570 	VN_RELE(backvp);
1571 out:
1572 	return (error);
1573 }
1574 
1575 /*
1576  * Pushes out pages to the front file system.
1577  * Called for both connected and disconnected states.
1578  */
1579 static int
1580 cachefs_push_front(vnode_t *vp, struct buf *bp, size_t iolen,
1581     u_offset_t iooff, cred_t *cr)
1582 {
1583 	struct cnode *cp = VTOC(vp);
1584 	fscache_t *fscp = C_TO_FSCACHE(cp);
1585 	int error = 0;
1586 	ssize_t resid;
1587 	u_offset_t popoff;
1588 	off_t commit = 0;
1589 	uint_t seq;
1590 	enum cachefs_rl_type type;
1591 	vnode_t *frontvp = NULL;
1592 
1593 	mutex_enter(&cp->c_statelock);
1594 
1595 	if (!CFS_ISFS_NONSHARED(fscp)) {
1596 		error = ETIMEDOUT;
1597 		goto out;
1598 	}
1599 
1600 	/* get the front file if necessary */
1601 	if ((cp->c_frontvp == NULL) &&
1602 	    ((cp->c_flags & CN_NOCACHE) == 0)) {
1603 		(void) cachefs_getfrontfile(cp);
1604 	}
1605 	if (cp->c_flags & CN_NOCACHE) {
1606 		error = ETIMEDOUT;
1607 		goto out;
1608 	}
1609 
1610 	/* if disconnected, needs to be populated and have good attributes */
1611 	if ((fscp->fs_cdconnected != CFS_CD_CONNECTED) &&
1612 	    (((cp->c_metadata.md_flags & MD_POPULATED) == 0) ||
1613 	    (cp->c_metadata.md_flags & MD_NEEDATTRS))) {
1614 		error = ETIMEDOUT;
1615 		goto out;
1616 	}
1617 
1618 	for (popoff = iooff; popoff < (iooff + iolen); popoff += MAXBSIZE) {
1619 		if (cachefs_charge_page(cp, popoff)) {
1620 			if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
1621 				cachefs_nocache(cp);
1622 				goto out;
1623 			} else {
1624 				error = ENOSPC;
1625 				goto out;
1626 			}
1627 		}
1628 	}
1629 
1630 	if (fscp->fs_cdconnected != CFS_CD_CONNECTED) {
1631 		/* log the first putpage to a file */
1632 		if ((cp->c_metadata.md_flags & MD_PUTPAGE) == 0) {
1633 			/* uses open's creds if we have them */
1634 			if (cp->c_cred)
1635 				cr = cp->c_cred;
1636 
1637 			if ((cp->c_metadata.md_flags & MD_MAPPING) == 0) {
1638 				error = cachefs_dlog_cidmap(fscp);
1639 				if (error) {
1640 					error = ENOSPC;
1641 					goto out;
1642 				}
1643 				cp->c_metadata.md_flags |= MD_MAPPING;
1644 			}
1645 
1646 			commit = cachefs_dlog_modify(fscp, cp, cr, &seq);
1647 			if (commit == 0) {
1648 				/* out of space */
1649 				error = ENOSPC;
1650 				goto out;
1651 			}
1652 
1653 			cp->c_metadata.md_seq = seq;
1654 			type = cp->c_metadata.md_rltype;
1655 			cachefs_modified(cp);
1656 			cp->c_metadata.md_flags |= MD_PUTPAGE;
1657 			cp->c_metadata.md_flags &= ~MD_PUSHDONE;
1658 			cp->c_flags |= CN_UPDATED;
1659 		}
1660 
1661 		/* subsequent putpages just get a new sequence number */
1662 		else {
1663 			/* but only if it matters */
1664 			if (cp->c_metadata.md_seq != fscp->fs_dlogseq) {
1665 				seq = cachefs_dlog_seqnext(fscp);
1666 				if (seq == 0) {
1667 					error = ENOSPC;
1668 					goto out;
1669 				}
1670 				cp->c_metadata.md_seq = seq;
1671 				cp->c_flags |= CN_UPDATED;
1672 				/* XXX maybe should do write_metadata here */
1673 			}
1674 		}
1675 	}
1676 
1677 	frontvp = cp->c_frontvp;
1678 	VN_HOLD(frontvp);
1679 	mutex_exit(&cp->c_statelock);
1680 	error = bp->b_error = vn_rdwr(UIO_WRITE, frontvp,
1681 	    bp->b_un.b_addr, iolen, iooff, UIO_SYSSPACE, 0,
1682 	    RLIM64_INFINITY, kcred, &resid);
1683 	mutex_enter(&cp->c_statelock);
1684 	VN_RELE(frontvp);
1685 	frontvp = NULL;
1686 	if (error) {
1687 		if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
1688 			cachefs_nocache(cp);
1689 			error = 0;
1690 			goto out;
1691 		} else {
1692 			goto out;
1693 		}
1694 	}
1695 
1696 	(void) cachefs_update_allocmap(cp, iooff, iolen);
1697 	cp->c_flags |= (CN_UPDATED | CN_NEED_FRONT_SYNC |
1698 	    CN_POPULATION_PENDING);
1699 	if (fscp->fs_cdconnected != CFS_CD_CONNECTED) {
1700 		gethrestime(&cp->c_metadata.md_localmtime);
1701 		cp->c_metadata.md_flags |= MD_LOCALMTIME;
1702 	}
1703 
1704 out:
1705 	if (commit) {
1706 		/* commit the log record */
1707 		ASSERT(fscp->fs_cdconnected == CFS_CD_DISCONNECTED);
1708 		if (cachefs_dlog_commit(fscp, commit, error)) {
1709 			/*EMPTY*/
1710 			/* XXX fix on panic */
1711 		}
1712 	}
1713 
1714 	if (error && commit) {
1715 		cp->c_metadata.md_flags &= ~MD_PUTPAGE;
1716 		cachefs_rlent_moveto(fscp->fs_cache, type,
1717 		    cp->c_metadata.md_rlno, cp->c_metadata.md_frontblks);
1718 		cp->c_metadata.md_rltype = type;
1719 		cp->c_flags |= CN_UPDATED;
1720 	}
1721 	mutex_exit(&cp->c_statelock);
1722 	return (error);
1723 }
1724 
1725 /*ARGSUSED*/
1726 static int
1727 cachefs_dump(struct vnode *vp, caddr_t foo1, offset_t foo2, offset_t foo3,
1728     caller_context_t *ct)
1729 {
1730 	return (ENOSYS); /* should we panic if we get here? */
1731 }
1732 
1733 /*ARGSUSED*/
1734 static int
1735 cachefs_ioctl(struct vnode *vp, int cmd, intptr_t arg, int flag, cred_t *cred,
1736 	int *rvalp, caller_context_t *ct)
1737 {
1738 	int error;
1739 	struct cnode *cp = VTOC(vp);
1740 	struct fscache *fscp = C_TO_FSCACHE(cp);
1741 	struct cachefscache *cachep;
1742 	extern kmutex_t cachefs_cachelock;
1743 	extern cachefscache_t *cachefs_cachelist;
1744 	cachefsio_pack_t *packp;
1745 	STRUCT_DECL(cachefsio_dcmd, dcmd);
1746 	int	inlen, outlen;	/* LP64: generic int for struct in/out len */
1747 	void *dinp, *doutp;
1748 	int (*dcmd_routine)(vnode_t *, void *, void *);
1749 
1750 	if (getzoneid() != GLOBAL_ZONEID)
1751 		return (EPERM);
1752 
1753 	/*
1754 	 * Cachefs only provides pass-through support for NFSv4,
1755 	 * and all vnode operations are passed through to the
1756 	 * back file system. For NFSv4 pass-through to work, only
1757 	 * connected operation is supported, the cnode backvp must
1758 	 * exist, and cachefs optional (eg., disconnectable) flags
1759 	 * are turned off. Assert these conditions which ensure
1760 	 * that only a subset of the ioctls are "truly supported"
1761 	 * for NFSv4 (these are CFSDCMD_DAEMONID and CFSDCMD_GETSTATS.
1762 	 * The packing operations are meaningless since there is
1763 	 * no caching for NFSv4, and the called functions silently
1764 	 * return if the backfilesystem is NFSv4. The daemon
1765 	 * commands except for those above are essentially used
1766 	 * for disconnectable operation support (including log
1767 	 * rolling), so in each called function, we assert that
1768 	 * NFSv4 is not in use. The _FIO* calls (except _FIOCOD)
1769 	 * are from "cfsfstype" which is not a documented
1770 	 * command. However, the command is visible in
1771 	 * /usr/lib/fs/cachefs so the commands are simply let
1772 	 * through (don't seem to impact pass-through functionality).
1773 	 */
1774 	CFS_BACKFS_NFSV4_ASSERT_FSCACHE(fscp);
1775 	CFS_BACKFS_NFSV4_ASSERT_CNODE(cp);
1776 
1777 	switch (cmd) {
1778 	case CACHEFSIO_PACK:
1779 		packp = cachefs_kmem_alloc(sizeof (cachefsio_pack_t), KM_SLEEP);
1780 		error = xcopyin((void *)arg, packp, sizeof (cachefsio_pack_t));
1781 		if (!error)
1782 			error = cachefs_pack(vp, packp->p_name, cred);
1783 		cachefs_kmem_free(packp, sizeof (cachefsio_pack_t));
1784 		break;
1785 
1786 	case CACHEFSIO_UNPACK:
1787 		packp = cachefs_kmem_alloc(sizeof (cachefsio_pack_t), KM_SLEEP);
1788 		error = xcopyin((void *)arg, packp, sizeof (cachefsio_pack_t));
1789 		if (!error)
1790 			error = cachefs_unpack(vp, packp->p_name, cred);
1791 		cachefs_kmem_free(packp, sizeof (cachefsio_pack_t));
1792 		break;
1793 
1794 	case CACHEFSIO_PACKINFO:
1795 		packp = cachefs_kmem_alloc(sizeof (cachefsio_pack_t), KM_SLEEP);
1796 		error = xcopyin((void *)arg, packp, sizeof (cachefsio_pack_t));
1797 		if (!error)
1798 			error = cachefs_packinfo(vp, packp->p_name,
1799 			    &packp->p_status, cred);
1800 		if (!error)
1801 			error = xcopyout(packp, (void *)arg,
1802 			    sizeof (cachefsio_pack_t));
1803 		cachefs_kmem_free(packp, sizeof (cachefsio_pack_t));
1804 		break;
1805 
1806 	case CACHEFSIO_UNPACKALL:
1807 		error = cachefs_unpackall(vp);
1808 		break;
1809 
1810 	case CACHEFSIO_DCMD:
1811 		/*
1812 		 * This is a private interface between the cachefsd and
1813 		 * this file system.
1814 		 */
1815 
1816 		/* must be root to use these commands */
1817 		if (secpolicy_fs_config(cred, vp->v_vfsp) != 0)
1818 			return (EPERM);
1819 
1820 		/* get the command packet */
1821 		STRUCT_INIT(dcmd, flag & DATAMODEL_MASK);
1822 		error = xcopyin((void *)arg, STRUCT_BUF(dcmd),
1823 		    SIZEOF_STRUCT(cachefsio_dcmd, DATAMODEL_NATIVE));
1824 		if (error)
1825 			return (error);
1826 
1827 		/* copy in the data for the operation */
1828 		dinp = NULL;
1829 		if ((inlen = STRUCT_FGET(dcmd, d_slen)) > 0) {
1830 			dinp = cachefs_kmem_alloc(inlen, KM_SLEEP);
1831 			error = xcopyin(STRUCT_FGETP(dcmd, d_sdata), dinp,
1832 			    inlen);
1833 			if (error)
1834 				return (error);
1835 		}
1836 
1837 		/* allocate space for the result */
1838 		doutp = NULL;
1839 		if ((outlen = STRUCT_FGET(dcmd, d_rlen)) > 0)
1840 			doutp = cachefs_kmem_alloc(outlen, KM_SLEEP);
1841 
1842 		/*
1843 		 * Assert NFSv4 only allows the daemonid and getstats
1844 		 * daemon requests
1845 		 */
1846 		ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0 ||
1847 		    STRUCT_FGET(dcmd, d_cmd) == CFSDCMD_DAEMONID ||
1848 		    STRUCT_FGET(dcmd, d_cmd) == CFSDCMD_GETSTATS);
1849 
1850 		/* get the routine to execute */
1851 		dcmd_routine = NULL;
1852 		switch (STRUCT_FGET(dcmd, d_cmd)) {
1853 		case CFSDCMD_DAEMONID:
1854 			dcmd_routine = cachefs_io_daemonid;
1855 			break;
1856 		case CFSDCMD_STATEGET:
1857 			dcmd_routine = cachefs_io_stateget;
1858 			break;
1859 		case CFSDCMD_STATESET:
1860 			dcmd_routine = cachefs_io_stateset;
1861 			break;
1862 		case CFSDCMD_XWAIT:
1863 			dcmd_routine = cachefs_io_xwait;
1864 			break;
1865 		case CFSDCMD_EXISTS:
1866 			dcmd_routine = cachefs_io_exists;
1867 			break;
1868 		case CFSDCMD_LOSTFOUND:
1869 			dcmd_routine = cachefs_io_lostfound;
1870 			break;
1871 		case CFSDCMD_GETINFO:
1872 			dcmd_routine = cachefs_io_getinfo;
1873 			break;
1874 		case CFSDCMD_CIDTOFID:
1875 			dcmd_routine = cachefs_io_cidtofid;
1876 			break;
1877 		case CFSDCMD_GETATTRFID:
1878 			dcmd_routine = cachefs_io_getattrfid;
1879 			break;
1880 		case CFSDCMD_GETATTRNAME:
1881 			dcmd_routine = cachefs_io_getattrname;
1882 			break;
1883 		case CFSDCMD_GETSTATS:
1884 			dcmd_routine = cachefs_io_getstats;
1885 			break;
1886 		case CFSDCMD_ROOTFID:
1887 			dcmd_routine = cachefs_io_rootfid;
1888 			break;
1889 		case CFSDCMD_CREATE:
1890 			dcmd_routine = cachefs_io_create;
1891 			break;
1892 		case CFSDCMD_REMOVE:
1893 			dcmd_routine = cachefs_io_remove;
1894 			break;
1895 		case CFSDCMD_LINK:
1896 			dcmd_routine = cachefs_io_link;
1897 			break;
1898 		case CFSDCMD_RENAME:
1899 			dcmd_routine = cachefs_io_rename;
1900 			break;
1901 		case CFSDCMD_MKDIR:
1902 			dcmd_routine = cachefs_io_mkdir;
1903 			break;
1904 		case CFSDCMD_RMDIR:
1905 			dcmd_routine = cachefs_io_rmdir;
1906 			break;
1907 		case CFSDCMD_SYMLINK:
1908 			dcmd_routine = cachefs_io_symlink;
1909 			break;
1910 		case CFSDCMD_SETATTR:
1911 			dcmd_routine = cachefs_io_setattr;
1912 			break;
1913 		case CFSDCMD_SETSECATTR:
1914 			dcmd_routine = cachefs_io_setsecattr;
1915 			break;
1916 		case CFSDCMD_PUSHBACK:
1917 			dcmd_routine = cachefs_io_pushback;
1918 			break;
1919 		default:
1920 			error = ENOTTY;
1921 			break;
1922 		}
1923 
1924 		/* execute the routine */
1925 		if (dcmd_routine)
1926 			error = (*dcmd_routine)(vp, dinp, doutp);
1927 
1928 		/* copy out the result */
1929 		if ((error == 0) && doutp)
1930 			error = xcopyout(doutp, STRUCT_FGETP(dcmd, d_rdata),
1931 			    outlen);
1932 
1933 		/* free allocated memory */
1934 		if (dinp)
1935 			cachefs_kmem_free(dinp, inlen);
1936 		if (doutp)
1937 			cachefs_kmem_free(doutp, outlen);
1938 
1939 		break;
1940 
1941 	case _FIOCOD:
1942 		if (secpolicy_fs_config(cred, vp->v_vfsp) != 0) {
1943 			error = EPERM;
1944 			break;
1945 		}
1946 
1947 		error = EBUSY;
1948 		if (arg) {
1949 			/* non-zero arg means do all filesystems */
1950 			mutex_enter(&cachefs_cachelock);
1951 			for (cachep = cachefs_cachelist; cachep != NULL;
1952 			    cachep = cachep->c_next) {
1953 				mutex_enter(&cachep->c_fslistlock);
1954 				for (fscp = cachep->c_fslist;
1955 				    fscp != NULL;
1956 				    fscp = fscp->fs_next) {
1957 					if (CFS_ISFS_CODCONST(fscp)) {
1958 						gethrestime(&fscp->fs_cod_time);
1959 						error = 0;
1960 					}
1961 				}
1962 				mutex_exit(&cachep->c_fslistlock);
1963 			}
1964 			mutex_exit(&cachefs_cachelock);
1965 		} else {
1966 			if (CFS_ISFS_CODCONST(fscp)) {
1967 				gethrestime(&fscp->fs_cod_time);
1968 				error = 0;
1969 			}
1970 		}
1971 		break;
1972 
1973 	case _FIOSTOPCACHE:
1974 		error = cachefs_stop_cache(cp);
1975 		break;
1976 
1977 	default:
1978 		error = ENOTTY;
1979 		break;
1980 	}
1981 
1982 	/* return the result */
1983 	return (error);
1984 }
1985 
1986 ino64_t
1987 cachefs_fileno_conflict(fscache_t *fscp, ino64_t old)
1988 {
1989 	ino64_t new;
1990 
1991 	ASSERT(MUTEX_HELD(&fscp->fs_fslock));
1992 
1993 	for (;;) {
1994 		fscp->fs_info.fi_localfileno++;
1995 		if (fscp->fs_info.fi_localfileno == 0)
1996 			fscp->fs_info.fi_localfileno = 3;
1997 		fscp->fs_flags |= CFS_FS_DIRTYINFO;
1998 
1999 		new = fscp->fs_info.fi_localfileno;
2000 		if (! cachefs_fileno_inuse(fscp, new))
2001 			break;
2002 	}
2003 
2004 	cachefs_inum_register(fscp, old, new);
2005 	cachefs_inum_register(fscp, new, 0);
2006 	return (new);
2007 }
2008 
2009 /*ARGSUSED*/
2010 static int
2011 cachefs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
2012 	caller_context_t *ct)
2013 {
2014 	struct cnode *cp = VTOC(vp);
2015 	fscache_t *fscp = C_TO_FSCACHE(cp);
2016 	int error = 0;
2017 	int held = 0;
2018 	int connected = 0;
2019 
2020 #ifdef CFSDEBUG
2021 	CFS_DEBUG(CFSDEBUG_VOPS)
2022 		printf("cachefs_getattr: ENTER vp %p\n", (void *)vp);
2023 #endif
2024 
2025 	if (getzoneid() != GLOBAL_ZONEID)
2026 		return (EPERM);
2027 
2028 	/* Call backfilesystem getattr if NFSv4 */
2029 	if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
2030 		error = cachefs_getattr_backfs_nfsv4(vp, vap, flags, cr, ct);
2031 		goto out;
2032 	}
2033 
2034 	/*
2035 	 * If it has been specified that the return value will
2036 	 * just be used as a hint, and we are only being asked
2037 	 * for size, fsid or rdevid, then return the client's
2038 	 * notion of these values without checking to make sure
2039 	 * that the attribute cache is up to date.
2040 	 * The whole point is to avoid an over the wire GETATTR
2041 	 * call.
2042 	 */
2043 	if (flags & ATTR_HINT) {
2044 		if (vap->va_mask ==
2045 		    (vap->va_mask & (AT_SIZE | AT_FSID | AT_RDEV))) {
2046 			if (vap->va_mask | AT_SIZE)
2047 				vap->va_size = cp->c_size;
2048 			/*
2049 			 * Return the FSID of the cachefs filesystem,
2050 			 * not the back filesystem
2051 			 */
2052 			if (vap->va_mask | AT_FSID)
2053 				vap->va_fsid = vp->v_vfsp->vfs_dev;
2054 			if (vap->va_mask | AT_RDEV)
2055 				vap->va_rdev = cp->c_attr.va_rdev;
2056 			return (0);
2057 		}
2058 	}
2059 
2060 	/*
2061 	 * Only need to flush pages if asking for the mtime
2062 	 * and if there any dirty pages.
2063 	 */
2064 	if (vap->va_mask & AT_MTIME) {
2065 		/*EMPTY*/
2066 #if 0
2067 		/*
2068 		 * XXX bob: stolen from nfs code, need to do something similar
2069 		 */
2070 		rp = VTOR(vp);
2071 		if ((rp->r_flags & RDIRTY) || rp->r_iocnt > 0)
2072 			(void) nfs3_putpage(vp, (offset_t)0, 0, 0, cr);
2073 #endif
2074 	}
2075 
2076 	for (;;) {
2077 		/* get (or renew) access to the file system */
2078 		if (held) {
2079 			cachefs_cd_release(fscp);
2080 			held = 0;
2081 		}
2082 		error = cachefs_cd_access(fscp, connected, 0);
2083 		if (error)
2084 			goto out;
2085 		held = 1;
2086 
2087 		/*
2088 		 * If it has been specified that the return value will
2089 		 * just be used as a hint, and we are only being asked
2090 		 * for size, fsid or rdevid, then return the client's
2091 		 * notion of these values without checking to make sure
2092 		 * that the attribute cache is up to date.
2093 		 * The whole point is to avoid an over the wire GETATTR
2094 		 * call.
2095 		 */
2096 		if (flags & ATTR_HINT) {
2097 			if (vap->va_mask ==
2098 			    (vap->va_mask & (AT_SIZE | AT_FSID | AT_RDEV))) {
2099 				if (vap->va_mask | AT_SIZE)
2100 					vap->va_size = cp->c_size;
2101 				/*
2102 				 * Return the FSID of the cachefs filesystem,
2103 				 * not the back filesystem
2104 				 */
2105 				if (vap->va_mask | AT_FSID)
2106 					vap->va_fsid = vp->v_vfsp->vfs_dev;
2107 				if (vap->va_mask | AT_RDEV)
2108 					vap->va_rdev = cp->c_attr.va_rdev;
2109 				goto out;
2110 			}
2111 		}
2112 
2113 		mutex_enter(&cp->c_statelock);
2114 		if ((cp->c_metadata.md_flags & MD_NEEDATTRS) &&
2115 		    (fscp->fs_cdconnected != CFS_CD_CONNECTED)) {
2116 			mutex_exit(&cp->c_statelock);
2117 			connected = 1;
2118 			continue;
2119 		}
2120 
2121 		error = CFSOP_CHECK_COBJECT(fscp, cp, 0, cr);
2122 		if (CFS_TIMEOUT(fscp, error)) {
2123 			mutex_exit(&cp->c_statelock);
2124 			cachefs_cd_release(fscp);
2125 			held = 0;
2126 			cachefs_cd_timedout(fscp);
2127 			continue;
2128 		}
2129 		if (error) {
2130 			mutex_exit(&cp->c_statelock);
2131 			break;
2132 		}
2133 
2134 		/* check for fileno conflict */
2135 		if ((fscp->fs_inum_size > 0) &&
2136 		    ((cp->c_metadata.md_flags & MD_LOCALFILENO) == 0)) {
2137 			ino64_t fakenum;
2138 
2139 			mutex_exit(&cp->c_statelock);
2140 			mutex_enter(&fscp->fs_fslock);
2141 			fakenum = cachefs_inum_real2fake(fscp,
2142 			    cp->c_attr.va_nodeid);
2143 			if (fakenum == 0) {
2144 				fakenum = cachefs_fileno_conflict(fscp,
2145 				    cp->c_attr.va_nodeid);
2146 			}
2147 			mutex_exit(&fscp->fs_fslock);
2148 
2149 			mutex_enter(&cp->c_statelock);
2150 			cp->c_metadata.md_flags |= MD_LOCALFILENO;
2151 			cp->c_metadata.md_localfileno = fakenum;
2152 			cp->c_flags |= CN_UPDATED;
2153 		}
2154 
2155 		/* copy out the attributes */
2156 		*vap = cp->c_attr;
2157 
2158 		/*
2159 		 * return the FSID of the cachefs filesystem,
2160 		 * not the back filesystem
2161 		 */
2162 		vap->va_fsid = vp->v_vfsp->vfs_dev;
2163 
2164 		/* return our idea of the size */
2165 		if (cp->c_size > vap->va_size)
2166 			vap->va_size = cp->c_size;
2167 
2168 		/* overwrite with our version of fileno and timestamps */
2169 		vap->va_nodeid = cp->c_metadata.md_localfileno;
2170 		vap->va_mtime = cp->c_metadata.md_localmtime;
2171 		vap->va_ctime = cp->c_metadata.md_localctime;
2172 
2173 		mutex_exit(&cp->c_statelock);
2174 		break;
2175 	}
2176 out:
2177 	if (held)
2178 		cachefs_cd_release(fscp);
2179 #ifdef CFS_CD_DEBUG
2180 	ASSERT((curthread->t_flag & T_CD_HELD) == 0);
2181 #endif
2182 
2183 #ifdef CFSDEBUG
2184 	CFS_DEBUG(CFSDEBUG_VOPS)
2185 		printf("cachefs_getattr: EXIT error = %d\n", error);
2186 #endif
2187 	return (error);
2188 }
2189 
2190 /*
2191  * cachefs_getattr_backfs_nfsv4
2192  *
2193  * Call NFSv4 back filesystem to handle the getattr (cachefs
2194  * pass-through support for NFSv4).
2195  */
2196 static int
2197 cachefs_getattr_backfs_nfsv4(vnode_t *vp, vattr_t *vap,
2198     int flags, cred_t *cr, caller_context_t *ct)
2199 {
2200 	cnode_t *cp = VTOC(vp);
2201 	fscache_t *fscp = C_TO_FSCACHE(cp);
2202 	vnode_t *backvp;
2203 	int error;
2204 
2205 	/*
2206 	 * For NFSv4 pass-through to work, only connected operation
2207 	 * is supported, the cnode backvp must exist, and cachefs
2208 	 * optional (eg., disconnectable) flags are turned off. Assert
2209 	 * these conditions for the getattr operation.
2210 	 */
2211 	CFS_BACKFS_NFSV4_ASSERT_FSCACHE(fscp);
2212 	CFS_BACKFS_NFSV4_ASSERT_CNODE(cp);
2213 
2214 	/* Call backfs vnode op after extracting backvp */
2215 	mutex_enter(&cp->c_statelock);
2216 	backvp = cp->c_backvp;
2217 	mutex_exit(&cp->c_statelock);
2218 
2219 	CFS_DPRINT_BACKFS_NFSV4(fscp, ("cachefs_getattr_backfs_nfsv4: cnode %p,"
2220 	    " backvp %p\n", cp, backvp));
2221 	error = VOP_GETATTR(backvp, vap, flags, cr, ct);
2222 
2223 	/* Update attributes */
2224 	cp->c_attr = *vap;
2225 
2226 	/*
2227 	 * return the FSID of the cachefs filesystem,
2228 	 * not the back filesystem
2229 	 */
2230 	vap->va_fsid = vp->v_vfsp->vfs_dev;
2231 
2232 	return (error);
2233 }
2234 
2235 /*ARGSUSED4*/
2236 static int
2237 cachefs_setattr(
2238 	vnode_t *vp,
2239 	vattr_t *vap,
2240 	int flags,
2241 	cred_t *cr,
2242 	caller_context_t *ct)
2243 {
2244 	cnode_t *cp = VTOC(vp);
2245 	fscache_t *fscp = C_TO_FSCACHE(cp);
2246 	int error;
2247 	int connected;
2248 	int held = 0;
2249 
2250 	if (getzoneid() != GLOBAL_ZONEID)
2251 		return (EPERM);
2252 
2253 	/*
2254 	 * Cachefs only provides pass-through support for NFSv4,
2255 	 * and all vnode operations are passed through to the
2256 	 * back file system. For NFSv4 pass-through to work, only
2257 	 * connected operation is supported, the cnode backvp must
2258 	 * exist, and cachefs optional (eg., disconnectable) flags
2259 	 * are turned off. Assert these conditions to ensure that
2260 	 * the backfilesystem is called for the setattr operation.
2261 	 */
2262 	CFS_BACKFS_NFSV4_ASSERT_FSCACHE(fscp);
2263 	CFS_BACKFS_NFSV4_ASSERT_CNODE(cp);
2264 
2265 	connected = 0;
2266 	for (;;) {
2267 		/* drop hold on file system */
2268 		if (held) {
2269 			/* Won't loop with NFSv4 connected behavior */
2270 			ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
2271 			cachefs_cd_release(fscp);
2272 			held = 0;
2273 		}
2274 
2275 		/* acquire access to the file system */
2276 		error = cachefs_cd_access(fscp, connected, 1);
2277 		if (error)
2278 			break;
2279 		held = 1;
2280 
2281 		/* perform the setattr */
2282 		error = cachefs_setattr_common(vp, vap, flags, cr, ct);
2283 		if (error) {
2284 			/* if connected */
2285 			if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
2286 				if (CFS_TIMEOUT(fscp, error)) {
2287 					cachefs_cd_release(fscp);
2288 					held = 0;
2289 					cachefs_cd_timedout(fscp);
2290 					connected = 0;
2291 					continue;
2292 				}
2293 			}
2294 
2295 			/* else must be disconnected */
2296 			else {
2297 				if (CFS_TIMEOUT(fscp, error)) {
2298 					connected = 1;
2299 					continue;
2300 				}
2301 			}
2302 		}
2303 		break;
2304 	}
2305 
2306 	if (held) {
2307 		cachefs_cd_release(fscp);
2308 	}
2309 #ifdef CFS_CD_DEBUG
2310 	ASSERT((curthread->t_flag & T_CD_HELD) == 0);
2311 #endif
2312 	return (error);
2313 }
2314 
2315 static int
2316 cachefs_setattr_common(
2317 	vnode_t *vp,
2318 	vattr_t *vap,
2319 	int flags,
2320 	cred_t *cr,
2321 	caller_context_t *ct)
2322 {
2323 	cnode_t *cp = VTOC(vp);
2324 	fscache_t *fscp = C_TO_FSCACHE(cp);
2325 	cachefscache_t *cachep = fscp->fs_cache;
2326 	uint_t mask = vap->va_mask;
2327 	int error = 0;
2328 	uint_t bcnt;
2329 
2330 	/* Cannot set these attributes. */
2331 	if (mask & AT_NOSET)
2332 		return (EINVAL);
2333 
2334 	/*
2335 	 * Truncate file.  Must have write permission and not be a directory.
2336 	 */
2337 	if (mask & AT_SIZE) {
2338 		if (vp->v_type == VDIR) {
2339 			if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_TRUNCATE))
2340 				cachefs_log_truncate(cachep, EISDIR,
2341 				    fscp->fs_cfsvfsp,
2342 				    &cp->c_metadata.md_cookie,
2343 				    cp->c_id.cid_fileno,
2344 				    crgetuid(cr), vap->va_size);
2345 			return (EISDIR);
2346 		}
2347 	}
2348 
2349 	/*
2350 	 * Gotta deal with one special case here, where we're setting the
2351 	 * size of the file. First, we zero out part of the page after the
2352 	 * new size of the file. Then we toss (not write) all pages after
2353 	 * page in which the new offset occurs. Note that the NULL passed
2354 	 * in instead of a putapage() fn parameter is correct, since
2355 	 * no dirty pages will be found (B_TRUNC | B_INVAL).
2356 	 */
2357 
2358 	rw_enter(&cp->c_rwlock, RW_WRITER);
2359 
2360 	/* sync dirty pages */
2361 	if (!CFS_ISFS_BACKFS_NFSV4(fscp)) {
2362 		error = cachefs_putpage_common(vp, (offset_t)0, 0, 0, cr);
2363 		if (error == EINTR)
2364 			goto out;
2365 	}
2366 	error = 0;
2367 
2368 	/* if connected */
2369 	if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
2370 		error = cachefs_setattr_connected(vp, vap, flags, cr, ct);
2371 	}
2372 	/* else must be disconnected */
2373 	else {
2374 		error = cachefs_setattr_disconnected(vp, vap, flags, cr, ct);
2375 	}
2376 	if (error)
2377 		goto out;
2378 
2379 	/*
2380 	 * If the file size has been changed then
2381 	 * toss whole pages beyond the end of the file and zero
2382 	 * the portion of the last page that is beyond the end of the file.
2383 	 */
2384 	if (mask & AT_SIZE && !CFS_ISFS_BACKFS_NFSV4(fscp)) {
2385 		bcnt = (uint_t)(cp->c_size & PAGEOFFSET);
2386 		if (bcnt)
2387 			pvn_vpzero(vp, cp->c_size, PAGESIZE - bcnt);
2388 		(void) pvn_vplist_dirty(vp, cp->c_size, cachefs_push,
2389 		    B_TRUNC | B_INVAL, cr);
2390 	}
2391 
2392 out:
2393 	rw_exit(&cp->c_rwlock);
2394 
2395 	if ((mask & AT_SIZE) &&
2396 	    (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_TRUNCATE)))
2397 		cachefs_log_truncate(cachep, error, fscp->fs_cfsvfsp,
2398 		    &cp->c_metadata.md_cookie, cp->c_id.cid_fileno,
2399 		    crgetuid(cr), vap->va_size);
2400 
2401 	return (error);
2402 }
2403 
2404 static int
2405 cachefs_setattr_connected(
2406 	vnode_t *vp,
2407 	vattr_t *vap,
2408 	int flags,
2409 	cred_t *cr,
2410 	caller_context_t *ct)
2411 {
2412 	cnode_t *cp = VTOC(vp);
2413 	fscache_t *fscp = C_TO_FSCACHE(cp);
2414 	uint_t mask = vap->va_mask;
2415 	int error = 0;
2416 	int setsize;
2417 
2418 	mutex_enter(&cp->c_statelock);
2419 
2420 	if (cp->c_backvp == NULL) {
2421 		error = cachefs_getbackvp(fscp, cp);
2422 		if (error)
2423 			goto out;
2424 	}
2425 
2426 	error = CFSOP_CHECK_COBJECT(fscp, cp, 0, cr);
2427 	if (error)
2428 		goto out;
2429 
2430 	CFS_DPRINT_BACKFS_NFSV4(fscp, ("cachefs_setattr (nfsv4): cnode %p, "
2431 	    "backvp %p\n", cp, cp->c_backvp));
2432 	error = VOP_SETATTR(cp->c_backvp, vap, flags, cr, ct);
2433 	if (error) {
2434 		goto out;
2435 	}
2436 
2437 	/* if the size of the file is being changed */
2438 	if (mask & AT_SIZE) {
2439 		cp->c_size = vap->va_size;
2440 		error = 0;
2441 		setsize = 0;
2442 
2443 		/* see if okay to try to set the file size */
2444 		if (((cp->c_flags & CN_NOCACHE) == 0) &&
2445 		    CFS_ISFS_NONSHARED(fscp)) {
2446 			/* okay to set size if file is populated */
2447 			if (cp->c_metadata.md_flags & MD_POPULATED)
2448 				setsize = 1;
2449 
2450 			/*
2451 			 * Okay to set size if front file exists and setting
2452 			 * file size to zero.
2453 			 */
2454 			if ((cp->c_metadata.md_flags & MD_FILE) &&
2455 			    (vap->va_size == 0))
2456 				setsize = 1;
2457 		}
2458 
2459 		/* if okay to try to set the file size */
2460 		if (setsize) {
2461 			error = 0;
2462 			if (cp->c_frontvp == NULL)
2463 				error = cachefs_getfrontfile(cp);
2464 			if (error == 0)
2465 				error = cachefs_frontfile_size(cp, cp->c_size);
2466 		} else if (cp->c_metadata.md_flags & MD_FILE) {
2467 			/* make sure file gets nocached */
2468 			error = EEXIST;
2469 		}
2470 
2471 		/* if we have to nocache the file */
2472 		if (error) {
2473 			if ((cp->c_flags & CN_NOCACHE) == 0 &&
2474 			    !CFS_ISFS_BACKFS_NFSV4(fscp))
2475 				cachefs_nocache(cp);
2476 			error = 0;
2477 		}
2478 	}
2479 
2480 	cp->c_flags |= CN_UPDATED;
2481 
2482 	/* XXX bob: given what modify_cobject does this seems unnecessary */
2483 	cp->c_attr.va_mask = AT_ALL;
2484 	error = VOP_GETATTR(cp->c_backvp, &cp->c_attr, 0, cr, ct);
2485 	if (error)
2486 		goto out;
2487 
2488 	cp->c_attr.va_size = MAX(cp->c_attr.va_size, cp->c_size);
2489 	cp->c_size = cp->c_attr.va_size;
2490 
2491 	CFSOP_MODIFY_COBJECT(fscp, cp, cr);
2492 out:
2493 	mutex_exit(&cp->c_statelock);
2494 	return (error);
2495 }
2496 
2497 /*
2498  * perform the setattr on the local file system
2499  */
2500 /*ARGSUSED4*/
2501 static int
2502 cachefs_setattr_disconnected(
2503 	vnode_t *vp,
2504 	vattr_t *vap,
2505 	int flags,
2506 	cred_t *cr,
2507 	caller_context_t *ct)
2508 {
2509 	cnode_t *cp = VTOC(vp);
2510 	fscache_t *fscp = C_TO_FSCACHE(cp);
2511 	int mask;
2512 	int error;
2513 	int newfile;
2514 	off_t commit = 0;
2515 
2516 	if (CFS_ISFS_WRITE_AROUND(fscp))
2517 		return (ETIMEDOUT);
2518 
2519 	/* if we do not have good attributes */
2520 	if (cp->c_metadata.md_flags & MD_NEEDATTRS)
2521 		return (ETIMEDOUT);
2522 
2523 	/* primary concern is to keep this routine as much like ufs_setattr */
2524 
2525 	mutex_enter(&cp->c_statelock);
2526 
2527 	error = secpolicy_vnode_setattr(cr, vp, vap, &cp->c_attr, flags,
2528 	    cachefs_access_local, cp);
2529 
2530 	if (error)
2531 		goto out;
2532 
2533 	mask = vap->va_mask;
2534 
2535 	/* if changing the size of the file */
2536 	if (mask & AT_SIZE) {
2537 		if (vp->v_type == VDIR) {
2538 			error = EISDIR;
2539 			goto out;
2540 		}
2541 
2542 		if (vp->v_type == VFIFO) {
2543 			error = 0;
2544 			goto out;
2545 		}
2546 
2547 		if ((vp->v_type != VREG) &&
2548 		    !((vp->v_type == VLNK) && (vap->va_size == 0))) {
2549 			error = EINVAL;
2550 			goto out;
2551 		}
2552 
2553 		if (vap->va_size > fscp->fs_offmax) {
2554 			error = EFBIG;
2555 			goto out;
2556 		}
2557 
2558 		/* if the file is not populated and we are not truncating it */
2559 		if (((cp->c_metadata.md_flags & MD_POPULATED) == 0) &&
2560 		    (vap->va_size != 0)) {
2561 			error = ETIMEDOUT;
2562 			goto out;
2563 		}
2564 
2565 		if ((cp->c_metadata.md_flags & MD_MAPPING) == 0) {
2566 			error = cachefs_dlog_cidmap(fscp);
2567 			if (error) {
2568 				error = ENOSPC;
2569 				goto out;
2570 			}
2571 			cp->c_metadata.md_flags |= MD_MAPPING;
2572 		}
2573 
2574 		/* log the operation */
2575 		commit = cachefs_dlog_setattr(fscp, vap, flags, cp, cr);
2576 		if (commit == 0) {
2577 			error = ENOSPC;
2578 			goto out;
2579 		}
2580 		cp->c_flags &= ~CN_NOCACHE;
2581 
2582 		/* special case truncating fast sym links */
2583 		if ((vp->v_type == VLNK) &&
2584 		    (cp->c_metadata.md_flags & MD_FASTSYMLNK)) {
2585 			/* XXX how can we get here */
2586 			/* XXX should update mtime */
2587 			cp->c_size = 0;
2588 			error = 0;
2589 			goto out;
2590 		}
2591 
2592 		/* get the front file, this may create one */
2593 		newfile = (cp->c_metadata.md_flags & MD_FILE) ? 0 : 1;
2594 		if (cp->c_frontvp == NULL) {
2595 			error = cachefs_getfrontfile(cp);
2596 			if (error)
2597 				goto out;
2598 		}
2599 		ASSERT(cp->c_frontvp);
2600 		if (newfile && (cp->c_flags & CN_UPDATED)) {
2601 			/* allocate space for the metadata */
2602 			ASSERT((cp->c_flags & CN_ALLOC_PENDING) == 0);
2603 			ASSERT((cp->c_filegrp->fg_flags & CFS_FG_ALLOC_ATTR)
2604 			    == 0);
2605 			error = filegrp_write_metadata(cp->c_filegrp,
2606 			    &cp->c_id, &cp->c_metadata);
2607 			if (error)
2608 				goto out;
2609 		}
2610 
2611 		/* change the size of the front file */
2612 		error = cachefs_frontfile_size(cp, vap->va_size);
2613 		if (error)
2614 			goto out;
2615 		cp->c_attr.va_size = cp->c_size = vap->va_size;
2616 		gethrestime(&cp->c_metadata.md_localmtime);
2617 		cp->c_metadata.md_flags |= MD_POPULATED | MD_LOCALMTIME;
2618 		cachefs_modified(cp);
2619 		cp->c_flags |= CN_UPDATED;
2620 	}
2621 
2622 	if (mask & AT_MODE) {
2623 		/* mark as modified */
2624 		if (cachefs_modified_alloc(cp)) {
2625 			error = ENOSPC;
2626 			goto out;
2627 		}
2628 
2629 		if ((cp->c_metadata.md_flags & MD_MAPPING) == 0) {
2630 			error = cachefs_dlog_cidmap(fscp);
2631 			if (error) {
2632 				error = ENOSPC;
2633 				goto out;
2634 			}
2635 			cp->c_metadata.md_flags |= MD_MAPPING;
2636 		}
2637 
2638 		/* log the operation if not already logged */
2639 		if (commit == 0) {
2640 			commit = cachefs_dlog_setattr(fscp, vap, flags, cp, cr);
2641 			if (commit == 0) {
2642 				error = ENOSPC;
2643 				goto out;
2644 			}
2645 		}
2646 
2647 		cp->c_attr.va_mode &= S_IFMT;
2648 		cp->c_attr.va_mode |= vap->va_mode & ~S_IFMT;
2649 		gethrestime(&cp->c_metadata.md_localctime);
2650 		cp->c_metadata.md_flags |= MD_LOCALCTIME;
2651 		cp->c_flags |= CN_UPDATED;
2652 	}
2653 
2654 	if (mask & (AT_UID|AT_GID)) {
2655 
2656 		/* mark as modified */
2657 		if (cachefs_modified_alloc(cp)) {
2658 			error = ENOSPC;
2659 			goto out;
2660 		}
2661 
2662 		if ((cp->c_metadata.md_flags & MD_MAPPING) == 0) {
2663 			error = cachefs_dlog_cidmap(fscp);
2664 			if (error) {
2665 				error = ENOSPC;
2666 				goto out;
2667 			}
2668 			cp->c_metadata.md_flags |= MD_MAPPING;
2669 		}
2670 
2671 		/* log the operation if not already logged */
2672 		if (commit == 0) {
2673 			commit = cachefs_dlog_setattr(fscp, vap, flags, cp, cr);
2674 			if (commit == 0) {
2675 				error = ENOSPC;
2676 				goto out;
2677 			}
2678 		}
2679 
2680 		if (mask & AT_UID)
2681 			cp->c_attr.va_uid = vap->va_uid;
2682 
2683 		if (mask & AT_GID)
2684 			cp->c_attr.va_gid = vap->va_gid;
2685 		gethrestime(&cp->c_metadata.md_localctime);
2686 		cp->c_metadata.md_flags |= MD_LOCALCTIME;
2687 		cp->c_flags |= CN_UPDATED;
2688 	}
2689 
2690 
2691 	if (mask & (AT_MTIME|AT_ATIME)) {
2692 		/* mark as modified */
2693 		if (cachefs_modified_alloc(cp)) {
2694 			error = ENOSPC;
2695 			goto out;
2696 		}
2697 
2698 		if ((cp->c_metadata.md_flags & MD_MAPPING) == 0) {
2699 			error = cachefs_dlog_cidmap(fscp);
2700 			if (error) {
2701 				error = ENOSPC;
2702 				goto out;
2703 			}
2704 			cp->c_metadata.md_flags |= MD_MAPPING;
2705 		}
2706 
2707 		/* log the operation if not already logged */
2708 		if (commit == 0) {
2709 			commit = cachefs_dlog_setattr(fscp, vap, flags, cp, cr);
2710 			if (commit == 0) {
2711 				error = ENOSPC;
2712 				goto out;
2713 			}
2714 		}
2715 
2716 		if (mask & AT_MTIME) {
2717 			cp->c_metadata.md_localmtime = vap->va_mtime;
2718 			cp->c_metadata.md_flags |= MD_LOCALMTIME;
2719 		}
2720 		if (mask & AT_ATIME)
2721 			cp->c_attr.va_atime = vap->va_atime;
2722 		gethrestime(&cp->c_metadata.md_localctime);
2723 		cp->c_metadata.md_flags |= MD_LOCALCTIME;
2724 		cp->c_flags |= CN_UPDATED;
2725 	}
2726 
2727 out:
2728 	mutex_exit(&cp->c_statelock);
2729 
2730 	/* commit the log entry */
2731 	if (commit) {
2732 		if (cachefs_dlog_commit(fscp, commit, error)) {
2733 			/*EMPTY*/
2734 			/* XXX bob: fix on panic */
2735 		}
2736 	}
2737 	return (error);
2738 }
2739 
2740 /* ARGSUSED */
2741 static int
2742 cachefs_access(vnode_t *vp, int mode, int flags, cred_t *cr,
2743 	caller_context_t *ct)
2744 {
2745 	cnode_t *cp = VTOC(vp);
2746 	fscache_t *fscp = C_TO_FSCACHE(cp);
2747 	int error;
2748 	int held = 0;
2749 	int connected = 0;
2750 
2751 #ifdef CFSDEBUG
2752 	CFS_DEBUG(CFSDEBUG_VOPS)
2753 		printf("cachefs_access: ENTER vp %p\n", (void *)vp);
2754 #endif
2755 	if (getzoneid() != GLOBAL_ZONEID) {
2756 		error = EPERM;
2757 		goto out;
2758 	}
2759 
2760 	/*
2761 	 * Cachefs only provides pass-through support for NFSv4,
2762 	 * and all vnode operations are passed through to the
2763 	 * back file system. For NFSv4 pass-through to work, only
2764 	 * connected operation is supported, the cnode backvp must
2765 	 * exist, and cachefs optional (eg., disconnectable) flags
2766 	 * are turned off. Assert these conditions to ensure that
2767 	 * the backfilesystem is called for the access operation.
2768 	 */
2769 	CFS_BACKFS_NFSV4_ASSERT_FSCACHE(fscp);
2770 	CFS_BACKFS_NFSV4_ASSERT_CNODE(cp);
2771 
2772 	for (;;) {
2773 		/* get (or renew) access to the file system */
2774 		if (held) {
2775 			/* Won't loop with NFSv4 connected behavior */
2776 			ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
2777 			cachefs_cd_release(fscp);
2778 			held = 0;
2779 		}
2780 		error = cachefs_cd_access(fscp, connected, 0);
2781 		if (error)
2782 			break;
2783 		held = 1;
2784 
2785 		if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
2786 			error = cachefs_access_connected(vp, mode, flags,
2787 			    cr);
2788 			if (CFS_TIMEOUT(fscp, error)) {
2789 				cachefs_cd_release(fscp);
2790 				held = 0;
2791 				cachefs_cd_timedout(fscp);
2792 				connected = 0;
2793 				continue;
2794 			}
2795 		} else {
2796 			mutex_enter(&cp->c_statelock);
2797 			error = cachefs_access_local(cp, mode, cr);
2798 			mutex_exit(&cp->c_statelock);
2799 			if (CFS_TIMEOUT(fscp, error)) {
2800 				if (cachefs_cd_access_miss(fscp)) {
2801 					mutex_enter(&cp->c_statelock);
2802 					if (cp->c_backvp == NULL) {
2803 						(void) cachefs_getbackvp(fscp,
2804 						    cp);
2805 					}
2806 					mutex_exit(&cp->c_statelock);
2807 					error = cachefs_access_connected(vp,
2808 					    mode, flags, cr);
2809 					if (!CFS_TIMEOUT(fscp, error))
2810 						break;
2811 					delay(5*hz);
2812 					connected = 0;
2813 					continue;
2814 				}
2815 				connected = 1;
2816 				continue;
2817 			}
2818 		}
2819 		break;
2820 	}
2821 	if (held)
2822 		cachefs_cd_release(fscp);
2823 #ifdef CFS_CD_DEBUG
2824 	ASSERT((curthread->t_flag & T_CD_HELD) == 0);
2825 #endif
2826 out:
2827 #ifdef CFSDEBUG
2828 	CFS_DEBUG(CFSDEBUG_VOPS)
2829 		printf("cachefs_access: EXIT error = %d\n", error);
2830 #endif
2831 	return (error);
2832 }
2833 
2834 static int
2835 cachefs_access_connected(struct vnode *vp, int mode, int flags, cred_t *cr)
2836 {
2837 	cnode_t *cp = VTOC(vp);
2838 	fscache_t *fscp = C_TO_FSCACHE(cp);
2839 	int error = 0;
2840 
2841 	mutex_enter(&cp->c_statelock);
2842 
2843 	/* Make sure the cnode attrs are valid first. */
2844 	error = CFSOP_CHECK_COBJECT(fscp, cp, 0, cr);
2845 	if (error)
2846 		goto out;
2847 
2848 	/* see if can do a local file system check */
2849 	if ((fscp->fs_info.fi_mntflags & CFS_ACCESS_BACKFS) == 0 &&
2850 	    !CFS_ISFS_BACKFS_NFSV4(fscp)) {
2851 		error = cachefs_access_local(cp, mode, cr);
2852 		goto out;
2853 	}
2854 
2855 	/* else do a remote file system check */
2856 	else {
2857 		if (cp->c_backvp == NULL) {
2858 			error = cachefs_getbackvp(fscp, cp);
2859 			if (error)
2860 				goto out;
2861 		}
2862 
2863 		CFS_DPRINT_BACKFS_NFSV4(fscp,
2864 		    ("cachefs_access (nfsv4): cnode %p, backvp %p\n",
2865 		    cp, cp->c_backvp));
2866 		error = VOP_ACCESS(cp->c_backvp, mode, flags, cr, NULL);
2867 
2868 		/*
2869 		 * even though we don't `need' the ACL to do access
2870 		 * via the backvp, we should cache it here to make our
2871 		 * behavior more reasonable if we go disconnected.
2872 		 */
2873 
2874 		if (((fscp->fs_info.fi_mntflags & CFS_NOACL) == 0) &&
2875 		    (cachefs_vtype_aclok(vp)) &&
2876 		    ((cp->c_flags & CN_NOCACHE) == 0) &&
2877 		    (!CFS_ISFS_BACKFS_NFSV4(fscp)) &&
2878 		    ((cp->c_metadata.md_flags & MD_ACL) == 0))
2879 			(void) cachefs_cacheacl(cp, NULL);
2880 	}
2881 out:
2882 	/*
2883 	 * If NFS returned ESTALE, mark this cnode as stale, so that
2884 	 * the vn_open retry will read the file anew from backfs
2885 	 */
2886 	if (error == ESTALE)
2887 		cachefs_cnode_stale(cp);
2888 
2889 	mutex_exit(&cp->c_statelock);
2890 	return (error);
2891 }
2892 
2893 /*
2894  * CFS has a fastsymlink scheme. If the size of the link is < C_FSL_SIZE, then
2895  * the link is placed in the metadata itself (no front file is allocated).
2896  */
2897 /*ARGSUSED*/
2898 static int
2899 cachefs_readlink(vnode_t *vp, uio_t *uiop, cred_t *cr, caller_context_t *ct)
2900 {
2901 	int error = 0;
2902 	cnode_t *cp = VTOC(vp);
2903 	fscache_t *fscp = C_TO_FSCACHE(cp);
2904 	cachefscache_t *cachep = fscp->fs_cache;
2905 	int held = 0;
2906 	int connected = 0;
2907 
2908 	if (getzoneid() != GLOBAL_ZONEID)
2909 		return (EPERM);
2910 
2911 	if (vp->v_type != VLNK)
2912 		return (EINVAL);
2913 
2914 	/*
2915 	 * Cachefs only provides pass-through support for NFSv4,
2916 	 * and all vnode operations are passed through to the
2917 	 * back file system. For NFSv4 pass-through to work, only
2918 	 * connected operation is supported, the cnode backvp must
2919 	 * exist, and cachefs optional (eg., disconnectable) flags
2920 	 * are turned off. Assert these conditions to ensure that
2921 	 * the backfilesystem is called for the readlink operation.
2922 	 */
2923 	CFS_BACKFS_NFSV4_ASSERT_FSCACHE(fscp);
2924 	CFS_BACKFS_NFSV4_ASSERT_CNODE(cp);
2925 
2926 	for (;;) {
2927 		/* get (or renew) access to the file system */
2928 		if (held) {
2929 			/* Won't loop with NFSv4 connected behavior */
2930 			ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
2931 			cachefs_cd_release(fscp);
2932 			held = 0;
2933 		}
2934 		error = cachefs_cd_access(fscp, connected, 0);
2935 		if (error)
2936 			break;
2937 		held = 1;
2938 
2939 		if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
2940 			/*
2941 			 * since readlink_connected will call stuffsymlink
2942 			 * on success, have to serialize access
2943 			 */
2944 			if (!rw_tryenter(&cp->c_rwlock, RW_WRITER)) {
2945 				cachefs_cd_release(fscp);
2946 				rw_enter(&cp->c_rwlock, RW_WRITER);
2947 				error = cachefs_cd_access(fscp, connected, 0);
2948 				if (error) {
2949 					held = 0;
2950 					rw_exit(&cp->c_rwlock);
2951 					break;
2952 				}
2953 			}
2954 			error = cachefs_readlink_connected(vp, uiop, cr);
2955 			rw_exit(&cp->c_rwlock);
2956 			if (CFS_TIMEOUT(fscp, error)) {
2957 				cachefs_cd_release(fscp);
2958 				held = 0;
2959 				cachefs_cd_timedout(fscp);
2960 				connected = 0;
2961 				continue;
2962 			}
2963 		} else {
2964 			error = cachefs_readlink_disconnected(vp, uiop);
2965 			if (CFS_TIMEOUT(fscp, error)) {
2966 				if (cachefs_cd_access_miss(fscp)) {
2967 					/* as above */
2968 					if (!rw_tryenter(&cp->c_rwlock,
2969 					    RW_WRITER)) {
2970 						cachefs_cd_release(fscp);
2971 						rw_enter(&cp->c_rwlock,
2972 						    RW_WRITER);
2973 						error = cachefs_cd_access(fscp,
2974 						    connected, 0);
2975 						if (error) {
2976 							held = 0;
2977 							rw_exit(&cp->c_rwlock);
2978 							break;
2979 						}
2980 					}
2981 					error = cachefs_readlink_connected(vp,
2982 					    uiop, cr);
2983 					rw_exit(&cp->c_rwlock);
2984 					if (!CFS_TIMEOUT(fscp, error))
2985 						break;
2986 					delay(5*hz);
2987 					connected = 0;
2988 					continue;
2989 				}
2990 				connected = 1;
2991 				continue;
2992 			}
2993 		}
2994 		break;
2995 	}
2996 	if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_READLINK))
2997 		cachefs_log_readlink(cachep, error, fscp->fs_cfsvfsp,
2998 		    &cp->c_metadata.md_cookie, cp->c_id.cid_fileno,
2999 		    crgetuid(cr), cp->c_size);
3000 
3001 	if (held)
3002 		cachefs_cd_release(fscp);
3003 #ifdef CFS_CD_DEBUG
3004 	ASSERT((curthread->t_flag & T_CD_HELD) == 0);
3005 #endif
3006 
3007 	/*
3008 	 * The over the wire error for attempting to readlink something
3009 	 * other than a symbolic link is ENXIO.  However, we need to
3010 	 * return EINVAL instead of ENXIO, so we map it here.
3011 	 */
3012 	return (error == ENXIO ? EINVAL : error);
3013 }
3014 
3015 static int
3016 cachefs_readlink_connected(vnode_t *vp, uio_t *uiop, cred_t *cr)
3017 {
3018 	int error;
3019 	cnode_t *cp = VTOC(vp);
3020 	fscache_t *fscp = C_TO_FSCACHE(cp);
3021 	caddr_t buf;
3022 	int buflen;
3023 	int readcache = 0;
3024 
3025 	mutex_enter(&cp->c_statelock);
3026 
3027 	error = CFSOP_CHECK_COBJECT(fscp, cp, 0, cr);
3028 	if (error)
3029 		goto out;
3030 
3031 	/* if the sym link is cached as a fast sym link */
3032 	if (cp->c_metadata.md_flags & MD_FASTSYMLNK) {
3033 		ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
3034 		error = uiomove(cp->c_metadata.md_allocinfo,
3035 		    MIN(cp->c_size, uiop->uio_resid), UIO_READ, uiop);
3036 #ifdef CFSDEBUG
3037 		readcache = 1;
3038 		goto out;
3039 #else /* CFSDEBUG */
3040 		/* XXX KLUDGE! correct for insidious 0-len symlink */
3041 		if (cp->c_size != 0) {
3042 			readcache = 1;
3043 			goto out;
3044 		}
3045 #endif /* CFSDEBUG */
3046 	}
3047 
3048 	/* if the sym link is cached in a front file */
3049 	if (cp->c_metadata.md_flags & MD_POPULATED) {
3050 		ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
3051 		ASSERT(cp->c_metadata.md_flags & MD_FILE);
3052 		if (cp->c_frontvp == NULL) {
3053 			(void) cachefs_getfrontfile(cp);
3054 		}
3055 		if (cp->c_metadata.md_flags & MD_POPULATED) {
3056 			/* read symlink data from frontfile */
3057 			uiop->uio_offset = 0;
3058 			(void) VOP_RWLOCK(cp->c_frontvp,
3059 			    V_WRITELOCK_FALSE, NULL);
3060 			error = VOP_READ(cp->c_frontvp, uiop, 0, kcred, NULL);
3061 			VOP_RWUNLOCK(cp->c_frontvp, V_WRITELOCK_FALSE, NULL);
3062 
3063 			/* XXX KLUDGE! correct for insidious 0-len symlink */
3064 			if (cp->c_size != 0) {
3065 				readcache = 1;
3066 				goto out;
3067 			}
3068 		}
3069 	}
3070 
3071 	/* get the sym link contents from the back fs */
3072 	error = cachefs_readlink_back(cp, cr, &buf, &buflen);
3073 	if (error)
3074 		goto out;
3075 
3076 	/* copy the contents out to the user */
3077 	error = uiomove(buf, MIN(buflen, uiop->uio_resid), UIO_READ, uiop);
3078 
3079 	/*
3080 	 * try to cache the sym link, note that its a noop if NOCACHE is set
3081 	 * or if NFSv4 pass-through is enabled.
3082 	 */
3083 	if (cachefs_stuffsymlink(cp, buf, buflen)) {
3084 		cachefs_nocache(cp);
3085 	}
3086 
3087 	cachefs_kmem_free(buf, MAXPATHLEN);
3088 
3089 out:
3090 	mutex_exit(&cp->c_statelock);
3091 	if (error == 0) {
3092 		if (readcache)
3093 			fscp->fs_stats.st_hits++;
3094 		else
3095 			fscp->fs_stats.st_misses++;
3096 	}
3097 	return (error);
3098 }
3099 
3100 static int
3101 cachefs_readlink_disconnected(vnode_t *vp, uio_t *uiop)
3102 {
3103 	int error;
3104 	cnode_t *cp = VTOC(vp);
3105 	fscache_t *fscp = C_TO_FSCACHE(cp);
3106 	int readcache = 0;
3107 
3108 	mutex_enter(&cp->c_statelock);
3109 
3110 	/* if the sym link is cached as a fast sym link */
3111 	if (cp->c_metadata.md_flags & MD_FASTSYMLNK) {
3112 		error = uiomove(cp->c_metadata.md_allocinfo,
3113 		    MIN(cp->c_size, uiop->uio_resid), UIO_READ, uiop);
3114 		readcache = 1;
3115 		goto out;
3116 	}
3117 
3118 	/* if the sym link is cached in a front file */
3119 	if (cp->c_metadata.md_flags & MD_POPULATED) {
3120 		ASSERT(cp->c_metadata.md_flags & MD_FILE);
3121 		if (cp->c_frontvp == NULL) {
3122 			(void) cachefs_getfrontfile(cp);
3123 		}
3124 		if (cp->c_metadata.md_flags & MD_POPULATED) {
3125 			/* read symlink data from frontfile */
3126 			uiop->uio_offset = 0;
3127 			(void) VOP_RWLOCK(cp->c_frontvp,
3128 			    V_WRITELOCK_FALSE, NULL);
3129 			error = VOP_READ(cp->c_frontvp, uiop, 0, kcred, NULL);
3130 			VOP_RWUNLOCK(cp->c_frontvp, V_WRITELOCK_FALSE, NULL);
3131 			readcache = 1;
3132 			goto out;
3133 		}
3134 	}
3135 	error = ETIMEDOUT;
3136 
3137 out:
3138 	mutex_exit(&cp->c_statelock);
3139 	if (error == 0) {
3140 		if (readcache)
3141 			fscp->fs_stats.st_hits++;
3142 		else
3143 			fscp->fs_stats.st_misses++;
3144 	}
3145 	return (error);
3146 }
3147 
3148 /*ARGSUSED*/
3149 static int
3150 cachefs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
3151 {
3152 	cnode_t *cp = VTOC(vp);
3153 	int error = 0;
3154 	fscache_t *fscp = C_TO_FSCACHE(cp);
3155 	int held = 0;
3156 	int connected = 0;
3157 
3158 #ifdef CFSDEBUG
3159 	CFS_DEBUG(CFSDEBUG_VOPS)
3160 		printf("cachefs_fsync: ENTER vp %p\n", (void *)vp);
3161 #endif
3162 
3163 	if (getzoneid() != GLOBAL_ZONEID) {
3164 		error = EPERM;
3165 		goto out;
3166 	}
3167 
3168 	if (fscp->fs_backvfsp && fscp->fs_backvfsp->vfs_flag & VFS_RDONLY)
3169 		goto out;
3170 
3171 	/*
3172 	 * Cachefs only provides pass-through support for NFSv4,
3173 	 * and all vnode operations are passed through to the
3174 	 * back file system. For NFSv4 pass-through to work, only
3175 	 * connected operation is supported, the cnode backvp must
3176 	 * exist, and cachefs optional (eg., disconnectable) flags
3177 	 * are turned off. Assert these conditions to ensure that
3178 	 * the backfilesystem is called for the fsync operation.
3179 	 */
3180 	CFS_BACKFS_NFSV4_ASSERT_FSCACHE(fscp);
3181 	CFS_BACKFS_NFSV4_ASSERT_CNODE(cp);
3182 
3183 	for (;;) {
3184 		/* get (or renew) access to the file system */
3185 		if (held) {
3186 			/* Won't loop with NFSv4 connected behavior */
3187 			ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
3188 			cachefs_cd_release(fscp);
3189 			held = 0;
3190 		}
3191 		error = cachefs_cd_access(fscp, connected, 1);
3192 		if (error)
3193 			break;
3194 		held = 1;
3195 		connected = 0;
3196 
3197 		/* if a regular file, write out the pages */
3198 		if ((vp->v_type == VREG) && vn_has_cached_data(vp) &&
3199 		    !CFS_ISFS_BACKFS_NFSV4(fscp)) {
3200 			error = cachefs_putpage_common(vp, (offset_t)0,
3201 			    0, 0, cr);
3202 			if (CFS_TIMEOUT(fscp, error)) {
3203 				if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
3204 					cachefs_cd_release(fscp);
3205 					held = 0;
3206 					cachefs_cd_timedout(fscp);
3207 					continue;
3208 				} else {
3209 					connected = 1;
3210 					continue;
3211 				}
3212 			}
3213 
3214 			/* if no space left in cache, wait until connected */
3215 			if ((error == ENOSPC) &&
3216 			    (fscp->fs_cdconnected != CFS_CD_CONNECTED)) {
3217 				connected = 1;
3218 				continue;
3219 			}
3220 
3221 			/* clear the cnode error if putpage worked */
3222 			if ((error == 0) && cp->c_error) {
3223 				mutex_enter(&cp->c_statelock);
3224 				cp->c_error = 0;
3225 				mutex_exit(&cp->c_statelock);
3226 			}
3227 
3228 			if (error)
3229 				break;
3230 		}
3231 
3232 		/* if connected, sync the backvp */
3233 		if ((fscp->fs_cdconnected == CFS_CD_CONNECTED) &&
3234 		    cp->c_backvp) {
3235 			mutex_enter(&cp->c_statelock);
3236 			if (cp->c_backvp) {
3237 				CFS_DPRINT_BACKFS_NFSV4(fscp,
3238 				    ("cachefs_fsync (nfsv4): cnode %p, "
3239 				    "backvp %p\n", cp, cp->c_backvp));
3240 				error = VOP_FSYNC(cp->c_backvp, syncflag, cr,
3241 				    ct);
3242 				if (CFS_TIMEOUT(fscp, error)) {
3243 					mutex_exit(&cp->c_statelock);
3244 					cachefs_cd_release(fscp);
3245 					held = 0;
3246 					cachefs_cd_timedout(fscp);
3247 					continue;
3248 				} else if (error && (error != EINTR))
3249 					cp->c_error = error;
3250 			}
3251 			mutex_exit(&cp->c_statelock);
3252 		}
3253 
3254 		/* sync the metadata and the front file to the front fs */
3255 		if (!CFS_ISFS_BACKFS_NFSV4(fscp)) {
3256 			error = cachefs_sync_metadata(cp);
3257 			if (error &&
3258 			    (fscp->fs_cdconnected == CFS_CD_CONNECTED))
3259 				error = 0;
3260 		}
3261 		break;
3262 	}
3263 
3264 	if (error == 0)
3265 		error = cp->c_error;
3266 
3267 	if (held)
3268 		cachefs_cd_release(fscp);
3269 
3270 out:
3271 #ifdef CFS_CD_DEBUG
3272 	ASSERT((curthread->t_flag & T_CD_HELD) == 0);
3273 #endif
3274 
3275 #ifdef CFSDEBUG
3276 	CFS_DEBUG(CFSDEBUG_VOPS)
3277 		printf("cachefs_fsync: EXIT vp %p\n", (void *)vp);
3278 #endif
3279 	return (error);
3280 }
3281 
3282 /*
3283  * Called from cachefs_inactive(), to make sure all the data goes out to disk.
3284  */
3285 int
3286 cachefs_sync_metadata(cnode_t *cp)
3287 {
3288 	int error = 0;
3289 	struct filegrp *fgp;
3290 	struct vattr va;
3291 	fscache_t *fscp = C_TO_FSCACHE(cp);
3292 
3293 #ifdef CFSDEBUG
3294 	CFS_DEBUG(CFSDEBUG_VOPS)
3295 		printf("c_sync_metadata: ENTER cp %p cflag %x\n",
3296 		    (void *)cp, cp->c_flags);
3297 #endif
3298 
3299 	mutex_enter(&cp->c_statelock);
3300 	if ((cp->c_flags & CN_UPDATED) == 0)
3301 		goto out;
3302 	if (cp->c_flags & (CN_STALE | CN_DESTROY))
3303 		goto out;
3304 	fgp = cp->c_filegrp;
3305 	if ((fgp->fg_flags & CFS_FG_WRITE) == 0)
3306 		goto out;
3307 	if (CFS_ISFS_BACKFS_NFSV4(fscp))
3308 		goto out;
3309 
3310 	if (fgp->fg_flags & CFS_FG_ALLOC_ATTR) {
3311 		mutex_exit(&cp->c_statelock);
3312 		error = filegrp_allocattr(fgp);
3313 		mutex_enter(&cp->c_statelock);
3314 		if (error) {
3315 			error = 0;
3316 			goto out;
3317 		}
3318 	}
3319 
3320 	if (cp->c_flags & CN_ALLOC_PENDING) {
3321 		error = filegrp_create_metadata(fgp, &cp->c_metadata,
3322 		    &cp->c_id);
3323 		if (error)
3324 			goto out;
3325 		cp->c_flags &= ~CN_ALLOC_PENDING;
3326 	}
3327 
3328 	if (cp->c_flags & CN_NEED_FRONT_SYNC) {
3329 		if (cp->c_frontvp != NULL) {
3330 			error = VOP_FSYNC(cp->c_frontvp, FSYNC, kcred, NULL);
3331 			if (error) {
3332 				cp->c_metadata.md_timestamp.tv_sec = 0;
3333 			} else {
3334 				va.va_mask = AT_MTIME;
3335 				error = VOP_GETATTR(cp->c_frontvp, &va, 0,
3336 				    kcred, NULL);
3337 				if (error)
3338 					goto out;
3339 				cp->c_metadata.md_timestamp = va.va_mtime;
3340 				cp->c_flags &=
3341 				    ~(CN_NEED_FRONT_SYNC |
3342 				    CN_POPULATION_PENDING);
3343 			}
3344 		} else {
3345 			cp->c_flags &=
3346 			    ~(CN_NEED_FRONT_SYNC | CN_POPULATION_PENDING);
3347 		}
3348 	}
3349 
3350 	/*
3351 	 * XXX tony: How can CN_ALLOC_PENDING still be set??
3352 	 * XXX tony: How can CN_UPDATED not be set?????
3353 	 */
3354 	if ((cp->c_flags & CN_ALLOC_PENDING) == 0 &&
3355 	    (cp->c_flags & CN_UPDATED)) {
3356 		error = filegrp_write_metadata(fgp, &cp->c_id,
3357 		    &cp->c_metadata);
3358 		if (error)
3359 			goto out;
3360 	}
3361 out:
3362 	if (error) {
3363 		/* XXX modified files? */
3364 		if (cp->c_metadata.md_rlno) {
3365 			cachefs_removefrontfile(&cp->c_metadata,
3366 			    &cp->c_id, fgp);
3367 			cachefs_rlent_moveto(C_TO_FSCACHE(cp)->fs_cache,
3368 			    CACHEFS_RL_FREE, cp->c_metadata.md_rlno, 0);
3369 			cp->c_metadata.md_rlno = 0;
3370 			cp->c_metadata.md_rltype = CACHEFS_RL_NONE;
3371 			if (cp->c_frontvp) {
3372 				VN_RELE(cp->c_frontvp);
3373 				cp->c_frontvp = NULL;
3374 			}
3375 		}
3376 		if ((cp->c_flags & CN_ALLOC_PENDING) == 0)
3377 			(void) filegrp_destroy_metadata(fgp, &cp->c_id);
3378 		cp->c_flags |= CN_ALLOC_PENDING;
3379 		cachefs_nocache(cp);
3380 	}
3381 	/*
3382 	 * we clear the updated bit even on errors because a retry
3383 	 * will probably fail also.
3384 	 */
3385 	cp->c_flags &= ~CN_UPDATED;
3386 	mutex_exit(&cp->c_statelock);
3387 
3388 #ifdef CFSDEBUG
3389 	CFS_DEBUG(CFSDEBUG_VOPS)
3390 		printf("c_sync_metadata: EXIT cp %p cflag %x\n",
3391 		    (void *)cp, cp->c_flags);
3392 #endif
3393 
3394 	return (error);
3395 }
3396 
3397 /*
3398  * This is the vop entry point for inactivating a vnode.
3399  * It just queues the request for the async thread which
3400  * calls cachefs_inactive.
3401  * Because of the dnlc, it is not safe to grab most locks here.
3402  */
3403 /*ARGSUSED*/
3404 static void
3405 cachefs_inactive(struct vnode *vp, cred_t *cr, caller_context_t *ct)
3406 {
3407 	cnode_t *cp;
3408 	struct cachefs_req *rp;
3409 	fscache_t *fscp;
3410 
3411 #ifdef CFSDEBUG
3412 	CFS_DEBUG(CFSDEBUG_VOPS)
3413 		printf("cachefs_inactive: ENTER vp %p\n", (void *)vp);
3414 #endif
3415 
3416 	cp = VTOC(vp);
3417 	fscp = C_TO_FSCACHE(cp);
3418 
3419 	ASSERT((cp->c_flags & CN_IDLE) == 0);
3420 
3421 	/*
3422 	 * Cachefs only provides pass-through support for NFSv4,
3423 	 * and all vnode operations are passed through to the
3424 	 * back file system. For NFSv4 pass-through to work, only
3425 	 * connected operation is supported, the cnode backvp must
3426 	 * exist, and cachefs optional (eg., disconnectable) flags
3427 	 * are turned off. Assert these conditions to ensure that
3428 	 * the backfilesystem is called for the inactive operation.
3429 	 */
3430 	CFS_BACKFS_NFSV4_ASSERT_FSCACHE(fscp);
3431 	CFS_BACKFS_NFSV4_ASSERT_CNODE(cp);
3432 
3433 	/* vn_rele() set the v_count == 1 */
3434 
3435 	cp->c_ipending = 1;
3436 
3437 	rp = kmem_cache_alloc(cachefs_req_cache, KM_SLEEP);
3438 	rp->cfs_cmd = CFS_IDLE;
3439 	rp->cfs_cr = cr;
3440 	crhold(rp->cfs_cr);
3441 	rp->cfs_req_u.cu_idle.ci_vp = vp;
3442 	cachefs_addqueue(rp, &(C_TO_FSCACHE(cp)->fs_workq));
3443 
3444 #ifdef CFSDEBUG
3445 	CFS_DEBUG(CFSDEBUG_VOPS)
3446 		printf("cachefs_inactive: EXIT vp %p\n", (void *)vp);
3447 #endif
3448 }
3449 
3450 /* ARGSUSED */
3451 static int
3452 cachefs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp,
3453     struct pathname *pnp, int flags, vnode_t *rdir, cred_t *cr,
3454     caller_context_t *ct, int *direntflags, pathname_t *realpnp)
3455 
3456 {
3457 	int error = 0;
3458 	cnode_t *dcp = VTOC(dvp);
3459 	fscache_t *fscp = C_TO_FSCACHE(dcp);
3460 	int held = 0;
3461 	int connected = 0;
3462 
3463 #ifdef CFSDEBUG
3464 	CFS_DEBUG(CFSDEBUG_VOPS)
3465 		printf("cachefs_lookup: ENTER dvp %p nm %s\n", (void *)dvp, nm);
3466 #endif
3467 
3468 	if (getzoneid() != GLOBAL_ZONEID) {
3469 		error = EPERM;
3470 		goto out;
3471 	}
3472 
3473 	/*
3474 	 * Cachefs only provides pass-through support for NFSv4,
3475 	 * and all vnode operations are passed through to the
3476 	 * back file system. For NFSv4 pass-through to work, only
3477 	 * connected operation is supported, the cnode backvp must
3478 	 * exist, and cachefs optional (eg., disconnectable) flags
3479 	 * are turned off. Assert these conditions to ensure that
3480 	 * the backfilesystem is called for the lookup operation.
3481 	 */
3482 	CFS_BACKFS_NFSV4_ASSERT_FSCACHE(fscp);
3483 	CFS_BACKFS_NFSV4_ASSERT_CNODE(dcp);
3484 
3485 	for (;;) {
3486 		/* get (or renew) access to the file system */
3487 		if (held) {
3488 			/* Won't loop with NFSv4 connected behavior */
3489 			ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
3490 			cachefs_cd_release(fscp);
3491 			held = 0;
3492 		}
3493 		error = cachefs_cd_access(fscp, connected, 0);
3494 		if (error)
3495 			break;
3496 		held = 1;
3497 
3498 		error = cachefs_lookup_common(dvp, nm, vpp, pnp,
3499 			flags, rdir, cr);
3500 		if (CFS_TIMEOUT(fscp, error)) {
3501 			if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
3502 				cachefs_cd_release(fscp);
3503 				held = 0;
3504 				cachefs_cd_timedout(fscp);
3505 				connected = 0;
3506 				continue;
3507 			} else {
3508 				if (cachefs_cd_access_miss(fscp)) {
3509 					rw_enter(&dcp->c_rwlock, RW_READER);
3510 					error = cachefs_lookup_back(dvp, nm,
3511 					    vpp, cr);
3512 					rw_exit(&dcp->c_rwlock);
3513 					if (!CFS_TIMEOUT(fscp, error))
3514 						break;
3515 					delay(5*hz);
3516 					connected = 0;
3517 					continue;
3518 				}
3519 				connected = 1;
3520 				continue;
3521 			}
3522 		}
3523 		break;
3524 	}
3525 	if (held)
3526 		cachefs_cd_release(fscp);
3527 
3528 	if (error == 0 && IS_DEVVP(*vpp)) {
3529 		struct vnode *newvp;
3530 		newvp = specvp(*vpp, (*vpp)->v_rdev, (*vpp)->v_type, cr);
3531 		VN_RELE(*vpp);
3532 		if (newvp == NULL) {
3533 			error = ENOSYS;
3534 		} else {
3535 			*vpp = newvp;
3536 		}
3537 	}
3538 
3539 #ifdef CFS_CD_DEBUG
3540 	ASSERT((curthread->t_flag & T_CD_HELD) == 0);
3541 #endif
3542 out:
3543 #ifdef CFSDEBUG
3544 	CFS_DEBUG(CFSDEBUG_VOPS)
3545 		printf("cachefs_lookup: EXIT error = %d\n", error);
3546 #endif
3547 
3548 	return (error);
3549 }
3550 
3551 /* ARGSUSED */
3552 int
3553 cachefs_lookup_common(vnode_t *dvp, char *nm, vnode_t **vpp,
3554     struct pathname *pnp, int flags, vnode_t *rdir, cred_t *cr)
3555 {
3556 	int error = 0;
3557 	cnode_t *cp, *dcp = VTOC(dvp);
3558 	fscache_t *fscp = C_TO_FSCACHE(dcp);
3559 	struct fid cookie;
3560 	u_offset_t d_offset;
3561 	struct cachefs_req *rp;
3562 	cfs_cid_t cid, dircid;
3563 	uint_t flag;
3564 	uint_t uncached = 0;
3565 
3566 	*vpp = NULL;
3567 
3568 	/*
3569 	 * If lookup is for "", just return dvp.  Don't need
3570 	 * to send it over the wire, look it up in the dnlc,
3571 	 * or perform any access checks.
3572 	 */
3573 	if (*nm == '\0') {
3574 		VN_HOLD(dvp);
3575 		*vpp = dvp;
3576 		return (0);
3577 	}
3578 
3579 	/* can't do lookups in non-directories */
3580 	if (dvp->v_type != VDIR)
3581 		return (ENOTDIR);
3582 
3583 	/* perform access check, also does consistency check if connected */
3584 	if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
3585 		error = cachefs_access_connected(dvp, VEXEC, 0, cr);
3586 	} else {
3587 		mutex_enter(&dcp->c_statelock);
3588 		error = cachefs_access_local(dcp, VEXEC, cr);
3589 		mutex_exit(&dcp->c_statelock);
3590 	}
3591 	if (error)
3592 		return (error);
3593 
3594 	/*
3595 	 * If lookup is for ".", just return dvp.  Don't need
3596 	 * to send it over the wire or look it up in the dnlc,
3597 	 * just need to check access.
3598 	 */
3599 	if (strcmp(nm, ".") == 0) {
3600 		VN_HOLD(dvp);
3601 		*vpp = dvp;
3602 		return (0);
3603 	}
3604 
3605 	/* check the dnlc */
3606 	*vpp = (vnode_t *)dnlc_lookup(dvp, nm);
3607 	if (*vpp)
3608 		return (0);
3609 
3610 	/* read lock the dir before starting the search */
3611 	rw_enter(&dcp->c_rwlock, RW_READER);
3612 
3613 	mutex_enter(&dcp->c_statelock);
3614 	dircid = dcp->c_id;
3615 
3616 	dcp->c_usage++;
3617 
3618 	/* if front file is not usable, lookup on the back fs */
3619 	if ((dcp->c_flags & (CN_NOCACHE | CN_ASYNC_POPULATE)) ||
3620 	    CFS_ISFS_BACKFS_NFSV4(fscp) ||
3621 	    ((dcp->c_filegrp->fg_flags & CFS_FG_READ) == 0)) {
3622 		mutex_exit(&dcp->c_statelock);
3623 		if (fscp->fs_cdconnected == CFS_CD_CONNECTED)
3624 			error = cachefs_lookup_back(dvp, nm, vpp, cr);
3625 		else
3626 			error = ETIMEDOUT;
3627 		goto out;
3628 	}
3629 
3630 	/* if the front file is not populated, try to populate it */
3631 	if ((dcp->c_metadata.md_flags & MD_POPULATED) == 0) {
3632 		if (fscp->fs_cdconnected != CFS_CD_CONNECTED) {
3633 			error = ETIMEDOUT;
3634 			mutex_exit(&dcp->c_statelock);
3635 			goto out;
3636 		}
3637 
3638 		if (cachefs_async_okay()) {
3639 			/* cannot populate if cache is not writable */
3640 			ASSERT((dcp->c_flags &
3641 			    (CN_ASYNC_POPULATE | CN_NOCACHE)) == 0);
3642 			dcp->c_flags |= CN_ASYNC_POPULATE;
3643 
3644 			rp = kmem_cache_alloc(cachefs_req_cache, KM_SLEEP);
3645 			rp->cfs_cmd = CFS_POPULATE;
3646 			rp->cfs_req_u.cu_populate.cpop_vp = dvp;
3647 			rp->cfs_cr = cr;
3648 
3649 			crhold(cr);
3650 			VN_HOLD(dvp);
3651 
3652 			cachefs_addqueue(rp, &fscp->fs_workq);
3653 		} else if (fscp->fs_info.fi_mntflags & CFS_NOACL) {
3654 			error = cachefs_dir_fill(dcp, cr);
3655 			if (error != 0) {
3656 				mutex_exit(&dcp->c_statelock);
3657 				goto out;
3658 			}
3659 		}
3660 		/* no populate if too many asyncs and we have to cache ACLs */
3661 
3662 		mutex_exit(&dcp->c_statelock);
3663 
3664 		if (fscp->fs_cdconnected == CFS_CD_CONNECTED)
3665 			error = cachefs_lookup_back(dvp, nm, vpp, cr);
3666 		else
3667 			error = ETIMEDOUT;
3668 		goto out;
3669 	}
3670 
3671 	/* by now we have a valid cached front file that we can search */
3672 
3673 	ASSERT((dcp->c_flags & CN_ASYNC_POPULATE) == 0);
3674 	error = cachefs_dir_look(dcp, nm, &cookie, &flag,
3675 	    &d_offset, &cid);
3676 	mutex_exit(&dcp->c_statelock);
3677 
3678 	if (error) {
3679 		/* if the entry does not have the fid, go get it */
3680 		if (error == EINVAL) {
3681 			if (fscp->fs_cdconnected == CFS_CD_CONNECTED)
3682 				error = cachefs_lookup_back(dvp, nm, vpp, cr);
3683 			else
3684 				error = ETIMEDOUT;
3685 		}
3686 
3687 		/* errors other than does not exist */
3688 		else if (error != ENOENT) {
3689 			if (fscp->fs_cdconnected == CFS_CD_CONNECTED)
3690 				error = cachefs_lookup_back(dvp, nm, vpp, cr);
3691 			else
3692 				error = ETIMEDOUT;
3693 		}
3694 		goto out;
3695 	}
3696 
3697 	/*
3698 	 * Else we found the entry in the cached directory.
3699 	 * Make a cnode for it.
3700 	 */
3701 	error = cachefs_cnode_make(&cid, fscp, &cookie, NULL, NULL,
3702 	    cr, 0, &cp);
3703 	if (error == ESTALE) {
3704 		ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
3705 		mutex_enter(&dcp->c_statelock);
3706 		cachefs_nocache(dcp);
3707 		mutex_exit(&dcp->c_statelock);
3708 		if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
3709 			error = cachefs_lookup_back(dvp, nm, vpp, cr);
3710 			uncached = 1;
3711 		} else
3712 			error = ETIMEDOUT;
3713 	} else if (error == 0) {
3714 		*vpp = CTOV(cp);
3715 	}
3716 
3717 out:
3718 	if (error == 0) {
3719 		/* put the entry in the dnlc */
3720 		if (cachefs_dnlc)
3721 			dnlc_enter(dvp, nm, *vpp);
3722 
3723 		/* save the cid of the parent so can find the name */
3724 		cp = VTOC(*vpp);
3725 		if (bcmp(&cp->c_metadata.md_parent, &dircid,
3726 		    sizeof (cfs_cid_t)) != 0) {
3727 			mutex_enter(&cp->c_statelock);
3728 			cp->c_metadata.md_parent = dircid;
3729 			cp->c_flags |= CN_UPDATED;
3730 			mutex_exit(&cp->c_statelock);
3731 		}
3732 	}
3733 
3734 	rw_exit(&dcp->c_rwlock);
3735 	if (uncached && dcp->c_metadata.md_flags & MD_PACKED)
3736 		(void) cachefs_pack_common(dvp, cr);
3737 	return (error);
3738 }
3739 
3740 /*
3741  * Called from cachefs_lookup_common when the back file system needs to be
3742  * examined to perform the lookup.
3743  */
3744 static int
3745 cachefs_lookup_back(vnode_t *dvp, char *nm, vnode_t **vpp,
3746     cred_t *cr)
3747 {
3748 	int error = 0;
3749 	cnode_t *cp, *dcp = VTOC(dvp);
3750 	fscache_t *fscp = C_TO_FSCACHE(dcp);
3751 	vnode_t *backvp = NULL;
3752 	struct vattr va;
3753 	struct fid cookie;
3754 	cfs_cid_t cid;
3755 	uint32_t valid_fid;
3756 
3757 	mutex_enter(&dcp->c_statelock);
3758 
3759 	/* do a lookup on the back FS to get the back vnode */
3760 	if (dcp->c_backvp == NULL) {
3761 		error = cachefs_getbackvp(fscp, dcp);
3762 		if (error)
3763 			goto out;
3764 	}
3765 
3766 	CFS_DPRINT_BACKFS_NFSV4(fscp,
3767 	    ("cachefs_lookup (nfsv4): dcp %p, dbackvp %p, name %s\n",
3768 	    dcp, dcp->c_backvp, nm));
3769 	error = VOP_LOOKUP(dcp->c_backvp, nm, &backvp, (struct pathname *)NULL,
3770 	    0, (vnode_t *)NULL, cr, NULL, NULL, NULL);
3771 	if (error)
3772 		goto out;
3773 	if (IS_DEVVP(backvp)) {
3774 		struct vnode *devvp = backvp;
3775 
3776 		if (VOP_REALVP(devvp, &backvp, NULL) == 0) {
3777 			VN_HOLD(backvp);
3778 			VN_RELE(devvp);
3779 		}
3780 	}
3781 
3782 	/* get the fid and attrs from the back fs */
3783 	valid_fid = (CFS_ISFS_BACKFS_NFSV4(fscp) ? FALSE : TRUE);
3784 	error = cachefs_getcookie(backvp, &cookie, &va, cr, valid_fid);
3785 	if (error)
3786 		goto out;
3787 
3788 	cid.cid_fileno = va.va_nodeid;
3789 	cid.cid_flags = 0;
3790 
3791 #if 0
3792 	/* XXX bob: this is probably no longer necessary */
3793 	/* if the directory entry was incomplete, we can complete it now */
3794 	if ((dcp->c_metadata.md_flags & MD_POPULATED) &&
3795 	    ((dcp->c_flags & CN_ASYNC_POPULATE) == 0) &&
3796 	    (dcp->c_filegrp->fg_flags & CFS_FG_WRITE)) {
3797 		cachefs_dir_modentry(dcp, d_offset, &cookie, &cid);
3798 	}
3799 #endif
3800 
3801 out:
3802 	mutex_exit(&dcp->c_statelock);
3803 
3804 	/* create the cnode */
3805 	if (error == 0) {
3806 		error = cachefs_cnode_make(&cid, fscp,
3807 		    (valid_fid ? &cookie : NULL),
3808 		    &va, backvp, cr, 0, &cp);
3809 		if (error == 0) {
3810 			*vpp = CTOV(cp);
3811 		}
3812 	}
3813 
3814 	if (backvp)
3815 		VN_RELE(backvp);
3816 
3817 	return (error);
3818 }
3819 
3820 /*ARGSUSED7*/
3821 static int
3822 cachefs_create(vnode_t *dvp, char *nm, vattr_t *vap,
3823     vcexcl_t exclusive, int mode, vnode_t **vpp, cred_t *cr, int flag,
3824     caller_context_t *ct, vsecattr_t *vsecp)
3825 
3826 {
3827 	cnode_t *dcp = VTOC(dvp);
3828 	fscache_t *fscp = C_TO_FSCACHE(dcp);
3829 	cachefscache_t *cachep = fscp->fs_cache;
3830 	int error;
3831 	int connected = 0;
3832 	int held = 0;
3833 
3834 #ifdef CFSDEBUG
3835 	CFS_DEBUG(CFSDEBUG_VOPS)
3836 		printf("cachefs_create: ENTER dvp %p, nm %s\n",
3837 		    (void *)dvp, nm);
3838 #endif
3839 	if (getzoneid() != GLOBAL_ZONEID) {
3840 		error = EPERM;
3841 		goto out;
3842 	}
3843 
3844 	/*
3845 	 * Cachefs only provides pass-through support for NFSv4,
3846 	 * and all vnode operations are passed through to the
3847 	 * back file system. For NFSv4 pass-through to work, only
3848 	 * connected operation is supported, the cnode backvp must
3849 	 * exist, and cachefs optional (eg., disconnectable) flags
3850 	 * are turned off. Assert these conditions to ensure that
3851 	 * the backfilesystem is called for the create operation.
3852 	 */
3853 	CFS_BACKFS_NFSV4_ASSERT_FSCACHE(fscp);
3854 	CFS_BACKFS_NFSV4_ASSERT_CNODE(dcp);
3855 
3856 	for (;;) {
3857 		/* get (or renew) access to the file system */
3858 		if (held) {
3859 			/* Won't loop with NFSv4 connected behavior */
3860 			ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
3861 			cachefs_cd_release(fscp);
3862 			held = 0;
3863 		}
3864 		error = cachefs_cd_access(fscp, connected, 1);
3865 		if (error)
3866 			break;
3867 		held = 1;
3868 
3869 		/*
3870 		 * if we are connected, perform the remote portion of the
3871 		 * create.
3872 		 */
3873 		if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
3874 			error = cachefs_create_connected(dvp, nm, vap,
3875 			    exclusive, mode, vpp, cr);
3876 			if (CFS_TIMEOUT(fscp, error)) {
3877 				cachefs_cd_release(fscp);
3878 				held = 0;
3879 				cachefs_cd_timedout(fscp);
3880 				connected = 0;
3881 				continue;
3882 			} else if (error) {
3883 				break;
3884 			}
3885 		}
3886 
3887 		/* else we must be disconnected */
3888 		else {
3889 			error = cachefs_create_disconnected(dvp, nm, vap,
3890 			    exclusive, mode, vpp, cr);
3891 			if (CFS_TIMEOUT(fscp, error)) {
3892 				connected = 1;
3893 				continue;
3894 			} else if (error) {
3895 				break;
3896 			}
3897 		}
3898 		break;
3899 	}
3900 
3901 	if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_CREATE)) {
3902 		fid_t *fidp = NULL;
3903 		ino64_t fileno = 0;
3904 		cnode_t *cp = NULL;
3905 		if (error == 0)
3906 			cp = VTOC(*vpp);
3907 
3908 		if (cp != NULL) {
3909 			fidp = &cp->c_metadata.md_cookie;
3910 			fileno = cp->c_id.cid_fileno;
3911 		}
3912 		cachefs_log_create(cachep, error, fscp->fs_cfsvfsp,
3913 		    fidp, fileno, crgetuid(cr));
3914 	}
3915 
3916 	if (held)
3917 		cachefs_cd_release(fscp);
3918 
3919 	if (error == 0 && CFS_ISFS_NONSHARED(fscp))
3920 		(void) cachefs_pack(dvp, nm, cr);
3921 	if (error == 0 && IS_DEVVP(*vpp)) {
3922 		struct vnode *spcvp;
3923 
3924 		spcvp = specvp(*vpp, (*vpp)->v_rdev, (*vpp)->v_type, cr);
3925 		VN_RELE(*vpp);
3926 		if (spcvp == NULL) {
3927 			error = ENOSYS;
3928 		} else {
3929 			*vpp = spcvp;
3930 		}
3931 	}
3932 
3933 #ifdef CFS_CD_DEBUG
3934 	ASSERT((curthread->t_flag & T_CD_HELD) == 0);
3935 #endif
3936 out:
3937 #ifdef CFSDEBUG
3938 	CFS_DEBUG(CFSDEBUG_VOPS)
3939 		printf("cachefs_create: EXIT error %d\n", error);
3940 #endif
3941 	return (error);
3942 }
3943 
3944 
3945 static int
3946 cachefs_create_connected(vnode_t *dvp, char *nm, vattr_t *vap,
3947     enum vcexcl exclusive, int mode, vnode_t **vpp, cred_t *cr)
3948 {
3949 	cnode_t *dcp = VTOC(dvp);
3950 	fscache_t *fscp = C_TO_FSCACHE(dcp);
3951 	int error;
3952 	vnode_t *tvp = NULL;
3953 	vnode_t *devvp;
3954 	fid_t cookie;
3955 	vattr_t va;
3956 	cnode_t *ncp;
3957 	cfs_cid_t cid;
3958 	vnode_t *vp;
3959 	uint32_t valid_fid;
3960 
3961 	/* special case if file already exists */
3962 	error = cachefs_lookup_common(dvp, nm, &vp, NULL, 0, NULL, cr);
3963 	if (CFS_TIMEOUT(fscp, error))
3964 		return (error);
3965 	if (error == 0) {
3966 		if (exclusive == EXCL)
3967 			error = EEXIST;
3968 		else if (vp->v_type == VDIR && (mode & VWRITE))
3969 			error = EISDIR;
3970 		else if ((error =
3971 		    cachefs_access_connected(vp, mode, 0, cr)) == 0) {
3972 			if ((vap->va_mask & AT_SIZE) && (vp->v_type == VREG)) {
3973 				vap->va_mask = AT_SIZE;
3974 				error = cachefs_setattr_common(vp, vap, 0,
3975 				    cr, NULL);
3976 			}
3977 		}
3978 		if (error) {
3979 			VN_RELE(vp);
3980 		} else
3981 			*vpp = vp;
3982 		return (error);
3983 	}
3984 
3985 	rw_enter(&dcp->c_rwlock, RW_WRITER);
3986 	mutex_enter(&dcp->c_statelock);
3987 
3988 	/* consistency check the directory */
3989 	error = CFSOP_CHECK_COBJECT(fscp, dcp, 0, cr);
3990 	if (error) {
3991 		mutex_exit(&dcp->c_statelock);
3992 		goto out;
3993 	}
3994 
3995 	/* get the backvp if necessary */
3996 	if (dcp->c_backvp == NULL) {
3997 		error = cachefs_getbackvp(fscp, dcp);
3998 		if (error) {
3999 			mutex_exit(&dcp->c_statelock);
4000 			goto out;
4001 		}
4002 	}
4003 
4004 	/* create the file on the back fs */
4005 	CFS_DPRINT_BACKFS_NFSV4(fscp,
4006 	    ("cachefs_create (nfsv4): dcp %p, dbackvp %p,"
4007 	    "name %s\n", dcp, dcp->c_backvp, nm));
4008 	error = VOP_CREATE(dcp->c_backvp, nm, vap, exclusive, mode,
4009 	    &devvp, cr, 0, NULL, NULL);
4010 	mutex_exit(&dcp->c_statelock);
4011 	if (error)
4012 		goto out;
4013 	if (VOP_REALVP(devvp, &tvp, NULL) == 0) {
4014 		VN_HOLD(tvp);
4015 		VN_RELE(devvp);
4016 	} else {
4017 		tvp = devvp;
4018 	}
4019 
4020 	/* get the fid and attrs from the back fs */
4021 	valid_fid = (CFS_ISFS_BACKFS_NFSV4(fscp) ? FALSE : TRUE);
4022 	error = cachefs_getcookie(tvp, &cookie, &va, cr, valid_fid);
4023 	if (error)
4024 		goto out;
4025 
4026 	/* make the cnode */
4027 	cid.cid_fileno = va.va_nodeid;
4028 	cid.cid_flags = 0;
4029 	error = cachefs_cnode_make(&cid, fscp, (valid_fid ? &cookie : NULL),
4030 	    &va, tvp, cr, 0, &ncp);
4031 	if (error)
4032 		goto out;
4033 
4034 	*vpp = CTOV(ncp);
4035 
4036 	/* enter it in the parent directory */
4037 	mutex_enter(&dcp->c_statelock);
4038 	if (CFS_ISFS_NONSHARED(fscp) &&
4039 	    (dcp->c_metadata.md_flags & MD_POPULATED)) {
4040 		/* see if entry already exists */
4041 		ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
4042 		error = cachefs_dir_look(dcp, nm, NULL, NULL, NULL, NULL);
4043 		if (error == ENOENT) {
4044 			/* entry, does not exist, add the new file */
4045 			error = cachefs_dir_enter(dcp, nm, &ncp->c_cookie,
4046 			    &ncp->c_id, SM_ASYNC);
4047 			if (error) {
4048 				cachefs_nocache(dcp);
4049 				error = 0;
4050 			}
4051 			/* XXX should this be done elsewhere, too? */
4052 			dnlc_enter(dvp, nm, *vpp);
4053 		} else {
4054 			/* entry exists or some other problem */
4055 			cachefs_nocache(dcp);
4056 			error = 0;
4057 		}
4058 	}
4059 	CFSOP_MODIFY_COBJECT(fscp, dcp, cr);
4060 	mutex_exit(&dcp->c_statelock);
4061 
4062 out:
4063 	rw_exit(&dcp->c_rwlock);
4064 	if (tvp)
4065 		VN_RELE(tvp);
4066 
4067 	return (error);
4068 }
4069 
4070 static int
4071 cachefs_create_disconnected(vnode_t *dvp, char *nm, vattr_t *vap,
4072 	enum vcexcl exclusive, int mode, vnode_t **vpp, cred_t *cr)
4073 {
4074 	cnode_t *dcp = VTOC(dvp);
4075 	cnode_t *cp;
4076 	cnode_t *ncp = NULL;
4077 	vnode_t *vp;
4078 	fscache_t *fscp = C_TO_FSCACHE(dcp);
4079 	int error = 0;
4080 	struct vattr va;
4081 	timestruc_t current_time;
4082 	off_t commit = 0;
4083 	fid_t cookie;
4084 	cfs_cid_t cid;
4085 
4086 	rw_enter(&dcp->c_rwlock, RW_WRITER);
4087 	mutex_enter(&dcp->c_statelock);
4088 
4089 	/* give up if the directory is not populated */
4090 	if ((dcp->c_metadata.md_flags & MD_POPULATED) == 0) {
4091 		mutex_exit(&dcp->c_statelock);
4092 		rw_exit(&dcp->c_rwlock);
4093 		return (ETIMEDOUT);
4094 	}
4095 
4096 	/* special case if file already exists */
4097 	error = cachefs_dir_look(dcp, nm, &cookie, NULL, NULL, &cid);
4098 	if (error == EINVAL) {
4099 		mutex_exit(&dcp->c_statelock);
4100 		rw_exit(&dcp->c_rwlock);
4101 		return (ETIMEDOUT);
4102 	}
4103 	if (error == 0) {
4104 		mutex_exit(&dcp->c_statelock);
4105 		rw_exit(&dcp->c_rwlock);
4106 		error = cachefs_cnode_make(&cid, fscp, &cookie, NULL, NULL,
4107 		    cr, 0, &cp);
4108 		if (error) {
4109 			return (error);
4110 		}
4111 		vp = CTOV(cp);
4112 
4113 		if (cp->c_metadata.md_flags & MD_NEEDATTRS)
4114 			error = ETIMEDOUT;
4115 		else if (exclusive == EXCL)
4116 			error = EEXIST;
4117 		else if (vp->v_type == VDIR && (mode & VWRITE))
4118 			error = EISDIR;
4119 		else {
4120 			mutex_enter(&cp->c_statelock);
4121 			error = cachefs_access_local(cp, mode, cr);
4122 			mutex_exit(&cp->c_statelock);
4123 			if (!error) {
4124 				if ((vap->va_mask & AT_SIZE) &&
4125 				    (vp->v_type == VREG)) {
4126 					vap->va_mask = AT_SIZE;
4127 					error = cachefs_setattr_common(vp,
4128 					    vap, 0, cr, NULL);
4129 				}
4130 			}
4131 		}
4132 		if (error) {
4133 			VN_RELE(vp);
4134 		} else
4135 			*vpp = vp;
4136 		return (error);
4137 	}
4138 
4139 	/* give up if cannot modify the cache */
4140 	if (CFS_ISFS_WRITE_AROUND(fscp)) {
4141 		mutex_exit(&dcp->c_statelock);
4142 		error = ETIMEDOUT;
4143 		goto out;
4144 	}
4145 
4146 	/* check access */
4147 	if (error = cachefs_access_local(dcp, VWRITE, cr)) {
4148 		mutex_exit(&dcp->c_statelock);
4149 		goto out;
4150 	}
4151 
4152 	/* mark dir as modified */
4153 	cachefs_modified(dcp);
4154 	mutex_exit(&dcp->c_statelock);
4155 
4156 	/* must be privileged to set sticky bit */
4157 	if ((vap->va_mode & VSVTX) && secpolicy_vnode_stky_modify(cr) != 0)
4158 		vap->va_mode &= ~VSVTX;
4159 
4160 	/* make up a reasonable set of attributes */
4161 	cachefs_attr_setup(vap, &va, dcp, cr);
4162 
4163 	/* create the cnode */
4164 	error = cachefs_cnode_create(fscp, &va, 0, &ncp);
4165 	if (error)
4166 		goto out;
4167 
4168 	mutex_enter(&ncp->c_statelock);
4169 
4170 	/* get the front file now instead of later */
4171 	if (vap->va_type == VREG) {
4172 		error = cachefs_getfrontfile(ncp);
4173 		if (error) {
4174 			mutex_exit(&ncp->c_statelock);
4175 			goto out;
4176 		}
4177 		ASSERT(ncp->c_frontvp != NULL);
4178 		ASSERT((ncp->c_flags & CN_ALLOC_PENDING) == 0);
4179 		ncp->c_metadata.md_flags |= MD_POPULATED;
4180 	} else {
4181 		ASSERT(ncp->c_flags & CN_ALLOC_PENDING);
4182 		if (ncp->c_filegrp->fg_flags & CFS_FG_ALLOC_ATTR) {
4183 			(void) filegrp_allocattr(ncp->c_filegrp);
4184 		}
4185 		error = filegrp_create_metadata(ncp->c_filegrp,
4186 		    &ncp->c_metadata, &ncp->c_id);
4187 		if (error) {
4188 			mutex_exit(&ncp->c_statelock);
4189 			goto out;
4190 		}
4191 		ncp->c_flags &= ~CN_ALLOC_PENDING;
4192 	}
4193 	mutex_enter(&dcp->c_statelock);
4194 	cachefs_creategid(dcp, ncp, vap, cr);
4195 	cachefs_createacl(dcp, ncp);
4196 	mutex_exit(&dcp->c_statelock);
4197 
4198 	/* set times on the file */
4199 	gethrestime(&current_time);
4200 	ncp->c_metadata.md_vattr.va_atime = current_time;
4201 	ncp->c_metadata.md_localctime = current_time;
4202 	ncp->c_metadata.md_localmtime = current_time;
4203 	ncp->c_metadata.md_flags |= MD_LOCALMTIME | MD_LOCALCTIME;
4204 
4205 	/* reserve space for the daemon cid mapping */
4206 	error = cachefs_dlog_cidmap(fscp);
4207 	if (error) {
4208 		mutex_exit(&ncp->c_statelock);
4209 		goto out;
4210 	}
4211 	ncp->c_metadata.md_flags |= MD_MAPPING;
4212 
4213 	/* mark the new file as modified */
4214 	if (cachefs_modified_alloc(ncp)) {
4215 		mutex_exit(&ncp->c_statelock);
4216 		error = ENOSPC;
4217 		goto out;
4218 	}
4219 	ncp->c_flags |= CN_UPDATED;
4220 
4221 	/*
4222 	 * write the metadata now rather than waiting until
4223 	 * inactive so that if there's no space we can let
4224 	 * the caller know.
4225 	 */
4226 	ASSERT((ncp->c_flags & CN_ALLOC_PENDING) == 0);
4227 	ASSERT((ncp->c_filegrp->fg_flags & CFS_FG_ALLOC_ATTR) == 0);
4228 	error = filegrp_write_metadata(ncp->c_filegrp,
4229 	    &ncp->c_id, &ncp->c_metadata);
4230 	if (error) {
4231 		mutex_exit(&ncp->c_statelock);
4232 		goto out;
4233 	}
4234 
4235 	/* log the operation */
4236 	commit = cachefs_dlog_create(fscp, dcp, nm, vap, exclusive,
4237 	    mode, ncp, 0, cr);
4238 	if (commit == 0) {
4239 		mutex_exit(&ncp->c_statelock);
4240 		error = ENOSPC;
4241 		goto out;
4242 	}
4243 
4244 	mutex_exit(&ncp->c_statelock);
4245 
4246 	mutex_enter(&dcp->c_statelock);
4247 
4248 	/* update parent dir times */
4249 	dcp->c_metadata.md_localmtime = current_time;
4250 	dcp->c_metadata.md_flags |= MD_LOCALMTIME;
4251 	dcp->c_flags |= CN_UPDATED;
4252 
4253 	/* enter new file name in the parent directory */
4254 	if (dcp->c_metadata.md_flags & MD_POPULATED) {
4255 		error = cachefs_dir_enter(dcp, nm, &ncp->c_cookie,
4256 		    &ncp->c_id, 0);
4257 		if (error) {
4258 			cachefs_nocache(dcp);
4259 			mutex_exit(&dcp->c_statelock);
4260 			error = ETIMEDOUT;
4261 			goto out;
4262 		}
4263 		dnlc_enter(dvp, nm, CTOV(ncp));
4264 	} else {
4265 		mutex_exit(&dcp->c_statelock);
4266 		error = ETIMEDOUT;
4267 		goto out;
4268 	}
4269 	mutex_exit(&dcp->c_statelock);
4270 
4271 out:
4272 	rw_exit(&dcp->c_rwlock);
4273 
4274 	if (commit) {
4275 		if (cachefs_dlog_commit(fscp, commit, error)) {
4276 			/*EMPTY*/
4277 			/* XXX bob: fix on panic */
4278 		}
4279 	}
4280 	if (error) {
4281 		/* destroy the cnode we created */
4282 		if (ncp) {
4283 			mutex_enter(&ncp->c_statelock);
4284 			ncp->c_flags |= CN_DESTROY;
4285 			mutex_exit(&ncp->c_statelock);
4286 			VN_RELE(CTOV(ncp));
4287 		}
4288 	} else {
4289 		*vpp = CTOV(ncp);
4290 	}
4291 	return (error);
4292 }
4293 
4294 /*ARGSUSED*/
4295 static int
4296 cachefs_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct,
4297     int flags)
4298 {
4299 	cnode_t *dcp = VTOC(dvp);
4300 	fscache_t *fscp = C_TO_FSCACHE(dcp);
4301 	cachefscache_t *cachep = fscp->fs_cache;
4302 	int error = 0;
4303 	int held = 0;
4304 	int connected = 0;
4305 	size_t namlen;
4306 	vnode_t *vp = NULL;
4307 	int vfslock = 0;
4308 
4309 #ifdef CFSDEBUG
4310 	CFS_DEBUG(CFSDEBUG_VOPS)
4311 		printf("cachefs_remove: ENTER dvp %p name %s\n",
4312 		    (void *)dvp, nm);
4313 #endif
4314 	if (getzoneid() != GLOBAL_ZONEID) {
4315 		error = EPERM;
4316 		goto out;
4317 	}
4318 
4319 	if (fscp->fs_cache->c_flags & (CACHE_NOFILL | CACHE_NOCACHE))
4320 		ASSERT(dcp->c_flags & CN_NOCACHE);
4321 
4322 	/*
4323 	 * Cachefs only provides pass-through support for NFSv4,
4324 	 * and all vnode operations are passed through to the
4325 	 * back file system. For NFSv4 pass-through to work, only
4326 	 * connected operation is supported, the cnode backvp must
4327 	 * exist, and cachefs optional (eg., disconnectable) flags
4328 	 * are turned off. Assert these conditions to ensure that
4329 	 * the backfilesystem is called for the remove operation.
4330 	 */
4331 	CFS_BACKFS_NFSV4_ASSERT_FSCACHE(fscp);
4332 	CFS_BACKFS_NFSV4_ASSERT_CNODE(dcp);
4333 
4334 	for (;;) {
4335 		if (vfslock) {
4336 			vn_vfsunlock(vp);
4337 			vfslock = 0;
4338 		}
4339 		if (vp) {
4340 			VN_RELE(vp);
4341 			vp = NULL;
4342 		}
4343 
4344 		/* get (or renew) access to the file system */
4345 		if (held) {
4346 			/* Won't loop with NFSv4 connected behavior */
4347 			ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
4348 			cachefs_cd_release(fscp);
4349 			held = 0;
4350 		}
4351 		error = cachefs_cd_access(fscp, connected, 1);
4352 		if (error)
4353 			break;
4354 		held = 1;
4355 
4356 		/* if disconnected, do some extra error checking */
4357 		if (fscp->fs_cdconnected != CFS_CD_CONNECTED) {
4358 			/* check permissions */
4359 			mutex_enter(&dcp->c_statelock);
4360 			error = cachefs_access_local(dcp, (VEXEC|VWRITE), cr);
4361 			mutex_exit(&dcp->c_statelock);
4362 			if (CFS_TIMEOUT(fscp, error)) {
4363 				connected = 1;
4364 				continue;
4365 			}
4366 			if (error)
4367 				break;
4368 
4369 			namlen = strlen(nm);
4370 			if (namlen == 0) {
4371 				error = EINVAL;
4372 				break;
4373 			}
4374 
4375 			/* cannot remove . and .. */
4376 			if (nm[0] == '.') {
4377 				if (namlen == 1) {
4378 					error = EINVAL;
4379 					break;
4380 				} else if (namlen == 2 && nm[1] == '.') {
4381 					error = EEXIST;
4382 					break;
4383 				}
4384 			}
4385 
4386 		}
4387 
4388 		/* get the cnode of the file to delete */
4389 		error = cachefs_lookup_common(dvp, nm, &vp, NULL, 0, NULL, cr);
4390 		if (error) {
4391 			if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
4392 				if (CFS_TIMEOUT(fscp, error)) {
4393 					cachefs_cd_release(fscp);
4394 					held = 0;
4395 					cachefs_cd_timedout(fscp);
4396 					connected = 0;
4397 					continue;
4398 				}
4399 			} else {
4400 				if (CFS_TIMEOUT(fscp, error)) {
4401 					connected = 1;
4402 					continue;
4403 				}
4404 			}
4405 			if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_REMOVE)) {
4406 				struct fid foo;
4407 
4408 				bzero(&foo, sizeof (foo));
4409 				cachefs_log_remove(cachep, error,
4410 				    fscp->fs_cfsvfsp, &foo, 0, crgetuid(cr));
4411 			}
4412 			break;
4413 		}
4414 
4415 		if (vp->v_type == VDIR) {
4416 			/* must be privileged to remove dirs with unlink() */
4417 			if ((error = secpolicy_fs_linkdir(cr, vp->v_vfsp)) != 0)
4418 				break;
4419 
4420 			/* see ufs_dirremove for why this is done, mount race */
4421 			if (vn_vfswlock(vp)) {
4422 				error = EBUSY;
4423 				break;
4424 			}
4425 			vfslock = 1;
4426 			if (vn_mountedvfs(vp) != NULL) {
4427 				error = EBUSY;
4428 				break;
4429 			}
4430 		}
4431 
4432 		if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
4433 			error = cachefs_remove_connected(dvp, nm, cr, vp);
4434 			if (CFS_TIMEOUT(fscp, error)) {
4435 				cachefs_cd_release(fscp);
4436 				held = 0;
4437 				cachefs_cd_timedout(fscp);
4438 				connected = 0;
4439 				continue;
4440 			}
4441 		} else {
4442 			error = cachefs_remove_disconnected(dvp, nm, cr,
4443 			    vp);
4444 			if (CFS_TIMEOUT(fscp, error)) {
4445 				connected = 1;
4446 				continue;
4447 			}
4448 		}
4449 		break;
4450 	}
4451 
4452 #if 0
4453 	if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_REMOVE))
4454 		cachefs_log_remove(cachep, error, fscp->fs_cfsvfsp,
4455 		    &cp->c_metadata.md_cookie, cp->c_id.cid_fileno,
4456 		    crgetuid(cr));
4457 #endif
4458 
4459 	if (held)
4460 		cachefs_cd_release(fscp);
4461 
4462 	if (vfslock)
4463 		vn_vfsunlock(vp);
4464 
4465 	if (vp)
4466 		VN_RELE(vp);
4467 
4468 #ifdef CFS_CD_DEBUG
4469 	ASSERT((curthread->t_flag & T_CD_HELD) == 0);
4470 #endif
4471 out:
4472 #ifdef CFSDEBUG
4473 	CFS_DEBUG(CFSDEBUG_VOPS)
4474 		printf("cachefs_remove: EXIT dvp %p\n", (void *)dvp);
4475 #endif
4476 
4477 	return (error);
4478 }
4479 
4480 int
4481 cachefs_remove_connected(vnode_t *dvp, char *nm, cred_t *cr, vnode_t *vp)
4482 {
4483 	cnode_t *dcp = VTOC(dvp);
4484 	cnode_t *cp = VTOC(vp);
4485 	fscache_t *fscp = C_TO_FSCACHE(dcp);
4486 	int error = 0;
4487 
4488 	/*
4489 	 * Acquire the rwlock (WRITER) on the directory to prevent other
4490 	 * activity on the directory.
4491 	 */
4492 	rw_enter(&dcp->c_rwlock, RW_WRITER);
4493 
4494 	/* purge dnlc of this entry so can get accurate vnode count */
4495 	dnlc_purge_vp(vp);
4496 
4497 	/*
4498 	 * If the cnode is active, make a link to the file
4499 	 * so operations on the file will continue.
4500 	 */
4501 	if ((vp->v_type != VDIR) &&
4502 	    !((vp->v_count == 1) || ((vp->v_count == 2) && cp->c_ipending))) {
4503 		error = cachefs_remove_dolink(dvp, vp, nm, cr);
4504 		if (error)
4505 			goto out;
4506 	}
4507 
4508 	/* else call backfs NFSv4 handler if NFSv4 */
4509 	else if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
4510 		error = cachefs_remove_backfs_nfsv4(dvp, nm, cr, vp);
4511 		goto out;
4512 	}
4513 
4514 	/* else drop the backvp so nfs does not do rename */
4515 	else if (cp->c_backvp) {
4516 		mutex_enter(&cp->c_statelock);
4517 		if (cp->c_backvp) {
4518 			VN_RELE(cp->c_backvp);
4519 			cp->c_backvp = NULL;
4520 		}
4521 		mutex_exit(&cp->c_statelock);
4522 	}
4523 
4524 	mutex_enter(&dcp->c_statelock);
4525 
4526 	/* get the backvp */
4527 	if (dcp->c_backvp == NULL) {
4528 		error = cachefs_getbackvp(fscp, dcp);
4529 		if (error) {
4530 			mutex_exit(&dcp->c_statelock);
4531 			goto out;
4532 		}
4533 	}
4534 
4535 	/* check directory consistency */
4536 	error = CFSOP_CHECK_COBJECT(fscp, dcp, 0, cr);
4537 	if (error) {
4538 		mutex_exit(&dcp->c_statelock);
4539 		goto out;
4540 	}
4541 
4542 	/* perform the remove on the back fs */
4543 	error = VOP_REMOVE(dcp->c_backvp, nm, cr, NULL, 0);
4544 	if (error) {
4545 		mutex_exit(&dcp->c_statelock);
4546 		goto out;
4547 	}
4548 
4549 	/* the dir has been modified */
4550 	CFSOP_MODIFY_COBJECT(fscp, dcp, cr);
4551 
4552 	/* remove the entry from the populated directory */
4553 	if (CFS_ISFS_NONSHARED(fscp) &&
4554 	    (dcp->c_metadata.md_flags & MD_POPULATED)) {
4555 		error = cachefs_dir_rmentry(dcp, nm);
4556 		if (error) {
4557 			cachefs_nocache(dcp);
4558 			error = 0;
4559 		}
4560 	}
4561 	mutex_exit(&dcp->c_statelock);
4562 
4563 	/* fix up the file we deleted */
4564 	mutex_enter(&cp->c_statelock);
4565 	if (cp->c_attr.va_nlink == 1)
4566 		cp->c_flags |= CN_DESTROY;
4567 	else
4568 		cp->c_flags |= CN_UPDATED;
4569 
4570 	cp->c_attr.va_nlink--;
4571 	CFSOP_MODIFY_COBJECT(fscp, cp, cr);
4572 	mutex_exit(&cp->c_statelock);
4573 
4574 out:
4575 	rw_exit(&dcp->c_rwlock);
4576 	return (error);
4577 }
4578 
4579 /*
4580  * cachefs_remove_backfs_nfsv4
4581  *
4582  * Call NFSv4 back filesystem to handle the remove (cachefs
4583  * pass-through support for NFSv4).
4584  */
4585 int
4586 cachefs_remove_backfs_nfsv4(vnode_t *dvp, char *nm, cred_t *cr, vnode_t *vp)
4587 {
4588 	cnode_t *dcp = VTOC(dvp);
4589 	cnode_t *cp = VTOC(vp);
4590 	vnode_t *dbackvp;
4591 	fscache_t *fscp = C_TO_FSCACHE(dcp);
4592 	int error = 0;
4593 
4594 	/*
4595 	 * For NFSv4 pass-through to work, only connected operation
4596 	 * is supported, the cnode backvp must exist, and cachefs
4597 	 * optional (eg., disconnectable) flags are turned off. Assert
4598 	 * these conditions for the getattr operation.
4599 	 */
4600 	CFS_BACKFS_NFSV4_ASSERT_FSCACHE(fscp);
4601 	CFS_BACKFS_NFSV4_ASSERT_CNODE(cp);
4602 
4603 	/* Should hold the directory readwrite lock to update directory */
4604 	ASSERT(RW_WRITE_HELD(&dcp->c_rwlock));
4605 
4606 	/*
4607 	 * Update attributes for directory. Note that
4608 	 * CFSOP_CHECK_COBJECT asserts for c_statelock being
4609 	 * held, so grab it before calling the routine.
4610 	 */
4611 	mutex_enter(&dcp->c_statelock);
4612 	error = CFSOP_CHECK_COBJECT(fscp, dcp, 0, cr);
4613 	mutex_exit(&dcp->c_statelock);
4614 	if (error)
4615 		goto out;
4616 
4617 	/*
4618 	 * Update attributes for cp. Note that CFSOP_CHECK_COBJECT
4619 	 * asserts for c_statelock being held, so grab it before
4620 	 * calling the routine.
4621 	 */
4622 	mutex_enter(&cp->c_statelock);
4623 	error = CFSOP_CHECK_COBJECT(fscp, cp, 0, cr);
4624 	if (error) {
4625 		mutex_exit(&cp->c_statelock);
4626 		goto out;
4627 	}
4628 
4629 	/*
4630 	 * Drop the backvp so nfs if the link count is 1 so that
4631 	 * nfs does not do rename. Ensure that we will destroy the cnode
4632 	 * since this cnode no longer contains the backvp. Note that we
4633 	 * maintain lock on this cnode to prevent change till the remove
4634 	 * completes, otherwise other operations will encounter an ESTALE
4635 	 * if they try to use the cnode with CN_DESTROY set (see
4636 	 * cachefs_get_backvp()), or change the state of the cnode
4637 	 * while we're removing it.
4638 	 */
4639 	if (cp->c_attr.va_nlink == 1) {
4640 		/*
4641 		 * The unldvp information is created for the case
4642 		 * when there is more than one reference on the
4643 		 * vnode when a remove operation is called. If the
4644 		 * remove itself was holding a reference to the
4645 		 * vnode, then a subsequent remove will remove the
4646 		 * backvp, so we need to get rid of the unldvp
4647 		 * before removing the backvp. An alternate would
4648 		 * be to simply ignore the remove and let the
4649 		 * inactivation routine do the deletion of the
4650 		 * unldvp.
4651 		 */
4652 		if (cp->c_unldvp) {
4653 			VN_RELE(cp->c_unldvp);
4654 			cachefs_kmem_free(cp->c_unlname, MAXNAMELEN);
4655 			crfree(cp->c_unlcred);
4656 			cp->c_unldvp = NULL;
4657 			cp->c_unlcred = NULL;
4658 		}
4659 		cp->c_flags |= CN_DESTROY;
4660 		cp->c_attr.va_nlink = 0;
4661 		VN_RELE(cp->c_backvp);
4662 		cp->c_backvp = NULL;
4663 	}
4664 
4665 	/* perform the remove on back fs after extracting directory backvp */
4666 	mutex_enter(&dcp->c_statelock);
4667 	dbackvp = dcp->c_backvp;
4668 	mutex_exit(&dcp->c_statelock);
4669 
4670 	CFS_DPRINT_BACKFS_NFSV4(fscp,
4671 	    ("cachefs_remove (nfsv4): dcp %p, dbackvp %p, name %s\n",
4672 	    dcp, dbackvp, nm));
4673 	error = VOP_REMOVE(dbackvp, nm, cr, NULL, 0);
4674 	if (error) {
4675 		mutex_exit(&cp->c_statelock);
4676 		goto out;
4677 	}
4678 
4679 	/* fix up the file we deleted, if not destroying the cnode */
4680 	if ((cp->c_flags & CN_DESTROY) == 0) {
4681 		cp->c_attr.va_nlink--;
4682 		cp->c_flags |= CN_UPDATED;
4683 	}
4684 
4685 	mutex_exit(&cp->c_statelock);
4686 
4687 out:
4688 	return (error);
4689 }
4690 
4691 int
4692 cachefs_remove_disconnected(vnode_t *dvp, char *nm, cred_t *cr,
4693     vnode_t *vp)
4694 {
4695 	cnode_t *dcp = VTOC(dvp);
4696 	cnode_t *cp = VTOC(vp);
4697 	fscache_t *fscp = C_TO_FSCACHE(dcp);
4698 	int error = 0;
4699 	off_t commit = 0;
4700 	timestruc_t current_time;
4701 
4702 	if (CFS_ISFS_WRITE_AROUND(fscp))
4703 		return (ETIMEDOUT);
4704 
4705 	if (cp->c_metadata.md_flags & MD_NEEDATTRS)
4706 		return (ETIMEDOUT);
4707 
4708 	/*
4709 	 * Acquire the rwlock (WRITER) on the directory to prevent other
4710 	 * activity on the directory.
4711 	 */
4712 	rw_enter(&dcp->c_rwlock, RW_WRITER);
4713 
4714 	/* dir must be populated */
4715 	if ((dcp->c_metadata.md_flags & MD_POPULATED) == 0) {
4716 		error = ETIMEDOUT;
4717 		goto out;
4718 	}
4719 
4720 	mutex_enter(&dcp->c_statelock);
4721 	mutex_enter(&cp->c_statelock);
4722 
4723 	error = cachefs_stickyrmchk(dcp, cp, cr);
4724 
4725 	mutex_exit(&cp->c_statelock);
4726 	mutex_exit(&dcp->c_statelock);
4727 	if (error)
4728 		goto out;
4729 
4730 	/* purge dnlc of this entry so can get accurate vnode count */
4731 	dnlc_purge_vp(vp);
4732 
4733 	/*
4734 	 * If the cnode is active, make a link to the file
4735 	 * so operations on the file will continue.
4736 	 */
4737 	if ((vp->v_type != VDIR) &&
4738 	    !((vp->v_count == 1) || ((vp->v_count == 2) && cp->c_ipending))) {
4739 		error = cachefs_remove_dolink(dvp, vp, nm, cr);
4740 		if (error)
4741 			goto out;
4742 	}
4743 
4744 	if (cp->c_attr.va_nlink > 1) {
4745 		mutex_enter(&cp->c_statelock);
4746 		if (cachefs_modified_alloc(cp)) {
4747 			mutex_exit(&cp->c_statelock);
4748 			error = ENOSPC;
4749 			goto out;
4750 		}
4751 		if ((cp->c_metadata.md_flags & MD_MAPPING) == 0) {
4752 			error = cachefs_dlog_cidmap(fscp);
4753 			if (error) {
4754 				mutex_exit(&cp->c_statelock);
4755 				error = ENOSPC;
4756 				goto out;
4757 			}
4758 			cp->c_metadata.md_flags |= MD_MAPPING;
4759 			cp->c_flags |= CN_UPDATED;
4760 		}
4761 		mutex_exit(&cp->c_statelock);
4762 	}
4763 
4764 	/* log the remove */
4765 	commit = cachefs_dlog_remove(fscp, dcp, nm, cp, cr);
4766 	if (commit == 0) {
4767 		error = ENOSPC;
4768 		goto out;
4769 	}
4770 
4771 	/* remove the file from the dir */
4772 	mutex_enter(&dcp->c_statelock);
4773 	if ((dcp->c_metadata.md_flags & MD_POPULATED) == 0) {
4774 		mutex_exit(&dcp->c_statelock);
4775 		error = ETIMEDOUT;
4776 		goto out;
4777 
4778 	}
4779 	cachefs_modified(dcp);
4780 	error = cachefs_dir_rmentry(dcp, nm);
4781 	if (error) {
4782 		mutex_exit(&dcp->c_statelock);
4783 		if (error == ENOTDIR)
4784 			error = ETIMEDOUT;
4785 		goto out;
4786 	}
4787 
4788 	/* update parent dir times */
4789 	gethrestime(&current_time);
4790 	dcp->c_metadata.md_localctime = current_time;
4791 	dcp->c_metadata.md_localmtime = current_time;
4792 	dcp->c_metadata.md_flags |= MD_LOCALCTIME | MD_LOCALMTIME;
4793 	dcp->c_flags |= CN_UPDATED;
4794 	mutex_exit(&dcp->c_statelock);
4795 
4796 	/* adjust file we are deleting */
4797 	mutex_enter(&cp->c_statelock);
4798 	cp->c_attr.va_nlink--;
4799 	cp->c_metadata.md_localctime = current_time;
4800 	cp->c_metadata.md_flags |= MD_LOCALCTIME;
4801 	if (cp->c_attr.va_nlink == 0) {
4802 		cp->c_flags |= CN_DESTROY;
4803 	} else {
4804 		cp->c_flags |= CN_UPDATED;
4805 	}
4806 	mutex_exit(&cp->c_statelock);
4807 
4808 out:
4809 	if (commit) {
4810 		/* commit the log entry */
4811 		if (cachefs_dlog_commit(fscp, commit, error)) {
4812 			/*EMPTY*/
4813 			/* XXX bob: fix on panic */
4814 		}
4815 	}
4816 
4817 	rw_exit(&dcp->c_rwlock);
4818 	return (error);
4819 }
4820 
4821 /*ARGSUSED*/
4822 static int
4823 cachefs_link(vnode_t *tdvp, vnode_t *fvp, char *tnm, cred_t *cr,
4824     caller_context_t *ct, int flags)
4825 {
4826 	fscache_t *fscp = VFS_TO_FSCACHE(tdvp->v_vfsp);
4827 	cnode_t *tdcp = VTOC(tdvp);
4828 	struct vnode *realvp;
4829 	int error = 0;
4830 	int held = 0;
4831 	int connected = 0;
4832 
4833 #ifdef CFSDEBUG
4834 	CFS_DEBUG(CFSDEBUG_VOPS)
4835 		printf("cachefs_link: ENTER fvp %p tdvp %p tnm %s\n",
4836 		    (void *)fvp, (void *)tdvp, tnm);
4837 #endif
4838 
4839 	if (getzoneid() != GLOBAL_ZONEID) {
4840 		error = EPERM;
4841 		goto out;
4842 	}
4843 
4844 	if (fscp->fs_cache->c_flags & (CACHE_NOFILL | CACHE_NOCACHE))
4845 		ASSERT(tdcp->c_flags & CN_NOCACHE);
4846 
4847 	if (VOP_REALVP(fvp, &realvp, ct) == 0) {
4848 		fvp = realvp;
4849 	}
4850 
4851 	/*
4852 	 * Cachefs only provides pass-through support for NFSv4,
4853 	 * and all vnode operations are passed through to the
4854 	 * back file system. For NFSv4 pass-through to work, only
4855 	 * connected operation is supported, the cnode backvp must
4856 	 * exist, and cachefs optional (eg., disconnectable) flags
4857 	 * are turned off. Assert these conditions to ensure that
4858 	 * the backfilesystem is called for the link operation.
4859 	 */
4860 
4861 	CFS_BACKFS_NFSV4_ASSERT_FSCACHE(fscp);
4862 	CFS_BACKFS_NFSV4_ASSERT_CNODE(tdcp);
4863 
4864 	for (;;) {
4865 		/* get (or renew) access to the file system */
4866 		if (held) {
4867 			/* Won't loop with NFSv4 connected behavior */
4868 			ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
4869 			rw_exit(&tdcp->c_rwlock);
4870 			cachefs_cd_release(fscp);
4871 			held = 0;
4872 		}
4873 		error = cachefs_cd_access(fscp, connected, 1);
4874 		if (error)
4875 			break;
4876 		rw_enter(&tdcp->c_rwlock, RW_WRITER);
4877 		held = 1;
4878 
4879 		if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
4880 			error = cachefs_link_connected(tdvp, fvp, tnm, cr);
4881 			if (CFS_TIMEOUT(fscp, error)) {
4882 				rw_exit(&tdcp->c_rwlock);
4883 				cachefs_cd_release(fscp);
4884 				held = 0;
4885 				cachefs_cd_timedout(fscp);
4886 				connected = 0;
4887 				continue;
4888 			}
4889 		} else {
4890 			error = cachefs_link_disconnected(tdvp, fvp, tnm,
4891 			    cr);
4892 			if (CFS_TIMEOUT(fscp, error)) {
4893 				connected = 1;
4894 				continue;
4895 			}
4896 		}
4897 		break;
4898 	}
4899 
4900 	if (held) {
4901 		rw_exit(&tdcp->c_rwlock);
4902 		cachefs_cd_release(fscp);
4903 	}
4904 
4905 #ifdef CFS_CD_DEBUG
4906 	ASSERT((curthread->t_flag & T_CD_HELD) == 0);
4907 #endif
4908 out:
4909 #ifdef CFSDEBUG
4910 	CFS_DEBUG(CFSDEBUG_VOPS)
4911 		printf("cachefs_link: EXIT fvp %p tdvp %p tnm %s\n",
4912 		    (void *)fvp, (void *)tdvp, tnm);
4913 #endif
4914 	return (error);
4915 }
4916 
4917 static int
4918 cachefs_link_connected(vnode_t *tdvp, vnode_t *fvp, char *tnm, cred_t *cr)
4919 {
4920 	cnode_t *tdcp = VTOC(tdvp);
4921 	cnode_t *fcp = VTOC(fvp);
4922 	fscache_t *fscp = VFS_TO_FSCACHE(tdvp->v_vfsp);
4923 	int error = 0;
4924 	vnode_t *backvp = NULL;
4925 
4926 	if (tdcp != fcp) {
4927 		mutex_enter(&fcp->c_statelock);
4928 
4929 		if (fcp->c_backvp == NULL) {
4930 			error = cachefs_getbackvp(fscp, fcp);
4931 			if (error) {
4932 				mutex_exit(&fcp->c_statelock);
4933 				goto out;
4934 			}
4935 		}
4936 
4937 		error = CFSOP_CHECK_COBJECT(fscp, fcp, 0, cr);
4938 		if (error) {
4939 			mutex_exit(&fcp->c_statelock);
4940 			goto out;
4941 		}
4942 		backvp = fcp->c_backvp;
4943 		VN_HOLD(backvp);
4944 		mutex_exit(&fcp->c_statelock);
4945 	}
4946 
4947 	mutex_enter(&tdcp->c_statelock);
4948 
4949 	/* get backvp of target directory */
4950 	if (tdcp->c_backvp == NULL) {
4951 		error = cachefs_getbackvp(fscp, tdcp);
4952 		if (error) {
4953 			mutex_exit(&tdcp->c_statelock);
4954 			goto out;
4955 		}
4956 	}
4957 
4958 	/* consistency check target directory */
4959 	error = CFSOP_CHECK_COBJECT(fscp, tdcp, 0, cr);
4960 	if (error) {
4961 		mutex_exit(&tdcp->c_statelock);
4962 		goto out;
4963 	}
4964 	if (backvp == NULL) {
4965 		backvp = tdcp->c_backvp;
4966 		VN_HOLD(backvp);
4967 	}
4968 
4969 	/* perform the link on the back fs */
4970 	CFS_DPRINT_BACKFS_NFSV4(fscp,
4971 	    ("cachefs_link (nfsv4): tdcp %p, tdbackvp %p, "
4972 	    "name %s\n", tdcp, tdcp->c_backvp, tnm));
4973 	error = VOP_LINK(tdcp->c_backvp, backvp, tnm, cr, NULL, 0);
4974 	if (error) {
4975 		mutex_exit(&tdcp->c_statelock);
4976 		goto out;
4977 	}
4978 
4979 	CFSOP_MODIFY_COBJECT(fscp, tdcp, cr);
4980 
4981 	/* if the dir is populated, add the new link */
4982 	if (CFS_ISFS_NONSHARED(fscp) &&
4983 	    (tdcp->c_metadata.md_flags & MD_POPULATED)) {
4984 		error = cachefs_dir_enter(tdcp, tnm, &fcp->c_cookie,
4985 		    &fcp->c_id, SM_ASYNC);
4986 		if (error) {
4987 			cachefs_nocache(tdcp);
4988 			error = 0;
4989 		}
4990 	}
4991 	mutex_exit(&tdcp->c_statelock);
4992 
4993 	/* get the new link count on the file */
4994 	mutex_enter(&fcp->c_statelock);
4995 	fcp->c_flags |= CN_UPDATED;
4996 	CFSOP_MODIFY_COBJECT(fscp, fcp, cr);
4997 	if (fcp->c_backvp == NULL) {
4998 		error = cachefs_getbackvp(fscp, fcp);
4999 		if (error) {
5000 			mutex_exit(&fcp->c_statelock);
5001 			goto out;
5002 		}
5003 	}
5004 
5005 	/* XXX bob: given what modify_cobject does this seems unnecessary */
5006 	fcp->c_attr.va_mask = AT_ALL;
5007 	error = VOP_GETATTR(fcp->c_backvp, &fcp->c_attr, 0, cr, NULL);
5008 	mutex_exit(&fcp->c_statelock);
5009 out:
5010 	if (backvp)
5011 		VN_RELE(backvp);
5012 
5013 	return (error);
5014 }
5015 
5016 static int
5017 cachefs_link_disconnected(vnode_t *tdvp, vnode_t *fvp, char *tnm,
5018     cred_t *cr)
5019 {
5020 	cnode_t *tdcp = VTOC(tdvp);
5021 	cnode_t *fcp = VTOC(fvp);
5022 	fscache_t *fscp = VFS_TO_FSCACHE(tdvp->v_vfsp);
5023 	int error = 0;
5024 	timestruc_t current_time;
5025 	off_t commit = 0;
5026 
5027 	if (fvp->v_type == VDIR && secpolicy_fs_linkdir(cr, fvp->v_vfsp) != 0 ||
5028 	    fcp->c_attr.va_uid != crgetuid(cr) && secpolicy_basic_link(cr) != 0)
5029 		return (EPERM);
5030 
5031 	if (CFS_ISFS_WRITE_AROUND(fscp))
5032 		return (ETIMEDOUT);
5033 
5034 	if (fcp->c_metadata.md_flags & MD_NEEDATTRS)
5035 		return (ETIMEDOUT);
5036 
5037 	mutex_enter(&tdcp->c_statelock);
5038 
5039 	/* check permissions */
5040 	if (error = cachefs_access_local(tdcp, (VEXEC|VWRITE), cr)) {
5041 		mutex_exit(&tdcp->c_statelock);
5042 		goto out;
5043 	}
5044 
5045 	/* the directory front file must be populated */
5046 	if ((tdcp->c_metadata.md_flags & MD_POPULATED) == 0) {
5047 		error = ETIMEDOUT;
5048 		mutex_exit(&tdcp->c_statelock);
5049 		goto out;
5050 	}
5051 
5052 	/* make sure tnm does not already exist in the directory */
5053 	error = cachefs_dir_look(tdcp, tnm, NULL, NULL, NULL, NULL);
5054 	if (error == ENOTDIR) {
5055 		error = ETIMEDOUT;
5056 		mutex_exit(&tdcp->c_statelock);
5057 		goto out;
5058 	}
5059 	if (error != ENOENT) {
5060 		error = EEXIST;
5061 		mutex_exit(&tdcp->c_statelock);
5062 		goto out;
5063 	}
5064 
5065 	mutex_enter(&fcp->c_statelock);
5066 
5067 	/* create a mapping for the file if necessary */
5068 	if ((fcp->c_metadata.md_flags & MD_MAPPING) == 0) {
5069 		error = cachefs_dlog_cidmap(fscp);
5070 		if (error) {
5071 			mutex_exit(&fcp->c_statelock);
5072 			mutex_exit(&tdcp->c_statelock);
5073 			error = ENOSPC;
5074 			goto out;
5075 		}
5076 		fcp->c_metadata.md_flags |= MD_MAPPING;
5077 		fcp->c_flags |= CN_UPDATED;
5078 	}
5079 
5080 	/* mark file as modified */
5081 	if (cachefs_modified_alloc(fcp)) {
5082 		mutex_exit(&fcp->c_statelock);
5083 		mutex_exit(&tdcp->c_statelock);
5084 		error = ENOSPC;
5085 		goto out;
5086 	}
5087 	mutex_exit(&fcp->c_statelock);
5088 
5089 	/* log the operation */
5090 	commit = cachefs_dlog_link(fscp, tdcp, tnm, fcp, cr);
5091 	if (commit == 0) {
5092 		mutex_exit(&tdcp->c_statelock);
5093 		error = ENOSPC;
5094 		goto out;
5095 	}
5096 
5097 	gethrestime(&current_time);
5098 
5099 	/* make the new link */
5100 	cachefs_modified(tdcp);
5101 	error = cachefs_dir_enter(tdcp, tnm, &fcp->c_cookie,
5102 	    &fcp->c_id, SM_ASYNC);
5103 	if (error) {
5104 		error = 0;
5105 		mutex_exit(&tdcp->c_statelock);
5106 		goto out;
5107 	}
5108 
5109 	/* Update mtime/ctime of parent dir */
5110 	tdcp->c_metadata.md_localmtime = current_time;
5111 	tdcp->c_metadata.md_localctime = current_time;
5112 	tdcp->c_metadata.md_flags |= MD_LOCALCTIME | MD_LOCALMTIME;
5113 	tdcp->c_flags |= CN_UPDATED;
5114 	mutex_exit(&tdcp->c_statelock);
5115 
5116 	/* update the file we linked to */
5117 	mutex_enter(&fcp->c_statelock);
5118 	fcp->c_attr.va_nlink++;
5119 	fcp->c_metadata.md_localctime = current_time;
5120 	fcp->c_metadata.md_flags |= MD_LOCALCTIME;
5121 	fcp->c_flags |= CN_UPDATED;
5122 	mutex_exit(&fcp->c_statelock);
5123 
5124 out:
5125 	if (commit) {
5126 		/* commit the log entry */
5127 		if (cachefs_dlog_commit(fscp, commit, error)) {
5128 			/*EMPTY*/
5129 			/* XXX bob: fix on panic */
5130 		}
5131 	}
5132 
5133 	return (error);
5134 }
5135 
5136 /*
5137  * Serialize all renames in CFS, to avoid deadlocks - We have to hold two
5138  * cnodes atomically.
5139  */
5140 kmutex_t cachefs_rename_lock;
5141 
5142 /*ARGSUSED*/
5143 static int
5144 cachefs_rename(vnode_t *odvp, char *onm, vnode_t *ndvp,
5145     char *nnm, cred_t *cr, caller_context_t *ct, int flags)
5146 {
5147 	fscache_t *fscp = C_TO_FSCACHE(VTOC(odvp));
5148 	cachefscache_t *cachep = fscp->fs_cache;
5149 	int error = 0;
5150 	int held = 0;
5151 	int connected = 0;
5152 	vnode_t *delvp = NULL;
5153 	vnode_t *tvp = NULL;
5154 	int vfslock = 0;
5155 	struct vnode *realvp;
5156 
5157 	if (getzoneid() != GLOBAL_ZONEID)
5158 		return (EPERM);
5159 
5160 	if (VOP_REALVP(ndvp, &realvp, ct) == 0)
5161 		ndvp = realvp;
5162 
5163 	/*
5164 	 * if the fs NOFILL or NOCACHE flags are on, then the old and new
5165 	 * directory cnodes better indicate NOCACHE mode as well.
5166 	 */
5167 	ASSERT(
5168 	    (fscp->fs_cache->c_flags & (CACHE_NOFILL | CACHE_NOCACHE)) == 0 ||
5169 	    ((VTOC(odvp)->c_flags & CN_NOCACHE) &&
5170 	    (VTOC(ndvp)->c_flags & CN_NOCACHE)));
5171 
5172 	/*
5173 	 * Cachefs only provides pass-through support for NFSv4,
5174 	 * and all vnode operations are passed through to the
5175 	 * back file system. For NFSv4 pass-through to work, only
5176 	 * connected operation is supported, the cnode backvp must
5177 	 * exist, and cachefs optional (eg., disconnectable) flags
5178 	 * are turned off. Assert these conditions to ensure that
5179 	 * the backfilesystem is called for the rename operation.
5180 	 */
5181 	CFS_BACKFS_NFSV4_ASSERT_FSCACHE(fscp);
5182 	CFS_BACKFS_NFSV4_ASSERT_CNODE(VTOC(odvp));
5183 	CFS_BACKFS_NFSV4_ASSERT_CNODE(VTOC(ndvp));
5184 
5185 	for (;;) {
5186 		if (vfslock) {
5187 			vn_vfsunlock(delvp);
5188 			vfslock = 0;
5189 		}
5190 		if (delvp) {
5191 			VN_RELE(delvp);
5192 			delvp = NULL;
5193 		}
5194 
5195 		/* get (or renew) access to the file system */
5196 		if (held) {
5197 			/* Won't loop for NFSv4 connected support */
5198 			ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
5199 			cachefs_cd_release(fscp);
5200 			held = 0;
5201 		}
5202 		error = cachefs_cd_access(fscp, connected, 1);
5203 		if (error)
5204 			break;
5205 		held = 1;
5206 
5207 		/* sanity check */
5208 		if ((odvp->v_type != VDIR) || (ndvp->v_type != VDIR)) {
5209 			error = EINVAL;
5210 			break;
5211 		}
5212 
5213 		/* cannot rename from or to . or .. */
5214 		if (strcmp(onm, ".") == 0 || strcmp(onm, "..") == 0 ||
5215 		    strcmp(nnm, ".") == 0 || strcmp(nnm, "..") == 0) {
5216 			error = EINVAL;
5217 			break;
5218 		}
5219 
5220 		if (odvp != ndvp) {
5221 			/*
5222 			 * if moving a directory, its notion
5223 			 * of ".." will change
5224 			 */
5225 			error = cachefs_lookup_common(odvp, onm, &tvp,
5226 			    NULL, 0, NULL, cr);
5227 			if (error == 0) {
5228 				ASSERT(tvp != NULL);
5229 				if (tvp->v_type == VDIR) {
5230 					cnode_t *cp = VTOC(tvp);
5231 
5232 					dnlc_remove(tvp, "..");
5233 
5234 					mutex_enter(&cp->c_statelock);
5235 					CFSOP_MODIFY_COBJECT(fscp, cp, cr);
5236 					mutex_exit(&cp->c_statelock);
5237 				}
5238 			} else {
5239 				tvp = NULL;
5240 				if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
5241 					if (CFS_TIMEOUT(fscp, error)) {
5242 						cachefs_cd_release(fscp);
5243 						held = 0;
5244 						cachefs_cd_timedout(fscp);
5245 						connected = 0;
5246 						continue;
5247 					}
5248 				} else {
5249 					if (CFS_TIMEOUT(fscp, error)) {
5250 						connected = 1;
5251 						continue;
5252 					}
5253 				}
5254 				break;
5255 			}
5256 		}
5257 
5258 		/* get the cnode if file being deleted */
5259 		error = cachefs_lookup_common(ndvp, nnm, &delvp, NULL, 0,
5260 		    NULL, cr);
5261 		if (error) {
5262 			delvp = NULL;
5263 			if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
5264 				if (CFS_TIMEOUT(fscp, error)) {
5265 					cachefs_cd_release(fscp);
5266 					held = 0;
5267 					cachefs_cd_timedout(fscp);
5268 					connected = 0;
5269 					continue;
5270 				}
5271 			} else {
5272 				if (CFS_TIMEOUT(fscp, error)) {
5273 					connected = 1;
5274 					continue;
5275 				}
5276 			}
5277 			if (error != ENOENT)
5278 				break;
5279 		}
5280 
5281 		if (delvp && delvp->v_type == VDIR) {
5282 			/* see ufs_dirremove for why this is done, mount race */
5283 			if (vn_vfswlock(delvp)) {
5284 				error = EBUSY;
5285 				break;
5286 			}
5287 			vfslock = 1;
5288 			if (vn_mountedvfs(delvp) != NULL) {
5289 				error = EBUSY;
5290 				break;
5291 			}
5292 		}
5293 
5294 		if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
5295 			error = cachefs_rename_connected(odvp, onm,
5296 			    ndvp, nnm, cr, delvp);
5297 			if (CFS_TIMEOUT(fscp, error)) {
5298 				cachefs_cd_release(fscp);
5299 				held = 0;
5300 				cachefs_cd_timedout(fscp);
5301 				connected = 0;
5302 				continue;
5303 			}
5304 		} else {
5305 			error = cachefs_rename_disconnected(odvp, onm,
5306 			    ndvp, nnm, cr, delvp);
5307 			if (CFS_TIMEOUT(fscp, error)) {
5308 				connected = 1;
5309 				continue;
5310 			}
5311 		}
5312 		break;
5313 	}
5314 
5315 	if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_RENAME)) {
5316 		struct fid gone;
5317 
5318 		bzero(&gone, sizeof (gone));
5319 		gone.fid_len = MAXFIDSZ;
5320 		if (delvp != NULL)
5321 			(void) VOP_FID(delvp, &gone, ct);
5322 
5323 		cachefs_log_rename(cachep, error, fscp->fs_cfsvfsp,
5324 		    &gone, 0, (delvp != NULL), crgetuid(cr));
5325 	}
5326 
5327 	if (held)
5328 		cachefs_cd_release(fscp);
5329 
5330 	if (vfslock)
5331 		vn_vfsunlock(delvp);
5332 
5333 	if (delvp)
5334 		VN_RELE(delvp);
5335 	if (tvp)
5336 		VN_RELE(tvp);
5337 
5338 #ifdef CFS_CD_DEBUG
5339 	ASSERT((curthread->t_flag & T_CD_HELD) == 0);
5340 #endif
5341 	return (error);
5342 }
5343 
5344 static int
5345 cachefs_rename_connected(vnode_t *odvp, char *onm, vnode_t *ndvp,
5346     char *nnm, cred_t *cr, vnode_t *delvp)
5347 {
5348 	cnode_t *odcp = VTOC(odvp);
5349 	cnode_t *ndcp = VTOC(ndvp);
5350 	vnode_t *revp = NULL;
5351 	cnode_t *recp;
5352 	cnode_t *delcp;
5353 	fscache_t *fscp = C_TO_FSCACHE(odcp);
5354 	int error = 0;
5355 	struct fid cookie;
5356 	struct fid *cookiep;
5357 	cfs_cid_t cid;
5358 	int gotdirent;
5359 
5360 	/* find the file we are renaming */
5361 	error = cachefs_lookup_common(odvp, onm, &revp, NULL, 0, NULL, cr);
5362 	if (error)
5363 		return (error);
5364 	recp = VTOC(revp);
5365 
5366 	/*
5367 	 * To avoid deadlock, we acquire this global rename lock before
5368 	 * we try to get the locks for the source and target directories.
5369 	 */
5370 	mutex_enter(&cachefs_rename_lock);
5371 	rw_enter(&odcp->c_rwlock, RW_WRITER);
5372 	if (odcp != ndcp) {
5373 		rw_enter(&ndcp->c_rwlock, RW_WRITER);
5374 	}
5375 	mutex_exit(&cachefs_rename_lock);
5376 
5377 	ASSERT((odcp->c_flags & CN_ASYNC_POP_WORKING) == 0);
5378 	ASSERT((ndcp->c_flags & CN_ASYNC_POP_WORKING) == 0);
5379 
5380 	mutex_enter(&odcp->c_statelock);
5381 	if (odcp->c_backvp == NULL) {
5382 		error = cachefs_getbackvp(fscp, odcp);
5383 		if (error) {
5384 			mutex_exit(&odcp->c_statelock);
5385 			goto out;
5386 		}
5387 	}
5388 
5389 	error = CFSOP_CHECK_COBJECT(fscp, odcp, 0, cr);
5390 	if (error) {
5391 		mutex_exit(&odcp->c_statelock);
5392 		goto out;
5393 	}
5394 	mutex_exit(&odcp->c_statelock);
5395 
5396 	if (odcp != ndcp) {
5397 		mutex_enter(&ndcp->c_statelock);
5398 		if (ndcp->c_backvp == NULL) {
5399 			error = cachefs_getbackvp(fscp, ndcp);
5400 			if (error) {
5401 				mutex_exit(&ndcp->c_statelock);
5402 				goto out;
5403 			}
5404 		}
5405 
5406 		error = CFSOP_CHECK_COBJECT(fscp, ndcp, 0, cr);
5407 		if (error) {
5408 			mutex_exit(&ndcp->c_statelock);
5409 			goto out;
5410 		}
5411 		mutex_exit(&ndcp->c_statelock);
5412 	}
5413 
5414 	/* if a file is being deleted because of this rename */
5415 	if (delvp) {
5416 		/* if src and dest file are same */
5417 		if (delvp == revp) {
5418 			error = 0;
5419 			goto out;
5420 		}
5421 
5422 		/*
5423 		 * If the cnode is active, make a link to the file
5424 		 * so operations on the file will continue.
5425 		 */
5426 		dnlc_purge_vp(delvp);
5427 		delcp = VTOC(delvp);
5428 		if ((delvp->v_type != VDIR) &&
5429 		    !((delvp->v_count == 1) ||
5430 		    ((delvp->v_count == 2) && delcp->c_ipending))) {
5431 			error = cachefs_remove_dolink(ndvp, delvp, nnm, cr);
5432 			if (error)
5433 				goto out;
5434 		}
5435 	}
5436 
5437 	/* do the rename on the back fs */
5438 	CFS_DPRINT_BACKFS_NFSV4(fscp,
5439 	    ("cachefs_rename (nfsv4): odcp %p, odbackvp %p, "
5440 	    " ndcp %p, ndbackvp %p, onm %s, nnm %s\n",
5441 	    odcp, odcp->c_backvp, ndcp, ndcp->c_backvp, onm, nnm));
5442 	error = VOP_RENAME(odcp->c_backvp, onm, ndcp->c_backvp, nnm, cr, NULL,
5443 	    0);
5444 	if (error)
5445 		goto out;
5446 
5447 	/* purge mappings to file in the old directory */
5448 	dnlc_purge_vp(odvp);
5449 
5450 	/* purge mappings in the new dir if we deleted a file */
5451 	if (delvp && (odvp != ndvp))
5452 		dnlc_purge_vp(ndvp);
5453 
5454 	/* update the file we just deleted */
5455 	if (delvp) {
5456 		mutex_enter(&delcp->c_statelock);
5457 		if (delcp->c_attr.va_nlink == 1) {
5458 			delcp->c_flags |= CN_DESTROY;
5459 		} else {
5460 			delcp->c_flags |= CN_UPDATED;
5461 		}
5462 		delcp->c_attr.va_nlink--;
5463 		CFSOP_MODIFY_COBJECT(fscp, delcp, cr);
5464 		mutex_exit(&delcp->c_statelock);
5465 	}
5466 
5467 	/* find the entry in the old directory */
5468 	mutex_enter(&odcp->c_statelock);
5469 	gotdirent = 0;
5470 	cookiep = NULL;
5471 	if (CFS_ISFS_NONSHARED(fscp) &&
5472 	    (odcp->c_metadata.md_flags & MD_POPULATED)) {
5473 		error = cachefs_dir_look(odcp, onm, &cookie,
5474 		    NULL, NULL, &cid);
5475 		if (error == 0 || error == EINVAL) {
5476 			gotdirent = 1;
5477 			if (error == 0)
5478 				cookiep = &cookie;
5479 		} else {
5480 			cachefs_inval_object(odcp);
5481 		}
5482 	}
5483 	error = 0;
5484 
5485 	/* remove the directory entry from the old directory */
5486 	if (gotdirent) {
5487 		error = cachefs_dir_rmentry(odcp, onm);
5488 		if (error) {
5489 			cachefs_nocache(odcp);
5490 			error = 0;
5491 		}
5492 	}
5493 	CFSOP_MODIFY_COBJECT(fscp, odcp, cr);
5494 	mutex_exit(&odcp->c_statelock);
5495 
5496 	/* install the directory entry in the new directory */
5497 	mutex_enter(&ndcp->c_statelock);
5498 	if (CFS_ISFS_NONSHARED(fscp) &&
5499 	    (ndcp->c_metadata.md_flags & MD_POPULATED)) {
5500 		error = 1;
5501 		if (gotdirent) {
5502 			ASSERT(cid.cid_fileno != 0);
5503 			error = 0;
5504 			if (delvp) {
5505 				error = cachefs_dir_rmentry(ndcp, nnm);
5506 			}
5507 			if (error == 0) {
5508 				error = cachefs_dir_enter(ndcp, nnm, cookiep,
5509 				    &cid, SM_ASYNC);
5510 			}
5511 		}
5512 		if (error) {
5513 			cachefs_nocache(ndcp);
5514 			error = 0;
5515 		}
5516 	}
5517 	if (odcp != ndcp)
5518 		CFSOP_MODIFY_COBJECT(fscp, ndcp, cr);
5519 	mutex_exit(&ndcp->c_statelock);
5520 
5521 	/* ctime of renamed file has changed */
5522 	mutex_enter(&recp->c_statelock);
5523 	CFSOP_MODIFY_COBJECT(fscp, recp, cr);
5524 	mutex_exit(&recp->c_statelock);
5525 
5526 out:
5527 	if (odcp != ndcp)
5528 		rw_exit(&ndcp->c_rwlock);
5529 	rw_exit(&odcp->c_rwlock);
5530 
5531 	VN_RELE(revp);
5532 
5533 	return (error);
5534 }
5535 
5536 static int
5537 cachefs_rename_disconnected(vnode_t *odvp, char *onm, vnode_t *ndvp,
5538     char *nnm, cred_t *cr, vnode_t *delvp)
5539 {
5540 	cnode_t *odcp = VTOC(odvp);
5541 	cnode_t *ndcp = VTOC(ndvp);
5542 	cnode_t *delcp = NULL;
5543 	vnode_t *revp = NULL;
5544 	cnode_t *recp;
5545 	fscache_t *fscp = C_TO_FSCACHE(odcp);
5546 	int error = 0;
5547 	struct fid cookie;
5548 	struct fid *cookiep;
5549 	cfs_cid_t cid;
5550 	off_t commit = 0;
5551 	timestruc_t current_time;
5552 
5553 	if (CFS_ISFS_WRITE_AROUND(fscp))
5554 		return (ETIMEDOUT);
5555 
5556 	/* find the file we are renaming */
5557 	error = cachefs_lookup_common(odvp, onm, &revp, NULL, 0, NULL, cr);
5558 	if (error)
5559 		return (error);
5560 	recp = VTOC(revp);
5561 
5562 	/*
5563 	 * To avoid deadlock, we acquire this global rename lock before
5564 	 * we try to get the locks for the source and target directories.
5565 	 */
5566 	mutex_enter(&cachefs_rename_lock);
5567 	rw_enter(&odcp->c_rwlock, RW_WRITER);
5568 	if (odcp != ndcp) {
5569 		rw_enter(&ndcp->c_rwlock, RW_WRITER);
5570 	}
5571 	mutex_exit(&cachefs_rename_lock);
5572 
5573 	if (recp->c_metadata.md_flags & MD_NEEDATTRS) {
5574 		error = ETIMEDOUT;
5575 		goto out;
5576 	}
5577 
5578 	if ((recp->c_metadata.md_flags & MD_MAPPING) == 0) {
5579 		mutex_enter(&recp->c_statelock);
5580 		if ((recp->c_metadata.md_flags & MD_MAPPING) == 0) {
5581 			error = cachefs_dlog_cidmap(fscp);
5582 			if (error) {
5583 				mutex_exit(&recp->c_statelock);
5584 				error = ENOSPC;
5585 				goto out;
5586 			}
5587 			recp->c_metadata.md_flags |= MD_MAPPING;
5588 			recp->c_flags |= CN_UPDATED;
5589 		}
5590 		mutex_exit(&recp->c_statelock);
5591 	}
5592 
5593 	/* check permissions */
5594 	/* XXX clean up this mutex junk sometime */
5595 	mutex_enter(&odcp->c_statelock);
5596 	error = cachefs_access_local(odcp, (VEXEC|VWRITE), cr);
5597 	mutex_exit(&odcp->c_statelock);
5598 	if (error != 0)
5599 		goto out;
5600 	mutex_enter(&ndcp->c_statelock);
5601 	error = cachefs_access_local(ndcp, (VEXEC|VWRITE), cr);
5602 	mutex_exit(&ndcp->c_statelock);
5603 	if (error != 0)
5604 		goto out;
5605 	mutex_enter(&odcp->c_statelock);
5606 	error = cachefs_stickyrmchk(odcp, recp, cr);
5607 	mutex_exit(&odcp->c_statelock);
5608 	if (error != 0)
5609 		goto out;
5610 
5611 	/* dirs must be populated */
5612 	if (((odcp->c_metadata.md_flags & MD_POPULATED) == 0) ||
5613 	    ((ndcp->c_metadata.md_flags & MD_POPULATED) == 0)) {
5614 		error = ETIMEDOUT;
5615 		goto out;
5616 	}
5617 
5618 	/* for now do not allow moving dirs because could cause cycles */
5619 	if ((((revp->v_type == VDIR) && (odvp != ndvp))) ||
5620 	    (revp == odvp)) {
5621 		error = ETIMEDOUT;
5622 		goto out;
5623 	}
5624 
5625 	/* if a file is being deleted because of this rename */
5626 	if (delvp) {
5627 		delcp = VTOC(delvp);
5628 
5629 		/* if src and dest file are the same */
5630 		if (delvp == revp) {
5631 			error = 0;
5632 			goto out;
5633 		}
5634 
5635 		if (delcp->c_metadata.md_flags & MD_NEEDATTRS) {
5636 			error = ETIMEDOUT;
5637 			goto out;
5638 		}
5639 
5640 		/* if there are hard links to this file */
5641 		if (delcp->c_attr.va_nlink > 1) {
5642 			mutex_enter(&delcp->c_statelock);
5643 			if (cachefs_modified_alloc(delcp)) {
5644 				mutex_exit(&delcp->c_statelock);
5645 				error = ENOSPC;
5646 				goto out;
5647 			}
5648 
5649 			if ((delcp->c_metadata.md_flags & MD_MAPPING) == 0) {
5650 				error = cachefs_dlog_cidmap(fscp);
5651 				if (error) {
5652 					mutex_exit(&delcp->c_statelock);
5653 					error = ENOSPC;
5654 					goto out;
5655 				}
5656 				delcp->c_metadata.md_flags |= MD_MAPPING;
5657 				delcp->c_flags |= CN_UPDATED;
5658 			}
5659 			mutex_exit(&delcp->c_statelock);
5660 		}
5661 
5662 		/* make sure we can delete file */
5663 		mutex_enter(&ndcp->c_statelock);
5664 		error = cachefs_stickyrmchk(ndcp, delcp, cr);
5665 		mutex_exit(&ndcp->c_statelock);
5666 		if (error != 0)
5667 			goto out;
5668 
5669 		/*
5670 		 * If the cnode is active, make a link to the file
5671 		 * so operations on the file will continue.
5672 		 */
5673 		dnlc_purge_vp(delvp);
5674 		if ((delvp->v_type != VDIR) &&
5675 		    !((delvp->v_count == 1) ||
5676 		    ((delvp->v_count == 2) && delcp->c_ipending))) {
5677 			error = cachefs_remove_dolink(ndvp, delvp, nnm, cr);
5678 			if (error)
5679 				goto out;
5680 		}
5681 	}
5682 
5683 	/* purge mappings to file in the old directory */
5684 	dnlc_purge_vp(odvp);
5685 
5686 	/* purge mappings in the new dir if we deleted a file */
5687 	if (delvp && (odvp != ndvp))
5688 		dnlc_purge_vp(ndvp);
5689 
5690 	/* find the entry in the old directory */
5691 	mutex_enter(&odcp->c_statelock);
5692 	if ((odcp->c_metadata.md_flags & MD_POPULATED) == 0) {
5693 		mutex_exit(&odcp->c_statelock);
5694 		error = ETIMEDOUT;
5695 		goto out;
5696 	}
5697 	cookiep = NULL;
5698 	error = cachefs_dir_look(odcp, onm, &cookie, NULL, NULL, &cid);
5699 	if (error == 0 || error == EINVAL) {
5700 		if (error == 0)
5701 			cookiep = &cookie;
5702 	} else {
5703 		mutex_exit(&odcp->c_statelock);
5704 		if (error == ENOTDIR)
5705 			error = ETIMEDOUT;
5706 		goto out;
5707 	}
5708 	error = 0;
5709 
5710 	/* write the log entry */
5711 	commit = cachefs_dlog_rename(fscp, odcp, onm, ndcp, nnm, cr,
5712 	    recp, delcp);
5713 	if (commit == 0) {
5714 		mutex_exit(&odcp->c_statelock);
5715 		error = ENOSPC;
5716 		goto out;
5717 	}
5718 
5719 	/* remove the directory entry from the old directory */
5720 	cachefs_modified(odcp);
5721 	error = cachefs_dir_rmentry(odcp, onm);
5722 	if (error) {
5723 		mutex_exit(&odcp->c_statelock);
5724 		if (error == ENOTDIR)
5725 			error = ETIMEDOUT;
5726 		goto out;
5727 	}
5728 	mutex_exit(&odcp->c_statelock);
5729 
5730 	/* install the directory entry in the new directory */
5731 	mutex_enter(&ndcp->c_statelock);
5732 	error = ENOTDIR;
5733 	if (ndcp->c_metadata.md_flags & MD_POPULATED) {
5734 		ASSERT(cid.cid_fileno != 0);
5735 		cachefs_modified(ndcp);
5736 		error = 0;
5737 		if (delvp) {
5738 			error = cachefs_dir_rmentry(ndcp, nnm);
5739 		}
5740 		if (error == 0) {
5741 			error = cachefs_dir_enter(ndcp, nnm, cookiep,
5742 			    &cid, SM_ASYNC);
5743 		}
5744 	}
5745 	if (error) {
5746 		cachefs_nocache(ndcp);
5747 		mutex_exit(&ndcp->c_statelock);
5748 		mutex_enter(&odcp->c_statelock);
5749 		cachefs_nocache(odcp);
5750 		mutex_exit(&odcp->c_statelock);
5751 		if (error == ENOTDIR)
5752 			error = ETIMEDOUT;
5753 		goto out;
5754 	}
5755 	mutex_exit(&ndcp->c_statelock);
5756 
5757 	gethrestime(&current_time);
5758 
5759 	/* update the file we just deleted */
5760 	if (delvp) {
5761 		mutex_enter(&delcp->c_statelock);
5762 		delcp->c_attr.va_nlink--;
5763 		delcp->c_metadata.md_localctime = current_time;
5764 		delcp->c_metadata.md_flags |= MD_LOCALCTIME;
5765 		if (delcp->c_attr.va_nlink == 0) {
5766 			delcp->c_flags |= CN_DESTROY;
5767 		} else {
5768 			delcp->c_flags |= CN_UPDATED;
5769 		}
5770 		mutex_exit(&delcp->c_statelock);
5771 	}
5772 
5773 	/* update the file we renamed */
5774 	mutex_enter(&recp->c_statelock);
5775 	recp->c_metadata.md_localctime = current_time;
5776 	recp->c_metadata.md_flags |= MD_LOCALCTIME;
5777 	recp->c_flags |= CN_UPDATED;
5778 	mutex_exit(&recp->c_statelock);
5779 
5780 	/* update the source directory */
5781 	mutex_enter(&odcp->c_statelock);
5782 	odcp->c_metadata.md_localctime = current_time;
5783 	odcp->c_metadata.md_localmtime = current_time;
5784 	odcp->c_metadata.md_flags |= MD_LOCALCTIME | MD_LOCALMTIME;
5785 	odcp->c_flags |= CN_UPDATED;
5786 	mutex_exit(&odcp->c_statelock);
5787 
5788 	/* update the destination directory */
5789 	if (odcp != ndcp) {
5790 		mutex_enter(&ndcp->c_statelock);
5791 		ndcp->c_metadata.md_localctime = current_time;
5792 		ndcp->c_metadata.md_localmtime = current_time;
5793 		ndcp->c_metadata.md_flags |= MD_LOCALCTIME | MD_LOCALMTIME;
5794 		ndcp->c_flags |= CN_UPDATED;
5795 		mutex_exit(&ndcp->c_statelock);
5796 	}
5797 
5798 out:
5799 	if (commit) {
5800 		/* commit the log entry */
5801 		if (cachefs_dlog_commit(fscp, commit, error)) {
5802 			/*EMPTY*/
5803 			/* XXX bob: fix on panic */
5804 		}
5805 	}
5806 
5807 	if (odcp != ndcp)
5808 		rw_exit(&ndcp->c_rwlock);
5809 	rw_exit(&odcp->c_rwlock);
5810 
5811 	VN_RELE(revp);
5812 
5813 	return (error);
5814 }
5815 
5816 /*ARGSUSED*/
5817 static int
5818 cachefs_mkdir(vnode_t *dvp, char *nm, vattr_t *vap, vnode_t **vpp,
5819     cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp)
5820 {
5821 	cnode_t *dcp = VTOC(dvp);
5822 	fscache_t *fscp = C_TO_FSCACHE(dcp);
5823 	cachefscache_t *cachep = fscp->fs_cache;
5824 	int error = 0;
5825 	int held = 0;
5826 	int connected = 0;
5827 
5828 #ifdef CFSDEBUG
5829 	CFS_DEBUG(CFSDEBUG_VOPS)
5830 		printf("cachefs_mkdir: ENTER dvp %p\n", (void *)dvp);
5831 #endif
5832 
5833 	if (getzoneid() != GLOBAL_ZONEID) {
5834 		error = EPERM;
5835 		goto out;
5836 	}
5837 
5838 	if (fscp->fs_cache->c_flags & (CACHE_NOFILL | CACHE_NOCACHE))
5839 		ASSERT(dcp->c_flags & CN_NOCACHE);
5840 
5841 	/*
5842 	 * Cachefs only provides pass-through support for NFSv4,
5843 	 * and all vnode operations are passed through to the
5844 	 * back file system. For NFSv4 pass-through to work, only
5845 	 * connected operation is supported, the cnode backvp must
5846 	 * exist, and cachefs optional (eg., disconnectable) flags
5847 	 * are turned off. Assert these conditions to ensure that
5848 	 * the backfilesystem is called for the mkdir operation.
5849 	 */
5850 	CFS_BACKFS_NFSV4_ASSERT_FSCACHE(fscp);
5851 	CFS_BACKFS_NFSV4_ASSERT_CNODE(dcp);
5852 
5853 	for (;;) {
5854 		/* get (or renew) access to the file system */
5855 		if (held) {
5856 			/* Won't loop with NFSv4 connected behavior */
5857 			ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
5858 			rw_exit(&dcp->c_rwlock);
5859 			cachefs_cd_release(fscp);
5860 			held = 0;
5861 		}
5862 		error = cachefs_cd_access(fscp, connected, 1);
5863 		if (error)
5864 			break;
5865 		rw_enter(&dcp->c_rwlock, RW_WRITER);
5866 		held = 1;
5867 
5868 		if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
5869 			error = cachefs_mkdir_connected(dvp, nm, vap,
5870 			    vpp, cr);
5871 			if (CFS_TIMEOUT(fscp, error)) {
5872 				rw_exit(&dcp->c_rwlock);
5873 				cachefs_cd_release(fscp);
5874 				held = 0;
5875 				cachefs_cd_timedout(fscp);
5876 				connected = 0;
5877 				continue;
5878 			}
5879 		} else {
5880 			error = cachefs_mkdir_disconnected(dvp, nm, vap,
5881 			    vpp, cr);
5882 			if (CFS_TIMEOUT(fscp, error)) {
5883 				connected = 1;
5884 				continue;
5885 			}
5886 		}
5887 		break;
5888 	}
5889 
5890 	if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_MKDIR)) {
5891 		fid_t *fidp = NULL;
5892 		ino64_t fileno = 0;
5893 		cnode_t *cp = NULL;
5894 		if (error == 0)
5895 			cp = VTOC(*vpp);
5896 
5897 		if (cp != NULL) {
5898 			fidp = &cp->c_metadata.md_cookie;
5899 			fileno = cp->c_id.cid_fileno;
5900 		}
5901 
5902 		cachefs_log_mkdir(cachep, error, fscp->fs_cfsvfsp,
5903 		    fidp, fileno, crgetuid(cr));
5904 	}
5905 
5906 	if (held) {
5907 		rw_exit(&dcp->c_rwlock);
5908 		cachefs_cd_release(fscp);
5909 	}
5910 	if (error == 0 && CFS_ISFS_NONSHARED(fscp))
5911 		(void) cachefs_pack(dvp, nm, cr);
5912 
5913 #ifdef CFS_CD_DEBUG
5914 	ASSERT((curthread->t_flag & T_CD_HELD) == 0);
5915 #endif
5916 out:
5917 #ifdef CFSDEBUG
5918 	CFS_DEBUG(CFSDEBUG_VOPS)
5919 		printf("cachefs_mkdir: EXIT error = %d\n", error);
5920 #endif
5921 	return (error);
5922 }
5923 
5924 static int
5925 cachefs_mkdir_connected(vnode_t *dvp, char *nm, vattr_t *vap,
5926     vnode_t **vpp, cred_t *cr)
5927 {
5928 	cnode_t *newcp = NULL, *dcp = VTOC(dvp);
5929 	struct vnode *vp = NULL;
5930 	int error = 0;
5931 	fscache_t *fscp = C_TO_FSCACHE(dcp);
5932 	struct fid cookie;
5933 	struct vattr attr;
5934 	cfs_cid_t cid, dircid;
5935 	uint32_t valid_fid;
5936 
5937 	if (fscp->fs_cache->c_flags & (CACHE_NOFILL | CACHE_NOCACHE))
5938 		ASSERT(dcp->c_flags & CN_NOCACHE);
5939 
5940 	mutex_enter(&dcp->c_statelock);
5941 
5942 	/* get backvp of dir */
5943 	if (dcp->c_backvp == NULL) {
5944 		error = cachefs_getbackvp(fscp, dcp);
5945 		if (error) {
5946 			mutex_exit(&dcp->c_statelock);
5947 			goto out;
5948 		}
5949 	}
5950 
5951 	/* consistency check the directory */
5952 	error = CFSOP_CHECK_COBJECT(fscp, dcp, 0, cr);
5953 	if (error) {
5954 		mutex_exit(&dcp->c_statelock);
5955 		goto out;
5956 	}
5957 	dircid = dcp->c_id;
5958 
5959 	/* make the dir on the back fs */
5960 	CFS_DPRINT_BACKFS_NFSV4(fscp,
5961 	    ("cachefs_mkdir (nfsv4): dcp %p, dbackvp %p, "
5962 	    "name %s\n", dcp, dcp->c_backvp, nm));
5963 	error = VOP_MKDIR(dcp->c_backvp, nm, vap, &vp, cr, NULL, 0, NULL);
5964 	mutex_exit(&dcp->c_statelock);
5965 	if (error) {
5966 		goto out;
5967 	}
5968 
5969 	/* get the cookie and make the cnode */
5970 	attr.va_mask = AT_ALL;
5971 	valid_fid = (CFS_ISFS_BACKFS_NFSV4(fscp) ? FALSE : TRUE);
5972 	error = cachefs_getcookie(vp, &cookie, &attr, cr, valid_fid);
5973 	if (error) {
5974 		goto out;
5975 	}
5976 	cid.cid_flags = 0;
5977 	cid.cid_fileno = attr.va_nodeid;
5978 	error = cachefs_cnode_make(&cid, fscp, (valid_fid ? &cookie : NULL),
5979 	    &attr, vp, cr, 0, &newcp);
5980 	if (error) {
5981 		goto out;
5982 	}
5983 	ASSERT(CTOV(newcp)->v_type == VDIR);
5984 	*vpp = CTOV(newcp);
5985 
5986 	/* if the dir is populated, add the new entry */
5987 	mutex_enter(&dcp->c_statelock);
5988 	if (CFS_ISFS_NONSHARED(fscp) &&
5989 	    (dcp->c_metadata.md_flags & MD_POPULATED)) {
5990 		error = cachefs_dir_enter(dcp, nm, &cookie, &newcp->c_id,
5991 		    SM_ASYNC);
5992 		if (error) {
5993 			cachefs_nocache(dcp);
5994 			error = 0;
5995 		}
5996 	}
5997 	dcp->c_attr.va_nlink++;
5998 	dcp->c_flags |= CN_UPDATED;
5999 	CFSOP_MODIFY_COBJECT(fscp, dcp, cr);
6000 	mutex_exit(&dcp->c_statelock);
6001 
6002 	/* XXX bob: should we do a filldir here? or just add . and .. */
6003 	/* maybe should kick off an async filldir so caller does not wait */
6004 
6005 	/* put the entry in the dnlc */
6006 	if (cachefs_dnlc)
6007 		dnlc_enter(dvp, nm, *vpp);
6008 
6009 	/* save the fileno of the parent so can find the name */
6010 	if (bcmp(&newcp->c_metadata.md_parent, &dircid,
6011 	    sizeof (cfs_cid_t)) != 0) {
6012 		mutex_enter(&newcp->c_statelock);
6013 		newcp->c_metadata.md_parent = dircid;
6014 		newcp->c_flags |= CN_UPDATED;
6015 		mutex_exit(&newcp->c_statelock);
6016 	}
6017 out:
6018 	if (vp)
6019 		VN_RELE(vp);
6020 
6021 	return (error);
6022 }
6023 
6024 static int
6025 cachefs_mkdir_disconnected(vnode_t *dvp, char *nm, vattr_t *vap,
6026     vnode_t **vpp, cred_t *cr)
6027 {
6028 	cnode_t *dcp = VTOC(dvp);
6029 	fscache_t *fscp = C_TO_FSCACHE(dcp);
6030 	int error;
6031 	cnode_t *newcp = NULL;
6032 	struct vattr va;
6033 	timestruc_t current_time;
6034 	off_t commit = 0;
6035 	char *s;
6036 	int namlen;
6037 
6038 	/* don't allow '/' characters in pathname component */
6039 	for (s = nm, namlen = 0; *s; s++, namlen++)
6040 		if (*s == '/')
6041 			return (EACCES);
6042 	if (namlen == 0)
6043 		return (EINVAL);
6044 
6045 	if (CFS_ISFS_WRITE_AROUND(fscp))
6046 		return (ETIMEDOUT);
6047 
6048 	mutex_enter(&dcp->c_statelock);
6049 
6050 	/* check permissions */
6051 	if (error = cachefs_access_local(dcp, (VEXEC|VWRITE), cr)) {
6052 		mutex_exit(&dcp->c_statelock);
6053 		goto out;
6054 	}
6055 
6056 	/* the directory front file must be populated */
6057 	if ((dcp->c_metadata.md_flags & MD_POPULATED) == 0) {
6058 		error = ETIMEDOUT;
6059 		mutex_exit(&dcp->c_statelock);
6060 		goto out;
6061 	}
6062 
6063 	/* make sure nm does not already exist in the directory */
6064 	error = cachefs_dir_look(dcp, nm, NULL, NULL, NULL, NULL);
6065 	if (error == ENOTDIR) {
6066 		error = ETIMEDOUT;
6067 		mutex_exit(&dcp->c_statelock);
6068 		goto out;
6069 	}
6070 	if (error != ENOENT) {
6071 		error = EEXIST;
6072 		mutex_exit(&dcp->c_statelock);
6073 		goto out;
6074 	}
6075 
6076 	/* make up a reasonable set of attributes */
6077 	cachefs_attr_setup(vap, &va, dcp, cr);
6078 	va.va_type = VDIR;
6079 	va.va_mode |= S_IFDIR;
6080 	va.va_nlink = 2;
6081 
6082 	mutex_exit(&dcp->c_statelock);
6083 
6084 	/* create the cnode */
6085 	error = cachefs_cnode_create(fscp, &va, 0, &newcp);
6086 	if (error)
6087 		goto out;
6088 
6089 	mutex_enter(&newcp->c_statelock);
6090 
6091 	error = cachefs_dlog_cidmap(fscp);
6092 	if (error) {
6093 		mutex_exit(&newcp->c_statelock);
6094 		goto out;
6095 	}
6096 
6097 	cachefs_creategid(dcp, newcp, vap, cr);
6098 	mutex_enter(&dcp->c_statelock);
6099 	cachefs_createacl(dcp, newcp);
6100 	mutex_exit(&dcp->c_statelock);
6101 	gethrestime(&current_time);
6102 	newcp->c_metadata.md_vattr.va_atime = current_time;
6103 	newcp->c_metadata.md_localctime = current_time;
6104 	newcp->c_metadata.md_localmtime = current_time;
6105 	newcp->c_metadata.md_flags |= MD_MAPPING | MD_LOCALMTIME |
6106 	    MD_LOCALCTIME;
6107 	newcp->c_flags |= CN_UPDATED;
6108 
6109 	/* make a front file for the new directory, add . and .. */
6110 	error = cachefs_dir_new(dcp, newcp);
6111 	if (error) {
6112 		mutex_exit(&newcp->c_statelock);
6113 		goto out;
6114 	}
6115 	cachefs_modified(newcp);
6116 
6117 	/*
6118 	 * write the metadata now rather than waiting until
6119 	 * inactive so that if there's no space we can let
6120 	 * the caller know.
6121 	 */
6122 	ASSERT(newcp->c_frontvp);
6123 	ASSERT((newcp->c_filegrp->fg_flags & CFS_FG_ALLOC_ATTR) == 0);
6124 	ASSERT((newcp->c_flags & CN_ALLOC_PENDING) == 0);
6125 	error = filegrp_write_metadata(newcp->c_filegrp,
6126 	    &newcp->c_id, &newcp->c_metadata);
6127 	if (error) {
6128 		mutex_exit(&newcp->c_statelock);
6129 		goto out;
6130 	}
6131 	mutex_exit(&newcp->c_statelock);
6132 
6133 	/* log the operation */
6134 	commit = cachefs_dlog_mkdir(fscp, dcp, newcp, nm, &va, cr);
6135 	if (commit == 0) {
6136 		error = ENOSPC;
6137 		goto out;
6138 	}
6139 
6140 	mutex_enter(&dcp->c_statelock);
6141 
6142 	/* make sure directory is still populated */
6143 	if ((dcp->c_metadata.md_flags & MD_POPULATED) == 0) {
6144 		mutex_exit(&dcp->c_statelock);
6145 		error = ETIMEDOUT;
6146 		goto out;
6147 	}
6148 	cachefs_modified(dcp);
6149 
6150 	/* enter the new file in the directory */
6151 	error = cachefs_dir_enter(dcp, nm, &newcp->c_metadata.md_cookie,
6152 	    &newcp->c_id, SM_ASYNC);
6153 	if (error) {
6154 		mutex_exit(&dcp->c_statelock);
6155 		goto out;
6156 	}
6157 
6158 	/* update parent dir times */
6159 	dcp->c_metadata.md_localctime = current_time;
6160 	dcp->c_metadata.md_localmtime = current_time;
6161 	dcp->c_metadata.md_flags |= MD_LOCALCTIME | MD_LOCALMTIME;
6162 	dcp->c_attr.va_nlink++;
6163 	dcp->c_flags |= CN_UPDATED;
6164 	mutex_exit(&dcp->c_statelock);
6165 
6166 out:
6167 	if (commit) {
6168 		/* commit the log entry */
6169 		if (cachefs_dlog_commit(fscp, commit, error)) {
6170 			/*EMPTY*/
6171 			/* XXX bob: fix on panic */
6172 		}
6173 	}
6174 	if (error) {
6175 		if (newcp) {
6176 			mutex_enter(&newcp->c_statelock);
6177 			newcp->c_flags |= CN_DESTROY;
6178 			mutex_exit(&newcp->c_statelock);
6179 			VN_RELE(CTOV(newcp));
6180 		}
6181 	} else {
6182 		*vpp = CTOV(newcp);
6183 	}
6184 	return (error);
6185 }
6186 
6187 /*ARGSUSED*/
6188 static int
6189 cachefs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
6190     caller_context_t *ct, int flags)
6191 {
6192 	cnode_t *dcp = VTOC(dvp);
6193 	fscache_t *fscp = C_TO_FSCACHE(dcp);
6194 	cachefscache_t *cachep = fscp->fs_cache;
6195 	int error = 0;
6196 	int held = 0;
6197 	int connected = 0;
6198 	size_t namlen;
6199 	vnode_t *vp = NULL;
6200 	int vfslock = 0;
6201 
6202 #ifdef CFSDEBUG
6203 	CFS_DEBUG(CFSDEBUG_VOPS)
6204 		printf("cachefs_rmdir: ENTER vp %p\n", (void *)dvp);
6205 #endif
6206 
6207 	if (getzoneid() != GLOBAL_ZONEID) {
6208 		error = EPERM;
6209 		goto out;
6210 	}
6211 
6212 	if (fscp->fs_cache->c_flags & (CACHE_NOFILL | CACHE_NOCACHE))
6213 		ASSERT(dcp->c_flags & CN_NOCACHE);
6214 
6215 	/*
6216 	 * Cachefs only provides pass-through support for NFSv4,
6217 	 * and all vnode operations are passed through to the
6218 	 * back file system. For NFSv4 pass-through to work, only
6219 	 * connected operation is supported, the cnode backvp must
6220 	 * exist, and cachefs optional (eg., disconnectable) flags
6221 	 * are turned off. Assert these conditions to ensure that
6222 	 * the backfilesystem is called for the rmdir operation.
6223 	 */
6224 	CFS_BACKFS_NFSV4_ASSERT_FSCACHE(fscp);
6225 	CFS_BACKFS_NFSV4_ASSERT_CNODE(dcp);
6226 
6227 	for (;;) {
6228 		if (vfslock) {
6229 			vn_vfsunlock(vp);
6230 			vfslock = 0;
6231 		}
6232 		if (vp) {
6233 			VN_RELE(vp);
6234 			vp = NULL;
6235 		}
6236 
6237 		/* get (or renew) access to the file system */
6238 		if (held) {
6239 			/* Won't loop with NFSv4 connected behavior */
6240 			ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
6241 			cachefs_cd_release(fscp);
6242 			held = 0;
6243 		}
6244 		error = cachefs_cd_access(fscp, connected, 1);
6245 		if (error)
6246 			break;
6247 		held = 1;
6248 
6249 		/* if disconnected, do some extra error checking */
6250 		if (fscp->fs_cdconnected != CFS_CD_CONNECTED) {
6251 			/* check permissions */
6252 			mutex_enter(&dcp->c_statelock);
6253 			error = cachefs_access_local(dcp, (VEXEC|VWRITE), cr);
6254 			mutex_exit(&dcp->c_statelock);
6255 			if (CFS_TIMEOUT(fscp, error)) {
6256 				connected = 1;
6257 				continue;
6258 			}
6259 			if (error)
6260 				break;
6261 
6262 			namlen = strlen(nm);
6263 			if (namlen == 0) {
6264 				error = EINVAL;
6265 				break;
6266 			}
6267 
6268 			/* cannot remove . and .. */
6269 			if (nm[0] == '.') {
6270 				if (namlen == 1) {
6271 					error = EINVAL;
6272 					break;
6273 				} else if (namlen == 2 && nm[1] == '.') {
6274 					error = EEXIST;
6275 					break;
6276 				}
6277 			}
6278 
6279 		}
6280 
6281 		/* get the cnode of the dir to remove */
6282 		error = cachefs_lookup_common(dvp, nm, &vp, NULL, 0, NULL, cr);
6283 		if (error) {
6284 			if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
6285 				if (CFS_TIMEOUT(fscp, error)) {
6286 					cachefs_cd_release(fscp);
6287 					held = 0;
6288 					cachefs_cd_timedout(fscp);
6289 					connected = 0;
6290 					continue;
6291 				}
6292 			} else {
6293 				if (CFS_TIMEOUT(fscp, error)) {
6294 					connected = 1;
6295 					continue;
6296 				}
6297 			}
6298 			break;
6299 		}
6300 
6301 		/* must be a dir */
6302 		if (vp->v_type != VDIR) {
6303 			error = ENOTDIR;
6304 			break;
6305 		}
6306 
6307 		/* must not be current dir */
6308 		if (VOP_CMP(vp, cdir, ct)) {
6309 			error = EINVAL;
6310 			break;
6311 		}
6312 
6313 		/* see ufs_dirremove for why this is done, mount race */
6314 		if (vn_vfswlock(vp)) {
6315 			error = EBUSY;
6316 			break;
6317 		}
6318 		vfslock = 1;
6319 		if (vn_mountedvfs(vp) != NULL) {
6320 			error = EBUSY;
6321 			break;
6322 		}
6323 
6324 		if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
6325 			error = cachefs_rmdir_connected(dvp, nm, cdir,
6326 			    cr, vp);
6327 			if (CFS_TIMEOUT(fscp, error)) {
6328 				cachefs_cd_release(fscp);
6329 				held = 0;
6330 				cachefs_cd_timedout(fscp);
6331 				connected = 0;
6332 				continue;
6333 			}
6334 		} else {
6335 			error = cachefs_rmdir_disconnected(dvp, nm, cdir,
6336 			    cr, vp);
6337 			if (CFS_TIMEOUT(fscp, error)) {
6338 				connected = 1;
6339 				continue;
6340 			}
6341 		}
6342 		break;
6343 	}
6344 
6345 	if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_RMDIR)) {
6346 		ino64_t fileno = 0;
6347 		fid_t *fidp = NULL;
6348 		cnode_t *cp = NULL;
6349 		if (vp)
6350 			cp = VTOC(vp);
6351 
6352 		if (cp != NULL) {
6353 			fidp = &cp->c_metadata.md_cookie;
6354 			fileno = cp->c_id.cid_fileno;
6355 		}
6356 
6357 		cachefs_log_rmdir(cachep, error, fscp->fs_cfsvfsp,
6358 		    fidp, fileno, crgetuid(cr));
6359 	}
6360 
6361 	if (held) {
6362 		cachefs_cd_release(fscp);
6363 	}
6364 
6365 	if (vfslock)
6366 		vn_vfsunlock(vp);
6367 
6368 	if (vp)
6369 		VN_RELE(vp);
6370 
6371 #ifdef CFS_CD_DEBUG
6372 	ASSERT((curthread->t_flag & T_CD_HELD) == 0);
6373 #endif
6374 out:
6375 #ifdef CFSDEBUG
6376 	CFS_DEBUG(CFSDEBUG_VOPS)
6377 		printf("cachefs_rmdir: EXIT error = %d\n", error);
6378 #endif
6379 
6380 	return (error);
6381 }
6382 
6383 static int
6384 cachefs_rmdir_connected(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
6385     vnode_t *vp)
6386 {
6387 	cnode_t *dcp = VTOC(dvp);
6388 	cnode_t *cp = VTOC(vp);
6389 	int error = 0;
6390 	fscache_t *fscp = C_TO_FSCACHE(dcp);
6391 
6392 	rw_enter(&dcp->c_rwlock, RW_WRITER);
6393 	mutex_enter(&dcp->c_statelock);
6394 	mutex_enter(&cp->c_statelock);
6395 
6396 	if (dcp->c_backvp == NULL) {
6397 		error = cachefs_getbackvp(fscp, dcp);
6398 		if (error) {
6399 			goto out;
6400 		}
6401 	}
6402 
6403 	error = CFSOP_CHECK_COBJECT(fscp, dcp, 0, cr);
6404 	if (error)
6405 		goto out;
6406 
6407 	/* rmdir on the back fs */
6408 	CFS_DPRINT_BACKFS_NFSV4(fscp,
6409 	    ("cachefs_rmdir (nfsv4): dcp %p, dbackvp %p, "
6410 	    "name %s\n", dcp, dcp->c_backvp, nm));
6411 	error = VOP_RMDIR(dcp->c_backvp, nm, cdir, cr, NULL, 0);
6412 	if (error)
6413 		goto out;
6414 
6415 	/* if the dir is populated, remove the entry from it */
6416 	if (CFS_ISFS_NONSHARED(fscp) &&
6417 	    (dcp->c_metadata.md_flags & MD_POPULATED)) {
6418 		error = cachefs_dir_rmentry(dcp, nm);
6419 		if (error) {
6420 			cachefs_nocache(dcp);
6421 			error = 0;
6422 		}
6423 	}
6424 
6425 	/*
6426 	 * *if* the (hard) link count goes to 0, then we set the CDESTROY
6427 	 * flag on the cnode. The cached object will then be destroyed
6428 	 * at inactive time where the chickens come home to roost :-)
6429 	 * The link cnt for directories is bumped down by 2 'cause the "."
6430 	 * entry has to be elided too ! The link cnt for the parent goes down
6431 	 * by 1 (because of "..").
6432 	 */
6433 	cp->c_attr.va_nlink -= 2;
6434 	dcp->c_attr.va_nlink--;
6435 	if (cp->c_attr.va_nlink == 0) {
6436 		cp->c_flags |= CN_DESTROY;
6437 	} else {
6438 		cp->c_flags |= CN_UPDATED;
6439 	}
6440 	dcp->c_flags |= CN_UPDATED;
6441 
6442 	dnlc_purge_vp(vp);
6443 	CFSOP_MODIFY_COBJECT(fscp, dcp, cr);
6444 
6445 out:
6446 	mutex_exit(&cp->c_statelock);
6447 	mutex_exit(&dcp->c_statelock);
6448 	rw_exit(&dcp->c_rwlock);
6449 
6450 	return (error);
6451 }
6452 
6453 static int
6454 /*ARGSUSED*/
6455 cachefs_rmdir_disconnected(vnode_t *dvp, char *nm, vnode_t *cdir,
6456     cred_t *cr, vnode_t *vp)
6457 {
6458 	cnode_t *dcp = VTOC(dvp);
6459 	cnode_t *cp = VTOC(vp);
6460 	fscache_t *fscp = C_TO_FSCACHE(dcp);
6461 	int error = 0;
6462 	off_t commit = 0;
6463 	timestruc_t current_time;
6464 
6465 	if (CFS_ISFS_WRITE_AROUND(fscp))
6466 		return (ETIMEDOUT);
6467 
6468 	rw_enter(&dcp->c_rwlock, RW_WRITER);
6469 	mutex_enter(&dcp->c_statelock);
6470 	mutex_enter(&cp->c_statelock);
6471 
6472 	/* both directories must be populated */
6473 	if (((dcp->c_metadata.md_flags & MD_POPULATED) == 0) ||
6474 	    ((cp->c_metadata.md_flags & MD_POPULATED) == 0)) {
6475 		error = ETIMEDOUT;
6476 		goto out;
6477 	}
6478 
6479 	/* if sticky bit set on the dir, more access checks to perform */
6480 	if (error = cachefs_stickyrmchk(dcp, cp, cr)) {
6481 		goto out;
6482 	}
6483 
6484 	/* make sure dir is empty */
6485 	if (cp->c_attr.va_nlink > 2) {
6486 		error = cachefs_dir_empty(cp);
6487 		if (error) {
6488 			if (error == ENOTDIR)
6489 				error = ETIMEDOUT;
6490 			goto out;
6491 		}
6492 		cachefs_modified(cp);
6493 	}
6494 	cachefs_modified(dcp);
6495 
6496 	/* log the operation */
6497 	commit = cachefs_dlog_rmdir(fscp, dcp, nm, cp, cr);
6498 	if (commit == 0) {
6499 		error = ENOSPC;
6500 		goto out;
6501 	}
6502 
6503 	/* remove name from parent dir */
6504 	error = cachefs_dir_rmentry(dcp, nm);
6505 	if (error == ENOTDIR) {
6506 		error = ETIMEDOUT;
6507 		goto out;
6508 	}
6509 	if (error)
6510 		goto out;
6511 
6512 	gethrestime(&current_time);
6513 
6514 	/* update deleted dir values */
6515 	cp->c_attr.va_nlink -= 2;
6516 	if (cp->c_attr.va_nlink == 0)
6517 		cp->c_flags |= CN_DESTROY;
6518 	else {
6519 		cp->c_metadata.md_localctime = current_time;
6520 		cp->c_metadata.md_flags |= MD_LOCALCTIME;
6521 		cp->c_flags |= CN_UPDATED;
6522 	}
6523 
6524 	/* update parent values */
6525 	dcp->c_metadata.md_localctime = current_time;
6526 	dcp->c_metadata.md_localmtime = current_time;
6527 	dcp->c_metadata.md_flags |= MD_LOCALCTIME | MD_LOCALMTIME;
6528 	dcp->c_attr.va_nlink--;
6529 	dcp->c_flags |= CN_UPDATED;
6530 
6531 out:
6532 	mutex_exit(&cp->c_statelock);
6533 	mutex_exit(&dcp->c_statelock);
6534 	rw_exit(&dcp->c_rwlock);
6535 	if (commit) {
6536 		/* commit the log entry */
6537 		if (cachefs_dlog_commit(fscp, commit, error)) {
6538 			/*EMPTY*/
6539 			/* XXX bob: fix on panic */
6540 		}
6541 		dnlc_purge_vp(vp);
6542 	}
6543 	return (error);
6544 }
6545 
6546 /*ARGSUSED*/
6547 static int
6548 cachefs_symlink(vnode_t *dvp, char *lnm, vattr_t *tva,
6549     char *tnm, cred_t *cr, caller_context_t *ct, int flags)
6550 {
6551 	cnode_t *dcp = VTOC(dvp);
6552 	fscache_t *fscp = C_TO_FSCACHE(dcp);
6553 	cachefscache_t *cachep = fscp->fs_cache;
6554 	int error = 0;
6555 	int held = 0;
6556 	int connected = 0;
6557 
6558 #ifdef CFSDEBUG
6559 	CFS_DEBUG(CFSDEBUG_VOPS)
6560 		printf("cachefs_symlink: ENTER dvp %p lnm %s tnm %s\n",
6561 		    (void *)dvp, lnm, tnm);
6562 #endif
6563 
6564 	if (getzoneid() != GLOBAL_ZONEID) {
6565 		error = EPERM;
6566 		goto out;
6567 	}
6568 
6569 	if (fscp->fs_cache->c_flags & CACHE_NOCACHE)
6570 		ASSERT(dcp->c_flags & CN_NOCACHE);
6571 
6572 	/*
6573 	 * Cachefs only provides pass-through support for NFSv4,
6574 	 * and all vnode operations are passed through to the
6575 	 * back file system. For NFSv4 pass-through to work, only
6576 	 * connected operation is supported, the cnode backvp must
6577 	 * exist, and cachefs optional (eg., disconnectable) flags
6578 	 * are turned off. Assert these conditions to ensure that
6579 	 * the backfilesystem is called for the symlink operation.
6580 	 */
6581 	CFS_BACKFS_NFSV4_ASSERT_FSCACHE(fscp);
6582 	CFS_BACKFS_NFSV4_ASSERT_CNODE(dcp);
6583 
6584 	for (;;) {
6585 		/* get (or renew) access to the file system */
6586 		if (held) {
6587 			/* Won't loop with NFSv4 connected behavior */
6588 			ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
6589 			rw_exit(&dcp->c_rwlock);
6590 			cachefs_cd_release(fscp);
6591 			held = 0;
6592 		}
6593 		error = cachefs_cd_access(fscp, connected, 1);
6594 		if (error)
6595 			break;
6596 		rw_enter(&dcp->c_rwlock, RW_WRITER);
6597 		held = 1;
6598 
6599 		if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
6600 			error = cachefs_symlink_connected(dvp, lnm, tva,
6601 			    tnm, cr);
6602 			if (CFS_TIMEOUT(fscp, error)) {
6603 				rw_exit(&dcp->c_rwlock);
6604 				cachefs_cd_release(fscp);
6605 				held = 0;
6606 				cachefs_cd_timedout(fscp);
6607 				connected = 0;
6608 				continue;
6609 			}
6610 		} else {
6611 			error = cachefs_symlink_disconnected(dvp, lnm, tva,
6612 			    tnm, cr);
6613 			if (CFS_TIMEOUT(fscp, error)) {
6614 				connected = 1;
6615 				continue;
6616 			}
6617 		}
6618 		break;
6619 	}
6620 
6621 	if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_SYMLINK))
6622 		cachefs_log_symlink(cachep, error, fscp->fs_cfsvfsp,
6623 		    &dcp->c_metadata.md_cookie, dcp->c_id.cid_fileno,
6624 		    crgetuid(cr), (uint_t)strlen(tnm));
6625 
6626 	if (held) {
6627 		rw_exit(&dcp->c_rwlock);
6628 		cachefs_cd_release(fscp);
6629 	}
6630 
6631 #ifdef CFS_CD_DEBUG
6632 	ASSERT((curthread->t_flag & T_CD_HELD) == 0);
6633 #endif
6634 out:
6635 #ifdef CFSDEBUG
6636 	CFS_DEBUG(CFSDEBUG_VOPS)
6637 		printf("cachefs_symlink: EXIT error = %d\n", error);
6638 #endif
6639 	return (error);
6640 }
6641 
6642 static int
6643 cachefs_symlink_connected(vnode_t *dvp, char *lnm, vattr_t *tva,
6644     char *tnm, cred_t *cr)
6645 {
6646 	cnode_t *dcp = VTOC(dvp);
6647 	fscache_t *fscp = C_TO_FSCACHE(dcp);
6648 	int error = 0;
6649 	vnode_t *backvp = NULL;
6650 	cnode_t *newcp = NULL;
6651 	struct vattr va;
6652 	struct fid cookie;
6653 	cfs_cid_t cid;
6654 	uint32_t valid_fid;
6655 
6656 	mutex_enter(&dcp->c_statelock);
6657 
6658 	if (dcp->c_backvp == NULL) {
6659 		error = cachefs_getbackvp(fscp, dcp);
6660 		if (error) {
6661 			cachefs_nocache(dcp);
6662 			mutex_exit(&dcp->c_statelock);
6663 			goto out;
6664 		}
6665 	}
6666 
6667 	error = CFSOP_CHECK_COBJECT(fscp, dcp, 0, cr);
6668 	if (error) {
6669 		mutex_exit(&dcp->c_statelock);
6670 		goto out;
6671 	}
6672 	CFS_DPRINT_BACKFS_NFSV4(fscp,
6673 	    ("cachefs_symlink (nfsv4): dcp %p, dbackvp %p, "
6674 	    "lnm %s, tnm %s\n", dcp, dcp->c_backvp, lnm, tnm));
6675 	error = VOP_SYMLINK(dcp->c_backvp, lnm, tva, tnm, cr, NULL, 0);
6676 	if (error) {
6677 		mutex_exit(&dcp->c_statelock);
6678 		goto out;
6679 	}
6680 	if ((dcp->c_filegrp->fg_flags & CFS_FG_WRITE) == 0 &&
6681 	    !CFS_ISFS_BACKFS_NFSV4(fscp)) {
6682 		cachefs_nocache(dcp);
6683 		mutex_exit(&dcp->c_statelock);
6684 		goto out;
6685 	}
6686 
6687 	CFSOP_MODIFY_COBJECT(fscp, dcp, cr);
6688 
6689 	/* lookup the symlink we just created and get its fid and attrs */
6690 	(void) VOP_LOOKUP(dcp->c_backvp, lnm, &backvp, NULL, 0, NULL, cr,
6691 	    NULL, NULL, NULL);
6692 	if (backvp == NULL) {
6693 		if (CFS_ISFS_BACKFS_NFSV4(fscp) == 0)
6694 			cachefs_nocache(dcp);
6695 		mutex_exit(&dcp->c_statelock);
6696 		goto out;
6697 	}
6698 
6699 	valid_fid = (CFS_ISFS_BACKFS_NFSV4(fscp) ? FALSE : TRUE);
6700 	error = cachefs_getcookie(backvp, &cookie, &va, cr, valid_fid);
6701 	if (error) {
6702 		ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
6703 		error = 0;
6704 		cachefs_nocache(dcp);
6705 		mutex_exit(&dcp->c_statelock);
6706 		goto out;
6707 	}
6708 	cid.cid_fileno = va.va_nodeid;
6709 	cid.cid_flags = 0;
6710 
6711 	/* if the dir is cached, add the symlink to it */
6712 	if (CFS_ISFS_NONSHARED(fscp) &&
6713 	    (dcp->c_metadata.md_flags & MD_POPULATED)) {
6714 		error = cachefs_dir_enter(dcp, lnm, &cookie, &cid, SM_ASYNC);
6715 		if (error) {
6716 			cachefs_nocache(dcp);
6717 			error = 0;
6718 		}
6719 	}
6720 	mutex_exit(&dcp->c_statelock);
6721 
6722 	/* make the cnode for the sym link */
6723 	error = cachefs_cnode_make(&cid, fscp, (valid_fid ? &cookie : NULL),
6724 	    &va, backvp, cr, 0, &newcp);
6725 	if (error) {
6726 		ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
6727 		cachefs_nocache(dcp);
6728 		error = 0;
6729 		goto out;
6730 	}
6731 
6732 	/* try to cache the symlink contents */
6733 	rw_enter(&newcp->c_rwlock, RW_WRITER);
6734 	mutex_enter(&newcp->c_statelock);
6735 
6736 	/*
6737 	 * try to cache the sym link, note that its a noop if NOCACHE
6738 	 * or NFSv4 is set
6739 	 */
6740 	error = cachefs_stuffsymlink(newcp, tnm, (int)newcp->c_size);
6741 	if (error) {
6742 		cachefs_nocache(newcp);
6743 		error = 0;
6744 	}
6745 	mutex_exit(&newcp->c_statelock);
6746 	rw_exit(&newcp->c_rwlock);
6747 
6748 out:
6749 	if (backvp)
6750 		VN_RELE(backvp);
6751 	if (newcp)
6752 		VN_RELE(CTOV(newcp));
6753 	return (error);
6754 }
6755 
6756 static int
6757 cachefs_symlink_disconnected(vnode_t *dvp, char *lnm, vattr_t *tva,
6758     char *tnm, cred_t *cr)
6759 {
6760 	cnode_t *dcp = VTOC(dvp);
6761 	fscache_t *fscp = C_TO_FSCACHE(dcp);
6762 	int error;
6763 	cnode_t *newcp = NULL;
6764 	struct vattr va;
6765 	timestruc_t current_time;
6766 	off_t commit = 0;
6767 
6768 	if (CFS_ISFS_WRITE_AROUND(fscp))
6769 		return (ETIMEDOUT);
6770 
6771 	mutex_enter(&dcp->c_statelock);
6772 
6773 	/* check permissions */
6774 	if (error = cachefs_access_local(dcp, (VEXEC|VWRITE), cr)) {
6775 		mutex_exit(&dcp->c_statelock);
6776 		goto out;
6777 	}
6778 
6779 	/* the directory front file must be populated */
6780 	if ((dcp->c_metadata.md_flags & MD_POPULATED) == 0) {
6781 		error = ETIMEDOUT;
6782 		mutex_exit(&dcp->c_statelock);
6783 		goto out;
6784 	}
6785 
6786 	/* make sure lnm does not already exist in the directory */
6787 	error = cachefs_dir_look(dcp, lnm, NULL, NULL, NULL, NULL);
6788 	if (error == ENOTDIR) {
6789 		error = ETIMEDOUT;
6790 		mutex_exit(&dcp->c_statelock);
6791 		goto out;
6792 	}
6793 	if (error != ENOENT) {
6794 		error = EEXIST;
6795 		mutex_exit(&dcp->c_statelock);
6796 		goto out;
6797 	}
6798 
6799 	/* make up a reasonable set of attributes */
6800 	cachefs_attr_setup(tva, &va, dcp, cr);
6801 	va.va_type = VLNK;
6802 	va.va_mode |= S_IFLNK;
6803 	va.va_size = strlen(tnm);
6804 
6805 	mutex_exit(&dcp->c_statelock);
6806 
6807 	/* create the cnode */
6808 	error = cachefs_cnode_create(fscp, &va, 0, &newcp);
6809 	if (error)
6810 		goto out;
6811 
6812 	rw_enter(&newcp->c_rwlock, RW_WRITER);
6813 	mutex_enter(&newcp->c_statelock);
6814 
6815 	error = cachefs_dlog_cidmap(fscp);
6816 	if (error) {
6817 		mutex_exit(&newcp->c_statelock);
6818 		rw_exit(&newcp->c_rwlock);
6819 		error = ENOSPC;
6820 		goto out;
6821 	}
6822 
6823 	cachefs_creategid(dcp, newcp, tva, cr);
6824 	mutex_enter(&dcp->c_statelock);
6825 	cachefs_createacl(dcp, newcp);
6826 	mutex_exit(&dcp->c_statelock);
6827 	gethrestime(&current_time);
6828 	newcp->c_metadata.md_vattr.va_atime = current_time;
6829 	newcp->c_metadata.md_localctime = current_time;
6830 	newcp->c_metadata.md_localmtime = current_time;
6831 	newcp->c_metadata.md_flags |= MD_MAPPING | MD_LOCALMTIME |
6832 	    MD_LOCALCTIME;
6833 	newcp->c_flags |= CN_UPDATED;
6834 
6835 	/* log the operation */
6836 	commit = cachefs_dlog_symlink(fscp, dcp, newcp, lnm, tva, tnm, cr);
6837 	if (commit == 0) {
6838 		mutex_exit(&newcp->c_statelock);
6839 		rw_exit(&newcp->c_rwlock);
6840 		error = ENOSPC;
6841 		goto out;
6842 	}
6843 
6844 	/* store the symlink contents */
6845 	error = cachefs_stuffsymlink(newcp, tnm, (int)newcp->c_size);
6846 	if (error) {
6847 		mutex_exit(&newcp->c_statelock);
6848 		rw_exit(&newcp->c_rwlock);
6849 		goto out;
6850 	}
6851 	if (cachefs_modified_alloc(newcp)) {
6852 		mutex_exit(&newcp->c_statelock);
6853 		rw_exit(&newcp->c_rwlock);
6854 		error = ENOSPC;
6855 		goto out;
6856 	}
6857 
6858 	/*
6859 	 * write the metadata now rather than waiting until
6860 	 * inactive so that if there's no space we can let
6861 	 * the caller know.
6862 	 */
6863 	if (newcp->c_flags & CN_ALLOC_PENDING) {
6864 		if (newcp->c_filegrp->fg_flags & CFS_FG_ALLOC_ATTR) {
6865 			(void) filegrp_allocattr(newcp->c_filegrp);
6866 		}
6867 		error = filegrp_create_metadata(newcp->c_filegrp,
6868 		    &newcp->c_metadata, &newcp->c_id);
6869 		if (error) {
6870 			mutex_exit(&newcp->c_statelock);
6871 			rw_exit(&newcp->c_rwlock);
6872 			goto out;
6873 		}
6874 		newcp->c_flags &= ~CN_ALLOC_PENDING;
6875 	}
6876 	error = filegrp_write_metadata(newcp->c_filegrp,
6877 	    &newcp->c_id, &newcp->c_metadata);
6878 	if (error) {
6879 		mutex_exit(&newcp->c_statelock);
6880 		rw_exit(&newcp->c_rwlock);
6881 		goto out;
6882 	}
6883 	mutex_exit(&newcp->c_statelock);
6884 	rw_exit(&newcp->c_rwlock);
6885 
6886 	mutex_enter(&dcp->c_statelock);
6887 
6888 	/* enter the new file in the directory */
6889 	if ((dcp->c_metadata.md_flags & MD_POPULATED) == 0) {
6890 		error = ETIMEDOUT;
6891 		mutex_exit(&dcp->c_statelock);
6892 		goto out;
6893 	}
6894 	cachefs_modified(dcp);
6895 	error = cachefs_dir_enter(dcp, lnm, &newcp->c_metadata.md_cookie,
6896 	    &newcp->c_id, SM_ASYNC);
6897 	if (error) {
6898 		mutex_exit(&dcp->c_statelock);
6899 		goto out;
6900 	}
6901 
6902 	/* update parent dir times */
6903 	dcp->c_metadata.md_localctime = current_time;
6904 	dcp->c_metadata.md_localmtime = current_time;
6905 	dcp->c_metadata.md_flags |= MD_LOCALMTIME | MD_LOCALCTIME;
6906 	dcp->c_flags |= CN_UPDATED;
6907 	mutex_exit(&dcp->c_statelock);
6908 
6909 out:
6910 	if (commit) {
6911 		/* commit the log entry */
6912 		if (cachefs_dlog_commit(fscp, commit, error)) {
6913 			/*EMPTY*/
6914 			/* XXX bob: fix on panic */
6915 		}
6916 	}
6917 
6918 	if (error) {
6919 		if (newcp) {
6920 			mutex_enter(&newcp->c_statelock);
6921 			newcp->c_flags |= CN_DESTROY;
6922 			mutex_exit(&newcp->c_statelock);
6923 		}
6924 	}
6925 	if (newcp) {
6926 		VN_RELE(CTOV(newcp));
6927 	}
6928 
6929 	return (error);
6930 }
6931 
6932 /*ARGSUSED*/
6933 static int
6934 cachefs_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp,
6935     caller_context_t *ct, int flags)
6936 {
6937 	cnode_t *dcp = VTOC(vp);
6938 	fscache_t *fscp = C_TO_FSCACHE(dcp);
6939 	cachefscache_t *cachep = fscp->fs_cache;
6940 	int error = 0;
6941 	int held = 0;
6942 	int connected = 0;
6943 
6944 #ifdef CFSDEBUG
6945 	CFS_DEBUG(CFSDEBUG_VOPS)
6946 		printf("cachefs_readdir: ENTER vp %p\n", (void *)vp);
6947 #endif
6948 	if (getzoneid() != GLOBAL_ZONEID) {
6949 		error = EPERM;
6950 		goto out;
6951 	}
6952 
6953 	/*
6954 	 * Cachefs only provides pass-through support for NFSv4,
6955 	 * and all vnode operations are passed through to the
6956 	 * back file system. For NFSv4 pass-through to work, only
6957 	 * connected operation is supported, the cnode backvp must
6958 	 * exist, and cachefs optional (eg., disconnectable) flags
6959 	 * are turned off. Assert these conditions to ensure that
6960 	 * the backfilesystem is called for the readdir operation.
6961 	 */
6962 	CFS_BACKFS_NFSV4_ASSERT_FSCACHE(fscp);
6963 	CFS_BACKFS_NFSV4_ASSERT_CNODE(dcp);
6964 
6965 	for (;;) {
6966 		/* get (or renew) access to the file system */
6967 		if (held) {
6968 			/* Won't loop with NFSv4 connected behavior */
6969 			ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
6970 			rw_exit(&dcp->c_rwlock);
6971 			cachefs_cd_release(fscp);
6972 			held = 0;
6973 		}
6974 		error = cachefs_cd_access(fscp, connected, 0);
6975 		if (error)
6976 			break;
6977 		rw_enter(&dcp->c_rwlock, RW_READER);
6978 		held = 1;
6979 
6980 		/* quit if link count of zero (posix) */
6981 		if (dcp->c_attr.va_nlink == 0) {
6982 			if (eofp)
6983 				*eofp = 1;
6984 			error = 0;
6985 			break;
6986 		}
6987 
6988 		if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
6989 			error = cachefs_readdir_connected(vp, uiop, cr,
6990 			    eofp);
6991 			if (CFS_TIMEOUT(fscp, error)) {
6992 				rw_exit(&dcp->c_rwlock);
6993 				cachefs_cd_release(fscp);
6994 				held = 0;
6995 				cachefs_cd_timedout(fscp);
6996 				connected = 0;
6997 				continue;
6998 			}
6999 		} else {
7000 			error = cachefs_readdir_disconnected(vp, uiop, cr,
7001 			    eofp);
7002 			if (CFS_TIMEOUT(fscp, error)) {
7003 				if (cachefs_cd_access_miss(fscp)) {
7004 					error = cachefs_readdir_connected(vp,
7005 					    uiop, cr, eofp);
7006 					if (!CFS_TIMEOUT(fscp, error))
7007 						break;
7008 					delay(5*hz);
7009 					connected = 0;
7010 					continue;
7011 				}
7012 				connected = 1;
7013 				continue;
7014 			}
7015 		}
7016 		break;
7017 	}
7018 
7019 	if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_READDIR))
7020 		cachefs_log_readdir(cachep, error, fscp->fs_cfsvfsp,
7021 		    &dcp->c_metadata.md_cookie, dcp->c_id.cid_fileno,
7022 		    crgetuid(cr), uiop->uio_loffset, *eofp);
7023 
7024 	if (held) {
7025 		rw_exit(&dcp->c_rwlock);
7026 		cachefs_cd_release(fscp);
7027 	}
7028 
7029 #ifdef CFS_CD_DEBUG
7030 	ASSERT((curthread->t_flag & T_CD_HELD) == 0);
7031 #endif
7032 out:
7033 #ifdef CFSDEBUG
7034 	CFS_DEBUG(CFSDEBUG_VOPS)
7035 		printf("cachefs_readdir: EXIT error = %d\n", error);
7036 #endif
7037 
7038 	return (error);
7039 }
7040 
7041 static int
7042 cachefs_readdir_connected(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp)
7043 {
7044 	cnode_t *dcp = VTOC(vp);
7045 	int error;
7046 	fscache_t *fscp = C_TO_FSCACHE(dcp);
7047 	struct cachefs_req *rp;
7048 
7049 	mutex_enter(&dcp->c_statelock);
7050 
7051 	/* check directory consistency */
7052 	error = CFSOP_CHECK_COBJECT(fscp, dcp, 0, cr);
7053 	if (error)
7054 		goto out;
7055 	dcp->c_usage++;
7056 
7057 	/* if dir was modified, toss old contents */
7058 	if (dcp->c_metadata.md_flags & MD_INVALREADDIR) {
7059 		ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
7060 		cachefs_inval_object(dcp);
7061 	}
7062 
7063 	error = 0;
7064 	if (((dcp->c_metadata.md_flags & MD_POPULATED) == 0) &&
7065 	    ((dcp->c_flags & (CN_ASYNC_POPULATE | CN_NOCACHE)) == 0) &&
7066 	    !CFS_ISFS_BACKFS_NFSV4(fscp) &&
7067 	    (fscp->fs_cdconnected == CFS_CD_CONNECTED)) {
7068 
7069 		if (cachefs_async_okay()) {
7070 
7071 			/*
7072 			 * Set up asynchronous request to fill this
7073 			 * directory.
7074 			 */
7075 
7076 			dcp->c_flags |= CN_ASYNC_POPULATE;
7077 
7078 			rp = kmem_cache_alloc(cachefs_req_cache, KM_SLEEP);
7079 			rp->cfs_cmd = CFS_POPULATE;
7080 			rp->cfs_req_u.cu_populate.cpop_vp = vp;
7081 			rp->cfs_cr = cr;
7082 
7083 			crhold(cr);
7084 			VN_HOLD(vp);
7085 
7086 			cachefs_addqueue(rp, &fscp->fs_workq);
7087 		} else {
7088 			error = cachefs_dir_fill(dcp, cr);
7089 			if (error != 0)
7090 				cachefs_nocache(dcp);
7091 		}
7092 	}
7093 
7094 	/* if front file is populated */
7095 	if (((dcp->c_flags & (CN_NOCACHE | CN_ASYNC_POPULATE)) == 0) &&
7096 	    !CFS_ISFS_BACKFS_NFSV4(fscp) &&
7097 	    (dcp->c_metadata.md_flags & MD_POPULATED)) {
7098 		ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
7099 		error = cachefs_dir_read(dcp, uiop, eofp);
7100 		if (error == 0)
7101 			fscp->fs_stats.st_hits++;
7102 	}
7103 
7104 	/* if front file could not be used */
7105 	if ((error != 0) ||
7106 	    CFS_ISFS_BACKFS_NFSV4(fscp) ||
7107 	    (dcp->c_flags & (CN_NOCACHE | CN_ASYNC_POPULATE)) ||
7108 	    ((dcp->c_metadata.md_flags & MD_POPULATED) == 0)) {
7109 
7110 		if (error && !(dcp->c_flags & CN_NOCACHE) &&
7111 		    !CFS_ISFS_BACKFS_NFSV4(fscp))
7112 			cachefs_nocache(dcp);
7113 
7114 		/* get the back vp */
7115 		if (dcp->c_backvp == NULL) {
7116 			error = cachefs_getbackvp(fscp, dcp);
7117 			if (error)
7118 				goto out;
7119 		}
7120 
7121 		if (fscp->fs_inum_size > 0) {
7122 			error = cachefs_readback_translate(dcp, uiop, cr, eofp);
7123 		} else {
7124 			/* do the dir read from the back fs */
7125 			(void) VOP_RWLOCK(dcp->c_backvp,
7126 			    V_WRITELOCK_FALSE, NULL);
7127 			CFS_DPRINT_BACKFS_NFSV4(fscp,
7128 			    ("cachefs_readdir (nfsv4): "
7129 			    "dcp %p, dbackvp %p\n", dcp, dcp->c_backvp));
7130 			error = VOP_READDIR(dcp->c_backvp, uiop, cr, eofp,
7131 			    NULL, 0);
7132 			VOP_RWUNLOCK(dcp->c_backvp, V_WRITELOCK_FALSE, NULL);
7133 		}
7134 
7135 		if (error == 0)
7136 			fscp->fs_stats.st_misses++;
7137 	}
7138 
7139 out:
7140 	mutex_exit(&dcp->c_statelock);
7141 
7142 	return (error);
7143 }
7144 
7145 static int
7146 cachefs_readback_translate(cnode_t *cp, uio_t *uiop, cred_t *cr, int *eofp)
7147 {
7148 	int error = 0;
7149 	fscache_t *fscp = C_TO_FSCACHE(cp);
7150 	caddr_t buffy = NULL;
7151 	int buffysize = MAXBSIZE;
7152 	caddr_t chrp, end;
7153 	ino64_t newinum;
7154 	struct dirent64 *de;
7155 	uio_t uioin;
7156 	iovec_t iov;
7157 
7158 	ASSERT(cp->c_backvp != NULL);
7159 	ASSERT(fscp->fs_inum_size > 0);
7160 
7161 	if (uiop->uio_resid < buffysize)
7162 		buffysize = (int)uiop->uio_resid;
7163 	buffy = cachefs_kmem_alloc(buffysize, KM_SLEEP);
7164 
7165 	iov.iov_base = buffy;
7166 	iov.iov_len = buffysize;
7167 	uioin.uio_iov = &iov;
7168 	uioin.uio_iovcnt = 1;
7169 	uioin.uio_segflg = UIO_SYSSPACE;
7170 	uioin.uio_fmode = 0;
7171 	uioin.uio_extflg = UIO_COPY_CACHED;
7172 	uioin.uio_loffset = uiop->uio_loffset;
7173 	uioin.uio_resid = buffysize;
7174 
7175 	(void) VOP_RWLOCK(cp->c_backvp, V_WRITELOCK_FALSE, NULL);
7176 	error = VOP_READDIR(cp->c_backvp, &uioin, cr, eofp, NULL, 0);
7177 	VOP_RWUNLOCK(cp->c_backvp, V_WRITELOCK_FALSE, NULL);
7178 
7179 	if (error != 0)
7180 		goto out;
7181 
7182 	end = buffy + buffysize - uioin.uio_resid;
7183 
7184 	mutex_exit(&cp->c_statelock);
7185 	mutex_enter(&fscp->fs_fslock);
7186 
7187 
7188 	for (chrp = buffy; chrp < end; chrp += de->d_reclen) {
7189 		de = (dirent64_t *)chrp;
7190 		newinum = cachefs_inum_real2fake(fscp, de->d_ino);
7191 		if (newinum == 0)
7192 			newinum = cachefs_fileno_conflict(fscp, de->d_ino);
7193 		de->d_ino = newinum;
7194 	}
7195 	mutex_exit(&fscp->fs_fslock);
7196 	mutex_enter(&cp->c_statelock);
7197 
7198 	error = uiomove(buffy, end - buffy, UIO_READ, uiop);
7199 	uiop->uio_loffset = uioin.uio_loffset;
7200 
7201 out:
7202 
7203 	if (buffy != NULL)
7204 		cachefs_kmem_free(buffy, buffysize);
7205 
7206 	return (error);
7207 }
7208 
7209 static int
7210 /*ARGSUSED*/
7211 cachefs_readdir_disconnected(vnode_t *vp, uio_t *uiop, cred_t *cr,
7212     int *eofp)
7213 {
7214 	cnode_t *dcp = VTOC(vp);
7215 	int error;
7216 
7217 	mutex_enter(&dcp->c_statelock);
7218 	if ((dcp->c_metadata.md_flags & MD_POPULATED) == 0) {
7219 		error = ETIMEDOUT;
7220 	} else {
7221 		error = cachefs_dir_read(dcp, uiop, eofp);
7222 		if (error == ENOTDIR)
7223 			error = ETIMEDOUT;
7224 	}
7225 	mutex_exit(&dcp->c_statelock);
7226 
7227 	return (error);
7228 }
7229 
7230 /*ARGSUSED*/
7231 static int
7232 cachefs_fid(struct vnode *vp, struct fid *fidp, caller_context_t *ct)
7233 {
7234 	int error = 0;
7235 	struct cnode *cp = VTOC(vp);
7236 	fscache_t *fscp = C_TO_FSCACHE(cp);
7237 
7238 	/*
7239 	 * Cachefs only provides pass-through support for NFSv4,
7240 	 * and all vnode operations are passed through to the
7241 	 * back file system. For NFSv4 pass-through to work, only
7242 	 * connected operation is supported, the cnode backvp must
7243 	 * exist, and cachefs optional (eg., disconnectable) flags
7244 	 * are turned off. Assert these conditions, then bail
7245 	 * as  NFSv4 doesn't support VOP_FID.
7246 	 */
7247 	CFS_BACKFS_NFSV4_ASSERT_FSCACHE(fscp);
7248 	CFS_BACKFS_NFSV4_ASSERT_CNODE(cp);
7249 	if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
7250 		return (ENOTSUP);
7251 	}
7252 
7253 	mutex_enter(&cp->c_statelock);
7254 	if (fidp->fid_len < cp->c_metadata.md_cookie.fid_len) {
7255 		fidp->fid_len = cp->c_metadata.md_cookie.fid_len;
7256 		error = ENOSPC;
7257 	} else {
7258 		bcopy(cp->c_metadata.md_cookie.fid_data, fidp->fid_data,
7259 		    cp->c_metadata.md_cookie.fid_len);
7260 		fidp->fid_len = cp->c_metadata.md_cookie.fid_len;
7261 	}
7262 	mutex_exit(&cp->c_statelock);
7263 	return (error);
7264 }
7265 
7266 /* ARGSUSED2 */
7267 static int
7268 cachefs_rwlock(struct vnode *vp, int write_lock, caller_context_t *ctp)
7269 {
7270 	cnode_t *cp = VTOC(vp);
7271 
7272 	/*
7273 	 * XXX - This is ifdef'ed out for now. The problem -
7274 	 * getdents() acquires the read version of rwlock, then we come
7275 	 * into cachefs_readdir() and that wants to acquire the write version
7276 	 * of this lock (if its going to populate the directory). This is
7277 	 * a problem, this can be solved by introducing another lock in the
7278 	 * cnode.
7279 	 */
7280 /* XXX */
7281 	if (vp->v_type != VREG)
7282 		return (-1);
7283 	if (write_lock)
7284 		rw_enter(&cp->c_rwlock, RW_WRITER);
7285 	else
7286 		rw_enter(&cp->c_rwlock, RW_READER);
7287 	return (write_lock);
7288 }
7289 
7290 /* ARGSUSED */
7291 static void
7292 cachefs_rwunlock(struct vnode *vp, int write_lock, caller_context_t *ctp)
7293 {
7294 	cnode_t *cp = VTOC(vp);
7295 	if (vp->v_type != VREG)
7296 		return;
7297 	rw_exit(&cp->c_rwlock);
7298 }
7299 
7300 /* ARGSUSED */
7301 static int
7302 cachefs_seek(struct vnode *vp, offset_t ooff, offset_t *noffp,
7303     caller_context_t *ct)
7304 {
7305 	return (0);
7306 }
7307 
7308 static int cachefs_lostpage = 0;
7309 /*
7310  * Return all the pages from [off..off+len] in file
7311  */
7312 /*ARGSUSED*/
7313 static int
7314 cachefs_getpage(struct vnode *vp, offset_t off, size_t len,
7315 	uint_t *protp, struct page *pl[], size_t plsz, struct seg *seg,
7316 	caddr_t addr, enum seg_rw rw, cred_t *cr, caller_context_t *ct)
7317 {
7318 	cnode_t *cp = VTOC(vp);
7319 	int error;
7320 	fscache_t *fscp = C_TO_FSCACHE(cp);
7321 	cachefscache_t *cachep = fscp->fs_cache;
7322 	int held = 0;
7323 	int connected = 0;
7324 
7325 #ifdef CFSDEBUG
7326 	u_offset_t offx = (u_offset_t)off;
7327 
7328 	CFS_DEBUG(CFSDEBUG_VOPS)
7329 		printf("cachefs_getpage: ENTER vp %p off %lld len %lu rw %d\n",
7330 		    (void *)vp, offx, len, rw);
7331 #endif
7332 	if (getzoneid() != GLOBAL_ZONEID) {
7333 		error = EPERM;
7334 		goto out;
7335 	}
7336 
7337 	if (vp->v_flag & VNOMAP) {
7338 		error = ENOSYS;
7339 		goto out;
7340 	}
7341 
7342 	/* Call backfilesystem if NFSv4 */
7343 	if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
7344 		error = cachefs_getpage_backfs_nfsv4(vp, off, len, protp, pl,
7345 		    plsz, seg, addr, rw, cr);
7346 		goto out;
7347 	}
7348 
7349 	/* XXX sam: make this do an async populate? */
7350 	if (pl == NULL) {
7351 		error = 0;
7352 		goto out;
7353 	}
7354 	if (protp != NULL)
7355 		*protp = PROT_ALL;
7356 
7357 	for (;;) {
7358 		/* get (or renew) access to the file system */
7359 		if (held) {
7360 			cachefs_cd_release(fscp);
7361 			held = 0;
7362 		}
7363 		error = cachefs_cd_access(fscp, connected, 0);
7364 		if (error)
7365 			break;
7366 		held = 1;
7367 
7368 		/*
7369 		 * If we are getting called as a side effect of a
7370 		 * cachefs_write()
7371 		 * operation the local file size might not be extended yet.
7372 		 * In this case we want to be able to return pages of zeroes.
7373 		 */
7374 		if ((u_offset_t)off + len >
7375 		    ((cp->c_size + PAGEOFFSET) & (offset_t)PAGEMASK)) {
7376 			if (seg != segkmap) {
7377 				error = EFAULT;
7378 				break;
7379 			}
7380 		}
7381 		if (len <= PAGESIZE)
7382 			error = cachefs_getapage(vp, (u_offset_t)off, len,
7383 			    protp, pl, plsz, seg, addr, rw, cr);
7384 		else
7385 			error = pvn_getpages(cachefs_getapage, vp,
7386 			    (u_offset_t)off, len, protp, pl, plsz, seg, addr,
7387 			    rw, cr);
7388 		if (error == 0)
7389 			break;
7390 
7391 		if (((cp->c_flags & CN_NOCACHE) && (error == ENOSPC)) ||
7392 		    error == EAGAIN) {
7393 			connected = 0;
7394 			continue;
7395 		}
7396 		if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
7397 			if (CFS_TIMEOUT(fscp, error)) {
7398 				cachefs_cd_release(fscp);
7399 				held = 0;
7400 				cachefs_cd_timedout(fscp);
7401 				connected = 0;
7402 				continue;
7403 			}
7404 		} else {
7405 			if (CFS_TIMEOUT(fscp, error)) {
7406 				if (cachefs_cd_access_miss(fscp)) {
7407 					if (len <= PAGESIZE)
7408 						error = cachefs_getapage_back(
7409 						    vp, (u_offset_t)off,
7410 						    len, protp, pl,
7411 						    plsz, seg, addr, rw, cr);
7412 					else
7413 						error = pvn_getpages(
7414 						    cachefs_getapage_back, vp,
7415 						    (u_offset_t)off, len,
7416 						    protp, pl,
7417 						    plsz, seg, addr, rw, cr);
7418 					if (!CFS_TIMEOUT(fscp, error) &&
7419 					    (error != EAGAIN))
7420 						break;
7421 					delay(5*hz);
7422 					connected = 0;
7423 					continue;
7424 				}
7425 				connected = 1;
7426 				continue;
7427 			}
7428 		}
7429 		break;
7430 	}
7431 
7432 	if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_GETPAGE))
7433 		cachefs_log_getpage(cachep, error, vp->v_vfsp,
7434 		    &cp->c_metadata.md_cookie, cp->c_id.cid_fileno,
7435 		    crgetuid(cr), off, len);
7436 
7437 	if (held) {
7438 		cachefs_cd_release(fscp);
7439 	}
7440 
7441 out:
7442 #ifdef CFS_CD_DEBUG
7443 	ASSERT((curthread->t_flag & T_CD_HELD) == 0);
7444 #endif
7445 #ifdef CFSDEBUG
7446 	CFS_DEBUG(CFSDEBUG_VOPS)
7447 		printf("cachefs_getpage: EXIT vp %p error %d\n",
7448 		    (void *)vp, error);
7449 #endif
7450 	return (error);
7451 }
7452 
7453 /*
7454  * cachefs_getpage_backfs_nfsv4
7455  *
7456  * Call NFSv4 back filesystem to handle the getpage (cachefs
7457  * pass-through support for NFSv4).
7458  */
7459 static int
7460 cachefs_getpage_backfs_nfsv4(struct vnode *vp, offset_t off, size_t len,
7461 			uint_t *protp, struct page *pl[], size_t plsz,
7462 			struct seg *seg, caddr_t addr, enum seg_rw rw,
7463 			cred_t *cr)
7464 {
7465 	cnode_t *cp = VTOC(vp);
7466 	fscache_t *fscp = C_TO_FSCACHE(cp);
7467 	vnode_t *backvp;
7468 	int error;
7469 
7470 	/*
7471 	 * For NFSv4 pass-through to work, only connected operation is
7472 	 * supported, the cnode backvp must exist, and cachefs optional
7473 	 * (eg., disconnectable) flags are turned off. Assert these
7474 	 * conditions for the getpage operation.
7475 	 */
7476 	CFS_BACKFS_NFSV4_ASSERT_FSCACHE(fscp);
7477 	CFS_BACKFS_NFSV4_ASSERT_CNODE(cp);
7478 
7479 	/* Call backfs vnode op after extracting backvp */
7480 	mutex_enter(&cp->c_statelock);
7481 	backvp = cp->c_backvp;
7482 	mutex_exit(&cp->c_statelock);
7483 
7484 	CFS_DPRINT_BACKFS_NFSV4(fscp,
7485 	    ("cachefs_getpage_backfs_nfsv4: cnode %p, backvp %p\n",
7486 	    cp, backvp));
7487 	error = VOP_GETPAGE(backvp, off, len, protp, pl, plsz, seg,
7488 	    addr, rw, cr, NULL);
7489 
7490 	return (error);
7491 }
7492 
7493 /*
7494  * Called from pvn_getpages or cachefs_getpage to get a particular page.
7495  */
7496 /*ARGSUSED*/
7497 static int
7498 cachefs_getapage(struct vnode *vp, u_offset_t off, size_t len, uint_t *protp,
7499 	struct page *pl[], size_t plsz, struct seg *seg, caddr_t addr,
7500 	enum seg_rw rw, cred_t *cr)
7501 {
7502 	cnode_t *cp = VTOC(vp);
7503 	page_t **ppp, *pp = NULL;
7504 	fscache_t *fscp = C_TO_FSCACHE(cp);
7505 	cachefscache_t *cachep = fscp->fs_cache;
7506 	int error = 0;
7507 	struct page **ourpl;
7508 	struct page *ourstackpl[17]; /* see ASSERT() below for 17 */
7509 	int index = 0;
7510 	int downgrade;
7511 	int have_statelock = 0;
7512 	u_offset_t popoff;
7513 	size_t popsize = 0;
7514 
7515 	/*LINTED*/
7516 	ASSERT(((DEF_POP_SIZE / PAGESIZE) + 1) <= 17);
7517 
7518 	if (fscp->fs_info.fi_popsize > DEF_POP_SIZE)
7519 		ourpl = cachefs_kmem_alloc(sizeof (struct page *) *
7520 		    ((fscp->fs_info.fi_popsize / PAGESIZE) + 1), KM_SLEEP);
7521 	else
7522 		ourpl = ourstackpl;
7523 
7524 	ourpl[0] = NULL;
7525 	off = off & (offset_t)PAGEMASK;
7526 again:
7527 	/*
7528 	 * Look for the page
7529 	 */
7530 	if (page_exists(vp, off) == 0) {
7531 		/*
7532 		 * Need to do work to get the page.
7533 		 * Grab our lock because we are going to
7534 		 * modify the state of the cnode.
7535 		 */
7536 		if (! have_statelock) {
7537 			mutex_enter(&cp->c_statelock);
7538 			have_statelock = 1;
7539 		}
7540 		/*
7541 		 * If we're in NOCACHE mode, we will need a backvp
7542 		 */
7543 		if (cp->c_flags & CN_NOCACHE) {
7544 			if (fscp->fs_cdconnected != CFS_CD_CONNECTED) {
7545 				error = ETIMEDOUT;
7546 				goto out;
7547 			}
7548 			if (cp->c_backvp == NULL) {
7549 				error = cachefs_getbackvp(fscp, cp);
7550 				if (error)
7551 					goto out;
7552 			}
7553 			error = VOP_GETPAGE(cp->c_backvp, off,
7554 			    PAGESIZE, protp, ourpl, PAGESIZE, seg,
7555 			    addr, S_READ, cr, NULL);
7556 			/*
7557 			 * backfs returns EFAULT when we are trying for a
7558 			 * page beyond EOF but cachefs has the knowledge that
7559 			 * it is not beyond EOF be cause cp->c_size is
7560 			 * greater then the offset requested.
7561 			 */
7562 			if (error == EFAULT) {
7563 				error = 0;
7564 				pp = page_create_va(vp, off, PAGESIZE,
7565 				    PG_EXCL | PG_WAIT, seg, addr);
7566 				if (pp == NULL)
7567 					goto again;
7568 				pagezero(pp, 0, PAGESIZE);
7569 				pvn_plist_init(pp, pl, plsz, off, PAGESIZE, rw);
7570 				goto out;
7571 			}
7572 			if (error)
7573 				goto out;
7574 			goto getpages;
7575 		}
7576 		/*
7577 		 * We need a front file. If we can't get it,
7578 		 * put the cnode in NOCACHE mode and try again.
7579 		 */
7580 		if (cp->c_frontvp == NULL) {
7581 			error = cachefs_getfrontfile(cp);
7582 			if (error) {
7583 				cachefs_nocache(cp);
7584 				error = EAGAIN;
7585 				goto out;
7586 			}
7587 		}
7588 		/*
7589 		 * Check if the front file needs population.
7590 		 * If population is necessary, make sure we have a
7591 		 * backvp as well. We will get the page from the backvp.
7592 		 * bug 4152459-
7593 		 * But if the file system is in disconnected mode
7594 		 * and the file is a local file then do not check the
7595 		 * allocmap.
7596 		 */
7597 		if (((fscp->fs_cdconnected == CFS_CD_CONNECTED) ||
7598 		    ((cp->c_metadata.md_flags & MD_LOCALFILENO) == 0)) &&
7599 		    (cachefs_check_allocmap(cp, off) == 0)) {
7600 			if (fscp->fs_cdconnected != CFS_CD_CONNECTED) {
7601 				error = ETIMEDOUT;
7602 				goto out;
7603 			}
7604 			if (cp->c_backvp == NULL) {
7605 				error = cachefs_getbackvp(fscp, cp);
7606 				if (error)
7607 					goto out;
7608 			}
7609 			if (cp->c_filegrp->fg_flags & CFS_FG_WRITE) {
7610 				cachefs_cluster_allocmap(off, &popoff,
7611 				    &popsize,
7612 				    fscp->fs_info.fi_popsize, cp);
7613 				if (popsize != 0) {
7614 					error = cachefs_populate(cp,
7615 					    popoff, popsize,
7616 					    cp->c_frontvp, cp->c_backvp,
7617 					    cp->c_size, cr);
7618 					if (error) {
7619 						cachefs_nocache(cp);
7620 						error = EAGAIN;
7621 						goto out;
7622 					} else {
7623 						cp->c_flags |=
7624 						    CN_UPDATED |
7625 						    CN_NEED_FRONT_SYNC |
7626 						    CN_POPULATION_PENDING;
7627 					}
7628 					popsize = popsize - (off - popoff);
7629 				} else {
7630 					popsize = PAGESIZE;
7631 				}
7632 			}
7633 			/* else XXX assert CN_NOCACHE? */
7634 			error = VOP_GETPAGE(cp->c_backvp, (offset_t)off,
7635 			    PAGESIZE, protp, ourpl, popsize,
7636 			    seg, addr, S_READ, cr, NULL);
7637 			if (error)
7638 				goto out;
7639 			fscp->fs_stats.st_misses++;
7640 		} else {
7641 			if (cp->c_flags & CN_POPULATION_PENDING) {
7642 				error = VOP_FSYNC(cp->c_frontvp, FSYNC, cr,
7643 				    NULL);
7644 				cp->c_flags &= ~CN_POPULATION_PENDING;
7645 				if (error) {
7646 					cachefs_nocache(cp);
7647 					error = EAGAIN;
7648 					goto out;
7649 				}
7650 			}
7651 			/*
7652 			 * File was populated so we get the page from the
7653 			 * frontvp
7654 			 */
7655 			error = VOP_GETPAGE(cp->c_frontvp, (offset_t)off,
7656 			    PAGESIZE, protp, ourpl, PAGESIZE, seg, addr,
7657 			    rw, cr, NULL);
7658 			if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_GPFRONT))
7659 				cachefs_log_gpfront(cachep, error,
7660 				    fscp->fs_cfsvfsp,
7661 				    &cp->c_metadata.md_cookie, cp->c_fileno,
7662 				    crgetuid(cr), off, PAGESIZE);
7663 			if (error) {
7664 				cachefs_nocache(cp);
7665 				error = EAGAIN;
7666 				goto out;
7667 			}
7668 			fscp->fs_stats.st_hits++;
7669 		}
7670 getpages:
7671 		ASSERT(have_statelock);
7672 		if (have_statelock) {
7673 			mutex_exit(&cp->c_statelock);
7674 			have_statelock = 0;
7675 		}
7676 		downgrade = 0;
7677 		for (ppp = ourpl; *ppp; ppp++) {
7678 			if ((*ppp)->p_offset < off) {
7679 				index++;
7680 				page_unlock(*ppp);
7681 				continue;
7682 			}
7683 			if (PAGE_SHARED(*ppp)) {
7684 				if (page_tryupgrade(*ppp) == 0) {
7685 					for (ppp = &ourpl[index]; *ppp; ppp++)
7686 						page_unlock(*ppp);
7687 					error = EAGAIN;
7688 					goto out;
7689 				}
7690 				downgrade = 1;
7691 			}
7692 			ASSERT(PAGE_EXCL(*ppp));
7693 			(void) hat_pageunload((*ppp), HAT_FORCE_PGUNLOAD);
7694 			page_rename(*ppp, vp, (*ppp)->p_offset);
7695 		}
7696 		pl[0] = ourpl[index];
7697 		pl[1] = NULL;
7698 		if (downgrade) {
7699 			page_downgrade(ourpl[index]);
7700 		}
7701 		/* Unlock the rest of the pages from the cluster */
7702 		for (ppp = &ourpl[index+1]; *ppp; ppp++)
7703 			page_unlock(*ppp);
7704 	} else {
7705 		ASSERT(! have_statelock);
7706 		if (have_statelock) {
7707 			mutex_exit(&cp->c_statelock);
7708 			have_statelock = 0;
7709 		}
7710 		/* XXX SE_SHARED probably isn't what we *always* want */
7711 		if ((pp = page_lookup(vp, off, SE_SHARED)) == NULL) {
7712 			cachefs_lostpage++;
7713 			goto again;
7714 		}
7715 		pl[0] = pp;
7716 		pl[1] = NULL;
7717 		/* XXX increment st_hits?  i don't think so, but... */
7718 	}
7719 
7720 out:
7721 	if (have_statelock) {
7722 		mutex_exit(&cp->c_statelock);
7723 		have_statelock = 0;
7724 	}
7725 	if (fscp->fs_info.fi_popsize > DEF_POP_SIZE)
7726 		cachefs_kmem_free(ourpl, sizeof (struct page *) *
7727 		    ((fscp->fs_info.fi_popsize / PAGESIZE) + 1));
7728 	return (error);
7729 }
7730 
7731 /* gets a page but only from the back fs */
7732 /*ARGSUSED*/
7733 static int
7734 cachefs_getapage_back(struct vnode *vp, u_offset_t off, size_t len,
7735     uint_t *protp, struct page *pl[], size_t plsz, struct seg *seg,
7736     caddr_t addr, enum seg_rw rw, cred_t *cr)
7737 {
7738 	cnode_t *cp = VTOC(vp);
7739 	page_t **ppp, *pp = NULL;
7740 	fscache_t *fscp = C_TO_FSCACHE(cp);
7741 	int error = 0;
7742 	struct page *ourpl[17];
7743 	int index = 0;
7744 	int have_statelock = 0;
7745 	int downgrade;
7746 
7747 	/*
7748 	 * Grab the cnode statelock so the cnode state won't change
7749 	 * while we're in here.
7750 	 */
7751 	ourpl[0] = NULL;
7752 	off = off & (offset_t)PAGEMASK;
7753 again:
7754 	if (page_exists(vp, off) == 0) {
7755 		if (! have_statelock) {
7756 			mutex_enter(&cp->c_statelock);
7757 			have_statelock = 1;
7758 		}
7759 
7760 		if (cp->c_backvp == NULL) {
7761 			error = cachefs_getbackvp(fscp, cp);
7762 			if (error)
7763 				goto out;
7764 		}
7765 		error = VOP_GETPAGE(cp->c_backvp, (offset_t)off,
7766 		    PAGESIZE, protp, ourpl, PAGESIZE, seg,
7767 		    addr, S_READ, cr, NULL);
7768 		if (error)
7769 			goto out;
7770 
7771 		if (have_statelock) {
7772 			mutex_exit(&cp->c_statelock);
7773 			have_statelock = 0;
7774 		}
7775 		downgrade = 0;
7776 		for (ppp = ourpl; *ppp; ppp++) {
7777 			if ((*ppp)->p_offset < off) {
7778 				index++;
7779 				page_unlock(*ppp);
7780 				continue;
7781 			}
7782 			if (PAGE_SHARED(*ppp)) {
7783 				if (page_tryupgrade(*ppp) == 0) {
7784 					for (ppp = &ourpl[index]; *ppp; ppp++)
7785 						page_unlock(*ppp);
7786 					error = EAGAIN;
7787 					goto out;
7788 				}
7789 				downgrade = 1;
7790 			}
7791 			ASSERT(PAGE_EXCL(*ppp));
7792 			(void) hat_pageunload((*ppp), HAT_FORCE_PGUNLOAD);
7793 			page_rename(*ppp, vp, (*ppp)->p_offset);
7794 		}
7795 		pl[0] = ourpl[index];
7796 		pl[1] = NULL;
7797 		if (downgrade) {
7798 			page_downgrade(ourpl[index]);
7799 		}
7800 		/* Unlock the rest of the pages from the cluster */
7801 		for (ppp = &ourpl[index+1]; *ppp; ppp++)
7802 			page_unlock(*ppp);
7803 	} else {
7804 		ASSERT(! have_statelock);
7805 		if (have_statelock) {
7806 			mutex_exit(&cp->c_statelock);
7807 			have_statelock = 0;
7808 		}
7809 		if ((pp = page_lookup(vp, off, SE_SHARED)) == NULL) {
7810 			cachefs_lostpage++;
7811 			goto again;
7812 		}
7813 		pl[0] = pp;
7814 		pl[1] = NULL;
7815 	}
7816 
7817 out:
7818 	if (have_statelock) {
7819 		mutex_exit(&cp->c_statelock);
7820 		have_statelock = 0;
7821 	}
7822 	return (error);
7823 }
7824 
7825 /*ARGSUSED*/
7826 static int
7827 cachefs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr,
7828     caller_context_t *ct)
7829 {
7830 	cnode_t *cp = VTOC(vp);
7831 	int error = 0;
7832 	fscache_t *fscp = C_TO_FSCACHE(cp);
7833 	int held = 0;
7834 	int connected = 0;
7835 
7836 	if (getzoneid() != GLOBAL_ZONEID)
7837 		return (EPERM);
7838 
7839 	/* Call backfilesytem if NFSv4 */
7840 	if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
7841 		error = cachefs_putpage_backfs_nfsv4(vp, off, len, flags, cr);
7842 		goto out;
7843 	}
7844 
7845 	for (;;) {
7846 		/* get (or renew) access to the file system */
7847 		if (held) {
7848 			cachefs_cd_release(fscp);
7849 			held = 0;
7850 		}
7851 		error = cachefs_cd_access(fscp, connected, 1);
7852 		if (error)
7853 			break;
7854 		held = 1;
7855 
7856 		error = cachefs_putpage_common(vp, off, len, flags, cr);
7857 		if (error == 0)
7858 			break;
7859 
7860 		if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
7861 			if (CFS_TIMEOUT(fscp, error)) {
7862 				cachefs_cd_release(fscp);
7863 				held = 0;
7864 				cachefs_cd_timedout(fscp);
7865 				connected = 0;
7866 				continue;
7867 			}
7868 		} else {
7869 			if (NOMEMWAIT()) {
7870 				error = 0;
7871 				goto out;
7872 			}
7873 			if (CFS_TIMEOUT(fscp, error)) {
7874 				connected = 1;
7875 				continue;
7876 			}
7877 		}
7878 		break;
7879 	}
7880 
7881 out:
7882 
7883 	if (held) {
7884 		cachefs_cd_release(fscp);
7885 	}
7886 
7887 #ifdef CFS_CD_DEBUG
7888 	ASSERT((curthread->t_flag & T_CD_HELD) == 0);
7889 #endif
7890 	return (error);
7891 }
7892 
7893 /*
7894  * cachefs_putpage_backfs_nfsv4
7895  *
7896  * Call NFSv4 back filesystem to handle the putpage (cachefs
7897  * pass-through support for NFSv4).
7898  */
7899 static int
7900 cachefs_putpage_backfs_nfsv4(vnode_t *vp, offset_t off, size_t len, int flags,
7901 			cred_t *cr)
7902 {
7903 	cnode_t *cp = VTOC(vp);
7904 	fscache_t *fscp = C_TO_FSCACHE(cp);
7905 	vnode_t *backvp;
7906 	int error;
7907 
7908 	/*
7909 	 * For NFSv4 pass-through to work, only connected operation is
7910 	 * supported, the cnode backvp must exist, and cachefs optional
7911 	 * (eg., disconnectable) flags are turned off. Assert these
7912 	 * conditions for the putpage operation.
7913 	 */
7914 	CFS_BACKFS_NFSV4_ASSERT_FSCACHE(fscp);
7915 	CFS_BACKFS_NFSV4_ASSERT_CNODE(cp);
7916 
7917 	/* Call backfs vnode op after extracting backvp */
7918 	mutex_enter(&cp->c_statelock);
7919 	backvp = cp->c_backvp;
7920 	mutex_exit(&cp->c_statelock);
7921 
7922 	CFS_DPRINT_BACKFS_NFSV4(fscp,
7923 	    ("cachefs_putpage_backfs_nfsv4: cnode %p, backvp %p\n",
7924 	    cp, backvp));
7925 	error = VOP_PUTPAGE(backvp, off, len, flags, cr, NULL);
7926 
7927 	return (error);
7928 }
7929 
7930 /*
7931  * Flags are composed of {B_INVAL, B_FREE, B_DONTNEED, B_FORCE}
7932  * If len == 0, do from off to EOF.
7933  *
7934  * The normal cases should be len == 0 & off == 0 (entire vp list),
7935  * len == MAXBSIZE (from segmap_release actions), and len == PAGESIZE
7936  * (from pageout).
7937  */
7938 
7939 /*ARGSUSED*/
7940 int
7941 cachefs_putpage_common(struct vnode *vp, offset_t off, size_t len,
7942     int flags, cred_t *cr)
7943 {
7944 	struct cnode *cp  = VTOC(vp);
7945 	struct page *pp;
7946 	size_t io_len;
7947 	u_offset_t eoff, io_off;
7948 	int error = 0;
7949 	fscache_t *fscp = C_TO_FSCACHE(cp);
7950 	cachefscache_t *cachep = fscp->fs_cache;
7951 
7952 	if (len == 0 && (flags & B_INVAL) == 0 && vn_is_readonly(vp)) {
7953 		return (0);
7954 	}
7955 	if (!vn_has_cached_data(vp) || (off >= cp->c_size &&
7956 	    (flags & B_INVAL) == 0))
7957 		return (0);
7958 
7959 	/*
7960 	 * Should never have cached data for the cachefs vnode
7961 	 * if NFSv4 is in use.
7962 	 */
7963 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
7964 
7965 	/*
7966 	 * If this is an async putpage let a thread handle it.
7967 	 */
7968 	if (flags & B_ASYNC) {
7969 		struct cachefs_req *rp;
7970 		int tflags = (flags & ~(B_ASYNC|B_DONTNEED));
7971 
7972 		if (ttoproc(curthread) == proc_pageout) {
7973 			/*
7974 			 * If this is the page daemon we
7975 			 * do the push synchronously (Dangerous!) and hope
7976 			 * we can free enough to keep running...
7977 			 */
7978 			flags &= ~B_ASYNC;
7979 			goto again;
7980 		}
7981 
7982 		if (! cachefs_async_okay()) {
7983 
7984 			/*
7985 			 * this is somewhat like NFS's behavior.  keep
7986 			 * the system from thrashing.  we've seen
7987 			 * cases where async queues get out of
7988 			 * control, especially if
7989 			 * madvise(MADV_SEQUENTIAL) is done on a large
7990 			 * mmap()ed file that is read sequentially.
7991 			 */
7992 
7993 			flags &= ~B_ASYNC;
7994 			goto again;
7995 		}
7996 
7997 		/*
7998 		 * if no flags other than B_ASYNC were set,
7999 		 * we coalesce putpage requests into a single one for the
8000 		 * whole file (len = off = 0).  If such a request is
8001 		 * already queued, we're done.
8002 		 *
8003 		 * If there are other flags set (e.g., B_INVAL), we don't
8004 		 * attempt to coalesce and we use the specified length and
8005 		 * offset.
8006 		 */
8007 		rp = kmem_cache_alloc(cachefs_req_cache, KM_SLEEP);
8008 		mutex_enter(&cp->c_iomutex);
8009 		if ((cp->c_ioflags & CIO_PUTPAGES) == 0 || tflags != 0) {
8010 			rp->cfs_cmd = CFS_PUTPAGE;
8011 			rp->cfs_req_u.cu_putpage.cp_vp = vp;
8012 			if (tflags == 0) {
8013 				off = len = 0;
8014 				cp->c_ioflags |= CIO_PUTPAGES;
8015 			}
8016 			rp->cfs_req_u.cu_putpage.cp_off = off;
8017 			rp->cfs_req_u.cu_putpage.cp_len = (uint_t)len;
8018 			rp->cfs_req_u.cu_putpage.cp_flags = flags & ~B_ASYNC;
8019 			rp->cfs_cr = cr;
8020 			crhold(rp->cfs_cr);
8021 			VN_HOLD(vp);
8022 			cp->c_nio++;
8023 			cachefs_addqueue(rp, &(C_TO_FSCACHE(cp)->fs_workq));
8024 		} else {
8025 			kmem_cache_free(cachefs_req_cache, rp);
8026 		}
8027 
8028 		mutex_exit(&cp->c_iomutex);
8029 		return (0);
8030 	}
8031 
8032 
8033 again:
8034 	if (len == 0) {
8035 		/*
8036 		 * Search the entire vp list for pages >= off
8037 		 */
8038 		error = pvn_vplist_dirty(vp, off, cachefs_push, flags, cr);
8039 	} else {
8040 		/*
8041 		 * Do a range from [off...off + len] looking for pages
8042 		 * to deal with.
8043 		 */
8044 		eoff = (u_offset_t)off + len;
8045 		for (io_off = off; io_off < eoff && io_off < cp->c_size;
8046 		    io_off += io_len) {
8047 			/*
8048 			 * If we are not invalidating, synchronously
8049 			 * freeing or writing pages use the routine
8050 			 * page_lookup_nowait() to prevent reclaiming
8051 			 * them from the free list.
8052 			 */
8053 			if ((flags & B_INVAL) || ((flags & B_ASYNC) == 0)) {
8054 				pp = page_lookup(vp, io_off,
8055 				    (flags & (B_INVAL | B_FREE)) ?
8056 				    SE_EXCL : SE_SHARED);
8057 			} else {
8058 				/* XXX this looks like dead code */
8059 				pp = page_lookup_nowait(vp, io_off,
8060 				    (flags & B_FREE) ? SE_EXCL : SE_SHARED);
8061 			}
8062 
8063 			if (pp == NULL || pvn_getdirty(pp, flags) == 0)
8064 				io_len = PAGESIZE;
8065 			else {
8066 				error = cachefs_push(vp, pp, &io_off,
8067 				    &io_len, flags, cr);
8068 				if (error != 0)
8069 					break;
8070 				/*
8071 				 * "io_off" and "io_len" are returned as
8072 				 * the range of pages we actually wrote.
8073 				 * This allows us to skip ahead more quickly
8074 				 * since several pages may've been dealt
8075 				 * with by this iteration of the loop.
8076 				 */
8077 			}
8078 		}
8079 	}
8080 
8081 	if (error == 0 && off == 0 && (len == 0 || len >= cp->c_size)) {
8082 		cp->c_flags &= ~CDIRTY;
8083 	}
8084 
8085 	if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_PUTPAGE))
8086 		cachefs_log_putpage(cachep, error, fscp->fs_cfsvfsp,
8087 		    &cp->c_metadata.md_cookie, cp->c_id.cid_fileno,
8088 		    crgetuid(cr), off, len);
8089 
8090 	return (error);
8091 
8092 }
8093 
8094 /*ARGSUSED*/
8095 static int
8096 cachefs_map(struct vnode *vp, offset_t off, struct as *as, caddr_t *addrp,
8097     size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr,
8098     caller_context_t *ct)
8099 {
8100 	cnode_t *cp = VTOC(vp);
8101 	fscache_t *fscp = C_TO_FSCACHE(cp);
8102 	struct segvn_crargs vn_a;
8103 	int error;
8104 	int held = 0;
8105 	int writing;
8106 	int connected = 0;
8107 
8108 #ifdef CFSDEBUG
8109 	u_offset_t offx = (u_offset_t)off;
8110 
8111 	CFS_DEBUG(CFSDEBUG_VOPS)
8112 		printf("cachefs_map: ENTER vp %p off %lld len %lu flags %d\n",
8113 		    (void *)vp, offx, len, flags);
8114 #endif
8115 	if (getzoneid() != GLOBAL_ZONEID) {
8116 		error = EPERM;
8117 		goto out;
8118 	}
8119 
8120 	if (vp->v_flag & VNOMAP) {
8121 		error = ENOSYS;
8122 		goto out;
8123 	}
8124 	if (off < 0 || (offset_t)(off + len) < 0) {
8125 		error = ENXIO;
8126 		goto out;
8127 	}
8128 	if (vp->v_type != VREG) {
8129 		error = ENODEV;
8130 		goto out;
8131 	}
8132 
8133 	/*
8134 	 * Check to see if the vnode is currently marked as not cachable.
8135 	 * If so, we have to refuse the map request as this violates the
8136 	 * don't cache attribute.
8137 	 */
8138 	if (vp->v_flag & VNOCACHE)
8139 		return (EAGAIN);
8140 
8141 #ifdef OBSOLETE
8142 	/*
8143 	 * If file is being locked, disallow mapping.
8144 	 */
8145 	if (vn_has_flocks(vp)) {
8146 		error = EAGAIN;
8147 		goto out;
8148 	}
8149 #endif
8150 
8151 	/* call backfilesystem if NFSv4 */
8152 	if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
8153 		error = cachefs_map_backfs_nfsv4(vp, off, as, addrp, len, prot,
8154 		    maxprot, flags, cr);
8155 		goto out;
8156 	}
8157 
8158 	writing = (prot & PROT_WRITE && ((flags & MAP_PRIVATE) == 0));
8159 
8160 	for (;;) {
8161 		/* get (or renew) access to the file system */
8162 		if (held) {
8163 			cachefs_cd_release(fscp);
8164 			held = 0;
8165 		}
8166 		error = cachefs_cd_access(fscp, connected, writing);
8167 		if (error)
8168 			break;
8169 		held = 1;
8170 
8171 		if (writing) {
8172 			mutex_enter(&cp->c_statelock);
8173 			if (CFS_ISFS_WRITE_AROUND(fscp)) {
8174 				if (fscp->fs_cdconnected != CFS_CD_CONNECTED) {
8175 					connected = 1;
8176 					continue;
8177 				} else {
8178 					cachefs_nocache(cp);
8179 				}
8180 			}
8181 
8182 			/*
8183 			 * CN_MAPWRITE is for an optimization in cachefs_delmap.
8184 			 * If CN_MAPWRITE is not set then cachefs_delmap does
8185 			 * not need to try to push out any pages.
8186 			 * This bit gets cleared when the cnode goes inactive.
8187 			 */
8188 			cp->c_flags |= CN_MAPWRITE;
8189 
8190 			mutex_exit(&cp->c_statelock);
8191 		}
8192 		break;
8193 	}
8194 
8195 	if (held) {
8196 		cachefs_cd_release(fscp);
8197 	}
8198 
8199 	as_rangelock(as);
8200 	error = choose_addr(as, addrp, len, off, ADDR_VACALIGN, flags);
8201 	if (error != 0) {
8202 		as_rangeunlock(as);
8203 		goto out;
8204 	}
8205 
8206 	/*
8207 	 * package up all the data passed in into a segvn_args struct and
8208 	 * call as_map with segvn_create function to create a new segment
8209 	 * in the address space.
8210 	 */
8211 	vn_a.vp = vp;
8212 	vn_a.offset = off;
8213 	vn_a.type = flags & MAP_TYPE;
8214 	vn_a.prot = (uchar_t)prot;
8215 	vn_a.maxprot = (uchar_t)maxprot;
8216 	vn_a.cred = cr;
8217 	vn_a.amp = NULL;
8218 	vn_a.flags = flags & ~MAP_TYPE;
8219 	vn_a.szc = 0;
8220 	vn_a.lgrp_mem_policy_flags = 0;
8221 	error = as_map(as, *addrp, len, segvn_create, &vn_a);
8222 	as_rangeunlock(as);
8223 out:
8224 
8225 #ifdef CFS_CD_DEBUG
8226 	ASSERT((curthread->t_flag & T_CD_HELD) == 0);
8227 #endif
8228 #ifdef CFSDEBUG
8229 	CFS_DEBUG(CFSDEBUG_VOPS)
8230 		printf("cachefs_map: EXIT vp %p error %d\n", (void *)vp, error);
8231 #endif
8232 	return (error);
8233 }
8234 
8235 /*
8236  * cachefs_map_backfs_nfsv4
8237  *
8238  * Call NFSv4 back filesystem to handle the map (cachefs
8239  * pass-through support for NFSv4).
8240  */
8241 static int
8242 cachefs_map_backfs_nfsv4(struct vnode *vp, offset_t off, struct as *as,
8243 			caddr_t *addrp, size_t len, uchar_t prot,
8244 			uchar_t maxprot, uint_t flags, cred_t *cr)
8245 {
8246 	cnode_t *cp = VTOC(vp);
8247 	fscache_t *fscp = C_TO_FSCACHE(cp);
8248 	vnode_t *backvp;
8249 	int error;
8250 
8251 	/*
8252 	 * For NFSv4 pass-through to work, only connected operation is
8253 	 * supported, the cnode backvp must exist, and cachefs optional
8254 	 * (eg., disconnectable) flags are turned off. Assert these
8255 	 * conditions for the map operation.
8256 	 */
8257 	CFS_BACKFS_NFSV4_ASSERT_FSCACHE(fscp);
8258 	CFS_BACKFS_NFSV4_ASSERT_CNODE(cp);
8259 
8260 	/* Call backfs vnode op after extracting backvp */
8261 	mutex_enter(&cp->c_statelock);
8262 	backvp = cp->c_backvp;
8263 	mutex_exit(&cp->c_statelock);
8264 
8265 	CFS_DPRINT_BACKFS_NFSV4(fscp,
8266 	    ("cachefs_map_backfs_nfsv4: cnode %p, backvp %p\n",
8267 	    cp, backvp));
8268 	error = VOP_MAP(backvp, off, as, addrp, len, prot, maxprot, flags, cr,
8269 	    NULL);
8270 
8271 	return (error);
8272 }
8273 
8274 /*ARGSUSED*/
8275 static int
8276 cachefs_addmap(struct vnode *vp, offset_t off, struct as *as,
8277     caddr_t addr, size_t len, uchar_t prot, uchar_t maxprot, uint_t flags,
8278     cred_t *cr, caller_context_t *ct)
8279 {
8280 	cnode_t *cp = VTOC(vp);
8281 	fscache_t *fscp = C_TO_FSCACHE(cp);
8282 
8283 	if (getzoneid() != GLOBAL_ZONEID)
8284 		return (EPERM);
8285 
8286 	if (vp->v_flag & VNOMAP)
8287 		return (ENOSYS);
8288 
8289 	/*
8290 	 * Check this is not an NFSv4 filesystem, as the mapping
8291 	 * is not done on the cachefs filesystem if NFSv4 is in
8292 	 * use.
8293 	 */
8294 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
8295 
8296 	mutex_enter(&cp->c_statelock);
8297 	cp->c_mapcnt += btopr(len);
8298 	mutex_exit(&cp->c_statelock);
8299 	return (0);
8300 }
8301 
8302 /*ARGSUSED*/
8303 static int
8304 cachefs_delmap(struct vnode *vp, offset_t off, struct as *as,
8305 	caddr_t addr, size_t len, uint_t prot, uint_t maxprot, uint_t flags,
8306 	cred_t *cr, caller_context_t *ct)
8307 {
8308 	cnode_t *cp = VTOC(vp);
8309 	fscache_t *fscp = C_TO_FSCACHE(cp);
8310 	int error;
8311 	int connected = 0;
8312 	int held = 0;
8313 
8314 	/*
8315 	 * The file may be passed in to (or inherited into) the zone, so we
8316 	 * need to let this operation go through since it happens as part of
8317 	 * exiting.
8318 	 */
8319 	if (vp->v_flag & VNOMAP)
8320 		return (ENOSYS);
8321 
8322 	/*
8323 	 * Check this is not an NFSv4 filesystem, as the mapping
8324 	 * is not done on the cachefs filesystem if NFSv4 is in
8325 	 * use.
8326 	 */
8327 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
8328 
8329 	mutex_enter(&cp->c_statelock);
8330 	cp->c_mapcnt -= btopr(len);
8331 	ASSERT(cp->c_mapcnt >= 0);
8332 	mutex_exit(&cp->c_statelock);
8333 
8334 	if (cp->c_mapcnt || !vn_has_cached_data(vp) ||
8335 	    ((cp->c_flags & CN_MAPWRITE) == 0))
8336 		return (0);
8337 
8338 	for (;;) {
8339 		/* get (or renew) access to the file system */
8340 		if (held) {
8341 			cachefs_cd_release(fscp);
8342 			held = 0;
8343 		}
8344 		error = cachefs_cd_access(fscp, connected, 1);
8345 		if (error)
8346 			break;
8347 		held = 1;
8348 		connected = 0;
8349 
8350 		error = cachefs_putpage_common(vp, (offset_t)0,
8351 		    (uint_t)0, 0, cr);
8352 		if (CFS_TIMEOUT(fscp, error)) {
8353 			if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
8354 				cachefs_cd_release(fscp);
8355 				held = 0;
8356 				cachefs_cd_timedout(fscp);
8357 				continue;
8358 			} else {
8359 				connected = 1;
8360 				continue;
8361 			}
8362 		}
8363 
8364 		/* if no space left in cache, wait until connected */
8365 		if ((error == ENOSPC) &&
8366 		    (fscp->fs_cdconnected != CFS_CD_CONNECTED)) {
8367 			connected = 1;
8368 			continue;
8369 		}
8370 
8371 		mutex_enter(&cp->c_statelock);
8372 		if (!error)
8373 			error = cp->c_error;
8374 		cp->c_error = 0;
8375 		mutex_exit(&cp->c_statelock);
8376 		break;
8377 	}
8378 
8379 	if (held)
8380 		cachefs_cd_release(fscp);
8381 
8382 #ifdef CFS_CD_DEBUG
8383 	ASSERT((curthread->t_flag & T_CD_HELD) == 0);
8384 #endif
8385 	return (error);
8386 }
8387 
8388 /* ARGSUSED */
8389 static int
8390 cachefs_frlock(struct vnode *vp, int cmd, struct flock64 *bfp, int flag,
8391 	offset_t offset, struct flk_callback *flk_cbp, cred_t *cr,
8392 	caller_context_t *ct)
8393 {
8394 	struct cnode *cp = VTOC(vp);
8395 	int error;
8396 	struct fscache *fscp = C_TO_FSCACHE(cp);
8397 	vnode_t *backvp;
8398 	int held = 0;
8399 	int connected = 0;
8400 
8401 	if (getzoneid() != GLOBAL_ZONEID)
8402 		return (EPERM);
8403 
8404 	if ((cmd != F_GETLK) && (cmd != F_SETLK) && (cmd != F_SETLKW))
8405 		return (EINVAL);
8406 
8407 	/* Disallow locking of files that are currently mapped */
8408 	if (((cmd == F_SETLK) || (cmd == F_SETLKW)) && (cp->c_mapcnt > 0)) {
8409 		ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
8410 		return (EAGAIN);
8411 	}
8412 
8413 	/*
8414 	 * Cachefs only provides pass-through support for NFSv4,
8415 	 * and all vnode operations are passed through to the
8416 	 * back file system. For NFSv4 pass-through to work, only
8417 	 * connected operation is supported, the cnode backvp must
8418 	 * exist, and cachefs optional (eg., disconnectable) flags
8419 	 * are turned off. Assert these conditions to ensure that
8420 	 * the backfilesystem is called for the frlock operation.
8421 	 */
8422 	CFS_BACKFS_NFSV4_ASSERT_FSCACHE(fscp);
8423 	CFS_BACKFS_NFSV4_ASSERT_CNODE(cp);
8424 
8425 	/* XXX bob: nfs does a bunch more checks than we do */
8426 	if (CFS_ISFS_LLOCK(fscp)) {
8427 		ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
8428 		return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct));
8429 	}
8430 
8431 	for (;;) {
8432 		/* get (or renew) access to the file system */
8433 		if (held) {
8434 			/* Won't loop with NFSv4 connected behavior */
8435 			ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
8436 			cachefs_cd_release(fscp);
8437 			held = 0;
8438 		}
8439 		error = cachefs_cd_access(fscp, connected, 0);
8440 		if (error)
8441 			break;
8442 		held = 1;
8443 
8444 		/* if not connected, quit or wait */
8445 		if (fscp->fs_cdconnected != CFS_CD_CONNECTED) {
8446 			connected = 1;
8447 			continue;
8448 		}
8449 
8450 		/* nocache the file */
8451 		if ((cp->c_flags & CN_NOCACHE) == 0 &&
8452 		    !CFS_ISFS_BACKFS_NFSV4(fscp)) {
8453 			mutex_enter(&cp->c_statelock);
8454 			cachefs_nocache(cp);
8455 			mutex_exit(&cp->c_statelock);
8456 		}
8457 
8458 		/*
8459 		 * XXX bob: probably should do a consistency check
8460 		 * Pass arguments unchanged if NFSv4 is the backfs.
8461 		 */
8462 		if (bfp->l_whence == 2 && CFS_ISFS_BACKFS_NFSV4(fscp) == 0) {
8463 			bfp->l_start += cp->c_size;
8464 			bfp->l_whence = 0;
8465 		}
8466 
8467 		/* get the back vp */
8468 		mutex_enter(&cp->c_statelock);
8469 		if (cp->c_backvp == NULL) {
8470 			error = cachefs_getbackvp(fscp, cp);
8471 			if (error) {
8472 				mutex_exit(&cp->c_statelock);
8473 				break;
8474 			}
8475 		}
8476 		backvp = cp->c_backvp;
8477 		VN_HOLD(backvp);
8478 		mutex_exit(&cp->c_statelock);
8479 
8480 		/*
8481 		 * make sure we can flush currently dirty pages before
8482 		 * allowing the lock
8483 		 */
8484 		if (bfp->l_type != F_UNLCK && cmd != F_GETLK &&
8485 		    !CFS_ISFS_BACKFS_NFSV4(fscp)) {
8486 			error = cachefs_putpage(
8487 			    vp, (offset_t)0, 0, B_INVAL, cr, ct);
8488 			if (error) {
8489 				error = ENOLCK;
8490 				VN_RELE(backvp);
8491 				break;
8492 			}
8493 		}
8494 
8495 		/* do lock on the back file */
8496 		CFS_DPRINT_BACKFS_NFSV4(fscp,
8497 		    ("cachefs_frlock (nfsv4): cp %p, backvp %p\n",
8498 		    cp, backvp));
8499 		error = VOP_FRLOCK(backvp, cmd, bfp, flag, offset, NULL, cr,
8500 		    ct);
8501 		VN_RELE(backvp);
8502 		if (CFS_TIMEOUT(fscp, error)) {
8503 			connected = 1;
8504 			continue;
8505 		}
8506 		break;
8507 	}
8508 
8509 	if (held) {
8510 		cachefs_cd_release(fscp);
8511 	}
8512 
8513 	/*
8514 	 * If we are setting a lock mark the vnode VNOCACHE so the page
8515 	 * cache does not give inconsistent results on locked files shared
8516 	 * between clients.  The VNOCACHE flag is never turned off as long
8517 	 * as the vnode is active because it is hard to figure out when the
8518 	 * last lock is gone.
8519 	 * XXX - what if some already has the vnode mapped in?
8520 	 * XXX bob: see nfs3_frlock, do not allow locking if vnode mapped in.
8521 	 */
8522 	if ((error == 0) && (bfp->l_type != F_UNLCK) && (cmd != F_GETLK) &&
8523 	    !CFS_ISFS_BACKFS_NFSV4(fscp))
8524 		vp->v_flag |= VNOCACHE;
8525 
8526 #ifdef CFS_CD_DEBUG
8527 	ASSERT((curthread->t_flag & T_CD_HELD) == 0);
8528 #endif
8529 	return (error);
8530 }
8531 
8532 /*
8533  * Free storage space associated with the specified vnode.  The portion
8534  * to be freed is specified by bfp->l_start and bfp->l_len (already
8535  * normalized to a "whence" of 0).
8536  *
8537  * This is an experimental facility whose continued existence is not
8538  * guaranteed.  Currently, we only support the special case
8539  * of l_len == 0, meaning free to end of file.
8540  */
8541 /* ARGSUSED */
8542 static int
8543 cachefs_space(struct vnode *vp, int cmd, struct flock64 *bfp, int flag,
8544 	offset_t offset, cred_t *cr, caller_context_t *ct)
8545 {
8546 	cnode_t *cp = VTOC(vp);
8547 	fscache_t *fscp = C_TO_FSCACHE(cp);
8548 	int error;
8549 
8550 	ASSERT(vp->v_type == VREG);
8551 	if (getzoneid() != GLOBAL_ZONEID)
8552 		return (EPERM);
8553 	if (cmd != F_FREESP)
8554 		return (EINVAL);
8555 
8556 	/* call backfilesystem if NFSv4 */
8557 	if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
8558 		error = cachefs_space_backfs_nfsv4(vp, cmd, bfp, flag,
8559 		    offset, cr, ct);
8560 		goto out;
8561 	}
8562 
8563 	if ((error = convoff(vp, bfp, 0, offset)) == 0) {
8564 		ASSERT(bfp->l_start >= 0);
8565 		if (bfp->l_len == 0) {
8566 			struct vattr va;
8567 
8568 			va.va_size = bfp->l_start;
8569 			va.va_mask = AT_SIZE;
8570 			error = cachefs_setattr(vp, &va, 0, cr, ct);
8571 		} else
8572 			error = EINVAL;
8573 	}
8574 
8575 out:
8576 	return (error);
8577 }
8578 
8579 /*
8580  * cachefs_space_backfs_nfsv4
8581  *
8582  * Call NFSv4 back filesystem to handle the space (cachefs
8583  * pass-through support for NFSv4).
8584  */
8585 static int
8586 cachefs_space_backfs_nfsv4(struct vnode *vp, int cmd, struct flock64 *bfp,
8587 		int flag, offset_t offset, cred_t *cr, caller_context_t *ct)
8588 {
8589 	cnode_t *cp = VTOC(vp);
8590 	fscache_t *fscp = C_TO_FSCACHE(cp);
8591 	vnode_t *backvp;
8592 	int error;
8593 
8594 	/*
8595 	 * For NFSv4 pass-through to work, only connected operation is
8596 	 * supported, the cnode backvp must exist, and cachefs optional
8597 	 * (eg., disconnectable) flags are turned off. Assert these
8598 	 * conditions for the space operation.
8599 	 */
8600 	CFS_BACKFS_NFSV4_ASSERT_FSCACHE(fscp);
8601 	CFS_BACKFS_NFSV4_ASSERT_CNODE(cp);
8602 
8603 	/* Call backfs vnode op after extracting backvp */
8604 	mutex_enter(&cp->c_statelock);
8605 	backvp = cp->c_backvp;
8606 	mutex_exit(&cp->c_statelock);
8607 
8608 	CFS_DPRINT_BACKFS_NFSV4(fscp,
8609 	    ("cachefs_space_backfs_nfsv4: cnode %p, backvp %p\n",
8610 	    cp, backvp));
8611 	error = VOP_SPACE(backvp, cmd, bfp, flag, offset, cr, ct);
8612 
8613 	return (error);
8614 }
8615 
8616 /*ARGSUSED*/
8617 static int
8618 cachefs_realvp(struct vnode *vp, struct vnode **vpp, caller_context_t *ct)
8619 {
8620 	return (EINVAL);
8621 }
8622 
8623 /*ARGSUSED*/
8624 static int
8625 cachefs_pageio(struct vnode *vp, page_t *pp, u_offset_t io_off, size_t io_len,
8626 	int flags, cred_t *cr, caller_context_t *ct)
8627 {
8628 	return (ENOSYS);
8629 }
8630 
8631 static int
8632 cachefs_setsecattr_connected(cnode_t *cp,
8633     vsecattr_t *vsec, int flag, cred_t *cr)
8634 {
8635 	fscache_t *fscp = C_TO_FSCACHE(cp);
8636 	int error = 0;
8637 
8638 	ASSERT(RW_WRITE_HELD(&cp->c_rwlock));
8639 	ASSERT((fscp->fs_info.fi_mntflags & CFS_NOACL) == 0);
8640 
8641 	mutex_enter(&cp->c_statelock);
8642 
8643 	if (cp->c_backvp == NULL) {
8644 		error = cachefs_getbackvp(fscp, cp);
8645 		if (error) {
8646 			cachefs_nocache(cp);
8647 			goto out;
8648 		}
8649 	}
8650 
8651 	error = CFSOP_CHECK_COBJECT(fscp, cp, 0, cr);
8652 	if (error)
8653 		goto out;
8654 
8655 	/* only owner can set acl */
8656 	if (cp->c_metadata.md_vattr.va_uid != crgetuid(cr)) {
8657 		error = EINVAL;
8658 		goto out;
8659 	}
8660 
8661 
8662 	CFS_DPRINT_BACKFS_NFSV4(fscp,
8663 	    ("cachefs_setsecattr (nfsv4): cp %p, backvp %p",
8664 	    cp, cp->c_backvp));
8665 	error = VOP_SETSECATTR(cp->c_backvp, vsec, flag, cr, NULL);
8666 	if (error) {
8667 		goto out;
8668 	}
8669 
8670 	if ((cp->c_filegrp->fg_flags & CFS_FG_WRITE) == 0 &&
8671 	    !CFS_ISFS_BACKFS_NFSV4(fscp)) {
8672 		cachefs_nocache(cp);
8673 		goto out;
8674 	}
8675 
8676 	CFSOP_MODIFY_COBJECT(fscp, cp, cr);
8677 
8678 	/* acl may have changed permissions -- handle this. */
8679 	if (!CFS_ISFS_BACKFS_NFSV4(fscp))
8680 		cachefs_acl2perm(cp, vsec);
8681 
8682 	if ((cp->c_flags & CN_NOCACHE) == 0 &&
8683 	    !CFS_ISFS_BACKFS_NFSV4(fscp)) {
8684 		error = cachefs_cacheacl(cp, vsec);
8685 		if (error != 0) {
8686 #ifdef CFSDEBUG
8687 			CFS_DEBUG(CFSDEBUG_VOPS)
8688 				printf("cachefs_setacl: cacheacl: error %d\n",
8689 				    error);
8690 #endif /* CFSDEBUG */
8691 			error = 0;
8692 			cachefs_nocache(cp);
8693 		}
8694 	}
8695 
8696 out:
8697 	mutex_exit(&cp->c_statelock);
8698 
8699 	return (error);
8700 }
8701 
8702 static int
8703 cachefs_setsecattr_disconnected(cnode_t *cp,
8704     vsecattr_t *vsec, int flag, cred_t *cr)
8705 {
8706 	fscache_t *fscp = C_TO_FSCACHE(cp);
8707 	mode_t failmode = cp->c_metadata.md_vattr.va_mode;
8708 	off_t commit = 0;
8709 	int error = 0;
8710 
8711 	ASSERT((fscp->fs_info.fi_mntflags & CFS_NOACL) == 0);
8712 
8713 	if (CFS_ISFS_WRITE_AROUND(fscp))
8714 		return (ETIMEDOUT);
8715 
8716 	mutex_enter(&cp->c_statelock);
8717 
8718 	/* only owner can set acl */
8719 	if (cp->c_metadata.md_vattr.va_uid != crgetuid(cr)) {
8720 		error = EINVAL;
8721 		goto out;
8722 	}
8723 
8724 	if (cp->c_metadata.md_flags & MD_NEEDATTRS) {
8725 		error = ETIMEDOUT;
8726 		goto out;
8727 	}
8728 
8729 	/* XXX do i need this?  is this right? */
8730 	if (cp->c_flags & CN_ALLOC_PENDING) {
8731 		if (cp->c_filegrp->fg_flags & CFS_FG_ALLOC_ATTR) {
8732 			(void) filegrp_allocattr(cp->c_filegrp);
8733 		}
8734 		error = filegrp_create_metadata(cp->c_filegrp,
8735 		    &cp->c_metadata, &cp->c_id);
8736 		if (error) {
8737 			goto out;
8738 		}
8739 		cp->c_flags &= ~CN_ALLOC_PENDING;
8740 	}
8741 
8742 	/* XXX is this right? */
8743 	if ((cp->c_metadata.md_flags & MD_MAPPING) == 0) {
8744 		error = cachefs_dlog_cidmap(fscp);
8745 		if (error) {
8746 			error = ENOSPC;
8747 			goto out;
8748 		}
8749 		cp->c_metadata.md_flags |= MD_MAPPING;
8750 		cp->c_flags |= CN_UPDATED;
8751 	}
8752 
8753 	commit = cachefs_dlog_setsecattr(fscp, vsec, flag, cp, cr);
8754 	if (commit == 0)
8755 		goto out;
8756 
8757 	/* fix modes in metadata */
8758 	cachefs_acl2perm(cp, vsec);
8759 
8760 	if ((cp->c_flags & CN_NOCACHE) == 0) {
8761 		error = cachefs_cacheacl(cp, vsec);
8762 		if (error != 0) {
8763 			goto out;
8764 		}
8765 	}
8766 
8767 	/* XXX is this right? */
8768 	if (cachefs_modified_alloc(cp)) {
8769 		error = ENOSPC;
8770 		goto out;
8771 	}
8772 
8773 out:
8774 	if (error != 0)
8775 		cp->c_metadata.md_vattr.va_mode = failmode;
8776 
8777 	mutex_exit(&cp->c_statelock);
8778 
8779 	if (commit) {
8780 		if (cachefs_dlog_commit(fscp, commit, error)) {
8781 			/*EMPTY*/
8782 			/* XXX fix on panic? */
8783 		}
8784 	}
8785 
8786 	return (error);
8787 }
8788 
8789 /*ARGSUSED*/
8790 static int
8791 cachefs_setsecattr(vnode_t *vp, vsecattr_t *vsec, int flag, cred_t *cr,
8792     caller_context_t *ct)
8793 {
8794 	cnode_t *cp = VTOC(vp);
8795 	fscache_t *fscp = C_TO_FSCACHE(cp);
8796 	int connected = 0;
8797 	int held = 0;
8798 	int error = 0;
8799 
8800 #ifdef CFSDEBUG
8801 	CFS_DEBUG(CFSDEBUG_VOPS)
8802 		printf("cachefs_setsecattr: ENTER vp %p\n", (void *)vp);
8803 #endif
8804 	if (getzoneid() != GLOBAL_ZONEID) {
8805 		error = EPERM;
8806 		goto out;
8807 	}
8808 
8809 	if (fscp->fs_info.fi_mntflags & CFS_NOACL) {
8810 		error = ENOSYS;
8811 		goto out;
8812 	}
8813 
8814 	if (! cachefs_vtype_aclok(vp)) {
8815 		error = EINVAL;
8816 		goto out;
8817 	}
8818 
8819 	/*
8820 	 * Cachefs only provides pass-through support for NFSv4,
8821 	 * and all vnode operations are passed through to the
8822 	 * back file system. For NFSv4 pass-through to work, only
8823 	 * connected operation is supported, the cnode backvp must
8824 	 * exist, and cachefs optional (eg., disconnectable) flags
8825 	 * are turned off. Assert these conditions to ensure that
8826 	 * the backfilesystem is called for the setsecattr operation.
8827 	 */
8828 	CFS_BACKFS_NFSV4_ASSERT_FSCACHE(fscp);
8829 	CFS_BACKFS_NFSV4_ASSERT_CNODE(cp);
8830 
8831 	for (;;) {
8832 		/* drop hold on file system */
8833 		if (held) {
8834 			/* Won't loop with NFSv4 connected operation */
8835 			ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
8836 			cachefs_cd_release(fscp);
8837 			held = 0;
8838 		}
8839 
8840 		/* acquire access to the file system */
8841 		error = cachefs_cd_access(fscp, connected, 1);
8842 		if (error)
8843 			break;
8844 		held = 1;
8845 
8846 		/* perform the setattr */
8847 		if (fscp->fs_cdconnected == CFS_CD_CONNECTED)
8848 			error = cachefs_setsecattr_connected(cp,
8849 			    vsec, flag, cr);
8850 		else
8851 			error = cachefs_setsecattr_disconnected(cp,
8852 			    vsec, flag, cr);
8853 		if (error) {
8854 			/* if connected */
8855 			if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
8856 				if (CFS_TIMEOUT(fscp, error)) {
8857 					cachefs_cd_release(fscp);
8858 					held = 0;
8859 					cachefs_cd_timedout(fscp);
8860 					connected = 0;
8861 					continue;
8862 				}
8863 			}
8864 
8865 			/* else must be disconnected */
8866 			else {
8867 				if (CFS_TIMEOUT(fscp, error)) {
8868 					connected = 1;
8869 					continue;
8870 				}
8871 			}
8872 		}
8873 		break;
8874 	}
8875 
8876 	if (held) {
8877 		cachefs_cd_release(fscp);
8878 	}
8879 	return (error);
8880 
8881 out:
8882 #ifdef CFS_CD_DEBUG
8883 	ASSERT((curthread->t_flag & T_CD_HELD) == 0);
8884 #endif
8885 
8886 #ifdef CFSDEBUG
8887 	CFS_DEBUG(CFSDEBUG_VOPS)
8888 		printf("cachefs_setsecattr: EXIT error = %d\n", error);
8889 #endif
8890 	return (error);
8891 }
8892 
8893 /*
8894  * call this BEFORE calling cachefs_cacheacl(), as the latter will
8895  * sanitize the acl.
8896  */
8897 
8898 static void
8899 cachefs_acl2perm(cnode_t *cp, vsecattr_t *vsec)
8900 {
8901 	aclent_t *aclp;
8902 	int i;
8903 
8904 	for (i = 0; i < vsec->vsa_aclcnt; i++) {
8905 		aclp = ((aclent_t *)vsec->vsa_aclentp) + i;
8906 		switch (aclp->a_type) {
8907 		case USER_OBJ:
8908 			cp->c_metadata.md_vattr.va_mode &= (~0700);
8909 			cp->c_metadata.md_vattr.va_mode |= (aclp->a_perm << 6);
8910 			break;
8911 
8912 		case GROUP_OBJ:
8913 			cp->c_metadata.md_vattr.va_mode &= (~070);
8914 			cp->c_metadata.md_vattr.va_mode |= (aclp->a_perm << 3);
8915 			break;
8916 
8917 		case OTHER_OBJ:
8918 			cp->c_metadata.md_vattr.va_mode &= (~07);
8919 			cp->c_metadata.md_vattr.va_mode |= (aclp->a_perm);
8920 			break;
8921 
8922 		case CLASS_OBJ:
8923 			cp->c_metadata.md_aclclass = aclp->a_perm;
8924 			break;
8925 		}
8926 	}
8927 
8928 	cp->c_flags |= CN_UPDATED;
8929 }
8930 
8931 static int
8932 cachefs_getsecattr(vnode_t *vp, vsecattr_t *vsec, int flag, cred_t *cr,
8933     caller_context_t *ct)
8934 {
8935 	cnode_t *cp = VTOC(vp);
8936 	fscache_t *fscp = C_TO_FSCACHE(cp);
8937 	int held = 0, connected = 0;
8938 	int error = 0;
8939 
8940 #ifdef CFSDEBUG
8941 	CFS_DEBUG(CFSDEBUG_VOPS)
8942 		printf("cachefs_getsecattr: ENTER vp %p\n", (void *)vp);
8943 #endif
8944 
8945 	if (getzoneid() != GLOBAL_ZONEID) {
8946 		error = EPERM;
8947 		goto out;
8948 	}
8949 
8950 	/*
8951 	 * Cachefs only provides pass-through support for NFSv4,
8952 	 * and all vnode operations are passed through to the
8953 	 * back file system. For NFSv4 pass-through to work, only
8954 	 * connected operation is supported, the cnode backvp must
8955 	 * exist, and cachefs optional (eg., disconnectable) flags
8956 	 * are turned off. Assert these conditions to ensure that
8957 	 * the backfilesystem is called for the getsecattr operation.
8958 	 */
8959 	CFS_BACKFS_NFSV4_ASSERT_FSCACHE(fscp);
8960 	CFS_BACKFS_NFSV4_ASSERT_CNODE(cp);
8961 
8962 	if (fscp->fs_info.fi_mntflags & CFS_NOACL) {
8963 		error = fs_fab_acl(vp, vsec, flag, cr, ct);
8964 		goto out;
8965 	}
8966 
8967 	for (;;) {
8968 		if (held) {
8969 			/* Won't loop with NFSv4 connected behavior */
8970 			ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
8971 			cachefs_cd_release(fscp);
8972 			held = 0;
8973 		}
8974 		error = cachefs_cd_access(fscp, connected, 0);
8975 		if (error)
8976 			break;
8977 		held = 1;
8978 
8979 		if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
8980 			error = cachefs_getsecattr_connected(vp, vsec, flag,
8981 			    cr);
8982 			if (CFS_TIMEOUT(fscp, error)) {
8983 				cachefs_cd_release(fscp);
8984 				held = 0;
8985 				cachefs_cd_timedout(fscp);
8986 				connected = 0;
8987 				continue;
8988 			}
8989 		} else {
8990 			error = cachefs_getsecattr_disconnected(vp, vsec, flag,
8991 			    cr);
8992 			if (CFS_TIMEOUT(fscp, error)) {
8993 				if (cachefs_cd_access_miss(fscp)) {
8994 					error = cachefs_getsecattr_connected(vp,
8995 					    vsec, flag, cr);
8996 					if (!CFS_TIMEOUT(fscp, error))
8997 						break;
8998 					delay(5*hz);
8999 					connected = 0;
9000 					continue;
9001 				}
9002 				connected = 1;
9003 				continue;
9004 			}
9005 		}
9006 		break;
9007 	}
9008 
9009 out:
9010 	if (held)
9011 		cachefs_cd_release(fscp);
9012 
9013 #ifdef CFS_CD_DEBUG
9014 	ASSERT((curthread->t_flag & T_CD_HELD) == 0);
9015 #endif
9016 #ifdef CFSDEBUG
9017 	CFS_DEBUG(CFSDEBUG_VOPS)
9018 		printf("cachefs_getsecattr: EXIT error = %d\n", error);
9019 #endif
9020 	return (error);
9021 }
9022 
9023 static int
9024 cachefs_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr,
9025     caller_context_t *ct)
9026 {
9027 	cnode_t *cp = VTOC(vp);
9028 	fscache_t *fscp = C_TO_FSCACHE(cp);
9029 	int error = 0;
9030 	vnode_t *backvp;
9031 
9032 #ifdef CFSDEBUG
9033 	CFS_DEBUG(CFSDEBUG_VOPS)
9034 		printf("cachefs_shrlock: ENTER vp %p\n", (void *)vp);
9035 #endif
9036 
9037 	if (getzoneid() != GLOBAL_ZONEID) {
9038 		error = EPERM;
9039 		goto out;
9040 	}
9041 
9042 	/*
9043 	 * Cachefs only provides pass-through support for NFSv4,
9044 	 * and all vnode operations are passed through to the
9045 	 * back file system. For NFSv4 pass-through to work, only
9046 	 * connected operation is supported, the cnode backvp must
9047 	 * exist, and cachefs optional (eg., disconnectable) flags
9048 	 * are turned off. Assert these conditions to ensure that
9049 	 * the backfilesystem is called for the shrlock operation.
9050 	 */
9051 	CFS_BACKFS_NFSV4_ASSERT_FSCACHE(fscp);
9052 	CFS_BACKFS_NFSV4_ASSERT_CNODE(cp);
9053 
9054 	mutex_enter(&cp->c_statelock);
9055 	if (cp->c_backvp == NULL)
9056 		error = cachefs_getbackvp(fscp, cp);
9057 	backvp = cp->c_backvp;
9058 	mutex_exit(&cp->c_statelock);
9059 	ASSERT((error != 0) || (backvp != NULL));
9060 
9061 	if (error == 0) {
9062 		CFS_DPRINT_BACKFS_NFSV4(fscp,
9063 		    ("cachefs_shrlock (nfsv4): cp %p, backvp %p",
9064 		    cp, backvp));
9065 		error = VOP_SHRLOCK(backvp, cmd, shr, flag, cr, ct);
9066 	}
9067 
9068 out:
9069 #ifdef CFSDEBUG
9070 	CFS_DEBUG(CFSDEBUG_VOPS)
9071 		printf("cachefs_shrlock: EXIT error = %d\n", error);
9072 #endif
9073 	return (error);
9074 }
9075 
9076 static int
9077 cachefs_getsecattr_connected(vnode_t *vp, vsecattr_t *vsec, int flag,
9078     cred_t *cr)
9079 {
9080 	cnode_t *cp = VTOC(vp);
9081 	fscache_t *fscp = C_TO_FSCACHE(cp);
9082 	int hit = 0;
9083 	int error = 0;
9084 
9085 
9086 	mutex_enter(&cp->c_statelock);
9087 	error = CFSOP_CHECK_COBJECT(fscp, cp, 0, cr);
9088 	if (error)
9089 		goto out;
9090 
9091 	/* read from the cache if we can */
9092 	if ((cp->c_metadata.md_flags & MD_ACL) &&
9093 	    ((cp->c_flags & CN_NOCACHE) == 0) &&
9094 	    !CFS_ISFS_BACKFS_NFSV4(fscp)) {
9095 		ASSERT((cp->c_flags & CN_NOCACHE) == 0);
9096 		error = cachefs_getaclfromcache(cp, vsec);
9097 		if (error) {
9098 			cachefs_nocache(cp);
9099 			ASSERT((cp->c_metadata.md_flags & MD_ACL) == 0);
9100 			error = 0;
9101 		} else {
9102 			hit = 1;
9103 			goto out;
9104 		}
9105 	}
9106 
9107 	ASSERT(error == 0);
9108 	if (cp->c_backvp == NULL)
9109 		error = cachefs_getbackvp(fscp, cp);
9110 	if (error)
9111 		goto out;
9112 
9113 	CFS_DPRINT_BACKFS_NFSV4(fscp,
9114 	    ("cachefs_getsecattr (nfsv4): cp %p, backvp %p",
9115 	    cp, cp->c_backvp));
9116 	error = VOP_GETSECATTR(cp->c_backvp, vsec, flag, cr, NULL);
9117 	if (error)
9118 		goto out;
9119 
9120 	if (((fscp->fs_info.fi_mntflags & CFS_NOACL) == 0) &&
9121 	    (cachefs_vtype_aclok(vp)) &&
9122 	    ((cp->c_flags & CN_NOCACHE) == 0) &&
9123 	    !CFS_ISFS_BACKFS_NFSV4(fscp)) {
9124 		error = cachefs_cacheacl(cp, vsec);
9125 		if (error) {
9126 			error = 0;
9127 			cachefs_nocache(cp);
9128 		}
9129 	}
9130 
9131 out:
9132 	if (error == 0) {
9133 		if (hit)
9134 			fscp->fs_stats.st_hits++;
9135 		else
9136 			fscp->fs_stats.st_misses++;
9137 	}
9138 	mutex_exit(&cp->c_statelock);
9139 
9140 	return (error);
9141 }
9142 
9143 static int
9144 /*ARGSUSED*/
9145 cachefs_getsecattr_disconnected(vnode_t *vp, vsecattr_t *vsec, int flag,
9146     cred_t *cr)
9147 {
9148 	cnode_t *cp = VTOC(vp);
9149 	fscache_t *fscp = C_TO_FSCACHE(cp);
9150 	int hit = 0;
9151 	int error = 0;
9152 
9153 
9154 	mutex_enter(&cp->c_statelock);
9155 
9156 	/* read from the cache if we can */
9157 	if (((cp->c_flags & CN_NOCACHE) == 0) &&
9158 	    (cp->c_metadata.md_flags & MD_ACL)) {
9159 		error = cachefs_getaclfromcache(cp, vsec);
9160 		if (error) {
9161 			cachefs_nocache(cp);
9162 			ASSERT((cp->c_metadata.md_flags & MD_ACL) == 0);
9163 			error = 0;
9164 		} else {
9165 			hit = 1;
9166 			goto out;
9167 		}
9168 	}
9169 	error = ETIMEDOUT;
9170 
9171 out:
9172 	if (error == 0) {
9173 		if (hit)
9174 			fscp->fs_stats.st_hits++;
9175 		else
9176 			fscp->fs_stats.st_misses++;
9177 	}
9178 	mutex_exit(&cp->c_statelock);
9179 
9180 	return (error);
9181 }
9182 
9183 /*
9184  * cachefs_cacheacl() -- cache an ACL, which we do by applying it to
9185  * the frontfile if possible; otherwise, the adjunct directory.
9186  *
9187  * inputs:
9188  * cp - the cnode, with its statelock already held
9189  * vsecp - a pointer to a vsecattr_t you'd like us to cache as-is,
9190  *  or NULL if you want us to do the VOP_GETSECATTR(backvp).
9191  *
9192  * returns:
9193  * 0 - all is well
9194  * nonzero - errno
9195  */
9196 
9197 int
9198 cachefs_cacheacl(cnode_t *cp, vsecattr_t *vsecp)
9199 {
9200 	fscache_t *fscp = C_TO_FSCACHE(cp);
9201 	vsecattr_t vsec;
9202 	aclent_t *aclp;
9203 	int gotvsec = 0;
9204 	int error = 0;
9205 	vnode_t *vp = NULL;
9206 	void *aclkeep = NULL;
9207 	int i;
9208 
9209 	ASSERT(MUTEX_HELD(&cp->c_statelock));
9210 	ASSERT((cp->c_flags & CN_NOCACHE) == 0);
9211 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
9212 	ASSERT((fscp->fs_info.fi_mntflags & CFS_NOACL) == 0);
9213 	ASSERT(cachefs_vtype_aclok(CTOV(cp)));
9214 
9215 	if (fscp->fs_info.fi_mntflags & CFS_NOACL) {
9216 		error = ENOSYS;
9217 		goto out;
9218 	}
9219 
9220 	if (vsecp == NULL) {
9221 		if (cp->c_backvp == NULL)
9222 			error = cachefs_getbackvp(fscp, cp);
9223 		if (error != 0)
9224 			goto out;
9225 		vsecp = &vsec;
9226 		bzero(&vsec, sizeof (vsec));
9227 		vsecp->vsa_mask =
9228 		    VSA_ACL | VSA_ACLCNT | VSA_DFACL | VSA_DFACLCNT;
9229 		error = VOP_GETSECATTR(cp->c_backvp, vsecp, 0, kcred, NULL);
9230 		if (error != 0) {
9231 			goto out;
9232 		}
9233 		gotvsec = 1;
9234 	} else if (vsecp->vsa_mask & VSA_ACL) {
9235 		aclkeep = vsecp->vsa_aclentp;
9236 		vsecp->vsa_aclentp = cachefs_kmem_alloc(vsecp->vsa_aclcnt *
9237 		    sizeof (aclent_t), KM_SLEEP);
9238 		bcopy(aclkeep, vsecp->vsa_aclentp, vsecp->vsa_aclcnt *
9239 		    sizeof (aclent_t));
9240 	} else if ((vsecp->vsa_mask & (VSA_ACL | VSA_DFACL)) == 0) {
9241 		/* unless there's real data, we can cache nothing. */
9242 		return (0);
9243 	}
9244 
9245 	/*
9246 	 * prevent the ACL from chmoding our frontfile, and
9247 	 * snarf the class info
9248 	 */
9249 
9250 	if ((vsecp->vsa_mask & (VSA_ACL | VSA_ACLCNT)) ==
9251 	    (VSA_ACL | VSA_ACLCNT)) {
9252 		for (i = 0; i < vsecp->vsa_aclcnt; i++) {
9253 			aclp = ((aclent_t *)vsecp->vsa_aclentp) + i;
9254 			switch (aclp->a_type) {
9255 			case CLASS_OBJ:
9256 				cp->c_metadata.md_aclclass =
9257 				    aclp->a_perm;
9258 				/*FALLTHROUGH*/
9259 			case USER_OBJ:
9260 			case GROUP_OBJ:
9261 			case OTHER_OBJ:
9262 				aclp->a_perm = 06;
9263 			}
9264 		}
9265 	}
9266 
9267 	/*
9268 	 * if the frontfile exists, then we always do the work.  but,
9269 	 * if there's no frontfile, and the ACL isn't a `real' ACL,
9270 	 * then we don't want to do the work.  otherwise, an `ls -l'
9271 	 * will create tons of emtpy frontfiles.
9272 	 */
9273 
9274 	if (((cp->c_metadata.md_flags & MD_FILE) == 0) &&
9275 	    ((vsecp->vsa_aclcnt + vsecp->vsa_dfaclcnt)
9276 	    <= MIN_ACL_ENTRIES)) {
9277 		cp->c_metadata.md_flags |= MD_ACL;
9278 		cp->c_flags |= CN_UPDATED;
9279 		goto out;
9280 	}
9281 
9282 	/*
9283 	 * if we have a default ACL, then we need a
9284 	 * real live directory in the frontfs that we
9285 	 * can apply the ACL to.  if not, then we just
9286 	 * use the frontfile.  we get the frontfile
9287 	 * regardless -- that way, we know the
9288 	 * directory for the frontfile exists.
9289 	 */
9290 
9291 	if (vsecp->vsa_dfaclcnt > 0) {
9292 		if (cp->c_acldirvp == NULL)
9293 			error = cachefs_getacldirvp(cp);
9294 		if (error != 0)
9295 			goto out;
9296 		vp = cp->c_acldirvp;
9297 	} else {
9298 		if (cp->c_frontvp == NULL)
9299 			error = cachefs_getfrontfile(cp);
9300 		if (error != 0)
9301 			goto out;
9302 		vp = cp->c_frontvp;
9303 	}
9304 	ASSERT(vp != NULL);
9305 
9306 	(void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
9307 	error = VOP_SETSECATTR(vp, vsecp, 0, kcred, NULL);
9308 	VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
9309 	if (error != 0) {
9310 #ifdef CFSDEBUG
9311 		CFS_DEBUG(CFSDEBUG_VOPS)
9312 			printf("cachefs_cacheacl: setsecattr: error %d\n",
9313 			    error);
9314 #endif /* CFSDEBUG */
9315 		/*
9316 		 * If there was an error, we don't want to call
9317 		 * cachefs_nocache(); so, set error to 0.
9318 		 * We will call cachefs_purgeacl(), in order to
9319 		 * clean such things as adjunct ACL directories.
9320 		 */
9321 		cachefs_purgeacl(cp);
9322 		error = 0;
9323 		goto out;
9324 	}
9325 	if (vp == cp->c_frontvp)
9326 		cp->c_flags |= CN_NEED_FRONT_SYNC;
9327 
9328 	cp->c_metadata.md_flags |= MD_ACL;
9329 	cp->c_flags |= CN_UPDATED;
9330 
9331 out:
9332 	if ((error) && (fscp->fs_cdconnected == CFS_CD_CONNECTED))
9333 		cachefs_nocache(cp);
9334 
9335 	if (gotvsec) {
9336 		if (vsec.vsa_aclcnt)
9337 			kmem_free(vsec.vsa_aclentp,
9338 			    vsec.vsa_aclcnt * sizeof (aclent_t));
9339 		if (vsec.vsa_dfaclcnt)
9340 			kmem_free(vsec.vsa_dfaclentp,
9341 			    vsec.vsa_dfaclcnt * sizeof (aclent_t));
9342 	} else if (aclkeep != NULL) {
9343 		cachefs_kmem_free(vsecp->vsa_aclentp,
9344 		    vsecp->vsa_aclcnt * sizeof (aclent_t));
9345 		vsecp->vsa_aclentp = aclkeep;
9346 	}
9347 
9348 	return (error);
9349 }
9350 
9351 void
9352 cachefs_purgeacl(cnode_t *cp)
9353 {
9354 	ASSERT(MUTEX_HELD(&cp->c_statelock));
9355 
9356 	ASSERT(!CFS_ISFS_BACKFS_NFSV4(C_TO_FSCACHE(cp)));
9357 
9358 	if (cp->c_acldirvp != NULL) {
9359 		VN_RELE(cp->c_acldirvp);
9360 		cp->c_acldirvp = NULL;
9361 	}
9362 
9363 	if (cp->c_metadata.md_flags & MD_ACLDIR) {
9364 		char name[CFS_FRONTFILE_NAME_SIZE + 2];
9365 
9366 		ASSERT(cp->c_filegrp->fg_dirvp != NULL);
9367 		make_ascii_name(&cp->c_id, name);
9368 		(void) strcat(name, ".d");
9369 
9370 		(void) VOP_RMDIR(cp->c_filegrp->fg_dirvp, name,
9371 		    cp->c_filegrp->fg_dirvp, kcred, NULL, 0);
9372 	}
9373 
9374 	cp->c_metadata.md_flags &= ~(MD_ACL | MD_ACLDIR);
9375 	cp->c_flags |= CN_UPDATED;
9376 }
9377 
9378 static int
9379 cachefs_getacldirvp(cnode_t *cp)
9380 {
9381 	char name[CFS_FRONTFILE_NAME_SIZE + 2];
9382 	int error = 0;
9383 
9384 	ASSERT(MUTEX_HELD(&cp->c_statelock));
9385 	ASSERT(cp->c_acldirvp == NULL);
9386 
9387 	if (cp->c_frontvp == NULL)
9388 		error = cachefs_getfrontfile(cp);
9389 	if (error != 0)
9390 		goto out;
9391 
9392 	ASSERT(cp->c_filegrp->fg_dirvp != NULL);
9393 	make_ascii_name(&cp->c_id, name);
9394 	(void) strcat(name, ".d");
9395 	error = VOP_LOOKUP(cp->c_filegrp->fg_dirvp,
9396 	    name, &cp->c_acldirvp, NULL, 0, NULL, kcred, NULL, NULL, NULL);
9397 	if ((error != 0) && (error != ENOENT))
9398 		goto out;
9399 
9400 	if (error != 0) {
9401 		vattr_t va;
9402 
9403 		va.va_mode = S_IFDIR | 0777;
9404 		va.va_uid = 0;
9405 		va.va_gid = 0;
9406 		va.va_type = VDIR;
9407 		va.va_mask = AT_TYPE | AT_MODE |
9408 		    AT_UID | AT_GID;
9409 		error =
9410 		    VOP_MKDIR(cp->c_filegrp->fg_dirvp,
9411 		    name, &va, &cp->c_acldirvp, kcred, NULL, 0, NULL);
9412 		if (error != 0)
9413 			goto out;
9414 	}
9415 
9416 	ASSERT(cp->c_acldirvp != NULL);
9417 	cp->c_metadata.md_flags |= MD_ACLDIR;
9418 	cp->c_flags |= CN_UPDATED;
9419 
9420 out:
9421 	if (error != 0)
9422 		cp->c_acldirvp = NULL;
9423 	return (error);
9424 }
9425 
9426 static int
9427 cachefs_getaclfromcache(cnode_t *cp, vsecattr_t *vsec)
9428 {
9429 	aclent_t *aclp;
9430 	int error = 0;
9431 	vnode_t *vp = NULL;
9432 	int i;
9433 
9434 	ASSERT(cp->c_metadata.md_flags & MD_ACL);
9435 	ASSERT(MUTEX_HELD(&cp->c_statelock));
9436 	ASSERT(vsec->vsa_aclentp == NULL);
9437 
9438 	if (cp->c_metadata.md_flags & MD_ACLDIR) {
9439 		if (cp->c_acldirvp == NULL)
9440 			error = cachefs_getacldirvp(cp);
9441 		if (error != 0)
9442 			goto out;
9443 		vp = cp->c_acldirvp;
9444 	} else if (cp->c_metadata.md_flags & MD_FILE) {
9445 		if (cp->c_frontvp == NULL)
9446 			error = cachefs_getfrontfile(cp);
9447 		if (error != 0)
9448 			goto out;
9449 		vp = cp->c_frontvp;
9450 	} else {
9451 
9452 		/*
9453 		 * if we get here, then we know that MD_ACL is on,
9454 		 * meaning an ACL was successfully cached.  we also
9455 		 * know that neither MD_ACLDIR nor MD_FILE are on, so
9456 		 * this has to be an entry without a `real' ACL.
9457 		 * thus, we forge whatever is necessary.
9458 		 */
9459 
9460 		if (vsec->vsa_mask & VSA_ACLCNT)
9461 			vsec->vsa_aclcnt = MIN_ACL_ENTRIES;
9462 
9463 		if (vsec->vsa_mask & VSA_ACL) {
9464 			vsec->vsa_aclentp =
9465 			    kmem_zalloc(MIN_ACL_ENTRIES *
9466 			    sizeof (aclent_t), KM_SLEEP);
9467 			aclp = (aclent_t *)vsec->vsa_aclentp;
9468 			aclp->a_type = USER_OBJ;
9469 			++aclp;
9470 			aclp->a_type = GROUP_OBJ;
9471 			++aclp;
9472 			aclp->a_type = OTHER_OBJ;
9473 			++aclp;
9474 			aclp->a_type = CLASS_OBJ;
9475 			ksort((caddr_t)vsec->vsa_aclentp, MIN_ACL_ENTRIES,
9476 			    sizeof (aclent_t), cmp2acls);
9477 		}
9478 
9479 		ASSERT(vp == NULL);
9480 	}
9481 
9482 	if (vp != NULL) {
9483 		if ((error = VOP_GETSECATTR(vp, vsec, 0, kcred, NULL)) != 0) {
9484 #ifdef CFSDEBUG
9485 			CFS_DEBUG(CFSDEBUG_VOPS)
9486 				printf("cachefs_getaclfromcache: error %d\n",
9487 				    error);
9488 #endif /* CFSDEBUG */
9489 			goto out;
9490 		}
9491 	}
9492 
9493 	if (vsec->vsa_aclentp != NULL) {
9494 		for (i = 0; i < vsec->vsa_aclcnt; i++) {
9495 			aclp = ((aclent_t *)vsec->vsa_aclentp) + i;
9496 			switch (aclp->a_type) {
9497 			case USER_OBJ:
9498 				aclp->a_id = cp->c_metadata.md_vattr.va_uid;
9499 				aclp->a_perm =
9500 				    cp->c_metadata.md_vattr.va_mode & 0700;
9501 				aclp->a_perm >>= 6;
9502 				break;
9503 
9504 			case GROUP_OBJ:
9505 				aclp->a_id = cp->c_metadata.md_vattr.va_gid;
9506 				aclp->a_perm =
9507 				    cp->c_metadata.md_vattr.va_mode & 070;
9508 				aclp->a_perm >>= 3;
9509 				break;
9510 
9511 			case OTHER_OBJ:
9512 				aclp->a_perm =
9513 				    cp->c_metadata.md_vattr.va_mode & 07;
9514 				break;
9515 
9516 			case CLASS_OBJ:
9517 				aclp->a_perm =
9518 				    cp->c_metadata.md_aclclass;
9519 				break;
9520 			}
9521 		}
9522 	}
9523 
9524 out:
9525 
9526 	if (error != 0)
9527 		cachefs_nocache(cp);
9528 
9529 	return (error);
9530 }
9531 
9532 /*
9533  * Fills in targp with attribute information from srcp, cp
9534  * and if necessary the system.
9535  */
9536 static void
9537 cachefs_attr_setup(vattr_t *srcp, vattr_t *targp, cnode_t *cp, cred_t *cr)
9538 {
9539 	time_t	now;
9540 
9541 	ASSERT((srcp->va_mask & (AT_TYPE | AT_MODE)) == (AT_TYPE | AT_MODE));
9542 
9543 	/*
9544 	 * Add code to fill in the va struct.  We use the fields from
9545 	 * the srcp struct if they are populated, otherwise we guess
9546 	 */
9547 
9548 	targp->va_mask = 0;	/* initialize all fields */
9549 	targp->va_mode = srcp->va_mode;
9550 	targp->va_type = srcp->va_type;
9551 	targp->va_nlink = 1;
9552 	targp->va_nodeid = 0;
9553 
9554 	if (srcp->va_mask & AT_UID)
9555 		targp->va_uid = srcp->va_uid;
9556 	else
9557 		targp->va_uid = crgetuid(cr);
9558 
9559 	if (srcp->va_mask & AT_GID)
9560 		targp->va_gid = srcp->va_gid;
9561 	else
9562 		targp->va_gid = crgetgid(cr);
9563 
9564 	if (srcp->va_mask & AT_FSID)
9565 		targp->va_fsid = srcp->va_fsid;
9566 	else
9567 		targp->va_fsid = 0;	/* initialize all fields */
9568 
9569 	now = gethrestime_sec();
9570 	if (srcp->va_mask & AT_ATIME)
9571 		targp->va_atime = srcp->va_atime;
9572 	else
9573 		targp->va_atime.tv_sec = now;
9574 
9575 	if (srcp->va_mask & AT_MTIME)
9576 		targp->va_mtime = srcp->va_mtime;
9577 	else
9578 		targp->va_mtime.tv_sec = now;
9579 
9580 	if (srcp->va_mask & AT_CTIME)
9581 		targp->va_ctime = srcp->va_ctime;
9582 	else
9583 		targp->va_ctime.tv_sec = now;
9584 
9585 
9586 	if (srcp->va_mask & AT_SIZE)
9587 		targp->va_size = srcp->va_size;
9588 	else
9589 		targp->va_size = 0;
9590 
9591 	/*
9592 	 * the remaing fields are set by the fs and not changable.
9593 	 * we populate these entries useing the parent directory
9594 	 * values.  It's a small hack, but should work.
9595 	 */
9596 	targp->va_blksize = cp->c_metadata.md_vattr.va_blksize;
9597 	targp->va_rdev = cp->c_metadata.md_vattr.va_rdev;
9598 	targp->va_nblocks = cp->c_metadata.md_vattr.va_nblocks;
9599 	targp->va_seq = 0; /* Never keep the sequence number */
9600 }
9601 
9602 /*
9603  * set the gid for a newly created file.  The algorithm is as follows:
9604  *
9605  *	1) If the gid is set in the attribute list, then use it if
9606  *	   the caller is privileged, belongs to the target group, or
9607  *	   the group is the same as the parent directory.
9608  *
9609  *	2) If the parent directory's set-gid bit is clear, then use
9610  *	   the process gid
9611  *
9612  *	3) Otherwise, use the gid of the parent directory.
9613  *
9614  * Note: newcp->c_attr.va_{mode,type} must already be set before calling
9615  * this routine.
9616  */
9617 static void
9618 cachefs_creategid(cnode_t *dcp, cnode_t *newcp, vattr_t *vap, cred_t *cr)
9619 {
9620 	if ((vap->va_mask & AT_GID) &&
9621 	    ((vap->va_gid == dcp->c_attr.va_gid) ||
9622 	    groupmember(vap->va_gid, cr) ||
9623 	    secpolicy_vnode_create_gid(cr) != 0)) {
9624 		newcp->c_attr.va_gid = vap->va_gid;
9625 	} else {
9626 		if (dcp->c_attr.va_mode & S_ISGID)
9627 			newcp->c_attr.va_gid = dcp->c_attr.va_gid;
9628 		else
9629 			newcp->c_attr.va_gid = crgetgid(cr);
9630 	}
9631 
9632 	/*
9633 	 * if we're creating a directory, and the parent directory has the
9634 	 * set-GID bit set, set it on the new directory.
9635 	 * Otherwise, if the user is neither privileged nor a member of the
9636 	 * file's new group, clear the file's set-GID bit.
9637 	 */
9638 	if (dcp->c_attr.va_mode & S_ISGID && newcp->c_attr.va_type == VDIR) {
9639 		newcp->c_attr.va_mode |= S_ISGID;
9640 	} else if ((newcp->c_attr.va_mode & S_ISGID) &&
9641 	    secpolicy_vnode_setids_setgids(cr, newcp->c_attr.va_gid) != 0)
9642 		newcp->c_attr.va_mode &= ~S_ISGID;
9643 }
9644 
9645 /*
9646  * create an acl for the newly created file.  should be called right
9647  * after cachefs_creategid.
9648  */
9649 
9650 static void
9651 cachefs_createacl(cnode_t *dcp, cnode_t *newcp)
9652 {
9653 	fscache_t *fscp = C_TO_FSCACHE(dcp);
9654 	vsecattr_t vsec;
9655 	int gotvsec = 0;
9656 	int error = 0; /* placeholder */
9657 	aclent_t *aclp;
9658 	o_mode_t *classp = NULL;
9659 	o_mode_t gunion = 0;
9660 	int i;
9661 
9662 	if ((fscp->fs_info.fi_mntflags & CFS_NOACL) ||
9663 	    (! cachefs_vtype_aclok(CTOV(newcp))))
9664 		return;
9665 
9666 	ASSERT(dcp->c_metadata.md_flags & MD_ACL);
9667 	ASSERT(MUTEX_HELD(&dcp->c_statelock));
9668 	ASSERT(MUTEX_HELD(&newcp->c_statelock));
9669 
9670 	/*
9671 	 * XXX should probably not do VSA_ACL and VSA_ACLCNT, but that
9672 	 * would hit code paths that isn't hit anywhere else.
9673 	 */
9674 
9675 	bzero(&vsec, sizeof (vsec));
9676 	vsec.vsa_mask = VSA_ACL | VSA_ACLCNT | VSA_DFACL | VSA_DFACLCNT;
9677 	error = cachefs_getaclfromcache(dcp, &vsec);
9678 	if (error != 0)
9679 		goto out;
9680 	gotvsec = 1;
9681 
9682 	if ((vsec.vsa_dfaclcnt > 0) && (vsec.vsa_dfaclentp != NULL)) {
9683 		if ((vsec.vsa_aclcnt > 0) && (vsec.vsa_aclentp != NULL))
9684 			kmem_free(vsec.vsa_aclentp,
9685 			    vsec.vsa_aclcnt * sizeof (aclent_t));
9686 
9687 		vsec.vsa_aclcnt = vsec.vsa_dfaclcnt;
9688 		vsec.vsa_aclentp = vsec.vsa_dfaclentp;
9689 		vsec.vsa_dfaclcnt = 0;
9690 		vsec.vsa_dfaclentp = NULL;
9691 
9692 		if (newcp->c_attr.va_type == VDIR) {
9693 			vsec.vsa_dfaclentp = kmem_alloc(vsec.vsa_aclcnt *
9694 			    sizeof (aclent_t), KM_SLEEP);
9695 			vsec.vsa_dfaclcnt = vsec.vsa_aclcnt;
9696 			bcopy(vsec.vsa_aclentp, vsec.vsa_dfaclentp,
9697 			    vsec.vsa_aclcnt * sizeof (aclent_t));
9698 		}
9699 
9700 		/*
9701 		 * this function should be called pretty much after
9702 		 * the rest of the file creation stuff is done.  so,
9703 		 * uid, gid, etc. should be `right'.  we'll go with
9704 		 * that, rather than trying to determine whether to
9705 		 * get stuff from cr or va.
9706 		 */
9707 
9708 		for (i = 0; i < vsec.vsa_aclcnt; i++) {
9709 			aclp = ((aclent_t *)vsec.vsa_aclentp) + i;
9710 			switch (aclp->a_type) {
9711 			case DEF_USER_OBJ:
9712 				aclp->a_type = USER_OBJ;
9713 				aclp->a_id = newcp->c_metadata.md_vattr.va_uid;
9714 				aclp->a_perm =
9715 				    newcp->c_metadata.md_vattr.va_mode;
9716 				aclp->a_perm &= 0700;
9717 				aclp->a_perm >>= 6;
9718 				break;
9719 
9720 			case DEF_GROUP_OBJ:
9721 				aclp->a_type = GROUP_OBJ;
9722 				aclp->a_id = newcp->c_metadata.md_vattr.va_gid;
9723 				aclp->a_perm =
9724 				    newcp->c_metadata.md_vattr.va_mode;
9725 				aclp->a_perm &= 070;
9726 				aclp->a_perm >>= 3;
9727 				gunion |= aclp->a_perm;
9728 				break;
9729 
9730 			case DEF_OTHER_OBJ:
9731 				aclp->a_type = OTHER_OBJ;
9732 				aclp->a_perm =
9733 				    newcp->c_metadata.md_vattr.va_mode & 07;
9734 				break;
9735 
9736 			case DEF_CLASS_OBJ:
9737 				aclp->a_type = CLASS_OBJ;
9738 				classp = &(aclp->a_perm);
9739 				break;
9740 
9741 			case DEF_USER:
9742 				aclp->a_type = USER;
9743 				gunion |= aclp->a_perm;
9744 				break;
9745 
9746 			case DEF_GROUP:
9747 				aclp->a_type = GROUP;
9748 				gunion |= aclp->a_perm;
9749 				break;
9750 			}
9751 		}
9752 
9753 		/* XXX is this the POSIX thing to do? */
9754 		if (classp != NULL)
9755 			*classp &= gunion;
9756 
9757 		/*
9758 		 * we don't need to log this; rather, we clear the
9759 		 * MD_ACL bit when we reconnect.
9760 		 */
9761 
9762 		error = cachefs_cacheacl(newcp, &vsec);
9763 		if (error != 0)
9764 			goto out;
9765 	}
9766 
9767 	newcp->c_metadata.md_aclclass = 07; /* XXX check posix */
9768 	newcp->c_metadata.md_flags |= MD_ACL;
9769 	newcp->c_flags |= CN_UPDATED;
9770 
9771 out:
9772 
9773 	if (gotvsec) {
9774 		if ((vsec.vsa_aclcnt > 0) && (vsec.vsa_aclentp != NULL))
9775 			kmem_free(vsec.vsa_aclentp,
9776 			    vsec.vsa_aclcnt * sizeof (aclent_t));
9777 		if ((vsec.vsa_dfaclcnt > 0) && (vsec.vsa_dfaclentp != NULL))
9778 			kmem_free(vsec.vsa_dfaclentp,
9779 			    vsec.vsa_dfaclcnt * sizeof (aclent_t));
9780 	}
9781 }
9782 
9783 /*
9784  * this is translated from the UFS code for access checking.
9785  */
9786 
9787 static int
9788 cachefs_access_local(void *vcp, int mode, cred_t *cr)
9789 {
9790 	cnode_t *cp = vcp;
9791 	fscache_t *fscp = C_TO_FSCACHE(cp);
9792 	int shift = 0;
9793 
9794 	ASSERT(MUTEX_HELD(&cp->c_statelock));
9795 
9796 	if (mode & VWRITE) {
9797 		/*
9798 		 * Disallow write attempts on read-only
9799 		 * file systems, unless the file is special.
9800 		 */
9801 		struct vnode *vp = CTOV(cp);
9802 		if (vn_is_readonly(vp)) {
9803 			if (!IS_DEVVP(vp)) {
9804 				return (EROFS);
9805 			}
9806 		}
9807 	}
9808 
9809 	/*
9810 	 * if we need to do ACLs, do it.  this works whether anyone
9811 	 * has explicitly made an ACL or not.
9812 	 */
9813 
9814 	if (((fscp->fs_info.fi_mntflags & CFS_NOACL) == 0) &&
9815 	    (cachefs_vtype_aclok(CTOV(cp))))
9816 		return (cachefs_acl_access(cp, mode, cr));
9817 
9818 	if (crgetuid(cr) != cp->c_attr.va_uid) {
9819 		shift += 3;
9820 		if (!groupmember(cp->c_attr.va_gid, cr))
9821 			shift += 3;
9822 	}
9823 
9824 	/* compute missing mode bits */
9825 	mode &= ~(cp->c_attr.va_mode << shift);
9826 
9827 	if (mode == 0)
9828 		return (0);
9829 
9830 	return (secpolicy_vnode_access(cr, CTOV(cp), cp->c_attr.va_uid, mode));
9831 }
9832 
9833 /*
9834  * This is transcribed from ufs_acl_access().  If that changes, then
9835  * this should, too.
9836  *
9837  * Check the cnode's ACL's to see if this mode of access is
9838  * allowed; return 0 if allowed, EACCES if not.
9839  *
9840  * We follow the procedure defined in Sec. 3.3.5, ACL Access
9841  * Check Algorithm, of the POSIX 1003.6 Draft Standard.
9842  */
9843 
9844 #define	ACL_MODE_CHECK(M, PERM, C, I) ((((M) & (PERM)) == (M)) ? 0 : \
9845 		    secpolicy_vnode_access(C, CTOV(I), owner, (M) & ~(PERM)))
9846 
9847 static int
9848 cachefs_acl_access(struct cnode *cp, int mode, cred_t *cr)
9849 {
9850 	int error = 0;
9851 
9852 	fscache_t *fscp = C_TO_FSCACHE(cp);
9853 
9854 	int mask = ~0;
9855 	int ismask = 0;
9856 
9857 	int gperm = 0;
9858 	int ngroup = 0;
9859 
9860 	vsecattr_t vsec;
9861 	int gotvsec = 0;
9862 	aclent_t *aclp;
9863 
9864 	uid_t owner = cp->c_attr.va_uid;
9865 
9866 	int i;
9867 
9868 	ASSERT(MUTEX_HELD(&cp->c_statelock));
9869 	ASSERT((fscp->fs_info.fi_mntflags & CFS_NOACL) == 0);
9870 
9871 	/*
9872 	 * strictly speaking, we shouldn't set VSA_DFACL and DFACLCNT,
9873 	 * but then i believe we'd be the only thing exercising those
9874 	 * code paths -- probably a bad thing.
9875 	 */
9876 
9877 	bzero(&vsec, sizeof (vsec));
9878 	vsec.vsa_mask = VSA_ACL | VSA_ACLCNT | VSA_DFACL | VSA_DFACLCNT;
9879 
9880 	/* XXX KLUDGE! correct insidious 0-class problem */
9881 	if (cp->c_metadata.md_aclclass == 0 &&
9882 	    fscp->fs_cdconnected == CFS_CD_CONNECTED)
9883 		cachefs_purgeacl(cp);
9884 again:
9885 	if (cp->c_metadata.md_flags & MD_ACL) {
9886 		error = cachefs_getaclfromcache(cp, &vsec);
9887 		if (error != 0) {
9888 #ifdef CFSDEBUG
9889 			if (error != ETIMEDOUT)
9890 				CFS_DEBUG(CFSDEBUG_VOPS)
9891 					printf("cachefs_acl_access():"
9892 					    "error %d from getaclfromcache()\n",
9893 					    error);
9894 #endif /* CFSDEBUG */
9895 			if ((cp->c_metadata.md_flags & MD_ACL) == 0) {
9896 				goto again;
9897 			} else {
9898 				goto out;
9899 			}
9900 		}
9901 	} else {
9902 		if (cp->c_backvp == NULL) {
9903 			if (fscp->fs_cdconnected == CFS_CD_CONNECTED)
9904 				error = cachefs_getbackvp(fscp, cp);
9905 			else
9906 				error = ETIMEDOUT;
9907 		}
9908 		if (error == 0)
9909 			error = VOP_GETSECATTR(cp->c_backvp, &vsec, 0, cr,
9910 			    NULL);
9911 		if (error != 0) {
9912 #ifdef CFSDEBUG
9913 			CFS_DEBUG(CFSDEBUG_VOPS)
9914 				printf("cachefs_acl_access():"
9915 				    "error %d from getsecattr(backvp)\n",
9916 				    error);
9917 #endif /* CFSDEBUG */
9918 			goto out;
9919 		}
9920 		if ((cp->c_flags & CN_NOCACHE) == 0 &&
9921 		    !CFS_ISFS_BACKFS_NFSV4(fscp))
9922 			(void) cachefs_cacheacl(cp, &vsec);
9923 	}
9924 	gotvsec = 1;
9925 
9926 	ASSERT(error == 0);
9927 	for (i = 0; i < vsec.vsa_aclcnt; i++) {
9928 		aclp = ((aclent_t *)vsec.vsa_aclentp) + i;
9929 		switch (aclp->a_type) {
9930 		case USER_OBJ:
9931 			/*
9932 			 * this might look cleaner in the 2nd loop
9933 			 * below, but we do it here as an
9934 			 * optimization.
9935 			 */
9936 
9937 			owner = aclp->a_id;
9938 			if (crgetuid(cr) == owner) {
9939 				error = ACL_MODE_CHECK(mode, aclp->a_perm << 6,
9940 				    cr, cp);
9941 				goto out;
9942 			}
9943 			break;
9944 
9945 		case CLASS_OBJ:
9946 			mask = aclp->a_perm;
9947 			ismask = 1;
9948 			break;
9949 		}
9950 	}
9951 
9952 	ASSERT(error == 0);
9953 	for (i = 0; i < vsec.vsa_aclcnt; i++) {
9954 		aclp = ((aclent_t *)vsec.vsa_aclentp) + i;
9955 		switch (aclp->a_type) {
9956 		case USER:
9957 			if (crgetuid(cr) == aclp->a_id) {
9958 				error = ACL_MODE_CHECK(mode,
9959 				    (aclp->a_perm & mask) << 6, cr, cp);
9960 				goto out;
9961 			}
9962 			break;
9963 
9964 		case GROUP_OBJ:
9965 			if (groupmember(aclp->a_id, cr)) {
9966 				++ngroup;
9967 				gperm |= aclp->a_perm;
9968 				if (! ismask) {
9969 					error = ACL_MODE_CHECK(mode,
9970 					    aclp->a_perm << 6,
9971 					    cr, cp);
9972 					goto out;
9973 				}
9974 			}
9975 			break;
9976 
9977 		case GROUP:
9978 			if (groupmember(aclp->a_id, cr)) {
9979 				++ngroup;
9980 				gperm |= aclp->a_perm;
9981 			}
9982 			break;
9983 
9984 		case OTHER_OBJ:
9985 			if (ngroup == 0) {
9986 				error = ACL_MODE_CHECK(mode, aclp->a_perm << 6,
9987 				    cr, cp);
9988 				goto out;
9989 			}
9990 			break;
9991 
9992 		default:
9993 			break;
9994 		}
9995 	}
9996 
9997 	ASSERT(ngroup > 0);
9998 	error = ACL_MODE_CHECK(mode, (gperm & mask) << 6, cr, cp);
9999 
10000 out:
10001 	if (gotvsec) {
10002 		if (vsec.vsa_aclcnt && vsec.vsa_aclentp)
10003 			kmem_free(vsec.vsa_aclentp,
10004 			    vsec.vsa_aclcnt * sizeof (aclent_t));
10005 		if (vsec.vsa_dfaclcnt && vsec.vsa_dfaclentp)
10006 			kmem_free(vsec.vsa_dfaclentp,
10007 			    vsec.vsa_dfaclcnt * sizeof (aclent_t));
10008 	}
10009 
10010 	return (error);
10011 }
10012 
10013 /*
10014  * see if permissions allow for removal of the given file from
10015  * the given directory.
10016  */
10017 static int
10018 cachefs_stickyrmchk(struct cnode *dcp, struct cnode *cp, cred_t *cr)
10019 {
10020 	uid_t uid;
10021 	/*
10022 	 * If the containing directory is sticky, the user must:
10023 	 *  - own the directory, or
10024 	 *  - own the file, or
10025 	 *  - be able to write the file (if it's a plain file), or
10026 	 *  - be sufficiently privileged.
10027 	 */
10028 	if ((dcp->c_attr.va_mode & S_ISVTX) &&
10029 	    ((uid = crgetuid(cr)) != dcp->c_attr.va_uid) &&
10030 	    (uid != cp->c_attr.va_uid) &&
10031 	    (cp->c_attr.va_type != VREG ||
10032 	    cachefs_access_local(cp, VWRITE, cr) != 0))
10033 		return (secpolicy_vnode_remove(cr));
10034 
10035 	return (0);
10036 }
10037 
10038 /*
10039  * Returns a new name, may even be unique.
10040  * Stolen from nfs code.
10041  * Since now we will use renaming to .cfs* in place of .nfs*
10042  * for CacheFS. Both NFS and CacheFS will rename opened files.
10043  */
10044 static char cachefs_prefix[] = ".cfs";
10045 kmutex_t cachefs_newnum_lock;
10046 
10047 static char *
10048 cachefs_newname(void)
10049 {
10050 	static uint_t newnum = 0;
10051 	char *news;
10052 	char *s, *p;
10053 	uint_t id;
10054 
10055 	mutex_enter(&cachefs_newnum_lock);
10056 	if (newnum == 0) {
10057 		newnum = gethrestime_sec() & 0xfffff;
10058 		newnum |= 0x10000;
10059 	}
10060 	id = newnum++;
10061 	mutex_exit(&cachefs_newnum_lock);
10062 
10063 	news = cachefs_kmem_alloc(MAXNAMELEN, KM_SLEEP);
10064 	s = news;
10065 	p = cachefs_prefix;
10066 	while (*p != '\0')
10067 		*s++ = *p++;
10068 	while (id != 0) {
10069 		*s++ = "0123456789ABCDEF"[id & 0x0f];
10070 		id >>= 4;
10071 	}
10072 	*s = '\0';
10073 	return (news);
10074 }
10075 
10076 /*
10077  * Called to rename the specified file to a temporary file so
10078  * operations to the file after remove work.
10079  * Must call this routine with the dir c_rwlock held as a writer.
10080  */
10081 static int
10082 /*ARGSUSED*/
10083 cachefs_remove_dolink(vnode_t *dvp, vnode_t *vp, char *nm, cred_t *cr)
10084 {
10085 	cnode_t *cp = VTOC(vp);
10086 	char *tmpname;
10087 	fscache_t *fscp = C_TO_FSCACHE(cp);
10088 	int error;
10089 
10090 	ASSERT(RW_WRITE_HELD(&(VTOC(dvp)->c_rwlock)));
10091 
10092 	/* get the new name for the file */
10093 	tmpname = cachefs_newname();
10094 
10095 	/* do the link */
10096 	if (fscp->fs_cdconnected == CFS_CD_CONNECTED)
10097 		error = cachefs_link_connected(dvp, vp, tmpname, cr);
10098 	else
10099 		error = cachefs_link_disconnected(dvp, vp, tmpname, cr);
10100 	if (error) {
10101 		cachefs_kmem_free(tmpname, MAXNAMELEN);
10102 		return (error);
10103 	}
10104 
10105 	mutex_enter(&cp->c_statelock);
10106 	if (cp->c_unldvp) {
10107 		VN_RELE(cp->c_unldvp);
10108 		cachefs_kmem_free(cp->c_unlname, MAXNAMELEN);
10109 		crfree(cp->c_unlcred);
10110 	}
10111 
10112 	VN_HOLD(dvp);
10113 	cp->c_unldvp = dvp;
10114 	crhold(cr);
10115 	cp->c_unlcred = cr;
10116 	cp->c_unlname = tmpname;
10117 
10118 	/* drop the backvp so NFS does not also do a rename */
10119 	mutex_exit(&cp->c_statelock);
10120 
10121 	return (0);
10122 }
10123 
10124 /*
10125  * Marks the cnode as modified.
10126  */
10127 static void
10128 cachefs_modified(cnode_t *cp)
10129 {
10130 	fscache_t *fscp = C_TO_FSCACHE(cp);
10131 	struct vattr va;
10132 	int error;
10133 
10134 	ASSERT(MUTEX_HELD(&cp->c_statelock));
10135 	ASSERT(cp->c_metadata.md_rlno);
10136 
10137 	/* if not on the modify list */
10138 	if (cp->c_metadata.md_rltype != CACHEFS_RL_MODIFIED) {
10139 		/* put on modified list, also marks the file as modified */
10140 		cachefs_rlent_moveto(fscp->fs_cache, CACHEFS_RL_MODIFIED,
10141 		    cp->c_metadata.md_rlno, cp->c_metadata.md_frontblks);
10142 		cp->c_metadata.md_rltype = CACHEFS_RL_MODIFIED;
10143 		cp->c_flags |= CN_UPDATED;
10144 
10145 		/* if a modified regular file that is not local */
10146 		if (((cp->c_id.cid_flags & CFS_CID_LOCAL) == 0) &&
10147 		    (cp->c_metadata.md_flags & MD_FILE) &&
10148 		    (cp->c_attr.va_type == VREG)) {
10149 
10150 			if (cp->c_frontvp == NULL)
10151 				(void) cachefs_getfrontfile(cp);
10152 			if (cp->c_frontvp) {
10153 				/* identify file so fsck knows it is modified */
10154 				va.va_mode = 0766;
10155 				va.va_mask = AT_MODE;
10156 				error = VOP_SETATTR(cp->c_frontvp,
10157 				    &va, 0, kcred, NULL);
10158 				if (error) {
10159 					cmn_err(CE_WARN,
10160 					    "Cannot change ff mode.\n");
10161 				}
10162 			}
10163 		}
10164 	}
10165 }
10166 
10167 /*
10168  * Marks the cnode as modified.
10169  * Allocates a rl slot for the cnode if necessary.
10170  * Returns 0 for success, !0 if cannot get an rl slot.
10171  */
10172 static int
10173 cachefs_modified_alloc(cnode_t *cp)
10174 {
10175 	fscache_t *fscp = C_TO_FSCACHE(cp);
10176 	filegrp_t *fgp = cp->c_filegrp;
10177 	int error;
10178 	rl_entry_t rl_ent;
10179 
10180 	ASSERT(MUTEX_HELD(&cp->c_statelock));
10181 
10182 	/* get the rl slot if needed */
10183 	if (cp->c_metadata.md_rlno == 0) {
10184 		/* get a metadata slot if we do not have one yet */
10185 		if (cp->c_flags & CN_ALLOC_PENDING) {
10186 			if (cp->c_filegrp->fg_flags & CFS_FG_ALLOC_ATTR) {
10187 				(void) filegrp_allocattr(cp->c_filegrp);
10188 			}
10189 			error = filegrp_create_metadata(cp->c_filegrp,
10190 			    &cp->c_metadata, &cp->c_id);
10191 			if (error)
10192 				return (error);
10193 			cp->c_flags &= ~CN_ALLOC_PENDING;
10194 		}
10195 
10196 		/* get a free rl entry */
10197 		rl_ent.rl_fileno = cp->c_id.cid_fileno;
10198 		rl_ent.rl_local = (cp->c_id.cid_flags & CFS_CID_LOCAL) ? 1 : 0;
10199 		rl_ent.rl_fsid = fscp->fs_cfsid;
10200 		rl_ent.rl_attrc = 0;
10201 		error = cachefs_rl_alloc(fscp->fs_cache, &rl_ent,
10202 		    &cp->c_metadata.md_rlno);
10203 		if (error)
10204 			return (error);
10205 		cp->c_metadata.md_rltype = CACHEFS_RL_NONE;
10206 
10207 		/* hold the filegrp so the attrcache file is not gc */
10208 		error = filegrp_ffhold(fgp);
10209 		if (error) {
10210 			cachefs_rlent_moveto(fscp->fs_cache,
10211 			    CACHEFS_RL_FREE, cp->c_metadata.md_rlno, 0);
10212 			cp->c_metadata.md_rlno = 0;
10213 			return (error);
10214 		}
10215 	}
10216 	cachefs_modified(cp);
10217 	return (0);
10218 }
10219 
10220 int
10221 cachefs_vtype_aclok(vnode_t *vp)
10222 {
10223 	vtype_t *vtp, oktypes[] = {VREG, VDIR, VFIFO, VNON};
10224 
10225 	if (vp->v_type == VNON)
10226 		return (0);
10227 
10228 	for (vtp = oktypes; *vtp != VNON; vtp++)
10229 		if (vp->v_type == *vtp)
10230 			break;
10231 
10232 	return (*vtp != VNON);
10233 }
10234 
10235 static int
10236 cachefs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
10237     caller_context_t *ct)
10238 {
10239 	int error = 0;
10240 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
10241 
10242 	/* Assert cachefs compatibility if NFSv4 is in use */
10243 	CFS_BACKFS_NFSV4_ASSERT_FSCACHE(fscp);
10244 	CFS_BACKFS_NFSV4_ASSERT_CNODE(VTOC(vp));
10245 
10246 	if (cmd == _PC_FILESIZEBITS) {
10247 		u_offset_t maxsize = fscp->fs_offmax;
10248 		(*valp) = 0;
10249 		while (maxsize != 0) {
10250 			maxsize >>= 1;
10251 			(*valp)++;
10252 		}
10253 		(*valp)++;
10254 	} else
10255 		error = fs_pathconf(vp, cmd, valp, cr, ct);
10256 
10257 	return (error);
10258 }
10259