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) ...@@ -82,7 +82,7 @@ static int gfs2_set_mode(struct inode *inode, umode_t mode)
iattr.ia_valid = ATTR_MODE; iattr.ia_valid = ATTR_MODE;
iattr.ia_mode = mode; iattr.ia_mode = mode;
error = gfs2_setattr_simple(GFS2_I(inode), &iattr); error = gfs2_setattr_simple(inode, &iattr);
} }
return error; return error;
...@@ -160,6 +160,7 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct inode *inode) ...@@ -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) int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr)
{ {
struct inode *inode = &ip->i_inode;
struct posix_acl *acl; struct posix_acl *acl;
char *data; char *data;
unsigned int len; unsigned int len;
...@@ -169,7 +170,7 @@ int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr) ...@@ -169,7 +170,7 @@ int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr)
if (IS_ERR(acl)) if (IS_ERR(acl))
return PTR_ERR(acl); return PTR_ERR(acl);
if (!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); error = posix_acl_chmod(&acl, GFP_NOFS, attr->ia_mode);
if (error) if (error)
......
...@@ -663,7 +663,7 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping, ...@@ -663,7 +663,7 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,
if (&ip->i_inode == sdp->sd_rindex) if (&ip->i_inode == sdp->sd_rindex)
rblocks += 2 * RES_STATFS; rblocks += 2 * RES_STATFS;
if (alloc_required) if (alloc_required)
rblocks += gfs2_rg_blocks(al); rblocks += gfs2_rg_blocks(ip);
error = gfs2_trans_begin(sdp, rblocks, error = gfs2_trans_begin(sdp, rblocks,
PAGE_CACHE_SIZE/sdp->sd_sb.sb_bsize); 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, ...@@ -787,7 +787,6 @@ static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh,
u64 to = pos + copied; u64 to = pos + copied;
void *kaddr; void *kaddr;
unsigned char *buf = dibh->b_data + sizeof(struct gfs2_dinode); 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))); BUG_ON((pos + len) > (dibh->b_size - sizeof(struct gfs2_dinode)));
kaddr = kmap_atomic(page, KM_USER0); kaddr = kmap_atomic(page, KM_USER0);
...@@ -804,7 +803,6 @@ static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh, ...@@ -804,7 +803,6 @@ static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh,
if (copied) { if (copied) {
if (inode->i_size < to) if (inode->i_size < to)
i_size_write(inode, to); i_size_write(inode, to);
gfs2_dinode_out(ip, di);
mark_inode_dirty(inode); mark_inode_dirty(inode);
} }
...@@ -873,10 +871,6 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping, ...@@ -873,10 +871,6 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping,
gfs2_page_add_databufs(ip, page, from, to); gfs2_page_add_databufs(ip, page, from, to);
ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata); 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) { if (inode == sdp->sd_rindex) {
adjust_fs_space(inode); adjust_fs_space(inode);
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/blkdev.h>
#include <linux/gfs2_ondisk.h> #include <linux/gfs2_ondisk.h>
#include <linux/crc32.h> #include <linux/crc32.h>
...@@ -36,11 +37,6 @@ struct metapath { ...@@ -36,11 +37,6 @@ struct metapath {
__u16 mp_list[GFS2_MAX_META_HEIGHT]; __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 { struct strip_mine {
int sm_first; int sm_first;
unsigned int sm_height; unsigned int sm_height;
...@@ -273,6 +269,30 @@ static inline __be64 *metapointer(unsigned int height, const struct metapath *mp ...@@ -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]; 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 * lookup_metapath - Walk the metadata tree to a specific point
* @ip: The inode * @ip: The inode
...@@ -432,12 +452,14 @@ static int gfs2_bmap_alloc(struct inode *inode, const sector_t lblock, ...@@ -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_inode *ip = GFS2_I(inode);
struct gfs2_sbd *sdp = GFS2_SB(inode); struct gfs2_sbd *sdp = GFS2_SB(inode);
struct super_block *sb = sdp->sd_vfs;
struct buffer_head *dibh = mp->mp_bh[0]; struct buffer_head *dibh = mp->mp_bh[0];
u64 bn, dblock = 0; u64 bn, dblock = 0;
unsigned n, i, blks, alloced = 0, iblks = 0, branch_start = 0; unsigned n, i, blks, alloced = 0, iblks = 0, branch_start = 0;
unsigned dblks = 0; unsigned dblks = 0;
unsigned ptrs_per_blk; unsigned ptrs_per_blk;
const unsigned end_of_metadata = height - 1; const unsigned end_of_metadata = height - 1;
int ret;
int eob = 0; int eob = 0;
enum alloc_state state; enum alloc_state state;
__be64 *ptr; __be64 *ptr;
...@@ -540,6 +562,15 @@ static int gfs2_bmap_alloc(struct inode *inode, const sector_t lblock, ...@@ -540,6 +562,15 @@ static int gfs2_bmap_alloc(struct inode *inode, const sector_t lblock,
dblock = bn; dblock = bn;
while (n-- > 0) while (n-- > 0)
*ptr++ = cpu_to_be64(bn++); *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; break;
} }
} while ((state != ALLOC_DATA) || !dblock); } while ((state != ALLOC_DATA) || !dblock);
...@@ -667,76 +698,6 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi ...@@ -667,76 +698,6 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi
return ret; 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 * do_strip - Look for a layer a particular layer of the file and strip it off
* @ip: the inode * @ip: the inode
...@@ -752,9 +713,8 @@ static int recursive_scan(struct gfs2_inode *ip, struct buffer_head *dibh, ...@@ -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, static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
struct buffer_head *bh, __be64 *top, __be64 *bottom, 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_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_rgrp_list rlist; struct gfs2_rgrp_list rlist;
u64 bn, bstart; u64 bn, bstart;
...@@ -783,11 +743,6 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, ...@@ -783,11 +743,6 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
else if (ip->i_depth) else if (ip->i_depth)
revokes = sdp->sd_inptrs; 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) if (error)
return error; return error;
...@@ -805,7 +760,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, ...@@ -805,7 +760,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
blen++; blen++;
else { else {
if (bstart) if (bstart)
gfs2_rlist_add(sdp, &rlist, bstart); gfs2_rlist_add(ip, &rlist, bstart);
bstart = bn; bstart = bn;
blen = 1; blen = 1;
...@@ -813,7 +768,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, ...@@ -813,7 +768,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
} }
if (bstart) if (bstart)
gfs2_rlist_add(sdp, &rlist, bstart); gfs2_rlist_add(ip, &rlist, bstart);
else else
goto out; /* Nothing to do */ goto out; /* Nothing to do */
...@@ -887,11 +842,81 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, ...@@ -887,11 +842,81 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
out_rlist: out_rlist:
gfs2_rlist_free(&rlist); gfs2_rlist_free(&rlist);
out: out:
if (ip != GFS2_I(sdp->sd_rindex))
gfs2_glock_dq_uninit(&ip->i_alloc->al_ri_gh);
return error; 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 * 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) ...@@ -1031,7 +1056,7 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 size)
sm.sm_first = !!size; sm.sm_first = !!size;
sm.sm_height = height; 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) if (error)
break; break;
} }
......
...@@ -240,16 +240,15 @@ static int gfs2_dir_write_data(struct gfs2_inode *ip, const char *buf, ...@@ -240,16 +240,15 @@ static int gfs2_dir_write_data(struct gfs2_inode *ip, const char *buf,
return error; return error;
} }
static int gfs2_dir_read_stuffed(struct gfs2_inode *ip, char *buf, static int gfs2_dir_read_stuffed(struct gfs2_inode *ip, __be64 *buf,
u64 offset, unsigned int size) unsigned int size)
{ {
struct buffer_head *dibh; struct buffer_head *dibh;
int error; int error;
error = gfs2_meta_inode_buffer(ip, &dibh); error = gfs2_meta_inode_buffer(ip, &dibh);
if (!error) { if (!error) {
offset += sizeof(struct gfs2_dinode); memcpy(buf, dibh->b_data + sizeof(struct gfs2_dinode), size);
memcpy(buf, dibh->b_data + offset, size);
brelse(dibh); brelse(dibh);
} }
...@@ -261,13 +260,12 @@ static int gfs2_dir_read_stuffed(struct gfs2_inode *ip, char *buf, ...@@ -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 * gfs2_dir_read_data - Read a data from a directory inode
* @ip: The GFS2 Inode * @ip: The GFS2 Inode
* @buf: The buffer to place result into * @buf: The buffer to place result into
* @offset: File offset to begin jdata_readng from
* @size: Amount of data to transfer * @size: Amount of data to transfer
* *
* Returns: The amount of data actually copied or the error * Returns: The amount of data actually copied or the error
*/ */
static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, u64 offset, static int gfs2_dir_read_data(struct gfs2_inode *ip, __be64 *buf,
unsigned int size, unsigned ra) unsigned int size)
{ {
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
u64 lblock, dblock; u64 lblock, dblock;
...@@ -275,24 +273,14 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, u64 offset, ...@@ -275,24 +273,14 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, u64 offset,
unsigned int o; unsigned int o;
int copied = 0; int copied = 0;
int error = 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)) 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))) if (gfs2_assert_warn(sdp, gfs2_is_jdata(ip)))
return -EINVAL; return -EINVAL;
lblock = offset; lblock = 0;
o = do_div(lblock, sdp->sd_jbsize) + sizeof(struct gfs2_meta_header); o = do_div(lblock, sdp->sd_jbsize) + sizeof(struct gfs2_meta_header);
while (copied < size) { while (copied < size) {
...@@ -311,8 +299,6 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, u64 offset, ...@@ -311,8 +299,6 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, u64 offset,
if (error || !dblock) if (error || !dblock)
goto fail; goto fail;
BUG_ON(extlen < 1); BUG_ON(extlen < 1);
if (!ra)
extlen = 1;
bh = gfs2_meta_ra(ip->i_gl, dblock, extlen); bh = gfs2_meta_ra(ip->i_gl, dblock, extlen);
} else { } else {
error = gfs2_meta_read(ip->i_gl, dblock, DIO_WAIT, &bh); 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, ...@@ -328,7 +314,7 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, u64 offset,
extlen--; extlen--;
memcpy(buf, bh->b_data + o, amount); memcpy(buf, bh->b_data + o, amount);
brelse(bh); brelse(bh);
buf += amount; buf += (amount/sizeof(__be64));
copied += amount; copied += amount;
lblock++; lblock++;
o = sizeof(struct gfs2_meta_header); o = sizeof(struct gfs2_meta_header);
...@@ -371,7 +357,7 @@ static __be64 *gfs2_dir_get_hash_table(struct gfs2_inode *ip) ...@@ -371,7 +357,7 @@ static __be64 *gfs2_dir_get_hash_table(struct gfs2_inode *ip)
if (hc == NULL) if (hc == NULL)
return ERR_PTR(-ENOMEM); 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) { if (ret < 0) {
kfree(hc); kfree(hc);
return ERR_PTR(ret); return ERR_PTR(ret);
...@@ -1695,7 +1681,6 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry) ...@@ -1695,7 +1681,6 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry)
const struct qstr *name = &dentry->d_name; const struct qstr *name = &dentry->d_name;
struct gfs2_dirent *dent, *prev = NULL; struct gfs2_dirent *dent, *prev = NULL;
struct buffer_head *bh; struct buffer_head *bh;
int error;
/* Returns _either_ the entry (if its first in block) or the /* Returns _either_ the entry (if its first in block) or the
previous entry otherwise */ previous entry otherwise */
...@@ -1724,22 +1709,15 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry) ...@@ -1724,22 +1709,15 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry)
} }
brelse(bh); brelse(bh);
error = gfs2_meta_inode_buffer(dip, &bh);
if (error)
return error;
if (!dip->i_entries) if (!dip->i_entries)
gfs2_consist_inode(dip); gfs2_consist_inode(dip);
gfs2_trans_add_bh(dip->i_gl, bh, 1);
dip->i_entries--; dip->i_entries--;
dip->i_inode.i_mtime = dip->i_inode.i_ctime = CURRENT_TIME; dip->i_inode.i_mtime = dip->i_inode.i_ctime = CURRENT_TIME;
if (S_ISDIR(dentry->d_inode->i_mode)) if (S_ISDIR(dentry->d_inode->i_mode))
drop_nlink(&dip->i_inode); drop_nlink(&dip->i_inode);
gfs2_dinode_out(dip, bh->b_data);
brelse(bh);
mark_inode_dirty(&dip->i_inode); 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, ...@@ -1829,10 +1807,6 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len,
if (error) if (error)
goto out_put; goto out_put;
error = gfs2_rindex_hold(sdp, &dip->i_alloc->al_ri_gh);
if (error)
goto out_qs;
/* Count the number of leaves */ /* Count the number of leaves */
bh = leaf_bh; bh = leaf_bh;
...@@ -1847,7 +1821,7 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len, ...@@ -1847,7 +1821,7 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len,
if (blk != leaf_no) if (blk != leaf_no)
brelse(bh); brelse(bh);
gfs2_rlist_add(sdp, &rlist, blk); gfs2_rlist_add(dip, &rlist, blk);
l_blocks++; l_blocks++;
} }
...@@ -1911,8 +1885,6 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len, ...@@ -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); gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs);
out_rlist: out_rlist:
gfs2_rlist_free(&rlist); gfs2_rlist_free(&rlist);
gfs2_glock_dq_uninit(&dip->i_alloc->al_ri_gh);
out_qs:
gfs2_quota_unhold(dip); gfs2_quota_unhold(dip);
out_put: out_put:
gfs2_alloc_put(dip); gfs2_alloc_put(dip);
......
This diff is collapsed.
...@@ -28,40 +28,55 @@ ...@@ -28,40 +28,55 @@
#include "trans.h" #include "trans.h"
#include "dir.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 * __gfs2_ail_flush - remove all buffers for a given lock from the AIL
* @gl: the glock * @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. * 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 gfs2_sbd *sdp = gl->gl_sbd;
struct list_head *head = &gl->gl_ail_list; struct list_head *head = &gl->gl_ail_list;
struct gfs2_bufdata *bd; struct gfs2_bufdata *bd, *tmp;
struct buffer_head *bh; 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); spin_lock(&sdp->sd_ail_lock);
while (!list_empty(head)) { list_for_each_entry_safe(bd, tmp, head, bd_ail_gl_list) {
bd = list_entry(head->next, struct gfs2_bufdata,
bd_ail_gl_list);
bh = bd->bd_bh; bh = bd->bd_bh;
gfs2_remove_from_ail(bd); if (bh->b_state & b_state) {
bd->bd_bh = NULL; if (fsync)
continue;
gfs2_ail_error(gl, bh);
}
blocknr = bh->b_blocknr;
bh->b_private = NULL; 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; bd->bd_bh = NULL;
gfs2_log_lock(sdp); bd->bd_blkno = blocknr;
gfs2_assert_withdraw(sdp, !buffer_busy(bh));
gfs2_trans_add_revoke(sdp, bd);
gfs2_log_unlock(sdp);
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); spin_unlock(&sdp->sd_ail_lock);
gfs2_log_unlock(sdp);
} }
...@@ -84,13 +99,13 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl) ...@@ -84,13 +99,13 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl)
BUG_ON(current->journal_info); BUG_ON(current->journal_info);
current->journal_info = &tr; current->journal_info = &tr;
__gfs2_ail_flush(gl); __gfs2_ail_flush(gl, 0);
gfs2_trans_end(sdp); gfs2_trans_end(sdp);
gfs2_log_flush(sdp, NULL); 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; struct gfs2_sbd *sdp = gl->gl_sbd;
unsigned int revokes = atomic_read(&gl->gl_ail_count); unsigned int revokes = atomic_read(&gl->gl_ail_count);
...@@ -102,7 +117,7 @@ void gfs2_ail_flush(struct gfs2_glock *gl) ...@@ -102,7 +117,7 @@ void gfs2_ail_flush(struct gfs2_glock *gl)
ret = gfs2_trans_begin(sdp, 0, revokes); ret = gfs2_trans_begin(sdp, 0, revokes);
if (ret) if (ret)
return; return;
__gfs2_ail_flush(gl); __gfs2_ail_flush(gl, fsync);
gfs2_trans_end(sdp); gfs2_trans_end(sdp);
gfs2_log_flush(sdp, NULL); gfs2_log_flush(sdp, NULL);
} }
...@@ -119,6 +134,7 @@ void gfs2_ail_flush(struct gfs2_glock *gl) ...@@ -119,6 +134,7 @@ void gfs2_ail_flush(struct gfs2_glock *gl)
static void rgrp_go_sync(struct gfs2_glock *gl) static void rgrp_go_sync(struct gfs2_glock *gl)
{ {
struct address_space *metamapping = gfs2_glock2aspace(gl); struct address_space *metamapping = gfs2_glock2aspace(gl);
struct gfs2_rgrpd *rgd;
int error; int error;
if (!test_and_clear_bit(GLF_DIRTY, &gl->gl_flags)) if (!test_and_clear_bit(GLF_DIRTY, &gl->gl_flags))
...@@ -130,6 +146,12 @@ static void rgrp_go_sync(struct gfs2_glock *gl) ...@@ -130,6 +146,12 @@ static void rgrp_go_sync(struct gfs2_glock *gl)
error = filemap_fdatawait(metamapping); error = filemap_fdatawait(metamapping);
mapping_set_error(metamapping, error); mapping_set_error(metamapping, error);
gfs2_ail_empty_gl(gl); 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) ...@@ -429,33 +451,6 @@ static int inode_go_dump(struct seq_file *seq, const struct gfs2_glock *gl)
return 0; 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 * trans_go_sync - promote/demote the transaction glock
* @gl: the glock * @gl: the glock
...@@ -558,8 +553,8 @@ const struct gfs2_glock_operations gfs2_inode_glops = { ...@@ -558,8 +553,8 @@ const struct gfs2_glock_operations gfs2_inode_glops = {
const struct gfs2_glock_operations gfs2_rgrp_glops = { const struct gfs2_glock_operations gfs2_rgrp_glops = {
.go_xmote_th = rgrp_go_sync, .go_xmote_th = rgrp_go_sync,
.go_inval = rgrp_go_inval, .go_inval = rgrp_go_inval,
.go_lock = rgrp_go_lock, .go_lock = gfs2_rgrp_go_lock,
.go_unlock = rgrp_go_unlock, .go_unlock = gfs2_rgrp_go_unlock,
.go_dump = gfs2_rgrp_dump, .go_dump = gfs2_rgrp_dump,
.go_type = LM_TYPE_RGRP, .go_type = LM_TYPE_RGRP,
.go_flags = GLOF_ASPACE, .go_flags = GLOF_ASPACE,
......
...@@ -23,6 +23,6 @@ extern const struct gfs2_glock_operations gfs2_quota_glops; ...@@ -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_journal_glops;
extern const struct gfs2_glock_operations *gfs2_glops_list[]; 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__ */ #endif /* __GLOPS_DOT_H__ */
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
#include <linux/rculist_bl.h> #include <linux/rculist_bl.h>
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/rbtree.h>
#define DIO_WAIT 0x00000010 #define DIO_WAIT 0x00000010
#define DIO_METADATA 0x00000020 #define DIO_METADATA 0x00000020
...@@ -78,8 +79,7 @@ struct gfs2_bitmap { ...@@ -78,8 +79,7 @@ struct gfs2_bitmap {
}; };
struct gfs2_rgrpd { struct gfs2_rgrpd {
struct list_head rd_list; /* Link with superblock */ struct rb_node rd_node; /* Link with superblock */
struct list_head rd_list_mru;
struct gfs2_glock *rd_gl; /* Glock for this rgrp */ struct gfs2_glock *rd_gl; /* Glock for this rgrp */
u64 rd_addr; /* grp block disk address */ u64 rd_addr; /* grp block disk address */
u64 rd_data0; /* first data location */ u64 rd_data0; /* first data location */
...@@ -91,10 +91,7 @@ struct gfs2_rgrpd { ...@@ -91,10 +91,7 @@ struct gfs2_rgrpd {
u32 rd_dinodes; u32 rd_dinodes;
u64 rd_igeneration; u64 rd_igeneration;
struct gfs2_bitmap *rd_bits; struct gfs2_bitmap *rd_bits;
struct mutex rd_mutex;
struct gfs2_log_element rd_le;
struct gfs2_sbd *rd_sbd; struct gfs2_sbd *rd_sbd;
unsigned int rd_bh_count;
u32 rd_last_alloc; u32 rd_last_alloc;
u32 rd_flags; u32 rd_flags;
#define GFS2_RDF_CHECK 0x10000000 /* check for unlinked inodes */ #define GFS2_RDF_CHECK 0x10000000 /* check for unlinked inodes */
...@@ -106,12 +103,15 @@ struct gfs2_rgrpd { ...@@ -106,12 +103,15 @@ struct gfs2_rgrpd {
enum gfs2_state_bits { enum gfs2_state_bits {
BH_Pinned = BH_PrivateStart, BH_Pinned = BH_PrivateStart,
BH_Escaped = BH_PrivateStart + 1, BH_Escaped = BH_PrivateStart + 1,
BH_Zeronew = BH_PrivateStart + 2,
}; };
BUFFER_FNS(Pinned, pinned) BUFFER_FNS(Pinned, pinned)
TAS_BUFFER_FNS(Pinned, pinned) TAS_BUFFER_FNS(Pinned, pinned)
BUFFER_FNS(Escaped, escaped) BUFFER_FNS(Escaped, escaped)
TAS_BUFFER_FNS(Escaped, escaped) TAS_BUFFER_FNS(Escaped, escaped)
BUFFER_FNS(Zeronew, zeronew)
TAS_BUFFER_FNS(Zeronew, zeronew)
struct gfs2_bufdata { struct gfs2_bufdata {
struct buffer_head *bd_bh; struct buffer_head *bd_bh;
...@@ -246,7 +246,6 @@ struct gfs2_glock { ...@@ -246,7 +246,6 @@ struct gfs2_glock {
struct gfs2_alloc { struct gfs2_alloc {
/* Quota stuff */ /* Quota stuff */
struct gfs2_quota_data *al_qd[2*MAXQUOTAS]; struct gfs2_quota_data *al_qd[2*MAXQUOTAS];
struct gfs2_holder al_qd_ghs[2*MAXQUOTAS]; struct gfs2_holder al_qd_ghs[2*MAXQUOTAS];
unsigned int al_qd_num; unsigned int al_qd_num;
...@@ -255,18 +254,13 @@ struct gfs2_alloc { ...@@ -255,18 +254,13 @@ struct gfs2_alloc {
u32 al_alloced; /* Filled in by gfs2_alloc_*() */ u32 al_alloced; /* Filled in by gfs2_alloc_*() */
/* Filled in by gfs2_inplace_reserve() */ /* 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_holder al_rgd_gh;
struct gfs2_rgrpd *al_rgd;
}; };
enum { enum {
GIF_INVALID = 0, GIF_INVALID = 0,
GIF_QD_LOCKED = 1, GIF_QD_LOCKED = 1,
GIF_ALLOC_FAILED = 2,
GIF_SW_PAGED = 3, GIF_SW_PAGED = 3,
}; };
...@@ -282,6 +276,7 @@ struct gfs2_inode { ...@@ -282,6 +276,7 @@ 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;
struct gfs2_rgrpd *i_rgd;
u64 i_goal; /* goal block for allocations */ u64 i_goal; /* goal block for allocations */
struct rw_semaphore i_rw_mutex; struct rw_semaphore i_rw_mutex;
struct list_head i_trunc_list; struct list_head i_trunc_list;
...@@ -574,9 +569,7 @@ struct gfs2_sbd { ...@@ -574,9 +569,7 @@ struct gfs2_sbd {
int sd_rindex_uptodate; 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 rb_root sd_rindex_tree;
struct list_head sd_rindex_mru_list;
struct gfs2_rgrpd *sd_rindex_forward;
unsigned int sd_rgrps; unsigned int sd_rgrps;
unsigned int sd_max_rg_data; unsigned int sd_max_rg_data;
......
...@@ -583,7 +583,7 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name, ...@@ -583,7 +583,7 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name,
goto fail_quota_locks; goto fail_quota_locks;
error = gfs2_trans_begin(sdp, sdp->sd_max_dirres + error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
al->al_rgd->rd_length + dip->i_rgd->rd_length +
2 * RES_DINODE + 2 * RES_DINODE +
RES_STATFS + RES_QUOTA, 0); RES_STATFS + RES_QUOTA, 0);
if (error) if (error)
...@@ -613,8 +613,7 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name, ...@@ -613,8 +613,7 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name,
gfs2_trans_end(sdp); gfs2_trans_end(sdp);
fail_ipreserv: fail_ipreserv:
if (dip->i_alloc->al_rgd) gfs2_inplace_release(dip);
gfs2_inplace_release(dip);
fail_quota_locks: fail_quota_locks:
gfs2_quota_unlock(dip); gfs2_quota_unlock(dip);
...@@ -661,7 +660,7 @@ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip, ...@@ -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, static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
unsigned int mode, dev_t dev, const char *symname, unsigned int mode, dev_t dev, const char *symname,
unsigned int size) unsigned int size, int excl)
{ {
const struct qstr *name = &dentry->d_name; const struct qstr *name = &dentry->d_name;
struct gfs2_holder ghs[2]; struct gfs2_holder ghs[2];
...@@ -681,6 +680,12 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, ...@@ -681,6 +680,12 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
goto fail; goto fail;
error = create_ok(dip, name, mode); 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) if (error)
goto fail_gunlock; goto fail_gunlock;
...@@ -723,21 +728,22 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, ...@@ -723,21 +728,22 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
brelse(bh); brelse(bh);
gfs2_trans_end(sdp); gfs2_trans_end(sdp);
if (dip->i_alloc->al_rgd) gfs2_inplace_release(dip);
gfs2_inplace_release(dip);
gfs2_quota_unlock(dip); gfs2_quota_unlock(dip);
gfs2_alloc_put(dip); gfs2_alloc_put(dip);
gfs2_glock_dq_uninit_m(2, ghs);
mark_inode_dirty(inode); mark_inode_dirty(inode);
gfs2_glock_dq_uninit_m(2, ghs);
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
return 0; return 0;
fail_gunlock2: fail_gunlock2:
gfs2_glock_dq_uninit(ghs + 1); gfs2_glock_dq_uninit(ghs + 1);
if (inode && !IS_ERR(inode))
iput(inode);
fail_gunlock: fail_gunlock:
gfs2_glock_dq_uninit(ghs); gfs2_glock_dq_uninit(ghs);
if (inode && !IS_ERR(inode)) {
set_bit(GIF_ALLOC_FAILED, &GFS2_I(inode)->i_flags);
iput(inode);
}
fail: fail:
if (bh) if (bh)
brelse(bh); brelse(bh);
...@@ -756,24 +762,10 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, ...@@ -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, static int gfs2_create(struct inode *dir, struct dentry *dentry,
int mode, struct nameidata *nd) int mode, struct nameidata *nd)
{ {
struct inode *inode; int excl = 0;
int ret; if (nd && (nd->flags & LOOKUP_EXCL))
excl = 1;
for (;;) { return gfs2_create_inode(dir, dentry, S_IFREG | mode, 0, NULL, 0, excl);
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;
} }
/** /**
...@@ -900,7 +892,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, ...@@ -900,7 +892,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
goto out_gunlock_q; goto out_gunlock_q;
error = gfs2_trans_begin(sdp, sdp->sd_max_dirres + error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
gfs2_rg_blocks(al) + gfs2_rg_blocks(dip) +
2 * RES_DINODE + RES_STATFS + 2 * RES_DINODE + RES_STATFS +
RES_QUOTA, 0); RES_QUOTA, 0);
if (error) if (error)
...@@ -922,8 +914,9 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, ...@@ -922,8 +914,9 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_trans_add_bh(ip->i_gl, dibh, 1);
inc_nlink(&ip->i_inode); inc_nlink(&ip->i_inode);
ip->i_inode.i_ctime = CURRENT_TIME; ip->i_inode.i_ctime = CURRENT_TIME;
gfs2_dinode_out(ip, dibh->b_data); ihold(inode);
mark_inode_dirty(&ip->i_inode); d_instantiate(dentry, inode);
mark_inode_dirty(inode);
out_brelse: out_brelse:
brelse(dibh); brelse(dibh);
...@@ -945,11 +938,6 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, ...@@ -945,11 +938,6 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
out_parent: out_parent:
gfs2_holder_uninit(ghs); gfs2_holder_uninit(ghs);
gfs2_holder_uninit(ghs + 1); gfs2_holder_uninit(ghs + 1);
if (!error) {
ihold(inode);
d_instantiate(dentry, inode);
mark_inode_dirty(inode);
}
return error; return error;
} }
...@@ -1022,8 +1010,6 @@ static int gfs2_unlink_inode(struct gfs2_inode *dip, ...@@ -1022,8 +1010,6 @@ static int gfs2_unlink_inode(struct gfs2_inode *dip,
clear_nlink(inode); clear_nlink(inode);
else else
drop_nlink(inode); drop_nlink(inode);
gfs2_trans_add_bh(ip->i_gl, bh, 1);
gfs2_dinode_out(ip, bh->b_data);
mark_inode_dirty(inode); mark_inode_dirty(inode);
if (inode->i_nlink == 0) if (inode->i_nlink == 0)
gfs2_unlink_di(inode); gfs2_unlink_di(inode);
...@@ -1051,13 +1037,8 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry) ...@@ -1051,13 +1037,8 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry)
struct buffer_head *bh; struct buffer_head *bh;
struct gfs2_holder ghs[3]; struct gfs2_holder ghs[3];
struct gfs2_rgrpd *rgd; struct gfs2_rgrpd *rgd;
struct gfs2_holder ri_gh;
int error; 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(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1); 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) ...@@ -1114,7 +1095,6 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry)
gfs2_glock_dq(ghs); gfs2_glock_dq(ghs);
out_parent: out_parent:
gfs2_holder_uninit(ghs); gfs2_holder_uninit(ghs);
gfs2_glock_dq_uninit(&ri_gh);
return error; return error;
} }
...@@ -1137,7 +1117,7 @@ static int gfs2_symlink(struct inode *dir, struct dentry *dentry, ...@@ -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) if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode) - 1)
return -ENAMETOOLONG; 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, ...@@ -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) 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) ...@@ -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, static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode,
dev_t dev) 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, ...@@ -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 *ip = GFS2_I(odentry->d_inode);
struct gfs2_inode *nip = NULL; struct gfs2_inode *nip = NULL;
struct gfs2_sbd *sdp = GFS2_SB(odir); 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; struct gfs2_rgrpd *nrgd;
unsigned int num_gh; unsigned int num_gh;
int dir_rename = 0; int dir_rename = 0;
...@@ -1246,10 +1226,6 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, ...@@ -1246,10 +1226,6 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
return 0; return 0;
} }
error = gfs2_rindex_hold(sdp, &ri_gh);
if (error)
return error;
if (odip != ndip) { if (odip != ndip) {
error = gfs2_glock_nq_init(sdp->sd_rename_gl, LM_ST_EXCLUSIVE, error = gfs2_glock_nq_init(sdp->sd_rename_gl, LM_ST_EXCLUSIVE,
0, &r_gh); 0, &r_gh);
...@@ -1386,12 +1362,12 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, ...@@ -1386,12 +1362,12 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
al->al_requested = sdp->sd_max_dirres; al->al_requested = sdp->sd_max_dirres;
error = gfs2_inplace_reserve_ri(ndip); error = gfs2_inplace_reserve(ndip);
if (error) if (error)
goto out_gunlock_q; goto out_gunlock_q;
error = gfs2_trans_begin(sdp, sdp->sd_max_dirres + error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
gfs2_rg_blocks(al) + gfs2_rg_blocks(ndip) +
4 * RES_DINODE + 4 * RES_LEAF + 4 * RES_DINODE + 4 * RES_LEAF +
RES_STATFS + RES_QUOTA + 4, 0); RES_STATFS + RES_QUOTA + 4, 0);
if (error) if (error)
...@@ -1457,7 +1433,6 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, ...@@ -1457,7 +1433,6 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
if (r_gh.gh_gl) if (r_gh.gh_gl)
gfs2_glock_dq_uninit(&r_gh); gfs2_glock_dq_uninit(&r_gh);
out: out:
gfs2_glock_dq_uninit(&ri_gh);
return error; return error;
} }
...@@ -1561,21 +1536,10 @@ int gfs2_permission(struct inode *inode, int mask) ...@@ -1561,21 +1536,10 @@ int gfs2_permission(struct inode *inode, int mask)
return error; 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); setattr_copy(inode, attr);
mark_inode_dirty(inode); mark_inode_dirty(inode);
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
gfs2_dinode_out(ip, dibh->b_data);
brelse(dibh);
return 0; return 0;
} }
...@@ -1587,19 +1551,19 @@ static int __gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr) ...@@ -1587,19 +1551,19 @@ static int __gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr)
* Returns: errno * 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; int error;
if (current->journal_info) 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) if (error)
return error; return error;
error = __gfs2_setattr_simple(ip, attr); error = __gfs2_setattr_simple(inode, attr);
gfs2_trans_end(GFS2_SB(&ip->i_inode)); gfs2_trans_end(GFS2_SB(inode));
return error; return error;
} }
...@@ -1637,7 +1601,7 @@ static int setattr_chown(struct inode *inode, struct iattr *attr) ...@@ -1637,7 +1601,7 @@ static int setattr_chown(struct inode *inode, struct iattr *attr)
if (error) if (error)
goto out_gunlock_q; goto out_gunlock_q;
error = gfs2_setattr_simple(ip, attr); error = gfs2_setattr_simple(inode, attr);
if (error) if (error)
goto out_end_trans; goto out_end_trans;
...@@ -1693,12 +1657,12 @@ static int gfs2_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -1693,12 +1657,12 @@ static int gfs2_setattr(struct dentry *dentry, struct iattr *attr)
else if ((attr->ia_valid & ATTR_MODE) && IS_POSIXACL(inode)) else if ((attr->ia_valid & ATTR_MODE) && IS_POSIXACL(inode))
error = gfs2_acl_chmod(ip, attr); error = gfs2_acl_chmod(ip, attr);
else else
error = gfs2_setattr_simple(ip, attr); error = gfs2_setattr_simple(inode, attr);
out: out:
gfs2_glock_dq_uninit(&i_gh);
if (!error) if (!error)
mark_inode_dirty(inode); mark_inode_dirty(inode);
gfs2_glock_dq_uninit(&i_gh);
return error; return error;
} }
......
...@@ -109,7 +109,7 @@ extern int gfs2_inode_refresh(struct gfs2_inode *ip); ...@@ -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, extern struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
int is_root); int is_root);
extern int gfs2_permission(struct inode *inode, int mask); 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 struct inode *gfs2_lookup_simple(struct inode *dip, const char *name);
extern void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf); 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) ...@@ -60,6 +60,29 @@ static void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh)
trace_gfs2_pin(bd, 1); 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 * gfs2_unpin - Unpin a buffer
* @sdp: the filesystem the buffer belongs to * @sdp: the filesystem the buffer belongs to
...@@ -81,6 +104,9 @@ static void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh, ...@@ -81,6 +104,9 @@ static void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh,
mark_buffer_dirty(bh); mark_buffer_dirty(bh);
clear_buffer_pinned(bh); clear_buffer_pinned(bh);
if (buffer_is_rgrp(bd))
maybe_release_space(bd);
spin_lock(&sdp->sd_ail_lock); spin_lock(&sdp->sd_ail_lock);
if (bd->bd_ail) { if (bd->bd_ail) {
list_del(&bd->bd_ail_st_list); 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) ...@@ -469,42 +495,6 @@ static void revoke_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass)
gfs2_revoke_clean(sdp); 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. * 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, ...@@ -705,8 +695,6 @@ static int databuf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start,
brelse(bh_log); brelse(bh_log);
brelse(bh_ip); brelse(bh_ip);
if (error)
break;
sdp->sd_replayed_blocks++; sdp->sd_replayed_blocks++;
} }
...@@ -771,8 +759,6 @@ const struct gfs2_log_operations gfs2_revoke_lops = { ...@@ -771,8 +759,6 @@ const struct gfs2_log_operations gfs2_revoke_lops = {
}; };
const struct gfs2_log_operations gfs2_rg_lops = { const struct gfs2_log_operations gfs2_rg_lops = {
.lo_add = rg_lo_add,
.lo_after_commit = rg_lo_after_commit,
.lo_name = "rg", .lo_name = "rg",
}; };
......
...@@ -77,8 +77,7 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) ...@@ -77,8 +77,7 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
spin_lock_init(&sdp->sd_rindex_spin); spin_lock_init(&sdp->sd_rindex_spin);
mutex_init(&sdp->sd_rindex_mutex); mutex_init(&sdp->sd_rindex_mutex);
INIT_LIST_HEAD(&sdp->sd_rindex_list); sdp->sd_rindex_tree.rb_node = NULL;
INIT_LIST_HEAD(&sdp->sd_rindex_mru_list);
INIT_LIST_HEAD(&sdp->sd_jindex_list); INIT_LIST_HEAD(&sdp->sd_jindex_list);
spin_lock_init(&sdp->sd_jindex_spin); spin_lock_init(&sdp->sd_jindex_spin);
...@@ -652,7 +651,6 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) ...@@ -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); fs_err(sdp, "can't lookup journal index: %d\n", error);
return PTR_ERR(sdp->sd_jindex); return PTR_ERR(sdp->sd_jindex);
} }
ip = GFS2_I(sdp->sd_jindex);
/* Load in the journal index special file */ /* Load in the journal index special file */
...@@ -764,7 +762,6 @@ static int init_journal(struct gfs2_sbd *sdp, int undo) ...@@ -764,7 +762,6 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
static int init_inodes(struct gfs2_sbd *sdp, int undo) static int init_inodes(struct gfs2_sbd *sdp, int undo)
{ {
int error = 0; int error = 0;
struct gfs2_inode *ip;
struct inode *master = sdp->sd_master_dir->d_inode; struct inode *master = sdp->sd_master_dir->d_inode;
if (undo) if (undo)
...@@ -789,7 +786,6 @@ static int init_inodes(struct gfs2_sbd *sdp, int 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); fs_err(sdp, "can't get resource index inode: %d\n", error);
goto fail_statfs; goto fail_statfs;
} }
ip = GFS2_I(sdp->sd_rindex);
sdp->sd_rindex_uptodate = 0; sdp->sd_rindex_uptodate = 0;
/* Read in the quota inode */ /* Read in the quota inode */
......
...@@ -638,15 +638,18 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc, ...@@ -638,15 +638,18 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
unsigned long index = loc >> PAGE_CACHE_SHIFT; unsigned long index = loc >> PAGE_CACHE_SHIFT;
unsigned offset = loc & (PAGE_CACHE_SIZE - 1); unsigned offset = loc & (PAGE_CACHE_SIZE - 1);
unsigned blocksize, iblock, pos; unsigned blocksize, iblock, pos;
struct buffer_head *bh, *dibh; struct buffer_head *bh;
struct page *page; struct page *page;
void *kaddr, *ptr; void *kaddr, *ptr;
struct gfs2_quota q, *qp; struct gfs2_quota q, *qp;
int err, nbytes; int err, nbytes;
u64 size; u64 size;
if (gfs2_is_stuffed(ip)) if (gfs2_is_stuffed(ip)) {
gfs2_unstuff_dinode(ip, NULL); err = gfs2_unstuff_dinode(ip, NULL);
if (err)
return err;
}
memset(&q, 0, sizeof(struct gfs2_quota)); memset(&q, 0, sizeof(struct gfs2_quota));
err = gfs2_internal_read(ip, NULL, (char *)&q, &loc, sizeof(q)); 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, ...@@ -736,22 +739,13 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
goto get_a_page; 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); size = loc + sizeof(struct gfs2_quota);
if (size > inode->i_size) if (size > inode->i_size)
i_size_write(inode, size); i_size_write(inode, size);
inode->i_mtime = inode->i_atime = CURRENT_TIME; 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); mark_inode_dirty(inode);
out:
return err; return err;
unlock_out: unlock_out:
unlock_page(page); unlock_page(page);
page_cache_release(page); page_cache_release(page);
...@@ -822,7 +816,7 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda) ...@@ -822,7 +816,7 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda)
goto out_alloc; goto out_alloc;
if (nalloc) 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); error = gfs2_trans_begin(sdp, blocks, 0);
if (error) if (error)
...@@ -936,7 +930,9 @@ int gfs2_quota_lock(struct gfs2_inode *ip, u32 uid, u32 gid) ...@@ -936,7 +930,9 @@ int gfs2_quota_lock(struct gfs2_inode *ip, u32 uid, u32 gid)
unsigned int x; unsigned int x;
int error = 0; 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) || if (capable(CAP_SYS_RESOURCE) ||
sdp->sd_args.ar_quota != GFS2_QUOTA_ON) 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, ...@@ -1607,7 +1603,7 @@ static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
error = gfs2_inplace_reserve(ip); error = gfs2_inplace_reserve(ip);
if (error) if (error)
goto out_alloc; goto out_alloc;
blocks += gfs2_rg_blocks(al); blocks += gfs2_rg_blocks(ip);
} }
/* Some quotas span block boundaries and can update two blocks, /* Some quotas span block boundaries and can update two blocks,
......
This diff is collapsed.
...@@ -18,18 +18,15 @@ struct gfs2_holder; ...@@ -18,18 +18,15 @@ struct gfs2_holder;
extern void gfs2_rgrp_verify(struct gfs2_rgrpd *rgd); extern void gfs2_rgrp_verify(struct gfs2_rgrpd *rgd);
struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk); extern struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk);
struct gfs2_rgrpd *gfs2_rgrpd_get_first(struct gfs2_sbd *sdp); extern 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_rgrpd_get_next(struct gfs2_rgrpd *rgd);
extern void gfs2_clear_rgrpd(struct gfs2_sbd *sdp); 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_rindex_update(struct gfs2_sbd *sdp);
extern void gfs2_free_clones(struct gfs2_rgrpd *rgd);
extern int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd); extern int gfs2_rgrp_go_lock(struct gfs2_holder *gh);
extern void gfs2_rgrp_bh_hold(struct gfs2_rgrpd *rgd); extern void gfs2_rgrp_go_unlock(struct gfs2_holder *gh);
extern void gfs2_rgrp_bh_put(struct gfs2_rgrpd *rgd);
extern void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd);
extern struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip); extern struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip);
static inline void gfs2_alloc_put(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) ...@@ -39,16 +36,9 @@ static inline void gfs2_alloc_put(struct gfs2_inode *ip)
ip->i_alloc = NULL; ip->i_alloc = NULL;
} }
extern int gfs2_inplace_reserve_i(struct gfs2_inode *ip, int hold_rindex, extern int gfs2_inplace_reserve(struct gfs2_inode *ip);
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 void gfs2_inplace_release(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_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n);
extern int gfs2_alloc_di(struct gfs2_inode *ip, u64 *bn, u64 *generation); extern int gfs2_alloc_di(struct gfs2_inode *ip, u64 *bn, u64 *generation);
...@@ -66,11 +56,14 @@ struct gfs2_rgrp_list { ...@@ -66,11 +56,14 @@ struct gfs2_rgrp_list {
struct gfs2_holder *rl_ghs; 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); u64 block);
extern void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, unsigned int state); extern void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, unsigned int state);
extern void gfs2_rlist_free(struct gfs2_rgrp_list *rlist); extern void gfs2_rlist_free(struct gfs2_rgrp_list *rlist);
extern u64 gfs2_ri_total(struct gfs2_sbd *sdp); extern u64 gfs2_ri_total(struct gfs2_sbd *sdp);
extern int gfs2_rgrp_dump(struct seq_file *seq, const struct gfs2_glock *gl); 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__ */ #endif /* __RGRP_DOT_H__ */
...@@ -752,51 +752,77 @@ static int gfs2_write_inode(struct inode *inode, struct writeback_control *wbc) ...@@ -752,51 +752,77 @@ static int gfs2_write_inode(struct inode *inode, struct writeback_control *wbc)
struct gfs2_sbd *sdp = GFS2_SB(inode); struct gfs2_sbd *sdp = GFS2_SB(inode);
struct address_space *metamapping = gfs2_glock2aspace(ip->i_gl); struct address_space *metamapping = gfs2_glock2aspace(ip->i_gl);
struct backing_dev_info *bdi = metamapping->backing_dev_info; 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 buffer_head *bh;
struct timespec atime; struct gfs2_holder gh;
struct gfs2_dinode *di; int need_unlock = 0;
int ret = -EAGAIN; int need_endtrans = 0;
int unlock_required = 0; int ret;
/* Skip timestamp update, if this is from a memalloc */ if (!(flags & (I_DIRTY_DATASYNC|I_DIRTY_SYNC)))
if (current->flags & PF_MEMALLOC) return;
goto do_flush;
if (!gfs2_glock_is_locked_by_me(ip->i_gl)) { if (!gfs2_glock_is_locked_by_me(ip->i_gl)) {
ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
if (ret) if (ret) {
goto do_flush; fs_err(sdp, "dirty_inode: glock %d\n", ret);
unlock_required = 1; return;
}
need_unlock = 1;
} }
ret = gfs2_trans_begin(sdp, RES_DINODE, 0);
if (ret) if (current->journal_info == NULL) {
goto do_unlock; 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); ret = gfs2_meta_inode_buffer(ip, &bh);
if (ret == 0) { if (ret == 0) {
di = (struct gfs2_dinode *)bh->b_data; gfs2_trans_add_bh(ip->i_gl, bh, 1);
atime.tv_sec = be64_to_cpu(di->di_atime); gfs2_dinode_out(ip, bh->b_data);
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);
}
brelse(bh); brelse(bh);
} }
gfs2_trans_end(sdp);
do_unlock: if (need_endtrans)
if (unlock_required) gfs2_trans_end(sdp);
out:
if (need_unlock)
gfs2_glock_dq_uninit(&gh); 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, ...@@ -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) 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_rgrpd *rgd_next;
struct gfs2_holder *gha, *gh; struct gfs2_holder *gha, *gh;
unsigned int slots = 64; unsigned int slots = 64;
...@@ -1024,10 +1049,6 @@ static int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change_host ...@@ -1024,10 +1049,6 @@ static int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change_host
if (!gha) if (!gha)
return -ENOMEM; return -ENOMEM;
error = gfs2_rindex_hold(sdp, &ri_gh);
if (error)
goto out;
rgd_next = gfs2_rgrpd_get_first(sdp); rgd_next = gfs2_rgrpd_get_first(sdp);
for (;;) { for (;;) {
...@@ -1070,9 +1091,6 @@ static int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change_host ...@@ -1070,9 +1091,6 @@ static int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change_host
yield(); yield();
} }
gfs2_glock_dq_uninit(&ri_gh);
out:
kfree(gha); kfree(gha);
return error; return error;
} }
...@@ -1124,6 +1142,10 @@ static int gfs2_statfs(struct dentry *dentry, struct kstatfs *buf) ...@@ -1124,6 +1142,10 @@ static int gfs2_statfs(struct dentry *dentry, struct kstatfs *buf)
struct gfs2_statfs_change_host sc; struct gfs2_statfs_change_host sc;
int error; int error;
error = gfs2_rindex_update(sdp);
if (error)
return error;
if (gfs2_tune_get(sdp, gt_statfs_slow)) if (gfs2_tune_get(sdp, gt_statfs_slow))
error = gfs2_statfs_slow(sdp, &sc); error = gfs2_statfs_slow(sdp, &sc);
else else
...@@ -1394,21 +1416,17 @@ static int gfs2_dinode_dealloc(struct gfs2_inode *ip) ...@@ -1394,21 +1416,17 @@ static int gfs2_dinode_dealloc(struct gfs2_inode *ip)
if (error) if (error)
goto out; goto out;
error = gfs2_rindex_hold(sdp, &al->al_ri_gh);
if (error)
goto out_qs;
rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr); rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr);
if (!rgd) { if (!rgd) {
gfs2_consist_inode(ip); gfs2_consist_inode(ip);
error = -EIO; error = -EIO;
goto out_rindex_relse; goto out_qs;
} }
error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0,
&al->al_rgd_gh); &al->al_rgd_gh);
if (error) if (error)
goto out_rindex_relse; goto out_qs;
error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_STATFS + RES_QUOTA, error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_STATFS + RES_QUOTA,
sdp->sd_jdesc->jd_blocks); sdp->sd_jdesc->jd_blocks);
...@@ -1423,8 +1441,6 @@ static int gfs2_dinode_dealloc(struct gfs2_inode *ip) ...@@ -1423,8 +1441,6 @@ static int gfs2_dinode_dealloc(struct gfs2_inode *ip)
out_rg_gunlock: out_rg_gunlock:
gfs2_glock_dq_uninit(&al->al_rgd_gh); gfs2_glock_dq_uninit(&al->al_rgd_gh);
out_rindex_relse:
gfs2_glock_dq_uninit(&al->al_ri_gh);
out_qs: out_qs:
gfs2_quota_unhold(ip); gfs2_quota_unhold(ip);
out: out:
...@@ -1471,9 +1487,11 @@ static void gfs2_evict_inode(struct inode *inode) ...@@ -1471,9 +1487,11 @@ static void gfs2_evict_inode(struct inode *inode)
goto out; goto out;
} }
error = gfs2_check_blk_type(sdp, ip->i_no_addr, GFS2_BLKST_UNLINKED); if (!test_bit(GIF_ALLOC_FAILED, &ip->i_flags)) {
if (error) error = gfs2_check_blk_type(sdp, ip->i_no_addr, GFS2_BLKST_UNLINKED);
goto out_truncate; if (error)
goto out_truncate;
}
if (test_bit(GIF_INVALID, &ip->i_flags)) { if (test_bit(GIF_INVALID, &ip->i_flags)) {
error = gfs2_inode_refresh(ip); error = gfs2_inode_refresh(ip);
...@@ -1513,6 +1531,10 @@ static void gfs2_evict_inode(struct inode *inode) ...@@ -1513,6 +1531,10 @@ static void gfs2_evict_inode(struct inode *inode)
goto out_unlock; goto out_unlock;
out_truncate: 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 */ /* Case 2 starts here */
error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks); error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks);
if (error) if (error)
...@@ -1552,6 +1574,7 @@ static struct inode *gfs2_alloc_inode(struct super_block *sb) ...@@ -1552,6 +1574,7 @@ static struct inode *gfs2_alloc_inode(struct super_block *sb)
if (ip) { if (ip) {
ip->i_flags = 0; ip->i_flags = 0;
ip->i_gl = NULL; ip->i_gl = NULL;
ip->i_rgd = NULL;
} }
return &ip->i_inode; return &ip->i_inode;
} }
...@@ -1572,6 +1595,7 @@ const struct super_operations gfs2_super_ops = { ...@@ -1572,6 +1595,7 @@ const struct super_operations gfs2_super_ops = {
.alloc_inode = gfs2_alloc_inode, .alloc_inode = gfs2_alloc_inode,
.destroy_inode = gfs2_destroy_inode, .destroy_inode = gfs2_destroy_inode,
.write_inode = gfs2_write_inode, .write_inode = gfs2_write_inode,
.dirty_inode = gfs2_dirty_inode,
.evict_inode = gfs2_evict_inode, .evict_inode = gfs2_evict_inode,
.put_super = gfs2_put_super, .put_super = gfs2_put_super,
.sync_fs = gfs2_sync_fs, .sync_fs = gfs2_sync_fs,
......
...@@ -185,8 +185,3 @@ void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno, unsigned int len) ...@@ -185,8 +185,3 @@ void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno, unsigned int len)
gfs2_log_unlock(sdp); 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; ...@@ -28,20 +28,20 @@ struct gfs2_glock;
/* reserve either the number of blocks to be allocated plus the rg header /* 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 */ * 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)? const struct gfs2_alloc *al = ip->i_alloc;
al->al_requested + 1 : al->al_rgd->rd_length; 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, extern int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks,
unsigned int revokes); unsigned int revokes);
void gfs2_trans_end(struct gfs2_sbd *sdp); 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);
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);
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);
void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno, unsigned int len);
void gfs2_trans_add_rg(struct gfs2_rgrpd *rgd);
#endif /* __TRANS_DOT_H__ */ #endif /* __TRANS_DOT_H__ */
...@@ -332,15 +332,8 @@ static int ea_remove_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh, ...@@ -332,15 +332,8 @@ static int ea_remove_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh,
if (error) if (error)
goto out_alloc; 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); 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); gfs2_quota_unhold(ip);
out_alloc: out_alloc:
gfs2_alloc_put(ip); gfs2_alloc_put(ip);
...@@ -734,7 +727,7 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er, ...@@ -734,7 +727,7 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er,
goto out_gunlock_q; goto out_gunlock_q;
error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), 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); RES_DINODE + RES_STATFS + RES_QUOTA, 0);
if (error) if (error)
goto out_ipres; goto out_ipres;
...@@ -1296,7 +1289,8 @@ static int ea_acl_chmod_unstuffed(struct gfs2_inode *ip, ...@@ -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) 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; struct gfs2_ea_location el;
int error; int error;
...@@ -1319,7 +1313,7 @@ int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data) ...@@ -1319,7 +1313,7 @@ int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data)
if (error) if (error)
return error; return error;
error = gfs2_setattr_simple(ip, attr); error = gfs2_setattr_simple(inode, attr);
gfs2_trans_end(sdp); gfs2_trans_end(sdp);
return error; return error;
} }
...@@ -1362,14 +1356,14 @@ static int ea_dealloc_indirect(struct gfs2_inode *ip) ...@@ -1362,14 +1356,14 @@ static int ea_dealloc_indirect(struct gfs2_inode *ip)
blen++; blen++;
else { else {
if (bstart) if (bstart)
gfs2_rlist_add(sdp, &rlist, bstart); gfs2_rlist_add(ip, &rlist, bstart);
bstart = bn; bstart = bn;
blen = 1; blen = 1;
} }
blks++; blks++;
} }
if (bstart) if (bstart)
gfs2_rlist_add(sdp, &rlist, bstart); gfs2_rlist_add(ip, &rlist, bstart);
else else
goto out; goto out;
...@@ -1501,24 +1495,18 @@ int gfs2_ea_dealloc(struct gfs2_inode *ip) ...@@ -1501,24 +1495,18 @@ int gfs2_ea_dealloc(struct gfs2_inode *ip)
if (error) if (error)
goto out_alloc; 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); error = ea_foreach(ip, ea_dealloc_unstuffed, NULL);
if (error) if (error)
goto out_rindex; goto out_quota;
if (ip->i_diskflags & GFS2_DIF_EA_INDIRECT) { if (ip->i_diskflags & GFS2_DIF_EA_INDIRECT) {
error = ea_dealloc_indirect(ip); error = ea_dealloc_indirect(ip);
if (error) if (error)
goto out_rindex; goto out_quota;
} }
error = ea_dealloc_block(ip); error = ea_dealloc_block(ip);
out_rindex:
gfs2_glock_dq_uninit(&al->al_ri_gh);
out_quota: out_quota:
gfs2_quota_unhold(ip); gfs2_quota_unhold(ip);
out_alloc: 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