Module Name: src Committed By: pooka Date: Tue Dec 22 17:32:03 UTC 2009
Modified Files: src/sys/dev/pud: pud_dev.c Log Message: Handle DIOCGPART in-kernel because a userspace server doesn't have a chance in phobos of handling it. This makes it possible to do a kernel mount of most file systems with the block device backed by a pud userspace server. - i'm too young to compile - hey, no tty rough - hurd me plenty => abstraction-violence - nightmare! To generate a diff of this commit: cvs rdiff -u -r1.5 -r1.6 src/sys/dev/pud/pud_dev.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/pud/pud_dev.c diff -u src/sys/dev/pud/pud_dev.c:1.5 src/sys/dev/pud/pud_dev.c:1.6 --- src/sys/dev/pud/pud_dev.c:1.5 Tue Dec 22 14:12:40 2009 +++ src/sys/dev/pud/pud_dev.c Tue Dec 22 17:32:03 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: pud_dev.c,v 1.5 2009/12/22 14:12:40 pooka Exp $ */ +/* $NetBSD: pud_dev.c,v 1.6 2009/12/22 17:32:03 pooka Exp $ */ /* * Copyright (c) 2007 Antti Kantee. All Rights Reserved. @@ -29,7 +29,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: pud_dev.c,v 1.5 2009/12/22 14:12:40 pooka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pud_dev.c,v 1.6 2009/12/22 17:32:03 pooka Exp $"); #include <sys/param.h> #include <sys/buf.h> @@ -57,13 +57,37 @@ return pud_request(dev, &pc_oc, sizeof(pc_oc), class, type); } +#include <sys/disklabel.h> +/* + * XXX: this is not "reentrant". But then again, partinfo isn't + * exactly safe in any case. + */ +static struct disklabel dl_partinfo; + static int doioctl(dev_t dev, u_long cmd, void *data, int flag, int class, int type) { struct pud_req_ioctl *pc_ioctl; size_t dlen, allocsize; + u_long origcmd = cmd; + void *origdata = NULL; /* XXXgcc */ int error; + /* + * XXX: kludge. This is a horrible abstraction violation, but + * then again DIOCGPART is a horrible ioctl (even more horrible + * than the generic ioctl). We handle it specially here since + * the server in userspace has no chance to handle it. And it's + * a common operation used by most file systems. But really, it + * should be replaced by something a bit more ... transactional. + */ + if (cmd == DIOCGPART) { + cmd = DIOCGDINFO; + origdata = data; + flag = 0; + data = &dl_partinfo; + } + dlen = IOCPARM_LEN(cmd); allocsize = sizeof(struct pud_req_ioctl) + dlen; pc_ioctl = kmem_zalloc(allocsize, KM_SLEEP); @@ -79,6 +103,39 @@ if (cmd & IOC_OUT) memcpy(data, pc_ioctl->pm_data, dlen); + /* + * In case doing the infamous DIOCGPART, issue the real + * ioctl and do pointer arithmetic to figure out the right + * partition. We could use DISKPART() too, but this seems + * "better". + */ + if (origcmd == DIOCGPART) { + struct partinfo *pi, *pi_user; + int labidx; + + CTASSERT(sizeof(struct partinfo) <= sizeof(struct disklabel)); + + pc_ioctl->pm_iocmd = DIOCGPART; + pc_ioctl->pm_flag = 0; + + error = pud_request(dev, pc_ioctl, allocsize, class, type); + if (error) + goto out; + + pi_user = (struct partinfo *)pc_ioctl->pm_data; + labidx = pi_user->part - &pi_user->disklab->d_partitions[0]; + /* userspace error, but punish caller, since we have no infra */ + if (labidx >= MAXPARTITIONS) { + error = E2BIG; + goto out; + } + + pi = origdata; + pi->disklab = &dl_partinfo; + pi->part = &dl_partinfo.d_partitions[labidx]; + + } + out: kmem_free(pc_ioctl, allocsize); return error;