]> git.proxmox.com Git - mirror_spl.git/blob - module/spl/spl-vnode.c
Fix cstyle warnings
[mirror_spl.git] / module / spl / spl-vnode.c
1 /*
2 * Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
3 * Copyright (C) 2007 The Regents of the University of California.
4 * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
5 * Written by Brian Behlendorf <behlendorf1@llnl.gov>.
6 * UCRL-CODE-235197
7 *
8 * This file is part of the SPL, Solaris Porting Layer.
9 * For details, see <http://zfsonlinux.org/>.
10 *
11 * The SPL is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2 of the License, or (at your
14 * option) any later version.
15 *
16 * The SPL is distributed in the hope that it will be useful, but WITHOUT
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 * for more details.
20 *
21 * You should have received a copy of the GNU General Public License along
22 * with the SPL. If not, see <http://www.gnu.org/licenses/>.
23 *
24 * Solaris Porting Layer (SPL) Vnode Implementation.
25 */
26
27 #include <sys/cred.h>
28 #include <sys/vnode.h>
29 #include <sys/kmem_cache.h>
30 #include <linux/falloc.h>
31 #include <linux/file_compat.h>
32
33 vnode_t *rootdir = (vnode_t *)0xabcd1234;
34 EXPORT_SYMBOL(rootdir);
35
36 static spl_kmem_cache_t *vn_cache;
37 static spl_kmem_cache_t *vn_file_cache;
38
39 static DEFINE_SPINLOCK(vn_file_lock);
40 static LIST_HEAD(vn_file_list);
41
42 vtype_t
43 vn_mode_to_vtype(mode_t mode)
44 {
45 if (S_ISREG(mode))
46 return (VREG);
47
48 if (S_ISDIR(mode))
49 return (VDIR);
50
51 if (S_ISCHR(mode))
52 return (VCHR);
53
54 if (S_ISBLK(mode))
55 return (VBLK);
56
57 if (S_ISFIFO(mode))
58 return (VFIFO);
59
60 if (S_ISLNK(mode))
61 return (VLNK);
62
63 if (S_ISSOCK(mode))
64 return (VSOCK);
65
66 return (VNON);
67 } /* vn_mode_to_vtype() */
68 EXPORT_SYMBOL(vn_mode_to_vtype);
69
70 mode_t
71 vn_vtype_to_mode(vtype_t vtype)
72 {
73 if (vtype == VREG)
74 return (S_IFREG);
75
76 if (vtype == VDIR)
77 return (S_IFDIR);
78
79 if (vtype == VCHR)
80 return (S_IFCHR);
81
82 if (vtype == VBLK)
83 return (S_IFBLK);
84
85 if (vtype == VFIFO)
86 return (S_IFIFO);
87
88 if (vtype == VLNK)
89 return (S_IFLNK);
90
91 if (vtype == VSOCK)
92 return (S_IFSOCK);
93
94 return (VNON);
95 } /* vn_vtype_to_mode() */
96 EXPORT_SYMBOL(vn_vtype_to_mode);
97
98 vnode_t *
99 vn_alloc(int flag)
100 {
101 vnode_t *vp;
102
103 vp = kmem_cache_alloc(vn_cache, flag);
104 if (vp != NULL) {
105 vp->v_file = NULL;
106 vp->v_type = 0;
107 }
108
109 return (vp);
110 } /* vn_alloc() */
111 EXPORT_SYMBOL(vn_alloc);
112
113 void
114 vn_free(vnode_t *vp)
115 {
116 kmem_cache_free(vn_cache, vp);
117 } /* vn_free() */
118 EXPORT_SYMBOL(vn_free);
119
120 int
121 vn_open(const char *path, uio_seg_t seg, int flags, int mode,
122 vnode_t **vpp, int x1, void *x2)
123 {
124 struct file *fp;
125 struct kstat stat;
126 int rc, saved_umask = 0;
127 gfp_t saved_gfp;
128 vnode_t *vp;
129
130 ASSERT(flags & (FWRITE | FREAD));
131 ASSERT(seg == UIO_SYSSPACE);
132 ASSERT(vpp);
133 *vpp = NULL;
134
135 if (!(flags & FCREAT) && (flags & FWRITE))
136 flags |= FEXCL;
137
138 /*
139 * Note for filp_open() the two low bits must be remapped to mean:
140 * 01 - read-only -> 00 read-only
141 * 10 - write-only -> 01 write-only
142 * 11 - read-write -> 10 read-write
143 */
144 flags--;
145
146 if (flags & FCREAT)
147 saved_umask = xchg(&current->fs->umask, 0);
148
149 fp = filp_open(path, flags, mode);
150
151 if (flags & FCREAT)
152 (void) xchg(&current->fs->umask, saved_umask);
153
154 if (IS_ERR(fp))
155 return (-PTR_ERR(fp));
156
157 #if defined(HAVE_4ARGS_VFS_GETATTR)
158 rc = vfs_getattr(&fp->f_path, &stat, STATX_TYPE, AT_STATX_SYNC_AS_STAT);
159 #elif defined(HAVE_2ARGS_VFS_GETATTR)
160 rc = vfs_getattr(&fp->f_path, &stat);
161 #else
162 rc = vfs_getattr(fp->f_path.mnt, fp->f_dentry, &stat);
163 #endif
164 if (rc) {
165 filp_close(fp, 0);
166 return (-rc);
167 }
168
169 vp = vn_alloc(KM_SLEEP);
170 if (!vp) {
171 filp_close(fp, 0);
172 return (ENOMEM);
173 }
174
175 saved_gfp = mapping_gfp_mask(fp->f_mapping);
176 mapping_set_gfp_mask(fp->f_mapping, saved_gfp & ~(__GFP_IO|__GFP_FS));
177
178 mutex_enter(&vp->v_lock);
179 vp->v_type = vn_mode_to_vtype(stat.mode);
180 vp->v_file = fp;
181 vp->v_gfp_mask = saved_gfp;
182 *vpp = vp;
183 mutex_exit(&vp->v_lock);
184
185 return (0);
186 } /* vn_open() */
187 EXPORT_SYMBOL(vn_open);
188
189 int
190 vn_openat(const char *path, uio_seg_t seg, int flags, int mode,
191 vnode_t **vpp, int x1, void *x2, vnode_t *vp, int fd)
192 {
193 char *realpath;
194 int len, rc;
195
196 ASSERT(vp == rootdir);
197
198 len = strlen(path) + 2;
199 realpath = kmalloc(len, kmem_flags_convert(KM_SLEEP));
200 if (!realpath)
201 return (ENOMEM);
202
203 (void) snprintf(realpath, len, "/%s", path);
204 rc = vn_open(realpath, seg, flags, mode, vpp, x1, x2);
205 kfree(realpath);
206
207 return (rc);
208 } /* vn_openat() */
209 EXPORT_SYMBOL(vn_openat);
210
211 int
212 vn_rdwr(uio_rw_t uio, vnode_t *vp, void *addr, ssize_t len, offset_t off,
213 uio_seg_t seg, int ioflag, rlim64_t x2, void *x3, ssize_t *residp)
214 {
215 struct file *fp = vp->v_file;
216 loff_t offset = off;
217 int rc;
218
219 ASSERT(uio == UIO_WRITE || uio == UIO_READ);
220 ASSERT(seg == UIO_SYSSPACE);
221 ASSERT((ioflag & ~FAPPEND) == 0);
222
223 if (ioflag & FAPPEND)
224 offset = fp->f_pos;
225
226 if (uio & UIO_WRITE)
227 rc = spl_kernel_write(fp, addr, len, &offset);
228 else
229 rc = spl_kernel_read(fp, addr, len, &offset);
230
231 fp->f_pos = offset;
232
233 if (rc < 0)
234 return (-rc);
235
236 if (residp) {
237 *residp = len - rc;
238 } else {
239 if (rc != len)
240 return (EIO);
241 }
242
243 return (0);
244 } /* vn_rdwr() */
245 EXPORT_SYMBOL(vn_rdwr);
246
247 int
248 vn_close(vnode_t *vp, int flags, int x1, int x2, void *x3, void *x4)
249 {
250 int rc;
251
252 ASSERT(vp);
253 ASSERT(vp->v_file);
254
255 mapping_set_gfp_mask(vp->v_file->f_mapping, vp->v_gfp_mask);
256 rc = filp_close(vp->v_file, 0);
257 vn_free(vp);
258
259 return (-rc);
260 } /* vn_close() */
261 EXPORT_SYMBOL(vn_close);
262
263 /*
264 * vn_seek() does not actually seek it only performs bounds checking on the
265 * proposed seek. We perform minimal checking and allow vn_rdwr() to catch
266 * anything more serious.
267 */
268 int
269 vn_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, void *ct)
270 {
271 return ((*noffp < 0 || *noffp > MAXOFFSET_T) ? EINVAL : 0);
272 }
273 EXPORT_SYMBOL(vn_seek);
274
275 int
276 vn_getattr(vnode_t *vp, vattr_t *vap, int flags, void *x3, void *x4)
277 {
278 struct file *fp;
279 struct kstat stat;
280 int rc;
281
282 ASSERT(vp);
283 ASSERT(vp->v_file);
284 ASSERT(vap);
285
286 fp = vp->v_file;
287
288 #if defined(HAVE_4ARGS_VFS_GETATTR)
289 rc = vfs_getattr(&fp->f_path, &stat, STATX_BASIC_STATS,
290 AT_STATX_SYNC_AS_STAT);
291 #elif defined(HAVE_2ARGS_VFS_GETATTR)
292 rc = vfs_getattr(&fp->f_path, &stat);
293 #else
294 rc = vfs_getattr(fp->f_path.mnt, fp->f_dentry, &stat);
295 #endif
296 if (rc)
297 return (-rc);
298
299 vap->va_type = vn_mode_to_vtype(stat.mode);
300 vap->va_mode = stat.mode;
301 vap->va_uid = KUID_TO_SUID(stat.uid);
302 vap->va_gid = KGID_TO_SGID(stat.gid);
303 vap->va_fsid = 0;
304 vap->va_nodeid = stat.ino;
305 vap->va_nlink = stat.nlink;
306 vap->va_size = stat.size;
307 vap->va_blksize = stat.blksize;
308 vap->va_atime = stat.atime;
309 vap->va_mtime = stat.mtime;
310 vap->va_ctime = stat.ctime;
311 vap->va_rdev = stat.rdev;
312 vap->va_nblocks = stat.blocks;
313
314 return (0);
315 }
316 EXPORT_SYMBOL(vn_getattr);
317
318 int
319 vn_fsync(vnode_t *vp, int flags, void *x3, void *x4)
320 {
321 int datasync = 0;
322 int error;
323 int fstrans;
324
325 ASSERT(vp);
326 ASSERT(vp->v_file);
327
328 if (flags & FDSYNC)
329 datasync = 1;
330
331 /*
332 * May enter XFS which generates a warning when PF_FSTRANS is set.
333 * To avoid this the flag is cleared over vfs_sync() and then reset.
334 */
335 fstrans = __spl_pf_fstrans_check();
336 if (fstrans)
337 current->flags &= ~(__SPL_PF_FSTRANS);
338
339 error = -spl_filp_fsync(vp->v_file, datasync);
340 if (fstrans)
341 current->flags |= __SPL_PF_FSTRANS;
342
343 return (error);
344 } /* vn_fsync() */
345 EXPORT_SYMBOL(vn_fsync);
346
347 int vn_space(vnode_t *vp, int cmd, struct flock *bfp, int flag,
348 offset_t offset, void *x6, void *x7)
349 {
350 int error = EOPNOTSUPP;
351 #ifdef FALLOC_FL_PUNCH_HOLE
352 int fstrans;
353 #endif
354
355 if (cmd != F_FREESP || bfp->l_whence != 0)
356 return (EOPNOTSUPP);
357
358 ASSERT(vp);
359 ASSERT(vp->v_file);
360 ASSERT(bfp->l_start >= 0 && bfp->l_len > 0);
361
362 #ifdef FALLOC_FL_PUNCH_HOLE
363 /*
364 * May enter XFS which generates a warning when PF_FSTRANS is set.
365 * To avoid this the flag is cleared over vfs_sync() and then reset.
366 */
367 fstrans = __spl_pf_fstrans_check();
368 if (fstrans)
369 current->flags &= ~(__SPL_PF_FSTRANS);
370
371 /*
372 * When supported by the underlying file system preferentially
373 * use the fallocate() callback to preallocate the space.
374 */
375 error = -spl_filp_fallocate(vp->v_file,
376 FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
377 bfp->l_start, bfp->l_len);
378
379 if (fstrans)
380 current->flags |= __SPL_PF_FSTRANS;
381
382 if (error == 0)
383 return (0);
384 #endif
385
386 #ifdef HAVE_INODE_TRUNCATE_RANGE
387 if (vp->v_file->f_dentry && vp->v_file->f_dentry->d_inode &&
388 vp->v_file->f_dentry->d_inode->i_op &&
389 vp->v_file->f_dentry->d_inode->i_op->truncate_range) {
390 off_t end = bfp->l_start + bfp->l_len;
391 /*
392 * Judging from the code in shmem_truncate_range(),
393 * it seems the kernel expects the end offset to be
394 * inclusive and aligned to the end of a page.
395 */
396 if (end % PAGE_SIZE != 0) {
397 end &= ~(off_t)(PAGE_SIZE - 1);
398 if (end <= bfp->l_start)
399 return (0);
400 }
401 --end;
402
403 vp->v_file->f_dentry->d_inode->i_op->truncate_range(
404 vp->v_file->f_dentry->d_inode,
405 bfp->l_start, end
406 );
407 return (0);
408 }
409 #endif
410
411 return (error);
412 }
413 EXPORT_SYMBOL(vn_space);
414
415 /* Function must be called while holding the vn_file_lock */
416 static file_t *
417 file_find(int fd, struct task_struct *task)
418 {
419 file_t *fp;
420
421 list_for_each_entry(fp, &vn_file_list, f_list) {
422 if (fd == fp->f_fd && fp->f_task == task) {
423 ASSERT(atomic_read(&fp->f_ref) != 0);
424 return (fp);
425 }
426 }
427
428 return (NULL);
429 } /* file_find() */
430
431 file_t *
432 vn_getf(int fd)
433 {
434 struct kstat stat;
435 struct file *lfp;
436 file_t *fp;
437 vnode_t *vp;
438 int rc = 0;
439
440 if (fd < 0)
441 return (NULL);
442
443 /* Already open just take an extra reference */
444 spin_lock(&vn_file_lock);
445
446 fp = file_find(fd, current);
447 if (fp) {
448 lfp = fget(fd);
449 fput(fp->f_file);
450 /*
451 * areleasef() can cause us to see a stale reference when
452 * userspace has reused a file descriptor before areleasef()
453 * has run. fput() the stale reference and replace it. We
454 * retain the original reference count such that the concurrent
455 * areleasef() will decrement its reference and terminate.
456 */
457 if (lfp != fp->f_file) {
458 fp->f_file = lfp;
459 fp->f_vnode->v_file = lfp;
460 }
461 atomic_inc(&fp->f_ref);
462 spin_unlock(&vn_file_lock);
463 return (fp);
464 }
465
466 spin_unlock(&vn_file_lock);
467
468 /* File was not yet opened create the object and setup */
469 fp = kmem_cache_alloc(vn_file_cache, KM_SLEEP);
470 if (fp == NULL)
471 goto out;
472
473 mutex_enter(&fp->f_lock);
474
475 fp->f_fd = fd;
476 fp->f_task = current;
477 fp->f_offset = 0;
478 atomic_inc(&fp->f_ref);
479
480 lfp = fget(fd);
481 if (lfp == NULL)
482 goto out_mutex;
483
484 vp = vn_alloc(KM_SLEEP);
485 if (vp == NULL)
486 goto out_fget;
487
488 #if defined(HAVE_4ARGS_VFS_GETATTR)
489 rc = vfs_getattr(&lfp->f_path, &stat, STATX_TYPE,
490 AT_STATX_SYNC_AS_STAT);
491 #elif defined(HAVE_2ARGS_VFS_GETATTR)
492 rc = vfs_getattr(&lfp->f_path, &stat);
493 #else
494 rc = vfs_getattr(lfp->f_path.mnt, lfp->f_dentry, &stat);
495 #endif
496 if (rc)
497 goto out_vnode;
498
499 mutex_enter(&vp->v_lock);
500 vp->v_type = vn_mode_to_vtype(stat.mode);
501 vp->v_file = lfp;
502 mutex_exit(&vp->v_lock);
503
504 fp->f_vnode = vp;
505 fp->f_file = lfp;
506
507 /* Put it on the tracking list */
508 spin_lock(&vn_file_lock);
509 list_add(&fp->f_list, &vn_file_list);
510 spin_unlock(&vn_file_lock);
511
512 mutex_exit(&fp->f_lock);
513 return (fp);
514
515 out_vnode:
516 vn_free(vp);
517 out_fget:
518 fput(lfp);
519 out_mutex:
520 mutex_exit(&fp->f_lock);
521 kmem_cache_free(vn_file_cache, fp);
522 out:
523 return (NULL);
524 } /* getf() */
525 EXPORT_SYMBOL(getf);
526
527 static void releasef_locked(file_t *fp)
528 {
529 ASSERT(fp->f_file);
530 ASSERT(fp->f_vnode);
531
532 /* Unlinked from list, no refs, safe to free outside mutex */
533 fput(fp->f_file);
534 vn_free(fp->f_vnode);
535
536 kmem_cache_free(vn_file_cache, fp);
537 }
538
539 void
540 vn_releasef(int fd)
541 {
542 areleasef(fd, P_FINFO(current));
543 }
544 EXPORT_SYMBOL(releasef);
545
546 void
547 vn_areleasef(int fd, uf_info_t *fip)
548 {
549 file_t *fp;
550 struct task_struct *task = (struct task_struct *)fip;
551
552 if (fd < 0)
553 return;
554
555 spin_lock(&vn_file_lock);
556 fp = file_find(fd, task);
557 if (fp) {
558 atomic_dec(&fp->f_ref);
559 if (atomic_read(&fp->f_ref) > 0) {
560 spin_unlock(&vn_file_lock);
561 return;
562 }
563
564 list_del(&fp->f_list);
565 releasef_locked(fp);
566 }
567 spin_unlock(&vn_file_lock);
568 } /* releasef() */
569 EXPORT_SYMBOL(areleasef);
570
571
572 static void
573 #ifdef HAVE_SET_FS_PWD_WITH_CONST
574 vn_set_fs_pwd(struct fs_struct *fs, const struct path *path)
575 #else
576 vn_set_fs_pwd(struct fs_struct *fs, struct path *path)
577 #endif /* HAVE_SET_FS_PWD_WITH_CONST */
578 {
579 struct path old_pwd;
580
581 #ifdef HAVE_FS_STRUCT_SPINLOCK
582 spin_lock(&fs->lock);
583 old_pwd = fs->pwd;
584 fs->pwd = *path;
585 path_get(path);
586 spin_unlock(&fs->lock);
587 #else
588 write_lock(&fs->lock);
589 old_pwd = fs->pwd;
590 fs->pwd = *path;
591 path_get(path);
592 write_unlock(&fs->lock);
593 #endif /* HAVE_FS_STRUCT_SPINLOCK */
594
595 if (old_pwd.dentry)
596 path_put(&old_pwd);
597 }
598
599 int
600 vn_set_pwd(const char *filename)
601 {
602 struct path path;
603 mm_segment_t saved_fs;
604 int rc;
605
606 /*
607 * user_path_dir() and __user_walk() both expect 'filename' to be
608 * a user space address so we must briefly increase the data segment
609 * size to ensure strncpy_from_user() does not fail with -EFAULT.
610 */
611 saved_fs = get_fs();
612 set_fs(get_ds());
613
614 rc = user_path_dir(filename, &path);
615 if (rc)
616 goto out;
617
618 rc = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS);
619 if (rc)
620 goto dput_and_out;
621
622 vn_set_fs_pwd(current->fs, &path);
623
624 dput_and_out:
625 path_put(&path);
626 out:
627 set_fs(saved_fs);
628
629 return (-rc);
630 } /* vn_set_pwd() */
631 EXPORT_SYMBOL(vn_set_pwd);
632
633 static int
634 vn_cache_constructor(void *buf, void *cdrarg, int kmflags)
635 {
636 struct vnode *vp = buf;
637
638 mutex_init(&vp->v_lock, NULL, MUTEX_DEFAULT, NULL);
639
640 return (0);
641 } /* vn_cache_constructor() */
642
643 static void
644 vn_cache_destructor(void *buf, void *cdrarg)
645 {
646 struct vnode *vp = buf;
647
648 mutex_destroy(&vp->v_lock);
649 } /* vn_cache_destructor() */
650
651 static int
652 vn_file_cache_constructor(void *buf, void *cdrarg, int kmflags)
653 {
654 file_t *fp = buf;
655
656 atomic_set(&fp->f_ref, 0);
657 mutex_init(&fp->f_lock, NULL, MUTEX_DEFAULT, NULL);
658 INIT_LIST_HEAD(&fp->f_list);
659
660 return (0);
661 } /* file_cache_constructor() */
662
663 static void
664 vn_file_cache_destructor(void *buf, void *cdrarg)
665 {
666 file_t *fp = buf;
667
668 mutex_destroy(&fp->f_lock);
669 } /* vn_file_cache_destructor() */
670
671 int
672 spl_vn_init(void)
673 {
674 vn_cache = kmem_cache_create("spl_vn_cache",
675 sizeof (struct vnode), 64, vn_cache_constructor,
676 vn_cache_destructor, NULL, NULL, NULL, 0);
677
678 vn_file_cache = kmem_cache_create("spl_vn_file_cache",
679 sizeof (file_t), 64, vn_file_cache_constructor,
680 vn_file_cache_destructor, NULL, NULL, NULL, 0);
681
682 return (0);
683 } /* vn_init() */
684
685 void
686 spl_vn_fini(void)
687 {
688 file_t *fp, *next_fp;
689 int leaked = 0;
690
691 spin_lock(&vn_file_lock);
692
693 list_for_each_entry_safe(fp, next_fp, &vn_file_list, f_list) {
694 list_del(&fp->f_list);
695 releasef_locked(fp);
696 leaked++;
697 }
698
699 spin_unlock(&vn_file_lock);
700
701 if (leaked > 0)
702 printk(KERN_WARNING "WARNING: %d vnode files leaked\n", leaked);
703
704 kmem_cache_destroy(vn_file_cache);
705 kmem_cache_destroy(vn_cache);
706 } /* vn_fini() */