Annotation of src/sys/fs/puffs/puffs_subr.c, Revision 1.13.2.2
1.13.2.2! yamt 1: /* $NetBSD: puffs_subr.c,v 1.13.2.1 2006/12/30 20:50:01 yamt Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2005, 2006 Antti Kantee. All Rights Reserved.
! 5: *
! 6: * Development of this software was supported by the
! 7: * Google Summer of Code program and the Ulla Tuominen Foundation.
! 8: * The Google SoC project was mentored by Bill Studenmund.
! 9: *
! 10: * Redistribution and use in source and binary forms, with or without
! 11: * modification, are permitted provided that the following conditions
! 12: * are met:
! 13: * 1. Redistributions of source code must retain the above copyright
! 14: * notice, this list of conditions and the following disclaimer.
! 15: * 2. Redistributions in binary form must reproduce the above copyright
! 16: * notice, this list of conditions and the following disclaimer in the
! 17: * documentation and/or other materials provided with the distribution.
! 18: * 3. The name of the company nor the name of the author may be used to
! 19: * endorse or promote products derived from this software without specific
! 20: * prior written permission.
! 21: *
! 22: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
! 23: * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
! 24: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
! 25: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
! 26: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 27: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
! 28: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 29: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 30: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 31: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 32: * SUCH DAMAGE.
! 33: */
! 34:
! 35: #include <sys/cdefs.h>
! 36: __KERNEL_RCSID(0, "$NetBSD: puffs_subr.c,v 1.13.2.1 2006/12/30 20:50:01 yamt Exp $");
! 37:
! 38: #include <sys/param.h>
! 39: #include <sys/conf.h>
! 40: #include <sys/malloc.h>
! 41: #include <sys/mount.h>
! 42: #include <sys/socketvar.h>
! 43: #include <sys/vnode.h>
! 44: #include <sys/kauth.h>
! 45: #include <sys/namei.h>
! 46:
! 47: #include <fs/puffs/puffs_msgif.h>
! 48: #include <fs/puffs/puffs_sys.h>
! 49:
! 50: #include <miscfs/genfs/genfs_node.h>
! 51: #include <miscfs/specfs/specdev.h>
! 52:
! 53: POOL_INIT(puffs_pnpool, sizeof(struct puffs_node), 0, 0, 0, "puffspnpl",
! 54: &pool_allocator_nointr);
! 55:
! 56: #ifdef DEBUG
! 57: int puffsdebug;
! 58: #endif
! 59:
! 60:
! 61: static void puffs_gop_size(struct vnode *, off_t, off_t *, int);
! 62: static void puffs_gop_markupdate(struct vnode *, int);
! 63:
! 64: static const struct genfs_ops puffs_genfsops = {
! 65: .gop_size = puffs_gop_size,
! 66: .gop_write = genfs_gop_write,
! 67: .gop_markupdate = puffs_gop_markupdate,
! 68: #if 0
! 69: .gop_alloc, should ask userspace
! 70: #endif
! 71: };
! 72:
! 73: /*
! 74: * Grab a vnode, intialize all the puffs-dependant stuff.
! 75: */
! 76: int
! 77: puffs_getvnode(struct mount *mp, void *cookie, enum vtype type,
! 78: voff_t vsize, dev_t rdev, struct vnode **vpp)
! 79: {
! 80: struct puffs_mount *pmp;
! 81: struct vnode *vp, *nvp;
! 82: struct puffs_node *pnode;
! 83: int error;
! 84:
! 85: pmp = MPTOPUFFSMP(mp);
! 86:
! 87: /*
! 88: * XXX: there is a deadlock condition between vfs_busy() and
! 89: * vnode locks. For an unmounting file system the mountpoint
! 90: * is frozen, but in unmount(FORCE) vflush() wants to access all
! 91: * of the vnodes. If we are here waiting for the mountpoint
! 92: * lock while holding on to a vnode lock, well, we ain't
! 93: * just pining for the fjords anymore. If we release the
! 94: * vnode lock, we will be in the situation "mount point
! 95: * is dying" and panic() will ensue in insmntque. So as a
! 96: * temporary workaround, get a vnode without putting it on
! 97: * the mount point list, check if mount point is still alive
! 98: * and kicking and only then add the vnode to the list.
! 99: */
! 100: error = getnewvnode(VT_PUFFS, NULL, puffs_vnodeop_p, &vp);
! 101: if (error)
! 102: return error;
! 103: vp->v_vnlock = NULL;
! 104: vp->v_type = type;
! 105:
! 106: /*
! 107: * Check what mount point isn't going away. This will work
! 108: * until we decide to remove biglock or make the kernel
! 109: * preemptive. But hopefully the real problem will be fixed
! 110: * by then.
! 111: *
! 112: * XXX: yes, should call vfs_busy(), but thar be rabbits with
! 113: * vicious streaks a mile wide ...
! 114: */
! 115: if (mp->mnt_iflag & IMNT_UNMOUNT) {
! 116: DPRINTF(("puffs_getvnode: mp %p unmount, unable to create "
! 117: "vnode for cookie %p\n", mp, cookie));
! 118: ungetnewvnode(vp);
! 119: return ENXIO;
! 120: }
! 121:
! 122: /* So it's not dead yet.. good.. inform new vnode of its master */
! 123: simple_lock(&mntvnode_slock);
! 124: if (TAILQ_EMPTY(&mp->mnt_vnodelist))
! 125: TAILQ_INSERT_HEAD(&mp->mnt_vnodelist, vp, v_mntvnodes);
! 126: else
! 127: TAILQ_INSERT_TAIL(&mp->mnt_vnodelist, vp, v_mntvnodes);
! 128: simple_unlock(&mntvnode_slock);
! 129: vp->v_mount = mp;
! 130:
! 131: /*
! 132: * clerical tasks & footwork
! 133: */
! 134:
! 135: /* dances based on vnode type. almost ufs_vinit(), but not quite */
! 136: switch (type) {
! 137: case VCHR:
! 138: case VBLK:
! 139: /*
! 140: * replace vnode operation vector with the specops vector.
! 141: * our user server has very little control over the node
! 142: * if it decides its a character or block special file
! 143: */
! 144: vp->v_op = puffs_specop_p;
! 145:
! 146: /* do the standard checkalias-dance */
! 147: if ((nvp = checkalias(vp, rdev, mp)) != NULL) {
! 148: /*
! 149: * found: release & unallocate aliased
! 150: * old (well, actually, new) node
! 151: */
! 152: vp->v_op = spec_vnodeop_p;
! 153: vp->v_flag &= ~VLOCKSWORK;
! 154: vrele(vp);
! 155: vgone(vp); /* cya */
! 156:
! 157: /* init "new" vnode */
! 158: vp = nvp;
! 159: vp->v_vnlock = NULL;
! 160: vp->v_mount = mp;
! 161: }
! 162: break;
! 163:
! 164: case VFIFO:
! 165: vp->v_op = puffs_fifoop_p;
! 166: break;
! 167:
! 168: case VREG:
! 169: uvm_vnp_setsize(vp, vsize);
! 170: break;
! 171:
! 172: case VDIR:
! 173: case VLNK:
! 174: case VSOCK:
! 175: break;
! 176: default:
! 177: #ifdef DIAGNOSTIC
! 178: panic("puffs_getvnode: invalid vtype %d", type);
! 179: #endif
! 180: break;
! 181: }
! 182:
! 183: pnode = pool_get(&puffs_pnpool, PR_WAITOK);
! 184: pnode->pn_cookie = cookie;
! 185: pnode->pn_stat = 0;
! 186: LIST_INSERT_HEAD(&pmp->pmp_pnodelist, pnode, pn_entries);
! 187: vp->v_data = pnode;
! 188: vp->v_type = type;
! 189: pnode->pn_vp = vp;
! 190:
! 191: genfs_node_init(vp, &puffs_genfsops);
! 192: *vpp = vp;
! 193:
! 194: DPRINTF(("new vnode at %p, pnode %p, cookie %p\n", vp,
! 195: pnode, pnode->pn_cookie));
! 196:
! 197: return 0;
! 198: }
! 199:
! 200: /* new node creating for creative vop ops (create, symlink, mkdir, mknod) */
! 201: int
! 202: puffs_newnode(struct mount *mp, struct vnode *dvp, struct vnode **vpp,
! 203: void *cookie, struct componentname *cnp, enum vtype type, dev_t rdev)
! 204: {
! 205: struct puffs_mount *pmp = MPTOPUFFSMP(mp);
! 206: struct vnode *vp;
! 207: int error;
! 208:
! 209: /* userspace probably has this as a NULL op */
! 210: if (cookie == NULL) {
! 211: error = EOPNOTSUPP;
! 212: return error;
! 213: }
! 214:
! 215: error = puffs_getvnode(dvp->v_mount, cookie, type, 0, rdev, &vp);
! 216: if (error)
! 217: return error;
! 218:
! 219: vp->v_type = type;
! 220: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
! 221: *vpp = vp;
! 222:
! 223: if ((cnp->cn_flags & MAKEENTRY) && PUFFS_DOCACHE(pmp))
! 224: cache_enter(dvp, vp, cnp);
! 225:
! 226: return 0;
! 227: }
! 228:
! 229: void
! 230: puffs_putvnode(struct vnode *vp)
! 231: {
! 232: struct puffs_mount *pmp;
! 233: struct puffs_node *pnode;
! 234:
! 235: pmp = VPTOPUFFSMP(vp);
! 236: pnode = VPTOPP(vp);
! 237:
! 238: #ifdef DIAGNOSTIC
! 239: if (vp->v_tag != VT_PUFFS)
! 240: panic("puffs_putvnode: %p not a puffs vnode", vp);
! 241: #endif
! 242:
! 243: LIST_REMOVE(pnode, pn_entries);
! 244: pool_put(&puffs_pnpool, vp->v_data);
! 245: vp->v_data = NULL;
! 246:
! 247: return;
! 248: }
! 249:
! 250: /*
! 251: * Locate the in-kernel vnode based on the cookie received given
! 252: * from userspace. Returns a locked & referenced vnode, if found,
! 253: * NULL otherwise.
! 254: *
! 255: * XXX: lists, although lookup cache mostly shields us from this
! 256: */
! 257: struct vnode *
! 258: puffs_pnode2vnode(struct puffs_mount *pmp, void *cookie)
! 259: {
! 260: struct puffs_node *pnode;
! 261: struct vnode *vp;
! 262:
! 263: simple_lock(&pmp->pmp_lock);
! 264: LIST_FOREACH(pnode, &pmp->pmp_pnodelist, pn_entries) {
! 265: if (pnode->pn_cookie == cookie)
! 266: break;
! 267: }
! 268: simple_unlock(&pmp->pmp_lock);
! 269: if (!pnode)
! 270: return NULL;
! 271: vp = pnode->pn_vp;
! 272:
! 273: if (pnode->pn_stat & PNODE_INACTIVE) {
! 274: if (vget(vp, LK_EXCLUSIVE | LK_RETRY))
! 275: return NULL;
! 276: } else {
! 277: vref(vp);
! 278: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
! 279: }
! 280: return vp;
! 281: }
! 282:
! 283: void
! 284: puffs_makecn(struct puffs_kcn *pkcn, const struct componentname *cn)
! 285: {
! 286:
! 287: pkcn->pkcn_nameiop = cn->cn_nameiop;
! 288: pkcn->pkcn_flags = cn->cn_flags;
! 289: pkcn->pkcn_pid = cn->cn_lwp->l_proc->p_pid;
! 290: puffs_credcvt(&pkcn->pkcn_cred, cn->cn_cred);
! 291:
! 292: (void)memcpy(&pkcn->pkcn_name, cn->cn_nameptr, cn->cn_namelen);
! 293: pkcn->pkcn_name[cn->cn_namelen] = '\0';
! 294: pkcn->pkcn_namelen = cn->cn_namelen;
! 295: }
! 296:
! 297: /*
! 298: * Convert given credentials to struct puffs_cred for userspace.
! 299: */
! 300: void
! 301: puffs_credcvt(struct puffs_cred *pcr, const kauth_cred_t cred)
! 302: {
! 303:
! 304: memset(pcr, 0, sizeof(struct puffs_cred));
! 305:
! 306: if (cred == NOCRED || cred == FSCRED) {
! 307: pcr->pcr_type = PUFFCRED_TYPE_INTERNAL;
! 308: if (cred == NOCRED)
! 309: pcr->pcr_internal = PUFFCRED_CRED_NOCRED;
! 310: if (cred == FSCRED)
! 311: pcr->pcr_internal = PUFFCRED_CRED_FSCRED;
! 312: } else {
! 313: pcr->pcr_type = PUFFCRED_TYPE_UUC;
! 314: kauth_cred_to_uucred(&pcr->pcr_uuc, cred);
! 315: }
! 316: }
! 317:
! 318: /*
! 319: * Return pid. In case the operation is coming from within the
! 320: * kernel without any process context, borrow the swapper's pid.
! 321: */
! 322: pid_t
! 323: puffs_lwp2pid(struct lwp *l)
! 324: {
! 325:
! 326: return l ? l->l_proc->p_pid : 0;
! 327: }
! 328:
! 329:
! 330: static void
! 331: puffs_gop_size(struct vnode *vp, off_t size, off_t *eobp,
! 332: int flags)
! 333: {
! 334:
! 335: *eobp = size;
! 336: }
! 337:
! 338: static void
! 339: puffs_gop_markupdate(struct vnode *vp, int flags)
! 340: {
! 341: int uflags = 0;
! 342:
! 343: if (flags & GOP_UPDATE_ACCESSED)
! 344: uflags |= PUFFS_UPDATEATIME;
! 345: if (flags & GOP_UPDATE_MODIFIED)
! 346: uflags |= PUFFS_UPDATEMTIME;
! 347:
! 348: puffs_updatenode(vp, uflags);
! 349: }
! 350:
! 351: void
! 352: puffs_updatenode(struct vnode *vp, int flags)
! 353: {
! 354: struct timespec ts;
! 355: struct puffs_vnreq_setattr *setattr_arg;
! 356:
! 357: if (flags == 0)
! 358: return;
! 359:
! 360: setattr_arg = malloc(sizeof(struct puffs_vnreq_setattr), M_PUFFS,
! 361: M_NOWAIT | M_ZERO);
! 362: if (setattr_arg == NULL)
! 363: return; /* 2bad */
! 364:
! 365: nanotime(&ts);
! 366:
! 367: VATTR_NULL(&setattr_arg->pvnr_va);
! 368: if (flags & PUFFS_UPDATEATIME)
! 369: setattr_arg->pvnr_va.va_atime = ts;
! 370: if (flags & PUFFS_UPDATECTIME)
! 371: setattr_arg->pvnr_va.va_ctime = ts;
! 372: if (flags & PUFFS_UPDATEMTIME)
! 373: setattr_arg->pvnr_va.va_mtime = ts;
! 374: if (flags & PUFFS_UPDATESIZE)
! 375: setattr_arg->pvnr_va.va_size = vp->v_size;
! 376:
! 377: setattr_arg->pvnr_pid = 0;
! 378: puffs_credcvt(&setattr_arg->pvnr_cred, NOCRED);
! 379:
! 380: /* setattr_arg ownership shifted to callee */
! 381: puffs_vntouser_faf(MPTOPUFFSMP(vp->v_mount), PUFFS_VN_SETATTR,
! 382: setattr_arg, sizeof(struct puffs_vnreq_setattr), VPTOPNC(vp));
! 383: }
! 384:
! 385: void
! 386: puffs_updatevpsize(struct vnode *vp)
! 387: {
! 388: struct vattr va;
! 389:
! 390: if (VOP_GETATTR(vp, &va, FSCRED, NULL))
! 391: return;
! 392:
! 393: if (va.va_size != VNOVAL)
! 394: vp->v_size = va.va_size;
! 395: }
! 396:
! 397: /*
! 398: * We're dead, kaput, RIP, slightly more than merely pining for the
! 399: * fjords, belly-up, fallen, lifeless, finished, expired, gone to meet
! 400: * our maker, ceased to be, etcetc. YASD. It's a dead FS!
! 401: */
! 402: void
! 403: puffs_userdead(struct puffs_mount *pmp)
! 404: {
! 405: struct puffs_park *park;
! 406:
! 407: simple_lock(&pmp->pmp_lock);
! 408:
! 409: /*
! 410: * Mark filesystem status as dying so that operations don't
! 411: * attempt to march to userspace any longer.
! 412: */
! 413: pmp->pmp_status = PUFFSTAT_DYING;
! 414:
! 415: /* and wakeup processes waiting for a reply from userspace */
! 416: TAILQ_FOREACH(park, &pmp->pmp_req_replywait, park_entries) {
! 417: park->park_preq->preq_rv = ENXIO;
! 418: TAILQ_REMOVE(&pmp->pmp_req_replywait, park, park_entries);
! 419: wakeup(park);
! 420: }
! 421:
! 422: /* wakeup waiters for completion of vfs/vnode requests */
! 423: TAILQ_FOREACH(park, &pmp->pmp_req_touser, park_entries) {
! 424: park->park_preq->preq_rv = ENXIO;
! 425: TAILQ_REMOVE(&pmp->pmp_req_touser, park, park_entries);
! 426: wakeup(park);
! 427: }
! 428:
! 429: simple_unlock(&pmp->pmp_lock);
! 430: }
CVSweb <webmaster@jp.NetBSD.org>