Home | History | Annotate | Line # | Download | only in efs
efs_subr.c revision 1.7.42.2
      1  1.7.42.2      tls /*	$NetBSD: efs_subr.c,v 1.7.42.2 2014/08/20 00:04:26 tls 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.7.42.2      tls __KERNEL_RCSID(0, "$NetBSD: efs_subr.c,v 1.7.42.2 2014/08/20 00:04:26 tls 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.1   rumble 	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.7  hannken 	    EFS_BB_SIZE, (l == NULL) ? NOCRED : l->l_cred, 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.7.42.2      tls 	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.7.42.2      tls #ifdef DIAGNOSTIC
    354       1.1   rumble 	KASSERT(efs_is_inode_synced(ei) == 0);
    355  1.7.42.2      tls #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