Remove references to CONFIG_PROFILE. Kernel profiling is no longer a
[linux-2.6/linux-mips.git] / fs / read_write.c
blob3d3519146bc73e1ef621ae5a2f6f61f9a982797f
1 /*
2 * linux/fs/read_write.c
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 */
7 #include <linux/malloc.h>
8 #include <linux/stat.h>
9 #include <linux/fcntl.h>
10 #include <linux/file.h>
11 #include <linux/uio.h>
12 #include <linux/smp_lock.h>
14 #include <asm/uaccess.h>
16 struct file_operations generic_ro_fops = {
17 read: generic_file_read,
18 mmap: generic_file_mmap,
21 ssize_t generic_read_dir(struct file *filp, char *buf, size_t siz, loff_t *ppos)
23 return -EISDIR;
26 loff_t default_llseek(struct file *file, loff_t offset, int origin)
28 long long retval;
30 switch (origin) {
31 case 2:
32 offset += file->f_dentry->d_inode->i_size;
33 break;
34 case 1:
35 offset += file->f_pos;
37 retval = -EINVAL;
38 if (offset >= 0) {
39 if (offset != file->f_pos) {
40 file->f_pos = offset;
41 file->f_reada = 0;
42 file->f_version = ++event;
44 retval = offset;
46 return retval;
49 static inline loff_t llseek(struct file *file, loff_t offset, int origin)
51 loff_t (*fn)(struct file *, loff_t, int);
52 loff_t retval;
54 fn = default_llseek;
55 if (file->f_op && file->f_op->llseek)
56 fn = file->f_op->llseek;
57 lock_kernel();
58 retval = fn(file, offset, origin);
59 unlock_kernel();
60 return retval;
63 asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
65 off_t retval;
66 struct file * file;
68 retval = -EBADF;
69 file = fget(fd);
70 if (!file)
71 goto bad;
72 retval = -EINVAL;
73 if (origin <= 2) {
74 loff_t res = llseek(file, offset, origin);
75 retval = res;
76 if (res != (loff_t)retval)
77 retval = -EOVERFLOW; /* LFS: should only happen on 32 bit platforms */
79 fput(file);
80 bad:
81 return retval;
84 #if !defined(__alpha__)
85 asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high,
86 unsigned long offset_low, loff_t * result,
87 unsigned int origin)
89 int retval;
90 struct file * file;
91 loff_t offset;
93 retval = -EBADF;
94 file = fget(fd);
95 if (!file)
96 goto bad;
97 retval = -EINVAL;
98 if (origin > 2)
99 goto out_putf;
101 offset = llseek(file, ((loff_t) offset_high << 32) | offset_low,
102 origin);
104 retval = (int)offset;
105 if (offset >= 0) {
106 retval = -EFAULT;
107 if (!copy_to_user(result, &offset, sizeof(offset)))
108 retval = 0;
110 out_putf:
111 fput(file);
112 bad:
113 return retval;
115 #endif
117 asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count)
119 ssize_t ret;
120 struct file * file;
122 ret = -EBADF;
123 file = fget(fd);
124 if (file) {
125 if (file->f_mode & FMODE_READ) {
126 ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
127 file, file->f_pos, count);
128 if (!ret) {
129 ssize_t (*read)(struct file *, char *, size_t, loff_t *);
130 ret = -EINVAL;
131 if (file->f_op && (read = file->f_op->read) != NULL)
132 ret = read(file, buf, count, &file->f_pos);
135 fput(file);
137 return ret;
140 asmlinkage ssize_t sys_write(unsigned int fd, const char * buf, size_t count)
142 ssize_t ret;
143 struct file * file;
145 ret = -EBADF;
146 file = fget(fd);
147 if (file) {
148 if (file->f_mode & FMODE_WRITE) {
149 struct inode *inode = file->f_dentry->d_inode;
150 ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,
151 file->f_pos, count);
152 if (!ret) {
153 ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
154 ret = -EINVAL;
155 if (file->f_op && (write = file->f_op->write) != NULL)
156 ret = write(file, buf, count, &file->f_pos);
159 fput(file);
161 return ret;
165 static ssize_t do_readv_writev(int type, struct file *file,
166 const struct iovec * vector,
167 unsigned long count)
169 typedef ssize_t (*io_fn_t)(struct file *, char *, size_t, loff_t *);
170 typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);
172 size_t tot_len;
173 struct iovec iovstack[UIO_FASTIOV];
174 struct iovec *iov=iovstack;
175 ssize_t ret, i;
176 io_fn_t fn;
177 iov_fn_t fnv;
178 struct inode *inode;
181 * First get the "struct iovec" from user memory and
182 * verify all the pointers
184 ret = 0;
185 if (!count)
186 goto out_nofree;
187 ret = -EINVAL;
188 if (count > UIO_MAXIOV)
189 goto out_nofree;
190 if (!file->f_op)
191 goto out_nofree;
192 if (count > UIO_FASTIOV) {
193 ret = -ENOMEM;
194 iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
195 if (!iov)
196 goto out_nofree;
198 ret = -EFAULT;
199 if (copy_from_user(iov, vector, count*sizeof(*vector)))
200 goto out;
202 /* BSD readv/writev returns EINVAL if one of the iov_len
203 values < 0 or tot_len overflowed a 32-bit integer. -ink */
204 tot_len = 0;
205 ret = -EINVAL;
206 for (i = 0 ; i < count ; i++) {
207 size_t tmp = tot_len;
208 int len = iov[i].iov_len;
209 if (len < 0)
210 goto out;
211 (u32)tot_len += len;
212 if (tot_len < tmp || tot_len < (u32)len)
213 goto out;
216 inode = file->f_dentry->d_inode;
217 /* VERIFY_WRITE actually means a read, as we write to user space */
218 ret = locks_verify_area((type == VERIFY_WRITE
219 ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
220 inode, file, file->f_pos, tot_len);
221 if (ret) goto out;
223 fnv = (type == VERIFY_WRITE ? file->f_op->readv : file->f_op->writev);
224 if (fnv) {
225 ret = fnv(file, iov, count, &file->f_pos);
226 goto out;
229 /* VERIFY_WRITE actually means a read, as we write to user space */
230 fn = (type == VERIFY_WRITE ? file->f_op->read :
231 (io_fn_t) file->f_op->write);
233 ret = 0;
234 vector = iov;
235 while (count > 0) {
236 void * base;
237 size_t len;
238 ssize_t nr;
240 base = vector->iov_base;
241 len = vector->iov_len;
242 vector++;
243 count--;
245 nr = fn(file, base, len, &file->f_pos);
247 if (nr < 0) {
248 if (!ret) ret = nr;
249 break;
251 ret += nr;
252 if (nr != len)
253 break;
256 out:
257 if (iov != iovstack)
258 kfree(iov);
259 out_nofree:
260 return ret;
263 asmlinkage ssize_t sys_readv(unsigned long fd, const struct iovec * vector,
264 unsigned long count)
266 struct file * file;
267 ssize_t ret;
270 ret = -EBADF;
271 file = fget(fd);
272 if (!file)
273 goto bad_file;
274 if (file->f_op && (file->f_mode & FMODE_READ) &&
275 (file->f_op->readv || file->f_op->read))
276 ret = do_readv_writev(VERIFY_WRITE, file, vector, count);
277 fput(file);
279 bad_file:
280 return ret;
283 asmlinkage ssize_t sys_writev(unsigned long fd, const struct iovec * vector,
284 unsigned long count)
286 struct file * file;
287 ssize_t ret;
290 ret = -EBADF;
291 file = fget(fd);
292 if (!file)
293 goto bad_file;
294 if (file->f_op && (file->f_mode & FMODE_WRITE) &&
295 (file->f_op->writev || file->f_op->write))
296 ret = do_readv_writev(VERIFY_READ, file, vector, count);
297 fput(file);
299 bad_file:
300 return ret;
303 /* From the Single Unix Spec: pread & pwrite act like lseek to pos + op +
304 lseek back to original location. They fail just like lseek does on
305 non-seekable files. */
307 asmlinkage ssize_t sys_pread(unsigned int fd, char * buf,
308 size_t count, loff_t pos)
310 ssize_t ret;
311 struct file * file;
312 ssize_t (*read)(struct file *, char *, size_t, loff_t *);
314 ret = -EBADF;
315 file = fget(fd);
316 if (!file)
317 goto bad_file;
318 if (!(file->f_mode & FMODE_READ))
319 goto out;
320 ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
321 file, pos, count);
322 if (ret)
323 goto out;
324 ret = -EINVAL;
325 if (!file->f_op || !(read = file->f_op->read))
326 goto out;
327 if (pos < 0)
328 goto out;
329 ret = read(file, buf, count, &pos);
330 out:
331 fput(file);
332 bad_file:
333 return ret;
336 asmlinkage ssize_t sys_pwrite(unsigned int fd, const char * buf,
337 size_t count, loff_t pos)
339 ssize_t ret;
340 struct file * file;
341 ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
343 ret = -EBADF;
344 file = fget(fd);
345 if (!file)
346 goto bad_file;
347 if (!(file->f_mode & FMODE_WRITE))
348 goto out;
349 ret = locks_verify_area(FLOCK_VERIFY_WRITE, file->f_dentry->d_inode,
350 file, pos, count);
351 if (ret)
352 goto out;
353 ret = -EINVAL;
354 if (!file->f_op || !(write = file->f_op->write))
355 goto out;
356 if (pos < 0)
357 goto out;
359 ret = write(file, buf, count, &pos);
360 out:
361 fput(file);
362 bad_file:
363 return ret;