summaryrefslogtreecommitdiffstats
path: root/fs/coda/psdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/coda/psdev.c')
-rw-r--r--fs/coda/psdev.c160
1 files changed, 101 insertions, 59 deletions
diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c
index b88c602c6..582ea7000 100644
--- a/fs/coda/psdev.c
+++ b/fs/coda/psdev.c
@@ -71,7 +71,7 @@ static unsigned int coda_psdev_poll(struct file *file, poll_table * wait)
struct venus_comm *vcp = &coda_upc_comm;
unsigned int mask = POLLOUT | POLLWRNORM;
- poll_wait(file, &(vcp->vc_waitq), wait);
+ poll_wait(file, &vcp->vc_waitq, wait);
if (!list_empty(&vcp->vc_pending))
mask |= POLLIN | POLLRDNORM;
@@ -99,24 +99,24 @@ static int coda_psdev_ioctl(struct inode * inode, struct file * filp,
*/
static ssize_t coda_psdev_write(struct file *file, const char *buf,
- size_t count, loff_t *off)
+ size_t nbytes, loff_t *off)
{
struct venus_comm *vcp = &coda_upc_comm;
struct upc_req *req = NULL;
struct upc_req *tmp;
struct list_head *lh;
struct coda_in_hdr hdr;
+ ssize_t retval = 0, count = 0;
int error;
-
if ( !coda_upc_comm.vc_pid )
return -EIO;
/* Peek at the opcode, uniquefier */
if (copy_from_user(&hdr, buf, 2 * sizeof(u_long)))
return -EFAULT;
- CDEBUG(D_PSDEV, "(process,opc,uniq)=(%d,%ld,%ld), count %ld\n",
- current->pid, hdr.opcode, hdr.unique, (long)count);
+ CDEBUG(D_PSDEV, "(process,opc,uniq)=(%d,%ld,%ld), nbytes %ld\n",
+ current->pid, hdr.opcode, hdr.unique, (long)nbytes);
if (DOWNCALL(hdr.opcode)) {
struct super_block *sb = NULL;
@@ -125,41 +125,47 @@ static ssize_t coda_psdev_write(struct file *file, const char *buf,
sb = coda_super_info.sbi_sb;
if ( !sb ) {
- printk("coda_psdev_write: downcall, no SB!\n");
- return count;
+ CDEBUG(D_PSDEV, "coda_psdev_write: downcall, no SB!\n");
+ count = nbytes;
+ goto out;
}
CDEBUG(D_PSDEV, "handling downcall\n");
- if ( count < sizeof(struct coda_out_hdr) ) {
+ if ( nbytes < sizeof(struct coda_out_hdr) ) {
printk("coda_downcall opc %ld uniq %ld, not enough!\n",
hdr.opcode, hdr.unique);
- return count;
+ count = nbytes;
+ goto out;
}
- CODA_ALLOC(dcbuf, union outputArgs *, size);
- if ( count > size ) {
+ if ( nbytes > size ) {
printk("Coda: downcall opc %ld, uniq %ld, too much!",
hdr.opcode, hdr.unique);
- count = size;
+ nbytes = size;
+ }
+ CODA_ALLOC(dcbuf, union outputArgs *, nbytes);
+ if (copy_from_user(dcbuf, buf, nbytes)) {
+ CODA_FREE(dcbuf, nbytes);
+ retval = -EFAULT;
+ goto out;
}
- if (copy_from_user(dcbuf, buf, count))
- return -EFAULT;
/* what downcall errors does Venus handle ? */
lock_kernel();
error = coda_downcall(hdr.opcode, dcbuf, sb);
unlock_kernel();
- if ( error) {
- printk("psdev_write: coda_downcall error: %d\n",
- error);
- return 0;
+ CODA_FREE(dcbuf, nbytes);
+ if (error) {
+ printk("psdev_write: coda_downcall error: %d\n", error);
+ retval = error;
+ goto out;
}
- CODA_FREE(dcbuf, size);
- return count;
+ count = nbytes;
+ goto out;
}
-
/* Look for the message on the processing queue. */
+ lock_kernel();
lh = &vcp->vc_processing;
while ( (lh = lh->next) != &vcp->vc_processing ) {
tmp = list_entry(lh, struct upc_req , uc_chain);
@@ -171,31 +177,40 @@ static ssize_t coda_psdev_write(struct file *file, const char *buf,
break;
}
}
+ unlock_kernel();
+
if (!req) {
printk("psdev_write: msg (%ld, %ld) not found\n",
hdr.opcode, hdr.unique);
- return(-ESRCH);
+ retval = -ESRCH;
+ goto out;
}
/* move data into response buffer. */
- if (req->uc_outSize < count) {
+ if (req->uc_outSize < nbytes) {
printk("psdev_write: too much cnt: %d, cnt: %ld, opc: %ld, uniq: %ld.\n",
- req->uc_outSize, (long)count, hdr.opcode, hdr.unique);
- count = req->uc_outSize; /* don't have more space! */
+ req->uc_outSize, (long)nbytes, hdr.opcode, hdr.unique);
+ nbytes = req->uc_outSize; /* don't have more space! */
+ }
+ if (copy_from_user(req->uc_data, buf, nbytes)) {
+ req->uc_flags |= REQ_ABORT;
+ wake_up(&req->uc_sleep);
+ retval = -EFAULT;
+ goto out;
}
- if (copy_from_user(req->uc_data, buf, count))
- return -EFAULT;
/* adjust outsize. is this usefull ?? */
- req->uc_outSize = count;
+ req->uc_outSize = nbytes;
req->uc_flags |= REQ_WRITE;
+ count = nbytes;
CDEBUG(D_PSDEV,
"Found! Count %ld for (opc,uniq)=(%ld,%ld), upc_req at %p\n",
(long)count, hdr.opcode, hdr.unique, &req);
wake_up(&req->uc_sleep);
- return(count);
+out:
+ return(count ? count : retval);
}
/*
@@ -203,45 +218,71 @@ static ssize_t coda_psdev_write(struct file *file, const char *buf,
*/
static ssize_t coda_psdev_read(struct file * file, char * buf,
- size_t count, loff_t *off)
+ size_t nbytes, loff_t *off)
{
+ DECLARE_WAITQUEUE(wait, current);
struct venus_comm *vcp = &coda_upc_comm;
struct upc_req *req;
- int result = count ;
+ ssize_t retval = 0, count = 0;
- CDEBUG(D_PSDEV, "count %ld\n", (long)count);
- if (list_empty(&(vcp->vc_pending))) {
- return -1;
- }
-
- req = list_entry((vcp->vc_pending.next), struct upc_req, uc_chain);
- list_del(&(req->uc_chain));
+ if (nbytes == 0)
+ return 0;
- /* Move the input args into userspace */
- if (req->uc_inSize <= count)
- result = req->uc_inSize;
+ lock_kernel();
- if (count < req->uc_inSize) {
+ add_wait_queue(&vcp->vc_waitq, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ while (list_empty(&vcp->vc_pending)) {
+ if (file->f_flags & O_NONBLOCK) {
+ retval = -EAGAIN;
+ break;
+ }
+ if (signal_pending(current)) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+ schedule();
+ }
+
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&vcp->vc_waitq, &wait);
+
+ if (retval)
+ goto out;
+
+ req = list_entry(vcp->vc_pending.next, struct upc_req,uc_chain);
+ list_del(&req->uc_chain);
+
+ /* Move the input args into userspace */
+ count = req->uc_inSize;
+ if (nbytes < req->uc_inSize) {
printk ("psdev_read: Venus read %ld bytes of %d in message\n",
- (long)count, req->uc_inSize);
+ (long)nbytes, req->uc_inSize);
+ count = nbytes;
}
- if ( copy_to_user(buf, req->uc_data, result))
- return -EFAULT;
+ if (copy_to_user(buf, req->uc_data, count)) {
+ retval = -EFAULT;
+ goto free_out;
+ }
- /* If request was a signal, don't enqueue */
- if (req->uc_opcode == CODA_SIGNAL) {
- CDEBUG(D_PSDEV, "vcread: signal msg (%d, %d)\n",
- req->uc_opcode, req->uc_unique);
- CODA_FREE(req->uc_data, sizeof(struct coda_in_hdr));
- CODA_FREE(req, sizeof(struct upc_req));
- return count;
- }
-
- req->uc_flags |= REQ_READ;
- list_add(&(req->uc_chain), vcp->vc_processing.prev);
+ /* If request was not a signal, enqueue and don't free */
+ if (req->uc_opcode != CODA_SIGNAL) {
+ req->uc_flags |= REQ_READ;
+ list_add(&(req->uc_chain), vcp->vc_processing.prev);
+ goto out;
+ }
+
+ CDEBUG(D_PSDEV, "vcread: signal msg (%d, %d)\n",
+ req->uc_opcode, req->uc_unique);
- return result;
+free_out:
+ CODA_FREE(req->uc_data, sizeof(struct coda_in_hdr));
+ CODA_FREE(req, sizeof(struct upc_req));
+out:
+ unlock_kernel();
+ return (count ? count : retval);
}
@@ -251,7 +292,7 @@ static int coda_psdev_open(struct inode * inode, struct file * file)
ENTRY;
/* first opener: must be lento. Initialize & take its pid */
- if ( file->f_flags == O_RDWR ) {
+ if ( (file->f_flags & O_ACCMODE) == O_RDWR ) {
if ( vcp->vc_pid ) {
printk("Venus pid already set to %d!!\n", vcp->vc_pid);
return -1;
@@ -264,7 +305,7 @@ static int coda_psdev_open(struct inode * inode, struct file * file)
vcp->vc_inuse++;
- if ( file->f_flags == O_RDWR ) {
+ if ( (file->f_flags & O_ACCMODE) == O_RDWR ) {
vcp->vc_pid = current->pid;
vcp->vc_seq = 0;
INIT_LIST_HEAD(&vcp->vc_pending);
@@ -334,6 +375,7 @@ static int coda_psdev_release(struct inode * inode, struct file * file)
static struct file_operations coda_psdev_fops = {
+ owner: THIS_MODULE,
read: coda_psdev_read,
write: coda_psdev_write,
poll: coda_psdev_poll,