/*
* Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
- * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
#include <linux/buffer_head.h>
#include <linux/gfs2_ondisk.h>
#include <linux/crc32.h>
-#include <asm/semaphore.h>
#include "gfs2.h"
#include "lm_interface.h"
static unsigned int calc_tree_height(struct gfs2_inode *ip, uint64_t size)
{
- struct gfs2_sbd *sdp = ip->i_sbd;
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
uint64_t *arr;
unsigned int max, height;
* @ip: The GFS2 inode
* @height: The height to build to
*
- * This routine makes sure that the metadata tree is tall enough to hold
- * "size" bytes of data.
*
* Returns: errno
*/
-static int build_height(struct gfs2_inode *ip, int height)
+static int build_height(struct inode *inode, unsigned height)
{
- struct gfs2_sbd *sdp = ip->i_sbd;
- struct buffer_head *bh, *dibh;
- uint64_t block = 0, *bp;
- unsigned int x;
- int new_block;
+ struct gfs2_inode *ip = GFS2_I(inode);
+ unsigned new_height = height - ip->i_di.di_height;
+ struct buffer_head *dibh;
+ struct buffer_head *blocks[GFS2_MAX_META_HEIGHT];
int error;
+ u64 *bp;
+ u64 bn;
+ unsigned n;
- while (ip->i_di.di_height < height) {
- error = gfs2_meta_inode_buffer(ip, &dibh);
- if (error)
- return error;
-
- new_block = 0;
- bp = (uint64_t *)(dibh->b_data + sizeof(struct gfs2_dinode));
- for (x = 0; x < sdp->sd_diptrs; x++, bp++)
- if (*bp) {
- new_block = 1;
- break;
- }
-
- if (new_block) {
- /* Get a new block, fill it with the old direct
- pointers, and write it out */
+ if (height <= ip->i_di.di_height)
+ return 0;
- block = gfs2_alloc_meta(ip);
+ error = gfs2_meta_inode_buffer(ip, &dibh);
+ if (error)
+ return error;
- bh = gfs2_meta_new(ip->i_gl, block);
- gfs2_trans_add_bh(ip->i_gl, bh, 1);
- gfs2_metatype_set(bh,
- GFS2_METATYPE_IN,
+ for(n = 0; n < new_height; n++) {
+ bn = gfs2_alloc_meta(ip);
+ blocks[n] = gfs2_meta_new(ip->i_gl, bn);
+ gfs2_trans_add_bh(ip->i_gl, blocks[n], 1);
+ }
+
+ n = 0;
+ bn = blocks[0]->b_blocknr;
+ if (new_height > 1) {
+ for(; n < new_height-1; n++) {
+ gfs2_metatype_set(blocks[n], GFS2_METATYPE_IN,
GFS2_FORMAT_IN);
- gfs2_buffer_copy_tail(bh,
- sizeof(struct gfs2_meta_header),
- dibh, sizeof(struct gfs2_dinode));
-
- brelse(bh);
- }
-
- /* Set up the new direct pointer and write it out to disk */
-
- gfs2_trans_add_bh(ip->i_gl, dibh, 1);
-
- gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode));
-
- if (new_block) {
- *(uint64_t *)(dibh->b_data +
- sizeof(struct gfs2_dinode)) =
- cpu_to_be64(block);
- ip->i_di.di_blocks++;
+ gfs2_buffer_clear_tail(blocks[n],
+ sizeof(struct gfs2_meta_header));
+ bp = (u64 *)(blocks[n]->b_data +
+ sizeof(struct gfs2_meta_header));
+ *bp = cpu_to_be64(blocks[n+1]->b_blocknr);
+ brelse(blocks[n]);
+ blocks[n] = NULL;
}
-
- ip->i_di.di_height++;
-
- gfs2_dinode_out(&ip->i_di, dibh->b_data);
- brelse(dibh);
}
-
- return 0;
+ gfs2_metatype_set(blocks[n], GFS2_METATYPE_IN, GFS2_FORMAT_IN);
+ gfs2_buffer_copy_tail(blocks[n], sizeof(struct gfs2_meta_header),
+ dibh, sizeof(struct gfs2_dinode));
+ brelse(blocks[n]);
+ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+ gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode));
+ bp = (u64 *)(dibh->b_data + sizeof(struct gfs2_dinode));
+ *bp = cpu_to_be64(bn);
+ ip->i_di.di_height += new_height;
+ ip->i_di.di_blocks += new_height;
+ gfs2_dinode_out(&ip->i_di, dibh->b_data);
+ brelse(dibh);
+ return error;
}
/**
static void find_metapath(struct gfs2_inode *ip, uint64_t block,
struct metapath *mp)
{
- struct gfs2_sbd *sdp = ip->i_sbd;
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
uint64_t b = block;
unsigned int i;
int *boundary,
struct metapath *mp)
{
- struct gfs2_inode *ip = inode->u.generic_ip;
- struct gfs2_sbd *sdp = ip->i_sbd;
+ struct gfs2_inode *ip = GFS2_I(inode);
+ struct gfs2_sbd *sdp = GFS2_SB(inode);
struct buffer_head *bh;
int create = *new;
unsigned int bsize;
if (!create)
goto out;
- error = build_height(ip, height);
+ error = build_height(inode, height);
if (error)
goto out;
}
static inline void bmap_lock(struct inode *inode, int create)
{
- struct gfs2_inode *ip = inode->u.generic_ip;
+ struct gfs2_inode *ip = GFS2_I(inode);
if (create)
down_write(&ip->i_rw_mutex);
else
static inline void bmap_unlock(struct inode *inode, int create)
{
- struct gfs2_inode *ip = inode->u.generic_ip;
+ struct gfs2_inode *ip = GFS2_I(inode);
if (create)
up_write(&ip->i_rw_mutex);
else
int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen)
{
- struct gfs2_inode *ip = inode->u.generic_ip;
- struct gfs2_sbd *sdp = ip->i_sbd;
+ struct gfs2_inode *ip = GFS2_I(inode);
+ struct gfs2_sbd *sdp = GFS2_SB(inode);
struct metapath mp;
struct buffer_head *bh;
int boundary;
uint64_t block, int first, block_call_t bc,
void *data)
{
- struct gfs2_sbd *sdp = ip->i_sbd;
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct buffer_head *bh = NULL;
uint64_t *top, *bottom;
uint64_t bn;
struct buffer_head *bh, uint64_t *top, uint64_t *bottom,
unsigned int height, void *data)
{
- struct strip_mine *sm = (struct strip_mine *)data;
- struct gfs2_sbd *sdp = ip->i_sbd;
+ struct strip_mine *sm = data;
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_rgrp_list rlist;
uint64_t bn, bstart;
uint32_t blen;
static int do_grow(struct gfs2_inode *ip, uint64_t size)
{
- struct gfs2_sbd *sdp = ip->i_sbd;
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_alloc *al;
struct buffer_head *dibh;
unsigned int h;
h = calc_tree_height(ip, size);
if (ip->i_di.di_height < h) {
down_write(&ip->i_rw_mutex);
- error = build_height(ip, h);
+ error = build_height(&ip->i_inode, h);
up_write(&ip->i_rw_mutex);
if (error)
goto out_end_trans;
static int trunc_start(struct gfs2_inode *ip, uint64_t size)
{
- struct gfs2_sbd *sdp = ip->i_sbd;
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct buffer_head *dibh;
int journaled = gfs2_is_jdata(ip);
int error;
} else {
if (size & (uint64_t)(sdp->sd_sb.sb_bsize - 1))
- error = gfs2_block_truncate_page(ip->i_vnode->i_mapping);
+ error = gfs2_block_truncate_page(ip->i_inode.i_mapping);
if (!error) {
ip->i_di.di_size = size;
if (!size)
lblock = 0;
else
- lblock = (size - 1) >> ip->i_sbd->sd_sb.sb_bsize_shift;
+ lblock = (size - 1) >> GFS2_SB(&ip->i_inode)->sd_sb.sb_bsize_shift;
find_metapath(ip, lblock, &mp);
gfs2_alloc_get(ip);
static int trunc_end(struct gfs2_inode *ip)
{
- struct gfs2_sbd *sdp = ip->i_sbd;
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct buffer_head *dibh;
int error;
{
int error;
- if (gfs2_assert_warn(ip->i_sbd, S_ISREG(ip->i_di.di_mode)))
+ if (gfs2_assert_warn(GFS2_SB(&ip->i_inode), S_ISREG(ip->i_di.di_mode)))
return -EINVAL;
if (size > ip->i_di.di_size)
void gfs2_write_calc_reserv(struct gfs2_inode *ip, unsigned int len,
unsigned int *data_blocks, unsigned int *ind_blocks)
{
- struct gfs2_sbd *sdp = ip->i_sbd;
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
unsigned int tmp;
if (gfs2_is_dir(ip)) {
int gfs2_write_alloc_required(struct gfs2_inode *ip, uint64_t offset,
unsigned int len, int *alloc_required)
{
- struct gfs2_sbd *sdp = ip->i_sbd;
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
uint64_t lblock, lblock_stop, dblock;
uint32_t extlen;
int new = 0;
}
for (; lblock < lblock_stop; lblock += extlen) {
- error = gfs2_extent_map(ip->i_vnode, lblock, &new, &dblock, &extlen);
+ error = gfs2_extent_map(&ip->i_inode, lblock, &new, &dblock, &extlen);
if (error)
return error;