1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 #include <sys/param.h>
29 #include <sys/types.h>
30 #include <sys/systm.h>
31 #include <sys/cred.h>
32 #include <sys/proc.h>
33 #include <sys/user.h>
34 #include <sys/time.h>
35 #include <sys/vnode.h>
36 #include <sys/vfs.h>
37 #include <sys/file.h>
38 #include <sys/filio.h>
39 #include <sys/uio.h>
40 #include <sys/buf.h>
41 #include <sys/mman.h>
42 #include <sys/tiuser.h>
43 #include <sys/pathname.h>
44 #include <sys/dirent.h>
45 #include <sys/conf.h>
46 #include <sys/debug.h>
47 #include <sys/vmsystm.h>
48 #include <sys/fcntl.h>
49 #include <sys/flock.h>
50 #include <sys/swap.h>
51 #include <sys/errno.h>
52 #include <sys/sysmacros.h>
53 #include <sys/disp.h>
54 #include <sys/kmem.h>
55 #include <sys/cmn_err.h>
56 #include <sys/vtrace.h>
57 #include <sys/mount.h>
58 #include <sys/bootconf.h>
59 #include <sys/dnlc.h>
60 #include <sys/stat.h>
61
62 #include <vm/hat.h>
63 #include <vm/as.h>
64 #include <vm/page.h>
65 #include <vm/pvn.h>
66 #include <vm/seg.h>
67 #include <vm/seg_map.h>
68 #include <vm/seg_vn.h>
69 #include <vm/rm.h>
70 #include <sys/fs/cachefs_fs.h>
71 #include <sys/fs/cachefs_dlog.h>
72 #include <fs/fs_subr.h>
73
74 static int cachefs_dlog_mapreserve(fscache_t *fscp, int size);
75
76 #ifdef _LP64
77
78 static void cachefs_dlog_attrchk(vattr_t *vap, char *funcname);
79
80 #define CACHEFS_DLOG_TS_COPY(in_tsp, out_tsp, str, str1) \
81 { \
82 int ovferr = 0; \
83 CACHEFS_TS_TO_CFS_TS_COPY(in_tsp, out_tsp, ovferr); \
84 if (ovferr) \
85 cmn_err(CE_WARN, "%s%s overflow", str, str1); \
86 }
87
88 #define CACHEFS_DLOG_DEV_COPY(in_dev, out_dev, str, str1) \
89 { \
90 int ovferr = 0; \
91 CACHEFS_DEV_TO_CFS_DEV_COPY(in_dev, out_dev, ovferr); \
92 if (ovferr) \
93 cmn_err(CE_WARN, "%s%s 0x%lx -> 0x%x overflow", \
94 str, str1, in_dev, (dev32_t)(out_dev)); \
95 }
96
97 #define CACHEFS_DLOG_VATTR_COPY(in_vap, out_vap, str) \
98 { \
99 int ovferr = 0; \
100 CACHEFS_VATTR_TO_CFS_VATTR_COPY(in_vap, out_vap, ovferr); \
101 if (ovferr) \
102 cachefs_dlog_attrchk(in_vap, str); \
103 }
104
105 /*
106 * check attr error - if we get an overflow error copying vattr, make sure
107 * the field affected is actually wanted, or it might be junk
108 */
109 static void
cachefs_dlog_attrchk(vattr_t * vap,char * str)110 cachefs_dlog_attrchk(vattr_t *vap, char *str)
111 {
112 dev_t tmpdev;
113 cfs_timestruc_t ts;
114
115 if (vap->va_mask & AT_FSID) {
116 CACHEFS_DLOG_DEV_COPY(vap->va_fsid, tmpdev, str, ".va_fsid");
117 }
118 if (vap->va_mask & AT_RDEV) {
119 CACHEFS_DLOG_DEV_COPY(vap->va_rdev, tmpdev, str, ".va_rdev");
120 }
121 if (vap->va_mask & AT_MTIME) {
122 CACHEFS_DLOG_TS_COPY(&vap->va_mtime, &ts, str, ".va_mtime");
123 }
124 if (vap->va_mask & AT_ATIME) {
125 CACHEFS_DLOG_TS_COPY(&vap->va_atime, &ts, str, ".va_atime");
126 }
127 if (vap->va_mask & AT_CTIME) {
128 CACHEFS_DLOG_TS_COPY(&vap->va_ctime, &ts, str, ".va_ctime");
129 }
130 }
131
132 #else /* not _LP64 */
133
134 #define CACHEFS_DLOG_TS_COPY(in_tsp, out_tsp, str, str1) \
135 CACHEFS_TS_TO_CFS_TS_COPY(in_tsp, out_tsp, error)
136
137 #define CACHEFS_DLOG_DEV_COPY(in_dev, out_dev, str, str1) \
138 CACHEFS_DEV_TO_CFS_DEV_COPY(in_dev, out_dev, error)
139
140 #define CACHEFS_DLOG_VATTR_COPY(in_vap, out_vap, str) \
141 CACHEFS_VATTR_TO_CFS_VATTR_COPY(in_vap, out_vap, error)
142
143 #endif /* _LP64 */
144
145 /*
146 *
147 * Cachefs used to know too much about how creds looked; since it's
148 * committed to persistent storage, we can't change the layout so
149 * it now has a "dl_cred_t" which (unsurprisingly) looks exactly like
150 * an old credential.
151 *
152 * The dst argument needs to point to:
153 * struct dl_cred_t;
154 * <buffer space> buffer for groups
155 *
156 * The source is a proper kernel cred_t.
157 *
158 */
159 static size_t
copy_cred(cred_t * src,dl_cred_t * dst)160 copy_cred(cred_t *src, dl_cred_t *dst)
161 {
162 int n;
163 const gid_t *sgrp = crgetgroups(src);
164
165 n = MIN(NGROUPS_MAX_DEFAULT, crgetngroups(src));
166
167 /* copy the fixed fields */
168 dst->cr_uid = crgetuid(src);
169 dst->cr_ruid = crgetruid(src);
170 dst->cr_suid = crgetsuid(src);
171 dst->cr_gid = crgetgid(src);
172 dst->cr_rgid = crgetrgid(src);
173 dst->cr_sgid = crgetsgid(src);
174 dst->cr_groups[0] = sgrp[0];
175
176 dst->cr_ngroups = n;
177 bcopy(sgrp, (void *)(dst + 1), (n - 1) * sizeof (gid_t));
178 return (sizeof (dl_cred_t) + (n - 1) * sizeof (gid_t));
179 }
180
181 /*
182 * Sets up for writing to the log files.
183 */
184 int
cachefs_dlog_setup(fscache_t * fscp,int createfile)185 cachefs_dlog_setup(fscache_t *fscp, int createfile)
186 {
187 struct vattr vattr;
188 int error = 0;
189 int createdone = 0;
190 int lookupdone = 0;
191 int version = CFS_DLOG_VERSION;
192 off_t offset;
193 struct cfs_dlog_trailer trailer;
194
195 mutex_enter(&fscp->fs_dlock);
196
197 /* all done if the log files already exist */
198 if (fscp->fs_dlogfile) {
199 ASSERT(fscp->fs_dmapfile);
200 goto out;
201 }
202
203 /* see if the log file exists */
204 error = VOP_LOOKUP(fscp->fs_fscdirvp, CACHEFS_DLOG_FILE,
205 &fscp->fs_dlogfile, NULL, 0, NULL, kcred, NULL, NULL, NULL);
206 if (error && (createfile == 0))
207 goto out;
208
209 /* if the lookup failed then create file log files */
210 if (error) {
211 createdone++;
212
213 vattr.va_mode = S_IFREG | 0666;
214 vattr.va_uid = 0;
215 vattr.va_gid = 0;
216 vattr.va_type = VREG;
217 vattr.va_mask = AT_TYPE|AT_MODE|AT_UID|AT_GID;
218 error = VOP_CREATE(fscp->fs_fscdirvp, CACHEFS_DLOG_FILE,
219 &vattr, 0, 0666, &fscp->fs_dlogfile, kcred, 0, NULL, NULL);
220 if (error) {
221 #ifdef CFSDEBUG
222 CFS_DEBUG(CFSDEBUG_DLOG)
223 printf("cachefs: log file create fail %d\n",
224 error);
225 #endif
226 goto out;
227 }
228
229 /* write the version number into the log file */
230 error = vn_rdwr(UIO_WRITE, fscp->fs_dlogfile, (caddr_t)&version,
231 sizeof (version), (offset_t)0, UIO_SYSSPACE, FSYNC,
232 RLIM_INFINITY, kcred, NULL);
233 if (error) {
234 #ifdef CFSDEBUG
235 CFS_DEBUG(CFSDEBUG_DLOG)
236 printf("cachefs: log file init fail %d\n",
237 error);
238 #endif
239 goto out;
240 }
241
242 vattr.va_mode = S_IFREG | 0666;
243 vattr.va_uid = 0;
244 vattr.va_gid = 0;
245 vattr.va_type = VREG;
246 vattr.va_mask = AT_TYPE|AT_MODE|AT_UID|AT_GID;
247 error = VOP_CREATE(fscp->fs_fscdirvp, CACHEFS_DMAP_FILE,
248 &vattr, 0, 0666, &fscp->fs_dmapfile, kcred, 0, NULL, NULL);
249 if (error) {
250 #ifdef CFSDEBUG
251 CFS_DEBUG(CFSDEBUG_DLOG)
252 printf("cachefs: map file create fail %d\n",
253 error);
254 #endif
255 goto out;
256 }
257
258 fscp->fs_dlogoff = sizeof (version);
259 fscp->fs_dlogseq = 0;
260 fscp->fs_dmapoff = 0;
261 fscp->fs_dmapsize = 0;
262 }
263
264 /*
265 * Else the lookup succeeded.
266 * Before mounting, fsck should have fixed any problems
267 * in the log file.
268 */
269 else {
270 lookupdone++;
271
272 /* find the end of the log file */
273 vattr.va_mask = AT_ALL;
274 error = VOP_GETATTR(fscp->fs_dlogfile, &vattr, 0, kcred, NULL);
275 if (error) {
276 #ifdef CFSDEBUG
277 CFS_DEBUG(CFSDEBUG_DLOG)
278 printf("cachefs: log file getattr fail %d\n",
279 error);
280 #endif
281 goto out;
282 }
283 /*LINTED alignment okay*/
284 ASSERT(vattr.va_size <= MAXOFF_T);
285 fscp->fs_dlogoff = (off_t)vattr.va_size;
286
287 offset = vattr.va_size - sizeof (struct cfs_dlog_trailer);
288 /*
289 * The last record in the dlog file is a trailer record
290 * that contains the last sequence number used. This is
291 * used to reset the sequence number when a logfile already
292 * exists.
293 */
294 error = vn_rdwr(UIO_READ, fscp->fs_dlogfile, (caddr_t)&trailer,
295 sizeof (struct cfs_dlog_trailer), (offset_t)offset,
296 UIO_SYSSPACE, FSYNC, RLIM_INFINITY, kcred, NULL);
297 if (error == 0) {
298 if (trailer.dl_op == CFS_DLOG_TRAILER) {
299 fscp->fs_dlogseq = trailer.dl_seq;
300 /*
301 * Set the offset of the next record to be
302 * written, to over write the current
303 * trailer.
304 */
305 fscp->fs_dlogoff = offset;
306 } else {
307 #ifdef CFSDEBUG
308 CFS_DEBUG(CFSDEBUG_DLOG) {
309 cmn_err(CE_WARN,
310 "cachefs: can't find dlog trailer");
311 cmn_err(CE_WARN,
312 "cachefs: fsck required");
313 }
314 #endif /* CFSDEBUG */
315 /*LINTED alignment okay*/
316 fscp->fs_dlogseq = (uint_t)vattr.va_size;
317 }
318 } else {
319 #ifdef CFSDEBUG
320 CFS_DEBUG(CFSDEBUG_DLOG)
321 cmn_err(CE_WARN,
322 "cachefs: error reading dlog trailer");
323 #endif /* CFSDEBUG */
324 /*LINTED alignment okay*/
325 fscp->fs_dlogseq = (uint_t)vattr.va_size;
326 }
327
328
329 error = VOP_LOOKUP(fscp->fs_fscdirvp, CACHEFS_DMAP_FILE,
330 &fscp->fs_dmapfile, NULL, 0, NULL, kcred, NULL, NULL, NULL);
331 if (error) {
332 #ifdef CFSDEBUG
333 CFS_DEBUG(CFSDEBUG_DLOG)
334 printf("cachefs: map file lookup fail %d\n",
335 error);
336 #endif
337 goto out;
338 }
339
340 vattr.va_mask = AT_ALL;
341 error = VOP_GETATTR(fscp->fs_dmapfile, &vattr, 0, kcred, NULL);
342 if (error) {
343 #ifdef CFSDEBUG
344 CFS_DEBUG(CFSDEBUG_DLOG)
345 printf("cachefs: map file getattr fail %d\n",
346 error);
347 #endif
348 goto out;
349 }
350 fscp->fs_dmapoff = (off_t)vattr.va_size;
351 fscp->fs_dmapsize = (off_t)vattr.va_size;
352 }
353
354 out:
355 if (error) {
356 if (createdone) {
357 if (fscp->fs_dlogfile) {
358 VN_RELE(fscp->fs_dlogfile);
359 fscp->fs_dlogfile = NULL;
360 (void) VOP_REMOVE(fscp->fs_fscdirvp,
361 CACHEFS_DLOG_FILE, kcred, NULL, 0);
362 }
363 if (fscp->fs_dmapfile) {
364 VN_RELE(fscp->fs_dmapfile);
365 fscp->fs_dmapfile = NULL;
366 (void) VOP_REMOVE(fscp->fs_fscdirvp,
367 CACHEFS_DMAP_FILE, kcred, NULL, 0);
368 }
369 }
370 if (lookupdone) {
371 if (fscp->fs_dlogfile) {
372 VN_RELE(fscp->fs_dlogfile);
373 fscp->fs_dlogfile = NULL;
374 }
375 if (fscp->fs_dmapfile) {
376 VN_RELE(fscp->fs_dmapfile);
377 fscp->fs_dmapfile = NULL;
378 }
379 }
380 }
381
382 mutex_exit(&fscp->fs_dlock);
383 return (error);
384 }
385
386 /*
387 * Drops reference to the log file.
388 */
389 void
cachefs_dlog_teardown(fscache_t * fscp)390 cachefs_dlog_teardown(fscache_t *fscp)
391 {
392 vattr_t va;
393 /*LINTED: set but not used */
394 int error;
395
396 mutex_enter(&fscp->fs_dlock);
397
398 /* clean up the log file */
399 if (fscp->fs_dlogfile) {
400 VN_RELE(fscp->fs_dlogfile);
401 fscp->fs_dlogfile = NULL;
402 }
403
404 /* clean up the map file */
405 if (fscp->fs_dmapfile) {
406 /* set the map file to the actual size needed */
407 va.va_mask = AT_SIZE;
408 va.va_size = fscp->fs_dmapoff;
409 error = VOP_SETATTR(fscp->fs_dmapfile, &va, 0, kcred, NULL);
410 #ifdef CFSDEBUG
411 if (error) {
412 cmn_err(CE_WARN, "cachefs: map setattr failed %d",
413 error);
414 }
415 #endif
416 VN_RELE(fscp->fs_dmapfile);
417 fscp->fs_dmapfile = NULL;
418 }
419 mutex_exit(&fscp->fs_dlock);
420 }
421
422 /*
423 * Outputs a dlog message to the log file.
424 */
425 static off_t
cachefs_dlog_output(fscache_t * fscp,cfs_dlog_entry_t * entp,uint_t * seqp)426 cachefs_dlog_output(fscache_t *fscp, cfs_dlog_entry_t *entp, uint_t *seqp)
427 {
428 int error;
429 off_t offset;
430 int xx;
431 uint_t seq;
432 int len;
433 struct cfs_dlog_trailer *trail;
434
435 ASSERT(entp->dl_len <= CFS_DLOG_ENTRY_MAXSIZE);
436
437 if (fscp->fs_dlogfile == NULL) {
438 error = cachefs_dlog_setup(fscp, 1);
439 if (error) {
440 offset = 0;
441 goto out;
442 }
443 }
444
445 /* round up length to a 4 byte boundary */
446 len = entp->dl_len;
447 xx = len & 0x03;
448 if (xx) {
449 xx = 4 - xx;
450 bzero((void *)((uintptr_t)entp + len), (size_t)xx);
451 len += xx;
452 entp->dl_len = len;
453 }
454
455 /* XXX turn this on/off in sync with code in cachefs_dlog_setsecattr */
456 #if 0
457 /* XXX debugging hack, round up to 16 byte boundary */
458 len = entp->dl_len;
459 xx = 16 - (len & 0x0f);
460 bcopy("UUUUUUUUUUUUUUUU", (void *)((uintptr_t)entp + len), (size_t)xx);
461 len += xx;
462 entp->dl_len = len;
463 #endif
464
465 /*
466 * All functions which allocate a dlog entry buffer must be sure
467 * to allocate space for the trailer record. The trailer record,
468 * is always located at the end of the log file. It contains the
469 * highest sequence number used. This allows cachefs_dlog_setup()
470 * to reset the sequence numbers properly when the log file
471 * already exists.
472 */
473 trail = (struct cfs_dlog_trailer *)((uintptr_t)entp + entp->dl_len);
474 trail->dl_len = sizeof (struct cfs_dlog_trailer);
475 trail->dl_op = CFS_DLOG_TRAILER;
476 trail->dl_valid = CFS_DLOG_VAL_COMMITTED;
477 mutex_enter(&fscp->fs_dlock);
478 ASSERT(fscp->fs_dlogfile);
479
480 /* get a sequence number for this log entry */
481 seq = fscp->fs_dlogseq + 1;
482 if (seq == 0) {
483 mutex_exit(&fscp->fs_dlock);
484 offset = 0;
485 #ifdef CFSDEBUG
486 cmn_err(CE_WARN, "cachefs: logging failed, seq overflow");
487 #endif
488 goto out;
489 }
490 fscp->fs_dlogseq++;
491 trail->dl_seq = fscp->fs_dlogseq;
492
493 /* add the sequence number to the record */
494 entp->dl_seq = seq;
495
496 /* get offset into file to write record */
497 offset = fscp->fs_dlogoff;
498
499 /* try to write the record to the log file */
500 /*
501 * NOTE This write will over write the previous trailer record and
502 * will add a new trailer record. This is done with a single
503 * write for performance reasons.
504 */
505 error = vn_rdwr(UIO_WRITE, fscp->fs_dlogfile, (caddr_t)entp,
506 entp->dl_len+trail->dl_len, (offset_t)offset, UIO_SYSSPACE, FSYNC,
507 RLIM_INFINITY, kcred, NULL);
508
509 if (error) {
510 offset = 0;
511 cmn_err(CE_WARN, "cachefs: logging failed (%d)", error);
512 } else {
513 fscp->fs_dlogoff += entp->dl_len;
514
515 /* get offset of valid field */
516 offset += offsetof(struct cfs_dlog_entry, dl_valid);
517 }
518
519 mutex_exit(&fscp->fs_dlock);
520
521 /* return sequence number used if requested */
522 if (seqp)
523 *seqp = seq;
524
525 out:
526 return (offset);
527 }
528
529 /*
530 * Commits a previously written dlog message.
531 */
532 int
cachefs_dlog_commit(fscache_t * fscp,off_t offset,int error)533 cachefs_dlog_commit(fscache_t *fscp, off_t offset, int error)
534 {
535 cfs_dlog_val_t valid;
536
537 if (error)
538 valid = CFS_DLOG_VAL_ERROR;
539 else
540 valid = CFS_DLOG_VAL_COMMITTED;
541
542 error = vn_rdwr(UIO_WRITE, fscp->fs_dlogfile,
543 (caddr_t)&valid, sizeof (valid), (offset_t)offset,
544 UIO_SYSSPACE, FSYNC, RLIM_INFINITY, kcred, NULL);
545
546 if (error)
547 cmn_err(CE_WARN, "cachefs: logging commit failed (%d)", error);
548 return (error);
549 }
550
551 /*
552 * Reserves space in the map file.
553 */
554 static int
cachefs_dlog_mapreserve(fscache_t * fscp,int size)555 cachefs_dlog_mapreserve(fscache_t *fscp, int size)
556 {
557 int error = 0;
558 int len;
559 char *bufp;
560
561 if (fscp->fs_dmapfile == NULL) {
562 error = cachefs_dlog_setup(fscp, 1);
563 if (error) {
564 return (error);
565 }
566 }
567
568 mutex_enter(&fscp->fs_dlock);
569 ASSERT(fscp->fs_dmapoff <= fscp->fs_dmapsize);
570 ASSERT(fscp->fs_dmapfile);
571
572 if ((fscp->fs_dmapoff + size) > fscp->fs_dmapsize) {
573 /* reserve 20% for optimal hashing */
574 size += MAXBSIZE / 5;
575
576 /* grow file by a MAXBSIZE chunk */
577 len = MAXBSIZE;
578 ASSERT((fscp->fs_dmapoff + size) < (fscp->fs_dmapsize + len));
579
580 bufp = cachefs_kmem_zalloc(len, KM_SLEEP);
581 error = vn_rdwr(UIO_WRITE, fscp->fs_dmapfile, (caddr_t)bufp,
582 len, (offset_t)fscp->fs_dmapsize, UIO_SYSSPACE, FSYNC,
583 RLIM_INFINITY, kcred, NULL);
584 if (error == 0) {
585 fscp->fs_dmapoff += size;
586 fscp->fs_dmapsize += len;
587 } else {
588 cmn_err(CE_WARN, "cachefs: logging secondary "
589 "failed (%d)", error);
590 }
591 cachefs_kmem_free(bufp, len);
592 } else {
593 fscp->fs_dmapoff += size;
594 }
595 mutex_exit(&fscp->fs_dlock);
596 return (error);
597 }
598
599 /*
600 * Reserves space for one cid mapping in the mapping file.
601 */
602 int
cachefs_dlog_cidmap(fscache_t * fscp)603 cachefs_dlog_cidmap(fscache_t *fscp)
604 {
605 int error;
606 error = cachefs_dlog_mapreserve(fscp,
607 sizeof (struct cfs_dlog_mapping_space));
608 return (error);
609 }
610
611 off_t
cachefs_dlog_setattr(fscache_t * fscp,struct vattr * vap,int flags,cnode_t * cp,cred_t * cr)612 cachefs_dlog_setattr(fscache_t *fscp, struct vattr *vap, int flags,
613 cnode_t *cp, cred_t *cr)
614 {
615 struct cfs_dlog_entry *entp;
616 struct cfs_dlog_setattr *up;
617 size_t len;
618 off_t offset;
619
620 ASSERT(MUTEX_HELD(&cp->c_statelock));
621
622 entp = cachefs_kmem_alloc(sizeof (cfs_dlog_entry_t), KM_SLEEP);
623
624 entp->dl_valid = CFS_DLOG_VAL_CRASH;
625 entp->dl_op = CFS_DLOG_SETATTR;
626 up = &entp->dl_u.dl_setattr;
627 CACHEFS_DLOG_VATTR_COPY(vap, &up->dl_attrs,
628 "cachefs_dlog_setattr: dl_attr");
629 up->dl_flags = flags;
630 up->dl_cid = cp->c_id;
631 CACHEFS_DLOG_TS_COPY(&cp->c_metadata.md_vattr.va_mtime,
632 &up->dl_times.tm_mtime, "cachefs_dlog_setattr: ", "mtime");
633 CACHEFS_DLOG_TS_COPY(&cp->c_metadata.md_vattr.va_ctime,
634 &up->dl_times.tm_ctime, "cachefs_dlog_setattr: ", "ctime");
635
636 /* store the cred info */
637 len = copy_cred(cr, &up->dl_cred);
638
639 /* Calculate the length of this record */
640 entp->dl_len = (int)(((uintptr_t)&up->dl_cred + len) - (uintptr_t)entp);
641
642 /* write the record in the log */
643 offset = cachefs_dlog_output(fscp, entp, NULL);
644
645 cachefs_kmem_free(entp, sizeof (cfs_dlog_entry_t));
646 return (offset);
647 }
648
649 off_t
650 /*ARGSUSED*/
cachefs_dlog_setsecattr(fscache_t * fscp,vsecattr_t * vsec,int flags,cnode_t * cp,cred_t * cr)651 cachefs_dlog_setsecattr(fscache_t *fscp, vsecattr_t *vsec, int flags,
652 cnode_t *cp, cred_t *cr)
653 {
654 struct cfs_dlog_entry *entp;
655 struct cfs_dlog_setsecattr *up;
656 size_t alen, clen, len;
657 off_t offset = 0;
658 aclent_t *aclp;
659
660 ASSERT(MUTEX_HELD(&cp->c_statelock));
661
662 /* paranoia */
663 ASSERT((vsec->vsa_mask & VSA_ACL) || (vsec->vsa_aclcnt == 0));
664 ASSERT((vsec->vsa_mask & VSA_DFACL) || (vsec->vsa_dfaclcnt == 0));
665 if ((vsec->vsa_mask & VSA_ACL) == 0)
666 vsec->vsa_aclcnt = 0;
667 if ((vsec->vsa_mask & VSA_DFACL) == 0)
668 vsec->vsa_dfaclcnt = 0;
669
670 /* calculate length of ACL and cred data */
671 alen = sizeof (aclent_t) * (vsec->vsa_aclcnt + vsec->vsa_dfaclcnt);
672 clen = sizeof (dl_cred_t) + (((long)crgetngroups(cr)) * sizeof (gid_t));
673
674 /*
675 * allocate entry. ACLs may be up to 24k currently, but they
676 * usually won't, so we don't want to make cfs_dlog_entry_t
677 * too big. so, we must compute the length here.
678 */
679
680 len = sizeof (cfs_dlog_entry_t) - sizeof (up->dl_buffer) -
681 sizeof (up->dl_cred) + alen + clen;
682
683
684 #if 0
685 /* make up for weird behavior in cachefs_dlog_output */
686 /* XXX turn this on/off in sync with code in cachefs_dlog_output */
687 entp = cachefs_kmem_alloc(len + 32 + sizeof (struct cfs_dlog_trailer),
688 KM_SLEEP);
689 #else
690 entp = cachefs_kmem_alloc(len, KM_SLEEP);
691 #endif
692
693 entp->dl_valid = CFS_DLOG_VAL_CRASH;
694 entp->dl_op = CFS_DLOG_SETSECATTR;
695
696 up = &entp->dl_u.dl_setsecattr;
697 up->dl_cid = cp->c_id;
698
699 CACHEFS_DLOG_TS_COPY(&cp->c_metadata.md_vattr.va_mtime,
700 &up->dl_times.tm_mtime, "cachefs_dlog_setsecattr: ", "mtime");
701 CACHEFS_DLOG_TS_COPY(&cp->c_metadata.md_vattr.va_ctime,
702 &up->dl_times.tm_ctime, "cachefs_dlog_setsecattr: ", "ctime");
703
704 /* get the creds */
705 (void) copy_cred(cr, &up->dl_cred);
706
707 /* mask and counts */
708 up->dl_mask = vsec->vsa_mask;
709 up->dl_aclcnt = vsec->vsa_aclcnt;
710 up->dl_dfaclcnt = vsec->vsa_dfaclcnt;
711
712 /* get the acls themselves */
713 aclp = (aclent_t *)((uintptr_t)(&up->dl_cred) + clen);
714 if (vsec->vsa_aclcnt > 0) {
715 bcopy(vsec->vsa_aclentp, aclp,
716 vsec->vsa_aclcnt * sizeof (aclent_t));
717 aclp += vsec->vsa_aclcnt;
718 }
719 if (vsec->vsa_dfaclcnt > 0) {
720 bcopy(vsec->vsa_dfaclentp, aclp,
721 vsec->vsa_dfaclcnt * sizeof (aclent_t));
722 }
723
724 entp->dl_len = (int)len;
725
726 offset = cachefs_dlog_output(fscp, entp, NULL);
727
728 #if 0
729 /* XXX turn on/off in sync with code in cachefs_dlog_output */
730 cachefs_kmem_free(entp, len + 32 + sizeof (struct cfs_dlog_trailer));
731 #else
732 cachefs_kmem_free(entp, len);
733 #endif
734
735 return (offset);
736 }
737
738 off_t
cachefs_dlog_create(fscache_t * fscp,cnode_t * pcp,char * nm,vattr_t * vap,int excl,int mode,cnode_t * cp,int exists,cred_t * cr)739 cachefs_dlog_create(fscache_t *fscp, cnode_t *pcp, char *nm,
740 vattr_t *vap, int excl, int mode, cnode_t *cp, int exists, cred_t *cr)
741 {
742 struct cfs_dlog_entry *entp;
743 struct cfs_dlog_create *up;
744 size_t len;
745 caddr_t curp;
746 off_t offset;
747
748 ASSERT(MUTEX_HELD(&cp->c_statelock));
749
750 entp = cachefs_kmem_alloc(sizeof (cfs_dlog_entry_t), KM_SLEEP);
751
752 entp->dl_valid = CFS_DLOG_VAL_CRASH;
753 entp->dl_op = CFS_DLOG_CREATE;
754 up = &entp->dl_u.dl_create;
755 up->dl_parent_cid = pcp->c_id;
756 up->dl_new_cid = cp->c_id;
757 CACHEFS_DLOG_VATTR_COPY(vap, &up->dl_attrs,
758 "cachefs_dlog_create: dl_attr");
759 up->dl_excl = excl;
760 up->dl_mode = mode;
761 up->dl_exists = exists;
762 bzero(&up->dl_fid, sizeof (up->dl_fid));
763 if (exists) {
764 CACHEFS_DLOG_TS_COPY(&cp->c_metadata.md_vattr.va_mtime,
765 &up->dl_times.tm_mtime,
766 "cachefs_dlog_create: ", "mtime");
767 CACHEFS_DLOG_TS_COPY(&cp->c_metadata.md_vattr.va_ctime,
768 &up->dl_times.tm_ctime,
769 "cachefs_dlog_create: ", "ctime");
770 } else {
771 up->dl_times.tm_ctime.tv_sec = 0;
772 up->dl_times.tm_ctime.tv_nsec = 0;
773 up->dl_times.tm_mtime.tv_sec = 0;
774 up->dl_times.tm_mtime.tv_nsec = 0;
775 }
776
777 /* store the cred info */
778 len = copy_cred(cr, &up->dl_cred);
779
780 /* find the address in buffer past where the creds are stored */
781 curp = (caddr_t)(((uintptr_t)&up->dl_cred) + len);
782
783 /* store the created name */
784 len = strlen(nm) + 1;
785 bcopy(nm, curp, len);
786
787 /* calculate the length of this record */
788 entp->dl_len = (int)(((uintptr_t)curp + len) - (uintptr_t)entp);
789
790 /* write the record in the log */
791 offset = cachefs_dlog_output(fscp, entp, NULL);
792
793 cachefs_kmem_free(entp, sizeof (cfs_dlog_entry_t));
794 return (offset);
795 }
796
797 off_t
cachefs_dlog_remove(fscache_t * fscp,cnode_t * pcp,char * nm,cnode_t * cp,cred_t * cr)798 cachefs_dlog_remove(fscache_t *fscp, cnode_t *pcp, char *nm, cnode_t *cp,
799 cred_t *cr)
800 {
801 struct cfs_dlog_entry *entp;
802 struct cfs_dlog_remove *up;
803 size_t len;
804 caddr_t curp;
805 off_t offset;
806
807 entp = cachefs_kmem_alloc(sizeof (cfs_dlog_entry_t), KM_SLEEP);
808
809 entp->dl_valid = CFS_DLOG_VAL_CRASH;
810 entp->dl_op = CFS_DLOG_REMOVE;
811 up = &entp->dl_u.dl_remove;
812 up->dl_parent_cid = pcp->c_id;
813 up->dl_child_cid = cp->c_id;
814 CACHEFS_DLOG_TS_COPY(&cp->c_metadata.md_vattr.va_mtime,
815 &up->dl_times.tm_mtime, "cachefs_dlog_remove: ", "mtime");
816 CACHEFS_DLOG_TS_COPY(&cp->c_metadata.md_vattr.va_ctime,
817 &up->dl_times.tm_ctime, "cachefs_dlog_remove: ", "ctime");
818 /* store the cred info */
819 len = copy_cred(cr, &up->dl_cred);
820
821 /* find the address in buffer past where the creds are stored */
822 curp = (caddr_t)(((uintptr_t)&up->dl_cred) + len);
823
824 /* store the removed name */
825 len = strlen(nm) + 1;
826 bcopy(nm, curp, len);
827
828 /* calculate the length of this record */
829 entp->dl_len = (int)(((uintptr_t)curp + len) - (uintptr_t)entp);
830
831 /* write the record in the log */
832 offset = cachefs_dlog_output(fscp, entp, NULL);
833
834 cachefs_kmem_free(entp, sizeof (cfs_dlog_entry_t));
835 return (offset);
836 }
837
838 off_t
cachefs_dlog_link(fscache_t * fscp,cnode_t * pcp,char * nm,cnode_t * cp,cred_t * cr)839 cachefs_dlog_link(fscache_t *fscp, cnode_t *pcp, char *nm, cnode_t *cp,
840 cred_t *cr)
841 {
842 struct cfs_dlog_entry *entp;
843 struct cfs_dlog_link *up;
844 size_t len;
845 caddr_t curp;
846 off_t offset;
847
848 entp = cachefs_kmem_alloc(sizeof (cfs_dlog_entry_t), KM_SLEEP);
849
850 entp->dl_valid = CFS_DLOG_VAL_CRASH;
851 entp->dl_op = CFS_DLOG_LINK;
852 up = &entp->dl_u.dl_link;
853 up->dl_parent_cid = pcp->c_id;
854 up->dl_child_cid = cp->c_id;
855 CACHEFS_DLOG_TS_COPY(&cp->c_metadata.md_vattr.va_mtime,
856 &up->dl_times.tm_mtime, "cachefs_dlog_link: ", "mtime");
857 CACHEFS_DLOG_TS_COPY(&cp->c_metadata.md_vattr.va_ctime,
858 &up->dl_times.tm_ctime, "cachefs_dlog_link: ", "ctime");
859
860 /* store the cred info */
861 len = copy_cred(cr, &up->dl_cred);
862
863 /* find the address in buffer past where the creds are stored */
864 curp = (caddr_t)(((uintptr_t)&up->dl_cred) + len);
865
866 /* store the link name */
867 len = strlen(nm) + 1;
868 bcopy(nm, curp, len);
869
870 /* calculate the length of this record */
871 entp->dl_len = (int)(((uintptr_t)curp + len) - (uintptr_t)entp);
872
873 /* write the record in the log */
874 offset = cachefs_dlog_output(fscp, entp, NULL);
875
876 cachefs_kmem_free(entp, sizeof (cfs_dlog_entry_t));
877 return (offset);
878 }
879
880 off_t
cachefs_dlog_rename(fscache_t * fscp,cnode_t * odcp,char * onm,cnode_t * ndcp,char * nnm,cred_t * cr,cnode_t * cp,cnode_t * delcp)881 cachefs_dlog_rename(fscache_t *fscp, cnode_t *odcp, char *onm, cnode_t *ndcp,
882 char *nnm, cred_t *cr, cnode_t *cp, cnode_t *delcp)
883 {
884 struct cfs_dlog_entry *entp;
885 struct cfs_dlog_rename *up;
886 size_t len;
887 caddr_t curp;
888 off_t offset;
889
890 entp = cachefs_kmem_alloc(sizeof (cfs_dlog_entry_t), KM_SLEEP);
891
892 entp->dl_valid = CFS_DLOG_VAL_CRASH;
893 entp->dl_op = CFS_DLOG_RENAME;
894 up = &entp->dl_u.dl_rename;
895 up->dl_oparent_cid = odcp->c_id;
896 up->dl_nparent_cid = ndcp->c_id;
897 up->dl_child_cid = cp->c_id;
898 CACHEFS_DLOG_TS_COPY(&cp->c_metadata.md_vattr.va_mtime,
899 &up->dl_times.tm_mtime, "cachefs_dlog_rename: ", "mtime");
900 CACHEFS_DLOG_TS_COPY(&cp->c_metadata.md_vattr.va_ctime,
901 &up->dl_times.tm_ctime, "cachefs_dlog_rename: ", "ctime");
902 if (delcp) {
903 up->dl_del_cid = delcp->c_id;
904 CACHEFS_DLOG_TS_COPY(&delcp->c_metadata.md_vattr.va_mtime,
905 &up->dl_del_times.tm_mtime,
906 "cachefs_dlog_rename: ", "del mtime");
907 CACHEFS_DLOG_TS_COPY(&delcp->c_metadata.md_vattr.va_ctime,
908 &up->dl_del_times.tm_ctime,
909 "cachefs_dlog_rename: ", "del ctime");
910 } else {
911 up->dl_del_cid.cid_fileno = 0;
912 up->dl_del_cid.cid_flags = 0;
913 up->dl_del_times.tm_mtime.tv_sec = 0;
914 up->dl_del_times.tm_mtime.tv_nsec = 0;
915 up->dl_del_times.tm_ctime.tv_sec = 0;
916 up->dl_del_times.tm_ctime.tv_nsec = 0;
917 }
918
919 /* store the cred info */
920 len = copy_cred(cr, &up->dl_cred);
921
922 /* find the address in buffer past where the creds are stored */
923 curp = (caddr_t)(((uintptr_t)&up->dl_cred) + len);
924
925 /* store the old name */
926 len = strlen(onm) + 1;
927 bcopy(onm, curp, len);
928
929 /* store the new name */
930 curp += len;
931 len = strlen(nnm) + 1;
932 bcopy(nnm, curp, len);
933
934 /* calculate the length of this record */
935 entp->dl_len = (int)(((uintptr_t)curp + len) - (uintptr_t)entp);
936
937 /* write the record in the log */
938 offset = cachefs_dlog_output(fscp, entp, NULL);
939
940 cachefs_kmem_free(entp, sizeof (cfs_dlog_entry_t));
941 return (offset);
942 }
943
944 off_t
cachefs_dlog_mkdir(fscache_t * fscp,cnode_t * pcp,cnode_t * cp,char * nm,vattr_t * vap,cred_t * cr)945 cachefs_dlog_mkdir(fscache_t *fscp, cnode_t *pcp, cnode_t *cp, char *nm,
946 vattr_t *vap, cred_t *cr)
947 {
948 struct cfs_dlog_entry *entp;
949 struct cfs_dlog_mkdir *up;
950 size_t len;
951 caddr_t curp;
952 off_t offset;
953
954 entp = cachefs_kmem_alloc(sizeof (cfs_dlog_entry_t), KM_SLEEP);
955
956 entp->dl_valid = CFS_DLOG_VAL_CRASH;
957 entp->dl_op = CFS_DLOG_MKDIR;
958 up = &entp->dl_u.dl_mkdir;
959 up->dl_parent_cid = pcp->c_id;
960 up->dl_child_cid = cp->c_id;
961 CACHEFS_DLOG_VATTR_COPY(vap, &up->dl_attrs,
962 "cachefs_dlog_mkdir: dl_attr");
963 bzero(&up->dl_fid, sizeof (up->dl_fid));
964
965 /* store the cred info */
966 len = copy_cred(cr, &up->dl_cred);
967
968 /* find the address in buffer past where the creds are stored */
969 curp = (caddr_t)(((uintptr_t)&up->dl_cred) + len);
970
971 /* store the new directory name */
972 len = strlen(nm) + 1;
973 bcopy(nm, curp, len);
974
975 /* calculate the length of this record */
976 entp->dl_len = (int)(((uintptr_t)curp + len) - (uintptr_t)entp);
977
978 /* write the record in the dlog */
979 offset = cachefs_dlog_output(fscp, entp, NULL);
980
981 cachefs_kmem_free(entp, sizeof (cfs_dlog_entry_t));
982 return (offset);
983 }
984
985 off_t
cachefs_dlog_rmdir(fscache_t * fscp,cnode_t * pcp,char * nm,cnode_t * cp,cred_t * cr)986 cachefs_dlog_rmdir(fscache_t *fscp, cnode_t *pcp, char *nm, cnode_t *cp,
987 cred_t *cr)
988 {
989 struct cfs_dlog_entry *entp;
990 struct cfs_dlog_rmdir *up;
991 size_t len;
992 caddr_t curp;
993 off_t offset;
994
995 /* if not a local dir, log the cid to fid mapping */
996 if ((cp->c_id.cid_flags & CFS_CID_LOCAL) == 0) {
997 if (cachefs_dlog_mapfid(fscp, cp))
998 return (0);
999 if (cachefs_dlog_cidmap(fscp))
1000 return (0);
1001 }
1002
1003 entp = cachefs_kmem_alloc(sizeof (cfs_dlog_entry_t), KM_SLEEP);
1004
1005 entp->dl_valid = CFS_DLOG_VAL_CRASH;
1006 entp->dl_op = CFS_DLOG_RMDIR;
1007 up = &entp->dl_u.dl_rmdir;
1008 up->dl_parent_cid = pcp->c_id;
1009
1010 /* store the cred info */
1011 len = copy_cred(cr, &up->dl_cred);
1012
1013 /* find the address in buffer past where the creds are stored */
1014 curp = (caddr_t)(((uintptr_t)&up->dl_cred) + len);
1015
1016 /* store the created name */
1017 len = strlen(nm) + 1;
1018 bcopy(nm, curp, len);
1019
1020 /* calculate the length of this record */
1021 entp->dl_len = (int)(((uintptr_t)curp + len) - (uintptr_t)entp);
1022
1023 /* write the record in the log */
1024 offset = cachefs_dlog_output(fscp, entp, NULL);
1025
1026 cachefs_kmem_free(entp, sizeof (cfs_dlog_entry_t));
1027 return (offset);
1028 }
1029
1030 off_t
cachefs_dlog_symlink(fscache_t * fscp,cnode_t * pcp,cnode_t * cp,char * lnm,vattr_t * vap,char * tnm,cred_t * cr)1031 cachefs_dlog_symlink(fscache_t *fscp, cnode_t *pcp, cnode_t *cp, char *lnm,
1032 vattr_t *vap, char *tnm, cred_t *cr)
1033 {
1034 struct cfs_dlog_entry *entp;
1035 struct cfs_dlog_symlink *up;
1036 size_t len;
1037 caddr_t curp;
1038 off_t offset;
1039
1040 ASSERT(MUTEX_HELD(&cp->c_statelock));
1041
1042 entp = cachefs_kmem_alloc(sizeof (cfs_dlog_entry_t), KM_SLEEP);
1043
1044 entp->dl_valid = CFS_DLOG_VAL_CRASH;
1045 entp->dl_op = CFS_DLOG_SYMLINK;
1046 up = &entp->dl_u.dl_symlink;
1047 up->dl_parent_cid = pcp->c_id;
1048 up->dl_child_cid = cp->c_id;
1049 CACHEFS_DLOG_VATTR_COPY(vap, &up->dl_attrs,
1050 "cachefs_dlog_symlink: dl_attr");
1051 up->dl_times.tm_ctime.tv_sec = 0;
1052 up->dl_times.tm_ctime.tv_nsec = 0;
1053 up->dl_times.tm_mtime.tv_sec = 0;
1054 up->dl_times.tm_mtime.tv_nsec = 0;
1055 bzero(&up->dl_fid, sizeof (up->dl_fid));
1056
1057 /* store the cred info */
1058 len = copy_cred(cr, &up->dl_cred);
1059
1060 /* find the address in buffer past where the creds are stored */
1061 curp = (caddr_t)(((uintptr_t)&up->dl_cred) + len);
1062
1063 /* store the link name */
1064 len = strlen(lnm) + 1;
1065 bcopy(lnm, curp, len);
1066
1067 /* store new name */
1068 curp += len;
1069 len = strlen(tnm) + 1;
1070 bcopy(tnm, curp, len);
1071
1072 /* calculate the length of this record */
1073 entp->dl_len = (int)(((uintptr_t)curp + len) - (uintptr_t)entp);
1074
1075 /* write the record in the log */
1076 offset = cachefs_dlog_output(fscp, entp, NULL);
1077
1078 cachefs_kmem_free(entp, sizeof (cfs_dlog_entry_t));
1079 return (offset);
1080 }
1081
1082 off_t
cachefs_dlog_modify(fscache_t * fscp,cnode_t * cp,cred_t * cr,uint_t * seqp)1083 cachefs_dlog_modify(fscache_t *fscp, cnode_t *cp, cred_t *cr, uint_t *seqp)
1084 {
1085 struct cfs_dlog_entry *entp;
1086 struct cfs_dlog_modify *up;
1087 off_t offset;
1088 uint_t seq;
1089 size_t len;
1090
1091 entp = cachefs_kmem_alloc(sizeof (cfs_dlog_entry_t), KM_SLEEP);
1092
1093 entp->dl_valid = CFS_DLOG_VAL_CRASH;
1094 entp->dl_op = CFS_DLOG_MODIFIED;
1095 up = &entp->dl_u.dl_modify;
1096 up->dl_cid = cp->c_id;
1097 CACHEFS_DLOG_TS_COPY(&cp->c_metadata.md_vattr.va_mtime,
1098 &up->dl_times.tm_mtime,
1099 "cachefs_dlog_modify: ", "mtime");
1100 CACHEFS_DLOG_TS_COPY(&cp->c_metadata.md_vattr.va_ctime,
1101 &up->dl_times.tm_ctime,
1102 "cachefs_dlog_modify: ", "ctime");
1103
1104 up->dl_next = 0;
1105
1106 /* store the cred info */
1107 len = copy_cred(cr, &up->dl_cred);
1108
1109 /* calculate the length of this record */
1110 entp->dl_len = (int)(((uintptr_t)&up->dl_cred + len) - (uintptr_t)entp);
1111
1112 /* write the record in the log */
1113 offset = cachefs_dlog_output(fscp, entp, &seq);
1114
1115 /* return sequence number */
1116 *seqp = seq;
1117
1118 cachefs_kmem_free(entp, sizeof (cfs_dlog_entry_t));
1119 return (offset);
1120 }
1121
1122 int
cachefs_dlog_mapfid(fscache_t * fscp,cnode_t * cp)1123 cachefs_dlog_mapfid(fscache_t *fscp, cnode_t *cp)
1124 {
1125 struct cfs_dlog_entry *entp;
1126 struct cfs_dlog_mapfid *up;
1127 off_t offset;
1128
1129 entp = cachefs_kmem_alloc(sizeof (cfs_dlog_entry_t), KM_SLEEP);
1130
1131 entp->dl_valid = CFS_DLOG_VAL_COMMITTED;
1132 entp->dl_op = CFS_DLOG_MAPFID;
1133 up = &entp->dl_u.dl_mapfid;
1134 up->dl_cid = cp->c_id;
1135 CACHEFS_FID_COPY(&cp->c_cookie, &up->dl_fid);
1136
1137 /* calculate the length of this record */
1138 /* entp->dl_len = ((caddr_t)up - (caddr_t)entp + sizeof (*up)); */
1139 entp->dl_len = (int)(offsetof(struct cfs_dlog_entry, dl_u.dl_mapfid) +
1140 sizeof (struct cfs_dlog_mapfid));
1141
1142 /* write the record in the log */
1143 offset = cachefs_dlog_output(fscp, entp, NULL);
1144
1145 cachefs_kmem_free(entp, sizeof (cfs_dlog_entry_t));
1146 return (offset == 0);
1147 }
1148
1149 /* Returns the next sequence number, 0 if an error */
1150 uint_t
cachefs_dlog_seqnext(fscache_t * fscp)1151 cachefs_dlog_seqnext(fscache_t *fscp)
1152 {
1153 int error;
1154 uint_t seq;
1155
1156 if (fscp->fs_dlogfile == NULL) {
1157 error = cachefs_dlog_setup(fscp, 1);
1158 if (error)
1159 return (0);
1160 }
1161
1162 mutex_enter(&fscp->fs_dlock);
1163 ASSERT(fscp->fs_dlogfile);
1164
1165 /* get a sequence number for this log entry */
1166 seq = fscp->fs_dlogseq + 1;
1167 if (seq != 0) {
1168 fscp->fs_dlogseq++;
1169 }
1170 #ifdef CFSDEBUG
1171 else {
1172 cmn_err(CE_WARN, "cachefs: logging failed, seq overflow 2.");
1173 }
1174 #endif
1175 mutex_exit(&fscp->fs_dlock);
1176 return (seq);
1177 }
1178