]> git.proxmox.com Git - mirror_spl-debian.git/blob - module/spl/spl-vnode.c
e3188a1af8b091523402f0a28b66d6abda59e85e
[mirror_spl-debian.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 if (S_ISCHR(mode))
67 return VCHR;
68
69 return VNON;
70 } /* vn_mode_to_vtype() */
71 EXPORT_SYMBOL(vn_mode_to_vtype);
72
73 mode_t
74 vn_vtype_to_mode(vtype_t vtype)
75 {
76 if (vtype == VREG)
77 return S_IFREG;
78
79 if (vtype == VDIR)
80 return S_IFDIR;
81
82 if (vtype == VCHR)
83 return S_IFCHR;
84
85 if (vtype == VBLK)
86 return S_IFBLK;
87
88 if (vtype == VFIFO)
89 return S_IFIFO;
90
91 if (vtype == VLNK)
92 return S_IFLNK;
93
94 if (vtype == VSOCK)
95 return S_IFSOCK;
96
97 return VNON;
98 } /* vn_vtype_to_mode() */
99 EXPORT_SYMBOL(vn_vtype_to_mode);
100
101 vnode_t *
102 vn_alloc(int flag)
103 {
104 vnode_t *vp;
105
106 vp = kmem_cache_alloc(vn_cache, flag);
107 if (vp != NULL) {
108 vp->v_file = NULL;
109 vp->v_type = 0;
110 }
111
112 return (vp);
113 } /* vn_alloc() */
114 EXPORT_SYMBOL(vn_alloc);
115
116 void
117 vn_free(vnode_t *vp)
118 {
119 kmem_cache_free(vn_cache, vp);
120 } /* vn_free() */
121 EXPORT_SYMBOL(vn_free);
122
123 int
124 vn_open(const char *path, uio_seg_t seg, int flags, int mode,
125 vnode_t **vpp, int x1, void *x2)
126 {
127 struct file *fp;
128 struct kstat stat;
129 int rc, saved_umask = 0;
130 gfp_t saved_gfp;
131 vnode_t *vp;
132
133 ASSERT(flags & (FWRITE | FREAD));
134 ASSERT(seg == UIO_SYSSPACE);
135 ASSERT(vpp);
136 *vpp = NULL;
137
138 if (!(flags & FCREAT) && (flags & FWRITE))
139 flags |= FEXCL;
140
141 /* Note for filp_open() the two low bits must be remapped to mean:
142 * 01 - read-only -> 00 read-only
143 * 10 - write-only -> 01 write-only
144 * 11 - read-write -> 10 read-write
145 */
146 flags--;
147
148 if (flags & FCREAT)
149 saved_umask = xchg(&current->fs->umask, 0);
150
151 fp = filp_open(path, flags, mode);
152
153 if (flags & FCREAT)
154 (void)xchg(&current->fs->umask, saved_umask);
155
156 if (IS_ERR(fp))
157 return (-PTR_ERR(fp));
158
159 #if defined(HAVE_4ARGS_VFS_GETATTR)
160 rc = vfs_getattr(&fp->f_path, &stat, STATX_TYPE, AT_STATX_SYNC_AS_STAT);
161 #elif defined(HAVE_2ARGS_VFS_GETATTR)
162 rc = vfs_getattr(&fp->f_path, &stat);
163 #else
164 rc = vfs_getattr(fp->f_path.mnt, fp->f_dentry, &stat);
165 #endif
166 if (rc) {
167 filp_close(fp, 0);
168 return (-rc);
169 }
170
171 vp = vn_alloc(KM_SLEEP);
172 if (!vp) {
173 filp_close(fp, 0);
174 return (ENOMEM);
175 }
176
177 saved_gfp = mapping_gfp_mask(fp->f_mapping);
178 mapping_set_gfp_mask(fp->f_mapping, saved_gfp & ~(__GFP_IO|__GFP_FS));
179
180 mutex_enter(&vp->v_lock);
181 vp->v_type = vn_mode_to_vtype(stat.mode);
182 vp->v_file = fp;
183 vp->v_gfp_mask = saved_gfp;
184 *vpp = vp;
185 mutex_exit(&vp->v_lock);
186
187 return (0);
188 } /* vn_open() */
189 EXPORT_SYMBOL(vn_open);
190
191 int
192 vn_openat(const char *path, uio_seg_t seg, int flags, int mode,
193 vnode_t **vpp, int x1, void *x2, vnode_t *vp, int fd)
194 {
195 char *realpath;
196 int len, rc;
197
198 ASSERT(vp == rootdir);
199
200 len = strlen(path) + 2;
201 realpath = kmalloc(len, kmem_flags_convert(KM_SLEEP));
202 if (!realpath)
203 return (ENOMEM);
204
205 (void)snprintf(realpath, len, "/%s", path);
206 rc = vn_open(realpath, seg, flags, mode, vpp, x1, x2);
207 kfree(realpath);
208
209 return (rc);
210 } /* vn_openat() */
211 EXPORT_SYMBOL(vn_openat);
212
213 int
214 vn_rdwr(uio_rw_t uio, vnode_t *vp, void *addr, ssize_t len, offset_t off,
215 uio_seg_t seg, int ioflag, rlim64_t x2, void *x3, ssize_t *residp)
216 {
217 loff_t offset;
218 mm_segment_t saved_fs;
219 struct file *fp;
220 int rc;
221
222 ASSERT(uio == UIO_WRITE || uio == UIO_READ);
223 ASSERT(vp);
224 ASSERT(vp->v_file);
225 ASSERT(seg == UIO_SYSSPACE);
226 ASSERT((ioflag & ~FAPPEND) == 0);
227 ASSERT(x2 == RLIM64_INFINITY);
228
229 fp = vp->v_file;
230
231 offset = off;
232 if (ioflag & FAPPEND)
233 offset = fp->f_pos;
234
235 /* Writable user data segment must be briefly increased for this
236 * process so we can use the user space read call paths to write
237 * in to memory allocated by the kernel. */
238 saved_fs = get_fs();
239 set_fs(get_ds());
240
241 if (uio & UIO_WRITE)
242 rc = vfs_write(fp, addr, len, &offset);
243 else
244 rc = vfs_read(fp, addr, len, &offset);
245
246 set_fs(saved_fs);
247 fp->f_pos = offset;
248
249 if (rc < 0)
250 return (-rc);
251
252 if (residp) {
253 *residp = len - rc;
254 } else {
255 if (rc != len)
256 return (EIO);
257 }
258
259 return (0);
260 } /* vn_rdwr() */
261 EXPORT_SYMBOL(vn_rdwr);
262
263 int
264 vn_close(vnode_t *vp, int flags, int x1, int x2, void *x3, void *x4)
265 {
266 int rc;
267
268 ASSERT(vp);
269 ASSERT(vp->v_file);
270
271 mapping_set_gfp_mask(vp->v_file->f_mapping, vp->v_gfp_mask);
272 rc = filp_close(vp->v_file, 0);
273 vn_free(vp);
274
275 return (-rc);
276 } /* vn_close() */
277 EXPORT_SYMBOL(vn_close);
278
279 /* vn_seek() does not actually seek it only performs bounds checking on the
280 * proposed seek. We perform minimal checking and allow vn_rdwr() to catch
281 * anything more serious. */
282 int
283 vn_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, void *ct)
284 {
285 return ((*noffp < 0 || *noffp > MAXOFFSET_T) ? EINVAL : 0);
286 }
287 EXPORT_SYMBOL(vn_seek);
288
289 /*
290 * spl_basename() takes a NULL-terminated string s as input containing a path.
291 * It returns a char pointer to a string and a length that describe the
292 * basename of the path. If the basename is not "." or "/", it will be an index
293 * into the string. While the string should be NULL terminated, the section
294 * referring to the basename is not. spl_basename is dual-licensed GPLv2+ and
295 * CC0. Anyone wishing to reuse it in another codebase may pick either license.
296 */
297 static void
298 spl_basename(const char *s, const char **str, int *len)
299 {
300 size_t i, end;
301
302 ASSERT(str);
303 ASSERT(len);
304
305 if (!s || !*s) {
306 *str = ".";
307 *len = 1;
308 return;
309 }
310
311 i = strlen(s) - 1;
312
313 while (i && s[i--] == '/');
314
315 if (i == 0) {
316 *str = "/";
317 *len = 1;
318 return;
319 }
320
321 end = i;
322
323 for (end = i; i; i--) {
324 if (s[i] == '/') {
325 *str = &s[i+1];
326 *len = end - i + 1;
327 return;
328 }
329 }
330
331 *str = s;
332 *len = end + 1;
333 }
334
335 static struct dentry *
336 spl_kern_path_locked(const char *name, struct path *path)
337 {
338 struct path parent;
339 struct dentry *dentry;
340 const char *basename;
341 int len;
342 int rc;
343
344 ASSERT(name);
345 ASSERT(path);
346
347 spl_basename(name, &basename, &len);
348
349 /* We do not accept "." or ".." */
350 if (len <= 2 && basename[0] == '.')
351 if (len == 1 || basename[1] == '.')
352 return (ERR_PTR(-EACCES));
353
354 rc = kern_path(name, LOOKUP_PARENT, &parent);
355 if (rc)
356 return (ERR_PTR(rc));
357
358 /* use I_MUTEX_PARENT because vfs_unlink needs it */
359 spl_inode_lock_nested(parent.dentry->d_inode, I_MUTEX_PARENT);
360
361 dentry = lookup_one_len(basename, parent.dentry, len);
362 if (IS_ERR(dentry)) {
363 spl_inode_unlock(parent.dentry->d_inode);
364 path_put(&parent);
365 } else {
366 *path = parent;
367 }
368
369 return (dentry);
370 }
371
372 /* Based on do_unlinkat() from linux/fs/namei.c */
373 int
374 vn_remove(const char *path, uio_seg_t seg, int flags)
375 {
376 struct dentry *dentry;
377 struct path parent;
378 struct inode *inode = NULL;
379 int rc = 0;
380
381 ASSERT(seg == UIO_SYSSPACE);
382 ASSERT(flags == RMFILE);
383
384 dentry = spl_kern_path_locked(path, &parent);
385 rc = PTR_ERR(dentry);
386 if (!IS_ERR(dentry)) {
387 if (parent.dentry->d_name.name[parent.dentry->d_name.len]) {
388 rc = 0;
389 goto slashes;
390 }
391
392 inode = dentry->d_inode;
393 if (inode) {
394 atomic_inc(&inode->i_count);
395 } else {
396 rc = 0;
397 goto slashes;
398 }
399
400 #ifdef HAVE_2ARGS_VFS_UNLINK
401 rc = vfs_unlink(parent.dentry->d_inode, dentry);
402 #else
403 rc = vfs_unlink(parent.dentry->d_inode, dentry, NULL);
404 #endif /* HAVE_2ARGS_VFS_UNLINK */
405 exit1:
406 dput(dentry);
407 } else {
408 return (-rc);
409 }
410
411 spl_inode_unlock(parent.dentry->d_inode);
412 if (inode)
413 iput(inode); /* truncate the inode here */
414
415 path_put(&parent);
416 return (-rc);
417
418 slashes:
419 rc = !dentry->d_inode ? -ENOENT :
420 S_ISDIR(dentry->d_inode->i_mode) ? -EISDIR : -ENOTDIR;
421 goto exit1;
422 } /* vn_remove() */
423 EXPORT_SYMBOL(vn_remove);
424
425 /* Based on do_rename() from linux/fs/namei.c */
426 int
427 vn_rename(const char *oldname, const char *newname, int x1)
428 {
429 struct dentry *old_dir, *new_dir;
430 struct dentry *old_dentry, *new_dentry;
431 struct dentry *trap;
432 struct path old_parent, new_parent;
433 int rc = 0;
434
435 old_dentry = spl_kern_path_locked(oldname, &old_parent);
436 if (IS_ERR(old_dentry)) {
437 rc = PTR_ERR(old_dentry);
438 goto exit;
439 }
440
441 spl_inode_unlock(old_parent.dentry->d_inode);
442
443 new_dentry = spl_kern_path_locked(newname, &new_parent);
444 if (IS_ERR(new_dentry)) {
445 rc = PTR_ERR(new_dentry);
446 goto exit2;
447 }
448
449 spl_inode_unlock(new_parent.dentry->d_inode);
450
451 rc = -EXDEV;
452 if (old_parent.mnt != new_parent.mnt)
453 goto exit3;
454
455 old_dir = old_parent.dentry;
456 new_dir = new_parent.dentry;
457 trap = lock_rename(new_dir, old_dir);
458
459 /* source should not be ancestor of target */
460 rc = -EINVAL;
461 if (old_dentry == trap)
462 goto exit4;
463
464 /* target should not be an ancestor of source */
465 rc = -ENOTEMPTY;
466 if (new_dentry == trap)
467 goto exit4;
468
469 /* source must exist */
470 rc = -ENOENT;
471 if (!old_dentry->d_inode)
472 goto exit4;
473
474 /* unless the source is a directory trailing slashes give -ENOTDIR */
475 if (!S_ISDIR(old_dentry->d_inode->i_mode)) {
476 rc = -ENOTDIR;
477 if (old_dentry->d_name.name[old_dentry->d_name.len])
478 goto exit4;
479 if (new_dentry->d_name.name[new_dentry->d_name.len])
480 goto exit4;
481 }
482
483 #if defined(HAVE_4ARGS_VFS_RENAME)
484 rc = vfs_rename(old_dir->d_inode, old_dentry,
485 new_dir->d_inode, new_dentry);
486 #elif defined(HAVE_5ARGS_VFS_RENAME)
487 rc = vfs_rename(old_dir->d_inode, old_dentry,
488 new_dir->d_inode, new_dentry, NULL);
489 #else
490 rc = vfs_rename(old_dir->d_inode, old_dentry,
491 new_dir->d_inode, new_dentry, NULL, 0);
492 #endif
493 exit4:
494 unlock_rename(new_dir, old_dir);
495 exit3:
496 dput(new_dentry);
497 path_put(&new_parent);
498 exit2:
499 dput(old_dentry);
500 path_put(&old_parent);
501 exit:
502 return (-rc);
503 }
504 EXPORT_SYMBOL(vn_rename);
505
506 int
507 vn_getattr(vnode_t *vp, vattr_t *vap, int flags, void *x3, void *x4)
508 {
509 struct file *fp;
510 struct kstat stat;
511 int rc;
512
513 ASSERT(vp);
514 ASSERT(vp->v_file);
515 ASSERT(vap);
516
517 fp = vp->v_file;
518
519 #if defined(HAVE_4ARGS_VFS_GETATTR)
520 rc = vfs_getattr(&fp->f_path, &stat, STATX_BASIC_STATS,
521 AT_STATX_SYNC_AS_STAT);
522 #elif defined(HAVE_2ARGS_VFS_GETATTR)
523 rc = vfs_getattr(&fp->f_path, &stat);
524 #else
525 rc = vfs_getattr(fp->f_path.mnt, fp->f_dentry, &stat);
526 #endif
527 if (rc)
528 return (-rc);
529
530 vap->va_type = vn_mode_to_vtype(stat.mode);
531 vap->va_mode = stat.mode;
532 vap->va_uid = KUID_TO_SUID(stat.uid);
533 vap->va_gid = KGID_TO_SGID(stat.gid);
534 vap->va_fsid = 0;
535 vap->va_nodeid = stat.ino;
536 vap->va_nlink = stat.nlink;
537 vap->va_size = stat.size;
538 vap->va_blksize = stat.blksize;
539 vap->va_atime = stat.atime;
540 vap->va_mtime = stat.mtime;
541 vap->va_ctime = stat.ctime;
542 vap->va_rdev = stat.rdev;
543 vap->va_nblocks = stat.blocks;
544
545 return (0);
546 }
547 EXPORT_SYMBOL(vn_getattr);
548
549 int vn_fsync(vnode_t *vp, int flags, void *x3, void *x4)
550 {
551 int datasync = 0;
552 int error;
553 int fstrans;
554
555 ASSERT(vp);
556 ASSERT(vp->v_file);
557
558 if (flags & FDSYNC)
559 datasync = 1;
560
561 /*
562 * May enter XFS which generates a warning when PF_FSTRANS is set.
563 * To avoid this the flag is cleared over vfs_sync() and then reset.
564 */
565 fstrans = __spl_pf_fstrans_check();
566 if (fstrans)
567 current->flags &= ~(__SPL_PF_FSTRANS);
568
569 error = -spl_filp_fsync(vp->v_file, datasync);
570 if (fstrans)
571 current->flags |= __SPL_PF_FSTRANS;
572
573 return (error);
574 } /* vn_fsync() */
575 EXPORT_SYMBOL(vn_fsync);
576
577 int vn_space(vnode_t *vp, int cmd, struct flock *bfp, int flag,
578 offset_t offset, void *x6, void *x7)
579 {
580 int error = EOPNOTSUPP;
581 #ifdef FALLOC_FL_PUNCH_HOLE
582 int fstrans;
583 #endif
584
585 if (cmd != F_FREESP || bfp->l_whence != 0)
586 return (EOPNOTSUPP);
587
588 ASSERT(vp);
589 ASSERT(vp->v_file);
590 ASSERT(bfp->l_start >= 0 && bfp->l_len > 0);
591
592 #ifdef FALLOC_FL_PUNCH_HOLE
593 /*
594 * May enter XFS which generates a warning when PF_FSTRANS is set.
595 * To avoid this the flag is cleared over vfs_sync() and then reset.
596 */
597 fstrans = __spl_pf_fstrans_check();
598 if (fstrans)
599 current->flags &= ~(__SPL_PF_FSTRANS);
600
601 /*
602 * When supported by the underlying file system preferentially
603 * use the fallocate() callback to preallocate the space.
604 */
605 error = -spl_filp_fallocate(vp->v_file,
606 FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
607 bfp->l_start, bfp->l_len);
608
609 if (fstrans)
610 current->flags |= __SPL_PF_FSTRANS;
611
612 if (error == 0)
613 return (0);
614 #endif
615
616 #ifdef HAVE_INODE_TRUNCATE_RANGE
617 if (vp->v_file->f_dentry && vp->v_file->f_dentry->d_inode &&
618 vp->v_file->f_dentry->d_inode->i_op &&
619 vp->v_file->f_dentry->d_inode->i_op->truncate_range) {
620 off_t end = bfp->l_start + bfp->l_len;
621 /*
622 * Judging from the code in shmem_truncate_range(),
623 * it seems the kernel expects the end offset to be
624 * inclusive and aligned to the end of a page.
625 */
626 if (end % PAGE_SIZE != 0) {
627 end &= ~(off_t)(PAGE_SIZE - 1);
628 if (end <= bfp->l_start)
629 return (0);
630 }
631 --end;
632
633 vp->v_file->f_dentry->d_inode->i_op->truncate_range(
634 vp->v_file->f_dentry->d_inode,
635 bfp->l_start, end
636 );
637 return (0);
638 }
639 #endif
640
641 return (error);
642 }
643 EXPORT_SYMBOL(vn_space);
644
645 /* Function must be called while holding the vn_file_lock */
646 static file_t *
647 file_find(int fd, struct task_struct *task)
648 {
649 file_t *fp;
650
651 ASSERT(spin_is_locked(&vn_file_lock));
652
653 list_for_each_entry(fp, &vn_file_list, f_list) {
654 if (fd == fp->f_fd && fp->f_task == task) {
655 ASSERT(atomic_read(&fp->f_ref) != 0);
656 return fp;
657 }
658 }
659
660 return NULL;
661 } /* file_find() */
662
663 file_t *
664 vn_getf(int fd)
665 {
666 struct kstat stat;
667 struct file *lfp;
668 file_t *fp;
669 vnode_t *vp;
670 int rc = 0;
671
672 if (fd < 0)
673 return (NULL);
674
675 /* Already open just take an extra reference */
676 spin_lock(&vn_file_lock);
677
678 fp = file_find(fd, current);
679 if (fp) {
680 atomic_inc(&fp->f_ref);
681 spin_unlock(&vn_file_lock);
682 return (fp);
683 }
684
685 spin_unlock(&vn_file_lock);
686
687 /* File was not yet opened create the object and setup */
688 fp = kmem_cache_alloc(vn_file_cache, KM_SLEEP);
689 if (fp == NULL)
690 goto out;
691
692 mutex_enter(&fp->f_lock);
693
694 fp->f_fd = fd;
695 fp->f_task = current;
696 fp->f_offset = 0;
697 atomic_inc(&fp->f_ref);
698
699 lfp = fget(fd);
700 if (lfp == NULL)
701 goto out_mutex;
702
703 vp = vn_alloc(KM_SLEEP);
704 if (vp == NULL)
705 goto out_fget;
706
707 #if defined(HAVE_4ARGS_VFS_GETATTR)
708 rc = vfs_getattr(&lfp->f_path, &stat, STATX_TYPE, AT_STATX_SYNC_AS_STAT);
709 #elif defined(HAVE_2ARGS_VFS_GETATTR)
710 rc = vfs_getattr(&lfp->f_path, &stat);
711 #else
712 rc = vfs_getattr(lfp->f_path.mnt, lfp->f_dentry, &stat);
713 #endif
714 if (rc)
715 goto out_vnode;
716
717 mutex_enter(&vp->v_lock);
718 vp->v_type = vn_mode_to_vtype(stat.mode);
719 vp->v_file = lfp;
720 mutex_exit(&vp->v_lock);
721
722 fp->f_vnode = vp;
723 fp->f_file = lfp;
724
725 /* Put it on the tracking list */
726 spin_lock(&vn_file_lock);
727 list_add(&fp->f_list, &vn_file_list);
728 spin_unlock(&vn_file_lock);
729
730 mutex_exit(&fp->f_lock);
731 return (fp);
732
733 out_vnode:
734 vn_free(vp);
735 out_fget:
736 fput(lfp);
737 out_mutex:
738 mutex_exit(&fp->f_lock);
739 kmem_cache_free(vn_file_cache, fp);
740 out:
741 return (NULL);
742 } /* getf() */
743 EXPORT_SYMBOL(getf);
744
745 static void releasef_locked(file_t *fp)
746 {
747 ASSERT(fp->f_file);
748 ASSERT(fp->f_vnode);
749
750 /* Unlinked from list, no refs, safe to free outside mutex */
751 fput(fp->f_file);
752 vn_free(fp->f_vnode);
753
754 kmem_cache_free(vn_file_cache, fp);
755 }
756
757 void
758 vn_releasef(int fd)
759 {
760 areleasef(fd, P_FINFO(current));
761 }
762 EXPORT_SYMBOL(releasef);
763
764 void
765 vn_areleasef(int fd, uf_info_t *fip)
766 {
767 file_t *fp;
768 struct task_struct *task = (struct task_struct *)fip;
769
770 if (fd < 0)
771 return;
772
773 spin_lock(&vn_file_lock);
774 fp = file_find(fd, task);
775 if (fp) {
776 atomic_dec(&fp->f_ref);
777 if (atomic_read(&fp->f_ref) > 0) {
778 spin_unlock(&vn_file_lock);
779 return;
780 }
781
782 list_del(&fp->f_list);
783 releasef_locked(fp);
784 }
785 spin_unlock(&vn_file_lock);
786
787 return;
788 } /* releasef() */
789 EXPORT_SYMBOL(areleasef);
790
791
792 static void
793 #ifdef HAVE_SET_FS_PWD_WITH_CONST
794 vn_set_fs_pwd(struct fs_struct *fs, const struct path *path)
795 #else
796 vn_set_fs_pwd(struct fs_struct *fs, struct path *path)
797 #endif /* HAVE_SET_FS_PWD_WITH_CONST */
798 {
799 struct path old_pwd;
800
801 #ifdef HAVE_FS_STRUCT_SPINLOCK
802 spin_lock(&fs->lock);
803 old_pwd = fs->pwd;
804 fs->pwd = *path;
805 path_get(path);
806 spin_unlock(&fs->lock);
807 #else
808 write_lock(&fs->lock);
809 old_pwd = fs->pwd;
810 fs->pwd = *path;
811 path_get(path);
812 write_unlock(&fs->lock);
813 #endif /* HAVE_FS_STRUCT_SPINLOCK */
814
815 if (old_pwd.dentry)
816 path_put(&old_pwd);
817 }
818
819 int
820 vn_set_pwd(const char *filename)
821 {
822 struct path path;
823 mm_segment_t saved_fs;
824 int rc;
825
826 /*
827 * user_path_dir() and __user_walk() both expect 'filename' to be
828 * a user space address so we must briefly increase the data segment
829 * size to ensure strncpy_from_user() does not fail with -EFAULT.
830 */
831 saved_fs = get_fs();
832 set_fs(get_ds());
833
834 rc = user_path_dir(filename, &path);
835 if (rc)
836 goto out;
837
838 rc = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS);
839 if (rc)
840 goto dput_and_out;
841
842 vn_set_fs_pwd(current->fs, &path);
843
844 dput_and_out:
845 path_put(&path);
846 out:
847 set_fs(saved_fs);
848
849 return (-rc);
850 } /* vn_set_pwd() */
851 EXPORT_SYMBOL(vn_set_pwd);
852
853 static int
854 vn_cache_constructor(void *buf, void *cdrarg, int kmflags)
855 {
856 struct vnode *vp = buf;
857
858 mutex_init(&vp->v_lock, NULL, MUTEX_DEFAULT, NULL);
859
860 return (0);
861 } /* vn_cache_constructor() */
862
863 static void
864 vn_cache_destructor(void *buf, void *cdrarg)
865 {
866 struct vnode *vp = buf;
867
868 mutex_destroy(&vp->v_lock);
869 } /* vn_cache_destructor() */
870
871 static int
872 vn_file_cache_constructor(void *buf, void *cdrarg, int kmflags)
873 {
874 file_t *fp = buf;
875
876 atomic_set(&fp->f_ref, 0);
877 mutex_init(&fp->f_lock, NULL, MUTEX_DEFAULT, NULL);
878 INIT_LIST_HEAD(&fp->f_list);
879
880 return (0);
881 } /* file_cache_constructor() */
882
883 static void
884 vn_file_cache_destructor(void *buf, void *cdrarg)
885 {
886 file_t *fp = buf;
887
888 mutex_destroy(&fp->f_lock);
889 } /* vn_file_cache_destructor() */
890
891 int
892 spl_vn_init(void)
893 {
894 vn_cache = kmem_cache_create("spl_vn_cache",
895 sizeof(struct vnode), 64,
896 vn_cache_constructor,
897 vn_cache_destructor,
898 NULL, NULL, NULL, 0);
899
900 vn_file_cache = kmem_cache_create("spl_vn_file_cache",
901 sizeof(file_t), 64,
902 vn_file_cache_constructor,
903 vn_file_cache_destructor,
904 NULL, NULL, NULL, 0);
905 return (0);
906 } /* vn_init() */
907
908 void
909 spl_vn_fini(void)
910 {
911 file_t *fp, *next_fp;
912 int leaked = 0;
913
914 spin_lock(&vn_file_lock);
915
916 list_for_each_entry_safe(fp, next_fp, &vn_file_list, f_list) {
917 list_del(&fp->f_list);
918 releasef_locked(fp);
919 leaked++;
920 }
921
922 spin_unlock(&vn_file_lock);
923
924 if (leaked > 0)
925 printk(KERN_WARNING "WARNING: %d vnode files leaked\n", leaked);
926
927 kmem_cache_destroy(vn_file_cache);
928 kmem_cache_destroy(vn_cache);
929
930 return;
931 } /* vn_fini() */