1 /*
2 * linux/fs/sysv/file.c
3 *
4 * minix/file.c
5 * Copyright (C) 1991, 1992 Linus Torvalds
6 *
7 * coh/file.c
8 * Copyright (C) 1993 Pascal Haible, Bruno Haible
9 *
10 * sysv/file.c
11 * Copyright (C) 1993 Bruno Haible
12 *
13 * SystemV/Coherent regular file handling primitives
14 */
15
16 #include <linux/kernel.h>
17 #include <linux/fs.h>
18 #include <linux/sysv_fs.h>
19 #include <linux/errno.h>
20 #include <linux/fcntl.h>
21 #include <linux/stat.h>
22 #include <linux/string.h>
23 #include <linux/locks.h>
24
25 #include <asm/segment.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/sysv_fs.h>
34
35 static int sysv_file_write(struct inode *, struct file *, const char *, int);
36
37 /*
38 * We have mostly NULL's here: the current defaults are ok for
39 * the coh filesystem.
40 */
41 static struct file_operations sysv_file_operations = {
42 NULL, /* lseek - default */
43 sysv_file_read, /* read */
44 sysv_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 sysv_sync_file /* fsync */
52 };
53
54 struct inode_operations sysv_file_inode_operations = {
55 &sysv_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 NULL, /* readpage */
68 NULL, /* writepage */
69 sysv_bmap, /* bmap */
70 sysv_truncate, /* truncate */
71 NULL /* permission */
72 };
73
74 int sysv_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)
*/
75 {
76 struct super_block * sb = inode->i_sb;
77 int read,left,chars;
78 unsigned int block;
79 int blocks, offset;
80 int bhrequest, uptodate;
81 struct buffer_head ** bhb, ** bhe;
82 struct buffer_head * bhreq[NBUF];
83 struct buffer_head * buflist[NBUF];
84 unsigned int size;
85
86 if (!inode) {
87 printk("sysv_file_read: inode = NULL\n");
88 return -EINVAL;
89 }
90 if (!S_ISREG(inode->i_mode)) {
91 printk("sysv_file_read: mode = %07o\n",inode->i_mode);
92 return -EINVAL;
93 }
94 offset = filp->f_pos;
95 size = inode->i_size;
96 if (offset > size)
97 left = 0;
98 else
99 left = size - offset;
100 if (left > count)
101 left = count;
102 if (left <= 0)
103 return 0;
104 read = 0;
105 block = offset >> sb->sv_block_size_bits;
106 offset &= sb->sv_block_size_1;
107 size = (size + sb->sv_block_size_1) >> sb->sv_block_size_bits;
108 blocks = (left + offset + sb->sv_block_size_1) >> sb->sv_block_size_bits;
109 bhb = bhe = buflist;
110 if (filp->f_reada) {
111 blocks += read_ahead[MAJOR(inode->i_dev)] >> (sb->sv_block_size_bits - 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
127 do {
128 bhrequest = 0;
129 uptodate = 1;
130 while (blocks) {
131 --blocks;
132 *bhb = sysv_getblk(inode, block++, 0);
133 if (*bhb && !buffer_uptodate(*bhb)) {
134 uptodate = 0;
135 bhreq[bhrequest++] = *bhb;
136 }
137
138 if (++bhb == &buflist[NBUF])
139 bhb = buflist;
140
141 /* If the block we have on hand is uptodate, go ahead
142 and complete processing. */
143 if (uptodate)
144 break;
145 if (bhb == bhe)
146 break;
147 }
148
149 /* Now request them all */
150 if (bhrequest)
151 ll_rw_block(READ, bhrequest, bhreq);
152
153 do { /* Finish off all I/O that has actually completed */
154 if (*bhe) {
155 wait_on_buffer(*bhe);
156 if (!buffer_uptodate(*bhe)) { /* read error? */
157 brelse(*bhe);
158 if (++bhe == &buflist[NBUF])
159 bhe = buflist;
160 left = 0;
161 break;
162 }
163 }
164 if (left < sb->sv_block_size - offset)
165 chars = left;
166 else
167 chars = sb->sv_block_size - offset;
168 filp->f_pos += chars;
169 left -= chars;
170 read += chars;
171 if (*bhe) {
172 memcpy_tofs(buf,offset+(*bhe)->b_data,chars);
173 brelse(*bhe);
174 buf += chars;
175 } else {
176 while (chars-- > 0)
177 put_user(0,buf++);
178 }
179 offset = 0;
180 if (++bhe == &buflist[NBUF])
181 bhe = buflist;
182 } while (left > 0 && bhe != bhb && (!*bhe || !buffer_locked(*bhe)));
183 } while (left > 0);
184
185 /* Release the read-ahead blocks */
186 while (bhe != bhb) {
187 brelse(*bhe);
188 if (++bhe == &buflist[NBUF])
189 bhe = buflist;
190 };
191 if (!read)
192 return -EIO;
193 filp->f_reada = 1;
194 if (!IS_RDONLY(inode)) {
195 inode->i_atime = CURRENT_TIME;
196 inode->i_dirt = 1;
197 }
198 return read;
199 }
200
201 static int sysv_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)
*/
202 {
203 struct super_block * sb = inode->i_sb;
204 off_t pos;
205 int written,c;
206 struct buffer_head * bh;
207 char * p;
208
209 if (!inode) {
210 printk("sysv_file_write: inode = NULL\n");
211 return -EINVAL;
212 }
213 if (!S_ISREG(inode->i_mode)) {
214 printk("sysv_file_write: mode = %07o\n",inode->i_mode);
215 return -EINVAL;
216 }
217 /*
218 * ok, append may not work when many processes are writing at the same time
219 * but so what. That way leads to madness anyway.
220 * But we need to protect against simultaneous truncate as we may end up
221 * writing our data into blocks that have meanwhile been incorporated into
222 * the freelist, thereby trashing the freelist.
223 */
224 if (filp->f_flags & O_APPEND)
225 pos = inode->i_size;
226 else
227 pos = filp->f_pos;
228 written = 0;
229 while (written<count) {
230 bh = sysv_getblk (inode, pos >> sb->sv_block_size_bits, 1);
231 if (!bh) {
232 if (!written)
233 written = -ENOSPC;
234 break;
235 }
236 c = sb->sv_block_size - (pos & sb->sv_block_size_1);
237 if (c > count-written)
238 c = count-written;
239 if (c != sb->sv_block_size && !buffer_uptodate(bh)) {
240 ll_rw_block(READ, 1, &bh);
241 wait_on_buffer(bh);
242 if (!buffer_uptodate(bh)) {
243 brelse(bh);
244 if (!written)
245 written = -EIO;
246 break;
247 }
248 }
249 /* now either c==sb->sv_block_size or buffer_uptodate(bh) */
250 p = (pos & sb->sv_block_size_1) + bh->b_data;
251 pos += c;
252 if (pos > inode->i_size) {
253 inode->i_size = pos;
254 inode->i_dirt = 1;
255 }
256 written += c;
257 memcpy_fromfs(p,buf,c);
258 buf += c;
259 mark_buffer_uptodate(bh, 1);
260 mark_buffer_dirty(bh, 0);
261 brelse(bh);
262 }
263 inode->i_mtime = inode->i_ctime = CURRENT_TIME;
264 filp->f_pos = pos;
265 inode->i_dirt = 1;
266 return written;
267 }