1 /* 2 * Copyright (c) 1992, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software donated to Berkeley by 6 * the UCLA Ficus project. 7 * 8 * %sccs.include.redist.c% 9 * 10 * @(#)umap_vnops.c 8.1 (Berkeley) 06/10/93 11 */ 12 13 /* 14 * Umap Layer 15 */ 16 17 #include <sys/param.h> 18 #include <sys/systm.h> 19 #include <sys/time.h> 20 #include <sys/types.h> 21 #include <sys/vnode.h> 22 #include <sys/mount.h> 23 #include <sys/namei.h> 24 #include <sys/malloc.h> 25 #include <sys/buf.h> 26 #include <miscfs/umapfs/umap.h> 27 28 29 int umap_bug_bypass = 0; /* for debugging: enables bypass printf'ing */ 30 31 /* 32 * This is the 10-Apr-92 bypass routine. 33 * See null_vnops.c:null_bypass for more details. 34 */ 35 int 36 umap_bypass(ap) 37 struct vop_generic_args /* { 38 struct vnodeop_desc *a_desc; 39 <other random data follows, presumably> 40 } */ *ap; 41 { 42 extern int (**umap_vnodeop_p)(); /* not extern, really "forward" */ 43 int *mapdata, nentries ; 44 int *gmapdata, gnentries ; 45 struct ucred **credpp,*credp, *savecredp, *saveucredp, *savecompcredp ; 46 struct ucred *compcredp; 47 register struct vnode **this_vp_p; 48 int error; 49 struct vnode *old_vps[VDESC_MAX_VPS], *vp1; 50 struct vnode **vps_p[VDESC_MAX_VPS]; 51 struct vnode ***vppp; 52 struct vnodeop_desc *descp = ap->a_desc; 53 int reles, i; 54 struct componentname **compnamepp; 55 56 if (umap_bug_bypass) 57 printf ("umap_bypass: %s\n", descp->vdesc_name); 58 59 #ifdef SAFETY 60 /* 61 * We require at least one vp. 62 */ 63 if (descp->vdesc_vp_offsets == NULL || 64 descp->vdesc_vp_offsets[0] == VDESC_NO_OFFSET) 65 panic ("umap_bypass: no vp's in map.\n"); 66 #endif 67 68 /* 69 * Map the vnodes going in. 70 * Later, we'll invoke the operation based on 71 * the first mapped vnode's operation vector. 72 */ 73 reles = descp->vdesc_flags; 74 for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) { 75 if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET) 76 break; /* bail out at end of list */ 77 vps_p[i] = this_vp_p = 78 VOPARG_OFFSETTO(struct vnode**,descp->vdesc_vp_offsets[i],ap); 79 80 if (i == 0) 81 { 82 vp1 = *vps_p[0]; 83 } 84 85 /* 86 * We're not guaranteed that any but the first vnode 87 * are of our type. Check for and don't map any 88 * that aren't. (Must map first vp or vclean fails.) 89 */ 90 91 if (i && (*this_vp_p)->v_op != umap_vnodeop_p) { 92 old_vps[i] = NULL; 93 } else { 94 old_vps[i] = *this_vp_p; 95 *(vps_p[i]) = UMAPVPTOLOWERVP(*this_vp_p); 96 if (reles & 1) 97 VREF(*this_vp_p); 98 } 99 100 } 101 102 /* 103 * Fix the credentials. (That's the purpose of this layer.) 104 */ 105 106 if (descp->vdesc_cred_offset != VDESC_NO_OFFSET) { 107 108 credpp = VOPARG_OFFSETTO(struct ucred**, 109 descp->vdesc_cred_offset, ap); 110 111 /* Save old values */ 112 113 savecredp = (*credpp); 114 (*credpp) = crdup(savecredp); 115 credp = *credpp; 116 117 if (umap_bug_bypass && credp->cr_uid != 0 ) 118 printf("umap_bypass: user was %d, group %d\n", 119 credp->cr_uid,credp->cr_gid); 120 121 /* Map all ids in the credential structure. */ 122 123 umap_mapids(vp1->v_mount,credp); 124 125 if (umap_bug_bypass && credp->cr_uid != 0 ) 126 printf("umap_bypass: user now %d, group %d\n", 127 credp->cr_uid,credp->cr_gid); 128 } 129 130 /* BSD often keeps a credential in the componentname structure 131 * for speed. If there is one, it better get mapped, too. 132 */ 133 134 if (descp->vdesc_componentname_offset != VDESC_NO_OFFSET) { 135 136 compnamepp = VOPARG_OFFSETTO(struct componentname**, 137 descp->vdesc_componentname_offset, ap); 138 139 compcredp = (*compnamepp)->cn_cred; 140 savecompcredp = compcredp; 141 compcredp = (*compnamepp)->cn_cred = crdup(savecompcredp); 142 143 if (umap_bug_bypass && compcredp->cr_uid != 0 ) 144 printf("umap_bypass: component credit user was %d, group %d\n", 145 compcredp->cr_uid,compcredp->cr_gid); 146 147 /* Map all ids in the credential structure. */ 148 149 umap_mapids(vp1->v_mount,compcredp); 150 151 if (umap_bug_bypass && compcredp->cr_uid != 0 ) 152 printf("umap_bypass: component credit user now %d, group %d\n", 153 compcredp->cr_uid,compcredp->cr_gid); 154 } 155 156 /* 157 * Call the operation on the lower layer 158 * with the modified argument structure. 159 */ 160 error = VCALL(*(vps_p[0]), descp->vdesc_offset, ap); 161 162 /* 163 * Maintain the illusion of call-by-value 164 * by restoring vnodes in the argument structure 165 * to their original value. 166 */ 167 reles = descp->vdesc_flags; 168 for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) { 169 if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET) 170 break; /* bail out at end of list */ 171 if (old_vps[i]) { 172 *(vps_p[i]) = old_vps[i]; 173 if (reles & 1) 174 vrele(*(vps_p[i])); 175 }; 176 }; 177 178 /* 179 * Map the possible out-going vpp 180 * (Assumes that the lower layer always returns 181 * a VREF'ed vpp unless it gets an error.) 182 */ 183 if (descp->vdesc_vpp_offset != VDESC_NO_OFFSET && 184 !(descp->vdesc_flags & VDESC_NOMAP_VPP) && 185 !error) { 186 if (descp->vdesc_flags & VDESC_VPP_WILLRELE) 187 goto out; 188 vppp = VOPARG_OFFSETTO(struct vnode***, 189 descp->vdesc_vpp_offset,ap); 190 error = umap_node_create(old_vps[0]->v_mount, **vppp, *vppp); 191 }; 192 193 out: 194 /* 195 * Free duplicate cred structure and restore old one. 196 */ 197 if (descp->vdesc_cred_offset != VDESC_NO_OFFSET) { 198 if (umap_bug_bypass && credp->cr_uid != 0 ) 199 printf("umap_bypass: returning-user was %d\n", credp->cr_uid); 200 201 crfree(credp); 202 (*credpp) = savecredp; 203 if (umap_bug_bypass && (*credpp)->cr_uid != 0 ) 204 printf("umap_bypass: returning-user now %d\n\n", 205 (*credpp)->cr_uid); 206 } 207 208 if (descp->vdesc_componentname_offset != VDESC_NO_OFFSET) { 209 if (umap_bug_bypass && compcredp->cr_uid != 0 ) 210 printf("umap_bypass: returning-component-user was %d\n", 211 compcredp->cr_uid); 212 213 crfree(compcredp); 214 (*compnamepp)->cn_cred = savecompcredp; 215 if (umap_bug_bypass && (*credpp)->cr_uid != 0 ) 216 printf("umap_bypass: returning-component-user now %d\n\n", 217 compcredp->cr_uid); 218 } 219 220 return (error); 221 } 222 223 224 /* 225 * We handle getattr to change the fsid. 226 */ 227 int 228 umap_getattr(ap) 229 struct vop_getattr_args /* { 230 struct vnode *a_vp; 231 struct vattr *a_vap; 232 struct ucred *a_cred; 233 struct proc *a_p; 234 } */ *ap; 235 { 236 short uid, gid; 237 int error, tmpid, *mapdata, nentries, *gmapdata, gnentries; 238 struct vnode **vp1p; 239 struct vnodeop_desc *descp = ap->a_desc; 240 241 if (error = umap_bypass(ap)) 242 return (error); 243 /* Requires that arguments be restored. */ 244 ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; 245 246 /* 247 * Umap needs to map the uid and gid returned by a stat 248 * into the proper values for this site. This involves 249 * finding the returned uid in the mapping information, 250 * translating it into the uid on the other end, 251 * and filling in the proper field in the vattr 252 * structure pointed to by ap->a_vap. The group 253 * is easier, since currently all groups will be 254 * translate to the NULLGROUP. 255 */ 256 257 /* Find entry in map */ 258 259 uid = ap->a_vap->va_uid; 260 gid = ap->a_vap->va_gid; 261 if (umap_bug_bypass) 262 printf("umap_getattr: mapped uid = %d, mapped gid = %d\n",uid, 263 gid); 264 265 vp1p = VOPARG_OFFSETTO(struct vnode**,descp->vdesc_vp_offsets[0],ap); 266 nentries = MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_nentries; 267 mapdata = &(MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_mapdata[0][0]); 268 gnentries = MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_gnentries; 269 gmapdata = &(MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_gmapdata[0][0]); 270 271 /* Reverse map the uid for the vnode. Since it's a reverse 272 map, we can't use umap_mapids() to do it. */ 273 274 tmpid = umap_reverse_findid(uid,mapdata,nentries); 275 276 if (tmpid != -1 ) { 277 278 ap->a_vap->va_uid = (uid_t)tmpid; 279 if (umap_bug_bypass) 280 printf("umap_getattr: original uid = %d\n",uid); 281 } else 282 ap->a_vap->va_uid = (uid_t)NOBODY; 283 284 /* Reverse map the gid for the vnode. */ 285 286 tmpid = umap_reverse_findid(gid,gmapdata,gnentries); 287 288 if (tmpid != -1) { 289 290 ap->a_vap->va_gid = (gid_t)tmpid; 291 if (umap_bug_bypass) 292 printf("umap_getattr: original gid = %d\n",gid); 293 } else 294 ap->a_vap->va_gid = (gid_t)NULLGROUP; 295 296 return (0); 297 } 298 299 int 300 umap_inactive(ap) 301 struct vop_inactive_args /* { 302 struct vnode *a_vp; 303 } */ *ap; 304 { 305 /* 306 * Do nothing (and _don't_ bypass). 307 * Wait to vrele lowervp until reclaim, 308 * so that until then our umap_node is in the 309 * cache and reusable. 310 * 311 */ 312 return (0); 313 } 314 315 int 316 umap_reclaim(ap) 317 struct vop_reclaim_args /* { 318 struct vnode *a_vp; 319 } */ *ap; 320 { 321 struct vnode *vp = ap->a_vp; 322 struct umap_node *xp = VTOUMAP(vp); 323 struct vnode *lowervp = xp->umap_lowervp; 324 325 /* After this assignment, this node will not be re-used. */ 326 xp->umap_lowervp = NULL; 327 remque(xp); 328 FREE(vp->v_data, M_TEMP); 329 vp->v_data = NULL; 330 vrele (lowervp); 331 return (0); 332 } 333 334 int 335 umap_strategy(ap) 336 struct vop_strategy_args /* { 337 struct buf *a_bp; 338 } */ *ap; 339 { 340 struct buf *bp = ap->a_bp; 341 int error; 342 struct vnode *savedvp; 343 344 savedvp = bp->b_vp; 345 bp->b_vp = UMAPVPTOLOWERVP(bp->b_vp); 346 347 error = VOP_STRATEGY(ap->a_bp); 348 349 bp->b_vp = savedvp; 350 351 return (error); 352 } 353 354 int 355 umap_bwrite(ap) 356 struct vop_bwrite_args /* { 357 struct buf *a_bp; 358 } */ *ap; 359 { 360 struct buf *bp = ap->a_bp; 361 int error; 362 struct vnode *savedvp; 363 364 savedvp = bp->b_vp; 365 bp->b_vp = UMAPVPTOLOWERVP(bp->b_vp); 366 367 error = VOP_BWRITE(ap->a_bp); 368 369 bp->b_vp = savedvp; 370 371 return (error); 372 } 373 374 375 int 376 umap_print(ap) 377 struct vop_print_args /* { 378 struct vnode *a_vp; 379 } */ *ap; 380 { 381 register struct vnode *vp = ap->a_vp; 382 printf ("\ttag VT_UMAPFS, vp=%x, lowervp=%x\n", vp, UMAPVPTOLOWERVP(vp)); 383 return (0); 384 } 385 386 int 387 umap_rename(ap) 388 struct vop_rename_args /* { 389 struct vnode *a_fdvp; 390 struct vnode *a_fvp; 391 struct componentname *a_fcnp; 392 struct vnode *a_tdvp; 393 struct vnode *a_tvp; 394 struct componentname *a_tcnp; 395 } */ *ap; 396 { 397 int error; 398 struct componentname *compnamep; 399 struct ucred *compcredp, *savecompcredp; 400 struct vnode *vp; 401 402 /* 403 * Rename is irregular, having two componentname structures. 404 * We need to map the cre in the second structure, 405 * and then bypass takes care of the rest. 406 */ 407 408 vp = ap->a_fdvp; 409 compnamep = ap->a_tcnp; 410 compcredp = compnamep->cn_cred; 411 412 savecompcredp = compcredp; 413 compcredp = compnamep->cn_cred = crdup(savecompcredp); 414 415 if (umap_bug_bypass && compcredp->cr_uid != 0 ) 416 printf("umap_rename: rename component credit user was %d, group %d\n", 417 compcredp->cr_uid,compcredp->cr_gid); 418 419 /* Map all ids in the credential structure. */ 420 421 umap_mapids(vp->v_mount,compcredp); 422 423 if (umap_bug_bypass && compcredp->cr_uid != 0 ) 424 printf("umap_rename: rename component credit user now %d, group %d\n", 425 compcredp->cr_uid,compcredp->cr_gid); 426 427 error = umap_bypass(ap); 428 429 /* Restore the additional mapped componentname cred structure. */ 430 431 crfree(compcredp); 432 compnamep->cn_cred = savecompcredp; 433 434 return error; 435 } 436 437 /* 438 * Global vfs data structures 439 */ 440 /* 441 * XXX - strategy,bwrite are hand coded currently. They should 442 * go away with a merged buffer/block cache. 443 * 444 */ 445 int (**umap_vnodeop_p)(); 446 struct vnodeopv_entry_desc umap_vnodeop_entries[] = { 447 { &vop_default_desc, umap_bypass }, 448 449 { &vop_getattr_desc, umap_getattr }, 450 { &vop_inactive_desc, umap_inactive }, 451 { &vop_reclaim_desc, umap_reclaim }, 452 { &vop_print_desc, umap_print }, 453 { &vop_rename_desc, umap_rename }, 454 455 { &vop_strategy_desc, umap_strategy }, 456 { &vop_bwrite_desc, umap_bwrite }, 457 458 { (struct vnodeop_desc*)NULL, (int(*)())NULL } 459 }; 460 struct vnodeopv_desc umap_vnodeop_opv_desc = 461 { &umap_vnodeop_p, umap_vnodeop_entries }; 462