OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [fs/] [read_write.c] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *  linux/fs/read_write.c
3
 *
4
 *  Copyright (C) 1991, 1992  Linus Torvalds
5
 *  Minor pieces Copyright (C) 2002 Red Hat Inc, All Rights Reserved
6
 *
7
 *  This program is free software; you can redistribute it and/or modify
8
 *  it under the terms of the GNU General Public License as published by
9
 *  the Free Software Foundation; either version 2 of the License, or
10
 *  (at your option) any later version.
11
 *
12
 *  This program is distributed in the hope that it will be useful,
13
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 *  GNU General Public License for more details.
16
 *
17
 *  You should have received a copy of the GNU General Public License
18
 *  along with this program; if not, write to the Free Software
19
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
 */
21
 
22
#include <linux/slab.h> 
23
#include <linux/stat.h>
24
#include <linux/fcntl.h>
25
#include <linux/file.h>
26
#include <linux/uio.h>
27
#include <linux/smp_lock.h>
28
#include <linux/dnotify.h>
29
 
30
#include <asm/uaccess.h>
31
 
32
struct file_operations generic_ro_fops = {
33
        llseek:         generic_file_llseek,
34
        read:           generic_file_read,
35
        mmap:           generic_file_mmap,
36
};
37
 
38
ssize_t generic_read_dir(struct file *filp, char *buf, size_t siz, loff_t *ppos)
39
{
40
        return -EISDIR;
41
}
42
 
43
loff_t generic_file_llseek(struct file *file, loff_t offset, int origin)
44
{
45
        long long retval;
46
 
47
        switch (origin) {
48
                case 2:
49
                        offset += file->f_dentry->d_inode->i_size;
50
                        break;
51
                case 1:
52
                        offset += file->f_pos;
53
        }
54
        retval = -EINVAL;
55
        if (offset>=0 && offset<=file->f_dentry->d_inode->i_sb->s_maxbytes) {
56
                if (offset != file->f_pos) {
57
                        file->f_pos = offset;
58
                        file->f_reada = 0;
59
                        file->f_version = ++event;
60
                }
61
                retval = offset;
62
        }
63
        return retval;
64
}
65
 
66
loff_t no_llseek(struct file *file, loff_t offset, int origin)
67
{
68
        return -ESPIPE;
69
}
70
 
71
loff_t default_llseek(struct file *file, loff_t offset, int origin)
72
{
73
        long long retval;
74
 
75
        switch (origin) {
76
                case 2:
77
                        offset += file->f_dentry->d_inode->i_size;
78
                        break;
79
                case 1:
80
                        offset += file->f_pos;
81
        }
82
        retval = -EINVAL;
83
        if (offset >= 0) {
84
                if (offset != file->f_pos) {
85
                        file->f_pos = offset;
86
                        file->f_reada = 0;
87
                        file->f_version = ++event;
88
                }
89
                retval = offset;
90
        }
91
        return retval;
92
}
93
 
94
static inline loff_t llseek(struct file *file, loff_t offset, int origin)
95
{
96
        loff_t (*fn)(struct file *, loff_t, int);
97
        loff_t retval;
98
 
99
        fn = default_llseek;
100
        if (file->f_op && file->f_op->llseek)
101
                fn = file->f_op->llseek;
102
        lock_kernel();
103
        retval = fn(file, offset, origin);
104
        unlock_kernel();
105
        return retval;
106
}
107
 
108
asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
109
{
110
        off_t retval;
111
        struct file * file;
112
 
113
        retval = -EBADF;
114
        file = fget(fd);
115
        if (!file)
116
                goto bad;
117
        retval = -EINVAL;
118
        if (origin <= 2) {
119
                loff_t res = llseek(file, offset, origin);
120
                retval = res;
121
                if (res != (loff_t)retval)
122
                        retval = -EOVERFLOW;    /* LFS: should only happen on 32 bit platforms */
123
        }
124
        fput(file);
125
bad:
126
        return retval;
127
}
128
 
129
#if !defined(__alpha__)
130
asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high,
131
                           unsigned long offset_low, loff_t * result,
132
                           unsigned int origin)
133
{
134
        int retval;
135
        struct file * file;
136
        loff_t offset;
137
 
138
        retval = -EBADF;
139
        file = fget(fd);
140
        if (!file)
141
                goto bad;
142
        retval = -EINVAL;
143
        if (origin > 2)
144
                goto out_putf;
145
 
146
        offset = llseek(file, ((loff_t) offset_high << 32) | offset_low,
147
                        origin);
148
 
149
        retval = (int)offset;
150
        if (offset >= 0) {
151
                retval = -EFAULT;
152
                if (!copy_to_user(result, &offset, sizeof(offset)))
153
                        retval = 0;
154
        }
155
out_putf:
156
        fput(file);
157
bad:
158
        return retval;
159
}
160
#endif
161
 
162
asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count)
163
{
164
        ssize_t ret;
165
        struct file * file;
166
 
167
        ret = -EBADF;
168
        file = fget(fd);
169
        if (file) {
170
                if (file->f_mode & FMODE_READ) {
171
                        ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
172
                                                file, file->f_pos, count);
173
                        if (!ret) {
174
                                ssize_t (*read)(struct file *, char *, size_t, loff_t *);
175
                                ret = -EINVAL;
176
                                if (file->f_op && (read = file->f_op->read) != NULL)
177
                                        ret = read(file, buf, count, &file->f_pos);
178
                        }
179
                }
180
                if (ret > 0)
181
                        dnotify_parent(file->f_dentry, DN_ACCESS);
182
                fput(file);
183
        }
184
        return ret;
185
}
186
 
187
asmlinkage ssize_t sys_write(unsigned int fd, const char * buf, size_t count)
188
{
189
        ssize_t ret;
190
        struct file * file;
191
 
192
        ret = -EBADF;
193
        file = fget(fd);
194
        if (file) {
195
                if (file->f_mode & FMODE_WRITE) {
196
                        struct inode *inode = file->f_dentry->d_inode;
197
                        ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,
198
                                file->f_pos, count);
199
                        if (!ret) {
200
                                ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
201
                                ret = -EINVAL;
202
                                if (file->f_op && (write = file->f_op->write) != NULL)
203
                                        ret = write(file, buf, count, &file->f_pos);
204
                        }
205
                }
206
                if (ret > 0)
207
                        dnotify_parent(file->f_dentry, DN_MODIFY);
208
                fput(file);
209
        }
210
        return ret;
211
}
212
 
213
 
214
static ssize_t do_readv_writev(int type, struct file *file,
215
                               const struct iovec * vector,
216
                               unsigned long count)
217
{
218
        typedef ssize_t (*io_fn_t)(struct file *, char *, size_t, loff_t *);
219
        typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);
220
 
221
        size_t tot_len;
222
        struct iovec iovstack[UIO_FASTIOV];
223
        struct iovec *iov=iovstack;
224
        ssize_t ret, i;
225
        io_fn_t fn;
226
        iov_fn_t fnv;
227
        struct inode *inode;
228
 
229
        /*
230
         * First get the "struct iovec" from user memory and
231
         * verify all the pointers
232
         */
233
        ret = 0;
234
        if (!count)
235
                goto out_nofree;
236
        ret = -EINVAL;
237
        if (count > UIO_MAXIOV)
238
                goto out_nofree;
239
        if (!file->f_op)
240
                goto out_nofree;
241
        if (count > UIO_FASTIOV) {
242
                ret = -ENOMEM;
243
                iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
244
                if (!iov)
245
                        goto out_nofree;
246
        }
247
        ret = -EFAULT;
248
        if (copy_from_user(iov, vector, count*sizeof(*vector)))
249
                goto out;
250
 
251
        /*
252
         * Single unix specification:
253
         * We should -EINVAL if an element length is not >= 0 and fitting an ssize_t
254
         * The total length is fitting an ssize_t
255
         *
256
         * Be careful here because iov_len is a size_t not an ssize_t
257
         */
258
 
259
        tot_len = 0;
260
        ret = -EINVAL;
261
        for (i = 0 ; i < count ; i++) {
262
                ssize_t len = (ssize_t) iov[i].iov_len;
263
                if (len < 0)     /* size_t not fitting an ssize_t .. */
264
                        goto out;
265
                tot_len += len;
266
                /* We must do this work unsigned - signed overflow is
267
                   undefined and gcc 3.2 now uses that fact sometimes...
268
 
269
                   FIXME: put in a proper limits.h for each platform */
270
#if BITS_PER_LONG==64
271
                if (tot_len > 0x7FFFFFFFFFFFFFFFUL)
272
#else
273
                if (tot_len > 0x7FFFFFFFUL)
274
#endif          
275
                        goto out;
276
        }
277
 
278
        inode = file->f_dentry->d_inode;
279
        /* VERIFY_WRITE actually means a read, as we write to user space */
280
        ret = locks_verify_area((type == VERIFY_WRITE
281
                                 ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
282
                                inode, file, file->f_pos, tot_len);
283
        if (ret) goto out;
284
 
285
        fnv = (type == VERIFY_WRITE ? file->f_op->readv : file->f_op->writev);
286
        if (fnv) {
287
                ret = fnv(file, iov, count, &file->f_pos);
288
                goto out;
289
        }
290
 
291
        /* VERIFY_WRITE actually means a read, as we write to user space */
292
        fn = (type == VERIFY_WRITE ? file->f_op->read :
293
              (io_fn_t) file->f_op->write);
294
 
295
        ret = 0;
296
        vector = iov;
297
        while (count > 0) {
298
                void * base;
299
                size_t len;
300
                ssize_t nr;
301
 
302
                base = vector->iov_base;
303
                len = vector->iov_len;
304
                vector++;
305
                count--;
306
 
307
                nr = fn(file, base, len, &file->f_pos);
308
 
309
                if (nr < 0) {
310
                        if (!ret) ret = nr;
311
                        break;
312
                }
313
                ret += nr;
314
                if (nr != len)
315
                        break;
316
        }
317
 
318
out:
319
        if (iov != iovstack)
320
                kfree(iov);
321
out_nofree:
322
        /* VERIFY_WRITE actually means a read, as we write to user space */
323
        if ((ret + (type == VERIFY_WRITE)) > 0)
324
                dnotify_parent(file->f_dentry,
325
                        (type == VERIFY_WRITE) ? DN_ACCESS : DN_MODIFY);
326
        return ret;
327
}
328
 
329
asmlinkage ssize_t sys_readv(unsigned long fd, const struct iovec * vector,
330
                             unsigned long count)
331
{
332
        struct file * file;
333
        ssize_t ret;
334
 
335
 
336
        ret = -EBADF;
337
        file = fget(fd);
338
        if (!file)
339
                goto bad_file;
340
        if (file->f_op && (file->f_mode & FMODE_READ) &&
341
            (file->f_op->readv || file->f_op->read))
342
                ret = do_readv_writev(VERIFY_WRITE, file, vector, count);
343
        fput(file);
344
 
345
bad_file:
346
        return ret;
347
}
348
 
349
asmlinkage ssize_t sys_writev(unsigned long fd, const struct iovec * vector,
350
                              unsigned long count)
351
{
352
        struct file * file;
353
        ssize_t ret;
354
 
355
 
356
        ret = -EBADF;
357
        file = fget(fd);
358
        if (!file)
359
                goto bad_file;
360
        if (file->f_op && (file->f_mode & FMODE_WRITE) &&
361
            (file->f_op->writev || file->f_op->write))
362
                ret = do_readv_writev(VERIFY_READ, file, vector, count);
363
        fput(file);
364
 
365
bad_file:
366
        return ret;
367
}
368
 
369
/* From the Single Unix Spec: pread & pwrite act like lseek to pos + op +
370
   lseek back to original location.  They fail just like lseek does on
371
   non-seekable files.  */
372
 
373
asmlinkage ssize_t sys_pread(unsigned int fd, char * buf,
374
                             size_t count, loff_t pos)
375
{
376
        ssize_t ret;
377
        struct file * file;
378
        ssize_t (*read)(struct file *, char *, size_t, loff_t *);
379
 
380
        ret = -EBADF;
381
        file = fget(fd);
382
        if (!file)
383
                goto bad_file;
384
        if (!(file->f_mode & FMODE_READ))
385
                goto out;
386
        ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
387
                                file, pos, count);
388
        if (ret)
389
                goto out;
390
        ret = -EINVAL;
391
        if (!file->f_op || !(read = file->f_op->read))
392
                goto out;
393
        if (pos < 0)
394
                goto out;
395
        ret = read(file, buf, count, &pos);
396
        if (ret > 0)
397
                dnotify_parent(file->f_dentry, DN_ACCESS);
398
out:
399
        fput(file);
400
bad_file:
401
        return ret;
402
}
403
 
404
asmlinkage ssize_t sys_pwrite(unsigned int fd, const char * buf,
405
                              size_t count, loff_t pos)
406
{
407
        ssize_t ret;
408
        struct file * file;
409
        ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
410
 
411
        ret = -EBADF;
412
        file = fget(fd);
413
        if (!file)
414
                goto bad_file;
415
        if (!(file->f_mode & FMODE_WRITE))
416
                goto out;
417
        ret = locks_verify_area(FLOCK_VERIFY_WRITE, file->f_dentry->d_inode,
418
                                file, pos, count);
419
        if (ret)
420
                goto out;
421
        ret = -EINVAL;
422
        if (!file->f_op || !(write = file->f_op->write))
423
                goto out;
424
        if (pos < 0)
425
                goto out;
426
 
427
        ret = write(file, buf, count, &pos);
428
        if (ret > 0)
429
                dnotify_parent(file->f_dentry, DN_MODIFY);
430
out:
431
        fput(file);
432
bad_file:
433
        return ret;
434
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.