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