1 /* $NetBSD: lfs_alloc.c,v 1.30 1999/12/15 07:19:07 perseant Exp $ */ 2 3 /*- 4 * Copyright (c) 1999 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Konrad E. Schroder <perseant@hhhh.org>. 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. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 /* 39 * Copyright (c) 1991, 1993 40 * The Regents of the University of California. All rights reserved. 41 * 42 * Redistribution and use in source and binary forms, with or without 43 * modification, are permitted provided that the following conditions 44 * are met: 45 * 1. Redistributions of source code must retain the above copyright 46 * notice, this list of conditions and the following disclaimer. 47 * 2. Redistributions in binary form must reproduce the above copyright 48 * notice, this list of conditions and the following disclaimer in the 49 * documentation and/or other materials provided with the distribution. 50 * 3. All advertising materials mentioning features or use of this software 51 * must display the following acknowledgement: 52 * This product includes software developed by the University of 53 * California, Berkeley and its contributors. 54 * 4. Neither the name of the University nor the names of its contributors 55 * may be used to endorse or promote products derived from this software 56 * without specific prior written permission. 57 * 58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 68 * SUCH DAMAGE. 69 * 70 * @(#)lfs_alloc.c 8.4 (Berkeley) 1/4/94 71 */ 72 73 #if defined(_KERNEL) && !defined(_LKM) 74 #include "opt_quota.h" 75 #endif 76 77 #include <sys/param.h> 78 #include <sys/systm.h> 79 #include <sys/kernel.h> 80 #include <sys/buf.h> 81 #include <sys/vnode.h> 82 #include <sys/syslog.h> 83 #include <sys/mount.h> 84 #include <sys/malloc.h> 85 #include <sys/pool.h> 86 87 #include <vm/vm.h> 88 89 #include <ufs/ufs/quota.h> 90 #include <ufs/ufs/inode.h> 91 #include <ufs/ufs/ufsmount.h> 92 #include <ufs/ufs/ufs_extern.h> 93 94 #include <ufs/lfs/lfs.h> 95 #include <ufs/lfs/lfs_extern.h> 96 97 extern struct lock ufs_hashlock; 98 99 /* Allocate a new inode. */ 100 /* ARGSUSED */ 101 int 102 lfs_valloc(v) 103 void *v; 104 { 105 struct vop_valloc_args /* { 106 struct vnode *a_pvp; 107 int a_mode; 108 struct ucred *a_cred; 109 struct vnode **a_vpp; 110 } */ *ap = v; 111 struct lfs *fs; 112 struct buf *bp; 113 struct ifile *ifp; 114 struct inode *ip; 115 struct vnode *vp; 116 ufs_daddr_t blkno; 117 ino_t new_ino; 118 u_long i, max; 119 int error; 120 extern int lfs_dirvcount; 121 122 fs = VTOI(ap->a_pvp)->i_lfs; 123 124 /* 125 * Prevent a race getting lfs_free. We use 126 * the ufs_hashlock here because we need that anyway for 127 * the hash insertion later. 128 */ 129 lockmgr(&ufs_hashlock, LK_EXCLUSIVE, 0); 130 131 /* Get the head of the freelist. */ 132 new_ino = fs->lfs_free; 133 #ifdef DIAGNOSTIC 134 if(new_ino == LFS_UNUSED_INUM) { 135 #ifdef DEBUG 136 lfs_dump_super(fs); 137 #endif /* DEBUG */ 138 panic("inode 0 allocated [1]"); 139 } 140 #endif /* DIAGNOSTIC */ 141 #ifdef ALLOCPRINT 142 printf("lfs_ialloc: allocate inode %d\n", new_ino); 143 #endif 144 145 /* 146 * Remove the inode from the free list and write the new start 147 * of the free list into the superblock. 148 */ 149 LFS_IENTRY(ifp, fs, new_ino, bp); 150 if (ifp->if_daddr != LFS_UNUSED_DADDR) 151 panic("lfs_ialloc: inuse inode %d on the free list", new_ino); 152 fs->lfs_free = ifp->if_nextfree; 153 #ifdef LFS_DEBUG_NEXTFREE 154 ifp->if_nextfree = 0; 155 VOP_BWRITE(bp); 156 #else 157 brelse(bp); 158 #endif 159 160 /* Extend IFILE so that the next lfs_valloc will succeed. */ 161 if (fs->lfs_free == LFS_UNUSED_INUM) { 162 vp = fs->lfs_ivnode; 163 VOP_LOCK(vp,LK_EXCLUSIVE); 164 ip = VTOI(vp); 165 blkno = lblkno(fs, ip->i_ffs_size); 166 if ((error = VOP_BALLOC(vp, ip->i_ffs_size, fs->lfs_bsize, 167 NULL, 0, &bp)) != 0) 168 return (error); 169 ip->i_ffs_size += fs->lfs_bsize; 170 uvm_vnp_setsize(vp, ip->i_ffs_size); 171 (void)uvm_vnp_uncache(vp); 172 173 i = (blkno - fs->lfs_segtabsz - fs->lfs_cleansz) * 174 fs->lfs_ifpb; 175 fs->lfs_free = i; 176 #ifdef DIAGNOSTIC 177 if(fs->lfs_free == LFS_UNUSED_INUM) 178 panic("inode 0 allocated [2]"); 179 #endif /* DIAGNOSTIC */ 180 max = i + fs->lfs_ifpb; 181 for (ifp = (struct ifile *)bp->b_data; i < max; ++ifp) { 182 ifp->if_version = 1; 183 ifp->if_daddr = LFS_UNUSED_DADDR; 184 ifp->if_nextfree = ++i; 185 } 186 ifp--; 187 ifp->if_nextfree = LFS_UNUSED_INUM; 188 VOP_UNLOCK(vp,0); 189 if ((error = VOP_BWRITE(bp)) != 0) { 190 lockmgr(&ufs_hashlock, LK_RELEASE, 0); 191 return (error); 192 } 193 } 194 195 #ifdef DIAGNOSTIC 196 if(fs->lfs_free == LFS_UNUSED_INUM) 197 panic("inode 0 allocated [3]"); 198 #endif /* DIAGNOSTIC */ 199 200 /* Create a vnode to associate with the inode. */ 201 if ((error = lfs_vcreate(ap->a_pvp->v_mount, new_ino, &vp)) != 0) { 202 lockmgr(&ufs_hashlock, LK_RELEASE, 0); 203 return (error); 204 } 205 206 ip = VTOI(vp); 207 /* Zero out the direct and indirect block addresses. */ 208 bzero(&ip->i_din, sizeof(ip->i_din)); 209 ip->i_din.ffs_din.di_inumber = new_ino; 210 211 /* Set a new generation number for this inode. */ 212 ip->i_ffs_gen++; 213 214 /* Insert into the inode hash table. */ 215 ufs_ihashins(ip); 216 lockmgr(&ufs_hashlock, LK_RELEASE, 0); 217 218 error = ufs_vinit(vp->v_mount, lfs_specop_p, lfs_fifoop_p, &vp); 219 if (error) { 220 vput(vp); 221 *ap->a_vpp = NULL; 222 return (error); 223 } 224 225 *ap->a_vpp = vp; 226 if(!(vp->v_flag & VDIROP)) { 227 lfs_vref(vp); 228 ++lfs_dirvcount; 229 } 230 vp->v_flag |= VDIROP; 231 VREF(ip->i_devvp); 232 233 /* Set superblock modified bit and increment file count. */ 234 fs->lfs_fmod = 1; 235 ++fs->lfs_nfiles; 236 return (0); 237 } 238 239 /* Create a new vnode/inode pair and initialize what fields we can. */ 240 int 241 lfs_vcreate(mp, ino, vpp) 242 struct mount *mp; 243 ino_t ino; 244 struct vnode **vpp; 245 { 246 extern int (**lfs_vnodeop_p) __P((void *)); 247 struct inode *ip; 248 struct ufsmount *ump; 249 int error; 250 #ifdef QUOTA 251 int i; 252 #endif 253 254 /* Create the vnode. */ 255 if ((error = getnewvnode(VT_LFS, mp, lfs_vnodeop_p, vpp)) != 0) { 256 *vpp = NULL; 257 return (error); 258 } 259 260 /* Get a pointer to the private mount structure. */ 261 ump = VFSTOUFS(mp); 262 263 /* Initialize the inode. */ 264 ip = pool_get(&lfs_inode_pool, PR_WAITOK); 265 (*vpp)->v_data = ip; 266 ip->i_vnode = *vpp; 267 ip->i_devvp = ump->um_devvp; 268 ip->i_flag = IN_MODIFIED; 269 ip->i_dev = ump->um_dev; 270 ip->i_number = ip->i_din.ffs_din.di_inumber = ino; 271 ip->i_lfs = ump->um_lfs; 272 #ifdef QUOTA 273 for (i = 0; i < MAXQUOTAS; i++) 274 ip->i_dquot[i] = NODQUOT; 275 #endif 276 ip->i_lockf = 0; 277 ip->i_diroff = 0; 278 ip->i_ffs_mode = 0; 279 ip->i_ffs_size = 0; 280 ip->i_ffs_blocks = 0; 281 ++ump->um_lfs->lfs_uinodes; 282 return (0); 283 } 284 285 /* Free an inode. */ 286 /* ARGUSED */ 287 int 288 lfs_vfree(v) 289 void *v; 290 { 291 struct vop_vfree_args /* { 292 struct vnode *a_pvp; 293 ino_t a_ino; 294 int a_mode; 295 } */ *ap = v; 296 SEGUSE *sup; 297 struct buf *bp; 298 struct ifile *ifp; 299 struct inode *ip; 300 struct vnode *vp; 301 struct lfs *fs; 302 ufs_daddr_t old_iaddr; 303 ino_t ino; 304 int already_locked; 305 extern int lfs_dirvcount; 306 307 /* Get the inode number and file system. */ 308 vp = ap->a_pvp; 309 ip = VTOI(vp); 310 fs = ip->i_lfs; 311 ino = ip->i_number; 312 313 /* If we already hold ufs_hashlock, don't panic, just do it anyway */ 314 already_locked = lockstatus(&ufs_hashlock) && ufs_hashlock.lk_lockholder == curproc->p_pid; 315 while(WRITEINPROG(vp) 316 || fs->lfs_seglock 317 || (!already_locked && lockmgr(&ufs_hashlock, LK_EXCLUSIVE|LK_SLEEPFAIL, 0))) 318 { 319 if (WRITEINPROG(vp)) { 320 tsleep(vp, (PRIBIO+1), "lfs_vfree", 0); 321 } 322 if (fs->lfs_seglock) { 323 if (fs->lfs_lockpid == curproc->p_pid) { 324 break; 325 } else { 326 tsleep(&fs->lfs_seglock, PRIBIO + 1, "lfs_vfr1", 0); 327 } 328 } 329 } 330 331 if(vp->v_flag & VDIROP) { 332 --lfs_dirvcount; 333 vp->v_flag &= ~VDIROP; 334 wakeup(&lfs_dirvcount); 335 lfs_vunref(vp); 336 } 337 338 if (ip->i_flag & IN_CLEANING) { 339 --fs->lfs_uinodes; 340 } 341 if (ip->i_flag & IN_MODIFIED) { 342 --fs->lfs_uinodes; 343 } 344 ip->i_flag &= ~(IN_CLEANING | IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE); 345 #ifdef DEBUG_LFS 346 if((int32_t)fs->lfs_uinodes<0) { 347 printf("U1"); 348 fs->lfs_uinodes=0; 349 } 350 #endif 351 /* 352 * Set the ifile's inode entry to unused, increment its version number 353 * and link it into the free chain. 354 */ 355 LFS_IENTRY(ifp, fs, ino, bp); 356 old_iaddr = ifp->if_daddr; 357 ifp->if_daddr = LFS_UNUSED_DADDR; 358 ++ifp->if_version; 359 ifp->if_nextfree = fs->lfs_free; 360 fs->lfs_free = ino; 361 (void) VOP_BWRITE(bp); 362 #ifdef DIAGNOSTIC 363 if(fs->lfs_free == LFS_UNUSED_INUM) { 364 panic("inode 0 freed"); 365 } 366 #endif /* DIAGNOSTIC */ 367 if (old_iaddr != LFS_UNUSED_DADDR) { 368 LFS_SEGENTRY(sup, fs, datosn(fs, old_iaddr), bp); 369 #ifdef DIAGNOSTIC 370 if (sup->su_nbytes < DINODE_SIZE) { 371 printf("lfs_vfree: negative byte count (segment %d short by %d)\n", datosn(fs, old_iaddr), (int)DINODE_SIZE - sup->su_nbytes); 372 panic("lfs_vfree: negative byte count"); 373 sup->su_nbytes = DINODE_SIZE; 374 } 375 #endif 376 sup->su_nbytes -= DINODE_SIZE; 377 (void) VOP_BWRITE(bp); 378 } 379 if(!already_locked) 380 lockmgr(&ufs_hashlock, LK_RELEASE, 0); 381 382 /* Set superblock modified bit and decrement file count. */ 383 fs->lfs_fmod = 1; 384 --fs->lfs_nfiles; 385 386 return (0); 387 } 388