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