Commit f793f296 authored by Linus Torvalds's avatar Linus Torvalds

Merge http://sucs.org/~rohan/git/gfs2-3.0-nmw

* http://sucs.org/~rohan/git/gfs2-3.0-nmw: (24 commits)
  GFS2: Move readahead of metadata during deallocation into its own function
  GFS2: Remove two unused variables
  GFS2: Misc fixes
  GFS2: rewrite fallocate code to write blocks directly
  GFS2: speed up delete/unlink performance for large files
  GFS2: Fix off-by-one in gfs2_blk2rgrpd
  GFS2: Clean up ->page_mkwrite
  GFS2: Correctly set goal block after allocation
  GFS2: Fix AIL flush issue during fsync
  GFS2: Use cached rgrp in gfs2_rlist_add()
  GFS2: Call do_strip() directly from recursive_scan()
  GFS2: Remove obsolete assert
  GFS2: Cache the most recently used resource group in the inode
  GFS2: Make resource groups "append only" during life of fs
  GFS2: Use rbtree for resource groups and clean up bitmap buffer ref count scheme
  GFS2: Fix lseek after SEEK_DATA, SEEK_HOLE have been added
  GFS2: Clean up gfs2_create
  GFS2: Use ->dirty_inode()
  GFS2: Fix bug trap and journaled data fsync
  GFS2: Fix inode allocation error path
  ...
parents dabcbb1b b99b98dc
......@@ -82,7 +82,7 @@ static int gfs2_set_mode(struct inode *inode, umode_t mode)
iattr.ia_valid = ATTR_MODE;
iattr.ia_mode = mode;
error = gfs2_setattr_simple(GFS2_I(inode), &iattr);
error = gfs2_setattr_simple(inode, &iattr);
}
return error;
......@@ -160,6 +160,7 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct inode *inode)
int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr)
{
struct inode *inode = &ip->i_inode;
struct posix_acl *acl;
char *data;
unsigned int len;
......@@ -169,7 +170,7 @@ int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr)
if (IS_ERR(acl))
return PTR_ERR(acl);
if (!acl)
return gfs2_setattr_simple(ip, attr);
return gfs2_setattr_simple(inode, attr);
error = posix_acl_chmod(&acl, GFP_NOFS, attr->ia_mode);
if (error)
......
......@@ -663,7 +663,7 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,
if (&ip->i_inode == sdp->sd_rindex)
rblocks += 2 * RES_STATFS;
if (alloc_required)
rblocks += gfs2_rg_blocks(al);
rblocks += gfs2_rg_blocks(ip);
error = gfs2_trans_begin(sdp, rblocks,
PAGE_CACHE_SIZE/sdp->sd_sb.sb_bsize);
......@@ -787,7 +787,6 @@ static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh,
u64 to = pos + copied;
void *kaddr;
unsigned char *buf = dibh->b_data + sizeof(struct gfs2_dinode);
struct gfs2_dinode *di = (struct gfs2_dinode *)dibh->b_data;
BUG_ON((pos + len) > (dibh->b_size - sizeof(struct gfs2_dinode)));
kaddr = kmap_atomic(page, KM_USER0);
......@@ -804,7 +803,6 @@ static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh,
if (copied) {
if (inode->i_size < to)
i_size_write(inode, to);
gfs2_dinode_out(ip, di);
mark_inode_dirty(inode);
}
......@@ -873,10 +871,6 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping,
gfs2_page_add_databufs(ip, page, from, to);
ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata);
if (ret > 0) {
gfs2_dinode_out(ip, dibh->b_data);
mark_inode_dirty(inode);
}
if (inode == sdp->sd_rindex) {
adjust_fs_space(inode);
......
......@@ -10,6 +10,7 @@
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/buffer_head.h>
#include <linux/blkdev.h>
#include <linux/gfs2_ondisk.h>
#include <linux/crc32.h>
......@@ -36,11 +37,6 @@ struct metapath {
__u16 mp_list[GFS2_MAX_META_HEIGHT];
};
typedef int (*block_call_t) (struct gfs2_inode *ip, struct buffer_head *dibh,
struct buffer_head *bh, __be64 *top,
__be64 *bottom, unsigned int height,
void *data);
struct strip_mine {
int sm_first;
unsigned int sm_height;
......@@ -273,6 +269,30 @@ static inline __be64 *metapointer(unsigned int height, const struct metapath *mp
return ((__be64 *)(bh->b_data + head_size)) + mp->mp_list[height];
}
static void gfs2_metapath_ra(struct gfs2_glock *gl,
const struct buffer_head *bh, const __be64 *pos)
{
struct buffer_head *rabh;
const __be64 *endp = (const __be64 *)(bh->b_data + bh->b_size);
const __be64 *t;
for (t = pos; t < endp; t++) {
if (!*t)
continue;
rabh = gfs2_getbuf(gl, be64_to_cpu(*t), CREATE);
if (trylock_buffer(rabh)) {
if (!buffer_uptodate(rabh)) {
rabh->b_end_io = end_buffer_read_sync;
submit_bh(READA | REQ_META, rabh);
continue;
}
unlock_buffer(rabh);
}
brelse(rabh);
}
}
/**
* lookup_metapath - Walk the metadata tree to a specific point
* @ip: The inode
......@@ -432,12 +452,14 @@ static int gfs2_bmap_alloc(struct inode *inode, const sector_t lblock,
{
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_sbd *sdp = GFS2_SB(inode);
struct super_block *sb = sdp->sd_vfs;
struct buffer_head *dibh = mp->mp_bh[0];
u64 bn, dblock = 0;
unsigned n, i, blks, alloced = 0, iblks = 0, branch_start = 0;
unsigned dblks = 0;
unsigned ptrs_per_blk;
const unsigned end_of_metadata = height - 1;
int ret;
int eob = 0;
enum alloc_state state;
__be64 *ptr;
......@@ -540,6 +562,15 @@ static int gfs2_bmap_alloc(struct inode *inode, const sector_t lblock,
dblock = bn;
while (n-- > 0)
*ptr++ = cpu_to_be64(bn++);
if (buffer_zeronew(bh_map)) {
ret = sb_issue_zeroout(sb, dblock, dblks,
GFP_NOFS);
if (ret) {
fs_err(sdp,
"Failed to zero data buffers\n");
clear_buffer_zeronew(bh_map);
}
}
break;
}
} while ((state != ALLOC_DATA) || !dblock);
......@@ -667,76 +698,6 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi
return ret;
}
/**
* recursive_scan - recursively scan through the end of a file
* @ip: the inode
* @dibh: the dinode buffer
* @mp: the path through the metadata to the point to start
* @height: the height the recursion is at
* @block: the indirect block to look at
* @first: 1 if this is the first block
* @bc: the call to make for each piece of metadata
* @data: data opaque to this function to pass to @bc
*
* When this is first called @height and @block should be zero and
* @first should be 1.
*
* Returns: errno
*/
static int recursive_scan(struct gfs2_inode *ip, struct buffer_head *dibh,
struct metapath *mp, unsigned int height,
u64 block, int first, block_call_t bc,
void *data)
{
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct buffer_head *bh = NULL;
__be64 *top, *bottom;
u64 bn;
int error;
int mh_size = sizeof(struct gfs2_meta_header);
if (!height) {
error = gfs2_meta_inode_buffer(ip, &bh);
if (error)
return error;
dibh = bh;
top = (__be64 *)(bh->b_data + sizeof(struct gfs2_dinode)) + mp->mp_list[0];
bottom = (__be64 *)(bh->b_data + sizeof(struct gfs2_dinode)) + sdp->sd_diptrs;
} else {
error = gfs2_meta_indirect_buffer(ip, height, block, 0, &bh);
if (error)
return error;
top = (__be64 *)(bh->b_data + mh_size) +
(first ? mp->mp_list[height] : 0);
bottom = (__be64 *)(bh->b_data + mh_size) + sdp->sd_inptrs;
}
error = bc(ip, dibh, bh, top, bottom, height, data);
if (error)
goto out;
if (height < ip->i_height - 1)
for (; top < bottom; top++, first = 0) {
if (!*top)
continue;
bn = be64_to_cpu(*top);
error = recursive_scan(ip, dibh, mp, height + 1, bn,
first, bc, data);
if (error)
break;
}
out:
brelse(bh);
return error;
}
/**
* do_strip - Look for a layer a particular layer of the file and strip it off
* @ip: the inode
......@@ -752,9 +713,8 @@ static int recursive_scan(struct gfs2_inode *ip, struct buffer_head *dibh,
static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
struct buffer_head *bh, __be64 *top, __be64 *bottom,
unsigned int height, void *data)
unsigned int height, struct strip_mine *sm)
{
struct strip_mine *sm = data;
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_rgrp_list rlist;
u64 bn, bstart;
......@@ -783,11 +743,6 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
else if (ip->i_depth)
revokes = sdp->sd_inptrs;
if (ip != GFS2_I(sdp->sd_rindex))
error = gfs2_rindex_hold(sdp, &ip->i_alloc->al_ri_gh);
else if (!sdp->sd_rgrps)
error = gfs2_ri_update(ip);
if (error)
return error;
......@@ -805,7 +760,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
blen++;
else {
if (bstart)
gfs2_rlist_add(sdp, &rlist, bstart);
gfs2_rlist_add(ip, &rlist, bstart);
bstart = bn;
blen = 1;
......@@ -813,7 +768,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
}
if (bstart)
gfs2_rlist_add(sdp, &rlist, bstart);
gfs2_rlist_add(ip, &rlist, bstart);
else
goto out; /* Nothing to do */
......@@ -887,11 +842,81 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
out_rlist:
gfs2_rlist_free(&rlist);
out:
if (ip != GFS2_I(sdp->sd_rindex))
gfs2_glock_dq_uninit(&ip->i_alloc->al_ri_gh);
return error;
}
/**
* recursive_scan - recursively scan through the end of a file
* @ip: the inode
* @dibh: the dinode buffer
* @mp: the path through the metadata to the point to start
* @height: the height the recursion is at
* @block: the indirect block to look at
* @first: 1 if this is the first block
* @sm: data opaque to this function to pass to @bc
*
* When this is first called @height and @block should be zero and
* @first should be 1.
*
* Returns: errno
*/
static int recursive_scan(struct gfs2_inode *ip, struct buffer_head *dibh,
struct metapath *mp, unsigned int height,
u64 block, int first, struct strip_mine *sm)
{
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct buffer_head *bh = NULL;
__be64 *top, *bottom;
u64 bn;
int error;
int mh_size = sizeof(struct gfs2_meta_header);
if (!height) {
error = gfs2_meta_inode_buffer(ip, &bh);
if (error)
return error;
dibh = bh;
top = (__be64 *)(bh->b_data + sizeof(struct gfs2_dinode)) + mp->mp_list[0];
bottom = (__be64 *)(bh->b_data + sizeof(struct gfs2_dinode)) + sdp->sd_diptrs;
} else {
error = gfs2_meta_indirect_buffer(ip, height, block, 0, &bh);
if (error)
return error;
top = (__be64 *)(bh->b_data + mh_size) +
(first ? mp->mp_list[height] : 0);
bottom = (__be64 *)(bh->b_data + mh_size) + sdp->sd_inptrs;
}
error = do_strip(ip, dibh, bh, top, bottom, height, sm);
if (error)
goto out;
if (height < ip->i_height - 1) {
gfs2_metapath_ra(ip->i_gl, bh, top);
for (; top < bottom; top++, first = 0) {
if (!*top)
continue;
bn = be64_to_cpu(*top);
error = recursive_scan(ip, dibh, mp, height + 1, bn,
first, sm);
if (error)
break;
}
}
out:
brelse(bh);
return error;
}
/**
* gfs2_block_truncate_page - Deal with zeroing out data for truncate
*
......@@ -1031,7 +1056,7 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 size)
sm.sm_first = !!size;
sm.sm_height = height;
error = recursive_scan(ip, NULL, &mp, 0, 0, 1, do_strip, &sm);
error = recursive_scan(ip, NULL, &mp, 0, 0, 1, &sm);
if (error)
break;
}
......
......@@ -240,16 +240,15 @@ static int gfs2_dir_write_data(struct gfs2_inode *ip, const char *buf,
return error;
}
static int gfs2_dir_read_stuffed(struct gfs2_inode *ip, char *buf,
u64 offset, unsigned int size)
static int gfs2_dir_read_stuffed(struct gfs2_inode *ip, __be64 *buf,
unsigned int size)
{
struct buffer_head *dibh;
int error;
error = gfs2_meta_inode_buffer(ip, &dibh);
if (!error) {
offset += sizeof(struct gfs2_dinode);
memcpy(buf, dibh->b_data + offset, size);
memcpy(buf, dibh->b_data + sizeof(struct gfs2_dinode), size);
brelse(dibh);
}
......@@ -261,13 +260,12 @@ static int gfs2_dir_read_stuffed(struct gfs2_inode *ip, char *buf,
* gfs2_dir_read_data - Read a data from a directory inode
* @ip: The GFS2 Inode
* @buf: The buffer to place result into
* @offset: File offset to begin jdata_readng from
* @size: Amount of data to transfer
*
* Returns: The amount of data actually copied or the error
*/
static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, u64 offset,
unsigned int size, unsigned ra)
static int gfs2_dir_read_data(struct gfs2_inode *ip, __be64 *buf,
unsigned int size)
{
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
u64 lblock, dblock;
......@@ -275,24 +273,14 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, u64 offset,
unsigned int o;
int copied = 0;
int error = 0;
u64 disksize = i_size_read(&ip->i_inode);
if (offset >= disksize)
return 0;
if (offset + size > disksize)
size = disksize - offset;
if (!size)
return 0;
if (gfs2_is_stuffed(ip))
return gfs2_dir_read_stuffed(ip, buf, offset, size);
return gfs2_dir_read_stuffed(ip, buf, size);
if (gfs2_assert_warn(sdp, gfs2_is_jdata(ip)))
return -EINVAL;
lblock = offset;
lblock = 0;
o = do_div(lblock, sdp->sd_jbsize) + sizeof(struct gfs2_meta_header);
while (copied < size) {
......@@ -311,8 +299,6 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, u64 offset,
if (error || !dblock)
goto fail;
BUG_ON(extlen < 1);
if (!ra)
extlen = 1;
bh = gfs2_meta_ra(ip->i_gl, dblock, extlen);
} else {
error = gfs2_meta_read(ip->i_gl, dblock, DIO_WAIT, &bh);
......@@ -328,7 +314,7 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, u64 offset,
extlen--;
memcpy(buf, bh->b_data + o, amount);
brelse(bh);
buf += amount;
buf += (amount/sizeof(__be64));
copied += amount;
lblock++;
o = sizeof(struct gfs2_meta_header);
......@@ -371,7 +357,7 @@ static __be64 *gfs2_dir_get_hash_table(struct gfs2_inode *ip)
if (hc == NULL)
return ERR_PTR(-ENOMEM);
ret = gfs2_dir_read_data(ip, (char *)hc, 0, hsize, 1);
ret = gfs2_dir_read_data(ip, hc, hsize);
if (ret < 0) {
kfree(hc);
return ERR_PTR(ret);
......@@ -1695,7 +1681,6 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry)
const struct qstr *name = &dentry->d_name;
struct gfs2_dirent *dent, *prev = NULL;
struct buffer_head *bh;
int error;
/* Returns _either_ the entry (if its first in block) or the
previous entry otherwise */
......@@ -1724,22 +1709,15 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry)
}
brelse(bh);
error = gfs2_meta_inode_buffer(dip, &bh);
if (error)
return error;
if (!dip->i_entries)
gfs2_consist_inode(dip);
gfs2_trans_add_bh(dip->i_gl, bh, 1);
dip->i_entries--;
dip->i_inode.i_mtime = dip->i_inode.i_ctime = CURRENT_TIME;
if (S_ISDIR(dentry->d_inode->i_mode))
drop_nlink(&dip->i_inode);
gfs2_dinode_out(dip, bh->b_data);
brelse(bh);
mark_inode_dirty(&dip->i_inode);
return error;
return 0;
}
/**
......@@ -1829,10 +1807,6 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len,
if (error)
goto out_put;
error = gfs2_rindex_hold(sdp, &dip->i_alloc->al_ri_gh);
if (error)
goto out_qs;
/* Count the number of leaves */
bh = leaf_bh;
......@@ -1847,7 +1821,7 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len,
if (blk != leaf_no)
brelse(bh);
gfs2_rlist_add(sdp, &rlist, blk);
gfs2_rlist_add(dip, &rlist, blk);
l_blocks++;
}
......@@ -1911,8 +1885,6 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len,
gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs);
out_rlist:
gfs2_rlist_free(&rlist);
gfs2_glock_dq_uninit(&dip->i_alloc->al_ri_gh);
out_qs:
gfs2_quota_unhold(dip);
out_put:
gfs2_alloc_put(dip);
......
This diff is collapsed.
......@@ -28,40 +28,55 @@
#include "trans.h"
#include "dir.h"
static void gfs2_ail_error(struct gfs2_glock *gl, const struct buffer_head *bh)
{
fs_err(gl->gl_sbd, "AIL buffer %p: blocknr %llu state 0x%08lx mapping %p page state 0x%lx\n",
bh, (unsigned long long)bh->b_blocknr, bh->b_state,
bh->b_page->mapping, bh->b_page->flags);
fs_err(gl->gl_sbd, "AIL glock %u:%llu mapping %p\n",
gl->gl_name.ln_type, gl->gl_name.ln_number,
gfs2_glock2aspace(gl));
gfs2_lm_withdraw(gl->gl_sbd, "AIL error\n");
}
/**
* __gfs2_ail_flush - remove all buffers for a given lock from the AIL
* @gl: the glock
* @fsync: set when called from fsync (not all buffers will be clean)
*
* None of the buffers should be dirty, locked, or pinned.
*/
static void __gfs2_ail_flush(struct gfs2_glock *gl)
static void __gfs2_ail_flush(struct gfs2_glock *gl, bool fsync)
{
struct gfs2_sbd *sdp = gl->gl_sbd;
struct list_head *head = &gl->gl_ail_list;
struct gfs2_bufdata *bd;
struct gfs2_bufdata *bd, *tmp;
struct buffer_head *bh;
const unsigned long b_state = (1UL << BH_Dirty)|(1UL << BH_Pinned)|(1UL << BH_Lock);
sector_t blocknr;
gfs2_log_lock(sdp);
spin_lock(&sdp->sd_ail_lock);
while (!list_empty(head)) {
bd = list_entry(head->next, struct gfs2_bufdata,
bd_ail_gl_list);
list_for_each_entry_safe(bd, tmp, head, bd_ail_gl_list) {
bh = bd->bd_bh;
gfs2_remove_from_ail(bd);
bd->bd_bh = NULL;
if (bh->b_state & b_state) {
if (fsync)
continue;
gfs2_ail_error(gl, bh);
}
blocknr = bh->b_blocknr;
bh->b_private = NULL;
spin_unlock(&sdp->sd_ail_lock);
gfs2_remove_from_ail(bd); /* drops ref on bh */
bd->bd_blkno = bh->b_blocknr;
gfs2_log_lock(sdp);
gfs2_assert_withdraw(sdp, !buffer_busy(bh));
gfs2_trans_add_revoke(sdp, bd);
gfs2_log_unlock(sdp);
bd->bd_bh = NULL;
bd->bd_blkno = blocknr;
spin_lock(&sdp->sd_ail_lock);
gfs2_trans_add_revoke(sdp, bd);
}
gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count));
BUG_ON(!fsync && atomic_read(&gl->gl_ail_count));
spin_unlock(&sdp->sd_ail_lock);
gfs2_log_unlock(sdp);
}
......@@ -84,13 +99,13 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl)
BUG_ON(current->journal_info);
current->journal_info = &tr;
__gfs2_ail_flush(gl);
__gfs2_ail_flush(gl, 0);
gfs2_trans_end(sdp);
gfs2_log_flush(sdp, NULL);
}
void gfs2_ail_flush(struct gfs2_glock *gl)
void gfs2_ail_flush(struct gfs2_glock *gl, bool fsync)
{
struct gfs2_sbd *sdp = gl->gl_sbd;
unsigned int revokes = atomic_read(&gl->gl_ail_count);
......@@ -102,7 +117,7 @@ void gfs2_ail_flush(struct gfs2_glock *gl)
ret = gfs2_trans_begin(sdp, 0, revokes);
if (ret)
return;
__gfs2_ail_flush(gl);
__gfs2_ail_flush(gl, fsync);
gfs2_trans_end(sdp);
gfs2_log_flush(sdp, NULL);
}
......@@ -119,6 +134,7 @@ void gfs2_ail_flush(struct gfs2_glock *gl)
static void rgrp_go_sync(struct gfs2_glock *gl)
{
struct address_space *metamapping = gfs2_glock2aspace(gl);
struct gfs2_rgrpd *rgd;
int error;
if (!test_and_clear_bit(GLF_DIRTY, &gl->gl_flags))
......@@ -130,6 +146,12 @@ static void rgrp_go_sync(struct gfs2_glock *gl)
error = filemap_fdatawait(metamapping);
mapping_set_error(metamapping, error);
gfs2_ail_empty_gl(gl);
spin_lock(&gl->gl_spin);
rgd = gl->gl_object;
if (rgd)
gfs2_free_clones(rgd);
spin_unlock(&gl->gl_spin);
}
/**
......@@ -429,33 +451,6 @@ static int inode_go_dump(struct seq_file *seq, const struct gfs2_glock *gl)
return 0;
}
/**
* rgrp_go_lock - operation done after an rgrp lock is locked by
* a first holder on this node.
* @gl: the glock
* @flags:
*
* Returns: errno
*/
static int rgrp_go_lock(struct gfs2_holder *gh)
{
return gfs2_rgrp_bh_get(gh->gh_gl->gl_object);
}
/**
* rgrp_go_unlock - operation done before an rgrp lock is unlocked by
* a last holder on this node.
* @gl: the glock
* @flags:
*
*/
static void rgrp_go_unlock(struct gfs2_holder *gh)
{
gfs2_rgrp_bh_put(gh->gh_gl->gl_object);
}
/**
* trans_go_sync - promote/demote the transaction glock
* @gl: the glock
......@@ -558,8 +553,8 @@ const struct gfs2_glock_operations gfs2_inode_glops = {
const struct gfs2_glock_operations gfs2_rgrp_glops = {
.go_xmote_th = rgrp_go_sync,
.go_inval = rgrp_go_inval,
.go_lock = rgrp_go_lock,
.go_unlock = rgrp_go_unlock,
.go_lock = gfs2_rgrp_go_lock,
.go_unlock = gfs2_rgrp_go_unlock,
.go_dump = gfs2_rgrp_dump,
.go_type = LM_TYPE_RGRP,
.go_flags = GLOF_ASPACE,
......
......@@ -23,6 +23,6 @@ extern const struct gfs2_glock_operations gfs2_quota_glops;
extern const struct gfs2_glock_operations gfs2_journal_glops;
extern const struct gfs2_glock_operations *gfs2_glops_list[];
extern void gfs2_ail_flush(struct gfs2_glock *gl);
extern void gfs2_ail_flush(struct gfs2_glock *gl, bool fsync);
#endif /* __GLOPS_DOT_H__ */
......@@ -18,6 +18,7 @@
#include <linux/rcupdate.h>
#include <linux/rculist_bl.h>
#include <linux/completion.h>
#include <linux/rbtree.h>
#define DIO_WAIT 0x00000010
#define DIO_METADATA 0x00000020
......@@ -78,8 +79,7 @@ struct gfs2_bitmap {
};
struct gfs2_rgrpd {
struct list_head rd_list; /* Link with superblock */
struct list_head rd_list_mru;
struct rb_node rd_node; /* Link with superblock */
struct gfs2_glock *rd_gl; /* Glock for this rgrp */
u64 rd_addr; /* grp block disk address */
u64 rd_data0; /* first data location */
......@@ -91,10 +91,7 @@ struct gfs2_rgrpd {
u32 rd_dinodes;
u64 rd_igeneration;
struct gfs2_bitmap *rd_bits;
struct mutex rd_mutex;
struct gfs2_log_element rd_le;
struct gfs2_sbd *rd_sbd;
unsigned int rd_bh_count;
u32 rd_last_alloc;
u32 rd_flags;
#define GFS2_RDF_CHECK 0x10000000 /* check for unlinked inodes */
......@@ -106,12 +103,15 @@ struct gfs2_rgrpd {
enum gfs2_state_bits {
BH_Pinned = BH_PrivateStart,
BH_Escaped = BH_PrivateStart + 1,
BH_Zeronew = BH_PrivateStart + 2,
};
BUFFER_FNS(Pinned, pinned)
TAS_BUFFER_FNS(Pinned, pinned)
BUFFER_FNS(Escaped, escaped)
TAS_BUFFER_FNS(Escaped, escaped)
BUFFER_FNS(Zeronew, zeronew)
TAS_BUFFER_FNS(Zeronew, zeronew)
struct gfs2_bufdata {
struct buffer_head *bd_bh;
......@@ -246,7 +246,6 @@ struct gfs2_glock {
struct gfs2_alloc {
/* Quota stuff */
struct gfs2_quota_data *al_qd[2*MAXQUOTAS];
struct gfs2_holder al_qd_ghs[2*MAXQUOTAS];
unsigned int al_qd_num;
......@@ -255,18 +254,13 @@ struct gfs2_alloc {
u32 al_alloced; /* Filled in by gfs2_alloc_*() */
/* Filled in by gfs2_inplace_reserve() */
unsigned int al_line;
char *al_file;
struct gfs2_holder al_ri_gh;
struct gfs2_holder al_rgd_gh;
struct gfs2_rgrpd *al_rgd;
};
enum {
GIF_INVALID = 0,
GIF_QD_LOCKED = 1,
GIF_ALLOC_FAILED = 2,
GIF_SW_PAGED = 3,
};
......@@ -282,6 +276,7 @@ struct gfs2_inode {
struct gfs2_holder i_iopen_gh;
struct gfs2_holder i_gh; /* for prepare/commit_write only */
struct gfs2_alloc *i_alloc;
struct gfs2_rgrpd *i_rgd;
u64 i_goal; /* goal block for allocations */
struct rw_semaphore i_rw_mutex;
struct list_head i_trunc_list;
......@@ -574,9 +569,7 @@ struct gfs2_sbd {
int sd_rindex_uptodate;
spinlock_t sd_rindex_spin;
struct mutex sd_rindex_mutex;
struct list_head sd_rindex_list;
struct list_head sd_rindex_mru_list;
struct gfs2_rgrpd *sd_rindex_forward;
struct rb_root sd_rindex_tree;
unsigned int sd_rgrps;
unsigned int sd_max_rg_data;
......
......@@ -583,7 +583,7 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name,
goto fail_quota_locks;
error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
al->al_rgd->rd_length +
dip->i_rgd->rd_length +
2 * RES_DINODE +
RES_STATFS + RES_QUOTA, 0);
if (error)
......@@ -613,8 +613,7 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name,
gfs2_trans_end(sdp);
fail_ipreserv:
if (dip->i_alloc->al_rgd)
gfs2_inplace_release(dip);
gfs2_inplace_release(dip);
fail_quota_locks:
gfs2_quota_unlock(dip);
......@@ -661,7 +660,7 @@ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip,
static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
unsigned int mode, dev_t dev, const char *symname,
unsigned int size)
unsigned int size, int excl)
{
const struct qstr *name = &dentry->d_name;
struct gfs2_holder ghs[2];
......@@ -681,6 +680,12 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
goto fail;
error = create_ok(dip, name, mode);
if ((error == -EEXIST) && S_ISREG(mode) && !excl) {
inode = gfs2_lookupi(dir, &dentry->d_name, 0);
gfs2_glock_dq_uninit(ghs);
d_instantiate(dentry, inode);
return IS_ERR(inode) ? PTR_ERR(inode) : 0;
}
if (error)
goto fail_gunlock;
......@@ -723,21 +728,22 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
brelse(bh);
gfs2_trans_end(sdp);
if (dip->i_alloc->al_rgd)
gfs2_inplace_release(dip);
gfs2_inplace_release(dip);
gfs2_quota_unlock(dip);
gfs2_alloc_put(dip);
gfs2_glock_dq_uninit_m(2, ghs);
mark_inode_dirty(inode);
gfs2_glock_dq_uninit_m(2, ghs);
d_instantiate(dentry, inode);
return 0;
fail_gunlock2:
gfs2_glock_dq_uninit(ghs + 1);
if (inode && !IS_ERR(inode))
iput(inode);
fail_gunlock:
gfs2_glock_dq_uninit(ghs);
if (inode && !IS_ERR(inode)) {
set_bit(GIF_ALLOC_FAILED, &GFS2_I(inode)->i_flags);
iput(inode);
}
fail:
if (bh)
brelse(bh);
......@@ -756,24 +762,10 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
static int gfs2_create(struct inode *dir, struct dentry *dentry,
int mode, struct nameidata *nd)
{
struct inode *inode;
int ret;
for (;;) {
ret = gfs2_create_inode(dir, dentry, S_IFREG | mode, 0, NULL, 0);
if (ret != -EEXIST || (nd && (nd->flags & LOOKUP_EXCL)))
return ret;
inode = gfs2_lookupi(dir, &dentry->d_name, 0);
if (inode) {
if (!IS_ERR(inode))
break;
return PTR_ERR(inode);
}
}
d_instantiate(dentry, inode);
return 0;
int excl = 0;
if (nd && (nd->flags & LOOKUP_EXCL))
excl = 1;
return gfs2_create_inode(dir, dentry, S_IFREG | mode, 0, NULL, 0, excl);
}
/**
......@@ -900,7 +892,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
goto out_gunlock_q;
error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
gfs2_rg_blocks(al) +
gfs2_rg_blocks(dip) +
2 * RES_DINODE + RES_STATFS +
RES_QUOTA, 0);
if (error)
......@@ -922,8 +914,9 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
inc_nlink(&ip->i_inode);
ip->i_inode.i_ctime = CURRENT_TIME;
gfs2_dinode_out(ip, dibh->b_data);
mark_inode_dirty(&ip->i_inode);
ihold(inode);
d_instantiate(dentry, inode);
mark_inode_dirty(inode);
out_brelse:
brelse(dibh);
......@@ -945,11 +938,6 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
out_parent:
gfs2_holder_uninit(ghs);
gfs2_holder_uninit(ghs + 1);
if (!error) {
ihold(inode);
d_instantiate(dentry, inode);
mark_inode_dirty(inode);
}
return error;
}
......@@ -1022,8 +1010,6 @@ static int gfs2_unlink_inode(struct gfs2_inode *dip,
clear_nlink(inode);
else
drop_nlink(inode);
gfs2_trans_add_bh(ip->i_gl, bh, 1);
gfs2_dinode_out(ip, bh->b_data);
mark_inode_dirty(inode);
if (inode->i_nlink == 0)
gfs2_unlink_di(inode);
......@@ -1051,13 +1037,8 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry)
struct buffer_head *bh;
struct gfs2_holder ghs[3];
struct gfs2_rgrpd *rgd;
struct gfs2_holder ri_gh;
int error;
error = gfs2_rindex_hold(sdp, &ri_gh);
if (error)
return error;
gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1);
......@@ -1114,7 +1095,6 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry)
gfs2_glock_dq(ghs);
out_parent:
gfs2_holder_uninit(ghs);
gfs2_glock_dq_uninit(&ri_gh);
return error;
}
......@@ -1137,7 +1117,7 @@ static int gfs2_symlink(struct inode *dir, struct dentry *dentry,
if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode) - 1)
return -ENAMETOOLONG;
return gfs2_create_inode(dir, dentry, S_IFLNK | S_IRWXUGO, 0, symname, size);
return gfs2_create_inode(dir, dentry, S_IFLNK | S_IRWXUGO, 0, symname, size, 0);
}
/**
......@@ -1151,7 +1131,7 @@ static int gfs2_symlink(struct inode *dir, struct dentry *dentry,
static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
return gfs2_create_inode(dir, dentry, S_IFDIR | mode, 0, NULL, 0);
return gfs2_create_inode(dir, dentry, S_IFDIR | mode, 0, NULL, 0, 0);
}
/**
......@@ -1166,7 +1146,7 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode)
static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode,
dev_t dev)
{
return gfs2_create_inode(dir, dentry, mode, dev, NULL, 0);
return gfs2_create_inode(dir, dentry, mode, dev, NULL, 0, 0);
}
/*
......@@ -1232,7 +1212,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
struct gfs2_inode *ip = GFS2_I(odentry->d_inode);
struct gfs2_inode *nip = NULL;
struct gfs2_sbd *sdp = GFS2_SB(odir);
struct gfs2_holder ghs[5], r_gh = { .gh_gl = NULL, }, ri_gh;
struct gfs2_holder ghs[5], r_gh = { .gh_gl = NULL, };
struct gfs2_rgrpd *nrgd;
unsigned int num_gh;
int dir_rename = 0;
......@@ -1246,10 +1226,6 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
return 0;
}
error = gfs2_rindex_hold(sdp, &ri_gh);
if (error)
return error;
if (odip != ndip) {
error = gfs2_glock_nq_init(sdp->sd_rename_gl, LM_ST_EXCLUSIVE,
0, &r_gh);
......@@ -1386,12 +1362,12 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
al->al_requested = sdp->sd_max_dirres;
error = gfs2_inplace_reserve_ri(ndip);
error = gfs2_inplace_reserve(ndip);
if (error)
goto out_gunlock_q;
error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
gfs2_rg_blocks(al) +
gfs2_rg_blocks(ndip) +
4 * RES_DINODE + 4 * RES_LEAF +
RES_STATFS + RES_QUOTA + 4, 0);
if (error)
......@@ -1457,7 +1433,6 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
if (r_gh.gh_gl)
gfs2_glock_dq_uninit(&r_gh);
out:
gfs2_glock_dq_uninit(&ri_gh);
return error;
}
......@@ -1561,21 +1536,10 @@ int gfs2_permission(struct inode *inode, int mask)
return error;
}
static int __gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr)
static int __gfs2_setattr_simple(struct inode *inode, struct iattr *attr)
{
struct inode *inode = &ip->i_inode;
struct buffer_head *dibh;
int error;
error = gfs2_meta_inode_buffer(ip, &dibh);
if (error)
return error;
setattr_copy(inode, attr);
mark_inode_dirty(inode);
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
gfs2_dinode_out(ip, dibh->b_data);
brelse(dibh);
return 0;
}
......@@ -1587,19 +1551,19 @@ static int __gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr)
* Returns: errno
*/
int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr)
int gfs2_setattr_simple(struct inode *inode, struct iattr *attr)
{
int error;
if (current->journal_info)
return __gfs2_setattr_simple(ip, attr);
return __gfs2_setattr_simple(inode, attr);
error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE, 0);
error = gfs2_trans_begin(GFS2_SB(inode), RES_DINODE, 0);
if (error)
return error;
error = __gfs2_setattr_simple(ip, attr);
gfs2_trans_end(GFS2_SB(&ip->i_inode));
error = __gfs2_setattr_simple(inode, attr);
gfs2_trans_end(GFS2_SB(inode));
return error;
}
......@@ -1637,7 +1601,7 @@ static int setattr_chown(struct inode *inode, struct iattr *attr)
if (error)
goto out_gunlock_q;
error = gfs2_setattr_simple(ip, attr);
error = gfs2_setattr_simple(inode, attr);
if (error)
goto out_end_trans;
......@@ -1693,12 +1657,12 @@ static int gfs2_setattr(struct dentry *dentry, struct iattr *attr)
else if ((attr->ia_valid & ATTR_MODE) && IS_POSIXACL(inode))
error = gfs2_acl_chmod(ip, attr);
else
error = gfs2_setattr_simple(ip, attr);
error = gfs2_setattr_simple(inode, attr);
out:
gfs2_glock_dq_uninit(&i_gh);
if (!error)
mark_inode_dirty(inode);
gfs2_glock_dq_uninit(&i_gh);
return error;
}
......
......@@ -109,7 +109,7 @@ extern int gfs2_inode_refresh(struct gfs2_inode *ip);
extern struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
int is_root);
extern int gfs2_permission(struct inode *inode, int mask);
extern int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr);
extern int gfs2_setattr_simple(struct inode *inode, struct iattr *attr);
extern struct inode *gfs2_lookup_simple(struct inode *dip, const char *name);
extern void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf);
......
......@@ -60,6 +60,29 @@ static void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh)
trace_gfs2_pin(bd, 1);
}
static bool buffer_is_rgrp(const struct gfs2_bufdata *bd)
{
return bd->bd_gl->gl_name.ln_type == LM_TYPE_RGRP;
}
static void maybe_release_space(struct gfs2_bufdata *bd)
{
struct gfs2_glock *gl = bd->bd_gl;
struct gfs2_sbd *sdp = gl->gl_sbd;
struct gfs2_rgrpd *rgd = gl->gl_object;
unsigned int index = bd->bd_bh->b_blocknr - gl->gl_name.ln_number;
struct gfs2_bitmap *bi = rgd->rd_bits + index;
if (bi->bi_clone == 0)
return;
if (sdp->sd_args.ar_discard)
gfs2_rgrp_send_discards(sdp, rgd->rd_data0, bd->bd_bh, bi);
memcpy(bi->bi_clone + bi->bi_offset,
bd->bd_bh->b_data + bi->bi_offset, bi->bi_len);
clear_bit(GBF_FULL, &bi->bi_flags);
rgd->rd_free_clone = rgd->rd_free;
}
/**
* gfs2_unpin - Unpin a buffer
* @sdp: the filesystem the buffer belongs to
......@@ -81,6 +104,9 @@ static void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh,
mark_buffer_dirty(bh);
clear_buffer_pinned(bh);
if (buffer_is_rgrp(bd))
maybe_release_space(bd);
spin_lock(&sdp->sd_ail_lock);
if (bd->bd_ail) {
list_del(&bd->bd_ail_st_list);
......@@ -469,42 +495,6 @@ static void revoke_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass)
gfs2_revoke_clean(sdp);
}
static void rg_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
{
struct gfs2_rgrpd *rgd;
struct gfs2_trans *tr = current->journal_info;
tr->tr_touched = 1;
rgd = container_of(le, struct gfs2_rgrpd, rd_le);
gfs2_log_lock(sdp);
if (!list_empty(&le->le_list)){
gfs2_log_unlock(sdp);
return;
}
gfs2_rgrp_bh_hold(rgd);
sdp->sd_log_num_rg++;
list_add(&le->le_list, &sdp->sd_log_le_rg);
gfs2_log_unlock(sdp);
}
static void rg_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
{
struct list_head *head = &sdp->sd_log_le_rg;
struct gfs2_rgrpd *rgd;
while (!list_empty(head)) {
rgd = list_entry(head->next, struct gfs2_rgrpd, rd_le.le_list);
list_del_init(&rgd->rd_le.le_list);
sdp->sd_log_num_rg--;
gfs2_rgrp_repolish_clones(rgd);
gfs2_rgrp_bh_put(rgd);
}
gfs2_assert_warn(sdp, !sdp->sd_log_num_rg);
}
/**
* databuf_lo_add - Add a databuf to the transaction.
*
......@@ -705,8 +695,6 @@ static int databuf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start,
brelse(bh_log);
brelse(bh_ip);
if (error)
break;
sdp->sd_replayed_blocks++;
}
......@@ -771,8 +759,6 @@ const struct gfs2_log_operations gfs2_revoke_lops = {
};
const struct gfs2_log_operations gfs2_rg_lops = {
.lo_add = rg_lo_add,
.lo_after_commit = rg_lo_after_commit,
.lo_name = "rg",
};
......
......@@ -77,8 +77,7 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
spin_lock_init(&sdp->sd_rindex_spin);
mutex_init(&sdp->sd_rindex_mutex);
INIT_LIST_HEAD(&sdp->sd_rindex_list);
INIT_LIST_HEAD(&sdp->sd_rindex_mru_list);
sdp->sd_rindex_tree.rb_node = NULL;
INIT_LIST_HEAD(&sdp->sd_jindex_list);
spin_lock_init(&sdp->sd_jindex_spin);
......@@ -652,7 +651,6 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
fs_err(sdp, "can't lookup journal index: %d\n", error);
return PTR_ERR(sdp->sd_jindex);
}
ip = GFS2_I(sdp->sd_jindex);
/* Load in the journal index special file */
......@@ -764,7 +762,6 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
static int init_inodes(struct gfs2_sbd *sdp, int undo)
{
int error = 0;
struct gfs2_inode *ip;
struct inode *master = sdp->sd_master_dir->d_inode;
if (undo)
......@@ -789,7 +786,6 @@ static int init_inodes(struct gfs2_sbd *sdp, int undo)
fs_err(sdp, "can't get resource index inode: %d\n", error);
goto fail_statfs;
}
ip = GFS2_I(sdp->sd_rindex);
sdp->sd_rindex_uptodate = 0;
/* Read in the quota inode */
......
......@@ -638,15 +638,18 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
unsigned long index = loc >> PAGE_CACHE_SHIFT;
unsigned offset = loc & (PAGE_CACHE_SIZE - 1);
unsigned blocksize, iblock, pos;
struct buffer_head *bh, *dibh;
struct buffer_head *bh;
struct page *page;
void *kaddr, *ptr;
struct gfs2_quota q, *qp;
int err, nbytes;
u64 size;
if (gfs2_is_stuffed(ip))
gfs2_unstuff_dinode(ip, NULL);
if (gfs2_is_stuffed(ip)) {
err = gfs2_unstuff_dinode(ip, NULL);
if (err)
return err;
}
memset(&q, 0, sizeof(struct gfs2_quota));
err = gfs2_internal_read(ip, NULL, (char *)&q, &loc, sizeof(q));
......@@ -736,22 +739,13 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
goto get_a_page;
}
/* Update the disk inode timestamp and size (if extended) */
err = gfs2_meta_inode_buffer(ip, &dibh);
if (err)
goto out;
size = loc + sizeof(struct gfs2_quota);
if (size > inode->i_size)
i_size_write(inode, size);
inode->i_mtime = inode->i_atime = CURRENT_TIME;
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
gfs2_dinode_out(ip, dibh->b_data);
brelse(dibh);
mark_inode_dirty(inode);
out:
return err;
unlock_out:
unlock_page(page);
page_cache_release(page);
......@@ -822,7 +816,7 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda)
goto out_alloc;
if (nalloc)
blocks += gfs2_rg_blocks(al) + nalloc * ind_blocks + RES_STATFS;
blocks += gfs2_rg_blocks(ip) + nalloc * ind_blocks + RES_STATFS;
error = gfs2_trans_begin(sdp, blocks, 0);
if (error)
......@@ -936,7 +930,9 @@ int gfs2_quota_lock(struct gfs2_inode *ip, u32 uid, u32 gid)
unsigned int x;
int error = 0;
gfs2_quota_hold(ip, uid, gid);
error = gfs2_quota_hold(ip, uid, gid);
if (error)
return error;
if (capable(CAP_SYS_RESOURCE) ||
sdp->sd_args.ar_quota != GFS2_QUOTA_ON)
......@@ -1607,7 +1603,7 @@ static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
error = gfs2_inplace_reserve(ip);
if (error)
goto out_alloc;
blocks += gfs2_rg_blocks(al);
blocks += gfs2_rg_blocks(ip);
}
/* Some quotas span block boundaries and can update two blocks,
......
This diff is collapsed.
......@@ -18,18 +18,15 @@ struct gfs2_holder;
extern void gfs2_rgrp_verify(struct gfs2_rgrpd *rgd);
struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk);
struct gfs2_rgrpd *gfs2_rgrpd_get_first(struct gfs2_sbd *sdp);
struct gfs2_rgrpd *gfs2_rgrpd_get_next(struct gfs2_rgrpd *rgd);
extern struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk);
extern struct gfs2_rgrpd *gfs2_rgrpd_get_first(struct gfs2_sbd *sdp);
extern struct gfs2_rgrpd *gfs2_rgrpd_get_next(struct gfs2_rgrpd *rgd);
extern void gfs2_clear_rgrpd(struct gfs2_sbd *sdp);
extern int gfs2_rindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ri_gh);
extern int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd);
extern void gfs2_rgrp_bh_hold(struct gfs2_rgrpd *rgd);
extern void gfs2_rgrp_bh_put(struct gfs2_rgrpd *rgd);
extern void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd);
extern int gfs2_rindex_update(struct gfs2_sbd *sdp);
extern void gfs2_free_clones(struct gfs2_rgrpd *rgd);
extern int gfs2_rgrp_go_lock(struct gfs2_holder *gh);
extern void gfs2_rgrp_go_unlock(struct gfs2_holder *gh);
extern struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip);
static inline void gfs2_alloc_put(struct gfs2_inode *ip)
......@@ -39,16 +36,9 @@ static inline void gfs2_alloc_put(struct gfs2_inode *ip)
ip->i_alloc = NULL;
}
extern int gfs2_inplace_reserve_i(struct gfs2_inode *ip, int hold_rindex,
char *file, unsigned int line);
#define gfs2_inplace_reserve(ip) \
gfs2_inplace_reserve_i((ip), 1, __FILE__, __LINE__)
#define gfs2_inplace_reserve_ri(ip) \
gfs2_inplace_reserve_i((ip), 0, __FILE__, __LINE__)
extern int gfs2_inplace_reserve(struct gfs2_inode *ip);
extern void gfs2_inplace_release(struct gfs2_inode *ip);
extern int gfs2_ri_update(struct gfs2_inode *ip);
extern int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n);
extern int gfs2_alloc_di(struct gfs2_inode *ip, u64 *bn, u64 *generation);
......@@ -66,11 +56,14 @@ struct gfs2_rgrp_list {
struct gfs2_holder *rl_ghs;
};
extern void gfs2_rlist_add(struct gfs2_sbd *sdp, struct gfs2_rgrp_list *rlist,
extern void gfs2_rlist_add(struct gfs2_inode *ip, struct gfs2_rgrp_list *rlist,
u64 block);
extern void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, unsigned int state);
extern void gfs2_rlist_free(struct gfs2_rgrp_list *rlist);
extern u64 gfs2_ri_total(struct gfs2_sbd *sdp);
extern int gfs2_rgrp_dump(struct seq_file *seq, const struct gfs2_glock *gl);
extern void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
struct buffer_head *bh,
const struct gfs2_bitmap *bi);
#endif /* __RGRP_DOT_H__ */
......@@ -752,51 +752,77 @@ static int gfs2_write_inode(struct inode *inode, struct writeback_control *wbc)
struct gfs2_sbd *sdp = GFS2_SB(inode);
struct address_space *metamapping = gfs2_glock2aspace(ip->i_gl);
struct backing_dev_info *bdi = metamapping->backing_dev_info;
struct gfs2_holder gh;
int ret = 0;
if (wbc->sync_mode == WB_SYNC_ALL)
gfs2_log_flush(GFS2_SB(inode), ip->i_gl);
if (bdi->dirty_exceeded)
gfs2_ail1_flush(sdp, wbc);
else
filemap_fdatawrite(metamapping);
if (wbc->sync_mode == WB_SYNC_ALL)
ret = filemap_fdatawait(metamapping);
if (ret)
mark_inode_dirty_sync(inode);
return ret;
}
/**
* gfs2_dirty_inode - check for atime updates
* @inode: The inode in question
* @flags: The type of dirty
*
* Unfortunately it can be called under any combination of inode
* glock and transaction lock, so we have to check carefully.
*
* At the moment this deals only with atime - it should be possible
* to expand that role in future, once a review of the locking has
* been carried out.
*/
static void gfs2_dirty_inode(struct inode *inode, int flags)
{
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_sbd *sdp = GFS2_SB(inode);
struct buffer_head *bh;
struct timespec atime;
struct gfs2_dinode *di;
int ret = -EAGAIN;
int unlock_required = 0;
/* Skip timestamp update, if this is from a memalloc */
if (current->flags & PF_MEMALLOC)
goto do_flush;
struct gfs2_holder gh;
int need_unlock = 0;
int need_endtrans = 0;
int ret;
if (!(flags & (I_DIRTY_DATASYNC|I_DIRTY_SYNC)))
return;
if (!gfs2_glock_is_locked_by_me(ip->i_gl)) {
ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
if (ret)
goto do_flush;
unlock_required = 1;
if (ret) {
fs_err(sdp, "dirty_inode: glock %d\n", ret);
return;
}
need_unlock = 1;
}
ret = gfs2_trans_begin(sdp, RES_DINODE, 0);
if (ret)
goto do_unlock;
if (current->journal_info == NULL) {
ret = gfs2_trans_begin(sdp, RES_DINODE, 0);
if (ret) {
fs_err(sdp, "dirty_inode: gfs2_trans_begin %d\n", ret);
goto out;
}
need_endtrans = 1;
}
ret = gfs2_meta_inode_buffer(ip, &bh);
if (ret == 0) {
di = (struct gfs2_dinode *)bh->b_data;
atime.tv_sec = be64_to_cpu(di->di_atime);
atime.tv_nsec = be32_to_cpu(di->di_atime_nsec);
if (timespec_compare(&inode->i_atime, &atime) > 0) {
gfs2_trans_add_bh(ip->i_gl, bh, 1);
gfs2_dinode_out(ip, bh->b_data);
}
gfs2_trans_add_bh(ip->i_gl, bh, 1);
gfs2_dinode_out(ip, bh->b_data);
brelse(bh);
}
gfs2_trans_end(sdp);
do_unlock:
if (unlock_required)
if (need_endtrans)
gfs2_trans_end(sdp);
out:
if (need_unlock)
gfs2_glock_dq_uninit(&gh);
do_flush:
if (wbc->sync_mode == WB_SYNC_ALL)
gfs2_log_flush(GFS2_SB(inode), ip->i_gl);
filemap_fdatawrite(metamapping);
if (bdi->dirty_exceeded)
gfs2_ail1_flush(sdp, wbc);
if (!ret && (wbc->sync_mode == WB_SYNC_ALL))
ret = filemap_fdatawait(metamapping);
if (ret)
mark_inode_dirty_sync(inode);
return ret;
}
/**
......@@ -1011,7 +1037,6 @@ static int statfs_slow_fill(struct gfs2_rgrpd *rgd,
static int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change_host *sc)
{
struct gfs2_holder ri_gh;
struct gfs2_rgrpd *rgd_next;
struct gfs2_holder *gha, *gh;
unsigned int slots = 64;
......@@ -1024,10 +1049,6 @@ static int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change_host
if (!gha)
return -ENOMEM;
error = gfs2_rindex_hold(sdp, &ri_gh);
if (error)
goto out;
rgd_next = gfs2_rgrpd_get_first(sdp);
for (;;) {
......@@ -1070,9 +1091,6 @@ static int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change_host
yield();
}
gfs2_glock_dq_uninit(&ri_gh);
out:
kfree(gha);
return error;
}
......@@ -1124,6 +1142,10 @@ static int gfs2_statfs(struct dentry *dentry, struct kstatfs *buf)
struct gfs2_statfs_change_host sc;
int error;
error = gfs2_rindex_update(sdp);
if (error)
return error;
if (gfs2_tune_get(sdp, gt_statfs_slow))
error = gfs2_statfs_slow(sdp, &sc);
else
......@@ -1394,21 +1416,17 @@ static int gfs2_dinode_dealloc(struct gfs2_inode *ip)
if (error)
goto out;
error = gfs2_rindex_hold(sdp, &al->al_ri_gh);
if (error)
goto out_qs;
rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr);
if (!rgd) {
gfs2_consist_inode(ip);
error = -EIO;
goto out_rindex_relse;
goto out_qs;
}
error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0,
&al->al_rgd_gh);
if (error)
goto out_rindex_relse;
goto out_qs;
error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_STATFS + RES_QUOTA,
sdp->sd_jdesc->jd_blocks);
......@@ -1423,8 +1441,6 @@ static int gfs2_dinode_dealloc(struct gfs2_inode *ip)
out_rg_gunlock:
gfs2_glock_dq_uninit(&al->al_rgd_gh);
out_rindex_relse:
gfs2_glock_dq_uninit(&al->al_ri_gh);
out_qs:
gfs2_quota_unhold(ip);
out:
......@@ -1471,9 +1487,11 @@ static void gfs2_evict_inode(struct inode *inode)
goto out;
}
error = gfs2_check_blk_type(sdp, ip->i_no_addr, GFS2_BLKST_UNLINKED);
if (error)
goto out_truncate;
if (!test_bit(GIF_ALLOC_FAILED, &ip->i_flags)) {
error = gfs2_check_blk_type(sdp, ip->i_no_addr, GFS2_BLKST_UNLINKED);
if (error)
goto out_truncate;
}
if (test_bit(GIF_INVALID, &ip->i_flags)) {
error = gfs2_inode_refresh(ip);
......@@ -1513,6 +1531,10 @@ static void gfs2_evict_inode(struct inode *inode)
goto out_unlock;
out_truncate:
gfs2_log_flush(sdp, ip->i_gl);
write_inode_now(inode, 1);
gfs2_ail_flush(ip->i_gl, 0);
/* Case 2 starts here */
error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks);
if (error)
......@@ -1552,6 +1574,7 @@ static struct inode *gfs2_alloc_inode(struct super_block *sb)
if (ip) {
ip->i_flags = 0;
ip->i_gl = NULL;
ip->i_rgd = NULL;
}
return &ip->i_inode;
}
......@@ -1572,6 +1595,7 @@ const struct super_operations gfs2_super_ops = {
.alloc_inode = gfs2_alloc_inode,
.destroy_inode = gfs2_destroy_inode,
.write_inode = gfs2_write_inode,
.dirty_inode = gfs2_dirty_inode,
.evict_inode = gfs2_evict_inode,
.put_super = gfs2_put_super,
.sync_fs = gfs2_sync_fs,
......
......@@ -185,8 +185,3 @@ void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno, unsigned int len)
gfs2_log_unlock(sdp);
}
void gfs2_trans_add_rg(struct gfs2_rgrpd *rgd)
{
lops_add(rgd->rd_sbd, &rgd->rd_le);
}
......@@ -28,20 +28,20 @@ struct gfs2_glock;
/* reserve either the number of blocks to be allocated plus the rg header
* block, or all of the blocks in the rg, whichever is smaller */
static inline unsigned int gfs2_rg_blocks(const struct gfs2_alloc *al)
static inline unsigned int gfs2_rg_blocks(const struct gfs2_inode *ip)
{
return (al->al_requested < al->al_rgd->rd_length)?
al->al_requested + 1 : al->al_rgd->rd_length;
const struct gfs2_alloc *al = ip->i_alloc;
if (al->al_requested < ip->i_rgd->rd_length)
return al->al_requested + 1;
return ip->i_rgd->rd_length;
}
int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks,
unsigned int revokes);
extern int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks,
unsigned int revokes);
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_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd);
void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno, unsigned int len);
void gfs2_trans_add_rg(struct gfs2_rgrpd *rgd);
extern void gfs2_trans_end(struct gfs2_sbd *sdp);
extern void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta);
extern void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd);
extern void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno, unsigned int len);
#endif /* __TRANS_DOT_H__ */
......@@ -332,15 +332,8 @@ static int ea_remove_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh,
if (error)
goto out_alloc;
error = gfs2_rindex_hold(GFS2_SB(&ip->i_inode), &al->al_ri_gh);
if (error)
goto out_quota;
error = ea_dealloc_unstuffed(ip, bh, ea, prev, (leave) ? &error : NULL);
gfs2_glock_dq_uninit(&al->al_ri_gh);
out_quota:
gfs2_quota_unhold(ip);
out_alloc:
gfs2_alloc_put(ip);
......@@ -734,7 +727,7 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er,
goto out_gunlock_q;
error = gfs2_trans_begin(GFS2_SB(&ip->i_inode),
blks + gfs2_rg_blocks(al) +
blks + gfs2_rg_blocks(ip) +
RES_DINODE + RES_STATFS + RES_QUOTA, 0);
if (error)
goto out_ipres;
......@@ -1296,7 +1289,8 @@ static int ea_acl_chmod_unstuffed(struct gfs2_inode *ip,
int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data)
{
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct inode *inode = &ip->i_inode;
struct gfs2_sbd *sdp = GFS2_SB(inode);
struct gfs2_ea_location el;
int error;
......@@ -1319,7 +1313,7 @@ int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data)
if (error)
return error;
error = gfs2_setattr_simple(ip, attr);
error = gfs2_setattr_simple(inode, attr);
gfs2_trans_end(sdp);
return error;
}
......@@ -1362,14 +1356,14 @@ static int ea_dealloc_indirect(struct gfs2_inode *ip)
blen++;
else {
if (bstart)
gfs2_rlist_add(sdp, &rlist, bstart);
gfs2_rlist_add(ip, &rlist, bstart);
bstart = bn;
blen = 1;
}
blks++;
}
if (bstart)
gfs2_rlist_add(sdp, &rlist, bstart);
gfs2_rlist_add(ip, &rlist, bstart);
else
goto out;
......@@ -1501,24 +1495,18 @@ int gfs2_ea_dealloc(struct gfs2_inode *ip)
if (error)
goto out_alloc;
error = gfs2_rindex_hold(GFS2_SB(&ip->i_inode), &al->al_ri_gh);
if (error)
goto out_quota;
error = ea_foreach(ip, ea_dealloc_unstuffed, NULL);
if (error)
goto out_rindex;
goto out_quota;
if (ip->i_diskflags & GFS2_DIF_EA_INDIRECT) {
error = ea_dealloc_indirect(ip);
if (error)
goto out_rindex;
goto out_quota;
}
error = ea_dealloc_block(ip);
out_rindex:
gfs2_glock_dq_uninit(&al->al_ri_gh);
out_quota:
gfs2_quota_unhold(ip);
out_alloc:
......
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