Commit f42ab0852946c1fb5103682c5897eb3da908e4b0
1 parent
627c10b7e4
Exists in
master
and in
4 other branches
GFS2: Optimise glock lru and end of life inodes
The GLF_LRU flag introduced in the previous patch can be used to check if a glock is on the lru list when a new holder is queued and if so remove it, without having first to get the lru_lock. The main purpose of this patch however is to optimise the glocks left over when an inode at end of life is being evicted. Previously such glocks were left with the GLF_LFLUSH flag set, so that when reclaimed, each one required a log flush. This patch resets the GLF_LFLUSH flag when there is nothing left to flush thus preventing later log flushes as glocks are reused or demoted. In order to do this, we need to keep track of the number of revokes which are outstanding, and also to clear the GLF_LFLUSH bit after a log commit when only revokes have been processed. Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Showing 7 changed files with 119 additions and 89 deletions Side-by-side Diff
fs/gfs2/glock.c
... | ... | @@ -145,15 +145,10 @@ |
145 | 145 | { |
146 | 146 | const struct gfs2_glock_operations *glops = gl->gl_ops; |
147 | 147 | |
148 | - /* assert_spin_locked(&gl->gl_spin); */ | |
149 | - | |
150 | 148 | if (gl->gl_state == LM_ST_UNLOCKED) |
151 | 149 | return 0; |
152 | - if (test_bit(GLF_LFLUSH, &gl->gl_flags)) | |
150 | + if (!list_empty(&gl->gl_holders)) | |
153 | 151 | return 0; |
154 | - if ((gl->gl_name.ln_type != LM_TYPE_INODE) && | |
155 | - !list_empty(&gl->gl_holders)) | |
156 | - return 0; | |
157 | 152 | if (glops->go_demote_ok) |
158 | 153 | return glops->go_demote_ok(gl); |
159 | 154 | return 1; |
... | ... | @@ -174,6 +169,17 @@ |
174 | 169 | spin_unlock(&lru_lock); |
175 | 170 | } |
176 | 171 | |
172 | +static void gfs2_glock_remove_from_lru(struct gfs2_glock *gl) | |
173 | +{ | |
174 | + spin_lock(&lru_lock); | |
175 | + if (!list_empty(&gl->gl_lru)) { | |
176 | + list_del_init(&gl->gl_lru); | |
177 | + atomic_dec(&lru_count); | |
178 | + clear_bit(GLF_LRU, &gl->gl_flags); | |
179 | + } | |
180 | + spin_unlock(&lru_lock); | |
181 | +} | |
182 | + | |
177 | 183 | /** |
178 | 184 | * __gfs2_glock_schedule_for_reclaim - Add a glock to the reclaim list |
179 | 185 | * @gl: the glock |
... | ... | @@ -217,12 +223,7 @@ |
217 | 223 | spin_lock_bucket(gl->gl_hash); |
218 | 224 | hlist_bl_del_rcu(&gl->gl_list); |
219 | 225 | spin_unlock_bucket(gl->gl_hash); |
220 | - spin_lock(&lru_lock); | |
221 | - if (!list_empty(&gl->gl_lru)) { | |
222 | - list_del_init(&gl->gl_lru); | |
223 | - atomic_dec(&lru_count); | |
224 | - } | |
225 | - spin_unlock(&lru_lock); | |
226 | + gfs2_glock_remove_from_lru(gl); | |
226 | 227 | GLOCK_BUG_ON(gl, !list_empty(&gl->gl_holders)); |
227 | 228 | GLOCK_BUG_ON(gl, mapping && mapping->nrpages); |
228 | 229 | trace_gfs2_glock_put(gl); |
... | ... | @@ -1025,6 +1026,9 @@ |
1025 | 1026 | if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) |
1026 | 1027 | return -EIO; |
1027 | 1028 | |
1029 | + if (test_bit(GLF_LRU, &gl->gl_flags)) | |
1030 | + gfs2_glock_remove_from_lru(gl); | |
1031 | + | |
1028 | 1032 | spin_lock(&gl->gl_spin); |
1029 | 1033 | add_to_queue(gh); |
1030 | 1034 | if ((LM_FLAG_NOEXP & gh->gh_flags) && |
... | ... | @@ -1082,7 +1086,8 @@ |
1082 | 1086 | !test_bit(GLF_DEMOTE, &gl->gl_flags)) |
1083 | 1087 | fast_path = 1; |
1084 | 1088 | } |
1085 | - __gfs2_glock_schedule_for_reclaim(gl); | |
1089 | + if (!test_bit(GLF_LFLUSH, &gl->gl_flags)) | |
1090 | + __gfs2_glock_schedule_for_reclaim(gl); | |
1086 | 1091 | trace_gfs2_glock_queue(gh, 0); |
1087 | 1092 | spin_unlock(&gl->gl_spin); |
1088 | 1093 | if (likely(fast_path)) |
... | ... | @@ -1461,12 +1466,7 @@ |
1461 | 1466 | |
1462 | 1467 | static void clear_glock(struct gfs2_glock *gl) |
1463 | 1468 | { |
1464 | - spin_lock(&lru_lock); | |
1465 | - if (!list_empty(&gl->gl_lru)) { | |
1466 | - list_del_init(&gl->gl_lru); | |
1467 | - atomic_dec(&lru_count); | |
1468 | - } | |
1469 | - spin_unlock(&lru_lock); | |
1469 | + gfs2_glock_remove_from_lru(gl); | |
1470 | 1470 | |
1471 | 1471 | spin_lock(&gl->gl_spin); |
1472 | 1472 | if (gl->gl_state != LM_ST_UNLOCKED) |
... | ... | @@ -1666,7 +1666,7 @@ |
1666 | 1666 | dtime *= 1000000/HZ; /* demote time in uSec */ |
1667 | 1667 | if (!test_bit(GLF_DEMOTE, &gl->gl_flags)) |
1668 | 1668 | dtime = 0; |
1669 | - gfs2_print_dbg(seq, "G: s:%s n:%u/%llx f:%s t:%s d:%s/%llu a:%d r:%d\n", | |
1669 | + gfs2_print_dbg(seq, "G: s:%s n:%u/%llx f:%s t:%s d:%s/%llu a:%d v:%d r:%d\n", | |
1670 | 1670 | state2str(gl->gl_state), |
1671 | 1671 | gl->gl_name.ln_type, |
1672 | 1672 | (unsigned long long)gl->gl_name.ln_number, |
... | ... | @@ -1674,6 +1674,7 @@ |
1674 | 1674 | state2str(gl->gl_target), |
1675 | 1675 | state2str(gl->gl_demote_state), dtime, |
1676 | 1676 | atomic_read(&gl->gl_ail_count), |
1677 | + atomic_read(&gl->gl_revokes), | |
1677 | 1678 | atomic_read(&gl->gl_ref)); |
1678 | 1679 | |
1679 | 1680 | list_for_each_entry(gh, &gl->gl_holders, gh_list) { |
fs/gfs2/incore.h
fs/gfs2/inode.c
... | ... | @@ -341,65 +341,6 @@ |
341 | 341 | return error; |
342 | 342 | } |
343 | 343 | |
344 | -int gfs2_dinode_dealloc(struct gfs2_inode *ip) | |
345 | -{ | |
346 | - struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | |
347 | - struct gfs2_alloc *al; | |
348 | - struct gfs2_rgrpd *rgd; | |
349 | - int error; | |
350 | - | |
351 | - if (gfs2_get_inode_blocks(&ip->i_inode) != 1) { | |
352 | - if (gfs2_consist_inode(ip)) | |
353 | - gfs2_dinode_print(ip); | |
354 | - return -EIO; | |
355 | - } | |
356 | - | |
357 | - al = gfs2_alloc_get(ip); | |
358 | - if (!al) | |
359 | - return -ENOMEM; | |
360 | - | |
361 | - error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); | |
362 | - if (error) | |
363 | - goto out; | |
364 | - | |
365 | - error = gfs2_rindex_hold(sdp, &al->al_ri_gh); | |
366 | - if (error) | |
367 | - goto out_qs; | |
368 | - | |
369 | - rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr); | |
370 | - if (!rgd) { | |
371 | - gfs2_consist_inode(ip); | |
372 | - error = -EIO; | |
373 | - goto out_rindex_relse; | |
374 | - } | |
375 | - | |
376 | - error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, | |
377 | - &al->al_rgd_gh); | |
378 | - if (error) | |
379 | - goto out_rindex_relse; | |
380 | - | |
381 | - error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_STATFS + RES_QUOTA, 1); | |
382 | - if (error) | |
383 | - goto out_rg_gunlock; | |
384 | - | |
385 | - set_bit(GLF_DIRTY, &ip->i_gl->gl_flags); | |
386 | - set_bit(GLF_LFLUSH, &ip->i_gl->gl_flags); | |
387 | - | |
388 | - gfs2_free_di(rgd, ip); | |
389 | - | |
390 | - gfs2_trans_end(sdp); | |
391 | - | |
392 | -out_rg_gunlock: | |
393 | - gfs2_glock_dq_uninit(&al->al_rgd_gh); | |
394 | -out_rindex_relse: | |
395 | - gfs2_glock_dq_uninit(&al->al_ri_gh); | |
396 | -out_qs: | |
397 | - gfs2_quota_unhold(ip); | |
398 | -out: | |
399 | - gfs2_alloc_put(ip); | |
400 | - return error; | |
401 | -} | |
402 | - | |
403 | 344 | /** |
404 | 345 | * gfs2_change_nlink - Change nlink count on inode |
405 | 346 | * @ip: The GFS2 inode |
fs/gfs2/inode.h
... | ... | @@ -106,7 +106,6 @@ |
106 | 106 | |
107 | 107 | extern int gfs2_inode_refresh(struct gfs2_inode *ip); |
108 | 108 | |
109 | -extern int gfs2_dinode_dealloc(struct gfs2_inode *inode); | |
110 | 109 | extern int gfs2_change_nlink(struct gfs2_inode *ip, int diff); |
111 | 110 | extern struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, |
112 | 111 | int is_root); |
fs/gfs2/lops.c
... | ... | @@ -320,12 +320,16 @@ |
320 | 320 | |
321 | 321 | static void revoke_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) |
322 | 322 | { |
323 | + struct gfs2_bufdata *bd = container_of(le, struct gfs2_bufdata, bd_le); | |
324 | + struct gfs2_glock *gl = bd->bd_gl; | |
323 | 325 | struct gfs2_trans *tr; |
324 | 326 | |
325 | 327 | tr = current->journal_info; |
326 | 328 | tr->tr_touched = 1; |
327 | 329 | tr->tr_num_revoke++; |
328 | 330 | sdp->sd_log_num_revoke++; |
331 | + atomic_inc(&gl->gl_revokes); | |
332 | + set_bit(GLF_LFLUSH, &gl->gl_flags); | |
329 | 333 | list_add(&le->le_list, &sdp->sd_log_le_revoke); |
330 | 334 | } |
331 | 335 | |
... | ... | @@ -348,9 +352,7 @@ |
348 | 352 | ld->ld_data1 = cpu_to_be32(sdp->sd_log_num_revoke); |
349 | 353 | offset = sizeof(struct gfs2_log_descriptor); |
350 | 354 | |
351 | - while (!list_empty(head)) { | |
352 | - bd = list_entry(head->next, struct gfs2_bufdata, bd_le.le_list); | |
353 | - list_del_init(&bd->bd_le.le_list); | |
355 | + list_for_each_entry(bd, head, bd_le.le_list) { | |
354 | 356 | sdp->sd_log_num_revoke--; |
355 | 357 | |
356 | 358 | if (offset + sizeof(u64) > sdp->sd_sb.sb_bsize) { |
... | ... | @@ -365,8 +367,6 @@ |
365 | 367 | } |
366 | 368 | |
367 | 369 | *(__be64 *)(bh->b_data + offset) = cpu_to_be64(bd->bd_blkno); |
368 | - kmem_cache_free(gfs2_bufdata_cachep, bd); | |
369 | - | |
370 | 370 | offset += sizeof(u64); |
371 | 371 | } |
372 | 372 | gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke); |
... | ... | @@ -374,6 +374,22 @@ |
374 | 374 | submit_bh(WRITE_SYNC, bh); |
375 | 375 | } |
376 | 376 | |
377 | +static void revoke_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai) | |
378 | +{ | |
379 | + struct list_head *head = &sdp->sd_log_le_revoke; | |
380 | + struct gfs2_bufdata *bd; | |
381 | + struct gfs2_glock *gl; | |
382 | + | |
383 | + while (!list_empty(head)) { | |
384 | + bd = list_entry(head->next, struct gfs2_bufdata, bd_le.le_list); | |
385 | + list_del_init(&bd->bd_le.le_list); | |
386 | + gl = bd->bd_gl; | |
387 | + atomic_dec(&gl->gl_revokes); | |
388 | + clear_bit(GLF_LFLUSH, &gl->gl_flags); | |
389 | + kmem_cache_free(gfs2_bufdata_cachep, bd); | |
390 | + } | |
391 | +} | |
392 | + | |
377 | 393 | static void revoke_lo_before_scan(struct gfs2_jdesc *jd, |
378 | 394 | struct gfs2_log_header_host *head, int pass) |
379 | 395 | { |
... | ... | @@ -747,6 +763,7 @@ |
747 | 763 | const struct gfs2_log_operations gfs2_revoke_lops = { |
748 | 764 | .lo_add = revoke_lo_add, |
749 | 765 | .lo_before_commit = revoke_lo_before_commit, |
766 | + .lo_after_commit = revoke_lo_after_commit, | |
750 | 767 | .lo_before_scan = revoke_lo_before_scan, |
751 | 768 | .lo_scan_elements = revoke_lo_scan_elements, |
752 | 769 | .lo_after_scan = revoke_lo_after_scan, |
fs/gfs2/main.c
fs/gfs2/super.c
... | ... | @@ -1315,6 +1315,78 @@ |
1315 | 1315 | return 0; |
1316 | 1316 | } |
1317 | 1317 | |
1318 | +static void gfs2_final_release_pages(struct gfs2_inode *ip) | |
1319 | +{ | |
1320 | + struct inode *inode = &ip->i_inode; | |
1321 | + struct gfs2_glock *gl = ip->i_gl; | |
1322 | + | |
1323 | + truncate_inode_pages(gfs2_glock2aspace(ip->i_gl), 0); | |
1324 | + truncate_inode_pages(&inode->i_data, 0); | |
1325 | + | |
1326 | + if (atomic_read(&gl->gl_revokes) == 0) { | |
1327 | + clear_bit(GLF_LFLUSH, &gl->gl_flags); | |
1328 | + clear_bit(GLF_DIRTY, &gl->gl_flags); | |
1329 | + } | |
1330 | +} | |
1331 | + | |
1332 | +static int gfs2_dinode_dealloc(struct gfs2_inode *ip) | |
1333 | +{ | |
1334 | + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | |
1335 | + struct gfs2_alloc *al; | |
1336 | + struct gfs2_rgrpd *rgd; | |
1337 | + int error; | |
1338 | + | |
1339 | + if (gfs2_get_inode_blocks(&ip->i_inode) != 1) { | |
1340 | + if (gfs2_consist_inode(ip)) | |
1341 | + gfs2_dinode_print(ip); | |
1342 | + return -EIO; | |
1343 | + } | |
1344 | + | |
1345 | + al = gfs2_alloc_get(ip); | |
1346 | + if (!al) | |
1347 | + return -ENOMEM; | |
1348 | + | |
1349 | + error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); | |
1350 | + if (error) | |
1351 | + goto out; | |
1352 | + | |
1353 | + error = gfs2_rindex_hold(sdp, &al->al_ri_gh); | |
1354 | + if (error) | |
1355 | + goto out_qs; | |
1356 | + | |
1357 | + rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr); | |
1358 | + if (!rgd) { | |
1359 | + gfs2_consist_inode(ip); | |
1360 | + error = -EIO; | |
1361 | + goto out_rindex_relse; | |
1362 | + } | |
1363 | + | |
1364 | + error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, | |
1365 | + &al->al_rgd_gh); | |
1366 | + if (error) | |
1367 | + goto out_rindex_relse; | |
1368 | + | |
1369 | + error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_STATFS + RES_QUOTA, 1); | |
1370 | + if (error) | |
1371 | + goto out_rg_gunlock; | |
1372 | + | |
1373 | + gfs2_free_di(rgd, ip); | |
1374 | + | |
1375 | + gfs2_final_release_pages(ip); | |
1376 | + | |
1377 | + gfs2_trans_end(sdp); | |
1378 | + | |
1379 | +out_rg_gunlock: | |
1380 | + gfs2_glock_dq_uninit(&al->al_rgd_gh); | |
1381 | +out_rindex_relse: | |
1382 | + gfs2_glock_dq_uninit(&al->al_ri_gh); | |
1383 | +out_qs: | |
1384 | + gfs2_quota_unhold(ip); | |
1385 | +out: | |
1386 | + gfs2_alloc_put(ip); | |
1387 | + return error; | |
1388 | +} | |
1389 | + | |
1318 | 1390 | /* |
1319 | 1391 | * We have to (at the moment) hold the inodes main lock to cover |
1320 | 1392 | * the gap between unlocking the shared lock on the iopen lock and |
1321 | 1393 | |
... | ... | @@ -1378,15 +1450,13 @@ |
1378 | 1450 | } |
1379 | 1451 | |
1380 | 1452 | error = gfs2_dinode_dealloc(ip); |
1381 | - if (error) | |
1382 | - goto out_unlock; | |
1453 | + goto out_unlock; | |
1383 | 1454 | |
1384 | 1455 | out_truncate: |
1385 | 1456 | error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks); |
1386 | 1457 | if (error) |
1387 | 1458 | goto out_unlock; |
1388 | - /* Needs to be done before glock release & also in a transaction */ | |
1389 | - truncate_inode_pages(&inode->i_data, 0); | |
1459 | + gfs2_final_release_pages(ip); | |
1390 | 1460 | gfs2_trans_end(sdp); |
1391 | 1461 | |
1392 | 1462 | out_unlock: |