예제 #1
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;
}
예제 #2
0
int
affs_remove_header(struct dentry *dentry)
{
    struct super_block *sb;
    struct inode *inode, *dir;
    struct buffer_head *bh = NULL;
    int retval;

    dir = dentry->d_parent->d_inode;
    sb = dir->i_sb;

    retval = -ENOENT;
    inode = dentry->d_inode;
    if (!inode)
        goto done;

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

    affs_lock_link(inode);
    affs_lock_dir(dir);
    switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) {
    case ST_USERDIR:
        /* if we ever want to support links to dirs
         * i_hash_lock of the inode must only be
         * taken after some checks
         */
        affs_lock_dir(inode);
        retval = affs_empty_dir(inode);
        affs_unlock_dir(inode);
        if (retval)
            goto done_unlock;
        break;
    default:
        break;
    }

    retval = affs_remove_hash(dir, bh);
    if (retval)
        goto done_unlock;
    mark_buffer_dirty_inode(bh, inode);

    affs_unlock_dir(dir);

    if (inode->i_nlink > 1)
        retval = affs_remove_link(dentry);
    else
        inode->i_nlink = 0;
    affs_unlock_link(inode);
    inode->i_ctime = CURRENT_TIME_SEC;
    mark_inode_dirty(inode);

done:
    affs_brelse(bh);
    return retval;

done_unlock:
    affs_unlock_dir(dir);
    affs_unlock_link(inode);
    goto done;
}