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