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);
......
...@@ -59,15 +59,24 @@ static loff_t gfs2_llseek(struct file *file, loff_t offset, int origin) ...@@ -59,15 +59,24 @@ static loff_t gfs2_llseek(struct file *file, loff_t offset, int origin)
struct gfs2_holder i_gh; struct gfs2_holder i_gh;
loff_t error; loff_t error;
if (origin == 2) { switch (origin) {
case SEEK_END: /* These reference inode->i_size */
case SEEK_DATA:
case SEEK_HOLE:
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY,
&i_gh); &i_gh);
if (!error) { if (!error) {
error = generic_file_llseek_unlocked(file, offset, origin); error = generic_file_llseek_unlocked(file, offset, origin);
gfs2_glock_dq_uninit(&i_gh); gfs2_glock_dq_uninit(&i_gh);
} }
} else break;
case SEEK_CUR:
case SEEK_SET:
error = generic_file_llseek_unlocked(file, offset, origin); error = generic_file_llseek_unlocked(file, offset, origin);
break;
default:
error = -EINVAL;
}
return error; return error;
} }
...@@ -357,8 +366,15 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) ...@@ -357,8 +366,15 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
unsigned int data_blocks, ind_blocks, rblocks; unsigned int data_blocks, ind_blocks, rblocks;
struct gfs2_holder gh; struct gfs2_holder gh;
struct gfs2_alloc *al; struct gfs2_alloc *al;
loff_t size;
int ret; int ret;
/* Wait if fs is frozen. This is racy so we check again later on
* and retry if the fs has been frozen after the page lock has
* been acquired
*/
vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE);
gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
ret = gfs2_glock_nq(&gh); ret = gfs2_glock_nq(&gh);
if (ret) if (ret)
...@@ -367,8 +383,15 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) ...@@ -367,8 +383,15 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
set_bit(GLF_DIRTY, &ip->i_gl->gl_flags); set_bit(GLF_DIRTY, &ip->i_gl->gl_flags);
set_bit(GIF_SW_PAGED, &ip->i_flags); set_bit(GIF_SW_PAGED, &ip->i_flags);
if (!gfs2_write_alloc_required(ip, pos, PAGE_CACHE_SIZE)) if (!gfs2_write_alloc_required(ip, pos, PAGE_CACHE_SIZE)) {
lock_page(page);
if (!PageUptodate(page) || page->mapping != inode->i_mapping) {
ret = -EAGAIN;
unlock_page(page);
}
goto out_unlock; goto out_unlock;
}
ret = -ENOMEM; ret = -ENOMEM;
al = gfs2_alloc_get(ip); al = gfs2_alloc_get(ip);
if (al == NULL) if (al == NULL)
...@@ -388,7 +411,7 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) ...@@ -388,7 +411,7 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
rblocks += data_blocks ? data_blocks : 1; rblocks += data_blocks ? data_blocks : 1;
if (ind_blocks || data_blocks) { if (ind_blocks || data_blocks) {
rblocks += RES_STATFS + RES_QUOTA; rblocks += RES_STATFS + RES_QUOTA;
rblocks += gfs2_rg_blocks(al); rblocks += gfs2_rg_blocks(ip);
} }
ret = gfs2_trans_begin(sdp, rblocks, 0); ret = gfs2_trans_begin(sdp, rblocks, 0);
if (ret) if (ret)
...@@ -396,21 +419,29 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) ...@@ -396,21 +419,29 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
lock_page(page); lock_page(page);
ret = -EINVAL; ret = -EINVAL;
last_index = ip->i_inode.i_size >> PAGE_CACHE_SHIFT; size = i_size_read(inode);
if (page->index > last_index) last_index = (size - 1) >> PAGE_CACHE_SHIFT;
goto out_unlock_page; /* Check page index against inode size */
if (size == 0 || (page->index > last_index))
goto out_trans_end;
ret = -EAGAIN;
/* If truncated, we must retry the operation, we may have raced
* with the glock demotion code.
*/
if (!PageUptodate(page) || page->mapping != inode->i_mapping)
goto out_trans_end;
/* Unstuff, if required, and allocate backing blocks for page */
ret = 0; ret = 0;
if (!PageUptodate(page) || page->mapping != ip->i_inode.i_mapping) if (gfs2_is_stuffed(ip))
goto out_unlock_page;
if (gfs2_is_stuffed(ip)) {
ret = gfs2_unstuff_dinode(ip, page); ret = gfs2_unstuff_dinode(ip, page);
if (ret) if (ret == 0)
goto out_unlock_page; ret = gfs2_allocate_page_backing(page);
}
ret = gfs2_allocate_page_backing(page);
out_unlock_page: out_trans_end:
unlock_page(page); if (ret)
unlock_page(page);
gfs2_trans_end(sdp); gfs2_trans_end(sdp);
out_trans_fail: out_trans_fail:
gfs2_inplace_release(ip); gfs2_inplace_release(ip);
...@@ -422,11 +453,17 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) ...@@ -422,11 +453,17 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
gfs2_glock_dq(&gh); gfs2_glock_dq(&gh);
out: out:
gfs2_holder_uninit(&gh); gfs2_holder_uninit(&gh);
if (ret == -ENOMEM) if (ret == 0) {
ret = VM_FAULT_OOM; set_page_dirty(page);
else if (ret) /* This check must be post dropping of transaction lock */
ret = VM_FAULT_SIGBUS; if (inode->i_sb->s_frozen == SB_UNFROZEN) {
return ret; wait_on_page_writeback(page);
} else {
ret = -EAGAIN;
unlock_page(page);
}
}
return block_page_mkwrite_return(ret);
} }
static const struct vm_operations_struct gfs2_vm_ops = { static const struct vm_operations_struct gfs2_vm_ops = {
...@@ -551,8 +588,16 @@ static int gfs2_close(struct inode *inode, struct file *file) ...@@ -551,8 +588,16 @@ static int gfs2_close(struct inode *inode, struct file *file)
* @end: the end position in the file to sync * @end: the end position in the file to sync
* @datasync: set if we can ignore timestamp changes * @datasync: set if we can ignore timestamp changes
* *
* The VFS will flush data for us. We only need to worry * We split the data flushing here so that we don't wait for the data
* about metadata here. * until after we've also sent the metadata to disk. Note that for
* data=ordered, we will write & wait for the data at the log flush
* stage anyway, so this is unlikely to make much of a difference
* except in the data=writeback case.
*
* If the fdatawrite fails due to any reason except -EIO, we will
* continue the remainder of the fsync, although we'll still report
* the error at the end. This is to match filemap_write_and_wait_range()
* behaviour.
* *
* Returns: errno * Returns: errno
*/ */
...@@ -560,30 +605,34 @@ static int gfs2_close(struct inode *inode, struct file *file) ...@@ -560,30 +605,34 @@ static int gfs2_close(struct inode *inode, struct file *file)
static int gfs2_fsync(struct file *file, loff_t start, loff_t end, static int gfs2_fsync(struct file *file, loff_t start, loff_t end,
int datasync) int datasync)
{ {
struct inode *inode = file->f_mapping->host; struct address_space *mapping = file->f_mapping;
struct inode *inode = mapping->host;
int sync_state = inode->i_state & (I_DIRTY_SYNC|I_DIRTY_DATASYNC); int sync_state = inode->i_state & (I_DIRTY_SYNC|I_DIRTY_DATASYNC);
struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_inode *ip = GFS2_I(inode);
int ret; int ret, ret1 = 0;
ret = filemap_write_and_wait_range(inode->i_mapping, start, end); if (mapping->nrpages) {
if (ret) ret1 = filemap_fdatawrite_range(mapping, start, end);
return ret; if (ret1 == -EIO)
mutex_lock(&inode->i_mutex); return ret1;
}
if (datasync) if (datasync)
sync_state &= ~I_DIRTY_SYNC; sync_state &= ~I_DIRTY_SYNC;
if (sync_state) { if (sync_state) {
ret = sync_inode_metadata(inode, 1); ret = sync_inode_metadata(inode, 1);
if (ret) { if (ret)
mutex_unlock(&inode->i_mutex);
return ret; return ret;
} if (gfs2_is_jdata(ip))
gfs2_ail_flush(ip->i_gl); filemap_write_and_wait(mapping);
gfs2_ail_flush(ip->i_gl, 1);
} }
mutex_unlock(&inode->i_mutex); if (mapping->nrpages)
return 0; ret = filemap_fdatawait_range(mapping, start, end);
return ret ? ret : ret1;
} }
/** /**
...@@ -620,135 +669,18 @@ static ssize_t gfs2_file_aio_write(struct kiocb *iocb, const struct iovec *iov, ...@@ -620,135 +669,18 @@ static ssize_t gfs2_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
return generic_file_aio_write(iocb, iov, nr_segs, pos); return generic_file_aio_write(iocb, iov, nr_segs, pos);
} }
static int empty_write_end(struct page *page, unsigned from,
unsigned to, int mode)
{
struct inode *inode = page->mapping->host;
struct gfs2_inode *ip = GFS2_I(inode);
struct buffer_head *bh;
unsigned offset, blksize = 1 << inode->i_blkbits;
pgoff_t end_index = i_size_read(inode) >> PAGE_CACHE_SHIFT;
zero_user(page, from, to-from);
mark_page_accessed(page);
if (page->index < end_index || !(mode & FALLOC_FL_KEEP_SIZE)) {
if (!gfs2_is_writeback(ip))
gfs2_page_add_databufs(ip, page, from, to);
block_commit_write(page, from, to);
return 0;
}
offset = 0;
bh = page_buffers(page);
while (offset < to) {
if (offset >= from) {
set_buffer_uptodate(bh);
mark_buffer_dirty(bh);
clear_buffer_new(bh);
write_dirty_buffer(bh, WRITE);
}
offset += blksize;
bh = bh->b_this_page;
}
offset = 0;
bh = page_buffers(page);
while (offset < to) {
if (offset >= from) {
wait_on_buffer(bh);
if (!buffer_uptodate(bh))
return -EIO;
}
offset += blksize;
bh = bh->b_this_page;
}
return 0;
}
static int needs_empty_write(sector_t block, struct inode *inode)
{
int error;
struct buffer_head bh_map = { .b_state = 0, .b_blocknr = 0 };
bh_map.b_size = 1 << inode->i_blkbits;
error = gfs2_block_map(inode, block, &bh_map, 0);
if (unlikely(error))
return error;
return !buffer_mapped(&bh_map);
}
static int write_empty_blocks(struct page *page, unsigned from, unsigned to,
int mode)
{
struct inode *inode = page->mapping->host;
unsigned start, end, next, blksize;
sector_t block = page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits);
int ret;
blksize = 1 << inode->i_blkbits;
next = end = 0;
while (next < from) {
next += blksize;
block++;
}
start = next;
do {
next += blksize;
ret = needs_empty_write(block, inode);
if (unlikely(ret < 0))
return ret;
if (ret == 0) {
if (end) {
ret = __block_write_begin(page, start, end - start,
gfs2_block_map);
if (unlikely(ret))
return ret;
ret = empty_write_end(page, start, end, mode);
if (unlikely(ret))
return ret;
end = 0;
}
start = next;
}
else
end = next;
block++;
} while (next < to);
if (end) {
ret = __block_write_begin(page, start, end - start, gfs2_block_map);
if (unlikely(ret))
return ret;
ret = empty_write_end(page, start, end, mode);
if (unlikely(ret))
return ret;
}
return 0;
}
static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len, static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len,
int mode) int mode)
{ {
struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_inode *ip = GFS2_I(inode);
struct buffer_head *dibh; struct buffer_head *dibh;
int error; int error;
u64 start = offset >> PAGE_CACHE_SHIFT; unsigned int nr_blks;
unsigned int start_offset = offset & ~PAGE_CACHE_MASK; sector_t lblock = offset >> inode->i_blkbits;
u64 end = (offset + len - 1) >> PAGE_CACHE_SHIFT;
pgoff_t curr;
struct page *page;
unsigned int end_offset = (offset + len) & ~PAGE_CACHE_MASK;
unsigned int from, to;
if (!end_offset)
end_offset = PAGE_CACHE_SIZE;
error = gfs2_meta_inode_buffer(ip, &dibh); error = gfs2_meta_inode_buffer(ip, &dibh);
if (unlikely(error)) if (unlikely(error))
goto out; return error;
gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_trans_add_bh(ip->i_gl, dibh, 1);
...@@ -758,40 +690,31 @@ static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len, ...@@ -758,40 +690,31 @@ static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len,
goto out; goto out;
} }
curr = start; while (len) {
offset = start << PAGE_CACHE_SHIFT; struct buffer_head bh_map = { .b_state = 0, .b_blocknr = 0 };
from = start_offset; bh_map.b_size = len;
to = PAGE_CACHE_SIZE; set_buffer_zeronew(&bh_map);
while (curr <= end) {
page = grab_cache_page_write_begin(inode->i_mapping, curr,
AOP_FLAG_NOFS);
if (unlikely(!page)) {
error = -ENOMEM;
goto out;
}
if (curr == end) error = gfs2_block_map(inode, lblock, &bh_map, 1);
to = end_offset; if (unlikely(error))
error = write_empty_blocks(page, from, to, mode);
if (!error && offset + to > inode->i_size &&
!(mode & FALLOC_FL_KEEP_SIZE)) {
i_size_write(inode, offset + to);
}
unlock_page(page);
page_cache_release(page);
if (error)
goto out; goto out;
curr++; len -= bh_map.b_size;
offset += PAGE_CACHE_SIZE; nr_blks = bh_map.b_size >> inode->i_blkbits;
from = 0; lblock += nr_blks;
if (!buffer_new(&bh_map))
continue;
if (unlikely(!buffer_zeronew(&bh_map))) {
error = -EIO;
goto out;
}
} }
if (offset + len > inode->i_size && !(mode & FALLOC_FL_KEEP_SIZE))
i_size_write(inode, offset + len);
gfs2_dinode_out(ip, dibh->b_data);
mark_inode_dirty(inode); mark_inode_dirty(inode);
brelse(dibh);
out: out:
brelse(dibh);
return error; return error;
} }
...@@ -799,7 +722,7 @@ static void calc_max_reserv(struct gfs2_inode *ip, loff_t max, loff_t *len, ...@@ -799,7 +722,7 @@ static void calc_max_reserv(struct gfs2_inode *ip, loff_t max, loff_t *len,
unsigned int *data_blocks, unsigned int *ind_blocks) unsigned int *data_blocks, unsigned int *ind_blocks)
{ {
const struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); const struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
unsigned int max_blocks = ip->i_alloc->al_rgd->rd_free_clone; unsigned int max_blocks = ip->i_rgd->rd_free_clone;
unsigned int tmp, max_data = max_blocks - 3 * (sdp->sd_max_height - 1); unsigned int tmp, max_data = max_blocks - 3 * (sdp->sd_max_height - 1);
for (tmp = max_data; tmp > sdp->sd_diptrs;) { for (tmp = max_data; tmp > sdp->sd_diptrs;) {
...@@ -831,6 +754,7 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset, ...@@ -831,6 +754,7 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset,
int error; int error;
loff_t bsize_mask = ~((loff_t)sdp->sd_sb.sb_bsize - 1); loff_t bsize_mask = ~((loff_t)sdp->sd_sb.sb_bsize - 1);
loff_t next = (offset + len - 1) >> sdp->sd_sb.sb_bsize_shift; loff_t next = (offset + len - 1) >> sdp->sd_sb.sb_bsize_shift;
loff_t max_chunk_size = UINT_MAX & bsize_mask;
next = (next + 1) << sdp->sd_sb.sb_bsize_shift; next = (next + 1) << sdp->sd_sb.sb_bsize_shift;
/* We only support the FALLOC_FL_KEEP_SIZE mode */ /* We only support the FALLOC_FL_KEEP_SIZE mode */
...@@ -884,11 +808,12 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset, ...@@ -884,11 +808,12 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset,
goto out_qunlock; goto out_qunlock;
} }
max_bytes = bytes; max_bytes = bytes;
calc_max_reserv(ip, len, &max_bytes, &data_blocks, &ind_blocks); calc_max_reserv(ip, (len > max_chunk_size)? max_chunk_size: len,
&max_bytes, &data_blocks, &ind_blocks);
al->al_requested = data_blocks + ind_blocks; al->al_requested = data_blocks + ind_blocks;
rblocks = RES_DINODE + ind_blocks + RES_STATFS + RES_QUOTA + rblocks = RES_DINODE + ind_blocks + RES_STATFS + RES_QUOTA +
RES_RG_HDR + gfs2_rg_blocks(al); RES_RG_HDR + gfs2_rg_blocks(ip);
if (gfs2_is_jdata(ip)) if (gfs2_is_jdata(ip))
rblocks += data_blocks ? data_blocks : 1; rblocks += data_blocks ? data_blocks : 1;
......
...@@ -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,
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/gfs2_ondisk.h> #include <linux/gfs2_ondisk.h>
#include <linux/prefetch.h> #include <linux/prefetch.h>
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <linux/rbtree.h>
#include "gfs2.h" #include "gfs2.h"
#include "incore.h" #include "incore.h"
...@@ -328,18 +329,22 @@ static inline int rgrp_contains_block(struct gfs2_rgrpd *rgd, u64 block) ...@@ -328,18 +329,22 @@ static inline int rgrp_contains_block(struct gfs2_rgrpd *rgd, u64 block)
struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk) struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk)
{ {
struct gfs2_rgrpd *rgd; struct rb_node **newn;
struct gfs2_rgrpd *cur;
spin_lock(&sdp->sd_rindex_spin); spin_lock(&sdp->sd_rindex_spin);
newn = &sdp->sd_rindex_tree.rb_node;
list_for_each_entry(rgd, &sdp->sd_rindex_mru_list, rd_list_mru) { while (*newn) {
if (rgrp_contains_block(rgd, blk)) { cur = rb_entry(*newn, struct gfs2_rgrpd, rd_node);
list_move(&rgd->rd_list_mru, &sdp->sd_rindex_mru_list); if (blk < cur->rd_addr)
newn = &((*newn)->rb_left);
else if (blk >= cur->rd_data0 + cur->rd_data)
newn = &((*newn)->rb_right);
else {
spin_unlock(&sdp->sd_rindex_spin); spin_unlock(&sdp->sd_rindex_spin);
return rgd; return cur;
} }
} }
spin_unlock(&sdp->sd_rindex_spin); spin_unlock(&sdp->sd_rindex_spin);
return NULL; return NULL;
...@@ -354,8 +359,15 @@ struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk) ...@@ -354,8 +359,15 @@ 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_first(struct gfs2_sbd *sdp)
{ {
gfs2_assert(sdp, !list_empty(&sdp->sd_rindex_list)); const struct rb_node *n;
return list_entry(sdp->sd_rindex_list.next, struct gfs2_rgrpd, rd_list); struct gfs2_rgrpd *rgd;
spin_lock(&sdp->sd_rindex_spin);
n = rb_first(&sdp->sd_rindex_tree);
rgd = rb_entry(n, struct gfs2_rgrpd, rd_node);
spin_unlock(&sdp->sd_rindex_spin);
return rgd;
} }
/** /**
...@@ -367,47 +379,60 @@ struct gfs2_rgrpd *gfs2_rgrpd_get_first(struct gfs2_sbd *sdp) ...@@ -367,47 +379,60 @@ struct gfs2_rgrpd *gfs2_rgrpd_get_first(struct gfs2_sbd *sdp)
struct gfs2_rgrpd *gfs2_rgrpd_get_next(struct gfs2_rgrpd *rgd) struct gfs2_rgrpd *gfs2_rgrpd_get_next(struct gfs2_rgrpd *rgd)
{ {
if (rgd->rd_list.next == &rgd->rd_sbd->sd_rindex_list) struct gfs2_sbd *sdp = rgd->rd_sbd;
const struct rb_node *n;
spin_lock(&sdp->sd_rindex_spin);
n = rb_next(&rgd->rd_node);
if (n == NULL)
n = rb_first(&sdp->sd_rindex_tree);
if (unlikely(&rgd->rd_node == n)) {
spin_unlock(&sdp->sd_rindex_spin);
return NULL; return NULL;
return list_entry(rgd->rd_list.next, struct gfs2_rgrpd, rd_list); }
rgd = rb_entry(n, struct gfs2_rgrpd, rd_node);
spin_unlock(&sdp->sd_rindex_spin);
return rgd;
} }
static void clear_rgrpdi(struct gfs2_sbd *sdp) void gfs2_free_clones(struct gfs2_rgrpd *rgd)
{ {
struct list_head *head; int x;
for (x = 0; x < rgd->rd_length; x++) {
struct gfs2_bitmap *bi = rgd->rd_bits + x;
kfree(bi->bi_clone);
bi->bi_clone = NULL;
}
}
void gfs2_clear_rgrpd(struct gfs2_sbd *sdp)
{
struct rb_node *n;
struct gfs2_rgrpd *rgd; struct gfs2_rgrpd *rgd;
struct gfs2_glock *gl; struct gfs2_glock *gl;
spin_lock(&sdp->sd_rindex_spin); while ((n = rb_first(&sdp->sd_rindex_tree))) {
sdp->sd_rindex_forward = NULL; rgd = rb_entry(n, struct gfs2_rgrpd, rd_node);
spin_unlock(&sdp->sd_rindex_spin);
head = &sdp->sd_rindex_list;
while (!list_empty(head)) {
rgd = list_entry(head->next, struct gfs2_rgrpd, rd_list);
gl = rgd->rd_gl; gl = rgd->rd_gl;
list_del(&rgd->rd_list); rb_erase(n, &sdp->sd_rindex_tree);
list_del(&rgd->rd_list_mru);
if (gl) { if (gl) {
spin_lock(&gl->gl_spin);
gl->gl_object = NULL; gl->gl_object = NULL;
spin_unlock(&gl->gl_spin);
gfs2_glock_add_to_lru(gl); gfs2_glock_add_to_lru(gl);
gfs2_glock_put(gl); gfs2_glock_put(gl);
} }
gfs2_free_clones(rgd);
kfree(rgd->rd_bits); kfree(rgd->rd_bits);
kmem_cache_free(gfs2_rgrpd_cachep, rgd); kmem_cache_free(gfs2_rgrpd_cachep, rgd);
} }
} }
void gfs2_clear_rgrpd(struct gfs2_sbd *sdp)
{
mutex_lock(&sdp->sd_rindex_mutex);
clear_rgrpdi(sdp);
mutex_unlock(&sdp->sd_rindex_mutex);
}
static void gfs2_rindex_print(const struct gfs2_rgrpd *rgd) static void gfs2_rindex_print(const struct gfs2_rgrpd *rgd)
{ {
printk(KERN_INFO " ri_addr = %llu\n", (unsigned long long)rgd->rd_addr); printk(KERN_INFO " ri_addr = %llu\n", (unsigned long long)rgd->rd_addr);
...@@ -524,22 +549,34 @@ u64 gfs2_ri_total(struct gfs2_sbd *sdp) ...@@ -524,22 +549,34 @@ u64 gfs2_ri_total(struct gfs2_sbd *sdp)
return total_data; return total_data;
} }
static void gfs2_rindex_in(struct gfs2_rgrpd *rgd, const void *buf) static void rgd_insert(struct gfs2_rgrpd *rgd)
{ {
const struct gfs2_rindex *str = buf; struct gfs2_sbd *sdp = rgd->rd_sbd;
struct rb_node **newn = &sdp->sd_rindex_tree.rb_node, *parent = NULL;
/* Figure out where to put new node */
while (*newn) {
struct gfs2_rgrpd *cur = rb_entry(*newn, struct gfs2_rgrpd,
rd_node);
parent = *newn;
if (rgd->rd_addr < cur->rd_addr)
newn = &((*newn)->rb_left);
else if (rgd->rd_addr > cur->rd_addr)
newn = &((*newn)->rb_right);
else
return;
}
rgd->rd_addr = be64_to_cpu(str->ri_addr); rb_link_node(&rgd->rd_node, parent, newn);
rgd->rd_length = be32_to_cpu(str->ri_length); rb_insert_color(&rgd->rd_node, &sdp->sd_rindex_tree);
rgd->rd_data0 = be64_to_cpu(str->ri_data0);
rgd->rd_data = be32_to_cpu(str->ri_data);
rgd->rd_bitbytes = be32_to_cpu(str->ri_bitbytes);
} }
/** /**
* read_rindex_entry - Pull in a new resource index entry from the disk * read_rindex_entry - Pull in a new resource index entry from the disk
* @gl: The glock covering the rindex inode * @gl: The glock covering the rindex inode
* *
* Returns: 0 on success, error code otherwise * Returns: 0 on success, > 0 on EOF, error code otherwise
*/ */
static int read_rindex_entry(struct gfs2_inode *ip, static int read_rindex_entry(struct gfs2_inode *ip,
...@@ -547,44 +584,53 @@ static int read_rindex_entry(struct gfs2_inode *ip, ...@@ -547,44 +584,53 @@ static int read_rindex_entry(struct gfs2_inode *ip,
{ {
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
loff_t pos = sdp->sd_rgrps * sizeof(struct gfs2_rindex); loff_t pos = sdp->sd_rgrps * sizeof(struct gfs2_rindex);
char buf[sizeof(struct gfs2_rindex)]; struct gfs2_rindex buf;
int error; int error;
struct gfs2_rgrpd *rgd; struct gfs2_rgrpd *rgd;
error = gfs2_internal_read(ip, ra_state, buf, &pos, if (pos >= i_size_read(&ip->i_inode))
return 1;
error = gfs2_internal_read(ip, ra_state, (char *)&buf, &pos,
sizeof(struct gfs2_rindex)); sizeof(struct gfs2_rindex));
if (!error)
return 0; if (error != sizeof(struct gfs2_rindex))
if (error != sizeof(struct gfs2_rindex)) { return (error == 0) ? 1 : error;
if (error > 0)
error = -EIO;
return error;
}
rgd = kmem_cache_zalloc(gfs2_rgrpd_cachep, GFP_NOFS); rgd = kmem_cache_zalloc(gfs2_rgrpd_cachep, GFP_NOFS);
error = -ENOMEM; error = -ENOMEM;
if (!rgd) if (!rgd)
return error; return error;
mutex_init(&rgd->rd_mutex);
lops_init_le(&rgd->rd_le, &gfs2_rg_lops);
rgd->rd_sbd = sdp; rgd->rd_sbd = sdp;
rgd->rd_addr = be64_to_cpu(buf.ri_addr);
rgd->rd_length = be32_to_cpu(buf.ri_length);
rgd->rd_data0 = be64_to_cpu(buf.ri_data0);
rgd->rd_data = be32_to_cpu(buf.ri_data);
rgd->rd_bitbytes = be32_to_cpu(buf.ri_bitbytes);
list_add_tail(&rgd->rd_list, &sdp->sd_rindex_list);
list_add_tail(&rgd->rd_list_mru, &sdp->sd_rindex_mru_list);
gfs2_rindex_in(rgd, buf);
error = compute_bitstructs(rgd); error = compute_bitstructs(rgd);
if (error) if (error)
return error; goto fail;
error = gfs2_glock_get(sdp, rgd->rd_addr, error = gfs2_glock_get(sdp, rgd->rd_addr,
&gfs2_rgrp_glops, CREATE, &rgd->rd_gl); &gfs2_rgrp_glops, CREATE, &rgd->rd_gl);
if (error) if (error)
return error; goto fail;
rgd->rd_gl->gl_object = rgd; rgd->rd_gl->gl_object = rgd;
rgd->rd_flags &= ~GFS2_RDF_UPTODATE; rgd->rd_flags &= ~GFS2_RDF_UPTODATE;
if (rgd->rd_data > sdp->sd_max_rg_data)
sdp->sd_max_rg_data = rgd->rd_data;
spin_lock(&sdp->sd_rindex_spin);
rgd_insert(rgd);
sdp->sd_rgrps++;
spin_unlock(&sdp->sd_rindex_spin);
return error;
fail:
kfree(rgd->rd_bits);
kmem_cache_free(gfs2_rgrpd_cachep, rgd);
return error; return error;
} }
...@@ -595,40 +641,28 @@ static int read_rindex_entry(struct gfs2_inode *ip, ...@@ -595,40 +641,28 @@ static int read_rindex_entry(struct gfs2_inode *ip,
* Returns: 0 on successful update, error code otherwise * Returns: 0 on successful update, error code otherwise
*/ */
int gfs2_ri_update(struct gfs2_inode *ip) static int gfs2_ri_update(struct gfs2_inode *ip)
{ {
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct inode *inode = &ip->i_inode; struct inode *inode = &ip->i_inode;
struct file_ra_state ra_state; struct file_ra_state ra_state;
u64 rgrp_count = i_size_read(inode);
struct gfs2_rgrpd *rgd;
unsigned int max_data = 0;
int error; int error;
do_div(rgrp_count, sizeof(struct gfs2_rindex));
clear_rgrpdi(sdp);
file_ra_state_init(&ra_state, inode->i_mapping); file_ra_state_init(&ra_state, inode->i_mapping);
for (sdp->sd_rgrps = 0; sdp->sd_rgrps < rgrp_count; sdp->sd_rgrps++) { do {
error = read_rindex_entry(ip, &ra_state); error = read_rindex_entry(ip, &ra_state);
if (error) { } while (error == 0);
clear_rgrpdi(sdp);
return error; if (error < 0)
} return error;
}
list_for_each_entry(rgd, &sdp->sd_rindex_list, rd_list)
if (rgd->rd_data > max_data)
max_data = rgd->rd_data;
sdp->sd_max_rg_data = max_data;
sdp->sd_rindex_uptodate = 1; sdp->sd_rindex_uptodate = 1;
return 0; return 0;
} }
/** /**
* gfs2_rindex_hold - Grab a lock on the rindex * gfs2_rindex_update - Update the rindex if required
* @sdp: The GFS2 superblock * @sdp: The GFS2 superblock
* @ri_gh: the glock holder
* *
* We grab a lock on the rindex inode to make sure that it doesn't * We grab a lock on the rindex inode to make sure that it doesn't
* change whilst we are performing an operation. We keep this lock * change whilst we are performing an operation. We keep this lock
...@@ -640,30 +674,29 @@ int gfs2_ri_update(struct gfs2_inode *ip) ...@@ -640,30 +674,29 @@ int gfs2_ri_update(struct gfs2_inode *ip)
* special file, which might have been updated if someone expanded the * special file, which might have been updated if someone expanded the
* filesystem (via gfs2_grow utility), which adds new resource groups. * filesystem (via gfs2_grow utility), which adds new resource groups.
* *
* Returns: 0 on success, error code otherwise * Returns: 0 on succeess, error code otherwise
*/ */
int gfs2_rindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ri_gh) int gfs2_rindex_update(struct gfs2_sbd *sdp)
{ {
struct gfs2_inode *ip = GFS2_I(sdp->sd_rindex); struct gfs2_inode *ip = GFS2_I(sdp->sd_rindex);
struct gfs2_glock *gl = ip->i_gl; struct gfs2_glock *gl = ip->i_gl;
int error; struct gfs2_holder ri_gh;
int error = 0;
error = gfs2_glock_nq_init(gl, LM_ST_SHARED, 0, ri_gh);
if (error)
return error;
/* Read new copy from disk if we don't have the latest */ /* Read new copy from disk if we don't have the latest */
if (!sdp->sd_rindex_uptodate) { if (!sdp->sd_rindex_uptodate) {
mutex_lock(&sdp->sd_rindex_mutex); mutex_lock(&sdp->sd_rindex_mutex);
if (!sdp->sd_rindex_uptodate) { error = gfs2_glock_nq_init(gl, LM_ST_SHARED, 0, &ri_gh);
if (error)
return error;
if (!sdp->sd_rindex_uptodate)
error = gfs2_ri_update(ip); error = gfs2_ri_update(ip);
if (error) gfs2_glock_dq_uninit(&ri_gh);
gfs2_glock_dq_uninit(ri_gh);
}
mutex_unlock(&sdp->sd_rindex_mutex); mutex_unlock(&sdp->sd_rindex_mutex);
} }
return error; return error;
} }
...@@ -694,7 +727,7 @@ static void gfs2_rgrp_out(struct gfs2_rgrpd *rgd, void *buf) ...@@ -694,7 +727,7 @@ static void gfs2_rgrp_out(struct gfs2_rgrpd *rgd, void *buf)
} }
/** /**
* gfs2_rgrp_bh_get - Read in a RG's header and bitmaps * gfs2_rgrp_go_lock - Read in a RG's header and bitmaps
* @rgd: the struct gfs2_rgrpd describing the RG to read in * @rgd: the struct gfs2_rgrpd describing the RG to read in
* *
* Read in all of a Resource Group's header and bitmap blocks. * Read in all of a Resource Group's header and bitmap blocks.
...@@ -703,8 +736,9 @@ static void gfs2_rgrp_out(struct gfs2_rgrpd *rgd, void *buf) ...@@ -703,8 +736,9 @@ static void gfs2_rgrp_out(struct gfs2_rgrpd *rgd, void *buf)
* Returns: errno * Returns: errno
*/ */
int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd) int gfs2_rgrp_go_lock(struct gfs2_holder *gh)
{ {
struct gfs2_rgrpd *rgd = gh->gh_gl->gl_object;
struct gfs2_sbd *sdp = rgd->rd_sbd; struct gfs2_sbd *sdp = rgd->rd_sbd;
struct gfs2_glock *gl = rgd->rd_gl; struct gfs2_glock *gl = rgd->rd_gl;
unsigned int length = rgd->rd_length; unsigned int length = rgd->rd_length;
...@@ -712,17 +746,6 @@ int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd) ...@@ -712,17 +746,6 @@ int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd)
unsigned int x, y; unsigned int x, y;
int error; int error;
mutex_lock(&rgd->rd_mutex);
spin_lock(&sdp->sd_rindex_spin);
if (rgd->rd_bh_count) {
rgd->rd_bh_count++;
spin_unlock(&sdp->sd_rindex_spin);
mutex_unlock(&rgd->rd_mutex);
return 0;
}
spin_unlock(&sdp->sd_rindex_spin);
for (x = 0; x < length; x++) { for (x = 0; x < length; x++) {
bi = rgd->rd_bits + x; bi = rgd->rd_bits + x;
error = gfs2_meta_read(gl, rgd->rd_addr + x, 0, &bi->bi_bh); error = gfs2_meta_read(gl, rgd->rd_addr + x, 0, &bi->bi_bh);
...@@ -747,15 +770,9 @@ int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd) ...@@ -747,15 +770,9 @@ int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd)
clear_bit(GBF_FULL, &rgd->rd_bits[x].bi_flags); clear_bit(GBF_FULL, &rgd->rd_bits[x].bi_flags);
gfs2_rgrp_in(rgd, (rgd->rd_bits[0].bi_bh)->b_data); gfs2_rgrp_in(rgd, (rgd->rd_bits[0].bi_bh)->b_data);
rgd->rd_flags |= (GFS2_RDF_UPTODATE | GFS2_RDF_CHECK); rgd->rd_flags |= (GFS2_RDF_UPTODATE | GFS2_RDF_CHECK);
rgd->rd_free_clone = rgd->rd_free;
} }
spin_lock(&sdp->sd_rindex_spin);
rgd->rd_free_clone = rgd->rd_free;
rgd->rd_bh_count++;
spin_unlock(&sdp->sd_rindex_spin);
mutex_unlock(&rgd->rd_mutex);
return 0; return 0;
fail: fail:
...@@ -765,52 +782,32 @@ int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd) ...@@ -765,52 +782,32 @@ int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd)
bi->bi_bh = NULL; bi->bi_bh = NULL;
gfs2_assert_warn(sdp, !bi->bi_clone); gfs2_assert_warn(sdp, !bi->bi_clone);
} }
mutex_unlock(&rgd->rd_mutex);
return error; return error;
} }
void gfs2_rgrp_bh_hold(struct gfs2_rgrpd *rgd)
{
struct gfs2_sbd *sdp = rgd->rd_sbd;
spin_lock(&sdp->sd_rindex_spin);
gfs2_assert_warn(rgd->rd_sbd, rgd->rd_bh_count);
rgd->rd_bh_count++;
spin_unlock(&sdp->sd_rindex_spin);
}
/** /**
* gfs2_rgrp_bh_put - Release RG bitmaps read in with gfs2_rgrp_bh_get() * gfs2_rgrp_go_unlock - Release RG bitmaps read in with gfs2_rgrp_bh_get()
* @rgd: the struct gfs2_rgrpd describing the RG to read in * @rgd: the struct gfs2_rgrpd describing the RG to read in
* *
*/ */
void gfs2_rgrp_bh_put(struct gfs2_rgrpd *rgd) void gfs2_rgrp_go_unlock(struct gfs2_holder *gh)
{ {
struct gfs2_sbd *sdp = rgd->rd_sbd; struct gfs2_rgrpd *rgd = gh->gh_gl->gl_object;
int x, length = rgd->rd_length; int x, length = rgd->rd_length;
spin_lock(&sdp->sd_rindex_spin);
gfs2_assert_warn(rgd->rd_sbd, rgd->rd_bh_count);
if (--rgd->rd_bh_count) {
spin_unlock(&sdp->sd_rindex_spin);
return;
}
for (x = 0; x < length; x++) { for (x = 0; x < length; x++) {
struct gfs2_bitmap *bi = rgd->rd_bits + x; struct gfs2_bitmap *bi = rgd->rd_bits + x;
kfree(bi->bi_clone);
bi->bi_clone = NULL;
brelse(bi->bi_bh); brelse(bi->bi_bh);
bi->bi_bh = NULL; bi->bi_bh = NULL;
} }
spin_unlock(&sdp->sd_rindex_spin);
} }
static void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset, void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
const struct gfs2_bitmap *bi) struct buffer_head *bh,
const struct gfs2_bitmap *bi)
{ {
struct super_block *sb = sdp->sd_vfs; struct super_block *sb = sdp->sd_vfs;
struct block_device *bdev = sb->s_bdev; struct block_device *bdev = sb->s_bdev;
...@@ -823,7 +820,7 @@ static void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset, ...@@ -823,7 +820,7 @@ static void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
unsigned int x; unsigned int x;
for (x = 0; x < bi->bi_len; x++) { for (x = 0; x < bi->bi_len; x++) {
const u8 *orig = bi->bi_bh->b_data + bi->bi_offset + x; const u8 *orig = bh->b_data + bi->bi_offset + x;
const u8 *clone = bi->bi_clone + bi->bi_offset + x; const u8 *clone = bi->bi_clone + bi->bi_offset + x;
u8 diff = ~(*orig | (*orig >> 1)) & (*clone | (*clone >> 1)); u8 diff = ~(*orig | (*orig >> 1)) & (*clone | (*clone >> 1));
diff &= 0x55; diff &= 0x55;
...@@ -862,28 +859,6 @@ static void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset, ...@@ -862,28 +859,6 @@ static void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
sdp->sd_args.ar_discard = 0; sdp->sd_args.ar_discard = 0;
} }
void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd)
{
struct gfs2_sbd *sdp = rgd->rd_sbd;
unsigned int length = rgd->rd_length;
unsigned int x;
for (x = 0; x < length; x++) {
struct gfs2_bitmap *bi = rgd->rd_bits + x;
if (!bi->bi_clone)
continue;
if (sdp->sd_args.ar_discard)
gfs2_rgrp_send_discards(sdp, rgd->rd_data0, bi);
clear_bit(GBF_FULL, &bi->bi_flags);
memcpy(bi->bi_clone + bi->bi_offset,
bi->bi_bh->b_data + bi->bi_offset, bi->bi_len);
}
spin_lock(&sdp->sd_rindex_spin);
rgd->rd_free_clone = rgd->rd_free;
spin_unlock(&sdp->sd_rindex_spin);
}
/** /**
* gfs2_alloc_get - get the struct gfs2_alloc structure for an inode * gfs2_alloc_get - get the struct gfs2_alloc structure for an inode
* @ip: the incore GFS2 inode structure * @ip: the incore GFS2 inode structure
...@@ -893,38 +868,35 @@ void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd) ...@@ -893,38 +868,35 @@ void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd)
struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip) struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip)
{ {
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
int error;
BUG_ON(ip->i_alloc != NULL); BUG_ON(ip->i_alloc != NULL);
ip->i_alloc = kzalloc(sizeof(struct gfs2_alloc), GFP_NOFS); ip->i_alloc = kzalloc(sizeof(struct gfs2_alloc), GFP_NOFS);
error = gfs2_rindex_update(sdp);
if (error)
fs_warn(sdp, "rindex update returns %d\n", error);
return ip->i_alloc; return ip->i_alloc;
} }
/** /**
* try_rgrp_fit - See if a given reservation will fit in a given RG * try_rgrp_fit - See if a given reservation will fit in a given RG
* @rgd: the RG data * @rgd: the RG data
* @al: the struct gfs2_alloc structure describing the reservation * @ip: the inode
* *
* If there's room for the requested blocks to be allocated from the RG: * If there's room for the requested blocks to be allocated from the RG:
* Sets the $al_rgd field in @al.
* *
* Returns: 1 on success (it fits), 0 on failure (it doesn't fit) * Returns: 1 on success (it fits), 0 on failure (it doesn't fit)
*/ */
static int try_rgrp_fit(struct gfs2_rgrpd *rgd, struct gfs2_alloc *al) static int try_rgrp_fit(const struct gfs2_rgrpd *rgd, const struct gfs2_inode *ip)
{ {
struct gfs2_sbd *sdp = rgd->rd_sbd; const struct gfs2_alloc *al = ip->i_alloc;
int ret = 0;
if (rgd->rd_flags & (GFS2_RGF_NOALLOC | GFS2_RDF_ERROR)) if (rgd->rd_flags & (GFS2_RGF_NOALLOC | GFS2_RDF_ERROR))
return 0; return 0;
if (rgd->rd_free_clone >= al->al_requested)
spin_lock(&sdp->sd_rindex_spin); return 1;
if (rgd->rd_free_clone >= al->al_requested) { return 0;
al->al_rgd = rgd;
ret = 1;
}
spin_unlock(&sdp->sd_rindex_spin);
return ret;
} }
/** /**
...@@ -991,76 +963,6 @@ static void try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked, u64 skip ...@@ -991,76 +963,6 @@ static void try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked, u64 skip
return; return;
} }
/**
* recent_rgrp_next - get next RG from "recent" list
* @cur_rgd: current rgrp
*
* Returns: The next rgrp in the recent list
*/
static struct gfs2_rgrpd *recent_rgrp_next(struct gfs2_rgrpd *cur_rgd)
{
struct gfs2_sbd *sdp = cur_rgd->rd_sbd;
struct list_head *head;
struct gfs2_rgrpd *rgd;
spin_lock(&sdp->sd_rindex_spin);
head = &sdp->sd_rindex_mru_list;
if (unlikely(cur_rgd->rd_list_mru.next == head)) {
spin_unlock(&sdp->sd_rindex_spin);
return NULL;
}
rgd = list_entry(cur_rgd->rd_list_mru.next, struct gfs2_rgrpd, rd_list_mru);
spin_unlock(&sdp->sd_rindex_spin);
return rgd;
}
/**
* forward_rgrp_get - get an rgrp to try next from full list
* @sdp: The GFS2 superblock
*
* Returns: The rgrp to try next
*/
static struct gfs2_rgrpd *forward_rgrp_get(struct gfs2_sbd *sdp)
{
struct gfs2_rgrpd *rgd;
unsigned int journals = gfs2_jindex_size(sdp);
unsigned int rg = 0, x;
spin_lock(&sdp->sd_rindex_spin);
rgd = sdp->sd_rindex_forward;
if (!rgd) {
if (sdp->sd_rgrps >= journals)
rg = sdp->sd_rgrps * sdp->sd_jdesc->jd_jid / journals;
for (x = 0, rgd = gfs2_rgrpd_get_first(sdp); x < rg;
x++, rgd = gfs2_rgrpd_get_next(rgd))
/* Do Nothing */;
sdp->sd_rindex_forward = rgd;
}
spin_unlock(&sdp->sd_rindex_spin);
return rgd;
}
/**
* forward_rgrp_set - set the forward rgrp pointer
* @sdp: the filesystem
* @rgd: The new forward rgrp
*
*/
static void forward_rgrp_set(struct gfs2_sbd *sdp, struct gfs2_rgrpd *rgd)
{
spin_lock(&sdp->sd_rindex_spin);
sdp->sd_rindex_forward = rgd;
spin_unlock(&sdp->sd_rindex_spin);
}
/** /**
* get_local_rgrp - Choose and lock a rgrp for allocation * get_local_rgrp - Choose and lock a rgrp for allocation
* @ip: the inode to reserve space for * @ip: the inode to reserve space for
...@@ -1076,14 +978,18 @@ static int get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked) ...@@ -1076,14 +978,18 @@ static int get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked)
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_rgrpd *rgd, *begin = NULL; struct gfs2_rgrpd *rgd, *begin = NULL;
struct gfs2_alloc *al = ip->i_alloc; struct gfs2_alloc *al = ip->i_alloc;
int flags = LM_FLAG_TRY;
int skipped = 0;
int loops = 0;
int error, rg_locked; int error, rg_locked;
int loops = 0;
if (ip->i_rgd && rgrp_contains_block(ip->i_rgd, ip->i_goal))
rgd = begin = ip->i_rgd;
else
rgd = begin = gfs2_blk2rgrpd(sdp, ip->i_goal);
rgd = gfs2_blk2rgrpd(sdp, ip->i_goal); if (rgd == NULL)
return -EBADSLT;
while (rgd) { while (loops < 3) {
rg_locked = 0; rg_locked = 0;
if (gfs2_glock_is_locked_by_me(rgd->rd_gl)) { if (gfs2_glock_is_locked_by_me(rgd->rd_gl)) {
...@@ -1095,92 +1001,36 @@ static int get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked) ...@@ -1095,92 +1001,36 @@ static int get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked)
} }
switch (error) { switch (error) {
case 0: case 0:
if (try_rgrp_fit(rgd, al)) if (try_rgrp_fit(rgd, ip)) {
goto out; ip->i_rgd = rgd;
return 0;
}
if (rgd->rd_flags & GFS2_RDF_CHECK) if (rgd->rd_flags & GFS2_RDF_CHECK)
try_rgrp_unlink(rgd, last_unlinked, ip->i_no_addr); try_rgrp_unlink(rgd, last_unlinked, ip->i_no_addr);
if (!rg_locked) if (!rg_locked)
gfs2_glock_dq_uninit(&al->al_rgd_gh); gfs2_glock_dq_uninit(&al->al_rgd_gh);
/* fall through */ /* fall through */
case GLR_TRYFAILED: case GLR_TRYFAILED:
rgd = recent_rgrp_next(rgd); rgd = gfs2_rgrpd_get_next(rgd);
break; if (rgd == begin)
loops++;
default:
return error;
}
}
/* Go through full list of rgrps */
begin = rgd = forward_rgrp_get(sdp);
for (;;) {
rg_locked = 0;
if (gfs2_glock_is_locked_by_me(rgd->rd_gl)) {
rg_locked = 1;
error = 0;
} else {
error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, flags,
&al->al_rgd_gh);
}
switch (error) {
case 0:
if (try_rgrp_fit(rgd, al))
goto out;
if (rgd->rd_flags & GFS2_RDF_CHECK)
try_rgrp_unlink(rgd, last_unlinked, ip->i_no_addr);
if (!rg_locked)
gfs2_glock_dq_uninit(&al->al_rgd_gh);
break;
case GLR_TRYFAILED:
skipped++;
break; break;
default: default:
return error; return error;
} }
rgd = gfs2_rgrpd_get_next(rgd);
if (!rgd)
rgd = gfs2_rgrpd_get_first(sdp);
if (rgd == begin) {
if (++loops >= 3)
return -ENOSPC;
if (!skipped)
loops++;
flags = 0;
if (loops == 2)
gfs2_log_flush(sdp, NULL);
}
} }
out: return -ENOSPC;
if (begin) {
spin_lock(&sdp->sd_rindex_spin);
list_move(&rgd->rd_list_mru, &sdp->sd_rindex_mru_list);
spin_unlock(&sdp->sd_rindex_spin);
rgd = gfs2_rgrpd_get_next(rgd);
if (!rgd)
rgd = gfs2_rgrpd_get_first(sdp);
forward_rgrp_set(sdp, rgd);
}
return 0;
} }
/** /**
* gfs2_inplace_reserve_i - Reserve space in the filesystem * gfs2_inplace_reserve - Reserve space in the filesystem
* @ip: the inode to reserve space for * @ip: the inode to reserve space for
* *
* Returns: errno * Returns: errno
*/ */
int gfs2_inplace_reserve_i(struct gfs2_inode *ip, int hold_rindex, int gfs2_inplace_reserve(struct gfs2_inode *ip)
char *file, unsigned int line)
{ {
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_alloc *al = ip->i_alloc; struct gfs2_alloc *al = ip->i_alloc;
...@@ -1191,45 +1041,22 @@ int gfs2_inplace_reserve_i(struct gfs2_inode *ip, int hold_rindex, ...@@ -1191,45 +1041,22 @@ int gfs2_inplace_reserve_i(struct gfs2_inode *ip, int hold_rindex,
if (gfs2_assert_warn(sdp, al->al_requested)) if (gfs2_assert_warn(sdp, al->al_requested))
return -EINVAL; return -EINVAL;
if (hold_rindex) {
/* We need to hold the rindex unless the inode we're using is
the rindex itself, in which case it's already held. */
if (ip != GFS2_I(sdp->sd_rindex))
error = gfs2_rindex_hold(sdp, &al->al_ri_gh);
else if (!sdp->sd_rgrps) /* We may not have the rindex read
in, so: */
error = gfs2_ri_update(ip);
if (error)
return error;
}
try_again:
do { do {
error = get_local_rgrp(ip, &last_unlinked); error = get_local_rgrp(ip, &last_unlinked);
/* If there is no space, flushing the log may release some */ if (error != -ENOSPC)
if (error) { break;
if (ip == GFS2_I(sdp->sd_rindex) && /* Check that fs hasn't grown if writing to rindex */
!sdp->sd_rindex_uptodate) { if (ip == GFS2_I(sdp->sd_rindex) && !sdp->sd_rindex_uptodate) {
error = gfs2_ri_update(ip); error = gfs2_ri_update(ip);
if (error) if (error)
return error; break;
goto try_again; continue;
}
gfs2_log_flush(sdp, NULL);
} }
} while (error && tries++ < 3); /* Flushing the log may release space */
gfs2_log_flush(sdp, NULL);
if (error) { } while (tries++ < 3);
if (hold_rindex && ip != GFS2_I(sdp->sd_rindex))
gfs2_glock_dq_uninit(&al->al_ri_gh);
return error;
}
/* no error, so we have the rgrp set in the inode's allocation. */
al->al_file = file;
al->al_line = line;
return 0; return error;
} }
/** /**
...@@ -1241,20 +1068,10 @@ int gfs2_inplace_reserve_i(struct gfs2_inode *ip, int hold_rindex, ...@@ -1241,20 +1068,10 @@ int gfs2_inplace_reserve_i(struct gfs2_inode *ip, int hold_rindex,
void gfs2_inplace_release(struct gfs2_inode *ip) void gfs2_inplace_release(struct gfs2_inode *ip)
{ {
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_alloc *al = ip->i_alloc; struct gfs2_alloc *al = ip->i_alloc;
if (gfs2_assert_warn(sdp, al->al_alloced <= al->al_requested) == -1)
fs_warn(sdp, "al_alloced = %u, al_requested = %u "
"al_file = %s, al_line = %u\n",
al->al_alloced, al->al_requested, al->al_file,
al->al_line);
al->al_rgd = NULL;
if (al->al_rgd_gh.gh_gl) if (al->al_rgd_gh.gh_gl)
gfs2_glock_dq_uninit(&al->al_rgd_gh); gfs2_glock_dq_uninit(&al->al_rgd_gh);
if (ip != GFS2_I(sdp->sd_rindex) && al->al_ri_gh.gh_gl)
gfs2_glock_dq_uninit(&al->al_ri_gh);
} }
/** /**
...@@ -1352,6 +1169,7 @@ static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal, ...@@ -1352,6 +1169,7 @@ static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal,
/* The GFS2_BLKST_UNLINKED state doesn't apply to the clone /* The GFS2_BLKST_UNLINKED state doesn't apply to the clone
bitmaps, so we must search the originals for that. */ bitmaps, so we must search the originals for that. */
buffer = bi->bi_bh->b_data + bi->bi_offset; buffer = bi->bi_bh->b_data + bi->bi_offset;
WARN_ON(!buffer_uptodate(bi->bi_bh));
if (old_state != GFS2_BLKST_UNLINKED && bi->bi_clone) if (old_state != GFS2_BLKST_UNLINKED && bi->bi_clone)
buffer = bi->bi_clone + bi->bi_offset; buffer = bi->bi_clone + bi->bi_offset;
...@@ -1371,6 +1189,7 @@ static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal, ...@@ -1371,6 +1189,7 @@ static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal,
if (blk == BFITNOENT) if (blk == BFITNOENT)
return blk; return blk;
*n = 1; *n = 1;
if (old_state == new_state) if (old_state == new_state)
goto out; goto out;
...@@ -1503,7 +1322,7 @@ int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n) ...@@ -1503,7 +1322,7 @@ int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n)
if (al == NULL) if (al == NULL)
return -ECANCELED; return -ECANCELED;
rgd = al->al_rgd; rgd = ip->i_rgd;
if (rgrp_contains_block(rgd, ip->i_goal)) if (rgrp_contains_block(rgd, ip->i_goal))
goal = ip->i_goal - rgd->rd_data0; goal = ip->i_goal - rgd->rd_data0;
...@@ -1518,7 +1337,7 @@ int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n) ...@@ -1518,7 +1337,7 @@ int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n)
rgd->rd_last_alloc = blk; rgd->rd_last_alloc = blk;
block = rgd->rd_data0 + blk; block = rgd->rd_data0 + blk;
ip->i_goal = block; ip->i_goal = block + *n - 1;
error = gfs2_meta_inode_buffer(ip, &dibh); error = gfs2_meta_inode_buffer(ip, &dibh);
if (error == 0) { if (error == 0) {
struct gfs2_dinode *di = (struct gfs2_dinode *)dibh->b_data; struct gfs2_dinode *di = (struct gfs2_dinode *)dibh->b_data;
...@@ -1539,9 +1358,7 @@ int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n) ...@@ -1539,9 +1358,7 @@ int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n)
gfs2_statfs_change(sdp, 0, -(s64)*n, 0); gfs2_statfs_change(sdp, 0, -(s64)*n, 0);
gfs2_quota_change(ip, *n, ip->i_inode.i_uid, ip->i_inode.i_gid); gfs2_quota_change(ip, *n, ip->i_inode.i_uid, ip->i_inode.i_gid);
spin_lock(&sdp->sd_rindex_spin);
rgd->rd_free_clone -= *n; rgd->rd_free_clone -= *n;
spin_unlock(&sdp->sd_rindex_spin);
trace_gfs2_block_alloc(ip, block, *n, GFS2_BLKST_USED); trace_gfs2_block_alloc(ip, block, *n, GFS2_BLKST_USED);
*bn = block; *bn = block;
return 0; return 0;
...@@ -1564,7 +1381,7 @@ int gfs2_alloc_di(struct gfs2_inode *dip, u64 *bn, u64 *generation) ...@@ -1564,7 +1381,7 @@ int gfs2_alloc_di(struct gfs2_inode *dip, u64 *bn, u64 *generation)
{ {
struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
struct gfs2_alloc *al = dip->i_alloc; struct gfs2_alloc *al = dip->i_alloc;
struct gfs2_rgrpd *rgd = al->al_rgd; struct gfs2_rgrpd *rgd = dip->i_rgd;
u32 blk; u32 blk;
u64 block; u64 block;
unsigned int n = 1; unsigned int n = 1;
...@@ -1594,9 +1411,7 @@ int gfs2_alloc_di(struct gfs2_inode *dip, u64 *bn, u64 *generation) ...@@ -1594,9 +1411,7 @@ int gfs2_alloc_di(struct gfs2_inode *dip, u64 *bn, u64 *generation)
gfs2_statfs_change(sdp, 0, -1, +1); gfs2_statfs_change(sdp, 0, -1, +1);
gfs2_trans_add_unrevoke(sdp, block, 1); gfs2_trans_add_unrevoke(sdp, block, 1);
spin_lock(&sdp->sd_rindex_spin);
rgd->rd_free_clone--; rgd->rd_free_clone--;
spin_unlock(&sdp->sd_rindex_spin);
trace_gfs2_block_alloc(dip, block, 1, GFS2_BLKST_DINODE); trace_gfs2_block_alloc(dip, block, 1, GFS2_BLKST_DINODE);
*bn = block; *bn = block;
return 0; return 0;
...@@ -1629,8 +1444,6 @@ void __gfs2_free_blocks(struct gfs2_inode *ip, u64 bstart, u32 blen, int meta) ...@@ -1629,8 +1444,6 @@ void __gfs2_free_blocks(struct gfs2_inode *ip, u64 bstart, u32 blen, int meta)
gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1); gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data); gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data);
gfs2_trans_add_rg(rgd);
/* Directories keep their data in the metadata address space */ /* Directories keep their data in the metadata address space */
if (meta || ip->i_depth) if (meta || ip->i_depth)
gfs2_meta_wipe(ip, bstart, blen); gfs2_meta_wipe(ip, bstart, blen);
...@@ -1666,7 +1479,6 @@ void gfs2_unlink_di(struct inode *inode) ...@@ -1666,7 +1479,6 @@ void gfs2_unlink_di(struct inode *inode)
trace_gfs2_block_alloc(ip, blkno, 1, GFS2_BLKST_UNLINKED); trace_gfs2_block_alloc(ip, blkno, 1, GFS2_BLKST_UNLINKED);
gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1); gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data); gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data);
gfs2_trans_add_rg(rgd);
} }
static void gfs2_free_uninit_di(struct gfs2_rgrpd *rgd, u64 blkno) static void gfs2_free_uninit_di(struct gfs2_rgrpd *rgd, u64 blkno)
...@@ -1688,7 +1500,6 @@ static void gfs2_free_uninit_di(struct gfs2_rgrpd *rgd, u64 blkno) ...@@ -1688,7 +1500,6 @@ static void gfs2_free_uninit_di(struct gfs2_rgrpd *rgd, u64 blkno)
gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data); gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data);
gfs2_statfs_change(sdp, 0, +1, -1); gfs2_statfs_change(sdp, 0, +1, -1);
gfs2_trans_add_rg(rgd);
} }
...@@ -1714,41 +1525,33 @@ void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip) ...@@ -1714,41 +1525,33 @@ void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip)
int gfs2_check_blk_type(struct gfs2_sbd *sdp, u64 no_addr, unsigned int type) int gfs2_check_blk_type(struct gfs2_sbd *sdp, u64 no_addr, unsigned int type)
{ {
struct gfs2_rgrpd *rgd; struct gfs2_rgrpd *rgd;
struct gfs2_holder ri_gh, rgd_gh; struct gfs2_holder rgd_gh;
struct gfs2_inode *ip = GFS2_I(sdp->sd_rindex);
int ri_locked = 0;
int error; int error;
if (!gfs2_glock_is_locked_by_me(ip->i_gl)) { error = gfs2_rindex_update(sdp);
error = gfs2_rindex_hold(sdp, &ri_gh); if (error)
if (error) return error;
goto fail;
ri_locked = 1;
}
error = -EINVAL; error = -EINVAL;
rgd = gfs2_blk2rgrpd(sdp, no_addr); rgd = gfs2_blk2rgrpd(sdp, no_addr);
if (!rgd) if (!rgd)
goto fail_rindex; goto fail;
error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_SHARED, 0, &rgd_gh); error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_SHARED, 0, &rgd_gh);
if (error) if (error)
goto fail_rindex; goto fail;
if (gfs2_get_block_type(rgd, no_addr) != type) if (gfs2_get_block_type(rgd, no_addr) != type)
error = -ESTALE; error = -ESTALE;
gfs2_glock_dq_uninit(&rgd_gh); gfs2_glock_dq_uninit(&rgd_gh);
fail_rindex:
if (ri_locked)
gfs2_glock_dq_uninit(&ri_gh);
fail: fail:
return error; return error;
} }
/** /**
* gfs2_rlist_add - add a RG to a list of RGs * gfs2_rlist_add - add a RG to a list of RGs
* @sdp: the filesystem * @ip: the inode
* @rlist: the list of resource groups * @rlist: the list of resource groups
* @block: the block * @block: the block
* *
...@@ -1758,9 +1561,10 @@ int gfs2_check_blk_type(struct gfs2_sbd *sdp, u64 no_addr, unsigned int type) ...@@ -1758,9 +1561,10 @@ int gfs2_check_blk_type(struct gfs2_sbd *sdp, u64 no_addr, unsigned int type)
* *
*/ */
void gfs2_rlist_add(struct gfs2_sbd *sdp, struct gfs2_rgrp_list *rlist, void gfs2_rlist_add(struct gfs2_inode *ip, struct gfs2_rgrp_list *rlist,
u64 block) u64 block)
{ {
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_rgrpd *rgd; struct gfs2_rgrpd *rgd;
struct gfs2_rgrpd **tmp; struct gfs2_rgrpd **tmp;
unsigned int new_space; unsigned int new_space;
...@@ -1769,12 +1573,15 @@ void gfs2_rlist_add(struct gfs2_sbd *sdp, struct gfs2_rgrp_list *rlist, ...@@ -1769,12 +1573,15 @@ void gfs2_rlist_add(struct gfs2_sbd *sdp, struct gfs2_rgrp_list *rlist,
if (gfs2_assert_warn(sdp, !rlist->rl_ghs)) if (gfs2_assert_warn(sdp, !rlist->rl_ghs))
return; return;
rgd = gfs2_blk2rgrpd(sdp, block); if (ip->i_rgd && rgrp_contains_block(ip->i_rgd, block))
rgd = ip->i_rgd;
else
rgd = gfs2_blk2rgrpd(sdp, block);
if (!rgd) { if (!rgd) {
if (gfs2_consist(sdp)) fs_err(sdp, "rlist_add: no rgrp for block %llu\n", (unsigned long long)block);
fs_err(sdp, "block = %llu\n", (unsigned long long)block);
return; return;
} }
ip->i_rgd = rgd;
for (x = 0; x < rlist->rl_rgrps; x++) for (x = 0; x < rlist->rl_rgrps; x++)
if (rlist->rl_rgd[x] == rgd) if (rlist->rl_rgd[x] == rgd)
......
...@@ -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