Commit ef38ff9d authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-2.6-nmw

* git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-2.6-nmw: (49 commits)
  [GFS2] fix assertion in log_refund()
  [GFS2] fix GFP_KERNEL misuses
  [GFS2] test for IS_ERR rather than 0
  [GFS2] Invalidate cache at correct point
  [GFS2] fs/gfs2/recovery.c: suppress warnings
  [GFS2] Faster gfs2_bitfit algorithm
  [GFS2] Streamline quota lock/check for no-quota case
  [GFS2] Remove drop of module ref where not needed
  [GFS2] gfs2_adjust_quota has broken unstuffing code
  [GFS2] possible null pointer dereference fixup
  [GFS2] Need to ensure that sector_t is 64bits for GFS2
  [GFS2] re-support special inode
  [GFS2] remove gfs2_dev_iops
  [GFS2] fix file_system_type leak on gfs2meta mount
  [GFS2] Allow bmap to allocate extents
  [GFS2] Fix a page lock / glock deadlock
  [GFS2] proper extern for gfs2/locking/dlm/mount.c:gdlm_ops
  [GFS2] gfs2/ops_file.c should #include "ops_inode.h"
  [GFS2] be*_add_cpu conversion
  [GFS2] Fix bug where we called drop_bh incorrectly
  ...
parents fda31d7d 62be1f71
config GFS2_FS config GFS2_FS
tristate "GFS2 file system support" tristate "GFS2 file system support"
depends on EXPERIMENTAL depends on EXPERIMENTAL && (64BIT || (LSF && LBD))
select FS_POSIX_ACL select FS_POSIX_ACL
select CRC32 select CRC32
help help
......
obj-$(CONFIG_GFS2_FS) += gfs2.o obj-$(CONFIG_GFS2_FS) += gfs2.o
gfs2-y := acl.o bmap.o daemon.o dir.o eaops.o eattr.o glock.o \ gfs2-y := acl.o bmap.o daemon.o dir.o eaops.o eattr.o glock.o \
glops.o inode.o lm.o log.o lops.o locking.o main.o meta_io.o \ glops.o inode.o log.o lops.o locking.o main.o meta_io.o \
mount.o ops_address.o ops_dentry.o ops_export.o ops_file.o \ mount.o ops_address.o ops_dentry.o ops_export.o ops_file.o \
ops_fstype.o ops_inode.o ops_super.o quota.o \ ops_fstype.o ops_inode.o ops_super.o quota.o \
recovery.o rgrp.o super.o sys.o trans.o util.o recovery.o rgrp.o super.o sys.o trans.o util.o
......
...@@ -116,7 +116,7 @@ static int acl_get(struct gfs2_inode *ip, int access, struct posix_acl **acl, ...@@ -116,7 +116,7 @@ static int acl_get(struct gfs2_inode *ip, int access, struct posix_acl **acl,
goto out; goto out;
er.er_data_len = GFS2_EA_DATA_LEN(el->el_ea); er.er_data_len = GFS2_EA_DATA_LEN(el->el_ea);
er.er_data = kmalloc(er.er_data_len, GFP_KERNEL); er.er_data = kmalloc(er.er_data_len, GFP_NOFS);
error = -ENOMEM; error = -ENOMEM;
if (!er.er_data) if (!er.er_data)
goto out; goto out;
...@@ -222,7 +222,7 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip) ...@@ -222,7 +222,7 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip)
return error; return error;
} }
clone = posix_acl_clone(acl, GFP_KERNEL); clone = posix_acl_clone(acl, GFP_NOFS);
error = -ENOMEM; error = -ENOMEM;
if (!clone) if (!clone)
goto out; goto out;
...@@ -272,7 +272,7 @@ int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr) ...@@ -272,7 +272,7 @@ int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr)
if (!acl) if (!acl)
return gfs2_setattr_simple(ip, attr); return gfs2_setattr_simple(ip, attr);
clone = posix_acl_clone(acl, GFP_KERNEL); clone = posix_acl_clone(acl, GFP_NOFS);
error = -ENOMEM; error = -ENOMEM;
if (!clone) if (!clone)
goto out; goto out;
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
* keep it small. * keep it small.
*/ */
struct metapath { struct metapath {
struct buffer_head *mp_bh[GFS2_MAX_META_HEIGHT];
__u16 mp_list[GFS2_MAX_META_HEIGHT]; __u16 mp_list[GFS2_MAX_META_HEIGHT];
}; };
...@@ -135,9 +136,10 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page) ...@@ -135,9 +136,10 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page)
/* Get a free block, fill it with the stuffed data, /* Get a free block, fill it with the stuffed data,
and write it out to disk */ and write it out to disk */
unsigned int n = 1;
block = gfs2_alloc_block(ip, &n);
if (isdir) { if (isdir) {
block = gfs2_alloc_meta(ip); gfs2_trans_add_unrevoke(GFS2_SB(&ip->i_inode), block, 1);
error = gfs2_dir_get_new_buffer(ip, block, &bh); error = gfs2_dir_get_new_buffer(ip, block, &bh);
if (error) if (error)
goto out_brelse; goto out_brelse;
...@@ -145,8 +147,6 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page) ...@@ -145,8 +147,6 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page)
dibh, sizeof(struct gfs2_dinode)); dibh, sizeof(struct gfs2_dinode));
brelse(bh); brelse(bh);
} else { } else {
block = gfs2_alloc_data(ip);
error = gfs2_unstuffer_page(ip, dibh, block, page); error = gfs2_unstuffer_page(ip, dibh, block, page);
if (error) if (error)
goto out_brelse; goto out_brelse;
...@@ -161,12 +161,11 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page) ...@@ -161,12 +161,11 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page)
if (ip->i_di.di_size) { if (ip->i_di.di_size) {
*(__be64 *)(di + 1) = cpu_to_be64(block); *(__be64 *)(di + 1) = cpu_to_be64(block);
ip->i_di.di_blocks++; gfs2_add_inode_blocks(&ip->i_inode, 1);
gfs2_set_inode_blocks(&ip->i_inode); di->di_blocks = cpu_to_be64(gfs2_get_inode_blocks(&ip->i_inode));
di->di_blocks = cpu_to_be64(ip->i_di.di_blocks);
} }
ip->i_di.di_height = 1; ip->i_height = 1;
di->di_height = cpu_to_be16(1); di->di_height = cpu_to_be16(1);
out_brelse: out_brelse:
...@@ -176,114 +175,13 @@ out: ...@@ -176,114 +175,13 @@ out:
return error; return error;
} }
/**
* calc_tree_height - Calculate the height of a metadata tree
* @ip: The GFS2 inode
* @size: The proposed size of the file
*
* Work out how tall a metadata tree needs to be in order to accommodate a
* file of a particular size. If size is less than the current size of
* the inode, then the current size of the inode is used instead of the
* supplied one.
*
* Returns: the height the tree should be
*/
static unsigned int calc_tree_height(struct gfs2_inode *ip, u64 size)
{
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
u64 *arr;
unsigned int max, height;
if (ip->i_di.di_size > size)
size = ip->i_di.di_size;
if (gfs2_is_dir(ip)) {
arr = sdp->sd_jheightsize;
max = sdp->sd_max_jheight;
} else {
arr = sdp->sd_heightsize;
max = sdp->sd_max_height;
}
for (height = 0; height < max; height++)
if (arr[height] >= size)
break;
return height;
}
/**
* build_height - Build a metadata tree of the requested height
* @ip: The GFS2 inode
* @height: The height to build to
*
*
* Returns: errno
*/
static int build_height(struct inode *inode, unsigned height)
{
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];
struct gfs2_dinode *di;
int error;
__be64 *bp;
u64 bn;
unsigned n;
if (height <= ip->i_di.di_height)
return 0;
error = gfs2_meta_inode_buffer(ip, &dibh);
if (error)
return error;
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_clear_tail(blocks[n],
sizeof(struct gfs2_meta_header));
bp = (__be64 *)(blocks[n]->b_data +
sizeof(struct gfs2_meta_header));
*bp = cpu_to_be64(blocks[n+1]->b_blocknr);
brelse(blocks[n]);
blocks[n] = NULL;
}
}
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);
di = (struct gfs2_dinode *)dibh->b_data;
gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode));
*(__be64 *)(di + 1) = cpu_to_be64(bn);
ip->i_di.di_height += new_height;
ip->i_di.di_blocks += new_height;
gfs2_set_inode_blocks(&ip->i_inode);
di->di_height = cpu_to_be16(ip->i_di.di_height);
di->di_blocks = cpu_to_be64(ip->i_di.di_blocks);
brelse(dibh);
return error;
}
/** /**
* find_metapath - Find path through the metadata tree * find_metapath - Find path through the metadata tree
* @ip: The inode pointer * @sdp: The superblock
* @mp: The metapath to return the result in * @mp: The metapath to return the result in
* @block: The disk block to look up * @block: The disk block to look up
* @height: The pre-calculated height of the metadata tree
* *
* This routine returns a struct metapath structure that defines a path * This routine returns a struct metapath structure that defines a path
* through the metadata of inode "ip" to get to block "block". * through the metadata of inode "ip" to get to block "block".
...@@ -338,21 +236,29 @@ static int build_height(struct inode *inode, unsigned height) ...@@ -338,21 +236,29 @@ static int build_height(struct inode *inode, unsigned height)
* *
*/ */
static void find_metapath(struct gfs2_inode *ip, u64 block, static void find_metapath(const struct gfs2_sbd *sdp, u64 block,
struct metapath *mp) struct metapath *mp, unsigned int height)
{ {
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
u64 b = block;
unsigned int i; unsigned int i;
for (i = ip->i_di.di_height; i--;) for (i = height; i--;)
mp->mp_list[i] = do_div(b, sdp->sd_inptrs); mp->mp_list[i] = do_div(block, sdp->sd_inptrs);
}
static inline unsigned int zero_metapath_length(const struct metapath *mp,
unsigned height)
{
unsigned int i;
for (i = 0; i < height - 1; i++) {
if (mp->mp_list[i] != 0)
return i;
}
return height;
} }
/** /**
* metapointer - Return pointer to start of metadata in a buffer * metapointer - Return pointer to start of metadata in a buffer
* @bh: The buffer
* @height: The metadata height (0 = dinode) * @height: The metadata height (0 = dinode)
* @mp: The metapath * @mp: The metapath
* *
...@@ -361,93 +267,302 @@ static void find_metapath(struct gfs2_inode *ip, u64 block, ...@@ -361,93 +267,302 @@ static void find_metapath(struct gfs2_inode *ip, u64 block,
* metadata tree. * metadata tree.
*/ */
static inline __be64 *metapointer(struct buffer_head *bh, int *boundary, static inline __be64 *metapointer(unsigned int height, const struct metapath *mp)
unsigned int height, const struct metapath *mp)
{ {
struct buffer_head *bh = mp->mp_bh[height];
unsigned int head_size = (height > 0) ? unsigned int head_size = (height > 0) ?
sizeof(struct gfs2_meta_header) : sizeof(struct gfs2_dinode); sizeof(struct gfs2_meta_header) : sizeof(struct gfs2_dinode);
__be64 *ptr; return ((__be64 *)(bh->b_data + head_size)) + mp->mp_list[height];
*boundary = 0;
ptr = ((__be64 *)(bh->b_data + head_size)) + mp->mp_list[height];
if (ptr + 1 == (__be64 *)(bh->b_data + bh->b_size))
*boundary = 1;
return ptr;
} }
/** /**
* lookup_block - Get the next metadata block in metadata tree * lookup_metapath - Walk the metadata tree to a specific point
* @ip: The GFS2 inode * @ip: The inode
* @bh: Buffer containing the pointers to metadata blocks
* @height: The height of the tree (0 = dinode)
* @mp: The metapath * @mp: The metapath
* @create: Non-zero if we may create a new meatdata block
* @new: Used to indicate if we did create a new metadata block
* @block: the returned disk block number
* *
* Given a metatree, complete to a particular height, checks to see if the next * Assumes that the inode's buffer has already been looked up and
* height of the tree exists. If not the next height of the tree is created. * hooked onto mp->mp_bh[0] and that the metapath has been initialised
* The block number of the next height of the metadata tree is returned. * by find_metapath().
*
* If this function encounters part of the tree which has not been
* allocated, it returns the current height of the tree at the point
* at which it found the unallocated block. Blocks which are found are
* added to the mp->mp_bh[] list.
* *
* Returns: error or height of metadata tree
*/ */
static int lookup_block(struct gfs2_inode *ip, struct buffer_head *bh, static int lookup_metapath(struct gfs2_inode *ip, struct metapath *mp)
unsigned int height, struct metapath *mp, int create,
int *new, u64 *block)
{ {
int boundary; unsigned int end_of_metadata = ip->i_height - 1;
__be64 *ptr = metapointer(bh, &boundary, height, mp); unsigned int x;
__be64 *ptr;
u64 dblock;
int ret;
if (*ptr) { for (x = 0; x < end_of_metadata; x++) {
*block = be64_to_cpu(*ptr); ptr = metapointer(x, mp);
return boundary; dblock = be64_to_cpu(*ptr);
} if (!dblock)
return x + 1;
*block = 0; ret = gfs2_meta_indirect_buffer(ip, x+1, dblock, 0, &mp->mp_bh[x+1]);
if (ret)
return ret;
}
if (!create) return ip->i_height;
return 0; }
if (height == ip->i_di.di_height - 1 && !gfs2_is_dir(ip)) static inline void release_metapath(struct metapath *mp)
*block = gfs2_alloc_data(ip); {
else int i;
*block = gfs2_alloc_meta(ip);
gfs2_trans_add_bh(ip->i_gl, bh, 1); for (i = 0; i < GFS2_MAX_META_HEIGHT; i++) {
if (mp->mp_bh[i] == NULL)
break;
brelse(mp->mp_bh[i]);
}
}
*ptr = cpu_to_be64(*block); /**
ip->i_di.di_blocks++; * gfs2_extent_length - Returns length of an extent of blocks
gfs2_set_inode_blocks(&ip->i_inode); * @start: Start of the buffer
* @len: Length of the buffer in bytes
* @ptr: Current position in the buffer
* @limit: Max extent length to return (0 = unlimited)
* @eob: Set to 1 if we hit "end of block"
*
* If the first block is zero (unallocated) it will return the number of
* unallocated blocks in the extent, otherwise it will return the number
* of contiguous blocks in the extent.
*
* Returns: The length of the extent (minimum of one block)
*/
*new = 1; static inline unsigned int gfs2_extent_length(void *start, unsigned int len, __be64 *ptr, unsigned limit, int *eob)
return 0; {
const __be64 *end = (start + len);
const __be64 *first = ptr;
u64 d = be64_to_cpu(*ptr);
*eob = 0;
do {
ptr++;
if (ptr >= end)
break;
if (limit && --limit == 0)
break;
if (d)
d++;
} while(be64_to_cpu(*ptr) == d);
if (ptr >= end)
*eob = 1;
return (ptr - first);
} }
static inline void bmap_lock(struct inode *inode, int create) static inline void bmap_lock(struct gfs2_inode *ip, int create)
{ {
struct gfs2_inode *ip = GFS2_I(inode);
if (create) if (create)
down_write(&ip->i_rw_mutex); down_write(&ip->i_rw_mutex);
else else
down_read(&ip->i_rw_mutex); down_read(&ip->i_rw_mutex);
} }
static inline void bmap_unlock(struct inode *inode, int create) static inline void bmap_unlock(struct gfs2_inode *ip, int create)
{ {
struct gfs2_inode *ip = GFS2_I(inode);
if (create) if (create)
up_write(&ip->i_rw_mutex); up_write(&ip->i_rw_mutex);
else else
up_read(&ip->i_rw_mutex); up_read(&ip->i_rw_mutex);
} }
static inline __be64 *gfs2_indirect_init(struct metapath *mp,
struct gfs2_glock *gl, unsigned int i,
unsigned offset, u64 bn)
{
__be64 *ptr = (__be64 *)(mp->mp_bh[i - 1]->b_data +
((i > 1) ? sizeof(struct gfs2_meta_header) :
sizeof(struct gfs2_dinode)));
BUG_ON(i < 1);
BUG_ON(mp->mp_bh[i] != NULL);
mp->mp_bh[i] = gfs2_meta_new(gl, bn);
gfs2_trans_add_bh(gl, mp->mp_bh[i], 1);
gfs2_metatype_set(mp->mp_bh[i], GFS2_METATYPE_IN, GFS2_FORMAT_IN);
gfs2_buffer_clear_tail(mp->mp_bh[i], sizeof(struct gfs2_meta_header));
ptr += offset;
*ptr = cpu_to_be64(bn);
return ptr;
}
enum alloc_state {
ALLOC_DATA = 0,
ALLOC_GROW_DEPTH = 1,
ALLOC_GROW_HEIGHT = 2,
/* ALLOC_UNSTUFF = 3, TBD and rather complicated */
};
/**
* gfs2_bmap_alloc - Build a metadata tree of the requested height
* @inode: The GFS2 inode
* @lblock: The logical starting block of the extent
* @bh_map: This is used to return the mapping details
* @mp: The metapath
* @sheight: The starting height (i.e. whats already mapped)
* @height: The height to build to
* @maxlen: The max number of data blocks to alloc
*
* In this routine we may have to alloc:
* i) Indirect blocks to grow the metadata tree height
* ii) Indirect blocks to fill in lower part of the metadata tree
* iii) Data blocks
*
* The function is in two parts. The first part works out the total
* number of blocks which we need. The second part does the actual
* allocation asking for an extent at a time (if enough contiguous free
* blocks are available, there will only be one request per bmap call)
* and uses the state machine to initialise the blocks in order.
*
* Returns: errno on error
*/
static int gfs2_bmap_alloc(struct inode *inode, const sector_t lblock,
struct buffer_head *bh_map, struct metapath *mp,
const unsigned int sheight,
const unsigned int height,
const unsigned int maxlen)
{
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_sbd *sdp = GFS2_SB(inode);
struct buffer_head *dibh = mp->mp_bh[0];
u64 bn, dblock = 0;
unsigned n, i, blks, alloced = 0, iblks = 0, zmpl = 0;
unsigned dblks = 0;
unsigned ptrs_per_blk;
const unsigned end_of_metadata = height - 1;
int eob = 0;
enum alloc_state state;
__be64 *ptr;
__be64 zero_bn = 0;
BUG_ON(sheight < 1);
BUG_ON(dibh == NULL);
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
if (height == sheight) {
struct buffer_head *bh;
/* Bottom indirect block exists, find unalloced extent size */
ptr = metapointer(end_of_metadata, mp);
bh = mp->mp_bh[end_of_metadata];
dblks = gfs2_extent_length(bh->b_data, bh->b_size, ptr, maxlen,
&eob);
BUG_ON(dblks < 1);
state = ALLOC_DATA;
} else {
/* Need to allocate indirect blocks */
ptrs_per_blk = height > 1 ? sdp->sd_inptrs : sdp->sd_diptrs;
dblks = min(maxlen, ptrs_per_blk - mp->mp_list[end_of_metadata]);
if (height == ip->i_height) {
/* Writing into existing tree, extend tree down */
iblks = height - sheight;
state = ALLOC_GROW_DEPTH;
} else {
/* Building up tree height */
state = ALLOC_GROW_HEIGHT;
iblks = height - ip->i_height;
zmpl = zero_metapath_length(mp, height);
iblks -= zmpl;
iblks += height;
}
}
/* start of the second part of the function (state machine) */
blks = dblks + iblks;
i = sheight;
do {
n = blks - alloced;
bn = gfs2_alloc_block(ip, &n);
alloced += n;
if (state != ALLOC_DATA || gfs2_is_jdata(ip))
gfs2_trans_add_unrevoke(sdp, bn, n);
switch (state) {
/* Growing height of tree */
case ALLOC_GROW_HEIGHT:
if (i == 1) {
ptr = (__be64 *)(dibh->b_data +
sizeof(struct gfs2_dinode));
zero_bn = *ptr;
}
for (; i - 1 < height - ip->i_height && n > 0; i++, n--)
gfs2_indirect_init(mp, ip->i_gl, i, 0, bn++);
if (i - 1 == height - ip->i_height) {
i--;
gfs2_buffer_copy_tail(mp->mp_bh[i],
sizeof(struct gfs2_meta_header),
dibh, sizeof(struct gfs2_dinode));
gfs2_buffer_clear_tail(dibh,
sizeof(struct gfs2_dinode) +
sizeof(__be64));
ptr = (__be64 *)(mp->mp_bh[i]->b_data +
sizeof(struct gfs2_meta_header));
*ptr = zero_bn;
state = ALLOC_GROW_DEPTH;
for(i = zmpl; i < height; i++) {
if (mp->mp_bh[i] == NULL)
break;
brelse(mp->mp_bh[i]);
mp->mp_bh[i] = NULL;
}
i = zmpl;
}
if (n == 0)
break;
/* Branching from existing tree */
case ALLOC_GROW_DEPTH:
if (i > 1 && i < height)
gfs2_trans_add_bh(ip->i_gl, mp->mp_bh[i-1], 1);
for (; i < height && n > 0; i++, n--)
gfs2_indirect_init(mp, ip->i_gl, i,
mp->mp_list[i-1], bn++);
if (i == height)
state = ALLOC_DATA;
if (n == 0)
break;
/* Tree complete, adding data blocks */
case ALLOC_DATA:
BUG_ON(n > dblks);
BUG_ON(mp->mp_bh[end_of_metadata] == NULL);
gfs2_trans_add_bh(ip->i_gl, mp->mp_bh[end_of_metadata], 1);
dblks = n;
ptr = metapointer(end_of_metadata, mp);
dblock = bn;
while (n-- > 0)
*ptr++ = cpu_to_be64(bn++);
break;
}
} while (state != ALLOC_DATA);
ip->i_height = height;
gfs2_add_inode_blocks(&ip->i_inode, alloced);
gfs2_dinode_out(ip, mp->mp_bh[0]->b_data);
map_bh(bh_map, inode->i_sb, dblock);
bh_map->b_size = dblks << inode->i_blkbits;
set_buffer_new(bh_map);
return 0;
}
/** /**
* gfs2_block_map - Map a block from an inode to a disk block * gfs2_block_map - Map a block from an inode to a disk block
* @inode: The inode * @inode: The inode
* @lblock: The logical block number * @lblock: The logical block number
* @bh_map: The bh to be mapped * @bh_map: The bh to be mapped
* @create: True if its ok to alloc blocks to satify the request
* *
* Find the block number on the current device which corresponds to an * Sets buffer_mapped() if successful, sets buffer_boundary() if a
* inode's block. If the block had to be created, "new" will be set. * read of metadata will be required before the next block can be
* mapped. Sets buffer_new() if new blocks were allocated.
* *
* Returns: errno * Returns: errno
*/ */
...@@ -457,97 +572,78 @@ int gfs2_block_map(struct inode *inode, sector_t lblock, ...@@ -457,97 +572,78 @@ int gfs2_block_map(struct inode *inode, sector_t lblock,
{ {
struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_sbd *sdp = GFS2_SB(inode); struct gfs2_sbd *sdp = GFS2_SB(inode);
struct buffer_head *bh; unsigned int bsize = sdp->sd_sb.sb_bsize;
unsigned int bsize; const unsigned int maxlen = bh_map->b_size >> inode->i_blkbits;
unsigned int height; const u64 *arr = sdp->sd_heightsize;
unsigned int end_of_metadata; __be64 *ptr;
unsigned int x;
int error = 0;
int new = 0;
u64 dblock = 0;
int boundary;
unsigned int maxlen = bh_map->b_size >> inode->i_blkbits;
struct metapath mp;
u64 size; u64 size;
struct buffer_head *dibh = NULL; struct metapath mp;
int ret;
int eob;
unsigned int len;
struct buffer_head *bh;
u8 height;
BUG_ON(maxlen == 0); BUG_ON(maxlen == 0);
if (gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip))) memset(mp.mp_bh, 0, sizeof(mp.mp_bh));
return 0; bmap_lock(ip, create);
bmap_lock(inode, create);
clear_buffer_mapped(bh_map); clear_buffer_mapped(bh_map);
clear_buffer_new(bh_map); clear_buffer_new(bh_map);
clear_buffer_boundary(bh_map); clear_buffer_boundary(bh_map);
bsize = gfs2_is_dir(ip) ? sdp->sd_jbsize : sdp->sd_sb.sb_bsize; if (gfs2_is_dir(ip)) {
size = (lblock + 1) * bsize; bsize = sdp->sd_jbsize;
arr = sdp->sd_jheightsize;
if (size > ip->i_di.di_size) {
height = calc_tree_height(ip, size);
if (ip->i_di.di_height < height) {
if (!create)
goto out_ok;
error = build_height(inode, height);
if (error)
goto out_fail;
}
} }
find_metapath(ip, lblock, &mp); ret = gfs2_meta_inode_buffer(ip, &mp.mp_bh[0]);
end_of_metadata = ip->i_di.di_height - 1; if (ret)
error = gfs2_meta_inode_buffer(ip, &bh); goto out;
if (error)
goto out_fail;
dibh = bh;
get_bh(dibh);
for (x = 0; x < end_of_metadata; x++) { height = ip->i_height;
lookup_block(ip, bh, x, &mp, create, &new, &dblock); size = (lblock + 1) * bsize;
brelse(bh); while (size > arr[height])
if (!dblock) height++;
goto out_ok; find_metapath(sdp, lblock, &mp, height);
ret = 1;
if (height > ip->i_height || gfs2_is_stuffed(ip))
goto do_alloc;
ret = lookup_metapath(ip, &mp);
if (ret < 0)
goto out;
if (ret != ip->i_height)
goto do_alloc;
ptr = metapointer(ip->i_height - 1, &mp);
if (*ptr == 0)
goto do_alloc;
map_bh(bh_map, inode->i_sb, be64_to_cpu(*ptr));
bh = mp.mp_bh[ip->i_height - 1];
len = gfs2_extent_length(bh->b_data, bh->b_size, ptr, maxlen, &eob);
bh_map->b_size = (len << inode->i_blkbits);
if (eob)
set_buffer_boundary(bh_map);
ret = 0;
out:
release_metapath(&mp);
bmap_unlock(ip, create);
return ret;
error = gfs2_meta_indirect_buffer(ip, x+1, dblock, new, &bh); do_alloc:
if (error) /* All allocations are done here, firstly check create flag */
goto out_fail; if (!create) {
BUG_ON(gfs2_is_stuffed(ip));
ret = 0;
goto out;
} }
boundary = lookup_block(ip, bh, end_of_metadata, &mp, create, &new, &dblock); /* At this point ret is the tree depth of already allocated blocks */
if (dblock) { ret = gfs2_bmap_alloc(inode, lblock, bh_map, &mp, ret, height, maxlen);
map_bh(bh_map, inode->i_sb, dblock); goto out;
if (boundary)
set_buffer_boundary(bh_map);
if (new) {
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
gfs2_dinode_out(ip, dibh->b_data);
set_buffer_new(bh_map);
goto out_brelse;
}
while(--maxlen && !buffer_boundary(bh_map)) {
u64 eblock;
mp.mp_list[end_of_metadata]++;
boundary = lookup_block(ip, bh, end_of_metadata, &mp, 0, &new, &eblock);
if (eblock != ++dblock)
break;
bh_map->b_size += (1 << inode->i_blkbits);
if (boundary)
set_buffer_boundary(bh_map);
}
}
out_brelse:
brelse(bh);
out_ok:
error = 0;
out_fail:
if (dibh)
brelse(dibh);
bmap_unlock(inode, create);
return error;
} }
/*
* Deprecated: do not use in new code
*/
int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen) int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen)
{ {
struct buffer_head bh = { .b_state = 0, .b_blocknr = 0 }; struct buffer_head bh = { .b_state = 0, .b_blocknr = 0 };
...@@ -558,7 +654,7 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi ...@@ -558,7 +654,7 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi
BUG_ON(!dblock); BUG_ON(!dblock);
BUG_ON(!new); BUG_ON(!new);
bh.b_size = 1 << (inode->i_blkbits + 5); bh.b_size = 1 << (inode->i_blkbits + (create ? 0 : 5));
ret = gfs2_block_map(inode, lblock, &bh, create); ret = gfs2_block_map(inode, lblock, &bh, create);
*extlen = bh.b_size >> inode->i_blkbits; *extlen = bh.b_size >> inode->i_blkbits;
*dblock = bh.b_blocknr; *dblock = bh.b_blocknr;
...@@ -621,7 +717,7 @@ static int recursive_scan(struct gfs2_inode *ip, struct buffer_head *dibh, ...@@ -621,7 +717,7 @@ static int recursive_scan(struct gfs2_inode *ip, struct buffer_head *dibh,
if (error) if (error)
goto out; goto out;
if (height < ip->i_di.di_height - 1) if (height < ip->i_height - 1)
for (; top < bottom; top++, first = 0) { for (; top < bottom; top++, first = 0) {
if (!*top) if (!*top)
continue; continue;
...@@ -679,7 +775,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, ...@@ -679,7 +775,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
sm->sm_first = 0; sm->sm_first = 0;
} }
metadata = (height != ip->i_di.di_height - 1); metadata = (height != ip->i_height - 1);
if (metadata) if (metadata)
revokes = (height) ? sdp->sd_inptrs : sdp->sd_diptrs; revokes = (height) ? sdp->sd_inptrs : sdp->sd_diptrs;
...@@ -713,7 +809,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, ...@@ -713,7 +809,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
else else
goto out; /* Nothing to do */ goto out; /* Nothing to do */
gfs2_rlist_alloc(&rlist, LM_ST_EXCLUSIVE, 0); gfs2_rlist_alloc(&rlist, LM_ST_EXCLUSIVE);
for (x = 0; x < rlist.rl_rgrps; x++) { for (x = 0; x < rlist.rl_rgrps; x++) {
struct gfs2_rgrpd *rgd; struct gfs2_rgrpd *rgd;
...@@ -760,10 +856,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, ...@@ -760,10 +856,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
} }
*p = 0; *p = 0;
if (!ip->i_di.di_blocks) gfs2_add_inode_blocks(&ip->i_inode, -1);
gfs2_consist_inode(ip);
ip->i_di.di_blocks--;
gfs2_set_inode_blocks(&ip->i_inode);
} }
if (bstart) { if (bstart) {
if (metadata) if (metadata)
...@@ -804,19 +897,16 @@ static int do_grow(struct gfs2_inode *ip, u64 size) ...@@ -804,19 +897,16 @@ static int do_grow(struct gfs2_inode *ip, u64 size)
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_alloc *al; struct gfs2_alloc *al;
struct buffer_head *dibh; struct buffer_head *dibh;
unsigned int h;
int error; int error;
al = gfs2_alloc_get(ip); al = gfs2_alloc_get(ip);
if (!al)
return -ENOMEM;
error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); error = gfs2_quota_lock_check(ip);
if (error) if (error)
goto out; goto out;
error = gfs2_quota_check(ip, ip->i_inode.i_uid, ip->i_inode.i_gid);
if (error)
goto out_gunlock_q;
al->al_requested = sdp->sd_max_height + RES_DATA; al->al_requested = sdp->sd_max_height + RES_DATA;
error = gfs2_inplace_reserve(ip); error = gfs2_inplace_reserve(ip);
...@@ -829,34 +919,25 @@ static int do_grow(struct gfs2_inode *ip, u64 size) ...@@ -829,34 +919,25 @@ static int do_grow(struct gfs2_inode *ip, u64 size)
if (error) if (error)
goto out_ipres; goto out_ipres;
error = gfs2_meta_inode_buffer(ip, &dibh);
if (error)
goto out_end_trans;
if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) { if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) {
if (gfs2_is_stuffed(ip)) { if (gfs2_is_stuffed(ip)) {
error = gfs2_unstuff_dinode(ip, NULL); error = gfs2_unstuff_dinode(ip, NULL);
if (error) if (error)
goto out_end_trans; goto out_brelse;
}
h = calc_tree_height(ip, size);
if (ip->i_di.di_height < h) {
down_write(&ip->i_rw_mutex);
error = build_height(&ip->i_inode, h);
up_write(&ip->i_rw_mutex);
if (error)
goto out_end_trans;
} }
} }
ip->i_di.di_size = size; ip->i_di.di_size = size;
ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME; ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME;
error = gfs2_meta_inode_buffer(ip, &dibh);
if (error)
goto out_end_trans;
gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_trans_add_bh(ip->i_gl, dibh, 1);
gfs2_dinode_out(ip, dibh->b_data); gfs2_dinode_out(ip, dibh->b_data);
brelse(dibh);
out_brelse:
brelse(dibh);
out_end_trans: out_end_trans:
gfs2_trans_end(sdp); gfs2_trans_end(sdp);
out_ipres: out_ipres:
...@@ -986,7 +1067,8 @@ out: ...@@ -986,7 +1067,8 @@ out:
static int trunc_dealloc(struct gfs2_inode *ip, u64 size) static int trunc_dealloc(struct gfs2_inode *ip, u64 size)
{ {
unsigned int height = ip->i_di.di_height; struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
unsigned int height = ip->i_height;
u64 lblock; u64 lblock;
struct metapath mp; struct metapath mp;
int error; int error;
...@@ -994,10 +1076,11 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 size) ...@@ -994,10 +1076,11 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 size)
if (!size) if (!size)
lblock = 0; lblock = 0;
else else
lblock = (size - 1) >> GFS2_SB(&ip->i_inode)->sd_sb.sb_bsize_shift; lblock = (size - 1) >> sdp->sd_sb.sb_bsize_shift;
find_metapath(ip, lblock, &mp); find_metapath(sdp, lblock, &mp, ip->i_height);
gfs2_alloc_get(ip); if (!gfs2_alloc_get(ip))
return -ENOMEM;
error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
if (error) if (error)
...@@ -1037,10 +1120,8 @@ static int trunc_end(struct gfs2_inode *ip) ...@@ -1037,10 +1120,8 @@ static int trunc_end(struct gfs2_inode *ip)
goto out; goto out;
if (!ip->i_di.di_size) { if (!ip->i_di.di_size) {
ip->i_di.di_height = 0; ip->i_height = 0;
ip->i_di.di_goal_meta = ip->i_goal = ip->i_no_addr;
ip->i_di.di_goal_data =
ip->i_no_addr;
gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode));
} }
ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME; ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME;
...@@ -1197,10 +1278,9 @@ int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset, ...@@ -1197,10 +1278,9 @@ int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset,
unsigned int len, int *alloc_required) unsigned int len, int *alloc_required)
{ {
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
u64 lblock, lblock_stop, dblock; struct buffer_head bh;
u32 extlen; unsigned int shift;
int new = 0; u64 lblock, lblock_stop, size;
int error = 0;
*alloc_required = 0; *alloc_required = 0;
...@@ -1214,6 +1294,8 @@ int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset, ...@@ -1214,6 +1294,8 @@ int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset,
return 0; return 0;
} }
*alloc_required = 1;
shift = sdp->sd_sb.sb_bsize_shift;
if (gfs2_is_dir(ip)) { if (gfs2_is_dir(ip)) {
unsigned int bsize = sdp->sd_jbsize; unsigned int bsize = sdp->sd_jbsize;
lblock = offset; lblock = offset;
...@@ -1221,27 +1303,25 @@ int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset, ...@@ -1221,27 +1303,25 @@ int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset,
lblock_stop = offset + len + bsize - 1; lblock_stop = offset + len + bsize - 1;
do_div(lblock_stop, bsize); do_div(lblock_stop, bsize);
} else { } else {
unsigned int shift = sdp->sd_sb.sb_bsize_shift;
u64 end_of_file = (ip->i_di.di_size + sdp->sd_sb.sb_bsize - 1) >> shift; u64 end_of_file = (ip->i_di.di_size + sdp->sd_sb.sb_bsize - 1) >> shift;
lblock = offset >> shift; lblock = offset >> shift;
lblock_stop = (offset + len + sdp->sd_sb.sb_bsize - 1) >> shift; lblock_stop = (offset + len + sdp->sd_sb.sb_bsize - 1) >> shift;
if (lblock_stop > end_of_file) { if (lblock_stop > end_of_file)
*alloc_required = 1;
return 0; return 0;
}
} }
for (; lblock < lblock_stop; lblock += extlen) { size = (lblock_stop - lblock) << shift;
error = gfs2_extent_map(&ip->i_inode, lblock, &new, &dblock, &extlen); do {
if (error) bh.b_state = 0;
return error; bh.b_size = size;
gfs2_block_map(&ip->i_inode, lblock, &bh, 0);
if (!dblock) { if (!buffer_mapped(&bh))
*alloc_required = 1;
return 0; return 0;
} size -= bh.b_size;
} lblock += (bh.b_size >> ip->i_inode.i_blkbits);
} while(size > 0);
*alloc_required = 0;
return 0; return 0;
} }
...@@ -159,6 +159,7 @@ static int gfs2_dir_write_data(struct gfs2_inode *ip, const char *buf, ...@@ -159,6 +159,7 @@ static int gfs2_dir_write_data(struct gfs2_inode *ip, const char *buf,
unsigned int o; unsigned int o;
int copied = 0; int copied = 0;
int error = 0; int error = 0;
int new = 0;
if (!size) if (!size)
return 0; return 0;
...@@ -183,7 +184,6 @@ static int gfs2_dir_write_data(struct gfs2_inode *ip, const char *buf, ...@@ -183,7 +184,6 @@ static int gfs2_dir_write_data(struct gfs2_inode *ip, const char *buf,
while (copied < size) { while (copied < size) {
unsigned int amount; unsigned int amount;
struct buffer_head *bh; struct buffer_head *bh;
int new = 0;
amount = size - copied; amount = size - copied;
if (amount > sdp->sd_sb.sb_bsize - o) if (amount > sdp->sd_sb.sb_bsize - o)
...@@ -757,7 +757,7 @@ static struct gfs2_dirent *gfs2_dirent_search(struct inode *inode, ...@@ -757,7 +757,7 @@ static struct gfs2_dirent *gfs2_dirent_search(struct inode *inode,
if (ip->i_di.di_flags & GFS2_DIF_EXHASH) { if (ip->i_di.di_flags & GFS2_DIF_EXHASH) {
struct gfs2_leaf *leaf; struct gfs2_leaf *leaf;
unsigned hsize = 1 << ip->i_di.di_depth; unsigned hsize = 1 << ip->i_depth;
unsigned index; unsigned index;
u64 ln; u64 ln;
if (hsize * sizeof(u64) != ip->i_di.di_size) { if (hsize * sizeof(u64) != ip->i_di.di_size) {
...@@ -765,7 +765,7 @@ static struct gfs2_dirent *gfs2_dirent_search(struct inode *inode, ...@@ -765,7 +765,7 @@ static struct gfs2_dirent *gfs2_dirent_search(struct inode *inode,
return ERR_PTR(-EIO); return ERR_PTR(-EIO);
} }
index = name->hash >> (32 - ip->i_di.di_depth); index = name->hash >> (32 - ip->i_depth);
error = get_first_leaf(ip, index, &bh); error = get_first_leaf(ip, index, &bh);
if (error) if (error)
return ERR_PTR(error); return ERR_PTR(error);
...@@ -803,14 +803,15 @@ got_dent: ...@@ -803,14 +803,15 @@ got_dent:
static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh, u16 depth) static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh, u16 depth)
{ {
struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_inode *ip = GFS2_I(inode);
u64 bn = gfs2_alloc_meta(ip); unsigned int n = 1;
u64 bn = gfs2_alloc_block(ip, &n);
struct buffer_head *bh = gfs2_meta_new(ip->i_gl, bn); struct buffer_head *bh = gfs2_meta_new(ip->i_gl, bn);
struct gfs2_leaf *leaf; struct gfs2_leaf *leaf;
struct gfs2_dirent *dent; struct gfs2_dirent *dent;
struct qstr name = { .name = "", .len = 0, .hash = 0 }; struct qstr name = { .name = "", .len = 0, .hash = 0 };
if (!bh) if (!bh)
return NULL; return NULL;
gfs2_trans_add_unrevoke(GFS2_SB(inode), bn, 1);
gfs2_trans_add_bh(ip->i_gl, bh, 1); gfs2_trans_add_bh(ip->i_gl, bh, 1);
gfs2_metatype_set(bh, GFS2_METATYPE_LF, GFS2_FORMAT_LF); gfs2_metatype_set(bh, GFS2_METATYPE_LF, GFS2_FORMAT_LF);
leaf = (struct gfs2_leaf *)bh->b_data; leaf = (struct gfs2_leaf *)bh->b_data;
...@@ -905,12 +906,11 @@ static int dir_make_exhash(struct inode *inode) ...@@ -905,12 +906,11 @@ static int dir_make_exhash(struct inode *inode)
*lp = cpu_to_be64(bn); *lp = cpu_to_be64(bn);
dip->i_di.di_size = sdp->sd_sb.sb_bsize / 2; dip->i_di.di_size = sdp->sd_sb.sb_bsize / 2;
dip->i_di.di_blocks++; gfs2_add_inode_blocks(&dip->i_inode, 1);
gfs2_set_inode_blocks(&dip->i_inode);
dip->i_di.di_flags |= GFS2_DIF_EXHASH; dip->i_di.di_flags |= GFS2_DIF_EXHASH;
for (x = sdp->sd_hash_ptrs, y = -1; x; x >>= 1, y++) ; for (x = sdp->sd_hash_ptrs, y = -1; x; x >>= 1, y++) ;
dip->i_di.di_depth = y; dip->i_depth = y;
gfs2_dinode_out(dip, dibh->b_data); gfs2_dinode_out(dip, dibh->b_data);
...@@ -941,7 +941,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) ...@@ -941,7 +941,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name)
int x, moved = 0; int x, moved = 0;
int error; int error;
index = name->hash >> (32 - dip->i_di.di_depth); index = name->hash >> (32 - dip->i_depth);
error = get_leaf_nr(dip, index, &leaf_no); error = get_leaf_nr(dip, index, &leaf_no);
if (error) if (error)
return error; return error;
...@@ -952,7 +952,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) ...@@ -952,7 +952,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name)
return error; return error;
oleaf = (struct gfs2_leaf *)obh->b_data; oleaf = (struct gfs2_leaf *)obh->b_data;
if (dip->i_di.di_depth == be16_to_cpu(oleaf->lf_depth)) { if (dip->i_depth == be16_to_cpu(oleaf->lf_depth)) {
brelse(obh); brelse(obh);
return 1; /* can't split */ return 1; /* can't split */
} }
...@@ -967,10 +967,10 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) ...@@ -967,10 +967,10 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name)
bn = nbh->b_blocknr; bn = nbh->b_blocknr;
/* Compute the start and len of leaf pointers in the hash table. */ /* Compute the start and len of leaf pointers in the hash table. */
len = 1 << (dip->i_di.di_depth - be16_to_cpu(oleaf->lf_depth)); len = 1 << (dip->i_depth - be16_to_cpu(oleaf->lf_depth));
half_len = len >> 1; half_len = len >> 1;
if (!half_len) { if (!half_len) {
printk(KERN_WARNING "di_depth %u lf_depth %u index %u\n", dip->i_di.di_depth, be16_to_cpu(oleaf->lf_depth), index); printk(KERN_WARNING "i_depth %u lf_depth %u index %u\n", dip->i_depth, be16_to_cpu(oleaf->lf_depth), index);
gfs2_consist_inode(dip); gfs2_consist_inode(dip);
error = -EIO; error = -EIO;
goto fail_brelse; goto fail_brelse;
...@@ -997,7 +997,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) ...@@ -997,7 +997,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name)
kfree(lp); kfree(lp);
/* Compute the divider */ /* Compute the divider */
divider = (start + half_len) << (32 - dip->i_di.di_depth); divider = (start + half_len) << (32 - dip->i_depth);
/* Copy the entries */ /* Copy the entries */
dirent_first(dip, obh, &dent); dirent_first(dip, obh, &dent);
...@@ -1021,13 +1021,13 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) ...@@ -1021,13 +1021,13 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name)
new->de_inum = dent->de_inum; /* No endian worries */ new->de_inum = dent->de_inum; /* No endian worries */
new->de_type = dent->de_type; /* No endian worries */ new->de_type = dent->de_type; /* No endian worries */
nleaf->lf_entries = cpu_to_be16(be16_to_cpu(nleaf->lf_entries)+1); be16_add_cpu(&nleaf->lf_entries, 1);
dirent_del(dip, obh, prev, dent); dirent_del(dip, obh, prev, dent);
if (!oleaf->lf_entries) if (!oleaf->lf_entries)
gfs2_consist_inode(dip); gfs2_consist_inode(dip);
oleaf->lf_entries = cpu_to_be16(be16_to_cpu(oleaf->lf_entries)-1); be16_add_cpu(&oleaf->lf_entries, -1);
if (!prev) if (!prev)
prev = dent; prev = dent;
...@@ -1044,8 +1044,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) ...@@ -1044,8 +1044,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name)
error = gfs2_meta_inode_buffer(dip, &dibh); error = gfs2_meta_inode_buffer(dip, &dibh);
if (!gfs2_assert_withdraw(GFS2_SB(&dip->i_inode), !error)) { if (!gfs2_assert_withdraw(GFS2_SB(&dip->i_inode), !error)) {
gfs2_trans_add_bh(dip->i_gl, dibh, 1); gfs2_trans_add_bh(dip->i_gl, dibh, 1);
dip->i_di.di_blocks++; gfs2_add_inode_blocks(&dip->i_inode, 1);
gfs2_set_inode_blocks(&dip->i_inode);
gfs2_dinode_out(dip, dibh->b_data); gfs2_dinode_out(dip, dibh->b_data);
brelse(dibh); brelse(dibh);
} }
...@@ -1082,7 +1081,7 @@ static int dir_double_exhash(struct gfs2_inode *dip) ...@@ -1082,7 +1081,7 @@ static int dir_double_exhash(struct gfs2_inode *dip)
int x; int x;
int error = 0; int error = 0;
hsize = 1 << dip->i_di.di_depth; hsize = 1 << dip->i_depth;
if (hsize * sizeof(u64) != dip->i_di.di_size) { if (hsize * sizeof(u64) != dip->i_di.di_size) {
gfs2_consist_inode(dip); gfs2_consist_inode(dip);
return -EIO; return -EIO;
...@@ -1090,7 +1089,7 @@ static int dir_double_exhash(struct gfs2_inode *dip) ...@@ -1090,7 +1089,7 @@ static int dir_double_exhash(struct gfs2_inode *dip)
/* Allocate both the "from" and "to" buffers in one big chunk */ /* Allocate both the "from" and "to" buffers in one big chunk */
buf = kcalloc(3, sdp->sd_hash_bsize, GFP_KERNEL | __GFP_NOFAIL); buf = kcalloc(3, sdp->sd_hash_bsize, GFP_NOFS | __GFP_NOFAIL);
for (block = dip->i_di.di_size >> sdp->sd_hash_bsize_shift; block--;) { for (block = dip->i_di.di_size >> sdp->sd_hash_bsize_shift; block--;) {
error = gfs2_dir_read_data(dip, (char *)buf, error = gfs2_dir_read_data(dip, (char *)buf,
...@@ -1125,7 +1124,7 @@ static int dir_double_exhash(struct gfs2_inode *dip) ...@@ -1125,7 +1124,7 @@ static int dir_double_exhash(struct gfs2_inode *dip)
error = gfs2_meta_inode_buffer(dip, &dibh); error = gfs2_meta_inode_buffer(dip, &dibh);
if (!gfs2_assert_withdraw(sdp, !error)) { if (!gfs2_assert_withdraw(sdp, !error)) {
dip->i_di.di_depth++; dip->i_depth++;
gfs2_dinode_out(dip, dibh->b_data); gfs2_dinode_out(dip, dibh->b_data);
brelse(dibh); brelse(dibh);
} }
...@@ -1370,16 +1369,16 @@ static int dir_e_read(struct inode *inode, u64 *offset, void *opaque, ...@@ -1370,16 +1369,16 @@ static int dir_e_read(struct inode *inode, u64 *offset, void *opaque,
int error = 0; int error = 0;
unsigned depth = 0; unsigned depth = 0;
hsize = 1 << dip->i_di.di_depth; hsize = 1 << dip->i_depth;
if (hsize * sizeof(u64) != dip->i_di.di_size) { if (hsize * sizeof(u64) != dip->i_di.di_size) {
gfs2_consist_inode(dip); gfs2_consist_inode(dip);
return -EIO; return -EIO;
} }
hash = gfs2_dir_offset2hash(*offset); hash = gfs2_dir_offset2hash(*offset);
index = hash >> (32 - dip->i_di.di_depth); index = hash >> (32 - dip->i_depth);
lp = kmalloc(sdp->sd_hash_bsize, GFP_KERNEL); lp = kmalloc(sdp->sd_hash_bsize, GFP_NOFS);
if (!lp) if (!lp)
return -ENOMEM; return -ENOMEM;
...@@ -1405,7 +1404,7 @@ static int dir_e_read(struct inode *inode, u64 *offset, void *opaque, ...@@ -1405,7 +1404,7 @@ static int dir_e_read(struct inode *inode, u64 *offset, void *opaque,
if (error) if (error)
break; break;
len = 1 << (dip->i_di.di_depth - depth); len = 1 << (dip->i_depth - depth);
index = (index & ~(len - 1)) + len; index = (index & ~(len - 1)) + len;
} }
...@@ -1444,7 +1443,7 @@ int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque, ...@@ -1444,7 +1443,7 @@ int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque,
error = -ENOMEM; error = -ENOMEM;
/* 96 is max number of dirents which can be stuffed into an inode */ /* 96 is max number of dirents which can be stuffed into an inode */
darr = kmalloc(96 * sizeof(struct gfs2_dirent *), GFP_KERNEL); darr = kmalloc(96 * sizeof(struct gfs2_dirent *), GFP_NOFS);
if (darr) { if (darr) {
g.pdent = darr; g.pdent = darr;
g.offset = 0; g.offset = 0;
...@@ -1549,7 +1548,7 @@ static int dir_new_leaf(struct inode *inode, const struct qstr *name) ...@@ -1549,7 +1548,7 @@ static int dir_new_leaf(struct inode *inode, const struct qstr *name)
u32 index; u32 index;
u64 bn; u64 bn;
index = name->hash >> (32 - ip->i_di.di_depth); index = name->hash >> (32 - ip->i_depth);
error = get_first_leaf(ip, index, &obh); error = get_first_leaf(ip, index, &obh);
if (error) if (error)
return error; return error;
...@@ -1579,8 +1578,7 @@ static int dir_new_leaf(struct inode *inode, const struct qstr *name) ...@@ -1579,8 +1578,7 @@ static int dir_new_leaf(struct inode *inode, const struct qstr *name)
if (error) if (error)
return error; return error;
gfs2_trans_add_bh(ip->i_gl, bh, 1); gfs2_trans_add_bh(ip->i_gl, bh, 1);
ip->i_di.di_blocks++; gfs2_add_inode_blocks(&ip->i_inode, 1);
gfs2_set_inode_blocks(&ip->i_inode);
gfs2_dinode_out(ip, bh->b_data); gfs2_dinode_out(ip, bh->b_data);
brelse(bh); brelse(bh);
return 0; return 0;
...@@ -1616,7 +1614,7 @@ int gfs2_dir_add(struct inode *inode, const struct qstr *name, ...@@ -1616,7 +1614,7 @@ int gfs2_dir_add(struct inode *inode, const struct qstr *name,
dent->de_type = cpu_to_be16(type); dent->de_type = cpu_to_be16(type);
if (ip->i_di.di_flags & GFS2_DIF_EXHASH) { if (ip->i_di.di_flags & GFS2_DIF_EXHASH) {
leaf = (struct gfs2_leaf *)bh->b_data; leaf = (struct gfs2_leaf *)bh->b_data;
leaf->lf_entries = cpu_to_be16(be16_to_cpu(leaf->lf_entries) + 1); be16_add_cpu(&leaf->lf_entries, 1);
} }
brelse(bh); brelse(bh);
error = gfs2_meta_inode_buffer(ip, &bh); error = gfs2_meta_inode_buffer(ip, &bh);
...@@ -1641,7 +1639,7 @@ int gfs2_dir_add(struct inode *inode, const struct qstr *name, ...@@ -1641,7 +1639,7 @@ int gfs2_dir_add(struct inode *inode, const struct qstr *name,
continue; continue;
if (error < 0) if (error < 0)
break; break;
if (ip->i_di.di_depth < GFS2_DIR_MAX_DEPTH) { if (ip->i_depth < GFS2_DIR_MAX_DEPTH) {
error = dir_double_exhash(ip); error = dir_double_exhash(ip);
if (error) if (error)
break; break;
...@@ -1785,13 +1783,13 @@ static int foreach_leaf(struct gfs2_inode *dip, leaf_call_t lc, void *data) ...@@ -1785,13 +1783,13 @@ static int foreach_leaf(struct gfs2_inode *dip, leaf_call_t lc, void *data)
u64 leaf_no; u64 leaf_no;
int error = 0; int error = 0;
hsize = 1 << dip->i_di.di_depth; hsize = 1 << dip->i_depth;
if (hsize * sizeof(u64) != dip->i_di.di_size) { if (hsize * sizeof(u64) != dip->i_di.di_size) {
gfs2_consist_inode(dip); gfs2_consist_inode(dip);
return -EIO; return -EIO;
} }
lp = kmalloc(sdp->sd_hash_bsize, GFP_KERNEL); lp = kmalloc(sdp->sd_hash_bsize, GFP_NOFS);
if (!lp) if (!lp)
return -ENOMEM; return -ENOMEM;
...@@ -1817,7 +1815,7 @@ static int foreach_leaf(struct gfs2_inode *dip, leaf_call_t lc, void *data) ...@@ -1817,7 +1815,7 @@ static int foreach_leaf(struct gfs2_inode *dip, leaf_call_t lc, void *data)
if (error) if (error)
goto out; goto out;
leaf = (struct gfs2_leaf *)bh->b_data; leaf = (struct gfs2_leaf *)bh->b_data;
len = 1 << (dip->i_di.di_depth - be16_to_cpu(leaf->lf_depth)); len = 1 << (dip->i_depth - be16_to_cpu(leaf->lf_depth));
brelse(bh); brelse(bh);
error = lc(dip, index, len, leaf_no, data); error = lc(dip, index, len, leaf_no, data);
...@@ -1866,15 +1864,18 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len, ...@@ -1866,15 +1864,18 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len,
memset(&rlist, 0, sizeof(struct gfs2_rgrp_list)); memset(&rlist, 0, sizeof(struct gfs2_rgrp_list));
ht = kzalloc(size, GFP_KERNEL); ht = kzalloc(size, GFP_NOFS);
if (!ht) if (!ht)
return -ENOMEM; return -ENOMEM;
gfs2_alloc_get(dip); if (!gfs2_alloc_get(dip)) {
error = -ENOMEM;
goto out;
}
error = gfs2_quota_hold(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); error = gfs2_quota_hold(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
if (error) if (error)
goto out; goto out_put;
error = gfs2_rindex_hold(sdp, &dip->i_alloc->al_ri_gh); error = gfs2_rindex_hold(sdp, &dip->i_alloc->al_ri_gh);
if (error) if (error)
...@@ -1894,7 +1895,7 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len, ...@@ -1894,7 +1895,7 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len,
l_blocks++; l_blocks++;
} }
gfs2_rlist_alloc(&rlist, LM_ST_EXCLUSIVE, 0); gfs2_rlist_alloc(&rlist, LM_ST_EXCLUSIVE);
for (x = 0; x < rlist.rl_rgrps; x++) { for (x = 0; x < rlist.rl_rgrps; x++) {
struct gfs2_rgrpd *rgd; struct gfs2_rgrpd *rgd;
...@@ -1921,11 +1922,7 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len, ...@@ -1921,11 +1922,7 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len,
brelse(bh); brelse(bh);
gfs2_free_meta(dip, blk, 1); gfs2_free_meta(dip, blk, 1);
gfs2_add_inode_blocks(&dip->i_inode, -1);
if (!dip->i_di.di_blocks)
gfs2_consist_inode(dip);
dip->i_di.di_blocks--;
gfs2_set_inode_blocks(&dip->i_inode);
} }
error = gfs2_dir_write_data(dip, ht, index * sizeof(u64), size); error = gfs2_dir_write_data(dip, ht, index * sizeof(u64), size);
...@@ -1952,8 +1949,9 @@ out_rlist: ...@@ -1952,8 +1949,9 @@ out_rlist:
gfs2_glock_dq_uninit(&dip->i_alloc->al_ri_gh); gfs2_glock_dq_uninit(&dip->i_alloc->al_ri_gh);
out_qs: out_qs:
gfs2_quota_unhold(dip); gfs2_quota_unhold(dip);
out: out_put:
gfs2_alloc_put(dip); gfs2_alloc_put(dip);
out:
kfree(ht); kfree(ht);
return error; return error;
} }
......
...@@ -277,10 +277,7 @@ static int ea_dealloc_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh, ...@@ -277,10 +277,7 @@ static int ea_dealloc_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh,
} }
*dataptrs = 0; *dataptrs = 0;
if (!ip->i_di.di_blocks) gfs2_add_inode_blocks(&ip->i_inode, -1);
gfs2_consist_inode(ip);
ip->i_di.di_blocks--;
gfs2_set_inode_blocks(&ip->i_inode);
} }
if (bstart) if (bstart)
gfs2_free_meta(ip, bstart, blen); gfs2_free_meta(ip, bstart, blen);
...@@ -321,6 +318,8 @@ static int ea_remove_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh, ...@@ -321,6 +318,8 @@ static int ea_remove_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh,
int error; int error;
al = gfs2_alloc_get(ip); al = gfs2_alloc_get(ip);
if (!al)
return -ENOMEM;
error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
if (error) if (error)
...@@ -449,7 +448,7 @@ static int ea_get_unstuffed(struct gfs2_inode *ip, struct gfs2_ea_header *ea, ...@@ -449,7 +448,7 @@ static int ea_get_unstuffed(struct gfs2_inode *ip, struct gfs2_ea_header *ea,
unsigned int x; unsigned int x;
int error = 0; int error = 0;
bh = kcalloc(nptrs, sizeof(struct buffer_head *), GFP_KERNEL); bh = kcalloc(nptrs, sizeof(struct buffer_head *), GFP_NOFS);
if (!bh) if (!bh)
return -ENOMEM; return -ENOMEM;
...@@ -582,10 +581,11 @@ static int ea_alloc_blk(struct gfs2_inode *ip, struct buffer_head **bhp) ...@@ -582,10 +581,11 @@ static int ea_alloc_blk(struct gfs2_inode *ip, struct buffer_head **bhp)
{ {
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_ea_header *ea; struct gfs2_ea_header *ea;
unsigned int n = 1;
u64 block; u64 block;
block = gfs2_alloc_meta(ip); block = gfs2_alloc_block(ip, &n);
gfs2_trans_add_unrevoke(sdp, block, 1);
*bhp = gfs2_meta_new(ip->i_gl, block); *bhp = gfs2_meta_new(ip->i_gl, block);
gfs2_trans_add_bh(ip->i_gl, *bhp, 1); gfs2_trans_add_bh(ip->i_gl, *bhp, 1);
gfs2_metatype_set(*bhp, GFS2_METATYPE_EA, GFS2_FORMAT_EA); gfs2_metatype_set(*bhp, GFS2_METATYPE_EA, GFS2_FORMAT_EA);
...@@ -597,8 +597,7 @@ static int ea_alloc_blk(struct gfs2_inode *ip, struct buffer_head **bhp) ...@@ -597,8 +597,7 @@ static int ea_alloc_blk(struct gfs2_inode *ip, struct buffer_head **bhp)
ea->ea_flags = GFS2_EAFLAG_LAST; ea->ea_flags = GFS2_EAFLAG_LAST;
ea->ea_num_ptrs = 0; ea->ea_num_ptrs = 0;
ip->i_di.di_blocks++; gfs2_add_inode_blocks(&ip->i_inode, 1);
gfs2_set_inode_blocks(&ip->i_inode);
return 0; return 0;
} }
...@@ -642,15 +641,15 @@ static int ea_write(struct gfs2_inode *ip, struct gfs2_ea_header *ea, ...@@ -642,15 +641,15 @@ static int ea_write(struct gfs2_inode *ip, struct gfs2_ea_header *ea,
struct buffer_head *bh; struct buffer_head *bh;
u64 block; u64 block;
int mh_size = sizeof(struct gfs2_meta_header); int mh_size = sizeof(struct gfs2_meta_header);
unsigned int n = 1;
block = gfs2_alloc_meta(ip); block = gfs2_alloc_block(ip, &n);
gfs2_trans_add_unrevoke(sdp, block, 1);
bh = gfs2_meta_new(ip->i_gl, block); bh = gfs2_meta_new(ip->i_gl, block);
gfs2_trans_add_bh(ip->i_gl, bh, 1); gfs2_trans_add_bh(ip->i_gl, bh, 1);
gfs2_metatype_set(bh, GFS2_METATYPE_ED, GFS2_FORMAT_ED); gfs2_metatype_set(bh, GFS2_METATYPE_ED, GFS2_FORMAT_ED);
ip->i_di.di_blocks++; gfs2_add_inode_blocks(&ip->i_inode, 1);
gfs2_set_inode_blocks(&ip->i_inode);
copy = data_len > sdp->sd_jbsize ? sdp->sd_jbsize : copy = data_len > sdp->sd_jbsize ? sdp->sd_jbsize :
data_len; data_len;
...@@ -684,15 +683,13 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er, ...@@ -684,15 +683,13 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er,
int error; int error;
al = gfs2_alloc_get(ip); al = gfs2_alloc_get(ip);
if (!al)
return -ENOMEM;
error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); error = gfs2_quota_lock_check(ip);
if (error) if (error)
goto out; goto out;
error = gfs2_quota_check(ip, ip->i_inode.i_uid, ip->i_inode.i_gid);
if (error)
goto out_gunlock_q;
al->al_requested = blks; al->al_requested = blks;
error = gfs2_inplace_reserve(ip); error = gfs2_inplace_reserve(ip);
...@@ -966,9 +963,9 @@ static int ea_set_block(struct gfs2_inode *ip, struct gfs2_ea_request *er, ...@@ -966,9 +963,9 @@ static int ea_set_block(struct gfs2_inode *ip, struct gfs2_ea_request *er,
gfs2_trans_add_bh(ip->i_gl, indbh, 1); gfs2_trans_add_bh(ip->i_gl, indbh, 1);
} else { } else {
u64 blk; u64 blk;
unsigned int n = 1;
blk = gfs2_alloc_meta(ip); blk = gfs2_alloc_block(ip, &n);
gfs2_trans_add_unrevoke(sdp, blk, 1);
indbh = gfs2_meta_new(ip->i_gl, blk); indbh = gfs2_meta_new(ip->i_gl, blk);
gfs2_trans_add_bh(ip->i_gl, indbh, 1); gfs2_trans_add_bh(ip->i_gl, indbh, 1);
gfs2_metatype_set(indbh, GFS2_METATYPE_IN, GFS2_FORMAT_IN); gfs2_metatype_set(indbh, GFS2_METATYPE_IN, GFS2_FORMAT_IN);
...@@ -978,8 +975,7 @@ static int ea_set_block(struct gfs2_inode *ip, struct gfs2_ea_request *er, ...@@ -978,8 +975,7 @@ static int ea_set_block(struct gfs2_inode *ip, struct gfs2_ea_request *er,
*eablk = cpu_to_be64(ip->i_di.di_eattr); *eablk = cpu_to_be64(ip->i_di.di_eattr);
ip->i_di.di_eattr = blk; ip->i_di.di_eattr = blk;
ip->i_di.di_flags |= GFS2_DIF_EA_INDIRECT; ip->i_di.di_flags |= GFS2_DIF_EA_INDIRECT;
ip->i_di.di_blocks++; gfs2_add_inode_blocks(&ip->i_inode, 1);
gfs2_set_inode_blocks(&ip->i_inode);
eablk++; eablk++;
} }
...@@ -1210,7 +1206,7 @@ static int ea_acl_chmod_unstuffed(struct gfs2_inode *ip, ...@@ -1210,7 +1206,7 @@ static int ea_acl_chmod_unstuffed(struct gfs2_inode *ip,
unsigned int x; unsigned int x;
int error; int error;
bh = kcalloc(nptrs, sizeof(struct buffer_head *), GFP_KERNEL); bh = kcalloc(nptrs, sizeof(struct buffer_head *), GFP_NOFS);
if (!bh) if (!bh)
return -ENOMEM; return -ENOMEM;
...@@ -1347,7 +1343,7 @@ static int ea_dealloc_indirect(struct gfs2_inode *ip) ...@@ -1347,7 +1343,7 @@ static int ea_dealloc_indirect(struct gfs2_inode *ip)
else else
goto out; goto out;
gfs2_rlist_alloc(&rlist, LM_ST_EXCLUSIVE, 0); gfs2_rlist_alloc(&rlist, LM_ST_EXCLUSIVE);
for (x = 0; x < rlist.rl_rgrps; x++) { for (x = 0; x < rlist.rl_rgrps; x++) {
struct gfs2_rgrpd *rgd; struct gfs2_rgrpd *rgd;
...@@ -1387,10 +1383,7 @@ static int ea_dealloc_indirect(struct gfs2_inode *ip) ...@@ -1387,10 +1383,7 @@ static int ea_dealloc_indirect(struct gfs2_inode *ip)
} }
*eablk = 0; *eablk = 0;
if (!ip->i_di.di_blocks) gfs2_add_inode_blocks(&ip->i_inode, -1);
gfs2_consist_inode(ip);
ip->i_di.di_blocks--;
gfs2_set_inode_blocks(&ip->i_inode);
} }
if (bstart) if (bstart)
gfs2_free_meta(ip, bstart, blen); gfs2_free_meta(ip, bstart, blen);
...@@ -1442,10 +1435,7 @@ static int ea_dealloc_block(struct gfs2_inode *ip) ...@@ -1442,10 +1435,7 @@ static int ea_dealloc_block(struct gfs2_inode *ip)
gfs2_free_meta(ip, ip->i_di.di_eattr, 1); gfs2_free_meta(ip, ip->i_di.di_eattr, 1);
ip->i_di.di_eattr = 0; ip->i_di.di_eattr = 0;
if (!ip->i_di.di_blocks) gfs2_add_inode_blocks(&ip->i_inode, -1);
gfs2_consist_inode(ip);
ip->i_di.di_blocks--;
gfs2_set_inode_blocks(&ip->i_inode);
error = gfs2_meta_inode_buffer(ip, &dibh); error = gfs2_meta_inode_buffer(ip, &dibh);
if (!error) { if (!error) {
...@@ -1474,6 +1464,8 @@ int gfs2_ea_dealloc(struct gfs2_inode *ip) ...@@ -1474,6 +1464,8 @@ int gfs2_ea_dealloc(struct gfs2_inode *ip)
int error; int error;
al = gfs2_alloc_get(ip); al = gfs2_alloc_get(ip);
if (!al)
return -ENOMEM;
error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
if (error) if (error)
......
/* /*
* Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
* Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
* *
* This copyrighted material is made available to anyone wishing to use, * This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions * modify, copy, or redistribute it subject to the terms and conditions
...@@ -35,7 +35,6 @@ ...@@ -35,7 +35,6 @@
#include "glock.h" #include "glock.h"
#include "glops.h" #include "glops.h"
#include "inode.h" #include "inode.h"
#include "lm.h"
#include "lops.h" #include "lops.h"
#include "meta_io.h" #include "meta_io.h"
#include "quota.h" #include "quota.h"
...@@ -183,7 +182,8 @@ static void glock_free(struct gfs2_glock *gl) ...@@ -183,7 +182,8 @@ static void glock_free(struct gfs2_glock *gl)
struct gfs2_sbd *sdp = gl->gl_sbd; struct gfs2_sbd *sdp = gl->gl_sbd;
struct inode *aspace = gl->gl_aspace; struct inode *aspace = gl->gl_aspace;
gfs2_lm_put_lock(sdp, gl->gl_lock); if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
sdp->sd_lockstruct.ls_ops->lm_put_lock(gl->gl_lock);
if (aspace) if (aspace)
gfs2_aspace_put(aspace); gfs2_aspace_put(aspace);
...@@ -197,7 +197,7 @@ static void glock_free(struct gfs2_glock *gl) ...@@ -197,7 +197,7 @@ static void glock_free(struct gfs2_glock *gl)
* *
*/ */
void gfs2_glock_hold(struct gfs2_glock *gl) static void gfs2_glock_hold(struct gfs2_glock *gl)
{ {
atomic_inc(&gl->gl_ref); atomic_inc(&gl->gl_ref);
} }
...@@ -293,6 +293,16 @@ static void glock_work_func(struct work_struct *work) ...@@ -293,6 +293,16 @@ static void glock_work_func(struct work_struct *work)
gfs2_glock_put(gl); gfs2_glock_put(gl);
} }
static int gfs2_lm_get_lock(struct gfs2_sbd *sdp, struct lm_lockname *name,
void **lockp)
{
int error = -EIO;
if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
error = sdp->sd_lockstruct.ls_ops->lm_get_lock(
sdp->sd_lockstruct.ls_lockspace, name, lockp);
return error;
}
/** /**
* gfs2_glock_get() - Get a glock, or create one if one doesn't exist * gfs2_glock_get() - Get a glock, or create one if one doesn't exist
* @sdp: The GFS2 superblock * @sdp: The GFS2 superblock
...@@ -338,8 +348,6 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, ...@@ -338,8 +348,6 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
gl->gl_ip = 0; gl->gl_ip = 0;
gl->gl_ops = glops; gl->gl_ops = glops;
gl->gl_req_gh = NULL; gl->gl_req_gh = NULL;
gl->gl_req_bh = NULL;
gl->gl_vn = 0;
gl->gl_stamp = jiffies; gl->gl_stamp = jiffies;
gl->gl_tchange = jiffies; gl->gl_tchange = jiffies;
gl->gl_object = NULL; gl->gl_object = NULL;
...@@ -595,11 +603,12 @@ static void run_queue(struct gfs2_glock *gl) ...@@ -595,11 +603,12 @@ static void run_queue(struct gfs2_glock *gl)
blocked = rq_mutex(gh); blocked = rq_mutex(gh);
} else if (test_bit(GLF_DEMOTE, &gl->gl_flags)) { } else if (test_bit(GLF_DEMOTE, &gl->gl_flags)) {
blocked = rq_demote(gl); blocked = rq_demote(gl);
if (gl->gl_waiters2 && !blocked) { if (test_bit(GLF_WAITERS2, &gl->gl_flags) &&
!blocked) {
set_bit(GLF_DEMOTE, &gl->gl_flags); set_bit(GLF_DEMOTE, &gl->gl_flags);
gl->gl_demote_state = LM_ST_UNLOCKED; gl->gl_demote_state = LM_ST_UNLOCKED;
} }
gl->gl_waiters2 = 0; clear_bit(GLF_WAITERS2, &gl->gl_flags);
} else if (!list_empty(&gl->gl_waiters3)) { } else if (!list_empty(&gl->gl_waiters3)) {
gh = list_entry(gl->gl_waiters3.next, gh = list_entry(gl->gl_waiters3.next,
struct gfs2_holder, gh_list); struct gfs2_holder, gh_list);
...@@ -710,7 +719,7 @@ static void handle_callback(struct gfs2_glock *gl, unsigned int state, ...@@ -710,7 +719,7 @@ static void handle_callback(struct gfs2_glock *gl, unsigned int state,
} else if (gl->gl_demote_state != LM_ST_UNLOCKED && } else if (gl->gl_demote_state != LM_ST_UNLOCKED &&
gl->gl_demote_state != state) { gl->gl_demote_state != state) {
if (test_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags)) if (test_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags))
gl->gl_waiters2 = 1; set_bit(GLF_WAITERS2, &gl->gl_flags);
else else
gl->gl_demote_state = LM_ST_UNLOCKED; gl->gl_demote_state = LM_ST_UNLOCKED;
} }
...@@ -742,6 +751,43 @@ static void state_change(struct gfs2_glock *gl, unsigned int new_state) ...@@ -742,6 +751,43 @@ static void state_change(struct gfs2_glock *gl, unsigned int new_state)
gl->gl_tchange = jiffies; gl->gl_tchange = jiffies;
} }
/**
* drop_bh - Called after a lock module unlock completes
* @gl: the glock
* @ret: the return status
*
* Doesn't wake up the process waiting on the struct gfs2_holder (if any)
* Doesn't drop the reference on the glock the top half took out
*
*/
static void drop_bh(struct gfs2_glock *gl, unsigned int ret)
{
struct gfs2_sbd *sdp = gl->gl_sbd;
struct gfs2_holder *gh = gl->gl_req_gh;
gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags));
gfs2_assert_warn(sdp, list_empty(&gl->gl_holders));
gfs2_assert_warn(sdp, !ret);
state_change(gl, LM_ST_UNLOCKED);
if (test_and_clear_bit(GLF_CONV_DEADLK, &gl->gl_flags)) {
spin_lock(&gl->gl_spin);
gh->gh_error = 0;
spin_unlock(&gl->gl_spin);
gfs2_glock_xmote_th(gl, gl->gl_req_gh);
gfs2_glock_put(gl);
return;
}
spin_lock(&gl->gl_spin);
gfs2_demote_wake(gl);
clear_bit(GLF_LOCK, &gl->gl_flags);
spin_unlock(&gl->gl_spin);
gfs2_glock_put(gl);
}
/** /**
* xmote_bh - Called after the lock module is done acquiring a lock * xmote_bh - Called after the lock module is done acquiring a lock
* @gl: The glock in question * @gl: The glock in question
...@@ -754,25 +800,19 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret) ...@@ -754,25 +800,19 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret)
struct gfs2_sbd *sdp = gl->gl_sbd; struct gfs2_sbd *sdp = gl->gl_sbd;
const struct gfs2_glock_operations *glops = gl->gl_ops; const struct gfs2_glock_operations *glops = gl->gl_ops;
struct gfs2_holder *gh = gl->gl_req_gh; struct gfs2_holder *gh = gl->gl_req_gh;
int prev_state = gl->gl_state;
int op_done = 1; int op_done = 1;
if (!gh && (ret & LM_OUT_ST_MASK) == LM_ST_UNLOCKED) {
drop_bh(gl, ret);
return;
}
gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags)); gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags));
gfs2_assert_warn(sdp, list_empty(&gl->gl_holders)); gfs2_assert_warn(sdp, list_empty(&gl->gl_holders));
gfs2_assert_warn(sdp, !(ret & LM_OUT_ASYNC)); gfs2_assert_warn(sdp, !(ret & LM_OUT_ASYNC));
state_change(gl, ret & LM_OUT_ST_MASK); state_change(gl, ret & LM_OUT_ST_MASK);
if (prev_state != LM_ST_UNLOCKED && !(ret & LM_OUT_CACHEABLE)) {
if (glops->go_inval)
glops->go_inval(gl, DIO_METADATA);
} else if (gl->gl_state == LM_ST_DEFERRED) {
/* We might not want to do this here.
Look at moving to the inode glops. */
if (glops->go_inval)
glops->go_inval(gl, 0);
}
/* Deal with each possible exit condition */ /* Deal with each possible exit condition */
if (!gh) { if (!gh) {
...@@ -782,7 +822,6 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret) ...@@ -782,7 +822,6 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret)
} else { } else {
spin_lock(&gl->gl_spin); spin_lock(&gl->gl_spin);
if (gl->gl_state != gl->gl_demote_state) { if (gl->gl_state != gl->gl_demote_state) {
gl->gl_req_bh = NULL;
spin_unlock(&gl->gl_spin); spin_unlock(&gl->gl_spin);
gfs2_glock_drop_th(gl); gfs2_glock_drop_th(gl);
gfs2_glock_put(gl); gfs2_glock_put(gl);
...@@ -793,6 +832,14 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret) ...@@ -793,6 +832,14 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret)
} }
} else { } else {
spin_lock(&gl->gl_spin); spin_lock(&gl->gl_spin);
if (ret & LM_OUT_CONV_DEADLK) {
gh->gh_error = 0;
set_bit(GLF_CONV_DEADLK, &gl->gl_flags);
spin_unlock(&gl->gl_spin);
gfs2_glock_drop_th(gl);
gfs2_glock_put(gl);
return;
}
list_del_init(&gh->gh_list); list_del_init(&gh->gh_list);
gh->gh_error = -EIO; gh->gh_error = -EIO;
if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
...@@ -824,7 +871,6 @@ out: ...@@ -824,7 +871,6 @@ out:
if (op_done) { if (op_done) {
spin_lock(&gl->gl_spin); spin_lock(&gl->gl_spin);
gl->gl_req_gh = NULL; gl->gl_req_gh = NULL;
gl->gl_req_bh = NULL;
clear_bit(GLF_LOCK, &gl->gl_flags); clear_bit(GLF_LOCK, &gl->gl_flags);
spin_unlock(&gl->gl_spin); spin_unlock(&gl->gl_spin);
} }
...@@ -835,6 +881,17 @@ out: ...@@ -835,6 +881,17 @@ out:
gfs2_holder_wake(gh); gfs2_holder_wake(gh);
} }
static unsigned int gfs2_lm_lock(struct gfs2_sbd *sdp, void *lock,
unsigned int cur_state, unsigned int req_state,
unsigned int flags)
{
int ret = 0;
if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
ret = sdp->sd_lockstruct.ls_ops->lm_lock(lock, cur_state,
req_state, flags);
return ret;
}
/** /**
* gfs2_glock_xmote_th - Call into the lock module to acquire or change a glock * gfs2_glock_xmote_th - Call into the lock module to acquire or change a glock
* @gl: The glock in question * @gl: The glock in question
...@@ -856,6 +913,8 @@ static void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh) ...@@ -856,6 +913,8 @@ static void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh)
if (glops->go_xmote_th) if (glops->go_xmote_th)
glops->go_xmote_th(gl); glops->go_xmote_th(gl);
if (state == LM_ST_DEFERRED && glops->go_inval)
glops->go_inval(gl, DIO_METADATA);
gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags)); gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags));
gfs2_assert_warn(sdp, list_empty(&gl->gl_holders)); gfs2_assert_warn(sdp, list_empty(&gl->gl_holders));
...@@ -863,7 +922,6 @@ static void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh) ...@@ -863,7 +922,6 @@ static void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh)
gfs2_assert_warn(sdp, state != gl->gl_state); gfs2_assert_warn(sdp, state != gl->gl_state);
gfs2_glock_hold(gl); gfs2_glock_hold(gl);
gl->gl_req_bh = xmote_bh;
lck_ret = gfs2_lm_lock(sdp, gl->gl_lock, gl->gl_state, state, lck_flags); lck_ret = gfs2_lm_lock(sdp, gl->gl_lock, gl->gl_state, state, lck_flags);
...@@ -876,49 +934,13 @@ static void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh) ...@@ -876,49 +934,13 @@ static void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh)
xmote_bh(gl, lck_ret); xmote_bh(gl, lck_ret);
} }
/** static unsigned int gfs2_lm_unlock(struct gfs2_sbd *sdp, void *lock,
* drop_bh - Called after a lock module unlock completes unsigned int cur_state)
* @gl: the glock
* @ret: the return status
*
* Doesn't wake up the process waiting on the struct gfs2_holder (if any)
* Doesn't drop the reference on the glock the top half took out
*
*/
static void drop_bh(struct gfs2_glock *gl, unsigned int ret)
{ {
struct gfs2_sbd *sdp = gl->gl_sbd; int ret = 0;
const struct gfs2_glock_operations *glops = gl->gl_ops; if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
struct gfs2_holder *gh = gl->gl_req_gh; ret = sdp->sd_lockstruct.ls_ops->lm_unlock(lock, cur_state);
return ret;
gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags));
gfs2_assert_warn(sdp, list_empty(&gl->gl_holders));
gfs2_assert_warn(sdp, !ret);
state_change(gl, LM_ST_UNLOCKED);
if (glops->go_inval)
glops->go_inval(gl, DIO_METADATA);
if (gh) {
spin_lock(&gl->gl_spin);
list_del_init(&gh->gh_list);
gh->gh_error = 0;
spin_unlock(&gl->gl_spin);
}
spin_lock(&gl->gl_spin);
gfs2_demote_wake(gl);
gl->gl_req_gh = NULL;
gl->gl_req_bh = NULL;
clear_bit(GLF_LOCK, &gl->gl_flags);
spin_unlock(&gl->gl_spin);
gfs2_glock_put(gl);
if (gh)
gfs2_holder_wake(gh);
} }
/** /**
...@@ -935,13 +957,14 @@ static void gfs2_glock_drop_th(struct gfs2_glock *gl) ...@@ -935,13 +957,14 @@ static void gfs2_glock_drop_th(struct gfs2_glock *gl)
if (glops->go_xmote_th) if (glops->go_xmote_th)
glops->go_xmote_th(gl); glops->go_xmote_th(gl);
if (glops->go_inval)
glops->go_inval(gl, DIO_METADATA);
gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags)); gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags));
gfs2_assert_warn(sdp, list_empty(&gl->gl_holders)); gfs2_assert_warn(sdp, list_empty(&gl->gl_holders));
gfs2_assert_warn(sdp, gl->gl_state != LM_ST_UNLOCKED); gfs2_assert_warn(sdp, gl->gl_state != LM_ST_UNLOCKED);
gfs2_glock_hold(gl); gfs2_glock_hold(gl);
gl->gl_req_bh = drop_bh;
ret = gfs2_lm_unlock(sdp, gl->gl_lock, gl->gl_state); ret = gfs2_lm_unlock(sdp, gl->gl_lock, gl->gl_state);
...@@ -964,16 +987,17 @@ static void gfs2_glock_drop_th(struct gfs2_glock *gl) ...@@ -964,16 +987,17 @@ static void gfs2_glock_drop_th(struct gfs2_glock *gl)
static void do_cancels(struct gfs2_holder *gh) static void do_cancels(struct gfs2_holder *gh)
{ {
struct gfs2_glock *gl = gh->gh_gl; struct gfs2_glock *gl = gh->gh_gl;
struct gfs2_sbd *sdp = gl->gl_sbd;
spin_lock(&gl->gl_spin); spin_lock(&gl->gl_spin);
while (gl->gl_req_gh != gh && while (gl->gl_req_gh != gh &&
!test_bit(HIF_HOLDER, &gh->gh_iflags) && !test_bit(HIF_HOLDER, &gh->gh_iflags) &&
!list_empty(&gh->gh_list)) { !list_empty(&gh->gh_list)) {
if (gl->gl_req_bh && !(gl->gl_req_gh && if (!(gl->gl_req_gh && (gl->gl_req_gh->gh_flags & GL_NOCANCEL))) {
(gl->gl_req_gh->gh_flags & GL_NOCANCEL))) {
spin_unlock(&gl->gl_spin); spin_unlock(&gl->gl_spin);
gfs2_lm_cancel(gl->gl_sbd, gl->gl_lock); if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
sdp->sd_lockstruct.ls_ops->lm_cancel(gl->gl_lock);
msleep(100); msleep(100);
spin_lock(&gl->gl_spin); spin_lock(&gl->gl_spin);
} else { } else {
...@@ -1041,7 +1065,6 @@ static int glock_wait_internal(struct gfs2_holder *gh) ...@@ -1041,7 +1065,6 @@ static int glock_wait_internal(struct gfs2_holder *gh)
spin_lock(&gl->gl_spin); spin_lock(&gl->gl_spin);
gl->gl_req_gh = NULL; gl->gl_req_gh = NULL;
gl->gl_req_bh = NULL;
clear_bit(GLF_LOCK, &gl->gl_flags); clear_bit(GLF_LOCK, &gl->gl_flags);
run_queue(gl); run_queue(gl);
spin_unlock(&gl->gl_spin); spin_unlock(&gl->gl_spin);
...@@ -1428,6 +1451,14 @@ void gfs2_glock_dq_uninit_m(unsigned int num_gh, struct gfs2_holder *ghs) ...@@ -1428,6 +1451,14 @@ void gfs2_glock_dq_uninit_m(unsigned int num_gh, struct gfs2_holder *ghs)
gfs2_glock_dq_uninit(&ghs[x]); gfs2_glock_dq_uninit(&ghs[x]);
} }
static int gfs2_lm_hold_lvb(struct gfs2_sbd *sdp, void *lock, char **lvbp)
{
int error = -EIO;
if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
error = sdp->sd_lockstruct.ls_ops->lm_hold_lvb(lock, lvbp);
return error;
}
/** /**
* gfs2_lvb_hold - attach a LVB from a glock * gfs2_lvb_hold - attach a LVB from a glock
* @gl: The glock in question * @gl: The glock in question
...@@ -1463,12 +1494,15 @@ int gfs2_lvb_hold(struct gfs2_glock *gl) ...@@ -1463,12 +1494,15 @@ int gfs2_lvb_hold(struct gfs2_glock *gl)
void gfs2_lvb_unhold(struct gfs2_glock *gl) void gfs2_lvb_unhold(struct gfs2_glock *gl)
{ {
struct gfs2_sbd *sdp = gl->gl_sbd;
gfs2_glock_hold(gl); gfs2_glock_hold(gl);
gfs2_glmutex_lock(gl); gfs2_glmutex_lock(gl);
gfs2_assert(gl->gl_sbd, atomic_read(&gl->gl_lvb_count) > 0); gfs2_assert(gl->gl_sbd, atomic_read(&gl->gl_lvb_count) > 0);
if (atomic_dec_and_test(&gl->gl_lvb_count)) { if (atomic_dec_and_test(&gl->gl_lvb_count)) {
gfs2_lm_unhold_lvb(gl->gl_sbd, gl->gl_lock, gl->gl_lvb); if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
sdp->sd_lockstruct.ls_ops->lm_unhold_lvb(gl->gl_lock, gl->gl_lvb);
gl->gl_lvb = NULL; gl->gl_lvb = NULL;
gfs2_glock_put(gl); gfs2_glock_put(gl);
} }
...@@ -1534,8 +1568,7 @@ void gfs2_glock_cb(void *cb_data, unsigned int type, void *data) ...@@ -1534,8 +1568,7 @@ void gfs2_glock_cb(void *cb_data, unsigned int type, void *data)
gl = gfs2_glock_find(sdp, &async->lc_name); gl = gfs2_glock_find(sdp, &async->lc_name);
if (gfs2_assert_warn(sdp, gl)) if (gfs2_assert_warn(sdp, gl))
return; return;
if (!gfs2_assert_warn(sdp, gl->gl_req_bh)) xmote_bh(gl, async->lc_ret);
gl->gl_req_bh(gl, async->lc_ret);
if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0)
gfs2_glock_put(gl); gfs2_glock_put(gl);
up_read(&gfs2_umount_flush_sem); up_read(&gfs2_umount_flush_sem);
...@@ -1594,10 +1627,10 @@ void gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl) ...@@ -1594,10 +1627,10 @@ void gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl)
gfs2_glock_hold(gl); gfs2_glock_hold(gl);
list_add(&gl->gl_reclaim, &sdp->sd_reclaim_list); list_add(&gl->gl_reclaim, &sdp->sd_reclaim_list);
atomic_inc(&sdp->sd_reclaim_count); atomic_inc(&sdp->sd_reclaim_count);
} spin_unlock(&sdp->sd_reclaim_lock);
spin_unlock(&sdp->sd_reclaim_lock); wake_up(&sdp->sd_reclaim_wq);
} else
wake_up(&sdp->sd_reclaim_wq); spin_unlock(&sdp->sd_reclaim_lock);
} }
/** /**
...@@ -1897,7 +1930,6 @@ static int dump_glock(struct glock_iter *gi, struct gfs2_glock *gl) ...@@ -1897,7 +1930,6 @@ static int dump_glock(struct glock_iter *gi, struct gfs2_glock *gl)
print_dbg(gi, " gl_owner = -1\n"); print_dbg(gi, " gl_owner = -1\n");
print_dbg(gi, " gl_ip = %lu\n", gl->gl_ip); print_dbg(gi, " gl_ip = %lu\n", gl->gl_ip);
print_dbg(gi, " req_gh = %s\n", (gl->gl_req_gh) ? "yes" : "no"); print_dbg(gi, " req_gh = %s\n", (gl->gl_req_gh) ? "yes" : "no");
print_dbg(gi, " req_bh = %s\n", (gl->gl_req_bh) ? "yes" : "no");
print_dbg(gi, " lvb_count = %d\n", atomic_read(&gl->gl_lvb_count)); print_dbg(gi, " lvb_count = %d\n", atomic_read(&gl->gl_lvb_count));
print_dbg(gi, " object = %s\n", (gl->gl_object) ? "yes" : "no"); print_dbg(gi, " object = %s\n", (gl->gl_object) ? "yes" : "no");
print_dbg(gi, " reclaim = %s\n", print_dbg(gi, " reclaim = %s\n",
......
...@@ -32,24 +32,23 @@ ...@@ -32,24 +32,23 @@
#define GLR_TRYFAILED 13 #define GLR_TRYFAILED 13
#define GLR_CANCELED 14 #define GLR_CANCELED 14
static inline int gfs2_glock_is_locked_by_me(struct gfs2_glock *gl) static inline struct gfs2_holder *gfs2_glock_is_locked_by_me(struct gfs2_glock *gl)
{ {
struct gfs2_holder *gh; struct gfs2_holder *gh;
int locked = 0;
struct pid *pid; struct pid *pid;
/* Look in glock's list of holders for one with current task as owner */ /* Look in glock's list of holders for one with current task as owner */
spin_lock(&gl->gl_spin); spin_lock(&gl->gl_spin);
pid = task_pid(current); pid = task_pid(current);
list_for_each_entry(gh, &gl->gl_holders, gh_list) { list_for_each_entry(gh, &gl->gl_holders, gh_list) {
if (gh->gh_owner_pid == pid) { if (gh->gh_owner_pid == pid)
locked = 1; goto out;
break;
}
} }
gh = NULL;
out:
spin_unlock(&gl->gl_spin); spin_unlock(&gl->gl_spin);
return locked; return gh;
} }
static inline int gfs2_glock_is_held_excl(struct gfs2_glock *gl) static inline int gfs2_glock_is_held_excl(struct gfs2_glock *gl)
...@@ -79,7 +78,6 @@ static inline int gfs2_glock_is_blocking(struct gfs2_glock *gl) ...@@ -79,7 +78,6 @@ static inline int gfs2_glock_is_blocking(struct gfs2_glock *gl)
int gfs2_glock_get(struct gfs2_sbd *sdp, int gfs2_glock_get(struct gfs2_sbd *sdp,
u64 number, const struct gfs2_glock_operations *glops, u64 number, const struct gfs2_glock_operations *glops,
int create, struct gfs2_glock **glp); int create, struct gfs2_glock **glp);
void gfs2_glock_hold(struct gfs2_glock *gl);
int gfs2_glock_put(struct gfs2_glock *gl); int gfs2_glock_put(struct gfs2_glock *gl);
void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags, void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags,
struct gfs2_holder *gh); struct gfs2_holder *gh);
......
/* /*
* Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
* Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
* *
* This copyrighted material is made available to anyone wishing to use, * This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions * modify, copy, or redistribute it subject to the terms and conditions
...@@ -126,7 +126,13 @@ static void meta_go_inval(struct gfs2_glock *gl, int flags) ...@@ -126,7 +126,13 @@ static void meta_go_inval(struct gfs2_glock *gl, int flags)
return; return;
gfs2_meta_inval(gl); gfs2_meta_inval(gl);
gl->gl_vn++; if (gl->gl_object == GFS2_I(gl->gl_sbd->sd_rindex))
gl->gl_sbd->sd_rindex_uptodate = 0;
else if (gl->gl_ops == &gfs2_rgrp_glops && gl->gl_object) {
struct gfs2_rgrpd *rgd = (struct gfs2_rgrpd *)gl->gl_object;
rgd->rd_flags &= ~GFS2_RDF_UPTODATE;
}
} }
/** /**
......
/* /*
* Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
* Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
* *
* This copyrighted material is made available to anyone wishing to use, * This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions * modify, copy, or redistribute it subject to the terms and conditions
...@@ -44,7 +44,6 @@ struct gfs2_log_header_host { ...@@ -44,7 +44,6 @@ struct gfs2_log_header_host {
struct gfs2_log_operations { struct gfs2_log_operations {
void (*lo_add) (struct gfs2_sbd *sdp, struct gfs2_log_element *le); void (*lo_add) (struct gfs2_sbd *sdp, struct gfs2_log_element *le);
void (*lo_incore_commit) (struct gfs2_sbd *sdp, struct gfs2_trans *tr);
void (*lo_before_commit) (struct gfs2_sbd *sdp); void (*lo_before_commit) (struct gfs2_sbd *sdp);
void (*lo_after_commit) (struct gfs2_sbd *sdp, struct gfs2_ail *ai); void (*lo_after_commit) (struct gfs2_sbd *sdp, struct gfs2_ail *ai);
void (*lo_before_scan) (struct gfs2_jdesc *jd, void (*lo_before_scan) (struct gfs2_jdesc *jd,
...@@ -70,7 +69,6 @@ struct gfs2_bitmap { ...@@ -70,7 +69,6 @@ struct gfs2_bitmap {
}; };
struct gfs2_rgrp_host { struct gfs2_rgrp_host {
u32 rg_flags;
u32 rg_free; u32 rg_free;
u32 rg_dinodes; u32 rg_dinodes;
u64 rg_igeneration; u64 rg_igeneration;
...@@ -87,17 +85,17 @@ struct gfs2_rgrpd { ...@@ -87,17 +85,17 @@ struct gfs2_rgrpd {
u32 rd_data; /* num of data blocks in rgrp */ u32 rd_data; /* num of data blocks in rgrp */
u32 rd_bitbytes; /* number of bytes in data bitmaps */ u32 rd_bitbytes; /* number of bytes in data bitmaps */
struct gfs2_rgrp_host rd_rg; struct gfs2_rgrp_host rd_rg;
u64 rd_rg_vn;
struct gfs2_bitmap *rd_bits; struct gfs2_bitmap *rd_bits;
unsigned int rd_bh_count; unsigned int rd_bh_count;
struct mutex rd_mutex; struct mutex rd_mutex;
u32 rd_free_clone; u32 rd_free_clone;
struct gfs2_log_element rd_le; struct gfs2_log_element rd_le;
u32 rd_last_alloc_data; u32 rd_last_alloc;
u32 rd_last_alloc_meta;
struct gfs2_sbd *rd_sbd; struct gfs2_sbd *rd_sbd;
unsigned long rd_flags; unsigned char rd_flags;
#define GFS2_RDF_CHECK 0x0001 /* Need to check for unlinked inodes */ #define GFS2_RDF_CHECK 0x01 /* Need to check for unlinked inodes */
#define GFS2_RDF_NOALLOC 0x02 /* rg prohibits allocation */
#define GFS2_RDF_UPTODATE 0x04 /* rg is up to date */
}; };
enum gfs2_state_bits { enum gfs2_state_bits {
...@@ -168,6 +166,8 @@ enum { ...@@ -168,6 +166,8 @@ enum {
GLF_DIRTY = 5, GLF_DIRTY = 5,
GLF_DEMOTE_IN_PROGRESS = 6, GLF_DEMOTE_IN_PROGRESS = 6,
GLF_LFLUSH = 7, GLF_LFLUSH = 7,
GLF_WAITERS2 = 8,
GLF_CONV_DEADLK = 9,
}; };
struct gfs2_glock { struct gfs2_glock {
...@@ -187,18 +187,15 @@ struct gfs2_glock { ...@@ -187,18 +187,15 @@ struct gfs2_glock {
struct list_head gl_holders; struct list_head gl_holders;
struct list_head gl_waiters1; /* HIF_MUTEX */ struct list_head gl_waiters1; /* HIF_MUTEX */
struct list_head gl_waiters3; /* HIF_PROMOTE */ struct list_head gl_waiters3; /* HIF_PROMOTE */
int gl_waiters2; /* GIF_DEMOTE */
const struct gfs2_glock_operations *gl_ops; const struct gfs2_glock_operations *gl_ops;
struct gfs2_holder *gl_req_gh; struct gfs2_holder *gl_req_gh;
gfs2_glop_bh_t gl_req_bh;
void *gl_lock; void *gl_lock;
char *gl_lvb; char *gl_lvb;
atomic_t gl_lvb_count; atomic_t gl_lvb_count;
u64 gl_vn;
unsigned long gl_stamp; unsigned long gl_stamp;
unsigned long gl_tchange; unsigned long gl_tchange;
void *gl_object; void *gl_object;
...@@ -213,6 +210,8 @@ struct gfs2_glock { ...@@ -213,6 +210,8 @@ struct gfs2_glock {
struct delayed_work gl_work; struct delayed_work gl_work;
}; };
#define GFS2_MIN_LVB_SIZE 32 /* Min size of LVB that gfs2 supports */
struct gfs2_alloc { struct gfs2_alloc {
/* Quota stuff */ /* Quota stuff */
...@@ -241,14 +240,9 @@ enum { ...@@ -241,14 +240,9 @@ enum {
struct gfs2_dinode_host { struct gfs2_dinode_host {
u64 di_size; /* number of bytes in file */ u64 di_size; /* number of bytes in file */
u64 di_blocks; /* number of blocks in file */
u64 di_goal_meta; /* rgrp to alloc from next */
u64 di_goal_data; /* data block goal */
u64 di_generation; /* generation number for NFS */ u64 di_generation; /* generation number for NFS */
u32 di_flags; /* GFS2_DIF_... */ u32 di_flags; /* GFS2_DIF_... */
u16 di_height; /* height of metadata */
/* These only apply to directories */ /* These only apply to directories */
u16 di_depth; /* Number of bits in the table */
u32 di_entries; /* The number of entries in the directory */ u32 di_entries; /* The number of entries in the directory */
u64 di_eattr; /* extended attribute block number */ u64 di_eattr; /* extended attribute block number */
}; };
...@@ -265,9 +259,10 @@ struct gfs2_inode { ...@@ -265,9 +259,10 @@ struct gfs2_inode {
struct gfs2_holder i_iopen_gh; struct gfs2_holder i_iopen_gh;
struct gfs2_holder i_gh; /* for prepare/commit_write only */ struct gfs2_holder i_gh; /* for prepare/commit_write only */
struct gfs2_alloc *i_alloc; struct gfs2_alloc *i_alloc;
u64 i_last_rg_alloc; u64 i_goal; /* goal block for allocations */
struct rw_semaphore i_rw_mutex; struct rw_semaphore i_rw_mutex;
u8 i_height;
u8 i_depth;
}; };
/* /*
...@@ -490,9 +485,9 @@ struct gfs2_sbd { ...@@ -490,9 +485,9 @@ struct gfs2_sbd {
u32 sd_qc_per_block; u32 sd_qc_per_block;
u32 sd_max_dirres; /* Max blocks needed to add a directory entry */ u32 sd_max_dirres; /* Max blocks needed to add a directory entry */
u32 sd_max_height; /* Max height of a file's metadata tree */ u32 sd_max_height; /* Max height of a file's metadata tree */
u64 sd_heightsize[GFS2_MAX_META_HEIGHT]; u64 sd_heightsize[GFS2_MAX_META_HEIGHT + 1];
u32 sd_max_jheight; /* Max height of journaled file's meta tree */ u32 sd_max_jheight; /* Max height of journaled file's meta tree */
u64 sd_jheightsize[GFS2_MAX_META_HEIGHT]; u64 sd_jheightsize[GFS2_MAX_META_HEIGHT + 1];
struct gfs2_args sd_args; /* Mount arguments */ struct gfs2_args sd_args; /* Mount arguments */
struct gfs2_tune sd_tune; /* Filesystem tuning structure */ struct gfs2_tune sd_tune; /* Filesystem tuning structure */
...@@ -533,7 +528,7 @@ struct gfs2_sbd { ...@@ -533,7 +528,7 @@ struct gfs2_sbd {
/* Resource group stuff */ /* Resource group stuff */
u64 sd_rindex_vn; int sd_rindex_uptodate;
spinlock_t sd_rindex_spin; spinlock_t sd_rindex_spin;
struct mutex sd_rindex_mutex; struct mutex sd_rindex_mutex;
struct list_head sd_rindex_list; struct list_head sd_rindex_list;
...@@ -637,9 +632,6 @@ struct gfs2_sbd { ...@@ -637,9 +632,6 @@ struct gfs2_sbd {
/* Counters */ /* Counters */
atomic_t sd_glock_count;
atomic_t sd_glock_held_count;
atomic_t sd_inode_count;
atomic_t sd_reclaimed; atomic_t sd_reclaimed;
char sd_fsname[GFS2_FSNAME_LEN]; char sd_fsname[GFS2_FSNAME_LEN];
......
/* /*
* Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
* Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
* *
* This copyrighted material is made available to anyone wishing to use, * This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions * modify, copy, or redistribute it subject to the terms and conditions
...@@ -149,7 +149,8 @@ void gfs2_set_iop(struct inode *inode) ...@@ -149,7 +149,8 @@ void gfs2_set_iop(struct inode *inode)
} else if (S_ISLNK(mode)) { } else if (S_ISLNK(mode)) {
inode->i_op = &gfs2_symlink_iops; inode->i_op = &gfs2_symlink_iops;
} else { } else {
inode->i_op = &gfs2_dev_iops; inode->i_op = &gfs2_file_iops;
init_special_inode(inode, inode->i_mode, inode->i_rdev);
} }
unlock_new_inode(inode); unlock_new_inode(inode);
...@@ -248,12 +249,10 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) ...@@ -248,12 +249,10 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
{ {
struct gfs2_dinode_host *di = &ip->i_di; struct gfs2_dinode_host *di = &ip->i_di;
const struct gfs2_dinode *str = buf; const struct gfs2_dinode *str = buf;
u16 height, depth;
if (ip->i_no_addr != be64_to_cpu(str->di_num.no_addr)) { if (unlikely(ip->i_no_addr != be64_to_cpu(str->di_num.no_addr)))
if (gfs2_consist_inode(ip)) goto corrupt;
gfs2_dinode_print(ip);
return -EIO;
}
ip->i_no_formal_ino = be64_to_cpu(str->di_num.no_formal_ino); ip->i_no_formal_ino = be64_to_cpu(str->di_num.no_formal_ino);
ip->i_inode.i_mode = be32_to_cpu(str->di_mode); ip->i_inode.i_mode = be32_to_cpu(str->di_mode);
ip->i_inode.i_rdev = 0; ip->i_inode.i_rdev = 0;
...@@ -275,8 +274,7 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) ...@@ -275,8 +274,7 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
ip->i_inode.i_nlink = be32_to_cpu(str->di_nlink); ip->i_inode.i_nlink = be32_to_cpu(str->di_nlink);
di->di_size = be64_to_cpu(str->di_size); di->di_size = be64_to_cpu(str->di_size);
i_size_write(&ip->i_inode, di->di_size); i_size_write(&ip->i_inode, di->di_size);
di->di_blocks = be64_to_cpu(str->di_blocks); gfs2_set_inode_blocks(&ip->i_inode, be64_to_cpu(str->di_blocks));
gfs2_set_inode_blocks(&ip->i_inode);
ip->i_inode.i_atime.tv_sec = be64_to_cpu(str->di_atime); ip->i_inode.i_atime.tv_sec = be64_to_cpu(str->di_atime);
ip->i_inode.i_atime.tv_nsec = be32_to_cpu(str->di_atime_nsec); ip->i_inode.i_atime.tv_nsec = be32_to_cpu(str->di_atime_nsec);
ip->i_inode.i_mtime.tv_sec = be64_to_cpu(str->di_mtime); ip->i_inode.i_mtime.tv_sec = be64_to_cpu(str->di_mtime);
...@@ -284,15 +282,20 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) ...@@ -284,15 +282,20 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
ip->i_inode.i_ctime.tv_sec = be64_to_cpu(str->di_ctime); ip->i_inode.i_ctime.tv_sec = be64_to_cpu(str->di_ctime);
ip->i_inode.i_ctime.tv_nsec = be32_to_cpu(str->di_ctime_nsec); ip->i_inode.i_ctime.tv_nsec = be32_to_cpu(str->di_ctime_nsec);
di->di_goal_meta = be64_to_cpu(str->di_goal_meta); ip->i_goal = be64_to_cpu(str->di_goal_meta);
di->di_goal_data = be64_to_cpu(str->di_goal_data);
di->di_generation = be64_to_cpu(str->di_generation); di->di_generation = be64_to_cpu(str->di_generation);
di->di_flags = be32_to_cpu(str->di_flags); di->di_flags = be32_to_cpu(str->di_flags);
gfs2_set_inode_flags(&ip->i_inode); gfs2_set_inode_flags(&ip->i_inode);
di->di_height = be16_to_cpu(str->di_height); height = be16_to_cpu(str->di_height);
if (unlikely(height > GFS2_MAX_META_HEIGHT))
di->di_depth = be16_to_cpu(str->di_depth); goto corrupt;
ip->i_height = (u8)height;
depth = be16_to_cpu(str->di_depth);
if (unlikely(depth > GFS2_DIR_MAX_DEPTH))
goto corrupt;
ip->i_depth = (u8)depth;
di->di_entries = be32_to_cpu(str->di_entries); di->di_entries = be32_to_cpu(str->di_entries);
di->di_eattr = be64_to_cpu(str->di_eattr); di->di_eattr = be64_to_cpu(str->di_eattr);
...@@ -300,6 +303,10 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) ...@@ -300,6 +303,10 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
gfs2_set_aops(&ip->i_inode); gfs2_set_aops(&ip->i_inode);
return 0; return 0;
corrupt:
if (gfs2_consist_inode(ip))
gfs2_dinode_print(ip);
return -EIO;
} }
/** /**
...@@ -337,13 +344,15 @@ int gfs2_dinode_dealloc(struct gfs2_inode *ip) ...@@ -337,13 +344,15 @@ int gfs2_dinode_dealloc(struct gfs2_inode *ip)
struct gfs2_rgrpd *rgd; struct gfs2_rgrpd *rgd;
int error; int error;
if (ip->i_di.di_blocks != 1) { if (gfs2_get_inode_blocks(&ip->i_inode) != 1) {
if (gfs2_consist_inode(ip)) if (gfs2_consist_inode(ip))
gfs2_dinode_print(ip); gfs2_dinode_print(ip);
return -EIO; return -EIO;
} }
al = gfs2_alloc_get(ip); al = gfs2_alloc_get(ip);
if (!al)
return -ENOMEM;
error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
if (error) if (error)
...@@ -487,7 +496,7 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, ...@@ -487,7 +496,7 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
return dir; return dir;
} }
if (gfs2_glock_is_locked_by_me(dip->i_gl) == 0) { if (gfs2_glock_is_locked_by_me(dip->i_gl) == NULL) {
error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh); error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh);
if (error) if (error)
return ERR_PTR(error); return ERR_PTR(error);
...@@ -818,7 +827,8 @@ static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, ...@@ -818,7 +827,8 @@ static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl,
int error; int error;
munge_mode_uid_gid(dip, &mode, &uid, &gid); munge_mode_uid_gid(dip, &mode, &uid, &gid);
gfs2_alloc_get(dip); if (!gfs2_alloc_get(dip))
return -ENOMEM;
error = gfs2_quota_lock(dip, uid, gid); error = gfs2_quota_lock(dip, uid, gid);
if (error) if (error)
...@@ -853,6 +863,8 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name, ...@@ -853,6 +863,8 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name,
int error; int error;
al = gfs2_alloc_get(dip); al = gfs2_alloc_get(dip);
if (!al)
return -ENOMEM;
error = gfs2_quota_lock(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); error = gfs2_quota_lock(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
if (error) if (error)
...@@ -1219,7 +1231,7 @@ int gfs2_readlinki(struct gfs2_inode *ip, char **buf, unsigned int *len) ...@@ -1219,7 +1231,7 @@ int gfs2_readlinki(struct gfs2_inode *ip, char **buf, unsigned int *len)
x = ip->i_di.di_size + 1; x = ip->i_di.di_size + 1;
if (x > *len) { if (x > *len) {
*buf = kmalloc(x, GFP_KERNEL); *buf = kmalloc(x, GFP_NOFS);
if (!*buf) { if (!*buf) {
error = -ENOMEM; error = -ENOMEM;
goto out_brelse; goto out_brelse;
...@@ -1391,21 +1403,21 @@ void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf) ...@@ -1391,21 +1403,21 @@ void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf)
str->di_gid = cpu_to_be32(ip->i_inode.i_gid); str->di_gid = cpu_to_be32(ip->i_inode.i_gid);
str->di_nlink = cpu_to_be32(ip->i_inode.i_nlink); str->di_nlink = cpu_to_be32(ip->i_inode.i_nlink);
str->di_size = cpu_to_be64(di->di_size); str->di_size = cpu_to_be64(di->di_size);
str->di_blocks = cpu_to_be64(di->di_blocks); str->di_blocks = cpu_to_be64(gfs2_get_inode_blocks(&ip->i_inode));
str->di_atime = cpu_to_be64(ip->i_inode.i_atime.tv_sec); str->di_atime = cpu_to_be64(ip->i_inode.i_atime.tv_sec);
str->di_mtime = cpu_to_be64(ip->i_inode.i_mtime.tv_sec); str->di_mtime = cpu_to_be64(ip->i_inode.i_mtime.tv_sec);
str->di_ctime = cpu_to_be64(ip->i_inode.i_ctime.tv_sec); str->di_ctime = cpu_to_be64(ip->i_inode.i_ctime.tv_sec);
str->di_goal_meta = cpu_to_be64(di->di_goal_meta); str->di_goal_meta = cpu_to_be64(ip->i_goal);
str->di_goal_data = cpu_to_be64(di->di_goal_data); str->di_goal_data = cpu_to_be64(ip->i_goal);
str->di_generation = cpu_to_be64(di->di_generation); str->di_generation = cpu_to_be64(di->di_generation);
str->di_flags = cpu_to_be32(di->di_flags); str->di_flags = cpu_to_be32(di->di_flags);
str->di_height = cpu_to_be16(di->di_height); str->di_height = cpu_to_be16(ip->i_height);
str->di_payload_format = cpu_to_be32(S_ISDIR(ip->i_inode.i_mode) && str->di_payload_format = cpu_to_be32(S_ISDIR(ip->i_inode.i_mode) &&
!(ip->i_di.di_flags & GFS2_DIF_EXHASH) ? !(ip->i_di.di_flags & GFS2_DIF_EXHASH) ?
GFS2_FORMAT_DE : 0); GFS2_FORMAT_DE : 0);
str->di_depth = cpu_to_be16(di->di_depth); str->di_depth = cpu_to_be16(ip->i_depth);
str->di_entries = cpu_to_be32(di->di_entries); str->di_entries = cpu_to_be32(di->di_entries);
str->di_eattr = cpu_to_be64(di->di_eattr); str->di_eattr = cpu_to_be64(di->di_eattr);
...@@ -1423,15 +1435,13 @@ void gfs2_dinode_print(const struct gfs2_inode *ip) ...@@ -1423,15 +1435,13 @@ void gfs2_dinode_print(const struct gfs2_inode *ip)
printk(KERN_INFO " no_addr = %llu\n", printk(KERN_INFO " no_addr = %llu\n",
(unsigned long long)ip->i_no_addr); (unsigned long long)ip->i_no_addr);
printk(KERN_INFO " di_size = %llu\n", (unsigned long long)di->di_size); printk(KERN_INFO " di_size = %llu\n", (unsigned long long)di->di_size);
printk(KERN_INFO " di_blocks = %llu\n", printk(KERN_INFO " blocks = %llu\n",
(unsigned long long)di->di_blocks); (unsigned long long)gfs2_get_inode_blocks(&ip->i_inode));
printk(KERN_INFO " di_goal_meta = %llu\n", printk(KERN_INFO " i_goal = %llu\n",
(unsigned long long)di->di_goal_meta); (unsigned long long)ip->i_goal);
printk(KERN_INFO " di_goal_data = %llu\n",
(unsigned long long)di->di_goal_data);
printk(KERN_INFO " di_flags = 0x%.8X\n", di->di_flags); printk(KERN_INFO " di_flags = 0x%.8X\n", di->di_flags);
printk(KERN_INFO " di_height = %u\n", di->di_height); printk(KERN_INFO " i_height = %u\n", ip->i_height);
printk(KERN_INFO " di_depth = %u\n", di->di_depth); printk(KERN_INFO " i_depth = %u\n", ip->i_depth);
printk(KERN_INFO " di_entries = %u\n", di->di_entries); printk(KERN_INFO " di_entries = %u\n", di->di_entries);
printk(KERN_INFO " di_eattr = %llu\n", printk(KERN_INFO " di_eattr = %llu\n",
(unsigned long long)di->di_eattr); (unsigned long long)di->di_eattr);
......
...@@ -10,9 +10,11 @@ ...@@ -10,9 +10,11 @@
#ifndef __INODE_DOT_H__ #ifndef __INODE_DOT_H__
#define __INODE_DOT_H__ #define __INODE_DOT_H__
#include "util.h"
static inline int gfs2_is_stuffed(const struct gfs2_inode *ip) static inline int gfs2_is_stuffed(const struct gfs2_inode *ip)
{ {
return !ip->i_di.di_height; return !ip->i_height;
} }
static inline int gfs2_is_jdata(const struct gfs2_inode *ip) static inline int gfs2_is_jdata(const struct gfs2_inode *ip)
...@@ -37,13 +39,25 @@ static inline int gfs2_is_dir(const struct gfs2_inode *ip) ...@@ -37,13 +39,25 @@ static inline int gfs2_is_dir(const struct gfs2_inode *ip)
return S_ISDIR(ip->i_inode.i_mode); return S_ISDIR(ip->i_inode.i_mode);
} }
static inline void gfs2_set_inode_blocks(struct inode *inode) static inline void gfs2_set_inode_blocks(struct inode *inode, u64 blocks)
{
inode->i_blocks = blocks <<
(GFS2_SB(inode)->sd_sb.sb_bsize_shift - GFS2_BASIC_BLOCK_SHIFT);
}
static inline u64 gfs2_get_inode_blocks(const struct inode *inode)
{ {
struct gfs2_inode *ip = GFS2_I(inode); return inode->i_blocks >>
inode->i_blocks = ip->i_di.di_blocks <<
(GFS2_SB(inode)->sd_sb.sb_bsize_shift - GFS2_BASIC_BLOCK_SHIFT); (GFS2_SB(inode)->sd_sb.sb_bsize_shift - GFS2_BASIC_BLOCK_SHIFT);
} }
static inline void gfs2_add_inode_blocks(struct inode *inode, s64 change)
{
gfs2_assert(GFS2_SB(inode), (change >= 0 || inode->i_blocks > -change));
change *= (GFS2_SB(inode)->sd_sb.sb_bsize/GFS2_BASIC_BLOCK);
inode->i_blocks += change;
}
static inline int gfs2_check_inum(const struct gfs2_inode *ip, u64 no_addr, static inline int gfs2_check_inum(const struct gfs2_inode *ip, u64 no_addr,
u64 no_formal_ino) u64 no_formal_ino)
{ {
......
/*
* Copyright (C) Sistina Software, Inc. 1997-2003 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
* of the GNU General Public License version 2.
*/
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/buffer_head.h>
#include <linux/delay.h>
#include <linux/gfs2_ondisk.h>
#include <linux/lm_interface.h>
#include "gfs2.h"
#include "incore.h"
#include "glock.h"
#include "lm.h"
#include "super.h"
#include "util.h"
/**
* gfs2_lm_mount - mount a locking protocol
* @sdp: the filesystem
* @args: mount arguements
* @silent: if 1, don't complain if the FS isn't a GFS2 fs
*
* Returns: errno
*/
int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent)
{
char *proto = sdp->sd_proto_name;
char *table = sdp->sd_table_name;
int flags = 0;
int error;
if (sdp->sd_args.ar_spectator)
flags |= LM_MFLAG_SPECTATOR;
fs_info(sdp, "Trying to join cluster \"%s\", \"%s\"\n", proto, table);
error = gfs2_mount_lockproto(proto, table, sdp->sd_args.ar_hostdata,
gfs2_glock_cb, sdp,
GFS2_MIN_LVB_SIZE, flags,
&sdp->sd_lockstruct, &sdp->sd_kobj);
if (error) {
fs_info(sdp, "can't mount proto=%s, table=%s, hostdata=%s\n",
proto, table, sdp->sd_args.ar_hostdata);
goto out;
}
if (gfs2_assert_warn(sdp, sdp->sd_lockstruct.ls_lockspace) ||
gfs2_assert_warn(sdp, sdp->sd_lockstruct.ls_ops) ||
gfs2_assert_warn(sdp, sdp->sd_lockstruct.ls_lvb_size >=
GFS2_MIN_LVB_SIZE)) {
gfs2_unmount_lockproto(&sdp->sd_lockstruct);
goto out;
}
if (sdp->sd_args.ar_spectator)
snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s.s", table);
else
snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s.%u", table,
sdp->sd_lockstruct.ls_jid);
fs_info(sdp, "Joined cluster. Now mounting FS...\n");
if ((sdp->sd_lockstruct.ls_flags & LM_LSFLAG_LOCAL) &&
!sdp->sd_args.ar_ignore_local_fs) {
sdp->sd_args.ar_localflocks = 1;
sdp->sd_args.ar_localcaching = 1;
}
out:
return error;
}
void gfs2_lm_others_may_mount(struct gfs2_sbd *sdp)
{
if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
sdp->sd_lockstruct.ls_ops->lm_others_may_mount(
sdp->sd_lockstruct.ls_lockspace);
}
void gfs2_lm_unmount(struct gfs2_sbd *sdp)
{
if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
gfs2_unmount_lockproto(&sdp->sd_lockstruct);
}
int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...)
{
va_list args;
if (test_and_set_bit(SDF_SHUTDOWN, &sdp->sd_flags))
return 0;
va_start(args, fmt);
vprintk(fmt, args);
va_end(args);
fs_err(sdp, "about to withdraw this file system\n");
BUG_ON(sdp->sd_args.ar_debug);
fs_err(sdp, "telling LM to withdraw\n");
gfs2_withdraw_lockproto(&sdp->sd_lockstruct);
fs_err(sdp, "withdrawn\n");
dump_stack();
return -1;
}
int gfs2_lm_get_lock(struct gfs2_sbd *sdp, struct lm_lockname *name,
void **lockp)
{
int error = -EIO;
if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
error = sdp->sd_lockstruct.ls_ops->lm_get_lock(
sdp->sd_lockstruct.ls_lockspace, name, lockp);
return error;
}
void gfs2_lm_put_lock(struct gfs2_sbd *sdp, void *lock)
{
if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
sdp->sd_lockstruct.ls_ops->lm_put_lock(lock);
}
unsigned int gfs2_lm_lock(struct gfs2_sbd *sdp, void *lock,
unsigned int cur_state, unsigned int req_state,
unsigned int flags)
{
int ret = 0;
if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
ret = sdp->sd_lockstruct.ls_ops->lm_lock(lock, cur_state,
req_state, flags);
return ret;
}
unsigned int gfs2_lm_unlock(struct gfs2_sbd *sdp, void *lock,
unsigned int cur_state)
{
int ret = 0;
if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
ret = sdp->sd_lockstruct.ls_ops->lm_unlock(lock, cur_state);
return ret;
}
void gfs2_lm_cancel(struct gfs2_sbd *sdp, void *lock)
{
if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
sdp->sd_lockstruct.ls_ops->lm_cancel(lock);
}
int gfs2_lm_hold_lvb(struct gfs2_sbd *sdp, void *lock, char **lvbp)
{
int error = -EIO;
if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
error = sdp->sd_lockstruct.ls_ops->lm_hold_lvb(lock, lvbp);
return error;
}
void gfs2_lm_unhold_lvb(struct gfs2_sbd *sdp, void *lock, char *lvb)
{
if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
sdp->sd_lockstruct.ls_ops->lm_unhold_lvb(lock, lvb);
}
int gfs2_lm_plock_get(struct gfs2_sbd *sdp, struct lm_lockname *name,
struct file *file, struct file_lock *fl)
{
int error = -EIO;
if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
error = sdp->sd_lockstruct.ls_ops->lm_plock_get(
sdp->sd_lockstruct.ls_lockspace, name, file, fl);
return error;
}
int gfs2_lm_plock(struct gfs2_sbd *sdp, struct lm_lockname *name,
struct file *file, int cmd, struct file_lock *fl)
{
int error = -EIO;
if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
error = sdp->sd_lockstruct.ls_ops->lm_plock(
sdp->sd_lockstruct.ls_lockspace, name, file, cmd, fl);
return error;
}
int gfs2_lm_punlock(struct gfs2_sbd *sdp, struct lm_lockname *name,
struct file *file, struct file_lock *fl)
{
int error = -EIO;
if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
error = sdp->sd_lockstruct.ls_ops->lm_punlock(
sdp->sd_lockstruct.ls_lockspace, name, file, fl);
return error;
}
void gfs2_lm_recovery_done(struct gfs2_sbd *sdp, unsigned int jid,
unsigned int message)
{
if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
sdp->sd_lockstruct.ls_ops->lm_recovery_done(
sdp->sd_lockstruct.ls_lockspace, jid, message);
}
/*
* Copyright (C) Sistina Software, Inc. 1997-2003 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
* of the GNU General Public License version 2.
*/
#ifndef __LM_DOT_H__
#define __LM_DOT_H__
struct gfs2_sbd;
#define GFS2_MIN_LVB_SIZE 32
int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent);
void gfs2_lm_others_may_mount(struct gfs2_sbd *sdp);
void gfs2_lm_unmount(struct gfs2_sbd *sdp);
int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...)
__attribute__ ((format(printf, 2, 3)));
int gfs2_lm_get_lock(struct gfs2_sbd *sdp, struct lm_lockname *name,
void **lockp);
void gfs2_lm_put_lock(struct gfs2_sbd *sdp, void *lock);
unsigned int gfs2_lm_lock(struct gfs2_sbd *sdp, void *lock,
unsigned int cur_state, unsigned int req_state,
unsigned int flags);
unsigned int gfs2_lm_unlock(struct gfs2_sbd *sdp, void *lock,
unsigned int cur_state);
void gfs2_lm_cancel(struct gfs2_sbd *sdp, void *lock);
int gfs2_lm_hold_lvb(struct gfs2_sbd *sdp, void *lock, char **lvbp);
void gfs2_lm_unhold_lvb(struct gfs2_sbd *sdp, void *lock, char *lvb);
int gfs2_lm_plock_get(struct gfs2_sbd *sdp, struct lm_lockname *name,
struct file *file, struct file_lock *fl);
int gfs2_lm_plock(struct gfs2_sbd *sdp, struct lm_lockname *name,
struct file *file, int cmd, struct file_lock *fl);
int gfs2_lm_punlock(struct gfs2_sbd *sdp, struct lm_lockname *name,
struct file *file, struct file_lock *fl);
void gfs2_lm_recovery_done(struct gfs2_sbd *sdp, unsigned int jid,
unsigned int message);
#endif /* __LM_DOT_H__ */
...@@ -137,7 +137,8 @@ static inline unsigned int make_flags(struct gdlm_lock *lp, ...@@ -137,7 +137,8 @@ static inline unsigned int make_flags(struct gdlm_lock *lp,
/* Conversion deadlock avoidance by DLM */ /* Conversion deadlock avoidance by DLM */
if (!test_bit(LFL_FORCE_PROMOTE, &lp->flags) && if (!(lp->ls->fsflags & LM_MFLAG_CONV_NODROP) &&
!test_bit(LFL_FORCE_PROMOTE, &lp->flags) &&
!(lkf & DLM_LKF_NOQUEUE) && !(lkf & DLM_LKF_NOQUEUE) &&
cur > DLM_LOCK_NL && req > DLM_LOCK_NL && cur != req) cur > DLM_LOCK_NL && req > DLM_LOCK_NL && cur != req)
lkf |= DLM_LKF_CONVDEADLK; lkf |= DLM_LKF_CONVDEADLK;
...@@ -164,7 +165,7 @@ static int gdlm_create_lp(struct gdlm_ls *ls, struct lm_lockname *name, ...@@ -164,7 +165,7 @@ static int gdlm_create_lp(struct gdlm_ls *ls, struct lm_lockname *name,
{ {
struct gdlm_lock *lp; struct gdlm_lock *lp;
lp = kzalloc(sizeof(struct gdlm_lock), GFP_KERNEL); lp = kzalloc(sizeof(struct gdlm_lock), GFP_NOFS);
if (!lp) if (!lp)
return -ENOMEM; return -ENOMEM;
...@@ -382,7 +383,7 @@ static int gdlm_add_lvb(struct gdlm_lock *lp) ...@@ -382,7 +383,7 @@ static int gdlm_add_lvb(struct gdlm_lock *lp)
{ {
char *lvb; char *lvb;
lvb = kzalloc(GDLM_LVB_SIZE, GFP_KERNEL); lvb = kzalloc(GDLM_LVB_SIZE, GFP_NOFS);
if (!lvb) if (!lvb)
return -ENOMEM; return -ENOMEM;
......
...@@ -183,5 +183,10 @@ int gdlm_plock_get(void *, struct lm_lockname *, struct file *, ...@@ -183,5 +183,10 @@ int gdlm_plock_get(void *, struct lm_lockname *, struct file *,
struct file_lock *); struct file_lock *);
int gdlm_punlock(void *, struct lm_lockname *, struct file *, int gdlm_punlock(void *, struct lm_lockname *, struct file *,
struct file_lock *); struct file_lock *);
/* mount.c */
extern const struct lm_lockops gdlm_ops;
#endif #endif
...@@ -11,8 +11,6 @@ ...@@ -11,8 +11,6 @@
#include "lock_dlm.h" #include "lock_dlm.h"
extern struct lm_lockops gdlm_ops;
static int __init init_lock_dlm(void) static int __init init_lock_dlm(void)
{ {
int error; int error;
......
...@@ -12,8 +12,6 @@ ...@@ -12,8 +12,6 @@
#include "lock_dlm.h" #include "lock_dlm.h"
extern struct lm_lockops gdlm_ops;
static ssize_t proto_name_show(struct gdlm_ls *ls, char *buf) static ssize_t proto_name_show(struct gdlm_ls *ls, char *buf)
{ {
return sprintf(buf, "%s\n", gdlm_ops.lm_proto_name); return sprintf(buf, "%s\n", gdlm_ops.lm_proto_name);
......
...@@ -135,7 +135,15 @@ static void process_complete(struct gdlm_lock *lp) ...@@ -135,7 +135,15 @@ static void process_complete(struct gdlm_lock *lp)
lp->lksb.sb_status, lp->lockname.ln_type, lp->lksb.sb_status, lp->lockname.ln_type,
(unsigned long long)lp->lockname.ln_number, (unsigned long long)lp->lockname.ln_number,
lp->flags); lp->flags);
return; if (lp->lksb.sb_status == -EDEADLOCK &&
lp->ls->fsflags & LM_MFLAG_CONV_NODROP) {
lp->req = lp->cur;
acb.lc_ret |= LM_OUT_CONV_DEADLK;
if (lp->cur == DLM_LOCK_IV)
lp->lksb.sb_lkid = 0;
goto out;
} else
return;
} }
/* /*
......
...@@ -140,7 +140,7 @@ static int nolock_hold_lvb(void *lock, char **lvbp) ...@@ -140,7 +140,7 @@ static int nolock_hold_lvb(void *lock, char **lvbp)
struct nolock_lockspace *nl = lock; struct nolock_lockspace *nl = lock;
int error = 0; int error = 0;
*lvbp = kzalloc(nl->nl_lvb_size, GFP_KERNEL); *lvbp = kzalloc(nl->nl_lvb_size, GFP_NOFS);
if (!*lvbp) if (!*lvbp)
error = -ENOMEM; error = -ENOMEM;
......
...@@ -769,8 +769,8 @@ static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr) ...@@ -769,8 +769,8 @@ static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
sdp->sd_log_commited_revoke += tr->tr_num_revoke - tr->tr_num_revoke_rm; sdp->sd_log_commited_revoke += tr->tr_num_revoke - tr->tr_num_revoke_rm;
gfs2_assert_withdraw(sdp, ((int)sdp->sd_log_commited_revoke) >= 0); gfs2_assert_withdraw(sdp, ((int)sdp->sd_log_commited_revoke) >= 0);
reserved = calc_reserved(sdp); reserved = calc_reserved(sdp);
gfs2_assert_withdraw(sdp, sdp->sd_log_blks_reserved + tr->tr_reserved >= reserved);
unused = sdp->sd_log_blks_reserved - reserved + tr->tr_reserved; unused = sdp->sd_log_blks_reserved - reserved + tr->tr_reserved;
gfs2_assert_withdraw(sdp, unused >= 0);
atomic_add(unused, &sdp->sd_log_blks_free); atomic_add(unused, &sdp->sd_log_blks_free);
gfs2_assert_withdraw(sdp, atomic_read(&sdp->sd_log_blks_free) <= gfs2_assert_withdraw(sdp, atomic_read(&sdp->sd_log_blks_free) <=
sdp->sd_jdesc->jd_blocks); sdp->sd_jdesc->jd_blocks);
...@@ -779,6 +779,21 @@ static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr) ...@@ -779,6 +779,21 @@ static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
gfs2_log_unlock(sdp); gfs2_log_unlock(sdp);
} }
static void buf_lo_incore_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
{
struct list_head *head = &tr->tr_list_buf;
struct gfs2_bufdata *bd;
gfs2_log_lock(sdp);
while (!list_empty(head)) {
bd = list_entry(head->next, struct gfs2_bufdata, bd_list_tr);
list_del_init(&bd->bd_list_tr);
tr->tr_num_buf--;
}
gfs2_log_unlock(sdp);
gfs2_assert_warn(sdp, !tr->tr_num_buf);
}
/** /**
* gfs2_log_commit - Commit a transaction to the log * gfs2_log_commit - Commit a transaction to the log
* @sdp: the filesystem * @sdp: the filesystem
...@@ -790,7 +805,7 @@ static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr) ...@@ -790,7 +805,7 @@ static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr) void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
{ {
log_refund(sdp, tr); log_refund(sdp, tr);
lops_incore_commit(sdp, tr); buf_lo_incore_commit(sdp, tr);
sdp->sd_vfs->s_dirt = 1; sdp->sd_vfs->s_dirt = 1;
up_read(&sdp->sd_log_flush_lock); up_read(&sdp->sd_log_flush_lock);
......
...@@ -152,21 +152,6 @@ out: ...@@ -152,21 +152,6 @@ out:
unlock_buffer(bd->bd_bh); unlock_buffer(bd->bd_bh);
} }
static void buf_lo_incore_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
{
struct list_head *head = &tr->tr_list_buf;
struct gfs2_bufdata *bd;
gfs2_log_lock(sdp);
while (!list_empty(head)) {
bd = list_entry(head->next, struct gfs2_bufdata, bd_list_tr);
list_del_init(&bd->bd_list_tr);
tr->tr_num_buf--;
}
gfs2_log_unlock(sdp);
gfs2_assert_warn(sdp, !tr->tr_num_buf);
}
static void buf_lo_before_commit(struct gfs2_sbd *sdp) static void buf_lo_before_commit(struct gfs2_sbd *sdp)
{ {
struct buffer_head *bh; struct buffer_head *bh;
...@@ -419,8 +404,10 @@ static int revoke_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, ...@@ -419,8 +404,10 @@ static int revoke_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start,
blkno = be64_to_cpu(*(__be64 *)(bh->b_data + offset)); blkno = be64_to_cpu(*(__be64 *)(bh->b_data + offset));
error = gfs2_revoke_add(sdp, blkno, start); error = gfs2_revoke_add(sdp, blkno, start);
if (error < 0) if (error < 0) {
brelse(bh);
return error; return error;
}
else if (error) else if (error)
sdp->sd_found_revokes++; sdp->sd_found_revokes++;
...@@ -737,7 +724,6 @@ static void databuf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai) ...@@ -737,7 +724,6 @@ static void databuf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
const struct gfs2_log_operations gfs2_buf_lops = { const struct gfs2_log_operations gfs2_buf_lops = {
.lo_add = buf_lo_add, .lo_add = buf_lo_add,
.lo_incore_commit = buf_lo_incore_commit,
.lo_before_commit = buf_lo_before_commit, .lo_before_commit = buf_lo_before_commit,
.lo_after_commit = buf_lo_after_commit, .lo_after_commit = buf_lo_after_commit,
.lo_before_scan = buf_lo_before_scan, .lo_before_scan = buf_lo_before_scan,
...@@ -763,7 +749,6 @@ const struct gfs2_log_operations gfs2_rg_lops = { ...@@ -763,7 +749,6 @@ const struct gfs2_log_operations gfs2_rg_lops = {
const struct gfs2_log_operations gfs2_databuf_lops = { const struct gfs2_log_operations gfs2_databuf_lops = {
.lo_add = databuf_lo_add, .lo_add = databuf_lo_add,
.lo_incore_commit = buf_lo_incore_commit,
.lo_before_commit = databuf_lo_before_commit, .lo_before_commit = databuf_lo_before_commit,
.lo_after_commit = databuf_lo_after_commit, .lo_after_commit = databuf_lo_after_commit,
.lo_scan_elements = databuf_lo_scan_elements, .lo_scan_elements = databuf_lo_scan_elements,
......
/* /*
* Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
* Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
* *
* This copyrighted material is made available to anyone wishing to use, * This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions * modify, copy, or redistribute it subject to the terms and conditions
...@@ -57,15 +57,6 @@ static inline void lops_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) ...@@ -57,15 +57,6 @@ static inline void lops_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
le->le_ops->lo_add(sdp, le); le->le_ops->lo_add(sdp, le);
} }
static inline void lops_incore_commit(struct gfs2_sbd *sdp,
struct gfs2_trans *tr)
{
int x;
for (x = 0; gfs2_log_ops[x]; x++)
if (gfs2_log_ops[x]->lo_incore_commit)
gfs2_log_ops[x]->lo_incore_commit(sdp, tr);
}
static inline void lops_before_commit(struct gfs2_sbd *sdp) static inline void lops_before_commit(struct gfs2_sbd *sdp)
{ {
int x; int x;
......
...@@ -89,6 +89,12 @@ static int __init init_gfs2_fs(void) ...@@ -89,6 +89,12 @@ static int __init init_gfs2_fs(void)
if (!gfs2_bufdata_cachep) if (!gfs2_bufdata_cachep)
goto fail; goto fail;
gfs2_rgrpd_cachep = kmem_cache_create("gfs2_rgrpd",
sizeof(struct gfs2_rgrpd),
0, 0, NULL);
if (!gfs2_rgrpd_cachep)
goto fail;
error = register_filesystem(&gfs2_fs_type); error = register_filesystem(&gfs2_fs_type);
if (error) if (error)
goto fail; goto fail;
...@@ -108,6 +114,9 @@ fail_unregister: ...@@ -108,6 +114,9 @@ fail_unregister:
fail: fail:
gfs2_glock_exit(); gfs2_glock_exit();
if (gfs2_rgrpd_cachep)
kmem_cache_destroy(gfs2_rgrpd_cachep);
if (gfs2_bufdata_cachep) if (gfs2_bufdata_cachep)
kmem_cache_destroy(gfs2_bufdata_cachep); kmem_cache_destroy(gfs2_bufdata_cachep);
...@@ -133,6 +142,7 @@ static void __exit exit_gfs2_fs(void) ...@@ -133,6 +142,7 @@ static void __exit exit_gfs2_fs(void)
unregister_filesystem(&gfs2_fs_type); unregister_filesystem(&gfs2_fs_type);
unregister_filesystem(&gfs2meta_fs_type); unregister_filesystem(&gfs2meta_fs_type);
kmem_cache_destroy(gfs2_rgrpd_cachep);
kmem_cache_destroy(gfs2_bufdata_cachep); kmem_cache_destroy(gfs2_bufdata_cachep);
kmem_cache_destroy(gfs2_inode_cachep); kmem_cache_destroy(gfs2_inode_cachep);
kmem_cache_destroy(gfs2_glock_cachep); kmem_cache_destroy(gfs2_glock_cachep);
......
/* /*
* Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
* Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
* *
* This copyrighted material is made available to anyone wishing to use, * This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions * modify, copy, or redistribute it subject to the terms and conditions
...@@ -21,7 +21,6 @@ ...@@ -21,7 +21,6 @@
#include <linux/gfs2_ondisk.h> #include <linux/gfs2_ondisk.h>
#include <linux/lm_interface.h> #include <linux/lm_interface.h>
#include <linux/backing-dev.h> #include <linux/backing-dev.h>
#include <linux/pagevec.h>
#include "gfs2.h" #include "gfs2.h"
#include "incore.h" #include "incore.h"
...@@ -104,11 +103,9 @@ static int gfs2_writepage_common(struct page *page, ...@@ -104,11 +103,9 @@ static int gfs2_writepage_common(struct page *page,
loff_t i_size = i_size_read(inode); loff_t i_size = i_size_read(inode);
pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT; pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT;
unsigned offset; unsigned offset;
int ret = -EIO;
if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(ip->i_gl))) if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(ip->i_gl)))
goto out; goto out;
ret = 0;
if (current->journal_info) if (current->journal_info)
goto redirty; goto redirty;
/* Is the page fully outside i_size? (truncate in progress) */ /* Is the page fully outside i_size? (truncate in progress) */
...@@ -280,7 +277,7 @@ static int gfs2_write_jdata_pagevec(struct address_space *mapping, ...@@ -280,7 +277,7 @@ static int gfs2_write_jdata_pagevec(struct address_space *mapping,
int i; int i;
int ret; int ret;
ret = gfs2_trans_begin(sdp, nrblocks, 0); ret = gfs2_trans_begin(sdp, nrblocks, nrblocks);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -510,23 +507,26 @@ static int __gfs2_readpage(void *file, struct page *page) ...@@ -510,23 +507,26 @@ static int __gfs2_readpage(void *file, struct page *page)
static int gfs2_readpage(struct file *file, struct page *page) static int gfs2_readpage(struct file *file, struct page *page)
{ {
struct gfs2_inode *ip = GFS2_I(page->mapping->host); struct gfs2_inode *ip = GFS2_I(page->mapping->host);
struct gfs2_holder gh; struct gfs2_holder *gh;
int error; int error;
gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME|LM_FLAG_TRY_1CB, &gh); gh = gfs2_glock_is_locked_by_me(ip->i_gl);
error = gfs2_glock_nq_atime(&gh); if (!gh) {
if (unlikely(error)) { gh = kmalloc(sizeof(struct gfs2_holder), GFP_NOFS);
if (!gh)
return -ENOBUFS;
gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, gh);
unlock_page(page); unlock_page(page);
goto out; error = gfs2_glock_nq_atime(gh);
if (likely(error != 0))
goto out;
return AOP_TRUNCATED_PAGE;
} }
error = __gfs2_readpage(file, page); error = __gfs2_readpage(file, page);
gfs2_glock_dq(&gh); gfs2_glock_dq(gh);
out: out:
gfs2_holder_uninit(&gh); gfs2_holder_uninit(gh);
if (error == GLR_TRYFAILED) { kfree(gh);
yield();
return AOP_TRUNCATED_PAGE;
}
return error; return error;
} }
...@@ -648,15 +648,15 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping, ...@@ -648,15 +648,15 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,
if (alloc_required) { if (alloc_required) {
al = gfs2_alloc_get(ip); al = gfs2_alloc_get(ip);
if (!al) {
error = -ENOMEM;
goto out_unlock;
}
error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); error = gfs2_quota_lock_check(ip);
if (error) if (error)
goto out_alloc_put; goto out_alloc_put;
error = gfs2_quota_check(ip, ip->i_inode.i_uid, ip->i_inode.i_gid);
if (error)
goto out_qunlock;
al->al_requested = data_blocks + ind_blocks; al->al_requested = data_blocks + ind_blocks;
error = gfs2_inplace_reserve(ip); error = gfs2_inplace_reserve(ip);
if (error) if (error)
...@@ -828,7 +828,7 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping, ...@@ -828,7 +828,7 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping,
unsigned int to = from + len; unsigned int to = from + len;
int ret; int ret;
BUG_ON(gfs2_glock_is_locked_by_me(ip->i_gl) == 0); BUG_ON(gfs2_glock_is_locked_by_me(ip->i_gl) == NULL);
ret = gfs2_meta_inode_buffer(ip, &dibh); ret = gfs2_meta_inode_buffer(ip, &dibh);
if (unlikely(ret)) { if (unlikely(ret)) {
......
...@@ -43,7 +43,7 @@ static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd) ...@@ -43,7 +43,7 @@ static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd)
struct gfs2_holder d_gh; struct gfs2_holder d_gh;
struct gfs2_inode *ip = NULL; struct gfs2_inode *ip = NULL;
int error; int error;
int had_lock=0; int had_lock = 0;
if (inode) { if (inode) {
if (is_bad_inode(inode)) if (is_bad_inode(inode))
...@@ -54,7 +54,7 @@ static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd) ...@@ -54,7 +54,7 @@ static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd)
if (sdp->sd_args.ar_localcaching) if (sdp->sd_args.ar_localcaching)
goto valid; goto valid;
had_lock = gfs2_glock_is_locked_by_me(dip->i_gl); had_lock = (gfs2_glock_is_locked_by_me(dip->i_gl) != NULL);
if (!had_lock) { if (!had_lock) {
error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh); error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh);
if (error) if (error)
......
...@@ -204,8 +204,6 @@ static struct dentry *gfs2_get_dentry(struct super_block *sb, ...@@ -204,8 +204,6 @@ static struct dentry *gfs2_get_dentry(struct super_block *sb,
inode = gfs2_inode_lookup(sb, DT_UNKNOWN, inode = gfs2_inode_lookup(sb, DT_UNKNOWN,
inum->no_addr, inum->no_addr,
0, 0); 0, 0);
if (!inode)
goto fail;
if (IS_ERR(inode)) { if (IS_ERR(inode)) {
error = PTR_ERR(inode); error = PTR_ERR(inode);
goto fail; goto fail;
......
...@@ -30,7 +30,6 @@ ...@@ -30,7 +30,6 @@
#include "glock.h" #include "glock.h"
#include "glops.h" #include "glops.h"
#include "inode.h" #include "inode.h"
#include "lm.h"
#include "log.h" #include "log.h"
#include "meta_io.h" #include "meta_io.h"
#include "quota.h" #include "quota.h"
...@@ -39,6 +38,7 @@ ...@@ -39,6 +38,7 @@
#include "util.h" #include "util.h"
#include "eaops.h" #include "eaops.h"
#include "ops_address.h" #include "ops_address.h"
#include "ops_inode.h"
/** /**
* gfs2_llseek - seek to a location in a file * gfs2_llseek - seek to a location in a file
...@@ -369,12 +369,9 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct page *page) ...@@ -369,12 +369,9 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct page *page)
if (al == NULL) if (al == NULL)
goto out_unlock; goto out_unlock;
ret = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); ret = gfs2_quota_lock_check(ip);
if (ret) if (ret)
goto out_alloc_put; goto out_alloc_put;
ret = gfs2_quota_check(ip, ip->i_inode.i_uid, ip->i_inode.i_gid);
if (ret)
goto out_quota_unlock;
al->al_requested = data_blocks + ind_blocks; al->al_requested = data_blocks + ind_blocks;
ret = gfs2_inplace_reserve(ip); ret = gfs2_inplace_reserve(ip);
if (ret) if (ret)
...@@ -596,6 +593,36 @@ static int gfs2_setlease(struct file *file, long arg, struct file_lock **fl) ...@@ -596,6 +593,36 @@ static int gfs2_setlease(struct file *file, long arg, struct file_lock **fl)
return generic_setlease(file, arg, fl); return generic_setlease(file, arg, fl);
} }
static int gfs2_lm_plock_get(struct gfs2_sbd *sdp, struct lm_lockname *name,
struct file *file, struct file_lock *fl)
{
int error = -EIO;
if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
error = sdp->sd_lockstruct.ls_ops->lm_plock_get(
sdp->sd_lockstruct.ls_lockspace, name, file, fl);
return error;
}
static int gfs2_lm_plock(struct gfs2_sbd *sdp, struct lm_lockname *name,
struct file *file, int cmd, struct file_lock *fl)
{
int error = -EIO;
if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
error = sdp->sd_lockstruct.ls_ops->lm_plock(
sdp->sd_lockstruct.ls_lockspace, name, file, cmd, fl);
return error;
}
static int gfs2_lm_punlock(struct gfs2_sbd *sdp, struct lm_lockname *name,
struct file *file, struct file_lock *fl)
{
int error = -EIO;
if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
error = sdp->sd_lockstruct.ls_ops->lm_punlock(
sdp->sd_lockstruct.ls_lockspace, name, file, fl);
return error;
}
/** /**
* gfs2_lock - acquire/release a posix lock on a file * gfs2_lock - acquire/release a posix lock on a file
* @file: the file pointer * @file: the file pointer
......
/* /*
* Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
* Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
* *
* This copyrighted material is made available to anyone wishing to use, * This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions * modify, copy, or redistribute it subject to the terms and conditions
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
#include "glock.h" #include "glock.h"
#include "glops.h" #include "glops.h"
#include "inode.h" #include "inode.h"
#include "lm.h"
#include "mount.h" #include "mount.h"
#include "ops_fstype.h" #include "ops_fstype.h"
#include "ops_dentry.h" #include "ops_dentry.h"
...@@ -363,6 +362,13 @@ static int map_journal_extents(struct gfs2_sbd *sdp) ...@@ -363,6 +362,13 @@ static int map_journal_extents(struct gfs2_sbd *sdp)
return rc; return rc;
} }
static void gfs2_lm_others_may_mount(struct gfs2_sbd *sdp)
{
if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
sdp->sd_lockstruct.ls_ops->lm_others_may_mount(
sdp->sd_lockstruct.ls_lockspace);
}
static int init_journal(struct gfs2_sbd *sdp, int undo) static int init_journal(struct gfs2_sbd *sdp, int undo)
{ {
struct gfs2_holder ji_gh; struct gfs2_holder ji_gh;
...@@ -542,7 +548,7 @@ static int init_inodes(struct gfs2_sbd *sdp, int undo) ...@@ -542,7 +548,7 @@ static int init_inodes(struct gfs2_sbd *sdp, int undo)
} }
ip = GFS2_I(sdp->sd_rindex); ip = GFS2_I(sdp->sd_rindex);
set_bit(GLF_STICKY, &ip->i_gl->gl_flags); set_bit(GLF_STICKY, &ip->i_gl->gl_flags);
sdp->sd_rindex_vn = ip->i_gl->gl_vn - 1; sdp->sd_rindex_uptodate = 0;
/* Read in the quota inode */ /* Read in the quota inode */
sdp->sd_quota_inode = gfs2_lookup_simple(sdp->sd_master_dir, "quota"); sdp->sd_quota_inode = gfs2_lookup_simple(sdp->sd_master_dir, "quota");
...@@ -704,6 +710,69 @@ fail: ...@@ -704,6 +710,69 @@ fail:
return error; return error;
} }
/**
* gfs2_lm_mount - mount a locking protocol
* @sdp: the filesystem
* @args: mount arguements
* @silent: if 1, don't complain if the FS isn't a GFS2 fs
*
* Returns: errno
*/
static int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent)
{
char *proto = sdp->sd_proto_name;
char *table = sdp->sd_table_name;
int flags = LM_MFLAG_CONV_NODROP;
int error;
if (sdp->sd_args.ar_spectator)
flags |= LM_MFLAG_SPECTATOR;
fs_info(sdp, "Trying to join cluster \"%s\", \"%s\"\n", proto, table);
error = gfs2_mount_lockproto(proto, table, sdp->sd_args.ar_hostdata,
gfs2_glock_cb, sdp,
GFS2_MIN_LVB_SIZE, flags,
&sdp->sd_lockstruct, &sdp->sd_kobj);
if (error) {
fs_info(sdp, "can't mount proto=%s, table=%s, hostdata=%s\n",
proto, table, sdp->sd_args.ar_hostdata);
goto out;
}
if (gfs2_assert_warn(sdp, sdp->sd_lockstruct.ls_lockspace) ||
gfs2_assert_warn(sdp, sdp->sd_lockstruct.ls_ops) ||
gfs2_assert_warn(sdp, sdp->sd_lockstruct.ls_lvb_size >=
GFS2_MIN_LVB_SIZE)) {
gfs2_unmount_lockproto(&sdp->sd_lockstruct);
goto out;
}
if (sdp->sd_args.ar_spectator)
snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s.s", table);
else
snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s.%u", table,
sdp->sd_lockstruct.ls_jid);
fs_info(sdp, "Joined cluster. Now mounting FS...\n");
if ((sdp->sd_lockstruct.ls_flags & LM_LSFLAG_LOCAL) &&
!sdp->sd_args.ar_ignore_local_fs) {
sdp->sd_args.ar_localflocks = 1;
sdp->sd_args.ar_localcaching = 1;
}
out:
return error;
}
void gfs2_lm_unmount(struct gfs2_sbd *sdp)
{
if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
gfs2_unmount_lockproto(&sdp->sd_lockstruct);
}
/** /**
* fill_super - Read in superblock * fill_super - Read in superblock
* @sb: The VFS superblock * @sb: The VFS superblock
...@@ -874,7 +943,6 @@ static struct super_block* get_gfs2_sb(const char *dev_name) ...@@ -874,7 +943,6 @@ static struct super_block* get_gfs2_sb(const char *dev_name)
{ {
struct kstat stat; struct kstat stat;
struct nameidata nd; struct nameidata nd;
struct file_system_type *fstype;
struct super_block *sb = NULL, *s; struct super_block *sb = NULL, *s;
int error; int error;
...@@ -886,8 +954,7 @@ static struct super_block* get_gfs2_sb(const char *dev_name) ...@@ -886,8 +954,7 @@ static struct super_block* get_gfs2_sb(const char *dev_name)
} }
error = vfs_getattr(nd.path.mnt, nd.path.dentry, &stat); error = vfs_getattr(nd.path.mnt, nd.path.dentry, &stat);
fstype = get_fs_type("gfs2"); list_for_each_entry(s, &gfs2_fs_type.fs_supers, s_instances) {
list_for_each_entry(s, &fstype->fs_supers, s_instances) {
if ((S_ISBLK(stat.mode) && s->s_dev == stat.rdev) || if ((S_ISBLK(stat.mode) && s->s_dev == stat.rdev) ||
(S_ISDIR(stat.mode) && (S_ISDIR(stat.mode) &&
s == nd.path.dentry->d_inode->i_sb)) { s == nd.path.dentry->d_inode->i_sb)) {
...@@ -931,7 +998,6 @@ static int gfs2_get_sb_meta(struct file_system_type *fs_type, int flags, ...@@ -931,7 +998,6 @@ static int gfs2_get_sb_meta(struct file_system_type *fs_type, int flags,
error = PTR_ERR(new); error = PTR_ERR(new);
goto error; goto error;
} }
module_put(fs_type->owner);
new->s_flags = flags; new->s_flags = flags;
strlcpy(new->s_id, sb->s_id, sizeof(new->s_id)); strlcpy(new->s_id, sb->s_id, sizeof(new->s_id));
sb_set_blocksize(new, sb->s_blocksize); sb_set_blocksize(new, sb->s_blocksize);
......
...@@ -200,15 +200,15 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, ...@@ -200,15 +200,15 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
if (alloc_required) { if (alloc_required) {
struct gfs2_alloc *al = gfs2_alloc_get(dip); struct gfs2_alloc *al = gfs2_alloc_get(dip);
if (!al) {
error = -ENOMEM;
goto out_gunlock;
}
error = gfs2_quota_lock(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); error = gfs2_quota_lock_check(dip);
if (error) if (error)
goto out_alloc; goto out_alloc;
error = gfs2_quota_check(dip, dip->i_inode.i_uid, dip->i_inode.i_gid);
if (error)
goto out_gunlock_q;
al->al_requested = sdp->sd_max_dirres; al->al_requested = sdp->sd_max_dirres;
error = gfs2_inplace_reserve(dip); error = gfs2_inplace_reserve(dip);
...@@ -716,15 +716,15 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, ...@@ -716,15 +716,15 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
if (alloc_required) { if (alloc_required) {
struct gfs2_alloc *al = gfs2_alloc_get(ndip); struct gfs2_alloc *al = gfs2_alloc_get(ndip);
if (!al) {
error = -ENOMEM;
goto out_gunlock;
}
error = gfs2_quota_lock(ndip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); error = gfs2_quota_lock_check(ndip);
if (error) if (error)
goto out_alloc; goto out_alloc;
error = gfs2_quota_check(ndip, ndip->i_inode.i_uid, ndip->i_inode.i_gid);
if (error)
goto out_gunlock_q;
al->al_requested = sdp->sd_max_dirres; al->al_requested = sdp->sd_max_dirres;
error = gfs2_inplace_reserve(ndip); error = gfs2_inplace_reserve(ndip);
...@@ -898,7 +898,7 @@ static int gfs2_permission(struct inode *inode, int mask, struct nameidata *nd) ...@@ -898,7 +898,7 @@ static int gfs2_permission(struct inode *inode, int mask, struct nameidata *nd)
int error; int error;
int unlock = 0; int unlock = 0;
if (gfs2_glock_is_locked_by_me(ip->i_gl) == 0) { if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) {
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
if (error) if (error)
return error; return error;
...@@ -953,7 +953,8 @@ static int setattr_chown(struct inode *inode, struct iattr *attr) ...@@ -953,7 +953,8 @@ static int setattr_chown(struct inode *inode, struct iattr *attr)
if (!(attr->ia_valid & ATTR_GID) || ogid == ngid) if (!(attr->ia_valid & ATTR_GID) || ogid == ngid)
ogid = ngid = NO_QUOTA_CHANGE; ogid = ngid = NO_QUOTA_CHANGE;
gfs2_alloc_get(ip); if (!gfs2_alloc_get(ip))
return -ENOMEM;
error = gfs2_quota_lock(ip, nuid, ngid); error = gfs2_quota_lock(ip, nuid, ngid);
if (error) if (error)
...@@ -981,8 +982,9 @@ static int setattr_chown(struct inode *inode, struct iattr *attr) ...@@ -981,8 +982,9 @@ static int setattr_chown(struct inode *inode, struct iattr *attr)
brelse(dibh); brelse(dibh);
if (ouid != NO_QUOTA_CHANGE || ogid != NO_QUOTA_CHANGE) { if (ouid != NO_QUOTA_CHANGE || ogid != NO_QUOTA_CHANGE) {
gfs2_quota_change(ip, -ip->i_di.di_blocks, ouid, ogid); u64 blocks = gfs2_get_inode_blocks(&ip->i_inode);
gfs2_quota_change(ip, ip->i_di.di_blocks, nuid, ngid); gfs2_quota_change(ip, -blocks, ouid, ogid);
gfs2_quota_change(ip, blocks, nuid, ngid);
} }
out_end_trans: out_end_trans:
...@@ -1064,7 +1066,7 @@ static int gfs2_getattr(struct vfsmount *mnt, struct dentry *dentry, ...@@ -1064,7 +1066,7 @@ static int gfs2_getattr(struct vfsmount *mnt, struct dentry *dentry,
int error; int error;
int unlock = 0; int unlock = 0;
if (gfs2_glock_is_locked_by_me(ip->i_gl) == 0) { if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) {
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh); error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh);
if (error) if (error)
return error; return error;
...@@ -1148,16 +1150,6 @@ const struct inode_operations gfs2_file_iops = { ...@@ -1148,16 +1150,6 @@ const struct inode_operations gfs2_file_iops = {
.removexattr = gfs2_removexattr, .removexattr = gfs2_removexattr,
}; };
const struct inode_operations gfs2_dev_iops = {
.permission = gfs2_permission,
.setattr = gfs2_setattr,
.getattr = gfs2_getattr,
.setxattr = gfs2_setxattr,
.getxattr = gfs2_getxattr,
.listxattr = gfs2_listxattr,
.removexattr = gfs2_removexattr,
};
const struct inode_operations gfs2_dir_iops = { const struct inode_operations gfs2_dir_iops = {
.create = gfs2_create, .create = gfs2_create,
.lookup = gfs2_lookup, .lookup = gfs2_lookup,
......
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
extern const struct inode_operations gfs2_file_iops; extern const struct inode_operations gfs2_file_iops;
extern const struct inode_operations gfs2_dir_iops; extern const struct inode_operations gfs2_dir_iops;
extern const struct inode_operations gfs2_symlink_iops; extern const struct inode_operations gfs2_symlink_iops;
extern const struct inode_operations gfs2_dev_iops;
extern const struct file_operations gfs2_file_fops; extern const struct file_operations gfs2_file_fops;
extern const struct file_operations gfs2_dir_fops; extern const struct file_operations gfs2_dir_fops;
extern const struct file_operations gfs2_file_fops_nolock; extern const struct file_operations gfs2_file_fops_nolock;
......
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
#include "incore.h" #include "incore.h"
#include "glock.h" #include "glock.h"
#include "inode.h" #include "inode.h"
#include "lm.h"
#include "log.h" #include "log.h"
#include "mount.h" #include "mount.h"
#include "ops_super.h" #include "ops_super.h"
......
...@@ -94,7 +94,7 @@ static int qd_alloc(struct gfs2_sbd *sdp, int user, u32 id, ...@@ -94,7 +94,7 @@ static int qd_alloc(struct gfs2_sbd *sdp, int user, u32 id,
struct gfs2_quota_data *qd; struct gfs2_quota_data *qd;
int error; int error;
qd = kzalloc(sizeof(struct gfs2_quota_data), GFP_KERNEL); qd = kzalloc(sizeof(struct gfs2_quota_data), GFP_NOFS);
if (!qd) if (!qd)
return -ENOMEM; return -ENOMEM;
...@@ -616,16 +616,9 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc, ...@@ -616,16 +616,9 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
s64 value; s64 value;
int err = -EIO; int err = -EIO;
if (gfs2_is_stuffed(ip)) { if (gfs2_is_stuffed(ip))
struct gfs2_alloc *al = NULL;
al = gfs2_alloc_get(ip);
/* just request 1 blk */
al->al_requested = 1;
gfs2_inplace_reserve(ip);
gfs2_unstuff_dinode(ip, NULL); gfs2_unstuff_dinode(ip, NULL);
gfs2_inplace_release(ip);
gfs2_alloc_put(ip);
}
page = grab_cache_page(mapping, index); page = grab_cache_page(mapping, index);
if (!page) if (!page)
return -ENOMEM; return -ENOMEM;
...@@ -690,14 +683,14 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda) ...@@ -690,14 +683,14 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda)
unsigned int qx, x; unsigned int qx, x;
struct gfs2_quota_data *qd; struct gfs2_quota_data *qd;
loff_t offset; loff_t offset;
unsigned int nalloc = 0; unsigned int nalloc = 0, blocks;
struct gfs2_alloc *al = NULL; struct gfs2_alloc *al = NULL;
int error; int error;
gfs2_write_calc_reserv(ip, sizeof(struct gfs2_quota), gfs2_write_calc_reserv(ip, sizeof(struct gfs2_quota),
&data_blocks, &ind_blocks); &data_blocks, &ind_blocks);
ghs = kcalloc(num_qd, sizeof(struct gfs2_holder), GFP_KERNEL); ghs = kcalloc(num_qd, sizeof(struct gfs2_holder), GFP_NOFS);
if (!ghs) if (!ghs)
return -ENOMEM; return -ENOMEM;
...@@ -727,30 +720,33 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda) ...@@ -727,30 +720,33 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda)
nalloc++; nalloc++;
} }
if (nalloc) { al = gfs2_alloc_get(ip);
al = gfs2_alloc_get(ip); if (!al) {
error = -ENOMEM;
goto out_gunlock;
}
/*
* 1 blk for unstuffing inode if stuffed. We add this extra
* block to the reservation unconditionally. If the inode
* doesn't need unstuffing, the block will be released to the
* rgrp since it won't be allocated during the transaction
*/
al->al_requested = 1;
/* +1 in the end for block requested above for unstuffing */
blocks = num_qd * data_blocks + RES_DINODE + num_qd + 1;
al->al_requested = nalloc * (data_blocks + ind_blocks); if (nalloc)
al->al_requested += nalloc * (data_blocks + ind_blocks);
error = gfs2_inplace_reserve(ip);
if (error)
goto out_alloc;
error = gfs2_inplace_reserve(ip); if (nalloc)
if (error) blocks += al->al_rgd->rd_length + nalloc * ind_blocks + RES_STATFS;
goto out_alloc;
error = gfs2_trans_begin(sdp, blocks, 0);
error = gfs2_trans_begin(sdp, if (error)
al->al_rgd->rd_length + goto out_ipres;
num_qd * data_blocks +
nalloc * ind_blocks +
RES_DINODE + num_qd +
RES_STATFS, 0);
if (error)
goto out_ipres;
} else {
error = gfs2_trans_begin(sdp,
num_qd * data_blocks +
RES_DINODE + num_qd, 0);
if (error)
goto out_gunlock;
}
for (x = 0; x < num_qd; x++) { for (x = 0; x < num_qd; x++) {
qd = qda[x]; qd = qda[x];
...@@ -769,11 +765,9 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda) ...@@ -769,11 +765,9 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda)
out_end_trans: out_end_trans:
gfs2_trans_end(sdp); gfs2_trans_end(sdp);
out_ipres: out_ipres:
if (nalloc) gfs2_inplace_release(ip);
gfs2_inplace_release(ip);
out_alloc: out_alloc:
if (nalloc) gfs2_alloc_put(ip);
gfs2_alloc_put(ip);
out_gunlock: out_gunlock:
gfs2_glock_dq_uninit(&i_gh); gfs2_glock_dq_uninit(&i_gh);
out: out:
...@@ -1124,12 +1118,12 @@ int gfs2_quota_init(struct gfs2_sbd *sdp) ...@@ -1124,12 +1118,12 @@ int gfs2_quota_init(struct gfs2_sbd *sdp)
error = -ENOMEM; error = -ENOMEM;
sdp->sd_quota_bitmap = kcalloc(sdp->sd_quota_chunks, sdp->sd_quota_bitmap = kcalloc(sdp->sd_quota_chunks,
sizeof(unsigned char *), GFP_KERNEL); sizeof(unsigned char *), GFP_NOFS);
if (!sdp->sd_quota_bitmap) if (!sdp->sd_quota_bitmap)
return error; return error;
for (x = 0; x < sdp->sd_quota_chunks; x++) { for (x = 0; x < sdp->sd_quota_chunks; x++) {
sdp->sd_quota_bitmap[x] = kzalloc(PAGE_SIZE, GFP_KERNEL); sdp->sd_quota_bitmap[x] = kzalloc(PAGE_SIZE, GFP_NOFS);
if (!sdp->sd_quota_bitmap[x]) if (!sdp->sd_quota_bitmap[x])
goto fail; goto fail;
} }
......
...@@ -32,4 +32,21 @@ int gfs2_quota_init(struct gfs2_sbd *sdp); ...@@ -32,4 +32,21 @@ int gfs2_quota_init(struct gfs2_sbd *sdp);
void gfs2_quota_scan(struct gfs2_sbd *sdp); void gfs2_quota_scan(struct gfs2_sbd *sdp);
void gfs2_quota_cleanup(struct gfs2_sbd *sdp); void gfs2_quota_cleanup(struct gfs2_sbd *sdp);
static inline int gfs2_quota_lock_check(struct gfs2_inode *ip)
{
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
int ret;
if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)
return 0;
ret = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
if (ret)
return ret;
if (sdp->sd_args.ar_quota != GFS2_QUOTA_ON)
return 0;
ret = gfs2_quota_check(ip, ip->i_inode.i_uid, ip->i_inode.i_gid);
if (ret)
gfs2_quota_unlock(ip);
return ret;
}
#endif /* __QUOTA_DOT_H__ */ #endif /* __QUOTA_DOT_H__ */
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include "bmap.h" #include "bmap.h"
#include "glock.h" #include "glock.h"
#include "glops.h" #include "glops.h"
#include "lm.h"
#include "lops.h" #include "lops.h"
#include "meta_io.h" #include "meta_io.h"
#include "recovery.h" #include "recovery.h"
...@@ -69,7 +68,7 @@ int gfs2_revoke_add(struct gfs2_sbd *sdp, u64 blkno, unsigned int where) ...@@ -69,7 +68,7 @@ int gfs2_revoke_add(struct gfs2_sbd *sdp, u64 blkno, unsigned int where)
return 0; return 0;
} }
rr = kmalloc(sizeof(struct gfs2_revoke_replay), GFP_KERNEL); rr = kmalloc(sizeof(struct gfs2_revoke_replay), GFP_NOFS);
if (!rr) if (!rr)
return -ENOMEM; return -ENOMEM;
...@@ -150,7 +149,7 @@ static int get_log_header(struct gfs2_jdesc *jd, unsigned int blk, ...@@ -150,7 +149,7 @@ static int get_log_header(struct gfs2_jdesc *jd, unsigned int blk,
struct gfs2_log_header_host *head) struct gfs2_log_header_host *head)
{ {
struct buffer_head *bh; struct buffer_head *bh;
struct gfs2_log_header_host lh; struct gfs2_log_header_host uninitialized_var(lh);
const u32 nothing = 0; const u32 nothing = 0;
u32 hash; u32 hash;
int error; int error;
...@@ -425,6 +424,16 @@ static int clean_journal(struct gfs2_jdesc *jd, struct gfs2_log_header_host *hea ...@@ -425,6 +424,16 @@ static int clean_journal(struct gfs2_jdesc *jd, struct gfs2_log_header_host *hea
return error; return error;
} }
static void gfs2_lm_recovery_done(struct gfs2_sbd *sdp, unsigned int jid,
unsigned int message)
{
if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
sdp->sd_lockstruct.ls_ops->lm_recovery_done(
sdp->sd_lockstruct.ls_lockspace, jid, message);
}
/** /**
* gfs2_recover_journal - recovery a given journal * gfs2_recover_journal - recovery a given journal
* @jd: the struct gfs2_jdesc describing the journal * @jd: the struct gfs2_jdesc describing the journal
......
/* /*
* Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
* Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
* *
* This copyrighted material is made available to anyone wishing to use, * This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions * modify, copy, or redistribute it subject to the terms and conditions
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/gfs2_ondisk.h> #include <linux/gfs2_ondisk.h>
#include <linux/lm_interface.h> #include <linux/lm_interface.h>
#include <linux/prefetch.h>
#include "gfs2.h" #include "gfs2.h"
#include "incore.h" #include "incore.h"
...@@ -33,6 +34,16 @@ ...@@ -33,6 +34,16 @@
#define BFITNOENT ((u32)~0) #define BFITNOENT ((u32)~0)
#define NO_BLOCK ((u64)~0) #define NO_BLOCK ((u64)~0)
#if BITS_PER_LONG == 32
#define LBITMASK (0x55555555UL)
#define LBITSKIP55 (0x55555555UL)
#define LBITSKIP00 (0x00000000UL)
#else
#define LBITMASK (0x5555555555555555UL)
#define LBITSKIP55 (0x5555555555555555UL)
#define LBITSKIP00 (0x0000000000000000UL)
#endif
/* /*
* These routines are used by the resource group routines (rgrp.c) * These routines are used by the resource group routines (rgrp.c)
* to keep track of block allocation. Each block is represented by two * to keep track of block allocation. Each block is represented by two
...@@ -53,7 +64,8 @@ static const char valid_change[16] = { ...@@ -53,7 +64,8 @@ static const char valid_change[16] = {
}; };
static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal, static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal,
unsigned char old_state, unsigned char new_state); unsigned char old_state, unsigned char new_state,
unsigned int *n);
/** /**
* gfs2_setbit - Set a bit in the bitmaps * gfs2_setbit - Set a bit in the bitmaps
...@@ -64,26 +76,32 @@ static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal, ...@@ -64,26 +76,32 @@ static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal,
* *
*/ */
static void gfs2_setbit(struct gfs2_rgrpd *rgd, unsigned char *buffer, static inline void gfs2_setbit(struct gfs2_rgrpd *rgd, unsigned char *buf1,
unsigned int buflen, u32 block, unsigned char *buf2, unsigned int offset,
unsigned char new_state) unsigned int buflen, u32 block,
unsigned char new_state)
{ {
unsigned char *byte, *end, cur_state; unsigned char *byte1, *byte2, *end, cur_state;
unsigned int bit; const unsigned int bit = (block % GFS2_NBBY) * GFS2_BIT_SIZE;
byte = buffer + (block / GFS2_NBBY); byte1 = buf1 + offset + (block / GFS2_NBBY);
bit = (block % GFS2_NBBY) * GFS2_BIT_SIZE; end = buf1 + offset + buflen;
end = buffer + buflen;
gfs2_assert(rgd->rd_sbd, byte < end); BUG_ON(byte1 >= end);
cur_state = (*byte >> bit) & GFS2_BIT_MASK; cur_state = (*byte1 >> bit) & GFS2_BIT_MASK;
if (valid_change[new_state * 4 + cur_state]) { if (unlikely(!valid_change[new_state * 4 + cur_state])) {
*byte ^= cur_state << bit;
*byte |= new_state << bit;
} else
gfs2_consist_rgrpd(rgd); gfs2_consist_rgrpd(rgd);
return;
}
*byte1 ^= (cur_state ^ new_state) << bit;
if (buf2) {
byte2 = buf2 + offset + (block / GFS2_NBBY);
cur_state = (*byte2 >> bit) & GFS2_BIT_MASK;
*byte2 ^= (cur_state ^ new_state) << bit;
}
} }
/** /**
...@@ -94,10 +112,12 @@ static void gfs2_setbit(struct gfs2_rgrpd *rgd, unsigned char *buffer, ...@@ -94,10 +112,12 @@ static void gfs2_setbit(struct gfs2_rgrpd *rgd, unsigned char *buffer,
* *
*/ */
static unsigned char gfs2_testbit(struct gfs2_rgrpd *rgd, unsigned char *buffer, static inline unsigned char gfs2_testbit(struct gfs2_rgrpd *rgd,
unsigned int buflen, u32 block) const unsigned char *buffer,
unsigned int buflen, u32 block)
{ {
unsigned char *byte, *end, cur_state; const unsigned char *byte, *end;
unsigned char cur_state;
unsigned int bit; unsigned int bit;
byte = buffer + (block / GFS2_NBBY); byte = buffer + (block / GFS2_NBBY);
...@@ -126,47 +146,66 @@ static unsigned char gfs2_testbit(struct gfs2_rgrpd *rgd, unsigned char *buffer, ...@@ -126,47 +146,66 @@ static unsigned char gfs2_testbit(struct gfs2_rgrpd *rgd, unsigned char *buffer,
* Return: the block number (bitmap buffer scope) that was found * Return: the block number (bitmap buffer scope) that was found
*/ */
static u32 gfs2_bitfit(unsigned char *buffer, unsigned int buflen, u32 goal, static u32 gfs2_bitfit(const u8 *buffer, unsigned int buflen, u32 goal,
unsigned char old_state) u8 old_state)
{ {
unsigned char *byte; const u8 *byte, *start, *end;
u32 blk = goal; int bit, startbit;
unsigned int bit, bitlong; u32 g1, g2, misaligned;
unsigned long *plong, plong55; unsigned long *plong;
unsigned long lskipval;
byte = buffer + (goal / GFS2_NBBY);
plong = (unsigned long *)(buffer + (goal / GFS2_NBBY)); lskipval = (old_state & GFS2_BLKST_USED) ? LBITSKIP00 : LBITSKIP55;
bit = (goal % GFS2_NBBY) * GFS2_BIT_SIZE; g1 = (goal / GFS2_NBBY);
bitlong = bit; start = buffer + g1;
#if BITS_PER_LONG == 32 byte = start;
plong55 = 0x55555555; end = buffer + buflen;
#else g2 = ALIGN(g1, sizeof(unsigned long));
plong55 = 0x5555555555555555; plong = (unsigned long *)(buffer + g2);
#endif startbit = bit = (goal % GFS2_NBBY) * GFS2_BIT_SIZE;
while (byte < buffer + buflen) { misaligned = g2 - g1;
if (!misaligned)
if (bitlong == 0 && old_state == 0 && *plong == plong55) { goto ulong_aligned;
plong++; /* parse the bitmap a byte at a time */
byte += sizeof(unsigned long); misaligned:
blk += sizeof(unsigned long) * GFS2_NBBY; while (byte < end) {
continue; if (((*byte >> bit) & GFS2_BIT_MASK) == old_state) {
return goal +
(((byte - start) * GFS2_NBBY) +
((bit - startbit) >> 1));
} }
if (((*byte >> bit) & GFS2_BIT_MASK) == old_state)
return blk;
bit += GFS2_BIT_SIZE; bit += GFS2_BIT_SIZE;
if (bit >= 8) { if (bit >= GFS2_NBBY * GFS2_BIT_SIZE) {
bit = 0; bit = 0;
byte++; byte++;
misaligned--;
if (!misaligned) {
plong = (unsigned long *)byte;
goto ulong_aligned;
}
} }
bitlong += GFS2_BIT_SIZE;
if (bitlong >= sizeof(unsigned long) * 8) {
bitlong = 0;
plong++;
}
blk++;
} }
return BFITNOENT;
/* parse the bitmap a unsigned long at a time */
ulong_aligned:
/* Stop at "end - 1" or else prefetch can go past the end and segfault.
We could "if" it but we'd lose some of the performance gained.
This way will only slow down searching the very last 4/8 bytes
depending on architecture. I've experimented with several ways
of writing this section such as using an else before the goto
but this one seems to be the fastest. */
while ((unsigned char *)plong < end - 1) {
prefetch(plong + 1);
if (((*plong) & LBITMASK) != lskipval)
break;
plong++;
}
if ((unsigned char *)plong < end) {
byte = (const u8 *)plong;
misaligned += sizeof(unsigned long) - 1;
goto misaligned;
}
return BFITNOENT; return BFITNOENT;
} }
...@@ -179,14 +218,14 @@ static u32 gfs2_bitfit(unsigned char *buffer, unsigned int buflen, u32 goal, ...@@ -179,14 +218,14 @@ static u32 gfs2_bitfit(unsigned char *buffer, unsigned int buflen, u32 goal,
* Returns: The number of bits * Returns: The number of bits
*/ */
static u32 gfs2_bitcount(struct gfs2_rgrpd *rgd, unsigned char *buffer, static u32 gfs2_bitcount(struct gfs2_rgrpd *rgd, const u8 *buffer,
unsigned int buflen, unsigned char state) unsigned int buflen, u8 state)
{ {
unsigned char *byte = buffer; const u8 *byte = buffer;
unsigned char *end = buffer + buflen; const u8 *end = buffer + buflen;
unsigned char state1 = state << 2; const u8 state1 = state << 2;
unsigned char state2 = state << 4; const u8 state2 = state << 4;
unsigned char state3 = state << 6; const u8 state3 = state << 6;
u32 count = 0; u32 count = 0;
for (; byte < end; byte++) { for (; byte < end; byte++) {
...@@ -353,7 +392,7 @@ static void clear_rgrpdi(struct gfs2_sbd *sdp) ...@@ -353,7 +392,7 @@ static void clear_rgrpdi(struct gfs2_sbd *sdp)
} }
kfree(rgd->rd_bits); kfree(rgd->rd_bits);
kfree(rgd); kmem_cache_free(gfs2_rgrpd_cachep, rgd);
} }
} }
...@@ -516,7 +555,7 @@ static int read_rindex_entry(struct gfs2_inode *ip, ...@@ -516,7 +555,7 @@ static int read_rindex_entry(struct gfs2_inode *ip,
return error; return error;
} }
rgd = kzalloc(sizeof(struct gfs2_rgrpd), GFP_NOFS); rgd = kmem_cache_zalloc(gfs2_rgrpd_cachep, GFP_NOFS);
error = -ENOMEM; error = -ENOMEM;
if (!rgd) if (!rgd)
return error; return error;
...@@ -539,7 +578,7 @@ static int read_rindex_entry(struct gfs2_inode *ip, ...@@ -539,7 +578,7 @@ static int read_rindex_entry(struct gfs2_inode *ip,
return error; return error;
rgd->rd_gl->gl_object = rgd; rgd->rd_gl->gl_object = rgd;
rgd->rd_rg_vn = rgd->rd_gl->gl_vn - 1; rgd->rd_flags &= ~GFS2_RDF_UPTODATE;
rgd->rd_flags |= GFS2_RDF_CHECK; rgd->rd_flags |= GFS2_RDF_CHECK;
return error; return error;
} }
...@@ -575,7 +614,7 @@ static int gfs2_ri_update(struct gfs2_inode *ip) ...@@ -575,7 +614,7 @@ static int gfs2_ri_update(struct gfs2_inode *ip)
} }
} }
sdp->sd_rindex_vn = ip->i_gl->gl_vn; sdp->sd_rindex_uptodate = 1;
return 0; return 0;
} }
...@@ -609,7 +648,7 @@ static int gfs2_ri_update_special(struct gfs2_inode *ip) ...@@ -609,7 +648,7 @@ static int gfs2_ri_update_special(struct gfs2_inode *ip)
} }
} }
sdp->sd_rindex_vn = ip->i_gl->gl_vn; sdp->sd_rindex_uptodate = 1;
return 0; return 0;
} }
...@@ -642,9 +681,9 @@ int gfs2_rindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ri_gh) ...@@ -642,9 +681,9 @@ int gfs2_rindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ri_gh)
return error; return error;
/* Read new copy from disk if we don't have the latest */ /* Read new copy from disk if we don't have the latest */
if (sdp->sd_rindex_vn != gl->gl_vn) { if (!sdp->sd_rindex_uptodate) {
mutex_lock(&sdp->sd_rindex_mutex); mutex_lock(&sdp->sd_rindex_mutex);
if (sdp->sd_rindex_vn != gl->gl_vn) { if (!sdp->sd_rindex_uptodate) {
error = gfs2_ri_update(ip); error = gfs2_ri_update(ip);
if (error) if (error)
gfs2_glock_dq_uninit(ri_gh); gfs2_glock_dq_uninit(ri_gh);
...@@ -655,21 +694,31 @@ int gfs2_rindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ri_gh) ...@@ -655,21 +694,31 @@ int gfs2_rindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ri_gh)
return error; return error;
} }
static void gfs2_rgrp_in(struct gfs2_rgrp_host *rg, const void *buf) static void gfs2_rgrp_in(struct gfs2_rgrpd *rgd, const void *buf)
{ {
const struct gfs2_rgrp *str = buf; const struct gfs2_rgrp *str = buf;
struct gfs2_rgrp_host *rg = &rgd->rd_rg;
u32 rg_flags;
rg->rg_flags = be32_to_cpu(str->rg_flags); rg_flags = be32_to_cpu(str->rg_flags);
if (rg_flags & GFS2_RGF_NOALLOC)
rgd->rd_flags |= GFS2_RDF_NOALLOC;
else
rgd->rd_flags &= ~GFS2_RDF_NOALLOC;
rg->rg_free = be32_to_cpu(str->rg_free); rg->rg_free = be32_to_cpu(str->rg_free);
rg->rg_dinodes = be32_to_cpu(str->rg_dinodes); rg->rg_dinodes = be32_to_cpu(str->rg_dinodes);
rg->rg_igeneration = be64_to_cpu(str->rg_igeneration); rg->rg_igeneration = be64_to_cpu(str->rg_igeneration);
} }
static void gfs2_rgrp_out(const struct gfs2_rgrp_host *rg, void *buf) static void gfs2_rgrp_out(struct gfs2_rgrpd *rgd, void *buf)
{ {
struct gfs2_rgrp *str = buf; struct gfs2_rgrp *str = buf;
struct gfs2_rgrp_host *rg = &rgd->rd_rg;
u32 rg_flags = 0;
str->rg_flags = cpu_to_be32(rg->rg_flags); if (rgd->rd_flags & GFS2_RDF_NOALLOC)
rg_flags |= GFS2_RGF_NOALLOC;
str->rg_flags = cpu_to_be32(rg_flags);
str->rg_free = cpu_to_be32(rg->rg_free); str->rg_free = cpu_to_be32(rg->rg_free);
str->rg_dinodes = cpu_to_be32(rg->rg_dinodes); str->rg_dinodes = cpu_to_be32(rg->rg_dinodes);
str->__pad = cpu_to_be32(0); str->__pad = cpu_to_be32(0);
...@@ -726,9 +775,9 @@ int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd) ...@@ -726,9 +775,9 @@ int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd)
} }
} }
if (rgd->rd_rg_vn != gl->gl_vn) { if (!(rgd->rd_flags & GFS2_RDF_UPTODATE)) {
gfs2_rgrp_in(&rgd->rd_rg, (rgd->rd_bits[0].bi_bh)->b_data); gfs2_rgrp_in(rgd, (rgd->rd_bits[0].bi_bh)->b_data);
rgd->rd_rg_vn = gl->gl_vn; rgd->rd_flags |= GFS2_RDF_UPTODATE;
} }
spin_lock(&sdp->sd_rindex_spin); spin_lock(&sdp->sd_rindex_spin);
...@@ -840,7 +889,7 @@ static int try_rgrp_fit(struct gfs2_rgrpd *rgd, struct gfs2_alloc *al) ...@@ -840,7 +889,7 @@ static int try_rgrp_fit(struct gfs2_rgrpd *rgd, struct gfs2_alloc *al)
struct gfs2_sbd *sdp = rgd->rd_sbd; struct gfs2_sbd *sdp = rgd->rd_sbd;
int ret = 0; int ret = 0;
if (rgd->rd_rg.rg_flags & GFS2_RGF_NOALLOC) if (rgd->rd_flags & GFS2_RDF_NOALLOC)
return 0; return 0;
spin_lock(&sdp->sd_rindex_spin); spin_lock(&sdp->sd_rindex_spin);
...@@ -866,13 +915,15 @@ static struct inode *try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked) ...@@ -866,13 +915,15 @@ static struct inode *try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked)
u32 goal = 0, block; u32 goal = 0, block;
u64 no_addr; u64 no_addr;
struct gfs2_sbd *sdp = rgd->rd_sbd; struct gfs2_sbd *sdp = rgd->rd_sbd;
unsigned int n;
for(;;) { for(;;) {
if (goal >= rgd->rd_data) if (goal >= rgd->rd_data)
break; break;
down_write(&sdp->sd_log_flush_lock); down_write(&sdp->sd_log_flush_lock);
n = 1;
block = rgblk_search(rgd, goal, GFS2_BLKST_UNLINKED, block = rgblk_search(rgd, goal, GFS2_BLKST_UNLINKED,
GFS2_BLKST_UNLINKED); GFS2_BLKST_UNLINKED, &n);
up_write(&sdp->sd_log_flush_lock); up_write(&sdp->sd_log_flush_lock);
if (block == BFITNOENT) if (block == BFITNOENT)
break; break;
...@@ -904,24 +955,20 @@ static struct inode *try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked) ...@@ -904,24 +955,20 @@ static struct inode *try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked)
static struct gfs2_rgrpd *recent_rgrp_first(struct gfs2_sbd *sdp, static struct gfs2_rgrpd *recent_rgrp_first(struct gfs2_sbd *sdp,
u64 rglast) u64 rglast)
{ {
struct gfs2_rgrpd *rgd = NULL; struct gfs2_rgrpd *rgd;
spin_lock(&sdp->sd_rindex_spin); spin_lock(&sdp->sd_rindex_spin);
if (list_empty(&sdp->sd_rindex_recent_list)) if (rglast) {
goto out; list_for_each_entry(rgd, &sdp->sd_rindex_recent_list, rd_recent) {
if (rgrp_contains_block(rgd, rglast))
if (!rglast) goto out;
goto first; }
list_for_each_entry(rgd, &sdp->sd_rindex_recent_list, rd_recent) {
if (rgd->rd_addr == rglast)
goto out;
} }
rgd = NULL;
first: if (!list_empty(&sdp->sd_rindex_recent_list))
rgd = list_entry(sdp->sd_rindex_recent_list.next, struct gfs2_rgrpd, rgd = list_entry(sdp->sd_rindex_recent_list.next,
rd_recent); struct gfs2_rgrpd, rd_recent);
out: out:
spin_unlock(&sdp->sd_rindex_spin); spin_unlock(&sdp->sd_rindex_spin);
return rgd; return rgd;
...@@ -1067,7 +1114,7 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked) ...@@ -1067,7 +1114,7 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked)
/* Try recently successful rgrps */ /* Try recently successful rgrps */
rgd = recent_rgrp_first(sdp, ip->i_last_rg_alloc); rgd = recent_rgrp_first(sdp, ip->i_goal);
while (rgd) { while (rgd) {
rg_locked = 0; rg_locked = 0;
...@@ -1151,8 +1198,6 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked) ...@@ -1151,8 +1198,6 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked)
} }
out: out:
ip->i_last_rg_alloc = rgd->rd_addr;
if (begin) { if (begin) {
recent_rgrp_add(rgd); recent_rgrp_add(rgd);
rgd = gfs2_rgrpd_get_next(rgd); rgd = gfs2_rgrpd_get_next(rgd);
...@@ -1275,6 +1320,7 @@ unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block) ...@@ -1275,6 +1320,7 @@ unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block)
* @goal: the goal block within the RG (start here to search for avail block) * @goal: the goal block within the RG (start here to search for avail block)
* @old_state: GFS2_BLKST_XXX the before-allocation state to find * @old_state: GFS2_BLKST_XXX the before-allocation state to find
* @new_state: GFS2_BLKST_XXX the after-allocation block state * @new_state: GFS2_BLKST_XXX the after-allocation block state
* @n: The extent length
* *
* Walk rgrp's bitmap to find bits that represent a block in @old_state. * Walk rgrp's bitmap to find bits that represent a block in @old_state.
* Add the found bitmap buffer to the transaction. * Add the found bitmap buffer to the transaction.
...@@ -1290,13 +1336,17 @@ unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block) ...@@ -1290,13 +1336,17 @@ unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block)
*/ */
static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal, static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal,
unsigned char old_state, unsigned char new_state) unsigned char old_state, unsigned char new_state,
unsigned int *n)
{ {
struct gfs2_bitmap *bi = NULL; struct gfs2_bitmap *bi = NULL;
u32 length = rgd->rd_length; const u32 length = rgd->rd_length;
u32 blk = 0; u32 blk = 0;
unsigned int buf, x; unsigned int buf, x;
const unsigned int elen = *n;
const u8 *buffer;
*n = 0;
/* Find bitmap block that contains bits for goal block */ /* Find bitmap block that contains bits for goal block */
for (buf = 0; buf < length; buf++) { for (buf = 0; buf < length; buf++) {
bi = rgd->rd_bits + buf; bi = rgd->rd_bits + buf;
...@@ -1317,12 +1367,11 @@ static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal, ...@@ -1317,12 +1367,11 @@ static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal,
for (x = 0; x <= length; x++) { for (x = 0; x <= length; x++) {
/* The GFS2_BLKST_UNLINKED state doesn't apply to the clone /* The GFS2_BLKST_UNLINKED state doesn't apply to the clone
bitmaps, so we must search the originals for that. */ bitmaps, so we must search the originals for that. */
buffer = bi->bi_bh->b_data + bi->bi_offset;
if (old_state != GFS2_BLKST_UNLINKED && bi->bi_clone) if (old_state != GFS2_BLKST_UNLINKED && bi->bi_clone)
blk = gfs2_bitfit(bi->bi_clone + bi->bi_offset, buffer = bi->bi_clone + bi->bi_offset;
bi->bi_len, goal, old_state);
else blk = gfs2_bitfit(buffer, bi->bi_len, goal, old_state);
blk = gfs2_bitfit(bi->bi_bh->b_data + bi->bi_offset,
bi->bi_len, goal, old_state);
if (blk != BFITNOENT) if (blk != BFITNOENT)
break; break;
...@@ -1333,12 +1382,23 @@ static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal, ...@@ -1333,12 +1382,23 @@ static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal,
} }
if (blk != BFITNOENT && old_state != new_state) { if (blk != BFITNOENT && old_state != new_state) {
*n = 1;
gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1); gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1);
gfs2_setbit(rgd, bi->bi_bh->b_data + bi->bi_offset, gfs2_setbit(rgd, bi->bi_bh->b_data, bi->bi_clone, bi->bi_offset,
bi->bi_len, blk, new_state); bi->bi_len, blk, new_state);
if (bi->bi_clone) goal = blk;
gfs2_setbit(rgd, bi->bi_clone + bi->bi_offset, while (*n < elen) {
bi->bi_len, blk, new_state); goal++;
if (goal >= (bi->bi_len * GFS2_NBBY))
break;
if (gfs2_testbit(rgd, buffer, bi->bi_len, goal) !=
GFS2_BLKST_FREE)
break;
gfs2_setbit(rgd, bi->bi_bh->b_data, bi->bi_clone,
bi->bi_offset, bi->bi_len, goal,
new_state);
(*n)++;
}
} }
return (blk == BFITNOENT) ? blk : (bi->bi_start * GFS2_NBBY) + blk; return (blk == BFITNOENT) ? blk : (bi->bi_start * GFS2_NBBY) + blk;
...@@ -1393,7 +1453,7 @@ static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, u64 bstart, ...@@ -1393,7 +1453,7 @@ static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, u64 bstart,
bi->bi_len); bi->bi_len);
} }
gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1); gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1);
gfs2_setbit(rgd, bi->bi_bh->b_data + bi->bi_offset, gfs2_setbit(rgd, bi->bi_bh->b_data, NULL, bi->bi_offset,
bi->bi_len, buf_blk, new_state); bi->bi_len, buf_blk, new_state);
} }
...@@ -1401,13 +1461,13 @@ static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, u64 bstart, ...@@ -1401,13 +1461,13 @@ static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, u64 bstart,
} }
/** /**
* gfs2_alloc_data - Allocate a data block * gfs2_alloc_block - Allocate a block
* @ip: the inode to allocate the data block for * @ip: the inode to allocate the block for
* *
* Returns: the allocated block * Returns: the allocated block
*/ */
u64 gfs2_alloc_data(struct gfs2_inode *ip) u64 gfs2_alloc_block(struct gfs2_inode *ip, unsigned int *n)
{ {
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_alloc *al = ip->i_alloc; struct gfs2_alloc *al = ip->i_alloc;
...@@ -1415,77 +1475,31 @@ u64 gfs2_alloc_data(struct gfs2_inode *ip) ...@@ -1415,77 +1475,31 @@ u64 gfs2_alloc_data(struct gfs2_inode *ip)
u32 goal, blk; u32 goal, blk;
u64 block; u64 block;
if (rgrp_contains_block(rgd, ip->i_di.di_goal_data)) if (rgrp_contains_block(rgd, ip->i_goal))
goal = ip->i_di.di_goal_data - rgd->rd_data0; goal = ip->i_goal - rgd->rd_data0;
else else
goal = rgd->rd_last_alloc_data; goal = rgd->rd_last_alloc;
blk = rgblk_search(rgd, goal, GFS2_BLKST_FREE, GFS2_BLKST_USED); blk = rgblk_search(rgd, goal, GFS2_BLKST_FREE, GFS2_BLKST_USED, n);
BUG_ON(blk == BFITNOENT); BUG_ON(blk == BFITNOENT);
rgd->rd_last_alloc_data = blk;
rgd->rd_last_alloc = blk;
block = rgd->rd_data0 + blk; block = rgd->rd_data0 + blk;
ip->i_di.di_goal_data = block; ip->i_goal = block;
gfs2_assert_withdraw(sdp, rgd->rd_rg.rg_free); gfs2_assert_withdraw(sdp, rgd->rd_rg.rg_free >= *n);
rgd->rd_rg.rg_free--; rgd->rd_rg.rg_free -= *n;
gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1); gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data); gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data);
al->al_alloced++; al->al_alloced += *n;
gfs2_statfs_change(sdp, 0, -1, 0); gfs2_statfs_change(sdp, 0, -*n, 0);
gfs2_quota_change(ip, +1, ip->i_inode.i_uid, ip->i_inode.i_gid); gfs2_quota_change(ip, *n, ip->i_inode.i_uid, ip->i_inode.i_gid);
spin_lock(&sdp->sd_rindex_spin); spin_lock(&sdp->sd_rindex_spin);
rgd->rd_free_clone--; rgd->rd_free_clone -= *n;
spin_unlock(&sdp->sd_rindex_spin);
return block;
}
/**
* gfs2_alloc_meta - Allocate a metadata block
* @ip: the inode to allocate the metadata block for
*
* Returns: the allocated block
*/
u64 gfs2_alloc_meta(struct gfs2_inode *ip)
{
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_alloc *al = ip->i_alloc;
struct gfs2_rgrpd *rgd = al->al_rgd;
u32 goal, blk;
u64 block;
if (rgrp_contains_block(rgd, ip->i_di.di_goal_meta))
goal = ip->i_di.di_goal_meta - rgd->rd_data0;
else
goal = rgd->rd_last_alloc_meta;
blk = rgblk_search(rgd, goal, GFS2_BLKST_FREE, GFS2_BLKST_USED);
BUG_ON(blk == BFITNOENT);
rgd->rd_last_alloc_meta = blk;
block = rgd->rd_data0 + blk;
ip->i_di.di_goal_meta = block;
gfs2_assert_withdraw(sdp, rgd->rd_rg.rg_free);
rgd->rd_rg.rg_free--;
gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data);
al->al_alloced++;
gfs2_statfs_change(sdp, 0, -1, 0);
gfs2_quota_change(ip, +1, ip->i_inode.i_uid, ip->i_inode.i_gid);
gfs2_trans_add_unrevoke(sdp, block);
spin_lock(&sdp->sd_rindex_spin);
rgd->rd_free_clone--;
spin_unlock(&sdp->sd_rindex_spin); spin_unlock(&sdp->sd_rindex_spin);
return block; return block;
...@@ -1505,12 +1519,13 @@ u64 gfs2_alloc_di(struct gfs2_inode *dip, u64 *generation) ...@@ -1505,12 +1519,13 @@ u64 gfs2_alloc_di(struct gfs2_inode *dip, u64 *generation)
struct gfs2_rgrpd *rgd = al->al_rgd; struct gfs2_rgrpd *rgd = al->al_rgd;
u32 blk; u32 blk;
u64 block; u64 block;
unsigned int n = 1;
blk = rgblk_search(rgd, rgd->rd_last_alloc_meta, blk = rgblk_search(rgd, rgd->rd_last_alloc,
GFS2_BLKST_FREE, GFS2_BLKST_DINODE); GFS2_BLKST_FREE, GFS2_BLKST_DINODE, &n);
BUG_ON(blk == BFITNOENT); BUG_ON(blk == BFITNOENT);
rgd->rd_last_alloc_meta = blk; rgd->rd_last_alloc = blk;
block = rgd->rd_data0 + blk; block = rgd->rd_data0 + blk;
...@@ -1519,12 +1534,12 @@ u64 gfs2_alloc_di(struct gfs2_inode *dip, u64 *generation) ...@@ -1519,12 +1534,12 @@ u64 gfs2_alloc_di(struct gfs2_inode *dip, u64 *generation)
rgd->rd_rg.rg_dinodes++; rgd->rd_rg.rg_dinodes++;
*generation = rgd->rd_rg.rg_igeneration++; *generation = rgd->rd_rg.rg_igeneration++;
gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1); gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data); gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data);
al->al_alloced++; al->al_alloced++;
gfs2_statfs_change(sdp, 0, -1, +1); gfs2_statfs_change(sdp, 0, -1, +1);
gfs2_trans_add_unrevoke(sdp, block); gfs2_trans_add_unrevoke(sdp, block, 1);
spin_lock(&sdp->sd_rindex_spin); spin_lock(&sdp->sd_rindex_spin);
rgd->rd_free_clone--; rgd->rd_free_clone--;
...@@ -1553,7 +1568,7 @@ void gfs2_free_data(struct gfs2_inode *ip, u64 bstart, u32 blen) ...@@ -1553,7 +1568,7 @@ void gfs2_free_data(struct gfs2_inode *ip, u64 bstart, u32 blen)
rgd->rd_rg.rg_free += blen; rgd->rd_rg.rg_free += blen;
gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1); gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data); gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data);
gfs2_trans_add_rg(rgd); gfs2_trans_add_rg(rgd);
...@@ -1581,7 +1596,7 @@ void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen) ...@@ -1581,7 +1596,7 @@ void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen)
rgd->rd_rg.rg_free += blen; rgd->rd_rg.rg_free += blen;
gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1); gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data); gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data);
gfs2_trans_add_rg(rgd); gfs2_trans_add_rg(rgd);
...@@ -1601,7 +1616,7 @@ void gfs2_unlink_di(struct inode *inode) ...@@ -1601,7 +1616,7 @@ void gfs2_unlink_di(struct inode *inode)
if (!rgd) if (!rgd)
return; return;
gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1); gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data); gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data);
gfs2_trans_add_rg(rgd); gfs2_trans_add_rg(rgd);
} }
...@@ -1621,7 +1636,7 @@ static void gfs2_free_uninit_di(struct gfs2_rgrpd *rgd, u64 blkno) ...@@ -1621,7 +1636,7 @@ static void gfs2_free_uninit_di(struct gfs2_rgrpd *rgd, u64 blkno)
rgd->rd_rg.rg_free++; rgd->rd_rg.rg_free++;
gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1); gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data); gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data);
gfs2_statfs_change(sdp, 0, +1, -1); gfs2_statfs_change(sdp, 0, +1, -1);
gfs2_trans_add_rg(rgd); gfs2_trans_add_rg(rgd);
...@@ -1699,8 +1714,7 @@ void gfs2_rlist_add(struct gfs2_sbd *sdp, struct gfs2_rgrp_list *rlist, ...@@ -1699,8 +1714,7 @@ void gfs2_rlist_add(struct gfs2_sbd *sdp, struct gfs2_rgrp_list *rlist,
* *
*/ */
void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, unsigned int state, void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, unsigned int state)
int flags)
{ {
unsigned int x; unsigned int x;
...@@ -1708,7 +1722,7 @@ void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, unsigned int state, ...@@ -1708,7 +1722,7 @@ void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, unsigned int state,
GFP_NOFS | __GFP_NOFAIL); GFP_NOFS | __GFP_NOFAIL);
for (x = 0; x < rlist->rl_rgrps; x++) for (x = 0; x < rlist->rl_rgrps; x++)
gfs2_holder_init(rlist->rl_rgd[x]->rd_gl, gfs2_holder_init(rlist->rl_rgd[x]->rd_gl,
state, flags, state, 0,
&rlist->rl_ghs[x]); &rlist->rl_ghs[x]);
} }
......
/* /*
* Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
* Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
* *
* This copyrighted material is made available to anyone wishing to use, * This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions * modify, copy, or redistribute it subject to the terms and conditions
...@@ -46,8 +46,7 @@ void gfs2_inplace_release(struct gfs2_inode *ip); ...@@ -46,8 +46,7 @@ void gfs2_inplace_release(struct gfs2_inode *ip);
unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block); unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block);
u64 gfs2_alloc_data(struct gfs2_inode *ip); u64 gfs2_alloc_block(struct gfs2_inode *ip, unsigned int *n);
u64 gfs2_alloc_meta(struct gfs2_inode *ip);
u64 gfs2_alloc_di(struct gfs2_inode *ip, u64 *generation); u64 gfs2_alloc_di(struct gfs2_inode *ip, u64 *generation);
void gfs2_free_data(struct gfs2_inode *ip, u64 bstart, u32 blen); void gfs2_free_data(struct gfs2_inode *ip, u64 bstart, u32 blen);
...@@ -64,8 +63,7 @@ struct gfs2_rgrp_list { ...@@ -64,8 +63,7 @@ struct gfs2_rgrp_list {
void gfs2_rlist_add(struct gfs2_sbd *sdp, struct gfs2_rgrp_list *rlist, void gfs2_rlist_add(struct gfs2_sbd *sdp, struct gfs2_rgrp_list *rlist,
u64 block); u64 block);
void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, unsigned int state, void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, unsigned int state);
int flags);
void gfs2_rlist_free(struct gfs2_rgrp_list *rlist); void gfs2_rlist_free(struct gfs2_rgrp_list *rlist);
u64 gfs2_ri_total(struct gfs2_sbd *sdp); u64 gfs2_ri_total(struct gfs2_sbd *sdp);
......
...@@ -210,7 +210,7 @@ int gfs2_read_super(struct gfs2_sbd *sdp, sector_t sector) ...@@ -210,7 +210,7 @@ int gfs2_read_super(struct gfs2_sbd *sdp, sector_t sector)
struct page *page; struct page *page;
struct bio *bio; struct bio *bio;
page = alloc_page(GFP_KERNEL); page = alloc_page(GFP_NOFS);
if (unlikely(!page)) if (unlikely(!page))
return -ENOBUFS; return -ENOBUFS;
...@@ -218,7 +218,7 @@ int gfs2_read_super(struct gfs2_sbd *sdp, sector_t sector) ...@@ -218,7 +218,7 @@ int gfs2_read_super(struct gfs2_sbd *sdp, sector_t sector)
ClearPageDirty(page); ClearPageDirty(page);
lock_page(page); lock_page(page);
bio = bio_alloc(GFP_KERNEL, 1); bio = bio_alloc(GFP_NOFS, 1);
if (unlikely(!bio)) { if (unlikely(!bio)) {
__free_page(page); __free_page(page);
return -ENOBUFS; return -ENOBUFS;
...@@ -316,6 +316,7 @@ int gfs2_read_sb(struct gfs2_sbd *sdp, struct gfs2_glock *gl, int silent) ...@@ -316,6 +316,7 @@ int gfs2_read_sb(struct gfs2_sbd *sdp, struct gfs2_glock *gl, int silent)
sdp->sd_heightsize[x] = space; sdp->sd_heightsize[x] = space;
} }
sdp->sd_max_height = x; sdp->sd_max_height = x;
sdp->sd_heightsize[x] = ~0;
gfs2_assert(sdp, sdp->sd_max_height <= GFS2_MAX_META_HEIGHT); gfs2_assert(sdp, sdp->sd_max_height <= GFS2_MAX_META_HEIGHT);
sdp->sd_jheightsize[0] = sdp->sd_sb.sb_bsize - sdp->sd_jheightsize[0] = sdp->sd_sb.sb_bsize -
...@@ -334,6 +335,7 @@ int gfs2_read_sb(struct gfs2_sbd *sdp, struct gfs2_glock *gl, int silent) ...@@ -334,6 +335,7 @@ int gfs2_read_sb(struct gfs2_sbd *sdp, struct gfs2_glock *gl, int silent)
sdp->sd_jheightsize[x] = space; sdp->sd_jheightsize[x] = space;
} }
sdp->sd_max_jheight = x; sdp->sd_max_jheight = x;
sdp->sd_jheightsize[x] = ~0;
gfs2_assert(sdp, sdp->sd_max_jheight <= GFS2_MAX_META_HEIGHT); gfs2_assert(sdp, sdp->sd_max_jheight <= GFS2_MAX_META_HEIGHT);
return 0; return 0;
......
...@@ -17,6 +17,7 @@ void gfs2_tune_init(struct gfs2_tune *gt); ...@@ -17,6 +17,7 @@ void gfs2_tune_init(struct gfs2_tune *gt);
int gfs2_check_sb(struct gfs2_sbd *sdp, struct gfs2_sb_host *sb, int silent); int gfs2_check_sb(struct gfs2_sbd *sdp, struct gfs2_sb_host *sb, int silent);
int gfs2_read_sb(struct gfs2_sbd *sdp, struct gfs2_glock *gl, int silent); int gfs2_read_sb(struct gfs2_sbd *sdp, struct gfs2_glock *gl, int silent);
int gfs2_read_super(struct gfs2_sbd *sdp, sector_t sector); int gfs2_read_super(struct gfs2_sbd *sdp, sector_t sector);
void gfs2_lm_unmount(struct gfs2_sbd *sdp);
static inline unsigned int gfs2_jindex_size(struct gfs2_sbd *sdp) static inline unsigned int gfs2_jindex_size(struct gfs2_sbd *sdp)
{ {
......
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include "gfs2.h" #include "gfs2.h"
#include "incore.h" #include "incore.h"
#include "lm.h"
#include "sys.h" #include "sys.h"
#include "super.h" #include "super.h"
#include "glock.h" #include "glock.h"
...@@ -328,15 +327,9 @@ static ssize_t name##_show(struct gfs2_sbd *sdp, char *buf) \ ...@@ -328,15 +327,9 @@ static ssize_t name##_show(struct gfs2_sbd *sdp, char *buf) \
} \ } \
static struct counters_attr counters_attr_##name = __ATTR_RO(name) static struct counters_attr counters_attr_##name = __ATTR_RO(name)
COUNTERS_ATTR(glock_count, "%u\n");
COUNTERS_ATTR(glock_held_count, "%u\n");
COUNTERS_ATTR(inode_count, "%u\n");
COUNTERS_ATTR(reclaimed, "%u\n"); COUNTERS_ATTR(reclaimed, "%u\n");
static struct attribute *counters_attrs[] = { static struct attribute *counters_attrs[] = {
&counters_attr_glock_count.attr,
&counters_attr_glock_held_count.attr,
&counters_attr_inode_count.attr,
&counters_attr_reclaimed.attr, &counters_attr_reclaimed.attr,
NULL, NULL,
}; };
......
...@@ -146,30 +146,25 @@ void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd) ...@@ -146,30 +146,25 @@ void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd)
lops_add(sdp, &bd->bd_le); lops_add(sdp, &bd->bd_le);
} }
void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno) void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno, unsigned int len)
{ {
struct gfs2_bufdata *bd; struct gfs2_bufdata *bd, *tmp;
int found = 0; struct gfs2_trans *tr = current->journal_info;
unsigned int n = len;
gfs2_log_lock(sdp); gfs2_log_lock(sdp);
list_for_each_entry_safe(bd, tmp, &sdp->sd_log_le_revoke, bd_le.le_list) {
list_for_each_entry(bd, &sdp->sd_log_le_revoke, bd_le.le_list) { if ((bd->bd_blkno >= blkno) && (bd->bd_blkno < (blkno + len))) {
if (bd->bd_blkno == blkno) {
list_del_init(&bd->bd_le.le_list); list_del_init(&bd->bd_le.le_list);
gfs2_assert_withdraw(sdp, sdp->sd_log_num_revoke); gfs2_assert_withdraw(sdp, sdp->sd_log_num_revoke);
sdp->sd_log_num_revoke--; sdp->sd_log_num_revoke--;
found = 1; kmem_cache_free(gfs2_bufdata_cachep, bd);
break; tr->tr_num_revoke_rm++;
if (--n == 0)
break;
} }
} }
gfs2_log_unlock(sdp); gfs2_log_unlock(sdp);
if (found) {
struct gfs2_trans *tr = current->journal_info;
kmem_cache_free(gfs2_bufdata_cachep, bd);
tr->tr_num_revoke_rm++;
}
} }
void gfs2_trans_add_rg(struct gfs2_rgrpd *rgd) void gfs2_trans_add_rg(struct gfs2_rgrpd *rgd)
......
...@@ -32,7 +32,7 @@ void gfs2_trans_end(struct gfs2_sbd *sdp); ...@@ -32,7 +32,7 @@ void gfs2_trans_end(struct gfs2_sbd *sdp);
void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta); void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta);
void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd); void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd);
void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno); void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno, unsigned int len);
void gfs2_trans_add_rg(struct gfs2_rgrpd *rgd); void gfs2_trans_add_rg(struct gfs2_rgrpd *rgd);
#endif /* __TRANS_DOT_H__ */ #endif /* __TRANS_DOT_H__ */
...@@ -19,12 +19,12 @@ ...@@ -19,12 +19,12 @@
#include "gfs2.h" #include "gfs2.h"
#include "incore.h" #include "incore.h"
#include "glock.h" #include "glock.h"
#include "lm.h"
#include "util.h" #include "util.h"
struct kmem_cache *gfs2_glock_cachep __read_mostly; struct kmem_cache *gfs2_glock_cachep __read_mostly;
struct kmem_cache *gfs2_inode_cachep __read_mostly; struct kmem_cache *gfs2_inode_cachep __read_mostly;
struct kmem_cache *gfs2_bufdata_cachep __read_mostly; struct kmem_cache *gfs2_bufdata_cachep __read_mostly;
struct kmem_cache *gfs2_rgrpd_cachep __read_mostly;
void gfs2_assert_i(struct gfs2_sbd *sdp) void gfs2_assert_i(struct gfs2_sbd *sdp)
{ {
...@@ -32,6 +32,28 @@ void gfs2_assert_i(struct gfs2_sbd *sdp) ...@@ -32,6 +32,28 @@ void gfs2_assert_i(struct gfs2_sbd *sdp)
sdp->sd_fsname); sdp->sd_fsname);
} }
int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...)
{
va_list args;
if (test_and_set_bit(SDF_SHUTDOWN, &sdp->sd_flags))
return 0;
va_start(args, fmt);
vprintk(fmt, args);
va_end(args);
fs_err(sdp, "about to withdraw this file system\n");
BUG_ON(sdp->sd_args.ar_debug);
fs_err(sdp, "telling LM to withdraw\n");
gfs2_withdraw_lockproto(&sdp->sd_lockstruct);
fs_err(sdp, "withdrawn\n");
dump_stack();
return -1;
}
/** /**
* gfs2_assert_withdraw_i - Cause the machine to withdraw if @assertion is false * gfs2_assert_withdraw_i - Cause the machine to withdraw if @assertion is false
* Returns: -1 if this call withdrew the machine, * Returns: -1 if this call withdrew the machine,
......
...@@ -147,6 +147,7 @@ gfs2_io_error_bh_i((sdp), (bh), __FUNCTION__, __FILE__, __LINE__); ...@@ -147,6 +147,7 @@ gfs2_io_error_bh_i((sdp), (bh), __FUNCTION__, __FILE__, __LINE__);
extern struct kmem_cache *gfs2_glock_cachep; extern struct kmem_cache *gfs2_glock_cachep;
extern struct kmem_cache *gfs2_inode_cachep; extern struct kmem_cache *gfs2_inode_cachep;
extern struct kmem_cache *gfs2_bufdata_cachep; extern struct kmem_cache *gfs2_bufdata_cachep;
extern struct kmem_cache *gfs2_rgrpd_cachep;
static inline unsigned int gfs2_tune_get_i(struct gfs2_tune *gt, static inline unsigned int gfs2_tune_get_i(struct gfs2_tune *gt,
unsigned int *p) unsigned int *p)
...@@ -163,6 +164,7 @@ gfs2_tune_get_i(&(sdp)->sd_tune, &(sdp)->sd_tune.field) ...@@ -163,6 +164,7 @@ gfs2_tune_get_i(&(sdp)->sd_tune, &(sdp)->sd_tune.field)
void gfs2_icbit_munge(struct gfs2_sbd *sdp, unsigned char **bitmap, void gfs2_icbit_munge(struct gfs2_sbd *sdp, unsigned char **bitmap,
unsigned int bit, int new_value); unsigned int bit, int new_value);
int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...);
#endif /* __UTIL_DOT_H__ */ #endif /* __UTIL_DOT_H__ */
...@@ -21,9 +21,15 @@ typedef void (*lm_callback_t) (void *ptr, unsigned int type, void *data); ...@@ -21,9 +21,15 @@ typedef void (*lm_callback_t) (void *ptr, unsigned int type, void *data);
* modify the filesystem. The lock module shouldn't assign a journal to the FS * modify the filesystem. The lock module shouldn't assign a journal to the FS
* mount. It shouldn't send recovery callbacks to the FS mount. If the node * mount. It shouldn't send recovery callbacks to the FS mount. If the node
* dies or withdraws, all locks can be wiped immediately. * dies or withdraws, all locks can be wiped immediately.
*
* LM_MFLAG_CONV_NODROP
* Do not allow the dlm to internally resolve conversion deadlocks by demoting
* the lock to unlocked and then reacquiring it in the requested mode. Instead,
* it should cancel the request and return LM_OUT_CONV_DEADLK.
*/ */
#define LM_MFLAG_SPECTATOR 0x00000001 #define LM_MFLAG_SPECTATOR 0x00000001
#define LM_MFLAG_CONV_NODROP 0x00000002
/* /*
* lm_lockstruct flags * lm_lockstruct flags
...@@ -110,6 +116,9 @@ typedef void (*lm_callback_t) (void *ptr, unsigned int type, void *data); ...@@ -110,6 +116,9 @@ typedef void (*lm_callback_t) (void *ptr, unsigned int type, void *data);
* *
* LM_OUT_ASYNC * LM_OUT_ASYNC
* The result of the request will be returned in an LM_CB_ASYNC callback. * The result of the request will be returned in an LM_CB_ASYNC callback.
*
* LM_OUT_CONV_DEADLK
* The lock request was canceled do to a conversion deadlock.
*/ */
#define LM_OUT_ST_MASK 0x00000003 #define LM_OUT_ST_MASK 0x00000003
...@@ -117,6 +126,7 @@ typedef void (*lm_callback_t) (void *ptr, unsigned int type, void *data); ...@@ -117,6 +126,7 @@ typedef void (*lm_callback_t) (void *ptr, unsigned int type, void *data);
#define LM_OUT_CANCELED 0x00000008 #define LM_OUT_CANCELED 0x00000008
#define LM_OUT_ASYNC 0x00000080 #define LM_OUT_ASYNC 0x00000080
#define LM_OUT_ERROR 0x00000100 #define LM_OUT_ERROR 0x00000100
#define LM_OUT_CONV_DEADLK 0x00000200
/* /*
* lm_callback_t types * lm_callback_t types
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment