xref: /minix3/minix/servers/vfs/read.c (revision e3b8d4bb58a799dc7fd563ac39bf3015762af03b)
1433d6423SLionel Sambuc /* This file contains the heart of the mechanism used to read (and write)
2433d6423SLionel Sambuc  * files.  Read and write requests are split up into chunks that do not cross
3433d6423SLionel Sambuc  * block boundaries.  Each chunk is then processed in turn.  Reads on special
4433d6423SLionel Sambuc  * files are also detected and handled.
5433d6423SLionel Sambuc  *
6433d6423SLionel Sambuc  * The entry points into this file are
7433d6423SLionel Sambuc  *   do_read:	 perform the READ system call by calling read_write
8433d6423SLionel Sambuc  *   do_getdents: read entries from a directory (GETDENTS)
9433d6423SLionel Sambuc  *   read_write: actually do the work of READ and WRITE
10433d6423SLionel Sambuc  *
11433d6423SLionel Sambuc  */
12433d6423SLionel Sambuc 
13433d6423SLionel Sambuc #include "fs.h"
14433d6423SLionel Sambuc #include <minix/callnr.h>
15433d6423SLionel Sambuc #include <minix/com.h>
16433d6423SLionel Sambuc #include <minix/u64.h>
17433d6423SLionel Sambuc #include <minix/vfsif.h>
18433d6423SLionel Sambuc #include <assert.h>
19433d6423SLionel Sambuc #include <sys/dirent.h>
20433d6423SLionel Sambuc #include <fcntl.h>
21433d6423SLionel Sambuc #include <unistd.h>
22433d6423SLionel Sambuc #include "file.h"
23433d6423SLionel Sambuc #include "vnode.h"
24433d6423SLionel Sambuc #include "vmnt.h"
25433d6423SLionel Sambuc 
26433d6423SLionel Sambuc 
27433d6423SLionel Sambuc /*===========================================================================*
28433d6423SLionel Sambuc  *				do_read					     *
29433d6423SLionel Sambuc  *===========================================================================*/
do_read(void)30433d6423SLionel Sambuc int do_read(void)
31433d6423SLionel Sambuc {
32232819ddSDavid van Moolenbroek 
33232819ddSDavid van Moolenbroek   /*
34232819ddSDavid van Moolenbroek    * This field is currently reserved for internal usage only, and must be set
35232819ddSDavid van Moolenbroek    * to zero by the caller.  We may use it for future SA_RESTART support just
36232819ddSDavid van Moolenbroek    * like we are using it internally now.
37232819ddSDavid van Moolenbroek    */
38232819ddSDavid van Moolenbroek   if (job_m_in.m_lc_vfs_readwrite.cum_io != 0)
39232819ddSDavid van Moolenbroek 	return(EINVAL);
40232819ddSDavid van Moolenbroek 
41433d6423SLionel Sambuc   return(do_read_write_peek(READING, job_m_in.m_lc_vfs_readwrite.fd,
42433d6423SLionel Sambuc 	job_m_in.m_lc_vfs_readwrite.buf, job_m_in.m_lc_vfs_readwrite.len));
43433d6423SLionel Sambuc }
44433d6423SLionel Sambuc 
45433d6423SLionel Sambuc 
46433d6423SLionel Sambuc /*===========================================================================*
47433d6423SLionel Sambuc  *				lock_bsf				     *
48433d6423SLionel Sambuc  *===========================================================================*/
lock_bsf(void)49433d6423SLionel Sambuc void lock_bsf(void)
50433d6423SLionel Sambuc {
51433d6423SLionel Sambuc   struct worker_thread *org_self;
52433d6423SLionel Sambuc 
53433d6423SLionel Sambuc   if (mutex_trylock(&bsf_lock) == 0)
54433d6423SLionel Sambuc 	return;
55433d6423SLionel Sambuc 
56433d6423SLionel Sambuc   org_self = worker_suspend();
57433d6423SLionel Sambuc 
58433d6423SLionel Sambuc   if (mutex_lock(&bsf_lock) != 0)
59433d6423SLionel Sambuc 	panic("unable to lock block special file lock");
60433d6423SLionel Sambuc 
61433d6423SLionel Sambuc   worker_resume(org_self);
62433d6423SLionel Sambuc }
63433d6423SLionel Sambuc 
64433d6423SLionel Sambuc /*===========================================================================*
65433d6423SLionel Sambuc  *				unlock_bsf				     *
66433d6423SLionel Sambuc  *===========================================================================*/
unlock_bsf(void)67433d6423SLionel Sambuc void unlock_bsf(void)
68433d6423SLionel Sambuc {
69433d6423SLionel Sambuc   if (mutex_unlock(&bsf_lock) != 0)
70433d6423SLionel Sambuc 	panic("failed to unlock block special file lock");
71433d6423SLionel Sambuc }
72433d6423SLionel Sambuc 
73433d6423SLionel Sambuc /*===========================================================================*
74433d6423SLionel Sambuc  *				check_bsf				     *
75433d6423SLionel Sambuc  *===========================================================================*/
check_bsf_lock(void)76433d6423SLionel Sambuc void check_bsf_lock(void)
77433d6423SLionel Sambuc {
78433d6423SLionel Sambuc 	int r = mutex_trylock(&bsf_lock);
79433d6423SLionel Sambuc 
80433d6423SLionel Sambuc 	if (r == -EBUSY)
81433d6423SLionel Sambuc 		panic("bsf_lock locked");
82433d6423SLionel Sambuc 	else if (r != 0)
83433d6423SLionel Sambuc 		panic("bsf_lock weird state");
84433d6423SLionel Sambuc 
85433d6423SLionel Sambuc 	/* r == 0 */
86433d6423SLionel Sambuc 	unlock_bsf();
87433d6423SLionel Sambuc }
88433d6423SLionel Sambuc 
89433d6423SLionel Sambuc /*===========================================================================*
90433d6423SLionel Sambuc  *				actual_read_write_peek			     *
91433d6423SLionel Sambuc  *===========================================================================*/
actual_read_write_peek(struct fproc * rfp,int rw_flag,int fd,vir_bytes buf,size_t nbytes)92232819ddSDavid van Moolenbroek int actual_read_write_peek(struct fproc *rfp, int rw_flag, int fd,
93232819ddSDavid van Moolenbroek 	vir_bytes buf, size_t nbytes)
94433d6423SLionel Sambuc {
95433d6423SLionel Sambuc /* Perform read(fd, buffer, nbytes) or write(fd, buffer, nbytes) call. */
96433d6423SLionel Sambuc   struct filp *f;
97433d6423SLionel Sambuc   tll_access_t locktype;
98433d6423SLionel Sambuc   int r;
99433d6423SLionel Sambuc   int ro = 1;
100433d6423SLionel Sambuc 
101433d6423SLionel Sambuc   if(rw_flag == WRITING) ro = 0;
102433d6423SLionel Sambuc 
103433d6423SLionel Sambuc   locktype = rw_flag == WRITING ? VNODE_WRITE : VNODE_READ;
104232819ddSDavid van Moolenbroek   if ((f = get_filp2(rfp, fd, locktype)) == NULL)
105433d6423SLionel Sambuc 	return(err_code);
106433d6423SLionel Sambuc 
107433d6423SLionel Sambuc   assert(f->filp_count > 0);
108433d6423SLionel Sambuc 
109433d6423SLionel Sambuc   if (((f->filp_mode) & (ro ? R_BIT : W_BIT)) == 0) {
110433d6423SLionel Sambuc 	unlock_filp(f);
111433d6423SLionel Sambuc 	return(EBADF);
112433d6423SLionel Sambuc   }
113232819ddSDavid van Moolenbroek   if (nbytes == 0) {
114433d6423SLionel Sambuc 	unlock_filp(f);
115433d6423SLionel Sambuc 	return(0);	/* so char special files need not check for 0*/
116433d6423SLionel Sambuc   }
117433d6423SLionel Sambuc 
118232819ddSDavid van Moolenbroek   r = read_write(rfp, rw_flag, fd, f, buf, nbytes, who_e);
119433d6423SLionel Sambuc 
120433d6423SLionel Sambuc   unlock_filp(f);
121433d6423SLionel Sambuc   return(r);
122433d6423SLionel Sambuc }
123433d6423SLionel Sambuc 
124433d6423SLionel Sambuc /*===========================================================================*
125433d6423SLionel Sambuc  *				do_read_write_peek			     *
126433d6423SLionel Sambuc  *===========================================================================*/
do_read_write_peek(int rw_flag,int fd,vir_bytes buf,size_t nbytes)127232819ddSDavid van Moolenbroek int do_read_write_peek(int rw_flag, int fd, vir_bytes buf, size_t nbytes)
128433d6423SLionel Sambuc {
129232819ddSDavid van Moolenbroek 	return actual_read_write_peek(fp, rw_flag, fd, buf, nbytes);
130433d6423SLionel Sambuc }
131433d6423SLionel Sambuc 
132433d6423SLionel Sambuc /*===========================================================================*
133433d6423SLionel Sambuc  *				read_write				     *
134433d6423SLionel Sambuc  *===========================================================================*/
read_write(struct fproc * rfp,int rw_flag,int fd,struct filp * f,vir_bytes buf,size_t size,endpoint_t for_e)135232819ddSDavid van Moolenbroek int read_write(struct fproc *rfp, int rw_flag, int fd, struct filp *f,
136433d6423SLionel Sambuc 	vir_bytes buf, size_t size, endpoint_t for_e)
137433d6423SLionel Sambuc {
138433d6423SLionel Sambuc   register struct vnode *vp;
139433d6423SLionel Sambuc   off_t position, res_pos;
1403c8950ccSBen Gras   size_t cum_io, res_cum_io;
1413c8950ccSBen Gras   size_t cum_io_incr;
142433d6423SLionel Sambuc   int op, r;
143433d6423SLionel Sambuc   dev_t dev;
144433d6423SLionel Sambuc 
145433d6423SLionel Sambuc   position = f->filp_pos;
146433d6423SLionel Sambuc   vp = f->filp_vno;
147433d6423SLionel Sambuc   r = OK;
148433d6423SLionel Sambuc   cum_io = 0;
149433d6423SLionel Sambuc 
150433d6423SLionel Sambuc   assert(rw_flag == READING || rw_flag == WRITING || rw_flag == PEEKING);
151433d6423SLionel Sambuc 
152433d6423SLionel Sambuc   if (size > SSIZE_MAX) return(EINVAL);
153433d6423SLionel Sambuc 
154433d6423SLionel Sambuc   if (S_ISFIFO(vp->v_mode)) {		/* Pipes */
155433d6423SLionel Sambuc 	if(rw_flag == PEEKING) {
156433d6423SLionel Sambuc 	  	printf("read_write: peek on pipe makes no sense\n");
157433d6423SLionel Sambuc 		return EINVAL;
158433d6423SLionel Sambuc 	}
159232819ddSDavid van Moolenbroek 	assert(fd != -1);
160232819ddSDavid van Moolenbroek 	op = (rw_flag == READING ? VFS_READ : VFS_WRITE);
161232819ddSDavid van Moolenbroek 	r = rw_pipe(rw_flag, for_e, f, op, fd, buf, size, 0 /*cum_io*/);
162433d6423SLionel Sambuc   } else if (S_ISCHR(vp->v_mode)) {	/* Character special files. */
163433d6423SLionel Sambuc 	if(rw_flag == PEEKING) {
164433d6423SLionel Sambuc 	  	printf("read_write: peek on char device makes no sense\n");
165433d6423SLionel Sambuc 		return EINVAL;
166433d6423SLionel Sambuc 	}
167433d6423SLionel Sambuc 
168433d6423SLionel Sambuc 	if (vp->v_sdev == NO_DEV)
169433d6423SLionel Sambuc 		panic("VFS: read_write tries to access char dev NO_DEV");
170433d6423SLionel Sambuc 
171433d6423SLionel Sambuc 	dev = vp->v_sdev;
172232819ddSDavid van Moolenbroek 	op = (rw_flag == READING ? CDEV_READ : CDEV_WRITE);
173433d6423SLionel Sambuc 
174433d6423SLionel Sambuc 	r = cdev_io(op, dev, for_e, buf, position, size, f->filp_flags);
175433d6423SLionel Sambuc 	if (r >= 0) {
176433d6423SLionel Sambuc 		/* This should no longer happen: all calls are asynchronous. */
177433d6423SLionel Sambuc 		printf("VFS: I/O to device %llx succeeded immediately!?\n", dev);
178433d6423SLionel Sambuc 		cum_io = r;
179433d6423SLionel Sambuc 		position += r;
180433d6423SLionel Sambuc 		r = OK;
181433d6423SLionel Sambuc 	} else if (r == SUSPEND) {
182433d6423SLionel Sambuc 		/* FIXME: multiple read/write operations on a single filp
183433d6423SLionel Sambuc 		 * should be serialized. They currently aren't; in order to
184433d6423SLionel Sambuc 		 * achieve a similar effect, we optimistically advance the file
185433d6423SLionel Sambuc 		 * position here. This works under the following assumptions:
186433d6423SLionel Sambuc 		 * - character drivers that use the seek position at all,
187433d6423SLionel Sambuc 		 *   expose a view of a statically-sized range of bytes, i.e.,
188433d6423SLionel Sambuc 		 *   they are basically byte-granular block devices;
189433d6423SLionel Sambuc 		 * - if short I/O or an error is returned, all subsequent calls
190433d6423SLionel Sambuc 		 *   will return (respectively) EOF and an error;
191433d6423SLionel Sambuc 		 * - the application never checks its own file seek position,
192433d6423SLionel Sambuc 		 *   or does not care that it may end up having seeked beyond
193433d6423SLionel Sambuc 		 *   the number of bytes it has actually read;
194433d6423SLionel Sambuc 		 * - communication to the character driver is FIFO (this one
195433d6423SLionel Sambuc 		 *   is actually true! whew).
196433d6423SLionel Sambuc 		 * Many improvements are possible here, but in the end,
197433d6423SLionel Sambuc 		 * anything short of queuing concurrent operations will be
198433d6423SLionel Sambuc 		 * suboptimal - so we settle for this hack for now.
199433d6423SLionel Sambuc 		 */
200433d6423SLionel Sambuc 		position += size;
201433d6423SLionel Sambuc 	}
202*e3b8d4bbSDavid van Moolenbroek   } else if (S_ISSOCK(vp->v_mode)) {
203*e3b8d4bbSDavid van Moolenbroek 	if (rw_flag == PEEKING) {
204*e3b8d4bbSDavid van Moolenbroek 		printf("VFS: read_write tries to peek on sock dev\n");
205*e3b8d4bbSDavid van Moolenbroek 		return EINVAL;
206*e3b8d4bbSDavid van Moolenbroek 	}
207*e3b8d4bbSDavid van Moolenbroek 
208*e3b8d4bbSDavid van Moolenbroek 	if (vp->v_sdev == NO_DEV)
209*e3b8d4bbSDavid van Moolenbroek 		panic("VFS: read_write tries to access sock dev NO_DEV");
210*e3b8d4bbSDavid van Moolenbroek 
211*e3b8d4bbSDavid van Moolenbroek 	r = sdev_readwrite(vp->v_sdev, buf, size, 0, 0, 0, 0, 0, rw_flag,
212*e3b8d4bbSDavid van Moolenbroek 	    f->filp_flags, 0);
213433d6423SLionel Sambuc   } else if (S_ISBLK(vp->v_mode)) {	/* Block special files. */
214433d6423SLionel Sambuc 	if (vp->v_sdev == NO_DEV)
215433d6423SLionel Sambuc 		panic("VFS: read_write tries to access block dev NO_DEV");
216433d6423SLionel Sambuc 
217433d6423SLionel Sambuc 	lock_bsf();
218433d6423SLionel Sambuc 
219433d6423SLionel Sambuc 	if(rw_flag == PEEKING) {
220433d6423SLionel Sambuc 		r = req_bpeek(vp->v_bfs_e, vp->v_sdev, position, size);
221433d6423SLionel Sambuc 	} else {
222433d6423SLionel Sambuc 		r = req_breadwrite(vp->v_bfs_e, for_e, vp->v_sdev, position,
223433d6423SLionel Sambuc 		       size, buf, rw_flag, &res_pos, &res_cum_io);
224433d6423SLionel Sambuc 		if (r == OK) {
225433d6423SLionel Sambuc 			position = res_pos;
226433d6423SLionel Sambuc 			cum_io += res_cum_io;
227433d6423SLionel Sambuc 		}
228433d6423SLionel Sambuc 	}
229433d6423SLionel Sambuc 
230433d6423SLionel Sambuc 	unlock_bsf();
231433d6423SLionel Sambuc   } else {				/* Regular files */
232433d6423SLionel Sambuc 	if (rw_flag == WRITING) {
233433d6423SLionel Sambuc 		/* Check for O_APPEND flag. */
234433d6423SLionel Sambuc 		if (f->filp_flags & O_APPEND) position = vp->v_size;
235433d6423SLionel Sambuc 	}
236433d6423SLionel Sambuc 
237433d6423SLionel Sambuc 	/* Issue request */
238433d6423SLionel Sambuc 	if(rw_flag == PEEKING) {
239433d6423SLionel Sambuc 		r = req_peek(vp->v_fs_e, vp->v_inode_nr, position, size);
240433d6423SLionel Sambuc 	} else {
241433d6423SLionel Sambuc 		off_t new_pos;
242433d6423SLionel Sambuc 		r = req_readwrite(vp->v_fs_e, vp->v_inode_nr, position,
243433d6423SLionel Sambuc 			rw_flag, for_e, buf, size, &new_pos,
244433d6423SLionel Sambuc 			&cum_io_incr);
245433d6423SLionel Sambuc 
246433d6423SLionel Sambuc 		if (r >= 0) {
247433d6423SLionel Sambuc 			position = new_pos;
248433d6423SLionel Sambuc 			cum_io += cum_io_incr;
249433d6423SLionel Sambuc 		}
250433d6423SLionel Sambuc         }
251433d6423SLionel Sambuc   }
252433d6423SLionel Sambuc 
253433d6423SLionel Sambuc   /* On write, update file size and access time. */
254433d6423SLionel Sambuc   if (rw_flag == WRITING) {
255433d6423SLionel Sambuc 	if (S_ISREG(vp->v_mode) || S_ISDIR(vp->v_mode)) {
256433d6423SLionel Sambuc 		if (position > vp->v_size) {
257433d6423SLionel Sambuc 			vp->v_size = position;
258433d6423SLionel Sambuc 		}
259433d6423SLionel Sambuc 	}
260433d6423SLionel Sambuc   }
261433d6423SLionel Sambuc 
262433d6423SLionel Sambuc   f->filp_pos = position;
263433d6423SLionel Sambuc 
264433d6423SLionel Sambuc   if (r == EPIPE && rw_flag == WRITING) {
265433d6423SLionel Sambuc 	/* Process is writing, but there is no reader. Tell the kernel to
266179bddcfSDavid van Moolenbroek 	 * generate a SIGPIPE signal.
267433d6423SLionel Sambuc 	 */
268433d6423SLionel Sambuc 	if (!(f->filp_flags & O_NOSIGPIPE)) {
269433d6423SLionel Sambuc 		sys_kill(rfp->fp_endpoint, SIGPIPE);
270433d6423SLionel Sambuc 	}
271433d6423SLionel Sambuc   }
272433d6423SLionel Sambuc 
273433d6423SLionel Sambuc   if (r == OK) {
274433d6423SLionel Sambuc 	return(cum_io);
275433d6423SLionel Sambuc   }
276433d6423SLionel Sambuc   return(r);
277433d6423SLionel Sambuc }
278433d6423SLionel Sambuc 
279433d6423SLionel Sambuc /*===========================================================================*
280433d6423SLionel Sambuc  *				do_getdents				     *
281433d6423SLionel Sambuc  *===========================================================================*/
do_getdents(void)282433d6423SLionel Sambuc int do_getdents(void)
283433d6423SLionel Sambuc {
284433d6423SLionel Sambuc /* Perform the getdents(fd, buf, size) system call. */
285232819ddSDavid van Moolenbroek   int fd, r = OK;
286433d6423SLionel Sambuc   off_t new_pos;
287232819ddSDavid van Moolenbroek   vir_bytes buf;
288232819ddSDavid van Moolenbroek   size_t size;
289433d6423SLionel Sambuc   register struct filp *rfilp;
290433d6423SLionel Sambuc 
291232819ddSDavid van Moolenbroek   /* This field must always be set to zero for getdents(). */
292232819ddSDavid van Moolenbroek   if (job_m_in.m_lc_vfs_readwrite.cum_io != 0)
293232819ddSDavid van Moolenbroek 	return(EINVAL);
294232819ddSDavid van Moolenbroek 
295232819ddSDavid van Moolenbroek   fd = job_m_in.m_lc_vfs_readwrite.fd;
296232819ddSDavid van Moolenbroek   buf = job_m_in.m_lc_vfs_readwrite.buf;
297232819ddSDavid van Moolenbroek   size = job_m_in.m_lc_vfs_readwrite.len;
298433d6423SLionel Sambuc 
299433d6423SLionel Sambuc   /* Is the file descriptor valid? */
300232819ddSDavid van Moolenbroek   if ( (rfilp = get_filp(fd, VNODE_READ)) == NULL)
301433d6423SLionel Sambuc 	return(err_code);
302433d6423SLionel Sambuc 
303433d6423SLionel Sambuc   if (!(rfilp->filp_mode & R_BIT))
304433d6423SLionel Sambuc 	r = EBADF;
305433d6423SLionel Sambuc   else if (!S_ISDIR(rfilp->filp_vno->v_mode))
306433d6423SLionel Sambuc 	r = EBADF;
307433d6423SLionel Sambuc 
308433d6423SLionel Sambuc   if (r == OK) {
309433d6423SLionel Sambuc 	r = req_getdents(rfilp->filp_vno->v_fs_e, rfilp->filp_vno->v_inode_nr,
310232819ddSDavid van Moolenbroek 	    rfilp->filp_pos, buf, size, &new_pos, 0);
311433d6423SLionel Sambuc 
312433d6423SLionel Sambuc 	if (r > 0) rfilp->filp_pos = new_pos;
313433d6423SLionel Sambuc   }
314433d6423SLionel Sambuc 
315433d6423SLionel Sambuc   unlock_filp(rfilp);
316433d6423SLionel Sambuc   return(r);
317433d6423SLionel Sambuc }
318433d6423SLionel Sambuc 
319433d6423SLionel Sambuc 
320433d6423SLionel Sambuc /*===========================================================================*
321433d6423SLionel Sambuc  *				rw_pipe					     *
322433d6423SLionel Sambuc  *===========================================================================*/
rw_pipe(int rw_flag,endpoint_t usr_e,struct filp * f,int callnr,int fd,vir_bytes buf,size_t nbytes,size_t cum_io)323232819ddSDavid van Moolenbroek int rw_pipe(int rw_flag, endpoint_t usr_e, struct filp *f, int callnr, int fd,
324232819ddSDavid van Moolenbroek 	vir_bytes buf, size_t nbytes, size_t cum_io)
325433d6423SLionel Sambuc {
326232819ddSDavid van Moolenbroek   int r, oflags, partial_pipe = FALSE;
327232819ddSDavid van Moolenbroek   size_t size;
3283c8950ccSBen Gras   size_t cum_io_incr;
329433d6423SLionel Sambuc   struct vnode *vp;
330433d6423SLionel Sambuc   off_t  position, new_pos;
331433d6423SLionel Sambuc 
332433d6423SLionel Sambuc   /* Must make sure we're operating on locked filp and vnode */
333433d6423SLionel Sambuc   assert(tll_locked_by_me(&f->filp_vno->v_lock));
334433d6423SLionel Sambuc   assert(mutex_trylock(&f->filp_lock) == -EDEADLK);
335433d6423SLionel Sambuc 
336433d6423SLionel Sambuc   oflags = f->filp_flags;
337433d6423SLionel Sambuc   vp = f->filp_vno;
338433d6423SLionel Sambuc   position = 0;	/* Not actually used */
339433d6423SLionel Sambuc 
340433d6423SLionel Sambuc   assert(rw_flag == READING || rw_flag == WRITING);
341433d6423SLionel Sambuc 
342232819ddSDavid van Moolenbroek   r = pipe_check(f, rw_flag, oflags, nbytes, 0);
343433d6423SLionel Sambuc   if (r <= 0) {
344232819ddSDavid van Moolenbroek 	if (r == SUSPEND)
345232819ddSDavid van Moolenbroek 		pipe_suspend(callnr, fd, buf, nbytes, cum_io);
346232819ddSDavid van Moolenbroek 
347179bddcfSDavid van Moolenbroek 	/* If pipe_check returns an error instead of suspending the call, we
348179bddcfSDavid van Moolenbroek 	 * return that error, even if we are resuming a partially completed
349179bddcfSDavid van Moolenbroek 	 * operation (ie, a large blocking write), to match NetBSD's behavior.
350179bddcfSDavid van Moolenbroek 	 */
351433d6423SLionel Sambuc 	return(r);
352433d6423SLionel Sambuc   }
353433d6423SLionel Sambuc 
354433d6423SLionel Sambuc   size = r;
355232819ddSDavid van Moolenbroek   if (size < nbytes) partial_pipe = TRUE;
356433d6423SLionel Sambuc 
357433d6423SLionel Sambuc   /* Truncate read request at size. */
358433d6423SLionel Sambuc   if (rw_flag == READING && size > vp->v_size) {
359433d6423SLionel Sambuc 	size = vp->v_size;
360433d6423SLionel Sambuc   }
361433d6423SLionel Sambuc 
362433d6423SLionel Sambuc   if (vp->v_mapfs_e == 0)
363433d6423SLionel Sambuc 	panic("unmapped pipe");
364433d6423SLionel Sambuc 
365433d6423SLionel Sambuc   r = req_readwrite(vp->v_mapfs_e, vp->v_mapinode_nr, position, rw_flag, usr_e,
366433d6423SLionel Sambuc 		    buf, size, &new_pos, &cum_io_incr);
367433d6423SLionel Sambuc 
368433d6423SLionel Sambuc   if (r != OK) {
369179bddcfSDavid van Moolenbroek 	assert(r != SUSPEND);
370433d6423SLionel Sambuc 	return(r);
371433d6423SLionel Sambuc   }
372433d6423SLionel Sambuc 
373433d6423SLionel Sambuc   cum_io += cum_io_incr;
374433d6423SLionel Sambuc   buf += cum_io_incr;
375232819ddSDavid van Moolenbroek   nbytes -= cum_io_incr;
376433d6423SLionel Sambuc 
377f859061eSDavid van Moolenbroek   if (rw_flag == READING)
378f859061eSDavid van Moolenbroek 	vp->v_size -= cum_io_incr;
379f859061eSDavid van Moolenbroek   else
380f859061eSDavid van Moolenbroek 	vp->v_size += cum_io_incr;
381433d6423SLionel Sambuc 
382433d6423SLionel Sambuc   if (partial_pipe) {
383433d6423SLionel Sambuc 	/* partial write on pipe with */
384433d6423SLionel Sambuc 	/* O_NONBLOCK, return write count */
385433d6423SLionel Sambuc 	if (!(oflags & O_NONBLOCK)) {
386232819ddSDavid van Moolenbroek 		/* partial write on pipe with nbytes > PIPE_BUF, non-atomic */
387232819ddSDavid van Moolenbroek 		pipe_suspend(callnr, fd, buf, nbytes, cum_io);
388433d6423SLionel Sambuc 		return(SUSPEND);
389433d6423SLionel Sambuc 	}
390433d6423SLionel Sambuc   }
391433d6423SLionel Sambuc 
392433d6423SLionel Sambuc   return(cum_io);
393433d6423SLionel Sambuc }
394