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