* 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 ...
This commit is contained in:
Коммит
f793f29611
|
@ -82,7 +82,7 @@ static int gfs2_set_mode(struct inode *inode, umode_t mode)
|
|||
iattr.ia_valid = ATTR_MODE;
|
||||
iattr.ia_mode = mode;
|
||||
|
||||
error = gfs2_setattr_simple(GFS2_I(inode), &iattr);
|
||||
error = gfs2_setattr_simple(inode, &iattr);
|
||||
}
|
||||
|
||||
return error;
|
||||
|
@ -160,6 +160,7 @@ out:
|
|||
|
||||
int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr)
|
||||
{
|
||||
struct inode *inode = &ip->i_inode;
|
||||
struct posix_acl *acl;
|
||||
char *data;
|
||||
unsigned int len;
|
||||
|
@ -169,7 +170,7 @@ int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr)
|
|||
if (IS_ERR(acl))
|
||||
return PTR_ERR(acl);
|
||||
if (!acl)
|
||||
return gfs2_setattr_simple(ip, attr);
|
||||
return gfs2_setattr_simple(inode, attr);
|
||||
|
||||
error = posix_acl_chmod(&acl, GFP_NOFS, attr->ia_mode);
|
||||
if (error)
|
||||
|
|
|
@ -663,7 +663,7 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,
|
|||
if (&ip->i_inode == sdp->sd_rindex)
|
||||
rblocks += 2 * RES_STATFS;
|
||||
if (alloc_required)
|
||||
rblocks += gfs2_rg_blocks(al);
|
||||
rblocks += gfs2_rg_blocks(ip);
|
||||
|
||||
error = gfs2_trans_begin(sdp, rblocks,
|
||||
PAGE_CACHE_SIZE/sdp->sd_sb.sb_bsize);
|
||||
|
@ -787,7 +787,6 @@ static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh,
|
|||
u64 to = pos + copied;
|
||||
void *kaddr;
|
||||
unsigned char *buf = dibh->b_data + sizeof(struct gfs2_dinode);
|
||||
struct gfs2_dinode *di = (struct gfs2_dinode *)dibh->b_data;
|
||||
|
||||
BUG_ON((pos + len) > (dibh->b_size - sizeof(struct gfs2_dinode)));
|
||||
kaddr = kmap_atomic(page, KM_USER0);
|
||||
|
@ -804,7 +803,6 @@ static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh,
|
|||
if (copied) {
|
||||
if (inode->i_size < to)
|
||||
i_size_write(inode, to);
|
||||
gfs2_dinode_out(ip, di);
|
||||
mark_inode_dirty(inode);
|
||||
}
|
||||
|
||||
|
@ -873,10 +871,6 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping,
|
|||
gfs2_page_add_databufs(ip, page, from, to);
|
||||
|
||||
ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata);
|
||||
if (ret > 0) {
|
||||
gfs2_dinode_out(ip, dibh->b_data);
|
||||
mark_inode_dirty(inode);
|
||||
}
|
||||
|
||||
if (inode == sdp->sd_rindex) {
|
||||
adjust_fs_space(inode);
|
||||
|
|
199
fs/gfs2/bmap.c
199
fs/gfs2/bmap.c
|
@ -10,6 +10,7 @@
|
|||
#include <linux/spinlock.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/gfs2_ondisk.h>
|
||||
#include <linux/crc32.h>
|
||||
|
||||
|
@ -36,11 +37,6 @@ struct metapath {
|
|||
__u16 mp_list[GFS2_MAX_META_HEIGHT];
|
||||
};
|
||||
|
||||
typedef int (*block_call_t) (struct gfs2_inode *ip, struct buffer_head *dibh,
|
||||
struct buffer_head *bh, __be64 *top,
|
||||
__be64 *bottom, unsigned int height,
|
||||
void *data);
|
||||
|
||||
struct strip_mine {
|
||||
int sm_first;
|
||||
unsigned int sm_height;
|
||||
|
@ -273,6 +269,30 @@ static inline __be64 *metapointer(unsigned int height, const struct metapath *mp
|
|||
return ((__be64 *)(bh->b_data + head_size)) + mp->mp_list[height];
|
||||
}
|
||||
|
||||
static void gfs2_metapath_ra(struct gfs2_glock *gl,
|
||||
const struct buffer_head *bh, const __be64 *pos)
|
||||
{
|
||||
struct buffer_head *rabh;
|
||||
const __be64 *endp = (const __be64 *)(bh->b_data + bh->b_size);
|
||||
const __be64 *t;
|
||||
|
||||
for (t = pos; t < endp; t++) {
|
||||
if (!*t)
|
||||
continue;
|
||||
|
||||
rabh = gfs2_getbuf(gl, be64_to_cpu(*t), CREATE);
|
||||
if (trylock_buffer(rabh)) {
|
||||
if (!buffer_uptodate(rabh)) {
|
||||
rabh->b_end_io = end_buffer_read_sync;
|
||||
submit_bh(READA | REQ_META, rabh);
|
||||
continue;
|
||||
}
|
||||
unlock_buffer(rabh);
|
||||
}
|
||||
brelse(rabh);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* lookup_metapath - Walk the metadata tree to a specific point
|
||||
* @ip: The inode
|
||||
|
@ -432,12 +452,14 @@ static int gfs2_bmap_alloc(struct inode *inode, const sector_t lblock,
|
|||
{
|
||||
struct gfs2_inode *ip = GFS2_I(inode);
|
||||
struct gfs2_sbd *sdp = GFS2_SB(inode);
|
||||
struct super_block *sb = sdp->sd_vfs;
|
||||
struct buffer_head *dibh = mp->mp_bh[0];
|
||||
u64 bn, dblock = 0;
|
||||
unsigned n, i, blks, alloced = 0, iblks = 0, branch_start = 0;
|
||||
unsigned dblks = 0;
|
||||
unsigned ptrs_per_blk;
|
||||
const unsigned end_of_metadata = height - 1;
|
||||
int ret;
|
||||
int eob = 0;
|
||||
enum alloc_state state;
|
||||
__be64 *ptr;
|
||||
|
@ -540,6 +562,15 @@ static int gfs2_bmap_alloc(struct inode *inode, const sector_t lblock,
|
|||
dblock = bn;
|
||||
while (n-- > 0)
|
||||
*ptr++ = cpu_to_be64(bn++);
|
||||
if (buffer_zeronew(bh_map)) {
|
||||
ret = sb_issue_zeroout(sb, dblock, dblks,
|
||||
GFP_NOFS);
|
||||
if (ret) {
|
||||
fs_err(sdp,
|
||||
"Failed to zero data buffers\n");
|
||||
clear_buffer_zeronew(bh_map);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
} while ((state != ALLOC_DATA) || !dblock);
|
||||
|
@ -667,76 +698,6 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* recursive_scan - recursively scan through the end of a file
|
||||
* @ip: the inode
|
||||
* @dibh: the dinode buffer
|
||||
* @mp: the path through the metadata to the point to start
|
||||
* @height: the height the recursion is at
|
||||
* @block: the indirect block to look at
|
||||
* @first: 1 if this is the first block
|
||||
* @bc: the call to make for each piece of metadata
|
||||
* @data: data opaque to this function to pass to @bc
|
||||
*
|
||||
* When this is first called @height and @block should be zero and
|
||||
* @first should be 1.
|
||||
*
|
||||
* Returns: errno
|
||||
*/
|
||||
|
||||
static int recursive_scan(struct gfs2_inode *ip, struct buffer_head *dibh,
|
||||
struct metapath *mp, unsigned int height,
|
||||
u64 block, int first, block_call_t bc,
|
||||
void *data)
|
||||
{
|
||||
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
|
||||
struct buffer_head *bh = NULL;
|
||||
__be64 *top, *bottom;
|
||||
u64 bn;
|
||||
int error;
|
||||
int mh_size = sizeof(struct gfs2_meta_header);
|
||||
|
||||
if (!height) {
|
||||
error = gfs2_meta_inode_buffer(ip, &bh);
|
||||
if (error)
|
||||
return error;
|
||||
dibh = bh;
|
||||
|
||||
top = (__be64 *)(bh->b_data + sizeof(struct gfs2_dinode)) + mp->mp_list[0];
|
||||
bottom = (__be64 *)(bh->b_data + sizeof(struct gfs2_dinode)) + sdp->sd_diptrs;
|
||||
} else {
|
||||
error = gfs2_meta_indirect_buffer(ip, height, block, 0, &bh);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
top = (__be64 *)(bh->b_data + mh_size) +
|
||||
(first ? mp->mp_list[height] : 0);
|
||||
|
||||
bottom = (__be64 *)(bh->b_data + mh_size) + sdp->sd_inptrs;
|
||||
}
|
||||
|
||||
error = bc(ip, dibh, bh, top, bottom, height, data);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
if (height < ip->i_height - 1)
|
||||
for (; top < bottom; top++, first = 0) {
|
||||
if (!*top)
|
||||
continue;
|
||||
|
||||
bn = be64_to_cpu(*top);
|
||||
|
||||
error = recursive_scan(ip, dibh, mp, height + 1, bn,
|
||||
first, bc, data);
|
||||
if (error)
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
brelse(bh);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* do_strip - Look for a layer a particular layer of the file and strip it off
|
||||
* @ip: the inode
|
||||
|
@ -752,9 +713,8 @@ out:
|
|||
|
||||
static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
|
||||
struct buffer_head *bh, __be64 *top, __be64 *bottom,
|
||||
unsigned int height, void *data)
|
||||
unsigned int height, struct strip_mine *sm)
|
||||
{
|
||||
struct strip_mine *sm = data;
|
||||
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
|
||||
struct gfs2_rgrp_list rlist;
|
||||
u64 bn, bstart;
|
||||
|
@ -783,11 +743,6 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
|
|||
else if (ip->i_depth)
|
||||
revokes = sdp->sd_inptrs;
|
||||
|
||||
if (ip != GFS2_I(sdp->sd_rindex))
|
||||
error = gfs2_rindex_hold(sdp, &ip->i_alloc->al_ri_gh);
|
||||
else if (!sdp->sd_rgrps)
|
||||
error = gfs2_ri_update(ip);
|
||||
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
@ -805,7 +760,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
|
|||
blen++;
|
||||
else {
|
||||
if (bstart)
|
||||
gfs2_rlist_add(sdp, &rlist, bstart);
|
||||
gfs2_rlist_add(ip, &rlist, bstart);
|
||||
|
||||
bstart = bn;
|
||||
blen = 1;
|
||||
|
@ -813,7 +768,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
|
|||
}
|
||||
|
||||
if (bstart)
|
||||
gfs2_rlist_add(sdp, &rlist, bstart);
|
||||
gfs2_rlist_add(ip, &rlist, bstart);
|
||||
else
|
||||
goto out; /* Nothing to do */
|
||||
|
||||
|
@ -887,11 +842,81 @@ out_rg_gunlock:
|
|||
out_rlist:
|
||||
gfs2_rlist_free(&rlist);
|
||||
out:
|
||||
if (ip != GFS2_I(sdp->sd_rindex))
|
||||
gfs2_glock_dq_uninit(&ip->i_alloc->al_ri_gh);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* recursive_scan - recursively scan through the end of a file
|
||||
* @ip: the inode
|
||||
* @dibh: the dinode buffer
|
||||
* @mp: the path through the metadata to the point to start
|
||||
* @height: the height the recursion is at
|
||||
* @block: the indirect block to look at
|
||||
* @first: 1 if this is the first block
|
||||
* @sm: data opaque to this function to pass to @bc
|
||||
*
|
||||
* When this is first called @height and @block should be zero and
|
||||
* @first should be 1.
|
||||
*
|
||||
* Returns: errno
|
||||
*/
|
||||
|
||||
static int recursive_scan(struct gfs2_inode *ip, struct buffer_head *dibh,
|
||||
struct metapath *mp, unsigned int height,
|
||||
u64 block, int first, struct strip_mine *sm)
|
||||
{
|
||||
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
|
||||
struct buffer_head *bh = NULL;
|
||||
__be64 *top, *bottom;
|
||||
u64 bn;
|
||||
int error;
|
||||
int mh_size = sizeof(struct gfs2_meta_header);
|
||||
|
||||
if (!height) {
|
||||
error = gfs2_meta_inode_buffer(ip, &bh);
|
||||
if (error)
|
||||
return error;
|
||||
dibh = bh;
|
||||
|
||||
top = (__be64 *)(bh->b_data + sizeof(struct gfs2_dinode)) + mp->mp_list[0];
|
||||
bottom = (__be64 *)(bh->b_data + sizeof(struct gfs2_dinode)) + sdp->sd_diptrs;
|
||||
} else {
|
||||
error = gfs2_meta_indirect_buffer(ip, height, block, 0, &bh);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
top = (__be64 *)(bh->b_data + mh_size) +
|
||||
(first ? mp->mp_list[height] : 0);
|
||||
|
||||
bottom = (__be64 *)(bh->b_data + mh_size) + sdp->sd_inptrs;
|
||||
}
|
||||
|
||||
error = do_strip(ip, dibh, bh, top, bottom, height, sm);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
if (height < ip->i_height - 1) {
|
||||
|
||||
gfs2_metapath_ra(ip->i_gl, bh, top);
|
||||
|
||||
for (; top < bottom; top++, first = 0) {
|
||||
if (!*top)
|
||||
continue;
|
||||
|
||||
bn = be64_to_cpu(*top);
|
||||
|
||||
error = recursive_scan(ip, dibh, mp, height + 1, bn,
|
||||
first, sm);
|
||||
if (error)
|
||||
break;
|
||||
}
|
||||
}
|
||||
out:
|
||||
brelse(bh);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gfs2_block_truncate_page - Deal with zeroing out data for truncate
|
||||
*
|
||||
|
@ -1031,7 +1056,7 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 size)
|
|||
sm.sm_first = !!size;
|
||||
sm.sm_height = height;
|
||||
|
||||
error = recursive_scan(ip, NULL, &mp, 0, 0, 1, do_strip, &sm);
|
||||
error = recursive_scan(ip, NULL, &mp, 0, 0, 1, &sm);
|
||||
if (error)
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -240,16 +240,15 @@ fail:
|
|||
return error;
|
||||
}
|
||||
|
||||
static int gfs2_dir_read_stuffed(struct gfs2_inode *ip, char *buf,
|
||||
u64 offset, unsigned int size)
|
||||
static int gfs2_dir_read_stuffed(struct gfs2_inode *ip, __be64 *buf,
|
||||
unsigned int size)
|
||||
{
|
||||
struct buffer_head *dibh;
|
||||
int error;
|
||||
|
||||
error = gfs2_meta_inode_buffer(ip, &dibh);
|
||||
if (!error) {
|
||||
offset += sizeof(struct gfs2_dinode);
|
||||
memcpy(buf, dibh->b_data + offset, size);
|
||||
memcpy(buf, dibh->b_data + sizeof(struct gfs2_dinode), size);
|
||||
brelse(dibh);
|
||||
}
|
||||
|
||||
|
@ -261,13 +260,12 @@ static int gfs2_dir_read_stuffed(struct gfs2_inode *ip, char *buf,
|
|||
* gfs2_dir_read_data - Read a data from a directory inode
|
||||
* @ip: The GFS2 Inode
|
||||
* @buf: The buffer to place result into
|
||||
* @offset: File offset to begin jdata_readng from
|
||||
* @size: Amount of data to transfer
|
||||
*
|
||||
* Returns: The amount of data actually copied or the error
|
||||
*/
|
||||
static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, u64 offset,
|
||||
unsigned int size, unsigned ra)
|
||||
static int gfs2_dir_read_data(struct gfs2_inode *ip, __be64 *buf,
|
||||
unsigned int size)
|
||||
{
|
||||
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
|
||||
u64 lblock, dblock;
|
||||
|
@ -275,24 +273,14 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, u64 offset,
|
|||
unsigned int o;
|
||||
int copied = 0;
|
||||
int error = 0;
|
||||
u64 disksize = i_size_read(&ip->i_inode);
|
||||
|
||||
if (offset >= disksize)
|
||||
return 0;
|
||||
|
||||
if (offset + size > disksize)
|
||||
size = disksize - offset;
|
||||
|
||||
if (!size)
|
||||
return 0;
|
||||
|
||||
if (gfs2_is_stuffed(ip))
|
||||
return gfs2_dir_read_stuffed(ip, buf, offset, size);
|
||||
return gfs2_dir_read_stuffed(ip, buf, size);
|
||||
|
||||
if (gfs2_assert_warn(sdp, gfs2_is_jdata(ip)))
|
||||
return -EINVAL;
|
||||
|
||||
lblock = offset;
|
||||
lblock = 0;
|
||||
o = do_div(lblock, sdp->sd_jbsize) + sizeof(struct gfs2_meta_header);
|
||||
|
||||
while (copied < size) {
|
||||
|
@ -311,8 +299,6 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, u64 offset,
|
|||
if (error || !dblock)
|
||||
goto fail;
|
||||
BUG_ON(extlen < 1);
|
||||
if (!ra)
|
||||
extlen = 1;
|
||||
bh = gfs2_meta_ra(ip->i_gl, dblock, extlen);
|
||||
} else {
|
||||
error = gfs2_meta_read(ip->i_gl, dblock, DIO_WAIT, &bh);
|
||||
|
@ -328,7 +314,7 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, u64 offset,
|
|||
extlen--;
|
||||
memcpy(buf, bh->b_data + o, amount);
|
||||
brelse(bh);
|
||||
buf += amount;
|
||||
buf += (amount/sizeof(__be64));
|
||||
copied += amount;
|
||||
lblock++;
|
||||
o = sizeof(struct gfs2_meta_header);
|
||||
|
@ -371,7 +357,7 @@ static __be64 *gfs2_dir_get_hash_table(struct gfs2_inode *ip)
|
|||
if (hc == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
ret = gfs2_dir_read_data(ip, (char *)hc, 0, hsize, 1);
|
||||
ret = gfs2_dir_read_data(ip, hc, hsize);
|
||||
if (ret < 0) {
|
||||
kfree(hc);
|
||||
return ERR_PTR(ret);
|
||||
|
@ -1695,7 +1681,6 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry)
|
|||
const struct qstr *name = &dentry->d_name;
|
||||
struct gfs2_dirent *dent, *prev = NULL;
|
||||
struct buffer_head *bh;
|
||||
int error;
|
||||
|
||||
/* Returns _either_ the entry (if its first in block) or the
|
||||
previous entry otherwise */
|
||||
|
@ -1724,22 +1709,15 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry)
|
|||
}
|
||||
brelse(bh);
|
||||
|
||||
error = gfs2_meta_inode_buffer(dip, &bh);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (!dip->i_entries)
|
||||
gfs2_consist_inode(dip);
|
||||
gfs2_trans_add_bh(dip->i_gl, bh, 1);
|
||||
dip->i_entries--;
|
||||
dip->i_inode.i_mtime = dip->i_inode.i_ctime = CURRENT_TIME;
|
||||
if (S_ISDIR(dentry->d_inode->i_mode))
|
||||
drop_nlink(&dip->i_inode);
|
||||
gfs2_dinode_out(dip, bh->b_data);
|
||||
brelse(bh);
|
||||
mark_inode_dirty(&dip->i_inode);
|
||||
|
||||
return error;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1829,10 +1807,6 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len,
|
|||
if (error)
|
||||
goto out_put;
|
||||
|
||||
error = gfs2_rindex_hold(sdp, &dip->i_alloc->al_ri_gh);
|
||||
if (error)
|
||||
goto out_qs;
|
||||
|
||||
/* Count the number of leaves */
|
||||
bh = leaf_bh;
|
||||
|
||||
|
@ -1847,7 +1821,7 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len,
|
|||
if (blk != leaf_no)
|
||||
brelse(bh);
|
||||
|
||||
gfs2_rlist_add(sdp, &rlist, blk);
|
||||
gfs2_rlist_add(dip, &rlist, blk);
|
||||
l_blocks++;
|
||||
}
|
||||
|
||||
|
@ -1911,8 +1885,6 @@ out_rg_gunlock:
|
|||
gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs);
|
||||
out_rlist:
|
||||
gfs2_rlist_free(&rlist);
|
||||
gfs2_glock_dq_uninit(&dip->i_alloc->al_ri_gh);
|
||||
out_qs:
|
||||
gfs2_quota_unhold(dip);
|
||||
out_put:
|
||||
gfs2_alloc_put(dip);
|
||||
|
|
299
fs/gfs2/file.c
299
fs/gfs2/file.c
|
@ -59,15 +59,24 @@ static loff_t gfs2_llseek(struct file *file, loff_t offset, int origin)
|
|||
struct gfs2_holder i_gh;
|
||||
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,
|
||||
&i_gh);
|
||||
if (!error) {
|
||||
error = generic_file_llseek_unlocked(file, offset, origin);
|
||||
gfs2_glock_dq_uninit(&i_gh);
|
||||
}
|
||||
} else
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
case SEEK_SET:
|
||||
error = generic_file_llseek_unlocked(file, offset, origin);
|
||||
break;
|
||||
default:
|
||||
error = -EINVAL;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
@ -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;
|
||||
struct gfs2_holder gh;
|
||||
struct gfs2_alloc *al;
|
||||
loff_t size;
|
||||
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);
|
||||
ret = gfs2_glock_nq(&gh);
|
||||
if (ret)
|
||||
|
@ -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(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;
|
||||
}
|
||||
|
||||
ret = -ENOMEM;
|
||||
al = gfs2_alloc_get(ip);
|
||||
if (al == NULL)
|
||||
|
@ -388,7 +411,7 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
|
|||
rblocks += data_blocks ? data_blocks : 1;
|
||||
if (ind_blocks || data_blocks) {
|
||||
rblocks += RES_STATFS + RES_QUOTA;
|
||||
rblocks += gfs2_rg_blocks(al);
|
||||
rblocks += gfs2_rg_blocks(ip);
|
||||
}
|
||||
ret = gfs2_trans_begin(sdp, rblocks, 0);
|
||||
if (ret)
|
||||
|
@ -396,21 +419,29 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
|
|||
|
||||
lock_page(page);
|
||||
ret = -EINVAL;
|
||||
last_index = ip->i_inode.i_size >> PAGE_CACHE_SHIFT;
|
||||
if (page->index > last_index)
|
||||
goto out_unlock_page;
|
||||
ret = 0;
|
||||
if (!PageUptodate(page) || page->mapping != ip->i_inode.i_mapping)
|
||||
goto out_unlock_page;
|
||||
if (gfs2_is_stuffed(ip)) {
|
||||
ret = gfs2_unstuff_dinode(ip, page);
|
||||
if (ret)
|
||||
goto out_unlock_page;
|
||||
}
|
||||
ret = gfs2_allocate_page_backing(page);
|
||||
size = i_size_read(inode);
|
||||
last_index = (size - 1) >> PAGE_CACHE_SHIFT;
|
||||
/* Check page index against inode size */
|
||||
if (size == 0 || (page->index > last_index))
|
||||
goto out_trans_end;
|
||||
|
||||
out_unlock_page:
|
||||
unlock_page(page);
|
||||
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;
|
||||
if (gfs2_is_stuffed(ip))
|
||||
ret = gfs2_unstuff_dinode(ip, page);
|
||||
if (ret == 0)
|
||||
ret = gfs2_allocate_page_backing(page);
|
||||
|
||||
out_trans_end:
|
||||
if (ret)
|
||||
unlock_page(page);
|
||||
gfs2_trans_end(sdp);
|
||||
out_trans_fail:
|
||||
gfs2_inplace_release(ip);
|
||||
|
@ -422,11 +453,17 @@ out_unlock:
|
|||
gfs2_glock_dq(&gh);
|
||||
out:
|
||||
gfs2_holder_uninit(&gh);
|
||||
if (ret == -ENOMEM)
|
||||
ret = VM_FAULT_OOM;
|
||||
else if (ret)
|
||||
ret = VM_FAULT_SIGBUS;
|
||||
return ret;
|
||||
if (ret == 0) {
|
||||
set_page_dirty(page);
|
||||
/* This check must be post dropping of transaction lock */
|
||||
if (inode->i_sb->s_frozen == SB_UNFROZEN) {
|
||||
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 = {
|
||||
|
@ -551,8 +588,16 @@ static int gfs2_close(struct inode *inode, struct file *file)
|
|||
* @end: the end position in the file to sync
|
||||
* @datasync: set if we can ignore timestamp changes
|
||||
*
|
||||
* The VFS will flush data for us. We only need to worry
|
||||
* about metadata here.
|
||||
* We split the data flushing here so that we don't wait for the data
|
||||
* 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
|
||||
*/
|
||||
|
@ -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,
|
||||
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);
|
||||
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 (ret)
|
||||
return ret;
|
||||
mutex_lock(&inode->i_mutex);
|
||||
if (mapping->nrpages) {
|
||||
ret1 = filemap_fdatawrite_range(mapping, start, end);
|
||||
if (ret1 == -EIO)
|
||||
return ret1;
|
||||
}
|
||||
|
||||
if (datasync)
|
||||
sync_state &= ~I_DIRTY_SYNC;
|
||||
|
||||
if (sync_state) {
|
||||
ret = sync_inode_metadata(inode, 1);
|
||||
if (ret) {
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
gfs2_ail_flush(ip->i_gl);
|
||||
if (gfs2_is_jdata(ip))
|
||||
filemap_write_and_wait(mapping);
|
||||
gfs2_ail_flush(ip->i_gl, 1);
|
||||
}
|
||||
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
return 0;
|
||||
if (mapping->nrpages)
|
||||
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,
|
|||
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,
|
||||
int mode)
|
||||
{
|
||||
struct gfs2_inode *ip = GFS2_I(inode);
|
||||
struct buffer_head *dibh;
|
||||
int error;
|
||||
u64 start = offset >> PAGE_CACHE_SHIFT;
|
||||
unsigned int start_offset = offset & ~PAGE_CACHE_MASK;
|
||||
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;
|
||||
unsigned int nr_blks;
|
||||
sector_t lblock = offset >> inode->i_blkbits;
|
||||
|
||||
error = gfs2_meta_inode_buffer(ip, &dibh);
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
return error;
|
||||
|
||||
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,
|
|||
goto out;
|
||||
}
|
||||
|
||||
curr = start;
|
||||
offset = start << PAGE_CACHE_SHIFT;
|
||||
from = start_offset;
|
||||
to = PAGE_CACHE_SIZE;
|
||||
while (curr <= end) {
|
||||
page = grab_cache_page_write_begin(inode->i_mapping, curr,
|
||||
AOP_FLAG_NOFS);
|
||||
if (unlikely(!page)) {
|
||||
error = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
while (len) {
|
||||
struct buffer_head bh_map = { .b_state = 0, .b_blocknr = 0 };
|
||||
bh_map.b_size = len;
|
||||
set_buffer_zeronew(&bh_map);
|
||||
|
||||
if (curr == end)
|
||||
to = end_offset;
|
||||
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)
|
||||
error = gfs2_block_map(inode, lblock, &bh_map, 1);
|
||||
if (unlikely(error))
|
||||
goto out;
|
||||
curr++;
|
||||
offset += PAGE_CACHE_SIZE;
|
||||
from = 0;
|
||||
len -= bh_map.b_size;
|
||||
nr_blks = bh_map.b_size >> inode->i_blkbits;
|
||||
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);
|
||||
|
||||
brelse(dibh);
|
||||
|
||||
out:
|
||||
brelse(dibh);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
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);
|
||||
|
||||
for (tmp = max_data; tmp > sdp->sd_diptrs;) {
|
||||
|
@ -831,6 +754,7 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset,
|
|||
int error;
|
||||
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 max_chunk_size = UINT_MAX & bsize_mask;
|
||||
next = (next + 1) << sdp->sd_sb.sb_bsize_shift;
|
||||
|
||||
/* We only support the FALLOC_FL_KEEP_SIZE mode */
|
||||
|
@ -884,11 +808,12 @@ retry:
|
|||
goto out_qunlock;
|
||||
}
|
||||
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;
|
||||
|
||||
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))
|
||||
rblocks += data_blocks ? data_blocks : 1;
|
||||
|
||||
|
|
|
@ -28,40 +28,55 @@
|
|||
#include "trans.h"
|
||||
#include "dir.h"
|
||||
|
||||
static void gfs2_ail_error(struct gfs2_glock *gl, const struct buffer_head *bh)
|
||||
{
|
||||
fs_err(gl->gl_sbd, "AIL buffer %p: blocknr %llu state 0x%08lx mapping %p page state 0x%lx\n",
|
||||
bh, (unsigned long long)bh->b_blocknr, bh->b_state,
|
||||
bh->b_page->mapping, bh->b_page->flags);
|
||||
fs_err(gl->gl_sbd, "AIL glock %u:%llu mapping %p\n",
|
||||
gl->gl_name.ln_type, gl->gl_name.ln_number,
|
||||
gfs2_glock2aspace(gl));
|
||||
gfs2_lm_withdraw(gl->gl_sbd, "AIL error\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* __gfs2_ail_flush - remove all buffers for a given lock from the AIL
|
||||
* @gl: the glock
|
||||
* @fsync: set when called from fsync (not all buffers will be clean)
|
||||
*
|
||||
* None of the buffers should be dirty, locked, or pinned.
|
||||
*/
|
||||
|
||||
static void __gfs2_ail_flush(struct gfs2_glock *gl)
|
||||
static void __gfs2_ail_flush(struct gfs2_glock *gl, bool fsync)
|
||||
{
|
||||
struct gfs2_sbd *sdp = gl->gl_sbd;
|
||||
struct list_head *head = &gl->gl_ail_list;
|
||||
struct gfs2_bufdata *bd;
|
||||
struct gfs2_bufdata *bd, *tmp;
|
||||
struct buffer_head *bh;
|
||||
const unsigned long b_state = (1UL << BH_Dirty)|(1UL << BH_Pinned)|(1UL << BH_Lock);
|
||||
sector_t blocknr;
|
||||
|
||||
gfs2_log_lock(sdp);
|
||||
spin_lock(&sdp->sd_ail_lock);
|
||||
while (!list_empty(head)) {
|
||||
bd = list_entry(head->next, struct gfs2_bufdata,
|
||||
bd_ail_gl_list);
|
||||
list_for_each_entry_safe(bd, tmp, head, bd_ail_gl_list) {
|
||||
bh = bd->bd_bh;
|
||||
gfs2_remove_from_ail(bd);
|
||||
bd->bd_bh = NULL;
|
||||
if (bh->b_state & b_state) {
|
||||
if (fsync)
|
||||
continue;
|
||||
gfs2_ail_error(gl, bh);
|
||||
}
|
||||
blocknr = bh->b_blocknr;
|
||||
bh->b_private = NULL;
|
||||
spin_unlock(&sdp->sd_ail_lock);
|
||||
gfs2_remove_from_ail(bd); /* drops ref on bh */
|
||||
|
||||
bd->bd_bh = NULL;
|
||||
bd->bd_blkno = blocknr;
|
||||
|
||||
bd->bd_blkno = bh->b_blocknr;
|
||||
gfs2_log_lock(sdp);
|
||||
gfs2_assert_withdraw(sdp, !buffer_busy(bh));
|
||||
gfs2_trans_add_revoke(sdp, bd);
|
||||
gfs2_log_unlock(sdp);
|
||||
|
||||
spin_lock(&sdp->sd_ail_lock);
|
||||
}
|
||||
gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count));
|
||||
BUG_ON(!fsync && atomic_read(&gl->gl_ail_count));
|
||||
spin_unlock(&sdp->sd_ail_lock);
|
||||
gfs2_log_unlock(sdp);
|
||||
}
|
||||
|
||||
|
||||
|
@ -84,13 +99,13 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl)
|
|||
BUG_ON(current->journal_info);
|
||||
current->journal_info = &tr;
|
||||
|
||||
__gfs2_ail_flush(gl);
|
||||
__gfs2_ail_flush(gl, 0);
|
||||
|
||||
gfs2_trans_end(sdp);
|
||||
gfs2_log_flush(sdp, NULL);
|
||||
}
|
||||
|
||||
void gfs2_ail_flush(struct gfs2_glock *gl)
|
||||
void gfs2_ail_flush(struct gfs2_glock *gl, bool fsync)
|
||||
{
|
||||
struct gfs2_sbd *sdp = gl->gl_sbd;
|
||||
unsigned int revokes = atomic_read(&gl->gl_ail_count);
|
||||
|
@ -102,7 +117,7 @@ void gfs2_ail_flush(struct gfs2_glock *gl)
|
|||
ret = gfs2_trans_begin(sdp, 0, revokes);
|
||||
if (ret)
|
||||
return;
|
||||
__gfs2_ail_flush(gl);
|
||||
__gfs2_ail_flush(gl, fsync);
|
||||
gfs2_trans_end(sdp);
|
||||
gfs2_log_flush(sdp, NULL);
|
||||
}
|
||||
|
@ -119,6 +134,7 @@ void gfs2_ail_flush(struct gfs2_glock *gl)
|
|||
static void rgrp_go_sync(struct gfs2_glock *gl)
|
||||
{
|
||||
struct address_space *metamapping = gfs2_glock2aspace(gl);
|
||||
struct gfs2_rgrpd *rgd;
|
||||
int error;
|
||||
|
||||
if (!test_and_clear_bit(GLF_DIRTY, &gl->gl_flags))
|
||||
|
@ -130,6 +146,12 @@ static void rgrp_go_sync(struct gfs2_glock *gl)
|
|||
error = filemap_fdatawait(metamapping);
|
||||
mapping_set_error(metamapping, error);
|
||||
gfs2_ail_empty_gl(gl);
|
||||
|
||||
spin_lock(&gl->gl_spin);
|
||||
rgd = gl->gl_object;
|
||||
if (rgd)
|
||||
gfs2_free_clones(rgd);
|
||||
spin_unlock(&gl->gl_spin);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -429,33 +451,6 @@ static int inode_go_dump(struct seq_file *seq, const struct gfs2_glock *gl)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* rgrp_go_lock - operation done after an rgrp lock is locked by
|
||||
* a first holder on this node.
|
||||
* @gl: the glock
|
||||
* @flags:
|
||||
*
|
||||
* Returns: errno
|
||||
*/
|
||||
|
||||
static int rgrp_go_lock(struct gfs2_holder *gh)
|
||||
{
|
||||
return gfs2_rgrp_bh_get(gh->gh_gl->gl_object);
|
||||
}
|
||||
|
||||
/**
|
||||
* rgrp_go_unlock - operation done before an rgrp lock is unlocked by
|
||||
* a last holder on this node.
|
||||
* @gl: the glock
|
||||
* @flags:
|
||||
*
|
||||
*/
|
||||
|
||||
static void rgrp_go_unlock(struct gfs2_holder *gh)
|
||||
{
|
||||
gfs2_rgrp_bh_put(gh->gh_gl->gl_object);
|
||||
}
|
||||
|
||||
/**
|
||||
* trans_go_sync - promote/demote the transaction glock
|
||||
* @gl: the glock
|
||||
|
@ -558,8 +553,8 @@ const struct gfs2_glock_operations gfs2_inode_glops = {
|
|||
const struct gfs2_glock_operations gfs2_rgrp_glops = {
|
||||
.go_xmote_th = rgrp_go_sync,
|
||||
.go_inval = rgrp_go_inval,
|
||||
.go_lock = rgrp_go_lock,
|
||||
.go_unlock = rgrp_go_unlock,
|
||||
.go_lock = gfs2_rgrp_go_lock,
|
||||
.go_unlock = gfs2_rgrp_go_unlock,
|
||||
.go_dump = gfs2_rgrp_dump,
|
||||
.go_type = LM_TYPE_RGRP,
|
||||
.go_flags = GLOF_ASPACE,
|
||||
|
|
|
@ -23,6 +23,6 @@ extern const struct gfs2_glock_operations gfs2_quota_glops;
|
|||
extern const struct gfs2_glock_operations gfs2_journal_glops;
|
||||
extern const struct gfs2_glock_operations *gfs2_glops_list[];
|
||||
|
||||
extern void gfs2_ail_flush(struct gfs2_glock *gl);
|
||||
extern void gfs2_ail_flush(struct gfs2_glock *gl, bool fsync);
|
||||
|
||||
#endif /* __GLOPS_DOT_H__ */
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <linux/rcupdate.h>
|
||||
#include <linux/rculist_bl.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/rbtree.h>
|
||||
|
||||
#define DIO_WAIT 0x00000010
|
||||
#define DIO_METADATA 0x00000020
|
||||
|
@ -78,8 +79,7 @@ struct gfs2_bitmap {
|
|||
};
|
||||
|
||||
struct gfs2_rgrpd {
|
||||
struct list_head rd_list; /* Link with superblock */
|
||||
struct list_head rd_list_mru;
|
||||
struct rb_node rd_node; /* Link with superblock */
|
||||
struct gfs2_glock *rd_gl; /* Glock for this rgrp */
|
||||
u64 rd_addr; /* grp block disk address */
|
||||
u64 rd_data0; /* first data location */
|
||||
|
@ -91,10 +91,7 @@ struct gfs2_rgrpd {
|
|||
u32 rd_dinodes;
|
||||
u64 rd_igeneration;
|
||||
struct gfs2_bitmap *rd_bits;
|
||||
struct mutex rd_mutex;
|
||||
struct gfs2_log_element rd_le;
|
||||
struct gfs2_sbd *rd_sbd;
|
||||
unsigned int rd_bh_count;
|
||||
u32 rd_last_alloc;
|
||||
u32 rd_flags;
|
||||
#define GFS2_RDF_CHECK 0x10000000 /* check for unlinked inodes */
|
||||
|
@ -106,12 +103,15 @@ struct gfs2_rgrpd {
|
|||
enum gfs2_state_bits {
|
||||
BH_Pinned = BH_PrivateStart,
|
||||
BH_Escaped = BH_PrivateStart + 1,
|
||||
BH_Zeronew = BH_PrivateStart + 2,
|
||||
};
|
||||
|
||||
BUFFER_FNS(Pinned, pinned)
|
||||
TAS_BUFFER_FNS(Pinned, pinned)
|
||||
BUFFER_FNS(Escaped, escaped)
|
||||
TAS_BUFFER_FNS(Escaped, escaped)
|
||||
BUFFER_FNS(Zeronew, zeronew)
|
||||
TAS_BUFFER_FNS(Zeronew, zeronew)
|
||||
|
||||
struct gfs2_bufdata {
|
||||
struct buffer_head *bd_bh;
|
||||
|
@ -246,7 +246,6 @@ struct gfs2_glock {
|
|||
|
||||
struct gfs2_alloc {
|
||||
/* Quota stuff */
|
||||
|
||||
struct gfs2_quota_data *al_qd[2*MAXQUOTAS];
|
||||
struct gfs2_holder al_qd_ghs[2*MAXQUOTAS];
|
||||
unsigned int al_qd_num;
|
||||
|
@ -255,18 +254,13 @@ struct gfs2_alloc {
|
|||
u32 al_alloced; /* Filled in by gfs2_alloc_*() */
|
||||
|
||||
/* Filled in by gfs2_inplace_reserve() */
|
||||
|
||||
unsigned int al_line;
|
||||
char *al_file;
|
||||
struct gfs2_holder al_ri_gh;
|
||||
struct gfs2_holder al_rgd_gh;
|
||||
struct gfs2_rgrpd *al_rgd;
|
||||
|
||||
};
|
||||
|
||||
enum {
|
||||
GIF_INVALID = 0,
|
||||
GIF_QD_LOCKED = 1,
|
||||
GIF_ALLOC_FAILED = 2,
|
||||
GIF_SW_PAGED = 3,
|
||||
};
|
||||
|
||||
|
@ -282,6 +276,7 @@ struct gfs2_inode {
|
|||
struct gfs2_holder i_iopen_gh;
|
||||
struct gfs2_holder i_gh; /* for prepare/commit_write only */
|
||||
struct gfs2_alloc *i_alloc;
|
||||
struct gfs2_rgrpd *i_rgd;
|
||||
u64 i_goal; /* goal block for allocations */
|
||||
struct rw_semaphore i_rw_mutex;
|
||||
struct list_head i_trunc_list;
|
||||
|
@ -574,9 +569,7 @@ struct gfs2_sbd {
|
|||
int sd_rindex_uptodate;
|
||||
spinlock_t sd_rindex_spin;
|
||||
struct mutex sd_rindex_mutex;
|
||||
struct list_head sd_rindex_list;
|
||||
struct list_head sd_rindex_mru_list;
|
||||
struct gfs2_rgrpd *sd_rindex_forward;
|
||||
struct rb_root sd_rindex_tree;
|
||||
unsigned int sd_rgrps;
|
||||
unsigned int sd_max_rg_data;
|
||||
|
||||
|
|
112
fs/gfs2/inode.c
112
fs/gfs2/inode.c
|
@ -583,7 +583,7 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name,
|
|||
goto fail_quota_locks;
|
||||
|
||||
error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
|
||||
al->al_rgd->rd_length +
|
||||
dip->i_rgd->rd_length +
|
||||
2 * RES_DINODE +
|
||||
RES_STATFS + RES_QUOTA, 0);
|
||||
if (error)
|
||||
|
@ -613,8 +613,7 @@ fail_end_trans:
|
|||
gfs2_trans_end(sdp);
|
||||
|
||||
fail_ipreserv:
|
||||
if (dip->i_alloc->al_rgd)
|
||||
gfs2_inplace_release(dip);
|
||||
gfs2_inplace_release(dip);
|
||||
|
||||
fail_quota_locks:
|
||||
gfs2_quota_unlock(dip);
|
||||
|
@ -661,7 +660,7 @@ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip,
|
|||
|
||||
static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
|
||||
unsigned int mode, dev_t dev, const char *symname,
|
||||
unsigned int size)
|
||||
unsigned int size, int excl)
|
||||
{
|
||||
const struct qstr *name = &dentry->d_name;
|
||||
struct gfs2_holder ghs[2];
|
||||
|
@ -681,6 +680,12 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
|
|||
goto fail;
|
||||
|
||||
error = create_ok(dip, name, mode);
|
||||
if ((error == -EEXIST) && S_ISREG(mode) && !excl) {
|
||||
inode = gfs2_lookupi(dir, &dentry->d_name, 0);
|
||||
gfs2_glock_dq_uninit(ghs);
|
||||
d_instantiate(dentry, inode);
|
||||
return IS_ERR(inode) ? PTR_ERR(inode) : 0;
|
||||
}
|
||||
if (error)
|
||||
goto fail_gunlock;
|
||||
|
||||
|
@ -723,21 +728,22 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
|
|||
brelse(bh);
|
||||
|
||||
gfs2_trans_end(sdp);
|
||||
if (dip->i_alloc->al_rgd)
|
||||
gfs2_inplace_release(dip);
|
||||
gfs2_inplace_release(dip);
|
||||
gfs2_quota_unlock(dip);
|
||||
gfs2_alloc_put(dip);
|
||||
gfs2_glock_dq_uninit_m(2, ghs);
|
||||
mark_inode_dirty(inode);
|
||||
gfs2_glock_dq_uninit_m(2, ghs);
|
||||
d_instantiate(dentry, inode);
|
||||
return 0;
|
||||
|
||||
fail_gunlock2:
|
||||
gfs2_glock_dq_uninit(ghs + 1);
|
||||
if (inode && !IS_ERR(inode))
|
||||
iput(inode);
|
||||
fail_gunlock:
|
||||
gfs2_glock_dq_uninit(ghs);
|
||||
if (inode && !IS_ERR(inode)) {
|
||||
set_bit(GIF_ALLOC_FAILED, &GFS2_I(inode)->i_flags);
|
||||
iput(inode);
|
||||
}
|
||||
fail:
|
||||
if (bh)
|
||||
brelse(bh);
|
||||
|
@ -756,24 +762,10 @@ fail:
|
|||
static int gfs2_create(struct inode *dir, struct dentry *dentry,
|
||||
int mode, struct nameidata *nd)
|
||||
{
|
||||
struct inode *inode;
|
||||
int ret;
|
||||
|
||||
for (;;) {
|
||||
ret = gfs2_create_inode(dir, dentry, S_IFREG | mode, 0, NULL, 0);
|
||||
if (ret != -EEXIST || (nd && (nd->flags & LOOKUP_EXCL)))
|
||||
return ret;
|
||||
|
||||
inode = gfs2_lookupi(dir, &dentry->d_name, 0);
|
||||
if (inode) {
|
||||
if (!IS_ERR(inode))
|
||||
break;
|
||||
return PTR_ERR(inode);
|
||||
}
|
||||
}
|
||||
|
||||
d_instantiate(dentry, inode);
|
||||
return 0;
|
||||
int excl = 0;
|
||||
if (nd && (nd->flags & LOOKUP_EXCL))
|
||||
excl = 1;
|
||||
return gfs2_create_inode(dir, dentry, S_IFREG | mode, 0, NULL, 0, excl);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -900,7 +892,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
|
|||
goto out_gunlock_q;
|
||||
|
||||
error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
|
||||
gfs2_rg_blocks(al) +
|
||||
gfs2_rg_blocks(dip) +
|
||||
2 * RES_DINODE + RES_STATFS +
|
||||
RES_QUOTA, 0);
|
||||
if (error)
|
||||
|
@ -922,8 +914,9 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
|
|||
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
|
||||
inc_nlink(&ip->i_inode);
|
||||
ip->i_inode.i_ctime = CURRENT_TIME;
|
||||
gfs2_dinode_out(ip, dibh->b_data);
|
||||
mark_inode_dirty(&ip->i_inode);
|
||||
ihold(inode);
|
||||
d_instantiate(dentry, inode);
|
||||
mark_inode_dirty(inode);
|
||||
|
||||
out_brelse:
|
||||
brelse(dibh);
|
||||
|
@ -945,11 +938,6 @@ out_child:
|
|||
out_parent:
|
||||
gfs2_holder_uninit(ghs);
|
||||
gfs2_holder_uninit(ghs + 1);
|
||||
if (!error) {
|
||||
ihold(inode);
|
||||
d_instantiate(dentry, inode);
|
||||
mark_inode_dirty(inode);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -1022,8 +1010,6 @@ static int gfs2_unlink_inode(struct gfs2_inode *dip,
|
|||
clear_nlink(inode);
|
||||
else
|
||||
drop_nlink(inode);
|
||||
gfs2_trans_add_bh(ip->i_gl, bh, 1);
|
||||
gfs2_dinode_out(ip, bh->b_data);
|
||||
mark_inode_dirty(inode);
|
||||
if (inode->i_nlink == 0)
|
||||
gfs2_unlink_di(inode);
|
||||
|
@ -1051,13 +1037,8 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry)
|
|||
struct buffer_head *bh;
|
||||
struct gfs2_holder ghs[3];
|
||||
struct gfs2_rgrpd *rgd;
|
||||
struct gfs2_holder ri_gh;
|
||||
int error;
|
||||
|
||||
error = gfs2_rindex_hold(sdp, &ri_gh);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
|
||||
gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1);
|
||||
|
||||
|
@ -1114,7 +1095,6 @@ out_child:
|
|||
gfs2_glock_dq(ghs);
|
||||
out_parent:
|
||||
gfs2_holder_uninit(ghs);
|
||||
gfs2_glock_dq_uninit(&ri_gh);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -1137,7 +1117,7 @@ static int gfs2_symlink(struct inode *dir, struct dentry *dentry,
|
|||
if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode) - 1)
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
return gfs2_create_inode(dir, dentry, S_IFLNK | S_IRWXUGO, 0, symname, size);
|
||||
return gfs2_create_inode(dir, dentry, S_IFLNK | S_IRWXUGO, 0, symname, size, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1151,7 +1131,7 @@ static int gfs2_symlink(struct inode *dir, struct dentry *dentry,
|
|||
|
||||
static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode)
|
||||
{
|
||||
return gfs2_create_inode(dir, dentry, S_IFDIR | mode, 0, NULL, 0);
|
||||
return gfs2_create_inode(dir, dentry, S_IFDIR | mode, 0, NULL, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1166,7 +1146,7 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode)
|
|||
static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode,
|
||||
dev_t dev)
|
||||
{
|
||||
return gfs2_create_inode(dir, dentry, mode, dev, NULL, 0);
|
||||
return gfs2_create_inode(dir, dentry, mode, dev, NULL, 0, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1232,7 +1212,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
|
|||
struct gfs2_inode *ip = GFS2_I(odentry->d_inode);
|
||||
struct gfs2_inode *nip = NULL;
|
||||
struct gfs2_sbd *sdp = GFS2_SB(odir);
|
||||
struct gfs2_holder ghs[5], r_gh = { .gh_gl = NULL, }, ri_gh;
|
||||
struct gfs2_holder ghs[5], r_gh = { .gh_gl = NULL, };
|
||||
struct gfs2_rgrpd *nrgd;
|
||||
unsigned int num_gh;
|
||||
int dir_rename = 0;
|
||||
|
@ -1246,10 +1226,6 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
|
|||
return 0;
|
||||
}
|
||||
|
||||
error = gfs2_rindex_hold(sdp, &ri_gh);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (odip != ndip) {
|
||||
error = gfs2_glock_nq_init(sdp->sd_rename_gl, LM_ST_EXCLUSIVE,
|
||||
0, &r_gh);
|
||||
|
@ -1386,12 +1362,12 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
|
|||
|
||||
al->al_requested = sdp->sd_max_dirres;
|
||||
|
||||
error = gfs2_inplace_reserve_ri(ndip);
|
||||
error = gfs2_inplace_reserve(ndip);
|
||||
if (error)
|
||||
goto out_gunlock_q;
|
||||
|
||||
error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
|
||||
gfs2_rg_blocks(al) +
|
||||
gfs2_rg_blocks(ndip) +
|
||||
4 * RES_DINODE + 4 * RES_LEAF +
|
||||
RES_STATFS + RES_QUOTA + 4, 0);
|
||||
if (error)
|
||||
|
@ -1457,7 +1433,6 @@ out_gunlock_r:
|
|||
if (r_gh.gh_gl)
|
||||
gfs2_glock_dq_uninit(&r_gh);
|
||||
out:
|
||||
gfs2_glock_dq_uninit(&ri_gh);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -1561,21 +1536,10 @@ int gfs2_permission(struct inode *inode, int mask)
|
|||
return error;
|
||||
}
|
||||
|
||||
static int __gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr)
|
||||
static int __gfs2_setattr_simple(struct inode *inode, struct iattr *attr)
|
||||
{
|
||||
struct inode *inode = &ip->i_inode;
|
||||
struct buffer_head *dibh;
|
||||
int error;
|
||||
|
||||
error = gfs2_meta_inode_buffer(ip, &dibh);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
setattr_copy(inode, attr);
|
||||
mark_inode_dirty(inode);
|
||||
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
|
||||
gfs2_dinode_out(ip, dibh->b_data);
|
||||
brelse(dibh);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1587,19 +1551,19 @@ static int __gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr)
|
|||
* Returns: errno
|
||||
*/
|
||||
|
||||
int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr)
|
||||
int gfs2_setattr_simple(struct inode *inode, struct iattr *attr)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (current->journal_info)
|
||||
return __gfs2_setattr_simple(ip, attr);
|
||||
return __gfs2_setattr_simple(inode, attr);
|
||||
|
||||
error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE, 0);
|
||||
error = gfs2_trans_begin(GFS2_SB(inode), RES_DINODE, 0);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = __gfs2_setattr_simple(ip, attr);
|
||||
gfs2_trans_end(GFS2_SB(&ip->i_inode));
|
||||
error = __gfs2_setattr_simple(inode, attr);
|
||||
gfs2_trans_end(GFS2_SB(inode));
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -1637,7 +1601,7 @@ static int setattr_chown(struct inode *inode, struct iattr *attr)
|
|||
if (error)
|
||||
goto out_gunlock_q;
|
||||
|
||||
error = gfs2_setattr_simple(ip, attr);
|
||||
error = gfs2_setattr_simple(inode, attr);
|
||||
if (error)
|
||||
goto out_end_trans;
|
||||
|
||||
|
@ -1693,12 +1657,12 @@ static int gfs2_setattr(struct dentry *dentry, struct iattr *attr)
|
|||
else if ((attr->ia_valid & ATTR_MODE) && IS_POSIXACL(inode))
|
||||
error = gfs2_acl_chmod(ip, attr);
|
||||
else
|
||||
error = gfs2_setattr_simple(ip, attr);
|
||||
error = gfs2_setattr_simple(inode, attr);
|
||||
|
||||
out:
|
||||
gfs2_glock_dq_uninit(&i_gh);
|
||||
if (!error)
|
||||
mark_inode_dirty(inode);
|
||||
gfs2_glock_dq_uninit(&i_gh);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
|
|
@ -109,7 +109,7 @@ extern int gfs2_inode_refresh(struct gfs2_inode *ip);
|
|||
extern struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
|
||||
int is_root);
|
||||
extern int gfs2_permission(struct inode *inode, int mask);
|
||||
extern int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr);
|
||||
extern int gfs2_setattr_simple(struct inode *inode, struct iattr *attr);
|
||||
extern struct inode *gfs2_lookup_simple(struct inode *dip, const char *name);
|
||||
extern void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf);
|
||||
|
||||
|
|
|
@ -60,6 +60,29 @@ static void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh)
|
|||
trace_gfs2_pin(bd, 1);
|
||||
}
|
||||
|
||||
static bool buffer_is_rgrp(const struct gfs2_bufdata *bd)
|
||||
{
|
||||
return bd->bd_gl->gl_name.ln_type == LM_TYPE_RGRP;
|
||||
}
|
||||
|
||||
static void maybe_release_space(struct gfs2_bufdata *bd)
|
||||
{
|
||||
struct gfs2_glock *gl = bd->bd_gl;
|
||||
struct gfs2_sbd *sdp = gl->gl_sbd;
|
||||
struct gfs2_rgrpd *rgd = gl->gl_object;
|
||||
unsigned int index = bd->bd_bh->b_blocknr - gl->gl_name.ln_number;
|
||||
struct gfs2_bitmap *bi = rgd->rd_bits + index;
|
||||
|
||||
if (bi->bi_clone == 0)
|
||||
return;
|
||||
if (sdp->sd_args.ar_discard)
|
||||
gfs2_rgrp_send_discards(sdp, rgd->rd_data0, bd->bd_bh, bi);
|
||||
memcpy(bi->bi_clone + bi->bi_offset,
|
||||
bd->bd_bh->b_data + bi->bi_offset, bi->bi_len);
|
||||
clear_bit(GBF_FULL, &bi->bi_flags);
|
||||
rgd->rd_free_clone = rgd->rd_free;
|
||||
}
|
||||
|
||||
/**
|
||||
* gfs2_unpin - Unpin a buffer
|
||||
* @sdp: the filesystem the buffer belongs to
|
||||
|
@ -81,6 +104,9 @@ static void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh,
|
|||
mark_buffer_dirty(bh);
|
||||
clear_buffer_pinned(bh);
|
||||
|
||||
if (buffer_is_rgrp(bd))
|
||||
maybe_release_space(bd);
|
||||
|
||||
spin_lock(&sdp->sd_ail_lock);
|
||||
if (bd->bd_ail) {
|
||||
list_del(&bd->bd_ail_st_list);
|
||||
|
@ -469,42 +495,6 @@ static void revoke_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass)
|
|||
gfs2_revoke_clean(sdp);
|
||||
}
|
||||
|
||||
static void rg_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
|
||||
{
|
||||
struct gfs2_rgrpd *rgd;
|
||||
struct gfs2_trans *tr = current->journal_info;
|
||||
|
||||
tr->tr_touched = 1;
|
||||
|
||||
rgd = container_of(le, struct gfs2_rgrpd, rd_le);
|
||||
|
||||
gfs2_log_lock(sdp);
|
||||
if (!list_empty(&le->le_list)){
|
||||
gfs2_log_unlock(sdp);
|
||||
return;
|
||||
}
|
||||
gfs2_rgrp_bh_hold(rgd);
|
||||
sdp->sd_log_num_rg++;
|
||||
list_add(&le->le_list, &sdp->sd_log_le_rg);
|
||||
gfs2_log_unlock(sdp);
|
||||
}
|
||||
|
||||
static void rg_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
|
||||
{
|
||||
struct list_head *head = &sdp->sd_log_le_rg;
|
||||
struct gfs2_rgrpd *rgd;
|
||||
|
||||
while (!list_empty(head)) {
|
||||
rgd = list_entry(head->next, struct gfs2_rgrpd, rd_le.le_list);
|
||||
list_del_init(&rgd->rd_le.le_list);
|
||||
sdp->sd_log_num_rg--;
|
||||
|
||||
gfs2_rgrp_repolish_clones(rgd);
|
||||
gfs2_rgrp_bh_put(rgd);
|
||||
}
|
||||
gfs2_assert_warn(sdp, !sdp->sd_log_num_rg);
|
||||
}
|
||||
|
||||
/**
|
||||
* databuf_lo_add - Add a databuf to the transaction.
|
||||
*
|
||||
|
@ -705,8 +695,6 @@ static int databuf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start,
|
|||
|
||||
brelse(bh_log);
|
||||
brelse(bh_ip);
|
||||
if (error)
|
||||
break;
|
||||
|
||||
sdp->sd_replayed_blocks++;
|
||||
}
|
||||
|
@ -771,8 +759,6 @@ const struct gfs2_log_operations gfs2_revoke_lops = {
|
|||
};
|
||||
|
||||
const struct gfs2_log_operations gfs2_rg_lops = {
|
||||
.lo_add = rg_lo_add,
|
||||
.lo_after_commit = rg_lo_after_commit,
|
||||
.lo_name = "rg",
|
||||
};
|
||||
|
||||
|
|
|
@ -77,8 +77,7 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
|
|||
|
||||
spin_lock_init(&sdp->sd_rindex_spin);
|
||||
mutex_init(&sdp->sd_rindex_mutex);
|
||||
INIT_LIST_HEAD(&sdp->sd_rindex_list);
|
||||
INIT_LIST_HEAD(&sdp->sd_rindex_mru_list);
|
||||
sdp->sd_rindex_tree.rb_node = NULL;
|
||||
|
||||
INIT_LIST_HEAD(&sdp->sd_jindex_list);
|
||||
spin_lock_init(&sdp->sd_jindex_spin);
|
||||
|
@ -652,7 +651,6 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
|
|||
fs_err(sdp, "can't lookup journal index: %d\n", error);
|
||||
return PTR_ERR(sdp->sd_jindex);
|
||||
}
|
||||
ip = GFS2_I(sdp->sd_jindex);
|
||||
|
||||
/* Load in the journal index special file */
|
||||
|
||||
|
@ -764,7 +762,6 @@ fail:
|
|||
static int init_inodes(struct gfs2_sbd *sdp, int undo)
|
||||
{
|
||||
int error = 0;
|
||||
struct gfs2_inode *ip;
|
||||
struct inode *master = sdp->sd_master_dir->d_inode;
|
||||
|
||||
if (undo)
|
||||
|
@ -789,7 +786,6 @@ static int init_inodes(struct gfs2_sbd *sdp, int undo)
|
|||
fs_err(sdp, "can't get resource index inode: %d\n", error);
|
||||
goto fail_statfs;
|
||||
}
|
||||
ip = GFS2_I(sdp->sd_rindex);
|
||||
sdp->sd_rindex_uptodate = 0;
|
||||
|
||||
/* Read in the quota inode */
|
||||
|
|
|
@ -638,15 +638,18 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
|
|||
unsigned long index = loc >> PAGE_CACHE_SHIFT;
|
||||
unsigned offset = loc & (PAGE_CACHE_SIZE - 1);
|
||||
unsigned blocksize, iblock, pos;
|
||||
struct buffer_head *bh, *dibh;
|
||||
struct buffer_head *bh;
|
||||
struct page *page;
|
||||
void *kaddr, *ptr;
|
||||
struct gfs2_quota q, *qp;
|
||||
int err, nbytes;
|
||||
u64 size;
|
||||
|
||||
if (gfs2_is_stuffed(ip))
|
||||
gfs2_unstuff_dinode(ip, NULL);
|
||||
if (gfs2_is_stuffed(ip)) {
|
||||
err = gfs2_unstuff_dinode(ip, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
memset(&q, 0, sizeof(struct gfs2_quota));
|
||||
err = gfs2_internal_read(ip, NULL, (char *)&q, &loc, sizeof(q));
|
||||
|
@ -736,22 +739,13 @@ 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);
|
||||
if (size > inode->i_size)
|
||||
i_size_write(inode, size);
|
||||
inode->i_mtime = inode->i_atime = CURRENT_TIME;
|
||||
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
|
||||
gfs2_dinode_out(ip, dibh->b_data);
|
||||
brelse(dibh);
|
||||
mark_inode_dirty(inode);
|
||||
|
||||
out:
|
||||
return err;
|
||||
|
||||
unlock_out:
|
||||
unlock_page(page);
|
||||
page_cache_release(page);
|
||||
|
@ -822,7 +816,7 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda)
|
|||
goto out_alloc;
|
||||
|
||||
if (nalloc)
|
||||
blocks += gfs2_rg_blocks(al) + nalloc * ind_blocks + RES_STATFS;
|
||||
blocks += gfs2_rg_blocks(ip) + nalloc * ind_blocks + RES_STATFS;
|
||||
|
||||
error = gfs2_trans_begin(sdp, blocks, 0);
|
||||
if (error)
|
||||
|
@ -936,7 +930,9 @@ int gfs2_quota_lock(struct gfs2_inode *ip, u32 uid, u32 gid)
|
|||
unsigned int x;
|
||||
int error = 0;
|
||||
|
||||
gfs2_quota_hold(ip, uid, gid);
|
||||
error = gfs2_quota_hold(ip, uid, gid);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (capable(CAP_SYS_RESOURCE) ||
|
||||
sdp->sd_args.ar_quota != GFS2_QUOTA_ON)
|
||||
|
@ -1607,7 +1603,7 @@ static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
|
|||
error = gfs2_inplace_reserve(ip);
|
||||
if (error)
|
||||
goto out_alloc;
|
||||
blocks += gfs2_rg_blocks(al);
|
||||
blocks += gfs2_rg_blocks(ip);
|
||||
}
|
||||
|
||||
/* Some quotas span block boundaries and can update two blocks,
|
||||
|
|
595
fs/gfs2/rgrp.c
595
fs/gfs2/rgrp.c
|
@ -15,6 +15,7 @@
|
|||
#include <linux/gfs2_ondisk.h>
|
||||
#include <linux/prefetch.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/rbtree.h>
|
||||
|
||||
#include "gfs2.h"
|
||||
#include "incore.h"
|
||||
|
@ -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 *rgd;
|
||||
struct rb_node **newn;
|
||||
struct gfs2_rgrpd *cur;
|
||||
|
||||
spin_lock(&sdp->sd_rindex_spin);
|
||||
|
||||
list_for_each_entry(rgd, &sdp->sd_rindex_mru_list, rd_list_mru) {
|
||||
if (rgrp_contains_block(rgd, blk)) {
|
||||
list_move(&rgd->rd_list_mru, &sdp->sd_rindex_mru_list);
|
||||
newn = &sdp->sd_rindex_tree.rb_node;
|
||||
while (*newn) {
|
||||
cur = rb_entry(*newn, struct gfs2_rgrpd, rd_node);
|
||||
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);
|
||||
return rgd;
|
||||
return cur;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock(&sdp->sd_rindex_spin);
|
||||
|
||||
return NULL;
|
||||
|
@ -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)
|
||||
{
|
||||
gfs2_assert(sdp, !list_empty(&sdp->sd_rindex_list));
|
||||
return list_entry(sdp->sd_rindex_list.next, struct gfs2_rgrpd, rd_list);
|
||||
const struct rb_node *n;
|
||||
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,45 +379,58 @@ struct gfs2_rgrpd *gfs2_rgrpd_get_first(struct gfs2_sbd *sdp)
|
|||
|
||||
struct gfs2_rgrpd *gfs2_rgrpd_get_next(struct gfs2_rgrpd *rgd)
|
||||
{
|
||||
if (rgd->rd_list.next == &rgd->rd_sbd->sd_rindex_list)
|
||||
return NULL;
|
||||
return list_entry(rgd->rd_list.next, struct gfs2_rgrpd, rd_list);
|
||||
}
|
||||
|
||||
static void clear_rgrpdi(struct gfs2_sbd *sdp)
|
||||
{
|
||||
struct list_head *head;
|
||||
struct gfs2_rgrpd *rgd;
|
||||
struct gfs2_glock *gl;
|
||||
struct gfs2_sbd *sdp = rgd->rd_sbd;
|
||||
const struct rb_node *n;
|
||||
|
||||
spin_lock(&sdp->sd_rindex_spin);
|
||||
sdp->sd_rindex_forward = NULL;
|
||||
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;
|
||||
}
|
||||
rgd = rb_entry(n, struct gfs2_rgrpd, rd_node);
|
||||
spin_unlock(&sdp->sd_rindex_spin);
|
||||
return rgd;
|
||||
}
|
||||
|
||||
head = &sdp->sd_rindex_list;
|
||||
while (!list_empty(head)) {
|
||||
rgd = list_entry(head->next, struct gfs2_rgrpd, rd_list);
|
||||
gl = rgd->rd_gl;
|
||||
void gfs2_free_clones(struct gfs2_rgrpd *rgd)
|
||||
{
|
||||
int x;
|
||||
|
||||
list_del(&rgd->rd_list);
|
||||
list_del(&rgd->rd_list_mru);
|
||||
|
||||
if (gl) {
|
||||
gl->gl_object = NULL;
|
||||
gfs2_glock_add_to_lru(gl);
|
||||
gfs2_glock_put(gl);
|
||||
}
|
||||
|
||||
kfree(rgd->rd_bits);
|
||||
kmem_cache_free(gfs2_rgrpd_cachep, rgd);
|
||||
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)
|
||||
{
|
||||
mutex_lock(&sdp->sd_rindex_mutex);
|
||||
clear_rgrpdi(sdp);
|
||||
mutex_unlock(&sdp->sd_rindex_mutex);
|
||||
struct rb_node *n;
|
||||
struct gfs2_rgrpd *rgd;
|
||||
struct gfs2_glock *gl;
|
||||
|
||||
while ((n = rb_first(&sdp->sd_rindex_tree))) {
|
||||
rgd = rb_entry(n, struct gfs2_rgrpd, rd_node);
|
||||
gl = rgd->rd_gl;
|
||||
|
||||
rb_erase(n, &sdp->sd_rindex_tree);
|
||||
|
||||
if (gl) {
|
||||
spin_lock(&gl->gl_spin);
|
||||
gl->gl_object = NULL;
|
||||
spin_unlock(&gl->gl_spin);
|
||||
gfs2_glock_add_to_lru(gl);
|
||||
gfs2_glock_put(gl);
|
||||
}
|
||||
|
||||
gfs2_free_clones(rgd);
|
||||
kfree(rgd->rd_bits);
|
||||
kmem_cache_free(gfs2_rgrpd_cachep, rgd);
|
||||
}
|
||||
}
|
||||
|
||||
static void gfs2_rindex_print(const struct gfs2_rgrpd *rgd)
|
||||
|
@ -524,22 +549,34 @@ u64 gfs2_ri_total(struct gfs2_sbd *sdp)
|
|||
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;
|
||||
|
||||
rgd->rd_addr = be64_to_cpu(str->ri_addr);
|
||||
rgd->rd_length = be32_to_cpu(str->ri_length);
|
||||
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);
|
||||
/* 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;
|
||||
}
|
||||
|
||||
rb_link_node(&rgd->rd_node, parent, newn);
|
||||
rb_insert_color(&rgd->rd_node, &sdp->sd_rindex_tree);
|
||||
}
|
||||
|
||||
/**
|
||||
* read_rindex_entry - Pull in a new resource index entry from the disk
|
||||
* @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,
|
||||
|
@ -547,44 +584,53 @@ static int read_rindex_entry(struct gfs2_inode *ip,
|
|||
{
|
||||
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
|
||||
loff_t pos = sdp->sd_rgrps * sizeof(struct gfs2_rindex);
|
||||
char buf[sizeof(struct gfs2_rindex)];
|
||||
struct gfs2_rindex buf;
|
||||
int error;
|
||||
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));
|
||||
if (!error)
|
||||
return 0;
|
||||
if (error != sizeof(struct gfs2_rindex)) {
|
||||
if (error > 0)
|
||||
error = -EIO;
|
||||
return error;
|
||||
}
|
||||
|
||||
if (error != sizeof(struct gfs2_rindex))
|
||||
return (error == 0) ? 1 : error;
|
||||
|
||||
rgd = kmem_cache_zalloc(gfs2_rgrpd_cachep, GFP_NOFS);
|
||||
error = -ENOMEM;
|
||||
if (!rgd)
|
||||
return error;
|
||||
|
||||
mutex_init(&rgd->rd_mutex);
|
||||
lops_init_le(&rgd->rd_le, &gfs2_rg_lops);
|
||||
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);
|
||||
if (error)
|
||||
return error;
|
||||
goto fail;
|
||||
|
||||
error = gfs2_glock_get(sdp, rgd->rd_addr,
|
||||
&gfs2_rgrp_glops, CREATE, &rgd->rd_gl);
|
||||
if (error)
|
||||
return error;
|
||||
goto fail;
|
||||
|
||||
rgd->rd_gl->gl_object = rgd;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -595,40 +641,28 @@ static int read_rindex_entry(struct gfs2_inode *ip,
|
|||
* 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 inode *inode = &ip->i_inode;
|
||||
struct file_ra_state ra_state;
|
||||
u64 rgrp_count = i_size_read(inode);
|
||||
struct gfs2_rgrpd *rgd;
|
||||
unsigned int max_data = 0;
|
||||
int error;
|
||||
|
||||
do_div(rgrp_count, sizeof(struct gfs2_rindex));
|
||||
clear_rgrpdi(sdp);
|
||||
|
||||
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);
|
||||
if (error) {
|
||||
clear_rgrpdi(sdp);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
} while (error == 0);
|
||||
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* gfs2_rindex_hold - Grab a lock on the rindex
|
||||
* gfs2_rindex_update - Update the rindex if required
|
||||
* @sdp: The GFS2 superblock
|
||||
* @ri_gh: the glock holder
|
||||
*
|
||||
* 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
|
||||
|
@ -640,30 +674,29 @@ int gfs2_ri_update(struct gfs2_inode *ip)
|
|||
* special file, which might have been updated if someone expanded the
|
||||
* 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_glock *gl = ip->i_gl;
|
||||
int error;
|
||||
|
||||
error = gfs2_glock_nq_init(gl, LM_ST_SHARED, 0, ri_gh);
|
||||
if (error)
|
||||
return error;
|
||||
struct gfs2_holder ri_gh;
|
||||
int error = 0;
|
||||
|
||||
/* Read new copy from disk if we don't have the latest */
|
||||
if (!sdp->sd_rindex_uptodate) {
|
||||
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);
|
||||
if (error)
|
||||
gfs2_glock_dq_uninit(ri_gh);
|
||||
}
|
||||
gfs2_glock_dq_uninit(&ri_gh);
|
||||
mutex_unlock(&sdp->sd_rindex_mutex);
|
||||
}
|
||||
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
*
|
||||
* 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)
|
|||
* 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_glock *gl = rgd->rd_gl;
|
||||
unsigned int length = rgd->rd_length;
|
||||
|
@ -712,17 +746,6 @@ int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd)
|
|||
unsigned int x, y;
|
||||
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++) {
|
||||
bi = rgd->rd_bits + x;
|
||||
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)
|
|||
clear_bit(GBF_FULL, &rgd->rd_bits[x].bi_flags);
|
||||
gfs2_rgrp_in(rgd, (rgd->rd_bits[0].bi_bh)->b_data);
|
||||
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;
|
||||
|
||||
fail:
|
||||
|
@ -765,52 +782,32 @@ fail:
|
|||
bi->bi_bh = NULL;
|
||||
gfs2_assert_warn(sdp, !bi->bi_clone);
|
||||
}
|
||||
mutex_unlock(&rgd->rd_mutex);
|
||||
|
||||
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
|
||||
*
|
||||
*/
|
||||
|
||||
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;
|
||||
|
||||
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++) {
|
||||
struct gfs2_bitmap *bi = rgd->rd_bits + x;
|
||||
kfree(bi->bi_clone);
|
||||
bi->bi_clone = NULL;
|
||||
brelse(bi->bi_bh);
|
||||
bi->bi_bh = NULL;
|
||||
}
|
||||
|
||||
spin_unlock(&sdp->sd_rindex_spin);
|
||||
}
|
||||
|
||||
static void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
|
||||
const struct gfs2_bitmap *bi)
|
||||
void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
|
||||
struct buffer_head *bh,
|
||||
const struct gfs2_bitmap *bi)
|
||||
{
|
||||
struct super_block *sb = sdp->sd_vfs;
|
||||
struct block_device *bdev = sb->s_bdev;
|
||||
|
@ -823,7 +820,7 @@ static void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
|
|||
unsigned int 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;
|
||||
u8 diff = ~(*orig | (*orig >> 1)) & (*clone | (*clone >> 1));
|
||||
diff &= 0x55;
|
||||
|
@ -862,28 +859,6 @@ fail:
|
|||
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
|
||||
* @ip: the incore GFS2 inode structure
|
||||
|
@ -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_sbd *sdp = GFS2_SB(&ip->i_inode);
|
||||
int error;
|
||||
BUG_ON(ip->i_alloc != NULL);
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* try_rgrp_fit - See if a given reservation will fit in a given RG
|
||||
* @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:
|
||||
* Sets the $al_rgd field in @al.
|
||||
*
|
||||
* 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;
|
||||
int ret = 0;
|
||||
const struct gfs2_alloc *al = ip->i_alloc;
|
||||
|
||||
if (rgd->rd_flags & (GFS2_RGF_NOALLOC | GFS2_RDF_ERROR))
|
||||
return 0;
|
||||
|
||||
spin_lock(&sdp->sd_rindex_spin);
|
||||
if (rgd->rd_free_clone >= al->al_requested) {
|
||||
al->al_rgd = rgd;
|
||||
ret = 1;
|
||||
}
|
||||
spin_unlock(&sdp->sd_rindex_spin);
|
||||
|
||||
return ret;
|
||||
if (rgd->rd_free_clone >= al->al_requested)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -991,76 +963,6 @@ static void try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked, u64 skip
|
|||
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
|
||||
* @ip: the inode to reserve space for
|
||||
|
@ -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_rgrpd *rgd, *begin = NULL;
|
||||
struct gfs2_alloc *al = ip->i_alloc;
|
||||
int flags = LM_FLAG_TRY;
|
||||
int skipped = 0;
|
||||
int loops = 0;
|
||||
int error, rg_locked;
|
||||
int loops = 0;
|
||||
|
||||
rgd = gfs2_blk2rgrpd(sdp, ip->i_goal);
|
||||
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);
|
||||
|
||||
while (rgd) {
|
||||
if (rgd == NULL)
|
||||
return -EBADSLT;
|
||||
|
||||
while (loops < 3) {
|
||||
rg_locked = 0;
|
||||
|
||||
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)
|
|||
}
|
||||
switch (error) {
|
||||
case 0:
|
||||
if (try_rgrp_fit(rgd, al))
|
||||
goto out;
|
||||
if (try_rgrp_fit(rgd, ip)) {
|
||||
ip->i_rgd = rgd;
|
||||
return 0;
|
||||
}
|
||||
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);
|
||||
/* fall through */
|
||||
case GLR_TRYFAILED:
|
||||
rgd = recent_rgrp_next(rgd);
|
||||
break;
|
||||
|
||||
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;
|
||||
|
||||
default:
|
||||
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)
|
||||
rgd = gfs2_rgrpd_get_next(rgd);
|
||||
if (rgd == begin)
|
||||
loops++;
|
||||
flags = 0;
|
||||
if (loops == 2)
|
||||
gfs2_log_flush(sdp, NULL);
|
||||
break;
|
||||
default:
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
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;
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
/**
|
||||
* gfs2_inplace_reserve_i - Reserve space in the filesystem
|
||||
* gfs2_inplace_reserve - Reserve space in the filesystem
|
||||
* @ip: the inode to reserve space for
|
||||
*
|
||||
* Returns: errno
|
||||
*/
|
||||
|
||||
int gfs2_inplace_reserve_i(struct gfs2_inode *ip, int hold_rindex,
|
||||
char *file, unsigned int line)
|
||||
int gfs2_inplace_reserve(struct gfs2_inode *ip)
|
||||
{
|
||||
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
|
||||
struct gfs2_alloc *al = ip->i_alloc;
|
||||
|
@ -1191,45 +1041,22 @@ int gfs2_inplace_reserve_i(struct gfs2_inode *ip, int hold_rindex,
|
|||
if (gfs2_assert_warn(sdp, al->al_requested))
|
||||
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 {
|
||||
error = get_local_rgrp(ip, &last_unlinked);
|
||||
/* If there is no space, flushing the log may release some */
|
||||
if (error) {
|
||||
if (ip == GFS2_I(sdp->sd_rindex) &&
|
||||
!sdp->sd_rindex_uptodate) {
|
||||
error = gfs2_ri_update(ip);
|
||||
if (error)
|
||||
return error;
|
||||
goto try_again;
|
||||
}
|
||||
gfs2_log_flush(sdp, NULL);
|
||||
if (error != -ENOSPC)
|
||||
break;
|
||||
/* Check that fs hasn't grown if writing to rindex */
|
||||
if (ip == GFS2_I(sdp->sd_rindex) && !sdp->sd_rindex_uptodate) {
|
||||
error = gfs2_ri_update(ip);
|
||||
if (error)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
} while (error && tries++ < 3);
|
||||
/* Flushing the log may release space */
|
||||
gfs2_log_flush(sdp, NULL);
|
||||
} while (tries++ < 3);
|
||||
|
||||
if (error) {
|
||||
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 @@ try_again:
|
|||
|
||||
void gfs2_inplace_release(struct gfs2_inode *ip)
|
||||
{
|
||||
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
|
||||
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)
|
||||
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 @@ do_search:
|
|||
/* The GFS2_BLKST_UNLINKED state doesn't apply to the clone
|
||||
bitmaps, so we must search the originals for that. */
|
||||
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)
|
||||
buffer = bi->bi_clone + bi->bi_offset;
|
||||
|
||||
|
@ -1371,6 +1189,7 @@ skip:
|
|||
|
||||
if (blk == BFITNOENT)
|
||||
return blk;
|
||||
|
||||
*n = 1;
|
||||
if (old_state == new_state)
|
||||
goto out;
|
||||
|
@ -1503,7 +1322,7 @@ int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n)
|
|||
if (al == NULL)
|
||||
return -ECANCELED;
|
||||
|
||||
rgd = al->al_rgd;
|
||||
rgd = ip->i_rgd;
|
||||
|
||||
if (rgrp_contains_block(rgd, ip->i_goal))
|
||||
goal = ip->i_goal - rgd->rd_data0;
|
||||
|
@ -1518,7 +1337,7 @@ int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n)
|
|||
|
||||
rgd->rd_last_alloc = blk;
|
||||
block = rgd->rd_data0 + blk;
|
||||
ip->i_goal = block;
|
||||
ip->i_goal = block + *n - 1;
|
||||
error = gfs2_meta_inode_buffer(ip, &dibh);
|
||||
if (error == 0) {
|
||||
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)
|
|||
gfs2_statfs_change(sdp, 0, -(s64)*n, 0);
|
||||
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;
|
||||
spin_unlock(&sdp->sd_rindex_spin);
|
||||
trace_gfs2_block_alloc(ip, block, *n, GFS2_BLKST_USED);
|
||||
*bn = block;
|
||||
return 0;
|
||||
|
@ -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_alloc *al = dip->i_alloc;
|
||||
struct gfs2_rgrpd *rgd = al->al_rgd;
|
||||
struct gfs2_rgrpd *rgd = dip->i_rgd;
|
||||
u32 blk;
|
||||
u64 block;
|
||||
unsigned int n = 1;
|
||||
|
@ -1594,9 +1411,7 @@ int gfs2_alloc_di(struct gfs2_inode *dip, u64 *bn, u64 *generation)
|
|||
gfs2_statfs_change(sdp, 0, -1, +1);
|
||||
gfs2_trans_add_unrevoke(sdp, block, 1);
|
||||
|
||||
spin_lock(&sdp->sd_rindex_spin);
|
||||
rgd->rd_free_clone--;
|
||||
spin_unlock(&sdp->sd_rindex_spin);
|
||||
trace_gfs2_block_alloc(dip, block, 1, GFS2_BLKST_DINODE);
|
||||
*bn = block;
|
||||
return 0;
|
||||
|
@ -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_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 */
|
||||
if (meta || ip->i_depth)
|
||||
gfs2_meta_wipe(ip, bstart, blen);
|
||||
|
@ -1666,7 +1479,6 @@ void gfs2_unlink_di(struct inode *inode)
|
|||
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_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)
|
||||
|
@ -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_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)
|
|||
int gfs2_check_blk_type(struct gfs2_sbd *sdp, u64 no_addr, unsigned int type)
|
||||
{
|
||||
struct gfs2_rgrpd *rgd;
|
||||
struct gfs2_holder ri_gh, rgd_gh;
|
||||
struct gfs2_inode *ip = GFS2_I(sdp->sd_rindex);
|
||||
int ri_locked = 0;
|
||||
struct gfs2_holder rgd_gh;
|
||||
int error;
|
||||
|
||||
if (!gfs2_glock_is_locked_by_me(ip->i_gl)) {
|
||||
error = gfs2_rindex_hold(sdp, &ri_gh);
|
||||
if (error)
|
||||
goto fail;
|
||||
ri_locked = 1;
|
||||
}
|
||||
error = gfs2_rindex_update(sdp);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = -EINVAL;
|
||||
rgd = gfs2_blk2rgrpd(sdp, no_addr);
|
||||
if (!rgd)
|
||||
goto fail_rindex;
|
||||
goto fail;
|
||||
|
||||
error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_SHARED, 0, &rgd_gh);
|
||||
if (error)
|
||||
goto fail_rindex;
|
||||
goto fail;
|
||||
|
||||
if (gfs2_get_block_type(rgd, no_addr) != type)
|
||||
error = -ESTALE;
|
||||
|
||||
gfs2_glock_dq_uninit(&rgd_gh);
|
||||
fail_rindex:
|
||||
if (ri_locked)
|
||||
gfs2_glock_dq_uninit(&ri_gh);
|
||||
fail:
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* gfs2_rlist_add - add a RG to a list of RGs
|
||||
* @sdp: the filesystem
|
||||
* @ip: the inode
|
||||
* @rlist: the list of resource groups
|
||||
* @block: the block
|
||||
*
|
||||
|
@ -1758,9 +1561,10 @@ fail:
|
|||
*
|
||||
*/
|
||||
|
||||
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)
|
||||
{
|
||||
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
|
||||
struct gfs2_rgrpd *rgd;
|
||||
struct gfs2_rgrpd **tmp;
|
||||
unsigned int new_space;
|
||||
|
@ -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))
|
||||
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 (gfs2_consist(sdp))
|
||||
fs_err(sdp, "block = %llu\n", (unsigned long long)block);
|
||||
fs_err(sdp, "rlist_add: no rgrp for block %llu\n", (unsigned long long)block);
|
||||
return;
|
||||
}
|
||||
ip->i_rgd = rgd;
|
||||
|
||||
for (x = 0; x < rlist->rl_rgrps; x++)
|
||||
if (rlist->rl_rgd[x] == rgd)
|
||||
|
|
|
@ -18,18 +18,15 @@ struct gfs2_holder;
|
|||
|
||||
extern void gfs2_rgrp_verify(struct gfs2_rgrpd *rgd);
|
||||
|
||||
struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk);
|
||||
struct gfs2_rgrpd *gfs2_rgrpd_get_first(struct gfs2_sbd *sdp);
|
||||
struct gfs2_rgrpd *gfs2_rgrpd_get_next(struct gfs2_rgrpd *rgd);
|
||||
extern struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk);
|
||||
extern struct gfs2_rgrpd *gfs2_rgrpd_get_first(struct gfs2_sbd *sdp);
|
||||
extern struct gfs2_rgrpd *gfs2_rgrpd_get_next(struct gfs2_rgrpd *rgd);
|
||||
|
||||
extern void gfs2_clear_rgrpd(struct gfs2_sbd *sdp);
|
||||
extern int gfs2_rindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ri_gh);
|
||||
|
||||
extern int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd);
|
||||
extern void gfs2_rgrp_bh_hold(struct gfs2_rgrpd *rgd);
|
||||
extern void gfs2_rgrp_bh_put(struct gfs2_rgrpd *rgd);
|
||||
|
||||
extern void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd);
|
||||
extern int gfs2_rindex_update(struct gfs2_sbd *sdp);
|
||||
extern void gfs2_free_clones(struct gfs2_rgrpd *rgd);
|
||||
extern int gfs2_rgrp_go_lock(struct gfs2_holder *gh);
|
||||
extern void gfs2_rgrp_go_unlock(struct gfs2_holder *gh);
|
||||
|
||||
extern struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip);
|
||||
static inline void gfs2_alloc_put(struct gfs2_inode *ip)
|
||||
|
@ -39,16 +36,9 @@ static inline void gfs2_alloc_put(struct gfs2_inode *ip)
|
|||
ip->i_alloc = NULL;
|
||||
}
|
||||
|
||||
extern int gfs2_inplace_reserve_i(struct gfs2_inode *ip, int hold_rindex,
|
||||
char *file, unsigned int line);
|
||||
#define gfs2_inplace_reserve(ip) \
|
||||
gfs2_inplace_reserve_i((ip), 1, __FILE__, __LINE__)
|
||||
#define gfs2_inplace_reserve_ri(ip) \
|
||||
gfs2_inplace_reserve_i((ip), 0, __FILE__, __LINE__)
|
||||
|
||||
extern int gfs2_inplace_reserve(struct gfs2_inode *ip);
|
||||
extern void gfs2_inplace_release(struct gfs2_inode *ip);
|
||||
|
||||
extern int gfs2_ri_update(struct gfs2_inode *ip);
|
||||
extern int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n);
|
||||
extern int gfs2_alloc_di(struct gfs2_inode *ip, u64 *bn, u64 *generation);
|
||||
|
||||
|
@ -66,11 +56,14 @@ struct gfs2_rgrp_list {
|
|||
struct gfs2_holder *rl_ghs;
|
||||
};
|
||||
|
||||
extern void gfs2_rlist_add(struct gfs2_sbd *sdp, struct gfs2_rgrp_list *rlist,
|
||||
extern void gfs2_rlist_add(struct gfs2_inode *ip, struct gfs2_rgrp_list *rlist,
|
||||
u64 block);
|
||||
extern void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, unsigned int state);
|
||||
extern void gfs2_rlist_free(struct gfs2_rgrp_list *rlist);
|
||||
extern u64 gfs2_ri_total(struct gfs2_sbd *sdp);
|
||||
extern int gfs2_rgrp_dump(struct seq_file *seq, const struct gfs2_glock *gl);
|
||||
extern void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
|
||||
struct buffer_head *bh,
|
||||
const struct gfs2_bitmap *bi);
|
||||
|
||||
#endif /* __RGRP_DOT_H__ */
|
||||
|
|
134
fs/gfs2/super.c
134
fs/gfs2/super.c
|
@ -752,53 +752,79 @@ static int gfs2_write_inode(struct inode *inode, struct writeback_control *wbc)
|
|||
struct gfs2_sbd *sdp = GFS2_SB(inode);
|
||||
struct address_space *metamapping = gfs2_glock2aspace(ip->i_gl);
|
||||
struct backing_dev_info *bdi = metamapping->backing_dev_info;
|
||||
struct gfs2_holder gh;
|
||||
struct buffer_head *bh;
|
||||
struct timespec atime;
|
||||
struct gfs2_dinode *di;
|
||||
int ret = -EAGAIN;
|
||||
int unlock_required = 0;
|
||||
int ret = 0;
|
||||
|
||||
/* Skip timestamp update, if this is from a memalloc */
|
||||
if (current->flags & PF_MEMALLOC)
|
||||
goto do_flush;
|
||||
if (!gfs2_glock_is_locked_by_me(ip->i_gl)) {
|
||||
ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
|
||||
if (ret)
|
||||
goto do_flush;
|
||||
unlock_required = 1;
|
||||
}
|
||||
ret = gfs2_trans_begin(sdp, RES_DINODE, 0);
|
||||
if (ret)
|
||||
goto do_unlock;
|
||||
ret = gfs2_meta_inode_buffer(ip, &bh);
|
||||
if (ret == 0) {
|
||||
di = (struct gfs2_dinode *)bh->b_data;
|
||||
atime.tv_sec = be64_to_cpu(di->di_atime);
|
||||
atime.tv_nsec = be32_to_cpu(di->di_atime_nsec);
|
||||
if (timespec_compare(&inode->i_atime, &atime) > 0) {
|
||||
gfs2_trans_add_bh(ip->i_gl, bh, 1);
|
||||
gfs2_dinode_out(ip, bh->b_data);
|
||||
}
|
||||
brelse(bh);
|
||||
}
|
||||
gfs2_trans_end(sdp);
|
||||
do_unlock:
|
||||
if (unlock_required)
|
||||
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))
|
||||
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 gfs2_holder gh;
|
||||
int need_unlock = 0;
|
||||
int need_endtrans = 0;
|
||||
int ret;
|
||||
|
||||
if (!(flags & (I_DIRTY_DATASYNC|I_DIRTY_SYNC)))
|
||||
return;
|
||||
|
||||
if (!gfs2_glock_is_locked_by_me(ip->i_gl)) {
|
||||
ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
|
||||
if (ret) {
|
||||
fs_err(sdp, "dirty_inode: glock %d\n", ret);
|
||||
return;
|
||||
}
|
||||
need_unlock = 1;
|
||||
}
|
||||
|
||||
if (current->journal_info == NULL) {
|
||||
ret = gfs2_trans_begin(sdp, RES_DINODE, 0);
|
||||
if (ret) {
|
||||
fs_err(sdp, "dirty_inode: gfs2_trans_begin %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
need_endtrans = 1;
|
||||
}
|
||||
|
||||
ret = gfs2_meta_inode_buffer(ip, &bh);
|
||||
if (ret == 0) {
|
||||
gfs2_trans_add_bh(ip->i_gl, bh, 1);
|
||||
gfs2_dinode_out(ip, bh->b_data);
|
||||
brelse(bh);
|
||||
}
|
||||
|
||||
if (need_endtrans)
|
||||
gfs2_trans_end(sdp);
|
||||
out:
|
||||
if (need_unlock)
|
||||
gfs2_glock_dq_uninit(&gh);
|
||||
}
|
||||
|
||||
/**
|
||||
* gfs2_make_fs_ro - Turn a Read-Write FS into a Read-Only one
|
||||
* @sdp: the filesystem
|
||||
|
@ -1011,7 +1037,6 @@ static int statfs_slow_fill(struct gfs2_rgrpd *rgd,
|
|||
|
||||
static int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change_host *sc)
|
||||
{
|
||||
struct gfs2_holder ri_gh;
|
||||
struct gfs2_rgrpd *rgd_next;
|
||||
struct gfs2_holder *gha, *gh;
|
||||
unsigned int slots = 64;
|
||||
|
@ -1024,10 +1049,6 @@ static int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change_host
|
|||
if (!gha)
|
||||
return -ENOMEM;
|
||||
|
||||
error = gfs2_rindex_hold(sdp, &ri_gh);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
rgd_next = gfs2_rgrpd_get_first(sdp);
|
||||
|
||||
for (;;) {
|
||||
|
@ -1070,9 +1091,6 @@ static int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change_host
|
|||
yield();
|
||||
}
|
||||
|
||||
gfs2_glock_dq_uninit(&ri_gh);
|
||||
|
||||
out:
|
||||
kfree(gha);
|
||||
return error;
|
||||
}
|
||||
|
@ -1124,6 +1142,10 @@ static int gfs2_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|||
struct gfs2_statfs_change_host sc;
|
||||
int error;
|
||||
|
||||
error = gfs2_rindex_update(sdp);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (gfs2_tune_get(sdp, gt_statfs_slow))
|
||||
error = gfs2_statfs_slow(sdp, &sc);
|
||||
else
|
||||
|
@ -1394,21 +1416,17 @@ static int gfs2_dinode_dealloc(struct gfs2_inode *ip)
|
|||
if (error)
|
||||
goto out;
|
||||
|
||||
error = gfs2_rindex_hold(sdp, &al->al_ri_gh);
|
||||
if (error)
|
||||
goto out_qs;
|
||||
|
||||
rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr);
|
||||
if (!rgd) {
|
||||
gfs2_consist_inode(ip);
|
||||
error = -EIO;
|
||||
goto out_rindex_relse;
|
||||
goto out_qs;
|
||||
}
|
||||
|
||||
error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0,
|
||||
&al->al_rgd_gh);
|
||||
if (error)
|
||||
goto out_rindex_relse;
|
||||
goto out_qs;
|
||||
|
||||
error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_STATFS + RES_QUOTA,
|
||||
sdp->sd_jdesc->jd_blocks);
|
||||
|
@ -1423,8 +1441,6 @@ static int gfs2_dinode_dealloc(struct gfs2_inode *ip)
|
|||
|
||||
out_rg_gunlock:
|
||||
gfs2_glock_dq_uninit(&al->al_rgd_gh);
|
||||
out_rindex_relse:
|
||||
gfs2_glock_dq_uninit(&al->al_ri_gh);
|
||||
out_qs:
|
||||
gfs2_quota_unhold(ip);
|
||||
out:
|
||||
|
@ -1471,9 +1487,11 @@ static void gfs2_evict_inode(struct inode *inode)
|
|||
goto out;
|
||||
}
|
||||
|
||||
error = gfs2_check_blk_type(sdp, ip->i_no_addr, GFS2_BLKST_UNLINKED);
|
||||
if (error)
|
||||
goto out_truncate;
|
||||
if (!test_bit(GIF_ALLOC_FAILED, &ip->i_flags)) {
|
||||
error = gfs2_check_blk_type(sdp, ip->i_no_addr, GFS2_BLKST_UNLINKED);
|
||||
if (error)
|
||||
goto out_truncate;
|
||||
}
|
||||
|
||||
if (test_bit(GIF_INVALID, &ip->i_flags)) {
|
||||
error = gfs2_inode_refresh(ip);
|
||||
|
@ -1513,6 +1531,10 @@ static void gfs2_evict_inode(struct inode *inode)
|
|||
goto out_unlock;
|
||||
|
||||
out_truncate:
|
||||
gfs2_log_flush(sdp, ip->i_gl);
|
||||
write_inode_now(inode, 1);
|
||||
gfs2_ail_flush(ip->i_gl, 0);
|
||||
|
||||
/* Case 2 starts here */
|
||||
error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks);
|
||||
if (error)
|
||||
|
@ -1552,6 +1574,7 @@ static struct inode *gfs2_alloc_inode(struct super_block *sb)
|
|||
if (ip) {
|
||||
ip->i_flags = 0;
|
||||
ip->i_gl = NULL;
|
||||
ip->i_rgd = NULL;
|
||||
}
|
||||
return &ip->i_inode;
|
||||
}
|
||||
|
@ -1572,6 +1595,7 @@ const struct super_operations gfs2_super_ops = {
|
|||
.alloc_inode = gfs2_alloc_inode,
|
||||
.destroy_inode = gfs2_destroy_inode,
|
||||
.write_inode = gfs2_write_inode,
|
||||
.dirty_inode = gfs2_dirty_inode,
|
||||
.evict_inode = gfs2_evict_inode,
|
||||
.put_super = gfs2_put_super,
|
||||
.sync_fs = gfs2_sync_fs,
|
||||
|
|
|
@ -185,8 +185,3 @@ void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno, unsigned int len)
|
|||
gfs2_log_unlock(sdp);
|
||||
}
|
||||
|
||||
void gfs2_trans_add_rg(struct gfs2_rgrpd *rgd)
|
||||
{
|
||||
lops_add(rgd->rd_sbd, &rgd->rd_le);
|
||||
}
|
||||
|
||||
|
|
|
@ -28,20 +28,20 @@ struct gfs2_glock;
|
|||
|
||||
/* reserve either the number of blocks to be allocated plus the rg header
|
||||
* block, or all of the blocks in the rg, whichever is smaller */
|
||||
static inline unsigned int gfs2_rg_blocks(const struct gfs2_alloc *al)
|
||||
static inline unsigned int gfs2_rg_blocks(const struct gfs2_inode *ip)
|
||||
{
|
||||
return (al->al_requested < al->al_rgd->rd_length)?
|
||||
al->al_requested + 1 : al->al_rgd->rd_length;
|
||||
const struct gfs2_alloc *al = ip->i_alloc;
|
||||
if (al->al_requested < ip->i_rgd->rd_length)
|
||||
return al->al_requested + 1;
|
||||
return ip->i_rgd->rd_length;
|
||||
}
|
||||
|
||||
int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks,
|
||||
unsigned int revokes);
|
||||
extern int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks,
|
||||
unsigned int revokes);
|
||||
|
||||
void gfs2_trans_end(struct gfs2_sbd *sdp);
|
||||
|
||||
void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta);
|
||||
void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd);
|
||||
void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno, unsigned int len);
|
||||
void gfs2_trans_add_rg(struct gfs2_rgrpd *rgd);
|
||||
extern void gfs2_trans_end(struct gfs2_sbd *sdp);
|
||||
extern void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta);
|
||||
extern void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd);
|
||||
extern void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno, unsigned int len);
|
||||
|
||||
#endif /* __TRANS_DOT_H__ */
|
||||
|
|
|
@ -332,15 +332,8 @@ static int ea_remove_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh,
|
|||
if (error)
|
||||
goto out_alloc;
|
||||
|
||||
error = gfs2_rindex_hold(GFS2_SB(&ip->i_inode), &al->al_ri_gh);
|
||||
if (error)
|
||||
goto out_quota;
|
||||
|
||||
error = ea_dealloc_unstuffed(ip, bh, ea, prev, (leave) ? &error : NULL);
|
||||
|
||||
gfs2_glock_dq_uninit(&al->al_ri_gh);
|
||||
|
||||
out_quota:
|
||||
gfs2_quota_unhold(ip);
|
||||
out_alloc:
|
||||
gfs2_alloc_put(ip);
|
||||
|
@ -734,7 +727,7 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er,
|
|||
goto out_gunlock_q;
|
||||
|
||||
error = gfs2_trans_begin(GFS2_SB(&ip->i_inode),
|
||||
blks + gfs2_rg_blocks(al) +
|
||||
blks + gfs2_rg_blocks(ip) +
|
||||
RES_DINODE + RES_STATFS + RES_QUOTA, 0);
|
||||
if (error)
|
||||
goto out_ipres;
|
||||
|
@ -1296,7 +1289,8 @@ fail:
|
|||
|
||||
int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data)
|
||||
{
|
||||
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
|
||||
struct inode *inode = &ip->i_inode;
|
||||
struct gfs2_sbd *sdp = GFS2_SB(inode);
|
||||
struct gfs2_ea_location el;
|
||||
int error;
|
||||
|
||||
|
@ -1319,7 +1313,7 @@ int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data)
|
|||
if (error)
|
||||
return error;
|
||||
|
||||
error = gfs2_setattr_simple(ip, attr);
|
||||
error = gfs2_setattr_simple(inode, attr);
|
||||
gfs2_trans_end(sdp);
|
||||
return error;
|
||||
}
|
||||
|
@ -1362,14 +1356,14 @@ static int ea_dealloc_indirect(struct gfs2_inode *ip)
|
|||
blen++;
|
||||
else {
|
||||
if (bstart)
|
||||
gfs2_rlist_add(sdp, &rlist, bstart);
|
||||
gfs2_rlist_add(ip, &rlist, bstart);
|
||||
bstart = bn;
|
||||
blen = 1;
|
||||
}
|
||||
blks++;
|
||||
}
|
||||
if (bstart)
|
||||
gfs2_rlist_add(sdp, &rlist, bstart);
|
||||
gfs2_rlist_add(ip, &rlist, bstart);
|
||||
else
|
||||
goto out;
|
||||
|
||||
|
@ -1501,24 +1495,18 @@ int gfs2_ea_dealloc(struct gfs2_inode *ip)
|
|||
if (error)
|
||||
goto out_alloc;
|
||||
|
||||
error = gfs2_rindex_hold(GFS2_SB(&ip->i_inode), &al->al_ri_gh);
|
||||
if (error)
|
||||
goto out_quota;
|
||||
|
||||
error = ea_foreach(ip, ea_dealloc_unstuffed, NULL);
|
||||
if (error)
|
||||
goto out_rindex;
|
||||
goto out_quota;
|
||||
|
||||
if (ip->i_diskflags & GFS2_DIF_EA_INDIRECT) {
|
||||
error = ea_dealloc_indirect(ip);
|
||||
if (error)
|
||||
goto out_rindex;
|
||||
goto out_quota;
|
||||
}
|
||||
|
||||
error = ea_dealloc_block(ip);
|
||||
|
||||
out_rindex:
|
||||
gfs2_glock_dq_uninit(&al->al_ri_gh);
|
||||
out_quota:
|
||||
gfs2_quota_unhold(ip);
|
||||
out_alloc:
|
||||
|
|
Загрузка…
Ссылка в новой задаче