1 /* 2 * Copyright 2012-2016 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 SyncAndCommit(true); 174 175 file_cache_delete(fFileCache); 176 177 struct stat st; 178 fMetaCache.InvalidateStat(); 179 result = Stat(&st); 180 if (result == B_OK) 181 fMaxFileSize = st.st_size; 182 fFileCache = file_cache_create(fFileSystem->DevId(), ID(), fMaxFileSize); 183 184 change = fChange; 185 return B_OK; 186 } 187 188 189 status_t 190 Inode::LookUp(const char* name, ino_t* id) 191 { 192 ASSERT(name != NULL); 193 ASSERT(id != NULL); 194 195 if (fType != NF4DIR) 196 return B_NOT_A_DIRECTORY; 197 198 uint64 change; 199 uint64 fileID; 200 FileHandle handle; 201 status_t result = NFS4Inode::LookUp(name, &change, &fileID, &handle); 202 if (result != B_OK) 203 return result; 204 205 *id = FileIdToInoT(fileID); 206 207 result = ChildAdded(name, fileID, handle); 208 if (result != B_OK) 209 return result; 210 211 fCache->Lock(); 212 if (!fCache->Valid()) { 213 fCache->Reset(); 214 fCache->SetChangeInfo(change); 215 } else 216 fCache->ValidateChangeInfo(change); 217 218 fCache->AddEntry(name, *id); 219 fCache->Unlock(); 220 221 return B_OK; 222 } 223 224 225 status_t 226 Inode::Link(Inode* dir, const char* name) 227 { 228 ASSERT(dir != NULL); 229 ASSERT(name != NULL); 230 231 ChangeInfo changeInfo; 232 status_t result = NFS4Inode::Link(dir, name, &changeInfo); 233 if (result != B_OK) 234 return result; 235 236 fFileSystem->Root()->MakeInfoInvalid(); 237 fInfo.fNames->AddName(dir->fInfo.fNames, name); 238 239 dir->fCache->Lock(); 240 if (dir->fCache->Valid()) { 241 if (changeInfo.fAtomic 242 && dir->fCache->ChangeInfo() == changeInfo.fBefore) { 243 dir->fCache->AddEntry(name, fInfo.fFileId, true); 244 dir->fCache->SetChangeInfo(changeInfo.fAfter); 245 } else 246 dir->fCache->Trash(); 247 } 248 dir->fCache->Unlock(); 249 250 notify_entry_created(fFileSystem->DevId(), dir->ID(), name, ID()); 251 252 return B_OK; 253 } 254 255 256 status_t 257 Inode::Remove(const char* name, FileType type, ino_t* id) 258 { 259 ASSERT(name != NULL); 260 261 MemoryDeleter nameDeleter; 262 if (type == NF4NAMEDATTR) { 263 status_t result = LoadAttrDirHandle(); 264 if (result != B_OK) 265 return result; 266 267 name = AttrToFileName(name); 268 if (name == NULL) 269 return B_NO_MEMORY; 270 nameDeleter.SetTo(const_cast<char*>(name)); 271 } 272 273 ChangeInfo changeInfo; 274 uint64 fileID; 275 status_t result = NFS4Inode::RemoveObject(name, type, &changeInfo, &fileID); 276 if (result != B_OK) 277 return result; 278 279 DirectoryCache* cache = type != NF4NAMEDATTR ? fCache : fAttrCache; 280 cache->Lock(); 281 if (cache->Valid()) { 282 if (changeInfo.fAtomic 283 && fCache->ChangeInfo() == changeInfo.fBefore) { 284 cache->RemoveEntry(name); 285 cache->SetChangeInfo(changeInfo.fAfter); 286 } else if (cache->ChangeInfo() != changeInfo.fBefore) 287 cache->Trash(); 288 } 289 cache->Unlock(); 290 291 fFileSystem->Root()->MakeInfoInvalid(); 292 if (id != NULL) 293 *id = FileIdToInoT(fileID); 294 295 if (type == NF4NAMEDATTR) { 296 notify_attribute_changed(fFileSystem->DevId(), -1, ID(), name, 297 B_ATTR_REMOVED); 298 } else { 299 notify_entry_removed(fFileSystem->DevId(), ID(), name, 300 FileIdToInoT(fileID)); 301 } 302 303 return B_OK; 304 } 305 306 307 status_t 308 Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName, 309 bool attribute, ino_t* id, ino_t* oldID) 310 { 311 ASSERT(from != NULL); 312 ASSERT(fromName != NULL); 313 ASSERT(to != NULL); 314 ASSERT(toName != NULL); 315 316 if (from->fFileSystem != to->fFileSystem) 317 return B_DONT_DO_THAT; 318 319 MemoryDeleter fromNameDeleter; 320 MemoryDeleter toNameDeleter; 321 if (attribute) { 322 status_t result = from->LoadAttrDirHandle(); 323 if (result != B_OK) 324 return result; 325 326 result = to->LoadAttrDirHandle(); 327 if (result != B_OK) 328 return result; 329 330 fromName = from->AttrToFileName(fromName); 331 toName = to->AttrToFileName(toName); 332 333 fromNameDeleter.SetTo(const_cast<char*>(fromName)); 334 toNameDeleter.SetTo(const_cast<char*>(toName)); 335 if (fromName == NULL || toName == NULL) 336 return B_NO_MEMORY; 337 } 338 339 uint64 oldFileID = 0; 340 if (!attribute) 341 to->NFS4Inode::LookUp(toName, NULL, &oldFileID, NULL); 342 343 uint64 fileID; 344 ChangeInfo fromChange, toChange; 345 status_t result = NFS4Inode::RenameNode(from, to, fromName, toName, 346 &fromChange, &toChange, &fileID, attribute); 347 if (result != B_OK) 348 return result; 349 350 from->fFileSystem->Root()->MakeInfoInvalid(); 351 352 if (id != NULL) 353 *id = FileIdToInoT(fileID); 354 if (oldID != NULL) 355 *oldID = FileIdToInoT(oldFileID); 356 357 DirectoryCache* cache = attribute ? from->fAttrCache : from->fCache; 358 cache->Lock(); 359 if (cache->Valid()) { 360 if (fromChange.fAtomic && cache->ChangeInfo() == fromChange.fBefore) { 361 cache->RemoveEntry(fromName); 362 if (to == from) 363 cache->AddEntry(toName, fileID, true); 364 cache->SetChangeInfo(fromChange.fAfter); 365 } else 366 cache->Trash(); 367 } 368 cache->Unlock(); 369 370 if (to != from) { 371 cache = attribute ? to->fAttrCache : to->fCache; 372 cache->Lock(); 373 if (cache->Valid()) { 374 if (toChange.fAtomic 375 && (cache->ChangeInfo() == toChange.fBefore)) { 376 cache->AddEntry(toName, fileID, true); 377 cache->SetChangeInfo(toChange.fAfter); 378 } else 379 cache->Trash(); 380 } 381 cache->Unlock(); 382 } 383 384 if (attribute) { 385 notify_attribute_changed(from->fFileSystem->DevId(), -1, from->ID(), 386 fromName, B_ATTR_REMOVED); 387 notify_attribute_changed(to->fFileSystem->DevId(), -1, to->ID(), toName, 388 B_ATTR_CREATED); 389 } else { 390 notify_entry_moved(from->fFileSystem->DevId(), from->ID(), fromName, 391 to->ID(), toName, FileIdToInoT(fileID)); 392 } 393 394 return B_OK; 395 } 396 397 398 status_t 399 Inode::CreateLink(const char* name, const char* path, int mode, ino_t* id) 400 { 401 return CreateObject(name, path, mode, NF4LNK, id); 402 } 403 404 405 status_t 406 Inode::CreateObject(const char* name, const char* path, int mode, FileType type, 407 ino_t* id) 408 { 409 ASSERT(name != NULL); 410 ASSERT(type != NF4LNK || path != NULL); 411 412 ChangeInfo changeInfo; 413 uint64 fileID; 414 FileHandle handle; 415 416 status_t result = NFS4Inode::CreateObject(name, path, mode, type, 417 &changeInfo, &fileID, &handle); 418 if (result != B_OK) 419 return result; 420 421 fFileSystem->Root()->MakeInfoInvalid(); 422 423 result = ChildAdded(name, fileID, handle); 424 if (result != B_OK) 425 return result; 426 427 fCache->Lock(); 428 if (fCache->Valid()) { 429 if (changeInfo.fAtomic && fCache->ChangeInfo() == changeInfo.fBefore) { 430 fCache->AddEntry(name, fileID, true); 431 fCache->SetChangeInfo(changeInfo.fAfter); 432 } else 433 fCache->Trash(); 434 } 435 fCache->Unlock(); 436 437 notify_entry_created(fFileSystem->DevId(), ID(), name, 438 FileIdToInoT(fileID)); 439 440 *id = FileIdToInoT(fileID); 441 return B_OK; 442 } 443 444 445 status_t 446 Inode::Access(int mode) 447 { 448 int acc = 0; 449 450 uint32 allowed; 451 bool cache = fFileSystem->GetConfiguration().fCacheMetadata; 452 status_t result = fMetaCache.GetAccess(geteuid(), &allowed); 453 if (result != B_OK || !cache) { 454 result = NFS4Inode::Access(&allowed); 455 if (result != B_OK) 456 return result; 457 fMetaCache.SetAccess(geteuid(), allowed); 458 } 459 460 if ((allowed & ACCESS4_READ) != 0) 461 acc |= R_OK; 462 463 if ((allowed & ACCESS4_LOOKUP) != 0) 464 acc |= X_OK | R_OK; 465 466 if ((allowed & ACCESS4_EXECUTE) != 0) 467 acc |= X_OK; 468 469 if ((allowed & ACCESS4_MODIFY) != 0) 470 acc |= W_OK; 471 472 if ((mode & acc) != mode) 473 return B_NOT_ALLOWED; 474 475 return B_OK; 476 } 477 478 479 status_t 480 Inode::Stat(struct stat* st, OpenAttrCookie* attr) 481 { 482 ASSERT(st != NULL); 483 484 if (attr != NULL) 485 return GetStat(st, attr); 486 487 bool cache = fFileSystem->GetConfiguration().fCacheMetadata; 488 if (!cache) 489 return GetStat(st, NULL); 490 491 status_t result = fMetaCache.GetStat(st); 492 if (result != B_OK) { 493 struct stat temp; 494 result = GetStat(&temp); 495 if (result != B_OK) 496 return result; 497 fMetaCache.SetStat(temp); 498 fMetaCache.GetStat(st); 499 } 500 501 return B_OK; 502 } 503 504 505 status_t 506 Inode::GetStat(struct stat* st, OpenAttrCookie* attr) 507 { 508 ASSERT(st != NULL); 509 510 AttrValue* values; 511 uint32 count; 512 status_t result = NFS4Inode::GetStat(&values, &count, attr); 513 if (result != B_OK) 514 return result; 515 516 // FATTR4_SIZE is mandatory 517 if (count < 1 || values[0].fAttribute != FATTR4_SIZE) { 518 delete[] values; 519 return B_BAD_VALUE; 520 } 521 st->st_size = values[0].fData.fValue64; 522 523 uint32 next = 1; 524 st->st_mode = Type(); 525 if (count >= next && values[next].fAttribute == FATTR4_MODE) { 526 st->st_mode |= values[next].fData.fValue32; 527 next++; 528 } else 529 st->st_mode = 777; 530 531 if (count >= next && values[next].fAttribute == FATTR4_NUMLINKS) { 532 st->st_nlink = values[next].fData.fValue32; 533 next++; 534 } else 535 st->st_nlink = 1; 536 537 if (count >= next && values[next].fAttribute == FATTR4_OWNER) { 538 char* owner = reinterpret_cast<char*>(values[next].fData.fPointer); 539 if (owner != NULL && isdigit(owner[0])) 540 st->st_uid = atoi(owner); 541 else 542 st->st_uid = gIdMapper->GetUserId(owner); 543 next++; 544 } else 545 st->st_uid = 0; 546 547 if (count >= next && values[next].fAttribute == FATTR4_OWNER_GROUP) { 548 char* group = reinterpret_cast<char*>(values[next].fData.fPointer); 549 if (group != NULL && isdigit(group[0])) 550 st->st_gid = atoi(group); 551 else 552 st->st_gid = gIdMapper->GetGroupId(group); 553 next++; 554 } else 555 st->st_gid = 0; 556 557 if (count >= next && values[next].fAttribute == FATTR4_TIME_ACCESS) { 558 memcpy(&st->st_atim, values[next].fData.fPointer, 559 sizeof(timespec)); 560 next++; 561 } else 562 memset(&st->st_atim, 0, sizeof(timespec)); 563 564 if (count >= next && values[next].fAttribute == FATTR4_TIME_CREATE) { 565 memcpy(&st->st_crtim, values[next].fData.fPointer, 566 sizeof(timespec)); 567 next++; 568 } else 569 memset(&st->st_crtim, 0, sizeof(timespec)); 570 571 if (count >= next && values[next].fAttribute == FATTR4_TIME_METADATA) { 572 memcpy(&st->st_ctim, values[next].fData.fPointer, 573 sizeof(timespec)); 574 next++; 575 } else 576 memset(&st->st_ctim, 0, sizeof(timespec)); 577 578 if (count >= next && values[next].fAttribute == FATTR4_TIME_MODIFY) { 579 memcpy(&st->st_mtim, values[next].fData.fPointer, 580 sizeof(timespec)); 581 next++; 582 } else 583 memset(&st->st_mtim, 0, sizeof(timespec)); 584 delete[] values; 585 586 st->st_blksize = fFileSystem->Root()->IOSize(); 587 st->st_blocks = st->st_size / st->st_blksize; 588 st->st_blocks += st->st_size % st->st_blksize == 0 ? 0 : 1; 589 590 return B_OK; 591 } 592 593 594 status_t 595 Inode::WriteStat(const struct stat* st, uint32 mask, OpenAttrCookie* cookie) 596 { 597 ASSERT(st != NULL); 598 599 status_t result; 600 AttrValue attr[6]; 601 uint32 i = 0; 602 603 if ((mask & B_STAT_SIZE) != 0) { 604 fMaxFileSize = st->st_size; 605 file_cache_set_size(fFileCache, st->st_size); 606 607 attr[i].fAttribute = FATTR4_SIZE; 608 attr[i].fFreePointer = false; 609 attr[i].fData.fValue64 = st->st_size; 610 i++; 611 } 612 613 if ((mask & B_STAT_MODE) != 0) { 614 attr[i].fAttribute = FATTR4_MODE; 615 attr[i].fFreePointer = false; 616 attr[i].fData.fValue32 = st->st_mode; 617 i++; 618 } 619 620 if ((mask & B_STAT_UID) != 0) { 621 attr[i].fAttribute = FATTR4_OWNER; 622 attr[i].fFreePointer = true; 623 attr[i].fData.fPointer = gIdMapper->GetOwner(st->st_uid); 624 i++; 625 } 626 627 if ((mask & B_STAT_GID) != 0) { 628 attr[i].fAttribute = FATTR4_OWNER_GROUP; 629 attr[i].fFreePointer = true; 630 attr[i].fData.fPointer = gIdMapper->GetOwnerGroup(st->st_gid); 631 i++; 632 } 633 634 if ((mask & B_STAT_ACCESS_TIME) != 0) { 635 attr[i].fAttribute = FATTR4_TIME_ACCESS_SET; 636 attr[i].fFreePointer = true; 637 attr[i].fData.fPointer = malloc(sizeof(st->st_atim)); 638 memcpy(attr[i].fData.fPointer, &st->st_atim, sizeof(st->st_atim)); 639 i++; 640 } 641 642 if ((mask & B_STAT_MODIFICATION_TIME) != 0) { 643 attr[i].fAttribute = FATTR4_TIME_MODIFY_SET; 644 attr[i].fFreePointer = true; 645 attr[i].fData.fPointer = malloc(sizeof(st->st_mtim)); 646 memcpy(attr[i].fData.fPointer, &st->st_mtim, sizeof(st->st_mtim)); 647 i++; 648 } 649 650 if (cookie == NULL) { 651 MutexLocker stateLocker(fStateLock); 652 ASSERT(fOpenState != NULL || !(mask & B_STAT_SIZE)); 653 result = NFS4Inode::WriteStat(fOpenState, attr, i); 654 } else 655 result = NFS4Inode::WriteStat(cookie->fOpenState, attr, i); 656 657 fMetaCache.InvalidateStat(); 658 659 const uint32 kAccessMask = B_STAT_MODE | B_STAT_UID | B_STAT_GID; 660 if ((mask & kAccessMask) != 0) 661 fMetaCache.InvalidateAccess(); 662 663 return result; 664 } 665 666 667 inline status_t 668 Inode::CheckLockType(short ltype, uint32 mode) 669 { 670 switch (ltype) { 671 case F_UNLCK: 672 return B_OK; 673 674 case F_RDLCK: 675 if ((mode & O_RDONLY) == 0 && (mode & O_RDWR) == 0) 676 return EBADF; 677 return B_OK; 678 679 case F_WRLCK: 680 if ((mode & O_WRONLY) == 0 && (mode & O_RDWR) == 0) 681 return EBADF; 682 return B_OK; 683 684 default: 685 return B_BAD_VALUE; 686 } 687 } 688 689 690 status_t 691 Inode::TestLock(OpenFileCookie* cookie, struct flock* lock) 692 { 693 ASSERT(cookie != NULL); 694 ASSERT(lock != NULL); 695 696 if (lock->l_type == F_UNLCK) 697 return B_OK; 698 699 status_t result = CheckLockType(lock->l_type, cookie->fMode); 700 if (result != B_OK) 701 return result; 702 703 LockType ltype = sGetLockType(lock->l_type, false); 704 uint64 position = lock->l_start; 705 uint64 length; 706 if (lock->l_len + lock->l_start == OFF_MAX) 707 length = UINT64_MAX; 708 else 709 length = lock->l_len; 710 711 bool conflict; 712 result = NFS4Inode::TestLock(cookie, <ype, &position, &length, conflict); 713 if (result != B_OK) 714 return result; 715 716 if (conflict) { 717 lock->l_type = sLockTypeToHaiku(ltype); 718 lock->l_start = static_cast<off_t>(position); 719 if (length >= OFF_MAX) 720 lock->l_len = OFF_MAX; 721 else 722 lock->l_len = static_cast<off_t>(length); 723 } else 724 lock->l_type = F_UNLCK; 725 726 return B_OK; 727 } 728 729 730 status_t 731 Inode::AcquireLock(OpenFileCookie* cookie, const struct flock* lock, 732 bool wait) 733 { 734 ASSERT(cookie != NULL); 735 ASSERT(lock != NULL); 736 737 OpenState* state = cookie->fOpenState; 738 739 status_t result = CheckLockType(lock->l_type, cookie->fMode); 740 if (result != B_OK) 741 return result; 742 743 thread_info info; 744 get_thread_info(find_thread(NULL), &info); 745 746 MutexLocker locker(state->fOwnerLock); 747 LockOwner* owner = state->GetLockOwner(info.team); 748 if (owner == NULL) 749 return B_NO_MEMORY; 750 751 LockInfo* linfo = new(std::nothrow) LockInfo(owner); 752 if (linfo == NULL) 753 return B_NO_MEMORY; 754 locker.Unlock(); 755 756 linfo->fStart = lock->l_start; 757 if (lock->l_len + lock->l_start == OFF_MAX) 758 linfo->fLength = UINT64_MAX; 759 else 760 linfo->fLength = lock->l_len; 761 linfo->fType = sGetLockType(lock->l_type, wait); 762 763 result = NFS4Inode::AcquireLock(cookie, linfo, wait); 764 if (result != B_OK) { 765 delete linfo; 766 return result; 767 } 768 769 MutexLocker _(state->fLocksLock); 770 state->AddLock(linfo); 771 cookie->AddLock(linfo); 772 773 return B_OK; 774 } 775 776 777 status_t 778 Inode::ReleaseLock(OpenFileCookie* cookie, const struct flock* lock) 779 { 780 ASSERT(cookie != NULL); 781 ASSERT(lock != NULL); 782 783 SyncAndCommit(); 784 785 LockInfo* prev = NULL; 786 787 thread_info info; 788 get_thread_info(find_thread(NULL), &info); 789 uint32 owner = info.team; 790 791 OpenState* state = cookie->fOpenState; 792 MutexLocker locker(state->fLocksLock); 793 LockInfo* linfo = state->fLocks; 794 while (linfo != NULL) { 795 if (linfo->fOwner->fOwner == owner && *linfo == *lock) { 796 state->RemoveLock(linfo, prev); 797 break; 798 } 799 800 prev = linfo; 801 linfo = linfo->fNext; 802 } 803 804 prev = NULL; 805 linfo = cookie->fLocks; 806 while (linfo != NULL) { 807 if (linfo->fOwner->fOwner == owner && *linfo == *lock) { 808 cookie->RemoveLock(linfo, prev); 809 break; 810 } 811 812 prev = linfo; 813 linfo = linfo->fCookieNext; 814 } 815 locker.Unlock(); 816 817 if (linfo == NULL) 818 return B_BAD_VALUE; 819 820 status_t result = NFS4Inode::ReleaseLock(cookie, linfo); 821 if (result != B_OK) 822 return result; 823 824 state->DeleteLock(linfo); 825 826 return B_OK; 827 } 828 829 830 status_t 831 Inode::ReleaseAllLocks(OpenFileCookie* cookie) 832 { 833 ASSERT(cookie != NULL); 834 835 if (cookie->fLocks) 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