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