diff options
| -rw-r--r-- | fs/ocfs2/quota_global.c | 169 |
1 files changed, 2 insertions, 167 deletions
diff --git a/fs/ocfs2/quota_global.c b/fs/ocfs2/quota_global.c index 6aff8f2d3e49..f4efa89baee5 100644 --- a/fs/ocfs2/quota_global.c +++ b/fs/ocfs2/quota_global.c | |||
| @@ -810,171 +810,6 @@ out: | |||
| 810 | return status; | 810 | return status; |
| 811 | } | 811 | } |
| 812 | 812 | ||
| 813 | /* This is difficult. We have to lock quota inode and start transaction | ||
| 814 | * in this function but we don't want to take the penalty of exlusive | ||
| 815 | * quota file lock when we are just going to use cached structures. So | ||
| 816 | * we just take read lock check whether we have dquot cached and if so, | ||
| 817 | * we don't have to take the write lock... */ | ||
| 818 | static int ocfs2_dquot_initialize(struct inode *inode, int type) | ||
| 819 | { | ||
| 820 | handle_t *handle = NULL; | ||
| 821 | int status = 0; | ||
| 822 | struct super_block *sb = inode->i_sb; | ||
| 823 | struct ocfs2_mem_dqinfo *oinfo; | ||
| 824 | int exclusive = 0; | ||
| 825 | int cnt; | ||
| 826 | qid_t id; | ||
| 827 | |||
| 828 | mlog_entry_void(); | ||
| 829 | |||
| 830 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) { | ||
| 831 | if (type != -1 && cnt != type) | ||
| 832 | continue; | ||
| 833 | if (!sb_has_quota_active(sb, cnt)) | ||
| 834 | continue; | ||
| 835 | oinfo = sb_dqinfo(sb, cnt)->dqi_priv; | ||
| 836 | status = ocfs2_lock_global_qf(oinfo, 0); | ||
| 837 | if (status < 0) | ||
| 838 | goto out; | ||
| 839 | /* This is just a performance optimization not a reliable test. | ||
| 840 | * Since we hold an inode lock, noone can actually release | ||
| 841 | * the structure until we are finished with initialization. */ | ||
| 842 | if (inode->i_dquot[cnt] != NODQUOT) { | ||
| 843 | ocfs2_unlock_global_qf(oinfo, 0); | ||
| 844 | continue; | ||
| 845 | } | ||
| 846 | /* When we have inode lock, we know that no dquot_release() can | ||
| 847 | * run and thus we can safely check whether we need to | ||
| 848 | * read+modify global file to get quota information or whether | ||
| 849 | * our node already has it. */ | ||
| 850 | if (cnt == USRQUOTA) | ||
| 851 | id = inode->i_uid; | ||
| 852 | else if (cnt == GRPQUOTA) | ||
| 853 | id = inode->i_gid; | ||
| 854 | else | ||
| 855 | BUG(); | ||
| 856 | /* Obtain exclusion from quota off... */ | ||
| 857 | down_write(&sb_dqopt(sb)->dqptr_sem); | ||
| 858 | exclusive = !dquot_is_cached(sb, id, cnt); | ||
| 859 | up_write(&sb_dqopt(sb)->dqptr_sem); | ||
| 860 | if (exclusive) { | ||
| 861 | status = ocfs2_lock_global_qf(oinfo, 1); | ||
| 862 | if (status < 0) { | ||
| 863 | exclusive = 0; | ||
| 864 | mlog_errno(status); | ||
| 865 | goto out_ilock; | ||
| 866 | } | ||
| 867 | handle = ocfs2_start_trans(OCFS2_SB(sb), | ||
| 868 | ocfs2_calc_qinit_credits(sb, cnt)); | ||
| 869 | if (IS_ERR(handle)) { | ||
| 870 | status = PTR_ERR(handle); | ||
| 871 | mlog_errno(status); | ||
| 872 | goto out_ilock; | ||
| 873 | } | ||
| 874 | } | ||
| 875 | dquot_initialize(inode, cnt); | ||
| 876 | if (exclusive) { | ||
| 877 | ocfs2_commit_trans(OCFS2_SB(sb), handle); | ||
| 878 | ocfs2_unlock_global_qf(oinfo, 1); | ||
| 879 | } | ||
| 880 | ocfs2_unlock_global_qf(oinfo, 0); | ||
| 881 | } | ||
| 882 | mlog_exit(0); | ||
| 883 | return 0; | ||
| 884 | out_ilock: | ||
| 885 | if (exclusive) | ||
| 886 | ocfs2_unlock_global_qf(oinfo, 1); | ||
| 887 | ocfs2_unlock_global_qf(oinfo, 0); | ||
| 888 | out: | ||
| 889 | mlog_exit(status); | ||
| 890 | return status; | ||
| 891 | } | ||
| 892 | |||
| 893 | static int ocfs2_dquot_drop_slow(struct inode *inode) | ||
| 894 | { | ||
| 895 | int status = 0; | ||
| 896 | int cnt; | ||
| 897 | int got_lock[MAXQUOTAS] = {0, 0}; | ||
| 898 | handle_t *handle; | ||
| 899 | struct super_block *sb = inode->i_sb; | ||
| 900 | struct ocfs2_mem_dqinfo *oinfo; | ||
| 901 | |||
| 902 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) { | ||
| 903 | if (!sb_has_quota_active(sb, cnt)) | ||
| 904 | continue; | ||
| 905 | oinfo = sb_dqinfo(sb, cnt)->dqi_priv; | ||
| 906 | status = ocfs2_lock_global_qf(oinfo, 1); | ||
| 907 | if (status < 0) | ||
| 908 | goto out; | ||
| 909 | got_lock[cnt] = 1; | ||
| 910 | } | ||
| 911 | handle = ocfs2_start_trans(OCFS2_SB(sb), | ||
| 912 | ocfs2_calc_qinit_credits(sb, USRQUOTA) + | ||
| 913 | ocfs2_calc_qinit_credits(sb, GRPQUOTA)); | ||
| 914 | if (IS_ERR(handle)) { | ||
| 915 | status = PTR_ERR(handle); | ||
| 916 | mlog_errno(status); | ||
| 917 | goto out; | ||
| 918 | } | ||
| 919 | dquot_drop(inode); | ||
| 920 | ocfs2_commit_trans(OCFS2_SB(sb), handle); | ||
| 921 | out: | ||
| 922 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) | ||
| 923 | if (got_lock[cnt]) { | ||
| 924 | oinfo = sb_dqinfo(sb, cnt)->dqi_priv; | ||
| 925 | ocfs2_unlock_global_qf(oinfo, 1); | ||
| 926 | } | ||
| 927 | return status; | ||
| 928 | } | ||
| 929 | |||
| 930 | /* See the comment before ocfs2_dquot_initialize. */ | ||
| 931 | static int ocfs2_dquot_drop(struct inode *inode) | ||
| 932 | { | ||
| 933 | int status = 0; | ||
| 934 | struct super_block *sb = inode->i_sb; | ||
| 935 | struct ocfs2_mem_dqinfo *oinfo; | ||
| 936 | int exclusive = 0; | ||
| 937 | int cnt; | ||
| 938 | int got_lock[MAXQUOTAS] = {0, 0}; | ||
| 939 | |||
| 940 | mlog_entry_void(); | ||
| 941 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) { | ||
| 942 | if (!sb_has_quota_active(sb, cnt)) | ||
| 943 | continue; | ||
| 944 | oinfo = sb_dqinfo(sb, cnt)->dqi_priv; | ||
| 945 | status = ocfs2_lock_global_qf(oinfo, 0); | ||
| 946 | if (status < 0) | ||
| 947 | goto out; | ||
| 948 | got_lock[cnt] = 1; | ||
| 949 | } | ||
| 950 | /* Lock against anyone releasing references so that when when we check | ||
| 951 | * we know we are not going to be last ones to release dquot */ | ||
| 952 | down_write(&sb_dqopt(sb)->dqptr_sem); | ||
| 953 | /* Urgh, this is a terrible hack :( */ | ||
| 954 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) { | ||
| 955 | if (inode->i_dquot[cnt] != NODQUOT && | ||
| 956 | atomic_read(&inode->i_dquot[cnt]->dq_count) > 1) { | ||
| 957 | exclusive = 1; | ||
| 958 | break; | ||
| 959 | } | ||
| 960 | } | ||
| 961 | if (!exclusive) | ||
| 962 | dquot_drop_locked(inode); | ||
| 963 | up_write(&sb_dqopt(sb)->dqptr_sem); | ||
| 964 | out: | ||
| 965 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) | ||
| 966 | if (got_lock[cnt]) { | ||
| 967 | oinfo = sb_dqinfo(sb, cnt)->dqi_priv; | ||
| 968 | ocfs2_unlock_global_qf(oinfo, 0); | ||
| 969 | } | ||
| 970 | /* In case we bailed out because we had to do expensive locking | ||
| 971 | * do it now... */ | ||
| 972 | if (exclusive) | ||
| 973 | status = ocfs2_dquot_drop_slow(inode); | ||
| 974 | mlog_exit(status); | ||
| 975 | return status; | ||
| 976 | } | ||
| 977 | |||
| 978 | static struct dquot *ocfs2_alloc_dquot(struct super_block *sb, int type) | 813 | static struct dquot *ocfs2_alloc_dquot(struct super_block *sb, int type) |
| 979 | { | 814 | { |
| 980 | struct ocfs2_dquot *dquot = | 815 | struct ocfs2_dquot *dquot = |
| @@ -991,8 +826,8 @@ static void ocfs2_destroy_dquot(struct dquot *dquot) | |||
| 991 | } | 826 | } |
| 992 | 827 | ||
| 993 | struct dquot_operations ocfs2_quota_operations = { | 828 | struct dquot_operations ocfs2_quota_operations = { |
| 994 | .initialize = ocfs2_dquot_initialize, | 829 | .initialize = dquot_initialize, |
| 995 | .drop = ocfs2_dquot_drop, | 830 | .drop = dquot_drop, |
| 996 | .alloc_space = dquot_alloc_space, | 831 | .alloc_space = dquot_alloc_space, |
| 997 | .alloc_inode = dquot_alloc_inode, | 832 | .alloc_inode = dquot_alloc_inode, |
| 998 | .free_space = dquot_free_space, | 833 | .free_space = dquot_free_space, |
