xref: /minix3/minix/servers/vfs/read.c (revision 3c8950cce94bbea7236b2d07ae8e59f07e4432c5)
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 "scratchpad.h"
24433d6423SLionel Sambuc #include "vnode.h"
25433d6423SLionel Sambuc #include "vmnt.h"
26433d6423SLionel Sambuc 
27433d6423SLionel Sambuc 
28433d6423SLionel Sambuc /*===========================================================================*
29433d6423SLionel Sambuc  *				do_read					     *
30433d6423SLionel Sambuc  *===========================================================================*/
31433d6423SLionel Sambuc int do_read(void)
32433d6423SLionel Sambuc {
33433d6423SLionel Sambuc   return(do_read_write_peek(READING, job_m_in.m_lc_vfs_readwrite.fd,
34433d6423SLionel Sambuc           job_m_in.m_lc_vfs_readwrite.buf, job_m_in.m_lc_vfs_readwrite.len));
35433d6423SLionel Sambuc }
36433d6423SLionel Sambuc 
37433d6423SLionel Sambuc 
38433d6423SLionel Sambuc /*===========================================================================*
39433d6423SLionel Sambuc  *				lock_bsf				     *
40433d6423SLionel Sambuc  *===========================================================================*/
41433d6423SLionel Sambuc void lock_bsf(void)
42433d6423SLionel Sambuc {
43433d6423SLionel Sambuc   struct worker_thread *org_self;
44433d6423SLionel Sambuc 
45433d6423SLionel Sambuc   if (mutex_trylock(&bsf_lock) == 0)
46433d6423SLionel Sambuc 	return;
47433d6423SLionel Sambuc 
48433d6423SLionel Sambuc   org_self = worker_suspend();
49433d6423SLionel Sambuc 
50433d6423SLionel Sambuc   if (mutex_lock(&bsf_lock) != 0)
51433d6423SLionel Sambuc 	panic("unable to lock block special file lock");
52433d6423SLionel Sambuc 
53433d6423SLionel Sambuc   worker_resume(org_self);
54433d6423SLionel Sambuc }
55433d6423SLionel Sambuc 
56433d6423SLionel Sambuc /*===========================================================================*
57433d6423SLionel Sambuc  *				unlock_bsf				     *
58433d6423SLionel Sambuc  *===========================================================================*/
59433d6423SLionel Sambuc void unlock_bsf(void)
60433d6423SLionel Sambuc {
61433d6423SLionel Sambuc   if (mutex_unlock(&bsf_lock) != 0)
62433d6423SLionel Sambuc 	panic("failed to unlock block special file lock");
63433d6423SLionel Sambuc }
64433d6423SLionel Sambuc 
65433d6423SLionel Sambuc /*===========================================================================*
66433d6423SLionel Sambuc  *				check_bsf				     *
67433d6423SLionel Sambuc  *===========================================================================*/
68433d6423SLionel Sambuc void check_bsf_lock(void)
69433d6423SLionel Sambuc {
70433d6423SLionel Sambuc 	int r = mutex_trylock(&bsf_lock);
71433d6423SLionel Sambuc 
72433d6423SLionel Sambuc 	if (r == -EBUSY)
73433d6423SLionel Sambuc 		panic("bsf_lock locked");
74433d6423SLionel Sambuc 	else if (r != 0)
75433d6423SLionel Sambuc 		panic("bsf_lock weird state");
76433d6423SLionel Sambuc 
77433d6423SLionel Sambuc 	/* r == 0 */
78433d6423SLionel Sambuc 	unlock_bsf();
79433d6423SLionel Sambuc }
80433d6423SLionel Sambuc 
81433d6423SLionel Sambuc /*===========================================================================*
82433d6423SLionel Sambuc  *				actual_read_write_peek			     *
83433d6423SLionel Sambuc  *===========================================================================*/
84433d6423SLionel Sambuc int actual_read_write_peek(struct fproc *rfp, int rw_flag, int io_fd,
85433d6423SLionel Sambuc 	vir_bytes io_buf, size_t io_nbytes)
86433d6423SLionel Sambuc {
87433d6423SLionel Sambuc /* Perform read(fd, buffer, nbytes) or write(fd, buffer, nbytes) call. */
88433d6423SLionel Sambuc   struct filp *f;
89433d6423SLionel Sambuc   tll_access_t locktype;
90433d6423SLionel Sambuc   int r;
91433d6423SLionel Sambuc   int ro = 1;
92433d6423SLionel Sambuc 
93433d6423SLionel Sambuc   if(rw_flag == WRITING) ro = 0;
94433d6423SLionel Sambuc 
95433d6423SLionel Sambuc   scratch(rfp).file.fd_nr = io_fd;
96433d6423SLionel Sambuc   scratch(rfp).io.io_buffer = io_buf;
97433d6423SLionel Sambuc   scratch(rfp).io.io_nbytes = io_nbytes;
98433d6423SLionel Sambuc 
99433d6423SLionel Sambuc   locktype = rw_flag == WRITING ? VNODE_WRITE : VNODE_READ;
100433d6423SLionel Sambuc   if ((f = get_filp2(rfp, scratch(rfp).file.fd_nr, locktype)) == NULL)
101433d6423SLionel Sambuc 	return(err_code);
102433d6423SLionel Sambuc 
103433d6423SLionel Sambuc   assert(f->filp_count > 0);
104433d6423SLionel Sambuc 
105433d6423SLionel Sambuc   if (((f->filp_mode) & (ro ? R_BIT : W_BIT)) == 0) {
106433d6423SLionel Sambuc 	unlock_filp(f);
107433d6423SLionel Sambuc 	return(EBADF);
108433d6423SLionel Sambuc   }
109433d6423SLionel Sambuc   if (scratch(rfp).io.io_nbytes == 0) {
110433d6423SLionel Sambuc 	unlock_filp(f);
111433d6423SLionel Sambuc 	return(0);	/* so char special files need not check for 0*/
112433d6423SLionel Sambuc   }
113433d6423SLionel Sambuc 
114433d6423SLionel Sambuc   r = read_write(rfp, rw_flag, f, scratch(rfp).io.io_buffer,
115433d6423SLionel Sambuc 	scratch(rfp).io.io_nbytes, who_e);
116433d6423SLionel Sambuc 
117433d6423SLionel Sambuc   unlock_filp(f);
118433d6423SLionel Sambuc   return(r);
119433d6423SLionel Sambuc }
120433d6423SLionel Sambuc 
121433d6423SLionel Sambuc /*===========================================================================*
122433d6423SLionel Sambuc  *				do_read_write_peek			     *
123433d6423SLionel Sambuc  *===========================================================================*/
124433d6423SLionel Sambuc int do_read_write_peek(int rw_flag, int io_fd, vir_bytes io_buf, size_t io_nbytes)
125433d6423SLionel Sambuc {
126433d6423SLionel Sambuc 	return actual_read_write_peek(fp, rw_flag, io_fd, io_buf, io_nbytes);
127433d6423SLionel Sambuc }
128433d6423SLionel Sambuc 
129433d6423SLionel Sambuc /*===========================================================================*
130433d6423SLionel Sambuc  *				read_write				     *
131433d6423SLionel Sambuc  *===========================================================================*/
132433d6423SLionel Sambuc int read_write(struct fproc *rfp, int rw_flag, struct filp *f,
133433d6423SLionel Sambuc 	vir_bytes buf, size_t size, endpoint_t for_e)
134433d6423SLionel Sambuc {
135433d6423SLionel Sambuc   register struct vnode *vp;
136433d6423SLionel Sambuc   off_t position, res_pos;
137*3c8950ccSBen Gras   size_t cum_io, res_cum_io;
138*3c8950ccSBen Gras   size_t cum_io_incr;
139433d6423SLionel Sambuc   int op, r;
140433d6423SLionel Sambuc   dev_t dev;
141433d6423SLionel Sambuc 
142433d6423SLionel Sambuc   position = f->filp_pos;
143433d6423SLionel Sambuc   vp = f->filp_vno;
144433d6423SLionel Sambuc   r = OK;
145433d6423SLionel Sambuc   cum_io = 0;
146433d6423SLionel Sambuc 
147433d6423SLionel Sambuc   assert(rw_flag == READING || rw_flag == WRITING || rw_flag == PEEKING);
148433d6423SLionel Sambuc 
149433d6423SLionel Sambuc   if (size > SSIZE_MAX) return(EINVAL);
150433d6423SLionel Sambuc 
151433d6423SLionel Sambuc   op = (rw_flag == READING ? CDEV_READ : CDEV_WRITE);
152433d6423SLionel Sambuc 
153433d6423SLionel Sambuc   if (S_ISFIFO(vp->v_mode)) {		/* Pipes */
154433d6423SLionel Sambuc 	if (rfp->fp_cum_io_partial != 0) {
155433d6423SLionel Sambuc 		panic("VFS: read_write: fp_cum_io_partial not clear");
156433d6423SLionel Sambuc 	}
157433d6423SLionel Sambuc 	if(rw_flag == PEEKING) {
158433d6423SLionel Sambuc 	  	printf("read_write: peek on pipe makes no sense\n");
159433d6423SLionel Sambuc 		return EINVAL;
160433d6423SLionel Sambuc 	}
161433d6423SLionel Sambuc 	r = rw_pipe(rw_flag, for_e, f, buf, size);
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;
172433d6423SLionel Sambuc 
173433d6423SLionel Sambuc 	r = cdev_io(op, dev, for_e, buf, position, size, f->filp_flags);
174433d6423SLionel Sambuc 	if (r >= 0) {
175433d6423SLionel Sambuc 		/* This should no longer happen: all calls are asynchronous. */
176433d6423SLionel Sambuc 		printf("VFS: I/O to device %llx succeeded immediately!?\n", dev);
177433d6423SLionel Sambuc 		cum_io = r;
178433d6423SLionel Sambuc 		position += r;
179433d6423SLionel Sambuc 		r = OK;
180433d6423SLionel Sambuc 	} else if (r == SUSPEND) {
181433d6423SLionel Sambuc 		/* FIXME: multiple read/write operations on a single filp
182433d6423SLionel Sambuc 		 * should be serialized. They currently aren't; in order to
183433d6423SLionel Sambuc 		 * achieve a similar effect, we optimistically advance the file
184433d6423SLionel Sambuc 		 * position here. This works under the following assumptions:
185433d6423SLionel Sambuc 		 * - character drivers that use the seek position at all,
186433d6423SLionel Sambuc 		 *   expose a view of a statically-sized range of bytes, i.e.,
187433d6423SLionel Sambuc 		 *   they are basically byte-granular block devices;
188433d6423SLionel Sambuc 		 * - if short I/O or an error is returned, all subsequent calls
189433d6423SLionel Sambuc 		 *   will return (respectively) EOF and an error;
190433d6423SLionel Sambuc 		 * - the application never checks its own file seek position,
191433d6423SLionel Sambuc 		 *   or does not care that it may end up having seeked beyond
192433d6423SLionel Sambuc 		 *   the number of bytes it has actually read;
193433d6423SLionel Sambuc 		 * - communication to the character driver is FIFO (this one
194433d6423SLionel Sambuc 		 *   is actually true! whew).
195433d6423SLionel Sambuc 		 * Many improvements are possible here, but in the end,
196433d6423SLionel Sambuc 		 * anything short of queuing concurrent operations will be
197433d6423SLionel Sambuc 		 * suboptimal - so we settle for this hack for now.
198433d6423SLionel Sambuc 		 */
199433d6423SLionel Sambuc 		position += size;
200433d6423SLionel Sambuc 	}
201433d6423SLionel Sambuc   } else if (S_ISBLK(vp->v_mode)) {	/* Block special files. */
202433d6423SLionel Sambuc 	if (vp->v_sdev == NO_DEV)
203433d6423SLionel Sambuc 		panic("VFS: read_write tries to access block dev NO_DEV");
204433d6423SLionel Sambuc 
205433d6423SLionel Sambuc 	lock_bsf();
206433d6423SLionel Sambuc 
207433d6423SLionel Sambuc 	if(rw_flag == PEEKING) {
208433d6423SLionel Sambuc 		r = req_bpeek(vp->v_bfs_e, vp->v_sdev, position, size);
209433d6423SLionel Sambuc 	} else {
210433d6423SLionel Sambuc 		r = req_breadwrite(vp->v_bfs_e, for_e, vp->v_sdev, position,
211433d6423SLionel Sambuc 		       size, buf, rw_flag, &res_pos, &res_cum_io);
212433d6423SLionel Sambuc 		if (r == OK) {
213433d6423SLionel Sambuc 			position = res_pos;
214433d6423SLionel Sambuc 			cum_io += res_cum_io;
215433d6423SLionel Sambuc 		}
216433d6423SLionel Sambuc 	}
217433d6423SLionel Sambuc 
218433d6423SLionel Sambuc 	unlock_bsf();
219433d6423SLionel Sambuc   } else {				/* Regular files */
220433d6423SLionel Sambuc 	if (rw_flag == WRITING) {
221433d6423SLionel Sambuc 		/* Check for O_APPEND flag. */
222433d6423SLionel Sambuc 		if (f->filp_flags & O_APPEND) position = vp->v_size;
223433d6423SLionel Sambuc 	}
224433d6423SLionel Sambuc 
225433d6423SLionel Sambuc 	/* Issue request */
226433d6423SLionel Sambuc 	if(rw_flag == PEEKING) {
227433d6423SLionel Sambuc 		r = req_peek(vp->v_fs_e, vp->v_inode_nr, position, size);
228433d6423SLionel Sambuc 	} else {
229433d6423SLionel Sambuc 		off_t new_pos;
230433d6423SLionel Sambuc 		r = req_readwrite(vp->v_fs_e, vp->v_inode_nr, position,
231433d6423SLionel Sambuc 			rw_flag, for_e, buf, size, &new_pos,
232433d6423SLionel Sambuc 			&cum_io_incr);
233433d6423SLionel Sambuc 
234433d6423SLionel Sambuc 		if (r >= 0) {
235433d6423SLionel Sambuc 			position = new_pos;
236433d6423SLionel Sambuc 			cum_io += cum_io_incr;
237433d6423SLionel Sambuc 		}
238433d6423SLionel Sambuc         }
239433d6423SLionel Sambuc   }
240433d6423SLionel Sambuc 
241433d6423SLionel Sambuc   /* On write, update file size and access time. */
242433d6423SLionel Sambuc   if (rw_flag == WRITING) {
243433d6423SLionel Sambuc 	if (S_ISREG(vp->v_mode) || S_ISDIR(vp->v_mode)) {
244433d6423SLionel Sambuc 		if (position > vp->v_size) {
245433d6423SLionel Sambuc 			vp->v_size = position;
246433d6423SLionel Sambuc 		}
247433d6423SLionel Sambuc 	}
248433d6423SLionel Sambuc   }
249433d6423SLionel Sambuc 
250433d6423SLionel Sambuc   f->filp_pos = position;
251433d6423SLionel Sambuc 
252433d6423SLionel Sambuc   if (r == EPIPE && rw_flag == WRITING) {
253433d6423SLionel Sambuc 	/* Process is writing, but there is no reader. Tell the kernel to
254433d6423SLionel Sambuc 	 * generate s SIGPIPE signal.
255433d6423SLionel Sambuc 	 */
256433d6423SLionel Sambuc 	if (!(f->filp_flags & O_NOSIGPIPE)) {
257433d6423SLionel Sambuc 		sys_kill(rfp->fp_endpoint, SIGPIPE);
258433d6423SLionel Sambuc 	}
259433d6423SLionel Sambuc   }
260433d6423SLionel Sambuc 
261433d6423SLionel Sambuc   if (r == OK) {
262433d6423SLionel Sambuc 	return(cum_io);
263433d6423SLionel Sambuc   }
264433d6423SLionel Sambuc   return(r);
265433d6423SLionel Sambuc }
266433d6423SLionel Sambuc 
267433d6423SLionel Sambuc /*===========================================================================*
268433d6423SLionel Sambuc  *				do_getdents				     *
269433d6423SLionel Sambuc  *===========================================================================*/
270433d6423SLionel Sambuc int do_getdents(void)
271433d6423SLionel Sambuc {
272433d6423SLionel Sambuc /* Perform the getdents(fd, buf, size) system call. */
273433d6423SLionel Sambuc   int r = OK;
274433d6423SLionel Sambuc   off_t new_pos;
275433d6423SLionel Sambuc   register struct filp *rfilp;
276433d6423SLionel Sambuc 
277433d6423SLionel Sambuc   scratch(fp).file.fd_nr = job_m_in.m_lc_vfs_readwrite.fd;
278433d6423SLionel Sambuc   scratch(fp).io.io_buffer = job_m_in.m_lc_vfs_readwrite.buf;
279433d6423SLionel Sambuc   scratch(fp).io.io_nbytes = job_m_in.m_lc_vfs_readwrite.len;
280433d6423SLionel Sambuc 
281433d6423SLionel Sambuc   /* Is the file descriptor valid? */
282433d6423SLionel Sambuc   if ( (rfilp = get_filp(scratch(fp).file.fd_nr, VNODE_READ)) == NULL)
283433d6423SLionel Sambuc 	return(err_code);
284433d6423SLionel Sambuc 
285433d6423SLionel Sambuc   if (!(rfilp->filp_mode & R_BIT))
286433d6423SLionel Sambuc 	r = EBADF;
287433d6423SLionel Sambuc   else if (!S_ISDIR(rfilp->filp_vno->v_mode))
288433d6423SLionel Sambuc 	r = EBADF;
289433d6423SLionel Sambuc 
290433d6423SLionel Sambuc   if (r == OK) {
291433d6423SLionel Sambuc 	r = req_getdents(rfilp->filp_vno->v_fs_e, rfilp->filp_vno->v_inode_nr,
292433d6423SLionel Sambuc 			 rfilp->filp_pos, scratch(fp).io.io_buffer,
293433d6423SLionel Sambuc 			 scratch(fp).io.io_nbytes, &new_pos, 0);
294433d6423SLionel Sambuc 
295433d6423SLionel Sambuc 	if (r > 0) rfilp->filp_pos = new_pos;
296433d6423SLionel Sambuc   }
297433d6423SLionel Sambuc 
298433d6423SLionel Sambuc   unlock_filp(rfilp);
299433d6423SLionel Sambuc   return(r);
300433d6423SLionel Sambuc }
301433d6423SLionel Sambuc 
302433d6423SLionel Sambuc 
303433d6423SLionel Sambuc /*===========================================================================*
304433d6423SLionel Sambuc  *				rw_pipe					     *
305433d6423SLionel Sambuc  *===========================================================================*/
306433d6423SLionel Sambuc int rw_pipe(rw_flag, usr_e, f, buf, req_size)
307433d6423SLionel Sambuc int rw_flag;			/* READING or WRITING */
308433d6423SLionel Sambuc endpoint_t usr_e;
309433d6423SLionel Sambuc struct filp *f;
310433d6423SLionel Sambuc vir_bytes buf;
311433d6423SLionel Sambuc size_t req_size;
312433d6423SLionel Sambuc {
313433d6423SLionel Sambuc   int r, oflags, partial_pipe = 0;
314*3c8950ccSBen Gras   size_t size, cum_io;
315*3c8950ccSBen Gras   size_t cum_io_incr;
316433d6423SLionel Sambuc   struct vnode *vp;
317433d6423SLionel Sambuc   off_t  position, new_pos;
318433d6423SLionel Sambuc 
319433d6423SLionel Sambuc   /* Must make sure we're operating on locked filp and vnode */
320433d6423SLionel Sambuc   assert(tll_locked_by_me(&f->filp_vno->v_lock));
321433d6423SLionel Sambuc   assert(mutex_trylock(&f->filp_lock) == -EDEADLK);
322433d6423SLionel Sambuc 
323433d6423SLionel Sambuc   oflags = f->filp_flags;
324433d6423SLionel Sambuc   vp = f->filp_vno;
325433d6423SLionel Sambuc   position = 0;	/* Not actually used */
326433d6423SLionel Sambuc 
327433d6423SLionel Sambuc   assert(rw_flag == READING || rw_flag == WRITING);
328433d6423SLionel Sambuc 
329433d6423SLionel Sambuc   /* fp->fp_cum_io_partial is only nonzero when doing partial writes */
330433d6423SLionel Sambuc   cum_io = fp->fp_cum_io_partial;
331433d6423SLionel Sambuc 
332433d6423SLionel Sambuc   r = pipe_check(f, rw_flag, oflags, req_size, 0);
333433d6423SLionel Sambuc   if (r <= 0) {
334433d6423SLionel Sambuc 	if (r == SUSPEND) pipe_suspend(f, buf, req_size);
335433d6423SLionel Sambuc 	return(r);
336433d6423SLionel Sambuc   }
337433d6423SLionel Sambuc 
338433d6423SLionel Sambuc   size = r;
339433d6423SLionel Sambuc   if (size < req_size) partial_pipe = 1;
340433d6423SLionel Sambuc 
341433d6423SLionel Sambuc   /* Truncate read request at size. */
342433d6423SLionel Sambuc   if (rw_flag == READING && size > vp->v_size) {
343433d6423SLionel Sambuc 	size = vp->v_size;
344433d6423SLionel Sambuc   }
345433d6423SLionel Sambuc 
346433d6423SLionel Sambuc   if (vp->v_mapfs_e == 0)
347433d6423SLionel Sambuc 	panic("unmapped pipe");
348433d6423SLionel Sambuc 
349433d6423SLionel Sambuc   r = req_readwrite(vp->v_mapfs_e, vp->v_mapinode_nr, position, rw_flag, usr_e,
350433d6423SLionel Sambuc 		    buf, size, &new_pos, &cum_io_incr);
351433d6423SLionel Sambuc 
352433d6423SLionel Sambuc   if (r != OK) {
353433d6423SLionel Sambuc 	return(r);
354433d6423SLionel Sambuc   }
355433d6423SLionel Sambuc 
356433d6423SLionel Sambuc   cum_io += cum_io_incr;
357433d6423SLionel Sambuc   buf += cum_io_incr;
358433d6423SLionel Sambuc   req_size -= cum_io_incr;
359433d6423SLionel Sambuc 
360f859061eSDavid van Moolenbroek   if (rw_flag == READING)
361f859061eSDavid van Moolenbroek 	vp->v_size -= cum_io_incr;
362f859061eSDavid van Moolenbroek   else
363f859061eSDavid van Moolenbroek 	vp->v_size += cum_io_incr;
364433d6423SLionel Sambuc 
365433d6423SLionel Sambuc   if (partial_pipe) {
366433d6423SLionel Sambuc 	/* partial write on pipe with */
367433d6423SLionel Sambuc 	/* O_NONBLOCK, return write count */
368433d6423SLionel Sambuc 	if (!(oflags & O_NONBLOCK)) {
369433d6423SLionel Sambuc 		/* partial write on pipe with req_size > PIPE_SIZE,
370433d6423SLionel Sambuc 		 * non-atomic
371433d6423SLionel Sambuc 		 */
372433d6423SLionel Sambuc 		fp->fp_cum_io_partial = cum_io;
373433d6423SLionel Sambuc 		pipe_suspend(f, buf, req_size);
374433d6423SLionel Sambuc 		return(SUSPEND);
375433d6423SLionel Sambuc 	}
376433d6423SLionel Sambuc   }
377433d6423SLionel Sambuc 
378433d6423SLionel Sambuc   fp->fp_cum_io_partial = 0;
379433d6423SLionel Sambuc 
380433d6423SLionel Sambuc   return(cum_io);
381433d6423SLionel Sambuc }
382