管理minix中增加的数据索引的三级存储结构代码

这段代码展示了Minix文件系统中对于数据增加索引后的三级结构管理方式,包括索引块的转换、路径查找、分配、拼接和释放等操作。主要涉及到了索引块的内存管理和磁盘读写,以及在面临数据变更时的错误处理和同步机制。
摘要由CSDN通过智能技术生成

这里2020年写的针对minix数据增加索引后,使用三级结构进行管理的相关代码。

#ifndef _H_ITREE_INDEX_H
#define _H_ITREE_INDEX_H 
#include <linux/buffer_head.h>
#include "minix.h"

static unsigned long max_size = 0x7fffffffffffffff;
/* added by linbin */

enum {IDXDIRECT = 7, IDXDEPTH = 4};	/* Have triple indirect */

typedef u32 index_block_t;	/* 32 bit, host order */

static inline unsigned long index_block_to_cpu(index_block_t n)
{
	return n;
}

static inline index_block_t cpu_to_index_block(unsigned long n)
{
	return n;
}

static inline index_block_t *index_data(struct inode *index_inode)
{
	return (index_block_t *)minix_index_i(index_inode)->i_data;
}

static inline index_block_t *block_end(struct buffer_head *bh)
{
	return (index_block_t *)((char*)bh->b_data + bh->b_size);
}

#define IDXDIRCOUNT 7
#define IDXINDIRCOUNT(sb) (1 << ((sb)->s_blocksize_bits - 2))

static int index_block_to_path(struct inode *index_inode, long block, int offsets[IDXDEPTH])
{
	int n = 0;
	struct super_block *sb = index_inode->i_sb;

	if (block < 0) {
		printk("minix-v2-fs: block_to_path: block %ld < 0 on dev %pg\n",block, sb->s_bdev);
	} else if ((u64)block * (u64)sb->s_blocksize >= max_size) {
		if (printk_ratelimit())
			printk("minix-v2-fs: block_to_path: block %ld too big on dev %pg\n",
				block, sb->s_bdev);
	} else if (block < IDXDIRCOUNT) {
		offsets[n++] = block;
	} else if ((block -= IDXDIRCOUNT) < IDXINDIRCOUNT(sb)) {
		offsets[n++] = IDXDIRCOUNT;
		offsets[n++] = block;
	} else if ((block -= IDXINDIRCOUNT(sb)) < IDXINDIRCOUNT(sb) * IDXINDIRCOUNT(sb)) {
		offsets[n++] = IDXDIRCOUNT + 1;
		offsets[n++] = block / IDXINDIRCOUNT(sb);
		offsets[n++] = block % IDXINDIRCOUNT(sb);
	} else {
		block -= IDXINDIRCOUNT(sb) * IDXINDIRCOUNT(sb);
		offsets[n++] = IDXDIRCOUNT + 2;
		offsets[n++] = (block / IDXINDIRCOUNT(sb)) / IDXINDIRCOUNT(sb);
		offsets[n++] = (block / IDXINDIRCOUNT(sb)) % IDXINDIRCOUNT(sb);
		offsets[n++] = block % IDXINDIRCOUNT(sb);
	}
	return n;
}

typedef struct {
	index_block_t	*p;
	index_block_t	key;
	struct buffer_head *bh;
} IDXIndirect;

static DEFINE_RWLOCK(idx_pointers_lock);

static inline void add_index_chain(IDXIndirect *p, struct buffer_head *bh, index_block_t *v)
{
	p->key = *(p->p = v);
	p->bh = bh;
}

static inline int verify_index_chain(IDXIndirect *from, IDXIndirect *to)
{
	while (from <= to && from->key == *from->p)
		from++;
	return (from > to);
}

static inline index_block_t *index_block_end(struct buffer_head *bh)
{
	return (index_block_t *)((char*)bh->b_data + bh->b_size);
}

static inline IDXIndirect *get_index_branch(struct inode *index_inode,
					int depth,
					int *offsets,
					IDXIndirect chain[IDXDEPTH],
					int *err)
{
	struct super_block *sb = index_inode->i_sb;

	IDXIndirect *p = chain;
	struct buffer_head *bh;

	*err = 0;
	/* i_data is not going away, no lock needed */
	add_index_chain(chain, NULL, index_data(index_inode) + *offsets);
	if (!p->key)
		goto no_block;
	while (--depth) {
		bh = sb_bread(sb, index_block_to_cpu(p->key));
		if (!bh)
			goto failure;
		read_lock(&idx_pointers_lock);
		if (!verify_index_chain(chain, p))
			goto changed;
		add_index_chain(++p, bh, (index_block_t *)bh->b_data + *++offsets);
		read_unlock(&idx_pointers_lock);
		if (!p->key)
			goto no_block;
	}
	return NULL;

changed:
	read_unlock(&idx_pointers_lock);
	brelse(bh);
	*err = -EAGAIN;
	goto no_block;
failure:
	*err = -EIO;
no_block:
	return p;
}

static int alloc_index_branch(struct inode *index_inode,
			     int num,
			     int *offsets,
			     IDXIndirect *branch)
{
	int n = 0;
	int i;

	int parent = minix_new_block(index_inode);

	branch[0].key = cpu_to_index_block(parent);
	if (parent) for (n = 1; n < num; n++) {
		struct buffer_head *bh;
		/* Allocate the next block */
		int nr = minix_new_block(index_inode);
		if (!nr)
			break;
		branch[n].key = cpu_to_index_block(nr);
		bh = sb_getblk(index_inode->i_sb, parent);
		lock_buffer(bh);
		memset(bh->b_data, 0, bh->b_size);
		branch[n].bh = bh;
		branch[n].p = (index_block_t*) bh->b_data + offsets[n];
		*branch[n].p = branch[n].key;
		set_buffer_uptodate(bh);
		unlock_buffer(bh);
		mark_buffer_dirty_inode(bh, index_inode);
		parent = nr;
	}
	if (n == num)
		return 0;

	/* Allocation failed, free what we already allocated */
	for (i = 1; i < n; i++)
		bforget(branch[i].bh);
	for (i = 0; i < n; i++){
		minix_free_block(index_inode, index_block_to_cpu(branch[i].key));
	}
		
	return -ENOSPC;
}

static inline int splice_index_branch(struct inode *index_inode,
				     IDXIndirect chain[IDXDEPTH],
				     IDXIndirect *where,
				     int num)
{
	int i;
	write_lock(&idx_pointers_lock);

	/* Verify that place we are splicing to is still there and vacant */
	if (!verify_index_chain(chain, where-1) || *where->p)
		goto changed;

	*where->p = where->key;

	write_unlock(&idx_pointers_lock);

	/* We are done with atomic stuff, now do the rest of housekeeping */

	/* had we spliced it onto indirect block? */
	if (where->bh)
		mark_buffer_dirty_inode(where->bh, index_inode);

	return 0;

changed:
	write_unlock(&idx_pointers_lock);
	for (i = 1; i < num; i++)
		bforget(where[i].bh);
	for (i = 0; i < num; i++){
		minix_free_block(index_inode, index_block_to_cpu(where[i].key));
	}
		
	return -EAGAIN;
}

static int get_index_block(struct inode * index_inode, sector_t block,
			struct buffer_head *bh, int create)
{
	int err = -EIO;
	int offsets[IDXDEPTH];
	IDXIndirect chain[IDXDEPTH];
	IDXIndirect *partial;
	int left;

	int depth = index_block_to_path(index_inode, block, offsets);

	if (depth == 0)
		goto out;

reread:
	partial = get_index_branch(index_inode, depth, offsets, chain, &err);

	/* Simplest case - block found, no allocation needed */
	if (!partial) {
got_it:
		map_bh(bh, index_inode->i_sb, index_block_to_cpu(chain[depth-1].key));
		/* Clean up and exit */
		partial = chain+depth-1; /* the whole chain */
		goto cleanup;
	}

	/* Next simple case - plain lookup or failed read of indirect block */
	if (!create || err == -EIO) {
cleanup:
		while (partial > chain) {
			brelse(partial->bh);
			partial--;
		}
out:
		return err;
	}

	/*
	 * Indirect block might be removed by truncate while we were
	 * reading it. Handling of that case (forget what we've got and
	 * reread) is taken out of the main path.
	 */
	if (err == -EAGAIN)
		goto changed;

	left = (chain + depth) - partial;
	err = alloc_index_branch(index_inode, left, offsets+(partial-chain), partial);
	if (err)
		goto cleanup;

	if (splice_index_branch(index_inode, chain, partial, left) < 0)
		goto changed;

	set_buffer_new(bh);
	goto got_it;

changed:
	while (partial > chain) {
		brelse(partial->bh);
		partial--;
	}
	goto reread;
}

static inline int all_index_zeroes(index_block_t *p, index_block_t *q)
{
	while (p < q)
		if (*p++)
			return 0;
	return 1;
}

static IDXIndirect *find_index_shared(struct inode *index_inode,
				int depth,
				int offsets[IDXDEPTH],
				IDXIndirect chain[IDXDEPTH],
				index_block_t *top)
{
	IDXIndirect *partial, *p;
	int k, err;
	*top = 0;
	for (k = depth; k > 1 && !offsets[k-1]; k--)
		;
	partial = get_index_branch(index_inode, k, offsets, chain, &err);

	write_lock(&idx_pointers_lock);
	if (!partial)
		partial = chain + k-1;
	if (!partial->key && *partial->p) {
		write_unlock(&idx_pointers_lock);
		goto no_top;
	}
	for (p=partial;p>chain && all_index_zeroes((index_block_t*)p->bh->b_data,p->p);p--)
		;
	if (p == chain + k - 1 && p > chain) {
		p->p--;
	} else {
		*top = *p->p;
		*p->p = 0;
	}
	write_unlock(&idx_pointers_lock);

	while(partial > p)
	{
		brelse(partial->bh);
		partial--;
	}
no_top:
	return partial;
}

static inline void free_index_data(struct inode *index_inode, index_block_t *p, index_block_t *q)
{
	unsigned long nr;

	for ( ; p < q ; p++) {
		nr = index_block_to_cpu(*p);
		if (nr) {
			*p = 0;
			minix_free_block(index_inode, nr);
		}
	}
}

static void free_index_branches(struct inode *index_inode, index_block_t *p, index_block_t *q, int depth)
{
	struct buffer_head * bh;
	unsigned long nr;

	if (depth--) {
		for ( ; p < q ; p++) {
			nr = index_block_to_cpu(*p);
			if (!nr)
				continue;
			*p = 0;
			bh = sb_bread(index_inode->i_sb, nr);
			if (!bh)
				continue;
			free_index_branches(index_inode, (index_block_t*)bh->b_data, block_end(bh), depth);
			bforget(bh);
			minix_free_block(index_inode, nr);
		}
	} else
		free_index_data(index_inode, p, q);
}

static inline void index_truncate(struct inode * index_inode)
{
	struct super_block *sb = index_inode->i_sb;
	index_block_t *idata = index_data(index_inode);
	int offsets[IDXDEPTH];
	IDXIndirect chain[IDXDEPTH];
	IDXIndirect *partial;
	index_block_t nr = 0;
	int n;
	int first_whole;
	long iblock;

	iblock = (index_inode->i_size + sb->s_blocksize -1) >> sb->s_blocksize_bits;
	block_truncate_page(index_inode->i_mapping, index_inode->i_size, get_index_block);

	n = index_block_to_path(index_inode, iblock, offsets);
	if (!n)
		return;

	if (n == 1) {
		free_index_data(index_inode, idata+offsets[0], idata + IDXDIRECT);
		first_whole = 0;
		goto do_indirects;
	}

	first_whole = offsets[0] + 1 - IDXDIRECT;
	partial = find_index_shared(index_inode, n, offsets, chain, &nr);
	if (nr) {
		if (partial != chain)
			mark_buffer_dirty_inode(partial->bh, index_inode);
		free_index_branches(index_inode, &nr, &nr+1, (chain+n-1) - partial);
	}
	/* Clear the ends of indirect blocks on the shared branch */
	while (partial > chain) {
		free_index_branches(index_inode, partial->p + 1, block_end(partial->bh),
				(chain+n-1) - partial);
		mark_buffer_dirty_inode(partial->bh, index_inode);
		brelse (partial->bh);
		partial--;
	}
do_indirects:
	/* Kill the remaining (whole) subtrees */
	while (first_whole < IDXDEPTH-1) {
		nr = idata[IDXDIRECT+first_whole];
		if (nr) {
			idata[IDXDIRECT+first_whole] = 0;
			free_index_branches(index_inode, &nr, &nr+1, first_whole+1);
		}
		first_whole++;
	}
}

static inline unsigned index_nblocks(loff_t size, struct super_block *sb)
{
	int k = sb->s_blocksize_bits - 10;
	unsigned blocks, res, direct = IDXDIRECT, i = IDXDEPTH;
	blocks = (size + sb->s_blocksize - 1) >> (BLOCK_SIZE_BITS + k);
	res = blocks;
	while (--i && blocks > direct) {
		blocks -= direct;
		blocks += sb->s_blocksize/sizeof(index_block_t) - 1;
		blocks /= sb->s_blocksize/sizeof(index_block_t);
		res += blocks;
		direct = 1;
	}
	return res;
}

int __minix_get_index_block(struct inode * index_inode, long block,
			struct buffer_head *bh_result, int create)
{
	return get_index_block(index_inode, block, bh_result, create);
}

unsigned minix_index_blocks(loff_t size, struct super_block *sb)
{
	return index_nblocks(size, sb);
}

#endif

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值