1 /* $NetBSD: ext2fs_bmap.c,v 1.11 2003/05/18 12:59:05 yamt Exp $ */ 2 3 /* 4 * Copyright (c) 1997 Manuel Bouyer. 5 * Copyright (c) 1989, 1991, 1993 6 * The Regents of the University of California. All rights reserved. 7 * (c) UNIX System Laboratories, Inc. 8 * All or some portions of this file are derived from material licensed 9 * to the University of California by American Telephone and Telegraph 10 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 11 * the permission of UNIX System Laboratories, Inc. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. All advertising materials mentioning features or use of this software 22 * must display the following acknowledgement: 23 * This product includes software developed by the University of 24 * California, Berkeley and its contributors. 25 * 4. Neither the name of the University nor the names of its contributors 26 * may be used to endorse or promote products derived from this software 27 * without specific prior written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 39 * SUCH DAMAGE. 40 * 41 * @(#)ufs_bmap.c 8.6 (Berkeley) 1/21/94 42 * Modified for ext2fs by Manuel Bouyer. 43 */ 44 45 #include <sys/cdefs.h> 46 __KERNEL_RCSID(0, "$NetBSD: ext2fs_bmap.c,v 1.11 2003/05/18 12:59:05 yamt Exp $"); 47 48 #include <sys/param.h> 49 #include <sys/systm.h> 50 #include <sys/buf.h> 51 #include <sys/proc.h> 52 #include <sys/vnode.h> 53 #include <sys/mount.h> 54 #include <sys/resourcevar.h> 55 #include <sys/trace.h> 56 57 #include <miscfs/specfs/specdev.h> 58 59 #include <ufs/ufs/inode.h> 60 #include <ufs/ufs/ufsmount.h> 61 #include <ufs/ufs/ufs_extern.h> 62 #include <ufs/ext2fs/ext2fs.h> 63 #include <ufs/ext2fs/ext2fs_extern.h> 64 65 static int ext2fs_bmaparray __P((struct vnode *, daddr_t, daddr_t *, 66 struct indir *, int *, int *)); 67 68 #define is_sequential(ump, a, b) ((b) == (a) + ump->um_seqinc) 69 70 /* 71 * Bmap converts a the logical block number of a file to its physical block 72 * number on the disk. The conversion is done by using the logical block 73 * number to index into the array of block pointers described by the dinode. 74 */ 75 int 76 ext2fs_bmap(v) 77 void *v; 78 { 79 struct vop_bmap_args /* { 80 struct vnode *a_vp; 81 daddr_t a_bn; 82 struct vnode **a_vpp; 83 daddr_t *a_bnp; 84 int *a_runp; 85 } */ *ap = v; 86 /* 87 * Check for underlying vnode requests and ensure that logical 88 * to physical mapping is requested. 89 */ 90 if (ap->a_vpp != NULL) 91 *ap->a_vpp = VTOI(ap->a_vp)->i_devvp; 92 if (ap->a_bnp == NULL) 93 return (0); 94 95 return (ext2fs_bmaparray(ap->a_vp, ap->a_bn, ap->a_bnp, NULL, NULL, 96 ap->a_runp)); 97 } 98 99 /* 100 * Indirect blocks are now on the vnode for the file. They are given negative 101 * logical block numbers. Indirect blocks are addressed by the negative 102 * address of the first data block to which they point. Double indirect blocks 103 * are addressed by one less than the address of the first indirect block to 104 * which they point. Triple indirect blocks are addressed by one less than 105 * the address of the first double indirect block to which they point. 106 * 107 * ext2fs_bmaparray does the bmap conversion, and if requested returns the 108 * array of logical blocks which must be traversed to get to a block. 109 * Each entry contains the offset into that block that gets you to the 110 * next block and the disk address of the block (if it is assigned). 111 */ 112 113 int 114 ext2fs_bmaparray(vp, bn, bnp, ap, nump, runp) 115 struct vnode *vp; 116 daddr_t bn; 117 daddr_t *bnp; 118 struct indir *ap; 119 int *nump; 120 int *runp; 121 { 122 struct inode *ip; 123 struct buf *bp; 124 struct ufsmount *ump; 125 struct mount *mp; 126 struct indir a[NIADDR+1], *xap; 127 daddr_t daddr; 128 daddr_t metalbn; 129 int error, maxrun = 0, num; 130 131 ip = VTOI(vp); 132 mp = vp->v_mount; 133 ump = VFSTOUFS(mp); 134 #ifdef DIAGNOSTIC 135 if ((ap != NULL && nump == NULL) || (ap == NULL && nump != NULL)) 136 panic("ext2fs_bmaparray: invalid arguments"); 137 #endif 138 139 if (runp) { 140 /* 141 * XXX 142 * If MAXBSIZE is the largest transfer the disks can handle, 143 * we probably want maxrun to be 1 block less so that we 144 * don't create a block larger than the device can handle. 145 */ 146 *runp = 0; 147 maxrun = MAXBSIZE / mp->mnt_stat.f_iosize - 1; 148 } 149 150 if (bn >= 0 && bn < NDADDR) { 151 /* XXX ondisk32 */ 152 *bnp = blkptrtodb(ump, (daddr_t)fs2h32(ip->i_e2fs_blocks[bn])); 153 if (*bnp == 0) 154 *bnp = -1; 155 else if (runp) 156 /* XXX ondisk32 */ 157 for (++bn; bn < NDADDR && *runp < maxrun && 158 is_sequential(ump, (daddr_t)fs2h32(ip->i_e2fs_blocks[bn - 1]), 159 (daddr_t)fs2h32(ip->i_e2fs_blocks[bn])); 160 ++bn, ++*runp); 161 return (0); 162 } 163 164 xap = ap == NULL ? a : ap; 165 if (!nump) 166 nump = # 167 if ((error = ufs_getlbns(vp, bn, xap, nump)) != 0) 168 return (error); 169 170 num = *nump; 171 172 /* Get disk address out of indirect block array */ 173 /* XXX ondisk32 */ 174 daddr = fs2h32(ip->i_e2fs_blocks[NDADDR + xap->in_off]); 175 176 #ifdef DIAGNOSTIC 177 if (num > NIADDR + 1 || num < 1) { 178 printf("ext2fs_bmaparray: num=%d\n", num); 179 panic("ext2fs_bmaparray: num"); 180 } 181 #endif 182 for (bp = NULL, ++xap; --num; ++xap) { 183 /* 184 * Exit the loop if there is no disk address assigned yet and 185 * the indirect block isn't in the cache, or if we were 186 * looking for an indirect block and we've found it. 187 */ 188 189 metalbn = xap->in_lbn; 190 if ((daddr == 0 && !incore(vp, metalbn)) || metalbn == bn) 191 break; 192 /* 193 * If we get here, we've either got the block in the cache 194 * or we have a disk address for it, go fetch it. 195 */ 196 if (bp) 197 brelse(bp); 198 199 xap->in_exists = 1; 200 bp = getblk(vp, metalbn, mp->mnt_stat.f_iosize, 0, 0); 201 if (bp->b_flags & (B_DONE | B_DELWRI)) { 202 trace(TR_BREADHIT, pack(vp, size), metalbn); 203 } 204 #ifdef DIAGNOSTIC 205 else if (!daddr) 206 panic("ext2fs_bmaparry: indirect block not in cache"); 207 #endif 208 else { 209 trace(TR_BREADMISS, pack(vp, size), metalbn); 210 bp->b_blkno = blkptrtodb(ump, daddr); 211 bp->b_flags |= B_READ; 212 VOP_STRATEGY(bp); 213 curproc->p_stats->p_ru.ru_inblock++; /* XXX */ 214 if ((error = biowait(bp)) != 0) { 215 brelse(bp); 216 return (error); 217 } 218 } 219 220 /* XXX ondisk32 */ 221 daddr = fs2h32(((int32_t *)bp->b_data)[xap->in_off]); 222 if (num == 1 && daddr && runp) 223 /* XXX ondisk32 */ 224 for (bn = xap->in_off + 1; 225 bn < MNINDIR(ump) && *runp < maxrun && 226 is_sequential(ump, ((int32_t *)bp->b_data)[bn - 1], 227 ((int32_t *)bp->b_data)[bn]); 228 ++bn, ++*runp); 229 } 230 if (bp) 231 brelse(bp); 232 233 daddr = blkptrtodb(ump, daddr); 234 *bnp = daddr == 0 ? -1 : daddr; 235 return (0); 236 } 237