Here's the patch doing this.

The following changes are introduced:

In the device handling:

 - Store the venus_comm info in an array indexed by the minor device
   number.  (it cannot be stored in the inode, since that belongs to
   the underlying fs)

 - It is also stored in file->private_data.

 - If the device is already used, open() returns EBUSY. This is so
   that clients can iterate through the devices and find a non-used
   one.


In the superblock handling:

 - In the data argument of mount() a coda_mount_data structure is
   passed, containing the file descriptor of the opened device.

 - If this data is invalid (as with current venus) then the first
   device is used (/dev/cfs0). This is for backward compatibility.
   
The mount flags (hard, timeout) are not changed in this patch. I
think, that those should be per-mount, but it is not trivial to do
this with the current sysctl method. Maybe an ioctl for the device
would be better (???).

Miklos

===File ~/patch/coda/multidev-2.4.0-test5.patch=============
diff -ru /tmp/linux/linux-2.4.0-test5.tar.gz@/linux/fs/coda/inode.c 
linux/fs/coda/inode.c
--- /tmp/linux/linux-2.4.0-test5.tar.gz@/linux/fs/coda/inode.c  Wed Jun 21 19:10:02 
2000
+++ linux/fs/coda/inode.c       Mon Aug  7 13:38:28 2000
@@ -18,6 +18,7 @@
 #include <linux/locks.h>
 #include <linux/unistd.h>
 #include <linux/smp_lock.h>
+#include <linux/file.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -48,6 +49,47 @@
        statfs:         coda_statfs,
 };
 
+static int get_device_index(struct coda_mount_data *data)
+{
+       struct file *file;
+       struct inode *inode;
+       int idx;
+
+       if(data == NULL) {
+               printk("coda_read_super: Bad mount data\n");
+               return -1;
+       }
+
+       if(data->version != CODA_MOUNT_VERSION) {
+               printk("coda_read_super: Bad mount version\n");
+               return -1;
+       }
+
+       file = fget(data->fd);
+       inode = NULL;
+       if(file)
+               inode = file->f_dentry->d_inode;
+       
+       if(!inode || !S_ISCHR(inode->i_mode) ||
+          MAJOR(inode->i_rdev) != CODA_PSDEV_MAJOR) {
+               if(file)
+                       fput(file);
+
+               printk("coda_read_super: Bad file\n");
+               return -1;
+       }
+
+       idx = MINOR(inode->i_rdev);
+       fput(file);
+
+       if(idx < 0 || idx >= MAX_CODADEVS) {
+               printk("coda_read_super: Bad minor number\n");
+               return -1;
+       }
+
+       return idx;
+}
+
 static struct super_block * coda_read_super(struct super_block *sb, 
                                            void *data, int silent)
 {
@@ -57,18 +99,38 @@
         ViceFid fid;
        kdev_t dev = sb->s_dev;
         int error;
-
+       int idx;
        ENTRY;
 
-        vc = &coda_upc_comm;
-       sbi = &coda_super_info;
+       idx = get_device_index((struct coda_mount_data *) data);
 
-        if ( sbi->sbi_sb ) {
-               printk("Already mounted\n");
+       /* Ignore errors in data, for backward compatibility */
+       if(idx == -1)
+               idx = 0;
+       
+       printk(KERN_INFO "coda_read_super: device index: %i\n", idx);
+
+       vc = &coda_comms[idx];
+       if (!vc->vc_inuse) {
+               printk("coda_read_super: No pseudo device\n");
+               EXIT;  
+               return NULL;
+       }
+
+        if ( vc->vc_sb ) {
+               printk("coda_read_super: Device already mounted\n");
+               EXIT;  
+               return NULL;
+       }
+
+       sbi = kmalloc(sizeof(struct coda_sb_info), GFP_KERNEL);
+       if(!sbi) {
                EXIT;  
                return NULL;
        }
 
+       vc->vc_sb = sb;
+
        sbi->sbi_sb = sb;
         sbi->sbi_psdev = psdev;
        sbi->sbi_vcomm = vc;
@@ -108,9 +170,9 @@
  error:
        EXIT;  
        if (sbi) {
-               sbi->sbi_vcomm = NULL;
-               sbi->sbi_root = NULL;
-               sbi->sbi_sb = NULL;
+               kfree(sbi);
+               if(vc)
+                       vc->vc_sb = NULL;               
        }
         if (root) {
                 iput(root);
@@ -120,15 +182,15 @@
 
 static void coda_put_super(struct super_block *sb)
 {
-        struct coda_sb_info *sb_info;
+        struct coda_sb_info *sbi;
 
         ENTRY;
 
        coda_cache_clear_all(sb);
-       sb_info = coda_sbp(sb);
-       coda_super_info.sbi_sb = NULL;
+       sbi = coda_sbp(sb);
+       sbi->sbi_vcomm->vc_sb = NULL;
        printk("Coda: Bye bye.\n");
-       memset(sb_info, 0, sizeof(* sb_info));
+       kfree(sbi);
 
        EXIT;
 }
@@ -237,9 +299,4 @@
 /* init_coda: used by filesystems.c to register coda */
 
 DECLARE_FSTYPE( coda_fs_type, "coda", coda_read_super, 0);
-
-int init_coda_fs(void)
-{
-       return register_filesystem(&coda_fs_type);
-}
 
diff -ru /tmp/linux/linux-2.4.0-test5.tar.gz@/linux/fs/coda/psdev.c 
linux/fs/coda/psdev.c
--- /tmp/linux/linux-2.4.0-test5.tar.gz@/linux/fs/coda/psdev.c  Thu Jul 13 06:58:43 
2000
+++ linux/fs/coda/psdev.c       Mon Aug  7 09:58:27 2000
@@ -53,14 +53,13 @@
  * Coda stuff
  */
 extern struct file_system_type coda_fs_type;
-extern int init_coda_fs(void);
 
 /* statistics */
 int           coda_hard    = 0;  /* allows signals during upcalls */
 unsigned long coda_timeout = 30; /* .. secs, then signals will dequeue */
 
-struct coda_sb_info coda_super_info;
-struct venus_comm coda_upc_comm;
+
+struct venus_comm coda_comms[MAX_CODADEVS];
 
 /*
  * Device operations
@@ -68,7 +67,7 @@
 
 static unsigned int coda_psdev_poll(struct file *file, poll_table * wait)
 {
-        struct venus_comm *vcp = &coda_upc_comm;
+        struct venus_comm *vcp = (struct venus_comm *) file->private_data;
        unsigned int mask = POLLOUT | POLLWRNORM;
 
        poll_wait(file, &vcp->vc_waitq, wait);
@@ -101,7 +100,7 @@
 static ssize_t coda_psdev_write(struct file *file, const char *buf, 
                                size_t nbytes, loff_t *off)
 {
-        struct venus_comm *vcp = &coda_upc_comm;
+        struct venus_comm *vcp = (struct venus_comm *) file->private_data;
         struct upc_req *req = NULL;
         struct upc_req *tmp;
        struct list_head *lh;
@@ -109,8 +108,6 @@
        ssize_t retval = 0, count = 0;
        int error;
 
-       if ( !coda_upc_comm.vc_inuse ) 
-               return -EIO;
         /* Peek at the opcode, uniquefier */
        if (copy_from_user(&hdr, buf, 2 * sizeof(u_long)))
                return -EFAULT;
@@ -123,7 +120,7 @@
                 union outputArgs *dcbuf;
                int size = sizeof(*dcbuf);
 
-               sb = coda_super_info.sbi_sb;
+               sb = vcp->vc_sb;
                if ( !sb ) {
                        CDEBUG(D_PSDEV, "coda_psdev_write: downcall, no SB!\n");
                         count = nbytes;
@@ -221,7 +218,7 @@
                               size_t nbytes, loff_t *off)
 {
        DECLARE_WAITQUEUE(wait, current);
-        struct venus_comm *vcp = &coda_upc_comm;
+        struct venus_comm *vcp = (struct venus_comm *) file->private_data;
         struct upc_req *req;
        ssize_t retval = 0, count = 0;
 
@@ -285,21 +282,32 @@
        return (count ? count : retval);
 }
 
-
 static int coda_psdev_open(struct inode * inode, struct file * file)
 {
-        struct venus_comm *vcp = &coda_upc_comm;
+        struct venus_comm *vcp;
+       int idx;
         ENTRY;
-       
-       /* first opener, initialize */
+
        lock_kernel();
+       idx = MINOR(inode->i_rdev);
+       if(idx >= MAX_CODADEVS)
+               return -ENODEV;
+
+       vcp = &coda_comms[idx];
+       if(vcp->vc_inuse)
+               return -EBUSY;
+       
        if (!vcp->vc_inuse++) {
-            INIT_LIST_HEAD(&vcp->vc_pending);
-            INIT_LIST_HEAD(&vcp->vc_processing);
-            vcp->vc_seq = 0;
+               INIT_LIST_HEAD(&vcp->vc_pending);
+               INIT_LIST_HEAD(&vcp->vc_processing);
+               init_waitqueue_head(&vcp->vc_waitq);
+               vcp->vc_sb = 0;
+               vcp->vc_seq = 0;
        }
+       
+       file->private_data = vcp;
 
-       CDEBUG(D_PSDEV, "inuse: %d\n", vcp->vc_inuse);
+       CDEBUG(D_PSDEV, "device %i - inuse: %d\n", idx, vcp->vc_inuse);
 
        EXIT;
        unlock_kernel();
@@ -309,7 +317,7 @@
 
 static int coda_psdev_release(struct inode * inode, struct file * file)
 {
-        struct venus_comm *vcp = &coda_upc_comm;
+        struct venus_comm *vcp = (struct venus_comm *) file->private_data;
         struct upc_req *req;
        struct list_head *lh, *next;
        ENTRY;
@@ -369,29 +377,9 @@
        release:        coda_psdev_release,
 };
 
-
-
-int __init init_coda(void)
-{
-       int status;
-       printk(KERN_INFO "Coda Kernel/Venus communications, v4.6.0, 
[EMAIL PROTECTED]\n");
-       
-       status = init_coda_psdev();
-       if ( status ) {
-               printk("Problem (%d) in init_coda_psdev\n", status);
-               return status;
-       }
-       
-       status = init_coda_fs();
-       if (status) {
-               printk("coda: failed in init_coda_fs!\n");
-       }
-       return status;
-}
-
 static devfs_handle_t devfs_handle = NULL;
 
-int init_coda_psdev(void)
+static int init_coda_psdev(void)
 {
        if(devfs_register_chrdev(CODA_PSDEV_MAJOR,"coda_psdev",
                                 &coda_psdev_fops)) {
@@ -404,9 +392,6 @@
                               CODA_PSDEV_MAJOR, 0,
                               S_IFCHR | S_IRUSR | S_IWUSR,
                               &coda_psdev_fops, NULL);
-       memset(&coda_upc_comm, 0, sizeof(coda_upc_comm));
-       memset(&coda_super_info, 0, sizeof(coda_super_info));
-       init_waitqueue_head(&coda_upc_comm.vc_waitq);
 
        coda_sysctl_init();
 
@@ -414,36 +399,35 @@
 }
 
 
-#ifdef MODULE
-
 MODULE_AUTHOR("Peter J. Braam <[EMAIL PROTECTED]>");
 
-int init_module(void)
+static int __init init_coda(void)
 {
        int status;
-       printk(KERN_INFO "Coda Kernel/Venus communications (module), v5.0-pre1, 
[EMAIL PROTECTED]\n");
+       printk(KERN_INFO "Coda Kernel/Venus communications, v4.6.0, 
[EMAIL PROTECTED]\n");
 
+       
        status = init_coda_psdev();
        if ( status ) {
                printk("Problem (%d) in init_coda_psdev\n", status);
                return status;
        }
-
-       status = init_coda_fs();
+       
+       status = register_filesystem(&coda_fs_type);
        if (status) {
                printk("coda: failed in init_coda_fs!\n");
        }
        return status;
 }
 
-
-void cleanup_module(void)
+static void __exit exit_coda(void)
 {
         int err;
 
         ENTRY;
 
-        if ( (err = unregister_filesystem(&coda_fs_type)) != 0 ) {
+       err = unregister_filesystem(&coda_fs_type);
+        if ( err != 0 ) {
                 printk("coda: failed to unregister filesystem\n");
         }
        devfs_unregister (devfs_handle);
@@ -451,5 +435,5 @@
        coda_sysctl_clean();
 }
 
-#endif
-
+module_init(init_coda);
+module_exit(exit_coda);
diff -ru /tmp/linux/linux-2.4.0-test5.tar.gz@/linux/fs/coda/upcall.c 
linux/fs/coda/upcall.c
--- /tmp/linux/linux-2.4.0-test5.tar.gz@/linux/fs/coda/upcall.c Thu Jun 29 04:31:36 
2000
+++ linux/fs/coda/upcall.c      Mon Aug  7 09:44:46 2000
@@ -607,7 +607,8 @@
  * 
  */
 
-static inline unsigned long coda_waitfor_upcall(struct upc_req *vmp)
+static inline unsigned long coda_waitfor_upcall(struct upc_req *vmp,
+                                               struct venus_comm *vcommp)
 {
        DECLARE_WAITQUEUE(wait, current);
        struct timeval begin = { 0, 0 }, end = { 0, 0 };
@@ -625,7 +626,7 @@
                        set_current_state(TASK_UNINTERRUPTIBLE);
 
                 /* venus died */
-                if ( !coda_upc_comm.vc_inuse )
+                if ( !vcommp->vc_inuse )
                         break;
 
                /* got a reply */
@@ -685,9 +686,9 @@
        struct upc_req *req;
        int error = 0;
 
-ENTRY;
+       ENTRY;
 
-       vcommp = &coda_upc_comm;
+       vcommp = sbi->sbi_vcomm;
        if ( !vcommp->vc_inuse ) {
                printk("No pseudo device in upcall comms at %p\n", vcommp);
                 return -ENXIO;
@@ -724,7 +725,7 @@
         * ENODEV.  */
 
        /* Go to sleep.  Wake up on signals only after the timeout. */
-       runtime = coda_waitfor_upcall(req);
+       runtime = coda_waitfor_upcall(req, vcommp);
        coda_upcall_stats(((union inputArgs *)buffer)->ih.opcode, runtime);
 
        CDEBUG(D_TIMING, "opc: %d time: %ld uniq: %d size: %d\n",
diff -ru /tmp/linux/linux-2.4.0-test5.tar.gz@/linux/fs/filesystems.c 
linux/fs/filesystems.c
--- /tmp/linux/linux-2.4.0-test5.tar.gz@/linux/fs/filesystems.c Sun Jul  9 04:42:43 
2000
+++ linux/fs/filesystems.c      Mon Aug  7 09:44:46 2000
@@ -23,9 +23,6 @@
 #include <linux/lockd/xdr.h>
 #include <linux/init.h>
 
-#ifdef CONFIG_CODA_FS
-extern int init_coda(void);
-#endif
 
 #ifdef CONFIG_DEVPTS_FS
 extern int init_devpts_fs(void);
@@ -37,10 +34,6 @@
 
 #ifdef CONFIG_NFS_FS
        init_nfs_fs();
-#endif
-
-#ifdef CONFIG_CODA_FS
-       init_coda();
 #endif
 
 #ifdef CONFIG_DEVPTS_FS
diff -ru /tmp/linux/linux-2.4.0-test5.tar.gz@/linux/include/linux/coda.h 
linux/include/linux/coda.h
--- /tmp/linux/linux-2.4.0-test5.tar.gz@/linux/include/linux/coda.h     Wed Jun 21 
19:10:02 2000
+++ linux/include/linux/coda.h  Mon Aug  7 10:09:44 2000
@@ -805,5 +805,15 @@
 #define        IS_CTL_FID(fidp)        ((fidp)->Volume == CTL_VOL &&\
                                 (fidp)->Vnode == CTL_VNO &&\
                                 (fidp)->Unique == CTL_UNI)
+
+/* Data passed to mount */
+
+#define CODA_MOUNT_VERSION 1
+
+struct coda_mount_data {
+       int             version;
+       int             fd;       /* Opened device */
+};
+
 #endif 
 
diff -ru /tmp/linux/linux-2.4.0-test5.tar.gz@/linux/include/linux/coda_psdev.h 
linux/include/linux/coda_psdev.h
--- /tmp/linux/linux-2.4.0-test5.tar.gz@/linux/include/linux/coda_psdev.h       Thu 
Jun 29 04:31:36 2000
+++ linux/include/linux/coda_psdev.h    Mon Aug  7 09:44:46 2000
@@ -4,8 +4,6 @@
 #define CODA_PSDEV_MAJOR 67
 #define MAX_CODADEVS  5           /* how many do we allow */
 
-extern struct venus_comm coda_upc_comm;
-extern struct coda_sb_info coda_super_info;
 #define CODA_SUPER_MAGIC       0x73757245
 
 struct coda_sb_info
@@ -26,6 +24,7 @@
        struct list_head    vc_pending;
        struct list_head    vc_processing;
        int                 vc_inuse;
+       struct super_block *vc_sb;
 };
 
 
@@ -35,11 +34,6 @@
 }
 
 
-
-extern void coda_psdev_detach(int unit);
-extern int  init_coda_psdev(void);
-
-
 /* upcalls */
 int venus_rootfid(struct super_block *sb, ViceFid *fidp);
 int venus_getattr(struct super_block *sb, struct ViceFid *fid, 
@@ -112,6 +106,7 @@
 } ;
 
 extern struct coda_upcallstats coda_callstats;
+extern struct venus_comm coda_comms[];
 
 static inline void clstats(int opcode)
 {
============================================================

Reply via email to