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