Exemple #1
0
struct inode *
affs_new_inode(struct inode *dir)
{
	struct super_block	*sb = dir->i_sb;
	struct inode		*inode;
	u32			 block;
	struct buffer_head	*bh;

	if (!(inode = new_inode(sb)))
		goto err_inode;

	if (!(block = affs_alloc_block(dir, dir->i_ino)))
		goto err_block;

	bh = affs_getzeroblk(sb, block);
	if (!bh)
		goto err_bh;
	mark_buffer_dirty_inode(bh, inode);
	affs_brelse(bh);

	inode->i_uid     = current_fsuid();
	inode->i_gid     = current_fsgid();
	inode->i_ino     = block;
	set_nlink(inode, 1);
	inode->i_mtime   = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
	atomic_set(&AFFS_I(inode)->i_opencnt, 0);
	AFFS_I(inode)->i_blkcnt = 0;
	AFFS_I(inode)->i_lc = NULL;
	AFFS_I(inode)->i_lc_size = 0;
	AFFS_I(inode)->i_lc_shift = 0;
	AFFS_I(inode)->i_lc_mask = 0;
	AFFS_I(inode)->i_ac = NULL;
	AFFS_I(inode)->i_ext_bh = NULL;
	AFFS_I(inode)->mmu_private = 0;
	AFFS_I(inode)->i_protect = 0;
	AFFS_I(inode)->i_lastalloc = 0;
	AFFS_I(inode)->i_pa_cnt = 0;
	AFFS_I(inode)->i_extcnt = 1;
	AFFS_I(inode)->i_ext_last = ~1;

	insert_inode_hash(inode);

	return inode;

err_bh:
	affs_free_block(sb, block);
err_block:
	iput(inode);
err_inode:
	return NULL;
}
Exemple #2
0
void
affs_free_prealloc(struct inode *inode)
{
	struct super_block	*sb = inode->i_sb;
	struct affs_zone	*zone;
	int block;

	pr_debug("AFFS: free_prealloc(ino=%lu)\n", inode->i_ino);

	while (inode->u.affs_i.i_pa_cnt) {	
		block = inode->u.affs_i.i_data[inode->u.affs_i.i_pa_next++];
		inode->u.affs_i.i_pa_next &= AFFS_MAX_PREALLOC - 1;
		inode->u.affs_i.i_pa_cnt--;
		affs_free_block(sb, block);
	}
	if (inode->u.affs_i.i_zone) {
		zone = &sb->u.affs_sb.s_zones[inode->u.affs_i.i_zone];
		if (zone->z_ino == inode->i_ino)
			zone->z_ino = 0;
	}
}
Exemple #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;
}
Exemple #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;
}
Exemple #5
0
void
affs_truncate(struct inode *inode)
{
	struct buffer_head	*bh = NULL;
	int	 first;			/* First block to be thrown away	*/
	int	 block;
	s32	 key;
	s32	*keyp;
	s32	 ekey;
	s32	 ptype, stype;
	int	 freethis;
	int	 net_blocksize;
	int	 blocksize = AFFS_I2BSIZE(inode);
	int	 rem;
	int	 ext;

	pr_debug("AFFS: truncate(inode=%ld,size=%lu)\n",inode->i_ino,inode->i_size);

	net_blocksize = blocksize - ((inode->i_sb->u.affs_sb.s_flags & SF_OFS) ? 24 : 0);
	first = (inode->i_size + net_blocksize - 1) / net_blocksize;
	if (inode->u.affs_i.i_lastblock < first - 1) {
		/* There has to be at least one new block to be allocated */
		if (!inode->u.affs_i.i_ec && alloc_ext_cache(inode)) {
			/* XXX Fine! No way to indicate an error. */
			return /* -ENOSPC */;
		}
		bh = affs_getblock(inode,first - 1);
		if (!bh) {
			affs_warning(inode->i_sb,"truncate","Cannot extend file");
			inode->i_size = net_blocksize * (inode->u.affs_i.i_lastblock + 1);
		} else if (inode->i_sb->u.affs_sb.s_flags & SF_OFS) {
			rem = inode->i_size % net_blocksize;
			DATA_FRONT(bh)->data_size = cpu_to_be32(rem ? rem : net_blocksize);
			affs_fix_checksum(blocksize,bh->b_data,5);
			mark_buffer_dirty(bh,0);
		}
		goto out_truncate;
	}
	ekey = inode->i_ino;
	ext  = 0;

	/* Free all blocks starting at 'first' and all then-empty
	 * extension blocks. Do not free the header block, though.
	 */
	while (ekey) {
		if (!(bh = affs_bread(inode->i_dev,ekey,blocksize))) {
			affs_error(inode->i_sb,"truncate","Cannot read block %d",ekey);
			goto out_truncate;
		}
		if (affs_checksum_block(blocksize,bh->b_data,&ptype,&stype)) {
			affs_error(inode->i_sb,"truncate","Checksum error in header/ext block %d",
				   ekey);
			goto out_truncate;
		}
		if (stype != ST_FILE || (ptype != T_SHORT && ptype != T_LIST)) {
			affs_error(inode->i_sb,"truncate",
				   "Bad block (key=%d, ptype=%d, stype=%d)",ekey,ptype,stype);
			goto out_truncate;
		}
		/* Do we have to free this extension block after
		 * freeing the data blocks pointed to?
		 */
		freethis = first == 0 && ekey != inode->i_ino;

		/* Free the data blocks. 'first' is relative to this
		 * extension block and may well lie behind this block.
		 */
		for (block = first; block < AFFS_I2HSIZE(inode); block++) {
			keyp = &AFFS_BLOCK(bh->b_data,inode,block);
			key  = be32_to_cpu(*keyp);
			if (key) {
				*keyp = 0;
				affs_free_block(inode->i_sb,key);
			} else
				break;
		}
		keyp = &GET_END_PTR(struct file_end,bh->b_data,blocksize)->extension;
		key  = be32_to_cpu(*keyp);

		/* If 'first' is in this block or is the first
		 * in the next one, this will be the last in
		 * the list, thus we have to adjust the count
		 * and zero the pointer to the next ext block.
		 */
		if (first <= AFFS_I2HSIZE(inode)) {
			((struct file_front *)bh->b_data)->block_count = cpu_to_be32(first);
			first = 0;
			*keyp = 0;
			affs_fix_checksum(blocksize,bh->b_data,5);
			mark_buffer_dirty(bh,1);
		} else
			first -= AFFS_I2HSIZE(inode);
		affs_brelse(bh);
		bh = NULL;
		if (freethis)			/* Don't bother fixing checksum */
			affs_free_block(inode->i_sb,ekey);
		ekey = key;
	}
	block = ((inode->i_size + net_blocksize - 1) / net_blocksize) - 1;
	inode->u.affs_i.i_lastblock = block;

	/* If the file is not truncated to a block boundary,
	 * the partial block after the EOF must be zeroed
	 * so it cannot become accessible again.
	 */

	rem = inode->i_size % net_blocksize;
	if (rem) {
		if ((inode->i_sb->u.affs_sb.s_flags & SF_OFS)) 
			rem += 24;
		pr_debug("AFFS: Zeroing from offset %d in block %d\n",rem,block);
		bh = affs_getblock(inode,block);
		if (bh) {
			memset(bh->b_data + rem,0,blocksize - rem);
			if ((inode->i_sb->u.affs_sb.s_flags & SF_OFS)) {
				((struct data_front *)bh->b_data)->data_size = cpu_to_be32(rem);
				((struct data_front *)bh->b_data)->next_data = 0;
				affs_fix_checksum(blocksize,bh->b_data,5);
			}
			mark_buffer_dirty(bh,1);
		} else 
			affs_error(inode->i_sb,"truncate","Cannot read block %d",block);
	}

out_truncate:
	affs_brelse(bh);
	/* Invalidate cache */
	if (inode->u.affs_i.i_ec) {
		inode->u.affs_i.i_ec->max_ext = 0;
		for (key = 0; key < 3; key++) {
			inode->u.affs_i.i_ec->kc[key].kc_next_key = 0;
			inode->u.affs_i.i_ec->kc[key].kc_last     = -1;
		}
	}
	mark_inode_dirty(inode);
}
Exemple #6
0
static struct buffer_head *
affs_getblock(struct inode *inode, s32 block)
{
	struct super_block	*sb = inode->i_sb;
	int			 ofs = sb->u.affs_sb.s_flags & SF_OFS;
	int			 ext = block / AFFS_I2HSIZE(inode);
	struct buffer_head	*bh, *ebh, *pbh = NULL;
	struct key_cache	*kc;
	s32			 key, nkey;
	int			 cf, j, pt;
	int			 index;
	int			 err;

	pr_debug("AFFS: getblock(%lu,%d)\n",inode->i_ino,block);

	if (block < 0)
		goto out_fail;

	key    = calc_key(inode,&ext);
	block -= ext * AFFS_I2HSIZE(inode);
	pt     = ext ? T_LIST : T_SHORT;

	/* Key refers now to the last known extension block,
	 * ext is its sequence number (if 0, key refers to the
	 * header block), and block is the block number relative
	 * to the first block stored in that extension block.
	 */
	for (;;) {	/* Loop over header block and extension blocks */
		struct file_front *fdp;

		bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
		if (!bh)
			goto out_fail;
		fdp = (struct file_front *) bh->b_data;
		err = affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&cf,&j);
		if (err || cf != pt || j != ST_FILE) {
		    	affs_error(sb, "getblock",
				"Block %d is not a valid %s", key,
				pt == T_SHORT ? "file header" : "ext block");
			goto out_free_bh;
		}
		j  = be32_to_cpu(((struct file_front *)bh->b_data)->block_count);
		for (cf = 0; j < AFFS_I2HSIZE(inode) && j <= block; j++) {
			if (ofs && !pbh && inode->u.affs_i.i_lastblock >= 0) {
				if (j > 0) {
					s32 k = AFFS_BLOCK(bh->b_data, inode,
								j - 1);
					pbh = affs_bread(inode->i_dev,
							be32_to_cpu(k),
							AFFS_I2BSIZE(inode));
				} else
					pbh = affs_getblock(inode,inode->u.affs_i.i_lastblock);
				if (!pbh) {
					affs_error(sb,"getblock",
						"Cannot get last block in file");
					break;
				}
			}
			nkey = affs_new_data(inode);
			if (!nkey)
				break;
			inode->u.affs_i.i_lastblock++;
			if (AFFS_BLOCK(bh->b_data,inode,j)) {
				affs_warning(sb,"getblock","Block already allocated");
				affs_free_block(sb,nkey);
				continue;
			}
			AFFS_BLOCK(bh->b_data,inode,j) = cpu_to_be32(nkey);
			if (ofs) {
				ebh = affs_bread(inode->i_dev,nkey,AFFS_I2BSIZE(inode));
				if (!ebh) {
					affs_error(sb,"getblock",
						   "Cannot get block %d",nkey);
					affs_free_block(sb,nkey);
					AFFS_BLOCK(bh->b_data,inode,j) = 0;
					break;
				}
				DATA_FRONT(ebh)->primary_type    = cpu_to_be32(T_DATA);
				DATA_FRONT(ebh)->header_key      = cpu_to_be32(inode->i_ino);
				DATA_FRONT(ebh)->sequence_number = cpu_to_be32(inode->u.affs_i.i_lastblock + 1);
				affs_fix_checksum(AFFS_I2BSIZE(inode),
							ebh->b_data, 5);
				mark_buffer_dirty(ebh, 0);
				if (pbh) {
					DATA_FRONT(pbh)->data_size = cpu_to_be32(AFFS_I2BSIZE(inode) - 24);
					DATA_FRONT(pbh)->next_data = cpu_to_be32(nkey);
					affs_fix_checksum(AFFS_I2BSIZE(inode),pbh->b_data,5);
					mark_buffer_dirty(pbh,0);
					affs_brelse(pbh);
				}
				pbh = ebh;
			}
			cf = 1;
		}
		/* N.B. May need to release pbh after here */

		if (cf) {
			if (pt == T_SHORT)
				fdp->first_data = AFFS_BLOCK(bh->b_data,inode,0);
			fdp->block_count = cpu_to_be32(j);
			affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
			mark_buffer_dirty(bh,1);
		}

		if (block < j) {
			if (pbh)
				affs_brelse(pbh);
			break;
		}
		if (j < AFFS_I2HSIZE(inode)) {
			/* N.B. What about pbh here? */
			goto out_free_bh;
		}

		block -= AFFS_I2HSIZE(inode);
		key    = be32_to_cpu(FILE_END(bh->b_data,inode)->extension);
		if (!key) {
			key = affs_new_header(inode);
			if (!key)
				goto out_free_bh;
			ebh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
			if (!ebh) {
				/* N.B. must free bh here */
				goto out_free_block;
			}
			((struct file_front *)ebh->b_data)->primary_type = cpu_to_be32(T_LIST);
			((struct file_front *)ebh->b_data)->own_key      = cpu_to_be32(key);
			FILE_END(ebh->b_data,inode)->secondary_type      = cpu_to_be32(ST_FILE);
			FILE_END(ebh->b_data,inode)->parent              = cpu_to_be32(inode->i_ino);
			affs_fix_checksum(AFFS_I2BSIZE(inode),ebh->b_data,5);
			mark_buffer_dirty(ebh, 1);
			FILE_END(bh->b_data,inode)->extension = cpu_to_be32(key);
			affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
			mark_buffer_dirty(bh,1);
			affs_brelse(bh);
			bh = ebh;
		}
		pt = T_LIST;
		ext++;
		index = seqnum_to_index(ext);
		if (index > inode->u.affs_i.i_ec->max_ext &&
		    AFFS_ISINDEX(ext)) {
			inode->u.affs_i.i_ec->ec[index] = key;
			inode->u.affs_i.i_ec->max_ext   = index;
		}
		affs_brelse(bh);
	}

	/* Invalidate key cache */
	for (j = 0; j < 4; j++) {
		kc = &inode->u.affs_i.i_ec->kc[j];
		kc->kc_last = -1;
	}
	key = be32_to_cpu(AFFS_BLOCK(bh->b_data,inode,block));
	affs_brelse(bh);
	if (!key)
		goto out_fail;

	bh = affs_bread(inode->i_dev, key, AFFS_I2BSIZE(inode));
	return bh;

out_free_block:
	affs_free_block(sb, key);
out_free_bh:
	affs_brelse(bh);
out_fail:
	return NULL;
}