diff --git a/src/kernel/core/fs/pipefs.cpp b/src/kernel/core/fs/pipefs.cpp index 1f9de396ec..3d24d91186 100644 --- a/src/kernel/core/fs/pipefs.cpp +++ b/src/kernel/core/fs/pipefs.cpp @@ -7,6 +7,8 @@ #include #include +#include +#include #include #include #include @@ -21,10 +23,12 @@ #include "builtin_fs.h" +namespace pipefs { + // ToDo: handles file names suboptimally - it has all file names // in a single linked list, no hash lookups or whatever. -#define PIPEFS_TRACE 0 +#define PIPEFS_TRACE 1 #if PIPEFS_TRACE # define TRACE(x) dprintf x @@ -32,108 +36,239 @@ # define TRACE(x) #endif -struct pipefs_vnode { - pipefs_vnode *next; - pipefs_vnode *hash_next; - vnode_id id; - int32 type; - char *name; +struct read_request { + read_request *next; + void *buffer; + size_t buffer_size; + size_t bytes_read; }; +class ReadRequests { + public: + ReadRequests(); + ~ReadRequests(); + + status_t Lock(); + status_t Unlock(); + + status_t Add(read_request &request); + status_t Remove(read_request &request); + + private: + benaphore fLock; + read_request *fFirst, *fCurrent, *fLast; +}; + +class Inode; +struct dir_cookie; + +class Volume { + public: + Volume(mount_id id); + ~Volume(); + + status_t InitCheck(); + mount_id ID() const { return fID; } + Inode &RootNode() const { return *fRootNode; } + + void Lock(); + void Unlock(); + + Inode *Lookup(vnode_id id); + Inode *FindNode(const char *name); + Inode *CreateNode(const char *name, int32 type); + status_t DeleteNode(Inode *inode, bool forceDelete = false); + status_t RemoveNode(Inode *directory, const char *name); + + vnode_id GetNextNodeID() { return fNextNodeID++; } + ReadRequests &GetReadRequests() { return fReadRequests; } + + Inode *FirstEntry() const { return fFirstEntry; } + + dir_cookie *FirstDirCookie() const { return fFirstDirCookie; } + void InsertCookie(dir_cookie *cookie); + + private: + void RemoveCookie(dir_cookie *cookie); + void UpdateDirCookies(Inode *inode); + + status_t RemoveNode(Inode *inode); + status_t InsertNode(Inode *inode); + + ReadRequests fReadRequests; + mutex fLock; + mount_id fID; + Inode *fRootNode; + vnode_id fNextNodeID; + hash_table *fNodeHash; + + // root directory contents - we don't support other directories + Inode *fFirstEntry; + dir_cookie *fFirstDirCookie; +}; + +class Inode { + public: + Inode(Volume *volume, const char *name, int32 type); + ~Inode(); + + status_t InitCheck(); + vnode_id ID() const { return fID; } + const char *Name() const { return fName; } + int32 Type() const { return fType; } + + Inode *Next() const { return fNext; } + void SetNext(Inode *inode) { fNext = inode; } + + benaphore *ReadLock() { return &fReadLock; } + benaphore *WriteLock() { return &fWriteLock; } + + static int32 HashNextOffset(); + static uint32 hash_func(void *_node, const void *_key, uint32 range); + static int compare_func(void *_node, const void *_key); + + + private: + Inode *fNext; + Inode *fHashNext; + vnode_id fID; + int32 fType; + const char *fName; + + benaphore fReadLock; + benaphore fWriteLock; +}; + + struct dir_cookie { dir_cookie *next; dir_cookie *prev; - pipefs_vnode *current; - int open_mode; + Inode *current; }; -struct pipefs { - mount_id id; - mutex lock; - vnode_id next_vnode_id; - hash_table *vnode_list_hash; - pipefs_vnode *root_vnode; - - // root directory contents - we don't support other directories - pipefs_vnode *first_entry; - dir_cookie *first_dir_cookie; +struct file_cookie { + int open_mode; }; #define PIPEFS_HASH_SIZE 16 -static uint32 -pipefs_vnode_hash_func(void *_vnode, const void *_key, uint32 range) +Volume::Volume(mount_id id) + : + fID(id), + fRootNode(NULL), + fNextNodeID(0), + fNodeHash(NULL), + fFirstEntry(NULL), + fFirstDirCookie(NULL) { - pipefs_vnode *vnode = (pipefs_vnode *)_vnode; - const vnode_id *key = (const vnode_id *)_key; + if (mutex_init(&fLock, "pipefs_mutex") < B_OK) + return; - if (vnode != NULL) - return vnode->id % range; + fNodeHash = hash_init(PIPEFS_HASH_SIZE, Inode::HashNextOffset(), + &Inode::compare_func, &Inode::hash_func); + if (fNodeHash == NULL) + return; - return (*key) % range; + // create the root vnode + fRootNode = CreateNode("", S_IFDIR); + if (fRootNode == NULL) + return; } -static int -pipefs_vnode_compare_func(void *_vnode, const void *_key) +Volume::~Volume() { - pipefs_vnode *vnode = (pipefs_vnode *)_vnode; - const vnode_id *key = (const vnode_id *)_key; + // put_vnode on the root to release the ref to it + if (fRootNode) + vfs_put_vnode(ID(), fRootNode->ID()); - if (vnode->id == *key) - return 0; + if (fNodeHash != NULL) { + // delete all of the inodes + struct hash_iterator i; + hash_open(fNodeHash, &i); - return -1; + Inode *inode; + while ((inode = (Inode *)hash_next(fNodeHash, &i)) != NULL) { + DeleteNode(inode, true); + } + + hash_close(fNodeHash, &i, false); + + hash_uninit(fNodeHash); + } + mutex_destroy(&fLock); } -static pipefs_vnode * -pipefs_create_vnode(pipefs *fs, const char *name, int32 type) +status_t +Volume::InitCheck() { - pipefs_vnode *vnode = (pipefs_vnode *)malloc(sizeof(pipefs_vnode)); - if (vnode == NULL) + if (fLock.sem < B_OK + || fRootNode == NULL) + return B_ERROR; + + return B_OK; +} + + +void +Volume::Lock() +{ + mutex_lock(&fLock); +} + + +void +Volume::Unlock() +{ + mutex_unlock(&fLock); +} + + +Inode * +Volume::CreateNode(const char *name, int32 type) +{ + Inode *inode = new Inode(this, name, type); + if (inode == NULL) return NULL; - vnode->name = strdup(name); - if (vnode->name == NULL) { - free(vnode); + if (inode->InitCheck() != B_OK) { + delete inode; return NULL; } - vnode->next = NULL; - vnode->id = fs->next_vnode_id++; - vnode->type = type; + if (type == S_IFIFO) + InsertNode(inode); + hash_insert(fNodeHash, inode); - return vnode; + return inode; } -static status_t -pipefs_delete_vnode(pipefs *fs, pipefs_vnode *vnode, bool forceDelete) +status_t +Volume::DeleteNode(Inode *inode, bool forceDelete) { // remove it from the global hash table - hash_remove(fs->vnode_list_hash, vnode); - - free(vnode->name); - free(vnode); + hash_remove(fNodeHash, inode); + delete inode; return 0; } -static void -insert_cookie_in_jar(pipefs *fs, dir_cookie *cookie) +void +Volume::InsertCookie(dir_cookie *cookie) { - cookie->next = fs->first_dir_cookie; - fs->first_dir_cookie = cookie; + cookie->next = fFirstDirCookie; + fFirstDirCookie = cookie; cookie->prev = NULL; } -static void -remove_cookie_from_jar(pipefs *fs, dir_cookie *cookie) +void +Volume::RemoveCookie(dir_cookie *cookie) { if (cookie->next) cookie->next->prev = cookie->prev; @@ -141,8 +276,8 @@ remove_cookie_from_jar(pipefs *fs, dir_cookie *cookie) if (cookie->prev) cookie->prev->next = cookie->next; - if (fs->first_dir_cookie == cookie) - fs->first_dir_cookie = cookie->next; + if (fFirstDirCookie == cookie) + fFirstDirCookie = cookie->next; cookie->prev = cookie->next = NULL; } @@ -150,59 +285,66 @@ remove_cookie_from_jar(pipefs *fs, dir_cookie *cookie) /* makes sure none of the dircookies point to the vnode passed in */ -static void -update_dircookies(pipefs *fs, pipefs_vnode *vnode) +void +Volume::UpdateDirCookies(Inode *inode) { dir_cookie *cookie; - for (cookie = fs->first_dir_cookie; cookie; cookie = cookie->next) { - if (cookie->current == vnode) - cookie->current = vnode->next; + for (cookie = fFirstDirCookie; cookie; cookie = cookie->next) { + if (cookie->current == inode) + cookie->current = inode->Next(); } } -static pipefs_vnode * -pipefs_find(pipefs *fs, const char *name) +Inode * +Volume::Lookup(vnode_id id) +{ + return (Inode *)hash_lookup(fNodeHash, &id); +} + + +Inode * +Volume::FindNode(const char *name) { if (!strcmp(name, ".") || !strcmp(name, "..")) - return fs->root_vnode; + return fRootNode; - for (pipefs_vnode *vnode = fs->first_entry; vnode; vnode = vnode->next) { - if (strcmp(vnode->name, name) == 0) - return vnode; + for (Inode *inode = fFirstEntry; inode; inode = inode->Next()) { + if (!strcmp(inode->Name(), name)) + return inode; } return NULL; } -static status_t -pipefs_insert(pipefs *fs, pipefs_vnode *vnode) +status_t +Volume::InsertNode(Inode *inode) { - vnode->next = fs->first_entry; - fs->first_entry = vnode; + inode->SetNext(fFirstEntry); + fFirstEntry = inode; return B_OK; } -static status_t -pipefs_remove_from_fs(pipefs *fs, pipefs_vnode *findNode) +status_t +Volume::RemoveNode(Inode *findNode) { - pipefs_vnode *vnode, *last; + Inode *inode, *last; - for (vnode = fs->first_entry, last = NULL; vnode; last = vnode, vnode = vnode->next) { - if (vnode == findNode) { - /* make sure all dircookies dont point to this vnode */ - update_dircookies(fs, vnode); + for (inode = fFirstEntry, last = NULL; inode; last = inode, inode = inode->Next()) { + if (inode == findNode) { + // make sure no dir cookies point to this node + UpdateDirCookies(inode); if (last) - last->next = vnode->next; + last->SetNext(inode->Next()); else - fs->first_entry = vnode->next; + fFirstEntry = inode->Next(); - vnode->next = NULL; + inode->SetNext(NULL); return B_OK; } } @@ -210,31 +352,30 @@ pipefs_remove_from_fs(pipefs *fs, pipefs_vnode *findNode) } -static status_t -pipefs_remove(pipefs *fs, pipefs_vnode *directory, const char *name) +status_t +Volume::RemoveNode(Inode *directory, const char *name) { - struct pipefs_vnode *vnode; + Lock(); + status_t status = B_OK; - mutex_lock(&fs->lock); - - vnode = pipefs_find(fs, name); - if (!vnode) + Inode *inode = FindNode(name); + if (inode == NULL) status = B_ENTRY_NOT_FOUND; - else if (vnode->type == S_IFDIR) + else if (inode->Type() == S_IFDIR) status = B_NOT_ALLOWED; if (status < B_OK) goto err; - pipefs_remove_from_fs(fs, vnode); - notify_listener(B_ENTRY_REMOVED, fs->id, directory->id, 0, vnode->id, name); + RemoveNode(inode); + notify_listener(B_ENTRY_REMOVED, ID(), directory->ID(), 0, inode->ID(), name); // schedule this vnode to be removed when it's ref goes to zero - vfs_remove_vnode(fs->id, vnode->id); + vfs_remove_vnode(ID(), inode->ID()); err: - mutex_unlock(&fs->lock); + Unlock(); return status; } @@ -243,84 +384,159 @@ err: // #pragma mark - -static status_t -pipefs_mount(mount_id id, const char *device, void *args, fs_volume *_fs, vnode_id *_rootVnodeID) +Inode::Inode(Volume *volume, const char *name, int32 type) + : + fNext(NULL) { - pipefs *fs; - pipefs_vnode *vnode; - status_t err; + fName = strdup(name); + if (fName == NULL) + return; - TRACE(("pipefs_mount: entry\n")); + fID = volume->GetNextNodeID(); + fType = type; - fs = (pipefs *)malloc(sizeof(pipefs)); - if (fs == NULL) - return ENOMEM; + if (benaphore_init(&fReadLock, "pipe read") == B_OK) + benaphore_init(&fWriteLock, "pipe write"); +} - fs->id = id; - fs->next_vnode_id = 0; - err = mutex_init(&fs->lock, "pipefs_mutex"); - if (err < 0) - goto err1; +Inode::~Inode() +{ + free(const_cast(fName)); +} - fs->vnode_list_hash = hash_init(PIPEFS_HASH_SIZE, (addr)&vnode->hash_next - (addr)vnode, - &pipefs_vnode_compare_func, &pipefs_vnode_hash_func); - if (fs->vnode_list_hash == NULL) { - err = B_NO_MEMORY; - goto err2; - } - // create the root vnode - vnode = pipefs_create_vnode(fs, "", S_IFDIR); - if (vnode == NULL) { - err = B_NO_MEMORY; - goto err3; - } - - fs->root_vnode = vnode; - fs->first_entry = NULL; - fs->first_dir_cookie = NULL; - - hash_insert(fs->vnode_list_hash, vnode); - - *_rootVnodeID = vnode->id; - *_fs = fs; +status_t +Inode::InitCheck() +{ + if (fName == NULL + || fReadLock.sem < B_OK + || fWriteLock.sem < B_OK) + return B_ERROR; return B_OK; +} -err3: - hash_uninit(fs->vnode_list_hash); -err2: - mutex_destroy(&fs->lock); -err1: - free(fs); - return err; +int32 +Inode::HashNextOffset() +{ + Inode *inode; + return (addr)&inode->fHashNext - (addr)inode; +} + + +uint32 +Inode::hash_func(void *_node, const void *_key, uint32 range) +{ + Inode *inode = (Inode *)_node; + const vnode_id *key = (const vnode_id *)_key; + + if (inode != NULL) + return inode->ID() % range; + + return (*key) % range; +} + + +int +Inode::compare_func(void *_node, const void *_key) +{ + Inode *inode = (Inode *)_node; + const vnode_id *key = (const vnode_id *)_key; + + if (inode->ID() == *key) + return 0; + + return -1; +} + + +// #pragma mark - + + +ReadRequests::ReadRequests() + : + fFirst(NULL), + fCurrent(NULL), + fLast(NULL) +{ + benaphore_init(&fLock, "pipefs read requests"); +} + + +ReadRequests::~ReadRequests() +{ + benaphore_destroy(&fLock); +} + + +status_t +ReadRequests::Lock() +{ + return benaphore_lock(&fLock); +} + + +status_t +ReadRequests::Unlock() +{ + return benaphore_unlock(&fLock); +} + + +status_t +ReadRequests::Add(read_request &request) +{ + if (fLast != NULL) + fLast->next = &request; + + if (fFirst == NULL) + fFirst = &request; + + fLast = &request; + request.next = NULL; +} + + +status_t +ReadRequests::Remove(read_request &request) +{ +} + + +// #pragma mark - + + +static status_t +pipefs_mount(mount_id id, const char *device, void *args, fs_volume *_volume, vnode_id *_rootVnodeID) +{ + TRACE(("pipefs_mount: entry\n")); + + Volume *volume = new Volume(id); + if (volume == NULL) + return B_NO_MEMORY; + + status_t status = volume->InitCheck(); + if (status < B_OK) { + delete volume; + return status; + } + + *_rootVnodeID = volume->RootNode().ID(); + *_volume = volume; + + return B_OK; } static status_t -pipefs_unmount(fs_volume _fs) +pipefs_unmount(fs_volume _volume) { - struct pipefs *fs = (struct pipefs *)_fs; - struct pipefs_vnode *vnode; - struct hash_iterator i; + struct Volume *volume = (struct Volume *)_volume; - TRACE(("pipefs_unmount: entry fs = %p\n", fs)); - - // put_vnode on the root to release the ref to it - vfs_put_vnode(fs->id, fs->root_vnode->id); - - // delete all of the vnodes - hash_open(fs->vnode_list_hash, &i); - while ((vnode = (struct pipefs_vnode *)hash_next(fs->vnode_list_hash, &i)) != NULL) { - pipefs_delete_vnode(fs, vnode, true); - } - hash_close(fs->vnode_list_hash, &i, false); - - hash_uninit(fs->vnode_list_hash); - mutex_destroy(&fs->lock); - free(fs); + TRACE(("pipefs_unmount: entry fs = %p\n", _volume)); + delete volume; return 0; } @@ -336,71 +552,71 @@ pipefs_sync(fs_volume fs) static status_t -pipefs_lookup(fs_volume _fs, fs_vnode _dir, const char *name, vnode_id *_id, int *_type) +pipefs_lookup(fs_volume _volume, fs_vnode _dir, const char *name, vnode_id *_id, int *_type) { - pipefs *fs = (pipefs *)_fs; + Volume *volume = (Volume *)_volume; status_t status; TRACE(("pipefs_lookup: entry dir %p, name '%s'\n", _dir, name)); - pipefs_vnode *directory = (pipefs_vnode *)_dir; - if (directory->type != S_IFDIR) + Inode *directory = (Inode *)_dir; + if (directory->Type() != S_IFDIR) return B_NOT_A_DIRECTORY; - mutex_lock(&fs->lock); + volume->Lock(); // look it up - pipefs_vnode *vnode = pipefs_find(fs, name); - if (!vnode) { + Inode *inode = volume->FindNode(name); + if (inode == NULL) { status = B_ENTRY_NOT_FOUND; goto err; } - pipefs_vnode *vnodeDummy; - status = vfs_get_vnode(fs->id, vnode->id, (fs_vnode *)&vnodeDummy); + Inode *dummy; + status = vfs_get_vnode(volume->ID(), inode->ID(), (fs_vnode *)&dummy); if (status < B_OK) goto err; - *_id = vnode->id; - *_type = vnode->type; + *_id = inode->ID(); + *_type = inode->Type(); err: - mutex_unlock(&fs->lock); + volume->Unlock(); return status; } static status_t -pipefs_get_vnode_name(fs_volume _fs, fs_vnode _vnode, char *buffer, size_t bufferSize) +pipefs_get_vnode_name(fs_volume _volume, fs_vnode _node, char *buffer, size_t bufferSize) { - pipefs_vnode *vnode = (pipefs_vnode *)_vnode; + Inode *inode = (Inode *)_node; - TRACE(("devfs_get_vnode_name: vnode = %p\n", vnode)); + TRACE(("pipefs_get_vnode_name(): inode = %p\n", inode)); - strlcpy(buffer, vnode->name, bufferSize); + strlcpy(buffer, inode->Name(), bufferSize); return B_OK; } static status_t -pipefs_get_vnode(fs_volume _fs, vnode_id id, fs_vnode *_vnode, bool reenter) +pipefs_get_vnode(fs_volume _volume, vnode_id id, fs_vnode *_inode, bool reenter) { - pipefs *fs = (pipefs *)_fs; + Volume *volume = (Volume *)_volume; TRACE(("pipefs_getvnode: asking for vnode 0x%Lx, r %d\n", id, reenter)); if (!reenter) - mutex_lock(&fs->lock); + volume->Lock(); - *_vnode = hash_lookup(fs->vnode_list_hash, &id); + *_inode = volume->Lookup(id); if (!reenter) - mutex_unlock(&fs->lock); + volume->Unlock(); - TRACE(("pipefs_getnvnode: looked it up at %p\n", *_vnode)); + TRACE(("pipefs_getnvnode: looked it up at %p\n", *_inode)); - if (*_vnode) + if (*_inode) return B_OK; return B_ENTRY_NOT_FOUND; @@ -408,85 +624,81 @@ pipefs_get_vnode(fs_volume _fs, vnode_id id, fs_vnode *_vnode, bool reenter) static status_t -pipefs_put_vnode(fs_volume _fs, fs_vnode _vnode, bool reenter) +pipefs_put_vnode(fs_volume _volume, fs_vnode _node, bool reenter) { #if PIPEFS_TRACE - pipefs_vnode *vnode = (pipefs_vnode *)_vnode; + Inode *inode = (Inode *)_node; - TRACE(("pipefs_putvnode: entry on vnode 0x%Lx, r %d\n", vnode->id, reenter)); + TRACE(("pipefs_putvnode: entry on vnode 0x%Lx, r %d\n", inode->ID(), reenter)); #endif return B_OK; } static status_t -pipefs_remove_vnode(fs_volume _fs, fs_vnode _vnode, bool reenter) +pipefs_remove_vnode(fs_volume _volume, fs_vnode _node, bool reenter) { - pipefs *fs = (pipefs *)_fs; + Volume *volume = (Volume *)_volume; + Inode *inode = (Inode *)_node; - TRACE(("pipefs_removevnode: remove %p (0x%Lx), r %d\n", vnode, vnode->id, reenter)); + TRACE(("pipefs_removevnode: remove %p (0x%Lx), r %d\n", inode, inode->ID(), reenter)); if (!reenter) - mutex_lock(&fs->lock); + volume->Lock(); - pipefs_vnode *vnode = (pipefs_vnode *)_vnode; - if (vnode->next) { + if (inode->Next()) { // can't remove node if it's linked to the dir - panic("pipefs_remove_vnode(): vnode %p asked to be removed is present in dir\n", vnode); + panic("pipefs_remove_vnode(): vnode %p asked to be removed is present in dir\n", inode); } - pipefs_delete_vnode(fs, vnode, false); + volume->DeleteNode(inode); if (!reenter) - mutex_unlock(&fs->lock); + volume->Unlock(); return 0; } static status_t -pipefs_create(fs_volume _fs, fs_vnode _dir, const char *name, int omode, int perms, fs_cookie *_cookie, vnode_id *new_vnid) +pipefs_create(fs_volume _volume, fs_vnode _dir, const char *name, int omode, int perms, + fs_cookie *_cookie, vnode_id *_newVnodeID) { - pipefs *fs = (pipefs *)_fs; + Volume *volume = (Volume *)_volume; - TRACE(("pipefs_create_dir: dir %p, name = '%s', perms = %d, id = 0x%Lx pointer id = %p\n", dir, name, perms,*new_vnid, new_vnid)); + TRACE(("pipefs_create_dir: dir = %p, name = '%s', perms = %d, &id = %p\n", + _dir, name, perms, _newVnodeID)); - mutex_lock(&fs->lock); + volume->Lock(); - pipefs_vnode *directory = (pipefs_vnode *)_dir; + Inode *directory = (Inode *)_dir; status_t status = B_OK; - pipefs_vnode *vnode = pipefs_find(fs, name); - if (vnode != NULL) { + Inode *inode = volume->FindNode(name); + if (inode != NULL) { status = B_FILE_EXISTS; goto err; } - vnode = pipefs_create_vnode(fs, name, S_IFIFO); - if (vnode == NULL) { + inode = volume->CreateNode(name, S_IFIFO); + if (inode == NULL) { status = B_NO_MEMORY; goto err; } - pipefs_insert(fs, vnode); - hash_insert(fs->vnode_list_hash, vnode); + volume->Unlock(); - mutex_unlock(&fs->lock); - - notify_listener(B_ENTRY_CREATED, fs->id, directory->id, 0, vnode->id, name); + notify_listener(B_ENTRY_CREATED, volume->ID(), directory->ID(), 0, inode->ID(), name); return B_OK; -err1: - pipefs_delete_vnode(fs, vnode, false); err: - mutex_unlock(&fs->lock); - + volume->Unlock(); return status; } static status_t -pipefs_open(fs_volume _fs, fs_vnode _v, int openMode, fs_cookie *_cookie) +pipefs_open(fs_volume _volume, fs_vnode _v, int openMode, fs_cookie *_cookie) { // allow to open the file, but it can't be done anything with it @@ -498,7 +710,7 @@ pipefs_open(fs_volume _fs, fs_vnode _v, int openMode, fs_cookie *_cookie) static status_t -pipefs_close(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie) +pipefs_close(fs_volume _volume, fs_vnode _vnode, fs_cookie _cookie) { TRACE(("pipefs_close: entry vnode %p, cookie %p\n", _vnode, _cookie)); @@ -507,7 +719,7 @@ pipefs_close(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie) static status_t -pipefs_free_cookie(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie) +pipefs_free_cookie(fs_volume _volume, fs_vnode _vnode, fs_cookie _cookie) { // pipefs_cookie *cookie = _cookie; @@ -521,94 +733,133 @@ pipefs_free_cookie(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie) static status_t -pipefs_fsync(fs_volume _fs, fs_vnode _v) +pipefs_fsync(fs_volume _volume, fs_vnode _v) { return B_OK; } static ssize_t -pipefs_read(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie, off_t pos, +pipefs_read(fs_volume _volume, fs_vnode _node, fs_cookie _cookie, off_t pos, void *buffer, size_t *_length) { - TRACE(("pipefs_read: vnode %p, cookie %p, pos 0x%Lx , len 0x%lx\n", vnode, cookie, pos, *len)); + file_cookie *cookie = (file_cookie *)_cookie; + Volume *fs = (Volume *)_volume; - return EINVAL; + (void)pos; + TRACE(("pipefs_read: vnode %p, cookie %p, pos 0x%Lx , len 0x%lx\n", _node, cookie, pos, *_length)); + + read_request request; + request.buffer = buffer; + request.buffer_size = *_length; + request.bytes_read = 0; + + ReadRequests &requests = fs->GetReadRequests(); + + if (requests.Lock() != B_OK) + return B_ERROR; + + requests.Add(request); + requests.Unlock(); + + Inode *inode = (Inode *)_node; + status_t status = benaphore_lock_etc(inode->ReadLock(), + cookie->open_mode & O_NONBLOCK ? B_TIMEOUT : 0, 0); + + if (requests.Lock() != B_OK) + panic("pipefs: could not get lock for read requests"); + +// if (status == B_OK) { +// requests.FillRequest(request); + + requests.Remove(request); + requests.Unlock(); + + if (status == B_TIMED_OUT && request.bytes_read > 0) + status = B_OK; + + if (status == B_OK) { + *_length = request.bytes_read; + } + return status; } static ssize_t -pipefs_write(fs_volume fs, fs_vnode vnode, fs_cookie cookie, off_t pos, +pipefs_write(fs_volume fs, fs_vnode _node, fs_cookie cookie, off_t pos, const void *buffer, size_t *_length) { - TRACE(("pipefs_write: vnode %p, cookie %p, pos 0x%Lx , len 0x%lx\n", vnode, cookie, pos, *len)); + TRACE(("pipefs_write: vnode %p, cookie %p, pos 0x%Lx , len 0x%lx\n", _node, cookie, pos, *_length)); return EINVAL; } static off_t -pipefs_seek(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie, off_t pos, int seekType) +pipefs_seek(fs_volume _volume, fs_vnode _vnode, fs_cookie _cookie, off_t pos, int seekType) { return ESPIPE; } static status_t -pipefs_create_dir(fs_volume _fs, fs_vnode _dir, const char *name, int perms, vnode_id *_newID) +pipefs_create_dir(fs_volume _volume, fs_vnode _dir, const char *name, int perms, vnode_id *_newID) { return ENOSYS; } static status_t -pipefs_remove_dir(fs_volume _fs, fs_vnode _dir, const char *name) +pipefs_remove_dir(fs_volume _volume, fs_vnode _dir, const char *name) { return EPERM; } static status_t -pipefs_open_dir(fs_volume _fs, fs_vnode _vnode, fs_cookie *_cookie) +pipefs_open_dir(fs_volume _volume, fs_vnode _node, fs_cookie *_cookie) { - pipefs *fs = (pipefs *)_fs; + Volume *volume = (Volume *)_volume; - TRACE(("pipefs_open_dir(): vnode = %p\n", _vnode)); + TRACE(("pipefs_open_dir(): vnode = %p\n", _node)); - pipefs_vnode *vnode = (pipefs_vnode *)_vnode; - if (vnode->type != S_IFDIR) + Inode *inode = (Inode *)_node; + if (inode->Type() != S_IFDIR) return B_BAD_VALUE; - if (vnode != fs->root_vnode) + if (inode != &volume->RootNode()) panic("pipefs: found directory that's not the root!"); dir_cookie *cookie = (dir_cookie *)malloc(sizeof(dir_cookie)); if (cookie == NULL) return B_NO_MEMORY; - mutex_lock(&fs->lock); + volume->Lock(); - cookie->current = fs->first_entry; + cookie->current = volume->FirstEntry(); + volume->InsertCookie(cookie); - insert_cookie_in_jar(fs, cookie); *_cookie = cookie; - mutex_unlock(&fs->lock); + volume->Unlock(); return B_OK; } static status_t -pipefs_read_dir(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie, +pipefs_read_dir(fs_volume _volume, fs_vnode _node, fs_cookie _cookie, struct dirent *dirent, size_t bufferSize, uint32 *_num) { - pipefs *fs = (pipefs *)_fs; + Volume *volume = (Volume *)_volume; status_t status = 0; - TRACE(("pipefs_read_dir: vnode %p, cookie %p, buffer = %p, bufferSize = %ld, num = %p\n", _vnode, cookie, dirent, bufferSize,_num)); + TRACE(("pipefs_read_dir: vnode %p, cookie %p, buffer = %p, bufferSize = %ld, num = %p\n", _node, _cookie, dirent, bufferSize,_num)); - mutex_lock(&fs->lock); + if (_node != &volume->RootNode()) + return B_BAD_VALUE; + + volume->Lock(); dir_cookie *cookie = (dir_cookie *)_cookie; if (cookie->current == NULL) { @@ -618,54 +869,53 @@ pipefs_read_dir(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie, goto err; } - dirent->d_dev = fs->id; - dirent->d_ino = cookie->current->id; - dirent->d_reclen = strlen(cookie->current->name) + sizeof(struct dirent); + dirent->d_dev = volume->ID(); + dirent->d_ino = cookie->current->ID(); + dirent->d_reclen = strlen(cookie->current->Name()) + sizeof(struct dirent); if (dirent->d_reclen > bufferSize) { status = ENOBUFS; goto err; } - status = user_strlcpy(dirent->d_name, cookie->current->name, bufferSize); + status = user_strlcpy(dirent->d_name, cookie->current->Name(), bufferSize); if (status < 0) goto err; - cookie->current = cookie->current->next; + cookie->current = cookie->current->Next(); err: - mutex_unlock(&fs->lock); + volume->Unlock(); return status; } static status_t -pipefs_rewind_dir(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie) +pipefs_rewind_dir(fs_volume _volume, fs_vnode _vnode, fs_cookie _cookie) { - pipefs *fs = (pipefs *)_fs; - - mutex_lock(&fs->lock); + Volume *volume = (Volume *)_volume; + volume->Lock(); dir_cookie *cookie = (dir_cookie *)_cookie; - cookie->current = fs->first_entry; + cookie->current = volume->FirstEntry(); - mutex_unlock(&fs->lock); + volume->Unlock(); return B_OK; } static status_t -pipefs_close_dir(fs_volume _fs, fs_vnode _v, fs_cookie _cookie) +pipefs_close_dir(fs_volume _volume, fs_vnode _node, fs_cookie _cookie) { - TRACE(("pipefs_close: entry vnode %p, cookie %p\n", _vnode, _cookie)); + TRACE(("pipefs_close: entry vnode %p, cookie %p\n", _node, _cookie)); return 0; } static status_t -pipefs_free_dir_cookie(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie) +pipefs_free_dir_cookie(fs_volume _volume, fs_vnode _vnode, fs_cookie _cookie) { dir_cookie *cookie = (dir_cookie *)_cookie; @@ -677,7 +927,7 @@ pipefs_free_dir_cookie(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie) static status_t -pipefs_ioctl(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie, ulong op, +pipefs_ioctl(fs_volume _volume, fs_vnode _vnode, fs_cookie _cookie, ulong op, void *buffer, size_t length) { TRACE(("pipefs_ioctl: vnode %p, cookie %p, op %ld, buf %p, len %ld\n", @@ -688,50 +938,50 @@ pipefs_ioctl(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie, ulong op, static status_t -pipefs_can_page(fs_volume _fs, fs_vnode _v) +pipefs_can_page(fs_volume _volume, fs_vnode _v) { return -1; } static ssize_t -pipefs_read_pages(fs_volume _fs, fs_vnode _v, iovecs *vecs, off_t pos) +pipefs_read_pages(fs_volume _volume, fs_vnode _v, iovecs *vecs, off_t pos) { return EPERM; } static ssize_t -pipefs_write_pages(fs_volume _fs, fs_vnode _v, iovecs *vecs, off_t pos) +pipefs_write_pages(fs_volume _volume, fs_vnode _v, iovecs *vecs, off_t pos) { return EPERM; } static status_t -pipefs_unlink(fs_volume _fs, fs_vnode _dir, const char *name) +pipefs_unlink(fs_volume _volume, fs_vnode _dir, const char *name) { - pipefs *fs = (pipefs *)_fs; - pipefs_vnode *directory = (pipefs_vnode *)_dir; + Volume *volume = (Volume *)_volume; + Inode *directory = (Inode *)_dir; - TRACE(("pipefs_unlink: dir %p (0x%Lx), name '%s'\n", _dir, directory->id, name)); + TRACE(("pipefs_unlink: dir %p (0x%Lx), name '%s'\n", _dir, directory->ID(), name)); - return pipefs_remove(fs, directory, name); + return volume->RemoveNode(directory, name); } static status_t -pipefs_read_stat(fs_volume _fs, fs_vnode _vnode, struct stat *stat) +pipefs_read_stat(fs_volume _volume, fs_vnode _node, struct stat *stat) { - pipefs *fs = (pipefs *)_fs; - pipefs_vnode *vnode = (pipefs_vnode *)_vnode; + Volume *volume = (Volume *)_volume; + Inode *inode = (Inode *)_node; - TRACE(("pipefs_rstat: vnode %p (0x%Lx), stat %p\n", vnode, vnode->id, stat)); + TRACE(("pipefs_rstat: vnode %p (0x%Lx), stat %p\n", inode, inode->ID(), stat)); - stat->st_dev = fs->id; - stat->st_ino = vnode->id; + stat->st_dev = volume->ID(); + stat->st_ino = inode->ID(); stat->st_size = 0; // ToDo: oughta get me! - stat->st_mode = vnode->type | DEFFILEMODE; + stat->st_mode = inode->Type() | 0777; return 0; } @@ -794,11 +1044,12 @@ static struct fs_ops pipefs_ops = { NULL, }; +} // namespace pipefs extern "C" status_t bootstrap_pipefs(void) { - dprintf("bootstrap_pipefs: entry\n"); + TRACE(("bootstrap_pipefs: entry\n")); - return vfs_register_filesystem("pipefs", &pipefs_ops); + return vfs_register_filesystem("pipefs", &pipefs::pipefs_ops); }