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
Inode()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
CreateInode(FileSystem * fs,const FileInfo & fi,Inode ** _inode)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
~Inode()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
RevalidateFileCache()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
LookUp(const char * name,ino_t * id)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
Link(Inode * dir,const char * name)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
Remove(const char * name,FileType type,ino_t * id)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
Rename(Inode * from,Inode * to,const char * fromName,const char * toName,bool attribute,ino_t * id,ino_t * oldID)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
CreateLink(const char * name,const char * path,int mode,ino_t * id)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
CreateObject(const char * name,const char * path,int mode,FileType type,ino_t * id)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
Access(int mode)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
Stat(struct stat * st,OpenAttrCookie * attr)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
GetStat(struct stat * st,OpenAttrCookie * attr)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
WriteStat(const struct stat * st,uint32 mask,OpenAttrCookie * cookie)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
CheckLockType(short ltype,uint32 mode)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
TestLock(OpenFileCookie * cookie,struct flock * lock)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
AcquireLock(OpenFileCookie * cookie,const struct flock * lock,bool wait)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
ReleaseLock(OpenFileCookie * cookie,const struct flock * lock)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
ReleaseAllLocks(OpenFileCookie * cookie)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
ChildAdded(const char * name,uint64 fileID,const FileHandle & fileHandle)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*
Name() const884 Inode::Name() const
885 {
886 ASSERT(fInfo.fNames->fNames.Head() != NULL);
887 return fInfo.fNames->fNames.Head()->fName;
888 }
889
890
891 void
SetDelegation(Delegation * delegation)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
RecallDelegation(bool truncate)911 Inode::RecallDelegation(bool truncate)
912 {
913 WriteLocker _(fDelegationLock);
914 if (fDelegation == NULL)
915 return;
916 ReturnDelegation(truncate);
917 }
918
919
920 void
RecallReadDelegation()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
ReturnDelegation(bool truncate)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
ReleaseOpenState()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
SyncAndCommit(bool force)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
BeginAIOOp()974 Inode::BeginAIOOp()
975 {
976 MutexLocker _(fAIOLock);
977 fAIOCount++;
978 if (fAIOCount == 1)
979 acquire_sem(fAIOWait);
980 }
981
982
983 void
EndAIOOp()984 Inode::EndAIOOp()
985 {
986 MutexLocker _(fAIOLock);
987 ASSERT(fAIOCount > 0);
988 fAIOCount--;
989 if (fAIOCount == 0)
990 release_sem(fAIOWait);
991 }
992
993