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