4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
21 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
22 /* All Rights Reserved */
26 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
27 * Copyright (c) 2016, 2017 by Delphix. All rights reserved.
31 * This file defines the vnode operations for mounted file descriptors.
32 * The routines in this file act as a layer between the NAMEFS file
33 * system and SPECFS/FIFOFS. With the exception of nm_open(), nm_setattr(),
34 * nm_getattr() and nm_access(), the routines simply apply the VOP operation
35 * to the vnode representing the file descriptor. This switches control
36 * to the underlying file system to which the file descriptor belongs.
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/systm.h>
42 #include <sys/errno.h>
45 #include <sys/fcntl.h>
46 #include <sys/flock.h>
50 #include <sys/vnode.h>
52 #include <sys/signal.h>
56 #include <sys/debug.h>
58 #include <sys/fs/namenode.h>
59 #include <sys/stream.h>
60 #include <sys/fs_subr.h>
61 #include <sys/policy.h>
64 * Create a reference to the vnode representing the file descriptor.
65 * Then, apply the fop_open operation to that vnode.
67 * The vnode for the file descriptor may be switched under you.
68 * If it is, search the hash list for an nodep - nodep->nm_filevp
69 * pair. If it exists, return that nodep to the user.
70 * If it does not exist, create a new namenode to attach
71 * to the nodep->nm_filevp then place the pair on the hash list.
73 * Newly created objects are like children/nodes in the mounted
74 * file system, with the parent being the initial mount.
77 nm_open(vnode_t
**vpp
, int flag
, cred_t
*crp
, caller_context_t
*ct
)
79 struct namenode
*nodep
= VTONM(*vpp
);
81 struct namenode
*newnamep
;
83 struct vnode
*infilevp
;
84 struct vnode
*outfilevp
;
87 * If the vnode is switched under us, the corresponding
88 * VN_RELE for this VN_HOLD will be done by the file system
89 * performing the switch. Otherwise, the corresponding
90 * VN_RELE will be done by nm_close().
92 infilevp
= outfilevp
= nodep
->nm_filevp
;
95 if ((error
= fop_open(&outfilevp
, flag
, crp
, ct
)) != 0) {
99 if (infilevp
!= outfilevp
) {
101 * See if the new filevp (outfilevp) is already associated
102 * with the mount point. If it is, then it already has a
103 * namenode associated with it.
105 mutex_enter(&ntable_lock
);
107 namefind(outfilevp
, nodep
->nm_mountpt
)) != NULL
) {
108 struct vnode
*vp
= NMTOV(newnamep
);
114 newnamep
= kmem_zalloc(sizeof (struct namenode
), KM_SLEEP
);
115 newvp
= vn_alloc(KM_SLEEP
);
116 newnamep
->nm_vnode
= newvp
;
118 mutex_init(&newnamep
->nm_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
120 mutex_enter(&nodep
->nm_lock
);
121 newvp
->v_flag
= ((*vpp
)->v_flag
| VNOMAP
| VNOSWAP
) & ~VROOT
;
122 vn_setops(newvp
, vn_getops(*vpp
));
123 newvp
->v_vfsp
= &namevfs
;
124 newvp
->v_stream
= outfilevp
->v_stream
;
125 newvp
->v_type
= outfilevp
->v_type
;
126 newvp
->v_rdev
= outfilevp
->v_rdev
;
127 newvp
->v_data
= (caddr_t
)newnamep
;
129 bcopy(&nodep
->nm_vattr
, &newnamep
->nm_vattr
, sizeof (vattr_t
));
130 newnamep
->nm_vattr
.va_type
= outfilevp
->v_type
;
131 newnamep
->nm_vattr
.va_nodeid
= namenodeno_alloc();
132 newnamep
->nm_vattr
.va_size
= 0;
133 newnamep
->nm_vattr
.va_rdev
= outfilevp
->v_rdev
;
134 newnamep
->nm_flag
= NMNMNT
;
135 newnamep
->nm_filevp
= outfilevp
;
136 newnamep
->nm_filep
= nodep
->nm_filep
;
137 newnamep
->nm_mountpt
= nodep
->nm_mountpt
;
138 mutex_exit(&nodep
->nm_lock
);
141 * Insert the new namenode into the hash list.
143 nameinsert(newnamep
);
145 mutex_exit(&ntable_lock
);
147 * Release the above reference to the infilevp, the reference
148 * to the NAMEFS vnode, create a reference to the new vnode
149 * and return the new vnode to the user.
152 *vpp
= NMTOV(newnamep
);
158 * Close a mounted file descriptor.
159 * Remove any locks and apply the fop_close operation to the vnode for
160 * the file descriptor.
163 nm_close(vnode_t
*vp
, int flag
, int count
, offset_t offset
, cred_t
*crp
,
164 caller_context_t
*ct
)
166 struct namenode
*nodep
= VTONM(vp
);
169 (void) cleanlocks(vp
, ttoproc(curthread
)->p_pid
, 0);
170 cleanshares(vp
, ttoproc(curthread
)->p_pid
);
171 error
= fop_close(nodep
->nm_filevp
, flag
, count
, offset
, crp
, ct
);
173 (void) fop_fsync(nodep
->nm_filevp
, FSYNC
, crp
, ct
);
175 * Before VN_RELE() we need to remove the vnode from
176 * the hash table. We should only do so in the NMNMNT case.
177 * In other cases, nodep->nm_filep keeps a reference
178 * to nm_filevp and the entry in the hash table doesn't
181 if ((nodep
->nm_flag
& NMNMNT
) != 0) {
182 mutex_enter(&ntable_lock
);
184 mutex_exit(&ntable_lock
);
186 VN_RELE(nodep
->nm_filevp
);
192 nm_read(vnode_t
*vp
, struct uio
*uiop
, int ioflag
, cred_t
*crp
,
193 caller_context_t
*ct
)
195 return (fop_read(VTONM(vp
)->nm_filevp
, uiop
, ioflag
, crp
, ct
));
199 nm_write(vnode_t
*vp
, struct uio
*uiop
, int ioflag
, cred_t
*crp
,
200 caller_context_t
*ct
)
202 return (fop_write(VTONM(vp
)->nm_filevp
, uiop
, ioflag
, crp
, ct
));
206 nm_ioctl(vnode_t
*vp
, int cmd
, intptr_t arg
, int mode
, cred_t
*cr
, int *rvalp
,
207 caller_context_t
*ct
)
209 return (fop_ioctl(VTONM(vp
)->nm_filevp
, cmd
, arg
, mode
, cr
, rvalp
, ct
));
213 * Return in vap the attributes that are stored in the namenode
214 * structure. Only the size is taken from the mounted object.
218 nm_getattr(vnode_t
*vp
, vattr_t
*vap
, int flags
, cred_t
*crp
,
219 caller_context_t
*ct
)
221 struct namenode
*nodep
= VTONM(vp
);
225 mutex_enter(&nodep
->nm_lock
);
226 bcopy(&nodep
->nm_vattr
, vap
, sizeof (vattr_t
));
227 mutex_exit(&nodep
->nm_lock
);
229 if ((va
.va_mask
= vap
->va_mask
& AT_SIZE
) != 0) {
230 if (error
= fop_getattr(nodep
->nm_filevp
, &va
, flags
, crp
, ct
))
232 vap
->va_size
= va
.va_size
;
239 * Standard access() like check. Figure out which mode bits apply
240 * to the caller then pass the missing mode bits to the secpolicy function.
243 nm_access_unlocked(void *vnp
, int mode
, cred_t
*crp
)
245 struct namenode
*nodep
= vnp
;
248 if (crgetuid(crp
) != nodep
->nm_vattr
.va_uid
) {
250 if (!groupmember(nodep
->nm_vattr
.va_gid
, crp
))
254 return (secpolicy_vnode_access2(crp
, NMTOV(nodep
),
255 nodep
->nm_vattr
.va_uid
, nodep
->nm_vattr
.va_mode
<< shift
,
259 * Set the attributes of the namenode from the attributes in vap.
263 nm_setattr(vnode_t
*vp
, vattr_t
*vap
, int flags
, cred_t
*crp
,
264 caller_context_t
*ctp
)
266 struct namenode
*nodep
= VTONM(vp
);
267 struct vattr
*nmvap
= &nodep
->nm_vattr
;
268 long mask
= vap
->va_mask
;
272 * Cannot set these attributes.
274 if (mask
& (AT_NOSET
|AT_SIZE
))
277 (void) fop_rwlock(nodep
->nm_filevp
, V_WRITELOCK_TRUE
, ctp
);
278 mutex_enter(&nodep
->nm_lock
);
281 * Change ownership/group/time/access mode of mounted file
285 error
= secpolicy_vnode_setattr(crp
, vp
, vap
, nmvap
, flags
,
286 nm_access_unlocked
, nodep
);
292 * If request to change mode, copy new
293 * mode into existing attribute structure.
296 nmvap
->va_mode
= vap
->va_mode
& ~VSVTX
;
299 * If request was to change user or group, turn off suid and sgid
301 * If the system was configured with the "rstchown" option, the
302 * owner is not permitted to give away the file, and can change
303 * the group id only to a group of which they are a member.
306 nmvap
->va_uid
= vap
->va_uid
;
308 nmvap
->va_gid
= vap
->va_gid
;
310 * If request is to modify times, make sure user has write
311 * permissions on the file.
314 nmvap
->va_atime
= vap
->va_atime
;
315 if (mask
& AT_MTIME
) {
316 nmvap
->va_mtime
= vap
->va_mtime
;
317 gethrestime(&nmvap
->va_ctime
);
320 mutex_exit(&nodep
->nm_lock
);
321 fop_rwunlock(nodep
->nm_filevp
, V_WRITELOCK_TRUE
, ctp
);
326 * Check mode permission on the namenode. First nm_access_unlocked()
327 * checks the bits on the name node, then an access check is performed
328 * on the underlying file.
332 nm_access(vnode_t
*vp
, int mode
, int flags
, cred_t
*crp
, caller_context_t
*ct
)
334 struct namenode
*nodep
= VTONM(vp
);
337 mutex_enter(&nodep
->nm_lock
);
338 error
= nm_access_unlocked(nodep
, mode
, crp
);
339 mutex_exit(&nodep
->nm_lock
);
341 return (fop_access(nodep
->nm_filevp
, mode
, flags
, crp
, ct
));
347 * We can get here if a creat or open with O_CREAT is done on a namefs
348 * mount point, for example, as the object of a shell output redirection to
353 nm_create(vnode_t
*dvp
, char *name
, vattr_t
*vap
, enum vcexcl excl
, int mode
,
354 vnode_t
**vpp
, cred_t
*cr
, int flag
, caller_context_t
*ct
,
359 ASSERT(dvp
&& *name
== '\0');
360 if (excl
== NONEXCL
) {
361 if (mode
&& (error
= nm_access(dvp
, mode
, 0, cr
, ct
)) != 0)
370 * Links are not allowed on mounted file descriptors.
374 nm_link(vnode_t
*tdvp
, vnode_t
*vp
, char *tnm
, cred_t
*crp
,
375 caller_context_t
*ct
, int flags
)
381 nm_fsync(vnode_t
*vp
, int syncflag
, cred_t
*crp
, caller_context_t
*ct
)
383 return (fop_fsync(VTONM(vp
)->nm_filevp
, syncflag
, crp
, ct
));
386 /* Free the namenode */
389 nm_inactive(vnode_t
*vp
, cred_t
*crp
, caller_context_t
*ct
)
391 struct namenode
*nodep
= VTONM(vp
);
392 vfs_t
*vfsp
= vp
->v_vfsp
;
394 mutex_enter(&vp
->v_lock
);
395 ASSERT(vp
->v_count
>= 1);
397 if (vp
->v_count
!= 0) {
398 mutex_exit(&vp
->v_lock
);
401 mutex_exit(&vp
->v_lock
);
402 if (!(nodep
->nm_flag
& NMNMNT
)) {
403 ASSERT(nodep
->nm_filep
->f_vnode
== nodep
->nm_filevp
);
404 (void) closef(nodep
->nm_filep
);
408 if (vfsp
!= &namevfs
)
410 namenodeno_free(nodep
->nm_vattr
.va_nodeid
);
411 kmem_free(nodep
, sizeof (struct namenode
));
415 nm_fid(vnode_t
*vp
, struct fid
*fidnodep
, caller_context_t
*ct
)
417 return (fop_fid(VTONM(vp
)->nm_filevp
, fidnodep
, ct
));
421 nm_rwlock(vnode_t
*vp
, int write
, caller_context_t
*ctp
)
423 return (fop_rwlock(VTONM(vp
)->nm_filevp
, write
, ctp
));
427 nm_rwunlock(vnode_t
*vp
, int write
, caller_context_t
*ctp
)
429 fop_rwunlock(VTONM(vp
)->nm_filevp
, write
, ctp
);
433 nm_seek(vnode_t
*vp
, offset_t ooff
, offset_t
*noffp
, caller_context_t
*ct
)
435 return (fop_seek(VTONM(vp
)->nm_filevp
, ooff
, noffp
, ct
));
439 * Return the vnode representing the file descriptor in vpp.
442 nm_realvp(vnode_t
*vp
, vnode_t
**vpp
, caller_context_t
*ct
)
446 vp
= VTONM(vp
)->nm_filevp
;
447 if (fop_realvp(vp
, &rvp
, ct
) == 0)
454 nm_poll(vnode_t
*vp
, short events
, int anyyet
, short *reventsp
,
455 pollhead_t
**phpp
, caller_context_t
*ct
)
457 return (fop_poll(VTONM(vp
)->nm_filevp
, events
, anyyet
, reventsp
,
461 const struct vnodeops nm_vnodeops
= {
462 .vnop_name
= "namefs",
464 .vop_close
= nm_close
,
466 .vop_write
= nm_write
,
467 .vop_ioctl
= nm_ioctl
,
468 .vop_getattr
= nm_getattr
,
469 .vop_setattr
= nm_setattr
,
470 .vop_access
= nm_access
,
471 .vop_create
= nm_create
,
473 .vop_fsync
= nm_fsync
,
474 .vop_inactive
= nm_inactive
,
476 .vop_rwlock
= nm_rwlock
,
477 .vop_rwunlock
= nm_rwunlock
,
479 .vop_realvp
= nm_realvp
,
481 .vop_dispose
= fs_nodispose
,