예제 #1
0
/*
 * Scan the free space map, for this zone, calculating the total
 * number of map bits in each free space fragment.
 *
 * Note: idmask is limited to 15 bits [3.2]
 */
static unsigned int
scan_free_map(struct adfs_sb_info *asb, struct adfs_discmap *dm)
{
	const unsigned int mapsize = dm->dm_endbit + 32;
	const unsigned int idlen  = asb->s_idlen;
	const unsigned int frag_idlen = idlen <= 15 ? idlen : 15;
	const u32 idmask = (1 << frag_idlen) - 1;
	unsigned char *map = dm->dm_bh->b_data;
	unsigned int start = 8, mapptr;
	u32 frag;
	unsigned long total = 0;

	/*
	 * get fragment id
	 */
	frag = GET_FRAG_ID(map, start, idmask);

	/*
	 * If the freelink is null, then no free fragments
	 * exist in this zone.
	 */
	if (frag == 0)
		return 0;

	do {
		start += frag;

		/*
		 * get fragment id
		 */
		frag = GET_FRAG_ID(map, start, idmask);
		mapptr = start + idlen;

		/*
		 * find end of fragment
		 */
		{
			__le32 *_map = (__le32 *)map;
			u32 v = le32_to_cpu(_map[mapptr >> 5]) >> (mapptr & 31);
			while (v == 0) {
				mapptr = (mapptr & ~31) + 32;
				if (mapptr >= mapsize)
					goto error;
				v = le32_to_cpu(_map[mapptr >> 5]);
			}

			mapptr += 1 + ffz(~v);
		}

		total += mapptr - start;
	} while (frag >= idlen + 1);

	if (frag != 0)
		printk(KERN_ERR "adfs: undersized free fragment\n");

	return total;
error:
	printk(KERN_ERR "adfs: oversized free fragment\n");
	return 0;
}
예제 #2
0
/*
 * return the map bit offset of the fragment frag_id in the zone dm.
 * Note that the loop is optimised for best asm code - look at the
 * output of:
 *  gcc -D__KERNEL__ -O2 -I../../include -o - -S map.c
 */
static int
lookup_zone(const struct adfs_discmap *dm, const unsigned int idlen,
	    const unsigned int frag_id, unsigned int *offset)
{
	const unsigned int mapsize = dm->dm_endbit;
	const u32 idmask = (1 << idlen) - 1;
	unsigned char *map = dm->dm_bh->b_data + 4;
	unsigned int start = dm->dm_startbit;
	unsigned int mapptr;
	u32 frag;

	do {
		frag = GET_FRAG_ID(map, start, idmask);
		mapptr = start + idlen;

		/*
		 * find end of fragment
		 */
		{
			u32 v, *_map = (u32 *)map;

			v = le32_to_cpu(_map[mapptr >> 5]) >> (mapptr & 31);
			while (v == 0) {
				mapptr = (mapptr & ~31) + 32;
				if (mapptr >= mapsize)
					goto error;
				v = le32_to_cpu(_map[mapptr >> 5]);
			}

			mapptr += 1 + ffz(~v);
		}

		if (frag == frag_id)
			goto found;
again:
		start = mapptr;
	} while (mapptr < mapsize);
	return -1;

error:
	printk(KERN_ERR "adfs: oversized fragment 0x%x at 0x%x-0x%x\n",
		frag, start, mapptr);
	return -1;

found:
	{
		int length = mapptr - start;
		if (*offset >= length) {
			*offset -= length;
			goto again;
		}
	}
	return start + *offset;
}
예제 #3
0
/*
 * return the map bit offset of the fragment frag_id in
 * the zone dm.
 * Note that the loop is optimised for best asm code -
 * look at the output of:
 *  gcc -D__KERNEL__ -O2 -I../../include -o - -S map.c
 */
static int
lookup_zone(const struct adfs_discmap *dm, const unsigned int idlen,
	    const unsigned int frag_id, unsigned int *offset)
{
	const unsigned int mapsize = dm->dm_endbit;
	const unsigned int idmask = (1 << idlen) - 1;
	unsigned long *map = ((unsigned long *)dm->dm_bh->b_data) + 1;
	unsigned int start = dm->dm_startbit;
	unsigned int mapptr;

	do {
		unsigned long frag;

		frag = GET_FRAG_ID(map, start, idmask);
		mapptr = start + idlen;

		/*
		 * find end of fragment
		 */
		{
			unsigned long v2;

			while ((v2 = map[mapptr >> 5] >> (mapptr & 31)) == 0) {
				mapptr = (mapptr & ~31) + 32;
				if (mapptr >= mapsize)
					goto error;
			}

			mapptr += 1 + ffz(~v2);
		}

		if (frag == frag_id)
			goto found;
again:
		start = mapptr;
	} while (mapptr < mapsize);

error:
	return -1;

found:
	{
		int length = mapptr - start;
		if (*offset >= length) {
			*offset -= length;
			goto again;
		}
	}
	return start + *offset;
}