1 /* 2 * Copyright 2012 Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Paweł Dziepak, pdziepak@quarnos.org 7 */ 8 9 10 #include "Inode.h" 11 12 #include <ctype.h> 13 #include <string.h> 14 15 #include <AutoDeleter.h> 16 #include <fs_cache.h> 17 #include <NodeMonitor.h> 18 19 #include "IdMap.h" 20 #include "Request.h" 21 #include "RootInode.h" 22 23 24 Inode::Inode() 25 : 26 fMetaCache(this), 27 fCache(NULL), 28 fAttrCache(NULL), 29 fDelegation(NULL), 30 fFileCache(NULL), 31 fMaxFileSize(0), 32 fOpenState(NULL), 33 fWriteDirty(false), 34 fAIOWait(create_sem(1, NULL)), 35 fAIOCount(0) 36 { 37 rw_lock_init(&fDelegationLock, NULL); 38 mutex_init(&fStateLock, NULL); 39 mutex_init(&fFileCacheLock, NULL); 40 rw_lock_init(&fWriteLock, NULL); 41 mutex_init(&fAIOLock, NULL); 42 } 43 44 45 status_t 46 Inode::CreateInode(FileSystem* fs, const FileInfo& fi, Inode** _inode) 47 { 48 ASSERT(fs != NULL); 49 ASSERT(_inode != NULL); 50 51 Inode* inode = NULL; 52 if (fs->Root() == NULL) 53 inode = new(std::nothrow) RootInode; 54 else 55 inode = new(std::nothrow) Inode; 56 57 if (inode == NULL) 58 return B_NO_MEMORY; 59 60 inode->fInfo = fi; 61 inode->fFileSystem = fs; 62 63 uint32 attempt = 0; 64 uint64 size; 65 do { 66 RPC::Server* serv = fs->Server(); 67 Request request(serv, fs); 68 RequestBuilder& req = request.Builder(); 69 70 req.PutFH(inode->fInfo.fHandle); 71 72 Attribute attr[] = { FATTR4_TYPE, FATTR4_CHANGE, FATTR4_SIZE, 73 FATTR4_FSID, FATTR4_FILEID }; 74 req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); 75 76 status_t result = request.Send(); 77 if (result != B_OK) 78 return result; 79 80 ReplyInterpreter& reply = request.Reply(); 81 82 if (inode->HandleErrors(attempt, reply.NFS4Error(), serv)) 83 continue; 84 85 reply.PutFH(); 86 87 AttrValue* values; 88 uint32 count; 89 result = reply.GetAttr(&values, &count); 90 if (result != B_OK) 91 return result; 92 93 if (fi.fFileId == 0) { 94 if (count < 5 || values[4].fAttribute != FATTR4_FILEID) 95 inode->fInfo.fFileId = fs->AllocFileId(); 96 else 97 inode->fInfo.fFileId = values[4].fData.fValue64; 98 } else 99 inode->fInfo.fFileId = fi.fFileId; 100 101 // FATTR4_TYPE is mandatory 102 inode->fType = values[0].fData.fValue32; 103 104 if (inode->fType == NF4DIR) 105 inode->fCache = new DirectoryCache(inode); 106 inode->fAttrCache = new DirectoryCache(inode, true); 107 108 // FATTR4_CHANGE is mandatory 109 inode->fChange = values[1].fData.fValue64; 110 111 // FATTR4_SIZE is mandatory 112 size = values[2].fData.fValue64; 113 inode->fMaxFileSize = size; 114 115 // FATTR4_FSID is mandatory 116 FileSystemId* fsid 117 = reinterpret_cast<FileSystemId*>(values[3].fData.fPointer); 118 if (*fsid != fs->FsId()) { 119 delete[] values; 120 return B_ENTRY_NOT_FOUND; 121 } 122 123 delete[] values; 124 125 *_inode = inode; 126 127 break; 128 } while (true); 129 130 if (inode->fType == NF4REG) 131 inode->fFileCache = file_cache_create(fs->DevId(), inode->ID(), size); 132 133 return B_OK; 134 } 135 136 137 Inode::~Inode() 138 { 139 if (fDelegation != NULL) 140 RecallDelegation(); 141 142 if (fFileCache != NULL) 143 file_cache_delete(fFileCache); 144 145 delete fCache; 146 delete fAttrCache; 147 148 delete_sem(fAIOWait); 149 mutex_destroy(&fAIOLock); 150 mutex_destroy(&fStateLock); 151 mutex_destroy(&fFileCacheLock); 152 rw_lock_destroy(&fDelegationLock); 153 rw_lock_destroy(&fWriteLock); 154 155 ASSERT(fAIOCount == 0); 156 } 157 158 159 status_t 160 Inode::RevalidateFileCache() 161 { 162 if (fDelegation != NULL) 163 return B_OK; 164 165 uint64 change; 166 status_t result = GetChangeInfo(&change); 167 if (result != B_OK) 168 return result; 169 170 MutexLocker _(fFileCacheLock); 171 if (change == fChange) 172 return B_OK; 173 174 SyncAndCommit(true); 175 file_cache_delete(fFileCache); 176 177 struct stat st; 178 fMetaCache.InvalidateStat(); 179 result = Stat(&st); 180 if (result != B_OK) 181 return result; 182 183 fFileCache = file_cache_create(fFileSystem->DevId(), ID(), st.st_size); 184 185 change = fChange; 186 return B_OK; 187 } 188 189 190 status_t 191 Inode::LookUp(const char* name, ino_t* id) 192 { 193 ASSERT(name != NULL); 194 ASSERT(id != NULL); 195 196 if (fType != NF4DIR) 197 return B_NOT_A_DIRECTORY; 198 199 uint64 change; 200 uint64 fileID; 201 FileHandle handle; 202 status_t result = NFS4Inode::LookUp(name, &change, &fileID, &handle); 203 if (result != B_OK) 204 return result; 205 206 *id = FileIdToInoT(fileID); 207 208 result = ChildAdded(name, fileID, handle); 209 if (result != B_OK) 210 return result; 211 212 fCache->Lock(); 213 if (!fCache->Valid()) { 214 fCache->Reset(); 215 fCache->SetChangeInfo(change); 216 } else 217 fCache->ValidateChangeInfo(change); 218 219 fCache->AddEntry(name, *id); 220 fCache->Unlock(); 221 222 return B_OK; 223 } 224 225 226 status_t 227 Inode::Link(Inode* dir, const char* name) 228 { 229 ASSERT(dir != NULL); 230 ASSERT(name != NULL); 231 232 ChangeInfo changeInfo; 233 status_t result = NFS4Inode::Link(dir, name, &changeInfo); 234 if (result != B_OK) 235 return result; 236 237 fFileSystem->Root()->MakeInfoInvalid(); 238 fInfo.fNames->AddName(dir->fInfo.fNames, name); 239 240 dir->fCache->Lock(); 241 if (dir->fCache->Valid()) { 242 if (changeInfo.fAtomic 243 && dir->fCache->ChangeInfo() == changeInfo.fBefore) { 244 dir->fCache->AddEntry(name, fInfo.fFileId, true); 245 dir->fCache->SetChangeInfo(changeInfo.fAfter); 246 } else 247 dir->fCache->Trash(); 248 } 249 dir->fCache->Unlock(); 250 251 notify_entry_created(fFileSystem->DevId(), dir->ID(), name, ID()); 252 253 return B_OK; 254 } 255 256 257 status_t 258 Inode::Remove(const char* name, FileType type, ino_t* id) 259 { 260 ASSERT(name != NULL); 261 262 MemoryDeleter nameDeleter; 263 if (type == NF4NAMEDATTR) { 264 status_t result = LoadAttrDirHandle(); 265 if (result != B_OK) 266 return result; 267 268 name = AttrToFileName(name); 269 if (name == NULL) 270 return B_NO_MEMORY; 271 nameDeleter.SetTo(const_cast<char*>(name)); 272 } 273 274 ChangeInfo changeInfo; 275 uint64 fileID; 276 status_t result = NFS4Inode::RemoveObject(name, type, &changeInfo, &fileID); 277 if (result != B_OK) 278 return result; 279 280 DirectoryCache* cache = type != NF4NAMEDATTR ? fCache : fAttrCache; 281 cache->Lock(); 282 if (cache->Valid()) { 283 if (changeInfo.fAtomic 284 && fCache->ChangeInfo() == changeInfo.fBefore) { 285 cache->RemoveEntry(name); 286 cache->SetChangeInfo(changeInfo.fAfter); 287 } else if (cache->ChangeInfo() != changeInfo.fBefore) 288 cache->Trash(); 289 } 290 cache->Unlock(); 291 292 fFileSystem->Root()->MakeInfoInvalid(); 293 if (id != NULL) 294 *id = FileIdToInoT(fileID); 295 296 if (type == NF4NAMEDATTR) { 297 notify_attribute_changed(fFileSystem->DevId(), ID(), name, 298 B_ATTR_REMOVED); 299 } else { 300 notify_entry_removed(fFileSystem->DevId(), ID(), name, 301 FileIdToInoT(fileID)); 302 } 303 304 return B_OK; 305 } 306 307 308 status_t 309 Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName, 310 bool attribute, ino_t* id, ino_t* oldID) 311 { 312 ASSERT(from != NULL); 313 ASSERT(fromName != NULL); 314 ASSERT(to != NULL); 315 ASSERT(toName != NULL); 316 317 if (from->fFileSystem != to->fFileSystem) 318 return B_DONT_DO_THAT; 319 320 MemoryDeleter fromNameDeleter; 321 MemoryDeleter toNameDeleter; 322 if (attribute) { 323 status_t result = from->LoadAttrDirHandle(); 324 if (result != B_OK) 325 return result; 326 327 result = to->LoadAttrDirHandle(); 328 if (result != B_OK) 329 return result; 330 331 fromName = from->AttrToFileName(fromName); 332 toName = to->AttrToFileName(toName); 333 334 fromNameDeleter.SetTo(const_cast<char*>(fromName)); 335 toNameDeleter.SetTo(const_cast<char*>(toName)); 336 if (fromName == NULL || toName == NULL) 337 return B_NO_MEMORY; 338 } 339 340 uint64 oldFileID = 0; 341 if (!attribute) 342 to->NFS4Inode::LookUp(toName, NULL, &oldFileID, NULL); 343 344 uint64 fileID; 345 ChangeInfo fromChange, toChange; 346 status_t result = NFS4Inode::RenameNode(from, to, fromName, toName, 347 &fromChange, &toChange, &fileID, attribute); 348 if (result != B_OK) 349 return result; 350 351 from->fFileSystem->Root()->MakeInfoInvalid(); 352 353 if (id != NULL) 354 *id = FileIdToInoT(fileID); 355 if (oldID != NULL) 356 *oldID = FileIdToInoT(oldFileID); 357 358 DirectoryCache* cache = attribute ? from->fAttrCache : from->fCache; 359 cache->Lock(); 360 if (cache->Valid()) { 361 if (fromChange.fAtomic && cache->ChangeInfo() == fromChange.fBefore) { 362 cache->RemoveEntry(fromName); 363 if (to == from) 364 cache->AddEntry(toName, fileID, true); 365 cache->SetChangeInfo(fromChange.fAfter); 366 } else 367 cache->Trash(); 368 } 369 cache->Unlock(); 370 371 if (to != from) { 372 cache = attribute ? to->fAttrCache : to->fCache; 373 cache->Lock(); 374 if (cache->Valid()) { 375 if (toChange.fAtomic 376 && (cache->ChangeInfo() == toChange.fBefore)) { 377 cache->AddEntry(toName, fileID, true); 378 cache->SetChangeInfo(toChange.fAfter); 379 } else 380 cache->Trash(); 381 } 382 cache->Unlock(); 383 } 384 385 if (attribute) { 386 notify_attribute_changed(from->fFileSystem->DevId(), from->ID(), 387 fromName, B_ATTR_REMOVED); 388 notify_attribute_changed(to->fFileSystem->DevId(), to->ID(), toName, 389 B_ATTR_CREATED); 390 } else { 391 notify_entry_moved(from->fFileSystem->DevId(), from->ID(), fromName, 392 to->ID(), toName, FileIdToInoT(fileID)); 393 } 394 395 return B_OK; 396 } 397 398 399 status_t 400 Inode::CreateLink(const char* name, const char* path, int mode, ino_t* id) 401 { 402 return CreateObject(name, path, mode, NF4LNK, id); 403 } 404 405 406 status_t 407 Inode::CreateObject(const char* name, const char* path, int mode, FileType type, 408 ino_t* id) 409 { 410 ASSERT(name != NULL); 411 ASSERT(type != NF4LNK || path != NULL); 412 413 ChangeInfo changeInfo; 414 uint64 fileID; 415 FileHandle handle; 416 417 status_t result = NFS4Inode::CreateObject(name, path, mode, type, 418 &changeInfo, &fileID, &handle); 419 if (result != B_OK) 420 return result; 421 422 fFileSystem->Root()->MakeInfoInvalid(); 423 424 result = ChildAdded(name, fileID, handle); 425 if (result != B_OK) 426 return result; 427 428 fCache->Lock(); 429 if (fCache->Valid()) { 430 if (changeInfo.fAtomic && fCache->ChangeInfo() == changeInfo.fBefore) { 431 fCache->AddEntry(name, fileID, true); 432 fCache->SetChangeInfo(changeInfo.fAfter); 433 } else 434 fCache->Trash(); 435 } 436 fCache->Unlock(); 437 438 notify_entry_created(fFileSystem->DevId(), ID(), name, 439 FileIdToInoT(fileID)); 440 441 *id = FileIdToInoT(fileID); 442 return B_OK; 443 } 444 445 446 status_t 447 Inode::Access(int mode) 448 { 449 int acc = 0; 450 451 uint32 allowed; 452 bool cache = fFileSystem->GetConfiguration().fCacheMetadata; 453 status_t result = fMetaCache.GetAccess(geteuid(), &allowed); 454 if (result != B_OK || !cache) { 455 result = NFS4Inode::Access(&allowed); 456 if (result != B_OK) 457 return result; 458 fMetaCache.SetAccess(geteuid(), allowed); 459 } 460 461 if ((allowed & ACCESS4_READ) != 0) 462 acc |= R_OK; 463 464 if ((allowed & ACCESS4_LOOKUP) != 0) 465 acc |= X_OK | R_OK; 466 467 if ((allowed & ACCESS4_EXECUTE) != 0) 468 acc |= X_OK; 469 470 if ((allowed & ACCESS4_MODIFY) != 0) 471 acc |= W_OK; 472 473 if ((mode & acc) != mode) 474 return B_NOT_ALLOWED; 475 476 return B_OK; 477 } 478 479 480 status_t 481 Inode::Stat(struct stat* st, OpenAttrCookie* attr) 482 { 483 ASSERT(st != NULL); 484 485 if (attr != NULL) 486 return GetStat(st, attr); 487 488 bool cache = fFileSystem->GetConfiguration().fCacheMetadata; 489 if (!cache) 490 return GetStat(st, NULL); 491 492 status_t result = fMetaCache.GetStat(st); 493 if (result != B_OK) { 494 struct stat temp; 495 result = GetStat(&temp); 496 if (result != B_OK) 497 return result; 498 fMetaCache.SetStat(temp); 499 fMetaCache.GetStat(st); 500 } 501 502 return B_OK; 503 } 504 505 506 status_t 507 Inode::GetStat(struct stat* st, OpenAttrCookie* attr) 508 { 509 ASSERT(st != NULL); 510 511 AttrValue* values; 512 uint32 count; 513 status_t result = NFS4Inode::GetStat(&values, &count, attr); 514 if (result != B_OK) 515 return result; 516 517 // FATTR4_SIZE is mandatory 518 if (count < 1 || values[0].fAttribute != FATTR4_SIZE) { 519 delete[] values; 520 return B_BAD_VALUE; 521 } 522 st->st_size = values[0].fData.fValue64; 523 524 uint32 next = 1; 525 st->st_mode = Type(); 526 if (count >= next && values[next].fAttribute == FATTR4_MODE) { 527 st->st_mode |= values[next].fData.fValue32; 528 next++; 529 } else 530 st->st_mode = 777; 531 532 if (count >= next && values[next].fAttribute == FATTR4_NUMLINKS) { 533 st->st_nlink = values[next].fData.fValue32; 534 next++; 535 } else 536 st->st_nlink = 1; 537 538 if (count >= next && values[next].fAttribute == FATTR4_OWNER) { 539 char* owner = reinterpret_cast<char*>(values[next].fData.fPointer); 540 if (owner != NULL && isdigit(owner[0])) 541 st->st_uid = atoi(owner); 542 else 543 st->st_uid = gIdMapper->GetUserId(owner); 544 next++; 545 } else 546 st->st_uid = 0; 547 548 if (count >= next && values[next].fAttribute == FATTR4_OWNER_GROUP) { 549 char* group = reinterpret_cast<char*>(values[next].fData.fPointer); 550 if (group != NULL && isdigit(group[0])) 551 st->st_gid = atoi(group); 552 else 553 st->st_gid = gIdMapper->GetGroupId(group); 554 next++; 555 } else 556 st->st_gid = 0; 557 558 if (count >= next && values[next].fAttribute == FATTR4_TIME_ACCESS) { 559 memcpy(&st->st_atim, values[next].fData.fPointer, 560 sizeof(timespec)); 561 next++; 562 } else 563 memset(&st->st_atim, 0, sizeof(timespec)); 564 565 if (count >= next && values[next].fAttribute == FATTR4_TIME_CREATE) { 566 memcpy(&st->st_crtim, values[next].fData.fPointer, 567 sizeof(timespec)); 568 next++; 569 } else 570 memset(&st->st_crtim, 0, sizeof(timespec)); 571 572 if (count >= next && values[next].fAttribute == FATTR4_TIME_METADATA) { 573 memcpy(&st->st_ctim, values[next].fData.fPointer, 574 sizeof(timespec)); 575 next++; 576 } else 577 memset(&st->st_ctim, 0, sizeof(timespec)); 578 579 if (count >= next && values[next].fAttribute == FATTR4_TIME_MODIFY) { 580 memcpy(&st->st_mtim, values[next].fData.fPointer, 581 sizeof(timespec)); 582 next++; 583 } else 584 memset(&st->st_mtim, 0, sizeof(timespec)); 585 delete[] values; 586 587 st->st_blksize = fFileSystem->Root()->IOSize(); 588 st->st_blocks = st->st_size / st->st_blksize; 589 st->st_blocks += st->st_size % st->st_blksize == 0 ? 0 : 1; 590 591 return B_OK; 592 } 593 594 595 status_t 596 Inode::WriteStat(const struct stat* st, uint32 mask, OpenAttrCookie* cookie) 597 { 598 ASSERT(st != NULL); 599 600 status_t result; 601 AttrValue attr[6]; 602 uint32 i = 0; 603 604 if ((mask & B_STAT_SIZE) != 0) { 605 fMaxFileSize = st->st_size; 606 file_cache_set_size(fFileCache, st->st_size); 607 608 attr[i].fAttribute = FATTR4_SIZE; 609 attr[i].fFreePointer = false; 610 attr[i].fData.fValue64 = st->st_size; 611 i++; 612 } 613 614 if ((mask & B_STAT_MODE) != 0) { 615 attr[i].fAttribute = FATTR4_MODE; 616 attr[i].fFreePointer = false; 617 attr[i].fData.fValue32 = st->st_mode; 618 i++; 619 } 620 621 if ((mask & B_STAT_UID) != 0) { 622 attr[i].fAttribute = FATTR4_OWNER; 623 attr[i].fFreePointer = true; 624 attr[i].fData.fPointer = gIdMapper->GetOwner(st->st_uid); 625 i++; 626 } 627 628 if ((mask & B_STAT_GID) != 0) { 629 attr[i].fAttribute = FATTR4_OWNER_GROUP; 630 attr[i].fFreePointer = true; 631 attr[i].fData.fPointer = gIdMapper->GetOwnerGroup(st->st_gid); 632 i++; 633 } 634 635 if ((mask & B_STAT_ACCESS_TIME) != 0) { 636 attr[i].fAttribute = FATTR4_TIME_ACCESS_SET; 637 attr[i].fFreePointer = true; 638 attr[i].fData.fPointer = malloc(sizeof(st->st_atim)); 639 memcpy(attr[i].fData.fPointer, &st->st_atim, sizeof(st->st_atim)); 640 i++; 641 } 642 643 if ((mask & B_STAT_MODIFICATION_TIME) != 0) { 644 attr[i].fAttribute = FATTR4_TIME_MODIFY_SET; 645 attr[i].fFreePointer = true; 646 attr[i].fData.fPointer = malloc(sizeof(st->st_mtim)); 647 memcpy(attr[i].fData.fPointer, &st->st_mtim, sizeof(st->st_mtim)); 648 i++; 649 } 650 651 if (cookie == NULL) { 652 MutexLocker stateLocker(fStateLock); 653 ASSERT(fOpenState != NULL || !(mask & B_STAT_SIZE)); 654 result = NFS4Inode::WriteStat(fOpenState, attr, i); 655 } else 656 result = NFS4Inode::WriteStat(cookie->fOpenState, attr, i); 657 658 fMetaCache.InvalidateStat(); 659 660 const uint32 kAccessMask = B_STAT_MODE | B_STAT_UID | B_STAT_GID; 661 if ((mask & kAccessMask) != 0) 662 fMetaCache.InvalidateAccess(); 663 664 return result; 665 } 666 667 668 inline status_t 669 Inode::CheckLockType(short ltype, uint32 mode) 670 { 671 switch (ltype) { 672 case F_UNLCK: 673 return B_OK; 674 675 case F_RDLCK: 676 if ((mode & O_RDONLY) == 0 && (mode & O_RDWR) == 0) 677 return EBADF; 678 return B_OK; 679 680 case F_WRLCK: 681 if ((mode & O_WRONLY) == 0 && (mode & O_RDWR) == 0) 682 return EBADF; 683 return B_OK; 684 685 default: 686 return B_BAD_VALUE; 687 } 688 } 689 690 691 status_t 692 Inode::TestLock(OpenFileCookie* cookie, struct flock* lock) 693 { 694 ASSERT(cookie != NULL); 695 ASSERT(lock != NULL); 696 697 if (lock->l_type == F_UNLCK) 698 return B_OK; 699 700 status_t result = CheckLockType(lock->l_type, cookie->fMode); 701 if (result != B_OK) 702 return result; 703 704 LockType ltype = sGetLockType(lock->l_type, false); 705 uint64 position = lock->l_start; 706 uint64 length; 707 if (lock->l_len + lock->l_start == OFF_MAX) 708 length = UINT64_MAX; 709 else 710 length = lock->l_len; 711 712 bool conflict; 713 result = NFS4Inode::TestLock(cookie, <ype, &position, &length, conflict); 714 if (result != B_OK) 715 return result; 716 717 if (conflict) { 718 lock->l_type = sLockTypeToHaiku(ltype); 719 lock->l_start = static_cast<off_t>(position); 720 if (length >= OFF_MAX) 721 lock->l_len = OFF_MAX; 722 else 723 lock->l_len = static_cast<off_t>(length); 724 } else 725 lock->l_type = F_UNLCK; 726 727 return B_OK; 728 } 729 730 731 status_t 732 Inode::AcquireLock(OpenFileCookie* cookie, const struct flock* lock, 733 bool wait) 734 { 735 ASSERT(cookie != NULL); 736 ASSERT(lock != NULL); 737 738 OpenState* state = cookie->fOpenState; 739 740 status_t result = CheckLockType(lock->l_type, cookie->fMode); 741 if (result != B_OK) 742 return result; 743 744 thread_info info; 745 get_thread_info(find_thread(NULL), &info); 746 747 MutexLocker locker(state->fOwnerLock); 748 LockOwner* owner = state->GetLockOwner(info.team); 749 if (owner == NULL) 750 return B_NO_MEMORY; 751 752 LockInfo* linfo = new LockInfo(owner); 753 if (linfo == NULL) 754 return B_NO_MEMORY; 755 locker.Unlock(); 756 757 linfo->fStart = lock->l_start; 758 if (lock->l_len + lock->l_start == OFF_MAX) 759 linfo->fLength = UINT64_MAX; 760 else 761 linfo->fLength = lock->l_len; 762 linfo->fType = sGetLockType(lock->l_type, wait); 763 764 result = NFS4Inode::AcquireLock(cookie, linfo, wait); 765 if (result != B_OK) { 766 delete linfo; 767 return result; 768 } 769 770 MutexLocker _(state->fLocksLock); 771 state->AddLock(linfo); 772 cookie->AddLock(linfo); 773 774 return B_OK; 775 } 776 777 778 status_t 779 Inode::ReleaseLock(OpenFileCookie* cookie, const struct flock* lock) 780 { 781 ASSERT(cookie != NULL); 782 ASSERT(lock != NULL); 783 784 SyncAndCommit(); 785 786 LockInfo* prev = NULL; 787 788 thread_info info; 789 get_thread_info(find_thread(NULL), &info); 790 uint32 owner = info.team; 791 792 OpenState* state = cookie->fOpenState; 793 MutexLocker locker(state->fLocksLock); 794 LockInfo* linfo = state->fLocks; 795 while (linfo != NULL) { 796 if (linfo->fOwner->fOwner == owner && *linfo == *lock) { 797 state->RemoveLock(linfo, prev); 798 break; 799 } 800 801 prev = linfo; 802 linfo = linfo->fNext; 803 } 804 805 prev = NULL; 806 linfo = cookie->fLocks; 807 while (linfo != NULL) { 808 if (linfo->fOwner->fOwner == owner && *linfo == *lock) { 809 cookie->RemoveLock(linfo, prev); 810 break; 811 } 812 813 prev = linfo; 814 linfo = linfo->fCookieNext; 815 } 816 locker.Unlock(); 817 818 if (linfo == NULL) 819 return B_BAD_VALUE; 820 821 status_t result = NFS4Inode::ReleaseLock(cookie, linfo); 822 if (result != B_OK) 823 return result; 824 825 state->DeleteLock(linfo); 826 827 return B_OK; 828 } 829 830 831 status_t 832 Inode::ReleaseAllLocks(OpenFileCookie* cookie) 833 { 834 ASSERT(cookie != NULL); 835 836 SyncAndCommit(); 837 838 OpenState* state = cookie->fOpenState; 839 MutexLocker _(state->fLocksLock); 840 LockInfo* linfo = cookie->fLocks; 841 while (linfo != NULL) { 842 cookie->RemoveLock(linfo, NULL); 843 844 LockInfo* prev = NULL; 845 LockInfo* stateLock = state->fLocks; 846 while (stateLock != NULL) { 847 if (*linfo == *stateLock) { 848 state->RemoveLock(stateLock, prev); 849 break; 850 } 851 852 prev = stateLock; 853 stateLock = stateLock->fNext; 854 } 855 856 NFS4Inode::ReleaseLock(cookie, linfo); 857 state->DeleteLock(linfo); 858 859 linfo = cookie->fLocks; 860 } 861 862 return B_OK; 863 } 864 865 866 status_t 867 Inode::ChildAdded(const char* name, uint64 fileID, 868 const FileHandle& fileHandle) 869 { 870 ASSERT(name != NULL); 871 872 fFileSystem->Root()->MakeInfoInvalid(); 873 874 FileInfo fi; 875 fi.fFileId = fileID; 876 fi.fHandle = fileHandle; 877 878 return fFileSystem->InoIdMap()->AddName(fi, fInfo.fNames, name, 879 FileIdToInoT(fileID)); 880 } 881 882 883 const char* 884 Inode::Name() const 885 { 886 ASSERT(fInfo.fNames->fNames.Head() != NULL); 887 return fInfo.fNames->fNames.Head()->fName; 888 } 889 890 891 void 892 Inode::SetDelegation(Delegation* delegation) 893 { 894 ASSERT(delegation != NULL); 895 896 WriteLocker _(fDelegationLock); 897 898 fMetaCache.InvalidateStat(); 899 struct stat st; 900 Stat(&st); 901 fMetaCache.LockValid(); 902 903 fDelegation = delegation; 904 fOpenState->AcquireReference(); 905 fOpenState->fDelegation = delegation; 906 fFileSystem->AddDelegation(delegation); 907 } 908 909 910 void 911 Inode::RecallDelegation(bool truncate) 912 { 913 WriteLocker _(fDelegationLock); 914 if (fDelegation == NULL) 915 return; 916 ReturnDelegation(truncate); 917 } 918 919 920 void 921 Inode::RecallReadDelegation() 922 { 923 WriteLocker _(fDelegationLock); 924 if (fDelegation == NULL || fDelegation->Type() != OPEN_DELEGATE_READ) 925 return; 926 ReturnDelegation(false); 927 } 928 929 930 void 931 Inode::ReturnDelegation(bool truncate) 932 { 933 ASSERT(fDelegation != NULL); 934 935 fDelegation->GiveUp(truncate); 936 937 fMetaCache.UnlockValid(); 938 fFileSystem->RemoveDelegation(fDelegation); 939 940 MutexLocker stateLocker(fStateLock); 941 fOpenState->fDelegation = NULL; 942 ReleaseOpenState(); 943 944 delete fDelegation; 945 fDelegation = NULL; 946 } 947 948 949 void 950 Inode::ReleaseOpenState() 951 { 952 ASSERT(fOpenState != NULL); 953 954 if (fOpenState->ReleaseReference() == 1) { 955 ASSERT(fAIOCount == 0); 956 fOpenState = NULL; 957 } 958 } 959 960 961 status_t 962 Inode::SyncAndCommit(bool force) 963 { 964 if (!force && fDelegation != NULL) 965 return B_OK; 966 967 file_cache_sync(fFileCache); 968 WaitAIOComplete(); 969 return Commit(); 970 } 971 972 973 void 974 Inode::BeginAIOOp() 975 { 976 MutexLocker _(fAIOLock); 977 fAIOCount++; 978 if (fAIOCount == 1) 979 acquire_sem(fAIOWait); 980 } 981 982 983 void 984 Inode::EndAIOOp() 985 { 986 MutexLocker _(fAIOLock); 987 ASSERT(fAIOCount > 0); 988 fAIOCount--; 989 if (fAIOCount == 0) 990 release_sem(fAIOWait); 991 } 992 993