Skip to content

Commit 2fba46a

Browse files
committed
gfs2: Change inode qa_data to allow multiple users
Before this patch, multiple users called gfs2_qa_alloc which allocated a qadata structure to the inode, if quotas are turned on. Later, in file close or evict, the structure was deleted with gfs2_qa_delete. But there can be several competing processes who need access to the structure. There were races between file close (release) and the others. Thus, a release could delete the structure out from under a process that relied upon its existence. For example, chown. This patch changes the management of the qadata structures to be a get/put scheme. Function gfs2_qa_alloc has been changed to gfs2_qa_get and if the structure is allocated, the count essentially starts out at 1. Function gfs2_qa_delete has been renamed to gfs2_qa_put, and the last guy to decrement the count to 0 frees the memory. Signed-off-by: Bob Peterson <[email protected]>
1 parent d580712 commit 2fba46a

File tree

10 files changed

+101
-58
lines changed

10 files changed

+101
-58
lines changed

fs/gfs2/acl.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,14 +117,14 @@ int gfs2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
117117
if (acl && acl->a_count > GFS2_ACL_MAX_ENTRIES(GFS2_SB(inode)))
118118
return -E2BIG;
119119

120-
ret = gfs2_qa_alloc(ip);
120+
ret = gfs2_qa_get(ip);
121121
if (ret)
122122
return ret;
123123

124124
if (!gfs2_glock_is_locked_by_me(ip->i_gl)) {
125125
ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
126126
if (ret)
127-
return ret;
127+
goto out;
128128
need_unlock = true;
129129
}
130130

@@ -144,5 +144,7 @@ int gfs2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
144144
unlock:
145145
if (need_unlock)
146146
gfs2_glock_dq_uninit(&gh);
147+
out:
148+
gfs2_qa_put(ip);
147149
return ret;
148150
}

fs/gfs2/bmap.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2183,7 +2183,7 @@ int gfs2_setattr_size(struct inode *inode, u64 newsize)
21832183

21842184
inode_dio_wait(inode);
21852185

2186-
ret = gfs2_qa_alloc(ip);
2186+
ret = gfs2_qa_get(ip);
21872187
if (ret)
21882188
goto out;
21892189

fs/gfs2/file.c

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ static vm_fault_t gfs2_page_mkwrite(struct vm_fault *vmf)
458458

459459
sb_start_pagefault(inode->i_sb);
460460

461-
ret = gfs2_qa_alloc(ip);
461+
ret = gfs2_qa_get(ip);
462462
if (ret)
463463
goto out;
464464

@@ -553,6 +553,7 @@ static vm_fault_t gfs2_page_mkwrite(struct vm_fault *vmf)
553553
out_unlock:
554554
gfs2_glock_dq(&gh);
555555
out_uninit:
556+
gfs2_qa_put(ip);
556557
gfs2_holder_uninit(&gh);
557558
if (ret == 0) {
558559
set_page_dirty(page);
@@ -635,7 +636,17 @@ int gfs2_open_common(struct inode *inode, struct file *file)
635636

636637
gfs2_assert_warn(GFS2_SB(inode), !file->private_data);
637638
file->private_data = fp;
639+
if (file->f_mode & FMODE_WRITE) {
640+
ret = gfs2_qa_get(GFS2_I(inode));
641+
if (ret)
642+
goto fail;
643+
}
638644
return 0;
645+
646+
fail:
647+
kfree(file->private_data);
648+
file->private_data = NULL;
649+
return ret;
639650
}
640651

641652
/**
@@ -690,10 +701,8 @@ static int gfs2_release(struct inode *inode, struct file *file)
690701
kfree(file->private_data);
691702
file->private_data = NULL;
692703

693-
if (!(file->f_mode & FMODE_WRITE))
694-
return 0;
695-
696-
gfs2_rsqa_delete(ip, &inode->i_writecount);
704+
if (file->f_mode & FMODE_WRITE)
705+
gfs2_rsqa_delete(ip, &inode->i_writecount);
697706
return 0;
698707
}
699708

@@ -849,7 +858,7 @@ static ssize_t gfs2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
849858
struct gfs2_inode *ip = GFS2_I(inode);
850859
ssize_t ret;
851860

852-
ret = gfs2_qa_alloc(ip);
861+
ret = gfs2_qa_get(ip);
853862
if (ret)
854863
return ret;
855864

@@ -860,7 +869,7 @@ static ssize_t gfs2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
860869

861870
ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &gh);
862871
if (ret)
863-
return ret;
872+
goto out;
864873
gfs2_glock_dq_uninit(&gh);
865874
}
866875

@@ -918,6 +927,8 @@ static ssize_t gfs2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
918927

919928
out_unlock:
920929
inode_unlock(inode);
930+
out:
931+
gfs2_qa_put(ip);
921932
return ret;
922933
}
923934

@@ -1149,14 +1160,15 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset, loff_t le
11491160
if (mode & FALLOC_FL_PUNCH_HOLE) {
11501161
ret = __gfs2_punch_hole(file, offset, len);
11511162
} else {
1152-
ret = gfs2_qa_alloc(ip);
1163+
ret = gfs2_qa_get(ip);
11531164
if (ret)
11541165
goto out_putw;
11551166

11561167
ret = __gfs2_fallocate(file, mode, offset, len);
11571168

11581169
if (ret)
11591170
gfs2_rs_deltree(&ip->i_res);
1171+
gfs2_qa_put(ip);
11601172
}
11611173

11621174
out_putw:
@@ -1175,14 +1187,17 @@ static ssize_t gfs2_file_splice_write(struct pipe_inode_info *pipe,
11751187
{
11761188
int error;
11771189
struct gfs2_inode *ip = GFS2_I(out->f_mapping->host);
1190+
ssize_t ret;
11781191

1179-
error = gfs2_qa_alloc(ip);
1192+
error = gfs2_qa_get(ip);
11801193
if (error)
11811194
return (ssize_t)error;
11821195

11831196
gfs2_size_hint(out, *ppos, len);
11841197

1185-
return iter_file_splice_write(pipe, out, ppos, len, flags);
1198+
ret = iter_file_splice_write(pipe, out, ppos, len, flags);
1199+
gfs2_qa_put(ip);
1200+
return ret;
11861201
}
11871202

11881203
#ifdef CONFIG_GFS2_FS_LOCKING_DLM

fs/gfs2/incore.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ struct gfs2_qadata { /* quota allocation data */
295295
struct gfs2_quota_data *qa_qd[2 * GFS2_MAXQUOTAS];
296296
struct gfs2_holder qa_qd_ghs[2 * GFS2_MAXQUOTAS];
297297
unsigned int qa_qd_num;
298+
int qa_ref;
298299
};
299300

300301
/* Resource group multi-block reservation, in order of appearance:

fs/gfs2/inode.c

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -588,13 +588,13 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
588588
if (!name->len || name->len > GFS2_FNAMESIZE)
589589
return -ENAMETOOLONG;
590590

591-
error = gfs2_qa_alloc(dip);
591+
error = gfs2_qa_get(dip);
592592
if (error)
593593
return error;
594594

595595
error = gfs2_rindex_update(sdp);
596596
if (error)
597-
return error;
597+
goto fail;
598598

599599
error = gfs2_glock_nq_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
600600
if (error)
@@ -641,7 +641,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
641641
goto fail_gunlock;
642642

643643
ip = GFS2_I(inode);
644-
error = gfs2_qa_alloc(ip);
644+
error = gfs2_qa_get(ip);
645645
if (error)
646646
goto fail_free_acls;
647647

@@ -776,6 +776,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
776776
clear_bit(GLF_INODE_CREATING, &io_gl->gl_flags);
777777
gfs2_glock_put(io_gl);
778778
fail_free_inode:
779+
gfs2_qa_put(ip);
779780
if (ip->i_gl) {
780781
glock_clear_object(ip->i_gl, ip);
781782
gfs2_glock_put(ip->i_gl);
@@ -798,6 +799,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
798799
if (gfs2_holder_initialized(ghs + 1))
799800
gfs2_glock_dq_uninit(ghs + 1);
800801
fail:
802+
gfs2_qa_put(dip);
801803
return error;
802804
}
803805

@@ -899,7 +901,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
899901
if (S_ISDIR(inode->i_mode))
900902
return -EPERM;
901903

902-
error = gfs2_qa_alloc(dip);
904+
error = gfs2_qa_get(dip);
903905
if (error)
904906
return error;
905907

@@ -1002,6 +1004,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
10021004
out_child:
10031005
gfs2_glock_dq(ghs);
10041006
out_parent:
1007+
gfs2_qa_put(ip);
10051008
gfs2_holder_uninit(ghs);
10061009
gfs2_holder_uninit(ghs + 1);
10071010
return error;
@@ -1362,7 +1365,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
13621365
if (error)
13631366
return error;
13641367

1365-
error = gfs2_qa_alloc(ndip);
1368+
error = gfs2_qa_get(ndip);
13661369
if (error)
13671370
return error;
13681371

@@ -1562,6 +1565,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
15621565
if (gfs2_holder_initialized(&r_gh))
15631566
gfs2_glock_dq_uninit(&r_gh);
15641567
out:
1568+
gfs2_qa_put(ndip);
15651569
return error;
15661570
}
15671571

@@ -1873,10 +1877,9 @@ static int setattr_chown(struct inode *inode, struct iattr *attr)
18731877
ouid = nuid = NO_UID_QUOTA_CHANGE;
18741878
if (!(attr->ia_valid & ATTR_GID) || gid_eq(ogid, ngid))
18751879
ogid = ngid = NO_GID_QUOTA_CHANGE;
1876-
1877-
error = gfs2_qa_alloc(ip);
1880+
error = gfs2_qa_get(ip);
18781881
if (error)
1879-
goto out;
1882+
return error;
18801883

18811884
error = gfs2_rindex_update(sdp);
18821885
if (error)
@@ -1914,6 +1917,7 @@ static int setattr_chown(struct inode *inode, struct iattr *attr)
19141917
out_gunlock_q:
19151918
gfs2_quota_unlock(ip);
19161919
out:
1920+
gfs2_qa_put(ip);
19171921
return error;
19181922
}
19191923

@@ -1935,21 +1939,21 @@ static int gfs2_setattr(struct dentry *dentry, struct iattr *attr)
19351939
struct gfs2_holder i_gh;
19361940
int error;
19371941

1938-
error = gfs2_qa_alloc(ip);
1942+
error = gfs2_qa_get(ip);
19391943
if (error)
19401944
return error;
19411945

19421946
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh);
19431947
if (error)
1944-
return error;
1948+
goto out;
19451949

19461950
error = -EPERM;
19471951
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
1948-
goto out;
1952+
goto error;
19491953

19501954
error = setattr_prepare(dentry, attr);
19511955
if (error)
1952-
goto out;
1956+
goto error;
19531957

19541958
if (attr->ia_valid & ATTR_SIZE)
19551959
error = gfs2_setattr_size(inode, attr->ia_size);
@@ -1961,10 +1965,12 @@ static int gfs2_setattr(struct dentry *dentry, struct iattr *attr)
19611965
error = posix_acl_chmod(inode, inode->i_mode);
19621966
}
19631967

1964-
out:
1968+
error:
19651969
if (!error)
19661970
mark_inode_dirty(inode);
19671971
gfs2_glock_dq_uninit(&i_gh);
1972+
out:
1973+
gfs2_qa_put(ip);
19681974
return error;
19691975
}
19701976

0 commit comments

Comments
 (0)