xref: /original-bsd/sys/ufs/ufs/ufs_vfsops.c (revision 22cb382a)
1 /*
2  * Copyright (c) 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)ufs_vfsops.c	7.62 (Berkeley) 08/11/92
8  */
9 
10 #include <sys/param.h>
11 #include <net/radix.h>
12 #include <sys/domain.h>
13 #include <sys/socket.h>
14 #include <sys/mbuf.h>
15 #include <sys/mount.h>
16 #include <sys/proc.h>
17 #include <sys/buf.h>
18 #include <sys/vnode.h>
19 #include <sys/malloc.h>
20 
21 #include <miscfs/specfs/specdev.h>
22 
23 #include <ufs/ufs/quota.h>
24 #include <ufs/ufs/inode.h>
25 #include <ufs/ufs/ufsmount.h>
26 #include <ufs/ufs/ufs_extern.h>
27 
28 /*
29  * Flag to permit forcible unmounting.
30  */
31 int doforce = 1;
32 
33 /*
34  * Make a filesystem operational.
35  * Nothing to do at the moment.
36  */
37 /* ARGSUSED */
38 int
39 ufs_start(mp, flags, p)
40 	struct mount *mp;
41 	int flags;
42 	struct proc *p;
43 {
44 
45 	return (0);
46 }
47 
48 /*
49  * Check to see if a filesystem is mounted on a block device.
50  */
51 int
52 ufs_mountedon(vp)
53 	register struct vnode *vp;
54 {
55 	register struct vnode *vq;
56 
57 	if (vp->v_specflags & SI_MOUNTEDON)
58 		return (EBUSY);
59 	if (vp->v_flag & VALIASED) {
60 		for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
61 			if (vq->v_rdev != vp->v_rdev ||
62 			    vq->v_type != vp->v_type)
63 				continue;
64 			if (vq->v_specflags & SI_MOUNTEDON)
65 				return (EBUSY);
66 		}
67 	}
68 	return (0);
69 }
70 
71 /*
72  * Do operations associated with quotas
73  */
74 int
75 ufs_quotactl(mp, cmds, uid, arg, p)
76 	struct mount *mp;
77 	int cmds;
78 	uid_t uid;
79 	caddr_t arg;
80 	struct proc *p;
81 {
82 	int cmd, type, error;
83 
84 #ifndef QUOTA
85 	return (EOPNOTSUPP);
86 #else
87 	if (uid == -1)
88 		uid = p->p_cred->p_ruid;
89 	cmd = cmds >> SUBCMDSHIFT;
90 
91 	switch (cmd) {
92 	case Q_GETQUOTA:
93 	case Q_SYNC:
94 		if (uid == p->p_cred->p_ruid)
95 			break;
96 		/* fall through */
97 	default:
98 		if (error = suser(p->p_ucred, &p->p_acflag))
99 			return (error);
100 	}
101 
102 	type = cmd & SUBCMDMASK;
103 	if ((u_int)type >= MAXQUOTAS)
104 		return (EINVAL);
105 
106 	switch (cmd) {
107 
108 	case Q_QUOTAON:
109 		return (quotaon(p, mp, type, arg));
110 
111 	case Q_QUOTAOFF:
112 		if (vfs_busy(mp))
113 			return (0);
114 		error = quotaoff(p, mp, type);
115 		vfs_unbusy(mp);
116 		return (error);
117 
118 	case Q_SETQUOTA:
119 		return (setquota(mp, uid, type, arg));
120 
121 	case Q_SETUSE:
122 		return (setuse(mp, uid, type, arg));
123 
124 	case Q_GETQUOTA:
125 		return (getquota(mp, uid, type, arg));
126 
127 	case Q_SYNC:
128 		if (vfs_busy(mp))
129 			return (0);
130 		error = qsync(mp);
131 		vfs_unbusy(mp);
132 		return (error);
133 
134 	default:
135 		return (EINVAL);
136 	}
137 	/* NOTREACHED */
138 #endif
139 }
140 
141 int syncprt = 0;
142 
143 /*
144  * Print out statistics on the current allocation of the buffer pool.
145  * Can be enabled to print out on every ``sync'' by setting "syncprt"
146  * above.
147  */
148 void
149 ufs_bufstats()
150 {
151 	int s, i, j, count;
152 	register struct buf *bp, *dp;
153 	int counts[MAXBSIZE/CLBYTES+1];
154 	static char *bname[BQUEUES] = { "LOCKED", "LRU", "AGE", "EMPTY" };
155 
156 	for (bp = bfreelist, i = 0; bp < &bfreelist[BQUEUES]; bp++, i++) {
157 		count = 0;
158 		for (j = 0; j <= MAXBSIZE/CLBYTES; j++)
159 			counts[j] = 0;
160 		s = splbio();
161 		for (dp = bp->av_forw; dp != bp; dp = dp->av_forw) {
162 			counts[dp->b_bufsize/CLBYTES]++;
163 			count++;
164 		}
165 		splx(s);
166 		printf("%s: total-%d", bname[i], count);
167 		for (j = 0; j <= MAXBSIZE/CLBYTES; j++)
168 			if (counts[j] != 0)
169 				printf(", %d-%d", j * CLBYTES, counts[j]);
170 		printf("\n");
171 	}
172 }
173 
174 /*
175  * Build hash lists of net addresses and hang them off the mount point.
176  * Called by ufs_mount() to set up the lists of export addresses.
177  */
178 ufs_hang_addrlist(mp, argp)
179 	struct mount *mp;
180 	struct ufs_args *argp;
181 {
182 	register struct netcred *np;
183 	register struct radix_node_head *rnh;
184 	register int i;
185 	struct radix_node *rn;
186 	struct ufsmount *ump;
187 	struct sockaddr *saddr, *smask = 0;
188 	struct domain *dom;
189 	int error;
190 
191 	if (argp->slen == 0) {
192 		if (mp->mnt_flag & MNT_DEFEXPORTED)
193 			return (EPERM);
194 		np = &ump->um_defexported;
195 		np->netc_exflags = argp->exflags;
196 		np->netc_anon = argp->anon;
197 		np->netc_anon.cr_ref = 1;
198 		mp->mnt_flag |= MNT_DEFEXPORTED;
199 		return (0);
200 	}
201 	i = sizeof(struct netcred) + argp->slen + argp->msklen;
202 	np = (struct netcred *)malloc(i, M_NETADDR, M_WAITOK);
203 	bzero((caddr_t)np, i);
204 	saddr = (struct sockaddr *)(np + 1);
205 	if (error = copyin(argp->saddr, (caddr_t)saddr, argp->slen))
206 		goto out;
207 	if (saddr->sa_len > argp->slen)
208 		saddr->sa_len = argp->slen;
209 	if (argp->msklen) {
210 		smask = (struct sockaddr *)((caddr_t)saddr + argp->slen);
211 		if (error = copyin(argp->saddr, (caddr_t)smask, argp->msklen))
212 			goto out;
213 		if (smask->sa_len > argp->msklen)
214 			smask->sa_len = argp->msklen;
215 	}
216 	ump = VFSTOUFS(mp);
217 	i = saddr->sa_family;
218 	if ((rnh = ump->um_rtable[i]) == 0) {
219 		/*
220 		 * Seems silly to initialize every AF when most are not
221 		 * used, do so on demand here
222 		 */
223 		for (dom = domains; dom; dom = dom->dom_next)
224 			if (dom->dom_family == i && dom->dom_rtattach) {
225 				dom->dom_rtattach((void **)&ump->um_rtable[i],
226 					dom->dom_rtoffset);
227 				break;
228 			}
229 		if ((rnh = ump->um_rtable[i]) == 0) {
230 			error = ENOBUFS;
231 			goto out;
232 		}
233 	}
234 	rn = (*rnh->rnh_add)((caddr_t)saddr, (caddr_t)smask, rnh->rnh_treetop,
235 	    np->netc_rnodes);
236 	if (rn == 0 || np != (struct netcred *)rn) { /* already exists */
237 		error = EPERM;
238 		goto out;
239 	}
240 	np->netc_exflags = argp->exflags;
241 	np->netc_anon = argp->anon;
242 	np->netc_anon.cr_ref = 1;
243 	return (0);
244 out:
245 	free(np, M_NETADDR);
246 	return (error);
247 }
248 
249 /* ARGSUSED */
250 static int
251 ufs_free_netcred(rn, w)
252 	struct radix_node *rn;
253 	caddr_t w;
254 {
255 	free((caddr_t)rn, M_NETADDR);
256 }
257 
258 
259 /*
260  * Free the net address hash lists that are hanging off the mount points.
261  */
262 void
263 ufs_free_addrlist(ump)
264 	struct ufsmount *ump;
265 {
266 	register int i;
267 	register struct radix_node_head *rnh;
268 
269 	for (i = 0; i <= AF_MAX; i++)
270 		if (rnh = ump->um_rtable[i]) {
271 			(*rnh->rnh_walk)(rnh->rnh_treetop,
272 				ufs_free_netcred, (caddr_t)0);
273 			free((caddr_t)rnh, M_RTABLE);
274 			ump->um_rtable[i] = 0;
275 		}
276 }
277 
278 /*
279  * This is the generic part of fhtovp called after the underlying
280  * filesystem has validated the file handle.
281  *
282  * Verify that a host should have access to a filesystem, and if so
283  * return a vnode for the presented file handle.
284  */
285 int
286 ufs_check_export(mp, fhp, nam, vpp, exflagsp, credanonp)
287 	register struct mount *mp;
288 	struct fid *fhp;
289 	struct mbuf *nam;
290 	struct vnode **vpp;
291 	int *exflagsp;
292 	struct ucred **credanonp;
293 {
294 	register struct ufid *ufhp;
295 	register struct inode *ip;
296 	register struct netcred *np;
297 	register struct ufsmount *ump = VFSTOUFS(mp);
298 	register struct radix_node_head *rnh;
299 	struct vnode *nvp;
300 	struct sockaddr *saddr;
301 	int error;
302 
303 	/*
304 	 * Get the export permission structure for this <mp, client> tuple.
305 	 */
306 	if ((mp->mnt_flag & MNT_EXPORTED) == 0)
307 		return (EACCES);
308 	if (nam == NULL) {
309 		np = NULL;
310 	} else {
311 		saddr = mtod(nam, struct sockaddr *);
312 		rnh = ump->um_rtable[saddr->sa_family];
313 		if (rnh == NULL) {
314 			np = NULL;
315 		} else {
316 			np = (struct netcred *)
317 			    (*rnh->rnh_match)((caddr_t)saddr, rnh->rnh_treetop);
318 			if (np->netc_rnodes->rn_flags & RNF_ROOT)
319 				np = NULL;
320 		}
321 	}
322 	if (np == NULL) {
323 		/*
324 		 * If no address match, use the default if it exists.
325 		 */
326 		if ((mp->mnt_flag & MNT_DEFEXPORTED) == 0)
327 			return (EACCES);
328 		np = &ump->um_defexported;
329 	}
330 	if (error = VFS_VGET(mp, ufhp->ufid_ino, &nvp)) {
331 		*vpp = NULLVP;
332 		return (error);
333 	}
334 	ip = VTOI(nvp);
335 	if (ip->i_mode == 0 || ip->i_gen != ufhp->ufid_gen) {
336 		ufs_iput(ip);
337 		*vpp = NULLVP;
338 		return (ESTALE);
339 	}
340 	*vpp = nvp;
341 	*exflagsp = np->netc_exflags;
342 	*credanonp = &np->netc_anon;
343 	return (0);
344 }
345