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