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