hrev46442 adds 4 changesets to branch 'master' old head: 9394e66cbceb75f1f29c62224ced948d62ffda94 new head: f170a888c26756f2a2586630aa280d8bc3d687ee overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=f170a88+%5E9394e66 ---------------------------------------------------------------------------- ed9f471: Fix FIONREAD related issues * Network stack socket module: socket_control(): The FIONREAD argument is int, not ssize_t. * Net kit: getsockopt(): R5_SO_FIONREAD: Fix ioctl() argument. Was taking a pointer of what already was a pointer to the buffer. * libedit: el_gets(): The FIONREAD argument is int, not long. fd0bfd5: FIFO: More correct locking when accessing file_cookie::open_mode 8019fdb: FIFO: Implement FION{BIO,READ}, B_SET_[NON]BLOCKING_IO ioctls f170a88: FIFO: Handle user reads/writes more correctly * Determine whether called from userland or kernel. * Check the buffer address via IS_USER_ADDRESS(), if from userland. * Simplify things by merging UserRead() with Read() and UserWrite() with Write(). [ Ingo Weinhold <ingo_weinhold@xxxxxx> ] ---------------------------------------------------------------------------- 4 files changed, 121 insertions(+), 55 deletions(-) src/add-ons/kernel/network/stack/net_socket.cpp | 9 +- src/kits/network/socket.cpp | 5 +- src/libs/edit/read.c | 2 +- src/system/kernel/fs/fifo.cpp | 160 ++++++++++++++------ ############################################################################ Commit: ed9f4719f7f22477353f0c09c4ed4db8857c6d57 URL: http://cgit.haiku-os.org/haiku/commit/?id=ed9f471 Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Mon Nov 25 14:47:26 2013 UTC Fix FIONREAD related issues * Network stack socket module: socket_control(): The FIONREAD argument is int, not ssize_t. * Net kit: getsockopt(): R5_SO_FIONREAD: Fix ioctl() argument. Was taking a pointer of what already was a pointer to the buffer. * libedit: el_gets(): The FIONREAD argument is int, not long. ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/network/stack/net_socket.cpp b/src/add-ons/kernel/network/stack/net_socket.cpp index 9d5cfc9..bc7b8de 100644 --- a/src/add-ons/kernel/network/stack/net_socket.cpp +++ b/src/add-ons/kernel/network/stack/net_socket.cpp @@ -550,17 +550,18 @@ socket_control(net_socket* socket, int32 op, void* data, size_t length) if (data == NULL) return B_BAD_VALUE; - ssize_t available = socket_read_avail(socket); - if (available < B_OK) + int available = (int)socket_read_avail(socket); + if (available < 0) return available; if (is_syscall()) { if (!IS_USER_ADDRESS(data) - || user_memcpy(data, &available, sizeof(ssize_t)) != B_OK) { + || user_memcpy(data, &available, sizeof(available)) + != B_OK) { return B_BAD_ADDRESS; } } else - *(ssize_t *)data = available; + *(int*)data = available; return B_OK; } diff --git a/src/kits/network/socket.cpp b/src/kits/network/socket.cpp index 9daf8ec..7829f20 100644 --- a/src/kits/network/socket.cpp +++ b/src/kits/network/socket.cpp @@ -315,9 +315,10 @@ getsockopt(int socket, int level, int option, void *value, socklen_t *_length) { if (check_r5_compatibility()) { if (option == R5_SO_FIONREAD) { - // there is no SO_FIONREAD in our stack; we're using FIONREAD instead + // there is no SO_FIONREAD in our stack; we're using FIONREAD + // instead *_length = sizeof(int); - return ioctl(socket, FIONREAD, &value); + return ioctl(socket, FIONREAD, value); } convert_from_r5_sockopt(level, option); diff --git a/src/libs/edit/read.c b/src/libs/edit/read.c index cfc5cbf..8ce1667 100644 --- a/src/libs/edit/read.c +++ b/src/libs/edit/read.c @@ -419,7 +419,7 @@ el_gets(EditLine *el, int *nread) #ifdef FIONREAD if (el->el_tty.t_mode == EX_IO && ma->level < 0) { - long chrs = 0; + int chrs = 0; (void) ioctl(el->el_infd, FIONREAD, (ioctl_t) & chrs); if (chrs == 0) { ############################################################################ Commit: fd0bfd5593f3abb48b1038112d7d85bbb1f4094c URL: http://cgit.haiku-os.org/haiku/commit/?id=fd0bfd5 Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Mon Nov 25 14:49:24 2013 UTC FIFO: More correct locking when accessing file_cookie::open_mode ---------------------------------------------------------------------------- diff --git a/src/system/kernel/fs/fifo.cpp b/src/system/kernel/fs/fifo.cpp index b24e258..2b403bd 100644 --- a/src/system/kernel/fs/fifo.cpp +++ b/src/system/kernel/fs/fifo.cpp @@ -188,7 +188,7 @@ public: void NotifyEndClosed(bool writer); void Open(int openMode); - void Close(int openMode, file_cookie* cookie); + void Close(file_cookie* cookie); int32 ReaderCount() const { return fReaderCount; } int32 WriterCount() const { return fWriterCount; } @@ -239,7 +239,8 @@ private: struct file_cookie { - int open_mode; + int open_mode; + // guarded by Inode::fRequestLock }; @@ -654,12 +655,14 @@ Inode::Open(int openMode) void -Inode::Close(int openMode, file_cookie* cookie) +Inode::Close(file_cookie* cookie) { TRACE("Inode %p::Close(openMode = %d)\n", this, openMode); MutexLocker locker(RequestLock()); + int openMode = cookie->open_mode; + // Notify all currently reading file descriptors ReadRequestList::Iterator iterator = fReadRequests.GetIterator(); while (ReadRequest* request = iterator.Next()) { @@ -898,7 +901,7 @@ fifo_close(fs_volume* volume, fs_vnode* vnode, void* _cookie) file_cookie* cookie = (file_cookie*)_cookie; FIFOInode* fifo = (FIFOInode*)vnode->private_node; - fifo->Close(cookie->open_mode, cookie); + fifo->Close(cookie); return B_OK; } @@ -934,11 +937,11 @@ fifo_read(fs_volume* _volume, fs_vnode* _node, void* _cookie, TRACE("fifo_read(vnode = %p, cookie = %p, length = %lu, mode = %d)\n", inode, cookie, *_length, cookie->open_mode); + MutexLocker locker(inode->RequestLock()); + if ((cookie->open_mode & O_RWMASK) != O_RDONLY) return B_NOT_ALLOWED; - MutexLocker locker(inode->RequestLock()); - if (inode->IsActive() && inode->WriterCount() == 0) { // as long there is no writer, and the pipe is empty, // we always just return 0 to indicate end of file @@ -982,11 +985,11 @@ fifo_write(fs_volume* _volume, fs_vnode* _node, void* _cookie, TRACE("fifo_write(vnode = %p, cookie = %p, length = %lu)\n", _node, cookie, *_length); + MutexLocker locker(inode->RequestLock()); + if ((cookie->open_mode & O_RWMASK) != O_WRONLY) return B_NOT_ALLOWED; - MutexLocker locker(inode->RequestLock()); - size_t length = *_length; if (length == 0) return B_OK; @@ -1067,12 +1070,15 @@ fifo_ioctl(fs_volume* _volume, fs_vnode* _vnode, void* _cookie, uint32 op, static status_t -fifo_set_flags(fs_volume* _volume, fs_vnode* _vnode, void* _cookie, +fifo_set_flags(fs_volume* _volume, fs_vnode* _node, void* _cookie, int flags) { + Inode* inode = (Inode*)_node->private_node; file_cookie* cookie = (file_cookie*)_cookie; TRACE("fifo_set_flags(vnode = %p, flags = %x)\n", _vnode, flags); + + MutexLocker locker(inode->RequestLock()); cookie->open_mode = (cookie->open_mode & ~(O_APPEND | O_NONBLOCK)) | flags; return B_OK; } ############################################################################ Commit: 8019fdbab89c0b320e8f70583182eae2189bc913 URL: http://cgit.haiku-os.org/haiku/commit/?id=8019fdb Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Mon Nov 25 14:50:26 2013 UTC FIFO: Implement FION{BIO,READ}, B_SET_[NON]BLOCKING_IO ioctls ---------------------------------------------------------------------------- diff --git a/src/system/kernel/fs/fifo.cpp b/src/system/kernel/fs/fifo.cpp index 2b403bd..bf42d02 100644 --- a/src/system/kernel/fs/fifo.cpp +++ b/src/system/kernel/fs/fifo.cpp @@ -11,6 +11,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/ioctl.h> #include <sys/stat.h> #include <new> @@ -24,6 +25,7 @@ #include <khash.h> #include <lock.h> #include <select_sync_pool.h> +#include <syscall_restart.h> #include <team.h> #include <thread.h> #include <util/DoublyLinkedList.h> @@ -241,6 +243,14 @@ private: struct file_cookie { int open_mode; // guarded by Inode::fRequestLock + + void SetNonBlocking(bool nonBlocking) + { + if (nonBlocking) + open_mode |= O_NONBLOCK; + else + open_mode &= ~(int)O_NONBLOCK; + } }; @@ -1059,12 +1069,65 @@ fifo_write_stat(fs_volume* volume, fs_vnode* vnode, const struct ::stat* st, static status_t -fifo_ioctl(fs_volume* _volume, fs_vnode* _vnode, void* _cookie, uint32 op, +fifo_ioctl(fs_volume* _volume, fs_vnode* _node, void* _cookie, uint32 op, void* buffer, size_t length) { + file_cookie* cookie = (file_cookie*)_cookie; + Inode* inode = (Inode*)_node->private_node; + TRACE("fifo_ioctl: vnode %p, cookie %p, op %ld, buf %p, len %ld\n", _vnode, _cookie, op, buffer, length); + switch (op) { + case FIONBIO: + { + if (buffer == NULL) + return B_BAD_VALUE; + + int value; + if (is_called_via_syscall()) { + if (!IS_USER_ADDRESS(buffer) + || user_memcpy(&value, buffer, sizeof(int)) != B_OK) { + return B_BAD_ADDRESS; + } + } else + value = *(int*)buffer; + + MutexLocker locker(inode->RequestLock()); + cookie->SetNonBlocking(value != 0); + return B_OK; + } + + case FIONREAD: + { + if (buffer == NULL) + return B_BAD_VALUE; + + MutexLocker locker(inode->RequestLock()); + int available = (int)inode->BytesAvailable(); + locker.Unlock(); + + if (is_called_via_syscall()) { + if (!IS_USER_ADDRESS(buffer) + || user_memcpy(buffer, &available, sizeof(available)) + != B_OK) { + return B_BAD_ADDRESS; + } + } else + *(int*)buffer = available; + + return B_OK; + } + + case B_SET_BLOCKING_IO: + case B_SET_NONBLOCKING_IO: + { + MutexLocker locker(inode->RequestLock()); + cookie->SetNonBlocking(op == B_SET_NONBLOCKING_IO); + return B_OK; + } + } + return EINVAL; } ############################################################################ Revision: hrev46442 Commit: f170a888c26756f2a2586630aa280d8bc3d687ee URL: http://cgit.haiku-os.org/haiku/commit/?id=f170a88 Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Mon Nov 25 15:06:45 2013 UTC FIFO: Handle user reads/writes more correctly * Determine whether called from userland or kernel. * Check the buffer address via IS_USER_ADDRESS(), if from userland. * Simplify things by merging UserRead() with Read() and UserWrite() with Write(). ---------------------------------------------------------------------------- diff --git a/src/system/kernel/fs/fifo.cpp b/src/system/kernel/fs/fifo.cpp index bf42d02..09d2e3f 100644 --- a/src/system/kernel/fs/fifo.cpp +++ b/src/system/kernel/fs/fifo.cpp @@ -62,12 +62,11 @@ public: status_t CreateBuffer(); void DeleteBuffer(); - ssize_t Write(const void* buffer, size_t length); - ssize_t Read(void* buffer, size_t length); + ssize_t Write(const void* buffer, size_t length, + bool isUser); + ssize_t Read(void* buffer, size_t length, bool isUser); ssize_t Peek(size_t offset, void* buffer, size_t length) const; - ssize_t UserWrite(const void* buffer, ssize_t length); - ssize_t UserRead(void* buffer, ssize_t length); size_t Readable() const; size_t Writable() const; @@ -172,9 +171,11 @@ public: mutex* RequestLock() { return &fRequestLock; } status_t WriteDataToBuffer(const void* data, - size_t* _length, bool nonBlocking); + size_t* _length, bool nonBlocking, + bool isUser); status_t ReadDataFromBuffer(void* data, size_t* _length, - bool nonBlocking, ReadRequest& request); + bool nonBlocking, bool isUser, + ReadRequest& request); size_t BytesAvailable() const { return fBuffer.Readable(); } size_t BytesWritable() const @@ -292,22 +293,30 @@ RingBuffer::DeleteBuffer() inline ssize_t -RingBuffer::Write(const void* buffer, size_t length) +RingBuffer::Write(const void* buffer, size_t length, bool isUser) { if (fBuffer == NULL) return B_NO_MEMORY; + if (isUser && !IS_USER_ADDRESS(buffer)) + return B_BAD_ADDRESS; - return ring_buffer_write(fBuffer, (const uint8*)buffer, length); + return isUser + ? ring_buffer_user_write(fBuffer, (const uint8*)buffer, length) + : ring_buffer_write(fBuffer, (const uint8*)buffer, length); } inline ssize_t -RingBuffer::Read(void* buffer, size_t length) +RingBuffer::Read(void* buffer, size_t length, bool isUser) { if (fBuffer == NULL) return B_NO_MEMORY; + if (isUser && !IS_USER_ADDRESS(buffer)) + return B_BAD_ADDRESS; - return ring_buffer_read(fBuffer, (uint8*)buffer, length); + return isUser + ? ring_buffer_user_read(fBuffer, (uint8*)buffer, length) + : ring_buffer_read(fBuffer, (uint8*)buffer, length); } @@ -321,26 +330,6 @@ RingBuffer::Peek(size_t offset, void* buffer, size_t length) const } -inline ssize_t -RingBuffer::UserWrite(const void* buffer, ssize_t length) -{ - if (fBuffer == NULL) - return B_NO_MEMORY; - - return ring_buffer_user_write(fBuffer, (const uint8*)buffer, length); -} - - -inline ssize_t -RingBuffer::UserRead(void* buffer, ssize_t length) -{ - if (fBuffer == NULL) - return B_NO_MEMORY; - - return ring_buffer_user_read(fBuffer, (uint8*)buffer, length); -} - - inline size_t RingBuffer::Readable() const { @@ -400,7 +389,8 @@ Inode::InitCheck() the returned length is > 0, the returned error code can be ignored. */ status_t -Inode::WriteDataToBuffer(const void* _data, size_t* _length, bool nonBlocking) +Inode::WriteDataToBuffer(const void* _data, size_t* _length, bool nonBlocking, + bool isUser) { const uint8* data = (const uint8*)_data; size_t dataSize = *_length; @@ -452,8 +442,11 @@ Inode::WriteDataToBuffer(const void* _data, size_t* _length, bool nonBlocking) if (toWrite > dataSize) toWrite = dataSize; - if (toWrite > 0 && fBuffer.UserWrite(data, toWrite) < 0) - return B_BAD_ADDRESS; + if (toWrite > 0) { + ssize_t bytesWritten = fBuffer.Write(data, toWrite, isUser); + if (bytesWritten < 0) + return bytesWritten; + } data += toWrite; dataSize -= toWrite; @@ -468,7 +461,7 @@ Inode::WriteDataToBuffer(const void* _data, size_t* _length, bool nonBlocking) status_t Inode::ReadDataFromBuffer(void* data, size_t* _length, bool nonBlocking, - ReadRequest& request) + bool isUser, ReadRequest& request) { size_t dataSize = *_length; *_length = 0; @@ -508,8 +501,9 @@ Inode::ReadDataFromBuffer(void* data, size_t* _length, bool nonBlocking, if (toRead > dataSize) toRead = dataSize; - if (fBuffer.UserRead(data, toRead) < 0) - return B_BAD_ADDRESS; + ssize_t bytesRead = fBuffer.Read(data, toRead, isUser); + if (bytesRead < 0) + return bytesRead; NotifyBytesRead(toRead); @@ -970,7 +964,8 @@ fifo_read(fs_volume* _volume, fs_vnode* _node, void* _cookie, size_t length = *_length; status_t status = inode->ReadDataFromBuffer(buffer, &length, - (cookie->open_mode & O_NONBLOCK) != 0, request); + (cookie->open_mode & O_NONBLOCK) != 0, is_called_via_syscall(), + request); inode->RemoveReadRequest(request); inode->NotifyReadDone(); @@ -1006,7 +1001,7 @@ fifo_write(fs_volume* _volume, fs_vnode* _node, void* _cookie, // copy data into ring buffer status_t status = inode->WriteDataToBuffer(buffer, &length, - (cookie->open_mode & O_NONBLOCK) != 0); + (cookie->open_mode & O_NONBLOCK) != 0, is_called_via_syscall()); if (length > 0) status = B_OK;