blob: b0c00eaa79e484becf969a25d0901582f07f4175 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Copyright (c) 2000-2005 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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include "xfs.h"
Nathan Scotta844f452005-11-02 14:38:42 +110033#include "xfs_bit.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include "xfs_log.h"
Nathan Scotta844f452005-11-02 14:38:42 +110035#include "xfs_inum.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include "xfs_sb.h"
Nathan Scotta844f452005-11-02 14:38:42 +110037#include "xfs_ag.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include "xfs_dir.h"
39#include "xfs_dir2.h"
40#include "xfs_trans.h"
41#include "xfs_dmapi.h"
42#include "xfs_mount.h"
43#include "xfs_bmap_btree.h"
44#include "xfs_alloc_btree.h"
45#include "xfs_ialloc_btree.h"
46#include "xfs_alloc.h"
47#include "xfs_btree.h"
48#include "xfs_attr_sf.h"
49#include "xfs_dir_sf.h"
50#include "xfs_dir2_sf.h"
51#include "xfs_dinode.h"
52#include "xfs_inode.h"
53#include "xfs_error.h"
54#include "xfs_rw.h"
55#include "xfs_ioctl32.h"
56
57#include <linux/dcache.h>
58#include <linux/smp_lock.h>
59
60static struct vm_operations_struct linvfs_file_vm_ops;
Dean Roehrich6fac0cb2005-06-21 14:07:45 +100061#ifdef CONFIG_XFS_DMAPI
62static struct vm_operations_struct linvfs_dmapi_file_vm_ops;
63#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
65STATIC inline ssize_t
66__linvfs_read(
67 struct kiocb *iocb,
68 char __user *buf,
69 int ioflags,
70 size_t count,
71 loff_t pos)
72{
73 struct iovec iov = {buf, count};
74 struct file *file = iocb->ki_filp;
75 vnode_t *vp = LINVFS_GET_VP(file->f_dentry->d_inode);
76 ssize_t rval;
77
78 BUG_ON(iocb->ki_pos != pos);
79
80 if (unlikely(file->f_flags & O_DIRECT))
81 ioflags |= IO_ISDIRECT;
82 VOP_READ(vp, iocb, &iov, 1, &iocb->ki_pos, ioflags, NULL, rval);
83 return rval;
84}
85
86
87STATIC ssize_t
88linvfs_aio_read(
89 struct kiocb *iocb,
90 char __user *buf,
91 size_t count,
92 loff_t pos)
93{
94 return __linvfs_read(iocb, buf, IO_ISAIO, count, pos);
95}
96
97STATIC ssize_t
98linvfs_aio_read_invis(
99 struct kiocb *iocb,
100 char __user *buf,
101 size_t count,
102 loff_t pos)
103{
104 return __linvfs_read(iocb, buf, IO_ISAIO|IO_INVIS, count, pos);
105}
106
107
108STATIC inline ssize_t
109__linvfs_write(
110 struct kiocb *iocb,
111 const char __user *buf,
112 int ioflags,
113 size_t count,
114 loff_t pos)
115{
116 struct iovec iov = {(void __user *)buf, count};
117 struct file *file = iocb->ki_filp;
118 struct inode *inode = file->f_mapping->host;
119 vnode_t *vp = LINVFS_GET_VP(inode);
120 ssize_t rval;
121
122 BUG_ON(iocb->ki_pos != pos);
123 if (unlikely(file->f_flags & O_DIRECT))
124 ioflags |= IO_ISDIRECT;
125
126 VOP_WRITE(vp, iocb, &iov, 1, &iocb->ki_pos, ioflags, NULL, rval);
127 return rval;
128}
129
130
131STATIC ssize_t
132linvfs_aio_write(
133 struct kiocb *iocb,
134 const char __user *buf,
135 size_t count,
136 loff_t pos)
137{
138 return __linvfs_write(iocb, buf, IO_ISAIO, count, pos);
139}
140
141STATIC ssize_t
142linvfs_aio_write_invis(
143 struct kiocb *iocb,
144 const char __user *buf,
145 size_t count,
146 loff_t pos)
147{
148 return __linvfs_write(iocb, buf, IO_ISAIO|IO_INVIS, count, pos);
149}
150
151
152STATIC inline ssize_t
153__linvfs_readv(
154 struct file *file,
155 const struct iovec *iov,
156 int ioflags,
157 unsigned long nr_segs,
158 loff_t *ppos)
159{
160 struct inode *inode = file->f_mapping->host;
161 vnode_t *vp = LINVFS_GET_VP(inode);
162 struct kiocb kiocb;
163 ssize_t rval;
164
165 init_sync_kiocb(&kiocb, file);
166 kiocb.ki_pos = *ppos;
167
168 if (unlikely(file->f_flags & O_DIRECT))
169 ioflags |= IO_ISDIRECT;
170 VOP_READ(vp, &kiocb, iov, nr_segs, &kiocb.ki_pos, ioflags, NULL, rval);
171
172 *ppos = kiocb.ki_pos;
173 return rval;
174}
175
176STATIC ssize_t
177linvfs_readv(
178 struct file *file,
179 const struct iovec *iov,
180 unsigned long nr_segs,
181 loff_t *ppos)
182{
183 return __linvfs_readv(file, iov, 0, nr_segs, ppos);
184}
185
186STATIC ssize_t
187linvfs_readv_invis(
188 struct file *file,
189 const struct iovec *iov,
190 unsigned long nr_segs,
191 loff_t *ppos)
192{
193 return __linvfs_readv(file, iov, IO_INVIS, nr_segs, ppos);
194}
195
196
197STATIC inline ssize_t
198__linvfs_writev(
199 struct file *file,
200 const struct iovec *iov,
201 int ioflags,
202 unsigned long nr_segs,
203 loff_t *ppos)
204{
205 struct inode *inode = file->f_mapping->host;
206 vnode_t *vp = LINVFS_GET_VP(inode);
207 struct kiocb kiocb;
208 ssize_t rval;
209
210 init_sync_kiocb(&kiocb, file);
211 kiocb.ki_pos = *ppos;
212 if (unlikely(file->f_flags & O_DIRECT))
213 ioflags |= IO_ISDIRECT;
214
215 VOP_WRITE(vp, &kiocb, iov, nr_segs, &kiocb.ki_pos, ioflags, NULL, rval);
216
217 *ppos = kiocb.ki_pos;
218 return rval;
219}
220
221
222STATIC ssize_t
223linvfs_writev(
224 struct file *file,
225 const struct iovec *iov,
226 unsigned long nr_segs,
227 loff_t *ppos)
228{
229 return __linvfs_writev(file, iov, 0, nr_segs, ppos);
230}
231
232STATIC ssize_t
233linvfs_writev_invis(
234 struct file *file,
235 const struct iovec *iov,
236 unsigned long nr_segs,
237 loff_t *ppos)
238{
239 return __linvfs_writev(file, iov, IO_INVIS, nr_segs, ppos);
240}
241
242STATIC ssize_t
243linvfs_sendfile(
244 struct file *filp,
245 loff_t *ppos,
246 size_t count,
247 read_actor_t actor,
248 void *target)
249{
250 vnode_t *vp = LINVFS_GET_VP(filp->f_dentry->d_inode);
251 ssize_t rval;
252
253 VOP_SENDFILE(vp, filp, ppos, 0, count, actor, target, NULL, rval);
254 return rval;
255}
256
257
258STATIC int
259linvfs_open(
260 struct inode *inode,
261 struct file *filp)
262{
263 vnode_t *vp = LINVFS_GET_VP(inode);
264 int error;
265
266 if (!(filp->f_flags & O_LARGEFILE) && i_size_read(inode) > MAX_NON_LFS)
267 return -EFBIG;
268
269 ASSERT(vp);
270 VOP_OPEN(vp, NULL, error);
271 return -error;
272}
273
274
275STATIC int
276linvfs_release(
277 struct inode *inode,
278 struct file *filp)
279{
280 vnode_t *vp = LINVFS_GET_VP(inode);
281 int error = 0;
282
283 if (vp)
284 VOP_RELEASE(vp, error);
285 return -error;
286}
287
288
289STATIC int
290linvfs_fsync(
291 struct file *filp,
292 struct dentry *dentry,
293 int datasync)
294{
295 struct inode *inode = dentry->d_inode;
296 vnode_t *vp = LINVFS_GET_VP(inode);
297 int error;
298 int flags = FSYNC_WAIT;
299
300 if (datasync)
301 flags |= FSYNC_DATA;
302
303 ASSERT(vp);
304 VOP_FSYNC(vp, flags, NULL, (xfs_off_t)0, (xfs_off_t)-1, error);
305 return -error;
306}
307
308/*
309 * linvfs_readdir maps to VOP_READDIR().
310 * We need to build a uio, cred, ...
311 */
312
313#define nextdp(dp) ((struct xfs_dirent *)((char *)(dp) + (dp)->d_reclen))
314
Dean Roehrichbb3f7242005-09-02 15:43:05 +1000315#ifdef CONFIG_XFS_DMAPI
316
317STATIC struct page *
318linvfs_filemap_nopage(
319 struct vm_area_struct *area,
320 unsigned long address,
321 int *type)
322{
323 struct inode *inode = area->vm_file->f_dentry->d_inode;
324 vnode_t *vp = LINVFS_GET_VP(inode);
325 xfs_mount_t *mp = XFS_VFSTOM(vp->v_vfsp);
326 int error;
327
328 ASSERT_ALWAYS(vp->v_vfsp->vfs_flag & VFS_DMI);
329
330 error = XFS_SEND_MMAP(mp, area, 0);
331 if (error)
332 return NULL;
333
334 return filemap_nopage(area, address, type);
335}
336
337#endif /* CONFIG_XFS_DMAPI */
338
339
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340STATIC int
341linvfs_readdir(
342 struct file *filp,
343 void *dirent,
344 filldir_t filldir)
345{
346 int error = 0;
347 vnode_t *vp;
348 uio_t uio;
349 iovec_t iov;
350 int eof = 0;
351 caddr_t read_buf;
352 int namelen, size = 0;
353 size_t rlen = PAGE_CACHE_SIZE;
354 xfs_off_t start_offset, curr_offset;
355 xfs_dirent_t *dbp = NULL;
356
357 vp = LINVFS_GET_VP(filp->f_dentry->d_inode);
358 ASSERT(vp);
359
360 /* Try fairly hard to get memory */
361 do {
362 if ((read_buf = (caddr_t)kmalloc(rlen, GFP_KERNEL)))
363 break;
364 rlen >>= 1;
365 } while (rlen >= 1024);
366
367 if (read_buf == NULL)
368 return -ENOMEM;
369
370 uio.uio_iov = &iov;
371 uio.uio_segflg = UIO_SYSSPACE;
372 curr_offset = filp->f_pos;
373 if (filp->f_pos != 0x7fffffff)
374 uio.uio_offset = filp->f_pos;
375 else
376 uio.uio_offset = 0xffffffff;
377
378 while (!eof) {
379 uio.uio_resid = iov.iov_len = rlen;
380 iov.iov_base = read_buf;
381 uio.uio_iovcnt = 1;
382
383 start_offset = uio.uio_offset;
384
385 VOP_READDIR(vp, &uio, NULL, &eof, error);
386 if ((uio.uio_offset == start_offset) || error) {
387 size = 0;
388 break;
389 }
390
391 size = rlen - uio.uio_resid;
392 dbp = (xfs_dirent_t *)read_buf;
393 while (size > 0) {
394 namelen = strlen(dbp->d_name);
395
396 if (filldir(dirent, dbp->d_name, namelen,
397 (loff_t) curr_offset & 0x7fffffff,
398 (ino_t) dbp->d_ino,
399 DT_UNKNOWN)) {
400 goto done;
401 }
402 size -= dbp->d_reclen;
403 curr_offset = (loff_t)dbp->d_off /* & 0x7fffffff */;
404 dbp = nextdp(dbp);
405 }
406 }
407done:
408 if (!error) {
409 if (size == 0)
410 filp->f_pos = uio.uio_offset & 0x7fffffff;
411 else if (dbp)
412 filp->f_pos = curr_offset;
413 }
414
415 kfree(read_buf);
416 return -error;
417}
418
419
420STATIC int
421linvfs_file_mmap(
422 struct file *filp,
423 struct vm_area_struct *vma)
424{
425 struct inode *ip = filp->f_dentry->d_inode;
426 vnode_t *vp = LINVFS_GET_VP(ip);
427 vattr_t va = { .va_mask = XFS_AT_UPDATIME };
428 int error;
429
Dean Roehrich6fac0cb2005-06-21 14:07:45 +1000430 vma->vm_ops = &linvfs_file_vm_ops;
431
Dean Roehrich6fac0cb2005-06-21 14:07:45 +1000432#ifdef CONFIG_XFS_DMAPI
Dean Roehrichbb3f7242005-09-02 15:43:05 +1000433 if (vp->v_vfsp->vfs_flag & VFS_DMI) {
Dean Roehrich6fac0cb2005-06-21 14:07:45 +1000434 vma->vm_ops = &linvfs_dmapi_file_vm_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 }
Dean Roehrichbb3f7242005-09-02 15:43:05 +1000436#endif /* CONFIG_XFS_DMAPI */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 VOP_SETATTR(vp, &va, XFS_AT_UPDATIME, NULL, error);
439 if (!error)
440 vn_revalidate(vp); /* update Linux inode flags */
441 return 0;
442}
443
444
445STATIC long
446linvfs_ioctl(
447 struct file *filp,
448 unsigned int cmd,
449 unsigned long arg)
450{
451 int error;
452 struct inode *inode = filp->f_dentry->d_inode;
453 vnode_t *vp = LINVFS_GET_VP(inode);
454
455 VOP_IOCTL(vp, inode, filp, 0, cmd, (void __user *)arg, error);
456 VMODIFY(vp);
457
458 /* NOTE: some of the ioctl's return positive #'s as a
459 * byte count indicating success, such as
460 * readlink_by_handle. So we don't "sign flip"
461 * like most other routines. This means true
462 * errors need to be returned as a negative value.
463 */
464 return error;
465}
466
467STATIC long
468linvfs_ioctl_invis(
469 struct file *filp,
470 unsigned int cmd,
471 unsigned long arg)
472{
473 int error;
474 struct inode *inode = filp->f_dentry->d_inode;
475 vnode_t *vp = LINVFS_GET_VP(inode);
476
477 ASSERT(vp);
478 VOP_IOCTL(vp, inode, filp, IO_INVIS, cmd, (void __user *)arg, error);
479 VMODIFY(vp);
480
481 /* NOTE: some of the ioctl's return positive #'s as a
482 * byte count indicating success, such as
483 * readlink_by_handle. So we don't "sign flip"
484 * like most other routines. This means true
485 * errors need to be returned as a negative value.
486 */
487 return error;
488}
489
Dean Roehrichbb3f7242005-09-02 15:43:05 +1000490#ifdef CONFIG_XFS_DMAPI
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491#ifdef HAVE_VMOP_MPROTECT
492STATIC int
493linvfs_mprotect(
494 struct vm_area_struct *vma,
495 unsigned int newflags)
496{
497 vnode_t *vp = LINVFS_GET_VP(vma->vm_file->f_dentry->d_inode);
498 int error = 0;
499
500 if (vp->v_vfsp->vfs_flag & VFS_DMI) {
501 if ((vma->vm_flags & VM_MAYSHARE) &&
502 (newflags & VM_WRITE) && !(vma->vm_flags & VM_WRITE)) {
503 xfs_mount_t *mp = XFS_VFSTOM(vp->v_vfsp);
504
505 error = XFS_SEND_MMAP(mp, vma, VM_WRITE);
506 }
507 }
508 return error;
509}
510#endif /* HAVE_VMOP_MPROTECT */
Dean Roehrichbb3f7242005-09-02 15:43:05 +1000511#endif /* CONFIG_XFS_DMAPI */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512
513#ifdef HAVE_FOP_OPEN_EXEC
514/* If the user is attempting to execute a file that is offline then
515 * we have to trigger a DMAPI READ event before the file is marked as busy
516 * otherwise the invisible I/O will not be able to write to the file to bring
517 * it back online.
518 */
519STATIC int
520linvfs_open_exec(
521 struct inode *inode)
522{
523 vnode_t *vp = LINVFS_GET_VP(inode);
524 xfs_mount_t *mp = XFS_VFSTOM(vp->v_vfsp);
525 int error = 0;
526 bhv_desc_t *bdp;
527 xfs_inode_t *ip;
528
529 if (vp->v_vfsp->vfs_flag & VFS_DMI) {
530 bdp = vn_bhv_lookup(VN_BHV_HEAD(vp), &xfs_vnodeops);
531 if (!bdp) {
532 error = -EINVAL;
533 goto open_exec_out;
534 }
535 ip = XFS_BHVTOI(bdp);
536 if (DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ)) {
537 error = -XFS_SEND_DATA(mp, DM_EVENT_READ, vp,
538 0, 0, 0, NULL);
539 }
540 }
541open_exec_out:
542 return error;
543}
544#endif /* HAVE_FOP_OPEN_EXEC */
545
546struct file_operations linvfs_file_operations = {
547 .llseek = generic_file_llseek,
548 .read = do_sync_read,
Dean Roehrichbb3f7242005-09-02 15:43:05 +1000549 .write = do_sync_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 .readv = linvfs_readv,
551 .writev = linvfs_writev,
552 .aio_read = linvfs_aio_read,
553 .aio_write = linvfs_aio_write,
554 .sendfile = linvfs_sendfile,
555 .unlocked_ioctl = linvfs_ioctl,
556#ifdef CONFIG_COMPAT
Nathan Scottd3870392005-05-06 06:44:46 -0700557 .compat_ioctl = linvfs_compat_ioctl,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558#endif
559 .mmap = linvfs_file_mmap,
560 .open = linvfs_open,
561 .release = linvfs_release,
562 .fsync = linvfs_fsync,
563#ifdef HAVE_FOP_OPEN_EXEC
564 .open_exec = linvfs_open_exec,
565#endif
566};
567
568struct file_operations linvfs_invis_file_operations = {
569 .llseek = generic_file_llseek,
570 .read = do_sync_read,
Dean Roehrichbb3f7242005-09-02 15:43:05 +1000571 .write = do_sync_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 .readv = linvfs_readv_invis,
573 .writev = linvfs_writev_invis,
574 .aio_read = linvfs_aio_read_invis,
575 .aio_write = linvfs_aio_write_invis,
576 .sendfile = linvfs_sendfile,
577 .unlocked_ioctl = linvfs_ioctl_invis,
578#ifdef CONFIG_COMPAT
Nathan Scottd3870392005-05-06 06:44:46 -0700579 .compat_ioctl = linvfs_compat_invis_ioctl,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580#endif
581 .mmap = linvfs_file_mmap,
582 .open = linvfs_open,
583 .release = linvfs_release,
584 .fsync = linvfs_fsync,
585};
586
587
588struct file_operations linvfs_dir_operations = {
589 .read = generic_read_dir,
590 .readdir = linvfs_readdir,
591 .unlocked_ioctl = linvfs_ioctl,
Nathan Scottd3870392005-05-06 06:44:46 -0700592#ifdef CONFIG_COMPAT
593 .compat_ioctl = linvfs_compat_ioctl,
594#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 .fsync = linvfs_fsync,
596};
597
598static struct vm_operations_struct linvfs_file_vm_ops = {
599 .nopage = filemap_nopage,
600 .populate = filemap_populate,
Dean Roehrich6fac0cb2005-06-21 14:07:45 +1000601};
602
603#ifdef CONFIG_XFS_DMAPI
604static struct vm_operations_struct linvfs_dmapi_file_vm_ops = {
Dean Roehrichbb3f7242005-09-02 15:43:05 +1000605 .nopage = linvfs_filemap_nopage,
Dean Roehrich6fac0cb2005-06-21 14:07:45 +1000606 .populate = filemap_populate,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607#ifdef HAVE_VMOP_MPROTECT
608 .mprotect = linvfs_mprotect,
609#endif
610};
Dean Roehrich6fac0cb2005-06-21 14:07:45 +1000611#endif /* CONFIG_XFS_DMAPI */