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