]> git.proxmox.com Git - mirror_spl.git/blame - module/spl/spl-vnode.c
Fix function name typos
[mirror_spl.git] / module / spl / spl-vnode.c
CommitLineData
4b393c50 1/*
716154c5
BB
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>.
715f6251 6 * UCRL-CODE-235197
7 *
716154c5 8 * This file is part of the SPL, Solaris Porting Layer.
3d6af2dd 9 * For details, see <http://zfsonlinux.org/>.
716154c5
BB
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.
715f6251 15 *
716154c5 16 * The SPL is distributed in the hope that it will be useful, but WITHOUT
715f6251 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
716154c5 22 * with the SPL. If not, see <http://www.gnu.org/licenses/>.
5461eefe 23 *
716154c5 24 * Solaris Porting Layer (SPL) Vnode Implementation.
4b393c50 25 */
715f6251 26
f7fd6ddd 27#include <sys/cred.h>
4b171585 28#include <sys/vnode.h>
e5b9b344 29#include <sys/kmem_cache.h>
bbdc6ae4 30#include <linux/falloc.h>
52479ecf 31#include <linux/file_compat.h>
937879f1 32
51a727e9 33vnode_t *rootdir = (vnode_t *)0xabcd1234;
4b171585 34EXPORT_SYMBOL(rootdir);
35
7afde631 36static spl_kmem_cache_t *vn_cache;
37static spl_kmem_cache_t *vn_file_cache;
e4f1d29f 38
83c623aa 39static DEFINE_SPINLOCK(vn_file_lock);
e4f1d29f 40static LIST_HEAD(vn_file_list);
af828292 41
4295b530
BB
42vtype_t
43vn_mode_to_vtype(mode_t mode)
4b171585 44{
45 if (S_ISREG(mode))
5461eefe 46 return (VREG);
4b171585 47
48 if (S_ISDIR(mode))
5461eefe 49 return (VDIR);
4b171585 50
51 if (S_ISCHR(mode))
5461eefe 52 return (VCHR);
4b171585 53
54 if (S_ISBLK(mode))
5461eefe 55 return (VBLK);
4b171585 56
57 if (S_ISFIFO(mode))
5461eefe 58 return (VFIFO);
4b171585 59
60 if (S_ISLNK(mode))
5461eefe 61 return (VLNK);
4b171585 62
63 if (S_ISSOCK(mode))
5461eefe 64 return (VSOCK);
4b171585 65
5461eefe 66 return (VNON);
4295b530
BB
67} /* vn_mode_to_vtype() */
68EXPORT_SYMBOL(vn_mode_to_vtype);
69
70mode_t
71vn_vtype_to_mode(vtype_t vtype)
72{
73 if (vtype == VREG)
5461eefe 74 return (S_IFREG);
4295b530
BB
75
76 if (vtype == VDIR)
5461eefe 77 return (S_IFDIR);
4295b530
BB
78
79 if (vtype == VCHR)
5461eefe 80 return (S_IFCHR);
4295b530
BB
81
82 if (vtype == VBLK)
5461eefe 83 return (S_IFBLK);
4295b530
BB
84
85 if (vtype == VFIFO)
5461eefe 86 return (S_IFIFO);
4295b530
BB
87
88 if (vtype == VLNK)
5461eefe 89 return (S_IFLNK);
4295b530
BB
90
91 if (vtype == VSOCK)
5461eefe 92 return (S_IFSOCK);
4295b530 93
5461eefe 94 return (VNON);
4295b530
BB
95} /* vn_vtype_to_mode() */
96EXPORT_SYMBOL(vn_vtype_to_mode);
4b171585 97
af828292 98vnode_t *
99vn_alloc(int flag)
100{
101 vnode_t *vp;
102
103 vp = kmem_cache_alloc(vn_cache, flag);
af828292 104 if (vp != NULL) {
e4f1d29f 105 vp->v_file = NULL;
af828292 106 vp->v_type = 0;
107 }
108
8d9a23e8 109 return (vp);
af828292 110} /* vn_alloc() */
111EXPORT_SYMBOL(vn_alloc);
112
113void
114vn_free(vnode_t *vp)
115{
116 kmem_cache_free(vn_cache, vp);
117} /* vn_free() */
118EXPORT_SYMBOL(vn_free);
119
0b3cf046 120int
af828292 121vn_open(const char *path, uio_seg_t seg, int flags, int mode,
4b171585 122 vnode_t **vpp, int x1, void *x2)
0b3cf046 123{
f7e8739c
RC
124 struct file *fp;
125 struct kstat stat;
126 int rc, saved_umask = 0;
4be55565 127 gfp_t saved_gfp;
0b3cf046 128 vnode_t *vp;
0b3cf046 129
937879f1 130 ASSERT(flags & (FWRITE | FREAD));
131 ASSERT(seg == UIO_SYSSPACE);
132 ASSERT(vpp);
4b171585 133 *vpp = NULL;
134
135 if (!(flags & FCREAT) && (flags & FWRITE))
136 flags |= FEXCL;
137
5461eefe
BB
138 /*
139 * Note for filp_open() the two low bits must be remapped to mean:
728b9dd8 140 * 01 - read-only -> 00 read-only
141 * 10 - write-only -> 01 write-only
142 * 11 - read-write -> 10 read-write
143 */
144 flags--;
0b3cf046 145
146 if (flags & FCREAT)
4b171585 147 saved_umask = xchg(&current->fs->umask, 0);
0b3cf046 148
f7e8739c 149 fp = filp_open(path, flags, mode);
0b3cf046 150
151 if (flags & FCREAT)
5461eefe 152 (void) xchg(&current->fs->umask, saved_umask);
0b3cf046 153
f7e8739c 154 if (IS_ERR(fp))
8d9a23e8 155 return (-PTR_ERR(fp));
0b3cf046 156
94b1ab2a
OF
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)
2a305c34
RY
160 rc = vfs_getattr(&fp->f_path, &stat);
161#else
bc90df66 162 rc = vfs_getattr(fp->f_path.mnt, fp->f_dentry, &stat);
2a305c34 163#endif
4b171585 164 if (rc) {
165 filp_close(fp, 0);
8d9a23e8 166 return (-rc);
0b3cf046 167 }
168
af828292 169 vp = vn_alloc(KM_SLEEP);
4b171585 170 if (!vp) {
171 filp_close(fp, 0);
8d9a23e8 172 return (ENOMEM);
4b171585 173 }
0b3cf046 174
4be55565
LW
175 saved_gfp = mapping_gfp_mask(fp->f_mapping);
176 mapping_set_gfp_mask(fp->f_mapping, saved_gfp & ~(__GFP_IO|__GFP_FS));
177
e4f1d29f 178 mutex_enter(&vp->v_lock);
4295b530 179 vp->v_type = vn_mode_to_vtype(stat.mode);
e4f1d29f 180 vp->v_file = fp;
4be55565 181 vp->v_gfp_mask = saved_gfp;
4b171585 182 *vpp = vp;
e4f1d29f 183 mutex_exit(&vp->v_lock);
0b3cf046 184
8d9a23e8 185 return (0);
4b171585 186} /* vn_open() */
187EXPORT_SYMBOL(vn_open);
0b3cf046 188
0b3cf046 189int
af828292 190vn_openat(const char *path, uio_seg_t seg, int flags, int mode,
5461eefe 191 vnode_t **vpp, int x1, void *x2, vnode_t *vp, int fd)
0b3cf046 192{
4b171585 193 char *realpath;
12018327 194 int len, rc;
0b3cf046 195
937879f1 196 ASSERT(vp == rootdir);
0b3cf046 197
12018327 198 len = strlen(path) + 2;
54cccfc2 199 realpath = kmalloc(len, kmem_flags_convert(KM_SLEEP));
4b171585 200 if (!realpath)
8d9a23e8 201 return (ENOMEM);
0b3cf046 202
5461eefe 203 (void) snprintf(realpath, len, "/%s", path);
4b171585 204 rc = vn_open(realpath, seg, flags, mode, vpp, x1, x2);
4b171585 205 kfree(realpath);
206
8d9a23e8 207 return (rc);
4b171585 208} /* vn_openat() */
209EXPORT_SYMBOL(vn_openat);
0b3cf046 210
0b3cf046 211int
4b171585 212vn_rdwr(uio_rw_t uio, vnode_t *vp, void *addr, ssize_t len, offset_t off,
663e02a1 213 uio_seg_t seg, int ioflag, rlim64_t x2, void *x3, ssize_t *residp)
0b3cf046 214{
ed19bccf
BB
215 struct file *fp = vp->v_file;
216 loff_t offset = off;
4b171585 217 int rc;
218
937879f1 219 ASSERT(uio == UIO_WRITE || uio == UIO_READ);
937879f1 220 ASSERT(seg == UIO_SYSSPACE);
663e02a1 221 ASSERT((ioflag & ~FAPPEND) == 0);
4b171585 222
663e02a1
RC
223 if (ioflag & FAPPEND)
224 offset = fp->f_pos;
225
4b171585 226 if (uio & UIO_WRITE)
ed19bccf 227 rc = spl_kernel_write(fp, addr, len, &offset);
4b171585 228 else
ed19bccf 229 rc = spl_kernel_read(fp, addr, len, &offset);
4b171585 230
f3989ed3 231 fp->f_pos = offset;
4b171585 232
233 if (rc < 0)
8d9a23e8 234 return (-rc);
0b3cf046 235
4b171585 236 if (residp) {
237 *residp = len - rc;
0b3cf046 238 } else {
4b171585 239 if (rc != len)
8d9a23e8 240 return (EIO);
0b3cf046 241 }
242
8d9a23e8 243 return (0);
4b171585 244} /* vn_rdwr() */
245EXPORT_SYMBOL(vn_rdwr);
246
247int
2f5d55aa 248vn_close(vnode_t *vp, int flags, int x1, int x2, void *x3, void *x4)
4b171585 249{
250 int rc;
251
937879f1 252 ASSERT(vp);
253 ASSERT(vp->v_file);
4b171585 254
4be55565 255 mapping_set_gfp_mask(vp->v_file->f_mapping, vp->v_gfp_mask);
97735c39
BB
256 rc = filp_close(vp->v_file, 0);
257 vn_free(vp);
4b171585 258
8d9a23e8 259 return (-rc);
4b171585 260} /* vn_close() */
261EXPORT_SYMBOL(vn_close);
262
5461eefe
BB
263/*
264 * vn_seek() does not actually seek it only performs bounds checking on the
97735c39 265 * proposed seek. We perform minimal checking and allow vn_rdwr() to catch
5461eefe
BB
266 * anything more serious.
267 */
97735c39 268int
47995fa6 269vn_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, void *ct)
97735c39
BB
270{
271 return ((*noffp < 0 || *noffp > MAXOFFSET_T) ? EINVAL : 0);
272}
273EXPORT_SYMBOL(vn_seek);
274
4b171585 275int
36e6f861 276vn_getattr(vnode_t *vp, vattr_t *vap, int flags, void *x3, void *x4)
0b3cf046 277{
4b171585 278 struct file *fp;
dcd9cb5a 279 struct kstat stat;
4b171585 280 int rc;
281
937879f1 282 ASSERT(vp);
283 ASSERT(vp->v_file);
284 ASSERT(vap);
4b171585 285
e4f1d29f 286 fp = vp->v_file;
4b171585 287
94b1ab2a
OF
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)
2a305c34
RY
292 rc = vfs_getattr(&fp->f_path, &stat);
293#else
294 rc = vfs_getattr(fp->f_path.mnt, fp->f_dentry, &stat);
295#endif
4b171585 296 if (rc)
8d9a23e8 297 return (-rc);
4b171585 298
5461eefe
BB
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;
4b171585 313
8d9a23e8 314 return (0);
0b3cf046 315}
4b171585 316EXPORT_SYMBOL(vn_getattr);
317
5461eefe
BB
318int
319vn_fsync(vnode_t *vp, int flags, void *x3, void *x4)
4b171585 320{
36e6f861 321 int datasync = 0;
2a5d574e
BB
322 int error;
323 int fstrans;
36e6f861 324
937879f1 325 ASSERT(vp);
326 ASSERT(vp->v_file);
4b171585 327
36e6f861 328 if (flags & FDSYNC)
329 datasync = 1;
330
2a5d574e
BB
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 */
8f87971e 335 fstrans = __spl_pf_fstrans_check();
2a5d574e 336 if (fstrans)
8f87971e 337 current->flags &= ~(__SPL_PF_FSTRANS);
2a5d574e
BB
338
339 error = -spl_filp_fsync(vp->v_file, datasync);
340 if (fstrans)
8f87971e 341 current->flags |= __SPL_PF_FSTRANS;
2a5d574e
BB
342
343 return (error);
4b171585 344} /* vn_fsync() */
345EXPORT_SYMBOL(vn_fsync);
af828292 346
bbdc6ae4
ED
347int 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;
ea2633ad
TC
351#ifdef FALLOC_FL_PUNCH_HOLE
352 int fstrans;
353#endif
bbdc6ae4
ED
354
355 if (cmd != F_FREESP || bfp->l_whence != 0)
8d9a23e8 356 return (EOPNOTSUPP);
bbdc6ae4
ED
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
ea2633ad
TC
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 */
8f87971e 367 fstrans = __spl_pf_fstrans_check();
ea2633ad 368 if (fstrans)
8f87971e 369 current->flags &= ~(__SPL_PF_FSTRANS);
ea2633ad 370
1c7b3eaf
BB
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);
ea2633ad
TC
378
379 if (fstrans)
8f87971e 380 current->flags |= __SPL_PF_FSTRANS;
ea2633ad 381
1c7b3eaf 382 if (error == 0)
8d9a23e8 383 return (0);
bbdc6ae4
ED
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)
8d9a23e8 399 return (0);
bbdc6ae4
ED
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 );
8d9a23e8 407 return (0);
bbdc6ae4
ED
408 }
409#endif
410
8d9a23e8 411 return (error);
bbdc6ae4
ED
412}
413EXPORT_SYMBOL(vn_space);
414
e4f1d29f 415/* Function must be called while holding the vn_file_lock */
416static file_t *
d3c677bc 417file_find(int fd, struct task_struct *task)
e4f1d29f 418{
5461eefe 419 file_t *fp;
e4f1d29f 420
5461eefe 421 list_for_each_entry(fp, &vn_file_list, f_list) {
d3c677bc 422 if (fd == fp->f_fd && fp->f_task == task) {
937879f1 423 ASSERT(atomic_read(&fp->f_ref) != 0);
5461eefe 424 return (fp);
e4f1d29f 425 }
426 }
427
5461eefe 428 return (NULL);
e4f1d29f 429} /* file_find() */
430
431file_t *
432vn_getf(int fd)
433{
5461eefe 434 struct kstat stat;
e4f1d29f 435 struct file *lfp;
436 file_t *fp;
437 vnode_t *vp;
937879f1 438 int rc = 0;
e4f1d29f 439
313b1ea6
RY
440 if (fd < 0)
441 return (NULL);
442
e4f1d29f 443 /* Already open just take an extra reference */
444 spin_lock(&vn_file_lock);
445
d3c677bc 446 fp = file_find(fd, current);
e4f1d29f 447 if (fp) {
1683e75e
RY
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 }
e4f1d29f 461 atomic_inc(&fp->f_ref);
462 spin_unlock(&vn_file_lock);
8d9a23e8 463 return (fp);
e4f1d29f 464 }
465
466 spin_unlock(&vn_file_lock);
467
468 /* File was not yet opened create the object and setup */
4afaaefa 469 fp = kmem_cache_alloc(vn_file_cache, KM_SLEEP);
e4f1d29f 470 if (fp == NULL)
8d9a23e8 471 goto out;
e4f1d29f 472
473 mutex_enter(&fp->f_lock);
474
475 fp->f_fd = fd;
763b2f3b 476 fp->f_task = current;
e4f1d29f 477 fp->f_offset = 0;
478 atomic_inc(&fp->f_ref);
479
480 lfp = fget(fd);
481 if (lfp == NULL)
8d9a23e8 482 goto out_mutex;
e4f1d29f 483
484 vp = vn_alloc(KM_SLEEP);
485 if (vp == NULL)
8d9a23e8 486 goto out_fget;
e4f1d29f 487
94b1ab2a 488#if defined(HAVE_4ARGS_VFS_GETATTR)
5461eefe
BB
489 rc = vfs_getattr(&lfp->f_path, &stat, STATX_TYPE,
490 AT_STATX_SYNC_AS_STAT);
94b1ab2a 491#elif defined(HAVE_2ARGS_VFS_GETATTR)
2a305c34
RY
492 rc = vfs_getattr(&lfp->f_path, &stat);
493#else
494 rc = vfs_getattr(lfp->f_path.mnt, lfp->f_dentry, &stat);
495#endif
5461eefe 496 if (rc)
8d9a23e8 497 goto out_vnode;
e4f1d29f 498
499 mutex_enter(&vp->v_lock);
4295b530 500 vp->v_type = vn_mode_to_vtype(stat.mode);
e4f1d29f 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);
8d9a23e8 513 return (fp);
e4f1d29f 514
515out_vnode:
e4f1d29f 516 vn_free(vp);
517out_fget:
e4f1d29f 518 fput(lfp);
519out_mutex:
e4f1d29f 520 mutex_exit(&fp->f_lock);
521 kmem_cache_free(vn_file_cache, fp);
522out:
5461eefe 523 return (NULL);
e4f1d29f 524} /* getf() */
525EXPORT_SYMBOL(getf);
526
527static void releasef_locked(file_t *fp)
528{
937879f1 529 ASSERT(fp->f_file);
530 ASSERT(fp->f_vnode);
e4f1d29f 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
539void
540vn_releasef(int fd)
d3c677bc
RY
541{
542 areleasef(fd, P_FINFO(current));
543}
544EXPORT_SYMBOL(releasef);
545
546void
547vn_areleasef(int fd, uf_info_t *fip)
e4f1d29f 548{
549 file_t *fp;
d3c677bc 550 struct task_struct *task = (struct task_struct *)fip;
e4f1d29f 551
313b1ea6
RY
552 if (fd < 0)
553 return;
554
e4f1d29f 555 spin_lock(&vn_file_lock);
d3c677bc 556 fp = file_find(fd, task);
e4f1d29f 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
5461eefe 564 list_del(&fp->f_list);
e4f1d29f 565 releasef_locked(fp);
566 }
567 spin_unlock(&vn_file_lock);
e4f1d29f 568} /* releasef() */
d3c677bc
RY
569EXPORT_SYMBOL(areleasef);
570
e4f1d29f 571
137af025
BB
572static void
573#ifdef HAVE_SET_FS_PWD_WITH_CONST
574vn_set_fs_pwd(struct fs_struct *fs, const struct path *path)
575#else
576vn_set_fs_pwd(struct fs_struct *fs, struct path *path)
577#endif /* HAVE_SET_FS_PWD_WITH_CONST */
51a727e9 578{
9b2048c2
BB
579 struct path old_pwd;
580
137af025 581#ifdef HAVE_FS_STRUCT_SPINLOCK
9b2048c2
BB
582 spin_lock(&fs->lock);
583 old_pwd = fs->pwd;
584 fs->pwd = *path;
585 path_get(path);
586 spin_unlock(&fs->lock);
137af025 587#else
9b2048c2
BB
588 write_lock(&fs->lock);
589 old_pwd = fs->pwd;
590 fs->pwd = *path;
591 path_get(path);
592 write_unlock(&fs->lock);
137af025 593#endif /* HAVE_FS_STRUCT_SPINLOCK */
9b2048c2
BB
594
595 if (old_pwd.dentry)
596 path_put(&old_pwd);
51a727e9 597}
51a727e9
BB
598
599int
600vn_set_pwd(const char *filename)
601{
5461eefe
BB
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)
8d9a23e8 616 goto out;
51a727e9 617
5461eefe
BB
618 rc = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS);
619 if (rc)
8d9a23e8 620 goto dput_and_out;
51a727e9 621
5461eefe 622 vn_set_fs_pwd(current->fs, &path);
51a727e9
BB
623
624dput_and_out:
5461eefe 625 path_put(&path);
51a727e9 626out:
82a358d9
BB
627 set_fs(saved_fs);
628
5461eefe 629 return (-rc);
51a727e9
BB
630} /* vn_set_pwd() */
631EXPORT_SYMBOL(vn_set_pwd);
632
af828292 633static int
634vn_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
643static void
644vn_cache_destructor(void *buf, void *cdrarg)
645{
646 struct vnode *vp = buf;
647
648 mutex_destroy(&vp->v_lock);
649} /* vn_cache_destructor() */
650
e4f1d29f 651static int
652vn_file_cache_constructor(void *buf, void *cdrarg, int kmflags)
653{
654 file_t *fp = buf;
655
656 atomic_set(&fp->f_ref, 0);
5461eefe 657 mutex_init(&fp->f_lock, NULL, MUTEX_DEFAULT, NULL);
4e62fd41 658 INIT_LIST_HEAD(&fp->f_list);
e4f1d29f 659
5461eefe 660 return (0);
378c6ed5 661} /* vn_file_cache_constructor() */
e4f1d29f 662
663static void
664vn_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
af828292 671int
12ff95ff 672spl_vn_init(void)
af828292 673{
57d86234 674 vn_cache = kmem_cache_create("spl_vn_cache",
5461eefe
BB
675 sizeof (struct vnode), 64, vn_cache_constructor,
676 vn_cache_destructor, NULL, NULL, NULL, 0);
e4f1d29f 677
678 vn_file_cache = kmem_cache_create("spl_vn_file_cache",
5461eefe
BB
679 sizeof (file_t), 64, vn_file_cache_constructor,
680 vn_file_cache_destructor, NULL, NULL, NULL, 0);
681
8d9a23e8 682 return (0);
378c6ed5 683} /* spl_vn_init() */
af828292 684
685void
12ff95ff 686spl_vn_fini(void)
af828292 687{
5461eefe 688 file_t *fp, *next_fp;
2fb9b26a 689 int leaked = 0;
e4f1d29f 690
691 spin_lock(&vn_file_lock);
692
5461eefe
BB
693 list_for_each_entry_safe(fp, next_fp, &vn_file_list, f_list) {
694 list_del(&fp->f_list);
e4f1d29f 695 releasef_locked(fp);
696 leaked++;
697 }
698
e4f1d29f 699 spin_unlock(&vn_file_lock);
700
701 if (leaked > 0)
8d9a23e8 702 printk(KERN_WARNING "WARNING: %d vnode files leaked\n", leaked);
e4f1d29f 703
2371321e 704 kmem_cache_destroy(vn_file_cache);
2fb9b26a 705 kmem_cache_destroy(vn_cache);
378c6ed5 706} /* spl_vn_fini() */