xref: /titanic_44/usr/src/uts/common/fs/cachefs/cachefs_ioctl.c (revision da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 #pragma ident	"%Z%%M%	%I%	%E% SMI"
26 
27 #include <sys/param.h>
28 #include <sys/types.h>
29 #include <sys/systm.h>
30 #include <sys/cred.h>
31 #include <sys/proc.h>
32 #include <sys/user.h>
33 #include <sys/time.h>
34 #include <sys/vnode.h>
35 #include <sys/vfs.h>
36 #include <sys/file.h>
37 #include <sys/filio.h>
38 #include <sys/uio.h>
39 #include <sys/buf.h>
40 #include <sys/mman.h>
41 #include <sys/tiuser.h>
42 #include <sys/pathname.h>
43 #include <sys/dirent.h>
44 #include <sys/conf.h>
45 #include <sys/debug.h>
46 #include <sys/vmsystm.h>
47 #include <sys/fcntl.h>
48 #include <sys/flock.h>
49 #include <sys/fbuf.h>
50 #include <sys/swap.h>
51 #include <sys/errno.h>
52 #include <sys/sysmacros.h>
53 #include <sys/disp.h>
54 #include <sys/kmem.h>
55 #include <sys/cmn_err.h>
56 #include <sys/vtrace.h>
57 #include <sys/mount.h>
58 #include <sys/dnlc.h>
59 #include <sys/stat.h>
60 #include <rpc/types.h>
61 
62 #include <vm/hat.h>
63 #include <vm/as.h>
64 #include <vm/page.h>
65 #include <vm/pvn.h>
66 #include <vm/seg.h>
67 #include <vm/seg_map.h>
68 #include <vm/seg_vn.h>
69 #include <vm/rm.h>
70 #include <sys/fs/cachefs_fs.h>
71 #include <sys/fs/cachefs_dlog.h>
72 #include <sys/fs/cachefs_ioctl.h>
73 #include <sys/fs/cachefs_dir.h>
74 #include <sys/fs/cachefs_dlog.h>
75 #include "fs/fs_subr.h"
76 
77 void cachefs_addhash(struct cnode *);
78 
79 
80 /*
81  * Local functions
82  */
83 static void sync_metadata(cnode_t *);
84 static void drop_backvp(cnode_t *);
85 static void allow_pendrm(cnode_t *cp);
86 static int cachefs_unpack_common(vnode_t *vp);
87 static int cachefs_unpackall_list(cachefscache_t *cachep,
88     enum cachefs_rl_type type);
89 static void cachefs_modified_fix(fscache_t *fscp);
90 static void cachefs_iosetneedattrs(fscache_t *fscp, cfs_cid_t *cidp);
91 
92 #if (defined(_SYSCALL32_IMPL) || defined(_LP64))
93 
94 #define	CACHEFS_DECL(type, handle)					\
95 	type	handle
96 
97 #define	CACHEFS_TMPPTR_SET(in_addr, tmp_addr, tmp_ptr, type)		\
98 	tmp_ptr = (type *)(tmp_addr)
99 
100 #define	CACHEFS_FID_COPYOUT(in_fidp, out_fidp)				\
101 	CACHEFS_FID_COPY((fid_t *)(in_fidp), (cfs_fid_t *)(out_fidp))
102 
103 #define	CACHEFS_FID_COPYIN(in_fidp, out_fidp)				\
104 	CACHEFS_FID_COPY((cfs_fid_t *)(in_fidp), (fid_t *)(out_fidp))
105 
106 #define	CACHEFS_VATTR_COPYOUT(in_vattrp, out_vattrp, error)		\
107 	if (!error) {							\
108 		CACHEFS_VATTR_TO_CFS_VATTR_COPY((vattr_t *)(in_vattrp),	\
109 			(cfs_vattr_t *)(out_vattrp), error);		\
110 	}
111 
112 #define	CACHEFS_VATTR_COPYIN(in_vattrp, out_vattrp)			\
113 	CACHEFS_CFS_VATTR_TO_VATTR_COPY((cfs_vattr_t *)(in_vattrp),	\
114 			(vattr_t *)(out_vattrp))
115 
116 #else /* not _SYSCALL32_IMPL || _LP64 */
117 
118 #define	CACHEFS_DECL(type, handle)
119 
120 #define	CACHEFS_TMPPTR_SET(in_addr, tmp_addr, tmp_ptr, type)		\
121 	tmp_ptr = (type *)(in_addr)
122 
123 #define	CACHEFS_FID_COPYOUT(in_fidp, out_fidp)
124 
125 #define	CACHEFS_FID_COPYIN(in_fidp, out_fidp)
126 
127 #define	CACHEFS_VATTR_COPYOUT(in_vattrp, out_vattrp, error)
128 
129 #define	CACHEFS_VATTR_COPYIN(in_vattrp, out_vattrp)
130 
131 #endif	/* _SYSCALL32_IMPL || _LP64 */
132 
133 /*
134  * Conjure up a credential from the partial credential stored in
135  * a file.  This is bogus and cachefs should really be fixed, but
136  * this maintains maximum compatibility.
137  * dl_cred *cr points to a basic credential followed directly by a buffer that
138  * takes a number of groups.
139  */
140 
141 static cred_t *
conj_cred(dl_cred_t * cr)142 conj_cred(dl_cred_t *cr)
143 {
144 	cred_t *newcr = crget();
145 
146 	(void) crsetresuid(newcr, cr->cr_ruid, cr->cr_uid, cr->cr_suid);
147 	(void) crsetresgid(newcr, cr->cr_rgid, cr->cr_gid, cr->cr_sgid);
148 
149 	(void) crsetgroups(newcr, MIN(NGROUPS_MAX_DEFAULT, cr->cr_ngroups),
150 		cr->cr_groups);
151 
152 	return (newcr);
153 }
154 /*
155  * Pack a file in the cache
156  *	dvp is the directory the file resides in.
157  *	name is the name of the file.
158  *	Returns 0 or an error if could not perform the operation.
159  */
160 int
cachefs_pack(struct vnode * dvp,char * name,cred_t * cr)161 cachefs_pack(struct vnode *dvp, char *name, cred_t *cr)
162 {
163 	fscache_t *fscp = C_TO_FSCACHE(VTOC(dvp));
164 	int error = 0;
165 	int connected = 0;
166 	vnode_t *vp;
167 
168 	/*
169 	 * Return if NFSv4 is the backfs (no caching).
170 	 */
171 	if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
172 		goto out;
173 	}
174 
175 	for (;;) {
176 		/* get access to the file system */
177 		error = cachefs_cd_access(fscp, connected, 0);
178 		if (error)
179 			break;
180 
181 		/* lookup the file name */
182 		error = cachefs_lookup_common(dvp, name, &vp, NULL, 0, NULL,
183 		    cr);
184 		if (error == 0) {
185 			error = cachefs_pack_common(vp, cr);
186 			VN_RELE(vp);
187 		}
188 		if (CFS_TIMEOUT(fscp, error)) {
189 			if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
190 				cachefs_cd_release(fscp);
191 				cachefs_cd_timedout(fscp);
192 				connected = 0;
193 				continue;
194 			} else {
195 				cachefs_cd_release(fscp);
196 				connected = 1;
197 				continue;
198 			}
199 		}
200 		cachefs_cd_release(fscp);
201 		break;
202 	}
203 
204 out:
205 	return (error);
206 }
207 /*
208  * Packs the file belonging to the passed in vnode.
209  */
210 int
cachefs_pack_common(vnode_t * vp,cred_t * cr)211 cachefs_pack_common(vnode_t *vp, cred_t *cr)
212 {
213 	cnode_t *cp = VTOC(vp);
214 	fscache_t *fscp = C_TO_FSCACHE(cp);
215 	int error = 0;
216 	offset_t off;
217 	caddr_t buf;
218 	int buflen;
219 	rl_entry_t rl_ent;
220 	u_offset_t cnode_size;
221 
222 	rw_enter(&cp->c_rwlock, RW_WRITER);
223 	mutex_enter(&cp->c_statelock);
224 
225 	/* done if cannot write to cache */
226 	if ((cp->c_filegrp->fg_flags & CFS_FG_WRITE) == 0) {
227 		error = EROFS;
228 		goto out;
229 	}
230 
231 	/* done if not usable */
232 	if (cp->c_flags & (CN_STALE | CN_DESTROY)) {
233 		error = ESTALE;
234 		goto out;
235 	}
236 
237 	/* make sure up to date */
238 	error = CFSOP_CHECK_COBJECT(fscp, cp, C_BACK_CHECK, cr);
239 	if (error)
240 		goto out;
241 
242 	/* make it cachable */
243 	cp->c_flags &= ~CN_NOCACHE;
244 
245 	/* get a metadata slot if we do not have one yet */
246 	if (cp->c_flags & CN_ALLOC_PENDING) {
247 		if (cp->c_filegrp->fg_flags & CFS_FG_ALLOC_ATTR) {
248 			(void) filegrp_allocattr(cp->c_filegrp);
249 		}
250 		error = filegrp_create_metadata(cp->c_filegrp,
251 		    &cp->c_metadata, &cp->c_id);
252 		if (error)
253 			goto out;
254 		cp->c_flags &= ~CN_ALLOC_PENDING;
255 		cp->c_flags |= CN_UPDATED;
256 	}
257 
258 	/* cache the ACL if necessary */
259 	if (((fscp->fs_info.fi_mntflags & CFS_NOACL) == 0) &&
260 	    (cachefs_vtype_aclok(vp)) &&
261 	    ((cp->c_metadata.md_flags & MD_ACL) == 0)) {
262 		error = cachefs_cacheacl(cp, NULL);
263 		if (error != 0)
264 			goto out;
265 	}
266 
267 	/* directory */
268 	if (vp->v_type == VDIR) {
269 		if (cp->c_metadata.md_flags & MD_POPULATED)
270 			goto out;
271 
272 		if (error = cachefs_dir_fill(cp, cr))
273 			goto out;
274 	}
275 
276 	/* regular file */
277 	else if (vp->v_type == VREG) {
278 		if (cp->c_metadata.md_flags & MD_POPULATED)
279 			goto out;
280 
281 		if (cp->c_backvp == NULL) {
282 			error = cachefs_getbackvp(fscp, cp);
283 			if (error)
284 				goto out;
285 		}
286 		if (cp->c_frontvp == NULL) {
287 			error = cachefs_getfrontfile(cp);
288 			if (error)
289 				goto out;
290 		}
291 		/* populate the file */
292 		off = (offset_t)0;
293 		cnode_size = cp->c_attr.va_size;
294 		while (off < cnode_size) {
295 			if (!cachefs_check_allocmap(cp, off)) {
296 				u_offset_t popoff;
297 				size_t popsize;
298 
299 				cachefs_cluster_allocmap(off, &popoff,
300 				    &popsize, (size_t)DEF_POP_SIZE, cp);
301 				if (popsize != 0) {
302 					error = cachefs_populate(cp, popoff,
303 					    popsize, cp->c_frontvp,
304 					    cp->c_backvp, cp->c_size, cr);
305 					if (error)
306 						goto out;
307 					else
308 						cp->c_flags |= (CN_UPDATED |
309 						    CN_NEED_FRONT_SYNC |
310 						    CN_POPULATION_PENDING);
311 					popsize = popsize - (off - popoff);
312 				}
313 			}
314 			off += PAGESIZE;
315 		}
316 	}
317 
318 	/* symbolic link */
319 	else if (vp->v_type == VLNK) {
320 		if (cp->c_metadata.md_flags & (MD_POPULATED | MD_FASTSYMLNK))
321 			goto out;
322 
323 		/* get the sym link contents from the back fs */
324 		error = cachefs_readlink_back(cp, cr, &buf, &buflen);
325 		if (error)
326 			goto out;
327 
328 		/* try to cache the sym link */
329 		error = cachefs_stuffsymlink(cp, buf, buflen);
330 		cachefs_kmem_free(buf, MAXPATHLEN);
331 	}
332 
333 	/* assume that all other types fit in the attributes */
334 
335 out:
336 	/* get the rl slot if needed */
337 	if ((error == 0) && (cp->c_metadata.md_rlno == 0)) {
338 		rl_ent.rl_fileno = cp->c_id.cid_fileno;
339 		rl_ent.rl_local = (cp->c_id.cid_flags & CFS_CID_LOCAL) ? 1 : 0;
340 		rl_ent.rl_fsid = fscp->fs_cfsid;
341 		rl_ent.rl_attrc = 0;
342 		cp->c_metadata.md_rltype = CACHEFS_RL_NONE;
343 		error = cachefs_rl_alloc(fscp->fs_cache, &rl_ent,
344 		    &cp->c_metadata.md_rlno);
345 		if (error == 0)
346 			error = filegrp_ffhold(cp->c_filegrp);
347 	}
348 
349 	/* mark the file as packed */
350 	if (error == 0) {
351 		/* modified takes precedence over packed */
352 		if (cp->c_metadata.md_rltype != CACHEFS_RL_MODIFIED) {
353 			cachefs_rlent_moveto(fscp->fs_cache,
354 			    CACHEFS_RL_PACKED, cp->c_metadata.md_rlno,
355 			    cp->c_metadata.md_frontblks);
356 			cp->c_metadata.md_rltype = CACHEFS_RL_PACKED;
357 		}
358 		cp->c_metadata.md_flags |= MD_PACKED;
359 		cp->c_flags |= CN_UPDATED;
360 	}
361 
362 	mutex_exit(&cp->c_statelock);
363 	rw_exit(&cp->c_rwlock);
364 
365 	return (error);
366 }
367 
368 /*
369  * Unpack a file from the cache
370  *	dvp is the directory the file resides in.
371  *	name is the name of the file.
372  *	Returns 0 or an error if could not perform the operation.
373  */
374 int
cachefs_unpack(struct vnode * dvp,char * name,cred_t * cr)375 cachefs_unpack(struct vnode *dvp, char *name, cred_t *cr)
376 {
377 	fscache_t *fscp = C_TO_FSCACHE(VTOC(dvp));
378 	int error = 0;
379 	int connected = 0;
380 	vnode_t *vp;
381 
382 	/* Return error if NFSv4 is the backfs (no caching) */
383 	if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
384 		goto out;
385 	}
386 
387 	for (;;) {
388 		/* get access to the file system */
389 		error = cachefs_cd_access(fscp, connected, 0);
390 		if (error)
391 			break;
392 
393 		/* lookup the file name */
394 		error = cachefs_lookup_common(dvp, name, &vp, NULL, 0, NULL,
395 		    cr);
396 		if (error == 0) {
397 			error = cachefs_unpack_common(vp);
398 			VN_RELE(vp);
399 		}
400 		if (CFS_TIMEOUT(fscp, error)) {
401 			if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
402 				cachefs_cd_release(fscp);
403 				cachefs_cd_timedout(fscp);
404 				connected = 0;
405 				continue;
406 			} else {
407 				cachefs_cd_release(fscp);
408 				connected = 1;
409 				continue;
410 			}
411 		}
412 		cachefs_cd_release(fscp);
413 		break;
414 	}
415 out:
416 	return (error);
417 }
418 
419 /*
420  * Unpacks the file belonging to the passed in vnode.
421  */
422 static int
cachefs_unpack_common(vnode_t * vp)423 cachefs_unpack_common(vnode_t *vp)
424 {
425 	cnode_t *cp = VTOC(vp);
426 	fscache_t *fscp = C_TO_FSCACHE(cp);
427 	int error = 0;
428 
429 	mutex_enter(&cp->c_statelock);
430 
431 	/* nothing to do if not packed */
432 	if ((cp->c_metadata.md_flags & MD_PACKED) == 0)
433 		goto out;
434 
435 	/* nothing to do if cannot modify cache */
436 	if ((cp->c_filegrp->fg_flags & CFS_FG_WRITE) == 0) {
437 		error = EROFS;
438 		goto out;
439 	}
440 
441 	/* mark file as no longer packed */
442 	ASSERT(cp->c_metadata.md_rlno);
443 	cp->c_metadata.md_flags &= ~MD_PACKED;
444 	cp->c_flags |= CN_UPDATED;
445 
446 	/* done if file has been modified */
447 	if (cp->c_metadata.md_rltype == CACHEFS_RL_MODIFIED)
448 		goto out;
449 
450 	/* if there is no front file */
451 	if ((cp->c_metadata.md_flags & MD_FILE) == 0) {
452 		/* nuke front file resources */
453 		filegrp_ffrele(cp->c_filegrp);
454 		cachefs_rlent_moveto(fscp->fs_cache,
455 		    CACHEFS_RL_FREE, cp->c_metadata.md_rlno, 0);
456 		cp->c_metadata.md_rlno = 0;
457 		cp->c_metadata.md_rltype = CACHEFS_RL_NONE;
458 	}
459 
460 	/* else move the front file to the active list */
461 	else {
462 		cachefs_rlent_moveto(fscp->fs_cache,
463 		    CACHEFS_RL_ACTIVE, cp->c_metadata.md_rlno,
464 		    cp->c_metadata.md_frontblks);
465 		cp->c_metadata.md_rltype = CACHEFS_RL_ACTIVE;
466 	}
467 
468 out:
469 	mutex_exit(&cp->c_statelock);
470 	return (error);
471 }
472 
473 /*
474  * Returns packing information on a file.
475  *	dvp is the directory the file resides in.
476  *	name is the name of the file.
477  *	*statusp is set to the status of the file
478  *	Returns 0 or an error if could not perform the operation.
479  */
480 int
cachefs_packinfo(struct vnode * dvp,char * name,int * statusp,cred_t * cr)481 cachefs_packinfo(struct vnode *dvp, char *name, int *statusp, cred_t *cr)
482 {
483 	fscache_t *fscp = C_TO_FSCACHE(VTOC(dvp));
484 	struct vnode *vp;
485 	struct cnode *cp;
486 	int error;
487 	int connected = 0;
488 
489 	*statusp = 0;
490 
491 	/*
492 	 * Return if NFSv4 is the backfs (no caching).
493 	 */
494 	if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
495 		goto out;
496 	}
497 
498 	for (;;) {
499 		/* get access to the file system */
500 		error = cachefs_cd_access(fscp, connected, 0);
501 		if (error)
502 			break;
503 
504 		/* lookup the file name */
505 		error = cachefs_lookup_common(dvp, name, &vp, NULL, 0, NULL,
506 		    cr);
507 		if (CFS_TIMEOUT(fscp, error)) {
508 			if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
509 				cachefs_cd_release(fscp);
510 				cachefs_cd_timedout(fscp);
511 				connected = 0;
512 				continue;
513 			} else {
514 				cachefs_cd_release(fscp);
515 				connected = 1;
516 				continue;
517 			}
518 		}
519 		if (error)
520 			break;
521 		cp = VTOC(vp);
522 
523 		mutex_enter(&cp->c_statelock);
524 		if (cp->c_metadata.md_flags & MD_PACKED)
525 			*statusp |= CACHEFS_PACKED_FILE;
526 		if (cp->c_metadata.md_flags & (MD_POPULATED | MD_FASTSYMLNK))
527 			*statusp |= CACHEFS_PACKED_DATA;
528 		else if ((vp->v_type != VREG) &&
529 		    (vp->v_type != VDIR) &&
530 		    (vp->v_type != VLNK))
531 			*statusp |= CACHEFS_PACKED_DATA;
532 		else if (cp->c_size == 0)
533 			*statusp |= CACHEFS_PACKED_DATA;
534 		if (cp->c_flags & CN_NOCACHE)
535 			*statusp |= CACHEFS_PACKED_NOCACHE;
536 		mutex_exit(&cp->c_statelock);
537 
538 		VN_RELE(vp);
539 		cachefs_cd_release(fscp);
540 		break;
541 	}
542 
543 out:
544 	return (error);
545 }
546 
547 /*
548  * Finds all packed files in the cache and unpacks them.
549  */
550 int
cachefs_unpackall(vnode_t * vp)551 cachefs_unpackall(vnode_t *vp)
552 {
553 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
554 	cachefscache_t *cachep = fscp->fs_cache;
555 	int error;
556 
557 	/*
558 	 * Return if NFSv4 is the backfs (no caching).
559 	 */
560 	if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
561 		goto out;
562 	}
563 
564 	error = cachefs_unpackall_list(cachep, CACHEFS_RL_PACKED);
565 	if (error)
566 		goto out;
567 	error = cachefs_unpackall_list(cachep, CACHEFS_RL_PACKED_PENDING);
568 out:
569 	return (error);
570 }
571 
572 /*
573  * Finds all packed files on the specified list and unpacks them.
574  */
575 static int
cachefs_unpackall_list(cachefscache_t * cachep,enum cachefs_rl_type type)576 cachefs_unpackall_list(cachefscache_t *cachep, enum cachefs_rl_type type)
577 {
578 	fscache_t *fscp = NULL;
579 	cnode_t *cp;
580 	int error = 0;
581 	rl_entry_t rl_ent;
582 	cfs_cid_t cid;
583 
584 	rl_ent.rl_current = type;
585 	for (;;) {
586 		/* get the next entry on the specified resource list */
587 		error = cachefs_rlent_data(cachep, &rl_ent, NULL);
588 		if (error) {
589 			error = 0;
590 			break;
591 		}
592 
593 		/* if the fscp we have does not match */
594 		if ((fscp == NULL) || (fscp->fs_cfsid != rl_ent.rl_fsid)) {
595 			if (fscp) {
596 				cachefs_cd_release(fscp);
597 				fscache_rele(fscp);
598 				fscp = NULL;
599 			}
600 
601 			/* get the file system cache object for this fsid */
602 			mutex_enter(&cachep->c_fslistlock);
603 			fscp = fscache_list_find(cachep, rl_ent.rl_fsid);
604 			if (fscp == NULL) {
605 				fscp = fscache_create(cachep);
606 				error = fscache_activate(fscp, rl_ent.rl_fsid,
607 				    NULL, NULL, 0);
608 				if (error) {
609 					cmn_err(CE_WARN,
610 					    "cachefs: cache error, run fsck\n");
611 					fscache_destroy(fscp);
612 					fscp = NULL;
613 					mutex_exit(&cachep->c_fslistlock);
614 					break;
615 				}
616 				fscache_list_add(cachep, fscp);
617 			}
618 			fscache_hold(fscp);
619 			mutex_exit(&cachep->c_fslistlock);
620 
621 			/* get access to the file system */
622 			error = cachefs_cd_access(fscp, 0, 0);
623 			if (error) {
624 				fscache_rele(fscp);
625 				fscp = NULL;
626 				break;
627 			}
628 		}
629 
630 		/* get the cnode for the file */
631 		cid.cid_fileno = rl_ent.rl_fileno;
632 		cid.cid_flags = rl_ent.rl_local ? CFS_CID_LOCAL : 0;
633 		error = cachefs_cnode_make(&cid, fscp,
634 		    NULL, NULL, NULL, kcred, 0, &cp);
635 		if (error) {
636 #ifdef CFSDEBUG
637 			CFS_DEBUG(CFSDEBUG_IOCTL)
638 				printf("cachefs: cul: could not find %llu\n",
639 				    (u_longlong_t)cid.cid_fileno);
640 			delay(5*hz);
641 #endif
642 			continue;
643 		}
644 
645 		/* unpack the file */
646 		(void) cachefs_unpack_common(CTOV(cp));
647 		VN_RELE(CTOV(cp));
648 	}
649 
650 	/* free up allocated resources */
651 	if (fscp) {
652 		cachefs_cd_release(fscp);
653 		fscache_rele(fscp);
654 	}
655 	return (error);
656 }
657 
658 /*
659  * Identifies this process as the cachefsd.
660  * Stays this way until close is done.
661  */
662 int
663 /*ARGSUSED*/
cachefs_io_daemonid(vnode_t * vp,void * dinp,void * doutp)664 cachefs_io_daemonid(vnode_t *vp, void *dinp, void *doutp)
665 {
666 	int error = 0;
667 
668 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
669 	cachefscache_t *cachep = fscp->fs_cache;
670 
671 	mutex_enter(&fscp->fs_cdlock);
672 
673 	/* can only do this on the root of the file system */
674 	if (vp != fscp->fs_rootvp)
675 		error = ENOENT;
676 
677 	/* else if there already is a daemon running */
678 	else if (fscp->fs_cddaemonid)
679 		error = EBUSY;
680 
681 	/* else use the pid to identify the daemon */
682 	else {
683 		fscp->fs_cddaemonid = ttoproc(curthread)->p_pid;
684 		cv_broadcast(&fscp->fs_cdwaitcv);
685 	}
686 
687 	mutex_exit(&fscp->fs_cdlock);
688 
689 	if (error == 0) {
690 		/* the daemon that takes care of root is special */
691 		if (fscp->fs_flags & CFS_FS_ROOTFS) {
692 			mutex_enter(&cachep->c_contentslock);
693 			ASSERT(cachep->c_rootdaemonid == 0);
694 			cachep->c_rootdaemonid = fscp->fs_cddaemonid;
695 			mutex_exit(&cachep->c_contentslock);
696 		}
697 	}
698 	return (error);
699 }
700 
701 /*
702  * Returns the current state in doutp
703  */
704 int
705 /*ARGSUSED*/
cachefs_io_stateget(vnode_t * vp,void * dinp,void * doutp)706 cachefs_io_stateget(vnode_t *vp, void *dinp, void *doutp)
707 {
708 	fscache_t  *fscp = C_TO_FSCACHE(VTOC(vp));
709 	int *statep = (int *)doutp;
710 	int state;
711 
712 	/*
713 	 * Only called in support of disconnectable operation, so assert
714 	 * that this is not called when NFSv4 is the backfilesytem.
715 	 */
716 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
717 
718 	mutex_enter(&fscp->fs_cdlock);
719 	switch (fscp->fs_cdconnected) {
720 	case CFS_CD_CONNECTED:
721 		state = CFS_FS_CONNECTED;
722 		break;
723 	case CFS_CD_DISCONNECTED:
724 		state = CFS_FS_DISCONNECTED;
725 		break;
726 	case CFS_CD_RECONNECTING:
727 		state = CFS_FS_RECONNECTING;
728 		break;
729 	default:
730 		ASSERT(0);
731 		break;
732 	}
733 	mutex_exit(&fscp->fs_cdlock);
734 
735 	*statep = state;
736 	return (0);
737 }
738 
739 /*
740  * Sets the state of the file system.
741  */
742 int
743 /*ARGSUSED*/
cachefs_io_stateset(vnode_t * vp,void * dinp,void * doutp)744 cachefs_io_stateset(vnode_t *vp, void *dinp, void *doutp)
745 {
746 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
747 	int error = 0;
748 	int nosig = 1;
749 	int state = *(int *)dinp;
750 
751 	/*
752 	 * State should not be changeable and always be connected if
753 	 * NFSv4 is in use.
754 	 */
755 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
756 
757 	/* wait until the file system is quiet */
758 	mutex_enter(&fscp->fs_cdlock);
759 	if (fscp->fs_cdtransition == 1) {
760 		/* if someone is already changing the state */
761 		mutex_exit(&fscp->fs_cdlock);
762 		return (0);
763 	}
764 	fscp->fs_cdtransition = 1;
765 	while (nosig && (fscp->fs_cdrefcnt != 0)) {
766 		nosig = cv_wait_sig(&fscp->fs_cdwaitcv, &fscp->fs_cdlock);
767 	}
768 	if (!nosig) {
769 		fscp->fs_cdtransition = 0;
770 		cv_broadcast(&fscp->fs_cdwaitcv);
771 		mutex_exit(&fscp->fs_cdlock);
772 		return (EINTR);
773 	}
774 	mutex_exit(&fscp->fs_cdlock);
775 
776 	switch (state) {
777 	case CFS_FS_CONNECTED:
778 		/* done if already in this state */
779 		if (fscp->fs_cdconnected == CFS_CD_CONNECTED)
780 			break;
781 
782 		mutex_enter(&fscp->fs_cdlock);
783 		fscp->fs_cdconnected = CFS_CD_CONNECTED;
784 		mutex_exit(&fscp->fs_cdlock);
785 
786 		/* fix up modified files */
787 		cachefs_modified_fix(fscp);
788 
789 #if 0
790 		if (fscp->fs_hostname != NULL)
791 			printf("\ncachefs:server          - %s",
792 			    fscp->fs_hostname);
793 		if (fscp->fs_mntpt != NULL)
794 			printf("\ncachefs:mount point     - %s",
795 			    fscp->fs_mntpt);
796 		if (fscp->fs_backfsname != NULL)
797 			printf("\ncachefs:back filesystem - %s",
798 			    fscp->fs_backfsname);
799 		printf("\nok\n");
800 #else
801 		if (fscp->fs_hostname && fscp->fs_backfsname)
802 			printf("cachefs: %s:%s ok\n",
803 			    fscp->fs_hostname, fscp->fs_backfsname);
804 		else
805 			printf("cachefs: server ok\n");
806 #endif
807 
808 		/* allow deletion of renamed open files to proceed */
809 		cachefs_cnode_traverse(fscp, allow_pendrm);
810 		break;
811 
812 	case CFS_FS_DISCONNECTED:
813 		/* done if already in this state */
814 		if (fscp->fs_cdconnected == CFS_CD_DISCONNECTED)
815 			break;
816 
817 		/* drop all back vps */
818 		cachefs_cnode_traverse(fscp, drop_backvp);
819 
820 
821 		mutex_enter(&fscp->fs_cdlock);
822 		fscp->fs_cdconnected = CFS_CD_DISCONNECTED;
823 		mutex_exit(&fscp->fs_cdlock);
824 
825 #if 0
826 		if (fscp->fs_hostname != NULL)
827 			printf("\ncachefs:server          - %s",
828 			    fscp->fs_hostname);
829 		if (fscp->fs_mntpt != NULL)
830 			printf("\ncachefs:mount point     - %s",
831 			    fscp->fs_mntpt);
832 		if (fscp->fs_backfsname != NULL)
833 			printf("\ncachefs:back filesystem - %s",
834 			    fscp->fs_backfsname);
835 		printf("\nnot responding still trying\n");
836 #else
837 		if (fscp->fs_hostname && fscp->fs_backfsname)
838 			printf("cachefs: %s:%s not responding still trying\n",
839 			    fscp->fs_hostname, fscp->fs_backfsname);
840 		else
841 			printf("cachefs: server not responding still trying\n");
842 #endif
843 		break;
844 
845 	case CFS_FS_RECONNECTING:
846 		/* done if already in this state */
847 		if (fscp->fs_cdconnected == CFS_CD_RECONNECTING)
848 			break;
849 
850 		/*
851 		 * Before we enter disconnected state we sync all metadata,
852 		 * this allows us to read metadata directly in subsequent
853 		 * calls so we don't need to allocate cnodes when
854 		 * we just need metadata information.
855 		 */
856 		/* XXX bob: need to eliminate this */
857 		cachefs_cnode_traverse(fscp, sync_metadata);
858 
859 		mutex_enter(&fscp->fs_cdlock);
860 		fscp->fs_cdconnected = CFS_CD_RECONNECTING;
861 		mutex_exit(&fscp->fs_cdlock);
862 
863 		/* no longer need dlog active */
864 		cachefs_dlog_teardown(fscp);
865 		break;
866 
867 	default:
868 		error = ENOTTY;
869 		break;
870 	}
871 
872 	mutex_enter(&fscp->fs_cdlock);
873 	fscp->fs_cdtransition = 0;
874 	cv_broadcast(&fscp->fs_cdwaitcv);
875 	mutex_exit(&fscp->fs_cdlock);
876 	return (error);
877 }
878 
879 /*
880  * Blocks until the file system switches
881  * out of the connected state.
882  */
883 int
884 /*ARGSUSED*/
cachefs_io_xwait(vnode_t * vp,void * dinp,void * doutp)885 cachefs_io_xwait(vnode_t *vp, void *dinp, void *doutp)
886 {
887 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
888 	int nosig = 1;
889 
890 	/*
891 	 * Only called in support of disconnectable operation, so assert
892 	 * that this is not used when NFSv4 is the backfilesytem.
893 	 */
894 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
895 
896 	mutex_enter(&fscp->fs_cdlock);
897 	while (nosig &&
898 	    (fscp->fs_cdconnected == CFS_CD_CONNECTED)) {
899 		nosig = cv_wait_sig(&fscp->fs_cdwaitcv, &fscp->fs_cdlock);
900 	}
901 	mutex_exit(&fscp->fs_cdlock);
902 	if (!nosig)
903 		return (EINTR);
904 
905 	return (0);
906 }
907 
908 #define	RL_HEAD(cachep, type) \
909 	(&(cachep->c_rlinfo.rl_items[CACHEFS_RL_INDEX(type)]))
910 
911 /*
912  * Returns some statistics about the cache.
913  */
914 #define	CFS_STAT_FACTOR		(MAXBSIZE / 1024)
915 int
916 /*ARGSUSED*/
cachefs_io_getstats(vnode_t * vp,void * dinp,void * doutp)917 cachefs_io_getstats(vnode_t *vp, void *dinp, void *doutp)
918 {
919 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
920 	cachefscache_t *cachep = fscp->fs_cache;
921 	struct statvfs64 sb;
922 	fsblkcnt64_t avail = 0;
923 	fsblkcnt64_t blocks;
924 	int error;
925 	cachefsio_getstats_t *gsp = (cachefsio_getstats_t *)doutp;
926 
927 	/* determine number of blocks available to the cache */
928 	error = VFS_STATVFS(cachep->c_dirvp->v_vfsp, &sb);
929 	if (error == 0) {
930 		blocks = (fsblkcnt64_t)(cachep->c_label.cl_maxblks -
931 		    cachep->c_usage.cu_blksused);
932 		if ((longlong_t)blocks < (longlong_t)0)
933 			blocks = (fsblkcnt64_t)0;
934 		avail = (sb.f_bfree * sb.f_frsize) / MAXBSIZE;
935 		if (blocks < avail)
936 			avail = blocks;
937 	}
938 
939 	gsp->gs_total = cachep->c_usage.cu_blksused * CFS_STAT_FACTOR;
940 	gsp->gs_gc = RL_HEAD(cachep, CACHEFS_RL_GC)->rli_blkcnt *
941 		CFS_STAT_FACTOR;
942 	gsp->gs_active = RL_HEAD(cachep, CACHEFS_RL_ACTIVE)->rli_blkcnt *
943 		CFS_STAT_FACTOR;
944 	gsp->gs_packed = RL_HEAD(cachep, CACHEFS_RL_PACKED)->rli_blkcnt *
945 		CFS_STAT_FACTOR;
946 	gsp->gs_free = (long)(avail * CFS_STAT_FACTOR);
947 	gsp->gs_gctime = cachep->c_rlinfo.rl_gctime;
948 	return (0);
949 }
950 
951 /*
952  * This looks to see if the specified file exists in the cache.
953  * 	0 is returned if it exists
954  *	ENOENT is returned if it doesn't exist.
955  */
956 int
957 /*ARGSUSED*/
cachefs_io_exists(vnode_t * vp,void * dinp,void * doutp)958 cachefs_io_exists(vnode_t *vp, void *dinp, void *doutp)
959 {
960 	fscache_t  *fscp = C_TO_FSCACHE(VTOC(vp));
961 	cnode_t *cp = NULL;
962 	int error;
963 	cfs_cid_t *cidp = (cfs_cid_t *)dinp;
964 
965 	/*
966 	 * Only called in support of disconnectable operation, so assert
967 	 * that this is not called when NFSv4 is the backfilesytem.
968 	 */
969 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
970 
971 	/* find the cnode of the file */
972 	error = cachefs_cnode_make(cidp, fscp,
973 	    NULL, NULL, NULL, kcred, 0, &cp);
974 	if (error)
975 		return (ENOENT);
976 
977 	if ((cp->c_flags & (CN_DESTROY | CN_NOCACHE)) ||
978 	    !(cp->c_metadata.md_flags & (MD_POPULATED | MD_FASTSYMLNK)))
979 		error = ENOENT;
980 
981 	VN_RELE(CTOV(cp));
982 	return	(error);
983 
984 }
985 
986 /*
987  * Moves the specified file to the lost+found directory for the
988  * cached file system.
989  * Invalidates cached data and attributes.
990  * Returns 0 or an error if could not perform operation.
991  */
992 int
cachefs_io_lostfound(vnode_t * vp,void * dinp,void * doutp)993 cachefs_io_lostfound(vnode_t *vp, void *dinp, void *doutp)
994 {
995 	int error;
996 	cnode_t *cp = NULL;
997 	fscache_t *fscp;
998 	cachefscache_t *cachep;
999 	cachefsio_lostfound_arg_t *lfp;
1000 	cachefsio_lostfound_return_t *rp;
1001 
1002 	lfp = (cachefsio_lostfound_arg_t *)dinp;
1003 	rp = (cachefsio_lostfound_return_t *)doutp;
1004 
1005 	fscp = C_TO_FSCACHE(VTOC(vp));
1006 	cachep = fscp->fs_cache;
1007 
1008 	ASSERT((cachep->c_flags & (CACHE_NOCACHE|CACHE_NOFILL)) == 0);
1009 
1010 	/*
1011 	 * Only called in support of disconnectable operation, so assert
1012 	 * that this is not called when NFSv4 is the backfilesytem.
1013 	 */
1014 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
1015 
1016 	/* find the cnode of the file */
1017 	error = cachefs_cnode_make(&lfp->lf_cid, fscp,
1018 	    NULL, NULL, NULL, kcred, 0, &cp);
1019 	if (error) {
1020 		error = ENOENT;
1021 		goto out;
1022 	}
1023 
1024 	mutex_enter(&cp->c_statelock);
1025 
1026 	/* must be regular file and modified */
1027 	if ((cp->c_attr.va_type != VREG) ||
1028 	    (cp->c_metadata.md_rltype != CACHEFS_RL_MODIFIED)) {
1029 		mutex_exit(&cp->c_statelock);
1030 		error = EINVAL;
1031 		goto out;
1032 	}
1033 
1034 	/* move to lost+found */
1035 	error = cachefs_cnode_lostfound(cp, lfp->lf_name);
1036 	mutex_exit(&cp->c_statelock);
1037 
1038 	if (error == 0)
1039 		(void) strcpy(rp->lf_name, lfp->lf_name);
1040 out:
1041 	if (cp)
1042 		VN_RELE(CTOV(cp));
1043 
1044 	return (error);
1045 }
1046 
1047 /*
1048  * Given a cid, returns info about the file in the cache.
1049  */
1050 int
cachefs_io_getinfo(vnode_t * vp,void * dinp,void * doutp)1051 cachefs_io_getinfo(vnode_t *vp, void *dinp, void *doutp)
1052 {
1053 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
1054 	struct cnode *dcp = NULL;
1055 	struct cnode *cp = NULL;
1056 	struct vattr va;
1057 	u_offset_t blockoff = 0;
1058 	struct fbuf *fbp;
1059 	int offset = 0;
1060 	int error = 0;
1061 	cfs_cid_t *fcidp;
1062 	cachefsio_getinfo_t *infop;
1063 
1064 	/*
1065 	 * Only called in support of disconnectable operation, so assert
1066 	 * that this is not called when NFSv4 is the backfilesytem.
1067 	 */
1068 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
1069 
1070 	fcidp = (cfs_cid_t *)dinp;
1071 	infop = (cachefsio_getinfo_t *)doutp;
1072 
1073 	/* find the cnode of the file */
1074 	error = cachefs_cnode_make(fcidp, fscp, NULL, NULL, NULL,
1075 	    kcred, 0, &cp);
1076 	if (error) {
1077 		error = ENOENT;
1078 		goto out;
1079 	}
1080 
1081 	infop->gi_cid = *fcidp;
1082 	infop->gi_modified = (cp->c_metadata.md_rltype == CACHEFS_RL_MODIFIED);
1083 	CACHEFS_VATTR_TO_CFS_VATTR_COPY(&cp->c_attr, &infop->gi_attr, error);
1084 	infop->gi_pcid = cp->c_metadata.md_parent;
1085 	infop->gi_name[0] = '\0';
1086 	infop->gi_seq = cp->c_metadata.md_seq;
1087 	if (error || (cp->c_metadata.md_parent.cid_fileno == 0))
1088 		goto out;
1089 
1090 	/* try to get the cnode of the parent dir */
1091 	error = cachefs_cnode_make(&cp->c_metadata.md_parent, fscp,
1092 	    NULL, NULL, NULL, kcred, 0, &dcp);
1093 	if (error) {
1094 		error = 0;
1095 		goto out;
1096 	}
1097 
1098 	/* make sure a directory and populated */
1099 	if ((((dcp->c_flags & CN_ASYNC_POPULATE) == 0) ||
1100 	    ((dcp->c_metadata.md_flags & MD_POPULATED) == 0)) &&
1101 	    (CTOV(dcp)->v_type == VDIR)) {
1102 		error = 0;
1103 		goto out;
1104 	}
1105 
1106 	/* get the front file */
1107 	if (dcp->c_frontvp == NULL) {
1108 		mutex_enter(&dcp->c_statelock);
1109 		error = cachefs_getfrontfile(dcp);
1110 		mutex_exit(&dcp->c_statelock);
1111 		if (error) {
1112 			error = 0;
1113 			goto out;
1114 		}
1115 
1116 		/* make sure frontvp is still populated */
1117 		if ((dcp->c_metadata.md_flags & MD_POPULATED) == 0) {
1118 			error = 0;
1119 			goto out;
1120 		}
1121 	}
1122 
1123 	/* Get the length of the directory */
1124 	va.va_mask = AT_SIZE;
1125 	error = VOP_GETATTR(dcp->c_frontvp, &va, 0, kcred, NULL);
1126 	if (error) {
1127 		error = 0;
1128 		goto out;
1129 	}
1130 
1131 	/* XXX bob: change this to use cachfs_dir_read */
1132 	/* We have found the parent, now we open the dir and look for file */
1133 	while (blockoff < va.va_size) {
1134 		offset = 0;
1135 		error = fbread(dcp->c_frontvp, (offset_t)blockoff, MAXBSIZE,
1136 						S_OTHER, &fbp);
1137 		if (error)
1138 			goto out;
1139 		while (offset < MAXBSIZE && (blockoff + offset) < va.va_size) {
1140 			struct c_dirent	*dep;
1141 			dep = (struct c_dirent *)((uintptr_t)fbp->fb_addr +
1142 									offset);
1143 			if ((dep->d_flag & CDE_VALID) &&
1144 			    (bcmp(&dep->d_id, &infop->gi_cid,
1145 			    sizeof (cfs_cid_t)) == 0)) {
1146 				/* found the name */
1147 				(void) strcpy(infop->gi_name, dep->d_name);
1148 				fbrelse(fbp, S_OTHER);
1149 				goto out;
1150 			}
1151 			offset += dep->d_length;
1152 		}
1153 		fbrelse(fbp, S_OTHER);
1154 		fbp = NULL;
1155 		blockoff += MAXBSIZE;
1156 
1157 	}
1158 out:
1159 	if (cp)
1160 		VN_RELE(CTOV(cp));
1161 	if (dcp)
1162 		VN_RELE(CTOV(dcp));
1163 	return (error);
1164 }
1165 
1166 /*
1167  * Given a file number, this functions returns the fid
1168  * for the back file system.
1169  * Returns ENOENT if file does not exist.
1170  * Returns ENOMSG if fid is not valid, ie: local file.
1171  */
1172 int
cachefs_io_cidtofid(vnode_t * vp,void * dinp,void * doutp)1173 cachefs_io_cidtofid(vnode_t *vp, void *dinp, void *doutp)
1174 {
1175 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
1176 	cnode_t *cp = NULL;
1177 	int error;
1178 	cfs_cid_t *cidp = (cfs_cid_t *)dinp;
1179 	cfs_fid_t *fidp = (cfs_fid_t *)doutp;
1180 
1181 	/*
1182 	 * Only called in support of disconnectable operation, so assert
1183 	 * that this is not called when NFSv4 is the backfilesytem.
1184 	 */
1185 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
1186 
1187 	/* get the cnode for the file */
1188 	error = cachefs_cnode_make(cidp, fscp, NULL, NULL, NULL, kcred, 0, &cp);
1189 	if (error)
1190 		goto out;
1191 
1192 	/* if local file, fid is a local fid and is not valid */
1193 	if (cp->c_id.cid_flags & CFS_CID_LOCAL) {
1194 		error = ENOMSG;
1195 		goto out;
1196 	}
1197 
1198 	/* copy out the fid */
1199 	CACHEFS_FID_COPY(&cp->c_cookie, fidp);
1200 
1201 out:
1202 	if (cp)
1203 		VN_RELE(CTOV(cp));
1204 	return	(error);
1205 }
1206 
1207 /*
1208  * This performs a getattr on the back file system given
1209  * a fid that is passed in.
1210  *
1211  * The backfid is in gafid->cg_backfid, the creds to use for
1212  * this operation are in gafid->cg_cred.  The attributes are
1213  * returned in gafid->cg_attr
1214  *
1215  * the error returned is 0 if successful, nozero if not
1216  */
1217 int
cachefs_io_getattrfid(vnode_t * vp,void * dinp,void * doutp)1218 cachefs_io_getattrfid(vnode_t *vp, void *dinp, void *doutp)
1219 {
1220 	vnode_t	*backvp = NULL;
1221 	fscache_t  *fscp = C_TO_FSCACHE(VTOC(vp));
1222 	int error = 0;
1223 	cred_t	*cr;
1224 	cachefsio_getattrfid_t *gafid;
1225 	fid_t	*tmpfidp;
1226 	vattr_t *tmpvap;
1227 	cfs_vattr_t *attrp;
1228 	CACHEFS_DECL(fid_t, tmpfid);
1229 	CACHEFS_DECL(vattr_t, va);
1230 
1231 	/*
1232 	 * Only called in support of disconnectable operation, so assert
1233 	 * that this is not called when NFSv4 is the backfilesytem.
1234 	 */
1235 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
1236 
1237 	gafid = (cachefsio_getattrfid_t *)dinp;
1238 	attrp = (cfs_vattr_t *)doutp;
1239 
1240 	/* Get a vnode for the back file */
1241 	CACHEFS_TMPPTR_SET(&gafid->cg_backfid, &tmpfid, tmpfidp, fid_t);
1242 	CACHEFS_FID_COPYIN(&gafid->cg_backfid, tmpfidp);
1243 	error = VFS_VGET(fscp->fs_backvfsp, &backvp, tmpfidp);
1244 	if (error)
1245 		return (error);
1246 
1247 	cr = conj_cred(&gafid->cg_cred);
1248 	CACHEFS_TMPPTR_SET(attrp, &va, tmpvap, vattr_t);
1249 	tmpvap->va_mask = AT_ALL;
1250 	error = VOP_GETATTR(backvp, tmpvap, 0, cr, NULL);
1251 	CACHEFS_VATTR_COPYOUT(tmpvap, attrp, error);
1252 	crfree(cr);
1253 
1254 	/* VFS_VGET performs a VN_HOLD on the vp */
1255 	VN_RELE(backvp);
1256 
1257 	return (error);
1258 }
1259 
1260 
1261 /*
1262  * This performs a getattr on the back file system.  Instead of
1263  * passing the fid to perform the gettr on we are given the
1264  * parent directory fid and a name.
1265  */
1266 int
cachefs_io_getattrname(vnode_t * vp,void * dinp,void * doutp)1267 cachefs_io_getattrname(vnode_t *vp, void *dinp, void *doutp)
1268 {
1269 	vnode_t	*pbackvp = NULL;
1270 	vnode_t	*cbackvp = NULL;
1271 	fscache_t  *fscp = C_TO_FSCACHE(VTOC(vp));
1272 	int error = 0;
1273 	cred_t	*cr;
1274 	fid_t	*tmpfidp;
1275 	vattr_t	*tmpvap;
1276 	cachefsio_getattrname_arg_t *gap;
1277 	cachefsio_getattrname_return_t *retp;
1278 	CACHEFS_DECL(fid_t, tmpfid);
1279 	CACHEFS_DECL(vattr_t, va);
1280 
1281 	/*
1282 	 * Only called in support of disconnectable operation, so assert
1283 	 * that this is not called when NFSv4 is the backfilesytem.
1284 	 */
1285 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
1286 
1287 	gap = (cachefsio_getattrname_arg_t *)dinp;
1288 	retp = (cachefsio_getattrname_return_t *)doutp;
1289 
1290 	/* Get a vnode for the parent directory */
1291 	CACHEFS_TMPPTR_SET(&gap->cg_dir, &tmpfid, tmpfidp, fid_t);
1292 	CACHEFS_FID_COPYIN(&gap->cg_dir, tmpfidp);
1293 	error = VFS_VGET(fscp->fs_backvfsp, &pbackvp, tmpfidp);
1294 	if (error)
1295 		return (error);
1296 
1297 	/* lookup the file name */
1298 	cr = conj_cred(&gap->cg_cred);
1299 	error = VOP_LOOKUP(pbackvp, gap->cg_name, &cbackvp,
1300 	    (struct pathname *)NULL, 0, (vnode_t *)NULL, cr, NULL, NULL, NULL);
1301 	if (error) {
1302 		crfree(cr);
1303 		VN_RELE(pbackvp);
1304 		return (error);
1305 	}
1306 
1307 	CACHEFS_TMPPTR_SET(&retp->cg_attr, &va, tmpvap, vattr_t);
1308 	tmpvap->va_mask = AT_ALL;
1309 	error = VOP_GETATTR(cbackvp, tmpvap, 0, cr, NULL);
1310 	CACHEFS_VATTR_COPYOUT(tmpvap, &retp->cg_attr, error);
1311 	if (!error) {
1312 		CACHEFS_TMPPTR_SET(&retp->cg_fid, &tmpfid, tmpfidp, fid_t);
1313 		tmpfidp->fid_len = MAXFIDSZ;
1314 		error = VOP_FID(cbackvp, tmpfidp, NULL);
1315 		CACHEFS_FID_COPYOUT(tmpfidp, &retp->cg_fid);
1316 	}
1317 
1318 	crfree(cr);
1319 	VN_RELE(cbackvp);
1320 	VN_RELE(pbackvp);
1321 	return (error);
1322 }
1323 
1324 /*
1325  * This will return the fid of the root of this mount point.
1326  */
1327 int
1328 /*ARGSUSED*/
cachefs_io_rootfid(vnode_t * vp,void * dinp,void * doutp)1329 cachefs_io_rootfid(vnode_t *vp, void *dinp, void *doutp)
1330 {
1331 	fscache_t  *fscp = C_TO_FSCACHE(VTOC(vp));
1332 	cfs_fid_t *rootfid = (cfs_fid_t *)doutp;
1333 
1334 	/*
1335 	 * Only called in support of disconnectable operation, so assert
1336 	 * that this is not called when NFSv4 is the backfilesytem.
1337 	 */
1338 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
1339 
1340 	CACHEFS_FID_COPY(&VTOC(fscp->fs_rootvp)->c_metadata.md_cookie, rootfid);
1341 	return (0);
1342 }
1343 
1344 /*
1345  * Pushes the data associated with a file back to the file server.
1346  */
1347 int
cachefs_io_pushback(vnode_t * vp,void * dinp,void * doutp)1348 cachefs_io_pushback(vnode_t *vp, void *dinp, void *doutp)
1349 {
1350 	vnode_t *backvp = NULL;
1351 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
1352 	caddr_t	buffer = NULL;
1353 	int error = 0;
1354 	cnode_t	*cp;
1355 	size_t amt;
1356 	u_offset_t size;
1357 	vattr_t	va;
1358 	offset_t off;
1359 	cred_t *cr = NULL;
1360 	fid_t	*tmpfidp;
1361 	cachefsio_pushback_arg_t *pbp;
1362 	cachefsio_pushback_return_t *retp;
1363 	CACHEFS_DECL(fid_t, tmpfid);
1364 
1365 	/*
1366 	 * Only called in support of disconnectable operation, so assert
1367 	 * that this is not called when NFSv4 is the backfilesytem.
1368 	 */
1369 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
1370 
1371 	pbp = (cachefsio_pushback_arg_t *)dinp;
1372 	retp = (cachefsio_pushback_return_t *)doutp;
1373 
1374 	cr = conj_cred(&pbp->pb_cred);
1375 
1376 	/* get the backvp to push to */
1377 	CACHEFS_TMPPTR_SET(&pbp->pb_fid, &tmpfid, tmpfidp, fid_t);
1378 	CACHEFS_FID_COPYIN(&pbp->pb_fid, tmpfidp);
1379 	error = VFS_VGET(fscp->fs_backvfsp, &backvp, tmpfidp);
1380 	if (error) {
1381 		backvp = NULL;
1382 		goto out;
1383 	}
1384 
1385 	/* Get the cnode for the file we are to push back */
1386 	error = cachefs_cnode_make(&pbp->pb_cid, fscp,
1387 	    NULL, NULL, NULL, cr, 0, &cp);
1388 	if (error) {
1389 		goto out;
1390 	}
1391 
1392 	/* must be a regular file */
1393 	if (cp->c_attr.va_type != VREG) {
1394 		error = EINVAL;
1395 		goto out;
1396 	}
1397 
1398 	mutex_enter(&cp->c_statelock);
1399 
1400 	/* get the front file */
1401 	if (cp->c_frontvp == NULL) {
1402 		error = cachefs_getfrontfile(cp);
1403 		if (error) {
1404 			mutex_exit(&cp->c_statelock);
1405 			goto out;
1406 		}
1407 	}
1408 
1409 	/* better be populated */
1410 	if ((cp->c_metadata.md_flags & MD_POPULATED) == 0) {
1411 		mutex_exit(&cp->c_statelock);
1412 		error = EINVAL;
1413 		goto out;
1414 	}
1415 
1416 	/* do open so NFS gets correct creds on writes */
1417 	error = VOP_OPEN(&backvp, FWRITE, cr, NULL);
1418 	if (error) {
1419 		mutex_exit(&cp->c_statelock);
1420 		goto out;
1421 	}
1422 
1423 	buffer = cachefs_kmem_alloc(MAXBSIZE, KM_SLEEP);
1424 
1425 	/* Read the data from the cache and write it to the server */
1426 	/* XXX why not use segmapio? */
1427 	off = 0;
1428 	for (size = cp->c_size; size != 0; size -= amt) {
1429 		if (size > MAXBSIZE)
1430 			amt = MAXBSIZE;
1431 		else
1432 			amt = size;
1433 
1434 		/* read a block of data from the front file */
1435 		error = vn_rdwr(UIO_READ, cp->c_frontvp, buffer,
1436 			amt, off, UIO_SYSSPACE, 0, RLIM_INFINITY, cr, 0);
1437 		if (error) {
1438 			mutex_exit(&cp->c_statelock);
1439 			goto out;
1440 		}
1441 
1442 		/* write the block of data to the back file */
1443 		error = vn_rdwr(UIO_WRITE, backvp, buffer, amt, off,
1444 			UIO_SYSSPACE, 0, RLIM_INFINITY, cr, 0);
1445 		if (error) {
1446 			mutex_exit(&cp->c_statelock);
1447 			goto out;
1448 		}
1449 		off += amt;
1450 	}
1451 
1452 	error = VOP_FSYNC(backvp, FSYNC, cr, NULL);
1453 	if (error == 0)
1454 		error = VOP_CLOSE(backvp, FWRITE, 1, (offset_t)0, cr, NULL);
1455 	if (error) {
1456 		mutex_exit(&cp->c_statelock);
1457 		goto out;
1458 	}
1459 
1460 	cp->c_metadata.md_flags |= MD_PUSHDONE;
1461 	cp->c_metadata.md_flags &= ~MD_PUTPAGE;
1462 	cp->c_metadata.md_flags |= MD_NEEDATTRS;
1463 	cp->c_flags |= CN_UPDATED;
1464 	mutex_exit(&cp->c_statelock);
1465 
1466 	/*
1467 	 * if we have successfully stored the data, we need the
1468 	 * new ctime and mtimes.
1469 	 */
1470 	va.va_mask = AT_ALL;
1471 	error = VOP_GETATTR(backvp, &va, 0, cr, NULL);
1472 	if (error)
1473 		goto out;
1474 	CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->pb_ctime, error);
1475 	CACHEFS_TS_TO_CFS_TS_COPY(&va.va_mtime, &retp->pb_mtime, error);
1476 
1477 out:
1478 	if (buffer)
1479 		cachefs_kmem_free(buffer, MAXBSIZE);
1480 	if (cp)
1481 		VN_RELE(CTOV(cp));
1482 	if (backvp)
1483 		VN_RELE(backvp);
1484 	if (cr)
1485 		crfree(cr);
1486 	return (error);
1487 }
1488 
1489 /*
1490  * Create a file on the back file system.
1491  */
1492 int
cachefs_io_create(vnode_t * vp,void * dinp,void * doutp)1493 cachefs_io_create(vnode_t *vp, void *dinp, void *doutp)
1494 {
1495 	vnode_t	*dvp = NULL;
1496 	vnode_t	*cvp = NULL;
1497 	cnode_t *cp = NULL;
1498 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
1499 	vattr_t	va, *tmpvap;
1500 	int error = 0;
1501 	cred_t *cr = NULL;
1502 	fid_t	*tmpfidp;
1503 	cachefsio_create_arg_t *crp;
1504 	cachefsio_create_return_t *retp;
1505 	CACHEFS_DECL(fid_t, tmpfid);
1506 
1507 	/*
1508 	 * Only called in support of disconnectable operation, so assert
1509 	 * that this is not called when NFSv4 is the backfilesytem.
1510 	 */
1511 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
1512 
1513 	crp = (cachefsio_create_arg_t *)dinp;
1514 	retp = (cachefsio_create_return_t *)doutp;
1515 
1516 	/* get a vnode for the parent directory  */
1517 	CACHEFS_TMPPTR_SET(&crp->cr_backfid, &tmpfid, tmpfidp, fid_t);
1518 	CACHEFS_FID_COPYIN(&crp->cr_backfid, tmpfidp);
1519 	error = VFS_VGET(fscp->fs_backvfsp, &dvp, tmpfidp);
1520 	if (error)
1521 		goto out;
1522 
1523 	cr = conj_cred(&crp->cr_cred);
1524 
1525 	/* do the create */
1526 	CACHEFS_TMPPTR_SET(&crp->cr_va, &va, tmpvap, vattr_t);
1527 	CACHEFS_VATTR_COPYIN(&crp->cr_va, tmpvap);
1528 	error = VOP_CREATE(dvp, crp->cr_name, tmpvap,
1529 	    crp->cr_exclusive, crp->cr_mode, &cvp, cr, 0, NULL, NULL);
1530 	if (error)
1531 		goto out;
1532 
1533 	/* get the fid of the file */
1534 	CACHEFS_TMPPTR_SET(&retp->cr_newfid, &tmpfid, tmpfidp, fid_t);
1535 	tmpfidp->fid_len = MAXFIDSZ;
1536 	error = VOP_FID(cvp, tmpfidp, NULL);
1537 	if (error)
1538 		goto out;
1539 	CACHEFS_FID_COPYOUT(tmpfidp, &retp->cr_newfid);
1540 
1541 	/* get attributes for the file */
1542 	va.va_mask = AT_ALL;
1543 	error = VOP_GETATTR(cvp, &va, 0, cr, NULL);
1544 	if (error)
1545 		goto out;
1546 	CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->cr_ctime, error);
1547 	CACHEFS_TS_TO_CFS_TS_COPY(&va.va_mtime, &retp->cr_mtime, error);
1548 	if (error)
1549 		goto out;
1550 
1551 	/* update the cnode for this file with the new info */
1552 	error = cachefs_cnode_make(&crp->cr_cid, fscp,
1553 	    NULL, NULL, NULL, cr, 0, &cp);
1554 	if (error) {
1555 		error = 0;
1556 		goto out;
1557 	}
1558 
1559 	mutex_enter(&cp->c_statelock);
1560 	ASSERT(cp->c_id.cid_flags & CFS_CID_LOCAL);
1561 	cp->c_attr.va_nodeid = va.va_nodeid;
1562 	cp->c_metadata.md_flags |= MD_CREATEDONE;
1563 	cp->c_metadata.md_flags |= MD_NEEDATTRS;
1564 	cp->c_metadata.md_cookie = *tmpfidp;
1565 	cp->c_flags |= CN_UPDATED;
1566 	mutex_exit(&cp->c_statelock);
1567 
1568 out:
1569 	if (cr)
1570 		crfree(cr);
1571 	if (dvp)
1572 		VN_RELE(dvp);
1573 	if (cvp)
1574 		VN_RELE(cvp);
1575 	if (cp)
1576 		VN_RELE(CTOV(cp));
1577 	return (error);
1578 }
1579 
1580 /*
1581  * Remove a file on the back file system.
1582  * Returns 0 or an error if could not perform operation.
1583  */
1584 int
cachefs_io_remove(vnode_t * vp,void * dinp,void * doutp)1585 cachefs_io_remove(vnode_t *vp, void *dinp, void *doutp)
1586 {
1587 	vnode_t	*dvp = NULL;
1588 	vnode_t	*cvp;
1589 	cred_t *cr = NULL;
1590 	vattr_t	va;
1591 	fscache_t  *fscp = C_TO_FSCACHE(VTOC(vp));
1592 	int error;
1593 	fid_t child_fid, *child_fidp;
1594 	cachefsio_remove_t *rmp = (cachefsio_remove_t *)dinp;
1595 	cfs_timestruc_t *ctimep = (cfs_timestruc_t *)doutp;
1596 
1597 	/*
1598 	 * Only called in support of disconnectable operation, so assert
1599 	 * that this is not called when NFSv4 is the backfilesytem.
1600 	 */
1601 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
1602 
1603 	/* Get a vnode for the directory */
1604 	CACHEFS_TMPPTR_SET(&rmp->rm_fid, &child_fid, child_fidp, fid_t);
1605 	CACHEFS_FID_COPYIN(&rmp->rm_fid, child_fidp);
1606 	error = VFS_VGET(fscp->fs_backvfsp, &dvp, child_fidp);
1607 	if (error) {
1608 		dvp = NULL;
1609 		goto out;
1610 	}
1611 
1612 	cr = conj_cred(&rmp->rm_cred);
1613 
1614 	/* if the caller wants the ctime after the remove */
1615 	if (ctimep) {
1616 		error = VOP_LOOKUP(dvp, rmp->rm_name, &cvp, NULL, 0, NULL, cr,
1617 			NULL, NULL, NULL);
1618 		if (error == 0) {
1619 			child_fid.fid_len = MAXFIDSZ;
1620 			error = VOP_FID(cvp, &child_fid, NULL);
1621 			VN_RELE(cvp);
1622 		}
1623 		if (error)
1624 			goto out;
1625 	}
1626 
1627 	/* do the remove */
1628 	error = VOP_REMOVE(dvp, rmp->rm_name, cr, NULL, 0);
1629 	if (error)
1630 		goto out;
1631 
1632 	/* get the new ctime if requested */
1633 	if (ctimep) {
1634 		error = VFS_VGET(fscp->fs_backvfsp, &cvp, &child_fid);
1635 		if (error == 0) {
1636 			va.va_mask = AT_ALL;
1637 			error = VOP_GETATTR(cvp, &va, 0, cr, NULL);
1638 			if (error == 0) {
1639 				CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime,
1640 					ctimep, error);
1641 			}
1642 			VN_RELE(cvp);
1643 		}
1644 		cachefs_iosetneedattrs(fscp, &rmp->rm_cid);
1645 	}
1646 
1647 out:
1648 	if (cr)
1649 		crfree(cr);
1650 	if (dvp)
1651 		VN_RELE(dvp);
1652 	return (error);
1653 }
1654 
1655 /*
1656  * Perform a link on the back file system.
1657  * Returns 0 or an error if could not perform operation.
1658  */
1659 int
cachefs_io_link(vnode_t * vp,void * dinp,void * doutp)1660 cachefs_io_link(vnode_t *vp, void *dinp, void *doutp)
1661 {
1662 	vnode_t	*dvp = NULL;
1663 	vnode_t	*lvp = NULL;
1664 	vattr_t	va;
1665 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
1666 	int error = 0;
1667 	cred_t *cr = NULL;
1668 	fid_t *tmpfidp;
1669 	cachefsio_link_t *linkp = (cachefsio_link_t *)dinp;
1670 	cfs_timestruc_t *ctimep = (cfs_timestruc_t *)doutp;
1671 	CACHEFS_DECL(fid_t, tmpfid);
1672 
1673 	/*
1674 	 * Only called in support of disconnectable operation, so assert
1675 	 * that this is not called when NFSv4 is the backfilesytem.
1676 	 */
1677 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
1678 
1679 	/* Get a vnode parent directory */
1680 	CACHEFS_TMPPTR_SET(&linkp->ln_dirfid, &tmpfid, tmpfidp, fid_t);
1681 	CACHEFS_FID_COPYIN(&linkp->ln_dirfid, tmpfidp);
1682 	error = VFS_VGET(fscp->fs_backvfsp, &dvp, tmpfidp);
1683 	if (error) {
1684 		dvp = NULL;
1685 		goto out;
1686 	}
1687 
1688 	/* Get a vnode file to link to */
1689 	CACHEFS_TMPPTR_SET(&linkp->ln_filefid, &tmpfid, tmpfidp, fid_t);
1690 	CACHEFS_FID_COPYIN(&linkp->ln_filefid, tmpfidp);
1691 	error = VFS_VGET(fscp->fs_backvfsp, &lvp, tmpfidp);
1692 	if (error) {
1693 		lvp = NULL;
1694 		goto out;
1695 	}
1696 
1697 	cr = conj_cred(&linkp->ln_cred);
1698 
1699 	/* do the link */
1700 	error = VOP_LINK(dvp, lvp, linkp->ln_name, cr, NULL, 0);
1701 	if (error)
1702 		goto out;
1703 
1704 	/* get the ctime */
1705 	va.va_mask = AT_ALL;
1706 	error = VOP_GETATTR(lvp, &va, 0, cr, NULL);
1707 	if (error)
1708 		goto out;
1709 	CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, ctimep, error);
1710 	if (error)
1711 		goto out;
1712 
1713 	cachefs_iosetneedattrs(fscp, &linkp->ln_cid);
1714 out:
1715 	if (cr)
1716 		crfree(cr);
1717 	if (dvp)
1718 		VN_RELE(dvp);
1719 	if (lvp)
1720 		VN_RELE(lvp);
1721 	return (error);
1722 }
1723 
1724 /*
1725  * Rename the file on the back file system.
1726  * Returns 0 or an error if could not perform operation.
1727  */
1728 int
cachefs_io_rename(vnode_t * vp,void * dinp,void * doutp)1729 cachefs_io_rename(vnode_t *vp, void *dinp, void *doutp)
1730 {
1731 	vnode_t	*odvp = NULL;
1732 	vnode_t	*ndvp = NULL;
1733 	cred_t *cr = NULL;
1734 	vnode_t	*cvp = NULL;
1735 	vattr_t va;
1736 	fscache_t  *fscp = C_TO_FSCACHE(VTOC(vp));
1737 	int error = 0;
1738 	fid_t child_fid, *child_fidp;
1739 	cachefsio_rename_arg_t *rnp;
1740 	cachefsio_rename_return_t *retp;
1741 
1742 	/*
1743 	 * Only called in support of disconnectable operation, so assert
1744 	 * that this is not called when NFSv4 is the backfilesytem.
1745 	 */
1746 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
1747 
1748 	rnp = (cachefsio_rename_arg_t *)dinp;
1749 	retp = (cachefsio_rename_return_t *)doutp;
1750 
1751 	/* Get vnode of old parent directory */
1752 	CACHEFS_TMPPTR_SET(&rnp->rn_olddir, &child_fid, child_fidp, fid_t);
1753 	CACHEFS_FID_COPYIN(&rnp->rn_olddir, child_fidp);
1754 	error = VFS_VGET(fscp->fs_backvfsp, &odvp, child_fidp);
1755 	if (error) {
1756 		odvp = NULL;
1757 		goto out;
1758 	}
1759 
1760 	/* Get vnode of new parent directory */
1761 	CACHEFS_TMPPTR_SET(&rnp->rn_newdir, &child_fid, child_fidp, fid_t);
1762 	CACHEFS_FID_COPYIN(&rnp->rn_newdir, child_fidp);
1763 	error = VFS_VGET(fscp->fs_backvfsp, &ndvp, child_fidp);
1764 	if (error) {
1765 		ndvp = NULL;
1766 		goto out;
1767 	}
1768 
1769 	cr = conj_cred(&rnp->rn_cred);
1770 
1771 	/* if the caller wants the ctime of the target after deletion */
1772 	if (rnp->rn_del_getctime) {
1773 		error = VOP_LOOKUP(ndvp, rnp->rn_newname, &cvp, NULL, 0,
1774 		    NULL, cr, NULL, NULL, NULL);
1775 		if (error) {
1776 			cvp = NULL; /* paranoia */
1777 			goto out;
1778 		}
1779 
1780 		child_fid.fid_len = MAXFIDSZ;
1781 		error = VOP_FID(cvp, &child_fid, NULL);
1782 		if (error)
1783 			goto out;
1784 		VN_RELE(cvp);
1785 		cvp = NULL;
1786 	}
1787 
1788 	/* do the rename */
1789 	error = VOP_RENAME(odvp, rnp->rn_oldname, ndvp, rnp->rn_newname, cr,
1790 		NULL, 0);
1791 	if (error)
1792 		goto out;
1793 
1794 	/* get the new ctime on the renamed file */
1795 	error = VOP_LOOKUP(ndvp, rnp->rn_newname, &cvp, NULL, 0, NULL, cr,
1796 		NULL, NULL, NULL);
1797 	if (error)
1798 		goto out;
1799 
1800 	va.va_mask = AT_ALL;
1801 	error = VOP_GETATTR(cvp, &va, 0, cr, NULL);
1802 	if (error)
1803 		goto out;
1804 	CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->rn_ctime, error);
1805 	VN_RELE(cvp);
1806 	cvp = NULL;
1807 	if (error)
1808 		goto out;
1809 
1810 	cachefs_iosetneedattrs(fscp, &rnp->rn_cid);
1811 
1812 	/* get the new ctime if requested of the deleted target */
1813 	if (rnp->rn_del_getctime) {
1814 		error = VFS_VGET(fscp->fs_backvfsp, &cvp, &child_fid);
1815 		if (error) {
1816 			cvp = NULL;
1817 			goto out;
1818 		}
1819 		va.va_mask = AT_ALL;
1820 		error = VOP_GETATTR(cvp, &va, 0, cr, NULL);
1821 		if (error)
1822 			goto out;
1823 		CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->rn_del_ctime,
1824 			error);
1825 		VN_RELE(cvp);
1826 		cvp = NULL;
1827 		if (error)
1828 			goto out;
1829 		cachefs_iosetneedattrs(fscp, &rnp->rn_del_cid);
1830 	}
1831 
1832 out:
1833 	if (cr)
1834 		crfree(cr);
1835 	if (cvp)
1836 		VN_RELE(cvp);
1837 	if (odvp)
1838 		VN_RELE(odvp);
1839 	if (ndvp)
1840 		VN_RELE(ndvp);
1841 	return (error);
1842 }
1843 
1844 /*
1845  * Make a directory on the backfs.
1846  * Returns 0 or an error if could not perform operation.
1847  */
1848 int
cachefs_io_mkdir(vnode_t * vp,void * dinp,void * doutp)1849 cachefs_io_mkdir(vnode_t *vp, void *dinp, void *doutp)
1850 {
1851 	vnode_t	*dvp = NULL;
1852 	vnode_t	*cvp = NULL;
1853 	cnode_t *cp = NULL;
1854 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
1855 	int error = 0;
1856 	cred_t *cr = NULL;
1857 	fid_t	*tmpfidp;
1858 	vattr_t va, *tmpvap;
1859 	cachefsio_mkdir_t *mdirp = (cachefsio_mkdir_t *)dinp;
1860 	cfs_fid_t *fidp = (cfs_fid_t *)doutp;
1861 	CACHEFS_DECL(fid_t, tmpfid);
1862 
1863 	/*
1864 	 * Only called in support of disconnectable operation, so assert
1865 	 * that this is not called when NFSv4 is the backfilesytem.
1866 	 */
1867 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
1868 
1869 	/* Get vnode of parent directory */
1870 	CACHEFS_TMPPTR_SET(&mdirp->md_dirfid, &tmpfid, tmpfidp, fid_t);
1871 	CACHEFS_FID_COPYIN(&mdirp->md_dirfid, tmpfidp);
1872 	error = VFS_VGET(fscp->fs_backvfsp, &dvp, tmpfidp);
1873 	if (error) {
1874 		dvp = NULL;
1875 		goto out;
1876 	}
1877 
1878 	cr = conj_cred(&mdirp->md_cred);
1879 
1880 	/* make the directory */
1881 	CACHEFS_TMPPTR_SET(&mdirp->md_vattr, &va, tmpvap, vattr_t);
1882 	CACHEFS_VATTR_COPYIN(&mdirp->md_vattr, tmpvap);
1883 	error = VOP_MKDIR(dvp, mdirp->md_name, tmpvap, &cvp, cr, NULL, 0, NULL);
1884 	if (error) {
1885 		if (error != EEXIST)
1886 			goto out;
1887 
1888 		/* if the directory already exists, then use it */
1889 		error = VOP_LOOKUP(dvp, mdirp->md_name, &cvp,
1890 		    NULL, 0, NULL, cr, NULL, NULL, NULL);
1891 		if (error) {
1892 			cvp = NULL;
1893 			goto out;
1894 		}
1895 		if (cvp->v_type != VDIR) {
1896 			error = EINVAL;
1897 			goto out;
1898 		}
1899 	}
1900 
1901 	/* get the fid of the directory */
1902 	CACHEFS_TMPPTR_SET(fidp, &tmpfid, tmpfidp, fid_t);
1903 	tmpfidp->fid_len = MAXFIDSZ;
1904 	error = VOP_FID(cvp, tmpfidp, NULL);
1905 	if (error)
1906 		goto out;
1907 	CACHEFS_FID_COPYOUT(tmpfidp, fidp);
1908 
1909 	/* get attributes of the directory */
1910 	va.va_mask = AT_ALL;
1911 	error = VOP_GETATTR(cvp, &va, 0, cr, NULL);
1912 	if (error)
1913 		goto out;
1914 
1915 	/* update the cnode for this dir with the new fid */
1916 	error = cachefs_cnode_make(&mdirp->md_cid, fscp,
1917 	    NULL, NULL, NULL, cr, 0, &cp);
1918 	if (error) {
1919 		error = 0;
1920 		goto out;
1921 	}
1922 	mutex_enter(&cp->c_statelock);
1923 	ASSERT(cp->c_id.cid_flags & CFS_CID_LOCAL);
1924 	cp->c_metadata.md_cookie = *tmpfidp;
1925 	cp->c_metadata.md_flags |= MD_CREATEDONE;
1926 	cp->c_metadata.md_flags |= MD_NEEDATTRS;
1927 	cp->c_attr.va_nodeid = va.va_nodeid;
1928 	cp->c_flags |= CN_UPDATED;
1929 	mutex_exit(&cp->c_statelock);
1930 out:
1931 	if (cr)
1932 		crfree(cr);
1933 	if (dvp)
1934 		VN_RELE(dvp);
1935 	if (cvp)
1936 		VN_RELE(cvp);
1937 	if (cp)
1938 		VN_RELE(CTOV(cp));
1939 	return (error);
1940 }
1941 
1942 /*
1943  * Perform a rmdir on the back file system.
1944  * Returns 0 or an error if could not perform operation.
1945  */
1946 int
1947 /*ARGSUSED*/
cachefs_io_rmdir(vnode_t * vp,void * dinp,void * doutp)1948 cachefs_io_rmdir(vnode_t *vp, void *dinp, void *doutp)
1949 {
1950 	vnode_t	*dvp = NULL;
1951 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
1952 	int error;
1953 	cred_t *cr;
1954 	fid_t	*tmpfidp;
1955 	cachefsio_rmdir_t *rdp = (cachefsio_rmdir_t *)dinp;
1956 	CACHEFS_DECL(fid_t, tmpfid);
1957 
1958 	/*
1959 	 * Only called in support of disconnectable operation, so assert
1960 	 * that this is not called when NFSv4 is the backfilesytem.
1961 	 */
1962 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
1963 
1964 	/* Get a vnode for the back file */
1965 	CACHEFS_TMPPTR_SET(&rdp->rd_dirfid, &tmpfid, tmpfidp, fid_t);
1966 	CACHEFS_FID_COPYIN(&rdp->rd_dirfid, tmpfidp);
1967 	error = VFS_VGET(fscp->fs_backvfsp, &dvp, tmpfidp);
1968 	if (error) {
1969 		dvp = NULL;
1970 		return (error);
1971 	}
1972 
1973 	cr = conj_cred(&rdp->rd_cred);
1974 	error = VOP_RMDIR(dvp, rdp->rd_name, dvp, cr, NULL, 0);
1975 	crfree(cr);
1976 
1977 	VN_RELE(dvp);
1978 	return (error);
1979 }
1980 
1981 /*
1982  * create a symlink on the back file system
1983  * Returns 0 or an error if could not perform operation.
1984  */
1985 int
cachefs_io_symlink(vnode_t * vp,void * dinp,void * doutp)1986 cachefs_io_symlink(vnode_t *vp, void *dinp, void *doutp)
1987 {
1988 	vnode_t	*dvp = NULL;
1989 	vnode_t	*svp = NULL;
1990 	cnode_t *cp = NULL;
1991 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
1992 	fid_t	*tmpfidp;
1993 	vattr_t	va, *tmpvap;
1994 	int error = 0;
1995 	cred_t *cr = NULL;
1996 	cachefsio_symlink_arg_t *symp;
1997 	cachefsio_symlink_return_t *retp;
1998 	CACHEFS_DECL(fid_t, tmpfid);
1999 
2000 	/*
2001 	 * Only called in support of disconnectable operation, so assert
2002 	 * that this is not called when NFSv4 is the backfilesytem.
2003 	 */
2004 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
2005 
2006 	symp = (cachefsio_symlink_arg_t *)dinp;
2007 	retp = (cachefsio_symlink_return_t *)doutp;
2008 
2009 	/* get a vnode for the back directory */
2010 	CACHEFS_TMPPTR_SET(&symp->sy_dirfid, &tmpfid, tmpfidp, fid_t);
2011 	CACHEFS_FID_COPYIN(&symp->sy_dirfid, tmpfidp);
2012 	error = VFS_VGET(fscp->fs_backvfsp, &dvp, tmpfidp);
2013 	if (error) {
2014 		dvp = NULL;
2015 		goto out;
2016 	}
2017 
2018 	cr = conj_cred(&symp->sy_cred);
2019 
2020 	/* create the symlink */
2021 	CACHEFS_TMPPTR_SET(&symp->sy_vattr, &va, tmpvap, vattr_t);
2022 	CACHEFS_VATTR_COPYIN(&symp->sy_vattr, tmpvap);
2023 	error = VOP_SYMLINK(dvp, symp->sy_name, tmpvap,
2024 	    symp->sy_link, cr, NULL, 0);
2025 	if (error)
2026 		goto out;
2027 
2028 	/* get the vnode for the symlink */
2029 	error = VOP_LOOKUP(dvp, symp->sy_name, &svp, NULL, 0, NULL, cr,
2030 		NULL, NULL, NULL);
2031 	if (error)
2032 		goto out;
2033 
2034 	/* get the attributes of the symlink */
2035 	va.va_mask = AT_ALL;
2036 	error = VOP_GETATTR(svp, &va, 0, cr, NULL);
2037 	if (error)
2038 		goto out;
2039 	CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->sy_ctime, error);
2040 	CACHEFS_TS_TO_CFS_TS_COPY(&va.va_mtime, &retp->sy_mtime, error);
2041 	if (error)
2042 		goto out;
2043 
2044 	/* get the fid */
2045 	CACHEFS_TMPPTR_SET(&retp->sy_newfid, &tmpfid, tmpfidp, fid_t);
2046 	tmpfidp->fid_len = MAXFIDSZ;
2047 	error = VOP_FID(svp, tmpfidp, NULL);
2048 	if (error)
2049 		goto out;
2050 	CACHEFS_FID_COPYOUT(tmpfidp, &retp->sy_newfid);
2051 
2052 	/* update the cnode for this file with the new info */
2053 	error = cachefs_cnode_make(&symp->sy_cid, fscp,
2054 	    NULL, NULL, NULL, cr, 0, &cp);
2055 	if (error) {
2056 		error = 0;
2057 		goto out;
2058 	}
2059 	mutex_enter(&cp->c_statelock);
2060 	ASSERT(cp->c_id.cid_flags & CFS_CID_LOCAL);
2061 	cp->c_metadata.md_cookie = *tmpfidp;
2062 	cp->c_metadata.md_flags |= MD_CREATEDONE;
2063 	cp->c_metadata.md_flags |= MD_NEEDATTRS;
2064 	cp->c_attr.va_nodeid = va.va_nodeid;
2065 	cp->c_flags |= CN_UPDATED;
2066 	mutex_exit(&cp->c_statelock);
2067 
2068 out:
2069 	if (cr)
2070 		crfree(cr);
2071 	if (dvp)
2072 		VN_RELE(dvp);
2073 	if (svp)
2074 		VN_RELE(svp);
2075 	if (cp)
2076 		VN_RELE(CTOV(cp));
2077 	return (error);
2078 }
2079 
2080 /*
2081  * Perform setattr on the back file system.
2082  * Returns 0 or an error if could not perform operation.
2083  */
2084 int
cachefs_io_setattr(vnode_t * vp,void * dinp,void * doutp)2085 cachefs_io_setattr(vnode_t *vp, void *dinp, void *doutp)
2086 {
2087 	vnode_t	*cvp = NULL;
2088 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
2089 	fid_t	*tmpfidp;
2090 	vattr_t	va, *tmpvap;
2091 	int error = 0;
2092 	cred_t *cr = NULL;
2093 	cachefsio_setattr_arg_t *sap;
2094 	cachefsio_setattr_return_t *retp;
2095 	CACHEFS_DECL(fid_t, tmpfid);
2096 
2097 	/*
2098 	 * Only called in support of disconnectable operation, so assert
2099 	 * that this is not called when NFSv4 is the backfilesytem.
2100 	 */
2101 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
2102 
2103 	sap = (cachefsio_setattr_arg_t *)dinp;
2104 	retp = (cachefsio_setattr_return_t *)doutp;
2105 
2106 	/* get a vnode for the back directory */
2107 	CACHEFS_TMPPTR_SET(&sap->sa_backfid, &tmpfid, tmpfidp, fid_t);
2108 	CACHEFS_FID_COPYIN(&sap->sa_backfid, tmpfidp);
2109 	error = VFS_VGET(fscp->fs_backvfsp, &cvp, tmpfidp);
2110 	if (error) {
2111 		cvp = NULL;
2112 		goto out;
2113 	}
2114 
2115 	cr = conj_cred(&sap->sa_cred);
2116 
2117 	/* perform the setattr */
2118 	CACHEFS_TMPPTR_SET(&sap->sa_vattr, &va, tmpvap, vattr_t);
2119 	CACHEFS_VATTR_COPYIN(&sap->sa_vattr, tmpvap);
2120 	error = VOP_SETATTR(cvp, tmpvap, 0, cr, NULL);
2121 	if (error)
2122 		goto out;
2123 
2124 	/* get the new ctime and mtime */
2125 	va.va_mask = AT_ALL;
2126 	error = VOP_GETATTR(cvp, &va, 0, cr, NULL);
2127 	if (error)
2128 		goto out;
2129 	CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->sa_ctime, error);
2130 	CACHEFS_TS_TO_CFS_TS_COPY(&va.va_mtime, &retp->sa_mtime, error);
2131 	if (error)
2132 		goto out;
2133 
2134 	cachefs_iosetneedattrs(fscp, &sap->sa_cid);
2135 out:
2136 	if (cr)
2137 		crfree(cr);
2138 	if (cvp)
2139 		VN_RELE(cvp);
2140 	return (error);
2141 }
2142 
2143 int
cachefs_io_setsecattr(vnode_t * vp,void * dinp,void * doutp)2144 cachefs_io_setsecattr(vnode_t *vp, void *dinp, void *doutp)
2145 {
2146 	int error = 0;
2147 	fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
2148 	vnode_t *tvp = NULL;
2149 	vsecattr_t vsec;
2150 	vattr_t va;
2151 	cred_t *cr = NULL;
2152 	fid_t	*tmpfidp;
2153 	cachefsio_setsecattr_arg_t *ssap;
2154 	cachefsio_setsecattr_return_t *retp;
2155 	CACHEFS_DECL(fid_t, tmpfid);
2156 
2157 	/*
2158 	 * Only called in support of disconnectable operation, so assert
2159 	 * that this is not called when NFSv4 is the backfilesytem.
2160 	 */
2161 	ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
2162 
2163 	ssap = (cachefsio_setsecattr_arg_t *)dinp;
2164 	retp = (cachefsio_setsecattr_return_t *)doutp;
2165 
2166 	/* get vnode of back file to do VOP_SETSECATTR to */
2167 	CACHEFS_TMPPTR_SET(&ssap->sc_backfid, &tmpfid, tmpfidp, fid_t);
2168 	CACHEFS_FID_COPYIN(&ssap->sc_backfid, tmpfidp);
2169 	error = VFS_VGET(fscp->fs_backvfsp, &tvp, tmpfidp);
2170 	if (error != 0) {
2171 		tvp = NULL;
2172 		goto out;
2173 	}
2174 
2175 	/* get the creds */
2176 	cr = conj_cred(&ssap->sc_cred);
2177 
2178 	/* form the vsecattr_t */
2179 	vsec.vsa_mask = ssap->sc_mask;
2180 	vsec.vsa_aclcnt = ssap->sc_aclcnt;
2181 	vsec.vsa_dfaclcnt = ssap->sc_dfaclcnt;
2182 	vsec.vsa_aclentp = ssap->sc_acl;
2183 	vsec.vsa_dfaclentp = ssap->sc_acl + ssap->sc_aclcnt;
2184 
2185 	/* set the ACL */
2186 	(void) VOP_RWLOCK(tvp, V_WRITELOCK_TRUE, NULL);
2187 	error = VOP_SETSECATTR(tvp, &vsec, 0, cr, NULL);
2188 	VOP_RWUNLOCK(tvp, V_WRITELOCK_TRUE, NULL);
2189 	if (error != 0)
2190 		goto out;
2191 
2192 	/* get the new ctime and mtime */
2193 	va.va_mask = AT_ALL;
2194 	error = VOP_GETATTR(tvp, &va, 0, cr, NULL);
2195 	if (error)
2196 		goto out;
2197 	CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->sc_ctime, error);
2198 	CACHEFS_TS_TO_CFS_TS_COPY(&va.va_mtime, &retp->sc_mtime, error);
2199 	if (error)
2200 		goto out;
2201 
2202 	cachefs_iosetneedattrs(fscp, &ssap->sc_cid);
2203 out:
2204 
2205 	if (cr != NULL)
2206 		crfree(cr);
2207 	if (tvp != NULL)
2208 		VN_RELE(tvp);
2209 
2210 	return (error);
2211 }
2212 
2213 static void
sync_metadata(cnode_t * cp)2214 sync_metadata(cnode_t *cp)
2215 {
2216 	if (cp->c_flags & (CN_STALE | CN_DESTROY))
2217 		return;
2218 	(void) cachefs_sync_metadata(cp);
2219 }
2220 
2221 static void
drop_backvp(cnode_t * cp)2222 drop_backvp(cnode_t *cp)
2223 {
2224 	if (cp->c_backvp) {
2225 		mutex_enter(&cp->c_statelock);
2226 		if (cp->c_backvp) {
2227 			/* dump any pages, may be a dirty one */
2228 			(void) VOP_PUTPAGE(cp->c_backvp, (offset_t)0, 0,
2229 			    B_INVAL | B_TRUNC, kcred, NULL);
2230 		}
2231 		mutex_exit(&cp->c_statelock);
2232 	}
2233 }
2234 
2235 static void
allow_pendrm(cnode_t * cp)2236 allow_pendrm(cnode_t *cp)
2237 {
2238 	if (cp->c_flags & CN_PENDRM) {
2239 		mutex_enter(&cp->c_statelock);
2240 		if (cp->c_flags & CN_PENDRM) {
2241 			cp->c_flags &= ~CN_PENDRM;
2242 			VN_RELE(CTOV(cp));
2243 		}
2244 		mutex_exit(&cp->c_statelock);
2245 	}
2246 }
2247 
2248 static void
cachefs_modified_fix(fscache_t * fscp)2249 cachefs_modified_fix(fscache_t *fscp)
2250 {
2251 	cnode_t *cp;
2252 	int error = 0;
2253 	rl_entry_t rl_ent;
2254 	cfs_cid_t cid;
2255 	cachefscache_t *cachep = fscp->fs_cache;
2256 	enum cachefs_rl_type type;
2257 	cachefs_metadata_t *mdp;
2258 	int timedout = 0;
2259 	struct vattr va;
2260 
2261 	/* XXX just return if fs is in error ro mode */
2262 
2263 	/* lock out other users of the MF list */
2264 	mutex_enter(&cachep->c_mflock);
2265 
2266 	/* move the modified entries for this file system to the MF list */
2267 	cachefs_move_modified_to_mf(cachep, fscp);
2268 
2269 	rl_ent.rl_current = CACHEFS_RL_MF;
2270 	for (;;) {
2271 		/* get the next entry on the MF list */
2272 		error = cachefs_rlent_data(cachep, &rl_ent, NULL);
2273 		if (error) {
2274 			error = 0;
2275 			break;
2276 		}
2277 		ASSERT(fscp->fs_cfsid == rl_ent.rl_fsid);
2278 
2279 		/* get the cnode for the file */
2280 		cid.cid_fileno = rl_ent.rl_fileno;
2281 		cid.cid_flags = rl_ent.rl_local ? CFS_CID_LOCAL : 0;
2282 		error = cachefs_cnode_make(&cid, fscp,
2283 		    NULL, NULL, NULL, kcred, 0, &cp);
2284 		if (error) {
2285 #ifdef CFSDEBUG
2286 			CFS_DEBUG(CFSDEBUG_IOCTL)
2287 				printf("cachefs: mf: could not find %llu\n",
2288 				    (u_longlong_t)cid.cid_fileno);
2289 			delay(5*hz);
2290 #endif
2291 			/* XXX this will loop forever, maybe put fs in */
2292 			/*   ro mode */
2293 			continue;
2294 		}
2295 
2296 		mutex_enter(&cp->c_statelock);
2297 
2298 		mdp = &cp->c_metadata;
2299 
2300 		/* if a regular file that has not been pushed */
2301 		if ((cp->c_attr.va_type == VREG) &&
2302 		    (((mdp->md_flags & (MD_PUSHDONE | MD_PUTPAGE)) ==
2303 		    MD_PUTPAGE))) {
2304 			/* move the file to lost+found */
2305 			error = cachefs_cnode_lostfound(cp, NULL);
2306 			if (error) {
2307 				/* XXX put fs in ro mode */
2308 				/* XXX need to drain MF list */
2309 				panic("lostfound failed %d", error);
2310 			}
2311 			mutex_exit(&cp->c_statelock);
2312 			VN_RELE(CTOV(cp));
2313 			continue;
2314 		}
2315 
2316 		/* if a local file */
2317 		if (cp->c_id.cid_flags & CFS_CID_LOCAL) {
2318 			/* if the file was not created */
2319 			if ((cp->c_metadata.md_flags & MD_CREATEDONE) == 0) {
2320 				/* do not allow cnode to be used */
2321 				cachefs_cnode_stale(cp);
2322 				mutex_exit(&cp->c_statelock);
2323 				VN_RELE(CTOV(cp));
2324 				continue;
2325 			}
2326 
2327 			/* save the local fileno for later getattrs */
2328 			mdp->md_localfileno = cp->c_id.cid_fileno;
2329 			mutex_exit(&cp->c_statelock);
2330 
2331 			/* register the mapping from old to new fileno */
2332 			mutex_enter(&fscp->fs_fslock);
2333 			cachefs_inum_register(fscp, cp->c_attr.va_nodeid,
2334 			    mdp->md_localfileno);
2335 			cachefs_inum_register(fscp, mdp->md_localfileno, 0);
2336 			mutex_exit(&fscp->fs_fslock);
2337 
2338 			/* move to new location in the cache */
2339 			cachefs_cnode_move(cp);
2340 			mutex_enter(&cp->c_statelock);
2341 		}
2342 
2343 		/* else if a modified file that needs to have its mode fixed */
2344 		else if ((cp->c_metadata.md_flags & MD_FILE) &&
2345 		    (cp->c_attr.va_type == VREG)) {
2346 
2347 			if (cp->c_frontvp == NULL)
2348 				(void) cachefs_getfrontfile(cp);
2349 			if (cp->c_frontvp) {
2350 				/* mark file as no longer modified */
2351 				va.va_mode = 0666;
2352 				va.va_mask = AT_MODE;
2353 				error = VOP_SETATTR(cp->c_frontvp, &va,
2354 				    0, kcred, NULL);
2355 				if (error) {
2356 					cmn_err(CE_WARN,
2357 					    "Cannot change ff mode.\n");
2358 				}
2359 			}
2360 		}
2361 
2362 
2363 		/* if there is a rl entry, put it on the correct list */
2364 		if (mdp->md_rlno) {
2365 			if (mdp->md_flags & MD_PACKED) {
2366 				if ((mdp->md_flags & MD_POPULATED) ||
2367 				    ((mdp->md_flags & MD_FILE) == 0))
2368 					type = CACHEFS_RL_PACKED;
2369 				else
2370 					type = CACHEFS_RL_PACKED_PENDING;
2371 				cachefs_rlent_moveto(fscp->fs_cache, type,
2372 				    mdp->md_rlno, mdp->md_frontblks);
2373 				mdp->md_rltype = type;
2374 			} else if (mdp->md_flags & MD_FILE) {
2375 				type = CACHEFS_RL_ACTIVE;
2376 				cachefs_rlent_moveto(fscp->fs_cache, type,
2377 				    mdp->md_rlno, mdp->md_frontblks);
2378 				mdp->md_rltype = type;
2379 			} else {
2380 				type = CACHEFS_RL_FREE;
2381 				cachefs_rlent_moveto(fscp->fs_cache, type,
2382 				    mdp->md_rlno, 0);
2383 				filegrp_ffrele(cp->c_filegrp);
2384 				mdp->md_rlno = 0;
2385 				mdp->md_rltype = CACHEFS_RL_NONE;
2386 			}
2387 		}
2388 		mdp->md_flags &= ~(MD_CREATEDONE | MD_PUTPAGE |
2389 		    MD_PUSHDONE | MD_MAPPING);
2390 
2391 		/* if a directory, populate it */
2392 		if (CTOV(cp)->v_type == VDIR) {
2393 			/* XXX hack for now */
2394 			mdp->md_flags |= MD_INVALREADDIR;
2395 			dnlc_purge_vp(CTOV(cp));
2396 
2397 			mdp->md_flags |= MD_NEEDATTRS;
2398 		}
2399 
2400 		if (!timedout) {
2401 			error = CFSOP_CHECK_COBJECT(fscp, cp, 0, kcred);
2402 			if (CFS_TIMEOUT(fscp, error))
2403 				timedout = 1;
2404 			else if ((error == 0) &&
2405 			    ((fscp->fs_info.fi_mntflags & CFS_NOACL) == 0)) {
2406 				if (cachefs_vtype_aclok(CTOV(cp)) &&
2407 				    ((cp->c_flags & CN_NOCACHE) == 0))
2408 					(void) cachefs_cacheacl(cp, NULL);
2409 			}
2410 		}
2411 
2412 		cp->c_flags |= CN_UPDATED;
2413 		mutex_exit(&cp->c_statelock);
2414 		VN_RELE(CTOV(cp));
2415 	}
2416 	mutex_exit(&cachep->c_mflock);
2417 }
2418 
2419 void
cachefs_inum_register(fscache_t * fscp,ino64_t real,ino64_t fake)2420 cachefs_inum_register(fscache_t *fscp, ino64_t real, ino64_t fake)
2421 {
2422 	cachefs_inum_trans_t *tbl;
2423 	int toff, thop;
2424 	int i;
2425 
2426 	ASSERT(MUTEX_HELD(&fscp->fs_fslock));
2427 
2428 	/*
2429 	 * first, see if an empty slot exists.
2430 	 */
2431 
2432 	for (i = 0; i < fscp->fs_inum_size; i++)
2433 		if (fscp->fs_inum_trans[i].cit_real == 0)
2434 			break;
2435 
2436 	/*
2437 	 * if there are no empty slots, try to grow the table.
2438 	 */
2439 
2440 	if (i >= fscp->fs_inum_size) {
2441 		cachefs_inum_trans_t *oldtbl;
2442 		int oldsize, newsize = 0;
2443 
2444 		/*
2445 		 * try to fetch a new table size that's bigger than
2446 		 * our current size
2447 		 */
2448 
2449 		for (i = 0; cachefs_hash_sizes[i] != 0; i++)
2450 			if (cachefs_hash_sizes[i] > fscp->fs_inum_size) {
2451 				newsize = cachefs_hash_sizes[i];
2452 				break;
2453 			}
2454 
2455 		/*
2456 		 * if we're out of larger twin-primes, give up.  thus,
2457 		 * the inode numbers in some directory entries might
2458 		 * change at reconnect, and disagree with what stat()
2459 		 * says.  this isn't worth panicing over, but it does
2460 		 * merit a warning message.
2461 		 */
2462 		if (newsize == 0) {
2463 			/* only print hash table warning once */
2464 			if ((fscp->fs_flags & CFS_FS_HASHPRINT) == 0) {
2465 				cmn_err(CE_WARN,
2466 				    "cachefs: inode hash table full\n");
2467 				fscp->fs_flags |= CFS_FS_HASHPRINT;
2468 			}
2469 			return;
2470 		}
2471 
2472 		/* set up this fscp with a new hash table */
2473 
2474 		oldtbl = fscp->fs_inum_trans;
2475 		oldsize = fscp->fs_inum_size;
2476 		fscp->fs_inum_size = newsize;
2477 		fscp->fs_inum_trans = (cachefs_inum_trans_t *)
2478 		    cachefs_kmem_zalloc(sizeof (cachefs_inum_trans_t) * newsize,
2479 			KM_SLEEP);
2480 
2481 		/*
2482 		 * re-insert all of the old values.  this will never
2483 		 * go more than one level into recursion-land.
2484 		 */
2485 
2486 		for (i = 0; i < oldsize; i++) {
2487 			tbl = oldtbl + i;
2488 			if (tbl->cit_real != 0) {
2489 				cachefs_inum_register(fscp, tbl->cit_real,
2490 				    tbl->cit_fake);
2491 			} else {
2492 				ASSERT(0);
2493 			}
2494 		}
2495 
2496 		if (oldsize > 0)
2497 			cachefs_kmem_free(oldtbl, oldsize *
2498 			    sizeof (cachefs_inum_trans_t));
2499 	}
2500 
2501 	/*
2502 	 * compute values for the hash table.  see ken rosen's
2503 	 * `elementary number theory and its applications' for one
2504 	 * description of double hashing.
2505 	 */
2506 
2507 	toff = (int)(real % fscp->fs_inum_size);
2508 	thop = (int)(real % (fscp->fs_inum_size - 2)) + 1;
2509 
2510 	/*
2511 	 * since we know the hash table isn't full when we get here,
2512 	 * this loop shouldn't terminate except via the `break'.
2513 	 */
2514 
2515 	for (i = 0; i < fscp->fs_inum_size; i++) {
2516 		tbl = fscp->fs_inum_trans + toff;
2517 		if ((tbl->cit_real == 0) || (tbl->cit_real == real)) {
2518 			tbl->cit_real = real;
2519 			tbl->cit_fake = fake;
2520 			break;
2521 		}
2522 
2523 		toff += thop;
2524 		toff %= fscp->fs_inum_size;
2525 	}
2526 	ASSERT(i < fscp->fs_inum_size);
2527 }
2528 
2529 /*
2530  * given an inode number, map it to the inode number that should be
2531  * put in a directory entry before its copied out.
2532  *
2533  * don't call this function unless there is a fscp->fs_inum_trans
2534  * table that has real entries in it!
2535  */
2536 
2537 ino64_t
cachefs_inum_real2fake(fscache_t * fscp,ino64_t real)2538 cachefs_inum_real2fake(fscache_t *fscp, ino64_t real)
2539 {
2540 	cachefs_inum_trans_t *tbl;
2541 	ino64_t rc = real;
2542 	int toff, thop;
2543 	int i;
2544 
2545 	ASSERT(fscp->fs_inum_size > 0);
2546 	ASSERT(MUTEX_HELD(&fscp->fs_fslock));
2547 
2548 	toff = (int)(real % fscp->fs_inum_size);
2549 	thop = (int)(real % (fscp->fs_inum_size - 2)) + 1;
2550 
2551 	for (i = 0; i < fscp->fs_inum_size; i++) {
2552 		tbl = fscp->fs_inum_trans + toff;
2553 
2554 		if (tbl->cit_real == 0) {
2555 			break;
2556 		} else if (tbl->cit_real == real) {
2557 			rc = tbl->cit_fake;
2558 			break;
2559 		}
2560 
2561 		toff += thop;
2562 		toff %= fscp->fs_inum_size;
2563 	}
2564 
2565 	return (rc);
2566 }
2567 
2568 /*
2569  * Passed a cid, finds the cnode and sets the MD_NEEDATTRS bit
2570  * in the metadata.
2571  */
2572 static void
cachefs_iosetneedattrs(fscache_t * fscp,cfs_cid_t * cidp)2573 cachefs_iosetneedattrs(fscache_t *fscp, cfs_cid_t *cidp)
2574 {
2575 	int error;
2576 	cnode_t *cp;
2577 
2578 	error = cachefs_cnode_make(cidp, fscp,
2579 	    NULL, NULL, NULL, kcred, 0, &cp);
2580 	if (error)
2581 		return;
2582 
2583 	mutex_enter(&cp->c_statelock);
2584 	cp->c_metadata.md_flags |= MD_NEEDATTRS;
2585 	cp->c_flags |= CN_UPDATED;
2586 	mutex_exit(&cp->c_statelock);
2587 
2588 	VN_RELE(CTOV(cp));
2589 }
2590