more changes on original files
[linux-2.4.git] / fs / xfs / linux-2.4 / xfs_file.c
1 /*
2  * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of version 2 of the GNU General Public License as
6  * published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it would be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11  *
12  * Further, this software is distributed without any warranty that it is
13  * free of the rightful claim of any third person regarding infringement
14  * or the like.  Any license provided herein, whether implied or
15  * otherwise, applies only to this software file.  Patent licenses, if
16  * any, provided herein do not apply to combinations of this program with
17  * other software, or any other product whatsoever.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write the Free Software Foundation, Inc., 59
21  * Temple Place - Suite 330, Boston MA 02111-1307, USA.
22  *
23  * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24  * Mountain View, CA  94043, or:
25  *
26  * http://www.sgi.com
27  *
28  * For further information regarding this notice, see:
29  *
30  * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
31  */
32
33 #include "xfs.h"
34 #include "xfs_inum.h"
35 #include "xfs_log.h"
36 #include "xfs_sb.h"
37 #include "xfs_dir.h"
38 #include "xfs_dir2.h"
39 #include "xfs_trans.h"
40 #include "xfs_dmapi.h"
41 #include "xfs_mount.h"
42 #include "xfs_bmap_btree.h"
43 #include "xfs_alloc_btree.h"
44 #include "xfs_ialloc_btree.h"
45 #include "xfs_alloc.h"
46 #include "xfs_btree.h"
47 #include "xfs_attr_sf.h"
48 #include "xfs_dir_sf.h"
49 #include "xfs_dir2_sf.h"
50 #include "xfs_dinode.h"
51 #include "xfs_inode.h"
52 #include "xfs_error.h"
53 #include "xfs_rw.h"
54 #include <linux/iobuf.h>
55
56 #include <linux/dcache.h>
57 #include <linux/smp_lock.h>
58 #include <linux/mman.h> /* for PROT_WRITE */
59
60 static struct vm_operations_struct linvfs_file_vm_ops;
61
62 STATIC inline ssize_t
63 __linvfs_read(
64         struct file     *file,
65         char            *buf,
66         int             ioflags,
67         size_t          size,
68         loff_t          *offset)
69 {
70         struct inode    *inode = file->f_dentry->d_inode;
71         vnode_t         *vp = LINVFS_GET_VP(inode);
72         ssize_t         rval;
73
74         if (unlikely(file->f_flags & O_DIRECT)) {
75                 ioflags |= IO_ISDIRECT;
76                 down_read(&inode->i_alloc_sem);
77                 VOP_READ(vp, file, buf, size, offset, ioflags, NULL, rval);
78                 up_read(&inode->i_alloc_sem);
79         } else {
80                 VOP_READ(vp, file, buf, size, offset, ioflags, NULL, rval);
81         }
82
83         return rval;
84 }
85
86 STATIC ssize_t
87 linvfs_read(
88         struct file     *file,
89         char            *buf,
90         size_t          size,
91         loff_t          *offset)
92 {
93         return __linvfs_read(file, buf, 0, size, offset);
94 }
95
96 STATIC ssize_t
97 linvfs_read_invis(
98         struct file     *file,
99         char            *buf,
100         size_t          size,
101         loff_t          *offset)
102 {
103         return __linvfs_read(file, buf, IO_INVIS, size, offset);
104 }
105
106
107 STATIC inline ssize_t
108 __linvfs_write(
109         struct file     *file,
110         const char      *buf,
111         int             ioflags,
112         size_t          count,
113         loff_t          *ppos)
114 {
115         struct inode    *inode = file->f_dentry->d_inode;
116         vnode_t         *vp = LINVFS_GET_VP(inode);
117         loff_t          pos;
118         ssize_t         rval;   /* Use negative errors in this f'n */
119
120         if ((ssize_t) count < 0)
121                 return -EINVAL;
122
123         if (!access_ok(VERIFY_READ, buf, count))
124                 return -EFAULT;
125
126         pos = *ppos;
127         if (pos < 0)
128                 return -EINVAL;
129
130         rval = file->f_error;
131         if (rval) {
132                 file->f_error = 0;
133                 return rval;
134         }
135
136         /* We allow multiple direct writers in, there is no
137          * potential call to vmtruncate in that path.
138          */
139         if (unlikely(file->f_flags & O_DIRECT)) {
140                 ioflags |= IO_ISDIRECT;
141                 down_read(&inode->i_alloc_sem);
142                 VOP_WRITE(vp, file, buf, count, &pos, ioflags, NULL, rval);
143                 *ppos = pos;
144                 up_read(&inode->i_alloc_sem);
145         } else {
146                 down(&inode->i_sem);
147                 VOP_WRITE(vp, file, buf, count, &pos, ioflags, NULL, rval);
148                 *ppos = pos;
149                 up(&inode->i_sem);
150         }
151
152         return rval;
153 }
154
155 STATIC inline ssize_t
156 linvfs_write(
157         struct file     *file,
158         const char      *buf,
159         size_t          count,
160         loff_t          *ppos)
161 {
162         return __linvfs_write(file, buf, 0, count, ppos);
163 }
164
165 STATIC inline ssize_t
166 linvfs_write_invis(
167         struct file     *file,
168         const char      *buf,
169         size_t          count,
170         loff_t          *ppos)
171 {
172         return __linvfs_write(file, buf, IO_INVIS, count, ppos);
173 }
174
175 STATIC int
176 linvfs_open(
177         struct inode    *inode,
178         struct file     *filp)
179 {
180         vnode_t         *vp = LINVFS_GET_VP(inode);
181         int             error;
182
183         if (!(filp->f_flags & O_LARGEFILE) && i_size_read(inode) > MAX_NON_LFS)
184                 return -EFBIG;
185
186         ASSERT(vp);
187         VOP_OPEN(vp, NULL, error);
188         return -error;
189 }
190
191
192 STATIC int
193 linvfs_release(
194         struct inode    *inode,
195         struct file     *filp)
196 {
197         vnode_t         *vp = LINVFS_GET_VP(inode);
198         int             error = 0;
199
200         if (vp)
201                 VOP_RELEASE(vp, error);
202         return -error;
203 }
204
205
206 STATIC int
207 linvfs_fsync(
208         struct file     *filp,
209         struct dentry   *dentry,
210         int             datasync)
211 {
212         struct inode    *inode = dentry->d_inode;
213         vnode_t         *vp = LINVFS_GET_VP(inode);
214         int             error;
215         int             flags = FSYNC_WAIT;
216
217         error = fsync_inode_data_buffers(inode);
218         if (error)
219                 return error;
220
221         if (datasync)
222                 flags |= FSYNC_DATA;
223
224         ASSERT(vp);
225         VOP_FSYNC(vp, flags, NULL, (xfs_off_t)0, (xfs_off_t)-1, error);
226         return -error;
227 }
228
229 /*
230  * linvfs_readdir maps to VOP_READDIR().
231  * We need to build a uio, cred, ...
232  */
233
234 #define nextdp(dp)      ((struct xfs_dirent *)((char *)(dp) + (dp)->d_reclen))
235
236 STATIC int
237 linvfs_readdir(
238         struct file     *filp,
239         void            *dirent,
240         filldir_t       filldir)
241 {
242         int             error = 0;
243         vnode_t         *vp;
244         uio_t           uio;
245         iovec_t         iov;
246         int             eof = 0;
247         caddr_t         read_buf;
248         int             namelen, size = 0;
249         size_t          rlen = PAGE_CACHE_SIZE;
250         xfs_off_t       start_offset, curr_offset;
251         xfs_dirent_t    *dbp = NULL;
252
253         vp = LINVFS_GET_VP(filp->f_dentry->d_inode);
254         ASSERT(vp);
255
256         /* Try fairly hard to get memory */
257         do {
258                 if ((read_buf = (caddr_t)kmalloc(rlen, GFP_KERNEL)))
259                         break;
260                 rlen >>= 1;
261         } while (rlen >= 1024);
262
263         if (read_buf == NULL)
264                 return -ENOMEM;
265
266         uio.uio_iov = &iov;
267         uio.uio_segflg = UIO_SYSSPACE;
268         curr_offset = filp->f_pos;
269         if (filp->f_pos != 0x7fffffff)
270                 uio.uio_offset = filp->f_pos;
271         else
272                 uio.uio_offset = 0xffffffff;
273
274         while (!eof) {
275                 uio.uio_resid = iov.iov_len = rlen;
276                 iov.iov_base = read_buf;
277                 uio.uio_iovcnt = 1;
278
279                 start_offset = uio.uio_offset;
280
281                 VOP_READDIR(vp, &uio, NULL, &eof, error);
282                 if ((uio.uio_offset == start_offset) || error) {
283                         size = 0;
284                         break;
285                 }
286
287                 size = rlen - uio.uio_resid;
288                 dbp = (xfs_dirent_t *)read_buf;
289                 while (size > 0) {
290                         namelen = strlen(dbp->d_name);
291
292                         if (filldir(dirent, dbp->d_name, namelen,
293                                         (loff_t) curr_offset & 0x7fffffff,
294                                         (ino_t) dbp->d_ino,
295                                         DT_UNKNOWN)) {
296                                 goto done;
297                         }
298                         size -= dbp->d_reclen;
299                         curr_offset = (loff_t)dbp->d_off /* & 0x7fffffff */;
300                         dbp = nextdp(dbp);
301                 }
302         }
303 done:
304         if (!error) {
305                 if (size == 0)
306                         filp->f_pos = uio.uio_offset & 0x7fffffff;
307                 else if (dbp)
308                         filp->f_pos = curr_offset;
309         }
310
311         kfree(read_buf);
312         return -error;
313 }
314
315 STATIC int
316 linvfs_file_mmap(
317         struct file     *filp,
318         struct vm_area_struct *vma)
319 {
320         struct inode    *ip = filp->f_dentry->d_inode;
321         vnode_t         *vp = LINVFS_GET_VP(ip);
322         vattr_t         va = { .va_mask = XFS_AT_UPDATIME };
323         int             error;
324
325         if (vp->v_vfsp->vfs_flag & VFS_DMI) {
326                 xfs_mount_t     *mp = XFS_VFSTOM(vp->v_vfsp);
327
328                 error = -XFS_SEND_MMAP(mp, vma, 0);
329                 if (error)
330                         return error;
331         }
332
333         vma->vm_ops = &linvfs_file_vm_ops;
334
335         VOP_SETATTR(vp, &va, XFS_AT_UPDATIME, NULL, error);
336         if (!error)
337                 vn_revalidate(vp);      /* update Linux inode flags */
338         return 0;
339 }
340
341
342 STATIC int
343 linvfs_ioctl(
344         struct inode    *inode,
345         struct file     *filp,
346         unsigned int    cmd,
347         unsigned long   arg)
348 {
349         int             error;
350         vnode_t         *vp = LINVFS_GET_VP(inode);
351
352         unlock_kernel();
353         VOP_IOCTL(vp, inode, filp, 0, cmd, arg, error);
354         VMODIFY(vp);
355         lock_kernel();
356
357         /* NOTE:  some of the ioctl's return positive #'s as a
358          *        byte count indicating success, such as
359          *        readlink_by_handle.  So we don't "sign flip"
360          *        like most other routines.  This means true
361          *        errors need to be returned as a negative value.
362          */
363         return error;
364 }
365
366 STATIC int
367 linvfs_ioctl_invis(
368         struct inode    *inode,
369         struct file     *filp,
370         unsigned int    cmd,
371         unsigned long   arg)
372 {
373         int             error;
374         vnode_t         *vp = LINVFS_GET_VP(inode);
375
376         unlock_kernel();
377         VOP_IOCTL(vp, inode, filp, IO_INVIS, cmd, arg, error);
378         VMODIFY(vp);
379         lock_kernel();
380
381         /* NOTE:  some of the ioctl's return positive #'s as a
382          *        byte count indicating success, such as
383          *        readlink_by_handle.  So we don't "sign flip"
384          *        like most other routines.  This means true
385          *        errors need to be returned as a negative value.
386          */
387         return error;
388 }
389
390 #ifdef HAVE_VMOP_MPROTECT
391 STATIC int
392 linvfs_mprotect(
393         struct vm_area_struct *vma,
394         unsigned int    newflags)
395 {
396         vnode_t         *vp = LINVFS_GET_VP(vma->vm_file->f_dentry->d_inode);
397         int             error = 0;
398
399         if (vp->v_vfsp->vfs_flag & VFS_DMI) {
400                 if ((vma->vm_flags & VM_MAYSHARE) &&
401                     (newflags & PROT_WRITE) && !(vma->vm_flags & PROT_WRITE)) {
402                         xfs_mount_t     *mp = XFS_VFSTOM(vp->v_vfsp);
403
404                         error = XFS_SEND_MMAP(mp, vma, VM_WRITE);
405                     }
406         }
407         return error;
408 }
409 #endif /* HAVE_VMOP_MPROTECT */
410
411
412 struct file_operations linvfs_file_operations = {
413         .llseek         = generic_file_llseek,
414         .read           = linvfs_read,
415         .write          = linvfs_write,
416         .ioctl          = linvfs_ioctl,
417         .mmap           = linvfs_file_mmap,
418         .open           = linvfs_open,
419         .release        = linvfs_release,
420         .fsync          = linvfs_fsync,
421 };
422
423 struct file_operations linvfs_invis_file_operations = {
424         .llseek         = generic_file_llseek,
425         .read           = linvfs_read_invis,
426         .write          = linvfs_write_invis,
427         .ioctl          = linvfs_ioctl_invis,
428         .mmap           = linvfs_file_mmap,
429         .open           = linvfs_open,
430         .release        = linvfs_release,
431         .fsync          = linvfs_fsync,
432 };
433
434
435 struct file_operations linvfs_dir_operations = {
436         .read           = generic_read_dir,
437         .readdir        = linvfs_readdir,
438         .ioctl          = linvfs_ioctl,
439         .fsync          = linvfs_fsync,
440 };
441
442 static struct vm_operations_struct linvfs_file_vm_ops = {
443         .nopage         = filemap_nopage,
444 #ifdef HAVE_VMOP_MPROTECT
445         .mprotect       = linvfs_mprotect,
446 #endif
447 };