1 /* 2 * Copyright (c) 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)ufs_vfsops.c 8.1 (Berkeley) 06/11/93 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 ump = VFSTOUFS(mp); 159 if (argp->slen == 0) { 160 if (mp->mnt_flag & MNT_DEFEXPORTED) 161 return (EPERM); 162 np = &ump->um_defexported; 163 np->netc_exflags = argp->exflags; 164 np->netc_anon = argp->anon; 165 np->netc_anon.cr_ref = 1; 166 mp->mnt_flag |= MNT_DEFEXPORTED; 167 return (0); 168 } 169 i = sizeof(struct netcred) + argp->slen + argp->msklen; 170 np = (struct netcred *)malloc(i, M_NETADDR, M_WAITOK); 171 bzero((caddr_t)np, i); 172 saddr = (struct sockaddr *)(np + 1); 173 if (error = copyin(argp->saddr, (caddr_t)saddr, argp->slen)) 174 goto out; 175 if (saddr->sa_len > argp->slen) 176 saddr->sa_len = argp->slen; 177 if (argp->msklen) { 178 smask = (struct sockaddr *)((caddr_t)saddr + argp->slen); 179 if (error = copyin(argp->saddr, (caddr_t)smask, argp->msklen)) 180 goto out; 181 if (smask->sa_len > argp->msklen) 182 smask->sa_len = argp->msklen; 183 } 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_addaddr)((caddr_t)saddr, (caddr_t)smask, rnh, 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 register struct radix_node_head *rnh = (struct radix_node_head *)w; 223 224 (*rnh->rnh_deladdr)(rn->rn_key, rn->rn_mask, rnh); 225 free((caddr_t)rn, M_NETADDR); 226 return (0); 227 } 228 229 230 /* 231 * Free the net address hash lists that are hanging off the mount points. 232 */ 233 void 234 ufs_free_addrlist(ump) 235 struct ufsmount *ump; 236 { 237 register int i; 238 register struct radix_node_head *rnh; 239 240 for (i = 0; i <= AF_MAX; i++) 241 if (rnh = ump->um_rtable[i]) { 242 (*rnh->rnh_walktree)(rnh, ufs_free_netcred, 243 (caddr_t)rnh); 244 free((caddr_t)rnh, M_RTABLE); 245 ump->um_rtable[i] = 0; 246 } 247 } 248 249 /* 250 * This is the generic part of fhtovp called after the underlying 251 * filesystem has validated the file handle. 252 * 253 * Verify that a host should have access to a filesystem, and if so 254 * return a vnode for the presented file handle. 255 */ 256 int 257 ufs_check_export(mp, ufhp, nam, vpp, exflagsp, credanonp) 258 register struct mount *mp; 259 struct ufid *ufhp; 260 struct mbuf *nam; 261 struct vnode **vpp; 262 int *exflagsp; 263 struct ucred **credanonp; 264 { 265 register struct inode *ip; 266 register struct netcred *np; 267 register struct ufsmount *ump = VFSTOUFS(mp); 268 register struct radix_node_head *rnh; 269 struct vnode *nvp; 270 struct sockaddr *saddr; 271 int error; 272 273 /* 274 * Get the export permission structure for this <mp, client> tuple. 275 */ 276 if ((mp->mnt_flag & MNT_EXPORTED) == 0) 277 return (EACCES); 278 np = NULL; 279 if (nam != NULL) { 280 saddr = mtod(nam, struct sockaddr *); 281 rnh = ump->um_rtable[saddr->sa_family]; 282 if (rnh != NULL) { 283 np = (struct netcred *) 284 (*rnh->rnh_matchaddr)((caddr_t)saddr, rnh); 285 if (np && np->netc_rnodes->rn_flags & RNF_ROOT) 286 np = NULL; 287 } 288 } 289 if (np == NULL) { 290 /* 291 * If no address match, use the default if it exists. 292 */ 293 if ((mp->mnt_flag & MNT_DEFEXPORTED) == 0) 294 return (EACCES); 295 np = &ump->um_defexported; 296 } 297 if (error = VFS_VGET(mp, ufhp->ufid_ino, &nvp)) { 298 *vpp = NULLVP; 299 return (error); 300 } 301 ip = VTOI(nvp); 302 if (ip->i_mode == 0 || ip->i_gen != ufhp->ufid_gen) { 303 vput(nvp); 304 *vpp = NULLVP; 305 return (ESTALE); 306 } 307 *vpp = nvp; 308 *exflagsp = np->netc_exflags; 309 *credanonp = &np->netc_anon; 310 return (0); 311 } 312