Пример #1
0
struct inode *
affs_new_inode(const struct inode *dir)
{
	struct inode		*inode;
	struct super_block	*sb;
	s32			 block;

	if (!dir || !(inode = get_empty_inode()))
		return NULL;

	sb = dir->i_sb;
	inode->i_sb    = sb;
	inode->i_flags = 0;

	if (!(block = affs_new_header((struct inode *)dir))) {
		iput(inode);
		return NULL;
	}

	inode->i_count   = 1;
	inode->i_nlink   = 1;
	inode->i_dev     = sb->s_dev;
	inode->i_uid     = current->fsuid;
	inode->i_gid     = current->fsgid;
	inode->i_ino     = block;
	inode->i_op      = NULL;
	inode->i_blocks  = 0;
	inode->i_size    = 0;
	inode->i_mode    = 0;
	inode->i_blksize = 0;
	inode->i_mtime   = inode->i_atime = inode->i_ctime = CURRENT_TIME;

	inode->u.affs_i.i_original  = 0;
	inode->u.affs_i.i_parent    = dir->i_ino;
	inode->u.affs_i.i_zone      = 0;
	inode->u.affs_i.i_hlink     = 0;
	inode->u.affs_i.i_pa_cnt    = 0;
	inode->u.affs_i.i_pa_next   = 0;
	inode->u.affs_i.i_pa_last   = 0;
	inode->u.affs_i.i_ec        = NULL;
	inode->u.affs_i.i_lastblock = -1;

	insert_inode_hash(inode);
	mark_inode_dirty(inode);

	return inode;
}
Пример #2
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;
}