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