1 1.22 andvar /* $NetBSD: adlookup.c,v 1.22 2022/08/06 18:26:41 andvar Exp $ */ 2 1.1 jdolecek 3 1.1 jdolecek /* 4 1.1 jdolecek * Copyright (c) 1994 Christian E. Hopps 5 1.1 jdolecek * Copyright (c) 1996 Matthias Scheler 6 1.1 jdolecek * All rights reserved. 7 1.1 jdolecek * 8 1.1 jdolecek * Redistribution and use in source and binary forms, with or without 9 1.1 jdolecek * modification, are permitted provided that the following conditions 10 1.1 jdolecek * are met: 11 1.1 jdolecek * 1. Redistributions of source code must retain the above copyright 12 1.1 jdolecek * notice, this list of conditions and the following disclaimer. 13 1.1 jdolecek * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 jdolecek * notice, this list of conditions and the following disclaimer in the 15 1.1 jdolecek * documentation and/or other materials provided with the distribution. 16 1.1 jdolecek * 3. All advertising materials mentioning features or use of this software 17 1.1 jdolecek * must display the following acknowledgement: 18 1.1 jdolecek * This product includes software developed by Christian E. Hopps. 19 1.1 jdolecek * 4. The name of the author may not be used to endorse or promote products 20 1.1 jdolecek * derived from this software without specific prior written permission 21 1.1 jdolecek * 22 1.1 jdolecek * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 1.1 jdolecek * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 1.1 jdolecek * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 1.1 jdolecek * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 1.1 jdolecek * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 1.1 jdolecek * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 1.1 jdolecek * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 1.1 jdolecek * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 1.1 jdolecek * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 1.1 jdolecek * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 1.1 jdolecek */ 33 1.1 jdolecek 34 1.1 jdolecek #include <sys/cdefs.h> 35 1.22 andvar __KERNEL_RCSID(0, "$NetBSD: adlookup.c,v 1.22 2022/08/06 18:26:41 andvar Exp $"); 36 1.1 jdolecek 37 1.1 jdolecek #include <sys/param.h> 38 1.1 jdolecek #include <sys/systm.h> 39 1.1 jdolecek #include <sys/vnode.h> 40 1.1 jdolecek #include <sys/namei.h> 41 1.1 jdolecek #include <sys/mount.h> 42 1.1 jdolecek #include <sys/time.h> 43 1.1 jdolecek #include <sys/queue.h> 44 1.1 jdolecek #include <fs/adosfs/adosfs.h> 45 1.1 jdolecek 46 1.1 jdolecek #ifdef ADOSFS_EXACTMATCH 47 1.1 jdolecek #define strmatch(s1, l1, s2, l2, i) \ 48 1.1 jdolecek ((l1) == (l2) && memcmp((s1), (s2), (l1)) == 0) 49 1.1 jdolecek #else 50 1.1 jdolecek #define strmatch(s1, l1, s2, l2, i) \ 51 1.1 jdolecek ((l1) == (l2) && adoscaseequ((s1), (s2), (l1), (i))) 52 1.1 jdolecek #endif 53 1.1 jdolecek 54 1.1 jdolecek /* 55 1.1 jdolecek * adosfs lookup. enters with: 56 1.1 jdolecek * pvp (parent vnode) referenced and locked. 57 1.1 jdolecek * exit with: 58 1.1 jdolecek * target vp referenced and locked. 59 1.9 chs * parent pvp locked. 60 1.1 jdolecek * special cases: 61 1.1 jdolecek * pvp == vp, just ref pvp, pvp already holds a ref and lock from 62 1.1 jdolecek * caller, this will not occur with RENAME or CREATE. 63 1.1 jdolecek */ 64 1.1 jdolecek int 65 1.12 dsl adosfs_lookup(void *v) 66 1.1 jdolecek { 67 1.19 hannken struct vop_lookup_v2_args /* { 68 1.1 jdolecek struct vnode *a_dvp; 69 1.1 jdolecek struct vnode **a_vpp; 70 1.1 jdolecek struct componentname *a_cnp; 71 1.1 jdolecek } */ *sp = v; 72 1.9 chs int nameiop, last, flags, error, nocache, i; 73 1.1 jdolecek struct componentname *cnp; 74 1.1 jdolecek struct vnode **vpp; /* place to store result */ 75 1.1 jdolecek struct anode *ap; /* anode to find */ 76 1.1 jdolecek struct vnode *vdp; /* vnode of search dir */ 77 1.1 jdolecek struct anode *adp; /* anode of search dir */ 78 1.8 elad kauth_cred_t ucp; /* lookup credentials */ 79 1.1 jdolecek u_long bn, plen, hval; 80 1.1 jdolecek const u_char *pelt; 81 1.1 jdolecek 82 1.1 jdolecek #ifdef ADOSFS_DIAGNOSTIC 83 1.1 jdolecek advopprint(sp); 84 1.1 jdolecek #endif 85 1.1 jdolecek cnp = sp->a_cnp; 86 1.1 jdolecek vdp = sp->a_dvp; 87 1.1 jdolecek adp = VTOA(vdp); 88 1.1 jdolecek vpp = sp->a_vpp; 89 1.1 jdolecek *vpp = NULL; 90 1.1 jdolecek ucp = cnp->cn_cred; 91 1.1 jdolecek nameiop = cnp->cn_nameiop; 92 1.1 jdolecek flags = cnp->cn_flags; 93 1.1 jdolecek last = flags & ISLASTCN; 94 1.1 jdolecek pelt = (const u_char *)cnp->cn_nameptr; 95 1.1 jdolecek plen = cnp->cn_namelen; 96 1.1 jdolecek nocache = 0; 97 1.6 perry 98 1.6 perry /* 99 1.22 andvar * Check accessibility of directory. 100 1.1 jdolecek */ 101 1.11 pooka if ((error = VOP_ACCESS(vdp, VEXEC, ucp)) != 0) 102 1.1 jdolecek return (error); 103 1.1 jdolecek 104 1.1 jdolecek if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) && 105 1.1 jdolecek (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) 106 1.1 jdolecek return (EROFS); 107 1.1 jdolecek 108 1.1 jdolecek /* 109 1.1 jdolecek * Before tediously performing a linear scan of the directory, 110 1.1 jdolecek * check the name cache to see if the directory/name pair 111 1.1 jdolecek * we are looking for is known already. 112 1.1 jdolecek */ 113 1.18 dholland if (cache_lookup(vdp, cnp->cn_nameptr, cnp->cn_namelen, 114 1.18 dholland cnp->cn_nameiop, cnp->cn_flags, NULL, vpp)) { 115 1.17 dholland return *vpp == NULLVP ? ENOENT : 0; 116 1.17 dholland } 117 1.1 jdolecek 118 1.1 jdolecek /* 119 1.1 jdolecek * fake a '.' 120 1.1 jdolecek */ 121 1.1 jdolecek if (plen == 1 && pelt[0] == '.') { 122 1.1 jdolecek /* see special cases in prologue. */ 123 1.1 jdolecek *vpp = vdp; 124 1.1 jdolecek goto found; 125 1.1 jdolecek } 126 1.1 jdolecek /* 127 1.1 jdolecek * fake a ".." 128 1.1 jdolecek */ 129 1.1 jdolecek if (flags & ISDOTDOT) { 130 1.10 ad if (vdp->v_type == VDIR && (vdp->v_vflag & VV_ROOT)) 131 1.1 jdolecek panic("adosfs .. attempted through root"); 132 1.1 jdolecek /* 133 1.1 jdolecek * cannot get `..' while `vdp' is locked 134 1.1 jdolecek * e.g. procA holds lock on `..' and waits for `vdp' 135 1.1 jdolecek * we wait for `..' and hold lock on `vdp'. deadlock. 136 1.5 wiz * because `vdp' may have been achieved through symlink 137 1.1 jdolecek * fancy detection code that decreases the race 138 1.1 jdolecek * window size is not reasonably possible. 139 1.1 jdolecek * 140 1.1 jdolecek * basically unlock the parent, try and lock the child (..) 141 1.6 perry * if that fails relock the parent (ignoring error) and 142 1.9 chs * fail. Otherwise we have the child (..), attempt to 143 1.1 jdolecek * relock the parent. If that fails unlock the child (..) 144 1.1 jdolecek * and fail. Otherwise we have succeded. 145 1.6 perry * 146 1.1 jdolecek */ 147 1.14 hannken VOP_UNLOCK(vdp); /* race */ 148 1.21 ad error = VFS_VGET(vdp->v_mount, (ino_t)adp->pblock, 149 1.21 ad LK_EXCLUSIVE, vpp); 150 1.9 chs vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY); 151 1.1 jdolecek if (error) { 152 1.1 jdolecek *vpp = NULL; 153 1.1 jdolecek return (error); 154 1.1 jdolecek } 155 1.1 jdolecek goto found_lockdone; 156 1.1 jdolecek } 157 1.1 jdolecek 158 1.1 jdolecek /* 159 1.1 jdolecek * hash the name and grab the first block in chain 160 1.1 jdolecek * then walk the chain. if chain has not been fully 161 1.1 jdolecek * walked before, track the count in `tabi' 162 1.1 jdolecek */ 163 1.1 jdolecek hval = adoshash(pelt, plen, adp->ntabent, IS_INTER(adp->amp)); 164 1.1 jdolecek bn = adp->tab[hval]; 165 1.20 riastrad i = uimin(adp->tabi[hval], 0); 166 1.1 jdolecek while (bn != 0) { 167 1.21 ad if ((error = VFS_VGET(vdp->v_mount, (ino_t)bn, 168 1.21 ad LK_EXCLUSIVE, vpp)) != 0) { 169 1.1 jdolecek #ifdef ADOSFS_DIAGNOSTIC 170 1.1 jdolecek printf("[aget] %d)", error); 171 1.1 jdolecek #endif 172 1.1 jdolecek return(error); 173 1.1 jdolecek } 174 1.1 jdolecek ap = VTOA(*vpp); 175 1.1 jdolecek if (i <= 0) { 176 1.1 jdolecek if (--i < adp->tabi[hval]) 177 1.6 perry adp->tabi[hval] = i; 178 1.1 jdolecek /* 179 1.1 jdolecek * last header in chain lock count down by 180 1.1 jdolecek * negating it to positive 181 1.1 jdolecek */ 182 1.1 jdolecek if (ap->hashf == 0) { 183 1.1 jdolecek #ifdef DEBUG 184 1.1 jdolecek if (i != adp->tabi[hval]) 185 1.1 jdolecek panic("adlookup: wrong chain count"); 186 1.1 jdolecek #endif 187 1.1 jdolecek adp->tabi[hval] = -adp->tabi[hval]; 188 1.1 jdolecek } 189 1.1 jdolecek } 190 1.6 perry if (strmatch(pelt, plen, ap->name, strlen(ap->name), 191 1.1 jdolecek IS_INTER(adp->amp))) 192 1.1 jdolecek goto found; 193 1.1 jdolecek bn = ap->hashf; 194 1.1 jdolecek vput(*vpp); 195 1.1 jdolecek } 196 1.1 jdolecek *vpp = NULL; 197 1.1 jdolecek /* 198 1.1 jdolecek * not found 199 1.1 jdolecek */ 200 1.1 jdolecek if ((nameiop == CREATE || nameiop == RENAME) && last) { 201 1.1 jdolecek 202 1.1 jdolecek if (vdp->v_mount->mnt_flag & MNT_RDONLY) 203 1.1 jdolecek return (EROFS); 204 1.1 jdolecek 205 1.11 pooka if ((error = VOP_ACCESS(vdp, VWRITE, ucp)) != 0) { 206 1.1 jdolecek #ifdef ADOSFS_DIAGNOSTIC 207 1.1 jdolecek printf("[VOP_ACCESS] %d)", error); 208 1.1 jdolecek #endif 209 1.1 jdolecek return (error); 210 1.1 jdolecek } 211 1.1 jdolecek #ifdef ADOSFS_DIAGNOSTIC 212 1.1 jdolecek printf("EJUSTRETURN)"); 213 1.1 jdolecek #endif 214 1.1 jdolecek return(EJUSTRETURN); 215 1.1 jdolecek } 216 1.16 rmind if (nameiop != CREATE) 217 1.18 dholland cache_enter(vdp, NULL, cnp->cn_nameptr, cnp->cn_namelen, 218 1.18 dholland cnp->cn_flags); 219 1.1 jdolecek #ifdef ADOSFS_DIAGNOSTIC 220 1.1 jdolecek printf("ENOENT)"); 221 1.1 jdolecek #endif 222 1.1 jdolecek return(ENOENT); 223 1.1 jdolecek 224 1.1 jdolecek found: 225 1.1 jdolecek if (nameiop == DELETE && last) { 226 1.11 pooka if ((error = VOP_ACCESS(vdp, VWRITE, ucp)) != 0) { 227 1.1 jdolecek if (vdp != *vpp) 228 1.1 jdolecek vput(*vpp); 229 1.1 jdolecek *vpp = NULL; 230 1.1 jdolecek return (error); 231 1.1 jdolecek } 232 1.1 jdolecek nocache = 1; 233 1.6 perry } 234 1.9 chs if (nameiop == RENAME && last) { 235 1.1 jdolecek if (vdp == *vpp) 236 1.1 jdolecek return(EISDIR); 237 1.11 pooka if ((error = VOP_ACCESS(vdp, VWRITE, ucp)) != 0) { 238 1.1 jdolecek vput(*vpp); 239 1.1 jdolecek *vpp = NULL; 240 1.1 jdolecek return (error); 241 1.1 jdolecek } 242 1.1 jdolecek nocache = 1; 243 1.1 jdolecek } 244 1.1 jdolecek if (vdp == *vpp) 245 1.13 pooka vref(vdp); 246 1.1 jdolecek found_lockdone: 247 1.19 hannken if (*vpp != vdp) 248 1.19 hannken VOP_UNLOCK(*vpp); 249 1.16 rmind if (nocache == 0) 250 1.18 dholland cache_enter(vdp, *vpp, cnp->cn_nameptr, cnp->cn_namelen, 251 1.18 dholland cnp->cn_flags); 252 1.1 jdolecek 253 1.1 jdolecek #ifdef ADOSFS_DIAGNOSTIC 254 1.1 jdolecek printf("0)\n"); 255 1.1 jdolecek #endif 256 1.1 jdolecek return(0); 257 1.1 jdolecek } 258