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) { ============================================================