Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S265993AbUFDUid (ORCPT ); Fri, 4 Jun 2004 16:38:33 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S265988AbUFDUid (ORCPT ); Fri, 4 Jun 2004 16:38:33 -0400 Received: from mailout.zma.compaq.com ([161.114.64.104]:8722 "EHLO zmamail04.zma.compaq.com") by vger.kernel.org with ESMTP id S265993AbUFDUiY (ORCPT ); Fri, 4 Jun 2004 16:38:24 -0400 Date: Fri, 4 Jun 2004 15:39:01 -0500 From: mikem@beardog.cca.cpqcorp.net To: marcelo.tosati@cyclades.com, axboe@suse.de Cc: linux-kernel@vger.kernel.org, coughlan@redhat.com Subject: cciss update for 2.4.27 Message-ID: <20040604203901.GB5598@beardog.cca.cpqcorp.net> Reply-To: mike.miller@hp.com Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.4.2i Sender: linux-kernel-owner@vger.kernel.org X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 7959 Lines: 213 This patch adds a conversion routine for the x86_64 architecture. When 32-bit user space apps pass pointers into a 64-bit kernel they get munged up. This patch allows our 32-bit Array Configuration Utility and management agents to work to work properly on 64-bit kernels. Please consider this for inclusion. Caveat: this spits out 2 warnings on x86_64 platforms. If someone has a useful suggestion on cleaning these up please let me know. Thanks, mikem ------------------------------------------------------------------------------- drivers/block/cciss.c | 139 +++++++++++++++++++++++++++++++++++++++++++- include/linux/cciss_ioctl.h | 27 ++++++++ 2 files changed, 165 insertions(+), 1 deletion(-) diff -burpN lx2427-rc2.orig/drivers/block/cciss.c lx2427-rc2-ioctl/drivers/block/cciss.c --- lx2427-rc2.orig/drivers/block/cciss.c 2004-04-14 08:05:29.000000000 -0500 +++ lx2427-rc2-ioctl/drivers/block/cciss.c 2004-06-02 15:23:02.000000000 -0500 @@ -487,6 +487,142 @@ static int cciss_release(struct inode *i return 0; } +#ifdef __x86_64__ +/* for AMD 64 bit kernel compatibility with 32-bit userland ioctls */ +extern int sys_ioctl(unsigned int fd, unsigned cmd, unsigned long arg); + +extern int +register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, + unsigned int, unsigned long, struct file *)); +extern int unregister_ioctl32_conversion(unsigned int cmd); + +static int cciss_ioctl32_passthru(unsigned int fd, unsigned cmd, unsigned long arg, struct file *file); +static int cciss_ioctl32_big_passthru(unsigned int fd, unsigned cmd, unsigned long arg, + struct file *file); + +typedef long (*handler type) (unsigned int, unsigned int, unsigned long, + struct file *); + +static struct ioctl32_map { + unsigned int cmd; + handler_type handler; + int registered; +} cciss_ioctl32_map[] = { + { CCISS_GETPCIINFO, (handler_type) sys_ioctl, 0 }, + { CCISS_GETINTINFO, (handler_type) sys_ioctl, 0 }, + { CCISS_SETINTINFO, (handler_type) sys_ioctl, 0 }, + { CCISS_GETNODENAME, (handler_type) sys_ioctl, 0 }, + { CCISS_SETNODENAME, (handler_type) sys_ioctl, 0 }, + { CCISS_GETHEARTBEAT, (handler_type) sys_ioctl, 0 }, + { CCISS_GETBUSTYPES, (handler_type) sys_ioctl, 0 }, + { CCISS_GETFIRMVER, (handler_type) sys_ioctl, 0 }, + { CCISS_GETDRIVVER, (handler_type) sys_ioctl, 0 }, + { CCISS_REVALIDVOLS, (handler_type) sys_ioctl, 0 }, + { CCISS_PASSTHRU32, cciss_ioctl32_passthru, 0 }, + { CCISS_DEREGDISK, (handler_type) sys_ioctl, 0 }, + { CCISS_REGNEWDISK, (handler_type) sys_ioctl, 0 }, + { CCISS_REGNEWD, (handler_type) sys_ioctl, 0 }, + { CCISS_RESCANDISK, (handler_type) sys_ioctl, 0 }, + { CCISS_GETLUNINFO, (handler_type) sys_ioctl, 0 }, + { CCISS_BIG_PASSTHRU32, cciss_ioctl32_big_passthru, 0 }, +}; +#define NCCISS_IOCTL32_ENTRIES (sizeof(cciss_ioctl32_map) / sizeof(cciss_ioctl32_map[0])) +static void register_cciss_ioctl32(void) +{ + int i, rc; + + for (i=0; i < NCCISS_IOCTL32_ENTRIES; i++) { + rc = register_ioctl32_conversion( + cciss_ioctl32_map[i].cmd, + cciss_ioctl32_map[i].handler); + if (rc != 0) { + printk(KERN_WARNING "cciss: failed to register " + "32 bit compatible ioctl 0x%08x\n", + cciss_ioctl32_map[i].cmd); + cciss_ioctl32_map[i].registered = 0; + } else + cciss_ioctl32_map[i].registered = 1; + } +} +static void unregister_cciss_ioctl32(void) +{ + int i, rc; + + for (i=0; i < NCCISS_IOCTL32_ENTRIES; i++) { + if (!cciss_ioctl32_map[i].registered) + continue; + rc = unregister_ioctl32_conversion( + cciss_ioctl32_map[i].cmd); + if (rc == 0) { + cciss_ioctl32_map[i].registered = 0; + continue; + } + printk(KERN_WARNING "cciss: failed to unregister " + "32 bit compatible ioctl 0x%08x\n", + cciss_ioctl32_map[i].cmd); + } +} +int cciss_ioctl32_passthru(unsigned int fd, unsigned cmd, unsigned long arg, + struct file *file) +{ + IOCTL32_Command_struct *arg32 = + (IOCTL32_Command_struct *) arg; + IOCTL_Command_struct arg64; + mm_segment_t old_fs; + int err; + + err = 0; + err |= copy_from_user(&arg64.LUN_info, &arg32->LUN_info, sizeof(arg64.LUN_info)); + err |= copy_from_user(&arg64.Request, &arg32->Request, sizeof(arg64.Request)); + err |= copy_from_user(&arg64.error_info, &arg32->error_info, sizeof(arg64.error_info)); + err |= get_user(arg64.buf_size, &arg32->buf_size); + err |= get_user(arg64.buf, &arg32->buf); + if (err) + return -EFAULT; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_ioctl(fd, CCISS_PASSTHRU, (unsigned long) &arg64); + set_fs(old_fs); + if (err) + return err; + err |= copy_to_user(&arg32->error_info, &arg64.error_info, sizeof(&arg32->error_info)); + if (err) + return -EFAULT; + return err; +} +int cciss_ioctl32_big_passthru(unsigned int fd, unsigned cmd, unsigned long arg, + struct file *file) +{ + BIG_IOCTL32_Command_struct *arg32 = + (BIG_IOCTL32_Command_struct *) arg; + BIG_IOCTL_Command_struct arg64; + mm_segment_t old_fs; + int err; + + err = 0; + err |= copy_from_user(&arg64.LUN_info, &arg32->LUN_info, sizeof(arg64.LUN_info)); + err |= copy_from_user(&arg64.Request, &arg32->Request, sizeof(arg64.Request)); + err |= copy_from_user(&arg64.error_info, &arg32->error_info, sizeof(arg64.error_info)); + err |= get_user(arg64.buf_size, &arg32->buf_size); + err |= get_user(arg64.malloc_size, &arg32->malloc_size); + err |= get_user(arg64.buf, &arg32->buf); + if (err) return -EFAULT; + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_ioctl(fd, CCISS_BIG_PASSTHRU, (unsigned long) &arg64); + set_fs(old_fs); + if (err) + return err; + err |= copy_to_user(&arg32->error_info, &arg64.error_info, sizeof(&arg32->error_info)); + if (err) + return -EFAULT; + return err; +} +#else +static inline void register_cciss_ioctl32(void) {} +static inline void unregister_cciss_ioctl32(void) {} +#endif /* * ioctl */ @@ -3317,7 +3453,7 @@ int __init cciss_init(void) EXPORT_NO_SYMBOLS; static int __init init_cciss_module(void) { - + register_cciss_ioctl32(); return cciss_init(); } @@ -3325,6 +3461,7 @@ static void __exit cleanup_cciss_module( { int i; + unregister_cciss_ioctl32(); pci_unregister_driver(&cciss_pci_driver); /* double check that all controller entrys have been removed */ for (i=0; i< MAX_CTLR; i++) { diff -burpN lx2427-rc2.orig/include/linux/cciss_ioctl.h lx2427-rc2-ioctl/include/linux/cciss_ioctl.h --- lx2427-rc2.orig/include/linux/cciss_ioctl.h 2003-06-13 09:51:38.000000000 -0500 +++ lx2427-rc2-ioctl/include/linux/cciss_ioctl.h 2004-06-02 15:23:02.000000000 -0500 @@ -208,4 +208,31 @@ typedef struct _LogvolInfo_struct{ #define CCISS_GETLUNINFO _IOR(CCISS_IOC_MAGIC, 17, LogvolInfo_struct) #define CCISS_BIG_PASSTHRU _IOWR(CCISS_IOC_MAGIC, 18, BIG_IOCTL_Command_struct) +#ifdef __KERNEL__ +#ifdef __x86_64__ + +/* 32 bit compatible ioctl structs */ +typedef struct _IOCTL32_Command_struct { + LUNAddr_struct LUN_info; + RequestBlock_struct Request; + ErrorInfo_struct error_info; + WORD buf_size; /* size in bytes of the buf */ + __u32 buf; /* 32 bit pointer to data buffer */ +} IOCTL32_Command_struct; + +typedef struct _BIG_IOCTL32_Command_struct { + LUNAddr_struct LUN_info; + RequestBlock_struct Request; + ErrorInfo_struct error_info; + DWORD malloc_size; /* < MAX_KMALLOC_SIZE in cciss.c */ + DWORD buf_size; /* size in bytes of the buf */ + /* < malloc_size * MAXSGENTRIES */ + __u32 buf; /* 32 bit pointer to data buffer */ +} BIG_IOCTL32_Command_struct; + +#define CCISS_PASSTHRU32 _IOWR(CCISS_IOC_MAGIC, 11, IOCTL32_Command_struct) +#define CCISS_BIG_PASSTHRU32 _IOWR(CCISS_IOC_MAGIC, 18, BIG_IOCTL32_Command_struct) + +#endif /* __x86_64__ */ +#endif /* __KERNEL__ */ #endif - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/