1 /* $NetBSD: lfs_alloc.c,v 1.33 2000/05/31 01:40:02 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. 126 */ 127 lockmgr(&fs->lfs_freelock, LK_EXCLUSIVE, 0); 128 129 /* Get the head of the freelist. */ 130 new_ino = fs->lfs_free; 131 #ifdef DIAGNOSTIC 132 if(new_ino == LFS_UNUSED_INUM) { 133 #ifdef DEBUG 134 lfs_dump_super(fs); 135 #endif /* DEBUG */ 136 panic("inode 0 allocated [1]"); 137 } 138 #endif /* DIAGNOSTIC */ 139 #ifdef ALLOCPRINT 140 printf("lfs_ialloc: allocate inode %d\n", new_ino); 141 #endif 142 143 /* 144 * Remove the inode from the free list and write the new start 145 * of the free list into the superblock. 146 */ 147 LFS_IENTRY(ifp, fs, new_ino, bp); 148 if (ifp->if_daddr != LFS_UNUSED_DADDR) 149 panic("lfs_ialloc: inuse inode %d on the free list", new_ino); 150 fs->lfs_free = ifp->if_nextfree; 151 #ifdef LFS_DEBUG_NEXTFREE 152 ifp->if_nextfree = 0; 153 VOP_BWRITE(bp); 154 #else 155 brelse(bp); 156 #endif 157 158 /* Extend IFILE so that the next lfs_valloc will succeed. */ 159 if (fs->lfs_free == LFS_UNUSED_INUM) { 160 vp = fs->lfs_ivnode; 161 VOP_LOCK(vp,LK_EXCLUSIVE); 162 ip = VTOI(vp); 163 blkno = lblkno(fs, ip->i_ffs_size); 164 if ((error = VOP_BALLOC(vp, ip->i_ffs_size, fs->lfs_bsize, 165 NULL, 0, &bp)) != 0) { 166 return (error); 167 } 168 ip->i_ffs_size += fs->lfs_bsize; 169 uvm_vnp_setsize(vp, ip->i_ffs_size); 170 (void)uvm_vnp_uncache(vp); 171 172 i = (blkno - fs->lfs_segtabsz - fs->lfs_cleansz) * 173 fs->lfs_ifpb; 174 fs->lfs_free = i; 175 #ifdef DIAGNOSTIC 176 if(fs->lfs_free == LFS_UNUSED_INUM) 177 panic("inode 0 allocated [2]"); 178 #endif /* DIAGNOSTIC */ 179 max = i + fs->lfs_ifpb; 180 for (ifp = (struct ifile *)bp->b_data; i < max; ++ifp) { 181 ifp->if_version = 1; 182 ifp->if_daddr = LFS_UNUSED_DADDR; 183 ifp->if_nextfree = ++i; 184 } 185 ifp--; 186 ifp->if_nextfree = LFS_UNUSED_INUM; 187 VOP_UNLOCK(vp,0); 188 if ((error = VOP_BWRITE(bp)) != 0) { 189 return (error); 190 } 191 } 192 #ifdef DIAGNOSTIC 193 if(fs->lfs_free == LFS_UNUSED_INUM) 194 panic("inode 0 allocated [3]"); 195 #endif /* DIAGNOSTIC */ 196 197 lockmgr(&fs->lfs_freelock, LK_RELEASE, 0); 198 199 lockmgr(&ufs_hashlock, LK_EXCLUSIVE, 0); 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 if(!(ip->i_flag & IN_ADIROP)) 234 ++fs->lfs_nadirop; 235 ip->i_flag |= IN_ADIROP; 236 237 /* Set superblock modified bit and increment file count. */ 238 fs->lfs_fmod = 1; 239 ++fs->lfs_nfiles; 240 return (0); 241 } 242 243 /* Create a new vnode/inode pair and initialize what fields we can. */ 244 int 245 lfs_vcreate(mp, ino, vpp) 246 struct mount *mp; 247 ino_t ino; 248 struct vnode **vpp; 249 { 250 extern int (**lfs_vnodeop_p) __P((void *)); 251 struct inode *ip; 252 struct ufsmount *ump; 253 int error; 254 #ifdef QUOTA 255 int i; 256 #endif 257 258 /* Create the vnode. */ 259 if ((error = getnewvnode(VT_LFS, mp, lfs_vnodeop_p, vpp)) != 0) { 260 *vpp = NULL; 261 return (error); 262 } 263 264 /* Get a pointer to the private mount structure. */ 265 ump = VFSTOUFS(mp); 266 267 /* Initialize the inode. */ 268 ip = pool_get(&lfs_inode_pool, PR_WAITOK); 269 (*vpp)->v_data = ip; 270 ip->i_vnode = *vpp; 271 ip->i_devvp = ump->um_devvp; 272 ip->i_flag = IN_MODIFIED; 273 ip->i_dev = ump->um_dev; 274 ip->i_number = ip->i_din.ffs_din.di_inumber = ino; 275 ip->i_lfs = ump->um_lfs; 276 #ifdef QUOTA 277 for (i = 0; i < MAXQUOTAS; i++) 278 ip->i_dquot[i] = NODQUOT; 279 #endif 280 ip->i_lockf = 0; 281 ip->i_diroff = 0; 282 ip->i_ffs_mode = 0; 283 ip->i_ffs_size = 0; 284 ip->i_ffs_blocks = 0; 285 ++ump->um_lfs->lfs_uinodes; 286 return (0); 287 } 288 289 /* Free an inode. */ 290 /* ARGUSED */ 291 int 292 lfs_vfree(v) 293 void *v; 294 { 295 struct vop_vfree_args /* { 296 struct vnode *a_pvp; 297 ino_t a_ino; 298 int a_mode; 299 } */ *ap = v; 300 SEGUSE *sup; 301 struct buf *bp; 302 struct ifile *ifp; 303 struct inode *ip; 304 struct vnode *vp; 305 struct lfs *fs; 306 ufs_daddr_t old_iaddr; 307 ino_t ino; 308 extern int lfs_dirvcount; 309 310 /* Get the inode number and file system. */ 311 vp = ap->a_pvp; 312 ip = VTOI(vp); 313 fs = ip->i_lfs; 314 ino = ip->i_number; 315 316 while(WRITEINPROG(vp) 317 || fs->lfs_seglock 318 || lockmgr(&fs->lfs_freelock, LK_EXCLUSIVE|LK_SLEEPFAIL, 0)) 319 { 320 if (WRITEINPROG(vp)) { 321 tsleep(vp, (PRIBIO+1), "lfs_vfree", 0); 322 } 323 if (fs->lfs_seglock) { 324 if (fs->lfs_lockpid == curproc->p_pid) { 325 break; 326 } else { 327 tsleep(&fs->lfs_seglock, PRIBIO + 1, "lfs_vfr1", 0); 328 } 329 } 330 } 331 332 if(vp->v_flag & VDIROP) { 333 --lfs_dirvcount; 334 vp->v_flag &= ~VDIROP; 335 wakeup(&lfs_dirvcount); 336 lfs_vunref(vp); 337 } 338 339 if (ip->i_flag & IN_CLEANING) { 340 --fs->lfs_uinodes; 341 } 342 if (ip->i_flag & (IN_MODIFIED | IN_ACCESSED)) { 343 --fs->lfs_uinodes; 344 } 345 ip->i_flag &= ~IN_ALLMOD; 346 #ifdef DEBUG_LFS 347 if((int32_t)fs->lfs_uinodes<0) { 348 printf("U1"); 349 fs->lfs_uinodes=0; 350 } 351 #endif 352 /* 353 * Set the ifile's inode entry to unused, increment its version number 354 * and link it into the free chain. 355 */ 356 LFS_IENTRY(ifp, fs, ino, bp); 357 old_iaddr = ifp->if_daddr; 358 ifp->if_daddr = LFS_UNUSED_DADDR; 359 ++ifp->if_version; 360 ifp->if_nextfree = fs->lfs_free; 361 fs->lfs_free = ino; 362 (void) VOP_BWRITE(bp); 363 #ifdef DIAGNOSTIC 364 if(fs->lfs_free == LFS_UNUSED_INUM) { 365 panic("inode 0 freed"); 366 } 367 #endif /* DIAGNOSTIC */ 368 if (old_iaddr != LFS_UNUSED_DADDR) { 369 LFS_SEGENTRY(sup, fs, datosn(fs, old_iaddr), bp); 370 #ifdef DIAGNOSTIC 371 if (sup->su_nbytes < DINODE_SIZE) { 372 printf("lfs_vfree: negative byte count (segment %d short by %d)\n", datosn(fs, old_iaddr), (int)DINODE_SIZE - sup->su_nbytes); 373 panic("lfs_vfree: negative byte count"); 374 sup->su_nbytes = DINODE_SIZE; 375 } 376 #endif 377 sup->su_nbytes -= DINODE_SIZE; 378 (void) VOP_BWRITE(bp); 379 } 380 lockmgr(&fs->lfs_freelock, 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