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