2 * An implementation of a loadable kernel mode driver providing 3 * multiple kernel/user space bidirectional communications links. 5 * Author: Alan Cox <alan@cymru.net> 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 10 * 2 of the License, or (at your option) any later version. 12 * Adapted to become the Linux 2.0 Coda pseudo device 13 * Peter Braam <braam@maths.ox.ac.uk> 14 * Michael Callahan <mjc@emmy.smith.edu> 16 * Changes for Linux 2.1 17 * Copyright (c) 1997 Carnegie-Mellon University 20 #include <linux/config.h>/* for CONFIG_PROC_FS */ 21 #include <linux/module.h> 22 #include <linux/errno.h> 23 #include <linux/kernel.h> 24 #include <linux/major.h> 25 #include <linux/sched.h> 27 #include <linux/malloc.h> 28 #include <linux/ioport.h> 29 #include <linux/fcntl.h> 30 #include <linux/delay.h> 31 #include <linux/skbuff.h> 32 #include <linux/proc_fs.h> 33 #include <linux/vmalloc.h> 35 #include <linux/poll.h> 37 #include <asm/segment.h> 38 #include <asm/system.h> 40 #include <asm/uaccess.h> 42 #include <linux/coda.h> 43 #include <linux/coda_linux.h> 44 #include <linux/coda_fs_i.h> 45 #include <linux/coda_psdev.h> 46 #include <linux/coda_cache.h> 47 #include <linux/coda_sysctl.h> 51 * Where is the prototype? 54 intproc_register_dynamic(struct proc_dir_entry
* dir
, 55 struct proc_dir_entry
* dp
); 60 externstruct file_system_type coda_fs_type
; 61 externintinit_coda_fs(void); 62 externintcfsnc_get_info(char*buffer
,char**start
, off_t offset
,int length
,int dummy
); 63 externintcfsnc_nc_info(char*buffer
,char**start
, off_t offset
,int length
,int dummy
); 66 struct coda_upcallstats coda_callstats
; 67 int coda_hard
=0;/* introduces a timeout on upcalls */ 68 unsigned long coda_timeout
=10;/* .. secs, then signals will dequeue */ 69 externstruct coda_sb_info coda_super_info
[MAX_CODADEVS
]; 70 struct vcomm psdev_vcomm
[MAX_CODADEVS
]; 72 /* queue stuff for the messages */ 73 staticinlinevoidinit_queue(struct queue
*head
) 79 staticinlinestruct vmsg
*q_getnext(struct queue
*elt
) 81 return(struct vmsg
*)(elt
->forw
); 84 staticinlineintq_end(struct vmsg
*msg
,struct queue
*queue
) 86 return(struct queue
*)msg
== queue
; 89 staticinlineintq_empty(struct queue
*queue
) 91 return queue
->forw
== queue
; 94 /* insert before head, ie. at the tail */ 95 voidcoda_q_insert(struct queue
*el
,struct queue
*head
) 97 el
->forw
= head
->back
->forw
; 98 el
->back
= head
->back
; 99 head
->back
->forw
= el
; 103 voidcoda_q_remove(struct queue
*el
) 105 el
->forw
->back
= el
->back
; 106 el
->back
->forw
= el
->forw
; 109 static struct vcomm
*coda_psdev2vcomm(struct file
*file
) 111 unsigned int minor
=MINOR(file
->f_dentry
->d_inode
->i_rdev
); 112 struct vcomm
*vcp
= NULL
; 114 if( (minor
>=0) && (minor
< MAX_CODADEVS
) ) 115 vcp
= &psdev_vcomm
[minor
]; 124 static unsigned intcoda_psdev_poll(struct file
*file
, poll_table
* wait
) 126 struct vcomm
*vcp
=coda_psdev2vcomm(file
); 127 unsigned int mask
= POLLOUT
| POLLWRNORM
; 132 poll_wait(file
, &(vcp
->vc_waitq
), wait
); 133 if(!q_empty(&(vcp
->vc_pending
))) 134 mask
|= POLLIN
| POLLRDNORM
; 141 * Receive a message written by Venus to the psdev 144 static ssize_t
coda_psdev_write(struct file
*file
,const char*buf
, 145 size_t count
, loff_t
*off
) 147 struct vcomm
*vcp
=coda_psdev2vcomm(file
); 158 /* Peek at the opcode, uniquefier */ 159 if(copy_from_user(opcodebuf
, buf
,2*sizeof(u_long
))) 161 opcode
= opcodebuf
[0]; 164 CDEBUG(D_PSDEV
,"(process,opc,uniq)=(%d,%ld,%ld)\n", 165 current
->pid
, opcode
, uniq
); 167 if(DOWNCALL(opcode
)) { 168 struct super_block
*sb
= NULL
; 169 union outputArgs
*dcbuf
; 170 size
=sizeof(*dcbuf
); 174 printk("coda_psdev_write: downcall, no SB!\n"); 177 CDEBUG(D_PSDEV
,"handling downcall\n"); 179 if( count
<sizeof(struct cfs_out_hdr
) ) { 180 printk("coda_downcall opc %ld uniq %ld, not enough!\n", 184 CODA_ALLOC(dcbuf
,union outputArgs
*, size
); 186 printk("Coda: downcall opc %ld, uniq %ld, too much!", 190 if(copy_from_user(dcbuf
, buf
, count
)) 193 /* what downcall errors does Venus handle ? */ 194 error
=coda_downcall(opcode
, dcbuf
, sb
); 197 printk("psdev_write: coda_downcall error: %d\n", 201 CODA_FREE(dcbuf
, size
); 206 /* Look for the message on the processing queue. */ 207 for(vmp
=q_getnext(&(vcp
->vc_processing
)); 208 !q_end(vmp
, &(vcp
->vc_processing
)); 209 vmp
=q_getnext(&(vmp
->vm_chain
))) { 210 if(vmp
->vm_unique
== uniq
) { 212 CDEBUG(D_PSDEV
,"Eureka: uniq %ld on queue!\n", uniq
); 215 if(q_end(vmp
, &(vcp
->vc_processing
))) { 216 printk("psdev_write: msg (%ld, %ld) not found\n", 221 /* Remove the message from the processing queue */ 222 coda_q_remove(&(vmp
->vm_chain
)); 224 /* move data into response buffer. */ 225 if(vmp
->vm_outSize
< count
) { 226 printk("psdev_write: too much cnt: %d, cnt: %d, opc: %ld, uniq: %ld.\n", 227 vmp
->vm_outSize
, count
, opcode
, uniq
); 228 count
= vmp
->vm_outSize
;/* don't have more space! */ 230 if(copy_from_user(vmp
->vm_data
, buf
, count
)) 233 /* adjust outsize. is this usefull ?? */ 234 vmp
->vm_outSize
= count
; 235 vmp
->vm_flags
|= VM_WRITE
; 238 "Found! Count %d for (opc,uniq)=(%ld,%ld), vmsg at %x\n", 239 count
, opcode
, uniq
, (int)&vmp
); 241 wake_up(&vmp
->vm_sleep
); 246 * Read a message from the kernel to Venus 249 static ssize_t
coda_psdev_read(struct file
* file
,char* buf
, 250 size_t count
, loff_t
*off
) 252 struct vcomm
*vcp
=coda_psdev2vcomm(file
); 259 /* Get message at head of request queue. */ 260 if(q_empty(&(vcp
->vc_pending
))) { 264 vmp
=q_getnext(&(vcp
->vc_pending
)); 265 coda_q_remove(&(vmp
->vm_chain
)); 267 /* Move the input args into userspace */ 268 if(vmp
->vm_inSize
<= count
) 269 result
= vmp
->vm_inSize
; 271 if(count
< vmp
->vm_inSize
) { 272 printk("psdev_read: Venus read %d bytes of %d in message\n", 273 count
, vmp
->vm_inSize
); 276 if(copy_to_user(buf
, vmp
->vm_data
, result
)) 279 if(vmp
->vm_chain
.forw
==0|| vmp
->vm_chain
.back
==0) 280 printk("coda_psdev_read: bad chain"); 282 /* If request was a signal, don't enqueue */ 283 if(vmp
->vm_opcode
== CFS_SIGNAL
) { 284 CDEBUG(D_PSDEV
,"vcread: signal msg (%d, %d)\n", 285 vmp
->vm_opcode
, vmp
->vm_unique
); 286 CODA_FREE(vmp
->vm_data
,sizeof(struct cfs_in_hdr
)); 287 CODA_FREE(vmp
,sizeof(struct vmsg
)); 291 vmp
->vm_flags
|= VM_READ
; 292 coda_q_insert(&(vmp
->vm_chain
), &(vcp
->vc_processing
)); 298 static intcoda_psdev_open(struct inode
* inode
,struct file
* file
) 300 registerstruct vcomm
*vcp
= NULL
; 303 vcp
=coda_psdev2vcomm(file
); 311 memset(vcp
,0,sizeof(struct vcomm
)); 315 init_queue(&(vcp
->vc_pending
)); 316 init_queue(&(vcp
->vc_processing
)); 318 memset(&coda_callstats
,0,sizeof(struct coda_upcallstats
)); 325 coda_psdev_release(struct inode
* inode
,struct file
* file
) 329 unsigned int minor
=MINOR(file
->f_dentry
->d_inode
->i_rdev
); 332 vcp
=coda_psdev2vcomm(file
); 334 if( !vcp
|| !vcomm_open(vcp
) ) { 335 printk("psdev_release: not open"); 340 /* flush the name cache so that we can unmount */ 341 CDEBUG(D_PSDEV
,"Flushing the cache.\n"); 344 CDEBUG(D_PSDEV
,"Done.\n"); 346 /* if operations are in progress perhaps the kernel 347 can profit from setting the C_DYING flag on the root 348 cnode of Coda filesystems */ 349 if(coda_super_info
[minor
].sbi_root
) { 350 struct coda_inode_info
*cnp
= 351 ITOC(coda_super_info
[minor
].sbi_root
); 352 cnp
->c_flags
|= C_DYING
; 357 /* Wakeup clients so they can return. */ 358 for(vmp
=q_getnext(&(vcp
->vc_pending
)); 359 !q_end(vmp
, &(vcp
->vc_pending
)); 360 vmp
=q_getnext(&(vmp
->vm_chain
))) { 361 /* Free signal request messages and don't wakeup cause 362 no one is waiting. */ 363 if(vmp
->vm_opcode
== CFS_SIGNAL
) { 364 CODA_FREE(vmp
->vm_data
,sizeof(struct cfs_in_hdr
)); 365 CODA_FREE(vmp
, (u_int
)sizeof(struct vmsg
)); 368 wake_up(&vmp
->vm_sleep
); 371 for(vmp
=q_getnext(&(vcp
->vc_processing
)); 372 !q_end(vmp
, &(vcp
->vc_processing
)); 373 vmp
=q_getnext(&(vmp
->vm_chain
))) { 374 wake_up(&vmp
->vm_sleep
); 377 mark_vcomm_closed(vcp
); 384 static struct file_operations coda_psdev_fops
= { 386 coda_psdev_read
,/* read */ 387 coda_psdev_write
,/* write */ 388 NULL
,/* coda_psdev_readdir */ 389 coda_psdev_poll
,/* poll */ 391 NULL
,/* coda_psdev_mmap */ 392 coda_psdev_open
,/* open */ 393 coda_psdev_release
,/* release */ 396 NULL
,/* check_media_change */ 397 NULL
,/* revalidate */ 402 #ifdef CONFIG_PROC_FS 404 struct proc_dir_entry proc_coda
= { 406 S_IFDIR
| S_IRUGO
| S_IXUGO
| S_IWUSR
,2,0,0, 407 0, &proc_net_inode_operations
, 411 struct proc_dir_entry proc_coda_ncstats
= { 413 S_IFREG
| S_IRUGO
,1,0,0, 414 0, &proc_net_inode_operations
, 421 intinit_coda_psdev(void) 423 if(register_chrdev(CODA_PSDEV_MAJOR
,"coda_psdev", &coda_psdev_fops
)) { 424 printk(KERN_ERR
"coda_psdev: unable to get major %d\n", 428 memset(psdev_vcomm
,0,sizeof(psdev_vcomm
)); 429 memset(coda_super_info
,0,sizeof(coda_super_info
)); 430 memset(&coda_callstats
,0,sizeof(coda_callstats
)); 432 #ifdef CONFIG_PROC_FS 433 proc_register(&proc_root
,&proc_coda
); 434 proc_register(&proc_coda
, &proc_coda_ncstats
); 445 MODULE_AUTHOR("Peter J. Braam <braam@cs.cmu.edu>"); 450 printk(KERN_INFO
"Coda Kernel/User communications module 1.0\n"); 452 status
=init_coda_psdev(); 454 printk("Problem (%d) in init_coda_psdev\n", status
); 458 status
=init_coda_fs(); 460 printk("coda: failed in init_coda_fs!\n"); 466 voidcleanup_module(void) 472 if( (err
=unregister_filesystem(&coda_fs_type
)) !=0) { 473 printk("coda: failed to unregister filesystem\n"); 475 unregister_chrdev(CODA_PSDEV_MAJOR
,"coda_psdev"); 479 proc_unregister(&proc_coda
, proc_coda_ncstats
.low_ino
); 480 proc_unregister(&proc_root
, proc_coda
.low_ino
);