1 /*
2 * Copyright 2001-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7 #include "Volume.h"
8
9 #include <util/AutoLock.h>
10
11 #include <thread.h>
12 #include <fs/node_monitor.h>
13 #include <Notifications.h>
14
15 #include "AutoLocker.h"
16 #include "Compatibility.h"
17 #include "Debug.h"
18 #include "FileSystem.h"
19 #include "HashMap.h"
20 #include "kernel_interface.h"
21 #include "KernelRequestHandler.h"
22 #include "PortReleaser.h"
23 #include "RequestAllocator.h"
24 #include "Requests.h"
25 #include "Settings.h"
26 #include "SingleReplyRequestHandler.h"
27
28
29 // The time after which the notification thread times out at the port and
30 // restarts the loop. Of interest only when the FS is deleted. It is the
31 // maximal time the destructor has to wait for the thread.
32 static const bigtime_t kNotificationRequestTimeout = 50000; // 50 ms
33
34
35 // #pragma mark - SelectSyncMap
36
37
38 struct FileSystem::SelectSyncMap
39 : public SynchronizedHashMap<HashKeyPointer<selectsync*>, int32*, Locker> {
40 };
41
42
43 // #pragma mark - NodeListenerKey
44
45
46 struct FileSystem::NodeListenerKey {
NodeListenerKeyFileSystem::NodeListenerKey47 NodeListenerKey(void* clientListener, dev_t device, ino_t node)
48 :
49 fClientListener(clientListener),
50 fDevice(device),
51 fNode(node)
52 {
53 }
54
ClientListenerFileSystem::NodeListenerKey55 void* ClientListener() const
56 {
57 return fClientListener;
58 }
59
DeviceFileSystem::NodeListenerKey60 dev_t Device() const
61 {
62 return fDevice;
63 }
64
NodeFileSystem::NodeListenerKey65 ino_t Node() const
66 {
67 return fNode;
68 }
69
HashValueFileSystem::NodeListenerKey70 uint32 HashValue() const
71 {
72 return (uint32)(addr_t)fClientListener ^ (uint32)fDevice
73 ^ (uint32)fNode ^ (uint32)(fNode >> 32);
74 }
75
operator ==FileSystem::NodeListenerKey76 bool operator==(const NodeListenerKey& other) const
77 {
78 return fClientListener == other.fClientListener
79 && fDevice == other.fDevice && fNode == other.fNode;
80 }
81
82 protected:
83 void* fClientListener;
84 dev_t fDevice;
85 ino_t fNode;
86 };
87
88
89 // #pragma mark - NodeListenerProxy
90
91
92 struct FileSystem::NodeListenerProxy : NodeListenerKey, NotificationListener {
NodeListenerProxyFileSystem::NodeListenerProxy93 NodeListenerProxy(FileSystem* fileSystem, void* clientListener,
94 dev_t device, ino_t node)
95 :
96 NodeListenerKey(clientListener, device, node),
97 fFileSystem(fileSystem)
98 {
99 }
100
EventOccurredFileSystem::NodeListenerProxy101 virtual void EventOccurred(NotificationService& service,
102 const KMessage* event)
103 {
104 fFileSystem->_NodeListenerEventOccurred(this, event);
105 }
106
HashTableLinkFileSystem::NodeListenerProxy107 NodeListenerProxy*& HashTableLink()
108 {
109 return fHashTableLink;
110 }
111
StartListeningFileSystem::NodeListenerProxy112 status_t StartListening(uint32 flags)
113 {
114 return add_node_listener(fDevice, fNode, flags, *this);
115 }
116
StopListeningFileSystem::NodeListenerProxy117 status_t StopListening()
118 {
119 return remove_node_listener(fDevice, fNode, *this);
120 }
121
122 private:
123 FileSystem* fFileSystem;
124 NodeListenerProxy* fHashTableLink;
125 };
126
127
128 // #pragma mark - NodeListenerHashDefinition
129
130
131 struct FileSystem::NodeListenerHashDefinition {
132 typedef NodeListenerKey KeyType;
133 typedef NodeListenerProxy ValueType;
134
HashKeyFileSystem::NodeListenerHashDefinition135 size_t HashKey(const NodeListenerKey& key) const
136 {
137 return key.HashValue();
138 }
139
HashFileSystem::NodeListenerHashDefinition140 size_t Hash(const NodeListenerProxy* value) const
141 {
142 return value->HashValue();
143 }
144
CompareFileSystem::NodeListenerHashDefinition145 bool Compare(const NodeListenerKey& key,
146 const NodeListenerProxy* value) const
147 {
148 return key == *value;
149 }
150
GetLinkFileSystem::NodeListenerHashDefinition151 NodeListenerProxy*& GetLink(NodeListenerProxy* value) const
152 {
153 return value->HashTableLink();
154 }
155 };
156
157
158 // #pragma mark - FileSystem
159
160
161 // constructor
FileSystem()162 FileSystem::FileSystem()
163 :
164 fVolumes(),
165 fName(),
166 fTeam(-1),
167 fNotificationPort(NULL),
168 fNotificationThread(-1),
169 fPortPool(),
170 fSelectSyncs(NULL),
171 fSettings(NULL),
172 fUserlandServerTeam(-1),
173 fInitialized(false),
174 fTerminating(false)
175 {
176 mutex_init(&fVolumeLock, "userlandfs volumes");
177 mutex_init(&fVNodeOpsLock, "userlandfs vnode ops");
178 mutex_init(&fNodeListenersLock, "userlandfs node listeners");
179 }
180
181 // destructor
~FileSystem()182 FileSystem::~FileSystem()
183 {
184 fTerminating = true;
185
186 // wait for the notification thread to terminate
187 if (fNotificationThread >= 0) {
188 int32 result;
189 wait_for_thread(fNotificationThread, &result);
190 }
191
192 // delete our data structures
193 if (fNodeListeners != NULL) {
194 MutexLocker nodeListenersLocker(fNodeListenersLock);
195 NodeListenerProxy* proxy = fNodeListeners->Clear(true);
196 while (proxy != NULL) {
197 NodeListenerProxy* next = proxy->HashTableLink();
198 proxy->StopListening();
199 delete proxy;
200 proxy = next;
201 }
202 }
203
204 if (fSelectSyncs) {
205 for (SelectSyncMap::Iterator it = fSelectSyncs->GetIterator();
206 it.HasNext();) {
207 SelectSyncMap::Entry entry = it.Next();
208 delete entry.value;
209 }
210 delete fSelectSyncs;
211 }
212
213 delete fSettings;
214
215 // delete vnode ops vectors -- there shouldn't be any left, though
216 VNodeOps* ops = fVNodeOps.Clear();
217 int32 count = 0;
218 while (ops != NULL) {
219 count++;
220 VNodeOps* next = ops->hash_link;
221 free(ops);
222 ops = next;
223 }
224 if (count > 0)
225 WARN(("Deleted %" B_PRId32 " vnode ops vectors!\n", count));
226
227
228 mutex_destroy(&fVolumeLock);
229 mutex_destroy(&fVNodeOpsLock);
230 mutex_destroy(&fNodeListenersLock);
231 }
232
233 // Init
234 status_t
Init(const char * name,team_id team,Port::Info * infos,int32 count,const FSCapabilities & capabilities)235 FileSystem::Init(const char* name, team_id team, Port::Info* infos, int32 count,
236 const FSCapabilities& capabilities)
237 {
238 PRINT(("FileSystem::Init(\"%s\", %p, %" B_PRId32 ")\n", name, infos,
239 count));
240 capabilities.Dump();
241
242 // check parameters
243 if (!name || !infos || count < 2)
244 RETURN_ERROR(B_BAD_VALUE);
245
246 // set the name
247 if (!fName.SetTo(name))
248 return B_NO_MEMORY;
249
250 // init VNodeOps map
251 status_t error = fVNodeOps.Init();
252 if (error != B_OK)
253 return error;
254
255 fTeam = team;
256 fCapabilities = capabilities;
257
258 // create the select sync entry map
259 fSelectSyncs = new(nothrow) SelectSyncMap;
260 if (!fSelectSyncs)
261 return B_NO_MEMORY;
262
263 // create the node listener proxy map
264 fNodeListeners = new(std::nothrow) NodeListenerMap;
265 if (fNodeListeners == NULL || fNodeListeners->Init() != B_OK)
266 return B_NO_MEMORY;
267
268 // create the request ports
269 // the notification port
270 fNotificationPort = new(nothrow) RequestPort(infos);
271 if (!fNotificationPort)
272 RETURN_ERROR(B_NO_MEMORY);
273 error = fNotificationPort->InitCheck();
274 if (error != B_OK)
275 return error;
276
277 // the other request ports
278 for (int32 i = 1; i < count; i++) {
279 RequestPort* port = new(nothrow) RequestPort(infos + i);
280 if (!port)
281 RETURN_ERROR(B_NO_MEMORY);
282 error = port->InitCheck();
283 if (error == B_OK)
284 error = fPortPool.AddPort(port);
285 if (error != B_OK) {
286 delete port;
287 RETURN_ERROR(error);
288 }
289 }
290
291 // get the userland team
292 port_info portInfo;
293 error = get_port_info(infos[0].owner_port, &portInfo);
294 if (error != B_OK)
295 RETURN_ERROR(error);
296 fUserlandServerTeam = portInfo.team;
297
298 // print some info about the userland team
299 D(
300 PRINT((" userland team is: %" B_PRId32 "\n", fUserlandServerTeam));
301 int32 cookie = 0;
302 thread_info threadInfo;
303 while (get_next_thread_info(fUserlandServerTeam, &cookie, &threadInfo)
304 == B_OK) {
305 PRINT((" userland thread: %" B_PRId32 ": `%s'\n",
306 threadInfo.thread, threadInfo.name));
307 }
308 );
309
310 // load the settings
311 fSettings = new(nothrow) Settings;
312 if (fSettings) {
313 status_t settingsError = fSettings->SetTo(fName.GetString());
314 if (settingsError != B_OK) {
315 PRINT(("Failed to load settings: %s\n", strerror(settingsError)));
316 delete fSettings;
317 fSettings = NULL;
318 } else
319 fSettings->Dump();
320 } else
321 ERROR(("Failed to allocate settings.\n"));
322
323 // spawn the notification thread
324 #if USER
325 fNotificationThread = spawn_thread(_NotificationThreadEntry,
326 "UFS notification thread", B_NORMAL_PRIORITY, this);
327 #else
328 fNotificationThread = spawn_kernel_thread(_NotificationThreadEntry,
329 "UFS notification thread", B_NORMAL_PRIORITY, this);
330 #endif
331 if (fNotificationThread < 0)
332 RETURN_ERROR(fNotificationThread);
333 resume_thread(fNotificationThread);
334
335 fInitialized = (error == B_OK);
336 RETURN_ERROR(error);
337 }
338
339 // GetName
340 const char*
GetName() const341 FileSystem::GetName() const
342 {
343 return fName.GetString();
344 }
345
346 // GetCapabilities
347 const FSCapabilities&
GetCapabilities() const348 FileSystem::GetCapabilities() const
349 {
350 return fCapabilities;
351 }
352
353 // GetPortPool
354 RequestPortPool*
GetPortPool()355 FileSystem::GetPortPool()
356 {
357 return &fPortPool;
358 }
359
360 // Mount
361 status_t
Mount(fs_volume * fsVolume,const char * device,uint32 flags,const char * parameters,Volume ** _volume)362 FileSystem::Mount(fs_volume* fsVolume, const char* device, uint32 flags,
363 const char* parameters, Volume** _volume)
364 {
365 // check initialization and parameters
366 if (!fInitialized || !_volume)
367 return B_BAD_VALUE;
368
369 // create volume
370 Volume* volume = new(nothrow) Volume(this, fsVolume);
371 if (!volume)
372 return B_NO_MEMORY;
373
374 // add volume to the volume list
375 MutexLocker locker(fVolumeLock);
376 status_t error = fVolumes.PushBack(volume);
377 locker.Unlock();
378 if (error != B_OK)
379 return error;
380
381 // mount volume
382 error = volume->Mount(device, flags, parameters);
383 if (error != B_OK) {
384 MutexLocker locker(fVolumeLock);
385 fVolumes.Remove(volume);
386 locker.Unlock();
387 volume->ReleaseReference();
388 return error;
389 }
390
391 *_volume = volume;
392 return error;
393 }
394
395 // Initialize
396 /*status_t
397 FileSystem::Initialize(const char* deviceName, const char* parameters,
398 size_t len)
399 {
400 // get a free port
401 RequestPort* port = fPortPool.AcquirePort();
402 if (!port)
403 return B_ERROR;
404 PortReleaser _(&fPortPool, port);
405 // prepare the request
406 RequestAllocator allocator(port->GetPort());
407 MountVolumeRequest* request;
408 status_t error = AllocateRequest(allocator, &request);
409 if (error != B_OK)
410 return error;
411 error = allocator.AllocateString(request->device, deviceName);
412 if (error == B_OK)
413 error = allocator.AllocateData(request->parameters, parameters, len, 1);
414 if (error != B_OK)
415 return error;
416 // send the request
417 SingleReplyRequestHandler handler(MOUNT_VOLUME_REPLY);
418 InitializeVolumeReply* reply;
419 error = port->SendRequest(&allocator, &handler, (Request**)&reply);
420 if (error != B_OK)
421 return error;
422 RequestReleaser requestReleaser(port, reply);
423 // process the reply
424 if (reply->error != B_OK)
425 return reply->error;
426 return error;
427 }*/
428
429 // VolumeUnmounted
430 void
VolumeUnmounted(Volume * volume)431 FileSystem::VolumeUnmounted(Volume* volume)
432 {
433 MutexLocker locker(fVolumeLock);
434 fVolumes.Remove(volume);
435 }
436
437 // GetVolume
438 Volume*
GetVolume(dev_t id)439 FileSystem::GetVolume(dev_t id)
440 {
441 MutexLocker _(fVolumeLock);
442 for (Vector<Volume*>::Iterator it = fVolumes.Begin();
443 it != fVolumes.End();
444 it++) {
445 Volume* volume = *it;
446 if (volume->GetID() == id) {
447 volume->AcquireReference();
448 return volume;
449 }
450 }
451 return NULL;
452 }
453
454 // GetIOCtlInfo
455 const IOCtlInfo*
GetIOCtlInfo(int command) const456 FileSystem::GetIOCtlInfo(int command) const
457 {
458 return (fSettings ? fSettings->GetIOCtlInfo(command) : NULL);
459 }
460
461 // AddSelectSyncEntry
462 status_t
AddSelectSyncEntry(selectsync * sync)463 FileSystem::AddSelectSyncEntry(selectsync* sync)
464 {
465 AutoLocker<SelectSyncMap> _(fSelectSyncs);
466 int32* count = fSelectSyncs->Get(sync);
467 if (!count) {
468 count = new(nothrow) int32(0);
469 if (!count)
470 return B_NO_MEMORY;
471 status_t error = fSelectSyncs->Put(sync, count);
472 if (error != B_OK) {
473 delete count;
474 return error;
475 }
476 }
477 (*count)++;
478 return B_OK;
479 }
480
481 // RemoveSelectSyncEntry
482 void
RemoveSelectSyncEntry(selectsync * sync)483 FileSystem::RemoveSelectSyncEntry(selectsync* sync)
484 {
485 AutoLocker<SelectSyncMap> _(fSelectSyncs);
486 if (int32* count = fSelectSyncs->Get(sync)) {
487 if (--(*count) <= 0) {
488 fSelectSyncs->Remove(sync);
489 delete count;
490 }
491 }
492 }
493
494
495 // KnowsSelectSyncEntry
496 bool
KnowsSelectSyncEntry(selectsync * sync)497 FileSystem::KnowsSelectSyncEntry(selectsync* sync)
498 {
499 return fSelectSyncs->ContainsKey(sync);
500 }
501
502
503 // AddNodeListener
504 status_t
AddNodeListener(dev_t device,ino_t node,uint32 flags,void * listener)505 FileSystem::AddNodeListener(dev_t device, ino_t node, uint32 flags,
506 void* listener)
507 {
508 MutexLocker nodeListenersLocker(fNodeListenersLock);
509
510 // lookup the proxy
511 NodeListenerProxy* proxy = fNodeListeners->Lookup(
512 NodeListenerKey(listener, device, node));
513 if (proxy != NULL)
514 return proxy->StartListening(flags);
515
516 // it doesn't exist yet -- create it
517 proxy = new(std::nothrow) NodeListenerProxy(this, listener, device, node);
518 if (proxy == NULL)
519 return B_NO_MEMORY;
520
521 // start listening
522 status_t error = proxy->StartListening(flags);
523 if (error != B_OK) {
524 delete proxy;
525 return error;
526 }
527
528 fNodeListeners->Insert(proxy);
529 return B_OK;
530 }
531
532
533 // RemoveNodeListener
534 status_t
RemoveNodeListener(dev_t device,ino_t node,void * listener)535 FileSystem::RemoveNodeListener(dev_t device, ino_t node, void* listener)
536 {
537 MutexLocker nodeListenersLocker(fNodeListenersLock);
538
539 // lookup the proxy
540 NodeListenerProxy* proxy = fNodeListeners->Lookup(
541 NodeListenerKey(listener, device, node));
542 if (proxy == NULL)
543 return B_BAD_VALUE;
544
545 status_t error = proxy->StopListening();
546
547 fNodeListeners->Remove(proxy);
548 delete proxy;
549
550 return error;
551 }
552
553
554 // GetVNodeOps
555 VNodeOps*
GetVNodeOps(const FSVNodeCapabilities & capabilities)556 FileSystem::GetVNodeOps(const FSVNodeCapabilities& capabilities)
557 {
558 MutexLocker locker(fVNodeOpsLock);
559
560 // do we already have ops for those capabilities
561 VNodeOps* ops = fVNodeOps.Lookup(capabilities);
562 if (ops != NULL) {
563 ops->refCount++;
564 return ops;
565 }
566
567 // no, create a new object
568 fs_vnode_ops* opsVector = new(std::nothrow) fs_vnode_ops;
569 if (opsVector == NULL)
570 return NULL;
571
572 // set the operations
573 _InitVNodeOpsVector(opsVector, capabilities);
574
575 // create the VNodeOps object
576 ops = new(std::nothrow) VNodeOps(capabilities, opsVector);
577 if (ops == NULL) {
578 delete opsVector;
579 return NULL;
580 }
581
582 fVNodeOps.Insert(ops);
583
584 return ops;
585 }
586
587
588 // PutVNodeOps
589 void
PutVNodeOps(VNodeOps * ops)590 FileSystem::PutVNodeOps(VNodeOps* ops)
591 {
592 MutexLocker locker(fVNodeOpsLock);
593
594 if (--ops->refCount == 0) {
595 fVNodeOps.Remove(ops);
596 delete ops;
597 }
598 }
599
600
601 // IsUserlandServerThread
602 bool
IsUserlandServerThread() const603 FileSystem::IsUserlandServerThread() const
604 {
605 thread_info info;
606 get_thread_info(find_thread(NULL), &info);
607 return (info.team == fUserlandServerTeam);
608 }
609
610
611 // _InitVNodeOpsVector
612 void
_InitVNodeOpsVector(fs_vnode_ops * ops,const FSVNodeCapabilities & capabilities)613 FileSystem::_InitVNodeOpsVector(fs_vnode_ops* ops,
614 const FSVNodeCapabilities& capabilities)
615 {
616 memcpy(ops, &gUserlandFSVnodeOps, sizeof(fs_vnode_ops));
617
618 #undef CLEAR_UNSUPPORTED
619 #define CLEAR_UNSUPPORTED(capability, op) \
620 if (!capabilities.Get(capability)) \
621 ops->op = NULL
622
623 // vnode operations
624 // FS_VNODE_CAPABILITY_LOOKUP: lookup
625 // FS_VNODE_CAPABILITY_GET_VNODE_NAME: get_vnode_name
626 // emulated in userland
627 // FS_VNODE_CAPABILITY_PUT_VNODE: put_vnode
628 // FS_VNODE_CAPABILITY_REMOVE_VNODE: remove_vnode
629 // needed by Volume to clean up
630
631 // asynchronous I/O
632 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_IO, io);
633 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_CANCEL_IO, cancel_io);
634
635 // cache file access
636 ops->get_file_map = NULL; // never used
637
638 // common operations
639 // FS_VNODE_CAPABILITY_IOCTL: ioctl
640 // needed by Volume
641 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_SET_FLAGS, set_flags);
642 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_SELECT, select);
643 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_DESELECT, deselect);
644 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_FSYNC, fsync);
645
646 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_READ_SYMLINK, read_symlink);
647 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_CREATE_SYMLINK, create_symlink);
648
649 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_LINK, link);
650 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_UNLINK, unlink);
651 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_RENAME, rename);
652
653 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_ACCESS, access);
654 // FS_VNODE_CAPABILITY_READ_STAT: read_stat
655 // needed by Volume
656 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_WRITE_STAT, write_stat);
657
658 // file operations
659 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_CREATE, create);
660 // FS_VNODE_CAPABILITY_OPEN: open
661 // mandatory
662 // FS_VNODE_CAPABILITY_CLOSE: close
663 // needed by Volume
664 // FS_VNODE_CAPABILITY_FREE_COOKIE: free_cookie
665 // needed by Volume
666 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_READ, read);
667 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_WRITE, write);
668
669 // directory operations
670 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_CREATE_DIR, create_dir);
671 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_REMOVE_DIR, remove_dir);
672 // FS_VNODE_CAPABILITY_OPEN_DIR: open_dir
673 // mandatory
674 // FS_VNODE_CAPABILITY_CLOSE_DIR: close_dir
675 // needed by Volume
676 // FS_VNODE_CAPABILITY_FREE_DIR_COOKIE: free_dir_cookie
677 // needed by Volume
678 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_READ_DIR, read_dir);
679 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_REWIND_DIR, rewind_dir);
680
681 // attribute directory operations
682 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_OPEN_ATTR_DIR, open_attr_dir);
683 // FS_VNODE_CAPABILITY_CLOSE_ATTR_DIR: close_attr_dir
684 // needed by Volume
685 // FS_VNODE_CAPABILITY_FREE_ATTR_DIR_COOKIE: free_attr_dir_cookie
686 // needed by Volume
687 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_READ_ATTR_DIR, read_attr_dir);
688 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_REWIND_ATTR_DIR, rewind_attr_dir);
689
690 // attribute operations
691 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_CREATE_ATTR, create_attr);
692 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_OPEN_ATTR, open_attr);
693 // FS_VNODE_CAPABILITY_CLOSE_ATTR: close_attr
694 // needed by Volume
695 // FS_VNODE_CAPABILITY_FREE_ATTR_COOKIE: free_attr_cookie
696 // needed by Volume
697 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_READ_ATTR, read_attr);
698 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_WRITE_ATTR, write_attr);
699
700 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_READ_ATTR_STAT, read_attr_stat);
701 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_WRITE_ATTR_STAT, write_attr_stat);
702 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_RENAME_ATTR, rename_attr);
703 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_REMOVE_ATTR, remove_attr);
704
705 // support for node and FS layers
706 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_CREATE_SPECIAL_NODE,
707 create_special_node);
708 CLEAR_UNSUPPORTED(FS_VNODE_CAPABILITY_GET_SUPER_VNODE, get_super_vnode);
709
710 #undef CLEAR_UNSUPPORTED
711 }
712
713
714 // _NodeListenerEventOccurred
715 void
_NodeListenerEventOccurred(NodeListenerProxy * proxy,const KMessage * event)716 FileSystem::_NodeListenerEventOccurred(NodeListenerProxy* proxy,
717 const KMessage* event)
718 {
719 // get a free port
720 RequestPort* port = fPortPool.AcquirePort();
721 if (port == NULL)
722 return;
723 PortReleaser _(&fPortPool, port);
724
725 // prepare the request
726 RequestAllocator allocator(port->GetPort());
727 NodeMonitoringEventRequest* request;
728 status_t error = AllocateRequest(allocator, &request);
729 if (error != B_OK)
730 return;
731
732 error = allocator.AllocateData(request->event, event->Buffer(),
733 event->ContentSize(), 1);
734 if (error != B_OK)
735 return;
736
737 Thread* thread = thread_get_current_thread();
738 request->team = thread->team->id;
739 request->thread = thread->id;
740 request->user = geteuid();
741 request->group = getegid();
742 request->listener = proxy->ClientListener();
743
744 // send the request
745 KernelRequestHandler handler(this, NODE_MONITORING_EVENT_REPLY);
746 port->SendRequest(&allocator, &handler);
747 }
748
749
750 // _NotificationThreadEntry
751 int32
_NotificationThreadEntry(void * data)752 FileSystem::_NotificationThreadEntry(void* data)
753 {
754 return ((FileSystem*)data)->_NotificationThread();
755 }
756
757
758 // _NotificationThread
759 int32
_NotificationThread()760 FileSystem::_NotificationThread()
761 {
762 // process the notification requests until the FS is deleted
763 while (!fTerminating) {
764 if (fNotificationPort->InitCheck() != B_OK)
765 return fNotificationPort->InitCheck();
766 KernelRequestHandler handler(this, NO_REQUEST);
767 fNotificationPort->HandleRequests(&handler, NULL,
768 kNotificationRequestTimeout);
769 }
770 // We eat all remaining notification requests, so that they aren't
771 // presented to the file system, when it is mounted next time.
772 // TODO: We should probably use a special handler that sends an ack reply,
773 // but ignores the requests otherwise.
774 KernelRequestHandler handler(this, NO_REQUEST);
775 fNotificationPort->HandleRequests(&handler, NULL, 0);
776 return 0;
777 }
778
779