Home | History | Annotate | Line # | Download | only in efs
efs_subr.c revision 1.12
      1  1.12      maxv /*	$NetBSD: efs_subr.c,v 1.12 2015/09/26 12:16:28 maxv Exp $	*/
      2   1.1    rumble 
      3   1.1    rumble /*
      4   1.1    rumble  * Copyright (c) 2006 Stephen M. Rumble <rumble (at) ephemeral.org>
      5   1.1    rumble  *
      6   1.1    rumble  * Permission to use, copy, modify, and distribute this software for any
      7   1.1    rumble  * purpose with or without fee is hereby granted, provided that the above
      8   1.1    rumble  * copyright notice and this permission notice appear in all copies.
      9   1.1    rumble  *
     10   1.1    rumble  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     11   1.1    rumble  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     12   1.1    rumble  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     13   1.1    rumble  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     14   1.1    rumble  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     15   1.1    rumble  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     16   1.1    rumble  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     17   1.1    rumble  */
     18   1.1    rumble 
     19   1.1    rumble #include <sys/cdefs.h>
     20  1.12      maxv __KERNEL_RCSID(0, "$NetBSD: efs_subr.c,v 1.12 2015/09/26 12:16:28 maxv Exp $");
     21   1.1    rumble 
     22   1.1    rumble #include <sys/param.h>
     23   1.1    rumble #include <sys/kauth.h>
     24   1.1    rumble #include <sys/lwp.h>
     25   1.1    rumble #include <sys/proc.h>
     26   1.1    rumble #include <sys/buf.h>
     27   1.1    rumble #include <sys/mount.h>
     28   1.1    rumble #include <sys/vnode.h>
     29   1.1    rumble #include <sys/namei.h>
     30   1.1    rumble #include <sys/stat.h>
     31   1.1    rumble #include <sys/malloc.h>
     32   1.1    rumble 
     33   1.1    rumble #include <miscfs/genfs/genfs_node.h>
     34   1.1    rumble 
     35   1.1    rumble #include <fs/efs/efs.h>
     36   1.1    rumble #include <fs/efs/efs_sb.h>
     37   1.1    rumble #include <fs/efs/efs_dir.h>
     38   1.1    rumble #include <fs/efs/efs_genfs.h>
     39   1.1    rumble #include <fs/efs/efs_mount.h>
     40   1.1    rumble #include <fs/efs/efs_extent.h>
     41   1.1    rumble #include <fs/efs/efs_dinode.h>
     42   1.1    rumble #include <fs/efs/efs_inode.h>
     43   1.1    rumble #include <fs/efs/efs_subr.h>
     44   1.1    rumble 
     45   1.1    rumble struct pool efs_inode_pool;
     46   1.1    rumble 
     47   1.1    rumble /*
     48   1.1    rumble  * Calculate a checksum for the provided superblock in __host byte order__.
     49   1.1    rumble  *
     50   1.1    rumble  * At some point SGI changed the checksum algorithm slightly, which can be
     51   1.1    rumble  * enabled with the 'new' flag.
     52   1.1    rumble  *
     53   1.1    rumble  * Presumably this change occured on or before 24 Oct 1988 (around IRIX 3.1),
     54   1.1    rumble  * so we're pretty unlikely to ever actually see an old checksum. Further, it
     55   1.1    rumble  * means that EFS_NEWMAGIC filesystems (IRIX >= 3.3) must match the new
     56   1.1    rumble  * checksum whereas EFS_MAGIC filesystems could potentially use either
     57   1.1    rumble  * algorithm.
     58   1.1    rumble  *
     59   1.1    rumble  * See comp.sys.sgi <1991Aug9.050838.16876 (at) odin.corp.sgi.com>
     60   1.1    rumble  */
     61   1.1    rumble int32_t
     62   1.1    rumble efs_sb_checksum(struct efs_sb *esb, int new)
     63   1.1    rumble {
     64   1.1    rumble 	int i;
     65   1.1    rumble 	int32_t cksum;
     66   1.4    rumble 	uint16_t *sbarray = (uint16_t *)esb;
     67   1.1    rumble 
     68   1.1    rumble 	KASSERT((EFS_SB_CHECKSUM_SIZE % 2) == 0);
     69   1.1    rumble 
     70   1.1    rumble 	for (i = cksum = 0; i < (EFS_SB_CHECKSUM_SIZE / 2); i++) {
     71   1.1    rumble 		cksum ^= be16toh(sbarray[i]);
     72   1.1    rumble 		cksum  = (cksum << 1) | (new && cksum < 0);
     73   1.1    rumble 	}
     74   1.1    rumble 
     75   1.1    rumble 	return (cksum);
     76   1.1    rumble }
     77   1.1    rumble 
     78   1.1    rumble /*
     79   1.1    rumble  * Determine if the superblock is valid.
     80   1.1    rumble  *
     81   1.1    rumble  * Returns 0 if valid, else invalid. If invalid, 'why' is set to an
     82   1.1    rumble  * explanation.
     83   1.1    rumble  */
     84   1.1    rumble int
     85   1.1    rumble efs_sb_validate(struct efs_sb *esb, const char **why)
     86   1.1    rumble {
     87   1.1    rumble 	uint32_t ocksum, ncksum;
     88   1.1    rumble 
     89   1.1    rumble 	*why = NULL;
     90   1.1    rumble 
     91   1.1    rumble 	if (be32toh(esb->sb_magic) != EFS_SB_MAGIC &&
     92   1.5    rumble 	    be32toh(esb->sb_magic) != EFS_SB_NEWMAGIC) {
     93   1.1    rumble 		*why = "sb_magic invalid";
     94   1.1    rumble 		return (1);
     95   1.1    rumble 	}
     96   1.1    rumble 
     97   1.1    rumble 	ocksum = htobe32(efs_sb_checksum(esb, 0));
     98   1.1    rumble 	ncksum = htobe32(efs_sb_checksum(esb, 1));
     99   1.1    rumble 	if (esb->sb_checksum != ocksum && esb->sb_checksum != ncksum) {
    100   1.1    rumble 		*why = "sb_checksum invalid";
    101   1.1    rumble 		return (1);
    102   1.1    rumble 	}
    103   1.1    rumble 
    104   1.1    rumble 	if (be32toh(esb->sb_size) > EFS_SIZE_MAX) {
    105   1.1    rumble 		*why = "sb_size > EFS_SIZE_MAX";
    106   1.1    rumble 		return (1);
    107   1.1    rumble 	}
    108   1.1    rumble 
    109   1.1    rumble 	if (be32toh(esb->sb_firstcg) <= EFS_BB_BITMAP) {
    110   1.1    rumble 		*why = "sb_firstcg <= EFS_BB_BITMAP";
    111   1.1    rumble 		return (1);
    112   1.1    rumble 	}
    113   1.1    rumble 
    114   1.1    rumble 	/* XXX - add better sb consistency checks here */
    115   1.1    rumble 	if (esb->sb_cgfsize == 0 ||
    116   1.1    rumble 	    esb->sb_cgisize == 0 ||
    117   1.1    rumble 	    esb->sb_ncg == 0 ||
    118   1.1    rumble 	    esb->sb_bmsize == 0) {
    119   1.1    rumble 		*why = "something bad happened";
    120   1.1    rumble 		return (1);
    121   1.1    rumble 	}
    122   1.1    rumble 
    123   1.1    rumble 	return (0);
    124   1.1    rumble }
    125   1.1    rumble 
    126   1.1    rumble /*
    127   1.1    rumble  * Determine the basic block offset and inode index within that block, given
    128   1.1    rumble  * the inode 'ino' and filesystem parameters _in host byte order_. The inode
    129   1.1    rumble  * will live at byte address 'bboff' * EFS_BB_SIZE + 'index' * EFS_DINODE_SIZE.
    130   1.1    rumble  */
    131   1.1    rumble void
    132   1.1    rumble efs_locate_inode(ino_t ino, struct efs_sb *sbp, uint32_t *bboff, int *index)
    133   1.1    rumble {
    134   1.1    rumble 	uint32_t cgfsize, firstcg;
    135   1.1    rumble 	uint16_t cgisize;
    136   1.1    rumble 
    137   1.1    rumble 	cgisize = be16toh(sbp->sb_cgisize);
    138   1.1    rumble 	cgfsize = be32toh(sbp->sb_cgfsize);
    139  1.12      maxv 	firstcg = be32toh(sbp->sb_firstcg);
    140   1.1    rumble 
    141   1.1    rumble 	*bboff = firstcg + ((ino / (cgisize * EFS_DINODES_PER_BB)) * cgfsize) +
    142   1.1    rumble 	    ((ino % (cgisize * EFS_DINODES_PER_BB)) / EFS_DINODES_PER_BB);
    143   1.1    rumble 	*index = ino & (EFS_DINODES_PER_BB - 1);
    144   1.1    rumble }
    145   1.1    rumble 
    146   1.1    rumble /*
    147   1.1    rumble  * Read in an inode from disk.
    148   1.1    rumble  *
    149   1.1    rumble  * We actually take in four inodes at a time. Hopefully these will stick
    150   1.1    rumble  * around in the buffer cache and get used without going to disk.
    151   1.1    rumble  *
    152   1.1    rumble  * Returns 0 on success.
    153   1.1    rumble  */
    154   1.1    rumble int
    155   1.1    rumble efs_read_inode(struct efs_mount *emp, ino_t ino, struct lwp *l,
    156   1.1    rumble     struct efs_dinode *di)
    157   1.1    rumble {
    158   1.1    rumble 	struct efs_sb *sbp;
    159   1.1    rumble 	struct buf *bp;
    160   1.1    rumble 	int index, err;
    161   1.1    rumble 	uint32_t bboff;
    162   1.1    rumble 
    163   1.1    rumble 	sbp = &emp->em_sb;
    164   1.1    rumble 	efs_locate_inode(ino, sbp, &bboff, &index);
    165   1.1    rumble 
    166   1.2    rumble 	err = efs_bread(emp, bboff, l, &bp);
    167   1.1    rumble 	if (err) {
    168   1.1    rumble 		return (err);
    169   1.1    rumble 	}
    170   1.1    rumble 	memcpy(di, ((struct efs_dinode *)bp->b_data) + index, sizeof(*di));
    171   1.6        ad 	brelse(bp, 0);
    172   1.1    rumble 
    173   1.1    rumble 	return (0);
    174   1.1    rumble }
    175   1.1    rumble 
    176   1.1    rumble /*
    177   1.1    rumble  * Perform a read from our device handling the potential DEV_BSIZE
    178   1.1    rumble  * messiness (although as of 19.2.2006, all ports appear to use 512) as
    179   1.1    rumble  * we as EFS block sizing.
    180   1.1    rumble  *
    181   1.1    rumble  * bboff: basic block offset
    182   1.1    rumble  *
    183   1.1    rumble  * Returns 0 on success.
    184   1.1    rumble  */
    185   1.1    rumble int
    186   1.2    rumble efs_bread(struct efs_mount *emp, uint32_t bboff, struct lwp *l, struct buf **bp)
    187   1.1    rumble {
    188   1.1    rumble 	KASSERT(bboff < EFS_SIZE_MAX);
    189   1.1    rumble 
    190   1.1    rumble 	return (bread(emp->em_devvp, (daddr_t)bboff * (EFS_BB_SIZE / DEV_BSIZE),
    191  1.11      maxv 	    EFS_BB_SIZE, 0, bp));
    192   1.1    rumble }
    193   1.1    rumble 
    194   1.1    rumble /*
    195   1.1    rumble  * Synchronise the in-core, host ordered and typed inode fields with their
    196   1.1    rumble  * corresponding on-disk, EFS ordered and typed copies.
    197   1.1    rumble  *
    198   1.1    rumble  * This is the inverse of efs_dinode_sync_inode(), and should be called when
    199   1.1    rumble  * an inode is loaded from disk.
    200   1.1    rumble  */
    201   1.1    rumble void
    202   1.1    rumble efs_sync_dinode_to_inode(struct efs_inode *ei)
    203   1.1    rumble {
    204   1.1    rumble 
    205   1.1    rumble 	ei->ei_mode		= be16toh(ei->ei_di.di_mode);	/*same as nbsd*/
    206   1.1    rumble 	ei->ei_nlink		= be16toh(ei->ei_di.di_nlink);
    207   1.1    rumble 	ei->ei_uid		= be16toh(ei->ei_di.di_uid);
    208   1.1    rumble 	ei->ei_gid		= be16toh(ei->ei_di.di_gid);
    209   1.1    rumble 	ei->ei_size		= be32toh(ei->ei_di.di_size);
    210   1.1    rumble 	ei->ei_atime		= be32toh(ei->ei_di.di_atime);
    211   1.1    rumble 	ei->ei_mtime		= be32toh(ei->ei_di.di_mtime);
    212   1.1    rumble 	ei->ei_ctime		= be32toh(ei->ei_di.di_ctime);
    213   1.1    rumble 	ei->ei_gen		= be32toh(ei->ei_di.di_gen);
    214   1.1    rumble 	ei->ei_numextents 	= be16toh(ei->ei_di.di_numextents);
    215   1.1    rumble 	ei->ei_version		= ei->ei_di.di_version;
    216   1.1    rumble }
    217   1.1    rumble 
    218   1.1    rumble /*
    219   1.1    rumble  * Synchronise the on-disk, EFS ordered and typed inode fields with their
    220   1.1    rumble  * corresponding in-core, host ordered and typed copies.
    221   1.1    rumble  *
    222   1.1    rumble  * This is the inverse of efs_inode_sync_dinode(), and should be called before
    223   1.1    rumble  * an inode is flushed to disk.
    224   1.1    rumble  */
    225   1.1    rumble void
    226   1.1    rumble efs_sync_inode_to_dinode(struct efs_inode *ei)
    227   1.1    rumble {
    228   1.1    rumble 
    229   1.1    rumble 	panic("readonly -- no need to call me");
    230   1.1    rumble }
    231   1.1    rumble 
    232   1.1    rumble #ifdef DIAGNOSTIC
    233   1.1    rumble /*
    234   1.1    rumble  * Ensure that the in-core inode's host cached fields match its on-disk copy.
    235   1.1    rumble  *
    236   1.1    rumble  * Returns 0 if they match.
    237   1.1    rumble  */
    238   1.1    rumble static int
    239   1.1    rumble efs_is_inode_synced(struct efs_inode *ei)
    240   1.1    rumble {
    241   1.1    rumble 	int s;
    242   1.1    rumble 
    243   1.1    rumble 	s = 0;
    244   1.1    rumble 	/* XXX -- see above remarks about assumption */
    245   1.1    rumble 	s += (ei->ei_mode	!= be16toh(ei->ei_di.di_mode));
    246   1.1    rumble 	s += (ei->ei_nlink	!= be16toh(ei->ei_di.di_nlink));
    247   1.1    rumble 	s += (ei->ei_uid	!= be16toh(ei->ei_di.di_uid));
    248   1.1    rumble 	s += (ei->ei_gid	!= be16toh(ei->ei_di.di_gid));
    249   1.1    rumble 	s += (ei->ei_size	!= be32toh(ei->ei_di.di_size));
    250   1.1    rumble 	s += (ei->ei_atime	!= be32toh(ei->ei_di.di_atime));
    251   1.1    rumble 	s += (ei->ei_mtime	!= be32toh(ei->ei_di.di_mtime));
    252   1.1    rumble 	s += (ei->ei_ctime	!= be32toh(ei->ei_di.di_ctime));
    253   1.1    rumble 	s += (ei->ei_gen	!= be32toh(ei->ei_di.di_gen));
    254   1.1    rumble 	s += (ei->ei_numextents	!= be16toh(ei->ei_di.di_numextents));
    255   1.1    rumble 	s += (ei->ei_version	!= ei->ei_di.di_version);
    256   1.1    rumble 
    257   1.1    rumble 	return (s);
    258   1.1    rumble }
    259   1.1    rumble #endif
    260   1.1    rumble 
    261   1.1    rumble /*
    262   1.1    rumble  * Given an efs_dirblk structure and a componentname to search for, return the
    263   1.1    rumble  * corresponding inode if it is found.
    264   1.1    rumble  *
    265   1.1    rumble  * Returns 0 on success.
    266   1.1    rumble  */
    267   1.1    rumble static int
    268   1.1    rumble efs_dirblk_lookup(struct efs_dirblk *dir, struct componentname *cn,
    269   1.1    rumble     ino_t *inode)
    270   1.1    rumble {
    271   1.1    rumble 	struct efs_dirent *de;
    272  1.10       mrg 	int i, slot __diagused, offset;
    273   1.1    rumble 
    274   1.1    rumble 	KASSERT(cn->cn_namelen <= EFS_DIRENT_NAMELEN_MAX);
    275   1.1    rumble 
    276   1.1    rumble 	slot = offset = 0;
    277   1.1    rumble 
    278   1.1    rumble 	for (i = 0; i < dir->db_slots; i++) {
    279   1.1    rumble 		offset = EFS_DIRENT_OFF_EXPND(dir->db_space[i]);
    280   1.1    rumble 
    281   1.1    rumble 		if (offset == EFS_DIRBLK_SLOT_FREE)
    282   1.1    rumble 			continue;
    283   1.1    rumble 
    284   1.1    rumble 		de = (struct efs_dirent *)((char *)dir + offset);
    285   1.1    rumble 		if (de->de_namelen == cn->cn_namelen &&
    286   1.1    rumble 		   (strncmp(cn->cn_nameptr, de->de_name, cn->cn_namelen) == 0)){
    287   1.1    rumble 			slot = i;
    288   1.1    rumble 			break;
    289   1.1    rumble 		}
    290   1.1    rumble 	}
    291   1.1    rumble 	if (i == dir->db_slots)
    292   1.1    rumble 		return (ENOENT);
    293   1.1    rumble 
    294   1.1    rumble 	KASSERT(slot < offset && offset < EFS_DIRBLK_SPACE_SIZE);
    295   1.1    rumble 	de = (struct efs_dirent *)((char *)dir + offset);
    296   1.1    rumble 	*inode = be32toh(de->de_inumber);
    297   1.1    rumble 
    298   1.1    rumble 	return (0);
    299   1.1    rumble }
    300   1.1    rumble 
    301   1.1    rumble /*
    302   1.1    rumble  * Given an extent descriptor that represents a directory, look up
    303   1.1    rumble  * componentname within its efs_dirblk's. If it is found, return the
    304   1.1    rumble  * corresponding inode in 'ino'.
    305   1.1    rumble  *
    306   1.1    rumble  * Returns 0 on success.
    307   1.1    rumble  */
    308   1.1    rumble static int
    309   1.1    rumble efs_extent_lookup(struct efs_mount *emp, struct efs_extent *ex,
    310   1.1    rumble     struct componentname *cn, ino_t *ino)
    311   1.1    rumble {
    312   1.1    rumble 	struct efs_dirblk *db;
    313   1.1    rumble 	struct buf *bp;
    314   1.1    rumble 	int i, err;
    315   1.1    rumble 
    316   1.1    rumble 	/*
    317   1.2    rumble 	 * Read in each of the dirblks until we find our entry.
    318   1.2    rumble 	 * If we don't, return ENOENT.
    319   1.1    rumble 	 */
    320   1.2    rumble 	for (i = 0; i < ex->ex_length; i++) {
    321   1.2    rumble 		err = efs_bread(emp, ex->ex_bn + i, NULL, &bp);
    322   1.2    rumble 		if (err) {
    323   1.2    rumble 			printf("efs: warning: invalid extent descriptor\n");
    324   1.2    rumble 			return (err);
    325   1.2    rumble 		}
    326   1.1    rumble 
    327   1.2    rumble 		db = (struct efs_dirblk *)bp->b_data;
    328   1.1    rumble 		if (efs_dirblk_lookup(db, cn, ino) == 0) {
    329   1.6        ad 			brelse(bp, 0);
    330   1.1    rumble 			return (0);
    331   1.1    rumble 		}
    332   1.6        ad 		brelse(bp, 0);
    333   1.1    rumble 	}
    334   1.1    rumble 
    335   1.1    rumble 	return (ENOENT);
    336   1.1    rumble }
    337   1.1    rumble 
    338   1.1    rumble /*
    339   1.1    rumble  * Given the provided in-core inode, look up the pathname requested. If
    340   1.1    rumble  * we find it, 'ino' reflects its corresponding on-disk inode number.
    341   1.1    rumble  *
    342   1.1    rumble  * Returns 0 on success.
    343   1.1    rumble  */
    344   1.1    rumble int
    345   1.1    rumble efs_inode_lookup(struct efs_mount *emp, struct efs_inode *ei,
    346   1.1    rumble     struct componentname *cn, ino_t *ino)
    347   1.1    rumble {
    348   1.1    rumble 	struct efs_extent ex;
    349   1.1    rumble 	struct efs_extent_iterator exi;
    350   1.1    rumble 	int ret;
    351   1.1    rumble 
    352   1.1    rumble 	KASSERT(VOP_ISLOCKED(ei->ei_vp));
    353   1.9  christos #ifdef DIAGNOSTIC
    354   1.1    rumble 	KASSERT(efs_is_inode_synced(ei) == 0);
    355   1.9  christos #endif
    356   1.1    rumble 	KASSERT((ei->ei_mode & S_IFMT) == S_IFDIR);
    357   1.1    rumble 
    358   1.2    rumble 	efs_extent_iterator_init(&exi, ei, 0);
    359   1.1    rumble 	while ((ret = efs_extent_iterator_next(&exi, &ex)) == 0) {
    360   1.1    rumble 		if (efs_extent_lookup(emp, &ex, cn, ino) == 0) {
    361   1.1    rumble 			return (0);
    362   1.1    rumble 		}
    363   1.1    rumble 	}
    364   1.1    rumble 
    365   1.1    rumble 	return ((ret == -1) ? ENOENT : ret);
    366   1.1    rumble }
    367   1.1    rumble 
    368   1.1    rumble /*
    369   1.1    rumble  * Convert on-disk extent structure to in-core format.
    370   1.1    rumble  */
    371   1.1    rumble void
    372   1.1    rumble efs_dextent_to_extent(struct efs_dextent *dex, struct efs_extent *ex)
    373   1.1    rumble {
    374   1.1    rumble 
    375   1.1    rumble 	KASSERT(dex != NULL && ex != NULL);
    376   1.1    rumble 
    377   1.1    rumble 	ex->ex_magic	= dex->ex_bytes[0];
    378   1.1    rumble 	ex->ex_bn	= be32toh(dex->ex_words[0]) & 0x00ffffff;
    379   1.1    rumble 	ex->ex_length	= dex->ex_bytes[4];
    380   1.1    rumble 	ex->ex_offset	= be32toh(dex->ex_words[1]) & 0x00ffffff;
    381   1.1    rumble }
    382   1.1    rumble 
    383   1.1    rumble /*
    384   1.1    rumble  * Convert in-core extent format to on-disk structure.
    385   1.1    rumble  */
    386   1.1    rumble void
    387   1.1    rumble efs_extent_to_dextent(struct efs_extent *ex, struct efs_dextent *dex)
    388   1.1    rumble {
    389   1.1    rumble 
    390   1.1    rumble 	KASSERT(ex != NULL && dex != NULL);
    391   1.1    rumble 	KASSERT(ex->ex_magic == EFS_EXTENT_MAGIC);
    392   1.1    rumble 	KASSERT((ex->ex_bn & ~EFS_EXTENT_BN_MASK) == 0);
    393   1.1    rumble 	KASSERT((ex->ex_offset & ~EFS_EXTENT_OFFSET_MASK) == 0);
    394   1.1    rumble 
    395   1.1    rumble 	dex->ex_words[0] = htobe32(ex->ex_bn);
    396   1.1    rumble 	dex->ex_bytes[0] = ex->ex_magic;
    397   1.1    rumble 	dex->ex_words[1] = htobe32(ex->ex_offset);
    398   1.1    rumble 	dex->ex_bytes[4] = ex->ex_length;
    399   1.1    rumble }
    400   1.1    rumble 
    401   1.1    rumble /*
    402   1.1    rumble  * Initialise an extent iterator.
    403   1.2    rumble  *
    404   1.2    rumble  * If start_hint is non-0, attempt to set up the iterator beginning with the
    405   1.2    rumble  * extent descriptor in which the start_hint'th byte exists. Callers must not
    406   1.2    rumble  * expect success (this is simply an optimisation), so we reserve the right
    407   1.2    rumble  * to start from the beginning.
    408   1.1    rumble  */
    409   1.1    rumble void
    410   1.2    rumble efs_extent_iterator_init(struct efs_extent_iterator *exi, struct efs_inode *eip,
    411   1.2    rumble     off_t start_hint)
    412   1.1    rumble {
    413   1.2    rumble 	struct efs_extent ex, ex2;
    414   1.2    rumble 	struct buf *bp;
    415   1.2    rumble 	struct efs_mount *emp = VFSTOEFS(eip->ei_vp->v_mount);
    416   1.2    rumble 	off_t offset, length, next;
    417   1.2    rumble 	int i, err, numextents, numinextents;
    418   1.2    rumble 	int hi, lo, mid;
    419   1.2    rumble 	int indir;
    420   1.1    rumble 
    421   1.2    rumble 	exi->exi_eip	= eip;
    422   1.2    rumble 	exi->exi_next	= 0;
    423   1.2    rumble 	exi->exi_dnext	= 0;
    424   1.2    rumble 	exi->exi_innext	= 0;
    425   1.2    rumble 
    426   1.2    rumble 	if (start_hint == 0)
    427   1.2    rumble 		return;
    428   1.2    rumble 
    429   1.2    rumble 	/* force iterator to end if hint is too big */
    430   1.2    rumble 	if (start_hint >= eip->ei_size) {
    431   1.2    rumble 		exi->exi_next = eip->ei_numextents;
    432   1.2    rumble 		return;
    433   1.2    rumble 	}
    434   1.2    rumble 
    435   1.2    rumble 	/*
    436   1.2    rumble 	 * Use start_hint to jump to the right extent descriptor. We'll
    437   1.2    rumble 	 * iterate over the 12 indirect extents because it's cheap, then
    438   1.2    rumble 	 * bring the appropriate vector into core and binary search it.
    439   1.2    rumble 	 */
    440   1.2    rumble 
    441   1.2    rumble 	/*
    442   1.2    rumble 	 * Handle the small file case separately first...
    443   1.2    rumble 	 */
    444   1.2    rumble 	if (eip->ei_numextents <= EFS_DIRECTEXTENTS) {
    445   1.2    rumble 		for (i = 0; i < eip->ei_numextents; i++) {
    446   1.2    rumble 			efs_dextent_to_extent(&eip->ei_di.di_extents[i], &ex);
    447   1.2    rumble 
    448   1.2    rumble 			offset = ex.ex_offset * EFS_BB_SIZE;
    449   1.2    rumble 			length = ex.ex_length * EFS_BB_SIZE;
    450   1.2    rumble 
    451   1.2    rumble 			if (start_hint >= offset &&
    452   1.2    rumble 			    start_hint < (offset + length)) {
    453   1.2    rumble 				exi->exi_next = exi->exi_dnext = i;
    454   1.2    rumble 				return;
    455   1.2    rumble 			}
    456   1.2    rumble 		}
    457   1.2    rumble 
    458   1.2    rumble 		/* shouldn't get here, no? */
    459   1.2    rumble 		EFS_DPRINTF(("efs_extent_iterator_init: bad direct extents\n"));
    460   1.2    rumble 		return;
    461   1.2    rumble 	}
    462   1.2    rumble 
    463   1.2    rumble 	/*
    464   1.2    rumble 	 * Now do the large files with indirect extents...
    465   1.2    rumble 	 *
    466   1.2    rumble 	 * The first indirect extent's ex_offset field contains the
    467   1.2    rumble 	 * number of indirect extents used.
    468   1.2    rumble 	 */
    469   1.2    rumble 	efs_dextent_to_extent(&eip->ei_di.di_extents[0], &ex);
    470   1.2    rumble 
    471   1.2    rumble 	numinextents = ex.ex_offset;
    472   1.2    rumble 	if (numinextents < 1 || numinextents >= EFS_DIRECTEXTENTS) {
    473   1.2    rumble 		EFS_DPRINTF(("efs_extent_iterator_init: bad ex.ex_offset\n"));
    474   1.2    rumble 		return;
    475   1.2    rumble 	}
    476   1.2    rumble 
    477   1.2    rumble 	next = 0;
    478   1.2    rumble 	indir = -1;
    479   1.2    rumble 	numextents = 0;
    480   1.2    rumble 	for (i = 0; i < numinextents; i++) {
    481   1.2    rumble 		efs_dextent_to_extent(&eip->ei_di.di_extents[i], &ex);
    482   1.2    rumble 
    483   1.2    rumble 		err = efs_bread(emp, ex.ex_bn, NULL, &bp);
    484   1.2    rumble 		if (err) {
    485   1.2    rumble 			return;
    486   1.2    rumble 		}
    487   1.2    rumble 
    488   1.2    rumble 		efs_dextent_to_extent((struct efs_dextent *)bp->b_data, &ex2);
    489   1.6        ad 		brelse(bp, 0);
    490   1.2    rumble 
    491   1.2    rumble 		offset = ex2.ex_offset * EFS_BB_SIZE;
    492   1.2    rumble 
    493   1.2    rumble 		if (offset > start_hint) {
    494   1.2    rumble 			indir = MAX(0, i - 1);
    495   1.2    rumble 			break;
    496   1.2    rumble 		}
    497   1.2    rumble 
    498   1.3    rumble 		/* number of extents prior to this indirect vector of extents */
    499   1.2    rumble 		next += numextents;
    500   1.2    rumble 
    501   1.3    rumble 		/* number of extents within this indirect vector of extents */
    502   1.2    rumble 		numextents = ex.ex_length * EFS_EXTENTS_PER_BB;
    503   1.3    rumble 		numextents = MIN(numextents, eip->ei_numextents - next);
    504   1.2    rumble 	}
    505   1.2    rumble 
    506   1.2    rumble 	/*
    507   1.2    rumble 	 * We hit the end, so assume it's in the last extent.
    508   1.2    rumble 	 */
    509   1.2    rumble 	if (indir == -1)
    510   1.2    rumble 		indir = numinextents - 1;
    511   1.2    rumble 
    512   1.2    rumble 	/*
    513   1.2    rumble 	 * Binary search to find our desired direct extent.
    514   1.2    rumble 	 */
    515   1.2    rumble 	lo = 0;
    516   1.2    rumble 	mid = 0;
    517   1.2    rumble 	hi = numextents - 1;
    518   1.2    rumble 	efs_dextent_to_extent(&eip->ei_di.di_extents[indir], &ex);
    519   1.2    rumble 	while (lo <= hi) {
    520   1.2    rumble 		int bboff;
    521   1.2    rumble 		int index;
    522   1.2    rumble 
    523   1.2    rumble 		mid = (lo + hi) / 2;
    524   1.2    rumble 
    525   1.2    rumble 		bboff = mid / EFS_EXTENTS_PER_BB;
    526   1.2    rumble 		index = mid % EFS_EXTENTS_PER_BB;
    527   1.2    rumble 
    528   1.2    rumble 		err = efs_bread(emp, ex.ex_bn + bboff, NULL, &bp);
    529   1.2    rumble 		if (err) {
    530   1.2    rumble 			EFS_DPRINTF(("efs_extent_iterator_init: bsrch read\n"));
    531   1.2    rumble 			return;
    532   1.2    rumble 		}
    533   1.2    rumble 
    534   1.2    rumble 		efs_dextent_to_extent((struct efs_dextent *)bp->b_data + index,
    535   1.2    rumble 		    &ex2);
    536   1.6        ad 		brelse(bp, 0);
    537   1.2    rumble 
    538   1.2    rumble 		offset = ex2.ex_offset * EFS_BB_SIZE;
    539   1.2    rumble 		length = ex2.ex_length * EFS_BB_SIZE;
    540   1.2    rumble 
    541   1.2    rumble 		if (start_hint >= offset && start_hint < (offset + length))
    542   1.2    rumble 			break;
    543   1.2    rumble 
    544   1.2    rumble 		if (start_hint < offset)
    545   1.2    rumble 			hi = mid - 1;
    546   1.2    rumble 		else
    547   1.2    rumble 			lo = mid + 1;
    548   1.2    rumble 	}
    549   1.2    rumble 
    550   1.2    rumble 	/*
    551   1.2    rumble 	 * This is bad. Either the hint is bogus (which shouldn't
    552   1.2    rumble 	 * happen) or the extent list must be screwed up. We
    553   1.2    rumble 	 * have to abort.
    554   1.2    rumble 	 */
    555   1.2    rumble 	if (lo > hi) {
    556   1.2    rumble 		EFS_DPRINTF(("efs_extent_iterator_init: bsearch "
    557   1.2    rumble 		    "failed to find extent\n"));
    558   1.2    rumble 		return;
    559   1.2    rumble 	}
    560   1.2    rumble 
    561   1.2    rumble 	exi->exi_next	= next + mid;
    562   1.2    rumble 	exi->exi_dnext	= indir;
    563   1.2    rumble 	exi->exi_innext	= mid;
    564   1.1    rumble }
    565   1.1    rumble 
    566   1.1    rumble /*
    567   1.1    rumble  * Return the next EFS extent.
    568   1.1    rumble  *
    569   1.1    rumble  * Returns 0 if another extent was iterated, -1 if we've exhausted all
    570   1.1    rumble  * extents, or an error number. If 'exi' is non-NULL, the next extent is
    571   1.1    rumble  * written to it (should it exist).
    572   1.1    rumble  */
    573   1.1    rumble int
    574   1.1    rumble efs_extent_iterator_next(struct efs_extent_iterator *exi,
    575   1.1    rumble     struct efs_extent *exp)
    576   1.1    rumble {
    577   1.2    rumble 	struct efs_extent ex;
    578   1.2    rumble 	struct efs_dextent *dexp;
    579   1.1    rumble 	struct efs_inode *eip = exi->exi_eip;
    580   1.2    rumble 	struct buf *bp;
    581   1.2    rumble 	int err, bboff, index;
    582   1.1    rumble 
    583   1.1    rumble 	if (exi->exi_next++ >= eip->ei_numextents)
    584   1.1    rumble 		return (-1);
    585   1.1    rumble 
    586   1.1    rumble 	/* direct or indirect extents? */
    587   1.1    rumble 	if (eip->ei_numextents <= EFS_DIRECTEXTENTS) {
    588   1.1    rumble 		if (exp != NULL) {
    589   1.2    rumble 			dexp = &eip->ei_di.di_extents[exi->exi_dnext++];
    590   1.2    rumble 			efs_dextent_to_extent(dexp, exp);
    591   1.1    rumble 		}
    592   1.1    rumble 	} else {
    593   1.2    rumble 		efs_dextent_to_extent(
    594   1.2    rumble 		    &eip->ei_di.di_extents[exi->exi_dnext], &ex);
    595   1.2    rumble 
    596   1.2    rumble 		bboff	= exi->exi_innext / EFS_EXTENTS_PER_BB;
    597   1.2    rumble 		index	= exi->exi_innext % EFS_EXTENTS_PER_BB;
    598   1.1    rumble 
    599   1.2    rumble 		err = efs_bread(VFSTOEFS(eip->ei_vp->v_mount),
    600   1.2    rumble 		    ex.ex_bn + bboff, NULL, &bp);
    601   1.2    rumble 		if (err) {
    602   1.2    rumble 			EFS_DPRINTF(("efs_extent_iterator_next: "
    603   1.2    rumble 			    "efs_bread failed: %d\n", err));
    604   1.2    rumble 			return (err);
    605   1.1    rumble 		}
    606   1.1    rumble 
    607   1.1    rumble 		if (exp != NULL) {
    608   1.2    rumble 			dexp = (struct efs_dextent *)bp->b_data + index;
    609   1.2    rumble 			efs_dextent_to_extent(dexp, exp);
    610   1.1    rumble 		}
    611   1.6        ad 		brelse(bp, 0);
    612   1.1    rumble 
    613   1.2    rumble 		bboff = exi->exi_innext++ / EFS_EXTENTS_PER_BB;
    614   1.2    rumble 		if (bboff >= ex.ex_length) {
    615   1.1    rumble 			exi->exi_innext = 0;
    616   1.1    rumble 			exi->exi_dnext++;
    617   1.1    rumble 		}
    618   1.1    rumble 	}
    619   1.1    rumble 
    620   1.1    rumble 	return (0);
    621   1.1    rumble }
    622