[GFS2] Readpages support
This adds readpages support (and also corrects a small bug in the readpage error path at the same time). Hopefully this will improve performance by allowing GFS to submit larger lumps of I/O at a time. In order to simplify the setting of BH_Boundary, it currently gets set when we hit the end of a indirect pointer block. There is always a boundary at this point with the current allocation code. It doesn't get all the boundaries right though, so there is still room for improvement in this. See comments in fs/gfs2/ops_address.c for further information about readpages with GFS2. Signed-off-by: Steven Whitehouse
This commit is contained in:
Родитель
5bb76af1e0
Коммит
fd88de569b
170
fs/gfs2/bmap.c
170
fs/gfs2/bmap.c
|
@ -314,13 +314,17 @@ static void find_metapath(struct gfs2_inode *ip, uint64_t block,
|
|||
* metadata tree.
|
||||
*/
|
||||
|
||||
static inline uint64_t *metapointer(struct buffer_head *bh,
|
||||
unsigned int height, struct metapath *mp)
|
||||
static inline u64 *metapointer(struct buffer_head *bh, int *boundary,
|
||||
unsigned int height, const struct metapath *mp)
|
||||
{
|
||||
unsigned int head_size = (height > 0) ?
|
||||
sizeof(struct gfs2_meta_header) : sizeof(struct gfs2_dinode);
|
||||
|
||||
return ((uint64_t *)(bh->b_data + head_size)) + mp->mp_list[height];
|
||||
u64 *ptr;
|
||||
*boundary = 0;
|
||||
ptr = ((u64 *)(bh->b_data + head_size)) + mp->mp_list[height];
|
||||
if (ptr + 1 == (u64*)(bh->b_data + bh->b_size))
|
||||
*boundary = 1;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -339,24 +343,24 @@ static inline uint64_t *metapointer(struct buffer_head *bh,
|
|||
*
|
||||
*/
|
||||
|
||||
static void lookup_block(struct gfs2_inode *ip, struct buffer_head *bh,
|
||||
unsigned int height, struct metapath *mp, int create,
|
||||
int *new, uint64_t *block)
|
||||
static int lookup_block(struct gfs2_inode *ip, struct buffer_head *bh,
|
||||
unsigned int height, struct metapath *mp, int create,
|
||||
int *new, uint64_t *block)
|
||||
{
|
||||
uint64_t *ptr = metapointer(bh, height, mp);
|
||||
int boundary;
|
||||
uint64_t *ptr = metapointer(bh, &boundary, height, mp);
|
||||
|
||||
if (*ptr) {
|
||||
*block = be64_to_cpu(*ptr);
|
||||
return;
|
||||
return boundary;
|
||||
}
|
||||
|
||||
*block = 0;
|
||||
|
||||
if (!create)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
if (height == ip->i_di.di_height - 1 &&
|
||||
!gfs2_is_dir(ip))
|
||||
if (height == ip->i_di.di_height - 1 && !gfs2_is_dir(ip))
|
||||
*block = gfs2_alloc_data(ip);
|
||||
else
|
||||
*block = gfs2_alloc_meta(ip);
|
||||
|
@ -367,15 +371,16 @@ static void lookup_block(struct gfs2_inode *ip, struct buffer_head *bh,
|
|||
ip->i_di.di_blocks++;
|
||||
|
||||
*new = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* gfs2_block_map - Map a block from an inode to a disk block
|
||||
* @ip: The GFS2 inode
|
||||
* gfs2_block_pointers - Map a block from an inode to a disk block
|
||||
* @inode: The inode
|
||||
* @lblock: The logical block number
|
||||
* @new: Value/Result argument (1 = may create/did create new blocks)
|
||||
* @dblock: the disk block number of the start of an extent
|
||||
* @extlen: the size of the extent
|
||||
* @boundary: gets set if we've hit a block boundary
|
||||
* @mp: metapath to use
|
||||
*
|
||||
* Find the block number on the current device which corresponds to an
|
||||
* inode's block. If the block had to be created, "new" will be set.
|
||||
|
@ -383,12 +388,14 @@ static void lookup_block(struct gfs2_inode *ip, struct buffer_head *bh,
|
|||
* Returns: errno
|
||||
*/
|
||||
|
||||
int gfs2_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new,
|
||||
uint64_t *dblock, uint32_t *extlen)
|
||||
static struct buffer_head *gfs2_block_pointers(struct inode *inode, u64 lblock,
|
||||
int *new, u64 *dblock,
|
||||
int *boundary,
|
||||
struct metapath *mp)
|
||||
{
|
||||
struct gfs2_inode *ip = inode->u.generic_ip;
|
||||
struct gfs2_sbd *sdp = ip->i_sbd;
|
||||
struct buffer_head *bh;
|
||||
struct metapath mp;
|
||||
int create = *new;
|
||||
unsigned int bsize;
|
||||
unsigned int height;
|
||||
|
@ -398,13 +405,6 @@ int gfs2_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new,
|
|||
|
||||
*new = 0;
|
||||
*dblock = 0;
|
||||
if (extlen)
|
||||
*extlen = 0;
|
||||
|
||||
if (create)
|
||||
down_write(&ip->i_rw_mutex);
|
||||
else
|
||||
down_read(&ip->i_rw_mutex);
|
||||
|
||||
if (gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip)))
|
||||
goto out;
|
||||
|
@ -421,7 +421,7 @@ int gfs2_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new,
|
|||
goto out;
|
||||
}
|
||||
|
||||
find_metapath(ip, lblock, &mp);
|
||||
find_metapath(ip, lblock, mp);
|
||||
end_of_metadata = ip->i_di.di_height - 1;
|
||||
|
||||
error = gfs2_meta_inode_buffer(ip, &bh);
|
||||
|
@ -429,7 +429,7 @@ int gfs2_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new,
|
|||
goto out;
|
||||
|
||||
for (x = 0; x < end_of_metadata; x++) {
|
||||
lookup_block(ip, bh, x, &mp, create, new, dblock);
|
||||
lookup_block(ip, bh, x, mp, create, new, dblock);
|
||||
brelse(bh);
|
||||
if (!*dblock)
|
||||
goto out;
|
||||
|
@ -439,49 +439,95 @@ int gfs2_block_map(struct gfs2_inode *ip, uint64_t lblock, int *new,
|
|||
goto out;
|
||||
}
|
||||
|
||||
lookup_block(ip, bh, end_of_metadata, &mp, create, new, dblock);
|
||||
|
||||
if (extlen && *dblock) {
|
||||
*extlen = 1;
|
||||
|
||||
if (!*new) {
|
||||
uint64_t tmp_dblock;
|
||||
int tmp_new;
|
||||
unsigned int nptrs;
|
||||
|
||||
nptrs = (end_of_metadata) ? sdp->sd_inptrs :
|
||||
sdp->sd_diptrs;
|
||||
|
||||
while (++mp.mp_list[end_of_metadata] < nptrs) {
|
||||
lookup_block(ip, bh, end_of_metadata, &mp,
|
||||
0, &tmp_new, &tmp_dblock);
|
||||
|
||||
if (*dblock + *extlen != tmp_dblock)
|
||||
break;
|
||||
|
||||
(*extlen)++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
brelse(bh);
|
||||
|
||||
*boundary = lookup_block(ip, bh, end_of_metadata, mp, create, new, dblock);
|
||||
if (*new) {
|
||||
error = gfs2_meta_inode_buffer(ip, &bh);
|
||||
struct buffer_head *dibh;
|
||||
error = gfs2_meta_inode_buffer(ip, &dibh);
|
||||
if (!error) {
|
||||
gfs2_trans_add_bh(ip->i_gl, bh, 1);
|
||||
gfs2_dinode_out(&ip->i_di, bh->b_data);
|
||||
brelse(bh);
|
||||
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
|
||||
gfs2_dinode_out(&ip->i_di, dibh->b_data);
|
||||
brelse(dibh);
|
||||
}
|
||||
}
|
||||
return bh;
|
||||
out:
|
||||
return ERR_PTR(error);
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
static inline void bmap_lock(struct inode *inode, int create)
|
||||
{
|
||||
struct gfs2_inode *ip = inode->u.generic_ip;
|
||||
if (create)
|
||||
down_write(&ip->i_rw_mutex);
|
||||
else
|
||||
down_read(&ip->i_rw_mutex);
|
||||
}
|
||||
|
||||
static inline void bmap_unlock(struct inode *inode, int create)
|
||||
{
|
||||
struct gfs2_inode *ip = inode->u.generic_ip;
|
||||
if (create)
|
||||
up_write(&ip->i_rw_mutex);
|
||||
else
|
||||
up_read(&ip->i_rw_mutex);
|
||||
}
|
||||
|
||||
return error;
|
||||
int gfs2_block_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, int *boundary)
|
||||
{
|
||||
struct metapath mp;
|
||||
struct buffer_head *bh;
|
||||
int create = *new;
|
||||
|
||||
bmap_lock(inode, create);
|
||||
bh = gfs2_block_pointers(inode, lblock, new, dblock, boundary, &mp);
|
||||
bmap_unlock(inode, create);
|
||||
if (!bh)
|
||||
return 0;
|
||||
if (IS_ERR(bh))
|
||||
return PTR_ERR(bh);
|
||||
brelse(bh);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen)
|
||||
{
|
||||
struct gfs2_inode *ip = inode->u.generic_ip;
|
||||
struct gfs2_sbd *sdp = ip->i_sbd;
|
||||
struct metapath mp;
|
||||
struct buffer_head *bh;
|
||||
int boundary;
|
||||
int create = *new;
|
||||
|
||||
BUG_ON(!extlen);
|
||||
BUG_ON(!dblock);
|
||||
BUG_ON(!new);
|
||||
|
||||
bmap_lock(inode, create);
|
||||
bh = gfs2_block_pointers(inode, lblock, new, dblock, &boundary, &mp);
|
||||
*extlen = 1;
|
||||
|
||||
if (bh && !IS_ERR(bh) && *dblock && !*new) {
|
||||
u64 tmp_dblock;
|
||||
int tmp_new;
|
||||
unsigned int nptrs;
|
||||
unsigned end_of_metadata = ip->i_di.di_height - 1;
|
||||
|
||||
nptrs = (end_of_metadata) ? sdp->sd_inptrs : sdp->sd_diptrs;
|
||||
while (++mp.mp_list[end_of_metadata] < nptrs) {
|
||||
lookup_block(ip, bh, end_of_metadata, &mp, 0, &tmp_new, &tmp_dblock);
|
||||
if (*dblock + *extlen != tmp_dblock)
|
||||
break;
|
||||
(*extlen)++;
|
||||
}
|
||||
}
|
||||
bmap_unlock(inode, create);
|
||||
if (!bh)
|
||||
return 0;
|
||||
if (IS_ERR(bh))
|
||||
return PTR_ERR(bh);
|
||||
brelse(bh);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1053,7 +1099,7 @@ int gfs2_write_alloc_required(struct gfs2_inode *ip, uint64_t offset,
|
|||
}
|
||||
|
||||
for (; lblock < lblock_stop; lblock += extlen) {
|
||||
error = gfs2_block_map(ip, lblock, &new, &dblock, &extlen);
|
||||
error = gfs2_extent_map(ip->i_vnode, lblock, &new, &dblock, &extlen);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
|
|
@ -16,9 +16,8 @@ typedef int (*gfs2_unstuffer_t) (struct gfs2_inode * ip,
|
|||
int gfs2_unstuff_dinode(struct gfs2_inode *ip, gfs2_unstuffer_t unstuffer,
|
||||
void *private);
|
||||
|
||||
int gfs2_block_map(struct gfs2_inode *ip,
|
||||
uint64_t lblock, int *new,
|
||||
uint64_t *dblock, uint32_t *extlen);
|
||||
int gfs2_block_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, int *boundary);
|
||||
int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen);
|
||||
|
||||
int gfs2_truncatei(struct gfs2_inode *ip, uint64_t size);
|
||||
int gfs2_truncatei_resume(struct gfs2_inode *ip);
|
||||
|
|
|
@ -197,8 +197,8 @@ static int gfs2_dir_write_data(struct gfs2_inode *ip, const char *buf,
|
|||
|
||||
if (!extlen) {
|
||||
new = 1;
|
||||
error = gfs2_block_map(ip, lblock, &new, &dblock,
|
||||
&extlen);
|
||||
error = gfs2_extent_map(ip->i_vnode, lblock, &new,
|
||||
&dblock, &extlen);
|
||||
if (error)
|
||||
goto fail;
|
||||
error = -EIO;
|
||||
|
@ -314,8 +314,8 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf,
|
|||
|
||||
if (!extlen) {
|
||||
new = 0;
|
||||
error = gfs2_block_map(ip, lblock, &new, &dblock,
|
||||
&extlen);
|
||||
error = gfs2_extent_map(ip->i_vnode, lblock, &new,
|
||||
&dblock, &extlen);
|
||||
if (error)
|
||||
goto fail;
|
||||
}
|
||||
|
|
|
@ -2125,7 +2125,7 @@ void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait)
|
|||
mutex_lock(&sdp->sd_invalidate_inodes_mutex);
|
||||
invalidate_inodes(sdp->sd_vfs);
|
||||
mutex_unlock(&sdp->sd_invalidate_inodes_mutex);
|
||||
yield();
|
||||
msleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1606,9 +1606,8 @@ int gfs2_glock_nq_atime(struct gfs2_holder *gh)
|
|||
curtime = get_seconds();
|
||||
if (curtime - ip->i_di.di_atime >= quantum) {
|
||||
gfs2_glock_dq(gh);
|
||||
gfs2_holder_reinit(LM_ST_EXCLUSIVE,
|
||||
gh->gh_flags & ~LM_FLAG_ANY,
|
||||
gh);
|
||||
gfs2_holder_reinit(LM_ST_EXCLUSIVE, gh->gh_flags & ~LM_FLAG_ANY,
|
||||
gh);
|
||||
error = gfs2_glock_nq(gh);
|
||||
if (error)
|
||||
return error;
|
||||
|
|
|
@ -211,9 +211,9 @@ static uint64_t log_bmap(struct gfs2_sbd *sdp, unsigned int lbn)
|
|||
int new = 0;
|
||||
uint64_t dbn;
|
||||
int error;
|
||||
int bdy;
|
||||
|
||||
error = gfs2_block_map(sdp->sd_jdesc->jd_inode->u.generic_ip,
|
||||
lbn, &new, &dbn, NULL);
|
||||
error = gfs2_block_map(sdp->sd_jdesc->jd_inode, lbn, &new, &dbn, &bdy);
|
||||
gfs2_assert_withdraw(sdp, !error && dbn);
|
||||
|
||||
return dbn;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/completion.h>
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/pagevec.h>
|
||||
#include <linux/mpage.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/gfs2_ondisk.h>
|
||||
|
@ -47,12 +48,12 @@
|
|||
int gfs2_get_block(struct inode *inode, sector_t lblock,
|
||||
struct buffer_head *bh_result, int create)
|
||||
{
|
||||
struct gfs2_inode *ip = inode->u.generic_ip;
|
||||
int new = create;
|
||||
uint64_t dblock;
|
||||
int error;
|
||||
int boundary;
|
||||
|
||||
error = gfs2_block_map(ip, lblock, &new, &dblock, NULL);
|
||||
error = gfs2_block_map(inode, lblock, &new, &dblock, &boundary);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
@ -62,6 +63,8 @@ int gfs2_get_block(struct inode *inode, sector_t lblock,
|
|||
map_bh(bh_result, inode->i_sb, dblock);
|
||||
if (new)
|
||||
set_buffer_new(bh_result);
|
||||
if (boundary)
|
||||
set_buffer_boundary(bh_result);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -83,8 +86,9 @@ static int get_block_noalloc(struct inode *inode, sector_t lblock,
|
|||
int new = 0;
|
||||
uint64_t dblock;
|
||||
int error;
|
||||
int boundary;
|
||||
|
||||
error = gfs2_block_map(ip, lblock, &new, &dblock, NULL);
|
||||
error = gfs2_block_map(inode, lblock, &new, &dblock, &boundary);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
@ -92,6 +96,8 @@ static int get_block_noalloc(struct inode *inode, sector_t lblock,
|
|||
map_bh(bh_result, inode->i_sb, dblock);
|
||||
else if (gfs2_assert_withdraw(ip->i_sbd, !create))
|
||||
error = -EIO;
|
||||
if (boundary)
|
||||
set_buffer_boundary(bh_result);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
@ -151,6 +157,19 @@ out_ignore:
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int zero_readpage(struct page *page)
|
||||
{
|
||||
void *kaddr;
|
||||
|
||||
kaddr = kmap_atomic(page, KM_USER0);
|
||||
memset(kaddr, 0, PAGE_CACHE_SIZE);
|
||||
kunmap_atomic(page, KM_USER0);
|
||||
|
||||
SetPageUptodate(page);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* stuffed_readpage - Fill in a Linux page with stuffed file data
|
||||
* @ip: the inode
|
||||
|
@ -165,17 +184,18 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page)
|
|||
void *kaddr;
|
||||
int error;
|
||||
|
||||
/* Only the first page of a stuffed file might contain data */
|
||||
if (unlikely(page->index))
|
||||
return zero_readpage(page);
|
||||
|
||||
error = gfs2_meta_inode_buffer(ip, &dibh);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
kaddr = kmap_atomic(page, KM_USER0);
|
||||
memcpy((char *)kaddr,
|
||||
dibh->b_data + sizeof(struct gfs2_dinode),
|
||||
memcpy(kaddr, dibh->b_data + sizeof(struct gfs2_dinode),
|
||||
ip->i_di.di_size);
|
||||
memset((char *)kaddr + ip->i_di.di_size,
|
||||
0,
|
||||
PAGE_CACHE_SIZE - ip->i_di.di_size);
|
||||
memset(kaddr + ip->i_di.di_size, 0, PAGE_CACHE_SIZE - ip->i_di.di_size);
|
||||
kunmap_atomic(page, KM_USER0);
|
||||
|
||||
brelse(dibh);
|
||||
|
@ -185,19 +205,6 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int zero_readpage(struct page *page)
|
||||
{
|
||||
void *kaddr;
|
||||
|
||||
kaddr = kmap_atomic(page, KM_USER0);
|
||||
memset(kaddr, 0, PAGE_CACHE_SIZE);
|
||||
kunmap_atomic(page, KM_USER0);
|
||||
|
||||
SetPageUptodate(page);
|
||||
unlock_page(page);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* gfs2_readpage - readpage with locking
|
||||
|
@ -215,19 +222,16 @@ static int gfs2_readpage(struct file *file, struct page *page)
|
|||
struct gfs2_holder gh;
|
||||
int error;
|
||||
|
||||
if (file != &gfs2_internal_file_sentinal) {
|
||||
if (likely(file != &gfs2_internal_file_sentinal)) {
|
||||
gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME|GL_AOP, &gh);
|
||||
error = gfs2_glock_nq_m_atime(1, &gh);
|
||||
if (error)
|
||||
if (unlikely(error))
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (gfs2_is_stuffed(ip)) {
|
||||
if (!page->index) {
|
||||
error = stuffed_readpage(ip, page);
|
||||
unlock_page(page);
|
||||
} else
|
||||
error = zero_readpage(page);
|
||||
error = stuffed_readpage(ip, page);
|
||||
unlock_page(page);
|
||||
} else
|
||||
error = mpage_readpage(page, gfs2_get_block);
|
||||
|
||||
|
@ -242,6 +246,90 @@ out:
|
|||
return error;
|
||||
out_unlock:
|
||||
unlock_page(page);
|
||||
if (file != &gfs2_internal_file_sentinal)
|
||||
gfs2_holder_uninit(&gh);
|
||||
goto out;
|
||||
}
|
||||
|
||||
#define list_to_page(head) (list_entry((head)->prev, struct page, lru))
|
||||
|
||||
/**
|
||||
* gfs2_readpages - Read a bunch of pages at once
|
||||
*
|
||||
* Some notes:
|
||||
* 1. This is only for readahead, so we can simply ignore any things
|
||||
* which are slightly inconvenient (such as locking conflicts between
|
||||
* the page lock and the glock) and return having done no I/O. Its
|
||||
* obviously not something we'd want to do on too regular a basis.
|
||||
* Any I/O we ignore at this time will be done via readpage later.
|
||||
* 2. We have to handle stuffed files here too.
|
||||
* 3. mpage_readpages() does most of the heavy lifting in the common case.
|
||||
* 4. gfs2_get_block() is relied upon to set BH_Boundary in the right places.
|
||||
* 5. We use LM_FLAG_TRY_1CB here, effectively we then have lock-ahead as
|
||||
* well as read-ahead.
|
||||
*/
|
||||
static int gfs2_readpages(struct file *file, struct address_space *mapping,
|
||||
struct list_head *pages, unsigned nr_pages)
|
||||
{
|
||||
struct inode *inode = mapping->host;
|
||||
struct gfs2_inode *ip = inode->u.generic_ip;
|
||||
struct gfs2_sbd *sdp = ip->i_sbd;
|
||||
struct gfs2_holder gh;
|
||||
unsigned page_idx;
|
||||
int ret;
|
||||
|
||||
if (likely(file != &gfs2_internal_file_sentinal)) {
|
||||
gfs2_holder_init(ip->i_gl, LM_ST_SHARED,
|
||||
LM_FLAG_TRY_1CB|GL_ATIME|GL_AOP, &gh);
|
||||
ret = gfs2_glock_nq_m_atime(1, &gh);
|
||||
if (ret == GLR_TRYFAILED)
|
||||
goto out_noerror;
|
||||
if (unlikely(ret))
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (gfs2_is_stuffed(ip)) {
|
||||
struct pagevec lru_pvec;
|
||||
pagevec_init(&lru_pvec, 0);
|
||||
for (page_idx = 0; page_idx < nr_pages; page_idx++) {
|
||||
struct page *page = list_to_page(pages);
|
||||
list_del(&page->lru);
|
||||
if (!add_to_page_cache(page, mapping,
|
||||
page->index, GFP_KERNEL)) {
|
||||
ret = stuffed_readpage(ip, page);
|
||||
unlock_page(page);
|
||||
if (!pagevec_add(&lru_pvec, page))
|
||||
__pagevec_lru_add(&lru_pvec);
|
||||
}
|
||||
page_cache_release(page);
|
||||
}
|
||||
pagevec_lru_add(&lru_pvec);
|
||||
ret = 0;
|
||||
} else {
|
||||
/* What we really want to do .... */
|
||||
ret = mpage_readpages(mapping, pages, nr_pages, gfs2_get_block);
|
||||
}
|
||||
|
||||
if (likely(file != &gfs2_internal_file_sentinal)) {
|
||||
gfs2_glock_dq_m(1, &gh);
|
||||
gfs2_holder_uninit(&gh);
|
||||
}
|
||||
out:
|
||||
if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
|
||||
ret = -EIO;
|
||||
return ret;
|
||||
out_noerror:
|
||||
ret = 0;
|
||||
out_unlock:
|
||||
/* unlock all pages, we can't do any I/O right now */
|
||||
for (page_idx = 0; page_idx < nr_pages; page_idx++) {
|
||||
struct page *page = list_to_page(pages);
|
||||
list_del(&page->lru);
|
||||
unlock_page(page);
|
||||
page_cache_release(page);
|
||||
}
|
||||
if (likely(file != &gfs2_internal_file_sentinal))
|
||||
gfs2_holder_uninit(&gh);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -572,6 +660,7 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb,
|
|||
struct address_space_operations gfs2_file_aops = {
|
||||
.writepage = gfs2_writepage,
|
||||
.readpage = gfs2_readpage,
|
||||
.readpages = gfs2_readpages,
|
||||
.sync_page = block_sync_page,
|
||||
.prepare_write = gfs2_prepare_write,
|
||||
.commit_write = gfs2_commit_write,
|
||||
|
|
|
@ -92,7 +92,6 @@ static void gfs2_put_super(struct super_block *sb)
|
|||
if (error)
|
||||
gfs2_io_error(sdp);
|
||||
}
|
||||
|
||||
/* At this point, we're through modifying the disk */
|
||||
|
||||
/* Release stuff */
|
||||
|
@ -125,12 +124,10 @@ static void gfs2_put_super(struct super_block *sb)
|
|||
gfs2_jindex_free(sdp);
|
||||
/* Take apart glock structures and buffer lists */
|
||||
gfs2_gl_hash_clear(sdp, WAIT);
|
||||
|
||||
/* Unmount the locking protocol */
|
||||
gfs2_lm_unmount(sdp);
|
||||
|
||||
/* At this point, we're through participating in the lockspace */
|
||||
|
||||
gfs2_sys_fs_del(sdp);
|
||||
vfree(sdp);
|
||||
sb->s_fs_info = NULL;
|
||||
|
|
|
@ -90,8 +90,7 @@ static int alloc_page_backing(struct gfs2_inode *ip, struct page *page)
|
|||
if (error)
|
||||
goto out_gunlock_q;
|
||||
|
||||
gfs2_write_calc_reserv(ip, PAGE_CACHE_SIZE,
|
||||
&data_blocks, &ind_blocks);
|
||||
gfs2_write_calc_reserv(ip, PAGE_CACHE_SIZE, &data_blocks, &ind_blocks);
|
||||
|
||||
al->al_requested = data_blocks + ind_blocks;
|
||||
|
||||
|
@ -99,8 +98,7 @@ static int alloc_page_backing(struct gfs2_inode *ip, struct page *page)
|
|||
if (error)
|
||||
goto out_gunlock_q;
|
||||
|
||||
error = gfs2_trans_begin(sdp,
|
||||
al->al_rgd->rd_ri.ri_length +
|
||||
error = gfs2_trans_begin(sdp, al->al_rgd->rd_ri.ri_length +
|
||||
ind_blocks + RES_DINODE +
|
||||
RES_STATFS + RES_QUOTA, 0);
|
||||
if (error)
|
||||
|
@ -117,7 +115,7 @@ static int alloc_page_backing(struct gfs2_inode *ip, struct page *page)
|
|||
unsigned int extlen;
|
||||
int new = 1;
|
||||
|
||||
error = gfs2_block_map(ip, lblock, &new, &dblock, &extlen);
|
||||
error = gfs2_extent_map(ip->i_vnode, lblock, &new, &dblock, &extlen);
|
||||
if (error)
|
||||
goto out_trans;
|
||||
|
||||
|
|
|
@ -255,6 +255,7 @@ static int bh_get(struct gfs2_quota_data *qd)
|
|||
int new = 0;
|
||||
struct buffer_head *bh;
|
||||
int error;
|
||||
int boundary;
|
||||
|
||||
mutex_lock(&sdp->sd_quota_mutex);
|
||||
|
||||
|
@ -266,7 +267,7 @@ static int bh_get(struct gfs2_quota_data *qd)
|
|||
block = qd->qd_slot / sdp->sd_qc_per_block;
|
||||
offset = qd->qd_slot % sdp->sd_qc_per_block;;
|
||||
|
||||
error = gfs2_block_map(ip, block, &new, &dblock, NULL);
|
||||
error = gfs2_block_map(ip->i_vnode, block, &new, &dblock, &boundary);
|
||||
if (error)
|
||||
goto fail;
|
||||
error = gfs2_meta_read(ip->i_gl, dblock, DIO_START | DIO_WAIT, &bh);
|
||||
|
@ -1162,7 +1163,7 @@ int gfs2_quota_init(struct gfs2_sbd *sdp)
|
|||
|
||||
if (!extlen) {
|
||||
int new = 0;
|
||||
error = gfs2_block_map(ip, x, &new, &dblock, &extlen);
|
||||
error = gfs2_extent_map(ip->i_vnode, x, &new, &dblock, &extlen);
|
||||
if (error)
|
||||
goto fail;
|
||||
}
|
||||
|
|
|
@ -40,8 +40,7 @@ int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk,
|
|||
uint32_t extlen;
|
||||
int error;
|
||||
|
||||
error = gfs2_block_map(ip, blk, &new, &dblock,
|
||||
&extlen);
|
||||
error = gfs2_extent_map(ip->i_vnode, blk, &new, &dblock, &extlen);
|
||||
if (error)
|
||||
return error;
|
||||
if (!dblock) {
|
||||
|
@ -378,10 +377,11 @@ static int clean_journal(struct gfs2_jdesc *jd, struct gfs2_log_header *head)
|
|||
uint32_t hash;
|
||||
struct buffer_head *bh;
|
||||
int error;
|
||||
|
||||
int boundary;
|
||||
|
||||
lblock = head->lh_blkno;
|
||||
gfs2_replay_incr_blk(sdp, &lblock);
|
||||
error = gfs2_block_map(ip, lblock, &new, &dblock, NULL);
|
||||
error = gfs2_block_map(ip->i_vnode, lblock, &new, &dblock, &boundary);
|
||||
if (error)
|
||||
return error;
|
||||
if (!dblock) {
|
||||
|
|
|
@ -956,8 +956,7 @@ static uint32_t rgblk_search(struct gfs2_rgrpd *rgd, uint32_t goal,
|
|||
search in the first part of our first-searched bit block. */
|
||||
for (x = 0; x <= length; x++) {
|
||||
if (bi->bi_clone)
|
||||
blk = gfs2_bitfit(rgd,
|
||||
bi->bi_clone + bi->bi_offset,
|
||||
blk = gfs2_bitfit(rgd, bi->bi_clone + bi->bi_offset,
|
||||
bi->bi_len, goal, old_state);
|
||||
else
|
||||
blk = gfs2_bitfit(rgd,
|
||||
|
@ -976,12 +975,10 @@ static uint32_t rgblk_search(struct gfs2_rgrpd *rgd, uint32_t goal,
|
|||
blk = 0;
|
||||
|
||||
gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1);
|
||||
gfs2_setbit(rgd,
|
||||
bi->bi_bh->b_data + bi->bi_offset,
|
||||
gfs2_setbit(rgd, bi->bi_bh->b_data + bi->bi_offset,
|
||||
bi->bi_len, blk, new_state);
|
||||
if (bi->bi_clone)
|
||||
gfs2_setbit(rgd,
|
||||
bi->bi_clone + bi->bi_offset,
|
||||
gfs2_setbit(rgd, bi->bi_clone + bi->bi_offset,
|
||||
bi->bi_len, blk, new_state);
|
||||
|
||||
return bi->bi_start * GFS2_NBBY + blk;
|
||||
|
@ -1064,8 +1061,7 @@ uint64_t gfs2_alloc_data(struct gfs2_inode *ip)
|
|||
else
|
||||
goal = rgd->rd_last_alloc_data;
|
||||
|
||||
blk = rgblk_search(rgd, goal,
|
||||
GFS2_BLKST_FREE, GFS2_BLKST_USED);
|
||||
blk = rgblk_search(rgd, goal, GFS2_BLKST_FREE, GFS2_BLKST_USED);
|
||||
rgd->rd_last_alloc_data = blk;
|
||||
|
||||
block = rgd->rd_ri.ri_data0 + blk;
|
||||
|
@ -1109,8 +1105,7 @@ uint64_t gfs2_alloc_meta(struct gfs2_inode *ip)
|
|||
else
|
||||
goal = rgd->rd_last_alloc_meta;
|
||||
|
||||
blk = rgblk_search(rgd, goal,
|
||||
GFS2_BLKST_FREE, GFS2_BLKST_USED);
|
||||
blk = rgblk_search(rgd, goal, GFS2_BLKST_FREE, GFS2_BLKST_USED);
|
||||
rgd->rd_last_alloc_meta = blk;
|
||||
|
||||
block = rgd->rd_ri.ri_data0 + blk;
|
||||
|
|
|
@ -35,11 +35,12 @@ static int munge_ondisk(struct gfs2_sbd *sdp, unsigned int slot,
|
|||
int new = 0;
|
||||
struct buffer_head *bh;
|
||||
int error;
|
||||
int boundary;
|
||||
|
||||
block = slot / sdp->sd_ut_per_block;
|
||||
offset = slot % sdp->sd_ut_per_block;
|
||||
|
||||
error = gfs2_block_map(ip, block, &new, &dblock, NULL);
|
||||
error = gfs2_block_map(ip->i_vnode, block, &new, &dblock, &boundary);
|
||||
if (error)
|
||||
return error;
|
||||
error = gfs2_meta_read(ip->i_gl, dblock, DIO_START | DIO_WAIT, &bh);
|
||||
|
@ -354,7 +355,7 @@ int gfs2_unlinked_init(struct gfs2_sbd *sdp)
|
|||
|
||||
if (!extlen) {
|
||||
int new = 0;
|
||||
error = gfs2_block_map(ip, x, &new, &dblock, &extlen);
|
||||
error = gfs2_extent_map(ip->i_vnode, x, &new, &dblock, &extlen);
|
||||
if (error)
|
||||
goto fail;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче