Blame gfs2/libgfs2/fs_ops.c

Packit 6ef888
#include "clusterautoconfig.h"
Packit 6ef888
Packit 6ef888
#include <stdio.h>
Packit 6ef888
#include <stdlib.h>
Packit 6ef888
#include <string.h>
Packit 6ef888
#include <stdint.h>
Packit 6ef888
#include <inttypes.h>
Packit 6ef888
#include <sys/types.h>
Packit 6ef888
#include <sys/stat.h>
Packit 6ef888
#include <fcntl.h>
Packit 6ef888
#include <unistd.h>
Packit 6ef888
#include <errno.h>
Packit 6ef888
Packit 6ef888
#include <linux/types.h>
Packit 6ef888
#include "libgfs2.h"
Packit 6ef888
#include "rgrp.h"
Packit 6ef888
Packit 6ef888
static __inline__ uint64_t *metapointer(struct gfs2_buffer_head *bh,
Packit 6ef888
					unsigned int height,
Packit 6ef888
					struct metapath *mp)
Packit 6ef888
{
Packit 6ef888
	unsigned int head_size = (height > 0) ?
Packit 6ef888
		sizeof(struct gfs2_meta_header) : sizeof(struct gfs2_dinode);
Packit 6ef888
Packit 6ef888
	return ((uint64_t *)(bh->b_data + head_size)) + mp->mp_list[height];
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* Detect directory is a stuffed inode */
Packit 6ef888
static int inode_is_stuffed(const struct gfs2_inode *ip)
Packit 6ef888
{
Packit 6ef888
	return !ip->i_di.di_height;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
struct gfs2_inode *lgfs2_inode_get(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_inode *ip;
Packit 6ef888
Packit 6ef888
	ip = calloc(1, sizeof(struct gfs2_inode));
Packit 6ef888
	if (ip == NULL) {
Packit 6ef888
		return NULL;
Packit 6ef888
	}
Packit 6ef888
	gfs2_dinode_in(&ip->i_di, bh->b_data);
Packit 6ef888
	ip->i_bh = bh;
Packit 6ef888
	ip->i_sbd = sdp;
Packit 6ef888
	return ip;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
struct gfs2_inode *lgfs2_inode_read(struct gfs2_sbd *sdp, uint64_t di_addr)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_inode *ip;
Packit 6ef888
	struct gfs2_buffer_head *bh = bread(sdp, di_addr);
Packit 6ef888
	if (bh == NULL) {
Packit 6ef888
		return NULL;
Packit 6ef888
	}
Packit 6ef888
	ip = lgfs2_inode_get(sdp, bh);
Packit 6ef888
	if (ip == NULL) {
Packit 6ef888
		brelse(bh);
Packit 6ef888
		return NULL;
Packit 6ef888
	}
Packit 6ef888
	ip->bh_owned = 1; /* We did the bread so we own the bh */
Packit 6ef888
	return ip;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
struct gfs2_inode *is_system_inode(struct gfs2_sbd *sdp, uint64_t block)
Packit 6ef888
{
Packit 6ef888
	int j;
Packit 6ef888
Packit 6ef888
	if (sdp->md.inum && block == sdp->md.inum->i_di.di_num.no_addr)
Packit 6ef888
		return sdp->md.inum;
Packit 6ef888
	if (sdp->md.statfs && block == sdp->md.statfs->i_di.di_num.no_addr)
Packit 6ef888
		return sdp->md.statfs;
Packit 6ef888
	if (sdp->md.jiinode && block == sdp->md.jiinode->i_di.di_num.no_addr)
Packit 6ef888
		return sdp->md.jiinode;
Packit 6ef888
	if (sdp->md.riinode && block == sdp->md.riinode->i_di.di_num.no_addr)
Packit 6ef888
		return sdp->md.riinode;
Packit 6ef888
	if (sdp->md.qinode && block == sdp->md.qinode->i_di.di_num.no_addr)
Packit 6ef888
		return sdp->md.qinode;
Packit 6ef888
	if (sdp->md.pinode && block == sdp->md.pinode->i_di.di_num.no_addr)
Packit 6ef888
		return sdp->md.pinode;
Packit 6ef888
	if (sdp->md.rooti && block == sdp->md.rooti->i_di.di_num.no_addr)
Packit 6ef888
		return sdp->md.rooti;
Packit 6ef888
	if (sdp->master_dir && block == sdp->master_dir->i_di.di_num.no_addr)
Packit 6ef888
		return sdp->master_dir;
Packit 6ef888
	for (j = 0; j < sdp->md.journals; j++)
Packit 6ef888
		if (sdp->md.journal && sdp->md.journal[j] &&
Packit 6ef888
		    block == sdp->md.journal[j]->i_di.di_num.no_addr)
Packit 6ef888
			return sdp->md.journal[j];
Packit 6ef888
	return NULL;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
void inode_put(struct gfs2_inode **ip_in)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_inode *ip = *ip_in;
Packit 6ef888
	uint64_t block = ip->i_di.di_num.no_addr;
Packit 6ef888
	struct gfs2_sbd *sdp = ip->i_sbd;
Packit 6ef888
Packit 6ef888
	if (ip->i_bh->b_modified) {
Packit 6ef888
		gfs2_dinode_out(&ip->i_di, ip->i_bh->b_data);
Packit 6ef888
		if (!ip->bh_owned && is_system_inode(sdp, block))
Packit 6ef888
			fprintf(stderr, "Warning: Change made to inode "
Packit 6ef888
				"were discarded.\n");
Packit 6ef888
		/* This is for debugging only: a convenient place to set
Packit 6ef888
		   a breakpoint. This means a system inode was modified but
Packit 6ef888
		   not written.  That's not fatal: some places like
Packit 6ef888
		   adjust_inode in gfs2_convert will do this on purpose.
Packit 6ef888
		   It can also point out a coding problem, but we don't
Packit 6ef888
		   want to raise alarm in the users either. */
Packit 6ef888
	}
Packit 6ef888
	if (ip->bh_owned)
Packit 6ef888
		brelse(ip->i_bh);
Packit 6ef888
	ip->i_bh = NULL;
Packit 6ef888
	free(ip);
Packit 6ef888
	*ip_in = NULL; /* make sure the memory isn't accessed again */
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static uint64_t find_free_block(struct rgrp_tree *rgd)
Packit 6ef888
{
Packit 6ef888
	unsigned bm;
Packit 6ef888
	uint64_t blkno = 0;
Packit 6ef888
Packit 6ef888
	if (rgd == NULL || rgd->rg.rg_free == 0) {
Packit 6ef888
		errno = ENOSPC;
Packit 6ef888
		return 0;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	for (bm = 0; bm < rgd->ri.ri_length; bm++) {
Packit 6ef888
		unsigned long blk = 0;
Packit 6ef888
		struct gfs2_bitmap *bits = &rgd->bits[bm];
Packit 6ef888
Packit 6ef888
		blk = gfs2_bitfit((uint8_t *)bits->bi_bh->b_data + bits->bi_offset,
Packit 6ef888
		                  bits->bi_len, blk, GFS2_BLKST_FREE);
Packit 6ef888
		if (blk != BFITNOENT) {
Packit 6ef888
			blkno = blk + (bits->bi_start * GFS2_NBBY) + rgd->ri.ri_data0;
Packit 6ef888
			break;
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
	return blkno;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int blk_alloc_in_rg(struct gfs2_sbd *sdp, unsigned state, struct rgrp_tree *rgd, uint64_t blkno, int dinode)
Packit 6ef888
{
Packit 6ef888
	if (blkno == 0)
Packit 6ef888
		return -1;
Packit 6ef888
Packit 6ef888
	if (gfs2_set_bitmap(rgd, blkno, state))
Packit 6ef888
		return -1;
Packit 6ef888
Packit 6ef888
	if (state == GFS2_BLKST_DINODE) {
Packit 6ef888
		struct gfs_rgrp *gfs1rg = (struct gfs_rgrp *)&rgd->rg;
Packit 6ef888
Packit 6ef888
		if (dinode)
Packit 6ef888
			rgd->rg.rg_dinodes++;
Packit 6ef888
		else if (sdp->gfs1)
Packit 6ef888
			gfs1rg->rg_usedmeta++;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	rgd->rg.rg_free--;
Packit 6ef888
	if (sdp->gfs1)
Packit 6ef888
		gfs_rgrp_out((struct gfs_rgrp *)&rgd->rg, rgd->bits[0].bi_bh);
Packit 6ef888
	else
Packit 6ef888
		gfs2_rgrp_out(&rgd->rg, rgd->bits[0].bi_bh->b_data);
Packit 6ef888
	bmodified(rgd->bits[0].bi_bh);
Packit 6ef888
	sdp->blks_alloced++;
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/**
Packit 6ef888
 * Allocate a block in a bitmap. In order to plan ahead we look for a
Packit 6ef888
 * resource group with blksreq free blocks but only allocate the one block.
Packit 6ef888
 * Returns 0 on success with the allocated block number in *blkno or non-zero otherwise.
Packit 6ef888
 */
Packit 6ef888
static int block_alloc(struct gfs2_sbd *sdp, const uint64_t blksreq, int state, uint64_t *blkno, int dinode)
Packit 6ef888
{
Packit 6ef888
	int ret;
Packit 6ef888
	int release = 0;
Packit 6ef888
	struct rgrp_tree *rgt = NULL;
Packit 6ef888
	struct osi_node *n = NULL;
Packit 6ef888
	uint64_t bn = 0;
Packit 6ef888
Packit 6ef888
	for (n = osi_first(&sdp->rgtree); n; n = osi_next(n)) {
Packit 6ef888
		rgt = (struct rgrp_tree *)n;
Packit 6ef888
		if (rgt->rg.rg_free >= blksreq)
Packit 6ef888
			break;
Packit 6ef888
	}
Packit 6ef888
	if (rgt == NULL)
Packit 6ef888
		return -1;
Packit 6ef888
Packit 6ef888
	if (rgt->bits[0].bi_bh == NULL) {
Packit 6ef888
		if (gfs2_rgrp_read(sdp, rgt))
Packit 6ef888
			return -1;
Packit 6ef888
		release = 1;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	bn = find_free_block(rgt);
Packit 6ef888
	ret = blk_alloc_in_rg(sdp, state, rgt, bn, dinode);
Packit 6ef888
	if (release)
Packit 6ef888
		gfs2_rgrp_relse(rgt);
Packit 6ef888
	*blkno = bn;
Packit 6ef888
	return ret;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
int lgfs2_dinode_alloc(struct gfs2_sbd *sdp, const uint64_t blksreq, uint64_t *blkno)
Packit 6ef888
{
Packit 6ef888
	int ret = block_alloc(sdp, blksreq, GFS2_BLKST_DINODE, blkno, TRUE);
Packit 6ef888
	if (ret == 0)
Packit 6ef888
		sdp->dinodes_alloced++;
Packit 6ef888
	return ret;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
int lgfs2_meta_alloc(struct gfs2_inode *ip, uint64_t *blkno)
Packit 6ef888
{
Packit 6ef888
	int ret = block_alloc(ip->i_sbd, 1,
Packit 6ef888
			      ip->i_sbd->gfs1 ? GFS2_BLKST_DINODE :
Packit 6ef888
			      GFS2_BLKST_USED, blkno, FALSE);
Packit 6ef888
	if (ret == 0) {
Packit 6ef888
		ip->i_di.di_goal_meta = *blkno;
Packit 6ef888
		bmodified(ip->i_bh);
Packit 6ef888
	}
Packit 6ef888
	return ret;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static __inline__ void buffer_clear_tail(struct gfs2_sbd *sdp,
Packit 6ef888
					 struct gfs2_buffer_head *bh, int head)
Packit 6ef888
{
Packit 6ef888
	memset(bh->b_data + head, 0, sdp->bsize - head);
Packit 6ef888
	bmodified(bh);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static __inline__ void
Packit 6ef888
buffer_copy_tail(struct gfs2_sbd *sdp,
Packit 6ef888
		 struct gfs2_buffer_head *to_bh, int to_head,
Packit 6ef888
		 struct gfs2_buffer_head *from_bh, int from_head)
Packit 6ef888
{
Packit 6ef888
	memcpy(to_bh->b_data + to_head, from_bh->b_data + from_head,
Packit 6ef888
	       sdp->bsize - from_head);
Packit 6ef888
	memset(to_bh->b_data + sdp->bsize + to_head - from_head, 0,
Packit 6ef888
	       from_head - to_head);
Packit 6ef888
	bmodified(to_bh);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
void unstuff_dinode(struct gfs2_inode *ip)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_sbd *sdp = ip->i_sbd;
Packit 6ef888
	struct gfs2_buffer_head *bh;
Packit 6ef888
	uint64_t block = 0;
Packit 6ef888
	int isdir = S_ISDIR(ip->i_di.di_mode) || is_gfs_dir(&ip->i_di);
Packit 6ef888
Packit 6ef888
	if (ip->i_di.di_size) {
Packit 6ef888
		if (lgfs2_meta_alloc(ip, &block))
Packit 6ef888
			exit(1);
Packit 6ef888
		if (isdir) {
Packit 6ef888
			struct gfs2_meta_header mh;
Packit 6ef888
Packit 6ef888
			bh = bget(sdp, block);
Packit 6ef888
			mh.mh_magic = GFS2_MAGIC;
Packit 6ef888
			mh.mh_type = GFS2_METATYPE_JD;
Packit 6ef888
			mh.mh_format = GFS2_FORMAT_JD;
Packit 6ef888
			gfs2_meta_header_out(&mh, bh->b_data);
Packit 6ef888
Packit 6ef888
			buffer_copy_tail(sdp, bh,
Packit 6ef888
					 sizeof(struct gfs2_meta_header),
Packit 6ef888
					 ip->i_bh, sizeof(struct gfs2_dinode));
Packit 6ef888
Packit 6ef888
			bmodified(bh);
Packit 6ef888
			brelse(bh);
Packit 6ef888
		} else {
Packit 6ef888
			bh = bget(sdp, block);
Packit 6ef888
Packit 6ef888
			buffer_copy_tail(sdp, bh, 0,
Packit 6ef888
					 ip->i_bh, sizeof(struct gfs2_dinode));
Packit 6ef888
			brelse(bh);
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	buffer_clear_tail(sdp, ip->i_bh, sizeof(struct gfs2_dinode));
Packit 6ef888
Packit 6ef888
	if (ip->i_di.di_size) {
Packit 6ef888
		*(uint64_t *)(ip->i_bh->b_data + sizeof(struct gfs2_dinode)) = cpu_to_be64(block);
Packit 6ef888
		/* no need: bmodified(ip->i_bh); buffer_clear_tail does it */
Packit 6ef888
		ip->i_di.di_blocks++;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	ip->i_di.di_height = 1;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/**
Packit 6ef888
 * Calculate the total number of blocks required by a file containing 'bytes' bytes of data.
Packit 6ef888
 */
Packit 6ef888
uint64_t lgfs2_space_for_data(const struct gfs2_sbd *sdp, const unsigned bsize, const uint64_t bytes)
Packit 6ef888
{
Packit 6ef888
	uint64_t blks = (bytes + bsize - 1) / bsize;
Packit 6ef888
	uint64_t ptrs = blks;
Packit 6ef888
Packit 6ef888
	if (bytes <= bsize - sizeof(struct gfs2_dinode))
Packit 6ef888
		return 1;
Packit 6ef888
Packit 6ef888
	while (ptrs > sdp->sd_diptrs) {
Packit 6ef888
		ptrs = (ptrs + sdp->sd_inptrs - 1) / sdp->sd_inptrs;
Packit 6ef888
		blks += ptrs;
Packit 6ef888
	}
Packit 6ef888
	return blks + 1;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/**
Packit 6ef888
 * Allocate an extent for a file in a resource group's bitmaps.
Packit 6ef888
 * rg: The resource group in which to allocate the extent
Packit 6ef888
 * di_size: The size of the file in bytes
Packit 6ef888
 * ip: A pointer to the inode structure, whose fields will be set appropriately.
Packit 6ef888
 *     If ip->i_di.di_num.no_addr is not 0, the extent search will be skipped and
Packit 6ef888
 *     the file allocated from that address.
Packit 6ef888
 * flags: GFS2_DIF_* flags
Packit 6ef888
 * mode: File mode flags, see creat(2)
Packit 6ef888
 * Returns 0 on success with the contents of ip set accordingly, or non-zero
Packit 6ef888
 * with errno set on error. If errno is ENOSPC then rg does not contain a
Packit 6ef888
 * large enough free extent for the given di_size.
Packit 6ef888
 */
Packit 6ef888
int lgfs2_file_alloc(lgfs2_rgrp_t rg, uint64_t di_size, struct gfs2_inode *ip, uint32_t flags, unsigned mode)
Packit 6ef888
{
Packit 6ef888
	unsigned extlen;
Packit 6ef888
	struct gfs2_dinode *di = &ip->i_di;
Packit 6ef888
	struct gfs2_sbd *sdp = rg->rgrps->sdp;
Packit 6ef888
	struct lgfs2_rbm rbm = { .rgd = rg, .offset = 0, .bii = 0 };
Packit 6ef888
	uint32_t blocks = lgfs2_space_for_data(sdp, sdp->bsize, di_size);
Packit 6ef888
Packit 6ef888
	if (ip->i_di.di_num.no_addr != 0) {
Packit 6ef888
		if (lgfs2_rbm_from_block(&rbm, ip->i_di.di_num.no_addr) != 0)
Packit 6ef888
			return 1;
Packit 6ef888
	} else if (lgfs2_rbm_find(&rbm, GFS2_BLKST_FREE, &blocks) != 0) {
Packit 6ef888
		return 1;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	extlen = lgfs2_alloc_extent(&rbm, GFS2_BLKST_DINODE, blocks);
Packit 6ef888
	if (extlen < blocks) {
Packit 6ef888
		errno = EINVAL;
Packit 6ef888
		return 1;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	ip->i_sbd = sdp;
Packit 6ef888
Packit 6ef888
	di->di_header.mh_magic = GFS2_MAGIC;
Packit 6ef888
	di->di_header.mh_type = GFS2_METATYPE_DI;
Packit 6ef888
	di->di_header.mh_format = GFS2_FORMAT_DI;
Packit 6ef888
	di->di_size = di_size;
Packit 6ef888
	di->di_num.no_addr = lgfs2_rbm_to_block(&rbm;;
Packit 6ef888
	di->di_num.no_formal_ino = sdp->md.next_inum++;
Packit 6ef888
	di->di_mode = mode;
Packit 6ef888
	di->di_nlink = 1;
Packit 6ef888
	di->di_blocks = blocks;
Packit 6ef888
	di->di_atime = di->di_mtime = di->di_ctime = sdp->time;
Packit 6ef888
	di->di_goal_data = di->di_num.no_addr + di->di_blocks - 1;
Packit 6ef888
	di->di_goal_meta = di->di_goal_data - ((di_size + sdp->bsize - 1) / sdp->bsize);
Packit 6ef888
	di->di_height = calc_tree_height(ip, di_size);
Packit 6ef888
	di->di_flags = flags;
Packit 6ef888
Packit 6ef888
	rg->rg.rg_free -= blocks;
Packit 6ef888
	rg->rg.rg_dinodes += 1;
Packit 6ef888
Packit 6ef888
	sdp->dinodes_alloced++;
Packit 6ef888
	sdp->blks_alloced += blocks;
Packit 6ef888
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
unsigned int calc_tree_height(struct gfs2_inode *ip, uint64_t size)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_sbd *sdp = ip->i_sbd;
Packit 6ef888
	uint64_t *arr;
Packit 6ef888
	unsigned int max, height;
Packit 6ef888
Packit 6ef888
	if (ip->i_di.di_size > size)
Packit 6ef888
		size = ip->i_di.di_size;
Packit 6ef888
Packit 6ef888
	if (S_ISDIR(ip->i_di.di_mode)) {
Packit 6ef888
		arr = sdp->sd_jheightsize;
Packit 6ef888
		max = sdp->sd_max_jheight;
Packit 6ef888
	} else {
Packit 6ef888
		arr = sdp->sd_heightsize;
Packit 6ef888
		max = sdp->sd_max_height;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	for (height = 0; height < max; height++)
Packit 6ef888
		if (arr[height] >= size)
Packit 6ef888
			break;
Packit 6ef888
Packit 6ef888
	return height;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
void build_height(struct gfs2_inode *ip, int height)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_sbd *sdp = ip->i_sbd;
Packit 6ef888
	struct gfs2_buffer_head *bh;
Packit 6ef888
	uint64_t block = 0, *bp;
Packit 6ef888
	unsigned int x;
Packit 6ef888
	int new_block;
Packit 6ef888
Packit 6ef888
	while (ip->i_di.di_height < height) {
Packit 6ef888
		new_block = FALSE;
Packit 6ef888
		bp = (uint64_t *)(ip->i_bh->b_data + sizeof(struct gfs2_dinode));
Packit 6ef888
		for (x = 0; x < sdp->sd_diptrs; x++, bp++)
Packit 6ef888
			if (*bp) {
Packit 6ef888
				new_block = TRUE;
Packit 6ef888
				break;
Packit 6ef888
			}
Packit 6ef888
Packit 6ef888
		if (new_block) {
Packit 6ef888
			struct gfs2_meta_header mh;
Packit 6ef888
Packit 6ef888
			if (lgfs2_meta_alloc(ip, &block))
Packit 6ef888
				exit(1);
Packit 6ef888
			bh = bget(sdp, block);
Packit 6ef888
			mh.mh_magic = GFS2_MAGIC;
Packit 6ef888
			mh.mh_type = GFS2_METATYPE_IN;
Packit 6ef888
			mh.mh_format = GFS2_FORMAT_IN;
Packit 6ef888
			gfs2_meta_header_out(&mh, bh->b_data);
Packit 6ef888
			buffer_copy_tail(sdp, bh,
Packit 6ef888
					 sizeof(struct gfs2_meta_header),
Packit 6ef888
					 ip->i_bh, sizeof(struct gfs2_dinode));
Packit 6ef888
			bmodified(bh);
Packit 6ef888
			brelse(bh);
Packit 6ef888
		}
Packit 6ef888
Packit 6ef888
		buffer_clear_tail(sdp, ip->i_bh, sizeof(struct gfs2_dinode));
Packit 6ef888
Packit 6ef888
		if (new_block) {
Packit 6ef888
			*(uint64_t *)(ip->i_bh->b_data + sizeof(struct gfs2_dinode)) = cpu_to_be64(block);
Packit 6ef888
			/* no need: bmodified(ip->i_bh);*/
Packit 6ef888
			ip->i_di.di_blocks++;
Packit 6ef888
		}
Packit 6ef888
Packit 6ef888
		ip->i_di.di_height++;
Packit 6ef888
	}
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
void find_metapath(struct gfs2_inode *ip, uint64_t block, struct metapath *mp)
Packit 6ef888
{
Packit 6ef888
	const uint32_t inptrs = ip->i_sbd->sd_inptrs;
Packit 6ef888
	unsigned int i = ip->i_di.di_height;
Packit 6ef888
Packit 6ef888
	memset(mp, 0, sizeof(struct metapath));
Packit 6ef888
	while (i--) {
Packit 6ef888
		mp->mp_list[i] = block % inptrs;
Packit 6ef888
		block /= inptrs;
Packit 6ef888
	}
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
void lookup_block(struct gfs2_inode *ip, struct gfs2_buffer_head *bh,
Packit 6ef888
		  unsigned int height, struct metapath *mp,
Packit 6ef888
		  int create, int *new, uint64_t *block)
Packit 6ef888
{
Packit 6ef888
	uint64_t *ptr = metapointer(bh, height, mp);
Packit 6ef888
Packit 6ef888
	if (*ptr) {
Packit 6ef888
		*block = be64_to_cpu(*ptr);
Packit 6ef888
		return;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	*block = 0;
Packit 6ef888
Packit 6ef888
	if (!create)
Packit 6ef888
		return;
Packit 6ef888
Packit 6ef888
	if (lgfs2_meta_alloc(ip, block))
Packit 6ef888
		return;
Packit 6ef888
	*ptr = cpu_to_be64(*block);
Packit 6ef888
	bmodified(bh);
Packit 6ef888
	ip->i_di.di_blocks++;
Packit 6ef888
	bmodified(ip->i_bh);
Packit 6ef888
Packit 6ef888
	*new = 1;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
void block_map(struct gfs2_inode *ip, uint64_t lblock, int *new,
Packit 6ef888
	       uint64_t *dblock, uint32_t *extlen, int prealloc)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_sbd *sdp = ip->i_sbd;
Packit 6ef888
	struct gfs2_buffer_head *bh;
Packit 6ef888
	struct metapath mp;
Packit 6ef888
	int create = *new;
Packit 6ef888
	unsigned int bsize;
Packit 6ef888
	unsigned int height;
Packit 6ef888
	unsigned int end_of_metadata;
Packit 6ef888
	unsigned int x;
Packit 6ef888
Packit 6ef888
	*new = 0;
Packit 6ef888
	*dblock = 0;
Packit 6ef888
	if (extlen)
Packit 6ef888
		*extlen = 0;
Packit 6ef888
Packit 6ef888
	if (inode_is_stuffed(ip)) {
Packit 6ef888
		if (!lblock) {
Packit 6ef888
			*dblock = ip->i_di.di_num.no_addr;
Packit 6ef888
			if (extlen)
Packit 6ef888
				*extlen = 1;
Packit 6ef888
		}
Packit 6ef888
		return;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	bsize = (S_ISDIR(ip->i_di.di_mode)) ? sdp->sd_jbsize : sdp->bsize;
Packit 6ef888
Packit 6ef888
	height = calc_tree_height(ip, (lblock + 1) * bsize);
Packit 6ef888
	if (ip->i_di.di_height < height) {
Packit 6ef888
		if (!create)
Packit 6ef888
			return;
Packit 6ef888
Packit 6ef888
		build_height(ip, height);
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	find_metapath(ip, lblock, &mp);
Packit 6ef888
	end_of_metadata = ip->i_di.di_height - 1;
Packit 6ef888
Packit 6ef888
	bh = ip->i_bh;
Packit 6ef888
Packit 6ef888
	for (x = 0; x < end_of_metadata; x++) {
Packit 6ef888
		lookup_block(ip, bh, x, &mp, create, new, dblock);
Packit 6ef888
		if (bh != ip->i_bh)
Packit 6ef888
			brelse(bh);
Packit 6ef888
		if (!*dblock)
Packit 6ef888
			return;
Packit 6ef888
Packit 6ef888
		if (*new) {
Packit 6ef888
			struct gfs2_meta_header mh;
Packit 6ef888
			bh = bget(sdp, *dblock);
Packit 6ef888
			mh.mh_magic = GFS2_MAGIC;
Packit 6ef888
			mh.mh_type = GFS2_METATYPE_IN;
Packit 6ef888
			mh.mh_format = GFS2_FORMAT_IN;
Packit 6ef888
			gfs2_meta_header_out(&mh, bh->b_data);
Packit 6ef888
			bmodified(bh);
Packit 6ef888
		} else {
Packit 6ef888
			if (*dblock == ip->i_di.di_num.no_addr)
Packit 6ef888
				bh = ip->i_bh;
Packit 6ef888
			else
Packit 6ef888
				bh = bread(sdp, *dblock);
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	if (!prealloc)
Packit 6ef888
		lookup_block(ip, bh, end_of_metadata, &mp, create, new, dblock);
Packit 6ef888
Packit 6ef888
	if (extlen && *dblock) {
Packit 6ef888
		*extlen = 1;
Packit 6ef888
Packit 6ef888
		if (!*new) {
Packit 6ef888
			uint64_t tmp_dblock;
Packit 6ef888
			int tmp_new;
Packit 6ef888
			unsigned int nptrs;
Packit 6ef888
Packit 6ef888
			nptrs = (end_of_metadata) ? sdp->sd_inptrs : sdp->sd_diptrs;
Packit 6ef888
Packit 6ef888
			while (++mp.mp_list[end_of_metadata] < nptrs) {
Packit 6ef888
				lookup_block(ip, bh, end_of_metadata, &mp, FALSE, &tmp_new,
Packit 6ef888
							 &tmp_dblock);
Packit 6ef888
Packit 6ef888
				if (*dblock + *extlen != tmp_dblock)
Packit 6ef888
					break;
Packit 6ef888
Packit 6ef888
				(*extlen)++;
Packit 6ef888
			}
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	if (bh != ip->i_bh)
Packit 6ef888
		brelse(bh);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static void
Packit 6ef888
copy2mem(struct gfs2_buffer_head *bh, void **buf, unsigned int offset,
Packit 6ef888
	 unsigned int size)
Packit 6ef888
{
Packit 6ef888
	char **p = (char **)buf;
Packit 6ef888
Packit 6ef888
	if (bh)
Packit 6ef888
		memcpy(*p, bh->b_data + offset, size);
Packit 6ef888
	else
Packit 6ef888
		memset(*p, 0, size);
Packit 6ef888
Packit 6ef888
	*p += size;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
int gfs2_readi(struct gfs2_inode *ip, void *buf,
Packit 6ef888
			   uint64_t offset, unsigned int size)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_sbd *sdp = ip->i_sbd;
Packit 6ef888
	struct gfs2_buffer_head *bh;
Packit 6ef888
	uint64_t lblock, dblock;
Packit 6ef888
	unsigned int o;
Packit 6ef888
	uint32_t extlen = 0;
Packit 6ef888
	unsigned int amount;
Packit 6ef888
	int not_new = 0;
Packit 6ef888
	int isdir = !!(S_ISDIR(ip->i_di.di_mode));
Packit 6ef888
	int journaled = ip->i_di.di_flags & GFS2_DIF_JDATA;
Packit 6ef888
	int copied = 0;
Packit 6ef888
Packit 6ef888
	if (offset >= ip->i_di.di_size)
Packit 6ef888
		return 0;
Packit 6ef888
Packit 6ef888
	if ((offset + size) > ip->i_di.di_size)
Packit 6ef888
		size = ip->i_di.di_size - offset;
Packit 6ef888
Packit 6ef888
	if (!size)
Packit 6ef888
		return 0;
Packit 6ef888
Packit 6ef888
	if ((sdp->gfs1 && journaled) || (!sdp->gfs1 && isdir)) {
Packit 6ef888
		lblock = offset;
Packit 6ef888
		o = lblock % sdp->sd_jbsize;
Packit 6ef888
		lblock /= sdp->sd_jbsize;
Packit 6ef888
	} else {
Packit 6ef888
		lblock = offset >> sdp->sd_sb.sb_bsize_shift;
Packit 6ef888
		o = offset & (sdp->bsize - 1);
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	if (inode_is_stuffed(ip))
Packit 6ef888
		o += sizeof(struct gfs2_dinode);
Packit 6ef888
	else if ((sdp->gfs1 && journaled) || (!sdp->gfs1 && isdir))
Packit 6ef888
		o += sizeof(struct gfs2_meta_header);
Packit 6ef888
Packit 6ef888
	while (copied < size) {
Packit 6ef888
		amount = size - copied;
Packit 6ef888
		if (amount > sdp->bsize - o)
Packit 6ef888
			amount = sdp->bsize - o;
Packit 6ef888
Packit 6ef888
		if (!extlen) {
Packit 6ef888
			if (sdp->gfs1)
Packit 6ef888
				gfs1_block_map(ip, lblock, &not_new, &dblock,
Packit 6ef888
					       &extlen, FALSE);
Packit 6ef888
			else
Packit 6ef888
				block_map(ip, lblock, &not_new, &dblock,
Packit 6ef888
					  &extlen, FALSE);
Packit 6ef888
		}
Packit 6ef888
Packit 6ef888
		if (dblock) {
Packit 6ef888
			if (dblock == ip->i_di.di_num.no_addr)
Packit 6ef888
				bh = ip->i_bh;
Packit 6ef888
			else
Packit 6ef888
				bh = bread(sdp, dblock);
Packit 6ef888
			dblock++;
Packit 6ef888
			extlen--;
Packit 6ef888
		} else
Packit 6ef888
			bh = NULL;
Packit 6ef888
Packit 6ef888
		copy2mem(bh, &buf, o, amount);
Packit 6ef888
		if (bh && bh != ip->i_bh)
Packit 6ef888
			brelse(bh);
Packit 6ef888
Packit 6ef888
		copied += amount;
Packit 6ef888
		lblock++;
Packit 6ef888
Packit 6ef888
		if (sdp->gfs1)
Packit 6ef888
			o = (journaled) ? sizeof(struct gfs2_meta_header) : 0;
Packit 6ef888
		else
Packit 6ef888
			o = (isdir) ? sizeof(struct gfs2_meta_header) : 0;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	return copied;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static void copy_from_mem(struct gfs2_buffer_head *bh, void **buf,
Packit 6ef888
			  unsigned int offset, unsigned int size)
Packit 6ef888
{
Packit 6ef888
	char **p = (char **)buf;
Packit 6ef888
Packit 6ef888
	memcpy(bh->b_data + offset, *p, size);
Packit 6ef888
	bmodified(bh);
Packit 6ef888
	*p += size;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
int __gfs2_writei(struct gfs2_inode *ip, void *buf,
Packit 6ef888
		  uint64_t offset, unsigned int size, int resize)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_sbd *sdp = ip->i_sbd;
Packit 6ef888
	struct gfs2_buffer_head *bh;
Packit 6ef888
	uint64_t lblock, dblock;
Packit 6ef888
	unsigned int o;
Packit 6ef888
	uint32_t extlen = 0;
Packit 6ef888
	unsigned int amount;
Packit 6ef888
	int new;
Packit 6ef888
	int isdir = !!(S_ISDIR(ip->i_di.di_mode));
Packit 6ef888
	const uint64_t start = offset;
Packit 6ef888
	int copied = 0;
Packit 6ef888
Packit 6ef888
	if (!size)
Packit 6ef888
		return 0;
Packit 6ef888
Packit 6ef888
	if (inode_is_stuffed(ip) &&
Packit 6ef888
	    ((start + size) > (sdp->bsize - sizeof(struct gfs2_dinode))))
Packit 6ef888
		unstuff_dinode(ip);
Packit 6ef888
Packit 6ef888
	if (isdir) {
Packit 6ef888
		lblock = offset;
Packit 6ef888
		o = lblock % sdp->sd_jbsize;
Packit 6ef888
		lblock /= sdp->sd_jbsize;
Packit 6ef888
	} else {
Packit 6ef888
		lblock = offset >> sdp->sd_sb.sb_bsize_shift;
Packit 6ef888
		o = offset & (sdp->bsize - 1);
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	if (inode_is_stuffed(ip))
Packit 6ef888
		o += sizeof(struct gfs2_dinode);
Packit 6ef888
	else if (isdir)
Packit 6ef888
		o += sizeof(struct gfs2_meta_header);
Packit 6ef888
Packit 6ef888
	while (copied < size) {
Packit 6ef888
		amount = size - copied;
Packit 6ef888
		if (amount > sdp->bsize - o)
Packit 6ef888
			amount = sdp->bsize - o;
Packit 6ef888
Packit 6ef888
		if (!extlen) {
Packit 6ef888
			new = TRUE;
Packit 6ef888
			block_map(ip, lblock, &new, &dblock, &extlen, FALSE);
Packit 6ef888
		}
Packit 6ef888
Packit 6ef888
		if (new) {
Packit 6ef888
			bh = bget(sdp, dblock);
Packit 6ef888
			if (isdir) {
Packit 6ef888
				struct gfs2_meta_header mh;
Packit 6ef888
				mh.mh_magic = GFS2_MAGIC;
Packit 6ef888
				mh.mh_type = GFS2_METATYPE_JD;
Packit 6ef888
				mh.mh_format = GFS2_FORMAT_JD;
Packit 6ef888
				gfs2_meta_header_out(&mh, bh->b_data);
Packit 6ef888
				bmodified(bh);
Packit 6ef888
			}
Packit 6ef888
		} else {
Packit 6ef888
			if (dblock == ip->i_di.di_num.no_addr)
Packit 6ef888
				bh = ip->i_bh;
Packit 6ef888
			else
Packit 6ef888
				bh = bread(sdp, dblock);
Packit 6ef888
		}
Packit 6ef888
		copy_from_mem(bh, &buf, o, amount);
Packit 6ef888
		if (bh != ip->i_bh)
Packit 6ef888
			brelse(bh);
Packit 6ef888
Packit 6ef888
		copied += amount;
Packit 6ef888
		lblock++;
Packit 6ef888
		dblock++;
Packit 6ef888
		extlen--;
Packit 6ef888
Packit 6ef888
		o = (isdir) ? sizeof(struct gfs2_meta_header) : 0;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	if (resize && ip->i_di.di_size < start + copied) {
Packit 6ef888
		bmodified(ip->i_bh);
Packit 6ef888
		ip->i_di.di_size = start + copied;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	return copied;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
struct gfs2_buffer_head *get_file_buf(struct gfs2_inode *ip, uint64_t lbn,
Packit 6ef888
				      int prealloc)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_sbd *sdp = ip->i_sbd;
Packit 6ef888
	uint64_t dbn;
Packit 6ef888
	int new = TRUE;
Packit 6ef888
Packit 6ef888
	if (inode_is_stuffed(ip))
Packit 6ef888
		unstuff_dinode(ip);
Packit 6ef888
Packit 6ef888
	block_map(ip, lbn, &new, &dbn, NULL, prealloc);
Packit 6ef888
	if (!dbn) {
Packit 6ef888
		fprintf(stderr, "get_file_buf\n");
Packit 6ef888
		exit(1);
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	if (!prealloc && new &&
Packit 6ef888
	    ip->i_di.di_size < (lbn + 1) << sdp->sd_sb.sb_bsize_shift) {
Packit 6ef888
		bmodified(ip->i_bh);
Packit 6ef888
		ip->i_di.di_size = (lbn + 1) << sdp->sd_sb.sb_bsize_shift;
Packit 6ef888
	}
Packit 6ef888
	if (dbn == ip->i_di.di_num.no_addr)
Packit 6ef888
		return ip->i_bh;
Packit 6ef888
	else
Packit 6ef888
		return bread(sdp, dbn);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
int gfs2_dirent_first(struct gfs2_inode *dip, struct gfs2_buffer_head *bh,
Packit 6ef888
					  struct gfs2_dirent **dent)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_meta_header *h = (struct gfs2_meta_header *)bh->b_data;
Packit 6ef888
Packit 6ef888
	if (be32_to_cpu(h->mh_type) == GFS2_METATYPE_LF) {
Packit 6ef888
		*dent = (struct gfs2_dirent *)(bh->b_data + sizeof(struct gfs2_leaf));
Packit 6ef888
		return IS_LEAF;
Packit 6ef888
	} else {
Packit 6ef888
		*dent = (struct gfs2_dirent *)(bh->b_data + sizeof(struct gfs2_dinode));
Packit 6ef888
		return IS_DINODE;
Packit 6ef888
	}
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
int gfs2_dirent_next(struct gfs2_inode *dip, struct gfs2_buffer_head *bh,
Packit 6ef888
					 struct gfs2_dirent **dent)
Packit 6ef888
{
Packit 6ef888
	char *bh_end;
Packit 6ef888
	uint16_t cur_rec_len;
Packit 6ef888
Packit 6ef888
	bh_end = bh->b_data + dip->i_sbd->bsize;
Packit 6ef888
	cur_rec_len = be16_to_cpu((*dent)->de_rec_len);
Packit 6ef888
Packit 6ef888
	if (cur_rec_len == 0 || (char *)(*dent) + cur_rec_len >= bh_end)
Packit 6ef888
		return -ENOENT;
Packit 6ef888
Packit 6ef888
	*dent = (struct gfs2_dirent *)((char *)(*dent) + cur_rec_len);
Packit 6ef888
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/**
Packit 6ef888
 * Allocate a gfs2 dirent
Packit 6ef888
 * Returns 0 on success, with *dent_out pointing to the new dirent,
Packit 6ef888
 * or -1 on failure, with errno set
Packit 6ef888
 */
Packit 6ef888
static int dirent_alloc(struct gfs2_inode *dip, struct gfs2_buffer_head *bh,
Packit 6ef888
			int name_len, struct gfs2_dirent **dent_out)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_dirent *dent, *new;
Packit 6ef888
	unsigned int rec_len = GFS2_DIRENT_SIZE(name_len);
Packit 6ef888
	unsigned int entries = 0, offset = 0;
Packit 6ef888
	int type;
Packit 6ef888
Packit 6ef888
	type = gfs2_dirent_first(dip, bh, &dent);
Packit 6ef888
Packit 6ef888
	if (type == IS_LEAF) {
Packit 6ef888
		struct gfs2_leaf *leaf = (struct gfs2_leaf *)bh->b_data;
Packit 6ef888
		entries = be16_to_cpu(leaf->lf_entries);
Packit 6ef888
		offset = sizeof(struct gfs2_leaf);
Packit 6ef888
	} else {
Packit 6ef888
		struct gfs2_dinode *dinode = (struct gfs2_dinode *)bh->b_data;
Packit 6ef888
		entries = be32_to_cpu(dinode->di_entries);
Packit 6ef888
		offset = sizeof(struct gfs2_dinode);
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	if (!entries) {
Packit 6ef888
		dent->de_rec_len = cpu_to_be16(dip->i_sbd->bsize - offset);
Packit 6ef888
		dent->de_name_len = cpu_to_be16(name_len);
Packit 6ef888
		bmodified(bh);
Packit 6ef888
		*dent_out = dent;
Packit 6ef888
		dip->i_di.di_entries++;
Packit 6ef888
		bmodified(dip->i_bh);
Packit 6ef888
		return 0;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	do {
Packit 6ef888
		uint16_t cur_rec_len;
Packit 6ef888
		uint16_t cur_name_len;
Packit 6ef888
		uint16_t new_rec_len;
Packit 6ef888
Packit 6ef888
		cur_rec_len = be16_to_cpu(dent->de_rec_len);
Packit 6ef888
		cur_name_len = be16_to_cpu(dent->de_name_len);
Packit 6ef888
Packit 6ef888
		if ((!dent->de_inum.no_formal_ino && cur_rec_len >= rec_len) ||
Packit 6ef888
		    (cur_rec_len >= GFS2_DIRENT_SIZE(cur_name_len) + rec_len)) {
Packit 6ef888
Packit 6ef888
			if (dent->de_inum.no_formal_ino) {
Packit 6ef888
				new = (struct gfs2_dirent *)((char *)dent +
Packit 6ef888
							    GFS2_DIRENT_SIZE(cur_name_len));
Packit 6ef888
				memset(new, 0, sizeof(struct gfs2_dirent));
Packit 6ef888
Packit 6ef888
				new->de_rec_len = cpu_to_be16(cur_rec_len -
Packit 6ef888
					  GFS2_DIRENT_SIZE(cur_name_len));
Packit 6ef888
				new->de_name_len = cpu_to_be16(name_len);
Packit 6ef888
Packit 6ef888
				new_rec_len = be16_to_cpu(new->de_rec_len);
Packit 6ef888
				dent->de_rec_len = cpu_to_be16(cur_rec_len - new_rec_len);
Packit 6ef888
Packit 6ef888
				*dent_out = new;
Packit 6ef888
				bmodified(bh);
Packit 6ef888
				dip->i_di.di_entries++;
Packit 6ef888
				bmodified(dip->i_bh);
Packit 6ef888
				return 0;
Packit 6ef888
			}
Packit 6ef888
Packit 6ef888
			dent->de_name_len = cpu_to_be16(name_len);
Packit 6ef888
Packit 6ef888
			*dent_out = dent;
Packit 6ef888
			bmodified(bh);
Packit 6ef888
			dip->i_di.di_entries++;
Packit 6ef888
			bmodified(dip->i_bh);
Packit 6ef888
			return 0;
Packit 6ef888
		}
Packit 6ef888
	} while (gfs2_dirent_next(dip, bh, &dent) == 0);
Packit 6ef888
Packit 6ef888
	errno = ENOSPC;
Packit 6ef888
	return -1;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
void dirent2_del(struct gfs2_inode *dip, struct gfs2_buffer_head *bh,
Packit 6ef888
		 struct gfs2_dirent *prev, struct gfs2_dirent *cur)
Packit 6ef888
{
Packit 6ef888
	uint16_t cur_rec_len, prev_rec_len;
Packit 6ef888
Packit 6ef888
	bmodified(bh);
Packit 6ef888
	if (gfs2_check_meta(bh, GFS2_METATYPE_LF) == 0) {
Packit 6ef888
		struct gfs2_leaf *lf = (struct gfs2_leaf *)bh->b_data;
Packit 6ef888
Packit 6ef888
		lf->lf_entries = be16_to_cpu(lf->lf_entries) - 1;
Packit 6ef888
		lf->lf_entries = cpu_to_be16(lf->lf_entries);
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	if (dip->i_di.di_entries) {
Packit 6ef888
		bmodified(dip->i_bh);
Packit 6ef888
		dip->i_di.di_entries--;
Packit 6ef888
	}
Packit 6ef888
	if (!prev) {
Packit 6ef888
		cur->de_inum.no_addr = 0;
Packit 6ef888
		cur->de_inum.no_formal_ino = 0;
Packit 6ef888
		return;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	prev_rec_len = be16_to_cpu(prev->de_rec_len);
Packit 6ef888
	cur_rec_len = be16_to_cpu(cur->de_rec_len);
Packit 6ef888
Packit 6ef888
	prev_rec_len += cur_rec_len;
Packit 6ef888
	prev->de_rec_len = cpu_to_be16(prev_rec_len);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
int lgfs2_get_leaf_ptr(struct gfs2_inode *dip, const uint32_t lindex, uint64_t *ptr)
Packit 6ef888
{
Packit 6ef888
	uint64_t leaf_no;
Packit 6ef888
	int count = gfs2_readi(dip, (char *)&leaf_no, lindex * sizeof(uint64_t), sizeof(uint64_t));
Packit 6ef888
	if (count != sizeof(uint64_t))
Packit 6ef888
		return -1;
Packit 6ef888
Packit 6ef888
	*ptr = be64_to_cpu(leaf_no);
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
void dir_split_leaf(struct gfs2_inode *dip, uint32_t start, uint64_t leaf_no,
Packit 6ef888
		    struct gfs2_buffer_head *obh)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_buffer_head *nbh;
Packit 6ef888
	struct gfs2_leaf *nleaf, *oleaf;
Packit 6ef888
	struct gfs2_dirent *dent, *prev = NULL, *next = NULL, *new;
Packit 6ef888
	uint32_t len, half_len, divider;
Packit 6ef888
	uint64_t bn, *lp;
Packit 6ef888
	uint32_t name_len;
Packit 6ef888
	int x, moved = FALSE;
Packit 6ef888
	int count;
Packit 6ef888
Packit 6ef888
	if (lgfs2_meta_alloc(dip, &bn))
Packit 6ef888
		exit(1);
Packit 6ef888
	nbh = bget(dip->i_sbd, bn);
Packit 6ef888
	{
Packit 6ef888
		struct gfs2_meta_header mh;
Packit 6ef888
		mh.mh_magic = GFS2_MAGIC;
Packit 6ef888
		mh.mh_type = GFS2_METATYPE_LF;
Packit 6ef888
		mh.mh_format = GFS2_FORMAT_LF;
Packit 6ef888
		gfs2_meta_header_out(&mh, nbh->b_data);
Packit 6ef888
		bmodified(nbh);
Packit 6ef888
		buffer_clear_tail(dip->i_sbd, nbh,
Packit 6ef888
				  sizeof(struct gfs2_meta_header));
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	nleaf = (struct gfs2_leaf *)nbh->b_data;
Packit 6ef888
	nleaf->lf_dirent_format = cpu_to_be32(GFS2_FORMAT_DE);
Packit 6ef888
Packit 6ef888
	oleaf = (struct gfs2_leaf *)obh->b_data;
Packit 6ef888
Packit 6ef888
	len = 1 << (dip->i_di.di_depth - be16_to_cpu(oleaf->lf_depth));
Packit 6ef888
	half_len = len >> 1;
Packit 6ef888
Packit 6ef888
	lp = calloc(1, half_len * sizeof(uint64_t));
Packit 6ef888
	if (lp == NULL) {
Packit 6ef888
		fprintf(stderr, "Out of memory in %s\n", __FUNCTION__);
Packit 6ef888
		exit(-1);
Packit 6ef888
	}
Packit 6ef888
	for (x = 0; x < half_len; x++)
Packit 6ef888
		lp[x] = cpu_to_be64(bn);
Packit 6ef888
Packit 6ef888
	if (dip->i_sbd->gfs1)
Packit 6ef888
		count = gfs1_writei(dip, (char *)lp, start * sizeof(uint64_t),
Packit 6ef888
				    half_len * sizeof(uint64_t));
Packit 6ef888
	else
Packit 6ef888
		count = gfs2_writei(dip, (char *)lp, start * sizeof(uint64_t),
Packit 6ef888
				    half_len * sizeof(uint64_t));
Packit 6ef888
	if (count != half_len * sizeof(uint64_t)) {
Packit 6ef888
		fprintf(stderr, "dir_split_leaf (2)\n");
Packit 6ef888
		exit(1);
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	free(lp);
Packit 6ef888
Packit 6ef888
	divider = (start + half_len) << (32 - dip->i_di.di_depth);
Packit 6ef888
Packit 6ef888
	gfs2_dirent_first(dip, obh, &dent);
Packit 6ef888
Packit 6ef888
	do {
Packit 6ef888
		next = dent;
Packit 6ef888
		if (gfs2_dirent_next(dip, obh, &next))
Packit 6ef888
			next = NULL;
Packit 6ef888
Packit 6ef888
		if (dent->de_inum.no_formal_ino &&
Packit 6ef888
		    be32_to_cpu(dent->de_hash) < divider) {
Packit 6ef888
			name_len = be16_to_cpu(dent->de_name_len);
Packit 6ef888
Packit 6ef888
			if (dirent_alloc(dip, nbh, name_len, &new)) {
Packit 6ef888
				fprintf(stderr, "dir_split_leaf (3)\n");
Packit 6ef888
				exit(1);
Packit 6ef888
			}
Packit 6ef888
Packit 6ef888
			new->de_inum = dent->de_inum;
Packit 6ef888
			new->de_hash = dent->de_hash;
Packit 6ef888
			new->de_type = dent->de_type;
Packit 6ef888
			memcpy((char *)(new + 1), (char *)(dent + 1), name_len);
Packit 6ef888
Packit 6ef888
			nleaf->lf_entries = be16_to_cpu(nleaf->lf_entries) + 1;
Packit 6ef888
			nleaf->lf_entries = cpu_to_be16(nleaf->lf_entries);
Packit 6ef888
Packit 6ef888
			dirent2_del(dip, obh, prev, dent);
Packit 6ef888
Packit 6ef888
			if (!prev)
Packit 6ef888
				prev = dent;
Packit 6ef888
Packit 6ef888
			moved = TRUE;
Packit 6ef888
		} else
Packit 6ef888
			prev = dent;
Packit 6ef888
Packit 6ef888
		dent = next;
Packit 6ef888
	} while (dent);
Packit 6ef888
Packit 6ef888
	if (!moved) {
Packit 6ef888
		if (dirent_alloc(dip, nbh, 0, &new)) {
Packit 6ef888
			fprintf(stderr, "dir_split_leaf (4)\n");
Packit 6ef888
			exit(1);
Packit 6ef888
		}
Packit 6ef888
		new->de_inum.no_formal_ino = 0;
Packit 6ef888
		/* Don't count the sentinel dirent as an entry */
Packit 6ef888
		dip->i_di.di_entries--;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	oleaf->lf_depth = be16_to_cpu(oleaf->lf_depth) + 1;
Packit 6ef888
	oleaf->lf_depth = cpu_to_be16(oleaf->lf_depth);
Packit 6ef888
	nleaf->lf_depth = oleaf->lf_depth;
Packit 6ef888
Packit 6ef888
#ifdef GFS2_HAS_LEAF_HINTS
Packit 6ef888
	nleaf->lf_inode = cpu_to_be64(dip->i_di.di_num.no_addr);
Packit 6ef888
#endif
Packit 6ef888
	dip->i_di.di_blocks++;
Packit 6ef888
	bmodified(dip->i_bh);
Packit 6ef888
Packit 6ef888
	bmodified(obh); /* Need to do this in case nothing was moved */
Packit 6ef888
	bmodified(nbh);
Packit 6ef888
	brelse(nbh);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static void dir_double_exhash(struct gfs2_inode *dip)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_sbd *sdp = dip->i_sbd;
Packit 6ef888
	uint64_t *buf;
Packit 6ef888
	uint64_t *from, *to;
Packit 6ef888
	uint64_t block;
Packit 6ef888
	int x;
Packit 6ef888
	int count;
Packit 6ef888
Packit 6ef888
	buf = calloc(1, 3 * sdp->sd_hash_bsize);
Packit 6ef888
	if (buf == NULL) {
Packit 6ef888
		fprintf(stderr, "Out of memory in %s\n", __FUNCTION__);
Packit 6ef888
		exit(-1);
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	for (block = dip->i_di.di_size >> sdp->sd_hash_bsize_shift; block--;) {
Packit 6ef888
		count = gfs2_readi(dip, (char *)buf,
Packit 6ef888
			      block * sdp->sd_hash_bsize,
Packit 6ef888
			      sdp->sd_hash_bsize);
Packit 6ef888
		if (count != sdp->sd_hash_bsize) {
Packit 6ef888
			fprintf(stderr, "dir_double_exhash (1)\n");
Packit 6ef888
			exit(1);
Packit 6ef888
		}
Packit 6ef888
Packit 6ef888
		from = buf;
Packit 6ef888
		to = (uint64_t *)((char *)buf + sdp->sd_hash_bsize);
Packit 6ef888
Packit 6ef888
		for (x = sdp->sd_hash_ptrs; x--; from++) {
Packit 6ef888
			*to++ = *from;
Packit 6ef888
			*to++ = *from;
Packit 6ef888
		}
Packit 6ef888
Packit 6ef888
		if (sdp->gfs1)
Packit 6ef888
			count = gfs1_writei(dip, (char *)buf +
Packit 6ef888
					    sdp->sd_hash_bsize,
Packit 6ef888
					    block * sdp->bsize, sdp->bsize);
Packit 6ef888
		else
Packit 6ef888
			count = gfs2_writei(dip, (char *)buf +
Packit 6ef888
					    sdp->sd_hash_bsize,
Packit 6ef888
					    block * sdp->bsize, sdp->bsize);
Packit 6ef888
		if (count != sdp->bsize) {
Packit 6ef888
			fprintf(stderr, "dir_double_exhash (2)\n");
Packit 6ef888
			exit(1);
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	free(buf);
Packit 6ef888
Packit 6ef888
	dip->i_di.di_depth++;
Packit 6ef888
	bmodified(dip->i_bh);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/**
Packit 6ef888
 * get_leaf - Get leaf
Packit 6ef888
 * @dip:
Packit 6ef888
 * @leaf_no:
Packit 6ef888
 * @bh_out:
Packit 6ef888
 *
Packit 6ef888
 * Returns: 0 on success, error code otherwise
Packit 6ef888
 */
Packit 6ef888
Packit 6ef888
int gfs2_get_leaf(struct gfs2_inode *dip, uint64_t leaf_no,
Packit 6ef888
				  struct gfs2_buffer_head **bhp)
Packit 6ef888
{
Packit 6ef888
	int error = 0;
Packit 6ef888
Packit 6ef888
	*bhp = bread(dip->i_sbd, leaf_no);
Packit 6ef888
	error = gfs2_check_meta(*bhp, GFS2_METATYPE_LF);
Packit 6ef888
	if(error)
Packit 6ef888
		brelse(*bhp);
Packit 6ef888
	return error;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/**
Packit 6ef888
 * get_first_leaf - Get first leaf
Packit 6ef888
 * @dip: The GFS2 inode
Packit 6ef888
 * @index:
Packit 6ef888
 * @bh_out:
Packit 6ef888
 *
Packit 6ef888
 * Returns: 0 on success, error code otherwise
Packit 6ef888
 */
Packit 6ef888
Packit 6ef888
static int get_first_leaf(struct gfs2_inode *dip, uint32_t lindex, struct gfs2_buffer_head **bh_out)
Packit 6ef888
{
Packit 6ef888
	uint64_t leaf_no;
Packit 6ef888
Packit 6ef888
	if (lgfs2_get_leaf_ptr(dip, lindex, &leaf_no) != 0)
Packit 6ef888
		return -1;
Packit 6ef888
	*bh_out = bread(dip->i_sbd, leaf_no);
Packit 6ef888
	if (*bh_out == NULL)
Packit 6ef888
		return -1;
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/**
Packit 6ef888
 * get_next_leaf - Get next leaf
Packit 6ef888
 * @dip: The GFS2 inode
Packit 6ef888
 * @bh_in: The buffer
Packit 6ef888
 * @bh_out:
Packit 6ef888
 *
Packit 6ef888
 * Returns: 0 on success, error code otherwise
Packit 6ef888
 */
Packit 6ef888
Packit 6ef888
static int get_next_leaf(struct gfs2_inode *dip,struct gfs2_buffer_head *bh_in,
Packit 6ef888
						 struct gfs2_buffer_head **bh_out)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_leaf *leaf;
Packit 6ef888
Packit 6ef888
	leaf = (struct gfs2_leaf *)bh_in->b_data;
Packit 6ef888
Packit 6ef888
	if (!leaf->lf_next)
Packit 6ef888
		return -1;
Packit 6ef888
	/* Check for a leaf that points to itself as "next" */
Packit 6ef888
	if (be64_to_cpu(leaf->lf_next) == bh_in->b_blocknr)
Packit 6ef888
		return -1;
Packit 6ef888
	*bh_out = bread(dip->i_sbd, be64_to_cpu(leaf->lf_next));
Packit 6ef888
	if (*bh_out == NULL)
Packit 6ef888
		return -ENOENT;
Packit 6ef888
	/* Check for a leaf pointing to a non-leaf */
Packit 6ef888
	if (gfs2_check_meta(*bh_out, GFS2_METATYPE_LF)) {
Packit 6ef888
		brelse(*bh_out);
Packit 6ef888
		*bh_out = NULL;
Packit 6ef888
		return -ENOENT;
Packit 6ef888
	}
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int dir_e_add(struct gfs2_inode *dip, const char *filename, int len,
Packit 6ef888
		      struct gfs2_inum *inum, unsigned int type)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_buffer_head *bh, *nbh;
Packit 6ef888
	struct gfs2_leaf *leaf, *nleaf;
Packit 6ef888
	struct gfs2_dirent *dent;
Packit 6ef888
	uint32_t lindex, llen;
Packit 6ef888
	uint32_t hash;
Packit 6ef888
	uint64_t leaf_no, bn;
Packit 6ef888
	int err = 0;
Packit 6ef888
Packit 6ef888
	hash = gfs2_disk_hash(filename, len);
Packit 6ef888
restart:
Packit 6ef888
	/* Have to kludge because (hash >> 32) gives hash for some reason. */
Packit 6ef888
	if (dip->i_di.di_depth)
Packit 6ef888
		lindex = hash >> (32 - dip->i_di.di_depth);
Packit 6ef888
	else
Packit 6ef888
		lindex = 0;
Packit 6ef888
Packit 6ef888
	err = lgfs2_get_leaf_ptr(dip, lindex, &leaf_no);
Packit 6ef888
	if (err)
Packit 6ef888
		return err;
Packit 6ef888
Packit 6ef888
	for (;;) {
Packit 6ef888
		bh = bread(dip->i_sbd, leaf_no);
Packit 6ef888
		leaf = (struct gfs2_leaf *)bh->b_data;
Packit 6ef888
Packit 6ef888
		if (dirent_alloc(dip, bh, len, &dent)) {
Packit 6ef888
Packit 6ef888
			if (be16_to_cpu(leaf->lf_depth) < dip->i_di.di_depth) {
Packit 6ef888
				llen = 1 << (dip->i_di.di_depth -
Packit 6ef888
					     be16_to_cpu(leaf->lf_depth));
Packit 6ef888
				dir_split_leaf(dip, lindex & ~(llen - 1),
Packit 6ef888
					       leaf_no, bh);
Packit 6ef888
				brelse(bh);
Packit 6ef888
				goto restart;
Packit 6ef888
Packit 6ef888
			} else if (dip->i_di.di_depth < GFS2_DIR_MAX_DEPTH) {
Packit 6ef888
				brelse(bh);
Packit 6ef888
				dir_double_exhash(dip);
Packit 6ef888
				goto restart;
Packit 6ef888
Packit 6ef888
			} else if (leaf->lf_next) {
Packit 6ef888
				leaf_no = be64_to_cpu(leaf->lf_next);
Packit 6ef888
				brelse(bh);
Packit 6ef888
				continue;
Packit 6ef888
Packit 6ef888
			} else {
Packit 6ef888
				struct gfs2_meta_header mh;
Packit 6ef888
Packit 6ef888
				if (lgfs2_meta_alloc(dip, &bn))
Packit 6ef888
					exit(1);
Packit 6ef888
				nbh = bget(dip->i_sbd, bn);
Packit 6ef888
				mh.mh_magic = GFS2_MAGIC;
Packit 6ef888
				mh.mh_type = GFS2_METATYPE_LF;
Packit 6ef888
				mh.mh_format = GFS2_FORMAT_LF;
Packit 6ef888
				gfs2_meta_header_out(&mh, nbh->b_data);
Packit 6ef888
				bmodified(nbh);
Packit 6ef888
Packit 6ef888
				leaf->lf_next = cpu_to_be64(bn);
Packit 6ef888
Packit 6ef888
				nleaf = (struct gfs2_leaf *)nbh->b_data;
Packit 6ef888
				nleaf->lf_depth = leaf->lf_depth;
Packit 6ef888
				nleaf->lf_dirent_format = cpu_to_be32(GFS2_FORMAT_DE);
Packit 6ef888
#ifdef GFS2_HAS_LEAF_HINTS
Packit 6ef888
				nleaf->lf_inode = cpu_to_be64(dip->i_di.di_num.no_addr);
Packit 6ef888
#endif
Packit 6ef888
				err = dirent_alloc(dip, nbh, len, &dent);
Packit 6ef888
				if (err)
Packit 6ef888
					return err;
Packit 6ef888
				dip->i_di.di_blocks++;
Packit 6ef888
				bmodified(dip->i_bh);
Packit 6ef888
				bmodified(bh);
Packit 6ef888
				brelse(bh);
Packit 6ef888
				bh = nbh;
Packit 6ef888
				leaf = nleaf;
Packit 6ef888
			}
Packit 6ef888
		}
Packit 6ef888
Packit 6ef888
		gfs2_inum_out(inum, (char *)&dent->de_inum);
Packit 6ef888
		dent->de_hash = cpu_to_be32(hash);
Packit 6ef888
		dent->de_type = cpu_to_be16(type);
Packit 6ef888
		memcpy((char *)(dent + 1), filename, len);
Packit 6ef888
Packit 6ef888
		leaf->lf_entries = be16_to_cpu(leaf->lf_entries) + 1;
Packit 6ef888
		leaf->lf_entries = cpu_to_be16(leaf->lf_entries);
Packit 6ef888
Packit 6ef888
		bmodified(bh);
Packit 6ef888
		brelse(bh);
Packit 6ef888
		return err;
Packit 6ef888
	}
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static void dir_make_exhash(struct gfs2_inode *dip)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_sbd *sdp = dip->i_sbd;
Packit 6ef888
	struct gfs2_dirent *dent;
Packit 6ef888
	struct gfs2_buffer_head *bh;
Packit 6ef888
	struct gfs2_leaf *leaf;
Packit 6ef888
	int y;
Packit 6ef888
	uint32_t x;
Packit 6ef888
	uint64_t *lp, bn;
Packit 6ef888
Packit 6ef888
	if (lgfs2_meta_alloc(dip, &bn))
Packit 6ef888
		exit(1);
Packit 6ef888
	bh = bget(sdp, bn);
Packit 6ef888
	{
Packit 6ef888
		struct gfs2_meta_header mh;
Packit 6ef888
		mh.mh_magic = GFS2_MAGIC;
Packit 6ef888
		mh.mh_type = GFS2_METATYPE_LF;
Packit 6ef888
		mh.mh_format = GFS2_FORMAT_LF;
Packit 6ef888
		gfs2_meta_header_out(&mh, bh->b_data);
Packit 6ef888
		bmodified(bh);
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	leaf = (struct gfs2_leaf *)bh->b_data;
Packit 6ef888
	leaf->lf_dirent_format = cpu_to_be32(GFS2_FORMAT_DE);
Packit 6ef888
	leaf->lf_entries = cpu_to_be16(dip->i_di.di_entries);
Packit 6ef888
#ifdef GFS2_HAS_LEAF_HINTS
Packit 6ef888
	leaf->lf_inode = cpu_to_be64(dip->i_di.di_num.no_addr);
Packit 6ef888
#endif
Packit 6ef888
	buffer_copy_tail(sdp, bh, sizeof(struct gfs2_leaf),
Packit 6ef888
			 dip->i_bh, sizeof(struct gfs2_dinode));
Packit 6ef888
Packit 6ef888
	x = 0;
Packit 6ef888
	gfs2_dirent_first(dip, bh, &dent);
Packit 6ef888
Packit 6ef888
	do {
Packit 6ef888
		if (!dent->de_inum.no_formal_ino)
Packit 6ef888
			continue;
Packit 6ef888
		if (++x == dip->i_di.di_entries)
Packit 6ef888
			break;
Packit 6ef888
	} while (gfs2_dirent_next(dip, bh, &dent) == 0);
Packit 6ef888
Packit 6ef888
	dent->de_rec_len = be16_to_cpu(dent->de_rec_len);
Packit 6ef888
	dent->de_rec_len = cpu_to_be16(dent->de_rec_len +
Packit 6ef888
		sizeof(struct gfs2_dinode) - sizeof(struct gfs2_leaf));
Packit 6ef888
Packit 6ef888
	/* no need to: bmodified(bh); (buffer_copy_tail does it) */
Packit 6ef888
	brelse(bh);
Packit 6ef888
Packit 6ef888
	buffer_clear_tail(sdp, dip->i_bh, sizeof(struct gfs2_dinode));
Packit 6ef888
Packit 6ef888
	lp = (uint64_t *)(dip->i_bh->b_data + sizeof(struct gfs2_dinode));
Packit 6ef888
Packit 6ef888
	for (x = sdp->sd_hash_ptrs; x--; lp++)
Packit 6ef888
		*lp = cpu_to_be64(bn);
Packit 6ef888
Packit 6ef888
	dip->i_di.di_size = sdp->bsize / 2;
Packit 6ef888
	dip->i_di.di_blocks++;
Packit 6ef888
	dip->i_di.di_flags |= GFS2_DIF_EXHASH;
Packit 6ef888
	dip->i_di.di_payload_format = 0;
Packit 6ef888
	/* no need: bmodified(dip->i_bh); buffer_clear_tail does it. */
Packit 6ef888
Packit 6ef888
	for (x = sdp->sd_hash_ptrs, y = -1; x; x >>= 1, y++) ;
Packit 6ef888
	dip->i_di.di_depth = y;
Packit 6ef888
Packit 6ef888
	gfs2_dinode_out(&dip->i_di, dip->i_bh->b_data);
Packit 6ef888
	bwrite(dip->i_bh);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int dir_l_add(struct gfs2_inode *dip, const char *filename, int len,
Packit 6ef888
		      struct gfs2_inum *inum, unsigned int type)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_dirent *dent;
Packit 6ef888
	int err = 0;
Packit 6ef888
Packit 6ef888
	if (dirent_alloc(dip, dip->i_bh, len, &dent)) {
Packit 6ef888
		dir_make_exhash(dip);
Packit 6ef888
		err = dir_e_add(dip, filename, len, inum, type);
Packit 6ef888
		return err;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	gfs2_inum_out(inum, (char *)&dent->de_inum);
Packit 6ef888
	dent->de_hash = gfs2_disk_hash(filename, len);
Packit 6ef888
	dent->de_hash = cpu_to_be32(dent->de_hash);
Packit 6ef888
	dent->de_type = cpu_to_be16(type);
Packit 6ef888
	memcpy((char *)(dent + 1), filename, len);
Packit 6ef888
	bmodified(dip->i_bh);
Packit 6ef888
	return err;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
int dir_add(struct gfs2_inode *dip, const char *filename, int len,
Packit 6ef888
	     struct gfs2_inum *inum, unsigned int type)
Packit 6ef888
{
Packit 6ef888
	int err = 0;
Packit 6ef888
	if (dip->i_di.di_flags & GFS2_DIF_EXHASH)
Packit 6ef888
		err = dir_e_add(dip, filename, len, inum, type);
Packit 6ef888
	else
Packit 6ef888
		err = dir_l_add(dip, filename, len, inum, type);
Packit 6ef888
	return err;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int __init_dinode(struct gfs2_sbd *sdp, struct gfs2_buffer_head **bhp, struct gfs2_inum *inum,
Packit 6ef888
                         unsigned int mode, uint32_t flags, struct gfs2_inum *parent, int gfs1)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_buffer_head *bh;
Packit 6ef888
	struct gfs2_dinode di = {{0}};
Packit 6ef888
	int is_dir;
Packit 6ef888
Packit 6ef888
	if (gfs1)
Packit 6ef888
		is_dir = (IF2DT(mode) == GFS_FILE_DIR);
Packit 6ef888
	else
Packit 6ef888
		is_dir = S_ISDIR(mode);
Packit 6ef888
Packit 6ef888
	errno = EINVAL;
Packit 6ef888
	if (bhp == NULL)
Packit 6ef888
		return 1;
Packit 6ef888
Packit 6ef888
	if (*bhp == NULL) {
Packit 6ef888
		*bhp = bget(sdp, inum->no_addr);
Packit 6ef888
		if (*bhp == NULL)
Packit 6ef888
			return 1;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	bh = *bhp;
Packit 6ef888
Packit 6ef888
	di.di_header.mh_magic = GFS2_MAGIC;
Packit 6ef888
	di.di_header.mh_type = GFS2_METATYPE_DI;
Packit 6ef888
	di.di_header.mh_format = GFS2_FORMAT_DI;
Packit 6ef888
	di.di_num = *inum;
Packit 6ef888
	di.di_mode = mode;
Packit 6ef888
	di.di_nlink = 1;
Packit 6ef888
	di.di_blocks = 1;
Packit 6ef888
	di.di_atime = di.di_mtime = di.di_ctime = sdp->time;
Packit 6ef888
	di.di_goal_meta = di.di_goal_data = bh->b_blocknr;
Packit 6ef888
	di.di_flags = flags;
Packit 6ef888
Packit 6ef888
	if (is_dir) {
Packit 6ef888
		struct gfs2_dirent de1, de2;
Packit 6ef888
Packit 6ef888
		memset(&de1, 0, sizeof(struct gfs2_dirent));
Packit 6ef888
		de1.de_inum = di.di_num;
Packit 6ef888
		de1.de_hash = gfs2_disk_hash(".", 1);
Packit 6ef888
		de1.de_rec_len = GFS2_DIRENT_SIZE(1);
Packit 6ef888
		de1.de_name_len = 1;
Packit 6ef888
		de1.de_type = (gfs1 ? GFS_FILE_DIR : IF2DT(S_IFDIR));
Packit 6ef888
Packit 6ef888
		memset(&de2, 0, sizeof(struct gfs2_dirent));
Packit 6ef888
		de2.de_inum = *parent;
Packit 6ef888
		de2.de_hash = gfs2_disk_hash("..", 2);
Packit 6ef888
		de2.de_rec_len = sdp->bsize - sizeof(struct gfs2_dinode) - de1.de_rec_len;
Packit 6ef888
		de2.de_name_len = 2;
Packit 6ef888
		de2.de_type = (gfs1 ? GFS_FILE_DIR : IF2DT(S_IFDIR));
Packit 6ef888
Packit 6ef888
		gfs2_dirent_out(&de1, bh->b_data + sizeof(struct gfs2_dinode));
Packit 6ef888
		memcpy(bh->b_data +
Packit 6ef888
		       sizeof(struct gfs2_dinode) +
Packit 6ef888
		       sizeof(struct gfs2_dirent),
Packit 6ef888
		       ".", 1);
Packit 6ef888
		gfs2_dirent_out(&de2, bh->b_data + sizeof(struct gfs2_dinode) + de1.de_rec_len);
Packit 6ef888
		memcpy(bh->b_data +
Packit 6ef888
		       sizeof(struct gfs2_dinode) +
Packit 6ef888
		       de1.de_rec_len +
Packit 6ef888
		       sizeof(struct gfs2_dirent),
Packit 6ef888
		       "..", 2);
Packit 6ef888
Packit 6ef888
		di.di_nlink = 2;
Packit 6ef888
		di.di_size = sdp->bsize - sizeof(struct gfs2_dinode);
Packit 6ef888
		di.di_flags |= GFS2_DIF_JDATA;
Packit 6ef888
		di.di_payload_format = GFS2_FORMAT_DE;
Packit 6ef888
		di.di_entries = 2;
Packit 6ef888
	}
Packit 6ef888
	gfs2_dinode_out(&di, bh->b_data);
Packit 6ef888
	bmodified(bh);
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
int init_dinode(struct gfs2_sbd *sdp, struct gfs2_buffer_head **bhp, struct gfs2_inum *inum,
Packit 6ef888
                unsigned int mode, uint32_t flags, struct gfs2_inum *parent)
Packit 6ef888
{
Packit 6ef888
	return __init_dinode(sdp, bhp, inum, mode, flags, parent, 0);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static void lgfs2_fill_indir(char *start, char *end, uint64_t ptr0, unsigned n, unsigned *p)
Packit 6ef888
{
Packit 6ef888
	char *bp;
Packit 6ef888
	memset(start, 0, end - start);
Packit 6ef888
	for (bp = start; bp < end && *p < n; bp += sizeof(uint64_t)) {
Packit 6ef888
		uint64_t pn = ptr0 + *p;
Packit 6ef888
		*(uint64_t *)bp = cpu_to_be64(pn);
Packit 6ef888
		(*p)++;
Packit 6ef888
	}
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/**
Packit 6ef888
 * Calculate and write the indirect blocks for a single-extent file of a given
Packit 6ef888
 * size.
Packit 6ef888
 * ip: The inode for which to write indirect blocks, with fields already set
Packit 6ef888
 *     appropriately (see lgfs2_file_alloc).
Packit 6ef888
 * Returns 0 on success or non-zero with errno set on failure.
Packit 6ef888
 */
Packit 6ef888
int lgfs2_write_filemeta(struct gfs2_inode *ip)
Packit 6ef888
{
Packit 6ef888
	unsigned height = 0;
Packit 6ef888
	struct metapath mp;
Packit 6ef888
	struct gfs2_sbd *sdp = ip->i_sbd;
Packit 6ef888
	uint64_t dblocks = (ip->i_di.di_size + sdp->bsize - 1) / sdp->bsize;
Packit 6ef888
	uint64_t ptr0 = ip->i_di.di_num.no_addr + 1;
Packit 6ef888
	unsigned ptrs = 1;
Packit 6ef888
	struct gfs2_meta_header mh = {
Packit 6ef888
		.mh_magic = GFS2_MAGIC,
Packit 6ef888
		.mh_type = GFS2_METATYPE_IN,
Packit 6ef888
		.mh_format = GFS2_FORMAT_IN,
Packit 6ef888
	};
Packit 6ef888
	struct gfs2_buffer_head *bh = bget(sdp, ip->i_di.di_num.no_addr);
Packit 6ef888
	if (bh == NULL)
Packit 6ef888
		return 1;
Packit 6ef888
Packit 6ef888
	/* Using find_metapath() to find the last data block in the file will
Packit 6ef888
	   effectively give a remainder for the number of pointers at each
Packit 6ef888
	   height. Just need to add 1 to convert ptr index to quantity later. */
Packit 6ef888
	find_metapath(ip, dblocks - 1, &mp);
Packit 6ef888
Packit 6ef888
	for (height = 0; height < ip->i_di.di_height; height++) {
Packit 6ef888
		unsigned p;
Packit 6ef888
		/* The number of pointers in this height will be the number of
Packit 6ef888
		   full indirect blocks pointed to by the previous height
Packit 6ef888
		   multiplied by the pointer capacity of an indirect block,
Packit 6ef888
		   plus the remainder which find_metapath() gave us. */
Packit 6ef888
		ptrs = ((ptrs - 1) * sdp->sd_inptrs) + mp.mp_list[height] + 1;
Packit 6ef888
Packit 6ef888
		for (p = 0; p < ptrs; bh->b_blocknr++) {
Packit 6ef888
			char *start = bh->b_data;
Packit 6ef888
			if (height == 0) {
Packit 6ef888
				start += sizeof(struct gfs2_dinode);
Packit 6ef888
				gfs2_dinode_out(&ip->i_di, bh->b_data);
Packit 6ef888
			} else {
Packit 6ef888
				start += sizeof(struct gfs2_meta_header);
Packit 6ef888
				gfs2_meta_header_out(&mh, bh->b_data);
Packit 6ef888
			}
Packit 6ef888
			lgfs2_fill_indir(start, bh->b_data + sdp->bsize, ptr0, ptrs, &p);
Packit 6ef888
			if (bwrite(bh)) {
Packit 6ef888
				free(bh);
Packit 6ef888
				return 1;
Packit 6ef888
			}
Packit 6ef888
		}
Packit 6ef888
		ptr0 += ptrs;
Packit 6ef888
	}
Packit 6ef888
	free(bh);
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static struct gfs2_inode *__createi(struct gfs2_inode *dip,
Packit 6ef888
				    const char *filename, unsigned int mode,
Packit 6ef888
				    uint32_t flags, int if_gfs1)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_sbd *sdp = dip->i_sbd;
Packit 6ef888
	uint64_t bn;
Packit 6ef888
	struct gfs2_inum inum;
Packit 6ef888
	struct gfs2_buffer_head *bh = NULL;
Packit 6ef888
	struct gfs2_inode *ip;
Packit 6ef888
	int err = 0;
Packit 6ef888
	int is_dir;
Packit 6ef888
Packit 6ef888
	gfs2_lookupi(dip, filename, strlen(filename), &ip);
Packit 6ef888
	if (!ip) {
Packit 6ef888
		err = lgfs2_dinode_alloc(sdp, 1, &bn);
Packit 6ef888
		if (err != 0)
Packit 6ef888
			return NULL;
Packit 6ef888
Packit 6ef888
		if (if_gfs1)
Packit 6ef888
			inum.no_formal_ino = bn;
Packit 6ef888
		else
Packit 6ef888
			inum.no_formal_ino = sdp->md.next_inum++;
Packit 6ef888
		inum.no_addr = bn;
Packit 6ef888
Packit 6ef888
		err = dir_add(dip, filename, strlen(filename), &inum, IF2DT(mode));
Packit 6ef888
		if (err)
Packit 6ef888
			return NULL;
Packit 6ef888
Packit 6ef888
		if (if_gfs1)
Packit 6ef888
			is_dir = (IF2DT(mode) == GFS_FILE_DIR);
Packit 6ef888
		else
Packit 6ef888
			is_dir = S_ISDIR(mode);
Packit 6ef888
		if (is_dir) {
Packit 6ef888
			bmodified(dip->i_bh);
Packit 6ef888
			dip->i_di.di_nlink++;
Packit 6ef888
		}
Packit 6ef888
Packit 6ef888
		err = __init_dinode(sdp, &bh, &inum, mode, flags, &dip->i_di.di_num, if_gfs1);
Packit 6ef888
		if (err != 0)
Packit 6ef888
			return NULL;
Packit 6ef888
Packit 6ef888
		ip = lgfs2_inode_get(sdp, bh);
Packit 6ef888
		if (ip == NULL)
Packit 6ef888
			return NULL;
Packit 6ef888
		bmodified(bh);
Packit 6ef888
	}
Packit 6ef888
	ip->bh_owned = 1;
Packit 6ef888
	return ip;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
struct gfs2_inode *createi(struct gfs2_inode *dip, const char *filename,
Packit 6ef888
			   unsigned int mode, uint32_t flags)
Packit 6ef888
{
Packit 6ef888
	return __createi(dip, filename, mode, flags, 0);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
struct gfs2_inode *gfs_createi(struct gfs2_inode *dip, const char *filename,
Packit 6ef888
			   unsigned int mode, uint32_t flags)
Packit 6ef888
{
Packit 6ef888
	return __createi(dip, filename, mode, flags, 1);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/**
Packit 6ef888
 * gfs2_filecmp - Compare two filenames
Packit 6ef888
 * @file1: The first filename
Packit 6ef888
 * @file2: The second filename
Packit 6ef888
 * @len_of_file2: The length of the second file
Packit 6ef888
 *
Packit 6ef888
 * This routine compares two filenames and returns 1 if they are equal.
Packit 6ef888
 *
Packit 6ef888
 * Returns: 1 if the files are the same, otherwise 0.
Packit 6ef888
 */
Packit 6ef888
Packit 6ef888
static int gfs2_filecmp(const char *file1, const char *file2, int len_of_file2)
Packit 6ef888
{
Packit 6ef888
	if (strlen(file1) != len_of_file2)
Packit 6ef888
		return 0;
Packit 6ef888
	if (memcmp(file1, file2, len_of_file2))
Packit 6ef888
		return 0;
Packit 6ef888
	return 1;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/**
Packit 6ef888
 * leaf_search
Packit 6ef888
 * @bh:
Packit 6ef888
 * @id:
Packit 6ef888
 * @dent_out:
Packit 6ef888
 * @dent_prev:
Packit 6ef888
 *
Packit 6ef888
 * Returns:
Packit 6ef888
 */
Packit 6ef888
static int leaf_search(struct gfs2_inode *dip, struct gfs2_buffer_head *bh, 
Packit 6ef888
		       const char *filename, int len,
Packit 6ef888
		       struct gfs2_dirent **dent_out,
Packit 6ef888
		       struct gfs2_dirent **dent_prev)
Packit 6ef888
{
Packit 6ef888
	uint32_t hash;
Packit 6ef888
	struct gfs2_dirent *dent, *prev = NULL;
Packit 6ef888
	unsigned int entries = 0, x = 0;
Packit 6ef888
	int type;
Packit 6ef888
Packit 6ef888
	type = gfs2_dirent_first(dip, bh, &dent);
Packit 6ef888
Packit 6ef888
	if (type == IS_LEAF){
Packit 6ef888
		struct gfs2_leaf *leaf = (struct gfs2_leaf *)bh->b_data;
Packit 6ef888
		entries = be16_to_cpu(leaf->lf_entries);
Packit 6ef888
	} else if (type == IS_DINODE)
Packit 6ef888
		entries = dip->i_di.di_entries;
Packit 6ef888
	else
Packit 6ef888
		return -1;
Packit 6ef888
Packit 6ef888
	hash = gfs2_disk_hash(filename, len);
Packit 6ef888
Packit 6ef888
	do{
Packit 6ef888
		if (!dent->de_inum.no_formal_ino){
Packit 6ef888
			prev = dent;
Packit 6ef888
			continue;
Packit 6ef888
		}
Packit 6ef888
		
Packit 6ef888
		if (be32_to_cpu(dent->de_hash) == hash &&
Packit 6ef888
			gfs2_filecmp(filename, (char *)(dent + 1),
Packit 6ef888
				     be16_to_cpu(dent->de_name_len))) {
Packit 6ef888
			*dent_out = dent;
Packit 6ef888
			if (dent_prev)
Packit 6ef888
				*dent_prev = prev;
Packit 6ef888
			return 0;
Packit 6ef888
		}
Packit 6ef888
		
Packit 6ef888
		if(x >= entries)
Packit 6ef888
			return -1;
Packit 6ef888
		x++;
Packit 6ef888
		prev = dent;
Packit 6ef888
	} while (gfs2_dirent_next(dip, bh, &dent) == 0);
Packit 6ef888
Packit 6ef888
	return -ENOENT;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/**
Packit 6ef888
 * linked_leaf_search - Linked leaf search
Packit 6ef888
 * @dip: The GFS2 inode
Packit 6ef888
 * @id:
Packit 6ef888
 * @dent_out:
Packit 6ef888
 * @dent_prev:
Packit 6ef888
 * @bh_out:
Packit 6ef888
 *
Packit 6ef888
 * Returns: 0 on sucess, error code otherwise
Packit 6ef888
 */
Packit 6ef888
Packit 6ef888
static int linked_leaf_search(struct gfs2_inode *dip, const char *filename,
Packit 6ef888
			      int len, struct gfs2_dirent **dent_out,
Packit 6ef888
			      struct gfs2_buffer_head **bh_out)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_buffer_head *bh = NULL, *bh_next;
Packit 6ef888
	uint32_t hsize, lindex;
Packit 6ef888
	uint32_t hash;
Packit 6ef888
	int error = 0;
Packit 6ef888
Packit 6ef888
	hsize = 1 << dip->i_di.di_depth;
Packit 6ef888
	if(hsize * sizeof(uint64_t) != dip->i_di.di_size)
Packit 6ef888
		return -1;
Packit 6ef888
Packit 6ef888
	/*  Figure out the address of the leaf node.  */
Packit 6ef888
Packit 6ef888
	hash = gfs2_disk_hash(filename, len);
Packit 6ef888
	lindex = hash >> (32 - dip->i_di.di_depth);
Packit 6ef888
Packit 6ef888
	error = get_first_leaf(dip, lindex, &bh_next);
Packit 6ef888
	if (error)
Packit 6ef888
		return error;
Packit 6ef888
	if (bh_next == NULL)
Packit 6ef888
		return errno;
Packit 6ef888
Packit 6ef888
	/*  Find the entry  */
Packit 6ef888
	do{
Packit 6ef888
		if (bh && bh != dip->i_bh)
Packit 6ef888
			brelse(bh);
Packit 6ef888
Packit 6ef888
		bh = bh_next;
Packit 6ef888
Packit 6ef888
		error = leaf_search(dip, bh, filename, len, dent_out, NULL);
Packit 6ef888
		switch (error){
Packit 6ef888
		case 0:
Packit 6ef888
			*bh_out = bh;
Packit 6ef888
			return 0;
Packit 6ef888
Packit 6ef888
		case -ENOENT:
Packit 6ef888
			break;
Packit 6ef888
Packit 6ef888
		default:
Packit 6ef888
			if (bh && bh != dip->i_bh)
Packit 6ef888
				brelse(bh);
Packit 6ef888
			return error;
Packit 6ef888
		}
Packit 6ef888
Packit 6ef888
		error = get_next_leaf(dip, bh, &bh_next);
Packit 6ef888
	} while (!error && bh_next != NULL);
Packit 6ef888
Packit 6ef888
	if (bh && bh != dip->i_bh)
Packit 6ef888
		brelse(bh);
Packit 6ef888
Packit 6ef888
	return error;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/**
Packit 6ef888
 * dir_e_search -
Packit 6ef888
 * @dip: The GFS2 inode
Packit 6ef888
 * @id:
Packit 6ef888
 * @inode:
Packit 6ef888
 *
Packit 6ef888
 * Returns:
Packit 6ef888
 */
Packit 6ef888
static int dir_e_search(struct gfs2_inode *dip, const char *filename,
Packit 6ef888
			int len, unsigned int *type, struct gfs2_inum *inum)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_buffer_head *bh = NULL;
Packit 6ef888
	struct gfs2_dirent *dent;
Packit 6ef888
	int error;
Packit 6ef888
Packit 6ef888
	error = linked_leaf_search(dip, filename, len, &dent, &bh;;
Packit 6ef888
	if (error)
Packit 6ef888
		return error;
Packit 6ef888
Packit 6ef888
	gfs2_inum_in(inum, (char *)&dent->de_inum);
Packit 6ef888
	if (type)
Packit 6ef888
		*type = be16_to_cpu(dent->de_type);
Packit 6ef888
Packit 6ef888
	brelse(bh);
Packit 6ef888
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
Packit 6ef888
/**
Packit 6ef888
 * dir_l_search -
Packit 6ef888
 * @dip: The GFS2 inode
Packit 6ef888
 * @id:
Packit 6ef888
 * @inode:
Packit 6ef888
 *
Packit 6ef888
 * Returns:
Packit 6ef888
 */
Packit 6ef888
static int dir_l_search(struct gfs2_inode *dip, const char *filename,
Packit 6ef888
			int len, unsigned int *type, struct gfs2_inum *inum)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_dirent *dent;
Packit 6ef888
	int error;
Packit 6ef888
Packit 6ef888
	if(!inode_is_stuffed(dip))
Packit 6ef888
		return -1;
Packit 6ef888
Packit 6ef888
	error = leaf_search(dip, dip->i_bh, filename, len, &dent, NULL);
Packit 6ef888
	if (!error) {
Packit 6ef888
		gfs2_inum_in(inum, (char *)&dent->de_inum);
Packit 6ef888
		if(type)
Packit 6ef888
			*type = be16_to_cpu(dent->de_type);
Packit 6ef888
	}
Packit 6ef888
	return error;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/**
Packit 6ef888
 * dir_search - Search a directory
Packit 6ef888
 * @dip: The GFS inode
Packit 6ef888
 * @id
Packit 6ef888
 * @type:
Packit 6ef888
 *
Packit 6ef888
 * This routine searches a directory for a file or another directory
Packit 6ef888
 * given its filename.  The component of the identifier that is
Packit 6ef888
 * not being used to search will be filled in and must be freed by
Packit 6ef888
 * the caller.
Packit 6ef888
 *
Packit 6ef888
 * Returns: 0 if found, -1 on failure, -ENOENT if not found.
Packit 6ef888
 */
Packit 6ef888
int dir_search(struct gfs2_inode *dip, const char *filename, int len,
Packit 6ef888
		      unsigned int *type, struct gfs2_inum *inum)
Packit 6ef888
{
Packit 6ef888
	int error;
Packit 6ef888
Packit 6ef888
	if(!S_ISDIR(dip->i_di.di_mode) && !is_gfs_dir(&dip->i_di))
Packit 6ef888
		return -1;
Packit 6ef888
Packit 6ef888
	if (dip->i_di.di_flags & GFS2_DIF_EXHASH)
Packit 6ef888
		error = dir_e_search(dip, filename, len, type, inum);
Packit 6ef888
	else
Packit 6ef888
		error = dir_l_search(dip, filename, len, type, inum);
Packit 6ef888
Packit 6ef888
	return error;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int dir_e_del(struct gfs2_inode *dip, const char *filename, int len)
Packit 6ef888
{
Packit 6ef888
	int lindex;
Packit 6ef888
	int error;
Packit 6ef888
	int found = 0;
Packit 6ef888
	uint64_t leaf_no;
Packit 6ef888
	struct gfs2_buffer_head *bh = NULL;
Packit 6ef888
	struct gfs2_dirent *cur, *prev;
Packit 6ef888
Packit 6ef888
	lindex = (1 << (dip->i_di.di_depth))-1;
Packit 6ef888
Packit 6ef888
	for(; (lindex >= 0) && !found; lindex--){
Packit 6ef888
		error = lgfs2_get_leaf_ptr(dip, lindex, &leaf_no);
Packit 6ef888
		if (error)
Packit 6ef888
			return error;
Packit 6ef888
Packit 6ef888
		while(leaf_no && !found){
Packit 6ef888
			bh = bread(dip->i_sbd, leaf_no);
Packit 6ef888
			error = leaf_search(dip, bh, filename, len, &cur, &prev;;
Packit 6ef888
			if (error) {
Packit 6ef888
				if(error != -ENOENT){
Packit 6ef888
					brelse(bh);
Packit 6ef888
					return -1;
Packit 6ef888
				}
Packit 6ef888
				leaf_no = be64_to_cpu(((struct gfs2_leaf *)bh->b_data)->lf_next);
Packit 6ef888
				brelse(bh);
Packit 6ef888
			} else
Packit 6ef888
				found = 1;
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	if(!found)
Packit 6ef888
		return 1;
Packit 6ef888
Packit 6ef888
	if (bh) {
Packit 6ef888
		dirent2_del(dip, bh, prev, cur);
Packit 6ef888
		brelse(bh);
Packit 6ef888
	}
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int dir_l_del(struct gfs2_inode *dip, const char *filename, int len)
Packit 6ef888
{
Packit 6ef888
	int error=0;
Packit 6ef888
	struct gfs2_dirent *cur, *prev;
Packit 6ef888
Packit 6ef888
	if(!inode_is_stuffed(dip))
Packit 6ef888
		return -1;
Packit 6ef888
Packit 6ef888
	error = leaf_search(dip, dip->i_bh, filename, len, &cur, &prev;;
Packit 6ef888
	if (error) {
Packit 6ef888
		if (error == -ENOENT)
Packit 6ef888
			return 1;
Packit 6ef888
		else
Packit 6ef888
			return -1;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	dirent2_del(dip, dip->i_bh, prev, cur);
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
Packit 6ef888
/*
Packit 6ef888
 * gfs2_dirent_del
Packit 6ef888
 * @dip
Packit 6ef888
 * filename
Packit 6ef888
 *
Packit 6ef888
 * Delete a directory entry from a directory.  This _only_
Packit 6ef888
 * removes the directory entry - leaving the dinode in
Packit 6ef888
 * place.  (Likely without a link.)
Packit 6ef888
 *
Packit 6ef888
 * Returns: 0 on success (or if it doesn't already exist), -1 on failure
Packit 6ef888
 */
Packit 6ef888
int gfs2_dirent_del(struct gfs2_inode *dip, const char *filename, int len)
Packit 6ef888
{
Packit 6ef888
	int error;
Packit 6ef888
Packit 6ef888
	if(!S_ISDIR(dip->i_di.di_mode) && !is_gfs_dir(&dip->i_di))
Packit 6ef888
		return -1;
Packit 6ef888
Packit 6ef888
	if (dip->i_di.di_flags & GFS2_DIF_EXHASH)
Packit 6ef888
		error = dir_e_del(dip, filename, len);
Packit 6ef888
	else
Packit 6ef888
		error = dir_l_del(dip, filename, len);
Packit 6ef888
	bmodified(dip->i_bh);
Packit 6ef888
	return error;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/**
Packit 6ef888
 * gfs2_lookupi - Look up a filename in a directory and return its inode
Packit 6ef888
 * @dip: The directory to search
Packit 6ef888
 * @name: The name of the inode to look for
Packit 6ef888
 * @ipp: Used to return the found inode if any
Packit 6ef888
 *
Packit 6ef888
 * Returns: 0 on success, -EXXXX on failure
Packit 6ef888
 */
Packit 6ef888
int gfs2_lookupi(struct gfs2_inode *dip, const char *filename, int len,
Packit 6ef888
		 struct gfs2_inode **ipp)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_sbd *sdp = dip->i_sbd;
Packit 6ef888
	int error = 0;
Packit 6ef888
	struct gfs2_inum inum;
Packit 6ef888
Packit 6ef888
	*ipp = NULL;
Packit 6ef888
Packit 6ef888
	if (!len || len > GFS2_FNAMESIZE)
Packit 6ef888
		return -ENAMETOOLONG;
Packit 6ef888
	if (gfs2_filecmp(filename, (char *)".", 1)) {
Packit 6ef888
		*ipp = dip;
Packit 6ef888
		return 0;
Packit 6ef888
	}
Packit 6ef888
	error = dir_search(dip, filename, len, NULL, &inum);
Packit 6ef888
	if (!error)
Packit 6ef888
		*ipp = lgfs2_inode_read(sdp, inum.no_addr);
Packit 6ef888
Packit 6ef888
	return error;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/**
Packit 6ef888
 * gfs2_free_block - free up a block given its block number
Packit 6ef888
 */
Packit 6ef888
void gfs2_free_block(struct gfs2_sbd *sdp, uint64_t block)
Packit 6ef888
{
Packit 6ef888
	struct rgrp_tree *rgd;
Packit 6ef888
Packit 6ef888
	/* Adjust the free space count for the freed block */
Packit 6ef888
	rgd = gfs2_blk2rgrpd(sdp, block); /* find the rg for indir block */
Packit 6ef888
	if (rgd) {
Packit 6ef888
		gfs2_set_bitmap(rgd, block, GFS2_BLKST_FREE);
Packit 6ef888
		rgd->rg.rg_free++; /* adjust the free count */
Packit 6ef888
		if (sdp->gfs1)
Packit 6ef888
			gfs_rgrp_out((struct gfs_rgrp *)&rgd->rg, rgd->bits[0].bi_bh);
Packit 6ef888
		else
Packit 6ef888
			gfs2_rgrp_out(&rgd->rg, rgd->bits[0].bi_bh->b_data);
Packit 6ef888
		bmodified(rgd->bits[0].bi_bh);
Packit 6ef888
		sdp->blks_alloced--;
Packit 6ef888
	}
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/**
Packit 6ef888
 * gfs2_freedi - unlink a disk inode by block number.
Packit 6ef888
 * Note: currently only works for regular files.
Packit 6ef888
 */
Packit 6ef888
int gfs2_freedi(struct gfs2_sbd *sdp, uint64_t diblock)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_inode *ip;
Packit 6ef888
	struct gfs2_buffer_head *bh, *nbh;
Packit 6ef888
	int h, head_size;
Packit 6ef888
	uint64_t *ptr, block;
Packit 6ef888
	struct rgrp_tree *rgd;
Packit 6ef888
	uint32_t height;
Packit 6ef888
	osi_list_t metalist[GFS2_MAX_META_HEIGHT];
Packit 6ef888
	osi_list_t *cur_list, *next_list, *tmp;
Packit 6ef888
Packit 6ef888
	for (h = 0; h < GFS2_MAX_META_HEIGHT; h++)
Packit 6ef888
		osi_list_init(&metalist[h]);
Packit 6ef888
Packit 6ef888
	bh = bread(sdp, diblock);
Packit 6ef888
	if (bh == NULL)
Packit 6ef888
		return -1;
Packit 6ef888
	ip = lgfs2_inode_get(sdp, bh);
Packit 6ef888
	if (ip == NULL)
Packit 6ef888
		return -1;
Packit 6ef888
	height = ip->i_di.di_height;
Packit 6ef888
	osi_list_add(&bh->b_altlist, &metalist[0]);
Packit 6ef888
Packit 6ef888
	for (h = 0; h < height; h++){
Packit 6ef888
		cur_list = &metalist[h];
Packit 6ef888
		next_list = &metalist[h + 1];
Packit 6ef888
		head_size = (h > 0 ? sizeof(struct gfs2_meta_header) :
Packit 6ef888
			     sizeof(struct gfs2_dinode));
Packit 6ef888
Packit 6ef888
		for (tmp = cur_list->next; tmp != cur_list; tmp = tmp->next){
Packit 6ef888
			bh = osi_list_entry(tmp, struct gfs2_buffer_head,
Packit 6ef888
					    b_altlist);
Packit 6ef888
Packit 6ef888
			for (ptr = (uint64_t *)(bh->b_data + head_size);
Packit 6ef888
			     (char *)ptr < (bh->b_data + sdp->bsize); ptr++) {
Packit 6ef888
				if (!*ptr)
Packit 6ef888
					continue;
Packit 6ef888
Packit 6ef888
				block = be64_to_cpu(*ptr);
Packit 6ef888
				gfs2_free_block(sdp, block);
Packit 6ef888
				if (h == height - 1) /* if not metadata */
Packit 6ef888
					continue; /* don't queue it up */
Packit 6ef888
				/* Read the next metadata block in the chain */
Packit 6ef888
				nbh = bread(sdp, block);
Packit 6ef888
				osi_list_add(&nbh->b_altlist, next_list);
Packit 6ef888
				brelse(nbh);
Packit 6ef888
			}
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
	rgd = gfs2_blk2rgrpd(sdp, diblock);
Packit 6ef888
	gfs2_set_bitmap(rgd, diblock, GFS2_BLKST_FREE);
Packit 6ef888
	inode_put(&ip);
Packit 6ef888
	/* inode_put deallocated the extra block used by the disk inode, */
Packit 6ef888
	/* so adjust it in the superblock struct */
Packit 6ef888
	sdp->blks_alloced--;
Packit 6ef888
	rgd->rg.rg_free++;
Packit 6ef888
	rgd->rg.rg_dinodes--;
Packit 6ef888
	if (sdp->gfs1)
Packit 6ef888
		gfs_rgrp_out((struct gfs_rgrp *)&rgd->rg, rgd->bits[0].bi_bh);
Packit 6ef888
	else
Packit 6ef888
		gfs2_rgrp_out(&rgd->rg, rgd->bits[0].bi_bh->b_data);
Packit 6ef888
	bmodified(rgd->bits[0].bi_bh);
Packit 6ef888
	sdp->dinodes_alloced--;
Packit 6ef888
	return 0;
Packit 6ef888
}