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 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 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 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 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 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 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 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 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 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*/ 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 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 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 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 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 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 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 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 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 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 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 }