1 /*
2 * linux/fs/minix/file.c
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 *
6 * minix regular file handling primitives
7 */
8
9 #include <asm/segment.h>
10 #include <asm/system.h>
11
12 #include <linux/sched.h>
13 #include <linux/minix_fs.h>
14 #include <linux/kernel.h>
15 #include <linux/errno.h>
16 #include <linux/fcntl.h>
17 #include <linux/stat.h>
18 #include <linux/locks.h>
19
20 #define NBUF 16
21
22 #define MIN(a,b) (((a)<(b))?(a):(b))
23 #define MAX(a,b) (((a)>(b))?(a):(b))
24
25 #include <linux/fs.h>
26 #include <linux/minix_fs.h>
27
28 static int minix_file_read(struct inode *, struct file *, char *, int);
29 static int minix_file_write(struct inode *, struct file *, char *, int);
30
31 /*
32 * We have mostly NULL's here: the current defaults are ok for
33 * the minix filesystem.
34 */
35 static struct file_operations minix_file_operations = {
36 NULL, /* lseek - default */
37 minix_file_read, /* read */
38 minix_file_write, /* write */
39 NULL, /* readdir - bad */
40 NULL, /* select - default */
41 NULL, /* ioctl - default */
42 NULL, /* mmap */
43 NULL, /* no special open is needed */
44 NULL /* release */
45 };
46
47 struct inode_operations minix_file_inode_operations = {
48 &minix_file_operations, /* default file operations */
49 NULL, /* create */
50 NULL, /* lookup */
51 NULL, /* link */
52 NULL, /* unlink */
53 NULL, /* symlink */
54 NULL, /* mkdir */
55 NULL, /* rmdir */
56 NULL, /* mknod */
57 NULL, /* rename */
58 NULL, /* readlink */
59 NULL, /* follow_link */
60 minix_bmap, /* bmap */
61 minix_truncate /* truncate */
62 };
63
64 static int minix_file_read(struct inode * inode, struct file * filp, char * buf, int count)
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
65 {
66 int read,left,chars;
67 int block, blocks, offset;
68 int bhrequest, uptodate;
69 struct buffer_head ** bhb, ** bhe;
70 struct buffer_head * bhreq[NBUF];
71 struct buffer_head * buflist[NBUF];
72 unsigned int size;
73
74 if (!inode) {
75 printk("minix_file_read: inode = NULL\n");
76 return -EINVAL;
77 }
78 if (!S_ISREG(inode->i_mode)) {
79 printk("minix_file_read: mode = %07o\n",inode->i_mode);
80 return -EINVAL;
81 }
82 offset = filp->f_pos;
83 size = inode->i_size;
84 if (offset > size)
85 left = 0;
86 else
87 left = size - offset;
88 if (left > count)
89 left = count;
90 if (left <= 0)
91 return 0;
92 read = 0;
93 block = offset >> BLOCK_SIZE_BITS;
94 offset &= BLOCK_SIZE-1;
95 size = (size + (BLOCK_SIZE-1)) >> BLOCK_SIZE_BITS;
96 blocks = (left + offset + BLOCK_SIZE - 1) >> BLOCK_SIZE_BITS;
97 bhb = bhe = buflist;
98 if (filp->f_reada) {
99 blocks += read_ahead[MAJOR(inode->i_dev)] / (BLOCK_SIZE >> 9);
100 if (block + blocks > size)
101 blocks = size - block;
102 }
103
104 /* We do this in a two stage process. We first try and request
105 as many blocks as we can, then we wait for the first one to
106 complete, and then we try and wrap up as many as are actually
107 done. This routine is rather generic, in that it can be used
108 in a filesystem by substituting the appropriate function in
109 for getblk.
110
111 This routine is optimized to make maximum use of the various
112 buffers and caches. */
113
114 do {
115 bhrequest = 0;
116 uptodate = 1;
117 while (blocks) {
118 --blocks;
119 *bhb = minix_getblk(inode, block++, 0);
120 if (*bhb && !(*bhb)->b_uptodate) {
121 uptodate = 0;
122 bhreq[bhrequest++] = *bhb;
123 }
124
125 if (++bhb == &buflist[NBUF])
126 bhb = buflist;
127
128 /* If the block we have on hand is uptodate, go ahead
129 and complete processing. */
130 if (uptodate)
131 break;
132 if (bhb == bhe)
133 break;
134 }
135
136 /* Now request them all */
137 if (bhrequest)
138 ll_rw_block(READ, bhrequest, bhreq);
139
140 do { /* Finish off all I/O that has actually completed */
141 if (*bhe) {
142 wait_on_buffer(*bhe);
143 if (!(*bhe)->b_uptodate) { /* read error? */
144 left = 0;
145 break;
146 }
147 }
148 if (left < BLOCK_SIZE - offset)
149 chars = left;
150 else
151 chars = BLOCK_SIZE - offset;
152 filp->f_pos += chars;
153 left -= chars;
154 read += chars;
155 if (*bhe) {
156 memcpy_tofs(buf,offset+(*bhe)->b_data,chars);
157 brelse(*bhe);
158 buf += chars;
159 } else {
160 while (chars-->0)
161 put_fs_byte(0,buf++);
162 }
163 offset = 0;
164 if (++bhe == &buflist[NBUF])
165 bhe = buflist;
166 } while (left > 0 && bhe != bhb && (!*bhe || !(*bhe)->b_lock));
167 } while (left > 0);
168
169 /* Release the read-ahead blocks */
170 while (bhe != bhb) {
171 brelse(*bhe);
172 if (++bhe == &buflist[NBUF])
173 bhe = buflist;
174 };
175 if (!read)
176 return -EIO;
177 filp->f_reada = 1;
178 if (!IS_RDONLY(inode)) {
179 inode->i_atime = CURRENT_TIME;
180 inode->i_dirt = 1;
181 }
182 return read;
183 }
184
185 static int minix_file_write(struct inode * inode, struct file * filp, char * buf, int count)
/* ![[previous]](../icons/left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
186 {
187 off_t pos;
188 int written,c;
189 struct buffer_head * bh;
190 char * p;
191
192 if (!inode) {
193 printk("minix_file_write: inode = NULL\n");
194 return -EINVAL;
195 }
196 if (!S_ISREG(inode->i_mode)) {
197 printk("minix_file_write: mode = %07o\n",inode->i_mode);
198 return -EINVAL;
199 }
200 /*
201 * ok, append may not work when many processes are writing at the same time
202 * but so what. That way leads to madness anyway.
203 */
204 if (filp->f_flags & O_APPEND)
205 pos = inode->i_size;
206 else
207 pos = filp->f_pos;
208 written = 0;
209 while (written<count) {
210 bh = minix_getblk(inode,pos/BLOCK_SIZE,1);
211 if (!bh) {
212 if (!written)
213 written = -ENOSPC;
214 break;
215 }
216 c = BLOCK_SIZE - (pos % BLOCK_SIZE);
217 if (c > count-written)
218 c = count-written;
219 if (c != BLOCK_SIZE && !bh->b_uptodate) {
220 ll_rw_block(READ, 1, &bh);
221 wait_on_buffer(bh);
222 if (!bh->b_uptodate) {
223 brelse(bh);
224 if (!written)
225 written = -EIO;
226 break;
227 }
228 }
229 p = (pos % BLOCK_SIZE) + bh->b_data;
230 pos += c;
231 if (pos > inode->i_size) {
232 inode->i_size = pos;
233 inode->i_dirt = 1;
234 }
235 written += c;
236 memcpy_fromfs(p,buf,c);
237 buf += c;
238 bh->b_uptodate = 1;
239 bh->b_dirt = 1;
240 brelse(bh);
241 }
242 inode->i_mtime = CURRENT_TIME;
243 inode->i_ctime = CURRENT_TIME;
244 filp->f_pos = pos;
245 inode->i_dirt = 1;
246 return written;
247 }