Blame gfs2/libgfs2/fs_ops.c

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