Added support for in-kernel node monitoring ({add,remove}_node_listener()).
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34147 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -188,6 +188,10 @@ enum {
|
|||||||
REWIND_QUERY_REQUEST,
|
REWIND_QUERY_REQUEST,
|
||||||
REWIND_QUERY_REPLY,
|
REWIND_QUERY_REPLY,
|
||||||
|
|
||||||
|
// node monitoring
|
||||||
|
NODE_MONITORING_EVENT_REQUEST,
|
||||||
|
NODE_MONITORING_EVENT_REPLY,
|
||||||
|
|
||||||
// userland -> kernel requests
|
// userland -> kernel requests
|
||||||
// notifications
|
// notifications
|
||||||
NOTIFY_LISTENER_REQUEST,
|
NOTIFY_LISTENER_REQUEST,
|
||||||
@@ -241,6 +245,12 @@ enum {
|
|||||||
NOTIFY_IO_REQUEST_REQUEST,
|
NOTIFY_IO_REQUEST_REQUEST,
|
||||||
NOTIFY_IO_REQUEST_REPLY,
|
NOTIFY_IO_REQUEST_REPLY,
|
||||||
|
|
||||||
|
// node monitoring
|
||||||
|
ADD_NODE_LISTENER_REQUEST,
|
||||||
|
ADD_NODE_LISTENER_REPLY,
|
||||||
|
REMOVE_NODE_LISTENER_REQUEST,
|
||||||
|
REMOVE_NODE_LISTENER_REPLY,
|
||||||
|
|
||||||
// general reply
|
// general reply
|
||||||
RECEIPT_ACK_REPLY,
|
RECEIPT_ACK_REPLY,
|
||||||
|
|
||||||
@@ -1506,6 +1516,27 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark ----- node monitoring -----
|
||||||
|
|
||||||
|
|
||||||
|
// NodeMonitoringEventRequest
|
||||||
|
class NodeMonitoringEventRequest : public KernelRequest {
|
||||||
|
public:
|
||||||
|
NodeMonitoringEventRequest()
|
||||||
|
: KernelRequest(NODE_MONITORING_EVENT_REQUEST) {}
|
||||||
|
status_t GetAddressInfos(AddressInfo* infos, int32* count);
|
||||||
|
|
||||||
|
void* listener;
|
||||||
|
Address event;
|
||||||
|
};
|
||||||
|
|
||||||
|
// NodeMonitoringEventReply
|
||||||
|
class NodeMonitoringEventReply : public ReplyRequest {
|
||||||
|
public:
|
||||||
|
NodeMonitoringEventReply() : ReplyRequest(NODE_MONITORING_EVENT_REPLY) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
// #pragma mark ----- userland requests -----
|
// #pragma mark ----- userland requests -----
|
||||||
|
|
||||||
@@ -1893,6 +1924,43 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - node monitoring
|
||||||
|
|
||||||
|
|
||||||
|
// AddNodeListenerRequest
|
||||||
|
class AddNodeListenerRequest : public Request {
|
||||||
|
public:
|
||||||
|
AddNodeListenerRequest() : Request(ADD_NODE_LISTENER_REQUEST) {}
|
||||||
|
|
||||||
|
dev_t device;
|
||||||
|
ino_t node;
|
||||||
|
uint32 flags;
|
||||||
|
void* listener;
|
||||||
|
};
|
||||||
|
|
||||||
|
// AddNodeListenerReply
|
||||||
|
class AddNodeListenerReply : public ReplyRequest {
|
||||||
|
public:
|
||||||
|
AddNodeListenerReply() : ReplyRequest(ADD_NODE_LISTENER_REPLY) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
// RemoveNodeListenerRequest
|
||||||
|
class RemoveNodeListenerRequest : public Request {
|
||||||
|
public:
|
||||||
|
RemoveNodeListenerRequest() : Request(REMOVE_NODE_LISTENER_REQUEST) {}
|
||||||
|
|
||||||
|
dev_t device;
|
||||||
|
ino_t node;
|
||||||
|
void* listener;
|
||||||
|
};
|
||||||
|
|
||||||
|
// RemoveNodeListenerReply
|
||||||
|
class RemoveNodeListenerReply : public ReplyRequest {
|
||||||
|
public:
|
||||||
|
RemoveNodeListenerReply() : ReplyRequest(REMOVE_NODE_LISTENER_REPLY) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
//////////////////
|
//////////////////
|
||||||
// General Reply
|
// General Reply
|
||||||
|
|
||||||
@@ -2209,6 +2277,11 @@ do_for_request(Request* request, Task& task)
|
|||||||
return task((RewindQueryRequest*)request);
|
return task((RewindQueryRequest*)request);
|
||||||
case REWIND_QUERY_REPLY:
|
case REWIND_QUERY_REPLY:
|
||||||
return task((RewindQueryReply*)request);
|
return task((RewindQueryReply*)request);
|
||||||
|
// node monitoring
|
||||||
|
case NODE_MONITORING_EVENT_REQUEST:
|
||||||
|
return task((NodeMonitoringEventRequest*)request);
|
||||||
|
case NODE_MONITORING_EVENT_REPLY:
|
||||||
|
return task((NodeMonitoringEventReply*)request);
|
||||||
|
|
||||||
// userland -> kernel requests
|
// userland -> kernel requests
|
||||||
// notifications
|
// notifications
|
||||||
@@ -2303,6 +2376,15 @@ do_for_request(Request* request, Task& task)
|
|||||||
return task((NotifyIORequestRequest*)request);
|
return task((NotifyIORequestRequest*)request);
|
||||||
case NOTIFY_IO_REQUEST_REPLY:
|
case NOTIFY_IO_REQUEST_REPLY:
|
||||||
return task((NotifyIORequestReply*)request);
|
return task((NotifyIORequestReply*)request);
|
||||||
|
// node monitoring
|
||||||
|
case ADD_NODE_LISTENER_REQUEST:
|
||||||
|
return task((AddNodeListenerRequest*)request);
|
||||||
|
case ADD_NODE_LISTENER_REPLY:
|
||||||
|
return task((AddNodeListenerReply*)request);
|
||||||
|
case REMOVE_NODE_LISTENER_REQUEST:
|
||||||
|
return task((RemoveNodeListenerRequest*)request);
|
||||||
|
case REMOVE_NODE_LISTENER_REPLY:
|
||||||
|
return task((RemoveNodeListenerReply*)request);
|
||||||
// general reply
|
// general reply
|
||||||
case RECEIPT_ACK_REPLY:
|
case RECEIPT_ACK_REPLY:
|
||||||
return task((ReceiptAckReply*)request);
|
return task((ReceiptAckReply*)request);
|
||||||
@@ -2482,6 +2564,9 @@ using UserlandFSUtil::ReadQueryRequest;
|
|||||||
using UserlandFSUtil::ReadQueryReply;
|
using UserlandFSUtil::ReadQueryReply;
|
||||||
using UserlandFSUtil::RewindQueryRequest;
|
using UserlandFSUtil::RewindQueryRequest;
|
||||||
using UserlandFSUtil::RewindQueryReply;
|
using UserlandFSUtil::RewindQueryReply;
|
||||||
|
// node monitoring
|
||||||
|
using UserlandFSUtil::NodeMonitoringEventRequest;
|
||||||
|
using UserlandFSUtil::NodeMonitoringEventReply;
|
||||||
|
|
||||||
// userland -> kernel requests
|
// userland -> kernel requests
|
||||||
// notifications
|
// notifications
|
||||||
@@ -2532,6 +2617,11 @@ using UserlandFSUtil::WriteToIORequestRequest;
|
|||||||
using UserlandFSUtil::WriteToIORequestReply;
|
using UserlandFSUtil::WriteToIORequestReply;
|
||||||
using UserlandFSUtil::NotifyIORequestRequest;
|
using UserlandFSUtil::NotifyIORequestRequest;
|
||||||
using UserlandFSUtil::NotifyIORequestReply;
|
using UserlandFSUtil::NotifyIORequestReply;
|
||||||
|
// node monitoring
|
||||||
|
using UserlandFSUtil::AddNodeListenerRequest;
|
||||||
|
using UserlandFSUtil::AddNodeListenerReply;
|
||||||
|
using UserlandFSUtil::RemoveNodeListenerRequest;
|
||||||
|
using UserlandFSUtil::RemoveNodeListenerReply;
|
||||||
// general reply
|
// general reply
|
||||||
using UserlandFSUtil::ReceiptAckReply;
|
using UserlandFSUtil::ReceiptAckReply;
|
||||||
|
|
||||||
|
|||||||
@@ -3,10 +3,14 @@
|
|||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include "Volume.h"
|
#include "Volume.h"
|
||||||
|
|
||||||
#include <util/AutoLock.h>
|
#include <util/AutoLock.h>
|
||||||
|
|
||||||
|
#include <fs/node_monitor.h>
|
||||||
|
#include <Notifications.h>
|
||||||
|
|
||||||
#include "AutoLocker.h"
|
#include "AutoLocker.h"
|
||||||
#include "Compatibility.h"
|
#include "Compatibility.h"
|
||||||
#include "Debug.h"
|
#include "Debug.h"
|
||||||
@@ -20,16 +24,139 @@
|
|||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
#include "SingleReplyRequestHandler.h"
|
#include "SingleReplyRequestHandler.h"
|
||||||
|
|
||||||
|
|
||||||
// The time after which the notification thread times out at the port and
|
// The time after which the notification thread times out at the port and
|
||||||
// restarts the loop. Of interest only when the FS is deleted. It is the
|
// restarts the loop. Of interest only when the FS is deleted. It is the
|
||||||
// maximal time the destructor has to wait for the thread.
|
// maximal time the destructor has to wait for the thread.
|
||||||
static const bigtime_t kNotificationRequestTimeout = 50000; // 50 ms
|
static const bigtime_t kNotificationRequestTimeout = 50000; // 50 ms
|
||||||
|
|
||||||
// SelectSyncMap
|
|
||||||
|
// #pragma mark - SelectSyncMap
|
||||||
|
|
||||||
|
|
||||||
struct FileSystem::SelectSyncMap
|
struct FileSystem::SelectSyncMap
|
||||||
: public SynchronizedHashMap<HashKey32<selectsync*>, int32*> {
|
: public SynchronizedHashMap<HashKey32<selectsync*>, int32*> {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - NodeListenerKey
|
||||||
|
|
||||||
|
|
||||||
|
struct FileSystem::NodeListenerKey {
|
||||||
|
NodeListenerKey(void* clientListener, dev_t device, ino_t node)
|
||||||
|
:
|
||||||
|
fClientListener(clientListener),
|
||||||
|
fDevice(device),
|
||||||
|
fNode(node)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void* ClientListener() const
|
||||||
|
{
|
||||||
|
return fClientListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_t Device() const
|
||||||
|
{
|
||||||
|
return fDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
ino_t Node() const
|
||||||
|
{
|
||||||
|
return fNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 HashValue() const
|
||||||
|
{
|
||||||
|
return (uint32)(addr_t)fClientListener ^ (uint32)fDevice
|
||||||
|
^ (uint32)fNode ^ (uint32)(fNode >> 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const NodeListenerKey& other) const
|
||||||
|
{
|
||||||
|
return fClientListener == other.fClientListener
|
||||||
|
&& fDevice == other.fDevice && fNode == other.fNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void* fClientListener;
|
||||||
|
dev_t fDevice;
|
||||||
|
ino_t fNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - NodeListenerProxy
|
||||||
|
|
||||||
|
|
||||||
|
struct FileSystem::NodeListenerProxy : NodeListenerKey, NotificationListener {
|
||||||
|
NodeListenerProxy(FileSystem* fileSystem, void* clientListener,
|
||||||
|
dev_t device, ino_t node)
|
||||||
|
:
|
||||||
|
NodeListenerKey(clientListener, device, node),
|
||||||
|
fFileSystem(fileSystem)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void EventOccurred(NotificationService& service,
|
||||||
|
const KMessage* event)
|
||||||
|
{
|
||||||
|
fFileSystem->_NodeListenerEventOccurred(this, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeListenerProxy*& HashTableLink()
|
||||||
|
{
|
||||||
|
return fHashTableLink;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t StartListening(uint32 flags)
|
||||||
|
{
|
||||||
|
return add_node_listener(fDevice, fNode, flags, *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t StopListening()
|
||||||
|
{
|
||||||
|
return remove_node_listener(fDevice, fNode, *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
FileSystem* fFileSystem;
|
||||||
|
NodeListenerProxy* fHashTableLink;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - NodeListenerHashDefinition
|
||||||
|
|
||||||
|
|
||||||
|
struct FileSystem::NodeListenerHashDefinition {
|
||||||
|
typedef NodeListenerKey KeyType;
|
||||||
|
typedef NodeListenerProxy ValueType;
|
||||||
|
|
||||||
|
size_t HashKey(const NodeListenerKey& key) const
|
||||||
|
{
|
||||||
|
return key.HashValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Hash(const NodeListenerProxy* value) const
|
||||||
|
{
|
||||||
|
return value->HashValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Compare(const NodeListenerKey& key,
|
||||||
|
const NodeListenerProxy* value) const
|
||||||
|
{
|
||||||
|
return key == *value;
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeListenerProxy*& GetLink(NodeListenerProxy* value) const
|
||||||
|
{
|
||||||
|
return value->HashTableLink();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - FileSystem
|
||||||
|
|
||||||
|
|
||||||
// constructor
|
// constructor
|
||||||
FileSystem::FileSystem()
|
FileSystem::FileSystem()
|
||||||
:
|
:
|
||||||
@@ -47,6 +174,7 @@ FileSystem::FileSystem()
|
|||||||
{
|
{
|
||||||
mutex_init(&fVolumeLock, "userlandfs volumes");
|
mutex_init(&fVolumeLock, "userlandfs volumes");
|
||||||
mutex_init(&fVNodeOpsLock, "userlandfs vnode ops");
|
mutex_init(&fVNodeOpsLock, "userlandfs vnode ops");
|
||||||
|
mutex_init(&fNodeListenersLock, "userlandfs node listeners");
|
||||||
}
|
}
|
||||||
|
|
||||||
// destructor
|
// destructor
|
||||||
@@ -61,6 +189,17 @@ FileSystem::~FileSystem()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// delete our data structures
|
// delete our data structures
|
||||||
|
if (fNodeListeners != NULL) {
|
||||||
|
MutexLocker nodeListenersLocker(fNodeListenersLock);
|
||||||
|
NodeListenerProxy* proxy = fNodeListeners->Clear(true);
|
||||||
|
while (proxy != NULL) {
|
||||||
|
NodeListenerProxy* next = proxy->HashTableLink();
|
||||||
|
proxy->StopListening();
|
||||||
|
delete proxy;
|
||||||
|
proxy = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (fSelectSyncs) {
|
if (fSelectSyncs) {
|
||||||
for (SelectSyncMap::Iterator it = fSelectSyncs->GetIterator();
|
for (SelectSyncMap::Iterator it = fSelectSyncs->GetIterator();
|
||||||
it.HasNext();) {
|
it.HasNext();) {
|
||||||
@@ -69,6 +208,7 @@ FileSystem::~FileSystem()
|
|||||||
}
|
}
|
||||||
delete fSelectSyncs;
|
delete fSelectSyncs;
|
||||||
}
|
}
|
||||||
|
|
||||||
delete fSettings;
|
delete fSettings;
|
||||||
|
|
||||||
// delete vnode ops vectors -- there shouldn't be any left, though
|
// delete vnode ops vectors -- there shouldn't be any left, though
|
||||||
@@ -82,6 +222,11 @@ FileSystem::~FileSystem()
|
|||||||
}
|
}
|
||||||
if (count > 0)
|
if (count > 0)
|
||||||
WARN(("Deleted %ld vnode ops vectors!\n", count));
|
WARN(("Deleted %ld vnode ops vectors!\n", count));
|
||||||
|
|
||||||
|
|
||||||
|
mutex_destroy(&fVolumeLock);
|
||||||
|
mutex_destroy(&fVNodeOpsLock);
|
||||||
|
mutex_destroy(&fNodeListenersLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init
|
// Init
|
||||||
@@ -113,6 +258,11 @@ FileSystem::Init(const char* name, team_id team, Port::Info* infos, int32 count,
|
|||||||
if (!fSelectSyncs)
|
if (!fSelectSyncs)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
// create the node listener proxy map
|
||||||
|
fNodeListeners = new(std::nothrow) NodeListenerMap;
|
||||||
|
if (fNodeListeners == NULL || fNodeListeners->Init() != B_OK)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
// create the request ports
|
// create the request ports
|
||||||
// the notification port
|
// the notification port
|
||||||
fNotificationPort = new(nothrow) RequestPort(infos);
|
fNotificationPort = new(nothrow) RequestPort(infos);
|
||||||
@@ -348,6 +498,57 @@ FileSystem::KnowsSelectSyncEntry(selectsync* sync)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// AddNodeListener
|
||||||
|
status_t
|
||||||
|
FileSystem::AddNodeListener(dev_t device, ino_t node, uint32 flags,
|
||||||
|
void* listener)
|
||||||
|
{
|
||||||
|
MutexLocker nodeListenersLocker(fNodeListenersLock);
|
||||||
|
|
||||||
|
// lookup the proxy
|
||||||
|
NodeListenerProxy* proxy = fNodeListeners->Lookup(
|
||||||
|
NodeListenerKey(listener, device, node));
|
||||||
|
if (proxy != NULL)
|
||||||
|
return proxy->StartListening(flags);
|
||||||
|
|
||||||
|
// it doesn't exist yet -- create it
|
||||||
|
proxy = new(std::nothrow) NodeListenerProxy(this, listener, device, node);
|
||||||
|
if (proxy == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
// start listening
|
||||||
|
status_t error = proxy->StartListening(flags);
|
||||||
|
if (error != B_OK) {
|
||||||
|
delete proxy;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
fNodeListeners->Insert(proxy);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// RemoveNodeListener
|
||||||
|
status_t
|
||||||
|
FileSystem::RemoveNodeListener(dev_t device, ino_t node, void* listener)
|
||||||
|
{
|
||||||
|
MutexLocker nodeListenersLocker(fNodeListenersLock);
|
||||||
|
|
||||||
|
// lookup the proxy
|
||||||
|
NodeListenerProxy* proxy = fNodeListeners->Lookup(
|
||||||
|
NodeListenerKey(listener, device, node));
|
||||||
|
if (proxy == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
status_t error = proxy->StopListening();
|
||||||
|
|
||||||
|
fNodeListeners->Remove(proxy);
|
||||||
|
delete proxy;
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// GetVNodeOps
|
// GetVNodeOps
|
||||||
VNodeOps*
|
VNodeOps*
|
||||||
FileSystem::GetVNodeOps(const FSVNodeCapabilities& capabilities)
|
FileSystem::GetVNodeOps(const FSVNodeCapabilities& capabilities)
|
||||||
@@ -508,6 +709,42 @@ FileSystem::_InitVNodeOpsVector(fs_vnode_ops* ops,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// _NodeListenerEventOccurred
|
||||||
|
void
|
||||||
|
FileSystem::_NodeListenerEventOccurred(NodeListenerProxy* proxy,
|
||||||
|
const KMessage* event)
|
||||||
|
{
|
||||||
|
// get a free port
|
||||||
|
RequestPort* port = fPortPool.AcquirePort();
|
||||||
|
if (port == NULL)
|
||||||
|
return;
|
||||||
|
PortReleaser _(&fPortPool, port);
|
||||||
|
|
||||||
|
// prepare the request
|
||||||
|
RequestAllocator allocator(port->GetPort());
|
||||||
|
NodeMonitoringEventRequest* request;
|
||||||
|
status_t error = AllocateRequest(allocator, &request);
|
||||||
|
if (error != B_OK)
|
||||||
|
return;
|
||||||
|
|
||||||
|
error = allocator.AllocateData(request->event, event->Buffer(),
|
||||||
|
event->ContentSize(), 1);
|
||||||
|
if (error != B_OK)
|
||||||
|
return;
|
||||||
|
|
||||||
|
struct thread* thread = thread_get_current_thread();
|
||||||
|
request->team = thread->team->id;
|
||||||
|
request->thread = thread->id;
|
||||||
|
request->user = geteuid();
|
||||||
|
request->group = getegid();
|
||||||
|
request->listener = proxy->ClientListener();
|
||||||
|
|
||||||
|
// send the request
|
||||||
|
KernelRequestHandler handler(this, NODE_MONITORING_EVENT_REPLY);
|
||||||
|
port->SendRequest(&allocator, &handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// _NotificationThreadEntry
|
// _NotificationThreadEntry
|
||||||
int32
|
int32
|
||||||
FileSystem::_NotificationThreadEntry(void* data)
|
FileSystem::_NotificationThreadEntry(void* data)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#ifndef USERLAND_FS_FILE_SYSTEM_H
|
#ifndef USERLAND_FS_FILE_SYSTEM_H
|
||||||
#define USERLAND_FS_FILE_SYSTEM_H
|
#define USERLAND_FS_FILE_SYSTEM_H
|
||||||
|
|
||||||
|
|
||||||
#include <fs_interface.h>
|
#include <fs_interface.h>
|
||||||
|
|
||||||
#include <util/OpenHashTable.h>
|
#include <util/OpenHashTable.h>
|
||||||
@@ -21,6 +22,7 @@
|
|||||||
|
|
||||||
|
|
||||||
struct IOCtlInfo;
|
struct IOCtlInfo;
|
||||||
|
class KMessage;
|
||||||
class Settings;
|
class Settings;
|
||||||
class Volume;
|
class Volume;
|
||||||
|
|
||||||
@@ -93,25 +95,40 @@ public:
|
|||||||
void RemoveSelectSyncEntry(selectsync* sync);
|
void RemoveSelectSyncEntry(selectsync* sync);
|
||||||
bool KnowsSelectSyncEntry(selectsync* sync);
|
bool KnowsSelectSyncEntry(selectsync* sync);
|
||||||
|
|
||||||
|
status_t AddNodeListener(dev_t device, ino_t node,
|
||||||
|
uint32 flags, void* listener);
|
||||||
|
status_t RemoveNodeListener(dev_t device, ino_t node,
|
||||||
|
void* listener);
|
||||||
|
|
||||||
VNodeOps* GetVNodeOps(
|
VNodeOps* GetVNodeOps(
|
||||||
const FSVNodeCapabilities& capabilities);
|
const FSVNodeCapabilities& capabilities);
|
||||||
void PutVNodeOps(VNodeOps* ops);
|
void PutVNodeOps(VNodeOps* ops);
|
||||||
|
|
||||||
bool IsUserlandServerThread() const;
|
bool IsUserlandServerThread() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class KernelDebug;
|
||||||
|
struct SelectSyncMap;
|
||||||
|
struct NodeListenerKey;
|
||||||
|
struct NodeListenerProxy;
|
||||||
|
struct NodeListenerHashDefinition;
|
||||||
|
|
||||||
|
typedef BOpenHashTable<VNodeOpsHashDefinition> VNodeOpsMap;
|
||||||
|
typedef BOpenHashTable<NodeListenerHashDefinition> NodeListenerMap;
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void _InitVNodeOpsVector(fs_vnode_ops* ops,
|
void _InitVNodeOpsVector(fs_vnode_ops* ops,
|
||||||
const FSVNodeCapabilities& capabilities);
|
const FSVNodeCapabilities& capabilities);
|
||||||
|
|
||||||
|
void _NodeListenerEventOccurred(
|
||||||
|
NodeListenerProxy* proxy,
|
||||||
|
const KMessage* event);
|
||||||
|
|
||||||
static int32 _NotificationThreadEntry(void* data);
|
static int32 _NotificationThreadEntry(void* data);
|
||||||
int32 _NotificationThread();
|
int32 _NotificationThread();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class KernelDebug;
|
|
||||||
struct SelectSyncEntry;
|
|
||||||
struct SelectSyncMap;
|
|
||||||
typedef BOpenHashTable<VNodeOpsHashDefinition> VNodeOpsMap;
|
|
||||||
|
|
||||||
Vector<Volume*> fVolumes;
|
Vector<Volume*> fVolumes;
|
||||||
mutex fVolumeLock;
|
mutex fVolumeLock;
|
||||||
VNodeOpsMap fVNodeOps;
|
VNodeOpsMap fVNodeOps;
|
||||||
@@ -123,6 +140,8 @@ private:
|
|||||||
thread_id fNotificationThread;
|
thread_id fNotificationThread;
|
||||||
RequestPortPool fPortPool;
|
RequestPortPool fPortPool;
|
||||||
SelectSyncMap* fSelectSyncs;
|
SelectSyncMap* fSelectSyncs;
|
||||||
|
mutex fNodeListenersLock;
|
||||||
|
NodeListenerMap* fNodeListeners;
|
||||||
Settings* fSettings;
|
Settings* fSettings;
|
||||||
team_id fUserlandServerTeam;
|
team_id fUserlandServerTeam;
|
||||||
bool fInitialized;
|
bool fInitialized;
|
||||||
|
|||||||
@@ -112,6 +112,11 @@ KernelRequestHandler::HandleRequest(Request* request)
|
|||||||
return _HandleRequest((WriteToIORequestRequest*)request);
|
return _HandleRequest((WriteToIORequestRequest*)request);
|
||||||
case NOTIFY_IO_REQUEST_REQUEST:
|
case NOTIFY_IO_REQUEST_REQUEST:
|
||||||
return _HandleRequest((NotifyIORequestRequest*)request);
|
return _HandleRequest((NotifyIORequestRequest*)request);
|
||||||
|
// node monitoring
|
||||||
|
case ADD_NODE_LISTENER_REQUEST:
|
||||||
|
return _HandleRequest((AddNodeListenerRequest*)request);
|
||||||
|
case REMOVE_NODE_LISTENER_REQUEST:
|
||||||
|
return _HandleRequest((RemoveNodeListenerRequest*)request);
|
||||||
}
|
}
|
||||||
PRINT(("KernelRequestHandler::HandleRequest(): unexpected request: %lu\n",
|
PRINT(("KernelRequestHandler::HandleRequest(): unexpected request: %lu\n",
|
||||||
request->GetType()));
|
request->GetType()));
|
||||||
@@ -842,6 +847,48 @@ KernelRequestHandler::_HandleRequest(NotifyIORequestRequest* request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
KernelRequestHandler::_HandleRequest(AddNodeListenerRequest* request)
|
||||||
|
{
|
||||||
|
// check and execute the request
|
||||||
|
status_t result = fFileSystem->AddNodeListener(request->device,
|
||||||
|
request->node, request->flags, request->listener);
|
||||||
|
|
||||||
|
// prepare the reply
|
||||||
|
RequestAllocator allocator(fPort->GetPort());
|
||||||
|
AddNodeListenerReply* reply;
|
||||||
|
status_t error = AllocateRequest(allocator, &reply);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
reply->error = result;
|
||||||
|
|
||||||
|
// send the reply
|
||||||
|
return fPort->SendRequest(&allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
KernelRequestHandler::_HandleRequest(RemoveNodeListenerRequest* request)
|
||||||
|
{
|
||||||
|
// check and execute the request
|
||||||
|
status_t result = fFileSystem->RemoveNodeListener(request->device,
|
||||||
|
request->node, request->listener);
|
||||||
|
|
||||||
|
// prepare the reply
|
||||||
|
RequestAllocator allocator(fPort->GetPort());
|
||||||
|
RemoveNodeListenerReply* reply;
|
||||||
|
status_t error = AllocateRequest(allocator, &reply);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
reply->error = result;
|
||||||
|
|
||||||
|
// send the reply
|
||||||
|
return fPort->SendRequest(&allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// _GetVolume
|
// _GetVolume
|
||||||
status_t
|
status_t
|
||||||
KernelRequestHandler::_GetVolume(dev_t id, Volume** volume)
|
KernelRequestHandler::_GetVolume(dev_t id, Volume** volume)
|
||||||
|
|||||||
@@ -80,6 +80,10 @@ private:
|
|||||||
status_t _HandleRequest(
|
status_t _HandleRequest(
|
||||||
WriteToIORequestRequest* request);
|
WriteToIORequestRequest* request);
|
||||||
status_t _HandleRequest(NotifyIORequestRequest* request);
|
status_t _HandleRequest(NotifyIORequestRequest* request);
|
||||||
|
// node monitoring
|
||||||
|
status_t _HandleRequest(AddNodeListenerRequest* request);
|
||||||
|
status_t _HandleRequest(
|
||||||
|
RemoveNodeListenerRequest* request);
|
||||||
|
|
||||||
status_t _GetVolume(dev_t id, Volume** volume);
|
status_t _GetVolume(dev_t id, Volume** volume);
|
||||||
|
|
||||||
|
|||||||
@@ -280,6 +280,14 @@ ReadQueryReply::GetAddressInfos(AddressInfo* infos, int32* count)
|
|||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NodeMonitoringEventRequest
|
||||||
|
status_t
|
||||||
|
NodeMonitoringEventRequest::GetAddressInfos(AddressInfo* infos, int32* count)
|
||||||
|
{
|
||||||
|
ADD_ADDRESS(event);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
// NotifyListenerRequest
|
// NotifyListenerRequest
|
||||||
status_t
|
status_t
|
||||||
NotifyListenerRequest::GetAddressInfos(AddressInfo* infos, int32* count)
|
NotifyListenerRequest::GetAddressInfos(AddressInfo* infos, int32* count)
|
||||||
@@ -687,6 +695,11 @@ UserlandFSUtil::is_kernel_request(uint32 type)
|
|||||||
case READ_QUERY_REPLY:
|
case READ_QUERY_REPLY:
|
||||||
case REWIND_QUERY_REPLY:
|
case REWIND_QUERY_REPLY:
|
||||||
return false;
|
return false;
|
||||||
|
// node monitoring
|
||||||
|
case NODE_MONITORING_EVENT_REQUEST:
|
||||||
|
return true;
|
||||||
|
case NODE_MONITORING_EVENT_REPLY:
|
||||||
|
return false;
|
||||||
|
|
||||||
// userland -> kernel requests
|
// userland -> kernel requests
|
||||||
// notifications
|
// notifications
|
||||||
@@ -745,6 +758,13 @@ UserlandFSUtil::is_kernel_request(uint32 type)
|
|||||||
case READ_FROM_IO_REQUEST_REPLY:
|
case READ_FROM_IO_REQUEST_REPLY:
|
||||||
case WRITE_TO_IO_REQUEST_REPLY:
|
case WRITE_TO_IO_REQUEST_REPLY:
|
||||||
return true;
|
return true;
|
||||||
|
// node monitoring
|
||||||
|
case ADD_NODE_LISTENER_REQUEST:
|
||||||
|
case REMOVE_NODE_LISTENER_REQUEST:
|
||||||
|
return false;
|
||||||
|
case ADD_NODE_LISTENER_REPLY:
|
||||||
|
case REMOVE_NODE_LISTENER_REPLY:
|
||||||
|
return true;
|
||||||
|
|
||||||
// general reply
|
// general reply
|
||||||
case RECEIPT_ACK_REPLY:
|
case RECEIPT_ACK_REPLY:
|
||||||
@@ -934,6 +954,11 @@ UserlandFSUtil::is_userland_request(uint32 type)
|
|||||||
case READ_QUERY_REPLY:
|
case READ_QUERY_REPLY:
|
||||||
case REWIND_QUERY_REPLY:
|
case REWIND_QUERY_REPLY:
|
||||||
return true;
|
return true;
|
||||||
|
// node monitoring
|
||||||
|
case NODE_MONITORING_EVENT_REQUEST:
|
||||||
|
return false;
|
||||||
|
case NODE_MONITORING_EVENT_REPLY:
|
||||||
|
return true;
|
||||||
|
|
||||||
// userland -> kernel requests
|
// userland -> kernel requests
|
||||||
// notifications
|
// notifications
|
||||||
@@ -992,6 +1017,13 @@ UserlandFSUtil::is_userland_request(uint32 type)
|
|||||||
case READ_FROM_IO_REQUEST_REPLY:
|
case READ_FROM_IO_REQUEST_REPLY:
|
||||||
case WRITE_TO_IO_REQUEST_REPLY:
|
case WRITE_TO_IO_REQUEST_REPLY:
|
||||||
return false;
|
return false;
|
||||||
|
// node monitoring
|
||||||
|
case ADD_NODE_LISTENER_REQUEST:
|
||||||
|
case REMOVE_NODE_LISTENER_REQUEST:
|
||||||
|
return true;
|
||||||
|
case ADD_NODE_LISTENER_REPLY:
|
||||||
|
case REMOVE_NODE_LISTENER_REPLY:
|
||||||
|
return false;
|
||||||
|
|
||||||
// general reply
|
// general reply
|
||||||
case RECEIPT_ACK_REPLY:
|
case RECEIPT_ACK_REPLY:
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ local userlandFSTop = [ FDirName $(HAIKU_TOP) src add-ons kernel
|
|||||||
local userlandFSIncludes = [ PrivateHeaders userlandfs ] ;
|
local userlandFSIncludes = [ PrivateHeaders userlandfs ] ;
|
||||||
|
|
||||||
SubDirSysHdrs [ FDirName $(userlandFSIncludes) ] ;
|
SubDirSysHdrs [ FDirName $(userlandFSIncludes) ] ;
|
||||||
UsePrivateHeaders kernel libroot shared ;
|
UsePrivateKernelHeaders ;
|
||||||
|
UsePrivateHeaders libroot shared ;
|
||||||
SubDirHdrs [ FDirName $(userlandFSIncludes) private ] ;
|
SubDirHdrs [ FDirName $(userlandFSIncludes) private ] ;
|
||||||
SubDirHdrs [ FDirName $(userlandFSIncludes) shared ] ;
|
SubDirHdrs [ FDirName $(userlandFSIncludes) shared ] ;
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,10 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <util/KMessage.h>
|
||||||
|
|
||||||
|
#include <Notifications.h>
|
||||||
|
|
||||||
#include "AutoDeleter.h"
|
#include "AutoDeleter.h"
|
||||||
#include "Compatibility.h"
|
#include "Compatibility.h"
|
||||||
#include "Debug.h"
|
#include "Debug.h"
|
||||||
@@ -208,6 +212,10 @@ UserlandRequestHandler::HandleRequest(Request* request)
|
|||||||
return _HandleRequest((ReadQueryRequest*)request);
|
return _HandleRequest((ReadQueryRequest*)request);
|
||||||
case REWIND_QUERY_REQUEST:
|
case REWIND_QUERY_REQUEST:
|
||||||
return _HandleRequest((RewindQueryRequest*)request);
|
return _HandleRequest((RewindQueryRequest*)request);
|
||||||
|
|
||||||
|
// node monitoring
|
||||||
|
case NODE_MONITORING_EVENT_REQUEST:
|
||||||
|
return _HandleRequest((NodeMonitoringEventRequest*)request);
|
||||||
}
|
}
|
||||||
PRINT(("UserlandRequestHandler::HandleRequest(): unexpected request: %lu\n",
|
PRINT(("UserlandRequestHandler::HandleRequest(): unexpected request: %lu\n",
|
||||||
request->GetType()));
|
request->GetType()));
|
||||||
@@ -2431,6 +2439,33 @@ UserlandRequestHandler::_HandleRequest(RewindQueryRequest* request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - node monitoring
|
||||||
|
|
||||||
|
|
||||||
|
// _HandleRequest
|
||||||
|
status_t
|
||||||
|
UserlandRequestHandler::_HandleRequest(NodeMonitoringEventRequest* request)
|
||||||
|
{
|
||||||
|
// check and execute the request
|
||||||
|
KMessage event;
|
||||||
|
event.SetTo(request->event.GetData(), request->event.GetSize());
|
||||||
|
((NotificationListener*)request->listener)->EventOccurred(
|
||||||
|
*(NotificationService*)NULL, &event);
|
||||||
|
|
||||||
|
// prepare the reply
|
||||||
|
RequestAllocator allocator(fPort->GetPort());
|
||||||
|
NodeMonitoringEventReply* reply;
|
||||||
|
status_t error = AllocateRequest(allocator, &reply);
|
||||||
|
if (error != B_OK)
|
||||||
|
RETURN_ERROR(error);
|
||||||
|
|
||||||
|
reply->error = B_OK;
|
||||||
|
|
||||||
|
// send the reply
|
||||||
|
return _SendReply(allocator, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - other
|
// #pragma mark - other
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -87,6 +87,8 @@ class CloseQueryRequest;
|
|||||||
class FreeQueryCookieRequest;
|
class FreeQueryCookieRequest;
|
||||||
class ReadQueryRequest;
|
class ReadQueryRequest;
|
||||||
class RewindQueryRequest;
|
class RewindQueryRequest;
|
||||||
|
// node monitoring
|
||||||
|
class NodeMonitoringEventRequest;
|
||||||
|
|
||||||
class RequestAllocator;
|
class RequestAllocator;
|
||||||
|
|
||||||
@@ -200,6 +202,10 @@ private:
|
|||||||
status_t _HandleRequest(ReadQueryRequest* request);
|
status_t _HandleRequest(ReadQueryRequest* request);
|
||||||
status_t _HandleRequest(RewindQueryRequest* request);
|
status_t _HandleRequest(RewindQueryRequest* request);
|
||||||
|
|
||||||
|
// node monitoring
|
||||||
|
status_t _HandleRequest(
|
||||||
|
NodeMonitoringEventRequest* request);
|
||||||
|
|
||||||
status_t _SendReply(RequestAllocator& allocator,
|
status_t _SendReply(RequestAllocator& allocator,
|
||||||
bool expectsReceipt);
|
bool expectsReceipt);
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ SharedLibrary libuserlandfs_haiku_kernel.so
|
|||||||
block_cache.cpp
|
block_cache.cpp
|
||||||
file_map.cpp
|
file_map.cpp
|
||||||
khash.c
|
khash.c
|
||||||
|
Notifications.cpp
|
||||||
Referenceable.cpp
|
Referenceable.cpp
|
||||||
|
|
||||||
# emulation
|
# emulation
|
||||||
@@ -55,6 +56,11 @@ SharedLibrary libuserlandfs_haiku_kernel.so
|
|||||||
$(TARGET_LIBSUPC++)
|
$(TARGET_LIBSUPC++)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
|
SEARCH on [ FGristFiles
|
||||||
|
Notifications.cpp
|
||||||
|
] = [ FDirName $(HAIKU_TOP) src system kernel ] ;
|
||||||
|
|
||||||
SEARCH on [ FGristFiles
|
SEARCH on [ FGristFiles
|
||||||
block_cache.cpp
|
block_cache.cpp
|
||||||
file_map.cpp
|
file_map.cpp
|
||||||
|
|||||||
@@ -14,6 +14,8 @@
|
|||||||
#include <KernelExport.h>
|
#include <KernelExport.h>
|
||||||
#include <NodeMonitor.h>
|
#include <NodeMonitor.h>
|
||||||
|
|
||||||
|
#include <fs/node_monitor.h>
|
||||||
|
|
||||||
#include "Debug.h"
|
#include "Debug.h"
|
||||||
|
|
||||||
#include "../FileSystem.h"
|
#include "../FileSystem.h"
|
||||||
@@ -366,6 +368,25 @@ notify_io_request(io_request* _request, status_t status)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - node monitoring
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
add_node_listener(dev_t device, ino_t node, uint32 flags,
|
||||||
|
NotificationListener& listener)
|
||||||
|
{
|
||||||
|
return UserlandFS::KernelEmu::add_node_listener(device, node, flags,
|
||||||
|
&listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
remove_node_listener(dev_t device, ino_t node, NotificationListener& listener)
|
||||||
|
{
|
||||||
|
return UserlandFS::KernelEmu::remove_node_listener(device, node, &listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - Disk Device Manager
|
// #pragma mark - Disk Device Manager
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1009,6 +1009,80 @@ UserlandFS::KernelEmu::notify_io_request(dev_t volumeID, int32 requestID,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - node monitoring
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
UserlandFS::KernelEmu::add_node_listener(dev_t device, ino_t node, uint32 flags,
|
||||||
|
void* listener)
|
||||||
|
{
|
||||||
|
// get the request port and the file system
|
||||||
|
RequestPort* port;
|
||||||
|
FileSystem* fileSystem;
|
||||||
|
status_t error = get_port_and_fs(&port, &fileSystem);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
// prepare the request
|
||||||
|
RequestAllocator allocator(port->GetPort());
|
||||||
|
AddNodeListenerRequest* request;
|
||||||
|
error = AllocateRequest(allocator, &request);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
request->device = device;
|
||||||
|
request->node = node;
|
||||||
|
request->flags = flags;
|
||||||
|
request->listener = listener;
|
||||||
|
|
||||||
|
// send the request
|
||||||
|
UserlandRequestHandler handler(fileSystem, ADD_NODE_LISTENER_REPLY);
|
||||||
|
AddNodeListenerReply* reply;
|
||||||
|
error = port->SendRequest(&allocator, &handler, (Request**)&reply);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
RequestReleaser requestReleaser(port, reply);
|
||||||
|
|
||||||
|
// process the reply
|
||||||
|
return reply->error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
UserlandFS::KernelEmu::remove_node_listener(dev_t device, ino_t node,
|
||||||
|
void* listener)
|
||||||
|
{
|
||||||
|
// get the request port and the file system
|
||||||
|
RequestPort* port;
|
||||||
|
FileSystem* fileSystem;
|
||||||
|
status_t error = get_port_and_fs(&port, &fileSystem);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
// prepare the request
|
||||||
|
RequestAllocator allocator(port->GetPort());
|
||||||
|
RemoveNodeListenerRequest* request;
|
||||||
|
error = AllocateRequest(allocator, &request);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
request->device = device;
|
||||||
|
request->node = node;
|
||||||
|
request->listener = listener;
|
||||||
|
|
||||||
|
// send the request
|
||||||
|
UserlandRequestHandler handler(fileSystem, REMOVE_NODE_LISTENER_REPLY);
|
||||||
|
RemoveNodeListenerReply* reply;
|
||||||
|
error = port->SendRequest(&allocator, &handler, (Request**)&reply);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
RequestReleaser requestReleaser(port, reply);
|
||||||
|
|
||||||
|
// process the reply
|
||||||
|
return reply->error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -56,6 +56,10 @@ status_t write_to_io_request(dev_t volumeID, int32 requestID, const void* buffer
|
|||||||
size_t size);
|
size_t size);
|
||||||
status_t notify_io_request(dev_t volumeID, int32 requestID, status_t status);
|
status_t notify_io_request(dev_t volumeID, int32 requestID, status_t status);
|
||||||
|
|
||||||
|
status_t add_node_listener(dev_t device, ino_t node, uint32 flags,
|
||||||
|
void* listener);
|
||||||
|
status_t remove_node_listener(dev_t device, ino_t node, void* listener);
|
||||||
|
|
||||||
void kernel_debugger(const char *message);
|
void kernel_debugger(const char *message);
|
||||||
void vpanic(const char *format, va_list args);
|
void vpanic(const char *format, va_list args);
|
||||||
void panic(const char *format, ...) __attribute__ ((format (__printf__, 1, 2)));
|
void panic(const char *format, ...) __attribute__ ((format (__printf__, 1, 2)));
|
||||||
|
|||||||
Reference in New Issue
Block a user