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.64 (Berkeley) 09/24/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 /* 142 * Build hash lists of net addresses and hang them off the mount point. 143 * Called by ufs_mount() to set up the lists of export addresses. 144 */ 145 ufs_hang_addrlist(mp, argp) 146 struct mount *mp; 147 struct ufs_args *argp; 148 { 149 register struct netcred *np; 150 register struct radix_node_head *rnh; 151 register int i; 152 struct radix_node *rn; 153 struct ufsmount *ump; 154 struct sockaddr *saddr, *smask = 0; 155 struct domain *dom; 156 int error; 157 158 if (argp->slen == 0) { 159 if (mp->mnt_flag & MNT_DEFEXPORTED) 160 return (EPERM); 161 np = &ump->um_defexported; 162 np->netc_exflags = argp->exflags; 163 np->netc_anon = argp->anon; 164 np->netc_anon.cr_ref = 1; 165 mp->mnt_flag |= MNT_DEFEXPORTED; 166 return (0); 167 } 168 i = sizeof(struct netcred) + argp->slen + argp->msklen; 169 np = (struct netcred *)malloc(i, M_NETADDR, M_WAITOK); 170 bzero((caddr_t)np, i); 171 saddr = (struct sockaddr *)(np + 1); 172 if (error = copyin(argp->saddr, (caddr_t)saddr, argp->slen)) 173 goto out; 174 if (saddr->sa_len > argp->slen) 175 saddr->sa_len = argp->slen; 176 if (argp->msklen) { 177 smask = (struct sockaddr *)((caddr_t)saddr + argp->slen); 178 if (error = copyin(argp->saddr, (caddr_t)smask, argp->msklen)) 179 goto out; 180 if (smask->sa_len > argp->msklen) 181 smask->sa_len = argp->msklen; 182 } 183 ump = VFSTOUFS(mp); 184 i = saddr->sa_family; 185 if ((rnh = ump->um_rtable[i]) == 0) { 186 /* 187 * Seems silly to initialize every AF when most are not 188 * used, do so on demand here 189 */ 190 for (dom = domains; dom; dom = dom->dom_next) 191 if (dom->dom_family == i && dom->dom_rtattach) { 192 dom->dom_rtattach((void **)&ump->um_rtable[i], 193 dom->dom_rtoffset); 194 break; 195 } 196 if ((rnh = ump->um_rtable[i]) == 0) { 197 error = ENOBUFS; 198 goto out; 199 } 200 } 201 rn = (*rnh->rnh_add)((caddr_t)saddr, (caddr_t)smask, rnh->rnh_treetop, 202 np->netc_rnodes); 203 if (rn == 0 || np != (struct netcred *)rn) { /* already exists */ 204 error = EPERM; 205 goto out; 206 } 207 np->netc_exflags = argp->exflags; 208 np->netc_anon = argp->anon; 209 np->netc_anon.cr_ref = 1; 210 return (0); 211 out: 212 free(np, M_NETADDR); 213 return (error); 214 } 215 216 /* ARGSUSED */ 217 static int 218 ufs_free_netcred(rn, w) 219 struct radix_node *rn; 220 caddr_t w; 221 { 222 free((caddr_t)rn, M_NETADDR); 223 } 224 225 226 /* 227 * Free the net address hash lists that are hanging off the mount points. 228 */ 229 void 230 ufs_free_addrlist(ump) 231 struct ufsmount *ump; 232 { 233 register int i; 234 register struct radix_node_head *rnh; 235 236 for (i = 0; i <= AF_MAX; i++) 237 if (rnh = ump->um_rtable[i]) { 238 (*rnh->rnh_walk)(rnh->rnh_treetop, 239 ufs_free_netcred, (caddr_t)0); 240 free((caddr_t)rnh, M_RTABLE); 241 ump->um_rtable[i] = 0; 242 } 243 } 244 245 /* 246 * This is the generic part of fhtovp called after the underlying 247 * filesystem has validated the file handle. 248 * 249 * Verify that a host should have access to a filesystem, and if so 250 * return a vnode for the presented file handle. 251 */ 252 int 253 ufs_check_export(mp, ufhp, nam, vpp, exflagsp, credanonp) 254 register struct mount *mp; 255 struct ufid *ufhp; 256 struct mbuf *nam; 257 struct vnode **vpp; 258 int *exflagsp; 259 struct ucred **credanonp; 260 { 261 register struct inode *ip; 262 register struct netcred *np; 263 register struct ufsmount *ump = VFSTOUFS(mp); 264 register struct radix_node_head *rnh; 265 struct vnode *nvp; 266 struct sockaddr *saddr; 267 int error; 268 269 /* 270 * Get the export permission structure for this <mp, client> tuple. 271 */ 272 if ((mp->mnt_flag & MNT_EXPORTED) == 0) 273 return (EACCES); 274 if (nam == NULL) { 275 np = NULL; 276 } else { 277 saddr = mtod(nam, struct sockaddr *); 278 rnh = ump->um_rtable[saddr->sa_family]; 279 if (rnh == NULL) { 280 np = NULL; 281 } else { 282 np = (struct netcred *) 283 (*rnh->rnh_match)((caddr_t)saddr, rnh->rnh_treetop); 284 if (np->netc_rnodes->rn_flags & RNF_ROOT) 285 np = NULL; 286 } 287 } 288 if (np == NULL) { 289 /* 290 * If no address match, use the default if it exists. 291 */ 292 if ((mp->mnt_flag & MNT_DEFEXPORTED) == 0) 293 return (EACCES); 294 np = &ump->um_defexported; 295 } 296 if (error = VFS_VGET(mp, ufhp->ufid_ino, &nvp)) { 297 *vpp = NULLVP; 298 return (error); 299 } 300 ip = VTOI(nvp); 301 if (ip->i_mode == 0 || ip->i_gen != ufhp->ufid_gen) { 302 ufs_iput(ip); 303 *vpp = NULLVP; 304 return (ESTALE); 305 } 306 *vpp = nvp; 307 *exflagsp = np->netc_exflags; 308 *credanonp = &np->netc_anon; 309 return (0); 310 } 311