xref: /original-bsd/sys/ufs/ffs/ufs_vfsops.c (revision 59b27db1)
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.61 (Berkeley) 07/13/92
8  */
9 
10 #include <sys/param.h>
11 #include <sys/mount.h>
12 #include <sys/proc.h>
13 #include <sys/buf.h>
14 #include <sys/vnode.h>
15 #include <sys/socket.h>
16 #include <sys/malloc.h>
17 #include <sys/mbuf.h>
18 #include <netinet/in.h>
19 
20 #include <miscfs/specfs/specdev.h>
21 
22 #include <ufs/ufs/quota.h>
23 #include <ufs/ufs/inode.h>
24 #include <ufs/ufs/ufsmount.h>
25 #include <ufs/ufs/ufs_extern.h>
26 
27 /*
28  * Flag to permit forcible unmounting.
29  */
30 int doforce = 1;
31 
32 /*
33  * Make a filesystem operational.
34  * Nothing to do at the moment.
35  */
36 /* ARGSUSED */
37 int
38 ufs_start(mp, flags, p)
39 	struct mount *mp;
40 	int flags;
41 	struct proc *p;
42 {
43 
44 	return (0);
45 }
46 
47 /*
48  * Check to see if a filesystem is mounted on a block device.
49  */
50 int
51 ufs_mountedon(vp)
52 	register struct vnode *vp;
53 {
54 	register struct vnode *vq;
55 
56 	if (vp->v_specflags & SI_MOUNTEDON)
57 		return (EBUSY);
58 	if (vp->v_flag & VALIASED) {
59 		for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
60 			if (vq->v_rdev != vp->v_rdev ||
61 			    vq->v_type != vp->v_type)
62 				continue;
63 			if (vq->v_specflags & SI_MOUNTEDON)
64 				return (EBUSY);
65 		}
66 	}
67 	return (0);
68 }
69 
70 /*
71  * Do operations associated with quotas
72  */
73 int
74 ufs_quotactl(mp, cmds, uid, arg, p)
75 	struct mount *mp;
76 	int cmds;
77 	uid_t uid;
78 	caddr_t arg;
79 	struct proc *p;
80 {
81 	int cmd, type, error;
82 
83 #ifndef QUOTA
84 	return (EOPNOTSUPP);
85 #else
86 	if (uid == -1)
87 		uid = p->p_cred->p_ruid;
88 	cmd = cmds >> SUBCMDSHIFT;
89 
90 	switch (cmd) {
91 	case Q_GETQUOTA:
92 	case Q_SYNC:
93 		if (uid == p->p_cred->p_ruid)
94 			break;
95 		/* fall through */
96 	default:
97 		if (error = suser(p->p_ucred, &p->p_acflag))
98 			return (error);
99 	}
100 
101 	type = cmd & SUBCMDMASK;
102 	if ((u_int)type >= MAXQUOTAS)
103 		return (EINVAL);
104 
105 	switch (cmd) {
106 
107 	case Q_QUOTAON:
108 		return (quotaon(p, mp, type, arg));
109 
110 	case Q_QUOTAOFF:
111 		if (vfs_busy(mp))
112 			return (0);
113 		error = quotaoff(p, mp, type);
114 		vfs_unbusy(mp);
115 		return (error);
116 
117 	case Q_SETQUOTA:
118 		return (setquota(mp, uid, type, arg));
119 
120 	case Q_SETUSE:
121 		return (setuse(mp, uid, type, arg));
122 
123 	case Q_GETQUOTA:
124 		return (getquota(mp, uid, type, arg));
125 
126 	case Q_SYNC:
127 		if (vfs_busy(mp))
128 			return (0);
129 		error = qsync(mp);
130 		vfs_unbusy(mp);
131 		return (error);
132 
133 	default:
134 		return (EINVAL);
135 	}
136 	/* NOTREACHED */
137 #endif
138 }
139 
140 int syncprt = 0;
141 
142 /*
143  * Print out statistics on the current allocation of the buffer pool.
144  * Can be enabled to print out on every ``sync'' by setting "syncprt"
145  * above.
146  */
147 void
148 ufs_bufstats()
149 {
150 	int s, i, j, count;
151 	register struct buf *bp, *dp;
152 	int counts[MAXBSIZE/CLBYTES+1];
153 	static char *bname[BQUEUES] = { "LOCKED", "LRU", "AGE", "EMPTY" };
154 
155 	for (bp = bfreelist, i = 0; bp < &bfreelist[BQUEUES]; bp++, i++) {
156 		count = 0;
157 		for (j = 0; j <= MAXBSIZE/CLBYTES; j++)
158 			counts[j] = 0;
159 		s = splbio();
160 		for (dp = bp->av_forw; dp != bp; dp = dp->av_forw) {
161 			counts[dp->b_bufsize/CLBYTES]++;
162 			count++;
163 		}
164 		splx(s);
165 		printf("%s: total-%d", bname[i], count);
166 		for (j = 0; j <= MAXBSIZE/CLBYTES; j++)
167 			if (counts[j] != 0)
168 				printf(", %d-%d", j * CLBYTES, counts[j]);
169 		printf("\n");
170 	}
171 }
172 
173 /*
174  * Build hash lists of net addresses and hang them off the mount point.
175  * Called by ufs_mount() to set up the lists of export addresses.
176  */
177 ufs_hang_addrlist(mp, argp)
178 	struct mount *mp;
179 	struct ufs_args *argp;
180 {
181 	register struct netaddrhash *np, **hnp;
182 	register int i;
183 	struct ufsmount *ump;
184 	struct sockaddr *saddr;
185 	struct mbuf *nam, *msk = (struct mbuf *)0;
186 	union nethostaddr netmsk;
187 	int error;
188 
189 	if (error = sockargs(&nam, (caddr_t)argp->saddr, argp->slen, MT_SONAME))
190 		return (error);
191 	saddr = mtod(nam, struct sockaddr *);
192 	ump = VFSTOUFS(mp);
193 	if (saddr->sa_family == AF_INET &&
194 		((struct sockaddr_in *)saddr)->sin_addr.s_addr == INADDR_ANY) {
195 		m_freem(nam);
196 		if (mp->mnt_flag & MNT_DEFEXPORTED)
197 			return (EPERM);
198 		np = &ump->um_defexported;
199 		np->neth_exflags = argp->exflags;
200 		np->neth_anon = argp->anon;
201 		np->neth_anon.cr_ref = 1;
202 		mp->mnt_flag |= MNT_DEFEXPORTED;
203 		return (0);
204 	}
205 	if (argp->msklen > 0) {
206 		if (error = sockargs(&msk, (caddr_t)argp->smask, argp->msklen,
207 		    MT_SONAME)) {
208 			m_freem(nam);
209 			return (error);
210 		}
211 
212 		/*
213 		 * Scan all the hash lists to check against duplications.
214 		 * For the net list, try both masks to catch a subnet
215 		 * of another network.
216 		 */
217 		hnp = &ump->um_netaddr[NETMASK_HASH];
218 		np = *hnp;
219 		if (saddr->sa_family == AF_INET)
220 			netmsk.had_inetaddr =
221 			    mtod(msk, struct sockaddr_in *)->sin_addr.s_addr;
222 		else
223 			netmsk.had_nam = msk;
224 		while (np) {
225 			if (netaddr_match(np->neth_family, &np->neth_haddr,
226 			    &np->neth_hmask, nam) ||
227 			    netaddr_match(np->neth_family, &np->neth_haddr,
228 			    &netmsk, nam)) {
229 				m_freem(nam);
230 				m_freem(msk);
231 				return (EPERM);
232 			}
233 			np = np->neth_next;
234 		}
235 		for (i = 0; i < NETHASHSZ; i++) {
236 			np = ump->um_netaddr[i];
237 			while (np) {
238 				if (netaddr_match(np->neth_family,
239 				    &np->neth_haddr, &netmsk, nam)) {
240 					m_freem(nam);
241 					m_freem(msk);
242 					return (EPERM);
243 				}
244 				np = np->neth_next;
245 			}
246 		}
247 	} else {
248 		hnp = &ump->um_netaddr[NETADDRHASH(saddr)];
249 		np = ump->um_netaddr[NETMASK_HASH];
250 		while (np) {
251 			if (netaddr_match(np->neth_family, &np->neth_haddr,
252 			    &np->neth_hmask, nam)) {
253 				m_freem(nam);
254 				return (EPERM);
255 			}
256 			np = np->neth_next;
257 		}
258 		np = *hnp;
259 		while (np) {
260 			if (netaddr_match(np->neth_family, &np->neth_haddr,
261 			    (union nethostaddr *)0, nam)) {
262 				m_freem(nam);
263 				return (EPERM);
264 			}
265 			np = np->neth_next;
266 		}
267 	}
268 	np = (struct netaddrhash *) malloc(sizeof(struct netaddrhash),
269 	    M_NETADDR, M_WAITOK);
270 	np->neth_family = saddr->sa_family;
271 	if (saddr->sa_family == AF_INET) {
272 		np->neth_inetaddr =
273 		    ((struct sockaddr_in *)saddr)->sin_addr.s_addr;
274 		m_freem(nam);
275 		if (msk) {
276 			np->neth_inetmask = netmsk.had_inetaddr;
277 			m_freem(msk);
278 			if (np->neth_inetaddr &~ np->neth_inetmask)
279 				return (EPERM);
280 		} else
281 			np->neth_inetmask = 0xffffffff;
282 	} else {
283 		np->neth_nam = nam;
284 		np->neth_msk = msk;
285 	}
286 	np->neth_exflags = argp->exflags;
287 	np->neth_anon = argp->anon;
288 	np->neth_anon.cr_ref = 1;
289 	np->neth_next = *hnp;
290 	*hnp = np;
291 	return (0);
292 }
293 
294 /*
295  * Free the net address hash lists that are hanging off the mount points.
296  */
297 void
298 ufs_free_addrlist(ump)
299 	struct ufsmount *ump;
300 {
301 	register struct netaddrhash *np, *onp;
302 	register int i;
303 
304 	for (i = 0; i <= NETHASHSZ; i++) {
305 		np = ump->um_netaddr[i];
306 		ump->um_netaddr[i] = (struct netaddrhash *)0;
307 		while (np) {
308 			onp = np;
309 			np = np->neth_next;
310 			if (onp->neth_family != AF_INET) {
311 				m_freem(onp->neth_nam);
312 				m_freem(onp->neth_msk);
313 			}
314 			free((caddr_t)onp, M_NETADDR);
315 		}
316 	}
317 }
318