From a037a7016903dba703990f8fb1445b27520ede20 Mon Sep 17 00:00:00 2001 From: David van Moolenbroek Date: Sat, 21 Sep 2013 17:44:05 +0200 Subject: [PATCH] flagday-log WIP, jenkins testing only Squashed commit of the following: commit 7414eb808dfbce800e2dfaa3ca7f5474ba2d3684 Author: David van Moolenbroek Date: Sat Sep 21 17:35:15 2013 +0200 Take LOG out of the boot image Change-Id: Id2629776b53aae46629b04a42c15cbbacac9b949 commit aa33a6af33169916d081f27e22fb7ca458e92022 Author: David van Moolenbroek Date: Sat Sep 21 15:03:20 2013 +0200 Kernel: make SIGKMESS target process list dynamic The set of processes to which a SIGKMESS signal is sent whenever new diagnostics messages are added to the kernel's message buffer, is now no longer hardcoded. Instead, processes can (un)register themselves to receive such notifications, by means of sys_diagctl(). Change-Id: I9d6ac006a5d9bbfad2757587a068fc1ec3cc083e commit 4991d187e7efcf6348fa761c45414938c99bf048 Author: David van Moolenbroek Date: Sat Sep 21 00:58:46 2013 +0200 Rename SYSCTL kernel call to DIAGCTL Change-Id: I1b17373f01808d887dcbeab493838946fbef4ef6 commit 4ac2419358f96fbafc6fdc2df14c716c232d830f Author: David van Moolenbroek Date: Wed Sep 18 20:13:59 2013 +0200 Prevent Jenkins from breaking on old df(1) Change-Id: Ie8e1758bd9de4d5c95c597302f80d568058fbb68 commit 9b17c22cf13b68bf063024be1de56813ea29940b Author: David van Moolenbroek Date: Wed Sep 18 14:09:47 2013 +0200 Add testvnd.sh test script As part of this, change the "run" script to allow certain scripts to be run as root only. Change-Id: I846e41037f9d4f6c7fc0b5ea8250303a7bd72f5d commit 8cde906ba03b1e9aaf2ebb1fdd990452e3d3c016 Author: David van Moolenbroek Date: Wed Sep 18 14:06:46 2013 +0200 Import NetBSD vndconfig(8) The tool has been changed heavily to match our VND driver model. NetBSD is in the process of renaming it from vnconfig(8) to vndconfig(8). To keep things in sync, we have to play along. Change-Id: Ie86df184f03ab00573ea76b43c9caa0412e8321d commit 0088920e85160ebe6f04eb6913a629a2f5c9a582 Author: David van Moolenbroek Date: Wed Sep 18 14:02:17 2013 +0200 Add VND driver, providing loopback devices Change-Id: I40fa695e28c67477a75383e6f1550e451afcab41 commit 0998c7cbcc8eb934f28830f3f5ba2e312c740ae9 Author: David van Moolenbroek Date: Wed Sep 18 13:55:15 2013 +0200 VFS: add dupfrom(2) call This call copies a file descriptor from a remote process into the calling process. The call is for the VND driver only, and in the future, ACLs will prevent any other process from using this call. Change-Id: Ib16fdd1f1a12cb38a70d7e441dad91bc86898f6d commit ca15ee79df5cc00b93464f83e823a02374dcf609 Author: David van Moolenbroek Date: Wed Sep 18 11:46:08 2013 +0200 tests: do not skip installed shell tests When installed, the test scripts lose their ".sh" suffix, causing them to be skipped by the "run" script. With this patch, the tests are no longer specified with ".sh" suffix in the run script, and the suffix is added automatically as necessary. Change-Id: I0b72312e79992b9818559c6546a0e52cd95184c2 commit a1b6eb025e61d23c39c7dfa07281bf8a52256648 Author: David van Moolenbroek Date: Wed Sep 18 13:41:56 2013 +0200 blocktest: prepare to be run as part of tests - fail SEF initialization if any of the subtests failed, so that the party invoking the "service up" can tell whether the test succeeded; - add "nocontig" option, because VM isn't particularly good at allocating contiguous memory; - add "silent" option, because it floods the console otherwise; - allow the device size to be smaller than the maximum transfer size; - install files to installed test directory. Change-Id: I45c818f817c11d90c5f94ae26a2fc49e36e6761e commit 27e85d168b5b0de4bd5dad71110a28ab7de1c506 Author: David van Moolenbroek Date: Wed Sep 18 13:38:36 2013 +0200 Enable devname(3) There is no support for a device name database yet, so this call is expected to be fairly slow. Change-Id: I73aa5f267e2b6921b7d3bbdcc4beac463931132c commit 9db9e3e97cd10f114f3b25e2f9f192023fee409d Author: David van Moolenbroek Date: Sun Sep 15 13:09:00 2013 +0200 libbdev: be less noisy about clean driver restarts Change-Id: Ie02a459c9b544d361ab00bac431ef99de53b0c5f commit 967b189e814cdd02d253d7c877bc4dbd7552f8b8 Author: David van Moolenbroek Date: Sat Sep 14 14:43:53 2013 +0200 Straighten ioctl.h - include all ioctl subheaders, properly listing all letters; - change FBD's ioctl calls to use 'B' instead of 'F', in preparation of the VND driver. Change-Id: Ia718979568cc057f47cf505a89238d5b3b6695d4 commit 0ec080b7a65598d66e8ff01d559993c27e91c026 Author: David van Moolenbroek Date: Sun Sep 15 18:55:42 2013 +0200 VM: readd support for forgetting cached FS blocks Not all services involved in block I/O go through VM to access the blocks they need. As a result, the blocks in VM may become stale, possibly causing corruption when the stale copy is restored by a service that does go through VM later on. This patch restores support for forgetting cached blocks that belong to a particular device, and makes the relevant file systems use this functionality 1) when requested by VFS through REQ_FLUSH, and 2) upon unmount. Change-Id: I0758c5ed8fe4b5ba81d432595d2113175776aff8 commit b13082423d41cbb21f38348c96e5ada4c550b4bd Author: David van Moolenbroek Date: Wed Sep 11 14:50:18 2013 +0200 filter: use libblockdriver Change-Id: Ifbca2482e996ddca58036d45f557165e636fb3fa commit 66d9724e08f8ec256f1fcfba65cb16eec9c62bfb Author: David van Moolenbroek Date: Tue Sep 10 20:25:01 2013 +0200 Rewrite character driver protocol As a side effect, remove the clone style, as the normal device style supports device cloning now. Change-Id: Ie82d1ef0385514a04a8faa139129a617895780b5 commit 0026fc3de77b5f4c70d72eb0320b0b92d9fe0066 Author: David van Moolenbroek Date: Tue Sep 10 16:06:37 2013 +0200 Remove support for reopening character devices Previously, VFS would reopen a character device after a driver crash if the associated file descriptor was opened with the O_REOPEN flag. This patch removes support for this feature. The code was complex, full of uncovered corner cases, and hard to test. Moreover, it did not actually hide the crash from user applications: they would get an error code to indicate that something went wrong, and have to decide based on the nature of the underlying device how to continue. - remove support for O_REOPEN, and make playwave(1) reopen its device; - remove support for the DEV_REOPEN protocol message; - remove all code in VFS related to reopening character devices; - no longer change VFS filp reference count and FD bitmap upon filp invalidation; instead, make get_filp* fail all calls on invalidated FDs except when obtained with the locktype VNODE_OPCL which is used by close_fd only; - remove the VFS fproc file descriptor bitmap entirely, returning to the situation that a FD is in use if its slot points to a filp; use FILP_CLOSED as single means of marking a filp as invalidated. Change-Id: I34f6bc69a036b3a8fc667c1f80435ff3af56558f commit 6eaaa958390eb80b81dafef2068378a5ce2e2946 Author: David van Moolenbroek Date: Tue Sep 10 12:19:08 2013 +0200 VFS: rework device code - block the calling thread on character device close; - fully separate block and character open/close routines; - reuse generic open/close code for the cloning case; - zero all messages to drivers before filling them; - use appropriate types for major/minor device numbers. Change-Id: Ia90e6fe5688f212f835c5ee1bfca831cb249cf51 commit 4ee8b6fab457a894c8e9c30310bff1ccc9f7d68b Author: David van Moolenbroek Date: Mon Sep 9 00:04:12 2013 +0200 Make PFS backcalls regular VFS calls - prefix them with VFS_ as they are going to VFS; - give these calls normal call numbers; - give them their own set of message field aliases; - also make do_mapdriver a regular call. Change-Id: I2140439f288b06d699a1f65438bd8306509b259e commit 367106e9e89dbae83b3dc3f946518ed6c93e3c4d Author: David van Moolenbroek Date: Wed Sep 11 12:48:10 2013 +0200 TTY: use libchardriver; clean up - writing to a PTY master side blocks if there is not already a blocked reader on the slave side, and select now reflects this; - internally, TTY now uses a test based on "caller != NONE" rather than "grant != GRANT_INVALID" to identify whether a call is currently ongoing; - "offset" fields have been removed as they equal the corresponding "cum" fields; - improved variable typing and function naming here and there; - various other small fixes. Change-Id: I6b51452888942e864b4e034e8c8490576184a23e commit e90437f66a75169e30f3aab114de37659a238492 Author: David van Moolenbroek Date: Wed Sep 11 01:13:59 2013 +0200 VFS: select(2) fixes - check each file descriptor's open access mode (filp_mode); - treat an error returned by a character driver as a select error; - check all filps in each set before finishing select; - do not copy back file descriptor sets if an error occurred; - remove the hardcoded list of supported character major devices, since all drivers should now be capable of responding properly; - add tests to test40 and fix its error count aggregation. Change-Id: I57ef58d3afb82640fc50b59c859ee4b25f02db17 commit db849cabad84c98f5d37c79dab4f5ed2e4471d78 Author: David van Moolenbroek Date: Wed Sep 11 01:07:28 2013 +0200 Retire EBADIOCTL in favor of ENOTTY Change-Id: I6bd0e301d21ab7f2336e350e7e6e15d238c2c93d commit 8ab3ef8007f241dff9fbdabc47b4d4da7faf8d8e Author: David van Moolenbroek Date: Wed Sep 4 15:42:36 2013 +0000 libnetsock: use libchardriver Change-Id: Ia5b780cad0b0c636db9bd866c7223da0d38ef6ea commit 1c1d697cb2bdcb8dd456b0dee757ec09032e689c Author: David van Moolenbroek Date: Wed Sep 11 00:50:36 2013 +0200 LWIP: move chardev message parsing into libnetsock Change-Id: Ie23fd003c9fa35811548f388c8e9b55e8d9de8d7 commit bbbeccd4fa5b2f0ab9c670bb6165eddfe7c95988 Author: David van Moolenbroek Date: Mon Sep 9 14:53:28 2013 +0000 INET: use libchardriver Change-Id: Icf8a1a5769ce0aede1cc28da99b9daf7d328182c commit 1db6dc9bc7352c87dbbdfc2a6b235572fc456b86 Author: David van Moolenbroek Date: Tue Sep 3 02:00:20 2013 +0200 PFS: use libchardriver; clean up - simplify and repair UDS request handling state machine; - simplify interface used between internal modules; - implement missing support for nonblocking I/O; - fix select implementation; - clean up global variables. Change-Id: Ia82c5c6f05cc3f0a498efc9a26de14b1cde6eace commit 1dd909f41c50f34f8d892fb2624a635bca39e983 Author: David van Moolenbroek Date: Tue Sep 3 01:59:20 2013 +0200 libaudiodriver: use libchardriver Change-Id: I299d58d110ad14b69076276ba46c4325875c34ca commit c0047f6a442a12c13f439969eca425c1bc4c2997 Author: David van Moolenbroek Date: Tue Sep 3 01:57:41 2013 +0200 printer: use libchardriver Change-Id: Ifa3cabeada74c32df2613b8279c00f86e831c775 commit 35539543724128287f42425ab053deffb97ab78e Author: David van Moolenbroek Date: Tue Sep 3 01:49:38 2013 +0200 libchardriver: full API rewrite The new API now covers the entire character driver protocol, while hiding all the message details. It should therefore be used by all new character drivers. All existing drivers that already made use of libchardriver have been changed to use the new API. As one of the most important API changes, support for scatter and gather transfers has been removed, as several key drivers already did not support this, and it could be supported at the safecopy level instead (for a future readv/writev). Additional changes include: - respond to block device open requests to avoid hanging VFS threads; - add support for sef_cancel. Change-Id: I1bab6c1cb66916c71b87aeb1db54a9bdf171fe6b commit 521df439aaff6012c91b39281c2e0101c088c6c3 Author: David van Moolenbroek Date: Thu Aug 1 18:20:33 2013 +0200 blocktest: add support for no alignment Some block drivers do not impose any alignment requirements, and this patch allows such block drivers to pass the test set. As a side effect, minimal support for min_write is added, but this part of blocktest is in need of further improvement. commit faa0389acea11c3aa4dd1ba1e5169385675442a5 Author: David van Moolenbroek Date: Wed Apr 18 00:04:28 2012 +0200 libutil: let opendisk(3) try /dev If a device node is given without path, and opening the node fails initially, prepend "/dev/" to the node name and try opening again. This is more in line with NetBSD behavior. commit f34bb193985eed63221c90c3ca48766c160c4fb4 Author: David van Moolenbroek Date: Tue Sep 10 23:57:32 2013 +0200 Block drivers: make IOCTL request unsigned long The block driver protocol and libblockdriver's bdr_ioctl hook are changed, as well as the users of this hook. Other parts of the system are expected to change accordingly eventually, since the ioctl(2) prototype has been aligned with NetBSD's. Change-Id: Ide46245b22cfa89ed267a38088fb0ab7696eba92 commit 2c70e7b0ee997654eb9ac48034325b29c3ab80ab Author: David van Moolenbroek Date: Sat Jul 27 00:49:49 2013 +0200 Block protocol: add user endpoint to IOCTL request I/O control requests now come with the endpoint of the user process that initiated the ioctl(2) call. It is stored in a new BDEV_USER field, which is an alias for BDEV_FLAGS. The contents of this field are to be used only in highly specific situations. It should be preserved (not replaced!) by services that forward IOCTL requests, and may be set to NONE for service-initiated IOCTL requests. Change-Id: I68a01b9ce43eca00e61b985a9cf87f55ba683de4 commit 622e08ee49e14b54e064b85e912e83466f1cfe6f Author: David van Moolenbroek Date: Sat Jul 27 00:49:49 2013 +0200 Block protocol: use own [RW]_BIT definitions The original R_BIT and W_BIT definitions have nothing to do with the way these bits are used. Their distinct usage is more apparent when they have different names. Change-Id: Ia984457f900078b2e3502ceed565fead4e5bb965 commit 49ddd9530a0909f9eadc324616a16c11b7ff5e56 Author: David van Moolenbroek Date: Tue Sep 10 23:35:15 2013 +0200 libblockdriver: expose BLOCKDRIVER_MAX_DEVICES This constant determines the range of valid device_id_t values that a block driver can return from the bdr_device hook: a value between 0 and (BLOCKDRIVER_MAX_DEVICES - 1) inclusive. Change-Id: I80fac469e88ac13d4b869007e6f2c2f7569da433 commit 07482d855ca11c45235673309beb1e26a1f389a0 Author: David van Moolenbroek Date: Wed Sep 11 13:33:00 2013 +0200 libblockdriver: various updates - internal structure rearrangement; - respond to char device open requests to avoid hanging VFS threads; - make drivers use designated initializers; - use devminor_t for all minor device numbers; - change bdr_other hook to take ipc_status and return nothing; - fix default geometry computation; - add support for sef_cancel. Change-Id: Ia063a136a3ddb2b78de36180feda870605753d70 commit f1a1ebb711626107014408a1b6561f3a67c0b557 Author: David van Moolenbroek Date: Sun Sep 1 14:34:17 2013 +0200 Block drivers: reply ENOTTY to unknown IOCTLs Change-Id: Ie2e82d2491d546f4dd73b009100646e249a147b5 commit b3f90bcbd9bf3e205624eccdcbfda3b349469bc5 Author: David van Moolenbroek Date: Sun Jul 28 14:03:07 2013 +0200 Move SUB_PER_DRIVE definition into minix/drvlib.h commit 478389a9ccc93974ad4158158e34b2d6d44441de Author: David van Moolenbroek Date: Mon Sep 2 17:34:44 2013 +0200 VFS: update filp_pos on chardev I/O (workaround) Previously, reading from or writing to a character device would not update the file position on the corresponding filp object. Performing this update correctly is not trivial: during and after the I/O operation, the filp object must not be locked. Ideally, read/write requests on a filp that is already involved in a read/write operation, should be queued. For now, we optimistically update the file position at the start of the I/O; this works under the assumptions listed in the corresponding comment. Change-Id: I172a61781850423709924390ae3df1f2d1f94707 commit 267c676b8867652666e74cfa4a6e21b7205e163c Author: David van Moolenbroek Date: Mon Sep 2 13:45:02 2013 +0200 I2C: change BUSC_I2C_xxx to use own protocol Previously it would use bits of the character driver protocol, which will change heavily. In the new situation, the BUSC_I2C_xxx requests use a protocol more in line with the PCI protocol, with the reply code in m_type. Change-Id: I51597b3f191078c8178ce17372de123031f7a4c4 commit ce5af0be47886f2b2aaf399cc93d5d1d839d180a Author: David van Moolenbroek Date: Sat Aug 31 16:13:37 2013 +0200 tests: add test77 for opening/closing PTYs Change-Id: I30e3418f75137aa08037fa6581ff3d4cce32a114 commit 302841555f16077f611539e0df24f9f11f32803a Author: David van Moolenbroek Date: Sat Aug 31 16:08:25 2013 +0200 TTY: fix for PTY open/close logic Opening and closing the master side of a pseudo terminal without opening the slave side would result in the pseudo terminal becoming permanently unavailable. In addition, reopening the slave side would be possible but not allow for I/O. Finally, attempting to open an in-use master would wipe its I/O state. These issues have been resolved. Change-Id: I9235e3d9aba321803f9280b86b6b5e3646ad5ef3 commit 3cd3c37232291e16cddb8fcfaf3f5da518874bb1 Author: David van Moolenbroek Date: Fri Aug 30 18:48:56 2013 +0200 tests: remove select subdirectory This test set has been obsoleted by test40. Change-Id: I55439152824906778ad07d409dfb327ac10bea70 commit d165339702810b72812d6e3c8730afe6f4da0579 Author: David van Moolenbroek Date: Fri Aug 30 18:43:23 2013 +0200 tests: add test76 for interrupting VFS operations Change-Id: Ic436cac61de8c42e0c7ee2d442c647528654cde9 commit befe9861f6e4bad449e65f32692376fbd2eafebc Author: David van Moolenbroek Date: Wed Aug 28 13:08:16 2013 +0200 VFS: fix interruption of blocking pipe operations POSIX states that when interrupted, partially successful pipe operations should return the partial result rather than EINTR. VFS previously wouldn't look at the partial result, and not clear it either, which would result in a panic upon the next pipe operation. Change-Id: Ia1eb72b4b77394051444e63a1390d49bb315eb04 commit 40bde438305a1fe9ae6285ef17703f3b2c119c3e Author: David van Moolenbroek Date: Fri Aug 30 00:57:16 2013 +0200 libmthread: do not dump stack for free threads Change-Id: Ic438a252f5bddaf1513f554c71173e6fffb0c674 commit 6687b172462e623c6fc76e785f20d15ccdb8bea0 Author: David van Moolenbroek Date: Fri Aug 30 14:00:50 2013 +0200 VFS: worker thread model overhaul The main purpose of this patch is to fix handling of unpause calls from PM while another call is ongoing. The solution to this problem sparked a full revision of the threading model, consisting of a large number of related changes: - all active worker threads are now always associated with a process, and every process has at most one active thread working for it; - the process lock is always held by a process's worker thread; - a process can now have both normal work and postponed PM work associated to it; - timer expiry and non-postponed PM work is done from the main thread; - filp garbage collection is done from a thread associated with VFS; - reboot calls from PM are now done from a thread associated with PM; - the DS events handler is protected from starting multiple threads; - support for a system worker thread has been removed; - the deadlock recovery thread has been replaced by a parameter to the worker_start() function; the number of worker threads has consequently been increased by one; - saving and restoring of global but per-thread variables is now centralized in worker_suspend() and worker_resume(); err_code is now saved and restored in all cases; - the concept of jobs has been removed, and job_m_in now points to a message stored in the worker thread structure instead; - the PM lock has been removed; - the separate exec lock has been replaced by a lock on the VM process, which was already being locked for exec calls anyway; - PM_UNPAUSE is now processed as a postponed PM request, from a thread associated with the target process; - the FP_DROP_WORK flag has been removed, since it is no longer more than just an optimization and only applied to processes operating on a pipe when getting killed; - assignment to "fp" now takes place only when obtaining new work in the main thread or a worker thread, when resuming execution of a thread, and in the special case of exiting processes during reboot; - there are no longer special cases where the yield() call is used to force a thread to run. Change-Id: I7a97b9b95c2450454a9b5318dfa0e6150d4e6858 commit 18adf3b3481cb93d48990ca6c27779d3354ed92e Author: David van Moolenbroek Date: Wed Aug 28 15:58:30 2013 +0200 Retire ptrace(T_DUMPCORE), dumpcore(1), gcore(1) The T_DUMPCORE implementation was not only broken - it would currently produce a coredump of the tracer process rather than the traced process - but also deeply flawed, and fixing it would require serious alteration of PM's internal state machine. It should be possible to implement the same functionality in userland, and that is now the suggested way forward. For now, also remove the (identical) utilities using T_DUMPCORE: dumpcore(1) and gcore(1). Change-Id: I1d51be19c739362b8a5833de949b76382a1edbcc commit c89c9bba1242ab64f00e33a7c103491d16a5dcc4 Author: David van Moolenbroek Date: Fri Aug 30 13:42:51 2013 +0200 VFS: process char driver replies from main thread Previously, processing of some replies coming from character drivers could block on locks, and therefore, such processing was done from threads that were associated to the character driver process. The hidden consequence of this was that if all threads were in use, VFS could drop replies coming from the driver. This patch returns VFS to a situation where the replies from character drivers are processed instantly from the main thread, by removing the situations that may cause VFS to block while handling those replies. - change the locking model for select, so that it will never block on any processing that happens after the select call has been set up, in particular processing of character driver select replies; - clearly mark all select routines that may never block; - protect against race conditions in do_select as result of the locking that still does happen there (as is required for pipes); - also handle select timers from the main thread; - move processing of character driver replies into device.c. Change-Id: I4dc8e69f265cbd178de0fbf321d35f58f067cc57 commit 4bafbd90372f7e6e5e37a9961e2da732597a5462 Author: David van Moolenbroek Date: Sun Aug 25 00:26:38 2013 +0200 VFS: properly cancel select queries on unpause Change-Id: I16e71db3f5c1bcc7ba6045bc9f02b13d71dc31eb commit 6fbc144cbefcccbf2486d5d4077a90f9a73ba0d7 Author: David van Moolenbroek Date: Fri Aug 30 13:33:56 2013 +0200 VFS: remove support for sync char driver protocol Change-Id: I57cc870a053b813b3a3fc45da46606ea84fe4cb1 commit 70d5e810f5b3b1d4be1069ef2b04c6ac3704c6ee Author: David van Moolenbroek Date: Fri Aug 30 13:00:44 2013 +0200 VFS: remove FP_BLOCKED_ON_DOPEN These days, DEV_OPEN calls to character drivers block the calling thread until completion or failure, and thus never return SUSPEND to the caller. The same already applied to BDEV_OPEN calls to block drivers. It has thus become impossible for a process to enter a state of being blocked on a device open call. There is currently no support for restarting device open calls to restarted character drivers. This support was present in the _DOPEN logic, but was already no longer triggering. In the future, this case should be handled by the thread performing the open request. Change-Id: I6cc1e7b4c9ed116c6ce160b315e6e060124dce00 commit c3ddc6bbb23987af924ab4ae09bc2bbc12b29ca7 Author: David van Moolenbroek Date: Fri Aug 30 12:18:27 2013 +0200 PFS: remember request information for IOCTLs Not doing so caused PFS to commit protocol violations by relying on stale information when sending replies. This stale information always happened to be correct, which is why the problem went unnoticed. Change-Id: Ia42ca670718d6e731193cd2c34a3ff455f8a94d3 commit 61080f73325be2793e5175c17c9007ee0707b4ee Author: David van Moolenbroek Date: Fri Aug 30 11:14:03 2013 +0200 Retire the synchronous character driver protocol - change all sync char drivers into async drivers; - retire support for the sync protocol in libchardev; - remove async dev style, as this is now the default; - remove dev_status from VFS; - clean up now-unused protocol messages. Change-Id: I6aacff712292f6b29f2ccd51bc1e7d7003723e87 commit 55e01bfda35e370a28841eed7017e091f7f55ba0 Author: David van Moolenbroek Date: Fri Aug 30 10:48:34 2013 +0200 Sync char protocol: add nonblocking transfer flag The async char protocol already has this, so this patch closes the gap between the two protocols a bit. Support for this flag has been added to all sync char drivers that support CANCEL at all. The LOG driver was already using the asynchronous protocol, but it did not support the nonblocking transfer flag. This has been fixed as well. Change-Id: Ia55432c9f102765b59ad3feb45a8bd47a782c93f commit fd34804e63e1ca6713c781f7437b4c60342d93e6 Author: David van Moolenbroek Date: Sat Aug 24 12:29:39 2013 +0200 VFS: set w_drv_sendrec only when needed As with w_task, this ensures that the field remains cleared if it is not used. Without this, worker_stop could mistakenly identify a thread as talking to a device driver rather than a (crashed) file server. Change-Id: I7d3ebed3efc3cd4f5c891f61c67a6463109b6376 commit ccbaf6bd8252ac5a2edeee4dd66fd1d43445a24e Author: Thomas Veerman Date: Sat Aug 24 12:23:41 2013 +0200 VFS: set w_task only when needed It was always set, but not always cleared, when talking to asynchronous drivers. This could cause erratic behavior upon a driver crash. Normally, a worker thread's w_task field is set when it's about to communicate with a driver or FS. Then upon receiving a reply we can do sanity checks (that the thread we want to wake up was actually waiting for a reply). Also, when a driver/FS crashes, we can identify which worker threads were talking to the crashed endpoint and handle the error gracefully. Asynchronous drivers are a bit special, though. In most cases, the sender of the request is not interested in the reply (the sender was suspended and only wants to know whether the request was successfully caried out or not). However, the open request is special, as the reply carries information needed by the sender. This is the only request where a worker thread actually yields and waits for the result. This is also the only case where we're interested in setting w_task for asynchronous drivers. Change-Id: Ia1ce2747937df376122b5e13b6a069de27fcc379 commit 80e6a4c121a64fc77cc5dfa0e33dfbd69ec2ea1a Author: David van Moolenbroek Date: Mon Aug 19 20:34:15 2013 +0200 Import NetBSD df(1) Change-Id: Ia60f8b23b961e4132efece1e7e38f0d63597c13b commit 7e0d00d6cfcb3d4d0ab1dd3eeac556817735139e Author: David van Moolenbroek Date: Tue Aug 20 01:33:43 2013 +0200 Enable getmntinfo(3) Change-Id: Id9d11a67cdcad331a52030127f7c7ead3c847919 commit 8d9632ecfc3d83be4e1b4ee256ee0388a77748f8 Author: David van Moolenbroek Date: Tue Aug 20 00:49:07 2013 +0200 test55: add tests for getvfsstat(2) Change-Id: Iad4567068a82bb0e780891a478ba5a06b63f1d48 commit 2e60389afacfce32940e330d28fffe5ed1a59eb3 Author: David van Moolenbroek Date: Tue Aug 20 01:28:23 2013 +0200 Implement support for [f]statvfs1(2) The [f]statvfs(3) calls now use [f]statvfs1(2). Change-Id: I56c92fe1c70670f476631c4a50e47351562712c6 commit be1d453fc179741aed20bd6122b6de8b15b43f1d Author: David van Moolenbroek Date: Tue Aug 20 01:39:47 2013 +0200 Implement support for getvfsstat(2) Change-Id: I4680c071b94fa855edfb6220b03cff6b20f3c1c9 commit 6ed7e451f149fa9e062ab66d4a976f3971dc08f1 Author: David van Moolenbroek Date: Tue Aug 20 01:37:18 2013 +0200 Redo mount(2)/umount(2) ABI - pass in file system type through mount(2), and return this type in statvfs structures as generated by [f]statvfs(2); - align mount flags field with NetBSD's, splitting out service flags which are not to be passed to VFS; - remove limitation of mount ABI to 16-byte labels, so that labels can be made larger in the future; - introduce new m11 message union type for mount(2) as side effect. Change-Id: Ia9ed4566d88af5239749c57274312be26bb61448 commit 314ccf892ad9db92b26ae8f6e0a8419f9f5a18b4 Author: David van Moolenbroek Date: Tue Aug 20 01:35:35 2013 +0200 Align "struct statvfs" with NetBSD This is a requirement for implementing calls such as getmntinfo(3). VFS is now responsible for filling in some of the structure's fields. Change-Id: I457b463c70ea2f326b9c50de954a91cfefba0065 commit 4d748d6c8f5b4f296d6b25f042e3f312c142b3ff Author: David van Moolenbroek Date: Tue Aug 20 00:55:49 2013 +0200 VFS/FS: remove fstatfs(2) and REQ_FSTATFS The fstatfs(3) call now uses fstatvfs(2). Change-Id: Ic6bbb040e1a8f01aaffe1a6a809dd4c7a2eae2f6 Change-Id: Ied93a28c893d639fb4d46eb6483b84219013e059 --- bin/Makefile | 2 +- bin/df/Makefile | 11 + bin/df/df.1 | 206 +++++ bin/df/df.c | 520 ++++++++++++ commands/DESCRIBE/DESCRIBE.sh | 16 + commands/MAKEDEV/MAKEDEV.sh | 45 +- commands/Makefile | 6 +- commands/df/Makefile | 4 - commands/df/df.c | 237 ------ commands/dumpcore/Makefile | 5 - commands/dumpcore/dumpcore.c | 71 -- commands/fdisk/fdisk.c | 32 +- commands/gcore/Makefile | 4 - commands/gcore/gcore.c | 58 -- commands/mount/mount.c | 15 +- commands/playwave/playwave.c | 77 +- commands/ps/ps.c | 1 - commands/service/parse.c | 1 + commands/service/service.c | 8 +- commands/setup/setup.sh | 6 +- commands/umount/umount.c | 2 +- distrib/sets/lists/minix/md.evbarm | 22 +- distrib/sets/lists/minix/md.i386 | 22 +- distrib/sets/lists/minix/mi | 32 +- drivers/Makefile | 4 +- drivers/ahci/ahci.c | 61 +- drivers/ahci/ahci.h | 1 - drivers/at_wini/at_wini.c | 58 +- drivers/at_wini/at_wini.h | 1 - drivers/audio/es1370/es1370.c | 2 +- drivers/audio/es1371/es1371.c | 2 +- drivers/audio/sb16/mixer.c | 2 +- drivers/audio/sb16/mixer.h | 2 +- drivers/audio/sb16/sb16.c | 15 +- drivers/bmp085/bmp085.c | 82 +- drivers/cat24c256/cat24c256.c | 63 +- drivers/fb/arch/earm/fb_arch.c | 8 +- drivers/fb/fb.c | 183 ++-- drivers/fb/fb.h | 2 +- drivers/fb/fb_edid.c | 2 +- drivers/fbd/fbd.c | 44 +- drivers/filter/driver.c | 3 +- drivers/filter/main.c | 215 ++--- drivers/floppy/floppy.c | 46 +- drivers/hello/hello.c | 91 +- drivers/i2c/i2c.c | 103 +-- drivers/log/log.c | 376 ++++----- drivers/log/log.h | 14 +- drivers/memory/memory.c | 466 +++++----- drivers/mmc/mmcblk.c | 54 +- drivers/printer/liveupdate.c | 7 +- drivers/printer/printer.c | 265 ++---- drivers/random/main.c | 163 ++-- drivers/sht21/sht21.c | 80 +- drivers/tda19988/tda19988.c | 60 +- drivers/tps65217/tps65217.c | 23 +- drivers/tsl2550/tsl2550.c | 80 +- drivers/tty/Makefile | 4 +- drivers/tty/arch/earm/console.c | 4 +- drivers/tty/arch/earm/keyboard.c | 15 +- drivers/tty/arch/earm/rs232.c | 28 +- drivers/tty/arch/i386/console.c | 179 ++-- drivers/tty/arch/i386/keyboard.c | 600 ++++++------- drivers/tty/arch/i386/rs232.c | 29 +- drivers/tty/pty.c | 713 ++++++++-------- drivers/tty/tty.c | 748 +++++++---------- drivers/tty/tty.h | 56 +- drivers/virtio_blk/virtio_blk.c | 76 +- drivers/vnd/Makefile | 12 + drivers/vnd/NOTES | 85 ++ drivers/vnd/vnd.c | 601 +++++++++++++ etc/mtree/NetBSD.dist.base | 1 + etc/rc | 3 +- etc/rs.inet | 4 +- etc/system.conf | 38 +- etc/usr/rc | 8 +- include/minix/Makefile | 2 +- include/minix/audio_fw.h | 11 +- include/minix/bdev.h | 5 +- include/minix/blockdriver.h | 26 +- include/minix/blockdriver_mt.h | 2 + include/minix/callnr.h | 19 +- include/minix/chardriver.h | 46 +- include/minix/com.h | 239 +++--- include/minix/config.h | 11 - include/minix/dmap.h | 10 +- include/minix/drvlib.h | 1 + include/minix/ioctl.h | 1 + include/minix/ipc.h | 13 + include/minix/mount.h | 16 +- include/minix/netsock.h | 62 +- include/minix/paths.h | 2 + include/minix/procfs.h | 1 - include/minix/sysinfo.h | 1 - include/minix/syslib.h | 13 +- include/minix/tty.h | 28 - include/minix/vfsif.h | 23 +- include/minix/vm.h | 2 + include/stdlib.h | 2 - include/sys/ioc_fbd.h | 6 +- include/sys/ioc_tty.h | 1 - include/unistd.h | 2 + kernel/arch/earm/pre_init.c | 6 +- kernel/arch/i386/pre_init.c | 2 +- kernel/priv.h | 2 + kernel/proto.h | 5 +- kernel/system.c | 22 +- kernel/system/Makefile.inc | 2 +- kernel/system/do_diagctl.c | 65 ++ kernel/system/do_privctl.c | 1 + kernel/system/do_sysctl.c | 50 -- kernel/system/do_update.c | 1 + kernel/table.c | 1 - kernel/utility.c | 15 +- lib/libaudiodriver/audio_fw.c | 358 ++------ lib/libaudiodriver/liveupdate.c | 14 +- lib/libbdev/bdev.c | 16 +- lib/libbdev/ipc.c | 15 +- lib/libbdev/minor.c | 16 + lib/libbdev/proto.h | 1 + lib/libblockdriver/const.h | 2 +- lib/libblockdriver/driver.c | 192 +++-- lib/libblockdriver/driver.h | 5 +- lib/libblockdriver/driver_mt.c | 22 +- lib/libblockdriver/driver_st.c | 21 +- lib/libblockdriver/trace.c | 6 +- lib/libblockdriver/trace.h | 2 +- lib/libc/gen/Makefile.inc | 8 +- lib/libc/gen/devname.c | 4 + lib/libc/include/namespace.h | 4 +- lib/libc/sys-minix/MISSING_SYSCALLS | 1 - lib/libc/sys-minix/Makefile.inc | 1 + lib/libc/sys-minix/accept.c | 6 +- lib/libc/sys-minix/bind.c | 6 +- lib/libc/sys-minix/connect.c | 8 +- lib/libc/sys-minix/fstatfs.c | 13 +- lib/libc/sys-minix/fstatvfs.c | 15 +- lib/libc/sys-minix/getpeername.c | 4 +- lib/libc/sys-minix/getsockname.c | 4 +- lib/libc/sys-minix/getsockopt.c | 6 +- lib/libc/sys-minix/getvfsstat.c | 19 + lib/libc/sys-minix/ioctl.c | 6 +- lib/libc/sys-minix/listen.c | 4 +- lib/libc/sys-minix/mount.c | 58 +- lib/libc/sys-minix/recvfrom.c | 6 +- lib/libc/sys-minix/recvmsg.c | 2 +- lib/libc/sys-minix/sendmsg.c | 2 +- lib/libc/sys-minix/sendto.c | 6 +- lib/libc/sys-minix/setsockopt.c | 6 +- lib/libc/sys-minix/shutdown.c | 4 +- lib/libc/sys-minix/statvfs.c | 17 +- lib/libc/sys/Makefile.inc | 8 +- lib/libchardriver/chardriver.c | 717 +++++++++------- lib/libddekit/src/msg_queue.c | 17 +- lib/libi2cdriver/i2cdriver.c | 8 +- lib/libminc/Makefile | 13 +- lib/libminixfs/cache.c | 2 + lib/libminlib/Makefile | 7 +- lib/libminlib/dupfrom.c | 15 + lib/libmthread/misc.c | 8 +- lib/libnetsock/socket.c | 486 ++++++----- lib/libpuffs/proto.h | 1 - lib/libpuffs/stadir.c | 27 +- lib/libpuffs/table.c | 7 +- lib/libsffs/const.h | 4 +- lib/libsffs/misc.c | 25 +- lib/libsffs/proto.h | 1 - lib/libsffs/table.c | 5 +- lib/libsys/Makefile | 3 +- lib/libsys/kputc.c | 2 +- lib/libsys/send_taskreply.c | 20 - lib/libsys/sys_diagctl.c | 13 + lib/libsys/sys_sysctl.c | 20 - lib/libsys/vm_cache.c | 14 + lib/libutil/Makefile | 4 +- lib/libutil/opendisk.c | 10 + lib/libvtreefs/proto.h | 1 - lib/libvtreefs/stadir.c | 22 +- lib/libvtreefs/table.c | 7 +- man/man1/Makefile | 5 +- man/man1/df.1 | 75 -- man/man1/dumpcore.1 | 29 - man/man2/Makefile | 3 +- man/man2/intro.2 | 1 - man/man2/mount.2 | 19 +- man/man2/statvfs.2 | 133 --- man/man4/ip.4 | 2 +- releasetools/Makefile | 1 - releasetools/arm_sdimage.sh | 2 +- releasetools/gen_uEnv.txt.sh | 17 +- releasetools/nbsd_ports | 3 + releasetools/release.functions | 11 +- releasetools/release.sh | 2 +- sbin/newfs_ext2fs/newfs_ext2fs.c | 15 +- servers/ext2/mount.c | 6 +- servers/ext2/proto.h | 1 - servers/ext2/stadir.c | 30 +- servers/ext2/table.c | 7 +- servers/inet/generic/eth.c | 2 +- servers/inet/generic/ip_ioctl.c | 6 +- servers/inet/generic/tcp.c | 2 +- servers/inet/generic/udp.c | 2 +- servers/inet/inet.c | 72 +- servers/inet/inet.h | 2 +- servers/inet/mq.h | 21 +- servers/inet/proto.h | 6 +- servers/inet/sr.c | 541 ++++-------- servers/inet/sr_int.h | 3 - servers/is/dmp_fs.c | 3 - servers/is/dmp_kernel.c | 2 +- servers/iso9660fs/mount.c | 2 +- servers/iso9660fs/proto.h | 1 - servers/iso9660fs/stadir.c | 28 +- servers/iso9660fs/table.c | 11 +- servers/lwip/driver.c | 231 +++-- servers/lwip/eth.c | 1 + servers/lwip/inet_config.c | 3 +- servers/lwip/lwip.c | 29 +- servers/lwip/proto.h | 4 +- servers/lwip/raw_ip.c | 146 ++-- servers/lwip/tcp.c | 326 ++++--- servers/lwip/udp.c | 134 ++- servers/mfs/mount.c | 8 +- servers/mfs/proto.h | 1 - servers/mfs/stadir.c | 28 +- servers/mfs/table.c | 7 +- servers/pfs/Makefile | 4 +- servers/pfs/dev_uds.c | 965 +++++++-------------- servers/pfs/glo.h | 5 - servers/pfs/inode.c | 6 +- servers/pfs/main.c | 59 +- servers/pfs/open.c | 8 +- servers/pfs/proto.h | 37 +- servers/pfs/read.c | 4 +- servers/pfs/table.c | 35 +- servers/pfs/uds.c | 556 ++++++------ servers/pfs/uds.h | 81 +- servers/pfs/utility.c | 2 +- servers/pm/forkexit.c | 5 +- servers/pm/main.c | 10 +- servers/pm/misc.c | 6 +- servers/pm/signal.c | 4 +- servers/pm/table.c | 10 +- servers/pm/trace.c | 21 - servers/procfs/Makefile | 2 +- servers/procfs/mounts.c | 34 - servers/procfs/mounts.h | 6 - servers/procfs/pid.c | 1 - servers/procfs/root.c | 20 +- servers/rs/main.c | 2 +- servers/rs/table.c | 5 +- servers/vfs/README | 212 ++--- servers/vfs/comm.c | 7 +- servers/vfs/comm.h | 12 - servers/vfs/const.h | 25 +- servers/vfs/coredump.c | 1 - servers/vfs/device.c | 1212 ++++++++++----------------- servers/vfs/dmap.c | 43 +- servers/vfs/dmap.h | 3 +- servers/vfs/exec.c | 80 +- servers/vfs/file.h | 8 +- servers/vfs/filedes.c | 211 +++-- servers/vfs/fproc.h | 22 +- servers/vfs/fs.h | 3 +- servers/vfs/gcov.c | 1 - servers/vfs/glo.h | 13 +- servers/vfs/job.h | 12 - servers/vfs/link.c | 1 - servers/vfs/lock.c | 1 - servers/vfs/main.c | 695 +++++---------- servers/vfs/misc.c | 148 ++-- servers/vfs/mount.c | 109 +-- servers/vfs/open.c | 21 +- servers/vfs/param.h | 4 - servers/vfs/path.c | 9 +- servers/vfs/pipe.c | 128 +-- servers/vfs/protect.c | 1 - servers/vfs/proto.h | 74 +- servers/vfs/read.c | 45 +- servers/vfs/request.c | 34 +- servers/vfs/select.c | 400 ++++----- servers/vfs/stadir.c | 198 ++++- servers/vfs/table.c | 24 +- servers/vfs/threads.h | 6 +- servers/vfs/time.c | 1 - servers/vfs/type.h | 41 + servers/vfs/utility.c | 1 - servers/vfs/vmnt.c | 2 - servers/vfs/vmnt.h | 7 +- servers/vfs/vnode.c | 2 - servers/vfs/vnode.h | 1 + servers/vfs/worker.c | 474 ++++++----- servers/vm/cache.c | 19 + servers/vm/main.c | 1 + servers/vm/mem_cache.c | 14 + servers/vm/mem_file.c | 2 +- servers/vm/mmap.c | 4 +- servers/vm/pagefaults.c | 2 +- servers/vm/proto.h | 2 + sys/dev/Makefile | 2 + sys/dev/vndvar.h | 218 +++++ sys/stdlib.h | 3 +- sys/sys/errno.h | 1 - sys/sys/ioctl.h | 5 +- sys/sys/ptrace.h | 1 - sys/sys/select.h | 9 - sys/sys/statvfs.h | 74 +- test/Makefile | 14 +- test/blocktest/Makefile | 4 +- test/blocktest/blocktest.c | 305 ++++--- test/blocktest/test.sh | 18 +- test/run | 42 +- test/select/Makefile | 39 - test/select/speed.c | 61 -- test/select/test00.c | 58 -- test/select/test01.c | 74 -- test/select/test02.c | 114 --- test/select/test03.c | 137 --- test/select/test04_cli.c | 148 ---- test/select/test04_srv.c | 134 --- test/select/test05_cli.c | 165 ---- test/select/test05_srv.c | 196 ----- test/select/test06_cli.c | 162 ---- test/select/test06_srv.c | 127 --- test/select/test07_cli.c | 182 ---- test/select/test07_srv.c | 137 --- test/select/test08_cli.c | 183 ---- test/select/test08_srv.c | 145 ---- test/select/test09.c | 62 -- test/select/test10.c | 71 -- test/select/test11.c | 164 ---- test/select/test12.c | 39 - test/select/test13a.c | 56 -- test/select/test13b.c | 67 -- test/select/test14.c | 144 ---- test/t40c.c | 51 +- test/t40g.c | 52 ++ test/test40.c | 6 +- test/test55.c | 197 +++-- test/test56.c | 6 +- test/test72.c | 15 +- test/test76.c | 446 ++++++++++ test/test77.c | 486 +++++++++++ test/testvm.c | 2 + test/testvm.conf | 2 +- test/testvnd.sh | 155 ++++ test/tvnd.c | 53 ++ usr.bin/stat/stat.c | 5 - usr.sbin/Makefile | 1 + usr.sbin/vnconfig/Makefile | 10 + usr.sbin/vnconfig/vnconfig.8 | 195 +++++ usr.sbin/vnconfig/vnconfig.c | 605 +++++++++++++ 352 files changed, 11327 insertions(+), 12778 deletions(-) create mode 100644 bin/df/Makefile create mode 100644 bin/df/df.1 create mode 100644 bin/df/df.c delete mode 100644 commands/df/Makefile delete mode 100644 commands/df/df.c delete mode 100644 commands/dumpcore/Makefile delete mode 100644 commands/dumpcore/dumpcore.c delete mode 100644 commands/gcore/Makefile delete mode 100644 commands/gcore/gcore.c create mode 100644 drivers/vnd/Makefile create mode 100644 drivers/vnd/NOTES create mode 100644 drivers/vnd/vnd.c delete mode 100644 include/minix/tty.h create mode 100644 kernel/system/do_diagctl.c delete mode 100644 kernel/system/do_sysctl.c create mode 100644 lib/libc/sys-minix/getvfsstat.c create mode 100644 lib/libminlib/dupfrom.c delete mode 100644 lib/libsys/send_taskreply.c create mode 100644 lib/libsys/sys_diagctl.c delete mode 100644 lib/libsys/sys_sysctl.c delete mode 100644 man/man1/df.1 delete mode 100644 man/man1/dumpcore.1 delete mode 100644 man/man2/statvfs.2 delete mode 100644 servers/procfs/mounts.c delete mode 100644 servers/procfs/mounts.h delete mode 100644 servers/vfs/comm.h delete mode 100644 servers/vfs/job.h create mode 100644 servers/vfs/type.h create mode 100644 sys/dev/vndvar.h delete mode 100644 test/select/Makefile delete mode 100644 test/select/speed.c delete mode 100644 test/select/test00.c delete mode 100644 test/select/test01.c delete mode 100644 test/select/test02.c delete mode 100644 test/select/test03.c delete mode 100644 test/select/test04_cli.c delete mode 100644 test/select/test04_srv.c delete mode 100644 test/select/test05_cli.c delete mode 100644 test/select/test05_srv.c delete mode 100644 test/select/test06_cli.c delete mode 100644 test/select/test06_srv.c delete mode 100644 test/select/test07_cli.c delete mode 100644 test/select/test07_srv.c delete mode 100644 test/select/test08_cli.c delete mode 100644 test/select/test08_srv.c delete mode 100644 test/select/test09.c delete mode 100644 test/select/test10.c delete mode 100644 test/select/test11.c delete mode 100644 test/select/test12.c delete mode 100644 test/select/test13a.c delete mode 100644 test/select/test13b.c delete mode 100644 test/select/test14.c create mode 100644 test/t40g.c create mode 100644 test/test76.c create mode 100644 test/test77.c create mode 100755 test/testvnd.sh create mode 100644 test/tvnd.c create mode 100644 usr.sbin/vnconfig/Makefile create mode 100644 usr.sbin/vnconfig/vnconfig.8 create mode 100644 usr.sbin/vnconfig/vnconfig.c 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); +}