more stack for boot
[minix.git] / servers / vfs / read.c
bloba1a377c8ee178747b3e773d825671cb3477ce93a
1 /* This file contains the heart of the mechanism used to read (and write)
2 * files. Read and write requests are split up into chunks that do not cross
3 * block boundaries. Each chunk is then processed in turn. Reads on special
4 * files are also detected and handled.
6 * The entry points into this file are
7 * do_read: perform the READ system call by calling read_write
8 * do_getdents: read entries from a directory (GETDENTS)
9 * read_write: actually do the work of READ and WRITE
13 #include "fs.h"
14 #include <fcntl.h>
15 #include <unistd.h>
16 #include <minix/com.h>
17 #include <minix/u64.h>
18 #include "file.h"
19 #include "fproc.h"
20 #include "param.h"
21 #include <dirent.h>
22 #include <assert.h>
23 #include <minix/vfsif.h>
24 #include "vnode.h"
25 #include "vmnt.h"
28 /*===========================================================================*
29 * do_read *
30 *===========================================================================*/
31 PUBLIC int do_read()
33 return(read_write(READING));
37 /*===========================================================================*
38 * read_write *
39 *===========================================================================*/
40 PUBLIC int read_write(rw_flag)
41 int rw_flag; /* READING or WRITING */
43 /* Perform read(fd, buffer, nbytes) or write(fd, buffer, nbytes) call. */
44 register struct filp *f;
45 register struct vnode *vp;
46 u64_t position, res_pos, new_pos;
47 unsigned int cum_io, cum_io_incr, res_cum_io;
48 int op, oflags, r, block_spec, char_spec;
49 int regular;
50 mode_t mode_word;
52 /* If the file descriptor is valid, get the vnode, size and mode. */
53 if (m_in.nbytes < 0) return(EINVAL);
54 if ((f = get_filp(m_in.fd)) == NIL_FILP) return(err_code);
55 if (((f->filp_mode) & (rw_flag == READING ? R_BIT : W_BIT)) == 0) {
56 return(f->filp_mode == FILP_CLOSED ? EIO : EBADF);
58 if (m_in.nbytes == 0)
59 return(0); /* so char special files need not check for 0*/
61 position = f->filp_pos;
62 oflags = f->filp_flags;
63 vp = f->filp_vno;
64 r = OK;
65 cum_io = 0;
67 if (vp->v_pipe == I_PIPE) {
68 if (fp->fp_cum_io_partial != 0) {
69 panic("read_write: fp_cum_io_partial not clear");
71 return rw_pipe(rw_flag, who_e, m_in.fd, f, m_in.buffer, m_in.nbytes);
74 op = (rw_flag == READING ? VFS_DEV_READ : VFS_DEV_WRITE);
75 mode_word = vp->v_mode & I_TYPE;
76 regular = mode_word == I_REGULAR;
78 if ((char_spec = (mode_word == I_CHAR_SPECIAL ? 1 : 0))) {
79 if (vp->v_sdev == NO_DEV)
80 panic("read_write tries to read from character device NO_DEV");
83 if ((block_spec = (mode_word == I_BLOCK_SPECIAL ? 1 : 0))) {
84 if (vp->v_sdev == NO_DEV)
85 panic("read_write tries to read from block device NO_DEV");
88 if (char_spec) { /* Character special files. */
89 dev_t dev;
90 int suspend_reopen;
92 suspend_reopen = (f->filp_state != FS_NORMAL);
93 dev = (dev_t) vp->v_sdev;
95 r = dev_io(op, dev, who_e, m_in.buffer, position, m_in.nbytes, oflags,
96 suspend_reopen);
97 if (r >= 0) {
98 cum_io = r;
99 position = add64ul(position, r);
100 r = OK;
102 } else if (block_spec) { /* Block special files. */
103 r = req_breadwrite(vp->v_bfs_e, who_e, vp->v_sdev, position,
104 m_in.nbytes, m_in.buffer, rw_flag, &res_pos, &res_cum_io);
105 if (r == OK) {
106 position = res_pos;
107 cum_io += res_cum_io;
109 } else { /* Regular files */
110 if (rw_flag == WRITING && block_spec == 0) {
111 /* Check for O_APPEND flag. */
112 if (oflags & O_APPEND) position = cvul64(vp->v_size);
115 /* Issue request */
116 r = req_readwrite(vp->v_fs_e, vp->v_inode_nr, position, rw_flag, who_e,
117 m_in.buffer, m_in.nbytes, &new_pos, &cum_io_incr);
119 if (r >= 0) {
120 if (ex64hi(new_pos))
121 panic("read_write: bad new pos");
123 position = new_pos;
124 cum_io += cum_io_incr;
128 /* On write, update file size and access time. */
129 if (rw_flag == WRITING) {
130 if (regular || mode_word == I_DIRECTORY) {
131 if (cmp64ul(position, vp->v_size) > 0) {
132 if (ex64hi(position) != 0) {
133 panic("read_write: file size too big ");
135 vp->v_size = ex64lo(position);
140 f->filp_pos = position;
141 if (r == OK) return(cum_io);
142 return(r);
146 /*===========================================================================*
147 * do_getdents *
148 *===========================================================================*/
149 PUBLIC int do_getdents()
151 /* Perform the getdents(fd, buf, size) system call. */
152 int r;
153 u64_t new_pos;
154 register struct filp *rfilp;
156 /* Is the file descriptor valid? */
157 if ( (rfilp = get_filp(m_in.fd)) == NIL_FILP) {
158 return(err_code);
161 if (!(rfilp->filp_mode & R_BIT))
162 return(EBADF);
164 if ((rfilp->filp_vno->v_mode & I_TYPE) != I_DIRECTORY)
165 return(EBADF);
167 if (ex64hi(rfilp->filp_pos) != 0)
168 panic("do_getdents: should handle large offsets");
170 r = req_getdents(rfilp->filp_vno->v_fs_e, rfilp->filp_vno->v_inode_nr,
171 rfilp->filp_pos, m_in.buffer, m_in.nbytes, &new_pos);
173 if (r > 0)
174 rfilp->filp_pos = new_pos;
175 return(r);
179 /*===========================================================================*
180 * rw_pipe *
181 *===========================================================================*/
182 PUBLIC int rw_pipe(rw_flag, usr_e, fd_nr, f, buf, req_size)
183 int rw_flag; /* READING or WRITING */
184 endpoint_t usr_e;
185 int fd_nr;
186 struct filp *f;
187 char *buf;
188 size_t req_size;
190 int r, oflags, partial_pipe = 0;
191 size_t size, cum_io, cum_io_incr;
192 struct vnode *vp;
193 u64_t position, new_pos;
195 oflags = f->filp_flags;
196 vp = f->filp_vno;
197 position = cvu64((rw_flag == READING) ? vp->v_pipe_rd_pos :
198 vp->v_pipe_wr_pos);
199 /* fp->fp_cum_io_partial is only nonzero when doing partial writes */
200 cum_io = fp->fp_cum_io_partial;
202 r = pipe_check(vp, rw_flag, oflags, req_size, position, 0);
203 if (r <= 0) {
204 if (r == SUSPEND) pipe_suspend(rw_flag, fd_nr, buf, req_size);
205 return(r);
208 size = r;
209 if (size < req_size) partial_pipe = 1;
211 /* Truncate read request at size. */
212 if((rw_flag == READING) &&
213 cmp64ul(add64ul(position, size), vp->v_size) > 0) {
214 /* Position always should fit in an off_t (LONG_MAX). */
215 off_t pos32;
217 assert(cmp64ul(position, LONG_MAX) <= 0);
218 pos32 = cv64ul(position);
219 assert(pos32 >= 0);
220 assert(pos32 <= LONG_MAX);
221 size = vp->v_size - pos32;
224 if (vp->v_mapfs_e == 0)
225 panic("unmapped pipe");
227 r = req_readwrite(vp->v_mapfs_e, vp->v_mapinode_nr, position, rw_flag, usr_e,
228 buf, size, &new_pos, &cum_io_incr);
230 if (r >= 0) {
231 if (ex64hi(new_pos))
232 panic("rw_pipe: bad new pos");
234 position = new_pos;
235 cum_io += cum_io_incr;
236 buf += cum_io_incr;
237 req_size -= cum_io_incr;
240 /* On write, update file size and access time. */
241 if (rw_flag == WRITING) {
242 if (cmp64ul(position, vp->v_size) > 0) {
243 if (ex64hi(position) != 0) {
244 panic("read_write: file size too big for v_size");
246 vp->v_size = ex64lo(position);
248 } else {
249 if (cmp64ul(position, vp->v_size) >= 0) {
250 /* Reset pipe pointers */
251 vp->v_size = 0;
252 vp->v_pipe_rd_pos= 0;
253 vp->v_pipe_wr_pos= 0;
254 position = cvu64(0);
258 if (rw_flag == READING)
259 vp->v_pipe_rd_pos= cv64ul(position);
260 else
261 vp->v_pipe_wr_pos= cv64ul(position);
263 if (r == OK) {
264 if (partial_pipe) {
265 /* partial write on pipe with */
266 /* O_NONBLOCK, return write count */
267 if (!(oflags & O_NONBLOCK)) {
268 /* partial write on pipe with req_size > PIPE_SIZE,
269 * non-atomic
271 fp->fp_cum_io_partial = cum_io;
272 pipe_suspend(rw_flag, fd_nr, buf, req_size);
273 return(SUSPEND);
276 fp->fp_cum_io_partial = 0;
277 return(cum_io);
280 return(r);