]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - spl/module/spl/spl-vnode.c
UBUNTU: SAUCE: (noup) Update spl to 0.6.5.9-1ubuntu2, zfs to 0.6.5.9-5ubuntu7
[mirror_ubuntu-artful-kernel.git] / spl / 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
582 if (cmd != F_FREESP || bfp->l_whence != 0)
583 return (EOPNOTSUPP);
584
585 ASSERT(vp);
586 ASSERT(vp->v_file);
587 ASSERT(bfp->l_start >= 0 && bfp->l_len > 0);
588
589 #ifdef FALLOC_FL_PUNCH_HOLE
590 /*
591 * When supported by the underlying file system preferentially
592 * use the fallocate() callback to preallocate the space.
593 */
594 error = -spl_filp_fallocate(vp->v_file,
595 FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
596 bfp->l_start, bfp->l_len);
597 if (error == 0)
598 return (0);
599 #endif
600
601 #ifdef HAVE_INODE_TRUNCATE_RANGE
602 if (vp->v_file->f_dentry && vp->v_file->f_dentry->d_inode &&
603 vp->v_file->f_dentry->d_inode->i_op &&
604 vp->v_file->f_dentry->d_inode->i_op->truncate_range) {
605 off_t end = bfp->l_start + bfp->l_len;
606 /*
607 * Judging from the code in shmem_truncate_range(),
608 * it seems the kernel expects the end offset to be
609 * inclusive and aligned to the end of a page.
610 */
611 if (end % PAGE_SIZE != 0) {
612 end &= ~(off_t)(PAGE_SIZE - 1);
613 if (end <= bfp->l_start)
614 return (0);
615 }
616 --end;
617
618 vp->v_file->f_dentry->d_inode->i_op->truncate_range(
619 vp->v_file->f_dentry->d_inode,
620 bfp->l_start, end
621 );
622 return (0);
623 }
624 #endif
625
626 return (error);
627 }
628 EXPORT_SYMBOL(vn_space);
629
630 /* Function must be called while holding the vn_file_lock */
631 static file_t *
632 file_find(int fd, struct task_struct *task)
633 {
634 file_t *fp;
635
636 ASSERT(spin_is_locked(&vn_file_lock));
637
638 list_for_each_entry(fp, &vn_file_list, f_list) {
639 if (fd == fp->f_fd && fp->f_task == task) {
640 ASSERT(atomic_read(&fp->f_ref) != 0);
641 return fp;
642 }
643 }
644
645 return NULL;
646 } /* file_find() */
647
648 file_t *
649 vn_getf(int fd)
650 {
651 struct kstat stat;
652 struct file *lfp;
653 file_t *fp;
654 vnode_t *vp;
655 int rc = 0;
656
657 if (fd < 0)
658 return (NULL);
659
660 /* Already open just take an extra reference */
661 spin_lock(&vn_file_lock);
662
663 fp = file_find(fd, current);
664 if (fp) {
665 atomic_inc(&fp->f_ref);
666 spin_unlock(&vn_file_lock);
667 return (fp);
668 }
669
670 spin_unlock(&vn_file_lock);
671
672 /* File was not yet opened create the object and setup */
673 fp = kmem_cache_alloc(vn_file_cache, KM_SLEEP);
674 if (fp == NULL)
675 goto out;
676
677 mutex_enter(&fp->f_lock);
678
679 fp->f_fd = fd;
680 fp->f_task = current;
681 fp->f_offset = 0;
682 atomic_inc(&fp->f_ref);
683
684 lfp = fget(fd);
685 if (lfp == NULL)
686 goto out_mutex;
687
688 vp = vn_alloc(KM_SLEEP);
689 if (vp == NULL)
690 goto out_fget;
691
692 #if defined(HAVE_4ARGS_VFS_GETATTR)
693 rc = vfs_getattr(&lfp->f_path, &stat, STATX_TYPE, AT_STATX_SYNC_AS_STAT);
694 #elif defined(HAVE_2ARGS_VFS_GETATTR)
695 rc = vfs_getattr(&lfp->f_path, &stat);
696 #else
697 rc = vfs_getattr(lfp->f_path.mnt, lfp->f_dentry, &stat);
698 #endif
699 if (rc)
700 goto out_vnode;
701
702 mutex_enter(&vp->v_lock);
703 vp->v_type = vn_mode_to_vtype(stat.mode);
704 vp->v_file = lfp;
705 mutex_exit(&vp->v_lock);
706
707 fp->f_vnode = vp;
708 fp->f_file = lfp;
709
710 /* Put it on the tracking list */
711 spin_lock(&vn_file_lock);
712 list_add(&fp->f_list, &vn_file_list);
713 spin_unlock(&vn_file_lock);
714
715 mutex_exit(&fp->f_lock);
716 return (fp);
717
718 out_vnode:
719 vn_free(vp);
720 out_fget:
721 fput(lfp);
722 out_mutex:
723 mutex_exit(&fp->f_lock);
724 kmem_cache_free(vn_file_cache, fp);
725 out:
726 return (NULL);
727 } /* getf() */
728 EXPORT_SYMBOL(getf);
729
730 static void releasef_locked(file_t *fp)
731 {
732 ASSERT(fp->f_file);
733 ASSERT(fp->f_vnode);
734
735 /* Unlinked from list, no refs, safe to free outside mutex */
736 fput(fp->f_file);
737 vn_free(fp->f_vnode);
738
739 kmem_cache_free(vn_file_cache, fp);
740 }
741
742 void
743 vn_releasef(int fd)
744 {
745 areleasef(fd, P_FINFO(current));
746 }
747 EXPORT_SYMBOL(releasef);
748
749 void
750 vn_areleasef(int fd, uf_info_t *fip)
751 {
752 file_t *fp;
753 struct task_struct *task = (struct task_struct *)fip;
754
755 if (fd < 0)
756 return;
757
758 spin_lock(&vn_file_lock);
759 fp = file_find(fd, task);
760 if (fp) {
761 atomic_dec(&fp->f_ref);
762 if (atomic_read(&fp->f_ref) > 0) {
763 spin_unlock(&vn_file_lock);
764 return;
765 }
766
767 list_del(&fp->f_list);
768 releasef_locked(fp);
769 }
770 spin_unlock(&vn_file_lock);
771
772 return;
773 } /* releasef() */
774 EXPORT_SYMBOL(areleasef);
775
776
777 static void
778 #ifdef HAVE_SET_FS_PWD_WITH_CONST
779 vn_set_fs_pwd(struct fs_struct *fs, const struct path *path)
780 #else
781 vn_set_fs_pwd(struct fs_struct *fs, struct path *path)
782 #endif /* HAVE_SET_FS_PWD_WITH_CONST */
783 {
784 struct path old_pwd;
785
786 #ifdef HAVE_FS_STRUCT_SPINLOCK
787 spin_lock(&fs->lock);
788 old_pwd = fs->pwd;
789 fs->pwd = *path;
790 path_get(path);
791 spin_unlock(&fs->lock);
792 #else
793 write_lock(&fs->lock);
794 old_pwd = fs->pwd;
795 fs->pwd = *path;
796 path_get(path);
797 write_unlock(&fs->lock);
798 #endif /* HAVE_FS_STRUCT_SPINLOCK */
799
800 if (old_pwd.dentry)
801 path_put(&old_pwd);
802 }
803
804 int
805 vn_set_pwd(const char *filename)
806 {
807 struct path path;
808 mm_segment_t saved_fs;
809 int rc;
810
811 /*
812 * user_path_dir() and __user_walk() both expect 'filename' to be
813 * a user space address so we must briefly increase the data segment
814 * size to ensure strncpy_from_user() does not fail with -EFAULT.
815 */
816 saved_fs = get_fs();
817 set_fs(get_ds());
818
819 rc = user_path_dir(filename, &path);
820 if (rc)
821 goto out;
822
823 rc = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS);
824 if (rc)
825 goto dput_and_out;
826
827 vn_set_fs_pwd(current->fs, &path);
828
829 dput_and_out:
830 path_put(&path);
831 out:
832 set_fs(saved_fs);
833
834 return (-rc);
835 } /* vn_set_pwd() */
836 EXPORT_SYMBOL(vn_set_pwd);
837
838 static int
839 vn_cache_constructor(void *buf, void *cdrarg, int kmflags)
840 {
841 struct vnode *vp = buf;
842
843 mutex_init(&vp->v_lock, NULL, MUTEX_DEFAULT, NULL);
844
845 return (0);
846 } /* vn_cache_constructor() */
847
848 static void
849 vn_cache_destructor(void *buf, void *cdrarg)
850 {
851 struct vnode *vp = buf;
852
853 mutex_destroy(&vp->v_lock);
854 } /* vn_cache_destructor() */
855
856 static int
857 vn_file_cache_constructor(void *buf, void *cdrarg, int kmflags)
858 {
859 file_t *fp = buf;
860
861 atomic_set(&fp->f_ref, 0);
862 mutex_init(&fp->f_lock, NULL, MUTEX_DEFAULT, NULL);
863 INIT_LIST_HEAD(&fp->f_list);
864
865 return (0);
866 } /* file_cache_constructor() */
867
868 static void
869 vn_file_cache_destructor(void *buf, void *cdrarg)
870 {
871 file_t *fp = buf;
872
873 mutex_destroy(&fp->f_lock);
874 } /* vn_file_cache_destructor() */
875
876 int
877 spl_vn_init(void)
878 {
879 vn_cache = kmem_cache_create("spl_vn_cache",
880 sizeof(struct vnode), 64,
881 vn_cache_constructor,
882 vn_cache_destructor,
883 NULL, NULL, NULL, 0);
884
885 vn_file_cache = kmem_cache_create("spl_vn_file_cache",
886 sizeof(file_t), 64,
887 vn_file_cache_constructor,
888 vn_file_cache_destructor,
889 NULL, NULL, NULL, 0);
890 return (0);
891 } /* vn_init() */
892
893 void
894 spl_vn_fini(void)
895 {
896 file_t *fp, *next_fp;
897 int leaked = 0;
898
899 spin_lock(&vn_file_lock);
900
901 list_for_each_entry_safe(fp, next_fp, &vn_file_list, f_list) {
902 list_del(&fp->f_list);
903 releasef_locked(fp);
904 leaked++;
905 }
906
907 spin_unlock(&vn_file_lock);
908
909 if (leaked > 0)
910 printk(KERN_WARNING "WARNING: %d vnode files leaked\n", leaked);
911
912 kmem_cache_destroy(vn_file_cache);
913 kmem_cache_destroy(vn_cache);
914
915 return;
916 } /* vn_fini() */