1*bf2ad724Sriastradh /* $NetBSD: ufs_bmap.c,v 1.19 2022/04/09 10:05:35 riastradh Exp $ */
268b8babdSlukem /* From: NetBSD: ufs_bmap.c,v 1.14 2001/11/08 05:00:51 chs Exp */
36325773eSlukem
46325773eSlukem /*
56325773eSlukem * Copyright (c) 1989, 1991, 1993
66325773eSlukem * The Regents of the University of California. All rights reserved.
76325773eSlukem * (c) UNIX System Laboratories, Inc.
86325773eSlukem * All or some portions of this file are derived from material licensed
96325773eSlukem * to the University of California by American Telephone and Telegraph
106325773eSlukem * Co. or Unix System Laboratories, Inc. and are reproduced herein with
116325773eSlukem * the permission of UNIX System Laboratories, Inc.
126325773eSlukem *
136325773eSlukem * Redistribution and use in source and binary forms, with or without
146325773eSlukem * modification, are permitted provided that the following conditions
156325773eSlukem * are met:
166325773eSlukem * 1. Redistributions of source code must retain the above copyright
176325773eSlukem * notice, this list of conditions and the following disclaimer.
186325773eSlukem * 2. Redistributions in binary form must reproduce the above copyright
196325773eSlukem * notice, this list of conditions and the following disclaimer in the
206325773eSlukem * documentation and/or other materials provided with the distribution.
21326b2259Sagc * 3. Neither the name of the University nor the names of its contributors
226325773eSlukem * may be used to endorse or promote products derived from this software
236325773eSlukem * without specific prior written permission.
246325773eSlukem *
256325773eSlukem * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
266325773eSlukem * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
276325773eSlukem * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
286325773eSlukem * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
296325773eSlukem * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
306325773eSlukem * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
316325773eSlukem * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
326325773eSlukem * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
336325773eSlukem * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
346325773eSlukem * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
356325773eSlukem * SUCH DAMAGE.
366325773eSlukem *
376325773eSlukem * @(#)ufs_bmap.c 8.8 (Berkeley) 8/11/95
386325773eSlukem */
396325773eSlukem
40b2f78261Sjmc #if HAVE_NBTOOL_CONFIG_H
41b2f78261Sjmc #include "nbtool_config.h"
42b2f78261Sjmc #endif
43b2f78261Sjmc
44cafb53fcSlukem #include <sys/cdefs.h>
4576834aefStv #if defined(__RCSID) && !defined(__lint)
46*bf2ad724Sriastradh __RCSID("$NetBSD: ufs_bmap.c,v 1.19 2022/04/09 10:05:35 riastradh Exp $");
47cafb53fcSlukem #endif /* !__lint */
48cafb53fcSlukem
496325773eSlukem #include <sys/param.h>
506325773eSlukem #include <sys/time.h>
516325773eSlukem
5268b8babdSlukem #include <assert.h>
536325773eSlukem #include <errno.h>
541b1d20a8Sthorpej #include <strings.h>
556325773eSlukem
56d74b2fc0Slukem #include "makefs.h"
57d74b2fc0Slukem
583d765797Slukem #include <ufs/ufs/dinode.h>
59557afc60Slukem #include <ufs/ufs/ufs_bswap.h>
60557afc60Slukem #include <ufs/ffs/fs.h>
616325773eSlukem
62944794a5Slukem #include "ffs/ufs_inode.h"
636325773eSlukem #include "ffs/ffs_extern.h"
646325773eSlukem
656325773eSlukem /*
666325773eSlukem * Create an array of logical block number/offset pairs which represent the
676325773eSlukem * path of indirect blocks required to access a data block. The first "pair"
686325773eSlukem * contains the logical block number of the appropriate single, double or
696325773eSlukem * triple indirect block and the offset into the inode indirect block array.
706325773eSlukem * Note, the logical block number of the inode single/double/triple indirect
716325773eSlukem * block appears twice in the array, once with the offset into the i_ffs_ib and
726325773eSlukem * once with the offset into the page itself.
736325773eSlukem */
746325773eSlukem int
ufs_getlbns(struct inode * ip,daddr_t bn,struct indir * ap,int * nump)75a3ff3a30Sfvdl ufs_getlbns(struct inode *ip, daddr_t bn, struct indir *ap, int *nump)
766325773eSlukem {
77a3ff3a30Sfvdl daddr_t metalbn, realbn;
786325773eSlukem int64_t blockcnt;
796325773eSlukem int lbc;
806325773eSlukem int i, numlevels, off;
816325773eSlukem u_long lognindir;
826325773eSlukem
83f1333577Sdholland lognindir = ffs(FFS_NINDIR(ip->i_fs)) - 1;
846325773eSlukem if (nump)
856325773eSlukem *nump = 0;
866325773eSlukem numlevels = 0;
876325773eSlukem realbn = bn;
886325773eSlukem if ((long)bn < 0)
896325773eSlukem bn = -(long)bn;
906325773eSlukem
91dcd34a91Sdholland assert (bn >= UFS_NDADDR);
926325773eSlukem
936325773eSlukem /*
946325773eSlukem * Determine the number of levels of indirection. After this loop
956325773eSlukem * is done, blockcnt indicates the number of data blocks possible
96dcd34a91Sdholland * at the given level of indirection, and UFS_NIADDR - i is the number
976325773eSlukem * of levels of indirection needed to locate the requested block.
986325773eSlukem */
996325773eSlukem
100dcd34a91Sdholland bn -= UFS_NDADDR;
101dcd34a91Sdholland for (lbc = 0, i = UFS_NIADDR;; i--, bn -= blockcnt) {
1026325773eSlukem if (i == 0)
1036325773eSlukem return (EFBIG);
1046325773eSlukem
1056325773eSlukem lbc += lognindir;
1066325773eSlukem blockcnt = (int64_t)1 << lbc;
1076325773eSlukem
1086325773eSlukem if (bn < blockcnt)
1096325773eSlukem break;
1106325773eSlukem }
1116325773eSlukem
1126325773eSlukem /* Calculate the address of the first meta-block. */
113dcd34a91Sdholland metalbn = -((realbn >= 0 ? realbn : -realbn) - bn + UFS_NIADDR - i);
1146325773eSlukem
1156325773eSlukem /*
1166325773eSlukem * At each iteration, off is the offset into the bap array which is
1176325773eSlukem * an array of disk addresses at the current level of indirection.
1186325773eSlukem * The logical block number and the offset in that block are stored
1196325773eSlukem * into the argument array.
1206325773eSlukem */
1216325773eSlukem ap->in_lbn = metalbn;
122dcd34a91Sdholland ap->in_off = off = UFS_NIADDR - i;
1236325773eSlukem ap->in_exists = 0;
1246325773eSlukem ap++;
125dcd34a91Sdholland for (++numlevels; i <= UFS_NIADDR; i++) {
1266325773eSlukem /* If searching for a meta-data block, quit when found. */
1276325773eSlukem if (metalbn == realbn)
1286325773eSlukem break;
1296325773eSlukem
1306325773eSlukem lbc -= lognindir;
1316325773eSlukem blockcnt = (int64_t)1 << lbc;
132f1333577Sdholland off = (bn >> lbc) & (FFS_NINDIR(ip->i_fs) - 1);
1336325773eSlukem
1346325773eSlukem ++numlevels;
1356325773eSlukem ap->in_lbn = metalbn;
1366325773eSlukem ap->in_off = off;
1376325773eSlukem ap->in_exists = 0;
1386325773eSlukem ++ap;
1396325773eSlukem
14068b8babdSlukem metalbn -= -1 + (off << lbc);
1416325773eSlukem }
1426325773eSlukem if (nump)
1436325773eSlukem *nump = numlevels;
1446325773eSlukem return (0);
1456325773eSlukem }
146