1 /*
2  * Copyright (c) 1992, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  * All rights reserved.
5  *
6  * This code is derived from software donated to Berkeley by
7  * Jan-Simon Pendry.
8  *
9  * %sccs.include.redist.c%
10  *
11  *	@(#)fdesc_vfsops.c	8.3 (Berkeley) 01/05/94
12  *
13  * $Id: fdesc_vfsops.c,v 1.9 1993/04/06 15:28:33 jsp Exp $
14  */
15 
16 /*
17  * /dev/fd Filesystem
18  */
19 
20 #include <sys/param.h>
21 #include <sys/systm.h>
22 #include <sys/time.h>
23 #include <sys/types.h>
24 #include <sys/proc.h>
25 #include <sys/resourcevar.h>
26 #include <sys/filedesc.h>
27 #include <sys/vnode.h>
28 #include <sys/mount.h>
29 #include <sys/namei.h>
30 #include <sys/malloc.h>
31 #include <miscfs/fdesc/fdesc.h>
32 
33 /*
34  * Mount the per-process file descriptors (/dev/fd)
35  */
36 int
37 fdesc_mount(mp, path, data, ndp, p)
38 	struct mount *mp;
39 	char *path;
40 	caddr_t data;
41 	struct nameidata *ndp;
42 	struct proc *p;
43 {
44 	int error = 0;
45 	u_int size;
46 	struct fdescmount *fmp;
47 	struct vnode *rvp;
48 
49 	/*
50 	 * Update is a no-op
51 	 */
52 	if (mp->mnt_flag & MNT_UPDATE)
53 		return (EOPNOTSUPP);
54 
55 	error = fdesc_allocvp(Froot, FD_ROOT, mp, &rvp);
56 	if (error)
57 		return (error);
58 
59 	MALLOC(fmp, struct fdescmount *, sizeof(struct fdescmount),
60 				M_UFSMNT, M_WAITOK);	/* XXX */
61 	rvp->v_type = VDIR;
62 	rvp->v_flag |= VROOT;
63 	fmp->f_root = rvp;
64 	/* XXX -- don't mark as local to work around fts() problems */
65 	/*mp->mnt_flag |= MNT_LOCAL;*/
66 	mp->mnt_data = (qaddr_t) fmp;
67 	getnewfsid(mp, MOUNT_FDESC);
68 
69 	(void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
70 	bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
71 	bzero(mp->mnt_stat.f_mntfromname, MNAMELEN);
72 	bcopy("fdesc", mp->mnt_stat.f_mntfromname, sizeof("fdesc"));
73 	return (0);
74 }
75 
76 int
77 fdesc_start(mp, flags, p)
78 	struct mount *mp;
79 	int flags;
80 	struct proc *p;
81 {
82 	return (0);
83 }
84 
85 int
86 fdesc_unmount(mp, mntflags, p)
87 	struct mount *mp;
88 	int mntflags;
89 	struct proc *p;
90 {
91 	int error;
92 	int flags = 0;
93 	extern int doforce;
94 	struct vnode *rootvp = VFSTOFDESC(mp)->f_root;
95 
96 	if (mntflags & MNT_FORCE) {
97 		/* fdesc can never be rootfs so don't check for it */
98 		if (!doforce)
99 			return (EINVAL);
100 		flags |= FORCECLOSE;
101 	}
102 
103 	/*
104 	 * Clear out buffer cache.  I don't think we
105 	 * ever get anything cached at this level at the
106 	 * moment, but who knows...
107 	 */
108 	if (rootvp->v_usecount > 1)
109 		return (EBUSY);
110 	if (error = vflush(mp, rootvp, flags))
111 		return (error);
112 
113 	/*
114 	 * Release reference on underlying root vnode
115 	 */
116 	vrele(rootvp);
117 	/*
118 	 * And blow it away for future re-use
119 	 */
120 	vgone(rootvp);
121 	/*
122 	 * Finally, throw away the fdescmount structure
123 	 */
124 	free(mp->mnt_data, M_UFSMNT);	/* XXX */
125 	mp->mnt_data = 0;
126 
127 	return (0);
128 }
129 
130 int
131 fdesc_root(mp, vpp)
132 	struct mount *mp;
133 	struct vnode **vpp;
134 {
135 	struct vnode *vp;
136 
137 	/*
138 	 * Return locked reference to root.
139 	 */
140 	vp = VFSTOFDESC(mp)->f_root;
141 	VREF(vp);
142 	VOP_LOCK(vp);
143 	*vpp = vp;
144 	return (0);
145 }
146 
147 int
148 fdesc_quotactl(mp, cmd, uid, arg, p)
149 	struct mount *mp;
150 	int cmd;
151 	uid_t uid;
152 	caddr_t arg;
153 	struct proc *p;
154 {
155 
156 	return (EOPNOTSUPP);
157 }
158 
159 int
160 fdesc_statfs(mp, sbp, p)
161 	struct mount *mp;
162 	struct statfs *sbp;
163 	struct proc *p;
164 {
165 	struct filedesc *fdp;
166 	int lim;
167 	int i;
168 	int last;
169 	int freefd;
170 
171 	/*
172 	 * Compute number of free file descriptors.
173 	 * [ Strange results will ensue if the open file
174 	 * limit is ever reduced below the current number
175 	 * of open files... ]
176 	 */
177 	lim = p->p_rlimit[RLIMIT_NOFILE].rlim_cur;
178 	fdp = p->p_fd;
179 	last = min(fdp->fd_nfiles, lim);
180 	freefd = 0;
181 	for (i = fdp->fd_freefile; i < last; i++)
182 		if (fdp->fd_ofiles[i] == NULL)
183 			freefd++;
184 
185 	/*
186 	 * Adjust for the fact that the fdesc array may not
187 	 * have been fully allocated yet.
188 	 */
189 	if (fdp->fd_nfiles < lim)
190 		freefd += (lim - fdp->fd_nfiles);
191 
192 	sbp->f_type = MOUNT_FDESC;
193 	sbp->f_flags = 0;
194 	sbp->f_bsize = DEV_BSIZE;
195 	sbp->f_iosize = DEV_BSIZE;
196 	sbp->f_blocks = 2;		/* 1K to keep df happy */
197 	sbp->f_bfree = 0;
198 	sbp->f_bavail = 0;
199 	sbp->f_files = lim + 1;		/* Allow for "." */
200 	sbp->f_ffree = freefd;		/* See comments above */
201 	if (sbp != &mp->mnt_stat) {
202 		bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
203 		bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
204 		bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
205 	}
206 	return (0);
207 }
208 
209 int
210 fdesc_sync(mp, waitfor)
211 	struct mount *mp;
212 	int waitfor;
213 {
214 
215 	return (0);
216 }
217 
218 /*
219  * Fdesc flat namespace lookup.
220  * Currently unsupported.
221  */
222 int
223 fdesc_vget(mp, ino, vpp)
224 	struct mount *mp;
225 	ino_t ino;
226 	struct vnode **vpp;
227 {
228 
229 	return (EOPNOTSUPP);
230 }
231 
232 int
233 fdesc_fhtovp(mp, fhp, setgen, vpp)
234 	struct mount *mp;
235 	struct fid *fhp;
236 	int setgen;
237 	struct vnode **vpp;
238 {
239 	return (EOPNOTSUPP);
240 }
241 
242 int
243 fdesc_vptofh(vp, fhp)
244 	struct vnode *vp;
245 	struct fid *fhp;
246 {
247 
248 	return (EOPNOTSUPP);
249 }
250 
251 struct vfsops fdesc_vfsops = {
252 	fdesc_mount,
253 	fdesc_start,
254 	fdesc_unmount,
255 	fdesc_root,
256 	fdesc_quotactl,
257 	fdesc_statfs,
258 	fdesc_sync,
259 	fdesc_vget,
260 	fdesc_fhtovp,
261 	fdesc_vptofh,
262 	fdesc_init,
263 };
264