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
16 #include <minix/com.h>
17 #include <minix/u64.h>
23 #include <minix/vfsif.h>
28 /*===========================================================================*
30 *===========================================================================*/
33 return(read_write(READING
));
37 /*===========================================================================*
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
;
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
);
59 return(0); /* so char special files need not check for 0*/
61 position
= f
->filp_pos
;
62 oflags
= f
->filp_flags
;
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. */
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
,
99 position
= add64ul(position
, r
);
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
);
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
);
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
);
121 panic("read_write: bad 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
);
146 /*===========================================================================*
148 *===========================================================================*/
149 PUBLIC
int do_getdents()
151 /* Perform the getdents(fd, buf, size) system call. */
154 register struct filp
*rfilp
;
156 /* Is the file descriptor valid? */
157 if ( (rfilp
= get_filp(m_in
.fd
)) == NIL_FILP
) {
161 if (!(rfilp
->filp_mode
& R_BIT
))
164 if ((rfilp
->filp_vno
->v_mode
& I_TYPE
) != I_DIRECTORY
)
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
);
174 rfilp
->filp_pos
= new_pos
;
179 /*===========================================================================*
181 *===========================================================================*/
182 PUBLIC
int rw_pipe(rw_flag
, usr_e
, fd_nr
, f
, buf
, req_size
)
183 int rw_flag
; /* READING or WRITING */
190 int r
, oflags
, partial_pipe
= 0;
191 size_t size
, cum_io
, cum_io_incr
;
193 u64_t position
, new_pos
;
195 oflags
= f
->filp_flags
;
197 position
= cvu64((rw_flag
== READING
) ? vp
->v_pipe_rd_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);
204 if (r
== SUSPEND
) pipe_suspend(rw_flag
, fd_nr
, buf
, req_size
);
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). */
217 assert(cmp64ul(position
, LONG_MAX
) <= 0);
218 pos32
= cv64ul(position
);
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
);
232 panic("rw_pipe: bad new pos");
235 cum_io
+= 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
);
249 if (cmp64ul(position
, vp
->v_size
) >= 0) {
250 /* Reset pipe pointers */
252 vp
->v_pipe_rd_pos
= 0;
253 vp
->v_pipe_wr_pos
= 0;
258 if (rw_flag
== READING
)
259 vp
->v_pipe_rd_pos
= cv64ul(position
);
261 vp
->v_pipe_wr_pos
= cv64ul(position
);
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,
271 fp
->fp_cum_io_partial
= cum_io
;
272 pipe_suspend(rw_flag
, fd_nr
, buf
, req_size
);
276 fp
->fp_cum_io_partial
= 0;