diff options
Diffstat (limited to 'fs/gfs2/quota.c')
-rw-r--r-- | fs/gfs2/quota.c | 113 |
1 files changed, 103 insertions, 10 deletions
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 3e073f5144fa..b08d09696b3e 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c | |||
@@ -46,6 +46,8 @@ | |||
46 | #include <linux/bio.h> | 46 | #include <linux/bio.h> |
47 | #include <linux/gfs2_ondisk.h> | 47 | #include <linux/gfs2_ondisk.h> |
48 | #include <linux/lm_interface.h> | 48 | #include <linux/lm_interface.h> |
49 | #include <linux/kthread.h> | ||
50 | #include <linux/freezer.h> | ||
49 | 51 | ||
50 | #include "gfs2.h" | 52 | #include "gfs2.h" |
51 | #include "incore.h" | 53 | #include "incore.h" |
@@ -94,7 +96,7 @@ static int qd_alloc(struct gfs2_sbd *sdp, int user, u32 id, | |||
94 | struct gfs2_quota_data *qd; | 96 | struct gfs2_quota_data *qd; |
95 | int error; | 97 | int error; |
96 | 98 | ||
97 | qd = kzalloc(sizeof(struct gfs2_quota_data), GFP_NOFS); | 99 | qd = kmem_cache_zalloc(gfs2_quotad_cachep, GFP_NOFS); |
98 | if (!qd) | 100 | if (!qd) |
99 | return -ENOMEM; | 101 | return -ENOMEM; |
100 | 102 | ||
@@ -119,7 +121,7 @@ static int qd_alloc(struct gfs2_sbd *sdp, int user, u32 id, | |||
119 | return 0; | 121 | return 0; |
120 | 122 | ||
121 | fail: | 123 | fail: |
122 | kfree(qd); | 124 | kmem_cache_free(gfs2_quotad_cachep, qd); |
123 | return error; | 125 | return error; |
124 | } | 126 | } |
125 | 127 | ||
@@ -158,7 +160,7 @@ static int qd_get(struct gfs2_sbd *sdp, int user, u32 id, int create, | |||
158 | if (qd || !create) { | 160 | if (qd || !create) { |
159 | if (new_qd) { | 161 | if (new_qd) { |
160 | gfs2_lvb_unhold(new_qd->qd_gl); | 162 | gfs2_lvb_unhold(new_qd->qd_gl); |
161 | kfree(new_qd); | 163 | kmem_cache_free(gfs2_quotad_cachep, new_qd); |
162 | } | 164 | } |
163 | *qdp = qd; | 165 | *qdp = qd; |
164 | return 0; | 166 | return 0; |
@@ -1013,7 +1015,7 @@ void gfs2_quota_change(struct gfs2_inode *ip, s64 change, | |||
1013 | 1015 | ||
1014 | if (gfs2_assert_warn(GFS2_SB(&ip->i_inode), change)) | 1016 | if (gfs2_assert_warn(GFS2_SB(&ip->i_inode), change)) |
1015 | return; | 1017 | return; |
1016 | if (ip->i_di.di_flags & GFS2_DIF_SYSTEM) | 1018 | if (ip->i_diskflags & GFS2_DIF_SYSTEM) |
1017 | return; | 1019 | return; |
1018 | 1020 | ||
1019 | for (x = 0; x < al->al_qd_num; x++) { | 1021 | for (x = 0; x < al->al_qd_num; x++) { |
@@ -1100,15 +1102,15 @@ static void gfs2_quota_change_in(struct gfs2_quota_change_host *qc, const void * | |||
1100 | int gfs2_quota_init(struct gfs2_sbd *sdp) | 1102 | int gfs2_quota_init(struct gfs2_sbd *sdp) |
1101 | { | 1103 | { |
1102 | struct gfs2_inode *ip = GFS2_I(sdp->sd_qc_inode); | 1104 | struct gfs2_inode *ip = GFS2_I(sdp->sd_qc_inode); |
1103 | unsigned int blocks = ip->i_di.di_size >> sdp->sd_sb.sb_bsize_shift; | 1105 | unsigned int blocks = ip->i_disksize >> sdp->sd_sb.sb_bsize_shift; |
1104 | unsigned int x, slot = 0; | 1106 | unsigned int x, slot = 0; |
1105 | unsigned int found = 0; | 1107 | unsigned int found = 0; |
1106 | u64 dblock; | 1108 | u64 dblock; |
1107 | u32 extlen = 0; | 1109 | u32 extlen = 0; |
1108 | int error; | 1110 | int error; |
1109 | 1111 | ||
1110 | if (!ip->i_di.di_size || ip->i_di.di_size > (64 << 20) || | 1112 | if (!ip->i_disksize || ip->i_disksize > (64 << 20) || |
1111 | ip->i_di.di_size & (sdp->sd_sb.sb_bsize - 1)) { | 1113 | ip->i_disksize & (sdp->sd_sb.sb_bsize - 1)) { |
1112 | gfs2_consist_inode(ip); | 1114 | gfs2_consist_inode(ip); |
1113 | return -EIO; | 1115 | return -EIO; |
1114 | } | 1116 | } |
@@ -1195,7 +1197,7 @@ fail: | |||
1195 | return error; | 1197 | return error; |
1196 | } | 1198 | } |
1197 | 1199 | ||
1198 | void gfs2_quota_scan(struct gfs2_sbd *sdp) | 1200 | static void gfs2_quota_scan(struct gfs2_sbd *sdp) |
1199 | { | 1201 | { |
1200 | struct gfs2_quota_data *qd, *safe; | 1202 | struct gfs2_quota_data *qd, *safe; |
1201 | LIST_HEAD(dead); | 1203 | LIST_HEAD(dead); |
@@ -1222,7 +1224,7 @@ void gfs2_quota_scan(struct gfs2_sbd *sdp) | |||
1222 | gfs2_assert_warn(sdp, !qd->qd_bh_count); | 1224 | gfs2_assert_warn(sdp, !qd->qd_bh_count); |
1223 | 1225 | ||
1224 | gfs2_lvb_unhold(qd->qd_gl); | 1226 | gfs2_lvb_unhold(qd->qd_gl); |
1225 | kfree(qd); | 1227 | kmem_cache_free(gfs2_quotad_cachep, qd); |
1226 | } | 1228 | } |
1227 | } | 1229 | } |
1228 | 1230 | ||
@@ -1257,7 +1259,7 @@ void gfs2_quota_cleanup(struct gfs2_sbd *sdp) | |||
1257 | gfs2_assert_warn(sdp, !qd->qd_bh_count); | 1259 | gfs2_assert_warn(sdp, !qd->qd_bh_count); |
1258 | 1260 | ||
1259 | gfs2_lvb_unhold(qd->qd_gl); | 1261 | gfs2_lvb_unhold(qd->qd_gl); |
1260 | kfree(qd); | 1262 | kmem_cache_free(gfs2_quotad_cachep, qd); |
1261 | 1263 | ||
1262 | spin_lock(&sdp->sd_quota_spin); | 1264 | spin_lock(&sdp->sd_quota_spin); |
1263 | } | 1265 | } |
@@ -1272,3 +1274,94 @@ void gfs2_quota_cleanup(struct gfs2_sbd *sdp) | |||
1272 | } | 1274 | } |
1273 | } | 1275 | } |
1274 | 1276 | ||
1277 | static void quotad_error(struct gfs2_sbd *sdp, const char *msg, int error) | ||
1278 | { | ||
1279 | if (error == 0 || error == -EROFS) | ||
1280 | return; | ||
1281 | if (!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) | ||
1282 | fs_err(sdp, "gfs2_quotad: %s error %d\n", msg, error); | ||
1283 | } | ||
1284 | |||
1285 | static void quotad_check_timeo(struct gfs2_sbd *sdp, const char *msg, | ||
1286 | int (*fxn)(struct gfs2_sbd *sdp), | ||
1287 | unsigned long t, unsigned long *timeo, | ||
1288 | unsigned int *new_timeo) | ||
1289 | { | ||
1290 | if (t >= *timeo) { | ||
1291 | int error = fxn(sdp); | ||
1292 | quotad_error(sdp, msg, error); | ||
1293 | *timeo = gfs2_tune_get_i(&sdp->sd_tune, new_timeo) * HZ; | ||
1294 | } else { | ||
1295 | *timeo -= t; | ||
1296 | } | ||
1297 | } | ||
1298 | |||
1299 | static void quotad_check_trunc_list(struct gfs2_sbd *sdp) | ||
1300 | { | ||
1301 | struct gfs2_inode *ip; | ||
1302 | |||
1303 | while(1) { | ||
1304 | ip = NULL; | ||
1305 | spin_lock(&sdp->sd_trunc_lock); | ||
1306 | if (!list_empty(&sdp->sd_trunc_list)) { | ||
1307 | ip = list_entry(sdp->sd_trunc_list.next, | ||
1308 | struct gfs2_inode, i_trunc_list); | ||
1309 | list_del_init(&ip->i_trunc_list); | ||
1310 | } | ||
1311 | spin_unlock(&sdp->sd_trunc_lock); | ||
1312 | if (ip == NULL) | ||
1313 | return; | ||
1314 | gfs2_glock_finish_truncate(ip); | ||
1315 | } | ||
1316 | } | ||
1317 | |||
1318 | /** | ||
1319 | * gfs2_quotad - Write cached quota changes into the quota file | ||
1320 | * @sdp: Pointer to GFS2 superblock | ||
1321 | * | ||
1322 | */ | ||
1323 | |||
1324 | int gfs2_quotad(void *data) | ||
1325 | { | ||
1326 | struct gfs2_sbd *sdp = data; | ||
1327 | struct gfs2_tune *tune = &sdp->sd_tune; | ||
1328 | unsigned long statfs_timeo = 0; | ||
1329 | unsigned long quotad_timeo = 0; | ||
1330 | unsigned long t = 0; | ||
1331 | DEFINE_WAIT(wait); | ||
1332 | int empty; | ||
1333 | |||
1334 | while (!kthread_should_stop()) { | ||
1335 | |||
1336 | /* Update the master statfs file */ | ||
1337 | quotad_check_timeo(sdp, "statfs", gfs2_statfs_sync, t, | ||
1338 | &statfs_timeo, &tune->gt_statfs_quantum); | ||
1339 | |||
1340 | /* Update quota file */ | ||
1341 | quotad_check_timeo(sdp, "sync", gfs2_quota_sync, t, | ||
1342 | "ad_timeo, &tune->gt_quota_quantum); | ||
1343 | |||
1344 | /* FIXME: This should be turned into a shrinker */ | ||
1345 | gfs2_quota_scan(sdp); | ||
1346 | |||
1347 | /* Check for & recover partially truncated inodes */ | ||
1348 | quotad_check_trunc_list(sdp); | ||
1349 | |||
1350 | if (freezing(current)) | ||
1351 | refrigerator(); | ||
1352 | t = min(quotad_timeo, statfs_timeo); | ||
1353 | |||
1354 | prepare_to_wait(&sdp->sd_quota_wait, &wait, TASK_UNINTERRUPTIBLE); | ||
1355 | spin_lock(&sdp->sd_trunc_lock); | ||
1356 | empty = list_empty(&sdp->sd_trunc_list); | ||
1357 | spin_unlock(&sdp->sd_trunc_lock); | ||
1358 | if (empty) | ||
1359 | t -= schedule_timeout(t); | ||
1360 | else | ||
1361 | t = 0; | ||
1362 | finish_wait(&sdp->sd_quota_wait, &wait); | ||
1363 | } | ||
1364 | |||
1365 | return 0; | ||
1366 | } | ||
1367 | |||