. service tells you which device it couldn't stat
[minix3.git] / servers / vfs / read.c
blob47e68155f93a5140d83e4f1e7276b6efd9e1ae6e
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
11 * Changes for VFS:
12 * Jul 2006 (Balazs Gerofi)
15 #include "fs.h"
16 #include <fcntl.h>
17 #include <unistd.h>
18 #include <minix/com.h>
19 #include <minix/u64.h>
20 #include "file.h"
21 #include "fproc.h"
22 #include "param.h"
23 #include <dirent.h>
24 #include <assert.h>
26 #include <minix/vfsif.h>
27 #include "vnode.h"
28 #include "vmnt.h"
31 /*===========================================================================*
32 * do_read *
33 *===========================================================================*/
34 PUBLIC int do_read()
36 return(read_write(READING));
40 /*===========================================================================*
41 * read_write *
42 *===========================================================================*/
43 PUBLIC int read_write(rw_flag)
44 int rw_flag; /* READING or WRITING */
46 /* Perform read(fd, buffer, nbytes) or write(fd, buffer, nbytes) call. */
47 register struct filp *f;
48 register struct vnode *vp;
49 off_t bytes_left;
50 u64_t position;
51 unsigned int off, cum_io;
52 int op, oflags, r, chunk, usr, seg, block_spec, char_spec;
53 int regular, partial_pipe = 0, partial_cnt = 0;
54 mode_t mode_word;
55 struct filp *wf;
56 phys_bytes p;
57 struct dmap *dp;
59 /* Request and response structures */
60 struct readwrite_req req;
61 struct readwrite_res res;
63 /* For block spec files */
64 struct breadwrite_req breq;
66 /* PM loads segments by putting funny things in other bits of the
67 * message, indicated by a high bit in fd. */
68 if (who_e == PM_PROC_NR && (m_in.fd & _PM_SEG_FLAG)) {
69 seg = (int) m_in.m1_p2;
70 usr = (int) m_in.m1_p3;
71 m_in.fd &= ~(_PM_SEG_FLAG); /* get rid of flag bit */
73 else {
74 usr = who_e; /* normal case */
75 seg = D;
78 /* If the file descriptor is valid, get the vnode, size and mode. */
79 if (m_in.nbytes < 0) return(EINVAL);
80 if ((f = get_filp(m_in.fd)) == NIL_FILP) return(err_code);
81 if (((f->filp_mode) & (rw_flag == READING ? R_BIT : W_BIT)) == 0) {
82 return(f->filp_mode == FILP_CLOSED ? EIO : EBADF);
85 if (m_in.nbytes == 0)
86 return(0); /* so char special files need not check for 0*/
88 /* check if user process has the memory it needs.
89 * if not, copying will fail later.
90 * do this after 0-check above because umap doesn't want to map 0 bytes. */
91 if ((r = sys_umap(usr, seg, (vir_bytes) m_in.buffer, m_in.nbytes, &p)) != OK)
93 printf("VFS: read_write: umap failed for process %d\n", usr);
94 return r;
97 position = f->filp_pos;
98 oflags = f->filp_flags;
100 vp = f->filp_vno;
102 r = OK;
103 if (vp->v_pipe == I_PIPE) {
104 /* fp->fp_cum_io_partial is only nonzero when doing partial writes */
105 cum_io = fp->fp_cum_io_partial;
107 else {
108 cum_io = 0;
111 op = (rw_flag == READING ? VFS_DEV_READ : VFS_DEV_WRITE);
112 mode_word = vp->v_mode & I_TYPE;
113 regular = mode_word == I_REGULAR || mode_word == I_NAMED_PIPE;
115 if ((char_spec = (mode_word == I_CHAR_SPECIAL ? 1 : 0))) {
116 if (vp->v_sdev == NO_DEV)
117 panic(__FILE__,"read_write tries to read from "
118 "character device NO_DEV", NO_NUM);
121 if ((block_spec = (mode_word == I_BLOCK_SPECIAL ? 1 : 0))) {
122 if (vp->v_sdev == NO_DEV)
123 panic(__FILE__,"read_write tries to read from "
124 " block device NO_DEV", NO_NUM);
127 /* Character special files. */
128 if (char_spec) {
129 dev_t dev;
130 /*dev = (dev_t) f->filp_ino->i_zone[0];*/
131 dev = (dev_t) vp->v_sdev;
132 r = dev_io(op, dev, usr, m_in.buffer, position, m_in.nbytes, oflags);
133 if (r >= 0) {
134 cum_io = r;
135 position = add64ul(position, r);
136 r = OK;
139 /* Block special files. */
140 else if (block_spec) {
141 /* Fill in the fields of the request */
142 breq.rw_flag = rw_flag;
143 breq.fs_e = vp->v_bfs_e;
144 breq.blocksize = vp->v_blocksize;
145 breq.dev = vp->v_sdev;
146 breq.user_e = usr;
147 breq.pos = position;
148 breq.num_of_bytes = m_in.nbytes;
149 breq.user_addr = m_in.buffer;
151 /* Issue request */
152 r = req_breadwrite(&breq, &res);
154 position = res.new_pos;
155 cum_io += res.cum_io;
157 /* Regular files (and pipes) */
158 else {
159 if (rw_flag == WRITING && block_spec == 0) {
160 /* Check for O_APPEND flag. */
161 if (oflags & O_APPEND) position = cvul64(vp->v_size);
163 /* Check in advance to see if file will grow too big. */
164 if (cmp64ul(position, vp->v_vmnt->m_max_file_size - m_in.nbytes) > 0)
165 return(EFBIG);
169 /* Pipes are a little different. Check. */
170 if (vp->v_pipe == I_PIPE) {
171 r = pipe_check(vp, rw_flag, oflags,
172 m_in.nbytes, position, &partial_cnt, 0);
173 if (r <= 0) return(r);
176 if (partial_cnt > 0) {
177 /* So that we don't need to deal with partial count
178 * in the FS process.
180 m_in.nbytes = MIN(m_in.nbytes, partial_cnt);
181 partial_pipe = 1;
184 /* Fill in request structure */
185 req.fs_e = vp->v_fs_e;
186 req.rw_flag = rw_flag;
187 req.inode_nr = vp->v_inode_nr;
188 req.user_e = usr;
189 req.seg = seg;
190 req.pos = position;
191 req.num_of_bytes = m_in.nbytes;
192 req.user_addr = m_in.buffer;
193 req.inode_index = vp->v_index;
195 /* Truncate read request at size (mustn't do this for special files). */
196 if((rw_flag == READING) &&
197 cmp64ul(add64ul(position, req.num_of_bytes), vp->v_size) > 0) {
198 /* Position always should fit in an off_t (LONG_MAX). */
199 off_t pos32;
200 assert(cmp64ul(position, LONG_MAX) <= 0);
201 pos32 = cv64ul(position);
202 assert(pos32 >= 0);
203 assert(pos32 <= LONG_MAX);
204 req.num_of_bytes = vp->v_size - pos32;
205 assert(req.num_of_bytes >= 0);
208 /* Issue request */
209 r = req_readwrite(&req, &res);
211 if (r >= 0)
213 if (ex64hi(res.new_pos))
214 panic(__FILE__, "read_write: bad new pos", NO_NUM);
216 position = res.new_pos;
217 cum_io += res.cum_io;
221 /* On write, update file size and access time. */
222 if (rw_flag == WRITING) {
223 if (regular || mode_word == I_DIRECTORY) {
224 if (cmp64ul(position, vp->v_size) > 0)
226 if (ex64hi(position) != 0)
228 panic(__FILE__,
229 "read_write: file size too big for v_size",
230 NO_NUM);
232 vp->v_size = ex64lo(position);
236 else {
237 if (vp->v_pipe == I_PIPE) {
238 if (cmp64ul(position, vp->v_size) >= 0) {
239 /* Reset pipe pointers */
240 vp->v_size = 0;
241 position = cvu64(0);
242 wf = find_filp(vp, W_BIT);
243 if (wf != NIL_FILP) wf->filp_pos = cvu64(0);
248 f->filp_pos = position;
250 if (r == OK) {
251 if (partial_pipe) {
252 partial_pipe = 0;
253 /* partial write on pipe with */
254 /* O_NONBLOCK, return write count */
255 if (!(oflags & O_NONBLOCK)) {
256 fp->fp_cum_io_partial = cum_io;
257 suspend(XPIPE); /* partial write on pipe with */
258 return(SUSPEND); /* nbyte > PIPE_SIZE - non-atomic */
261 fp->fp_cum_io_partial = 0;
262 return cum_io;
265 return r;
269 /* Original "uncached" code for block spec files */
270 #if 0
271 else if (block_spec) {
272 char buf[_MIN_BLOCK_SIZE];
273 block_t b;
274 int bleft = m_in.nbytes;
275 dev_t dev = vp->v_sdev;
277 b = position / _MIN_BLOCK_SIZE;
278 off = position % _MIN_BLOCK_SIZE;
280 while (bleft) {
281 /* First read the whole block */
282 r = dev_bio(VFS_DEV_READ, dev, FS_PROC_NR, buf,
283 b * _MIN_BLOCK_SIZE, _MIN_BLOCK_SIZE);
285 if (r != _MIN_BLOCK_SIZE)
286 break;
288 /* How many bytes to copy? */
289 chunk = MIN(bleft, _MIN_BLOCK_SIZE - off);
291 if (rw_flag == READING) {
292 /* Copy a chunk from the buffer to user space. */
293 r = sys_vircopy(FS_PROC_NR, D, (phys_bytes) (&buf[off]),
294 usr, seg, (phys_bytes) m_in.buffer,
295 (phys_bytes) chunk);
297 else {
298 /* Copy a chunk from user space to the buffer. */
299 r = sys_vircopy(usr, seg, (phys_bytes) m_in.buffer,
300 FS_PROC_NR, D, (phys_bytes) (&buf[off]),
301 (phys_bytes) chunk);
304 /* Write back if WRITE */
305 if (rw_flag == WRITING) {
306 r = dev_bio(DEV_WRITE, dev, FS_PROC_NR, buf,
307 b * _MIN_BLOCK_SIZE, _MIN_BLOCK_SIZE);
309 if (r != _MIN_BLOCK_SIZE)
310 break;
313 bleft -= chunk;
314 m_in.buffer += chunk;
316 /* 0 offset in the next block */
317 b++;
318 off = 0;
321 cum_io = m_in.nbytes - bleft;
322 position += cum_io;
323 r = OK;
325 #endif
328 /*===========================================================================*
329 * do_getdents *
330 *===========================================================================*/
331 PUBLIC int do_getdents()
333 /* Perform the getdents(fd, buf, size) system call. */
334 int r;
335 off_t pos_change;
336 cp_grant_id_t gid;
337 register struct filp *rfilp;
339 /* Is the file descriptor valid? */
340 if ( (rfilp = get_filp(m_in.fd)) == NIL_FILP) {
341 return(err_code);
344 if (!(rfilp->filp_mode & R_BIT))
345 return EBADF;
347 if ((rfilp->filp_vno->v_mode & I_TYPE) != I_DIRECTORY)
348 return EBADF;
350 gid=cpf_grant_magic(rfilp->filp_vno->v_fs_e, who_e, (vir_bytes) m_in.buffer,
351 m_in.nbytes, CPF_WRITE);
352 if (gid < 0) panic(__FILE__, "cpf_grant_magic failed", gid);
354 /* Issue request */
355 if (ex64hi(rfilp->filp_pos) != 0)
356 panic(__FILE__, "do_getdents: should handle large offsets", NO_NUM);
358 r= req_getdents(rfilp->filp_vno->v_fs_e, rfilp->filp_vno->v_inode_nr,
359 ex64lo(rfilp->filp_pos), gid, m_in.nbytes, &pos_change);
361 cpf_revoke(gid);
363 if (r > 0)
364 rfilp->filp_pos= add64ul(rfilp->filp_pos, pos_change);
365 return r;