1/*
2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
29/*
30 * Copyright (c) 1992, 1993, 1995
31 *	The Regents of the University of California.  All rights reserved.
32 *
33 * This code is derived from software donated to Berkeley by
34 * Jan-Simon Pendry.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 *    notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 *    notice, this list of conditions and the following disclaimer in the
43 *    documentation and/or other materials provided with the distribution.
44 * 3. All advertising materials mentioning features or use of this software
45 *    must display the following acknowledgement:
46 *	This product includes software developed by the University of
47 *	California, Berkeley and its contributors.
48 * 4. Neither the name of the University nor the names of its contributors
49 *    may be used to endorse or promote products derived from this software
50 *    without specific prior written permission.
51 *
52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * SUCH DAMAGE.
63 *
64 *	@(#)fdesc_vfsops.c	8.10 (Berkeley) 5/14/95
65 *
66 */
67/*
68* /dev/fd Filesystem
69 */
70
71#include <sys/param.h>
72#include <sys/systm.h>
73#include <sys/time.h>
74#include <sys/types.h>
75#include <sys/proc_internal.h>
76#include <sys/resourcevar.h>
77#include <sys/filedesc.h>
78#include <sys/vnode.h>
79#include <sys/mount_internal.h>
80#include <sys/namei.h>
81#include <sys/malloc.h>
82#include <miscfs/fdesc/fdesc.h>
83
84/*
85 * Mount the per-process file descriptors (/dev/fd)
86 */
87static int
88fdesc_mount(struct mount *mp, __unused vnode_t devvp, __unused user_addr_t data, __unused vfs_context_t context)
89{
90	int error = 0;
91	struct fdescmount *fmp;
92	struct vnode *rvp;
93
94	/*
95	 * Update is a no-op
96	 */
97	if (mp->mnt_flag & MNT_UPDATE)
98		return (ENOTSUP);
99
100	error = fdesc_allocvp(Froot, FD_ROOT, mp, &rvp, VDIR);
101	if (error)
102		return (error);
103
104	MALLOC(fmp, struct fdescmount *, sizeof(struct fdescmount),
105				M_UFSMNT, M_WAITOK);	/* XXX */
106
107	vnode_setnoflush(rvp);
108	vnode_ref(rvp);
109	vnode_put(rvp);
110
111	fmp->f_root = rvp;
112	/* XXX -- don't mark as local to work around fts() problems */
113	/*mp->mnt_flag |= MNT_LOCAL;*/
114	mp->mnt_data = (qaddr_t) fmp;
115	vfs_getnewfsid(mp);
116
117	bzero(mp->mnt_vfsstat.f_mntfromname, MAXPATHLEN);
118	bcopy("fdesc", mp->mnt_vfsstat.f_mntfromname, sizeof("fdesc"));
119	return (0);
120}
121
122static int
123fdesc_start(__unused struct mount *mp, __unused int flags, __unused vfs_context_t context)
124{
125	return (0);
126}
127
128static int
129fdesc_unmount(struct mount *mp, int mntflags, __unused vfs_context_t context)
130{
131	int error;
132	int flags = 0;
133	int force = 0;
134	struct vnode *rvp = VFSTOFDESC(mp)->f_root;
135
136	if (mntflags & MNT_FORCE) {
137		flags |= FORCECLOSE;
138		force = 1;
139	}
140
141	if ( vnode_isinuse(rvp, 1) && !force )
142		return (EBUSY);
143	if ( (error = vflush(mp, rvp, flags|SKIPSYSTEM)) && !force )
144		return (error);
145
146	/*
147	 * And mark for recycle after we drop its reference; it away for future re-use
148	 */
149	vnode_recycle(rvp);
150	/*
151	 * Release reference on underlying root vnode
152	 */
153	vnode_rele(rvp);
154	/*
155	 * Finally, throw away the fdescmount structure
156	 */
157	_FREE(mp->mnt_data, M_UFSMNT);	/* XXX */
158	mp->mnt_data = NULL;
159
160	return (0);
161}
162
163int
164fdesc_root(struct mount *mp, struct vnode **vpp, __unused vfs_context_t context)
165{
166	struct vnode *vp;
167
168	/*
169	 * Return locked reference to root.
170	 */
171	vp = VFSTOFDESC(mp)->f_root;
172	vnode_get(vp);
173	*vpp = vp;
174	return (0);
175}
176
177#if 0
178/*
179 * XXX commented out in mount.h
180 */
181int
182fdesc_statfs(__unused struct mount *mp, struct vfsstatfs *sbp, vfs_context_t context)
183{
184	proc_t p = vfs_context_proc(context);
185	struct filedesc *fdp;
186	int lim;
187	int i;
188	int last;
189	int freefd;
190
191	/*
192	 * Compute number of free file descriptors.
193	 * [ Strange results will ensue if the open file
194	 * limit is ever reduced below the current number
195	 * of open files... ]
196	 */
197	lim = p->p_rlimit[RLIMIT_NOFILE].rlim_cur;
198	fdp = p->p_fd;
199	last = min(fdp->fd_nfiles, lim);
200	freefd = 0;
201	for (i = fdp->fd_freefile; i < last; i++)
202		if (fdp->fd_ofiles[i] == NULL &&
203				!(fdp->fd_ofileflags[i] & UF_RESERVED))
204			freefd++;
205
206	/*
207	 * Adjust for the fact that the fdesc array may not
208	 * have been fully allocated yet.
209	 */
210	if (fdp->fd_nfiles < lim)
211		freefd += (lim - fdp->fd_nfiles);
212
213	sbp->f_flags = 0;
214	sbp->f_bsize = DEV_BSIZE;
215	sbp->f_iosize = DEV_BSIZE;
216	sbp->f_blocks = (uint64_t)2;		/* 1K to keep df happy */
217	sbp->f_bfree = 0;
218	sbp->f_bavail = 0;
219	sbp->f_files = (uint64_t)((unsigned long)(lim + 1));		/* Allow for "." */
220	sbp->f_ffree = (uint64_t)((unsigned long)freefd);		/* See comments above */
221
222	return (0);
223}
224#endif	/* 0 */
225
226static int
227fdesc_vfs_getattr(__unused mount_t mp, struct vfs_attr *fsap, vfs_context_t context)
228{
229	VFSATTR_RETURN(fsap, f_bsize, DEV_BSIZE);
230	VFSATTR_RETURN(fsap, f_iosize, DEV_BSIZE);
231	VFSATTR_RETURN(fsap, f_blocks, 2);
232	VFSATTR_RETURN(fsap, f_bfree, 0);
233	VFSATTR_RETURN(fsap, f_bavail, 0);
234	VFSATTR_RETURN(fsap, f_fssubtype, 0);
235
236	if (VFSATTR_IS_ACTIVE(fsap, f_objcount) ||
237	    VFSATTR_IS_ACTIVE(fsap, f_maxobjcount) ||
238	    VFSATTR_IS_ACTIVE(fsap, f_files) ||
239	    VFSATTR_IS_ACTIVE(fsap, f_ffree))
240	{
241		proc_t p = vfs_context_proc(context);
242		struct filedesc *fdp;
243		int lim;
244		int i;
245		int last;
246		int freefd;
247
248		/*
249		 * Compute number of free file descriptors.
250		 * [ Strange results will ensue if the open file
251		 * limit is ever reduced below the current number
252		 * of open files... ]
253		 */
254		lim = p->p_rlimit[RLIMIT_NOFILE].rlim_cur;
255		fdp = p->p_fd;
256		last = min(fdp->fd_nfiles, lim);
257		freefd = 0;
258		for (i = fdp->fd_freefile; i < last; i++)
259			if (fdp->fd_ofiles[i] == NULL &&
260					!(fdp->fd_ofileflags[i] & UF_RESERVED))
261				freefd++;
262
263		/*
264		 * Adjust for the fact that the fdesc array may not
265		 * have been fully allocated yet.
266		 */
267		if (fdp->fd_nfiles < lim)
268			freefd += (lim - fdp->fd_nfiles);
269
270		VFSATTR_RETURN(fsap, f_objcount, lim+1);
271		VFSATTR_RETURN(fsap, f_maxobjcount, lim+1);
272		VFSATTR_RETURN(fsap, f_files, lim+1);
273		VFSATTR_RETURN(fsap, f_ffree, freefd);
274	}
275
276	return 0;
277}
278
279static int
280fdesc_sync(__unused struct mount *mp, __unused int waitfor, __unused vfs_context_t context)
281{
282
283	return (0);
284}
285
286#define fdesc_fhtovp (int (*) (mount_t, int, unsigned char *, vnode_t *, vfs_context_t))eopnotsupp
287#define fdesc_sysctl (int (*) (int *, u_int, user_addr_t, size_t *, user_addr_t, size_t, vfs_context_t))eopnotsupp
288#define fdesc_vget (int (*) (mount_t, ino64_t, vnode_t *, vfs_context_t))eopnotsupp
289#define fdesc_vptofh (int (*) (vnode_t, int *, unsigned char *, vfs_context_t))eopnotsupp
290
291struct vfsops fdesc_vfsops = {
292	fdesc_mount,
293	fdesc_start,
294	fdesc_unmount,
295	fdesc_root,
296	NULL, 			/* quotactl */
297	fdesc_vfs_getattr,
298/*	fdesc_statfs,	XXX commented out in mount.h */
299	fdesc_sync,
300	fdesc_vget,
301	fdesc_fhtovp,
302	fdesc_vptofh,
303	fdesc_init,
304	fdesc_sysctl,
305	NULL,
306	{NULL}
307};
308