1 /* $NetBSD: lfs_alloc.c,v 1.42 2000/07/05 22:25:43 perseant Exp $ */ 2 3 /*- 4 * Copyright (c) 1999, 2000 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 <ufs/ufs/quota.h> 88 #include <ufs/ufs/inode.h> 89 #include <ufs/ufs/ufsmount.h> 90 #include <ufs/ufs/ufs_extern.h> 91 92 #include <ufs/lfs/lfs.h> 93 #include <ufs/lfs/lfs_extern.h> 94 95 extern int lfs_dirvcount; 96 extern struct lock ufs_hashlock; 97 98 /* Allocate a new inode. */ 99 /* ARGSUSED */ 100 int 101 lfs_valloc(v) 102 void *v; 103 { 104 struct vop_valloc_args /* { 105 struct vnode *a_pvp; 106 int a_mode; 107 struct ucred *a_cred; 108 struct vnode **a_vpp; 109 } */ *ap = v; 110 struct lfs *fs; 111 struct buf *bp; 112 struct ifile *ifp; 113 struct inode *ip; 114 struct vnode *vp; 115 ufs_daddr_t blkno; 116 ino_t new_ino; 117 u_long i, max; 118 int error; 119 int new_gen; 120 extern int lfs_dirvcount; 121 122 fs = VTOI(ap->a_pvp)->i_lfs; 123 if (fs->lfs_ronly) 124 return EROFS; 125 *ap->a_vpp = NULL; 126 127 /* 128 * Use lfs_seglock here, instead of fs->lfs_freelock, to ensure that 129 * the free list is not changed in between the time that the ifile 130 * blocks are written to disk and the time that the superblock is 131 * written to disk. 132 * 133 * XXX this sucks. We should instead encode the head of the free 134 * list into the CLEANERINFO block of the Ifile. 135 */ 136 lfs_seglock(fs, SEGM_PROT); 137 138 /* Get the head of the freelist. */ 139 new_ino = fs->lfs_free; 140 #ifdef DIAGNOSTIC 141 if(new_ino == LFS_UNUSED_INUM) { 142 #ifdef DEBUG 143 lfs_dump_super(fs); 144 #endif /* DEBUG */ 145 panic("inode 0 allocated [1]"); 146 } 147 #endif /* DIAGNOSTIC */ 148 #ifdef ALLOCPRINT 149 printf("lfs_ialloc: allocate inode %d\n", new_ino); 150 #endif 151 152 /* 153 * Remove the inode from the free list and write the new start 154 * of the free list into the superblock. 155 */ 156 LFS_IENTRY(ifp, fs, new_ino, bp); 157 if (ifp->if_daddr != LFS_UNUSED_DADDR) 158 panic("lfs_ialloc: inuse inode %d on the free list", new_ino); 159 fs->lfs_free = ifp->if_nextfree; 160 new_gen = ifp->if_version; /* version was updated by vfree */ 161 #ifdef LFS_DEBUG_NEXTFREE 162 ifp->if_nextfree = 0; 163 VOP_BWRITE(bp); 164 #else 165 brelse(bp); 166 #endif 167 168 /* Extend IFILE so that the next lfs_valloc will succeed. */ 169 if (fs->lfs_free == LFS_UNUSED_INUM) { 170 vp = fs->lfs_ivnode; 171 (void)lfs_vref(vp); 172 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 173 ip = VTOI(vp); 174 blkno = lblkno(fs, ip->i_ffs_size); 175 if ((error = VOP_BALLOC(vp, ip->i_ffs_size, fs->lfs_bsize, 176 ap->a_cred, 0, &bp)) != 0) { 177 VOP_UNLOCK(vp, 0); 178 lfs_segunlock(fs); 179 fs->lfs_free = new_ino; 180 return (error); 181 } 182 ip->i_ffs_size += fs->lfs_bsize; 183 uvm_vnp_setsize(vp, ip->i_ffs_size); 184 (void)uvm_vnp_uncache(vp); 185 VOP_UNLOCK(vp, 0); 186 187 i = (blkno - fs->lfs_segtabsz - fs->lfs_cleansz) * 188 fs->lfs_ifpb; 189 fs->lfs_free = i; 190 #ifdef DIAGNOSTIC 191 if(fs->lfs_free == LFS_UNUSED_INUM) 192 panic("inode 0 allocated [2]"); 193 #endif /* DIAGNOSTIC */ 194 max = i + fs->lfs_ifpb; 195 for (ifp = (struct ifile *)bp->b_data; i < max; ++ifp) { 196 ifp->if_version = 1; 197 ifp->if_daddr = LFS_UNUSED_DADDR; 198 ifp->if_nextfree = ++i; 199 } 200 ifp--; 201 ifp->if_nextfree = LFS_UNUSED_INUM; 202 VOP_BWRITE(bp); 203 lfs_vunref(vp); 204 } 205 #ifdef DIAGNOSTIC 206 if(fs->lfs_free == LFS_UNUSED_INUM) 207 panic("inode 0 allocated [3]"); 208 #endif /* DIAGNOSTIC */ 209 210 lfs_segunlock(fs); 211 212 if ((error = getnewvnode(VT_LFS, ap->a_pvp->v_mount, 213 lfs_vnodeop_p, &vp)) != 0) 214 goto errout; 215 216 lockmgr(&ufs_hashlock, LK_EXCLUSIVE, 0); 217 /* Create an inode to associate with the vnode. */ 218 lfs_vcreate(ap->a_pvp->v_mount, new_ino, vp); 219 220 ip = VTOI(vp); 221 /* Zero out the direct and indirect block addresses. */ 222 bzero(&ip->i_din, sizeof(ip->i_din)); 223 ip->i_din.ffs_din.di_inumber = new_ino; 224 225 /* Set a new generation number for this inode. */ 226 ip->i_ffs_gen = new_gen; 227 228 /* Insert into the inode hash table. */ 229 ufs_ihashins(ip); 230 lockmgr(&ufs_hashlock, LK_RELEASE, 0); 231 232 error = ufs_vinit(vp->v_mount, lfs_specop_p, lfs_fifoop_p, &vp); 233 if (error) { 234 vput(vp); 235 goto errout; 236 } 237 238 *ap->a_vpp = vp; 239 #if 1 240 if(!(vp->v_flag & VDIROP)) { 241 (void)lfs_vref(vp); 242 ++lfs_dirvcount; 243 } 244 vp->v_flag |= VDIROP; 245 246 if(!(ip->i_flag & IN_ADIROP)) 247 ++fs->lfs_nadirop; 248 ip->i_flag |= IN_ADIROP; 249 #endif 250 VREF(ip->i_devvp); 251 /* Set superblock modified bit and increment file count. */ 252 fs->lfs_fmod = 1; 253 ++fs->lfs_nfiles; 254 return (0); 255 256 errout: 257 /* 258 * Put the new inum back on the free list. 259 */ 260 LFS_IENTRY(ifp, fs, new_ino, bp); 261 ifp->if_daddr = LFS_UNUSED_DADDR; 262 ifp->if_nextfree = fs->lfs_free; 263 fs->lfs_free = new_ino; 264 VOP_BWRITE(bp); 265 266 return (error); 267 } 268 269 /* Create a new vnode/inode pair and initialize what fields we can. */ 270 void 271 lfs_vcreate(mp, ino, vp) 272 struct mount *mp; 273 ino_t ino; 274 struct vnode *vp; 275 { 276 struct inode *ip; 277 struct ufsmount *ump; 278 #ifdef QUOTA 279 int i; 280 #endif 281 282 /* Get a pointer to the private mount structure. */ 283 ump = VFSTOUFS(mp); 284 285 /* Initialize the inode. */ 286 ip = pool_get(&lfs_inode_pool, PR_WAITOK); 287 vp->v_data = ip; 288 ip->i_vnode = vp; 289 ip->i_devvp = ump->um_devvp; 290 ip->i_dev = ump->um_dev; 291 ip->i_number = ip->i_din.ffs_din.di_inumber = ino; 292 ip->i_lfs = ump->um_lfs; 293 #ifdef QUOTA 294 for (i = 0; i < MAXQUOTAS; i++) 295 ip->i_dquot[i] = NODQUOT; 296 #endif 297 ip->i_lockf = 0; 298 ip->i_diroff = 0; 299 ip->i_ffs_mode = 0; 300 ip->i_ffs_size = 0; 301 ip->i_ffs_blocks = 0; 302 ip->i_lfs_effnblks = 0; 303 ip->i_flag = 0; 304 LFS_SET_UINO(ip, IN_MODIFIED); 305 } 306 307 /* Free an inode. */ 308 /* ARGUSED */ 309 int 310 lfs_vfree(v) 311 void *v; 312 { 313 struct vop_vfree_args /* { 314 struct vnode *a_pvp; 315 ino_t a_ino; 316 int a_mode; 317 } */ *ap = v; 318 SEGUSE *sup; 319 struct buf *bp; 320 struct ifile *ifp; 321 struct inode *ip; 322 struct vnode *vp; 323 struct lfs *fs; 324 ufs_daddr_t old_iaddr; 325 ino_t ino; 326 extern int lfs_dirvcount; 327 328 /* Get the inode number and file system. */ 329 vp = ap->a_pvp; 330 ip = VTOI(vp); 331 fs = ip->i_lfs; 332 ino = ip->i_number; 333 334 #if 0 335 /* 336 * Right now this is unnecessary since we take the seglock. 337 * But if the seglock is no longer necessary (e.g. we put the 338 * head of the free list into the Ifile) we will need to drain 339 * this vnode of any pending writes. 340 */ 341 if (WRITEINPROG(vp)) 342 tsleep(vp, (PRIBIO+1), "lfs_vfree", 0); 343 #endif 344 lfs_seglock(fs, SEGM_PROT); 345 346 if(vp->v_flag & VDIROP) { 347 --lfs_dirvcount; 348 vp->v_flag &= ~VDIROP; 349 wakeup(&lfs_dirvcount); 350 lfs_vunref(vp); 351 } 352 if (ip->i_flag & IN_ADIROP) { 353 --fs->lfs_nadirop; 354 ip->i_flag &= ~IN_ADIROP; 355 } 356 357 LFS_CLR_UINO(ip, IN_ACCESSED|IN_CLEANING|IN_MODIFIED); 358 ip->i_flag &= ~IN_ALLMOD; 359 360 /* 361 * Set the ifile's inode entry to unused, increment its version number 362 * and link it into the free chain. 363 */ 364 LFS_IENTRY(ifp, fs, ino, bp); 365 old_iaddr = ifp->if_daddr; 366 ifp->if_daddr = LFS_UNUSED_DADDR; 367 ++ifp->if_version; 368 ifp->if_nextfree = fs->lfs_free; 369 fs->lfs_free = ino; 370 (void) VOP_BWRITE(bp); 371 #ifdef DIAGNOSTIC 372 if(fs->lfs_free == LFS_UNUSED_INUM) { 373 panic("inode 0 freed"); 374 } 375 #endif /* DIAGNOSTIC */ 376 if (old_iaddr != LFS_UNUSED_DADDR) { 377 LFS_SEGENTRY(sup, fs, datosn(fs, old_iaddr), bp); 378 #ifdef DIAGNOSTIC 379 if (sup->su_nbytes < DINODE_SIZE) { 380 printf("lfs_vfree: negative byte count (segment %d short by %d)\n", datosn(fs, old_iaddr), (int)DINODE_SIZE - sup->su_nbytes); 381 panic("lfs_vfree: negative byte count"); 382 sup->su_nbytes = DINODE_SIZE; 383 } 384 #endif 385 sup->su_nbytes -= DINODE_SIZE; 386 (void) VOP_BWRITE(bp); 387 } 388 389 /* Set superblock modified bit and decrement file count. */ 390 fs->lfs_fmod = 1; 391 --fs->lfs_nfiles; 392 393 lfs_segunlock(fs); 394 return (0); 395 } 396