union_subr.c
来自「早期freebsd实现」· C语言 代码 · 共 745 行 · 第 1/2 页
C
745 行
/* * Copyright (c) 1994 Jan-Simon Pendry * Copyright (c) 1994 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Jan-Simon Pendry. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)union_subr.c 8.4 (Berkeley) 2/17/94 */#include <sys/param.h>#include <sys/systm.h>#include <sys/time.h>#include <sys/kernel.h>#include <sys/vnode.h>#include <sys/namei.h>#include <sys/malloc.h>#include <sys/file.h>#include <sys/filedesc.h>#include <sys/queue.h>#include <miscfs/union/union.h>#ifdef DIAGNOSTIC#include <sys/proc.h>#endif/* must be power of two, otherwise change UNION_HASH() */#define NHASH 32/* unsigned int ... */#define UNION_HASH(u, l) \ (((((unsigned long) (u)) + ((unsigned long) l)) >> 8) & (NHASH-1))static LIST_HEAD(unhead, union_node) unhead[NHASH];static int unvplock[NHASH];intunion_init(){ int i; for (i = 0; i < NHASH; i++) LIST_INIT(&unhead[i]); bzero((caddr_t) unvplock, sizeof(unvplock));}static intunion_list_lock(ix) int ix;{ if (unvplock[ix] & UN_LOCKED) { unvplock[ix] |= UN_WANT; sleep((caddr_t) &unvplock[ix], PINOD); return (1); } unvplock[ix] |= UN_LOCKED; return (0);}static voidunion_list_unlock(ix) int ix;{ unvplock[ix] &= ~UN_LOCKED; if (unvplock[ix] & UN_WANT) { unvplock[ix] &= ~UN_WANT; wakeup((caddr_t) &unvplock[ix]); }}voidunion_updatevp(un, uppervp, lowervp) struct union_node *un; struct vnode *uppervp; struct vnode *lowervp;{ int ohash = UNION_HASH(un->un_uppervp, un->un_lowervp); int nhash = UNION_HASH(uppervp, lowervp); if (ohash != nhash) { /* * Ensure locking is ordered from lower to higher * to avoid deadlocks. */ if (nhash < ohash) { int t = ohash; ohash = nhash; nhash = t; } while (union_list_lock(ohash)) continue; while (union_list_lock(nhash)) continue; LIST_REMOVE(un, un_cache); union_list_unlock(ohash); } else { while (union_list_lock(nhash)) continue; } if (un->un_lowervp != lowervp) { if (un->un_lowervp) { vrele(un->un_lowervp); if (un->un_path) { free(un->un_path, M_TEMP); un->un_path = 0; } if (un->un_dirvp) { vrele(un->un_dirvp); un->un_dirvp = NULLVP; } } un->un_lowervp = lowervp; } if (un->un_uppervp != uppervp) { if (un->un_uppervp) vrele(un->un_uppervp); un->un_uppervp = uppervp; } if (ohash != nhash) LIST_INSERT_HEAD(&unhead[nhash], un, un_cache); union_list_unlock(nhash);}voidunion_newlower(un, lowervp) struct union_node *un; struct vnode *lowervp;{ union_updatevp(un, un->un_uppervp, lowervp);}voidunion_newupper(un, uppervp) struct union_node *un; struct vnode *uppervp;{ union_updatevp(un, uppervp, un->un_lowervp);}/* * allocate a union_node/vnode pair. the vnode is * referenced and locked. the new vnode is returned * via (vpp). (mp) is the mountpoint of the union filesystem, * (dvp) is the parent directory where the upper layer object * should exist (but doesn't) and (cnp) is the componentname * information which is partially copied to allow the upper * layer object to be created at a later time. (uppervp) * and (lowervp) reference the upper and lower layer objects * being mapped. either, but not both, can be nil. * if supplied, (uppervp) is locked. * the reference is either maintained in the new union_node * object which is allocated, or they are vrele'd. * * all union_nodes are maintained on a singly-linked * list. new nodes are only allocated when they cannot * be found on this list. entries on the list are * removed when the vfs reclaim entry is called. * * a single lock is kept for the entire list. this is * needed because the getnewvnode() function can block * waiting for a vnode to become free, in which case there * may be more than one process trying to get the same * vnode. this lock is only taken if we are going to * call getnewvnode, since the kernel itself is single-threaded. * * if an entry is found on the list, then call vget() to * take a reference. this is done because there may be * zero references to it and so it needs to removed from * the vnode free list. */intunion_allocvp(vpp, mp, undvp, dvp, cnp, uppervp, lowervp) struct vnode **vpp; struct mount *mp; struct vnode *undvp; struct vnode *dvp; /* may be null */ struct componentname *cnp; /* may be null */ struct vnode *uppervp; /* may be null */ struct vnode *lowervp; /* may be null */{ int error; struct union_node *un; struct union_node **pp; struct vnode *xlowervp = NULLVP; int hash; int try; if (uppervp == NULLVP && lowervp == NULLVP) panic("union: unidentifiable allocation"); if (uppervp && lowervp && (uppervp->v_type != lowervp->v_type)) { xlowervp = lowervp; lowervp = NULLVP; }loop: for (try = 0; try < 3; try++) { switch (try) { case 0: if (lowervp == NULLVP) continue; hash = UNION_HASH(uppervp, lowervp); break; case 1: if (uppervp == NULLVP) continue; hash = UNION_HASH(uppervp, NULLVP); break; case 2: if (lowervp == NULLVP) continue; hash = UNION_HASH(NULLVP, lowervp); break; } while (union_list_lock(hash)) continue; for (un = unhead[hash].lh_first; un != 0; un = un->un_cache.le_next) { if ((un->un_lowervp == lowervp || un->un_lowervp == NULLVP) && (un->un_uppervp == uppervp || un->un_uppervp == NULLVP) && (UNIONTOV(un)->v_mount == mp)) { if (vget(UNIONTOV(un), 0)) { union_list_unlock(hash); goto loop; } break; } } union_list_unlock(hash); if (un) break; } if (un) { /* * Obtain a lock on the union_node. * uppervp is locked, though un->un_uppervp * may not be. this doesn't break the locking * hierarchy since in the case that un->un_uppervp * is not yet locked it will be vrele'd and replaced * with uppervp. */ if ((dvp != NULLVP) && (uppervp == dvp)) { /* * Access ``.'', so (un) will already * be locked. Since this process has * the lock on (uppervp) no other * process can hold the lock on (un). */#ifdef DIAGNOSTIC if ((un->un_flags & UN_LOCKED) == 0) panic("union: . not locked"); else if (curproc && un->un_pid != curproc->p_pid && un->un_pid > -1 && curproc->p_pid > -1) panic("union: allocvp not lock owner");#endif } else { if (un->un_flags & UN_LOCKED) { vrele(UNIONTOV(un)); un->un_flags |= UN_WANT; sleep((caddr_t) &un->un_flags, PINOD); goto loop; } un->un_flags |= UN_LOCKED;#ifdef DIAGNOSTIC if (curproc) un->un_pid = curproc->p_pid; else un->un_pid = -1;#endif } /* * At this point, the union_node is locked, * un->un_uppervp may not be locked, and uppervp * is locked or nil. */ /* * Save information about the upper layer. */ if (uppervp != un->un_uppervp) { union_newupper(un, uppervp); } else if (uppervp) { vrele(uppervp); } if (un->un_uppervp) { un->un_flags |= UN_ULOCK; un->un_flags &= ~UN_KLOCK; } /* * Save information about the lower layer. * This needs to keep track of pathname * and directory information which union_vn_create * might need. */ if (lowervp != un->un_lowervp) { union_newlower(un, lowervp); if (cnp && (lowervp != NULLVP) && (lowervp->v_type == VREG)) { un->un_hash = cnp->cn_hash; un->un_path = malloc(cnp->cn_namelen+1, M_TEMP, M_WAITOK); bcopy(cnp->cn_nameptr, un->un_path, cnp->cn_namelen); un->un_path[cnp->cn_namelen] = '\0'; VREF(dvp); un->un_dirvp = dvp; } } else if (lowervp) { vrele(lowervp); } *vpp = UNIONTOV(un); return (0); } /*
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?