btrfs: [] on the end of a struct field is a variable length array.
[haiku.git] / src / add-ons / kernel / file_systems / nfs4 / Inode.cpp
blob9e186fc02ba269b998b119d6496bd68b6e7280f8
1 /*
2 * Copyright 2012-2016 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Paweł Dziepak, pdziepak@quarnos.org
7 */
10 #include "Inode.h"
12 #include <ctype.h>
13 #include <string.h>
15 #include <AutoDeleter.h>
16 #include <fs_cache.h>
17 #include <NodeMonitor.h>
19 #include "IdMap.h"
20 #include "Request.h"
21 #include "RootInode.h"
24 Inode::Inode()
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)
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);
45 status_t
46 Inode::CreateInode(FileSystem* fs, const FileInfo& fi, Inode** _inode)
48 ASSERT(fs != NULL);
49 ASSERT(_inode != NULL);
51 Inode* inode = NULL;
52 if (fs->Root() == NULL)
53 inode = new(std::nothrow) RootInode;
54 else
55 inode = new(std::nothrow) Inode;
57 if (inode == NULL)
58 return B_NO_MEMORY;
60 inode->fInfo = fi;
61 inode->fFileSystem = fs;
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();
70 req.PutFH(inode->fInfo.fHandle);
72 Attribute attr[] = { FATTR4_TYPE, FATTR4_CHANGE, FATTR4_SIZE,
73 FATTR4_FSID, FATTR4_FILEID };
74 req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
76 status_t result = request.Send();
77 if (result != B_OK)
78 return result;
80 ReplyInterpreter& reply = request.Reply();
82 if (inode->HandleErrors(attempt, reply.NFS4Error(), serv))
83 continue;
85 reply.PutFH();
87 AttrValue* values;
88 uint32 count;
89 result = reply.GetAttr(&values, &count);
90 if (result != B_OK)
91 return result;
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;
101 // FATTR4_TYPE is mandatory
102 inode->fType = values[0].fData.fValue32;
104 if (inode->fType == NF4DIR)
105 inode->fCache = new DirectoryCache(inode);
106 inode->fAttrCache = new DirectoryCache(inode, true);
108 // FATTR4_CHANGE is mandatory
109 inode->fChange = values[1].fData.fValue64;
111 // FATTR4_SIZE is mandatory
112 size = values[2].fData.fValue64;
113 inode->fMaxFileSize = size;
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;
123 delete[] values;
125 *_inode = inode;
127 break;
128 } while (true);
130 if (inode->fType == NF4REG)
131 inode->fFileCache = file_cache_create(fs->DevId(), inode->ID(), size);
133 return B_OK;
137 Inode::~Inode()
139 if (fDelegation != NULL)
140 RecallDelegation();
142 if (fFileCache != NULL)
143 file_cache_delete(fFileCache);
145 delete fCache;
146 delete fAttrCache;
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);
155 ASSERT(fAIOCount == 0);
159 status_t
160 Inode::RevalidateFileCache()
162 if (fDelegation != NULL)
163 return B_OK;
165 uint64 change;
166 status_t result = GetChangeInfo(&change);
167 if (result != B_OK)
168 return result;
170 MutexLocker _(fFileCacheLock);
171 if (change == fChange)
172 return B_OK;
173 SyncAndCommit(true);
175 file_cache_delete(fFileCache);
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);
184 change = fChange;
185 return B_OK;
189 status_t
190 Inode::LookUp(const char* name, ino_t* id)
192 ASSERT(name != NULL);
193 ASSERT(id != NULL);
195 if (fType != NF4DIR)
196 return B_NOT_A_DIRECTORY;
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;
205 *id = FileIdToInoT(fileID);
207 result = ChildAdded(name, fileID, handle);
208 if (result != B_OK)
209 return result;
211 fCache->Lock();
212 if (!fCache->Valid()) {
213 fCache->Reset();
214 fCache->SetChangeInfo(change);
215 } else
216 fCache->ValidateChangeInfo(change);
218 fCache->AddEntry(name, *id);
219 fCache->Unlock();
221 return B_OK;
225 status_t
226 Inode::Link(Inode* dir, const char* name)
228 ASSERT(dir != NULL);
229 ASSERT(name != NULL);
231 ChangeInfo changeInfo;
232 status_t result = NFS4Inode::Link(dir, name, &changeInfo);
233 if (result != B_OK)
234 return result;
236 fFileSystem->Root()->MakeInfoInvalid();
237 fInfo.fNames->AddName(dir->fInfo.fNames, name);
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();
248 dir->fCache->Unlock();
250 notify_entry_created(fFileSystem->DevId(), dir->ID(), name, ID());
252 return B_OK;
256 status_t
257 Inode::Remove(const char* name, FileType type, ino_t* id)
259 ASSERT(name != NULL);
261 MemoryDeleter nameDeleter;
262 if (type == NF4NAMEDATTR) {
263 status_t result = LoadAttrDirHandle();
264 if (result != B_OK)
265 return result;
267 name = AttrToFileName(name);
268 if (name == NULL)
269 return B_NO_MEMORY;
270 nameDeleter.SetTo(const_cast<char*>(name));
273 ChangeInfo changeInfo;
274 uint64 fileID;
275 status_t result = NFS4Inode::RemoveObject(name, type, &changeInfo, &fileID);
276 if (result != B_OK)
277 return result;
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();
289 cache->Unlock();
291 fFileSystem->Root()->MakeInfoInvalid();
292 if (id != NULL)
293 *id = FileIdToInoT(fileID);
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));
303 return B_OK;
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)
311 ASSERT(from != NULL);
312 ASSERT(fromName != NULL);
313 ASSERT(to != NULL);
314 ASSERT(toName != NULL);
316 if (from->fFileSystem != to->fFileSystem)
317 return B_DONT_DO_THAT;
319 MemoryDeleter fromNameDeleter;
320 MemoryDeleter toNameDeleter;
321 if (attribute) {
322 status_t result = from->LoadAttrDirHandle();
323 if (result != B_OK)
324 return result;
326 result = to->LoadAttrDirHandle();
327 if (result != B_OK)
328 return result;
330 fromName = from->AttrToFileName(fromName);
331 toName = to->AttrToFileName(toName);
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;
339 uint64 oldFileID = 0;
340 if (!attribute)
341 to->NFS4Inode::LookUp(toName, NULL, &oldFileID, NULL);
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;
350 from->fFileSystem->Root()->MakeInfoInvalid();
352 if (id != NULL)
353 *id = FileIdToInoT(fileID);
354 if (oldID != NULL)
355 *oldID = FileIdToInoT(oldFileID);
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();
368 cache->Unlock();
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();
381 cache->Unlock();
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));
394 return B_OK;
398 status_t
399 Inode::CreateLink(const char* name, const char* path, int mode, ino_t* id)
401 return CreateObject(name, path, mode, NF4LNK, id);
405 status_t
406 Inode::CreateObject(const char* name, const char* path, int mode, FileType type,
407 ino_t* id)
409 ASSERT(name != NULL);
410 ASSERT(type != NF4LNK || path != NULL);
412 ChangeInfo changeInfo;
413 uint64 fileID;
414 FileHandle handle;
416 status_t result = NFS4Inode::CreateObject(name, path, mode, type,
417 &changeInfo, &fileID, &handle);
418 if (result != B_OK)
419 return result;
421 fFileSystem->Root()->MakeInfoInvalid();
423 result = ChildAdded(name, fileID, handle);
424 if (result != B_OK)
425 return result;
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();
435 fCache->Unlock();
437 notify_entry_created(fFileSystem->DevId(), ID(), name,
438 FileIdToInoT(fileID));
440 *id = FileIdToInoT(fileID);
441 return B_OK;
445 status_t
446 Inode::Access(int mode)
448 int acc = 0;
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);
460 if ((allowed & ACCESS4_READ) != 0)
461 acc |= R_OK;
463 if ((allowed & ACCESS4_LOOKUP) != 0)
464 acc |= X_OK | R_OK;
466 if ((allowed & ACCESS4_EXECUTE) != 0)
467 acc |= X_OK;
469 if ((allowed & ACCESS4_MODIFY) != 0)
470 acc |= W_OK;
472 if ((mode & acc) != mode)
473 return B_NOT_ALLOWED;
475 return B_OK;
479 status_t
480 Inode::Stat(struct stat* st, OpenAttrCookie* attr)
482 ASSERT(st != NULL);
484 if (attr != NULL)
485 return GetStat(st, attr);
487 bool cache = fFileSystem->GetConfiguration().fCacheMetadata;
488 if (!cache)
489 return GetStat(st, NULL);
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);
501 return B_OK;
505 status_t
506 Inode::GetStat(struct stat* st, OpenAttrCookie* attr)
508 ASSERT(st != NULL);
510 AttrValue* values;
511 uint32 count;
512 status_t result = NFS4Inode::GetStat(&values, &count, attr);
513 if (result != B_OK)
514 return result;
516 // FATTR4_SIZE is mandatory
517 if (count < 1 || values[0].fAttribute != FATTR4_SIZE) {
518 delete[] values;
519 return B_BAD_VALUE;
521 st->st_size = values[0].fData.fValue64;
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;
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;
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;
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;
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));
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));
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));
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;
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;
590 return B_OK;
594 status_t
595 Inode::WriteStat(const struct stat* st, uint32 mask, OpenAttrCookie* cookie)
597 ASSERT(st != NULL);
599 status_t result;
600 AttrValue attr[6];
601 uint32 i = 0;
603 if ((mask & B_STAT_SIZE) != 0) {
604 fMaxFileSize = st->st_size;
605 file_cache_set_size(fFileCache, st->st_size);
607 attr[i].fAttribute = FATTR4_SIZE;
608 attr[i].fFreePointer = false;
609 attr[i].fData.fValue64 = st->st_size;
610 i++;
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++;
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++;
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++;
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++;
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++;
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);
657 fMetaCache.InvalidateStat();
659 const uint32 kAccessMask = B_STAT_MODE | B_STAT_UID | B_STAT_GID;
660 if ((mask & kAccessMask) != 0)
661 fMetaCache.InvalidateAccess();
663 return result;
667 inline status_t
668 Inode::CheckLockType(short ltype, uint32 mode)
670 switch (ltype) {
671 case F_UNLCK:
672 return B_OK;
674 case F_RDLCK:
675 if ((mode & O_RDONLY) == 0 && (mode & O_RDWR) == 0)
676 return EBADF;
677 return B_OK;
679 case F_WRLCK:
680 if ((mode & O_WRONLY) == 0 && (mode & O_RDWR) == 0)
681 return EBADF;
682 return B_OK;
684 default:
685 return B_BAD_VALUE;
690 status_t
691 Inode::TestLock(OpenFileCookie* cookie, struct flock* lock)
693 ASSERT(cookie != NULL);
694 ASSERT(lock != NULL);
696 if (lock->l_type == F_UNLCK)
697 return B_OK;
699 status_t result = CheckLockType(lock->l_type, cookie->fMode);
700 if (result != B_OK)
701 return result;
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;
711 bool conflict;
712 result = NFS4Inode::TestLock(cookie, &ltype, &position, &length, conflict);
713 if (result != B_OK)
714 return result;
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;
726 return B_OK;
730 status_t
731 Inode::AcquireLock(OpenFileCookie* cookie, const struct flock* lock,
732 bool wait)
734 ASSERT(cookie != NULL);
735 ASSERT(lock != NULL);
737 OpenState* state = cookie->fOpenState;
739 status_t result = CheckLockType(lock->l_type, cookie->fMode);
740 if (result != B_OK)
741 return result;
743 thread_info info;
744 get_thread_info(find_thread(NULL), &info);
746 MutexLocker locker(state->fOwnerLock);
747 LockOwner* owner = state->GetLockOwner(info.team);
748 if (owner == NULL)
749 return B_NO_MEMORY;
751 LockInfo* linfo = new(std::nothrow) LockInfo(owner);
752 if (linfo == NULL)
753 return B_NO_MEMORY;
754 locker.Unlock();
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);
763 result = NFS4Inode::AcquireLock(cookie, linfo, wait);
764 if (result != B_OK) {
765 delete linfo;
766 return result;
769 MutexLocker _(state->fLocksLock);
770 state->AddLock(linfo);
771 cookie->AddLock(linfo);
773 return B_OK;
777 status_t
778 Inode::ReleaseLock(OpenFileCookie* cookie, const struct flock* lock)
780 ASSERT(cookie != NULL);
781 ASSERT(lock != NULL);
783 SyncAndCommit();
785 LockInfo* prev = NULL;
787 thread_info info;
788 get_thread_info(find_thread(NULL), &info);
789 uint32 owner = info.team;
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;
800 prev = linfo;
801 linfo = linfo->fNext;
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;
812 prev = linfo;
813 linfo = linfo->fCookieNext;
815 locker.Unlock();
817 if (linfo == NULL)
818 return B_BAD_VALUE;
820 status_t result = NFS4Inode::ReleaseLock(cookie, linfo);
821 if (result != B_OK)
822 return result;
824 state->DeleteLock(linfo);
826 return B_OK;
830 status_t
831 Inode::ReleaseAllLocks(OpenFileCookie* cookie)
833 ASSERT(cookie != NULL);
835 if (cookie->fLocks)
836 SyncAndCommit();
838 OpenState* state = cookie->fOpenState;
839 MutexLocker _(state->fLocksLock);
840 LockInfo* linfo = cookie->fLocks;
841 while (linfo != NULL) {
842 cookie->RemoveLock(linfo, NULL);
844 LockInfo* prev = NULL;
845 LockInfo* stateLock = state->fLocks;
846 while (stateLock != NULL) {
847 if (*linfo == *stateLock) {
848 state->RemoveLock(stateLock, prev);
849 break;
852 prev = stateLock;
853 stateLock = stateLock->fNext;
856 NFS4Inode::ReleaseLock(cookie, linfo);
857 state->DeleteLock(linfo);
859 linfo = cookie->fLocks;
862 return B_OK;
866 status_t
867 Inode::ChildAdded(const char* name, uint64 fileID,
868 const FileHandle& fileHandle)
870 ASSERT(name != NULL);
872 fFileSystem->Root()->MakeInfoInvalid();
874 FileInfo fi;
875 fi.fFileId = fileID;
876 fi.fHandle = fileHandle;
878 return fFileSystem->InoIdMap()->AddName(fi, fInfo.fNames, name,
879 FileIdToInoT(fileID));
883 const char*
884 Inode::Name() const
886 ASSERT(fInfo.fNames->fNames.Head() != NULL);
887 return fInfo.fNames->fNames.Head()->fName;
891 void
892 Inode::SetDelegation(Delegation* delegation)
894 ASSERT(delegation != NULL);
896 WriteLocker _(fDelegationLock);
898 fMetaCache.InvalidateStat();
899 struct stat st;
900 Stat(&st);
901 fMetaCache.LockValid();
903 fDelegation = delegation;
904 fOpenState->AcquireReference();
905 fOpenState->fDelegation = delegation;
906 fFileSystem->AddDelegation(delegation);
910 void
911 Inode::RecallDelegation(bool truncate)
913 WriteLocker _(fDelegationLock);
914 if (fDelegation == NULL)
915 return;
916 ReturnDelegation(truncate);
920 void
921 Inode::RecallReadDelegation()
923 WriteLocker _(fDelegationLock);
924 if (fDelegation == NULL || fDelegation->Type() != OPEN_DELEGATE_READ)
925 return;
926 ReturnDelegation(false);
930 void
931 Inode::ReturnDelegation(bool truncate)
933 ASSERT(fDelegation != NULL);
935 fDelegation->GiveUp(truncate);
937 fMetaCache.UnlockValid();
938 fFileSystem->RemoveDelegation(fDelegation);
940 MutexLocker stateLocker(fStateLock);
941 fOpenState->fDelegation = NULL;
942 ReleaseOpenState();
944 delete fDelegation;
945 fDelegation = NULL;
949 void
950 Inode::ReleaseOpenState()
952 ASSERT(fOpenState != NULL);
954 if (fOpenState->ReleaseReference() == 1) {
955 ASSERT(fAIOCount == 0);
956 fOpenState = NULL;
961 status_t
962 Inode::SyncAndCommit(bool force)
964 if (!force && fDelegation != NULL)
965 return B_OK;
967 file_cache_sync(fFileCache);
968 WaitAIOComplete();
969 return Commit();
973 void
974 Inode::BeginAIOOp()
976 MutexLocker _(fAIOLock);
977 fAIOCount++;
978 if (fAIOCount == 1)
979 acquire_sem(fAIOWait);
983 void
984 Inode::EndAIOOp()
986 MutexLocker _(fAIOLock);
987 ASSERT(fAIOCount > 0);
988 fAIOCount--;
989 if (fAIOCount == 0)
990 release_sem(fAIOWait);