From owner-svn-src-head@FreeBSD.ORG Mon Jun 4 20:45:34 2012 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 53322106564A; Mon, 4 Jun 2012 20:45:34 +0000 (UTC) (envelope-from marius@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 33B5F8FC08; Mon, 4 Jun 2012 20:45:34 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id q54KjYnj064755; Mon, 4 Jun 2012 20:45:34 GMT (envelope-from marius@svn.freebsd.org) Received: (from marius@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q54KjYK7064753; Mon, 4 Jun 2012 20:45:34 GMT (envelope-from marius@svn.freebsd.org) Message-Id: <201206042045.q54KjYK7064753@svn.freebsd.org> From: Marius Strobl Date: Mon, 4 Jun 2012 20:45:34 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r236579 - head/sys/boot/ofw/libofw X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 04 Jun 2012 20:45:34 -0000 Author: marius Date: Mon Jun 4 20:45:33 2012 New Revision: 236579 URL: http://svn.freebsd.org/changeset/base/236579 Log: The workaround added in r151650 for handling firmwares that don't allow a single device to be opened multiple times concurrently unfortunately isn't sufficient with ZFS. This is due to the fact, that ZFS may open different partitions of a single device simultaneously. So the best we can do in this case is to cache the lastly used device path and close and open devices in ofwd_strategy() as needed. PR: 165025 Submitted by: Gavin Mu MFC after: 1 week Modified: head/sys/boot/ofw/libofw/ofw_disk.c Modified: head/sys/boot/ofw/libofw/ofw_disk.c ============================================================================== --- head/sys/boot/ofw/libofw/ofw_disk.c Mon Jun 4 20:36:11 2012 (r236578) +++ head/sys/boot/ofw/libofw/ofw_disk.c Mon Jun 4 20:45:33 2012 (r236579) @@ -31,7 +31,6 @@ __FBSDID("$FreeBSD$"); */ #include -#include #include @@ -43,8 +42,8 @@ __FBSDID("$FreeBSD$"); #include "libofw.h" static int ofwd_init(void); -static int ofwd_strategy(void *devdata, int flag, daddr_t dblk, - size_t size, char *buf, size_t *rsize); +static int ofwd_strategy(void *devdata, int flag, daddr_t dblk, + size_t size, char *buf, size_t *rsize); static int ofwd_open(struct open_file *f, ...); static int ofwd_close(struct open_file *f); static int ofwd_ioctl(struct open_file *f, u_long cmd, void *data); @@ -61,120 +60,109 @@ struct devsw ofwdisk = { ofwd_print }; -struct opened_dev { - ihandle_t handle; - u_int count; - SLIST_ENTRY(opened_dev) link; -}; - -SLIST_HEAD(, opened_dev) opened_devs = SLIST_HEAD_INITIALIZER(opened_devs); +/* + * We're not guaranteed to be able to open a device more than once and there + * is no OFW standard method to determine whether a device is already opened. + * Opening a device multiple times simultaneously happens to work with most + * OFW block device drivers but triggers a trap with at least the driver for + * the on-board controllers of Sun Fire V100 and Ultra 1. Upper layers and MI + * code expect to be able to open a device more than once however. Given that + * different partitions of the same device might be opened at the same time as + * done by ZFS, we can't generally just keep track of the opened devices and + * reuse the instance handle when asked to open an already opened device. So + * the best we can do is to cache the lastly used device path and close and + * open devices in ofwd_strategy() as needed. + */ +static struct ofw_devdesc *kdp; static int ofwd_init(void) { - return 0; + return (0); } static int -ofwd_strategy(void *devdata, int flag, daddr_t dblk, size_t size, char *buf, - size_t *rsize) +ofwd_strategy(void *devdata, int flag __unused, daddr_t dblk, size_t size, + char *buf, size_t *rsize) { struct ofw_devdesc *dp = (struct ofw_devdesc *)devdata; daddr_t pos; int n; + if (dp != kdp) { + if (kdp != NULL) { +#if !defined(__powerpc__) + OF_close(kdp->d_handle); +#endif + kdp = NULL; + } + if ((dp->d_handle = OF_open(dp->d_path)) == -1) + return (ENOENT); + kdp = dp; + } + pos = dblk * 512; do { if (OF_seek(dp->d_handle, pos) < 0) - return EIO; + return (EIO); n = OF_read(dp->d_handle, buf, size); if (n < 0 && n != -2) - return EIO; + return (EIO); } while (n == -2); *rsize = size; - return 0; + return (0); } static int ofwd_open(struct open_file *f, ...) { - char path[256]; struct ofw_devdesc *dp; - struct opened_dev *odp; va_list vl; va_start(vl, f); dp = va_arg(vl, struct ofw_devdesc *); va_end(vl); - /* - * We're not guaranteed to be able to open a device more than once - * simultaneously and there is no OFW standard method to determine - * whether a device is already opened. Opening a device more than - * once happens to work with most OFW block device drivers but - * triggers a trap with at least the driver for the on-board SCSI - * controller in Sun Ultra 1. Upper layers and MI code expect to - * be able to open a device more than once however. As a workaround - * keep track of the opened devices and reuse the instance handle - * when asked to open an already opened device. - */ - SLIST_FOREACH(odp, &opened_devs, link) { - if (OF_instance_to_path(odp->handle, path, sizeof(path)) == -1) - continue; - if (strcmp(path, dp->d_path) == 0) { - odp->count++; - dp->d_handle = odp->handle; - return 0; + + if (dp != kdp) { + if (kdp != NULL) { + OF_close(kdp->d_handle); + kdp = NULL; } + if ((dp->d_handle = OF_open(dp->d_path)) == -1) { + printf("%s: Could not open %s\n", __func__, + dp->d_path); + return (ENOENT); + } + kdp = dp; } - odp = malloc(sizeof(struct opened_dev)); - if (odp == NULL) { - printf("ofwd_open: malloc failed\n"); - return ENOMEM; - } - if ((odp->handle = OF_open(dp->d_path)) == -1) { - printf("ofwd_open: Could not open %s\n", dp->d_path); - free(odp); - return ENOENT; - } - odp->count = 1; - SLIST_INSERT_HEAD(&opened_devs, odp, link); - dp->d_handle = odp->handle; - return 0; + return (0); } static int ofwd_close(struct open_file *f) { struct ofw_devdesc *dev = f->f_devdata; - struct opened_dev *odp; - SLIST_FOREACH(odp, &opened_devs, link) { - if (odp->handle == dev->d_handle) { - odp->count--; - if (odp->count == 0) { - SLIST_REMOVE(&opened_devs, odp, opened_dev, - link); - #if !defined(__powerpc__) - OF_close(odp->handle); - #endif - free(odp); - } - break; - } + if (dev == kdp) { +#if !defined(__powerpc__) + OF_close(dev->d_handle); +#endif + kdp = NULL; } - return 0; + return (0); } static int -ofwd_ioctl(struct open_file *f, u_long cmd, void *data) +ofwd_ioctl(struct open_file *f __unused, u_long cmd __unused, + void *data __unused) { return (EINVAL); } static void -ofwd_print(int verbose) +ofwd_print(int verbose __unused) { }