1 /* $OpenBSD: ext2fs_balloc.c,v 1.18 2011/07/04 04:30:41 tedu Exp $ */ 2 /* $NetBSD: ext2fs_balloc.c,v 1.10 2001/07/04 21:16:01 chs Exp $ */ 3 4 /* 5 * Copyright (c) 1997 Manuel Bouyer. 6 * Copyright (c) 1982, 1986, 1989, 1993 7 * The Regents of the University of California. All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * @(#)ffs_balloc.c 8.4 (Berkeley) 9/23/93 34 * Modified for ext2fs by Manuel Bouyer. 35 */ 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/buf.h> 40 #include <sys/proc.h> 41 #include <sys/file.h> 42 #include <sys/vnode.h> 43 44 #include <uvm/uvm_extern.h> 45 46 #include <ufs/ufs/quota.h> 47 #include <ufs/ufs/inode.h> 48 #include <ufs/ufs/ufs_extern.h> 49 50 #include <ufs/ext2fs/ext2fs.h> 51 #include <ufs/ext2fs/ext2fs_extern.h> 52 53 /* 54 * Balloc defines the structure of file system storage 55 * by allocating the physical blocks on a device given 56 * the inode and the logical block number in a file. 57 */ 58 int 59 ext2fs_buf_alloc(struct inode *ip, daddr64_t bn, int size, struct ucred *cred, 60 struct buf **bpp, int flags) 61 { 62 struct m_ext2fs *fs; 63 struct buf *bp, *nbp; 64 struct vnode *vp = ITOV(ip); 65 struct indir indirs[NIADDR + 2]; 66 int32_t nb, newb, *bap; 67 int num, i, error; 68 u_int deallocated; 69 int32_t *allocib, *blkp, *allocblk, allociblk[NIADDR + 1]; 70 int unwindidx = -1; 71 daddr64_t lbn, pref; 72 73 *bpp = NULL; 74 if (bn < 0) 75 return (EFBIG); 76 fs = ip->i_e2fs; 77 lbn = bn; 78 79 /* 80 * The first NDADDR blocks are direct blocks 81 */ 82 if (bn < NDADDR) { 83 nb = fs2h32(ip->i_e2fs_blocks[bn]); 84 if (nb != 0) { 85 error = bread(vp, bn, fs->e2fs_bsize, &bp); 86 if (error) { 87 brelse(bp); 88 return (error); 89 } 90 *bpp = bp; 91 return (0); 92 } 93 94 /* 95 * allocate a new direct block. 96 */ 97 error = ext2fs_alloc(ip, bn, 98 ext2fs_blkpref(ip, bn, (int)bn, &ip->i_e2fs_blocks[0]), 99 cred, &newb); 100 if (error) 101 return (error); 102 ip->i_e2fs_last_lblk = lbn; 103 ip->i_e2fs_last_blk = newb; 104 ip->i_e2fs_blocks[bn] = h2fs32(newb); 105 ip->i_flag |= IN_CHANGE | IN_UPDATE; 106 bp = getblk(vp, bn, fs->e2fs_bsize, 0, 0); 107 bp->b_blkno = fsbtodb(fs, newb); 108 if (flags & B_CLRBUF) 109 clrbuf(bp); 110 *bpp = bp; 111 return (0); 112 } 113 /* 114 * Determine the number of levels of indirection. 115 */ 116 pref = 0; 117 if ((error = ufs_getlbns(vp, bn, indirs, &num)) != 0) 118 return(error); 119 #ifdef DIAGNOSTIC 120 if (num < 1) 121 panic ("ext2fs_balloc: ufs_getlbns returned indirect block"); 122 #endif 123 /* 124 * Fetch the first indirect block allocating if necessary. 125 */ 126 --num; 127 nb = fs2h32(ip->i_e2fs_blocks[NDADDR + indirs[0].in_off]); 128 allocib = NULL; 129 allocblk = allociblk; 130 if (nb == 0) { 131 pref = ext2fs_blkpref(ip, lbn, 0, (int32_t *)0); 132 error = ext2fs_alloc(ip, lbn, pref, cred, &newb); 133 if (error) 134 return (error); 135 nb = newb; 136 *allocblk++ = nb; 137 ip->i_e2fs_last_blk = newb; 138 bp = getblk(vp, indirs[1].in_lbn, fs->e2fs_bsize, 0, 0); 139 bp->b_blkno = fsbtodb(fs, newb); 140 clrbuf(bp); 141 /* 142 * Write synchronously so that indirect blocks 143 * never point at garbage. 144 */ 145 if ((error = bwrite(bp)) != 0) 146 goto fail; 147 unwindidx = 0; 148 allocib = &ip->i_e2fs_blocks[NDADDR + indirs[0].in_off]; 149 *allocib = h2fs32(newb); 150 ip->i_flag |= IN_CHANGE | IN_UPDATE; 151 } 152 /* 153 * Fetch through the indirect blocks, allocating as necessary. 154 */ 155 for (i = 1;;) { 156 error = bread(vp, indirs[i].in_lbn, (int)fs->e2fs_bsize, &bp); 157 if (error) { 158 brelse(bp); 159 goto fail; 160 } 161 bap = (int32_t *)bp->b_data; 162 nb = fs2h32(bap[indirs[i].in_off]); 163 if (i == num) 164 break; 165 i++; 166 if (nb != 0) { 167 brelse(bp); 168 continue; 169 } 170 pref = ext2fs_blkpref(ip, lbn, 0, (int32_t *)0); 171 error = ext2fs_alloc(ip, lbn, pref, cred, &newb); 172 if (error) { 173 brelse(bp); 174 goto fail; 175 } 176 nb = newb; 177 *allocblk++ = nb; 178 ip->i_e2fs_last_blk = newb; 179 nbp = getblk(vp, indirs[i].in_lbn, fs->e2fs_bsize, 0, 0); 180 nbp->b_blkno = fsbtodb(fs, nb); 181 clrbuf(nbp); 182 /* 183 * Write synchronously so that indirect blocks 184 * never point at garbage. 185 */ 186 if ((error = bwrite(nbp)) != 0) { 187 brelse(bp); 188 goto fail; 189 } 190 if (unwindidx < 0) 191 unwindidx = i - 1; 192 bap[indirs[i - 1].in_off] = h2fs32(nb); 193 /* 194 * If required, write synchronously, otherwise use 195 * delayed write. 196 */ 197 if (flags & B_SYNC) { 198 bwrite(bp); 199 } else { 200 bdwrite(bp); 201 } 202 } 203 /* 204 * Get the data block, allocating if necessary. 205 */ 206 if (nb == 0) { 207 pref = ext2fs_blkpref(ip, lbn, indirs[num].in_off, &bap[0]); 208 error = ext2fs_alloc(ip, lbn, pref, cred, &newb); 209 if (error) { 210 brelse(bp); 211 goto fail; 212 } 213 nb = newb; 214 *allocblk++ = nb; 215 ip->i_e2fs_last_lblk = lbn; 216 ip->i_e2fs_last_blk = newb; 217 bap[indirs[num].in_off] = h2fs32(nb); 218 /* 219 * If required, write synchronously, otherwise use 220 * delayed write. 221 */ 222 if (flags & B_SYNC) { 223 bwrite(bp); 224 } else { 225 bdwrite(bp); 226 } 227 nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0); 228 nbp->b_blkno = fsbtodb(fs, nb); 229 if (flags & B_CLRBUF) 230 clrbuf(nbp); 231 *bpp = nbp; 232 return (0); 233 } 234 brelse(bp); 235 if (flags & B_CLRBUF) { 236 error = bread(vp, lbn, (int)fs->e2fs_bsize, &nbp); 237 if (error) { 238 brelse(nbp); 239 goto fail; 240 } 241 } else { 242 nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0); 243 nbp->b_blkno = fsbtodb(fs, nb); 244 } 245 246 *bpp = nbp; 247 return (0); 248 fail: 249 /* 250 * If we have failed part way through block allocation, we 251 * have to deallocate any indirect blocks that we have allocated. 252 */ 253 for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) { 254 ext2fs_blkfree(ip, *blkp); 255 deallocated += fs->e2fs_bsize; 256 } 257 if (unwindidx >= 0) { 258 if (unwindidx == 0) { 259 *allocib = 0; 260 } else { 261 int r; 262 263 r = bread(vp, indirs[unwindidx].in_lbn, 264 (int)fs->e2fs_bsize, &bp); 265 if (r) { 266 panic("Could not unwind indirect block, error %d", r); 267 } else { 268 bap = (int32_t *)bp->b_data; 269 bap[indirs[unwindidx].in_off] = 0; 270 if (flags & B_SYNC) 271 bwrite(bp); 272 else 273 bdwrite(bp); 274 } 275 } 276 for (i = unwindidx + 1; i <= num; i++) { 277 bp = getblk(vp, indirs[i].in_lbn, (int)fs->e2fs_bsize, 278 0, 0); 279 bp->b_flags |= B_INVAL; 280 brelse(bp); 281 } 282 } 283 if (deallocated) { 284 ip->i_e2fs_nblock -= btodb(deallocated); 285 ip->i_e2fs_flags |= IN_CHANGE | IN_UPDATE; 286 } 287 return error; 288 } 289