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