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
__linvfs_read(struct file * file,char * buf,int ioflags,size_t size,loff_t * offset)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
linvfs_read(struct file * file,char * buf,size_t size,loff_t * offset)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
linvfs_read_invis(struct file * file,char * buf,size_t size,loff_t * offset)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
__linvfs_write(struct file * file,const char * buf,int ioflags,size_t count,loff_t * ppos)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
linvfs_write(struct file * file,const char * buf,size_t count,loff_t * ppos)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
linvfs_write_invis(struct file * file,const char * buf,size_t count,loff_t * ppos)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
linvfs_open(struct inode * inode,struct file * filp)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
linvfs_release(struct inode * inode,struct file * filp)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
linvfs_fsync(struct file * filp,struct dentry * dentry,int datasync)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
linvfs_readdir(struct file * filp,void * dirent,filldir_t filldir)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
linvfs_file_mmap(struct file * filp,struct vm_area_struct * vma)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
linvfs_ioctl(struct inode * inode,struct file * filp,unsigned int cmd,unsigned long arg)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
linvfs_ioctl_invis(struct inode * inode,struct file * filp,unsigned int cmd,unsigned long arg)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
linvfs_mprotect(struct vm_area_struct * vma,unsigned int newflags)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 };
448