提交 ab9bbda0 编写于 作者: S Steven Whitehouse

GFS2: Use ->dirty_inode()

The aim of this patch is to use the newly enhanced ->dirty_inode()
super block operation to deal with atime updates, rather than
piggy backing that code into ->write_inode() as is currently
done.

The net result is a simplification of the code in various places
and a reduction of the number of gfs2_dinode_out() calls since
this is now implied by ->dirty_inode().

Some of the mark_inode_dirty() calls have been moved under glocks
in order to take advantage of then being able to avoid locking in
->dirty_inode() when we already have suitable locks.

One consequence is that generic_write_end() now correctly deals
with file size updates, so that we do not need a separate check
for that afterwards. This also, indirectly, means that fdatasync
should work correctly on GFS2 - the current code always syncs the
metadata whether it needs to or not.

Has survived testing with postmark (with and without atime) and
also fsx.
Signed-off-by: NSteven Whitehouse <swhiteho@redhat.com>
上级 f1818529
...@@ -82,7 +82,7 @@ static int gfs2_set_mode(struct inode *inode, umode_t mode) ...@@ -82,7 +82,7 @@ static int gfs2_set_mode(struct inode *inode, umode_t mode)
iattr.ia_valid = ATTR_MODE; iattr.ia_valid = ATTR_MODE;
iattr.ia_mode = mode; iattr.ia_mode = mode;
error = gfs2_setattr_simple(GFS2_I(inode), &iattr); error = gfs2_setattr_simple(inode, &iattr);
} }
return error; return error;
...@@ -160,6 +160,7 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct inode *inode) ...@@ -160,6 +160,7 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct inode *inode)
int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr) int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr)
{ {
struct inode *inode = &ip->i_inode;
struct posix_acl *acl; struct posix_acl *acl;
char *data; char *data;
unsigned int len; unsigned int len;
...@@ -169,7 +170,7 @@ int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr) ...@@ -169,7 +170,7 @@ int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr)
if (IS_ERR(acl)) if (IS_ERR(acl))
return PTR_ERR(acl); return PTR_ERR(acl);
if (!acl) if (!acl)
return gfs2_setattr_simple(ip, attr); return gfs2_setattr_simple(inode, attr);
error = posix_acl_chmod(&acl, GFP_NOFS, attr->ia_mode); error = posix_acl_chmod(&acl, GFP_NOFS, attr->ia_mode);
if (error) if (error)
......
...@@ -787,7 +787,6 @@ static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh, ...@@ -787,7 +787,6 @@ static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh,
u64 to = pos + copied; u64 to = pos + copied;
void *kaddr; void *kaddr;
unsigned char *buf = dibh->b_data + sizeof(struct gfs2_dinode); unsigned char *buf = dibh->b_data + sizeof(struct gfs2_dinode);
struct gfs2_dinode *di = (struct gfs2_dinode *)dibh->b_data;
BUG_ON((pos + len) > (dibh->b_size - sizeof(struct gfs2_dinode))); BUG_ON((pos + len) > (dibh->b_size - sizeof(struct gfs2_dinode)));
kaddr = kmap_atomic(page, KM_USER0); kaddr = kmap_atomic(page, KM_USER0);
...@@ -804,7 +803,6 @@ static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh, ...@@ -804,7 +803,6 @@ static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh,
if (copied) { if (copied) {
if (inode->i_size < to) if (inode->i_size < to)
i_size_write(inode, to); i_size_write(inode, to);
gfs2_dinode_out(ip, di);
mark_inode_dirty(inode); mark_inode_dirty(inode);
} }
...@@ -873,10 +871,6 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping, ...@@ -873,10 +871,6 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping,
gfs2_page_add_databufs(ip, page, from, to); gfs2_page_add_databufs(ip, page, from, to);
ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata); ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata);
if (ret > 0) {
gfs2_dinode_out(ip, dibh->b_data);
mark_inode_dirty(inode);
}
if (inode == sdp->sd_rindex) { if (inode == sdp->sd_rindex) {
adjust_fs_space(inode); adjust_fs_space(inode);
......
...@@ -1681,7 +1681,6 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry) ...@@ -1681,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 */
...@@ -1710,22 +1709,15 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry) ...@@ -1710,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;
} }
/** /**
......
...@@ -802,7 +802,6 @@ static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len, ...@@ -802,7 +802,6 @@ static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len,
from = 0; from = 0;
} }
gfs2_dinode_out(ip, dibh->b_data);
mark_inode_dirty(inode); mark_inode_dirty(inode);
brelse(dibh); brelse(dibh);
......
...@@ -729,8 +729,8 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, ...@@ -729,8 +729,8 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
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;
...@@ -926,8 +926,9 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, ...@@ -926,8 +926,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);
...@@ -949,11 +950,6 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, ...@@ -949,11 +950,6 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
out_parent: out_parent:
gfs2_holder_uninit(ghs); gfs2_holder_uninit(ghs);
gfs2_holder_uninit(ghs + 1); gfs2_holder_uninit(ghs + 1);
if (!error) {
ihold(inode);
d_instantiate(dentry, inode);
mark_inode_dirty(inode);
}
return error; return error;
} }
...@@ -1026,8 +1022,6 @@ static int gfs2_unlink_inode(struct gfs2_inode *dip, ...@@ -1026,8 +1022,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);
...@@ -1565,21 +1559,10 @@ int gfs2_permission(struct inode *inode, int mask) ...@@ -1565,21 +1559,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;
} }
...@@ -1591,19 +1574,19 @@ static int __gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr) ...@@ -1591,19 +1574,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;
} }
...@@ -1641,7 +1624,7 @@ static int setattr_chown(struct inode *inode, struct iattr *attr) ...@@ -1641,7 +1624,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;
...@@ -1697,12 +1680,12 @@ static int gfs2_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -1697,12 +1680,12 @@ static int gfs2_setattr(struct dentry *dentry, struct iattr *attr)
else if ((attr->ia_valid & ATTR_MODE) && IS_POSIXACL(inode)) else if ((attr->ia_valid & ATTR_MODE) && IS_POSIXACL(inode))
error = gfs2_acl_chmod(ip, attr); error = gfs2_acl_chmod(ip, attr);
else else
error = gfs2_setattr_simple(ip, attr); error = gfs2_setattr_simple(inode, attr);
out: out:
gfs2_glock_dq_uninit(&i_gh);
if (!error) if (!error)
mark_inode_dirty(inode); mark_inode_dirty(inode);
gfs2_glock_dq_uninit(&i_gh);
return error; return error;
} }
......
...@@ -109,7 +109,7 @@ extern int gfs2_inode_refresh(struct gfs2_inode *ip); ...@@ -109,7 +109,7 @@ extern int gfs2_inode_refresh(struct gfs2_inode *ip);
extern struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, extern struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
int is_root); int is_root);
extern int gfs2_permission(struct inode *inode, int mask); extern int gfs2_permission(struct inode *inode, int mask);
extern int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr); extern int gfs2_setattr_simple(struct inode *inode, struct iattr *attr);
extern struct inode *gfs2_lookup_simple(struct inode *dip, const char *name); extern struct inode *gfs2_lookup_simple(struct inode *dip, const char *name);
extern void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf); extern void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf);
......
...@@ -638,7 +638,7 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc, ...@@ -638,7 +638,7 @@ 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;
...@@ -736,22 +736,13 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc, ...@@ -736,22 +736,13 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
goto get_a_page; goto get_a_page;
} }
/* Update the disk inode timestamp and size (if extended) */
err = gfs2_meta_inode_buffer(ip, &dibh);
if (err)
goto out;
size = loc + sizeof(struct gfs2_quota); size = loc + sizeof(struct gfs2_quota);
if (size > inode->i_size) if (size > inode->i_size)
i_size_write(inode, size); i_size_write(inode, size);
inode->i_mtime = inode->i_atime = CURRENT_TIME; inode->i_mtime = inode->i_atime = CURRENT_TIME;
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
gfs2_dinode_out(ip, dibh->b_data);
brelse(dibh);
mark_inode_dirty(inode); mark_inode_dirty(inode);
out:
return err; return err;
unlock_out: unlock_out:
unlock_page(page); unlock_page(page);
page_cache_release(page); page_cache_release(page);
......
...@@ -752,51 +752,77 @@ static int gfs2_write_inode(struct inode *inode, struct writeback_control *wbc) ...@@ -752,51 +752,77 @@ static int gfs2_write_inode(struct inode *inode, struct writeback_control *wbc)
struct gfs2_sbd *sdp = GFS2_SB(inode); struct gfs2_sbd *sdp = GFS2_SB(inode);
struct address_space *metamapping = gfs2_glock2aspace(ip->i_gl); struct address_space *metamapping = gfs2_glock2aspace(ip->i_gl);
struct backing_dev_info *bdi = metamapping->backing_dev_info; struct backing_dev_info *bdi = metamapping->backing_dev_info;
struct gfs2_holder gh; int ret = 0;
if (wbc->sync_mode == WB_SYNC_ALL)
gfs2_log_flush(GFS2_SB(inode), ip->i_gl);
if (bdi->dirty_exceeded)
gfs2_ail1_flush(sdp, wbc);
else
filemap_fdatawrite(metamapping);
if (wbc->sync_mode == WB_SYNC_ALL)
ret = filemap_fdatawait(metamapping);
if (ret)
mark_inode_dirty_sync(inode);
return ret;
}
/**
* gfs2_dirty_inode - check for atime updates
* @inode: The inode in question
* @flags: The type of dirty
*
* Unfortunately it can be called under any combination of inode
* glock and transaction lock, so we have to check carefully.
*
* At the moment this deals only with atime - it should be possible
* to expand that role in future, once a review of the locking has
* been carried out.
*/
static void gfs2_dirty_inode(struct inode *inode, int flags)
{
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_sbd *sdp = GFS2_SB(inode);
struct buffer_head *bh; struct buffer_head *bh;
struct timespec atime; struct gfs2_holder gh;
struct gfs2_dinode *di; int need_unlock = 0;
int ret = -EAGAIN; int need_endtrans = 0;
int unlock_required = 0; int ret;
/* Skip timestamp update, if this is from a memalloc */ if (!(flags & (I_DIRTY_DATASYNC|I_DIRTY_SYNC)))
if (current->flags & PF_MEMALLOC) return;
goto do_flush;
if (!gfs2_glock_is_locked_by_me(ip->i_gl)) { if (!gfs2_glock_is_locked_by_me(ip->i_gl)) {
ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
if (ret) if (ret) {
goto do_flush; fs_err(sdp, "dirty_inode: glock %d\n", ret);
unlock_required = 1; return;
} }
ret = gfs2_meta_inode_buffer(ip, &bh); need_unlock = 1;
if (ret == 0) { }
di = (struct gfs2_dinode *)bh->b_data;
atime.tv_sec = be64_to_cpu(di->di_atime); if (current->journal_info == NULL) {
atime.tv_nsec = be32_to_cpu(di->di_atime_nsec);
if (timespec_compare(&inode->i_atime, &atime) > 0) {
ret = gfs2_trans_begin(sdp, RES_DINODE, 0); 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) { if (ret == 0) {
gfs2_trans_add_bh(ip->i_gl, bh, 1); gfs2_trans_add_bh(ip->i_gl, bh, 1);
gfs2_dinode_out(ip, bh->b_data); gfs2_dinode_out(ip, bh->b_data);
gfs2_trans_end(sdp);
}
}
brelse(bh); brelse(bh);
} }
if (unlock_required)
if (need_endtrans)
gfs2_trans_end(sdp);
out:
if (need_unlock)
gfs2_glock_dq_uninit(&gh); gfs2_glock_dq_uninit(&gh);
do_flush:
if (wbc->sync_mode == WB_SYNC_ALL)
gfs2_log_flush(GFS2_SB(inode), ip->i_gl);
if (bdi->dirty_exceeded)
gfs2_ail1_flush(sdp, wbc);
else
filemap_fdatawrite(metamapping);
if (!ret && (wbc->sync_mode == WB_SYNC_ALL))
ret = filemap_fdatawait(metamapping);
if (ret)
mark_inode_dirty_sync(inode);
return ret;
} }
/** /**
...@@ -1578,6 +1604,7 @@ const struct super_operations gfs2_super_ops = { ...@@ -1578,6 +1604,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,
......
...@@ -1296,7 +1296,8 @@ static int ea_acl_chmod_unstuffed(struct gfs2_inode *ip, ...@@ -1296,7 +1296,8 @@ static int ea_acl_chmod_unstuffed(struct gfs2_inode *ip,
int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data) int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data)
{ {
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct inode *inode = &ip->i_inode;
struct gfs2_sbd *sdp = GFS2_SB(inode);
struct gfs2_ea_location el; struct gfs2_ea_location el;
int error; int error;
...@@ -1319,7 +1320,7 @@ int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data) ...@@ -1319,7 +1320,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;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册