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 NULL /* 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 blocks += read_ahead[MAJOR(inode->i_dev)] / (BLOCK_SIZE >> 9);
108 if (block + blocks > size)
109 blocks = size - block;
110 }
111
112 /* We do this in a two stage process. We first try and request
113 as many blocks as we can, then we wait for the first one to
114 complete, and then we try and wrap up as many as are actually
115 done. This routine is rather generic, in that it can be used
116 in a filesystem by substituting the appropriate function in
117 for getblk.
118
119 This routine is optimized to make maximum use of the various
120 buffers and caches. */
121
122 do {
123 bhrequest = 0;
124 uptodate = 1;
125 while (blocks) {
126 --blocks;
127 *bhb = ext_getblk(inode, block++, 0);
128 if (*bhb && !(*bhb)->b_uptodate) {
129 uptodate = 0;
130 bhreq[bhrequest++] = *bhb;
131 }
132
133 if (++bhb == &buflist[NBUF])
134 bhb = buflist;
135
136 /* If the block we have on hand is uptodate, go ahead
137 and complete processing. */
138 if (uptodate)
139 break;
140 if (bhb == bhe)
141 break;
142 }
143
144 /* Now request them all */
145 if (bhrequest)
146 ll_rw_block(READ, bhrequest, bhreq);
147
148 do { /* Finish off all I/O that has actually completed */
149 if (*bhe) {
150 wait_on_buffer(*bhe);
151 if (!(*bhe)->b_uptodate) { /* read error? */
152 left = 0;
153 break;
154 }
155 }
156 if (left < BLOCK_SIZE - offset)
157 chars = left;
158 else
159 chars = BLOCK_SIZE - offset;
160 filp->f_pos += chars;
161 left -= chars;
162 read += chars;
163 if (*bhe) {
164 memcpy_tofs(buf,offset+(*bhe)->b_data,chars);
165 brelse(*bhe);
166 buf += chars;
167 } else {
168 while (chars-->0)
169 put_fs_byte(0,buf++);
170 }
171 offset = 0;
172 if (++bhe == &buflist[NBUF])
173 bhe = buflist;
174 } while (left > 0 && bhe != bhb && (!*bhe || !(*bhe)->b_lock));
175 } while (left > 0);
176
177 /* Release the read-ahead blocks */
178 while (bhe != bhb) {
179 brelse(*bhe);
180 if (++bhe == &buflist[NBUF])
181 bhe = buflist;
182 };
183 if (!read)
184 return -EIO;
185 filp->f_reada = 1;
186 if (!IS_RDONLY(inode)) {
187 inode->i_atime = CURRENT_TIME;
188 inode->i_dirt = 1;
189 }
190 return read;
191 }
192
193 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)
*/
194 {
195 off_t pos;
196 int written,c;
197 struct buffer_head * bh;
198 char * p;
199
200 if (!inode) {
201 printk("ext_file_write: inode = NULL\n");
202 return -EINVAL;
203 }
204 if (!S_ISREG(inode->i_mode)) {
205 printk("ext_file_write: mode = %07o\n",inode->i_mode);
206 return -EINVAL;
207 }
208 /*
209 * ok, append may not work when many processes are writing at the same time
210 * but so what. That way leads to madness anyway.
211 */
212 if (filp->f_flags & O_APPEND)
213 pos = inode->i_size;
214 else
215 pos = filp->f_pos;
216 written = 0;
217 while (written<count) {
218 bh = ext_getblk(inode,pos/BLOCK_SIZE,1);
219 if (!bh) {
220 if (!written)
221 written = -ENOSPC;
222 break;
223 }
224 c = BLOCK_SIZE - (pos % BLOCK_SIZE);
225 if (c > count-written)
226 c = count-written;
227 if (c != BLOCK_SIZE && !bh->b_uptodate) {
228 ll_rw_block(READ, 1, &bh);
229 wait_on_buffer(bh);
230 if (!bh->b_uptodate) {
231 brelse(bh);
232 if (!written)
233 written = -EIO;
234 break;
235 }
236 }
237 p = (pos % BLOCK_SIZE) + bh->b_data;
238 pos += c;
239 if (pos > inode->i_size) {
240 inode->i_size = pos;
241 inode->i_dirt = 1;
242 }
243 written += c;
244 memcpy_fromfs(p,buf,c);
245 buf += c;
246 bh->b_uptodate = 1;
247 bh->b_dirt = 1;
248 brelse(bh);
249 }
250 inode->i_mtime = CURRENT_TIME;
251 inode->i_ctime = CURRENT_TIME;
252 filp->f_pos = pos;
253 inode->i_dirt = 1;
254 return written;
255 }