Signed-off-by: Bob Peterson <[email protected]>
---
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index 61296ec..3daf05b 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -1291,15 +1291,11 @@ int gfs2_setattr_size(struct inode *inode, u64 newsize)
if (ret)
return ret;
- ret = get_write_access(inode);
- if (ret)
- return ret;
-
inode_dio_wait(inode);
- ret = gfs2_rs_alloc(ip);
+ ret = gfs2_rs_get(ip);
if (ret)
- goto out;
+ return ret;
oldsize = inode->i_size;
if (newsize >= oldsize) {
@@ -1307,10 +1303,9 @@ int gfs2_setattr_size(struct inode *inode, u64 newsize)
goto out;
}
- gfs2_rs_deltree(ip->i_res);
ret = do_shrink(inode, oldsize, newsize);
out:
- put_write_access(inode);
+ gfs2_rs_put(GFS2_I(inode));
return ret;
}
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c
index cf4ab89..0c3a69b 100644
--- a/fs/gfs2/file.c
+++ b/fs/gfs2/file.c
@@ -397,14 +397,10 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma,
struct vm_fault *vmf)
/* Update file times before taking page lock */
file_update_time(vma->vm_file);
- ret = get_write_access(inode);
+ ret = gfs2_rs_get(ip);
if (ret)
goto out;
- ret = gfs2_rs_alloc(ip);
- if (ret)
- goto out_write_access;
-
gfs2_size_hint(vma->vm_file, pos, PAGE_CACHE_SIZE);
gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
@@ -486,8 +482,7 @@ out_uninit:
set_page_dirty(page);
wait_for_stable_page(page);
}
-out_write_access:
- put_write_access(inode);
+ gfs2_rs_put(ip);
out:
sb_end_pagefault(inode->i_sb);
return block_page_mkwrite_return(ret);
@@ -602,6 +597,9 @@ static int gfs2_open(struct inode *inode, struct file *file)
if (need_unlock)
gfs2_glock_dq_uninit(&i_gh);
+ if (error == 0 && file->f_mode & FMODE_WRITE)
+ error = gfs2_rs_get(ip);
+
return error;
}
@@ -620,10 +618,9 @@ static int gfs2_release(struct inode *inode, struct file *file)
kfree(file->private_data);
file->private_data = NULL;
- if (!(file->f_mode & FMODE_WRITE))
- return 0;
+ if (file->f_mode & FMODE_WRITE)
+ gfs2_rs_put(ip);
- gfs2_rs_delete(ip, &inode->i_writecount);
return 0;
}
@@ -703,7 +700,7 @@ static ssize_t gfs2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
struct gfs2_inode *ip = GFS2_I(file_inode(file));
int ret;
- ret = gfs2_rs_alloc(ip);
+ ret = gfs2_rs_get(ip);
if (ret)
return ret;
@@ -714,11 +711,14 @@ static ssize_t gfs2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &gh);
if (ret)
- return ret;
+ goto out;
gfs2_glock_dq_uninit(&gh);
}
- return generic_file_write_iter(iocb, from);
+ ret = generic_file_write_iter(iocb, from);
+out:
+ gfs2_rs_put(ip);
+ return ret;
}
static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len,
@@ -934,19 +934,11 @@ static long gfs2_fallocate(struct file *file, int mode,
loff_t offset, loff_t le
goto out_unlock;
}
- ret = get_write_access(inode);
- if (ret)
- goto out_unlock;
-
- ret = gfs2_rs_alloc(ip);
- if (ret)
- goto out_putw;
-
- ret = __gfs2_fallocate(file, mode, offset, len);
- if (ret)
- gfs2_rs_deltree(ip->i_res);
-out_putw:
- put_write_access(inode);
+ ret = gfs2_rs_get(ip);
+ if (ret == 0) {
+ ret = __gfs2_fallocate(file, mode, offset, len);
+ gfs2_rs_put(ip);
+ }
out_unlock:
gfs2_glock_dq(&gh);
out_uninit:
@@ -962,13 +954,15 @@ static ssize_t gfs2_file_splice_write(struct
pipe_inode_info *pipe,
int error;
struct gfs2_inode *ip = GFS2_I(out->f_mapping->host);
- error = gfs2_rs_alloc(ip);
+ error = gfs2_rs_get(ip);
if (error)
return (ssize_t)error;
gfs2_size_hint(out, *ppos, len);
- return iter_file_splice_write(pipe, out, ppos, len, flags);
+ error = iter_file_splice_write(pipe, out, ppos, len, flags);
+ gfs2_rs_put(ip);
+ return (ssize_t)error;
}
#ifdef CONFIG_GFS2_FS_LOCKING_DLM
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index e300f74..f7603e1 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -288,6 +288,7 @@ struct gfs2_blkreserv {
struct gfs2_rbm rs_rbm; /* Start of reservation */
u32 rs_free; /* how many blocks are still free */
u64 rs_inum; /* Inode number for reservation */
+ atomic_t rs_ref; /* References to the reservation */
/* ancillary quota stuff */
struct gfs2_quota_data *rs_qa_qd[2 * GFS2_MAXQUOTAS];
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 063fdfc..7c58d25 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -601,13 +601,15 @@ static int gfs2_create_inode(struct inode *dir, struct
dentry *dentry,
if (!name->len || name->len > GFS2_FNAMESIZE)
return -ENAMETOOLONG;
- error = gfs2_rs_alloc(dip);
+ error = gfs2_rs_get(dip);
if (error)
return error;
error = gfs2_rindex_update(sdp);
- if (error)
+ if (error) {
+ gfs2_rs_put(dip);
return error;
+ }
error = gfs2_glock_nq_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
if (error)
@@ -634,6 +636,7 @@ static int gfs2_create_inode(struct inode *dir, struct
dentry *dentry,
error = finish_no_open(file, NULL);
}
gfs2_glock_dq_uninit(ghs);
+ gfs2_rs_put(dip);
return error;
} else if (error != -ENOENT) {
goto fail_gunlock;
@@ -653,7 +656,7 @@ static int gfs2_create_inode(struct inode *dir, struct
dentry *dentry,
goto fail_free_vfs_inode;
ip = GFS2_I(inode);
- error = gfs2_rs_alloc(ip);
+ error = gfs2_rs_get(ip);
if (error)
goto fail_free_acls;
@@ -696,18 +699,18 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
error = alloc_dinode(ip, aflags, &blocks);
if (error)
- goto fail_free_inode;
+ goto fail_rs_put;
gfs2_set_inode_blocks(inode, blocks);
error = gfs2_glock_get(sdp, ip->i_no_addr, &gfs2_inode_glops, CREATE, &ip->i_gl);
if (error)
- goto fail_free_inode;
+ goto fail_rs_put;
ip->i_gl->gl_object = ip;
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_SKIP, ghs + 1);
if (error)
- goto fail_free_inode;
+ goto fail_rs_put;
error = gfs2_trans_begin(sdp, blocks, 0);
if (error)
@@ -763,20 +766,22 @@ static int gfs2_create_inode(struct inode *dir, struct
dentry *dentry,
}
gfs2_glock_dq_uninit(ghs);
gfs2_glock_dq_uninit(ghs + 1);
+ gfs2_rs_put(dip);
return error;
fail_gunlock3:
gfs2_glock_dq_uninit(ghs + 1);
+ gfs2_rs_put(ip);
if (ip->i_gl)
gfs2_glock_put(ip->i_gl);
goto fail_gunlock;
fail_gunlock2:
gfs2_glock_dq_uninit(ghs + 1);
-fail_free_inode:
+fail_rs_put:
+ gfs2_rs_put(ip);
if (ip->i_gl)
gfs2_glock_put(ip->i_gl);
- gfs2_rs_delete(ip, NULL);
fail_free_acls:
if (default_acl)
posix_acl_release(default_acl);
@@ -796,6 +801,7 @@ fail_gunlock:
iput(inode);
}
fail:
+ gfs2_rs_put(dip);
return error;
}
@@ -898,7 +904,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
if (S_ISDIR(inode->i_mode))
return -EPERM;
- error = gfs2_rs_alloc(dip);
+ error = gfs2_rs_get(dip);
if (error)
return error;
@@ -1003,6 +1009,7 @@ out_child:
out_parent:
gfs2_holder_uninit(ghs);
gfs2_holder_uninit(ghs + 1);
+ gfs2_rs_put(dip);
return error;
}
@@ -1371,7 +1378,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
if (error)
return error;
- error = gfs2_rs_alloc(ndip);
+ error = gfs2_rs_get(ndip);
if (error)
return error;
@@ -1553,6 +1560,7 @@ out_gunlock_r:
if (r_gh.gh_gl)
gfs2_glock_dq_uninit(&r_gh);
out:
+ gfs2_rs_put(ndip);
return error;
}
@@ -1854,21 +1862,17 @@ static int setattr_chown(struct inode *inode, struct iattr *attr)
if (!(attr->ia_valid & ATTR_GID) || gid_eq(ogid, ngid))
ogid = ngid = NO_GID_QUOTA_CHANGE;
- error = get_write_access(inode);
- if (error)
- return error;
-
- error = gfs2_rs_alloc(ip);
+ error = gfs2_rs_get(ip);
if (error)
goto out;
error = gfs2_rindex_update(sdp);
if (error)
- goto out;
+ goto out_put;
error = gfs2_quota_lock(ip, nuid, ngid);
if (error)
- goto out;
+ goto out_put;
ap.target = gfs2_get_inode_blocks(&ip->i_inode);
@@ -1897,8 +1901,9 @@ out_end_trans:
gfs2_trans_end(sdp);
out_gunlock_q:
gfs2_quota_unlock(ip);
+out_put:
+ gfs2_rs_put(ip);
out:
- put_write_access(inode);
return error;
}
@@ -1920,21 +1925,21 @@ static int gfs2_setattr(struct dentry *dentry, struct iattr *attr)
struct gfs2_holder i_gh;
int error;
- error = gfs2_rs_alloc(ip);
+ error = gfs2_rs_get(ip);
if (error)
return error;
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh);
if (error)
- return error;
+ goto out;
error = -EPERM;
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
- goto out;
+ goto out_dq;
error = inode_change_ok(inode, attr);
if (error)
- goto out;
+ goto out_dq;
if (attr->ia_valid & ATTR_SIZE)
error = gfs2_setattr_size(inode, attr->ia_size);
@@ -1946,10 +1951,12 @@ static int gfs2_setattr(struct dentry *dentry, struct
iattr *attr)
error = posix_acl_chmod(inode, inode->i_mode);
}
-out:
+out_dq:
if (!error)
mark_inode_dirty(inode);
gfs2_glock_dq_uninit(&i_gh);
+out:
+ gfs2_rs_put(ip);
return error;
}
@@ -2002,9 +2009,10 @@ static int gfs2_setxattr(struct dentry *dentry, const char *name,
gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
ret = gfs2_glock_nq(&gh);
if (ret == 0) {
- ret = gfs2_rs_alloc(ip);
+ ret = gfs2_rs_get(ip);
if (ret == 0)
ret = generic_setxattr(dentry, name, data, size, flags);
+ gfs2_rs_put(ip);
gfs2_glock_dq(&gh);
}
gfs2_holder_uninit(&gh);
@@ -2043,9 +2051,11 @@ static int gfs2_removexattr(struct dentry *dentry, const
char *name)
gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
ret = gfs2_glock_nq(&gh);
if (ret == 0) {
- ret = gfs2_rs_alloc(ip);
- if (ret == 0)
+ ret = gfs2_rs_get(ip);
+ if (ret == 0) {
ret = generic_removexattr(dentry, name);
+ gfs2_rs_put(ip);
+ }
gfs2_glock_dq(&gh);
}
gfs2_holder_uninit(&gh);
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
index 3a31226..c52eab1 100644
--- a/fs/gfs2/quota.c
+++ b/fs/gfs2/quota.c
@@ -533,20 +533,22 @@ int gfs2_quota_hold(struct gfs2_inode *ip, kuid_t uid,
kgid_t gid)
struct gfs2_quota_data **qd;
int error;
- if (ip->i_res == NULL) {
- error = gfs2_rs_alloc(ip);
- if (error)
- return error;
- }
+ error = gfs2_rs_get(ip);
+ if (error)
+ return error;
qd = ip->i_res->rs_qa_qd;
if (gfs2_assert_warn(sdp, !ip->i_res->rs_qa_qd_num) ||
- gfs2_assert_warn(sdp, !test_bit(GIF_QD_LOCKED, &ip->i_flags)))
- return -EIO;
+ gfs2_assert_warn(sdp, !test_bit(GIF_QD_LOCKED, &ip->i_flags))) {
+ error = -EIO;
+ goto out_err;
+ }
- if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)
- return 0;
+ if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF) {
+ error = 0;
+ goto out_err;
+ }
error = qdsb_get(sdp, make_kqid_uid(ip->i_inode.i_uid), qd);
if (error)
@@ -581,6 +583,7 @@ int gfs2_quota_hold(struct gfs2_inode *ip, kuid_t uid,
kgid_t gid)
out:
if (error)
gfs2_quota_unhold(ip);
+out_err:
return error;
}
@@ -598,6 +601,7 @@ void gfs2_quota_unhold(struct gfs2_inode *ip)
ip->i_res->rs_qa_qd[x] = NULL;
}
ip->i_res->rs_qa_qd_num = 0;
+ gfs2_rs_put(ip);
}
static int sort_qd(const void *a, const void *b)
@@ -843,7 +847,7 @@ static int do_sync(unsigned int num_qd, struct
gfs2_quota_data **qda)
unsigned int nalloc = 0, blocks;
int error;
- error = gfs2_rs_alloc(ip);
+ error = gfs2_rs_get(ip);
if (error)
return error;
@@ -851,8 +855,10 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda)
&data_blocks, &ind_blocks);
ghs = kcalloc(num_qd, sizeof(struct gfs2_holder), GFP_NOFS);
- if (!ghs)
- return -ENOMEM;
+ if (!ghs) {
+ error = -ENOMEM;
+ goto out_err;
+ }
sort(qda, num_qd, sizeof(struct gfs2_quota_data *), sort_qd, NULL);
mutex_lock(&ip->i_inode.i_mutex);
@@ -923,6 +929,8 @@ out:
mutex_unlock(&ip->i_inode.i_mutex);
kfree(ghs);
gfs2_log_flush(ip->i_gl->gl_name.ln_sbd, ip->i_gl, NORMAL_FLUSH);
+out_err:
+ gfs2_rs_put(ip);
return error;
}
@@ -1635,7 +1643,7 @@ static int gfs2_set_dqblk(struct super_block *sb, struct kqid qid,
if (error)
return error;
- error = gfs2_rs_alloc(ip);
+ error = gfs2_rs_get(ip);
if (error)
goto out_put;
@@ -1705,6 +1713,7 @@ out_q:
gfs2_glock_dq_uninit(&q_gh);
out_unlockput:
mutex_unlock(&ip->i_inode.i_mutex);
+ gfs2_rs_put(ip);
out_put:
qd_put(qd);
return error;
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c
index c92ae7fd..89e9b66 100644
--- a/fs/gfs2/rgrp.c
+++ b/fs/gfs2/rgrp.c
@@ -596,24 +596,27 @@ void gfs2_free_clones(struct gfs2_rgrpd *rgd)
}
/**
- * gfs2_rs_alloc - make sure we have a reservation assigned to the inode
+ * gfs2_rs_get - make sure we have a reservation assigned to the inode
* @ip: the inode for this reservation
*/
-int gfs2_rs_alloc(struct gfs2_inode *ip)
+int gfs2_rs_get(struct gfs2_inode *ip)
{
int error = 0;
down_write(&ip->i_rw_mutex);
if (ip->i_res)
- goto out;
+ goto out_incr;
ip->i_res = kmem_cache_zalloc(gfs2_rsrv_cachep, GFP_NOFS);
if (!ip->i_res) {
error = -ENOMEM;
goto out;
}
+ atomic_set(&ip->i_res->rs_ref, 0);
RB_CLEAR_NODE(&ip->i_res->rs_node);
+out_incr:
+ atomic_inc(&ip->i_res->rs_ref);
out:
up_write(&ip->i_rw_mutex);
return error;
@@ -621,10 +624,11 @@ out:
static void dump_rs(struct seq_file *seq, const struct gfs2_blkreserv *rs)
{
- gfs2_print_dbg(seq, " B: n:%llu s:%llu b:%u f:%u\n",
+ gfs2_print_dbg(seq, " B: n:%llu s:%llu b:%u f:%u r:%u\n",
(unsigned long long)rs->rs_inum,
(unsigned long long)gfs2_rbm_to_block(&rs->rs_rbm),
- rs->rs_rbm.offset, rs->rs_free);
+ rs->rs_rbm.offset, rs->rs_free,
+ atomic_read(&rs->rs_ref));
}
/**
@@ -678,15 +682,15 @@ void gfs2_rs_deltree(struct gfs2_blkreserv *rs)
}
/**
- * gfs2_rs_delete - delete a multi-block reservation
+ * gfs2_rs_put - put a multi-block reservation
* @ip: The inode for this reservation
* @wcount: The inode's write count, or NULL
*
*/
-void gfs2_rs_delete(struct gfs2_inode *ip, atomic_t *wcount)
+void gfs2_rs_put(struct gfs2_inode *ip)
{
down_write(&ip->i_rw_mutex);
- if (ip->i_res && ((wcount == NULL) || (atomic_read(wcount) <= 1))) {
+ if (ip->i_res && atomic_dec_and_test(&ip->i_res->rs_ref)) {
gfs2_rs_deltree(ip->i_res);
BUG_ON(ip->i_res->rs_free);
kmem_cache_free(gfs2_rsrv_cachep, ip->i_res);
diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h
index c0ab33f..51cce86 100644
--- a/fs/gfs2/rgrp.h
+++ b/fs/gfs2/rgrp.h
@@ -49,9 +49,9 @@ extern void gfs2_inplace_release(struct gfs2_inode *ip);
extern int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *n,
bool dinode, u64 *generation);
-extern int gfs2_rs_alloc(struct gfs2_inode *ip);
+extern int gfs2_rs_get(struct gfs2_inode *ip);
extern void gfs2_rs_deltree(struct gfs2_blkreserv *rs);
-extern void gfs2_rs_delete(struct gfs2_inode *ip, atomic_t *wcount);
+extern void gfs2_rs_put(struct gfs2_inode *ip);
extern void __gfs2_free_blocks(struct gfs2_inode *ip, u64 bstart, u32 blen,
int meta);
extern void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen);
extern void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip);
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index 2982445..b4d12a1 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -1607,7 +1607,8 @@ out_unlock:
out:
/* Case 3 starts here */
truncate_inode_pages_final(&inode->i_data);
- gfs2_rs_delete(ip, NULL);
+ gfs2_rs_put(ip);
+ BUG_ON(ip->i_res);
gfs2_ordered_del_inode(ip);
clear_inode(inode);
gfs2_dir_hash_inval(ip);
diff --git a/fs/gfs2/trace_gfs2.h b/fs/gfs2/trace_gfs2.h
index fff47d0..811a809 100644
--- a/fs/gfs2/trace_gfs2.h
+++ b/fs/gfs2/trace_gfs2.h
@@ -32,13 +32,13 @@
{ GFS2_BLKST_DINODE, "dinode" }, \
{ GFS2_BLKST_UNLINKED, "unlinked" })
-#define TRACE_RS_DELETE 0
+#define TRACE_RS_PUT 0
#define TRACE_RS_TREEDEL 1
#define TRACE_RS_INSERT 2
#define TRACE_RS_CLAIM 3
#define rs_func_name(x) __print_symbolic(x, \
- { 0, "del " }, \
+ { 0, "put " }, \
{ 1, "tdel" }, \
{ 2, "ins " }, \
{ 3, "clm " })
@@ -524,6 +524,7 @@ TRACE_EVENT(gfs2_rs,
__field( u64, inum )
__field( u64, start )
__field( u32, free )
+ __field( u32, ref )
__field( u8, func )
),
@@ -535,17 +536,20 @@ TRACE_EVENT(gfs2_rs,
__entry->inum = rs->rs_inum;
__entry->start = gfs2_rbm_to_block(&rs->rs_rbm);
__entry->free = rs->rs_free;
+ __entry->ref = atomic_read(&rs->rs_ref);
__entry->func = func;
),
- TP_printk("%u,%u bmap %llu resrv %llu rg:%llu rf:%lu rr:%lu %s f:%lu",
+ TP_printk("%u,%u bmap %llu resrv %llu rg:%llu rf:%lu rr:%lu %s f:%lu "
+ "r:%lu",
MAJOR(__entry->dev), MINOR(__entry->dev),
(unsigned long long)__entry->inum,
(unsigned long long)__entry->start,
(unsigned long long)__entry->rd_addr,
(unsigned long)__entry->rd_free_clone,
(unsigned long)__entry->rd_reserved,
- rs_func_name(__entry->func), (unsigned long)__entry->free)
+ rs_func_name(__entry->func), (unsigned long)__entry->free,
+ (unsigned long)__entry->ref)
);
#endif /* _TRACE_GFS2_H */