1 /* 2 * Copyright (c) 2007 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * $DragonFly: src/sys/vfs/hammer/hammer_inode.c,v 1.17 2008/01/03 06:48:49 dillon Exp $ 35 */ 36 37 #include "hammer.h" 38 #include <sys/buf.h> 39 #include <sys/buf2.h> 40 41 /* 42 * The kernel is not actively referencing this vnode but is still holding 43 * it cached. 44 */ 45 int 46 hammer_vop_inactive(struct vop_inactive_args *ap) 47 { 48 struct hammer_inode *ip = VTOI(ap->a_vp); 49 50 /* 51 * Degenerate case 52 */ 53 if (ip == NULL) { 54 vrecycle(ap->a_vp); 55 return(0); 56 } 57 58 /* 59 * If the inode no longer has any references we recover its 60 * in-memory resources immediately. 61 */ 62 if (ip->ino_rec.ino_nlinks == 0) 63 vrecycle(ap->a_vp); 64 return(0); 65 } 66 67 /* 68 * Release the vnode association. This is typically (but not always) 69 * the last reference on the inode and will flush the inode to the 70 * buffer cache. 71 * 72 * XXX Currently our sync code only runs through inodes with vnode 73 * associations, so we depend on hammer_rel_inode() to sync any inode 74 * record data to the block device prior to losing the association. 75 * Otherwise transactions that the user expected to be distinct by 76 * doing a manual sync may be merged. 77 */ 78 int 79 hammer_vop_reclaim(struct vop_reclaim_args *ap) 80 { 81 struct hammer_inode *ip; 82 struct vnode *vp; 83 84 vp = ap->a_vp; 85 86 if ((ip = vp->v_data) != NULL) { 87 vp->v_data = NULL; 88 ip->vp = NULL; 89 hammer_rel_inode(ip, 0); 90 } 91 return(0); 92 } 93 94 /* 95 * Obtain a vnode for the specified inode number. An exclusively locked 96 * vnode is returned. 97 */ 98 int 99 hammer_vfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) 100 { 101 struct hammer_mount *hmp = (void *)mp->mnt_data; 102 struct hammer_inode *ip; 103 int error; 104 105 /* 106 * Get/allocate the hammer_inode structure. The structure must be 107 * unlocked while we manipulate the related vnode to avoid a 108 * deadlock. 109 */ 110 ip = hammer_get_inode(hmp, NULL, ino, hmp->asof, 0, &error); 111 if (ip == NULL) { 112 *vpp = NULL; 113 return(error); 114 } 115 error = hammer_get_vnode(ip, LK_EXCLUSIVE, vpp); 116 hammer_rel_inode(ip, 0); 117 return (error); 118 } 119 120 /* 121 * Return a locked vnode for the specified inode. The inode must be 122 * referenced but NOT LOCKED on entry and will remain referenced on 123 * return. 124 */ 125 int 126 hammer_get_vnode(struct hammer_inode *ip, int lktype, struct vnode **vpp) 127 { 128 struct vnode *vp; 129 int error = 0; 130 131 for (;;) { 132 if ((vp = ip->vp) == NULL) { 133 error = getnewvnode(VT_HAMMER, ip->hmp->mp, vpp, 0, 0); 134 if (error) 135 break; 136 hammer_lock_ex(&ip->lock); 137 if (ip->vp != NULL) { 138 hammer_unlock(&ip->lock); 139 vp->v_type = VBAD; 140 vx_put(vp); 141 continue; 142 } 143 hammer_ref(&ip->lock); 144 vp = *vpp; 145 ip->vp = vp; 146 vp->v_type = hammer_get_vnode_type( 147 ip->ino_rec.base.base.obj_type); 148 149 switch(ip->ino_rec.base.base.obj_type) { 150 case HAMMER_OBJTYPE_CDEV: 151 case HAMMER_OBJTYPE_BDEV: 152 vp->v_ops = &ip->hmp->mp->mnt_vn_spec_ops; 153 addaliasu(vp, ip->ino_data.rmajor, 154 ip->ino_data.rminor); 155 break; 156 case HAMMER_OBJTYPE_FIFO: 157 vp->v_ops = &ip->hmp->mp->mnt_vn_fifo_ops; 158 break; 159 default: 160 break; 161 } 162 if (ip->obj_id == HAMMER_OBJID_ROOT) 163 vp->v_flag |= VROOT; 164 165 vp->v_data = (void *)ip; 166 /* vnode locked by getnewvnode() */ 167 /* make related vnode dirty if inode dirty? */ 168 hammer_unlock(&ip->lock); 169 if (vp->v_type == VREG) 170 vinitvmio(vp, ip->ino_rec.ino_size); 171 break; 172 } 173 174 /* 175 * loop if the vget fails (aka races), or if the vp 176 * no longer matches ip->vp. 177 */ 178 if (vget(vp, LK_EXCLUSIVE) == 0) { 179 if (vp == ip->vp) 180 break; 181 vput(vp); 182 } 183 } 184 *vpp = vp; 185 return(error); 186 } 187 188 /* 189 * Acquire a HAMMER inode. The returned inode is not locked. These functions 190 * do not attach or detach the related vnode (use hammer_get_vnode() for 191 * that). 192 * 193 * The flags argument is only applied for newly created inodes, and only 194 * certain flags are inherited. 195 */ 196 struct hammer_inode * 197 hammer_get_inode(struct hammer_mount *hmp, struct hammer_node **cache, 198 u_int64_t obj_id, hammer_tid_t asof, int flags, int *errorp) 199 { 200 struct hammer_inode_info iinfo; 201 struct hammer_cursor cursor; 202 struct hammer_inode *ip; 203 204 /* 205 * Determine if we already have an inode cached. If we do then 206 * we are golden. 207 */ 208 iinfo.obj_id = obj_id; 209 iinfo.obj_asof = asof; 210 loop: 211 ip = hammer_ino_rb_tree_RB_LOOKUP_INFO(&hmp->rb_inos_root, &iinfo); 212 if (ip) { 213 hammer_ref(&ip->lock); 214 *errorp = 0; 215 return(ip); 216 } 217 218 ip = kmalloc(sizeof(*ip), M_HAMMER, M_WAITOK|M_ZERO); 219 ++hammer_count_inodes; 220 ip->obj_id = obj_id; 221 ip->obj_asof = iinfo.obj_asof; 222 ip->hmp = hmp; 223 ip->flags = flags & HAMMER_INODE_RO; 224 if (hmp->ronly) 225 ip->flags |= HAMMER_INODE_RO; 226 RB_INIT(&ip->rec_tree); 227 228 /* 229 * Locate the on-disk inode. 230 */ 231 hammer_init_cursor_hmp(&cursor, cache, hmp); 232 cursor.key_beg.obj_id = ip->obj_id; 233 cursor.key_beg.key = 0; 234 cursor.key_beg.create_tid = iinfo.obj_asof; 235 cursor.key_beg.delete_tid = 0; 236 cursor.key_beg.rec_type = HAMMER_RECTYPE_INODE; 237 cursor.key_beg.obj_type = 0; 238 cursor.flags = HAMMER_CURSOR_GET_RECORD | HAMMER_CURSOR_GET_DATA; 239 240 *errorp = hammer_btree_lookup(&cursor); 241 242 /* 243 * On success the B-Tree lookup will hold the appropriate 244 * buffer cache buffers and provide a pointer to the requested 245 * information. Copy the information to the in-memory inode 246 * and cache the B-Tree node to improve future operations. 247 */ 248 if (*errorp == 0) { 249 ip->ino_rec = cursor.record->inode; 250 ip->ino_data = cursor.data->inode; 251 hammer_cache_node(cursor.node, &ip->cache[0]); 252 if (cache) 253 hammer_cache_node(cursor.node, cache); 254 } 255 256 /* 257 * On success load the inode's record and data and insert the 258 * inode into the B-Tree. It is possible to race another lookup 259 * insertion of the same inode so deal with that condition too. 260 * 261 * The cursor's locked node interlocks against others creating and 262 * destroying ip while we were blocked. 263 */ 264 if (*errorp == 0) { 265 hammer_ref(&ip->lock); 266 if (RB_INSERT(hammer_ino_rb_tree, &hmp->rb_inos_root, ip)) { 267 hammer_uncache_node(&ip->cache[0]); 268 hammer_uncache_node(&ip->cache[1]); 269 hammer_unref(&ip->lock); 270 --hammer_count_inodes; 271 kfree(ip, M_HAMMER); 272 hammer_done_cursor(&cursor); 273 goto loop; 274 } 275 ip->flags |= HAMMER_INODE_ONDISK; 276 } else { 277 --hammer_count_inodes; 278 kfree(ip, M_HAMMER); 279 ip = NULL; 280 } 281 hammer_done_cursor(&cursor); 282 return (ip); 283 } 284 285 /* 286 * Create a new filesystem object, returning the inode in *ipp. The 287 * returned inode will be referenced but not locked. 288 * 289 * The inode is created in-memory and will be delay-synchronized to the 290 * disk. 291 */ 292 int 293 hammer_create_inode(hammer_transaction_t trans, struct vattr *vap, 294 struct ucred *cred, hammer_inode_t dip, 295 struct hammer_inode **ipp) 296 { 297 hammer_mount_t hmp; 298 hammer_inode_t ip; 299 uid_t xuid; 300 301 hmp = trans->hmp; 302 ip = kmalloc(sizeof(*ip), M_HAMMER, M_WAITOK|M_ZERO); 303 ++hammer_count_inodes; 304 ip->obj_id = hammer_alloc_tid(trans); 305 KKASSERT(ip->obj_id != 0); 306 ip->obj_asof = hmp->asof; 307 ip->hmp = hmp; 308 ip->flags = HAMMER_INODE_DDIRTY | HAMMER_INODE_RDIRTY | 309 HAMMER_INODE_ITIMES; 310 ip->last_tid = trans->tid; 311 312 RB_INIT(&ip->rec_tree); 313 314 ip->ino_rec.ino_atime = trans->tid; 315 ip->ino_rec.ino_mtime = trans->tid; 316 ip->ino_rec.ino_size = 0; 317 ip->ino_rec.ino_nlinks = 0; 318 /* XXX */ 319 ip->ino_rec.base.rec_id = hammer_alloc_recid(trans); 320 KKASSERT(ip->ino_rec.base.rec_id != 0); 321 ip->ino_rec.base.base.obj_id = ip->obj_id; 322 ip->ino_rec.base.base.key = 0; 323 ip->ino_rec.base.base.create_tid = trans->tid; 324 ip->ino_rec.base.base.delete_tid = 0; 325 ip->ino_rec.base.base.rec_type = HAMMER_RECTYPE_INODE; 326 ip->ino_rec.base.base.obj_type = hammer_get_obj_type(vap->va_type); 327 328 ip->ino_data.version = HAMMER_INODE_DATA_VERSION; 329 ip->ino_data.mode = vap->va_mode; 330 ip->ino_data.ctime = trans->tid; 331 ip->ino_data.parent_obj_id = (dip) ? dip->ino_rec.base.base.obj_id : 0; 332 333 switch(ip->ino_rec.base.base.obj_type) { 334 case HAMMER_OBJTYPE_CDEV: 335 case HAMMER_OBJTYPE_BDEV: 336 ip->ino_data.rmajor = vap->va_rmajor; 337 ip->ino_data.rminor = vap->va_rminor; 338 break; 339 default: 340 break; 341 } 342 343 /* 344 * Calculate default uid/gid and overwrite with information from 345 * the vap. 346 */ 347 xuid = hammer_to_unix_xid(&dip->ino_data.uid); 348 ip->ino_data.gid = dip->ino_data.gid; 349 xuid = vop_helper_create_uid(hmp->mp, dip->ino_data.mode, xuid, cred, 350 &vap->va_mode); 351 ip->ino_data.mode = vap->va_mode; 352 353 if (vap->va_vaflags & VA_UID_UUID_VALID) 354 ip->ino_data.uid = vap->va_uid_uuid; 355 else if (vap->va_uid != (uid_t)VNOVAL) 356 hammer_guid_to_uuid(&ip->ino_data.uid, xuid); 357 if (vap->va_vaflags & VA_GID_UUID_VALID) 358 ip->ino_data.gid = vap->va_gid_uuid; 359 else if (vap->va_gid != (gid_t)VNOVAL) 360 hammer_guid_to_uuid(&ip->ino_data.gid, vap->va_gid); 361 362 hammer_ref(&ip->lock); 363 if (RB_INSERT(hammer_ino_rb_tree, &hmp->rb_inos_root, ip)) { 364 hammer_unref(&ip->lock); 365 panic("hammer_create_inode: duplicate obj_id %llx", ip->obj_id); 366 } 367 *ipp = ip; 368 return(0); 369 } 370 371 /* 372 * Called by hammer_sync_inode(). 373 */ 374 static int 375 hammer_update_inode(hammer_inode_t ip) 376 { 377 struct hammer_cursor cursor; 378 struct hammer_cursor *spike = NULL; 379 hammer_record_t record; 380 int error; 381 hammer_tid_t last_tid; 382 383 /* 384 * Locate the record on-disk and mark it as deleted. Both the B-Tree 385 * node and the record must be marked deleted. The record may or 386 * may not be physically deleted, depending on the retention policy. 387 * 388 * If the inode has already been deleted on-disk we have nothing 389 * to do. 390 * 391 * XXX Update the inode record and data in-place if the retention 392 * policy allows it. 393 */ 394 last_tid = ip->last_tid; 395 retry: 396 error = 0; 397 398 if ((ip->flags & (HAMMER_INODE_ONDISK|HAMMER_INODE_DELONDISK)) == 399 HAMMER_INODE_ONDISK) { 400 hammer_init_cursor_hmp(&cursor, &ip->cache[0], ip->hmp); 401 cursor.key_beg.obj_id = ip->obj_id; 402 cursor.key_beg.key = 0; 403 cursor.key_beg.create_tid = ip->obj_asof; 404 cursor.key_beg.delete_tid = 0; 405 cursor.key_beg.rec_type = HAMMER_RECTYPE_INODE; 406 cursor.key_beg.obj_type = 0; 407 cursor.flags = HAMMER_CURSOR_GET_RECORD; 408 409 error = hammer_btree_lookup(&cursor); 410 411 if (error == 0) { 412 error = hammer_ip_delete_record(&cursor, last_tid); 413 if (error == 0) 414 ip->flags |= HAMMER_INODE_DELONDISK; 415 } 416 hammer_cache_node(cursor.node, &ip->cache[0]); 417 hammer_done_cursor(&cursor); 418 } 419 420 /* 421 * Write out a new record if the in-memory inode is not marked 422 * as having been deleted. Update our inode statistics if this 423 * is the first application of the inode on-disk. 424 * 425 * If the inode has been deleted permanently, HAMMER_INODE_DELONDISK 426 * will remain set and prevent further updates. 427 */ 428 if (error == 0 && (ip->flags & HAMMER_INODE_DELETED) == 0) { 429 record = hammer_alloc_mem_record(ip); 430 record->rec.inode = ip->ino_rec; 431 record->rec.inode.base.base.create_tid = last_tid; 432 record->rec.inode.base.data_len = sizeof(ip->ino_data); 433 record->data = (void *)&ip->ino_data; 434 error = hammer_ip_sync_record(record, &spike); 435 record->flags |= HAMMER_RECF_DELETED; 436 hammer_rel_mem_record(record); 437 if (error == ENOSPC) { 438 error = hammer_spike(&spike); 439 if (error == 0) 440 goto retry; 441 } 442 KKASSERT(spike == NULL); 443 if (error == 0) { 444 ip->flags &= ~(HAMMER_INODE_RDIRTY | 445 HAMMER_INODE_DDIRTY | 446 HAMMER_INODE_DELONDISK | 447 HAMMER_INODE_ITIMES); 448 if ((ip->flags & HAMMER_INODE_ONDISK) == 0) { 449 hammer_modify_volume(ip->hmp->rootvol); 450 ++ip->hmp->rootvol->ondisk->vol0_stat_inodes; 451 hammer_modify_volume_done(ip->hmp->rootvol); 452 ip->flags |= HAMMER_INODE_ONDISK; 453 } 454 } 455 } 456 return(error); 457 } 458 459 /* 460 * Update only the itimes fields. This is done no-historically. The 461 * record is updated in-place on the disk. 462 */ 463 static int 464 hammer_update_itimes(hammer_inode_t ip) 465 { 466 struct hammer_cursor cursor; 467 struct hammer_inode_record *rec; 468 int error; 469 470 error = 0; 471 if ((ip->flags & (HAMMER_INODE_ONDISK|HAMMER_INODE_DELONDISK)) == 472 HAMMER_INODE_ONDISK) { 473 hammer_init_cursor_hmp(&cursor, &ip->cache[0], ip->hmp); 474 cursor.key_beg.obj_id = ip->obj_id; 475 cursor.key_beg.key = 0; 476 cursor.key_beg.create_tid = ip->obj_asof; 477 cursor.key_beg.delete_tid = 0; 478 cursor.key_beg.rec_type = HAMMER_RECTYPE_INODE; 479 cursor.key_beg.obj_type = 0; 480 cursor.flags = HAMMER_CURSOR_GET_RECORD; 481 482 error = hammer_btree_lookup(&cursor); 483 484 if (error == 0) { 485 rec = &cursor.record->inode; 486 hammer_modify_buffer(cursor.record_buffer); 487 rec->ino_atime = ip->ino_rec.ino_atime; 488 rec->ino_mtime = ip->ino_rec.ino_mtime; 489 hammer_modify_buffer_done(cursor.record_buffer); 490 ip->flags &= ~HAMMER_INODE_ITIMES; 491 /* XXX recalculate crc */ 492 } 493 hammer_cache_node(cursor.node, &ip->cache[0]); 494 hammer_done_cursor(&cursor); 495 } 496 return(error); 497 } 498 499 /* 500 * Release a reference on an inode. If asked to flush the last release 501 * will flush the inode. 502 */ 503 void 504 hammer_rel_inode(struct hammer_inode *ip, int flush) 505 { 506 hammer_unref(&ip->lock); 507 if (flush) 508 ip->flags |= HAMMER_INODE_FLUSH; 509 if (ip->lock.refs == 0) { 510 if (ip->flags & HAMMER_INODE_FLUSH) 511 hammer_unload_inode(ip, (void *)MNT_WAIT); 512 else 513 hammer_unload_inode(ip, (void *)MNT_NOWAIT); 514 } 515 } 516 517 /* 518 * Unload and destroy the specified inode. 519 * 520 * (called via RB_SCAN) 521 */ 522 int 523 hammer_unload_inode(struct hammer_inode *ip, void *data) 524 { 525 int error; 526 527 KASSERT(ip->lock.refs == 0, 528 ("hammer_unload_inode: %d refs\n", ip->lock.refs)); 529 KKASSERT(ip->vp == NULL); 530 hammer_ref(&ip->lock); 531 532 error = hammer_sync_inode(ip, (int)data, 1); 533 if (error) 534 kprintf("hammer_sync_inode failed error %d\n", error); 535 if (ip->lock.refs == 1) { 536 KKASSERT(RB_EMPTY(&ip->rec_tree)); 537 RB_REMOVE(hammer_ino_rb_tree, &ip->hmp->rb_inos_root, ip); 538 539 hammer_uncache_node(&ip->cache[0]); 540 hammer_uncache_node(&ip->cache[1]); 541 --hammer_count_inodes; 542 kfree(ip, M_HAMMER); 543 } else { 544 hammer_unref(&ip->lock); 545 } 546 return(0); 547 } 548 549 /* 550 * A transaction has modified an inode, requiring updates as specified by 551 * the passed flags. 552 * 553 * HAMMER_INODE_RDIRTY: Inode record has been updated 554 * HAMMER_INODE_DDIRTY: Inode data has been updated 555 * HAMMER_INODE_DELETED: Inode record/data must be deleted 556 * HAMMER_INODE_ITIMES: mtime/atime has been updated 557 * 558 * last_tid is the TID to use to generate the correct TID when the inode 559 * is synced to disk. 560 */ 561 void 562 hammer_modify_inode(struct hammer_transaction *trans, 563 struct hammer_inode *ip, int flags) 564 { 565 KKASSERT ((ip->flags & HAMMER_INODE_RO) == 0 || 566 (HAMMER_INODE_RDIRTY|HAMMER_INODE_DDIRTY| 567 HAMMER_INODE_DELETED|HAMMER_INODE_ITIMES) == 0); 568 569 if (flags & 570 (HAMMER_INODE_RDIRTY|HAMMER_INODE_DDIRTY|HAMMER_INODE_DELETED)) { 571 if (hammer_debug_tid) { 572 kprintf("hammer_modify_inode: %016llx (%08x)\n", 573 trans->tid, (int)(trans->tid / 1000000000LL)); 574 } 575 ip->last_tid = trans->tid; 576 } 577 ip->flags |= flags; 578 } 579 580 /* 581 * Sync any dirty buffers and records associated with an inode. The 582 * inode's last_tid field is used as the transaction id for the sync, 583 * overriding any intermediate TIDs that were used for records. Note 584 * that the dirty buffer cache buffers do not have any knowledge of 585 * the transaction id they were modified under. 586 * 587 * If we can't sync due to a cluster becoming full the spike structure 588 * will be filled in and ENOSPC returned. We must return -ENOSPC to 589 * terminate the RB_SCAN. 590 */ 591 static int 592 hammer_sync_inode_callback(hammer_record_t rec, void *data) 593 { 594 struct hammer_cursor **spike = data; 595 int error; 596 597 hammer_ref(&rec->lock); 598 error = hammer_ip_sync_record(rec, spike); 599 hammer_rel_mem_record(rec); 600 601 if (error) { 602 error = -error; 603 if (error != -ENOSPC) { 604 kprintf("hammer_sync_inode_callback: sync failed rec " 605 "%p, error %d\n", rec, error); 606 } 607 } 608 return(error); 609 } 610 611 /* 612 * XXX error handling 613 */ 614 int 615 hammer_sync_inode(hammer_inode_t ip, int waitfor, int handle_delete) 616 { 617 struct hammer_transaction trans; 618 struct hammer_cursor *spike = NULL; 619 int error; 620 621 if ((ip->flags & HAMMER_INODE_MODMASK) == 0) { 622 return(0); 623 } 624 625 hammer_lock_ex(&ip->lock); 626 627 /* 628 * Use the transaction id of the last operation to sync. 629 */ 630 if (ip->last_tid) 631 hammer_start_transaction_tid(&trans, ip->hmp, ip->last_tid); 632 else 633 hammer_start_transaction(&trans, ip->hmp); 634 635 /* 636 * If the inode has been deleted (nlinks == 0), and the OS no longer 637 * has any references to it (handle_delete != 0), clean up in-memory 638 * data. 639 * 640 * NOTE: We do not set the RDIRTY flag when updating the delete_tid, 641 * setting HAMMER_INODE_DELETED takes care of it. 642 * 643 * NOTE: Because we may sync records within this new transaction, 644 * force the inode update later on to use our transaction id or 645 * the delete_tid of the inode may be less then the create_tid of 646 * the inode update. XXX shouldn't happen but don't take the chance. 647 * 648 * NOTE: The call to hammer_ip_delete_range() cannot return ENOSPC 649 * so we can pass a NULL spike structure, because no partial data 650 * deletion can occur (yet). 651 */ 652 if (ip->ino_rec.ino_nlinks == 0 && handle_delete && 653 (ip->flags & HAMMER_INODE_GONE) == 0) { 654 ip->flags |= HAMMER_INODE_GONE; 655 if (ip->vp) 656 vtruncbuf(ip->vp, 0, HAMMER_BUFSIZE); 657 error = hammer_ip_delete_range_all(&trans, ip); 658 KKASSERT(RB_EMPTY(&ip->rec_tree)); 659 ip->ino_rec.base.base.delete_tid = trans.tid; 660 hammer_modify_inode(&trans, ip, HAMMER_INODE_DELETED); 661 hammer_modify_volume(ip->hmp->rootvol); 662 --ip->hmp->rootvol->ondisk->vol0_stat_inodes; 663 hammer_modify_volume_done(ip->hmp->rootvol); 664 } 665 666 /* 667 * Sync the buffer cache 668 */ 669 if (ip->vp != NULL) 670 error = vfsync(ip->vp, waitfor, 1, NULL, NULL); 671 else 672 error = 0; 673 674 /* 675 * Now sync related records 676 */ 677 for (;;) { 678 error = RB_SCAN(hammer_rec_rb_tree, &ip->rec_tree, NULL, 679 hammer_sync_inode_callback, &spike); 680 KKASSERT(error <= 0); 681 if (error < 0) 682 error = -error; 683 if (error == ENOSPC) { 684 error = hammer_spike(&spike); 685 if (error == 0) 686 continue; 687 } 688 break; 689 } 690 if (RB_EMPTY(&ip->rec_tree)) 691 ip->flags &= ~HAMMER_INODE_XDIRTY; 692 693 /* 694 * Now update the inode's on-disk inode-data and/or on-disk record. 695 */ 696 switch(ip->flags & (HAMMER_INODE_DELETED|HAMMER_INODE_ONDISK)) { 697 case HAMMER_INODE_DELETED|HAMMER_INODE_ONDISK: 698 /* 699 * If deleted and on-disk, don't set any additional flags. 700 * the delete flag takes care of things. 701 */ 702 break; 703 case HAMMER_INODE_DELETED: 704 /* 705 * Take care of the case where a deleted inode was never 706 * flushed to the disk in the first place. 707 */ 708 ip->flags &= ~(HAMMER_INODE_RDIRTY|HAMMER_INODE_DDIRTY| 709 HAMMER_INODE_XDIRTY|HAMMER_INODE_ITIMES); 710 while (RB_ROOT(&ip->rec_tree)) { 711 hammer_record_t rec = RB_ROOT(&ip->rec_tree); 712 hammer_ref(&rec->lock); 713 rec->flags |= HAMMER_RECF_DELETED; 714 hammer_rel_mem_record(rec); 715 } 716 break; 717 case HAMMER_INODE_ONDISK: 718 /* 719 * If already on-disk, do not set any additional flags. 720 */ 721 break; 722 default: 723 /* 724 * If not on-disk and not deleted, set both dirty flags 725 * to force an initial record to be written. 726 */ 727 ip->flags |= HAMMER_INODE_RDIRTY | HAMMER_INODE_DDIRTY; 728 break; 729 } 730 731 /* 732 * If RDIRTY or DDIRTY is set, write out a new record. If the inode 733 * is already on-disk the old record is marked as deleted. 734 * 735 * If DELETED is set hammer_update_inode() will delete the existing 736 * record without writing out a new one. 737 * 738 * If *ONLY* the ITIMES flag is set we can update the record in-place. 739 */ 740 if ((ip->flags & (HAMMER_INODE_RDIRTY | HAMMER_INODE_DDIRTY | 741 HAMMER_INODE_ITIMES | HAMMER_INODE_DELETED)) == 742 HAMMER_INODE_ITIMES) { 743 error = hammer_update_itimes(ip); 744 } else 745 if (ip->flags & (HAMMER_INODE_RDIRTY | HAMMER_INODE_DDIRTY | 746 HAMMER_INODE_ITIMES | HAMMER_INODE_DELETED)) { 747 error = hammer_update_inode(ip); 748 } 749 hammer_commit_transaction(&trans); 750 hammer_unlock(&ip->lock); 751 return(error); 752 } 753 754 /* 755 * Access the filesystem buffer containing the cluster-relative byte 756 * offset, validate the buffer type, load *bufferp and return a 757 * pointer to the requested data. The buffer is reference and locked on 758 * return. 759 * 760 * If buf_type is 0 the buffer is assumed to be a pure-data buffer and 761 * no type or crc check is performed. 762 * 763 * If *bufferp is not NULL on entry it is assumed to contain a locked 764 * and referenced buffer which will then be replaced. 765 * 766 * If the caller is holding another unrelated buffer locked it must be 767 * passed in reorderbuf so we can properly order buffer locks. 768 * 769 * XXX add a flag for the buffer type and check the CRC here XXX 770 */ 771 void * 772 hammer_bread(hammer_cluster_t cluster, int32_t cloff, 773 u_int64_t buf_type, int *errorp, 774 struct hammer_buffer **bufferp) 775 { 776 hammer_buffer_t buffer; 777 int32_t buf_no; 778 int32_t buf_off; 779 780 /* 781 * Load the correct filesystem buffer, replacing *bufferp. 782 */ 783 buf_no = cloff / HAMMER_BUFSIZE; 784 buffer = *bufferp; 785 if (buffer == NULL || buffer->cluster != cluster || 786 buffer->buf_no != buf_no) { 787 if (buffer) { 788 /*hammer_unlock(&buffer->io.lock);*/ 789 hammer_rel_buffer(buffer, 0); 790 } 791 buffer = hammer_get_buffer(cluster, buf_no, 0, errorp); 792 *bufferp = buffer; 793 if (buffer == NULL) 794 return(NULL); 795 /*hammer_lock_ex(&buffer->io.lock);*/ 796 } 797 798 /* 799 * Validate the buffer type 800 */ 801 buf_off = cloff & HAMMER_BUFMASK; 802 if (buf_type) { 803 if (buf_type != buffer->ondisk->head.buf_type) { 804 kprintf("BUFFER HEAD TYPE MISMATCH %llx %llx\n", 805 buf_type, buffer->ondisk->head.buf_type); 806 *errorp = EIO; 807 return(NULL); 808 } 809 if (buf_off < sizeof(buffer->ondisk->head)) { 810 kprintf("BUFFER OFFSET TOO LOW %d\n", buf_off); 811 *errorp = EIO; 812 return(NULL); 813 } 814 } 815 816 /* 817 * Return a pointer to the buffer data. 818 */ 819 *errorp = 0; 820 return((char *)buffer->ondisk + buf_off); 821 } 822 823