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