Exemple #1
0
/*
 * shrink_fork()
 *
 * Try to remove enough allocation blocks from 'fork'
 * so that it is 'ablocks' allocation blocks long.
 */
static void shrink_fork(struct hfs_fork *fork, int ablocks)
{
    struct hfs_mdb *mdb = fork->entry->mdb;
    struct hfs_extent *ext;
    int i, error, next, count;
    hfs_u32 ablksz = mdb->alloc_blksz;

    next =  (fork->psize / ablksz) - 1;
    ext = find_ext(fork, next);
    while (ext && ext->start && (ext->start >= ablocks)) {
        next = ext->start - 1;
        delete_extent(fork, ext);
        ext = find_ext(fork, next);
    }
    if (!ext) {
        fork->psize = (next + 1) * ablksz;
        return;
    }

    if ((count = next + 1 - ablocks) > 0) {
        for (i=2; (i>=0) && !ext->length[i]; --i) {};
        lock_bitmap(mdb);
        while (count && (ext->length[i] <= count)) {
            ext->end -= ext->length[i];
            count -= ext->length[i];
            error = hfs_clear_vbm_bits(mdb, ext->block[i],
                                       ext->length[i]);
            if (error) {
                hfs_warn("hfs_truncate: error %d freeing "
                         "blocks.\n", error);
            }
            ext->block[i] = ext->length[i] = 0;
            --i;
        }
        if (count) {
            ext->end -= count;
            ext->length[i] -= count;
            error = hfs_clear_vbm_bits(mdb, ext->block[i] +
                                       ext->length[i], count);
            if (error) {
                hfs_warn("hfs_truncate: error %d freeing "
                         "blocks.\n", error);
            }
        }
        unlock_bitmap(mdb);
        update_ext(fork, ext);
    }

    fork->psize = ablocks * ablksz;
}
Exemple #2
0
static int hfs_free_extents(struct super_block *sb, struct hfs_extent *extent,
			    u16 offset, u16 block_nr)
{
	u16 count, start;
	int i;

	hfs_dump_extent(extent);
	for (i = 0; i < 3; extent++, i++) {
		count = be16_to_cpu(extent->count);
		if (offset == count)
			goto found;
		else if (offset < count)
			break;
		offset -= count;
	}
	/* panic? */
	return -EIO;
found:
	for (;;) {
		start = be16_to_cpu(extent->block);
		if (count <= block_nr) {
			hfs_clear_vbm_bits(sb, start, count);
			extent->block = 0;
			extent->count = 0;
			block_nr -= count;
		} else {
			count -= block_nr;
			hfs_clear_vbm_bits(sb, start + count, block_nr);
			extent->count = cpu_to_be16(count);
			block_nr = 0;
		}
		if (!block_nr || !i)
			return 0;
		i--;
		extent--;
		count = be16_to_cpu(extent->count);
	}
}
Exemple #3
0
/*
 * delete_extent()
 *
 * Description:
 *   Deletes an extent record from a fork, reducing its physical length.
 * Input Variable(s):
 *   struct hfs_fork *fork: the fork
 *   struct hfs_extent *ext: the current last extent for 'fork'
 * Output Variable(s):
 *   NONE
 * Returns:
 *   void
 * Preconditions:
 *   'fork' points to a valid (struct hfs_fork)
 *   'ext' point to a valid (struct hfs_extent) which is the last in 'fork'
 *    and which is not also the first extent in 'fork'.
 * Postconditions:
 *   The extent record has been removed if possible, and a warning has been
 *   printed otherwise.
 */
static void delete_extent(struct hfs_fork *fork, struct hfs_extent *ext)
{
    struct hfs_mdb *mdb = fork->entry->mdb;
    struct hfs_ext_key key;
    int error;

    if (fork->cache == ext) {
        set_cache(fork, ext->prev);
    }
    ext->prev->next = NULL;
    if (ext->count != 1) {
        hfs_warn("hfs_truncate: extent has count %d.\n", ext->count);
    }

    lock_bitmap(mdb);
    error = hfs_clear_vbm_bits(mdb, ext->block[2], ext->length[2]);
    if (error) {
        hfs_warn("hfs_truncate: error %d freeing blocks.\n", error);
    }
    error = hfs_clear_vbm_bits(mdb, ext->block[1], ext->length[1]);
    if (error) {
        hfs_warn("hfs_truncate: error %d freeing blocks.\n", error);
    }
    error = hfs_clear_vbm_bits(mdb, ext->block[0], ext->length[0]);
    if (error) {
        hfs_warn("hfs_truncate: error %d freeing blocks.\n", error);
    }
    unlock_bitmap(mdb);

    build_key(&key, fork, ext->start);

    error = hfs_bdelete(mdb->ext_tree, HFS_BKEY(&key));
    if (error) {
        hfs_warn("hfs_truncate: error %d deleting an extent.\n", error);
    }

    HFS_DELETE(ext);
}
Exemple #4
0
/*
 * grow_fork()
 *
 * Try to add enough allocation blocks to 'fork'
 * so that it is 'ablock' allocation blocks long.
 */
static int grow_fork(struct hfs_fork *fork, int ablocks)
{
    struct hfs_cat_entry *entry = fork->entry;
    struct hfs_mdb *mdb = entry->mdb;
    struct hfs_extent *ext;
    int i, start, err;
    hfs_u16 need, len=0;
    hfs_u32 ablksz = mdb->alloc_blksz;
    hfs_u32 blocks, clumpablks;

    blocks = fork->psize;
    need = ablocks - blocks/ablksz;
    if (need < 1) { /* no need to grow the fork */
        return 0;
    }

    /* round up to clumpsize */
    if (entry->u.file.clumpablks) {
        clumpablks = entry->u.file.clumpablks;
    } else {
        clumpablks = mdb->clumpablks;
    }
    need = ((need + clumpablks - 1) / clumpablks) * clumpablks;

    /* find last extent record and try to extend it */
    if (!(ext = find_ext(fork, blocks/ablksz - 1))) {
        /* somehow we couldn't find the end of the file! */
        return -1;
    }

    /* determine which is the last used extent in the record */
    /* then try to allocate the blocks immediately following it */
    for (i=2; (i>=0) && !ext->length[i]; --i) {};
    if (i>=0) {
        /* try to extend the last extent */
        start = ext->block[i] + ext->length[i];

        err = 0;
        lock_bitmap(mdb);
        len = hfs_vbm_count_free(mdb, start);
        if (!len) {
            unlock_bitmap(mdb);
            goto more_extents;
        }
        if (need < len) {
            len = need;
        }
        err = hfs_set_vbm_bits(mdb, start, len);
        unlock_bitmap(mdb);
        if (err) {
            relse_ext(ext);
            return -1;
        }

        zero_blocks(mdb, start, len);

        ext->length[i] += len;
        ext->end += len;
        blocks = (fork->psize += len * ablksz);
        need -= len;
        update_ext(fork, ext);
    }

more_extents:
    /* add some more extents */
    while (need) {
        len = need;
        err = 0;
        lock_bitmap(mdb);
        start = hfs_vbm_search_free(mdb, &len);
        if (need < len) {
            len = need;
        }
        err = hfs_set_vbm_bits(mdb, start, len);
        unlock_bitmap(mdb);
        if (!len || err) {
            relse_ext(ext);
            return -1;
        }
        zero_blocks(mdb, start, len);

        /* determine which is the first free extent in the record */
        for (i=0; (i<3) && ext->length[i]; ++i) {};
        if (i < 3) {
            ext->block[i] = start;
            ext->length[i] = len;
            ext->end += len;
            update_ext(fork, ext);
        } else {
            if (!(ext = new_extent(fork, ext, blocks/ablksz,
                                   start, len, ablksz))) {
                lock_bitmap(mdb);
                hfs_clear_vbm_bits(mdb, start, len);
                unlock_bitmap(mdb);
                return -1;
            }
        }
        blocks = (fork->psize += len * ablksz);
        need -= len;
    }
    set_cache(fork, ext);
    relse_ext(ext);
    return 0;
}