Example #1
0
int
affs_remove_hash(struct inode *dir, struct buffer_head *rem_bh)
{
    struct super_block *sb;
    struct buffer_head *bh;
    u32 rem_ino, hash_ino;
    __be32 ino;
    int offset, retval;

    sb = dir->i_sb;
    rem_ino = rem_bh->b_blocknr;
    offset = affs_hash_name(sb, AFFS_TAIL(sb, rem_bh)->name+1, AFFS_TAIL(sb, rem_bh)->name[0]);
    pr_debug("AFFS: remove_hash(dir=%d, ino=%d, hashval=%d)\n", (u32)dir->i_ino, rem_ino, offset);

    bh = affs_bread(sb, dir->i_ino);
    if (!bh)
        return -EIO;

    retval = -ENOENT;
    hash_ino = be32_to_cpu(AFFS_HEAD(bh)->table[offset]);
    while (hash_ino) {
        if (hash_ino == rem_ino) {
            ino = AFFS_TAIL(sb, rem_bh)->hash_chain;
            if (dir->i_ino == bh->b_blocknr)
                AFFS_HEAD(bh)->table[offset] = ino;
            else
                AFFS_TAIL(sb, bh)->hash_chain = ino;
            affs_adjust_checksum(bh, be32_to_cpu(ino) - hash_ino);
            mark_buffer_dirty_inode(bh, dir);
            AFFS_TAIL(sb, rem_bh)->parent = 0;
            retval = 0;
            break;
        }
        affs_brelse(bh);
        bh = affs_bread(sb, hash_ino);
        if (!bh)
            return -EIO;
        hash_ino = be32_to_cpu(AFFS_TAIL(sb, bh)->hash_chain);
    }

    affs_brelse(bh);

    dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
    dir->i_version++;
    mark_inode_dirty(dir);

    return retval;
}
Example #2
0
int
affs_insert_hash(struct inode *dir, struct buffer_head *bh)
{
    struct super_block *sb = dir->i_sb;
    struct buffer_head *dir_bh;
    u32 ino, hash_ino;
    int offset;

    ino = bh->b_blocknr;
    offset = affs_hash_name(sb, AFFS_TAIL(sb, bh)->name + 1, AFFS_TAIL(sb, bh)->name[0]);

    pr_debug("AFFS: insert_hash(dir=%u, ino=%d)\n", (u32)dir->i_ino, ino);

    dir_bh = affs_bread(sb, dir->i_ino);
    if (!dir_bh)
        return -EIO;

    hash_ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[offset]);
    while (hash_ino) {
        affs_brelse(dir_bh);
        dir_bh = affs_bread(sb, hash_ino);
        if (!dir_bh)
            return -EIO;
        hash_ino = be32_to_cpu(AFFS_TAIL(sb, dir_bh)->hash_chain);
    }
    AFFS_TAIL(sb, bh)->parent = cpu_to_be32(dir->i_ino);
    AFFS_TAIL(sb, bh)->hash_chain = 0;
    affs_fix_checksum(sb, bh);

    if (dir->i_ino == dir_bh->b_blocknr)
        AFFS_HEAD(dir_bh)->table[offset] = cpu_to_be32(ino);
    else
        AFFS_TAIL(sb, dir_bh)->hash_chain = cpu_to_be32(ino);

    affs_adjust_checksum(dir_bh, ino);
    mark_buffer_dirty_inode(dir_bh, dir);
    affs_brelse(dir_bh);

    dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
    dir->i_version++;
    mark_inode_dirty(dir);

    return 0;
}
Example #3
0
int
affs_add_entry(struct inode *dir, struct inode *inode, struct dentry *dentry, s32 type)
{
    struct super_block *sb = dir->i_sb;
    struct buffer_head *inode_bh = NULL;
    struct buffer_head *bh = NULL;
    u32 block = 0;
    int retval;

    pr_debug("AFFS: add_entry(dir=%u, inode=%u, \"%*s\", type=%d)\n", (u32)dir->i_ino,
             (u32)inode->i_ino, (int)dentry->d_name.len, dentry->d_name.name, type);

    retval = -EIO;
    bh = affs_bread(sb, inode->i_ino);
    if (!bh)
        goto done;

    affs_lock_link(inode);
    switch (type) {
    case ST_LINKFILE:
    case ST_LINKDIR:
        retval = -ENOSPC;
        block = affs_alloc_block(dir, dir->i_ino);
        if (!block)
            goto err;
        retval = -EIO;
        inode_bh = bh;
        bh = affs_getzeroblk(sb, block);
        if (!bh)
            goto err;
        break;
    default:
        break;
    }

    AFFS_HEAD(bh)->ptype = cpu_to_be32(T_SHORT);
    AFFS_HEAD(bh)->key = cpu_to_be32(bh->b_blocknr);
    affs_copy_name(AFFS_TAIL(sb, bh)->name, dentry);
    AFFS_TAIL(sb, bh)->stype = cpu_to_be32(type);
    AFFS_TAIL(sb, bh)->parent = cpu_to_be32(dir->i_ino);

    if (inode_bh) {
        __be32 chain;
        chain = AFFS_TAIL(sb, inode_bh)->link_chain;
        AFFS_TAIL(sb, bh)->original = cpu_to_be32(inode->i_ino);
        AFFS_TAIL(sb, bh)->link_chain = chain;
        AFFS_TAIL(sb, inode_bh)->link_chain = cpu_to_be32(block);
        affs_adjust_checksum(inode_bh, block - be32_to_cpu(chain));
        mark_buffer_dirty_inode(inode_bh, inode);
        inode->i_nlink = 2;
        atomic_inc(&inode->i_count);
    }
    affs_fix_checksum(sb, bh);
    mark_buffer_dirty_inode(bh, inode);
    dentry->d_fsdata = (void *)(long)bh->b_blocknr;

    affs_lock_dir(dir);
    retval = affs_insert_hash(dir, bh);
    mark_buffer_dirty_inode(bh, inode);
    affs_unlock_dir(dir);
    affs_unlock_link(inode);

    d_instantiate(dentry, inode);
done:
    affs_brelse(inode_bh);
    affs_brelse(bh);
    return retval;
err:
    if (block)
        affs_free_block(sb, block);
    affs_unlock_link(inode);
    goto done;
}
Example #4
0
static int
affs_remove_link(struct dentry *dentry)
{
    struct inode *dir, *inode = dentry->d_inode;
    struct super_block *sb = inode->i_sb;
    struct buffer_head *bh = NULL, *link_bh = NULL;
    u32 link_ino, ino;
    int retval;

    pr_debug("AFFS: remove_link(key=%ld)\n", inode->i_ino);
    retval = -EIO;
    bh = affs_bread(sb, inode->i_ino);
    if (!bh)
        goto done;

    link_ino = (u32)(long)dentry->d_fsdata;
    if (inode->i_ino == link_ino) {
        /* we can't remove the head of the link, as its blocknr is still used as ino,
         * so we remove the block of the first link instead.
         */
        link_ino = be32_to_cpu(AFFS_TAIL(sb, bh)->link_chain);
        link_bh = affs_bread(sb, link_ino);
        if (!link_bh)
            goto done;

        dir = affs_iget(sb, be32_to_cpu(AFFS_TAIL(sb, link_bh)->parent));
        if (IS_ERR(dir)) {
            retval = PTR_ERR(dir);
            goto done;
        }

        affs_lock_dir(dir);
        affs_fix_dcache(dentry, link_ino);
        retval = affs_remove_hash(dir, link_bh);
        if (retval) {
            affs_unlock_dir(dir);
            goto done;
        }
        mark_buffer_dirty_inode(link_bh, inode);

        memcpy(AFFS_TAIL(sb, bh)->name, AFFS_TAIL(sb, link_bh)->name, 32);
        retval = affs_insert_hash(dir, bh);
        if (retval) {
            affs_unlock_dir(dir);
            goto done;
        }
        mark_buffer_dirty_inode(bh, inode);

        affs_unlock_dir(dir);
        iput(dir);
    } else {
        link_bh = affs_bread(sb, link_ino);
        if (!link_bh)
            goto done;
    }

    while ((ino = be32_to_cpu(AFFS_TAIL(sb, bh)->link_chain)) != 0) {
        if (ino == link_ino) {
            __be32 ino2 = AFFS_TAIL(sb, link_bh)->link_chain;
            AFFS_TAIL(sb, bh)->link_chain = ino2;
            affs_adjust_checksum(bh, be32_to_cpu(ino2) - link_ino);
            mark_buffer_dirty_inode(bh, inode);
            retval = 0;
            /* Fix the link count, if bh is a normal header block without links */
            switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) {
            case ST_LINKDIR:
            case ST_LINKFILE:
                break;
            default:
                if (!AFFS_TAIL(sb, bh)->link_chain)
                    inode->i_nlink = 1;
            }
            affs_free_block(sb, link_ino);
            goto done;
        }
        affs_brelse(bh);
        bh = affs_bread(sb, ino);
        if (!bh)
            goto done;
    }
    retval = -ENOENT;
done:
    affs_brelse(link_bh);
    affs_brelse(bh);
    return retval;
}