diff --git a/bin/Makefile b/bin/Makefile index cfbbfbb1f..1d2a3c8a2 100644 --- a/bin/Makefile +++ b/bin/Makefile @@ -1,7 +1,7 @@ # $NetBSD: Makefile,v 1.22 2007/12/31 15:31:24 ad Exp $ # @(#)Makefile 8.1 (Berkeley) 5/31/93 -SUBDIR= cat date echo ed expr kill ksh ln ls \ +SUBDIR= cat date df echo ed expr kill ksh ln ls \ mkdir pax pwd rm rmdir sync test .include diff --git a/bin/df/Makefile b/bin/df/Makefile new file mode 100644 index 000000000..e3c5edb60 --- /dev/null +++ b/bin/df/Makefile @@ -0,0 +1,11 @@ +# $NetBSD: Makefile,v 1.19 2011/08/28 08:20:58 christos Exp $ +# @(#)Makefile 8.3 (Berkeley) 5/8/95 + +.include + +PROG= df + +LDADD+=-lutil +DPADD+=${LIBUTIL} + +.include diff --git a/bin/df/df.1 b/bin/df/df.1 new file mode 100644 index 000000000..7ab3d0c67 --- /dev/null +++ b/bin/df/df.1 @@ -0,0 +1,206 @@ +.\" $NetBSD: df.1,v 1.44 2010/04/05 21:17:28 joerg Exp $ +.\" +.\" Copyright (c) 1989, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)df.1 8.2 (Berkeley) 1/13/92 +.\" +.Dd March 4, 2008 +.Dt DF 1 +.Os +.Sh NAME +.Nm df +.Nd display free disk space +.Sh SYNOPSIS +.Nm +.Op Fl agklmn +.Op Fl G | Fl i | Fl P +.Op Fl t Ar type +.Op Ar file | Ar file_system ... +.Sh DESCRIPTION +.Nm +displays statistics about the amount of free disk space on the specified +.Ar file_system +or on the file system of which +.Ar file +is a part. +By default, all sizes are reported in 512-byte block counts. +If neither a file or a +.Ar file_system +operand is specified, +statistics for all mounted file systems are displayed +(subject to the +.Fl l +and +.Fl t +options below). +.Pp +Note that the printed count of available blocks takes +.Va minfree +into account, and thus will be negative when the number of free blocks +on the filesystem is less than +.Va minfree . +.Pp +The following options are available: +.Bl -tag -width Ds +.It Fl a +Show all mount points, +including those that were mounted with the +.Dv MNT_IGNORE +flag. +.It Fl G +Display all the fields of the structure(s) returned by +.Xr statvfs 2 . +This option cannot be used with the +.Fl i +or +.Fl P +options, and it is modelled after the Solaris +.Fl g +option. +This option will override the +.Fl g , +.Fl h , +.Fl k , +and +.Fl m +options, as well as any setting of +.Ev BLOCKSIZE . +.It Fl g +The +.Fl g +option causes the numbers to be reported in gigabytes (1024*1024*1024 +bytes). +.It Fl h +"Human-readable" output. +Use unit suffixes: Byte, Kilobyte, Megabyte, +Gigabyte, Terabyte, Petabyte, Exabyte in order to reduce the number of +digits to four or less. +.It Fl i +Include statistics on the number of free inodes. +.It Fl k +By default, all sizes are reported in 512-byte block counts. +The +.Fl k +option causes the numbers to be reported in kilobytes (1024 bytes). +.It Fl l +Display statistics only about mounted file systems with the +.Dv MNT_LOCAL +flag set. +If a non-local file system is given as an argument, a +warning is issued and no information is given on that file system. +.It Fl m +The +.Fl m +option causes the numbers to be reported in megabytes (1024*1024 bytes). +.It Fl n +Print out the previously obtained statistics from the file systems. +This option should be used if it is possible that one or more +file systems are in a state such that they will not be able to provide +statistics without a long delay. +When this option is specified, +.Nm +will not request new statistics from the file systems, but will respond +with the possibly stale statistics that were previously obtained. +.It Fl P +Produce output in the following portable format: +.Pp +If both the +.Fl P +and +.Fl k +option are specified, the output will be preceded by the following header +line, formatted to match the data following it: +.Bd -literal +"Filesystem 1024-blocks Used Available Capacity Mounted on\en" +.Ed +.Pp +If the +.Fl P +option is specified without the +.Fl k +options, the output will be preceded by the following header line, +formatted to match the data following it: +.Bd -literal +"Filesystem \*[Lt]blksize\*[Gt]-blocks Used Available Capacity Mounted on\en" +.Ed +.Pp +The header line is followed by data formatted as follows: +.Bd -literal +"%s %d %d %d %d%% %s\en", \*[Lt]file system name\*[Gt], \*[Lt]total space\*[Gt], + \*[Lt]space used\*[Gt], \*[Lt]space free\*[Gt], \*[Lt]percentage used\*[Gt], + \*[Lt]file system root\*[Gt] +.Ed +.Pp +Note that the +.Fl i +option may not be specified with +.Fl P . +.It Fl t Ar type +Is used to indicate the actions should only be taken on +filesystems of the specified type. +More than one type may be specified in a comma-separated list. +The list of filesystem types can be prefixed with +.Dq no +to specify the filesystem types for which action should +.Em not +be taken. +If a file system is given on the command line that is not of +the specified type, a warning is issued and no information is given on +that file system. +.El +.Sh ENVIRONMENT +.Bl -tag -width BLOCKSIZE +.It Ev BLOCKSIZE +If the environment variable +.Ev BLOCKSIZE +is set, and the +.Fl g , +.Fl h , +.Fl k +and +.Fl m +options are not specified, the block counts will be displayed in units of that +size block. +.El +.Sh SEE ALSO +.Xr quota 1 , +.Xr fstatvfs 2 , +.Xr getvfsstat 2 , +.Xr statvfs 2 , +.Xr getbsize 3 , +.Xr getmntinfo 3 , +.Xr fs 5 , +.Xr fstab 5 , +.Xr mount 8 , +.Xr quot 8 , +.Xr tunefs 8 +.Sh HISTORY +A +.Nm +utility appeared in +.At v6 . diff --git a/bin/df/df.c b/bin/df/df.c new file mode 100644 index 000000000..d36157411 --- /dev/null +++ b/bin/df/df.c @@ -0,0 +1,520 @@ +/* $NetBSD: df.c,v 1.90 2012/01/07 18:45:13 christos Exp $ */ + +/* + * Copyright (c) 1980, 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#ifndef lint +__COPYRIGHT( +"@(#) Copyright (c) 1980, 1990, 1993, 1994\ + The Regents of the University of California. All rights reserved."); +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)df.c 8.7 (Berkeley) 4/2/94"; +#else +__RCSID("$NetBSD: df.c,v 1.90 2012/01/07 18:45:13 christos Exp $"); +#endif +#endif /* not lint */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static char *getmntpt(const char *); +static void prtstat(struct statvfs *, int); +static int selected(const char *, size_t); +static void maketypelist(char *); +static size_t regetmntinfo(struct statvfs **, size_t); +__dead static void usage(void); +static void prthumanval(int64_t, const char *); +static void prthuman(struct statvfs *, int64_t, int64_t); + +static int aflag, gflag, hflag, iflag, lflag, nflag, Pflag; +static long usize; +static char **typelist; + +int +main(int argc, char *argv[]) +{ + struct stat stbuf; + struct statvfs *mntbuf; + long mntsize; + int ch, i, maxwidth, width; + char *mntpt; + + setprogname(argv[0]); + (void)setlocale(LC_ALL, ""); + + while ((ch = getopt(argc, argv, "aGghiklmnPt:")) != -1) + switch (ch) { + case 'a': + aflag = 1; + break; + case 'g': + hflag = 0; + usize = 1024 * 1024 * 1024; + break; + case 'G': + gflag = 1; + break; + case 'h': + hflag = 1; + usize = 0; + break; + case 'i': + iflag = 1; + break; + case 'k': + hflag = 0; + usize = 1024; + break; + case 'l': + lflag = 1; + break; + case 'm': + hflag = 0; + usize = 1024 * 1024; + break; + case 'n': + nflag = 1; + break; + case 'P': + Pflag = 1; + break; + case 't': + if (typelist != NULL) + errx(EXIT_FAILURE, + "only one -t option may be specified."); + maketypelist(optarg); + break; + case '?': + default: + usage(); + } + + if (gflag && (Pflag || iflag)) + errx(EXIT_FAILURE, + "only one of -G and -P or -i may be specified"); + if (Pflag && iflag) + errx(EXIT_FAILURE, + "only one of -P and -i may be specified"); +#if 0 + /* + * The block size cannot be checked until after getbsize() is called. + */ + if (Pflag && (hflag || (usize != 1024 && usize != 512))) + errx(EXIT_FAILURE, + "non-standard block size incompatible with -P"); +#endif + argc -= optind; + argv += optind; + + mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); + if (mntsize == 0) + err(EXIT_FAILURE, + "retrieving information on mounted file systems"); + + if (*argv == NULL) { + mntsize = regetmntinfo(&mntbuf, mntsize); + } else { + if ((mntbuf = malloc(argc * sizeof(*mntbuf))) == NULL) + err(EXIT_FAILURE, "can't allocate statvfs array"); + mntsize = 0; + for (/*EMPTY*/; *argv != NULL; argv++) { + if (stat(*argv, &stbuf) < 0) { + if ((mntpt = getmntpt(*argv)) == 0) { + warn("%s", *argv); + continue; + } + } else if (S_ISBLK(stbuf.st_mode)) { + if ((mntpt = getmntpt(*argv)) == 0) + mntpt = *argv; + } else + mntpt = *argv; + /* + * Statfs does not take a `wait' flag, so we cannot + * implement nflag here. + */ + if (!statvfs(mntpt, &mntbuf[mntsize])) + if (lflag && + (mntbuf[mntsize].f_flag & MNT_LOCAL) == 0) + warnx("Warning: %s is not a local %s", + *argv, "file system"); + else if + (!selected(mntbuf[mntsize].f_fstypename, + sizeof(mntbuf[mntsize].f_fstypename))) + warnx("Warning: %s mounted as a %s %s", + *argv, + mntbuf[mntsize].f_fstypename, + "file system"); + else + ++mntsize; + else + warn("%s", *argv); + } + } + + maxwidth = 0; + for (i = 0; i < mntsize; i++) { + width = (int)strlen(mntbuf[i].f_mntfromname); + if (width > maxwidth) + maxwidth = width; + } + for (i = 0; i < mntsize; i++) + prtstat(&mntbuf[i], maxwidth); + return 0; +} + +static char * +getmntpt(const char *name) +{ + size_t mntsize, i; + struct statvfs *mntbuf; + + mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); + if (mntsize == 0) + err(EXIT_FAILURE, "Can't get mount information"); + for (i = 0; i < mntsize; i++) { + if (!strcmp(mntbuf[i].f_mntfromname, name)) + return mntbuf[i].f_mntonname; + } + return 0; +} + +static enum { IN_LIST, NOT_IN_LIST } which; + +static int +selected(const char *type, size_t len) +{ + char **av; + + /* If no type specified, it's always selected. */ + if (typelist == NULL) + return 1; + for (av = typelist; *av != NULL; ++av) + if (!strncmp(type, *av, len)) + return which == IN_LIST ? 1 : 0; + return which == IN_LIST ? 0 : 1; +} + +static void +maketypelist(char *fslist) +{ + size_t i; + char *nextcp, **av; + + if ((fslist == NULL) || (fslist[0] == '\0')) + errx(EXIT_FAILURE, "empty type list"); + + /* + * XXX + * Note: the syntax is "noxxx,yyy" for no xxx's and + * no yyy's, not the more intuitive "noyyy,noyyy". + */ + if (fslist[0] == 'n' && fslist[1] == 'o') { + fslist += 2; + which = NOT_IN_LIST; + } else + which = IN_LIST; + + /* Count the number of types. */ + for (i = 1, nextcp = fslist; + (nextcp = strchr(nextcp, ',')) != NULL; i++) + ++nextcp; + + /* Build an array of that many types. */ + if ((av = typelist = malloc((i + 1) * sizeof(*av))) == NULL) + err(EXIT_FAILURE, "can't allocate type array"); + av[0] = fslist; + for (i = 1, nextcp = fslist; + (nextcp = strchr(nextcp, ',')) != NULL; i++) { + *nextcp = '\0'; + av[i] = ++nextcp; + } + /* Terminate the array. */ + av[i] = NULL; +} + +/* + * Make a pass over the filesystem info in ``mntbuf'' filtering out + * filesystem types not in ``fsmask'' and possibly re-stating to get + * current (not cached) info. Returns the new count of valid statvfs bufs. + */ +static size_t +regetmntinfo(struct statvfs **mntbufp, size_t mntsize) +{ + size_t i, j; + struct statvfs *mntbuf; + + if (!lflag && typelist == NULL && aflag) + return nflag ? mntsize : (size_t)getmntinfo(mntbufp, MNT_WAIT); + + mntbuf = *mntbufp; + j = 0; + for (i = 0; i < mntsize; i++) { + if (!aflag && (mntbuf[i].f_flag & MNT_IGNORE) != 0) + continue; + if (lflag && (mntbuf[i].f_flag & MNT_LOCAL) == 0) + continue; + if (!selected(mntbuf[i].f_fstypename, + sizeof(mntbuf[i].f_fstypename))) + continue; + if (nflag) + mntbuf[j] = mntbuf[i]; + else { + struct statvfs layerbuf = mntbuf[i]; + (void)statvfs(mntbuf[i].f_mntonname, &mntbuf[j]); + /* + * If the FS name changed, then new data is for + * a different layer and we don't want it. + */ + if (memcmp(layerbuf.f_mntfromname, + mntbuf[j].f_mntfromname, MNAMELEN)) + mntbuf[j] = layerbuf; + } + j++; + } + return j; +} + +static void +prthumanval(int64_t bytes, const char *pad) +{ + char buf[6]; + + (void)humanize_number(buf, sizeof(buf) - (bytes < 0 ? 0 : 1), + bytes, "", HN_AUTOSCALE, + HN_B | HN_NOSPACE | HN_DECIMAL); + + (void)printf("%s %6s", pad, buf); +} + +static void +prthuman(struct statvfs *sfsp, int64_t used, int64_t bavail) +{ + + prthumanval((int64_t)(sfsp->f_blocks * sfsp->f_frsize), " "); + prthumanval((int64_t)(used * sfsp->f_frsize), " "); + prthumanval((int64_t)(bavail * sfsp->f_frsize), " "); +} + +/* + * Convert statvfs returned filesystem size into BLOCKSIZE units. + * Attempts to avoid overflow for large filesystems. + */ +#define fsbtoblk(num, fsbs, bs) \ + (((fsbs) != 0 && (uint64_t)(fsbs) < (uint64_t)(bs)) ? \ + (int64_t)(num) / (int64_t)((bs) / (fsbs)) : \ + (int64_t)(num) * (int64_t)((fsbs) / (bs))) + +/* + * Print out status about a filesystem. + */ +static void +prtstat(struct statvfs *sfsp, int maxwidth) +{ + static long blocksize; + static int headerlen, timesthrough; + static const char *header; + static const char full[] = "100"; + static const char empty[] = " 0"; + int64_t used, availblks, inodes; + int64_t bavail; + char pb[64]; + + if (gflag) { + /* + * From SunOS-5.6: + * + * /var (/dev/dsk/c0t0d0s3 ): 8192 block size 1024 frag size + * 984242 total blocks 860692 free blocks 859708 available 249984 total files + * 248691 free files 8388611 filesys id + * ufs fstype 0x00000004 flag 255 filename length + * + */ + (void)printf("%10s (%-12s): %7ld block size %12ld frag size\n", + sfsp->f_mntonname, sfsp->f_mntfromname, + sfsp->f_iosize, /* On UFS/FFS systems this is + * also called the "optimal + * transfer block size" but it + * is of course the file + * system's block size too. + */ + sfsp->f_bsize); /* not so surprisingly the + * "fundamental file system + * block size" is the frag + * size. + */ + (void)printf("%10" PRId64 " total blocks %10" PRId64 + " free blocks %10" PRId64 " available\n", + (uint64_t)sfsp->f_blocks, (uint64_t)sfsp->f_bfree, + (uint64_t)sfsp->f_bavail); + (void)printf("%10" PRId64 " total files %10" PRId64 + " free files %12lx filesys id\n", + (uint64_t)sfsp->f_ffree, (uint64_t)sfsp->f_files, + sfsp->f_fsid); + (void)printf("%10s fstype %#15lx flag %17ld filename " + "length\n", sfsp->f_fstypename, sfsp->f_flag, + sfsp->f_namemax); + (void)printf("%10lu owner %17" PRId64 " syncwrites %12" PRId64 + " asyncwrites\n\n", (unsigned long)sfsp->f_owner, + sfsp->f_syncwrites, sfsp->f_asyncwrites); + + /* + * a concession by the structured programming police to the + * indentation police.... + */ + return; + } + if (maxwidth < 12) + maxwidth = 12; + if (++timesthrough == 1) { + switch (blocksize = usize) { + case 1024: + header = Pflag ? "1024-blocks" : "1K-blocks"; + headerlen = (int)strlen(header); + break; + case 1024 * 1024: + header = "1M-blocks"; + headerlen = (int)strlen(header); + break; + case 1024 * 1024 * 1024: + header = "1G-blocks"; + headerlen = (int)strlen(header); + break; + default: + if (hflag) { + header = "Size"; + headerlen = (int)strlen(header); + } else + header = getbsize(&headerlen, &blocksize); + break; + } + if (Pflag) { + /* + * either: + * "Filesystem 1024-blocks Used Available Capacity Mounted on\n" + * or: + * "Filesystem 512-blocks Used Available Capacity Mounted on\n" + */ + if (blocksize != 1024 && blocksize != 512) + errx(EXIT_FAILURE, + "non-standard block size incompatible with -P"); + (void)printf("Filesystem %s Used Available Capacity " + "Mounted on\n", header); + } else { + (void)printf("%-*.*s %s Used Avail %%Cap", + maxwidth - (headerlen - 10), + maxwidth - (headerlen - 10), + "Filesystem", header); + if (iflag) + (void)printf(" iUsed iAvail %%iCap"); + (void)printf(" Mounted on\n"); + } + } + used = sfsp->f_blocks - sfsp->f_bfree; + bavail = sfsp->f_bfree - sfsp->f_bresvd; + availblks = bavail + used; + if (Pflag) { + assert(hflag == 0); + assert(blocksize > 0); + /* + * "%s %d %d %d %s %s\n", , , + * , , , + * + */ + (void)printf("%s %" PRId64 " %" PRId64 " %" PRId64 " %s%% %s\n", + sfsp->f_mntfromname, + fsbtoblk(sfsp->f_blocks, sfsp->f_frsize, blocksize), + fsbtoblk(used, sfsp->f_frsize, blocksize), + fsbtoblk(bavail, sfsp->f_frsize, blocksize), + availblks == 0 ? full : strspct(pb, sizeof(pb), used, + availblks, 0), sfsp->f_mntonname); + /* + * another concession by the structured programming police to + * the indentation police.... + * + * Note iflag cannot be set when Pflag is set. + */ + return; + } + + (void)printf("%-*.*s ", maxwidth, maxwidth, sfsp->f_mntfromname); + + if (hflag) + prthuman(sfsp, used, bavail); + else + (void)printf("%10" PRId64 " %10" PRId64 " %10" PRId64, + fsbtoblk(sfsp->f_blocks, sfsp->f_frsize, blocksize), + fsbtoblk(used, sfsp->f_frsize, blocksize), + fsbtoblk(bavail, sfsp->f_frsize, blocksize)); + (void)printf(" %3s%%", + availblks == 0 ? full : + strspct(pb, sizeof(pb), used, availblks, 0)); + if (iflag) { + inodes = sfsp->f_files; + used = inodes - sfsp->f_ffree; + (void)printf(" %8jd %8jd %3s%%", + (intmax_t)used, (intmax_t)sfsp->f_ffree, + inodes == 0 ? (used == 0 ? empty : full) : + strspct(pb, sizeof(pb), used, inodes, 0)); + } + (void)printf(" %s\n", sfsp->f_mntonname); +} + +static void +usage(void) +{ + + (void)fprintf(stderr, + "Usage: %s [-aGgln] [-hkm|-ihkm|-Pk] [-t type] [file | " + "file_system ...]\n", + getprogname()); + exit(1); + /* NOTREACHED */ +} diff --git a/commands/DESCRIBE/DESCRIBE.sh b/commands/DESCRIBE/DESCRIBE.sh index 63560ae36..b028e7667 100644 --- a/commands/DESCRIBE/DESCRIBE.sh +++ b/commands/DESCRIBE/DESCRIBE.sh @@ -196,6 +196,22 @@ do 18,0) des="UNIX domain socket" dev=uds ;; + 5[6-9],0|6[0-3],0) + drive=`expr $major - 56` + des="vnode disk $drive" dev=vnd$drive + ;; + 5[6-9],[1-4]|6[0-3],[1-4]) + drive=`expr $major - 56` + par=`expr $minor - 1` + des="vnode disk $drive partition $par" dev=vnd${drive}p${par} + ;; + 5[6-9],12[89]|5[6-9],13[0-9]|5[6-9],14[0-3]|6[0-3],12[89]|5[6-9],13[0-9]|5[6-9],14[0-3]) + drive=`expr $major - 56` + par=`expr \\( \\( $minor - 128 \\) / 4 \\) % 4` + sub=`expr \\( $minor - 128 \\) % 4` + des="vnode disk $drive partition $par slice $sub" + dev=vnd${drive}p${par}s${sub} + ;; BAD,BAD) des= dev= ;; diff --git a/commands/MAKEDEV/MAKEDEV.sh b/commands/MAKEDEV/MAKEDEV.sh index 9a4c1a9cd..83e2270a8 100644 --- a/commands/MAKEDEV/MAKEDEV.sh +++ b/commands/MAKEDEV/MAKEDEV.sh @@ -33,7 +33,9 @@ case $#:$1 in eepromb3s54 eepromb3s55 eepromb3s56 eepromb3s57 \ tsl2550b1s39 tsl2550b2s39 tsl2550b3s39 \ sht21b1s40 sht21b2s40 sht21b3s40 \ - bmp085b1s77 bmp085b2s77 bmp085b3s77 + bmp085b1s77 bmp085b2s77 bmp085b3s77 \ + vnd0 vnd0p0 vnd0p0s0 vnd1 vnd1p0 vnd1p0s0 \ + vnd2 vnd3 vnd4 vnd5 vnd6 vnd7 ;; 0:|1:-\?) cat >&2 <&2 ex=1 diff --git a/commands/Makefile b/commands/Makefile index bfe16beb3..dc0d86500 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -6,11 +6,11 @@ SUBDIR= add_route arp ash at backup btrace \ cawf cd cdprobe cpp \ chmod chown ci cleantmp cmp co \ comm compress cp crc cron crontab cut \ - dd decomp16 DESCRIBE devmand devsize df dhcpd \ - dhrystone diff diskctl dumpcore \ + dd decomp16 DESCRIBE devmand devsize dhcpd \ + dhrystone diff diskctl \ eject env factor fbdctl \ find fix fold format fortune fsck.mfs \ - gcore gcov-pull getty grep hexdump host \ + gcov-pull getty grep hexdump host \ hostaddr id ifconfig ifdef \ intr ipcrm ipcs irdpd isoread last \ less loadkeys loadramdisk logger look lp \ diff --git a/commands/df/Makefile b/commands/df/Makefile deleted file mode 100644 index a77a7bffa..000000000 --- a/commands/df/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -PROG= df -MAN= - -.include diff --git a/commands/df/df.c b/commands/df/df.c deleted file mode 100644 index be07620b8..000000000 --- a/commands/df/df.c +++ /dev/null @@ -1,237 +0,0 @@ -/* df - disk free block printout Author: Andy Tanenbaum - * - * 91/04/30 Kees J. Bot (kjb@cs.vu.nl) - * Map filename arguments to the devices they live on. - * Changed output to show percentages. - * - * 92/12/12 Kees J. Bot - * Posixized. (Almost, the normal output is in kilobytes, it should - * be 512-byte units. 'df -P' and 'df -kP' are as it should be.) - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct mtab { /* List of mounted devices from /etc/mtab. */ - struct mtab *next; - dev_t device; - char *devname; - char *mountpoint; -} *mtab= NULL; - -struct mtab *searchtab(char *name); -static void readmtab(const char *type); -int df(const struct mtab *mt); - -int iflag= 0; /* Focus on inodes instead of blocks. */ -int Pflag= 0; /* Posix standard output. */ -int kflag= 0; /* Output in kilobytes instead of 512 byte units for -P. */ -int istty; /* isatty(1) */ - -void usage(void) -{ - fprintf(stderr, "Usage: df [-ikP] [-t type] [device]...\n"); - exit(1); -} - -int unitsize; - -int main(int argc, char *argv[]) -{ - int i; - struct mtab *mt; - char *type= "dev"; - int ex= 0; - - while (argc > 1 && argv[1][0] == '-') { - char *opt= argv[1]+1; - - while (*opt != 0) { - switch (*opt++) { - case 'i': iflag= 1; break; - case 'k': kflag= 1; break; - case 'P': Pflag= 1; break; - case 't': - if (argc < 3) usage(); - type= argv[2]; - argv++; - argc--; - break; - default: - usage(); - } - } - argc--; - argv++; - } - - istty= isatty(1); - - readmtab(type); - - if(!Pflag || (Pflag && kflag)) unitsize = 1024; - else unitsize = 512; - - if (Pflag) { - if (!iflag) - printf("\ -Filesystem %4d-blocks Used Available Capacity Mounted on\n", - unitsize); - else - printf("\ -Filesystem Inodes IUsed IFree %%IUsed Mounted on\n" - ); - } else { - printf("%s\n", !iflag ? "\ -Filesystem Size (kB) Free Used % Files% Mounted on" : "\ -Filesystem Files Free Used % BUsed% Mounted on" - ); - } - - if (argc == 1) { - for (mt= mtab; mt != NULL; mt= mt->next) ex |= df(mt); - } else { - for (i = 1; i < argc; i++) ex |= df(searchtab(argv[i])); - } - exit(ex); -} - -static void readmtab(const char *type) -/* Turn the mounted file table into a list. */ -{ - struct mtab **amt= &mtab, *new; - struct stat st; - char devname[PATH_MAX], mountpoint[PATH_MAX], version[MNTNAMELEN], - rw_flag[MNTFLAGLEN]; - - if (load_mtab("df") < 0) exit(1); - - while (get_mtab_entry(devname, mountpoint, version, rw_flag), - devname[0] != 0) { - if (strcmp(type, "dev") != 0 && strcmp(type, version) != 0) continue; - - /* Make new list cell. */ - if ((new= (struct mtab *) malloc(sizeof(*new))) == NULL - || (new->devname= (char *) malloc(strlen(devname) + 1)) == NULL - || (new->mountpoint= (char *) malloc(strlen(mountpoint) + 1)) == NULL - ) break; - - if (strcmp(devname, "none") != 0 && stat(devname, &st) == 0 && - S_ISBLK(st.st_mode)) { - new->device= st.st_rdev; - } else if (stat(mountpoint, &st) == 0) { - new->device= st.st_dev; - } - strcpy(new->devname, devname); - strcpy(new->mountpoint, mountpoint); - - *amt= new; /* Add the cell to the end. */ - amt= &new->next; - *amt= NULL; - } -} - -struct mtab *searchtab(char *name) -/* See what we can do with a user supplied name, there are three possibilities: - * 1. It's a device and it is in the mtab: Return mtab entry. - * 2. It's a file and lives on a device in the mtab: Return mtab entry. - * 3. It's anything else: Return something df() will choke on. - */ -{ - static struct mtab unknown; - struct mtab *mt; - struct stat st; - - unknown.devname= name; - unknown.mountpoint= ""; - - if (stat(name, &st) < 0) return &unknown; /* Case 3. */ - - unknown.device= S_ISBLK(st.st_mode) ? st.st_rdev : st.st_dev; - - for (mt= mtab; mt != NULL; mt= mt->next) { - if (unknown.device == mt->device) - return mt; /* Case 1 & 2. */ - } - - return &unknown; /* Case 3. */ -} - -/* (num / tot) in percentages rounded up. */ -#define percent(num, tot) \ - ((tot > 0) ? ((int) ((100ULL * (num) + ((tot) - 1)) / (tot))) : 0) - -int df(const struct mtab *mt) -{ - long totblocks, busyblocks, totinodes, busyinodes; - struct statvfs sv; - int n; - - if (statvfs(mt->mountpoint, &sv) < 0) { - fprintf(stderr, "df: %s: %s\n", mt->devname, strerror(errno)); - return(1); - } - - /* Print results. */ - printf("%s", mt->devname); - n= strlen(mt->devname); - if (n > 15 && istty) { putchar('\n'); n= 0; } - while (n < 15) { putchar(' '); n++; } - - totblocks = sv.f_blocks; - busyblocks = sv.f_blocks - sv.f_bfree; - - busyblocks = busyblocks * (sv.f_bsize/512) / (unitsize/512); - totblocks = totblocks * (sv.f_bsize/512) / (unitsize/512); - - totinodes = sv.f_files; - busyinodes = sv.f_files - sv.f_ffree; - - if (!Pflag && !iflag) { - printf(" %9ld %9ld %9ld %3d%% %3d%% %s\n", - totblocks, /* Blocks */ - totblocks - busyblocks, /* free */ - busyblocks, /* used */ - percent(busyblocks, totblocks), /* % */ - percent(busyinodes, totinodes), /* FUsed% */ - mt->mountpoint /* Mounted on */ - ); - } - if (!Pflag && iflag) { - printf(" %9ld %9ld %9ld %3d%% %3d%% %s\n", - totinodes, /* Files */ - totinodes - busyinodes, /* free */ - busyinodes, /* used */ - percent(busyinodes, totinodes), /* % */ - percent(busyblocks, totblocks), /* BUsed% */ - mt->mountpoint /* Mounted on */ - ); - } - if (Pflag && !iflag) { - printf(" %9ld %9ld %9ld %4d%% %s\n", - totblocks, /* Blocks */ - busyblocks, /* Used */ - totblocks - busyblocks, /* Available */ - percent(busyblocks, totblocks), /* Capacity */ - mt->mountpoint /* Mounted on */ - ); - } - if (Pflag && iflag) { - printf(" %9ld %9ld %9ld %4d%% %s\n", - totinodes, /* Inodes */ - busyinodes, /* IUsed */ - totinodes - busyinodes, /* IAvail */ - percent(busyinodes, totinodes), /* Capacity */ - mt->mountpoint /* Mounted on */ - ); - } - return(0); -} diff --git a/commands/dumpcore/Makefile b/commands/dumpcore/Makefile deleted file mode 100644 index 3b469fb13..000000000 --- a/commands/dumpcore/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -PROG= dumpcore -CPPFLAGS+= -I${NETBSDSRCDIR} -MAN= - -.include diff --git a/commands/dumpcore/dumpcore.c b/commands/dumpcore/dumpcore.c deleted file mode 100644 index ca6b70bc6..000000000 --- a/commands/dumpcore/dumpcore.c +++ /dev/null @@ -1,71 +0,0 @@ -/* dumpcore - create core file of running process */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "kernel/proc.h" - -#define CLICK_WORDS (CLICK_SIZE / sizeof(unsigned long)) - -int main(int argc, char *argv[]) -{ - pid_t pid; - int r, status; - - if(argc != 2) { - printf("usage: %s \n", argv[0]); - return 1; - } - - pid = atoi(argv[1]); - - if (ptrace(T_ATTACH, pid, 0, 0) != 0) { - perror("ptrace(T_ATTACH)"); - return 1; - } - - if (waitpid(pid, &status, 0) != pid) { - perror("waitpid"); - return 1; - } - - while (WIFSTOPPED(status) && WSTOPSIG(status) != SIGSTOP) { - /* whatever happens here is fine */ - ptrace(T_RESUME, pid, 0, WSTOPSIG(status)); - - if (waitpid(pid, &status, 0) != pid) { - perror("waitpid"); - return 1; - } - } - - if (!WIFSTOPPED(status)) { - fprintf(stderr, "process died while attaching\n"); - return 1; - } - - if (ptrace(T_DUMPCORE, pid, 0, 0) != 0) { - fprintf(stderr, "warning, dumpcore failed (%s)\n", - strerror(errno)); - } - - if (ptrace(T_DETACH, pid, 0, 0)) { - fprintf(stderr, "warning, detaching failed (%s)\n", - strerror(errno)); - } - - return r; -} diff --git a/commands/fdisk/fdisk.c b/commands/fdisk/fdisk.c index 4c237f27a..5b41d8308 100644 --- a/commands/fdisk/fdisk.c +++ b/commands/fdisk/fdisk.c @@ -75,7 +75,7 @@ char *secbuf; int badbases; int badsizes; int badorders; -char *devname; +char *dev_name; int nhead; int nsec; int ncyl = 1024; @@ -161,9 +161,9 @@ int main(int argc, char *argv[]) } if (argn == argc) - devname = DEFAULT_DEV; + dev_name = DEFAULT_DEV; else if (argn == argc - 1) - devname = argv[argn]; + dev_name = argv[argn]; else usage(); @@ -232,7 +232,7 @@ void getgeom(void) if (override) return; - if ((fd= open(devname, O_RDONLY)) < 0) return; + if ((fd= open(dev_name, O_RDONLY)) < 0) return; r = ioctl(fd, DIOCGETP, &geom); close(fd); @@ -242,21 +242,21 @@ void getgeom(void) nsec = geom.sectors; ncyl = geom.cylinders; - printf("Geometry of %s: %dx%dx%d\n", devname, ncyl, nhead, nsec); + printf("Geometry of %s: %dx%dx%d\n", dev_name, ncyl, nhead, nsec); } static int devfd; void getboot(char *buffer) { - devfd = open(devname, 2); + devfd = open(dev_name, 2); if (devfd < 0) { - printf("No write permission on %s\n", devname); + printf("No write permission on %s\n", dev_name); readonly = 1; - devfd = open(devname, 0); + devfd = open(dev_name, 0); } if (devfd < 0) { - printf("Cannot open device %s\n", devname); + printf("Cannot open device %s\n", dev_name); exit(1); } if (read(devfd, buffer, SECSIZE) != SECSIZE) { @@ -264,7 +264,7 @@ void getboot(char *buffer) exit(1); } if (* (unsigned short *) &buffer[510] != 0xAA55) { - printf("Invalid boot sector on %s.\n", devname); + printf("Invalid boot sector on %s.\n", dev_name); printf("Partition table reset and boot code installed.\n"); memset(buffer, 0, 512); memcpy(buffer, bootstrap, sizeof(bootstrap)); @@ -514,8 +514,8 @@ int chk_table(void) printf( "Disk appears to have mis-specified number of heads or sectors.\n"); printf("Try fdisk -h%d -s%d %s instead of\n", - maxhead + 1, maxsec, devname); - printf(" fdisk -h%d -s%d %s\n", nhead, nsec, devname); + maxhead + 1, maxsec, dev_name); + printf(" fdisk -h%d -s%d %s\n", nhead, nsec, dev_name); seenpart = 0; } } else { @@ -695,12 +695,12 @@ void getboot(char *buffer) segread(&sregs); /* get ds */ - if (devname[1] != ':') { - printf("Invalid drive %s\n", devname); + if (dev_name[1] != ':') { + printf("Invalid drive %s\n", dev_name); exit(1); } - if (*devname >= 'a') *devname += 'A' - 'a'; - drivenum = (*devname - 'C') & 0xff; + if (*dev_name >= 'a') *dev_name += 'A' - 'a'; + drivenum = (*dev_name - 'C') & 0xff; if (drivenum < 0 || drivenum > 7) { printf("Funny drive number %d\n", drivenum); exit(1); diff --git a/commands/gcore/Makefile b/commands/gcore/Makefile deleted file mode 100644 index 4ad31cc0e..000000000 --- a/commands/gcore/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -PROG= gcore -MAN= - -.include diff --git a/commands/gcore/gcore.c b/commands/gcore/gcore.c deleted file mode 100644 index d07d9c0b2..000000000 --- a/commands/gcore/gcore.c +++ /dev/null @@ -1,58 +0,0 @@ -/* gcore - create core file of running process */ - -#include -#include -#include -#include -#include -#include -#include -#include - -int main(int argc, char *argv[]) -{ - pid_t pid; - int status; - - if(argc != 2) { - printf("usage: %s \n", argv[0]); - return 1; - } - - pid = atoi(argv[1]); - - if (ptrace(T_ATTACH, pid, 0, 0) != 0) { - perror("ptrace(T_ATTACH)"); - return 1; - } - - if (waitpid(pid, &status, 0) != pid) { - perror("waitpid"); - return 1; - } - - while (WIFSTOPPED(status) && WSTOPSIG(status) != SIGSTOP) { - /* whatever happens here is fine */ - ptrace(T_RESUME, pid, 0, WSTOPSIG(status)); - - if (waitpid(pid, &status, 0) != pid) { - perror("waitpid"); - return 1; - } - } - - if (!WIFSTOPPED(status)) { - fprintf(stderr, "process died while attaching\n"); - return 1; - } - - if (ptrace(T_DUMPCORE, pid, 0, 0)) { - fprintf(stderr, "warning, dumpcore failed (%s)\n", strerror(errno)); - } - - if (ptrace(T_DETACH, pid, 0, 0)) { - fprintf(stderr, "warning, detaching failed (%s)\n", strerror(errno)); - } - - return 0; -} diff --git a/commands/mount/mount.c b/commands/mount/mount.c index f4e463cad..fa34bcccd 100644 --- a/commands/mount/mount.c +++ b/commands/mount/mount.c @@ -24,11 +24,12 @@ int main(argc, argv) int argc; char *argv[]; { - int all = 0, i, v = 0, mountflags; + int all = 0, i, v = 0, mountflags, srvflags; char **ap, *opt, *err, *type, *args, *device; if (argc == 1) list(); /* just list /etc/mtab */ mountflags = 0; + srvflags = 0; type = NULL; args = NULL; ap = argv+1; @@ -36,12 +37,12 @@ char *argv[]; if (argv[i][0] == '-') { opt = argv[i]+1; while (*opt != 0) switch (*opt++) { - case 'r': mountflags |= MS_RDONLY; break; + case 'r': mountflags |= MNT_RDONLY; break; case 't': if (++i == argc) usage(); type = argv[i]; break; - case 'i': mountflags |= MS_REUSE; break; - case 'e': mountflags |= MS_EXISTING; break; + case 'i': srvflags |= MS_REUSE; break; + case 'e': srvflags |= MS_EXISTING; break; case 'n': write_mtab = 0; break; case 'o': if (++i == argc) usage(); args = argv[i]; @@ -75,7 +76,7 @@ char *argv[]; } } - if (mount(device, argv[2], mountflags, type, args) < 0) { + if (mount(device, argv[2], mountflags, srvflags, type, args) < 0) { err = strerror(errno); fprintf(stderr, "mount: Can't mount %s on %s: %s\n", argv[1], argv[2], err); @@ -141,7 +142,7 @@ mount_all() if (has_opt(fs->fs_mntops, "ro")) ro = 1; if (ro) { - mountflags |= MS_RDONLY; + mountflags |= MNT_RDONLY; } device = fs->fs_spec; @@ -152,7 +153,7 @@ mount_all() if (!strcmp(device, "none")) device = NULL; - if (mount(device, mountpoint, mountflags, fs->fs_vfstype, + if (mount(device, mountpoint, mountflags, 0, fs->fs_vfstype, fs->fs_mntops) != 0) { err = strerror(errno); fprintf(stderr, "mount: Can't mount %s on %s: %s\n", diff --git a/commands/playwave/playwave.c b/commands/playwave/playwave.c index 53b92d8dc..28bdbf588 100644 --- a/commands/playwave/playwave.c +++ b/commands/playwave/playwave.c @@ -66,15 +66,36 @@ void usage() exit(-1); } +int open_audio(unsigned int *fragment_size, unsigned int channels, + unsigned int samples_per_sec, unsigned int bits) +{ + unsigned int sign; + int audio; + + /* Open DSP */ + if ((audio = open("/dev/audio", O_RDWR | O_REOPEN)) < 0) + { + printf("Cannot open /dev/audio: %s\n", strerror(errno)); + exit(-1); + } + + ioctl(audio, DSPIOMAX, fragment_size); /* Get maximum fragment size. */ + + /* Set DSP parameters (should check return values..) */ + ioctl(audio, DSPIOSIZE, fragment_size); /* Use max. fragment size. */ + ioctl(audio, DSPIOSTEREO, &channels); + ioctl(audio, DSPIORATE, &samples_per_sec); + ioctl(audio, DSPIOBITS, &bits); + sign = (bits == 16 ? 1 : 0); + ioctl(audio, DSPIOSIGN, &sign); + return audio; +} int main ( int argc, char *argv[] ) { int i, r, audio, file; char *buffer, *file_name = NULL; - unsigned int sign; - unsigned int fragment_size; - unsigned int channels; - unsigned int bits; + unsigned int fragment_size, fragment_size2; long data_pos; int showinfo = 0; @@ -91,22 +112,6 @@ int main ( int argc, char *argv[] ) } else file_name = argv[1]; - /* Open DSP */ - if ((audio = open("/dev/audio", O_RDWR | O_REOPEN)) < 0) - { - printf("Cannot open /dev/audio: %s\n", strerror(errno)); - exit(-1); - } - - /* Get maximum fragment size and try to allocate a buffer */ - ioctl(audio, DSPIOMAX, &fragment_size); - if ((buffer = malloc(fragment_size)) == (char *)0) - { - fprintf(stderr, "Cannot allocate buffer\n"); - exit(-1); - } - ioctl(audio, DSPIOSIZE, &fragment_size); - /* Open wav file */ if((file = open(file_name, O_RDONLY)) < 0) { @@ -141,15 +146,15 @@ int main ( int argc, char *argv[] ) exit(1); } - /* Set DSP parameters */ - channels = c_fields.Channels; - channels--; - bits = s_fields.BitsPerSample; - ioctl(audio, DSPIOSTEREO, &channels); - ioctl(audio, DSPIORATE, &c_fields.SamplesPerSec); - ioctl(audio, DSPIOBITS, &bits); - sign = (bits == 16 ? 1 : 0); - ioctl(audio, DSPIOSIGN, &sign); + /* Open audio device and set DSP parameters */ + audio = open_audio(&fragment_size, c_fields.Channels - 1, + c_fields.SamplesPerSec, s_fields.BitsPerSample); + + if ((buffer = malloc(fragment_size)) == (char *)0) + { + fprintf(stderr, "Cannot allocate buffer\n"); + exit(-1); + } /* Goto data chunk */ lseek(file, data_pos, SEEK_SET); @@ -203,6 +208,20 @@ int main ( int argc, char *argv[] ) { fprintf(stderr, "playwave: write to audio device failed: %s\n", strerror(errno)); + + /* If we get EIO, the driver might have restarted. Reopen the + * audio device. + */ + if (errno == EIO) { + close(audio); + audio = open_audio(&fragment_size2, + c_fields.Channels - 1, c_fields.SamplesPerSec, + s_fields.BitsPerSample); + if (fragment_size2 != fragment_size) { + fprintf(stderr, "Fragment size has changed\n"); + exit(1); + } + } } else { diff --git a/commands/ps/ps.c b/commands/ps/ps.c index c421c7ab9..0b69eb21a 100644 --- a/commands/ps/ps.c +++ b/commands/ps/ps.c @@ -203,7 +203,6 @@ static char *prrecv(struct pstat *ps) case FSTATE_LOCK: blkstr = "flock"; break; case FSTATE_POPEN: blkstr = "popen"; break; case FSTATE_SELECT: blkstr = "select"; break; - case FSTATE_DOPEN: blkstr = "dopen"; break; case FSTATE_TASK: blkstr = taskname(ps->ps_ftask); break; default: blkstr = "??"; break; } diff --git a/commands/service/parse.c b/commands/service/parse.c index a84db8012..342080ba0 100644 --- a/commands/service/parse.c +++ b/commands/service/parse.c @@ -734,6 +734,7 @@ struct { "PROCCTL", VM_PROCCTL }, { "MAPCACHEPAGE", VM_MAPCACHEPAGE }, { "SETCACHEPAGE", VM_SETCACHEPAGE }, + { "CLEARCACHE", VM_CLEARCACHE }, { "VFS_MMAP", VM_VFS_MMAP }, { "VFS_REPLY", VM_VFS_REPLY }, { NULL, 0 }, diff --git a/commands/service/service.c b/commands/service/service.c index 09a4f4c1c..b20b65a14 100644 --- a/commands/service/service.c +++ b/commands/service/service.c @@ -334,10 +334,10 @@ static int parse_arguments(int argc, char **argv, u32_t *rss_flags) } } else if (strcmp(argv[i], ARG_DEVSTYLE)==0) { - char* dev_style_keys[] = { "STYLE_DEV", "STYLE_DEVA", "STYLE_TTY", - "STYLE_CTTY", "STYLE_CLONE", "STYLE_CLONE_A", NULL }; - int dev_style_values[] = { STYLE_DEV, STYLE_DEVA, STYLE_TTY, - STYLE_CTTY, STYLE_CLONE, STYLE_CLONE_A }; + char* dev_style_keys[] = { "STYLE_DEV", "STYLE_TTY", + "STYLE_CTTY", NULL }; + int dev_style_values[] = { STYLE_DEV, STYLE_TTY, + STYLE_CTTY }; for(j=0;dev_style_keys[j]!=NULL;j++) { if(!strcmp(dev_style_keys[j], argv[i+1])) { break; diff --git a/commands/setup/setup.sh b/commands/setup/setup.sh index ed276bd62..c33909018 100644 --- a/commands/setup/setup.sh +++ b/commands/setup/setup.sh @@ -432,9 +432,9 @@ then # Get sizes and space availability while the file systems are still # mounted. Otherwise we have to mount them again just for this. - required_root_space=`df -k /dev/$root | awk '{print $4}' | tail -n 1` - free_root_space=`df -k /dev/$root | awk '{print $3}' | tail -n 1` - free_usr_space=`df -k /dev/$usr | awk '{print $3}' | tail -n 1` + required_root_space=`df -kP /dev/$root | awk '{print $3}' | tail -n 1` + free_root_space=`df -kP /dev/$root | awk '{print $4}' | tail -n 1` + free_usr_space=`df -kP /dev/$usr | awk '{print $4}' | tail -n 1` umount /mnt/usr && umount /mnt || exit diff --git a/commands/umount/umount.c b/commands/umount/umount.c index 34b3cfe6c..b724a7a11 100644 --- a/commands/umount/umount.c +++ b/commands/umount/umount.c @@ -47,7 +47,7 @@ char *argv[]; found = find_mtab_entry(name); - if (umount2(name, umount_flags) < 0) { + if (umount(name, umount_flags) < 0) { if (errno == EINVAL) std_err("umount: Device not mounted\n"); else if (errno == ENOTBLK) diff --git a/distrib/sets/lists/minix/md.evbarm b/distrib/sets/lists/minix/md.evbarm index c29a9dd8e..b3eb2aab6 100644 --- a/distrib/sets/lists/minix/md.evbarm +++ b/distrib/sets/lists/minix/md.evbarm @@ -1,18 +1,16 @@ -./boot/minix/.temp/mod07_log minix-sys -./boot/minix/.temp/mod08_tty minix-sys -./boot/minix/.temp/mod09_mfs minix-sys -./boot/minix/.temp/mod10_vm minix-sys -./boot/minix/.temp/mod11_pfs minix-sys -./boot/minix/.temp/mod12_init minix-sys +./boot/minix/.temp/mod07_tty minix-sys +./boot/minix/.temp/mod08_mfs minix-sys +./boot/minix/.temp/mod09_vm minix-sys +./boot/minix/.temp/mod10_pfs minix-sys +./boot/minix/.temp/mod11_init minix-sys ./etc/rc.capes minix-sys ./etc/rc.capes/BB-BONE-WTHR-01 minix-sys ./etc/system.conf.d/lan8710a minix-sys -./multiboot/mod07_log minix-sys -./multiboot/mod08_tty minix-sys -./multiboot/mod09_mfs minix-sys -./multiboot/mod10_vm minix-sys -./multiboot/mod11_pfs minix-sys -./multiboot/mod12_init minix-sys +./multiboot/mod07_tty minix-sys +./multiboot/mod08_mfs minix-sys +./multiboot/mod09_vm minix-sys +./multiboot/mod10_pfs minix-sys +./multiboot/mod11_init minix-sys ./sbin/gpio minix-sys ./usr/bin/eepromread minix-sys ./usr/include/arm minix-sys diff --git a/distrib/sets/lists/minix/md.i386 b/distrib/sets/lists/minix/md.i386 index 35d8762ec..27509aa5b 100644 --- a/distrib/sets/lists/minix/md.i386 +++ b/distrib/sets/lists/minix/md.i386 @@ -1,10 +1,9 @@ -./boot/minix/.temp/mod07_log minix-sys -./boot/minix/.temp/mod08_tty minix-sys -./boot/minix/.temp/mod09_mfs minix-sys -./boot/minix/.temp/mod10_vm minix-sys -./boot/minix/.temp/mod11_pfs minix-sys -./boot/minix/.temp/mod12_init minix-sys +./boot/minix/.temp/mod07_tty minix-sys +./boot/minix/.temp/mod08_mfs minix-sys +./boot/minix/.temp/mod09_vm minix-sys +./boot/minix/.temp/mod10_pfs minix-sys +./boot/minix/.temp/mod11_init minix-sys ./etc/system.conf.d/atl2 minix-sys ./etc/system.conf.d/dec21140A minix-sys ./etc/system.conf.d/e1000 minix-sys @@ -13,12 +12,11 @@ ./etc/system.conf.d/rtl8139 minix-sys ./etc/system.conf.d/rtl8169 minix-sys ./etc/system.conf.d/virtio_net minix-sys -./multiboot/mod07_log minix-sys -./multiboot/mod08_tty minix-sys -./multiboot/mod09_mfs minix-sys -./multiboot/mod10_vm minix-sys -./multiboot/mod11_pfs minix-sys -./multiboot/mod12_init minix-sys +./multiboot/mod07_tty minix-sys +./multiboot/mod08_mfs minix-sys +./multiboot/mod09_vm minix-sys +./multiboot/mod10_pfs minix-sys +./multiboot/mod11_init minix-sys ./sbin/ahci minix-sys ./sbin/at_wini minix-sys ./sbin/floppy minix-sys diff --git a/distrib/sets/lists/minix/mi b/distrib/sets/lists/minix/mi index 726e1778d..c59613c39 100644 --- a/distrib/sets/lists/minix/mi +++ b/distrib/sets/lists/minix/mi @@ -18,6 +18,7 @@ ./bin/cpio minix-sys ./bin/date minix-sys ./bin/dev2name minix-sys obsolete +./bin/df minix-sys ./bin/echo minix-sys ./bin/ed minix-sys ./bin/expr minix-sys @@ -278,14 +279,14 @@ ./usr/bin/DESCRIBE minix-sys ./usr/bin/devmand minix-sys ./usr/bin/devsize minix-sys -./usr/bin/df minix-sys +./usr/bin/df minix-sys obsolete ./usr/bin/dhcpd minix-sys ./usr/bin/dhrystone minix-sys ./usr/bin/diff minix-sys ./usr/bin/dirname minix-sys ./usr/bin/diskctl minix-sys ./usr/bin/du minix-sys -./usr/bin/dumpcore minix-sys +./usr/bin/dumpcore minix-sys obsolete ./usr/bin/egrep minix-sys ./usr/bin/eject minix-sys ./usr/bin/elfedit minix-sys binutils @@ -314,7 +315,7 @@ ./usr/bin/ftp minix-sys ./usr/bin/g++ minix-sys gcccmds ./usr/bin/gcc minix-sys gcccmds -./usr/bin/gcore minix-sys +./usr/bin/gcore minix-sys obsolete ./usr/bin/gcov minix-sys gcccmds ./usr/bin/gcov-pull minix-sys ./usr/bin/gcpp minix-sys gcccmds @@ -617,6 +618,7 @@ ./usr/include/dev minix-sys ./usr/include/dev/i2c minix-sys ./usr/include/dev/i2c/i2c_io.h minix-sys +./usr/include/dev/vndvar.h minix-sys ./usr/include/dirent.h minix-sys ./usr/include/disktab.h minix-sys ./usr/include/dlfcn.h minix-sys @@ -1166,7 +1168,7 @@ ./usr/include/minix/sysutil.h minix-sys ./usr/include/minix/termios.h minix-sys ./usr/include/minix/timers.h minix-sys -./usr/include/minix/tty.h minix-sys +./usr/include/minix/tty.h minix-sys obsolete ./usr/include/minix/type.h minix-sys ./usr/include/minix/types.h minix-sys obsolete ./usr/include/minix/u64.h minix-sys @@ -1828,7 +1830,7 @@ ./usr/man/man1/dosread.1 minix-sys ./usr/man/man1/doswrite.1 minix-sys ./usr/man/man1/du.1 minix-sys -./usr/man/man1/dumpcore.1 minix-sys +./usr/man/man1/dumpcore.1 minix-sys obsolete ./usr/man/man1/echo.1 minix-sys ./usr/man/man1/ed.1 minix-sys ./usr/man/man1/egrep.1 minix-sys @@ -2114,6 +2116,7 @@ ./usr/man/man2/FD_SET.2 minix-sys ./usr/man/man2/fork.2 minix-sys ./usr/man/man2/fstatvfs.2 minix-sys +./usr/man/man2/fstatvfs1.2 minix-sys ./usr/man/man2/getgid.2 minix-sys ./usr/man/man2/getitimer.2 minix-sys ./usr/man/man2/getnucred.2 minix-sys @@ -2126,6 +2129,7 @@ ./usr/man/man2/getsockopt.2 minix-sys ./usr/man/man2/gettimeofday.2 minix-sys ./usr/man/man2/getuid.2 minix-sys +./usr/man/man2/getvfsstat.2 minix-sys ./usr/man/man2/intro.2 minix-sys ./usr/man/man2/ioctl.2 minix-sys ./usr/man/man2/kill.2 minix-sys @@ -2165,6 +2169,7 @@ ./usr/man/man2/socket.2 minix-sys ./usr/man/man2/socketpair.2 minix-sys ./usr/man/man2/statvfs.2 minix-sys +./usr/man/man2/statvfs1.2 minix-sys ./usr/man/man2/svrctl.2 minix-sys ./usr/man/man2/symlink.2 minix-sys ./usr/man/man2/sync.2 minix-sys @@ -3961,6 +3966,7 @@ ./usr/man/man3/strnvis.3 minix-sys ./usr/man/man3/strnvisx.3 minix-sys ./usr/man/man3/strpbrk.3 minix-sys +./usr/man/man3/strpct.3 minix-sys ./usr/man/man3/strptime.3 minix-sys ./usr/man/man3/strrchr.3 minix-sys ./usr/man/man3/strsep.3 minix-sys @@ -4436,6 +4442,8 @@ ./usr/man/man8/usermod.8 minix-sys ./usr/man/man8/vbfs.8 minix-sys ./usr/man/man8/vipw.8 minix-sys +./usr/man/man8/vnconfig.8 minix-sys +./usr/man/man8/vndconfig.8 minix-sys ./usr/man/man8/zdump.8 minix-sys ./usr/man/man8/zic.8 minix-sys ./usr/man/man9 minix-sys @@ -4488,6 +4496,9 @@ ./usr/sbin/vfs minix-sys ./usr/sbin/vipw minix-sys ./usr/sbin/vm minix-sys +./usr/sbin/vnconfig minix-sys +./usr/sbin/vndconfig minix-sys +./usr/sbin/vnd minix-sys ./usr/sbin/zic minix-sys ./usr/share minix-sys ./usr/share/atf minix-sys atf @@ -5289,6 +5300,7 @@ ./usr/tests/minix-posix/t40d minix-sys ./usr/tests/minix-posix/t40e minix-sys ./usr/tests/minix-posix/t40f minix-sys +./usr/tests/minix-posix/t40g minix-sys ./usr/tests/minix-posix/t60a minix-sys ./usr/tests/minix-posix/t60b minix-sys ./usr/tests/minix-posix/t67a minix-sys @@ -5364,6 +5376,8 @@ ./usr/tests/minix-posix/test73 minix-sys ./usr/tests/minix-posix/test74 minix-sys ./usr/tests/minix-posix/test75 minix-sys +./usr/tests/minix-posix/test76 minix-sys +./usr/tests/minix-posix/test77 minix-sys ./usr/tests/minix-posix/test8 minix-sys ./usr/tests/minix-posix/test9 minix-sys ./usr/tests/minix-posix/testinterp minix-sys @@ -5371,6 +5385,14 @@ ./usr/tests/minix-posix/testsh2 minix-sys ./usr/tests/minix-posix/testvm minix-sys ./usr/tests/minix-posix/testvm.conf minix-sys +./usr/tests/minix-posix/testvnd minix-sys +./usr/tests/minix-posix/tvnd minix-sys +./usr/tests/minix-posix/blocktest minix-sys +./usr/tests/minix-posix/blocktest/README minix-sys +./usr/tests/minix-posix/blocktest/blocktest minix-sys +./usr/tests/minix-posix/blocktest/support.sh minix-sys +./usr/tests/minix-posix/blocktest/system.conf minix-sys +./usr/tests/minix-posix/blocktest/test.sh minix-sys ./usr/tests/usr.bin/jot/Atffile minix-sys atf ./usr/tests/usr.bin/jot/d_basic.out minix-sys atf ./usr/tests/usr.bin/jot/t_jot minix-sys atf diff --git a/drivers/Makefile b/drivers/Makefile index 907ad6d9d..dd7ed24d4 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -19,12 +19,12 @@ SUBDIR= log tty SUBDIR= ahci amddev atl2 at_wini audio dec21140A dp8390 dpeth \ e1000 fbd filter floppy fxp hello lance log mmc orinoco pci printer \ random readclock rtl8139 rtl8169 ti1225 tty vbox acpi \ - virtio_blk virtio_net + virtio_blk virtio_net vnd .endif .if ${MACHINE_ARCH} == "earm" SUBDIR= bmp085 cat24c256 fb gpio i2c mmc lan8710a log readclock \ - sht21 tda19988 tps65217 tps65950 tsl2550 tty random + sht21 tda19988 tps65217 tps65950 tsl2550 tty random vnd .endif .endif # ${MKIMAGEONLY} != "yes" diff --git a/drivers/ahci/ahci.c b/drivers/ahci/ahci.c index 2ef4dfb7e..5803b5a35 100644 --- a/drivers/ahci/ahci.c +++ b/drivers/ahci/ahci.c @@ -236,32 +236,29 @@ static void port_timeout(struct timer *tp); static void port_disconnect(struct port_state *ps); static char *ahci_portname(struct port_state *ps); -static int ahci_open(dev_t minor, int access); -static int ahci_close(dev_t minor); -static ssize_t ahci_transfer(dev_t minor, int do_write, u64_t position, +static int ahci_open(devminor_t minor, int access); +static int ahci_close(devminor_t minor); +static ssize_t ahci_transfer(devminor_t minor, int do_write, u64_t position, endpoint_t endpt, iovec_t *iovec, unsigned int count, int flags); -static struct device *ahci_part(dev_t minor); +static struct device *ahci_part(devminor_t minor); static void ahci_alarm(clock_t stamp); -static int ahci_ioctl(dev_t minor, unsigned int request, endpoint_t endpt, - cp_grant_id_t grant); +static int ahci_ioctl(devminor_t minor, unsigned long request, + endpoint_t endpt, cp_grant_id_t grant, endpoint_t user_endpt); static void ahci_intr(unsigned int mask); -static int ahci_device(dev_t minor, device_id_t *id); -static struct port_state *ahci_get_port(dev_t minor); +static int ahci_device(devminor_t minor, device_id_t *id); +static struct port_state *ahci_get_port(devminor_t minor); /* AHCI driver table. */ static struct blockdriver ahci_dtab = { - BLOCKDRIVER_TYPE_DISK, - ahci_open, - ahci_close, - ahci_transfer, - ahci_ioctl, - NULL, /* bdr_cleanup */ - ahci_part, - NULL, /* bdr_geometry */ - ahci_intr, - ahci_alarm, - NULL, /* bdr_other */ - ahci_device + .bdr_type = BLOCKDRIVER_TYPE_DISK, + .bdr_open = ahci_open, + .bdr_close = ahci_close, + .bdr_transfer = ahci_transfer, + .bdr_ioctl = ahci_ioctl, + .bdr_part = ahci_part, + .bdr_intr = ahci_intr, + .bdr_alarm = ahci_alarm, + .bdr_device = ahci_device }; /*===========================================================================* @@ -2421,7 +2418,7 @@ static char *ahci_portname(struct port_state *ps) /*===========================================================================* * ahci_map_minor * *===========================================================================*/ -static struct port_state *ahci_map_minor(dev_t minor, struct device **dvp) +static struct port_state *ahci_map_minor(devminor_t minor, struct device **dvp) { /* Map a minor device number to a port and a pointer to the partition's * device structure. Return NULL if this minor device number does not @@ -2432,7 +2429,7 @@ static struct port_state *ahci_map_minor(dev_t minor, struct device **dvp) ps = NULL; - if (minor < NR_MINORS) { + if (minor >= 0 && minor < NR_MINORS) { port = ahci_map[minor / DEV_PER_DRIVE]; if (port == NO_PORT) @@ -2457,7 +2454,7 @@ static struct port_state *ahci_map_minor(dev_t minor, struct device **dvp) /*===========================================================================* * ahci_part * *===========================================================================*/ -static struct device *ahci_part(dev_t minor) +static struct device *ahci_part(devminor_t minor) { /* Return a pointer to the partition information structure of the given * minor device. @@ -2473,7 +2470,7 @@ static struct device *ahci_part(dev_t minor) /*===========================================================================* * ahci_open * *===========================================================================*/ -static int ahci_open(dev_t minor, int access) +static int ahci_open(devminor_t minor, int access) { /* Open a device. */ @@ -2499,7 +2496,7 @@ static int ahci_open(dev_t minor, int access) return ENXIO; /* Some devices may only be opened in read-only mode. */ - if ((ps->flags & FLAG_READONLY) && (access & W_BIT)) + if ((ps->flags & FLAG_READONLY) && (access & BDEV_W_BIT)) return EACCES; if (ps->open_count == 0) { @@ -2542,7 +2539,7 @@ static int ahci_open(dev_t minor, int access) /*===========================================================================* * ahci_close * *===========================================================================*/ -static int ahci_close(dev_t minor) +static int ahci_close(devminor_t minor) { /* Close a device. */ @@ -2598,7 +2595,7 @@ static int ahci_close(dev_t minor) /*===========================================================================* * ahci_transfer * *===========================================================================*/ -static ssize_t ahci_transfer(dev_t minor, int do_write, u64_t position, +static ssize_t ahci_transfer(devminor_t minor, int do_write, u64_t position, endpoint_t endpt, iovec_t *iovec, unsigned int count, int flags) { /* Perform data transfer on the selected device. @@ -2633,8 +2630,8 @@ static ssize_t ahci_transfer(dev_t minor, int do_write, u64_t position, /*===========================================================================* * ahci_ioctl * *===========================================================================*/ -static int ahci_ioctl(dev_t minor, unsigned int request, endpoint_t endpt, - cp_grant_id_t grant) +static int ahci_ioctl(devminor_t minor, unsigned long request, + endpoint_t endpt, cp_grant_id_t grant, endpoint_t UNUSED(user_endpt)) { /* Process I/O control requests. */ @@ -2684,13 +2681,13 @@ static int ahci_ioctl(dev_t minor, unsigned int request, endpoint_t endpt, sizeof(val)); } - return EINVAL; + return ENOTTY; } /*===========================================================================* * ahci_device * *===========================================================================*/ -static int ahci_device(dev_t minor, device_id_t *id) +static int ahci_device(devminor_t minor, device_id_t *id) { /* Map a minor device number to a device ID. */ @@ -2708,7 +2705,7 @@ static int ahci_device(dev_t minor, device_id_t *id) /*===========================================================================* * ahci_get_port * *===========================================================================*/ -static struct port_state *ahci_get_port(dev_t minor) +static struct port_state *ahci_get_port(devminor_t minor) { /* Get the port structure associated with the given minor device. * Called only from worker threads, so the minor device is already diff --git a/drivers/ahci/ahci.h b/drivers/ahci/ahci.h index 5b77d9e63..ab7c52c74 100644 --- a/drivers/ahci/ahci.h +++ b/drivers/ahci/ahci.h @@ -264,7 +264,6 @@ typedef struct vumap_phys prd_t; */ #define MAX_DRIVES 8 #define NR_MINORS (MAX_DRIVES * DEV_PER_DRIVE) -#define SUB_PER_DRIVE (NR_PARTITIONS * NR_PARTITIONS) #define NR_SUBDEVS (MAX_DRIVES * SUB_PER_DRIVE) /* Port states. */ diff --git a/drivers/at_wini/at_wini.c b/drivers/at_wini/at_wini.c index 00943acc1..6694b620d 100644 --- a/drivers/at_wini/at_wini.c +++ b/drivers/at_wini/at_wini.c @@ -140,14 +140,14 @@ static void init_params(void); static void init_drive(struct wini *w, int base_cmd, int base_ctl, int base_dma, int irq, int ack, int hook, int drive); static void init_params_pci(int); -static int w_do_open(dev_t minor, int access); -static struct device *w_prepare(dev_t dev); -static struct device *w_part(dev_t minor); +static int w_do_open(devminor_t minor, int access); +static struct device *w_prepare(devminor_t dev); +static struct device *w_part(devminor_t minor); static int w_identify(void); static char *w_name(void); static int w_specify(void); static int w_io_test(void); -static ssize_t w_transfer(dev_t minor, int do_write, u64_t position, +static ssize_t w_transfer(devminor_t minor, int do_write, u64_t position, endpoint_t proc_nr, iovec_t *iov, unsigned int nr_req, int flags); static int com_out(struct command *cmd); static int com_out_ext(struct command *cmd); @@ -155,9 +155,9 @@ static int setup_dma(unsigned *sizep, endpoint_t proc_nr, iovec_t *iov, size_t addr_offset, int do_write); static void w_need_reset(void); static void ack_irqs(unsigned int); -static int w_do_close(dev_t minor); -static int w_ioctl(dev_t minor, unsigned int request, endpoint_t endpt, - cp_grant_id_t grant); +static int w_do_close(devminor_t minor); +static int w_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt, + cp_grant_id_t grant, endpoint_t user_endpt); static void w_hw_int(unsigned int irqs); static int com_simple(struct command *cmd); static void w_timeout(void); @@ -166,7 +166,7 @@ static void w_intr_wait(void); static int at_intr_wait(void); static int w_waitfor(int mask, int value); static int w_waitfor_dma(int mask, int value); -static void w_geometry(dev_t minor, struct part_geom *entry); +static void w_geometry(devminor_t minor, struct part_geom *entry); #if ENABLE_ATAPI static int atapi_sendpacket(u8_t *packet, unsigned cnt, int do_dma); static int atapi_intr_wait(int dma, size_t max); @@ -196,18 +196,14 @@ static int at_in(int line, u32_t port, u32_t *value, char *typename, /* Entry points to this driver. */ static struct blockdriver w_dtab = { - BLOCKDRIVER_TYPE_DISK,/* handle partition requests */ - w_do_open, /* open or mount request, initialize device */ - w_do_close, /* release device */ - w_transfer, /* do the I/O */ - w_ioctl, /* I/O control requests */ - NULL, /* nothing to clean up */ - w_part, /* return partition information */ - w_geometry, /* tell the geometry of the disk */ - w_hw_int, /* leftover hardware interrupts */ - NULL, /* ignore leftover alarms */ - NULL, /* ignore unrecognized messages */ - NULL /* no multithreading support */ + .bdr_type = BLOCKDRIVER_TYPE_DISK, /* handle partition requests */ + .bdr_open = w_do_open, /* open or mount request, initialize device */ + .bdr_close = w_do_close, /* release device */ + .bdr_transfer = w_transfer, /* do the I/O */ + .bdr_ioctl = w_ioctl, /* I/O control requests */ + .bdr_part = w_part, /* return partition information */ + .bdr_geometry = w_geometry, /* tell the geometry of the disk */ + .bdr_intr = w_hw_int, /* leftover hardware interrupts */ }; /* SEF functions and variables. */ @@ -583,7 +579,7 @@ static void init_params_pci(int skip) /*===========================================================================* * w_do_open * *===========================================================================*/ -static int w_do_open(dev_t minor, int access) +static int w_do_open(devminor_t minor, int access) { /* Device open: Initialize the controller and read the partition table. */ @@ -626,7 +622,7 @@ static int w_do_open(dev_t minor, int access) } #if ENABLE_ATAPI - if ((wn->state & ATAPI) && (access & W_BIT)) + if ((wn->state & ATAPI) && (access & BDEV_W_BIT)) return(EACCES); #endif @@ -652,12 +648,12 @@ static int w_do_open(dev_t minor, int access) /*===========================================================================* * w_prepare * *===========================================================================*/ -static struct device *w_prepare(dev_t device) +static struct device *w_prepare(devminor_t device) { /* Prepare for I/O on a device. */ w_device = (int) device; - if (device < NR_MINORS) { /* d0, d0p[0-3], d1, ... */ + if (device >= 0 && device < NR_MINORS) { /* d0, d0p[0-3], d1, ... */ w_drive = device / DEV_PER_DRIVE; /* save drive number */ w_wn = &wini[w_drive]; w_dv = &w_wn->part[device % DEV_PER_DRIVE]; @@ -676,7 +672,7 @@ static struct device *w_prepare(dev_t device) /*===========================================================================* * w_part * *===========================================================================*/ -static struct device *w_part(dev_t device) +static struct device *w_part(devminor_t device) { /* Return a pointer to the partition information of the given minor device. */ @@ -1172,7 +1168,7 @@ static int error_dma(const struct wini *wn) * w_transfer * *===========================================================================*/ static ssize_t w_transfer( - dev_t minor, /* minor device to perform the transfer on */ + devminor_t minor, /* minor device to perform the transfer on */ int do_write, /* read or write? */ u64_t position, /* offset on device to read or write */ endpoint_t proc_nr, /* process doing the request */ @@ -1640,7 +1636,7 @@ static void w_need_reset(void) /*===========================================================================* * w_do_close * *===========================================================================*/ -static int w_do_close(dev_t minor) +static int w_do_close(devminor_t minor) { /* Device close: Release a device. */ if (w_prepare(minor) == NULL) @@ -1882,7 +1878,7 @@ int value; /* required status */ /*===========================================================================* * w_geometry * *===========================================================================*/ -static void w_geometry(dev_t minor, struct part_geom *entry) +static void w_geometry(devminor_t minor, struct part_geom *entry) { struct wini *wn; @@ -2215,8 +2211,8 @@ int do_dma; /*===========================================================================* * w_ioctl * *===========================================================================*/ -static int w_ioctl(dev_t minor, unsigned int request, endpoint_t endpt, - cp_grant_id_t grant) +static int w_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt, + cp_grant_id_t grant, endpoint_t UNUSED(user_endpt)) { int r, timeout, prev, count; struct command cmd; @@ -2290,7 +2286,7 @@ static int w_ioctl(dev_t minor, unsigned int request, endpoint_t endpt, return (w_wn->w_status & (STATUS_ERR|STATUS_WF)) ? EIO : OK; } - return EINVAL; + return ENOTTY; } /*===========================================================================* diff --git a/drivers/at_wini/at_wini.h b/drivers/at_wini/at_wini.h index 868c8cd0d..3385dc014 100644 --- a/drivers/at_wini/at_wini.h +++ b/drivers/at_wini/at_wini.h @@ -194,7 +194,6 @@ #define MAX_SECS 256 /* controller can transfer this many sectors */ #define MAX_ERRORS 4 /* how often to try rd/wt before quitting */ #define NR_MINORS (MAX_DRIVES * DEV_PER_DRIVE) -#define SUB_PER_DRIVE (NR_PARTITIONS * NR_PARTITIONS) #define NR_SUBDEVS (MAX_DRIVES * SUB_PER_DRIVE) #define DELAY_USECS 1000 /* controller timeout in microseconds */ #define DELAY_TICKS 1 /* controller timeout in ticks */ diff --git a/drivers/audio/es1370/es1370.c b/drivers/audio/es1370/es1370.c index 9e2785987..c2c7cf3e9 100644 --- a/drivers/audio/es1370/es1370.c +++ b/drivers/audio/es1370/es1370.c @@ -286,7 +286,7 @@ int drv_stop(int sub_dev) /* all IO-ctl's sent to the upper driver are passed to this function */ -int drv_io_ctl(int request, void * val, int * len, int sub_dev) { +int drv_io_ctl(unsigned long request, void * val, int * len, int sub_dev) { int status; diff --git a/drivers/audio/es1371/es1371.c b/drivers/audio/es1371/es1371.c index 8830aa18a..ee51f8c7e 100644 --- a/drivers/audio/es1371/es1371.c +++ b/drivers/audio/es1371/es1371.c @@ -287,7 +287,7 @@ int drv_stop(int sub_dev) /* all IO-ctl's sent to the upper driver are passed to this function */ -int drv_io_ctl(int request, void * val, int * len, int sub_dev) { +int drv_io_ctl(unsigned long request, void * val, int * len, int sub_dev) { int status; diff --git a/drivers/audio/sb16/mixer.c b/drivers/audio/sb16/mixer.c index 4dbf5368d..4338dc3ff 100644 --- a/drivers/audio/sb16/mixer.c +++ b/drivers/audio/sb16/mixer.c @@ -14,7 +14,7 @@ static int get_set_output(struct inout_ctrl *output, int flag); /*=========================================================================* * mixer_ioctl *=========================================================================*/ -int mixer_ioctl(int request, void *val, int *UNUSED(len)) { +int mixer_ioctl(unsigned long request, void *val, int *UNUSED(len)) { int status; switch(request) { diff --git a/drivers/audio/sb16/mixer.h b/drivers/audio/sb16/mixer.h index 8cfe2c6b5..5d05fa5d6 100644 --- a/drivers/audio/sb16/mixer.h +++ b/drivers/audio/sb16/mixer.h @@ -2,7 +2,7 @@ #define SB16_MIXER_H int mixer_init(void); -int mixer_ioctl(int request, void *val, int *len); +int mixer_ioctl(unsigned long request, void *val, int *len); int mixer_set(int reg, int data); int mixer_get(int reg); diff --git a/drivers/audio/sb16/sb16.c b/drivers/audio/sb16/sb16.c index db7cd7f45..5ef1a1621 100644 --- a/drivers/audio/sb16/sb16.c +++ b/drivers/audio/sb16/sb16.c @@ -13,7 +13,7 @@ static void dsp_dma_setup(phys_bytes address, int count, int sub_dev); -static int dsp_ioctl(int request, void *val, int *len); +static int dsp_ioctl(unsigned long request, void *val, int *len); static int dsp_set_size(unsigned int size); static int dsp_set_speed(unsigned int speed); static int dsp_set_stereo(unsigned int stereo); @@ -141,7 +141,7 @@ int drv_start(int channel, int DmaMode) { dsp_set_speed(DspSpeed); /* Put the speaker on */ - if(DmaMode == DEV_WRITE_S) { + if(DmaMode == WRITE_DMA) { dsp_command (DSP_CMD_SPKON); /* put speaker on */ /* Program DSP with dma mode */ @@ -232,8 +232,9 @@ int drv_resume(int UNUSED(chan)) { -int drv_io_ctl(int request, void *val, int *len, int sub_dev) { - Dprint(("dsp_ioctl: got ioctl %d, argument: %d sub_dev: %d\n", request, val, sub_dev)); +int drv_io_ctl(unsigned long request, void *val, int *len, int sub_dev) { + Dprint(("dsp_ioctl: got ioctl %lu, argument: %d sub_dev: %d\n", + request, val, sub_dev)); if(sub_dev == AUDIO) { return dsp_ioctl(request, val, len); @@ -262,7 +263,7 @@ int drv_get_frag_size(u32_t *frag_size, int UNUSED(sub_dev)) { -static int dsp_ioctl(int request, void *val, int *len) { +static int dsp_ioctl(unsigned long request, void *val, int *len) { int status; switch(request) { @@ -293,7 +294,7 @@ static void dsp_dma_setup(phys_bytes address, int count, int DmaMode) { pv_set(pvb[1], DMA8_CLEAR, 0x00); /* Clear flip flop */ /* set DMA mode */ - pv_set(pvb[2], DMA8_MODE, (DmaMode == DEV_WRITE_S ? DMA8_AUTO_PLAY : DMA8_AUTO_REC)); + pv_set(pvb[2], DMA8_MODE, (DmaMode == WRITE_DMA ? DMA8_AUTO_PLAY : DMA8_AUTO_REC)); pv_set(pvb[3], DMA8_ADDR, (u8_t)(address >> 0)); /* Low_byte of address */ pv_set(pvb[4], DMA8_ADDR, (u8_t)(address >> 8)); /* High byte of address */ @@ -311,7 +312,7 @@ static void dsp_dma_setup(phys_bytes address, int count, int DmaMode) { pv_set(pvb[1], DMA16_CLEAR, 0x00); /* Clear flip flop */ /* Set dma mode */ - pv_set(pvb[2], DMA16_MODE, (DmaMode == DEV_WRITE_S ? DMA16_AUTO_PLAY : DMA16_AUTO_REC)); + pv_set(pvb[2], DMA16_MODE, (DmaMode == WRITE_DMA ? DMA16_AUTO_PLAY : DMA16_AUTO_REC)); pv_set(pvb[3], DMA16_ADDR, (address >> 1) & 0xFF); /* Low_byte of address */ pv_set(pvb[4], DMA16_ADDR, (address >> 9) & 0xFF); /* High byte of address */ diff --git a/drivers/bmp085/bmp085.c b/drivers/bmp085/bmp085.c index 40cd0aaba..ab3ea1604 100644 --- a/drivers/bmp085/bmp085.c +++ b/drivers/bmp085/bmp085.c @@ -151,11 +151,9 @@ static int read_cal_coef(void); static int measure(int32_t * temperature, int32_t * pressure); /* libchardriver callbacks */ -static struct device *bmp085_prepare(dev_t UNUSED(dev)); -static int bmp085_transfer(endpoint_t endpt, int opcode, u64_t position, - iovec_t * iov, unsigned nr_req, endpoint_t UNUSED(user_endpt), - unsigned int UNUSED(flags)); -static int bmp085_other(message * m); +static ssize_t bmp085_read(devminor_t minor, u64_t position, endpoint_t endpt, + cp_grant_id_t grant, size_t size, int flags, cdev_id_t id); +static void bmp085_other(message * m, int ipc_status); /* i2c bus access */ static int reg_read(uint8_t reg, uint8_t * val); @@ -171,21 +169,8 @@ static void sef_local_startup(void); /* Entry points to this driver from libchardriver. */ static struct chardriver bmp085_tab = { - .cdr_open = do_nop, - .cdr_close = do_nop, - .cdr_ioctl = nop_ioctl, - .cdr_prepare = bmp085_prepare, - .cdr_transfer = bmp085_transfer, - .cdr_cleanup = nop_cleanup, - .cdr_alarm = nop_alarm, - .cdr_cancel = nop_cancel, - .cdr_select = nop_select, - .cdr_other = bmp085_other -}; - -static struct device bmp085_device = { - .dv_base = 0, - .dv_size = 0 + .cdr_read = bmp085_read, + .cdr_other = bmp085_other }; static int @@ -605,18 +590,12 @@ measure(int32_t * temperature, int32_t * pressure) return OK; } -static struct device * -bmp085_prepare(dev_t UNUSED(dev)) +static ssize_t +bmp085_read(devminor_t UNUSED(minor), u64_t position, endpoint_t endpt, + cp_grant_id_t grant, size_t size, int UNUSED(flags), cdev_id_t UNUSED(id)) { - return &bmp085_device; -} - -static int -bmp085_transfer(endpoint_t endpt, int opcode, u64_t position, - iovec_t * iov, unsigned nr_req, endpoint_t UNUSED(user_endpt), - unsigned int UNUSED(flags)) -{ - int bytes, r; + u64_t dev_size; + int r; uint32_t temperature, pressure; r = measure(&temperature, &pressure); @@ -631,48 +610,33 @@ bmp085_transfer(endpoint_t endpt, int opcode, u64_t position, log_trace(&log, "%s", buffer); - bytes = strlen(buffer) - position < iov->iov_size ? - strlen(buffer) - position : iov->iov_size; + dev_size = (u64_t)strlen(buffer); + if (position >= dev_size) return 0; + if (position + size > dev_size) + size = (size_t)(dev_size - position); - if (bytes <= 0) { - return OK; - } + r = sys_safecopyto(endpt, grant, 0, + (vir_bytes)(buffer + (size_t)position), size); - switch (opcode) { - case DEV_GATHER_S: - r = sys_safecopyto(endpt, (cp_grant_id_t) iov->iov_addr, 0, - (vir_bytes) (buffer + position), bytes); - iov->iov_size -= bytes; - break; - default: - return EINVAL; - } - - return r; + return (r != OK) ? r : size; } -static int -bmp085_other(message * m) +static void +bmp085_other(message * m, int ipc_status) { int r; - switch (m->m_type) { - case NOTIFY_MESSAGE: + if (is_ipc_notify(ipc_status)) { if (m->m_source == DS_PROC_NR) { log_debug(&log, "bus driver changed state, update endpoint\n"); i2cdriver_handle_bus_update(&bus_endpoint, bus, address); } - r = OK; - break; - default: - log_warn(&log, "Invalid message type (0x%x)\n", m->m_type); - r = EINVAL; - break; + return; } - return r; + log_warn(&log, "Invalid message type (0x%x)\n", m->m_type); } static int @@ -791,7 +755,7 @@ main(int argc, char *argv[]) sef_local_startup(); - chardriver_task(&bmp085_tab, CHARDRIVER_SYNC); + chardriver_task(&bmp085_tab); return 0; } diff --git a/drivers/cat24c256/cat24c256.c b/drivers/cat24c256/cat24c256.c index b52cb73a8..7a02cbdab 100644 --- a/drivers/cat24c256/cat24c256.c +++ b/drivers/cat24c256/cat24c256.c @@ -29,14 +29,14 @@ static int sef_cb_lu_state_save(int); static int lu_state_restore(void); /* libblockdriver callbacks */ -static int cat24c256_blk_open(dev_t minor, int access); -static int cat24c256_blk_close(dev_t minor); -static ssize_t cat24c256_blk_transfer(dev_t minor, int do_write, u64_t pos, - endpoint_t endpt, iovec_t * iov, unsigned count, int flags); -static int cat24c256_blk_ioctl(dev_t minor, unsigned int request, - endpoint_t endpt, cp_grant_id_t grant); -static struct device *cat24c256_blk_part(dev_t minor); -static int cat24c256_blk_other(message * m); +static int cat24c256_blk_open(devminor_t minor, int access); +static int cat24c256_blk_close(devminor_t minor); +static ssize_t cat24c256_blk_transfer(devminor_t minor, int do_write, + u64_t pos, endpoint_t endpt, iovec_t * iov, unsigned int count, int flags); +static int cat24c256_blk_ioctl(devminor_t minor, unsigned long request, + endpoint_t endpt, cp_grant_id_t grant, endpoint_t user_endpt); +static struct device *cat24c256_blk_part(devminor_t minor); +static void cat24c256_blk_other(message * m, int ipc_status); /* Entry points into the device dependent code of block drivers. */ struct blockdriver cat24c256_tab = { @@ -44,14 +44,9 @@ struct blockdriver cat24c256_tab = { .bdr_open = cat24c256_blk_open, .bdr_close = cat24c256_blk_close, .bdr_transfer = cat24c256_blk_transfer, - .bdr_ioctl = cat24c256_blk_ioctl, /* nop -- always returns EINVAL */ - .bdr_cleanup = NULL, /* nothing allocated -- nothing to clean up */ + .bdr_ioctl = cat24c256_blk_ioctl, /* always returns ENOTTY */ .bdr_part = cat24c256_blk_part, - .bdr_geometry = NULL, /* no geometry (cylinders, heads, sectors, etc) */ - .bdr_intr = NULL, /* i2c devices don't generate interrupts */ - .bdr_alarm = NULL, /* alarm not needed */ - .bdr_other = cat24c256_blk_other, /* to recv notify events from DS */ - .bdr_device = NULL /* 1 insance per bus, threads not needed */ + .bdr_other = cat24c256_blk_other /* for notify events from DS */ }; static int cat24c256_read128(uint16_t memaddr, void *buf, size_t buflen, int flags); @@ -84,7 +79,7 @@ static struct log log = { }; static int -cat24c256_blk_open(dev_t minor, int access) +cat24c256_blk_open(devminor_t minor, int access) { log_trace(&log, "cat24c256_blk_open(%d,%d)\n", minor, access); if (cat24c256_blk_part(minor) == NULL) { @@ -97,7 +92,7 @@ cat24c256_blk_open(dev_t minor, int access) } static int -cat24c256_blk_close(dev_t minor) +cat24c256_blk_close(devminor_t minor) { log_trace(&log, "cat24c256_blk_close(%d)\n", minor); if (cat24c256_blk_part(minor) == NULL) { @@ -114,11 +109,11 @@ cat24c256_blk_close(dev_t minor) } static ssize_t -cat24c256_blk_transfer(dev_t minor, int do_write, u64_t pos64, - endpoint_t endpt, iovec_t * iov, unsigned nr_req, int flags) +cat24c256_blk_transfer(devminor_t minor, int do_write, u64_t pos64, + endpoint_t endpt, iovec_t * iov, unsigned int nr_req, int flags) { /* Read or write one the driver's block devices. */ - unsigned count; + unsigned int count; struct device *dv; u64_t dv_size; int r; @@ -214,50 +209,40 @@ cat24c256_blk_transfer(dev_t minor, int do_write, u64_t pos64, } static int -cat24c256_blk_ioctl(dev_t minor, unsigned int request, endpoint_t endpt, - cp_grant_id_t grant) +cat24c256_blk_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt, + cp_grant_id_t grant, endpoint_t UNUSED(user_endpt)) { log_trace(&log, "cat24c256_blk_ioctl(%d)\n", minor); /* no supported ioctls for this device */ - return EINVAL; + return ENOTTY; } static struct device * -cat24c256_blk_part(dev_t minor) +cat24c256_blk_part(devminor_t minor) { log_trace(&log, "cat24c256_blk_part(%d)\n", minor); - if (minor >= NR_DEVS) { + if (minor < 0 || minor >= NR_DEVS) { return NULL; } return &geom[minor]; } -static int -cat24c256_blk_other(message * m) +static void +cat24c256_blk_other(message * m, int ipc_status) { - int r; - log_trace(&log, "cat24c256_blk_other(0x%x)\n", m->m_type); - switch (m->m_type) { - case NOTIFY_MESSAGE: + if (is_ipc_notify(ipc_status)) { if (m->m_source == DS_PROC_NR) { log_debug(&log, "bus driver changed state, update endpoint\n"); i2cdriver_handle_bus_update(&bus_endpoint, bus, address); } - r = OK; - break; - default: + } else log_warn(&log, "Invalid message type (0x%x)\n", m->m_type); - r = EINVAL; - break; - } - - return r; } /* The lower level i2c interface can only read/write 128 bytes at a time. diff --git a/drivers/fb/arch/earm/fb_arch.c b/drivers/fb/arch/earm/fb_arch.c index d324ed16a..6e3e58a1c 100644 --- a/drivers/fb/arch/earm/fb_arch.c +++ b/drivers/fb/arch/earm/fb_arch.c @@ -312,7 +312,7 @@ arch_pan_display(int minor, struct fb_var_screeninfo *fbvsp) } int -arch_fb_init(int minor, struct device *dev, struct edid_info *info) +arch_fb_init(int minor, struct edid_info *info) { int r; u32_t rdispc; @@ -320,13 +320,9 @@ arch_fb_init(int minor, struct device *dev, struct edid_info *info) const struct panel_config *panel_cfg = &omap_cfg[minor]; - assert(dev != NULL); if (minor != 0) return ENXIO; /* We support only one minor */ - if (initialized) { - dev->dv_base = fb_vir; - dev->dv_size = fb_size; return OK; } else if (info != NULL) { log_debug(&log, "Configuring Settings based on EDID...\n"); @@ -403,8 +399,6 @@ arch_fb_init(int minor, struct device *dev, struct edid_info *info) if (fb_vir == (vir_bytes) MAP_FAILED) { panic("Unable to allocate contiguous memory\n"); } - dev->dv_base = fb_vir; - dev->dv_size = fb_size; /* Configure buffer settings and turn on LCD/Digital */ arch_configure_display(minor); diff --git a/drivers/fb/fb.c b/drivers/fb/fb.c index 52c08fce7..d8d271d33 100644 --- a/drivers/fb/fb.c +++ b/drivers/fb/fb.c @@ -23,17 +23,14 @@ /* * Function prototypes for the fb driver. */ -static int fb_open(message *m); -static int fb_close(message *m); -static struct device * fb_prepare(dev_t device); -static int fb_transfer(endpoint_t endpt, int opcode, u64_t position, - iovec_t *iov, unsigned int nr_req, endpoint_t user_endpt, unsigned int - flags); -static int fb_do_read(endpoint_t ep, iovec_t *iov, int minor, u64_t pos, - size_t *io_bytes); -static int fb_do_write(endpoint_t ep, iovec_t *iov, int minor, u64_t pos, - size_t *io_bytes); -static int fb_ioctl(message *m); +static int fb_open(devminor_t minor, int access, endpoint_t user_endpt); +static int fb_close(devminor_t minor); +static ssize_t fb_read(devminor_t minor, u64_t pos, endpoint_t ep, + cp_grant_id_t gid, size_t size, int flags, cdev_id_t id); +static ssize_t fb_write(devminor_t minor, u64_t pos, endpoint_t ep, + cp_grant_id_t gid, size_t size, int flags, cdev_id_t id); +static int fb_ioctl(devminor_t minor, unsigned long request, endpoint_t ep, + cp_grant_id_t gid, int flags, endpoint_t user_ep, cdev_id_t id); static void paint_bootlogo(int minor); static void paint_restartlogo(int minor); static void paint_centered(int minor, char *data, int width, int height); @@ -52,143 +49,90 @@ static int lu_state_restore(void); /* Entry points to the fb driver. */ static struct chardriver fb_tab = { - fb_open, - fb_close, - fb_ioctl, - fb_prepare, - fb_transfer, - nop_cleanup, - nop_alarm, - nop_cancel, - nop_select, - NULL + .cdr_open = fb_open, + .cdr_close = fb_close, + .cdr_read = fb_read, + .cdr_write = fb_write, + .cdr_ioctl = fb_ioctl }; /** Represents the /dev/fb device. */ -static struct device fb_device[FB_DEV_NR]; -static int fb_minor, has_restarted = 0; +static int has_restarted = 0; static u64_t has_restarted_t1, has_restarted_t2; static int open_counter[FB_DEV_NR]; /* Open count */ static int -fb_open(message *m) +fb_open(devminor_t minor, int UNUSED(access), endpoint_t UNUSED(user_endpt)) { int r; static int initialized = 0; static struct edid_info info; static struct edid_info *infop = NULL; - if (m->DEVICE < 0 || m->DEVICE >= FB_DEV_NR) return ENXIO; + if (minor < 0 || minor >= FB_DEV_NR) return ENXIO; if (!initialized) { - r = fb_edid_read(m->DEVICE, &info); + r = fb_edid_read(minor, &info); infop = (r == 0) ? &info : NULL; } - if (arch_fb_init(m->DEVICE, &fb_device[m->DEVICE], infop) == OK) { - open_counter[m->DEVICE]++; + if (arch_fb_init(minor, infop) == OK) { + open_counter[minor]++; if (!initialized) { if (has_restarted) { read_frclock_64(&has_restarted_t1); - paint_restartlogo(m->DEVICE); + paint_restartlogo(minor); } else { - paint_bootlogo(m->DEVICE); + paint_bootlogo(minor); } initialized = 1; } return OK; } - return ENXIO ; + return ENXIO; } static int -fb_close(message *m) +fb_close(devminor_t minor) { - if (m->DEVICE < 0 || m->DEVICE >= FB_DEV_NR) return ENXIO; - assert(open_counter[m->DEVICE] > 0); - open_counter[m->DEVICE]--; + if (minor < 0 || minor >= FB_DEV_NR) return ENXIO; + assert(open_counter[minor] > 0); + open_counter[minor]--; return OK; } -static struct device * -fb_prepare(dev_t dev) -{ - if (dev < 0 || dev >= FB_DEV_NR) return NULL; - assert(open_counter[dev] > 0); - fb_minor = dev; - return &fb_device[dev]; -} - -static int -fb_transfer(endpoint_t endpt, int opcode, u64_t position, - iovec_t *iov, unsigned nr_req, endpoint_t UNUSED(user_endpt), - unsigned int UNUSED(flags)) -{ - size_t io_bytes = 0, ret; - - if (nr_req != 1) { - /* This should never trigger for char drivers at the moment. */ - printf("fb: vectored transfer, using first element only\n"); - } - - switch (opcode) { - case DEV_GATHER_S: - /* Userland read operation */ - ret = fb_do_read(endpt, iov, fb_minor, position, &io_bytes); - iov->iov_size -= io_bytes; - break; - case DEV_SCATTER_S: - /* Userland write operation */ - ret = fb_do_write(endpt, iov, fb_minor, position, &io_bytes); - iov->iov_size -= io_bytes; - break; - default: - return EINVAL; - } - return ret; -} - -static int -fb_do_read(endpoint_t ep, iovec_t *iov, int minor, u64_t pos, size_t *io_bytes) +static ssize_t +fb_read(devminor_t minor, u64_t pos, endpoint_t ep, cp_grant_id_t gid, + size_t size, int UNUSED(flags), cdev_id_t UNUSED(id)) { struct device dev; + int r; + + if (minor < 0 || minor >= FB_DEV_NR) return ENXIO; + assert(open_counter[minor] > 0); arch_get_device(minor, &dev); - if (pos >= dev.dv_size) return EINVAL; + if (size == 0 || pos >= dev.dv_size) return 0; + if (pos + size > dev.dv_size) + size = (size_t)(dev.dv_size - pos); - if (dev.dv_size - pos < iov->iov_size) { - *io_bytes = dev.dv_size - pos; - } else { - *io_bytes = iov->iov_size; - } + r = sys_safecopyto(ep, gid, 0, (vir_bytes)(dev.dv_base + (size_t)pos), + size); - if (*io_bytes <= 0) { - return OK; - } - - return sys_safecopyto(ep, (cp_grant_id_t) iov->iov_addr, 0, - (vir_bytes) (dev.dv_base + ex64lo(pos)), - *io_bytes); + return (r != OK) ? r : size; } static int -fb_ioctl(message *m) +fb_ioctl(devminor_t minor, unsigned long request, endpoint_t ep, + cp_grant_id_t gid, int UNUSED(flags), endpoint_t UNUSED(user_ep), + cdev_id_t UNUSED(id)) { /* Process I/O control requests */ - endpoint_t ep; - cp_grant_id_t gid; - int minor; - unsigned int request; int r; - minor = m->DEVICE; - request = m->COUNT; - ep = (endpoint_t) m->USER_ENDPT; - gid = (cp_grant_id_t) m->IO_GRANT; - - if (minor != 0) return EINVAL; + if (minor < 0 || minor >= FB_DEV_NR) return ENXIO; switch(request) { case FBIOGET_VSCREENINFO: @@ -205,7 +149,7 @@ fb_ioctl(message *m) return r; } - return EINVAL; + return ENOTTY; } static int @@ -270,34 +214,29 @@ do_get_fixscreeninfo(int minor, endpoint_t ep, cp_grant_id_t gid) return r; } -static int -fb_do_write(endpoint_t ep, iovec_t *iov, int minor, u64_t pos, size_t *io_bytes) +static ssize_t +fb_write(devminor_t minor, u64_t pos, endpoint_t ep, cp_grant_id_t gid, + size_t size, int UNUSED(flags), cdev_id_t UNUSED(id)) { struct device dev; + int r; + + if (minor < 0 || minor >= FB_DEV_NR) return ENXIO; + assert(open_counter[minor] > 0); + + if (has_restarted && keep_displaying_restarted()) + return EAGAIN; arch_get_device(minor, &dev); - if (pos >= dev.dv_size) { - return EINVAL; - } + if (size == 0 || pos >= dev.dv_size) return 0; + if (pos + size > dev.dv_size) + size = (size_t)(dev.dv_size - pos); - if (dev.dv_size - pos < iov->iov_size) { - *io_bytes = dev.dv_size - pos; - } else { - *io_bytes = iov->iov_size; - } + r = sys_safecopyfrom(ep, gid, 0, + (vir_bytes)(dev.dv_base + (size_t)pos), size); - if (*io_bytes <= 0) { - return OK; - } - - if (has_restarted && keep_displaying_restarted()) { - return EAGAIN; - } - - return sys_safecopyfrom(ep, (cp_grant_id_t) iov->iov_addr, 0, - (vir_bytes) (dev.dv_base + ex64lo(pos)), - *io_bytes); + return (r != OK) ? r : size; } static int @@ -382,7 +321,7 @@ main(int argc, char *argv[]) fb_edid_args_parse(); sef_local_startup(); - chardriver_task(&fb_tab, CHARDRIVER_SYNC); + chardriver_task(&fb_tab); return OK; } diff --git a/drivers/fb/fb.h b/drivers/fb/fb.h index cf9da112d..1eba57fae 100644 --- a/drivers/fb/fb.h +++ b/drivers/fb/fb.h @@ -3,7 +3,7 @@ #include -int arch_fb_init(int minor, struct device *dev, struct edid_info *info); +int arch_fb_init(int minor, struct edid_info *info); int arch_get_device(int minor, struct device *dev); int arch_get_varscreeninfo(int minor, struct fb_var_screeninfo *fbvsp); int arch_put_varscreeninfo(int minor, struct fb_var_screeninfo *fbvs_copy); diff --git a/drivers/fb/fb_edid.c b/drivers/fb/fb_edid.c index 116b64434..f2a16c4f6 100644 --- a/drivers/fb/fb_edid.c +++ b/drivers/fb/fb_edid.c @@ -92,7 +92,7 @@ do_read(endpoint_t driver_endpt, uint8_t *buf, size_t bufsize) /* Open Device - required for drivers using libblockdriver */ memset(&m, '\0', sizeof(message)); m.m_type = BDEV_OPEN; - m.BDEV_ACCESS = R_BIT; + m.BDEV_ACCESS = BDEV_R_BIT; m.BDEV_ID = 0; m.BDEV_MINOR = 0; diff --git a/drivers/fbd/fbd.c b/drivers/fbd/fbd.c index 700fe92b9..ac79a82f5 100644 --- a/drivers/fbd/fbd.c +++ b/drivers/fbd/fbd.c @@ -15,34 +15,27 @@ #define BUF_SIZE (NR_IOREQS * CLICK_SIZE) /* 256k */ /* Function declarations. */ -static int fbd_open(dev_t minor, int access); -static int fbd_close(dev_t minor); -static int fbd_transfer(dev_t minor, int do_write, u64_t position, +static int fbd_open(devminor_t minor, int access); +static int fbd_close(devminor_t minor); +static int fbd_transfer(devminor_t minor, int do_write, u64_t position, endpoint_t endpt, iovec_t *iov, unsigned int nr_req, int flags); -static int fbd_ioctl(dev_t minor, unsigned int request, endpoint_t endpt, - cp_grant_id_t grant); +static int fbd_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt, + cp_grant_id_t grant, endpoint_t user_endpt); /* Variables. */ static char *fbd_buf; /* scratch buffer */ static char driver_label[32] = ""; /* driver DS label */ -static dev_t driver_minor = -1; /* driver's partition minor to use */ -static endpoint_t driver_endpt; /* driver endpoint */ +static devminor_t driver_minor = -1; /* driver's partition minor to use */ +static endpoint_t driver_endpt; /* driver endpoint */ /* Entry points to this driver. */ static struct blockdriver fbd_dtab = { - BLOCKDRIVER_TYPE_OTHER, /* do not handle partition requests */ - fbd_open, /* open or mount request, initialize device */ - fbd_close, /* release device */ - fbd_transfer, /* do the I/O */ - fbd_ioctl, /* perform I/O control request */ - NULL, /* nothing to clean up */ - NULL, /* we will not be asked about partitions */ - NULL, /* we will not be asked for geometry */ - NULL, /* ignore leftover hardware interrupts */ - NULL, /* ignore alarms */ - NULL, /* ignore other messages */ - NULL /* no multithreading support */ + .bdr_type = BLOCKDRIVER_TYPE_OTHER,/* do not handle part. reqs */ + .bdr_open = fbd_open, /* open request, initialize device */ + .bdr_close = fbd_close, /* release device */ + .bdr_transfer = fbd_transfer, /* do the I/O */ + .bdr_ioctl = fbd_ioctl /* perform I/O control request */ }; /* Options supported by this driver. */ @@ -147,7 +140,7 @@ int main(int argc, char **argv) /*===========================================================================* * fbd_open * *===========================================================================*/ -static int fbd_open(dev_t UNUSED(minor), int access) +static int fbd_open(devminor_t UNUSED(minor), int access) { /* Open a device. */ message m; @@ -172,7 +165,7 @@ static int fbd_open(dev_t UNUSED(minor), int access) /*===========================================================================* * fbd_close * *===========================================================================*/ -static int fbd_close(dev_t UNUSED(minor)) +static int fbd_close(devminor_t UNUSED(minor)) { /* Close a device. */ message m; @@ -196,8 +189,8 @@ static int fbd_close(dev_t UNUSED(minor)) /*===========================================================================* * fbd_ioctl * *===========================================================================*/ -static int fbd_ioctl(dev_t UNUSED(minor), unsigned int request, - endpoint_t endpt, cp_grant_id_t grant) +static int fbd_ioctl(devminor_t UNUSED(minor), unsigned long request, + endpoint_t endpt, cp_grant_id_t grant, endpoint_t UNUSED(user_endpt)) { /* Handle an I/O control request. */ cp_grant_id_t gid; @@ -222,6 +215,7 @@ static int fbd_ioctl(dev_t UNUSED(minor), unsigned int request, m.BDEV_MINOR = driver_minor; m.BDEV_REQUEST = request; m.BDEV_GRANT = gid; + m.BDEV_USER = NONE; m.BDEV_ID = 0; if ((r = sendrec(driver_endpt, &m)) != OK) @@ -406,11 +400,11 @@ static ssize_t fbd_transfer_copy(int do_write, u64_t position, /*===========================================================================* * fbd_transfer * *===========================================================================*/ -static int fbd_transfer(dev_t UNUSED(minor), int do_write, u64_t position, +static int fbd_transfer(devminor_t UNUSED(minor), int do_write, u64_t position, endpoint_t endpt, iovec_t *iov, unsigned int nr_req, int flags) { /* Transfer data from or to the device. */ - unsigned count; + unsigned int count; size_t size, osize; int i, hooks; ssize_t r; diff --git a/drivers/filter/driver.c b/drivers/filter/driver.c index d0a959078..478c3e597 100644 --- a/drivers/filter/driver.c +++ b/drivers/filter/driver.c @@ -31,7 +31,7 @@ static int driver_open(int which) memset(&msg, 0, sizeof(msg)); msg.m_type = BDEV_OPEN; msg.BDEV_MINOR = driver[which].minor; - msg.BDEV_ACCESS = R_BIT | W_BIT; + msg.BDEV_ACCESS = BDEV_R_BIT | BDEV_W_BIT; msg.BDEV_ID = 0; r = sendrec(driver[which].endpt, &msg); @@ -60,6 +60,7 @@ static int driver_open(int which) msg.BDEV_MINOR = driver[which].minor; msg.BDEV_REQUEST = DIOCGETP; msg.BDEV_GRANT = gid; + msg.BDEV_USER = NONE; msg.BDEV_ID = 0; r = sendrec(driver[which].endpt, &msg); diff --git a/drivers/filter/main.c b/drivers/filter/main.c index b825ed31c..75a3a9379 100644 --- a/drivers/filter/main.c +++ b/drivers/filter/main.c @@ -63,12 +63,6 @@ static struct optset optset_table[] = { { NULL, 0, NULL, 0 } }; -/* Request message. */ -static message m_in; -static endpoint_t who_e; /* m_source */ -static long req_id; /* BDEV_ID */ -static cp_grant_id_t grant_id; /* BDEV_GRANT */ - /* Data buffers. */ static char *buf_array, *buffer; /* contiguous buffer */ @@ -77,26 +71,46 @@ static void sef_local_startup(void); static int sef_cb_init_fresh(int type, sef_init_info_t *info); static void sef_cb_signal_handler(int signo); -/*===========================================================================* - * carry * - *===========================================================================*/ -static int carry(size_t size, int flag_rw) -{ - /* Carry data between caller proc and filter. - */ +static int filter_open(devminor_t minor, int access); +static int filter_close(devminor_t minor); +static ssize_t filter_transfer(devminor_t minor, int do_write, u64_t pos, + endpoint_t endpt, iovec_t *iov, unsigned int count, int flags); +static int filter_ioctl(devminor_t minor, unsigned long request, + endpoint_t endpt, cp_grant_id_t grant, endpoint_t user_endpt); +static void filter_other(message *m, int ipc_status); - if (flag_rw == FLT_WRITE) - return sys_safecopyfrom(who_e, grant_id, 0, - (vir_bytes) buffer, size); - else - return sys_safecopyto(who_e, grant_id, 0, - (vir_bytes) buffer, size); +static struct blockdriver filter_tab = { + .bdr_type = BLOCKDRIVER_TYPE_OTHER, + .bdr_open = filter_open, + .bdr_close = filter_close, + .bdr_transfer = filter_transfer, + .bdr_ioctl = filter_ioctl, + .bdr_other = filter_other +}; + +/*===========================================================================* + * filter_open * + *===========================================================================*/ +static int filter_open(devminor_t UNUSED(minor), int UNUSED(access)) +{ + /* Open is a noop for filter. */ + return OK; +} + +/*===========================================================================* + * filter_close * + *===========================================================================*/ +static int filter_close(devminor_t UNUSED(minor)) +{ + /* Close is a noop for filter. */ + return OK; } /*===========================================================================* * vcarry * *===========================================================================*/ -static int vcarry(int grants, iovec_t *iov, int flag_rw, size_t size) +static int vcarry(endpoint_t endpt, unsigned int grants, iovec_t *iov, + int do_write, size_t size) { /* Carry data between caller proc and filter, through grant-vector. */ @@ -108,12 +122,12 @@ static int vcarry(int grants, iovec_t *iov, int flag_rw, size_t size) for(i = 0; i < grants && size > 0; i++) { bytes = MIN(size, iov[i].iov_size); - if (flag_rw == FLT_WRITE) - r = sys_safecopyfrom(who_e, + if (do_write) + r = sys_safecopyfrom(endpt, (vir_bytes) iov[i].iov_addr, 0, (vir_bytes) bufp, bytes); else - r = sys_safecopyto(who_e, + r = sys_safecopyto(endpt, (vir_bytes) iov[i].iov_addr, 0, (vir_bytes) bufp, bytes); @@ -127,76 +141,19 @@ static int vcarry(int grants, iovec_t *iov, int flag_rw, size_t size) return OK; } -/*===========================================================================* - * do_rdwt * - *===========================================================================*/ -static int do_rdwt(int flag_rw) -{ - size_t size, size_ret; - u64_t pos; - int r; - - pos = make64(m_in.BDEV_POS_LO, m_in.BDEV_POS_HI); - size = m_in.BDEV_COUNT; - - if (rem64u(pos, SECTOR_SIZE) != 0 || size % SECTOR_SIZE != 0) { - printf("Filter: unaligned request from caller!\n"); - - return EINVAL; - } - - buffer = flt_malloc(size, buf_array, BUF_SIZE); - - if(flag_rw == FLT_WRITE) - carry(size, flag_rw); - - reset_kills(); - - for (;;) { - size_ret = size; - r = transfer(pos, buffer, &size_ret, flag_rw); - if(r != RET_REDO) - break; - -#if DEBUG - printf("Filter: transfer yielded RET_REDO, checking drivers\n"); -#endif - if((r = check_driver(DRIVER_MAIN)) != OK) break; - if((r = check_driver(DRIVER_BACKUP)) != OK) break; - } - - if(r == OK && flag_rw == FLT_READ) - carry(size_ret, flag_rw); - - flt_free(buffer, size, buf_array); - - if (r != OK) - return r; - - return size_ret; -} /*===========================================================================* - * do_vrdwt * + * filter_transfer * *===========================================================================*/ -static int do_vrdwt(int flag_rw) +static ssize_t filter_transfer(devminor_t UNUSED(minor), int do_write, + u64_t pos, endpoint_t endpt, iovec_t *iov, unsigned int count, + int UNUSED(flags)) { size_t size, size_ret; - int grants; int r, i; - u64_t pos; - iovec_t iov_proc[NR_IOREQS]; - /* Extract informations. */ - grants = m_in.BDEV_COUNT; - if((r = sys_safecopyfrom(who_e, grant_id, 0, (vir_bytes) iov_proc, - grants * sizeof(iovec_t))) != OK) { - panic("copying in grant vector failed: %d", r); - } - - pos = make64(m_in.BDEV_POS_LO, m_in.BDEV_POS_HI); - for(size = 0, i = 0; i < grants; i++) - size += iov_proc[i].iov_size; + for(size = 0, i = 0; i < count; i++) + size += iov[i].iov_size; if (rem64u(pos, SECTOR_SIZE) != 0 || size % SECTOR_SIZE != 0) { printf("Filter: unaligned request from caller!\n"); @@ -205,14 +162,15 @@ static int do_vrdwt(int flag_rw) buffer = flt_malloc(size, buf_array, BUF_SIZE); - if(flag_rw == FLT_WRITE) - vcarry(grants, iov_proc, flag_rw, size); + if (do_write) + vcarry(endpt, count, iov, do_write, size); reset_kills(); for (;;) { size_ret = size; - r = transfer(pos, buffer, &size_ret, flag_rw); + r = transfer(pos, buffer, &size_ret, + do_write ? FLT_WRITE : FLT_READ); if(r != RET_REDO) break; @@ -228,8 +186,8 @@ static int do_vrdwt(int flag_rw) return r; } - if(flag_rw == FLT_READ) - vcarry(grants, iov_proc, flag_rw, size_ret); + if (!do_write) + vcarry(endpt, count, iov, do_write, size_ret); flt_free(buffer, size, buf_array); @@ -237,13 +195,14 @@ static int do_vrdwt(int flag_rw) } /*===========================================================================* - * do_ioctl * + * filter_ioctl * *===========================================================================*/ -static int do_ioctl(message *m) +static int filter_ioctl(devminor_t UNUSED(minor), unsigned long request, + endpoint_t endpt, cp_grant_id_t grant, endpoint_t UNUSED(user_endpt)) { struct part_geom sizepart; - switch(m->BDEV_REQUEST) { + switch (request) { case DIOCSETP: case DIOCTIMEOUT: case DIOCOPENCT: @@ -258,8 +217,7 @@ static int do_ioctl(message *m) */ sizepart.size = convert(get_raw_size()); - if(sys_safecopyto(who_e, (vir_bytes) grant_id, 0, - (vir_bytes) &sizepart, + if (sys_safecopyto(endpt, grant, 0, (vir_bytes) &sizepart, sizeof(struct part_geom)) != OK) { printf("Filter: DIOCGETP safecopyto failed\n"); return EIO; @@ -267,14 +225,24 @@ static int do_ioctl(message *m) break; default: - printf("Filter: unknown ioctl request: %d!\n", - m->BDEV_REQUEST); - return EINVAL; + printf("Filter: unknown ioctl request: %ld!\n", request); + return ENOTTY; } return OK; } +/*===========================================================================* + * filter_other * + *===========================================================================*/ +static void filter_other(message *m, int ipc_status) +{ + /* Process other messages. */ + if (m->m_source == DS_PROC_NR && is_ipc_notify(ipc_status)) { + ds_event(); + } +} + /*===========================================================================* * parse_arguments * *===========================================================================*/ @@ -371,53 +339,7 @@ int main(int argc, char *argv[]) env_setargs(argc, argv); sef_local_startup(); - for (;;) { - /* Wait for request. */ - if(driver_receive(ANY, &m_in, &ipc_status) != OK) { - panic("driver_receive failed"); - } - -#if DEBUG2 - printf("Filter: got request %d from %d\n", - m_in.m_type, m_in.m_source); -#endif - - if(m_in.m_source == DS_PROC_NR && is_ipc_notify(ipc_status)) { - ds_event(); - continue; - } - - who_e = m_in.m_source; - req_id = m_in.BDEV_ID; - grant_id = m_in.BDEV_GRANT; - size = 0; - - /* Forword the request message to the drivers. */ - switch(m_in.m_type) { - case BDEV_OPEN: /* open/close is a noop for filter. */ - case BDEV_CLOSE: r = OK; break; - case BDEV_READ: r = do_rdwt(FLT_READ); break; - case BDEV_WRITE: r = do_rdwt(FLT_WRITE); break; - case BDEV_GATHER: r = do_vrdwt(FLT_READ); break; - case BDEV_SCATTER: r = do_vrdwt(FLT_WRITE); break; - case BDEV_IOCTL: r = do_ioctl(&m_in); break; - - default: - printf("Filter: ignoring unknown request %d from %d\n", - m_in.m_type, m_in.m_source); - continue; - } - -#if DEBUG2 - printf("Filter: replying with code %d\n", r); -#endif - - /* Send back reply message. */ - m_out.m_type = BDEV_REPLY; - m_out.BDEV_ID = req_id; - m_out.BDEV_STATUS = r; - send(who_e, &m_out); - } + blockdriver_task(&filter_tab); return 0; } @@ -490,4 +412,3 @@ static void sef_cb_signal_handler(int signo) exit(0); } - diff --git a/drivers/floppy/floppy.c b/drivers/floppy/floppy.c index 43f15f402..835d2b3e1 100644 --- a/drivers/floppy/floppy.c +++ b/drivers/floppy/floppy.c @@ -242,10 +242,10 @@ static void f_expire_tmrs(clock_t stamp); static void stop_motor(timer_t *tp); static void f_timeout(timer_t *tp); -static struct device *f_prepare(dev_t device); -static struct device *f_part(dev_t minor); +static struct device *f_prepare(devminor_t device); +static struct device *f_part(devminor_t minor); static void f_cleanup(void); -static ssize_t f_transfer(dev_t minor, int do_write, u64_t position, +static ssize_t f_transfer(devminor_t minor, int do_write, u64_t position, endpoint_t proc_nr, iovec_t *iov, unsigned int nr_req, int flags); static int dma_setup(int do_write); static void start_motor(void); @@ -258,25 +258,21 @@ static int recalibrate(void); static void f_reset(void); static int f_intr_wait(void); static int read_id(void); -static int f_do_open(dev_t minor, int access); -static int f_do_close(dev_t minor); +static int f_do_open(devminor_t minor, int access); +static int f_do_close(devminor_t minor); static int test_read(int density); -static void f_geometry(dev_t minor, struct part_geom *entry); +static void f_geometry(devminor_t minor, struct part_geom *entry); /* Entry points to this driver. */ static struct blockdriver f_dtab = { - BLOCKDRIVER_TYPE_DISK, /* handle partition requests */ - f_do_open, /* open or mount request, sense type of diskette */ - f_do_close, /* nothing on a close */ - f_transfer, /* do the I/O */ - NULL, /* no other I/O control requests are supported */ - f_cleanup, /* cleanup before sending reply to user process */ - f_part, /* return partition information structure */ - f_geometry, /* tell the geometry of the diskette */ - NULL, /* no processing of hardware interrupts */ - f_expire_tmrs,/* expire all alarm timers */ - NULL, /* no processing of other messages */ - NULL /* no threading support */ + .bdr_type = BLOCKDRIVER_TYPE_DISK, /* handle partition requests */ + .bdr_open = f_do_open, /* open request, sense type of diskette */ + .bdr_close = f_do_close, /* nothing on a close */ + .bdr_transfer = f_transfer, /* do the I/O */ + .bdr_cleanup = f_cleanup, /* cleanup before sending reply to caller */ + .bdr_part = f_part, /* return partition information structure */ + .bdr_geometry = f_geometry, /* tell the geometry of the diskette */ + .bdr_alarm = f_expire_tmrs /* expire all alarm timers */ }; static char *floppy_buf; @@ -397,13 +393,13 @@ static void f_expire_tmrs(clock_t stamp) /*===========================================================================* * f_prepare * *===========================================================================*/ -static struct device *f_prepare(dev_t device) +static struct device *f_prepare(devminor_t device) { /* Prepare for I/O on a device. */ f_device = device; f_drive = device & ~(DEV_TYPE_BITS | FORMAT_DEV_BIT); - if (f_drive >= NR_DRIVES) return(NULL); + if (device < 0 || f_drive >= NR_DRIVES) return(NULL); f_fp = &floppy[f_drive]; f_dv = &f_fp->fl_geom; @@ -424,7 +420,7 @@ static struct device *f_prepare(dev_t device) /*===========================================================================* * f_part * *===========================================================================*/ -static struct device *f_part(dev_t minor) +static struct device *f_part(devminor_t minor) { /* Return a pointer to the partition information of the given minor device. */ @@ -447,7 +443,7 @@ static void f_cleanup(void) * f_transfer * *===========================================================================*/ static ssize_t f_transfer( - dev_t minor, /* minor device number */ + devminor_t minor, /* minor device number */ int do_write, /* read or write? */ u64_t pos64, /* offset on device to read or write */ endpoint_t proc_nr, /* process doing the request */ @@ -1251,7 +1247,7 @@ static int read_id(void) /*===========================================================================* * f_do_open * *===========================================================================*/ -static int f_do_open(dev_t minor, int UNUSED(access)) +static int f_do_open(devminor_t minor, int UNUSED(access)) { /* Handle an open on a floppy. Determine diskette type if need be. */ @@ -1310,7 +1306,7 @@ static int f_do_open(dev_t minor, int UNUSED(access)) /*===========================================================================* * f_do_close * *===========================================================================*/ -static int f_do_close(dev_t UNUSED(minor)) +static int f_do_close(devminor_t UNUSED(minor)) { /* Handle a close on a floppy. Nothing to do here. */ @@ -1350,7 +1346,7 @@ static int test_read(int density) /*===========================================================================* * f_geometry * *===========================================================================*/ -static void f_geometry(dev_t minor, struct part_geom *entry) +static void f_geometry(devminor_t minor, struct part_geom *entry) { if (f_prepare(minor) == NULL) return; diff --git a/drivers/hello/hello.c b/drivers/hello/hello.c index 0dd6a27e4..6eae09998 100644 --- a/drivers/hello/hello.c +++ b/drivers/hello/hello.c @@ -8,12 +8,10 @@ /* * Function prototypes for the hello driver. */ -static int hello_open(message *m); -static int hello_close(message *m); -static struct device * hello_prepare(dev_t device); -static int hello_transfer(endpoint_t endpt, int opcode, u64_t position, - iovec_t *iov, unsigned int nr_req, endpoint_t user_endpt, unsigned int - flags); +static int hello_open(devminor_t minor, int access, endpoint_t user_endpt); +static int hello_close(devminor_t minor); +static ssize_t hello_read(devminor_t minor, u64_t position, endpoint_t endpt, + cp_grant_id_t grant, size_t size, int flags, cdev_id_t id); /* SEF functions and variables. */ static void sef_local_startup(void); @@ -24,77 +22,54 @@ static int lu_state_restore(void); /* Entry points to the hello driver. */ static struct chardriver hello_tab = { - hello_open, - hello_close, - nop_ioctl, - hello_prepare, - hello_transfer, - nop_cleanup, - nop_alarm, - nop_cancel, - nop_select, - NULL + .cdr_open = hello_open, + .cdr_close = hello_close, + .cdr_read = hello_read, }; -/** Represents the /dev/hello device. */ -static struct device hello_device; - -/** State variable to count the number of times the device has been opened. */ +/** State variable to count the number of times the device has been opened. + * Note that this is not the regular type of open counter: it never decreases. + */ static int open_counter; -static int hello_open(message *UNUSED(m)) +static int hello_open(devminor_t UNUSED(minor), int UNUSED(access), + endpoint_t UNUSED(user_endpt)) { printf("hello_open(). Called %d time(s).\n", ++open_counter); return OK; } -static int hello_close(message *UNUSED(m)) +static int hello_close(devminor_t UNUSED(minor)) { printf("hello_close()\n"); return OK; } -static struct device * hello_prepare(dev_t UNUSED(dev)) +static ssize_t hello_read(devminor_t UNUSED(minor), u64_t position, + endpoint_t endpt, cp_grant_id_t grant, size_t size, int UNUSED(flags), + cdev_id_t UNUSED(id)) { - hello_device.dv_base = make64(0, 0); - hello_device.dv_size = make64(strlen(HELLO_MESSAGE), 0); - return &hello_device; -} + u64_t dev_size; + char *ptr; + int ret; -static int hello_transfer(endpoint_t endpt, int opcode, u64_t position, - iovec_t *iov, unsigned nr_req, endpoint_t UNUSED(user_endpt), - unsigned int UNUSED(flags)) -{ - int bytes, ret; + printf("hello_read()\n"); - printf("hello_transfer()\n"); + /* This is the total size of our device. */ + dev_size = (u64_t) strlen(HELLO_MESSAGE); - if (nr_req != 1) - { - /* This should never trigger for character drivers at the moment. */ - printf("HELLO: vectored transfer request, using first element only\n"); - } + /* Check for EOF, and possibly limit the read size. */ + if (position >= dev_size) return 0; /* EOF */ + if (position + size > dev_size) + size = (size_t)(dev_size - position); /* limit size */ - bytes = strlen(HELLO_MESSAGE) - ex64lo(position) < iov->iov_size ? - strlen(HELLO_MESSAGE) - ex64lo(position) : iov->iov_size; + /* Copy the requested part to the caller. */ + ptr = HELLO_MESSAGE + (size_t)position; + if ((ret = sys_safecopyto(endpt, grant, 0, (vir_bytes) ptr, size)) != OK) + return ret; - if (bytes <= 0) - { - return OK; - } - switch (opcode) - { - case DEV_GATHER_S: - ret = sys_safecopyto(endpt, (cp_grant_id_t) iov->iov_addr, 0, - (vir_bytes) (HELLO_MESSAGE + ex64lo(position)), - bytes); - iov->iov_size -= bytes; - break; - - default: - return EINVAL; - } - return ret; + /* Return the number of bytes read. */ + return size; } static int sef_cb_lu_state_save(int UNUSED(state)) { @@ -181,7 +156,7 @@ int main(void) /* * Run the main loop. */ - chardriver_task(&hello_tab, CHARDRIVER_SYNC); + chardriver_task(&hello_tab); return OK; } diff --git a/drivers/i2c/i2c.c b/drivers/i2c/i2c.c index 36d8af324..4bf803954 100644 --- a/drivers/i2c/i2c.c +++ b/drivers/i2c/i2c.c @@ -33,16 +33,14 @@ static void update_reservation(endpoint_t endpt, char *key); static void ds_event(void); static int validate_ioctl_exec(minix_i2c_ioctl_exec_t * ioctl_exec); -static int do_i2c_ioctl_exec(message * m); +static int do_i2c_ioctl_exec(endpoint_t caller, cp_grant_id_t grant_nr); static int env_parse_instance(void); /* libchardriver callbacks */ -int i2c_ioctl(message * m); -struct device *i2c_prepare(dev_t dev); -int i2c_transfer(endpoint_t endpt, int opcode, u64_t position, - iovec_t * iov, unsigned nr_req, endpoint_t user_endpt, unsigned int flags); -int i2c_other(message * m); +static int i2c_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt, + cp_grant_id_t grant, int flags, endpoint_t user_endpt, cdev_id_t id); +static void i2c_other(message * m, int ipc_status); /* SEF callbacks and driver state management */ static int sef_cb_lu_state_save(int); @@ -68,8 +66,6 @@ static struct i2cdev */ int (*process) (minix_i2c_ioctl_exec_t * ioctl_exec); -struct device i2c_device; - /* logging - use with log_warn(), log_info(), log_debug(), log_trace() */ static struct log log = { .name = "i2c", @@ -81,16 +77,8 @@ static struct log log = { * Only i2c_ioctl() and i2c_other() are implemented. The rest are no-op. */ static struct chardriver i2c_tab = { - .cdr_open = do_nop, - .cdr_close = do_nop, - .cdr_ioctl = i2c_ioctl, - .cdr_prepare = i2c_prepare, - .cdr_transfer = i2c_transfer, - .cdr_cleanup = nop_cleanup, - .cdr_alarm = nop_alarm, - .cdr_cancel = nop_cancel, - .cdr_select = nop_select, - .cdr_other = i2c_other + .cdr_ioctl = i2c_ioctl, + .cdr_other = i2c_other }; /* @@ -232,14 +220,14 @@ validate_ioctl_exec(minix_i2c_ioctl_exec_t * ioctl_exec) } len = ioctl_exec->iie_cmdlen; - if (len < 0 || len > I2C_EXEC_MAX_CMDLEN) { + if (len > I2C_EXEC_MAX_CMDLEN) { log_warn(&log, "iie_cmdlen out of range 0-I2C_EXEC_MAX_CMDLEN\n"); return EINVAL; } len = ioctl_exec->iie_buflen; - if (len < 0 || len > I2C_EXEC_MAX_BUFLEN) { + if (len > I2C_EXEC_MAX_BUFLEN) { log_warn(&log, "iie_buflen out of range 0-I2C_EXEC_MAX_BUFLEN\n"); return EINVAL; @@ -252,16 +240,11 @@ validate_ioctl_exec(minix_i2c_ioctl_exec_t * ioctl_exec) * Performs the action in minix_i2c_ioctl_exec_t. */ static int -do_i2c_ioctl_exec(message * m) +do_i2c_ioctl_exec(endpoint_t caller, cp_grant_id_t grant_nr) { int r; - endpoint_t caller; - cp_grant_id_t grant_nr; minix_i2c_ioctl_exec_t ioctl_exec; - caller = (endpoint_t) m->m_source; - grant_nr = (cp_grant_id_t) m->IO_GRANT; - /* Copy the requested exection into the driver */ r = sys_safecopyfrom(caller, grant_nr, (vir_bytes) 0, (vir_bytes) & ioctl_exec, sizeof(ioctl_exec)); @@ -302,45 +285,48 @@ do_i2c_ioctl_exec(message * m) return OK; } -int -i2c_ioctl(message * m) +static int +i2c_ioctl(devminor_t UNUSED(minor), unsigned long request, endpoint_t endpt, + cp_grant_id_t grant, int UNUSED(flags), endpoint_t UNUSED(user_endpt), + cdev_id_t UNUSED(id)) { int r; - switch (m->COUNT) { + switch (request) { case MINIX_I2C_IOCTL_EXEC: - r = do_i2c_ioctl_exec(m); + r = do_i2c_ioctl_exec(endpt, grant); break; default: - log_warn(&log, "Invalid ioctl() 0x%x\n", m->COUNT); - r = EINVAL; + log_warn(&log, "Invalid ioctl() 0x%x\n", request); + r = ENOTTY; break; } return r; } -int -i2c_other(message * m) +static void +i2c_other(message * m, int ipc_status) { + message m_reply; int r; - switch (m->m_type) { - case BUSC_I2C_RESERVE: - /* reserve a device on the bus for exclusive access */ - r = do_reserve((endpoint_t) m->m_source, m->DEVICE); - break; - case BUSC_I2C_EXEC: - /* handle request from another driver */ - m->COUNT = MINIX_I2C_IOCTL_EXEC; - r = do_i2c_ioctl_exec(m); - break; - case NOTIFY_MESSAGE: + if (is_ipc_notify(ipc_status)) { /* handle notifications about drivers changing state */ if (m->m_source == DS_PROC_NR) { ds_event(); } - r = OK; + return; + } + + switch (m->m_type) { + case BUSC_I2C_RESERVE: + /* reserve a device on the bus for exclusive access */ + r = do_reserve(m->m_source, m->BUSC_I2C_ADDR); + break; + case BUSC_I2C_EXEC: + /* handle request from another driver */ + r = do_i2c_ioctl_exec(m->m_source, m->BUSC_I2C_GRANT); break; default: log_warn(&log, "Invalid message type (0x%x)\n", m->m_type); @@ -350,25 +336,12 @@ i2c_other(message * m) log_trace(&log, "i2c_other() returning r=%d\n", r); - return r; -} + /* Send a reply. */ + memset(&m_reply, 0, sizeof(m_reply)); + m_reply.m_type = r; -struct device * -i2c_prepare(dev_t dev) -{ - /* NOP */ - i2c_device.dv_base = make64(0, 0); - i2c_device.dv_size = make64(0, 0); - - return &i2c_device; -} - -int -i2c_transfer(endpoint_t endpt, int opcode, u64_t position, - iovec_t * iov, unsigned nr_req, endpoint_t user_endpt, unsigned int flags) -{ - /* NOP */ - return OK; + if ((r = send(m->m_source, &m_reply)) != OK) + log_warn(&log, "send() to %d failed: %d\n", m->m_source, r); } /* @@ -549,7 +522,7 @@ main(int argc, char *argv[]) memset(i2cdev, '\0', sizeof(i2cdev)); sef_local_startup(); - chardriver_task(&i2c_tab, CHARDRIVER_SYNC); + chardriver_task(&i2c_tab); return OK; } diff --git a/drivers/log/log.c b/drivers/log/log.c index 5de3d89df..df267aec2 100644 --- a/drivers/log/log.c +++ b/drivers/log/log.c @@ -19,32 +19,24 @@ #define LOGINC(n, i) do { (n) = (((n) + (i)) % LOG_SIZE); } while(0) struct logdevice logdevices[NR_DEVS]; -static struct device log_geom[NR_DEVS]; /* base and size of devices */ -static int log_device = -1; /* current device */ -static struct device *log_prepare(dev_t device); -static int log_transfer(endpoint_t endpt, int opcode, u64_t position, - iovec_t *iov, unsigned int nr_req, endpoint_t user_endpt, unsigned int - flags); -static int log_do_open(message *m_ptr); -static int log_cancel(message *m_ptr); -static int log_select(message *m_ptr); -static int log_other(message *m_ptr); -static int subread(struct logdevice *log, int count, endpoint_t endpt, - cp_grant_id_t grant, size_t); +static ssize_t log_read(devminor_t minor, u64_t position, endpoint_t endpt, + cp_grant_id_t grant, size_t size, int flags, cdev_id_t id); +static ssize_t log_write(devminor_t minor, u64_t position, endpoint_t endpt, + cp_grant_id_t grant, size_t size, int flags, cdev_id_t id); +static int log_open(devminor_t minor, int access, endpoint_t user_endpt); +static int log_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id); +static int log_select(devminor_t minor, unsigned int ops, endpoint_t endpt); +static int subread(struct logdevice *log, size_t size, endpoint_t endpt, + cp_grant_id_t grant); /* Entry points to this driver. */ static struct chardriver log_dtab = { - log_do_open, /* open or mount */ - do_nop, /* nothing on a close */ - nop_ioctl, /* ioctl nop */ - log_prepare, /* prepare for I/O on a given minor device */ - log_transfer, /* do the I/O */ - nop_cleanup, /* no need to clean up */ - nop_alarm, /* no alarm */ - log_cancel, /* CANCEL request */ - log_select, /* DEV_SELECT request */ - log_other /* Unrecognized messages */ + .cdr_open = log_open, + .cdr_read = log_read, + .cdr_write = log_write, + .cdr_cancel = log_cancel, + .cdr_select = log_select }; /* SEF functions and variables. */ @@ -64,7 +56,7 @@ int main(void) sef_local_startup(); /* Call the generic receive loop. */ - chardriver_task(&log_dtab, CHARDRIVER_ASYNC); + chardriver_task(&log_dtab); return(OK); } @@ -101,17 +93,15 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info)) /* Initialize log devices. */ for(i = 0; i < NR_DEVS; i++) { - log_geom[i].dv_size = ((u64_t)(LOG_SIZE)); - log_geom[i].dv_base = ((u64_t)((long)logdevices[i].log_buffer)); logdevices[i].log_size = logdevices[i].log_read = logdevices[i].log_write = - logdevices[i].log_select_alerted = - logdevices[i].log_selected = - logdevices[i].log_select_ready_ops = 0; + logdevices[i].log_selected = 0; logdevices[i].log_source = NONE; - logdevices[i].log_revive_alerted = 0; } + /* Register for diagnostics notifications. */ + sys_diagctl_register(); + return(OK); } @@ -126,29 +116,24 @@ static void sef_cb_signal_handler(int signo) do_new_kmess(); } -/*===========================================================================* - * log_prepare * - *===========================================================================*/ -static struct device *log_prepare(dev_t device) -{ -/* Prepare for I/O on a device: check if the minor device number is ok. */ - - if (device >= NR_DEVS) return(NULL); - log_device = (int) device; - - return(&log_geom[device]); -} - /*===========================================================================* * subwrite * *===========================================================================*/ static int -subwrite(struct logdevice *log, int count, endpoint_t endpt, - cp_grant_id_t grant, size_t offset, char *localbuf) +subwrite(struct logdevice *log, size_t size, endpoint_t endpt, + cp_grant_id_t grant, char *localbuf) { - int d, r; - char *buf; - message m; + size_t count, offset; + int overflow, r; + devminor_t minor; + char *buf; + message m; + + /* With a sufficiently large input size, we might wrap around the ring buffer + * multiple times. + */ + for (offset = 0; offset < size; offset += count) { + count = size - offset; if (log->log_write + count > LOG_SIZE) count = LOG_SIZE - log->log_write; @@ -156,75 +141,49 @@ subwrite(struct logdevice *log, int count, endpoint_t endpt, if(localbuf != NULL) { memcpy(buf, localbuf, count); + localbuf += count; } else { if((r=sys_safecopyfrom(endpt, grant, offset, (vir_bytes)buf, count)) != OK) - return r; + break; /* do process partial write upon error */ } LOGINC(log->log_write, count); log->log_size += count; if(log->log_size > LOG_SIZE) { - int overflow; overflow = log->log_size - LOG_SIZE; log->log_size -= overflow; LOGINC(log->log_read, overflow); } - if(log->log_size > 0 && log->log_source != NONE && - !log->log_revive_alerted) { - /* Someone who was suspended on read can now - * be revived. - */ - log->log_status = subread(log, log->log_iosize, - log->log_source, log->log_user_grant, - log->log_user_offset); + r = offset; /* this will be the return value upon success */ + } - m.m_type = DEV_REVIVE; - m.REP_ENDPT = log->log_proc_nr; - m.REP_STATUS = log->log_status; - m.REP_IO_GRANT = log->log_user_grant; - r= send(log->log_source, &m); - if (r != OK) - { - printf("log`subwrite: send to %d failed: %d\n", - log->log_source, r); - } - log->log_source = NONE; - } + if (log->log_size > 0 && log->log_source != NONE) { + /* Someone who was suspended on read can now be revived. */ + r = subread(log, log->log_iosize, log->log_source, log->log_grant); - if(log->log_size > 0) - log->log_select_ready_ops |= SEL_RD; + chardriver_reply_task(log->log_source, log->log_id, r); - if(log->log_size > 0 && log->log_selected && - !(log->log_select_alerted)) { - /* Someone(s) who was/were select()ing can now - * be awoken. If there was a blocking read (above), - * this can only happen if the blocking read didn't - * swallow all the data (log_size > 0). - */ - if(log->log_selected & SEL_RD) { - d= log-logdevices; - m.m_type = DEV_SEL_REPL2; - m.DEV_SEL_OPS = log->log_select_ready_ops; - m.DEV_MINOR = d; + log->log_source = NONE; + } + + if (log->log_size > 0 && (log->log_selected & CDEV_OP_RD)) { + /* Someone(s) who was/were select()ing can now be awoken. If there was + * a blocking read (above), this can only happen if the blocking read + * didn't swallow all the data (log_size > 0). + */ + minor = log-logdevices; #if LOG_DEBUG - printf("select sending DEV_SEL_REPL2\n"); + printf("select sending CDEV_SEL2_REPLY\n"); #endif - r= send(log->log_select_proc, &m); - if (r != OK) - { - printf( - "log`subwrite: send to %d failed: %d\n", - log->log_select_proc, r); - } - log->log_selected &= ~log->log_select_ready_ops; - } - } + chardriver_reply_select(log->log_select_proc, minor, CDEV_OP_RD); + log->log_selected &= ~CDEV_OP_RD; + } - return count; + return r; } /*===========================================================================* @@ -233,210 +192,156 @@ subwrite(struct logdevice *log, int count, endpoint_t endpt, void log_append(char *buf, int count) { - int w = 0, skip = 0; + int skip = 0; - if(count < 1) return; - if(count > LOG_SIZE) skip = count - LOG_SIZE; - count -= skip; - buf += skip; - w = subwrite(&logdevices[0], count, SELF, GRANT_INVALID, 0, buf); + if(count < 1) return; + if(count > LOG_SIZE) skip = count - LOG_SIZE; + count -= skip; + buf += skip; - if(w > 0 && w < count) - subwrite(&logdevices[0], count-w, SELF, GRANT_INVALID, 0, - buf + w); - return; + subwrite(&logdevices[0], count, SELF, GRANT_INVALID, buf); } /*===========================================================================* * subread * *===========================================================================*/ static int -subread(struct logdevice *log, int count, endpoint_t endpt, - cp_grant_id_t grant, size_t offset) +subread(struct logdevice *log, size_t size, endpoint_t endpt, + cp_grant_id_t grant) { - char *buf; - int r; + size_t offset, count; + char *buf; + int r; + + for (offset = 0; log->log_size > 0 && offset < size; offset += count) { + count = size - offset; + if (count > log->log_size) count = log->log_size; if (log->log_read + count > LOG_SIZE) count = LOG_SIZE - log->log_read; buf = log->log_buffer + log->log_read; - if((r=sys_safecopyto(endpt, grant, offset, - (vir_bytes)buf, count)) != OK) + if((r=sys_safecopyto(endpt, grant, offset, (vir_bytes)buf, + count)) != OK) return r; LOGINC(log->log_read, count); log->log_size -= count; + } - return count; + return offset; } /*===========================================================================* - * log_transfer * + * log_read * *===========================================================================*/ -static int log_transfer( - endpoint_t endpt, /* endpoint of grant owner */ - int opcode, /* DEV_GATHER_S or DEV_SCATTER_S */ - u64_t UNUSED(position), /* offset on device to read or write */ - iovec_t *iov, /* pointer to read or write request vector */ - unsigned int nr_req, /* length of request vector */ - endpoint_t user_endpt, /* endpoint of user process */ - unsigned int UNUSED(flags) -) +static ssize_t log_read(devminor_t minor, u64_t UNUSED(position), + endpoint_t endpt, cp_grant_id_t grant, size_t size, int flags, + cdev_id_t id) { -/* Read or write one the driver's minor devices. */ - int count; - cp_grant_id_t grant; - int accumulated_read = 0; +/* Read from one of the driver's minor devices. */ struct logdevice *log; - size_t vir_offset = 0; + int r; - if(log_device < 0 || log_device >= NR_DEVS) - return EIO; + if (minor < 0 || minor >= NR_DEVS) return EIO; + log = &logdevices[minor]; - /* Get minor device number and check for /dev/null. */ - log = &logdevices[log_device]; + /* If there's already someone hanging to read, don't accept new work. */ + if (log->log_source != NONE) return OK; - while (nr_req > 0) { - /* How much to transfer and where to / from. */ - count = iov->iov_size; - grant = iov->iov_addr; + if (!log->log_size && size > 0) { + if (flags & CDEV_NONBLOCK) return EAGAIN; - switch (log_device) { - - case MINOR_KLOG: - if (opcode == DEV_GATHER_S) { - if (log->log_source != NONE || count < 1) { - /* There's already someone hanging to read, or - * no real I/O requested. - */ - return(OK); - } - - if (!log->log_size) { - if(accumulated_read) - return OK; - /* No data available; let caller block. */ - log->log_source = endpt; - log->log_iosize = count; - log->log_user_grant = grant; - log->log_user_offset = 0; - log->log_revive_alerted = 0; - log->log_proc_nr = user_endpt; + /* No data available; let caller block. */ + log->log_source = endpt; + log->log_iosize = size; + log->log_grant = grant; + log->log_id = id; #if LOG_DEBUG - printf("blocked %d (%d)\n", - log->log_source, log->log_proc_nr); + printf("blocked %d (%d)\n", log->log_source, id); #endif - return(EDONTREPLY); - } - count = subread(log, count, endpt, grant, vir_offset); - if(count < 0) { - return count; - } - accumulated_read += count; - } else { - count = subwrite(log, count, endpt, grant, vir_offset, NULL); - if(count < 0) - return count; - } - break; - /* Unknown (illegal) minor device. */ - default: - return(EINVAL); - } - - /* Book the number of bytes transferred. */ - vir_offset += count; - if ((iov->iov_size -= count) == 0) { iov++; nr_req--; vir_offset = 0; } + return EDONTREPLY; } - return(OK); + + return subread(log, size, endpt, grant); +} + +/*===========================================================================* + * log_write * + *===========================================================================*/ +static ssize_t log_write(devminor_t minor, u64_t UNUSED(position), + endpoint_t endpt, cp_grant_id_t grant, size_t size, int UNUSED(flags), + cdev_id_t UNUSED(id)) +{ +/* Write to one of the driver's minor devices. */ + struct logdevice *log; + int r; + + if (minor < 0 || minor >= NR_DEVS) return EIO; + log = &logdevices[minor]; + + return subwrite(log, size, endpt, grant, NULL); } /*============================================================================* - * log_do_open * + * log_open * *============================================================================*/ -static int log_do_open(message *m_ptr) +static int log_open(devminor_t minor, int UNUSED(access), + endpoint_t UNUSED(user_endpt)) { - if (log_prepare(m_ptr->DEVICE) == NULL) return(ENXIO); + if (minor < 0 || minor >= NR_DEVS) return(ENXIO); + return(OK); } /*============================================================================* * log_cancel * *============================================================================*/ -static int log_cancel(message *m_ptr) +static int log_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id) { - int d; - d = m_ptr->TTY_LINE; - if(d < 0 || d >= NR_DEVS) + if (minor < 0 || minor >= NR_DEVS) return EINVAL; - logdevices[d].log_proc_nr = NONE; - logdevices[d].log_revive_alerted = 0; - return(OK); -} -/*============================================================================* - * log_other * - *============================================================================*/ -static int log_other(message *m_ptr) -{ - int r; + /* Not for the suspended request? Must be a stale cancel request. Ignore. */ + if (logdevices[minor].log_source != endpt || logdevices[minor].log_id != id) + return EDONTREPLY; - /* This function gets messages that the generic driver doesn't - * understand. - */ - if (is_notify(m_ptr->m_type)) { - return EINVAL; - } + logdevices[minor].log_source = NONE; - switch(m_ptr->m_type) { - case DEV_STATUS: { - printf("log_other: unexpected DEV_STATUS request\n"); - r = EDONTREPLY; - break; - } - default: - r = EINVAL; - break; - } - return r; + return EINTR; /* this is the reply to the original, interrupted request */ } /*============================================================================* * log_select * *============================================================================*/ -static int log_select(message *m_ptr) +static int log_select(devminor_t minor, unsigned int ops, endpoint_t endpt) { - int d, ready_ops = 0, ops = 0; - d = m_ptr->TTY_LINE; - if(d < 0 || d >= NR_DEVS) { -#if LOG_DEBUG - printf("line %d? EINVAL\n", d); -#endif - return EINVAL; - } + int want_ops, ready_ops = 0; - ops = m_ptr->USER_ENDPT & (SEL_RD|SEL_WR|SEL_ERR); + if (minor < 0 || minor >= NR_DEVS) + return ENXIO; + + want_ops = ops & (CDEV_OP_RD | CDEV_OP_WR | CDEV_OP_ERR); /* Read blocks when there is no log. */ - if((m_ptr->USER_ENDPT & SEL_RD) && logdevices[d].log_size > 0) { + if ((want_ops & CDEV_OP_RD) && logdevices[minor].log_size > 0) { #if LOG_DEBUG - printf("log can read; size %d\n", logdevices[d].log_size); + printf("log can read; size %d\n", logdevices[minor].log_size); #endif - ready_ops |= SEL_RD; /* writes never block */ + ready_ops |= CDEV_OP_RD; } /* Write never blocks. */ - if(m_ptr->USER_ENDPT & SEL_WR) ready_ops |= SEL_WR; + if (want_ops & CDEV_OP_WR) ready_ops |= CDEV_OP_WR; - /* Enable select calback if no operations were - * ready to go, but operations were requested, - * and notify was enabled. - */ - if((m_ptr->USER_ENDPT & SEL_NOTIFY) && ops && !ready_ops) { - logdevices[d].log_selected |= ops; - logdevices[d].log_select_proc = m_ptr->m_source; + /* Enable select calback if not all requested operations were ready to go, + * and notify was enabled. + */ + want_ops &= ~ready_ops; + if ((ops & CDEV_NOTIFY) && want_ops) { + logdevices[minor].log_selected |= want_ops; + logdevices[minor].log_select_proc = endpt; #if LOG_DEBUG printf("log setting selector.\n"); #endif @@ -448,4 +353,3 @@ static int log_select(message *m_ptr) return(ready_ops); } - diff --git a/drivers/log/log.h b/drivers/log/log.h index 98129c2d8..a4170aaba 100644 --- a/drivers/log/log.h +++ b/drivers/log/log.h @@ -10,24 +10,18 @@ /* Constants and types. */ #define LOG_SIZE (50*1024) -#define SUSPENDABLE 1 struct logdevice { char log_buffer[LOG_SIZE]; int log_size, /* no. of bytes in log buffer */ log_read, /* read mark */ log_write; /* write mark */ -#if SUSPENDABLE - endpoint_t log_proc_nr, - log_source; + endpoint_t log_source; + cdev_id_t log_id; int log_iosize, - log_revive_alerted, log_status; - cp_grant_id_t log_user_grant; - vir_bytes log_user_offset; -#endif - int log_selected, log_select_proc, - log_select_alerted, log_select_ready_ops; + cp_grant_id_t log_grant; + int log_selected, log_select_proc; }; /* Function prototypes. */ diff --git a/drivers/memory/memory.c b/drivers/memory/memory.c index d42167864..77f1c8953 100644 --- a/drivers/memory/memory.c +++ b/drivers/memory/memory.c @@ -41,63 +41,46 @@ static struct device m_geom[NR_DEVS]; /* base and size of each device */ static vir_bytes m_vaddrs[NR_DEVS]; -static dev_t m_device; /* current minor character device */ static int openct[NR_DEVS]; -static struct device *m_prepare(dev_t device); -static int m_transfer(endpoint_t endpt, int opcode, u64_t position, - iovec_t *iov, unsigned int nr_req, endpoint_t user_endpt, unsigned int - flags); -static int m_do_open(message *m_ptr); -static int m_do_close(message *m_ptr); +static ssize_t m_char_read(devminor_t minor, u64_t position, endpoint_t endpt, + cp_grant_id_t grant, size_t size, int flags, cdev_id_t id); +static ssize_t m_char_write(devminor_t minor, u64_t position, endpoint_t endpt, + cp_grant_id_t grant, size_t size, int flags, cdev_id_t id); +static int m_char_open(devminor_t minor, int access, endpoint_t user_endpt); +static int m_char_close(devminor_t minor); -static struct device *m_block_part(dev_t minor); -static int m_block_transfer(dev_t minor, int do_write, u64_t position, +static struct device *m_block_part(devminor_t minor); +static ssize_t m_block_transfer(devminor_t minor, int do_write, u64_t position, endpoint_t endpt, iovec_t *iov, unsigned int nr_req, int flags); -static int m_block_open(dev_t minor, int access); -static int m_block_close(dev_t minor); -static int m_block_ioctl(dev_t minor, unsigned int request, endpoint_t - endpt, cp_grant_id_t grant); +static int m_block_open(devminor_t minor, int access); +static int m_block_close(devminor_t minor); +static int m_block_ioctl(devminor_t minor, unsigned long request, endpoint_t + endpt, cp_grant_id_t grant, endpoint_t user_endpt); /* Entry points to the CHARACTER part of this driver. */ static struct chardriver m_cdtab = { - m_do_open, /* open or mount */ - m_do_close, /* nothing on a close */ - nop_ioctl, /* no I/O control */ - m_prepare, /* prepare for I/O on a given minor device */ - m_transfer, /* do the I/O */ - nop_cleanup, /* no need to clean up */ - nop_alarm, /* no alarms */ - nop_cancel, /* no blocking operations */ - nop_select, /* select not supported */ - NULL /* other messages not supported */ + .cdr_open = m_char_open, /* open device */ + .cdr_close = m_char_close, /* close device */ + .cdr_read = m_char_read, /* read from device */ + .cdr_write = m_char_write /* write to device */ }; /* Entry points to the BLOCK part of this driver. */ static struct blockdriver m_bdtab = { - BLOCKDRIVER_TYPE_DISK,/* handle partition requests */ - m_block_open, /* open or mount */ - m_block_close, /* nothing on a close */ - m_block_transfer, /* do the I/O */ - m_block_ioctl, /* ram disk I/O control */ - NULL, /* no need to clean up */ - m_block_part, /* return partition information */ - NULL, /* no geometry */ - NULL, /* no interrupt processing */ - NULL, /* no alarm processing */ - NULL, /* no processing of other messages */ - NULL /* no threading support */ + .bdr_type = BLOCKDRIVER_TYPE_DISK,/* handle partition requests */ + .bdr_open = m_block_open, /* open device */ + .bdr_close = m_block_close, /* nothing on a close */ + .bdr_transfer = m_block_transfer, /* do the I/O */ + .bdr_ioctl = m_block_ioctl, /* ram disk I/O control */ + .bdr_part = m_block_part /* return partition information */ }; -#define click_to_round_k(n) \ - ((unsigned) ((((unsigned long) (n) << CLICK_SHIFT) + 512) / 1024)) - /* SEF functions and variables. */ static void sef_local_startup(void); static int sef_cb_init_fresh(int type, sef_init_info_t *info); - /*===========================================================================* * main * *===========================================================================*/ @@ -117,8 +100,7 @@ int main(void) if (IS_BDEV_RQ(msg.m_type)) blockdriver_process(&m_bdtab, &msg, ipc_status); else - chardriver_process(&m_cdtab, CHARDRIVER_SYNC, &msg, - ipc_status); + chardriver_process(&m_cdtab, &msg, ipc_status); } return(OK); @@ -158,8 +140,8 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info)) } /* Map in kernel memory for /dev/kmem. */ - m_geom[KMEM_DEV].dv_base = cvul64(kinfo.kmem_base); - m_geom[KMEM_DEV].dv_size = cvul64(kinfo.kmem_size); + m_geom[KMEM_DEV].dv_base = kinfo.kmem_base; + m_geom[KMEM_DEV].dv_size = kinfo.kmem_size; if((m_vaddrs[KMEM_DEV] = vm_map_phys(SELF, (void *) kinfo.kmem_base, kinfo.kmem_size)) == MAP_FAILED) { printf("MEM: Couldn't map in /dev/kmem."); @@ -167,16 +149,16 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info)) #endif /* Ramdisk image built into the memory driver */ - m_geom[IMGRD_DEV].dv_base= ((u64_t)(0)); - m_geom[IMGRD_DEV].dv_size= ((u64_t)(imgrd_size)); + m_geom[IMGRD_DEV].dv_base= 0; + m_geom[IMGRD_DEV].dv_size= imgrd_size; m_vaddrs[IMGRD_DEV] = (vir_bytes) imgrd; for(i = 0; i < NR_DEVS; i++) openct[i] = 0; /* Set up memory range for /dev/mem. */ - m_geom[MEM_DEV].dv_base = ((u64_t)(0)); - m_geom[MEM_DEV].dv_size = ((u64_t)(0xffffffff)); + m_geom[MEM_DEV].dv_base = 0; + m_geom[MEM_DEV].dv_size = 0xffffffffULL; m_vaddrs[MEM_DEV] = (vir_bytes) MAP_FAILED; /* we are not mapping this in. */ @@ -186,7 +168,7 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info)) /*===========================================================================* * m_is_block * *===========================================================================*/ -static int m_is_block(dev_t minor) +static int m_is_block(devminor_t minor) { /* Return TRUE iff the given minor device number is for a block device. */ @@ -203,206 +185,218 @@ static int m_is_block(dev_t minor) } /*===========================================================================* - * m_prepare * + * m_transfer_kmem * *===========================================================================*/ -static struct device *m_prepare(dev_t device) +static ssize_t m_transfer_kmem(devminor_t minor, int do_write, u64_t position, + endpoint_t endpt, cp_grant_id_t grant, size_t size) { -/* Prepare for I/O on a device: check if the minor device number is ok. */ - if (device >= NR_DEVS || m_is_block(device)) return(NULL); - m_device = device; - - return(&m_geom[device]); -} - -/*===========================================================================* - * m_transfer * - *===========================================================================*/ -static int m_transfer( - endpoint_t endpt, /* endpoint of grant owner */ - int opcode, /* DEV_GATHER_S or DEV_SCATTER_S */ - u64_t pos64, /* offset on device to read or write */ - iovec_t *iov, /* pointer to read or write request vector */ - unsigned int nr_req, /* length of request vector */ - endpoint_t UNUSED(user_endpt),/* endpoint of user process */ - unsigned int UNUSED(flags) -) -{ -/* Read or write one the driver's character devices. */ - unsigned count; - vir_bytes vir_offset = 0; - struct device *dv; - u64_t dv_size; - int s, r; - u64_t position; - cp_grant_id_t grant; - vir_bytes dev_vaddr; - - /* ZERO_DEV and NULL_DEV are infinite in size. */ - if (m_device != ZERO_DEV && m_device != NULL_DEV && ex64hi(pos64) != 0) - return OK; /* Beyond EOF */ - position= pos64; - - /* Get minor device number and check for /dev/null. */ - dv = &m_geom[m_device]; - dv_size = dv->dv_size; - dev_vaddr = m_vaddrs[m_device]; - - while (nr_req > 0) { - - /* How much to transfer and where to / from. */ - count = iov->iov_size; - grant = (cp_grant_id_t) iov->iov_addr; - - switch (m_device) { - - /* No copying; ignore request. */ - case NULL_DEV: - if (opcode == DEV_GATHER_S) return(OK); /* always at EOF */ - break; - - /* Virtual copying. For kernel memory. */ - default: - case KMEM_DEV: - if(!dev_vaddr || dev_vaddr == (vir_bytes) MAP_FAILED) { - printf("MEM: dev %d not initialized\n", m_device); - return EIO; - } - if (position >= dv_size) return(OK); /* check for EOF */ - if (position + count > dv_size) count = dv_size - position; - if (opcode == DEV_GATHER_S) { /* copy actual data */ - r=sys_safecopyto(endpt, grant, vir_offset, - dev_vaddr + position, count); - } else { - r=sys_safecopyfrom(endpt, grant, vir_offset, - dev_vaddr + position, count); - } - if(r != OK) { - panic("I/O copy failed: %d", r); - } - break; - - /* Physical copying. Only used to access entire memory. - * Transfer one 'page window' at a time. - */ - case MEM_DEV: - { - u32_t pagestart, page_off; - static u32_t pagestart_mapped; - static int any_mapped = 0; - static char *vaddr; - int r; - u32_t subcount; - phys_bytes mem_phys; - - if (position >= dv_size) - return(OK); /* check for EOF */ - if (position + count > dv_size) - count = dv_size - position; - mem_phys = position; - - page_off = mem_phys % PAGE_SIZE; - pagestart = mem_phys - page_off; - - /* All memory to the map call has to be page-aligned. - * Don't have to map same page over and over. - */ - if(!any_mapped || pagestart_mapped != pagestart) { - if(any_mapped) { - if(vm_unmap_phys(SELF, vaddr, PAGE_SIZE) != OK) - panic("vm_unmap_phys failed"); - any_mapped = 0; - } - vaddr = vm_map_phys(SELF, (void *) pagestart, PAGE_SIZE); - if(vaddr == MAP_FAILED) - r = ENOMEM; - else - r = OK; - if(r != OK) { - printf("memory: vm_map_phys failed\n"); - return r; - } - any_mapped = 1; - pagestart_mapped = pagestart; - } - - /* how much to be done within this page. */ - subcount = PAGE_SIZE-page_off; - if(subcount > count) - subcount = count; - - if (opcode == DEV_GATHER_S) { /* copy data */ - s=sys_safecopyto(endpt, grant, - vir_offset, (vir_bytes) vaddr+page_off, subcount); - } else { - s=sys_safecopyfrom(endpt, grant, - vir_offset, (vir_bytes) vaddr+page_off, subcount); - } - if(s != OK) - return s; - count = subcount; - break; - } - - /* Null byte stream generator. */ - case ZERO_DEV: - if (opcode == DEV_GATHER_S) - if ((s = sys_safememset(endpt, grant, 0, '\0', count)) != OK) - return s; - - break; - - } - - /* Book the number of bytes transferred. */ - position += count; - vir_offset += count; - if ((iov->iov_size -= count) == 0) { iov++; nr_req--; vir_offset = 0; } - - } - return(OK); -} - -/*===========================================================================* - * m_do_open * - *===========================================================================*/ -static int m_do_open(message *m_ptr) -{ -/* Open a memory character device. */ +/* Transfer from or to the KMEM device. */ + u64_t dv_size, dev_vaddr; int r; -/* Check device number on open. */ - if (m_prepare(m_ptr->DEVICE) == NULL) return(ENXIO); + dv_size = m_geom[minor].dv_size; + dev_vaddr = m_vaddrs[minor]; + + if (!dev_vaddr || dev_vaddr == (vir_bytes) MAP_FAILED) { + printf("MEM: dev %d not initialized\n", minor); + return EIO; + } + + if (position >= dv_size) return 0; /* check for EOF */ + if (position + size > dv_size) size = dv_size - position; + + if (!do_write) /* copy actual data */ + r = sys_safecopyto(endpt, grant, 0, dev_vaddr + position, size); + else + r = sys_safecopyfrom(endpt, grant, 0, dev_vaddr + position, size); + + return (r != OK) ? r : size; +} + +/*===========================================================================* + * m_transfer_mem * + *===========================================================================*/ +static ssize_t m_transfer_mem(devminor_t minor, int do_write, u64_t position, + endpoint_t endpt, cp_grant_id_t grant, size_t size) +{ +/* Transfer from or to the MEM device. */ + static int any_mapped = 0; + static phys_bytes pagestart_mapped; + static char *vaddr; + phys_bytes mem_phys, pagestart; + size_t off, page_off, subcount; + u64_t dv_size; + int r; + + dv_size = m_geom[minor].dv_size; + if (position >= dv_size) return 0; /* check for EOF */ + if (position + size > dv_size) size = dv_size - position; + + /* Physical copying. Only used to access entire memory. + * Transfer one 'page window' at a time. + */ + off = 0; + while (off < size) { + mem_phys = (phys_bytes) position; + + page_off = (size_t) (mem_phys % PAGE_SIZE); + pagestart = mem_phys - page_off; + + /* All memory to the map call has to be page-aligned. + * Don't have to map same page over and over. + */ + if (!any_mapped || pagestart_mapped != pagestart) { + if (any_mapped) { + if (vm_unmap_phys(SELF, vaddr, PAGE_SIZE) != OK) + panic("vm_unmap_phys failed"); + any_mapped = 0; + } + + vaddr = vm_map_phys(SELF, (void *) pagestart, PAGE_SIZE); + if (vaddr == MAP_FAILED) { + printf("memory: vm_map_phys failed\n"); + return ENOMEM; + } + any_mapped = 1; + pagestart_mapped = pagestart; + } + + /* how much to be done within this page. */ + subcount = PAGE_SIZE - page_off; + if (subcount > size) + subcount = size; + + if (!do_write) /* copy data */ + r = sys_safecopyto(endpt, grant, off, + (vir_bytes) vaddr + page_off, subcount); + else + r = sys_safecopyfrom(endpt, grant, off, + (vir_bytes) vaddr + page_off, subcount); + if (r != OK) + return r; + + position += subcount; + off += subcount; + } + + return off; +} + +/*===========================================================================* + * m_char_read * + *===========================================================================*/ +static ssize_t m_char_read(devminor_t minor, u64_t position, endpoint_t endpt, + cp_grant_id_t grant, size_t size, int UNUSED(flags), + cdev_id_t UNUSED(id)) +{ +/* Read from one of the driver's character devices. */ + ssize_t r; + + /* Check if the minor device number is ok. */ + if (minor < 0 || minor >= NR_DEVS || m_is_block(minor)) return ENXIO; + + switch (minor) { + case NULL_DEV: + r = 0; /* always at EOF */ + break; + + case ZERO_DEV: + /* Fill the target area with zeroes. In fact, let the kernel do it! */ + if ((r = sys_safememset(endpt, grant, 0, '\0', size)) == OK) + r = size; + break; + + case KMEM_DEV: + r = m_transfer_kmem(minor, FALSE, position, endpt, grant, size); + break; + + case MEM_DEV: + r = m_transfer_mem(minor, FALSE, position, endpt, grant, size); + break; + + default: + panic("unknown character device %d", minor); + } + + return r; +} + +/*===========================================================================* + * m_char_write * + *===========================================================================*/ +static ssize_t m_char_write(devminor_t minor, u64_t position, endpoint_t endpt, + cp_grant_id_t grant, size_t size, int UNUSED(flags), + cdev_id_t UNUSED(id)) +{ +/* Write to one of the driver's character devices. */ + ssize_t r; + + /* Check if the minor device number is ok. */ + if (minor < 0 || minor >= NR_DEVS || m_is_block(minor)) return ENXIO; + + switch (minor) { + case NULL_DEV: + case ZERO_DEV: + r = size; /* just eat everything */ + break; + + case KMEM_DEV: + r = m_transfer_kmem(minor, TRUE, position, endpt, grant, size); + break; + + case MEM_DEV: + r = m_transfer_mem(minor, TRUE, position, endpt, grant, size); + break; + + default: + panic("unknown character device %d", minor); + } + + return r; +} + +/*===========================================================================* + * m_char_open * + *===========================================================================*/ +static int m_char_open(devminor_t minor, int access, endpoint_t user_endpt) +{ +/* Open a memory character device. */ + + /* Check if the minor device number is ok. */ + if (minor < 0 || minor >= NR_DEVS || m_is_block(minor)) return ENXIO; + #if defined(__i386__) - if (m_device == MEM_DEV) + if (minor == MEM_DEV) { - r = sys_enable_iop(m_ptr->USER_ENDPT); + int r = sys_enable_iop(user_endpt); if (r != OK) { - printf("m_do_open: sys_enable_iop failed for %d: %d\n", - m_ptr->USER_ENDPT, r); + printf("m_char_open: sys_enable_iop failed for %d: %d\n", + user_endpt, r); return r; } } #endif - openct[m_device]++; + openct[minor]++; return(OK); } /*===========================================================================* - * m_do_close * + * m_char_close * *===========================================================================*/ -static int m_do_close(message *m_ptr) +static int m_char_close(devminor_t minor) { /* Close a memory character device. */ - if (m_prepare(m_ptr->DEVICE) == NULL) return(ENXIO); - if(openct[m_device] < 1) { - printf("MEMORY: closing unopened device %d\n", m_device); + if (minor < 0 || minor >= NR_DEVS || m_is_block(minor)) return ENXIO; + + if(openct[minor] < 1) { + printf("MEMORY: closing unopened device %d\n", minor); return(EINVAL); } - openct[m_device]--; + openct[minor]--; return(OK); } @@ -410,10 +404,10 @@ static int m_do_close(message *m_ptr) /*===========================================================================* * m_block_part * *===========================================================================*/ -static struct device *m_block_part(dev_t minor) +static struct device *m_block_part(devminor_t minor) { /* Prepare for I/O on a device: check if the minor device number is ok. */ - if (minor >= NR_DEVS || !m_is_block(minor)) return(NULL); + if (minor < 0 || minor >= NR_DEVS || !m_is_block(minor)) return(NULL); return(&m_geom[minor]); } @@ -422,9 +416,9 @@ static struct device *m_block_part(dev_t minor) * m_block_transfer * *===========================================================================*/ static int m_block_transfer( - dev_t minor, /* minor device number */ + devminor_t minor, /* minor device number */ int do_write, /* read or write? */ - u64_t pos64, /* offset on device to read or write */ + u64_t position, /* offset on device to read or write */ endpoint_t endpt, /* process doing the request */ iovec_t *iov, /* pointer to read or write request vector */ unsigned int nr_req, /* length of request vector */ @@ -437,7 +431,6 @@ static int m_block_transfer( struct device *dv; u64_t dv_size; int r; - u64_t position; vir_bytes dev_vaddr; cp_grant_id_t grant; ssize_t total = 0; @@ -447,9 +440,8 @@ static int m_block_transfer( dv_size = dv->dv_size; dev_vaddr = m_vaddrs[minor]; - if (ex64hi(pos64) != 0) + if (ex64hi(position) != 0) return OK; /* Beyond EOF */ - position= pos64; while (nr_req > 0) { @@ -488,7 +480,7 @@ static int m_block_transfer( /*===========================================================================* * m_block_open * *===========================================================================*/ -static int m_block_open(dev_t minor, int UNUSED(access)) +static int m_block_open(devminor_t minor, int UNUSED(access)) { /* Open a memory block device. */ if (m_block_part(minor) == NULL) return(ENXIO); @@ -501,7 +493,7 @@ static int m_block_open(dev_t minor, int UNUSED(access)) /*===========================================================================* * m_block_close * *===========================================================================*/ -static int m_block_close(dev_t minor) +static int m_block_close(devminor_t minor) { /* Close a memory block device. */ if (m_block_part(minor) == NULL) return(ENXIO); @@ -518,8 +510,8 @@ static int m_block_close(dev_t minor) /*===========================================================================* * m_block_ioctl * *===========================================================================*/ -static int m_block_ioctl(dev_t minor, unsigned int request, endpoint_t endpt, - cp_grant_id_t grant) +static int m_block_ioctl(devminor_t minor, unsigned long request, + endpoint_t endpt, cp_grant_id_t grant, endpoint_t UNUSED(user_endpt)) { /* I/O controls for the block devices of the memory driver. Currently there is * one I/O control specific to the memory driver: @@ -554,7 +546,7 @@ static int m_block_ioctl(dev_t minor, unsigned int request, endpoint_t endpt, return s; if(is_imgrd) ramdev_size = 0; - if(m_vaddrs[minor] && !cmp64(dv->dv_size, ((u64_t)(ramdev_size)))) { + if(m_vaddrs[minor] && dv->dv_size == (u64_t) ramdev_size) { return(OK); } /* openct is 1 for the ioctl(). */ @@ -602,7 +594,7 @@ static int m_block_ioctl(dev_t minor, unsigned int request, endpoint_t endpt, m_vaddrs[minor] = (vir_bytes) mem; - dv->dv_size = ((u64_t)(ramdev_size)); + dv->dv_size = ramdev_size; return(OK); } diff --git a/drivers/mmc/mmcblk.c b/drivers/mmc/mmcblk.c index 7541a0605..a3bcb171b 100644 --- a/drivers/mmc/mmcblk.c +++ b/drivers/mmc/mmcblk.c @@ -32,7 +32,6 @@ static struct log log = { /* holding the current host controller */ static struct mmc_host host; -#define SUB_PER_DRIVE (NR_PARTITIONS * NR_PARTITIONS) #define NR_SUBDEVS (MAX_DRIVES * SUB_PER_DRIVE) /* When passing data over a grant one needs to pass @@ -40,19 +39,19 @@ static struct mmc_host host; #define COPYBUFF_SIZE 0x1000 /* 4k buff */ static unsigned char copybuff[COPYBUFF_SIZE]; -static struct sd_slot *get_slot(dev_t minor); +static struct sd_slot *get_slot(devminor_t minor); /* Prototypes for the block device */ -static int block_open(dev_t minor, int access); -static int block_close(dev_t minor); -static int block_transfer(dev_t minor, +static int block_open(devminor_t minor, int access); +static int block_close(devminor_t minor); +static int block_transfer(devminor_t minor, int do_write, u64_t position, endpoint_t endpt, iovec_t * iov, unsigned int nr_req, int flags); -static int block_ioctl(dev_t minor, - unsigned int request, endpoint_t endpt, cp_grant_id_t grant); -static struct device *block_part(dev_t minor); +static int block_ioctl(devminor_t minor, unsigned long request, + endpoint_t endpt, cp_grant_id_t grant, endpoint_t user_endpt); +static struct device *block_part(devminor_t minor); /* System even handling */ static void sef_local_startup(); @@ -73,18 +72,14 @@ static void set_log_level(int level); /* Entry points for the BLOCK driver. */ static struct blockdriver mmc_driver = { - BLOCKDRIVER_TYPE_DISK, /* handle partition requests */ - block_open, /* open or mount */ - block_close, /* on a close */ - block_transfer, /* does the I/O */ - block_ioctl, /* ioclt's */ - NULL, /* no need to clean up (yet) */ - block_part, /* return partition information */ - NULL, /* no geometry */ - hw_intr, /* left over interrupts */ - bdr_alarm, /* no alarm processing */ - NULL, /* no processing of other messages */ - NULL /* no threading support */ + .bdr_type = BLOCKDRIVER_TYPE_DISK,/* handle partition requests */ + .bdr_open = block_open, /* device open */ + .bdr_close = block_close, /* on a close */ + .bdr_transfer = block_transfer, /* does the I/O */ + .bdr_ioctl = block_ioctl, /* ioctls */ + .bdr_part = block_part, /* get partition information */ + .bdr_intr = hw_intr, /* left over interrupts */ + .bdr_alarm = bdr_alarm /* no alarm processing */ }; static void @@ -142,7 +137,7 @@ apply_env() * block_open * *===========================================================================*/ static int -block_open(dev_t minor, int access) +block_open(devminor_t minor, int access) { struct sd_slot *slot; slot = get_slot(minor); @@ -214,7 +209,7 @@ block_open(dev_t minor, int access) * block_close * *===========================================================================*/ static int -block_close(dev_t minor) +block_close(devminor_t minor) { struct sd_slot *slot; @@ -281,7 +276,8 @@ copyfrom(endpoint_t src_e, * block_transfer * *===========================================================================*/ static int -block_transfer(dev_t minor, /* minor device number */ +block_transfer( + devminor_t minor, /* minor device number */ int do_write, /* read or write? */ u64_t position, /* offset on device to read or write */ endpoint_t endpt, /* process doing the request */ @@ -439,8 +435,8 @@ block_transfer(dev_t minor, /* minor device number */ * block_ioctl * *===========================================================================*/ static int -block_ioctl(dev_t minor, - unsigned int request, endpoint_t endpt, cp_grant_id_t grant) +block_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt, + cp_grant_id_t grant, endpoint_t UNUSED(user_endpt)) { /* IOCTL handling */ struct sd_slot *slot; @@ -470,14 +466,14 @@ block_ioctl(dev_t minor, return OK; } - return EINVAL; + return ENOTTY; } /*===========================================================================* * block_part * *===========================================================================*/ static struct device * -block_part(dev_t minor) +block_part(devminor_t minor) { /* * Reuse the existing MINIX major/minor partitioning scheme. @@ -615,7 +611,7 @@ block_signal_handler_cb(int signo) #define IS_MINIX_SUB_PARTITION_MINOR(minor) (minor >= MINOR_d0p0s0 ) static struct sd_slot * -get_slot(dev_t minor) +get_slot(devminor_t minor) { /* * Get an sd_slot based on the minor number. @@ -627,7 +623,7 @@ get_slot(dev_t minor) * number 128 till 144 for sub partitions. */ /* If this is a minor for the first disk (e.g. minor 0 till 5) */ - if (minor / DEV_PER_DRIVE == 0) { + if (minor >= 0 && minor / DEV_PER_DRIVE == 0) { /* we are talking about the first disk and that is all we * support */ return &host.slot[0]; diff --git a/drivers/printer/liveupdate.c b/drivers/printer/liveupdate.c index 1f3655569..232e4e29c 100644 --- a/drivers/printer/liveupdate.c +++ b/drivers/printer/liveupdate.c @@ -2,7 +2,6 @@ /* State management variables. */ EXTERN int writing; -EXTERN int is_status_msg_expected; /* Custom states definition. */ #define PR_STATE_WRITE_PROTOCOL_FREE (SEF_LU_STATE_CUSTOM_BASE + 0) @@ -24,7 +23,7 @@ int sef_cb_lu_prepare(int state) break; case SEF_LU_STATE_PROTOCOL_FREE: - is_ready = (!writing && !is_status_msg_expected); + is_ready = (!writing); break; /* Custom states. */ @@ -52,15 +51,13 @@ void sef_cb_lu_state_dump(int state) { sef_lu_dprint("printer: live update state = %d\n", state); sef_lu_dprint("printer: writing = %d\n", writing); - sef_lu_dprint("printer: is_status_msg_expected = %d\n", - is_status_msg_expected); sef_lu_dprint("printer: SEF_LU_STATE_WORK_FREE(%d) reached = %d\n", SEF_LU_STATE_WORK_FREE, TRUE); sef_lu_dprint("printer: SEF_LU_STATE_REQUEST_FREE(%d) reached = %d\n", SEF_LU_STATE_REQUEST_FREE, TRUE); sef_lu_dprint("printer: SEF_LU_STATE_PROTOCOL_FREE(%d) reached = %d\n", - SEF_LU_STATE_PROTOCOL_FREE, (!writing && !is_status_msg_expected)); + SEF_LU_STATE_PROTOCOL_FREE, (!writing)); sef_lu_dprint("printer: PR_STATE_WRITE_PROTOCOL_FREE(%d) reached = %d\n", PR_STATE_WRITE_PROTOCOL_FREE, (!writing)); } diff --git a/drivers/printer/printer.c b/drivers/printer/printer.c index 5ab2a9491..47abec238 100644 --- a/drivers/printer/printer.c +++ b/drivers/printer/printer.c @@ -5,29 +5,6 @@ * Changes: * May 07, 2004 fix: wait until printer is ready (Jorrit N. Herder) * May 06, 2004 printer driver moved to user-space (Jorrit N. Herder) - * - * The valid messages and their parameters are: - * - * DEV_OPEN: initializes the printer - * DEV_CLOSE: does nothing - * HARD_INT: interrupt handler has finished current chunk of output - * DEV_WRITE: a process wants to write on a terminal - * CANCEL: terminate a previous incomplete system call immediately - * - * m_type TTY_LINE USER_ENDPT COUNT ADDRESS - * |-------------+---------+---------+---------+---------| - * | DEV_OPEN | | | | | - * |-------------+---------+---------+---------+---------| - * | DEV_CLOSE | | proc nr | | | - * ------------------------------------------------------- - * | HARD_INT | | | | | - * |-------------+---------+---------+---------+---------| - * | SYS_EVENT | | | | | - * |-------------+---------+---------+---------+---------| - * | DEV_WRITE |minor dev| proc nr | count | buf ptr | - * |-------------+---------+---------+---------+---------| - * | CANCEL |minor dev| proc nr | | | - * ------------------------------------------------------- * * Note: since only 1 printer is supported, minor dev is not used at present. */ @@ -87,30 +64,29 @@ */ static endpoint_t caller; /* process to tell when printing done (FS) */ -static int revive_pending; /* set to true if revive is pending */ -static int revive_status; /* revive status */ static int done_status; /* status of last output completion */ static int oleft; /* bytes of output left in obuf */ static unsigned char obuf[128]; /* output buffer */ static unsigned const char *optr; /* ptr to next char in obuf to print */ static int orig_count; /* original byte count */ static int port_base; /* I/O port for printer */ -static endpoint_t proc_nr; /* user requesting the printing */ static cp_grant_id_t grant_nr; /* grant on which print happens */ static int user_left; /* bytes of output left in user buf */ static vir_bytes user_vir_d; /* offset in user buf */ int writing; /* nonzero while write is in progress */ +static cdev_id_t write_id; /* request ID of ongoing write */ static int irq_hook_id; /* id of irq hook at kernel */ -static void do_cancel(message *m_ptr); static void output_done(void); -static void do_write(message *m_ptr); -static void do_status(message *m_ptr); static void prepare_output(void); static int do_probe(void); static void do_initialize(void); -static void reply(int code,int replyee,int proc,int status); -static void do_printer_output(void); +static int printer_open(devminor_t minor, int access, endpoint_t user_endpt); +static ssize_t printer_write(devminor_t minor, u64_t position, + endpoint_t endpt, cp_grant_id_t grant, size_t size, int flags, + cdev_id_t id); +static int printer_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id); +static void printer_intr(unsigned int mask); /* SEF functions and variables. */ static void sef_local_startup(void); @@ -118,7 +94,14 @@ static int sef_cb_init_fresh(int type, sef_init_info_t *info); EXTERN int sef_cb_lu_prepare(int state); EXTERN int sef_cb_lu_state_isvalid(int state); EXTERN void sef_cb_lu_state_dump(int state); -int is_status_msg_expected = FALSE; + +/* Entry points to this driver. */ +static struct chardriver printer_tab = { + .cdr_open = printer_open, + .cdr_write = printer_write, + .cdr_cancel = printer_cancel, + .cdr_intr = printer_intr +}; /*===========================================================================* * printer_task * @@ -126,44 +109,11 @@ int is_status_msg_expected = FALSE; int main(void) { /* Main routine of the printer task. */ - message pr_mess; /* buffer for all incoming messages */ - int ipc_status; /* SEF local startup. */ sef_local_startup(); - while (TRUE) { - if(driver_receive(ANY, &pr_mess, &ipc_status) != OK) { - panic("driver_receive failed"); - } - - if (is_ipc_notify(ipc_status)) { - switch (_ENDPOINT_P(pr_mess.m_source)) { - case HARDWARE: - do_printer_output(); - break; - default: - reply(TASK_REPLY, pr_mess.m_source, - pr_mess.USER_ENDPT, EINVAL); - } - continue; - } - - switch(pr_mess.m_type) { - case DEV_OPEN: - do_initialize(); /* initialize */ - /* fall through */ - case DEV_CLOSE: - reply(TASK_REPLY, pr_mess.m_source, pr_mess.USER_ENDPT, OK); - break; - case DEV_WRITE_S: do_write(&pr_mess); break; - case DEV_STATUS: do_status(&pr_mess); break; - case CANCEL: do_cancel(&pr_mess); break; - default: - reply(TASK_REPLY, pr_mess.m_source, pr_mess.USER_ENDPT, - EINVAL); - } - } + chardriver_task(&printer_tab); } /*===========================================================================* @@ -208,53 +158,49 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info)) /*===========================================================================* * do_write * *===========================================================================*/ -static void do_write(m_ptr) -register message *m_ptr; /* pointer to the newly arrived message */ +static ssize_t printer_write(devminor_t UNUSED(minor), u64_t UNUSED(position), + endpoint_t endpt, cp_grant_id_t grant, size_t size, int flags, + cdev_id_t id) { -/* The printer is used by sending DEV_WRITE messages to it. Process one. */ +/* The printer is used by sending write requests to it. Process one. */ + int retries; + u32_t status; - register int r = SUSPEND; - int retries; - u32_t status; + /* Reject command if last write is not yet finished, the count is not + * positive, or we're asked not to block. + */ + if (writing) return EIO; + if (size <= 0) return EINVAL; + if (flags & CDEV_NONBLOCK) return EAGAIN; /* not supported */ - /* Reject command if last write is not yet finished, the count is not - * positive, or the user address is bad. - */ - if (writing) r = EIO; - else if (m_ptr->COUNT <= 0) r = EINVAL; + /* If no errors occurred, continue printing with the caller. + * First wait until the printer is online to prevent stupid errors. + */ + caller = endpt; + user_left = size; + orig_count = size; + user_vir_d = 0; /* Offset. */ + writing = TRUE; + grant_nr = grant; + write_id = id; - /* Reply to FS, no matter what happened, possible SUSPEND caller. */ - reply(TASK_REPLY, m_ptr->m_source, m_ptr->USER_ENDPT, r); - - /* If no errors occurred, continue printing with SUSPENDED caller. - * First wait until the printer is online to prevent stupid errors. - */ - if (SUSPEND == r) { - caller = m_ptr->m_source; - proc_nr = m_ptr->USER_ENDPT; - user_left = m_ptr->COUNT; - orig_count = m_ptr->COUNT; - user_vir_d = 0; /* Offset. */ - writing = TRUE; - grant_nr = (cp_grant_id_t) m_ptr->IO_GRANT; - - retries = MAX_ONLINE_RETRIES + 1; - while (--retries > 0) { - if(sys_inb(port_base + 1, &status) != OK) { + retries = MAX_ONLINE_RETRIES + 1; + while (--retries > 0) { + if (sys_inb(port_base + 1, &status) != OK) { printf("printer: sys_inb of %x failed\n", port_base+1); panic("sys_inb failed"); - } - if ((status & ON_LINE)) { /* printer online! */ - prepare_output(); - do_printer_output(); - return; - } - micro_delay(500000); /* wait before retry */ - } - /* If we reach this point, the printer was not online in time. */ - done_status = status; - output_done(); - } + } + if (status & ON_LINE) { /* printer online! */ + prepare_output(); + printer_intr(0); + return EDONTREPLY; /* we may already have sent a reply */ + } + micro_delay(500000); /* wait before retry */ + } + /* If we reach this point, the printer was not online in time. */ + done_status = status; + output_done(); + return EDONTREPLY; } /*===========================================================================* @@ -265,11 +211,11 @@ static void output_done() /* Previous chunk of printing is finished. Continue if OK and more. * Otherwise, reply to caller (FS). */ - register int status; + int status; - if (!writing) return; /* probably leftover interrupt */ - if (done_status != OK) { /* printer error occurred */ - status = EIO; + if (!writing) return; /* probably leftover interrupt */ + if (done_status != OK) { /* printer error occurred */ + status = EIO; if ((done_status & ON_LINE) == 0) { printf("Printer is not on line\n"); } else if ((done_status & NO_PAPER)) { @@ -283,79 +229,36 @@ static void output_done() status = orig_count - user_left; } oleft = 0; /* cancel further output */ - } - else if (user_left != 0) { /* not yet done, continue! */ + } else if (user_left != 0) { /* not yet done, continue! */ prepare_output(); return; - } - else { /* done! report back to FS */ + } else { /* done! report back to FS */ status = orig_count; - } - is_status_msg_expected = TRUE; - revive_pending = TRUE; - revive_status = status; - notify(caller); -} - -/*===========================================================================* - * do_status * - *===========================================================================*/ -static void do_status(m_ptr) -register message *m_ptr; /* pointer to the newly arrived message */ -{ - if (revive_pending) { - m_ptr->m_type = DEV_REVIVE; /* build message */ - m_ptr->REP_ENDPT = proc_nr; - m_ptr->REP_STATUS = revive_status; - m_ptr->REP_IO_GRANT = grant_nr; - - writing = FALSE; /* unmark event */ - revive_pending = FALSE; /* unmark event */ - } else { - m_ptr->m_type = DEV_NO_STATUS; - - is_status_msg_expected = FALSE; } - send(m_ptr->m_source, m_ptr); /* send the message */ + + chardriver_reply_task(caller, write_id, status); + + writing = FALSE; /* unmark event */ } /*===========================================================================* - * do_cancel * + * printer_cancel * *===========================================================================*/ -static void do_cancel(m_ptr) -register message *m_ptr; /* pointer to the newly arrived message */ +static int printer_cancel(devminor_t UNUSED(minor), endpoint_t endpt, + cdev_id_t id) { /* Cancel a print request that has already started. Usually this means that * the process doing the printing has been killed by a signal. It is not * clear if there are race conditions. Try not to cancel the wrong process, - * but rely on FS to handle the EINTR reply and de-suspension properly. + * but rely on VFS to handle the EINTR reply and de-suspension properly. */ - if (writing && m_ptr->USER_ENDPT == proc_nr) { + if (writing && caller == endpt && write_id == id) { oleft = 0; /* cancel output by interrupt handler */ writing = FALSE; - revive_pending = FALSE; + return EINTR; } - reply(TASK_REPLY, m_ptr->m_source, m_ptr->USER_ENDPT, EINTR); -} - -/*===========================================================================* - * reply * - *===========================================================================*/ -static void reply(code, replyee, process, status) -int code; /* TASK_REPLY or REVIVE */ -int replyee; /* destination for message (normally FS) */ -int process; /* which user requested the printing */ -int status; /* number of chars printed or error code */ -{ -/* Send a reply telling FS that printing has started or stopped. */ - - message pr_mess; - - pr_mess.m_type = code; /* TASK_REPLY or REVIVE */ - pr_mess.REP_STATUS = status; /* count or EIO */ - pr_mess.REP_ENDPT = process; /* which user does this pertain to */ - send(replyee, &pr_mess); /* send the message */ + return EDONTREPLY; } /*===========================================================================* @@ -367,7 +270,7 @@ static int do_probe(void) /* Get the base port for first printer. */ if(sys_readbios(LPT1_IO_PORT_ADDR, &port_base, LPT1_IO_PORT_SIZE) != OK) { - panic("do_initialize: sys_readbios failed"); + panic("do_probe: sys_readbios failed"); } /* If the port is zero, the parallel port is not available at all. */ @@ -380,10 +283,6 @@ static int do_probe(void) static void do_initialize() { /* Set global variables and initialize the printer. */ - static int initialized = FALSE; - if (initialized) return; - initialized = TRUE; - if(sys_outb(port_base + 2, INIT_PRINTER) != OK) { printf("printer: sys_outb of %x failed\n", port_base+2); panic("do_initialize: sys_outb init failed"); @@ -400,6 +299,24 @@ static void do_initialize() } } +/*==========================================================================* + * printer_open * + *==========================================================================*/ +static int printer_open(devminor_t UNUSED(minor), int UNUSED(access), + endpoint_t UNUSED(user_endpt)) +{ +/* Initialize on first open. */ + static int initialized = FALSE; + + if (!initialized) { + do_initialize(); + + initialized = TRUE; + } + + return OK; +} + /*==========================================================================* * prepare_output * *==========================================================================*/ @@ -424,9 +341,9 @@ static void prepare_output() } /*===========================================================================* - * do_printer_output * + * printer_intr * *===========================================================================*/ -static void do_printer_output() +static void printer_intr(unsigned int UNUSED(mask)) { /* This function does the actual output to the printer. This is called on an * interrupt message sent from the generic interrupt handler that 'forwards' diff --git a/drivers/random/main.c b/drivers/random/main.c index 18ed36d34..1ded6f37e 100644 --- a/drivers/random/main.c +++ b/drivers/random/main.c @@ -21,25 +21,20 @@ static dev_t m_device; /* current device */ extern int errno; /* error number for PM calls */ static struct device *r_prepare(dev_t device); -static int r_transfer(endpoint_t endpt, int opcode, u64_t position, - iovec_t *iov, unsigned int nr_req, endpoint_t user_endpt, unsigned int - flags); -static int r_do_open(message *m_ptr); -static void r_random(message *m_ptr); +static ssize_t r_read(devminor_t minor, u64_t position, endpoint_t endpt, + cp_grant_id_t grant, size_t size, int flags, cdev_id_t id); +static ssize_t r_write(devminor_t minor, u64_t position, endpoint_t endpt, + cp_grant_id_t grant, size_t size, int flags, cdev_id_t id); +static int r_open(devminor_t minor, int access, endpoint_t user_endpt); +static void r_random(clock_t stamp); static void r_updatebin(int source, struct k_randomness_bin *rb); /* Entry points to this driver. */ static struct chardriver r_dtab = { - r_do_open, /* open or mount */ - do_nop, /* nothing on a close */ - nop_ioctl, /* no I/O controls supported */ - r_prepare, /* prepare for I/O on a given minor device */ - r_transfer, /* do the I/O */ - nop_cleanup, /* no need to clean up */ - r_random, /* get randomness from kernel (alarm) */ - nop_cancel, /* cancel not supported */ - nop_select, /* select not supported */ - NULL, /* other messages not supported */ + .cdr_open = r_open, /* open device */ + .cdr_read = r_read, /* read from device */ + .cdr_write = r_write, /* write to device (seeding it) */ + .cdr_alarm = r_random /* get randomness from kernel (alarm) */ }; /* Buffer for the /dev/random number generator. */ @@ -59,7 +54,7 @@ int main(void) sef_local_startup(); /* Call the generic receive loop. */ - chardriver_task(&r_dtab, CHARDRIVER_ASYNC); + chardriver_task(&r_dtab); return(OK); } @@ -92,7 +87,7 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info)) int i, s; random_init(); - r_random(NULL); /* also set periodic timer */ + r_random(0); /* also set periodic timer */ /* Retrieve first randomness buffer with parameters. */ if (OK != (s=sys_getrandomness(&krandom))) { @@ -120,103 +115,71 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info)) } /*===========================================================================* - * r_prepare * + * r_read * *===========================================================================*/ -static struct device *r_prepare(dev_t device) +static ssize_t r_read(devminor_t minor, u64_t UNUSED(position), + endpoint_t endpt, cp_grant_id_t grant, size_t size, int UNUSED(flags), + cdev_id_t UNUSED(id)) { -/* Prepare for I/O on a device: check if the minor device number is ok. */ - - if (device >= NR_DEVS) return(NULL); - m_device = device; - - return(&m_geom[device]); -} - -/*===========================================================================* - * r_transfer * - *===========================================================================*/ -static int r_transfer( - endpoint_t endpt, /* endpoint of grant owner */ - int opcode, /* DEV_GATHER or DEV_SCATTER */ - u64_t position, /* offset on device to read or write */ - iovec_t *iov, /* pointer to read or write request vector */ - unsigned int nr_req, /* length of request vector */ - endpoint_t UNUSED(user_endpt),/* endpoint of user process */ - unsigned int UNUSED(flags) -) -{ -/* Read or write one the driver's minor devices. */ - unsigned count, left, chunk; - cp_grant_id_t grant; - struct device *dv; +/* Read from one of the driver's minor devices. */ + size_t offset, chunk; int r; - size_t vir_offset = 0; - /* Get minor device number and check for /dev/null. */ - dv = &m_geom[m_device]; + if (minor != RANDOM_DEV) return(EIO); - while (nr_req > 0) { + if (!random_isseeded()) return(EAGAIN); - /* How much to transfer and where to / from. */ - count = iov->iov_size; - grant = (cp_grant_id_t) iov->iov_addr; - - switch (m_device) { - - /* Random number generator. Character instead of block device. */ - case RANDOM_DEV: - if (opcode == DEV_GATHER_S && !random_isseeded()) - return(EAGAIN); - left = count; - while (left > 0) { - chunk = (left > RANDOM_BUF_SIZE) ? RANDOM_BUF_SIZE : left; - if (opcode == DEV_GATHER_S) { - random_getbytes(random_buf, chunk); - r= sys_safecopyto(endpt, grant, vir_offset, - (vir_bytes) random_buf, chunk); - if (r != OK) - { - printf("random: sys_safecopyto failed for proc %d, " - "grant %d\n", endpt, grant); - return r; - } - } else if (opcode == DEV_SCATTER_S) { - r= sys_safecopyfrom(endpt, grant, vir_offset, - (vir_bytes) random_buf, chunk); - if (r != OK) - { - printf("random: sys_safecopyfrom failed for proc %d, " - "grant %d\n", endpt, grant); - return r; - } - random_putbytes(random_buf, chunk); - } - vir_offset += chunk; - left -= chunk; - } - break; - - /* Unknown (illegal) minor device. */ - default: - return(EINVAL); + for (offset = 0; offset < size; offset += chunk) { + chunk = MIN(size - offset, RANDOM_BUF_SIZE); + random_getbytes(random_buf, chunk); + r = sys_safecopyto(endpt, grant, offset, (vir_bytes)random_buf, chunk); + if (r != OK) { + printf("random: sys_safecopyto failed for proc %d, grant %d\n", + endpt, grant); + return r; } - - /* Book the number of bytes transferred. */ - position= add64u(position, count); - if ((iov->iov_size -= count) == 0) { iov++; nr_req--; vir_offset = 0; } - } - return(OK); + + return size; } /*===========================================================================* - * r_do_open * + * r_write * *===========================================================================*/ -static int r_do_open(message *m_ptr) +static ssize_t r_write(devminor_t minor, u64_t UNUSED(position), + endpoint_t endpt, cp_grant_id_t grant, size_t size, int UNUSED(flags), + cdev_id_t UNUSED(id)) +{ +/* Write to one of the driver's minor devices. */ + size_t offset, chunk; + int r; + + if (minor != RANDOM_DEV) return(EIO); + + for (offset = 0; offset < size; offset += chunk) { + chunk = MIN(size - offset, RANDOM_BUF_SIZE); + r = sys_safecopyfrom(endpt, grant, offset, (vir_bytes)random_buf, + chunk); + if (r != OK) { + printf("random: sys_safecopyfrom failed for proc %d," + " grant %d\n", endpt, grant); + return r; + } + random_putbytes(random_buf, chunk); + } + + return size; +} + +/*===========================================================================* + * r_open * + *===========================================================================*/ +static int r_open(devminor_t minor, int access, endpoint_t UNUSED(user_endpt)) { /* Check device number on open. */ - if (r_prepare(m_ptr->DEVICE) == NULL) return(ENXIO); + + if (minor < 0 || minor >= NR_DEVS) return(ENXIO); return(OK); } @@ -265,7 +228,7 @@ static void r_updatebin(int source, struct k_randomness_bin *rb) /*===========================================================================* * r_random * *===========================================================================*/ -static void r_random(message *UNUSED(m_ptr)) +static void r_random(clock_t UNUSED(stamp)) { /* Fetch random information from the kernel to update /dev/random. */ int s; diff --git a/drivers/sht21/sht21.c b/drivers/sht21/sht21.c index cb9f327d2..efaabc934 100644 --- a/drivers/sht21/sht21.c +++ b/drivers/sht21/sht21.c @@ -116,11 +116,9 @@ static uint8_t crc8(uint8_t crc, uint8_t byte); static int checksum(uint8_t * bytes, int nbytes, uint8_t expected_crc); /* libchardriver callbacks */ -static struct device *sht21_prepare(dev_t UNUSED(dev)); -static int sht21_transfer(endpoint_t endpt, int opcode, u64_t position, - iovec_t * iov, unsigned nr_req, endpoint_t UNUSED(user_endpt), - unsigned int UNUSED(flags)); -static int sht21_other(message * m); +static ssize_t sht21_read(devminor_t minor, u64_t position, endpoint_t endpt, + cp_grant_id_t grant, size_t size, int flags, cdev_id_t id); +static void sht21_other(message * m, int ipc_status); /* SEF functions */ static int sef_cb_lu_state_save(int); @@ -130,21 +128,8 @@ static void sef_local_startup(void); /* Entry points to this driver from libchardriver. */ static struct chardriver sht21_tab = { - .cdr_open = do_nop, - .cdr_close = do_nop, - .cdr_ioctl = nop_ioctl, - .cdr_prepare = sht21_prepare, - .cdr_transfer = sht21_transfer, - .cdr_cleanup = nop_cleanup, - .cdr_alarm = nop_alarm, - .cdr_cancel = nop_cancel, - .cdr_select = nop_select, - .cdr_other = sht21_other -}; - -static struct device sht21_device = { - .dv_base = 0, - .dv_size = 0 + .cdr_read = sht21_read, + .cdr_other = sht21_other }; /* @@ -427,17 +412,11 @@ checksum(uint8_t * bytes, int nbytes, uint8_t expected_crc) } } -static struct device * -sht21_prepare(dev_t UNUSED(dev)) -{ - return &sht21_device; -} - -static int -sht21_transfer(endpoint_t endpt, int opcode, u64_t position, - iovec_t * iov, unsigned nr_req, endpoint_t UNUSED(user_endpt), - unsigned int UNUSED(flags)) +static ssize_t +sht21_read(devminor_t UNUSED(minor), u64_t position, endpoint_t endpt, + cp_grant_id_t grant, size_t size, int UNUSED(flags), cdev_id_t UNUSED(id)) { + u64_t dev_size; int bytes, r; r = measure(); @@ -452,48 +431,33 @@ sht21_transfer(endpoint_t endpt, int opcode, u64_t position, log_trace(&log, "%s", buffer); - bytes = strlen(buffer) - position < iov->iov_size ? - strlen(buffer) - position : iov->iov_size; + dev_size = (u64_t)strlen(buffer); + if (position >= dev_size) return 0; + if (position + size > dev_size) + size = (size_t)(dev_size - position); - if (bytes <= 0) { - return OK; - } + r = sys_safecopyto(endpt, grant, 0, + (vir_bytes)(buffer + (size_t)position), size); - switch (opcode) { - case DEV_GATHER_S: - r = sys_safecopyto(endpt, (cp_grant_id_t) iov->iov_addr, 0, - (vir_bytes) (buffer + position), bytes); - iov->iov_size -= bytes; - break; - default: - return EINVAL; - } - - return r; + return (r != OK) ? r : size; } -static int -sht21_other(message * m) +static void +sht21_other(message * m, int ipc_status) { int r; - switch (m->m_type) { - case NOTIFY_MESSAGE: + if (is_ipc_notify(ipc_status)) { if (m->m_source == DS_PROC_NR) { log_debug(&log, "bus driver changed state, update endpoint\n"); i2cdriver_handle_bus_update(&bus_endpoint, bus, address); } - r = OK; - break; - default: - log_warn(&log, "Invalid message type (0x%x)\n", m->m_type); - r = EINVAL; - break; + return; } - return r; + log_warn(&log, "Invalid message type (0x%x)\n", m->m_type); } static int @@ -612,7 +576,7 @@ main(int argc, char *argv[]) sef_local_startup(); - chardriver_task(&sht21_tab, CHARDRIVER_SYNC); + chardriver_task(&sht21_tab); return 0; } diff --git a/drivers/tda19988/tda19988.c b/drivers/tda19988/tda19988.c index 0913936fd..133851744 100644 --- a/drivers/tda19988/tda19988.c +++ b/drivers/tda19988/tda19988.c @@ -163,14 +163,14 @@ static int check_revision(void); static int read_edid(uint8_t * data, size_t count); /* libblockdriver callbacks */ -static int tda19988_blk_open(dev_t minor, int access); -static int tda19988_blk_close(dev_t minor); -static ssize_t tda19988_blk_transfer(dev_t minor, int do_write, u64_t pos, - endpoint_t endpt, iovec_t * iov, unsigned count, int flags); -static int tda19988_blk_ioctl(dev_t minor, unsigned int request, - endpoint_t endpt, cp_grant_id_t grant); -static struct device *tda19988_blk_part(dev_t minor); -static int tda19988_blk_other(message * m); +static int tda19988_blk_open(devminor_t minor, int access); +static int tda19988_blk_close(devminor_t minor); +static ssize_t tda19988_blk_transfer(devminor_t minor, int do_write, u64_t pos, + endpoint_t endpt, iovec_t * iov, unsigned int count, int flags); +static int tda19988_blk_ioctl(devminor_t minor, unsigned long request, + endpoint_t endpt, cp_grant_id_t grant, endpoint_t user_endpt); +static struct device *tda19988_blk_part(devminor_t minor); +static void tda19988_blk_other(message * m, int ipc_status); /* Entry points into the device dependent code of block drivers. */ struct blockdriver tda19988_tab = { @@ -178,14 +178,9 @@ struct blockdriver tda19988_tab = { .bdr_open = tda19988_blk_open, .bdr_close = tda19988_blk_close, .bdr_transfer = tda19988_blk_transfer, - .bdr_ioctl = tda19988_blk_ioctl, /* nop -- always returns EINVAL */ - .bdr_cleanup = NULL, /* nothing allocated -- nothing to clean up */ + .bdr_ioctl = tda19988_blk_ioctl, /* always returns ENOTTY */ .bdr_part = tda19988_blk_part, - .bdr_geometry = NULL, /* no geometry (cylinders, heads, sectors, etc) */ - .bdr_intr = NULL, /* i2c devices don't generate interrupts */ - .bdr_alarm = NULL, /* alarm not needed */ - .bdr_other = tda19988_blk_other, /* to recv notify events from DS */ - .bdr_device = NULL /* 1 insance per device, threads not needed */ + .bdr_other = tda19988_blk_other /* for notify events from DS */ }; /* counts the number of times a device file is open */ @@ -195,7 +190,7 @@ static int openct[NR_DEVS]; static struct device geom[NR_DEVS]; static int -tda19988_blk_open(dev_t minor, int access) +tda19988_blk_open(devminor_t minor, int access) { log_trace(&log, "tda19988_blk_open(%d,%d)\n", minor, access); if (tda19988_blk_part(minor) == NULL) { @@ -208,7 +203,7 @@ tda19988_blk_open(dev_t minor, int access) } static int -tda19988_blk_close(dev_t minor) +tda19988_blk_close(devminor_t minor) { log_trace(&log, "tda19988_blk_close(%d)\n", minor); if (tda19988_blk_part(minor) == NULL) { @@ -225,8 +220,8 @@ tda19988_blk_close(dev_t minor) } static ssize_t -tda19988_blk_transfer(dev_t minor, int do_write, u64_t pos64, - endpoint_t endpt, iovec_t * iov, unsigned nr_req, int flags) +tda19988_blk_transfer(devminor_t minor, int do_write, u64_t pos64, + endpoint_t endpt, iovec_t * iov, unsigned int nr_req, int flags) { unsigned count; struct device *dv; @@ -319,35 +314,32 @@ tda19988_blk_transfer(dev_t minor, int do_write, u64_t pos64, } static int -tda19988_blk_ioctl(dev_t minor, unsigned int request, endpoint_t endpt, - cp_grant_id_t grant) +tda19988_blk_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt, + cp_grant_id_t grant, endpoint_t UNUSED(user_endpt)) { log_trace(&log, "tda19988_blk_ioctl(%d)\n", minor); /* no supported ioctls for this device */ - return EINVAL; + return ENOTTY; } static struct device * -tda19988_blk_part(dev_t minor) +tda19988_blk_part(devminor_t minor) { log_trace(&log, "tda19988_blk_part(%d)\n", minor); - if (minor >= NR_DEVS) { + if (minor < 0 || minor >= NR_DEVS) { return NULL; } return &geom[minor]; } -static int -tda19988_blk_other(message * m) +static void +tda19988_blk_other(message * m, int ipc_status) { - int r; - log_trace(&log, "tda19988_blk_other(0x%x)\n", m->m_type); - switch (m->m_type) { - case NOTIFY_MESSAGE: + if (is_ipc_notify(ipc_status)) { if (m->m_source == DS_PROC_NR) { log_debug(&log, "bus driver changed state, update endpoint\n"); @@ -356,15 +348,9 @@ tda19988_blk_other(message * m) i2cdriver_handle_bus_update(&hdmi_bus_endpoint, hdmi_bus, hdmi_address); } - r = OK; - break; - default: + } else { log_warn(&log, "Invalid message type (0x%x)\n", m->m_type); - r = EINVAL; - break; } - - return r; } /* diff --git a/drivers/tps65217/tps65217.c b/drivers/tps65217/tps65217.c index 63d943f6a..12baa0ea8 100644 --- a/drivers/tps65217/tps65217.c +++ b/drivers/tps65217/tps65217.c @@ -434,7 +434,6 @@ int main(int argc, char *argv[]) { int r; - endpoint_t user, caller; message m; int ipc_status; @@ -485,26 +484,8 @@ main(int argc, char *argv[]) continue; } - caller = m.m_source; - user = m.USER_ENDPT; - - /* - * Handle Message - * - * So far this driver only deals with notifications - * so it always replies to non-notifications with EINVAL. - */ - - /* Send Reply */ - m.m_type = TASK_REPLY; - m.REP_ENDPT = user; - m.REP_STATUS = EINVAL; - - r = sendnb(caller, &m); - if (r != OK) { - log_warn(&log, "sendnb() failed\n"); - continue; - } + log_warn(&log, "Ignoring message 0x%x from 0x%x\n", m.m_type, + m.m_source); } return 0; diff --git a/drivers/tsl2550/tsl2550.c b/drivers/tsl2550/tsl2550.c index 06cc31d7c..15ec996c6 100644 --- a/drivers/tsl2550/tsl2550.c +++ b/drivers/tsl2550/tsl2550.c @@ -69,11 +69,9 @@ static int adc_read(int adc, uint8_t * val); static int measure_lux(uint32_t * lux); /* libchardriver callbacks */ -static struct device *tsl2550_prepare(dev_t UNUSED(dev)); -static int tsl2550_transfer(endpoint_t endpt, int opcode, u64_t position, - iovec_t * iov, unsigned nr_req, endpoint_t UNUSED(user_endpt), - unsigned int UNUSED(flags)); -static int tsl2550_other(message * m); +static ssize_t tsl2550_read(devminor_t minor, u64_t position, endpoint_t endpt, + cp_grant_id_t grant, size_t size, int flags, cdev_id_t id); +static void tsl2550_other(message * m, int ipc_status); /* SEF functions */ static int sef_cb_lu_state_save(int); @@ -83,21 +81,8 @@ static void sef_local_startup(void); /* Entry points to this driver from libchardriver. */ static struct chardriver tsl2550_tab = { - .cdr_open = do_nop, - .cdr_close = do_nop, - .cdr_ioctl = nop_ioctl, - .cdr_prepare = tsl2550_prepare, - .cdr_transfer = tsl2550_transfer, - .cdr_cleanup = nop_cleanup, - .cdr_alarm = nop_alarm, - .cdr_cancel = nop_cancel, - .cdr_select = nop_select, - .cdr_other = tsl2550_other -}; - -static struct device tsl2550_device = { - .dv_base = 0, - .dv_size = 0 + .cdr_read = tsl2550_read, + .cdr_other = tsl2550_other }; /* @@ -379,17 +364,11 @@ tsl2550_init(void) return OK; } -static struct device * -tsl2550_prepare(dev_t UNUSED(dev)) -{ - return &tsl2550_device; -} - -static int -tsl2550_transfer(endpoint_t endpt, int opcode, u64_t position, - iovec_t * iov, unsigned nr_req, endpoint_t UNUSED(user_endpt), - unsigned int UNUSED(flags)) +static ssize_t +tsl2550_read(devminor_t UNUSED(minor), u64_t position, endpoint_t endpt, + cp_grant_id_t grant, size_t size, int UNUSED(flags), cdev_id_t UNUSED(id)) { + u64_t dev_size; int bytes, r; uint32_t lux; @@ -401,48 +380,33 @@ tsl2550_transfer(endpoint_t endpt, int opcode, u64_t position, memset(buffer, '\0', BUFFER_LEN + 1); snprintf(buffer, BUFFER_LEN, "%-16s: %d\n", "ILLUMINANCE", lux); - bytes = strlen(buffer) - position < iov->iov_size ? - strlen(buffer) - position : iov->iov_size; + dev_size = (u64_t)strlen(buffer); + if (position >= dev_size) return 0; + if (position + size > dev_size) + size = (size_t)(dev_size - position); - if (bytes <= 0) { - return OK; - } + r = sys_safecopyto(endpt, grant, 0, + (vir_bytes)(buffer + (size_t)position), size); - switch (opcode) { - case DEV_GATHER_S: - r = sys_safecopyto(endpt, (cp_grant_id_t) iov->iov_addr, 0, - (vir_bytes) (buffer + position), bytes); - iov->iov_size -= bytes; - break; - default: - return EINVAL; - } - - return r; + return (r != OK) ? r : size; } -static int -tsl2550_other(message * m) +static void +tsl2550_other(message * m, int ipc_status) { int r; - switch (m->m_type) { - case NOTIFY_MESSAGE: + if (is_ipc_notify(ipc_status)) { if (m->m_source == DS_PROC_NR) { log_debug(&log, "bus driver changed state, update endpoint\n"); i2cdriver_handle_bus_update(&bus_endpoint, bus, address); } - r = OK; - break; - default: - log_warn(&log, "Invalid message type (0x%x)\n", m->m_type); - r = EINVAL; - break; + return; } - return r; + log_warn(&log, "Invalid message type (0x%x)\n", m->m_type); } static int @@ -561,7 +525,7 @@ main(int argc, char *argv[]) sef_local_startup(); - chardriver_task(&tsl2550_tab, CHARDRIVER_SYNC); + chardriver_task(&tsl2550_tab); return 0; } diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile index 6f0336eac..5575a4ccf 100644 --- a/drivers/tty/Makefile +++ b/drivers/tty/Makefile @@ -6,8 +6,8 @@ PROG= tty SRCS += tty.c pty.c -DPADD+= ${LIBSYS} ${LIBTIMERS} -LDADD+= -lsys -ltimers +DPADD+= ${LIBCHARDRIVER} ${LIBSYS} ${LIBTIMERS} +LDADD+= -lchardriver -lsys -ltimers MAN= diff --git a/drivers/tty/arch/earm/console.c b/drivers/tty/arch/earm/console.c index 3c820bcea..04a5aff34 100644 --- a/drivers/tty/arch/earm/console.c +++ b/drivers/tty/arch/earm/console.c @@ -4,7 +4,7 @@ #include "tty.h" void -do_video(message *m) +do_video(message *m, int ipc_status) { } @@ -19,7 +19,7 @@ cons_stop(void) } int -con_loadfont(message *m) +con_loadfont(endpoint_t endpt, cp_grant_id_t grant) { return 0; } diff --git a/drivers/tty/arch/earm/keyboard.c b/drivers/tty/arch/earm/keyboard.c index 3c6c1e570..cf278378b 100644 --- a/drivers/tty/arch/earm/keyboard.c +++ b/drivers/tty/arch/earm/keyboard.c @@ -19,12 +19,7 @@ do_kb_inject(message *m) } void -do_kbd(message *m) -{ -} - -void -do_kbdaux(message *m) +do_kbd(message *m, int ipc_status) { } @@ -34,13 +29,7 @@ kb_init_once(void) } int -kbd_status(message *m) -{ - return 0; -} - -int -kbd_loadmap(message *m) +kbd_loadmap(endpoint_t endpt, cp_grant_id_t grant) { return 0; } diff --git a/drivers/tty/arch/earm/rs232.c b/drivers/tty/arch/earm/rs232.c index 432d2d9cf..1dd004da7 100644 --- a/drivers/tty/arch/earm/rs232.c +++ b/drivers/tty/arch/earm/rs232.c @@ -239,11 +239,11 @@ rs_write(register tty_t *tp, int try) if (tp->tty_outcaller == KERNEL) { /* We're trying to print on kernel's behalf */ memcpy(rs->ohead, - (void *) tp->tty_outgrant + tp->tty_outoffset, + (char *) tp->tty_outgrant + tp->tty_outcum, count); } else { if ((r = sys_safecopyfrom(tp->tty_outcaller, - tp->tty_outgrant, tp->tty_outoffset, + tp->tty_outgrant, tp->tty_outcum, (vir_bytes) rs->ohead, count)) != OK) { return 0; } @@ -264,31 +264,21 @@ rs_write(register tty_t *tp, int try) rs_ostart(rs); if ((rs->ohead += ocount) >= bufend(rs->obuf)) rs->ohead -= buflen(rs->obuf); - tp->tty_outoffset += count; tp->tty_outcum += count; if ((tp->tty_outleft -= count) == 0) { /* Output is finished, reply to the writer. */ - if(tp->tty_outrepcode == TTY_REVIVE) { - notify(tp->tty_outcaller); - tp->tty_outrevived = 1; - } else { - tty_reply(tp->tty_outrepcode, tp->tty_outcaller, - tp->tty_outproc, tp->tty_outcum); - tp->tty_outcum = 0; - } + chardriver_reply_task(tp->tty_outcaller, tp->tty_outid, + tp->tty_outcum); + tp->tty_outcum = 0; + tp->tty_outcaller = NONE; } } if (tp->tty_outleft > 0 && tp->tty_termios.c_ospeed == B0) { /* Oops, the line has hung up. */ - if(tp->tty_outrepcode == TTY_REVIVE) { - notify(tp->tty_outcaller); - tp->tty_outrevived = 1; - } else { - tty_reply(tp->tty_outrepcode, tp->tty_outcaller, - tp->tty_outproc, EIO); - tp->tty_outleft = tp->tty_outcum = 0; - } + chardriver_reply_task(tp->tty_outcaller, tp->tty_outid, EIO); + tp->tty_outleft = tp->tty_outcum = 0; + tp->tty_outcaller = NONE; } return 1; diff --git a/drivers/tty/arch/i386/console.c b/drivers/tty/arch/i386/console.c index b18b853f4..d8034190c 100644 --- a/drivers/tty/arch/i386/console.c +++ b/drivers/tty/arch/i386/console.c @@ -18,16 +18,10 @@ #include #include -#include #include #include #include #include -#include -#include -#include -#include -#include #include "tty.h" /* Set this to 1 if you want console output duplicated on the first @@ -142,6 +136,18 @@ static void vid_vid_copy(int src, int dst, int count); static void get_6845(int reg, unsigned *val); #endif +static int video_open(devminor_t minor, int access, endpoint_t user_endpt); +static int video_close(devminor_t minor); +static int video_ioctl(devminor_t minor, unsigned long request, + endpoint_t endpt, cp_grant_id_t grant, int flags, + endpoint_t user_endpt, cdev_id_t id); + +static struct chardriver video_tab = { + .cdr_open = video_open, + .cdr_close = video_close, + .cdr_ioctl = video_ioctl +}; + /*===========================================================================* * cons_write * *===========================================================================*/ @@ -174,16 +180,14 @@ int try; if (count > sizeof(buf)) count = sizeof(buf); if (tp->tty_outcaller == KERNEL) { /* We're trying to print on kernel's behalf */ - memcpy(buf, (void *) tp->tty_outgrant + tp->tty_outoffset, - count); + memcpy(buf, (char *) tp->tty_outgrant + tp->tty_outcum, count); } else { if ((result = sys_safecopyfrom(tp->tty_outcaller, - tp->tty_outgrant, tp->tty_outoffset, + tp->tty_outgrant, tp->tty_outcum, (vir_bytes) buf, count)) != OK) { break; } } - tp->tty_outoffset += count; tbuf = buf; /* Update terminal data structure. */ @@ -215,14 +219,10 @@ int try; /* Reply to the writer if all output is finished or if an error occured. */ if (tp->tty_outleft == 0 || result != OK) { - if(tp->tty_outrepcode == TTY_REVIVE) { - notify(tp->tty_outcaller); - tp->tty_outrevived = 1; - } else { - tty_reply(tp->tty_outrepcode, tp->tty_outcaller, - tp->tty_outproc, tp->tty_outcum); - tp->tty_outcum = 0; - } + chardriver_reply_task(tp->tty_outcaller, tp->tty_outid, + result != OK ? result : tp->tty_outcum); + tp->tty_outcum = tp->tty_outleft = 0; + tp->tty_outcaller = NONE; } return 0; @@ -811,82 +811,69 @@ static void beep() } } +/*===========================================================================* + * video_open * + *===========================================================================*/ +static int video_open(devminor_t minor, int UNUSED(access), + endpoint_t UNUSED(user_endpt)) +{ + /* Should grant IOPL */ + disable_console(); + return OK; +} + +/*===========================================================================* + * video_close * + *===========================================================================*/ +static int video_close(devminor_t minor) +{ + reenable_console(); + return OK; +} + +/*===========================================================================* + * video_ioctl * + *===========================================================================*/ +static int video_ioctl(devminor_t minor, unsigned long request, + endpoint_t endpt, cp_grant_id_t grant, int flags, + endpoint_t user_endpt, cdev_id_t id) +{ + struct mapreqvm mapreqvm; + int r, do_map; + + switch (request) { + case TIOCMAPMEM: + case TIOCUNMAPMEM: + do_map = (request == TIOCMAPMEM); /* else unmap */ + + if ((r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &mapreqvm, + sizeof(mapreqvm))) != OK) + return r; + + if (do_map) { + mapreqvm.vaddr_ret = vm_map_phys(user_endpt, + (void *) mapreqvm.phys_offset, mapreqvm.size); + r = sys_safecopyto(endpt, grant, 0, (vir_bytes) &mapreqvm, + sizeof(mapreqvm)); + } else { + r = vm_unmap_phys(user_endpt, mapreqvm.vaddr, mapreqvm.size); + } + + return r; + + default: + return ENOTTY; + } +} /*===========================================================================* * do_video * *===========================================================================*/ -void do_video(message *m) +void do_video(message *m, int ipc_status) { - int r; - - /* Execute the requested device driver function. */ - r= EINVAL; /* just in case */ - switch (m->m_type) { - case DEV_OPEN: - /* Should grant IOPL */ - disable_console(); - r= OK; - break; - case DEV_CLOSE: - reenable_console(); - r= OK; - break; - case DEV_IOCTL_S: - switch(m->TTY_REQUEST) { - case TIOCMAPMEM: - case TIOCUNMAPMEM: { - int r, do_map; - struct mapreqvm mapreqvm; - - do_map= (m->REQUEST == TIOCMAPMEM); /* else unmap */ - - r = sys_safecopyfrom(m->m_source, - (cp_grant_id_t) m->IO_GRANT, 0, - (vir_bytes) &mapreqvm, sizeof(mapreqvm)); - - if (r != OK) - { - printf("tty: sys_safecopyfrom failed\n"); - tty_reply(TASK_REPLY, m->m_source, - m->USER_ENDPT, r); - return; - } - - /* In safe ioctl mode, the POSITION field contains - * the endpt number of the original requestor. - * USER_ENDPT is always FS. - */ - - if(do_map) { - mapreqvm.vaddr_ret = vm_map_phys(m->POSITION, - (void *) mapreqvm.phys_offset, mapreqvm.size); - if((r = sys_safecopyto(m->m_source, - (cp_grant_id_t) m->IO_GRANT, 0, - (vir_bytes) &mapreqvm, - sizeof(mapreqvm))) != OK) { - printf("tty: sys_safecopyto failed\n"); - } - } else { - r = vm_unmap_phys(m->POSITION, - mapreqvm.vaddr, mapreqvm.size); - } - tty_reply(TASK_REPLY, m->m_source, m->USER_ENDPT, r); - return; - } - } - r= ENOTTY; - break; - - default: - printf( - "Warning, TTY(video) got unexpected request %d from %d\n", - m->m_type, m->m_source); - r= EINVAL; - } - tty_reply(TASK_REPLY, m->m_source, m->USER_ENDPT, r); + chardriver_process(&video_tab, m, ipc_status); } - /*===========================================================================* * beep_x * *===========================================================================*/ @@ -1139,12 +1126,11 @@ void select_console(int cons_line) /*===========================================================================* * con_loadfont * *===========================================================================*/ -int con_loadfont(m) -message *m; +int con_loadfont(endpoint_t endpt, cp_grant_id_t grant) { /* Load a font into the EGA or VGA adapter. */ - int result; + int r, r2; static struct sequence seq1[7] = { { GA_SEQUENCER_INDEX, 0x00, 0x01 }, { GA_SEQUENCER_INDEX, 0x02, 0x04 }, @@ -1166,17 +1152,14 @@ message *m; seq2[6].value= color ? 0x0E : 0x0A; - result = ga_program(seq1); /* bring font memory into view */ + r = ga_program(seq1); /* bring font memory into view */ + if (r != OK) return r; - if(sys_safecopyfrom(m->m_source, (cp_grant_id_t) m->IO_GRANT, 0, - (vir_bytes) font_memory, GA_FONT_SIZE) != OK) { - printf("tty: copying from %d failed\n", m->m_source); - return EFAULT; - } + r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) font_memory, GA_FONT_SIZE); - result = ga_program(seq2); /* restore */ + r2 = ga_program(seq2); /* restore */ - return(result); + return(r != OK ? r : r2); } /*===========================================================================* diff --git a/drivers/tty/arch/i386/keyboard.c b/drivers/tty/arch/i386/keyboard.c index fb02ce2a8..60e98378d 100644 --- a/drivers/tty/arch/i386/keyboard.c +++ b/drivers/tty/arch/i386/keyboard.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "tty.h" #include "kernel/const.h" #include "kernel/config.h" @@ -122,18 +123,17 @@ static obs_t sfkey_obs[12]; /* observers for SHIFT F1-F12 */ static struct kbd { - int minor; + devminor_t minor; int nr_open; char buf[KBD_BUFSZ]; int offset; int avail; - int req_size; - int req_proc; + size_t req_size; + cdev_id_t req_id; cp_grant_id_t req_grant; - vir_bytes req_addr_offset; - int incaller; - int select_ops; - int select_proc; + endpoint_t req_caller; + unsigned int select_ops; + endpoint_t select_proc; } kbd, kbdaux; /* Data that is to be sent to the keyboard. Each byte is ACKed by the @@ -153,8 +153,6 @@ static long sticky_alt_mode = 0; static long debug_fkeys = 1; static timer_t tmr_kbd_wd; -static void handle_req(struct kbd *kbdp, message *m); -static int handle_status(struct kbd *kbdp, message *m); static void kbc_cmd0(int cmd); static void kbc_cmd1(int cmd, int data); static int kbc_read(void); @@ -170,278 +168,285 @@ static int kb_read(struct tty *tp, int try); static unsigned map_key(int scode); static void kbd_watchdog(timer_t *tmrp); -int micro_delay(u32_t usecs) +static int kbd_open(devminor_t minor, int access, endpoint_t user_endpt); +static int kbd_close(devminor_t minor); +static ssize_t kbd_read(devminor_t minor, u64_t position, endpoint_t endpt, + cp_grant_id_t grant, size_t size, int flags, cdev_id_t id); +static ssize_t kbd_write(devminor_t minor, u64_t position, endpoint_t endpt, + cp_grant_id_t grant, size_t size, int flags, cdev_id_t id); +static int kbd_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt, + cp_grant_id_t grant, int flags, endpoint_t user_endpt, cdev_id_t id); +static int kbd_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id); +static int kbd_select(devminor_t minor, unsigned int ops, endpoint_t endpt); + +static struct chardriver kbd_tab = { + .cdr_open = kbd_open, + .cdr_close = kbd_close, + .cdr_read = kbd_read, + .cdr_write = kbd_write, + .cdr_ioctl = kbd_ioctl, + .cdr_cancel = kbd_cancel, + .cdr_select = kbd_select +}; + +/*===========================================================================* + * line2kbd * + *===========================================================================*/ +static struct kbd * +line2kbd(devminor_t minor) { - /* TTY can't use the library micro_delay() as that calls PM. */ - tickdelay(micros_to_ticks(usecs)); + switch (minor) { + case KBD_MINOR: return &kbd; + case KBDAUX_MINOR: return &kbdaux; + default: return NULL; + } +} + +/*===========================================================================* + * kbd_open * + *===========================================================================*/ +static int +kbd_open(devminor_t minor, int UNUSED(access), endpoint_t UNUSED(user_endpt)) +{ + struct kbd *kbdp; + + if ((kbdp = line2kbd(minor)) == NULL) + return ENXIO; + + kbdp->nr_open++; return OK; } +/*===========================================================================* + * kbd_close * + *===========================================================================*/ +static int +kbd_close(devminor_t minor) +{ + struct kbd *kbdp; + + if ((kbdp = line2kbd(minor)) == NULL) + return ENXIO; + + kbdp->nr_open--; + if (kbdp->nr_open < 0) { + printf("TTY(kbd): open count is negative\n"); + kbdp->nr_open= 0; + } + if (kbdp->nr_open == 0) + kbdp->avail= 0; + + return OK; +} + +/*===========================================================================* + * kbd_read * + *===========================================================================*/ +static ssize_t +kbd_read(devminor_t minor, u64_t UNUSED(position), endpoint_t endpt, + cp_grant_id_t grant, size_t size, int flags, cdev_id_t id) +{ + ssize_t n, r; + struct kbd *kbdp; + + if ((kbdp = line2kbd(minor)) == NULL) + return ENXIO; + + /* We handle only one request at a time. */ + if (kbdp->req_size) + return EIO; + + if ((ssize_t) size <= 0) + return EINVAL; + + /* If no data is available, suspend the caller. */ + if (kbdp->avail == 0) { + if (flags & CDEV_NONBLOCK) + return EAGAIN; + kbdp->req_size = size; + kbdp->req_id = id; + kbdp->req_grant = grant; + kbdp->req_caller = endpt; + return EDONTREPLY; + } + + /* Handle read request. */ + n = kbdp->avail; + if (n > (ssize_t) size) + n = size; + if (kbdp->offset + n > KBD_BUFSZ) + n = KBD_BUFSZ - kbdp->offset; + if (n <= 0) + panic("do_kbd(READ): bad n: %d", n); + r = sys_safecopyto(endpt, grant, 0, + (vir_bytes) &kbdp->buf[kbdp->offset], n); + if (r == OK) { + kbdp->offset = (kbdp->offset + n) % KBD_BUFSZ; + kbdp->avail -= n; + r = n; + } else + printf("TTY(kbd): copy in read kbd failed: %d\n", r); + + return r; +} + +/*===========================================================================* + * kbd_write * + *===========================================================================*/ +static ssize_t +kbd_write(devminor_t minor, u64_t UNUSED(position), endpoint_t endpt, + cp_grant_id_t grant, size_t size, int flags, cdev_id_t id) +{ + struct kbd *kbdp; + unsigned char c; + size_t i; + int r; + + if ((kbdp = line2kbd(minor)) == NULL) + return ENXIO; + if (kbdp != &kbdaux) { + printf("TTY(kbd): write to keyboard not implemented\n"); + return EINVAL; + } + + /* + * Assume that output to AUX only happens during initialization and we + * can afford to lose input. This should be fixed at a later time. + */ + for (i = 0; i < size; i++) { + r = sys_safecopyfrom(endpt, grant, i, (vir_bytes) &c, 1); + if (r != OK) + return i ? i : r; + kbc_cmd1(KBC_WRITE_AUX, c); + } + + return r; +} + +/*===========================================================================* + * kbd_ioctl * + *===========================================================================*/ +static int +kbd_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt, + cp_grant_id_t grant, int flags, endpoint_t UNUSED(user_endpt), + cdev_id_t id) +{ + struct kbd *kbdp; + kio_leds_t leds; + kio_bell_t bell; + clock_t ticks; + unsigned char b; + int r; + + if ((kbdp = line2kbd(minor)) == NULL) + return ENXIO; + if (kbdp != &kbd) + return ENOTTY; /* we only support ioctls on keyboards now */ + + switch (request) { + case KIOCSLEDS: + r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &leds, + sizeof(leds)); + if (r != OK) + return r; + + b = 0; + if (leds.kl_bits & KBD_LEDS_NUM) b |= NUM_LOCK; + if (leds.kl_bits & KBD_LEDS_CAPS) b |= CAPS_LOCK; + if (leds.kl_bits & KBD_LEDS_SCROLL) b |= SCROLL_LOCK; + if (kbdout.avail == 0) + kbdout.offset = 0; + if (kbdout.offset + kbdout.avail + 2 > KBD_OUT_BUFSZ) { + /* Output buffer is full. Ignore this command. + * Reset ACK flag. + */ + kbdout.expect_ack = 0; + } else { + kbdout.buf[kbdout.offset+kbdout.avail] = LED_CODE; + kbdout.buf[kbdout.offset+kbdout.avail+1] = b; + kbdout.avail += 2; + } + if (!kbdout.expect_ack) + kbd_send(); + + return OK; + + case KIOCBELL: + r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &bell, + sizeof(bell)); + if (r != OK) + return r; + + ticks = bell.kb_duration.tv_usec * system_hz / 1000000; + ticks += bell.kb_duration.tv_sec * system_hz; + if (!ticks) + ticks++; + beep_x(bell.kb_pitch, ticks); + + return OK; + + default: + return ENOTTY; + } +} + +/*===========================================================================* + * kbd_cancel * + *===========================================================================*/ +static int +kbd_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id) +{ + struct kbd *kbdp; + + if ((kbdp = line2kbd(minor)) == NULL) + return ENXIO; + + if (kbdp->req_size > 0 && endpt == kbdp->req_caller && + id == kbdp->req_id) + return EINTR; + + return EDONTREPLY; +} + +/*===========================================================================* + * kbd_select * + *===========================================================================*/ +static int +kbd_select(devminor_t minor, unsigned int ops, endpoint_t endpt) +{ + struct kbd *kbdp; + int watch, ready_ops; + + if ((kbdp = line2kbd(minor)) == NULL) + return ENXIO; + + watch = (ops & CDEV_NOTIFY); + ops &= (CDEV_OP_RD | CDEV_OP_WR | CDEV_OP_ERR); + + ready_ops = 0; + if (kbdp->avail && (ops & CDEV_OP_RD)) + ready_ops |= CDEV_OP_RD; + if (ops & CDEV_OP_WR) + ready_ops |= CDEV_OP_WR; /* writes never block */ + + ops &= ~ready_ops; + if (ops && watch) { + kbdp->select_ops |= ops; + kbdp->select_proc = endpt; + } + + return ready_ops; +} + /*===========================================================================* * do_kbd * *===========================================================================*/ -void do_kbd(message *m) +void +do_kbd(message *m, int ipc_status) { - handle_req(&kbd, m); + chardriver_process(&kbd_tab, m, ipc_status); } - -/*===========================================================================* - * kbd_status * - *===========================================================================*/ -int kbd_status(message *m) -{ - int r; - - r= handle_status(&kbd, m); - if (r) - return r; - return handle_status(&kbdaux, m); -} - - -/*===========================================================================* - * do_kbdaux * - *===========================================================================*/ -void do_kbdaux(message *m) -{ - handle_req(&kbdaux, m); -} - - -/*===========================================================================* - * handle_req * - *===========================================================================*/ -static void handle_req(kbdp, m) -struct kbd *kbdp; -message *m; -{ - int i, n, r, ops, watch; - unsigned char c; - - /* Execute the requested device driver function. */ - r= EINVAL; /* just in case */ - switch (m->m_type) { - case DEV_OPEN: - kbdp->nr_open++; - r= OK; - break; - case DEV_CLOSE: - kbdp->nr_open--; - if (kbdp->nr_open < 0) - { - printf("TTY(kbd): open count is negative\n"); - kbdp->nr_open= 0; - } - if (kbdp->nr_open == 0) - kbdp->avail= 0; - r= OK; - break; - case DEV_READ_S: - if (kbdp->req_size) - { - /* We handle only request at a time */ - r= EIO; - break; - } - if (kbdp->avail == 0) - { - /* Should record proc */ - kbdp->req_size= m->COUNT; - kbdp->req_proc= m->USER_ENDPT; - kbdp->req_grant= (cp_grant_id_t) m->IO_GRANT; - kbdp->req_addr_offset= 0; - kbdp->incaller= m->m_source; - r= SUSPEND; - break; - } - - /* Handle read request */ - n= kbdp->avail; - if (n > m->COUNT) - n= m->COUNT; - if (kbdp->offset + n > KBD_BUFSZ) - n= KBD_BUFSZ-kbdp->offset; - if (n <= 0) - panic("do_kbd(READ): bad n: %d", n); - r= sys_safecopyto(m->m_source, (cp_grant_id_t) m->IO_GRANT, 0, - (vir_bytes) &kbdp->buf[kbdp->offset], n); - if (r == OK) - { - kbdp->offset= (kbdp->offset+n) % KBD_BUFSZ; - kbdp->avail -= n; - r= n; - } else { - printf("copy in read kbd failed: %d\n", r); - } - - break; - - case DEV_WRITE_S: - if (kbdp != &kbdaux) - { - printf("write to keyboard not implemented\n"); - r= EINVAL; - break; - } - - /* Assume that output to AUX only happens during - * initialization and we can afford to lose input. This should - * be fixed at a later time. - */ - for (i= 0; iCOUNT; i++) - { - r= sys_safecopyfrom(m->m_source, (cp_grant_id_t) - m->IO_GRANT, i, (vir_bytes) &c, 1); - if (r != OK) - break; - kbc_cmd1(KBC_WRITE_AUX, c); - } - r= i; - break; - - case CANCEL: - kbdp->req_size= 0; - r= OK; - break; - case DEV_SELECT: - ops = m->USER_ENDPT & (SEL_RD|SEL_WR|SEL_ERR); - watch = (m->USER_ENDPT & SEL_NOTIFY) ? 1 : 0; - - r= 0; - if (kbdp->avail && (ops & SEL_RD)) - { - r |= SEL_RD; - break; - } - - if (ops && watch) - { - kbdp->select_ops |= ops; - kbdp->select_proc= m->m_source; - } - break; - case DEV_IOCTL_S: - if (kbdp == &kbd && m->TTY_REQUEST == KIOCSLEDS) - { - kio_leds_t leds; - unsigned char b; - - - r= sys_safecopyfrom(m->m_source, (cp_grant_id_t) - m->IO_GRANT, 0, (vir_bytes) &leds, - sizeof(leds)); - if (r != OK) - break; - b= 0; - if (leds.kl_bits & KBD_LEDS_NUM) b |= NUM_LOCK; - if (leds.kl_bits & KBD_LEDS_CAPS) b |= CAPS_LOCK; - if (leds.kl_bits & KBD_LEDS_SCROLL) b |= SCROLL_LOCK; - if (kbdout.avail == 0) - kbdout.offset= 0; - if (kbdout.offset + kbdout.avail + 2 > KBD_OUT_BUFSZ) - { - /* Output buffer is full. Ignore this command. - * Reset ACK flag. - */ - kbdout.expect_ack= 0; - } - else - { - kbdout.buf[kbdout.offset+kbdout.avail]= - LED_CODE; - kbdout.buf[kbdout.offset+kbdout.avail+1]= b; - kbdout.avail += 2; - } - if (!kbdout.expect_ack) - kbd_send(); - r= OK; - break; - } - if (kbdp == &kbd && m->TTY_REQUEST == KIOCBELL) - { - kio_bell_t bell; - clock_t ticks; - - r = sys_safecopyfrom(m->m_source, (cp_grant_id_t) - m->IO_GRANT, 0, (vir_bytes) &bell, - sizeof(bell)); - if (r != OK) - break; - - ticks= bell.kb_duration.tv_usec * system_hz / 1000000; - ticks += bell.kb_duration.tv_sec * system_hz; - if (!ticks) - ticks++; - beep_x(bell.kb_pitch, ticks); - - r= OK; - break; - } - r= ENOTTY; - break; - - default: - printf("Warning, TTY(kbd) got unexpected request %d from %d\n", - m->m_type, m->m_source); - r= EINVAL; - } - tty_reply(TASK_REPLY, m->m_source, m->USER_ENDPT, r); -} - - -/*===========================================================================* - * handle_status * - *===========================================================================*/ -static int handle_status(kbdp, m) -struct kbd *kbdp; -message *m; -{ - int n, r; - - if (kbdp->avail && kbdp->req_size && m->m_source == kbdp->incaller && - kbdp->req_grant != GRANT_INVALID) - { - /* Handle read request */ - n= kbdp->avail; - if (n > kbdp->req_size) - n= kbdp->req_size; - if (kbdp->offset + n > KBD_BUFSZ) - n= KBD_BUFSZ-kbdp->offset; - if (n <= 0) - panic("kbd_status: bad n: %d", n); - kbdp->req_size= 0; - r= sys_safecopyto(kbdp->incaller, kbdp->req_grant, 0, - (vir_bytes)&kbdp->buf[kbdp->offset], n); - if (r == OK) - { - kbdp->offset= (kbdp->offset+n) % KBD_BUFSZ; - kbdp->avail -= n; - r= n; - } else printf("copy in revive kbd failed: %d\n", r); - - m->m_type = DEV_REVIVE; - m->REP_ENDPT= kbdp->req_proc; - m->REP_IO_GRANT= kbdp->req_grant; - m->REP_STATUS= r; - kbdp->req_grant = GRANT_INVALID; - return 1; - } - if (kbdp->avail && (kbdp->select_ops & SEL_RD) && - m->m_source == kbdp->select_proc) - { - m->m_type = DEV_IO_READY; - m->DEV_MINOR = kbdp->minor; - m->DEV_SEL_OPS = SEL_RD; - - kbdp->select_ops &= ~SEL_RD; - return 1; - } - - return 0; -} - - /*===========================================================================* * map_key * *===========================================================================*/ @@ -486,7 +491,7 @@ int scode; void kbd_interrupt(message *UNUSED(m_ptr)) { /* A keyboard interrupt has occurred. Process it. */ - int o, isaux; + int n, r, o, isaux; unsigned char scode; struct kbd *kbdp; @@ -512,15 +517,38 @@ void kbd_interrupt(message *UNUSED(m_ptr)) #endif return; /* Buffer is full */ } - o= (kbdp->offset + kbdp->avail) % KBD_BUFSZ; - kbdp->buf[o]= scode; - kbdp->avail++; - if (kbdp->req_size) { - notify(kbdp->incaller); - } - if (kbdp->select_ops & SEL_RD) - notify(kbdp->select_proc); - return; + o= (kbdp->offset + kbdp->avail) % KBD_BUFSZ; + kbdp->buf[o]= scode; + kbdp->avail++; + if (kbdp->req_size) { + /* Reply to read request */ + n= kbdp->avail; + if (n > kbdp->req_size) + n= kbdp->req_size; + if (kbdp->offset + n > KBD_BUFSZ) + n= KBD_BUFSZ-kbdp->offset; + if (n <= 0) + panic("kbd_interrupt: bad n: %d", n); + kbdp->req_size= 0; + r= sys_safecopyto(kbdp->req_caller, kbdp->req_grant, 0, + (vir_bytes)&kbdp->buf[kbdp->offset], n); + if (r == OK) + { + kbdp->offset= (kbdp->offset+n) % KBD_BUFSZ; + kbdp->avail -= n; + r= n; + } else printf("copy in revive kbd failed: %d\n", r); + + chardriver_reply_task(kbdp->req_caller, kbdp->req_id, r); + kbdp->req_caller = NONE; + } + /* Only satisfy pending select if characters weren't just read. */ + if (kbdp->avail && (kbdp->select_ops & CDEV_OP_RD)) { + chardriver_reply_select(kbdp->select_proc, kbdp->minor, + CDEV_OP_RD); + kbdp->select_ops &= ~CDEV_OP_RD; + } + return; } /* Store the scancode in memory so the task can get at it later. */ @@ -529,7 +557,7 @@ void kbd_interrupt(message *UNUSED(m_ptr)) if (ihead == ibuf + KB_IN_BYTES) ihead = ibuf; icount++; tty_table[ccurrent].tty_events = 1; - if (tty_table[ccurrent].tty_select_ops & SEL_RD) { + if (tty_table[ccurrent].tty_select_ops & CDEV_OP_RD) { select_retry(&tty_table[ccurrent]); } } @@ -553,7 +581,7 @@ void do_kb_inject(message *msg) if (injhead == injbuf + KB_IN_BYTES) injhead = injbuf; injcount++; tty_table[ccurrent].tty_events = 1; - if (tty_table[ccurrent].tty_select_ops & SEL_RD) { + if (tty_table[ccurrent].tty_select_ops & CDEV_OP_RD) { select_retry(&tty_table[ccurrent]); } } @@ -1055,12 +1083,10 @@ void kb_init_once(void) /*===========================================================================* * kbd_loadmap * *===========================================================================*/ -int kbd_loadmap(m) -message *m; +int kbd_loadmap(endpoint_t endpt, cp_grant_id_t grant) { /* Load a new keymap. */ - return sys_safecopyfrom(m->m_source, (cp_grant_id_t) m->IO_GRANT, - 0, (vir_bytes) keymap, (vir_bytes) sizeof(keymap)); + return sys_safecopyfrom(endpt, grant, 0, (vir_bytes) keymap, sizeof(keymap)); } /*===========================================================================* diff --git a/drivers/tty/arch/i386/rs232.c b/drivers/tty/arch/i386/rs232.c index d7b2472dd..9fe52d2ab 100644 --- a/drivers/tty/arch/i386/rs232.c +++ b/drivers/tty/arch/i386/rs232.c @@ -246,10 +246,11 @@ static int rs_write(register tty_t *tp, int try) /* Copy from user space to the RS232 output buffer. */ if (tp->tty_outcaller == KERNEL) { /* We're trying to print on kernel's behalf */ - memcpy(rs->ohead, (void *) tp->tty_outgrant + tp->tty_outoffset, count); + memcpy(rs->ohead, (char *) tp->tty_outgrant + tp->tty_outcum, + count); } else { if ((r = sys_safecopyfrom(tp->tty_outcaller, tp->tty_outgrant, - tp->tty_outoffset, (vir_bytes) rs->ohead, count)) != OK) + tp->tty_outcum, (vir_bytes) rs->ohead, count)) != OK) printf("TTY: sys_safecopyfrom() failed: %d", r); } @@ -265,30 +266,20 @@ static int rs_write(register tty_t *tp, int try) rs_ostart(rs); if ((rs->ohead += ocount) >= bufend(rs->obuf)) rs->ohead -= buflen(rs->obuf); - tp->tty_outoffset += count; tp->tty_outcum += count; if ((tp->tty_outleft -= count) == 0) { /* Output is finished, reply to the writer. */ - if(tp->tty_outrepcode == TTY_REVIVE) { - notify(tp->tty_outcaller); - tp->tty_outrevived = 1; - } else { - tty_reply(tp->tty_outrepcode, tp->tty_outcaller, - tp->tty_outproc, tp->tty_outcum); - tp->tty_outcum = 0; - } + chardriver_reply_task(tp->tty_outcaller, tp->tty_outid, + tp->tty_outcum); + tp->tty_outcum = 0; + tp->tty_outcaller = NONE; } } if (tp->tty_outleft > 0 && tp->tty_termios.c_ospeed == B0) { /* Oops, the line has hung up. */ - if(tp->tty_outrepcode == TTY_REVIVE) { - notify(tp->tty_outcaller); - tp->tty_outrevived = 1; - } else { - tty_reply(tp->tty_outrepcode, tp->tty_outcaller, - tp->tty_outproc, EIO); - tp->tty_outleft = tp->tty_outcum = 0; - } + chardriver_reply_task(tp->tty_outcaller, tp->tty_outid, EIO); + tp->tty_outleft = tp->tty_outcum = 0; + tp->tty_outcaller = NONE; } return 1; diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 72e4724eb..2a16fd074 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -9,20 +9,16 @@ * This file takes care of copying data between the tty/pty device pairs and * the open/read/write/close calls on the pty devices. The TTY task takes * care of the input and output processing (interrupt, backspace, raw I/O, - * etc.) using the pty_read() and pty_write() functions as the "keyboard" and - * "screen" functions of the ttypX devices. + * etc.) using the pty_slave_read() and pty_slave_write() functions as the + * "keyboard" and "screen" functions of the ttypX devices. * Be careful when reading this code, the terms "reading" and "writing" are - * used both for the tty and the pty end of the pseudo tty. Writes to one - * end are to be read at the other end and vice-versa. + * used both for the tty (slave) and the pty (master) end of the pseudo tty. + * Writes to one end are to be read at the other end and vice-versa. */ #include -#include #include #include -#include -#include -#include #include "tty.h" #if NR_PTYS > 0 @@ -32,23 +28,19 @@ typedef struct pty { tty_t *tty; /* associated TTY structure */ char state; /* flags: busy, closed, ... */ - /* Read call on /dev/ptypX. */ - char rdsendreply; /* send a reply (instead of notify) */ - int rdcaller; /* process making the call (usually FS) */ - int rdproc; /* process that wants to read from the pty */ - cp_grant_id_t rdgrant; /* grant for readers address space */ - vir_bytes rdoffset; /* offset in above grant */ - int rdleft; /* # bytes yet to be read */ - int rdcum; /* # bytes written so far */ + /* Read call on master (/dev/ptypX). */ + endpoint_t rdcaller; /* process making the call, or NONE if none */ + cdev_id_t rdid; /* ID of suspended read request */ + cp_grant_id_t rdgrant; /* grant for reader's address space */ + size_t rdleft; /* # bytes yet to be read */ + size_t rdcum; /* # bytes written so far */ - /* Write call to /dev/ptypX. */ - char wrsendreply; /* send a reply (instead of notify) */ - int wrcaller; /* process making the call (usually FS) */ - int wrproc; /* process that wants to write to the pty */ - cp_grant_id_t wrgrant; /* grant for writers address space */ - vir_bytes wroffset; /* offset in above grant */ - int wrleft; /* # bytes yet to be written */ - int wrcum; /* # bytes written so far */ + /* Write call to master (/dev/ptypX). */ + endpoint_t wrcaller; /* process making the call, or NONE if none*/ + cdev_id_t wrid; /* ID of suspended write request */ + cp_grant_id_t wrgrant; /* grant for writer's address space */ + size_t wrleft; /* # bytes yet to be written */ + size_t wrcum; /* # bytes written so far */ /* Output buffer. */ int ocount; /* # characters in the buffer */ @@ -56,157 +48,299 @@ typedef struct pty { char obuf[2048]; /* buffer for bytes going to the pty reader */ /* select() data. */ - int select_ops, /* Which operations do we want to know about? */ - select_proc, /* Who wants to know about it? */ - select_ready_ops; /* For callback. */ + unsigned int select_ops; /* Which operations do we want to know about? */ + endpoint_t select_proc; /* Who wants to know about it? */ } pty_t; -#define PTY_ACTIVE 0x01 /* pty is open/active */ -#define TTY_CLOSED 0x02 /* tty side has closed down */ -#define PTY_CLOSED 0x04 /* pty side has closed down */ +#define TTY_ACTIVE 0x01 /* tty is open/active */ +#define PTY_ACTIVE 0x02 /* pty is open/active */ +#define TTY_CLOSED 0x04 /* tty side has closed down */ +#define PTY_CLOSED 0x08 /* pty side has closed down */ static pty_t pty_table[NR_PTYS]; /* PTY bookkeeping */ -static int pty_write(tty_t *tp, int try); -static void pty_echo(tty_t *tp, int c); static void pty_start(pty_t *pp); static void pty_finish(pty_t *pp); -static int pty_read(tty_t *tp, int try); -static int pty_close(tty_t *tp, int try); -static int pty_icancel(tty_t *tp, int try); -static int pty_ocancel(tty_t *tp, int try); -static int pty_select(tty_t *tp, message *m); + +static int pty_master_open(devminor_t minor, int access, + endpoint_t user_endpt); +static int pty_master_close(devminor_t minor); +static ssize_t pty_master_read(devminor_t minor, u64_t position, + endpoint_t endpt, cp_grant_id_t grant, size_t size, int flags, + cdev_id_t id); +static ssize_t pty_master_write(devminor_t minor, u64_t position, + endpoint_t endpt, cp_grant_id_t grant, size_t size, int flags, + cdev_id_t id); +static int pty_master_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id); +static int pty_master_select(devminor_t minor, unsigned int ops, + endpoint_t endpt); + +static struct chardriver pty_master_tab = { + .cdr_open = pty_master_open, + .cdr_close = pty_master_close, + .cdr_read = pty_master_read, + .cdr_write = pty_master_write, + .cdr_cancel = pty_master_cancel, + .cdr_select = pty_master_select +}; + +/*===========================================================================* + * pty_master_open * + *===========================================================================*/ +static int pty_master_open(devminor_t minor, int UNUSED(access), + endpoint_t UNUSED(user_endpt)) +{ + tty_t *tp; + pty_t *pp; + + if ((tp = line2tty(minor)) == NULL) + return ENXIO; + pp = tp->tty_priv; + + if (pp->state & PTY_ACTIVE) + return EIO; + + pp->state |= PTY_ACTIVE; + pp->rdcum = 0; + pp->wrcum = 0; + + return OK; +} + +/*===========================================================================* + * pty_master_close * + *===========================================================================*/ +static int pty_master_close(devminor_t minor) +{ + tty_t *tp; + pty_t *pp; + + if ((tp = line2tty(minor)) == NULL) + return ENXIO; + pp = tp->tty_priv; + + if ((pp->state & (TTY_ACTIVE | TTY_CLOSED)) != TTY_ACTIVE) { + pp->state = 0; + } else { + pp->state |= PTY_CLOSED; + sigchar(tp, SIGHUP, 1); + } + + return OK; +} + +/*===========================================================================* + * pty_master_read * + *===========================================================================*/ +static ssize_t pty_master_read(devminor_t minor, u64_t UNUSED(position), + endpoint_t endpt, cp_grant_id_t grant, size_t size, int flags, + cdev_id_t id) +{ + tty_t *tp; + pty_t *pp; + ssize_t r; + + if ((tp = line2tty(minor)) == NULL) + return ENXIO; + pp = tp->tty_priv; + + /* Check, store information on the reader, do I/O. */ + if (pp->state & TTY_CLOSED) + return 0; /* EOF */ + + if (pp->rdcaller != NONE || pp->rdleft != 0 || pp->rdcum != 0) + return EIO; + + if (size <= 0) + return EINVAL; + + pp->rdcaller = endpt; + pp->rdid = id; + pp->rdgrant = grant; + pp->rdleft = size; + pty_start(pp); + + handle_events(tp); + + if (pp->rdleft == 0) { + pp->rdcaller = NONE; + return EDONTREPLY; /* already done */ + } + + if (flags & CDEV_NONBLOCK) { + r = pp->rdcum > 0 ? pp->rdcum : EAGAIN; + pp->rdleft = pp->rdcum = 0; + pp->rdcaller = NONE; + return r; + } + + return EDONTREPLY; /* do suspend */ +} + +/*===========================================================================* + * pty_master_write * + *===========================================================================*/ +static ssize_t pty_master_write(devminor_t minor, u64_t UNUSED(position), + endpoint_t endpt, cp_grant_id_t grant, size_t size, int flags, + cdev_id_t id) +{ + tty_t *tp; + pty_t *pp; + ssize_t r; + + if ((tp = line2tty(minor)) == NULL) + return ENXIO; + pp = tp->tty_priv; + + /* Check, store information on the writer, do I/O. */ + if (pp->state & TTY_CLOSED) + return EIO; + + if (pp->wrcaller != NONE || pp->wrleft != 0 || pp->wrcum != 0) + return EIO; + + if (size <= 0) + return EINVAL; + + pp->wrcaller = endpt; + pp->wrid = id; + pp->wrgrant = grant; + pp->wrleft = size; + + handle_events(tp); + + if (pp->wrleft == 0) { + pp->wrcaller = NONE; + return EDONTREPLY; /* already done */ + } + + if (flags & CDEV_NONBLOCK) { + r = pp->wrcum > 0 ? pp->wrcum : EAGAIN; + pp->wrleft = pp->wrcum = 0; + pp->wrcaller = NONE; + return r; + } + + return EDONTREPLY; /* do suspend */ +} + +/*===========================================================================* + * pty_master_cancel * + *===========================================================================*/ +static int pty_master_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id) +{ + tty_t *tp; + pty_t *pp; + int r; + + if ((tp = line2tty(minor)) == NULL) + return ENXIO; + pp = tp->tty_priv; + + if (pp->rdcaller == endpt && pp->rdid == id) { + /* Cancel a read from a PTY. */ + r = pp->rdcum > 0 ? pp->rdcum : EINTR; + pp->rdleft = pp->rdcum = 0; + pp->rdcaller = NONE; + return r; + } + + if (pp->wrcaller == endpt && pp->wrid == id) { + /* Cancel a write to a PTY. */ + r = pp->wrcum > 0 ? pp->wrcum : EINTR; + pp->wrleft = pp->wrcum = 0; + pp->wrcaller = NONE; + return r; + } + + /* Request not found. */ + return EDONTREPLY; +} + +/*===========================================================================* + * select_try_pty * + *===========================================================================*/ +static int select_try_pty(tty_t *tp, int ops) +{ + pty_t *pp = tp->tty_priv; + int r = 0; + + if (ops & CDEV_OP_WR) { + /* Write won't block on error. */ + if (pp->state & TTY_CLOSED) r |= CDEV_OP_WR; + else if (pp->wrleft != 0 || pp->wrcum != 0) r |= CDEV_OP_WR; + else if (tp->tty_inleft > 0) r |= CDEV_OP_WR; /* There's a reader. */ + } + + if (ops & CDEV_OP_RD) { + /* Read won't block on error. */ + if (pp->state & TTY_CLOSED) r |= CDEV_OP_RD; + else if (pp->rdleft != 0 || pp->rdcum != 0) r |= CDEV_OP_RD; + else if (pp->ocount > 0) r |= CDEV_OP_RD; /* Actual data. */ + } + + return r; +} + +/*===========================================================================* + * select_retry_pty * + *===========================================================================*/ +void select_retry_pty(tty_t *tp) +{ + pty_t *pp = tp->tty_priv; + devminor_t minor; + int r; + + /* See if the pty side of a pty is ready to return a select. */ + if (pp->select_ops && (r = select_try_pty(tp, pp->select_ops))) { + minor = PTYPX_MINOR + (int) (pp - pty_table); + chardriver_reply_select(pp->select_proc, minor, r); + pp->select_ops &= ~r; + } +} + +/*===========================================================================* + * pty_master_select * + *===========================================================================*/ +static int pty_master_select(devminor_t minor, unsigned int ops, + endpoint_t endpt) +{ + tty_t *tp; + pty_t *pp; + int ready_ops, watch; + + if ((tp = line2tty(minor)) == NULL) + return ENXIO; + pp = tp->tty_priv; + + watch = (ops & CDEV_NOTIFY); + ops &= (CDEV_OP_RD | CDEV_OP_WR | CDEV_OP_ERR); + + ready_ops = select_try_pty(tp, ops); + + ops &= ~ready_ops; + if (ops && watch) { + pp->select_ops |= ops; + pp->select_proc = endpt; + } + + return ready_ops; +} /*===========================================================================* * do_pty * *===========================================================================*/ -void do_pty(tty_t *tp, message *m_ptr) +void do_pty(message *m_ptr, int ipc_status) { -/* Perform an open/close/read/write call on a /dev/ptypX device. */ - pty_t *pp = tp->tty_priv; - int r; +/* Process a request for a PTY master (/dev/ptypX) device. */ - switch (m_ptr->m_type) { - case DEV_READ_S: - /* Check, store information on the reader, do I/O. */ - if (pp->state & TTY_CLOSED) { - r = 0; - break; - } - if (pp->rdleft != 0 || pp->rdcum != 0) { - r = EIO; - break; - } - if (m_ptr->COUNT <= 0) { - r = EINVAL; - break; - } - if (pp->rdgrant != GRANT_INVALID) { - r = ENOBUFS; - break; - } - pp->rdsendreply = TRUE; - pp->rdcaller = m_ptr->m_source; - pp->rdproc = m_ptr->USER_ENDPT; - pp->rdgrant = (cp_grant_id_t) m_ptr->IO_GRANT; - pp->rdoffset = 0; - pp->rdleft = m_ptr->COUNT; - pty_start(pp); - handle_events(tp); - if (pp->rdleft == 0) { - pp->rdgrant = GRANT_INVALID; - return; /* already done */ - } - - { - r = SUSPEND; /* do suspend */ - pp->rdsendreply = FALSE; - } - break; - - case DEV_WRITE_S: - /* Check, store information on the writer, do I/O. */ - if (pp->state & TTY_CLOSED) { - r = EIO; - break; - } - if (pp->wrleft != 0 || pp->wrcum != 0) { - r = EIO; - break; - } - if (m_ptr->COUNT <= 0) { - r = EINVAL; - break; - } - if (pp->wrgrant != GRANT_INVALID) { - r = ENOBUFS; - break; - } - pp->wrsendreply = TRUE; - pp->wrcaller = m_ptr->m_source; - pp->wrproc = m_ptr->USER_ENDPT; - pp->wrgrant = (cp_grant_id_t) m_ptr->IO_GRANT; - pp->wroffset = 0; - pp->wrleft = m_ptr->COUNT; - handle_events(tp); - if (pp->wrleft == 0) { - pp->wrgrant = GRANT_INVALID; - return; /* already done */ - } - - { - pp->wrsendreply = FALSE; /* do suspend */ - r = SUSPEND; - } - break; - - case DEV_OPEN: - r = pp->state != 0 ? EIO : OK; - pp->state |= PTY_ACTIVE; - pp->rdcum = 0; - pp->wrcum = 0; - break; - - case DEV_CLOSE: - r = OK; - if (pp->state & TTY_CLOSED) { - pp->state = 0; - } else { - pp->state |= PTY_CLOSED; - sigchar(tp, SIGHUP, 1); - } - break; - - case DEV_SELECT: - r = pty_select(tp, m_ptr); - break; - - case CANCEL: - r = EINTR; - if (m_ptr->USER_ENDPT == pp->rdproc) { - /* Cancel a read from a PTY. */ - r = pp->rdcum > 0 ? pp->rdcum : EAGAIN; - pp->rdleft = pp->rdcum = 0; - pp->rdgrant = GRANT_INVALID; - } - if (m_ptr->USER_ENDPT == pp->wrproc) { - /* Cancel a write to a PTY. */ - r = pp->wrcum > 0 ? pp->wrcum : EAGAIN; - pp->wrleft = pp->wrcum = 0; - pp->wrgrant = GRANT_INVALID; - } - break; - - default: - r = EINVAL; - } - tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->USER_ENDPT, r); + chardriver_process(&pty_master_tab, m_ptr, ipc_status); } /*===========================================================================* - * pty_write * + * pty_slave_write * *===========================================================================*/ -static int pty_write(tty_t *tp, int try) +static int pty_slave_write(tty_t *tp, int try) { /* (*dev_write)() routine for PTYs. Transfer bytes from the writer on * /dev/ttypX to the output buffer. @@ -214,19 +348,13 @@ static int pty_write(tty_t *tp, int try) pty_t *pp = tp->tty_priv; int count, ocount, s; - /* PTY closed down? */ if (pp->state & PTY_CLOSED) { if (try) return 1; if (tp->tty_outleft > 0) { - if(tp->tty_outrepcode == TTY_REVIVE) { - notify(tp->tty_outcaller); - tp->tty_outrevived = 1; - } else { - tty_reply(tp->tty_outrepcode, tp->tty_outcaller, - tp->tty_outproc, EIO); - tp->tty_outleft = tp->tty_outcum = 0; - } + chardriver_reply_task(tp->tty_outcaller, tp->tty_outid, EIO); + tp->tty_outleft = tp->tty_outcum = 0; + tp->tty_outcaller = NONE; } return 0; } @@ -244,11 +372,11 @@ static int pty_write(tty_t *tp, int try) /* Copy from user space to the PTY output buffer. */ if (tp->tty_outcaller == KERNEL) { /* We're trying to print on kernel's behalf */ - memcpy(pp->ohead, (void *) tp->tty_outgrant + tp->tty_outoffset, + memcpy(pp->ohead, (void *) tp->tty_outgrant + tp->tty_outcum, count); } else { if ((s = sys_safecopyfrom(tp->tty_outcaller, tp->tty_outgrant, - tp->tty_outoffset, (vir_bytes) pp->ohead, + tp->tty_outcum, (vir_bytes) pp->ohead, count)) != OK) { break; } @@ -267,19 +395,13 @@ static int pty_write(tty_t *tp, int try) pp->ohead -= buflen(pp->obuf); pty_start(pp); - tp->tty_outoffset += count; - tp->tty_outcum += count; if ((tp->tty_outleft -= count) == 0) { /* Output is finished, reply to the writer. */ - if(tp->tty_outrepcode == TTY_REVIVE) { - notify(tp->tty_outcaller); - tp->tty_outrevived = 1; - } else { - tty_reply(tp->tty_outrepcode, tp->tty_outcaller, - tp->tty_outproc, tp->tty_outcum); - tp->tty_outcum = 0; - } + chardriver_reply_task(tp->tty_outcaller, tp->tty_outid, + tp->tty_outcum); + tp->tty_outcum = 0; + tp->tty_outcaller = NONE; } } pty_finish(pp); @@ -287,9 +409,9 @@ static int pty_write(tty_t *tp, int try) } /*===========================================================================* - * pty_echo * + * pty_slave_echo * *===========================================================================*/ -static void pty_echo(tty_t *tp, int c) +static void pty_slave_echo(tty_t *tp, int c) { /* Echo one character. (Like pty_write, but only one character, optionally.) */ @@ -326,11 +448,10 @@ static void pty_start(pty_t *pp) if (count == 0) break; /* Copy from the output buffer to the readers address space. */ - if((s = sys_safecopyto(pp->rdcaller, pp->rdgrant, - pp->rdoffset, (vir_bytes) pp->otail, count)) != OK) { + if((s = sys_safecopyto(pp->rdcaller, pp->rdgrant, pp->rdcum, + (vir_bytes) pp->otail, count)) != OK) { break; } - pp->rdoffset += count; /* Bookkeeping. */ pp->ocount -= count; @@ -348,21 +469,18 @@ static void pty_finish(pty_t *pp) /* Finish the read request of a PTY reader if there is at least one byte * transferred. */ - if (pp->rdcum > 0) { - if (pp->rdsendreply) { - tty_reply(TASK_REPLY, pp->rdcaller, pp->rdproc, pp->rdcum); - pp->rdleft = pp->rdcum = 0; - } - else - notify(pp->rdcaller); - } + if (pp->rdcum > 0) { + chardriver_reply_task(pp->rdcaller, pp->rdid, pp->rdcum); + pp->rdleft = pp->rdcum = 0; + pp->rdcaller = NONE; + } } /*===========================================================================* - * pty_read * + * pty_slave_read * *===========================================================================*/ -static int pty_read(tty_t *tp, int try) +static int pty_slave_read(tty_t *tp, int try) { /* Offer bytes from the PTY writer for input on the TTY. (Do it one byte at * a time, 99% of the writes will be for one byte, so no sense in being smart.) @@ -373,14 +491,10 @@ static int pty_read(tty_t *tp, int try) if (pp->state & PTY_CLOSED) { if (try) return 1; if (tp->tty_inleft > 0) { - if(tp->tty_inrepcode == TTY_REVIVE) { - notify(tp->tty_incaller); - tp->tty_inrevived = 1; - } else { - tty_reply(tp->tty_inrepcode, tp->tty_incaller, - tp->tty_inproc, tp->tty_incum); - tp->tty_inleft = tp->tty_incum = 0; - } + chardriver_reply_task(tp->tty_incaller, tp->tty_inid, + tp->tty_incum); + tp->tty_inleft = tp->tty_incum = 0; + tp->tty_incaller = NONE; } return 1; } @@ -395,12 +509,11 @@ static int pty_read(tty_t *tp, int try) int s; /* Transfer one character to 'c'. */ - if ((s = sys_safecopyfrom(pp->wrcaller, pp->wrgrant, pp->wroffset, + if ((s = sys_safecopyfrom(pp->wrcaller, pp->wrgrant, pp->wrcum, (vir_bytes) &c, 1)) != OK) { printf("pty: safecopy failed (error %d)\n", s); break; } - pp->wroffset++; /* Input processing. */ if (in_process(tp, &c, 1, -1) == 0) break; @@ -408,13 +521,9 @@ static int pty_read(tty_t *tp, int try) /* PTY writer bookkeeping. */ pp->wrcum++; if (--pp->wrleft == 0) { - if (pp->wrsendreply) { - tty_reply(TASK_REPLY, pp->wrcaller, pp->wrproc, - pp->wrcum); - pp->wrcum = 0; - } - else - notify(pp->wrcaller); + chardriver_reply_task(pp->wrcaller, pp->wrid, pp->wrcum); + pp->wrcum = 0; + pp->wrcaller = NONE; } } @@ -422,9 +531,27 @@ static int pty_read(tty_t *tp, int try) } /*===========================================================================* - * pty_close * + * pty_slave_open * *===========================================================================*/ -static int pty_close(tty_t *tp, int UNUSED(try)) +static int pty_slave_open(tty_t *tp, int UNUSED(try)) +{ +/* The tty side has been opened. */ + pty_t *pp = tp->tty_priv; + + /* TTY_ACTIVE may already be set, which would indicate that the slave is + * reopened after being fully closed while the master is still open. In that + * case TTY_CLOSED will also be set, so clear that one. + */ + pp->state |= TTY_ACTIVE; + pp->state &= ~TTY_CLOSED; + + return 0; +} + +/*===========================================================================* + * pty_slave_close * + *===========================================================================*/ +static int pty_slave_close(tty_t *tp, int UNUSED(try)) { /* The tty side has closed, so shut down the pty side. */ pty_t *pp = tp->tty_priv; @@ -432,41 +559,44 @@ static int pty_close(tty_t *tp, int UNUSED(try)) if (!(pp->state & PTY_ACTIVE)) return 0; if (pp->rdleft > 0) { - assert(!pp->rdsendreply); - notify(pp->rdcaller); + chardriver_reply_task(pp->rdcaller, pp->rdid, pp->rdcum); + pp->rdleft = pp->rdcum = 0; + pp->rdcaller = NONE; } if (pp->wrleft > 0) { - assert(!pp->wrsendreply); - notify(pp->wrcaller); + chardriver_reply_task(pp->wrcaller, pp->wrid, pp->wrcum); + pp->wrleft = pp->wrcum = 0; + pp->wrcaller = NONE; } - if (pp->state & PTY_CLOSED) pp->state = 0; else pp->state |= TTY_CLOSED; + if (pp->state & PTY_CLOSED) pp->state = 0; + else pp->state |= TTY_CLOSED; return 0; } /*===========================================================================* - * pty_icancel * + * pty_slave_icancel * *===========================================================================*/ -static int pty_icancel(tty_t *tp, int UNUSED(try)) +static int pty_slave_icancel(tty_t *tp, int UNUSED(try)) { /* Discard waiting input. */ pty_t *pp = tp->tty_priv; if (pp->wrleft > 0) { - pp->wrcum += pp->wrleft; - pp->wrleft= 0; - notify(pp->wrcaller); + chardriver_reply_task(pp->wrcaller, pp->wrid, pp->wrcum + pp->wrleft); + pp->wrcum = pp->wrleft = 0; + pp->wrcaller = NONE; } return 0; } /*===========================================================================* - * pty_ocancel * + * pty_slave_ocancel * *===========================================================================*/ -static int pty_ocancel(tty_t *tp, int UNUSED(try)) +static int pty_slave_ocancel(tty_t *tp, int UNUSED(try)) { /* Drain the output buffer. */ pty_t *pp = tp->tty_priv; @@ -490,136 +620,21 @@ void pty_init(tty_t *tp) pp = tp->tty_priv = &pty_table[line]; pp->tty = tp; pp->select_ops = 0; - pp->rdgrant = GRANT_INVALID; - pp->wrgrant = GRANT_INVALID; + pp->rdcaller = NONE; + pp->wrcaller = NONE; /* Set up output queue. */ pp->ohead = pp->otail = pp->obuf; /* Fill in TTY function hooks. */ - tp->tty_devread = pty_read; - tp->tty_devwrite = pty_write; - tp->tty_echo = pty_echo; - tp->tty_icancel = pty_icancel; - tp->tty_ocancel = pty_ocancel; - tp->tty_close = pty_close; + tp->tty_devread = pty_slave_read; + tp->tty_devwrite = pty_slave_write; + tp->tty_echo = pty_slave_echo; + tp->tty_icancel = pty_slave_icancel; + tp->tty_ocancel = pty_slave_ocancel; + tp->tty_open = pty_slave_open; + tp->tty_close = pty_slave_close; tp->tty_select_ops = 0; } -/*===========================================================================* - * pty_status * - *===========================================================================*/ -int pty_status(message *m_ptr) -{ - int i, event_found; - pty_t *pp; - - event_found = 0; - for (i= 0, pp = pty_table; istate & TTY_CLOSED) && pp->rdleft > 0) || - pp->rdcum > 0) && - pp->rdcaller == m_ptr->m_source) - { - m_ptr->m_type = DEV_REVIVE; - m_ptr->REP_ENDPT = pp->rdproc; - m_ptr->REP_IO_GRANT = pp->rdgrant; - m_ptr->REP_STATUS = pp->rdcum; - pp->rdleft = pp->rdcum = 0; - pp->rdgrant = GRANT_INVALID; - event_found = 1; - break; - } - - if ((((pp->state & TTY_CLOSED) && pp->wrleft > 0) || - pp->wrcum > 0) && - pp->wrcaller == m_ptr->m_source) - { - m_ptr->m_type = DEV_REVIVE; - m_ptr->REP_ENDPT = pp->wrproc; - m_ptr->REP_IO_GRANT = pp->wrgrant; - if (pp->wrcum == 0) - m_ptr->REP_STATUS = EIO; - else - m_ptr->REP_STATUS = pp->wrcum; - - pp->wrleft = pp->wrcum = 0; - pp->wrgrant = GRANT_INVALID; - event_found = 1; - break; - } - - if (pp->select_ready_ops && pp->select_proc == m_ptr->m_source) { - m_ptr->m_type = DEV_IO_READY; - m_ptr->DEV_MINOR = PTYPX_MINOR + i; - m_ptr->DEV_SEL_OPS = pp->select_ready_ops; - pp->select_ready_ops = 0; - event_found = 1; - break; - } - } - return event_found; -} - -/*===========================================================================* - * select_try_pty * - *===========================================================================*/ -static int select_try_pty(tty_t *tp, int ops) -{ - pty_t *pp = tp->tty_priv; - int r = 0; - - if (ops & SEL_WR) { - /* Write won't block on error. */ - if (pp->state & TTY_CLOSED) r |= SEL_WR; - else if (pp->wrleft != 0 || pp->wrcum != 0) r |= SEL_WR; - else r |= SEL_WR; - } - - if (ops & SEL_RD) { - /* Read won't block on error. */ - if (pp->state & TTY_CLOSED) r |= SEL_RD; - else if (pp->rdleft != 0 || pp->rdcum != 0) r |= SEL_RD; - else if (pp->ocount > 0) r |= SEL_RD; /* Actual data. */ - } - - return r; -} - -/*===========================================================================* - * select_retry_pty * - *===========================================================================*/ -void select_retry_pty(tty_t *tp) -{ - pty_t *pp = tp->tty_priv; - int r; - - /* See if the pty side of a pty is ready to return a select. */ - if (pp->select_ops && (r=select_try_pty(tp, pp->select_ops))) { - pp->select_ops &= ~r; - pp->select_ready_ops |= r; - notify(pp->select_proc); - } -} - -/*===========================================================================* - * pty_select * - *===========================================================================*/ -static int pty_select(tty_t *tp, message *m) -{ - pty_t *pp = tp->tty_priv; - int ops, ready_ops = 0, watch; - - ops = m->USER_ENDPT & (SEL_RD|SEL_WR|SEL_ERR); - watch = (m->USER_ENDPT & SEL_NOTIFY) ? 1 : 0; - - ready_ops = select_try_pty(tp, ops); - - if (!ready_ops && ops && watch) { - pp->select_ops |= ops; - pp->select_proc = m->m_source; - } - - return ready_ops; -} - #endif /* NR_PTYS > 0 */ diff --git a/drivers/tty/tty.c b/drivers/tty/tty.c index 8c28b0927..3fc2e6ff5 100644 --- a/drivers/tty/tty.c +++ b/drivers/tty/tty.c @@ -16,41 +16,6 @@ * to, you guessed it, wake up the TTY to check if input or output can * continue. * - * The valid messages and their parameters are: - * - * notify from HARDWARE: output has been completed or input has arrived - * notify from SYSTEM : e.g., MINIX wants to shutdown; run code to - * cleanly stop - * DEV_READ: a process wants to read from a terminal - * DEV_WRITE: a process wants to write on a terminal - * DEV_IOCTL: a process wants to change a terminal's parameters - * DEV_OPEN: a tty line has been opened - * DEV_CLOSE: a tty line has been closed - * DEV_SELECT: start select notification request - * DEV_STATUS: FS wants to know status for SELECT or REVIVE - * CANCEL: terminate a previous incomplete system call immediately - * - * m_type TTY_LINE USER_ENDPT COUNT TTY_SPEKS IO_GRANT - * ----------------------------------------------------------------- - * | HARD_INT | | | | | | - * |-------------+---------+---------+---------+---------+---------| - * | SYS_SIG | sig set | | | | | - * |-------------+---------+---------+---------+---------+---------| - * | DEV_READ |minor dev| proc nr | count | | grant | - * |-------------+---------+---------+---------+---------+---------| - * | DEV_WRITE |minor dev| proc nr | count | | grant | - * |-------------+---------+---------+---------+---------+---------| - * | DEV_IOCTL |minor dev| proc nr |func code|erase etc| | - * |-------------+---------+---------+---------+---------+---------| - * | DEV_OPEN |minor dev| proc nr | O_NOCTTY| | | - * |-------------+---------+---------+---------+---------+---------| - * | DEV_CLOSE |minor dev| proc nr | | | | - * |-------------+---------+---------+---------+---------+---------| - * | DEV_STATUS | | | | | | - * |-------------+---------+---------+---------+---------+---------| - * | CANCEL |minor dev| proc nr | | | | - * ----------------------------------------------------------------- - * * Changes: * Jan 20, 2004 moved TTY driver to user-space (Jorrit N. Herder) * Sep 20, 2004 local timer management/ sync alarms (Jorrit N. Herder) @@ -63,11 +28,7 @@ #include #include #include -#include -#include -#include #include -#include #include "tty.h" #include @@ -104,14 +65,6 @@ struct kmessages kmess; static void tty_timed_out(timer_t *tp); static void settimer(tty_t *tty_ptr, int enable); -static void do_cancel(tty_t *tp, message *m_ptr); -static void do_ioctl(tty_t *tp, message *m_ptr); -static void do_open(tty_t *tp, message *m_ptr); -static void do_close(tty_t *tp, message *m_ptr); -static void do_read(tty_t *tp, message *m_ptr); -static void do_write(tty_t *tp, message *m_ptr); -static void do_select(tty_t *tp, message *m_ptr); -static void do_status(message *m_ptr); static void in_transfer(tty_t *tp); static int tty_echo(tty_t *tp, int ch); static void rawecho(tty_t *tp, int ch); @@ -122,12 +75,32 @@ static void setattr(tty_t *tp); static void tty_icancel(tty_t *tp); static void tty_init(void); static void do_new_kmess(void); -static tty_t * line2tty(int line); static void set_console_line(char term[CONS_ARG]); static void set_kernel_color(char color[CONS_ARG]); static void set_color(tty_t *tp, int color); static void reset_color(tty_t *tp); +static int do_open(devminor_t minor, int access, endpoint_t user_endpt); +static int do_close(devminor_t minor); +static ssize_t do_read(devminor_t minor, u64_t position, endpoint_t endpt, + cp_grant_id_t grant, size_t size, int flags, cdev_id_t id); +static ssize_t do_write(devminor_t minor, u64_t position, endpoint_t endpt, + cp_grant_id_t grant, size_t size, int flags, cdev_id_t id); +static int do_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt, + cp_grant_id_t grant, int flags, endpoint_t user_endpt, cdev_id_t id); +static int do_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id); +static int do_select(devminor_t minor, unsigned int ops, endpoint_t endpt); + +static struct chardriver tty_tab = { + .cdr_open = do_open, + .cdr_close = do_close, + .cdr_read = do_read, + .cdr_write = do_write, + .cdr_ioctl = do_ioctl, + .cdr_cancel = do_cancel, + .cdr_select = do_select +}; + /* Default attributes. */ static struct termios termios_defaults = { TINPUT_DEF, TOUTPUT_DEF, TCTRL_DEF, TLOCAL_DEF, TSPEED_DEF, TSPEED_DEF, @@ -221,7 +194,6 @@ int main(void) switch (tty_mess.m_type) { case TTY_FKEY_CONTROL: /* (un)register a fkey observer */ - case OLD_FKEY_CONTROL: /* old number */ do_fkey_ctl(&tty_mess); continue; case INPUT_EVENT: @@ -231,71 +203,34 @@ int main(void) ; /* do nothing; end switch */ } - /* Only device requests should get to this point. All requests, - * except DEV_STATUS, have a minor device number. Check this - * exception and get the minor device number otherwise. + if (!IS_CDEV_RQ(tty_mess.m_type)) { + chardriver_process(&tty_tab, &tty_mess, ipc_status); + continue; + } + + /* Only device requests should get to this point. + * All requests have a minor device number. */ - if (tty_mess.m_type == DEV_STATUS) { - do_status(&tty_mess); - continue; - } - line = tty_mess.TTY_LINE; - if (line == CONS_MINOR || line == LOG_MINOR) { - /* /dev/log output goes to /dev/console */ - if (consoleline != CONS_MINOR) { - /* Console output must redirected */ - line = consoleline; - tty_mess.TTY_LINE = line; - } - } - if (line == KBD_MINOR) { - do_kbd(&tty_mess); - continue; - } else if (line == KBDAUX_MINOR) { - do_kbdaux(&tty_mess); + line = tty_mess.CDEV_MINOR; + if (line == KBD_MINOR || line == KBDAUX_MINOR) { + do_kbd(&tty_mess, ipc_status); continue; } else if (line == VIDEO_MINOR) { - do_video(&tty_mess); + do_video(&tty_mess, ipc_status); continue; - } else { - tp = line2tty(line); - + } else if (line - PTYPX_MINOR < NR_PTYS && + tty_mess.m_type != CDEV_IOCTL) { /* Terminals and pseudo terminals belong together. We can only * make a distinction between the two based on position in the * tty_table and not on minor number (i.e., use ispty macro). * Hence this special case. */ - if (line - PTYPX_MINOR < NR_PTYS && - tty_mess.m_type != DEV_IOCTL_S){ - do_pty(tp, &tty_mess); - continue; - } - } - - /* If the device doesn't exist or is not configured return ENXIO. */ - if (tp == NULL || ! tty_active(tp)) { - if (tty_mess.m_source != LOG_PROC_NR) { - tty_reply(TASK_REPLY, tty_mess.m_source, - tty_mess.USER_ENDPT, ENXIO); - } + do_pty(&tty_mess, ipc_status); continue; } /* Execute the requested device driver function. */ - switch (tty_mess.m_type) { - case DEV_READ_S: do_read(tp, &tty_mess); break; - case DEV_WRITE_S: do_write(tp, &tty_mess); break; - case DEV_IOCTL_S: do_ioctl(tp, &tty_mess); break; - case DEV_OPEN: do_open(tp, &tty_mess); break; - case DEV_CLOSE: do_close(tp, &tty_mess); break; - case DEV_SELECT: do_select(tp, &tty_mess); break; - case CANCEL: do_cancel(tp, &tty_mess); break; - default: - printf("Warning, TTY got unexpected request %d from %d\n", - tty_mess.m_type, tty_mess.m_source); - tty_reply(TASK_REPLY, tty_mess.m_source, - tty_mess.USER_ENDPT, EINVAL); - } + chardriver_process(&tty_tab, &tty_mess, ipc_status); } return 0; @@ -304,45 +239,41 @@ int main(void) static void set_color(tty_t *tp, int color) { - message msg; char buf[8]; buf[0] = '\033'; snprintf(&buf[1], sizeof(buf) - 1, "[1;%dm", color); - msg.m_source = KERNEL; - msg.IO_GRANT = buf; - msg.COUNT = sizeof(buf); - do_write(tp, &msg); + do_write(tp->tty_minor, 0, KERNEL, (cp_grant_id_t) buf, sizeof(buf), + CDEV_NONBLOCK, 0); } static void reset_color(tty_t *tp) { - message msg; char buf[8]; #define SGR_COLOR_RESET 39 buf[0] = '\033'; snprintf(&buf[1], sizeof(buf) - 1, "[0;%dm", SGR_COLOR_RESET); - msg.m_source = KERNEL; - msg.IO_GRANT = buf; - msg.COUNT = sizeof(buf); - do_write(tp, &msg); + do_write(tp->tty_minor, 0, KERNEL, (cp_grant_id_t) buf, sizeof(buf), + CDEV_NONBLOCK, 0); } -static tty_t * -line2tty(int line) +tty_t * +line2tty(devminor_t line) { /* Convert a terminal line to tty_table pointer */ tty_t* tp; + /* /dev/log goes to /dev/console, and both may be redirected. */ + if (line == CONS_MINOR || line == LOG_MINOR) + line = consoleline; + if (line == KBD_MINOR || line == KBDAUX_MINOR || line == VIDEO_MINOR) { return(NULL); } else if ((line - CONS_MINOR) < NR_CONS) { tp = tty_addr(line - CONS_MINOR); - } else if (line == LOG_MINOR) { - tp = tty_addr(consoleline); } else if ((line - RS232_MINOR) < NR_RS_LINES) { tp = tty_addr(line - RS232_MINOR + NR_CONS); } else if ((line - TTYPX_MINOR) < NR_PTYS) { @@ -353,6 +284,9 @@ line2tty(int line) tp = NULL; } + if (tp != NULL && !tty_active(tp)) + tp = NULL; + return(tp); } @@ -402,6 +336,9 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info)) /* Final one-time keyboard initialization. */ kb_init_once(); + /* Register for diagnostics notifications. */ + sys_diagctl_register(); + return(OK); } @@ -427,7 +364,7 @@ set_console_line(char term[CONS_ARG]) } /* Serial lines */ - assert(NR_RS_LINES <= 9);/* bellow assumes this is the case */ + assert(NR_RS_LINES <= 9);/* below assumes this is the case */ for (i = 0; i < NR_RS_LINES; i++) { char sercons[6]; strlcpy(sercons, "tty00", sizeof(sercons)); @@ -462,7 +399,6 @@ do_new_kmess(void) static int prev_next = 0; int next, bytes, copy, restore = 0; tty_t *tp, rtp; - message print_kmsg; assert(_minix_kerninfo); kmess_ptr = _minix_kerninfo->kmessages; @@ -488,7 +424,7 @@ do_new_kmess(void) } tp = line2tty(consoleline); - if (tp == NULL || !tty_active(tp)) + if (tp == NULL) panic("Don't know where to send kernel messages"); if (tp->tty_outleft > 0) { /* Terminal is already printing */ @@ -499,10 +435,9 @@ do_new_kmess(void) if (kernel_msg_color != 0) set_color(tp, kernel_msg_color); - print_kmsg.m_source = KERNEL; - print_kmsg.IO_GRANT = kernel_buf_copy; - print_kmsg.COUNT = bytes; - do_write(tp, &print_kmsg); + do_write(tp->tty_minor, 0, KERNEL, + (cp_grant_id_t) kernel_buf_copy, bytes, + CDEV_NONBLOCK, 0); if (kernel_msg_color != 0) reset_color(tp); if (restore) { @@ -534,228 +469,141 @@ static void sef_cb_signal_handler(int signo) } } -/*===========================================================================* - * do_status * - *===========================================================================*/ -static void do_status(m_ptr) -message *m_ptr; -{ - register struct tty *tp; - int event_found; - int status; - int ops; - - /* Check for select or revive events on any of the ttys. If we found an, - * event return a single status message for it. The FS will make another - * call to see if there is more. - */ - event_found = 0; - for (tp = FIRST_TTY; tp < END_TTY; tp++) { - if ((ops = select_try(tp, tp->tty_select_ops)) && - tp->tty_select_proc == m_ptr->m_source) { - - /* I/O for a selected minor device is ready. */ - m_ptr->m_type = DEV_IO_READY; - m_ptr->DEV_MINOR = tp->tty_minor; - m_ptr->DEV_SEL_OPS = ops; - - tp->tty_select_ops &= ~ops; /* unmark select event */ - event_found = 1; - break; - } - else if (tp->tty_inrevived && tp->tty_incaller == m_ptr->m_source) { - - /* Suspended request finished. Send a REVIVE. */ - m_ptr->m_type = DEV_REVIVE; - m_ptr->REP_ENDPT = tp->tty_inproc; - m_ptr->REP_IO_GRANT = tp->tty_ingrant; - m_ptr->REP_STATUS = tp->tty_incum; - - tp->tty_inleft = tp->tty_incum = 0; - tp->tty_inrevived = 0; /* unmark revive event */ - tp->tty_ingrant = GRANT_INVALID; - event_found = 1; - break; - } - else if (tp->tty_outrevived && tp->tty_outcaller == m_ptr->m_source) { - - /* Suspended request finished. Send a REVIVE. */ - m_ptr->m_type = DEV_REVIVE; - m_ptr->REP_ENDPT = tp->tty_outproc; - m_ptr->REP_IO_GRANT = tp->tty_outgrant; - m_ptr->REP_STATUS = tp->tty_outcum; - - tp->tty_outcum = 0; - tp->tty_outrevived = 0; /* unmark revive event */ - tp->tty_outgrant = GRANT_INVALID; - event_found = 1; - break; - } - else if (tp->tty_iorevived && tp->tty_iocaller == m_ptr->m_source) { - - /* Suspended request finished. Send a REVIVE. */ - m_ptr->m_type = DEV_REVIVE; - m_ptr->REP_ENDPT = tp->tty_ioproc; - m_ptr->REP_IO_GRANT = tp->tty_iogrant; - m_ptr->REP_STATUS = tp->tty_iostatus; - tp->tty_iorevived = 0; /* unmark revive event */ - tp->tty_iogrant = GRANT_INVALID; - event_found = 1; - break; - } - } - -#if NR_PTYS > 0 - if (!event_found) - event_found = pty_status(m_ptr); -#endif - if (!event_found) - event_found= kbd_status(m_ptr); - - if (! event_found) { - /* No events of interest were found. Return an empty message. */ - m_ptr->m_type = DEV_NO_STATUS; - } - - /* Almost done. Send back the reply message to the caller. */ - status = send(m_ptr->m_source, m_ptr); - if (status != OK) { - printf("tty`do_status: send to %d failed: %d\n", - m_ptr->m_source, status); - } -} - /*===========================================================================* * do_read * *===========================================================================*/ -static void do_read(tp, m_ptr) -register tty_t *tp; /* pointer to tty struct */ -register message *m_ptr; /* pointer to message sent to the task */ +static ssize_t do_read(devminor_t minor, u64_t UNUSED(position), + endpoint_t endpt, cp_grant_id_t grant, size_t size, int flags, + cdev_id_t id) { /* A process wants to read from a terminal. */ + tty_t *tp; int r; + if ((tp = line2tty(minor)) == NULL) + return ENXIO; + /* Check if there is already a process hanging in a read, check if the * parameters are correct, do I/O. */ - if (tp->tty_inleft > 0) { - r = EIO; - } else - if (m_ptr->COUNT <= 0) { - r = EINVAL; - } else if (tp->tty_ingrant != GRANT_INVALID) { - /* This is actually a fundamental problem with TTY; it can handle - * only one reader per minor device. If we don't return an error, - * we'll overwrite the previous reader and that process will get - * stuck forever. */ - r = ENOBUFS; - } else { - /* Copy information from the message to the tty struct. */ - tp->tty_inrepcode = TASK_REPLY; - tp->tty_incaller = m_ptr->m_source; - tp->tty_inproc = m_ptr->USER_ENDPT; - tp->tty_ingrant = (cp_grant_id_t) m_ptr->IO_GRANT; - tp->tty_inoffset = 0; - tp->tty_inleft = m_ptr->COUNT; + if (tp->tty_incaller != NONE || tp->tty_inleft > 0) + return EIO; + if (size <= 0) + return EINVAL; - if (!(tp->tty_termios.c_lflag & ICANON) - && tp->tty_termios.c_cc[VTIME] > 0) { - if (tp->tty_termios.c_cc[VMIN] == 0) { - /* MIN & TIME specify a read timer that finishes the - * read in TIME/10 seconds if no bytes are available. - */ - settimer(tp, TRUE); - tp->tty_min = 1; - } else { - /* MIN & TIME specify an inter-byte timer that may - * have to be cancelled if there are no bytes yet. - */ - if (tp->tty_eotct == 0) { - settimer(tp, FALSE); - tp->tty_min = tp->tty_termios.c_cc[VMIN]; - } + /* Copy information from the message to the tty struct. */ + tp->tty_incaller = endpt; + tp->tty_inid = id; + tp->tty_ingrant = grant; + assert(tp->tty_incum == 0); + tp->tty_inleft = size; + + if (!(tp->tty_termios.c_lflag & ICANON) && tp->tty_termios.c_cc[VTIME] > 0) { + if (tp->tty_termios.c_cc[VMIN] == 0) { + /* MIN & TIME specify a read timer that finishes the + * read in TIME/10 seconds if no bytes are available. + */ + settimer(tp, TRUE); + tp->tty_min = 1; + } else { + /* MIN & TIME specify an inter-byte timer that may + * have to be cancelled if there are no bytes yet. + */ + if (tp->tty_eotct == 0) { + settimer(tp, FALSE); + tp->tty_min = tp->tty_termios.c_cc[VMIN]; } } - - /* Anything waiting in the input buffer? Clear it out... */ - in_transfer(tp); - /* ...then go back for more. */ - handle_events(tp); - if (tp->tty_inleft == 0) { - return; /* already done */ - } - - /* There were no bytes in the input queue available, so suspend - * the caller. - */ - r = SUSPEND; /* suspend the caller */ - tp->tty_inrepcode = TTY_REVIVE; } - tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->USER_ENDPT, r); + + /* Anything waiting in the input buffer? Clear it out... */ + in_transfer(tp); + /* ...then go back for more. */ + handle_events(tp); + if (tp->tty_inleft == 0) + return EDONTREPLY; /* already done */ + + /* There were no bytes in the input queue available. */ + if (flags & CDEV_NONBLOCK) { + tty_icancel(tp); + r = tp->tty_incum > 0 ? tp->tty_incum : EAGAIN; + tp->tty_inleft = tp->tty_incum = 0; + tp->tty_incaller = NONE; + return r; + } + if (tp->tty_select_ops) - select_retry(tp); + select_retry(tp); + + return EDONTREPLY; /* suspend the caller */ } /*===========================================================================* * do_write * *===========================================================================*/ -static void do_write(tp, m_ptr) -register tty_t *tp; -register message *m_ptr; /* pointer to message sent to the task */ +static ssize_t do_write(devminor_t minor, u64_t UNUSED(position), + endpoint_t endpt, cp_grant_id_t grant, size_t size, int flags, + cdev_id_t id) { /* A process wants to write on a terminal. */ + tty_t *tp; int r; + if ((tp = line2tty(minor)) == NULL) + return ENXIO; + /* Check if there is already a process hanging in a write, check if the * parameters are correct, do I/O. */ - if (tp->tty_outleft > 0) { - r = EIO; - } else - if (m_ptr->COUNT <= 0) { - r = EINVAL; - } else { - /* Copy message parameters to the tty structure. */ - tp->tty_outrepcode = TASK_REPLY; - tp->tty_outcaller = m_ptr->m_source; - tp->tty_outproc = m_ptr->USER_ENDPT; - tp->tty_outgrant = (cp_grant_id_t) m_ptr->IO_GRANT; - tp->tty_outoffset = 0; - tp->tty_outleft = m_ptr->COUNT; + if (tp->tty_outcaller != NONE || tp->tty_outleft > 0) + return EIO; + if (size <= 0) + return EINVAL; - /* Try to write. */ - handle_events(tp); - if (tp->tty_outleft == 0) - return; /* already done */ + /* Copy message parameters to the tty structure. */ + tp->tty_outcaller = endpt; + tp->tty_outid = id; + tp->tty_outgrant = grant; + assert(tp->tty_outcum == 0); + tp->tty_outleft = size; - /* None or not all the bytes could be written, so suspend the - * caller. - */ - r = SUSPEND; /* suspend the caller */ - tp->tty_outrepcode = TTY_REVIVE; + /* Try to write. */ + handle_events(tp); + if (tp->tty_outleft == 0) + return EDONTREPLY; /* already done */ + + /* None or not all the bytes could be written. */ + if (flags & CDEV_NONBLOCK) { + r = tp->tty_outcum > 0 ? tp->tty_outcum : EAGAIN; + tp->tty_outleft = tp->tty_outcum = 0; + tp->tty_outcaller = NONE; + return r; } - tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->USER_ENDPT, r); + + if (tp->tty_select_ops) + select_retry(tp); + + return EDONTREPLY; /* suspend the caller */ } /*===========================================================================* * do_ioctl * *===========================================================================*/ -static void do_ioctl(tp, m_ptr) -register tty_t *tp; -message *m_ptr; /* pointer to message sent to task */ +static int do_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt, + cp_grant_id_t grant, int flags, endpoint_t user_endpt, cdev_id_t id) { -/* Perform an IOCTL on this terminal. Posix termios calls are handled - * by the IOCTL system call +/* Perform an IOCTL on this terminal. POSIX termios calls are handled + * by the IOCTL system call. */ - - int r; - union { - int i; - } param; + tty_t *tp; + int i, r; size_t size; + if ((tp = line2tty(minor)) == NULL) + return ENXIO; + /* Size of the ioctl parameter. */ - switch (m_ptr->TTY_REQUEST) { + switch (request) { case TCGETS: /* Posix tcgetattr function */ case TCSETS: /* Posix tcsetattr function, TCSANOW option */ case TCSETSW: /* Posix tcsetattr function, TCSADRAIN option */ @@ -789,56 +637,55 @@ message *m_ptr; /* pointer to message sent to task */ } r = OK; - switch (m_ptr->TTY_REQUEST) { + switch (request) { case TCGETS: /* Get the termios attributes. */ - r = sys_safecopyto(m_ptr->m_source, (cp_grant_id_t) m_ptr->IO_GRANT, 0, - (vir_bytes) &tp->tty_termios, (vir_bytes) size); + r = sys_safecopyto(endpt, grant, 0, (vir_bytes) &tp->tty_termios, + size); break; case TCSETSW: case TCSETSF: case TCDRAIN: if (tp->tty_outleft > 0) { + if (flags & CDEV_NONBLOCK) + return EAGAIN; /* Wait for all ongoing output processing to finish. */ - tp->tty_iocaller = m_ptr->m_source; - tp->tty_ioproc = m_ptr->USER_ENDPT; - tp->tty_ioreq = m_ptr->REQUEST; - tp->tty_iogrant = (cp_grant_id_t) m_ptr->IO_GRANT; - r = SUSPEND; - break; + tp->tty_iocaller = endpt; + tp->tty_ioid = id; + tp->tty_ioreq = request; + tp->tty_iogrant = grant; + return EDONTREPLY; /* suspend the caller */ } - if (m_ptr->TTY_REQUEST == TCDRAIN) break; - if (m_ptr->TTY_REQUEST == TCSETSF) tty_icancel(tp); + if (request == TCDRAIN) break; + if (request == TCSETSF) tty_icancel(tp); /*FALL THROUGH*/ case TCSETS: /* Set the termios attributes. */ - r = sys_safecopyfrom(m_ptr->m_source, (cp_grant_id_t) m_ptr->IO_GRANT, - 0, (vir_bytes) &tp->tty_termios, (vir_bytes) size); + r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &tp->tty_termios, + size); if (r != OK) break; setattr(tp); break; case TCFLSH: - r = sys_safecopyfrom(m_ptr->m_source, (cp_grant_id_t) m_ptr->IO_GRANT, - 0, (vir_bytes) ¶m.i, (vir_bytes) size); + r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &i, size); if (r != OK) break; - switch (param.i) { - case TCIFLUSH: tty_icancel(tp); break; - case TCOFLUSH: (*tp->tty_ocancel)(tp, 0); break; - case TCIOFLUSH: tty_icancel(tp); (*tp->tty_ocancel)(tp, 0); break; - default: r = EINVAL; + switch (i) { + case TCIFLUSH: tty_icancel(tp); break; + case TCOFLUSH: (*tp->tty_ocancel)(tp, 0); break; + case TCIOFLUSH: tty_icancel(tp); (*tp->tty_ocancel)(tp, 0); break; + default: r = EINVAL; } break; case TCFLOW: - r = sys_safecopyfrom(m_ptr->m_source, (cp_grant_id_t) m_ptr->IO_GRANT, - 0, (vir_bytes) ¶m.i, (vir_bytes) size); + r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &i, size); if (r != OK) break; - switch (param.i) { + switch (i) { case TCOOFF: case TCOON: - tp->tty_inhibited = (param.i == TCOOFF); + tp->tty_inhibited = (i == TCOOFF); tp->tty_events = 1; break; case TCIOFF: @@ -857,27 +704,24 @@ message *m_ptr; /* pointer to message sent to task */ break; case TIOCGWINSZ: - r = sys_safecopyto(m_ptr->m_source, (cp_grant_id_t) m_ptr->IO_GRANT, 0, - (vir_bytes) &tp->tty_winsize, (vir_bytes) size); + r = sys_safecopyto(endpt, grant, 0, (vir_bytes) &tp->tty_winsize, + size); break; case TIOCSWINSZ: - r = sys_safecopyfrom(m_ptr->m_source, (cp_grant_id_t) m_ptr->IO_GRANT, - 0, (vir_bytes) &tp->tty_winsize, (vir_bytes) size); + r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &tp->tty_winsize, + size); sigchar(tp, SIGWINCH, 0); break; case KIOCSMAP: /* Load a new keymap (only /dev/console). */ - if (isconsole(tp)) r = kbd_loadmap(m_ptr); + if (isconsole(tp)) r = kbd_loadmap(endpt, grant); break; - case TIOCSFON_OLD: - printf("TTY: old TIOCSFON ignored.\n"); - break; case TIOCSFON: /* Load a font into an EGA or VGA card (hs@hck.hr) */ - if (isconsole(tp)) r = con_loadfont(m_ptr); + if (isconsole(tp)) r = con_loadfont(endpt, grant); break; /* These Posix functions are allowed to fail if _POSIX_JOB_CONTROL is @@ -889,30 +733,31 @@ message *m_ptr; /* pointer to message sent to task */ r = ENOTTY; } - /* Send the reply. */ - tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->USER_ENDPT, r); + return r; } /*===========================================================================* * do_open * *===========================================================================*/ -static void do_open(tp, m_ptr) -register tty_t *tp; -message *m_ptr; /* pointer to message sent to task */ +static int do_open(devminor_t minor, int access, endpoint_t user_endpt) { /* A tty line has been opened. Make it the callers controlling tty if - * O_NOCTTY is *not* set and it is not the log device. 1 is returned if - * the tty is made the controlling tty, otherwise OK or an error code. + * CDEV_NOCTTY is *not* set and it is not the log device. CDEV_CTTY is returned + * if the tty is made the controlling tty, otherwise OK or an error code. */ + tty_t *tp; int r = OK; - if (m_ptr->TTY_LINE == LOG_MINOR) { + if ((tp = line2tty(minor)) == NULL) + return ENXIO; + + if (minor == LOG_MINOR) { /* The log device is a write-only diagnostics device. */ - if (m_ptr->COUNT & R_BIT) r = EACCES; + if (access & CDEV_R_BIT) return EACCES; } else { - if (!(m_ptr->COUNT & O_NOCTTY)) { - tp->tty_pgrp = m_ptr->USER_ENDPT; - r = 1; + if (!(access & CDEV_NOCTTY)) { + tp->tty_pgrp = user_endpt; + r = CDEV_CTTY; } tp->tty_openct++; if (tp->tty_openct == 1) { @@ -920,19 +765,22 @@ message *m_ptr; /* pointer to message sent to task */ (*tp->tty_open)(tp, 0); } } - tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->USER_ENDPT, r); + + return r; } /*===========================================================================* * do_close * *===========================================================================*/ -static void do_close(tp, m_ptr) -register tty_t *tp; -message *m_ptr; /* pointer to message sent to task */ +static int do_close(devminor_t minor) { /* A tty line has been closed. Clean up the line if it is the last close. */ + tty_t *tp; - if (m_ptr->TTY_LINE != LOG_MINOR && --tp->tty_openct == 0) { + if ((tp = line2tty(minor)) == NULL) + return ENXIO; + + if (minor != LOG_MINOR && --tp->tty_openct == 0) { tp->tty_pgrp = 0; tty_icancel(tp); (*tp->tty_ocancel)(tp, 0); @@ -941,48 +789,49 @@ message *m_ptr; /* pointer to message sent to task */ tp->tty_winsize = winsize_defaults; setattr(tp); } - tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->USER_ENDPT, OK); + + return OK; } /*===========================================================================* * do_cancel * *===========================================================================*/ -static void do_cancel(tp, m_ptr) -register tty_t *tp; -message *m_ptr; /* pointer to message sent to task */ +static int do_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id) { /* A signal has been sent to a process that is hanging trying to read or write. * The pending read or write must be finished off immediately. */ + tty_t *tp; + int r; - int proc_nr; - int mode; - int r = EINTR; + if ((tp = line2tty(minor)) == NULL) + return ENXIO; /* Check the parameters carefully, to avoid cancelling twice. */ - proc_nr = m_ptr->USER_ENDPT; - mode = m_ptr->COUNT; - if ((mode & R_BIT) && tp->tty_inleft != 0 && proc_nr == tp->tty_inproc && - tp->tty_ingrant == (cp_grant_id_t) m_ptr->IO_GRANT) { + r = EDONTREPLY; + if (tp->tty_inleft != 0 && endpt == tp->tty_incaller && id == tp->tty_inid) { /* Process was reading when killed. Clean up input. */ tty_icancel(tp); r = tp->tty_incum > 0 ? tp->tty_incum : EAGAIN; - tp->tty_inleft = tp->tty_incum = tp->tty_inrevived = 0; - tp->tty_ingrant = GRANT_INVALID; - } - if ((mode & W_BIT) && tp->tty_outleft != 0 && proc_nr == tp->tty_outproc && - tp->tty_outgrant == (cp_grant_id_t) m_ptr->IO_GRANT) { + tp->tty_inleft = tp->tty_incum = 0; + tp->tty_incaller = NONE; + } else if (tp->tty_outleft != 0 && endpt == tp->tty_outcaller && + id == tp->tty_outid) { /* Process was writing when killed. Clean up output. */ r = tp->tty_outcum > 0 ? tp->tty_outcum : EAGAIN; - tp->tty_outleft = tp->tty_outcum = tp->tty_outrevived = 0; - tp->tty_outgrant = GRANT_INVALID; - } - if (tp->tty_ioreq != 0 && proc_nr == tp->tty_ioproc) { + tp->tty_outleft = tp->tty_outcum = 0; + tp->tty_outcaller = NONE; + } else if (tp->tty_ioreq != 0 && endpt == tp->tty_iocaller && + id == tp->tty_ioid) { /* Process was waiting for output to drain. */ + r = EINTR; tp->tty_ioreq = 0; + tp->tty_iocaller = NONE; } - tp->tty_events = 1; - tty_reply(TASK_REPLY, m_ptr->m_source, proc_nr, r); + if (r != EDONTREPLY) + tp->tty_events = 1; + /* Only reply if we found a matching request. */ + return r; } int select_try(struct tty *tp, int ops) @@ -996,10 +845,10 @@ int select_try(struct tty *tp, int ops) ready_ops |= ops; } - if (ops & SEL_RD) { + if (ops & CDEV_OP_RD) { /* will i/o not block on read? */ if (tp->tty_inleft > 0) { - ready_ops |= SEL_RD; /* EIO - no blocking */ + ready_ops |= CDEV_OP_RD; /* EIO - no blocking */ } else if (tp->tty_incount > 0) { /* Is a regular read possible? tty_incount * says there is data. But a read will only succeed @@ -1007,25 +856,60 @@ int select_try(struct tty *tp, int ops) */ if (!(tp->tty_termios.c_lflag & ICANON) || tp->tty_eotct > 0) { - ready_ops |= SEL_RD; + ready_ops |= CDEV_OP_RD; } } } - if (ops & SEL_WR) { - if (tp->tty_outleft > 0) ready_ops |= SEL_WR; - else if ((*tp->tty_devwrite)(tp, 1)) ready_ops |= SEL_WR; + if (ops & CDEV_OP_WR) { + if (tp->tty_outleft > 0) ready_ops |= CDEV_OP_WR; + else if ((*tp->tty_devwrite)(tp, 1)) ready_ops |= CDEV_OP_WR; } return ready_ops; } int select_retry(struct tty *tp) { - if (tp->tty_select_ops && select_try(tp, tp->tty_select_ops)) - notify(tp->tty_select_proc); + int ops; + + if (tp->tty_select_ops && (ops = select_try(tp, tp->tty_select_ops))) { + chardriver_reply_select(tp->tty_select_proc, tp->tty_minor, + ops); + tp->tty_select_ops &= ~ops; + } return OK; } +/*===========================================================================* + * do_select * + *===========================================================================*/ +static int do_select(devminor_t minor, unsigned int ops, endpoint_t endpt) +{ + tty_t *tp; + int ready_ops, watch; + + if ((tp = line2tty(minor)) == NULL) + return ENXIO; + + /* Translated minor numbers are a problem when sending late replies. */ + if (tp->tty_minor != minor) + return EBADF; + + watch = (ops & CDEV_NOTIFY); + ops &= (CDEV_OP_RD | CDEV_OP_WR | CDEV_OP_ERR); + + ready_ops = select_try(tp, ops); + + ops &= ~ready_ops; + if (ops && watch) { + tp->tty_select_ops |= ops; + tp->tty_select_proc = endpt; + } + + assert(tp->tty_minor == minor); + return ready_ops; +} + /*===========================================================================* * handle_events * *===========================================================================*/ @@ -1042,8 +926,8 @@ tty_t *tp; /* TTY to check for events. */ * to avoid swamping the TTY task. Messages may be overwritten when the * lines are fast or when there are races between different lines, input * and output, because MINIX only provides single buffering for interrupt - * messages (in proc.c). This is handled by explicitly checking each line - * for fresh input and completed output on each interrupt. + * messages. This is handled by explicitly checking each line for fresh input + * and completed output on each interrupt. */ do { @@ -1064,16 +948,9 @@ tty_t *tp; /* TTY to check for events. */ /* Reply if enough bytes are available. */ if (tp->tty_incum >= tp->tty_min && tp->tty_inleft > 0) { - if (tp->tty_inrepcode == TTY_REVIVE) { - notify(tp->tty_incaller); - tp->tty_inrevived = 1; - } else { - tty_reply(tp->tty_inrepcode, tp->tty_incaller, - tp->tty_inproc, tp->tty_incum); - tp->tty_inleft = tp->tty_incum = 0; - tp->tty_inrevived = 0; - tp->tty_ingrant = GRANT_INVALID; - } + chardriver_reply_task(tp->tty_incaller, tp->tty_inid, tp->tty_incum); + tp->tty_inleft = tp->tty_incum = 0; + tp->tty_incaller = NONE; } if (tp->tty_select_ops) { @@ -1114,10 +991,8 @@ register tty_t *tp; /* pointer to terminal to read from */ if (++bp == bufend(buf)) { /* Temp buffer full, copy to user space. */ sys_safecopyto(tp->tty_incaller, - tp->tty_ingrant, tp->tty_inoffset, - (vir_bytes) buf, - (vir_bytes) buflen(buf)); - tp->tty_inoffset += buflen(buf); + tp->tty_ingrant, tp->tty_incum, + (vir_bytes) buf, (vir_bytes) buflen(buf)); tp->tty_incum += buflen(buf); bp = buf; } @@ -1137,25 +1012,16 @@ register tty_t *tp; /* pointer to terminal to read from */ if (bp > buf) { /* Leftover characters in the buffer. */ count = bp - buf; - sys_safecopyto(tp->tty_incaller, - tp->tty_ingrant, tp->tty_inoffset, + sys_safecopyto(tp->tty_incaller, tp->tty_ingrant, tp->tty_incum, (vir_bytes) buf, (vir_bytes) count); - tp->tty_inoffset += count; tp->tty_incum += count; } /* Usually reply to the reader, possibly even if incum == 0 (EOF). */ if (tp->tty_inleft == 0) { - if (tp->tty_inrepcode == TTY_REVIVE) { - notify(tp->tty_incaller); - tp->tty_inrevived = 1; - } else { - tty_reply(tp->tty_inrepcode, tp->tty_incaller, - tp->tty_inproc, tp->tty_incum); - tp->tty_inleft = tp->tty_incum = 0; - tp->tty_inrevived = 0; - tp->tty_ingrant = GRANT_INVALID; - } + chardriver_reply_task(tp->tty_incaller, tp->tty_inid, tp->tty_incum); + tp->tty_inleft = tp->tty_incum = 0; + tp->tty_incaller = NONE; } } @@ -1585,9 +1451,8 @@ tty_t *tp; if (result == OK) setattr(tp); } tp->tty_ioreq = 0; - notify(tp->tty_iocaller); - tp->tty_iorevived = 1; - tp->tty_iostatus = result; + chardriver_reply_task(tp->tty_iocaller, tp->tty_ioid, result); + tp->tty_iocaller = NONE; } /*===========================================================================* @@ -1646,30 +1511,6 @@ tty_t *tp; (*tp->tty_ioctl)(tp, 0); } -/*===========================================================================* - * tty_reply * - *===========================================================================*/ -void -tty_reply_f( -file, line, code, replyee, proc_nr, status) -char *file; -int line; -int code; /* TASK_REPLY or REVIVE */ -int replyee; /* destination address for the reply */ -int proc_nr; /* to whom should the reply go? */ -int status; /* reply code */ -{ -/* Send a reply to a process that wanted to read or write data. */ - assert(code == TASK_REPLY); - - /* Don't reply to KERNEL (kernel messages) */ - if (replyee == KERNEL) return; - - status = send_taskreply(replyee, proc_nr, status); - if (status != OK) - printf("tty`tty_reply: send to %d failed: %d\n", replyee, status); -} - /*===========================================================================* * sigchar * *===========================================================================*/ @@ -1744,7 +1585,7 @@ static void tty_init() tp->tty_intail = tp->tty_inhead = tp->tty_inbuf; tp->tty_min = 1; - tp->tty_ingrant = tp->tty_outgrant = tp->tty_iogrant = GRANT_INVALID; + tp->tty_incaller = tp->tty_outcaller = tp->tty_iocaller = NONE; tp->tty_termios = termios_defaults; tp->tty_icancel = tp->tty_ocancel = tp->tty_ioctl = tp->tty_close = tp->tty_open = tty_devnop; @@ -1798,28 +1639,3 @@ int enable; /* set timer if true, otherwise unset */ cancel_timer(&tty_ptr->tty_tmr); } } - -/*===========================================================================* - * do_select * - *===========================================================================*/ -static void do_select(tp, m_ptr) -register tty_t *tp; /* pointer to tty struct */ -register message *m_ptr; /* pointer to message sent to the task */ -{ - int ops, ready_ops = 0, watch; - - ops = m_ptr->USER_ENDPT & (SEL_RD|SEL_WR|SEL_ERR); - watch = (m_ptr->USER_ENDPT & SEL_NOTIFY) ? 1 : 0; - - ready_ops = select_try(tp, ops); - - if (!ready_ops && ops && watch) { - tp->tty_select_ops |= ops; - tp->tty_select_proc = m_ptr->m_source; - } - - tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->USER_ENDPT, ready_ops); - - return; -} - diff --git a/drivers/tty/tty.h b/drivers/tty/tty.h index 9bf4147de..f83a980f7 100644 --- a/drivers/tty/tty.h +++ b/drivers/tty/tty.h @@ -1,12 +1,11 @@ /* tty.h - Terminals */ +#include #include #undef lock #undef unlock -#define TTY_REVIVE 6767 - /* First minor numbers for the various classes of TTY devices. */ #define CONS_MINOR 0 #define LOG_MINOR 15 @@ -26,9 +25,6 @@ #define ESC '\33' /* escape */ -#define O_NOCTTY 00400 /* from , or cc will choke */ -#define O_NONBLOCK 04000 - struct tty; typedef int(*devfun_t) (struct tty *tp, int try_only); typedef void(*devfunarg_t) (struct tty *tp, int c); @@ -36,7 +32,7 @@ typedef void(*devfunarg_t) (struct tty *tp, int c); typedef struct tty { int tty_events; /* set when TTY should inspect this line */ int tty_index; /* index into TTY table */ - int tty_minor; /* device minor number */ + devminor_t tty_minor; /* device minor number */ /* Input queue. Typed characters are stored here until read by a program. */ u16_t *tty_inhead; /* pointer to place where next char goes */ @@ -63,27 +59,19 @@ typedef struct tty { char tty_openct; /* count of number of opens of this tty */ /* Information about incomplete I/O requests is stored here. */ - int tty_inrepcode; /* reply code, TASK_REPLY or REVIVE */ - char tty_inrevived; /* set to 1 if revive callback is pending */ - endpoint_t tty_incaller; /* process that made the call (usually VFS) */ - endpoint_t tty_inproc; /* process that wants to read from tty */ + endpoint_t tty_incaller; /* process that made the call, or NONE */ + cdev_id_t tty_inid; /* ID of suspended read request */ cp_grant_id_t tty_ingrant; /* grant where data is to go */ - vir_bytes tty_inoffset; /* offset into grant */ - int tty_inleft; /* how many chars are still needed */ - int tty_incum; /* # chars input so far */ - int tty_outrepcode; /* reply code, TASK_REPLY or REVIVE */ - int tty_outrevived; /* set to 1 if revive callback is pending */ - endpoint_t tty_outcaller; /* process that made the call (usually VFS) */ - endpoint_t tty_outproc; /* process that wants to write to tty */ + size_t tty_inleft; /* how many chars are still needed */ + size_t tty_incum; /* # chars input so far */ + endpoint_t tty_outcaller; /* process that made the call, or NONE */ + cdev_id_t tty_outid; /* ID of suspended write request */ cp_grant_id_t tty_outgrant; /* grant where data comes from */ - vir_bytes tty_outoffset; /* offset into grant */ - int tty_outleft; /* # chars yet to be output */ - int tty_outcum; /* # chars output so far */ - endpoint_t tty_iocaller; /* process that made the call (usually VFS) */ - int tty_iorevived; /* set to 1 if revive callback is pending */ - endpoint_t tty_ioproc; /* process that wants to do an ioctl */ - int tty_iostatus; /* result */ - int tty_ioreq; /* ioctl request code */ + size_t tty_outleft; /* # chars yet to be output */ + size_t tty_outcum; /* # chars output so far */ + endpoint_t tty_iocaller; /* process that made the call, or NONE */ + cdev_id_t tty_ioid; /* ID of suspended ioctl request */ + unsigned int tty_ioreq; /* ioctl request code */ cp_grant_id_t tty_iogrant; /* virtual address of ioctl buffer or grant */ /* select() data */ @@ -142,13 +130,11 @@ extern struct kmessages kmess; void handle_events(struct tty *tp); void sigchar(struct tty *tp, int sig, int mayflush); void tty_task(void); +tty_t *line2tty(devminor_t minor); int in_process(struct tty *tp, char *buf, int count, int scode); void out_process(struct tty *tp, char *bstart, char *bpos, char *bend, int *icount, int *ocount); void tty_wakeup(clock_t now); -#define tty_reply(c, r, p, s) tty_reply_f(__FILE__, __LINE__, (c), (r), (p), (s)) -void tty_reply_f(char *f, int l, int code, int replyee, int proc_nr, int - status); int select_try(struct tty *tp, int ops); int select_retry(struct tty *tp); @@ -161,25 +147,21 @@ void kputc(int c); void cons_stop(void); void scr_init(struct tty *tp); void toggle_scroll(void); -int con_loadfont(message *m); +int con_loadfont(endpoint_t endpt, cp_grant_id_t grant); void select_console(int cons_line); void beep_x( unsigned freq, clock_t dur); -void do_video(message *m); +void do_video(message *m, int ipc_status); /* keyboard.c */ void kb_init(struct tty *tp); void kb_init_once(void); -int kbd_loadmap(message *m); +int kbd_loadmap(endpoint_t endpt, cp_grant_id_t grant); void do_fkey_ctl(message *m); void kbd_interrupt(message *m); -void do_kbd(message *m); +void do_kbd(message *m, int ipc_status); void do_kb_inject(message *m); -void do_kbdaux(message *m); -int kbd_status(message *m_ptr); /* pty.c */ -void do_pty(struct tty *tp, message *m_ptr); +void do_pty(message *m_ptr, int ipc_status); void pty_init(struct tty *tp); void select_retry_pty(struct tty *tp); -int pty_status(message *m_ptr); - diff --git a/drivers/virtio_blk/virtio_blk.c b/drivers/virtio_blk/virtio_blk.c index cc1b7d069..4583101c7 100644 --- a/drivers/virtio_blk/virtio_blk.c +++ b/drivers/virtio_blk/virtio_blk.c @@ -60,9 +60,8 @@ static int terminating = 0; static int open_count = 0; /* Partition magic */ -#define VIRTIO_BLK_SUB_PER_DRIVE (NR_PARTITIONS * NR_PARTITIONS) struct device part[DEV_PER_DRIVE]; -struct device subpart[VIRTIO_BLK_SUB_PER_DRIVE]; +struct device subpart[SUB_PER_DRIVE]; /* Headers for requests */ static struct virtio_blk_outhdr *hdrs_vir; @@ -78,19 +77,19 @@ static u16_t *status_vir; static phys_bytes status_phys; /* Prototypes */ -static int virtio_blk_open(dev_t minor, int access); -static int virtio_blk_close(dev_t minor); -static ssize_t virtio_blk_transfer(dev_t minor, int write, u64_t position, +static int virtio_blk_open(devminor_t minor, int access); +static int virtio_blk_close(devminor_t minor); +static ssize_t virtio_blk_transfer(devminor_t minor, int write, u64_t position, endpoint_t endpt, iovec_t *iovec, unsigned int cnt, int flags); -static int virtio_blk_ioctl(dev_t minor, unsigned int req, endpoint_t endpt, - cp_grant_id_t grant); -static struct device * virtio_blk_part(dev_t minor); -static void virtio_blk_geometry(dev_t minor, struct part_geom *entry); +static int virtio_blk_ioctl(devminor_t minor, unsigned long req, + endpoint_t endpt, cp_grant_id_t grant, endpoint_t user_endpt); +static struct device * virtio_blk_part(devminor_t minor); +static void virtio_blk_geometry(devminor_t minor, struct part_geom *entry); static void virtio_blk_device_intr(void); static void virtio_blk_spurious_intr(void); static void virtio_blk_intr(unsigned int irqs); -static int virtio_blk_device(dev_t minor, device_id_t *id); +static int virtio_blk_device(devminor_t minor, device_id_t *id); static int virtio_blk_flush(void); static void virtio_blk_terminate(void); @@ -104,22 +103,19 @@ static int virtio_blk_probe(int skip); /* libblockdriver driver tab */ static struct blockdriver virtio_blk_dtab = { - BLOCKDRIVER_TYPE_DISK, - virtio_blk_open, - virtio_blk_close, - virtio_blk_transfer, - virtio_blk_ioctl, - NULL, /* bdr_cleanup */ - virtio_blk_part, - virtio_blk_geometry, - virtio_blk_intr, - NULL, /* bdr_alarm */ - NULL, /* bdr_other */ - virtio_blk_device + .bdr_type = BLOCKDRIVER_TYPE_DISK, + .bdr_open = virtio_blk_open, + .bdr_close = virtio_blk_close, + .bdr_transfer = virtio_blk_transfer, + .bdr_ioctl = virtio_blk_ioctl, + .bdr_part = virtio_blk_part, + .bdr_geometry = virtio_blk_geometry, + .bdr_intr = virtio_blk_intr, + .bdr_device = virtio_blk_device }; static int -virtio_blk_open(dev_t minor, int access) +virtio_blk_open(devminor_t minor, int access) { struct device *dev = virtio_blk_part(minor); @@ -128,7 +124,8 @@ virtio_blk_open(dev_t minor, int access) return ENXIO; /* Read only devices should only be mounted... read-only */ - if ((access & W_BIT) && virtio_host_supports(blk_dev, VIRTIO_BLK_F_RO)) + if ((access & BDEV_W_BIT) && + virtio_host_supports(blk_dev, VIRTIO_BLK_F_RO)) return EACCES; /* Partition magic when opened the first time or re-opened after @@ -147,7 +144,7 @@ virtio_blk_open(dev_t minor, int access) } static int -virtio_blk_close(dev_t minor) +virtio_blk_close(devminor_t minor) { struct device *dev = virtio_blk_part(minor); @@ -238,8 +235,9 @@ prepare_vir_vec(endpoint_t endpt, struct vumap_vir *vir, iovec_s_t *iv, } static ssize_t -virtio_blk_transfer(dev_t minor, int write, u64_t position, endpoint_t endpt, - iovec_t *iovec, unsigned int cnt, int flags) +virtio_blk_transfer(devminor_t minor, int write, u64_t position, + endpoint_t endpt, iovec_t *iovec, unsigned int cnt, + int flags) { /* Need to translate vir to phys */ struct vumap_vir vir[NR_IOREQS]; @@ -377,8 +375,8 @@ virtio_blk_transfer(dev_t minor, int write, u64_t position, endpoint_t endpt, } static int -virtio_blk_ioctl(dev_t minor, unsigned int req, endpoint_t endpt, - cp_grant_id_t grant) +virtio_blk_ioctl(devminor_t minor, unsigned long req, endpoint_t endpt, + cp_grant_id_t grant, endpoint_t UNUSED(user_endpt)) { switch (req) { @@ -391,28 +389,26 @@ virtio_blk_ioctl(dev_t minor, unsigned int req, endpoint_t endpt, } - return EINVAL; + return ENOTTY; } static struct device * -virtio_blk_part(dev_t minor) +virtio_blk_part(devminor_t minor) { /* There's only a single drive attached to this device, alyways. * Lets take some shortcuts... */ /* Take care of d0 d0p0 ... */ - if (minor < 5) + if (minor >= 0 && minor < DEV_PER_DRIVE) return &part[minor]; - /* subparts start at 128 */ - if (minor >= 128) { - - /* Mask away upper bits */ - minor = minor & 0x7F; + /* subparts start at MINOR_d0p0s0 */ + if (minor >= MINOR_d0p0s0) { + minor -= MINOR_d0p0s0; /* Only for the first disk */ - if (minor > 15) + if (minor >= SUB_PER_DRIVE) return NULL; return &subpart[minor]; @@ -422,7 +418,7 @@ virtio_blk_part(dev_t minor) } static void -virtio_blk_geometry(dev_t minor, struct part_geom *entry) +virtio_blk_geometry(devminor_t minor, struct part_geom *entry) { /* Only for the drive */ if (minor != 0) @@ -471,7 +467,7 @@ virtio_blk_intr(unsigned int irqs) } static int -virtio_blk_device(dev_t minor, device_id_t *id) +virtio_blk_device(devminor_t minor, device_id_t *id) { struct device *dev = virtio_blk_part(minor); diff --git a/drivers/vnd/Makefile b/drivers/vnd/Makefile new file mode 100644 index 000000000..493430b27 --- /dev/null +++ b/drivers/vnd/Makefile @@ -0,0 +1,12 @@ +# Makefile for the VNode Disk driver (VND) +PROG= vnd +SRCS= vnd.c + +DPADD+= ${LIBBLOCKDRIVER} ${LIBSYS} +LDADD+= -lblockdriver -lsys + +MAN= + +BINDIR?= /usr/sbin + +.include diff --git a/drivers/vnd/NOTES b/drivers/vnd/NOTES new file mode 100644 index 000000000..382ead657 --- /dev/null +++ b/drivers/vnd/NOTES @@ -0,0 +1,85 @@ +Development notes regarding VND. Original document by David van Moolenbroek. + + +DESIGN DECISIONS + +As simple as the VND driver implementation looks, several important decisions +had to be made in the design process. These decisions are listed here. + +Multiple instances instead of a single instance: The decision to spawn a +separate driver instance for each VND unit was not ideologically inspired, but +rather based on a practical issue. Namely, users may reasonably expect to be +able to set up a VND using a backing file that resides on a file system hosted +on another VND. If one single driver instance were to host both VND units, its +implementation would have to perform all its backcalls to VFS asynchronously, +so as to be able to process another incoming request that was initiated as part +of such an ongoing backcall. As of writing, MINIX3 does not support any form of +asynchronous I/O, but this would not even be sufficient: the asynchrony would +have to extend even to the close(2) call that takes place during device +unconfiguration, as this call could spark I/O to another VND device. +Ultimately, using one driver instance per VND unit avoids these complications +altogether, thus making nesting possible with a maximum depth of the number of +VFS threads. Of course, this comes at the cost of having more VND driver +processes; in order to avoid this cost in the common case, driver instances are +dynamically started and stopped by vndconfig(8). + +dupfrom(2) instead of openas(2): Compared to the NetBSD interface, the MINIX3 +VND API requires that the user program configuring a device pass in a file +descriptor in the vnd_ioctl structure instead of a pointer to a path name. +While binary compatibility with NetBSD would be impossible anyway (MINIX3 can +not support pointers in IOCTL data structures), providing a path name buffer +would be closer to what NetBSD does. There are two reasons behind the choice to +pass in a file descriptor instead. First, performing an open(2)-like call as +a driver backcall is tricky in terms of avoiding deadlocks in VFS, since it +would by nature violate the VFS locking order. On top of that, special +provisions would have to be added to support opening a file in the context of +another process so that chrooted processes would be supported, for example. +In contrast, copying a file descriptor to a remote process is relatively easy +because there is only one potential deadlock case to cover - that of the given +file descriptor identifying the VFS filp object used to control the very same +device - and VFS need only implement a procedure that very much resembles +sending a file descriptor across a UNIX domain socket. Second, since passing a +file descriptor is effectively passing an object capability, it is easier to +improve the isolation of the VND drivers in the future, as described below. + +No separate control device: The driver uses the same minor (block) device for +configuration and for actual (whole-disk) I/O, instead of exposing a separate +device that exists only for the purpose of configuring the device. The reason +for this is that such a control device simply does not fit the NetBSD +opendisk(3) API. While MINIX3 may at some point implement support for NetBSD's +notion of raw devices, such raw devices are still expected to support I/O, and +that means they cannot be control-only. In this regard, it should be mentioned +that the entire VND infrastructure relies on block caches being invalidated +properly upon (un)configuration of VND units, and that such invalidation +(through the REQ_FLUSH file system request) is currently initiated only by +closing block devices. Support for configuration or I/O through character +devices would thus require more work on that side first. In any case, the +primary downside of not having a separate control device is that handling +access permissions on device open is a bit of a hack in order to keep the +MINIX3 userland happy. + + +FUTURE IMPROVEMENTS + +Currently, the VND driver instances are run as root just and only because the +dupfrom(2) call requires root. Obviously, nonroot user processes should never +be able to copy file descriptors from arbitrary processes, and thus, some +security check is required there. However, an access control list for VFS calls +would be a much better solution: in that case, VND driver processes can be +given exclusive rights to the use of the dupfrom(2) call, while they can be +given a normal driver UID at the same time. + +In MINIX3's dependability model, drivers are generally not considered to be +malicious. However, the VND case is interesting because it is possible to +isolate individual driver instances to the point of actual "least authority". +The dupfrom(2) call currently allows any file descriptor to be copied, but it +would be possible to extend the scheme to let user processes (and vndconfig(8) +in particular) mark the file descriptors that may be the target of a dupfrom(2) +call. One of several schemes may be implemented in VFS for this purpose. For +example, each process could be allowed to mark one of its file descriptors as +"copyable" using a new VFS call, and VFS would then allow dupfrom(2) only on a +"copyable" file descriptor from a process blocked on a call to the driver that +invoked dupfrom(2). This approach precludes hiding a VND driver behind a RAID +or FBD (etc) driver, but more sophisticated approaches can solve that as well. +Regardless of the scheme, the end result would be a situation where the VND +drivers are strictly limited to operating on the resources given to them. diff --git a/drivers/vnd/vnd.c b/drivers/vnd/vnd.c new file mode 100644 index 000000000..422ce0088 --- /dev/null +++ b/drivers/vnd/vnd.c @@ -0,0 +1,601 @@ +/* VNode Disk driver, by D.C. van Moolenbroek */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define VND_BUF_SIZE 65536 + +static struct { + int fd; /* file descriptor for the underlying file */ + int openct; /* number of times the device is open */ + int exiting; /* exit after the last close? */ + int rdonly; /* is the device set up read-only? */ + dev_t dev; /* device on which the file resides */ + ino_t ino; /* inode number of the file */ + struct device part[DEV_PER_DRIVE]; /* partition bases and sizes */ + struct device subpart[SUB_PER_DRIVE]; /* same for subpartitions */ + struct part_geom geom; /* geometry information */ + char *buf; /* intermediate I/O transfer buffer */ +} state; + +static unsigned int instance; + +static int vnd_open(devminor_t, int); +static int vnd_close(devminor_t); +static int vnd_transfer(devminor_t, int, u64_t, endpoint_t, iovec_t *, + unsigned int, int); +static int vnd_ioctl(devminor_t, unsigned long, endpoint_t, cp_grant_id_t, + endpoint_t); +static struct device *vnd_part(devminor_t); +static void vnd_geometry(devminor_t, struct part_geom *); + +static struct blockdriver vnd_dtab = { + .bdr_type = BLOCKDRIVER_TYPE_DISK, + .bdr_open = vnd_open, + .bdr_close = vnd_close, + .bdr_transfer = vnd_transfer, + .bdr_ioctl = vnd_ioctl, + .bdr_part = vnd_part, + .bdr_geometry = vnd_geometry +}; + +/* + * Parse partition tables. + */ +static void +vnd_partition(void) +{ + memset(state.part, 0, sizeof(state.part)); + memset(state.subpart, 0, sizeof(state.subpart)); + + state.part[0].dv_size = state.geom.size; + + partition(&vnd_dtab, 0, P_PRIMARY, FALSE /*atapi*/); +} + +/* + * Open a device. + */ +static int +vnd_open(devminor_t minor, int access) +{ + /* No sub/partition devices are available before initialization. */ + if (state.fd == -1 && minor != 0) + return ENXIO; + else if (state.fd != -1 && vnd_part(minor) == NULL) + return ENXIO; + + /* + * If the device either is not configured or configured as read-only, + * block open calls that request write permission. This is what user- + * land expects, although it does mean that vnconfig(8) has to open the + * device as read-only in order to (un)configure it. + */ + if (access & BDEV_W_BIT) { + if (state.fd == -1) + return ENXIO; + if (state.rdonly) + return EACCES; + } + + /* + * Userland expects that if the device is opened after having been + * fully closed, partition tables are (re)parsed. Since we already + * parse partition tables upon initialization, we could skip this for + * the first open, but that would introduce more state. + */ + if (state.fd != -1 && state.openct == 0) { + vnd_partition(); + + /* Make sure our target device didn't just disappear. */ + if (vnd_part(minor) == NULL) + return ENXIO; + } + + state.openct++; + + return OK; +} + +/* + * Close a device. + */ +static int +vnd_close(devminor_t UNUSED(minor)) +{ + if (state.openct == 0) { + printf("VND%u: closing already-closed device\n", instance); + return EINVAL; + } + + state.openct--; + + if (state.exiting) + blockdriver_terminate(); + + return OK; +} + +/* + * Copy a number of bytes from or to the caller, to or from the intermediate + * buffer. If the given endpoint is SELF, a local memory copy must be made. + */ +static int +vnd_copy(iovec_s_t *iov, size_t iov_off, size_t bytes, endpoint_t endpt, + int do_write) +{ + struct vscp_vec vvec[SCPVEC_NR], *vvp; + size_t off, chunk; + int count; + char *ptr; + + assert(bytes > 0 && bytes <= VND_BUF_SIZE); + + vvp = vvec; + count = 0; + + for (off = 0; off < bytes; off += chunk) { + chunk = MIN(bytes - off, iov->iov_size - iov_off); + + if (endpt == SELF) { + ptr = (char *) iov->iov_grant + iov_off; + + if (do_write) + memcpy(&state.buf[off], ptr, chunk); + else + memcpy(ptr, &state.buf[off], chunk); + } else { + assert(count < SCPVEC_NR); /* SCPVEC_NR >= NR_IOREQS */ + + vvp->v_from = do_write ? endpt : SELF; + vvp->v_to = do_write ? SELF : endpt; + vvp->v_bytes = chunk; + vvp->v_gid = iov->iov_grant; + vvp->v_offset = iov_off; + vvp->v_addr = (vir_bytes) &state.buf[off]; + + vvp++; + count++; + } + + iov_off += chunk; + if (iov_off == iov->iov_size) { + iov++; + iov_off = 0; + } + } + + if (endpt != SELF) + return sys_vsafecopy(vvec, count); + else + return OK; +} + +/* + * Advance the given I/O vector, and the offset into its first element, by the + * given number of bytes. + */ +static iovec_s_t * +vnd_advance(iovec_s_t *iov, size_t *iov_offp, size_t bytes) +{ + size_t iov_off; + + assert(bytes > 0 && bytes <= VND_BUF_SIZE); + + iov_off = *iov_offp; + + while (bytes > 0) { + if (bytes >= iov->iov_size - iov_off) { + bytes -= iov->iov_size - iov_off; + iov++; + iov_off = 0; + } else { + iov_off += bytes; + bytes = 0; + } + } + + *iov_offp = iov_off; + return iov; +} + +/* + * Perform data transfer on the selected device. + */ +static int +vnd_transfer(devminor_t minor, int do_write, u64_t position, + endpoint_t endpt, iovec_t *iovt, unsigned int nr_req, int flags) +{ + struct device *dv; + iovec_s_t *iov; + size_t off, chunk, bytes, iov_off; + ssize_t r; + unsigned int i; + + iov = (iovec_s_t *) iovt; + + if (state.fd == -1 || (dv = vnd_part(minor)) == NULL) + return ENXIO; + + /* Prevent write operations on devices opened as write-only. */ + if (do_write && state.rdonly) + return EACCES; + + /* Determine the total number of bytes to transfer. */ + if (position >= dv->dv_size) + return 0; + + bytes = 0; + + for (i = 0; i < nr_req; i++) { + if (iov[i].iov_size == 0 || iov[i].iov_size > LONG_MAX) + return EINVAL; + bytes += iov[i].iov_size; + if (bytes > LONG_MAX) + return EINVAL; + } + + if (bytes > dv->dv_size - position) + bytes = dv->dv_size - position; + + position += dv->dv_base; + + /* Perform the actual transfer, in chunks if necessary. */ + iov_off = 0; + + for (off = 0; off < bytes; off += chunk) { + chunk = MIN(bytes - off, VND_BUF_SIZE); + + assert((unsigned int) (iov - (iovec_s_t *) iovt) < nr_req); + + /* For reads, read in the data for the chunk; possibly less. */ + if (!do_write) { + chunk = r = pread64(state.fd, state.buf, chunk, + position); + + if (r < 0) { + printf("VND%u: pread failed (%d)\n", instance, + -errno); + return -errno; + } + if (r == 0) + break; + } + + /* Copy the data for this chunk from or to the caller. */ + if ((r = vnd_copy(iov, iov_off, chunk, endpt, do_write)) < 0) { + printf("VND%u: data copy failed (%d)\n", instance, r); + return r; + } + + /* For writes, write the data to the file; possibly less. */ + if (do_write) { + chunk = r = pwrite64(state.fd, state.buf, chunk, + position); + + if (r <= 0) { + if (r < 0) + r = -errno; + printf("VND%u: pwrite failed (%d)\n", instance, + r); + return (r < 0) ? r : EIO; + } + } + + /* Move ahead on the I/O vector and the file position. */ + iov = vnd_advance(iov, &iov_off, chunk); + + position += chunk; + } + + /* If force-write is requested, flush the underlying file to disk. */ + if (do_write && (flags & BDEV_FORCEWRITE)) + fsync(state.fd); + + /* Return the number of bytes transferred. */ + return off; +} + +/* + * Initialize the size and geometry for the device and any partitions. If the + * user provided a geometry, this will be used; otherwise, a geometry will be + * computed. + */ +static int +vnd_layout(u64_t size, struct vnd_ioctl *vnd) +{ + u64_t sectors; + + state.geom.base = 0ULL; + + if (vnd->vnd_flags & VNDIOF_HASGEOM) { + /* + * The geometry determines the accessible part of the file. + * The resulting size must not exceed the file size. + */ + state.geom.cylinders = vnd->vnd_geom.vng_ncylinders; + state.geom.heads = vnd->vnd_geom.vng_ntracks; + state.geom.sectors = vnd->vnd_geom.vng_nsectors; + + state.geom.size = (u64_t) state.geom.cylinders * + state.geom.heads * state.geom.sectors * + vnd->vnd_geom.vng_secsize; + if (state.geom.size == 0 || state.geom.size > size) + return EINVAL; + } else { + sectors = size / SECTOR_SIZE; + state.geom.size = sectors * SECTOR_SIZE; + + if (sectors >= 32 * 64) { + state.geom.cylinders = sectors / (32 * 64); + state.geom.heads = 64; + state.geom.sectors = 32; + } else { + state.geom.cylinders = sectors; + state.geom.heads = 1; + state.geom.sectors = 1; + } + } + + /* + * Parse partition tables immediately, so that (sub)partitions can be + * opened right away. The first open will perform the same procedure, + * but that is only necessary to match userland expectations. + */ + vnd_partition(); + + return OK; +} + +/* + * Process I/O control requests. + */ +static int +vnd_ioctl(devminor_t UNUSED(minor), unsigned long request, endpoint_t endpt, + cp_grant_id_t grant, endpoint_t user_endpt) +{ + struct vnd_ioctl vnd; + struct vnd_user vnu; + struct stat st; + int r; + + switch (request) { + case VNDIOCSET: + /* + * The VND must not be busy. Note that the caller has the + * device open to perform the IOCTL request. + */ + if (state.fd != -1 || state.openct != 1) + return EBUSY; + + if ((r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &vnd, + sizeof(vnd))) != OK) + return r; + + /* + * Issue a special VFS backcall that copies a file descriptor + * to the current process, from the user process ultimately + * making the IOCTL call. The result is either a newly + * allocated file descriptor or an error. + */ + if ((state.fd = dupfrom(user_endpt, vnd.vnd_fildes)) == -1) + return -errno; + + /* The target file must be regular. */ + if (fstat(state.fd, &st) == -1) { + printf("VND%u: fstat failed (%d)\n", instance, -errno); + r = -errno; + } + if (r == OK && !S_ISREG(st.st_mode)) + r = EINVAL; + + /* + * Allocate memory for an intermediate I/O transfer buffer. In + * order to save on memory in the common case, the buffer is + * only allocated when the vnd is in use. We use mmap instead + * of malloc to allow the memory to be actually freed later. + */ + if (r == OK) { + state.buf = minix_mmap(NULL, VND_BUF_SIZE, PROT_READ | + PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); + if (state.buf == MAP_FAILED) + r = ENOMEM; + } + + if (r != OK) { + close(state.fd); + state.fd = -1; + return r; + } + + /* Set various device state fields. */ + state.dev = st.st_dev; + state.ino = st.st_ino; + state.rdonly = !!(vnd.vnd_flags & VNDIOF_READONLY); + + r = vnd_layout(st.st_size, &vnd); + + /* Upon success, return the device size to userland. */ + if (r == OK) { + vnd.vnd_size = state.geom.size; + + r = sys_safecopyto(endpt, grant, 0, (vir_bytes) &vnd, + sizeof(vnd)); + } + + if (r != OK) { + minix_munmap(state.buf, VND_BUF_SIZE); + close(state.fd); + state.fd = -1; + } + + return r; + + case VNDIOCCLR: + /* The VND can only be cleared if it has been configured. */ + if (state.fd == -1) + return ENXIO; + + if ((r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &vnd, + sizeof(vnd))) != OK) + return r; + + /* The caller has the device open to do the IOCTL request. */ + if (!(vnd.vnd_flags & VNDIOF_FORCE) && state.openct != 1) + return EBUSY; + + /* + * Close the associated file descriptor immediately, but do not + * allow reuse until the device has been closed by the other + * users. + */ + minix_munmap(state.buf, VND_BUF_SIZE); + close(state.fd); + state.fd = -1; + + return OK; + + case VNDIOCGET: + /* + * We need not copy in the given structure. It would contain + * the requested unit number, but each driver instance provides + * only one unit anyway. + */ + + memset(&vnu, 0, sizeof(vnu)); + + vnu.vnu_unit = instance; + + /* Leave these fields zeroed if the device is not in use. */ + if (state.fd != -1) { + vnu.vnu_dev = state.dev; + vnu.vnu_ino = state.ino; + } + + return sys_safecopyto(endpt, grant, 0, (vir_bytes) &vnu, + sizeof(vnu)); + + case DIOCOPENCT: + return sys_safecopyto(endpt, grant, 0, + (vir_bytes) &state.openct, sizeof(state.openct)); + + case DIOCFLUSH: + if (state.fd == -1) + return ENXIO; + + fsync(state.fd); + + return OK; + } + + return ENOTTY; +} + +/* + * Return a pointer to the partition structure for the given minor device. + */ +static struct device * +vnd_part(devminor_t minor) +{ + if (minor >= 0 && minor < DEV_PER_DRIVE) + return &state.part[minor]; + else if ((unsigned int) (minor -= MINOR_d0p0s0) < SUB_PER_DRIVE) + return &state.subpart[minor]; + else + return NULL; +} + +/* + * Return geometry information. + */ +static void +vnd_geometry(devminor_t UNUSED(minor), struct part_geom *part) +{ + part->cylinders = state.geom.cylinders; + part->heads = state.geom.heads; + part->sectors = state.geom.sectors; +} + +/* + * Initialize the device. + */ +static int +vnd_init(int UNUSED(type), sef_init_info_t *UNUSED(info)) +{ + long v; + + /* + * No support for crash recovery. The driver would have no way to + * reacquire the file descriptor for the target file. + */ + + /* + * The instance number is used for two purposes: reporting errors, and + * returning the proper unit number to userland in VNDIOCGET calls. + */ + v = 0; + (void) env_parse("instance", "d", 0, &v, 0, 255); + instance = (unsigned int) v; + + state.openct = 0; + state.exiting = FALSE; + state.fd = -1; + + return OK; +} + +/* + * Process an incoming signal. + */ +static void +vnd_signal(int signo) +{ + + /* In case of a termination signal, initiate driver shutdown. */ + if (signo != SIGTERM) + return; + + state.exiting = TRUE; + + /* Keep running until the device has been fully closed. */ + if (state.openct == 0) + blockdriver_terminate(); +} + +/* + * Set callbacks and initialize the System Event Framework (SEF). + */ +static void +vnd_startup(void) +{ + + /* Register init and signal callbacks. */ + sef_setcb_init_fresh(vnd_init); + sef_setcb_signal_handler(vnd_signal); + + /* Let SEF perform startup. */ + sef_startup(); +} + +/* + * Driver task. + */ +int +main(int argc, char **argv) +{ + + /* Initialize the driver. */ + env_setargs(argc, argv); + vnd_startup(); + + /* Process requests until shutdown. */ + blockdriver_task(&vnd_dtab); + + return 0; +} diff --git a/etc/mtree/NetBSD.dist.base b/etc/mtree/NetBSD.dist.base index 01b9756cc..87ee5cf3b 100644 --- a/etc/mtree/NetBSD.dist.base +++ b/etc/mtree/NetBSD.dist.base @@ -160,6 +160,7 @@ /set type=dir uid=2 gid=0 mode=755 ./usr/tests/minix-posix +./usr/tests/minix-posix/blocktest # this one is for term(1) /set type=dir uid=0 gid=5 mode=775 diff --git a/etc/rc b/etc/rc index e241c2752..af08178c1 100755 --- a/etc/rc +++ b/etc/rc @@ -171,8 +171,7 @@ start) edit ds edit tty edit memory - edit -p log - edit -c pfs + edit pfs edit init fi diff --git a/etc/rs.inet b/etc/rs.inet index 57c458827..b4bc3c840 100755 --- a/etc/rs.inet +++ b/etc/rs.inet @@ -65,10 +65,10 @@ kill_by_name syslogd sleep 3 if [ X`/bin/sysenv lwip` = Xyes ] then - service up /usr/sbin/lwip -script /etc/rs.inet -dev /dev/ip -devstyle STYLE_CLONE_A + service up /usr/sbin/lwip -script /etc/rs.inet -dev /dev/ip dhcpd --lwip & else - service up /usr/sbin/inet -script /etc/rs.inet -dev /dev/ip -devstyle STYLE_CLONE + service up /usr/sbin/inet -script /etc/rs.inet -dev /dev/ip daemonize dhcpd fi daemonize nonamed -L diff --git a/etc/system.conf b/etc/system.conf index 48796b607..e5bbfc195 100644 --- a/etc/system.conf +++ b/etc/system.conf @@ -110,7 +110,7 @@ service mfs { ipc ALL_SYS; # All system ipc targets allowed system BASIC; # Only basic kernel calls allowed - vm MAPCACHEPAGE SETCACHEPAGE; + vm MAPCACHEPAGE SETCACHEPAGE CLEARCACHE; io NONE; # No I/O range allowed irq NONE; # No IRQ allowed sigmgr rs; # Signal manager is RS @@ -137,7 +137,7 @@ service ext2 { ipc ALL_SYS; # All system ipc targets allowed system BASIC; # Only basic kernel calls allowed - vm MAPCACHEPAGE SETCACHEPAGE; + vm MAPCACHEPAGE SETCACHEPAGE CLEARCACHE; io NONE; # No I/O range allowed irq NONE; # No IRQ allowed sigmgr rs; # Signal manager is RS @@ -150,7 +150,7 @@ service pfs { ipc ALL_SYS; # All system ipc targets allowed system BASIC; # Only basic kernel calls allowed - vm MAPCACHEPAGE SETCACHEPAGE; + vm MAPCACHEPAGE SETCACHEPAGE CLEARCACHE; io NONE; # No I/O range allowed irq NONE; # No IRQ allowed sigmgr rs; # Signal manager is RS @@ -212,24 +212,8 @@ service memory service log { - uid 0; - ipc ALL_SYS; # All system ipc targets allowed - system # Extra kernel calls allowed: - UMAP # 14 - VIRCOPY # 15 - IRQCTL # 19 - INT86 # 20 - DEVIO # 21 - SDEVIO # 22 - VDEVIO # 23 - ; - vm BASIC; # Only basic VM calls allowed - io NONE; # No I/O range allowed - irq NONE; # No IRQ allowed - sigmgr rs; # Signal manager is RS - scheduler sched; # Scheduler is sched - priority 2; # priority queue 2 - quantum 50; # default driver quantum + ipc SYSTEM vfs rs vm; + priority 2; }; service init @@ -513,7 +497,7 @@ service osscore 4/1 # Multimedia / Audio device ; ipc - SYSTEM pm rs log tty ds vfs vm + SYSTEM pm rs tty ds vfs vm pci inet lwip amddev ; uid 0; @@ -539,7 +523,7 @@ service hello DEVIO # 21 ; ipc - SYSTEM pm rs log tty ds vm vfs + SYSTEM pm rs tty ds vm vfs pci inet lwip amddev ; uid 0; @@ -687,3 +671,11 @@ service fbd bios_wini ; }; + +service vnd +{ + ipc + SYSTEM VFS RS VM + ; + uid 0; # only for dupfrom(2) +}; diff --git a/etc/usr/rc b/etc/usr/rc index 51f802a98..85a2ca0cf 100644 --- a/etc/usr/rc +++ b/etc/usr/rc @@ -167,7 +167,7 @@ start) # Start servers and drivers set at the boot monitor. echo -n "Starting services:" - up -n random -dev /dev/random -devstyle STYLE_DEVA -period 3HZ + up -n random -dev /dev/random -period 3HZ # load random number generator if [ -f $RANDOM_FILE ] @@ -188,13 +188,15 @@ start) done if [ X`/bin/sysenv lwip` = Xyes ] then - up lwip -script /etc/rs.inet -dev /dev/ip -devstyle STYLE_CLONE_A + up lwip -script /etc/rs.inet -dev /dev/ip else - up inet -script /etc/rs.inet -dev /dev/ip -devstyle STYLE_CLONE + up inet -script /etc/rs.inet -dev /dev/ip fi up -n ipc + up log -dev /dev/klog + if [ $ARCH = i386 ] then up -n printer -dev /dev/lp -period 10HZ diff --git a/include/minix/Makefile b/include/minix/Makefile index bf2cdd730..f0bc0d90c 100644 --- a/include/minix/Makefile +++ b/include/minix/Makefile @@ -18,7 +18,7 @@ INCS+= acpi.h audio_fw.h bitmap.h \ reboot.h rs.h safecopies.h sched.h sef.h sffs.h \ sound.h spin.h sys_config.h sysinfo.h \ syslib.h sysutil.h termios.h timers.h type.h \ - tty.h u64.h usb.h usb_ch9.h vbox.h \ + u64.h usb.h usb_ch9.h vbox.h \ vboxfs.h vboxif.h vboxtype.h vm.h \ vfsif.h vtreefs.h libminixfs.h netsock.h \ virtio.h diff --git a/include/minix/audio_fw.h b/include/minix/audio_fw.h index d31392868..324dbfe81 100644 --- a/include/minix/audio_fw.h +++ b/include/minix/audio_fw.h @@ -17,7 +17,7 @@ int drv_int_sum(void); int drv_int(int sub_dev); int drv_pause(int chan); int drv_resume(int chan); -int drv_io_ctl(int request, void * val, int * len, int sub_dev); +int drv_io_ctl(unsigned long request, void * val, int * len, int sub_dev); int drv_get_irq(char *irq); int drv_get_frag_size(u32_t *frag_size, int sub_dev); @@ -42,11 +42,9 @@ typedef struct { int BufFillNext; /* end of extra circular buffer */ int BufLength; int RevivePending; /* process waiting for this dev? */ - int ReviveStatus; /* return val when proc unblocked */ endpoint_t ReviveProcNr; /* the process to unblock */ + cdev_id_t ReviveId; /* request ID */ cp_grant_id_t ReviveGrant; /* grant id associated with io */ - void *UserBuf; /* address of user's data buffer */ - int ReadyToRevive; /* are we ready to revive process?*/ endpoint_t SourceProcNr; /* process to send notify to (FS) */ u32_t FragSize; /* dma fragment size */ char *DmaBuf; /* the dma buffer; extra space for @@ -82,9 +80,8 @@ EXTERN special_file_t special_file[]; #define NO_CHANNEL -1 -#define TRUE 1 -#define FALSE 0 #define NO_DMA 0 - +#define READ_DMA 1 +#define WRITE_DMA 2 #endif /* AUDIO_FW_H */ diff --git a/include/minix/bdev.h b/include/minix/bdev.h index dce412a4c..0aca2887a 100644 --- a/include/minix/bdev.h +++ b/include/minix/bdev.h @@ -16,7 +16,8 @@ extern ssize_t bdev_gather(dev_t dev, u64_t pos, iovec_t *vec, int count, int flags); extern ssize_t bdev_scatter(dev_t dev, u64_t pos, iovec_t *vec, int count, int flags); -extern int bdev_ioctl(dev_t dev, int request, void *buf); +extern int bdev_ioctl(dev_t dev, int request, void *buf, + endpoint_t user_endpt); /* Asynchronous API. */ typedef int bdev_id_t; @@ -36,7 +37,7 @@ extern bdev_id_t bdev_gather_asyn(dev_t dev, u64_t pos, iovec_t *vec, extern bdev_id_t bdev_scatter_asyn(dev_t dev, u64_t pos, iovec_t *vec, int count, int flags, bdev_callback_t callback, bdev_param_t param); extern bdev_id_t bdev_ioctl_asyn(dev_t dev, int request, void *buf, - bdev_callback_t callback, bdev_param_t param); + endpoint_t user_endpt, bdev_callback_t callback, bdev_param_t param); extern int bdev_wait_asyn(bdev_id_t id); diff --git a/include/minix/blockdriver.h b/include/minix/blockdriver.h index 6d28265ee..d7e1e7d89 100644 --- a/include/minix/blockdriver.h +++ b/include/minix/blockdriver.h @@ -15,19 +15,19 @@ typedef enum { /* Entry points into the device dependent code of block drivers. */ struct blockdriver { blockdriver_type_t bdr_type; - int(*bdr_open) (dev_t minor, int access); - int(*bdr_close) (dev_t minor); - ssize_t(*bdr_transfer) (dev_t minor, int do_write, u64_t pos, - endpoint_t endpt, iovec_t *iov, unsigned count, int flags); - int(*bdr_ioctl) (dev_t minor, unsigned int request, endpoint_t endpt, - cp_grant_id_t grant); - void(*bdr_cleanup) (void); - struct device *(*bdr_part)(dev_t minor); - void(*bdr_geometry) (dev_t minor, struct part_geom *part); - void(*bdr_intr) (unsigned int irqs); - void(*bdr_alarm) (clock_t stamp); - int(*bdr_other) (message *m_ptr); - int(*bdr_device) (dev_t minor, device_id_t *id); + int (*bdr_open)(devminor_t minor, int access); + int (*bdr_close)(devminor_t minor); + ssize_t (*bdr_transfer)(devminor_t minor, int do_write, u64_t pos, + endpoint_t endpt, iovec_t *iov, unsigned int count, int flags); + int (*bdr_ioctl)(devminor_t minor, unsigned long request, endpoint_t endpt, + cp_grant_id_t grant, endpoint_t user_endpt); + void (*bdr_cleanup)(void); + struct device *(*bdr_part)(devminor_t minor); + void (*bdr_geometry)(devminor_t minor, struct part_geom *part); + void (*bdr_intr)(unsigned int mask); + void (*bdr_alarm)(clock_t stamp); + void (*bdr_other)(message *m_ptr, int ipc_status); + int (*bdr_device)(devminor_t minor, device_id_t *id); }; /* Functions defined by libblockdriver. These can be used for both diff --git a/include/minix/blockdriver_mt.h b/include/minix/blockdriver_mt.h index d3cf62563..2b96c505d 100644 --- a/include/minix/blockdriver_mt.h +++ b/include/minix/blockdriver_mt.h @@ -4,6 +4,8 @@ #define BLOCKDRIVER_MT_API 1 /* do not expose the singlethreaded API */ #include +#define BLOCKDRIVER_MAX_DEVICES 32 + void blockdriver_mt_task(struct blockdriver *driver_tab); void blockdriver_mt_sleep(void); void blockdriver_mt_wakeup(thread_id_t id); diff --git a/include/minix/callnr.h b/include/minix/callnr.h index 629f04ec2..311886131 100644 --- a/include/minix/callnr.h +++ b/include/minix/callnr.h @@ -1,4 +1,4 @@ -#define NCALLS 124 /* number of system calls allowed */ +#define NCALLS 130 /* number of system calls allowed */ /* In case it isn't obvious enough: this list is sorted numerically. */ #define EXIT 1 @@ -49,6 +49,7 @@ #define LSTAT 53 #define IOCTL 54 #define FCNTL 55 +#define DUPFROM 56 #define FS_READY 57 #define PIPE2 58 #define EXEC 59 @@ -72,9 +73,9 @@ #define SYSUNAME 78 #define GETDENTS 80 /* to VFS */ #define LLSEEK 81 /* to VFS */ -#define FSTATFS 82 /* to VFS */ -#define STATVFS 83 /* to VFS */ -#define FSTATVFS 84 /* to VFS */ +#define GETVFSSTAT 82 /* to VFS */ +#define STATVFS1 83 /* to VFS */ +#define FSTATVFS1 84 /* to VFS */ #define SELECT 85 /* to VFS */ #define FCHDIR 86 /* to VFS */ #define FSYNC 87 /* to VFS */ @@ -109,8 +110,12 @@ #define VFS_VMCALL 117 -#define TASK_REPLY 121 /* to VFS: reply code from drivers, not - * really a standalone call. - */ #define MAPDRIVER 122 /* to VFS, map a device */ #define GETRUSAGE 123 /* to PM, VFS */ + +#define VFS_PFS_CHECK_PERMS 124 /* to VFS */ +#define VFS_PFS_VERIFY_FD 125 /* to VFS */ +#define VFS_PFS_SET_FILP 126 /* to VFS */ +#define VFS_PFS_COPY_FILP 127 /* to VFS */ +#define VFS_PFS_PUT_FILP 128 /* to VFS */ +#define VFS_PFS_CANCEL_FD 129 /* to VFS */ diff --git a/include/minix/chardriver.h b/include/minix/chardriver.h index a7a594f67..880ab824b 100644 --- a/include/minix/chardriver.h +++ b/include/minix/chardriver.h @@ -3,39 +3,33 @@ #include +typedef unsigned int cdev_id_t; + /* Entry points into the device dependent code of character drivers. */ struct chardriver { - int(*cdr_open) (message *m_ptr); - int(*cdr_close) (message *m_ptr); - int(*cdr_ioctl) (message *m_ptr); - struct device *(*cdr_prepare)(dev_t device); - int(*cdr_transfer) (endpoint_t endpt, int opcode, u64_t position, - iovec_t *iov, unsigned int nr_req, endpoint_t user_endpt, unsigned int - flags); - void(*cdr_cleanup) (void); - void(*cdr_alarm) (message *m_ptr); - int(*cdr_cancel) (message *m_ptr); - int(*cdr_select) (message *m_ptr); - int(*cdr_other) (message *m_ptr); + int (*cdr_open)(devminor_t minor, int access, endpoint_t user_endpt); + int (*cdr_close)(devminor_t minor); + ssize_t (*cdr_read)(devminor_t minor, u64_t position, endpoint_t endpt, + cp_grant_id_t grant, size_t size, int flags, cdev_id_t id); + ssize_t (*cdr_write)(devminor_t minor, u64_t position, endpoint_t endpt, + cp_grant_id_t grant, size_t size, int flags, cdev_id_t id); + int (*cdr_ioctl)(devminor_t minor, unsigned long request, endpoint_t endpt, + cp_grant_id_t grant, int flags, endpoint_t user_endpt, cdev_id_t id); + int (*cdr_cancel)(devminor_t minor, endpoint_t endpt, cdev_id_t id); + int (*cdr_select)(devminor_t minor, unsigned int ops, endpoint_t endpt); + void (*cdr_intr)(unsigned int mask); + void (*cdr_alarm)(clock_t stamp); + void (*cdr_other)(message *m_ptr, int ipc_status); }; -#define CHARDRIVER_SYNC 0 /* use the synchronous protocol */ -#define CHARDRIVER_ASYNC 1 /* use the asynchronous protocol */ - -#define IS_CDEV_MINOR_RQ(type) (IS_DEV_RQ(type) && (type) != DEV_STATUS) - /* Functions defined by libchardriver. */ void chardriver_announce(void); -void chardriver_process(struct chardriver *cdp, int driver_type, message - *m_ptr, int ipc_status); +void chardriver_process(struct chardriver *cdp, message *m_ptr, + int ipc_status); void chardriver_terminate(void); -void chardriver_task(struct chardriver *cdp, int driver_type); +void chardriver_task(struct chardriver *cdp); -int do_nop(message *m_ptr); -void nop_cleanup(void); -void nop_alarm(message *m_ptr); -int nop_cancel(message *m_ptr); -int nop_select(message *m_ptr); -int nop_ioctl(message *m_ptr); +void chardriver_reply_task(endpoint_t endpt, cdev_id_t id, int r); +void chardriver_reply_select(endpoint_t endpt, devminor_t minor, int ops); #endif /* _MINIX_CHARDRIVER_H */ diff --git a/include/minix/com.h b/include/minix/com.h index 3100c2ac5..831145af1 100644 --- a/include/minix/com.h +++ b/include/minix/com.h @@ -8,8 +8,8 @@ * 1 - 0xFF POSIX requests (see callnr.h) * 0x200 - 0x2FF Data link layer requests and responses * 0x300 - 0x3FF Bus controller requests and responses - * 0x400 - 0x4FF Character device requests - * 0x500 - 0x5FF Character device responses + * 0x400 - 0x4FF Character device requests and responses + * 0x500 - 0x5FF Block device requests and responses * 0x600 - 0x6FF Kernel calls to SYSTEM task * 0x700 - 0x7FF Reincarnation Server (RS) requests * 0x800 - 0x8FF Data Store (DS) requests @@ -25,7 +25,7 @@ * 0x1200 - 0x12FF Devman * 0x1300 - 0x13FF TTY Requests * 0x1400 - 0x14FF VFS-FS transaction IDs - * 0x1500 - 0x15FF Block device requests and responses + * 0x1500 - 0x15FF (unused) * 0x1600 - 0x16FF VirtualBox (VBOX) requests (see vboxif.h) * 0x1700 - 0x17FF Real Time Clock requests and responses * @@ -74,14 +74,13 @@ #define VFS_PROC_NR ((endpoint_t) 1) /* file system */ #define RS_PROC_NR ((endpoint_t) 2) /* reincarnation server */ #define MEM_PROC_NR ((endpoint_t) 3) /* memory driver (RAM disk, null, etc.) */ -#define LOG_PROC_NR ((endpoint_t) 4) /* log device driver */ +#define SCHED_PROC_NR ((endpoint_t) 4) /* scheduler */ #define TTY_PROC_NR ((endpoint_t) 5) /* terminal (TTY) driver */ #define DS_PROC_NR ((endpoint_t) 6) /* data store server */ #define MFS_PROC_NR ((endpoint_t) 7) /* minix root filesystem */ #define VM_PROC_NR ((endpoint_t) 8) /* memory server */ #define PFS_PROC_NR ((endpoint_t) 9) /* pipe filesystem */ -#define SCHED_PROC_NR ((endpoint_t) 10) /* scheduler */ -#define LAST_SPECIAL_PROC_NR 11 /* An untyped version for +#define LAST_SPECIAL_PROC_NR 10 /* An untyped version for computation in macros.*/ #define INIT_PROC_NR ((endpoint_t) LAST_SPECIAL_PROC_NR) /* init -- goes multiuser */ @@ -182,70 +181,9 @@ */ #define BUSC_I2C_RESERVE (BUSC_RQ_BASE + 64) /* reserve i2c device */ +#define BUSC_I2C_ADDR m2_i1 /* slave address */ #define BUSC_I2C_EXEC (BUSC_RQ_BASE + 65) /* perform i2c action */ - -/*===========================================================================* - * Messages for CHARACTER device drivers * - *===========================================================================*/ - -/* Message types for character device drivers. */ -#define DEV_RQ_BASE 0x400 /* base for character device request types */ -#define DEV_RS_BASE 0x500 /* base for character device response types */ - -#define CANCEL (DEV_RQ_BASE + 0) /* force a task to cancel */ -#define DEV_OPEN (DEV_RQ_BASE + 6) /* open a minor device */ -#define DEV_CLOSE (DEV_RQ_BASE + 7) /* close a minor device */ -#define DEV_SELECT (DEV_RQ_BASE + 12) /* request select() attention */ -#define DEV_STATUS (DEV_RQ_BASE + 13) /* request driver status */ -#define DEV_REOPEN (DEV_RQ_BASE + 14) /* reopen a minor device */ - -#define DEV_READ_S (DEV_RQ_BASE + 20) /* (safecopy) read from minor */ -#define DEV_WRITE_S (DEV_RQ_BASE + 21) /* (safecopy) write to minor */ -#define DEV_SCATTER_S (DEV_RQ_BASE + 22) /* (safecopy) write from a vector */ -#define DEV_GATHER_S (DEV_RQ_BASE + 23) /* (safecopy) read into a vector */ -#define DEV_IOCTL_S (DEV_RQ_BASE + 24) /* (safecopy) I/O control code */ - -#define IS_DEV_RQ(type) (((type) & ~0xff) == DEV_RQ_BASE) - -#define DEV_REVIVE (DEV_RS_BASE + 2) /* driver revives process */ -#define DEV_IO_READY (DEV_RS_BASE + 3) /* selected device ready */ -#define DEV_NO_STATUS (DEV_RS_BASE + 4) /* empty status reply */ -#define DEV_REOPEN_REPL (DEV_RS_BASE + 5) /* reply to DEV_REOPEN */ -#define DEV_CLOSE_REPL (DEV_RS_BASE + 6) /* reply to DEV_CLOSE */ -#define DEV_SEL_REPL1 (DEV_RS_BASE + 7) /* first reply to DEV_SELECT */ -#define DEV_SEL_REPL2 (DEV_RS_BASE + 8) /* (opt) second reply to DEV_SELECT */ -#define DEV_OPEN_REPL (DEV_RS_BASE + 9) /* reply to DEV_OPEN */ - -#define IS_DEV_RS(type) (((type) & ~0xff) == DEV_RS_BASE) - -/* Field names for messages to character device drivers. */ -#define DEVICE m2_i1 /* major-minor device */ -#define USER_ENDPT m2_i2 /* which endpoint initiated this call? */ -#define COUNT m2_i3 /* how many bytes to transfer */ -#define REQUEST m2_i3 /* ioctl request code */ -#define POSITION m2_l1 /* file offset (low 4 bytes) */ -#define HIGHPOS m2_l2 /* file offset (high 4 bytes) */ -#define ADDRESS m2_p1 /* core buffer address */ -#define IO_GRANT m2_p1 /* grant id (for DEV_*_S variants) */ -#define FLAGS m2_s1 /* operation flags */ - -#define FLG_OP_NONBLOCK 0x1 /* operation is non blocking */ - -/* Field names for DEV_SELECT messages to character device drivers. */ -#define DEV_MINOR m2_i1 /* minor device */ -#define DEV_SEL_OPS m2_i2 /* which select operations are requested */ - -/* Field names used in reply messages from tasks. */ -#define REP_ENDPT m2_i1 /* # of proc on whose behalf I/O was done */ -#define REP_STATUS m2_i2 /* bytes transferred or error number */ -#define REP_IO_GRANT m2_i3 /* DEV_REVIVE: grant by which I/O was done */ -# define SUSPEND -998 /* status to suspend caller, reply later */ - -/* Field names for messages to TTY driver. */ -#define TTY_LINE DEVICE /* message parameter: terminal line */ -#define TTY_REQUEST COUNT /* message parameter: ioctl request code */ -#define TTY_SPEK POSITION/* message parameter: ioctl speed, erasing */ -#define TTY_PGRP m2_i3 /* message parameter: process group */ +#define BUSC_I2C_GRANT m2_i1 /* grant for request */ /*===========================================================================* * Messages for networking layer * @@ -344,7 +282,8 @@ # define SYS_SETTIME (KERNEL_CALL + 40) /* sys_settime() */ # define SYS_VMCTL (KERNEL_CALL + 43) /* sys_vmctl() */ -# define SYS_SYSCTL (KERNEL_CALL + 44) /* sys_sysctl() */ + +# define SYS_DIAGCTL (KERNEL_CALL + 44) /* sys_diagctl() */ # define SYS_VTIMER (KERNEL_CALL + 45) /* sys_vtimer() */ # define SYS_RUNCTL (KERNEL_CALL + 46) /* sys_runctl() */ @@ -370,7 +309,7 @@ #define SYS_BASIC_CALLS \ SYS_EXIT, SYS_SAFECOPYFROM, SYS_SAFECOPYTO, SYS_VSAFECOPY, SYS_GETINFO, \ SYS_TIMES, SYS_SETALARM, SYS_SETGRANT, \ - SYS_PROFBUF, SYS_SYSCTL, SYS_STATECTL, SYS_SAFEMEMSET + SYS_PROFBUF, SYS_DIAGCTL, SYS_STATECTL, SYS_SAFEMEMSET /* Field names for SYS_MEMSET. */ #define MEM_PTR m2_p1 /* base */ @@ -644,12 +583,14 @@ #define VMCTL_CLEARMAPCACHE 32 #define VMCTL_BOOTINHIBIT_CLEAR 33 -/* Codes and field names for SYS_SYSCTL. */ -#define SYSCTL_CODE m1_i1 /* SYSCTL_CODE_* below */ -#define SYSCTL_ARG1 m1_p1 -#define SYSCTL_ARG2 m1_i2 -#define SYSCTL_CODE_DIAG 1 /* Print diagnostics. */ -#define SYSCTL_CODE_STACKTRACE 2 /* Print process stack. */ +/* Codes and field names for SYS_DIAGCTL. */ +#define DIAGCTL_CODE m1_i1 /* DIAGCTL_CODE_* below */ +#define DIAGCTL_ARG1 m1_p1 +#define DIAGCTL_ARG2 m1_i2 +#define DIAGCTL_CODE_DIAG 1 /* Print diagnostics. */ +#define DIAGCTL_CODE_STACKTRACE 2 /* Print process stack. */ +#define DIAGCTL_CODE_REGISTER 3 /* Register for diagnostic signals */ +#define DIAGCTL_CODE_UNREGISTER 4 /* Unregister for diagnostic signals */ #define DIAG_BUFSIZE (80*25) /* Field names for SYS_VTIMER. */ @@ -825,7 +766,6 @@ /* Additional parameters for PM_DUMPCORE */ # define PM_TERM_SIG m7_i2 /* process's termination signal */ -# define PM_TRACED_PROC m7_i3 /* required for T_DUMPCORE */ /* Parameters for the EXEC_NEWMEM call */ #define EXC_NM_PROC m1_i1 /* process that needs new map */ @@ -902,14 +842,59 @@ #define SEL_ERRORFDS m8_p3 #define SEL_TIMEOUT m8_p4 -/* Field names for the fstatvfs call */ -#define FSTATVFS_FD m1_i1 -#define FSTATVFS_BUF m1_p1 +/* Field names for the getvfsstat(2) call. */ +#define VFS_GETVFSSTAT_BUF m1_p1 +#define VFS_GETVFSSTAT_SIZE m1_i1 +#define VFS_GETVFSSTAT_FLAGS m1_i2 -/* Field names for the statvfs call */ -#define STATVFS_LEN m1_i1 -#define STATVFS_NAME m1_p1 -#define STATVFS_BUF m1_p2 +/* Field names for the fstatvfs1(2) call. */ +#define VFS_FSTATVFS1_FD m1_i1 +#define VFS_FSTATVFS1_BUF m1_p1 +#define VFS_FSTATVFS1_FLAGS m1_i2 + +/* Field names for the statvfs1(2) call. */ +#define VFS_STATVFS1_LEN m1_i1 +#define VFS_STATVFS1_NAME m1_p1 +#define VFS_STATVFS1_BUF m1_p2 +#define VFS_STATVFS1_FLAGS m1_i2 + +/* Field names for the mount(2) call. */ +#define VFS_MOUNT_FLAGS m11_i1 +#define VFS_MOUNT_DEVLEN m11_s1 +#define VFS_MOUNT_PATHLEN m11_s2 +#define VFS_MOUNT_TYPELEN m11_s3 +#define VFS_MOUNT_LABELLEN m11_s4 +#define VFS_MOUNT_DEV m11_p1 +#define VFS_MOUNT_PATH m11_p2 +#define VFS_MOUNT_TYPE m11_p3 +#define VFS_MOUNT_LABEL m11_p4 + +/* Field names for the umount(2) call. */ +#define VFS_UMOUNT_NAME m1_p1 +#define VFS_UMOUNT_NAMELEN m1_i1 +#define VFS_UMOUNT_LABEL m1_p2 +#define VFS_UMOUNT_LABELLEN m1_i2 + +/* Field names for the ioctl(2) call. */ +#define VFS_IOCTL_FD m2_i1 +#define VFS_IOCTL_REQ m2_i3 +#define VFS_IOCTL_ARG m2_p1 + +/* Field names for the PFS backcalls to VFS. */ +#define VFS_PFS_ENDPT m2_i1 +#define VFS_PFS_GRANT m2_i2 +#define VFS_PFS_COUNT m2_i3 +#define VFS_PFS_FD m2_i3 +#define VFS_PFS_FILP m2_p1 + +/* Field names for the dupfrom(2) call. */ +#define VFS_DUPFROM_ENDPT m1_i1 +#define VFS_DUPFROM_FD m1_i2 + +/* Field names for GETRUSAGE related calls */ +#define RU_ENDPT m1_i1 /* indicates a process for sys_getrusage */ +#define RU_WHO m1_i1 /* who argument in getrusage call */ +#define RU_RUSAGE_ADDR m1_p1 /* pointer to struct rusage */ /*===========================================================================* * Messages for VM server * @@ -997,6 +982,9 @@ /* To VM: identify cache block in FS */ #define VM_SETCACHEPAGE (VM_RQ_BASE+27) +/* To VM: clear all cache blocks for a device */ +#define VM_CLEARCACHE (VM_RQ_BASE+28) + /* To VFS: fields for request from VM. */ # define VFS_VMCALL_REQ m10_i1 # define VFS_VMCALL_FD m10_i2 @@ -1252,7 +1240,6 @@ #define TTY_FKEY_CONTROL (TTY_RQ_BASE + 1) /* control an F-key at TTY */ -#define OLD_FKEY_CONTROL 98 /* previously used for TTY_FKEY_CONTROL */ # define FKEY_REQUEST m2_i1 /* request to perform at TTY */ # define FKEY_MAP 10 /* observe function key */ # define FKEY_UNMAP 11 /* stop observing function key */ @@ -1271,13 +1258,71 @@ #define VFS_TRANSID (VFS_TRANSACTION_BASE + 1) #define IS_VFS_FS_TRANSID(type) (((type) & ~0xff) == VFS_TRANSACTION_BASE) +/*===========================================================================* + * Messages for character devices * + *===========================================================================*/ + +/* Base type for character device requests and responses. */ +#define CDEV_RQ_BASE 0x400 +#define CDEV_RS_BASE 0x480 + +#define IS_CDEV_RQ(type) (((type) & ~0x7f) == CDEV_RQ_BASE) +#define IS_CDEV_RS(type) (((type) & ~0x7f) == CDEV_RS_BASE) + +/* Message types for character device requests. */ +#define CDEV_OPEN (CDEV_RQ_BASE + 0) /* open a minor device */ +#define CDEV_CLOSE (CDEV_RQ_BASE + 1) /* close a minor device */ +#define CDEV_READ (CDEV_RQ_BASE + 2) /* read into a buffer */ +#define CDEV_WRITE (CDEV_RQ_BASE + 3) /* write from a buffer */ +#define CDEV_IOCTL (CDEV_RQ_BASE + 4) /* I/O control operation */ +#define CDEV_CANCEL (CDEV_RQ_BASE + 5) /* cancel suspended request */ +#define CDEV_SELECT (CDEV_RQ_BASE + 6) /* test for ready operations */ + +/* Message types for character device responses. */ +#define CDEV_REPLY (CDEV_RS_BASE + 0) /* general reply code */ +#define CDEV_SEL1_REPLY (CDEV_RS_BASE + 1) /* immediate select reply */ +#define CDEV_SEL2_REPLY (CDEV_RS_BASE + 2) /* select notification reply */ + +/* Field names for block device messages. */ +#define CDEV_MINOR m10_i1 /* minor device number */ +#define CDEV_STATUS m10_i2 /* OK, error code, minor device, operations */ +#define CDEV_ACCESS m10_i2 /* access bits for open requests */ +#define CDEV_GRANT m10_i2 /* grant ID of buffer */ +#define CDEV_OPS m10_i2 /* requested select operations */ +#define CDEV_COUNT m10_i3 /* number of bytes to transfer */ +#define CDEV_USER m10_i3 /* endpoint of user process */ +#define CDEV_FLAGS m10_i4 /* transfer flags */ +#define CDEV_ID m10_l1 /* opaque request ID */ +#define CDEV_REQUEST m10_l2 /* I/O control request */ +#define CDEV_POS_LO m10_l2 /* transfer position (low bits) */ +#define CDEV_POS_HI m10_l3 /* transfer position (high bits) */ + +/* Bits in 'CDEV_ACCESS' field of block device open requests. */ +# define CDEV_R_BIT 0x01 /* open with read access */ +# define CDEV_W_BIT 0x02 /* open with write access */ +# define CDEV_NOCTTY 0x04 /* not to become the controlling TTY */ + +/* Bits in 'CDEV_FLAGS' field of block device transfer requests. */ +# define CDEV_NOFLAGS 0x00 /* no flags are set */ +# define CDEV_NONBLOCK 0x01 /* do not suspend I/O request */ + +/* Bits in 'CDEV_OPS', 'CDEV_STATUS' fields of block device select messages. */ +# define CDEV_OP_RD 0x01 /* selected for read operation */ +# define CDEV_OP_WR 0x02 /* selected for write operation */ +# define CDEV_OP_ERR 0x04 /* selected for error operation */ +# define CDEV_NOTIFY 0x08 /* notification requested */ + +/* Bits in 'CDEV_STATUS' field of block device open responses. */ +# define CDEV_CLONED 0x20000000 /* device is cloned */ +# define CDEV_CTTY 0x40000000 /* device is controlling TTY */ + /*===========================================================================* * Messages for block devices * *===========================================================================*/ /* Base type for block device requests and responses. */ -#define BDEV_RQ_BASE 0x1500 -#define BDEV_RS_BASE 0x1580 +#define BDEV_RQ_BASE 0x500 +#define BDEV_RS_BASE 0x580 #define IS_BDEV_RQ(type) (((type) & ~0x7f) == BDEV_RQ_BASE) #define IS_BDEV_RS(type) (((type) & ~0x7f) == BDEV_RS_BASE) @@ -1298,24 +1343,24 @@ #define BDEV_MINOR m10_i1 /* minor device number */ #define BDEV_STATUS m10_i1 /* OK or error code */ #define BDEV_ACCESS m10_i2 /* access bits for open requests */ -#define BDEV_REQUEST m10_i2 /* I/O control request */ #define BDEV_COUNT m10_i2 /* number of bytes or elements in transfer */ #define BDEV_GRANT m10_i3 /* grant ID of buffer or vector */ #define BDEV_FLAGS m10_i4 /* transfer flags */ +#define BDEV_USER m10_i4 /* user endpoint requesting I/O control */ #define BDEV_ID m10_l1 /* opaque request ID */ +#define BDEV_REQUEST m10_l2 /* I/O control request */ #define BDEV_POS_LO m10_l2 /* transfer position (low bits) */ #define BDEV_POS_HI m10_l3 /* transfer position (high bits) */ +/* Bits in 'BDEV_ACCESS' field of block device open requests. */ +# define BDEV_R_BIT 0x01 /* open with read access */ +# define BDEV_W_BIT 0x02 /* open with write access */ + /* Bits in 'BDEV_FLAGS' field of block device transfer requests. */ # define BDEV_NOFLAGS 0x00 /* no flags are set */ # define BDEV_FORCEWRITE 0x01 /* force write to disk immediately */ # define BDEV_NOPAGE 0x02 /* eeprom: don't send page address */ -/* Field names for GETRUSAGE related calls */ -#define RU_ENDPT m1_i1 /* indicates a process for sys_getrusage */ -#define RU_WHO m1_i1 /* who argument in getrusage call */ -#define RU_RUSAGE_ADDR m1_p1 /* pointer to struct rusage */ - /*===========================================================================* * Messages for Real Time Clocks * *===========================================================================*/ @@ -1350,4 +1395,10 @@ #define RTCDEV_Y2KBUG 0x01 /* Interpret 1980 as 2000 for RTC w/Y2K bug */ #define RTCDEV_CMOSREG 0x02 /* Also set the CMOS clock register bits. */ +/*===========================================================================* + * Internal codes used by several services * + *===========================================================================*/ + +#define SUSPEND -998 /* status to suspend caller, reply later */ + /* _MINIX_COM_H */ diff --git a/include/minix/config.h b/include/minix/config.h index 0ae3767a7..52d3c6d44 100644 --- a/include/minix/config.h +++ b/include/minix/config.h @@ -35,17 +35,6 @@ /* DMA_SECTORS may be increased to speed up DMA based drivers. */ #define DMA_SECTORS 1 /* DMA buffer size (must be >= 1) */ -/* Which processes should receive diagnostics from the kernel and system? - * Directly sending it to TTY only displays the output. Sending it to the - * log driver will cause the diagnostics to be buffered and displayed. - * Messages are sent by src/lib/sysutil/kputc.c to these processes, in - * the order of this array, which must be terminated by NONE. This is used - * by drivers and servers that printf(). - * The kernel does this for its own kprintf() in kernel/utility.c, also using - * this array, but a slightly different mechanism. - */ -#define OUTPUT_PROCS_ARRAY { TTY_PROC_NR, LOG_PROC_NR, NONE } - /* NR_CONS, NR_RS_LINES, and NR_PTYS determine the number of terminals the * system can handle. */ diff --git a/include/minix/dmap.h b/include/minix/dmap.h index b041ee3e7..c7b59d11e 100644 --- a/include/minix/dmap.h +++ b/include/minix/dmap.h @@ -4,12 +4,8 @@ #include #include -enum dev_style { STYLE_NDEV, STYLE_DEV, STYLE_DEVA, STYLE_TTY, STYLE_CTTY, - STYLE_CLONE, STYLE_CLONE_A }; -#define IS_DEV_STYLE(s) (s>=STYLE_NDEV && s<=STYLE_CLONE_A) - -#define dev_style_asyn(devstyle) ((devstyle) == STYLE_DEVA || \ - (devstyle) == STYLE_CLONE_A) +enum dev_style { STYLE_NDEV, STYLE_DEV, STYLE_TTY, STYLE_CTTY }; +#define IS_DEV_STYLE(s) (s>=STYLE_NDEV && s<=STYLE_CTTY) /*===========================================================================* * Major and minor device numbers * @@ -75,7 +71,7 @@ enum dev_style { STYLE_NDEV, STYLE_DEV, STYLE_DEVA, STYLE_TTY, STYLE_CTTY, #define BMP085B1S77_MAJOR 53 /* 53 = /dev/bmp085b1s77 (bmp085) */ #define BMP085B2S77_MAJOR 54 /* 54 = /dev/bmp085b2s77 (bmp085) */ #define BMP085B3S77_MAJOR 55 /* 55 = /dev/bmp085b3s77 (bmp085) */ - + /* 56-63 = /dev/vnd[0-7] (vnd) */ /* Minor device numbers for memory driver. */ # define RAM_DEV_OLD 0 /* minor device for /dev/ram */ diff --git a/include/minix/drvlib.h b/include/minix/drvlib.h index b2a71e381..402a89c93 100644 --- a/include/minix/drvlib.h +++ b/include/minix/drvlib.h @@ -8,6 +8,7 @@ void partition(struct blockdriver *bdr, int device, int style, int atapi); #define DEV_PER_DRIVE (1 + NR_PARTITIONS) +#define SUB_PER_DRIVE (NR_PARTITIONS * NR_PARTITIONS) #define MINOR_t0 64 #define MINOR_r0 120 #define MINOR_d0p0s0 128 diff --git a/include/minix/ioctl.h b/include/minix/ioctl.h index fe18d9d47..03f146d00 100644 --- a/include/minix/ioctl.h +++ b/include/minix/ioctl.h @@ -34,6 +34,7 @@ _IOC_IN) #define _IORW(x,y,t) ((x << 8) | y | ((sizeof(t) & _IOCPARM_MASK) << 16) |\ _IOC_INOUT) +#define _IOWR(x,y,t) _IORW(x,y,t) /* NetBSD compatibility */ #define _IOW_BIG(y,t) (y | ((sizeof(t) & _IOCPARM_MASK_BIG) << 8) \ | _IOC_IN | _IOC_BIG) diff --git a/include/minix/ipc.h b/include/minix/ipc.h index e2ddcfa32..1136d7294 100644 --- a/include/minix/ipc.h +++ b/include/minix/ipc.h @@ -29,6 +29,8 @@ typedef struct {long m9l1, m9l2, m9l3, m9l4, m9l5; short m9s1, m9s2, m9s3, m9s4; } mess_9; typedef struct {int m10i1, m10i2, m10i3, m10i4; long m10l1, m10l2, m10l3; } mess_10; +typedef struct {int m11i1; short m11s1, m11s2, m11s3, m11s4; + char *m11p1, *m11p2, *m11p3, *m11p4; } mess_11; typedef struct { void *block; @@ -68,6 +70,7 @@ typedef struct { mess_6 m_m6; mess_9 m_m9; mess_10 m_m10; + mess_11 m_m11; mess_vmmcp m_vmmcp; mess_vmmcp_reply m_vmmcp_reply; mess_vm_vfs_mmap m_vm_vfs; @@ -154,6 +157,16 @@ typedef struct { #define m10_l2 m_u.m_m10.m10l2 #define m10_l3 m_u.m_m10.m10l3 +#define m11_i1 m_u.m_m11.m11i1 +#define m11_s1 m_u.m_m11.m11s1 +#define m11_s2 m_u.m_m11.m11s2 +#define m11_s3 m_u.m_m11.m11s3 +#define m11_s4 m_u.m_m11.m11s4 +#define m11_p1 m_u.m_m11.m11p1 +#define m11_p2 m_u.m_m11.m11p2 +#define m11_p3 m_u.m_m11.m11p3 +#define m11_p4 m_u.m_m11.m11p4 + /*==========================================================================* * Minix run-time system (IPC). * *==========================================================================*/ diff --git a/include/minix/mount.h b/include/minix/mount.h index dddb4e6c8..3188694ee 100644 --- a/include/minix/mount.h +++ b/include/minix/mount.h @@ -5,16 +5,16 @@ #ifndef _MOUNT_H #define _MOUNT_H -#define MS_RDONLY 0x001 /* Mount device read only */ -#define MS_REUSE 0x002 /* Tell RS to try reusing binary from memory */ -#define MS_LABEL16 0x004 /* Mount message points to 16-byte label */ -#define MS_EXISTING 0x008 /* Tell mount to use already running server */ +/* Service flags. These are not passed to VFS. */ +#define MS_REUSE 0x001 /* Tell RS to try reusing binary from memory */ +#define MS_EXISTING 0x002 /* Tell mount to use already running server */ + +/* Legacy definitions. */ #define MNTNAMELEN 16 /* Length of fs type name including nul */ #define MNTFLAGLEN 64 /* Length of flags string including nul */ -int mount(char *_spec, char *_name, int _mountflags, char *type, char - *args); -int umount(const char *_name); -int umount2(const char *_name, int flags); +int mount(char *_spec, char *_name, int _mountflags, int srvflags, char *type, + char *args); +int umount(const char *_name, int srvflags); #endif /* _MOUNT_H */ diff --git a/include/minix/netsock.h b/include/minix/netsock.h index c341cc2fd..1a53813ef 100644 --- a/include/minix/netsock.h +++ b/include/minix/netsock.h @@ -5,6 +5,7 @@ #include #include +#include /* * User can set this variable to make the debugging output differ between @@ -18,19 +19,21 @@ extern char * netsock_user_name; #define SOCK_TYPES 3 struct socket; +struct sock_req; -typedef void (* sock_op_t)(struct socket *, message *); -typedef void (* sock_op_io_t)(struct socket *, message *, int blk); -typedef int (* sock_op_open_t)(struct socket *, message *); +typedef int (* sock_op_opcl_t)(struct socket *); +typedef int (* sock_op_io_t)(struct socket *, struct sock_req *, int blk); +typedef int (* sock_op_select_t)(struct socket *, unsigned int); +typedef int (* sock_op_select_reply_t)(struct socket *); struct sock_ops { - sock_op_open_t open; - sock_op_t close; - sock_op_io_t read; - sock_op_io_t write; - sock_op_io_t ioctl; - sock_op_t select; - sock_op_t select_reply; + sock_op_opcl_t open; + sock_op_opcl_t close; + sock_op_io_t read; + sock_op_io_t write; + sock_op_io_t ioctl; + sock_op_select_t select; + sock_op_select_reply_t select_reply; }; struct recv_q { @@ -63,6 +66,23 @@ struct recv_q { SOCK_FLG_SEL_ERROR); \ } while (0) +struct sock_req { + enum { + SOCK_REQ_READ, + SOCK_REQ_WRITE, + SOCK_REQ_IOCTL + } type; + devminor_t minor; + endpoint_t endpt; + cp_grant_id_t grant; + union { + size_t size; /* for SOCK_REQ_READ, SOCK_REQ_WRITE */ + unsigned long req; /* for SOCK_REQ_IOCTL */ + }; + int flags; + cdev_id_t id; +}; + struct socket { int type; u32_t flags; @@ -71,9 +91,7 @@ struct socket { struct sock_ops * ops; void * buf; size_t buf_size; - message mess; /* store the message which initiated the - last operation on this socket in case - we have to suspend the operation */ + struct sock_req req; void * shm; size_t shm_size; endpoint_t select_ep; @@ -87,7 +105,7 @@ struct socket { * Each component needs to provide a method how to initially open a socket. * The rest is handled byt the socket library. */ -void socket_open(message * m); +int socket_open(devminor_t minor); #define get_sock_num(x) ((long int) ((x) - socket)) #define is_valid_sock_num(x) (x < MAX_SOCKETS) @@ -100,19 +118,13 @@ void socket_open(message * m); extern struct socket socket[MAX_SOCKETS]; -void socket_request(message * m); +void socket_request(message * m, int ipc_status); void mq_process(void); - struct socket * get_unused_sock(void); struct socket * get_nic_sock(unsigned dev); -void send_reply(message * m, int status); -void send_reply_open(message * m, int status); -void send_reply_close(message * m, int status); -void sock_reply(struct socket * sock, int status); -void sock_reply_close(struct socket * sock, int status); -void sock_reply_select(struct socket * sock, unsigned selops); +void send_req_reply(struct sock_req * req, int status); typedef void (* recv_data_free_fn)(void *); @@ -139,10 +151,8 @@ static inline void * debug_malloc(size_t s) free(x); \ } while(0) -void generic_op_select(struct socket * sock, message * m); -void generic_op_select_reply(struct socket * sock, message * m); - -int mq_enqueue(message * m); +int generic_op_select(struct socket * sock, unsigned int sel); +int generic_op_select_reply(struct socket * sock); /* a function thr user has to provide to reply to the posix server */ void posix_reply(endpoint_t ep, message * m); diff --git a/include/minix/paths.h b/include/minix/paths.h index 65ea4325b..447c465af 100644 --- a/include/minix/paths.h +++ b/include/minix/paths.h @@ -17,4 +17,6 @@ #define _PATH_RAMDISK "/dev/ram" +#define _PATH_DRIVERS "/usr/sbin" + #endif /* _MINIX_PATHS_H_ */ diff --git a/include/minix/procfs.h b/include/minix/procfs.h index fec097b61..eb6733644 100644 --- a/include/minix/procfs.h +++ b/include/minix/procfs.h @@ -35,7 +35,6 @@ #define FSTATE_LOCK 'L' #define FSTATE_POPEN 'O' #define FSTATE_SELECT 'S' -#define FSTATE_DOPEN 'D' #define FSTATE_TASK 'T' #define FSTATE_UNKNOWN '?' diff --git a/include/minix/sysinfo.h b/include/minix/sysinfo.h index 88f9d6fcf..e63bb006e 100644 --- a/include/minix/sysinfo.h +++ b/include/minix/sysinfo.h @@ -13,7 +13,6 @@ int getsysinfo(endpoint_t who, int what, void *where, size_t size); #define SI_DATA_STORE 5 /* get copy of data store mappings */ #define SI_CALL_STATS 9 /* system call statistics */ #define SI_PROCPUB_TAB 11 /* copy of public entries of process table */ -#define SI_VMNT_TAB 12 /* get vmnt table */ #endif diff --git a/include/minix/syslib.h b/include/minix/syslib.h index 0d1a922da..6969a26a8 100644 --- a/include/minix/syslib.h +++ b/include/minix/syslib.h @@ -69,8 +69,6 @@ int sys_vmctl_enable_paging(void * data); int sys_readbios(phys_bytes address, void *buf, size_t size); int sys_settime(int now, clockid_t clk_id, time_t sec, long nsec); int sys_stime(time_t boottime); -int sys_sysctl(int ctl, char *arg1, int arg2); -int sys_sysctl_stacktrace(endpoint_t who); int sys_vmctl_get_mapping(int index, phys_bytes *addr, phys_bytes *len, int *flags); int sys_vmctl_reply_mapping(int index, vir_bytes addr); @@ -159,7 +157,16 @@ int sys_umap_data_fb(endpoint_t proc_ep, vir_bytes vir_addr, vir_bytes int sys_umap_remote(endpoint_t proc_ep, endpoint_t grantee, int seg, vir_bytes vir_addr, vir_bytes bytes, phys_bytes *phys_addr); -int send_taskreply(endpoint_t who, endpoint_t endpoint, int status); +/* Shorthands for sys_diagctl() system call. */ +#define sys_diagctl_diag(buf,len) \ + sys_diagctl(DIAGCTL_CODE_DIAG, buf, len) +#define sys_diagctl_stacktrace(ep) \ + sys_diagctl(DIAGCTL_CODE_STACKTRACE, NULL, ep) +#define sys_diagctl_register() \ + sys_diagctl(DIAGCTL_CODE_REGISTER, NULL, 0) +#define sys_diagctl_unregister() \ + sys_diagctl(DIAGCTL_CODE_UNREGISTER, NULL, 0) +int sys_diagctl(int ctl, char *arg1, int arg2); /* Shorthands for sys_getinfo() system call. */ #define sys_getkinfo(dst) sys_getinfo(GET_KINFO, dst, 0,0,0) diff --git a/include/minix/tty.h b/include/minix/tty.h deleted file mode 100644 index fcf8d2f97..000000000 --- a/include/minix/tty.h +++ /dev/null @@ -1,28 +0,0 @@ - -#ifndef _MINIX_TTY_H -#define _MINIX_TTY_H - -#include - -#define TTYMAGIC 0xb105 - -/* A struct that the tty driver can use to pass values to the boot monitor. - * Currently only the value of the origin of the first vty (console), so the - * boot monitor can properly display it when panicing (tty isn't scheduled - * to switch to the first vty). It's written at the end of video memory - * (video memory base + video memory size - sizeof(struct boot_tty_info). - */ - -struct boot_tty_info { - u16_t reserved[30]; /* reserved, set to 0 */ - u16_t consorigin; /* origin in video memory of console */ - u16_t conscursor; /* position of cursor of console */ - u16_t flags; /* flags indicating which fields are valid */ - u16_t magic; /* magic number indicating struct is valid */ -}; - -#define BTIF_CONSORIGIN 0x01 /* consorigin is set */ -#define BTIF_CONSCURSOR 0x02 /* conscursor is set */ - -#endif - diff --git a/include/minix/vfsif.h b/include/minix/vfsif.h index 10a8568f4..b0ad4e779 100644 --- a/include/minix/vfsif.h +++ b/include/minix/vfsif.h @@ -93,7 +93,7 @@ typedef struct { #define REQ_INHIBREAD (VFS_BASE + 7) #define REQ_STAT (VFS_BASE + 8) #define REQ_UTIME (VFS_BASE + 9) -#define REQ_FSTATFS (VFS_BASE + 10) +#define REQ_STATVFS (VFS_BASE + 10) #define REQ_BREAD (VFS_BASE + 11) #define REQ_BWRITE (VFS_BASE + 12) #define REQ_UNLINK (VFS_BASE + 13) @@ -115,11 +115,10 @@ typedef struct { #define REQ_NEWNODE (VFS_BASE + 29) #define REQ_RDLINK (VFS_BASE + 30) #define REQ_GETDENTS (VFS_BASE + 31) -#define REQ_STATVFS (VFS_BASE + 32) -#define REQ_PEEK (VFS_BASE + 33) -#define REQ_BPEEK (VFS_BASE + 34) +#define REQ_PEEK (VFS_BASE + 32) +#define REQ_BPEEK (VFS_BASE + 33) -#define NREQS 35 +#define NREQS 34 #define IS_VFS_RQ(type) (((type) & ~0xff) == VFS_BASE) @@ -127,19 +126,5 @@ typedef struct { #define TRNS_ADD_ID(t,id) (((t) << 16) | ((id) & 0xFFFF)) #define TRNS_DEL_ID(t) ((short)((t) >> 16)) -#define PFS_BASE (VFS_BASE + 100) - -#define PFS_REQ_CHECK_PERMS (PFS_BASE + 1) -#define PFS_REQ_VERIFY_FD (PFS_BASE + 2) -#define PFS_REQ_SET_FILP (PFS_BASE + 3) -#define PFS_REQ_COPY_FILP (PFS_BASE + 4) -#define PFS_REQ_PUT_FILP (PFS_BASE + 5) -#define PFS_REQ_CANCEL_FD (PFS_BASE + 6) - -#define PFS_NREQS 7 - -#define IS_PFS_VFS_RQ(type) (type >= PFS_BASE && \ - type < (PFS_BASE + PFS_NREQS)) - #endif diff --git a/include/minix/vm.h b/include/minix/vm.h index a4388ddb3..f41cbf002 100644 --- a/include/minix/vm.h +++ b/include/minix/vm.h @@ -72,6 +72,8 @@ int vm_set_cacheblock(void *block, u32_t dev, u64_t dev_offset, void *vm_map_cacheblock(u32_t dev, u64_t dev_offset, u64_t ino, u64_t ino_offset, u32_t *flags, int blocksize); +int vm_clear_cache(u32_t dev); + /* flags for vm cache functions */ #define VMMC_FLAGS_LOCKED 0x01 /* someone is updating the flags; don't read/write */ #define VMMC_DIRTY 0x02 /* dirty buffer and it may not be evicted */ diff --git a/include/stdlib.h b/include/stdlib.h index 124be16b7..2f2e697f4 100644 --- a/include/stdlib.h +++ b/include/stdlib.h @@ -271,12 +271,10 @@ int cgetustr(char *, const char *, char **); void csetexpandtc(int); int daemon(int, int); -#ifndef __minix int devname_r(dev_t, mode_t, char *, size_t); #ifndef __LIBC12_SOURCE__ __aconst char *devname(dev_t, mode_t) __RENAME(__devname50); #endif -#endif /* !__minix */ #define HN_DECIMAL 0x01 #define HN_NOSPACE 0x02 diff --git a/include/sys/ioc_fbd.h b/include/sys/ioc_fbd.h index da7266798..1aea7481f 100644 --- a/include/sys/ioc_fbd.h +++ b/include/sys/ioc_fbd.h @@ -59,8 +59,8 @@ enum { }; /* The I/O control requests. */ -#define FBDCADDRULE _IOW('F', 1, struct fbd_rule) /* add a rule */ -#define FBDCDELRULE _IOW('F', 2, fbd_rulenum_t) /* delete a rule */ -#define FBDCGETRULE _IORW('F', 3, struct fbd_rule) /* retrieve a rule */ +#define FBDCADDRULE _IOW('B', 1, struct fbd_rule) /* add a rule */ +#define FBDCDELRULE _IOW('B', 2, fbd_rulenum_t) /* delete a rule */ +#define FBDCGETRULE _IORW('B', 3, struct fbd_rule) /* retrieve a rule */ #endif /* _S_I_FBD_H */ diff --git a/include/sys/ioc_tty.h b/include/sys/ioc_tty.h index ff42c13a5..c51361f75 100644 --- a/include/sys/ioc_tty.h +++ b/include/sys/ioc_tty.h @@ -22,7 +22,6 @@ #define TIOCSWINSZ _IOW('T', 17, struct winsize) #define TIOCGPGRP _IOW('T', 18, int) #define TIOCSPGRP _IOW('T', 19, int) -#define TIOCSFON_OLD _IOW('T', 20, u8_t [8192]) #define TIOCSFON _IOW_BIG(1, u8_t [8192]) /* Keyboard ioctls. */ diff --git a/include/unistd.h b/include/unistd.h index c15848b61..b51d532a7 100644 --- a/include/unistd.h +++ b/include/unistd.h @@ -320,6 +320,7 @@ int unlinkat(int, const char *, int); /* * Implementation-defined extensions + * FIXME: most of these should be moved into syslib.h */ #ifdef __minix @@ -335,6 +336,7 @@ int mapdriver(char *label, int major, int style, int flags); pid_t getnpid(endpoint_t proc_ep); uid_t getnuid(endpoint_t proc_ep); gid_t getngid(endpoint_t proc_ep); +int dupfrom(endpoint_t endpt, int fd); ssize_t pread64(int fd, void *buf, size_t count, u64_t where); ssize_t pwrite64(int fd, const void *buf, size_t count, u64_t where); #endif /* defined(_NETBSD_SOURCE) */ diff --git a/kernel/arch/earm/pre_init.c b/kernel/arch/earm/pre_init.c index d311c28c1..7c451845b 100644 --- a/kernel/arch/earm/pre_init.c +++ b/kernel/arch/earm/pre_init.c @@ -100,9 +100,9 @@ int overlaps(multiboot_module_t *mod, int n, int cmp_mod) } /* XXX: hard-coded stuff for modules */ -#define MB_MODS_NR 12 +#define MB_MODS_NR NR_BOOT_MODULES #define MB_MODS_BASE 0x82000000 -#define MB_PARAM_MOD 0x88000000 +#define MB_PARAM_MOD 0x87800000 #define MB_MODS_ALIGN 0x00800000 /* 8 MB */ #define MB_MMAP_START 0x80000000 #define MB_MMAP_SIZE 0x10000000 /* 256 MB */ @@ -291,7 +291,7 @@ kinfo_t *pre_init(u32_t magic, u32_t ebx) * ensure this). The following methods are used in that context. Once we jump to kmain they are no * longer used and the "real" implementations are visible */ -int send_sig(endpoint_t proc_nr, int sig_nr) { return 0; } +void send_diag_sig(void) { } void minix_shutdown(timer_t *t) { arch_shutdown(RBT_PANIC); } void busy_delay_ms(int x) { } int raise(int n) { panic("raise(%d)\n", n); } diff --git a/kernel/arch/i386/pre_init.c b/kernel/arch/i386/pre_init.c index d63575e48..c946072f7 100644 --- a/kernel/arch/i386/pre_init.c +++ b/kernel/arch/i386/pre_init.c @@ -243,7 +243,7 @@ kinfo_t *pre_init(u32_t magic, u32_t ebx) return &kinfo; } -int send_sig(endpoint_t proc_nr, int sig_nr) { return 0; } +void send_diag_sig(void) { } void minix_shutdown(timer_t *t) { arch_shutdown(RBT_PANIC); } void busy_delay_ms(int x) { } int raise(int sig) { panic("raise(%d)\n", sig); } diff --git a/kernel/priv.h b/kernel/priv.h index f053c3b59..c9fb74ed6 100644 --- a/kernel/priv.h +++ b/kernel/priv.h @@ -45,6 +45,8 @@ struct priv { timer_t s_alarm_timer; /* synchronous alarm timer */ reg_t *s_stack_guard; /* stack guard word for kernel tasks */ + char s_diag_sig; /* send a SIGKMESS when diagnostics arrive? */ + int s_nr_io_range; /* allowed I/O ports */ struct io_range s_io_tab[NR_IO_RANGE]; diff --git a/kernel/proto.h b/kernel/proto.h index e59c54d6c..f33f6dd73 100644 --- a/kernel/proto.h +++ b/kernel/proto.h @@ -92,6 +92,7 @@ void fill_sendto_mask(const struct proc *rc, sys_map_t *map); int send_sig(endpoint_t proc_nr, int sig_nr); void cause_sig(proc_nr_t proc_nr, int sig_nr); void sig_delay_done(struct proc *rp); +void send_diag_sig(void); void kernel_call(message *m_user, struct proc * caller); void system_init(void); void clear_endpoint(struct proc *rc); @@ -138,8 +139,8 @@ void hook_ipc_clear(struct proc *proc); int verify_grant(endpoint_t, endpoint_t, cp_grant_id_t, vir_bytes, int, vir_bytes, vir_bytes *, endpoint_t *); -/* system/do_sysctl.c */ -int do_sysctl(struct proc * caller, message *m); +/* system/do_diagctl.c */ +int do_diagctl(struct proc * caller, message *m); #if SPROFILE /* profile.c */ diff --git a/kernel/system.c b/kernel/system.c index 3f2705ded..b412e8bd5 100644 --- a/kernel/system.c +++ b/kernel/system.c @@ -18,6 +18,7 @@ * send_sig: send a signal directly to a system process * cause_sig: take action to cause a signal to occur via a signal mgr * sig_delay_done: tell PM that a process is not sending + * send_diag_sig: send a diagnostics signal to interested processes * get_randomness: accumulate randomness in a buffer * clear_endpoint: remove a process' ability to send and receive messages * sched_proc: schedule a process @@ -241,7 +242,7 @@ void system_init(void) /* System control. */ map(SYS_ABORT, do_abort); /* abort MINIX */ map(SYS_GETINFO, do_getinfo); /* request system information */ - map(SYS_SYSCTL, do_sysctl); /* misc system manipulation */ + map(SYS_DIAGCTL, do_diagctl); /* diagnostics-related functionality */ /* Profiling. */ map(SYS_SPROF, do_sprofile); /* start/stop statistical profiling */ @@ -464,6 +465,25 @@ void sig_delay_done(struct proc *rp) cause_sig(proc_nr(rp), SIGSNDELAY); } +/*===========================================================================* + * send_diag_sig * + *===========================================================================*/ +void send_diag_sig(void) +{ +/* Send a SIGKMESS signal to all processes in receiving updates about new + * diagnostics messages. + */ + struct priv *privp; + endpoint_t ep; + + for (privp = BEG_PRIV_ADDR; privp < END_PRIV_ADDR; privp++) { + if (privp->s_proc_nr != NONE && privp->s_diag_sig == TRUE) { + ep = proc_addr(privp->s_proc_nr)->p_endpoint; + send_sig(ep, SIGKMESS); + } + } +} + /*===========================================================================* * clear_ipc * *===========================================================================*/ diff --git a/kernel/system/Makefile.inc b/kernel/system/Makefile.inc index e90b47640..431bbe584 100644 --- a/kernel/system/Makefile.inc +++ b/kernel/system/Makefile.inc @@ -25,7 +25,7 @@ SRCS+= \ do_privctl.c \ do_safecopy.c \ do_safememset.c \ - do_sysctl.c \ + do_diagctl.c \ do_getksig.c \ do_endksig.c \ do_kill.c \ diff --git a/kernel/system/do_diagctl.c b/kernel/system/do_diagctl.c new file mode 100644 index 000000000..788dddba3 --- /dev/null +++ b/kernel/system/do_diagctl.c @@ -0,0 +1,65 @@ +/* The kernel call implemented in this file: + * m_type: SYS_DIAGCTL + * + * The parameters for this kernel call are: + * DIAGCTL_CODE request + * and then request-specific arguments in DIAGCTL_ARG1 and DIAGCTL_ARG2. + */ + +#include "kernel/system.h" + + +/*===========================================================================* + * do_diagctl * + *===========================================================================*/ +int do_diagctl(struct proc * caller, message * m_ptr) +{ + vir_bytes len, buf; + static char mybuf[DIAG_BUFSIZE]; + int s, i, proc_nr; + + switch (m_ptr->DIAGCTL_CODE) { + case DIAGCTL_CODE_DIAG: + buf = (vir_bytes) m_ptr->DIAGCTL_ARG1; + len = (vir_bytes) m_ptr->DIAGCTL_ARG2; + if(len < 1 || len > DIAG_BUFSIZE) { + printf("do_diagctl: diag for %d: len %d out of range\n", + caller->p_endpoint, len); + return EINVAL; + } + if((s=data_copy_vmcheck(caller, caller->p_endpoint, buf, KERNEL, + (vir_bytes) mybuf, len)) != OK) { + printf("do_diagctl: diag for %d: len %d: copy failed: %d\n", + caller->p_endpoint, len, s); + return s; + } + for(i = 0; i < len; i++) + kputc(mybuf[i]); + kputc(END_OF_KMESS); + return OK; + case DIAGCTL_CODE_STACKTRACE: + if(!isokendpt(m_ptr->DIAGCTL_ARG2, &proc_nr)) + return EINVAL; + proc_stacktrace(proc_addr(proc_nr)); + return OK; + case DIAGCTL_CODE_REGISTER: + if (!(priv(caller)->s_flags & SYS_PROC)) + return EPERM; + priv(caller)->s_diag_sig = TRUE; + /* If the message log is not empty, send a first notification + * immediately. After bootup the log is basically never empty. + */ + if (kmess.km_size > 0 && !kinfo.do_serial_debug) + send_sig(caller->p_endpoint, SIGKMESS); + return OK; + case DIAGCTL_CODE_UNREGISTER: + if (!(priv(caller)->s_flags & SYS_PROC)) + return EPERM; + priv(caller)->s_diag_sig = FALSE; + return OK; + default: + printf("do_diagctl: invalid request %d\n", m_ptr->DIAGCTL_CODE); + return(EINVAL); + } +} + diff --git a/kernel/system/do_privctl.c b/kernel/system/do_privctl.c index 9bc2366de..ac4a77222 100644 --- a/kernel/system/do_privctl.c +++ b/kernel/system/do_privctl.c @@ -116,6 +116,7 @@ int do_privctl(struct proc * caller, message * m_ptr) reset_timer(&priv(rp)->s_alarm_timer); /* - alarm */ priv(rp)->s_asyntab= -1; /* - asynsends */ priv(rp)->s_asynsize= 0; + priv(rp)->s_diag_sig = FALSE; /* no request for diag sigs */ /* Set defaults for privilege bitmaps. */ priv(rp)->s_flags= DSRV_F; /* privilege flags */ diff --git a/kernel/system/do_sysctl.c b/kernel/system/do_sysctl.c deleted file mode 100644 index 5bc6b100a..000000000 --- a/kernel/system/do_sysctl.c +++ /dev/null @@ -1,50 +0,0 @@ -/* The kernel call implemented in this file: - * m_type: SYS_SYSCTL - * - * The parameters for this kernel call are: - * SYSCTL_CODE request - * and then request-specific arguments in SYSCTL_ARG1 and SYSCTL_ARG2. - */ - -#include "kernel/system.h" - - -/*===========================================================================* - * do_sysctl * - *===========================================================================*/ -int do_sysctl(struct proc * caller, message * m_ptr) -{ - vir_bytes len, buf; - static char mybuf[DIAG_BUFSIZE]; - int s, i, proc_nr; - - switch (m_ptr->SYSCTL_CODE) { - case SYSCTL_CODE_DIAG: - buf = (vir_bytes) m_ptr->SYSCTL_ARG1; - len = (vir_bytes) m_ptr->SYSCTL_ARG2; - if(len < 1 || len > DIAG_BUFSIZE) { - printf("do_sysctl: diag for %d: len %d out of range\n", - caller->p_endpoint, len); - return EINVAL; - } - if((s=data_copy_vmcheck(caller, caller->p_endpoint, buf, KERNEL, - (vir_bytes) mybuf, len)) != OK) { - printf("do_sysctl: diag for %d: len %d: copy failed: %d\n", - caller->p_endpoint, len, s); - return s; - } - for(i = 0; i < len; i++) - kputc(mybuf[i]); - kputc(END_OF_KMESS); - return OK; - case SYSCTL_CODE_STACKTRACE: - if(!isokendpt(m_ptr->SYSCTL_ARG2, &proc_nr)) - return EINVAL; - proc_stacktrace(proc_addr(proc_nr)); - return OK; - default: - printf("do_sysctl: invalid request %d\n", m_ptr->SYSCTL_CODE); - return(EINVAL); - } -} - diff --git a/kernel/system/do_update.c b/kernel/system/do_update.c index 38341b32a..d0f7ceb90 100644 --- a/kernel/system/do_update.c +++ b/kernel/system/do_update.c @@ -161,6 +161,7 @@ static void adjust_priv_slot(struct priv *privp, struct priv *from_privp) privp->s_int_pending = from_privp->s_int_pending; privp->s_sig_pending = from_privp->s_sig_pending; privp->s_alarm_timer = from_privp->s_alarm_timer; + privp->s_diag_sig = from_privp->s_diag_sig; } /*===========================================================================* diff --git a/kernel/table.c b/kernel/table.c index e77dc2013..425e23cdf 100644 --- a/kernel/table.c +++ b/kernel/table.c @@ -57,7 +57,6 @@ struct boot_image image[NR_BOOT_PROCS] = { {SCHED_PROC_NR, "sched" }, {VFS_PROC_NR, "vfs" }, {MEM_PROC_NR, "memory"}, -{LOG_PROC_NR, "log" }, {TTY_PROC_NR, "tty" }, {MFS_PROC_NR, "mfs" }, {VM_PROC_NR, "vm" }, diff --git a/kernel/utility.c b/kernel/utility.c index f112ee07a..d5fdbdb02 100644 --- a/kernel/utility.c +++ b/kernel/utility.c @@ -55,7 +55,7 @@ void kputc(c) int c; /* character to append */ { /* Accumulate a single character for a kernel message. Send a notification - * to the output driver if an END_OF_KMESS is encountered. + * to the output drivers if an END_OF_KMESS is encountered. */ if (c != END_OF_KMESS) { int maxblpos = sizeof(kmess.kmess_buf) - 2; @@ -75,18 +75,9 @@ int c; /* character to append */ memmove(kmess.kmess_buf, kmess.kmess_buf+1, sizeof(kmess.kmess_buf)-1); } else kmess.blpos++; - } else { - int p; - endpoint_t outprocs[] = OUTPUT_PROCS_ARRAY; - if(!(kinfo.minix_panicing || kinfo.do_serial_debug)) { - for(p = 0; outprocs[p] != NONE; p++) { - if(isokprocn(outprocs[p])) { - send_sig(outprocs[p], SIGKMESS); - } - } - } + } else if (!(kinfo.minix_panicing || kinfo.do_serial_debug)) { + send_diag_sig(); } - return; } /*===========================================================================* diff --git a/lib/libaudiodriver/audio_fw.c b/lib/libaudiodriver/audio_fw.c index 34ae2f5e8..d70a92d9b 100644 --- a/lib/libaudiodriver/audio_fw.c +++ b/lib/libaudiodriver/audio_fw.c @@ -5,27 +5,6 @@ * extra buffer space beside the dma buffer. * This driver also support sub devices, which can be independently * opened and closed. - * - * The driver supports the following operations: - * - * m_type DEVICE USER_ENDPT COUNT POSITION ADRRESS - * ----------------------------------------------------------------- - * | DEV_OPEN | device | proc nr | | | | - * |-------------+---------+---------+---------+---------+---------| - * | DEV_CLOSE | device | proc nr | | | | - * |-------------+---------+---------+---------+---------+---------| - * | DEV_READ_S | device | proc nr | bytes | | buf ptr | - * |-------------+---------+---------+---------+---------+---------| - * | DEV_WRITE_S | device | proc nr | bytes | | buf ptr | - * |-------------+---------+---------+---------+---------+---------| - * | DEV_IOCTL_S | device | proc nr |func code| | buf ptr | - * |-------------+---------+---------+---------+---------+---------| - * | DEV_STATUS | | | | | | - * |-------------+---------+---------+---------+---------+---------| - * | HARD_INT | | | | | | - * |-------------+---------+---------+---------+---------+---------| - * | SIG_STOP | | | | | | - * ----------------------------------------------------------------- * * The file contains one entry point: * @@ -47,14 +26,16 @@ #include -static int msg_open(int minor_dev_nr); +static int msg_open(devminor_t minor_dev_nr, int access, + endpoint_t user_endpt); static int msg_close(int minor_dev_nr); -static int msg_ioctl(const message *m_ptr); -static void msg_write(const message *m_ptr); -static void msg_read(message *m_ptr); -static void msg_hardware(void); -static void msg_status(message *m_ptr); -static int init_driver(void); +static ssize_t msg_read(devminor_t minor, u64_t position, endpoint_t endpt, + cp_grant_id_t grant, size_t size, int flags, cdev_id_t id); +static ssize_t msg_write(devminor_t minor, u64_t position, endpoint_t endpt, + cp_grant_id_t grant, size_t size, int flags, cdev_id_t id); +static int msg_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt, + cp_grant_id_t grant, int flags, endpoint_t user_endpt, cdev_id_t id); +static void msg_hardware(unsigned int mask); static int open_sub_dev(int sub_dev_nr, int operation); static int close_sub_dev(int sub_dev_nr); static void handle_int_write(int sub_dev_nr); @@ -63,7 +44,6 @@ static void data_to_user(sub_dev_t *sub_dev_ptr); static void data_from_user(sub_dev_t *sub_dev_ptr); static int init_buffers(sub_dev_t *sub_dev_ptr); static int get_started(sub_dev_t *sub_dev_ptr); -static void reply(int code, int replyee, int process,int status); static int io_ctl_length(int io_request); static special_file_t* get_special_file(int minor_dev_nr); static void tell_dev(vir_bytes buf, size_t size, int pci_bus, int @@ -72,7 +52,6 @@ static void tell_dev(vir_bytes buf, size_t size, int pci_bus, int static char io_ctl_buf[_IOCPARM_MASK]; static int irq_hook_id = 0; /* id of irq hook at the kernel */ static int irq_hook_set = FALSE; -static int device_available = 0;/*todo*/ /* SEF functions and variables. */ static void sef_local_startup(void); @@ -81,7 +60,15 @@ static void sef_cb_signal_handler(int signo); EXTERN int sef_cb_lu_prepare(int state); EXTERN int sef_cb_lu_state_isvalid(int state); EXTERN void sef_cb_lu_state_dump(int state); -int is_status_msg_expected = FALSE; + +static struct chardriver audio_tab = { + .cdr_open = msg_open, /* open the special file */ + .cdr_close = msg_close, /* close the special file */ + .cdr_read = msg_read, + .cdr_write = msg_write, + .cdr_ioctl = msg_ioctl, + .cdr_intr = msg_hardware +}; int main(void) { @@ -94,87 +81,9 @@ int main(void) /* Here is the main loop of the dma driver. It waits for a message, carries it out, and sends a reply. */ + chardriver_task(&audio_tab); - while(1) { - if(driver_receive(ANY, &mess, &ipc_status) != OK) { - panic("driver_receive failed"); - } - caller = mess.m_source; - - /* Now carry out the work. First check for notifications. */ - if (is_ipc_notify(ipc_status)) { - switch (_ENDPOINT_P(mess.m_source)) { - case HARDWARE: - msg_hardware(); - break; - default: - printf("%s: %d uncaught notify!\n", - drv.DriverName, mess.m_type); - } - - /* get next message */ - continue; - } - - /* Normal messages. */ - switch(mess.m_type) { - case DEV_OPEN: - /* open the special file ( = parameter) */ - r = msg_open(mess.DEVICE); - repl_mess.m_type = DEV_REVIVE; - repl_mess.REP_ENDPT = mess.USER_ENDPT; - repl_mess.REP_STATUS = r; - send(caller, &repl_mess); - - continue; - - case DEV_CLOSE: - /* close the special file ( = parameter) */ - r = msg_close(mess.DEVICE); - repl_mess.m_type = DEV_CLOSE_REPL; - repl_mess.REP_ENDPT = mess.USER_ENDPT; - repl_mess.REP_STATUS = r; - send(caller, &repl_mess); - - continue; - - case DEV_IOCTL_S: - r = msg_ioctl(&mess); - - if (r != SUSPEND) - { - repl_mess.m_type = DEV_REVIVE; - repl_mess.REP_ENDPT = mess.USER_ENDPT; - repl_mess.REP_IO_GRANT = - (unsigned)mess.IO_GRANT; - repl_mess.REP_STATUS = r; - send(caller, &repl_mess); - } - continue; - - case DEV_READ_S: - msg_read(&mess); continue; /* don't reply */ - case DEV_WRITE_S: - msg_write(&mess); continue; /* don't reply */ - case DEV_STATUS: - msg_status(&mess);continue; /* don't reply */ - case DEV_REOPEN: - /* reopen the special file ( = parameter) */ - r = msg_open(mess.DEVICE); - repl_mess.m_type = DEV_REOPEN_REPL; - repl_mess.REP_ENDPT = mess.USER_ENDPT; - repl_mess.REP_STATUS = r; - send(caller, &repl_mess); - continue; - default: - printf("%s: %d uncaught msg!\n", - drv.DriverName, mess.m_type); - continue; - } - - /* Should not be here. Just continue. */ - } - return 1; + return 0; } /*===========================================================================* @@ -205,10 +114,6 @@ static void sef_local_startup() static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info)) { /* Initialize the audio driver framework. */ - return init_driver(); -} - -static int init_driver(void) { u32_t i; char irq; static int executed = 0; sub_dev_t* sub_dev_ptr; @@ -295,7 +200,9 @@ static void sef_cb_signal_handler(int signo) } } -static int msg_open (int minor_dev_nr) { +static int msg_open(devminor_t minor_dev_nr, int UNUSED(access), + endpoint_t UNUSED(user_endpt)) +{ int r, read_chan, write_chan, io_ctl; special_file_t* special_file_ptr; @@ -318,22 +225,13 @@ static int msg_open (int minor_dev_nr) { drv.DriverName, minor_dev_nr); return EIO; } - /* init driver */ - if (!device_available) { - if (init_driver() != OK) { - printf("%s: Couldn't init driver!\n", drv.DriverName); - return EIO; - } else { - device_available = TRUE; - } - } /* open the sub devices specified in the interface header file */ if (write_chan != NO_CHANNEL) { /* open sub device for writing */ - if (open_sub_dev(write_chan, DEV_WRITE_S) != OK) return EIO; + if (open_sub_dev(write_chan, WRITE_DMA) != OK) return EIO; } if (read_chan != NO_CHANNEL) { - if (open_sub_dev(read_chan, DEV_READ_S) != OK) return EIO; + if (open_sub_dev(read_chan, READ_DMA) != OK) return EIO; } if (read_chan == io_ctl || write_chan == io_ctl) { /* io_ctl is already opened because it's the same as read or write */ @@ -383,7 +281,8 @@ static int open_sub_dev(int sub_dev_nr, int dma_mode) { } -static int msg_close(int minor_dev_nr) { +static int msg_close(devminor_t minor_dev_nr) +{ int r, read_chan, write_chan, io_ctl; special_file_t* special_file_ptr; @@ -422,7 +321,7 @@ static int close_sub_dev(int sub_dev_nr) { size_t size; sub_dev_t *sub_dev_ptr; sub_dev_ptr = &sub_dev[sub_dev_nr]; - if (sub_dev_ptr->DmaMode == DEV_WRITE_S && !sub_dev_ptr->OutOfData) { + if (sub_dev_ptr->DmaMode == WRITE_DMA && !sub_dev_ptr->OutOfData) { /* do nothing, still data in buffers that has to be transferred */ sub_dev_ptr->Opened = FALSE; /* keep DMA busy */ return OK; @@ -444,13 +343,14 @@ static int close_sub_dev(int sub_dev_nr) { } -static int msg_ioctl(const message *m_ptr) +static int msg_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt, + cp_grant_id_t grant, int flags, endpoint_t user_endpt, cdev_id_t id) { int status, len, chan; sub_dev_t *sub_dev_ptr; special_file_t* special_file_ptr; - special_file_ptr = get_special_file(m_ptr->DEVICE); + special_file_ptr = get_special_file(minor); if(special_file_ptr == NULL) { return EIO; } @@ -469,34 +369,24 @@ static int msg_ioctl(const message *m_ptr) return EIO; } + if (request & _IOC_IN) { /* if there is data for us, copy it */ + len = io_ctl_length(request); - /* this is a hack...todo: may we intercept reset calls? */ - /* - if(m_ptr->REQUEST == DSPIORESET) { - device_available = FALSE; - } - */ - - - if (m_ptr->REQUEST & _IOC_IN) { /* if there is data for us, copy it */ - len = io_ctl_length(m_ptr->REQUEST); - - if(sys_safecopyfrom(m_ptr->m_source, - (vir_bytes)m_ptr->ADDRESS, 0, - (vir_bytes)io_ctl_buf, len) != OK) { + if (sys_safecopyfrom(endpt, grant, 0, (vir_bytes)io_ctl_buf, + len) != OK) { printf("%s:%d: safecopyfrom failed\n", __FILE__, __LINE__); } } /* all ioctl's are passed to the device specific part of the driver */ - status = drv_io_ctl(m_ptr->REQUEST, (void *)io_ctl_buf, &len, chan); + status = drv_io_ctl(request, (void *)io_ctl_buf, &len, chan); /* _IOC_OUT bit -> user expects data */ - if (status == OK && m_ptr->REQUEST & _IOC_OUT) { + if (status == OK && request & _IOC_OUT) { /* copy result back to user */ - if(sys_safecopyto(m_ptr->m_source, (vir_bytes)m_ptr->ADDRESS, 0, - (vir_bytes)io_ctl_buf, len) != OK) { + if (sys_safecopyto(endpt, grant, 0, (vir_bytes)io_ctl_buf, + len) != OK) { printf("%s:%d: safecopyto failed\n", __FILE__, __LINE__); } @@ -505,18 +395,19 @@ static int msg_ioctl(const message *m_ptr) } -static void msg_write(const message *m_ptr) +static ssize_t msg_write(devminor_t minor, u64_t UNUSED(position), + endpoint_t endpt, cp_grant_id_t grant, size_t size, int UNUSED(flags), + cdev_id_t id) { int chan; sub_dev_t *sub_dev_ptr; special_file_t* special_file_ptr; - special_file_ptr = get_special_file(m_ptr->DEVICE); + special_file_ptr = get_special_file(minor); chan = special_file_ptr->write_chan; if (chan == NO_CHANNEL) { printf("%s: No write channel specified!\n", drv.DriverName); - reply(DEV_REVIVE, m_ptr->m_source, m_ptr->USER_ENDPT, EIO); - return; + return EIO; } /* get pointer to sub device data */ sub_dev_ptr = &sub_dev[chan]; @@ -524,47 +415,49 @@ static void msg_write(const message *m_ptr) if (!sub_dev_ptr->DmaBusy) { /* get fragment size on first write */ if (drv_get_frag_size(&(sub_dev_ptr->FragSize), sub_dev_ptr->Nr) != OK){ printf("%s; Failed to get fragment size!\n", drv.DriverName); - return; + return EIO; } } - if(m_ptr->COUNT != sub_dev_ptr->FragSize) { + if(size != sub_dev_ptr->FragSize) { printf("Fragment size does not match user's buffer length\n"); - reply(DEV_REVIVE, m_ptr->m_source, m_ptr->USER_ENDPT, EINVAL); - return; + return EINVAL; } /* if we are busy with something else than writing, return EBUSY */ - if(sub_dev_ptr->DmaBusy && sub_dev_ptr->DmaMode != DEV_WRITE_S) { - printf("Already busy with something else then writing\n"); - reply(DEV_REVIVE, m_ptr->m_source, m_ptr->USER_ENDPT, EBUSY); - return; + if(sub_dev_ptr->DmaBusy && sub_dev_ptr->DmaMode != WRITE_DMA) { + printf("Already busy with something else than writing\n"); + return EBUSY; } sub_dev_ptr->RevivePending = TRUE; - sub_dev_ptr->ReviveProcNr = m_ptr->USER_ENDPT; - sub_dev_ptr->ReviveGrant = (cp_grant_id_t) m_ptr->ADDRESS; - sub_dev_ptr->SourceProcNr = m_ptr->m_source; + sub_dev_ptr->ReviveId = id; + sub_dev_ptr->ReviveGrant = grant; + sub_dev_ptr->SourceProcNr = endpt; data_from_user(sub_dev_ptr); if(!sub_dev_ptr->DmaBusy) { /* Dma tranfer not yet started */ get_started(sub_dev_ptr); - sub_dev_ptr->DmaMode = DEV_WRITE_S; /* Dma mode is writing */ - } + sub_dev_ptr->DmaMode = WRITE_DMA; /* Dma mode is writing */ + } + + /* We may already have replied by now. In any case don't reply here. */ + return EDONTREPLY; } -static void msg_read(message *m_ptr) +static ssize_t msg_read(devminor_t minor, u64_t UNUSED(position), + endpoint_t endpt, cp_grant_id_t grant, size_t size, int UNUSED(flags), + cdev_id_t id) { int chan; sub_dev_t *sub_dev_ptr; special_file_t* special_file_ptr; - special_file_ptr = get_special_file(m_ptr->DEVICE); + special_file_ptr = get_special_file(minor); chan = special_file_ptr->read_chan; if (chan == NO_CHANNEL) { printf("%s: No read channel specified!\n", drv.DriverName); - reply(DEV_REVIVE, m_ptr->m_source, m_ptr->USER_ENDPT, EIO); - return; + return EIO; } /* get pointer to sub device data */ sub_dev_ptr = &sub_dev[chan]; @@ -572,39 +465,39 @@ static void msg_read(message *m_ptr) if (!sub_dev_ptr->DmaBusy) { /* get fragment size on first read */ if (drv_get_frag_size(&(sub_dev_ptr->FragSize), sub_dev_ptr->Nr) != OK){ printf("%s: Could not retrieve fragment size!\n", drv.DriverName); - reply(DEV_REVIVE, m_ptr->m_source, m_ptr->USER_ENDPT, - EIO); - return; + return EIO; } } - if(m_ptr->COUNT != sub_dev_ptr->FragSize) { - reply(DEV_REVIVE, m_ptr->m_source, m_ptr->USER_ENDPT, EINVAL); + if(size != sub_dev_ptr->FragSize) { printf("fragment size does not match message size\n"); - return; + return EINVAL; } /* if we are busy with something else than reading, reply EBUSY */ - if(sub_dev_ptr->DmaBusy && sub_dev_ptr->DmaMode != DEV_READ_S) { - reply(DEV_REVIVE, m_ptr->m_source, m_ptr->USER_ENDPT, EBUSY); - return; + if(sub_dev_ptr->DmaBusy && sub_dev_ptr->DmaMode != READ_DMA) { + return EBUSY; } sub_dev_ptr->RevivePending = TRUE; - sub_dev_ptr->ReviveProcNr = m_ptr->USER_ENDPT; - sub_dev_ptr->ReviveGrant = (cp_grant_id_t) m_ptr->ADDRESS; - sub_dev_ptr->SourceProcNr = m_ptr->m_source; + sub_dev_ptr->ReviveId = id; + sub_dev_ptr->ReviveGrant = grant; + sub_dev_ptr->SourceProcNr = endpt; if(!sub_dev_ptr->DmaBusy) { /* Dma tranfer not yet started */ get_started(sub_dev_ptr); - sub_dev_ptr->DmaMode = DEV_READ_S; /* Dma mode is reading */ - return; /* no need to get data from DMA buffer at this point */ + sub_dev_ptr->DmaMode = READ_DMA; /* Dma mode is reading */ + /* no need to get data from DMA buffer at this point */ + return EDONTREPLY; } /* check if data is available and possibly fill user's buffer */ data_to_user(sub_dev_ptr); + + /* We may already have replied by now. In any case don't reply here. */ + return EDONTREPLY; } -static void msg_hardware(void) { - +static void msg_hardware(unsigned int UNUSED(mask)) +{ u32_t i; /* loop over all sub devices */ @@ -612,8 +505,10 @@ static void msg_hardware(void) { /* if interrupt from sub device and Dma transfer was actually busy, take care of business */ if( drv_int(i) && sub_dev[i].DmaBusy ) { - if (sub_dev[i].DmaMode == DEV_WRITE_S) handle_int_write(i); - if (sub_dev[i].DmaMode == DEV_READ_S) handle_int_read(i); + if (sub_dev[i].DmaMode == WRITE_DMA) + handle_int_write(i); + if (sub_dev[i].DmaMode == READ_DMA) + handle_int_read(i); } } @@ -626,36 +521,7 @@ static void msg_hardware(void) { } -static void msg_status(message *m_ptr) -{ - int i; - - for (i = 0; i < drv.NrOfSubDevices; i++) { - - if(sub_dev[i].ReadyToRevive) - { - m_ptr->m_type = DEV_REVIVE; /* build message */ - m_ptr->REP_ENDPT = sub_dev[i].ReviveProcNr; - m_ptr->REP_IO_GRANT = sub_dev[i].ReviveGrant; - m_ptr->REP_STATUS = sub_dev[i].ReviveStatus; - send(m_ptr->m_source, m_ptr); /* send the message */ - - /* reset variables */ - sub_dev[i].ReadyToRevive = FALSE; - sub_dev[i].RevivePending = 0; - - is_status_msg_expected = TRUE; - return; /* stop after one mess, - file system will get back for other processes */ - } - } - m_ptr->m_type = DEV_NO_STATUS; - m_ptr->REP_STATUS = 0; - send(m_ptr->m_source, m_ptr); /* send DEV_NO_STATUS message */ - is_status_msg_expected = FALSE; -} - -/* handle interrupt for specified sub device; DmaMode == DEV_WRITE_S*/ +/* handle interrupt for specified sub device; DmaMode == WRITE_DMA */ static void handle_int_write(int sub_dev_nr) { sub_dev_t *sub_dev_ptr; @@ -708,10 +574,11 @@ static void handle_int_write(int sub_dev_nr) } -/* handle interrupt for specified sub device; DmaMode == DEV_READ_S */ +/* handle interrupt for specified sub device; DmaMode == READ_DMA */ static void handle_int_read(int sub_dev_nr) { sub_dev_t *sub_dev_ptr; + message m; sub_dev_ptr = &sub_dev[sub_dev_nr]; @@ -729,9 +596,9 @@ static void handle_int_read(int sub_dev_nr) printf("All buffers full, we have a problem.\n"); drv_stop(sub_dev_nr); /* stop the sub device */ sub_dev_ptr->DmaBusy = FALSE; - sub_dev_ptr->ReviveStatus = 0; /* no data for user, - this is a sad story */ - sub_dev_ptr->ReadyToRevive = TRUE; /* wake user up */ + /* no data for user, this is a sad story */ + chardriver_reply_task(sub_dev_ptr->SourceProcNr, + sub_dev_ptr->ReviveId, 0); return; } else { /* dma full, still room in extra buf; @@ -790,9 +657,6 @@ static void data_from_user(sub_dev_t *subdev) if (!subdev->RevivePending) return; /* no new data waiting to be copied */ - if (subdev->RevivePending && - subdev->ReadyToRevive) return; /* we already got this data */ - if (subdev->DmaLength < subdev->NrOfDmaFragments) { /* room in dma buf */ r = sys_safecopyfrom(subdev->SourceProcNr, @@ -834,22 +698,10 @@ static void data_from_user(sub_dev_t *subdev) drv_resume(subdev->Nr); /* resume resume the sub device */ } - subdev->ReviveStatus = subdev->FragSize; - subdev->ReadyToRevive = TRUE; - - m.m_type = DEV_REVIVE; /* build message */ - m.REP_ENDPT = subdev->ReviveProcNr; - m.REP_IO_GRANT = subdev->ReviveGrant; - m.REP_STATUS = subdev->ReviveStatus; - r= send(subdev->SourceProcNr, &m); /* send the message */ - if (r != OK) - { - printf("audio_fw: send to %d failed: %d\n", - subdev->SourceProcNr, r); - } + chardriver_reply_task(subdev->SourceProcNr, subdev->ReviveId, + subdev->FragSize); /* reset variables */ - subdev->ReadyToRevive = FALSE; subdev->RevivePending = 0; } @@ -860,7 +712,6 @@ static void data_to_user(sub_dev_t *sub_dev_ptr) message m; if (!sub_dev_ptr->RevivePending) return; /* nobody is wating for data */ - if (sub_dev_ptr->ReadyToRevive) return;/* we already filled user's buffer */ if (sub_dev_ptr->BufLength == 0 && sub_dev_ptr->DmaLength == 0) return; /* no data for user */ @@ -895,23 +746,10 @@ static void data_to_user(sub_dev_t *sub_dev_ptr) sub_dev_ptr->DmaLength -= 1; } - sub_dev_ptr->ReviveStatus = sub_dev_ptr->FragSize; - sub_dev_ptr->ReadyToRevive = TRUE; - /* drv_status will send REVIVE mess to FS*/ - - m.m_type = DEV_REVIVE; /* build message */ - m.REP_ENDPT = sub_dev_ptr->ReviveProcNr; - m.REP_IO_GRANT = sub_dev_ptr->ReviveGrant; - m.REP_STATUS = sub_dev_ptr->ReviveStatus; - r= send(sub_dev_ptr->SourceProcNr, &m); /* send the message */ - if (r != OK) - { - printf("audio_fw: send to %d failed: %d\n", - sub_dev_ptr->SourceProcNr, r); - } + chardriver_reply_task(sub_dev_ptr->SourceProcNr, sub_dev_ptr->ReviveId, + sub_dev_ptr->FragSize); /* reset variables */ - sub_dev_ptr->ReadyToRevive = FALSE; sub_dev_ptr->RevivePending = 0; } @@ -972,16 +810,6 @@ static int init_buffers(sub_dev_t *sub_dev_ptr) } -static void reply(int code, int replyee, int process, int status) { - message m; - - m.m_type = code; /* DEV_REVIVE */ - m.REP_STATUS = status; /* result of device operation */ - m.REP_ENDPT = process; /* which user made the request */ - send(replyee, &m); -} - - static int io_ctl_length(int io_request) { io_request >>= 16; return io_request & _IOCPARM_MASK; diff --git a/lib/libaudiodriver/liveupdate.c b/lib/libaudiodriver/liveupdate.c index 96b8a35fe..000da3672 100644 --- a/lib/libaudiodriver/liveupdate.c +++ b/lib/libaudiodriver/liveupdate.c @@ -1,7 +1,5 @@ #include -/* State management variables. */ -EXTERN int is_status_msg_expected; /* * - From audio_fw.h: * EXTERN drv_t drv; @@ -23,10 +21,10 @@ static void load_state_info(void) if(sub_dev[i].RevivePending) { dma_mode = sub_dev[i].DmaMode; - if(dma_mode == DEV_READ_S) { + if(dma_mode == READ_DMA) { is_read_pending = TRUE; } - else if (dma_mode == DEV_WRITE_S){ + else if (dma_mode == WRITE_DMA){ is_write_pending = TRUE; } } @@ -60,8 +58,7 @@ int sef_cb_lu_prepare(int state) break; case SEF_LU_STATE_PROTOCOL_FREE: - is_ready = (!is_read_pending && !is_write_pending - && !is_status_msg_expected); + is_ready = (!is_read_pending && !is_write_pending); break; /* Custom states. */ @@ -95,8 +92,6 @@ void sef_cb_lu_state_dump(int state) load_state_info(); sef_lu_dprint("audio: live update state = %d\n", state); - sef_lu_dprint("audio: is_status_msg_expected = %d\n", - is_status_msg_expected); sef_lu_dprint("audio: is_read_pending = %d\n", is_read_pending); sef_lu_dprint("audio: is_write_pending = %d\n", is_write_pending); @@ -105,8 +100,7 @@ void sef_cb_lu_state_dump(int state) sef_lu_dprint("audio: SEF_LU_STATE_REQUEST_FREE(%d) reached = %d\n", SEF_LU_STATE_REQUEST_FREE, (!is_read_pending && !is_write_pending)); sef_lu_dprint("audio: SEF_LU_STATE_PROTOCOL_FREE(%d) reached = %d\n", - SEF_LU_STATE_PROTOCOL_FREE, (!is_read_pending && !is_write_pending - && !is_status_msg_expected)); + SEF_LU_STATE_PROTOCOL_FREE, (!is_read_pending && !is_write_pending)); sef_lu_dprint("audio: AUDIO_STATE_READ_REQUEST_FREE(%d) reached = %d\n", AUDIO_STATE_READ_REQUEST_FREE, (!is_read_pending)); sef_lu_dprint("audio: AUDIO_STATE_WRITE_REQUEST_FREE(%d) reached = %d\n", diff --git a/lib/libbdev/bdev.c b/lib/libbdev/bdev.c index fb4dfc239..dcceff0cd 100644 --- a/lib/libbdev/bdev.c +++ b/lib/libbdev/bdev.c @@ -304,7 +304,8 @@ ssize_t bdev_scatter(dev_t dev, u64_t pos, iovec_t *vec, int count, int flags) return bdev_vrdwt(BDEV_SCATTER, dev, pos, vec, count, flags); } -static int bdev_ioctl_setup(dev_t dev, int request, void *buf, message *m) +static int bdev_ioctl_setup(dev_t dev, int request, void *buf, + endpoint_t user_endpt, message *m) { /* Set up an I/O control request. */ @@ -338,6 +339,7 @@ static int bdev_ioctl_setup(dev_t dev, int request, void *buf, message *m) m->BDEV_MINOR = minor(dev); m->BDEV_REQUEST = request; m->BDEV_GRANT = grant; + m->BDEV_USER = user_endpt; return OK; } @@ -350,7 +352,7 @@ static void bdev_ioctl_cleanup(const message *m) cpf_revoke(m->BDEV_GRANT); } -int bdev_ioctl(dev_t dev, int request, void *buf) +int bdev_ioctl(dev_t dev, int request, void *buf, endpoint_t user_endpt) { /* Perform a synchronous I/O control request. */ @@ -358,7 +360,7 @@ int bdev_ioctl(dev_t dev, int request, void *buf) int r, driver_tries = 0; do { - if ((r = bdev_ioctl_setup(dev, request, buf, &m)) != OK) + if ((r = bdev_ioctl_setup(dev, request, buf, user_endpt, &m)) != OK) break; r = bdev_sendrec(dev, &m); @@ -495,7 +497,7 @@ bdev_id_t bdev_scatter_asyn(dev_t dev, u64_t pos, iovec_t *vec, int count, } bdev_id_t bdev_ioctl_asyn(dev_t dev, int request, void *buf, - bdev_callback_t callback, bdev_param_t param) + endpoint_t user_endpt, bdev_callback_t callback, bdev_param_t param) { /* Perform an asynchronous I/O control request. */ @@ -505,7 +507,8 @@ bdev_id_t bdev_ioctl_asyn(dev_t dev, int request, void *buf, if ((call = bdev_call_alloc(1)) == NULL) return ENOMEM; - if ((r = bdev_ioctl_setup(dev, request, buf, &call->msg)) != OK) { + if ((r = bdev_ioctl_setup(dev, request, buf, user_endpt, + &call->msg)) != OK) { bdev_call_free(call); return r; @@ -622,7 +625,8 @@ int bdev_restart_asyn(bdev_call_t *call) bdev_ioctl_cleanup(&call->msg); r = bdev_ioctl_setup(call->dev, call->msg.BDEV_REQUEST, - (char *) call->vec[0].iov_addr, &call->msg); + (char *) call->vec[0].iov_addr, call->msg.BDEV_USER, + &call->msg); break; diff --git a/lib/libbdev/ipc.c b/lib/libbdev/ipc.c index ce6403e37..2c4ce2701 100644 --- a/lib/libbdev/ipc.c +++ b/lib/libbdev/ipc.c @@ -36,9 +36,17 @@ static int bdev_recover(dev_t dev, int update_endpt) */ bdev_call_t *call, *next; endpoint_t endpt; - int r, nr_tries; + int r, active, nr_tries; - printf("bdev: recovering from a driver restart on major %d\n", major(dev)); + /* Only print output if there is something to recover. Some drivers may be + * shut down and later restarted legitimately, and if they were not in use + * while that happened, there is no need to flood the console with messages. + */ + active = bdev_minor_is_open(dev) || bdev_call_iter_maj(dev, NULL, &next); + + if (active) + printf("bdev: recovering from a driver restart on major %d\n", + major(dev)); for (nr_tries = 0; nr_tries < RECOVER_TRIES; nr_tries++) { /* First update the endpoint, if necessary. */ @@ -79,7 +87,8 @@ static int bdev_recover(dev_t dev, int update_endpt) /* Recovery seems successful. We can now reissue the current * synchronous request (if any), and continue normal operation. */ - printf("bdev: recovery successful, new driver is at %d\n", endpt); + if (active) + printf("bdev: recovery successful, new driver at %d\n", endpt); return TRUE; } diff --git a/lib/libbdev/minor.c b/lib/libbdev/minor.c index 519da33eb..205f16c89 100644 --- a/lib/libbdev/minor.c +++ b/lib/libbdev/minor.c @@ -118,3 +118,19 @@ void bdev_minor_del(dev_t dev) } } } + +int bdev_minor_is_open(dev_t dev) +{ +/* Return whether any minor is open for the major of the given device. + */ + int i, major; + + major = major(dev); + + for (i = 0; i < NR_OPEN_DEVS; i++) { + if (major(open_dev[i].dev) == major) + return TRUE; + } + + return FALSE; +} diff --git a/lib/libbdev/proto.h b/lib/libbdev/proto.h index 24f11d089..51963a8e7 100644 --- a/lib/libbdev/proto.h +++ b/lib/libbdev/proto.h @@ -29,5 +29,6 @@ extern int bdev_sendrec(dev_t dev, const message *m_orig); extern int bdev_minor_reopen(dev_t dev); extern void bdev_minor_add(dev_t dev, int access); extern void bdev_minor_del(dev_t dev); +extern int bdev_minor_is_open(dev_t dev); #endif /* _BDEV_PROTO_H */ diff --git a/lib/libblockdriver/const.h b/lib/libblockdriver/const.h index 5f475e3e9..1b3495bfa 100644 --- a/lib/libblockdriver/const.h +++ b/lib/libblockdriver/const.h @@ -5,7 +5,7 @@ #define STACK_SIZE 8192 /* Maximum number of devices supported. */ -#define MAX_DEVICES 32 +#define MAX_DEVICES BLOCKDRIVER_MAX_DEVICES /* The maximum number of worker threads per device. */ #define MAX_WORKERS 32 diff --git a/lib/libblockdriver/driver.c b/lib/libblockdriver/driver.c index f45b11552..932aa576d 100644 --- a/lib/libblockdriver/driver.c +++ b/lib/libblockdriver/driver.c @@ -2,31 +2,31 @@ * * Block drivers support the following requests. Message format m10 is used. * Field names are prefixed with BDEV_. Separate field names are used for the - * "access" and "request" fields. + * "access", "request", and "user" fields. * - * m_type MINOR COUNT GRANT FLAGS ID POS_LO POS_HI - * +--------------+--------+----------+-------+-------+------+------+------+ - * | BDEV_OPEN | minor | access | | | id | | | - * |--------------+--------+----------+-------+-------+------+------+------| - * | BDEV_CLOSE | minor | | | | id | | | - * |--------------+--------+----------+-------+-------+------+------+------| - * | BDEV_READ | minor | bytes | grant | flags | id | position | - * |--------------+--------+----------+-------+-------+------+------+------| - * | BDEV_WRITE | minor | bytes | grant | flags | id | position | - * |--------------+--------+----------+-------+-------+------+------+------| - * | BDEV_GATHER | minor | elements | grant | flags | id | position | - * |--------------+--------+----------+-------+-------+------+------+------| - * | BDEV_SCATTER | minor | elements | grant | flags | id | position | - * |--------------+--------+----------+-------+-------+------+------+------| - * | BDEV_IOCTL | minor | request | grant | flags | id | | | - * ------------------------------------------------------------------------- + * m_type MINOR COUNT GRANT FLAGS ID POS_LO POS_HI + * +--------------+--------+----------+-------+-------+------+---------+------+ + * | BDEV_OPEN | minor | access | | | id | | | + * |--------------+--------+----------+-------+-------+------+---------+------| + * | BDEV_CLOSE | minor | | | | id | | | + * |--------------+--------+----------+-------+-------+------+---------+------| + * | BDEV_READ | minor | bytes | grant | flags | id | position | + * |--------------+--------+----------+-------+-------+------+---------+------| + * | BDEV_WRITE | minor | bytes | grant | flags | id | position | + * |--------------+--------+----------+-------+-------+------+---------+------| + * | BDEV_GATHER | minor | elements | grant | flags | id | position | + * |--------------+--------+----------+-------+-------+------+---------+------| + * | BDEV_SCATTER | minor | elements | grant | flags | id | position | + * |--------------+--------+----------+-------+-------+------+---------+------| + * | BDEV_IOCTL | minor | | grant | user | id | request | | + * ---------------------------------------------------------------------------- * * The following reply message is used for all requests. * * m_type STATUS ID - * +--------------+--------+----------+-------+-------+------+------+------+ - * | BDEV_REPLY | status | | | | id | | | - * ------------------------------------------------------------------------- + * +--------------+--------+----------+-------+-------+------+---------+------+ + * | BDEV_REPLY | status | | | | id | | | + * ---------------------------------------------------------------------------- * * Changes: * Oct 16, 2011 split character and block protocol (D.C. van Moolenbroek) @@ -128,40 +128,45 @@ void blockdriver_announce(int type) } /*===========================================================================* - * blockdriver_reply * + * send_reply * *===========================================================================*/ -void blockdriver_reply(message *m_ptr, int ipc_status, int reply) +static void send_reply(endpoint_t endpt, message *m_ptr, int ipc_status) { -/* Reply to a block request sent to the driver. */ - endpoint_t caller_e; - long id; +/* Send a reply message to a request. */ int r; - if (reply == EDONTREPLY) - return; - - caller_e = m_ptr->m_source; - id = m_ptr->BDEV_ID; - - memset(m_ptr, 0, sizeof(*m_ptr)); - - m_ptr->m_type = BDEV_REPLY; - m_ptr->BDEV_STATUS = reply; - m_ptr->BDEV_ID = id; - /* If we would block sending the message, send it asynchronously. The NOREPLY * flag is set because the caller may also issue a SENDREC (mixing sync and * async comm), and the asynchronous reply could otherwise end up satisfying * the SENDREC's receive part, after which our next SENDNB call would fail. */ if (IPC_STATUS_CALL(ipc_status) == SENDREC) - r = sendnb(caller_e, m_ptr); + r = sendnb(endpt, m_ptr); else - r = asynsend3(caller_e, m_ptr, AMF_NOREPLY); + r = asynsend3(endpt, m_ptr, AMF_NOREPLY); if (r != OK) - printf("blockdriver_reply: unable to send reply to %d: %d\n", - caller_e, r); + printf("blockdriver: unable to send reply to %d: %d\n", endpt, r); +} + +/*===========================================================================* + * blockdriver_reply * + *===========================================================================*/ +void blockdriver_reply(message *m_ptr, int ipc_status, int reply) +{ +/* Reply to a block request sent to the driver. */ + message m_reply; + + if (reply == EDONTREPLY) + return; + + memset(&m_reply, 0, sizeof(m_reply)); + + m_reply.m_type = BDEV_REPLY; + m_reply.BDEV_STATUS = reply; + m_reply.BDEV_ID = m_ptr->BDEV_ID; + + send_reply(m_ptr->m_source, &m_reply, ipc_status); } /*===========================================================================* @@ -175,7 +180,7 @@ static int do_open(struct blockdriver *bdp, message *mp) } /*===========================================================================* - * do_close * + * do_close * *===========================================================================*/ static int do_close(struct blockdriver *bdp, message *mp) { @@ -220,7 +225,7 @@ static int do_vrdwt(struct blockdriver *bdp, message *mp, thread_id_t id) { /* Carry out an device read or write to/from a vector of buffers. */ iovec_t iovec[NR_IOREQS]; - unsigned nr_req; + unsigned int nr_req; u64_t position; int i, do_write; ssize_t r, size; @@ -258,7 +263,7 @@ static int do_vrdwt(struct blockdriver *bdp, message *mp, thread_id_t id) * do_dioctl * *===========================================================================*/ static int do_dioctl(struct blockdriver *bdp, dev_t minor, - unsigned int request, endpoint_t endpt, cp_grant_id_t grant) + unsigned long request, endpoint_t endpt, cp_grant_id_t grant) { /* Carry out a disk-specific I/O control request. */ struct device *dv; @@ -290,7 +295,7 @@ static int do_dioctl(struct blockdriver *bdp, dev_t minor, (*bdp->bdr_geometry)(minor, &entry); } else { /* The driver doesn't care -- make up fake geometry. */ - entry.cylinders = div64u(entry.size, SECTOR_SIZE); + entry.cylinders = div64u(entry.size, SECTOR_SIZE) / (64 * 32); entry.heads = 64; entry.sectors = 32; } @@ -313,13 +318,15 @@ static int do_ioctl(struct blockdriver *bdp, message *mp) * has specified that it is a disk driver. */ dev_t minor; - unsigned int request; + unsigned long request; cp_grant_id_t grant; + endpoint_t user_endpt; int r; minor = mp->BDEV_MINOR; request = mp->BDEV_REQUEST; grant = mp->BDEV_GRANT; + user_endpt = mp->BDEV_USER; switch (request) { case BIOCTRACEBUF: @@ -343,61 +350,86 @@ static int do_ioctl(struct blockdriver *bdp, message *mp) /* fall-through */ default: if (bdp->bdr_ioctl) - r = (*bdp->bdr_ioctl)(minor, request, mp->m_source, grant); + r = (*bdp->bdr_ioctl)(minor, request, mp->m_source, grant, + user_endpt); else - r = EINVAL; + r = ENOTTY; } return r; } /*===========================================================================* - * blockdriver_handle_notify * + * do_char_open * *===========================================================================*/ -void blockdriver_handle_notify(struct blockdriver *bdp, message *m_ptr) +static void do_char_open(message *m_ptr, int ipc_status) { -/* Take care of the notifications (interrupt and clock messages) by calling - * the appropiate callback functions. Never send a reply. - */ +/* Reply to a character driver open request stating there is no such device. */ + message m_reply; - /* Call the appropriate function for this notification. */ - switch (_ENDPOINT_P(m_ptr->m_source)) { - case HARDWARE: - if (bdp->bdr_intr) - (*bdp->bdr_intr)(m_ptr->NOTIFY_ARG); - break; + memset(&m_reply, 0, sizeof(m_reply)); - case CLOCK: - if (bdp->bdr_alarm) - (*bdp->bdr_alarm)(m_ptr->NOTIFY_TIMESTAMP); - break; + m_reply.m_type = CDEV_REPLY; + m_reply.CDEV_STATUS = ENXIO; + m_reply.CDEV_ID = m_ptr->CDEV_ID; - default: - if (bdp->bdr_other) - (void) (*bdp->bdr_other)(m_ptr); - } + send_reply(m_ptr->m_source, &m_reply, ipc_status); } /*===========================================================================* - * blockdriver_handle_request * + * blockdriver_process_on_thread * *===========================================================================*/ -int blockdriver_handle_request(struct blockdriver *bdp, message *m_ptr, - thread_id_t id) +void blockdriver_process_on_thread(struct blockdriver *bdp, message *m_ptr, + int ipc_status, thread_id_t id) { -/* Call the appropiate driver function, based on the type of request. Return - * the result code that is to be sent back to the caller, or EDONTREPLY if no - * reply is to be sent. +/* Call the appropiate driver function, based on the type of request. Send + * a result code to the caller. The call is processed in the context of the + * given thread ID, which may be SINGLE_THREAD for single-threaded callers. */ int r; + /* Check for notifications first. We never reply to notifications. */ + if (is_ipc_notify(ipc_status)) { + switch (_ENDPOINT_P(m_ptr->m_source)) { + case HARDWARE: + if (bdp->bdr_intr) + (*bdp->bdr_intr)(m_ptr->NOTIFY_ARG); + break; + + case CLOCK: + if (bdp->bdr_alarm) + (*bdp->bdr_alarm)(m_ptr->NOTIFY_TIMESTAMP); + break; + + default: + if (bdp->bdr_other) + (*bdp->bdr_other)(m_ptr, ipc_status); + } + + return; /* do not send a reply */ + } + + /* Reply to character driver open requests with an error code. Otherwise, if + * someone creates a character device node for a block driver, opening that + * device node will cause the corresponding VFS thread to block forever. + */ + if (m_ptr->m_type == CDEV_OPEN) { + do_char_open(m_ptr, ipc_status); + + return; + } + /* We might get spurious requests if the driver has been restarted. Deny any * requests on devices that have not previously been opened, signaling the * caller that something went wrong. */ if (IS_BDEV_RQ(m_ptr->m_type) && !is_open_dev(m_ptr->BDEV_MINOR)) { /* Reply ERESTART to spurious requests for unopened devices. */ - if (m_ptr->m_type != BDEV_OPEN) - return ERESTART; + if (m_ptr->m_type != BDEV_OPEN) { + blockdriver_reply(m_ptr, ipc_status, ERESTART); + + return; + } /* Mark the device as opened otherwise. */ set_open_dev(m_ptr->BDEV_MINOR); @@ -415,10 +447,10 @@ int blockdriver_handle_request(struct blockdriver *bdp, message *m_ptr, case BDEV_SCATTER: r = do_vrdwt(bdp, m_ptr, id); break; case BDEV_IOCTL: r = do_ioctl(bdp, m_ptr); break; default: - if (bdp->bdr_other) - r = bdp->bdr_other(m_ptr); - else - r = EINVAL; + if (bdp->bdr_other != NULL) + (*bdp->bdr_other)(m_ptr, ipc_status); + + return; /* do not send a reply */ } /* Let the driver perform any cleanup. */ @@ -427,5 +459,5 @@ int blockdriver_handle_request(struct blockdriver *bdp, message *m_ptr, trace_finish(id, r); - return r; + blockdriver_reply(m_ptr, ipc_status, r); } diff --git a/lib/libblockdriver/driver.h b/lib/libblockdriver/driver.h index 92dfb8cad..d02f5f71f 100644 --- a/lib/libblockdriver/driver.h +++ b/lib/libblockdriver/driver.h @@ -1,9 +1,8 @@ #ifndef _BLOCKDRIVER_DRIVER_H #define _BLOCKDRIVER_DRIVER_H -void blockdriver_handle_notify(struct blockdriver *bdp, message *m_ptr); -int blockdriver_handle_request(struct blockdriver *bdp, message *m_ptr, - thread_id_t thread); +void blockdriver_process_on_thread(struct blockdriver *bdp, message *m_ptr, + int ipc_status, thread_id_t thread); void blockdriver_reply(message *m_ptr, int ipc_status, int reply); #endif /* _BLOCKDRIVER_DRIVER_H */ diff --git a/lib/libblockdriver/driver_mt.c b/lib/libblockdriver/driver_mt.c index 31be86fec..6a8a5ef67 100644 --- a/lib/libblockdriver/driver_mt.c +++ b/lib/libblockdriver/driver_mt.c @@ -184,9 +184,7 @@ static void *worker_thread(void *param) mthread_rwlock_wrlock(&dp->barrier); /* Handle the request and send a reply. */ - r = blockdriver_handle_request(bdtab, &m, tid); - - blockdriver_reply(&m, ipc_status, r); + blockdriver_process_on_thread(bdtab, &m, ipc_status, tid); /* Switch the thread back to running state, and unlock the barrier. */ wp->state = STATE_RUNNING; @@ -274,13 +272,14 @@ static void master_handle_exits(void) } /*===========================================================================* - * master_handle_request * + * master_handle_message * *===========================================================================*/ -static void master_handle_request(message *m_ptr, int ipc_status) +static void master_handle_message(message *m_ptr, int ipc_status) { /* For real request messages, query the device ID, start a thread if none is * free and the maximum number of threads for that device has not yet been - * reached, and enqueue the message in the devices's message queue. + * reached, and enqueue the message in the devices's message queue. All other + * messages are handled immediately from the main thread. */ device_id_t id; worker_t *wp; @@ -291,11 +290,9 @@ static void master_handle_request(message *m_ptr, int ipc_status) * associated with it, and thus we can not tell which thread should process * it either. In that case, the master thread has to handle it instead. */ - if (!IS_BDEV_RQ(m_ptr->m_type)) { + if (is_ipc_notify(ipc_status) || !IS_BDEV_RQ(m_ptr->m_type)) { /* Process as 'other' message. */ - r = blockdriver_handle_request(bdtab, m_ptr, MAIN_THREAD); - - blockdriver_reply(m_ptr, ipc_status, r); + blockdriver_process_on_thread(bdtab, m_ptr, ipc_status, MAIN_THREAD); return; } @@ -423,10 +420,7 @@ void blockdriver_mt_task(struct blockdriver *driver_tab) blockdriver_mt_receive(&mess, &ipc_status); /* Dispatch the message. */ - if (is_ipc_notify(ipc_status)) - blockdriver_handle_notify(bdtab, &mess); - else - master_handle_request(&mess, ipc_status); + master_handle_message(&mess, ipc_status); /* Let other threads run. */ mthread_yield_all(); diff --git a/lib/libblockdriver/driver_st.c b/lib/libblockdriver/driver_st.c index 3fb10632e..4b105a31a 100644 --- a/lib/libblockdriver/driver_st.c +++ b/lib/libblockdriver/driver_st.c @@ -6,7 +6,6 @@ * The entry points into this file are: * blockdriver_task: the main message loop of the driver * blockdriver_terminate: break out of the main message loop - * blockdriver_handle_msg: handle a single received message * blockdriver_receive_mq: message receive interface with message queueing * blockdriver_mq_queue: queue an incoming message for later processing */ @@ -43,6 +42,8 @@ void blockdriver_terminate(void) /* Break out of the main driver loop after finishing the current request. */ running = FALSE; + + sef_cancel(); } /*===========================================================================* @@ -60,8 +61,12 @@ void blockdriver_task(struct blockdriver *bdp) * it out, and sends a reply. */ while (running) { - if ((r = blockdriver_receive_mq(&mess, &ipc_status)) != OK) + if ((r = blockdriver_receive_mq(&mess, &ipc_status)) != OK) { + if (r == EINTR && !running) + break; + panic("blockdriver_receive_mq failed: %d", r); + } blockdriver_process(bdp, &mess, ipc_status); } @@ -74,18 +79,8 @@ void blockdriver_process(struct blockdriver *bdp, message *m_ptr, int ipc_status) { /* Handle the given received message. */ - int r; - /* Process the notification or request. */ - if (is_ipc_notify(ipc_status)) { - blockdriver_handle_notify(bdp, m_ptr); - - /* Do not reply to notifications. */ - } else { - r = blockdriver_handle_request(bdp, m_ptr, SINGLE_THREAD); - - blockdriver_reply(m_ptr, ipc_status, r); - } + blockdriver_process_on_thread(bdp, m_ptr, ipc_status, SINGLE_THREAD); } /*===========================================================================* diff --git a/lib/libblockdriver/trace.c b/lib/libblockdriver/trace.c index 395066847..555470266 100644 --- a/lib/libblockdriver/trace.c +++ b/lib/libblockdriver/trace.c @@ -48,7 +48,7 @@ static u32_t trace_gettime(void) /*===========================================================================* * trace_ctl * *===========================================================================*/ -int trace_ctl(dev_t minor, unsigned int request, endpoint_t endpt, +int trace_ctl(dev_t minor, unsigned long request, endpoint_t endpt, cp_grant_id_t grant) { /* Process a block trace control request. @@ -195,7 +195,7 @@ void trace_start(thread_id_t id, message *m_ptr) switch (m_ptr->m_type) { case BDEV_OPEN: case BDEV_CLOSE: - pos = ((u64_t)(0)); + pos = 0; size = m_ptr->BDEV_ACCESS; flags = 0; @@ -212,7 +212,7 @@ void trace_start(thread_id_t id, message *m_ptr) break; case BDEV_IOCTL: - pos = ((u64_t)(0)); + pos = 0; size = m_ptr->BDEV_REQUEST; flags = 0; diff --git a/lib/libblockdriver/trace.h b/lib/libblockdriver/trace.h index 4bf3bfdf4..bb15289d9 100644 --- a/lib/libblockdriver/trace.h +++ b/lib/libblockdriver/trace.h @@ -1,7 +1,7 @@ #ifndef _BLOCKDRIVER_TRACE_H #define _BLOCKDRIVER_TRACE_H -int trace_ctl(dev_t minor, unsigned int request, endpoint_t endpt, +int trace_ctl(dev_t minor, unsigned long request, endpoint_t endpt, cp_grant_id_t grant); void trace_start(thread_id_t thread_id, message *m_ptr); diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc index 142fbb318..69d9e21f1 100644 --- a/lib/libc/gen/Makefile.inc +++ b/lib/libc/gen/Makefile.inc @@ -9,10 +9,10 @@ .if defined(__MINIX) # Unsupported by Minix. -# closefrom.c confstr.c extattr.c getdevmajor.c getmntinfo.c \ +# closefrom.c confstr.c extattr.c getdevmajor.c \ # pthread_atfork.c setdomainname.c sethostname.c setproctitle.c \ # sysctl.c sysctlbyname.c sysctlgetmibinfo.c sysctlnametomib.c \ -# devname.c wait3.c +# wait3.c # To be ported # nlist.c nlist_aout.c nlist_coff.c nlist_ecoff.c nlist_elf32.c nlist_elf64.c @@ -26,13 +26,13 @@ SRCS+= _errno.c alarm.c alphasort.c arc4random.c assert.c basename.c clock.c \ closedir.c \ ctermid.c ctype_.c daemon.c \ - dehumanize_number.c dirname.c err.c errx.c \ + dehumanize_number.c devname.c dirname.c err.c errx.c \ errlist.c errno.c execl.c execle.c execlp.c execv.c execvp.c \ fmtcheck.c fmtmsg.c fnmatch.c fstab.c ftok.c \ fts.c ftw.c getbsize.c getcap.c getcwd.c \ getdomainname.c getgrent.c \ getgrouplist.c getgroupmembership.c gethostname.c \ - getloadavg.c getlogin.c \ + getloadavg.c getlogin.c getmntinfo.c \ getnetgrent.c getpagesize.c \ getpass.c getprogname.c getpwent.c getttyent.c \ getusershell.c glob.c humanize_number.c initdir.c initgroups.c \ diff --git a/lib/libc/gen/devname.c b/lib/libc/gen/devname.c index f6719108f..d48b51e77 100644 --- a/lib/libc/gen/devname.c +++ b/lib/libc/gen/devname.c @@ -49,6 +49,7 @@ __RCSID("$NetBSD: devname.c,v 1.22 2012/06/03 21:42:46 joerg Exp $"); __weak_alias(devname_r,_devname_r) #endif +#ifndef __minix static once_t db_opened = ONCE_INITIALIZER; static struct cdbr *db; static devmajor_t pts; @@ -101,6 +102,7 @@ devname_ptslookup(dev_t dev, mode_t type, char *path, size_t len) return ERANGE; return 0; } +#endif static int devname_fts(dev_t dev, mode_t type, char *path, size_t len) @@ -140,6 +142,7 @@ devname_r(dev_t dev, mode_t type, char *path, size_t len) { int rv; +#ifndef __minix thr_once(&db_opened, devname_dbopen); if (db != NULL) { @@ -154,6 +157,7 @@ devname_r(dev_t dev, mode_t type, char *path, size_t len) if (db != NULL) return ENOENT; +#endif rv = devname_fts(dev, type, path, len); return rv; } diff --git a/lib/libc/include/namespace.h b/lib/libc/include/namespace.h index 84d39338a..930a8acf2 100644 --- a/lib/libc/include/namespace.h +++ b/lib/libc/include/namespace.h @@ -284,6 +284,7 @@ #define freeaddrinfo _freeaddrinfo #define freeifaddrs _freeifaddrs #define fstatvfs _fstatvfs +#define fstatvfs1 _fstatvfs1 #define ftok _ftok #define ftruncate _ftruncate #define fts_children _fts_children @@ -366,6 +367,7 @@ #define getttyent _getttyent #define getttynam _getttynam #define getusershell _getusershell +#define getvfsstat _getvfsstat #define glob _glob #define globfree _globfree #define gmtime_r _gmtime_r @@ -599,6 +601,7 @@ #define srand48 _srand48 #define srandom _srandom #define statvfs(a, b) _statvfs(a, b) +#define statvfs1 _statvfs1 #define strcasecmp _strcasecmp #define strdup _strdup #define stresep _stresep @@ -920,7 +923,6 @@ #define stime _stime #define umask _umask #define umount _umount -#define umount2 _umount2 #define unlink _unlink #define vm_remap _vm_remap #define vm_unmap _vm_unmap diff --git a/lib/libc/sys-minix/MISSING_SYSCALLS b/lib/libc/sys-minix/MISSING_SYSCALLS index 98ee058c0..2d50827e7 100644 --- a/lib/libc/sys-minix/MISSING_SYSCALLS +++ b/lib/libc/sys-minix/MISSING_SYSCALLS @@ -14,7 +14,6 @@ getpgid setrlimit getrusage getsid -getvfsstat issetugid /* WARNING: Always returns 0 in this impl. */ kevent kqueue diff --git a/lib/libc/sys-minix/Makefile.inc b/lib/libc/sys-minix/Makefile.inc index 890b66d87..38ef33de8 100644 --- a/lib/libc/sys-minix/Makefile.inc +++ b/lib/libc/sys-minix/Makefile.inc @@ -8,6 +8,7 @@ SRCS+= accept.c access.c adjtime.c bind.c brk.c sbrk.c m_closefrom.c getsid.c \ getgroups.c getitimer.c setitimer.c __getlogin.c getpeername.c \ getpgrp.c getpid.c getppid.c priority.c getrlimit.c getsockname.c \ getsockopt.c setsockopt.c gettimeofday.c geteuid.c getuid.c \ + getvfsstat.c \ ioctl.c issetugid.c kill.c link.c listen.c loadname.c lseek.c \ minix_rs.c mkdir.c mkfifo.c mknod.c mmap.c mount.c nanosleep.c \ open.c pathconf.c pipe.c poll.c pread.c ptrace.c pwrite.c \ diff --git a/lib/libc/sys-minix/accept.c b/lib/libc/sys-minix/accept.c index 88c9c9c0c..bccb81a2a 100644 --- a/lib/libc/sys-minix/accept.c +++ b/lib/libc/sys-minix/accept.c @@ -33,11 +33,11 @@ int accept(int sock, struct sockaddr *__restrict address, nwio_udpopt_t udpopt; r= _tcp_accept(sock, address, address_len); - if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL)) + if (r != -1 || errno != ENOTTY) return r; r= _uds_accept(sock, address, address_len); - if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL)) + if (r != -1 || errno != ENOTTY) return r; /* Unfortunately, we have to return EOPNOTSUPP for a socket that @@ -51,7 +51,7 @@ int accept(int sock, struct sockaddr *__restrict address, errno= EOPNOTSUPP; return -1; } - if ((errno == ENOTTY || errno == EBADIOCTL)) + if (errno == ENOTTY) { errno= ENOTSOCK; return -1; diff --git a/lib/libc/sys-minix/bind.c b/lib/libc/sys-minix/bind.c index 47c90d8cd..faf26d632 100644 --- a/lib/libc/sys-minix/bind.c +++ b/lib/libc/sys-minix/bind.c @@ -45,7 +45,7 @@ int bind(int sock, const struct sockaddr *address, socklen_t address_len) struct sockaddr_un uds_addr; r= ioctl(sock, NWIOGTCPCONF, &tcpconf); - if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL)) + if (r != -1 || errno != ENOTTY) { if (r == -1) return r; @@ -63,7 +63,7 @@ int bind(int sock, const struct sockaddr *address, socklen_t address_len) } r= ioctl(sock, NWIOGUDPOPT, &udpopt); - if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL)) + if (r != -1 || errno != ENOTTY) { if (r == -1) return r; @@ -71,7 +71,7 @@ int bind(int sock, const struct sockaddr *address, socklen_t address_len) } r= ioctl(sock, NWIOGUDSADDR, &uds_addr); - if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL)) + if (r != -1 || errno != ENOTTY) { if (r == -1) return r; diff --git a/lib/libc/sys-minix/connect.c b/lib/libc/sys-minix/connect.c index 3ef50854e..dd5b7b7f5 100644 --- a/lib/libc/sys-minix/connect.c +++ b/lib/libc/sys-minix/connect.c @@ -39,7 +39,7 @@ int connect(int sock, const struct sockaddr *address, nwio_udpopt_t udpopt; r= ioctl(sock, NWIOGTCPCONF, &tcpconf); - if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL)) + if (r != -1 || errno != ENOTTY) { if (r == -1) { @@ -50,7 +50,7 @@ int connect(int sock, const struct sockaddr *address, } r= ioctl(sock, NWIOGUDPOPT, &udpopt); - if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL)) + if (r != -1 || errno != ENOTTY) { if (r == -1) { @@ -61,9 +61,7 @@ int connect(int sock, const struct sockaddr *address, } r= _uds_connect(sock, address, address_len); - if (r != -1 || - (errno != ENOTTY && errno != EBADIOCTL && - errno != EAFNOSUPPORT)) + if (r != -1 || (errno != ENOTTY && errno != EAFNOSUPPORT)) { if (r == -1) { diff --git a/lib/libc/sys-minix/fstatfs.c b/lib/libc/sys-minix/fstatfs.c index 82ec2e044..89c0349eb 100644 --- a/lib/libc/sys-minix/fstatfs.c +++ b/lib/libc/sys-minix/fstatfs.c @@ -4,6 +4,7 @@ #include #include +#include #ifdef __weak_alias __weak_alias(fstatfs, _fstatfs) @@ -11,9 +12,13 @@ __weak_alias(fstatfs, _fstatfs) int fstatfs(int fd, struct statfs *buffer) { - message m; + struct statvfs svbuffer; + int r; - m.m1_i1 = fd; - m.m1_p1 = (char *) buffer; - return(_syscall(VFS_PROC_NR, FSTATFS, &m)); + if ((r = fstatvfs(fd, &svbuffer)) != 0) + return r; + + buffer->f_bsize = svbuffer.f_bsize; + + return 0; } diff --git a/lib/libc/sys-minix/fstatvfs.c b/lib/libc/sys-minix/fstatvfs.c index 63e4d39e5..c4bbb9e15 100644 --- a/lib/libc/sys-minix/fstatvfs.c +++ b/lib/libc/sys-minix/fstatvfs.c @@ -5,14 +5,21 @@ #include #ifdef __weak_alias +__weak_alias(fstatvfs1, _fstatvfs1) __weak_alias(fstatvfs, _fstatvfs) #endif -int fstatvfs(int fd, struct statvfs *buffer) +int fstatvfs1(int fd, struct statvfs *buffer, int flags) { message m; - m.FSTATVFS_FD = fd; - m.FSTATVFS_BUF = (char *) buffer; - return(_syscall(VFS_PROC_NR, FSTATVFS, &m)); + m.VFS_FSTATVFS1_FD = fd; + m.VFS_FSTATVFS1_BUF = (char *) buffer; + m.VFS_FSTATVFS1_FLAGS = flags; + return(_syscall(VFS_PROC_NR, FSTATVFS1, &m)); +} + +int fstatvfs(int fd, struct statvfs *buffer) +{ + return fstatvfs1(fd, buffer, ST_WAIT); } diff --git a/lib/libc/sys-minix/getpeername.c b/lib/libc/sys-minix/getpeername.c index d0487248a..a6a68851c 100644 --- a/lib/libc/sys-minix/getpeername.c +++ b/lib/libc/sys-minix/getpeername.c @@ -30,7 +30,7 @@ int getpeername(int sock, struct sockaddr *__restrict address, struct sockaddr_un uds_addr; r= ioctl(sock, NWIOGTCPCONF, &tcpconf); - if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL)) + if (r != -1 || errno != ENOTTY) { if (r == -1) { @@ -42,7 +42,7 @@ int getpeername(int sock, struct sockaddr *__restrict address, } r= ioctl(sock, NWIOGUDSPADDR, &uds_addr); - if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL)) + if (r != -1 || errno != ENOTTY) { if (r == -1) { diff --git a/lib/libc/sys-minix/getsockname.c b/lib/libc/sys-minix/getsockname.c index d6ea05787..e1cb73050 100644 --- a/lib/libc/sys-minix/getsockname.c +++ b/lib/libc/sys-minix/getsockname.c @@ -43,7 +43,7 @@ int getsockname(int fd, struct sockaddr *__restrict address, #endif r= ioctl(fd, NWIOGTCPCONF, &tcpconf); - if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL)) + if (r != -1 || errno != ENOTTY) { if (r == -1) { @@ -55,7 +55,7 @@ int getsockname(int fd, struct sockaddr *__restrict address, } r= ioctl(fd, NWIOGUDSADDR, &uds_addr); - if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL)) + if (r != -1 || errno != ENOTTY) { if (r == -1) { diff --git a/lib/libc/sys-minix/getsockopt.c b/lib/libc/sys-minix/getsockopt.c index c37b5dc36..cf22862eb 100644 --- a/lib/libc/sys-minix/getsockopt.c +++ b/lib/libc/sys-minix/getsockopt.c @@ -39,7 +39,7 @@ int getsockopt(int sock, int level, int option_name, struct sockaddr_un uds_addr; r= ioctl(sock, NWIOGTCPOPT, &tcpopt); - if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL)) + if (r != -1 || errno != ENOTTY) { if (r == -1) { @@ -51,7 +51,7 @@ int getsockopt(int sock, int level, int option_name, } r= ioctl(sock, NWIOGUDPOPT, &udpopt); - if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL)) + if (r != -1 || errno != ENOTTY) { if (r == -1) { @@ -63,7 +63,7 @@ int getsockopt(int sock, int level, int option_name, } r= ioctl(sock, NWIOGUDSADDR, &uds_addr); - if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL)) + if (r != -1 || errno != ENOTTY) { if (r == -1) { diff --git a/lib/libc/sys-minix/getvfsstat.c b/lib/libc/sys-minix/getvfsstat.c new file mode 100644 index 000000000..69a086496 --- /dev/null +++ b/lib/libc/sys-minix/getvfsstat.c @@ -0,0 +1,19 @@ +#include +#include +#include "namespace.h" + +#include + +#ifdef __weak_alias +__weak_alias(getvfsstat, _getvfsstat) +#endif + +int getvfsstat(struct statvfs *buf, size_t bufsize, int flags) +{ + message m; + + m.VFS_GETVFSSTAT_BUF = (char *) buf; + m.VFS_GETVFSSTAT_SIZE = bufsize; + m.VFS_GETVFSSTAT_FLAGS = flags; + return(_syscall(VFS_PROC_NR, GETVFSSTAT, &m)); +} diff --git a/lib/libc/sys-minix/ioctl.c b/lib/libc/sys-minix/ioctl.c index c61478473..fa2d00f94 100644 --- a/lib/libc/sys-minix/ioctl.c +++ b/lib/libc/sys-minix/ioctl.c @@ -73,9 +73,9 @@ void *data; break; } - m.TTY_LINE = fd; - m.TTY_REQUEST = request; - m.ADDRESS = (char *) addr; + m.VFS_IOCTL_FD = fd; + m.VFS_IOCTL_REQ = request; + m.VFS_IOCTL_ARG = (char *) addr; r = _syscall(VFS_PROC_NR, IOCTL, &m); diff --git a/lib/libc/sys-minix/listen.c b/lib/libc/sys-minix/listen.c index e700b77ed..f8e196786 100644 --- a/lib/libc/sys-minix/listen.c +++ b/lib/libc/sys-minix/listen.c @@ -21,11 +21,11 @@ int listen(int sock, int backlog) int r; r= ioctl(sock, NWIOTCPLISTENQ, &backlog); - if (r != -1 || errno != EBADIOCTL) + if (r != -1 || errno != ENOTTY) return r; r= ioctl(sock, NWIOSUDSBLOG, &backlog); - if (r != -1 || errno != EBADIOCTL) + if (r != -1 || errno != ENOTTY) return r; #if DEBUG diff --git a/lib/libc/sys-minix/mount.c b/lib/libc/sys-minix/mount.c index 3bfd98cb8..fabb6a78d 100644 --- a/lib/libc/sys-minix/mount.c +++ b/lib/libc/sys-minix/mount.c @@ -16,7 +16,6 @@ #ifdef __weak_alias __weak_alias(mount, _mount) __weak_alias(umount, _umount) -__weak_alias(umount2, _umount2) #endif #define FSDEFAULT "mfs" @@ -33,9 +32,9 @@ static int rs_down(char *label) } char *find_rslabel(char *args_line); -int mount(special, name, mountflags, type, args) +int mount(special, name, mountflags, srvflags, type, args) char *name, *special, *type, *args; -int mountflags; +int mountflags, srvflags; { int r; message m; @@ -54,16 +53,12 @@ int mountflags; reuse = 0; memset(path, '\0', sizeof(path)); - /* Check mount flags */ - if(mountflags & MS_REUSE) { + /* Check service flags. */ + if(srvflags & MS_REUSE) reuse = 1; - mountflags &= ~MS_REUSE; /* Temporary: turn off to not confuse VFS */ - } - if(mountflags & MS_EXISTING) { + if(srvflags & MS_EXISTING) use_existing = 1; - mountflags &= ~MS_EXISTING; /* Temporary: turn off to not confuse VFS */ - } /* Make a label for the file system process. This label must be unique and * may currently not exceed 16 characters including terminating null. For @@ -104,9 +99,6 @@ int mountflags; } } - /* Tell VFS that we are passing in a 16-byte label. */ - mountflags |= MS_LABEL16; - /* Sanity check on user input. */ if(strchr(args, '\'')) { errno = EINVAL; @@ -156,12 +148,15 @@ int mountflags; } /* Now perform mount(). */ - m.m1_i1 = special ? strlen(special) + 1 : 0; - m.m1_i2 = strlen(name) + 1; - m.m1_i3 = mountflags; - m.m1_p1 = special; - m.m1_p2 = name; - m.m1_p3 = label; + m.VFS_MOUNT_FLAGS = mountflags; + m.VFS_MOUNT_DEVLEN = special ? strlen(special) + 1 : 0; + m.VFS_MOUNT_PATHLEN = strlen(name) + 1; + m.VFS_MOUNT_TYPELEN = strlen(type) + 1; + m.VFS_MOUNT_LABELLEN = strlen(label) + 1; + m.VFS_MOUNT_DEV = special; + m.VFS_MOUNT_PATH = name; + m.VFS_MOUNT_TYPE = type; + m.VFS_MOUNT_LABEL = label; r = _syscall(VFS_PROC_NR, MOUNT, &m); if (r != OK && !use_existing) { @@ -174,30 +169,25 @@ int mountflags; return r; } -int umount(name) +int umount(name, srvflags) const char *name; +int srvflags; { - return umount2(name, 0); -} - -int umount2(name, flags) -const char *name; -int flags; -{ + char label[16]; message m; int r; - - _loadname(name, &m); + m.VFS_UMOUNT_NAME = __UNCONST(name); + m.VFS_UMOUNT_NAMELEN = strlen(name) + 1; + m.VFS_UMOUNT_LABEL = label; + m.VFS_UMOUNT_LABELLEN = sizeof(label); r = _syscall(VFS_PROC_NR, UMOUNT, &m); /* don't shut down the driver when exist flag is set */ - if (!(flags & MS_EXISTING)) { + if (!(srvflags & MS_EXISTING)) { if (r == OK) { - /* VFS returns the label of the unmounted file system in the reply. - * As of writing, the size of the m3_ca1 field is 16 bytes. - */ - rs_down(m.m3_ca1); + /* VFS returns the label of the unmounted file system to us. */ + rs_down(label); } } diff --git a/lib/libc/sys-minix/recvfrom.c b/lib/libc/sys-minix/recvfrom.c index 091559f9e..0cc663321 100644 --- a/lib/libc/sys-minix/recvfrom.c +++ b/lib/libc/sys-minix/recvfrom.c @@ -50,7 +50,7 @@ ssize_t recvfrom(int sock, void *__restrict buffer, size_t length, #endif r= ioctl(sock, NWIOGTCPCONF, &tcpconf); - if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL)) + if (r != -1 || errno != ENOTTY) { if (r == -1) return r; @@ -59,7 +59,7 @@ ssize_t recvfrom(int sock, void *__restrict buffer, size_t length, } r= ioctl(sock, NWIOGUDPOPT, &udpopt); - if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL)) + if (r != -1 || errno != ENOTTY) { if (r == -1) return r; @@ -68,7 +68,7 @@ ssize_t recvfrom(int sock, void *__restrict buffer, size_t length, } r= ioctl(sock, NWIOGUDSSOTYPE, &uds_sotype); - if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL)) + if (r != -1 || errno != ENOTTY) { if (r == -1) { diff --git a/lib/libc/sys-minix/recvmsg.c b/lib/libc/sys-minix/recvmsg.c index 057d7f1d5..49ee7c13a 100644 --- a/lib/libc/sys-minix/recvmsg.c +++ b/lib/libc/sys-minix/recvmsg.c @@ -26,7 +26,7 @@ ssize_t recvmsg(int sock, struct msghdr *msg, int flags) } r= ioctl(sock, NWIOGUDSSOTYPE, &uds_sotype); - if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL)) { + if (r != -1 || errno != ENOTTY) { if (r == -1) { return r; } diff --git a/lib/libc/sys-minix/sendmsg.c b/lib/libc/sys-minix/sendmsg.c index 6ffa7ab0f..4d97f79ac 100644 --- a/lib/libc/sys-minix/sendmsg.c +++ b/lib/libc/sys-minix/sendmsg.c @@ -29,7 +29,7 @@ ssize_t sendmsg(int sock, const struct msghdr *msg, int flags) } r= ioctl(sock, NWIOGUDSSOTYPE, &uds_sotype); - if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL)) { + if (r != -1 || errno != ENOTTY) { if (r == -1) { return r; } diff --git a/lib/libc/sys-minix/sendto.c b/lib/libc/sys-minix/sendto.c index c3c039d1d..4f174bba2 100644 --- a/lib/libc/sys-minix/sendto.c +++ b/lib/libc/sys-minix/sendto.c @@ -41,7 +41,7 @@ ssize_t sendto(int sock, const void *message, size_t length, int flags, int uds_sotype = -1; r= ioctl(sock, NWIOGTCPOPT, &tcpopt); - if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL)) + if (r != -1 || errno != ENOTTY) { if (r == -1) return r; @@ -50,7 +50,7 @@ ssize_t sendto(int sock, const void *message, size_t length, int flags, } r= ioctl(sock, NWIOGUDPOPT, &udpopt); - if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL)) + if (r != -1 || errno != ENOTTY) { if (r == -1) return r; @@ -59,7 +59,7 @@ ssize_t sendto(int sock, const void *message, size_t length, int flags, } r= ioctl(sock, NWIOGUDSSOTYPE, &uds_sotype); - if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL)) + if (r != -1 || errno != ENOTTY) { if (r == -1) { return r; diff --git a/lib/libc/sys-minix/setsockopt.c b/lib/libc/sys-minix/setsockopt.c index ff4811177..ed36dc77e 100644 --- a/lib/libc/sys-minix/setsockopt.c +++ b/lib/libc/sys-minix/setsockopt.c @@ -35,7 +35,7 @@ int setsockopt(int sock, int level, int option_name, struct sockaddr_un uds_addr; r= ioctl(sock, NWIOGTCPOPT, &tcpopt); - if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL)) + if (r != -1 || errno != ENOTTY) { if (r == -1) { @@ -47,7 +47,7 @@ int setsockopt(int sock, int level, int option_name, } r= ioctl(sock, NWIOGUDPOPT, &udpopt); - if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL)) + if (r != -1 || errno != ENOTTY) { if (r == -1) { @@ -59,7 +59,7 @@ int setsockopt(int sock, int level, int option_name, } r= ioctl(sock, NWIOGUDSADDR, &uds_addr); - if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL)) + if (r != -1 || errno != ENOTTY) { if (r == -1) { diff --git a/lib/libc/sys-minix/shutdown.c b/lib/libc/sys-minix/shutdown.c index 3f86cc516..68236c7de 100644 --- a/lib/libc/sys-minix/shutdown.c +++ b/lib/libc/sys-minix/shutdown.c @@ -27,7 +27,7 @@ int shutdown(int sock, int how) nwio_tcpconf_t tcpconf; r= ioctl(sock, NWIOGTCPCONF, &tcpconf); - if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL)) + if (r != -1 || errno != ENOTTY) { if (r == -1) { @@ -38,7 +38,7 @@ int shutdown(int sock, int how) } r= ioctl(sock, NWIOGUDSADDR, &uds_addr); - if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL)) + if (r != -1 || errno != ENOTTY) { if (r == -1) { diff --git a/lib/libc/sys-minix/statvfs.c b/lib/libc/sys-minix/statvfs.c index 1de8ab77a..54c046c54 100644 --- a/lib/libc/sys-minix/statvfs.c +++ b/lib/libc/sys-minix/statvfs.c @@ -6,15 +6,22 @@ #include #ifdef __weak_alias +__weak_alias(statvfs1, _statvfs1) __weak_alias(statvfs, _statvfs) #endif -int statvfs(const char *name, struct statvfs *buffer) +int statvfs1(const char *name, struct statvfs *buffer, int flags) { message m; - m.STATVFS_LEN = strlen(name) + 1; - m.STATVFS_NAME = (char *) __UNCONST(name); - m.STATVFS_BUF = (char *) buffer; - return(_syscall(VFS_PROC_NR, STATVFS, &m)); + m.VFS_STATVFS1_LEN = strlen(name) + 1; + m.VFS_STATVFS1_NAME = (char *) __UNCONST(name); + m.VFS_STATVFS1_BUF = (char *) buffer; + m.VFS_STATVFS1_FLAGS = flags; + return(_syscall(VFS_PROC_NR, STATVFS1, &m)); +} + +int statvfs(const char *name, struct statvfs *buffer) +{ + return statvfs1(name, buffer, ST_WAIT); } diff --git a/lib/libc/sys/Makefile.inc b/lib/libc/sys/Makefile.inc index 2fa88dfd5..9e5554b4c 100644 --- a/lib/libc/sys/Makefile.inc +++ b/lib/libc/sys/Makefile.inc @@ -226,7 +226,7 @@ MAN+= accept.2 access.2 acct.2 bind.2 brk.2 chdir.2 \ connect.2 dup.2 execve.2 _exit.2 extattr_get_file.2 \ fcntl.2 fdatasync.2 fhopen.2 \ flock.2 fork.2 fsync.2 getcontext.2 getdents.2 \ - getfh.2 getvfsstat.2 getgid.2 getgroups.2 \ + getfh.2 getgid.2 getgroups.2 \ getitimer.2 getlogin.2 getpeername.2 getpgrp.2 getpid.2 \ getpriority.2 getrlimit.2 getsid.2 getsockname.2 \ getsockopt.2 gettimeofday.2 getuid.2 intro.2 ioctl.2 issetugid.2 \ @@ -244,7 +244,7 @@ MAN+= accept.2 access.2 acct.2 bind.2 brk.2 chdir.2 \ mprotect.2 mremap.2 msgctl.2 msgget.2 msgrcv.2 msgsnd.2 msync.2 \ munmap.2 nanosleep.2 nfssvc.2 ntp_adjtime.2 open.2 pathconf.2 pipe.2 .else -MAN+= adjtime.2 clock_settime.2 pipe.2 getrusage.2 +MAN+= adjtime.2 clock_settime.2 getvfsstat.2 pipe.2 getrusage.2 .endif # !defined(__MINIX) .if !defined(__MINIX) MAN+= pmc_control.2 poll.2 posix_fadvise.2 profil.2 ptrace.2 __quotactl.2 \ @@ -272,6 +272,7 @@ MLINKS+=chmod.2 fchmod.2 chmod.2 lchmod.2 MLINKS+=chown.2 fchown.2 chown.2 lchown.2 MLINKS+=chroot.2 fchroot.2 .else +MAN+= statvfs.2 MLINKS+=clock_settime.2 clock_gettime.2 MLINKS+=clock_settime.2 clock_getres.2 .endif # !defined(__MINIX) @@ -339,6 +340,9 @@ MLINKS+=wait.2 wait3.2 wait.2 wait4.2 wait.2 waitpid.2 MLINKS+=write.2 writev.2 write.2 pwrite.2 write.2 pwritev.2 .else MLINKS+=pipe.2 pipe2.2 +MLINKS+=statvfs.2 fstatvfs.2 +MLINKS+=statvfs.2 statvfs1.2 +MLINKS+=statvfs.2 fstatvfs1.2 .endif # !defined(__MINIX) .if !defined(__MINIX) MLINKS+=accept.2 paccept.2 diff --git a/lib/libchardriver/chardriver.c b/lib/libchardriver/chardriver.c index 13fa620b0..03d924537 100644 --- a/lib/libchardriver/chardriver.c +++ b/lib/libchardriver/chardriver.c @@ -1,33 +1,40 @@ /* This file contains the device independent character driver interface. * - * The drivers support the following operations (using message format m2): + * Charaxter drivers support the following requests. Message format m10 is + * used. Field names are prefixed with CDEV_. Separate field names are used for + * the "access", "ops", "user", and "request" fields. * - * m_type DEVICE USER_ENDPT COUNT POSITION HIGHPOS IO_GRANT - * ---------------------------------------------------------------------------- - * | DEV_OPEN | device | proc nr | mode | | | | - * |---------------+--------+---------+---------+--------+--------+-----------| - * | DEV_CLOSE | device | proc nr | | | | | - * |---------------+--------+---------+---------+--------+--------+-----------| - * | DEV_READ_S | device | proc nr | bytes | off lo | off hi i buf grant | - * |---------------+--------+---------+---------+--------+--------+-----------| - * | DEV_WRITE_S | device | proc nr | bytes | off lo | off hi | buf grant | - * |---------------+--------+---------+---------+--------+--------+-----------| - * | DEV_GATHER_S | device | proc nr | iov len | off lo | off hi | iov grant | - * |---------------+--------+---------+---------+--------+--------+-----------| - * | DEV_SCATTER_S | device | proc nr | iov len | off lo | off hi | iov grant | - * |---------------+--------+---------+---------+--------+--------+-----------| - * | DEV_IOCTL_S | device | proc nr | request | | | buf grant | - * |---------------+--------+---------+---------+--------+--------+-----------| - * | CANCEL | device | proc nr | r/w | | | grant | - * |---------------+--------+---------+---------+--------+--------+-----------| - * | DEV_SELECT | device | ops | | | | | - * ---------------------------------------------------------------------------- + * m_type MINOR GRANT COUNT FLAGS ID POS_LO POS_HI + * +-------------+-------+--------+-------+-------+------+---------+--------+ + * | CDEV_OPEN | minor | access | user | | id | | | + * |-------------+-------+--------+-------+-------+------+---------+--------| + * | CDEV_CLOSE | minor | | | | id | | | + * |-------------+-------+--------+-------+-------+------+---------+--------| + * | CDEV_READ | minor | grant | bytes | flags | id | position | + * |-------------+-------+--------+-------+-------+------+---------+--------| + * | CDEV_WRITE | minor | grant | bytes | flags | id | position | + * |-------------+-------+--------+-------+-------+------+---------+--------| + * | CDEV_IOCTL | minor | grant | user | flags | id | request | | + * |-------------+-------+--------+-------+-------+------+---------+--------| + * | CDEV_CANCEL | minor | | | | id | | | + * |-------------+-------+--------+-------+-------+------+---------+--------| + * | CDEV_SELECT | minor | ops | | | | | | + * -------------------------------------------------------------------------- * - * The entry points into this file are: - * driver_task: the main message loop of the driver - * driver_receive: message receive interface for drivers + * The following reply messages are used. + * + * m_type MINOR STATUS ID + * +-----------------+-------+--------+-----+-----+------+---------+--------+ + * | CDEV_REPLY | | status | | | id | | | + * |-----------------+-------+--------+-----+-----+------+---------+--------| + * | CDEV_SEL1_REPLY | minor | status | | | | | | + * |-----------------+-------+--------+-----+-----+------+---------+--------| + * | CDEV_SEL2_REPLY | minor | status | | | | | | + * -------------------------------------------------------------------------- * * Changes: + * Sep 01, 2013 complete rewrite of the API (D.C. van Moolenboek) + * Aug 20, 2013 retire synchronous protocol (D.C. van Moolenbroek) * Oct 16, 2011 split character and block protocol (D.C. van Moolenbroek) * Aug 27, 2011 move common functions into driver.c (A. Welzel) * Jul 25, 2005 added SYS_SIG type for signals (Jorrit N. Herder) @@ -43,7 +50,7 @@ static int running; /* Management data for opened devices. */ -static int open_devs[MAX_NR_OPEN_DEVICES]; +static devminor_t open_devs[MAX_NR_OPEN_DEVICES]; static int next_open_devs_slot = 0; /*===========================================================================* @@ -58,13 +65,13 @@ static void clear_open_devs(void) /*===========================================================================* * is_open_dev * *===========================================================================*/ -static int is_open_dev(int device) +static int is_open_dev(devminor_t minor) { /* Check whether the given minor device has previously been opened. */ int i; for (i = 0; i < next_open_devs_slot; i++) - if (open_devs[i] == device) + if (open_devs[i] == minor) return TRUE; return FALSE; @@ -73,14 +80,14 @@ static int is_open_dev(int device) /*===========================================================================* * set_open_dev * *===========================================================================*/ -static void set_open_dev(int device) +static void set_open_dev(devminor_t minor) { /* Mark the given minor device as having been opened. */ if (next_open_devs_slot >= MAX_NR_OPEN_DEVICES) panic("out of slots for open devices"); - open_devs[next_open_devs_slot] = device; + open_devs[next_open_devs_slot] = minor; next_open_devs_slot++; } @@ -112,21 +119,115 @@ void chardriver_announce(void) if ((r = ds_publish_u32(key, DS_DRIVER_UP, DSF_OVERWRITE)) != OK) panic("chardriver_init: unable to publish driver up event: %d", r); - /* Expect a DEV_OPEN for any device before serving regular driver requests. */ + /* Expect an open for any device before serving regular driver requests. */ clear_open_devs(); } /*===========================================================================* - * async_reply * + * chardriver_reply_task * *===========================================================================*/ -static void async_reply(message *mess, int r) +void chardriver_reply_task(endpoint_t endpt, cdev_id_t id, int r) { -/* Send a reply using the asynchronous character device protocol. */ +/* Reply to a (read, write, ioctl) task request that was suspended earlier. + * Not-so-well-written drivers may use this function to send a reply to a + * request that is being processed right now, and then return EDONTREPLY later. + */ + message m_reply; + + if (r == EDONTREPLY || r == SUSPEND) + panic("chardriver: bad task reply: %d", r); + + memset(&m_reply, 0, sizeof(m_reply)); + + m_reply.m_type = CDEV_REPLY; + m_reply.CDEV_STATUS = r; + m_reply.CDEV_ID = id; + + if ((r = asynsend3(endpt, &m_reply, AMF_NOREPLY)) != OK) + printf("chardriver_reply_task: send to %d failed: %d\n", endpt, r); +} + +/*===========================================================================* + * chardriver_reply_select * + *===========================================================================*/ +void chardriver_reply_select(endpoint_t endpt, devminor_t minor, int r) +{ +/* Reply to a select request with a status update. This must not be used to + * reply to a select request that is being processed right now. + */ + message m_reply; + + /* Replying with an error is allowed (if unusual). */ + if (r == EDONTREPLY || r == SUSPEND) + panic("chardriver: bad select reply: %d", r); + + memset(&m_reply, 0, sizeof(m_reply)); + + m_reply.m_type = CDEV_SEL2_REPLY; + m_reply.CDEV_MINOR = minor; + m_reply.CDEV_STATUS = r; + + if ((r = asynsend3(endpt, &m_reply, AMF_NOREPLY)) != OK) + printf("chardriver_reply_select: send to %d failed: %d\n", endpt, r); +} + +/*===========================================================================* + * send_reply * + *===========================================================================*/ +static void send_reply(endpoint_t endpt, message *m_ptr, int ipc_status) +{ +/* Send a reply message to a request. */ + int r; + + /* If we would block sending the message, send it asynchronously. */ + if (IPC_STATUS_CALL(ipc_status) == SENDREC) + r = sendnb(endpt, m_ptr); + else + r = asynsend3(endpt, m_ptr, AMF_NOREPLY); + + if (r != OK) + printf("chardriver: unable to send reply to %d: %d\n", endpt, r); +} + +/*===========================================================================* + * chardriver_reply * + *===========================================================================*/ +static void chardriver_reply(message *mess, int ipc_status, int r) +{ +/* Prepare and send a reply message. */ message reply_mess; - /* Do not reply with ERESTART in this protocol. The only possible caller, - * VFS, will find out through other means when we have restarted, and is not - * (fully) ready to deal with ERESTART errors. + /* If the EDONTREPLY pseudo-reply is given, we do not reply. This is however + * allowed only for blocking task calls. Perform a sanity check. + */ + if (r == EDONTREPLY) { + switch (mess->m_type) { + case CDEV_READ: + case CDEV_WRITE: + case CDEV_IOCTL: + /* FIXME: we should be able to check CDEV_FLAGS against + * CDEV_NONBLOCK here, but in practice, several drivers do not + * send a reply through this path (eg TTY) or simply do not + * implement nonblocking calls properly (eg audio, LWIP). + */ +#if 0 + if (mess->CDEV_FLAGS & CDEV_NONBLOCK) + panic("chardriver: cannot suspend nonblocking I/O"); +#endif + /*fall-through*/ + case CDEV_CANCEL: + return; /* alright */ + default: + panic("chardriver: cannot suspend request %d", mess->m_type); + } + } + + if (r == SUSPEND) + panic("chardriver: SUSPEND should not be used anymore"); + + /* Do not reply with ERESTART. The only possible caller, VFS, will find out + * through other means when we have restarted, and is not (fully) ready to + * deal with ERESTART errors. */ if (r == ERESTART) return; @@ -134,274 +235,292 @@ static void async_reply(message *mess, int r) memset(&reply_mess, 0, sizeof(reply_mess)); switch (mess->m_type) { - case DEV_OPEN: - reply_mess.m_type = DEV_OPEN_REPL; - reply_mess.REP_ENDPT = mess->USER_ENDPT; - reply_mess.REP_STATUS = r; + case CDEV_OPEN: + case CDEV_CLOSE: + case CDEV_READ: + case CDEV_WRITE: + case CDEV_IOCTL: + case CDEV_CANCEL: /* For cancel, this is a reply to the original request! */ + reply_mess.m_type = CDEV_REPLY; + reply_mess.CDEV_STATUS = r; + reply_mess.CDEV_ID = mess->CDEV_ID; break; - case DEV_CLOSE: - reply_mess.m_type = DEV_CLOSE_REPL; - reply_mess.REP_ENDPT = mess->USER_ENDPT; - reply_mess.REP_STATUS = r; - break; - - case DEV_READ_S: - case DEV_WRITE_S: - case DEV_IOCTL_S: - if (r == SUSPEND) - printf("driver_task: reviving %d (%d) with SUSPEND\n", - mess->m_source, mess->USER_ENDPT); - - reply_mess.m_type = DEV_REVIVE; - reply_mess.REP_ENDPT = mess->USER_ENDPT; - reply_mess.REP_IO_GRANT = (cp_grant_id_t) mess->IO_GRANT; - reply_mess.REP_STATUS = r; - break; - - case CANCEL: - /* The original request should send a reply. */ - return; - - case DEV_SELECT: - reply_mess.m_type = DEV_SEL_REPL1; - reply_mess.DEV_MINOR = mess->DEVICE; - reply_mess.DEV_SEL_OPS = r; + case CDEV_SELECT: + reply_mess.m_type = CDEV_SEL1_REPLY; + reply_mess.CDEV_MINOR = mess->CDEV_MINOR; + reply_mess.CDEV_STATUS = r; break; default: - reply_mess.m_type = TASK_REPLY; - reply_mess.REP_ENDPT = mess->USER_ENDPT; - /* Status is # of bytes transferred or error code. */ - reply_mess.REP_STATUS = r; - break; + panic("chardriver: unknown request %d", mess->m_type); } - r = asynsend(mess->m_source, &reply_mess); - - if (r != OK) - printf("asyn_reply: unable to asynsend reply to %d: %d\n", - mess->m_source, r); + send_reply(mess->m_source, &reply_mess, ipc_status); } /*===========================================================================* - * sync_reply * + * do_open * *===========================================================================*/ -static void sync_reply(message *m_ptr, int ipc_status, int reply) +static int do_open(struct chardriver *cdp, message *m_ptr) { -/* Reply to a message sent to the driver. */ - endpoint_t caller_e, user_e; - int r; +/* Open a minor device. */ + endpoint_t user_endpt; + devminor_t minor; + int r, access; - caller_e = m_ptr->m_source; - user_e = m_ptr->USER_ENDPT; + /* Default action if no open hook is in place. */ + if (cdp->cdr_open == NULL) + return OK; - m_ptr->m_type = TASK_REPLY; - m_ptr->REP_ENDPT = user_e; - m_ptr->REP_STATUS = reply; + /* Call the open hook. */ + minor = m_ptr->CDEV_MINOR; + access = m_ptr->CDEV_ACCESS; + user_endpt = m_ptr->CDEV_USER; - /* If we would block sending the message, send it asynchronously. */ - if (IPC_STATUS_CALL(ipc_status) == SENDREC) - r = sendnb(caller_e, m_ptr); - else - r = asynsend(caller_e, m_ptr); + r = cdp->cdr_open(minor, access, user_endpt); - if (r != OK) - printf("driver_reply: unable to send reply to %d: %d\n", caller_e, r); -} - -/*===========================================================================* - * send_reply * - *===========================================================================*/ -static void send_reply(int type, message *m_ptr, int ipc_status, int reply) -{ -/* Prepare and send a reply message. */ - - if (reply == EDONTREPLY) - return; - - if (type == CHARDRIVER_ASYNC) - async_reply(m_ptr, reply); - else - sync_reply(m_ptr, ipc_status, reply); -} - -/*===========================================================================* - * do_rdwt * - *===========================================================================*/ -static int do_rdwt(struct chardriver *cdp, message *mp) -{ -/* Carry out a single read or write request. */ - iovec_t iovec1; - int r, opcode; - u64_t position; - - /* Disk address? Address and length of the user buffer? */ - if (mp->COUNT < 0) return(EINVAL); - - /* Prepare for I/O. */ - if ((*cdp->cdr_prepare)(mp->DEVICE) == NULL) return(ENXIO); - - /* Create a one element scatter/gather vector for the buffer. */ - if(mp->m_type == DEV_READ_S) - opcode = DEV_GATHER_S; - else - opcode = DEV_SCATTER_S; - - iovec1.iov_addr = (vir_bytes) mp->IO_GRANT; - iovec1.iov_size = mp->COUNT; - - /* Transfer bytes from/to the device. */ - position= make64(mp->POSITION, mp->HIGHPOS); - r = (*cdp->cdr_transfer)(mp->m_source, opcode, position, &iovec1, 1, - mp->USER_ENDPT, mp->FLAGS); - - /* Return the number of bytes transferred or an error code. */ - return(r == OK ? (int) (mp->COUNT - iovec1.iov_size) : r); -} - -/*===========================================================================* - * do_vrdwt * - *===========================================================================*/ -static int do_vrdwt(struct chardriver *cdp, message *mp) -{ -/* Carry out an device read or write to/from a vector of user addresses. - * The "user addresses" are assumed to be safe, i.e. FS transferring to/from - * its own buffers, so they are not checked. - */ - iovec_t iovec[NR_IOREQS]; - phys_bytes iovec_size; - unsigned nr_req; - int r, opcode; - u64_t position; - - nr_req = mp->COUNT; /* Length of I/O vector */ - - /* Copy the vector from the caller to kernel space. */ - if (nr_req > NR_IOREQS) nr_req = NR_IOREQS; - iovec_size = (phys_bytes) (nr_req * sizeof(iovec[0])); - - if (OK != sys_safecopyfrom(mp->m_source, (vir_bytes) mp->IO_GRANT, - 0, (vir_bytes) iovec, iovec_size)) { - printf("bad I/O vector by: %d\n", mp->m_source); - return(EINVAL); + /* If the device has been cloned, mark the new minor as open too. */ + if (r >= 0 && (r & CDEV_CLONED)) { + minor = r & ~(CDEV_CLONED | CDEV_CTTY); + if (!is_open_dev(minor)) + set_open_dev(minor); } - /* Prepare for I/O. */ - if ((*cdp->cdr_prepare)(mp->DEVICE) == NULL) return(ENXIO); - - /* Transfer bytes from/to the device. */ - opcode = mp->m_type; - position= make64(mp->POSITION, mp->HIGHPOS); - r = (*cdp->cdr_transfer)(mp->m_source, opcode, position, iovec, nr_req, - mp->USER_ENDPT, mp->FLAGS); - - /* Copy the I/O vector back to the caller. */ - if (OK != sys_safecopyto(mp->m_source, (vir_bytes) mp->IO_GRANT, - 0, (vir_bytes) iovec, iovec_size)) { - printf("couldn't return I/O vector: %d\n", mp->m_source); - return(EINVAL); - } - - return(r); -} - -/*===========================================================================* - * handle_notify * - *===========================================================================*/ -static void handle_notify(struct chardriver *cdp, message *m_ptr) -{ -/* Take care of the notifications (interrupt and clock messages) by calling the - * appropiate callback functions. Never send a reply. - */ - - /* Call the appropriate function for this notification. */ - switch (_ENDPOINT_P(m_ptr->m_source)) { - case CLOCK: - if (cdp->cdr_alarm) - cdp->cdr_alarm(m_ptr); - break; - - default: - if (cdp->cdr_other) - (void) cdp->cdr_other(m_ptr); - } -} - -/*===========================================================================* - * handle_request * - *===========================================================================*/ -static int handle_request(struct chardriver *cdp, message *m_ptr) -{ -/* Call the appropiate driver function, based on the type of request. Return - * the result code that is to be sent back to the caller, or EDONTREPLY if no - * reply is to be sent. - */ - int r; - - /* We might get spurious requests if the driver has been restarted. Deny any - * requests on devices that have not previously been opened, signaling the - * caller that something went wrong. - */ - if (IS_CDEV_MINOR_RQ(m_ptr->m_type) && !is_open_dev(m_ptr->DEVICE)) { - /* Reply ERESTART to spurious requests for unopened devices. */ - if (m_ptr->m_type != DEV_OPEN) - return ERESTART; - - /* Mark the device as opened otherwise. */ - set_open_dev(m_ptr->DEVICE); - } - - /* Call the appropriate function(s) for this request. */ - switch (m_ptr->m_type) { - case DEV_OPEN: r = (*cdp->cdr_open)(m_ptr); break; - case DEV_CLOSE: r = (*cdp->cdr_close)(m_ptr); break; - case DEV_IOCTL_S: r = (*cdp->cdr_ioctl)(m_ptr); break; - case CANCEL: r = (*cdp->cdr_cancel)(m_ptr); break; - case DEV_SELECT: r = (*cdp->cdr_select)(m_ptr); break; - case DEV_READ_S: - case DEV_WRITE_S: r = do_rdwt(cdp, m_ptr); break; - case DEV_GATHER_S: - case DEV_SCATTER_S: r = do_vrdwt(cdp, m_ptr); break; - default: - if (cdp->cdr_other) - r = cdp->cdr_other(m_ptr); - else - r = EINVAL; - } - - /* Let the driver perform any cleanup. */ - if (cdp->cdr_cleanup) - (*cdp->cdr_cleanup)(); - return r; } +/*===========================================================================* + * do_close * + *===========================================================================*/ +static int do_close(struct chardriver *cdp, message *m_ptr) +{ +/* Close a minor device. */ + devminor_t minor; + + /* Default action if no close hook is in place. */ + if (cdp->cdr_close == NULL) + return OK; + + /* Call the close hook. */ + minor = m_ptr->CDEV_MINOR; + + return cdp->cdr_close(minor); +} + +/*===========================================================================* + * do_trasnfer * + *===========================================================================*/ +static int do_transfer(struct chardriver *cdp, message *m_ptr, int do_write) +{ +/* Carry out a read or write task request. */ + devminor_t minor; + u64_t position; + endpoint_t endpt; + cp_grant_id_t grant; + size_t size; + int flags; + cdev_id_t id; + ssize_t r; + + minor = m_ptr->CDEV_MINOR; + position = make64(m_ptr->CDEV_POS_LO, m_ptr->CDEV_POS_HI); + endpt = m_ptr->m_source; + grant = (cp_grant_id_t) m_ptr->CDEV_GRANT; + size = m_ptr->CDEV_COUNT; + flags = m_ptr->CDEV_FLAGS; + id = m_ptr->CDEV_ID; + + /* Call the read/write hook, if the appropriate one is in place. */ + if (!do_write && cdp->cdr_read != NULL) + r = cdp->cdr_read(minor, position, endpt, grant, size, flags, id); + else if (do_write && cdp->cdr_write != NULL) + r = cdp->cdr_write(minor, position, endpt, grant, size, flags, id); + else + r = EIO; /* Default action if no read/write hook is in place. */ + + return r; +} + +/*===========================================================================* + * do_ioctl * + *===========================================================================*/ +static int do_ioctl(struct chardriver *cdp, message *m_ptr) +{ +/* Carry out an I/O control task request. */ + devminor_t minor; + unsigned long request; + cp_grant_id_t grant; + endpoint_t endpt, user_endpt; + int flags; + cdev_id_t id; + + /* Default action if no ioctl hook is in place. */ + if (cdp->cdr_ioctl == NULL) + return ENOTTY; + + /* Call the ioctl hook. */ + minor = m_ptr->CDEV_MINOR; + request = m_ptr->CDEV_REQUEST; + endpt = m_ptr->m_source; + grant = m_ptr->CDEV_GRANT; + flags = m_ptr->CDEV_FLAGS; + user_endpt = m_ptr->CDEV_USER; + id = m_ptr->CDEV_ID; + + return cdp->cdr_ioctl(minor, request, endpt, grant, flags, user_endpt, id); +} + +/*===========================================================================* + * do_cancel * + *===========================================================================*/ +static int do_cancel(struct chardriver *cdp, message *m_ptr) +{ +/* Cancel a suspended (read, write, ioctl) task request. The original request + * may already have finished, in which case no reply should be sent. + */ + devminor_t minor; + endpoint_t endpt; + cdev_id_t id; + + /* Default action if no cancel hook is in place: let the request finish. */ + if (cdp->cdr_cancel == NULL) + return EDONTREPLY; + + /* Call the cancel hook. */ + minor = m_ptr->CDEV_MINOR; + endpt = m_ptr->m_source; + id = m_ptr->CDEV_ID; + + return cdp->cdr_cancel(minor, endpt, id); +} + +/*===========================================================================* + * do_select * + *===========================================================================*/ +static int do_select(struct chardriver *cdp, message *m_ptr) +{ +/* Perform a select query on a minor device. */ + devminor_t minor; + unsigned int ops; + endpoint_t endpt; + + /* Default action if no select hook is in place. */ + if (cdp->cdr_select == NULL) + return EBADF; + + /* Call the select hook. */ + minor = m_ptr->CDEV_MINOR; + ops = m_ptr->CDEV_OPS; + endpt = m_ptr->m_source; + + return cdp->cdr_select(minor, ops, endpt); +} + +/*===========================================================================* + * do_block_open * + *===========================================================================*/ +static void do_block_open(message *m_ptr, int ipc_status) +{ +/* Reply to a block driver open request stating there is no such device. */ + message m_reply; + + memset(&m_reply, 0, sizeof(m_reply)); + + m_reply.m_type = BDEV_REPLY; + m_reply.BDEV_STATUS = ENXIO; + m_reply.BDEV_ID = m_ptr->BDEV_ID; + + send_reply(m_ptr->m_source, &m_reply, ipc_status); +} + /*===========================================================================* * chardriver_process * *===========================================================================*/ -void chardriver_process(struct chardriver *cdp, int driver_type, - message *m_ptr, int ipc_status) +void chardriver_process(struct chardriver *cdp, message *m_ptr, int ipc_status) { -/* Handle the given received message. */ - int r; +/* Call the appropiate driver function, based on the type of request. Send a + * reply to the caller if necessary. + */ + int r, reply; - /* Process the notification or request. */ + /* Check for notifications first. We never reply to notifications. */ if (is_ipc_notify(ipc_status)) { - handle_notify(cdp, m_ptr); + switch (_ENDPOINT_P(m_ptr->m_source)) { + case HARDWARE: + if (cdp->cdr_intr) + cdp->cdr_intr(m_ptr->NOTIFY_ARG); + break; - /* Do not reply to notifications. */ - } else { - r = handle_request(cdp, m_ptr); + case CLOCK: + if (cdp->cdr_alarm) + cdp->cdr_alarm(m_ptr->NOTIFY_TIMESTAMP); + break; - send_reply(driver_type, m_ptr, ipc_status, r); + default: + if (cdp->cdr_other) + cdp->cdr_other(m_ptr, ipc_status); + } + + return; /* do not send a reply */ } + + /* Reply to block driver open requests with an error code. Otherwise, if + * someone creates a block device node for a character driver, opening that + * device node will cause the corresponding VFS thread to block forever. + */ + if (m_ptr->m_type == BDEV_OPEN) { + do_block_open(m_ptr, ipc_status); + + return; + } + + /* We might get spurious requests if the driver has been restarted. Deny any + * requests on devices that have not previously been opened. + */ + if (IS_CDEV_RQ(m_ptr->m_type) && !is_open_dev(m_ptr->CDEV_MINOR)) { + /* Ignore spurious requests for unopened devices. */ + if (m_ptr->m_type != CDEV_OPEN) + return; /* do not send a reply */ + + /* Mark the device as opened otherwise. */ + set_open_dev(m_ptr->CDEV_MINOR); + } + + /* Call the appropriate function(s) for this request. */ + switch (m_ptr->m_type) { + case CDEV_OPEN: r = do_open(cdp, m_ptr); break; + case CDEV_CLOSE: r = do_close(cdp, m_ptr); break; + case CDEV_READ: r = do_transfer(cdp, m_ptr, FALSE); break; + case CDEV_WRITE: r = do_transfer(cdp, m_ptr, TRUE); break; + case CDEV_IOCTL: r = do_ioctl(cdp, m_ptr); break; + case CDEV_CANCEL: r = do_cancel(cdp, m_ptr); break; + case CDEV_SELECT: r = do_select(cdp, m_ptr); break; + default: + if (cdp->cdr_other) + cdp->cdr_other(m_ptr, ipc_status); + return; /* do not send a reply */ + } + + chardriver_reply(m_ptr, ipc_status, r); +} + +/*===========================================================================* + * chardriver_terminate * + *===========================================================================*/ +void chardriver_terminate(void) +{ +/* Break out of the main loop after finishing the current request. */ + + running = FALSE; + + sef_cancel(); } /*===========================================================================* * chardriver_task * *===========================================================================*/ -void chardriver_task(struct chardriver *cdp, int driver_type) +void chardriver_task(struct chardriver *cdp) { /* Main program of any device driver task. */ int r, ipc_status; @@ -413,59 +532,13 @@ void chardriver_task(struct chardriver *cdp, int driver_type) * it out, and sends a reply. */ while (running) { - if ((r = sef_receive_status(ANY, &mess, &ipc_status)) != OK) - panic("driver_receive failed: %d", r); + if ((r = sef_receive_status(ANY, &mess, &ipc_status)) != OK) { + if (r == EINTR && !running) + break; - chardriver_process(cdp, driver_type, &mess, ipc_status); + panic("driver_receive failed: %d", r); + } + + chardriver_process(cdp, &mess, ipc_status); } } - -/*===========================================================================* - * do_nop * - *===========================================================================*/ -int do_nop(message *UNUSED(mp)) -{ - return(OK); -} - -/*===========================================================================* - * nop_ioctl * - *===========================================================================*/ -int nop_ioctl(message *UNUSED(mp)) -{ - return(ENOTTY); -} - -/*===========================================================================* - * nop_alarm * - *===========================================================================*/ -void nop_alarm(message *UNUSED(mp)) -{ -/* Ignore the leftover alarm. */ -} - -/*===========================================================================* - * nop_cleanup * - *===========================================================================*/ -void nop_cleanup(void) -{ -/* Nothing to clean up. */ -} - -/*===========================================================================* - * nop_cancel * - *===========================================================================*/ -int nop_cancel(message *UNUSED(m)) -{ -/* Nothing to do for cancel. */ - return(OK); -} - -/*===========================================================================* - * nop_select * - *===========================================================================*/ -int nop_select(message *UNUSED(m)) -{ -/* Nothing to do for select. */ - return(OK); -} diff --git a/lib/libddekit/src/msg_queue.c b/lib/libddekit/src/msg_queue.c index 3ea82708b..a68e6cf10 100644 --- a/lib/libddekit/src/msg_queue.c +++ b/lib/libddekit/src/msg_queue.c @@ -93,19 +93,14 @@ _ddekit_minix_queue_msg ( full = ddekit_sem_down_try(mq->msg_w_sem); if (full) { - /* Our message queue is full... inform the sender. */ + /* Our message queue is full... */ int result; - DDEBUG_MSG_WARN("Receive queue is full. Ommiting ingoing msg.\n"); - - m->m_type = TASK_REPLY; - m->REP_STATUS = EAGAIN; - result = asynsend(m->m_source, m); - - if (result != 0) { - ddekit_panic("unable to send reply to %d: %d\n", - m->m_source, result); - } + DDEBUG_MSG_WARN("Receive queue is full. Dropping request.\n"); + /* XXX should reply to the sender with EIO or so, but for that + * we would need to look at the request and find a suitable + * reply code.. + */ } else { /* queue the message */ memcpy(&mq->messages[mq->msg_w_pos], m, sizeof(message)); diff --git a/lib/libi2cdriver/i2cdriver.c b/lib/libi2cdriver/i2cdriver.c index 755bd8a1f..3c3231c37 100644 --- a/lib/libi2cdriver/i2cdriver.c +++ b/lib/libi2cdriver/i2cdriver.c @@ -160,14 +160,14 @@ i2cdriver_reserve_device(endpoint_t bus_endpoint, i2c_addr_t address) message m; m.m_type = BUSC_I2C_RESERVE; - m.DEVICE = address; + m.BUSC_I2C_ADDR = address; r = sendrec(bus_endpoint, &m); if (r != OK) { return EIO; } - return m.REP_STATUS; /* return reply code OK, EBUSY, EINVAL, etc. */ + return m.m_type; /* return reply code OK, EBUSY, EINVAL, etc. */ } int @@ -183,7 +183,7 @@ i2cdriver_exec(endpoint_t bus_endpoint, minix_i2c_ioctl_exec_t * ioctl_exec) memset(&m, '\0', sizeof(message)); m.m_type = BUSC_I2C_EXEC; - m.IO_GRANT = (char *) grant_nr; + m.BUSC_I2C_GRANT = grant_nr; r = sendrec(bus_endpoint, &m); cpf_revoke(grant_nr); @@ -191,5 +191,5 @@ i2cdriver_exec(endpoint_t bus_endpoint, minix_i2c_ioctl_exec_t * ioctl_exec) return EIO; } - return m.REP_STATUS; + return m.m_type; } diff --git a/lib/libminc/Makefile b/lib/libminc/Makefile index 35e644d8d..d9c6a59c5 100644 --- a/lib/libminc/Makefile +++ b/lib/libminc/Makefile @@ -143,12 +143,13 @@ CPPFLAGS.${i}+= -I${LIBCDIR}/locale .endfor # Import from sys-minix -.for i in access.c brk.c close.c environ.c execve.c fork.c \ - getgid.c getpid.c geteuid.c getuid.c gettimeofday.c loadname.c \ - link.c _mcontext.c mknod.c mmap.c nanosleep.c open.c \ - read.c reboot.c sbrk.c select.c setuid.c sigprocmask.c stat.c \ - stime.c syscall.c _ucontext.c umask.c unlink.c waitpid.c \ - brksize.S _ipc.S _senda.S ucontext.S mmap.c init.c +.for i in access.c brk.c close.c environ.c execve.c fork.c fsync.c \ + getgid.c getpid.c geteuid.c getuid.c gettimeofday.c getvfsstat.c \ + init.c link.c loadname.c lseek.c lseek64.c _mcontext.c mknod.c \ + mmap.c nanosleep.c open.c pread.c pwrite.c read.c reboot.c sbrk.c \ + select.c setuid.c sigprocmask.c stat.c stime.c syscall.c _ucontext.c \ + umask.c unlink.c waitpid.c write.c brksize.S _ipc.S _senda.S \ + ucontext.S .PATH.c: ${LIBCDIR}/sys-minix .PATH.S: ${ARCHDIR}/sys-minix SRCS+= ${i} diff --git a/lib/libminixfs/cache.c b/lib/libminixfs/cache.c index 2ff548faa..02f84c4a4 100644 --- a/lib/libminixfs/cache.c +++ b/lib/libminixfs/cache.c @@ -567,6 +567,8 @@ void lmfs_invalidate( bp->data = NULL; } } + + vm_clear_cache(device); } /*===========================================================================* diff --git a/lib/libminlib/Makefile b/lib/libminlib/Makefile index af025661c..5d5092d52 100644 --- a/lib/libminlib/Makefile +++ b/lib/libminlib/Makefile @@ -30,9 +30,10 @@ SRCS+= servxcheck.c # queryparam SRCS+= paramvalue.c -# Minix servers/drivers syscall. -SRCS+= getngid.c getnpid.c getnprocnr.c getnucred.c getnuid.c getprocnr.c \ - mapdriver.c vm_memctl.c vm_set_priv.c vm_query_exit.c vm_update.c +# Minix servers/drivers syscall. FIXME: these should be moved into libsys. +SRCS+= dupfrom.c getngid.c getnpid.c getnprocnr.c getnucred.c getnuid.c \ + getprocnr.c mapdriver.c vm_memctl.c vm_set_priv.c vm_query_exit.c \ + vm_update.c SRCS+= oneC_sum.c diff --git a/lib/libminlib/dupfrom.c b/lib/libminlib/dupfrom.c new file mode 100644 index 000000000..6a4641584 --- /dev/null +++ b/lib/libminlib/dupfrom.c @@ -0,0 +1,15 @@ +#include +#include +#include + +int +dupfrom(endpoint_t endpt, int fd) +{ + message m; + + memset(&m, 0, sizeof(m)); + m.VFS_DUPFROM_ENDPT = endpt; + m.VFS_DUPFROM_FD = fd; + + return _syscall(VFS_PROC_NR, DUPFROM, &m); +} diff --git a/lib/libmthread/misc.c b/lib/libmthread/misc.c index 86c8800ac..51c99c8ab 100644 --- a/lib/libmthread/misc.c +++ b/lib/libmthread/misc.c @@ -122,10 +122,14 @@ void mthread_stacktrace(mthread_thread_t t) mcontext_t *mtx; struct stackframe_s *frame; - printf("thread %d: ", t); - tcb = mthread_find_tcb(t); ctx = &tcb->m_context; + + if (t != MAIN_THREAD && ctx->uc_stack.ss_size == 0) + return; /* no stack, no stacktrace */ + + printf("thread %d: ", t); + mtx = &ctx->uc_mcontext; frame = &mtx->mc_p_reg; bp = frame->fp; diff --git a/lib/libnetsock/socket.c b/lib/libnetsock/socket.c index 7897a126e..bef626ec7 100644 --- a/lib/libnetsock/socket.c +++ b/lib/libnetsock/socket.c @@ -42,11 +42,35 @@ char * netsock_user_name = NULL; struct socket socket[MAX_SOCKETS]; +static int netsock_open(devminor_t minor, int access, endpoint_t user_endpt); +static int netsock_close(devminor_t minor); +static ssize_t netsock_read(devminor_t minor, u64_t position, endpoint_t endpt, + cp_grant_id_t grant, size_t size, int flags, cdev_id_t id); +static ssize_t netsock_write(devminor_t minor, u64_t position, + endpoint_t endpt, cp_grant_id_t grant, size_t size, int flags, + cdev_id_t id); +static int netsock_ioctl(devminor_t minor, unsigned long request, + endpoint_t endpt, cp_grant_id_t grant, int flags, + endpoint_t user_endpt, cdev_id_t id); +static int netsock_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id); +static int netsock_select(devminor_t minor, unsigned int ops, + endpoint_t endpt); + +static struct chardriver netsock_tab = { + .cdr_open = netsock_open, + .cdr_close = netsock_close, + .cdr_read = netsock_read, + .cdr_write = netsock_write, + .cdr_ioctl = netsock_ioctl, + .cdr_cancel = netsock_cancel, + .cdr_select = netsock_select +}; + #define recv_q_alloc() debug_malloc(sizeof(struct recv_q)) #define recv_q_free debug_free struct mq { - message m; + struct sock_req req; struct mq * prev; struct mq * next; }; @@ -56,18 +80,18 @@ struct mq { static struct mq * mq_head, *mq_tail; -int mq_enqueue(message * m) +int mq_enqueue(struct sock_req * req) { struct mq * mq; - debug_sock_print("sock %d op %d", m->DEVICE, m->m_type); + debug_sock_print("sock %d op %d", req->minor, req->type); mq = mq_alloc(); if (mq == NULL) return -1; mq->next = NULL; - mq->m = *m; + mq->req = *req; if (mq_head) { mq->prev = mq_tail; @@ -97,7 +121,7 @@ __unused static struct mq * mq_dequeue_head(void) } else mq_head = mq_tail = NULL; - debug_sock_print("socket %d\n", ret->m.DEVICE); + debug_sock_print("socket %d\n", ret->req.minor); return ret; } @@ -120,15 +144,14 @@ static void mq_dequeue(struct mq * mq) } } -static int mq_cancel(message * m) +static int mq_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id) { struct mq * mq; for (mq = mq_tail; mq; mq = mq->prev) { - if (m->DEVICE == mq->m.DEVICE && - m->USER_ENDPT == mq->m.USER_ENDPT && - m->IO_GRANT == mq->m.IO_GRANT) { - debug_sock_print("socket %d\n", mq->m.DEVICE); + if (minor == mq->req.minor && endpt == mq->req.endpt && + id == mq->req.id) { + debug_sock_print("socket %d\n", minor); break; } } @@ -138,6 +161,7 @@ static int mq_cancel(message * m) mq_free(mq); } + /* FIXME: shouldn't this return (!!mq) ? */ return 1; } @@ -191,113 +215,35 @@ void sock_dequeue_data_all(struct socket * sock, sock->recv_data_size = 0; } -static void set_reply_msg(message * m, int status) +void send_req_reply(struct sock_req * req, int status) { - int proc, ref; + if (status == EDONTREPLY) + return; - proc= m->USER_ENDPT; - ref= (int)m->IO_GRANT; - - m->REP_ENDPT= proc; - m->REP_STATUS= status; - m->REP_IO_GRANT= ref; -} - -void send_reply_type(message * m, int type, int status) -{ - int result; - - set_reply_msg(m, status); - - m->m_type = type; - result = send(m->m_source, m); - if (result != OK) - netsock_panic("unable to send (err %d)", result); -} - -void send_reply(message * m, int status) -{ - debug_sock_print("status %d", status); - send_reply_type(m, DEV_REVIVE, status); -} - -void send_reply_open(message * m, int status) -{ - debug_sock_print("status %d", status); - send_reply_type(m, DEV_OPEN_REPL, status); -} - -void send_reply_close(message * m, int status) -{ - debug_sock_print("status %d", status); - send_reply_type(m, DEV_CLOSE_REPL, status); -} - -void sock_reply_select(struct socket * sock, unsigned selops) -{ - int result; - message msg; - - debug_sock_select_print("selops %d", selops); - - msg.m_type = DEV_SEL_REPL1; - msg.DEV_MINOR = get_sock_num(sock); - msg.DEV_SEL_OPS = selops; - - result = send(sock->select_ep, &msg); - if (result != OK) - netsock_panic("unable to send (err %d)", result); + chardriver_reply_task(req->endpt, req->id, status); } void sock_select_notify(struct socket * sock) { - int result; - message msg; + unsigned int ops; debug_sock_select_print("socket num %ld", get_sock_num(sock)); assert(sock->select_ep != NONE); - msg.DEV_SEL_OPS = 0; - sock->ops->select_reply(sock, &msg); - if (msg.DEV_SEL_OPS == 0) { + ops = sock->ops->select_reply(sock); + if (ops == 0) { debug_sock_select_print("called from %p sflags 0x%x TXsz %d RXsz %d\n", __builtin_return_address(0), sock->flags, sock->buf_size, sock->recv_data_size); return; } - msg.m_type = DEV_SEL_REPL2; - msg.DEV_MINOR = get_sock_num(sock); - - debug_sock_select_print("socket num %d select result 0x%x sent", - msg.DEV_MINOR, msg.DEV_SEL_OPS); - result = send(sock->select_ep, &msg); - if (result != OK) - netsock_panic("unable to send (err %d)", result); + chardriver_reply_select(sock->select_ep, get_sock_num(sock), ops); sock_clear_select(sock); sock->select_ep = NONE; } -static void sock_reply_type(struct socket * sock, int type, int status) -{ - sock->mess.m_type = type; - - send_reply_type(&sock->mess, type, status); -} - -void sock_reply_close(struct socket * sock, int status) -{ - debug_sock_print("sock %ld status %d", get_sock_num(sock), status); - sock_reply_type(sock, DEV_CLOSE_REPL, status); -} - -void sock_reply(struct socket * sock, int status) -{ - debug_sock_print("sock %ld status %d", get_sock_num(sock), status); - sock_reply_type(sock, DEV_REVIVE, status); -} - struct socket * get_unused_sock(void) { int i; @@ -313,145 +259,240 @@ struct socket * get_unused_sock(void) return NULL; } -static void socket_request_socket(struct socket * sock, message * m) +static int socket_request_socket(struct socket * sock, struct sock_req * req) { - int blocking = m->FLAGS & FLG_OP_NONBLOCK ? 0 : 1; + int r, blocking = (req->flags & CDEV_NONBLOCK) ? 0 : 1; - switch (m->m_type) { - case DEV_READ_S: + switch (req->type) { + case SOCK_REQ_READ: if (sock->ops && sock->ops->read) - sock->ops->read(sock, m, blocking); + r = sock->ops->read(sock, req, blocking); else - send_reply(m, EINVAL); - return; - case DEV_WRITE_S: + r = EINVAL; + break; + case SOCK_REQ_WRITE: if (sock->ops && sock->ops->write) - sock->ops->write(sock, m, blocking); + r = sock->ops->write(sock, req, blocking); else - send_reply(m, EINVAL); - return; - case DEV_IOCTL_S: + r = EINVAL; + break; + case SOCK_REQ_IOCTL: if (sock->ops && sock->ops->ioctl) - sock->ops->ioctl(sock, m, blocking); + r = sock->ops->ioctl(sock, req, blocking); else - send_reply(m, EINVAL); - return; + r = EINVAL; + break; default: netsock_panic("cannot happen!"); } + + return r; } -void socket_request(message * m) +static int netsock_open(devminor_t minor, int UNUSED(access), + endpoint_t UNUSED(user_endpt)) { - struct socket * sock; + int r; - debug_sock_print("request %d", m->m_type); - switch (m->m_type) { - case DEV_OPEN: - socket_open(m); - return; - case DEV_CLOSE: - sock = get_sock(m->DEVICE); - if (sock->ops && sock->ops->close) { - sock->flags &= ~SOCK_FLG_OP_PENDING; - sock->mess = *m; - sock->ops->close(sock, m); - } else - send_reply_close(m, EINVAL); - return; - case DEV_READ_S: - case DEV_WRITE_S: - case DEV_IOCTL_S: - sock = get_sock(m->DEVICE); - if (!sock) { - send_reply(m, EINVAL); - return; + if ((r = socket_open(minor)) < 0) + return r; + + return CDEV_CLONED | r; +} + +static int netsock_close(devminor_t minor) +{ + struct socket *sock; + + if (!(sock = get_sock(minor))) + return EINVAL; + + if (sock->ops && sock->ops->close) { + sock->flags &= ~SOCK_FLG_OP_PENDING; + + return sock->ops->close(sock); + } else + return EINVAL; +} + +static int netsock_request(struct socket *sock, struct sock_req *req) +{ + char *o; + + /* + * If an operation is pending (blocking operation) or writing is + * still going on and we're reading, suspend the new operation + */ + if ((sock->flags & SOCK_FLG_OP_PENDING) || + (req->type == SOCK_REQ_READ && + sock->flags & SOCK_FLG_OP_WRITING)) { + if (sock->flags & SOCK_FLG_OP_READING) + o = "READ"; + else if (sock->flags & SOCK_FLG_OP_WRITING) + o = "WRITE"; + else + o = "non R/W op"; + debug_sock_print("socket %ld is busy by %s flgs 0x%x\n", + get_sock_num(sock), o, sock->flags); + + if (mq_enqueue(req) != 0) { + debug_sock_print("Enqueuing suspended call failed"); + return ENOMEM; } - /* - * If an operation is pending (blocking operation) or writing is - * still going and we want to read, suspend the new operation - */ - if ((sock->flags & SOCK_FLG_OP_PENDING) || - (m->m_type == DEV_READ_S && - sock->flags & SOCK_FLG_OP_WRITING)) { - char * o = "\0"; - if (sock->flags & SOCK_FLG_OP_READING) - o = "READ"; - else if (sock->flags & SOCK_FLG_OP_WRITING) - o = "WRITE"; - else - o = "non R/W op"; - debug_sock_print("socket %ld is busy by %s flgs 0x%x\n", - get_sock_num(sock), o, sock->flags); - if (mq_enqueue(m) != 0) { - debug_sock_print("Enqueuing suspended " - "call failed"); - send_reply(m, ENOMEM); - } - return; - } - sock->mess = *m; - socket_request_socket(sock, m); - return; - case CANCEL: - sock = get_sock(m->DEVICE); - printf("socket num %ld\n", get_sock_num(sock)); - debug_sock_print("socket num %ld", get_sock_num(sock)); - /* Cancel the last operation in the queue */ - if (mq_cancel(m)) { - send_reply(m, EINTR); - return; - /* ... or a blocked read */ - } else if (sock->flags & SOCK_FLG_OP_PENDING && - sock->flags & SOCK_FLG_OP_READING) { - sock->flags &= ~SOCK_FLG_OP_PENDING; - send_reply(m, EINTR); - return; - } else - netsock_panic("no operation to cancel"); - return; - case DEV_SELECT: - /* - * Select is always executed immediately and is never suspended. - * Although, it sets actions which must be monitored - */ - sock = get_sock(m->DEVICE); - assert(sock->select_ep == NONE || sock->select_ep == m->m_source); - - if (sock->ops && sock->ops->select) { - sock->select_ep = m->m_source; - sock->ops->select(sock, m); - if (!sock_select_set(sock)) - sock->select_ep = NONE; - } else - send_reply(m, EINVAL); - return; - default: - netsock_error("unknown message from VFS, type %d\n", - m->m_type); + return EDONTREPLY; } - send_reply(m, EGENERIC); + + return socket_request_socket(sock, req); +} + +static ssize_t netsock_read(devminor_t minor, u64_t UNUSED(position), + endpoint_t endpt, cp_grant_id_t grant, size_t size, int flags, + cdev_id_t id) +{ + struct socket *sock; + struct sock_req req; + + if (!(sock = get_sock(minor))) + return EINVAL; + + /* Build a request record for this request. */ + req.type = SOCK_REQ_READ; + req.minor = minor; + req.endpt = endpt; + req.grant = grant; + req.size = size; + req.flags = flags; + req.id = id; + + /* Process the request. */ + return netsock_request(sock, &req); +} + +static ssize_t netsock_write(devminor_t minor, u64_t UNUSED(position), + endpoint_t endpt, cp_grant_id_t grant, size_t size, int flags, + cdev_id_t id) +{ + struct socket *sock; + struct sock_req req; + + if (!(sock = get_sock(minor))) + return EINVAL; + + /* Build a request record for this request. */ + req.type = SOCK_REQ_WRITE; + req.minor = minor; + req.endpt = endpt; + req.grant = grant; + req.size = size; + req.flags = flags; + req.id = id; + + /* Process the request. */ + return netsock_request(sock, &req); +} + +static int netsock_ioctl(devminor_t minor, unsigned long request, + endpoint_t endpt, cp_grant_id_t grant, int flags, + endpoint_t UNUSED(user_endpt), cdev_id_t id) +{ + struct socket *sock; + struct sock_req req; + + if (!(sock = get_sock(minor))) + return EINVAL; + + /* Build a request record for this request. */ + req.type = SOCK_REQ_IOCTL; + req.minor = minor; + req.req = request; + req.endpt = endpt; + req.grant = grant; + req.flags = flags; + req.id = id; + + /* Process the request. */ + return netsock_request(sock, &req); +} + +static int netsock_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id) +{ + struct socket *sock; + + if (!(sock = get_sock(minor))) + return EDONTREPLY; + + debug_sock_print("socket num %ld", get_sock_num(sock)); + + /* Cancel the last operation in the queue */ + if (mq_cancel(minor, endpt, id)) + return EINTR; + + /* Cancel any ongoing blocked read */ + if ((sock->flags & SOCK_FLG_OP_PENDING) && + (sock->flags & SOCK_FLG_OP_READING) && + endpt == sock->req.endpt && id == sock->req.id) { + sock->flags &= ~SOCK_FLG_OP_PENDING; + return EINTR; + } + + /* The request may not be found. This is OK. Do not reply. */ + return EDONTREPLY; +} + +static int netsock_select(devminor_t minor, unsigned int ops, endpoint_t endpt) +{ + struct socket *sock; + int r; + + /* + * Select is always executed immediately and is never suspended. + * Although, it sets actions which must be monitored + */ + if (!(sock = get_sock(minor))) + return EBADF; + + assert(sock->select_ep == NONE || sock->select_ep == endpt); + + if (sock->ops && sock->ops->select) { + sock->select_ep = endpt; + r = sock->ops->select(sock, ops); + if (!sock_select_set(sock)) + sock->select_ep = NONE; + } else + r = EINVAL; + + return r; +} + +void socket_request(message * m, int ipc_status) +{ + debug_sock_print("request %d", m->m_type); + + /* Let the chardriver library decode the request for us. */ + chardriver_process(&netsock_tab, m, ipc_status); } void mq_process(void) { struct mq * mq; struct socket * sock; + int r; mq = mq_head; while(mq) { struct mq * next = mq->next; - sock = get_sock(mq->m.DEVICE); + sock = get_sock(mq->req.minor); if (!(sock->flags & SOCK_FLG_OP_PENDING) && - !(mq->m.m_type == DEV_READ_S && + !(mq->req.type == SOCK_REQ_READ && sock->flags & SOCK_FLG_OP_WRITING)) { debug_sock_print("resuming op on sock %ld\n", get_sock_num(sock)); - sock->mess = mq->m; - socket_request_socket(sock, &sock->mess); + sock->req = mq->req; + r = socket_request_socket(sock, &sock->req); + send_req_reply(&sock->req, r); mq_dequeue(mq); mq_free(mq); return; @@ -461,43 +502,42 @@ void mq_process(void) } } -void generic_op_select(struct socket * sock, message * m) +int generic_op_select(struct socket * sock, unsigned int sel) { - int retsel = 0, sel; + int retsel = 0; - debug_sock_print("socket num %ld 0x%x", get_sock_num(sock), m->USER_ENDPT); - - sel = m->USER_ENDPT; + debug_sock_print("socket num %ld 0x%x", get_sock_num(sock), sel); /* in this case any operation would block, no error */ if (sock->flags & SOCK_FLG_OP_PENDING) { - if (sel & SEL_NOTIFY) { - if (sel & SEL_RD) + if (sel & CDEV_NOTIFY) { + if (sel & CDEV_OP_RD) sock->flags |= SOCK_FLG_SEL_READ; - if (sel & SEL_WR) + if (sel & CDEV_OP_WR) sock->flags |= SOCK_FLG_SEL_WRITE; /* FIXME we do not monitor error */ } - sock_reply_select(sock, 0); - return; + return 0; } - if (sel & SEL_RD) { + if (sel & CDEV_OP_RD) { if (sock->recv_head) - retsel |= SEL_RD; - else if (sel & SEL_NOTIFY) + retsel |= CDEV_OP_RD; + else if (sel & CDEV_NOTIFY) sock->flags |= SOCK_FLG_SEL_READ; } /* FIXME generic packet socket never blocks on write */ - if (sel & SEL_WR) - retsel |= SEL_WR; - /* FIXME SEL_ERR is ignored, we do not generate exceptions */ + if (sel & CDEV_OP_WR) + retsel |= CDEV_OP_WR; + /* FIXME CDEV_OP_ERR is ignored, we do not generate exceptions */ - sock_reply_select(sock, retsel); + return retsel; } -void generic_op_select_reply(struct socket * sock, __unused message * m) +int generic_op_select_reply(struct socket * sock) { + unsigned int sel = 0; + assert(sock->select_ep != NONE); debug_sock_print("socket num %ld", get_sock_num(sock)); @@ -506,13 +546,15 @@ void generic_op_select_reply(struct socket * sock, __unused message * m) if (sock->flags & SOCK_FLG_OP_PENDING) { debug_sock_print("WARNING socket still blocking!"); - return; + return 0; } if (sock->flags & SOCK_FLG_SEL_READ && sock->recv_head) - m->DEV_SEL_OPS |= SEL_RD; + sel |= CDEV_OP_RD; - if (m->DEV_SEL_OPS) + if (sel) sock->flags &= ~(SOCK_FLG_SEL_WRITE | SOCK_FLG_SEL_READ | SOCK_FLG_SEL_ERROR); + + return sel; } diff --git a/lib/libpuffs/proto.h b/lib/libpuffs/proto.h index c3758a7b7..10ecfcd49 100644 --- a/lib/libpuffs/proto.h +++ b/lib/libpuffs/proto.h @@ -57,7 +57,6 @@ int fs_breadwrite(void); int fs_readwrite(void); /* stadir.c */ -int fs_fstatfs(void); int fs_stat(void); int fs_statvfs(void); diff --git a/lib/libpuffs/stadir.c b/lib/libpuffs/stadir.c index a22faa773..378b7b672 100644 --- a/lib/libpuffs/stadir.c +++ b/lib/libpuffs/stadir.c @@ -4,7 +4,6 @@ #include "fs.h" #include -#include #include #include @@ -12,30 +11,6 @@ #include "puffs_priv.h" -/*===========================================================================* - * fs_fstatfs * - *===========================================================================*/ -int fs_fstatfs() -{ - int r; - struct statvfs st_vfs; - struct statfs st; - - if (global_pu->pu_ops.puffs_fs_statvfs(global_pu, &st_vfs) != 0) { - lpuffs_debug("statfs failed\n"); - return(EINVAL); - } - - st.f_bsize = st_vfs.f_bsize; - - /* Copy the struct to user space. */ - r = sys_safecopyto(fs_m_in.m_source, (cp_grant_id_t) fs_m_in.REQ_GRANT, - (vir_bytes) 0, (vir_bytes) &st, (size_t) sizeof(st)); - - return(r); -} - - /*===========================================================================* * fs_stat * *===========================================================================*/ @@ -108,6 +83,8 @@ int fs_statvfs() int r; struct statvfs st; + memset(&st, 0, sizeof(st)); + if (global_pu->pu_ops.puffs_fs_statvfs(global_pu, &st) != 0) { lpuffs_debug("statvfs failed\n"); return(EINVAL); diff --git a/lib/libpuffs/table.c b/lib/libpuffs/table.c index b28cf6766..d00ede2c4 100644 --- a/lib/libpuffs/table.c +++ b/lib/libpuffs/table.c @@ -20,7 +20,7 @@ int (*fs_call_vec[])(void) = { fs_inhibread, /* 7 */ fs_stat, /* 8 */ fs_utime, /* 9 */ - fs_fstatfs, /* 10 */ + fs_statvfs, /* 10 */ fs_breadwrite, /* 11 */ fs_breadwrite, /* 12 */ fs_unlink, /* 13 */ @@ -42,7 +42,6 @@ int (*fs_call_vec[])(void) = { no_sys, /* 29 */ /* Was: fs_newnode */ fs_rdlink, /* 30 */ fs_getdents, /* 31 */ - fs_statvfs, /* 32 */ - no_sys, /* 33 peek */ - no_sys, /* 34 bpeek */ + no_sys, /* 32 peek */ + no_sys, /* 33 bpeek */ }; diff --git a/lib/libsffs/const.h b/lib/libsffs/const.h index ca6c37886..1064f13e7 100644 --- a/lib/libsffs/const.h +++ b/lib/libsffs/const.h @@ -8,8 +8,8 @@ /* Number of entries in the name hashtable. */ #define NUM_HASH_SLOTS 1023 -/* Arbitrary block size constant returned by fstatfs and statvfs. - * Also used by getdents. This is not the underlying data transfer unit size. +/* Arbitrary block size constant returned by statvfs. Also used by getdents. + * This is not the underlying data transfer unit size. */ #define BLOCK_SIZE 4096 diff --git a/lib/libsffs/misc.c b/lib/libsffs/misc.c index fe48d84cf..89d43b19c 100644 --- a/lib/libsffs/misc.c +++ b/lib/libsffs/misc.c @@ -1,7 +1,6 @@ /* This file contains miscellaneous file system call handlers. * * The entry points into this file are: - * do_fstatfs perform the FSTATFS file system call * do_statvfs perform the STATVFS file system call * * Created: @@ -10,24 +9,8 @@ #include "inc.h" -#include #include -/*===========================================================================* - * do_fstatfs * - *===========================================================================*/ -int do_fstatfs() -{ -/* Retrieve file system statistics. - */ - struct statfs statfs; - - statfs.f_bsize = BLOCK_SIZE; /* arbitrary block size constant */ - - return sys_safecopyto(m_in.m_source, m_in.REQ_GRANT, 0, - (vir_bytes) &statfs, sizeof(statfs)); -} - /*===========================================================================* * do_statvfs * *===========================================================================*/ @@ -60,17 +43,13 @@ int do_statvfs() /* Returning zero for unknown values seems to be the convention. However, we * do have to use a nonzero block size, even though it is entirely arbitrary. */ + statvfs.f_flag = ST_NOTRUNC; statvfs.f_bsize = BLOCK_SIZE; statvfs.f_frsize = BLOCK_SIZE; + statvfs.f_iosize = BLOCK_SIZE; statvfs.f_blocks = div64u(total, BLOCK_SIZE); statvfs.f_bfree = div64u(free, BLOCK_SIZE); statvfs.f_bavail = statvfs.f_bfree; - statvfs.f_files = 0; - statvfs.f_ffree = 0; - statvfs.f_favail = 0; - statvfs.f_fsid = state.s_dev; - statvfs.f_flag = state.s_read_only ? ST_RDONLY : 0; - statvfs.f_flag |= ST_NOTRUNC; statvfs.f_namemax = NAME_MAX; return sys_safecopyto(m_in.m_source, m_in.REQ_GRANT, 0, diff --git a/lib/libsffs/proto.h b/lib/libsffs/proto.h index fcc1a76aa..fb4131243 100644 --- a/lib/libsffs/proto.h +++ b/lib/libsffs/proto.h @@ -37,7 +37,6 @@ int do_lookup(void); int main(int argc, char *argv[]); /* misc.c */ -int do_fstatfs(void); int do_statvfs(void); /* mount.c */ diff --git a/lib/libsffs/table.c b/lib/libsffs/table.c index 35e778dec..125b6041b 100644 --- a/lib/libsffs/table.c +++ b/lib/libsffs/table.c @@ -18,7 +18,7 @@ int (*call_vec[])(void) = { do_noop, /* 7 inhibread */ do_stat, /* 8 stat */ do_utime, /* 9 utime */ - do_fstatfs, /* 10 fstatfs */ + do_statvfs, /* 10 statvfs */ no_sys, /* 11 bread */ no_sys, /* 12 bwrite */ do_unlink, /* 13 unlink */ @@ -40,8 +40,7 @@ int (*call_vec[])(void) = { no_sys, /* 29 newnode */ no_sys, /* 30 rdlink */ do_getdents, /* 31 getdents */ - do_statvfs, /* 32 statvfs */ - no_sys, /* 33 peek */ + no_sys, /* 32 peek */ no_sys, /* 33 bpeek */ }; diff --git a/lib/libsys/Makefile b/lib/libsys/Makefile index 9b2ec3d36..9468788b9 100644 --- a/lib/libsys/Makefile +++ b/lib/libsys/Makefile @@ -38,6 +38,7 @@ SRCS+= \ sys_abort.c \ sys_clear.c \ sys_cprof.c \ + sys_diagctl.c \ sys_endsig.c \ sys_exec.c \ sys_exit.c \ @@ -66,7 +67,6 @@ SRCS+= \ sys_sprof.c \ sys_statectl.c \ sys_stime.c \ - sys_sysctl.c \ sys_times.c \ sys_trace.c \ sys_umap.c \ @@ -76,7 +76,6 @@ SRCS+= \ sys_vsafecopy.c \ sys_vtimer.c \ sys_vumap.c \ - send_taskreply.c \ taskcall.c \ tickdelay.c \ timers.c \ diff --git a/lib/libsys/kputc.c b/lib/libsys/kputc.c index 9e7301272..7a2106dcc 100644 --- a/lib/libsys/kputc.c +++ b/lib/libsys/kputc.c @@ -20,7 +20,7 @@ void kputc(int c) static int buf_count; /* # characters in the buffer */ if ((c == 0 && buf_count > 0) || buf_count == sizeof(print_buf)) { - sys_sysctl(SYSCTL_CODE_DIAG, print_buf, buf_count); + sys_diagctl_diag(print_buf, buf_count); buf_count = 0; } if (c != 0) { diff --git a/lib/libsys/send_taskreply.c b/lib/libsys/send_taskreply.c deleted file mode 100644 index c14daf573..000000000 --- a/lib/libsys/send_taskreply.c +++ /dev/null @@ -1,20 +0,0 @@ - -#include - -#include "syslib.h" - -/*===========================================================================* - * sys_taskreply * - *===========================================================================*/ -int send_taskreply(endpoint_t who, endpoint_t endpoint, int status) -{ - message m; - - memset(&m, 0, sizeof(m)); - - m.REP_ENDPT = endpoint; - m.REP_STATUS = status; - - return _sendcall(who, TASK_REPLY, &m); -} - diff --git a/lib/libsys/sys_diagctl.c b/lib/libsys/sys_diagctl.c new file mode 100644 index 000000000..bf7ca5d8c --- /dev/null +++ b/lib/libsys/sys_diagctl.c @@ -0,0 +1,13 @@ + +#include "syslib.h" + +int sys_diagctl(int code, char *arg1, int arg2) +{ + message m; + + m.DIAGCTL_CODE = code; + m.DIAGCTL_ARG1 = arg1; + m.DIAGCTL_ARG2 = arg2; + + return(_kernel_call(SYS_DIAGCTL, &m)); +} diff --git a/lib/libsys/sys_sysctl.c b/lib/libsys/sys_sysctl.c deleted file mode 100644 index 443a9cc97..000000000 --- a/lib/libsys/sys_sysctl.c +++ /dev/null @@ -1,20 +0,0 @@ - -#include "syslib.h" - -int sys_sysctl(int code, char *arg1, int arg2) -{ - message m; - - m.SYSCTL_CODE = code; - m.SYSCTL_ARG1 = arg1; - m.SYSCTL_ARG2 = arg2; - - return(_kernel_call(SYS_SYSCTL, &m)); - -} - -int sys_sysctl_stacktrace(endpoint_t ep) -{ - return sys_sysctl(SYSCTL_CODE_STACKTRACE, NULL, ep); -} - diff --git a/lib/libsys/vm_cache.c b/lib/libsys/vm_cache.c index ce844acf0..171ba39c8 100644 --- a/lib/libsys/vm_cache.c +++ b/lib/libsys/vm_cache.c @@ -60,3 +60,17 @@ int vm_set_cacheblock(void *block, u32_t dev, u64_t dev_offset, return vm_cachecall(&m, VM_SETCACHEPAGE, block, dev, dev_offset, ino, ino_offset, flags, blocksize); } + +int +vm_clear_cache(u32_t dev) +{ + message m; + + assert(dev != NO_DEV); + + memset(&m, 0, sizeof(m)); + + m.m_u.m_vmmcp.dev = dev; + + return _taskcall(VM_PROC_NR, VM_CLEARCACHE, &m); +} diff --git a/lib/libutil/Makefile b/lib/libutil/Makefile index 601fc4d81..8994b79aa 100644 --- a/lib/libutil/Makefile +++ b/lib/libutil/Makefile @@ -42,7 +42,7 @@ SRCS+= efun.c \ passwd.c pw_scan.c pidfile.c pidlock.c pty.c \ raise_default_signal.c \ secure_path.c stat_flags.c \ - ttyaction.c \ + strpct.c ttyaction.c \ MAN= efun.3 \ getmntopts.3 \ @@ -50,7 +50,7 @@ MAN= efun.3 \ opendisk.3 openpty.3 pidfile.3 pidlock.3 \ pw_getconf.3 pw_init.3 pw_lock.3 secure_path.3 \ raise_default_signal.3 \ - snprintb.3 stat_flags.3 ttyaction.3 \ + snprintb.3 stat_flags.3 strpct.3 ttyaction.3 \ util.3 .endif diff --git a/lib/libutil/opendisk.c b/lib/libutil/opendisk.c index 18a314f4f..25daa348c 100644 --- a/lib/libutil/opendisk.c +++ b/lib/libutil/opendisk.c @@ -54,6 +54,14 @@ __opendisk(const char *path, int flags, char *buf, size_t buflen, int iscooked, int f; #endif +#ifdef __minix + /* + * MINIX does not have the cooked/raw distinction. Do not prepend 'r' + * to the device name when generating a full path. + */ + iscooked = 1; +#endif + if (buf == NULL) { errno = EFAULT; return (-1); @@ -80,6 +88,7 @@ __opendisk(const char *path, int flags, char *buf, size_t buflen, int iscooked, f = ofn(buf, flags, 0); if (f != -1 || errno != ENOENT) return (f); +#endif if (strchr(path, '/') != NULL) return (-1); @@ -89,6 +98,7 @@ __opendisk(const char *path, int flags, char *buf, size_t buflen, int iscooked, if (f != -1 || errno != ENOENT) return (f); +#ifndef __minix snprintf(buf, buflen, "%s%s%s%c", _PATH_DEV, iscooked ? "" : "r", path, 'a' + rawpart); f = ofn(buf, flags, 0); diff --git a/lib/libvtreefs/proto.h b/lib/libvtreefs/proto.h index 6199583f8..6c558da73 100644 --- a/lib/libvtreefs/proto.h +++ b/lib/libvtreefs/proto.h @@ -32,7 +32,6 @@ long sdbm_hash(char *str, int len); /* stadir.c */ int fs_stat(void); -int fs_fstatfs(void); int fs_statvfs(void); /* utility.c */ diff --git a/lib/libvtreefs/stadir.c b/lib/libvtreefs/stadir.c index c2f9a1e50..82c313334 100644 --- a/lib/libvtreefs/stadir.c +++ b/lib/libvtreefs/stadir.c @@ -3,7 +3,6 @@ #include "inc.h" #include -#include #include #include @@ -56,23 +55,7 @@ int fs_stat(void) } /*===========================================================================* - * fs_fstatfs * - *===========================================================================*/ -int fs_fstatfs(void) -{ - /* Retrieve file system statistics. - */ - struct statfs statfs; - - memset(&statfs, 0, sizeof(statfs)); - - /* Copy the struct to user space. */ - return sys_safecopyto(fs_m_in.m_source, fs_m_in.REQ_GRANT, 0, - (vir_bytes) &statfs, (phys_bytes) sizeof(statfs)); -} - -/*===========================================================================* - * fs_fstatfs * + * fs_statvfs * *===========================================================================*/ int fs_statvfs(void) { @@ -82,8 +65,7 @@ int fs_statvfs(void) memset(&statvfs, 0, sizeof(statvfs)); - statvfs.f_fsid = fs_dev; - statvfs.f_flag = ST_RDONLY | ST_NOTRUNC; + statvfs.f_flag = ST_NOTRUNC; statvfs.f_namemax = PNAME_MAX; return sys_safecopyto(fs_m_in.m_source, fs_m_in.REQ_GRANT, 0, diff --git a/lib/libvtreefs/table.c b/lib/libvtreefs/table.c index d3f20fac5..468dccba7 100644 --- a/lib/libvtreefs/table.c +++ b/lib/libvtreefs/table.c @@ -14,7 +14,7 @@ int (*fs_call_vec[])(void) = { do_noop, /* 7 inhibread */ fs_stat, /* 8 stat */ no_sys, /* 9 utime */ - fs_fstatfs, /* 10 fstatfs */ + fs_statvfs, /* 10 statvfs */ no_sys, /* 11 bread */ no_sys, /* 12 bwrite */ no_sys, /* 13 unlink */ @@ -36,9 +36,8 @@ int (*fs_call_vec[])(void) = { no_sys, /* 29 newnode */ fs_rdlink, /* 30 rdlink */ fs_getdents, /* 31 getdents */ - fs_statvfs, /* 32 statvfs */ - no_sys, /* 33 peek */ - no_sys, /* 34 bpeek */ + no_sys, /* 32 peek */ + no_sys, /* 33 bpeek */ }; /* This should not fail with "array size is negative": */ diff --git a/man/man1/Makefile b/man/man1/Makefile index 2e7f2b231..ce4ee0075 100644 --- a/man/man1/Makefile +++ b/man/man1/Makefile @@ -2,9 +2,8 @@ MAN= ash.1 at.1 \ bsfilt.1 cawf.1 chgrp.1 \ chmod.1 cmp.1 comm.1 compress.1 \ cp.1 crc.1 crontab.1 dd.1 \ - df.1 dhrystone.1 dosdir.1 dosread.1 doswrite.1 \ - dumpcore.1 eject.1 \ - env.1 factor.1 \ + dhrystone.1 dosdir.1 dosread.1 doswrite.1 \ + eject.1 env.1 factor.1 \ flexdoc.1 fold.1 format.1 fortune.1 \ fsck.mfs.1 host.1 hostaddr.1 ifdef.1 \ isodir.1 isoinfo.1 isoread.1 \ diff --git a/man/man1/df.1 b/man/man1/df.1 deleted file mode 100644 index 7c9d7575c..000000000 --- a/man/man1/df.1 +++ /dev/null @@ -1,75 +0,0 @@ -.TH DF 1 -.SH NAME -df \- report on free disk space -.SH SYNOPSIS -\fBdf\fP [\fB\-ikP\fP] [\fB\-t\fP \fItype\fP] [\fIfile\fP ...] -.SH DESCRIPTION -.B Df -lists the amount of free space on the currently mounted devices (no arguments), -or the devices given as arguments. If the argument is not a device then the -device it resides on is listed. -.SH OPTIONS -Without options, -.B df -will give a listing like this: -.sp -.nf -.if t .ft C -Filesystem 1k-Blocks free used % FUsed% Mounted on -/dev/c0d0p1s0 1440 635 805 56% 26% / -/dev/c0d0p1s1 32768 32390 378 2% 1% /tmp -/dev/c0d0p1s2 784657 517809 266848 35% 29% /usr -.if t .ft R -.fi -.PP -The -.B \-i -option shifts the focus to the files: -.sp -.nf -.if t .ft C -Filesystem Files free used % BUsed% Mounted on -/dev/c0d0p1s0 1024 759 265 26% 56% / -/dev/c0d0p1s1 5472 5468 4 1% 2% /tmp -/dev/c0d0p1s2 65535 46734 18801 29% 35% /usr -.if t .ft R -.fi -.PP -Option -.B \-P -makes -.B df -use \s-2POSIX\s+2 defined output in 512 byte units: -.sp -.nf -.if t .ft C -Filesystem 512-blocks Used Available Capacity Mounted on -/dev/c0d0p1s0 2880 1628 1252 57% / -/dev/c0d0p1s1 65536 756 64780 2% /tmp -/dev/c0d0p1s2 1569314 533748 1035566 35% /usr -.if t .ft R -.fi -.PP -With -.B \-k -1024 byte units would be used. -.PP -The -.B \-t -option limits -.BR df 's -output to file systems of the given -.IR type . -.SH FILES -.TP 15n -.B /etc/mtab -List of mounted file systems. -.SH "SEE ALSO" -.BR du (1), -.BR fstab (5). -.SH BUGS -Default output should also be in 512 byte units says \s-2POSIX\s+2. -.SH AUTHOR -Kees J. Bot (kjb@cs.vu.nl) -.\" -.\" $PchId: df.1,v 1.5 1998/07/27 19:48:47 philip Exp $ diff --git a/man/man1/dumpcore.1 b/man/man1/dumpcore.1 deleted file mode 100644 index 2f3926a93..000000000 --- a/man/man1/dumpcore.1 +++ /dev/null @@ -1,29 +0,0 @@ -.TH DUMPCORE 1 -.SH NAME -dumpcore \- generate core file of running process -.SH SYNOPSIS -dumpcore \fIpid\fR -.br -.de FL -.TP -\\fB\\$1\\fR -\\$2 -.. -.de EX -.TP 20 -\\fB\\$1\\fR -# \\$2 -.. -.SH DESCRIPTION -The \fBdumpcore\fR utility generates a core file for a running process, based -on that process's process ID (\fIpid\fP). The resulting core file will be -stored under the name "core" in the current working directory. Any previous -file with that name will be overwritten. -.PP -The resulting core file can be used with for example -.BR mdb (1). -.SH BUGS -The process of generating the core file is currently very rudimentary, and -the generated core file does not contain for example memory mapped areas. -.SH "SEE ALSO" -.BR mdb (1). diff --git a/man/man2/Makefile b/man/man2/Makefile index edbfe5852..40c3ecf7f 100644 --- a/man/man2/Makefile +++ b/man/man2/Makefile @@ -8,7 +8,7 @@ MAN= accept.2 access.2 alarm.2 bind.2 brk.2 chdir.2 chmod.2 chown.2 \ rmdir.2 select.2 send.2 sendmsg.2 sendto.2 setsid.2 \ setsockopt.2 setuid.2 shutdown.2 sigaction.2 sigpending.2 \ sigprocmask.2 sigsuspend.2 socket.2 socketpair.2 \ - statvfs.2 svrctl.2 symlink.2 sync.2 time.2 times.2 truncate.2 \ + svrctl.2 symlink.2 sync.2 time.2 times.2 truncate.2 \ umask.2 uname.2 unlink.2 utime.2 wait.2 write.2 MLINKS += select.2 FD_CLR.2 @@ -16,7 +16,6 @@ MLINKS += select.2 FD_ISSET.2 MLINKS += select.2 FD_SET.2 MLINKS += setuid.2 seteuid.2 MLINKS += setuid.2 setgid.2 -MLINKS += statvfs.2 fstatvfs.2 .include .include diff --git a/man/man2/intro.2 b/man/man2/intro.2 index 30eeea535..69e1afdcd 100644 --- a/man/man2/intro.2 +++ b/man/man2/intro.2 @@ -266,7 +266,6 @@ caller-provided space. .It Er 51 ENOBUFS Em "\&No buffer space available" . An operation on a socket or pipe was not performed because the system lacked sufficient buffer space or because a queue was full. -.It Er 52 EBADIOCTL Em "Illegal ioctl for device" . .It Er 53 EBADMODE Em "Bad mode in ioctl" . .It Er 54 EWOULDBLOCK Em "Would block" . .It Er 55 ENETUNREACH Em "Network is unreachable" . diff --git a/man/man2/mount.2 b/man/man2/mount.2 index d86d6375f..78d762fea 100644 --- a/man/man2/mount.2 +++ b/man/man2/mount.2 @@ -6,9 +6,8 @@ mount, umount \- mount or umount a file system .nf #include -int mount(char *\fIspecial\fP, char *\fIname\fP, int \fImountflags\fP, char *\fItype\fP, char *\fIargs\fP) -int umount(char *\fIname\fP) -int umount2(char *\fIname\fP, int \fIflags) +int mount(char *\fIspecial\fP, char *\fIname\fP, int \fImountflags\fP, int \fIsrvflags\fP, char *\fItype\fP, char *\fIargs\fP) +int umount(char *\fIname\fP, int \fIsrvflags) .fi .ft P .SH DESCRIPTION @@ -34,9 +33,12 @@ mounted without a block device. .I Mountflags may be a bitwise combination of the following flags: .TP 2 -.B MS_RDONLY +.B MNT_RDONLY Mount file system read-only, rather than read-write. -.TP +.PP +.I Srvflags +may be a bitwise combination of the following flags: +.TP 2 .B MS_REUSE Reuse the file system server image if possible. .TP @@ -60,12 +62,7 @@ may refer to either of them. If more than one device is mounted on the same mount point then unmounting at the mount point removes the last mounted device, unmounting a device removes precisely that device. The unmount will only succeed if none of the files on the device are in use. -.PP -.B Umount2() -Same as Umount(), but takes an additional -.I flags -parameter. -.I Flags +.I Srvflags may be a bitwise combination of the following flags: .TP 2 .B MS_EXISTING diff --git a/man/man2/statvfs.2 b/man/man2/statvfs.2 deleted file mode 100644 index 505ead513..000000000 --- a/man/man2/statvfs.2 +++ /dev/null @@ -1,133 +0,0 @@ -.\" $NetBSD: statvfs.2,v 1.4 2005/11/04 06:09:20 gendalia Exp $ -.\" -.\" Copyright (c) 1989, 1991, 1993 -.\" The Regents of the University of California. All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. Neither the name of the University nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" @(#)statfs.2 8.5 (Berkeley) 5/24/95 -.\" -.Dd April 14, 2004 -.Dt STATVFS 2 -.Os -.Sh NAME -.Nm statvfs , -.Nm fstatvfs , -.Nd get file system statistics -.Sh LIBRARY -.Lb libc -.Sh SYNOPSIS -.In sys/statvfs.h -.Ft int -.Fn statvfs "const char *path" "struct statvfs *buf" -.Ft int -.Fn fstatvfs "int fd" "struct statvfs *buf" -.Sh DESCRIPTION -.Fn statvfs -returns information about a mounted file system. -.Fa path -is the path name of any file within the mounted file system. -.Fa buf -is a pointer to a -.Nm statvfs -structure defined in -.Xr statvfs 5 . -.Pp -.Fn fstatvfs -returns the same information about an open file referenced by descriptor -.Fa fd . -.Pp -.Sh RETURN VALUES -Upon successful completion, a value of 0 is returned. -Otherwise, \-1 is returned and the global variable -.Va errno -is set to indicate the error. -.Sh ERRORS -.Fn statvfs -fails if one or more of the following are true: -.Bl -tag -width Er -.It Bq Er ENOTDIR -A component of the path prefix of -.Fa path -is not a directory. -.It Bq Er ENAMETOOLONG -The length of a component of -.Fa path -exceeds -.Dv NAME_MAX -characters, or the length of -.Fa path -exceeds -.Dv PATH_MAX -characters. -.It Bq Er ENOENT -The file referred to by -.Fa path -does not exist. -.It Bq Er EACCES -Search permission is denied for a component of the path prefix of -.Fa path . -.It Bq Er ELOOP -Too many symbolic links were encountered in translating -.Fa path . -.It Bq Er EFAULT -.Fa buf -or -.Fa path -points to an invalid address. -.It Bq Er EIO -An -.Tn I/O -error occurred while reading from or writing to the file system. -.El -.Pp -.Fn fstatvfs -fails if one or more of the following are true: -.Bl -tag -width Er -.It Bq Er EBADF -.Fa fd -is not a valid open file descriptor. -.It Bq Er EFAULT -.Fa buf -points to an invalid address. -.It Bq Er EIO -An -.Tn I/O -error occurred while reading from or writing to the file system. -.El -.Sh SEE ALSO -.Xr statvfs 5 -.Sh HISTORY -The -.Fn statvfs , -and -.Fn fstatvfs , -functions first appeared in -.Nx 3.0 -to replace -the -.Fn statfs -family of functions which first appeared in -.Bx 4.4 . diff --git a/man/man4/ip.4 b/man/man4/ip.4 index c7b8d7e5c..483971353 100644 --- a/man/man4/ip.4 +++ b/man/man4/ip.4 @@ -1420,7 +1420,7 @@ This indicates an attempt to read or write with a buffer that is too large or too small. .IP ENOBUFS The TCP/IP server has insufficient memory to execute the request. -.IP EBADIOCTL +.IP ENOTTY This indicates an attempt to execute a command the particular server does not understand. For example, a diff --git a/releasetools/Makefile b/releasetools/Makefile index 429caa327..e113858c5 100644 --- a/releasetools/Makefile +++ b/releasetools/Makefile @@ -24,7 +24,6 @@ PROGRAMS+= ${PROGROOT}/servers/pm/pm PROGRAMS+= ${PROGROOT}/servers/sched/sched PROGRAMS+= ${PROGROOT}/servers/vfs/vfs PROGRAMS+= ${PROGROOT}/drivers/memory/memory -PROGRAMS+= ${PROGROOT}/drivers/log/log PROGRAMS+= ${PROGROOT}/drivers/tty/tty PROGRAMS+= ${PROGROOT}/servers/mfs/mfs PROGRAMS+= ${PROGROOT}/servers/vm/vm diff --git a/releasetools/arm_sdimage.sh b/releasetools/arm_sdimage.sh index 9bdebca6b..cbeb4176d 100755 --- a/releasetools/arm_sdimage.sh +++ b/releasetools/arm_sdimage.sh @@ -211,7 +211,7 @@ do mcopy -bsp -i ${IMG_DIR}/fat.img ${OBJ}/${f}.elf ::${f}.elf done -for f in tty memory log +for f in tty memory do cp ${OBJ}/drivers/${f}/${f} ${OBJ}/${f}.elf ${CROSS_PREFIX}strip -s ${OBJ}/${f}.elf diff --git a/releasetools/gen_uEnv.txt.sh b/releasetools/gen_uEnv.txt.sh index 6cd7552dc..a5c64a127 100755 --- a/releasetools/gen_uEnv.txt.sh +++ b/releasetools/gen_uEnv.txt.sh @@ -8,13 +8,12 @@ list="0x80200000 kernel.bin 0x83800000 sched.elf 0x84000000 vfs.elf 0x84800000 memory.elf -0x85000000 log.elf -0x85800000 tty.elf -0x86000000 mfs.elf -0x86800000 vm.elf -0x87000000 pfs.elf -0x87800000 init.elf -0x88000000 cmdline.txt" +0x85000000 tty.elf +0x85800000 mfs.elf +0x86000000 vm.elf +0x86800000 pfs.elf +0x87000000 init.elf +0x87800000 cmdline.txt" # # PREFIX for loading file over tftp to allow hosting multiple @@ -63,12 +62,12 @@ echo "# Set the command to be executed" echo "uenvcmd=run $BOOT" echo echo "# With cmdline/bootargs in cmdline.txt" -echo "mmcbootcmd=echo starting from MMC ; mmc part 0; mw.b 0x88000000 0 16384 $(fill_cmd "fatload mmc 0:1" "") ; dcache off ; icache off ; go 0x80200000" +echo "mmcbootcmd=echo starting from MMC ; mmc part 0; mw.b 0x87800000 0 16384 $(fill_cmd "fatload mmc 0:1" "") ; dcache off ; icache off ; go 0x80200000" echo echo "# Netbooting." echo "serverip=192.168.12.10" echo "ipaddr=192.168.12.62" echo "usbnet_devaddr=e8:03:9a:24:f9:10" echo "usbethaddr=e8:03:9a:24:f9:11" -echo "netbootcmd=echo starting from TFTP; mw.b 0x88000000 0 16384 $(fill_cmd "tftp" "$NETBOOT_PREFIX") ; dcache off ; icache off ; go 0x80200000" +echo "netbootcmd=echo starting from TFTP; mw.b 0x87800000 0 16384 $(fill_cmd "tftp" "$NETBOOT_PREFIX") ; dcache off ; icache off ; go 0x80200000" exit 0 diff --git a/releasetools/nbsd_ports b/releasetools/nbsd_ports index 5de902ff8..48a81d4c1 100644 --- a/releasetools/nbsd_ports +++ b/releasetools/nbsd_ports @@ -8,6 +8,7 @@ # netbsdpath: path in BSD source tree (starting from src/) 2012/01/16 18:47:57,bin/cat 2011/08/27 12:55:09,bin/date +2013/08/19 12:00:00,bin/df 2012/10/17 12:00:00,bin/echo 2012/01/16 18:47:57,bin/ed 2012/10/17 12:00:00,bin/expr @@ -110,6 +111,7 @@ 2013/04/23 12:00:00,sys/dev/i2c/Makefile 2013/04/23 12:00:00,sys/dev/i2c/i2c_io.h 2013/07/22 12:00:00,sys/dev/videomode +2013/07/31 12:00:00,sys/dev/vndvar.h 2012/01/16 18:47:57,sys/lib/libsa 2012/10/17 12:00:00,sys/lib/libz 2012/10/17 12:00:00,sys/Makefile @@ -208,4 +210,5 @@ 2013/04/05 12:00:00,usr.sbin/rdate 2011/01/04 10:30:21,usr.sbin/user 2009/04/19 00:44:49,usr.sbin/vipw +2013/07/31 12:00:00,usr.sbin/vnconfig 2009/04/22 15:23:10,usr.sbin/zic diff --git a/releasetools/release.functions b/releasetools/release.functions index 7f83c252b..df128d6f7 100644 --- a/releasetools/release.functions +++ b/releasetools/release.functions @@ -73,12 +73,11 @@ load=/mod03_pm load=/mod04_sched load=/mod05_vfs load=/mod06_memory -load=/mod07_log -load=/mod08_tty -load=/mod09_mfs -load=/mod10_vm -load=/mod11_pfs -load=/mod12_init +load=/mod07_tty +load=/mod08_mfs +load=/mod09_vm +load=/mod10_pfs +load=/mod11_init # This space intentionally left blank - leave to appease bootloader! # This space intentionally left blank - leave to appease bootloader! # This space intentionally left blank - leave to appease bootloader! diff --git a/releasetools/release.sh b/releasetools/release.sh index 91d9d6bbe..2539ee3e4 100755 --- a/releasetools/release.sh +++ b/releasetools/release.sh @@ -337,7 +337,7 @@ mount $TMPDISKUSR $RELEASEMNTDIR/usr || exit echo " * Copying files from staging to image" ########################################################################## synctree -f $RELEASEDIR $RELEASEMNTDIR > /dev/null || true -expr `df -k $TMPDISKUSR | tail -1 | awk '{ print $4 }'` - $extrakb >$RELEASEMNTDIR/.usrkb +expr `/bin/df -kP $TMPDISKUSR | tail -1 | awk '{ print $3 }'` - $extrakb >$RELEASEMNTDIR/.usrkb echo " * Unmounting $TMPDISKUSR from $RELEASEMNTDIR/usr" umount $TMPDISKUSR || exit diff --git a/sbin/newfs_ext2fs/newfs_ext2fs.c b/sbin/newfs_ext2fs/newfs_ext2fs.c index f3cc5ad89..1c79f8467 100644 --- a/sbin/newfs_ext2fs/newfs_ext2fs.c +++ b/sbin/newfs_ext2fs/newfs_ext2fs.c @@ -136,12 +136,12 @@ main(int argc, char *argv[]) #ifndef __minix struct disk_geom geo; struct dkwedge_info dkw; - struct statvfs *mp; - char *s2; - int len, n; #else u64_t minix_fssize; #endif + struct statvfs *mp; + char *s2; + int len, n; struct stat sb; int ch, fsi, fso, Fflag, Iflag, Zflag; char *cp, *s1, *special; @@ -280,7 +280,6 @@ main(int argc, char *argv[]) if (fsi < 0 || fstat(fsi, &sb) == -1) err(EXIT_FAILURE, "%s: open for read", special); -#ifndef __minix if (!Nflag) { fso = open(special, O_WRONLY, 0); if (fso < 0) @@ -312,6 +311,7 @@ main(int argc, char *argv[]) } } +#ifndef __minix if (getdiskinfo(special, fsi, disktype, &geo, &dkw) == -1) errx(EXIT_FAILURE, lmsg, special); @@ -335,12 +335,6 @@ main(int argc, char *argv[]) } } #else - { - fso = open(special, O_WRONLY, 0); - if (fso < 0) - err(EXIT_FAILURE, - "%s: open for write", special); - if(minix_sizeup(special, &minix_fssize) < 0) errx(EXIT_FAILURE, "minix_sizeup failed"); @@ -349,7 +343,6 @@ main(int argc, char *argv[]) if (sectorsize == 0) sectorsize = 512; - } #endif } diff --git a/servers/ext2/mount.c b/servers/ext2/mount.c index 956de908a..29f9c6399 100644 --- a/servers/ext2/mount.c +++ b/servers/ext2/mount.c @@ -54,7 +54,8 @@ int fs_readsuper() bdev_driver(fs_dev, fs_dev_label); /* Open the device the file system lives on. */ - if (bdev_open(fs_dev, readonly ? R_BIT : (R_BIT|W_BIT)) != OK) { + if (bdev_open(fs_dev, readonly ? BDEV_R_BIT : (BDEV_R_BIT|BDEV_W_BIT)) != + OK) { return(EINVAL); } @@ -241,6 +242,9 @@ int fs_unmount() /* Close the device the file system lives on. */ bdev_close(fs_dev); + /* Throw all blocks out of the VM cache, to prevent corruption later. */ + lmfs_invalidate(fs_dev); + /* Finish off the unmount. */ superblock->s_dev = NO_DEV; unmountdone = TRUE; diff --git a/servers/ext2/proto.h b/servers/ext2/proto.h index b66291f1e..f7f890d52 100644 --- a/servers/ext2/proto.h +++ b/servers/ext2/proto.h @@ -81,7 +81,6 @@ block_t read_map(struct inode *rip, off_t pos, int opportunistic); struct buf *get_block_map(register struct inode *rip, u64_t position); /* stadir.c */ -int fs_fstatfs(void); int fs_stat(void); int fs_statvfs(void); diff --git a/servers/ext2/stadir.c b/servers/ext2/stadir.c index d5a245979..31bdfa880 100644 --- a/servers/ext2/stadir.c +++ b/servers/ext2/stadir.c @@ -5,7 +5,6 @@ #include "fs.h" #include #include -#include #include #include "inode.h" #include "super.h" @@ -60,28 +59,6 @@ static int stat_inode( } -/*===========================================================================* - * fs_fstatfs * - *===========================================================================*/ -int fs_fstatfs() -{ - struct statfs st; - struct inode *rip; - int r; - - if((rip = find_inode(fs_dev, ROOT_INODE)) == NULL) - return(EINVAL); - - st.f_bsize = rip->i_sp->s_block_size; - - /* Copy the struct to user space. */ - r = sys_safecopyto(fs_m_in.m_source, (cp_grant_id_t) fs_m_in.REQ_GRANT, - (vir_bytes) 0, (vir_bytes) &st, (size_t) sizeof(st)); - - return(r); -} - - /*===========================================================================* * fs_stat * *===========================================================================*/ @@ -107,19 +84,20 @@ int fs_statvfs() struct super_block *sp; int r; + memset(&st, 0, sizeof(st)); + sp = get_super(fs_dev); + st.f_flag = ST_NOTRUNC; st.f_bsize = sp->s_block_size; st.f_frsize = sp->s_block_size; + st.f_iosize = sp->s_block_size; st.f_blocks = sp->s_blocks_count; st.f_bfree = sp->s_free_blocks_count; st.f_bavail = sp->s_free_blocks_count - sp->s_r_blocks_count; st.f_files = sp->s_inodes_count; st.f_ffree = sp->s_free_inodes_count; st.f_favail = sp->s_free_inodes_count; - st.f_fsid = fs_dev; - st.f_flag = (sp->s_rd_only == 1 ? ST_RDONLY : 0); - st.f_flag |= ST_NOTRUNC; st.f_namemax = NAME_MAX; /* Copy the struct to user space. */ diff --git a/servers/ext2/table.c b/servers/ext2/table.c index 1d779a9a6..7f3528427 100644 --- a/servers/ext2/table.c +++ b/servers/ext2/table.c @@ -23,7 +23,7 @@ int (*fs_call_vec[])(void) = { fs_inhibread, /* 7 */ fs_stat, /* 8 */ fs_utime, /* 9 */ - fs_fstatfs, /* 10 */ + fs_statvfs, /* 10 */ fs_breadwrite, /* 11 */ fs_breadwrite, /* 12 */ fs_unlink, /* 13 */ @@ -45,7 +45,6 @@ int (*fs_call_vec[])(void) = { no_sys, /* 29 */ /* Was: fs_newnode */ fs_rdlink, /* 30 */ fs_getdents, /* 31 */ - fs_statvfs, /* 32 */ - fs_readwrite, /* 33 */ - fs_bpeek, /* 34 */ + fs_readwrite, /* 32 */ + fs_bpeek, /* 33 */ }; diff --git a/servers/inet/generic/eth.c b/servers/inet/generic/eth.c index e3e9df6e0..685b7ee88 100644 --- a/servers/inet/generic/eth.c +++ b/servers/inet/generic/eth.c @@ -412,7 +412,7 @@ printf("eth_ioctl: setting etp_getstat in port %d to %p\n", default: break; } - reply_thr_put(eth_fd, EBADIOCTL, TRUE); + reply_thr_put(eth_fd, ENOTTY, TRUE); return NW_OK; } diff --git a/servers/inet/generic/ip_ioctl.c b/servers/inet/generic/ip_ioctl.c index 327e85106..4b63f3de3 100644 --- a/servers/inet/generic/ip_ioctl.c +++ b/servers/inet/generic/ip_ioctl.c @@ -424,7 +424,7 @@ ioreq_t req; if (ip_port->ip_dl_type != IPDL_ETH) { return (*ip_fd->if_put_userdata)(ip_fd->if_srfd, - EBADIOCTL, (acc_t *)0, TRUE); + ENOTTY, (acc_t *)0, TRUE); } if (!(ip_port->ip_flags & IPF_IPADDRSET)) @@ -445,8 +445,8 @@ ioreq_t req; default: break; } - DBLOCK(1, printf("replying EBADIOCTL: 0x%x\n", req)); - return (*ip_fd->if_put_userdata)(ip_fd->if_srfd, EBADIOCTL, + DBLOCK(1, printf("replying ENOTTY: 0x%lx\n", req)); + return (*ip_fd->if_put_userdata)(ip_fd->if_srfd, ENOTTY, (acc_t *)0, TRUE); } diff --git a/servers/inet/generic/tcp.c b/servers/inet/generic/tcp.c index 2c072548f..6827e65f8 100644 --- a/servers/inet/generic/tcp.c +++ b/servers/inet/generic/tcp.c @@ -957,7 +957,7 @@ assert (conf_acc->acc_length == sizeof(*io_tcp_conf)); default: tcp_fd->tf_flags &= ~TFF_IOCTL_IP; - reply_thr_get(tcp_fd, EBADIOCTL, TRUE); + reply_thr_get(tcp_fd, ENOTTY, TRUE); result= NW_OK; break; } diff --git a/servers/inet/generic/udp.c b/servers/inet/generic/udp.c index da12ff645..9dfc60785 100644 --- a/servers/inet/generic/udp.c +++ b/servers/inet/generic/udp.c @@ -183,7 +183,7 @@ assert (opt_acc->acc_length == sizeof(*udp_opt)); result= udp_peek(udp_fd); break; default: - reply_thr_get(udp_fd, EBADIOCTL, TRUE); + reply_thr_get(udp_fd, ENOTTY, TRUE); result= NW_OK; break; } diff --git a/servers/inet/inet.c b/servers/inet/inet.c index 24ffa0b9e..c18dd58cc 100644 --- a/servers/inet/inet.c +++ b/servers/inet/inet.c @@ -2,35 +2,6 @@ minix. Furthermore it contains the main loop of the network task. Copyright 1995 Philip Homburg - -The valid messages and their parameters are: - -from FS: - __________________________________________________________________ -| | | | | | | -| m_type | DEVICE | PROC_NR | COUNT | POSITION | ADDRESS | -|_______________|___________|_________|_______|__________|_________| -| | | | | | | -| DEV_OPEN | minor dev | proc nr | mode | | | -|_______________|___________|_________|_______|__________|_________| -| | | | | | | -| DEV_CLOSE | minor dev | proc nr | | | | -|_______________|___________|_________|_______|__________|_________| -| | | | | | | -| DEV_IOCTL_S | minor dev | proc nr | | NWIO.. | address | -|_______________|___________|_________|_______|__________|_________| -| | | | | | | -| DEV_READ_S | minor dev | proc nr | count | | address | -|_______________|___________|_________|_______|__________|_________| -| | | | | | | -| DEV_WRITE_S | minor dev | proc nr | count | | address | -|_______________|___________|_________|_______|__________|_________| -| | | | | | | -| CANCEL | minor dev | proc nr | | | | -|_______________|___________|_________|_______|__________|_________| - -from DL_ETH: - (not documented here) */ #include "inet.h" @@ -90,11 +61,9 @@ static int sef_cb_init_fresh(int type, sef_init_info_t *info); int main(int argc, char *argv[]) { - mq_t *mq; + message mess; int ipc_status; int r; - endpoint_t source; - int m_type; /* SEF local startup. */ sef_local_startup(); @@ -124,59 +93,44 @@ int main(int argc, char *argv[]) clck_expire_timers(); continue; } - mq= mq_get(); - if (!mq) - ip_panic(("out of messages")); - r= sef_receive_status(ANY, &mq->mq_mess, &ipc_status); + r= sef_receive_status(ANY, &mess, &ipc_status); if (r<0) { ip_panic(("unable to receive: %d", r)); } reset_time(); - source= mq->mq_mess.m_source; - m_type= mq->mq_mess.m_type; - if (source == VFS_PROC_NR) + if (mess.m_source == VFS_PROC_NR) { - sr_rec(mq); + sr_rec(&mess, ipc_status); } else if (is_ipc_notify(ipc_status)) { - if (source == CLOCK) + if (mess.m_source == CLOCK) { - clck_tick(&mq->mq_mess); - mq_free(mq); + clck_tick(&mess); } - else if (source == PM_PROC_NR) - { - /* signaled */ - /* probably SIGTERM */ - mq_free(mq); - } - else if (source == DS_PROC_NR) + else if (mess.m_source == DS_PROC_NR) { /* DS notifies us of an event. */ ds_event(); - mq_free(mq); } else { printf("inet: got unexpected notify from %d\n", - mq->mq_mess.m_source); - mq_free(mq); + mess.m_source); } } - else if (m_type == DL_CONF_REPLY || m_type == DL_TASK_REPLY || - m_type == DL_STAT_REPLY) + else if (mess.m_type == DL_CONF_REPLY || + mess.m_type == DL_TASK_REPLY || + mess.m_type == DL_STAT_REPLY) { - eth_rec(&mq->mq_mess); - mq_free(mq); + eth_rec(&mess); } else { printf("inet: got bad message type 0x%x from %d\n", - mq->mq_mess.m_type, mq->mq_mess.m_source); - mq_free(mq); + mess.m_type, mess.m_source); } } ip_panic(("task is not allowed to terminate")); diff --git a/servers/inet/inet.h b/servers/inet/inet.h index 5999fa930..a078f4230 100644 --- a/servers/inet/inet.h +++ b/servers/inet/inet.h @@ -25,7 +25,7 @@ Copyright 1995 Philip Homburg #define _NORETURN /* Should be non empty for GCC */ -typedef int ioreq_t; +typedef unsigned long ioreq_t; #include #include diff --git a/servers/inet/mq.h b/servers/inet/mq.h index 203a683b1..73199f52a 100644 --- a/servers/inet/mq.h +++ b/servers/inet/mq.h @@ -9,9 +9,28 @@ Copyright 1995 Philip Homburg #ifndef INET__MQ_H #define INET__MQ_H +#include + +typedef struct sr_req { + enum { + SRR_READ, + SRR_WRITE, + SRR_IOCTL + } srr_type; + devminor_t srr_minor; + endpoint_t srr_endpt; + cp_grant_id_t srr_grant; + union { + size_t srr_size; /* for SRR_READ, SRR_WRITE */ + unsigned long srr_req; /* for SRR_IOCTL */ + }; + int srr_flags; + cdev_id_t srr_id; +} sr_req_t; + typedef struct mq { - message mq_mess; + sr_req_t mq_req; struct mq *mq_next; int mq_allocated; } mq_t; diff --git a/servers/inet/proto.h b/servers/inet/proto.h index 673d31e5c..394ddacf8 100644 --- a/servers/inet/proto.h +++ b/servers/inet/proto.h @@ -17,11 +17,7 @@ void eth_check_driver(char *label, endpoint_t endpoint); /* sr.c */ -struct mq; -void sr_rec(struct mq *m); - - - +void sr_rec(message *m, int ipc_status); /* * $PchId: proto.h,v 1.4 1995/11/21 06:36:37 philip Exp $ diff --git a/servers/inet/sr.c b/servers/inet/sr.c index a84792c45..fc94f43df 100644 --- a/servers/inet/sr.c +++ b/servers/inet/sr.c @@ -2,61 +2,10 @@ * system. * * Copyright 1995 Philip Homburg - * - * The valid messages and their parameters are: - * - * Requests: - * - * m_type DEVICE USER_ENDPT COUNT - * -------------------------------------------------- - * | DEV_OPEN | minor dev | proc nr | mode | - * |-------------+-----------+-----------+----------+ - * | DEV_CLOSE | minor dev | proc nr | | - * |-------------+-----------+-----------+----------+ - * - * m_type DEVICE USER_ENDPT COUNT IO_GRANT - * --------------------------------------------------------------- - * | DEV_READ_S | minor dev | proc nr | count | grant ID | - * |-------------+-----------+-----------+-----------+-----------| - * | DEV_WRITE_S | minor dev | proc nr | count | grant ID | - * |-------------+-----------+-----------+-----------+-----------| - * | DEV_IOCTL_S | minor dev | proc nr | command | grant ID | - * |-------------+-----------+-----------+-----------+-----------| - * | DEV_SELECT | minor dev | ops | | | - * |-------------+-----------+-----------+-----------+-----------| - * - * m_type - * --------------| - * | DEV_STATUS | - * |-------------| - * - * m_type DEVICE USER_ENDPT COUNT - * --------------------------------------------------| - * | CANCEL | minor dev | proc nr | mode | - * |-------------+-----------+-----------+-----------| - * - * Replies: - * - * m_type REP_ENDPT REP_STATUS REP_IO_GRANT - * -------------------------------------------------------| - * | TASK_REPLY | proc nr | status | grant ID | - * |---------------+-----------+-----------+--------------| - * - * m_type REP_ENDPT REP_STATUS REP_IO_GRANT - * ----------------+-----------+--------------------------| - * | DEV_REVIVE | proc nr | | grant ID | - * |---------------+-----------+-----------+--------------| - * | DEV_IO_READY | minor dev | sel ops | | - * |---------------+-----------+-----------+--------------| - * | DEV_NO_STATUS | | | | - * |---------------+-----------+-----------+--------------| */ #include "inet.h" -#include -#include - #include "mq.h" #include "qp.h" #include "proto.h" @@ -72,34 +21,46 @@ THIS_FILE sr_fd_t sr_fd_table[FD_NR]; -static mq_t *repl_queue, *repl_queue_tail; static struct vscp_vec s_cp_req[SCPVEC_NR]; -static int sr_open(message *m); -static void sr_close(message *m); -static int sr_rwio(mq_t *m); +static int sr_open(devminor_t minor, int access, endpoint_t user_endpt); +static int sr_close(devminor_t minor); +static ssize_t sr_read(devminor_t minor, u64_t position, endpoint_t endpt, + cp_grant_id_t grant, size_t size, int flags, cdev_id_t id); +static ssize_t sr_write(devminor_t minor, u64_t position, endpoint_t endpt, + cp_grant_id_t grant, size_t size, int flags, cdev_id_t id); +static int sr_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt, + cp_grant_id_t grant, int flags, endpoint_t user_endpt, cdev_id_t id); +static int sr_rwio(sr_req_t *req); static int sr_restart_read(sr_fd_t *fdp); static int sr_restart_write(sr_fd_t *fdp); static int sr_restart_ioctl(sr_fd_t *fdp); -static int sr_cancel(message *m); -static int sr_select(message *m); -static void sr_status(message *m); -static void sr_reply_(mq_t *m, int reply, int is_revive); +static int sr_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id); +static int sr_select(devminor_t minor, unsigned int ops, endpoint_t endpt); static sr_fd_t *sr_getchannel(int minor); static acc_t *sr_get_userdata(int fd, size_t offset, size_t count, int for_ioctl); static int sr_put_userdata(int fd, size_t offset, acc_t *data, int for_ioctl); static void sr_select_res(int fd, unsigned ops); -static int sr_repl_queue(int proc, int ref, int operation); -static int walk_queue(sr_fd_t *sr_fd, mq_t **q_head_ptr, mq_t - **q_tail_ptr, int type, int proc_nr, int ref, int first_flag); +static int walk_queue(sr_fd_t *sr_fd, mq_t **q_head_ptr, mq_t **q_tail_ptr, + int type, endpoint_t endpt, cdev_id_t id, int first_flag); static void sr_event(event_t *evp, ev_arg_t arg); static int cp_u2b(endpoint_t proc, cp_grant_id_t gid, vir_bytes offset, acc_t **var_acc_ptr, int size); static int cp_b2u(acc_t *acc_ptr, endpoint_t proc, cp_grant_id_t gid, vir_bytes offset); +static struct chardriver inet_tab = { + .cdr_open = sr_open, + .cdr_close = sr_close, + .cdr_read = sr_read, + .cdr_write = sr_write, + .cdr_ioctl = sr_ioctl, + .cdr_cancel = sr_cancel, + .cdr_select = sr_select +}; + void sr_init() { int i; @@ -111,83 +72,11 @@ void sr_init() ev_init(&sr_fd_table[i].srf_read_ev); ev_init(&sr_fd_table[i].srf_write_ev); } - repl_queue= NULL; } -void sr_rec(m) -mq_t *m; +void sr_rec(message *m, int ipc_status) { - int result; - int send_reply = 0, free_mess = 0; - - if (repl_queue) - { - if (m->mq_mess.m_type == CANCEL) - { - result= sr_repl_queue(m->mq_mess.USER_ENDPT, - (int)m->mq_mess.IO_GRANT, 0); - - if (result) - { - mq_free(m); - return; /* canceled request in queue */ - } - } -#if 0 - else - sr_repl_queue(ANY, 0, 0); -#endif - } - - switch (m->mq_mess.m_type) - { - case DEV_OPEN: - result= sr_open(&m->mq_mess); - send_reply= 1; - free_mess= 1; - break; - case DEV_CLOSE: - sr_close(&m->mq_mess); - result= OK; - send_reply= 1; - free_mess= 1; - break; - case DEV_READ_S: - case DEV_WRITE_S: - case DEV_IOCTL_S: - result= sr_rwio(m); - assert(result == OK || result == SUSPEND); - send_reply= (result == SUSPEND); - free_mess= 0; - break; - case CANCEL: - result= sr_cancel(&m->mq_mess); - assert(result == OK || result == EINTR); - send_reply= (result == EINTR); - free_mess= 1; - m->mq_mess.m_type= 0; - break; - case DEV_SELECT: - result= sr_select(&m->mq_mess); - send_reply= 1; - free_mess= 1; - break; - case DEV_STATUS: - sr_status(&m->mq_mess); - result= OK; /* Satisfy lint. */ - send_reply= 0; - free_mess= 1; - break; - default: - ip_panic(("unknown message, from %d, type %d", - m->mq_mess.m_source, m->mq_mess.m_type)); - } - if (send_reply) - { - sr_reply_(m, result, FALSE /* !is_revive */); - } - if (free_mess) - mq_free(m); + chardriver_process(&inet_tab, m, ipc_status); } void sr_add_minor(minor, port, openf, closef, readf, writef, @@ -221,12 +110,10 @@ sr_select_t selectf; sr_fd->srf_select= selectf; } -static int sr_open(m) -message *m; +static int sr_open(devminor_t minor, int UNUSED(access), + endpoint_t UNUSED(user_endpt)) { sr_fd_t *sr_fd; - - int minor= m->DEVICE; int i, fd; if (minor<0 || minor>FD_NR) @@ -259,15 +146,14 @@ message *m; return fd; } sr_fd->srf_fd= fd; - return i; + return CDEV_CLONED | i; } -static void sr_close(m) -message *m; +static int sr_close(devminor_t minor) { sr_fd_t *sr_fd; - sr_fd= sr_getchannel(m->DEVICE); + sr_fd= sr_getchannel(minor); assert (sr_fd); if (sr_fd->srf_flags & SFF_BUSY) @@ -276,38 +162,43 @@ message *m; assert (!(sr_fd->srf_flags & SFF_MINOR)); (*sr_fd->srf_close)(sr_fd->srf_fd); sr_fd->srf_flags= SFF_FREE; + + return OK; } -static int sr_rwio(m) -mq_t *m; +static int sr_rwio(sr_req_t *req) { sr_fd_t *sr_fd; - mq_t **q_head_ptr = NULL, **q_tail_ptr = NULL; + mq_t *m, **q_head_ptr = NULL, **q_tail_ptr = NULL; int ip_flag = 0, susp_flag = 0, first_flag = 0; int r = OK; ioreq_t request; size_t size; - sr_fd= sr_getchannel(m->mq_mess.DEVICE); + if (!(m = mq_get())) + ip_panic(("out of messages")); + m->mq_req = *req; + + sr_fd= sr_getchannel(m->mq_req.srr_minor); assert (sr_fd); - switch(m->mq_mess.m_type) + switch(m->mq_req.srr_type) { - case DEV_READ_S: + case SRR_READ: q_head_ptr= &sr_fd->srf_read_q; q_tail_ptr= &sr_fd->srf_read_q_tail; ip_flag= SFF_READ_IP; susp_flag= SFF_READ_SUSP; first_flag= SFF_READ_FIRST; break; - case DEV_WRITE_S: + case SRR_WRITE: q_head_ptr= &sr_fd->srf_write_q; q_tail_ptr= &sr_fd->srf_write_q_tail; ip_flag= SFF_WRITE_IP; susp_flag= SFF_WRITE_SUSP; first_flag= SFF_WRITE_FIRST; break; - case DEV_IOCTL_S: + case SRR_IOCTL: q_head_ptr= &sr_fd->srf_ioctl_q; q_tail_ptr= &sr_fd->srf_ioctl_q_tail; ip_flag= SFF_IOCTL_IP; @@ -315,7 +206,7 @@ mq_t *m; first_flag= SFF_IOCTL_FIRST; break; default: - ip_panic(("illegal case entry")); + ip_panic(("illegal request type")); } if (sr_fd->srf_flags & ip_flag) @@ -323,9 +214,14 @@ mq_t *m; assert(sr_fd->srf_flags & susp_flag); assert(*q_head_ptr); + if (m->mq_req.srr_flags & CDEV_NONBLOCK) { + mq_free(m); + return EAGAIN; + } + (*q_tail_ptr)->mq_next= m; *q_tail_ptr= m; - return SUSPEND; + return EDONTREPLY; } assert(!*q_head_ptr); @@ -334,18 +230,16 @@ mq_t *m; assert(!(sr_fd->srf_flags & first_flag)); sr_fd->srf_flags |= first_flag; - switch(m->mq_mess.m_type) + switch(m->mq_req.srr_type) { - case DEV_READ_S: - r= (*sr_fd->srf_read)(sr_fd->srf_fd, - m->mq_mess.COUNT); + case SRR_READ: + r= (*sr_fd->srf_read)(sr_fd->srf_fd, m->mq_req.srr_size); break; - case DEV_WRITE_S: - r= (*sr_fd->srf_write)(sr_fd->srf_fd, - m->mq_mess.COUNT); + case SRR_WRITE: + r= (*sr_fd->srf_write)(sr_fd->srf_fd, m->mq_req.srr_size); break; - case DEV_IOCTL_S: - request= m->mq_mess.REQUEST; + case SRR_IOCTL: + request= m->mq_req.srr_req; size= (request >> 16) & _IOCPARM_MASK; if (size>MAX_IOCTL_S) { @@ -355,7 +249,7 @@ mq_t *m; assert(r == OK); assert(sr_fd->srf_flags & first_flag); sr_fd->srf_flags &= ~first_flag; - return OK; + return EDONTREPLY; } r= (*sr_fd->srf_ioctl)(sr_fd->srf_fd, request); break; @@ -368,11 +262,67 @@ mq_t *m; assert(r == OK || r == SUSPEND || (printf("r= %d\n", r), 0)); - if (r == SUSPEND) + if (r == SUSPEND) { sr_fd->srf_flags |= susp_flag; - else + if (m->mq_req.srr_flags & CDEV_NONBLOCK) { + r= sr_cancel(m->mq_req.srr_minor, m->mq_req.srr_endpt, + m->mq_req.srr_id); + assert(r == EDONTREPLY); /* head of the queue */ + } + } else mq_free(m); - return r; + return EDONTREPLY; /* request already completed */ +} + +static ssize_t sr_read(devminor_t minor, u64_t UNUSED(position), + endpoint_t endpt, cp_grant_id_t grant, size_t size, int flags, + cdev_id_t id) +{ + sr_req_t req; + + req.srr_type = SRR_READ; + req.srr_minor = minor; + req.srr_endpt = endpt; + req.srr_grant = grant; + req.srr_size = size; + req.srr_flags = flags; + req.srr_id = id; + + return sr_rwio(&req); +} + +static ssize_t sr_write(devminor_t minor, u64_t UNUSED(position), + endpoint_t endpt, cp_grant_id_t grant, size_t size, int flags, + cdev_id_t id) +{ + sr_req_t req; + + req.srr_type = SRR_WRITE; + req.srr_minor = minor; + req.srr_endpt = endpt; + req.srr_grant = grant; + req.srr_size = size; + req.srr_flags = flags; + req.srr_id = id; + + return sr_rwio(&req); +} + +static int sr_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt, + cp_grant_id_t grant, int flags, endpoint_t UNUSED(user_endpt), + cdev_id_t id) +{ + sr_req_t req; + + req.srr_type = SRR_IOCTL; + req.srr_minor = minor; + req.srr_req = request; + req.srr_endpt = endpt; + req.srr_grant = grant; + req.srr_flags = flags; + req.srr_id = id; + + return sr_rwio(&req); } static int sr_restart_read(sr_fd) @@ -391,8 +341,7 @@ sr_fd_t *sr_fd; } sr_fd->srf_flags |= SFF_READ_IP; - r= (*sr_fd->srf_read)(sr_fd->srf_fd, - mp->mq_mess.COUNT); + r= (*sr_fd->srf_read)(sr_fd->srf_fd, mp->mq_req.srr_size); assert(r == OK || r == SUSPEND || (printf("r= %d\n", r), 0)); @@ -417,8 +366,7 @@ sr_fd_t *sr_fd; } sr_fd->srf_flags |= SFF_WRITE_IP; - r= (*sr_fd->srf_write)(sr_fd->srf_fd, - mp->mq_mess.COUNT); + r= (*sr_fd->srf_write)(sr_fd->srf_fd, mp->mq_req.srr_size); assert(r == OK || r == SUSPEND || (printf("r= %d\n", r), 0)); @@ -443,8 +391,7 @@ sr_fd_t *sr_fd; } sr_fd->srf_flags |= SFF_IOCTL_IP; - r= (*sr_fd->srf_ioctl)(sr_fd->srf_fd, - mp->mq_mess.COUNT); + r= (*sr_fd->srf_ioctl)(sr_fd->srf_fd, mp->mq_req.srr_req); assert(r == OK || r == SUSPEND || (printf("r= %d\n", r), 0)); @@ -453,142 +400,74 @@ sr_fd_t *sr_fd; return r; } -static int sr_cancel(m) -message *m; +static int sr_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id) { sr_fd_t *sr_fd; int result; - int proc_nr, ref; - result=EINTR; - proc_nr= m->USER_ENDPT; - ref= (int)m->IO_GRANT; - sr_fd= sr_getchannel(m->DEVICE); + sr_fd= sr_getchannel(minor); assert (sr_fd); result= walk_queue(sr_fd, &sr_fd->srf_ioctl_q, &sr_fd->srf_ioctl_q_tail, SR_CANCEL_IOCTL, - proc_nr, ref, SFF_IOCTL_FIRST); + endpt, id, SFF_IOCTL_FIRST); if (result != EAGAIN) - return result; + return (result == OK) ? EDONTREPLY : EINTR; result= walk_queue(sr_fd, &sr_fd->srf_read_q, &sr_fd->srf_read_q_tail, SR_CANCEL_READ, - proc_nr, ref, SFF_READ_FIRST); + endpt, id, SFF_READ_FIRST); if (result != EAGAIN) - return result; + return (result == OK) ? EDONTREPLY : EINTR; result= walk_queue(sr_fd, &sr_fd->srf_write_q, &sr_fd->srf_write_q_tail, SR_CANCEL_WRITE, - proc_nr, ref, SFF_WRITE_FIRST); + endpt, id, SFF_WRITE_FIRST); if (result != EAGAIN) - return result; + return (result == OK) ? EDONTREPLY : EINTR; - ip_panic(( -"request not found: from %d, type %d, MINOR= %d, PROC= %d, REF= %d", - m->m_source, m->m_type, m->DEVICE, - m->USER_ENDPT, (int) m->IO_GRANT)); - - return result; + /* We already replied to the request, so don't reply to the CANCEL. */ + return EDONTREPLY; } -static int sr_select(m) -message *m; +static int sr_select(devminor_t minor, unsigned int ops, endpoint_t endpt) { sr_fd_t *sr_fd; - int r; - unsigned m_ops, i_ops; + int r, m_ops; + unsigned int i_ops; - sr_fd= sr_getchannel(m->DEVICE); + sr_fd= sr_getchannel(minor); assert (sr_fd); - sr_fd->srf_select_proc= m->m_source; + sr_fd->srf_select_proc= endpt; - m_ops= m->USER_ENDPT; i_ops= 0; - if (m_ops & SEL_RD) i_ops |= SR_SELECT_READ; - if (m_ops & SEL_WR) i_ops |= SR_SELECT_WRITE; - if (m_ops & SEL_ERR) i_ops |= SR_SELECT_EXCEPTION; - if (!(m_ops & SEL_NOTIFY)) i_ops |= SR_SELECT_POLL; + if (ops & CDEV_OP_RD) i_ops |= SR_SELECT_READ; + if (ops & CDEV_OP_WR) i_ops |= SR_SELECT_WRITE; + if (ops & CDEV_OP_ERR) i_ops |= SR_SELECT_EXCEPTION; + if (!(ops & CDEV_NOTIFY)) i_ops |= SR_SELECT_POLL; r= (*sr_fd->srf_select)(sr_fd->srf_fd, i_ops); - if (r < 0) - return r; - m_ops= 0; - if (r & SR_SELECT_READ) m_ops |= SEL_RD; - if (r & SR_SELECT_WRITE) m_ops |= SEL_WR; - if (r & SR_SELECT_EXCEPTION) m_ops |= SEL_ERR; + if (r < 0) { + m_ops= r; + } else { + m_ops= 0; + if (r & SR_SELECT_READ) m_ops |= CDEV_OP_RD; + if (r & SR_SELECT_WRITE) m_ops |= CDEV_OP_WR; + if (r & SR_SELECT_EXCEPTION) m_ops |= CDEV_OP_ERR; + } return m_ops; } -static void sr_status(m) -message *m; -{ - int fd, result; - unsigned m_ops; - sr_fd_t *sr_fd; - mq_t *mq; - - mq= repl_queue; - if (mq != NULL) - { - repl_queue= mq->mq_next; - - mq->mq_mess.m_type= DEV_REVIVE; - result= send(mq->mq_mess.m_source, &mq->mq_mess); - if (result != OK) - ip_panic(("unable to send")); - mq_free(mq); - - return; - } - - for (fd=0, sr_fd= sr_fd_table; fdsrf_flags & - (SFF_SELECT_R|SFF_SELECT_W|SFF_SELECT_X)) == 0) - { - /* Nothing to report */ - continue; - } - if (sr_fd->srf_select_proc != m->m_source) - { - /* Wrong process */ - continue; - } - - m_ops= 0; - if (sr_fd->srf_flags & SFF_SELECT_R) m_ops |= SEL_RD; - if (sr_fd->srf_flags & SFF_SELECT_W) m_ops |= SEL_WR; - if (sr_fd->srf_flags & SFF_SELECT_X) m_ops |= SEL_ERR; - - sr_fd->srf_flags &= ~(SFF_SELECT_R|SFF_SELECT_W|SFF_SELECT_X); - - m->m_type= DEV_IO_READY; - m->DEV_MINOR= fd; - m->DEV_SEL_OPS= m_ops; - - result= send(m->m_source, m); - if (result != OK) - ip_panic(("unable to send")); - return; - } - - m->m_type= DEV_NO_STATUS; - result= send(m->m_source, m); - if (result != OK) - ip_panic(("unable to send")); -} - -static int walk_queue(sr_fd, q_head_ptr, q_tail_ptr, type, proc_nr, ref, +static int walk_queue(sr_fd, q_head_ptr, q_tail_ptr, type, endpt, id, first_flag) sr_fd_t *sr_fd; mq_t **q_head_ptr; mq_t **q_tail_ptr; int type; -int proc_nr; -int ref; +endpoint_t endpt; +cdev_id_t id; int first_flag; { mq_t *q_ptr_prv, *q_ptr; @@ -597,15 +476,16 @@ int first_flag; for(q_ptr_prv= NULL, q_ptr= *q_head_ptr; q_ptr; q_ptr_prv= q_ptr, q_ptr= q_ptr->mq_next) { - if (q_ptr->mq_mess.USER_ENDPT != proc_nr) + if (q_ptr->mq_req.srr_endpt != endpt) continue; - if ((int)q_ptr->mq_mess.IO_GRANT != ref) + if (q_ptr->mq_req.srr_id != id) continue; if (!q_ptr_prv) { assert(!(sr_fd->srf_flags & first_flag)); sr_fd->srf_flags |= first_flag; + /* This will also send a reply. */ result= (*sr_fd->srf_cancel)(sr_fd->srf_fd, type); assert(result == OK); @@ -642,52 +522,6 @@ int minor; return loc_fd; } -static void sr_reply_(mq, status, is_revive) -mq_t *mq; -int status; -int is_revive; -{ - int result, proc, ref; - message reply, *mp; - - proc= mq->mq_mess.USER_ENDPT; - ref= (int)mq->mq_mess.IO_GRANT; - - if (is_revive) - mp= &mq->mq_mess; - else - mp= &reply; - - mp->m_type= TASK_REPLY; - mp->REP_ENDPT= proc; - mp->REP_STATUS= status; - mp->REP_IO_GRANT= ref; - if (is_revive) - { - notify(mq->mq_mess.m_source); - result= ELOCKED; - } - else - { - result= send(mq->mq_mess.m_source, mp); - } - - if (result == ELOCKED && is_revive) - { - mq->mq_next= NULL; - if (repl_queue) - repl_queue_tail->mq_next= mq; - else - repl_queue= mq; - repl_queue_tail= mq; - return; - } - if (result != OK) - ip_panic(("unable to send")); - if (is_revive) - mq_free(mq); -} - static acc_t *sr_get_userdata (fd, offset, count, for_ioctl) int fd; size_t offset; @@ -730,7 +564,10 @@ int for_ioctl; *head_ptr= mq; result= (int)offset; is_revive= !(loc_fd->srf_flags & first_flag); - sr_reply_(m, result, is_revive); + chardriver_reply_task(m->mq_req.srr_endpt, m->mq_req.srr_id, + result); + if (is_revive) + mq_free(m); suspended= (loc_fd->srf_flags & susp_flag); loc_fd->srf_flags &= ~(ip_flag|susp_flag); if (suspended) @@ -744,8 +581,8 @@ int for_ioctl; return NULL; } - result= cp_u2b ((*head_ptr)->mq_mess.m_source, - (int)(*head_ptr)->mq_mess.IO_GRANT, offset, &acc, count); + result= cp_u2b ((*head_ptr)->mq_req.srr_endpt, + (*head_ptr)->mq_req.srr_grant, offset, &acc, count); return result<0 ? NULL : acc; } @@ -791,7 +628,10 @@ int for_ioctl; *head_ptr= mq; result= (int)offset; is_revive= !(loc_fd->srf_flags & first_flag); - sr_reply_(m, result, is_revive); + chardriver_reply_task(m->mq_req.srr_endpt, m->mq_req.srr_id, + result); + if (is_revive) + mq_free(m); suspended= (loc_fd->srf_flags & susp_flag); loc_fd->srf_flags &= ~(ip_flag|susp_flag); if (suspended) @@ -805,21 +645,23 @@ int for_ioctl; return OK; } - return cp_b2u (data, (*head_ptr)->mq_mess.m_source, - (int)(*head_ptr)->mq_mess.IO_GRANT, offset); + return cp_b2u (data, (*head_ptr)->mq_req.srr_endpt, + (*head_ptr)->mq_req.srr_grant, offset); } static void sr_select_res(int fd, unsigned ops) { sr_fd_t *sr_fd; + unsigned int m_ops; sr_fd= &sr_fd_table[fd]; - - if (ops & SR_SELECT_READ) sr_fd->srf_flags |= SFF_SELECT_R; - if (ops & SR_SELECT_WRITE) sr_fd->srf_flags |= SFF_SELECT_W; - if (ops & SR_SELECT_EXCEPTION) sr_fd->srf_flags |= SFF_SELECT_X; - notify(sr_fd->srf_select_proc); + m_ops= 0; + if (ops & SR_SELECT_READ) m_ops |= CDEV_OP_RD; + if (ops & SR_SELECT_WRITE) m_ops |= CDEV_OP_WR; + if (ops & SR_SELECT_EXCEPTION) m_ops |= CDEV_OP_ERR; + + chardriver_reply_select(sr_fd->srf_select_proc, fd, m_ops); } static void sr_event(evp, arg) @@ -989,45 +831,6 @@ vir_bytes offset; return OK; } -static int sr_repl_queue(proc, ref, operation) -int proc; -int ref; -int operation; -{ - mq_t *m, *m_cancel, *m_tmp; - mq_t *new_queue; - int result; - - m_cancel= NULL; - new_queue= NULL; - - for (m= repl_queue; m;) - { - if (m->mq_mess.REP_ENDPT == proc && - m->mq_mess.REP_IO_GRANT == ref) - { - assert(!m_cancel); - m_cancel= m; - m= m->mq_next; - continue; - } - m_tmp= m; - m= m->mq_next; - m_tmp->mq_next= new_queue; - new_queue= m_tmp; - } - repl_queue= new_queue; - if (m_cancel) - { - result= send(m_cancel->mq_mess.m_source, &m_cancel->mq_mess); - if (result != OK) - ip_panic(("unable to send: %d", result)); - mq_free(m_cancel); - return 1; - } - return 0; -} - /* * $PchId: sr.c,v 1.17 2005/06/28 14:26:16 philip Exp $ */ diff --git a/servers/inet/sr_int.h b/servers/inet/sr_int.h index 0a5494ecd..4699c9da4 100644 --- a/servers/inet/sr_int.h +++ b/servers/inet/sr_int.h @@ -43,9 +43,6 @@ typedef struct sr_fd #define SFF_IOCTL_FIRST 0x200 #define SFF_READ_FIRST 0x400 #define SFF_WRITE_FIRST 0x800 -#define SFF_SELECT_R 0x1000 -#define SFF_SELECT_W 0x2000 -#define SFF_SELECT_X 0x4000 EXTERN sr_fd_t sr_fd_table[FD_NR]; diff --git a/servers/is/dmp_fs.c b/servers/is/dmp_fs.c index ee486c99d..1230235cd 100644 --- a/servers/is/dmp_fs.c +++ b/servers/is/dmp_fs.c @@ -74,11 +74,8 @@ static char * dmap_style(int dev_style) { switch(dev_style) { case STYLE_DEV: return "STYLE_DEV"; - case STYLE_DEVA: return "STYLE_DEVA"; case STYLE_TTY: return "STYLE_TTY"; case STYLE_CTTY: return "STYLE_CTTY"; - case STYLE_CLONE: return "STYLE_CLONE"; - case STYLE_CLONE_A: return "STYLE_CLONE_A"; default: return "UNKNOWN"; } } diff --git a/servers/is/dmp_kernel.c b/servers/is/dmp_kernel.c index ff9d53b6c..2919d5d60 100644 --- a/servers/is/dmp_kernel.c +++ b/servers/is/dmp_kernel.c @@ -370,7 +370,7 @@ void procstack_dmp() PROCLOOP(rp, oldrp) PRINTRTS(rp); printf("\n"); pagelines++; - sys_sysctl_stacktrace(rp->p_endpoint); + sys_diagctl_stacktrace(rp->p_endpoint); } } diff --git a/servers/iso9660fs/mount.c b/servers/iso9660fs/mount.c index aa23ebd6a..0fe8290cd 100644 --- a/servers/iso9660fs/mount.c +++ b/servers/iso9660fs/mount.c @@ -32,7 +32,7 @@ int fs_readsuper() { bdev_driver(fs_dev, fs_dev_label); /* Open the device the file system lives on in read only mode */ - if (bdev_open(fs_dev, R_BIT) != OK) { + if (bdev_open(fs_dev, BDEV_R_BIT) != OK) { return(EINVAL); } diff --git a/servers/iso9660fs/proto.h b/servers/iso9660fs/proto.h index f99d57093..082ab9028 100644 --- a/servers/iso9660fs/proto.h +++ b/servers/iso9660fs/proto.h @@ -54,7 +54,6 @@ int read_chunk(struct dir_record *rip, u64_t position, unsigned off, int /* stadir.c */ int fs_stat(void); -int fs_fstatfs(void); int fs_statvfs(void); /* super.c */ diff --git a/servers/iso9660fs/stadir.c b/servers/iso9660fs/stadir.c index 9e41e3659..e6e3fcfaf 100644 --- a/servers/iso9660fs/stadir.c +++ b/servers/iso9660fs/stadir.c @@ -1,7 +1,6 @@ #include "inc.h" #include #include -#include #include #include #include @@ -93,24 +92,6 @@ int fs_stat() } -/*===========================================================================* - * fs_fstatfs * - *===========================================================================*/ -int fs_fstatfs() -{ - struct statfs st; - int r; - - st.f_bsize = v_pri.logical_block_size_l; - - /* Copy the struct to user space. */ - r = sys_safecopyto(fs_m_in.m_source, fs_m_in.REQ_GRANT, 0, - (vir_bytes) &st, (phys_bytes) sizeof(st)); - - return(r); -} - - /*===========================================================================* * fs_statvfs * *===========================================================================*/ @@ -119,17 +100,12 @@ int fs_statvfs() struct statvfs st; int r; + memset(&st, 0, sizeof(st)); st.f_bsize = v_pri.logical_block_size_l; st.f_frsize = st.f_bsize; + st.f_iosize = st.f_bsize; st.f_blocks = v_pri.volume_space_size_l; - st.f_bfree = 0; - st.f_bavail = 0; - st.f_files = 0; - st.f_ffree = 0; - st.f_favail = 0; - st.f_fsid = fs_dev; - st.f_flag = ST_RDONLY; st.f_namemax = NAME_MAX; /* Copy the struct to user space. */ diff --git a/servers/iso9660fs/table.c b/servers/iso9660fs/table.c index 12ac2f79a..6f9297c51 100644 --- a/servers/iso9660fs/table.c +++ b/servers/iso9660fs/table.c @@ -18,7 +18,7 @@ int (*fs_call_vec[])(void) = { do_noop, /* 7 */ fs_stat, /* 8 */ no_sys, /* 9: not used */ - fs_fstatfs, /* 10 */ + fs_statvfs, /* 10 */ fs_bread, /* 11 */ no_sys, /* 12: not used */ no_sys, /* 13: not used */ @@ -40,12 +40,11 @@ int (*fs_call_vec[])(void) = { no_sys, /* 29: not used */ no_sys, /* 30: not used */ fs_getdents, /* 31 */ - fs_statvfs, /* 32 */ #if 0 - fs_read, /* 33 */ - no_sys, + fs_read, /* 32 */ + no_sys, /* 33 */ #else - no_sys, - no_sys, + no_sys, /* 32 */ + no_sys, /* 33 */ #endif }; diff --git a/servers/lwip/driver.c b/servers/lwip/driver.c index 6bd3f1a76..2bf1baafc 100644 --- a/servers/lwip/driver.c +++ b/servers/lwip/driver.c @@ -258,11 +258,11 @@ __unused static void print_pkt(unsigned char * pkt, int len) printf("--- PKT END ---\n"); } -static int raw_receive(message * m, +static int raw_receive(struct sock_req *req, struct pbuf *pbuf) { struct pbuf * p; - unsigned int rem_len = m->COUNT; + unsigned int rem_len = req->size; unsigned int written = 0; int err; @@ -272,10 +272,8 @@ static int raw_receive(message * m, size_t cp_len; cp_len = (rem_len < p->len) ? rem_len : p->len; - err = copy_to_user(m->m_source, p->payload, cp_len, - (cp_grant_id_t) m->IO_GRANT, - written); - + err = copy_to_user(req->endpt, p->payload, cp_len, + req->grant, written); if (err != OK) return err; @@ -300,16 +298,13 @@ int raw_socket_input(struct pbuf * pbuf, struct nic * nic) if (sock->flags & SOCK_FLG_OP_PENDING) { int ret; /* we are resuming a suspended operation */ - ret = raw_receive(&sock->mess, pbuf); + ret = raw_receive(&sock->req, pbuf); - if (ret > 0) { - sock_reply(sock, ret); - sock->flags &= ~SOCK_FLG_OP_PENDING; + send_req_reply(&sock->req, ret); + sock->flags &= ~SOCK_FLG_OP_PENDING; + + if (ret > 0) return 0; - } else { - sock_reply(sock, ret); - sock->flags &= ~SOCK_FLG_OP_PENDING; - } } /* Do not enqueue more data than allowed */ @@ -453,11 +448,11 @@ static void raw_recv_free(__unused void * data) pbuf_free((struct pbuf *) data); } -static void nic_op_close(struct socket * sock, __unused message * m) +static int nic_op_close(struct socket * sock) { struct nic * nic = (struct nic *)sock->data; - debug_drv_print("socket %d", get_sock_num(sock)); + debug_drv_print("socket %ld", get_sock_num(sock)); sock_dequeue_data_all(sock, raw_recv_free); sock->ops = NULL; @@ -467,20 +462,20 @@ static void nic_op_close(struct socket * sock, __unused message * m) debug_drv_print("no active raw sock at %s", nic->name); } - sock_reply_close(sock, OK); + return OK; } -static void nic_ioctl_set_conf(__unused struct socket * sock, +static int nic_ioctl_set_conf(__unused struct socket * sock, struct nic * nic, - message * m) + endpoint_t endpt, + cp_grant_id_t grant) { nwio_ipconf_t ipconf; int err; - err = copy_from_user(m->m_source, &ipconf, sizeof(ipconf), - (cp_grant_id_t) m->IO_GRANT, 0); + err = copy_from_user(endpt, &ipconf, sizeof(ipconf), grant, 0); if (err != OK) - send_reply(m, err); + return err; if (ipconf.nwic_flags & NWIC_IPADDR_SET) netif_set_ipaddr(&nic->netif, @@ -492,51 +487,47 @@ static void nic_ioctl_set_conf(__unused struct socket * sock, if (nic->flags & NWEO_EN_BROAD) nic->netif.flags |= NETIF_FLAG_BROADCAST; - send_reply(m, OK); + + return OK; } -static void nic_ioctl_get_conf(__unused struct socket * sock, +static int nic_ioctl_get_conf(__unused struct socket * sock, struct nic * nic, - message * m) + endpoint_t endpt, + cp_grant_id_t grant) { nwio_ipconf_t ipconf; - int err; ipconf.nwic_flags = nic->flags; ipconf.nwic_ipaddr = nic->netif.ip_addr.addr; ipconf.nwic_netmask = nic->netif.netmask.addr; ipconf.nwic_mtu = nic->netif.mtu; - err = copy_to_user(m->m_source, &ipconf, sizeof(ipconf), - (cp_grant_id_t) m->IO_GRANT, 0); - if (err != OK) - send_reply(m, err); - - send_reply(m, OK); + return copy_to_user(endpt, &ipconf, sizeof(ipconf), grant, 0); } -static void nic_ioctl_set_gateway(__unused struct socket * sock, +static int nic_ioctl_set_gateway(__unused struct socket * sock, struct nic * nic, - message * m) + endpoint_t endpt, + cp_grant_id_t grant) { nwio_route_t route; int err; - err = copy_from_user(m->m_source, &route, sizeof(route), - (cp_grant_id_t) m->IO_GRANT, 0); + err = copy_from_user(endpt, &route, sizeof(route), grant, 0); if (err != OK) - send_reply(m, err); + return err; netif_set_gw(&nic->netif, (ip_addr_t *)&route.nwr_gateway); - - send_reply(m, OK); + + return OK; } -static void nic_ioctl_get_ethstat(__unused struct socket * sock, +static int nic_ioctl_get_ethstat(__unused struct socket * sock, struct nic * nic, - message * m) + endpoint_t endpt, + cp_grant_id_t grant) { - int err; nwio_ethstat_t ethstat; debug_drv_print("device /dev/%s", nic->name); @@ -548,34 +539,27 @@ static void nic_ioctl_get_ethstat(__unused struct socket * sock, !(nic->netif.flags & (NETIF_FLAG_ETHERNET | NETIF_FLAG_ETHARP))) { printf("LWIP no such device FUCK\n"); - send_reply(m, ENODEV); - return; + return ENODEV; } memset(ðstat, 0, sizeof(ethstat)); memcpy(ðstat.nwes_addr, nic->netif.hwaddr, 6); - err = copy_to_user(m->m_source, ðstat, sizeof(ethstat), - (cp_grant_id_t) m->IO_GRANT, 0); - if (err != OK) - send_reply(m, err); - - send_reply(m, OK); + return copy_to_user(endpt, ðstat, sizeof(ethstat), grant, 0); } -static void nic_ioctl_set_ethopt(struct socket * sock, +static int nic_ioctl_set_ethopt(struct socket * sock, struct nic * nic, - message * m) + endpoint_t endpt, + cp_grant_id_t grant) { int err; nwio_ethopt_t ethopt; assert(nic); - if (!sock) { - send_reply(m, EINVAL); - return; - } + if (!sock) + return EINVAL; debug_drv_print("device /dev/%s", nic->name); /* @@ -585,83 +569,83 @@ static void nic_ioctl_set_ethopt(struct socket * sock, if (!nic->netif.flags & NETIF_FLAG_UP || !(nic->netif.flags & (NETIF_FLAG_ETHERNET | NETIF_FLAG_ETHARP))) { - send_reply(m, ENODEV); - return; + return ENODEV; } - err = copy_from_user(m->m_source, ðopt, sizeof(ethopt), - (cp_grant_id_t) m->IO_GRANT, 0); + err = copy_from_user(endpt, ðopt, sizeof(ethopt), grant, 0); if (err != OK) - send_reply(m, err); + return err; /* we want to get data from this sock */ if (ethopt.nweo_flags & NWEO_COPY) { - if (nic->raw_socket) { - send_reply(m, EBUSY); - return; - } + if (nic->raw_socket) + return EBUSY; nic->raw_socket = sock; - debug_drv_print("active raw sock %d at %s", + debug_drv_print("active raw sock %ld at %s", get_sock_num(sock), nic->name); } - send_reply(m, OK); + return OK; } -static void nic_do_ioctl(struct socket * sock, struct nic * nic, message * m) +static int nic_do_ioctl(struct socket * sock, struct nic * nic, + struct sock_req * req) { - debug_print("device /dev/%s req %c %d %d", - nic->name, - (m->REQUEST >> 8) & 0xff, - m->REQUEST & 0xff, - (m->REQUEST >> 16) & _IOCPARM_MASK); - - debug_drv_print("socket %d", sock ? get_sock_num(sock) : -1); + int r; - switch (m->REQUEST) { + debug_print("device /dev/%s req %c %ld %ld", + nic->name, + (unsigned char) (req->req >> 8), + req->req & 0xff, + (req->req >> 16) & _IOCPARM_MASK); + + debug_drv_print("socket %ld", sock ? get_sock_num(sock) : -1); + + switch (req->req) { case NWIOSIPCONF: - nic_ioctl_set_conf(sock, nic, m); + r = nic_ioctl_set_conf(sock, nic, req->endpt, req->grant); break; case NWIOGIPCONF: - nic_ioctl_get_conf(sock, nic, m); + r = nic_ioctl_get_conf(sock, nic, req->endpt, req->grant); break; case NWIOSIPOROUTE: - nic_ioctl_set_gateway(sock, nic, m); + r = nic_ioctl_set_gateway(sock, nic, req->endpt, req->grant); break; case NWIOGETHSTAT: - nic_ioctl_get_ethstat(sock, nic, m); + r = nic_ioctl_get_ethstat(sock, nic, req->endpt, req->grant); break; case NWIOSETHOPT: - nic_ioctl_set_ethopt(sock, nic, m); + r = nic_ioctl_set_ethopt(sock, nic, req->endpt, req->grant); break; default: - send_reply(m, EBADIOCTL); - return; + r = ENOTTY; } + + return r; } -void nic_default_ioctl(message *m) +int nic_default_ioctl(struct sock_req *req) { struct nic * nic = lookup_nic_default(); if (nic == NULL) { debug_print("No default nic, reporting error"); - send_reply(m, EBADIOCTL); - return; + return ENOTTY; } - nic_do_ioctl(NULL, nic, m); + return nic_do_ioctl(NULL, nic, req); } -static void nic_op_ioctl(struct socket * sock, message * m, __unused int blk) +static int nic_op_ioctl(struct socket * sock, struct sock_req * req, + __unused int blk) { - nic_do_ioctl(sock, (struct nic *)sock->data, m); + return nic_do_ioctl(sock, (struct nic *)sock->data, req); } -static void nic_op_read(struct socket * sock, message * m, int blk) +static int nic_op_read(struct socket * sock, struct sock_req * req, int blk) { - debug_drv_print("sock num %d", get_sock_num(sock)); + debug_drv_print("sock num %ld", get_sock_num(sock)); if (sock->recv_head) { /* data available receive immeditely */ @@ -671,59 +655,56 @@ static void nic_op_read(struct socket * sock, message * m, int blk) pbuf = sock->recv_head->data; - ret = raw_receive(m, pbuf); + ret = raw_receive(req, pbuf); if (ret > 0) { sock_dequeue_data(sock); sock->recv_data_size -= pbuf->tot_len; pbuf_free(pbuf); } - sock_reply(sock, ret); + return ret; } else if (!blk) - send_reply(m, EAGAIN); + return EAGAIN; else { - /* store the message so we know how to reply */ - sock->mess = *m; + /* store the request so we know how to reply */ + sock->req = *req; /* operation is being processes */ sock->flags |= SOCK_FLG_OP_PENDING; debug_print("no data to read, suspending"); + return EDONTREPLY; } } -static void nic_op_write(struct socket * sock, message * m, __unused int blk) +static int nic_op_write(struct socket * sock, struct sock_req * req, + __unused int blk) { int ret; struct pbuf * pbuf; struct nic * nic = (struct nic *)sock->data; assert(nic); - debug_print("device %s data size %d", nic->name, - get_sock_num(sock), m->COUNT); + debug_print("device %s data size %u", nic->name, req->size); - pbuf = pbuf_alloc(PBUF_RAW, m->COUNT, PBUF_RAM); - if (!pbuf) { - ret = ENOMEM; - goto write_err; - } + pbuf = pbuf_alloc(PBUF_RAW, req->size, PBUF_RAM); + if (!pbuf) + return ENOMEM; - if ((ret = copy_from_user(m->m_source, pbuf->payload, m->COUNT, - (cp_grant_id_t) m->IO_GRANT, 0)) != OK) { + if ((ret = copy_from_user(req->endpt, pbuf->payload, req->size, + req->grant, 0)) != OK) { pbuf_free(pbuf); - goto write_err; + return ret; } if ((ret = nic->netif.linkoutput(&nic->netif, pbuf) != ERR_OK)) { debug_print("raw linkoutput failed %d", ret); ret = EIO; } else - ret = m->COUNT; - + ret = req->size; pbuf_free(pbuf); - -write_err: - sock_reply(sock, ret); + + return ret; } static struct sock_ops nic_ops = { @@ -735,34 +716,28 @@ static struct sock_ops nic_ops = { .select_reply = generic_op_select_reply }; -void nic_open(message *m) +int nic_open(devminor_t minor) { struct socket * sock; - debug_print("device %d", m->DEVICE); + debug_print("device %d", minor); - if (m->DEVICE > MAX_DEVS || devices[m->DEVICE].drv_ep == NONE) { - send_reply_open(m, ENODEV); - return; - } + if (minor > MAX_DEVS || devices[minor].drv_ep == NONE) + return ENODEV; sock = get_unused_sock(); - if (sock == NULL) { - send_reply(m, ENODEV); - return; - } - if (sock->ops != NULL) { - send_reply(m, EBUSY); - return; - } + if (sock == NULL) + return ENODEV; + if (sock->ops != NULL) + return EBUSY; sock->ops = &nic_ops; sock->select_ep = NONE; sock->recv_data_size = 0; - sock->data = &devices[m->DEVICE]; + sock->data = &devices[minor]; - send_reply_open(m, get_sock_num(sock)); + return get_sock_num(sock); } static int driver_pkt_enqueue(struct packet_q ** head, diff --git a/servers/lwip/eth.c b/servers/lwip/eth.c index 9e15bbfb8..74890e5e6 100644 --- a/servers/lwip/eth.c +++ b/servers/lwip/eth.c @@ -44,6 +44,7 @@ */ #include +#include #include "lwip/opt.h" diff --git a/servers/lwip/inet_config.c b/servers/lwip/inet_config.c index b57a70056..d4ec68f10 100644 --- a/servers/lwip/inet_config.c +++ b/servers/lwip/inet_config.c @@ -22,11 +22,10 @@ Copyright 1995 Philip Homburg #include #include #include +#include #include "inet_config.h" #include "proto.h" -#include - struct eth_conf eth_conf[IP_PORT_MAX]; struct psip_conf psip_conf[IP_PORT_MAX]; diff --git a/servers/lwip/lwip.c b/servers/lwip/lwip.c index aec4fc434..c7f75a85d 100644 --- a/servers/lwip/lwip.c +++ b/servers/lwip/lwip.c @@ -206,13 +206,13 @@ static void netif_poll_lo(void) netif_poll(netif_lo); } -void socket_open(message * m) +int socket_open(devminor_t minor) { struct sock_ops * ops; struct socket * sock; int ret = OK; - switch (m->DEVICE) { + switch (minor) { case SOCK_TYPE_TCP: ops = &sock_tcp_ops; break; @@ -223,21 +223,17 @@ void socket_open(message * m) ops = &sock_raw_ip_ops; break; default: - if (m->DEVICE - SOCK_TYPES < MAX_DEVS) { - m->DEVICE -= SOCK_TYPES; - nic_open(m); - return; - } - printf("LWIP unknown socket type %d\n", m->DEVICE); - send_reply_open(m, EINVAL); - return; + if (minor - SOCK_TYPES < MAX_DEVS) + return nic_open(minor - SOCK_TYPES); + + printf("LWIP unknown socket type %d\n", minor); + return EINVAL; } sock = get_unused_sock(); if (!sock) { printf("LWIP : no free socket\n"); - send_reply_open(m, EAGAIN); - return; + return EAGAIN; } sock->ops = ops; @@ -245,15 +241,16 @@ void socket_open(message * m) sock->recv_data_size = 0; if (sock->ops && sock->ops->open) - ret = sock->ops->open(sock, m); + ret = sock->ops->open(sock); if (ret == OK) { debug_print("new socket %ld", get_sock_num(sock)); - send_reply_open(m, get_sock_num(sock)); + ret = get_sock_num(sock); } else { debug_print("failed %d", ret); - send_reply_open(m, ret); + /* FIXME: shouldn't sock be freed now? */ } + return ret; } int main(__unused int argc, __unused char ** argv) @@ -274,7 +271,7 @@ int main(__unused int argc, __unused char ** argv) } if (m.m_source == VFS_PROC_NR) - socket_request(&m); + socket_request(&m, ipc_status); else if (is_ipc_notify(ipc_status)) { switch (m.m_source) { case CLOCK: diff --git a/servers/lwip/proto.h b/servers/lwip/proto.h index 400e5b945..ce967a02f 100644 --- a/servers/lwip/proto.h +++ b/servers/lwip/proto.h @@ -28,8 +28,8 @@ void nic_init_all(void); void driver_request(message * m); void driver_up(const char * label, endpoint_t ep); /* opens a raw NIC socket */ -void nic_open(message *m); -void nic_default_ioctl(message *m); +int nic_open(devminor_t minor); +int nic_default_ioctl(struct sock_req *req); /* inet_config.c */ void inet_read_conf(void); diff --git a/servers/lwip/raw_ip.c b/servers/lwip/raw_ip.c index a8b8e5190..d199caac5 100644 --- a/servers/lwip/raw_ip.c +++ b/servers/lwip/raw_ip.c @@ -30,7 +30,7 @@ static void raw_ip_recv_free(void * data) } -static int raw_ip_op_open(struct socket * sock, __unused message * m) +static int raw_ip_op_open(struct socket * sock) { debug_print("socket num %ld", get_sock_num(sock)); @@ -56,31 +56,30 @@ static void raw_ip_close(struct socket * sock) sock->ops = NULL; } -static void raw_ip_op_close(struct socket * sock, __unused message * m) +static int raw_ip_op_close(struct socket * sock) { debug_print("socket num %ld", get_sock_num(sock)); raw_ip_close(sock); - sock_reply_close(sock, OK); + return OK; } -static int raw_ip_do_receive(message * m, +static int raw_ip_do_receive(struct sock_req *req, struct pbuf *pbuf) { struct pbuf * p; - unsigned int rem_len = m->COUNT; + size_t rem_len = req->size; unsigned int written = 0, hdr_sz = 0; int err; - debug_print("user buffer size : %d\n", rem_len); + debug_print("user buffer size : %u\n", rem_len); for (p = pbuf; p && rem_len; p = p->next) { size_t cp_len; cp_len = (rem_len < p->len) ? rem_len : p->len; - err = copy_to_user(m->m_source, p->payload, cp_len, - (cp_grant_id_t) m->IO_GRANT, + err = copy_to_user(req->endpt, p->payload, cp_len, req->grant, hdr_sz + written); if (err != OK) @@ -108,19 +107,17 @@ static u8_t raw_ip_op_receive(void *arg, if (sock->flags & SOCK_FLG_OP_PENDING) { /* we are resuming a suspended operation */ - ret = raw_ip_do_receive(&sock->mess, pbuf); + ret = raw_ip_do_receive(&sock->req, pbuf); + + send_req_reply(&sock->req, ret); + sock->flags &= ~SOCK_FLG_OP_PENDING; if (ret > 0) { - sock_reply(sock, ret); - sock->flags &= ~SOCK_FLG_OP_PENDING; if (sock->usr_flags & NWIO_EXCL) { pbuf_free(pbuf); return 1; } else return 0; - } else { - sock_reply(sock, ret); - sock->flags &= ~SOCK_FLG_OP_PENDING; } } @@ -170,14 +167,12 @@ static u8_t raw_ip_op_receive(void *arg, return ret; } -static void raw_ip_op_read(struct socket * sock, message * m, int blk) +static int raw_ip_op_read(struct socket * sock, struct sock_req * req, int blk) { debug_print("socket num %ld", get_sock_num(sock)); - if (sock->pcb == NULL) { - sock_reply(sock, EIO); - return; - } + if (sock->pcb == NULL) + return EIO; if (sock->recv_head) { /* data available receive immeditely */ @@ -187,62 +182,57 @@ static void raw_ip_op_read(struct socket * sock, message * m, int blk) data = (struct raw_ip_recv_data *) sock->recv_head->data; - ret = raw_ip_do_receive(m, data->pbuf); + ret = raw_ip_do_receive(req, data->pbuf); if (ret > 0) { sock_dequeue_data(sock); sock->recv_data_size -= data->pbuf->tot_len; raw_ip_recv_free(data); } - sock_reply(sock, ret); + return ret; } else if (!blk) - sock_reply(sock, EAGAIN); + return EAGAIN; else { - /* store the message so we know how to reply */ - sock->mess = *m; + /* store the request so we know how to reply */ + sock->req = *req; /* operation is being processes */ sock->flags |= SOCK_FLG_OP_PENDING; debug_print("no data to read, suspending"); + return EDONTREPLY; } } -static void raw_ip_op_write(struct socket * sock, message * m, __unused int blk) +static int raw_ip_op_write(struct socket * sock, struct sock_req * req, + __unused int blk) { int ret; struct pbuf * pbuf; struct ip_hdr * ip_hdr; - debug_print("socket num %ld data size %d", - get_sock_num(sock), m->COUNT); + debug_print("socket num %ld data size %u", + get_sock_num(sock), req->size); - if (sock->pcb == NULL) { - ret = EIO; - goto write_err; - } + if (sock->pcb == NULL) + return EIO; - if ((size_t) m->COUNT > sock->buf_size) { - ret = ENOMEM; - goto write_err; - } + if (req->size > sock->buf_size) + return ENOMEM; - pbuf = pbuf_alloc(PBUF_LINK, m->COUNT, PBUF_RAM); - if (!pbuf) { - ret = ENOMEM; - goto write_err; - } + pbuf = pbuf_alloc(PBUF_LINK, req->size, PBUF_RAM); + if (!pbuf) + return ENOMEM; - if ((ret = copy_from_user(m->m_source, pbuf->payload, m->COUNT, - (cp_grant_id_t) m->IO_GRANT, 0)) != OK) { + if ((ret = copy_from_user(req->endpt, pbuf->payload, req->size, + req->grant, 0)) != OK) { pbuf_free(pbuf); - goto write_err; + return ret; } ip_hdr = (struct ip_hdr *) pbuf->payload; if (pbuf_header(pbuf, -IP_HLEN)) { pbuf_free(pbuf); - ret = EIO; - goto write_err; + return EIO; } if ((ret = raw_sendto((struct raw_pcb *)sock->pcb, pbuf, @@ -250,28 +240,27 @@ static void raw_ip_op_write(struct socket * sock, message * m, __unused int blk) debug_print("raw_sendto failed %d", ret); ret = EIO; } else - ret = m->COUNT; + ret = req->size; pbuf_free(pbuf); -write_err: - sock_reply(sock, ret); + return ret; } -static void raw_ip_set_opt(struct socket * sock, message * m) +static int raw_ip_set_opt(struct socket * sock, endpoint_t endpt, + cp_grant_id_t grant) { int err; nwio_ipopt_t ipopt; struct raw_pcb * pcb; - err = copy_from_user(m->m_source, &ipopt, sizeof(ipopt), - (cp_grant_id_t) m->IO_GRANT, 0); + err = copy_from_user(endpt, &ipopt, sizeof(ipopt), grant, 0); if (err != OK) - sock_reply(sock, err); + return err; - debug_print("ipopt.nwio_flags = 0x%lx", ipopt.nwio_flags); + debug_print("ipopt.nwio_flags = 0x%x", ipopt.nwio_flags); debug_print("ipopt.nwio_proto = 0x%x", ipopt.nwio_proto); debug_print("ipopt.nwio_rem = 0x%x", (unsigned int) ipopt.nwio_rem); @@ -279,8 +268,7 @@ static void raw_ip_set_opt(struct socket * sock, message * m) if (sock->pcb == NULL) { if (!(pcb = raw_new(ipopt.nwio_proto))) { raw_ip_close(sock); - sock_reply(sock, ENOMEM); - return; + return ENOMEM; } sock->pcb = pcb; @@ -289,7 +277,7 @@ static void raw_ip_set_opt(struct socket * sock, message * m) if (pcb->protocol != ipopt.nwio_proto) { debug_print("conflicting ip socket protocols\n"); - sock_reply(sock, EBADIOCTL); + return EINVAL; } sock->usr_flags = ipopt.nwio_flags; @@ -297,20 +285,19 @@ static void raw_ip_set_opt(struct socket * sock, message * m) #if 0 if (raw_bind(pcb, (ip_addr_t *)&ipopt.nwio_rem) == ERR_USE) { raw_ip_close(sock); - sock_reply(sock, EADDRINUSE); - return; + return EADDRINUSE; } #endif /* register a receive hook */ raw_recv((struct raw_pcb *) sock->pcb, raw_ip_op_receive, sock); - sock_reply(sock, OK); + return OK; } -static void raw_ip_get_opt(struct socket * sock, message * m) +static int raw_ip_get_opt(struct socket * sock, endpoint_t endpt, + cp_grant_id_t grant) { - int err; nwio_ipopt_t ipopt; struct raw_pcb * pcb = (struct raw_pcb *) sock->pcb; @@ -319,43 +306,36 @@ static void raw_ip_get_opt(struct socket * sock, message * m) ipopt.nwio_rem = pcb->remote_ip.addr; ipopt.nwio_flags = sock->usr_flags; - if ((unsigned int) m->COUNT < sizeof(ipopt)) { - sock_reply(sock, EINVAL); - return; - } - - err = copy_to_user(m->m_source, &ipopt, sizeof(ipopt), - (cp_grant_id_t) m->IO_GRANT, 0); - - if (err != OK) - sock_reply(sock, err); - - sock_reply(sock, OK); + return copy_to_user(endpt, &ipopt, sizeof(ipopt), grant, 0); } -static void raw_ip_op_ioctl(struct socket * sock, message * m, __unused int blk) +static int raw_ip_op_ioctl(struct socket * sock, struct sock_req * req, + __unused int blk) { - debug_print("socket num %ld req %c %d %d", + int r; + + debug_print("socket num %ld req %c %ld %ld", get_sock_num(sock), - (m->REQUEST >> 8) & 0xff, - m->REQUEST & 0xff, - (m->REQUEST >> 16) & _IOCPARM_MASK); + (unsigned char) (req->req >> 8), + req->req & 0xff, + (req->req >> 16) & _IOCPARM_MASK); - switch (m->REQUEST) { + switch (req->req) { case NWIOSIPOPT: - raw_ip_set_opt(sock, m); + r = raw_ip_set_opt(sock, req->endpt, req->grant); break; case NWIOGIPOPT: - raw_ip_get_opt(sock, m); + r = raw_ip_get_opt(sock, req->endpt, req->grant); break; default: /* * /dev/ip can be also accessed as a default device to be * configured */ - nic_default_ioctl(m); - return; + r = nic_default_ioctl(req); } + + return r; } struct sock_ops sock_raw_ip_ops = { diff --git a/servers/lwip/tcp.c b/servers/lwip/tcp.c index 3a33e8092..7d0cea26f 100644 --- a/servers/lwip/tcp.c +++ b/servers/lwip/tcp.c @@ -65,9 +65,10 @@ static void tcp_error_callback(void *arg, err_t err) default: perr = EIO; } - + + /* FIXME: what if this is for a write that was already replied to? */ if (sock->flags & SOCK_FLG_OP_PENDING) { - sock_reply(sock, perr); + send_req_reply(&sock->req, perr); sock->flags &= ~SOCK_FLG_OP_PENDING; } else if (sock_select_set(sock)) sock_select_notify(sock); @@ -98,7 +99,7 @@ static int tcp_fill_new_socket(struct socket * sock, struct tcp_pcb * pcb) return OK; } -static int tcp_op_open(struct socket * sock, __unused message * m) +static int tcp_op_open(struct socket * sock) { struct tcp_pcb * pcb; int ret; @@ -142,7 +143,7 @@ static void free_wbuf_chain(struct wbuf_chain * wc) debug_free(wc); } -static void tcp_op_close(struct socket * sock, __unused message * m) +static int tcp_op_close(struct socket * sock) { debug_tcp_print("socket num %ld", get_sock_num(sock)); @@ -175,11 +176,12 @@ static void tcp_op_close(struct socket * sock, __unused message * m) } debug_tcp_print("freed TX data"); - sock_reply_close(sock, OK); debug_tcp_print("socket unused"); /* mark it as unused */ sock->ops = NULL; + + return OK; } __unused static void print_tcp_payload(unsigned char * buf, int len) @@ -195,14 +197,14 @@ __unused static void print_tcp_payload(unsigned char * buf, int len) kputc('\n'); } -static int read_from_tcp(struct socket * sock, message * m) +static int read_from_tcp(struct socket * sock, struct sock_req * req) { unsigned int rem_buf, written = 0; struct pbuf * p; assert(!(sock->flags & SOCK_FLG_OP_LISTENING) && sock->recv_head); - rem_buf = m->COUNT; + rem_buf = req->size; debug_tcp_print("socket num %ld recv buff sz %d", get_sock_num(sock), rem_buf); @@ -220,8 +222,8 @@ static int read_from_tcp(struct socket * sock, message * m) #if 0 print_tcp_payload(p->payload, p->len); #endif - err = copy_to_user(m->m_source, p->payload, p->len, - (cp_grant_id_t) m->IO_GRANT, written); + err = copy_to_user(req->endpt, p->payload, p->len, + req->grant, written); if (err != OK) goto cp_error; sock->recv_data_size -= p->len; @@ -261,8 +263,8 @@ static int read_from_tcp(struct socket * sock, message * m) #if 0 print_tcp_payload(p->payload, rem_buf); #endif - err = copy_to_user(m->m_source, p->payload, rem_buf, - (cp_grant_id_t) m->IO_GRANT, written); + err = copy_to_user(req->endpt, p->payload, rem_buf, + req->grant, written); if (err != OK) goto cp_error; sock->recv_data_size -= rem_buf; @@ -292,37 +294,36 @@ cp_error: return EFAULT; } -static void tcp_op_read(struct socket * sock, message * m, int blk) +static int tcp_op_read(struct socket * sock, struct sock_req * req, int blk) { debug_tcp_print("socket num %ld", get_sock_num(sock)); if (!sock->pcb || ((struct tcp_pcb *) sock->pcb)->state != ESTABLISHED) { debug_tcp_print("Connection not established\n"); - sock_reply(sock, ENOTCONN); - return; + return ENOTCONN; } if (sock->recv_head) { /* data available receive immeditely */ - int ret = read_from_tcp(sock, m); + int ret = read_from_tcp(sock, req); debug_tcp_print("read op finished"); - sock_reply(sock, ret); + return ret; } else { if (sock->flags & SOCK_FLG_CLOSED) { printf("socket %ld already closed!!! call from %d\n", - get_sock_num(sock), m->USER_ENDPT); + get_sock_num(sock), req->endpt); do_tcp_debug = 1; - sock_reply(sock, 0); - return; + return 0; } if (!blk) { debug_tcp_print("reading would block -> EAGAIN"); - sock_reply(sock, EAGAIN); - return; + return EAGAIN; } /* operation is being processed */ + sock->req = *req; debug_tcp_print("no data to read, suspending"); sock->flags |= SOCK_FLG_OP_PENDING | SOCK_FLG_OP_READING; + return EDONTREPLY; } } @@ -389,7 +390,8 @@ static struct wbuf * wbuf_ack_sent(struct socket * sock, unsigned int sz) return wc->head; } -static void tcp_op_write(struct socket * sock, message * m, __unused int blk) +static int tcp_op_write(struct socket * sock, struct sock_req * req, + __unused int blk) { int ret; struct wbuf * wbuf; @@ -397,12 +399,10 @@ static void tcp_op_write(struct socket * sock, message * m, __unused int blk) u8_t flgs = 0; - if (!sock->pcb) { - sock_reply(sock, ENOTCONN); - return; - } + if (!sock->pcb) + return ENOTCONN; - usr_buf_len = m->COUNT; + usr_buf_len = req->size; debug_tcp_print("socket num %ld data size %d", get_sock_num(sock), usr_buf_len); @@ -413,8 +413,7 @@ static void tcp_op_write(struct socket * sock, message * m, __unused int blk) if (sock->buf_size >= TCP_BUF_SIZE) { /* FIXME do not block for now */ debug_tcp_print("WARNING : tcp buffers too large, cannot allocate more"); - sock_reply(sock, ENOMEM); - return; + return ENOMEM; } /* * Never let the allocated buffers grow more than to 2xTCP_BUF_SIZE and @@ -426,13 +425,12 @@ static void tcp_op_write(struct socket * sock, message * m, __unused int blk) if (!wbuf) { debug_tcp_print("cannot allocate new buffer of %d bytes", usr_buf_len); - sock_reply(sock, ENOMEM); + return ENOMEM; } - if ((ret = copy_from_user(m->m_source, wbuf->data, usr_buf_len, - (cp_grant_id_t) m->IO_GRANT, 0)) != OK) { - sock_reply(sock, ret); - return; + if ((ret = copy_from_user(req->endpt, wbuf->data, usr_buf_len, + req->grant, 0)) != OK) { + return ret; } wbuf->written = 0; @@ -453,15 +451,18 @@ static void tcp_op_write(struct socket * sock, message * m, __unused int blk) debug_tcp_print("unsent %p remains %d\n", wbuf, wbuf->rem_len); } debug_tcp_print("returns %d\n", usr_buf_len); - sock_reply(sock, usr_buf_len); /* * We cannot accept new operations (write). We set the flag * after sending reply not to revive only. We could deadlock. */ + /* + * FIXME: this looks like bad logic. We acknowledge the write + * operation, so we will never reply to it or cancel it later. + */ if (sock->buf_size >= TCP_BUF_SIZE) sock->flags |= SOCK_FLG_OP_PENDING; - return; + return usr_buf_len; } /* @@ -496,15 +497,20 @@ static void tcp_op_write(struct socket * sock, message * m, __unused int blk) * in this case, we are going to reply immediatly */ debug_tcp_print("returns %d\n", usr_buf_len); - sock_reply(sock, usr_buf_len); sock->flags |= SOCK_FLG_OP_WRITING; + /* + * FIXME: this looks like bad logic. We acknowledge the write + * operation, so we will never reply to it or cancel it later. + */ if (sock->buf_size >= TCP_BUF_SIZE) sock->flags |= SOCK_FLG_OP_PENDING; + return usr_buf_len; } else - sock_reply(sock, EIO); + return EIO; } -static void tcp_set_conf(struct socket * sock, message * m) +static int tcp_set_conf(struct socket * sock, endpoint_t endpt, + cp_grant_id_t grant) { int err; nwio_tcpconf_t tconf; @@ -514,13 +520,12 @@ static void tcp_set_conf(struct socket * sock, message * m) assert(pcb); - err = copy_from_user(m->m_source, &tconf, sizeof(tconf), - (cp_grant_id_t) m->IO_GRANT, 0); + err = copy_from_user(endpt, &tconf, sizeof(tconf), grant, 0); if (err != OK) - sock_reply(sock, err); + return err; - debug_tcp_print("tconf.nwtc_flags = 0x%lx", tconf.nwtc_flags); + debug_tcp_print("tconf.nwtc_flags = 0x%x", tconf.nwtc_flags); debug_tcp_print("tconf.nwtc_remaddr = 0x%x", (unsigned int) tconf.nwtc_remaddr); debug_tcp_print("tconf.nwtc_remport = 0x%x", ntohs(tconf.nwtc_remport)); @@ -538,17 +543,16 @@ static void tcp_set_conf(struct socket * sock, message * m) if (sock->usr_flags & NWTC_LP_SET) { /* FIXME the user library can only bind to ANY anyway */ if (tcp_bind(pcb, IP_ADDR_ANY, ntohs(tconf.nwtc_locport)) == ERR_USE) { - sock_reply(sock, EADDRINUSE); - return; + return EADDRINUSE; } } - - sock_reply(sock, OK); + + return OK; } -static void tcp_get_conf(struct socket * sock, message * m) +static int tcp_get_conf(struct socket * sock, endpoint_t endpt, + cp_grant_id_t grant) { - int err; nwio_tcpconf_t tconf; struct tcp_pcb * pcb = (struct tcp_pcb *) sock->pcb; @@ -562,7 +566,7 @@ static void tcp_get_conf(struct socket * sock, message * m) tconf.nwtc_remport = htons(pcb->remote_port); tconf.nwtc_flags = sock->usr_flags; - debug_tcp_print("tconf.nwtc_flags = 0x%lx", tconf.nwtc_flags); + debug_tcp_print("tconf.nwtc_flags = 0x%x", tconf.nwtc_flags); debug_tcp_print("tconf.nwtc_remaddr = 0x%x", (unsigned int) tconf.nwtc_remaddr); debug_tcp_print("tconf.nwtc_remport = 0x%x", ntohs(tconf.nwtc_remport)); @@ -570,18 +574,7 @@ static void tcp_get_conf(struct socket * sock, message * m) (unsigned int) tconf.nwtc_locaddr); debug_tcp_print("tconf.nwtc_locport = 0x%x", ntohs(tconf.nwtc_locport)); - if ((unsigned int) m->COUNT < sizeof(tconf)) { - sock_reply(sock, EINVAL); - return; - } - - err = copy_to_user(m->m_source, &tconf, sizeof(tconf), - (cp_grant_id_t) m->IO_GRANT, 0); - - if (err != OK) - sock_reply(sock, err); - - sock_reply(sock, OK); + return copy_to_user(endpt, &tconf, sizeof(tconf), grant, 0); } static int enqueue_rcv_data(struct socket * sock, struct pbuf * pbuf) @@ -627,7 +620,7 @@ static err_t tcp_recv_callback(void *arg, /* wake up the reader and report EOF */ if (sock->flags & SOCK_FLG_OP_PENDING && sock->flags & SOCK_FLG_OP_READING) { - sock_reply(sock, 0); + send_req_reply(&sock->req, 0); sock->flags &= ~(SOCK_FLG_OP_PENDING | SOCK_FLG_OP_READING); } @@ -655,9 +648,9 @@ static err_t tcp_recv_callback(void *arg, */ if (sock->flags & SOCK_FLG_OP_PENDING) { if (sock->flags & SOCK_FLG_OP_READING) { - ret = read_from_tcp(sock, &sock->mess); + ret = read_from_tcp(sock, &sock->req); debug_tcp_print("read op finished"); - sock_reply(sock, ret); + send_req_reply(&sock->req, ret); sock->flags &= ~(SOCK_FLG_OP_PENDING | SOCK_FLG_OP_READING); } @@ -692,7 +685,11 @@ static err_t tcp_sent_callback(void *arg, struct tcp_pcb *tpcb, u16_t len) assert((struct tcp_pcb *)sock->pcb == tpcb); /* operation must have been canceled, do not send any other data */ - if (!sock->flags & SOCK_FLG_OP_PENDING) + /* + * FIXME: this looks like bad logic. We already acknowledged the write + * operation, so we should not set or check the OP_PENDING flag.. + */ + if (!(sock->flags & SOCK_FLG_OP_PENDING)) return ERR_OK; wbuf = wbuf_ack_sent(sock, len); @@ -797,7 +794,7 @@ static err_t tcp_connected_callback(void *arg, tcp_sent(tpcb, tcp_sent_callback); tcp_recv(tpcb, tcp_recv_callback); - sock_reply(sock, OK); + send_req_reply(&sock->req, OK); sock->flags &= ~(SOCK_FLG_OP_PENDING | SOCK_FLG_OP_CONNECTING); /* revive does the sock_select_notify() for us */ @@ -805,7 +802,7 @@ static err_t tcp_connected_callback(void *arg, return ERR_OK; } -static void tcp_op_connect(struct socket * sock) +static int tcp_op_connect(struct socket * sock, struct sock_req * req) { ip_addr_t remaddr; struct tcp_pcb * pcb; @@ -821,16 +818,18 @@ static void tcp_op_connect(struct socket * sock) /* try to connect now */ pcb = (struct tcp_pcb *) sock->pcb; remaddr = pcb->remote_ip; + sock->req = *req; err = tcp_connect(pcb, &remaddr, pcb->remote_port, tcp_connected_callback); if (err == ERR_VAL) panic("Wrong tcp_connect arguments"); if (err != ERR_OK) panic("Other tcp_connect error %d\n", err); + return EDONTREPLY; } static int tcp_do_accept(struct socket * listen_sock, - message * m, + struct sock_req * req, struct tcp_pcb * newpcb) { struct socket * newsock; @@ -839,8 +838,8 @@ static int tcp_do_accept(struct socket * listen_sock, debug_tcp_print("socket num %ld", get_sock_num(listen_sock)); - if ((ret = copy_from_user(m->m_source, &sock_num, sizeof(sock_num), - (cp_grant_id_t) m->IO_GRANT, 0)) != OK) + if ((ret = copy_from_user(req->endpt, &sock_num, sizeof(sock_num), + req->grant, 0)) != OK) return EFAULT; if (!is_valid_sock_num(sock_num)) return EBADF; @@ -877,8 +876,8 @@ static err_t tcp_accept_callback(void *arg, struct tcp_pcb *newpcb, err_t err) if (sock->flags & SOCK_FLG_OP_PENDING) { int ret; - ret = tcp_do_accept(sock, &sock->mess, newpcb); - sock_reply(sock, ret); + ret = tcp_do_accept(sock, &sock->req, newpcb); + send_req_reply(&sock->req, ret); sock->flags &= ~SOCK_FLG_OP_PENDING; if (ret == OK) { return ERR_OK; @@ -900,15 +899,18 @@ static err_t tcp_accept_callback(void *arg, struct tcp_pcb *newpcb, err_t err) return ERR_OK; } -static void tcp_op_listen(struct socket * sock, message * m) +static int tcp_op_listen(struct socket * sock, endpoint_t endpt, + cp_grant_id_t grant) { int backlog, err; struct tcp_pcb * new_pcb; debug_tcp_print("socket num %ld", get_sock_num(sock)); - err = copy_from_user(m->m_source, &backlog, sizeof(backlog), - (cp_grant_id_t) m->IO_GRANT, 0); + err = copy_from_user(endpt, &backlog, sizeof(backlog), grant, 0); + + if (err != OK) + return err; new_pcb = tcp_listen_with_backlog((struct tcp_pcb *) sock->pcb, (u8_t) backlog); @@ -916,8 +918,7 @@ static void tcp_op_listen(struct socket * sock, message * m) if (!new_pcb) { debug_tcp_print("Cannot listen on socket %ld", get_sock_num(sock)); - sock_reply(sock, EGENERIC); - return; + return EIO; } /* advertise that this socket is willing to accept connections */ @@ -925,17 +926,16 @@ static void tcp_op_listen(struct socket * sock, message * m) sock->flags |= SOCK_FLG_OP_LISTENING; sock->pcb = new_pcb; - sock_reply(sock, OK); + return OK; } -static void tcp_op_accept(struct socket * sock, message * m) +static int tcp_op_accept(struct socket * sock, struct sock_req * req) { debug_tcp_print("socket num %ld", get_sock_num(sock)); if (!(sock->flags & SOCK_FLG_OP_LISTENING)) { debug_tcp_print("socket %ld does not listen\n", get_sock_num(sock)); - sock_reply(sock, EINVAL); - return; + return EINVAL; } /* there is a connection ready to be accepted */ @@ -946,19 +946,22 @@ static void tcp_op_accept(struct socket * sock, message * m) pcb = (struct tcp_pcb *) sock->recv_head->data; assert(pcb); - ret = tcp_do_accept(sock, m, pcb); - sock_reply(sock, ret); + ret = tcp_do_accept(sock, req, pcb); if (ret == OK) sock_dequeue_data(sock); - return; + return ret; } debug_tcp_print("no ready connection, suspending\n"); + sock->req = *req; + sock->flags |= SOCK_FLG_OP_PENDING; + + return EDONTREPLY; } -static void tcp_op_shutdown_tx(struct socket * sock) +static int tcp_op_shutdown_tx(struct socket * sock) { err_t err; @@ -968,17 +971,16 @@ static void tcp_op_shutdown_tx(struct socket * sock) switch (err) { case ERR_OK: - sock_reply(sock, OK); - break; + return OK; case ERR_CONN: - sock_reply(sock, ENOTCONN); - break; + return ENOTCONN; default: - sock_reply(sock, EGENERIC); + return EIO; } } -static void tcp_op_get_cookie(struct socket * sock, message * m) +static int tcp_op_get_cookie(struct socket * sock, endpoint_t endpt, + cp_grant_id_t grant) { tcp_cookie_t cookie; unsigned int sock_num; @@ -988,16 +990,12 @@ static void tcp_op_get_cookie(struct socket * sock, message * m) sock_num = get_sock_num(sock); memcpy(&cookie, &sock_num, sizeof(sock_num)); - if (copy_to_user(m->m_source, &cookie, sizeof(sock), - (cp_grant_id_t) m->IO_GRANT, 0) == OK) - sock_reply(sock, OK); - else - sock_reply(sock, EFAULT); + return copy_to_user(endpt, &cookie, sizeof(sock), grant, 0); } -static void tcp_get_opt(struct socket * sock, message * m) +static int tcp_get_opt(struct socket * sock, endpoint_t endpt, + cp_grant_id_t grant) { - int err; nwio_tcpopt_t tcpopt; struct tcp_pcb * pcb = (struct tcp_pcb *) sock->pcb; @@ -1005,26 +1003,15 @@ static void tcp_get_opt(struct socket * sock, message * m) assert(pcb); - if ((unsigned int) m->COUNT < sizeof(tcpopt)) { - sock_reply(sock, EINVAL); - return; - } - /* FIXME : not used by the userspace library */ tcpopt.nwto_flags = 0; - err = copy_to_user(m->m_source, &tcpopt, sizeof(tcpopt), - (cp_grant_id_t) m->IO_GRANT, 0); - - if (err != OK) - sock_reply(sock, err); - - sock_reply(sock, OK); + return copy_to_user(endpt, &tcpopt, sizeof(tcpopt), grant, 0); } -static void tcp_set_opt(struct socket * sock, message * m) +static int tcp_set_opt(struct socket * sock, endpoint_t endpt, + cp_grant_id_t grant) { - int err; nwio_tcpopt_t tcpopt; struct tcp_pcb * pcb = (struct tcp_pcb *) sock->pcb; @@ -1032,91 +1019,85 @@ static void tcp_set_opt(struct socket * sock, message * m) assert(pcb); - err = copy_from_user(m->m_source, &tcpopt, sizeof(tcpopt), - (cp_grant_id_t) m->IO_GRANT, 0); - - if (err != OK) - sock_reply(sock, err); - /* FIXME : The userspace library does not use this */ - sock_reply(sock, OK); + return copy_from_user(endpt, &tcpopt, sizeof(tcpopt), grant, 0); } -static void tcp_op_ioctl(struct socket * sock, message * m, __unused int blk) +static int tcp_op_ioctl(struct socket * sock, struct sock_req * req, + __unused int blk) { - if (!sock->pcb) { - sock_reply(sock, ENOTCONN); - return; - } + int r; - debug_tcp_print("socket num %ld req %c %d %d", + if (!sock->pcb) + return ENOTCONN; + + debug_tcp_print("socket num %ld req %c %ld %ld", get_sock_num(sock), - (m->REQUEST >> 8) & 0xff, - m->REQUEST & 0xff, - (m->REQUEST >> 16) & _IOCPARM_MASK); + (unsigned char) (req->req >> 8), + req->req & 0xff, + (req->req >> 16) & _IOCPARM_MASK); - switch (m->REQUEST) { + switch (req->req) { case NWIOGTCPCONF: - tcp_get_conf(sock, m); + r = tcp_get_conf(sock, req->endpt, req->grant); break; case NWIOSTCPCONF: - tcp_set_conf(sock, m); + r = tcp_set_conf(sock, req->endpt, req->grant); break; case NWIOTCPCONN: - tcp_op_connect(sock); + r = tcp_op_connect(sock, req); break; case NWIOTCPLISTENQ: - tcp_op_listen(sock, m); + r = tcp_op_listen(sock, req->endpt, req->grant); break; case NWIOGTCPCOOKIE: - tcp_op_get_cookie(sock, m); + r = tcp_op_get_cookie(sock, req->endpt, req->grant); break; case NWIOTCPACCEPTTO: - tcp_op_accept(sock, m); + r = tcp_op_accept(sock, req); break; case NWIOTCPSHUTDOWN: - tcp_op_shutdown_tx(sock); + r = tcp_op_shutdown_tx(sock); break; case NWIOGTCPOPT: - tcp_get_opt(sock, m); + r = tcp_get_opt(sock, req->endpt, req->grant); break; case NWIOSTCPOPT: - tcp_set_opt(sock, m); + r = tcp_set_opt(sock, req->endpt, req->grant); break; default: - sock_reply(sock, EBADIOCTL); - return; + r = ENOTTY; } + + return r; } -static void tcp_op_select(struct socket * sock, __unused message * m) +static int tcp_op_select(struct socket * sock, unsigned int sel) { - int retsel = 0, sel; + int retsel = 0; - sel = m->USER_ENDPT; debug_tcp_print("socket num %ld 0x%x", get_sock_num(sock), sel); /* in this case any operation would block, no error */ if (sock->flags & SOCK_FLG_OP_PENDING) { debug_tcp_print("SOCK_FLG_OP_PENDING"); - if (sel & SEL_NOTIFY) { - if (sel & SEL_RD) { + if (sel & CDEV_NOTIFY) { + if (sel & CDEV_OP_RD) { sock->flags |= SOCK_FLG_SEL_READ; debug_tcp_print("monitor read"); } - if (sel & SEL_WR) { + if (sel & CDEV_OP_WR) { sock->flags |= SOCK_FLG_SEL_WRITE; debug_tcp_print("monitor write"); } - if (sel & SEL_ERR) + if (sel & CDEV_OP_ERR) sock->flags |= SOCK_FLG_SEL_ERROR; } - sock_reply_select(sock, 0); - return; + return 0; } - if (sel & SEL_RD) { + if (sel & CDEV_OP_RD) { /* * If recv_head is not NULL we can either read or accept a * connection which is the same for select() @@ -1124,52 +1105,53 @@ static void tcp_op_select(struct socket * sock, __unused message * m) if (sock->pcb) { if (sock->recv_head && !(sock->flags & SOCK_FLG_OP_WRITING)) - retsel |= SEL_RD; + retsel |= CDEV_OP_RD; else if (!(sock->flags & SOCK_FLG_OP_LISTENING) && ((struct tcp_pcb *) sock->pcb)->state != ESTABLISHED) - retsel |= SEL_RD; - else if (sel & SEL_NOTIFY) { + retsel |= CDEV_OP_RD; + else if (sel & CDEV_NOTIFY) { sock->flags |= SOCK_FLG_SEL_READ; debug_tcp_print("monitor read"); } - } else - retsel |= SEL_RD; /* not connected read does not block */ + } else /* not connected read does not block */ + retsel |= CDEV_OP_RD; } - if (sel & SEL_WR) { + if (sel & CDEV_OP_WR) { if (sock->pcb) { if (((struct tcp_pcb *) sock->pcb)->state == ESTABLISHED) - retsel |= SEL_WR; - else if (sel & SEL_NOTIFY) { + retsel |= CDEV_OP_WR; + else if (sel & CDEV_NOTIFY) { sock->flags |= SOCK_FLG_SEL_WRITE; debug_tcp_print("monitor write"); } - } else - retsel |= SEL_WR; /* not connected write does not block */ + } else /* not connected write does not block */ + retsel |= CDEV_OP_WR; } - if (retsel & SEL_RD) { + if (retsel & CDEV_OP_RD) { debug_tcp_print("read won't block"); } - if (retsel & SEL_WR) { + if (retsel & CDEV_OP_WR) { debug_tcp_print("write won't block"); } /* we only monitor if errors will happen in the future */ - if (sel & SEL_ERR && sel & SEL_NOTIFY) + if (sel & CDEV_OP_ERR && sel & CDEV_NOTIFY) sock->flags |= SOCK_FLG_SEL_ERROR; - sock_reply_select(sock, retsel); + return retsel; } -static void tcp_op_select_reply(struct socket * sock, message * m) +static int tcp_op_select_reply(struct socket * sock) { + unsigned int sel = 0; + assert(sock->select_ep != NONE); debug_tcp_print("socket num %ld", get_sock_num(sock)); - if (sock->flags & SOCK_FLG_OP_PENDING) { debug_tcp_print("WARNING socket still blocking!"); - return; + return EDONTREPLY; } if (sock->flags & SOCK_FLG_SEL_READ) { @@ -1178,7 +1160,7 @@ static void tcp_op_select_reply(struct socket * sock, message * m) (!(sock->flags & SOCK_FLG_OP_LISTENING) && ((struct tcp_pcb *) sock->pcb)->state != ESTABLISHED)) { - m->DEV_SEL_OPS |= SEL_RD; + sel |= CDEV_OP_RD; debug_tcp_print("read won't block"); } } @@ -1187,13 +1169,15 @@ static void tcp_op_select_reply(struct socket * sock, message * m) (sock->pcb == NULL || ((struct tcp_pcb *) sock->pcb)->state == ESTABLISHED)) { - m->DEV_SEL_OPS |= SEL_WR; + sel |= CDEV_OP_WR; debug_tcp_print("write won't block"); } - if (m->DEV_SEL_OPS) + if (sel) sock->flags &= ~(SOCK_FLG_SEL_WRITE | SOCK_FLG_SEL_READ | SOCK_FLG_SEL_ERROR); + + return sel; } struct sock_ops sock_tcp_ops = { diff --git a/servers/lwip/udp.c b/servers/lwip/udp.c index c3367c01a..97326a21b 100644 --- a/servers/lwip/udp.c +++ b/servers/lwip/udp.c @@ -41,7 +41,7 @@ static void udp_recv_free(void * data) debug_free(data); } -static int udp_op_open(struct socket * sock, __unused message * m) +static int udp_op_open(struct socket * sock) { struct udp_pcb * pcb; @@ -58,7 +58,7 @@ static int udp_op_open(struct socket * sock, __unused message * m) return OK; } -static void udp_op_close(struct socket * sock, __unused message * m) +static int udp_op_close(struct socket * sock) { debug_udp_print("socket num %ld", get_sock_num(sock)); @@ -72,22 +72,22 @@ static void udp_op_close(struct socket * sock, __unused message * m) /* mark it as unused */ sock->ops = NULL; - sock_reply_close(sock, OK); + return OK; } static int udp_do_receive(struct socket * sock, - message * m, + struct sock_req * req, struct udp_pcb *pcb, struct pbuf *pbuf, ip_addr_t *addr, u16_t port) { struct pbuf * p; - unsigned int rem_len = m->COUNT; + size_t rem_len = req->size; unsigned int written = 0, hdr_sz = 0; int err; - debug_udp_print("user buffer size : %d", rem_len); + debug_udp_print("user buffer size : %u", rem_len); /* FIXME make it both a single copy */ if (!(sock->usr_flags & NWUO_RWDATONLY)) { @@ -101,10 +101,8 @@ static int udp_do_receive(struct socket * sock, hdr.uih_data_len = 0; hdr.uih_ip_opt_len = 0; - err = copy_to_user(m->m_source, - &hdr, sizeof(hdr), - (cp_grant_id_t) m->IO_GRANT, - 0); + err = copy_to_user(req->endpt, &hdr, sizeof(hdr), req->grant, + 0); if (err != OK) return err; @@ -116,8 +114,7 @@ static int udp_do_receive(struct socket * sock, size_t cp_len; cp_len = (rem_len < p->len) ? rem_len : p->len; - err = copy_to_user(m->m_source, p->payload, cp_len, - (cp_grant_id_t) m->IO_GRANT, + err = copy_to_user(req->endpt, p->payload, cp_len, req->grant, hdr_sz + written); if (err != OK) @@ -147,16 +144,14 @@ static void udp_recv_callback(void *arg, /* we are resuming a suspended operation */ int ret; - ret = udp_do_receive(sock, &sock->mess, pcb, pbuf, addr, port); + ret = udp_do_receive(sock, &sock->req, pcb, pbuf, addr, port); + + send_req_reply(&sock->req, ret); + sock->flags &= ~SOCK_FLG_OP_PENDING; if (ret > 0) { pbuf_free(pbuf); - sock_reply(sock, ret); - sock->flags &= ~SOCK_FLG_OP_PENDING; return; - } else { - sock_reply(sock, ret); - sock->flags &= ~SOCK_FLG_OP_PENDING; } } @@ -193,7 +188,7 @@ static void udp_recv_callback(void *arg, sock_select_notify(sock); } -static void udp_op_read(struct socket * sock, message * m, int blk) +static int udp_op_read(struct socket * sock, struct sock_req * req, int blk) { debug_udp_print("socket num %ld", get_sock_num(sock)); @@ -205,7 +200,7 @@ static void udp_op_read(struct socket * sock, message * m, int blk) data = (struct udp_recv_data *) sock->recv_head->data; - ret = udp_do_receive(sock, m, (struct udp_pcb *) sock->pcb, + ret = udp_do_receive(sock, req, (struct udp_pcb *) sock->pcb, data->pbuf, &data->ip, data->port); if (ret > 0) { @@ -213,36 +208,37 @@ static void udp_op_read(struct socket * sock, message * m, int blk) sock->recv_data_size -= data->pbuf->tot_len; udp_recv_free(data); } - sock_reply(sock, ret); + return ret; } else if (!blk) - sock_reply(sock, EAGAIN); + return EAGAIN; else { /* store the message so we know how to reply */ - sock->mess = *m; + sock->req = *req; /* operation is being processes */ sock->flags |= SOCK_FLG_OP_PENDING; debug_udp_print("no data to read, suspending\n"); + return EDONTREPLY; } } static int udp_op_send(struct socket * sock, struct pbuf * pbuf, - message * m) + size_t size) { int err; debug_udp_print("pbuf len %d\n", pbuf->len); if ((err = udp_send(sock->pcb, pbuf)) == ERR_OK) - return m->COUNT; + return size; else { debug_udp_print("udp_send failed %d", err); return EIO; } } -static int udp_op_sendto(struct socket * sock, struct pbuf * pbuf, message * m) +static int udp_op_sendto(struct socket * sock, struct pbuf * pbuf, size_t size) { int err; udp_io_hdr_t hdr; @@ -256,47 +252,46 @@ static int udp_op_sendto(struct socket * sock, struct pbuf * pbuf, message * m) if ((err = udp_sendto(sock->pcb, pbuf, (ip_addr_t *) &hdr.uih_dst_addr, ntohs(hdr.uih_dst_port))) == ERR_OK) - return m->COUNT; + return size; else { debug_udp_print("udp_sendto failed %d", err); return EIO; } } -static void udp_op_write(struct socket * sock, message * m, __unused int blk) +static int udp_op_write(struct socket * sock, struct sock_req * req, + __unused int blk) { int ret; struct pbuf * pbuf; - debug_udp_print("socket num %ld data size %d", - get_sock_num(sock), m->COUNT); + debug_udp_print("socket num %ld data size %u", + get_sock_num(sock), req->size); - pbuf = pbuf_alloc(PBUF_TRANSPORT, m->COUNT, PBUF_POOL); - if (!pbuf) { - ret = ENOMEM; - goto write_err; - } + pbuf = pbuf_alloc(PBUF_TRANSPORT, req->size, PBUF_POOL); + if (!pbuf) + return ENOMEM; - if ((ret = copy_from_user(m->m_source, pbuf->payload, m->COUNT, - (cp_grant_id_t) m->IO_GRANT, 0)) != OK) { + if ((ret = copy_from_user(req->endpt, pbuf->payload, req->size, + req->grant, 0)) != OK) { pbuf_free(pbuf); - goto write_err; + return ret; } if (sock->usr_flags & NWUO_RWDATONLY) - ret = udp_op_send(sock, pbuf, m); + ret = udp_op_send(sock, pbuf, req->size); else - ret = udp_op_sendto(sock, pbuf, m); + ret = udp_op_sendto(sock, pbuf, req->size); if (pbuf_free(pbuf) == 0) { panic("We cannot buffer udp packets yet!"); } - -write_err: - sock_reply(sock, ret); + + return ret; } -static void udp_set_opt(struct socket * sock, message * m) +static int udp_set_opt(struct socket * sock, endpoint_t endpt, + cp_grant_id_t grant) { int err; nwio_udpopt_t udpopt; @@ -305,11 +300,10 @@ static void udp_set_opt(struct socket * sock, message * m) assert(pcb); - err = copy_from_user(m->m_source, &udpopt, sizeof(udpopt), - (cp_grant_id_t) m->IO_GRANT, 0); + err = copy_from_user(endpt, &udpopt, sizeof(udpopt), grant, 0); if (err != OK) - sock_reply(sock, err); + return err; debug_udp_print("udpopt.nwuo_flags = 0x%lx", udpopt.nwuo_flags); debug_udp_print("udpopt.nwuo_remaddr = 0x%x", @@ -341,16 +335,15 @@ static void udp_set_opt(struct socket * sock, message * m) if (sock->usr_flags & NWUO_LP_SEL) udp_bind(pcb, &loc_ip, 0); - /* register a receive hook */ udp_recv((struct udp_pcb *) sock->pcb, udp_recv_callback, sock); - sock_reply(sock, OK); + return OK; } -static void udp_get_opt(struct socket * sock, message * m) +static int udp_get_opt(struct socket * sock, endpoint_t endpt, + cp_grant_id_t grant) { - int err; nwio_udpopt_t udpopt; struct udp_pcb * pcb = (struct udp_pcb *) sock->pcb; @@ -372,39 +365,32 @@ static void udp_get_opt(struct socket * sock, message * m) debug_udp_print("udpopt.nwuo_locport = 0x%x", ntohs(udpopt.nwuo_locport)); - if ((unsigned int) m->COUNT < sizeof(udpopt)) { - sock_reply(sock, EINVAL); - return; - } - - err = copy_to_user(m->m_source, &udpopt, sizeof(udpopt), - (cp_grant_id_t) m->IO_GRANT, 0); - - if (err != OK) - sock_reply(sock, err); - - sock_reply(sock, OK); + return copy_to_user(endpt, &udpopt, sizeof(udpopt), grant, 0); } -static void udp_op_ioctl(struct socket * sock, message * m, __unused int blk) +static int udp_op_ioctl(struct socket * sock, struct sock_req * req, + __unused int blk) { - debug_udp_print("socket num %ld req %c %d %d", - get_sock_num(sock), - (m->REQUEST >> 8) & 0xff, - m->REQUEST & 0xff, - (m->REQUEST >> 16) & _IOCPARM_MASK); + int r; - switch (m->REQUEST) { + debug_udp_print("socket num %ld req %c %ld %ld", + get_sock_num(sock), + (unsigned char) (req->req >> 8), + req->req & 0xff, + (req->req >> 16) & _IOCPARM_MASK); + + switch (req->req) { case NWIOSUDPOPT: - udp_set_opt(sock, m); + r = udp_set_opt(sock, req->endpt, req->grant); break; case NWIOGUDPOPT: - udp_get_opt(sock, m); + r = udp_get_opt(sock, req->endpt, req->grant); break; default: - sock_reply(sock, EBADIOCTL); - return; + r = ENOTTY; } + + return r; } struct sock_ops sock_udp_ops = { diff --git a/servers/mfs/mount.c b/servers/mfs/mount.c index 689e3c87c..df4b8db61 100644 --- a/servers/mfs/mount.c +++ b/servers/mfs/mount.c @@ -44,7 +44,8 @@ int fs_readsuper() bdev_driver(fs_dev, fs_dev_label); /* Open the device the file system lives on. */ - if (bdev_open(fs_dev, readonly ? R_BIT : (R_BIT|W_BIT) ) != OK) { + if (bdev_open(fs_dev, readonly ? BDEV_R_BIT : (BDEV_R_BIT|BDEV_W_BIT) ) != + OK) { return(EINVAL); } @@ -71,7 +72,7 @@ int fs_readsuper() panic("couldn't bdev_close after found unclean FS"); readonly = 1; - if (bdev_open(fs_dev, R_BIT) != OK) { + if (bdev_open(fs_dev, BDEV_R_BIT) != OK) { panic("couldn't bdev_open after found unclean FS"); return(EINVAL); } @@ -187,6 +188,9 @@ int fs_unmount() /* Close the device the file system lives on. */ bdev_close(fs_dev); + /* Throw out blocks out of the VM cache, to prevent corruption later. */ + lmfs_invalidate(fs_dev); + /* Finish off the unmount. */ superblock.s_dev = NO_DEV; unmountdone = TRUE; diff --git a/servers/mfs/proto.h b/servers/mfs/proto.h index 142c6f125..6d9557692 100644 --- a/servers/mfs/proto.h +++ b/servers/mfs/proto.h @@ -79,7 +79,6 @@ struct buf *get_block_map(register struct inode *rip, u64_t position); zone_t rd_indir(struct buf *bp, int index); /* stadir.c */ -int fs_fstatfs(void); int fs_stat(void); int fs_statvfs(void); diff --git a/servers/mfs/stadir.c b/servers/mfs/stadir.c index 5b8e0236a..0104e3afc 100644 --- a/servers/mfs/stadir.c +++ b/servers/mfs/stadir.c @@ -2,7 +2,6 @@ #include #include #include -#include #include #include "inode.h" #include "super.h" @@ -86,28 +85,6 @@ static int stat_inode( return(r); } -/*===========================================================================* - * fs_fstatfs * - *===========================================================================*/ -int fs_fstatfs() -{ - struct statfs st; - struct inode *rip; - int r; - - if((rip = find_inode(fs_dev, ROOT_INODE)) == NULL) - return(EINVAL); - - st.f_bsize = rip->i_sp->s_block_size; - - /* Copy the struct to user space. */ - r = sys_safecopyto(fs_m_in.m_source, (cp_grant_id_t) fs_m_in.REQ_GRANT, - (vir_bytes) 0, (vir_bytes) &st, (size_t) sizeof(st)); - - return(r); -} - - /*===========================================================================* * fs_statvfs * *===========================================================================*/ @@ -122,16 +99,17 @@ int fs_statvfs() scale = sp->s_log_zone_size; + memset(&st, 0, sizeof(st)); + fs_blockstats((u32_t *) &st.f_blocks, (u32_t *) &st.f_bfree, &used); st.f_bavail = st.f_bfree; st.f_bsize = sp->s_block_size << scale; st.f_frsize = sp->s_block_size; + st.f_iosize = st.f_frsize; st.f_files = sp->s_ninodes; st.f_ffree = count_free_bits(sp, IMAP); st.f_favail = st.f_ffree; - st.f_fsid = fs_dev; - st.f_flag = (sp->s_rd_only == 1 ? ST_RDONLY : 0); st.f_namemax = MFS_DIRSIZ; /* Copy the struct to user space. */ diff --git a/servers/mfs/table.c b/servers/mfs/table.c index 1fb73334e..058aa23d8 100644 --- a/servers/mfs/table.c +++ b/servers/mfs/table.c @@ -23,7 +23,7 @@ int (*fs_call_vec[])(void) = { fs_inhibread, /* 7 */ fs_stat, /* 8 */ fs_utime, /* 9 */ - fs_fstatfs, /* 10 */ + fs_statvfs, /* 10 */ fs_breadwrite, /* 11 */ fs_breadwrite, /* 12 */ fs_unlink, /* 13 */ @@ -45,8 +45,7 @@ int (*fs_call_vec[])(void) = { no_sys, /* 29 */ /* Was: fs_newnode */ fs_rdlink, /* 30 */ fs_getdents, /* 31 */ - fs_statvfs, /* 32 */ - fs_readwrite, /* 33 */ - fs_bpeek, /* 34 */ + fs_readwrite, /* 32 */ + fs_bpeek, /* 33 */ }; diff --git a/servers/pfs/Makefile b/servers/pfs/Makefile index f4b0cb699..ef3d013e9 100644 --- a/servers/pfs/Makefile +++ b/servers/pfs/Makefile @@ -4,8 +4,8 @@ SRCS= open.c table.c inode.c main.c super.c link.c \ buffer.c read.c misc.c mount.c utility.c stadir.c \ uds.c dev_uds.c -DPADD+= ${LIBSYS} -LDADD+= -lsys +DPADD+= ${LIBCHARDRIVER} ${LIBSYS} +LDADD+= -lchardriver -lsys LDADD+= -lc diff --git a/servers/pfs/dev_uds.c b/servers/pfs/dev_uds.c index cada761a5..391b928c6 100644 --- a/servers/pfs/dev_uds.c +++ b/servers/pfs/dev_uds.c @@ -4,25 +4,17 @@ * * The entry points into this file are... * - * uds_open: handles the open(2) syscall on /dev/uds - * uds_close: handles the close(2) syscall on /dev/uds - * uds_select: handles the select(2) syscall on /dev/uds - * uds_read: handles the read(2) syscall on /dev/uds - * uds_write: handles the write(2) syscall on /dev/uds - * uds_ioctl: handles the ioctl(2) syscall on /dev/uds - * uds_status: handles status requests. - * uds_cancel: handles cancelled syscalls. + * uds_request: process a character device request * * Also See... * - * table.c, uds.c, uds.h + * uds.c, uds.h * * Overview * - * The interface to unix domain sockets is similar to the - * the interface to network sockets. There is a character - * device (/dev/uds) that uses STYLE_CLONE and this server - * is a 'driver' for that device. + * The interface to unix domain sockets is similar to the interface to network + * sockets. There is a character device (/dev/uds) and this server is a + * 'driver' for that device. */ #define DEBUG 0 @@ -32,23 +24,50 @@ #include "glo.h" #include "uds.h" -static int uds_perform_read(int minor, endpoint_t m_source, size_t - size, int pretend); -static int uds_perform_write(int minor, endpoint_t m_source, size_t - size, int pretend); +static ssize_t uds_perform_read(devminor_t minor, endpoint_t endpt, + cp_grant_id_t grant, size_t size, int pretend); +static ssize_t uds_perform_write(devminor_t minor, endpoint_t endpt, + cp_grant_id_t grant, size_t size, int pretend); -int uds_open(message *dev_m_in, message *dev_m_out) +static int uds_open(devminor_t orig_minor, int access, endpoint_t user_endpt); +static int uds_close(devminor_t minor); +static ssize_t uds_read(devminor_t minor, u64_t position, endpoint_t endpt, + cp_grant_id_t grant, size_t size, int flags, cdev_id_t id); +static ssize_t uds_write(devminor_t minor, u64_t position, endpoint_t endpt, + cp_grant_id_t grant, size_t size, int flags, cdev_id_t id); +static int uds_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt, + cp_grant_id_t grant, int flags, endpoint_t user_endpt, cdev_id_t id); +static int uds_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id); +static int uds_select(devminor_t minor, unsigned int ops, endpoint_t endpt); + +static struct chardriver uds_tab = { + .cdr_open = uds_open, + .cdr_close = uds_close, + .cdr_read = uds_read, + .cdr_write = uds_write, + .cdr_ioctl = uds_ioctl, + .cdr_cancel = uds_cancel, + .cdr_select = uds_select +}; + +void uds_request(message *m_ptr, int ipc_status) +{ + /* Use libchardriver to process character device requests. */ + chardriver_process(&uds_tab, m_ptr, ipc_status); +} + +static int uds_open(devminor_t UNUSED(orig_minor), int access, + endpoint_t user_endpt) { message fs_m_in, fs_m_out; struct ucred ucred; + devminor_t minor; int rc, i; - int minor; #if DEBUG == 1 static int call_count = 0; - printf("(uds) [%d] uds_open() call_count=%d\n", uds_minor(dev_m_in), - ++call_count); - printf("Endpoint: 0x%x\n", dev_m_in->USER_ENDPT); + printf("(uds) [-] uds_open() call_count=%d\n", ++call_count); + printf("Endpoint: 0x%x\n", user_endpt); #endif /* @@ -68,13 +87,8 @@ int uds_open(message *dev_m_in, message *dev_m_out) } } - if (minor == -1) { - - /* descriptor table full */ - uds_set_reply(dev_m_out, DEV_OPEN_REPL, dev_m_in->USER_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, ENFILE); + if (minor == -1) return ENFILE; - } /* * We found a slot in uds_fd_table, now initialize the descriptor @@ -85,21 +99,12 @@ int uds_open(message *dev_m_in, message *dev_m_out) */ uds_fd_table[minor].state = UDS_INUSE; - /* track the system call we are performing in case it gets cancelled */ - uds_fd_table[minor].call_nr = dev_m_in->m_type; - uds_fd_table[minor].ioctl = 0; - uds_fd_table[minor].syscall_done = 0; - /* set the socket owner */ - uds_fd_table[minor].owner = dev_m_in->USER_ENDPT; - uds_fd_table[minor].endpoint = dev_m_in->USER_ENDPT; + uds_fd_table[minor].owner = user_endpt; /* setup select(2) framework */ - uds_fd_table[minor].selecting = 0; - uds_fd_table[minor].select_proc = 0; - uds_fd_table[minor].sel_ops_in = 0; - uds_fd_table[minor].sel_ops_out = 0; - uds_fd_table[minor].status_updated = 0; + uds_fd_table[minor].sel_endpt = NONE; + uds_fd_table[minor].sel_ops = 0; /* initialize the data pointer (pos) to the start of the PIPE */ uds_fd_table[minor].pos = 0; @@ -151,26 +156,15 @@ int uds_open(message *dev_m_in, message *dev_m_out) /* Initially the socket isn't suspended. */ uds_fd_table[minor].suspended = UDS_NOT_SUSPENDED; - /* and the socket doesn't have an I/O grant initially */ - uds_fd_table[minor].io_gr = (cp_grant_id_t) 0; - - /* since there is no I/O grant it effectively has no size either */ - uds_fd_table[minor].io_gr_size = 0; - - /* The process isn't suspended so we don't flag it as revivable */ - uds_fd_table[minor].ready_to_revive = 0; - /* get the effective user id and effective group id from the endpoint */ /* this is needed in the REQ_NEWNODE request to PFS. */ - rc = getnucred(uds_fd_table[minor].endpoint, &ucred); + rc = getnucred(user_endpt, &ucred); if (rc == -1) { /* roll back the changes we made to the descriptor */ memset(&(uds_fd_table[minor]), '\0', sizeof(uds_fd_t)); /* likely error: invalid endpoint / proc doesn't exist */ - uds_set_reply(dev_m_out, DEV_OPEN_REPL, dev_m_in->USER_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, errno); - return errno; + return EIO; } /* Prepare Request to the FS side of PFS */ @@ -189,52 +183,34 @@ int uds_open(message *dev_m_in, message *dev_m_out) memset(&(uds_fd_table[minor]), '\0', sizeof(uds_fd_t)); /* likely error: get_block() failed */ - uds_set_reply(dev_m_out, DEV_OPEN_REPL, dev_m_in->USER_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, rc); return rc; } /* Process the response */ - uds_fd_table[minor].inode_nr = fs_m_out.RES_INODE_NR; - /* prepare the reply */ - - uds_fd_table[minor].syscall_done = 1; - uds_set_reply(dev_m_out, DEV_OPEN_REPL, dev_m_in->USER_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, minor); - return minor; + return CDEV_CLONED | minor; } -int uds_close(message *dev_m_in, message *dev_m_out) +static int uds_close(devminor_t minor) { - int minor; message fs_m_in, fs_m_out; int rc; #if DEBUG == 1 static int call_count = 0; - printf("(uds) [%d] uds_close() call_count=%d\n", uds_minor(dev_m_in), - ++call_count); - printf("Endpoint: 0x%x\n", dev_m_in->USER_ENDPT); + printf("(uds) [%d] uds_close() call_count=%d\n", minor, ++call_count); #endif - minor = uds_minor(dev_m_in); + if (minor < 0 || minor >= NR_FDS) return ENXIO; if (uds_fd_table[minor].state != UDS_INUSE) { /* attempted to close a socket that hasn't been opened -- * something is very wrong :( */ - uds_set_reply(dev_m_out, DEV_CLOSE_REPL, dev_m_in->USER_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL); return EINVAL; } - /* no need to track the syscall in case of cancellation. close() is - * atomic and can't be cancelled. no need to update the endpoint here, - * we won't be needing it to kill the socket - */ - /* if the socket is connected, disconnect it */ if (uds_fd_table[minor].peer != -1) { int peer = uds_fd_table[minor].peer; @@ -246,14 +222,12 @@ int uds_close(message *dev_m_in, message *dev_m_out) uds_fd_table[peer].err = ECONNRESET; /* if peer was blocked on I/O revive peer */ - if (uds_fd_table[peer].suspended) { - uds_fd_table[peer].ready_to_revive = 1; - uds_unsuspend(dev_m_in->m_source, peer); - } + if (uds_fd_table[peer].suspended != UDS_NOT_SUSPENDED) + uds_unsuspend(peer); } if (uds_fd_table[minor].ancillary_data.nfiledes > 0) { - clear_fds(minor, &(uds_fd_table[minor].ancillary_data)); + uds_clear_fds(minor, &uds_fd_table[minor].ancillary_data); } /* Prepare Request to the FS side of PFS */ @@ -269,90 +243,84 @@ int uds_close(message *dev_m_in, message *dev_m_out) rc = fs_putnode(&fs_m_in, &fs_m_out); if (rc != OK) { - perror("fs_putnode"); - /* likely error: get_block() failed */ + printf("PFS: fs_putnode returned %d\n", rc); + return rc; } - uds_set_reply(dev_m_out, DEV_CLOSE_REPL, dev_m_in->USER_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, OK); return OK; } -int uds_select(message *dev_m_in, message *dev_m_out) +static int uds_select(devminor_t minor, unsigned int ops, endpoint_t endpt) { - int i, bytes; - int minor; + unsigned int ready_ops; + int i, bytes, watch; #if DEBUG == 1 static int call_count = 0; - printf("(uds) [%d] uds_select() call_count=%d\n", uds_minor(dev_m_in), - ++call_count); - printf("Endpoint: 0x%x\n", dev_m_in->USER_ENDPT); + printf("(uds) [%d] uds_select() call_count=%d\n", minor, ++call_count); #endif - minor = uds_minor(dev_m_in); + if (minor < 0 || minor >= NR_FDS) return ENXIO; if (uds_fd_table[minor].state != UDS_INUSE) { - - /* attempted to close a socket that hasn't been opened -- + /* attempted to select on a socket that hasn't been opened -- * something is very wrong :( */ - - uds_sel_reply(dev_m_out, DEV_SEL_REPL1, minor, EINVAL); return EINVAL; } - /* setup select(2) framework */ - uds_fd_table[minor].selecting = 1; - uds_fd_table[minor].select_proc = dev_m_in->m_source; + watch = (ops & CDEV_NOTIFY); + ops &= (CDEV_OP_RD | CDEV_OP_WR | CDEV_OP_ERR); - /* track the system call we are performing in case it gets cancelled */ - uds_fd_table[minor].call_nr = dev_m_in->m_type; - uds_fd_table[minor].ioctl = 0; - uds_fd_table[minor].syscall_done = 0; - - /* Can't update the process endpoint here, no info. */ - - uds_fd_table[minor].sel_ops_in = dev_m_in->USER_ENDPT; - uds_fd_table[minor].sel_ops_out = 0; + ready_ops = 0; /* check if there is data available to read */ - bytes = uds_perform_read(minor, dev_m_in->m_source, 1, 1); - if (bytes > 0) { - - /* there is data in the pipe for us to read */ - uds_fd_table[minor].sel_ops_out |= SEL_RD; - - } else if (uds_fd_table[minor].listening == 1) { - - /* check for pending connections */ - for (i = 0; i < uds_fd_table[minor].backlog_size; i++) { - if (uds_fd_table[minor].backlog[i] != -1) { - uds_fd_table[minor].sel_ops_out |= SEL_RD; - break; + if (ops & CDEV_OP_RD) { + bytes = uds_perform_read(minor, NONE, GRANT_INVALID, 1, 1); + if (bytes > 0) { + /* there is data in the pipe for us to read */ + ready_ops |= CDEV_OP_RD; + } else if (uds_fd_table[minor].listening == 1) { + /* check for pending connections */ + for (i = 0; i < uds_fd_table[minor].backlog_size; i++) + { + if (uds_fd_table[minor].backlog[i] != -1) { + ready_ops |= CDEV_OP_RD; + break; + } } + } else if (bytes != SUSPEND) { + ready_ops |= CDEV_OP_RD; } - } else if (bytes != SUSPEND) { - uds_fd_table[minor].sel_ops_out |= SEL_RD; } /* check if we can write without blocking */ - bytes = uds_perform_write(minor, dev_m_in->m_source, PIPE_BUF, 1); - if (bytes != 0 && bytes != SUSPEND) { - /* There is room to write or there is an error condition */ - uds_fd_table[minor].sel_ops_out |= SEL_WR; + if (ops & CDEV_OP_WR) { + bytes = uds_perform_write(minor, NONE, GRANT_INVALID, PIPE_BUF, + 1); + if (bytes != 0 && bytes != SUSPEND) { + /* There is room to write or there is an error + * condition. + */ + ready_ops |= CDEV_OP_WR; + } } - uds_fd_table[minor].syscall_done = 1; - uds_sel_reply(dev_m_out, DEV_SEL_REPL1, minor, - uds_fd_table[minor].sel_ops_out); + /* If not all requested ops were ready, and the caller requests to be + * notified about changes, we add the remaining ops to the saved set. + */ + ops &= ~ready_ops; + if (ops && watch) { + uds_fd_table[minor].sel_endpt = endpt; + uds_fd_table[minor].sel_ops |= ops; + } - return uds_fd_table[minor].sel_ops_out; + return ready_ops; } -static int uds_perform_read(int minor, endpoint_t m_source, - size_t size, int pretend) +static ssize_t uds_perform_read(devminor_t minor, endpoint_t endpt, + cp_grant_id_t grant, size_t size, int pretend) { int rc, peer; message fs_m_in; @@ -366,20 +334,18 @@ static int uds_perform_read(int minor, endpoint_t m_source, peer = uds_fd_table[minor].peer; + /* skip reads and writes of 0 (or less!) bytes */ if (size <= 0) { return 0; } /* check if we are allowed to read */ if (!(uds_fd_table[minor].mode & S_IRUSR)) { - /* socket is shutdown for reading */ return EPIPE; } - /* skip reads and writes of 0 (or less!) bytes */ if (uds_fd_table[minor].size == 0) { - if (peer == -1) { /* We're not connected. That's only a problem when this * socket is connection oriented. */ @@ -400,7 +366,6 @@ static int uds_perform_read(int minor, endpoint_t m_source, return 0; } - if (pretend) { return SUSPEND; } @@ -408,10 +373,9 @@ static int uds_perform_read(int minor, endpoint_t m_source, /* maybe a process is blocked waiting to write? if * needed revive the writer */ - if (peer != -1 && uds_fd_table[peer].suspended) { - uds_fd_table[peer].ready_to_revive = 1; - uds_unsuspend(m_source, peer); - } + if (peer != -1 && + uds_fd_table[peer].suspended == UDS_SUSPENDED_WRITE) + uds_unsuspend(peer); #if DEBUG == 1 printf("(uds) [%d] suspending read request\n", minor); @@ -419,21 +383,19 @@ static int uds_perform_read(int minor, endpoint_t m_source, /* Process is reading from an empty pipe, * suspend it so some bytes can be written */ - uds_fd_table[minor].suspended = UDS_SUSPENDED_READ; - return SUSPEND; + return EDONTREPLY; } if (pretend) { - return (size > uds_fd_table[minor].size) ? uds_fd_table[minor].size : size; } - /* Prepare Request to the FS side of PFS */ + fs_m_in.m_source = endpt; fs_m_in.m_type = REQ_READ; fs_m_in.REQ_INODE_NR = uds_fd_table[minor].inode_nr; - fs_m_in.REQ_GRANT = uds_fd_table[minor].io_gr; + fs_m_in.REQ_GRANT = grant; fs_m_in.REQ_SEEK_POS_HI = 0; fs_m_in.REQ_SEEK_POS_LO = uds_fd_table[minor].pos; fs_m_in.REQ_NBYTES = (size > uds_fd_table[minor].size) ? @@ -442,7 +404,7 @@ static int uds_perform_read(int minor, endpoint_t m_source, /* perform the read */ rc = fs_readwrite(&fs_m_in, &fs_m_out); if (rc != OK) { - perror("fs_readwrite"); + printf("PFS: fs_readwrite returned %d\n", rc); return rc; } @@ -469,35 +431,26 @@ static int uds_perform_read(int minor, endpoint_t m_source, /* maybe a big write was waiting for us to read some data, if * needed revive the writer */ - if (peer != -1 && uds_fd_table[peer].suspended) { - uds_fd_table[peer].ready_to_revive = 1; - uds_unsuspend(m_source, peer); - } + if (peer != -1 && uds_fd_table[peer].suspended == UDS_SUSPENDED_WRITE) + uds_unsuspend(peer); - /* see if peer is blocked on select() and a write is possible - * (from peer to minor) + /* see if peer is blocked on select() and a write is possible (from + * peer to minor); if the peer wants to know about write being possible + * and it doesn't know about it already, then let the peer know. */ - if (peer != -1 && uds_fd_table[peer].selecting == 1 && + if (peer != -1 && (uds_fd_table[peer].sel_ops & CDEV_OP_WR) && (uds_fd_table[minor].size+uds_fd_table[minor].pos + 1 < PIPE_BUF)){ - - /* if the peer wants to know about write being possible - * and it doesn't know about it already, then let the peer know. - */ - if (peer != -1 && (uds_fd_table[peer].sel_ops_in & SEL_WR) && - !(uds_fd_table[peer].sel_ops_out & SEL_WR)) { - - /* a write on peer is possible now */ - uds_fd_table[peer].sel_ops_out |= SEL_WR; - uds_fd_table[peer].status_updated = 1; - uds_unsuspend(m_source, peer); - } + /* a write on peer is possible now */ + chardriver_reply_select(uds_fd_table[peer].sel_endpt, peer, + CDEV_OP_WR); + uds_fd_table[peer].sel_ops &= ~CDEV_OP_WR; } return fs_m_out.RES_NBYTES; /* return number of bytes read */ } -static int uds_perform_write(int minor, endpoint_t m_source, - size_t size, int pretend) +static ssize_t uds_perform_write(devminor_t minor, endpoint_t endpt, + cp_grant_id_t grant, size_t size, int pretend) { int rc, peer, i; message fs_m_in; @@ -516,20 +469,17 @@ static int uds_perform_write(int minor, endpoint_t m_source, /* check if we are allowed to write */ if (!(uds_fd_table[minor].mode & S_IWUSR)) { - /* socket is shutdown for writing */ return EPIPE; } if (size > PIPE_BUF) { - /* message is too big to ever write to the PIPE */ return EMSGSIZE; } if (uds_fd_table[minor].type == SOCK_STREAM || uds_fd_table[minor].type == SOCK_SEQPACKET) { - /* if we're writing with a connection oriented socket, * then it needs a peer to write to */ @@ -542,12 +492,9 @@ static int uds_perform_write(int minor, endpoint_t m_source, return ENOTCONN; } } else { - peer = uds_fd_table[minor].peer; } - } else /* uds_fd_table[minor].type == SOCK_DGRAM */ { - peer = -1; /* locate the "peer" we want to write to */ @@ -601,10 +548,8 @@ static int uds_perform_write(int minor, endpoint_t m_source, } /* if needed revive the reader */ - if (uds_fd_table[peer].suspended) { - uds_fd_table[peer].ready_to_revive = 1; - uds_unsuspend(m_source, peer); - } + if (uds_fd_table[peer].suspended == UDS_SUSPENDED_READ) + uds_unsuspend(peer); #if DEBUG == 1 printf("(uds) [%d] suspending write request\n", minor); @@ -613,8 +558,7 @@ static int uds_perform_write(int minor, endpoint_t m_source, /* Process is reading from an empty pipe, * suspend it so some bytes can be written */ - uds_fd_table[minor].suspended = UDS_SUSPENDED_WRITE; - return SUSPEND; + return EDONTREPLY; } if (pretend) { @@ -622,9 +566,10 @@ static int uds_perform_write(int minor, endpoint_t m_source, } /* Prepare Request to the FS side of PFS */ + fs_m_in.m_source = endpt; fs_m_in.m_type = REQ_WRITE; fs_m_in.REQ_INODE_NR = uds_fd_table[peer].inode_nr; - fs_m_in.REQ_GRANT = uds_fd_table[minor].io_gr; + fs_m_in.REQ_GRANT = grant; fs_m_in.REQ_SEEK_POS_HI = 0; fs_m_in.REQ_SEEK_POS_LO = uds_fd_table[peer].pos + uds_fd_table[peer].size; @@ -633,7 +578,7 @@ static int uds_perform_write(int minor, endpoint_t m_source, /* Request the write */ rc = fs_readwrite(&fs_m_in, &fs_m_out); if (rc != OK) { - perror("fs_readwrite"); + printf("PFS: fs_readwrite returned %d\n", rc); return rc; } @@ -644,7 +589,6 @@ static int uds_perform_write(int minor, endpoint_t m_source, /* increase the count of unread bytes */ uds_fd_table[peer].size += fs_m_out.RES_NBYTES; - /* fill in the source address to be returned by recvfrom & recvmsg */ if (uds_fd_table[minor].type == SOCK_DGRAM) { memcpy(&uds_fd_table[peer].source, &uds_fd_table[minor].addr, @@ -652,541 +596,270 @@ static int uds_perform_write(int minor, endpoint_t m_source, } /* revive peer that was waiting for us to write */ - if (uds_fd_table[peer].suspended) { - uds_fd_table[peer].ready_to_revive = 1; - uds_unsuspend(m_source, peer); - } + if (uds_fd_table[peer].suspended == UDS_SUSPENDED_READ) + uds_unsuspend(peer); - /* see if peer is blocked on select()*/ - if (uds_fd_table[peer].selecting == 1 && fs_m_out.RES_NBYTES > 0) { - - /* if the peer wants to know about data ready to read - * and it doesn't know about it already, then let the peer - * know we have data for it. - */ - if ((uds_fd_table[peer].sel_ops_in & SEL_RD) && - !(uds_fd_table[peer].sel_ops_out & SEL_RD)) { - - /* a read on peer is possible now */ - uds_fd_table[peer].sel_ops_out |= SEL_RD; - uds_fd_table[peer].status_updated = 1; - uds_unsuspend(m_source, peer); - } + /* see if peer is blocked on select(); if the peer wants to know about + * data ready to read and it doesn't know about it already, then let + * the peer know we have data for it. + */ + if ((uds_fd_table[peer].sel_ops & CDEV_OP_RD) && + fs_m_out.RES_NBYTES > 0) { + /* a read on peer is possible now */ + chardriver_reply_select(uds_fd_table[peer].sel_endpt, peer, + CDEV_OP_RD); + uds_fd_table[peer].sel_ops &= ~CDEV_OP_RD; } return fs_m_out.RES_NBYTES; /* return number of bytes written */ } -int uds_read(message *dev_m_in, message *dev_m_out) +static ssize_t uds_read(devminor_t minor, u64_t position, endpoint_t endpt, + cp_grant_id_t grant, size_t size, int flags, cdev_id_t id) { - int bytes; - int minor; + ssize_t rc; #if DEBUG == 1 static int call_count = 0; - printf("(uds) [%d] uds_read() call_count=%d\n", uds_minor(dev_m_in), - ++call_count); - printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in->USER_ENDPT, - dev_m_in->POSITION); + printf("(uds) [%d] uds_read() call_count=%d\n", minor, ++call_count); #endif - minor = uds_minor(dev_m_in); + if (minor < 0 || minor >= NR_FDS) return ENXIO; if (uds_fd_table[minor].state != UDS_INUSE) { - - /* attempted to close a socket that hasn't been opened -- + /* attempted to read from a socket that hasn't been opened -- * something is very wrong :( */ - uds_set_reply(dev_m_out, DEV_REVIVE, dev_m_in->USER_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL); - return EINVAL; } - /* track the system call we are performing in case it gets cancelled */ - uds_fd_table[minor].call_nr = dev_m_in->m_type; - uds_fd_table[minor].ioctl = 0; - uds_fd_table[minor].syscall_done = 0; + rc = uds_perform_read(minor, endpt, grant, size, 0); - /* Update the process endpoint. */ - uds_fd_table[minor].endpoint = dev_m_in->USER_ENDPT; + /* If the call couldn't complete, suspend the caller. */ + if (rc == EDONTREPLY) { + uds_fd_table[minor].suspended = UDS_SUSPENDED_READ; + uds_fd_table[minor].susp_endpt = endpt; + uds_fd_table[minor].susp_grant = grant; + uds_fd_table[minor].susp_size = size; + uds_fd_table[minor].susp_id = id; - /* setup select(2) framework */ - uds_fd_table[minor].selecting = 0; + /* If the call wasn't supposed to block, cancel immediately. */ + if (flags & CDEV_NONBLOCK) { + uds_cancel(minor, endpt, id); - /* save I/O Grant info */ - uds_fd_table[minor].io_gr = (cp_grant_id_t) dev_m_in->IO_GRANT; - uds_fd_table[minor].io_gr_size = dev_m_in->COUNT; - - bytes = uds_perform_read(minor, dev_m_in->m_source, - uds_fd_table[minor].io_gr_size, 0); - - uds_set_reply(dev_m_out, DEV_REVIVE, uds_fd_table[minor].endpoint, - uds_fd_table[minor].io_gr, bytes); - - return bytes; -} - -int uds_write(message *dev_m_in, message *dev_m_out) -{ - int bytes; - int minor; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] uds_write() call_count=%d\n", uds_minor(dev_m_in), - ++call_count); - printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in->USER_ENDPT, - dev_m_in->POSITION); -#endif - - minor = uds_minor(dev_m_in); - - if (uds_fd_table[minor].state != UDS_INUSE) { - - /* attempted to write to a socket that hasn't been opened -- - * something is very wrong :( - */ - uds_set_reply(dev_m_out, DEV_REVIVE, dev_m_in->USER_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL); - - return EINVAL; + rc = EAGAIN; + } } - /* track the system call we are performing in case it gets cancelled */ - uds_fd_table[minor].call_nr = dev_m_in->m_type; - uds_fd_table[minor].ioctl = 0; - uds_fd_table[minor].syscall_done = 0; - - /* Update the process endpoint. */ - uds_fd_table[minor].endpoint = dev_m_in->USER_ENDPT; - - /* setup select(2) framework */ - uds_fd_table[minor].selecting = 0; - - /* save I/O Grant info */ - uds_fd_table[minor].io_gr = (cp_grant_id_t) dev_m_in->IO_GRANT; - uds_fd_table[minor].io_gr_size = dev_m_in->COUNT; - - bytes = uds_perform_write(minor, dev_m_in->m_source, - uds_fd_table[minor].io_gr_size, 0); - - uds_set_reply(dev_m_out, DEV_REVIVE, uds_fd_table[minor].endpoint, - uds_fd_table[minor].io_gr, bytes); - - return bytes; -} - -int uds_ioctl(message *dev_m_in, message *dev_m_out) -{ - int rc, minor; - -#if DEBUG == 1 - static int call_count = 0; - printf("(uds) [%d] uds_ioctl() call_count=%d\n", uds_minor(dev_m_in), - ++call_count); - printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in->USER_ENDPT, - dev_m_in->POSITION); -#endif - - minor = uds_minor(dev_m_in); - - if (uds_fd_table[minor].state != UDS_INUSE) { - - /* attempted to close a socket that hasn't been opened -- - * something is very wrong :( - */ - uds_set_reply(dev_m_out, DEV_REVIVE, dev_m_in->USER_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL); - - return EINVAL; - } - - /* track the system call we are performing in case it gets cancelled */ - uds_fd_table[minor].call_nr = dev_m_in->m_type; - uds_fd_table[minor].ioctl = dev_m_in->COUNT; - uds_fd_table[minor].syscall_done = 0; - - /* setup select(2) framework */ - uds_fd_table[minor].selecting = 0; - - /* update the owner endpoint - yes it's really stored in POSITION */ - uds_fd_table[minor].owner = dev_m_in->POSITION; - - switch (dev_m_in->COUNT) { /* Handle the ioctl(2) command */ - - case NWIOSUDSCONN: - - /* connect to a listening socket -- connect() */ - rc = do_connect(dev_m_in, dev_m_out); - - break; - - case NWIOSUDSACCEPT: - - /* accept an incoming connection -- accept() */ - rc = do_accept(dev_m_in, dev_m_out); - - break; - - case NWIOSUDSBLOG: - - /* set the backlog_size and put the socket into the - * listening state -- listen() - */ - rc = do_listen(dev_m_in, dev_m_out); - - break; - - case NWIOSUDSTYPE: - - /* set the type for this socket (i.e. - * SOCK_STREAM, SOCK_DGRAM, etc) -- socket() - */ - rc = do_socket(dev_m_in, dev_m_out); - - break; - - case NWIOSUDSADDR: - - /* set the address for this socket -- bind() */ - rc = do_bind(dev_m_in, dev_m_out); - - break; - - case NWIOGUDSADDR: - - /* get the address for this socket -- getsockname() */ - rc = do_getsockname(dev_m_in, dev_m_out); - - break; - - case NWIOGUDSPADDR: - - /* get the address for the peer -- getpeername() */ - rc = do_getpeername(dev_m_in, dev_m_out); - - break; - - case NWIOSUDSSHUT: - - /* shutdown a socket for reading, writing, or - * both -- shutdown() - */ - rc = do_shutdown(dev_m_in, dev_m_out); - - break; - - case NWIOSUDSPAIR: - - /* connect two sockets -- socketpair() */ - rc = do_socketpair(dev_m_in, dev_m_out); - - break; - - case NWIOGUDSSOTYPE: - - /* get socket type -- getsockopt(SO_TYPE) */ - rc = do_getsockopt_sotype(dev_m_in, dev_m_out); - - break; - - case NWIOGUDSPEERCRED: - - /* get peer endpoint -- getsockopt(SO_PEERCRED) */ - rc = do_getsockopt_peercred(dev_m_in, dev_m_out); - - break; - - case NWIOSUDSTADDR: - - /* set target address -- sendto() */ - rc = do_sendto(dev_m_in, dev_m_out); - - break; - - case NWIOGUDSFADDR: - - /* get from address -- recvfrom() */ - rc = do_recvfrom(dev_m_in, dev_m_out); - - break; - - case NWIOGUDSSNDBUF: - - /* get the send buffer size -- getsockopt(SO_SNDBUF) */ - rc = do_getsockopt_sndbuf(dev_m_in, dev_m_out); - - break; - - case NWIOSUDSSNDBUF: - - /* set the send buffer size -- setsockopt(SO_SNDBUF) */ - rc = do_setsockopt_sndbuf(dev_m_in, dev_m_out); - - break; - - case NWIOGUDSRCVBUF: - - /* get the send buffer size -- getsockopt(SO_SNDBUF) */ - rc = do_getsockopt_rcvbuf(dev_m_in, dev_m_out); - - break; - - case NWIOSUDSRCVBUF: - - /* set the send buffer size -- setsockopt(SO_SNDBUF) */ - rc = do_setsockopt_rcvbuf(dev_m_in, dev_m_out); - - break; - - case NWIOSUDSCTRL: - - /* set the control data -- sendmsg() */ - rc = do_sendmsg(dev_m_in, dev_m_out); - - break; - - case NWIOGUDSCTRL: - - /* set the control data -- recvmsg() */ - rc = do_recvmsg(dev_m_in, dev_m_out); - - break; - - default: - - /* the IOCTL command is not valid for /dev/uds -- - * this happens a lot and is normal. a lot of - * libc functions determine the socket type with - * IOCTLs. Any not for us simply get a EBADIOCTL - * response. - */ - - rc = EBADIOCTL; - } - - if (rc != SUSPEND) - uds_fd_table[minor].syscall_done = 1; - - uds_set_reply(dev_m_out, DEV_REVIVE, dev_m_in->USER_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, rc); - return rc; } -int uds_unsuspend(endpoint_t m_source, int minor) +static ssize_t uds_write(devminor_t minor, u64_t position, endpoint_t endpt, + cp_grant_id_t grant, size_t size, int flags, cdev_id_t id) { - int r = OK, bytes; - message m_out; + ssize_t rc; + +#if DEBUG == 1 + static int call_count = 0; + printf("(uds) [%d] uds_write() call_count=%d\n", minor, ++call_count); +#endif + + if (minor < 0 || minor >= NR_FDS) return ENXIO; + + if (uds_fd_table[minor].state != UDS_INUSE) { + /* attempted to write to a socket that hasn't been opened -- + * something is very wrong :( + */ + return EINVAL; + } + + rc = uds_perform_write(minor, endpt, grant, size, 0); + + /* If the call couldn't complete, suspend the caller. */ + if (rc == EDONTREPLY) { + uds_fd_table[minor].suspended = UDS_SUSPENDED_WRITE; + uds_fd_table[minor].susp_endpt = endpt; + uds_fd_table[minor].susp_grant = grant; + uds_fd_table[minor].susp_size = size; + uds_fd_table[minor].susp_id = id; + + /* If the call wasn't supposed to block, cancel immediately. */ + if (flags & CDEV_NONBLOCK) { + uds_cancel(minor, endpt, id); + + rc = EAGAIN; + } + } + + return rc; +} + +static int uds_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt, + cp_grant_id_t grant, int flags, endpoint_t user_endpt, cdev_id_t id) +{ + int rc; + +#if DEBUG == 1 + static int call_count = 0; + printf("(uds) [%d] uds_ioctl() call_count=%d\n", minor, ++call_count); +#endif + + if (minor < 0 || minor >= NR_FDS) return ENXIO; + + if (uds_fd_table[minor].state != UDS_INUSE) { + /* attempted to perform I/O control on a socket that hasn't + * been opened -- something is very wrong :( + */ + return EINVAL; + } + + /* update the owner endpoint */ + uds_fd_table[minor].owner = user_endpt; + + /* let the UDS subsystem handle the actual request */ + rc = uds_do_ioctl(minor, request, endpt, grant); + + /* If the call couldn't complete, suspend the caller. */ + if (rc == EDONTREPLY) { + /* The suspension type is already set by the IOCTL handler. */ + if (uds_fd_table[minor].suspended == UDS_NOT_SUSPENDED) + panic("IOCTL did not actually suspend?"); + uds_fd_table[minor].susp_endpt = endpt; + uds_fd_table[minor].susp_grant = grant; + uds_fd_table[minor].susp_size = 0; /* irrelevant */ + uds_fd_table[minor].susp_id = id; + + /* If the call wasn't supposed to block, cancel immediately. */ + if (flags & CDEV_NONBLOCK) { + uds_cancel(minor, endpt, id); + + rc = EAGAIN; + } + } + + return rc; +} + +void uds_unsuspend(devminor_t minor) +{ + int r; uds_fd_t *fdp; fdp = &uds_fd_table[minor]; - if (fdp->status_updated == 1) { + switch (fdp->suspended) { + case UDS_SUSPENDED_READ: + r = uds_perform_read(minor, fdp->susp_endpt, fdp->susp_grant, + fdp->susp_size, 0); - /* clear the status_updated flag */ - fdp->status_updated = 0; - fdp->selecting = 0; + if (r == EDONTREPLY) + return; - /* prepare the response */ - uds_sel_reply(&m_out, DEV_SEL_REPL2, minor, fdp->sel_ops_out); - } else if (fdp->ready_to_revive == 1) { + break; - /* clear the ready to revive flag */ - fdp->ready_to_revive = 0; + case UDS_SUSPENDED_WRITE: + r = uds_perform_write(minor, fdp->susp_endpt, fdp->susp_grant, + fdp->susp_size, 0); - switch (fdp->suspended) { + if (r == EDONTREPLY) + return; - case UDS_SUSPENDED_READ: + break; - bytes = uds_perform_read(minor, m_source, - fdp->io_gr_size, 0); + case UDS_SUSPENDED_CONNECT: + case UDS_SUSPENDED_ACCEPT: + /* In both cases, the caller already set up the connection. + * The only thing to do here is unblock. + */ + r = OK; - if (bytes == SUSPEND) { - r = SUSPEND; - break; - } - - fdp->suspended = UDS_NOT_SUSPENDED; - - uds_set_reply(&m_out, DEV_REVIVE, fdp->endpoint, - fdp->io_gr, bytes); - - break; - - case UDS_SUSPENDED_WRITE: - - bytes = uds_perform_write(minor, m_source, - fdp->io_gr_size, 0); - - if (bytes == SUSPEND) { - r = SUSPEND; - break; - } - - fdp->suspended = UDS_NOT_SUSPENDED; - - uds_set_reply(&m_out, DEV_REVIVE, fdp->endpoint, - fdp->io_gr, bytes); - - break; - - case UDS_SUSPENDED_CONNECT: - case UDS_SUSPENDED_ACCEPT: - - /* In both cases, the process - * that send the notify() - * already performed the connection. - * The only thing to do here is - * unblock. - */ - - fdp->suspended = UDS_NOT_SUSPENDED; - - uds_set_reply(&m_out, DEV_REVIVE, fdp->endpoint, - fdp->io_gr, OK); - - break; - - default: - return(OK); - } + break; + default: + panic("unknown suspension type %d", fdp->suspended); } - if (r == OK) reply(m_source, &m_out); - return(r); + chardriver_reply_task(fdp->susp_endpt, fdp->susp_id, r); + + fdp->suspended = UDS_NOT_SUSPENDED; } -int uds_cancel(message *dev_m_in, message *dev_m_out) +static int uds_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id) { + uds_fd_t *fdp; int i, j; - int minor; - /* XXX: should become a noop? */ + #if DEBUG == 1 static int call_count = 0; - printf("(uds) [%d] uds_cancel() call_count=%d\n", uds_minor(dev_m_in), - ++call_count); - printf("Endpoint: 0x%x\n", dev_m_in->USER_ENDPT); + printf("(uds) [%d] uds_cancel() call_count=%d\n", minor, ++call_count); #endif - minor = uds_minor(dev_m_in); + if (minor < 0 || minor >= NR_FDS) return EDONTREPLY; - if (uds_fd_table[minor].state != UDS_INUSE) { + fdp = &uds_fd_table[minor]; - /* attempted to close a socket that hasn't been opened -- - * something is very wrong :( - */ - uds_set_reply(dev_m_out, DEV_NO_STATUS, dev_m_in->USER_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL); - - return EINVAL; + if (fdp->state != UDS_INUSE) { + printf("PFS: cancel request for closed minor %d\n", minor); + return EDONTREPLY; } - /* Update the process endpoint. */ - uds_fd_table[minor].endpoint = dev_m_in->USER_ENDPT; + /* Make sure the cancel request is for a request we're hanging on. */ + if (fdp->suspended == UDS_NOT_SUSPENDED || fdp->susp_endpt != endpt || + fdp->susp_id != id) { + return EDONTREPLY; /* this happens. */ + } - /* setup select(2) framework */ - uds_fd_table[minor].selecting = 0; - - /* the system call was cancelled, so if the socket was suspended - * (which is likely the case), then it is not suspended anymore. + /* The system call was cancelled, so the socket is not suspended + * anymore. */ - uds_fd_table[minor].suspended = UDS_NOT_SUSPENDED; + switch (fdp->suspended) { + case UDS_SUSPENDED_ACCEPT: /* accept() */ + /* partial accept() only changes + * uds_fd_table[minorparent].child + */ + for (i = 0; i < NR_FDS; i++) { + if (uds_fd_table[i].child == minor) { + uds_fd_table[i].child = -1; + } + } - /* If there is a system call and it isn't complete, roll back */ - if (uds_fd_table[minor].call_nr && !uds_fd_table[minor].syscall_done) { + break; + case UDS_SUSPENDED_CONNECT: /* connect() */ + /* partial connect() sets addr and adds minor to server backlog + */ - if (uds_fd_table[minor].call_nr == DEV_IOCTL_S) { + for (i = 0; i < NR_FDS; i++) { + /* find a socket that is in use. */ + if (uds_fd_table[i].state != UDS_INUSE) + continue; - switch (uds_fd_table[minor].ioctl) { - - case NWIOSUDSACCEPT: /* accept() */ - - /* partial accept() only changes - * uds_fd_table[minorparent].child - */ - - for (i = 0; i < NR_FDS; i++) { - if (uds_fd_table[i].child == - minor) { - - uds_fd_table[i].child = -1; - - } - } - - break; - - case NWIOSUDSCONN: /* connect() */ - - /* partial connect() sets addr - * and adds minor to server backlog - */ - - for (i = 0; i < NR_FDS; i++) { - - /* find a socket that is in - * use. - */ - if (uds_fd_table[i].state == - UDS_INUSE) { - - /* see if minor is in - * the backlog - */ + /* see if minor is in the backlog */ for (j = 0; j < uds_fd_table[i].backlog_size; j++) { - if (uds_fd_table[i].backlog[j] == minor) { /* remove from backlog */ uds_fd_table[i].backlog[j] = -1; } } - - } - } - - /* clear the address */ - memset(&(uds_fd_table[minor].addr), - '\0', - sizeof(struct sockaddr_un)); - - break; - - case NWIOSUDSTADDR: /* sendto() */ - case NWIOSUDSADDR: /* bind() */ - case NWIOGUDSADDR: /* getsockname() */ - case NWIOGUDSPADDR: /* getpeername() */ - case NWIOSUDSTYPE: /* socket() */ - case NWIOSUDSBLOG: /* listen() */ - case NWIOSUDSSHUT: /* shutdown() */ - case NWIOSUDSPAIR: /* socketpair() */ - case NWIOGUDSSOTYPE: /* SO_TYPE */ - case NWIOGUDSPEERCRED: /* SO_PEERCRED */ - default: - /* these are atomic, never suspend, - * and can't be cancelled once called - */ - break; - } - } - /* DEV_READ_S or DEV_WRITE_S don't need to do anything - * when cancelled. DEV_OPEN, DEV_REOPEN, DEV_SELECT, - * DEV_CLOSE are atomic, never suspend, and can't - * be cancelled once called. - */ + /* clear the address */ + memset(&(uds_fd_table[minor].addr), '\0', + sizeof(struct sockaddr_un)); - uds_fd_table[minor].syscall_done = 1; + break; + + case UDS_SUSPENDED_READ: + case UDS_SUSPENDED_WRITE: + /* Nothing more to do. */ + break; + + default: + panic("unknown suspension type %d", fdp->suspended); } + fdp->suspended = UDS_NOT_SUSPENDED; - uds_set_reply(dev_m_out, DEV_NO_STATUS, dev_m_in->USER_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, EINTR); - - return EINTR; + return EINTR; /* reply to the original request */ } diff --git a/servers/pfs/glo.h b/servers/pfs/glo.h index fd0db9075..96ca9c42e 100644 --- a/servers/pfs/glo.h +++ b/servers/pfs/glo.h @@ -13,12 +13,7 @@ EXTERN int err_code; /* temporary storage for error number */ EXTERN int(*fs_call_vec[]) (message *fs_m_in, message *fs_m_out); -EXTERN int(*dev_call_vec[]) (message *fs_m_in, message *fs_m_out); -EXTERN uid_t caller_uid; -EXTERN gid_t caller_gid; -EXTERN int req_nr; -EXTERN int SELF_E; EXTERN int exitsignaled; EXTERN int busy; EXTERN int unmountdone; diff --git a/servers/pfs/inode.c b/servers/pfs/inode.c index b6a508649..8ab0ac22f 100644 --- a/servers/pfs/inode.c +++ b/servers/pfs/inode.c @@ -238,7 +238,7 @@ struct inode *rip; /* pointer to inode to be released */ /*===========================================================================* * alloc_inode * *===========================================================================*/ -struct inode *alloc_inode(dev_t dev, mode_t bits) +struct inode *alloc_inode(dev_t dev, mode_t bits, uid_t uid, gid_t gid) { /* Allocate a free inode on 'dev', and return a pointer to it. */ @@ -268,8 +268,8 @@ struct inode *alloc_inode(dev_t dev, mode_t bits) rip->i_mode = bits; /* set up RWX bits */ rip->i_nlinks = NO_LINK; /* initial no links */ - rip->i_uid = caller_uid; /* file's uid is owner's */ - rip->i_gid = caller_gid; /* ditto group id */ + rip->i_uid = uid; /* set file user id */ + rip->i_gid = gid; /* ditto group id */ /* Fields not cleared already are cleared in wipe_inode(). They have * been put there because truncate() needs to clear the same fields if diff --git a/servers/pfs/main.c b/servers/pfs/main.c index f88fe0cb2..b605b092b 100644 --- a/servers/pfs/main.c +++ b/servers/pfs/main.c @@ -12,7 +12,7 @@ #include "inode.h" #include "uds.h" -static void get_work(message *m_in); +static void get_work(message *m_in, int *status); /* SEF functions and variables. */ static void sef_local_startup(void); @@ -28,20 +28,25 @@ int main(int argc, char *argv[]) * three major activities: getting new work, processing the work, and * sending the reply. The loop never terminates, unless a panic occurs. */ - int ind, do_reply, transid; + int ind, transid, req_nr, ipc_status; message pfs_m_in; message pfs_m_out; + endpoint_t src; /* SEF local startup. */ env_setargs(argc, argv); sef_local_startup(); while(!unmountdone || !exitsignaled) { - endpoint_t src; - - do_reply = 1; /* Wait for request message. */ - get_work(&pfs_m_in); + get_work(&pfs_m_in, &ipc_status); + + /* If this is a UDS device request, process it and continue. */ + if (IS_CDEV_RQ(pfs_m_in.m_type)) { + uds_request(&pfs_m_in, ipc_status); + + continue; + } transid = TRNS_GET_ID(pfs_m_in.m_type); pfs_m_in.m_type = TRNS_DEL_ID(pfs_m_in.m_type); @@ -53,25 +58,9 @@ int main(int argc, char *argv[]) assert(IS_VFS_FS_TRANSID(transid) || transid == 0); src = pfs_m_in.m_source; - caller_uid = INVAL_UID; /* To trap errors */ - caller_gid = INVAL_GID; req_nr = pfs_m_in.m_type; - if (IS_DEV_RQ(req_nr)) { - ind = req_nr - DEV_RQ_BASE; - if (ind < 0 || ind >= DEV_CALL_VEC_SIZE) { - printf("pfs: bad DEV request %d\n", req_nr); - pfs_m_out.m_type = EINVAL; - } else { - int result; - result = (*dev_call_vec[ind])(&pfs_m_in, &pfs_m_out); - if (pfs_m_out.REP_STATUS == SUSPEND || - result == SUSPEND) { - /* Nothing to tell, so not replying */ - do_reply = 0; - } - } - } else if (IS_VFS_RQ(req_nr)) { + if (IS_VFS_RQ(req_nr)) { ind = req_nr - VFS_BASE; if (ind < 0 || ind >= FS_CALL_VEC_SIZE) { printf("pfs: bad FS request %d\n", req_nr); @@ -85,13 +74,10 @@ int main(int argc, char *argv[]) pfs_m_out.m_type = EINVAL; } - if (do_reply) { - if (IS_VFS_RQ(req_nr) && IS_VFS_FS_TRANSID(transid)) { - pfs_m_out.m_type = TRNS_ADD_ID(pfs_m_out.m_type, - transid); - } - reply(src, &pfs_m_out); + if (IS_VFS_RQ(req_nr) && IS_VFS_FS_TRANSID(transid)) { + pfs_m_out.m_type = TRNS_ADD_ID(pfs_m_out.m_type, transid); } + reply(src, &pfs_m_out); } return(OK); } @@ -145,8 +131,6 @@ static int sef_cb_init_fresh(int type, sef_init_info_t *info) panic("unable to drop privileges"); } - SELF_E = getprocnr(); - return(OK); } @@ -165,15 +149,14 @@ static void sef_cb_signal_handler(int signo) /*===========================================================================* * get_work * *===========================================================================*/ -static void get_work(m_in) -message *m_in; /* pointer to message */ +static void get_work(message * m_in, int *status) { - int r, srcok = 0, status; + int r, srcok = 0; endpoint_t src; do { /* wait for a message */ - if ((r = sef_receive_status(ANY, m_in, &status)) != OK) + if ((r = sef_receive_status(ANY, m_in, status)) != OK) panic("sef_receive_status failed: %d", r); src = m_in->m_source; @@ -192,6 +175,8 @@ void reply(who, m_out) endpoint_t who; message *m_out; /* report result */ { - if (OK != send(who, m_out)) /* send the message */ - printf("PFS(%d) was unable to send reply\n", SELF_E); + int r; + + if (OK != (r = send(who, m_out))) /* send the message */ + printf("PFS: unable to send reply: %d\n", r); } diff --git a/servers/pfs/open.c b/servers/pfs/open.c index 72ab0b5df..4c7e17d25 100644 --- a/servers/pfs/open.c +++ b/servers/pfs/open.c @@ -13,15 +13,17 @@ int fs_newnode(message *fs_m_in, message *fs_m_out) register int r = OK; mode_t bits; struct inode *rip; + uid_t uid; + gid_t gid; dev_t dev; - caller_uid = (uid_t) fs_m_in->REQ_UID; - caller_gid = (gid_t) fs_m_in->REQ_GID; + uid = (uid_t) fs_m_in->REQ_UID; + gid = (gid_t) fs_m_in->REQ_GID; bits = (mode_t) fs_m_in->REQ_MODE; dev = (dev_t) fs_m_in->REQ_DEV; /* Try to allocate the inode */ - if( (rip = alloc_inode(dev, bits) ) == NULL) return(err_code); + if( (rip = alloc_inode(dev, bits, uid, gid) ) == NULL) return(err_code); switch (bits & S_IFMT) { case S_IFBLK: diff --git a/servers/pfs/proto.h b/servers/pfs/proto.h index a268be29a..cad213662 100644 --- a/servers/pfs/proto.h +++ b/servers/pfs/proto.h @@ -17,7 +17,7 @@ void put_block(dev_t dev, ino_t inum); void buf_pool(void); /* inode.c */ -struct inode *alloc_inode(dev_t dev, mode_t mode); +struct inode *alloc_inode(dev_t dev, mode_t mode, uid_t uid, gid_t gid); void dup_inode(struct inode *ip); struct inode *find_inode(ino_t numb); void free_inode(struct inode *rip); @@ -61,37 +61,12 @@ bit_t alloc_bit(void); void free_bit(bit_t bit_returned); /* dev_uds.c */ -int uds_open(message *dev_m_in, message *dev_m_out); -int uds_close(message *dev_m_in, message *dev_m_out); -int uds_read(message *dev_m_in, message *dev_m_out); -int uds_write(message *dev_m_in, message *dev_m_out); -int uds_ioctl(message *dev_m_in, message *dev_m_out); -int uds_select(message *dev_m_in, message *dev_m_out); -int uds_unsuspend(endpoint_t m_source, int minor); -int uds_cancel(message *dev_m_in, message *dev_m_out); +void uds_request(message *m_ptr, int ipc_status); +void uds_unsuspend(devminor_t minor); /* uds.c */ void uds_init(void); -int do_accept(message *dev_m_in, message *dev_m_out); -int do_connect(message *dev_m_in, message *dev_m_out); -int do_listen(message *dev_m_in, message *dev_m_out); -int do_socket(message *dev_m_in, message *dev_m_out); -int do_bind(message *dev_m_in, message *dev_m_out); -int do_getsockname(message *dev_m_in, message *dev_m_out); -int do_getpeername(message *dev_m_in, message *dev_m_out); -int do_shutdown(message *dev_m_in, message *dev_m_out); -int do_socketpair(message *dev_m_in, message *dev_m_out); -int do_getsockopt_sotype(message *dev_m_in, message *dev_m_out); -int do_getsockopt_peercred(message *dev_m_in, message *dev_m_out); -int do_getsockopt_sndbuf(message *dev_m_in, message *dev_m_out); -int do_setsockopt_sndbuf(message *dev_m_in, message *dev_m_out); -int do_getsockopt_rcvbuf(message *dev_m_in, message *dev_m_out); -int do_setsockopt_rcvbuf(message *dev_m_in, message *dev_m_out); -int do_sendto(message *dev_m_in, message *dev_m_out); -int do_recvfrom(message *dev_m_in, message *dev_m_out); -int do_sendmsg(message *dev_m_in, message *dev_m_out); -int do_recvmsg(message *dev_m_in, message *dev_m_out); -int perform_connection(message *dev_m_in, message *dev_m_out, struct - sockaddr_un *addr, int minorx, int minory); -int clear_fds(int minor, struct ancillary *data); +int uds_clear_fds(devminor_t minor, struct ancillary *data); +int uds_do_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt, + cp_grant_id_t grant); #endif diff --git a/servers/pfs/read.c b/servers/pfs/read.c index cbbba89a5..b55c9ca85 100644 --- a/servers/pfs/read.c +++ b/servers/pfs/read.c @@ -63,11 +63,11 @@ int fs_readwrite(message *fs_m_in, message *fs_m_out) if (rw_flag == READING) { /* Copy a chunk from the block buffer to user space. */ - r = sys_safecopyto(VFS_PROC_NR, gid, (vir_bytes) 0, + r = sys_safecopyto(fs_m_in->m_source, gid, (vir_bytes) 0, (vir_bytes) (bp->b_data+position), (size_t) nrbytes); } else { /* Copy a chunk from user space to the block buffer. */ - r = sys_safecopyfrom(VFS_PROC_NR, gid, (vir_bytes) 0, + r = sys_safecopyfrom(fs_m_in->m_source, gid, (vir_bytes) 0, (vir_bytes) (bp->b_data+position), (size_t) nrbytes); } diff --git a/servers/pfs/table.c b/servers/pfs/table.c index ff3e62da3..0169b0b25 100644 --- a/servers/pfs/table.c +++ b/servers/pfs/table.c @@ -1,10 +1,11 @@ -/* This file contains the table used to map system call numbers onto the +/* This file contains the table used to map VFS/FS call numbers onto the * routines that perform them. */ #define _TABLE +#include "inc.h" #include "fs.h" #include "inode.h" #include "buf.h" @@ -12,7 +13,6 @@ /* File System Handlers (pfs) */ int (*fs_call_vec[])(message *fs_m_in, message *fs_m_out) = { - no_sys, /* 0 not used */ no_sys, /* 1 */ fs_putnode, /* 2 */ @@ -47,34 +47,3 @@ int (*fs_call_vec[])(message *fs_m_in, message *fs_m_out) = { no_sys, /* 31 */ no_sys, /* 32 */ }; - -/* Device Handlers (/dev/uds) */ -int (*dev_call_vec[])(message *dev_m_in, message *dev_m_out) = { - - uds_cancel, /* 0 CANCEL */ - no_sys, /* 1 */ - no_sys, /* 2 */ - no_sys, /* 3 */ - no_sys, /* 4 */ - no_sys, /* 5 */ - uds_open, /* 6 DEV_OPEN */ - uds_close, /* 7 DEV_CLOSE */ - no_sys, /* 8 */ - no_sys, /* 9 */ - no_sys, /* 10 TTY_SETPGRP */ - no_sys, /* 11 TTY_EXIT */ - uds_select, /* 12 DEV_SELECT */ - no_sys, /* 13 DEV_STATUS */ - uds_open, /* 14 DEV_REOPEN */ - no_sys, /* 15 */ - no_sys, /* 16 */ - no_sys, /* 17 */ - no_sys, /* 18 */ - no_sys, /* 19 */ - uds_read, /* 20 DEV_READ_S */ - uds_write, /* 21 DEV_WRITE_S */ - no_sys, /* 22 DEV_SCATTER_S */ - no_sys, /* 23 DEV_GATHER_S */ - uds_ioctl, /* 24 DEV_IOCTL_S */ - no_sys, /* 25 DEV_MMAP_S */ -}; diff --git a/servers/pfs/uds.c b/servers/pfs/uds.c index 34b9d1006..4bd36793e 100644 --- a/servers/pfs/uds.c +++ b/servers/pfs/uds.c @@ -6,31 +6,12 @@ * The entry points into this file are... * * uds_init: initialize the descriptor table. - * do_accept: handles the accept(2) syscall. - * do_connect: handles the connect(2) syscall. - * do_listen: handles the listen(2) syscall. - * do_socket: handles the socket(2) syscall. - * do_bind: handles the bind(2) syscall. - * do_getsockname: handles the getsockname(2) syscall. - * do_getpeername: handles the getpeername(2) syscall. - * do_shutdown: handles the shutdown(2) syscall. - * do_socketpair: handles the socketpair(2) syscall. - * do_getsockopt_sotype: handles the getsockopt(2) syscall. - * do_getsockopt_peercred: handles the getsockopt(2) syscall. - * do_getsockopt_sndbuf: handles the getsockopt(2) syscall. - * do_setsockopt_sndbuf: handles the setsockopt(2) syscall. - * do_getsockopt_rcvbuf: handles the getsockopt(2) syscall. - * do_setsockopt_rcvbuf: handles the setsockopt(2) syscall. - * do_sendto: handles the sendto(2) syscall. - * do_recvfrom: handles the recvfrom(2) syscall. - * do_sendmsg: handles the sendmsg(2) syscall. - * do_recvmsg: handles the recvmsg(2) syscall. - * perform_connection: performs the connection of two descriptors. - * clear_fds: calls put_filp for undelivered FDs. + * uds_do_ioctl: process an IOCTL request. + * uds_clear_fds: calls put_filp for undelivered FDs. * * Also see... * - * table.c, dev_uds.c, uds.h + * dev_uds.c, uds.h */ #define DEBUG 0 @@ -54,7 +35,7 @@ void uds_init(void) } /* check the permissions of a socket file */ -static int check_perms(int minor, struct sockaddr_un *addr) +static int check_perms(devminor_t minor, struct sockaddr_un *addr) { int rc; message vfs_m; @@ -66,10 +47,10 @@ static int check_perms(int minor, struct sockaddr_un *addr) /* ask the VFS to verify the permissions */ memset(&vfs_m, '\0', sizeof(message)); - vfs_m.m_type = PFS_REQ_CHECK_PERMS; - vfs_m.USER_ENDPT = uds_fd_table[minor].owner; - vfs_m.IO_GRANT = (char *) grant_id; - vfs_m.COUNT = UNIX_PATH_MAX; + vfs_m.m_type = VFS_PFS_CHECK_PERMS; + vfs_m.VFS_PFS_ENDPT = uds_fd_table[minor].owner; + vfs_m.VFS_PFS_GRANT = grant_id; + vfs_m.VFS_PFS_COUNT = UNIX_PATH_MAX; rc = sendrec(VFS_PROC_NR, &vfs_m); cpf_revoke(grant_id); @@ -101,9 +82,9 @@ static filp_id_t verify_fd(endpoint_t ep, int fd) memset(&vfs_m, '\0', sizeof(message)); - vfs_m.m_type = PFS_REQ_VERIFY_FD; - vfs_m.USER_ENDPT = ep; - vfs_m.COUNT = fd; + vfs_m.m_type = VFS_PFS_VERIFY_FD; + vfs_m.VFS_PFS_ENDPT = ep; + vfs_m.VFS_PFS_FD = fd; rc = sendrec(VFS_PROC_NR, &vfs_m); if (OK != rc) { @@ -116,7 +97,7 @@ static filp_id_t verify_fd(endpoint_t ep, int fd) printf("(uds) VFS reply => %d\n", vfs_m.m_type); #endif - return vfs_m.ADDRESS; + return vfs_m.VFS_PFS_FILP; } static int set_filp(filp_id_t sfilp) @@ -126,13 +107,13 @@ static int set_filp(filp_id_t sfilp) #if DEBUG == 1 static int call_count = 0; - printf("(uds) set_filp(0x%x) call_count=%d\n", sfilp, ++call_count); + printf("(uds) set_filp(%p) call_count=%d\n", sfilp, ++call_count); #endif memset(&vfs_m, '\0', sizeof(message)); - vfs_m.m_type = PFS_REQ_SET_FILP; - vfs_m.ADDRESS = sfilp; + vfs_m.m_type = VFS_PFS_SET_FILP; + vfs_m.VFS_PFS_FILP = sfilp; rc = sendrec(VFS_PROC_NR, &vfs_m); if (OK != rc) { @@ -154,15 +135,15 @@ static int copy_filp(endpoint_t to_ep, filp_id_t cfilp) #if DEBUG == 1 static int call_count = 0; - printf("(uds) copy_filp(%d, 0x%x) call_count=%d\n",to_ep, cfilp, + printf("(uds) copy_filp(%d, %p) call_count=%d\n",to_ep, cfilp, ++call_count); #endif memset(&vfs_m, '\0', sizeof(message)); - vfs_m.m_type = PFS_REQ_COPY_FILP; - vfs_m.USER_ENDPT = to_ep; - vfs_m.ADDRESS = cfilp; + vfs_m.m_type = VFS_PFS_COPY_FILP; + vfs_m.VFS_PFS_ENDPT = to_ep; + vfs_m.VFS_PFS_FILP = cfilp; rc = sendrec(VFS_PROC_NR, &vfs_m); if (OK != rc) { @@ -184,13 +165,13 @@ static int put_filp(filp_id_t pfilp) #if DEBUG == 1 static int call_count = 0; - printf("(uds) put_filp(0x%x) call_count=%d\n", pfilp, ++call_count); + printf("(uds) put_filp(%p) call_count=%d\n", pfilp, ++call_count); #endif memset(&vfs_m, '\0', sizeof(message)); - vfs_m.m_type = PFS_REQ_PUT_FILP; - vfs_m.ADDRESS = pfilp; + vfs_m.m_type = VFS_PFS_PUT_FILP; + vfs_m.VFS_PFS_FILP = pfilp; rc = sendrec(VFS_PROC_NR, &vfs_m); if (OK != rc) { @@ -217,9 +198,9 @@ static int cancel_fd(endpoint_t ep, int fd) memset(&vfs_m, '\0', sizeof(message)); - vfs_m.m_type = PFS_REQ_CANCEL_FD; - vfs_m.USER_ENDPT = ep; - vfs_m.COUNT = fd; + vfs_m.m_type = VFS_PFS_CANCEL_FD; + vfs_m.VFS_PFS_ENDPT = ep; + vfs_m.VFS_PFS_FD = fd; rc = sendrec(VFS_PROC_NR, &vfs_m); if (OK != rc) { @@ -234,8 +215,8 @@ static int cancel_fd(endpoint_t ep, int fd) return vfs_m.m_type; /* return reply code OK, ELOOP, etc. */ } -int perform_connection(message *dev_m_in, message *dev_m_out, - struct sockaddr_un *addr, int minorx, int minory) +static int perform_connection(devminor_t minorx, devminor_t minory, + struct sockaddr_un *addr) { /* there are several places were a connection is established. */ /* accept(2), connect(2), uds_status(2), socketpair(2) */ @@ -244,8 +225,8 @@ int perform_connection(message *dev_m_in, message *dev_m_out, #if DEBUG == 1 static int call_count = 0; - printf("(uds) [%d] perform_connection() call_count=%d\n", - uds_minor(dev_m_in), ++call_count); + printf("(uds) [%d] perform_connection() call_count=%d\n", minorx, + ++call_count); #endif /* only connection oriented types are acceptable and only like @@ -270,19 +251,16 @@ int perform_connection(message *dev_m_in, message *dev_m_out, return OK; } - -int do_accept(message *dev_m_in, message *dev_m_out) +static int do_accept(devminor_t minor, endpoint_t endpt, cp_grant_id_t grant) { - int minor; - int minorparent; /* minor number of parent (server) */ - int minorpeer; + devminor_t minorparent; /* minor number of parent (server) */ + devminor_t minorpeer; int rc, i; struct sockaddr_un addr; #if DEBUG == 1 static int call_count = 0; - printf("(uds) [%d] do_accept() call_count=%d\n", - uds_minor(dev_m_in), ++call_count); + printf("(uds) [%d] do_accept() call_count=%d\n", minor, ++call_count); #endif /* Somewhat weird logic is used in this function, so here's an @@ -294,16 +272,14 @@ int do_accept(message *dev_m_in, message *dev_m_out) * connection or suspend and wait for a connect(). */ - minor = uds_minor(dev_m_in); - if (uds_fd_table[minor].type != -1) { /* this IOCTL must be called on a 'fresh' socket */ return EINVAL; } /* Get the server's address */ - rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &addr, sizeof(struct sockaddr_un)); + rc = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &addr, + sizeof(struct sockaddr_un)); if (rc != OK) { return EIO; @@ -313,7 +289,6 @@ int do_accept(message *dev_m_in, message *dev_m_out) rc = -1; /* to trap error */ for (i = 0; i < NR_FDS; i++) { - if (uds_fd_table[i].addr.sun_family == AF_UNIX && !strncmp(addr.sun_path, uds_fd_table[i].addr.sun_path, @@ -364,7 +339,7 @@ int do_accept(message *dev_m_in, message *dev_m_out) */ uds_fd_table[minor].suspended = UDS_SUSPENDED_ACCEPT; - return SUSPEND; + return EDONTREPLY; } #if DEBUG == 1 @@ -372,7 +347,7 @@ int do_accept(message *dev_m_in, message *dev_m_out) minorpeer, minorparent); #endif - rc = perform_connection(dev_m_in, dev_m_out, &addr, minor, minorpeer); + rc = perform_connection(minor, minorpeer, &addr); if (rc != OK) { #if DEBUG == 1 printf("(uds) [%d] {do_accept} connection not performed\n", @@ -389,27 +364,23 @@ int do_accept(message *dev_m_in, message *dev_m_out) printf("(uds) [%d] {do_accept} revive %d\n", minor, minorpeer); #endif - uds_fd_table[minorpeer].ready_to_revive = 1; - uds_unsuspend(dev_m_in->m_source, minorpeer); + uds_unsuspend(minorpeer); } return OK; } -int do_connect(message *dev_m_in, message *dev_m_out) +static int do_connect(devminor_t minor, endpoint_t endpt, cp_grant_id_t grant) { - int minor, child; + int child; struct sockaddr_un addr; int rc, i, j; #if DEBUG == 1 static int call_count = 0; - printf("(uds) [%d] do_connect() call_count=%d\n", uds_minor(dev_m_in), - ++call_count); + printf("(uds) [%d] do_connect() call_count=%d\n", minor, ++call_count); #endif - minor = uds_minor(dev_m_in); - /* only connection oriented sockets can connect */ if (uds_fd_table[minor].type != SOCK_STREAM && uds_fd_table[minor].type != SOCK_SEQPACKET) { @@ -421,9 +392,8 @@ int do_connect(message *dev_m_in, message *dev_m_out) return EISCONN; } - rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &addr, - sizeof(struct sockaddr_un)); + rc = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &addr, + sizeof(struct sockaddr_un)); if (rc != OK) { return EIO; @@ -439,7 +409,6 @@ int do_connect(message *dev_m_in, message *dev_m_out) * address we want to connect to */ for (i = 0; i < NR_FDS; i++) { - if (uds_fd_table[minor].type == uds_fd_table[i].type && uds_fd_table[i].listening && uds_fd_table[i].addr.sun_family == AF_UNIX && @@ -452,11 +421,9 @@ int do_connect(message *dev_m_in, message *dev_m_out) * perform connection to the child */ - rc = perform_connection(dev_m_in, dev_m_out, - &addr, minor, child); + rc = perform_connection(minor, child, &addr); if (rc == OK) { - uds_fd_table[i].child = -1; #if DEBUG == 1 @@ -464,16 +431,11 @@ int do_connect(message *dev_m_in, message *dev_m_out) #endif /* wake the parent (server) */ - uds_fd_table[child].ready_to_revive = - 1; - uds_unsuspend(dev_m_in->m_source, - child); + uds_unsuspend(child); } return rc; - } else { - #if DEBUG == 1 printf("(uds) [%d] adding to %d's backlog\n", minor, i); @@ -497,33 +459,23 @@ int do_connect(message *dev_m_in, message *dev_m_out) } if (rc == -1) { - /* backlog is full */ break; } /* see if the server is blocked on select() */ - if (uds_fd_table[i].selecting == 1) { - - /* if the server wants to know - * about data ready to read and - * it doesn't know about it - * already, then let the server - * know we have data for it. + if (uds_fd_table[i].sel_ops & CDEV_OP_RD) { + /* if the server wants to know about + * data ready to read and it doesn't + * doesn't know about it already, then + * let the server know we have data for + * it. */ - if ((uds_fd_table[i].sel_ops_in & - SEL_RD) && - !(uds_fd_table[i].sel_ops_out & - SEL_RD)) { + chardriver_reply_select( + uds_fd_table[i].sel_endpt, i, + CDEV_OP_RD); - uds_fd_table[i].sel_ops_out |= - SEL_RD; - uds_fd_table[i].status_updated - = 1; - - uds_unsuspend( - dev_m_in->m_source, i); - } + uds_fd_table[i].sel_ops &= ~CDEV_OP_RD; } /* we found our server */ @@ -554,23 +506,19 @@ int do_connect(message *dev_m_in, message *dev_m_out) uds_fd_table[minor].suspended = UDS_SUSPENDED_CONNECT; - return SUSPEND; + return EDONTREPLY; } -int do_listen(message *dev_m_in, message *dev_m_out) +static int do_listen(devminor_t minor, endpoint_t endpt, cp_grant_id_t grant) { - int minor; int rc; int backlog_size; #if DEBUG == 1 static int call_count = 0; - printf("(uds) [%d] do_listen() call_count=%d\n", uds_minor(dev_m_in), - ++call_count); + printf("(uds) [%d] do_listen() call_count=%d\n", minor, ++call_count); #endif - minor = uds_minor(dev_m_in); - /* ensure the socket has a type and is bound */ if (uds_fd_table[minor].type == -1 || uds_fd_table[minor].addr.sun_family != AF_UNIX) { @@ -594,8 +542,8 @@ int do_listen(message *dev_m_in, message *dev_m_out) * let it happen, but if listen() has already been called, we * don't allow the backlog to shrink */ - rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &backlog_size, sizeof(int)); + rc = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &backlog_size, + sizeof(int)); if (rc != OK) { return EIO; @@ -637,19 +585,15 @@ int do_listen(message *dev_m_in, message *dev_m_out) return OK; } -int do_socket(message *dev_m_in, message *dev_m_out) +static int do_socket(devminor_t minor, endpoint_t endpt, cp_grant_id_t grant) { int rc; - int minor; #if DEBUG == 1 static int call_count = 0; - printf("(uds) [%d] do_socket() call_count=%d\n", uds_minor(dev_m_in), - ++call_count); + printf("(uds) [%d] do_socket() call_count=%d\n", minor, ++call_count); #endif - minor = uds_minor(dev_m_in); - /* see if this socket already has a type */ if (uds_fd_table[minor].type != -1) { /* socket type can only be set once */ @@ -657,12 +601,10 @@ int do_socket(message *dev_m_in, message *dev_m_out) } /* get the requested type */ - rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &(uds_fd_table[minor].type), - sizeof(int)); + rc = sys_safecopyfrom(endpt, grant, 0, + (vir_bytes) &uds_fd_table[minor].type, sizeof(int)); if (rc != OK) { - /* something went wrong and we couldn't get the type */ return EIO; } @@ -672,12 +614,10 @@ int do_socket(message *dev_m_in, message *dev_m_out) case SOCK_STREAM: case SOCK_DGRAM: case SOCK_SEQPACKET: - /* the type is one of the 3 valid socket types */ return OK; default: - /* if the type isn't one of the 3 valid socket * types, then it must be invalid. */ @@ -689,20 +629,16 @@ int do_socket(message *dev_m_in, message *dev_m_out) } } -int do_bind(message *dev_m_in, message *dev_m_out) +static int do_bind(devminor_t minor, endpoint_t endpt, cp_grant_id_t grant) { - int minor; struct sockaddr_un addr; int rc, i; #if DEBUG == 1 static int call_count = 0; - printf("(uds) [%d] do_bind() call_count=%d\n", uds_minor(dev_m_in), - ++call_count); + printf("(uds) [%d] do_bind() call_count=%d\n", minor, ++call_count); #endif - minor = uds_minor(dev_m_in); - if ((uds_fd_table[minor].type == -1) || (uds_fd_table[minor].addr.sun_family == AF_UNIX && uds_fd_table[minor].type != SOCK_DGRAM)) { @@ -713,8 +649,8 @@ int do_bind(message *dev_m_in, message *dev_m_out) return EINVAL; } - rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &addr, sizeof(struct sockaddr_un)); + rc = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &addr, + sizeof(struct sockaddr_un)); if (rc != OK) { return EIO; @@ -722,13 +658,11 @@ int do_bind(message *dev_m_in, message *dev_m_out) /* do some basic sanity checks on the address */ if (addr.sun_family != AF_UNIX) { - /* bad family */ return EAFNOSUPPORT; } if (addr.sun_path[0] == '\0') { - /* bad address */ return ENOENT; } @@ -756,45 +690,41 @@ int do_bind(message *dev_m_in, message *dev_m_out) return OK; } -int do_getsockname(message *dev_m_in, message *dev_m_out) +static int do_getsockname(devminor_t minor, endpoint_t endpt, + cp_grant_id_t grant) { - int minor; int rc; #if DEBUG == 1 static int call_count = 0; - printf("(uds) [%d] do_getsockname() call_count=%d\n", - uds_minor(dev_m_in), ++call_count); + printf("(uds) [%d] do_getsockname() call_count=%d\n", minor, + ++call_count); #endif - minor = uds_minor(dev_m_in); - /* Unconditionally send the address we have assigned to this socket. * The POSIX standard doesn't say what to do if the address * hasn't been set. If the address isn't currently set, then * the user will get NULL bytes. Note: libc depends on this * behavior. */ - rc = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &(uds_fd_table[minor].addr), + rc = sys_safecopyto(endpt, grant, 0, + (vir_bytes) &uds_fd_table[minor].addr, sizeof(struct sockaddr_un)); return rc ? EIO : OK; } -int do_getpeername(message *dev_m_in, message *dev_m_out) +static int do_getpeername(devminor_t minor, endpoint_t endpt, + cp_grant_id_t grant) { - int minor; int rc; #if DEBUG == 1 static int call_count = 0; - printf("(uds) [%d] do_getpeername() call_count=%d\n", - uds_minor(dev_m_in), ++call_count); + printf("(uds) [%d] do_getpeername() call_count=%d\n", minor, + ++call_count); #endif - minor = uds_minor(dev_m_in); - /* check that the socket is connected with a valid peer */ if (uds_fd_table[minor].peer != -1) { int peer_minor; @@ -802,9 +732,8 @@ int do_getpeername(message *dev_m_in, message *dev_m_out) peer_minor = uds_fd_table[minor].peer; /* copy the address from the peer */ - rc = sys_safecopyto(VFS_PROC_NR, - (cp_grant_id_t) dev_m_in->IO_GRANT, (vir_bytes) 0, - (vir_bytes) &(uds_fd_table[peer_minor].addr), + rc = sys_safecopyto(endpt, grant, 0, + (vir_bytes) &uds_fd_table[peer_minor].addr, sizeof(struct sockaddr_un)); return rc ? EIO : OK; @@ -819,19 +748,16 @@ int do_getpeername(message *dev_m_in, message *dev_m_out) } } -int do_shutdown(message *dev_m_in, message *dev_m_out) +static int do_shutdown(devminor_t minor, endpoint_t endpt, cp_grant_id_t grant) { - int minor; int rc, how; #if DEBUG == 1 static int call_count = 0; - printf("(uds) [%d] do_shutdown() call_count=%d\n", - uds_minor(dev_m_in), ++call_count); + printf("(uds) [%d] do_shutdown() call_count=%d\n", minor, + ++call_count); #endif - minor = uds_minor(dev_m_in); - if (uds_fd_table[minor].type != SOCK_STREAM && uds_fd_table[minor].type != SOCK_SEQPACKET) { @@ -849,8 +775,7 @@ int do_shutdown(message *dev_m_in, message *dev_m_out) } /* get the 'how' parameter from the process */ - rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &how, sizeof(int)); + rc = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &how, sizeof(int)); if (rc != OK) { return EIO; @@ -880,25 +805,23 @@ int do_shutdown(message *dev_m_in, message *dev_m_out) return OK; } -int do_socketpair(message *dev_m_in, message *dev_m_out) +static int do_socketpair(devminor_t minorx, endpoint_t endpt, + cp_grant_id_t grant) { int rc; dev_t minorin; - int minorx, minory; + devminor_t minory; struct sockaddr_un addr; #if DEBUG == 1 static int call_count = 0; - printf("(uds) [%d] do_socketpair() call_count=%d\n", - uds_minor(dev_m_in), ++call_count); + printf("(uds) [%d] do_socketpair() call_count=%d\n", minorx, + ++call_count); #endif - /* first ioctl param is the first socket */ - minorx = uds_minor(dev_m_in); - - /* third ioctl param is the minor number of the second socket */ - rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &minorin, sizeof(dev_t)); + /* ioctl argument is the minor number of the second socket */ + rc = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &minorin, + sizeof(dev_t)); if (rc != OK) { return EIO; @@ -912,7 +835,6 @@ int do_socketpair(message *dev_m_in, message *dev_m_out) /* security check - both sockets must have the same endpoint (owner) */ if (uds_fd_table[minorx].owner != uds_fd_table[minory].owner) { - /* we won't allow you to magically connect your socket to * someone elses socket */ @@ -923,53 +845,46 @@ int do_socketpair(message *dev_m_in, message *dev_m_out) addr.sun_path[0] = 'X'; addr.sun_path[1] = '\0'; - uds_fd_table[minorx].syscall_done = 1; - return perform_connection(dev_m_in, dev_m_out, &addr, minorx, minory); + return perform_connection(minorx, minory, &addr); } -int do_getsockopt_sotype(message *dev_m_in, message *dev_m_out) +static int do_getsockopt_sotype(devminor_t minor, endpoint_t endpt, + cp_grant_id_t grant) { - int minor; int rc; #if DEBUG == 1 static int call_count = 0; - printf("(uds) [%d] do_getsockopt_sotype() call_count=%d\n", - uds_minor(dev_m_in), ++call_count); + printf("(uds) [%d] do_getsockopt_sotype() call_count=%d\n", minor, + ++call_count); #endif - minor = uds_minor(dev_m_in); - if (uds_fd_table[minor].type == -1) { - /* the type hasn't been set yet. instead of returning an * invalid type, we fail with EINVAL */ return EINVAL; } - rc = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &(uds_fd_table[minor].type), - sizeof(int)); + rc = sys_safecopyto(endpt, grant, 0, + (vir_bytes) &uds_fd_table[minor].type, sizeof(int)); return rc ? EIO : OK; } -int do_getsockopt_peercred(message *dev_m_in, message *dev_m_out) +static int do_getsockopt_peercred(devminor_t minor, endpoint_t endpt, + cp_grant_id_t grant) { - int minor; int peer_minor; int rc; struct ucred cred; #if DEBUG == 1 static int call_count = 0; - printf("(uds) [%d] do_getsockopt_peercred() call_count=%d\n", - uds_minor(dev_m_in), ++call_count); + printf("(uds) [%d] do_getsockopt_peercred() call_count=%d\n", minor, + ++call_count); #endif - minor = uds_minor(dev_m_in); - if (uds_fd_table[minor].peer == -1) { if (uds_fd_table[minor].err == ECONNRESET) { @@ -990,43 +905,44 @@ int do_getsockopt_peercred(message *dev_m_in, message *dev_m_out) return errno; } - rc = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &cred, sizeof(struct ucred)); + rc = sys_safecopyto(endpt, grant, 0, (vir_bytes) &cred, + sizeof(struct ucred)); return rc ? EIO : OK; } -int do_getsockopt_sndbuf(message *dev_m_in, message *dev_m_out) +static int do_getsockopt_sndbuf(devminor_t minor, endpoint_t endpt, + cp_grant_id_t grant) { int rc; size_t sndbuf = PIPE_BUF; #if DEBUG == 1 static int call_count = 0; - printf("(uds) [%d] do_getsockopt_sndbuf() call_count=%d\n", - uds_minor(dev_m_in), ++call_count); + printf("(uds) [%d] do_getsockopt_sndbuf() call_count=%d\n", minor, + ++call_count); #endif - rc = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &(sndbuf), sizeof(size_t)); + rc = sys_safecopyto(endpt, grant, 0, (vir_bytes) &sndbuf, + sizeof(size_t)); return rc ? EIO : OK; } -int do_setsockopt_sndbuf(message *dev_m_in, message *dev_m_out) +static int do_setsockopt_sndbuf(devminor_t minor, endpoint_t endpt, + cp_grant_id_t grant) { int rc; size_t sndbuf; #if DEBUG == 1 static int call_count = 0; - printf("(uds) [%d] do_setsockopt_rcvbuf() call_count=%d\n", - uds_minor(dev_m_in), ++call_count); + printf("(uds) [%d] do_setsockopt_rcvbuf() call_count=%d\n", minor, + ++call_count); #endif - rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &sndbuf, - sizeof(size_t)); + rc = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &sndbuf, + sizeof(size_t)); if (rc != OK) { return EIO; @@ -1043,37 +959,38 @@ int do_setsockopt_sndbuf(message *dev_m_in, message *dev_m_out) return OK; } -int do_getsockopt_rcvbuf(message *dev_m_in, message *dev_m_out) +static int do_getsockopt_rcvbuf(devminor_t minor, endpoint_t endpt, + cp_grant_id_t grant) { int rc; size_t rcvbuf = PIPE_BUF; #if DEBUG == 1 static int call_count = 0; - printf("(uds) [%d] do_getsockopt_rcvbuf() call_count=%d\n", - uds_minor(dev_m_in), ++call_count); + printf("(uds) [%d] do_getsockopt_rcvbuf() call_count=%d\n", minor, + ++call_count); #endif - rc = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &(rcvbuf), sizeof(size_t)); + rc = sys_safecopyto(endpt, grant, 0, (vir_bytes) &rcvbuf, + sizeof(size_t)); return rc ? EIO : OK; } -int do_setsockopt_rcvbuf(message *dev_m_in, message *dev_m_out) +static int do_setsockopt_rcvbuf(devminor_t minor, endpoint_t endpt, + cp_grant_id_t grant) { int rc; size_t rcvbuf; #if DEBUG == 1 static int call_count = 0; - printf("(uds) [%d] do_setsockopt_rcvbuf() call_count=%d\n", - uds_minor(dev_m_in), ++call_count); + printf("(uds) [%d] do_setsockopt_rcvbuf() call_count=%d\n", minor, + ++call_count); #endif - rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &rcvbuf, - sizeof(size_t)); + rc = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &rcvbuf, + sizeof(size_t)); if (rc != OK) { return EIO; @@ -1090,28 +1007,23 @@ int do_setsockopt_rcvbuf(message *dev_m_in, message *dev_m_out) return OK; } - -int do_sendto(message *dev_m_in, message *dev_m_out) +static int do_sendto(devminor_t minor, endpoint_t endpt, cp_grant_id_t grant) { - int minor; int rc; struct sockaddr_un addr; #if DEBUG == 1 static int call_count = 0; - printf("(uds) [%d] do_sendto() call_count=%d\n", uds_minor(dev_m_in), - ++call_count); + printf("(uds) [%d] do_sendto() call_count=%d\n", minor, ++call_count); #endif - minor = uds_minor(dev_m_in); - if (uds_fd_table[minor].type != SOCK_DGRAM) { /* This IOCTL is only for SOCK_DGRAM sockets */ return EINVAL; } - rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &addr, sizeof(struct sockaddr_un)); + rc = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &addr, + sizeof(struct sockaddr_un)); if (rc != OK) { return EIO; @@ -1134,28 +1046,25 @@ int do_sendto(message *dev_m_in, message *dev_m_out) return OK; } -int do_recvfrom(message *dev_m_in, message *dev_m_out) +static int do_recvfrom(devminor_t minor, endpoint_t endpt, cp_grant_id_t grant) { - int minor; int rc; #if DEBUG == 1 static int call_count = 0; - printf("(uds) [%d] do_recvfrom() call_count=%d\n", - uds_minor(dev_m_in), ++call_count); + printf("(uds) [%d] do_recvfrom() call_count=%d\n", minor, + ++call_count); #endif - minor = uds_minor(dev_m_in); - - rc = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &(uds_fd_table[minor].source), + rc = sys_safecopyto(endpt, grant, 0, + (vir_bytes) &uds_fd_table[minor].source, sizeof(struct sockaddr_un)); return rc ? EIO : OK; } -int msg_control_read(struct msg_control *msg_ctrl, struct ancillary *data, - int minor) +static int msg_control_read(struct msg_control *msg_ctrl, + struct ancillary *data, devminor_t minor) { int rc; struct msghdr msghdr; @@ -1213,7 +1122,7 @@ int msg_control_read(struct msg_control *msg_ctrl, struct ancillary *data, return OK; } -static int send_fds(int minor, struct ancillary *data) +static int send_fds(devminor_t minor, struct ancillary *data) { int rc, i, j; @@ -1247,7 +1156,7 @@ static int send_fds(int minor, struct ancillary *data) return OK; } -int clear_fds(int minor, struct ancillary *data) +int uds_clear_fds(devminor_t minor, struct ancillary *data) { /* This function calls put_filp() for all of the FDs in data. * This is used when a Unix Domain Socket is closed and there @@ -1258,14 +1167,14 @@ int clear_fds(int minor, struct ancillary *data) #if DEBUG == 1 static int call_count = 0; - printf("(uds) [%d] recv_fds() call_count=%d\n", minor, + printf("(uds) [%d] uds_clear_fds() call_count=%d\n", minor, ++call_count); #endif for (i = 0; i < data->nfiledes; i++) { put_filp(data->filps[i]); #if DEBUG == 1 - printf("(uds) clear_fds() => %d\n", data->fds[i]); + printf("(uds) uds_clear_fds() => %d\n", data->fds[i]); #endif data->fds[i] = -1; data->filps[i] = NULL; @@ -1276,7 +1185,7 @@ int clear_fds(int minor, struct ancillary *data) return OK; } -static int recv_fds(int minor, struct ancillary *data, +static int recv_fds(devminor_t minor, struct ancillary *data, struct msg_control *msg_ctrl) { int rc, i, j; @@ -1332,7 +1241,7 @@ static int recv_fds(int minor, struct ancillary *data, return OK; } -static int recv_cred(int minor, struct ancillary *data, +static int recv_cred(devminor_t minor, struct ancillary *data, struct msg_control *msg_ctrl) { struct msghdr msghdr; @@ -1360,24 +1269,20 @@ static int recv_cred(int minor, struct ancillary *data, return OK; } -int do_sendmsg(message *dev_m_in, message *dev_m_out) +static int do_sendmsg(devminor_t minor, endpoint_t endpt, cp_grant_id_t grant) { - int minor, peer, rc, i; + int peer, rc, i; struct msg_control msg_ctrl; #if DEBUG == 1 static int call_count = 0; - printf("(uds) [%d] do_sendmsg() call_count=%d\n", - uds_minor(dev_m_in), ++call_count); + printf("(uds) [%d] do_sendmsg() call_count=%d\n", minor, ++call_count); #endif - minor = uds_minor(dev_m_in); - memset(&msg_ctrl, '\0', sizeof(struct msg_control)); - rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &msg_ctrl, - sizeof(struct msg_control)); + rc = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &msg_ctrl, + sizeof(struct msg_control)); if (rc != OK) { return EIO; @@ -1434,9 +1339,8 @@ int do_sendmsg(message *dev_m_in, message *dev_m_out) return send_fds(minor, &uds_fd_table[peer].ancillary_data); } -int do_recvmsg(message *dev_m_in, message *dev_m_out) +static int do_recvmsg(devminor_t minor, endpoint_t endpt, cp_grant_id_t grant) { - int minor; int rc; struct msg_control msg_ctrl; socklen_t controllen_avail = 0; @@ -1445,14 +1349,7 @@ int do_recvmsg(message *dev_m_in, message *dev_m_out) #if DEBUG == 1 static int call_count = 0; - printf("(uds) [%d] do_sendmsg() call_count=%d\n", - uds_minor(dev_m_in), ++call_count); -#endif - - minor = uds_minor(dev_m_in); - - -#if DEBUG == 1 + printf("(uds) [%d] do_sendmsg() call_count=%d\n", minor, ++call_count); printf("(uds) [%d] CREDENTIALS {pid:%d,uid:%d,gid:%d}\n", minor, uds_fd_table[minor].ancillary_data.cred.pid, uds_fd_table[minor].ancillary_data.cred.uid, @@ -1464,9 +1361,8 @@ int do_recvmsg(message *dev_m_in, message *dev_m_out) /* get the msg_control from the user, it will include the * amount of space the user has allocated for control data. */ - rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &msg_ctrl, - sizeof(struct msg_control)); + rc = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &msg_ctrl, + sizeof(struct msg_control)); if (rc != OK) { return EIO; @@ -1501,9 +1397,147 @@ int do_recvmsg(message *dev_m_in, message *dev_m_out) } /* send the user the control data */ - rc = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, - (vir_bytes) 0, (vir_bytes) &msg_ctrl, + rc = sys_safecopyto(endpt, grant, 0, (vir_bytes) &msg_ctrl, sizeof(struct msg_control)); return rc ? EIO : OK; } + +int uds_do_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt, + cp_grant_id_t grant) +{ + int rc; + + switch (request) { /* Handle the ioctl(2) command */ + case NWIOSUDSCONN: + /* connect to a listening socket -- connect() */ + rc = do_connect(minor, endpt, grant); + + break; + + case NWIOSUDSACCEPT: + /* accept an incoming connection -- accept() */ + rc = do_accept(minor, endpt, grant); + + break; + + case NWIOSUDSBLOG: + /* set the backlog_size and put the socket into the listening + * state -- listen() + */ + rc = do_listen(minor, endpt, grant); + + break; + + case NWIOSUDSTYPE: + /* set the type for this socket (i.e. SOCK_STREAM, SOCK_DGRAM, + * etc) -- socket() + */ + rc = do_socket(minor, endpt, grant); + + break; + + case NWIOSUDSADDR: + /* set the address for this socket -- bind() */ + rc = do_bind(minor, endpt, grant); + + break; + + case NWIOGUDSADDR: + /* get the address for this socket -- getsockname() */ + rc = do_getsockname(minor, endpt, grant); + + break; + + case NWIOGUDSPADDR: + /* get the address for the peer -- getpeername() */ + rc = do_getpeername(minor, endpt, grant); + + break; + + case NWIOSUDSSHUT: + /* shutdown a socket for reading, writing, or both -- + * shutdown() + */ + rc = do_shutdown(minor, endpt, grant); + + break; + + case NWIOSUDSPAIR: + /* connect two sockets -- socketpair() */ + rc = do_socketpair(minor, endpt, grant); + + break; + + case NWIOGUDSSOTYPE: + /* get socket type -- getsockopt(SO_TYPE) */ + rc = do_getsockopt_sotype(minor, endpt, grant); + + break; + + case NWIOGUDSPEERCRED: + /* get peer endpoint -- getsockopt(SO_PEERCRED) */ + rc = do_getsockopt_peercred(minor, endpt, grant); + + break; + + case NWIOSUDSTADDR: + /* set target address -- sendto() */ + rc = do_sendto(minor, endpt, grant); + + break; + + case NWIOGUDSFADDR: + /* get from address -- recvfrom() */ + rc = do_recvfrom(minor, endpt, grant); + + break; + + case NWIOGUDSSNDBUF: + /* get the send buffer size -- getsockopt(SO_SNDBUF) */ + rc = do_getsockopt_sndbuf(minor, endpt, grant); + + break; + + case NWIOSUDSSNDBUF: + /* set the send buffer size -- setsockopt(SO_SNDBUF) */ + rc = do_setsockopt_sndbuf(minor, endpt, grant); + + break; + + case NWIOGUDSRCVBUF: + /* get the send buffer size -- getsockopt(SO_SNDBUF) */ + rc = do_getsockopt_rcvbuf(minor, endpt, grant); + + break; + + case NWIOSUDSRCVBUF: + /* set the send buffer size -- setsockopt(SO_SNDBUF) */ + rc = do_setsockopt_rcvbuf(minor, endpt, grant); + + break; + + case NWIOSUDSCTRL: + /* set the control data -- sendmsg() */ + rc = do_sendmsg(minor, endpt, grant); + + break; + + case NWIOGUDSCTRL: + /* set the control data -- recvmsg() */ + rc = do_recvmsg(minor, endpt, grant); + + break; + + default: + /* the IOCTL command is not valid for /dev/uds -- this happens + * a lot and is normal. a lot of libc functions determine the + * socket type with IOCTLs. Any not for us simply get an ENOTTY + * response. + */ + + rc = ENOTTY; + } + + return rc; +} diff --git a/servers/pfs/uds.h b/servers/pfs/uds.h index 6d412dce3..24d78fa3f 100644 --- a/servers/pfs/uds.h +++ b/servers/pfs/uds.h @@ -15,6 +15,7 @@ #include #include +#include /* max connection backlog for incoming connections */ #define UDS_SOMAXCONN 64 @@ -54,9 +55,6 @@ struct uds_fd { /* Socket Owner */ endpoint_t owner; - /* endpoint for suspend/resume */ - endpoint_t endpoint; - /* Pipe Housekeeping */ /* inode number on PFS -- each descriptor is backed by 1 @@ -82,7 +80,6 @@ struct uds_fd { /* Socket Info */ - /* socket type - SOCK_STREAM, SOCK_DGRAM, or SOCK_SEQPACKET * Set by uds_ioctl(NWIOSUDSTYPE). It defaults to -1 in * uds_open(). Any action on a socket with type -1 besides @@ -144,7 +141,6 @@ struct uds_fd { /* Suspend/Revive Housekeeping */ - /* SUSPEND State Flags */ enum UDS_SUSPENDED { @@ -164,56 +160,27 @@ struct uds_fd { UDS_SUSPENDED_ACCEPT = 8 } suspended; - /* Flag (1 or 0) - thing socket was waiting for is ready. - * If 1, then uds_status() will attempt the operation that - * the socket was blocked on. - */ - int ready_to_revive; + /* source endpoint, saved for later use by suspended procs */ + endpoint_t susp_endpt; /* i/o grant, saved for later use by suspended procs */ - cp_grant_id_t io_gr; + cp_grant_id_t susp_grant; - /* is of i/o grant, saved for later use by suspended procs */ - size_t io_gr_size; + /* size of request, saved for later use by suspended procs */ + size_t susp_size; - /* Save the call number so that uds_cancel() can unwind the - * call properly. - */ - int call_nr; - - /* Save the IOCTL so uds_cancel() knows what got cancelled. */ - int ioctl; - - /* Flag (1 or 0) - the system call completed. - * A doc I read said DEV_CANCEL might be called even though - * the operation is finished. We use this variable to - * determine if we should rollback the changes or not. - */ - int syscall_done; + /* request ID, saved for later use by suspended procs */ + cdev_id_t susp_id; /* select() */ - /* Flag (1 or 0) - the process blocked on select(2). When - * selecting is 1 and I/O happens on this socket, then - * select_proc should be notified. - */ - int selecting; - /* when a select is in progress, we notify() this endpoint * of new data. */ - endpoint_t select_proc; + endpoint_t sel_endpt; - /* Options (SEL_RD, SEL_WR, SEL_ERR) that are requested. */ - int sel_ops_in; - - /* Options that are available for this socket. */ - int sel_ops_out; - - /* Flag (1 or 0) to be set to one before calling notify(). - * uds_status() will use the flag to locate this descriptor. - */ - int status_updated; + /* Options (CDEV_OP_RD,WR,ERR) that are requested. */ + unsigned int sel_ops; }; typedef struct uds_fd uds_fd_t; @@ -221,30 +188,4 @@ typedef struct uds_fd uds_fd_t; /* File Descriptor Table -- Defined in uds.c */ EXTERN uds_fd_t uds_fd_table[NR_FDS]; -/* - * Take message m and get the index in uds_fd_table. - */ -#define uds_minor(m) (minor((dev_t) m->DEVICE)) - -/* - * Fill in a reply message. - */ -#define uds_set_reply(msg,type,endpoint,io_gr,status) \ - do { \ - (msg)->m_type = type; \ - (msg)->REP_ENDPT = endpoint; \ - (msg)->REP_IO_GRANT = io_gr; \ - (msg)->REP_STATUS = status; \ - } while (0) - -#define uds_sel_reply(msg,type,minor,ops) \ - do { \ - (msg)->m_type = type; \ - (msg)->DEV_MINOR = minor; \ - (msg)->DEV_SEL_OPS = ops; \ - } while (0) - - - - #endif diff --git a/servers/pfs/utility.c b/servers/pfs/utility.c index f1c4849ab..4109d83d0 100644 --- a/servers/pfs/utility.c +++ b/servers/pfs/utility.c @@ -7,7 +7,7 @@ int no_sys(message *pfs_m_in, message *pfs_m_out) { /* Somebody has used an illegal system call number */ - printf("no_sys: invalid call 0x%x to pfs\n", req_nr); + printf("no_sys: invalid call 0x%x to pfs\n", pfs_m_in->m_type); return(EINVAL); } diff --git a/servers/pm/forkexit.c b/servers/pm/forkexit.c index 6e01f41ee..8cc065af5 100644 --- a/servers/pm/forkexit.c +++ b/servers/pm/forkexit.c @@ -320,11 +320,10 @@ int dump_core; /* flag indicating whether to dump core */ /* Tell VFS about the exiting process. */ m.m_type = dump_core ? PM_DUMPCORE : PM_EXIT; m.PM_PROC = rmp->mp_endpoint; - m.PM_TRACED_PROC = rmp->mp_endpoint; if (dump_core) { - m.PM_TERM_SIG = rmp->mp_sigstatus; - m.PM_PATH = rmp->mp_name; + m.PM_TERM_SIG = rmp->mp_sigstatus; + m.PM_PATH = rmp->mp_name; } tell_vfs(rmp, &m); diff --git a/servers/pm/main.c b/servers/pm/main.c index ace611bf4..19b972c34 100644 --- a/servers/pm/main.c +++ b/servers/pm/main.c @@ -447,15 +447,7 @@ static void handle_vfs_reply() if (m_in.PM_STATUS == OK) rmp->mp_sigstatus |= DUMPED; - if (m_in.PM_PROC == m_in.PM_TRACED_PROC) - /* The reply is to a core dump request - * for a killed process */ - exit_restart(rmp, TRUE /*dump_core*/); - else - /* The reply is to a core dump request - * for a traced process (T_DUMPCORE) */ - /* Wake up the original caller */ - setreply(rmp-mproc, rmp->mp_procgrp); + exit_restart(rmp, TRUE /*dump_core*/); break; diff --git a/servers/pm/misc.c b/servers/pm/misc.c index 40291a53c..579024f6b 100644 --- a/servers/pm/misc.c +++ b/servers/pm/misc.c @@ -142,7 +142,7 @@ int do_getsysinfo() { printf("PM: unauthorized call of do_getsysinfo by proc %d '%s'\n", mp->mp_endpoint, mp->mp_name); - sys_sysctl_stacktrace(mp->mp_endpoint); + sys_diagctl_stacktrace(mp->mp_endpoint); return EPERM; } @@ -190,7 +190,7 @@ int do_getprocnr() printf("PM: unauthorized call of do_getprocnr by proc %d\n", mp->mp_endpoint); - sys_sysctl_stacktrace(mp->mp_endpoint); + sys_diagctl_stacktrace(mp->mp_endpoint); return EPERM; } @@ -267,7 +267,7 @@ int do_getepinfo_o() if (mp->mp_effuid != 0) { printf("PM: unauthorized call of do_getepinfo_o by proc %d\n", mp->mp_endpoint); - sys_sysctl_stacktrace(mp->mp_endpoint); + sys_diagctl_stacktrace(mp->mp_endpoint); return EPERM; } diff --git a/servers/pm/signal.c b/servers/pm/signal.c index 43122caab..fd35304c7 100644 --- a/servers/pm/signal.c +++ b/servers/pm/signal.c @@ -380,7 +380,7 @@ int ksig; /* non-zero means signal comes from kernel */ /* Print stacktrace if necessary. */ if(SIGS_IS_STACKTRACE(signo)) { - sys_sysctl_stacktrace(rmp->mp_endpoint); + sys_diagctl_stacktrace(rmp->mp_endpoint); } if(!SIGS_IS_TERMINATION(signo)) { @@ -475,7 +475,7 @@ int signo; /* signal that caused termination */ if(!(rmp->mp_flags & PRIV_PROC)) { printf("PM: coredump signal %d for %d / %s\n", signo, rmp->mp_pid, rmp->mp_name); - sys_sysctl_stacktrace(rmp->mp_endpoint); + sys_diagctl_stacktrace(rmp->mp_endpoint); } exit_proc(rmp, 0, TRUE /*dump_core*/); } diff --git a/servers/pm/table.c b/servers/pm/table.c index b9007553b..2150f0bf6 100644 --- a/servers/pm/table.c +++ b/servers/pm/table.c @@ -67,7 +67,7 @@ int (*call_vec[])(void) = { no_sys, /* 53 = (lstat) */ no_sys, /* 54 = ioctl */ no_sys, /* 55 = fcntl */ - no_sys, /* 56 = unused */ + no_sys, /* 56 = dupfrom */ no_sys, /* 57 = unused */ no_sys, /* 58 = unused */ do_exec, /* 59 = execve */ @@ -93,7 +93,7 @@ int (*call_vec[])(void) = { no_sys, /* 79 = unused */ no_sys, /* 80 = (getdents) */ no_sys, /* 81 = unused */ - no_sys, /* 82 = (fstatfs) */ + no_sys, /* 82 = (getvfsstat) */ no_sys, /* 83 = unused */ no_sys, /* 84 = unused */ no_sys, /* 85 = (select) */ @@ -135,6 +135,12 @@ int (*call_vec[])(void) = { no_sys, /* 121 = (task reply) */ no_sys, /* 122 = (map driver ) */ do_getrusage, /* 123 = getrusage */ + no_sys, /* 124 = (check_perms) */ + no_sys, /* 125 = (verify_fd) */ + no_sys, /* 126 = (set_filp) */ + no_sys, /* 127 = (copy_filp) */ + no_sys, /* 128 = (put_filp) */ + no_sys, /* 129 = (cancel_fd) */ }; /* This should not fail with "array size is negative": */ extern int dummy[sizeof(call_vec) == NCALLS * sizeof(call_vec[0]) ? 1 : -1]; diff --git a/servers/pm/trace.c b/servers/pm/trace.c index 522a401f0..17d4e1d9b 100644 --- a/servers/pm/trace.c +++ b/servers/pm/trace.c @@ -91,27 +91,6 @@ int do_trace() mp->mp_reply.reply_trace = 0; return(OK); - case T_DUMPCORE: - if ((child = find_proc(m_in.pid)) == NULL) return(ESRCH); - - /* Allow dumpcore only if traced! */ - if (child->mp_tracer != who_p) return(EPERM); - - /* Tell VFS to dump the core. */ - m.m_type = PM_DUMPCORE; - m.PM_PROC = mp->mp_endpoint; - m.PM_TRACED_PROC = child->mp_endpoint; - /* Note that m.PM_PROC != m.PM_TRACED_PROC - * (we use this to differentiate between a VFS core dump reply for a - * an exiting process and the one for a traced process) */ - - m.PM_TERM_SIG = child->mp_sigstatus; - m.PM_PATH = child->mp_name; - - tell_vfs(mp, &m); - - return(SUSPEND); /* Suspend the process until we receive reply from VFS */ - case T_STOP: /* stop the process */ /* This call is not exposed to user programs, because its effect can be * achieved better by sending the traced process a signal with kill(2). diff --git a/servers/procfs/Makefile b/servers/procfs/Makefile index 52d79cbbe..cd426ebc6 100644 --- a/servers/procfs/Makefile +++ b/servers/procfs/Makefile @@ -4,7 +4,7 @@ .include PROG= procfs -SRCS= buf.c main.c pid.c root.c tree.c util.c cpuinfo.c mounts.c +SRCS= buf.c main.c pid.c root.c tree.c util.c cpuinfo.c CPPFLAGS+= -I${NETBSDSRCDIR} -I${NETBSDSRCDIR}/servers diff --git a/servers/procfs/mounts.c b/servers/procfs/mounts.c deleted file mode 100644 index cfd4f2663..000000000 --- a/servers/procfs/mounts.c +++ /dev/null @@ -1,34 +0,0 @@ -#include "inc.h" -#include "vfs/vmnt.h" - -extern struct mproc mproc[NR_PROCS]; - -/*===========================================================================* - * root_mtab * - *===========================================================================*/ -void -root_mounts(void) -{ - struct vmnt vmnt[NR_MNTS]; - struct vmnt *vmp; - struct mproc *rmp; - int slot; - - if (getsysinfo(VFS_PROC_NR, SI_VMNT_TAB, vmnt, sizeof(vmnt)) != OK) - return; - - for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; vmp++) { - if (vmp->m_dev == NO_DEV) - continue; - if (vmp->m_fs_e == PFS_PROC_NR) - continue; /* Skip (special case) */ - - slot = _ENDPOINT_P(vmp->m_fs_e); - if (slot < 0 || slot >= NR_PROCS) - continue; - rmp = &mproc[slot]; - buf_printf("%s on %s type %s (%s)\n", vmp->m_mount_dev, - vmp->m_mount_path, rmp->mp_name, - (vmp->m_flags & VMNT_READONLY) ? "ro" : "rw"); - } -} diff --git a/servers/procfs/mounts.h b/servers/procfs/mounts.h deleted file mode 100644 index ca5712b4b..000000000 --- a/servers/procfs/mounts.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef __PROCFS_MOUNTS_H -#define __PROCFS_MOUNTS_H__ - -void root_mounts(void); - -#endif /* __PROCFS_MOUNTS_H__ */ diff --git a/servers/procfs/pid.c b/servers/procfs/pid.c index f37e049a1..b6e7becc9 100644 --- a/servers/procfs/pid.c +++ b/servers/procfs/pid.c @@ -136,7 +136,6 @@ static void pid_psinfo(int i) case FP_BLOCKED_ON_LOCK: f_state = FSTATE_LOCK; break; case FP_BLOCKED_ON_POPEN: f_state = FSTATE_POPEN; break; case FP_BLOCKED_ON_SELECT: f_state = FSTATE_SELECT; break; - case FP_BLOCKED_ON_DOPEN: f_state = FSTATE_DOPEN; break; case FP_BLOCKED_ON_OTHER: f_state = FSTATE_TASK; break; default: f_state = FSTATE_UNKNOWN; } diff --git a/servers/procfs/root.c b/servers/procfs/root.c index 7629c0ad6..02f8cec2d 100644 --- a/servers/procfs/root.c +++ b/servers/procfs/root.c @@ -7,7 +7,6 @@ #endif #include #include "cpuinfo.h" -#include "mounts.h" static void root_hz(void); static void root_uptime(void); @@ -19,6 +18,7 @@ static void root_pci(void); #endif static void root_dmap(void); static void root_ipcvecs(void); +static void root_mounts(void); struct file root_files[] = { { "hz", REG_ALL_MODE, (data_t) root_hz }, @@ -209,3 +209,21 @@ static void root_ipcvecs(void) PRINT_ENTRYPOINT(do_kernel_call); } +/*===========================================================================* + * root_mounts * + *===========================================================================*/ +void +root_mounts(void) +{ + struct statvfs buf[NR_MNTS]; + int i, count; + + if ((count = getvfsstat(buf, sizeof(buf), ST_NOWAIT)) < 0) + return; + + for (i = 0; i < count; i++) { + buf_printf("%s on %s type %s (%s)\n", buf[i].f_mntfromname, + buf[i].f_mntonname, buf[i].f_fstypename, + (buf[i].f_flag & ST_RDONLY) ? "ro" : "rw"); + } +} diff --git a/servers/rs/main.c b/servers/rs/main.c index dc1caf797..0201fe1b0 100644 --- a/servers/rs/main.c +++ b/servers/rs/main.c @@ -540,7 +540,7 @@ static int sef_cb_signal_manager(endpoint_t target, int signo) /* Print stacktrace if necessary. */ if(SIGS_IS_STACKTRACE(signo)) { - sys_sysctl_stacktrace(target); + sys_diagctl_stacktrace(target); } /* In case of termination signal handle the event. */ diff --git a/servers/rs/table.c b/servers/rs/table.c index 4bcb40dfb..070b8b2fc 100644 --- a/servers/rs/table.c +++ b/servers/rs/table.c @@ -22,7 +22,6 @@ struct boot_image_priv boot_image_priv_table[] = { {DS_PROC_NR, "ds", SRV_F }, {TTY_PROC_NR, "tty", SRV_F }, {MEM_PROC_NR, "memory", SRV_F }, -{LOG_PROC_NR, "log", SRV_F }, {MFS_PROC_NR,"fs_imgrd", SRV_F }, {PFS_PROC_NR, "pfs", SRV_F }, {INIT_PROC_NR, "init", USR_F }, @@ -36,7 +35,6 @@ struct boot_image_sys boot_image_sys_table[] = { { VM_PROC_NR, VM_SF }, { PM_PROC_NR, SRVR_SF }, { VFS_PROC_NR, SRVR_SF }, - { LOG_PROC_NR, SRV_SF }, { MFS_PROC_NR, 0 }, { PFS_PROC_NR, SRV_SF }, { DEFAULT_BOOT_NR, SRV_SF } /* default entry */ @@ -47,8 +45,7 @@ struct boot_image_dev boot_image_dev_table[] = { /*endpoint, flags, dev_nr, dev_style, dev_style2 */ { TTY_PROC_NR, SRV_DF, TTY_MAJOR, STYLE_TTY, STYLE_CTTY }, { MEM_PROC_NR, SRV_DF, MEMORY_MAJOR, STYLE_DEV, STYLE_NDEV }, - { LOG_PROC_NR, SRV_DF, LOG_MAJOR, STYLE_DEVA, STYLE_NDEV }, - { PFS_PROC_NR, SRV_DF, UDS_MAJOR, STYLE_CLONE_A,STYLE_NDEV }, + { PFS_PROC_NR, SRV_DF, UDS_MAJOR, STYLE_DEV, STYLE_NDEV }, { DEFAULT_BOOT_NR, SRV_DF, 0, STYLE_NDEV, STYLE_NDEV } /* default * entry */ diff --git a/servers/vfs/README b/servers/vfs/README index a6ee74d5e..c2a3d3549 100644 --- a/servers/vfs/README +++ b/servers/vfs/README @@ -38,7 +38,7 @@ it supports a few calls necessary for libc. The following system calls are handled by VFS: access, chdir, chmod, chown, chroot, close, creat, fchdir, fcntl, fstat, -fstatfs, fstatvfs, fsync, ftruncate getdents, ioctl, link, llseek, lseek, +fstatvfs, fsync, ftruncate, getdents, getvfsstat, ioctl, link, llseek, lseek, lstat, mkdir, mknod, mount, open, pipe, read, readlink, rename, rmdir, select, stat, statvfs, symlink, sync, truncate, umask, umount, unlink, utime, write. @@ -106,83 +106,84 @@ know the details of the protocol. Upon start up, VFS spawns a configurable amount of worker threads. The main thread fetches requests and replies, and hands them off to idle or reply-pending workers, respectively. If no worker threads are available, -the request is queued. There are 3 types of worker threads: normal, a system -worker, and a deadlock resolver. All standard system calls are handled by -normal worker threads. Jobs from PM and notifications from the kernel are taken -care of by the system worker. The deadlock resolver handles jobs from system +the request is queued. All standard system calls are handled by such worker +threads. One of the threads is reserved to handle new requests from system processes (i.e., File Servers and drivers) when there are no normal worker threads available; all normal threads might be blocked on a single worker thread that caused a system process to send a request on its own. To unblock -all normal threads, we need to reserve one thread to handle that situation. -VFS drives all File Servers and drivers asynchronously. While waiting for -a reply, a worker thread is blocked and other workers can keep processing -requests. Upon reply the worker thread is unblocked. -As mentioned above, the main thread is responsible for retrieving new jobs and -replies to current jobs and start or unblock the proper worker thread. Given -how many sources for new jobs and replies there are, the work for the main -thread is quite complicated. Consider Table 1. -{{{ ---------------------------------------------------------- -| From | normal | deadlock | system | ---------------------------------------------------------- - msg is new job ---------------------------------------------------------- -| PM | | | X | -+----------------------+----------+----------+----------+ -| Notification from | | | | -| the kernel | | | X | -+----------------------+----------+----------+----------+ -| Notification from | | | | -| DS or system process | X | X | | -+----------------------+----------+----------+----------+ -| User process | X | | | -+----------------------+----------+----------+----------+ -| Unsuspended process | X | | | ---------------------------------------------------------- - msg is reply ---------------------------------------------------------- -| File Server reply | resume | | | -+----------------------+----------+----------+----------+ -| Sync. driver reply | resume | | | -+----------------------+----------+----------+----------+ -| Async. driver reply | resume/X | X | | ---------------------------------------------------------- -}}} -Table 1: VFS' message fetching main loop. X means 'start thread'. +all normal threads, we need to reserve one spare thread to handle that +situation. VFS drives all File Servers and drivers asynchronously. While +waiting for a reply, a worker thread is blocked and other workers can keep +processing requests. Upon reply the worker thread is unblocked. -The reason why asynchronous driver replies get their own thread is for the -following. In some cases, a reply has a thread blocked waiting for it which -can be resumed (e.g., open). In another case there's a lot of work to be -done which involves sending new messages (e.g., select replies). Finally, -DEV_REVIVE replies unblock suspended processes which in turn generate new jobs -to be handled by the main loop (e.g., suspended reads and writes). So depending -on the reply a new thread has to be started. Having all this logic in the main -loop is messy, so we start a thread regardless of the actual reply contents. -When there are no worker threads available and there is no need to invoke -the deadlock resolver (i.e., normal system calls), the request is queued in -the fproc table. This works because a process can send only one system call -at a time. When implementing kernel threads, one has to take this assumption -into account. -The protocol PM speaks with VFS is asynchronous and PM is allowed to -send as many request to VFS as it wants. It is impossible to use the same -queueing mechanism as normal processes use, because that would allow for -just 1 queued message. Instead, the system worker maintains a linked list -of pending requests. Moreover, this queueing mechanism is also the reason -why notifications from the kernel are handled by the system worker; the -kernel has no corresponding fproc table entry (so we can't store it there) -and the linked list has no dependencies on that table. -Communication with drivers is asynchronous even when the driver uses the -synchronous driver protocol. However, to guarantee identical behavior, -access to synchronous drivers is serialized. File Servers are treated -differently. VFS was designed to be able to send requests concurrently to -File Servers, although at the time of writing there are no File Servers that -can actually make use of that functionality. To identify which reply from an -FS belongs to which worker thread, all requests have an embedded transaction -identification number (a magic number + thread id encoded in the mtype field -of a message) which the FS has to echo upon reply. Because the range of valid -transaction IDs is isolated from valid system call numbers, VFS can use that -ID to differentiate between replies from File Servers and actual new system -calls from FSes. Using this mechanism VFS is able to support FUSE and ProcFS. +As mentioned above, the main thread is responsible for retrieving new jobs and +replies to current jobs and start or unblock the proper worker thread. +Driver replies are processed directly from the main thread. As a consequence, +these processing routines may not block their calling thread. In some cases, +these routines may resume a thread that is blocked waiting for the reply. This +is always the case for block driver replies, and may or may not be the case for +character driver replies. The character driver reply processing routines may +also unblock suspended processes which in turn generate new jobs to be handled +by the main loop (e.g., suspended reads and writes on pipes). So depending +on the reply a new thread may have to be started. + +Worker threads are strictly tied to a process, and each process can have at +most one worker thread running for it. Generally speaking, there are two types +of work supported by worker threads: normal work, and work from PM. The main +subtype of normal work is the handling of a system call made by the process +itself. The process is blocked while VFS is handling the system call, so no new +system call can arrive from a process while VFS has not completed a previous +system call from that process. For that reason, if there are no worker threads +available to handle the work, the work is queued in the corresponding process +entry of the fproc table. + +The other main type of work consists of requests from PM. The protocol PM +speaks with VFS is asynchronous. PM is allowed to send up to one request per +process to VFS, in addition to a request to initiate a reboot. Most jobs from +PM are taken care of immediately by the main thread, but some jobs require a +worker thread context (to be able to sleep) and/or serialization with normal +work. Therefore, each process may have a PM request queued for execution, also +in the fproc table. Managing proper queuing, addition, and execution of both +normal and PM work is the responsibility of the worker thread infrastructure. + +There are several special tasks that require a worker thread, and these are +implemented as normal work associated with a certain special process that does +not make regular VFS calls anyway. For example, the initial ramdisk mount +procedure uses a thread associated with the VFS process. Some of these special +tasks require protection against being started multiple times at once, as this +is not only undesirable but also disallowed. The full list of worker thread +task types and subtypes is shown in Table 1. + +{{{ +------------------------------------------------------------------------- +| Worker thread task | Type | Association | May use spare? | ++---------------------------+--------+-----------------+----------------+ +| system call from process | normal | calling process | if system proc | ++---------------------------+--------+-----------------+----------------+ +| resumed pipe operation | normal | calling process | no | ++---------------------------+--------+-----------------+----------------+ +| postponed PM request | PM | target process | no | ++---------------------------+--------+-----------------+----------------+ +| DS event notification | normal | DS | yes | ++---------------------------+--------+-----------------+----------------+ +| initial ramdisk mounting | normal | VFS | no | ++---------------------------+--------+-----------------+----------------+ +| reboot sequence | normal | PM | no | +------------------------------------------------------------------------- +}}} +Table 1: worker thread work types and subtypes + +Communication with block drivers is asynchronous, but at this time, access to +these drivers is serialized on a per-driver basis. File Servers are treated +differently. VFS was designed to be able to send requests concurrently to File +Servers, although at the time of writing there are no File Servers that can +actually make use of that functionality. To identify which reply from an FS +belongs to which worker thread, all requests have an embedded transaction +identification number (a magic number + thread id encoded in the mtype field of +a message) which the FS has to echo upon reply. Because the range of valid +transaction IDs is isolated from valid system call numbers, VFS can use that ID +to differentiate between replies from File Servers and actual new system calls +from FSes. Using this mechanism VFS is able to support FUSE and ProcFS. == Locking == ## 4 Locking @@ -306,22 +307,42 @@ fproc, vmnt, vnode, and filp objects. To prevent deadlocks as a result of object locking, we need to define a strict locking order. In VFS we use the following order: -fproc -> [exec] -> vmnt -> vnode -> filp -> [block special file] -> [dmap] +{{{ +fproc > [exec] > vmnt > vnode > filp > [block special file] > [dmap] +}}} That is, no thread may lock an fproc object while holding a vmnt lock, and no thread may lock a vmnt object while holding an (associated) vnode, etc. + Fproc needs protection because processes themselves can initiate system calls, but also PM can cause system calls that have to be executed in their name. For example, a process might be busy reading from a character device and another process sends a termination signal. The exit(2) that follows is sent by PM and is to be executed by the to-be-killed process itself. At this point there is contention for the fproc object that belongs to the process, -hence the need for protection. -The exec(2) call is protected by a mutex for the following reason. VFS uses a -number of variables on the heap to read ELF headers. They are on the heap due -to their size; putting them on the stack would increase stack size demands for -worker threads. The exec call does blocking read calls and thus needs exclusive -access to these variables. However, only the exec(2) syscall needs this lock. +hence the need for protection. This problem is solved in a simple way. Recall +that all worker threads are bound to a process. This also forms the basis of +fproc locking: each worker thread acquires and holds the fproc lock for its +associated process for as long as it is processing work for that process. + +There are two cases where a worker thread may hold the lock to more than one +process. First, as mentioned, the reboot procedure is executed from a worker +thread set in the context of the PM process, thus with the PM process entry +lock held. The procedure itself then acquires a temporary lock on every other +process in turn, in order to clean it up without interference. Thus, the PM +process entry is higher up in the locking order than all other process entries. + +Second, the exec(2) call is protected by a lock, and this exec lock is +currently implemented as a lock on the VM process entry. The exec lock is +acquired by a worker thread for the process performing the exec(2) call, and +thus, the VM process entry is below all other process entries in the locking +order. The exec(2) call is protected by a lock for the following reason. VFS +uses a number of variables on the heap to read ELF headers. They are on the +heap due to their size; putting them on the stack would increase stack size +demands for worker threads. The exec call does blocking read calls and thus +needs exclusive access to these variables. However, only the exec(2) syscall +needs this lock. + Access to block special files needs to be exclusive. File Servers are responsible for handling reads from and writes to block special files; if a block special file is on a device that is mounted, the FS responsible for @@ -355,7 +376,7 @@ requests) do need a vmnt lock. | a file descriptor | getdents, ioctl, llseek, pipe, read, select, write | | argument | | +-------------------+---------------------------------------------------------+ -| System calls with | fsync++, sync, umask | +| System calls with | fsync++, getvfsstat, sync, umask | | other or no | | | arguments | | ------------------------------------------------------------------------------- @@ -452,11 +473,12 @@ as used by VFS. | File rename | rename | VMNT_EXCL | Identical to file unlink | | ops. | | | operations | +-------------+--------------+------------+-----------------------------------+ -| Non-file | sync, umask | VMNT_READ | umask does not involve the file | -| ops. | | or none | system, so it does not need | +| Non-file | sync, umask, | VMNT_READ | umask does not involve the file | +| ops. | getvfsstat | or none | system, so it does not need | | | | | locks. sync does not alter state | | | | | in VFS and is atomic at the FS | -| | | | level | +| | | | level. getvfsstat caches stats | +| | | | only and requires no exclusion. | ------------------------------------------------------------------------------- }}} Table 5: System call without file descriptor argument sub-categorization @@ -572,8 +594,6 @@ REQ_INODE_NR field in requests, unless the notes say otherwise. | REQ_FLUSH | | | Mutually exclusive to REQ_BREAD and | | | | | REQ_BWRITE | +--------------+---------+---------+-----------------------------------------+ -| REQ_FSTATFS | | | | -+--------------+---------+---------+-----------------------------------------+ | REQ_FTRUNC | READ | WRITE | vmnt is only locked if file is not | | | | | already opened | +--------------+---------+---------+-----------------------------------------+ @@ -654,15 +674,15 @@ a request. VFS does this with an arbitrary maximum of 5 attempts. === Recovery from character driver crashes === ## 5.2 Recovery from character driver crashes -Character special files are treated differently. Once VFS has found out a -driver has been restarted, it will stop the current request (if there is -any). It makes no sense to retry requests due to the nature of character -special files. If a character special driver can restart without changing -endpoints, this merely results in the current request (e.g., read, write, or -ioctl) failing and allows the user process to reissue the same request. On -the other hand, if a driver restart causes the driver to change endpoint -number, all associated file descriptors are marked invalid and subsequent -operations on them will always fail with a bad file descriptor error. +While VFS used to support minimal recovery from character driver crashes, the +added complexity has so far proven to outweigh the benefits, especially since +such crash recovery can never be fully transparent: it depends entirely on the +character device as to whether repeating an I/O request makes sense at all. +Currently, all operations except close(2) on a file descriptor that identifies +a device on a crashed character driver, will result in an EIO error. It is up +to the application to reopen the character device and retry whatever it was +doing in the appropriate manner. In the future, automatic reopen and I/O +restart may be reintroduced for a limited subset of character drivers. === Recovery from File Server crashes === ## 5.3 Recovery from File Server crashes diff --git a/servers/vfs/comm.c b/servers/vfs/comm.c index 41760827f..840c96785 100644 --- a/servers/vfs/comm.c +++ b/servers/vfs/comm.c @@ -1,7 +1,4 @@ #include "fs.h" -#include "glo.h" -#include "vmnt.h" -#include "fproc.h" #include #include @@ -96,7 +93,7 @@ int drv_sendrec(endpoint_t drv_e, message *reqmp) panic("driver endpoint %d invalid", drv_e); lock_dmap(dp); - if (dp->dmap_servicing != NONE) + if (dp->dmap_servicing != INVALID_THREAD) panic("driver locking inconsistency"); dp->dmap_servicing = self->w_tid; self->w_task = drv_e; @@ -111,7 +108,7 @@ int drv_sendrec(endpoint_t drv_e, message *reqmp) util_stacktrace(); } - dp->dmap_servicing = NONE; + dp->dmap_servicing = INVALID_THREAD; self->w_task = NONE; self->w_drv_sendrec = NULL; unlock_dmap(dp); diff --git a/servers/vfs/comm.h b/servers/vfs/comm.h deleted file mode 100644 index 4e0d00cc3..000000000 --- a/servers/vfs/comm.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __VFS_COMM_H__ -#define __VFS_COMM_H__ - -/* VFS<->FS communication */ - -typedef struct { - int c_max_reqs; /* Max requests an FS can handle simultaneously */ - int c_cur_reqs; /* Number of requests the FS is currently handling */ - struct worker_thread *c_req_queue;/* Queue of procs waiting to send a message */ -} comm_t; - -#endif diff --git a/servers/vfs/const.h b/servers/vfs/const.h index 7262aee70..bb5bdcaac 100644 --- a/servers/vfs/const.h +++ b/servers/vfs/const.h @@ -6,7 +6,7 @@ #define NR_LOCKS 8 /* # slots in the file locking table */ #define NR_MNTS 16 /* # slots in mount table */ #define NR_VNODES 1024 /* # slots in vnode table */ -#define NR_WTHREADS 8 /* # slots in worker thread table */ +#define NR_WTHREADS 9 /* # slots in worker thread table */ #define NR_NONEDEVS NR_MNTS /* # slots in nonedev bitmap */ @@ -20,21 +20,13 @@ #define FP_BLOCKED_ON_LOCK 2 /* susp'd on lock */ #define FP_BLOCKED_ON_POPEN 3 /* susp'd on pipe open */ #define FP_BLOCKED_ON_SELECT 4 /* susp'd on select */ -#define FP_BLOCKED_ON_DOPEN 5 /* susp'd on device open */ -#define FP_BLOCKED_ON_OTHER 6 /* blocked on other process, check +#define FP_BLOCKED_ON_OTHER 5 /* blocked on other process, check fp_task to find out */ /* test if the process is blocked on something */ #define fp_is_blocked(fp) ((fp)->fp_blocked_on != FP_BLOCKED_ON_NONE) -/* test if reply is a driver reply */ -#define IS_DRV_REPLY(x) (IS_DEV_RS(x) || IS_BDEV_RS(x) || (x) == TASK_REPLY) -#define DUP_MASK 0100 /* mask to distinguish dup2 from dup */ - -#define LOOK_UP 0 /* tells search_dir to lookup string */ -#define ENTER 1 /* tells search_dir to make dir entry */ -#define DELETE 2 /* tells search_dir to delete entry */ -#define IS_EMPTY 3 /* tells search_dir to ret. OK or ENOTEMPTY */ +#define INVALID_THREAD ((thread_t) -1) /* known-invalid thread ID */ #define SYMLOOP 16 @@ -42,11 +34,12 @@ * not be smaller than 16 or bigger than * M3_LONG_STRING. */ +#define FSTYPE_MAX VFS_NAMELEN /* maximum file system type size */ -/* Args to dev_io */ -#define VFS_DEV_READ 2001 -#define VFS_DEV_WRITE 2002 -#define VFS_DEV_IOCTL 2005 -#define VFS_DEV_SELECT 2006 +/* possible select() operation types; read, write, errors */ +#define SEL_RD CDEV_OP_RD +#define SEL_WR CDEV_OP_WR +#define SEL_ERR CDEV_OP_ERR +#define SEL_NOTIFY CDEV_NOTIFY /* not a real select operation */ #endif diff --git a/servers/vfs/coredump.c b/servers/vfs/coredump.c index 578d43df5..f1a3f800d 100644 --- a/servers/vfs/coredump.c +++ b/servers/vfs/coredump.c @@ -1,7 +1,6 @@ #include "fs.h" #include #include -#include "fproc.h" #include #include #include diff --git a/servers/vfs/device.c b/servers/vfs/device.c index ab42a2238..549a40735 100644 --- a/servers/vfs/device.c +++ b/servers/vfs/device.c @@ -2,22 +2,25 @@ * Special character files also require I/O. The routines for these are here. * * The entry points in this file are: - * dev_open: open a character device - * dev_reopen: reopen a character device after a driver crash - * dev_close: close a character device - * bdev_open: open a block device - * bdev_close: close a block device - * dev_io: FS does a read or write on a device - * dev_status: FS processes callback request alert - * gen_opcl: generic call to a task to perform an open/close - * gen_io: generic call to a task to perform an I/O operation - * no_dev: open/close processing for devices that don't exist - * no_dev_io: i/o processing for devices that don't exist - * tty_opcl: perform tty-specific processing for open/close - * ctty_opcl: perform controlling-tty-specific processing for open/close - * ctty_io: perform controlling-tty-specific processing for I/O - * pm_setsid: perform VFS's side of setsid system call - * do_ioctl: perform the IOCTL system call + * cdev_open: open a character device + * cdev_close: close a character device + * cdev_io: initiate a read, write, or ioctl to a character device + * cdev_select: initiate a select call on a device + * cdev_cancel: cancel an I/O request, blocking until it has been cancelled + * cdev_reply: process the result of a character driver request + * bdev_open: open a block device + * bdev_close: close a block device + * bdev_reply: process the result of a block driver request + * bdev_up: a block driver has been mapped in + * gen_opcl: generic call to a character driver to perform an open/close + * gen_io: generic call to a character driver to initiate I/O + * no_dev: open/close processing for devices that don't exist + * no_dev_io: i/o processing for devices that don't exist + * tty_opcl: perform tty-specific processing for open/close + * ctty_opcl: perform controlling-tty-specific processing for open/close + * ctty_io: perform controlling-tty-specific processing for I/O + * pm_setsid: perform VFS's side of setsid system call + * do_ioctl: perform the IOCTL system call */ #include "fs.h" @@ -31,7 +34,6 @@ #include #include #include "file.h" -#include "fproc.h" #include "scratchpad.h" #include "dmap.h" #include @@ -39,99 +41,79 @@ #include "vmnt.h" #include "param.h" -static void restart_reopen(int major); -static int safe_io_conversion(endpoint_t, cp_grant_id_t *, int *, - endpoint_t *, void **, size_t, u32_t *); - -static int dummyproc; - +static int block_io(endpoint_t driver_e, message *mess_ptr); +static cp_grant_id_t make_grant(endpoint_t driver_e, endpoint_t user_e, int op, + void *buf, unsigned long size); /*===========================================================================* - * dev_open * + * cdev_open * *===========================================================================*/ -int dev_open( - dev_t dev, /* device to open */ - endpoint_t proc_e, /* process to open for */ - int flags /* mode bits and flags */ -) +int cdev_open(dev_t dev, int flags) { /* Open a character device. */ - int major, r; + devmajor_t major_dev; + int r; /* Determine the major device number so as to call the device class specific * open/close routine. (This is the only routine that must check the * device number for being in range. All others can trust this check.) */ - major = major(dev); - if (major < 0 || major >= NR_DEVICES) major = 0; - if (dmap[major].dmap_driver == NONE) return(ENXIO); - r = (*dmap[major].dmap_opcl)(DEV_OPEN, dev, proc_e, flags); + major_dev = major(dev); + if (major_dev < 0 || major_dev >= NR_DEVICES) return(ENXIO); + if (dmap[major_dev].dmap_driver == NONE) return(ENXIO); + r = (*dmap[major_dev].dmap_opcl)(CDEV_OPEN, dev, fp->fp_endpoint, flags); return(r); } /*===========================================================================* - * dev_reopen * + * cdev_close * *===========================================================================*/ -int dev_reopen( - dev_t dev, /* device to open */ - int filp_no, /* filp to reopen for */ - int flags /* mode bits and flags */ -) -{ -/* Reopen a character device after a failing device driver. */ - - int major, r; - struct dmap *dp; - - /* Determine the major device number and call the device class specific - * open/close routine. (This is the only routine that must check the device - * number for being in range. All others can trust this check.) - */ - - major = major(dev); - if (major < 0 || major >= NR_DEVICES) major = 0; - dp = &dmap[major]; - if (dp->dmap_driver == NONE) return(ENXIO); - r = (*dp->dmap_opcl)(DEV_REOPEN, dev, filp_no, flags); - if (r == SUSPEND) r = OK; - return(r); -} - - -/*===========================================================================* - * dev_close * - *===========================================================================*/ -int dev_close( - dev_t dev, /* device to close */ - int filp_no -) +int cdev_close(dev_t dev) { /* Close a character device. */ - int r, major; + devmajor_t major_dev; + int r; /* See if driver is roughly valid. */ - major = major(dev); - if (major < 0 || major >= NR_DEVICES) return(ENXIO); - if (dmap[major].dmap_driver == NONE) return(ENXIO); - r = (*dmap[major].dmap_opcl)(DEV_CLOSE, dev, filp_no, 0); + major_dev = major(dev); + if (major_dev < 0 || major_dev >= NR_DEVICES) return(ENXIO); + if (dmap[major_dev].dmap_driver == NONE) return(ENXIO); + r = (*dmap[major_dev].dmap_opcl)(CDEV_CLOSE, dev, fp->fp_endpoint, 0); return(r); } /*===========================================================================* - * dev_open * + * bdev_open * *===========================================================================*/ int bdev_open(dev_t dev, int access) { /* Open a block device. */ - int major; + devmajor_t major_dev; + devminor_t minor_dev; + message dev_mess; + int r; - major = major(dev); - if (major < 0 || major >= NR_DEVICES) return(ENXIO); - if (dmap[major].dmap_driver == NONE) return(ENXIO); + major_dev = major(dev); + minor_dev = minor(dev); + if (major_dev < 0 || major_dev >= NR_DEVICES) return ENXIO; + if (dmap[major_dev].dmap_driver == NONE) return ENXIO; - return (*dmap[major].dmap_opcl)(BDEV_OPEN, dev, 0, access); + memset(&dev_mess, 0, sizeof(dev_mess)); + dev_mess.m_type = BDEV_OPEN; + dev_mess.BDEV_MINOR = minor_dev; + dev_mess.BDEV_ACCESS = 0; + if (access & R_BIT) dev_mess.BDEV_ACCESS |= BDEV_R_BIT; + if (access & W_BIT) dev_mess.BDEV_ACCESS |= BDEV_W_BIT; + dev_mess.BDEV_ID = 0; + + /* Call the task. */ + r = block_io(dmap[major_dev].dmap_driver, &dev_mess); + if (r != OK) + return r; + + return dev_mess.BDEV_STATUS; } @@ -141,27 +123,41 @@ int bdev_open(dev_t dev, int access) int bdev_close(dev_t dev) { /* Close a block device. */ - int major; + devmajor_t major_dev; + devminor_t minor_dev; + message dev_mess; + int r; - major = major(dev); - if (major < 0 || major >= NR_DEVICES) return(ENXIO); - if (dmap[major].dmap_driver == NONE) return(ENXIO); + major_dev = major(dev); + minor_dev = minor(dev); + if (major_dev < 0 || major_dev >= NR_DEVICES) return ENXIO; + if (dmap[major_dev].dmap_driver == NONE) return ENXIO; - return (*dmap[major].dmap_opcl)(BDEV_CLOSE, dev, 0, 0); + memset(&dev_mess, 0, sizeof(dev_mess)); + dev_mess.m_type = BDEV_CLOSE; + dev_mess.BDEV_MINOR = minor_dev; + dev_mess.BDEV_ID = 0; + + r = block_io(dmap[major_dev].dmap_driver, &dev_mess); + if (r != OK) + return r; + + return dev_mess.BDEV_STATUS; } /*===========================================================================* * bdev_ioctl * *===========================================================================*/ -static int bdev_ioctl(dev_t dev, endpoint_t proc_e, int req, void *buf) +static int bdev_ioctl(dev_t dev, endpoint_t proc_e, unsigned long req, + void *buf) { /* Perform an I/O control operation on a block device. */ struct dmap *dp; - u32_t dummy; cp_grant_id_t gid; message dev_mess; - int op, major_dev, minor_dev; + devmajor_t major_dev; + devminor_t minor_dev; major_dev = major(dev); minor_dev = minor(dev); @@ -169,14 +165,12 @@ static int bdev_ioctl(dev_t dev, endpoint_t proc_e, int req, void *buf) /* Determine task dmap. */ dp = &dmap[major_dev]; if (dp->dmap_driver == NONE) { - printf("VFS: dev_io: no driver for major %d\n", major_dev); + printf("VFS: bdev_ioctl: no driver for major %d\n", major_dev); return(ENXIO); } /* Set up a grant if necessary. */ - op = VFS_DEV_IOCTL; - (void) safe_io_conversion(dp->dmap_driver, &gid, &op, &proc_e, &buf, req, - &dummy); + gid = make_grant(dp->dmap_driver, proc_e, BDEV_IOCTL, buf, req); /* Set up the message passed to the task. */ memset(&dev_mess, 0, sizeof(dev_mess)); @@ -185,10 +179,11 @@ static int bdev_ioctl(dev_t dev, endpoint_t proc_e, int req, void *buf) dev_mess.BDEV_MINOR = minor_dev; dev_mess.BDEV_REQUEST = req; dev_mess.BDEV_GRANT = gid; + dev_mess.BDEV_USER = proc_e; dev_mess.BDEV_ID = 0; /* Call the task. */ - (*dp->dmap_io)(dp->dmap_driver, &dev_mess); + block_io(dp->dmap_driver, &dev_mess); /* Clean up. */ if (GRANT_VALID(gid)) cpf_revoke(gid); @@ -204,127 +199,29 @@ static int bdev_ioctl(dev_t dev, endpoint_t proc_e, int req, void *buf) /*===========================================================================* - * find_suspended_ep * + * make_grant * *===========================================================================*/ -endpoint_t find_suspended_ep(endpoint_t driver, cp_grant_id_t g) +static cp_grant_id_t make_grant(endpoint_t driver_e, endpoint_t user_e, int op, + void *buf, unsigned long bytes) { -/* A process is suspended on a driver for which VFS issued a grant. Find out - * which process it was. - */ - struct fproc *rfp; - for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { - if(rfp->fp_pid == PID_FREE) - continue; - - if(rfp->fp_blocked_on == FP_BLOCKED_ON_OTHER && - rfp->fp_task == driver && rfp->fp_grant == g) - return(rfp->fp_endpoint); - } - - return(NONE); -} - - -/*===========================================================================* - * dev_status * - *===========================================================================*/ -void dev_status(endpoint_t drv_e) -{ -/* A device sent us a notification it has something for us. Retrieve it. */ - - message st; - int major, get_more = 1; - endpoint_t endpt; - - for (major = 0; major < NR_DEVICES; major++) - if (dmap_driver_match(drv_e, major)) - break; /* 'major' is the device that sent the message */ - - if (major >= NR_DEVICES) /* Device endpoint not found; nothing to do */ - return; - - if (dev_style_asyn(dmap[major].dmap_style)) { - printf("VFS: not doing dev_status for async driver %d\n", drv_e); - return; - } - - /* Continuously send DEV_STATUS messages until the device has nothing to - * say to us anymore. */ - do { - int r; - st.m_type = DEV_STATUS; - r = drv_sendrec(drv_e, &st); - if (r == OK && st.REP_STATUS == ERESTART) r = EDEADEPT; - if (r != OK) { - printf("VFS: DEV_STATUS failed to %d: %d\n", drv_e, r); - if (r == EDEADSRCDST || r == EDEADEPT) return; - panic("VFS: couldn't sendrec for DEV_STATUS: %d", r); - } - - switch(st.m_type) { - case DEV_REVIVE: - /* We've got results for a read/write/ioctl call to a - * synchronous character driver */ - endpt = st.REP_ENDPT; - if (endpt == VFS_PROC_NR) { - endpt = find_suspended_ep(drv_e, st.REP_IO_GRANT); - if (endpt == NONE) { - printf("VFS: proc with grant %d from %d not found\n", - st.REP_IO_GRANT, st.m_source); - continue; - } - } - revive(endpt, st.REP_STATUS); - break; - case DEV_IO_READY: - /* Reply to a select request: driver is ready for I/O */ - select_reply2(st.m_source, st.DEV_MINOR, st.DEV_SEL_OPS); - break; - default: - printf("VFS: unrecognized reply %d to DEV_STATUS\n",st.m_type); - /* Fall through. */ - case DEV_NO_STATUS: - get_more = 0; - break; - } - } while(get_more); -} - -/*===========================================================================* - * safe_io_conversion * - *===========================================================================*/ -static int safe_io_conversion(driver, gid, op, io_ept, buf, bytes, pos_lo) -endpoint_t driver; -cp_grant_id_t *gid; -int *op; -endpoint_t *io_ept; -void **buf; -size_t bytes; -u32_t *pos_lo; -{ -/* Convert operation to the 'safe' variant (i.e., grant based) if applicable. - * If no copying of data is involved, there is also no need to convert. */ - - int access = 0; +/* Create a magic grant for the given operation and buffer. */ + cp_grant_id_t gid; + int access; size_t size; - *gid = GRANT_INVALID; /* Grant to buffer */ - - switch(*op) { - case VFS_DEV_READ: - case VFS_DEV_WRITE: - /* Change to safe op. */ - *op = (*op == VFS_DEV_READ) ? DEV_READ_S : DEV_WRITE_S; - *gid = cpf_grant_magic(driver, *io_ept, (vir_bytes) *buf, bytes, - *op == DEV_READ_S ? CPF_WRITE : CPF_READ); - if (*gid < 0) - panic("VFS: cpf_grant_magic of READ/WRITE buffer failed"); + switch (op) { + case CDEV_READ: + case CDEV_WRITE: + gid = cpf_grant_magic(driver_e, user_e, (vir_bytes) buf, + (size_t) bytes, op == CDEV_READ ? CPF_WRITE : CPF_READ); break; - case VFS_DEV_IOCTL: - *pos_lo = *io_ept; /* Old endpoint in POSITION field. */ - *op = DEV_IOCTL_S; - /* For IOCTLs, the bytes parameter encodes requested access method - * and buffer size */ + + case CDEV_IOCTL: + case BDEV_IOCTL: + /* For IOCTLs, the bytes parameter contains the IOCTL request. + * This request encodes the requested access method and buffer size. + */ + access = 0; if(_MINIX_IOCTL_IOR(bytes)) access |= CPF_WRITE; if(_MINIX_IOCTL_IOW(bytes)) access |= CPF_READ; if(_MINIX_IOCTL_BIG(bytes)) @@ -332,203 +229,168 @@ u32_t *pos_lo; else size = _MINIX_IOCTL_SIZE(bytes); - /* Grant access to the buffer even if no I/O happens with the ioctl, in - * order to disambiguate requests with DEV_IOCTL_S. + /* Grant access to the buffer even if no I/O happens with the ioctl, + * although now that we no longer identify responses based on grants, + * this is not strictly necessary. */ - *gid = cpf_grant_magic(driver, *io_ept, (vir_bytes) *buf, size, access); - if (*gid < 0) - panic("VFS: cpf_grant_magic IOCTL buffer failed"); + gid = cpf_grant_magic(driver_e, user_e, (vir_bytes) buf, size, access); + break; - break; - case VFS_DEV_SELECT: - *op = DEV_SELECT; - break; - default: - panic("VFS: unknown operation %d for safe I/O conversion", *op); + default: + panic("VFS: unknown operation %d", op); } - /* If we have converted to a safe operation, I/O endpoint becomes VFS if it - * wasn't already. - */ - if(GRANT_VALID(*gid)) { - *io_ept = VFS_PROC_NR; - return(1); - } + if (!GRANT_VALID(gid)) + panic("VFS: cpf_grant_magic failed"); - /* Not converted to a safe operation (because there is no copying involved in - * this operation). - */ - return(0); + return gid; } -static int cancel_nblock(struct dmap * dp, - int minor, - int call, - endpoint_t ioproc, - cp_grant_id_t gid) -{ - message dev_mess; - - dev_mess.m_type = CANCEL; - dev_mess.USER_ENDPT = ioproc; - dev_mess.IO_GRANT = (char *) gid; - - /* This R_BIT/W_BIT check taken from suspend()/unpause() - * logic. Mode is expected in the COUNT field. - */ - dev_mess.COUNT = 0; - if (call == READ) - dev_mess.COUNT = R_BIT; - else if (call == WRITE) - dev_mess.COUNT = W_BIT; - dev_mess.DEVICE = minor; - (*dp->dmap_io)(dp->dmap_driver, &dev_mess); - - return dev_mess.REP_STATUS; -} /*===========================================================================* - * dev_io * + * cdev_io * *===========================================================================*/ -int dev_io( - int op, /* DEV_READ, DEV_WRITE, DEV_IOCTL, etc. */ +int cdev_io( + int op, /* CDEV_READ, CDEV_WRITE, or CDEV_IOCTL */ dev_t dev, /* major-minor device number */ - endpoint_t proc_e, /* in whose address space is buf? */ + endpoint_t proc_e, /* in whose address space is buf? */ void *buf, /* virtual address of the buffer */ u64_t pos, /* byte position */ - size_t bytes, /* how many bytes to transfer */ - int flags, /* special flags, like O_NONBLOCK */ - int suspend_reopen /* Just suspend the process */ + unsigned long bytes, /* how many bytes to transfer, or request */ + int flags /* special flags, like O_NONBLOCK */ ) { -/* Read from or write to a device. The parameter 'dev' tells which one. */ +/* Initiate a read, write, or ioctl to a character device. */ struct dmap *dp; - u32_t pos_lo, pos_high; message dev_mess; - cp_grant_id_t gid = GRANT_INVALID; - int safe, minor_dev, major_dev; - void *buf_used; - endpoint_t ioproc; - int ret, is_asyn; + cp_grant_id_t gid; + devmajor_t major_dev; + devminor_t minor_dev; + int r, slot; - pos_lo = ex64lo(pos); - pos_high = ex64hi(pos); - major_dev = major(dev); - minor_dev = minor(dev); + assert(op == CDEV_READ || op == CDEV_WRITE || op == CDEV_IOCTL); /* Determine task dmap. */ + major_dev = major(dev); + minor_dev = minor(dev); dp = &dmap[major_dev]; /* See if driver is roughly valid. */ if (dp->dmap_driver == NONE) return(ENXIO); - if (suspend_reopen) { - /* Suspend user. */ - fp->fp_grant = GRANT_INVALID; - fp->fp_ioproc = NONE; - wait_for(dp->dmap_driver); - fp->fp_flags |= FP_SUSP_REOPEN; - return(SUSPEND); - } - - if(isokendpt(dp->dmap_driver, &dummyproc) != OK) { + if(isokendpt(dp->dmap_driver, &slot) != OK) { printf("VFS: dev_io: old driver for major %x (%d)\n", major_dev, dp->dmap_driver); return(ENXIO); } - /* By default, these are right. */ - dev_mess.USER_ENDPT = proc_e; - dev_mess.ADDRESS = buf; - - /* Convert DEV_* to DEV_*_S variants. */ - buf_used = buf; - safe = safe_io_conversion(dp->dmap_driver, &gid, &op, - (endpoint_t *) &dev_mess.USER_ENDPT, &buf_used, - bytes, &pos_lo); - - is_asyn = dev_style_asyn(dp->dmap_style); - - /* If the safe conversion was done, set the IO_GRANT to - * the grant id. - */ - if(safe) dev_mess.IO_GRANT = (char *) gid; - - /* Set up the rest of the message passed to task. */ - dev_mess.m_type = op; - dev_mess.DEVICE = minor_dev; - dev_mess.POSITION = pos_lo; - dev_mess.COUNT = bytes; - dev_mess.HIGHPOS = pos_high; - dev_mess.FLAGS = 0; + /* Create a grant for the buffer provided by the user process. */ + gid = make_grant(dp->dmap_driver, proc_e, op, buf, bytes); + /* Set up the rest of the message that will be sent to the driver. */ + memset(&dev_mess, 0, sizeof(dev_mess)); + dev_mess.m_type = op; + dev_mess.CDEV_MINOR = minor_dev; + if (op == CDEV_IOCTL) { + dev_mess.CDEV_REQUEST = bytes; + dev_mess.CDEV_USER = proc_e; + } else { + dev_mess.CDEV_POS_LO = ex64lo(pos); + dev_mess.CDEV_POS_HI = ex64hi(pos); + dev_mess.CDEV_COUNT = (size_t) bytes; + } + dev_mess.CDEV_ID = proc_e; + dev_mess.CDEV_GRANT = gid; + dev_mess.CDEV_FLAGS = 0; if (flags & O_NONBLOCK) - dev_mess.FLAGS |= FLG_OP_NONBLOCK; + dev_mess.CDEV_FLAGS |= CDEV_NONBLOCK; - /* This will be used if the i/o is suspended. */ - ioproc = dev_mess.USER_ENDPT; + /* Send the request to the driver. */ + r = (*dp->dmap_io)(dp->dmap_driver, &dev_mess); - /* Call the task. */ - (*dp->dmap_io)(dp->dmap_driver, &dev_mess); + if (r != OK) { + cpf_revoke(gid); - if(dp->dmap_driver == NONE) { - /* Driver has vanished. */ - printf("VFS: driver gone?!\n"); - if(safe) cpf_revoke(gid); - return(EIO); + return r; } - ret = dev_mess.REP_STATUS; + /* Suspend the calling process until a reply arrives. */ + wait_for(dp->dmap_driver); + assert(!GRANT_VALID(fp->fp_grant)); + fp->fp_grant = gid; /* revoke this when unsuspended. */ - /* Task has completed. See if call completed. */ - if (ret == SUSPEND) { - if ((flags & O_NONBLOCK) && !is_asyn) { - /* Not supposed to block. */ - ret = cancel_nblock(dp, minor_dev, job_call_nr, ioproc, gid); - if (ret == EINTR) - ret = EAGAIN; - } else { - /* select() will do suspending itself. */ - if(op != DEV_SELECT) { - /* Suspend user. */ - wait_for(dp->dmap_driver); - } - assert(!GRANT_VALID(fp->fp_grant)); - fp->fp_grant = gid; /* revoke this when unsuspended. */ - fp->fp_ioproc = ioproc; - - if ((flags & O_NONBLOCK) && !is_asyn) { - /* Not supposed to block, send cancel message */ - cancel_nblock(dp, minor_dev, job_call_nr, ioproc, gid); - /* - * FIXME Should do something about EINTR -> EAGAIN - * mapping - */ - } - return(SUSPEND); - } - } - - /* No suspend, or cancelled suspend, so I/O is over and can be cleaned up. */ - if(safe) cpf_revoke(gid); - - return ret; + return SUSPEND; } + +/*===========================================================================* + * clone_cdev * + *===========================================================================*/ +static int cdev_clone(dev_t dev, endpoint_t proc_e, devminor_t new_minor) +{ +/* A new minor device number has been returned. Request PFS to create a + * temporary device file to hold it. + */ + struct vnode *vp; + struct node_details res; + int r; + + assert(proc_e == fp->fp_endpoint); + + /* Device number of the new device. */ + dev = makedev(major(dev), new_minor); + + /* Issue request */ + r = req_newnode(PFS_PROC_NR, fp->fp_effuid, fp->fp_effgid, + ALL_MODES | I_CHAR_SPECIAL, dev, &res); + if (r != OK) { + (void) gen_opcl(CDEV_CLOSE, dev, proc_e, 0); + return r; + } + + /* Drop old node and use the new values */ + if ((vp = get_free_vnode()) == NULL) { + req_putnode(PFS_PROC_NR, res.inode_nr, 1); /* is this right? */ + (void) gen_opcl(CDEV_CLOSE, dev, proc_e, 0); + return(err_code); + } + lock_vnode(vp, VNODE_OPCL); + + assert(fp->fp_filp[scratch(fp).file.fd_nr] != NULL); + unlock_vnode(fp->fp_filp[scratch(fp).file.fd_nr]->filp_vno); + put_vnode(fp->fp_filp[scratch(fp).file.fd_nr]->filp_vno); + + vp->v_fs_e = res.fs_e; + vp->v_vmnt = NULL; + vp->v_dev = NO_DEV; + vp->v_fs_e = res.fs_e; + vp->v_inode_nr = res.inode_nr; + vp->v_mode = res.fmode; + vp->v_sdev = dev; + vp->v_fs_count = 1; + vp->v_ref_count = 1; + fp->fp_filp[scratch(fp).file.fd_nr]->filp_vno = vp; + + return OK; +} + + /*===========================================================================* * gen_opcl * *===========================================================================*/ int gen_opcl( - int op, /* operation, (B)DEV_OPEN or (B)DEV_CLOSE */ + int op, /* operation, CDEV_OPEN or CDEV_CLOSE */ dev_t dev, /* device to open or close */ endpoint_t proc_e, /* process to open/close for */ int flags /* mode bits and flags */ ) { /* Called from the dmap struct on opens & closes of special files.*/ - int r, minor_dev, major_dev, is_bdev; + devmajor_t major_dev; + devminor_t minor_dev, new_minor; struct dmap *dp; message dev_mess; + int r, r2; /* Determine task dmap. */ major_dev = major(dev); @@ -537,48 +399,70 @@ int gen_opcl( dp = &dmap[major_dev]; assert(dp->dmap_driver != NONE); - is_bdev = IS_BDEV_RQ(op); + assert(!IS_BDEV_RQ(op)); - if (is_bdev) { - memset(&dev_mess, 0, sizeof(dev_mess)); - dev_mess.m_type = op; - dev_mess.BDEV_MINOR = minor_dev; - dev_mess.BDEV_ACCESS = flags; - dev_mess.BDEV_ID = 0; - } else { - dev_mess.m_type = op; - dev_mess.DEVICE = minor_dev; - dev_mess.USER_ENDPT = proc_e; - dev_mess.COUNT = flags; + /* Prepare the request message. */ + memset(&dev_mess, 0, sizeof(dev_mess)); + + dev_mess.m_type = op; + dev_mess.CDEV_MINOR = minor_dev; + dev_mess.CDEV_ID = proc_e; + if (op == CDEV_OPEN) { + dev_mess.CDEV_USER = proc_e; + dev_mess.CDEV_ACCESS = 0; + if (flags & R_BIT) dev_mess.CDEV_ACCESS |= CDEV_R_BIT; + if (flags & W_BIT) dev_mess.CDEV_ACCESS |= CDEV_W_BIT; + if (flags & O_NOCTTY) dev_mess.CDEV_ACCESS |= CDEV_NOCTTY; } /* Call the task. */ r = (*dp->dmap_io)(dp->dmap_driver, &dev_mess); + if (r != OK) return(r); - if (op == DEV_OPEN && dp->dmap_style == STYLE_DEVA) { - fp->fp_task = dp->dmap_driver; - worker_wait(); + /* Block the thread waiting for a reply. */ + fp->fp_task = dp->dmap_driver; + self->w_task = dp->dmap_driver; + self->w_drv_sendrec = &dev_mess; + + worker_wait(); + + self->w_task = NONE; + self->w_drv_sendrec = NULL; + + r = dev_mess.CDEV_STATUS; + + /* Some devices need special processing upon open. Such a device is "cloned", + * i.e. on a succesful open it is replaced by a new device with a new unique + * minor device number. This new device number identifies a new object (such + * as a new network connection) that has been allocated within a task. + */ + if (op == CDEV_OPEN && r >= 0) { + if (r & CDEV_CLONED) { + new_minor = r & ~(CDEV_CLONED | CDEV_CTTY); + r &= CDEV_CTTY; + if ((r2 = cdev_clone(dev, proc_e, new_minor)) < 0) + r = r2; + } else + r &= CDEV_CTTY; + /* Upon success, we now return either OK or CDEV_CTTY. */ } - if (is_bdev) - return(dev_mess.BDEV_STATUS); - else - return(dev_mess.REP_STATUS); + /* Return the result from the driver. */ + return(r); } /*===========================================================================* * tty_opcl * *===========================================================================*/ int tty_opcl( - int op, /* operation, DEV_OPEN or DEV_CLOSE */ + int op, /* operation, CDEV_OPEN or CDEV_CLOSE */ dev_t dev, /* device to open or close */ endpoint_t proc_e, /* process to open/close for */ int flags /* mode bits and flags */ ) { /* This procedure is called from the dmap struct on tty open/close. */ - int r; register struct fproc *rfp; @@ -600,7 +484,7 @@ int tty_opcl( r = gen_opcl(op, dev, proc_e, flags); /* Did this call make the tty the controlling tty? */ - if (r == 1) { + if (r >= 0 && (r & CDEV_CTTY)) { fp->fp_tty = dev; r = OK; } @@ -613,7 +497,7 @@ int tty_opcl( * ctty_opcl * *===========================================================================*/ int ctty_opcl( - int op, /* operation, DEV_OPEN or DEV_CLOSE */ + int op, /* operation, CDEV_OPEN or CDEV_CLOSE */ dev_t UNUSED(dev), /* device to open or close */ endpoint_t UNUSED(proc_e), /* process to open/close for */ int UNUSED(flags) /* mode bits and flags */ @@ -655,16 +539,16 @@ void pm_setsid(endpoint_t proc_e) int do_ioctl(message *UNUSED(m_out)) { /* Perform the ioctl(ls_fd, request, argx) system call */ - - int r = OK, suspend_reopen, ioctlrequest; + unsigned long ioctlrequest; + int r = OK; struct filp *f; register struct vnode *vp; dev_t dev; void *argx; - scratch(fp).file.fd_nr = job_m_in.ls_fd; - ioctlrequest = job_m_in.REQUEST; - argx = job_m_in.ADDRESS; + scratch(fp).file.fd_nr = job_m_in.VFS_IOCTL_FD; + ioctlrequest = job_m_in.VFS_IOCTL_REQ; + argx = job_m_in.VFS_IOCTL_ARG; if ((f = get_filp(scratch(fp).file.fd_nr, VNODE_READ)) == NULL) return(err_code); @@ -674,14 +558,13 @@ int do_ioctl(message *UNUSED(m_out)) } if (r == OK) { - suspend_reopen = (f->filp_state & FS_NEEDS_REOPEN); dev = (dev_t) vp->v_sdev; if (S_ISBLK(vp->v_mode)) r = bdev_ioctl(dev, who_e, ioctlrequest, argx); else - r = dev_io(VFS_DEV_IOCTL, dev, who_e, argx, ((u64_t)(0)), - ioctlrequest, f->filp_flags, suspend_reopen); + r = cdev_io(CDEV_IOCTL, dev, who_e, argx, 0, ioctlrequest, + f->filp_flags); } unlock_filp(f); @@ -691,31 +574,98 @@ int do_ioctl(message *UNUSED(m_out)) /*===========================================================================* - * gen_io * + * cdev_select * *===========================================================================*/ -int gen_io(driver_e, mess_ptr) -endpoint_t driver_e; /* which endpoint to call */ -message *mess_ptr; /* pointer to message for task */ +int cdev_select(dev_t dev, int ops) { -/* All file system I/O ultimately comes down to I/O on major/minor device - * pairs. These lead to calls on the following routines via the dmap table. +/* Initiate a select call on a device. Return OK iff the request was sent. */ + devmajor_t major_dev; + devminor_t minor_dev; + message dev_mess; + struct dmap *dp; + + major_dev = major(dev); + minor_dev = minor(dev); + dp = &dmap[major_dev]; + + if (dp->dmap_driver == NONE) return ENXIO; + + memset(&dev_mess, 0, sizeof(dev_mess)); + + dev_mess.m_type = CDEV_SELECT; + dev_mess.CDEV_MINOR = minor_dev; + dev_mess.CDEV_OPS = ops; + + /* Call the task. */ + return (*dp->dmap_io)(dp->dmap_driver, &dev_mess); +} + + +/*===========================================================================* + * cdev_cancel * + *===========================================================================*/ +int cdev_cancel(dev_t dev) +{ +/* Cancel an I/O request, blocking until it has been cancelled. */ + devmajor_t major_dev; + devminor_t minor_dev; + message dev_mess; + struct dmap *dp; + int r; + + major_dev = major(dev); + minor_dev = minor(dev); + dp = &dmap[major_dev]; + + memset(&dev_mess, 0, sizeof(dev_mess)); + + dev_mess.m_type = CDEV_CANCEL; + dev_mess.CDEV_MINOR = minor_dev; + dev_mess.CDEV_ID = fp->fp_endpoint; + + r = (*dp->dmap_io)(fp->fp_task, &dev_mess); + if (r != OK) return r; /* ctty_io returned an error? should be impossible */ + + /* Suspend this thread until we have received the response. */ + fp->fp_task = dp->dmap_driver; + self->w_task = dp->dmap_driver; + self->w_drv_sendrec = &dev_mess; + + worker_wait(); + + self->w_task = NONE; + self->w_drv_sendrec = NULL; + + /* Clean up and return the result (note: the request may have completed). */ + if (GRANT_VALID(fp->fp_grant)) { + (void) cpf_revoke(fp->fp_grant); + fp->fp_grant = GRANT_INVALID; + } + + r = dev_mess.CDEV_STATUS; + return (r == EAGAIN) ? EINTR : r; +} + + +/*===========================================================================* + * block_io * + *===========================================================================*/ +static int block_io(endpoint_t driver_e, message *mess_ptr) +{ +/* Perform I/O on a block device. The current thread is suspended until a reply + * comes in from the driver. */ - int r, status = OK, proc_e = NONE, is_bdev, retry_count; + int r, status, retry_count; message mess_retry; - is_bdev = IS_BDEV_RQ(mess_ptr->m_type); + assert(IS_BDEV_RQ(mess_ptr->m_type)); mess_retry = *mess_ptr; retry_count = 0; - if (!is_bdev) proc_e = mess_ptr->USER_ENDPT; - do { r = drv_sendrec(driver_e, mess_ptr); if (r == OK) { - if (is_bdev) - status = mess_ptr->BDEV_STATUS; - else - status = mess_ptr->REP_STATUS; + status = mess_ptr->BDEV_STATUS; if (status == ERESTART) { r = EDEADEPT; *mess_ptr = mess_retry; @@ -739,44 +689,27 @@ message *mess_ptr; /* pointer to message for task */ printf("VFS: ELOCKED talking to %d\n", driver_e); return(r); } - panic("call_task: can't send/receive: %d", r); + panic("block_io: can't send/receive: %d", r); } - /* Did the process we did the sendrec() for get a result? */ - if (!is_bdev && mess_ptr->REP_ENDPT != proc_e && mess_ptr->m_type != EIO) { - printf("VFS: strange device reply from %d, type = %d, " - "proc = %d (not %d) (2) ignored\n", mess_ptr->m_source, - mess_ptr->m_type, proc_e, mess_ptr->REP_ENDPT); - - return(EIO); - } else if (!IS_DRV_REPLY(mess_ptr->m_type)) - return(EIO); - return(OK); } /*===========================================================================* - * asyn_io * + * gen_io * *===========================================================================*/ -int asyn_io(endpoint_t drv_e, message *mess_ptr) +int gen_io(endpoint_t drv_e, message *mess_ptr) { -/* All file system I/O ultimately comes down to I/O on major/minor device - * pairs. These lead to calls on the following routines via the dmap table. - */ - +/* Initiate I/O to a character driver. Do not wait for the reply. */ int r; assert(!IS_BDEV_RQ(mess_ptr->m_type)); - self->w_drv_sendrec = mess_ptr; /* Remember where result should be stored */ - self->w_task = drv_e; r = asynsend3(drv_e, mess_ptr, AMF_NOREPLY); - if (r != OK) panic("VFS: asynsend in asyn_io failed: %d", r); + if (r != OK) panic("VFS: asynsend in gen_io failed: %d", r); - /* Fake a SUSPEND */ - mess_ptr->REP_STATUS = SUSPEND; return(OK); } @@ -793,31 +726,29 @@ int ctty_io( * is to change the message to use the controlling terminal, instead of the * major/minor pair for /dev/tty itself. */ - struct dmap *dp; + int slot; if (fp->fp_tty == 0) { /* No controlling tty present anymore, return an I/O error. */ - mess_ptr->REP_STATUS = EIO; + return(EIO); } else { /* Substitute the controlling terminal device. */ dp = &dmap[major(fp->fp_tty)]; - mess_ptr->DEVICE = minor(fp->fp_tty); + mess_ptr->CDEV_MINOR = minor(fp->fp_tty); if (dp->dmap_driver == NONE) { printf("FS: ctty_io: no driver for dev\n"); return(EIO); } - if (isokendpt(dp->dmap_driver, &dummyproc) != OK) { + if (isokendpt(dp->dmap_driver, &slot) != OK) { printf("VFS: ctty_io: old driver %d\n", dp->dmap_driver); return(EIO); } - (*dp->dmap_io)(dp->dmap_driver, mess_ptr); + return (*dp->dmap_io)(dp->dmap_driver, mess_ptr); } - - return(OK); } @@ -825,7 +756,7 @@ int ctty_io( * no_dev * *===========================================================================*/ int no_dev( - int UNUSED(op), /* operation, DEV_OPEN or DEV_CLOSE */ + int UNUSED(op), /* operation, CDEV_OPEN or CDEV_CLOSE */ dev_t UNUSED(dev), /* device to open or close */ endpoint_t UNUSED(proc), /* process to open/close for */ int UNUSED(flags) /* mode bits and flags */ @@ -846,105 +777,10 @@ int no_dev_io(endpoint_t UNUSED(proc), message *UNUSED(m)) } -/*===========================================================================* - * clone_opcl * - *===========================================================================*/ -int clone_opcl( - int op, /* operation, DEV_OPEN or DEV_CLOSE */ - dev_t dev, /* device to open or close */ - endpoint_t proc_e, /* process to open/close for */ - int flags /* mode bits and flags */ -) -{ -/* Some devices need special processing upon open. Such a device is "cloned", - * i.e. on a succesful open it is replaced by a new device with a new unique - * minor device number. This new device number identifies a new object (such - * as a new network connection) that has been allocated within a task. - */ - struct dmap *dp; - int r, minor_dev, major_dev; - message dev_mess; - - assert(!IS_BDEV_RQ(op)); - - /* Determine task dmap. */ - minor_dev = minor(dev); - major_dev = major(dev); - assert(major_dev >= 0 && major_dev < NR_DEVICES); - dp = &dmap[major_dev]; - assert(dp->dmap_driver != NONE); - - dev_mess.m_type = op; - dev_mess.DEVICE = minor_dev; - dev_mess.USER_ENDPT = proc_e; - dev_mess.COUNT = flags; - - if(isokendpt(dp->dmap_driver, &dummyproc) != OK) { - printf("VFS clone_opcl: bad driver endpoint for major %d (%d)\n", - major_dev, dp->dmap_driver); - return(ENXIO); - } - - /* Call the task. */ - r = (*dp->dmap_io)(dp->dmap_driver, &dev_mess); - if (r != OK) return(r); - - if (op == DEV_OPEN && dev_style_asyn(dp->dmap_style)) { - /* Wait for reply when driver is asynchronous */ - fp->fp_task = dp->dmap_driver; - worker_wait(); - } - - if (op == DEV_OPEN && dev_mess.REP_STATUS >= 0) { - if (dev_mess.REP_STATUS != minor_dev) { - struct vnode *vp; - struct node_details res; - - /* A new minor device number has been returned. - * Request PFS to create a temporary device file to hold it. - */ - - /* Device number of the new device. */ - dev = makedev(major(dev), minor(dev_mess.REP_STATUS)); - - /* Issue request */ - r = req_newnode(PFS_PROC_NR, fp->fp_effuid, fp->fp_effgid, - ALL_MODES | I_CHAR_SPECIAL, dev, &res); - if (r != OK) { - (void) clone_opcl(DEV_CLOSE, dev, proc_e, 0); - return r; - } - - /* Drop old node and use the new values */ - if ((vp = get_free_vnode()) == NULL) - return(err_code); - lock_vnode(vp, VNODE_OPCL); - - assert(FD_ISSET(scratch(fp).file.fd_nr, &fp->fp_filp_inuse)); - unlock_vnode(fp->fp_filp[scratch(fp).file.fd_nr]->filp_vno); - put_vnode(fp->fp_filp[scratch(fp).file.fd_nr]->filp_vno); - - vp->v_fs_e = res.fs_e; - vp->v_vmnt = NULL; - vp->v_dev = NO_DEV; - vp->v_fs_e = res.fs_e; - vp->v_inode_nr = res.inode_nr; - vp->v_mode = res.fmode; - vp->v_sdev = dev; - vp->v_fs_count = 1; - vp->v_ref_count = 1; - fp->fp_filp[scratch(fp).file.fd_nr]->filp_vno = vp; - } - dev_mess.REP_STATUS = OK; - } - return(dev_mess.REP_STATUS); -} - - /*===========================================================================* * bdev_up * *===========================================================================*/ -void bdev_up(int maj) +void bdev_up(devmajor_t maj) { /* A new block device driver has been mapped in. This may affect both mounted * file systems and open block-special files. @@ -1000,258 +836,112 @@ void bdev_up(int maj) printf("VFSdev_up: error sending new driver label to %d\n", ROOT_FS_E); } - } /*===========================================================================* - * cdev_up * + * cdev_generic_reply * *===========================================================================*/ -void cdev_up(int maj) -{ - /* A new character device driver has been mapped in. - */ - int needs_reopen, fd_nr; - struct filp *rfilp; - struct fproc *rfp; - struct vnode *vp; - - /* Look for processes that are suspended in an OPEN call. Set FP_SUSP_REOPEN - * to indicate that this process was suspended before the call to dev_up. - */ - for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { - if(rfp->fp_pid == PID_FREE) continue; - if(rfp->fp_blocked_on != FP_BLOCKED_ON_DOPEN) continue; - - fd_nr = scratch(rfp).file.fd_nr; - printf("VFS: dev_up: found process in FP_BLOCKED_ON_DOPEN, fd %d\n", - fd_nr); - rfilp = rfp->fp_filp[fd_nr]; - vp = rfilp->filp_vno; - if (!vp) panic("VFS: cdev_up: no vp"); - if (!S_ISCHR(vp->v_mode)) continue; - if (major(vp->v_sdev) != maj) continue; - - rfp->fp_flags |= FP_SUSP_REOPEN; - } - - needs_reopen= FALSE; - for (rfilp = filp; rfilp < &filp[NR_FILPS]; rfilp++) { - if (rfilp->filp_count < 1 || !(vp = rfilp->filp_vno)) continue; - if (major(vp->v_sdev) != maj) continue; - if (!S_ISCHR(vp->v_mode)) continue; - - rfilp->filp_state |= FS_NEEDS_REOPEN; - needs_reopen = TRUE; - } - - if (needs_reopen) - restart_reopen(maj); -} - -/*===========================================================================* - * open_reply * - *===========================================================================*/ -void open_reply(void) +static void cdev_generic_reply(message *m_ptr) { +/* A character driver has results for an open, close, read, write, or ioctl + * call (i.e., everything except select). There may be a thread waiting for + * these results as part of an ongoing open, close, or (for read/write/ioctl) + * cancel call. If so, wake up that thread; if not, send a reply to the + * requesting process. This function MUST NOT block its calling thread. + */ struct fproc *rfp; struct worker_thread *wp; endpoint_t proc_e; int slot; - proc_e = job_m_in.REP_ENDPT; - if (isokendpt(proc_e, &slot) != OK) return; + proc_e = m_ptr->CDEV_ID; + + if (m_ptr->CDEV_STATUS == SUSPEND) { + printf("VFS: got SUSPEND from %d, not reviving\n", m_ptr->m_source); + return; + } + + if (isokendpt(proc_e, &slot) != OK) { + printf("VFS: proc %d from %d not found\n", proc_e, m_ptr->m_source); + return; + } rfp = &fproc[slot]; - wp = worker_get(rfp->fp_wtid); + wp = rfp->fp_worker; + if (wp != NULL && wp->w_task == who_e) { + assert(!fp_is_blocked(rfp)); + *wp->w_drv_sendrec = *m_ptr; + worker_signal(wp); /* Continue open/close/cancel */ + } else if (rfp->fp_blocked_on != FP_BLOCKED_ON_OTHER || + rfp->fp_task != m_ptr->m_source) { + /* This would typically be caused by a protocol error, i.e. a driver + * not properly following the character driver protocol rules. + */ + printf("VFS: proc %d not blocked on %d\n", proc_e, m_ptr->m_source); + } else { + revive(proc_e, m_ptr->CDEV_STATUS); + } +} + + +/*===========================================================================* + * cdev_reply * + *===========================================================================*/ +void cdev_reply(void) +{ +/* A character driver has results for us. */ + + if (get_dmap(who_e) == NULL) { + printf("VFS: ignoring char dev reply from unknown driver %d\n", who_e); + return; + } + + switch (call_nr) { + case CDEV_REPLY: + cdev_generic_reply(&m_in); + break; + case CDEV_SEL1_REPLY: + select_reply1(m_in.m_source, m_in.CDEV_MINOR, m_in.CDEV_STATUS); + break; + case CDEV_SEL2_REPLY: + select_reply2(m_in.m_source, m_in.CDEV_MINOR, m_in.CDEV_STATUS); + break; + default: + printf("VFS: char driver %u sent unknown reply %x\n", who_e, call_nr); + } +} + + +/*===========================================================================* + * bdev_reply * + *===========================================================================*/ +void bdev_reply(void) +{ +/* A block driver has results for a call. There must be a thread waiting for + * these results - wake it up. This function MUST NOT block its calling thread. + */ + struct worker_thread *wp; + struct dmap *dp; + + if ((dp = get_dmap(who_e)) == NULL) { + printf("VFS: ignoring block dev reply from unknown driver %d\n", + who_e); + return; + } + + if (dp->dmap_servicing == INVALID_THREAD) { + printf("VFS: ignoring spurious block dev reply from %d\n", who_e); + return; + } + + wp = worker_get(dp->dmap_servicing); if (wp == NULL || wp->w_task != who_e) { printf("VFS: no worker thread waiting for a reply from %d\n", who_e); return; } - *wp->w_drv_sendrec = job_m_in; + + assert(wp->w_drv_sendrec != NULL); + *wp->w_drv_sendrec = m_in; wp->w_drv_sendrec = NULL; - wp->w_task = NONE; - worker_signal(wp); /* Continue open */ -} - -/*===========================================================================* - * dev_reply * - *===========================================================================*/ -void dev_reply(struct dmap *dp) -{ - struct worker_thread *wp; - - assert(dp != NULL); - assert(dp->dmap_servicing != NONE); - - wp = worker_get(dp->dmap_servicing); - if (wp == NULL || wp->w_task != who_e) { - printf("VFS: no worker thread waiting for a reply from %d\n", - who_e); - return; - } - - assert(wp->w_drv_sendrec != NULL); - *wp->w_drv_sendrec = m_in; - wp->w_drv_sendrec = NULL; - worker_signal(wp); -} - -/*===========================================================================* - * restart_reopen * - *===========================================================================*/ -static void restart_reopen(maj) -int maj; -{ - int n, r, minor_dev, major_dev, fd_nr; - endpoint_t driver_e; - struct vnode *vp; - struct filp *rfilp; - struct fproc *rfp; - message m_out; - memset(&m_out, 0, sizeof(m_out)); - - if (maj < 0 || maj >= NR_DEVICES) panic("VFS: out-of-bound major"); - - for (rfilp = filp; rfilp < &filp[NR_FILPS]; rfilp++) { - if (rfilp->filp_count < 1 || !(vp = rfilp->filp_vno)) continue; - if (!(rfilp->filp_state & FS_NEEDS_REOPEN)) continue; - if (!S_ISCHR(vp->v_mode)) continue; - - major_dev = major(vp->v_sdev); - minor_dev = minor(vp->v_sdev); - if (major_dev != maj) continue; - - if (rfilp->filp_flags & O_REOPEN) { - /* Try to reopen a file upon driver restart */ - r = dev_reopen(vp->v_sdev, rfilp-filp, - rfilp->filp_mode & (R_BIT|W_BIT)); - - if (r == OK) - return; - - printf("VFS: file on dev %d/%d re-open failed: %d\n", - major_dev, minor_dev, r); - } - - /* File descriptor is to be closed when driver restarts. */ - n = invalidate_filp(rfilp); - if (n != rfilp->filp_count) { - printf("VFS: warning: invalidate/count " - "discrepancy (%d, %d)\n", n, rfilp->filp_count); - } - rfilp->filp_count = 0; - - /* We have to clean up this filp and vnode, but can't do that yet as - * it's locked by a worker thread. Start a new job to garbage collect - * invalidated filps associated with this device driver. - */ - sys_worker_start(do_filp_gc); - } - - /* Nothing more to re-open. Restart suspended processes */ - driver_e = dmap[maj].dmap_driver; - for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { - if(rfp->fp_pid == PID_FREE) continue; - if(rfp->fp_blocked_on == FP_BLOCKED_ON_OTHER && - rfp->fp_task == driver_e && (rfp->fp_flags & FP_SUSP_REOPEN)) { - rfp->fp_flags &= ~FP_SUSP_REOPEN; - rfp->fp_blocked_on = FP_BLOCKED_ON_NONE; - reply(&m_out, rfp->fp_endpoint, ERESTART); - } - } - - /* Look for processes that are suspened in an OPEN call */ - for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { - if (rfp->fp_pid == PID_FREE) continue; - if (rfp->fp_blocked_on == FP_BLOCKED_ON_DOPEN || - !(rfp->fp_flags & FP_SUSP_REOPEN)) continue; - - fd_nr = scratch(rfp).file.fd_nr; - printf("VFS: restart_reopen: process in FP_BLOCKED_ON_DOPEN fd=%d\n", - fd_nr); - rfilp = rfp->fp_filp[fd_nr]; - - if (!rfilp) { - /* Open failed, and automatic reopen was not requested */ - rfp->fp_blocked_on = FP_BLOCKED_ON_NONE; - FD_CLR(fd_nr, &rfp->fp_filp_inuse); - reply(&m_out, rfp->fp_endpoint, EIO); - continue; - } - - vp = rfilp->filp_vno; - if (!vp) panic("VFS: restart_reopen: no vp"); - if (!S_ISCHR(vp->v_mode)) continue; - if (major(vp->v_sdev) != maj) continue; - - rfp->fp_blocked_on = FP_BLOCKED_ON_NONE; - reply(&m_out, rfp->fp_endpoint, fd_nr); - } -} - - -/*===========================================================================* - * reopen_reply * - *===========================================================================*/ -void reopen_reply() -{ - endpoint_t driver_e; - int filp_no, status, maj; - struct filp *rfilp; - struct vnode *vp; - struct dmap *dp; - - driver_e = job_m_in.m_source; - filp_no = job_m_in.REP_ENDPT; - status = job_m_in.REP_STATUS; - - if (filp_no < 0 || filp_no >= NR_FILPS) { - printf("VFS: reopen_reply: bad filp number %d from driver %d\n", - filp_no, driver_e); - return; - } - - rfilp = &filp[filp_no]; - if (rfilp->filp_count < 1) { - printf("VFS: reopen_reply: filp number %d not inuse (from driver %d)\n", - filp_no, driver_e); - return; - } - - vp = rfilp->filp_vno; - if (!vp) { - printf("VFS: reopen_reply: no vnode for filp number %d (from driver " - "%d)\n", filp_no, driver_e); - return; - } - - if (!(rfilp->filp_state & FS_NEEDS_REOPEN)) { - printf("VFS: reopen_reply: bad state %d for filp number %d" - " (from driver %d)\n", rfilp->filp_state, filp_no, driver_e); - return; - } - - if (!S_ISCHR(vp->v_mode)) { - printf("VFS: reopen_reply: bad mode 0%o for filp number %d" - " (from driver %d)\n", vp->v_mode, filp_no, driver_e); - return; - } - - maj = major(vp->v_sdev); - dp = &dmap[maj]; - if (dp->dmap_driver != driver_e) { - printf("VFS: reopen_reply: bad major %d for filp number %d " - "(from driver %d, current driver is %d)\n", maj, filp_no, - driver_e, dp->dmap_driver); - return; - } - - if (status == OK) { - rfilp->filp_state &= ~FS_NEEDS_REOPEN; - } else { - printf("VFS: reopen_reply: should handle error status\n"); - return; - } - - restart_reopen(maj); + worker_signal(wp); } diff --git a/servers/vfs/dmap.c b/servers/vfs/dmap.c index 7f0b513be..0221aacb8 100644 --- a/servers/vfs/dmap.c +++ b/servers/vfs/dmap.c @@ -11,8 +11,6 @@ #include #include #include -#include "fproc.h" -#include "dmap.h" #include "param.h" /* The order of the entries in the table determines the mapping between major @@ -24,9 +22,6 @@ struct dmap dmap[NR_DEVICES]; -#define DT_EMPTY { no_dev, no_dev_io, NONE, "", 0, STYLE_NDEV, NULL, NONE, \ - 0, NULL, 0} - /*===========================================================================* * lock_dmap * *===========================================================================*/ @@ -34,20 +29,17 @@ void lock_dmap(struct dmap *dp) { /* Lock a driver */ struct worker_thread *org_self; - struct fproc *org_fp; int r; assert(dp != NULL); assert(dp->dmap_driver != NONE); - org_fp = fp; - org_self = self; + org_self = worker_suspend(); if ((r = mutex_lock(dp->dmap_lock_ref)) != 0) panic("unable to get a lock on dmap: %d\n", r); - fp = org_fp; - self = org_self; + worker_resume(org_self); } /*===========================================================================* @@ -67,7 +59,7 @@ void unlock_dmap(struct dmap *dp) /*===========================================================================* * do_mapdriver * *===========================================================================*/ -int do_mapdriver() +int do_mapdriver(message *UNUSED(m_out)) { /* Create a device->driver mapping. RS will tell us which major is driven by * this driver, what type of device it is (regular, TTY, asynchronous, clone, @@ -182,10 +174,6 @@ int flags; /* device flags */ dp->dmap_opcl = gen_opcl; dp->dmap_io = gen_io; break; - case STYLE_DEVA: - dp->dmap_opcl = gen_opcl; - dp->dmap_io = asyn_io; - break; case STYLE_TTY: dp->dmap_opcl = tty_opcl; dp->dmap_io = gen_io; @@ -194,13 +182,6 @@ int flags; /* device flags */ dp->dmap_opcl = ctty_opcl; dp->dmap_io = ctty_io; break; - case STYLE_CLONE: - dp->dmap_opcl = clone_opcl; - dp->dmap_io = gen_io; - break; - case STYLE_CLONE_A: - dp->dmap_opcl = clone_opcl; - dp->dmap_io = asyn_io; break; default: return(EINVAL); @@ -289,10 +270,16 @@ void init_dmap() { /* Initialize the table with empty device <-> driver mappings. */ int i; - struct dmap dmap_default = DT_EMPTY; - for (i = 0; i < NR_DEVICES; i++) - dmap[i] = dmap_default; + memset(dmap, 0, sizeof(dmap)); + + for (i = 0; i < NR_DEVICES; i++) { + dmap[i].dmap_opcl = no_dev; + dmap[i].dmap_io = no_dev_io; + dmap[i].dmap_driver = NONE; + dmap[i].dmap_style = STYLE_NDEV; + dmap[i].dmap_servicing = INVALID_THREAD; + } } /*===========================================================================* @@ -354,7 +341,7 @@ void dmap_endpt_up(endpoint_t proc_e, int is_blk) if (dp->dmap_recovering) { printf("VFS: driver recovery failure for" " major %d\n", major); - if (dp->dmap_servicing != NONE) { + if (dp->dmap_servicing != INVALID_THREAD) { worker = worker_get(dp->dmap_servicing); worker_stop(worker); } @@ -365,11 +352,11 @@ void dmap_endpt_up(endpoint_t proc_e, int is_blk) bdev_up(major); dp->dmap_recovering = 0; } else { - if (dp->dmap_servicing != NONE) { + if (dp->dmap_servicing != INVALID_THREAD) { worker = worker_get(dp->dmap_servicing); worker_stop(worker); } - cdev_up(major); + invalidate_filp_by_char_major(major); } } } diff --git a/servers/vfs/dmap.h b/servers/vfs/dmap.h index cd15a1cc4..959ecb070 100644 --- a/servers/vfs/dmap.h +++ b/servers/vfs/dmap.h @@ -20,8 +20,9 @@ extern struct dmap { char dmap_label[LABEL_MAX]; int dmap_flags; int dmap_style; + int dmap_sel_busy; struct filp *dmap_sel_filp; - endpoint_t dmap_servicing; + thread_t dmap_servicing; mutex_t dmap_lock; mutex_t *dmap_lock_ref; int dmap_recovering; diff --git a/servers/vfs/exec.c b/servers/vfs/exec.c index 638d1d404..3d9fa202d 100644 --- a/servers/vfs/exec.c +++ b/servers/vfs/exec.c @@ -26,7 +26,6 @@ #include #include #include -#include "fproc.h" #include "path.h" #include "param.h" #include "vnode.h" @@ -53,8 +52,6 @@ struct vfs_exec_info { int vmfd_used; }; -static void lock_exec(void); -static void unlock_exec(void); static int patch_stack(struct vnode *vp, char stack[ARG_MAX], size_t *stk_bytes, char path[PATH_MAX]); static int is_script(struct vfs_exec_info *execi); @@ -82,36 +79,8 @@ static const struct exec_loaders exec_loaders[] = { { NULL, NULL } }; -/*===========================================================================* - * lock_exec * - *===========================================================================*/ -static void lock_exec(void) -{ - struct fproc *org_fp; - struct worker_thread *org_self; - - /* First try to get it right off the bat */ - if (mutex_trylock(&exec_lock) == 0) - return; - - org_fp = fp; - org_self = self; - - if (mutex_lock(&exec_lock) != 0) - panic("Could not obtain lock on exec"); - - fp = org_fp; - self = org_self; -} - -/*===========================================================================* - * unlock_exec * - *===========================================================================*/ -static void unlock_exec(void) -{ - if (mutex_unlock(&exec_lock) != 0) - panic("Could not release lock on exec"); -} +#define lock_exec() lock_proc(fproc_addr(VM_PROC_NR)) +#define unlock_exec() unlock_proc(fproc_addr(VM_PROC_NR)) /*===========================================================================* * get_read_vp * @@ -212,17 +181,15 @@ static int vfs_memmap(struct exec_info *execi, /*===========================================================================* * pm_exec * *===========================================================================*/ -int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len, - vir_bytes frame, size_t frame_len, vir_bytes *pc, - vir_bytes *newsp, int user_exec_flags) +int pm_exec(vir_bytes path, size_t path_len, vir_bytes frame, size_t frame_len, + vir_bytes *pc, vir_bytes *newsp, int user_exec_flags) { /* Perform the execve(name, argv, envp) call. The user library builds a * complete stack image, including pointers, args, environ, etc. The stack * is copied to a buffer inside VFS, and then to the new core image. */ - int r, slot; + int r; vir_bytes vsp; - struct fproc *rfp; int extrabase = 0; static char mbuf[ARG_MAX]; /* buffer for stack and zeroes */ struct vfs_exec_info execi; @@ -232,14 +199,13 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len, firstexec[PATH_MAX], finalexec[PATH_MAX]; struct lookup resolve; - struct fproc *vmfp = &fproc[VM_PROC_NR]; + struct fproc *vmfp = fproc_addr(VM_PROC_NR); stackhook_t makestack = NULL; static int n; n++; struct filp *newfilp = NULL; lock_exec(); - lock_proc(vmfp, 0); /* unset execi values are 0. */ memset(&execi, 0, sizeof(execi)); @@ -250,10 +216,8 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len, execi.args.stack_high = kinfo.user_sp; execi.args.stack_size = DEFAULT_STACK_LIMIT; - okendpt(proc_e, &slot); - rfp = fp = &fproc[slot]; - rfp->text_size = 0; - rfp->data_size = 0; + fp->text_size = 0; + fp->data_size = 0; lookup_init(&resolve, fullpath, PATH_NOFLAGS, &execi.vmp, &execi.vp); @@ -264,7 +228,7 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len, if (frame_len > ARG_MAX) FAILCHECK(ENOMEM); /* stack too big */ - r = sys_datacopy(proc_e, (vir_bytes) frame, SELF, (vir_bytes) mbuf, + r = sys_datacopy(fp->fp_endpoint, (vir_bytes) frame, SELF, (vir_bytes) mbuf, (size_t) frame_len); if (r != OK) { /* can't fetch stack (e.g. bad virtual addr) */ printf("VFS: pm_exec: sys_datacopy failed\n"); @@ -272,8 +236,8 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len, } /* The default is to keep the original user and group IDs */ - execi.args.new_uid = rfp->fp_effuid; - execi.args.new_gid = rfp->fp_effgid; + execi.args.new_uid = fp->fp_effuid; + execi.args.new_gid = fp->fp_effgid; /* Get the exec file name. */ FAILCHECK(fetch_name(path, path_len, fullpath)); @@ -351,7 +315,6 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len, newfilp->filp_count = 1; newfilp->filp_vno = vp; newfilp->filp_flags = O_RDONLY; - FD_SET(newfd, &vmfp->fp_filp_inuse); vmfp->fp_filp[newfd] = newfilp; /* dup_vnode(vp); */ execi.vmfd = newfd; @@ -369,7 +332,7 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len, execi.args.allocmem_ondemand = libexec_alloc_mmap_ondemand; execi.args.opaque = &execi; - execi.args.proc_e = proc_e; + execi.args.proc_e = fp->fp_endpoint; execi.args.frame_len = frame_len; execi.args.filesize = execi.vp->v_size; @@ -382,7 +345,7 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len, FAILCHECK(r); /* Inform PM */ - FAILCHECK(libexec_pm_newexec(proc_e, &execi.args)); + FAILCHECK(libexec_pm_newexec(fp->fp_endpoint, &execi.args)); /* Save off PC */ *pc = execi.args.pc; @@ -393,25 +356,25 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len, /* Patch up stack and copy it from VFS to new core image. */ libexec_patch_ptr(mbuf, vsp + extrabase); - FAILCHECK(sys_datacopy(SELF, (vir_bytes) mbuf, proc_e, (vir_bytes) vsp, - (phys_bytes)frame_len)); + FAILCHECK(sys_datacopy(SELF, (vir_bytes) mbuf, fp->fp_endpoint, + (vir_bytes) vsp, (phys_bytes)frame_len)); /* Return new stack pointer to caller */ *newsp = vsp; - clo_exec(rfp); + clo_exec(fp); if (execi.args.allow_setuid) { /* If after loading the image we're still allowed to run with * setuid or setgid, change credentials now */ - rfp->fp_effuid = execi.args.new_uid; - rfp->fp_effgid = execi.args.new_gid; + fp->fp_effuid = execi.args.new_uid; + fp->fp_effgid = execi.args.new_gid; } /* Remember the new name of the process */ - strlcpy(rfp->fp_name, execi.args.progname, PROC_NAME_LEN); - rfp->text_size = execi.args.text_size; - rfp->data_size = execi.args.data_size; + strlcpy(fp->fp_name, execi.args.progname, PROC_NAME_LEN); + fp->text_size = execi.args.text_size; + fp->data_size = execi.args.data_size; pm_execfinal: if(newfilp) unlock_filp(newfilp); @@ -426,7 +389,6 @@ pm_execfinal: } } - unlock_proc(vmfp); unlock_exec(); return(r); diff --git a/servers/vfs/file.h b/servers/vfs/file.h index f28001249..3d47d40be 100644 --- a/servers/vfs/file.h +++ b/servers/vfs/file.h @@ -8,7 +8,6 @@ EXTERN struct filp { mode_t filp_mode; /* RW bits, telling how file is opened */ int filp_flags; /* flags from open and fcntl */ - int filp_state; /* state for crash recovery */ int filp_count; /* how many file descriptors share this slot?*/ struct vnode *filp_vno; /* vnode belonging to this file */ u64_t filp_pos; /* file position */ @@ -19,6 +18,7 @@ EXTERN struct filp { /* the following fields are for select() and are owned by the generic * select() code (i.e., fd-type-specific select() code can't touch these). + * These fields may be changed without holding the filp lock. */ int filp_selectors; /* select()ing processes blocking on this fd */ int filp_select_ops; /* interested in these SEL_* operations */ @@ -28,11 +28,7 @@ EXTERN struct filp { int filp_pipe_select_ops; } filp[NR_FILPS]; -#define FILP_CLOSED 0 /* filp_mode: associated device closed */ - -#define FS_NORMAL 000 /* file descriptor can be used normally */ -#define FS_NEEDS_REOPEN 001 /* file descriptor needs to be re-opened */ -#define FS_INVALIDATED 002 /* file was invalidated */ +#define FILP_CLOSED 0 /* filp_mode: associated device closed/gone */ #define FSF_UPDATE 001 /* The driver should be informed about new * state. diff --git a/servers/vfs/filedes.c b/servers/vfs/filedes.c index c8c5f4c77..a6593179c 100644 --- a/servers/vfs/filedes.c +++ b/servers/vfs/filedes.c @@ -13,6 +13,7 @@ * do_put_filp: marks a filp as not in-flight anymore. * do_cancel_fd: cancel the transaction when something goes wrong for * the receiver. + * do_dupfrom: copies a filp from another endpoint. */ #include @@ -22,7 +23,6 @@ #include #include "fs.h" #include "file.h" -#include "fproc.h" #include "vnode.h" @@ -77,60 +77,7 @@ void check_filp_locks(void) } /*===========================================================================* - * do_filp_gc * - *===========================================================================*/ -void *do_filp_gc(void *UNUSED(arg)) -{ - struct filp *f; - struct vnode *vp; - - for (f = &filp[0]; f < &filp[NR_FILPS]; f++) { - if (!(f->filp_state & FS_INVALIDATED)) continue; - - if (f->filp_mode == FILP_CLOSED || f->filp_vno == NULL) { - /* File was already closed before gc could kick in */ - assert(f->filp_count <= 0); - f->filp_state &= ~FS_INVALIDATED; - f->filp_count = 0; - continue; - } - - assert(f->filp_vno != NULL); - vp = f->filp_vno; - - /* Synchronize with worker thread that might hold a lock on the vp */ - lock_vnode(vp, VNODE_OPCL); - unlock_vnode(vp); - - /* If garbage collection was invoked due to a failed device open - * request, then common_open has already cleaned up and we have - * nothing to do. - */ - if (!(f->filp_state & FS_INVALIDATED)) { - continue; - } - - /* If garbage collection was invoked due to a failed device close - * request, the close_filp has already cleaned up and we have nothing - * to do. - */ - if (f->filp_mode != FILP_CLOSED) { - assert(f->filp_count == 0); - f->filp_count = 1; /* So lock_filp and close_filp will do - * their job */ - lock_filp(f, VNODE_READ); - close_filp(f); - } - - f->filp_state &= ~FS_INVALIDATED; - } - - thread_cleanup(NULL); - return(NULL); -} - -/*===========================================================================* - * init_filps * + * init_filps * *===========================================================================*/ void init_filps(void) { @@ -159,7 +106,7 @@ int get_fd(struct fproc *rfp, int start, mode_t bits, int *k, struct filp **fpt) /* Search the fproc fp_filp table for a free file descriptor. */ for (i = start; i < OPEN_MAX; i++) { - if (rfp->fp_filp[i] == NULL && !FD_ISSET(i, &rfp->fp_filp_inuse)) { + if (rfp->fp_filp[i] == NULL) { /* A file descriptor has been located. */ *k = i; break; @@ -182,7 +129,6 @@ int get_fd(struct fproc *rfp, int start, mode_t bits, int *k, struct filp **fpt) f->filp_select_ops = 0; f->filp_pipe_select_ops = 0; f->filp_flags = 0; - f->filp_state = FS_NORMAL; f->filp_select_flags = 0; f->filp_softlock = NULL; *fpt = f; @@ -222,12 +168,12 @@ tll_access_t locktype; filp = NULL; if (fild < 0 || fild >= OPEN_MAX) err_code = EBADF; - else if (rfp->fp_filp[fild] == NULL && FD_ISSET(fild, &rfp->fp_filp_inuse)) - err_code = EIO; /* The filedes is not there, but is not closed either. - */ + else if (locktype != VNODE_OPCL && rfp->fp_filp[fild] != NULL && + rfp->fp_filp[fild]->filp_mode == FILP_CLOSED) + err_code = EIO; /* disallow all use except close(2) */ else if ((filp = rfp->fp_filp[fild]) == NULL) err_code = EBADF; - else + else if (locktype != VNODE_NONE) /* Only lock the filp if requested */ lock_filp(filp, locktype); /* All is fine */ return(filp); /* may also be NULL */ @@ -261,24 +207,11 @@ struct filp *find_filp(struct vnode *vp, mode_t bits) /*===========================================================================* * invalidate_filp * *===========================================================================*/ -int invalidate_filp(struct filp *rfilp) +void invalidate_filp(struct filp *rfilp) { -/* Invalidate filp. fp_filp_inuse is not cleared, so filp can't be reused - until it is closed first. */ +/* Invalidate filp. */ - int f, fd, n = 0; - for (f = 0; f < NR_PROCS; f++) { - if (fproc[f].fp_pid == PID_FREE) continue; - for (fd = 0; fd < OPEN_MAX; fd++) { - if(fproc[f].fp_filp[fd] && fproc[f].fp_filp[fd] == rfilp) { - fproc[f].fp_filp[fd] = NULL; - n++; - } - } - } - - rfilp->filp_state |= FS_INVALIDATED; - return(n); /* Report back how often this filp has been invalidated. */ + rfilp->filp_mode = FILP_CLOSED; } /*===========================================================================* @@ -292,7 +225,7 @@ void invalidate_filp_by_char_major(int major) if (f->filp_count != 0 && f->filp_vno != NULL) { if (major(f->filp_vno->v_sdev) == major && S_ISCHR(f->filp_vno->v_mode)) { - (void) invalidate_filp(f); + invalidate_filp(f); } } } @@ -308,7 +241,7 @@ void invalidate_filp_by_endpt(endpoint_t proc_e) for (f = &filp[0]; f < &filp[NR_FILPS]; f++) { if (f->filp_count != 0 && f->filp_vno != NULL) { if (f->filp_vno->v_fs_e == proc_e) - (void) invalidate_filp(f); + invalidate_filp(f); } } } @@ -320,7 +253,6 @@ void lock_filp(filp, locktype) struct filp *filp; tll_access_t locktype; { - struct fproc *org_fp; struct worker_thread *org_self; struct vnode *vp; @@ -350,14 +282,12 @@ tll_access_t locktype; if (mutex_trylock(&filp->filp_lock) != 0) { /* Already in use, let's wait for our turn */ - org_fp = fp; - org_self = self; + org_self = worker_suspend(); if (mutex_lock(&filp->filp_lock) != 0) panic("unable to obtain lock on filp"); - fp = org_fp; - self = org_self; + worker_resume(org_self); } } @@ -371,7 +301,7 @@ struct filp *filp; if (filp->filp_softlock != NULL) assert(filp->filp_softlock == fp); - if (filp->filp_count > 0 || filp->filp_state & FS_INVALIDATED) { + if (filp->filp_count > 0) { /* Only unlock vnode if filp is still in use */ /* and if we don't hold a soft lock */ @@ -449,11 +379,14 @@ int do_verify_fd(message *m_out) endpoint_t proc_e; int fd; - proc_e = job_m_in.USER_ENDPT; - fd = job_m_in.COUNT; + /* This should be replaced with an ACL check. */ + if (who_e != PFS_PROC_NR) return EPERM; + + proc_e = job_m_in.VFS_PFS_ENDPT; + fd = job_m_in.VFS_PFS_FD; rfilp = (struct filp *) verify_fd(proc_e, fd); - m_out->ADDRESS = (void *) rfilp; + m_out->VFS_PFS_FILP = (void *) rfilp; if (rfilp != NULL) unlock_filp(rfilp); return (rfilp != NULL) ? OK : EINVAL; } @@ -479,7 +412,11 @@ filp_id_t sfilp; int do_set_filp(message *UNUSED(m_out)) { filp_id_t f; - f = (filp_id_t) job_m_in.ADDRESS; + + /* This should be replaced with an ACL check. */ + if (who_e != PFS_PROC_NR) return EPERM; + + f = (filp_id_t) job_m_in.VFS_PFS_FILP; return set_filp(f); } @@ -499,11 +436,8 @@ filp_id_t cfilp; /* Find an open slot in fp_filp */ for (fd = 0; fd < OPEN_MAX; fd++) { - if (rfp->fp_filp[fd] == NULL && - !FD_ISSET(fd, &rfp->fp_filp_inuse)) { - + if (rfp->fp_filp[fd] == NULL) { /* Found a free slot, add descriptor */ - FD_SET(fd, &rfp->fp_filp_inuse); rfp->fp_filp[fd] = cfilp; rfp->fp_filp[fd]->filp_count++; return(fd); @@ -522,8 +456,11 @@ int do_copy_filp(message *UNUSED(m_out)) endpoint_t proc_e; filp_id_t f; - proc_e = job_m_in.USER_ENDPT; - f = (filp_id_t) job_m_in.ADDRESS; + /* This should be replaced with an ACL check. */ + if (who_e != PFS_PROC_NR) return EPERM; + + proc_e = job_m_in.VFS_PFS_ENDPT; + f = (filp_id_t) job_m_in.VFS_PFS_FILP; return copy_filp(proc_e, f); } @@ -549,7 +486,11 @@ filp_id_t pfilp; int do_put_filp(message *UNUSED(m_out)) { filp_id_t f; - f = (filp_id_t) job_m_in.ADDRESS; + + /* This should be replaced with an ACL check. */ + if (who_e != PFS_PROC_NR) return EPERM; + + f = (filp_id_t) job_m_in.VFS_PFS_FILP; return put_filp(f); } @@ -571,7 +512,6 @@ int fd; rfilp = (struct filp *) verify_fd(ep, fd); if (rfilp != NULL) { /* Found a valid descriptor, remove it */ - FD_CLR(fd, &rfp->fp_filp_inuse); if (rfp->fp_filp[fd]->filp_count == 0) { unlock_filp(rfilp); printf("VFS: filp_count for slot %d fd %d already zero", slot, @@ -596,8 +536,11 @@ int do_cancel_fd(message *UNUSED(m_out)) endpoint_t proc_e; int fd; - proc_e = job_m_in.USER_ENDPT; - fd = job_m_in.COUNT; + /* This should be replaced with an ACL check. */ + if (who_e != PFS_PROC_NR) return EPERM; + + proc_e = job_m_in.VFS_PFS_ENDPT; + fd = job_m_in.VFS_PFS_FD; return cancel_fd(proc_e, fd); } @@ -635,15 +578,9 @@ struct filp *f; } unlock_bsf(); - /* Attempt to close only when feasible */ - if (!(f->filp_state & FS_INVALIDATED)) { - (void) bdev_close(dev); /* Ignore errors */ - } + (void) bdev_close(dev); /* Ignore errors */ } else { - /* Attempt to close only when feasible */ - if (!(f->filp_state & FS_INVALIDATED)) { - (void) dev_close(dev, f-filp);/*Ignore errors*/ - } + (void) cdev_close(dev); /* Ignore errors */ } f->filp_mode = FILP_CLOSED; @@ -656,10 +593,7 @@ struct filp *f; release(vp, rw, susp_count); } - f->filp_count--; /* If filp got invalidated at device closure, the - * count might've become negative now */ - if (f->filp_count == 0 || - (f->filp_count < 0 && f->filp_state & FS_INVALIDATED)) { + if (--f->filp_count == 0) { if (S_ISFIFO(vp->v_mode)) { /* Last reader or writer is going. Tell PFS about latest * pipe size. @@ -681,3 +615,58 @@ struct filp *f; mutex_unlock(&f->filp_lock); } + +/*===========================================================================* + * do_dupfrom * + *===========================================================================*/ +int do_dupfrom(message *UNUSED(m_out)) +{ +/* Duplicate a file descriptor from another process into the calling process. + * The other process is identified by a magic grant created for it to make the + * initial (IOCTL) request to the calling process. This call has been added + * specifically for the VND driver. + */ + struct fproc *rfp; + struct filp *rfilp; + struct vnode *vp; + endpoint_t endpt; + int r, fd, slot; + + /* This should be replaced with an ACL check. */ + if (!super_user) return(EPERM); + + endpt = (endpoint_t) job_m_in.VFS_DUPFROM_ENDPT; + fd = job_m_in.VFS_DUPFROM_FD; + + if (isokendpt(endpt, &slot) != OK) return(EINVAL); + rfp = &fproc[slot]; + + /* Obtain the filp, but do not lock it yet: we first need to make sure that + * locking it will not result in a deadlock. + */ + if ((rfilp = get_filp2(rfp, fd, VNODE_NONE)) == NULL) + return(err_code); + + /* For now, we do not allow remote duplication of device nodes. In practice, + * only a block-special file can cause a deadlock for the caller (currently + * only the VND driver). This would happen if a user process passes in the + * file descriptor to the device node on which it is performing the IOCTL. + * This would cause two VFS threads to deadlock on the same filp. Since the + * VND driver does not allow device nodes to be used anyway, this somewhat + * rudimentary check eliminates such deadlocks. A better solution would be + * to check if the given endpoint holds a lock to the target filp, but we + * currently do not have this information within VFS. + */ + vp = rfilp->filp_vno; + if (S_ISCHR(vp->v_mode) || S_ISBLK(vp->v_mode)) + return(EINVAL); + + /* Now we can safely lock the filp, copy it, and unlock it again. */ + lock_filp(rfilp, VNODE_READ); + + r = copy_filp(who_e, (filp_id_t) rfilp); + + unlock_filp(rfilp); + + return(r); +} diff --git a/servers/vfs/fproc.h b/servers/vfs/fproc.h index 3f9ff28e9..1831236ff 100644 --- a/servers/vfs/fproc.h +++ b/servers/vfs/fproc.h @@ -20,8 +20,7 @@ EXTERN struct fproc { struct vnode *fp_wd; /* working directory; NULL during reboot */ struct vnode *fp_rd; /* root directory; NULL during reboot */ - struct filp *fp_filp[OPEN_MAX];/* the file descriptor table */ - fd_set fp_filp_inuse; /* which fd's are in use? */ + struct filp *fp_filp[OPEN_MAX];/* the file descriptor table (free if NULL) */ fd_set fp_cloexec_set; /* bit map for POSIX Table 6-2 FD_CLOEXEC */ dev_t fp_tty; /* major/minor of controlling tty */ @@ -30,8 +29,6 @@ EXTERN struct fproc { int fp_block_callnr; /* blocked call if rd/wr can't finish */ int fp_cum_io_partial; /* partial byte count if rd/wr can't finish */ endpoint_t fp_task; /* which task is proc suspended on */ - endpoint_t fp_ioproc; /* proc no. in suspended-on i/o message */ - cp_grant_id_t fp_grant; /* revoke this grant on unsuspend if > -1 */ uid_t fp_realuid; /* real user id */ @@ -43,8 +40,11 @@ EXTERN struct fproc { mode_t fp_umask; /* mask set by umask system call */ mutex_t fp_lock; /* mutex to lock fproc object */ - struct job fp_job; /* pending job */ - thread_t fp_wtid; /* Thread ID of worker */ + struct worker_thread *fp_worker;/* active worker thread, or NULL */ + void (*fp_func)(); /* handler function for pending work */ + message fp_msg; /* pending or active message from process */ + message fp_pm_msg; /* pending/active postponed PM request */ + char fp_name[PROC_NAME_LEN]; /* Last exec() */ #if LOCK_DEBUG int fp_vp_rdlocks; /* number of read-only locks on vnodes */ @@ -56,17 +56,13 @@ EXTERN struct fproc { } fproc[NR_PROCS]; /* fp_flags */ -#define FP_NOFLAGS 00 -#define FP_SUSP_REOPEN 01 /* Process is suspended until the reopens are - * completed (after the restart of a driver). - */ +#define FP_NOFLAGS 0000 +#define FP_SRV_PROC 0001 /* Set if process is a service */ #define FP_REVIVED 0002 /* Indicates process is being revived */ #define FP_SESLDR 0004 /* Set if process is session leader */ #define FP_PENDING 0010 /* Set if process has pending work */ #define FP_EXITING 0020 /* Set if process is exiting */ -#define FP_PM_PENDING 0040 /* Set if process has pending PM request */ -#define FP_SRV_PROC 0100 /* Set if process is a service */ -#define FP_DROP_WORK 0200 /* Set if process won't accept new work */ +#define FP_PM_WORK 0040 /* Set if process has a postponed PM request */ /* Field values. */ #define NOT_REVIVING 0xC0FFEEE /* process is not being revived */ diff --git a/servers/vfs/fs.h b/servers/vfs/fs.h index 3c95e26d5..085f3d4d1 100644 --- a/servers/vfs/fs.h +++ b/servers/vfs/fs.h @@ -28,7 +28,8 @@ #include "proto.h" #include "threads.h" #include "glo.h" -#include "comm.h" +#include "type.h" #include "vmnt.h" +#include "fproc.h" #endif diff --git a/servers/vfs/gcov.c b/servers/vfs/gcov.c index 683a2bf82..642fe558a 100644 --- a/servers/vfs/gcov.c +++ b/servers/vfs/gcov.c @@ -1,7 +1,6 @@ #include "fs.h" #include "file.h" -#include "fproc.h" int gcov_flush(cp_grant_id_t grantid, size_t size ); diff --git a/servers/vfs/glo.h b/servers/vfs/glo.h index be48c1ba3..09009c450 100644 --- a/servers/vfs/glo.h +++ b/servers/vfs/glo.h @@ -25,24 +25,17 @@ EXTERN u32_t system_hz; /* system clock frequency. */ /* The parameters of the call are kept here. */ EXTERN message m_in; /* the input message itself */ # define who_p ((int) (fp - fproc)) -# define isokslot(p) (p >= 0 && \ - p < (int)(sizeof(fproc) / sizeof(struct fproc))) -# define who_e (self != NULL && fp != NULL ? fp->fp_endpoint : \ - m_in.m_source) +# define fproc_addr(e) (&fproc[_ENDPOINT_P(e)]) +# define who_e (self != NULL ? fp->fp_endpoint : m_in.m_source) # define call_nr (m_in.m_type) -# define job_m_in (self->w_job.j_m_in) +# define job_m_in (self->w_msg) # define job_call_nr (job_m_in.m_type) # define super_user (fp->fp_effuid == SU_UID ? 1 : 0) # define scratch(p) (scratchpad[((int) ((p) - fproc))]) EXTERN struct worker_thread *self; -EXTERN int force_sync; /* toggle forced synchronous communication */ EXTERN int deadlock_resolving; -EXTERN mutex_t exec_lock; EXTERN mutex_t bsf_lock;/* Global lock for access to block special files */ EXTERN struct worker_thread workers[NR_WTHREADS]; -EXTERN struct worker_thread sys_worker; -EXTERN struct worker_thread dl_worker; -EXTERN thread_t invalid_thread_id; EXTERN char mount_label[LABEL_MAX]; /* label of file system to mount */ /* The following variables are used for returning results to the caller. */ diff --git a/servers/vfs/job.h b/servers/vfs/job.h deleted file mode 100644 index 046a11b30..000000000 --- a/servers/vfs/job.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __VFS_WORK_H__ -#define __VFS_WORK_H__ - -struct job { - struct fproc *j_fp; - message j_m_in; - int j_err_code; - void *(*j_func)(void *arg); - struct job *j_next; -}; - -#endif diff --git a/servers/vfs/link.c b/servers/vfs/link.c index 8ffc03ee0..6a4fe25e9 100644 --- a/servers/vfs/link.c +++ b/servers/vfs/link.c @@ -20,7 +20,6 @@ #include #include #include "file.h" -#include "fproc.h" #include "path.h" #include "vnode.h" #include "param.h" diff --git a/servers/vfs/lock.c b/servers/vfs/lock.c index 0551a8401..5484a31ce 100644 --- a/servers/vfs/lock.c +++ b/servers/vfs/lock.c @@ -11,7 +11,6 @@ #include #include #include "file.h" -#include "fproc.h" #include "scratchpad.h" #include "lock.h" #include "vnode.h" diff --git a/servers/vfs/main.c b/servers/vfs/main.c index 0bf2624f3..280b4c7a8 100644 --- a/servers/vfs/main.c +++ b/servers/vfs/main.c @@ -27,12 +27,9 @@ #include #include #include "file.h" -#include "dmap.h" -#include "fproc.h" #include "scratchpad.h" #include "vmnt.h" #include "vnode.h" -#include "job.h" #include "param.h" #if ENABLE_SYSCALL_STATS @@ -40,26 +37,18 @@ EXTERN unsigned long calls_stats[NCALLS]; #endif /* Thread related prototypes */ -static void *do_async_dev_result(void *arg); -static void *do_control_msgs(void *arg); -static void *do_dev_event(void *arg); -static void *do_fs_reply(struct job *job); -static void *do_work(void *arg); -static void *do_pm(void *arg); -static void *do_init_root(void *arg); -static void handle_work(void *(*func)(void *arg)); +static void do_fs_reply(struct worker_thread *wp); +static void do_work(void); +static void do_init_root(void); +static void handle_work(void (*func)(void)); static void get_work(void); -static void lock_pm(void); -static void unlock_pm(void); static void service_pm(void); -static void service_pm_postponed(void); static int unblock(struct fproc *rfp); /* SEF functions and variables. */ static void sef_local_startup(void); static int sef_cb_init_fresh(int type, sef_init_info_t *info); -static mutex_t pm_lock; static endpoint_t receive_from; /*===========================================================================* @@ -72,7 +61,7 @@ int main(void) * the reply. This loop never terminates as long as the file system runs. */ int transid; - struct job *job; + struct worker_thread *wp; /* SEF local startup. */ sef_local_startup(); @@ -86,38 +75,46 @@ int main(void) while (TRUE) { yield_all(); /* let other threads run */ self = NULL; - job = NULL; send_work(); get_work(); transid = TRNS_GET_ID(m_in.m_type); if (IS_VFS_FS_TRANSID(transid)) { - job = worker_getjob( (thread_t) transid - VFS_TRANSID); - if (job == NULL) { + wp = worker_get((thread_t) transid - VFS_TRANSID); + if (wp == NULL || wp->w_fp == NULL) { printf("VFS: spurious message %d from endpoint %d\n", m_in.m_type, m_in.m_source); continue; } m_in.m_type = TRNS_DEL_ID(m_in.m_type); - } - - if (job != NULL) { - do_fs_reply(job); + do_fs_reply(wp); continue; } else if (who_e == PM_PROC_NR) { /* Calls from PM */ /* Special control messages from PM */ - sys_worker_start(do_pm); + service_pm(); continue; } else if (is_notify(call_nr)) { /* A task notify()ed us */ - if (who_e == DS_PROC_NR) - handle_work(ds_event); - else if (who_e == KERNEL) + switch (who_e) { + case DS_PROC_NR: + /* Start a thread to handle DS events, if no thread + * is pending or active for it already. DS is not + * supposed to issue calls to VFS or be the subject of + * postponed PM requests, so this should be no problem. + */ + if (worker_can_start(fp)) + handle_work(ds_event); + break; + case KERNEL: mthread_stacktraces(); - else if (fp != NULL && (fp->fp_flags & FP_SRV_PROC)) - handle_work(do_dev_event); - else - sys_worker_start(do_control_msgs); + break; + case CLOCK: + /* Timer expired. Used only for select(). Check it. */ + expire_timers(m_in.NOTIFY_TIMESTAMP); + break; + default: + printf("VFS: ignoring notification from %d\n", who_e); + } continue; } else if (who_p < 0) { /* i.e., message comes from a task */ /* We're going to ignore this message. Tasks should @@ -127,36 +124,14 @@ int main(void) continue; } - /* At this point we either have results from an asynchronous device - * or a new system call. In both cases a new worker thread has to be - * started and there might not be one available from the pool. This is - * not a problem (requests/replies are simply queued), except when - * they're from an FS endpoint, because these can cause a deadlock. - * handle_work() takes care of the details. */ - if (IS_DRV_REPLY(call_nr)) { - /* We've got results for a device request */ - - struct dmap *dp; - - dp = get_dmap(who_e); - if (dp != NULL) { - if (dev_style_asyn(dp->dmap_style)) { - handle_work(do_async_dev_result); - - } else { - if (dp->dmap_servicing == NONE) { - printf("Got spurious dev reply from %d", - who_e); - } else { - dev_reply(dp); - } - } - continue; - } - printf("VFS: ignoring dev reply from unknown driver %d\n", - who_e); + if (IS_BDEV_RS(call_nr)) { + /* We've got results for a block device request. */ + bdev_reply(); + } else if (IS_CDEV_RS(call_nr)) { + /* We've got results for a character device request. */ + cdev_reply(); } else { - /* Normal syscall. */ + /* Normal syscall. This spawns a new thread. */ handle_work(do_work); } } @@ -166,217 +141,73 @@ int main(void) /*===========================================================================* * handle_work * *===========================================================================*/ -static void handle_work(void *(*func)(void *arg)) +static void handle_work(void (*func)(void)) { /* Handle asynchronous device replies and new system calls. If the originating * endpoint is an FS endpoint, take extra care not to get in deadlock. */ struct vmnt *vmp = NULL; endpoint_t proc_e; + int use_spare = FALSE; proc_e = m_in.m_source; if (fp->fp_flags & FP_SRV_PROC) { vmp = find_vmnt(proc_e); if (vmp != NULL) { - /* A call back or dev result from an FS - * endpoint. Set call back flag. Can do only - * one call back at a time. - */ + /* A callback from an FS endpoint. Can do only one at once. */ if (vmp->m_flags & VMNT_CALLBACK) { replycode(proc_e, EAGAIN); return; } + /* Already trying to resolve a deadlock? Can't handle more. */ + if (worker_available() == 0) { + replycode(proc_e, EAGAIN); + return; + } + /* A thread is available. Set callback flag. */ vmp->m_flags |= VMNT_CALLBACK; if (vmp->m_flags & VMNT_MOUNTING) { vmp->m_flags |= VMNT_FORCEROOTBSF; } } - if (worker_available() == 0) { - if (!deadlock_resolving) { - deadlock_resolving = 1; - dl_worker_start(func); - return; - } - - if (vmp != NULL) { - /* Already trying to resolve a deadlock, can't - * handle more, sorry */ - - replycode(proc_e, EAGAIN); - return; - } - } + /* Use the spare thread to handle this request if needed. */ + use_spare = TRUE; } - worker_start(func); + worker_start(fp, func, &m_in, use_spare); } -/*===========================================================================* - * do_async_dev_result * - *===========================================================================*/ -static void *do_async_dev_result(void *arg) -{ - endpoint_t endpt; - struct job my_job; - - my_job = *((struct job *) arg); - fp = my_job.j_fp; - - /* An asynchronous character driver has results for us */ - if (job_call_nr == DEV_REVIVE) { - endpt = job_m_in.REP_ENDPT; - if (endpt == VFS_PROC_NR) - endpt = find_suspended_ep(job_m_in.m_source, - job_m_in.REP_IO_GRANT); - - if (endpt == NONE) { - printf("VFS: proc with grant %d from %d not found\n", - job_m_in.REP_IO_GRANT, job_m_in.m_source); - } else if (job_m_in.REP_STATUS == SUSPEND) { - printf("VFS: got SUSPEND on DEV_REVIVE: not reviving proc\n"); - } else - revive(endpt, job_m_in.REP_STATUS); - } - else if (job_call_nr == DEV_OPEN_REPL) open_reply(); - else if (job_call_nr == DEV_REOPEN_REPL) reopen_reply(); - else if (job_call_nr == DEV_CLOSE_REPL) close_reply(); - else if (job_call_nr == DEV_SEL_REPL1) - select_reply1(job_m_in.m_source, job_m_in.DEV_MINOR, - job_m_in.DEV_SEL_OPS); - else if (job_call_nr == DEV_SEL_REPL2) - select_reply2(job_m_in.m_source, job_m_in.DEV_MINOR, - job_m_in.DEV_SEL_OPS); - - thread_cleanup(fp); - return(NULL); -} - -/*===========================================================================* - * do_control_msgs * - *===========================================================================*/ -static void *do_control_msgs(void *arg) -{ - struct job my_job; - - my_job = *((struct job *) arg); - fp = my_job.j_fp; - - /* Check for special control messages. */ - if (job_m_in.m_source == CLOCK) { - /* Alarm timer expired. Used only for select(). Check it. */ - expire_timers(job_m_in.NOTIFY_TIMESTAMP); - } - - thread_cleanup(NULL); - return(NULL); -} - -/*===========================================================================* - * do_dev_event * - *===========================================================================*/ -static void *do_dev_event(void *arg) -{ -/* Device notifies us of an event. */ - struct job my_job; - - my_job = *((struct job *) arg); - fp = my_job.j_fp; - - dev_status(job_m_in.m_source); - - thread_cleanup(fp); - return(NULL); -} /*===========================================================================* * do_fs_reply * *===========================================================================*/ -static void *do_fs_reply(struct job *job) +static void do_fs_reply(struct worker_thread *wp) { struct vmnt *vmp; - struct worker_thread *wp; if ((vmp = find_vmnt(who_e)) == NULL) panic("Couldn't find vmnt for endpoint %d", who_e); - wp = worker_get(job->j_fp->fp_wtid); - - if (wp == NULL) { - printf("VFS: spurious reply from %d\n", who_e); - return(NULL); - } - if (wp->w_task != who_e) { printf("VFS: expected %d to reply, not %d\n", wp->w_task, who_e); - return(NULL); + return; } *wp->w_fs_sendrec = m_in; wp->w_task = NONE; vmp->m_comm.c_cur_reqs--; /* We've got our reply, make room for others */ worker_signal(wp); /* Continue this thread */ - return(NULL); -} - -/*===========================================================================* - * lock_pm * - *===========================================================================*/ -static void lock_pm(void) -{ - struct fproc *org_fp; - struct worker_thread *org_self; - - /* First try to get it right off the bat */ - if (mutex_trylock(&pm_lock) == 0) - return; - - org_fp = fp; - org_self = self; - - if (mutex_lock(&pm_lock) != 0) - panic("Could not obtain lock on pm\n"); - - fp = org_fp; - self = org_self; -} - -/*===========================================================================* - * unlock_pm * - *===========================================================================*/ -static void unlock_pm(void) -{ - if (mutex_unlock(&pm_lock) != 0) - panic("Could not release lock on pm"); -} - -/*===========================================================================* - * do_pm * - *===========================================================================*/ -static void *do_pm(void *arg __unused) -{ - lock_pm(); - service_pm(); - unlock_pm(); - - thread_cleanup(NULL); - return(NULL); } /*===========================================================================* * do_pending_pipe * *===========================================================================*/ -static void *do_pending_pipe(void *arg) +static void do_pending_pipe(void) { int r, op; - struct job my_job; struct filp *f; tll_access_t locktype; - my_job = *((struct job *) arg); - fp = my_job.j_fp; - - lock_proc(fp, 1 /* force lock */); - f = scratch(fp).file.filp; assert(f != NULL); scratch(fp).file.filp = NULL; @@ -391,66 +222,26 @@ static void *do_pending_pipe(void *arg) replycode(fp->fp_endpoint, r); unlock_filp(f); - thread_cleanup(fp); - unlock_proc(fp); - return(NULL); -} - -/*===========================================================================* - * do_dummy * - *===========================================================================*/ -void *do_dummy(void *arg) -{ - struct job my_job; - int r; - - my_job = *((struct job *) arg); - fp = my_job.j_fp; - - if ((r = mutex_trylock(&fp->fp_lock)) == 0) { - thread_cleanup(fp); - unlock_proc(fp); - } else { - /* Proc is busy, let that worker thread carry out the work */ - thread_cleanup(NULL); - } - return(NULL); } /*===========================================================================* * do_work * *===========================================================================*/ -static void *do_work(void *arg) +static void do_work(void) { int error; - struct job my_job; message m_out; memset(&m_out, 0, sizeof(m_out)); - my_job = *((struct job *) arg); - fp = my_job.j_fp; - - lock_proc(fp, 0); /* This proc is busy */ - - if (job_call_nr == MAPDRIVER) { - error = do_mapdriver(); - } else if (job_call_nr == COMMON_GETSYSINFO) { + if (job_call_nr == COMMON_GETSYSINFO) { error = do_getsysinfo(); - } else if (IS_PFS_VFS_RQ(job_call_nr)) { - if (who_e != PFS_PROC_NR) { - printf("VFS: only PFS is allowed to make nested VFS calls\n"); - error = ENOSYS; - } else if (job_call_nr <= PFS_BASE || - job_call_nr >= PFS_BASE + PFS_NREQS) { - error = ENOSYS; - } else { - job_call_nr -= PFS_BASE; - error = (*pfs_call_vec[job_call_nr])(&m_out); - } } else { - /* We're dealing with a POSIX system call from a normal - * process. Call the internal function that does the work. + /* At this point we assume that we're dealing with a call that has been + * made specifically to VFS. Typically it will be a POSIX call from a + * normal process, but we also handle a few calls made by system + * processes (such as PFS) through here. Call the internal function + * that does the work. */ if (job_call_nr < 0 || job_call_nr >= NCALLS) { error = ENOSYS; @@ -468,10 +259,6 @@ static void *do_work(void *arg) /* Copy the results back to the user and send reply. */ if (error != SUSPEND) reply(&m_out, fp->fp_endpoint, error); - - thread_cleanup(fp); - unlock_proc(fp); - return(NULL); } /*===========================================================================* @@ -500,7 +287,6 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *info) message mess; struct rprocpub rprocpub[NR_BOOT_PROCS]; - force_sync = 0; receive_from = ANY; self = NULL; verbose = 0; @@ -541,8 +327,6 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *info) s = send(PM_PROC_NR, &mess); /* send synchronization message */ /* All process table entries have been set. Continue with initialization. */ - fp = &fproc[_ENDPOINT_P(VFS_PROC_NR)];/* During init all communication with - * FSes is on behalf of myself */ init_dmap(); /* Initialize device table. */ system_hz = sys_hz(); @@ -564,28 +348,29 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *info) if (s != OK) panic("VFS: can't subscribe to driver events (%d)", s); /* Initialize worker threads */ - for (i = 0; i < NR_WTHREADS; i++) { - worker_init(&workers[i]); - } - worker_init(&sys_worker); /* exclusive system worker thread */ - worker_init(&dl_worker); /* exclusive worker thread to resolve deadlocks */ + worker_init(); /* Initialize global locks */ - if (mthread_mutex_init(&pm_lock, NULL) != 0) - panic("VFS: couldn't initialize pm lock mutex"); - if (mthread_mutex_init(&exec_lock, NULL) != 0) - panic("VFS: couldn't initialize exec lock"); if (mthread_mutex_init(&bsf_lock, NULL) != 0) panic("VFS: couldn't initialize block special file lock"); - /* Initialize event resources for boot procs and locks for all procs */ + /* Initialize locks and initial values for all processes. */ for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { if (mutex_init(&rfp->fp_lock, NULL) != 0) panic("unable to initialize fproc lock"); + rfp->fp_worker = NULL; #if LOCK_DEBUG rfp->fp_vp_rdlocks = 0; rfp->fp_vmnt_rdlocks = 0; #endif + + /* Initialize process directories. mount_fs will set them to the + * correct values. + */ + for (i = 0; i < OPEN_MAX; i++) + rfp->fp_filp[i] = NULL; + rfp->fp_rd = NULL; + rfp->fp_wd = NULL; } init_dmap_locks(); /* init dmap locks */ @@ -594,9 +379,11 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *info) init_select(); /* init select() structures */ init_filps(); /* Init filp structures */ mount_pfs(); /* mount Pipe File Server */ - worker_start(do_init_root); /* mount initial ramdisk as file system root */ - yield(); /* force do_init_root to start */ - self = NULL; + + /* Mount initial ramdisk as file system root. */ + receive_from = MFS_PROC_NR; + worker_start(fproc_addr(VFS_PROC_NR), do_init_root, &mess /*unused*/, + FALSE /*use_spare*/); return(OK); } @@ -604,66 +391,36 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *info) /*===========================================================================* * do_init_root * *===========================================================================*/ -static void *do_init_root(void *arg) +static void do_init_root(void) { - struct fproc *rfp; - struct job my_job; int r; + char *mount_type = "mfs"; /* FIXME: use boot image process name instead */ char *mount_label = "fs_imgrd"; /* FIXME: obtain this from RS */ - my_job = *((struct job *) arg); - fp = my_job.j_fp; - - lock_proc(fp, 1 /* force lock */); /* This proc is busy */ - lock_pm(); - - /* Initialize process directories. mount_fs will set them to the correct - * values */ - for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { - FD_ZERO(&(rfp->fp_filp_inuse)); - rfp->fp_rd = NULL; - rfp->fp_wd = NULL; - } - - receive_from = MFS_PROC_NR; - r = mount_fs(DEV_IMGRD, "bootramdisk", "/", MFS_PROC_NR, 0, mount_label); + r = mount_fs(DEV_IMGRD, "bootramdisk", "/", MFS_PROC_NR, 0, mount_type, + mount_label); if (r != OK) panic("Failed to initialize root"); receive_from = ANY; - - unlock_pm(); - thread_cleanup(fp); - unlock_proc(fp); - return(NULL); } /*===========================================================================* * lock_proc * *===========================================================================*/ -void lock_proc(struct fproc *rfp, int force_lock) +void lock_proc(struct fproc *rfp) { int r; - struct fproc *org_fp; struct worker_thread *org_self; r = mutex_trylock(&rfp->fp_lock); - - /* Were we supposed to obtain this lock immediately? */ - if (force_lock) { - assert(r == 0); - return; - } - if (r == 0) return; - org_fp = fp; - org_self = self; + org_self = worker_suspend(); if ((r = mutex_lock(&rfp->fp_lock)) != 0) panic("unable to lock fproc lock: %d", r); - fp = org_fp; - self = org_self; + worker_resume(org_self); } /*===========================================================================* @@ -680,48 +437,23 @@ void unlock_proc(struct fproc *rfp) /*===========================================================================* * thread_cleanup * *===========================================================================*/ -void thread_cleanup(struct fproc *rfp) +void thread_cleanup(void) { -/* Clean up worker thread. Skip parts if this thread is not associated - * with a particular process (i.e., rfp is NULL) */ +/* Perform cleanup actions for a worker thread. */ #if LOCK_DEBUG - if (rfp != NULL) { - check_filp_locks_by_me(); - check_vnode_locks_by_me(rfp); - check_vmnt_locks_by_me(rfp); - } + check_filp_locks_by_me(); + check_vnode_locks_by_me(fp); + check_vmnt_locks_by_me(fp); #endif - if (rfp != NULL && rfp->fp_flags & FP_PM_PENDING) { /* Postponed PM call */ - job_m_in = rfp->fp_job.j_m_in; - rfp->fp_flags &= ~FP_PM_PENDING; - service_pm_postponed(); - } + if (fp->fp_flags & FP_SRV_PROC) { + struct vmnt *vmp; -#if LOCK_DEBUG - if (rfp != NULL) { - check_filp_locks_by_me(); - check_vnode_locks_by_me(rfp); - check_vmnt_locks_by_me(rfp); - } -#endif - - if (rfp != NULL) { - rfp->fp_flags &= ~FP_DROP_WORK; - if (rfp->fp_flags & FP_SRV_PROC) { - struct vmnt *vmp; - - if ((vmp = find_vmnt(rfp->fp_endpoint)) != NULL) { - vmp->m_flags &= ~VMNT_CALLBACK; - } + if ((vmp = find_vmnt(fp->fp_endpoint)) != NULL) { + vmp->m_flags &= ~VMNT_CALLBACK; } } - - if (deadlock_resolving) { - if (self->w_tid == dl_worker.w_tid) - deadlock_resolving = 0; - } } /*===========================================================================* @@ -831,80 +563,81 @@ void replycode(endpoint_t whom, int result) /*===========================================================================* * service_pm_postponed * *===========================================================================*/ -static void service_pm_postponed(void) +void service_pm_postponed(void) { - int r; - vir_bytes pc, newsp; + int r, term_signal; + vir_bytes core_path; + vir_bytes exec_path, stack_frame, pc, newsp; + size_t exec_path_len, stack_frame_len; + endpoint_t proc_e; message m_out; memset(&m_out, 0, sizeof(m_out)); switch(job_call_nr) { - case PM_EXEC: - { - endpoint_t proc_e; - vir_bytes exec_path, stack_frame; - size_t exec_path_len, stack_frame_len; + case PM_EXEC: + proc_e = job_m_in.PM_PROC; + exec_path = (vir_bytes) job_m_in.PM_PATH; + exec_path_len = (size_t) job_m_in.PM_PATH_LEN; + stack_frame = (vir_bytes) job_m_in.PM_FRAME; + stack_frame_len = (size_t) job_m_in.PM_FRAME_LEN; - proc_e = job_m_in.PM_PROC; - exec_path = (vir_bytes) job_m_in.PM_PATH; - exec_path_len = (size_t) job_m_in.PM_PATH_LEN; - stack_frame = (vir_bytes) job_m_in.PM_FRAME; - stack_frame_len = (size_t) job_m_in.PM_FRAME_LEN; + assert(proc_e == fp->fp_endpoint); - r = pm_exec(proc_e, exec_path, exec_path_len, stack_frame, - stack_frame_len, &pc, &newsp, job_m_in.PM_EXECFLAGS); + r = pm_exec(exec_path, exec_path_len, stack_frame, stack_frame_len, + &pc, &newsp, job_m_in.PM_EXECFLAGS); + + /* Reply status to PM */ + m_out.m_type = PM_EXEC_REPLY; + m_out.PM_PROC = proc_e; + m_out.PM_PC = (void*) pc; + m_out.PM_STATUS = r; + m_out.PM_NEWSP = (void *) newsp; - /* Reply status to PM */ - m_out.m_type = PM_EXEC_REPLY; - m_out.PM_PROC = proc_e; - m_out.PM_PC = (void*) pc; - m_out.PM_STATUS = r; - m_out.PM_NEWSP = (void *) newsp; - } break; - case PM_EXIT: - { - endpoint_t proc_e; - proc_e = job_m_in.PM_PROC; + case PM_EXIT: + proc_e = job_m_in.PM_PROC; - pm_exit(proc_e); + assert(proc_e == fp->fp_endpoint); + + pm_exit(); + + /* Reply dummy status to PM for synchronization */ + m_out.m_type = PM_EXIT_REPLY; + m_out.PM_PROC = proc_e; - /* Reply dummy status to PM for synchronization */ - m_out.m_type = PM_EXIT_REPLY; - m_out.PM_PROC = proc_e; - } break; - case PM_DUMPCORE: - { - endpoint_t proc_e, traced_proc_e; - int term_signal; - vir_bytes core_path; + case PM_DUMPCORE: + proc_e = job_m_in.PM_PROC; + term_signal = job_m_in.PM_TERM_SIG; + core_path = (vir_bytes) job_m_in.PM_PATH; - proc_e = job_m_in.PM_PROC; - traced_proc_e = job_m_in.PM_TRACED_PROC; - if(job_m_in.PM_PROC != job_m_in.PM_TRACED_PROC) { - /* dumpcore request */ - term_signal = 0; - } else { - /* dumpcore on exit */ - term_signal = job_m_in.PM_TERM_SIG; - } - core_path = (vir_bytes) job_m_in.PM_PATH; + assert(proc_e == fp->fp_endpoint); - r = pm_dumpcore(proc_e, term_signal, core_path); + r = pm_dumpcore(term_signal, core_path); + + /* Reply status to PM */ + m_out.m_type = PM_CORE_REPLY; + m_out.PM_PROC = proc_e; + m_out.PM_STATUS = r; - /* Reply status to PM */ - m_out.m_type = PM_CORE_REPLY; - m_out.PM_PROC = proc_e; - m_out.PM_TRACED_PROC = traced_proc_e; - m_out.PM_STATUS = r; - } break; - default: + case PM_UNPAUSE: + proc_e = job_m_in.PM_PROC; + + assert(proc_e == fp->fp_endpoint); + + unpause(); + + m_out.m_type = PM_UNPAUSE_REPLY; + m_out.PM_PROC = proc_e; + + break; + + default: panic("Unhandled postponed PM call %d", job_m_in.m_type); } @@ -916,22 +649,34 @@ static void service_pm_postponed(void) /*===========================================================================* * service_pm * *===========================================================================*/ -static void service_pm() +static void service_pm(void) { +/* Process a request from PM. This function is called from the main thread, and + * may therefore not block. Any requests that may require blocking the calling + * thread must be executed in a separate thread. Aside from PM_REBOOT, all + * requests from PM involve another, target process: for example, PM tells VFS + * that a process is performing a setuid() call. For some requests however, + * that other process may not be idle, and in that case VFS must serialize the + * PM request handling with any operation is it handling for that target + * process. As it happens, the requests that may require blocking are also the + * ones where the target process may not be idle. For both these reasons, such + * requests are run in worker threads associated to the target process. + */ + struct fproc *rfp; int r, slot; message m_out; memset(&m_out, 0, sizeof(m_out)); - switch (job_call_nr) { + switch (call_nr) { case PM_SETUID: { endpoint_t proc_e; uid_t euid, ruid; - proc_e = job_m_in.PM_PROC; - euid = job_m_in.PM_EID; - ruid = job_m_in.PM_RID; + proc_e = m_in.PM_PROC; + euid = m_in.PM_EID; + ruid = m_in.PM_RID; pm_setuid(proc_e, euid, ruid); @@ -945,9 +690,9 @@ static void service_pm() endpoint_t proc_e; gid_t egid, rgid; - proc_e = job_m_in.PM_PROC; - egid = job_m_in.PM_EID; - rgid = job_m_in.PM_RID; + proc_e = m_in.PM_PROC; + egid = m_in.PM_EID; + rgid = m_in.PM_RID; pm_setgid(proc_e, egid, rgid); @@ -960,7 +705,7 @@ static void service_pm() { endpoint_t proc_e; - proc_e = job_m_in.PM_PROC; + proc_e = m_in.PM_PROC; pm_setsid(proc_e); m_out.m_type = PM_SETSID_REPLY; @@ -971,39 +716,22 @@ static void service_pm() case PM_EXEC: case PM_EXIT: case PM_DUMPCORE: + case PM_UNPAUSE: { - endpoint_t proc_e = job_m_in.PM_PROC; + endpoint_t proc_e = m_in.PM_PROC; if(isokendpt(proc_e, &slot) != OK) { printf("VFS: proc ep %d not ok\n", proc_e); return; } - fp = &fproc[slot]; - - if (fp->fp_flags & FP_PENDING) { - /* This process has a request pending, but PM wants it - * gone. Forget about the pending request and satisfy - * PM's request instead. Note that a pending request - * AND an EXEC request are mutually exclusive. Also, PM - * should send only one request/process at a time. - */ - assert(fp->fp_job.j_m_in.m_source != PM_PROC_NR); - } + rfp = &fproc[slot]; /* PM requests on behalf of a proc are handled after the * system call that might be in progress for that proc has - * finished. If the proc is not busy, we start a dummy call. + * finished. If the proc is not busy, we start a new thread. */ - if (!(fp->fp_flags & FP_PENDING) && - mutex_trylock(&fp->fp_lock) == 0) { - mutex_unlock(&fp->fp_lock); - worker_start(do_dummy); - fp->fp_flags |= FP_DROP_WORK; - } - - fp->fp_job.j_m_in = job_m_in; - fp->fp_flags |= FP_PM_PENDING; + worker_start(rfp, NULL, &m_in, FALSE /*use_spare*/); return; } @@ -1015,16 +743,16 @@ static void service_pm() uid_t reuid; gid_t regid; - pproc_e = job_m_in.PM_PPROC; - proc_e = job_m_in.PM_PROC; - child_pid = job_m_in.PM_CPID; - reuid = job_m_in.PM_REUID; - regid = job_m_in.PM_REGID; + pproc_e = m_in.PM_PPROC; + proc_e = m_in.PM_PROC; + child_pid = m_in.PM_CPID; + reuid = m_in.PM_REUID; + regid = m_in.PM_REGID; pm_fork(pproc_e, proc_e, child_pid); m_out.m_type = PM_FORK_REPLY; - if (job_call_nr == PM_SRV_FORK) { + if (call_nr == PM_SRV_FORK) { m_out.m_type = PM_SRV_FORK_REPLY; pm_setuid(proc_e, reuid, reuid); pm_setgid(proc_e, regid, regid); @@ -1039,9 +767,9 @@ static void service_pm() int group_no; gid_t *group_addr; - proc_e = job_m_in.PM_PROC; - group_no = job_m_in.PM_GROUP_NO; - group_addr = (gid_t *) job_m_in.PM_GROUP_ADDR; + proc_e = m_in.PM_PROC; + group_no = m_in.PM_GROUP_NO; + group_addr = (gid_t *) m_in.PM_GROUP_ADDR; pm_setgroups(proc_e, group_no, group_addr); @@ -1050,29 +778,21 @@ static void service_pm() } break; - case PM_UNPAUSE: - { - endpoint_t proc_e; - - proc_e = job_m_in.PM_PROC; - - unpause(proc_e); - - m_out.m_type = PM_UNPAUSE_REPLY; - m_out.PM_PROC = proc_e; - } - break; - case PM_REBOOT: - pm_reboot(); + /* Reboot requests are not considered postponed PM work and are instead + * handled from a separate worker thread that is associated with PM's + * process. PM makes no regular VFS calls, and thus, from VFS's + * perspective, PM is always idle. Therefore, we can safely do this. + * We do assume that PM sends us only one PM_REBOOT message at once, + * or ever for that matter. :) + */ + worker_start(fproc_addr(PM_PROC_NR), pm_reboot, &m_in, + FALSE /*use_spare*/); - /* Reply dummy status to PM for synchronization */ - m_out.m_type = PM_REBOOT_REPLY; - - break; + return; default: - printf("VFS: don't know how to handle PM request %d\n", job_call_nr); + printf("VFS: don't know how to handle PM request %d\n", call_nr); return; } @@ -1080,7 +800,6 @@ static void service_pm() r = send(PM_PROC_NR, &m_out); if (r != OK) panic("service_pm: send failed: %d", r); - } @@ -1090,33 +809,41 @@ static void service_pm() static int unblock(rfp) struct fproc *rfp; { +/* Unblock a process that was previously blocked on a pipe or a lock. This is + * done by reconstructing the original request and continuing/repeating it. + * This function returns TRUE when it has restored a request for execution, and + * FALSE if the caller should continue looking for work to do. + */ int blocked_on; - fp = rfp; blocked_on = rfp->fp_blocked_on; + + assert(blocked_on == FP_BLOCKED_ON_PIPE || blocked_on == FP_BLOCKED_ON_LOCK); + + /* READ, WRITE, FCNTL requests all use the same message layout. */ m_in.m_source = rfp->fp_endpoint; m_in.m_type = rfp->fp_block_callnr; - m_in.fd = scratch(fp).file.fd_nr; - m_in.buffer = scratch(fp).io.io_buffer; - m_in.nbytes = scratch(fp).io.io_nbytes; + m_in.fd = scratch(rfp).file.fd_nr; + m_in.buffer = scratch(rfp).io.io_buffer; + m_in.nbytes = scratch(rfp).io.io_nbytes; rfp->fp_blocked_on = FP_BLOCKED_ON_NONE; /* no longer blocked */ rfp->fp_flags &= ~FP_REVIVED; reviving--; assert(reviving >= 0); - /* This should be a pipe I/O, not a device I/O. If it is, it'll 'leak' - * grants. - */ + /* This should not be device I/O. If it is, it'll 'leak' grants. */ assert(!GRANT_VALID(rfp->fp_grant)); - /* Pending pipe reads/writes can be handled directly */ + /* Pending pipe reads/writes cannot be repeated as is, and thus require a + * special resumption procedure. + */ if (blocked_on == FP_BLOCKED_ON_PIPE) { - worker_start(do_pending_pipe); - yield(); /* Give thread a chance to run */ - self = NULL; - return(0); /* Retrieve more work */ + worker_start(rfp, do_pending_pipe, &m_in, FALSE /*use_spare*/); + return(FALSE); /* Retrieve more work */ } - return(1); /* We've unblocked a process */ + /* A lock request. Repeat the original request as though it just came in. */ + fp = rfp; + return(TRUE); /* We've unblocked a process */ } diff --git a/servers/vfs/misc.c b/servers/vfs/misc.c index 8d1a4499c..c4111d2ce 100644 --- a/servers/vfs/misc.c +++ b/servers/vfs/misc.c @@ -32,9 +32,7 @@ #include #include #include "file.h" -#include "fproc.h" #include "scratchpad.h" -#include "dmap.h" #include #include "vnode.h" #include "vmnt.h" @@ -47,14 +45,7 @@ unsigned long calls_stats[NCALLS]; #endif -static void free_proc(struct fproc *freed, int flags); -/* -static int dumpcore(int proc_e, struct mem_map *seg_ptr); -static int write_bytes(struct inode *rip, off_t off, char *buf, size_t - bytes); -static int write_seg(struct inode *rip, off_t off, int proc_e, int seg, - off_t seg_off, phys_bytes seg_bytes); -*/ +static void free_proc(int flags); /*===========================================================================* * do_getsysinfo * @@ -91,11 +82,6 @@ int do_getsysinfo() len = sizeof(calls_stats); break; #endif - case SI_VMNT_TAB: - fetch_vmnt_paths(); - src_addr = (vir_bytes) vmnt; - len = sizeof(struct vmnt) * NR_MNTS; - break; default: return(EINVAL); } @@ -135,7 +121,6 @@ int do_fcntl(message *UNUSED(m_out)) else if ((r = get_fd(fp, fcntl_argx, 0, &new_fd, NULL)) == OK) { f->filp_count++; fp->fp_filp[new_fd] = f; - FD_SET(new_fd, &fp->fp_filp_inuse); r = new_fd; } break; @@ -316,7 +301,7 @@ int dupvm(struct fproc *rfp, int pfd, int *vmfd, struct filp **newfilp) { int result, procfd; struct filp *f = NULL; - struct fproc *vmf = &fproc[VM_PROC_NR]; + struct fproc *vmf = fproc_addr(VM_PROC_NR); *newfilp = NULL; @@ -354,9 +339,6 @@ int dupvm(struct fproc *rfp, int pfd, int *vmfd, struct filp **newfilp) assert(f->filp_count > 0); vmf->fp_filp[procfd] = f; - /* mmap FD's are inuse */ - FD_SET(procfd, &vmf->fp_filp_inuse); - *newfilp = f; return OK; @@ -391,7 +373,7 @@ int do_vm_call(message *m_out) if(isokendpt(ep, &slot) != OK) rfp = NULL; else rfp = &fproc[slot]; - vmf = &fproc[VM_PROC_NR]; + vmf = fproc_addr(VM_PROC_NR); assert(fp == vmf); assert(rfp != vmf); @@ -487,9 +469,14 @@ reqdone: *===========================================================================*/ void pm_reboot() { -/* Perform the VFS side of the reboot call. */ - int i; - struct fproc *rfp; +/* Perform the VFS side of the reboot call. This call is performed from the PM + * process context. + */ + message m_out; + int i, r; + struct fproc *rfp, *pmfp; + + pmfp = fp; sync_fses(); @@ -499,15 +486,25 @@ void pm_reboot() * them the chance to unmount (which should be possible as all normal * processes have no open files anymore). */ + /* This is the only place where we allow special modification of "fp". The + * reboot procedure should really be implemented as a PM message broadcasted + * to all processes, so that each process will be shut down cleanly by a + * thread operating on its behalf. Doing everything here is simpler, but it + * requires an exception to the strict model of having "fp" be the process + * that owns the current worker thread. + */ for (i = 0; i < NR_PROCS; i++) { rfp = &fproc[i]; /* Don't just free the proc right away, but let it finish what it was * doing first */ - lock_proc(rfp, 0); - if (rfp->fp_endpoint != NONE && find_vmnt(rfp->fp_endpoint) == NULL) - free_proc(rfp, 0); - unlock_proc(rfp); + if (rfp != fp) lock_proc(rfp); + if (rfp->fp_endpoint != NONE && find_vmnt(rfp->fp_endpoint) == NULL) { + worker_set_proc(rfp); /* temporarily fake process context */ + free_proc(0); + worker_set_proc(pmfp); /* restore original process context */ + } + if (rfp != fp) unlock_proc(rfp); } sync_fses(); @@ -519,15 +516,25 @@ void pm_reboot() /* Don't just free the proc right away, but let it finish what it was * doing first */ - lock_proc(rfp, 0); - if (rfp->fp_endpoint != NONE) - free_proc(rfp, 0); - unlock_proc(rfp); + if (rfp != fp) lock_proc(rfp); + if (rfp->fp_endpoint != NONE) { + worker_set_proc(rfp); /* temporarily fake process context */ + free_proc(0); + worker_set_proc(pmfp); /* restore original process context */ + } + if (rfp != fp) unlock_proc(rfp); } sync_fses(); unmount_all(1 /* Force */); + /* Reply to PM for synchronization */ + memset(&m_out, 0, sizeof(m_out)); + + m_out.m_type = PM_REBOOT_REPLY; + + if ((r = send(PM_PROC_NR, &m_out)) != OK) + panic("pm_reboot: send failed: %d", r); } /*===========================================================================* @@ -597,7 +604,7 @@ void pm_fork(endpoint_t pproc, endpoint_t cproc, pid_t cpid) /*===========================================================================* * free_proc * *===========================================================================*/ -static void free_proc(struct fproc *exiter, int flags) +static void free_proc(int flags) { int i; register struct fproc *rfp; @@ -605,46 +612,43 @@ static void free_proc(struct fproc *exiter, int flags) register struct vnode *vp; dev_t dev; - if (exiter->fp_endpoint == NONE) + if (fp->fp_endpoint == NONE) panic("free_proc: already free"); - if (fp_is_blocked(exiter)) - unpause(exiter->fp_endpoint); + if (fp_is_blocked(fp)) + unpause(); /* Loop on file descriptors, closing any that are open. */ for (i = 0; i < OPEN_MAX; i++) { - (void) close_fd(exiter, i); + (void) close_fd(fp, i); } /* Release root and working directories. */ - if (exiter->fp_rd) { put_vnode(exiter->fp_rd); exiter->fp_rd = NULL; } - if (exiter->fp_wd) { put_vnode(exiter->fp_wd); exiter->fp_wd = NULL; } + if (fp->fp_rd) { put_vnode(fp->fp_rd); fp->fp_rd = NULL; } + if (fp->fp_wd) { put_vnode(fp->fp_wd); fp->fp_wd = NULL; } /* The rest of these actions is only done when processes actually exit. */ if (!(flags & FP_EXITING)) return; - exiter->fp_flags |= FP_EXITING; + fp->fp_flags |= FP_EXITING; /* Check if any process is SUSPENDed on this driver. * If a driver exits, unmap its entries in the dmap table. * (unmapping has to be done after the first step, because the * dmap table is used in the first step.) */ - unsuspend_by_endpt(exiter->fp_endpoint); - dmap_unmap_by_endpt(exiter->fp_endpoint); + unsuspend_by_endpt(fp->fp_endpoint); + dmap_unmap_by_endpt(fp->fp_endpoint); - worker_stop_by_endpt(exiter->fp_endpoint); /* Unblock waiting threads */ - vmnt_unmap_by_endpt(exiter->fp_endpoint); /* Invalidate open files if this + worker_stop_by_endpt(fp->fp_endpoint); /* Unblock waiting threads */ + vmnt_unmap_by_endpt(fp->fp_endpoint); /* Invalidate open files if this * was an active FS */ - /* Invalidate endpoint number for error and sanity checks. */ - exiter->fp_endpoint = NONE; - /* If a session leader exits and it has a controlling tty, then revoke * access to its controlling tty from all other processes using it. */ - if ((exiter->fp_flags & FP_SESLDR) && exiter->fp_tty != 0) { - dev = exiter->fp_tty; + if ((fp->fp_flags & FP_SESLDR) && fp->fp_tty != 0) { + dev = fp->fp_tty; for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { if(rfp->fp_pid == PID_FREE) continue; if (rfp->fp_tty == dev) rfp->fp_tty = 0; @@ -656,8 +660,7 @@ static void free_proc(struct fproc *exiter, int flags) if (!S_ISCHR(vp->v_mode)) continue; if ((dev_t) vp->v_sdev != dev) continue; lock_filp(rfilp, VNODE_READ); - (void) dev_close(dev, rfilp-filp); /* Ignore any errors, even - * SUSPEND. */ + (void) cdev_close(dev); /* Ignore any errors. */ rfilp->filp_mode = FILP_CLOSED; unlock_filp(rfilp); @@ -666,25 +669,21 @@ static void free_proc(struct fproc *exiter, int flags) } /* Exit done. Mark slot as free. */ - exiter->fp_pid = PID_FREE; - if (exiter->fp_flags & FP_PENDING) - pending--; /* No longer pending job, not going to do it */ - exiter->fp_flags = FP_NOFLAGS; + fp->fp_endpoint = NONE; + fp->fp_pid = PID_FREE; + fp->fp_flags = FP_NOFLAGS; } /*===========================================================================* * pm_exit * *===========================================================================*/ -void pm_exit(proc) -endpoint_t proc; +void pm_exit(void) { -/* Perform the file system portion of the exit(status) system call. */ - int exitee_p; +/* Perform the file system portion of the exit(status) system call. + * This function is called from the context of the exiting process. + */ - /* Nevertheless, pretend that the call came from the user. */ - okendpt(proc, &exitee_p); - fp = &fproc[exitee_p]; - free_proc(fp, FP_EXITING); + free_proc(FP_EXITING); } /*===========================================================================* @@ -850,21 +849,18 @@ int do_svrctl(message *UNUSED(m_out)) /*===========================================================================* * pm_dumpcore * *===========================================================================*/ -int pm_dumpcore(endpoint_t proc_e, int csig, vir_bytes exe_name) +int pm_dumpcore(int csig, vir_bytes exe_name) { - int slot, r = OK, core_fd; + int r = OK, core_fd; struct filp *f; char core_path[PATH_MAX]; char proc_name[PROC_NAME_LEN]; - okendpt(proc_e, &slot); - fp = &fproc[slot]; - /* if a process is blocked, scratch(fp).file.fd_nr holds the fd it's blocked * on. free it up for use by common_open(). */ if (fp_is_blocked(fp)) - unpause(fp->fp_endpoint); + unpause(); /* open core file */ snprintf(core_path, PATH_MAX, "%s.%d", CORE_NAME, fp->fp_pid); @@ -884,15 +880,15 @@ int pm_dumpcore(endpoint_t proc_e, int csig, vir_bytes exe_name) core_exit: if(csig) - free_proc(fp, FP_EXITING); + free_proc(FP_EXITING); return(r); } /*===========================================================================* * ds_event * *===========================================================================*/ -void * -ds_event(void *arg) +void +ds_event(void) { char key[DS_MAX_KEYLEN]; char *blkdrv_prefix = "drv.blk."; @@ -901,11 +897,6 @@ ds_event(void *arg) int type, r, is_blk; endpoint_t owner_endpoint; - struct job my_job; - - my_job = *((struct job *) arg); - fp = my_job.j_fp; - /* Get the event and the owner from DS. */ while ((r = ds_check(key, &type, &owner_endpoint)) == OK) { /* Only check for block and character driver up events. */ @@ -928,9 +919,6 @@ ds_event(void *arg) } if (r != ENOENT) printf("VFS: ds_event: ds_check failed: %d\n", r); - - thread_cleanup(NULL); - return(NULL); } /* A function to be called on panic(). */ diff --git a/servers/vfs/mount.c b/servers/vfs/mount.c index 6db6b379d..fc4862b4d 100644 --- a/servers/vfs/mount.c +++ b/servers/vfs/mount.c @@ -24,8 +24,6 @@ #include #include #include "file.h" -#include "fproc.h" -#include "dmap.h" #include #include "vnode.h" #include "vmnt.h" @@ -99,48 +97,42 @@ int do_mount(message *UNUSED(m_out)) { /* Perform the mount(name, mfile, mount_flags) system call. */ endpoint_t fs_e; - int r, slot, rdonly, nodev; + int r, slot, nodev; char mount_path[PATH_MAX], mount_dev[PATH_MAX]; - char mount_label[LABEL_MAX]; + char mount_label[LABEL_MAX], mount_type[FSTYPE_MAX]; dev_t dev; int mflags; - vir_bytes label, vname1, vname2; - size_t vname1_length, vname2_length; + vir_bytes label, type, vname1, vname2; + size_t vname1_length, vname2_length, label_len, type_len; - mflags = job_m_in.mount_flags; - label = (vir_bytes) job_m_in.fs_label; - vname1 = (vir_bytes) job_m_in.name1; - vname1_length = (size_t) job_m_in.name1_length; - vname2 = (vir_bytes) job_m_in.name2; - vname2_length = (size_t) job_m_in.name2_length; + mflags = job_m_in.VFS_MOUNT_FLAGS; + label = (vir_bytes) job_m_in.VFS_MOUNT_LABEL; + label_len = (size_t) job_m_in.VFS_MOUNT_LABELLEN; + vname1 = (vir_bytes) job_m_in.VFS_MOUNT_DEV; + vname1_length = (size_t) job_m_in.VFS_MOUNT_DEVLEN; + vname2 = (vir_bytes) job_m_in.VFS_MOUNT_PATH; + vname2_length = (size_t) job_m_in.VFS_MOUNT_PATHLEN; + type = (vir_bytes) job_m_in.VFS_MOUNT_TYPE; + type_len = (size_t) job_m_in.VFS_MOUNT_TYPELEN; /* Only the super-user may do MOUNT. */ if (!super_user) return(EPERM); + /* Get the label from the caller, and ask DS for the endpoint of the FS. */ + if (label_len > sizeof(mount_label)) + return EINVAL; + r = sys_datacopy(who_e, label, SELF, (vir_bytes) mount_label, + sizeof(mount_label)); + if (r != OK) return(r); - /* FS process' endpoint number */ - if (mflags & MS_LABEL16) { - /* Get the label from the caller, and ask DS for the endpoint. */ - r = sys_datacopy(who_e, label, SELF, (vir_bytes) mount_label, - sizeof(mount_label)); - if (r != OK) return(r); + mount_label[sizeof(mount_label)-1] = 0; - mount_label[sizeof(mount_label)-1] = 0; - - r = ds_retrieve_label_endpt(mount_label, &fs_e); - if (r != OK) return(r); - } else { - /* Legacy support: get the endpoint from the request itself. */ - fs_e = (endpoint_t) label; - mount_label[0] = 0; - } + r = ds_retrieve_label_endpt(mount_label, &fs_e); + if (r != OK) return(r); /* Sanity check on process number. */ if (isokendpt(fs_e, &slot) != OK) return(EINVAL); - /* Should the file system be mounted read-only? */ - rdonly = (mflags & MS_RDONLY); - /* A null string for block special device means don't use a device at all. */ nodev = (vname1_length == 0); if (!nodev) { @@ -159,8 +151,13 @@ int do_mount(message *UNUSED(m_out)) /* Fetch the name of the mountpoint */ if (fetch_name(vname2, vname2_length, mount_path) != OK) return(err_code); + /* Fetch the type of the file system. */ + if (type_len > sizeof(mount_type)) return(ENAMETOOLONG); + if (fetch_name(type, type_len, mount_type) != OK) return(err_code); + /* Do the actual job */ - return mount_fs(dev, mount_dev, mount_path, fs_e, rdonly, mount_label); + return mount_fs(dev, mount_dev, mount_path, fs_e, mflags, mount_type, + mount_label); } @@ -172,7 +169,8 @@ dev_t dev, char mount_dev[PATH_MAX], char mount_path[PATH_MAX], endpoint_t fs_e, -int rdonly, +int flags, +char mount_type[FSTYPE_MAX], char mount_label[LABEL_MAX] ) { int i, r = OK, found, isroot, mount_root, con_reqs, slot; @@ -183,6 +181,7 @@ char mount_label[LABEL_MAX] ) char *label; struct node_details res; struct lookup resolve; + struct statvfs statvfs_buf; /* Look up block device driver label when dev is not a pseudo-device */ label = ""; @@ -212,6 +211,7 @@ char mount_label[LABEL_MAX] ) strlcpy(new_vmp->m_mount_path, mount_path, PATH_MAX); strlcpy(new_vmp->m_mount_dev, mount_dev, PATH_MAX); + strlcpy(new_vmp->m_fstype, mount_type, sizeof(new_vmp->m_fstype)); isroot = (strcmp(mount_path, "/") == 0); mount_root = (isroot && have_root < 2); /* Root can be mounted twice: * 1: ramdisk @@ -274,12 +274,13 @@ char mount_label[LABEL_MAX] ) /* Store some essential vmnt data first */ new_vmp->m_fs_e = fs_e; new_vmp->m_dev = dev; - if (rdonly) new_vmp->m_flags |= VMNT_READONLY; + if (flags & MNT_RDONLY) new_vmp->m_flags |= VMNT_READONLY; else new_vmp->m_flags &= ~VMNT_READONLY; /* Tell FS which device to mount */ new_vmp->m_flags |= VMNT_MOUNTING; - r = req_readsuper(fs_e, label, dev, rdonly, isroot, &res, &con_reqs); + r = req_readsuper(fs_e, label, dev, !!(flags & MNT_RDONLY), isroot, &res, + &con_reqs); new_vmp->m_flags &= ~VMNT_MOUNTING; if(req_peek(fs_e, 1, 0, PAGE_SIZE) != OK || @@ -289,6 +290,10 @@ char mount_label[LABEL_MAX] ) new_vmp->m_haspeek = 1; } + /* Fill the statvfs cache with initial values. */ + if (r == OK) + r = update_statvfs(new_vmp, &statvfs_buf); + if (r != OK) { mark_vmnt_free(new_vmp); unlock_vnode(root_node); @@ -322,6 +327,9 @@ char mount_label[LABEL_MAX] ) new_vmp->m_comm.c_max_reqs = con_reqs; new_vmp->m_comm.c_cur_reqs = 0; + /* No more blocking operations, so we can now report on this file system. */ + new_vmp->m_flags |= VMNT_CANSTAT; + if (mount_root) { /* Superblock and root node already read. * Nothing else can go wrong. Perform the mount. */ @@ -421,30 +429,28 @@ void mount_pfs(void) /*===========================================================================* * do_umount * *===========================================================================*/ -int do_umount(message *m_out) +int do_umount(message *UNUSED(m_out)) { -/* Perform the umount(name) system call. - * syscall might provide 'name' embedded in the message. +/* Perform the umount(name) system call. Return the label of the FS service. */ char label[LABEL_MAX]; dev_t dev; int r; char fullpath[PATH_MAX]; - vir_bytes vname; - size_t vname_length; + vir_bytes vname, label_addr; + size_t vname_length, label_len; - vname = (vir_bytes) job_m_in.name; - vname_length = (size_t) job_m_in.name_length; + vname = (vir_bytes) job_m_in.VFS_UMOUNT_NAME; + vname_length = (size_t) job_m_in.VFS_UMOUNT_NAMELEN; + label_addr = (vir_bytes) job_m_in.VFS_UMOUNT_LABEL; + label_len = (size_t) job_m_in.VFS_UMOUNT_LABELLEN; /* Only the super-user may do umount. */ if (!super_user) return(EPERM); /* If 'name' is not for a block special file or mountpoint, return error. */ - if (copy_name(vname_length, fullpath) != OK) { - /* Direct copy failed, try fetching from user space */ - if (fetch_name(vname, vname_length, fullpath) != OK) - return(err_code); - } + if (fetch_name(vname, vname_length, fullpath) != OK) + return(err_code); if ((dev = name_to_dev(TRUE /*allow_mountpt*/, fullpath)) == NO_DEV) return(err_code); @@ -453,10 +459,10 @@ int do_umount(message *m_out) /* Return the label of the mounted file system, so that the caller * can shut down the corresponding server process. */ - if (strlen(label) >= M3_LONG_STRING) /* should never evaluate to true */ - label[M3_LONG_STRING-1] = 0; - strlcpy(m_out->umount_label, label, M3_LONG_STRING); - return(OK); + if (strlen(label) >= label_len) + label[label_len-1] = 0; + return sys_datacopy(SELF, (vir_bytes) label, who_e, label_addr, + strlen(label) + 1); } @@ -499,6 +505,9 @@ int unmount( return(EBUSY); /* can't umount a busy file system */ } + /* This FS will now disappear, so stop listing it in statistics. */ + vmp->m_flags &= ~VMNT_CANSTAT; + /* Tell FS to drop all inode references for root inode except 1. */ vnode_clean_refs(vmp->m_root_node); diff --git a/servers/vfs/open.c b/servers/vfs/open.c index 2d0dde200..139751811 100644 --- a/servers/vfs/open.c +++ b/servers/vfs/open.c @@ -19,9 +19,7 @@ #include #include #include "file.h" -#include "fproc.h" #include "scratchpad.h" -#include "dmap.h" #include "lock.h" #include "param.h" #include @@ -130,7 +128,6 @@ int common_open(char path[PATH_MAX], int oflags, mode_t omode) /* Claim the file descriptor and filp slot and fill them in. */ fp->fp_filp[scratch(fp).file.fd_nr] = filp; - FD_SET(scratch(fp).file.fd_nr, &fp->fp_filp_inuse); filp->filp_count = 1; filp->filp_vno = vp; filp->filp_flags = oflags; @@ -160,10 +157,9 @@ int common_open(char path[PATH_MAX], int oflags, mode_t omode) /* Invoke the driver for special processing. */ dev = (dev_t) vp->v_sdev; /* TTY needs to know about the O_NOCTTY flag. */ - r = dev_open(dev, who_e, bits | (oflags & O_NOCTTY)); - if (r == SUSPEND) suspend(FP_BLOCKED_ON_DOPEN); - else vp = filp->filp_vno; /* Might be updated by - * dev_open/clone_opcl */ + r = cdev_open(dev, bits | (oflags & O_NOCTTY)); + vp = filp->filp_vno; /* Might be updated by + * cdev_open after cloning */ break; case S_IFBLK: @@ -271,10 +267,8 @@ int common_open(char path[PATH_MAX], int oflags, mode_t omode) if (r != OK) { if (r != SUSPEND) { fp->fp_filp[scratch(fp).file.fd_nr] = NULL; - FD_CLR(scratch(fp).file.fd_nr, &fp->fp_filp_inuse); filp->filp_count = 0; filp->filp_vno = NULL; - filp->filp_state &= ~FS_INVALIDATED; /* Prevent garbage col. */ put_vnode(vp); } } else { @@ -749,7 +743,6 @@ int fd_nr; close_filp(rfilp); FD_CLR(fd_nr, &rfp->fp_cloexec_set); - FD_CLR(fd_nr, &rfp->fp_filp_inuse); /* Check to see if the file is locked. If so, release all locks. */ if (nr_locks > 0) { @@ -767,11 +760,3 @@ int fd_nr; return(OK); } - -/*===========================================================================* - * close_reply * - *===========================================================================*/ -void close_reply() -{ - /* No need to do anything */ -} diff --git a/servers/vfs/param.h b/servers/vfs/param.h index c31b58fe3..e76ce33f4 100644 --- a/servers/vfs/param.h +++ b/servers/vfs/param.h @@ -30,13 +30,9 @@ #define offset_lo m2_l1 #define offset_high m2_l2 #define ctl_req m4_l1 -#define mount_flags m1_i3 #define pipe_flags m1_i3 #define request m1_i2 #define sig m1_i2 -#define endpt1 m1_i1 -#define fs_label m1_p3 -#define umount_label m3_ca1 #define tp m2_l1 #define utime_actime m2_l1 #define utime_modtime m2_l2 diff --git a/servers/vfs/path.c b/servers/vfs/path.c index 3d94215db..d5a886de7 100644 --- a/servers/vfs/path.c +++ b/servers/vfs/path.c @@ -18,11 +18,9 @@ #include #include #include -#include "threads.h" #include "vmnt.h" #include "vnode.h" #include "path.h" -#include "fproc.h" #include "param.h" /* Set to following define to 1 if you really want to use the POSIX definition @@ -872,6 +870,9 @@ size_t pathlen; *===========================================================================*/ int do_check_perms(message *UNUSED(m_out)) { - return check_perms(job_m_in.USER_ENDPT, (cp_grant_id_t) job_m_in.IO_GRANT, - (size_t) job_m_in.COUNT); + /* This should be replaced by an ACL check. */ + if (who_e != PFS_PROC_NR) return EPERM; + + return check_perms(job_m_in.VFS_PFS_ENDPT, job_m_in.VFS_PFS_GRANT, + (size_t) job_m_in.VFS_PFS_COUNT); } diff --git a/servers/vfs/pipe.c b/servers/vfs/pipe.c index 8f4fd7036..135891e3b 100644 --- a/servers/vfs/pipe.c +++ b/servers/vfs/pipe.c @@ -27,9 +27,7 @@ #include #include #include "file.h" -#include "fproc.h" #include "scratchpad.h" -#include "dmap.h" #include "param.h" #include #include "vnode.h" @@ -107,11 +105,9 @@ static int create_pipe(int fil_des[2], int flags) return(r); } rfp->fp_filp[fil_des[0]] = fil_ptr0; - FD_SET(fil_des[0], &rfp->fp_filp_inuse); fil_ptr0->filp_count = 1; /* mark filp in use */ if ((r = get_fd(fp, 0, W_BIT, &fil_des[1], &fil_ptr1)) != OK) { rfp->fp_filp[fil_des[0]] = NULL; - FD_CLR(fil_des[0], &rfp->fp_filp_inuse); fil_ptr0->filp_count = 0; /* mark filp free */ unlock_filp(fil_ptr0); unlock_vnode(vp); @@ -119,7 +115,6 @@ static int create_pipe(int fil_des[2], int flags) return(r); } rfp->fp_filp[fil_des[1]] = fil_ptr1; - FD_SET(fil_des[1], &rfp->fp_filp_inuse); fil_ptr1->filp_count = 1; /* Create a named pipe inode on PipeFS */ @@ -128,10 +123,8 @@ static int create_pipe(int fil_des[2], int flags) if (r != OK) { rfp->fp_filp[fil_des[0]] = NULL; - FD_CLR(fil_des[0], &rfp->fp_filp_inuse); fil_ptr0->filp_count = 0; rfp->fp_filp[fil_des[1]] = NULL; - FD_CLR(fil_des[1], &rfp->fp_filp_inuse); fil_ptr1->filp_count = 0; unlock_filp(fil_ptr1); unlock_filp(fil_ptr0); @@ -334,9 +327,6 @@ void suspend(int why) fp->fp_blocked_on = why; assert(fp->fp_grant == GRANT_INVALID || !GRANT_VALID(fp->fp_grant)); fp->fp_block_callnr = job_call_nr; - fp->fp_flags &= ~FP_SUSP_REOPEN; /* Clear this flag. The caller - * can set it when needed. - */ } /*===========================================================================* @@ -383,7 +373,7 @@ void unsuspend_by_endpt(endpoint_t proc_e) for (rp = &fproc[0]; rp < &fproc[NR_PROCS]; rp++) { if (rp->fp_pid == PID_FREE) continue; if (rp->fp_blocked_on == FP_BLOCKED_ON_OTHER && rp->fp_task == proc_e) - revive(rp->fp_endpoint, EAGAIN); + revive(rp->fp_endpoint, EIO); } /* Revive processes waiting in drivers on select()s with EAGAIN too */ @@ -436,11 +426,10 @@ int count; /* max number of processes to release */ */ if (rp->fp_blocked_on == FP_BLOCKED_ON_POPEN || - rp->fp_blocked_on == FP_BLOCKED_ON_DOPEN || rp->fp_blocked_on == FP_BLOCKED_ON_LOCK || rp->fp_blocked_on == FP_BLOCKED_ON_OTHER) { - if (!FD_ISSET(scratch(rp).file.fd_nr, - &rp->fp_filp_inuse)) + f = rp->fp_filp[scratch(rp).file.fd_nr]; + if (f == NULL || f->filp_mode == FILP_CLOSED) continue; if (rp->fp_filp[scratch(rp).file.fd_nr]->filp_vno != vp) continue; @@ -469,12 +458,12 @@ int count; /* max number of processes to release */ void revive(endpoint_t proc_e, int returned) { /* Revive a previously blocked process. When a process hangs on tty, this - * is the way it is eventually released. + * is the way it is eventually released. For processes blocked on _SELECT and + * _OTHER, this function MUST NOT block its calling thread. */ struct fproc *rfp; int blocked_on; int fd_nr, slot; - struct filp *fil_ptr; if (proc_e == NONE || isokendpt(proc_e, &slot) != OK) return; @@ -492,26 +481,6 @@ void revive(endpoint_t proc_e, int returned) /* Revive a process suspended on a pipe or lock. */ rfp->fp_flags |= FP_REVIVED; reviving++; /* process was waiting on pipe or lock */ - } else if (blocked_on == FP_BLOCKED_ON_DOPEN) { - rfp->fp_blocked_on = FP_BLOCKED_ON_NONE; - scratch(rfp).file.fd_nr = 0; - if (returned < 0) { - fil_ptr = rfp->fp_filp[fd_nr]; - lock_filp(fil_ptr, VNODE_OPCL); - rfp->fp_filp[fd_nr] = NULL; - FD_CLR(fd_nr, &rfp->fp_filp_inuse); - if (fil_ptr->filp_count != 1) { - panic("VFS: revive: bad count in filp: %d", - fil_ptr->filp_count); - } - fil_ptr->filp_count = 0; - unlock_filp(fil_ptr); - put_vnode(fil_ptr->filp_vno); - fil_ptr->filp_vno = NULL; - replycode(proc_e, returned); - } else { - replycode(proc_e, fd_nr); - } } else { rfp->fp_blocked_on = FP_BLOCKED_ON_NONE; scratch(rfp).file.fd_nr = 0; @@ -544,97 +513,68 @@ void revive(endpoint_t proc_e, int returned) /*===========================================================================* * unpause * *===========================================================================*/ -void unpause(endpoint_t proc_e) +void unpause(void) { /* A signal has been sent to a user who is paused on the file system. * Abort the system call with the EINTR error message. */ - - register struct fproc *rfp, *org_fp; - int slot, blocked_on, fild, status = EINTR, major_dev, minor_dev; + int blocked_on, fild, status = EINTR; struct filp *f; dev_t dev; - message mess; int wasreviving = 0; - if (isokendpt(proc_e, &slot) != OK) { - printf("VFS: ignoring unpause for bogus endpoint %d\n", proc_e); - return; - } + if (!fp_is_blocked(fp)) return; + blocked_on = fp->fp_blocked_on; - rfp = &fproc[slot]; - if (!fp_is_blocked(rfp)) return; - blocked_on = rfp->fp_blocked_on; + /* Clear the block status now. The procedure below might make blocking calls + * and it is imperative that while at least cdev_cancel() is executing, other + * parts of VFS do not perceive this process as blocked on something. + */ + fp->fp_blocked_on = FP_BLOCKED_ON_NONE; - if (rfp->fp_flags & FP_REVIVED) { - rfp->fp_flags &= ~FP_REVIVED; + if (fp->fp_flags & FP_REVIVED) { + fp->fp_flags &= ~FP_REVIVED; reviving--; wasreviving = 1; } switch (blocked_on) { case FP_BLOCKED_ON_PIPE:/* process trying to read or write a pipe */ + /* If the operation succeeded partially, return the bytes + * processed so far, and clear the remembered state. Otherwise, + * return EINTR as usual. + */ + if (fp->fp_cum_io_partial > 0) { + status = fp->fp_cum_io_partial; + + fp->fp_cum_io_partial = 0; + } break; case FP_BLOCKED_ON_LOCK:/* process trying to set a lock with FCNTL */ break; case FP_BLOCKED_ON_SELECT:/* process blocking on select() */ - select_forget(proc_e); + select_forget(); break; case FP_BLOCKED_ON_POPEN: /* process trying to open a fifo */ break; - case FP_BLOCKED_ON_DOPEN:/* process trying to open a device */ - /* Don't cancel OPEN. Just wait until the open completes. */ - return; - case FP_BLOCKED_ON_OTHER:/* process trying to do device I/O (e.g. tty)*/ - if (rfp->fp_flags & FP_SUSP_REOPEN) { - /* Process is suspended while waiting for a reopen. - * Just reply EINTR. - */ - rfp->fp_flags &= ~FP_SUSP_REOPEN; - status = EINTR; - break; - } - - fild = scratch(rfp).file.fd_nr; + fild = scratch(fp).file.fd_nr; if (fild < 0 || fild >= OPEN_MAX) panic("file descriptor out-of-range"); - f = rfp->fp_filp[fild]; + f = fp->fp_filp[fild]; if(!f) { - sys_sysctl_stacktrace(rfp->fp_endpoint); + sys_diagctl_stacktrace(fp->fp_endpoint); panic("process %d blocked on empty fd %d", - rfp->fp_endpoint, fild); + fp->fp_endpoint, fild); } dev = (dev_t) f->filp_vno->v_sdev; /* device hung on */ - major_dev = major(dev); - minor_dev = minor(dev); - mess.TTY_LINE = minor_dev; - mess.USER_ENDPT = rfp->fp_ioproc; - mess.IO_GRANT = (char *) rfp->fp_grant; - /* Tell kernel R or W. Mode is from current call, not open. */ - mess.COUNT = rfp->fp_block_callnr == READ ? R_BIT : W_BIT; - mess.m_type = CANCEL; + status = cdev_cancel(dev); - org_fp = fp; - fp = rfp; /* hack - ctty_io uses fp */ - (*dmap[major_dev].dmap_io)(rfp->fp_task, &mess); - fp = org_fp; - status = mess.REP_STATUS; - if (status == SUSPEND) - return; /* Process will be revived at a - * later time. - */ - - if (status == EAGAIN) status = EINTR; - if (GRANT_VALID(rfp->fp_grant)) { - (void) cpf_revoke(rfp->fp_grant); - rfp->fp_grant = GRANT_INVALID; - } break; default : panic("VFS: unknown block reason: %d", blocked_on); @@ -645,9 +585,5 @@ void unpause(endpoint_t proc_e) susp_count--; } - if(rfp->fp_blocked_on != FP_BLOCKED_ON_NONE) { - rfp->fp_blocked_on = FP_BLOCKED_ON_NONE; - replycode(proc_e, status); /* signal interrupted call */ - } + replycode(fp->fp_endpoint, status); /* signal interrupted call */ } - diff --git a/servers/vfs/protect.c b/servers/vfs/protect.c index 4f76bc9e2..d719e3e07 100644 --- a/servers/vfs/protect.c +++ b/servers/vfs/protect.c @@ -14,7 +14,6 @@ #include #include #include "file.h" -#include "fproc.h" #include "path.h" #include "param.h" #include diff --git a/servers/vfs/proto.h b/servers/vfs/proto.h index 6a048c25d..b6037445f 100644 --- a/servers/vfs/proto.h +++ b/servers/vfs/proto.h @@ -29,17 +29,19 @@ void fs_sendmore(struct vmnt *vmp); void send_work(void); /* device.c */ -int dev_open(dev_t dev, endpoint_t proc_e, int flags); -int dev_reopen(dev_t dev, int filp_no, int flags); -void dev_reply(struct dmap *dp); -int dev_close(dev_t dev, int filp_no); +int cdev_open(dev_t dev, int flags); +int cdev_close(dev_t dev); +int cdev_io(int op, dev_t dev, endpoint_t proc_e, void *buf, u64_t pos, + unsigned long bytes, int flags); +int cdev_select(dev_t dev, int ops); +int cdev_cancel(dev_t dev); +void cdev_reply(void); int bdev_open(dev_t dev, int access); int bdev_close(dev_t dev); -int dev_io(int op, dev_t dev, endpoint_t proc_e, void *buf, u64_t pos, - size_t bytes, int flags, int suspend_reopen); +void bdev_reply(void); +void bdev_up(int major); int gen_opcl(int op, dev_t dev, endpoint_t task_nr, int flags); -int gen_io(endpoint_t driver_e, message *mess_ptr); -int asyn_io(endpoint_t drv_e, message *mess_ptr); +int gen_io(endpoint_t drv_e, message *mess_ptr); int no_dev(int op, dev_t dev, endpoint_t proc, int flags); int no_dev_io(endpoint_t, message *); int tty_opcl(int op, dev_t dev, endpoint_t proc, int flags); @@ -48,17 +50,11 @@ int clone_opcl(int op, dev_t dev, endpoint_t proc, int flags); int ctty_io(endpoint_t task_nr, message *mess_ptr); int do_ioctl(message *m_out); void pm_setsid(endpoint_t proc_e); -void dev_status(endpoint_t drv_e); -void bdev_up(int major); -void cdev_up(int major); -endpoint_t find_suspended_ep(endpoint_t driver, cp_grant_id_t g); -void reopen_reply(void); -void open_reply(void); /* dmap.c */ void lock_dmap(struct dmap *dp); void unlock_dmap(struct dmap *dp); -int do_mapdriver(void); +int do_mapdriver(message *m_out); void init_dmap(void); void init_dmap_locks(void); int dmap_driver_match(endpoint_t proc, int major); @@ -66,7 +62,6 @@ void dmap_endpt_up(endpoint_t proc_nr, int is_blk); void dmap_unmap_by_endpt(endpoint_t proc_nr); struct dmap *get_dmap(endpoint_t proc_e); struct dmap *get_dmap_by_major(int major); -int do_mapdriver(void); int map_service(struct rprocpub *rpub); void dmap_unmap_by_endpt(endpoint_t proc_nr); int map_driver(const char *label, int major, endpoint_t proc_nr, int @@ -77,11 +72,10 @@ int map_service(struct rprocpub *rpub); void write_elf_core_file(struct filp *f, int csig, char *exe_name); /* exec.c */ -int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len, vir_bytes frame, - size_t frame_len, vir_bytes *pc, vir_bytes *newsp, int flags); +int pm_exec(vir_bytes path, size_t path_len, vir_bytes frame, size_t frame_len, + vir_bytes *pc, vir_bytes *newsp, int flags); /* filedes.c */ -void *do_filp_gc(void *arg); void check_filp_locks(void); void check_filp_locks_by_me(void); void init_filps(void); @@ -93,7 +87,7 @@ struct filp *get_filp2(struct fproc *rfp, int fild, tll_access_t locktype); void lock_filp(struct filp *filp, tll_access_t locktype); void unlock_filp(struct filp *filp); void unlock_filps(struct filp *filp1, struct filp *filp2); -int invalidate_filp(struct filp *); +void invalidate_filp(struct filp *); void invalidate_filp_by_endpt(endpoint_t proc_e); void invalidate_filp_by_char_major(int major); int do_verify_fd(message *m_out); @@ -106,6 +100,7 @@ int do_put_filp(message *m_out); int cancel_fd(endpoint_t ep, int fd); int do_cancel_fd(message *m_out); void close_filp(struct filp *fp); +int do_dupfrom(message *m_out); /* fscall.c */ void nested_fs_call(message *m); @@ -125,14 +120,15 @@ void lock_revive(void); /* main.c */ int main(void); -void lock_proc(struct fproc *rfp, int force_lock); +void lock_proc(struct fproc *rfp); +void unlock_proc(struct fproc *rfp); void reply(message *m_out, endpoint_t whom, int result); void replycode(endpoint_t whom, int result); -void thread_cleanup(struct fproc *rfp); -void unlock_proc(struct fproc *rfp); +void service_pm_postponed(void); +void thread_cleanup(void); /* misc.c */ -void pm_exit(endpoint_t proc); +void pm_exit(void); int do_fcntl(message *m_out); void pm_fork(endpoint_t pproc, endpoint_t cproc, pid_t cpid); void pm_setgid(endpoint_t proc_e, int egid, int rgid); @@ -144,8 +140,8 @@ void pm_reboot(void); int do_svrctl(message *m_out); int do_getsysinfo(void); int do_vm_call(message *m_out); -int pm_dumpcore(endpoint_t proc_e, int sig, vir_bytes exe_name); -void * ds_event(void *arg); +int pm_dumpcore(int sig, vir_bytes exe_name); +void ds_event(void); int dupvm(struct fproc *fp, int pfd, int *vmfd, struct filp **f); int do_getrusage(message *m_out); @@ -156,14 +152,14 @@ int do_umount(message *m_out); int is_nonedev(dev_t dev); void mount_pfs(void); int mount_fs(dev_t dev, char mount_dev[PATH_MAX], char mount_path[PATH_MAX], - endpoint_t fs_e, int rdonly, char mount_label[LABEL_MAX]); + endpoint_t fs_e, int rdonly, char mount_type[FSTYPE_MAX], + char mount_label[LABEL_MAX]); int unmount(dev_t dev, char label[LABEL_MAX]); void unmount_all(int force); /* open.c */ int do_close(message *m_out); int close_fd(struct fproc *rfp, int fd_nr); -void close_reply(void); int common_open(char path[PATH_MAX], int oflags, mode_t omode); int do_creat(void); int do_lseek(message *m_out); @@ -193,7 +189,7 @@ int do_check_perms(message *m_out); int do_pipe(message *m_out); int do_pipe2(message *m_out); int map_vnode(struct vnode *vp, endpoint_t fs_e); -void unpause(endpoint_t proc_e); +void unpause(void); int pipe_check(struct filp *filp, int rw_flag, int oflags, int bytes, int notouch); void release(struct vnode *vp, int op, int count); @@ -236,8 +232,7 @@ int req_chown(endpoint_t fs_e, ino_t inode_nr, uid_t newuid, gid_t newgid, int req_create(int fs_e, ino_t inode_nr, int omode, uid_t uid, gid_t gid, char *path, node_details_t *res); int req_flush(endpoint_t fs_e, dev_t dev); -int req_fstatfs(endpoint_t fs_e, endpoint_t proc_e, vir_bytes buf); -int req_statvfs(endpoint_t fs_e, endpoint_t proc_e, vir_bytes buf); +int req_statvfs(endpoint_t fs_e, struct statvfs *buf); int req_ftrunc(endpoint_t fs_e, ino_t inode_nr, off_t start, off_t end); int req_getdents(endpoint_t fs_e, ino_t inode_nr, u64_t pos, char *buf, size_t size, u64_t *new_pos, int direct); @@ -283,11 +278,12 @@ int do_fchdir(message *m_out); int do_chroot(message *m_out); int do_fstat(message *m_out); int do_stat(message *m_out); -int do_fstatfs(message *m_out); int do_statvfs(message *m_out); int do_fstatvfs(message *m_out); +int do_getvfsstat(message *m_out); int do_rdlink(message *m_out); int do_lstat(message *m_out); +int update_statvfs(struct vmnt *vmp, struct statvfs *buf); /* time.c */ int do_utime(message *); @@ -359,22 +355,24 @@ int do_gcov_flush(void); int do_select(message *m_out); void init_select(void); void select_callback(struct filp *, int ops); -void select_forget(endpoint_t proc_e); +void select_forget(void); void select_reply1(endpoint_t driver_e, int minor, int status); void select_reply2(endpoint_t driver_e, int minor, int status); void select_timeout_check(timer_t *); void select_unsuspend_by_endpt(endpoint_t proc); /* worker.c */ +void worker_init(void); int worker_available(void); struct worker_thread *worker_get(thread_t worker_tid); -struct job *worker_getjob(thread_t worker_tid); -void worker_init(struct worker_thread *worker); void worker_signal(struct worker_thread *worker); -void worker_start(void *(*func)(void *arg)); +int worker_can_start(struct fproc *rfp); +void worker_start(struct fproc *rfp, void (*func)(void), message *m_ptr, + int use_spare); void worker_stop(struct worker_thread *worker); void worker_stop_by_endpt(endpoint_t proc_e); void worker_wait(void); -void sys_worker_start(void *(*func)(void *arg)); -void dl_worker_start(void *(*func)(void *arg)); +struct worker_thread *worker_suspend(void); +void worker_resume(struct worker_thread *org_self); +void worker_set_proc(struct fproc *rfp); #endif diff --git a/servers/vfs/read.c b/servers/vfs/read.c index a96f07066..775102dc7 100644 --- a/servers/vfs/read.c +++ b/servers/vfs/read.c @@ -16,7 +16,6 @@ #include #include #include "file.h" -#include "fproc.h" #include "scratchpad.h" #include "param.h" #include @@ -41,20 +40,17 @@ int do_read(message *UNUSED(m_out)) *===========================================================================*/ void lock_bsf(void) { - struct fproc *org_fp; struct worker_thread *org_self; if (mutex_trylock(&bsf_lock) == 0) return; - org_fp = fp; - org_self = self; + org_self = worker_suspend(); if (mutex_lock(&bsf_lock) != 0) panic("unable to lock block special file lock"); - fp = org_fp; - self = org_self; + worker_resume(org_self); } /*===========================================================================* @@ -108,7 +104,7 @@ int actual_read_write_peek(struct fproc *rfp, int rw_flag, int io_fd, if (((f->filp_mode) & (ro ? R_BIT : W_BIT)) == 0) { unlock_filp(f); - return(f->filp_mode == FILP_CLOSED ? EIO : EBADF); + return(EBADF); } if (scratch(rfp).io.io_nbytes == 0) { unlock_filp(f); @@ -140,6 +136,7 @@ int read_write(struct fproc *rfp, int rw_flag, struct filp *f, u64_t position, res_pos; unsigned int cum_io, cum_io_incr, res_cum_io; int op, r; + dev_t dev; position = f->filp_pos; vp = f->filp_vno; @@ -150,7 +147,7 @@ int read_write(struct fproc *rfp, int rw_flag, struct filp *f, if (size > SSIZE_MAX) return(EINVAL); - op = (rw_flag == READING ? VFS_DEV_READ : VFS_DEV_WRITE); + op = (rw_flag == READING ? CDEV_READ : CDEV_WRITE); if (S_ISFIFO(vp->v_mode)) { /* Pipes */ if (rfp->fp_cum_io_partial != 0) { @@ -162,10 +159,6 @@ int read_write(struct fproc *rfp, int rw_flag, struct filp *f, } r = rw_pipe(rw_flag, for_e, f, buf, size); } else if (S_ISCHR(vp->v_mode)) { /* Character special files. */ - dev_t dev; - int suspend_reopen; - int op = (rw_flag == READING ? VFS_DEV_READ : VFS_DEV_WRITE); - if(rw_flag == PEEKING) { printf("read_write: peek on char device makes no sense\n"); return EINVAL; @@ -174,15 +167,35 @@ int read_write(struct fproc *rfp, int rw_flag, struct filp *f, if (vp->v_sdev == NO_DEV) panic("VFS: read_write tries to access char dev NO_DEV"); - suspend_reopen = (f->filp_state & FS_NEEDS_REOPEN); dev = (dev_t) vp->v_sdev; - r = dev_io(op, dev, for_e, buf, position, size, f->filp_flags, - suspend_reopen); + r = cdev_io(op, dev, for_e, buf, position, size, f->filp_flags); if (r >= 0) { + /* This should no longer happen: all calls are asynchronous. */ + printf("VFS: I/O to device %x succeeded immediately!?\n", dev); cum_io = r; - position = add64ul(position, r); + position += r; r = OK; + } else if (r == SUSPEND) { + /* FIXME: multiple read/write operations on a single filp + * should be serialized. They currently aren't; in order to + * achieve a similar effect, we optimistically advance the file + * position here. This works under the following assumptions: + * - character drivers that use the seek position at all, + * expose a view of a statically-sized range of bytes, i.e., + * they are basically byte-granular block devices; + * - if short I/O or an error is returned, all subsequent calls + * will return (respectively) EOF and an error; + * - the application never checks its own file seek position, + * or does not care that it may end up having seeked beyond + * the number of bytes it has actually read; + * - communication to the character driver is FIFO (this one + * is actually true! whew). + * Many improvements are possible here, but in the end, + * anything short of queuing concurrent operations will be + * suboptimal - so we settle for this hack for now. + */ + position += size; } } else if (S_ISBLK(vp->v_mode)) { /* Block special files. */ if (vp->v_sdev == NO_DEV) diff --git a/servers/vfs/request.c b/servers/vfs/request.c index 71ea86ae2..d4f850508 100644 --- a/servers/vfs/request.c +++ b/servers/vfs/request.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -18,7 +17,6 @@ #include #include #include -#include "fproc.h" #include "vmnt.h" #include "vnode.h" #include "path.h" @@ -218,45 +216,19 @@ int req_flush(endpoint_t fs_e, dev_t dev) } -/*===========================================================================* - * req_fstatfs * - *===========================================================================*/ -int req_fstatfs(endpoint_t fs_e, endpoint_t proc_e, vir_bytes buf) -{ - int r; - cp_grant_id_t grant_id; - message m; - - grant_id = cpf_grant_magic(fs_e, proc_e, buf, sizeof(struct statfs), - CPF_WRITE); - if (grant_id == GRANT_INVALID) - panic("req_fstatfs: cpf_grant_magic failed"); - - /* Fill in request message */ - m.m_type = REQ_FSTATFS; - m.REQ_GRANT = grant_id; - - /* Send/rec request */ - r = fs_sendrec(fs_e, &m); - cpf_revoke(grant_id); - - return(r); -} - - /*===========================================================================* * req_statvfs * *===========================================================================*/ -int req_statvfs(endpoint_t fs_e, endpoint_t proc_e, vir_bytes buf) +int req_statvfs(endpoint_t fs_e, struct statvfs *buf) { int r; cp_grant_id_t grant_id; message m; - grant_id = cpf_grant_magic(fs_e, proc_e, buf, sizeof(struct statvfs), + grant_id = cpf_grant_direct(fs_e, (vir_bytes) buf, sizeof(struct statvfs), CPF_WRITE); if(grant_id == GRANT_INVALID) - panic("req_statvfs: cpf_grant_magic failed"); + panic("req_statvfs: cpf_grant_direct failed"); /* Fill in request message */ m.m_type = REQ_STATVFS; diff --git a/servers/vfs/select.c b/servers/vfs/select.c index 53f183bf9..e831afc28 100644 --- a/servers/vfs/select.c +++ b/servers/vfs/select.c @@ -4,6 +4,14 @@ * do_select: perform the SELECT system call * select_callback: notify select system of possible fd operation * select_unsuspend_by_endpt: cancel a blocking select on exiting driver + * + * The select code uses minimal locking, so that the replies from character + * drivers can be processed without blocking. Filps are locked only for pipes. + * We make the assumption that any other structures and fields are safe to + * check (and possibly change) as long as we know that a process is blocked on + * a select(2) call, meaning that all involved filps are guaranteed to stay + * open until either we finish the select call, it the process gets interrupted + * by a signal. */ #include "fs.h" @@ -17,8 +25,6 @@ #include #include "file.h" -#include "fproc.h" -#include "dmap.h" #include "vnode.h" /* max. number of simultaneously pending select() calls */ @@ -37,26 +43,23 @@ static struct selectentry { int nfds, nreadyfds; int error; char block; + char starting; clock_t expiry; timer_t timer; /* if expiry > 0 */ } selecttab[MAXSELECTS]; -static int copy_fdsets(struct selectentry *se, int nfds, int - direction); -static int do_select_request(struct selectentry *se, int fd, int *ops); +static int copy_fdsets(struct selectentry *se, int nfds, int direction); static void filp_status(struct filp *fp, int status); static int is_deferred(struct selectentry *se); static void restart_proc(struct selectentry *se); static void ops2tab(int ops, int fd, struct selectentry *e); static int is_regular_file(struct filp *f); static int is_pipe(struct filp *f); -static int is_supported_major(struct filp *f); +static int is_char_device(struct filp *f); static void select_lock_filp(struct filp *f, int ops); -static int select_request_async(struct filp *f, int *ops, int block); static int select_request_file(struct filp *f, int *ops, int block); -static int select_request_major(struct filp *f, int *ops, int block); +static int select_request_char(struct filp *f, int *ops, int block); static int select_request_pipe(struct filp *f, int *ops, int block); -static int select_request_sync(struct filp *f, int *ops, int block); static void select_cancel_all(struct selectentry *e); static void select_cancel_filp(struct filp *f); static void select_return(struct selectentry *); @@ -68,18 +71,11 @@ static struct fdtype { int (*select_request)(struct filp *, int *ops, int block); int (*type_match)(struct filp *f); } fdtypes[] = { - { select_request_major, is_supported_major }, + { select_request_char, is_char_device }, { select_request_file, is_regular_file }, { select_request_pipe, is_pipe }, }; #define SEL_FDS (sizeof(fdtypes) / sizeof(fdtypes[0])) -static int select_majors[] = { /* List of majors that support selecting on */ - TTY_MAJOR, - INET_MAJOR, - UDS_MAJOR, - LOG_MAJOR, -}; -#define SEL_MAJORS (sizeof(select_majors) / sizeof(select_majors[0])) /*===========================================================================* * do_select * @@ -88,13 +84,15 @@ int do_select(message *UNUSED(m_out)) { /* Implement the select(nfds, readfds, writefds, errorfds, timeout) system * call. First we copy the arguments and verify their sanity. Then we check - * whether there are file descriptors that satisfy the select call right of the - * bat. If so, or if there are no ready file descriptors but the process + * whether there are file descriptors that satisfy the select call right off + * the bat. If so, or if there are no ready file descriptors but the process * requested to return immediately, we return the result. Otherwise we set a * timeout and wait for either the file descriptors to become ready or the - * timer to go off. If no timeout value was provided, we wait indefinitely. */ - + * timer to go off. If no timeout value was provided, we wait indefinitely. + */ int r, nfds, do_timeout = 0, fd, s; + struct filp *f; + unsigned int type, ops; struct timeval timeout; struct selectentry *se; vir_bytes vtimeout; @@ -153,11 +151,14 @@ int do_select(message *UNUSED(m_out)) se->block = 0; se->expiry = 0; /* no timer set (yet) */ + /* We are going to lock filps, and that means that while locking a second + * filp, we might already get the results for the first one. In that case, + * the incoming results must not cause the select call to finish prematurely. + */ + se->starting = TRUE; + /* Verify that file descriptors are okay to select on */ for (fd = 0; fd < nfds; fd++) { - struct filp *f; - unsigned int type, ops; - /* Because the select() interface implicitly includes file descriptors * you might not want to select on, we have to figure out whether we're * interested in them. Typically, these file descriptors include fd's @@ -189,9 +190,11 @@ int do_select(message *UNUSED(m_out)) * TTY major and sockets by either INET major (socket type AF_INET) or * PFS major (socket type AF_UNIX). PFS acts as an FS when it handles * pipes and as a driver when it handles sockets. Additionally, we - * support select on the LOG major to handle kernel logging, which is - * beyond the POSIX spec. */ - + * give other character drivers the chance to handle select for any of + * their device nodes. Some may not implement support for select and + * let libchardriver return EBADF, which we then pass to the calling + * process once we receive the reply. + */ se->type[fd] = -1; for (type = 0; type < SEL_FDS; type++) { if (fdtypes[type].type_match(f)) { @@ -210,23 +213,37 @@ int do_select(message *UNUSED(m_out)) /* Check all file descriptors in the set whether one is 'ready' now */ for (fd = 0; fd < nfds; fd++) { - int ops, r; - struct filp *f; - /* Again, check for involuntarily selected fd's */ if (!(ops = tab2ops(fd, se))) continue; /* No operations set; nothing to do for this fd */ + /* File descriptors selected for reading that are not opened for + * reading should be marked as readable, as read calls would fail + * immediately. The same applies to writing. + */ + f = se->filps[fd]; + if ((ops & SEL_RD) && !(f->filp_mode & R_BIT)) { + ops2tab(SEL_RD, fd, se); + ops &= ~SEL_RD; + } + if ((ops & SEL_WR) && !(f->filp_mode & W_BIT)) { + ops2tab(SEL_WR, fd, se); + ops &= ~SEL_WR; + } /* Test filp for select operations if not already done so. e.g., * processes sharing a filp and both doing a select on that filp. */ - f = se->filps[fd]; if ((f->filp_select_ops & ops) != ops) { int wantops; wantops = (f->filp_select_ops |= ops); - r = do_select_request(se, fd, &wantops); - if (r != OK && r != SUSPEND) + type = se->type[fd]; + select_lock_filp(f, wantops); + r = fdtypes[type].select_request(f, &wantops, se->block); + unlock_filp(f); + if (r != OK && r != SUSPEND) { + se->error = r; break; /* Error or bogus return code; abort */ + } /* The select request above might have turned on/off some * operations because they were 'ready' or not meaningful. @@ -236,20 +253,24 @@ int do_select(message *UNUSED(m_out)) } } - if ((se->nreadyfds > 0 || !se->block) && !is_deferred(se)) { - /* fd's were found that were ready to go right away, and/or - * we were instructed not to block at all. Must return - * immediately. + /* At this point there won't be any blocking calls anymore. */ + se->starting = FALSE; + + if ((se->nreadyfds > 0 || se->error != OK || !se->block) && + !is_deferred(se)) { + /* An error occurred, or fd's were found that were ready to go right + * away, and/or we were instructed not to block at all. Must return + * immediately. Do not copy FD sets if an error occurred. */ - r = copy_fdsets(se, se->nfds, TO_PROC); + if (se->error != OK) + r = se->error; + else + r = copy_fdsets(se, se->nfds, TO_PROC); select_cancel_all(se); se->requestor = NULL; if (r != OK) return(r); - else if (se->error != OK) - return(se->error); - return(se->nreadyfds); } @@ -291,6 +312,9 @@ static int is_deferred(struct selectentry *se) int fd; struct filp *f; + /* The select call must have finished its initialization at all. */ + if (se->starting) return(TRUE); + for (fd = 0; fd < se->nfds; fd++) { if ((f = se->filps[fd]) == NULL) continue; if (f->filp_select_flags & (FSF_UPDATE|FSF_BUSY)) return(TRUE); @@ -318,31 +342,33 @@ static int is_pipe(struct filp *f) } /*===========================================================================* - * is_supported_major * + * is_char_device * *===========================================================================*/ -static int is_supported_major(struct filp *f) +static int is_char_device(struct filp *f) { -/* See if this filp is a handle on a device on which we support select() */ - unsigned int m; +/* See if this filp is a handle on a character device. This function MUST NOT + * block its calling thread. The given filp may or may not be locked. + */ - if (!(f && f->filp_vno)) return(FALSE); - if (!S_ISCHR(f->filp_vno->v_mode)) return(FALSE); - - for (m = 0; m < SEL_MAJORS; m++) - if (major(f->filp_vno->v_sdev) == select_majors[m]) - return(TRUE); - - return(FALSE); + return (f && f->filp_vno && S_ISCHR(f->filp_vno->v_mode)); } /*===========================================================================* - * select_request_async * + * select_request_char * *===========================================================================*/ -static int select_request_async(struct filp *f, int *ops, int block) +static int select_request_char(struct filp *f, int *ops, int block) { +/* Check readiness status on a character device. Unless suitable results are + * available right now, this will only initiate the polling process, causing + * result processing to be deferred. This function MUST NOT block its calling + * thread. The given filp may or may not be locked. + */ int r, rops, major; struct dmap *dp; + major = major(f->filp_vno->v_sdev); + if (major < 0 || major >= NR_DEVICES) return(ENXIO); + rops = *ops; /* By default, nothing to do */ @@ -375,21 +401,16 @@ static int select_request_async(struct filp *f, int *ops, int block) if (f->filp_select_flags & FSF_BUSY) return(SUSPEND); - major = major(f->filp_vno->v_sdev); - if (major < 0 || major >= NR_DEVICES) return(ENXIO); dp = &dmap[major]; - if (dp->dmap_sel_filp) + if (dp->dmap_sel_busy) return(SUSPEND); f->filp_select_flags &= ~FSF_UPDATE; - r = dev_io(VFS_DEV_SELECT, f->filp_vno->v_sdev, rops, NULL, - ((u64_t)(0)), 0, 0, FALSE); - if (r < 0 && r != SUSPEND) + r = cdev_select(f->filp_vno->v_sdev, rops); + if (r != OK) return(r); - if (r != SUSPEND) - panic("select_request_asynch: expected SUSPEND got: %d", r); - + dp->dmap_sel_busy = TRUE; dp->dmap_sel_filp = f; f->filp_select_flags |= FSF_BUSY; @@ -406,47 +427,14 @@ static int select_request_file(struct filp *UNUSED(f), int *UNUSED(ops), return(OK); } -/*===========================================================================* - * select_request_major * - *===========================================================================*/ -static int select_request_major(struct filp *f, int *ops, int block) -{ - int major, r; - - major = major(f->filp_vno->v_sdev); - if (major < 0 || major >= NR_DEVICES) return(ENXIO); - - if (dmap[major].dmap_style == STYLE_DEVA || - dmap[major].dmap_style == STYLE_CLONE_A) - r = select_request_async(f, ops, block); - else - r = select_request_sync(f, ops, block); - - return(r); -} - -/*===========================================================================* - * select_request_sync * - *===========================================================================*/ -static int select_request_sync(struct filp *f, int *ops, int block) -{ - int rops; - - rops = *ops; - if (block) rops |= SEL_NOTIFY; - *ops = dev_io(VFS_DEV_SELECT, f->filp_vno->v_sdev, rops, NULL, - ((u64_t)(0)), 0, 0, FALSE); - if (*ops < 0) - return(*ops); - - return(OK); -} - /*===========================================================================* * select_request_pipe * *===========================================================================*/ static int select_request_pipe(struct filp *f, int *ops, int block) { +/* Check readiness status on a pipe. The given filp is locked. This function + * may block its calling thread if necessary. + */ int orig_ops, r = 0, err; orig_ops = *ops; @@ -460,12 +448,6 @@ static int select_request_pipe(struct filp *f, int *ops, int block) r |= SEL_RD; if (err < 0 && err != SUSPEND) r |= SEL_ERR; - if (err == SUSPEND && !(f->filp_mode & R_BIT)) { - /* A "meaningless" read select, therefore ready - * for reading and no error set. */ - r |= SEL_RD; - r &= ~SEL_ERR; - } } if ((*ops & (SEL_WR|SEL_ERR))) { @@ -477,12 +459,6 @@ static int select_request_pipe(struct filp *f, int *ops, int block) r |= SEL_WR; if (err < 0 && err != SUSPEND) r |= SEL_ERR; - if (err == SUSPEND && !(f->filp_mode & W_BIT)) { - /* A "meaningless" write select, therefore ready - for writing and no error set. */ - r |= SEL_WR; - r &= ~SEL_ERR; - } } /* Some options we collected might not be requested. */ @@ -538,6 +514,9 @@ static void ops2tab(int ops, int fd, struct selectentry *e) *===========================================================================*/ static int copy_fdsets(struct selectentry *se, int nfds, int direction) { +/* Copy FD sets from or to the user process calling select(2). This function + * MUST NOT block the calling thread. + */ int r; size_t fd_setsize; endpoint_t src_e, dst_e; @@ -589,7 +568,9 @@ static int copy_fdsets(struct selectentry *se, int nfds, int direction) *===========================================================================*/ static void select_cancel_all(struct selectentry *se) { -/* Cancel select. Decrease select usage and cancel timer */ +/* Cancel select, possibly on success. Decrease select usage and cancel timer. + * This function MUST NOT block its calling thread. + */ int fd; struct filp *f; @@ -613,14 +594,14 @@ static void select_cancel_all(struct selectentry *se) *===========================================================================*/ static void select_cancel_filp(struct filp *f) { -/* Reduce number of select users of this filp */ +/* Reduce the number of select users of this filp. This function MUST NOT block + * its calling thread. + */ + dev_t major; assert(f); - assert(f->filp_selectors >= 0); - if (f->filp_selectors == 0) return; - if (f->filp_count == 0) return; - - select_lock_filp(f, f->filp_select_ops); + assert(f->filp_selectors > 0); + assert(f->filp_count > 0); f->filp_selectors--; if (f->filp_selectors == 0) { @@ -628,9 +609,18 @@ static void select_cancel_filp(struct filp *f) f->filp_select_ops = 0; f->filp_select_flags = 0; f->filp_pipe_select_ops = 0; - } - unlock_filp(f); + /* If this filp is the subject of an ongoing select query to a + * character device, mark the query as stale, so that this filp will + * not be checked when the result arrives. + */ + if (is_char_device(f)) { + major = major(f->filp_vno->v_sdev); + if (dmap[major].dmap_sel_busy && + dmap[major].dmap_sel_filp == f) + dmap[major].dmap_sel_filp = NULL; /* leave _busy set */ + } + } } /*===========================================================================* @@ -638,18 +628,20 @@ static void select_cancel_filp(struct filp *f) *===========================================================================*/ static void select_return(struct selectentry *se) { - int r, r1; +/* Return the results of a select call to the user process and revive the + * process. This function MUST NOT block its calling thread. + */ + int r; assert(!is_deferred(se)); /* Not done yet, first wait for async reply */ select_cancel_all(se); - r1 = copy_fdsets(se, se->nfds, TO_PROC); - if (r1 != OK) - r = r1; - else if (se->error != OK) + if (se->error != OK) r = se->error; else + r = copy_fdsets(se, se->nfds, TO_PROC); + if (r == OK) r = se->nreadyfds; revive(se->req_endpt, r); @@ -661,6 +653,11 @@ static void select_return(struct selectentry *se) *===========================================================================*/ void select_callback(struct filp *f, int status) { +/* The status of a filp has changed, with the given ready operations or error. + * This function is currently called only for pipes, and holds the lock to + * the filp. + */ + filp_status(f, status); } @@ -679,24 +676,27 @@ void init_select(void) /*===========================================================================* * select_forget * *===========================================================================*/ -void select_forget(endpoint_t proc_e) +void select_forget(void) { -/* Something has happened (e.g. signal delivered that interrupts select()). - * Totally forget about the select(). */ - +/* The calling thread's associated process is expected to be unpaused, due to + * a signal that is supposed to interrupt the current system call. Totally + * forget about the select(). This function may block its calling thread if + * necessary (but it doesn't). + */ int slot; struct selectentry *se; for (slot = 0; slot < MAXSELECTS; slot++) { se = &selecttab[slot]; - if (se->requestor != NULL && se->req_endpt == proc_e) + if (se->requestor == fp) break; } if (slot >= MAXSELECTS) return; /* Entry not found */ - se->error = EINTR; - if (is_deferred(se)) return; /* Still awaiting initial reply */ + assert(se->starting == FALSE); + + /* Do NOT test on is_deferred here. We can safely cancel ongoing queries. */ select_cancel_all(se); } @@ -706,6 +706,9 @@ void select_forget(endpoint_t proc_e) *===========================================================================*/ void select_timeout_check(timer_t *timer) { +/* An alarm has gone off for one of the select queries. This function MUST NOT + * block its calling thread. + */ int s; struct selectentry *se; @@ -714,10 +717,9 @@ void select_timeout_check(timer_t *timer) se = &selecttab[s]; if (se->requestor == NULL) return; - fp = se->requestor; if (se->expiry <= 0) return; /* Strange, did we even ask for a timeout? */ se->expiry = 0; - if (is_deferred(se)) return; /* Wait for initial replies to DEV_SELECT */ + if (is_deferred(se)) return; /* Wait for initial replies to CDEV_SELECT */ select_return(se); } @@ -750,7 +752,7 @@ void select_unsuspend_by_endpt(endpoint_t proc_e) major = major(f->filp_vno->v_sdev); if (dmap_driver_match(proc_e, major)) { se->filps[fd] = NULL; - se->error = EINTR; + se->error = EIO; select_cancel_filp(f); wakehim = 1; } @@ -769,8 +771,9 @@ endpoint_t driver_e; int minor; int status; { -/* Handle reply to DEV_SELECT request */ - +/* Handle the initial reply to CDEV_SELECT request. This function MUST NOT + * block its calling thread. + */ int major; dev_t dev; struct filp *f; @@ -784,20 +787,25 @@ int status; dev = makedev(major, minor); /* Get filp belonging to character special file */ - if ((f = dp->dmap_sel_filp) == NULL) { - printf("VFS (%s:%d): major %d was not expecting a DEV_SELECT reply\n", + if (!dp->dmap_sel_busy) { + printf("VFS (%s:%d): major %d was not expecting a CDEV_SELECT reply\n", __FILE__, __LINE__, major); return; } - /* Is the filp still in use and busy waiting for a reply? The owner might - * have vanished before the driver was able to reply. */ - if (f->filp_count >= 1 && (f->filp_select_flags & FSF_BUSY)) { + /* The select filp may have been set to NULL if the requestor has been + * unpaused in the meantime. In that case, we ignore the result, but we do + * look for other filps to restart later. + */ + if ((f = dp->dmap_sel_filp) != NULL) { /* Find vnode and check we got a reply from the device we expected */ vp = f->filp_vno; assert(vp != NULL); assert(S_ISCHR(vp->v_mode)); if (vp->v_sdev != dev) { + /* This should never happen. The driver may be misbehaving. + * For now we assume that the reply we want will arrive later.. + */ printf("VFS (%s:%d): expected reply from dev %d not %d\n", __FILE__, __LINE__, vp->v_sdev, dev); return; @@ -805,13 +813,14 @@ int status; } /* No longer waiting for a reply from this device */ + dp->dmap_sel_busy = FALSE; dp->dmap_sel_filp = NULL; - /* Process select result only if requestor is still around. That is, the - * corresponding filp is still in use. - */ - if (f->filp_count >= 1) { - select_lock_filp(f, f->filp_select_ops); + /* Process the select result only if the filp is valid. */ + if (f != NULL) { + assert(f->filp_count >= 1); + assert(f->filp_select_flags & FSF_BUSY); + f->filp_select_flags &= ~FSF_BUSY; /* The select call is done now, except when @@ -826,7 +835,7 @@ int status; */ if (!(f->filp_select_flags & (FSF_UPDATE|FSF_BLOCKED))) f->filp_select_ops = 0; /* done selecting */ - else if (!(f->filp_select_flags & FSF_UPDATE)) + else if (status > 0 && !(f->filp_select_flags & FSF_UPDATE)) /* there may be operations pending */ f->filp_select_ops &= ~status; @@ -845,7 +854,6 @@ int status; } } - unlock_filp(f); filp_status(f, status); /* Tell filp owners about the results */ } @@ -862,8 +870,10 @@ int minor; int status; { /* Handle secondary reply to DEV_SELECT request. A secondary reply occurs when - * the select request is 'blocking' until an operation becomes ready. */ - int major, slot, fd; + * the select request is 'blocking' until an operation becomes ready. This + * function MUST NOT block its calling thread. + */ + int major, slot, found, fd; dev_t dev; struct filp *f; struct dmap *dp; @@ -890,13 +900,13 @@ int status; se = &selecttab[slot]; if (se->requestor == NULL) continue; /* empty slot */ + found = FALSE; for (fd = 0; fd < se->nfds; fd++) { if ((f = se->filps[fd]) == NULL) continue; if ((vp = f->filp_vno) == NULL) continue; if (!S_ISCHR(vp->v_mode)) continue; if (vp->v_sdev != dev) continue; - select_lock_filp(f, f->filp_select_ops); if (status > 0) { /* Operations ready */ /* Clear the replied bits from the request * mask unless FSF_UPDATE is set. @@ -913,11 +923,16 @@ int status; ops2tab(status, fd, se); } else { f->filp_select_flags &= ~FSF_BLOCKED; - ops2tab(SEL_RD|SEL_WR|SEL_ERR, fd, se); + se->error = status; } - unlock_filp(f); - if (se->nreadyfds > 0) restart_proc(se); + found = TRUE; } + /* Even if 'found' is set now, nothing may have changed for this call, + * as it may not have been interested in the operations that were + * reported as ready. Let restart_proc check. + */ + if (found) + restart_proc(se); } select_restart_filps(); @@ -926,11 +941,14 @@ int status; /*===========================================================================* * select_restart_filps * *===========================================================================*/ -static void select_restart_filps() +static void select_restart_filps(void) { +/* We got a result from a character driver, and now we need to check if we can + * restart deferred polling operations. This function MUST NOT block its + * calling thread. + */ int fd, slot; struct filp *f; - struct vnode *vp; struct selectentry *se; /* Locate filps that can be restarted */ @@ -954,44 +972,24 @@ static void select_restart_filps() if (!(f->filp_select_flags & FSF_UPDATE)) /* Must be in */ continue; /* 'update' state */ + /* This function is suitable only for character devices. In + * particular, checking pipes the same way would introduce a + * serious locking problem. + */ + assert(is_char_device(f)); + wantops = ops = f->filp_select_ops; - vp = f->filp_vno; - assert(S_ISCHR(vp->v_mode)); - r = do_select_request(se, fd, &wantops); - if (r != OK && r != SUSPEND) + r = select_request_char(f, &wantops, se->block); + if (r != OK && r != SUSPEND) { + se->error = r; + restart_proc(se); break; /* Error or bogus return code; abort */ + } if (wantops & ops) ops2tab(wantops, fd, se); } } } -/*===========================================================================* - * do_select_request * - *===========================================================================*/ -static int do_select_request(se, fd, ops) -struct selectentry *se; -int fd; -int *ops; -{ -/* Perform actual select request for file descriptor fd */ - - int r, type; - struct filp *f; - - type = se->type[fd]; - f = se->filps[fd]; - select_lock_filp(f, *ops); - r = fdtypes[type].select_request(f, ops, se->block); - unlock_filp(f); - if (r != OK && r != SUSPEND) { - se->error = EINTR; - se->block = 0; /* Stop blocking to return asap */ - if (!is_deferred(se)) select_cancel_all(se); - } - - return(r); -} - /*===========================================================================* * filp_status * *===========================================================================*/ @@ -999,22 +997,27 @@ static void filp_status(f, status) struct filp *f; int status; { -/* Tell processes that need to know about the status of this filp */ - int fd, slot; +/* Tell processes that need to know about the status of this filp. This + * function MUST NOT block its calling thread. + */ + int fd, slot, found; struct selectentry *se; for (slot = 0; slot < MAXSELECTS; slot++) { se = &selecttab[slot]; if (se->requestor == NULL) continue; /* empty slot */ + found = FALSE; for (fd = 0; fd < se->nfds; fd++) { if (se->filps[fd] != f) continue; if (status < 0) - ops2tab(SEL_RD|SEL_WR|SEL_ERR, fd, se); + se->error = status; else ops2tab(status, fd, se); - restart_proc(se); + found = TRUE; } + if (found) + restart_proc(se); } } @@ -1025,9 +1028,10 @@ static void restart_proc(se) struct selectentry *se; { /* Tell process about select results (if any) unless there are still results - * pending. */ + * pending. This function MUST NOT block its calling thread. + */ - if ((se->nreadyfds > 0 || !se->block) && !is_deferred(se)) + if ((se->nreadyfds > 0 || se->error != OK || !se->block) && !is_deferred(se)) select_return(se); } @@ -1055,8 +1059,10 @@ static void wipe_select(struct selectentry *se) *===========================================================================*/ static void select_lock_filp(struct filp *f, int ops) { -/* Lock a filp and vnode based on which operations are requested */ - tll_access_t locktype;; +/* Lock a filp and vnode based on which operations are requested. This function + * may block its calling thread, obviously. + */ + tll_access_t locktype; locktype = VNODE_READ; /* By default */ diff --git a/servers/vfs/stadir.c b/servers/vfs/stadir.c index 09763f41b..badcf10f8 100644 --- a/servers/vfs/stadir.c +++ b/servers/vfs/stadir.c @@ -7,19 +7,17 @@ * do_lstat: perform the LSTAT system call * do_stat: perform the STAT system call * do_fstat: perform the FSTAT system call - * do_fstatfs: perform the FSTATFS system call - * do_statvfs: perform the STATVFS system call - * do_fstatvfs: perform the FSTATVFS system call + * do_statvfs: perform the STATVFS1 system call + * do_fstatvfs: perform the FSTATVFS1 system call + * do_getvfsstat: perform the GETVFSSTAT system call */ #include "fs.h" #include -#include #include #include #include #include "file.h" -#include "fproc.h" #include "path.h" #include "param.h" #include @@ -211,26 +209,99 @@ int do_fstat(message *UNUSED(m_out)) } /*===========================================================================* - * do_fstatfs * + * update_statvfs * *===========================================================================*/ -int do_fstatfs(message *UNUSED(m_out)) +int update_statvfs(struct vmnt *vmp, struct statvfs *buf) { -/* Perform the fstatfs(fd, buf) system call. */ - struct filp *rfilp; - int r, rfd; - vir_bytes statbuf; +/* Get statistics from a file system, and cache part of the results. */ + int r; - rfd = job_m_in.fd; - statbuf = (vir_bytes) job_m_in.buffer; + if ((r = req_statvfs(vmp->m_fs_e, buf)) != OK) + return r; - /* Is the file descriptor valid? */ - if( (rfilp = get_filp(rfd, VNODE_READ)) == NULL) return(err_code); + vmp->m_stats.f_flag = buf->f_flag; + vmp->m_stats.f_bsize = buf->f_bsize; + vmp->m_stats.f_frsize = buf->f_frsize; + vmp->m_stats.f_iosize = buf->f_iosize; - r = req_fstatfs(rfilp->filp_vno->v_fs_e, who_e, statbuf); + vmp->m_stats.f_blocks = buf->f_blocks; + vmp->m_stats.f_bfree = buf->f_bfree; + vmp->m_stats.f_bavail = buf->f_bavail; + vmp->m_stats.f_bresvd = buf->f_bresvd; - unlock_filp(rfilp); + vmp->m_stats.f_files = buf->f_files; + vmp->m_stats.f_ffree = buf->f_ffree; + vmp->m_stats.f_favail = buf->f_favail; + vmp->m_stats.f_fresvd = buf->f_fresvd; - return(r); + vmp->m_stats.f_syncreads = buf->f_syncreads; + vmp->m_stats.f_syncwrites = buf->f_syncwrites; + + vmp->m_stats.f_asyncreads = buf->f_asyncreads; + vmp->m_stats.f_asyncwrites = buf->f_asyncwrites; + + vmp->m_stats.f_namemax = buf->f_namemax; + + return OK; +} + +/*===========================================================================* + * fill_statvfs * + *===========================================================================*/ +static int fill_statvfs(struct vmnt *vmp, endpoint_t endpt, vir_bytes buf_addr, + int flags) +{ +/* Fill a statvfs structure in a userspace process. First let the target file + * server fill in most fields, or use the cached copy if ST_NOWAIT is given. + * Then fill in some remaining fields with local information. Finally, copy + * the result to user space. + */ + struct statvfs buf; + + if (!(flags & ST_NOWAIT)) { + /* Get fresh statistics from the file system. */ + if (update_statvfs(vmp, &buf) != OK) + return EIO; + } else { + /* Use the cached statistics. */ + memset(&buf, 0, sizeof(buf)); + + buf.f_flag = vmp->m_stats.f_flag; + buf.f_bsize = vmp->m_stats.f_bsize; + buf.f_frsize = vmp->m_stats.f_frsize; + buf.f_iosize = vmp->m_stats.f_iosize; + + buf.f_blocks = vmp->m_stats.f_blocks; + buf.f_bfree = vmp->m_stats.f_bfree; + buf.f_bavail = vmp->m_stats.f_bavail; + buf.f_bresvd = vmp->m_stats.f_bresvd; + + buf.f_files = vmp->m_stats.f_files; + buf.f_ffree = vmp->m_stats.f_ffree; + buf.f_favail = vmp->m_stats.f_favail; + buf.f_fresvd = vmp->m_stats.f_fresvd; + + buf.f_syncreads = vmp->m_stats.f_syncreads; + buf.f_syncwrites = vmp->m_stats.f_syncwrites; + + buf.f_asyncreads = vmp->m_stats.f_asyncreads; + buf.f_asyncwrites = vmp->m_stats.f_asyncwrites; + + buf.f_namemax = vmp->m_stats.f_namemax; + } + + if (vmp->m_flags & VMNT_READONLY) + buf.f_flag |= ST_RDONLY; + + buf.f_fsid = vmp->m_dev; + buf.f_fsidx.__fsid_val[0] = 0; + buf.f_fsidx.__fsid_val[1] = vmp->m_dev; + + strlcpy(buf.f_fstypename, vmp->m_fstype, sizeof(buf.f_fstypename)); + strlcpy(buf.f_mntonname, vmp->m_mount_path, sizeof(buf.f_mntonname)); + strlcpy(buf.f_mntfromname, vmp->m_mount_dev, sizeof(buf.f_mntfromname)); + + return sys_datacopy(SELF, (vir_bytes) &buf, endpt, buf_addr, sizeof(buf)); } /*===========================================================================* @@ -238,8 +309,8 @@ int do_fstatfs(message *UNUSED(m_out)) *===========================================================================*/ int do_statvfs(message *UNUSED(m_out)) { -/* Perform the stat(name, buf) system call. */ - int r; +/* Perform the statvfs1(name, buf, flags) system call. */ + int r, flags; struct vnode *vp; struct vmnt *vmp; char fullpath[PATH_MAX]; @@ -247,9 +318,10 @@ int do_statvfs(message *UNUSED(m_out)) vir_bytes vname1, statbuf; size_t vname1_length; - vname1 = (vir_bytes) job_m_in.name1; - vname1_length = (size_t) job_m_in.name1_length; - statbuf = (vir_bytes) job_m_in.name2; + vname1 = (vir_bytes) job_m_in.VFS_STATVFS1_NAME; + vname1_length = (size_t) job_m_in.VFS_STATVFS1_LEN; + statbuf = (vir_bytes) job_m_in.VFS_STATVFS1_BUF; + flags = job_m_in.VFS_STATVFS1_FLAGS; lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp, &vp); resolve.l_vmnt_lock = VMNT_READ; @@ -257,7 +329,7 @@ int do_statvfs(message *UNUSED(m_out)) if (fetch_name(vname1, vname1_length, fullpath) != OK) return(err_code); if ((vp = eat_path(&resolve, fp)) == NULL) return(err_code); - r = req_statvfs(vp->v_fs_e, who_e, statbuf); + r = fill_statvfs(vp->v_vmnt, who_e, statbuf, flags); unlock_vnode(vp); unlock_vmnt(vmp); @@ -271,23 +343,91 @@ int do_statvfs(message *UNUSED(m_out)) *===========================================================================*/ int do_fstatvfs(message *UNUSED(m_out)) { -/* Perform the fstat(fd, buf) system call. */ +/* Perform the fstatvfs1(fd, buf, flags) system call. */ register struct filp *rfilp; - int r, rfd; + int r, rfd, flags; vir_bytes statbuf; - rfd = job_m_in.fd; - statbuf = (vir_bytes) job_m_in.name2; + rfd = job_m_in.VFS_FSTATVFS1_FD; + statbuf = (vir_bytes) job_m_in.VFS_FSTATVFS1_BUF; + flags = job_m_in.VFS_FSTATVFS1_FLAGS; /* Is the file descriptor valid? */ if ((rfilp = get_filp(rfd, VNODE_READ)) == NULL) return(err_code); - r = req_statvfs(rfilp->filp_vno->v_fs_e, who_e, statbuf); + r = fill_statvfs(rfilp->filp_vno->v_vmnt, who_e, statbuf, flags); unlock_filp(rfilp); return(r); } +/*===========================================================================* + * do_getvfsstat * + *===========================================================================*/ +int do_getvfsstat(message *UNUSED(m_out)) +{ +/* Perform the getvfsstat(buf, bufsize, flags) system call. */ + struct vmnt *vmp; + vir_bytes buf; + size_t bufsize; + int r, flags, count, do_lock; + + buf = (vir_bytes) job_m_in.VFS_GETVFSSTAT_BUF; + bufsize = job_m_in.VFS_GETVFSSTAT_SIZE; + flags = job_m_in.VFS_GETVFSSTAT_FLAGS; + + count = 0; + + if (buf != 0) { + /* We only need to lock target file systems if we are going to query + * them. This will only happen if ST_NOWAIT is not given. If we do + * not lock, we rely on the VMNT_CANSTAT flag to protect us from + * concurrent (un)mount operations. Note that procfs relies on + * ST_NOWAIT calls being lock free, as it is a file system itself. + */ + do_lock = !(flags & ST_NOWAIT); + + for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; vmp++) { + /* If there is no more space, return the count so far. */ + if (bufsize < sizeof(struct statvfs)) + break; + + /* Lock the file system before checking any fields. */ + if (do_lock && (r = lock_vmnt(vmp, VMNT_READ)) != OK) + return r; + + /* Obtain information for this file system, if it is in use and + * can be reported. File systems that are being (un)mounted + * are skipped, as is PFS. The fill call will block only if + * ST_NOWAIT was not given. + */ + if (vmp->m_dev != NO_DEV && (vmp->m_flags & VMNT_CANSTAT)) { + if ((r = fill_statvfs(vmp, who_e, buf, flags)) != OK) { + if (do_lock) + unlock_vmnt(vmp); + + return r; + } + + count++; + buf += sizeof(struct statvfs); + bufsize -= sizeof(struct statvfs); + } + + if (do_lock) + unlock_vmnt(vmp); + } + } else { + /* Just report a file system count. No need to lock, as above. */ + for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; vmp++) { + if (vmp->m_dev != NO_DEV && (vmp->m_flags & VMNT_CANSTAT)) + count++; + } + } + + return count; +} + /*===========================================================================* * do_lstat * *===========================================================================*/ diff --git a/servers/vfs/table.c b/servers/vfs/table.c index 586c055d5..3b9448fbc 100644 --- a/servers/vfs/table.c +++ b/servers/vfs/table.c @@ -8,7 +8,6 @@ #include #include #include "file.h" -#include "fproc.h" #include "lock.h" #include "scratchpad.h" #include "vnode.h" @@ -71,7 +70,7 @@ int (*call_vec[])(message *m_out) = { do_lstat, /* 53 = lstat */ do_ioctl, /* 54 = ioctl */ do_fcntl, /* 55 = fcntl */ - no_sys, /* 56 = (mpx) */ + do_dupfrom, /* 56 = dupfrom */ do_fsready, /* 57 = FS proc ready */ do_pipe2, /* 58 = pipe2 */ no_sys, /* 59 = (execve)*/ @@ -97,7 +96,7 @@ int (*call_vec[])(message *m_out) = { no_sys, /* 79 = unused */ do_getdents, /* 80 = getdents */ do_llseek, /* 81 = llseek */ - do_fstatfs, /* 82 = fstatfs */ + do_getvfsstat, /* 82 = getvfsstat */ do_statvfs, /* 83 = fstatvfs */ do_fstatvfs, /* 84 = statvfs */ do_select, /* 85 = select */ @@ -137,19 +136,14 @@ int (*call_vec[])(message *m_out) = { no_sys, /* 119 = unsused */ no_sys, /* 120 = unsused */ no_sys, /* 121 = (task reply) */ - no_sys, /* 122 = (map driver ) */ + do_mapdriver, /* 122 = mapdriver */ do_getrusage, /* 123 = getrusage */ + do_check_perms, /* 124 = from PFS: check_perms */ + do_verify_fd, /* 125 = from PFS: verify_fd */ + do_set_filp, /* 126 = from PFS: set_filp */ + do_copy_filp, /* 127 = from PFS: copy_filp */ + do_put_filp, /* 128 = from PFS: put_filp */ + do_cancel_fd, /* 129 = from PFS: cancel_fd */ }; /* This should not fail with "array size is negative": */ extern int dummy[sizeof(call_vec) == NCALLS * sizeof(call_vec[0]) ? 1 : -1]; - -int (*pfs_call_vec[])(message *m_out) = { - - no_sys, /* 0 */ - do_check_perms, /* 1 */ - do_verify_fd, /* 2 */ - do_set_filp, /* 3 */ - do_copy_filp, /* 4 */ - do_put_filp, /* 5 */ - do_cancel_fd /* 6 */ -}; diff --git a/servers/vfs/threads.h b/servers/vfs/threads.h index cddb73e9a..93ca0be34 100644 --- a/servers/vfs/threads.h +++ b/servers/vfs/threads.h @@ -1,7 +1,6 @@ #ifndef __VFS_WORKERS_H__ #define __VFS_WORKERS_H__ #include -#include "job.h" #define thread_t mthread_thread_t #define mutex_t mthread_mutex_t @@ -23,12 +22,15 @@ #define cond_wait mthread_cond_wait #define cond_signal mthread_cond_signal +struct fproc; + struct worker_thread { thread_t w_tid; mutex_t w_event_mutex; cond_t w_event; - struct job w_job; struct fproc *w_fp; + message w_msg; + int w_err_code; message *w_fs_sendrec; message *w_drv_sendrec; endpoint_t w_task; diff --git a/servers/vfs/time.c b/servers/vfs/time.c index d3b42669b..4de1cd747 100644 --- a/servers/vfs/time.c +++ b/servers/vfs/time.c @@ -13,7 +13,6 @@ #include #include #include "file.h" -#include "fproc.h" #include "path.h" #include "param.h" #include "vnode.h" diff --git a/servers/vfs/type.h b/servers/vfs/type.h new file mode 100644 index 000000000..673be5f1f --- /dev/null +++ b/servers/vfs/type.h @@ -0,0 +1,41 @@ +#ifndef __VFS_TYPE_H__ +#define __VFS_TYPE_H__ + +/* VFS<->FS communication */ + +typedef struct { + int c_max_reqs; /* Max requests an FS can handle simultaneously */ + int c_cur_reqs; /* Number of requests the FS is currently handling */ + struct worker_thread *c_req_queue;/* Queue of procs waiting to send a message */ +} comm_t; + +/* + * Cached statvfs fields. We are not using struct statvfs itself because that + * would add over 2K of unused memory per mount table entry. + */ +struct statvfs_cache { + unsigned long f_flag; /* copy of mount exported flags */ + unsigned long f_bsize; /* file system block size */ + unsigned long f_frsize; /* fundamental file system block size */ + unsigned long f_iosize; /* optimal file system block size */ + + fsblkcnt_t f_blocks; /* number of blocks in file system, */ + fsblkcnt_t f_bfree; /* free blocks avail in file system */ + fsblkcnt_t f_bavail; /* free blocks avail to non-root */ + fsblkcnt_t f_bresvd; /* blocks reserved for root */ + + fsfilcnt_t f_files; /* total file nodes in file system */ + fsfilcnt_t f_ffree; /* free file nodes in file system */ + fsfilcnt_t f_favail; /* free file nodes avail to non-root */ + fsfilcnt_t f_fresvd; /* file nodes reserved for root */ + + uint64_t f_syncreads; /* count of sync reads since mount */ + uint64_t f_syncwrites; /* count of sync writes since mount */ + + uint64_t f_asyncreads; /* count of async reads since mount */ + uint64_t f_asyncwrites; /* count of async writes since mount */ + + unsigned long f_namemax; /* maximum filename length */ +}; + +#endif diff --git a/servers/vfs/utility.c b/servers/vfs/utility.c index 687b53d95..b35d2809d 100644 --- a/servers/vfs/utility.c +++ b/servers/vfs/utility.c @@ -20,7 +20,6 @@ #include #include #include "file.h" -#include "fproc.h" #include "param.h" #include "vmnt.h" diff --git a/servers/vfs/vmnt.c b/servers/vfs/vmnt.c index 00e9a7dc0..b7e3d6567 100644 --- a/servers/vfs/vmnt.c +++ b/servers/vfs/vmnt.c @@ -3,11 +3,9 @@ */ #include "fs.h" -#include "threads.h" #include "vmnt.h" #include #include -#include "fproc.h" static int is_vmnt_locked(struct vmnt *vmp); static void clear_vmnt(struct vmnt *vmp); diff --git a/servers/vfs/vmnt.h b/servers/vfs/vmnt.h index 40c032a3f..2b0ee68a2 100644 --- a/servers/vfs/vmnt.h +++ b/servers/vfs/vmnt.h @@ -2,7 +2,7 @@ #define __VFS_VMNT_H__ #include "tll.h" -#include "comm.h" +#include "type.h" EXTERN struct vmnt { int m_fs_e; /* FS process' kernel endpoint */ @@ -14,8 +14,10 @@ EXTERN struct vmnt { struct vnode *m_root_node; /* root vnode */ char m_label[LABEL_MAX]; /* label of the file system process */ char m_mount_path[PATH_MAX]; /* path on which vmnt is mounted */ - char m_mount_dev[PATH_MAX]; /* path on which vmnt is mounted */ + char m_mount_dev[PATH_MAX]; /* device from which vmnt is mounted */ + char m_fstype[FSTYPE_MAX]; /* file system type */ int m_haspeek; /* supports REQ_PEEK, REQ_BPEEK */ + struct statvfs_cache m_stats; /* cached file system statistics */ } vmnt[NR_MNTS]; /* vmnt flags */ @@ -23,6 +25,7 @@ EXTERN struct vmnt { #define VMNT_CALLBACK 02 /* FS did back call */ #define VMNT_MOUNTING 04 /* Device is being mounted */ #define VMNT_FORCEROOTBSF 010 /* Force usage of none-device */ +#define VMNT_CANSTAT 020 /* Include FS in getvfsstat output */ /* vmnt lock types mapping */ #define VMNT_READ TLL_READ diff --git a/servers/vfs/vnode.c b/servers/vfs/vnode.c index 022711748..438c057ba 100644 --- a/servers/vfs/vnode.c +++ b/servers/vfs/vnode.c @@ -9,10 +9,8 @@ */ #include "fs.h" -#include "threads.h" #include "vnode.h" #include "vmnt.h" -#include "fproc.h" #include "file.h" #include #include diff --git a/servers/vfs/vnode.h b/servers/vfs/vnode.h index 2f01d7379..527a68a14 100644 --- a/servers/vfs/vnode.h +++ b/servers/vfs/vnode.h @@ -26,6 +26,7 @@ EXTERN struct vnode { } vnode[NR_VNODES]; /* vnode lock types mapping */ +#define VNODE_NONE TLL_NONE /* used only for get_filp2 to avoid locking */ #define VNODE_READ TLL_READ #define VNODE_OPCL TLL_READSER #define VNODE_WRITE TLL_WRITE diff --git a/servers/vfs/worker.c b/servers/vfs/worker.c index 8b9f20f27..2eb74c270 100644 --- a/servers/vfs/worker.c +++ b/servers/vfs/worker.c @@ -1,18 +1,10 @@ #include "fs.h" -#include "glo.h" -#include "fproc.h" -#include "threads.h" -#include "job.h" #include -static void append_job(struct job *job, void *(*func)(void *arg)); -static void get_work(struct worker_thread *worker); +static void worker_get_work(void); static void *worker_main(void *arg); -static void worker_sleep(struct worker_thread *worker); +static void worker_sleep(void); static void worker_wake(struct worker_thread *worker); -static int worker_waiting_for(struct worker_thread *worker, endpoint_t - proc_e); -static int init = 0; static mthread_attr_t tattr; #ifdef MKCOVERAGE @@ -21,66 +13,60 @@ static mthread_attr_t tattr; # define TH_STACKSIZE (28 * 1024) #endif -#define ASSERTW(w) assert((w) == &sys_worker || (w) == &dl_worker || \ - ((w) >= &workers[0] && (w) < &workers[NR_WTHREADS])); +#define ASSERTW(w) assert((w) >= &workers[0] && (w) < &workers[NR_WTHREADS]) /*===========================================================================* * worker_init * *===========================================================================*/ -void worker_init(struct worker_thread *wp) +void worker_init(void) { /* Initialize worker thread */ - if (!init) { - threads_init(); - if (mthread_attr_init(&tattr) != 0) - panic("failed to initialize attribute"); - if (mthread_attr_setstacksize(&tattr, TH_STACKSIZE) != 0) - panic("couldn't set default thread stack size"); - if (mthread_attr_setdetachstate(&tattr, MTHREAD_CREATE_DETACHED) != 0) - panic("couldn't set default thread detach state"); - invalid_thread_id = mthread_self(); /* Assuming we're the main thread*/ - pending = 0; - init = 1; + struct worker_thread *wp; + int i; + + threads_init(); + if (mthread_attr_init(&tattr) != 0) + panic("failed to initialize attribute"); + if (mthread_attr_setstacksize(&tattr, TH_STACKSIZE) != 0) + panic("couldn't set default thread stack size"); + if (mthread_attr_setdetachstate(&tattr, MTHREAD_CREATE_DETACHED) != 0) + panic("couldn't set default thread detach state"); + pending = 0; + + for (i = 0; i < NR_WTHREADS; i++) { + wp = &workers[i]; + + wp->w_fp = NULL; /* Mark not in use */ + wp->w_next = NULL; + if (mutex_init(&wp->w_event_mutex, NULL) != 0) + panic("failed to initialize mutex"); + if (cond_init(&wp->w_event, NULL) != 0) + panic("failed to initialize conditional variable"); + if (mthread_create(&wp->w_tid, &tattr, worker_main, (void *) wp) != 0) + panic("unable to start thread"); } - ASSERTW(wp); - - wp->w_job.j_func = NULL; /* Mark not in use */ - wp->w_next = NULL; - if (mutex_init(&wp->w_event_mutex, NULL) != 0) - panic("failed to initialize mutex"); - if (cond_init(&wp->w_event, NULL) != 0) - panic("failed to initialize conditional variable"); - if (mthread_create(&wp->w_tid, &tattr, worker_main, (void *) wp) != 0) - panic("unable to start thread"); - yield(); + /* Let all threads get ready to accept work. */ + yield_all(); } /*===========================================================================* - * get_work * + * worker_get_work * *===========================================================================*/ -static void get_work(struct worker_thread *worker) +static void worker_get_work(void) { /* Find new work to do. Work can be 'queued', 'pending', or absent. In the - * latter case wait for new work to come in. */ - - struct job *new_job; + * latter case wait for new work to come in. + */ struct fproc *rfp; - ASSERTW(worker); - self = worker; - /* Do we have queued work to do? */ - if ((new_job = worker->w_job.j_next) != NULL) { - worker->w_job = *new_job; - free(new_job); - return; - } else if (worker != &sys_worker && worker != &dl_worker && pending > 0) { + if (pending > 0) { /* Find pending work */ for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { if (rfp->fp_flags & FP_PENDING) { - worker->w_job = rfp->fp_job; - rfp->fp_job.j_func = NULL; + self->w_fp = rfp; + rfp->fp_worker = self; rfp->fp_flags &= ~FP_PENDING; /* No longer pending */ pending--; assert(pending >= 0); @@ -91,11 +77,11 @@ static void get_work(struct worker_thread *worker) } /* Wait for work to come to us */ - worker_sleep(worker); + worker_sleep(); } /*===========================================================================* - * worker_available * + * worker_available * *===========================================================================*/ int worker_available(void) { @@ -103,7 +89,7 @@ int worker_available(void) busy = 0; for (i = 0; i < NR_WTHREADS; i++) { - if (workers[i].w_job.j_func != NULL) + if (workers[i].w_fp != NULL) busy++; } @@ -116,151 +102,207 @@ int worker_available(void) static void *worker_main(void *arg) { /* Worker thread main loop */ - struct worker_thread *me; - me = (struct worker_thread *) arg; - ASSERTW(me); + self = (struct worker_thread *) arg; + ASSERTW(self); while(TRUE) { - get_work(me); + worker_get_work(); - /* Register ourselves in fproc table if possible */ - if (me->w_job.j_fp != NULL) { - me->w_job.j_fp->fp_wtid = me->w_tid; + fp = self->w_fp; + assert(fp->fp_worker == self); + + /* Lock the process. */ + lock_proc(fp); + + /* The following two blocks could be run in a loop until both the + * conditions are no longer met, but it is currently impossible that + * more normal work is present after postponed PM work has been done. + */ + + /* Perform normal work, if any. */ + if (fp->fp_func != NULL) { + self->w_msg = fp->fp_msg; + err_code = OK; + + fp->fp_func(); + + fp->fp_func = NULL; /* deliberately unset AFTER the call */ } - /* Carry out work */ - me->w_job.j_func(&me->w_job); + /* Perform postponed PM work, if any. */ + if (fp->fp_flags & FP_PM_WORK) { + self->w_msg = fp->fp_pm_msg; - /* Deregister if possible */ - if (me->w_job.j_fp != NULL) { - me->w_job.j_fp->fp_wtid = invalid_thread_id; + service_pm_postponed(); + + fp->fp_flags &= ~FP_PM_WORK; } - /* Mark ourselves as done */ - me->w_job.j_func = NULL; - me->w_job.j_fp = NULL; + /* Perform cleanup actions. */ + thread_cleanup(); + + unlock_proc(fp); + + fp->fp_worker = NULL; + self->w_fp = NULL; } return(NULL); /* Unreachable */ } /*===========================================================================* - * dl_worker_start * + * worker_can_start * *===========================================================================*/ -void dl_worker_start(void *(*func)(void *arg)) +int worker_can_start(struct fproc *rfp) { -/* Start the deadlock resolving worker. This worker is reserved to run in case - * all other workers are busy and we have to have an additional worker to come - * to the rescue. */ - assert(dl_worker.w_job.j_func == NULL); +/* Return whether normal (non-PM) work can be started for the given process. + * This function is used to serialize invocation of "special" procedures, and + * not entirely safe for other cases, as explained in the comments below. + */ + int is_pending, is_active, has_normal_work, has_pm_work; - if (dl_worker.w_job.j_func == NULL) { - dl_worker.w_job.j_fp = fp; - dl_worker.w_job.j_m_in = m_in; - dl_worker.w_job.j_func = func; - worker_wake(&dl_worker); - } + is_pending = (rfp->fp_flags & FP_PENDING); + is_active = (rfp->fp_worker != NULL); + has_normal_work = (rfp->fp_func != NULL); + has_pm_work = (rfp->fp_flags & FP_PM_WORK); + + /* If there is no work scheduled for the process, we can start work. */ + if (!is_pending && !is_active) return TRUE; + + /* If there is already normal work scheduled for the process, we cannot add + * more, since we support only one normal job per process. + */ + if (has_normal_work) return FALSE; + + /* If this process has pending PM work but no normal work, we can add the + * normal work for execution before the worker will start. + */ + if (is_pending) return TRUE; + + /* However, if a worker is active for PM work, we cannot add normal work + * either, because the work will not be considered. For this reason, we can + * not use this function for processes that can possibly get postponed PM + * work. It is still safe for core system processes, though. + */ + return FALSE; } /*===========================================================================* - * sys_worker_start * + * worker_try_activate * *===========================================================================*/ -void sys_worker_start(void *(*func)(void *arg)) +static void worker_try_activate(struct fproc *rfp, int use_spare) { -/* Carry out work for the system (i.e., kernel or PM). If this thread is idle - * do it right away, else create new job and append it to the queue. */ - - if (sys_worker.w_job.j_func == NULL) { - sys_worker.w_job.j_fp = fp; - sys_worker.w_job.j_m_in = m_in; - sys_worker.w_job.j_func = func; - worker_wake(&sys_worker); - } else { - append_job(&sys_worker.w_job, func); - } -} - -/*===========================================================================* - * append_job * - *===========================================================================*/ -static void append_job(struct job *job, void *(*func)(void *arg)) -{ -/* Append a job */ - - struct job *new_job, *tail; - - /* Create new job */ - new_job = calloc(1, sizeof(struct job)); - assert(new_job != NULL); - new_job->j_fp = fp; - new_job->j_m_in = m_in; - new_job->j_func = func; - new_job->j_next = NULL; - new_job->j_err_code = OK; - - /* Append to queue */ - tail = job; - while (tail->j_next != NULL) tail = tail->j_next; - tail->j_next = new_job; -} - -/*===========================================================================* - * worker_start * - *===========================================================================*/ -void worker_start(void *(*func)(void *arg)) -{ -/* Find an available worker or wait for one */ - int i; +/* See if we can wake up a thread to do the work scheduled for the given + * process. If not, mark the process as having pending work for later. + */ + int i, available, needed; struct worker_thread *worker; - if (fp->fp_flags & FP_DROP_WORK) { - return; /* This process is not allowed to accept new work */ - } + /* Use the last available thread only if requested. Otherwise, leave at least + * one spare thread for deadlock resolution. + */ + needed = use_spare ? 1 : 2; worker = NULL; - for (i = 0; i < NR_WTHREADS; i++) { - if (workers[i].w_job.j_func == NULL) { - worker = &workers[i]; - break; + for (i = available = 0; i < NR_WTHREADS; i++) { + if (workers[i].w_fp == NULL) { + if (worker == NULL) + worker = &workers[i]; + if (++available >= needed) + break; } } - if (worker != NULL) { - worker->w_job.j_fp = fp; - worker->w_job.j_m_in = m_in; - worker->w_job.j_func = func; - worker->w_job.j_next = NULL; - worker->w_job.j_err_code = OK; + if (available >= needed) { + assert(worker != NULL); + rfp->fp_worker = worker; + worker->w_fp = rfp; worker_wake(worker); - return; - } - - /* No worker threads available, let's wait for one to finish. */ - /* If this process already has a job scheduled, forget about this new - * job; - * - the new job is do_dummy and we have already scheduled an actual job - * - the new job is an actual job and we have already scheduled do_dummy in - * order to exit this proc, so doing the new job is pointless. */ - if (fp->fp_job.j_func == NULL) { - assert(!(fp->fp_flags & FP_PENDING)); - fp->fp_job.j_fp = fp; - fp->fp_job.j_m_in = m_in; - fp->fp_job.j_func = func; - fp->fp_job.j_next = NULL; - fp->fp_job.j_err_code = OK; - fp->fp_flags |= FP_PENDING; + } else { + rfp->fp_flags |= FP_PENDING; pending++; } } +/*===========================================================================* + * worker_start * + *===========================================================================*/ +void worker_start(struct fproc *rfp, void (*func)(void), message *m_ptr, + int use_spare) +{ +/* Schedule work to be done by a worker thread. The work is bound to the given + * process. If a function pointer is given, the work is considered normal work, + * and the function will be called to handle it. If the function pointer is + * NULL, the work is considered postponed PM work, and service_pm_postponed + * will be called to handle it. The input message will be a copy of the given + * message. Optionally, the last spare (deadlock-resolving) thread may be used + * to execute the work immediately. + */ + int is_pm_work, is_pending, is_active, has_normal_work, has_pm_work; + + assert(rfp != NULL); + + is_pm_work = (func == NULL); + is_pending = (rfp->fp_flags & FP_PENDING); + is_active = (rfp->fp_worker != NULL); + has_normal_work = (rfp->fp_func != NULL); + has_pm_work = (rfp->fp_flags & FP_PM_WORK); + + /* Sanity checks. If any of these trigger, someone messed up badly! */ + if (is_pending || is_active) { + if (is_pending && is_active) + panic("work cannot be both pending and active"); + + /* The process cannot make more than one call at once. */ + if (!is_pm_work && has_normal_work) + panic("process has two calls (%x, %x)", + rfp->fp_msg.m_type, m_ptr->m_type); + + /* PM will not send more than one job per process to us at once. */ + if (is_pm_work && has_pm_work) + panic("got two calls from PM (%x, %x)", + rfp->fp_pm_msg.m_type, m_ptr->m_type); + + /* Despite PM's sys_delay_stop() system, it is possible that normal + * work (in particular, do_pending_pipe) arrives after postponed PM + * work has been scheduled for execution, so we don't check for that. + */ +#if 0 + printf("VFS: adding %s work to %s thread\n", + is_pm_work ? "PM" : "normal", + is_pending ? "pending" : "active"); +#endif + } else { + /* Some cleanup step forgotten somewhere? */ + if (has_normal_work || has_pm_work) + panic("worker administration error"); + } + + /* Save the work to be performed. */ + if (!is_pm_work) { + rfp->fp_msg = *m_ptr; + rfp->fp_func = func; + } else { + rfp->fp_pm_msg = *m_ptr; + rfp->fp_flags |= FP_PM_WORK; + } + + /* If we have not only added to existing work, go look for a free thread. + * Note that we won't be using the spare thread for normal work if there is + * already PM work pending, but that situation will never occur in practice. + */ + if (!is_pending && !is_active) + worker_try_activate(rfp, use_spare); +} + /*===========================================================================* * worker_sleep * *===========================================================================*/ -static void worker_sleep(struct worker_thread *worker) +static void worker_sleep(void) { + struct worker_thread *worker = self; ASSERTW(worker); - assert(self == worker); if (mutex_lock(&worker->w_event_mutex) != 0) panic("unable to lock event mutex"); if (cond_wait(&worker->w_event, &worker->w_event_mutex) != 0) @@ -285,16 +327,55 @@ static void worker_wake(struct worker_thread *worker) panic("unable to unlock event mutex"); } +/*===========================================================================* + * worker_suspend * + *===========================================================================*/ +struct worker_thread *worker_suspend(void) +{ +/* Suspend the current thread, saving certain thread variables. Return a + * pointer to the thread's worker structure for later resumption. + */ + + ASSERTW(self); + assert(fp != NULL); + assert(self->w_fp == fp); + assert(fp->fp_worker == self); + + self->w_err_code = err_code; + + return self; +} + +/*===========================================================================* + * worker_resume * + *===========================================================================*/ +void worker_resume(struct worker_thread *org_self) +{ +/* Resume the current thread after suspension, restoring thread variables. */ + + ASSERTW(org_self); + + self = org_self; + + fp = self->w_fp; + assert(fp != NULL); + + err_code = self->w_err_code; +} + /*===========================================================================* * worker_wait * *===========================================================================*/ void worker_wait(void) { - self->w_job.j_err_code = err_code; - worker_sleep(self); +/* Put the current thread to sleep until woken up by the main thread. */ + + (void) worker_suspend(); /* worker_sleep already saves and restores 'self' */ + + worker_sleep(); + /* We continue here after waking up */ - fp = self->w_job.j_fp; /* Restore global data */ - err_code = self->w_job.j_err_code; + worker_resume(self); assert(self->w_next == NULL); } @@ -323,7 +404,9 @@ void worker_stop(struct worker_thread *worker) panic("reply storage consistency error"); /* Oh dear */ } } else { - worker->w_job.j_m_in.m_type = EIO; + /* This shouldn't happen at all... */ + printf("VFS: stopping worker not blocked on any task?\n"); + util_stacktrace(); } worker_wake(worker); } @@ -338,12 +421,9 @@ void worker_stop_by_endpt(endpoint_t proc_e) if (proc_e == NONE) return; - if (worker_waiting_for(&sys_worker, proc_e)) worker_stop(&sys_worker); - if (worker_waiting_for(&dl_worker, proc_e)) worker_stop(&dl_worker); - for (i = 0; i < NR_WTHREADS; i++) { worker = &workers[i]; - if (worker_waiting_for(worker, proc_e)) + if (worker->w_fp != NULL && worker->w_task == proc_e) worker_stop(worker); } } @@ -354,52 +434,36 @@ void worker_stop_by_endpt(endpoint_t proc_e) struct worker_thread *worker_get(thread_t worker_tid) { int i; - struct worker_thread *worker; - worker = NULL; - if (worker_tid == sys_worker.w_tid) - worker = &sys_worker; - else if (worker_tid == dl_worker.w_tid) - worker = &dl_worker; - else { - for (i = 0; i < NR_WTHREADS; i++) { - if (workers[i].w_tid == worker_tid) { - worker = &workers[i]; - break; - } - } - } - - return(worker); -} - -/*===========================================================================* - * worker_getjob * - *===========================================================================*/ -struct job *worker_getjob(thread_t worker_tid) -{ - struct worker_thread *worker; - - if ((worker = worker_get(worker_tid)) != NULL) - return(&worker->w_job); + for (i = 0; i < NR_WTHREADS; i++) + if (workers[i].w_tid == worker_tid) + return(&workers[i]); return(NULL); } /*===========================================================================* - * worker_waiting_for * + * worker_set_proc * *===========================================================================*/ -static int worker_waiting_for(struct worker_thread *worker, endpoint_t proc_e) +void worker_set_proc(struct fproc *rfp) { - ASSERTW(worker); /* Make sure we have a valid thread */ +/* Perform an incredibly ugly action that completely violates the threading + * model: change the current working thread's process context to another + * process. The caller is expected to hold the lock to both the calling and the + * target process, and neither process is expected to continue regular + * operation when done. This code is here *only* and *strictly* for the reboot + * code, and *must not* be used for anything else. + */ - if (worker->w_job.j_func != NULL) { - if (worker->w_task != NONE) - return(worker->w_task == proc_e); - else if (worker->w_job.j_fp != NULL) { - return(worker->w_job.j_fp->fp_task == proc_e); - } - } + if (fp == rfp) return; - return(0); + if (rfp->fp_worker != NULL) + panic("worker_set_proc: target process not idle"); + + fp->fp_worker = NULL; + + fp = rfp; + + self->w_fp = rfp; + fp->fp_worker = self; } diff --git a/servers/vm/cache.c b/servers/vm/cache.c index fd6be5ab3..6935357d0 100644 --- a/servers/vm/cache.c +++ b/servers/vm/cache.c @@ -304,6 +304,25 @@ int cache_freepages(int pages) return freed; } +/* + * Remove all pages that are associated with the given device. + */ +void +clear_cache_bydev(dev_t dev) +{ + struct cached_page *cp, *ncp; + int h; + + for (h = 0; h < HASHSIZE; h++) { + for (cp = cache_hash_bydev[h]; cp != NULL; cp = ncp) { + ncp = cp->hash_next_dev; + + if (cp->dev == dev) + rmcache(cp); + } + } +} + void get_stats_info(struct vm_stats_info *vsi) { vsi->vsi_cached = cached_pages; diff --git a/servers/vm/main.c b/servers/vm/main.c index 8b63b6fbb..1b0ef0653 100644 --- a/servers/vm/main.c +++ b/servers/vm/main.c @@ -444,6 +444,7 @@ void init_vm(void) /* Cache blocks. */ CALLMAP(VM_MAPCACHEPAGE, do_mapcache); CALLMAP(VM_SETCACHEPAGE, do_setcache); + CALLMAP(VM_CLEARCACHE, do_clearcache); /* getrusage */ CALLMAP(VM_GETRUSAGE, do_getrusage); diff --git a/servers/vm/mem_cache.c b/servers/vm/mem_cache.c index 646008eb0..65df8cfb2 100644 --- a/servers/vm/mem_cache.c +++ b/servers/vm/mem_cache.c @@ -227,3 +227,17 @@ do_setcache(message *msg) return OK; } +/* + * A file system wants to invalidate all pages belonging to a certain device. + */ +int +do_clearcache(message *msg) +{ + dev_t dev; + + dev = msg->m_u.m_vmmcp.dev; + + clear_cache_bydev(dev); + + return OK; +} diff --git a/servers/vm/mem_file.c b/servers/vm/mem_file.c index 9fc51140d..c21721aea 100644 --- a/servers/vm/mem_file.c +++ b/servers/vm/mem_file.c @@ -115,7 +115,7 @@ static int mappedfile_pagefault(struct vmproc *vmp, struct vir_region *region, if(!cb) { printf("VM: mem_file: no callback, returning EFAULT\n"); - sys_sysctl_stacktrace(vmp->vm_endpoint); + sys_diagctl_stacktrace(vmp->vm_endpoint); return EFAULT; } diff --git a/servers/vm/mmap.c b/servers/vm/mmap.c index aa2ad2b16..7c135fac8 100644 --- a/servers/vm/mmap.c +++ b/servers/vm/mmap.c @@ -181,7 +181,7 @@ static void mmap_file_cont(struct vmproc *vmp, message *replymsg, void *cbarg, if(replymsg->VMV_RESULT != OK) { printf("VM: VFS reply failed (%d)\n", replymsg->VMV_RESULT); - sys_sysctl_stacktrace(vmp->vm_endpoint); + sys_diagctl_stacktrace(vmp->vm_endpoint); result = origmsg->VMV_RESULT; } else { /* Finish mmap */ @@ -530,7 +530,7 @@ int do_munmap(message *m) if(!(vr = map_lookup(vmp, addr, NULL))) { printf("VM: unmap: address 0x%lx not found in %d\n", addr, target); - sys_sysctl_stacktrace(target); + sys_diagctl_stacktrace(target); return EFAULT; } len = vr->length; diff --git a/servers/vm/pagefaults.c b/servers/vm/pagefaults.c index 6ae166a68..1cba5e2e9 100644 --- a/servers/vm/pagefaults.c +++ b/servers/vm/pagefaults.c @@ -87,7 +87,7 @@ static void handle_pagefault(endpoint_t ep, vir_bytes addr, u32_t err, int retry assert(PFERR_NOPAGE(err)); printf("VM: pagefault: SIGSEGV %d bad addr 0x%lx; %s\n", ep, addr, pf_errstr(err)); - sys_sysctl_stacktrace(ep); + sys_diagctl_stacktrace(ep); } if((s=sys_kill(vmp->vm_endpoint, SIGSEGV)) != OK) panic("sys_kill failed: %d", s); diff --git a/servers/vm/proto.h b/servers/vm/proto.h index 5092a875f..995a99e6d 100644 --- a/servers/vm/proto.h +++ b/servers/vm/proto.h @@ -218,6 +218,7 @@ void shared_setsource(struct vir_region *vr, endpoint_t ep, struct vir_region *s /* mem_cache.c */ int do_mapcache(message *m); int do_setcache(message *m); +int do_clearcache(message *m); /* cache.c */ struct cached_page *find_cached_page_bydev(dev_t dev, u64_t dev_off, @@ -229,6 +230,7 @@ int cache_freepages(int pages); void get_stats_info(struct vm_stats_info *vsi); void cache_lru_touch(struct cached_page *hb); void rmcache(struct cached_page *cp); +void clear_cache_bydev(dev_t dev); /* vfs.c */ int vfs_request(int reqno, int fd, struct vmproc *vmp, u64_t offset, diff --git a/sys/dev/Makefile b/sys/dev/Makefile index 00d1bc537..ed2838983 100644 --- a/sys/dev/Makefile +++ b/sys/dev/Makefile @@ -21,6 +21,8 @@ INCSDIR= /usr/include/dev # Only install includes which are used by userland INCS= biovar.h ccdvar.h cgdvar.h fssvar.h keylock.h kttcpio.h lockstat.h \ md.h vndvar.h +.else +INCS= vndvar.h .endif .include diff --git a/sys/dev/vndvar.h b/sys/dev/vndvar.h new file mode 100644 index 000000000..cc06ce867 --- /dev/null +++ b/sys/dev/vndvar.h @@ -0,0 +1,218 @@ +/* $NetBSD: vndvar.h,v 1.31 2011/06/29 09:12:42 hannken Exp $ */ + +/*- + * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: Utah $Hdr: fdioctl.h 1.1 90/07/09$ + * + * @(#)vnioctl.h 8.1 (Berkeley) 6/10/93 + */ + +#ifndef _SYS_DEV_VNDVAR_H_ +#define _SYS_DEV_VNDVAR_H_ + +#ifndef __minix +#include +#endif + +/* + * Vnode disk pseudo-geometry information. + */ +struct vndgeom { + u_int32_t vng_secsize; /* # bytes per sector */ + u_int32_t vng_nsectors; /* # data sectors per track */ + u_int32_t vng_ntracks; /* # tracks per cylinder */ + u_int32_t vng_ncylinders; /* # cylinders per unit */ +}; + +/* + * Ioctl definitions for file (vnode) disk pseudo-device. + */ +struct vnd_ioctl { +#ifndef __minix + char *vnd_file; /* pathname of file to mount */ +#else + int vnd_fildes; /* file descriptor of file to mount */ +#endif + int vnd_flags; /* flags; see below */ + struct vndgeom vnd_geom; /* geometry to emulate */ +#ifndef __minix + unsigned int vnd_osize; /* (returned) size of disk */ +#endif + uint64_t vnd_size; /* (returned) size of disk */ +}; + +/* vnd_flags */ +#define VNDIOF_HASGEOM 0x01 /* use specified geometry */ +#define VNDIOF_READONLY 0x02 /* as read-only device */ +#define VNDIOF_FORCE 0x04 /* force close */ + +#ifndef __minix +#ifdef _KERNEL + +struct vnode; + +/* + * A vnode disk's state information. + */ +struct vnd_softc { + device_t sc_dev; + int sc_flags; /* flags */ + size_t sc_size; /* size of vnd */ + struct vnode *sc_vp; /* vnode */ + kauth_cred_t sc_cred; /* credentials */ + int sc_maxactive; /* max # of active requests */ + struct bufq_state *sc_tab; /* transfer queue */ + int sc_active; /* number of active transfers */ + struct disk sc_dkdev; /* generic disk device info */ + struct vndgeom sc_geom; /* virtual geometry */ + struct pool sc_vxpool; /* vndxfer pool */ + struct pool sc_vbpool; /* vndbuf pool */ + struct lwp *sc_kthread; /* kernel thread */ + u_int32_t sc_comp_blksz; /* precompressed block size */ + u_int32_t sc_comp_numoffs;/* count of compressed block offsets */ + u_int64_t *sc_comp_offsets;/* file idx's to compressed blocks */ + unsigned char *sc_comp_buff; /* compressed data buffer */ + unsigned char *sc_comp_decombuf;/* decompressed data buffer */ + int32_t sc_comp_buffblk;/*current decompressed block */ + z_stream sc_comp_stream;/* decompress descriptor */ +}; +#endif + +/* sc_flags */ +#define VNF_INITED 0x001 /* unit has been initialized */ +#define VNF_WLABEL 0x002 /* label area is writable */ +#define VNF_LABELLING 0x004 /* unit is currently being labelled */ +#define VNF_WANTED 0x008 /* someone is waiting to obtain a lock */ +#define VNF_LOCKED 0x010 /* unit is locked */ +#define VNF_READONLY 0x020 /* unit is read-only */ +#define VNF_KLABEL 0x040 /* keep label on close */ +#define VNF_VLABEL 0x080 /* label is valid */ +#define VNF_KTHREAD 0x100 /* thread is running */ +#define VNF_VUNCONF 0x200 /* device is unconfiguring */ +#define VNF_COMP 0x400 /* file is compressed */ +#define VNF_CLEARING 0x800 /* unit is being torn down */ +#define VNF_USE_VN_RDWR 0x1000 /* have to use vn_rdwr() */ + +/* structure of header in a compressed file */ +struct vnd_comp_header +{ + char preamble[128]; + u_int32_t block_size; + u_int32_t num_blocks; +}; +#endif + +/* + * A simple structure for describing which vnd units are in use. + */ + +struct vnd_user { + int vnu_unit; /* which vnd unit */ + dev_t vnu_dev; /* file is on this device... */ + ino_t vnu_ino; /* ...at this inode */ +}; + +/* + * Before you can use a unit, it must be configured with VNDIOCSET. + * The configuration persists across opens and closes of the device; + * an VNDIOCCLR must be used to reset a configuration. An attempt to + * VNDIOCSET an already active unit will return EBUSY. + */ +#define VNDIOCSET _IOWR('F', 0, struct vnd_ioctl) /* enable disk */ +#define VNDIOCCLR _IOW('F', 1, struct vnd_ioctl) /* disable disk */ +#define VNDIOCGET _IOWR('F', 3, struct vnd_user) /* get list */ + +#ifdef _KERNEL +/* + * Everything else is kernel-private, mostly exported for compat/netbsd32. + * + * NetBSD 3.0 had a 32-bit value for vnu_ino. + * + * NetBSD 5.0 had a 32-bit value for vnu_dev, and vnd_size. + */ +struct vnd_user30 { + int vnu_unit; /* which vnd unit */ + uint32_t vnu_dev; /* file is on this device... */ + uint32_t vnu_ino; /* ...at this inode */ +}; +#define VNDIOCGET30 _IOWR('F', 2, struct vnd_user30) /* get list */ + +struct vnd_user50 { + int vnu_unit; /* which vnd unit */ + uint32_t vnu_dev; /* file is on this device... */ + ino_t vnu_ino; /* ...at this inode */ +}; +#define VNDIOCGET50 _IOWR('F', 3, struct vnd_user50) /* get list */ + +struct vnd_ioctl50 { + char *vnd_file; /* pathname of file to mount */ + int vnd_flags; /* flags; see below */ + struct vndgeom vnd_geom; /* geometry to emulate */ + unsigned int vnd_size; /* (returned) size of disk */ +}; +#define VNDIOCSET50 _IOWR('F', 0, struct vnd_ioctl50) +#define VNDIOCCLR50 _IOW('F', 1, struct vnd_ioctl50) + +#endif /* _KERNEL */ + +#endif /* _SYS_DEV_VNDVAR_H_ */ diff --git a/sys/stdlib.h b/sys/stdlib.h index 66f86c382..287bb29ae 100644 --- a/sys/stdlib.h +++ b/sys/stdlib.h @@ -267,11 +267,10 @@ int cgetustr(char *, const char *, char **); void csetexpandtc(int); int daemon(int, int); -#ifndef __minix +int devname_r(dev_t, mode_t, char *, size_t); #if !defined(__LIBC12_SOURCE__) && !defined(_STANDALONE) __aconst char *devname(dev_t, mode_t) __RENAME(__devname50); #endif -#endif /* !__minix */ #define HN_DECIMAL 0x01 #define HN_NOSPACE 0x02 diff --git a/sys/sys/errno.h b/sys/sys/errno.h index d8f1b5b7b..c29599388 100644 --- a/sys/sys/errno.h +++ b/sys/sys/errno.h @@ -79,7 +79,6 @@ /* The following errors relate to networking. */ #define EPACKSIZE (_SIGN 50 ) /* invalid packet size for some protocol */ #define ENOBUFS (_SIGN 51 ) /* not enough buffers left */ -#define EBADIOCTL (_SIGN 52 ) /* illegal ioctl for device */ #define EBADMODE (_SIGN 53 ) /* badmode in ioctl */ #define EWOULDBLOCK (_SIGN 54 ) /* call would block on nonblocking socket */ #define ENETUNREACH (_SIGN 55 ) /* network unreachable */ diff --git a/sys/sys/ioctl.h b/sys/sys/ioctl.h index dc5666f33..b85abb839 100644 --- a/sys/sys/ioctl.h +++ b/sys/sys/ioctl.h @@ -20,7 +20,10 @@ #include /* 'm' */ #include /* 'M' */ #include /* 's' */ -#include /* 'F' */ +#include /* 'b' */ +#include /* 'B' */ +#include /* 'V' */ +#include /* 'F' */ #if defined(_NETBSD_SOURCE) #define TIOCDRAIN TCDRAIN diff --git a/sys/sys/ptrace.h b/sys/sys/ptrace.h index 59c1a442a..b829771a4 100644 --- a/sys/sys/ptrace.h +++ b/sys/sys/ptrace.h @@ -23,7 +23,6 @@ #define T_SETOPT 13 /* set trace options */ #define T_GETRANGE 14 /* get range of values */ #define T_SETRANGE 15 /* set range of values */ -#define T_DUMPCORE 16 /* dumps the core for the process with the given pid */ #define T_READB_INS 100 /* Read a byte from the text segment of an * untraced process (only for root) diff --git a/sys/sys/select.h b/sys/sys/select.h index fa9d1b4b4..57925821e 100644 --- a/sys/sys/select.h +++ b/sys/sys/select.h @@ -75,13 +75,4 @@ int select(int, fd_set * __restrict, fd_set * __restrict, __END_DECLS #endif /* _KERNEL */ -#if defined(__minix) && defined(_NETBSD_SOURCE) -/* possible select() operation types; read, write, errors */ -/* (FS/driver internal use only) */ -#define SEL_RD (1 << 0) -#define SEL_WR (1 << 1) -#define SEL_ERR (1 << 2) -#define SEL_NOTIFY (1 << 3) /* not a real select operation */ -#endif /* defined(__minix) && defined(_NETBSD_SOURCE) */ - #endif /* !_SYS_SELECT_H_ */ diff --git a/sys/sys/statvfs.h b/sys/sys/statvfs.h index 111f17ce6..c6a92df5d 100644 --- a/sys/sys/statvfs.h +++ b/sys/sys/statvfs.h @@ -37,6 +37,7 @@ #include #include #include +#include #define _VFS_NAMELEN 32 #define _VFS_MNAMELEN 1024 @@ -63,33 +64,66 @@ typedef _BSD_SIZE_T_ size_t; #endif struct statvfs { - unsigned long f_bsize; /* File system block size. */ - unsigned long f_frsize; /* Fundamental file system block size. */ - fsblkcnt_t f_blocks; /* Total number of blocks on file system */ - /* in units of f_frsize. */ - fsblkcnt_t f_bfree; /* Total number of free blocks. */ - fsblkcnt_t f_bavail; /* Number of free blocks available to */ - /* non-privileged process. */ - fsfilcnt_t f_files; /* Total number of file serial numbers. */ - fsfilcnt_t f_ffree; /* Total number of free file serial numbers. */ - fsfilcnt_t f_favail; /* Number of file serial numbers available */ - /* to non-privileged process. */ - unsigned long f_fsid; /* File system ID. */ - unsigned long f_flag; /* Bit mask of f_flag values. */ - unsigned long f_namemax; /* Maximum filename length. */ - unsigned char __padding[32]; /* Padding for future compatibility */ + unsigned long f_flag; /* copy of mount exported flags */ + unsigned long f_bsize; /* file system block size */ + unsigned long f_frsize; /* fundamental file system block size */ + unsigned long f_iosize; /* optimal file system block size */ + + /* The following are in units of f_frsize */ + fsblkcnt_t f_blocks; /* number of blocks in file system, */ + fsblkcnt_t f_bfree; /* free blocks avail in file system */ + fsblkcnt_t f_bavail; /* free blocks avail to non-root */ + fsblkcnt_t f_bresvd; /* blocks reserved for root */ + + fsfilcnt_t f_files; /* total file nodes in file system */ + fsfilcnt_t f_ffree; /* free file nodes in file system */ + fsfilcnt_t f_favail; /* free file nodes avail to non-root */ + fsfilcnt_t f_fresvd; /* file nodes reserved for root */ + + uint64_t f_syncreads; /* count of sync reads since mount */ + uint64_t f_syncwrites; /* count of sync writes since mount */ + + uint64_t f_asyncreads; /* count of async reads since mount */ + uint64_t f_asyncwrites; /* count of async writes since mount */ + + fsid_t f_fsidx; /* NetBSD compatible fsid */ + unsigned long f_fsid; /* Posix compatible fsid */ + unsigned long f_namemax; /* maximum filename length */ + uid_t f_owner; /* user that mounted the file system */ + + uint32_t f_spare[4]; /* spare space */ + + char f_fstypename[_VFS_NAMELEN]; /* fs type name */ + char f_mntonname[_VFS_MNAMELEN]; /* directory on which mounted */ + char f_mntfromname[_VFS_MNAMELEN]; /* mounted file system */ + }; -/* Possible values for statvfs->f_flag */ -#define ST_RDONLY 0x1 -#define ST_NOSUID 0x2 +#if defined(_NETBSD_SOURCE) && !defined(_POSIX_SOURCE) && \ + !defined(_XOPEN_SOURCE) +#define VFS_NAMELEN _VFS_NAMELEN +#define VFS_MNAMELEN _VFS_MNAMELEN +#endif + +#define ST_RDONLY MNT_RDONLY +#define ST_NOSUID MNT_NOSUID #ifdef __minix -#define ST_NOTRUNC 0x4 +#define ST_NOTRUNC __MNT_UNUSED1 #endif /* !__minix*/ +#define ST_WAIT MNT_WAIT +#define ST_NOWAIT MNT_NOWAIT + __BEGIN_DECLS int statvfs(const char *__restrict, struct statvfs *__restrict); int fstatvfs(int, struct statvfs *); +int getvfsstat(struct statvfs *, size_t, int); +#ifndef __LIBC12_SOURCE__ +int getmntinfo(struct statvfs **, int) __RENAME(__getmntinfo13); +#endif /* __LIBC12_SOURCE__ */ + +int statvfs1(const char *__restrict, struct statvfs *__restrict, int); +int fstatvfs1(int, struct statvfs *, int); __END_DECLS -#endif /* _SYS_STATVFS_H_ */ +#endif /* !_SYS_STATVFS_H_ */ diff --git a/test/Makefile b/test/Makefile index ffeda323e..91dd65f85 100644 --- a/test/Makefile +++ b/test/Makefile @@ -16,6 +16,8 @@ LDADD+= -lm -lcompat_minix .include +SUBDIR= blocktest + # Some have special flags compiling .if ${MACHINE_ARCH} == "i386" # LSC FIXME: Compilation error for now on ARM with that! @@ -31,6 +33,8 @@ COPTS.test68.c= -O0 # Some have special libraries LDADD.test59= -lmthread +LDADD.test76= -lutil +LDADD.test77= -lutil # Some have an extra file OBJS.test57= test57loop.o @@ -53,7 +57,7 @@ MINIX_TESTS= \ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \ 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \ 41 42 43 44 45 46 48 49 50 52 53 54 55 56 58 59 60 \ -61 64 65 66 67 68 69 70 71 72 73 74 75 +61 64 65 66 67 68 69 70 71 72 73 74 75 76 77 .if ${MACHINE_ARCH} == "i386" MINIX_TESTS+= \ @@ -71,10 +75,10 @@ LDSTATIC:= -static PROGS+= test${t} .endfor -PROGS+= t10a t11a t11b t40a t40b t40c t40d t40e t40f t60a t60b \ - t67a t67b t68a t68b +PROGS+= t10a t11a t11b t40a t40b t40c t40d t40e t40f t40g t60a t60b \ + t67a t67b t68a t68b tvnd -SCRIPTS+= run testinterp.sh testsh1.sh testsh2.sh +SCRIPTS+= run testinterp.sh testsh1.sh testsh2.sh testvnd.sh .if ${MKPIC} == "yes" # Build them as dynamic executables by default if shared libraries @@ -111,7 +115,7 @@ OBJS.${o} += common.o # LSC Make sure there is not leftover after a failed testrun clean: .PHONY .MAKE - $(MAKE) -C select clean rm -rf DIR* .include +.include diff --git a/test/blocktest/Makefile b/test/blocktest/Makefile index fdd4d7811..b13ba095c 100644 --- a/test/blocktest/Makefile +++ b/test/blocktest/Makefile @@ -1,13 +1,15 @@ # Makefile for the Block Device Driver Test driver (blocktest) PROG= blocktest SRCS= blocktest.c +FILES= system.conf support.sh test.sh README DPADD+= ${LIBSYS} LDADD+= -lsys MAN= -BINDIR?= /usr/sbin +BINDIR?= /usr/tests/minix-posix/blocktest +FILESDIR?= /usr/tests/minix-posix/blocktest .include "Makefile.inc" .include diff --git a/test/blocktest/blocktest.c b/test/blocktest/blocktest.c index e512d93e9..7d7526cb3 100644 --- a/test/blocktest/blocktest.c +++ b/test/blocktest/blocktest.c @@ -1,10 +1,12 @@ /* Block Device Driver Test driver, by D.C. van Moolenbroek */ #include +#include #include #include #include #include #include +#include #include enum { @@ -33,12 +35,17 @@ static endpoint_t driver_endpt; /* driver endpoint */ static int may_write = FALSE; /* may we write to the device? */ static int sector_size = 512; /* size of a single disk sector */ static int min_read = 512; /* minimum total size of read req */ +static int min_write = 0; /* minimum total size of write req */ static int element_size = 512; /* minimum I/O vector element size */ static int max_size = 131072; /* maximum total size of any req */ /* Note that we do not test exceeding the max_size limit, so it is safe to set * it to a value lower than the driver supports. */ +/* These settings are used for automated test runs. */ +static int contig = TRUE; /* allocate contiguous DMA memory? */ +static int silent = FALSE; /* do not produce console output? */ + static struct part_geom part; /* base and size of target partition */ #define NR_OPENED 10 /* maximum number of opened devices */ @@ -60,10 +67,60 @@ static struct optset optset_table[] = { { "sector", OPT_INT, §or_size, 10 }, { "element", OPT_INT, &element_size, 10 }, { "min_read", OPT_INT, &min_read, 10 }, + { "min_write", OPT_INT, &min_write, 10 }, { "max", OPT_INT, &max_size, 10 }, + { "nocontig", OPT_BOOL, &contig, FALSE }, + { "silent", OPT_BOOL, &silent, TRUE }, { NULL, 0, NULL, 0 } }; +static void output(char *fmt, ...) +{ + /* Print debugging information, unless configured to be silent. + */ + va_list argp; + + if (silent) + return; + + va_start(argp, fmt); + + vprintf(fmt, argp); + + va_end(argp); +} + +static void *alloc_dma_memory(size_t size) +{ + /* Allocate memory that may be used for direct DMA. For most drivers, + * this means that the memory has to be physically contiguous. For some + * drivers (e.g. VND) we allow non-contiguous allocation, because VM is + * currently flaky and does not always manage to provide contiguous + * memory even when it should, thus causing needless test failures. + */ + void *ptr; + + if (contig) + ptr = alloc_contig(size, 0, NULL); + else + ptr = minix_mmap(NULL, size, PROT_READ | PROT_WRITE, + MAP_PREALLOC | MAP_ANON, -1, 0); + + if (ptr == MAP_FAILED) + panic("unable to allocate %d bytes of memory", size); + + return ptr; +} + +static void free_dma_memory(void *ptr, size_t size) +{ + /* Free memory previously allocated for direct DMA. */ + if (contig) + free_contig(ptr, size); + else + minix_munmap(ptr, size); +} + static int set_result(result_t *res, int type, ssize_t value) { /* Set the result to the given result type and with the given optional @@ -107,42 +164,42 @@ static void got_result(result_t *res, char *desc) } } - printf("#%02d: %-38s\t[%s]\n", ++i, desc, + output("#%02d: %-38s\t[%s]\n", ++i, desc, (res->type == RESULT_OK) ? "PASS" : "FAIL"); switch (res->type) { case RESULT_DEATH: - printf("- driver died\n"); + output("- driver died\n"); break; case RESULT_COMMFAIL: - printf("- communication failed; sendrec returned %d\n", + output("- communication failed; sendrec returned %d\n", res->value); break; case RESULT_BADTYPE: - printf("- bad type %d in reply message\n", res->value); + output("- bad type %d in reply message\n", res->value); break; case RESULT_BADID: - printf("- mismatched ID %d in reply message\n", res->value); + output("- mismatched ID %d in reply message\n", res->value); break; case RESULT_BADSTATUS: - printf("- bad or unexpected status %d in reply message\n", + output("- bad or unexpected status %d in reply message\n", res->value); break; case RESULT_TRUNC: - printf("- result size not as expected (%u bytes left)\n", + output("- result size not as expected (%u bytes left)\n", res->value); break; case RESULT_CORRUPT: - printf("- buffer has been modified erroneously\n"); + output("- buffer has been modified erroneously\n"); break; case RESULT_MISSING: - printf("- buffer has been left untouched erroneously\n"); + output("- buffer has been left untouched erroneously\n"); break; case RESULT_OVERFLOW: - printf("- area around target buffer modified\n"); + output("- area around target buffer modified\n"); break; case RESULT_BADVALUE: - printf("- bad or unexpected return value %d from call\n", + output("- bad or unexpected return value %d from call\n", res->value); break; } @@ -153,7 +210,7 @@ static void test_group(char *name, int exec) /* Start a new group of tests. */ - printf("Test group: %s%s\n", name, exec ? "" : " (skipping)"); + output("Test group: %s%s\n", name, exec ? "" : " (skipping)"); group_failure = FALSE; } @@ -169,7 +226,7 @@ static void reopen_device(dev_t minor) memset(&m, 0, sizeof(m)); m.m_type = BDEV_OPEN; m.BDEV_MINOR = minor; - m.BDEV_ACCESS = (may_write) ? (R_BIT | W_BIT) : R_BIT; + m.BDEV_ACCESS = (may_write) ? (BDEV_R_BIT | BDEV_W_BIT) : BDEV_R_BIT; m.BDEV_ID = 0; (void) sendrec(driver_endpt, &m); @@ -194,7 +251,7 @@ static int sendrec_driver(message *m_ptr, ssize_t exp, result_t *res) /* The driver has died. Find its new endpoint, and reopen all * devices that we opened earlier. Then return failure. */ - printf("WARNING: driver has died, attempting to proceed\n"); + output("WARNING: driver has died, attempting to proceed\n"); driver_deaths++; @@ -323,9 +380,7 @@ static void alloc_buf_and_grant(u8_t **ptr, cp_grant_id_t *grant, * grant for it with the requested CPF_* grant permissions. */ - *ptr = alloc_contig(size, 0, NULL); - if (*ptr == NULL) - panic("unable to allocate memory"); + *ptr = alloc_dma_memory(size); if ((*grant = cpf_grant_direct(driver_endpt, (vir_bytes) *ptr, size, perms)) == GRANT_INVALID) @@ -339,7 +394,7 @@ static void free_buf_and_grant(u8_t *ptr, cp_grant_id_t grant, size_t size) cpf_revoke(grant); - free_contig(ptr, size); + free_dma_memory(ptr, size); } static void bad_read1(void) @@ -723,19 +778,28 @@ static void bad_read2(void) cpf_revoke(grant); /* Test word-unaligned position. */ - memcpy(iov, iovt, sizeof(iovt)); + /* Only perform this test if the minimum read size is not 1, in which + * case it is safe to assume that the driver expects no position + * alignment either. These tests are indeed not exhaustive yet. For now + * we assume that if no alignment is required at all, the driver does + * not implement special logic to achieve this, so we don't need to + * test all possible positions and sizes either (yes, laziness..). + */ + if (min_read > 1) { + memcpy(iov, iovt, sizeof(iovt)); - buf_sum = fill_rand(buf_ptr, buf_size); - buf2_sum = fill_rand(buf2_ptr, buf2_size); - buf3_sum = fill_rand(buf3_ptr, buf3_size); + buf_sum = fill_rand(buf_ptr, buf_size); + buf2_sum = fill_rand(buf2_ptr, buf2_size); + buf3_sum = fill_rand(buf3_ptr, buf3_size); - raw_xfer(driver_minor, 1ULL, iov, 3, FALSE, EINVAL, &res); + raw_xfer(driver_minor, 1ULL, iov, 3, FALSE, EINVAL, &res); - test_sum(buf_ptr, buf_size, buf_sum, TRUE, &res); - test_sum(buf2_ptr, buf2_size, buf2_sum, TRUE, &res); - test_sum(buf3_ptr, buf3_size, buf3_sum, TRUE, &res); + test_sum(buf_ptr, buf_size, buf_sum, TRUE, &res); + test_sum(buf2_ptr, buf2_size, buf2_sum, TRUE, &res); + test_sum(buf3_ptr, buf3_size, buf3_sum, TRUE, &res); - got_result(&res, "word-unaligned position"); + got_result(&res, "word-unaligned position"); + } /* Test normal vector request (final check). */ memcpy(iov, iovt, sizeof(iovt)); @@ -759,16 +823,14 @@ static void bad_read2(void) free_buf_and_grant(buf_ptr, buf_grant, buf_size); } -#define SECTOR_UNALIGN 2ULL /* word-aligned and sector-unaligned */ - static void bad_write(void) { /* Test various illegal write transfer requests, if writing is allowed. * If handled correctly, these requests will not actually write data. - * However, the last test currently erroneously does end up writing. + * This part of the test set is in need of further expansion. */ u8_t *buf_ptr, *buf2_ptr, *buf3_ptr; - size_t buf_size, buf2_size, buf3_size; + size_t buf_size, buf2_size, buf3_size, sector_unalign; cp_grant_id_t buf_grant, buf2_grant, buf3_grant; cp_grant_id_t grant; u32_t buf_sum, buf2_sum, buf3_sum; @@ -793,36 +855,49 @@ static void bad_write(void) iovt[2].iov_grant = buf3_grant; iovt[2].iov_size = buf3_size; - /* Test sector-unaligned write position. */ - memcpy(iov, iovt, sizeof(iovt)); + /* Only perform write alignment tests if writes require alignment. */ + if (min_write == 0) + min_write = sector_size; - buf_sum = fill_rand(buf_ptr, buf_size); - buf2_sum = fill_rand(buf2_ptr, buf2_size); - buf3_sum = fill_rand(buf3_ptr, buf3_size); + if (min_write > 1) { + /* If min_write is larger than 2, use 2 as sector-unaligned + * size, as word-unaligned values (e.g., 1) may be filtered out + * on another code path. + */ + sector_unalign = (min_write > 2) ? 2 : 1; - raw_xfer(driver_minor, SECTOR_UNALIGN, iov, 3, TRUE, EINVAL, &res); + /* Test sector-unaligned write position. */ + memcpy(iov, iovt, sizeof(iovt)); - test_sum(buf_ptr, buf_size, buf_sum, TRUE, &res); - test_sum(buf2_ptr, buf2_size, buf2_sum, TRUE, &res); - test_sum(buf3_ptr, buf3_size, buf3_sum, TRUE, &res); + buf_sum = fill_rand(buf_ptr, buf_size); + buf2_sum = fill_rand(buf2_ptr, buf2_size); + buf3_sum = fill_rand(buf3_ptr, buf3_size); - got_result(&res, "sector-unaligned write position"); + raw_xfer(driver_minor, (u64_t)sector_unalign, iov, 3, TRUE, + EINVAL, &res); - /* Test sector-unaligned write size. */ - memcpy(iov, iovt, sizeof(iovt)); - iov[1].iov_size -= SECTOR_UNALIGN; + test_sum(buf_ptr, buf_size, buf_sum, TRUE, &res); + test_sum(buf2_ptr, buf2_size, buf2_sum, TRUE, &res); + test_sum(buf3_ptr, buf3_size, buf3_sum, TRUE, &res); - buf_sum = fill_rand(buf_ptr, buf_size); - buf2_sum = fill_rand(buf2_ptr, buf2_size); - buf3_sum = fill_rand(buf3_ptr, buf3_size); + got_result(&res, "sector-unaligned write position"); - raw_xfer(driver_minor, 0ULL, iov, 3, TRUE, EINVAL, &res); + /* Test sector-unaligned write size. */ + memcpy(iov, iovt, sizeof(iovt)); + iov[1].iov_size -= sector_unalign; - test_sum(buf_ptr, buf_size, buf_sum, TRUE, &res); - test_sum(buf2_ptr, buf2_size, buf2_sum, TRUE, &res); - test_sum(buf3_ptr, buf3_size, buf3_sum, TRUE, &res); + buf_sum = fill_rand(buf_ptr, buf_size); + buf2_sum = fill_rand(buf2_ptr, buf2_size); + buf3_sum = fill_rand(buf3_ptr, buf3_size); - got_result(&res, "sector-unaligned write size"); + raw_xfer(driver_minor, 0ULL, iov, 3, TRUE, EINVAL, &res); + + test_sum(buf_ptr, buf_size, buf_sum, TRUE, &res); + test_sum(buf2_ptr, buf2_size, buf2_sum, TRUE, &res); + test_sum(buf3_ptr, buf3_size, buf3_sum, TRUE, &res); + + got_result(&res, "sector-unaligned write size"); + } /* Test write-only grant in iovec element. */ memcpy(iov, iovt, sizeof(iovt)); @@ -873,10 +948,8 @@ static void vector_and_large_sub(size_t small_size) buf_size = large_size + sizeof(u32_t) * 2; buf2_size = large_size + sizeof(u32_t) * (NR_IOREQS + 1); - buf_ptr = alloc_contig(buf_size, 0, NULL); - buf2_ptr = alloc_contig(buf2_size, 0, NULL); - if (buf_ptr == NULL || buf2_ptr == NULL) - panic("unable to allocate memory"); + buf_ptr = alloc_dma_memory(buf_size); + buf2_ptr = alloc_dma_memory(buf2_size); /* The first buffer has one large chunk with dword-sized guards on each * side. LPTR(n) points to the start of the nth small data chunk within @@ -980,8 +1053,8 @@ static void vector_and_large_sub(size_t small_size) #undef SPTR /* Clean up. */ - free_contig(buf2_ptr, buf2_size); - free_contig(buf_ptr, buf_size); + free_dma_memory(buf2_ptr, buf2_size); + free_dma_memory(buf_ptr, buf_size); } static void vector_and_large(void) @@ -993,6 +1066,12 @@ static void vector_and_large(void) */ size_t max_block; + /* Make sure that the maximum size does not exceed the target device + * size, minus the margins we need for testing here and there. + */ + if (max_size > part.size - sector_size * 4) + max_size = part.size - sector_size * 4; + /* Compute the largest sector multiple which, when multiplied by * NR_IOREQS, is no more than the maximum transfer size. Note that if * max_size is not a multiple of sector_size, we're not going up to the @@ -1025,7 +1104,7 @@ static void open_device(dev_t minor) memset(&m, 0, sizeof(m)); m.m_type = BDEV_OPEN; m.BDEV_MINOR = minor; - m.BDEV_ACCESS = may_write ? (R_BIT | W_BIT) : R_BIT; + m.BDEV_ACCESS = may_write ? (BDEV_R_BIT | BDEV_W_BIT) : BDEV_R_BIT; m.BDEV_ID = lrand48(); sendrec_driver(&m, OK, &res); @@ -1090,10 +1169,9 @@ static int vir_ioctl(dev_t minor, int req, void *ptr, ssize_t exp, memset(&m, 0, sizeof(m)); m.m_type = BDEV_IOCTL; m.BDEV_MINOR = minor; - m.BDEV_POS_LO = 0L; - m.BDEV_POS_HI = 0L; m.BDEV_REQUEST = req; m.BDEV_GRANT = grant; + m.BDEV_USER = NONE; m.BDEV_ID = lrand48(); r = sendrec_driver(&m, exp, res); @@ -1120,7 +1198,7 @@ static void misc_ioctl(void) /* The other tests do not check whether there is sufficient room. */ if (res.type == RESULT_OK && part.size < (u64_t)max_size * 2) - printf("WARNING: small partition, some tests may fail\n"); + output("WARNING: small partition, some tests may fail\n"); /* Test retrieving global driver open count. */ openct = 0x0badcafe; @@ -1176,9 +1254,7 @@ static void read_limits(dev_t sub0_minor, dev_t sub1_minor, size_t sub_size) test_group("read around subpartition limits", TRUE); buf_size = sector_size * 3; - - if ((buf_ptr = alloc_contig(buf_size, 0, NULL)) == NULL) - panic("unable to allocate memory"); + buf_ptr = alloc_dma_memory(buf_size); /* Read one sector up to the partition limit. */ fill_rand(buf_ptr, buf_size); @@ -1274,7 +1350,7 @@ static void read_limits(dev_t sub0_minor, dev_t sub1_minor, size_t sub_size) got_result(&res, "read with negative offset"); /* Clean up. */ - free_contig(buf_ptr, buf_size); + free_dma_memory(buf_ptr, buf_size); } static void write_limits(dev_t sub0_minor, dev_t sub1_minor, size_t sub_size) @@ -1296,9 +1372,7 @@ static void write_limits(dev_t sub0_minor, dev_t sub1_minor, size_t sub_size) return; buf_size = sector_size * 3; - - if ((buf_ptr = alloc_contig(buf_size, 0, NULL)) == NULL) - panic("unable to allocate memory"); + buf_ptr = alloc_dma_memory(buf_size); /* Write to the start of the second subpartition, so that we can * reliably check whether the contents have changed later. @@ -1415,7 +1489,7 @@ static void write_limits(dev_t sub0_minor, dev_t sub1_minor, size_t sub_size) got_result(&res, "read up to partition end"); /* Clean up. */ - free_contig(buf_ptr, buf_size); + free_dma_memory(buf_ptr, buf_size); } static void vir_limits(dev_t sub0_minor, dev_t sub1_minor, int part_secs) @@ -1510,9 +1584,7 @@ static void real_limits(dev_t sub0_minor, dev_t sub1_minor, int part_secs) * anyway. */ buf_size = sector_size; - - if ((buf_ptr = alloc_contig(buf_size, 0, NULL)) == NULL) - panic("unable to allocate memory"); + buf_ptr = alloc_dma_memory(buf_size); memset(buf_ptr, 0, buf_size); @@ -1621,7 +1693,7 @@ static void real_limits(dev_t sub0_minor, dev_t sub1_minor, int part_secs) close_device(sub0_minor); close_device(sub1_minor); - free_contig(buf_ptr, buf_size); + free_dma_memory(buf_ptr, buf_size); } static void part_limits(void) @@ -1637,7 +1709,7 @@ static void part_limits(void) * cannot conduct this test. */ if (driver_minor >= MINOR_d0p0s0) { - printf("WARNING: operating on subpartition, " + output("WARNING: operating on subpartition, " "skipping partition tests\n"); return; } @@ -1858,14 +1930,9 @@ static void unaligned_size(void) base_pos = (u64_t)sector_size * 2; - if ((buf_ptr = alloc_contig(buf_size, 0, NULL)) == NULL) - panic("unable to allocate memory"); - - if ((sec_ptr[0] = alloc_contig(sector_size, 0, NULL)) == NULL) - panic("unable to allocate memory"); - - if ((sec_ptr[1] = alloc_contig(sector_size, 0, NULL)) == NULL) - panic("unable to allocate memory"); + buf_ptr = alloc_dma_memory(buf_size); + sec_ptr[0] = alloc_dma_memory(sector_size); + sec_ptr[1] = alloc_dma_memory(sector_size); if (may_write) { sum = fill_rand(buf_ptr, buf_size); @@ -1926,18 +1993,17 @@ static void unaligned_size(void) } /* Clean up. */ - free_contig(sec_ptr[1], sector_size); - free_contig(sec_ptr[0], sector_size); - free_contig(buf_ptr, buf_size); + free_dma_memory(sec_ptr[1], sector_size); + free_dma_memory(sec_ptr[0], sector_size); + free_dma_memory(buf_ptr, buf_size); } static void unaligned_pos1(void) { /* Test sector-unaligned positions and total sizes for requests. This - * is a read-only test as no driver currently supports sector-unaligned - * writes. In this context, the term "lead" means an unwanted first - * part of a sector, and "trail" means an unwanted last part of a - * sector. + * is a read-only test for now. Write support should be added later. + * In the current context, the term "lead" means an unwanted first part + * of a sector, and "trail" means an unwanted last part of a sector. */ u8_t *buf_ptr, *buf2_ptr; size_t buf_size, buf2_size, size; @@ -1963,11 +2029,8 @@ static void unaligned_pos1(void) base_pos = (u64_t)sector_size * 3; - if ((buf_ptr = alloc_contig(buf_size, 0, NULL)) == NULL) - panic("unable to allocate memory"); - - if ((buf2_ptr = alloc_contig(buf2_size, 0, NULL)) == NULL) - panic("unable to allocate memory"); + buf_ptr = alloc_dma_memory(buf_size); + buf2_ptr = alloc_dma_memory(buf2_size); if (may_write) { sum = fill_rand(buf_ptr, buf_size); @@ -2080,8 +2143,8 @@ static void unaligned_pos1(void) got_result(&res, "multisector read with lead and trail"); /* Clean up. */ - free_contig(buf2_ptr, buf2_size); - free_contig(buf_ptr, buf_size); + free_dma_memory(buf2_ptr, buf2_size); + free_dma_memory(buf_ptr, buf_size); } static void unaligned_pos2(void) @@ -2111,11 +2174,8 @@ static void unaligned_pos2(void) base_pos = (u64_t)sector_size * 3; - if ((buf_ptr = alloc_contig(buf_size, 0, NULL)) == NULL) - panic("unable to allocate memory"); - - if ((buf2_ptr = alloc_contig(buf2_size, 0, NULL)) == NULL) - panic("unable to allocate memory"); + buf_ptr = alloc_dma_memory(buf_size); + buf2_ptr = alloc_dma_memory(buf2_size); /* First establish a baseline. We need two requests for this, as the * total area intentionally exceeds the max request size. @@ -2224,8 +2284,8 @@ static void unaligned_pos2(void) got_result(&res, "large fully unaligned filled vector"); /* Clean up. */ - free_contig(buf2_ptr, buf2_size); - free_contig(buf_ptr, buf_size); + free_dma_memory(buf2_ptr, buf2_size); + free_dma_memory(buf_ptr, buf_size); } static void sweep_area(u64_t base_pos) @@ -2241,9 +2301,7 @@ static void sweep_area(u64_t base_pos) int i, j; buf_size = sector_size * 8; - - if ((buf_ptr = alloc_contig(buf_size, 0, NULL)) == NULL) - panic("unable to allocate memory"); + buf_ptr = alloc_dma_memory(buf_size); /* First (write to, if allowed, and) read from the entire area in one * go, so that we know the (initial) contents of the area. @@ -2316,7 +2374,7 @@ static void sweep_area(u64_t base_pos) } /* Clean up. */ - free_contig(buf_ptr, buf_size); + free_dma_memory(buf_ptr, buf_size); } static void sweep_and_check(u64_t pos, int check_integ) @@ -2333,9 +2391,7 @@ static void sweep_and_check(u64_t pos, int check_integ) if (check_integ) { buf_size = sector_size * 3; - - if ((buf_ptr = alloc_contig(buf_size, 0, NULL)) == NULL) - panic("unable to allocate memory"); + buf_ptr = alloc_dma_memory(buf_size); if (may_write) { sum = fill_rand(buf_ptr, buf_size); @@ -2371,7 +2427,7 @@ static void sweep_and_check(u64_t pos, int check_integ) got_result(&res, "check integrity zone"); - free_contig(buf_ptr, buf_size); + free_dma_memory(buf_ptr, buf_size); } } @@ -2633,7 +2689,20 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info)) srand48(now); - return OK; + output("BLOCKTEST: driver label '%s' (endpt %d), minor %d\n", + driver_label, driver_endpt, driver_minor); + + do_tests(); + + output("BLOCKTEST: summary: %d out of %d tests failed " + "across %d group%s; %d driver deaths\n", + failed_tests, total_tests, failed_groups, + failed_groups == 1 ? "" : "s", driver_deaths); + + /* The returned code will determine the outcome of the RS call, and + * thus the entire test. The actual error code does not matter. + */ + return (failed_tests) ? EINVAL : OK; } static void sef_local_startup(void) @@ -2654,15 +2723,5 @@ int main(int argc, char **argv) env_setargs(argc, argv); sef_local_startup(); - printf("BLOCKTEST: driver label '%s' (endpt %d), minor %d\n", - driver_label, driver_endpt, driver_minor); - - do_tests(); - - printf("BLOCKTEST: summary: %d out of %d tests failed " - "across %d group%s; %d driver deaths\n", - failed_tests, total_tests, failed_groups, - failed_groups == 1 ? "" : "s", driver_deaths); - return 0; } diff --git a/test/blocktest/test.sh b/test/blocktest/test.sh index ad550b146..bd48dd132 100755 --- a/test/blocktest/test.sh +++ b/test/blocktest/test.sh @@ -22,15 +22,17 @@ # on other partitions and possibly other disks) WILL BE DESTROYED. # Use "ro" for read-only mediums, such as CD-ROMs. # sector Sector size, in bytes. This should be 512 for ATA devices, and -# 2048 for ATAPI devices. -# min_read Minimum size of a read request. This must be at least 2 and at +# 2048 for ATAPI devices. The default is 512. +# min_read Minimum size of a read request. This must be at least 1 and at # most the sector size, and the sector size must be divisible by # it. A value other than the sector size allows blocktest to test -# sub-sector reads. Sub-sector writes are currently not supported -# by any driver and hence not by blocktest, so there is no -# matching "min_write" (yet). +# sub-sector reads. +# min_write Minimum size of a write request. This must be at least 1 and at +# most the sector size. Sub-sector write support is not common in +# drivers, and therefore not yet well tested by blocktest. This +# parameter is optional; if omitted, the sector size is used. # element Minimum size of a vector element within a larger I/O request. -# This must be at least 2 and at most min_read, and min_read must +# This must be at least 1 and at most min_read, and min_read must # be divisible by this value. The idea is that several small # elements may add up to the minimum read size. # max Maximum size of any request. This should be a multiple of the @@ -60,3 +62,7 @@ # AHCI ATAPI TEST (for SATA CD-ROM devices) #block_test /dev/c2d1 "ro,sector=2048,min_read=2,element=2,max=4194304" + +# VND TEST (for configured vnode disk devices) + +#block_test /dev/vnd0 "rw,min_read=1,min_write=1,element=1,max=16777216" diff --git a/test/run b/test/run index 453126e08..667c63e58 100755 --- a/test/run +++ b/test/run @@ -17,15 +17,19 @@ skipped=`expr 0` # count number of tests that were skipped total=`expr 0` # total number of tests tried badones= # list of tests that failed -# Tests which require setuid +# In the lists below, shell scripts should be listed without ".sh" suffix + +# Programs that require setuid setuids="test11 test33 test43 test44 test46 test56 test60 test61 test65 \ - test69" # test73" + test69 test76 test77" # test73" +# Scripts that require to be run as root +rootscripts="testvnd" alltests=" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \ 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \ 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 \ - 61 62 63 64 65 66 67 68 69 70 71 72 75 \ - sh1.sh sh2.sh interp.sh" + 61 62 63 64 65 66 67 68 69 70 71 72 75 76 77 \ + sh1 sh2 interp vnd" tests_no=`expr 0` # test mmap only if enabled in sysenv @@ -71,7 +75,7 @@ done # Count tests for i in `echo $tests`; do - if [ -x ./test$i ]; then + if [ -x ./test$i -o -x ./test${i}.sh ]; then tests_no=`expr $tests_no + 1` fi done @@ -103,9 +107,27 @@ ARGS_63=`pwd`/mod runtest() { i=$1 ARG=$2 + # setuid doesn't work with scripts, so we can only run those as root + if echo "$rootscripts" | tr ' ' '\n' | grep "^test${i}\$" >/dev/null + then needroot=1 + else needroot=0 + fi + # depending on where we are, scripts might have a .sh suffix or not + if [ -x test${i}.sh ] + then NAME=./test${i}.sh + else NAME=./test$i + fi if [ "$ROOT" ] - then su - bin -c "cd `pwd`; ./test$i $ARG" || return 1 - else ./test$i $ARG || return 1 + then + if [ $needroot -eq 1 ] + then $NAME $ARG || return 1 + else su - bin -c "cd `pwd`; $NAME $ARG" || return 1 + fi + else + if [ $needroot -eq 1 ] + then echo "skipping test$i, not root" >&2 && return 0 + else $NAME $ARG || return 1 + fi fi return 0 } @@ -113,13 +135,11 @@ runtest() { # Run all the tests, keeping track of who failed. for i in `echo $tests` do - if [ -x ./test$i ] + if [ -x ./test$i -o -x ./test${i}.sh ] then total=`expr $total + 1` FAIL=0 - unset ARG - testid="`echo $i | sed 's/\..*//'`" - ARG=`eval echo "\\${ARGS_$testid}"` + ARG=`eval echo "\\${ARGS_$i}"` if [ "$tapmode" ] then out=out.$$ diff --git a/test/select/Makefile b/test/select/Makefile deleted file mode 100644 index 5b776dec3..000000000 --- a/test/select/Makefile +++ /dev/null @@ -1,39 +0,0 @@ -# Makefile for the tests - -CC = exec cc -CFLAGS = -Wall - -PROG = speed test00 test01 test02 test03 test04_srv test04_cli test05_srv \ - test05_cli test06_srv test06_cli test07_srv test07_cli test08_srv \ - test08_cli test09 test10 test11 test12 test13a test13b test14 - -all: $(PROG) - -$(PROG): - $(CC) $(CFLAGS) -o $@ $@.c -lutil - -clean: - rm -f *.o $(PROG) - -speed: speed.c -test00: test00.c -test01: test01.c -test02: test02.c -test03: test03.c -test04_cli: test04_cli.c -test04_srv: test04_srv.c -test05_cli: test05_cli.c -test05_srv: test05_srv.c -test06_cli: test06_cli.c -test06_srv: test06_srv.c -test07_cli: test07_cli.c -test07_srv: test07_srv.c -test08_cli: test08_cli.c -test08_srv: test08_srv.c -test09: test09.c -test10: test10.c -test11: test11.c -test12: test12.c -test13a: test13a.c -test13b: test13b.c -test14: test14.c diff --git a/test/select/speed.c b/test/select/speed.c deleted file mode 100644 index 46956b181..000000000 --- a/test/select/speed.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Test name: speed.c - * - * Objetive: Test the time it takes for select to run. - * - * Description: This tests creates a number of udp connections and performs - * a select call waiting on them for reading with timeout of 0. - * This is done 10,000 thousands of times and then the average time it takes - * is computed - * - * Jose M. Gomez - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define NUMBER 12 - -int main(int argc, char *argv[]) -{ - char *udp_device; - int fd[NUMBER]; - fd_set fds_write; - struct timeval timeout; - time_t start_time, end_time; - int i; - - FD_ZERO(&fds_write); - for (i = 0; i < NUMBER; i++) { - fd[i] = open("/dev/tty", O_RDWR); - if (fd[i] < 0) { - fprintf(stderr, "Error opening tty %d\n", i); - exit(-1); - } - FD_SET(fd[i], &fds_write); - } - - printf("Select will send 1 msg to terminal and %d to inet: \n", NUMBER); - timeout.tv_sec = 0; - timeout.tv_usec = 0; - /* get initial time */ - start_time = time(NULL); - for (i = 0; i < 32000; i++) { - select(NUMBER + 4, NULL, &fds_write, NULL, &timeout); - } - /* get final time */ - end_time = time(NULL); - printf("The select call took on average: %f\n", (float)(end_time - start_time) / 32000.0); - for (i = 0; i < NUMBER; i++) { - close(fd[i]); - } - return 0; -} diff --git a/test/select/test00.c b/test/select/test00.c deleted file mode 100644 index f25a9cd8c..000000000 --- a/test/select/test00.c +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Test name: test00.c - * - * Objetive: The purpose of this test is to make sure that the bitmap - * manipulation macros work without problems. - * - * Description: This tests first fills a fd_set bit by bit, and shows it, then - * it clears the fd_set bit by bit as well. - * - * Jose M. Gomez - */ - -#include -#include -#include -#include -#include -#include -#include - -int main(int argc, char *argv[]) { - fd_set fds; - int i,j; - - FD_ZERO(&fds); - for (i=0;i -#include -#include -#include -#include -#include -#include - -#define SECONDS 3 -#define USECONDS 3000000L - -int main(void) { - int r; - time_t start, end; /* variables for timing */ - struct timeval timeout; /* timeout structure */ - - /* Set timeout for 3 seconds */ - timeout.tv_sec = SECONDS; - timeout.tv_usec = 0; - printf("Sleeping now for %d seconds...\n", SECONDS); - /* Record time before starting */ - start = time(NULL); - r = select(0, NULL, NULL, NULL, &timeout); - printf("select return code: %d error: %s\n", - r, strerror(errno)); - end = time(NULL); - printf("For a timeout with select of %d seconds, it took %d actual seconds\n", - SECONDS, end-start); - - /* Set timeout for 3 seconds , but specified in microseconds */ - - timeout.tv_sec = 0; - timeout.tv_usec = USECONDS; - printf("\n***************************\n"); - printf("Sleeping now for %ld microseconds...\n", USECONDS); - /* Record time before starting */ - start = time(NULL); - r = select(0, NULL, NULL, NULL, &timeout); - printf("select return code: %d error: %s\n", - r, strerror(errno)); - end = time(NULL); - printf("For a timeout with select of %ld useconds, it took %d actual seconds\n", - USECONDS, end-start); - - /* Set timeout for 1.5 seconds, but specified in microseconds */ - - timeout.tv_sec = 0; - timeout.tv_usec = USECONDS/2; - printf("\n***************************\n"); - printf("Sleeping now for %ld microseconds...\n", USECONDS/2); - /* Record time before starting */ - start = time(NULL); - r = select(0, NULL, NULL, NULL, &timeout); - printf("select return code: %d error: %s\n", - r, strerror(errno)); - end = time(NULL); - printf("For a timeout with select of %ld useconds, it took %d actual seconds\n", - USECONDS/2, end-start); - return 0; -} diff --git a/test/select/test02.c b/test/select/test02.c deleted file mode 100644 index 338565734..000000000 --- a/test/select/test02.c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Test name: test02.c - * - * Objetive: The purpose of this test is to make sure that select works - * when working with files. - * - * Description: This tests first creates six dummy files with different - * modes and performs select calls on them evaluating the input and resulting - * bitmaps. - * - * Jose M. Gomez - */ - -#include -#include -#include -#include -#include -#include -#include - -void dump_fdset(fd_set *set) { - int i; - for (i = 0; i < OPEN_MAX; i++) - if (FD_ISSET(i, set)) - printf(" %d->1 ", i); - else - printf(" %d->0 ", i); - printf("\n"); -} - -int main(int argc, char *argv[]) -{ - int fd1, fd2, fd3, fd4, fd5, fd6; /* file descriptors of files */ - fd_set fds_read, fds_write; - int retval; - - /* Creates the dummy files with different modes */ - fd1 = open("dummy1.txt", O_CREAT | O_RDONLY); - if (fd1 < 0) { - perror("Error opening file"); - exit(-1); - } - - fd2 = open("dummy2.txt", O_CREAT | O_RDONLY); - if (fd2 < 0) { - perror("Error opening file"); - exit(-1); - } - - fd3 = open("dummy3.txt", O_CREAT | O_WRONLY); - if (fd3 < 0) { - perror("Error opening file"); - exit(-1); - } - - fd4 = open("dummy4.txt", O_CREAT | O_WRONLY); - if (fd4 < 0) { - perror("Error opening file"); - exit(-1); - } - - fd5 = open("dummy5.txt", O_CREAT | O_RDWR); - if (fd5 < 0) { - perror("Error opening file"); - exit(-1); - } - - fd6 = open("dummy6.txt", O_CREAT | O_RDWR); - if (fd6 < 0) { - perror("Error opening file"); - exit(-1); - } - - /* Create the fd_set structures */ - FD_ZERO(&fds_read); - FD_ZERO(&fds_write); - FD_SET(fd1, &fds_read); /* fd1 => O_RDONLY */ - FD_SET(fd2, &fds_read); /* fd2 => O_RDONLY */ - FD_SET(fd3, &fds_write); /* fd3 => O_WRONLY */ - FD_SET(fd4, &fds_write); /* fd4 => O_WRONLY */ - FD_SET(fd5, &fds_read); /* fd5 => O_RDWR */ - FD_SET(fd5, &fds_write); /* fd5 => O_RDWR */ - FD_SET(fd6, &fds_read); /* fd6 => O_RDWR */ - FD_SET(fd6, &fds_write); /* fd6 => O_RDWR */ - - printf("* Dump INPUT fds_read:\n"); - dump_fdset(&fds_read); - printf("* Dump INPUT fds_write:\n"); - dump_fdset(&fds_write); - - retval=select(9, &fds_read, &fds_write, NULL, NULL); - printf("\n***********************\n"); - printf("After select: \n"); - printf("Return value: %d\n", retval); - printf("* Dump RESULTING fds_read:\n"); - dump_fdset(&fds_read); - printf("* Dump RESULTING fds_write:\n"); - dump_fdset(&fds_write); - /* close and delete dummy files */ - close(fd1); - close(fd2); - close(fd3); - close(fd4); - close(fd5); - close(fd6); - unlink("dummy1.txt"); - unlink("dummy2.txt"); - unlink("dummy3.txt"); - unlink("dummy4.txt"); - unlink("dummy5.txt"); - unlink("dummy6.txt"); - return 0; -} diff --git a/test/select/test03.c b/test/select/test03.c deleted file mode 100644 index 14e2eba8d..000000000 --- a/test/select/test03.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Test name: test03.c - * - * Objetive: The purpose of this test is to make sure that select works - * when working with files. - * - * Description: This test shows more cases than in test02.c, where every - * descriptor is ready. Here in one select call only half of the fd's will - * be ready and in the next one none of them will be ready. - * - * Jose M. Gomez - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -void dump_fdset(fd_set *set) { - int i; - for (i = 0; i < OPEN_MAX; i++) - if (FD_ISSET(i, set)) - printf(" %d ", i); - printf("\n"); -} - -int main(int argc, char *argv[]) -{ - int fd1, fd2, fd3, fd4, fd5, fd6; /* file descriptors of files */ - fd_set fds_read, fds_write; /* bit maps */ - struct timeval timeout; /* timeout */ - int retval; /* ret value */ - - /* Creates the dummy files with different modes */ - fd1 = open("dummy1.txt", O_CREAT | O_RDONLY); - if (fd1 < 0) { - perror("Error opening file"); - exit(-1); - } - - fd2 = open("dummy2.txt", O_CREAT | O_RDONLY); - if (fd2 < 0) { - perror("Error opening file"); - exit(-1); - } - - fd3 = open("dummy3.txt", O_CREAT | O_WRONLY); - if (fd3 < 0) { - perror("Error opening file"); - exit(-1); - } - - fd4 = open("dummy4.txt", O_CREAT | O_WRONLY); - if (fd4 < 0) { - perror("Error opening file"); - exit(-1); - } - - fd5 = open("dummy5.txt", O_CREAT | O_RDWR); - if (fd5 < 0) { - perror("Error opening file"); - exit(-1); - } - - fd6 = open("dummy6.txt", O_CREAT | O_RDWR); - if (fd6 < 0) { - perror("Error opening file"); - exit(-1); - } - - /* Create the fd_set structures */ - FD_ZERO(&fds_read); - FD_ZERO(&fds_write); - FD_SET(fd1, &fds_write); /* fd1 => O_RDONLY */ - FD_SET(fd2, &fds_write); /* fd2 => O_RDONLY */ - FD_SET(fd3, &fds_read); /* fd3 => O_WRONLY */ - FD_SET(fd4, &fds_read); /* fd4 => O_WRONLY */ - FD_SET(fd5, &fds_read); /* fd5 => O_RDWR */ - FD_SET(fd5, &fds_write); /* fd5 => O_RDWR */ - FD_SET(fd6, &fds_read); /* fd6 => O_RDWR */ - FD_SET(fd6, &fds_write); /* fd6 => O_RDWR */ - - printf("* Dump INPUT fds_read:\n"); - dump_fdset(&fds_read); - printf("* Dump INPUT fds_write:\n"); - dump_fdset(&fds_write); - - retval=select(9, &fds_read, &fds_write, NULL, NULL); - printf("\n***********************\n"); - printf("After select: \n"); - printf("Return value: %d\n", retval); - printf("* Dump RESULTING fds_read:\n"); - dump_fdset(&fds_read); - printf("* Dump RESULTING fds_write:\n"); - dump_fdset(&fds_write); - - /* make a select call where none of them are ready (don't use fd5 and fd6) */ - - FD_ZERO(&fds_read); - FD_ZERO(&fds_write); - FD_SET(fd1, &fds_write); /* fd1 => O_RDONLY */ - FD_SET(fd2, &fds_write); /* fd2 => O_RDONLY */ - FD_SET(fd3, &fds_read); /* fd3 => O_WRONLY */ - FD_SET(fd4, &fds_read); /* fd4 => O_WRONLY */ - - /* make a select call where none of them are ready (don't use fd5 and fd6) */ - /* create a timeout as well */ - timeout.tv_sec = 5; - timeout.tv_usec = 0; - retval=select(7, &fds_read, &fds_write, NULL, NULL); - printf("\n***********************\n"); - printf("After select: \n"); - printf("Return value: %d\n", retval); - printf("* Dump RESULTING fds_read:\n"); - dump_fdset(&fds_read); - printf("* Dump RESULTING fds_write:\n"); - dump_fdset(&fds_write); - - /* close and delete dummy files */ - close(fd1); - close(fd2); - close(fd3); - close(fd4); - close(fd5); - close(fd6); - unlink("dummy1.txt"); - unlink("dummy2.txt"); - unlink("dummy3.txt"); - unlink("dummy4.txt"); - unlink("dummy5.txt"); - unlink("dummy6.txt"); - return 0; -} diff --git a/test/select/test04_cli.c b/test/select/test04_cli.c deleted file mode 100644 index db92f930c..000000000 --- a/test/select/test04_cli.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Test name: test04_cli.c - * - * Objective: Test a simple UDP client - * - * Description: Implements a simple echo client using the UDP protocol. First - * it waits until it is possible to write (which is always). - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PORT 6000L - -/* Type for received data */ -typedef struct -{ - udp_io_hdr_t header; - char data[1024]; -} udp_buffer_t; - -int udp_conf(char *host, long port, udp_io_hdr_t *header) -{ - /* configures UDP connection */ - char *udp_device; - struct hostent *hp; - int netfd; - nwio_udpopt_t udpopt; - ipaddr_t dirhost; - int result; - - /* get host address */ - if ((hp = gethostbyname(host)) == (struct hostent*) NULL) - { - fprintf(stderr,"Unknown host\n"); - return(-1); - } - memcpy((char *)&dirhost, (char *)hp->h_addr, hp->h_length); - - /* Get UDP device */ - if (( udp_device = getenv("UDP_DEVICE") ) == NULL) - udp_device = UDP_DEVICE; - - /* Get UDP connection */ - if ((netfd = open(udp_device, O_RDWR)) < 0) - { - fprintf(stderr,"Error opening UDP device\n"); - return -1; - } - - /* Configure UDP connection */ - udpopt.nwuo_flags = NWUO_COPY | NWUO_LP_SEL | NWUO_EN_LOC | NWUO_DI_BROAD - | NWUO_RP_SET | NWUO_RA_SET | NWUO_RWDATALL | NWUO_DI_IPOPT; - udpopt.nwuo_remaddr = dirhost; - udpopt.nwuo_remport = (udpport_t) htons(port); - - if ((result = ioctl(netfd, NWIOSUDPOPT, &udpopt) ) <0) - { - fprintf(stderr, "Error establishing communication\n"); - printf("Error: %d\n",result); - close(netfd); - return -1; - } - - /* Get configuration for UDP comm */ - if ((result = ioctl(netfd, NWIOGUDPOPT, &udpopt) ) < 0) - { - fprintf(stderr,"Error getting configuration\n"); - printf("Error: %d\n", result); - close(netfd); - return -1; - } - - header->uih_src_addr = udpopt.nwuo_locaddr; - header->uih_dst_addr = udpopt.nwuo_remaddr; - header->uih_src_port = udpopt.nwuo_locport; - header->uih_dst_port = udpopt.nwuo_remport; - - return netfd; -} - -int main(int argc,char *argv[]) { - int fd; - ssize_t data_read; - udp_buffer_t buffer_send, buffer_rec; - fd_set fds_write; - int ret; - - /* Check parameters */ - if (argc !=2) { - fprintf(stderr,"Usage: %s host\n", argv[0]); - exit(-1); - } - - if ((fd = udp_conf(argv[1], PORT, &buffer_send.header) ) < 0) - exit(-1); - - /* init fd_set */ - FD_ZERO(&fds_write); - FD_SET(fd, &fds_write); - - while (1) - { - /* Wait until it is possible to write with select */ - - ret = select(4, NULL, &fds_write, NULL, NULL); - if (ret < 0) { - fprintf(stderr, "Error on select waiting for write: %d\n", errno); - exit(-1); - } - if (!FD_ISSET(fd, &fds_write)) { - fprintf(stderr, "Error: The net connection is not ready for writing (?)\n"); - exit(-1); - } - - /* Get a string and send it */ - printf("Ready to write...\n"); - printf("Send data: "); - gets(buffer_send.data); - write(fd, &buffer_send, sizeof(udp_buffer_t)); - - /* If data sent is exit then break */ - if (!strcmp(buffer_send.data,"exit")) - break; - - /* Get server response */ - data_read = read(fd, &buffer_rec, sizeof(udp_buffer_t)); - printf("Received: %s\n\n", buffer_rec.data); - } - - /* Close UDP communication */ - close(fd); -} diff --git a/test/select/test04_srv.c b/test/select/test04_srv.c deleted file mode 100644 index b6fc6a5c4..000000000 --- a/test/select/test04_srv.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Test name: test04_srv.c - * - * Objective: Test a simple UDP server - * - * Description: Implements a simple echo server using the UDP protocol. Instead - * of blocking on read(), it performs a select call first blocking there - * until there is data to be read - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PORT 6000L - -/* type for received data */ -typedef struct -{ - udp_io_hdr_t header; - char data[1024]; -} udp_buffer_t; - -int udp_conf(long port) { - - char *udp_device; - int netfd; - nwio_udpopt_t udpopt; - - /* Get default UDP device */ - if ((udp_device = getenv("UDP_DEVICE")) == NULL) - udp_device = UDP_DEVICE; - - /* Open UDP connection */ - if ((netfd = open(udp_device, O_RDWR)) < 0) - { - fprintf(stderr,"Error opening UDP connection\n"); - return -1; - } - - /* Configure UDP connection */ - udpopt.nwuo_flags = NWUO_COPY | NWUO_LP_SET | NWUO_EN_LOC | NWUO_DI_BROAD - | NWUO_RP_ANY | NWUO_RA_ANY | NWUO_RWDATALL | NWUO_DI_IPOPT; - - udpopt.nwuo_locport = (udpport_t) htons(port); - - if ((ioctl(netfd, NWIOSUDPOPT, &udpopt))<0) - { - fprintf(stderr,"Error configuring the connection\n"); - close(netfd); - return -1; - } - - /* Get conf options */ - if ((ioctl(netfd, NWIOGUDPOPT, &udpopt))<0) - { - fprintf(stderr,"Error getting the conf\n"); - close(netfd); - return -1; - } - - return netfd; -} - -int main(int argc,char *argv[]) { - int fd; - ssize_t data_read; - udp_buffer_t buffer; - ipaddr_t tmp_addr; - udpport_t tmp_port; - int ret; - fd_set fds_read; - - if ((fd = udp_conf(PORT)) < 0) { - fprintf(stderr, "Error configuring UDP connection\n"); - exit(-1); - } - printf("Waiting for messages on port: %ld\n", PORT); - fflush(stdout); - /* Initialize fd_set */ - FD_ZERO(&fds_read); - FD_SET(fd, &fds_read); - - while (1) - { - /* Wait for data available to be read (no timeout) */ - ret = select(4, &fds_read, NULL, NULL, NULL); - if (ret < 0) { - fprintf(stderr, "Error on select: %d", errno); - exit(-1); - } - if (!FD_ISSET(fd, &fds_read)) { - printf("Error: network fd is not ready (?)\n"); - exit(-1); - } - printf("Ready to receive...\n"); - /* Read received data */ - data_read = read(fd, &buffer, sizeof(udp_buffer_t)); - printf("Received data: %s\n", buffer.data); - - /* Can exit if the received string == exit */ - if (!strcmp(buffer.data,"exit")) - break; - - /* Send data back, swap addresses */ - tmp_addr = buffer.header.uih_src_addr; - buffer.header.uih_src_addr = buffer.header.uih_dst_addr; - buffer.header.uih_dst_addr = tmp_addr; - - /* Swap ports */ - tmp_port = buffer.header.uih_src_port; - buffer.header.uih_src_port = buffer.header.uih_dst_port; - buffer.header.uih_dst_port = tmp_port; - - /* Write the same back */ - write(fd, &buffer, data_read); - } - - close(fd); -} diff --git a/test/select/test05_cli.c b/test/select/test05_cli.c deleted file mode 100644 index aad9bf0e6..000000000 --- a/test/select/test05_cli.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Test name: test05_cli.c - * - * Objective: Test a impatient UDP client with timeout and incoming data from - * network and terminal. - * - * Description: Implements a echo client using the UDP protocol. It is - * based on test04_cli, but the difference is that it uses timeout and waits - * for data both from terminal (stdin) and network connection. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PORT 6000L - -/* Type for received data */ -typedef struct -{ - udp_io_hdr_t header; - char data[1024]; -} udp_buffer_t; - -int udp_conf(char *host, long port, udp_io_hdr_t *header) -{ - /* configures UDP connection */ - char *udp_device; - struct hostent *hp; - int netfd; - nwio_udpopt_t udpopt; - ipaddr_t dirhost; - int result; - - /* get host address */ - if ((hp = gethostbyname(host)) == (struct hostent*) NULL) - { - fprintf(stderr,"Unknown host\n"); - return(-1); - } - memcpy((char *)&dirhost, (char *)hp->h_addr, hp->h_length); - - /* Get UDP device */ - if (( udp_device = getenv("UDP_DEVICE") ) == NULL) - udp_device = UDP_DEVICE; - - /* Get UDP connection */ - if ((netfd = open(udp_device, O_RDWR)) < 0) - { - fprintf(stderr,"Error opening UDP device\n"); - return -1; - } - - /* Configure UDP connection */ - udpopt.nwuo_flags = NWUO_COPY | NWUO_LP_SEL | NWUO_EN_LOC | NWUO_DI_BROAD - | NWUO_RP_SET | NWUO_RA_SET | NWUO_RWDATALL | NWUO_DI_IPOPT; - udpopt.nwuo_remaddr = dirhost; - udpopt.nwuo_remport = (udpport_t) htons(port); - - if ((result = ioctl(netfd, NWIOSUDPOPT, &udpopt) ) <0) - { - fprintf(stderr, "Error establishing communication\n"); - printf("Error: %d\n",result); - close(netfd); - return -1; - } - - /* Get configuration for UDP comm */ - if ((result = ioctl(netfd, NWIOGUDPOPT, &udpopt) ) < 0) - { - fprintf(stderr,"Error getting configuration\n"); - printf("Error: %d\n", result); - close(netfd); - return -1; - } - - header->uih_src_addr = udpopt.nwuo_locaddr; - header->uih_dst_addr = udpopt.nwuo_remaddr; - header->uih_src_port = udpopt.nwuo_locport; - header->uih_dst_port = udpopt.nwuo_remport; - - return netfd; -} - -int main(int argc,char *argv[]) { - int fd; - ssize_t data_read; - udp_buffer_t buffer_send, buffer_rec; - fd_set fds_read; - int ret; - struct timeval timeout; - - /* Check parameters */ - if (argc !=2) { - fprintf(stderr,"Usage: %s host\n", argv[0]); - exit(-1); - } - - if ((fd = udp_conf(argv[1], PORT, &buffer_send.header) ) < 0) - exit(-1); - - while (1) - { - - /* init fd_set */ - FD_ZERO(&fds_read); - FD_SET(0, &fds_read); - FD_SET(fd, &fds_read); - - /* set timeval */ - timeout.tv_sec = 5; - timeout.tv_usec = 0; - printf("Send data: "); - fflush(stdout); - /* Wait until it is possible to write with select */ - ret = select(4, &fds_read, NULL, NULL, &timeout); - if (ret < 0) { - fprintf(stderr, "Error on select waiting for read: %d\n", errno); - exit(-1); - } - if (ret == 0) { - printf("\nClient says: Hey! I want to send data!!\n"); - fflush(stdout); - continue; - } - /* if got message from server */ - if (FD_ISSET(fd, &fds_read)) { - data_read = read(fd, &buffer_rec, sizeof(udp_buffer_t)); - printf("Server says: %s\n\n", buffer_rec.data); - fflush(stdout); - } - /* if got data from terminal */ - if (FD_ISSET(0, &fds_read)) { - /* Get a string and send it */ - gets(buffer_send.data); - write(fd, &buffer_send, sizeof(udp_buffer_t)); - - /* If data sent is exit then break */ - if (!strcmp(buffer_send.data,"exit")) - break; - /* Get server response */ - data_read = read(fd, &buffer_rec, sizeof(udp_buffer_t)); - printf("Received: %s\n\n", buffer_rec.data); - fflush(stdout); - } - } - - /* Close UDP communication */ - close(fd); -} diff --git a/test/select/test05_srv.c b/test/select/test05_srv.c deleted file mode 100644 index a88526b28..000000000 --- a/test/select/test05_srv.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Test name: test05_srv.c - * - * Objective: Test an impatient UDP server with timeouts - * - * Description: Implements an echo server using the UDP protocol. It is - * based on test04_srv, but it has a timeout value. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PORT 6000L - -/* type for received data */ -typedef struct -{ - udp_io_hdr_t header; - char data[1024]; -} udp_buffer_t; - -int udp_conf(long port) { - - char *udp_device; - int netfd; - nwio_udpopt_t udpopt; - - /* Get default UDP device */ - if ((udp_device = getenv("UDP_DEVICE")) == NULL) - udp_device = UDP_DEVICE; - - /* Open UDP connection */ - if ((netfd = open(udp_device, O_RDWR)) < 0) - { - fprintf(stderr,"Error opening UDP connection\n"); - return -1; - } - - /* Configure UDP connection */ - udpopt.nwuo_flags = NWUO_COPY | NWUO_LP_SET | NWUO_EN_LOC | NWUO_DI_BROAD - | NWUO_RP_ANY | NWUO_RA_ANY | NWUO_RWDATALL | NWUO_DI_IPOPT; - - udpopt.nwuo_locport = (udpport_t) htons(port); - - if ((ioctl(netfd, NWIOSUDPOPT, &udpopt))<0) - { - fprintf(stderr,"Error configuring the connection\n"); - close(netfd); - return -1; - } - - /* Get conf options */ - if ((ioctl(netfd, NWIOGUDPOPT, &udpopt))<0) - { - fprintf(stderr,"Error getting the conf\n"); - close(netfd); - return -1; - } - - return netfd; -} - -int main(int argc,char *argv[]) { - int fd; - ssize_t data_read; - udp_buffer_t buffer; - ipaddr_t tmp_addr; - udpport_t tmp_port; - int ret; - fd_set fds_read; - struct timeval timeout; - ipaddr_t client_addr, this_addr; - udpport_t client_port; - - if ((fd = udp_conf(PORT)) < 0) { - fprintf(stderr, "Error configuring UDP connection\n"); - exit(-1); - } - printf("Waiting for messages on port: %ld\n", PORT); - fflush(stdout); - - /* get a first message so we know who is the client and we can harass it - afterwards */ - - /* Initialize fd_set */ - FD_ZERO(&fds_read); - FD_SET(fd, &fds_read); - /* Set timeout structure */ - timeout.tv_sec = 3; - timeout.tv_usec = 0; - ret = select(4, &fds_read, NULL, NULL, NULL); - - if (ret < 0) { - fprintf(stderr, "Error in select\n"); - exit(-1); - } - if (!FD_ISSET(fd, &fds_read)) { - fprintf(stderr, "Error: Should be receiving some data from network(?)\n"); - exit(-1); - } - printf("Ready to receive...\n"); - /* Read received data */ - data_read = read(fd, &buffer, sizeof(udp_buffer_t)); - printf("Received data: %s\n", buffer.data); - - /* Can exit if the received string == exit */ - if (!strcmp(buffer.data,"exit")) - exit(0); - - /* Send data back, swap addresses */ - tmp_addr = buffer.header.uih_src_addr; - buffer.header.uih_src_addr = buffer.header.uih_dst_addr; - buffer.header.uih_dst_addr = tmp_addr; - /* save address of both ends */ - client_addr = tmp_addr; - this_addr = buffer.header.uih_src_addr; - - /* Swap ports */ - tmp_port = buffer.header.uih_src_port; - buffer.header.uih_src_port = buffer.header.uih_dst_port; - buffer.header.uih_dst_port = tmp_port; - /* save client port */ - client_port = tmp_port; - - /* Write the same back */ - write(fd, &buffer, data_read); - - while (1) - { - - /* Initialize fd_set */ - FD_ZERO(&fds_read); - FD_SET(fd, &fds_read); - /* Set timeout structure */ - timeout.tv_sec = 3; - timeout.tv_usec = 0; - /* Wait for data available to be read (timeout) */ - ret = select(4, &fds_read, NULL, NULL, &timeout); - if (ret < 0) { - fprintf(stderr, "Error on select: %d", errno); - exit(-1); - } - /* if timeout */ - if (ret == 0) { - /* Send angry msg to client asking for more */ - printf("Tired of waiting, send client an angry message\n"); - buffer.header.uih_src_addr = this_addr; - buffer.header.uih_dst_addr = client_addr; - buffer.header.uih_src_port = PORT; - buffer.header.uih_dst_port = client_port; - strcpy(buffer.data, "Hey! I want to receive some data!\n"); - write(fd, &buffer, sizeof(udp_buffer_t)); - } - /* If receive data from network */ - if (FD_ISSET(fd, &fds_read)) { - printf("Ready to receive...\n"); - /* Read received data */ - data_read = read(fd, &buffer, sizeof(udp_buffer_t)); - printf("Received data: %s\n", buffer.data); - - /* Can exit if the received string == exit */ - if (!strcmp(buffer.data,"exit")) - break; - - /* Send data back, swap addresses */ - tmp_addr = buffer.header.uih_src_addr; - buffer.header.uih_src_addr = buffer.header.uih_dst_addr; - buffer.header.uih_dst_addr = tmp_addr; - - /* Swap ports */ - tmp_port = buffer.header.uih_src_port; - buffer.header.uih_src_port = buffer.header.uih_dst_port; - buffer.header.uih_dst_port = tmp_port; - - /* Write the same back */ - write(fd, &buffer, data_read); - } - } - close(fd); -} diff --git a/test/select/test06_cli.c b/test/select/test06_cli.c deleted file mode 100644 index 05f072337..000000000 --- a/test/select/test06_cli.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Test name: test06_cli.c - * - * Objective: Test a simple TCP client - * - * Description: Implements a simple echo client using the TCP protocol. First - * it waits until it is possible to write (which is always). - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PORT 6060L - -int tcp_connect(char *host, long port) -{ - /* creates a tcp connection with specified host and port */ - char *tcp_device; - struct hostent *hp; - int netfd; - nwio_tcpcl_t tcpcopt; - nwio_tcpconf_t tcpconf; - ipaddr_t dirhost; - int tries; - int result; - - /* get host address */ - if ((hp = gethostbyname(host)) == (struct hostent*) NULL) - { - fprintf(stderr,"Unknown host\n"); - return(-1); - } - memcpy((char *)&dirhost, (char *)hp->h_addr, hp->h_length); - - /* Get default TCP device */ - if (( tcp_device = getenv("TCP_DEVICE") ) == NULL) - tcp_device = TCP_DEVICE; - - /* Establish TCP connection */ - if ((netfd = open(tcp_device, O_RDWR)) < 0) - { - fprintf(stderr,"Error opening TCP device\n"); - return -1; - } - - /* Configure TCP connection */ - tcpconf.nwtc_flags=NWTC_LP_SEL | NWTC_SET_RA | NWTC_SET_RP; - tcpconf.nwtc_remaddr = dirhost; - tcpconf.nwtc_remport = (tcpport_t) htons(port); - - if ((result = ioctl(netfd, NWIOSTCPCONF, &tcpconf) ) <0) - { - fprintf(stderr, "Error establishing communication\n"); - printf("Error: %d\n",result); - close(netfd); - return -1; - } - - /* Get configuration for TCP comm */ - if ((result = ioctl(netfd, NWIOGTCPCONF, &tcpconf) ) < 0) - { - fprintf(stderr,"Error getting configuration\n"); - printf("Error: %d\n", result); - close(netfd); - return -1; - } - - /* Establish connection */ - tcpcopt.nwtcl_flags = 0; - tries = 0; - while (tries < 10) { - if ( (result = ioctl(netfd, NWIOTCPCONN, &tcpcopt)) < 0 ) { - if (errno != EAGAIN) - { - fprintf(stderr, "Server is not listening\n"); - close(netfd); - return(-1); - } - fprintf(stderr, "Unable to connect\n"); - sleep(1); - tries++; - } - else - break; /* Connection */ - } - /* Check result value */ - if (result < 0) { - fprintf(stderr, "Error connecting\n"); - fprintf(stderr, "Error: %d\n", result); - printf("Number of tries: %d\n", tries); - printf("Error: %d\n", errno); - close(netfd); - return -1; - } - return netfd; -} - -int main(int argc,char *argv[]) { - int fd; - ssize_t data_read; - char send_buf[1024]; - char recv_buf[1024]; - fd_set fds_write; - int ret; - - /* Check parameters */ - if (argc !=2) { - fprintf(stderr,"Usage: %s host\n", argv[0]); - exit(-1); - } - - if ((fd = tcp_connect(argv[1], PORT) ) < 0) - exit(-1); - printf("Connected to server\n"); - /* init fd_set */ - FD_ZERO(&fds_write); - FD_SET(fd, &fds_write); - while (1) - { - /* Wait until it is possible to write with select */ - ret = select(4, NULL, &fds_write, NULL, NULL); - if (ret < 0) { - fprintf(stderr, "Error on select waiting for write: %d\n", errno); - exit(-1); - } - if (!FD_ISSET(fd, &fds_write)) { - fprintf(stderr, "Error: The net connection is not ready for writing (?)\n"); - exit(-1); - } - - /* Get a string and send it */ - printf("Ready to write...\n"); - printf("Send data: "); - gets(send_buf); - write(fd, &send_buf, strlen(send_buf)+1); - - /* If data sent is exit then break */ - if (!strcmp(send_buf,"exit")) - break; - - /* Get server response */ - data_read = read(fd, &recv_buf, 1024); - printf("Received: %s\n\n", recv_buf); - } - - /* Close TCP communication */ - close(fd); -} diff --git a/test/select/test06_srv.c b/test/select/test06_srv.c deleted file mode 100644 index 4834e555a..000000000 --- a/test/select/test06_srv.c +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Test name: test06_srv.c - * - * Objective: Test a simple TCP server - * - * Description: Implements a simple echo server using the TCP protocol. Instead - * of blocking on read(), it performs a select call first blocking there - * until there is data to be read - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PORT 6060L - -int my_listen(long port) { - - char *tcp_device; - int netfd; - nwio_tcpconf_t tcpconf; - nwio_tcpcl_t tcplistenopt; - - /* Get default UDP device */ - if ((tcp_device = getenv("TCP_DEVICE")) == NULL) - tcp_device = TCP_DEVICE; - - /* Open TCP connection */ - if ((netfd = open(tcp_device, O_RDWR)) < 0) - { - fprintf(stderr,"Error opening TCP connection\n"); - return -1; - } - - /* Configure TCP connection */ - tcpconf.nwtc_flags = NWTC_LP_SET | NWTC_UNSET_RA | NWTC_UNSET_RP; - tcpconf.nwtc_locport = (tcpport_t) htons(port); - - if ((ioctl(netfd, NWIOSTCPCONF, &tcpconf))<0) - { - fprintf(stderr,"Error configuring the connection\n"); - close(netfd); - return -1; - } - - /* Get communication options */ - if ((ioctl(netfd, NWIOGTCPCONF, &tcpconf)) < 0) { - fprintf(stderr, "Error getting configuration\n"); - close(netfd); - return -1; - } - - /* Set conf options */ - tcplistenopt.nwtcl_flags = 0; - printf("Waiting for connections...\n"); - while ((ioctl(netfd, NWIOTCPLISTEN, &tcplistenopt)) == -1) - { - if (errno != EAGAIN) - { - fprintf(stderr,"Unable to listen for connections\n"); - close(netfd); - } - sleep(-1); - } - return netfd; -} - -int main(int argc,char *argv[]) { - int fd; - ssize_t data_read; - char buffer[1024]; - int ret; - fd_set fds_read; - - if ((fd = my_listen(PORT)) < 0) { - exit(-1); - } - printf("Waiting for messages on port: %ld\n", PORT); - fflush(stdout); - /* Initialize fd_set */ - FD_ZERO(&fds_read); - FD_SET(fd, &fds_read); - - while (1) - { - /* Wait for data available to be read (no timeout) */ - - ret = select(4, &fds_read, NULL, NULL, NULL); - if (ret < 0) { - fprintf(stderr, "Error on select: %d\n", errno); - exit(-1); - } - if (!FD_ISSET(fd, &fds_read)) { - printf("Error: network fd is not ready (?)\n"); - exit(-1); - } - - printf("Ready to receive...\n"); - /* Read received data */ - data_read = read(fd, &buffer, 1024); - printf("Received data: %s\n", buffer); - - /* Can exit if the received string == exit */ - if (!strcmp(buffer,"exit")) - break; - - /* Write the same back */ - write(fd, &buffer, data_read); - } - printf("Connection finished\n"); - close(fd); -} diff --git a/test/select/test07_cli.c b/test/select/test07_cli.c deleted file mode 100644 index 8bc21010a..000000000 --- a/test/select/test07_cli.c +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Test name: test07_cli.c - * - * Objective: Test an impatient TCP client with timeout which waits input both - * from the terminal and from the network connection. - * - * Description: Implements a echo client using the TCP protocol with a timeout - * value. It waites for data on both the terminal and the network connection and - * prints an angry message asking for more data if there is a timeout. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PORT 6060L - -int tcp_connect(char *host, long port) -{ - /* creates a tcp connection with specified host and port */ - char *tcp_device; - struct hostent *hp; - int netfd; - nwio_tcpcl_t tcpcopt; - nwio_tcpconf_t tcpconf; - ipaddr_t dirhost; - int tries; - int result; - - /* get host address */ - if ((hp = gethostbyname(host)) == (struct hostent*) NULL) - { - fprintf(stderr,"Unknown host\n"); - return(-1); - } - memcpy((char *)&dirhost, (char *)hp->h_addr, hp->h_length); - - /* Get default TCP device */ - if (( tcp_device = getenv("TCP_DEVICE") ) == NULL) - tcp_device = TCP_DEVICE; - - /* Establish TCP connection */ - if ((netfd = open(tcp_device, O_RDWR)) < 0) - { - fprintf(stderr,"Error opening TCP device\n"); - return -1; - } - - /* Configure TCP connection */ - tcpconf.nwtc_flags=NWTC_LP_SEL | NWTC_SET_RA | NWTC_SET_RP; - tcpconf.nwtc_remaddr = dirhost; - tcpconf.nwtc_remport = (tcpport_t) htons(port); - - if ((result = ioctl(netfd, NWIOSTCPCONF, &tcpconf) ) <0) - { - fprintf(stderr, "Error establishing communication\n"); - printf("Error: %d\n",result); - close(netfd); - return -1; - } - - /* Get configuration for TCP comm */ - if ((result = ioctl(netfd, NWIOGTCPCONF, &tcpconf) ) < 0) - { - fprintf(stderr,"Error getting configuration\n"); - printf("Error: %d\n", result); - close(netfd); - return -1; - } - - /* Establish connection */ - tcpcopt.nwtcl_flags = 0; - tries = 0; - while (tries < 10) { - if ( (result = ioctl(netfd, NWIOTCPCONN, &tcpcopt)) < 0 ) { - if (errno != EAGAIN) - { - fprintf(stderr, "Server is not listening\n"); - close(netfd); - return(-1); - } - fprintf(stderr, "Unable to connect\n"); - sleep(1); - tries++; - } - else - break; /* Connection */ - } - /* Check result value */ - if (result < 0) { - fprintf(stderr, "Error connecting\n"); - fprintf(stderr, "Error: %d\n", result); - printf("Number of tries: %d\n", tries); - printf("Error: %d\n", errno); - close(netfd); - return -1; - } - return netfd; -} - -int main(int argc,char *argv[]) { - int fd; - ssize_t data_read; - char send_buf[1024]; - char recv_buf[1024]; - fd_set fds_read; - int ret; - struct timeval timeout; - - /* Check parameters */ - if (argc !=2) { - fprintf(stderr,"Usage: %s host\n", argv[0]); - exit(-1); - } - - if ((fd = tcp_connect(argv[1], PORT) ) < 0) - exit(-1); - printf("Connected to server\n"); - - while (1) - { - - /* init fd_set */ - FD_ZERO(&fds_read); - FD_SET(0, &fds_read); /* stdin */ - FD_SET(fd, &fds_read); - /* set timeout */ - timeout.tv_sec = 3; - timeout.tv_usec = 0; - - printf("Send data: "); - fflush(stdout); - /* Wait until it is possible to read with select */ - ret = select(4, &fds_read, NULL, NULL, &timeout); - if (ret < 0) { - fprintf(stderr, "Error on select waiting for write: %d\n", errno); - exit(-1); - } - /* timeout */ - if (ret == 0) { - printf("\nClient says: Hey! I want to send some data!!\n"); - continue; - } - /* handle data from network */ - if (FD_ISSET(fd, &fds_read)) { - data_read = read(fd, &recv_buf, 1024); - printf("Server says: %s\n\n", recv_buf); - } - /* handle data from terminal */ - if (FD_ISSET(0, &fds_read)) { - /* Get a string and send it */ - gets(send_buf); - write(fd, &send_buf, strlen(send_buf)+1); - - /* If data sent is exit then break */ - if (!strcmp(send_buf,"exit")) - break; - - /* Get server response */ - data_read = read(fd, &recv_buf, 1024); - printf("Received: %s\n\n", recv_buf); - } - } - - /* Close TCP communication */ - close(fd); -} diff --git a/test/select/test07_srv.c b/test/select/test07_srv.c deleted file mode 100644 index b0cffba36..000000000 --- a/test/select/test07_srv.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Test name: test07_srv.c - * - * Objective: Test an impatient TCP server with a timeout. - * - * Description: Implements an echo server using the TCP protocol. It is - * based on test06_srv.c but has a timeout for receiving data from a client - * and if the time is up it sends an angry message to the client requesting - * for more information. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PORT 6060L - -int my_listen(long port) { - - char *tcp_device; - int netfd; - nwio_tcpconf_t tcpconf; - nwio_tcpcl_t tcplistenopt; - - /* Get default UDP device */ - if ((tcp_device = getenv("TCP_DEVICE")) == NULL) - tcp_device = TCP_DEVICE; - - /* Open TCP connection */ - if ((netfd = open(tcp_device, O_RDWR)) < 0) - { - fprintf(stderr,"Error opening TCP connection\n"); - return -1; - } - - /* Configure TCP connection */ - tcpconf.nwtc_flags = NWTC_LP_SET | NWTC_UNSET_RA | NWTC_UNSET_RP; - tcpconf.nwtc_locport = (tcpport_t) htons(port); - - if ((ioctl(netfd, NWIOSTCPCONF, &tcpconf))<0) - { - fprintf(stderr,"Error configuring the connection\n"); - close(netfd); - return -1; - } - - /* Get communication options */ - if ((ioctl(netfd, NWIOGTCPCONF, &tcpconf)) < 0) { - fprintf(stderr, "Error getting configuration\n"); - close(netfd); - return -1; - } - - /* Set conf options */ - tcplistenopt.nwtcl_flags = 0; - printf("Waiting for connections...\n"); - while ((ioctl(netfd, NWIOTCPLISTEN, &tcplistenopt)) == -1) - { - if (errno != EAGAIN) - { - fprintf(stderr,"Unable to listen for connections\n"); - close(netfd); - } - sleep(-1); - } - return netfd; -} - -int main(int argc,char *argv[]) { - int fd; - ssize_t data_read; - char buffer[1024]; - int ret; - fd_set fds_read; - struct timeval timeout; - - if ((fd = my_listen(PORT)) < 0) { - exit(-1); - } - printf("Waiting for messages on port: %ld\n", PORT); - fflush(stdout); - while (1) - { - - /* Initialize fd_set */ - FD_ZERO(&fds_read); - FD_SET(fd, &fds_read); - /* set timeout */ - timeout.tv_sec = 3; - timeout.tv_usec = 0; - /* Wait for data available to be read (no timeout) */ - ret = select(4, &fds_read, NULL, NULL, &timeout); - if (ret < 0) { - fprintf(stderr, "Error on select: %d\n", errno); - exit(-1); - } - /* timeout */ - if (ret == 0) { - strcpy(buffer, "I want to get some data!!\n"); - write(fd, &buffer, 1024); - continue; - } - - /* data received from client */ - if (FD_ISSET(fd, &fds_read)) { - printf("Ready to receive...\n"); - /* Read received data */ - data_read = read(fd, &buffer, 1024); - printf("Received data: %s\n", buffer); - - /* Can exit if the received string == exit */ - if (!strcmp(buffer,"exit")) - break; - - /* Write the same back */ - write(fd, &buffer, data_read); - } - } - printf("Connection finished\n"); - close(fd); -} diff --git a/test/select/test08_cli.c b/test/select/test08_cli.c deleted file mode 100644 index 20a8cedf1..000000000 --- a/test/select/test08_cli.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Test name: test08_cli.c - * - * Objective: Test select on urgent data. TCP client. - * - * Description: It is based on test06_cli but sends urgent data. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PORT 6060L - -int tcp_connect(char *host, long port) -{ - /* creates a tcp connection with specified host and port */ - char *tcp_device; - struct hostent *hp; - int netfd; - nwio_tcpcl_t tcpcl; - nwio_tcpopt_t tcpopt; - nwio_tcpconf_t tcpconf; - ipaddr_t dirhost; - int tries; - int result; - - /* get host address */ - if ((hp = gethostbyname(host)) == (struct hostent*) NULL) - { - fprintf(stderr,"Unknown host\n"); - return(-1); - } - memcpy((char *)&dirhost, (char *)hp->h_addr, hp->h_length); - - /* Get default TCP device */ - if (( tcp_device = getenv("TCP_DEVICE") ) == NULL) - tcp_device = TCP_DEVICE; - - /* Establish TCP connection */ - if ((netfd = open(tcp_device, O_RDWR)) < 0) - { - fprintf(stderr,"Error opening TCP device\n"); - return -1; - } - - /* Configure TCP connection */ - tcpconf.nwtc_flags=NWTC_LP_SEL | NWTC_SET_RA | NWTC_SET_RP; - tcpconf.nwtc_remaddr = dirhost; - tcpconf.nwtc_remport = (tcpport_t) htons(port); - - if ((result = ioctl(netfd, NWIOSTCPCONF, &tcpconf) ) <0) - { - fprintf(stderr, "Error establishing communication\n"); - printf("Error: %d\n",result); - close(netfd); - return -1; - } - - /* Get configuration for TCP comm */ - if ((result = ioctl(netfd, NWIOGTCPCONF, &tcpconf) ) < 0) - { - fprintf(stderr,"Error getting configuration\n"); - printf("Error: %d\n", result); - close(netfd); - return -1; - } - - /* Establish connection options (send URG data) */ - tcpopt.nwto_flags = NWTO_SND_URG_MASK; - - /* Set options for TCP comm */ - if ((result = ioctl(netfd, NWIOSTCPOPT, &tcpopt) ) < 0) - { - fprintf(stderr,"Error getting configuration\n"); - printf("Error: %d\n", result); - close(netfd); - return -1; - } - - /* Get configuration for TCP comm */ - if ((result = ioctl(netfd, NWIOGTCPOPT, &tcpopt) ) < 0) - { - fprintf(stderr,"Error getting options\n"); - printf("Error: %d\n", result); - close(netfd); - return -1; - } - - tcpcl.nwtcl_flags = 0; - tries = 0; - while (tries < 10) { - if ( (result = ioctl(netfd, NWIOTCPCONN, &tcpcl)) < 0 ) { - if (errno != EAGAIN) - { - fprintf(stderr, "Server is not listening\n"); - close(netfd); - return(-1); - } - fprintf(stderr, "Unable to connect\n"); - sleep(1); - tries++; - } - else - break; /* Connection */ - } - /* Check result value */ - if (result < 0) { - fprintf(stderr, "Error connecting\n"); - fprintf(stderr, "Error: %d\n", result); - printf("Number of tries: %d\n", tries); - printf("Error: %d\n", errno); - close(netfd); - return -1; - } - return netfd; -} - -int main(int argc,char *argv[]) { - int fd; - ssize_t data_read; - char send_buf[1024]; - char recv_buf[1024]; - fd_set fds_write; - int ret; - - /* Check parameters */ - if (argc !=2) { - fprintf(stderr,"Usage: %s host\n", argv[0]); - exit(-1); - } - - if ((fd = tcp_connect(argv[1], PORT) ) < 0) - exit(-1); - printf("Connected to server\n"); - /* init fd_set */ - FD_ZERO(&fds_write); - FD_SET(fd, &fds_write); - while (1) - { - /* Wait until it is possible to write with select */ - ret = select(4, NULL, &fds_write, NULL, NULL); - if (ret < 0) { - fprintf(stderr, "Error on select waiting for write: %d\n", errno); - exit(-1); - } - if (!FD_ISSET(fd, &fds_write)) { - fprintf(stderr, "Error: The net connection is not ready for writing (?)\n"); - exit(-1); - } - - /* Get a string and send it */ - printf("Ready to write...\n"); - printf("Send data: "); - gets(send_buf); - write(fd, &send_buf, strlen(send_buf)+1); - - /* If data sent is exit then break */ - if (!strcmp(send_buf,"exit")) - break; - - /* Get server response */ - data_read = read(fd, &recv_buf, 1024); - printf("Received: %s\n\n", recv_buf); - } - - /* Close UDP communication */ - close(fd); -} diff --git a/test/select/test08_srv.c b/test/select/test08_srv.c deleted file mode 100644 index fa4f6f8fb..000000000 --- a/test/select/test08_srv.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Test name: test08_srv.c - * - * Objective: Test a simple TCP server waiting for urgent data. - * - * Description: Implements a echo TCP server as in test06_srv but waits - * for urgent data, using select on exception. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PORT 6060L - -int my_listen(long port) { - - char *tcp_device; - int netfd; - nwio_tcpconf_t tcpconf; - nwio_tcpcl_t tcpcl; - nwio_tcpopt_t tcpopt; - - /* Get default UDP device */ - if ((tcp_device = getenv("TCP_DEVICE")) == NULL) - tcp_device = TCP_DEVICE; - - /* Open TCP connection */ - if ((netfd = open(tcp_device, O_RDWR)) < 0) - { - fprintf(stderr,"Error opening TCP connection\n"); - return -1; - } - - /* Configure TCP connection */ - tcpconf.nwtc_flags = NWTC_LP_SET | NWTC_UNSET_RA | NWTC_UNSET_RP; - tcpconf.nwtc_locport = (tcpport_t) htons(port); - - if ((ioctl(netfd, NWIOSTCPCONF, &tcpconf))<0) - { - fprintf(stderr,"Error configuring the connection\n"); - close(netfd); - return -1; - } - - /* Get communication conf*/ - if ((ioctl(netfd, NWIOGTCPCONF, &tcpconf)) < 0) { - fprintf(stderr, "Error getting configuration\n"); - close(netfd); - return -1; - } - - /* Set comm options */ - tcpopt.nwto_flags = NWTO_RCV_URG; - - if ((ioctl(netfd, NWIOSTCPOPT, &tcpopt))<0) - { - fprintf(stderr,"Error configuring the connection\n"); - close(netfd); - return -1; - } - - /* Get communication opt*/ - if ((ioctl(netfd, NWIOGTCPOPT, &tcpopt)) < 0) { - fprintf(stderr, "Error getting options\n"); - close(netfd); - return -1; - } - - /* Set conn options */ - tcpcl.nwtcl_flags = 0; - printf("Waiting for connections...\n"); - while ((ioctl(netfd, NWIOTCPLISTEN, &tcpcl)) == -1) - { - if (errno != EAGAIN) - { - fprintf(stderr,"Unable to listen for connections\n"); - close(netfd); - } - sleep(-1); - } - return netfd; -} - -int main(int argc,char *argv[]) { - int fd; - ssize_t data_read; - char buffer[1024]; - int ret; - fd_set fds_excep; - - if ((fd = my_listen(PORT)) < 0) { - exit(-1); - } - printf("Waiting for messages on port: %ld\n", PORT); - fflush(stdout); - /* Initialize fd_set */ - FD_ZERO(&fds_excep); - FD_SET(fd, &fds_excep); - - while (1) - { - /* Wait for data available to be read (no timeout) */ - - ret = select(4, NULL, NULL, &fds_excep, NULL); - if (ret < 0) { - fprintf(stderr, "Error on select: %d\n", errno); - exit(-1); - } - if (!FD_ISSET(fd, &fds_excep)) { - printf("Error: no URG data received (?)\n"); - exit(-1); - } - - printf("Ready to receive...\n"); - /* Read received data */ - data_read = read(fd, &buffer, 1024); - printf("Received data: %s\n", buffer); - - /* Can exit if the received string == exit */ - if (!strcmp(buffer,"exit")) - break; - - /* Write the same back */ - write(fd, &buffer, data_read); - } - printf("Connection finished\n"); - close(fd); -} diff --git a/test/select/test09.c b/test/select/test09.c deleted file mode 100644 index 3fc9ecf4c..000000000 --- a/test/select/test09.c +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Test name: test09.c - * - * Objetive: The purpose of this test is to make sure that select works - * when working with the terminal. - * - * Description: This tests wait entry from stdin using select and displays - * it again in stdout when it is ready to write (which is always) - * - * Jose M. Gomez - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -void main(void) { - fd_set fds_read, fds_write; - int retval; - char data[1024]; - - FD_ZERO(&fds_read); - FD_ZERO(&fds_write); - FD_SET(0, &fds_read); /* stdin */ - FD_SET(1, &fds_write); /* stdout */ - - while(1) { - printf("Input some data: "); - fflush(stdout); - retval=select(3, &fds_read, NULL, NULL, NULL); - if (retval < 0) { - fprintf(stderr, "Error while executing select\n"); - exit(-1); - } - printf("select retval: %d\n", retval); - if (!FD_ISSET(0, &fds_read)) { - fprintf(stderr, "Error: stdin not ready (?)\n"); - exit(-1); - } - printf("gets..\n"); - gets(data); - printf("gets done..\n"); - if (!strcmp(data, "exit")) - exit(0); - printf("Try to write it back\n"); - retval=select(3, NULL, &fds_write, NULL, NULL); - if (retval < 0) { - fprintf(stderr, "Error while executing select\n"); - exit(-1); - } - if (!FD_ISSET(1, &fds_write)) { - fprintf(stderr, "Error: stdout not ready (?)\n"); - exit(-1); - } - printf("Data: %s\n", data); - } -} diff --git a/test/select/test10.c b/test/select/test10.c deleted file mode 100644 index 6f68c8490..000000000 --- a/test/select/test10.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Test name: test10.c - * - * Objetive: The purpose of this test is to make sure that select works - * when working with the terminal with timeouts - * - * Description: This tests wait entry from stdin using select and displays - * it again in stdout when it is ready to write (which is always). It has - * a timeout value as well. - * - * Jose M. Gomez - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int main(int argc, char *argv[]) -{ - fd_set fds_read, fds_write; - int retval; - char data[1024]; - struct timeval timeout; - - while(1) { - timeout.tv_sec = 3; - timeout.tv_usec = 0; - FD_ZERO(&fds_read); - FD_ZERO(&fds_write); - FD_SET(0, &fds_read); - FD_SET(1, &fds_write); - printf("Input some data: "); - fflush(stdout); - retval=select(3, &fds_read, NULL, NULL, &timeout); - if (retval < 0) { - fprintf(stderr, "Error while executing select\n"); - exit(-1); - } - if (retval == 0) { - printf("\n Hey! Feed me some data!\n"); - fflush(stdout); - continue; - } - if (!FD_ISSET(0, &fds_read)) { - fprintf(stderr, "Error: stdin not ready (?)\n"); - exit(-1); - } - gets(data); - if (!strcmp(data, "exit")) - exit(0); - printf("Try to write it back\n"); - retval=select(3, NULL, &fds_write, NULL, NULL); - if (retval < 0) { - fprintf(stderr, "Error while executing select\n"); - exit(-1); - } - if (!FD_ISSET(1, &fds_write)) { - fprintf(stderr, "Error: stdout not ready (?)\n"); - exit(-1); - } - printf("Data: %s\n", data); - } - return 1; -} diff --git a/test/select/test11.c b/test/select/test11.c deleted file mode 100644 index 99c8381b8..000000000 --- a/test/select/test11.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Test name: test11.c - * - * Objetive: The purpose of this test is to make sure that select works - * with pipes. - * - * Description: The select checks are divided in checks on writing for the - * parent process, which has the writing end of the pipe, and checks on reading - * and exception on the child process, which has the reading end of pipe. So - * when the first process is ready to write to the pipe it will request a string - * from the terminal and send it through the pipe. If the string is 'exit' then - * the pipe is closed. The child process is blocked in a select checking for read - * and exception. If there is data to be read then it will perform the read and - * prints the read data. If the pipe is closed (user typed 'exit'), the child - * process finishes. - * - * Jose M. Gomez - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -void pipehandler(int sig) -{ - -} - -void do_child(int data_pipe[]) -{ - /* reads from pipe and prints out the data */ - char data[2048]; - int retval; - fd_set fds_read; - fd_set fds_exception; - struct timeval timeout; - - signal(SIGPIPE, pipehandler); - signal(SIGUSR1, pipehandler); - - /* first, close the write part of the pipe, since it is not needed */ - close(data_pipe[1]); - - while(1) { - FD_ZERO(&fds_read); - FD_ZERO(&fds_exception); - FD_SET(data_pipe[0], &fds_read); - FD_SET(data_pipe[0], &fds_exception); - timeout.tv_sec = 5; - timeout.tv_usec = 0; - retval = select(data_pipe[0]+1, &fds_read, NULL, &fds_exception, &timeout); - if (retval == -1) { - perror("select"); - fprintf(stderr, "child: Error in select\n"); - continue; - } else printf("child select: %d\n", retval); - if (FD_ISSET(data_pipe[0], &fds_exception)) { - printf("child: exception fd set. quitting.\n"); - break; - } - if (FD_ISSET(data_pipe[0], &fds_read)) { - printf("child: read fd set. reading.\n"); - if ((retval = read(data_pipe[0], data, sizeof(data))) < 0) { - perror("read"); - fprintf(stderr, "child: couldn't read from pipe\n"); - exit(-1); - } - if(retval == 0) { - fprintf(stderr, "child: eof on pipe\n"); - break; - } - data[retval] = '\0'; - printf("pid %d Pipe reads (%d): %s\n", getpid(), retval, data); - } else printf("child: no fd set\n"); - } - - /* probably pipe was broken, or got EOF via the pipe. */ - exit(0); -} - -void do_parent(int data_pipe[]) -{ - char data[1024]; - int retval; - fd_set fds_write; - - signal(SIGPIPE, pipehandler); - signal(SIGUSR1, pipehandler); - - /* first, close the read part of pipe, since it is not needed */ - close(data_pipe[0]); - - /* now enter a loop of read user input, and writing it to the pipe */ - while (1) { - FD_ZERO(&fds_write); - FD_SET(data_pipe[1], &fds_write); - printf("pid %d Waiting for pipe ready to write...\n", getpid()); - retval = select(data_pipe[1]+1, NULL, &fds_write, NULL, NULL); - if (retval == -1) { - perror("select"); - fprintf(stderr, "Parent: Error in select\n"); - exit(-1); - } - - printf("Input data: "); - if(!gets(data)) { - printf("parent: eof; exiting\n"); - break; - } - if (!strcmp(data, "exit")) - break; - if (!FD_ISSET(data_pipe[1], &fds_write)) { - fprintf(stderr, "parent: write fd not set?! retrying\n"); - continue; - } - retval = write(data_pipe[1], &data, 1024); - if (retval == -1) { - perror("write"); - fprintf(stderr, "Error writing on pipe\n"); - exit(-1); - } - } - - /* got exit from user */ - close(data_pipe[1]); /* close pipe, let child know we're done */ - wait(&retval); - printf("Child exited with status: %d\n", retval); - exit(0); -} - -int main(int argc, char *argv[]) -{ - int pipes[2]; - int retval; - int pid; - - /* create the pipe */ - retval = pipe(pipes); - if (retval == -1) { - perror("pipe"); - fprintf(stderr, "Error creating the pipe\n"); - exit(-1); - } - pid = fork(); - if (pid == -1) { - fprintf(stderr, "Error forking\n"); - exit(-1); - } - - if (pid == 0) /* child proc */ - do_child(pipes); - else - do_parent(pipes); - return 0; -} diff --git a/test/select/test12.c b/test/select/test12.c deleted file mode 100644 index f69d876da..000000000 --- a/test/select/test12.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Test name: test12.c - * - * Objective: The purpose of this check the behaviour when a signal is received - * and there is a handler. - * - * Description: The program handles SIGHUP and expects the user to actually send - * the signal from other terminal with 'kill -1 pid' - - * Jose M. Gomez - */ - -#include -#include -#include -#include -#include -#include -#include - -#define SECONDS 15 - -void catch_hup(int sig_num) -{ - /* don't need to reset signal handler */ - printf("Received a SIGHUP, inside the handler now\n"); -} - -int main(void) { - int ret; /* return value */ - - /* set the HUP sginal handler to 'catch_hup' */ - signal(SIGHUP, catch_hup); - /* Get proc_id and print it */ - printf("Send a signal from other terminal with: kill -1 %d\n", getpid()); - printf("Blocking now on select...\n", SECONDS); - ret = select(0, NULL, NULL, NULL, NULL); - printf("Errno: %d\n", errno); -} diff --git a/test/select/test13a.c b/test/select/test13a.c deleted file mode 100644 index 9b76bd801..000000000 --- a/test/select/test13a.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Test name: test13a.c - * - * Objective: The purpose of this tests is to show how a select can - * get into a race condition when dealing with signals. - * - * Description: The program waits for SIGHUP or input in the terminal - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -int got_sighup = 0; - -void catch_hup(int sig_num) -{ - printf("Received a SIGHUP, set global vble \n"); - got_sighup = 1; -} - -int main(void) { - int ret; /* return value */ - fd_set read_fds; - char data[1024]; - - /* Init read fd_set */ - FD_ZERO(&read_fds); - FD_SET(0, &read_fds); - - /* set the HUP signal handler to 'catch_hup' */ - signal(SIGHUP, catch_hup); - - /* Get proc_id and print it */ - printf("Send a signal from other terminal with: kill -1 %d\n", getpid()); - printf("Going to sleep for 5 seconds, if the signal arrives meanwhile\n"); - printf("the process will be blocked until there is input in the keyboard\n"); - printf("if the signal arrives after the timeout and while in select, it will\n"); - printf("behave as it should.\n"); - printf("Sleeping for 5 secs\n"); - sleep(5); - - printf("Blocking now on select...\n"); - ret = select(1, &read_fds, NULL, NULL, NULL); - if (got_sighup) { - printf("We have a sighup signal so exit the program\n"); - exit(0); - } - gets(data); - printf("Got entry for terminal then, bye\n"); -} diff --git a/test/select/test13b.c b/test/select/test13b.c deleted file mode 100644 index 8d14a0523..000000000 --- a/test/select/test13b.c +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Test name: test13b.c - * - * Objective: The purpose of this tests is to show how pselect() - * solves the situation shown in test13a.c - * - * Description: The program waits for SIGHUP or input in the terminal - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -int got_sighup = 0; - -void catch_hup(int sig_num) -{ - printf("Received a SIGHUP, set global vble \n"); - got_sighup = 1; -} - -int main(void) { - int ret; /* return value */ - fd_set read_fds; - sigset_t sigmask, orig_sigmask; - char data[1024]; - - /* Init read fd_set */ - FD_ZERO(&read_fds); - FD_SET(0, &read_fds); - - /* set the signal masks */ - sigemptyset(&sigmask); - sigaddset(&sigmask, SIGHUP); - sigprocmask( SIG_BLOCK, &sigmask, &orig_sigmask); - - /* set the HUP signal handler to 'catch_hup' */ - signal(SIGHUP, catch_hup); - - /* Get proc_id and print it */ - printf("Send a signal from other terminal with: kill -1 %d\n", getpid()); - printf("Going to sleep for 5 seconds, if the signal arrives meanwhile\n"); - printf("the process will be blocked until there is input in the keyboard\n"); - printf("if the signal arrives after the timeout and while in select, it will\n"); - printf("behave as it should.\n"); - printf("Sleeping for 5 secs\n"); - sleep(5); - - printf("Blocking now on select...\n"); -#if 0 - ret = pselect(1, &read_fds, NULL, NULL, NULL, &orig_sigmask); -#else - ret = -1; -#endif - if (got_sighup) { - printf("We have a sighup signal so exit the program\n"); - exit(0); - } - gets(data); - printf("Got entry for terminal then, bye\n"); - -} diff --git a/test/select/test14.c b/test/select/test14.c deleted file mode 100644 index 99cc009a3..000000000 --- a/test/select/test14.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Test name: test14.c - * - * Objetive: The purpose of this test is to make sure that select works - * with ptys. - * - * Adapted from test11.c (pipe test). - * - * Ben Gras - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -char name[100]; -void pipehandler(int sig) -{ -} -#define CHILDFD 1 -#define PARENTFD 0 -void do_child(int pty_fds[]) -{ - /* reads from pipe and prints out the data */ - char data[2048]; - int retval; - fd_set fds_read; - fd_set fds_exception; - struct timeval timeout; - signal(SIGPIPE, pipehandler); - signal(SIGUSR1, pipehandler); - /* first, close the write part, since it is not needed */ - close(pty_fds[PARENTFD]); - - while(1) { - FD_ZERO(&fds_read); - FD_ZERO(&fds_exception); - FD_SET(pty_fds[CHILDFD], &fds_read); - FD_SET(pty_fds[CHILDFD], &fds_exception); - timeout.tv_sec = 5; - timeout.tv_usec = 0; - retval = select(pty_fds[CHILDFD]+2, &fds_read, NULL, &fds_exception, &timeout); - if (retval == -1) { - perror("select"); - fprintf(stderr, "child: Error in select\n"); - continue; - } else printf("child select: %d\n", retval); - if (FD_ISSET(pty_fds[CHILDFD], &fds_exception)) { - printf("child: exception fd set. quitting.\n"); - break; - } - if (FD_ISSET(pty_fds[CHILDFD], &fds_read)) { - printf("child: read fd set. reading.\n"); - if ((retval = read(pty_fds[CHILDFD], data, sizeof(data))) < 0) { - perror("read"); - fprintf(stderr, "child: couldn't read from pty\n"); - exit(-1); - } - if(retval == 0) { - fprintf(stderr, "child: eof on pty\n"); - break; - } - data[retval] = '\0'; - printf("pid %d pty reads (%d): %s\n", getpid(), retval, data); - } else printf("child: no fd set\n"); - } - - exit(0); -} -void do_parent(int pty_fds[]) -{ - char data[1024]; - int retval; - fd_set fds_write; - signal(SIGPIPE, pipehandler); - signal(SIGUSR1, pipehandler); - /* first, close the read part of pty, since it is not needed */ - close(pty_fds[CHILDFD]); - /* now enter a loop of read user input, and writing it to the pty */ - while (1) { - FD_ZERO(&fds_write); - FD_SET(pty_fds[PARENTFD], &fds_write); - printf("pid %d Waiting for pty ready to write on %s...\n", - getpid(), name); - retval = select(pty_fds[PARENTFD]+2, NULL, &fds_write, NULL, NULL); - if (retval == -1) { - perror("select"); - fprintf(stderr, "Parent: Error in select\n"); - exit(-1); - } - printf("Input data: "); - if(!gets(data)) { - printf("parent: eof; exiting\n"); - break; - } - if (!strcmp(data, "exit")) - break; - if (!FD_ISSET(pty_fds[PARENTFD], &fds_write)) { - fprintf(stderr, "parent: write fd not set?! retrying\n"); - continue; - } - retval = write(pty_fds[PARENTFD], data, 1024); - if (retval == -1) { - perror("write"); - fprintf(stderr, "Error writing on pty\n"); - exit(-1); - } else printf("wrote %d\n", retval); - } - /* got exit from user */ - close(pty_fds[PARENTFD]); /* close pty, let child know we're done */ - wait(&retval); - printf("Child exited with status: %d\n", retval); - exit(0); -} -int main(int argc, char *argv[]) -{ - int ptys[2]; - int retval; - int pid; - if(openpty(&ptys[0], &ptys[1], name, NULL, NULL) < 0) { - perror("openpty"); - return 1; - } - printf("Using %s\n", name); - pid = fork(); - if (pid == -1) { - fprintf(stderr, "Error forking\n"); - exit(-1); - } - if (pid == 0) /* child proc */ - do_child(ptys); - else - do_parent(ptys); - /* not reached */ - return 0; -} diff --git a/test/t40c.c b/test/t40c.c index 6a71c4d9d..d78f981aa 100644 --- a/test/t40c.c +++ b/test/t40c.c @@ -60,26 +60,28 @@ static void open_terminal(int *child_fd, int *parent_fd) { } static int do_child(int terminal) { - struct timeval tv; - /* Going to sleep for two seconds to allow the parent proc to get ready */ - tv.tv_sec = 2; - tv.tv_usec = 0; - select(0, NULL, NULL, NULL, &tv); + sleep(2); /* Try to write. Doesn't matter how many bytes we actually send. */ (void) write(terminal, SENDSTRING, strlen(SENDSTRING)); - close(terminal); /* Wait for another second to allow the parent to process incoming data */ - tv.tv_usec = 1000000; - (void) select(0,NULL, NULL, NULL, &tv); + sleep(1); + + /* Write some more, and wait some more. */ + (void) write(terminal, SENDSTRING, strlen(SENDSTRING)); + + sleep(1); + + close(terminal); exit(0); } static int do_parent(int child, int terminal) { - fd_set fds_read, fds_write, fds_error; - int retval; + fd_set fds_read, fds_read2, fds_write, fds_error; + int retval, terminal2, highest; + char buf[256]; /* Clear bit masks */ FD_ZERO(&fds_read); FD_ZERO(&fds_write); FD_ZERO(&fds_error); @@ -96,7 +98,6 @@ static int do_parent(int child, int terminal) { if(retval != 1) em(1, "incorrect amount of ready file descriptors"); - if(FD_ISSET(terminal, &fds_read)) em(2, "read should NOT be set"); if(!FD_ISSET(terminal, &fds_write)) em(3, "write should be set"); if(FD_ISSET(terminal, &fds_error)) em(4, "error should NOT be set"); @@ -110,7 +111,6 @@ static int do_parent(int child, int terminal) { if(!FD_ISSET(terminal, &fds_read)) em(6, "read should be set"); if(FD_ISSET(terminal, &fds_error)) em(7, "error should not be set"); - FD_ZERO(&fds_read); FD_ZERO(&fds_error); FD_SET(terminal, &fds_write); retval = select(terminal+1, NULL, &fds_write, NULL, NULL); @@ -118,6 +118,33 @@ static int do_parent(int child, int terminal) { * immediately with fd set in fds_write. */ if(retval != 1) em(8, "incorrect amount or ready file descriptors"); + /* See if selecting on the same object with two different fds results in both + * fds being returned as ready, immediately. + */ + terminal2 = dup(terminal); + if (terminal2 < 0) em(9, "unable to dup file descriptor"); + + FD_ZERO(&fds_read); + FD_SET(terminal, &fds_read); + FD_SET(terminal2, &fds_read); + fds_read2 = fds_read; + highest = terminal > terminal2 ? terminal : terminal2; + + retval = select(highest+1, &fds_read, NULL, NULL, NULL); + if (retval != 2) em(10, "incorrect amount of ready file descriptors"); + if (!FD_ISSET(terminal, &fds_read)) em(11, "first fd missing from set"); + if (!FD_ISSET(terminal2, &fds_read)) em(12, "second fd missing from set"); + + /* Empty the buffer. */ + if (read(terminal, buf, sizeof(buf)) <= 0) em(13, "unable to read data"); + + /* Repeat the test, now with a delay. */ + retval = select(highest+1, &fds_read2, NULL, NULL, NULL); + if (retval != 2) em(10, "incorrect amount of ready file descriptors"); + if (!FD_ISSET(terminal, &fds_read2)) em(11, "first fd missing from set"); + if (!FD_ISSET(terminal2, &fds_read2)) em(12, "second fd missing from set"); + + close(terminal2); close(terminal); waitpid(child, &retval, 0); exit(errct); diff --git a/test/t40g.c b/test/t40g.c new file mode 100644 index 000000000..038a907db --- /dev/null +++ b/test/t40g.c @@ -0,0 +1,52 @@ +/* t40g.c + * + * Test select on character driver that does not support select + * + * We use /dev/zero for this right now. If the memory driver ever implements + * select support, this test should be changed to use another character driver. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +int +main(int argc, char **argv) +{ + fd_set set; + int fd, retval; + + /* Get subtest number */ + if (argc != 2 || sscanf(argv[1], "%d", &subtest) != 1) { + printf("Usage: %s subtest_no\n", argv[0]); + exit(-2); + } + + /* + * Do a select on /dev/zero, with the expectation that it will fail + * with an EBADF error code. + */ + fd = open("/dev/zero", O_RDONLY); + if (fd < 0) em(1, "unable to open /dev/zero"); + + FD_ZERO(&set); + FD_SET(fd, &set); + + retval = select(fd + 1, &set, NULL, NULL, NULL); + if (retval != -1) em(2, "select call was expected to fail"); + if (errno != EBADF) em(3, "error code other than EBADF returned"); + if (!FD_ISSET(fd, &set)) em(4, "file descriptor set was modified"); + + exit(errct); +} diff --git a/test/test40.c b/test/test40.c index 686f02268..15a36e3ca 100644 --- a/test/test40.c +++ b/test/test40.c @@ -16,9 +16,9 @@ int max_error = 5; int main(int argc, char **argv) { - char *tests[] = {"t40a", "t40b", "t40c", "t40d", "t40e", "t40f"}; + char *tests[] = {"t40a", "t40b", "t40c", "t40d", "t40e", "t40f", "t40g"}; char copy_command[8+PATH_MAX+1]; - int no_tests, i, forkres, status = 0, errorct = 0; + int no_tests, i, forkres, status = 0; no_tests = sizeof(tests) / sizeof(char *); @@ -39,7 +39,7 @@ int main(int argc, char **argv) { exit(-2); } else if(forkres > 0) { /* Parent */ if(waitpid(forkres, &status, 0) > 0 && WEXITSTATUS(status) < 20) { - errorct += WEXITSTATUS(status); /* Count errors */ + errct += WEXITSTATUS(status); /* Count errors */ } status = 0; /* Reset */ } else { diff --git a/test/test55.c b/test/test55.c index f6974da8d..6716bd496 100644 --- a/test/test55.c +++ b/test/test55.c @@ -1,3 +1,4 @@ +/* Tests for statvfs(2) call family */ #include #include #include @@ -7,11 +8,11 @@ #include #define TRIALS 10 #define SIZE 65536 +#define FSMAX 64 int max_error = 3; #include "common.h" - int subtest; char *filename = "statvfs_test_XXXXXX"; @@ -36,7 +37,7 @@ static void create_file(void) if (close(fd) < 0) e(3); } -int main(int argc, char *argv[]) +static void test55a(void) { struct statvfs stats; unsigned long f_bsize, f_bsize_new; @@ -50,56 +51,158 @@ int main(int argc, char *argv[]) unsigned long f_fsid, f_fsid_new; unsigned long f_flag, f_flag_new; unsigned long f_namemax, f_namemax_new; + + subtest = 1; + + if (statvfs(".", &stats) < 0) e(1); + + f_bsize = stats.f_bsize ; + f_frsize = stats.f_frsize ; + f_blocks = stats.f_blocks ; + f_bfree = stats.f_bfree ; + f_bavail = stats.f_bavail ; + f_files = stats.f_files ; + f_ffree = stats.f_ffree ; + f_favail = stats.f_favail ; + f_fsid = stats.f_fsid ; + f_flag = stats.f_flag ; + f_namemax = stats.f_namemax; + + create_file(); + + if (statvfs(".", &stats) < 0) e(2); + if (unlink(filename) < 0) e(3); + + f_bsize_new = stats.f_bsize ; + f_frsize_new = stats.f_frsize ; + f_blocks_new = stats.f_blocks ; + f_bfree_new = stats.f_bfree ; + f_bavail_new = stats.f_bavail ; + f_files_new = stats.f_files ; + f_ffree_new = stats.f_ffree ; + f_favail_new = stats.f_favail ; + f_fsid_new = stats.f_fsid ; + f_flag_new = stats.f_flag ; + f_namemax_new = stats.f_namemax; + + if (!((f_bsize == f_bsize_new) && + (f_frsize == f_frsize_new) && + (f_blocks == f_blocks_new) && + (f_bfree > f_bfree_new) && + (f_bavail > f_bavail_new) && + (f_files == f_files_new) && + (f_ffree == f_ffree_new + 1) && + (f_favail == f_favail_new + 1) && + (f_fsid == f_fsid_new) && + (f_flag == f_flag_new) && + (f_namemax == f_namemax_new))) { + e(4); + } +} + +static int do_getvfsstat(struct statvfs *buf, size_t bufsz, int flags, + int count) +{ + int i, j; + + if (getvfsstat(buf, bufsz, flags) != count) e(101); + + /* All file system identifiers should be unique. */ + for (i = 0; i < count - 1; i++) { + for (j = i + 1; j < count; j++) { + if (buf[i].f_fsid == buf[j].f_fsid) e(102); + if (!memcmp(&buf[i].f_fsidx, &buf[j].f_fsidx, + sizeof(buf[j].f_fsidx))) e(103); + } + } + + /* Expect one root file system. */ + j = -1; + for (i = 0; i < count; i++) { + if (!strcmp(buf[i].f_mntonname, "/")) { + if (j != -1) e(104); + j = i; + } + } + if (j == -1) e(105); + + return j; +} + +static void compare_statvfs(struct statvfs *st1, struct statvfs *st2) +{ + int i; + + /* The structures should basically be identical, but a background + * process calling statvfs for some reason might screw things up. + * Thus, we only compare fields that we know should be identical. + * For the strings, we use memcmp rather than strcmp to ensure that + * no garbage is left in the fields. + */ + if (st1->f_flag != st2->f_flag) e(201); + if (st1->f_bsize != st2->f_bsize) e(202); + if (st1->f_frsize != st2->f_frsize) e(203); + if (st1->f_iosize != st2->f_iosize) e(204); + + if (st1->f_fsid != st2->f_fsid) e(205); + if (memcmp(&st1->f_fsidx, &st2->f_fsidx, sizeof(st1->f_fsidx))) e(206); + + if (st1->f_namemax != st2->f_namemax) e(207); + if (st1->f_owner != st2->f_owner) e(208); + + for (i = 0; i < sizeof(st1->f_spare) / sizeof(st1->f_spare[0]); i++) { + if (st1->f_spare[i] != 0) e(209); + if (st2->f_spare[i] != 0) e(210); + } + + if (memcmp(st1->f_fstypename, st2->f_fstypename, + sizeof(st1->f_fstypename))) e(211); + if (memcmp(st1->f_mntonname, st2->f_mntonname, + sizeof(st1->f_mntonname))) e(212); + if (memcmp(st1->f_mntfromname, st2->f_mntfromname, + sizeof(st1->f_mntfromname))) e(213); +} + +static void test55b(void) +{ + static struct statvfs buf[FSMAX]; + struct statvfs rootbuf; + int count, root; + + subtest = 2; + + count = getvfsstat(NULL, 0, ST_WAIT); + if (count < 2) e(1); /* we have at least the root FS and ProcFS */ + if (count > FSMAX) e(2); + + if (getvfsstat(buf, 0, ST_WAIT) != 0) e(3); + if (getvfsstat(buf, sizeof(buf[0]) - 1, ST_WAIT) != 0) e(4); + if (getvfsstat(buf, sizeof(buf[0]), ST_WAIT) != 1) e(5); + if (getvfsstat(buf, sizeof(buf[0]) + 1, ST_WAIT) != 1) e(6); + if (getvfsstat(buf, sizeof(buf[0]) * 2, ST_WAIT) != 2) e(7); + + /* We assume that nothing is being un/mounted right now. */ + root = do_getvfsstat(buf, sizeof(buf), ST_WAIT, count); + + /* Compare cached and uncached copies. */ + if (statvfs1("/", &rootbuf, ST_NOWAIT) != 0) e(13); + compare_statvfs(&buf[root], &rootbuf); + + /* Do the same again, but now the other way around. */ + rootbuf = buf[root]; + root = do_getvfsstat(buf, sizeof(buf), ST_NOWAIT, count); + compare_statvfs(&buf[root], &rootbuf); +} + +int main(int argc, char **argv) +{ int i; start(55); - subtest = 1; for(i = 0; i < TRIALS; i++) { - if (statvfs(".", &stats) < 0) e(1); - - f_bsize = stats.f_bsize ; - f_frsize = stats.f_frsize ; - f_blocks = stats.f_blocks ; - f_bfree = stats.f_bfree ; - f_bavail = stats.f_bavail ; - f_files = stats.f_files ; - f_ffree = stats.f_ffree ; - f_favail = stats.f_favail ; - f_fsid = stats.f_fsid ; - f_flag = stats.f_flag ; - f_namemax = stats.f_namemax; - - create_file(); - - if (statvfs(".", &stats) < 0) e(2); - if (unlink(filename) < 0) e(3); - - f_bsize_new = stats.f_bsize ; - f_frsize_new = stats.f_frsize ; - f_blocks_new = stats.f_blocks ; - f_bfree_new = stats.f_bfree ; - f_bavail_new = stats.f_bavail ; - f_files_new = stats.f_files ; - f_ffree_new = stats.f_ffree ; - f_favail_new = stats.f_favail ; - f_fsid_new = stats.f_fsid ; - f_flag_new = stats.f_flag ; - f_namemax_new = stats.f_namemax; - - if (!((f_bsize == f_bsize_new) && - (f_frsize == f_frsize_new) && - (f_blocks == f_blocks_new) && - (f_bfree > f_bfree_new) && - (f_bavail > f_bavail_new) && - (f_files == f_files_new) && - (f_ffree == f_ffree_new + 1) && - (f_favail == f_favail_new + 1) && - (f_fsid == f_fsid_new) && - (f_flag == f_flag_new) && - (f_namemax == f_namemax_new))) { - e(4); - } + test55a(); + test55b(); } quit(); diff --git a/test/test56.c b/test/test56.c index 0b1b3197a..0c428d36e 100644 --- a/test/test56.c +++ b/test/test56.c @@ -599,7 +599,11 @@ void test_listen(void) errno = 0; rc = listen(0, 0); - if (!(rc == -1 && errno == ENOTTY)) { + /* Test on errno disabled here: there's currently no telling what this + * will return. POSIX says it should be ENOTSOCK, MINIX3 libc returns + * ENOSYS, and we used to test for ENOTTY here.. + */ + if (!(rc == -1)) { test_fail("listen(0, 0) should have failed"); } diff --git a/test/test72.c b/test/test72.c index c87037332..521b9c74d 100644 --- a/test/test72.c +++ b/test/test72.c @@ -224,16 +224,6 @@ panic(const char *fmt, ...) exit(1); } -int vm_forgetblock(u64_t id) -{ - return ENOSYS; -} - -void vm_forgetblocks(void) -{ - return; -} - int vm_info_stats(struct vm_stats_info *vsi) { @@ -274,6 +264,11 @@ void *vm_map_cacheblock(u32_t dev, u64_t dev_offset, return MAP_FAILED; } +int vm_clear_cache(u32_t dev) +{ + return 0; +} + int main(int argc, char *argv[]) { diff --git a/test/test76.c b/test/test76.c new file mode 100644 index 000000000..062ccf4ce --- /dev/null +++ b/test/test76.c @@ -0,0 +1,446 @@ +/* Tests for interrupting VFS calls - by D.C. van Moolenbroek */ +/* This test needs to be run as root; otherwise, openpty() won't work. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ITERATIONS 1 + +#include "common.h" + +/* + * This signal handler does nothing. It just needs to be triggered, so that + * PM will tell VFS to unpause this process. + */ +static void dummy_handler(int sig) +{ + /* Nothing. */ +} + +/* + * Interrupt a select(2) call. + */ +static void +test76a(void) +{ + struct sigaction act, oact; + struct itimerval it; + struct sockaddr_in sin; + struct timeval tv; + fd_set set; + int tfd[2], pfd[2], sfd, maxfd; + + subtest = 1; + + act.sa_handler = dummy_handler; + sigfillset(&act.sa_mask); + act.sa_flags = 0; + if (sigaction(SIGALRM, &act, &oact) < 0) e(1); + + memset(&it, 0, sizeof(it)); + it.it_value.tv_sec = 0; + it.it_value.tv_usec = 10000; + if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(2); + + /* First try without any file descriptors. */ + tv.tv_sec = 1; + tv.tv_usec = 0; + if (select(0, NULL, NULL, NULL, &tv) >= 0) e(3); + if (errno != EINTR) e(4); + + /* Then try with different types of file descriptors, all blocking. */ + if (openpty(&tfd[0], &tfd[1], NULL, NULL, NULL) < 0) e(5); + + FD_ZERO(&set); + FD_SET(tfd[0], &set); /* reading from the PTY master should block */ + maxfd = tfd[0]; + + if (pipe(pfd) < 0) e(6); + FD_SET(pfd[0], &set); /* reading from an empty pipe should block */ + if (maxfd < pfd[0]) maxfd = pfd[0]; + + if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) e(7); + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + /* Binding to an arbitrary port is fine. */ + if (bind(sfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) e(8); + + if (listen(sfd, 1) < 0) e(9); + + FD_SET(sfd, &set); /* reading from a listening socket should block */ + if (maxfd < sfd) maxfd = sfd; + + memset(&it, 0, sizeof(it)); + it.it_value.tv_sec = 0; + it.it_value.tv_usec = 100000; + if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(10); + + tv.tv_sec = 1; + tv.tv_usec = 0; + if (select(maxfd + 1, &set, NULL, NULL, &tv) >= 0) e(11); + if (errno != EINTR) e(12); + + if (close(tfd[0]) < 0) e(13); + if (close(tfd[1]) < 0) e(14); + if (close(pfd[0]) < 0) e(15); + if (close(pfd[1]) < 0) e(16); + if (close(sfd) < 0) e(17); + + if (sigaction(SIGUSR1, &oact, NULL) < 0) e(18); +} + +/* + * Interrupt reads and writes to a pipe. POSIX states that if the operation + * was partially successful, the number of bytes written so far should be + * returned; otherwise, the we should get the normal EINTR. + */ +static void +test76b(void) +{ + struct sigaction act, oact; + struct itimerval it; + char *buf; + int pfd[2]; + + subtest = 2; + + if ((buf = malloc(PIPE_BUF * 2)) == NULL) e(1); + + if (pipe(pfd) < 0) e(2); + + act.sa_handler = dummy_handler; + sigfillset(&act.sa_mask); + act.sa_flags = 0; + if (sigaction(SIGALRM, &act, &oact) < 0) e(3); + + memset(&it, 0, sizeof(it)); + it.it_value.tv_sec = 0; + it.it_value.tv_usec = 10000; + if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(4); + + /* + * This write is too large for the pipe, so it will block until the + * signal arrives. When being interrupted, it should return the pipe + * size, as that is the part that has been filled successfully so far. + */ + if (write(pfd[1], buf, PIPE_BUF * 2) != PIPE_BUF) e(5); + + /* + * Since the write partially succeeded, we should be able to read all + * we wrote so far, without blocking. + */ + if (read(pfd[0], buf, PIPE_BUF) != PIPE_BUF) e(6); + + /* We should now be able to fill the pipe up to its full size again. */ + if (write(pfd[1], buf, PIPE_BUF) != PIPE_BUF) e(7); + + memset(&it, 0, sizeof(it)); + it.it_value.tv_sec = 0; + it.it_value.tv_usec = 10000; + if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(8); + + /* Now interrupt a write attempt on a full pipe. */ + if (write(pfd[1], buf, 1) >= 0) e(9); + if (errno != EINTR) e(10); + + /* Empty the pipe again. */ + if (read(pfd[0], buf, PIPE_BUF) != PIPE_BUF) e(11); + + memset(&it, 0, sizeof(it)); + it.it_value.tv_sec = 0; + it.it_value.tv_usec = 10000; + if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(12); + + /* Now interrupt a read on an empty pipe. */ + if (read(pfd[0], buf, PIPE_BUF) >= 0) e(13); + if (errno != EINTR) e(14); + + if (close(pfd[0]) < 0) e(15); + if (close(pfd[1]) < 0) e(16); + + if (sigaction(SIGUSR1, &oact, NULL) < 0) e(17); + + free(buf); +} + +/* + * Interrupt an ioctl(2) call. We use an alarm to interrupt an accept(3) call + * on a TCP socket - the accept procedure is (currently) implemented using + * ioctl(2) calls. + */ +static void +test76c(void) +{ + struct sigaction act, oact; + struct itimerval it; + struct sockaddr_in sin; + socklen_t len; + int sfd; + + subtest = 3; + + if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) e(1); + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + /* Binding to an arbitrary port is fine. */ + if (bind(sfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) e(2); + + if (listen(sfd, 1) < 0) e(3); + + act.sa_handler = dummy_handler; + sigfillset(&act.sa_mask); + act.sa_flags = 0; + if (sigaction(SIGALRM, &act, &oact) < 0) e(4); + + memset(&it, 0, sizeof(it)); + it.it_value.tv_sec = 0; + it.it_value.tv_usec = 10000; + if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(5); + + /* This will block until the timer fires. */ + len = sizeof(sin); + if (accept(sfd, (struct sockaddr *)&sin, &len) >= 0) e(6); + if (errno != EINTR) e(7); + + if (close(sfd) < 0) e(8); + + if (sigaction(SIGUSR1, &oact, NULL) < 0) e(9); +} + +/* + * Try to trigger semi-concurrent processing of normal system calls and + * postponed PM requests for a single process within VFS. + */ +static void +test76d(void) +{ + struct utsname name; + struct sigaction act, oact; + struct itimerval it; + int r, fd, pfd[2], count, status; + time_t stime, etime, runtime = 30 /*seconds*/; + char buf[3], *pbuf; + + subtest = 4; + + /* This test would kill wimpy platforms such as ARM. */ + if (uname(&name) < 0) e(1); + if (!strcmp(name.machine, "arm")) return; + + act.sa_handler = dummy_handler; + sigfillset(&act.sa_mask); + act.sa_flags = 0; + if (sigaction(SIGALRM, &act, &oact) < 0) e(2); + + if (pipe(pfd) < 0) e(3); + + /* Pre-fill the pipe. */ + if ((pbuf = malloc(PIPE_BUF - 1)) == NULL) e(4); + + if (write(pfd[1], pbuf, PIPE_BUF - 1) != PIPE_BUF - 1) e(5); + + free(pbuf); + + switch (fork()) { + case 0: + if (close(pfd[1]) < 0) e(6); + + /* Read from the pipe, but more slowly than the writer. */ + while ((r = read(pfd[0], buf, 2)) != 0) + if (r < 0) e(7); + + exit(0); + case -1: + e(8); + default: + break; + } + + switch (fork()) { + case 0: + if (close(pfd[0]) < 0) e(9); + + time(&stime); + + /* Start an alarm mayhem. */ + it.it_value.tv_sec = 0; + it.it_value.tv_usec = 1; + it.it_interval.tv_sec = 0; + it.it_interval.tv_usec = 1; + if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(10); + + /* + * Then start writing to the pipe, in such a way that the + * write operation will be suspended in every so many cases. + */ + do { + if (write(pfd[1], buf, 3) < 0 && errno != EINTR) + e(11); + + time(&etime); + } while ((int)(etime - stime) < runtime); + + exit(0); + case -1: + e(12); + default: + break; + } + + if (close(pfd[0]) < 0) e(13); + if (close(pfd[1]) < 0) e(14); + + /* + * First give the two processes a while to run regularly. Then start + * creating additional noise to keep the VFS worker threads busy. + */ + runtime /= 2; + + sleep(runtime); + + /* + * As of writing, VFS has less than 20 worker threads. Create more + * processes than that. + */ + for (count = 2; count < 20; count++) { + switch (fork()) { + case 0: + time(&stime); + + do { + /* + * Opening a character device blocks the + * calling thread, hopefully causing work to be + * queued. Sadly, in practice, the high + * priorities of system processes prevent this + * case from occurring frequently. It works + * better with a driver that has a priority + * below that of of user processes. + */ + if ((fd = open("/dev/null", O_WRONLY)) < 0) + e(15); + + close(fd); + + time(&etime); + } while ((int)(etime - stime) < runtime); + + exit(0); + case -1: + e(16); + default: + break; + } + } + + /* Wait for all children to shut down. */ + while (count-- > 0) { + if (wait(&status) <= 0) e(17); + if (!WIFEXITED(status)) e(18); + if (WEXITSTATUS(status) != 0) e(19); + } + + if (sigaction(SIGUSR1, &oact, NULL) < 0) e(20); +} + +/* + * Try to get a nonblocking select(2) call to be interrupted by a signal. + * In the future, VFS should prevent this from happening at all; for now, we + * just want to make sure it does not result in disaster when it does happen. + */ +static void +test76e(void) +{ + struct utsname name; + struct sigaction act, oact; + struct itimerval it; + struct timeval tv; + fd_set set; + int tfd[2], left; + + subtest = 5; + + /* This test would kill wimpy platforms such as ARM. */ + if (uname(&name) < 0) e(1); + if (!strcmp(name.machine, "arm")) return; + + if (openpty(&tfd[0], &tfd[1], NULL, NULL, NULL) < 0) e(2); + + act.sa_handler = dummy_handler; + sigfillset(&act.sa_mask); + act.sa_flags = 0; + if (sigaction(SIGALRM, &act, &oact) < 0) e(3); + + /* + * Start an alarm mayhem. We have to try to get a signal in between + * VFS sending a select request to TTY, and TTY replying to VFS with + * initial results. + */ + it.it_value.tv_sec = 0; + it.it_value.tv_usec = 1; + it.it_interval.tv_sec = 0; + it.it_interval.tv_usec = 1; + if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(4); + + /* + * Now issue nonblocking selects until we get interrupted, or until + * we have gone through a hardcoded maximum of attempts. + */ + left = 100000; + do { + if (--left == 0) break; + + FD_ZERO(&set); + FD_SET(tfd[0], &set); /* reading from master should block */ + + tv.tv_sec = 0; + tv.tv_usec = 0; + } while (select(2, &set, NULL, NULL, &tv) >= 0); + + if (left > 0 && errno != EINTR) e(5); + + it.it_value.tv_sec = 0; + it.it_value.tv_usec = 0; + if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(6); + + /* The call failed, so the set must be unmodified. */ + if (left > 0 && !FD_SET(tfd[0], &set)) e(7); + + if (close(tfd[0]) < 0) e(8); + if (close(tfd[1]) < 0) e(9); + + if (sigaction(SIGUSR1, &oact, NULL) < 0) e(10); +} + +int +main(int argc, char **argv) +{ + int i, m; + + start(76); + + if (argc == 2) + m = atoi(argv[1]); + else + m = 0xFF; + + for (i = 0; i < ITERATIONS; i++) { + if (m & 0x01) test76a(); + if (m & 0x02) test76b(); + if (m & 0x04) test76c(); + if (m & 0x08) test76d(); + if (m & 0x10) test76e(); + } + + quit(); +} diff --git a/test/test77.c b/test/test77.c new file mode 100644 index 000000000..b634a0091 --- /dev/null +++ b/test/test77.c @@ -0,0 +1,486 @@ +/* Tests for opening/closing pseudo terminals - by D.C. van Moolenbroek */ +/* This test needs to be run as root; otherwise, openpty() won't work. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ITERATIONS 10 + +#include "common.h" + +static int sighups; /* number of SIGHUP signals received */ + +/* + * Signal handler for SIGHUP and SIGUSR1. + */ +void +signal_handler(int sig) +{ + if (sig == SIGHUP) + sighups++; +} + +/* + * Set the slave side of the pseudo terminal to raw mode. This simplifies + * testing communication. + */ +static void +make_raw(int slavefd) +{ + struct termios tios; + + if (tcgetattr(slavefd, &tios) < 0) e(100); + + cfmakeraw(&tios); + + if (tcsetattr(slavefd, TCSANOW, &tios) < 0) e(101); +} + +/* + * See if the given pseudo terminal can successfully perform basic + * communication between master and slave. + */ +static void +test_comm(int masterfd, int slavefd) +{ + char c; + + make_raw(slavefd); + + c = 'A'; + if (write(masterfd, &c, sizeof(c)) != sizeof(c)) e(200); + if (read(slavefd, &c, sizeof(c)) != sizeof(c)) e(201); + if (c != 'A') e(202); + + c = 'B'; + if (write(slavefd, &c, sizeof(c)) != sizeof(c)) e(203); + if (read(masterfd, &c, sizeof(c)) != sizeof(c)) e(204); + if (c != 'B') e(205); + + c = 'C'; + if (write(masterfd, &c, sizeof(c)) != sizeof(c)) e(206); + if (read(slavefd, &c, sizeof(c)) != sizeof(c)) e(207); + if (c != 'C') e(208); + + c = 'D'; + if (write(slavefd, &c, sizeof(c)) != sizeof(c)) e(209); + if (read(masterfd, &c, sizeof(c)) != sizeof(c)) e(210); + if (c != 'D') e(211); +} + +/* + * Get device node names for the master and slave end of a free pseudo + * terminal. We don't want to replicate the entire openpty(3) logic here, so + * start by letting openpty(3) do the work for us. We make the assumption that + * nobody snatches the pair while we are running. + */ +static void +get_names(char pname[PATH_MAX], char tname[PATH_MAX]) +{ + int len, masterfd, slavefd; + + if (openpty(&masterfd, &slavefd, tname, NULL, NULL) < 0) e(300); + + /* + * openpty(3) gives us only the slave name, but we also need the master + * name. + */ + strlcpy(pname, tname, PATH_MAX); + len = strlen(_PATH_DEV); + + if (strncmp(pname, _PATH_DEV, len)) e(301); + + /* If this fails, this test needs to be updated. */ + if (pname[len] != 't') e(302); + + pname[len] = 'p'; + + test_comm(masterfd, slavefd); + + if (close(masterfd) < 0) e(303); + if (close(slavefd) < 0) e(304); +} + +/* + * Test various orders of opening and closing the master and slave sides of a + * pseudo terminal, as well as opening/closing one side without ever opening + * the other. + */ +static void +test77a(void) +{ + struct sigaction act, oact; + char pname[PATH_MAX], tname[PATH_MAX]; + int masterfd, slavefd; + + subtest = 1; + + /* We do not want to get SIGHUP signals in this test. */ + memset(&act, 0, sizeof(act)); + act.sa_handler = SIG_IGN; + if (sigaction(SIGHUP, &act, &oact) < 0) e(1); + + /* Get master and slave device names for a free pseudo terminal. */ + get_names(pname, tname); + + /* Try opening and then closing the master. */ + if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(2); + + if (close(masterfd) < 0) e(3); + + /* Now see if we can reopen the master as well as the slave. */ + if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(4); + if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(5); + + test_comm(masterfd, slavefd); + + /* In the meantime, test different closing orders. This is order A. */ + if (close(slavefd) < 0) e(6); + if (close(masterfd) < 0) e(7); + + /* Now try opening the pair again. */ + if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(8); + if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(9); + + test_comm(masterfd, slavefd); + + if (close(slavefd) < 0) e(10); + + /* + * Try reopening the slave after closing it. It is not very important + * that this works, but the TTY driver should currently support it. + */ + if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(11); + + test_comm(masterfd, slavefd); + + /* This is closing order B. This may or may not cause a SIGHUP. */ + if (close(masterfd) < 0) e(12); + if (close(slavefd) < 0) e(13); + + /* Try the normal open procedure. */ + if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(14); + if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(15); + + test_comm(masterfd, slavefd); + + if (close(slavefd) < 0) e(16); + if (close(masterfd) < 0) e(17); + + /* Try reopening and closing the slave, without opening the master. */ + if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(18); + + if (close(slavefd) < 0) e(19); + + /* Again, try the normal open procedure. */ + if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(20); + if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(21); + + test_comm(masterfd, slavefd); + + if (close(slavefd) < 0) e(22); + if (close(masterfd) < 0) e(23); + + /* Finally, try opening the slave first. */ + if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(24); + if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(25); + + test_comm(masterfd, slavefd); + + if (close(slavefd) < 0) e(26); + if (close(masterfd) < 0) e(27); + + if (sigaction(SIGHUP, &oact, NULL) < 0) e(28); +} + +/* + * Test opening a single side multiple times. + */ +static void +test77b(void) +{ + char pname[PATH_MAX], tname[PATH_MAX]; + int masterfd, slavefd, extrafd; + + subtest = 2; + + /* Get master and slave device names for a free pseudo terminal. */ + get_names(pname, tname); + + /* It must not be possible to open the master multiple times. */ + if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(1); + if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(2); + + test_comm(masterfd, slavefd); + + if ((extrafd = open(pname, O_RDWR | O_NOCTTY)) >= 0) e(3); + if (errno != EIO) e(4); + + test_comm(masterfd, slavefd); + + if (close(slavefd) < 0) e(5); + if (close(masterfd) < 0) e(6); + + /* The slave can be opened multiple times, though. */ + if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(7); + if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(8); + + test_comm(masterfd, slavefd); + + if ((extrafd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(9); + + test_comm(masterfd, extrafd); + test_comm(masterfd, slavefd); + + if (close(slavefd) < 0) e(10); + if (close(extrafd) < 0) e(11); + if (close(masterfd) < 0) e(12); +} + +/* + * Test communication on half-open pseudo terminals. + */ +static void +test77c(void) +{ + struct sigaction act, oact; + char pname[PATH_MAX], tname[PATH_MAX]; + int masterfd, slavefd; + char c; + + subtest = 3; + + /* We do not want to get SIGHUP signals in this test. */ + memset(&act, 0, sizeof(act)); + act.sa_handler = SIG_IGN; + if (sigaction(SIGHUP, &act, &oact) < 0) e(1); + + /* Get master and slave device names for a free pseudo terminal. */ + get_names(pname, tname); + + if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(2); + + /* Writes to the master should be buffered until there is a slave. */ + c = 'E'; + if (write(masterfd, &c, sizeof(c)) != sizeof(c)) e(3); + + if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(4); + + make_raw(slavefd); + + if (read(slavefd, &c, sizeof(c)) != sizeof(c)) e(5); + if (c != 'E') e(6); + + /* Discard the echo on the master. */ + if (tcflush(slavefd, TCOFLUSH) != 0) e(7); + + test_comm(masterfd, slavefd); + + if (close(slavefd) < 0) e(8); + + /* Writes to the master after the slave has been closed should fail. */ + if (write(masterfd, &c, sizeof(c)) >= 0) e(9); + if (errno != EIO) e(10); + + if (close(masterfd) < 0) e(11); + + /* Writes to the slave should be buffered until there is a master. */ + if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(12); + + make_raw(slavefd); + + c = 'F'; + if (write(slavefd, &c, sizeof(c)) != sizeof(c)) e(13); + + if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(14); + + if (read(masterfd, &c, sizeof(c)) != sizeof(c)) e(15); + if (c != 'F') e(16); + + test_comm(masterfd, slavefd); + + if (close(masterfd) < 0) e(17); + + if (write(slavefd, &c, sizeof(c)) >= 0) e(18); + if (errno != EIO) e(19); + + if (close(slavefd) < 0) e(20); + + if (sigaction(SIGHUP, &oact, NULL) < 0) e(21); +} + +/* + * Test opening the slave side with and without the O_NOCTTY flag. + */ +static void +test77d(void) +{ + char pname[PATH_MAX], tname[PATH_MAX]; + int masterfd, slavefd; + + subtest = 4; + + /* Get master and slave device names for a free pseudo terminal. */ + get_names(pname, tname); + + /* Make ourselves process group leader if we aren't already. */ + (void) setsid(); + + if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(1); + + /* + * Opening the slave with O_NOCTTY should not change its controlling + * terminal. + */ + switch (fork()) { + case 0: + if (setsid() < 0) e(2); + + if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(3); + + if (open("/dev/tty", O_RDWR) >= 0) e(4); + if (errno != ENXIO) e(5); + + exit(0); + case -1: + e(6); + default: + break; + } + + if (wait(NULL) <= 0) e(7); + + if (close(masterfd) < 0) e(8); + + if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(9); + + /* + * Opening the slave without O_NOCTTY should change its controlling + * terminal, though. + */ + switch (fork()) { + case 0: + if (setsid() < 0) e(10); + + if ((slavefd = open(tname, O_RDWR)) < 0) e(11); + + if (open("/dev/tty", O_RDWR) < 0) e(12); + + exit(0); + case -1: + e(13); + default: + break; + } + + if (wait(NULL) <= 0) e(14); + + if (close(masterfd) < 0) e(15); +} + +/* + * Test receiving of SIGHUP on master hang-up. All of the tests so far have + * ignored SIGHUP, and probably would not have received one anyway, since the + * process was not its own session leader. Time to test this aspect. + */ +static void +test77e(void) +{ + struct sigaction act, hup_oact, usr_oact; + sigset_t set, oset; + char pname[PATH_MAX], tname[PATH_MAX]; + int masterfd, slavefd; + + subtest = 5; + + /* Get master and slave device names for a free pseudo terminal. */ + get_names(pname, tname); + + memset(&act, 0, sizeof(act)); + act.sa_handler = signal_handler; + if (sigaction(SIGHUP, &act, &hup_oact) < 0) e(1); + + memset(&act, 0, sizeof(act)); + act.sa_handler = signal_handler; + if (sigaction(SIGUSR1, &act, &usr_oact) < 0) e(2); + + sigemptyset(&set); + sigaddset(&set, SIGHUP); + sigaddset(&set, SIGUSR1); + if (sigprocmask(SIG_BLOCK, &set, &oset) < 0) e(3); + + sighups = 0; + + /* Make ourselves process group leader if we aren't already. */ + (void) setsid(); + + if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(4); + + switch (fork()) { + case 0: + if (close(masterfd) < 0) e(5); + + /* Become session leader. */ + if (setsid() < 0) e(6); + + if ((slavefd = open(tname, O_RDWR)) < 0) e(7); + + /* Tell the parent we are ready. */ + kill(getppid(), SIGUSR1); + + /* We should now get a SIGHUP. */ + set = oset; + if (sigsuspend(&set) >= 0) e(8); + + if (sighups != 1) e(9); + + exit(0); + case -1: + e(10); + default: + break; + } + + /* Wait for SIGUSR1 from the child. */ + set = oset; + if (sigsuspend(&set) >= 0) e(11); + + /* Closing the master should now raise a SIGHUP signal in the child. */ + if (close(masterfd) < 0) e(12); + + if (wait(NULL) <= 0) e(13); + + if (sigprocmask(SIG_SETMASK, &oset, NULL) < 0) e(14); + + if (sigaction(SIGHUP, &hup_oact, NULL) < 0) e(15); + if (sigaction(SIGUSR1, &usr_oact, NULL) < 0) e(16); +} + +int +main(int argc, char **argv) +{ + int i, m; + + start(77); + + if (argc == 2) + m = atoi(argv[1]); + else + m = 0xFF; + + for (i = 0; i < ITERATIONS; i++) { + if (m & 0x01) test77a(); + if (m & 0x02) test77b(); + if (m & 0x04) test77c(); + if (m & 0x08) test77d(); + if (m & 0x10) test77e(); + } + + quit(); +} diff --git a/test/testvm.c b/test/testvm.c index d42d211a9..847f93e12 100644 --- a/test/testvm.c +++ b/test/testvm.c @@ -177,6 +177,8 @@ main(int argc, char *argv[]) writepipe(&info); + vm_clear_cache(MYDEV); + return 0; } diff --git a/test/testvm.conf b/test/testvm.conf index 24aed285e..ec42c0e25 100644 --- a/test/testvm.conf +++ b/test/testvm.conf @@ -1,7 +1,7 @@ service testvm { ipc ALL; # All system ipc targets allowed system BASIC; # Only basic kernel calls allowed - vm MAPCACHEPAGE SETCACHEPAGE; + vm MAPCACHEPAGE SETCACHEPAGE CLEARCACHE; io NONE; # No I/O range allowed irq NONE; # No IRQ allowed sigmgr rs; # Signal manager is RS diff --git a/test/testvnd.sh b/test/testvnd.sh new file mode 100755 index 000000000..96fdf1833 --- /dev/null +++ b/test/testvnd.sh @@ -0,0 +1,155 @@ +#!/bin/sh + +# Shell script used to test the VNode Disk (VND) driver. + +# The main purpose of this script is to test the ability of the driver to cope +# with regular operational conditions. It also calls the blocktest test suite +# to perform I/O stress testing. It does not aim to cover all of vndconfig(8). + +bomb() { + echo $* + cd .. + rm -rf $TESTDIR + umount /dev/vnd1 >/dev/null 2>&1 + umount /dev/vnd0 >/dev/null 2>&1 + vndconfig -u vnd1 >/dev/null 2>&1 + vndconfig -u vnd0 >/dev/null 2>&1 + exit 1 +} + +PATH=/bin:/usr/bin:/sbin:/usr/sbin +export PATH + +TESTDIR=DIR_VND +export TESTDIR + +echo -n "Test VND " + +# We cannot run the test if vnd0 or vnd1 are in use. +if vndconfig -l vnd0 >/dev/null 2>&1; then + if ! vndconfig -l vnd0 2>/dev/null | grep "not in use" >/dev/null; then + echo "vnd0 in use, skipping test" >&2 + echo "ok" + exit 0 + else + service down vnd0 + fi +fi +if vndconfig -l vnd1 >/dev/null 2>&1; then + if ! vndconfig -l vnd1 2>/dev/null | grep "not in use" >/dev/null; then + echo "vnd1 in use, skipping test" >&2 + echo "ok" + exit 0 + else + service down vnd1 + fi +fi + +rm -rf $TESTDIR +mkdir $TESTDIR +cd $TESTDIR + +mkdir mnt0 +mkdir mnt1 + +# Test persisting a file inside a vnode device. +dd if=/dev/zero of=image0 bs=4096 count=257 2>/dev/null || bomb "out of space?" +vndconfig vnd0 image0 || bomb "unable to configure vnd0" +[ "`devsize /dev/vnd0`" = 2056 ] || bomb "unexpected vnd0 device size" +mkfs.mfs /dev/vnd0 || bomb "unable to mkfs vnd0" +mount -t mfs /dev/vnd0 mnt0 >/dev/null || bomb "unable to mount vnd0" +STRING="Hello, world!" +echo "$STRING" >mnt0/TEST || bomb "unable to create file on vnd0" +umount /dev/vnd0 >/dev/null || bomb "unable to unmount vnd0" +[ ! -f mnt0/TEST ] || bomb "was vnd0 ever really mounted?" +mount -t mfs /dev/vnd0 mnt0 >/dev/null || bomb "unable to mount vnd0" +[ -f mnt0/TEST ] || bomb "test file was not saved across mounts" +[ "`cat mnt0/TEST`" = "$STRING" ] || bomb "test file was corrupted" +umount /dev/vnd0 >/dev/null || bomb "unable to unmount vnd0" +vndconfig -u vnd0 || bomb "unable to unconfigure vnd0" +vndconfig vnd1 image0 || bomb "unable to configure vnd1" +mount -t mfs /dev/vnd1 mnt1 >/dev/null || bomb "unable to mount vnd1" +[ "`cat mnt1/TEST`" = "$STRING" ] || bomb "test file was corrupted" + +# Test nesting images. +dd if=/dev/zero of=mnt1/image1 bs=4096 count=128 2>/dev/null || bomb "dd fail" +vndconfig vnd0 mnt1/image1 +mkfs.mfs /dev/vnd0 || bomb "unable to mkfs vnd0" +mount -t mfs /dev/vnd0 mnt0 >/dev/null || bomb "unable to mount vnd0" +echo "x" >mnt0/TEST2 || bomb "unable to create file on vnd0" +umount mnt1 >/dev/null 2>&1 && bomb "should not be able to unmount vnd1" +umount mnt0 >/dev/null || bomb "unable to unmount vnd0" +umount mnt1 >/dev/null 2>&1 && bomb "should not be able to unmount vnd1" +vndconfig -u vnd0 || bomb "unable to unconfigure vnd0" +cp mnt1/image1 . || bomb "unable to copy image off vnd1" +umount mnt1 >/dev/null || bomb "unable to unmount vnd1" +vndconfig -uS vnd1 || bomb "unable to unconfigure vnd1" +vndconfig -S vnd1 ./image1 +mount -t mfs /dev/vnd1 mnt1 >/dev/null || bomb "unable to mount vnd1" +[ -f mnt1/TEST2 ] || bomb "test file not found, VM cache broken again?" +[ "`cat mnt1/TEST2`" = "x" ] || bomb "test file corrupted" +umount /dev/vnd1 >/dev/null || bomb "unable to unmount vnd1" +vndconfig -u /dev/vnd1 || bomb "unable to unconfigure vnd1" + +# Test a read-only configuration. +SUM=`sha1 image0` +vndconfig -r vnd0 image0 +dd if=/dev/zero of=/dev/vnd0 bs=4096 count=1 2>/dev/null && bomb "dd succeeded" +mount /dev/vnd0 mnt0 >/dev/null 2>&1 && bomb "mounting read-write should fail" +mount -r /dev/vnd0 mnt0 >/dev/null || bomb "unable to mount vnd0" +[ "`cat mnt0/TEST`" = "$STRING" ] || bomb "test file was corrupted" +dd if=/dev/zero of=/dev/vnd0 bs=4096 count=1 2>/dev/null && bomb "dd succeeded" +umount /dev/vnd0 >/dev/null +vndconfig -uS vnd0 +[ "`sha1 image0`" = "$SUM" ] || bomb "read-only file changed" + +# Test geometry and sub/partitions. +vndconfig -c vnd0 image0 512/32/64/2 2>/dev/null && bomb "vndconfig succeeded" +vndconfig -c vnd0 image0 512/32/64/1 || bomb "unable to configure vnd0" +# no need for repartition: nobody is holding the device open +[ "`devsize /dev/vnd0`" = 2048 ] || bomb "geometry not applied to size" +partition -mf /dev/vnd0 8 81:512 81:512* 81:512 81:1+ >/dev/null +partition -f /dev/vnd0p1 81:256 81:1 81:8 81:1+ >/dev/null +dd if=/dev/zero of=/dev/vnd0p1s2 bs=512 count=8 2>/dev/null || bomb "dd failed" +dd if=/dev/zero of=/dev/vnd0p1s2 bs=512 count=9 2>/dev/null && bomb "dd nofail" +mkfs.mfs /dev/vnd0p0 || bomb "unable to mkfs vnd0p1s3" +mkfs.mfs /dev/vnd0p1s3 || bomb "unable to mkfs vnd0p1s3" +mount /dev/vnd0p0 mnt0 >/dev/null || bomb "unable to mount vnd0p0" +mount /dev/vnd0p1s3 mnt1 >/dev/null || bomb "unable to mount vnd0p1s3" +umount /dev/vnd0p0 >/dev/null || bomb "unable to unmount vnd0p0" +umount mnt1 >/dev/null || bomb "unable to unmount vnd0p1s3" +vndconfig -u /dev/vnd0 +vndconfig /dev/vnd1 image1 512/1/1/1025 2>/dev/null && bomb "can config vnd1" +vndconfig /dev/vnd1 image1 512/1/1/1024 2>/dev/null || bomb "can't config vnd1" +[ "`devsize /dev/vnd1`" = 1024 ] || bomb "invalid vnd1 device size" +dd if=/dev/vnd1 of=/dev/null bs=512 count=1024 2>/dev/null || bomb "dd fail" +dd if=/dev/vnd1 of=tmp bs=512 skip=1023 count=2 2>/dev/null +[ "`stat -f '%z' tmp`" = 512 ] || bomb "unexpected dd result" + +# Test miscellaneous stuff. +vndconfig /dev/vnd1 image1 2>/dev/null && bomb "reconfiguring should not work" +# the -r is needed here to pass vndconfig(8)'s open test (which is buggy, too!) +vndconfig -r vnd0 . 2>/dev/null && bomb "config to a directory should not work" +vndconfig vnd0 /dev/vnd1 2>/dev/null && bomb "config to another vnd? horrible!" +diskctl /dev/vnd1 flush >/dev/null || bomb "unable to flush vnd1" +vndconfig -u vnd1 + +# Test the low-level driver API. +vndconfig vnd0 image0 || bomb "unable to configure vnd0" +../tvnd /dev/vnd0 || bomb "API subtest failed" +# the device is now unconfigured, but the driver is still running + +# Invoke the blocktest test set to test various other aspects. +vndconfig -S vnd0 image0 || bomb "unable to configure vnd0" +cd ../blocktest +. support.sh +block_test /dev/vnd0 \ + "rw,min_read=1,min_write=1,element=1,max=16777216,nocontig,silent" || \ + bomb "blocktest test set failed" +vndconfig -u vnd0 || bomb "unable to unconfigure vnd0" + +cd .. +rm -rf $TESTDIR + +echo "ok" +exit 0 diff --git a/test/tvnd.c b/test/tvnd.c new file mode 100644 index 000000000..68b76b26d --- /dev/null +++ b/test/tvnd.c @@ -0,0 +1,53 @@ +/* Tests for the VND driver API. Part of testvnd.sh. */ +#include +#include +#include +#include +#include +#include + +/* + * For now, just test the most dreaded case: the driver being told to use the + * file descriptor used to configure the device. Without appropriate checks, + * this would cause a deadlock in VFS, since the corresponding filp object is + * locked to perform the ioctl(2) call when VFS gets the dupfrom(2) back-call. + */ +int +main(int argc, char **argv) +{ + struct vnd_ioctl vnd; + int fd; + + if (argc != 2) { + fprintf(stderr, "usage: %s /dev/vnd0\n", argv[0]); + return EXIT_FAILURE; + } + + if ((fd = open(argv[1], O_RDONLY)) < 0) { + perror("open"); + return EXIT_FAILURE; + } + + memset(&vnd, 0, sizeof(vnd)); + + if (ioctl(fd, VNDIOCCLR, &vnd) < 0) { + perror("ioctl(VNDIOCCLR)"); + return EXIT_FAILURE; + } + + vnd.vnd_fildes = fd; + + if (ioctl(fd, VNDIOCSET, &vnd) >= 0) { + fprintf(stderr, "ioctl(VNDIOCSET): unexpected success\n"); + return EXIT_FAILURE; + } + + if (errno != EINVAL) { + perror("ioctl(VNDIOCSET)"); + return EXIT_FAILURE; + } + + close(fd); + + return EXIT_SUCCESS; +} diff --git a/usr.bin/stat/stat.c b/usr.bin/stat/stat.c index 8beadb3bf..95d4cf340 100644 --- a/usr.bin/stat/stat.c +++ b/usr.bin/stat/stat.c @@ -44,12 +44,7 @@ __RCSID("$NetBSD: stat.c,v 1.33 2011/01/15 22:54:10 njoly Exp $"); #define HAVE_STRUCT_STAT_ST_BIRTHTIME 1 #define HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC 1 #define HAVE_STRUCT_STAT_ST_MTIMENSEC 1 -#ifdef __minix -/* Not supported in Minix. */ -#define HAVE_DEVNAME 0 -#else /* __minix */ #define HAVE_DEVNAME 1 -#endif /* __minx */ #endif /* HAVE_NBTOOL_CONFIG_H */ #include diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile index 1e5fe653b..8d24dd947 100644 --- a/usr.sbin/Makefile +++ b/usr.sbin/Makefile @@ -10,6 +10,7 @@ SUBDIR= \ pwd_mkdb postinstall \ rdate user \ vipw \ + vnconfig \ zic # LSC MINIX Specific diff --git a/usr.sbin/vnconfig/Makefile b/usr.sbin/vnconfig/Makefile new file mode 100644 index 000000000..491662809 --- /dev/null +++ b/usr.sbin/vnconfig/Makefile @@ -0,0 +1,10 @@ +# $NetBSD: Makefile,v 1.8 2013/06/09 22:00:50 jmmv Exp $ + +PROG= vnconfig +MAN= vnconfig.8 +DPADD+= ${LIBUTIL} +LDADD+= -lutil +LINKS+= ${BINDIR}/vnconfig ${BINDIR}/vndconfig +MLINKS+= vnconfig.8 vndconfig.8 + +.include diff --git a/usr.sbin/vnconfig/vnconfig.8 b/usr.sbin/vnconfig/vnconfig.8 new file mode 100644 index 000000000..5b6ca008d --- /dev/null +++ b/usr.sbin/vnconfig/vnconfig.8 @@ -0,0 +1,195 @@ +.\" $NetBSD: vnconfig.8,v 1.39 2013/06/09 18:39:31 christos Exp $ +.\" +.\" Copyright (c) 1997 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Jason R. Thorpe. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.\" Copyright (c) 1993 University of Utah. +.\" Copyright (c) 1980, 1989, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Systems Programming Group of the University of Utah Computer +.\" Science Department. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)vnconfig.8 8.1 (Berkeley) 6/5/93 +.\" +.Dd June 9, 2013 +.Dt VNDCONFIG 8 +.Os +.Sh NAME +.Nm vndconfig +.Nd configure vnode disks +.Sh SYNOPSIS +.Nm +.Op Fl Scrv +.Ar vnode_disk +.Ar regular_file +.Op Ar geomspec +.Nm +.Fl u +.Op Fl SFv +.Ar vnode_disk +.Nm +.Fl l +.Op Ar vnode_disk +.Sh DESCRIPTION +The +.Nm +command configures vnode pseudo disk devices. +It will associate the vnode disk +.Ar vnode_disk +with the regular file +.Ar regular_file +allowing the latter to be accessed as though it were a disk. +Hence a regular file within the filesystem can be used for swapping +or can contain a filesystem that is mounted in the name space. +The +.Ar vnode_disk +is a special file of raw partition or name of vnode disk like +.Pa vnd0 . +.Pp +Options indicate an action to be performed: +.Bl -tag -width indent +.It Fl c +Configures the device. +If successful, references to +.Ar vnode_disk +will access the contents of +.Ar regular_file . +.Pp +If +.Ar geomspec +is specified, the vnode device will emulate the specified disk geometry. +The format of the +.Ar geomspec +argument is: +.Bd -ragged -offset indent +.Sm off +.Xo Ar secsize Li / Ar nsectors Li / +.Ar ntracks Li / Ar ncylinders Xc +.Sm on +.Ed +.Pp +If geometry is not specified, the driver will choose a default based on 1MB +cylinders. +.Ar secsize +is the number of bytes per sector. +It must be an even multiple of 512. +.Ar nsectors +is the number of sectors per track. +.Ar ntracks +is the number of tracks per cylinder. +.Ar ncylinders +is the number of cylinders in the device. +.It Fl S +Do not start or stop the corresponding device driver instance. +.It Fl F +Force unconfiguration if the device is in use. +Does not imply +.Fl u . +.It Fl l +List the vnd devices and indicate which ones are in use. +If a specific +.Ar vnode_disk +is given, then only that will be described. +.It Fl r +Configure the device as read-only. +.It Fl u +Unconfigures the device. +.It Fl v +Print messages to stdout describing actions taken. +.El +.Pp +If no action option is given, +.Fl c +is assumed. +.Sh FILES +.Bl -tag -width /dev/vnd* -compact +.It Pa /dev/vnd* +.El +.Sh EXAMPLES +.Dl vndconfig vnd0 /tmp/diskimage +or +.Dl vndconfig /dev/vnd0 /tmp/diskimage +.Pp +Configures the vnode disk +.Pa vnd0 . +.Pp +.Dl vndconfig vnd0 /tmp/floppy.img 512/18/2/80 +.Pp +Configures the vnode disk +.Pa vnd0 +emulating the geometry of 512 bytes per sector, 18 sectors per track, +2 tracks per cylinder, and 80 cylinders total. +.Pp +.Dl vndconfig -u vnd0 +.Pp +Unconfigures the +.Pa vnd0 +device. +.Sh NOTES +If +.Ic vnconfig -uF +is used and the device was still in use, the driver instance +will not be shut down, even if +.Fl S +was not given. One may manually shut down +the service later with +.Ic service down +.Ar vndN +where +.Ar N +is the instance number, or simply +leave the driver running for later reuse. +.Sh SEE ALSO +.Xr opendisk 3 , +.Xr mount 8 , +.Xr umount 8 diff --git a/usr.sbin/vnconfig/vnconfig.c b/usr.sbin/vnconfig/vnconfig.c new file mode 100644 index 000000000..e95f6d2a4 --- /dev/null +++ b/usr.sbin/vnconfig/vnconfig.c @@ -0,0 +1,605 @@ +/* $NetBSD: vnconfig.c,v 1.41 2013/06/09 13:25:40 christos Exp $ */ + +/*- + * Copyright (c) 1997 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 1993 University of Utah. + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: Utah $Hdr: vnconfig.c 1.1 93/12/15$ + * + * @(#)vnconfig.c 8.1 (Berkeley) 12/15/93 + */ + +#include +#include +#include +#ifndef __minix +#include +#include +#include +#include +#else +#include +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define VND_CONFIG 1 +#define VND_UNCONFIG 2 +#define VND_GET 3 + +static int verbose = 0; +static int readonly = 0; +static int force = 0; +static int compressed = 0; +static char *tabname; +#ifdef __minix +static int service = 1; +#endif + +#ifndef __minix +static void show(int, int); +#else +static void show(const char *, int); +#endif +static int config(char *, char *, char *, int); +static int getgeom(struct vndgeom *, char *); +__dead static void usage(void); + +#ifdef __minix +/* + * Start a driver instance for the given vnd name. The return value indicates + * whether the instance has been started successfully. + */ +static int +start_service(char *dev) +{ + char *p, *endp, cmd[PATH_MAX]; + int n, status; + + p = strrchr(dev, '/'); + if (p == NULL) p = dev; + else p++; + + /* + * There are two alternatives to get the instance number for the + * driver: either we scan the given device name, or we obtain its major + * number. We choose to scan the name, because major numbers are more + * likely to change in the future. + */ + if (strncmp(p, "vnd", 3) != 0) + return 0; + n = strtoul(p + 3, &endp, 10); + if (endp[0]) + return 0; + + if (verbose) + printf("%s: starting driver\n", dev); + + snprintf(cmd, sizeof(cmd), + "%s up %s/vnd -label vnd%u -args instance=%u -dev %s", + _PATH_SERVICE, _PATH_DRIVERS, n, n, dev); + + status = system(cmd); + + if (!WIFEXITED(status)) + return 0; + return !WEXITSTATUS(status); +} + +/* + * Stop the driver instance responsible for the given file descriptor. + * The file descriptor is closed upon return. + */ +static void +stop_service(int fd, char *dev) +{ + char cmd[PATH_MAX]; + struct vnd_user vnu; + int openct, stop = 0; + + /* Only shut down the driver if the device is opened once, by us. */ + if (ioctl(fd, DIOCOPENCT, &openct) == 0 && openct == 1) { + /* We let the driver tell us what instance number it has. */ + if (ioctl(fd, VNDIOCGET, &vnu) == 0) + stop = 1; + } + + /* Close the file descriptor before shutting down the driver! */ + (void) close(fd); + + if (stop) { + if (verbose) + printf("%s: stopping driver\n", dev); + + snprintf(cmd, sizeof(cmd), "%s down vnd%u", _PATH_SERVICE, + vnu.vnu_unit); + + system(cmd); + } +} +#endif + +int +main(int argc, char *argv[]) +{ + int ch, rv, action = VND_CONFIG; + +#ifndef __minix + while ((ch = getopt(argc, argv, "Fcf:lrt:uvz")) != -1) { +#else + /* MINIX3: added -S; no support for -f, -t, -z at this time. */ + while ((ch = getopt(argc, argv, "SFclruv")) != -1) { +#endif + switch (ch) { +#ifdef __minix + case 'S': + service = 0; + break; +#endif + case 'F': + force = 1; + break; + case 'c': + action = VND_CONFIG; + break; + case 'f': +#ifndef __minix + if (setdisktab(optarg) == -1) + usage(); +#endif + break; + case 'l': + action = VND_GET; + break; + case 'r': + readonly = 1; + break; + case 't': + tabname = optarg; + break; + case 'u': + action = VND_UNCONFIG; + break; + case 'v': + verbose = 1; + break; + case 'z': + compressed = 1; + readonly = 1; + break; + default: + case '?': + usage(); + /* NOTREACHED */ + } + } + argc -= optind; + argv += optind; + + if (action == VND_CONFIG) { + if ((argc < 2 || argc > 3) || + (argc == 3 && tabname != NULL)) + usage(); + rv = config(argv[0], argv[1], (argc == 3) ? argv[2] : NULL, + action); + } else if (action == VND_UNCONFIG) { + if (argc != 1 || tabname != NULL) + usage(); + rv = config(argv[0], NULL, NULL, action); + } else { /* VND_GET */ +#ifndef __minix + int n, v; + const char *vn; + char path[64]; +#else + int n; +#endif + + if (argc != 0 && argc != 1) + usage(); + +#ifndef __minix + vn = argc ? argv[0] : "vnd0"; + + v = opendisk(vn, O_RDONLY, path, sizeof(path), 0); + if (v == -1) + err(1, "open: %s", vn); +#endif + + if (argc) +#ifndef __minix + show(v, -1); +#else + show(argv[0], -1); +#endif + else { + DIR *dirp; + struct dirent *dp; +#ifndef __minix + __BITMAP_TYPE(, uint32_t, 65536) bm; + + __BITMAP_ZERO(&bm); +#else + char *endp; +#endif + + if ((dirp = opendir(_PATH_DEV)) == NULL) + err(1, "opendir: %s", _PATH_DEV); + + while ((dp = readdir(dirp)) != NULL) { +#ifndef __minix + if (strncmp(dp->d_name, "rvnd", 4) != 0) + continue; + n = atoi(dp->d_name + 4); + if (__BITMAP_ISSET(n, &bm)) + continue; + __BITMAP_SET(n, &bm); + show(v, n); +#else + if (strncmp(dp->d_name, "vnd", 3) != 0) + continue; + n = strtoul(dp->d_name + 3, &endp, 10); + if (endp[0]) + continue; + show(dp->d_name, n); +#endif + } + + closedir(dirp); + } +#ifndef __minix + close(v); +#endif + rv = 0; + } + return rv; +} + +static void +#ifndef __minix +show(int v, int n) +#else +show(const char *vn, int n) +#endif +{ + struct vnd_user vnu; + char *dev; + struct statvfs *mnt; + int i, nmount; +#ifdef __minix + int v; + char path[PATH_MAX]; + + v = opendisk(vn, O_RDONLY, path, sizeof(path), 0); + if (v == -1) { + if (n == -1) + err(1, "open: %s", vn); + else + printf("vnd%d: not in use\n", n); + return; + } +#endif + + vnu.vnu_unit = n; + if (ioctl(v, VNDIOCGET, &vnu) == -1) + err(1, "VNDIOCGET"); + +#ifdef __minix + close(v); +#endif + + if (vnu.vnu_ino == 0) { + printf("vnd%d: not in use\n", vnu.vnu_unit); + return; + } + + printf("vnd%d: ", vnu.vnu_unit); + + dev = devname(vnu.vnu_dev, S_IFBLK); + if (dev != NULL) + nmount = getmntinfo(&mnt, MNT_NOWAIT); + else { + mnt = NULL; + nmount = 0; + } + + if (mnt != NULL) { + for (i = 0; i < nmount; i++) { + if (strncmp(mnt[i].f_mntfromname, "/dev/", 5) == 0 && + strcmp(mnt[i].f_mntfromname + 5, dev) == 0) + break; + } + if (i < nmount) + printf("%s (%s) ", mnt[i].f_mntonname, + mnt[i].f_mntfromname); + else + printf("%s ", dev); + } + else if (dev != NULL) + printf("%s ", dev); + else + printf("dev %llu,%llu ", + (unsigned long long)major(vnu.vnu_dev), + (unsigned long long)minor(vnu.vnu_dev)); + + printf("inode %llu\n", (unsigned long long)vnu.vnu_ino); +} + +static int +config(char *dev, char *file, char *geom, int action) +{ + struct vnd_ioctl vndio; +#ifndef __minix + struct disklabel *lp; +#else + int stop = 0; +#endif + char rdev[MAXPATHLEN + 1]; + int fd, rv; + +#ifdef __minix + /* + * MINIX does not have the concept of raw devices. As such, the access + * checks that apply to opening block devices, automatically apply here + * as well. Therefore, we must open the device as read-only, or we + * would be unable to un-configure a device that was configured as + * read-only: opening such a device as read-write would fail. + */ + fd = opendisk(dev, O_RDONLY, rdev, sizeof(rdev), 0); + + if (fd < 0 && errno == ENXIO && action == VND_CONFIG && service) { + stop = start_service(rdev); + + fd = opendisk(dev, O_RDONLY, rdev, sizeof(rdev), 0); + } +#else + fd = opendisk(dev, O_RDWR, rdev, sizeof(rdev), 0); +#endif + if (fd < 0) { + warn("%s: opendisk", rdev); + return (1); + } + + memset(&vndio, 0, sizeof(vndio)); +#ifdef __GNUC__ + rv = 0; /* XXX */ +#endif + +#ifndef __minix + vndio.vnd_file = file; +#endif + if (geom != NULL) { + rv = getgeom(&vndio.vnd_geom, geom); +#ifdef __minix + if (rv && stop) + stop_service(fd, rdev); +#endif + if (rv != 0) + errx(1, "invalid geometry: %s", geom); + vndio.vnd_flags = VNDIOF_HASGEOM; +#ifndef __minix + } else if (tabname != NULL) { + lp = getdiskbyname(tabname); + if (lp == NULL) + errx(1, "unknown disk type: %s", tabname); + vndio.vnd_geom.vng_secsize = lp->d_secsize; + vndio.vnd_geom.vng_nsectors = lp->d_nsectors; + vndio.vnd_geom.vng_ntracks = lp->d_ntracks; + vndio.vnd_geom.vng_ncylinders = lp->d_ncylinders; + vndio.vnd_flags = VNDIOF_HASGEOM; +#endif + } + + if (readonly) + vndio.vnd_flags |= VNDIOF_READONLY; + +#ifndef __minix + if (compressed) + vndio.vnd_flags |= VNF_COMP; +#endif + + /* + * Clear (un-configure) the device + */ + if (action == VND_UNCONFIG) { + if (force) + vndio.vnd_flags |= VNDIOF_FORCE; + rv = ioctl(fd, VNDIOCCLR, &vndio); +#ifdef VNDIOOCCLR + if (rv && errno == ENOTTY) + rv = ioctl(fd, VNDIOOCCLR, &vndio); +#endif + if (rv) + warn("%s: VNDIOCCLR", rdev); + else if (verbose) + printf("%s: cleared\n", rdev); +#ifdef __minix + if (!rv && service) + stop = 2; +#endif + } + /* + * Configure the device + */ + if (action == VND_CONFIG) { + int ffd; + + ffd = open(file, readonly ? O_RDONLY : O_RDWR); + if (ffd < 0) + warn("%s", file); + else { +#ifndef __minix + (void) close(ffd); +#else + vndio.vnd_fildes = ffd; +#endif + + rv = ioctl(fd, VNDIOCSET, &vndio); +#ifdef VNDIOOCSET + if (rv && errno == ENOTTY) { + rv = ioctl(fd, VNDIOOCSET, &vndio); + vndio.vnd_size = vndio.vnd_osize; + } +#endif +#ifdef __minix + (void) close(ffd); +#endif + if (rv) + warn("%s: VNDIOCSET", rdev); + else if (verbose) { + printf("%s: %" PRIu64 " bytes on %s", rdev, + vndio.vnd_size, file); + if (vndio.vnd_flags & VNDIOF_HASGEOM) + printf(" using geometry %d/%d/%d/%d", + vndio.vnd_geom.vng_secsize, + vndio.vnd_geom.vng_nsectors, + vndio.vnd_geom.vng_ntracks, + vndio.vnd_geom.vng_ncylinders); + printf("\n"); + } + } +#ifdef __minix + if ((ffd < 0 || rv) && service) + stop++; +#endif + } + +#ifdef __minix + if (stop >= 2) + stop_service(fd, rdev); + else +#endif + (void) close(fd); + fflush(stdout); + return (rv < 0); +} + +static int +getgeom(struct vndgeom *vng, char *cp) +{ + char *secsize, *nsectors, *ntracks, *ncylinders; + +#define GETARG(arg) \ + do { \ + if (cp == NULL || *cp == '\0') \ + return (1); \ + arg = strsep(&cp, "/"); \ + if (arg == NULL) \ + return (1); \ + } while (0) + + GETARG(secsize); + GETARG(nsectors); + GETARG(ntracks); + GETARG(ncylinders); + +#undef GETARG + + /* Too many? */ + if (cp != NULL) + return (1); + +#define CVTARG(str, num) \ + do { \ + num = strtol(str, &cp, 10); \ + if (*cp != '\0') \ + return (1); \ + } while (0) + + CVTARG(secsize, vng->vng_secsize); + CVTARG(nsectors, vng->vng_nsectors); + CVTARG(ntracks, vng->vng_ntracks); + CVTARG(ncylinders, vng->vng_ncylinders); + +#undef CVTARG + + return (0); +} + +static void +usage(void) +{ + + (void)fprintf(stderr, "%s%s", +#ifndef __minix + "usage: vnconfig [-crvz] [-f disktab] [-t typename] vnode_disk" + " regular-file [geomspec]\n", + " vnconfig -u [-Fv] vnode_disk\n" +#else + "usage: vnconfig [-Scrv] vnode_disk regular-file [geomspec]\n", + " vnconfig -u [-SFv] vnode_disk\n" +#endif + " vnconfig -l [vnode_disk]\n"); + exit(1); +}